diff --git a/.gitignore b/.gitignore index 67e0dd8e795bb..d34ed114972c5 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ __pycache__/ .project .settings/ .valgrindrc -.vscode/ +.vscode .favorites.json /*-*-*-*/ /*-*-*/ diff --git a/.gitmodules b/.gitmodules index b75e312dedf73..dd74d49828f75 100644 --- a/.gitmodules +++ b/.gitmodules @@ -43,7 +43,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/8.0-2019-01-16 + branch = rustc/8.0-2019-03-18 [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git diff --git a/.mailmap b/.mailmap index d265f45c5cafa..5673cc5cfbc9d 100644 --- a/.mailmap +++ b/.mailmap @@ -5,8 +5,8 @@ # email addresses. # +Aaron Power Erin Power Aaron Todd -Aaron Power Abhishek Chanda Abhishek Chanda Adolfo Ochagavía Adrien Tétar @@ -30,6 +30,7 @@ Ariel Ben-Yehuda arielb1 Austin Seipp Aydin Kim aydin.kim Barosl Lee Barosl LEE +Bastian Kauschke Ben Alpert Ben Sago Ben S Ben Sago Ben S @@ -45,21 +46,24 @@ Brian Anderson Brian Dawn Brian Leibig Brian Leibig Carl-Anton Ingmarsson +Carol (Nichols || Goulding) <193874+carols10cents@users.noreply.github.com> +Carol (Nichols || Goulding) Carol (Nichols || Goulding) -Carol (Nichols || Goulding) Carol Nichols Carol Willing Chris C Cerami Chris C Cerami Chris Pressey Chris Thorn Chris Thorn Chris Vittal Christopher Vittal -Christian Poveda +Christian Poveda +Christian Poveda +Christian Poveda Clark Gaebel Clinton Ryan Corey Richardson Elaine "See More" Nemo Cyryl Płotnicki Damien Schoof -Daniel Ramos Daniel J Rollins +Daniel Ramos David Klein David Manescu David Ross @@ -68,9 +72,9 @@ Diggory Hardy Diggory Hardy Dylan Braithwaite Dzmitry Malyshau E. Dunham edunham +Eduard-Mihai Burtescu Eduardo Bautista <=> Eduardo Bautista -Eduard-Mihai Burtescu Elliott Slaughter Elly Fong-Jones Eric Holk @@ -78,7 +82,9 @@ Eric Holk Eric Holmes Eric Reed Erick Tryzelaar -Esteban Küber +Esteban Küber +Esteban Küber +Esteban Küber Evgeny Sologubov Falco Hirschenberger Felix S. Klock II Felix S Klock II @@ -98,9 +104,9 @@ Herman J. Radtke III Herman J. Radtke III Ivan Ivaschenko J. J. Weber +Jakub Adam Wieczorek Jakub Adam Wieczorek Jakub Adam Wieczorek -Jakub Adam Wieczorek James Deng James Miller James Perry @@ -115,6 +121,7 @@ Jethro Beekman Jihyun Yu Jihyun Yu jihyun Jihyun Yu Jihyun Yu +João Oliveira joaoxsouls Johann Hofmann Johann John Clements John Hodge John Hodge @@ -125,13 +132,15 @@ Jonathan S Jonathan S Jonathan Turner Jorge Aparicio Joseph Martin -João Oliveira joaoxsouls +Joseph T. Lyons +Joseph T. Lyons Junyoung Cho Jyun-Yan You Kang Seonghoon Keegan McAllister Kevin Butler Kyeongwoon Lee +Laurențiu Nicola Lee Jeffery Lee Jeffery Lee Wondong Lennart Kudling @@ -141,16 +150,16 @@ Lindsey Kuper Luke Metz Luqman Aden Luqman Aden -NAKASHIMA, Makoto -NAKASHIMA, Makoto Marcell Pardavi Margaret Meyerhofer -Mark Simulacrum +Mark Rousskov Mark Sinclair Mark Sinclair =Mark Sinclair <=125axel125@gmail.com> Markus Westerlind Markus Martin Hafskjold Thoresen Matej Lach Matej Ľach +Mateusz Mikuła +Mateusz Mikuła Matt Brubeck Matthew Auld Matthew McPherrin @@ -161,11 +170,14 @@ Michael Woerister Mickaël Raybaud-Roig m-r-r Ms2ger Mukilan Thiagarajan +NAKASHIMA, Makoto +NAKASHIMA, Makoto +Nathan West Nathan Wilson Nathaniel Herman Nathaniel Herman Neil Pankey -Nicole Mazzuca Nick Platt +Nicole Mazzuca Nif Ward Oliver Schneider oli-obk Oliver Schneider Oliver 'ker' Schneider @@ -223,8 +235,8 @@ Tim JIANG Tim Joseph Dumol Torsten Weber Ty Overby +Ulrik Sverdrup bluss Ulrik Sverdrup bluss -Ulrik Sverdrup bluss bluss Ulrik Sverdrup Ulrik Sverdrup Vadim Petrochenkov Vadim Petrochenkov petrochenkov diff --git a/.travis.yml b/.travis.yml index 7985b6c0e191f..1d35ea0efacc2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,337 +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 - -matrix: - fast_finish: true - include: - # Images used in testing PR and try-build should be run first. - - env: IMAGE=x86_64-gnu-llvm-6.0 RUST_BACKTRACE=1 - if: type = pull_request OR branch = auto - - - env: IMAGE=dist-x86_64-linux DEPLOY=1 - if: branch = try OR branch = auto - - # "alternate" deployments, these are "nightlies" but have LLVM assertions - # turned on, they're deployed to a different location primarily for - # additional testing. - - env: IMAGE=dist-x86_64-linux DEPLOY_ALT=1 CI_JOB_NAME=dist-x86_64-linux-alt - if: branch = try OR branch = auto - - - env: > - RUST_CHECK_TARGET=dist - RUST_CONFIGURE_ARGS="--enable-extended --enable-profiler --enable-lldb --set rust.jemalloc" - SRC=. - DEPLOY_ALT=1 - RUSTC_RETRY_LINKER_ON_SEGFAULT=1 - MACOSX_DEPLOYMENT_TARGET=10.7 - NO_LLVM_ASSERTIONS=1 - NO_DEBUG_ASSERTIONS=1 - CI_JOB_NAME=dist-x86_64-apple-alt - os: osx - osx_image: xcode9.3-moar - if: branch = auto - - # macOS builders. These are placed near the beginning because they are very - # slow to run. - - # OSX builders running tests, these run the full test suite. - # NO_DEBUG_ASSERTIONS=1 to make them go faster, but also do have some - # runners that run `//ignore-debug` tests. - # - # Note that the compiler is compiled to target 10.8 here because the Xcode - # version that we're using, 8.2, cannot compile LLVM for OSX 10.7. - - env: > - RUST_CHECK_TARGET=check - RUST_CONFIGURE_ARGS="--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc" - SRC=. - RUSTC_RETRY_LINKER_ON_SEGFAULT=1 - MACOSX_DEPLOYMENT_TARGET=10.8 - MACOSX_STD_DEPLOYMENT_TARGET=10.7 - NO_LLVM_ASSERTIONS=1 - NO_DEBUG_ASSERTIONS=1 - CI_JOB_NAME=x86_64-apple - os: osx - osx_image: xcode9.3-moar - if: branch = auto - - - env: > - RUST_CHECK_TARGET=check - RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --set rust.jemalloc" - SRC=. - RUSTC_RETRY_LINKER_ON_SEGFAULT=1 - MACOSX_DEPLOYMENT_TARGET=10.8 - MACOSX_STD_DEPLOYMENT_TARGET=10.7 - NO_LLVM_ASSERTIONS=1 - NO_DEBUG_ASSERTIONS=1 - CI_JOB_NAME=i686-apple - os: osx - osx_image: xcode9.3-moar - if: branch = auto - - # OSX builders producing releases. These do not run the full test suite and - # just produce a bunch of artifacts. - # - # Note that these are running in the `xcode7` image instead of the - # `xcode8.2` image as above. That's because we want to build releases for - # OSX 10.7 and `xcode7` is the latest Xcode able to compile LLVM for 10.7. - - env: > - RUST_CHECK_TARGET=dist - RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-full-tools --enable-profiler --enable-lldb --set rust.jemalloc" - SRC=. - DEPLOY=1 - RUSTC_RETRY_LINKER_ON_SEGFAULT=1 - MACOSX_DEPLOYMENT_TARGET=10.7 - NO_LLVM_ASSERTIONS=1 - NO_DEBUG_ASSERTIONS=1 - DIST_REQUIRE_ALL_TOOLS=1 - CI_JOB_NAME=dist-i686-apple - os: osx - osx_image: xcode9.3-moar - if: branch = auto - - - env: > - RUST_CHECK_TARGET=dist - RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --enable-lldb --set rust.jemalloc" - SRC=. - DEPLOY=1 - RUSTC_RETRY_LINKER_ON_SEGFAULT=1 - MACOSX_DEPLOYMENT_TARGET=10.7 - NO_LLVM_ASSERTIONS=1 - NO_DEBUG_ASSERTIONS=1 - DIST_REQUIRE_ALL_TOOLS=1 - CI_JOB_NAME=dist-x86_64-apple - os: osx - osx_image: xcode9.3-moar - if: branch = auto - - # Linux builders, remaining docker images - - env: IMAGE=arm-android - if: branch = auto - - env: IMAGE=armhf-gnu - if: branch = auto - - env: IMAGE=dist-various-1 DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-various-2 DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-aarch64-linux DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-android DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-arm-linux DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-armhf-linux DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-armv7-linux DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-i586-gnu-i586-i686-musl DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-i686-freebsd DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-i686-linux DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-mips-linux DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-mips64-linux DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-mips64el-linux DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-mipsel-linux DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-powerpc-linux DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-powerpc64-linux DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-powerpc64le-linux DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-s390x-linux DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-x86_64-freebsd DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-x86_64-musl DEPLOY=1 - if: branch = auto - - env: IMAGE=dist-x86_64-netbsd DEPLOY=1 - if: branch = auto - - env: IMAGE=asmjs - if: branch = auto - - env: IMAGE=i686-gnu - if: branch = auto - - env: IMAGE=i686-gnu-nopt - if: branch = auto - - env: IMAGE=test-various - if: branch = auto - - env: IMAGE=x86_64-gnu - if: branch = auto - - env: IMAGE=x86_64-gnu-full-bootstrap - if: branch = auto - - env: IMAGE=x86_64-gnu-aux - if: branch = auto - - env: IMAGE=x86_64-gnu-tools - if: branch = auto OR (type = pull_request AND commit_message =~ /(?i:^update.*\b(rls|rustfmt|clippy|miri|cargo)\b)/) - - env: IMAGE=x86_64-gnu-debug - if: branch = auto - - env: IMAGE=x86_64-gnu-nopt - if: branch = auto - - env: IMAGE=x86_64-gnu-distcheck - if: branch = auto - - env: IMAGE=mingw-check - if: type = pull_request OR branch = auto - - - stage: publish toolstate - if: branch = master AND type = push - before_install: [] - install: [] - sudo: false - script: - MESSAGE_FILE=$(mktemp -t msg.XXXXXX); - . src/ci/docker/x86_64-gnu-tools/repo.sh; - commit_toolstate_change "$MESSAGE_FILE" "$TRAVIS_BUILD_DIR/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "$MESSAGE_FILE" "$TOOLSTATE_REPO_ACCESS_TOKEN"; - -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 [[ "$RUST_CHECK_TARGET" == dist ]]; then - travis_retry brew update && - travis_retry brew install xz && - travis_retry brew install swig; - 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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e785f03d7de2b..db37fa0caf6c7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,7 +15,7 @@ links to the major sections: * [Helpful Links and Information](#helpful-links-and-information) If you have questions, please make a post on [internals.rust-lang.org][internals] or -hop on [#rust-internals][pound-rust-internals]. +hop on the [Rust Discord server][rust-discord], [Rust Zulip server][rust-zulip] or [#rust-internals][pound-rust-internals]. As a reminder, all contributors are expected to follow our [Code of Conduct][coc]. @@ -27,14 +27,17 @@ can give you a good example of how a typical contribution would go. [pound-rust-internals]: https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-internals [internals]: https://internals.rust-lang.org +[rust-discord]: http://discord.gg/rust-lang +[rust-zulip]: https://rust-lang.zulipchat.com [coc]: https://www.rust-lang.org/conduct.html +[rustc-guide]: https://rust-lang.github.io/rustc-guide/ [walkthrough]: https://rust-lang.github.io/rustc-guide/walkthrough.html ## Feature Requests [feature-requests]: #feature-requests To request a change to the way the Rust language works, please head over -to the [RFCs repository](https://github.com/rust-lang/rfcs) and view the +to the [RFCs repository](https://github.com/rust-lang/rfcs) and view the [README](https://github.com/rust-lang/rfcs/blob/master/README.md) for instructions. @@ -119,6 +122,13 @@ bring those changes into the source repository. Please make pull requests against the `master` branch. +Rust follows a no merge policy, meaning, when you encounter merge +conflicts you are expected to always rebase instead of merge. +E.g. always use rebase when bringing the latest changes from +the master branch to your feature branch. +Also, please make sure that fixup commits are squashed into other related +commits with meaningful commit messages. + Please make sure your pull request is in compliance with Rust's style guidelines by running @@ -129,28 +139,40 @@ request); you can add [git hooks](https://git-scm.com/book/en/v2/Customizing-Git before every push to make sure you never forget to make this check. All pull requests are reviewed by another person. We have a bot, -@rust-highfive, that will automatically assign a random person to review your +[@rust-highfive][rust-highfive], that will automatically assign a random person to review your request. If you want to request that a specific person reviews your pull request, -you can add an `r?` to the message. For example, Steve usually reviews +you can add an `r?` to the message. For example, [Steve][steveklabnik] usually reviews documentation changes. So if you were to make a documentation change, add r? @steveklabnik -to the end of the message, and @rust-highfive will assign @steveklabnik instead +to the end of the message, and @rust-highfive will assign [@steveklabnik][steveklabnik] instead of a random person. This is entirely optional. After someone has reviewed your pull request, they will leave an annotation on the pull request with an `r+`. It will look something like this: - @bors: r+ 38fe8d2 + @bors r+ -This tells @bors, our lovable integration bot, that your pull request has -been approved. The PR then enters the [merge queue][merge-queue], where @bors +This tells [@bors][bors], our lovable integration bot, that your pull request has +been approved. The PR then enters the [merge queue][merge-queue], where [@bors][bors] will run all the tests on every platform we support. If it all works out, -@bors will merge your code into `master` and close the pull request. +[@bors][bors] will merge your code into `master` and close the pull request. + +Depending on the scale of the change, you may see a slightly different form of `r+`: + + @bors r+ rollup + +The additional `rollup` tells [@bors][bors] that this change is eligible for to be +"rolled up". Changes that are rolled up are tested and merged at the same time, to +speed the process up. Typically only small changes that are expected not to conflict +with one another are rolled up. +[rust-highfive]: https://github.com/rust-highfive +[steveklabnik]: https://github.com/steveklabnik +[bors]: https://github.com/bors [merge-queue]: https://buildbot2.rust-lang.org/homu/queue/rust Speaking of tests, Rust has a comprehensive test suite. More information about @@ -190,7 +212,7 @@ before the PR is merged. [breaking-tools-built-with-the-compiler]: #breaking-tools-built-with-the-compiler Rust's build system builds a number of tools that make use of the -internals of the compiler. This includes +internals of the compiler. This includes [Clippy](https://github.com/rust-lang/rust-clippy), [RLS](https://github.com/rust-lang/rls) and [rustfmt](https://github.com/rust-lang/rustfmt). If these tools @@ -292,18 +314,8 @@ the submodule to. Running `./x.py build` should work now. Documentation improvements are very welcome. The source of `doc.rust-lang.org` is located in `src/doc` in the tree, and standard API documentation is generated -from the source code itself. - -Documentation pull requests function in the same way as other pull requests, -though you may see a slightly different form of `r+`: - - @bors: r+ 38fe8d2 rollup - -That additional `rollup` tells @bors that this change is eligible for a 'rollup'. -To save @bors some work, and to get small changes through more quickly, when -@bors attempts to merge a commit that's rollup-eligible, it will also merge -the other rollup-eligible patches too, and they'll get tested and merged at -the same time. +from the source code itself. Documentation pull requests function in the same way +as other pull requests. To find documentation-related issues, sort by the [T-doc label][tdoc]. @@ -428,7 +440,8 @@ are: * Although out of date, [Tom Lee's great blog article][tlgba] is very helpful * [rustaceans.org][ro] is helpful, but mostly dedicated to IRC * The [Rust Compiler Testing Docs][rctd] -* For @bors, [this cheat sheet][cheatsheet] is helpful (Remember to replace `@homu` with `@bors` in the commands that you use.) +* For [@bors][bors], [this cheat sheet][cheatsheet] is helpful +(though you'll need to replace `@homu` with `@bors` in any commands) * **Google!** ([search only in Rust Documentation][gsearchdocs] to find types, traits, etc. quickly) * Don't be afraid to ask! The Rust community is friendly and helpful. diff --git a/Cargo.lock b/Cargo.lock index 4fe8195117048..98dd10955d57d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,14 +10,22 @@ name = "aho-corasick" version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "aho-corasick" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "alloc" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -25,17 +33,38 @@ dependencies = [ [[package]] name = "ammonia" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "html5ever 0.22.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ammonia" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "html5ever 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "annotate-snippets" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ansi_term" version = "0.11.0" @@ -54,6 +83,7 @@ name = "arena" version = "0.0.0" dependencies = [ "rustc_data_structures 0.0.0", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -83,21 +113,28 @@ name = "atty" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "autocfg" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "backtrace" -version = "0.3.11" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace-sys 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-std-workspace-core 1.0.0", ] [[package]] @@ -105,25 +142,12 @@ name = "backtrace-sys" version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] -[[package]] -name = "bit-set" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bit-vec" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "bitflags" version = "0.9.1" @@ -157,22 +181,29 @@ name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bstr" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bufstream" version = "0.1.4" @@ -182,8 +213,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "build-manifest" version = "0.1.0" dependencies = [ - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -230,82 +260,93 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cargo" -version = "0.35.0" +version = "0.38.0" dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo-test-macro 0.1.0", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crates-io 0.23.0", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crates-io 0.26.0", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "curl 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "git2-curl 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "git2-curl 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "im-rc 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jobserver 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "im-rc 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opener 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opener 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proptest 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0", "rustfix 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "strip-ansi-escapes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cargo-test-macro" +version = "0.1.0" +dependencies = [ + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cargo_metadata" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cargo_metadata" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -316,13 +357,17 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.28" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-std-workspace-core 1.0.0", +] [[package]] name = "chalk-engine" @@ -370,53 +415,39 @@ dependencies = [ name = "clippy" version = "0.0.212" dependencies = [ - "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.2.0", - "clippy_dev 0.0.1", "clippy_lints 0.0.212", - "compiletest_rs 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0", - "rustc_tools_util 0.1.1", + "rustc_tools_util 0.2.0", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "clippy-mini-macro-test" version = "0.2.0" -[[package]] -name = "clippy_dev" -version = "0.0.1" -dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "clippy_lints" version = "0.0.212" dependencies = [ - "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "if_chain 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -431,10 +462,10 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.33" +version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -458,15 +489,15 @@ name = "commoncrypto-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "compiler_builtins" -version = "0.1.5" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -476,16 +507,14 @@ version = "0.0.0" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustfix 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -493,21 +522,22 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.3.18" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustfix 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -529,7 +559,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -539,11 +569,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crates-io" -version = "0.23.0" +version = "0.26.0" dependencies = [ - "curl 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -562,19 +593,16 @@ name = "crc32fast" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-channel" -version = "0.3.4" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -592,7 +620,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -601,9 +629,9 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -615,9 +643,9 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -627,15 +655,16 @@ name = "crossbeam-utils" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-utils" -version = "0.6.2" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -651,14 +680,14 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.19" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "curl-sys 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", "schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -666,19 +695,50 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.15" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "libnghttp2-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "darling" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "darling_core 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_macro 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "darling_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "darling_macro" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "darling_core 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "datafrog" version = "2.0.1" @@ -689,9 +749,9 @@ name = "derive-new" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -699,10 +759,10 @@ name = "derive_more" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -725,20 +785,31 @@ dependencies = [ [[package]] name = "directories" -version = "1.0.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "dirs" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dirs-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -747,8 +818,8 @@ name = "dlmalloc" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -762,9 +833,9 @@ name = "elasticlunr-rs" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "strum 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -773,7 +844,7 @@ dependencies = [ [[package]] name = "ena" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -787,7 +858,7 @@ dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -799,7 +870,7 @@ dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -808,7 +879,7 @@ name = "error-chain" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -816,7 +887,7 @@ name = "error-chain" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -831,7 +902,7 @@ name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.29 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -840,10 +911,10 @@ name = "failure_derive" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -856,8 +927,8 @@ name = "filetime" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -872,7 +943,7 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -881,6 +952,9 @@ dependencies = [ [[package]] name = "fmt_macros" version = "0.0.0" +dependencies = [ + "syntax_pos 0.0.0", +] [[package]] name = "fnv" @@ -905,7 +979,7 @@ name = "fortanix-sgx-abi" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -914,7 +988,7 @@ name = "fs2" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -931,6 +1005,11 @@ dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -951,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]] @@ -964,7 +1043,7 @@ name = "fwdansi" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -978,49 +1057,52 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "git2" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "git2-curl" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "curl 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "glob" -version = "0.2.11" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "globset" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1032,13 +1114,13 @@ name = "handlebars" version = "0.32.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "pest_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1047,15 +1129,24 @@ name = "handlebars" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hashbrown" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-std-workspace-alloc 1.0.0", + "rustc-std-workspace-core 1.0.0", ] [[package]] @@ -1087,10 +1178,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "markup5ever 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "html5ever" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "markup5ever 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "http" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1101,6 +1215,11 @@ dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "idna" version = "0.1.5" @@ -1113,35 +1232,41 @@ dependencies = [ [[package]] name = "if_chain" -version = "0.1.3" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ignore" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "im-rc" -version = "12.3.0" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "sized-chunks 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "indexmap" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "installer" version = "0.0.0" @@ -1149,7 +1274,7 @@ dependencies = [ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1162,7 +1287,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1189,25 +1314,25 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jemalloc-sys" -version = "0.1.8" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jobserver" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1219,12 +1344,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonrpc-core" -version = "10.0.1" +version = "12.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1245,7 +1370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1255,7 +1380,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.46" +version = "0.2.54" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc-std-workspace-core 1.0.0", @@ -1263,15 +1388,14 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.7.11" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1280,8 +1404,8 @@ name = "libnghttp2-sys" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1289,10 +1413,10 @@ name = "libssh2-sys" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1302,8 +1426,8 @@ name = "libz-sys" version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1326,7 +1450,7 @@ name = "log" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1334,12 +1458,12 @@ name = "log_settings" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lsp-codec" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1349,13 +1473,13 @@ dependencies = [ [[package]] name = "lsp-types" -version = "0.55.4" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1367,9 +1491,9 @@ name = "lzma-sys" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1390,12 +1514,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "markup5ever" -version = "0.7.2" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "markup5ever" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", "phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1413,7 +1553,7 @@ name = "mdbook" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ammonia 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "elasticlunr-rs 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1421,13 +1561,13 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "handlebars 0.32.4 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1438,48 +1578,53 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ammonia 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "elasticlunr-rs 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "toml-query 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "toml-query 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "memchr" -version = "2.1.1" +name = "measureme" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "memchr" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "memmap" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1490,7 +1635,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "minifier" -version = "0.0.28" +version = "0.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1501,8 +1646,8 @@ name = "miniz-sys" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1518,9 +1663,9 @@ name = "miniz_oxide_c_api" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1534,7 +1679,7 @@ dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1559,7 +1704,7 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1588,12 +1733,15 @@ name = "miri" version = "0.1.0" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "directories 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1605,18 +1753,15 @@ name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[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" @@ -1629,9 +1774,9 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1652,7 +1797,7 @@ name = "num_cpus" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1662,11 +1807,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "opener" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1676,11 +1819,11 @@ version = "0.10.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1693,18 +1836,19 @@ name = "openssl-src" version = "111.1.0+1.1.1a" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl-sys" -version = "0.9.40" +version = "0.9.43" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-src 111.1.0+1.1.1a (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1731,16 +1875,16 @@ name = "packed_simd" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "panic_abort" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1748,21 +1892,13 @@ name = "panic_unwind" version = "0.0.0" dependencies = [ "alloc 0.0.0", - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "unwind 0.0.0", ] -[[package]] -name = "parking_lot" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parking_lot" version = "0.7.1" @@ -1772,26 +1908,15 @@ dependencies = [ "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "parking_lot_core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1839,9 +1964,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "pest_meta 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1886,7 +2011,7 @@ version = "0.7.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1904,7 +2029,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "polonius-engine" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "datafrog 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1938,7 +2063,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "0.4.24" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1952,46 +2077,36 @@ version = "0.0.0" name = "profiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] -[[package]] -name = "proptest" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rusty-fork 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "pulldown-cmark" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pulldown-cmark" -version = "0.2.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "punycode" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "quick-error" version = "1.2.2" @@ -2009,15 +2124,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "0.6.10" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "racer" -version = "2.1.19" +version = "2.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2025,31 +2140,21 @@ dependencies = [ "derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-span 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.5.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2060,7 +2165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2076,21 +2181,18 @@ name = "rand_chacha" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "rand_core" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2098,7 +2200,7 @@ name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2109,6 +2211,19 @@ dependencies = [ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_pcg" version = "0.1.1" @@ -2123,7 +2238,7 @@ name = "rand_xorshift" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2132,19 +2247,26 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2162,12 +2284,12 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2177,7 +2299,7 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2185,12 +2307,12 @@ dependencies = [ [[package]] name = "regex" -version = "1.1.0" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2205,7 +2327,7 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.4" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2229,12 +2351,12 @@ dependencies = [ [[package]] name = "rls" -version = "1.34.0" +version = "1.37.0" dependencies = [ - "cargo 0.35.0", - "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo 0.38.0", + "cargo_metadata 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "clippy_lints 0.0.212", - "crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2242,28 +2364,28 @@ dependencies = [ "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lsp-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lsp-types 0.55.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lsp-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lsp-types 0.57.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "racer 2.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "racer 2.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-analysis 0.16.12 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-analysis 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-blacklist 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.18.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-rustc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-span 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-vfs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-rustc 0.6.0", + "rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-vfs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0", - "rustc_tools_util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt-nightly 1.0.3", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_tools_util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfmt-nightly 1.3.0", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2271,14 +2393,14 @@ dependencies = [ "tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-process 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-analysis" -version = "0.16.12" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2286,9 +2408,10 @@ dependencies = [ "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.18.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-span 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2298,37 +2421,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rls-data" -version = "0.18.2" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rls-span 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-rustc" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.6.0" [[package]] name = "rls-span" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-vfs" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-span 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2337,7 +2455,7 @@ version = "0.1.0" dependencies = [ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "mdbook 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mdbook 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2345,29 +2463,31 @@ name = "rustc" version = "0.0.0" dependencies = [ "arena 0.0.0", - "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.29 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "fmt_macros 0.0.0", "graphviz 0.0.0", - "jobserver 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "measureme 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "polonius-engine 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon-core 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "polonius-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_apfloat 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_fs_util 0.0.0", + "rustc_macros 0.1.0", "rustc_target 0.0.0", "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2375,20 +2495,21 @@ dependencies = [ [[package]] name = "rustc-ap-arena" -version = "373.0.0" +version = "491.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-ap-rustc_data_structures 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-graphviz" -version = "373.0.0" +version = "491.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc-ap-rustc_cratesio_shim" -version = "373.0.0" +version = "491.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2398,93 +2519,114 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_data_structures" -version = "373.0.0" +version = "491.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-graphviz 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_cratesio_shim 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-graphviz 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_cratesio_shim 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon-core 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-rustc_errors" -version = "373.0.0" +version = "491.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "annotate-snippets 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_cratesio_shim 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_cratesio_shim 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc-ap-rustc_macros" +version = "491.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-ap-rustc_target" -version = "373.0.0" +version = "491.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_cratesio_shim 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_cratesio_shim 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-serialize" -version = "373.0.0" +version = "491.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-syntax" -version = "373.0.0" +version = "491.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_errors 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_target 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_errors 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_macros 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_target 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-syntax_pos" -version = "373.0.0" +version = "491.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-arena 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-arena 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_macros 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-demangle" -version = "0.1.10" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -2500,7 +2642,7 @@ dependencies = [ name = "rustc-main" version = "0.0.0" dependencies = [ - "jemalloc-sys 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "jemalloc-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_codegen_ssa 0.0.0", "rustc_driver 0.0.0", "rustc_target 0.0.0", @@ -2508,22 +2650,22 @@ dependencies = [ [[package]] name = "rustc-rayon" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon-core 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-rayon-core" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2532,6 +2674,13 @@ name = "rustc-serialize" version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc-std-workspace-alloc" +version = "1.0.0" +dependencies = [ + "alloc 0.0.0", +] + [[package]] name = "rustc-std-workspace-core" version = "1.0.0" @@ -2545,12 +2694,12 @@ version = "1.0.0" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2563,7 +2712,7 @@ dependencies = [ "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2574,7 +2723,7 @@ version = "0.0.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2583,8 +2732,8 @@ version = "0.0.0" dependencies = [ "alloc 0.0.0", "build_helper 0.1.0", - "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2606,10 +2755,10 @@ dependencies = [ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_llvm 0.0.0", ] @@ -2618,14 +2767,15 @@ name = "rustc_codegen_ssa" version = "0.0.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "jobserver 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_apfloat 0.0.0", "rustc_codegen_utils 0.0.0", @@ -2633,11 +2783,11 @@ dependencies = [ "rustc_errors 0.0.0", "rustc_fs_util 0.0.0", "rustc_incremental 0.0.0", - "rustc_mir 0.0.0", "rustc_target 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", + "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2646,11 +2796,11 @@ version = "0.0.0" dependencies = [ "flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "punycode 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", + "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", - "rustc_incremental 0.0.0", "rustc_metadata 0.0.0", - "rustc_mir 0.0.0", "rustc_target 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", @@ -2669,19 +2819,20 @@ dependencies = [ name = "rustc_data_structures" version = "0.0.0" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", - "jobserver 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-rayon-core 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", "serialize 0.0.0", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2694,7 +2845,7 @@ dependencies = [ "graphviz 0.0.0", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc-rayon 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_borrowck 0.0.0", "rustc_codegen_utils 0.0.0", @@ -2715,7 +2866,7 @@ dependencies = [ "rustc_typeck 0.0.0", "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_ext 0.0.0", "syntax_pos 0.0.0", @@ -2725,6 +2876,7 @@ dependencies = [ name = "rustc_errors" version = "0.0.0" dependencies = [ + "annotate-snippets 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", @@ -2745,7 +2897,7 @@ version = "0.0.0" dependencies = [ "graphviz 0.0.0", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_fs_util 0.0.0", @@ -2760,9 +2912,10 @@ version = "0.0.0" dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc-rayon 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_borrowck 0.0.0", + "rustc_codegen_ssa 0.0.0", "rustc_codegen_utils 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -2776,12 +2929,13 @@ dependencies = [ "rustc_resolve 0.0.0", "rustc_traits 0.0.0", "rustc_typeck 0.0.0", - "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_ext 0.0.0", "syntax_pos 0.0.0", + "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2801,7 +2955,7 @@ name = "rustc_llvm" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2810,11 +2964,22 @@ version = "0.0.0" dependencies = [ "alloc 0.0.0", "build_helper 0.1.0", - "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] +[[package]] +name = "rustc_macros" +version = "0.1.0" +dependencies = [ + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc_metadata" version = "0.0.0" @@ -2827,6 +2992,7 @@ dependencies = [ "rustc_errors 0.0.0", "rustc_target 0.0.0", "serialize 0.0.0", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_ext 0.0.0", @@ -2843,14 +3009,14 @@ dependencies = [ "graphviz 0.0.0", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log_settings 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "polonius-engine 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "polonius-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_apfloat 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", "serialize 0.0.0", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2861,8 +3027,8 @@ version = "0.0.0" dependencies = [ "alloc 0.0.0", "build_helper 0.1.0", - "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2909,11 +3075,13 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_metadata 0.0.0", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2923,14 +3091,14 @@ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.18.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-span 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_codegen_utils 0.0.0", "rustc_data_structures 0.0.0", "rustc_target 0.0.0", "rustc_typeck 0.0.0", + "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2944,15 +3112,16 @@ dependencies = [ "rustc_cratesio_shim 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", + "syntax_pos 0.0.0", ] [[package]] name = "rustc_tools_util" -version = "0.1.1" +version = "0.2.0" [[package]] name = "rustc_tools_util" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2966,7 +3135,7 @@ dependencies = [ "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_target 0.0.0", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2977,8 +3146,8 @@ version = "0.0.0" dependencies = [ "alloc 0.0.0", "build_helper 0.1.0", - "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2992,7 +3161,7 @@ dependencies = [ "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -3009,9 +3178,10 @@ dependencies = [ name = "rustdoc" version = "0.0.0" dependencies = [ - "minifier 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "minifier 0.0.30 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3033,53 +3203,55 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustfmt-config_proc_macro" +version = "0.1.0" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustfmt-nightly" -version = "1.0.3" +version = "1.3.0" dependencies = [ + "annotate-snippets 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", + "ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_target 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_target 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfmt-config_proc_macro 0.1.0", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rusty-fork" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "wait-timeout 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ryu" version = "0.2.7" @@ -3090,7 +3262,7 @@ name = "same-file" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3098,15 +3270,10 @@ name = "schannel" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "scoped-tls" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "scoped-tls" version = "1.0.0" @@ -3128,7 +3295,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3138,7 +3305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.82" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3149,9 +3316,9 @@ name = "serde_derive" version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3159,7 +3326,7 @@ name = "serde_ignored" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3167,16 +3334,17 @@ name = "serde_json" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serialize" version = "0.0.0" dependencies = [ - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3206,7 +3374,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3214,6 +3382,14 @@ name = "siphasher" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "sized-chunks" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "slab" version = "0.4.2" @@ -3221,19 +3397,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.7" +version = "0.6.10" 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 = "socket2" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3248,18 +3421,19 @@ name = "std" version = "0.0.0" dependencies = [ "alloc 0.0.0", - "backtrace-sys 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.29 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "dlmalloc 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "fortanix-sgx-abi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "panic_abort 0.0.0", "panic_unwind 0.0.0", "profiler_builtins 0.0.0", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_asan 0.0.0", "rustc_lsan 0.0.0", "rustc_msan 0.0.0", @@ -3272,11 +3446,11 @@ name = "string_cache" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.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)", + "lazy_static 1.3.0 (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.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3288,8 +3462,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "phf_generator 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3298,11 +3472,39 @@ name = "string_cache_shared" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "strip-ansi-escapes" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strsim" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "structopt" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "structopt-derive" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strum" version = "0.11.0" @@ -3314,9 +3516,9 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3331,11 +3533,11 @@ dependencies = [ [[package]] name = "syn" -version = "0.15.22" +version = "0.15.35" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3349,12 +3551,12 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3363,13 +3565,15 @@ name = "syntax" version = "0.0.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_macros 0.1.0", "rustc_target 0.0.0", "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax_pos 0.0.0", ] @@ -3382,7 +3586,7 @@ dependencies = [ "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -3392,8 +3596,9 @@ name = "syntax_pos" version = "0.0.0" dependencies = [ "arena 0.0.0", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", + "rustc_macros 0.1.0", "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3405,7 +3610,7 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3415,8 +3620,8 @@ name = "tempfile" version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3437,6 +3642,15 @@ dependencies = [ name = "term" version = "0.0.0" +[[package]] +name = "term" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "term" version = "0.5.1" @@ -3459,7 +3673,7 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3468,11 +3682,21 @@ dependencies = [ name = "test" version = "0.0.0" dependencies = [ - "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "term 0.0.0", ] +[[package]] +name = "tester" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "textwrap" version = "0.10.0" @@ -3486,16 +3710,18 @@ name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tidy" version = "0.1.0" dependencies = [ - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3503,7 +3729,7 @@ name = "time" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3554,7 +3780,7 @@ name = "tokio-executor" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3584,7 +3810,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3598,9 +3824,9 @@ name = "tokio-reactor" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3616,7 +3842,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3644,9 +3870,9 @@ name = "tokio-threadpool" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3659,7 +3885,7 @@ name = "tokio-timer" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3687,7 +3913,7 @@ dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3701,7 +3927,15 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "toml" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3711,21 +3945,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml-query" -version = "0.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "toml-query_derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "toml-query_derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "darling 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3743,6 +3989,14 @@ name = "ucd-util" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicase" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-bidi" version = "0.3.4" @@ -3781,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" @@ -3801,9 +4047,11 @@ dependencies = [ name = "unwind" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3821,7 +4069,7 @@ name = "url_serde" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3835,6 +4083,11 @@ name = "utf8-ranges" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "utf8parse" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vcpkg" version = "0.2.6" @@ -3861,16 +4114,11 @@ 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 = "wait-timeout" -version = "0.1.5" +name = "vte" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3880,7 +4128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3909,7 +4157,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3926,7 +4174,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3943,7 +4191,7 @@ name = "xattr" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3962,21 +4210,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" -"checksum ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4c682378117e4186a492b2252b9537990e1617f44aed9788b9a1149de45477" +"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" +"checksum ammonia 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8b93ecb80665873703bf3b0a77f369c96b183d8e0afaf30a3ff5ff07dfc6409" +"checksum ammonia 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c799ecf1ad77acb48b643e2f45b12d60ee41576287fc575031aa020de88b8f45" +"checksum annotate-snippets 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e8bcdcd5b291ce85a78f2b9d082a8de9676c12b1840d386d67bc5eea6f9d2b4e" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6" "checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "18b65ea1161bfb2dd6da6fade5edd4dbd08fba85012123dd333d2fd1b90b2782" +"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum backtrace 0.3.29 (registry+https://github.com/rust-lang/crates.io-index)" = "2d631cd7af21b7ff796293f1990104e3cdb606852863bac32f000c193aa35dfb" "checksum backtrace-sys 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "6ea90dd7b012b3d1a2cb6bec16670a0db2c95d4e931e84f4047e0460c1b34c8d" -"checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a" -"checksum bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4440d5cb623bb7390ae27fec0bb6c61111969860f8e3ae198bfa0663645e67cf" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" +"checksum bstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "853b090ce0f45d0265902666bf88039ea3da825e33796716c511a1ec9c170036" "checksum bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8" "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" @@ -3984,48 +4235,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" "checksum bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010" -"checksum cargo_metadata 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d8dfe3adeb30f7938e6c1dd5327f29235d8ada3e898aeb08c343005ec2915a2" "checksum cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "585784cac9b05c93a53b17a0b24a5cdd1dfdda5256f030e089b549d2390cc720" -"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"checksum cargo_metadata 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "929766d993a2fde7a0ae962ee82429069cd7b68839cd9375b98efd719df65d3a" +"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" +"checksum cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "89431bba4e6b7092fb5fcd00a6f6ca596c55cc26b2f1e6dcdd08a1f4933f66b2" "checksum chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17ec698a6f053a23bfbe646d9f2fde4b02abc19125595270a99e6f44ae0bdd1a" "checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "704fbf3bb5149daab0afb255dbea24a1f08d2f4099cedb9baab6d470d4c5eefb" +"checksum cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "96210eec534fc3fbfc0452a63769424eaa80205fda6cea98e5b61cb3d97bcec8" "checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc" "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" "checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" -"checksum compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6711d51cb46744dd8305293cc3fbc392aaff7a8f5095a7c4fae1e5113ef07c96" -"checksum compiletest_rs 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0d76d4322a40f6b0db7259d4f2c8a65ed8b0d84fce0bbc61b98cf47f8ec6eec3" +"checksum compiler_builtins 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "e79ed19793c99771b386d76e08c3419409bb3d418b81a8b8afc73524247461cf" +"checksum compiletest_rs 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "f40ecc9332b68270998995c00f8051ee856121764a0d3230e64c9efd059d27b6" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4e2640d6d0bf22e82bed1b73c6aef8d5dd31e5abe6666c57e6d45e2649f4f887" "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192" -"checksum crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2a9ea8f77c7f9efd317a8a5645f515d903a2d86ee14d2337a5facd1bd52c12" +"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f10a4f8f409aaac4b16a5474fb233624238fcdeefb9ba50d5ea059aab63ba31c" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e07fc155212827475223f0bcfae57e945e694fc90950ddf3f6695bbfd5555c72" +"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4" -"checksum curl 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "c7c9d851c825e0c033979d4516c9173bc19a78a96eb4d6ae51d4045440eafa16" -"checksum curl-sys 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "721c204978be2143fab0a84b708c49d79d1f6100b8785610f456043a90708870" +"checksum curl 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)" = "a85f2f95f2bd277d316d1aa8a477687ab4a6942258c7db7c89c187534669979c" +"checksum curl-sys 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)" = "9d91a0052d5b982887d8e829bee0faffc7218ea3c6ebd3d6c2c8f678a93c9a42" +"checksum darling 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9158d690bc62a3a57c3e45b85e4d50de2008b39345592c64efd79345c7e24be0" +"checksum darling_core 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d2a368589465391e127e10c9e3a08efc8df66fd49b87dc8524c764bbe7f2ef82" +"checksum darling_macro 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "244e8987bd4e174385240cde20a3657f607fb0797563c28255c353b5819a07b1" "checksum datafrog 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69" "checksum derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6ca414e896ae072546f4d789f452daaecf60ddee4c9df5dc6d5936d769e3d87c" "checksum derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f57d78cf3bd45270dad4e70c21ec77a960b36c7a841ff9db76aaa775a8fb871" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" "checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" -"checksum directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72d337a64190607d4fcca2cb78982c5dd57f4916e19696b48a575fa746b6cb0f" -"checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a" +"checksum directories 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ccc83e029c3cebb4c8155c644d34e3a070ccdb4ff90d369c74cd73f7cb3c984" +"checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" +"checksum dirs-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "937756392ec77d1f2dd9dc3ac9d69867d109a2121479d72c364e42f4cab21e2d" "checksum dlmalloc 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f283302e035e61c23f2b86b3093e8c6273a4c3125742d6087e96ade001ca5e63" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum elasticlunr-rs 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a99a310cd1f9770e7bf8e48810c7bcbb0e078c8fb23a8c7bcf0da4c2bf61a455" -"checksum ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f56c93cc076508c549d9bb747f79aa9b4eb098be7b8cad8830c3137ef52d1e00" +"checksum ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dc01d68e08ca384955a3aeba9217102ca1aa85b6e168639bf27739f1d749d87" "checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" "checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" @@ -4043,63 +4298,71 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" "checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" "checksum fst 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d94485a00b1827b861dd9d1a2cc9764f9044d4c535514c0760a5a2012ef3399f" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34dd4c507af68d37ffef962063dfa1944ce0dd4d5b82043dbab1dabe088610c3" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" -"checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05" -"checksum git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7339329bfa14a00223244311560d11f8f489b453fb90092af97f267a6090ab0" -"checksum git2-curl 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d58551e903ed7e2d6fe3a2f3c7efa3a784ec29b19d0fbb035aaf0497c183fbdd" -"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4743617a7464bbda3c8aec8558ff2f9429047e025771037df561d383337ff865" +"checksum getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "72327b15c228bfe31f1390f93dd5e9279587f0463836393c9df719ce62a3e450" +"checksum git2 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "924b2e7d2986e625dcad89e8a429a7b3adee3c3d71e585f4a66c4f7e78715e31" +"checksum git2-curl 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f21f0550fd5d3f7c5adb94797fcd3d1002d7fc1fa349c82fe44f3c97ef80b62c" +"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +"checksum globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4feaabe24a0a658fd9cf4a9acf6ed284f045c77df0f49020ba3245cfb7b454" "checksum handlebars 0.32.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d89ec99d1594f285d4590fc32bac5f75cdab383f1123d504d27862c644a807dd" "checksum handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d82e5750d8027a97b9640e3fefa66bbaf852a35228e1c90790efd13c4b09c166" +"checksum hashbrown 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9529213c67695ca2d146e6f263b7b72df8fa973368beadf767e8ed80c03f2f36" "checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "80dff82fb58cfbbc617fb9a9184b010be0529201553cda50ad04372bc2333aff" "checksum html5ever 0.22.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c213fa6a618dc1da552f54f85cba74b05d8e883c92ec4e89067736938084c26e" +"checksum html5ever 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce65ac8028cf5a287a7dbf6c4e0a6cf2dcf022ed5b167a81bae66ebf599a8b7" +"checksum http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fe67e3678f2827030e89cc4b9e7ecd16d52f132c0b940ab5005f88e821500f6a" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +"checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4bac95d9aa0624e7b78187d6fb8ab012b41d9f6f54b1bcb61e61c4845f8357ec" -"checksum ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ad03ca67dc12474ecd91fdb94d758cbd20cb4e7a78ebe831df26a9b7511e1162" -"checksum im-rc 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9460397452f537fd51808056ff209f4c4c4c9d20d42ae952f517708726284972" +"checksum if_chain 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d" +"checksum ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8dc57fa12805f367736a38541ac1a9fc6a52812a0ca959b1d4d4b640a89eb002" +"checksum im-rc 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0197597d095c0d11107975d3175173f810ee572c2501ff4de64f4f3f119806" +"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053" "checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" -"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" -"checksum jemalloc-sys 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "bfc62c8e50e381768ce8ee0428ee53741929f7ebd73e4d83f669bcf7693e00ae" -"checksum jobserver 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "dd80e58f77e0cdea53ba96acc5e04479e5ffc5d869626a6beafe50fed867eace" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum jemalloc-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bef0d4ce37578dfd80b466e3d8324bd9de788e249f1accebb0c472ea4b52bdc" +"checksum jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b3d51e24009d966c8285d524dbaf6d60926636b2a89caee9ce0bd612494ddc16" "checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be" -"checksum jsonrpc-core 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a5152c3fda235dfd68341b3edf4121bc4428642c93acbd6de88c26bf95fc5d7" +"checksum jsonrpc-core 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "288dca7f9713710a29e485076b9340156cb701edb46a881f5d0c31aa4f5b9143" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" -"checksum libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)" = "023a4cd09b2ff695f9734c1934145a315594b7986398496841c7031a5a1bbdbd" -"checksum libgit2-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "48441cb35dc255da8ae72825689a95368bf510659ae1ad55dc4aa88cb1789bf1" +"checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6" +"checksum libgit2-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "941a41e23f77323b8c9d2ee118aec9ee39dfc176078c18b4757d3bad049d9ff7" "checksum libnghttp2-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d75d7966bda4730b722d1eab8e668df445368a24394bae9fc1e8dc0ab3dbe4f4" "checksum libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "126a1f4078368b163bfdee65fbab072af08a1b374a5551b21e87ade27b1fbf9d" "checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" "checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum log_settings 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19af41f0565d7c19b2058153ad0b42d4d5ce89ec4dbf06ed6741114a8b63e7cd" -"checksum lsp-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3570f641b984e3e4613a1ca34db2ea72549bbc3c0316d33f5af91ab514dcbff" -"checksum lsp-types 0.55.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6392b5843615b8a2adeebe87b83fdd29567c0870baba3407a67e6dbfee4712f8" +"checksum lsp-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "169d737ad89cf8ddd82d1804d9122f54568c49377665157277cc90d747b1d31a" +"checksum lsp-types 0.57.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b62b77309737b1e262b3bbf37ff8faa740562c633b14702afe9be85dbcb6f88a" "checksum lzma-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d1eaa027402541975218bb0eec67d6b0412f6233af96e0d096d31dbdfd22e614" "checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" "checksum macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2c4deaccc2ead6a28c16c0ba82f07d52b6475397415ce40876e559b0b0ea510" "checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" -"checksum markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfedc97d5a503e96816d10fedcd5b42f760b2e525ce2f7ec71f6a41780548475" +"checksum markup5ever 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "897636f9850c3eef4905a5540683ed53dc9393860f0846cab2c2ddf9939862ff" +"checksum markup5ever 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f1af46a727284117e09780d05038b1ce6fc9c76cc6df183c3dae5a8955a25e21" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f" -"checksum mdbook 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0ba0d44cb4089c741b9a91f3e5218298a40699c2f3a070a85014eed290c60819" -"checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16" +"checksum mdbook 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c8e2c6442721202fb3b5800741aaafcc7076cdd199b326f0a39ce52a042cd37" +"checksum measureme 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09de7dafa3aa334bc806447c7e4de69419723312f4b88b80b561dea66601ce8" +"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum minifier 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "3a2898502751dcc9d66b6fff57f3cf63cc91605e83e1a33515396f5027f8e4ca" +"checksum minifier 0.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "4c909e78edf61f3aa0dd2086da168cdf304329044bbf248768ca3d20253ec8c0" "checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649" "checksum miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c" "checksum miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28edaef377517fd9fe3e085c37d892ce7acd1fbeab9239c5a36eec352d8a8b7e" @@ -4109,25 +4372,23 @@ 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" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113" -"checksum opener 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "04b1d6b086d9b3009550f9b6f81b10ad9428cf14f404b8e1a3a06f6f012c8ec9" +"checksum opener 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "998c59e83d9474c01127a96e023b7a04bb061dd286bf8bb939d31dc8d31a7448" "checksum openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" "checksum openssl-src 111.1.0+1.1.1a (registry+https://github.com/rust-lang/crates.io-index)" = "26bb632127731bf4ac49bf86a5dde12d2ca0918c2234fc39d79d4da2ccbc6da7" -"checksum openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)" = "1bb974e77de925ef426b6bc82fce15fd45bdcbeb5728bffcfc7cdeeb7ce1c2d6" +"checksum openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)" = "33c86834957dd5b915623e94f2f4ab2c70dd8f6b70679824155d5ae21dbd495d" "checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" "checksum ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum packed_simd 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "25d36de864f7218ec5633572a800109bbe5a1cc8d9d95a967f3daf93ea7e6ddc" -"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -"checksum parking_lot_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06a2b6aae052309c2fd2161ef58f5067bc17bb758377a0de9d4b279d603fdd8a" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc" @@ -4142,73 +4403,72 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum phf_generator 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "05a079dd052e7b674d21cb31cbb6c05efd56a2cd2827db7692e2f1a507ebd998" "checksum phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "c2261d544c2bb6aa3b10022b0be371b9c7c64f762ef28c6f5d4f1ef6d97b5930" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" -"checksum polonius-engine 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2490c396085801abf88df91758bad806b0890354f0875d624e62ecf0579a8145" +"checksum polonius-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b24942fee141ea45628484a453762bb7e515099c3ec05fbeb76b7bf57b1aeed" "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" "checksum pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8b3f4e0475def7d9c2e5de8e5a1306949849761e107b360d03e98eafaffd61" -"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" -"checksum proptest 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "926d0604475349f463fe44130aae73f2294b5309ab2ca0310b998bd334ef191f" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32" -"checksum pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eef52fac62d0ea7b9b4dc7da092aa64ea7ec3d90af6679422d3d7e0e14b6ee15" +"checksum pulldown-cmark 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "051e60ace841b3bfecd402fe5051c06cb3bec4a6e6fdd060a37aa8eb829a1db3" +"checksum punycode 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6ddd112cca70a4d30883b2d21568a1d376ff8be4758649f64f973c6845128ad3" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" -"checksum racer 2.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "d634483bed41bb116122b84ffe0ef8740345c2ceb2784ce86c33499700eb13a7" -"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" -"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" +"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" +"checksum racer 2.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "94dbdea3d959d8f76a2e303b3eadf107fd76da886b231291e649168613d432fb" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a" "checksum rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "771b009e3a508cb67e8823dda454aaa5368c7bc1c16829fb77d3e980440dd34a" -"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" "checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" "checksum rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effa3fcaa47e18db002bdde6060944b6d2f9cfd8db471c30e873448ad9187be3" "checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1" -"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" +"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "214a97e49be64fd2c86f568dd0cb2c757d2cc53de95b273b6ad0a1c908482f26" +"checksum redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828" "checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" -"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" +"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" "checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" -"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1" +"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum rls-analysis 0.16.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ae18d8ad01dec3b2014f4d7ae3c607d7adbcff79e5d3b48ea42ea71c10d43a71" +"checksum rls-analysis 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d53d49a28f75da9d02790d9256fecf6c0481e0871374326023c7a33131295579" "checksum rls-blacklist 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ce1fdac03e138c4617ff87b194e1ff57a39bb985a044ccbd8673d30701e411" -"checksum rls-data 0.18.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f80b84551b32e26affaf7f12374913b5061730c0dcd185d9e8fa5a15e36e65c" -"checksum rls-rustc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9dba7390427aefa953608429701e3665192ca810ba8ae09301e001b7c7bed0" -"checksum rls-span 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "33d66f1d6c6ccd5c98029f162544131698f6ebb61d8c697681cac409dcd08805" -"checksum rls-vfs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "72d56425bd5aa86d9d4372b76f0381d3b4bda9c0220e71956c9fcc929f45c1f1" -"checksum rustc-ap-arena 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8be999235b541fc8eb54901b66e899a06076709ac5f53d6b2c5c59d29ad54780" -"checksum rustc-ap-graphviz 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "532b5df15ca1a19a42815e37e521a20a7632b86b36868d1447932f8476f8f789" -"checksum rustc-ap-rustc_cratesio_shim 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c388afe1ef810013c878bdf9073ab1ae28dc49e9325863b351afb10acf4cc46e" -"checksum rustc-ap-rustc_data_structures 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63a8f08b9fb6d607afb842ee7206273d09d69c9201bfc1c479a726093251a24e" -"checksum rustc-ap-rustc_errors 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6dc0df7bf31588ea67e6386f6ad19f6b9a37ba7d5726ecad1cacce22e231bd98" -"checksum rustc-ap-rustc_target 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb4623a6f6c65b928cbe8d9c52b38cf57ba1722677645dc53fb1bdadfd0e127" -"checksum rustc-ap-serialize 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c290b148c9e4e08bbcb8a313393e257c1103cedf6a038aefc9f957c8a77c755" -"checksum rustc-ap-syntax 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "526fdc5bdbaaeae3b2a9ba42e5f5f7f29cda6ce8971b607a2955b1cb4ca339b5" -"checksum rustc-ap-syntax_pos 373.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e4f88a1213562373cee9de5a1d77bbf16dd706030304af041c9733492fcc952" -"checksum rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "82ae957aa1b3055d8e086486723c0ccd3d7b8fa190ae8fa2e35543b6171c810e" +"checksum rls-data 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76c72ea97e045be5f6290bb157ebdc5ee9f2b093831ff72adfaf59025cf5c491" +"checksum rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f1cb4694410d8d2ce43ccff3682f1c782158a018d5a9a92185675677f7533eb3" +"checksum rls-vfs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce4b57b25b4330ed5ec14028fc02141e083ddafda327e7eb598dc0569c8c83c9" +"checksum rustc-ap-arena 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc0ad4318f3425229ed7b117275368b83269bec75f9609d4965dcb9752483c86" +"checksum rustc-ap-graphviz 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b80b7ea7902919f397c4bb12d102abe896fced7893d09d84bcac233e555bb388" +"checksum rustc-ap-rustc_cratesio_shim 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "752463d2b80039d23e42e667a9f6fe08213bd865f6ea301fb35f8068d94955ac" +"checksum rustc-ap-rustc_data_structures 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c3d6a14181e11c132d0ef97a6c27e1bb1d4da09682d02222393875c10d1c364" +"checksum rustc-ap-rustc_errors 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55caea8426565de362e8df0df737e43b9f22d632e0e52710cbfe316acc6ce2f0" +"checksum rustc-ap-rustc_macros 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "071420d762d2c779d1d4972356f37f5d049dcdd6c49e78f1b037e04c5a0f1a19" +"checksum rustc-ap-rustc_target 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5464696d0748e3019b9e5daca5fcadc53889dc2bca1dc26bf42001fd1c4194f" +"checksum rustc-ap-serialize 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9464445c11c15cf32ef27815b3ec89315b0ed73c6c771cbcf8543be59a3c1502" +"checksum rustc-ap-syntax 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff53245ae370d8e8073dc9cc13f8921e6110d0ccd208b64c388c5653fa6b9c83" +"checksum rustc-ap-syntax_pos 491.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41896f0eb2eb2f4ddba406939aa6b07386160fa38bee8cde3f7f0d85663e3d47" +"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" -"checksum rustc-rayon 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d98c51d9cbbe810c8b6693236d3412d8cd60513ff27a3e1b6af483dca0af544" -"checksum rustc-rayon-core 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "526e7b6d2707a5b9bec3927d424ad70fa3cfc68e0ac1b75e46cdbbc95adc5108" +"checksum rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2e07e19601f21c59aad953c2632172ba70cb27e685771514ea66e4062b3363" +"checksum rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79d38ca7cbc22fa59f09d8534ea4b27f67b0facf0cbe274433aceea227a02543" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustc_tools_util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c5a95edfa0c893236ae4778bb7c4752760e4c0d245e19b5eff33c5aa5eb9dc" +"checksum rustc_tools_util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b725dadae9fabc488df69a287f5a99c5eaf5d10853842a8a3dfac52476f544ee" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustfix 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "af7c21531a91512a4a51b490be6ba1c8eff34fdda0dc5bf87dc28d86748aac56" -"checksum rusty-fork 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9591f190d2852720b679c21f66ad929f9f1d7bb09d1193c26167586029d8489c" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56" -"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" "checksum scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)" = "6fa52f19aee12441d5ad11c9a00459122bd8f98707cadf9778c540674f1935b6" +"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be" "checksum serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)" = "477b13b646f5b5b56fc95bedfc3b550d12141ce84f466f6c44b9a17589923885" "checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" "checksum serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "c37ccd6be3ed1fdf419ee848f7c758eb31b054d7cd3ae3600e3bae0adf569811" @@ -4217,26 +4477,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f272d1b7586bec132ed427f532dd418d8beca1ca7f2caf7df35569b1415a4b4" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" +"checksum sized-chunks 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2a2eb3fe454976eefb479f78f9b394d34d661b647c6326a3a6e66f68bb12c26" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" +"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7" "checksum stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa" "checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423" "checksum string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eea1eee654ef80933142157fdad9dd8bc43cf7c74e999e369263496f04ff4da" "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" +"checksum strip-ansi-escapes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d63676e2abafa709460982ddc02a3bb586b6d15a49b75c212e06edd3933acee" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" +"checksum structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fa19a5a708e22bb5be31c1b6108a2a902f909c4b9ba85cba44c06632386bc0ff" +"checksum structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d59d0ae8ef8de16e49e3ca7afa16024a3e0dfd974a75ef93fdc5464e34523f" "checksum strum 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c3a2071519ab6a48f465808c4c1ffdd00dfc8e93111d02b4fc5abab177676e" "checksum strum_macros 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8baacebd7b7c9b864d83a6ba7a246232983e277b86fa5cdec77f565715a4b136" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" +"checksum syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)" = "641e117d55514d6d918490e47102f7e08d096fdde360247e4a10f7a91a8478d3" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum tar 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "a303ba60a099fcd2aaa646b14d2724591a96a75283e4b7ed3d1a1658909d9ae2" "checksum tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2" "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" +"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" +"checksum tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e812cb26c597f86a49b26dbb58b878bd2a2b4b93fc069dc39499228fe556ff6" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" @@ -4255,11 +4521,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" "checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039" "checksum toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6854664bfc6df0360c695480836ee90e2d0c965f06db291d10be9344792d43e8" -"checksum toml-query 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab234a943a2363ad774020e2f9474a38a85bc4396bace01a96380144aef17db3" +"checksum toml-query 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a24369a1894ac8224efcfd567c3d141aea360292f49888e7ec7dcc316527aebb" +"checksum toml-query_derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c99ca245ec273c7e75c8ee58f47b882d0146f3c2c8495158082c6671e8b5335" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" +"checksum unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84e5511b2a947f3ae965dcb29b13b7b1691b6e7332cf5dbc1744138d5acb7f6" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" @@ -4267,23 +4536,22 @@ 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" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" +"checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" "checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" "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 wait-timeout 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b9f3bf741a801531993db6478b95682117471f76916f5e690dd8d45395b09349" +"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" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/Cargo.toml b/Cargo.toml index cb3c0ee194fe2..ccd7e8b7654a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,6 +67,7 @@ rustc-workspace-hack = { path = 'src/tools/rustc-workspace-hack' } # See comments in `tools/rustc-std-workspace-core/README.md` for what's going on # here rustc-std-workspace-core = { path = 'src/tools/rustc-std-workspace-core' } +rustc-std-workspace-alloc = { path = 'src/tools/rustc-std-workspace-alloc' } [patch."https://github.com/rust-lang/rust-clippy"] clippy_lints = { path = "src/tools/clippy/clippy_lints" } diff --git a/README.md b/README.md index 59ba087810b40..bb1d4b1684e5d 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,22 @@ of the rustc-guide instead._ $ ./x.py build && sudo ./x.py install ``` + If after running `sudo ./x.py install` you see an error message like + + ``` + error: failed to load source for a dependency on 'cc' + ``` + + then run these two commands and then try `sudo ./x.py install` again: + + ``` + $ cargo install cargo-vendor + ``` + + ``` + $ cargo vendor + ``` + > ***Note:*** Install locations can be adjusted by copying the config file > from `./config.toml.example` to `./config.toml`, and > adjusting the `prefix` option under `[install]`. Various other options, such @@ -118,9 +134,14 @@ build. #### MSVC [windows-msvc]: #windows-msvc -MSVC builds of Rust additionally require an installation of Visual Studio 2013 -(or later) so `rustc` can use its linker. Make sure to check the “C++ tools” -option. +MSVC builds of Rust additionally require an installation of Visual Studio 2017 +(or later) so `rustc` can use its linker. The simplest way is to get the +[Visual Studio], check the “C++ build tools” and “Windows 10 SDK” workload. + +[Visual Studio]: https://visualstudio.microsoft.com/downloads/ + +(If you're installing cmake yourself, be careful that “C++ CMake tools for +Windows” doesn't get included under “Individual components”.) With these dependencies installed, you can build the compiler in a `cmd.exe` shell with: @@ -135,7 +156,7 @@ then you may need to force rustbuild to use an older version. This can be done by manually calling the appropriate vcvars file before running the bootstrap. ```batch -> CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" +> CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars64.bat" > python x.py build ``` @@ -251,3 +272,19 @@ BSD-like licenses. See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and [COPYRIGHT](COPYRIGHT) for details. + +## Trademark +[trademark]: #trademark + +The Rust programming language is an open source, community project governed +by a core team. It is also sponsored by the Mozilla Foundation (“Mozilla”), +which owns and protects the Rust and Cargo trademarks and logos +(the “Rust Trademarks”). + +If you want to use these names or brands, please read the [media guide][media-guide]. + +Third-party logos may be subject to third-party copyrights and trademarks. See +[Licenses][policies-licenses] for details. + +[media-guide]: https://www.rust-lang.org/policies/media-guide +[policies-licenses]: https://www.rust-lang.org/policies/licenses diff --git a/RELEASES.md b/RELEASES.md index 841467b69c986..6049a8ef4c9ea 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,13 +1,498 @@ +Version 1.37.0 (2019-08-15) +========================== + +Language +-------- +- `#[must_use]` will now warn if the type is contained in a [tuple][61100], + [`Box`][62228], or an [array][62235] and unused. +- [You can now use the `cfg` and `cfg_attr` attributes on + generic parameters.][61547] +- [You can now use enum variants through type alias.][61682] e.g. You can + write the following: + ```rust + type MyOption = Option; + + fn increment_or_zero(x: MyOption) -> u8 { + match x { + MyOption::Some(y) => y + 1, + MyOption::None => 0, + } + } + ``` +- [You can now use `_` as an identifier for consts.][61347] e.g. You can write + `const _: u32 = 5;`. +- [You can now use `#[repr(align(X)]` on enums.][61229] +- [The `?`/_"Kleene"_ macro operator is now available in the + 2015 edition.][60932] + +Compiler +-------- +- [You can now enable Profile-Guided Optimization with the `-C profile-generate` + and `-C profile-use` flags.][61268] For more information on how to use profile + guided optimization, please refer to the [rustc book][rustc-book-pgo]. +- [The `rust-lldb` wrapper script should now work again.][61827] + +Libraries +--------- +- [`mem::MaybeUninit` is now ABI-compatible with `T`.][61802] + +Stabilized APIs +--------------- +- [`BufReader::buffer`] +- [`BufWriter::buffer`] +- [`Cell::from_mut`] +- [`Cell<[T]>::as_slice_of_cells`][`Cell::as_slice_of_cells`] +- [`DoubleEndedIterator::nth_back`] +- [`Option::xor`] +- [`Wrapping::reverse_bits`] +- [`i128::reverse_bits`] +- [`i16::reverse_bits`] +- [`i32::reverse_bits`] +- [`i64::reverse_bits`] +- [`i8::reverse_bits`] +- [`isize::reverse_bits`] +- [`slice::copy_within`] +- [`u128::reverse_bits`] +- [`u16::reverse_bits`] +- [`u32::reverse_bits`] +- [`u64::reverse_bits`] +- [`u8::reverse_bits`] +- [`usize::reverse_bits`] + +Cargo +----- +- [`Cargo.lock` files are now included by default when publishing executable crates + with executables.][cargo/7026] +- [You can now specify `default-run="foo"` in `[package]` to specify the + default executable to use for `cargo run`.][cargo/7056] + +Misc +---- + +Compatibility Notes +------------------- +- [Using `...` for inclusive range patterns will now warn by default.][61342] + Please transition your code to using the `..=` syntax for inclusive + ranges instead. +- [Using a trait object without the `dyn` will now warn by default.][61203] + Please transition your code to use `dyn Trait` for trait objects instead. + +[62228]: https://github.com/rust-lang/rust/pull/62228/ +[62235]: https://github.com/rust-lang/rust/pull/62235/ +[61802]: https://github.com/rust-lang/rust/pull/61802/ +[61827]: https://github.com/rust-lang/rust/pull/61827/ +[61547]: https://github.com/rust-lang/rust/pull/61547/ +[61682]: https://github.com/rust-lang/rust/pull/61682/ +[61268]: https://github.com/rust-lang/rust/pull/61268/ +[61342]: https://github.com/rust-lang/rust/pull/61342/ +[61347]: https://github.com/rust-lang/rust/pull/61347/ +[61100]: https://github.com/rust-lang/rust/pull/61100/ +[61203]: https://github.com/rust-lang/rust/pull/61203/ +[61229]: https://github.com/rust-lang/rust/pull/61229/ +[60932]: https://github.com/rust-lang/rust/pull/60932/ +[cargo/7026]: https://github.com/rust-lang/cargo/pull/7026/ +[cargo/7056]: https://github.com/rust-lang/cargo/pull/7056/ +[`BufReader::buffer`]: https://doc.rust-lang.org/std/io/struct.BufReader.html#method.buffer +[`BufWriter::buffer`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html#method.buffer +[`Cell::from_mut`]: https://doc.rust-lang.org/std/cell/struct.Cell.html#method.from_mut +[`Cell::as_slice_of_cells`]: https://doc.rust-lang.org/std/cell/struct.Cell.html#method.as_slice_of_cells +[`DoubleEndedIterator::nth_back`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.nth_back +[`Option::xor`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.xor +[`RefCell::try_borrow_unguarded`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow_unguarded +[`Wrapping::reverse_bits`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html#method.reverse_bits +[`i128::reverse_bits`]: https://doc.rust-lang.org/std/primitive.i128.html#method.reverse_bits +[`i16::reverse_bits`]: https://doc.rust-lang.org/std/primitive.i16.html#method.reverse_bits +[`i32::reverse_bits`]: https://doc.rust-lang.org/std/primitive.i32.html#method.reverse_bits +[`i64::reverse_bits`]: https://doc.rust-lang.org/std/primitive.i64.html#method.reverse_bits +[`i8::reverse_bits`]: https://doc.rust-lang.org/std/primitive.i8.html#method.reverse_bits +[`isize::reverse_bits`]: https://doc.rust-lang.org/std/primitive.isize.html#method.reverse_bits +[`slice::copy_within`]: https://doc.rust-lang.org/std/primitive.slice.html#method.copy_within +[`u128::reverse_bits`]: https://doc.rust-lang.org/std/primitive.u128.html#method.reverse_bits +[`u16::reverse_bits`]: https://doc.rust-lang.org/std/primitive.u16.html#method.reverse_bits +[`u32::reverse_bits`]: https://doc.rust-lang.org/std/primitive.u32.html#method.reverse_bits +[`u64::reverse_bits`]: https://doc.rust-lang.org/std/primitive.u64.html#method.reverse_bits +[`u8::reverse_bits`]: https://doc.rust-lang.org/std/primitive.u8.html#method.reverse_bits +[`usize::reverse_bits`]: https://doc.rust-lang.org/std/primitive.usize.html#method.reverse_bits +[rustc-book-pgo]: https://doc.rust-lang.org/rustc/profile-guided-optimization.html + + +Version 1.36.0 (2019-07-04) +========================== + +Language +-------- +- [Non-Lexical Lifetimes are now enabled on the 2015 edition.][59114] +- [The order of traits in trait objects no longer affects the semantics of that + object.][59445] e.g. `dyn Send + fmt::Debug` is now equivalent to + `dyn fmt::Debug + Send`, where this was previously not the case. + +Libraries +--------- +- [`HashMap`'s implementation has been replaced with `hashbrown::HashMap` implementation.][58623] +- [`TryFromSliceError` now implements `From`.][60318] +- [`mem::needs_drop` is now available as a const fn.][60364] +- [`alloc::Layout::from_size_align_unchecked` is now available as a const fn.][60370] +- [`String` now implements `BorrowMut`.][60404] +- [`io::Cursor` now implements `Default`.][60234] +- [Both `NonNull::{dangling, cast}` are now const fns.][60244] +- [The `alloc` crate is now stable.][59675] `alloc` allows you to use a subset + of `std` (e.g. `Vec`, `Box`, `Arc`) in `#![no_std]` environments if the + environment has access to heap memory allocation. +- [`String` now implements `From<&String>`.][59825] +- [You can now pass multiple arguments to the `dbg!` macro.][59826] `dbg!` will + return a tuple of each argument when there is multiple arguments. +- [`Result::{is_err, is_ok}` are now `#[must_use]` and will produce a warning if + not used.][59648] + +Stabilized APIs +--------------- +- [`VecDeque::rotate_left`] +- [`VecDeque::rotate_right`] +- [`Iterator::copied`] +- [`io::IoSlice`] +- [`io::IoSliceMut`] +- [`Read::read_vectored`] +- [`Write::write_vectored`] +- [`str::as_mut_ptr`] +- [`mem::MaybeUninit`] +- [`pointer::align_offset`] +- [`future::Future`] +- [`task::Context`] +- [`task::RawWaker`] +- [`task::RawWakerVTable`] +- [`task::Waker`] +- [`task::Poll`] + +Cargo +----- +- [Cargo will now produce an error if you attempt to use the name of a required dependency as a feature.][cargo/6860] +- [You can now pass the `--offline` flag to run cargo without accessing the network.][cargo/6934] + +You can find further change's in [Cargo's 1.36.0 release notes][cargo-1-36-0]. + +Clippy +------ +There have been numerous additions and fixes to clippy, see [Clippy's 1.36.0 release notes][clippy-1-36-0] for more details. + +Misc +---- + +Compatibility Notes +------------------- +- [`std::arch::x86::_rdtsc` returns `u64` instead of `i64`][stdsimd/559] +- [`std::arch::x86_64::_mm_shuffle_ps` takes an `i32` instead of `u32` for `mask`][stdsimd/522] +- With the stabilisation of `mem::MaybeUninit`, `mem::uninitialized` use is no + longer recommended, and will be deprecated in 1.38.0. + +[60318]: https://github.com/rust-lang/rust/pull/60318/ +[60364]: https://github.com/rust-lang/rust/pull/60364/ +[60370]: https://github.com/rust-lang/rust/pull/60370/ +[60404]: https://github.com/rust-lang/rust/pull/60404/ +[60234]: https://github.com/rust-lang/rust/pull/60234/ +[60244]: https://github.com/rust-lang/rust/pull/60244/ +[58623]: https://github.com/rust-lang/rust/pull/58623/ +[59648]: https://github.com/rust-lang/rust/pull/59648/ +[59675]: https://github.com/rust-lang/rust/pull/59675/ +[59825]: https://github.com/rust-lang/rust/pull/59825/ +[59826]: https://github.com/rust-lang/rust/pull/59826/ +[59445]: https://github.com/rust-lang/rust/pull/59445/ +[59114]: https://github.com/rust-lang/rust/pull/59114/ +[cargo/6860]: https://github.com/rust-lang/cargo/pull/6860/ +[cargo/6934]: https://github.com/rust-lang/cargo/pull/6934/ +[`VecDeque::rotate_left`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.rotate_left +[`VecDeque::rotate_right`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.rotate_right +[`Iterator::copied`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.copied +[`io::IoSlice`]: https://doc.rust-lang.org/std/io/struct.IoSlice.html +[`io::IoSliceMut`]: https://doc.rust-lang.org/std/io/struct.IoSliceMut.html +[`Read::read_vectored`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_vectored +[`Write::write_vectored`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_vectored +[`str::as_mut_ptr`]: https://doc.rust-lang.org/std/primitive.str.html#method.as_mut_ptr +[`mem::MaybeUninit`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html +[`pointer::align_offset`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.align_offset +[`future::Future`]: https://doc.rust-lang.org/std/future/trait.Future.html +[`task::Context`]: https://doc.rust-lang.org/beta/std/task/struct.Context.html +[`task::RawWaker`]: https://doc.rust-lang.org/beta/std/task/struct.RawWaker.html +[`task::RawWakerVTable`]: https://doc.rust-lang.org/beta/std/task/struct.RawWakerVTable.html +[`task::Waker`]: https://doc.rust-lang.org/beta/std/task/struct.Waker.html +[`task::Poll`]: https://doc.rust-lang.org/beta/std/task/enum.Poll.html +[clippy-1-36-0]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md#rust-136 +[cargo-1-36-0]: https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-136-2019-07-04 +[stdsimd/522]: https://github.com/rust-lang-nursery/stdsimd/issues/522 +[stdsimd/559]: https://github.com/rust-lang-nursery/stdsimd/issues/559 + +Version 1.35.0 (2019-05-23) +========================== + +Language +-------- +- [`FnOnce`, `FnMut`, and the `Fn` traits are now implemented for `Box`, + `Box`, and `Box` respectively.][59500] +- [You can now coerce closures into unsafe function pointers.][59580] e.g. + ```rust + unsafe fn call_unsafe(func: unsafe fn()) { + func() + } + + pub fn main() { + unsafe { call_unsafe(|| {}); } + } + ``` + + +Compiler +-------- +- [Added the `armv6-unknown-freebsd-gnueabihf` and + `armv7-unknown-freebsd-gnueabihf` targets.][58080] +- [Added the `wasm32-unknown-wasi` target.][59464] + + +Libraries +--------- +- [`Thread` will now show its ID in `Debug` output.][59460] +- [`StdinLock`, `StdoutLock`, and `StderrLock` now implement `AsRawFd`.][59512] +- [`alloc::System` now implements `Default`.][59451] +- [Expanded `Debug` output (`{:#?}`) for structs now has a trailing comma on the + last field.][59076] +- [`char::{ToLowercase, ToUppercase}` now + implement `ExactSizeIterator`.][58778] +- [All `NonZero` numeric types now implement `FromStr`.][58717] +- [Removed the `Read` trait bounds + on the `BufReader::{get_ref, get_mut, into_inner}` methods.][58423] +- [You can now call the `dbg!` macro without any parameters to print the file + and line where it is called.][57847] +- [In place ASCII case conversions are now up to 4× faster.][59283] + e.g. `str::make_ascii_lowercase` +- [`hash_map::{OccupiedEntry, VacantEntry}` now implement `Sync` + and `Send`.][58369] + +Stabilized APIs +--------------- +- [`f32::copysign`] +- [`f64::copysign`] +- [`RefCell::replace_with`] +- [`RefCell::map_split`] +- [`ptr::hash`] +- [`Range::contains`] +- [`RangeFrom::contains`] +- [`RangeTo::contains`] +- [`RangeInclusive::contains`] +- [`RangeToInclusive::contains`] +- [`Option::copied`] + +Cargo +----- +- [You can now set `cargo:rustc-cdylib-link-arg` at build time to pass custom + linker arguments when building a `cdylib`.][cargo/6298] Its usage is highly + platform specific. + +Misc +---- +- [The Rust toolchain is now available natively for musl based distros.][58575] + +[59460]: https://github.com/rust-lang/rust/pull/59460/ +[59464]: https://github.com/rust-lang/rust/pull/59464/ +[59500]: https://github.com/rust-lang/rust/pull/59500/ +[59512]: https://github.com/rust-lang/rust/pull/59512/ +[59580]: https://github.com/rust-lang/rust/pull/59580/ +[59283]: https://github.com/rust-lang/rust/pull/59283/ +[59451]: https://github.com/rust-lang/rust/pull/59451/ +[59076]: https://github.com/rust-lang/rust/pull/59076/ +[58778]: https://github.com/rust-lang/rust/pull/58778/ +[58717]: https://github.com/rust-lang/rust/pull/58717/ +[58369]: https://github.com/rust-lang/rust/pull/58369/ +[58423]: https://github.com/rust-lang/rust/pull/58423/ +[58080]: https://github.com/rust-lang/rust/pull/58080/ +[57847]: https://github.com/rust-lang/rust/pull/57847/ +[58575]: https://github.com/rust-lang/rust/pull/58575 +[cargo/6298]: https://github.com/rust-lang/cargo/pull/6298/ +[`f32::copysign`]: https://doc.rust-lang.org/stable/std/primitive.f32.html#method.copysign +[`f64::copysign`]: https://doc.rust-lang.org/stable/std/primitive.f64.html#method.copysign +[`RefCell::replace_with`]: https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html#method.replace_with +[`RefCell::map_split`]: https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html#method.map_split +[`ptr::hash`]: https://doc.rust-lang.org/stable/std/ptr/fn.hash.html +[`Range::contains`]: https://doc.rust-lang.org/std/ops/struct.Range.html#method.contains +[`RangeFrom::contains`]: https://doc.rust-lang.org/std/ops/struct.RangeFrom.html#method.contains +[`RangeTo::contains`]: https://doc.rust-lang.org/std/ops/struct.RangeTo.html#method.contains +[`RangeInclusive::contains`]: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html#method.contains +[`RangeToInclusive::contains`]: https://doc.rust-lang.org/std/ops/struct.RangeToInclusive.html#method.contains +[`Option::copied`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.copied + +Version 1.34.2 (2019-05-14) +=========================== + +* [Destabilize the `Error::type_id` function due to a security + vulnerability][60785] ([CVE-2019-12083]) + +[60785]: https://github.com/rust-lang/rust/pull/60785 +[CVE-2019-12083]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-12083 + +Version 1.34.1 (2019-04-25) +=========================== + +* [Fix false positives for the `redundant_closure` Clippy lint][clippy/3821] +* [Fix false positives for the `missing_const_for_fn` Clippy lint][clippy/3844] +* [Fix Clippy panic when checking some macros][clippy/3805] + +[clippy/3821]: https://github.com/rust-lang/rust-clippy/pull/3821 +[clippy/3844]: https://github.com/rust-lang/rust-clippy/pull/3844 +[clippy/3805]: https://github.com/rust-lang/rust-clippy/pull/3805 + +Version 1.34.0 (2019-04-11) +========================== + +Language +-------- +- [You can now use `#[deprecated = "reason"]`][58166] as a shorthand for + `#[deprecated(note = "reason")]`. This was previously allowed by mistake + but had no effect. +- [You can now accept token streams in `#[attr()]`,`#[attr[]]`, and + `#[attr{}]` procedural macros.][57367] +- [You can now write `extern crate self as foo;`][57407] to import your + crate's root into the extern prelude. + + +Compiler +-------- +- [You can now target `riscv64imac-unknown-none-elf` and + `riscv64gc-unknown-none-elf`.][58406] +- [You can now enable linker plugin LTO optimisations with + `-C linker-plugin-lto`.][58057] This allows rustc to compile your Rust code + into LLVM bitcode allowing LLVM to perform LTO optimisations across C/C++ FFI + boundaries. +- [You can now target `powerpc64-unknown-freebsd`.][57809] + + +Libraries +--------- +- [The trait bounds have been removed on some of `HashMap`'s and + `HashSet`'s basic methods.][58370] Most notably you no longer require + the `Hash` trait to create an iterator. +- [The `Ord` trait bounds have been removed on some of `BinaryHeap`'s basic + methods.][58421] Most notably you no longer require the `Ord` trait to create + an iterator. +- [The methods `overflowing_neg` and `wrapping_neg` are now `const` functions + for all numeric types.][58044] +- [Indexing a `str` is now generic over all types that + implement `SliceIndex`.][57604] +- [`str::trim`, `str::trim_matches`, `str::trim_{start, end}`, and + `str::trim_{start, end}_matches` are now `#[must_use]`][57106] and will + produce a warning if their returning type is unused. +- [The methods `checked_pow`, `saturating_pow`, `wrapping_pow`, and + `overflowing_pow` are now available for all numeric types.][57873] These are + equivalent to methods such as `wrapping_add` for the `pow` operation. + + +Stabilized APIs +--------------- + +#### std & core +* [`Any::type_id`] +* [`Error::type_id`] +* [`atomic::AtomicI16`] +* [`atomic::AtomicI32`] +* [`atomic::AtomicI64`] +* [`atomic::AtomicI8`] +* [`atomic::AtomicU16`] +* [`atomic::AtomicU32`] +* [`atomic::AtomicU64`] +* [`atomic::AtomicU8`] +* [`convert::Infallible`] +* [`convert::TryFrom`] +* [`convert::TryInto`] +* [`iter::from_fn`] +* [`iter::successors`] +* [`num::NonZeroI128`] +* [`num::NonZeroI16`] +* [`num::NonZeroI32`] +* [`num::NonZeroI64`] +* [`num::NonZeroI8`] +* [`num::NonZeroIsize`] +* [`slice::sort_by_cached_key`] +* [`str::escape_debug`] +* [`str::escape_default`] +* [`str::escape_unicode`] +* [`str::split_ascii_whitespace`] + +#### std +* [`Instant::checked_add`] +* [`Instant::checked_sub`] +* [`SystemTime::checked_add`] +* [`SystemTime::checked_sub`] + +Cargo +----- +- [You can now use alternative registries to crates.io.][cargo/6654] + +Misc +---- +- [You can now use the `?` operator in your documentation tests without manually + adding `fn main() -> Result<(), _> {}`.][56470] + +Compatibility Notes +------------------- +- [`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/ +[58406]: https://github.com/rust-lang/rust/pull/58406/ +[58421]: https://github.com/rust-lang/rust/pull/58421/ +[58166]: https://github.com/rust-lang/rust/pull/58166/ +[58044]: https://github.com/rust-lang/rust/pull/58044/ +[58057]: https://github.com/rust-lang/rust/pull/58057/ +[58059]: https://github.com/rust-lang/rust/pull/58059/ +[57809]: https://github.com/rust-lang/rust/pull/57809/ +[57873]: https://github.com/rust-lang/rust/pull/57873/ +[57604]: https://github.com/rust-lang/rust/pull/57604/ +[57367]: https://github.com/rust-lang/rust/pull/57367/ +[57407]: https://github.com/rust-lang/rust/pull/57407/ +[57425]: https://github.com/rust-lang/rust/pull/57425/ +[57106]: https://github.com/rust-lang/rust/pull/57106/ +[56470]: https://github.com/rust-lang/rust/pull/56470/ +[cargo/6654]: https://github.com/rust-lang/cargo/pull/6654/ +[`Any::type_id`]: https://doc.rust-lang.org/std/any/trait.Any.html#tymethod.type_id +[`Error::type_id`]: https://doc.rust-lang.org/std/error/trait.Error.html#method.type_id +[`atomic::AtomicI16`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicI16.html +[`atomic::AtomicI32`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicI32.html +[`atomic::AtomicI64`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicI64.html +[`atomic::AtomicI8`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicI8.html +[`atomic::AtomicU16`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicU16.html +[`atomic::AtomicU32`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicU32.html +[`atomic::AtomicU64`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicU64.html +[`atomic::AtomicU8`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicU8.html +[`convert::Infallible`]: https://doc.rust-lang.org/std/convert/enum.Infallible.html +[`convert::TryFrom`]: https://doc.rust-lang.org/std/convert/trait.TryFrom.html +[`convert::TryInto`]: https://doc.rust-lang.org/std/convert/trait.TryInto.html +[`iter::from_fn`]: https://doc.rust-lang.org/std/iter/fn.from_fn.html +[`iter::successors`]: https://doc.rust-lang.org/std/iter/fn.successors.html +[`num::NonZeroI128`]: https://doc.rust-lang.org/std/num/struct.NonZeroI128.html +[`num::NonZeroI16`]: https://doc.rust-lang.org/std/num/struct.NonZeroI16.html +[`num::NonZeroI32`]: https://doc.rust-lang.org/std/num/struct.NonZeroI32.html +[`num::NonZeroI64`]: https://doc.rust-lang.org/std/num/struct.NonZeroI64.html +[`num::NonZeroI8`]: https://doc.rust-lang.org/std/num/struct.NonZeroI8.html +[`num::NonZeroIsize`]: https://doc.rust-lang.org/std/num/struct.NonZeroIsize.html +[`slice::sort_by_cached_key`]: https://doc.rust-lang.org/std/primitive.slice.html#method.sort_by_cached_key +[`str::escape_debug`]: https://doc.rust-lang.org/std/primitive.str.html#method.escape_debug +[`str::escape_default`]: https://doc.rust-lang.org/std/primitive.str.html#method.escape_default +[`str::escape_unicode`]: https://doc.rust-lang.org/std/primitive.str.html#method.escape_unicode +[`str::split_ascii_whitespace`]: https://doc.rust-lang.org/std/primitive.str.html#method.split_ascii_whitespace +[`Instant::checked_add`]: https://doc.rust-lang.org/std/time/struct.Instant.html#method.checked_add +[`Instant::checked_sub`]: https://doc.rust-lang.org/std/time/struct.Instant.html#method.checked_sub +[`SystemTime::checked_add`]: https://doc.rust-lang.org/std/time/struct.SystemTime.html#method.checked_add +[`SystemTime::checked_sub`]: https://doc.rust-lang.org/std/time/struct.SystemTime.html#method.checked_sub + + Version 1.33.0 (2019-02-28) ========================== Language -------- - [You can now use the `cfg(target_vendor)` attribute.][57465] E.g. - `#[cfg(target_vendor="linux")] fn main() { println!("Hello Linux!"); }` + `#[cfg(target_vendor="apple")] fn main() { println!("Hello Apple!"); }` - [Integer patterns such as in a match expression can now be exhaustive.][56362] E.g. You can have match statement on a `u8` that covers `0..=255` and - you would no longer be required to have a `_ => unreachable!()` case. + you would no longer be required to have a `_ => unreachable!()` case. - [You can now have multiple patterns in `if let` and `while let` expressions.][57532] You can do this with the same syntax as a `match` expression. E.g. @@ -51,8 +536,7 @@ Language // Allowed as there is only one `Read` in the module. pub trait Read {} ``` -- [`extern` functions will now abort by default when panicking.][55982] - This was previously undefined behaviour. +- [You may now use `Rc`, `Arc`, and `Pin` as method receivers][56805]. Compiler -------- @@ -100,6 +584,8 @@ Stabilized APIs Cargo ----- +- [You can now publish crates that require a feature flag to compile with + `cargo publish --features` or `cargo publish --all-features`.][cargo/6453] - [Cargo should now rebuild a crate if a file was modified during the initial build.][cargo/6484] @@ -109,27 +595,34 @@ Compatibility Notes are now deprecated in the standard library, and their usage will now produce a warning. Please use the `str::{trim_start, trim_end, trim_start_matches, trim_end_matches}` methods instead. +- The `Error::cause` method has been deprecated in favor of `Error::source` which supports + downcasting. +- [Libtest no longer creates a new thread for each test when + `--test-threads=1`. It also runs the tests in deterministic order][56243] -[57615]: https://github.com/rust-lang/rust/pull/57615/ -[57465]: https://github.com/rust-lang/rust/pull/57465/ -[57532]: https://github.com/rust-lang/rust/pull/57532/ -[57535]: https://github.com/rust-lang/rust/pull/57535/ -[57566]: https://github.com/rust-lang/rust/pull/57566/ +[55982]: https://github.com/rust-lang/rust/pull/55982/ +[56243]: https://github.com/rust-lang/rust/pull/56243 +[56303]: https://github.com/rust-lang/rust/pull/56303/ +[56351]: https://github.com/rust-lang/rust/pull/56351/ +[56362]: https://github.com/rust-lang/rust/pull/56362 +[56642]: https://github.com/rust-lang/rust/pull/56642/ +[56769]: https://github.com/rust-lang/rust/pull/56769/ +[56805]: https://github.com/rust-lang/rust/pull/56805 +[56947]: https://github.com/rust-lang/rust/pull/56947/ +[57049]: https://github.com/rust-lang/rust/pull/57049/ +[57067]: https://github.com/rust-lang/rust/pull/57067/ +[57105]: https://github.com/rust-lang/rust/pull/57105 [57130]: https://github.com/rust-lang/rust/pull/57130/ [57167]: https://github.com/rust-lang/rust/pull/57167/ [57175]: https://github.com/rust-lang/rust/pull/57175/ [57234]: https://github.com/rust-lang/rust/pull/57234/ [57332]: https://github.com/rust-lang/rust/pull/57332/ -[56947]: https://github.com/rust-lang/rust/pull/56947/ -[57049]: https://github.com/rust-lang/rust/pull/57049/ -[57067]: https://github.com/rust-lang/rust/pull/57067/ -[56769]: https://github.com/rust-lang/rust/pull/56769/ -[56642]: https://github.com/rust-lang/rust/pull/56642/ -[56303]: https://github.com/rust-lang/rust/pull/56303/ -[56351]: https://github.com/rust-lang/rust/pull/56351/ -[55982]: https://github.com/rust-lang/rust/pull/55982/ -[56362]: https://github.com/rust-lang/rust/pull/56362 -[57105]: https://github.com/rust-lang/rust/pull/57105 +[57465]: https://github.com/rust-lang/rust/pull/57465/ +[57532]: https://github.com/rust-lang/rust/pull/57532/ +[57535]: https://github.com/rust-lang/rust/pull/57535/ +[57566]: https://github.com/rust-lang/rust/pull/57566/ +[57615]: https://github.com/rust-lang/rust/pull/57615/ +[cargo/6453]: https://github.com/rust-lang/cargo/pull/6453/ [cargo/6484]: https://github.com/rust-lang/cargo/pull/6484/ [`unix::FileExt::read_exact_at`]: https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html#method.read_exact_at [`unix::FileExt::write_all_at`]: https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html#method.write_all_at @@ -170,7 +663,7 @@ Language - [You can now match against literals in macros with the `literal` specifier.][56072] This will match against a literal of any type. E.g. `1`, `'A'`, `"Hello World"` -- [Self can now be used as a constructor and pattern for unit and tuple structs.][56365] E.g. +- [Self can now be used as a constructor and pattern for unit and tuple structs.][56365] E.g. ```rust struct Point(i32, i32); @@ -460,7 +953,7 @@ Version 1.31.0 (2018-12-06) Language -------- -- 🎉 [This version marks the release of the 2018 edition of Rust.][54057] 🎉 +- 🎉 [This version marks the release of the 2018 edition of Rust.][54057] 🎉 - [New lifetime elision rules now allow for eliding lifetimes in functions and impl headers.][54778] E.g. `impl<'a> Reader for BufReader<'a> {}` can now be `impl Reader for BufReader<'_> {}`. Lifetimes are still required to be defined diff --git a/appveyor.yml b/appveyor.yml index 3a0cb8b4fceea..003de85184c32 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,267 +1,9 @@ -environment: - - # 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 - - # Execute the builds on GCE instead of Hyper-V. Those builders have a 3-4 - # minute startup overhead, but AppVeyor support recommended this as a - # possible solution for #58160 (spurious 259 exit codes) - appveyor_build_worker_cloud: gce - - matrix: - # 32/64 bit MSVC tests - - MSYS_BITS: 64 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler - SCRIPT: python x.py test - CI_JOB_NAME: x86_64-msvc - - MSYS_BITS: 32 - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc - SCRIPT: make appveyor-subset-1 - CI_JOB_NAME: i686-msvc-1 - - MSYS_BITS: 32 - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc - SCRIPT: make appveyor-subset-2 - CI_JOB_NAME: i686-msvc-2 - - # MSVC aux tests - - MSYS_BITS: 64 - RUST_CHECK_TARGET: check-aux EXCLUDE_CARGO=1 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc - CI_JOB_NAME: x86_64-msvc-aux - - MSYS_BITS: 64 - SCRIPT: python x.py test src/tools/cargotest src/tools/cargo - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc - CI_JOB_NAME: x86_64-msvc-cargo - - # MSVC tools tests - - 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 - CI_JOB_NAME: x86_64-msvc-tools - - # 32/64-bit MinGW builds. - # - # We are using MinGW with posix threads since LLVM does not compile with - # the win32 threads version due to missing support for C++'s std::thread. - # - # Instead of relying on the MinGW version installed on appveryor we download - # and install one ourselves so we won't be surprised by changes to appveyor's - # build image. - # - # Finally, note that the downloads below are all in the `rust-lang-ci` S3 - # bucket, but they cleraly didn't originate there! The downloads originally - # came from the mingw-w64 SourceForge download site. Unfortunately - # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. - - MSYS_BITS: 32 - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu - SCRIPT: make appveyor-subset-1 - MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror - MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z - MINGW_DIR: mingw32 - CI_JOB_NAME: i686-mingw-1 - - MSYS_BITS: 32 - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu - SCRIPT: make appveyor-subset-2 - MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror - MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z - MINGW_DIR: mingw32 - CI_JOB_NAME: i686-mingw-2 - - MSYS_BITS: 64 - SCRIPT: python x.py test - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror - MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z - MINGW_DIR: mingw64 - CI_JOB_NAME: x86_64-mingw - - # 32/64 bit MSVC and GNU deployment - - RUST_CONFIGURE_ARGS: > - --build=x86_64-pc-windows-msvc - --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc - --enable-full-tools - --enable-profiler - SCRIPT: python x.py dist - DIST_REQUIRE_ALL_TOOLS: 1 - DEPLOY: 1 - CI_JOB_NAME: dist-x86_64-msvc - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 Preview - - RUST_CONFIGURE_ARGS: > - --build=i686-pc-windows-msvc - --target=i586-pc-windows-msvc - --enable-full-tools - --enable-profiler - SCRIPT: python x.py dist - DIST_REQUIRE_ALL_TOOLS: 1 - DEPLOY: 1 - CI_JOB_NAME: dist-i686-msvc - - MSYS_BITS: 32 - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools - SCRIPT: python x.py dist - MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror - MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z - MINGW_DIR: mingw32 - DIST_REQUIRE_ALL_TOOLS: 1 - DEPLOY: 1 - CI_JOB_NAME: dist-i686-mingw - - MSYS_BITS: 64 - SCRIPT: python x.py dist - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools - MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror - MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z - MINGW_DIR: mingw64 - DIST_REQUIRE_ALL_TOOLS: 1 - DEPLOY: 1 - CI_JOB_NAME: dist-x86_64-mingw - - # "alternate" deployment, see .travis.yml for more info - - MSYS_BITS: 64 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler - SCRIPT: python x.py dist - DEPLOY_ALT: 1 - CI_JOB_NAME: dist-x86_64-msvc-alt - -matrix: - fast_finish: true - -clone_depth: 2 +clone_depth: 1 build: false -install: - # 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/7.0.0/LLVM-7.0.0-win64.exe - - if NOT defined MINGW_URL appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/LLVM-7.0.0-win64.exe - - if NOT defined MINGW_URL .\LLVM-7.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://s3-us-west-1.amazonaws.com/rust-lang-ci2/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://s3-us-west-1.amazonaws.com/rust-lang-ci2/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://s3-us-west-1.amazonaws.com/rust-lang-ci2/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://s3-us-west-1.amazonaws.com/rust-lang-ci2/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 - -on_failure: - # Dump crash log - - set PATH=%PATH%;"C:\Program Files (x86)\Windows Kits\10\Debuggers\X64" - - if exist %LOCALAPPDATA%\CrashDumps for %%f in (%LOCALAPPDATA%\CrashDumps\*) do cdb -c "k;q" -G -z "%%f" + - echo AppVeyor is not used anymore branches: only: - auto - -before_deploy: - - ps: | - New-Item -Path deploy -ItemType directory - Remove-Item -Recurse -Force build\dist\doc - Get-ChildItem -Path build\dist | Move-Item -Destination deploy - Get-ChildItem -Path deploy | Foreach-Object { - Push-AppveyorArtifact $_.FullName -FileName ${env:APPVEYOR_REPO_COMMIT}/$_ - } - -deploy: - - provider: S3 - access_key_id: $(AWS_ACCESS_KEY_ID) - secret_access_key: $(AWS_SECRET_ACCESS_KEY) - bucket: rust-lang-ci2 - set_public: true - region: us-west-1 - artifact: /.*/ - folder: rustc-builds - on: - branch: auto - DEPLOY: 1 - max_error_retry: 5 - - # This provider is the same as the one above except that it has a slightly - # different upload directory and a slightly different trigger - - provider: S3 - access_key_id: $(AWS_ACCESS_KEY_ID) - secret_access_key: $(AWS_SECRET_ACCESS_KEY) - bucket: rust-lang-ci2 - set_public: true - region: us-west-1 - artifact: /.*/ - folder: rustc-builds-alt - on: - branch: auto - DEPLOY_ALT: 1 - max_error_retry: 5 - -# init: -# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) -# on_finish: -# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/config.toml.example b/config.toml.example index 8f6bf03489f06..c14adf8ce33c7 100644 --- a/config.toml.example +++ b/config.toml.example @@ -14,10 +14,6 @@ # ============================================================================= [llvm] -# Indicates whether rustc will support compilation with LLVM -# note: rustc does not compile without LLVM at the moment -#enabled = true - # Indicates whether the LLVM build is a Release or Debug build #optimize = true @@ -61,7 +57,7 @@ # support. You'll need to write a target specification at least, and most # likely, teach rustc about the C ABI of the target. Get in touch with the # Rust team and file an issue if you need assistance in porting! -#targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX;Hexagon" +#targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;MSP430;Sparc;NVPTX;Hexagon" # LLVM experimental targets to build support for. These targets are specified in # the same format as above, but since these targets are experimental, they are @@ -164,6 +160,9 @@ # Python interpreter to use for various tasks throughout the build, notably # rustdoc tests, the lldb python interpreter, and some dist bits and pieces. # Note that Python 2 is currently required. +# +# Defaults to python2.7, then python2. If neither executable can be found, then +# it defaults to the Python interpreter used to execute x.py. #python = "python2.7" # Force Cargo to check that Cargo.lock describes the precise dependency @@ -302,20 +301,27 @@ # library. #debug-assertions = false -# Whether or not debuginfo is emitted -#debuginfo = false +# Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`. +# `0` - no debug info +# `1` - line tables only +# `2` - full debug info with variable and type information +# Can be overriden for specific subsets of Rust code (rustc, std or tools). +# Debuginfo for tests run with compiletest is not controlled by this option +# and needs to be enabled separately with `debuginfo-level-tests`. +#debuginfo-level = if debug { 2 } else { 0 } + +# Debuginfo level for the compiler. +#debuginfo-level-rustc = debuginfo-level -# Whether or not line number debug information is emitted -#debuginfo-lines = false +# Debuginfo level for the standard library. +#debuginfo-level-std = debuginfo-level -# Whether or not to only build debuginfo for the standard library if enabled. -# If enabled, this will not compile the compiler with debuginfo, just the -# standard library. -#debuginfo-only-std = false +# Debuginfo level for the tools. +#debuginfo-level-tools = debuginfo-level -# Enable debuginfo for the extended tools: cargo, rls, rustfmt -# Adding debuginfo makes them several times larger. -#debuginfo-tools = false +# Debuginfo level for the test suites run with compiletest. +# FIXME(#61117): Some tests fail when this option is enabled. +#debuginfo-level-tests = 0 # Whether or not `panic!`s generate backtraces (RUST_BACKTRACE) #backtrace = true @@ -346,10 +352,8 @@ # harness are debuggable just from logfiles. #verbose-tests = false -# Flag indicating whether tests are compiled with optimizations (the -O flag) or -# with debuginfo (the -g flag) +# Flag indicating whether tests are compiled with optimizations (the -O flag). #optimize-tests = true -#debuginfo-tests = true # Flag indicating whether codegen tests will be run or not. If you get an error # saying that the FileCheck executable is missing, you may want to disable this. @@ -422,6 +426,9 @@ # development of NLL #test-compare-mode = false +# Use LLVM libunwind as the implementation for Rust's unwinder. +#llvm-libunwind = false + # ============================================================================= # Options for specific targets # @@ -478,6 +485,9 @@ # linked binaries #musl-root = "..." +# The root location of the `wasm32-wasi` sysroot. +#wasi-root = "..." + # Used in testing for configuring where the QEMU images are located, you # probably don't want to use this. #qemu-rootfs = "..." diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000000000..df230cde9b713 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,6 @@ +# Currently, most of the code in the compiler uses historical style. +# +# For new code, consider running rustfmt with this config (it should +# be picked up automatically). +version = "Two" +use_small_heuristics = "Max" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 0f7b6c22e1cc5..589ee9276a5a3 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -36,17 +36,16 @@ test = false [dependencies] build_helper = { path = "../build_helper" } -cmake = "0.1.23" +cmake = "0.1.38" filetime = "0.2" num_cpus = "1.0" -getopts = "0.2" -cc = "1.0.1" +getopts = "0.2.19" +cc = "1.0.35" libc = "0.2" -serde = "1.0.8" -serde_derive = "1.0.8" +serde = { version = "1.0.8", features = ["derive"] } serde_json = "1.0.2" toml = "0.4" -lazy_static = "0.2" +lazy_static = "1.3.0" time = "0.1" petgraph = "0.4.13" diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 70e4a69a07d44..595deb07ec82b 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -89,12 +89,31 @@ fn main() { let mut cmd = Command::new(rustc); cmd.args(&args) - .arg("--cfg") - .arg(format!("stage{}", stage)) .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); let mut maybe_crate = None; + // Get the name of the crate we're compiling, if any. + let maybe_crate_name = args.windows(2) + .find(|a| &*a[0] == "--crate-name") + .map(|crate_name| &*crate_name[1]); + + if let Some(current_crate) = maybe_crate_name { + if let Some(target) = env::var_os("RUSTC_TIME") { + if target == "all" || + target.into_string().unwrap().split(",").any(|c| c.trim() == current_crate) + { + cmd.arg("-Ztime"); + } + } + } + + // Non-zero stages must all be treated uniformly to avoid problems when attempting to uplift + // compiler libraries and such from stage 1 to 2. + if stage == "0" { + cmd.arg("--cfg").arg("bootstrap"); + } + // Print backtrace in case of ICE if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() { cmd.env("RUST_BACKTRACE", "1"); @@ -102,6 +121,10 @@ fn main() { cmd.env("RUSTC_BREAK_ON_ICE", "1"); + if let Ok(debuginfo_level) = env::var("RUSTC_DEBUGINFO_LEVEL") { + cmd.arg(format!("-Cdebuginfo={}", debuginfo_level)); + } + if let Some(target) = target { // The stage0 compiler has a special sysroot distinct from what we // actually downloaded, so we just always pass the `--sysroot` option. @@ -109,6 +132,12 @@ fn main() { cmd.arg("-Zexternal-macro-backtrace"); + // Link crates to the proc macro crate for the target, but use a host proc macro crate + // to actually run the macros + if env::var_os("RUST_DUAL_PROC_MACROS").is_some() { + cmd.arg("-Zdual-proc-macros"); + } + // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of // linking all deps statically into the dylib. @@ -116,8 +145,8 @@ fn main() { cmd.arg("-Cprefer-dynamic"); } - // Help the libc crate compile by assisting it in finding the MUSL - // native libraries. + // Help the libc crate compile by assisting it in finding various + // sysroot native libraries. if let Some(s) = env::var_os("MUSL_ROOT") { if target.contains("musl") { let mut root = OsString::from("native="); @@ -126,16 +155,19 @@ fn main() { cmd.arg("-L").arg(&root); } } + if let Some(s) = env::var_os("WASI_ROOT") { + let mut root = OsString::from("native="); + root.push(&s); + root.push("/lib/wasm32-wasi"); + cmd.arg("-L").arg(&root); + } // Override linker if necessary. if let Ok(target_linker) = env::var("RUSTC_TARGET_LINKER") { cmd.arg(format!("-Clinker={}", target_linker)); } - let crate_name = args.windows(2) - .find(|a| &*a[0] == "--crate-name") - .unwrap(); - let crate_name = &*crate_name[1]; + let crate_name = maybe_crate_name.unwrap(); maybe_crate = Some(crate_name); // If we're compiling specifically the `panic_abort` crate then we pass @@ -157,11 +189,6 @@ fn main() { // Set various options from config.toml to configure how we're building // code. - if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) { - cmd.arg("-g"); - } else if env::var("RUSTC_DEBUGINFO_LINES") == Ok("true".to_string()) { - cmd.arg("-Cdebuginfo=1"); - } let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") { Ok(s) => if s == "true" { "y" } else { "n" }, Err(..) => "n", @@ -250,6 +277,7 @@ fn main() { // The flags here should be kept in sync with `add_miri_default_args` // in miri's `src/lib.rs`. cmd.arg("-Zalways-encode-mir"); + cmd.arg("--cfg=miri"); // These options are preferred by miri, to be able to perform better validation, // but the bootstrap compiler might not understand them. if stage != "0" { @@ -258,13 +286,6 @@ fn main() { } } - // Force all crates compiled by this compiler to (a) be unstable and (b) - // allow the `rustc_private` feature to link to other unstable crates - // also in the sysroot. - if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() { - cmd.arg("-Z").arg("force-unstable-if-unmarked"); - } - if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { cmd.arg("--remap-path-prefix").arg(&map); } @@ -284,6 +305,17 @@ fn main() { } } + // This is required for internal lints. + cmd.arg("-Zunstable-options"); + + // Force all crates compiled by this compiler to (a) be unstable and (b) + // allow the `rustc_private` feature to link to other unstable crates + // also in the sysroot. We also do this for host crates, since those + // may be proc macros, in which case we might ship them. + if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() && (stage != "0" || target.is_some()) { + cmd.arg("-Z").arg("force-unstable-if-unmarked"); + } + if env::var_os("RUSTC_PARALLEL_COMPILER").is_some() { cmd.arg("--cfg").arg("parallel_compiler"); } @@ -292,6 +324,7 @@ fn main() { { cmd.arg("-Dwarnings"); cmd.arg("-Dbare_trait_objects"); + cmd.arg("-Drust_2018_idioms"); } if verbose > 1 { diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index 36beec3a944a0..1c9f6e1ab285c 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -35,7 +35,7 @@ fn main() { .arg("--cfg") .arg("dox") .arg("--sysroot") - .arg(sysroot) + .arg(&sysroot) .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); @@ -69,10 +69,27 @@ fn main() { .arg("unstable-options"); } cmd.arg("--generate-redirect-pages"); + has_unstable = true; + } + + // Needed to be able to run all rustdoc tests. + if let Some(ref x) = env::var_os("RUSTDOC_RESOURCE_SUFFIX") { + // This "unstable-options" can be removed when `--resource-suffix` is stabilized + if !has_unstable { + cmd.arg("-Z") + .arg("unstable-options"); + } + cmd.arg("--resource-suffix").arg(x); } if verbose > 1 { - eprintln!("rustdoc command: {:?}", cmd); + eprintln!( + "rustdoc command: {:?}={:?} {:?}", + bootstrap::util::dylib_path_var(), + env::join_paths(&dylib_path).unwrap(), + cmd, + ); + eprintln!("sysroot: {:?}", sysroot); eprintln!("libdir: {:?}", libdir); } diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index c98d8b8ecf437..1c2b882f66594 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -177,7 +177,6 @@ def default_build_triple(): # The goal here is to come up with the same triple as LLVM would, # at least for the subset of platforms we're willing to target. ostype_mapper = { - 'Bitrig': 'unknown-bitrig', 'Darwin': 'apple-darwin', 'DragonFly': 'unknown-dragonfly', 'FreeBSD': 'unknown-freebsd', @@ -262,6 +261,10 @@ def default_build_triple(): cputype = 'arm' if ostype == 'linux-android': ostype = 'linux-androideabi' + elif ostype == 'unknown-freebsd': + cputype = subprocess.check_output( + ['uname', '-p']).strip().decode(default_encoding) + ostype = 'unknown-freebsd' elif cputype == 'armv6l': cputype = 'arm' if ostype == 'linux-android': @@ -673,9 +676,15 @@ def update_submodule(self, module, checked_out, recorded_submodules): run(["git", "submodule", "-q", "sync", module], cwd=self.rust_root, verbose=self.verbose) - run(["git", "submodule", "update", - "--init", "--recursive", "--progress", module], - cwd=self.rust_root, verbose=self.verbose) + try: + run(["git", "submodule", "update", + "--init", "--recursive", "--progress", module], + cwd=self.rust_root, verbose=self.verbose, exception=True) + except RuntimeError: + # Some versions of git don't support --progress. + run(["git", "submodule", "update", + "--init", "--recursive", module], + cwd=self.rust_root, verbose=self.verbose) run(["git", "reset", "-q", "--hard"], cwd=module_path, verbose=self.verbose) run(["git", "clean", "-qdfx"], diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 7e6c0a9f52aa2..2e9df48d00002 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -11,6 +11,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::time::{Duration, Instant}; +use build_helper::t; + use crate::cache::{Cache, Interned, INTERNER}; use crate::check; use crate::compile; @@ -57,7 +59,7 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { const DEFAULT: bool = false; - /// Run this rule for all hosts without cross compiling. + /// If true, then this rule should be skipped if --target was specified, but --host was not const ONLY_HOSTS: bool = false; /// Primary function to execute this rule. Can call `builder.ensure()` @@ -161,7 +163,7 @@ impl StepDescription { // Determine the targets participating in this rule. let targets = if self.only_hosts { - if !builder.config.run_host_only { + if builder.config.skip_only_host_steps { return; // don't run anything } else { &builder.hosts @@ -316,6 +318,8 @@ impl<'a> ShouldRun<'a> { pub enum Kind { Build, Check, + Clippy, + Fix, Test, Bench, Dist, @@ -357,7 +361,7 @@ impl<'a> Builder<'a> { tool::Miri, native::Lld ), - Kind::Check => describe!( + Kind::Check | Kind::Clippy | Kind::Fix => describe!( check::Std, check::Test, check::Rustc, @@ -374,6 +378,7 @@ impl<'a> Builder<'a> { test::MirOpt, test::Codegen, test::CodegenUnits, + test::Assembly, test::Incremental, test::Debuginfo, test::UiFullDeps, @@ -401,17 +406,19 @@ impl<'a> Builder<'a> { test::UnstableBook, test::RustcBook, test::EmbeddedBook, + test::EditionGuide, test::Rustfmt, test::Miri, test::Clippy, test::CompiletestTest, - test::RustdocJS, + test::RustdocJSStd, + test::RustdocJSNotStd, test::RustdocTheme, + test::RustdocUi, // Run bootstrap close to the end as it's unlikely to fail test::Bootstrap, // Run run-make last, since these won't pass without make on Windows test::RunMake, - test::RustdocUi ), Kind::Bench => describe!(test::Crate, test::CrateLibrustc), Kind::Doc => describe!( @@ -515,6 +522,8 @@ impl<'a> Builder<'a> { let (kind, paths) = match build.config.cmd { Subcommand::Build { ref paths } => (Kind::Build, &paths[..]), Subcommand::Check { ref paths } => (Kind::Check, &paths[..]), + Subcommand::Clippy { ref paths } => (Kind::Clippy, &paths[..]), + Subcommand::Fix { ref paths } => (Kind::Fix, &paths[..]), Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]), Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]), Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]), @@ -572,6 +581,30 @@ impl<'a> Builder<'a> { }) } + /// Similar to `compiler`, except handles the full-bootstrap option to + /// silently use the stage1 compiler instead of a stage2 compiler if one is + /// requested. + /// + /// Note that this does *not* have the side effect of creating + /// `compiler(stage, host)`, unlike `compiler` above which does have such + /// a side effect. The returned compiler here can only be used to compile + /// new artifacts, it can't be used to rely on the presence of a particular + /// sysroot. + /// + /// See `force_use_stage1` for documentation on what each argument is. + pub fn compiler_for( + &self, + stage: u32, + host: Interned, + target: Interned, + ) -> Compiler { + if self.build.force_use_stage1(Compiler { stage, host }, target) { + self.compiler(1, self.config.build) + } else { + self.compiler(stage, host) + } + } + pub fn sysroot(&self, compiler: Compiler) -> Interned { self.ensure(compile::Sysroot { compiler }) } @@ -631,7 +664,28 @@ impl<'a> Builder<'a> { if compiler.is_snapshot(self) { self.rustc_snapshot_libdir() } else { - self.sysroot(compiler).join(libdir(&compiler.host)) + match self.config.libdir_relative() { + Some(relative_libdir) if compiler.stage >= 1 + => self.sysroot(compiler).join(relative_libdir), + _ => self.sysroot(compiler).join(libdir(&compiler.host)) + } + } + } + + /// Returns the compiler's relative libdir where it stores the dynamic libraries that + /// it itself links against. + /// + /// For example this returns `lib` on Unix and `bin` on + /// Windows. + pub fn libdir_relative(&self, compiler: Compiler) -> &Path { + if compiler.is_snapshot(self) { + libdir(&self.config.build).as_ref() + } else { + match self.config.libdir_relative() { + Some(relative_libdir) if compiler.stage >= 1 + => relative_libdir, + _ => libdir(&compiler.host).as_ref() + } } } @@ -668,20 +722,19 @@ impl<'a> Builder<'a> { .map(|entry| entry.path()) } - pub fn rustdoc(&self, host: Interned) -> PathBuf { - self.ensure(tool::Rustdoc { host }) + pub fn rustdoc(&self, compiler: Compiler) -> PathBuf { + self.ensure(tool::Rustdoc { compiler }) } - pub fn rustdoc_cmd(&self, host: Interned) -> Command { + pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command { let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc")); - let compiler = self.compiler(self.top_stage, host); cmd.env("RUSTC_STAGE", compiler.stage.to_string()) .env("RUSTC_SYSROOT", self.sysroot(compiler)) // Note that this is *not* the sysroot_libdir because rustdoc must be linked // equivalently to rustc. .env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler)) .env("CFG_RELEASE_CHANNEL", &self.config.channel) - .env("RUSTDOC_REAL", self.rustdoc(host)) + .env("RUSTDOC_REAL", self.rustdoc(compiler)) .env("RUSTDOC_CRATE_VERSION", self.rust_version()) .env("RUSTC_BOOTSTRAP", "1"); @@ -689,7 +742,7 @@ impl<'a> Builder<'a> { cmd.env_remove("MAKEFLAGS"); cmd.env_remove("MFLAGS"); - if let Some(linker) = self.linker(host) { + if let Some(linker) = self.linker(compiler.host) { cmd.env("RUSTC_TARGET_LINKER", linker); } cmd @@ -725,24 +778,20 @@ impl<'a> Builder<'a> { // This is for the original compiler, but if we're forced to use stage 1, then // std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since // we copy the libs forward. - let cmp = if self.force_use_stage1(compiler, target) { - self.compiler(1, compiler.host) - } else { - compiler - }; + let cmp = self.compiler_for(compiler.stage, compiler.host, target); let libstd_stamp = match cmd { - "check" => check::libstd_stamp(self, cmp, target), + "check" | "clippy" | "fix" => check::libstd_stamp(self, cmp, target), _ => compile::libstd_stamp(self, cmp, target), }; let libtest_stamp = match cmd { - "check" => check::libtest_stamp(self, cmp, target), - _ => compile::libstd_stamp(self, cmp, target), + "check" | "clippy" | "fix" => check::libtest_stamp(self, cmp, target), + _ => compile::libtest_stamp(self, cmp, target), }; let librustc_stamp = match cmd { - "check" => check::librustc_stamp(self, cmp, target), + "check" | "clippy" | "fix" => check::librustc_stamp(self, cmp, target), _ => compile::librustc_stamp(self, cmp, target), }; @@ -751,7 +800,7 @@ impl<'a> Builder<'a> { // This is the intended out directory for compiler documentation. my_out = self.compiler_doc_out(target); } - let rustdoc = self.rustdoc(compiler.host); + let rustdoc = self.rustdoc(compiler); self.clear_if_dirty(&my_out, &rustdoc); } else if cmd != "test" { match mode { @@ -806,12 +855,23 @@ impl<'a> Builder<'a> { assert_eq!(target, compiler.host); } - // Set a flag for `check` so that certain build scripts can do less work - // (e.g., not building/requiring LLVM). - if cmd == "check" { + // Set a flag for `check`/`clippy`/`fix`, so that certain build + // scripts can do less work (e.g. not building/requiring LLVM). + if cmd == "check" || cmd == "clippy" || cmd == "fix" { cargo.env("RUST_CHECK", "1"); } + match mode { + Mode::Std | Mode::Test | Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTest=> {}, + Mode::Rustc | Mode::Codegen | Mode::ToolRustc => { + // Build proc macros both for the host and the target + if target != compiler.host && cmd != "check" { + cargo.arg("-Zdual-proc-macros"); + cargo.env("RUST_DUAL_PROC_MACROS", "1"); + } + }, + } + cargo.arg("-j").arg(self.jobs().to_string()); // Remove make-related flags to ensure Cargo can correctly set things up cargo.env_remove("MAKEFLAGS"); @@ -819,14 +879,30 @@ impl<'a> Builder<'a> { // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005 // Force cargo to output binaries with disambiguating hashes in the name - let metadata = if compiler.stage == 0 { - // Treat stage0 like special channel, whether it's a normal prior- + let mut metadata = if compiler.stage == 0 { + // Treat stage0 like a special channel, whether it's a normal prior- // release rustc or a local rebuild with the same version, so we // never mix these libraries by accident. - "bootstrap" + "bootstrap".to_string() } else { - &self.config.channel + self.config.channel.to_string() }; + // We want to make sure that none of the dependencies between + // std/test/rustc unify with one another. This is done for weird linkage + // reasons but the gist of the problem is that if librustc, libtest, and + // libstd all depend on libc from crates.io (which they actually do) we + // want to make sure they all get distinct versions. Things get really + // weird if we try to unify all these dependencies right now, namely + // around how many times the library is linked in dynamic libraries and + // such. If rustc were a static executable or if we didn't ship dylibs + // this wouldn't be a problem, but we do, so it is. This is in general + // just here to make sure things build right. If you can remove this and + // things still build right, please do! + match mode { + Mode::Std => metadata.push_str("std"), + Mode::Test => metadata.push_str("test"), + _ => {}, + } cargo.env("__CARGO_DEFAULT_LIB_METADATA", &metadata); let stage; @@ -846,6 +922,11 @@ impl<'a> Builder<'a> { extra_args.push_str(&s); } + if cmd == "clippy" { + extra_args.push_str("-Zforce-unstable-if-unmarked -Zunstable-options \ + --json-rendered=termcolor"); + } + if !extra_args.is_empty() { cargo.env( "RUSTFLAGS", @@ -897,7 +978,7 @@ impl<'a> Builder<'a> { .env( "RUSTDOC_REAL", if cmd == "doc" || cmd == "rustdoc" || (cmd == "test" && want_rustdoc) { - self.rustdoc(compiler.host) + self.rustdoc(compiler) } else { PathBuf::from("/path/to/nowhere/rustdoc/not/required") }, @@ -914,26 +995,19 @@ impl<'a> Builder<'a> { if let Some(ref error_format) = self.config.rustc_error_format { cargo.env("RUSTC_ERROR_FORMAT", error_format); } - if cmd != "build" && cmd != "check" && cmd != "rustc" && want_rustdoc { + if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc { cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler)); } - if mode.is_tool() { - // Tools like cargo and rls don't get debuginfo by default right now, but this can be - // enabled in the config. Adding debuginfo makes them several times larger. - if self.config.rust_debuginfo_tools { - cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()); - cargo.env( - "RUSTC_DEBUGINFO_LINES", - self.config.rust_debuginfo_lines.to_string(), - ); - } - } else { - cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()); - cargo.env( - "RUSTC_DEBUGINFO_LINES", - self.config.rust_debuginfo_lines.to_string(), - ); + let debuginfo_level = match mode { + Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc, + Mode::Std | Mode::Test => self.config.rust_debuginfo_level_std, + Mode::ToolBootstrap | Mode::ToolStd | + Mode::ToolTest | Mode::ToolRustc => self.config.rust_debuginfo_level_tools, + }; + cargo.env("RUSTC_DEBUGINFO_LEVEL", debuginfo_level.to_string()); + + if !mode.is_tool() { cargo.env("RUSTC_FORCE_UNSTABLE", "1"); // Currently the compiler depends on crates from crates.io, and @@ -984,10 +1058,7 @@ impl<'a> Builder<'a> { // For other crates, however, we know that we've already got a standard // library up and running, so we can use the normal compiler to compile // build scripts in that situation. - // - // If LLVM support is disabled we need to use the snapshot compiler to compile - // build scripts, as the new compiler doesn't support executables. - if mode == Mode::Std || !self.config.llvm_enabled { + if mode == Mode::Std { cargo .env("RUSTC_SNAPSHOT", &self.initial_rustc) .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()); @@ -1256,650 +1327,4 @@ impl<'a> Builder<'a> { } #[cfg(test)] -mod __test { - use super::*; - use crate::config::Config; - use std::thread; - - fn configure(host: &[&str], target: &[&str]) -> Config { - let mut config = Config::default_opts(); - // don't save toolstates - config.save_toolstates = None; - config.run_host_only = true; - config.dry_run = true; - // try to avoid spurious failures in dist where we create/delete each others file - let dir = config.out.join("tmp-rustbuild-tests").join( - &thread::current() - .name() - .unwrap_or("unknown") - .replace(":", "-"), - ); - t!(fs::create_dir_all(&dir)); - config.out = dir; - config.build = INTERNER.intern_str("A"); - config.hosts = vec![config.build] - .clone() - .into_iter() - .chain(host.iter().map(|s| INTERNER.intern_str(s))) - .collect::>(); - config.targets = config - .hosts - .clone() - .into_iter() - .chain(target.iter().map(|s| INTERNER.intern_str(s))) - .collect::>(); - config - } - - fn first(v: Vec<(A, B)>) -> Vec { - v.into_iter().map(|(a, _)| a).collect::>() - } - - #[test] - fn dist_baseline() { - let build = Build::new(configure(&[], &[])); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); - - let a = INTERNER.intern_str("A"); - - assert_eq!( - first(builder.cache.all::()), - &[dist::Docs { stage: 2, host: a },] - ); - assert_eq!( - first(builder.cache.all::()), - &[dist::Mingw { host: a },] - ); - assert_eq!( - first(builder.cache.all::()), - &[dist::Rustc { - compiler: Compiler { host: a, stage: 2 } - },] - ); - assert_eq!( - first(builder.cache.all::()), - &[dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - },] - ); - assert_eq!(first(builder.cache.all::()), &[dist::Src]); - } - - #[test] - fn dist_with_targets() { - let build = Build::new(configure(&[], &["B"])); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); - - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); - - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - ] - ); - assert_eq!( - first(builder.cache.all::()), - &[dist::Mingw { host: a }, dist::Mingw { host: b },] - ); - assert_eq!( - first(builder.cache.all::()), - &[dist::Rustc { - compiler: Compiler { host: a, stage: 2 } - },] - ); - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ] - ); - assert_eq!(first(builder.cache.all::()), &[dist::Src]); - } - - #[test] - fn dist_with_hosts() { - let build = Build::new(configure(&["B"], &[])); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); - - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); - - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - ] - ); - assert_eq!( - first(builder.cache.all::()), - &[dist::Mingw { host: a }, dist::Mingw { host: b },] - ); - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Rustc { - compiler: Compiler { host: a, stage: 2 } - }, - dist::Rustc { - compiler: Compiler { host: b, stage: 2 } - }, - ] - ); - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ] - ); - assert_eq!(first(builder.cache.all::()), &[dist::Src]); - } - - #[test] - fn dist_with_targets_and_hosts() { - let build = Build::new(configure(&["B"], &["C"])); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); - - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); - let c = INTERNER.intern_str("C"); - - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - dist::Docs { stage: 2, host: c }, - ] - ); - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Mingw { host: a }, - dist::Mingw { host: b }, - dist::Mingw { host: c }, - ] - ); - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Rustc { - compiler: Compiler { host: a, stage: 2 } - }, - dist::Rustc { - compiler: Compiler { host: b, stage: 2 } - }, - ] - ); - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - ] - ); - assert_eq!(first(builder.cache.all::()), &[dist::Src]); - } - - #[test] - fn dist_with_target_flag() { - let mut config = configure(&["B"], &["C"]); - config.run_host_only = false; // as-if --target=C was passed - let build = Build::new(config); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); - - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); - let c = INTERNER.intern_str("C"); - - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - dist::Docs { stage: 2, host: c }, - ] - ); - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Mingw { host: a }, - dist::Mingw { host: b }, - dist::Mingw { host: c }, - ] - ); - assert_eq!(first(builder.cache.all::()), &[]); - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - ] - ); - assert_eq!(first(builder.cache.all::()), &[]); - } - - #[test] - fn dist_with_same_targets_and_hosts() { - let build = Build::new(configure(&["B"], &["B"])); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); - - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); - - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - ] - ); - assert_eq!( - first(builder.cache.all::()), - &[dist::Mingw { host: a }, dist::Mingw { host: b },] - ); - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Rustc { - compiler: Compiler { host: a, stage: 2 } - }, - dist::Rustc { - compiler: Compiler { host: b, stage: 2 } - }, - ] - ); - assert_eq!( - first(builder.cache.all::()), - &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ] - ); - assert_eq!(first(builder.cache.all::()), &[dist::Src]); - assert_eq!( - first(builder.cache.all::()), - &[ - compile::Std { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Std { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Std { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ] - ); - assert_eq!( - first(builder.cache.all::()), - &[ - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ] - ); - assert_eq!( - first(builder.cache.all::()), - &[ - compile::Assemble { - target_compiler: Compiler { host: a, stage: 0 }, - }, - compile::Assemble { - target_compiler: Compiler { host: a, stage: 1 }, - }, - compile::Assemble { - target_compiler: Compiler { host: a, stage: 2 }, - }, - compile::Assemble { - target_compiler: Compiler { host: b, stage: 2 }, - }, - ] - ); - } - - #[test] - fn build_default() { - let build = Build::new(configure(&["B"], &["C"])); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); - - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); - let c = INTERNER.intern_str("C"); - - assert!(!builder.cache.all::().is_empty()); - assert!(!builder.cache.all::().is_empty()); - assert_eq!( - first(builder.cache.all::()), - &[ - compile::Rustc { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: b, stage: 2 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 0 }, - target: b, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - compile::Rustc { - compiler: Compiler { host: b, stage: 2 }, - target: b, - }, - ] - ); - - assert_eq!( - first(builder.cache.all::()), - &[ - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: c, - }, - ] - ); - } - - #[test] - fn build_with_target_flag() { - let mut config = configure(&["B"], &["C"]); - config.run_host_only = false; - let build = Build::new(config); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); - - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); - let c = INTERNER.intern_str("C"); - - assert!(!builder.cache.all::().is_empty()); - assert_eq!( - first(builder.cache.all::()), - &[ - compile::Assemble { - target_compiler: Compiler { host: a, stage: 0 }, - }, - compile::Assemble { - target_compiler: Compiler { host: a, stage: 1 }, - }, - compile::Assemble { - target_compiler: Compiler { host: b, stage: 1 }, - }, - compile::Assemble { - target_compiler: Compiler { host: a, stage: 2 }, - }, - compile::Assemble { - target_compiler: Compiler { host: b, stage: 2 }, - }, - ] - ); - assert_eq!( - first(builder.cache.all::()), - &[ - compile::Rustc { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 0 }, - target: b, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - ] - ); - - assert_eq!( - first(builder.cache.all::()), - &[ - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: c, - }, - ] - ); - } - - #[test] - fn test_with_no_doc_stage0() { - let mut config = configure(&[], &[]); - config.stage = Some(0); - config.cmd = Subcommand::Test { - paths: vec!["src/libstd".into()], - test_args: vec![], - rustc_args: vec![], - fail_fast: true, - doc_tests: DocTests::No, - bless: false, - compare_mode: None, - }; - - let build = Build::new(config); - let mut builder = Builder::new(&build); - - let host = INTERNER.intern_str("A"); - - builder.run_step_descriptions( - &[StepDescription::from::()], - &["src/libstd".into()], - ); - - // Ensure we don't build any compiler artifacts. - assert!(!builder.cache.contains::()); - assert_eq!( - first(builder.cache.all::()), - &[test::Crate { - compiler: Compiler { host, stage: 0 }, - target: host, - mode: Mode::Std, - test_kind: test::TestKind::Test, - krate: INTERNER.intern_str("std"), - },] - ); - } - - #[test] - fn test_exclude() { - let mut config = configure(&[], &[]); - config.exclude = vec![ - "src/test/run-pass".into(), - "src/tools/tidy".into(), - ]; - config.cmd = Subcommand::Test { - paths: Vec::new(), - test_args: Vec::new(), - rustc_args: Vec::new(), - fail_fast: true, - doc_tests: DocTests::No, - bless: false, - compare_mode: None, - }; - - let build = Build::new(config); - let builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]); - - // Ensure we have really excluded run-pass & tidy - assert!(!builder.cache.contains::()); - assert!(!builder.cache.contains::()); - - // Ensure other tests are not affected. - assert!(builder.cache.contains::()); - assert!(builder.cache.contains::()); - } -} +mod tests; diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs new file mode 100644 index 0000000000000..cab7443bf3fe8 --- /dev/null +++ b/src/bootstrap/builder/tests.rs @@ -0,0 +1,658 @@ +use super::*; +use crate::config::Config; +use std::thread; + +use pretty_assertions::assert_eq; + +fn configure(host: &[&str], target: &[&str]) -> Config { + let mut config = Config::default_opts(); + // don't save toolstates + config.save_toolstates = None; + config.skip_only_host_steps = false; + config.dry_run = true; + // try to avoid spurious failures in dist where we create/delete each others file + let dir = config.out.join("tmp-rustbuild-tests").join( + &thread::current() + .name() + .unwrap_or("unknown") + .replace(":", "-"), + ); + t!(fs::create_dir_all(&dir)); + config.out = dir; + config.build = INTERNER.intern_str("A"); + config.hosts = vec![config.build] + .clone() + .into_iter() + .chain(host.iter().map(|s| INTERNER.intern_str(s))) + .collect::>(); + config.targets = config + .hosts + .clone() + .into_iter() + .chain(target.iter().map(|s| INTERNER.intern_str(s))) + .collect::>(); + config +} + +fn first(v: Vec<(A, B)>) -> Vec { + v.into_iter().map(|(a, _)| a).collect::>() +} + +#[test] +fn dist_baseline() { + let build = Build::new(configure(&[], &[])); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + + let a = INTERNER.intern_str("A"); + + assert_eq!( + first(builder.cache.all::()), + &[dist::Docs { host: a },] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Mingw { host: a },] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + },] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Std { + compiler: Compiler { host: a, stage: 1 }, + target: a, + },] + ); + assert_eq!(first(builder.cache.all::()), &[dist::Src]); +} + +#[test] +fn dist_with_targets() { + let build = Build::new(configure(&[], &["B"])); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { host: a }, + dist::Docs { host: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Mingw { host: a }, dist::Mingw { host: b },] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + },] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ] + ); + assert_eq!(first(builder.cache.all::()), &[dist::Src]); +} + +#[test] +fn dist_with_hosts() { + let build = Build::new(configure(&["B"], &[])); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { host: a }, + dist::Docs { host: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Mingw { host: a }, dist::Mingw { host: b },] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + }, + dist::Rustc { + compiler: Compiler { host: b, stage: 2 } + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + ] + ); + assert_eq!(first(builder.cache.all::()), &[dist::Src]); +} + +#[test] +fn dist_only_cross_host() { + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + let mut build = Build::new(configure(&["B"], &[])); + build.config.docs = false; + build.config.extended = true; + build.hosts = vec![b]; + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Rustc { + compiler: Compiler { host: b, stage: 2 } + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + ] + ); +} + +#[test] +fn dist_with_targets_and_hosts() { + let build = Build::new(configure(&["B"], &["C"])); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + let c = INTERNER.intern_str("C"); + + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { host: a }, + dist::Docs { host: b }, + dist::Docs { host: c }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Mingw { host: a }, + dist::Mingw { host: b }, + dist::Mingw { host: c }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + }, + dist::Rustc { + compiler: Compiler { host: b, stage: 2 } + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + ] + ); + assert_eq!(first(builder.cache.all::()), &[dist::Src]); +} + +#[test] +fn dist_with_target_flag() { + let mut config = configure(&["B"], &["C"]); + config.skip_only_host_steps = true; // as-if --target=C was passed + let build = Build::new(config); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + let c = INTERNER.intern_str("C"); + + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { host: a }, + dist::Docs { host: b }, + dist::Docs { host: c }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Mingw { host: a }, + dist::Mingw { host: b }, + dist::Mingw { host: c }, + ] + ); + assert_eq!(first(builder.cache.all::()), &[]); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + ] + ); + assert_eq!(first(builder.cache.all::()), &[]); +} + +#[test] +fn dist_with_same_targets_and_hosts() { + let build = Build::new(configure(&["B"], &["B"])); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { host: a }, + dist::Docs { host: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Mingw { host: a }, dist::Mingw { host: b },] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + }, + dist::Rustc { + compiler: Compiler { host: b, stage: 2 } + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + ] + ); + assert_eq!(first(builder.cache.all::()), &[dist::Src]); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Std { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Assemble { + target_compiler: Compiler { host: a, stage: 0 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 1 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 2 }, + }, + compile::Assemble { + target_compiler: Compiler { host: b, stage: 2 }, + }, + ] + ); +} + +#[test] +fn build_default() { + let build = Build::new(configure(&["B"], &["C"])); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + let c = INTERNER.intern_str("C"); + + assert!(!builder.cache.all::().is_empty()); + assert!(!builder.cache.all::().is_empty()); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + ] + ); + + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: c, + }, + ] + ); +} + +#[test] +fn build_with_target_flag() { + let mut config = configure(&["B"], &["C"]); + config.skip_only_host_steps = true; + let build = Build::new(config); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + let c = INTERNER.intern_str("C"); + + assert!(!builder.cache.all::().is_empty()); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Assemble { + target_compiler: Compiler { host: a, stage: 0 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 1 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 2 }, + }, + compile::Assemble { + target_compiler: Compiler { host: b, stage: 2 }, + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + ] + ); + + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: c, + }, + ] + ); +} + +#[test] +fn test_with_no_doc_stage0() { + let mut config = configure(&[], &[]); + config.stage = Some(0); + config.cmd = Subcommand::Test { + paths: vec!["src/libstd".into()], + test_args: vec![], + rustc_args: vec![], + fail_fast: true, + doc_tests: DocTests::No, + bless: false, + compare_mode: None, + rustfix_coverage: false, + pass: None, + }; + + let build = Build::new(config); + let mut builder = Builder::new(&build); + + let host = INTERNER.intern_str("A"); + + builder.run_step_descriptions( + &[StepDescription::from::()], + &["src/libstd".into()], + ); + + // Ensure we don't build any compiler artifacts. + assert!(!builder.cache.contains::()); + assert_eq!( + first(builder.cache.all::()), + &[test::Crate { + compiler: Compiler { host, stage: 0 }, + target: host, + mode: Mode::Std, + test_kind: test::TestKind::Test, + krate: INTERNER.intern_str("std"), + },] + ); +} + +#[test] +fn test_exclude() { + let mut config = configure(&[], &[]); + config.exclude = vec![ + "src/test/run-pass".into(), + "src/tools/tidy".into(), + ]; + config.cmd = Subcommand::Test { + paths: Vec::new(), + test_args: Vec::new(), + rustc_args: Vec::new(), + fail_fast: true, + doc_tests: DocTests::No, + bless: false, + compare_mode: None, + rustfix_coverage: false, + pass: None, + }; + + let build = Build::new(config); + let builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]); + + // Ensure we have really excluded run-pass & tidy + assert!(!builder.cache.contains::()); + assert!(!builder.cache.contains::()); + + // Ensure other tests are not affected. + assert!(builder.cache.contains::()); + assert!(builder.cache.contains::()); +} diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs index 239959682cb00..f137a7b8cc281 100644 --- a/src/bootstrap/cache.rs +++ b/src/bootstrap/cache.rs @@ -13,6 +13,8 @@ use std::path::{Path, PathBuf}; use std::sync::Mutex; use std::cmp::{PartialOrd, Ord, Ordering}; +use lazy_static::lazy_static; + use crate::builder::Step; pub struct Interned(usize, PhantomData<*const T>); diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index dfc243b7054ab..400375cd201c4 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -95,29 +95,39 @@ pub fn find(build: &mut Build) { }; build.cc.insert(target, compiler); - build.verbose(&format!("CC_{} = {:?}", &target, build.cc(target))); - build.verbose(&format!("CFLAGS_{} = {:?}", &target, build.cflags(target, GitRepo::Rustc))); - if let Some(ar) = ar { - build.verbose(&format!("AR_{} = {:?}", &target, ar)); - build.ar.insert(target, ar); - } - } + let cflags = build.cflags(target, GitRepo::Rustc); - // For all host triples we need to find a C++ compiler as well - let hosts = build.hosts.iter().cloned().chain(iter::once(build.build)).collect::>(); - for host in hosts.into_iter() { + // If we use llvm-libunwind, we will need a C++ compiler as well for all targets + // We'll need one anyways if the target triple is also a host triple let mut cfg = cc::Build::new(); cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false).cpp(true) - .target(&host).host(&build.build); - let config = build.config.target_config.get(&host); - if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) { + .target(&target).host(&build.build); + + let cxx_configured = if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) { cfg.compiler(cxx); + true + } else if build.hosts.contains(&target) || build.build == target { + set_compiler(&mut cfg, Language::CPlusPlus, target, config, build); + true } else { - set_compiler(&mut cfg, Language::CPlusPlus, host, config, build); + false + }; + + if cxx_configured { + let compiler = cfg.get_compiler(); + build.cxx.insert(target, compiler); + } + + build.verbose(&format!("CC_{} = {:?}", &target, build.cc(target))); + build.verbose(&format!("CFLAGS_{} = {:?}", &target, cflags)); + if let Ok(cxx) = build.cxx(target) { + build.verbose(&format!("CXX_{} = {:?}", &target, cxx)); + build.verbose(&format!("CXXFLAGS_{} = {:?}", &target, cflags)); + } + if let Some(ar) = ar { + build.verbose(&format!("AR_{} = {:?}", &target, ar)); + build.ar.insert(target, ar); } - let compiler = cfg.get_compiler(); - build.verbose(&format!("CXX_{} = {:?}", host, compiler.path())); - build.cxx.insert(host, compiler); } } diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 0b2f62485c9ee..41235d911c03e 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -11,10 +11,9 @@ use std::process::Command; use build_helper::output; use crate::Build; -use crate::config::Config; // The version number -pub const CFG_RELEASE_NUM: &str = "1.34.0"; +pub const CFG_RELEASE_NUM: &str = "1.37.0"; pub struct GitInfo { inner: Option, @@ -27,20 +26,20 @@ struct Info { } impl GitInfo { - pub fn new(config: &Config, dir: &Path) -> GitInfo { + pub fn new(ignore_git: bool, dir: &Path) -> GitInfo { // See if this even begins to look like a git dir - if config.ignore_git || !dir.join(".git").exists() { + if ignore_git || !dir.join(".git").exists() { return GitInfo { inner: None } } // Make sure git commands work - let out = Command::new("git") - .arg("rev-parse") - .current_dir(dir) - .output() - .expect("failed to spawn git"); - if !out.status.success() { - return GitInfo { inner: None } + match Command::new("git") + .arg("rev-parse") + .current_dir(dir) + .output() + { + Ok(ref out) if out.status.success() => {} + _ => return GitInfo { inner: None }, } // Ok, let's scrape some info diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 20370372082b9..bdf5306d4b549 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -1,8 +1,8 @@ -//! Implementation of compiling the compiler and standard library, in "check" mode. +//! Implementation of compiling the compiler and standard library, in "check"-based modes. use crate::compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, rustc_cargo_env, add_to_sysroot}; -use crate::builder::{RunConfig, Builder, ShouldRun, Step}; +use crate::builder::{RunConfig, Builder, Kind, ShouldRun, Step}; use crate::tool::{prepare_tool_cargo, SourceType}; use crate::{Compiler, Mode}; use crate::cache::{INTERNER, Interned}; @@ -13,6 +13,22 @@ pub struct Std { pub target: Interned, } +fn args(kind: Kind) -> Vec { + match kind { + Kind::Clippy => vec!["--".to_owned(), "--cap-lints".to_owned(), "warn".to_owned()], + _ => Vec::new() + } +} + +fn cargo_subcommand(kind: Kind) -> &'static str { + match kind { + Kind::Check => "check", + Kind::Clippy => "clippy", + Kind::Fix => "fix", + _ => unreachable!() + } +} + impl Step for Std { type Output = (); const DEFAULT: bool = true; @@ -31,18 +47,20 @@ impl Step for Std { let target = self.target; let compiler = builder.compiler(0, builder.config.build); - let mut cargo = builder.cargo(compiler, Mode::Std, target, "check"); + let mut cargo = builder.cargo(compiler, Mode::Std, target, cargo_subcommand(builder.kind)); std_cargo(builder, &compiler, target, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage)); builder.info(&format!("Checking std artifacts ({} -> {})", &compiler.host, target)); run_cargo(builder, &mut cargo, + args(builder.kind), &libstd_stamp(builder, compiler, target), true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(&builder, &libdir, &libstd_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); } } @@ -77,18 +95,21 @@ impl Step for Rustc { builder.ensure(Test { target }); - let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "check"); + let mut cargo = builder.cargo(compiler, Mode::Rustc, target, + cargo_subcommand(builder.kind)); rustc_cargo(builder, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage)); builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target)); run_cargo(builder, &mut cargo, + args(builder.kind), &librustc_stamp(builder, compiler, target), true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(&builder, &libdir, &librustc_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target)); } } @@ -125,7 +146,8 @@ impl Step for CodegenBackend { builder.ensure(Rustc { target }); - let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "check"); + let mut cargo = builder.cargo(compiler, Mode::Codegen, target, + cargo_subcommand(builder.kind)); cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml")); rustc_cargo_env(builder, &mut cargo); @@ -134,6 +156,7 @@ impl Step for CodegenBackend { let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage)); run_cargo(builder, &mut cargo, + args(builder.kind), &codegen_backend_stamp(builder, compiler, target, backend), true); } @@ -164,18 +187,20 @@ impl Step for Test { builder.ensure(Std { target }); - let mut cargo = builder.cargo(compiler, Mode::Test, target, "check"); + let mut cargo = builder.cargo(compiler, Mode::Test, target, cargo_subcommand(builder.kind)); test_cargo(builder, &compiler, target, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage)); builder.info(&format!("Checking test artifacts ({} -> {})", &compiler.host, target)); run_cargo(builder, &mut cargo, + args(builder.kind), &libtest_stamp(builder, compiler, target), true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(builder, &libdir, &libtest_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(builder, &libdir, &hostdir, &libtest_stamp(builder, compiler, target)); } } @@ -209,7 +234,7 @@ impl Step for Rustdoc { compiler, Mode::ToolRustc, target, - "check", + cargo_subcommand(builder.kind), "src/tools/rustdoc", SourceType::InTree, &[]); @@ -218,11 +243,13 @@ impl Step for Rustdoc { println!("Checking rustdoc artifacts ({} -> {})", &compiler.host, target); run_cargo(builder, &mut cargo, + args(builder.kind), &rustdoc_stamp(builder, compiler, target), true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(&builder, &libdir, &rustdoc_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(&builder, &libdir, &hostdir, &rustdoc_stamp(builder, compiler, target)); builder.cargo(compiler, Mode::ToolRustc, target, "clean"); } } diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index b52e1a7b0e681..73be8bfed8e88 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -9,6 +9,8 @@ use std::fs; use std::io::{self, ErrorKind}; use std::path::Path; +use build_helper::t; + use crate::Build; pub fn clean(build: &Build, all: bool) { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 249a183189048..576267e6948f5 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -15,12 +15,13 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio, exit}; use std::str; -use build_helper::{output, mtime, up_to_date}; +use build_helper::{output, mtime, t, up_to_date}; use filetime::FileTime; +use serde::Deserialize; use serde_json; use crate::dist; -use crate::util::{exe, libdir, is_dylib}; +use crate::util::{exe, is_dylib}; use crate::{Compiler, Mode, GitRepo}; use crate::native; @@ -69,20 +70,20 @@ impl Step for Std { builder.ensure(StartupObjects { compiler, target }); - if builder.force_use_stage1(compiler, target) { - let from = builder.compiler(1, builder.config.build); + let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); + if compiler_to_use != compiler { builder.ensure(Std { - compiler: from, + compiler: compiler_to_use, target, }); - builder.info(&format!("Uplifting stage1 std ({} -> {})", from.host, target)); + builder.info(&format!("Uplifting stage1 std ({} -> {})", compiler_to_use.host, target)); // Even if we're not building std this stage, the new sysroot must // still contain the third party objects needed by various targets. copy_third_party_objects(builder, &compiler, target); builder.ensure(StdLink { - compiler: from, + compiler: compiler_to_use, target_compiler: compiler, target, }); @@ -99,6 +100,7 @@ impl Step for Std { &compiler.host, target)); run_cargo(builder, &mut cargo, + vec![], &libstd_stamp(builder, compiler, target), false); @@ -127,6 +129,13 @@ fn copy_third_party_objects(builder: &Builder<'_>, compiler: &Compiler, target: &libdir.join(obj), ); } + } else if target.ends_with("-wasi") { + for &obj in &["crt1.o"] { + builder.copy( + &builder.wasi_root(target).unwrap().join("lib/wasm32-wasi").join(obj), + &libdir.join(obj), + ); + } } // Copies libunwind.a compiled to be linked wit x86_64-fortanix-unknown-sgx. @@ -153,16 +162,43 @@ pub fn std_cargo(builder: &Builder<'_>, cargo.env("MACOSX_DEPLOYMENT_TARGET", target); } + // Determine if we're going to compile in optimized C intrinsics to + // the `compiler-builtins` crate. These intrinsics live in LLVM's + // `compiler-rt` repository, but our `src/llvm-project` submodule isn't + // always checked out, so we need to conditionally look for this. (e.g. if + // an external LLVM is used we skip the LLVM submodule checkout). + // + // Note that this shouldn't affect the correctness of `compiler-builtins`, + // but only its speed. Some intrinsics in C haven't been translated to Rust + // yet but that's pretty rare. Other intrinsics have optimized + // implementations in C which have only had slower versions ported to Rust, + // so we favor the C version where we can, but it's not critical. + // + // If `compiler-rt` is available ensure that the `c` feature of the + // `compiler-builtins` crate is enabled and it's configured to learn where + // `compiler-rt` is located. + let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt"); + let compiler_builtins_c_feature = if compiler_builtins_root.exists() { + cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root); + " compiler-builtins-c".to_string() + } else { + String::new() + }; + if builder.no_std(target) == Some(true) { + let mut features = "compiler-builtins-mem".to_string(); + features.push_str(&compiler_builtins_c_feature); + // for no-std targets we only compile a few no_std crates cargo .args(&["-p", "alloc"]) .arg("--manifest-path") .arg(builder.src.join("src/liballoc/Cargo.toml")) .arg("--features") - .arg("compiler-builtins-mem"); + .arg("compiler-builtins-mem compiler-builtins-c"); } else { - let features = builder.std_features(); + let mut features = builder.std_features(); + features.push_str(&compiler_builtins_c_feature); if compiler.stage != 0 && builder.config.sanitizers { // This variable is used by the sanitizer runtime crates, e.g. @@ -188,6 +224,12 @@ pub fn std_cargo(builder: &Builder<'_>, cargo.env("MUSL_ROOT", p); } } + + if target.ends_with("-wasi") { + if let Some(p) = builder.wasi_root(target) { + cargo.env("WASI_ROOT", p); + } + } } } @@ -224,7 +266,8 @@ impl Step for StdLink { target_compiler.host, target)); let libdir = builder.sysroot_libdir(target_compiler, target); - add_to_sysroot(builder, &libdir, &libstd_stamp(builder, compiler, target)); + let hostdir = builder.sysroot_libdir(target_compiler, compiler.host); + add_to_sysroot(builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); if builder.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" { // The sanitizers are only built in stage1 or above, so the dylibs will @@ -298,7 +341,7 @@ impl Step for StartupObjects { if !up_to_date(src_file, dst_file) { let mut cmd = Command::new(&builder.initial_rustc); builder.run(cmd.env("RUSTC_BOOTSTRAP", "1") - .arg("--cfg").arg("stage0") + .arg("--cfg").arg("bootstrap") .arg("--target").arg(target) .arg("--emit=obj") .arg("-o").arg(dst_file) @@ -360,15 +403,16 @@ impl Step for Test { return; } - if builder.force_use_stage1(compiler, target) { + let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); + if compiler_to_use != compiler { builder.ensure(Test { - compiler: builder.compiler(1, builder.config.build), + compiler: compiler_to_use, target, }); builder.info( &format!("Uplifting stage1 test ({} -> {})", builder.config.build, target)); builder.ensure(TestLink { - compiler: builder.compiler(1, builder.config.build), + compiler: compiler_to_use, target_compiler: compiler, target, }); @@ -383,6 +427,7 @@ impl Step for Test { &compiler.host, target)); run_cargo(builder, &mut cargo, + vec![], &libtest_stamp(builder, compiler, target), false); @@ -431,8 +476,12 @@ impl Step for TestLink { &compiler.host, target_compiler.host, target)); - add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target), - &libtest_stamp(builder, compiler, target)); + add_to_sysroot( + builder, + &builder.sysroot_libdir(target_compiler, target), + &builder.sysroot_libdir(target_compiler, compiler.host), + &libtest_stamp(builder, compiler, target) + ); builder.cargo(target_compiler, Mode::ToolTest, target, "clean"); } @@ -481,23 +530,24 @@ impl Step for Rustc { return; } - if builder.force_use_stage1(compiler, target) { + let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); + if compiler_to_use != compiler { builder.ensure(Rustc { - compiler: builder.compiler(1, builder.config.build), + compiler: compiler_to_use, target, }); builder.info(&format!("Uplifting stage1 rustc ({} -> {})", builder.config.build, target)); builder.ensure(RustcLink { - compiler: builder.compiler(1, builder.config.build), + compiler: compiler_to_use, target_compiler: compiler, target, }); return; } - // Ensure that build scripts have a std to link against. - builder.ensure(Std { + // Ensure that build scripts and proc macros have a std / libproc_macro to link against. + builder.ensure(Test { compiler: builder.compiler(self.compiler.stage, builder.config.build), target: builder.config.build, }); @@ -510,6 +560,7 @@ impl Step for Rustc { compiler.stage, &compiler.host, target)); run_cargo(builder, &mut cargo, + vec![], &librustc_stamp(builder, compiler, target), false); @@ -540,13 +591,6 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Command) { let libdir_relative = builder.config.libdir_relative().unwrap_or(Path::new("lib")); cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative); - // If we're not building a compiler with debugging information then remove - // these two env vars which would be set otherwise. - if builder.config.rust_debuginfo_only_std { - cargo.env_remove("RUSTC_DEBUGINFO"); - cargo.env_remove("RUSTC_DEBUGINFO_LINES"); - } - if let Some(ref ver_date) = builder.rust_info.commit_date() { cargo.env("CFG_VER_DATE", ver_date); } @@ -592,8 +636,12 @@ impl Step for RustcLink { &compiler.host, target_compiler.host, target)); - add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target), - &librustc_stamp(builder, compiler, target)); + add_to_sysroot( + builder, + &builder.sysroot_libdir(target_compiler, target), + &builder.sysroot_libdir(target_compiler, compiler.host), + &librustc_stamp(builder, compiler, target) + ); builder.cargo(target_compiler, Mode::ToolRustc, target, "clean"); } } @@ -641,9 +689,10 @@ impl Step for CodegenBackend { return; } - if builder.force_use_stage1(compiler, target) { + let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); + if compiler_to_use != compiler { builder.ensure(CodegenBackend { - compiler: builder.compiler(1, builder.config.build), + compiler: compiler_to_use, target, backend, }); @@ -664,6 +713,7 @@ impl Step for CodegenBackend { let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage)); let files = run_cargo(builder, cargo.arg("--features").arg(features), + vec![], &tmp_stamp, false); if builder.config.dry_run { @@ -725,6 +775,10 @@ pub fn build_codegen_backend(builder: &Builder<'_>, cargo.env("CFG_LLVM_ROOT", s); } } + // Some LLVM linker flags (-L and -l) may be needed to link librustc_llvm. + if let Some(ref s) = builder.config.llvm_ldflags { + cargo.env("LLVM_LINKER_FLAGS", s); + } // Building with a static libstdc++ is only supported on linux right now, // not for MSVC or macOS if builder.config.llvm_static_stdcpp && @@ -979,13 +1033,13 @@ impl Step for Assemble { // Link in all dylibs to the libdir let sysroot = builder.sysroot(target_compiler); - let sysroot_libdir = sysroot.join(libdir(&*host)); - t!(fs::create_dir_all(&sysroot_libdir)); + let rustc_libdir = builder.rustc_libdir(target_compiler); + t!(fs::create_dir_all(&rustc_libdir)); let src_libdir = builder.sysroot_libdir(build_compiler, host); for f in builder.read_dir(&src_libdir) { let filename = f.file_name().into_string().unwrap(); if is_dylib(&filename) { - builder.copy(&f.path(), &sysroot_libdir.join(&filename)); + builder.copy(&f.path(), &rustc_libdir.join(&filename)); } } @@ -1015,15 +1069,26 @@ impl Step for Assemble { /// /// For a particular stage this will link the file listed in `stamp` into the /// `sysroot_dst` provided. -pub fn add_to_sysroot(builder: &Builder<'_>, sysroot_dst: &Path, stamp: &Path) { +pub fn add_to_sysroot( + builder: &Builder<'_>, + sysroot_dst: &Path, + sysroot_host_dst: &Path, + stamp: &Path +) { t!(fs::create_dir_all(&sysroot_dst)); - for path in builder.read_stamp_file(stamp) { - builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap())); + t!(fs::create_dir_all(&sysroot_host_dst)); + for (path, host) in builder.read_stamp_file(stamp) { + if host { + builder.copy(&path, &sysroot_host_dst.join(path.file_name().unwrap())); + } else { + builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap())); + } } } pub fn run_cargo(builder: &Builder<'_>, cargo: &mut Command, + tail_args: Vec, stamp: &Path, is_check: bool) -> Vec @@ -1046,9 +1111,19 @@ pub fn run_cargo(builder: &Builder<'_>, // files we need to probe for later. let mut deps = Vec::new(); let mut toplevel = Vec::new(); - let ok = stream_cargo(builder, cargo, &mut |msg| { - let filenames = match msg { - CargoMessage::CompilerArtifact { filenames, .. } => filenames, + let ok = stream_cargo(builder, cargo, tail_args, &mut |msg| { + let (filenames, crate_types) = match msg { + CargoMessage::CompilerArtifact { + filenames, + target: CargoTarget { + crate_types, + }, + .. + } => (filenames, crate_types), + CargoMessage::CompilerMessage { message } => { + eprintln!("{}", message.rendered); + return; + } _ => return, }; for filename in filenames { @@ -1063,15 +1138,19 @@ pub fn run_cargo(builder: &Builder<'_>, let filename = Path::new(&*filename); // If this was an output file in the "host dir" we don't actually - // worry about it, it's not relevant for us. + // worry about it, it's not relevant for us if filename.starts_with(&host_root_dir) { + // Unless it's a proc macro used in the compiler + if crate_types.iter().any(|t| t == "proc-macro") { + deps.push((filename.to_path_buf(), true)); + } continue; } // If this was output in the `deps` dir then this is a precise file // name (hash included) so we start tracking it. if filename.starts_with(&target_deps_dir) { - deps.push(filename.to_path_buf()); + deps.push((filename.to_path_buf(), false)); continue; } @@ -1124,10 +1203,10 @@ pub fn run_cargo(builder: &Builder<'_>, let candidate = format!("{}.lib", path_to_add); let candidate = PathBuf::from(candidate); if candidate.exists() { - deps.push(candidate); + deps.push((candidate, false)); } } - deps.push(path_to_add.into()); + deps.push((path_to_add.into(), false)); } // Now we want to update the contents of the stamp file, if necessary. First @@ -1140,12 +1219,13 @@ pub fn run_cargo(builder: &Builder<'_>, let mut new_contents = Vec::new(); let mut max = None; let mut max_path = None; - for dep in deps.iter() { + for (dep, proc_macro) in deps.iter() { let mtime = mtime(dep); if Some(mtime) > max { max = Some(mtime); max_path = Some(dep.clone()); } + new_contents.extend(if *proc_macro { b"h" } else { b"t" }); new_contents.extend(dep.to_str().unwrap().as_bytes()); new_contents.extend(b"\0"); } @@ -1157,7 +1237,7 @@ pub fn run_cargo(builder: &Builder<'_>, if contents_equal && max <= stamp_mtime { builder.verbose(&format!("not updating {:?}; contents equal and {:?} <= {:?}", stamp, max, stamp_mtime)); - return deps + return deps.into_iter().map(|(d, _)| d).collect() } if max > stamp_mtime { builder.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path)); @@ -1165,12 +1245,13 @@ pub fn run_cargo(builder: &Builder<'_>, builder.verbose(&format!("updating {:?} as deps changed", stamp)); } t!(fs::write(&stamp, &new_contents)); - deps + deps.into_iter().map(|(d, _)| d).collect() } pub fn stream_cargo( builder: &Builder<'_>, cargo: &mut Command, + tail_args: Vec, cb: &mut dyn FnMut(CargoMessage<'_>), ) -> bool { if builder.config.dry_run { @@ -1181,6 +1262,10 @@ pub fn stream_cargo( cargo.arg("--message-format").arg("json") .stdout(Stdio::piped()); + for arg in tail_args { + cargo.arg(arg); + } + builder.verbose(&format!("running: {:?}", cargo)); let mut child = match cargo.spawn() { Ok(child) => child, @@ -1211,6 +1296,11 @@ pub fn stream_cargo( status.success() } +#[derive(Deserialize)] +pub struct CargoTarget<'a> { + crate_types: Vec>, +} + #[derive(Deserialize)] #[serde(tag = "reason", rename_all = "kebab-case")] pub enum CargoMessage<'a> { @@ -1218,8 +1308,17 @@ pub enum CargoMessage<'a> { package_id: Cow<'a, str>, features: Vec>, filenames: Vec>, + target: CargoTarget<'a>, }, BuildScriptExecuted { package_id: Cow<'a, str>, + }, + CompilerMessage { + message: ClippyMessage<'a> } } + +#[derive(Deserialize)] +pub struct ClippyMessage<'a> { + rendered: Cow<'a, str>, +} diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index d20958854ed6a..66f504ea924e9 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -10,8 +10,9 @@ use std::path::{Path, PathBuf}; use std::process; use std::cmp; -use num_cpus; +use build_helper::t; use toml; +use serde::Deserialize; use crate::cache::{INTERNER, Interned}; use crate::flags::Flags; pub use crate::flags::Subcommand; @@ -48,8 +49,9 @@ pub struct Config { pub exclude: Vec, pub rustc_error_format: Option, pub test_compare_mode: bool, + pub llvm_libunwind: bool, - pub run_host_only: bool, + pub skip_only_host_steps: bool, pub on_fail: Option, pub stage: Option, @@ -64,7 +66,6 @@ pub struct Config { pub backtrace_on_ice: bool, // llvm codegen options - pub llvm_enabled: bool, pub llvm_assertions: bool, pub llvm_optimize: bool, pub llvm_thin_lto: bool, @@ -94,15 +95,14 @@ pub struct Config { pub rust_codegen_units: Option, pub rust_codegen_units_std: Option, pub rust_debug_assertions: bool, - pub rust_debuginfo: bool, - pub rust_debuginfo_lines: bool, - pub rust_debuginfo_only_std: bool, - pub rust_debuginfo_tools: bool, + pub rust_debuginfo_level_rustc: u32, + pub rust_debuginfo_level_std: u32, + pub rust_debuginfo_level_tools: u32, + pub rust_debuginfo_level_tests: u32, pub rust_rpath: bool, pub rustc_parallel: bool, pub rustc_default_linker: Option, pub rust_optimize_tests: bool, - pub rust_debuginfo_tests: bool, pub rust_dist_src: bool, pub rust_codegen_backends: Vec>, pub rust_codegen_backends_dir: String, @@ -170,6 +170,7 @@ pub struct Target { pub ndk: Option, pub crt_static: Option, pub musl_root: Option, + pub wasi_root: Option, pub qemu_rootfs: Option, pub no_std: bool, } @@ -244,7 +245,6 @@ struct Install { #[derive(Deserialize, Default)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Llvm { - enabled: Option, ccache: Option, ninja: Option, assertions: Option, @@ -298,10 +298,11 @@ struct Rust { codegen_units: Option, codegen_units_std: Option, debug_assertions: Option, - debuginfo: Option, - debuginfo_lines: Option, - debuginfo_only_std: Option, - debuginfo_tools: Option, + debuginfo_level: Option, + debuginfo_level_rustc: Option, + debuginfo_level_std: Option, + debuginfo_level_tools: Option, + debuginfo_level_tests: Option, parallel_compiler: Option, backtrace: Option, default_linker: Option, @@ -309,7 +310,6 @@ struct Rust { musl_root: Option, rpath: Option, optimize_tests: Option, - debuginfo_tests: Option, codegen_tests: Option, ignore_git: Option, debug: Option, @@ -330,6 +330,7 @@ struct Rust { remap_debuginfo: Option, jemalloc: Option, test_compare_mode: Option, + llvm_libunwind: Option, } /// TOML representation of how each build target is configured. @@ -346,6 +347,7 @@ struct TomlTarget { android_ndk: Option, crt_static: Option, musl_root: Option, + wasi_root: Option, qemu_rootfs: Option, } @@ -360,7 +362,6 @@ impl Config { pub fn default_opts() -> Config { let mut config = Config::default(); - config.llvm_enabled = true; config.llvm_optimize = true; config.llvm_version_check = true; config.backtrace = true; @@ -399,7 +400,7 @@ impl Config { config.rustc_error_format = flags.rustc_error_format; config.on_fail = flags.on_fail; config.stage = flags.stage; - config.jobs = flags.jobs; + config.jobs = flags.jobs.map(threads_from_config); config.cmd = flags.cmd; config.incremental = flags.incremental; config.dry_run = flags.dry_run; @@ -415,7 +416,9 @@ impl Config { } // If --target was specified but --host wasn't specified, don't run any host-only tests. - config.run_host_only = !(flags.host.is_empty() && !flags.target.is_empty()); + let has_hosts = !flags.host.is_empty(); + let has_targets = !flags.target.is_empty(); + config.skip_only_host_steps = !has_hosts && has_targets; let toml = file.map(|file| { let contents = t!(fs::read_to_string(&file)); @@ -492,12 +495,13 @@ impl Config { // Store off these values as options because if they're not provided // we'll infer default values for them later let mut llvm_assertions = None; - let mut debuginfo_lines = None; - let mut debuginfo_only_std = None; - let mut debuginfo_tools = None; let mut debug = None; - let mut debuginfo = None; let mut debug_assertions = None; + let mut debuginfo_level = None; + let mut debuginfo_level_rustc = None; + let mut debuginfo_level_std = None; + let mut debuginfo_level_tools = None; + let mut debuginfo_level_tests = None; let mut optimize = None; let mut ignore_git = None; @@ -512,7 +516,6 @@ impl Config { Some(StringOrBool::Bool(false)) | None => {} } set(&mut config.ninja, llvm.ninja); - set(&mut config.llvm_enabled, llvm.enabled); llvm_assertions = llvm.assertions; set(&mut config.llvm_optimize, llvm.optimize); set(&mut config.llvm_thin_lto, llvm.thin_lto); @@ -538,18 +541,19 @@ impl Config { if let Some(ref rust) = toml.rust { debug = rust.debug; debug_assertions = rust.debug_assertions; - debuginfo = rust.debuginfo; - debuginfo_lines = rust.debuginfo_lines; - debuginfo_only_std = rust.debuginfo_only_std; - debuginfo_tools = rust.debuginfo_tools; + debuginfo_level = rust.debuginfo_level; + debuginfo_level_rustc = rust.debuginfo_level_rustc; + debuginfo_level_std = rust.debuginfo_level_std; + debuginfo_level_tools = rust.debuginfo_level_tools; + debuginfo_level_tests = rust.debuginfo_level_tests; optimize = rust.optimize; ignore_git = rust.ignore_git; set(&mut config.rust_optimize_tests, rust.optimize_tests); - set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests); set(&mut config.codegen_tests, rust.codegen_tests); set(&mut config.rust_rpath, rust.rpath); set(&mut config.jemalloc, rust.jemalloc); set(&mut config.test_compare_mode, rust.test_compare_mode); + set(&mut config.llvm_libunwind, rust.llvm_libunwind); set(&mut config.backtrace, rust.backtrace); set(&mut config.channel, rust.channel.clone()); set(&mut config.rust_dist_src, rust.dist_src); @@ -580,13 +584,8 @@ impl Config { set(&mut config.rust_codegen_backends_dir, rust.codegen_backends_dir.clone()); - match rust.codegen_units { - Some(0) => config.rust_codegen_units = Some(num_cpus::get() as u32), - Some(n) => config.rust_codegen_units = Some(n), - None => {} - } - - config.rust_codegen_units_std = rust.codegen_units_std; + config.rust_codegen_units = rust.codegen_units.map(threads_from_config); + config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config); } if let Some(ref t) = toml.target { @@ -609,6 +608,7 @@ impl Config { target.linker = cfg.linker.clone().map(PathBuf::from); target.crt_static = cfg.crt_static.clone(); target.musl_root = cfg.musl_root.clone().map(PathBuf::from); + target.wasi_root = cfg.wasi_root.clone().map(PathBuf::from); target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from); config.target_config.insert(INTERNER.intern_string(triple.clone()), target); @@ -635,18 +635,19 @@ impl Config { let default = true; config.rust_optimize = optimize.unwrap_or(default); - let default = match &config.channel[..] { - "stable" | "beta" | "nightly" => true, - _ => false, - }; - config.rust_debuginfo_lines = debuginfo_lines.unwrap_or(default); - config.rust_debuginfo_only_std = debuginfo_only_std.unwrap_or(default); - config.rust_debuginfo_tools = debuginfo_tools.unwrap_or(false); - let default = debug == Some(true); - config.rust_debuginfo = debuginfo.unwrap_or(default); config.rust_debug_assertions = debug_assertions.unwrap_or(default); + let with_defaults = |debuginfo_level_specific: Option| { + debuginfo_level_specific + .or(debuginfo_level) + .unwrap_or(if debug == Some(true) { 2 } else { 0 }) + }; + config.rust_debuginfo_level_rustc = with_defaults(debuginfo_level_rustc); + config.rust_debuginfo_level_std = with_defaults(debuginfo_level_std); + config.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools); + config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(0); + let default = config.channel == "dev"; config.ignore_git = ignore_git.unwrap_or(default); @@ -671,6 +672,11 @@ impl Config { pub fn very_verbose(&self) -> bool { self.verbose > 1 } + + pub fn llvm_enabled(&self) -> bool { + self.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) + || self.rust_codegen_backends.contains(&INTERNER.intern_str("emscripten")) + } } fn set(field: &mut T, val: Option) { @@ -678,3 +684,10 @@ fn set(field: &mut T, val: Option) { *field = v; } } + +fn threads_from_config(v: u32) -> u32 { + match v { + 0 => num_cpus::get() as u32, + n => n, + } +} diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index b2d8f2d8ebfcf..907983d43ade7 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -37,7 +37,6 @@ def v(*args): o("optimize-tests", "rust.optimize-tests", "build tests with optimizations") o("parallel-compiler", "rust.parallel-compiler", "build a multi-threaded rustc") o("test-miri", "rust.test-miri", "run miri's test suite") -o("debuginfo-tests", "rust.debuginfo-tests", "build tests with debugger metadata") o("verbose-tests", "rust.verbose-tests", "enable verbose output when running tests") o("ccache", "llvm.ccache", "invoke gcc/clang via ccache to reuse object files between builds") o("sccache", None, "invoke gcc/clang via sccache to reuse object files between builds") @@ -68,6 +67,8 @@ def v(*args): o("cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags") o("ldflags", "llvm.ldflags", "build LLVM with these extra linker flags") +o("llvm-libunwind", "rust.llvm_libunwind", "use LLVM libunwind") + # Optimization and debugging options. These may be overridden by the release # channel, etc. o("optimize", "rust.optimize", "build optimized rust code") @@ -75,10 +76,11 @@ def v(*args): o("llvm-assertions", "llvm.assertions", "build LLVM with assertions") o("debug-assertions", "rust.debug-assertions", "build with debugging assertions") o("llvm-release-debuginfo", "llvm.release-debuginfo", "build LLVM with debugger metadata") -o("debuginfo", "rust.debuginfo", "build with debugger metadata") -o("debuginfo-lines", "rust.debuginfo-lines", "build with line number debugger metadata") -o("debuginfo-only-std", "rust.debuginfo-only-std", "build only libstd with debugging information") -o("debuginfo-tools", "rust.debuginfo-tools", "build extended tools with debugging information") +v("debuginfo-level", "rust.debuginfo-level", "debuginfo level for Rust code") +v("debuginfo-level-rustc", "rust.debuginfo-level-rustc", "debuginfo level for the compiler") +v("debuginfo-level-std", "rust.debuginfo-level-std", "debuginfo level for the standard library") +v("debuginfo-level-tools", "rust.debuginfo-level-tools", "debuginfo level for the tools") +v("debuginfo-level-tests", "rust.debuginfo-level-tests", "debuginfo level for the test suites run with compiletest") v("save-toolstates", "rust.save-toolstates", "save build and test status of external tools into this file") v("prefix", "install.prefix", "set installation prefix") diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 2dae3f9135d84..45bc77ec97d47 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -14,11 +14,11 @@ use std::io::Write; use std::path::{PathBuf, Path}; use std::process::{Command, Stdio}; -use build_helper::output; +use build_helper::{output, t}; use crate::{Compiler, Mode, LLVM_TOOLS}; use crate::channel; -use crate::util::{libdir, is_dylib, exe}; +use crate::util::{is_dylib, exe}; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::compile; use crate::tool::{self, Tool}; @@ -68,7 +68,6 @@ fn missing_tool(tool_name: &str, skip: bool) { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Docs { - pub stage: u32, pub host: Interned, } @@ -82,7 +81,6 @@ impl Step for Docs { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Docs { - stage: run.builder.top_stage, host: run.target, }); } @@ -130,7 +128,6 @@ impl Step for Docs { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustcDocs { - pub stage: u32, pub host: Interned, } @@ -144,7 +141,6 @@ impl Step for RustcDocs { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RustcDocs { - stage: run.builder.top_stage, host: run.target, }); } @@ -473,21 +469,23 @@ impl Step for Rustc { fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) { let host = compiler.host; let src = builder.sysroot(compiler); - let libdir = libdir(&host); + let libdir = builder.rustc_libdir(compiler); // Copy rustc/rustdoc binaries t!(fs::create_dir_all(image.join("bin"))); builder.cp_r(&src.join("bin"), &image.join("bin")); - builder.install(&builder.rustdoc(compiler.host), &image.join("bin"), 0o755); + builder.install(&builder.rustdoc(compiler), &image.join("bin"), 0o755); + + let libdir_relative = builder.libdir_relative(compiler); // Copy runtime DLLs needed by the compiler - if libdir != "bin" { - for entry in builder.read_dir(&src.join(libdir)) { + if libdir_relative.to_str() != Some("bin") { + for entry in builder.read_dir(&libdir) { let name = entry.file_name(); if let Some(s) = name.to_str() { if is_dylib(s) { - builder.install(&entry.path(), &image.join(libdir), 0o644); + builder.install(&entry.path(), &image.join(&libdir_relative), 0o644); } } } @@ -645,7 +643,11 @@ impl Step for Std { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Std { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler_for( + run.builder.top_stage, + run.builder.config.build, + run.target, + ), target: run.target, }); } @@ -735,7 +737,14 @@ impl Step for Analysis { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Analysis { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + // Find the actual compiler (handling the full bootstrap option) which + // produced the save-analysis data because that data isn't copied + // through the sysroot uplifting. + compiler: run.builder.compiler_for( + run.builder.top_stage, + run.builder.config.build, + run.target, + ), target: run.target, }); } @@ -755,14 +764,6 @@ impl Step for Analysis { builder.ensure(Std { compiler, target }); - // Package save-analysis from stage1 if not doing a full bootstrap, as the - // stage2 artifacts is simply copied from stage1 in that case. - let compiler = if builder.force_use_stage1(compiler, target) { - builder.compiler(1, compiler.host) - } else { - compiler.clone() - }; - let image = tmpdir(builder).join(format!("{}-{}-image", name, target)); let src = builder.stage_out(compiler, Mode::Std) @@ -803,6 +804,7 @@ fn copy_src_dirs(builder: &Builder<'_>, src_dirs: &[&str], exclude_dirs: &[&str] const LLVM_PROJECTS: &[&str] = &[ "llvm-project/clang", "llvm-project\\clang", + "llvm-project/libunwind", "llvm-project\\libunwind", "llvm-project/lld", "llvm-project\\lld", "llvm-project/lldb", "llvm-project\\lldb", "llvm-project/llvm", "llvm-project\\llvm", @@ -904,6 +906,9 @@ impl Step for Src { "src/stdsimd", "src/libproc_macro", "src/tools/rustc-std-workspace-core", + "src/tools/rustc-std-workspace-alloc", + "src/librustc", + "src/libsyntax", ]; copy_src_dirs(builder, &std_src_dirs[..], &[], &dst_src); @@ -1061,7 +1066,7 @@ pub fn sanitize_sh(path: &Path) -> String { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Cargo { - pub stage: u32, + pub compiler: Compiler, pub target: Interned, } @@ -1075,16 +1080,20 @@ impl Step for Cargo { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Cargo { - stage: run.builder.top_stage, + compiler: run.builder.compiler_for( + run.builder.top_stage, + run.builder.config.build, + run.target, + ), target: run.target, }); } fn run(self, builder: &Builder<'_>) -> PathBuf { - let stage = self.stage; + let compiler = self.compiler; let target = self.target; - builder.info(&format!("Dist cargo stage{} ({})", stage, target)); + builder.info(&format!("Dist cargo stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/cargo"); let etc = src.join("src/etc"); let release_num = builder.release_num("cargo"); @@ -1099,10 +1108,7 @@ impl Step for Cargo { // Prepare the image directory builder.create_dir(&image.join("share/zsh/site-functions")); builder.create_dir(&image.join("etc/bash_completion.d")); - let cargo = builder.ensure(tool::Cargo { - compiler: builder.compiler(stage, builder.config.build), - target - }); + let cargo = builder.ensure(tool::Cargo { compiler, target }); builder.install(&cargo, &image.join("bin"), 0o755); for man in t!(etc.join("man").read_dir()) { let man = t!(man); @@ -1147,7 +1153,7 @@ impl Step for Cargo { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rls { - pub stage: u32, + pub compiler: Compiler, pub target: Interned, } @@ -1161,17 +1167,21 @@ impl Step for Rls { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Rls { - stage: run.builder.top_stage, + compiler: run.builder.compiler_for( + run.builder.top_stage, + run.builder.config.build, + run.target, + ), target: run.target, }); } fn run(self, builder: &Builder<'_>) -> Option { - let stage = self.stage; + let compiler = self.compiler; let target = self.target; assert!(builder.config.extended); - builder.info(&format!("Dist RLS stage{} ({})", stage, target)); + builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/rls"); let release_num = builder.release_num("rls"); let name = pkgname(builder, "rls"); @@ -1186,8 +1196,9 @@ impl Step for Rls { // We expect RLS to build, because we've exited this step above if tool // state for RLS isn't testing. let rls = builder.ensure(tool::Rls { - compiler: builder.compiler(stage, builder.config.build), - target, extra_features: Vec::new() + compiler, + target, + extra_features: Vec::new(), }).or_else(|| { missing_tool("RLS", builder.build.config.missing_tools); None })?; builder.install(&rls, &image.join("bin"), 0o755); @@ -1226,7 +1237,7 @@ impl Step for Rls { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Clippy { - pub stage: u32, + pub compiler: Compiler, pub target: Interned, } @@ -1240,17 +1251,21 @@ impl Step for Clippy { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Clippy { - stage: run.builder.top_stage, + compiler: run.builder.compiler_for( + run.builder.top_stage, + run.builder.config.build, + run.target, + ), target: run.target, }); } fn run(self, builder: &Builder<'_>) -> Option { - let stage = self.stage; + let compiler = self.compiler; let target = self.target; assert!(builder.config.extended); - builder.info(&format!("Dist clippy stage{} ({})", stage, target)); + builder.info(&format!("Dist clippy stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/clippy"); let release_num = builder.release_num("clippy"); let name = pkgname(builder, "clippy"); @@ -1265,11 +1280,12 @@ impl Step for Clippy { // We expect clippy to build, because we've exited this step above if tool // state for clippy isn't testing. let clippy = builder.ensure(tool::Clippy { - compiler: builder.compiler(stage, builder.config.build), - target, extra_features: Vec::new() + compiler, + target, + extra_features: Vec::new(), }).or_else(|| { missing_tool("clippy", builder.build.config.missing_tools); None })?; let cargoclippy = builder.ensure(tool::CargoClippy { - compiler: builder.compiler(stage, builder.config.build), + compiler, target, extra_features: Vec::new() }).or_else(|| { missing_tool("cargo clippy", builder.build.config.missing_tools); None })?; @@ -1310,7 +1326,7 @@ impl Step for Clippy { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Miri { - pub stage: u32, + pub compiler: Compiler, pub target: Interned, } @@ -1324,17 +1340,21 @@ impl Step for Miri { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Miri { - stage: run.builder.top_stage, + compiler: run.builder.compiler_for( + run.builder.top_stage, + run.builder.config.build, + run.target, + ), target: run.target, }); } fn run(self, builder: &Builder<'_>) -> Option { - let stage = self.stage; + let compiler = self.compiler; let target = self.target; assert!(builder.config.extended); - builder.info(&format!("Dist miri stage{} ({})", stage, target)); + builder.info(&format!("Dist miri stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/miri"); let release_num = builder.release_num("miri"); let name = pkgname(builder, "miri"); @@ -1349,12 +1369,14 @@ impl Step for Miri { // We expect miri to build, because we've exited this step above if tool // state for miri isn't testing. let miri = builder.ensure(tool::Miri { - compiler: builder.compiler(stage, builder.config.build), - target, extra_features: Vec::new() + compiler, + target, + extra_features: Vec::new(), }).or_else(|| { missing_tool("miri", builder.build.config.missing_tools); None })?; let cargomiri = builder.ensure(tool::CargoMiri { - compiler: builder.compiler(stage, builder.config.build), - target, extra_features: Vec::new() + compiler, + target, + extra_features: Vec::new() }).or_else(|| { missing_tool("cargo miri", builder.build.config.missing_tools); None })?; builder.install(&miri, &image.join("bin"), 0o755); @@ -1394,7 +1416,7 @@ impl Step for Miri { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustfmt { - pub stage: u32, + pub compiler: Compiler, pub target: Interned, } @@ -1408,16 +1430,20 @@ impl Step for Rustfmt { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Rustfmt { - stage: run.builder.top_stage, + compiler: run.builder.compiler_for( + run.builder.top_stage, + run.builder.config.build, + run.target, + ), target: run.target, }); } fn run(self, builder: &Builder<'_>) -> Option { - let stage = self.stage; + let compiler = self.compiler; let target = self.target; - builder.info(&format!("Dist Rustfmt stage{} ({})", stage, target)); + builder.info(&format!("Dist Rustfmt stage{} ({})", compiler.stage, target)); let src = builder.src.join("src/tools/rustfmt"); let release_num = builder.release_num("rustfmt"); let name = pkgname(builder, "rustfmt"); @@ -1430,12 +1456,14 @@ impl Step for Rustfmt { // Prepare the image directory let rustfmt = builder.ensure(tool::Rustfmt { - compiler: builder.compiler(stage, builder.config.build), - target, extra_features: Vec::new() + compiler, + target, + extra_features: Vec::new(), }).or_else(|| { missing_tool("Rustfmt", builder.build.config.missing_tools); None })?; let cargofmt = builder.ensure(tool::Cargofmt { - compiler: builder.compiler(stage, builder.config.build), - target, extra_features: Vec::new() + compiler, + target, + extra_features: Vec::new(), }).or_else(|| { missing_tool("Cargofmt", builder.build.config.missing_tools); None })?; builder.install(&rustfmt, &image.join("bin"), 0o755); @@ -1500,30 +1528,28 @@ impl Step for Extended { /// Creates a combined installer for the specified target in the provided stage. fn run(self, builder: &Builder<'_>) { - let stage = self.stage; let target = self.target; + let stage = self.stage; + let compiler = builder.compiler_for(self.stage, self.host, self.target); - builder.info(&format!("Dist extended stage{} ({})", stage, target)); + builder.info(&format!("Dist extended stage{} ({})", compiler.stage, target)); let rustc_installer = builder.ensure(Rustc { compiler: builder.compiler(stage, target), }); - let cargo_installer = builder.ensure(Cargo { stage, target }); - let rustfmt_installer = builder.ensure(Rustfmt { stage, target }); - let rls_installer = builder.ensure(Rls { stage, target }); - let llvm_tools_installer = builder.ensure(LlvmTools { stage, target }); - let clippy_installer = builder.ensure(Clippy { stage, target }); - let miri_installer = builder.ensure(Miri { stage, target }); + let cargo_installer = builder.ensure(Cargo { compiler, target }); + let rustfmt_installer = builder.ensure(Rustfmt { compiler, target }); + let rls_installer = builder.ensure(Rls { compiler, target }); + let llvm_tools_installer = builder.ensure(LlvmTools { target }); + let clippy_installer = builder.ensure(Clippy { compiler, target }); + let miri_installer = builder.ensure(Miri { compiler, target }); let lldb_installer = builder.ensure(Lldb { target }); let mingw_installer = builder.ensure(Mingw { host: target }); - let analysis_installer = builder.ensure(Analysis { - compiler: builder.compiler(stage, self.host), - target - }); + let analysis_installer = builder.ensure(Analysis { compiler, target }); - let docs_installer = builder.ensure(Docs { stage, host: target, }); + let docs_installer = builder.ensure(Docs { host: target, }); let std_installer = builder.ensure(Std { - compiler: builder.compiler(stage, self.host), + compiler: builder.compiler(stage, target), target, }); @@ -2071,7 +2097,6 @@ pub fn maybe_install_llvm_dylib(builder: &Builder<'_>, #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct LlvmTools { - pub stage: u32, pub target: Interned, } @@ -2085,26 +2110,24 @@ impl Step for LlvmTools { fn make_run(run: RunConfig<'_>) { run.builder.ensure(LlvmTools { - stage: run.builder.top_stage, target: run.target, }); } fn run(self, builder: &Builder<'_>) -> Option { - let stage = self.stage; let target = self.target; assert!(builder.config.extended); /* run only if llvm-config isn't used */ if let Some(config) = builder.config.target_config.get(&target) { if let Some(ref _s) = config.llvm_config { - builder.info(&format!("Skipping LlvmTools stage{} ({}): external LLVM", - stage, target)); + builder.info(&format!("Skipping LlvmTools ({}): external LLVM", + target)); return None; } } - builder.info(&format!("Dist LlvmTools stage{} ({})", stage, target)); + builder.info(&format!("Dist LlvmTools ({})", target)); let src = builder.src.join("src/llvm-project/llvm"); let name = pkgname(builder, "llvm-tools"); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index e0ad0422a6ce3..2969bbf5b0044 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -13,7 +13,7 @@ use std::io; use std::path::{PathBuf, Path}; use crate::Mode; -use build_helper::up_to_date; +use build_helper::{t, up_to_date}; use crate::util::symlink_dir; use crate::builder::{Builder, Compiler, RunConfig, ShouldRun, Step}; @@ -46,10 +46,11 @@ macro_rules! book { } fn run(self, builder: &Builder<'_>) { - builder.ensure(Rustbook { + builder.ensure(RustbookSrc { target: self.target, name: INTERNER.intern_str($book_name), version: $book_ver, + src: doc_src(builder), }) } } @@ -60,50 +61,23 @@ macro_rules! book { // NOTE: When adding a book here, make sure to ALSO build the book by // adding a build step in `src/bootstrap/builder.rs`! book!( - EditionGuide, "src/doc/edition-guide", "edition-guide", RustbookVersion::MdBook2; - EmbeddedBook, "src/doc/embedded-book", "embedded-book", RustbookVersion::MdBook2; - Nomicon, "src/doc/nomicon", "nomicon", RustbookVersion::MdBook1; + EditionGuide, "src/doc/edition-guide", "edition-guide", RustbookVersion::Latest; + EmbeddedBook, "src/doc/embedded-book", "embedded-book", RustbookVersion::Latest; + Nomicon, "src/doc/nomicon", "nomicon", RustbookVersion::Latest; Reference, "src/doc/reference", "reference", RustbookVersion::MdBook1; - RustByExample, "src/doc/rust-by-example", "rust-by-example", RustbookVersion::MdBook1; + RustByExample, "src/doc/rust-by-example", "rust-by-example", RustbookVersion::Latest; RustcBook, "src/doc/rustc", "rustc", RustbookVersion::MdBook1; - RustdocBook, "src/doc/rustdoc", "rustdoc", RustbookVersion::MdBook1; + RustdocBook, "src/doc/rustdoc", "rustdoc", RustbookVersion::Latest; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] enum RustbookVersion { MdBook1, - MdBook2, + Latest, } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -struct Rustbook { - target: Interned, - name: Interned, - version: RustbookVersion, -} - -impl Step for Rustbook { - type Output = (); - - // rustbook is never directly called, and only serves as a shim for the nomicon and the - // reference. - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.never() - } - - /// Invoke `rustbook` for `target` for the doc book `name`. - /// - /// This will not actually generate any documentation if the documentation has - /// already been generated. - fn run(self, builder: &Builder<'_>) { - let src = builder.src.join("src/doc"); - builder.ensure(RustbookSrc { - target: self.target, - name: self.name, - src: INTERNER.intern_path(src), - version: self.version, - }); - } +fn doc_src(builder: &Builder<'_>) -> Interned { + INTERNER.intern_path(builder.src.join("src/doc")) } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] @@ -134,7 +108,7 @@ impl Step for UnstableBook { target: self.target, name: INTERNER.intern_str("unstable-book"), src: builder.md_doc_out(self.target), - version: RustbookVersion::MdBook1, + version: RustbookVersion::Latest, }) } } @@ -222,7 +196,7 @@ impl Step for RustbookSrc { let vers = match self.version { RustbookVersion::MdBook1 => "1", - RustbookVersion::MdBook2 => "2", + RustbookVersion::Latest => "3", }; builder.run(rustbook_cmd @@ -274,33 +248,37 @@ impl Step for TheBook { let name = self.name; // build book - builder.ensure(Rustbook { + builder.ensure(RustbookSrc { target, name: INTERNER.intern_string(name.to_string()), - version: RustbookVersion::MdBook1, + version: RustbookVersion::Latest, + src: doc_src(builder), }); // building older edition redirects let source_name = format!("{}/first-edition", name); - builder.ensure(Rustbook { + builder.ensure(RustbookSrc { target, name: INTERNER.intern_string(source_name), - version: RustbookVersion::MdBook1, + version: RustbookVersion::Latest, + src: doc_src(builder), }); let source_name = format!("{}/second-edition", name); - builder.ensure(Rustbook { + builder.ensure(RustbookSrc { target, name: INTERNER.intern_string(source_name), - version: RustbookVersion::MdBook1, + version: RustbookVersion::Latest, + src: doc_src(builder), }); let source_name = format!("{}/2018-edition", name); - builder.ensure(Rustbook { + builder.ensure(RustbookSrc { target, name: INTERNER.intern_string(source_name), - version: RustbookVersion::MdBook1, + version: RustbookVersion::Latest, + src: doc_src(builder), }); // build the version info page and CSS @@ -331,24 +309,21 @@ fn invoke_rustdoc( let path = builder.src.join("src/doc").join(markdown); - let favicon = builder.src.join("src/doc/favicon.inc"); + let header = builder.src.join("src/doc/redirect.inc"); let footer = builder.src.join("src/doc/footer.inc"); let version_info = out.join("version_info.html"); - let mut cmd = builder.rustdoc_cmd(compiler.host); + let mut cmd = builder.rustdoc_cmd(compiler); let out = out.join("book"); cmd.arg("--html-after-content").arg(&footer) .arg("--html-before-content").arg(&version_info) - .arg("--html-in-header").arg(&favicon) + .arg("--html-in-header").arg(&header) .arg("--markdown-no-toc") - .arg("--markdown-playground-url") - .arg("https://play.rust-lang.org/") - .arg("-o").arg(&out) - .arg(&path) - .arg("--markdown-css") - .arg("../rust.css"); + .arg("--markdown-playground-url").arg("https://play.rust-lang.org/") + .arg("-o").arg(&out).arg(&path) + .arg("--markdown-css").arg("../rust.css"); builder.run(&mut cmd); } @@ -415,7 +390,7 @@ impl Step for Standalone { } let html = out.join(filename).with_extension("html"); - let rustdoc = builder.rustdoc(compiler.host); + let rustdoc = builder.rustdoc(compiler); if up_to_date(&path, &html) && up_to_date(&footer, &html) && up_to_date(&favicon, &html) && @@ -425,14 +400,13 @@ impl Step for Standalone { continue } - let mut cmd = builder.rustdoc_cmd(compiler.host); + let mut cmd = builder.rustdoc_cmd(compiler); cmd.arg("--html-after-content").arg(&footer) .arg("--html-before-content").arg(&version_info) .arg("--html-in-header").arg(&favicon) .arg("--markdown-no-toc") .arg("--index-page").arg(&builder.src.join("src/doc/index.md")) - .arg("--markdown-playground-url") - .arg("https://play.rust-lang.org/") + .arg("--markdown-playground-url").arg("https://play.rust-lang.org/") .arg("-o").arg(&out) .arg(&path); @@ -479,12 +453,7 @@ impl Step for Std { builder.info(&format!("Documenting stage{} std ({})", stage, target)); let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = builder.compiler(stage, builder.config.build); - let compiler = if builder.force_use_stage1(compiler, target) { - builder.compiler(1, compiler.host) - } else { - compiler - }; + let compiler = builder.compiler_for(stage, builder.config.build, target); builder.ensure(compile::Std { compiler, target }); let out_dir = builder.stage_out(compiler, Mode::Std) @@ -523,6 +492,7 @@ impl Step for Std { .arg("--markdown-css").arg("rust.css") .arg("--markdown-no-toc") .arg("--generate-redirect-pages") + .arg("--resource-suffix").arg(crate::channel::CFG_RELEASE_NUM) .arg("--index-page").arg(&builder.src.join("src/doc/index.md")); builder.run(&mut cargo); @@ -566,12 +536,7 @@ impl Step for Test { builder.info(&format!("Documenting stage{} test ({})", stage, target)); let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = builder.compiler(stage, builder.config.build); - let compiler = if builder.force_use_stage1(compiler, target) { - builder.compiler(1, compiler.host) - } else { - compiler - }; + let compiler = builder.compiler_for(stage, builder.config.build, target); // Build libstd docs so that we generate relative links builder.ensure(Std { stage, target }); @@ -589,6 +554,7 @@ impl Step for Test { cargo.arg("--no-deps") .arg("-p").arg("test") + .env("RUSTDOC_RESOURCE_SUFFIX", crate::channel::CFG_RELEASE_NUM) .env("RUSTDOC_GENERATE_REDIRECT_PAGES", "1"); builder.run(&mut cargo); @@ -634,12 +600,7 @@ impl Step for WhitelistedRustc { builder.info(&format!("Documenting stage{} whitelisted compiler ({})", stage, target)); let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = builder.compiler(stage, builder.config.build); - let compiler = if builder.force_use_stage1(compiler, target) { - builder.compiler(1, compiler.host) - } else { - compiler - }; + let compiler = builder.compiler_for(stage, builder.config.build, target); // Build libstd docs so that we generate relative links builder.ensure(Std { stage, target }); @@ -660,6 +621,7 @@ impl Step for WhitelistedRustc { // for which docs must be built. for krate in &["proc_macro"] { cargo.arg("-p").arg(krate) + .env("RUSTDOC_RESOURCE_SUFFIX", crate::channel::CFG_RELEASE_NUM) .env("RUSTDOC_GENERATE_REDIRECT_PAGES", "1"); } @@ -707,12 +669,7 @@ impl Step for Rustc { t!(fs::create_dir_all(&out)); // Get the correct compiler for this stage. - let compiler = builder.compiler(stage, builder.config.build); - let compiler = if builder.force_use_stage1(compiler, target) { - builder.compiler(1, compiler.host) - } else { - compiler - }; + let compiler = builder.compiler_for(stage, builder.config.build, target); if !builder.config.compiler_docs { builder.info("\tskipping - compiler/librustdoc docs disabled"); @@ -729,7 +686,7 @@ impl Step for Rustc { // Build cargo command. let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc"); - cargo.env("RUSTDOCFLAGS", "--document-private-items"); + cargo.env("RUSTDOCFLAGS", "--document-private-items --passes strip-hidden"); compile::rustc_cargo(builder, &mut cargo); // Only include compiler crates, no dependencies of those, such as `libc`. @@ -808,12 +765,7 @@ impl Step for Rustdoc { t!(fs::create_dir_all(&out)); // Get the correct compiler for this stage. - let compiler = builder.compiler(stage, builder.config.build); - let compiler = if builder.force_use_stage1(compiler, target) { - builder.compiler(1, compiler.host) - } else { - compiler - }; + let compiler = builder.compiler_for(stage, builder.config.build, target); if !builder.config.compiler_docs { builder.info("\tskipping - compiler/librustdoc docs disabled"); @@ -824,7 +776,7 @@ impl Step for Rustdoc { builder.ensure(Rustc { stage, target }); // Build rustdoc. - builder.ensure(tool::Rustdoc { host: compiler.host }); + builder.ensure(tool::Rustdoc { compiler: compiler }); // Symlink compiler docs to the output directory of rustdoc documentation. let out_dir = builder.stage_out(compiler, Mode::ToolRustc) @@ -883,9 +835,14 @@ impl Step for ErrorIndex { builder.info(&format!("Documenting error index ({})", target)); let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); - let mut index = builder.tool_cmd(Tool::ErrorIndex); + let compiler = builder.compiler(2, builder.config.build); + let mut index = tool::ErrorIndex::command( + builder, + compiler, + ); index.arg("html"); index.arg(out.join("error-index.html")); + index.arg(crate::channel::CFG_RELEASE_NUM); // FIXME: shouldn't have to pass this env var index.env("CFG_BUILD", &builder.config.build) @@ -919,11 +876,6 @@ impl Step for UnstableBookGen { fn run(self, builder: &Builder<'_>) { let target = self.target; - builder.ensure(compile::Std { - compiler: builder.compiler(builder.top_stage, builder.config.build), - target, - }); - builder.info(&format!("Generating unstable book md files ({})", target)); let out = builder.md_doc_out(target).join("unstable-book"); builder.create_dir(&out); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 0f9a4271ac062..179accda0c8b2 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -44,6 +44,12 @@ pub enum Subcommand { Check { paths: Vec, }, + Clippy { + paths: Vec, + }, + Fix { + paths: Vec, + }, Doc { paths: Vec, }, @@ -52,10 +58,12 @@ pub enum Subcommand { /// Whether to automatically update stderr/stdout files bless: bool, compare_mode: Option, + pass: Option, test_args: Vec, rustc_args: Vec, fail_fast: bool, doc_tests: DocTests, + rustfix_coverage: bool, }, Bench { paths: Vec, @@ -89,6 +97,8 @@ Usage: x.py [options] [...] Subcommands: build Compile either the compiler or libraries check Compile either the compiler or libraries, using cargo check + clippy Run clippy + fix Run cargo fix test Build and run some test suites bench Build and run some benchmarks doc Build documentation @@ -145,6 +155,8 @@ To learn more about a subcommand, run `./x.py -h`" let subcommand = args.iter().find(|&s| { (s == "build") || (s == "check") + || (s == "clippy") + || (s == "fix") || (s == "test") || (s == "bench") || (s == "doc") @@ -188,6 +200,18 @@ To learn more about a subcommand, run `./x.py -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", + "enable this to generate a Rustfix coverage file, which is saved in \ + `//rustfix_missing_coverage.txt`", + ); } "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); @@ -274,6 +298,28 @@ Arguments: the compiler.", ); } + "clippy" => { + subcommand_help.push_str( + "\n +Arguments: + This subcommand accepts a number of paths to directories to the crates + and/or artifacts to run clippy against. For example: + + ./x.py clippy src/libcore + ./x.py clippy src/libcore src/libproc_macro", + ); + } + "fix" => { + subcommand_help.push_str( + "\n +Arguments: + This subcommand accepts a number of paths to directories to the crates + and/or artifacts to run `cargo fix` against. For example: + + ./x.py fix src/libcore + ./x.py fix src/libcore src/libproc_macro", + ); + } "test" => { subcommand_help.push_str( "\n @@ -356,13 +402,17 @@ Arguments: let cmd = match subcommand.as_str() { "build" => Subcommand::Build { paths }, "check" => Subcommand::Check { paths }, + "clippy" => Subcommand::Clippy { paths }, + "fix" => Subcommand::Fix { paths }, "test" => Subcommand::Test { 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"), + rustfix_coverage: matches.opt_present("rustfix-coverage"), doc_tests: if matches.opt_present("doc") { DocTests::Only } else if matches.opt_present("no-doc") { @@ -467,6 +517,13 @@ impl Subcommand { } } + pub fn rustfix_coverage(&self) -> bool { + match *self { + Subcommand::Test { rustfix_coverage, .. } => rustfix_coverage, + _ => false, + } + } + pub fn compare_mode(&self) -> Option<&str> { match *self { Subcommand::Test { @@ -475,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 { diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 2d040d60e5fd7..557586709c612 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -5,10 +5,13 @@ use std::env; use std::fs; -use std::path::{Path, PathBuf, Component}; +use std::path::{Component, Path, PathBuf}; use std::process::Command; +use build_helper::t; + use crate::dist::{self, pkgname, sanitize_sh, tmpdir}; +use crate::Compiler; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::cache::Interned; @@ -56,7 +59,7 @@ fn install_sh( package: &str, name: &str, stage: u32, - host: Option> + host: Option>, ) { builder.info(&format!("Install {} stage{} ({:?})", package, stage, host)); @@ -142,9 +145,8 @@ macro_rules! install { $( #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct $name { - pub stage: u32, + pub compiler: Compiler, pub target: Interned, - pub host: Interned, } impl $name { @@ -173,9 +175,8 @@ macro_rules! install { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { - stage: run.builder.top_stage, + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), target: run.target, - host: run.builder.config.build, }); } @@ -188,67 +189,81 @@ macro_rules! install { install!((self, builder, _config), Docs, "src/doc", _config.docs, only_hosts: false, { - builder.ensure(dist::Docs { stage: self.stage, host: self.target }); - install_docs(builder, self.stage, self.target); + builder.ensure(dist::Docs { host: self.target }); + install_docs(builder, self.compiler.stage, self.target); }; Std, "src/libstd", true, only_hosts: true, { for target in &builder.targets { builder.ensure(dist::Std { - compiler: builder.compiler(self.stage, self.host), + compiler: self.compiler, target: *target }); - install_std(builder, self.stage, *target); + install_std(builder, self.compiler.stage, *target); } }; Cargo, "cargo", Self::should_build(_config), only_hosts: true, { - builder.ensure(dist::Cargo { stage: self.stage, target: self.target }); - install_cargo(builder, self.stage, self.target); + builder.ensure(dist::Cargo { compiler: self.compiler, target: self.target }); + install_cargo(builder, self.compiler.stage, self.target); }; Rls, "rls", Self::should_build(_config), only_hosts: true, { - if builder.ensure(dist::Rls { stage: self.stage, target: self.target }).is_some() || + if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() || Self::should_install(builder) { - install_rls(builder, self.stage, self.target); + install_rls(builder, self.compiler.stage, self.target); } else { - builder.info(&format!("skipping Install RLS stage{} ({})", self.stage, self.target)); + builder.info( + &format!("skipping Install RLS stage{} ({})", self.compiler.stage, self.target), + ); } }; Clippy, "clippy", Self::should_build(_config), only_hosts: true, { - if builder.ensure(dist::Clippy { stage: self.stage, target: self.target }).is_some() || - Self::should_install(builder) { - install_clippy(builder, self.stage, self.target); + if builder.ensure(dist::Clippy { + compiler: self.compiler, + target: self.target, + }).is_some() || Self::should_install(builder) { + install_clippy(builder, self.compiler.stage, self.target); } else { - builder.info(&format!("skipping Install clippy stage{} ({})", self.stage, self.target)); + builder.info( + &format!("skipping Install clippy stage{} ({})", self.compiler.stage, self.target), + ); } }; Miri, "miri", Self::should_build(_config), only_hosts: true, { - if builder.ensure(dist::Miri { stage: self.stage, target: self.target }).is_some() || + if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() || Self::should_install(builder) { - install_miri(builder, self.stage, self.target); + install_miri(builder, self.compiler.stage, self.target); } else { - builder.info(&format!("skipping Install miri stage{} ({})", self.stage, self.target)); + builder.info( + &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target), + ); } }; Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, { - if builder.ensure(dist::Rustfmt { stage: self.stage, target: self.target }).is_some() || - Self::should_install(builder) { - install_rustfmt(builder, self.stage, self.target); + if builder.ensure(dist::Rustfmt { + compiler: self.compiler, + target: self.target + }).is_some() || Self::should_install(builder) { + install_rustfmt(builder, self.compiler.stage, self.target); } else { builder.info( - &format!("skipping Install Rustfmt stage{} ({})", self.stage, self.target)); + &format!("skipping Install Rustfmt stage{} ({})", self.compiler.stage, self.target), + ); } }; Analysis, "analysis", Self::should_build(_config), only_hosts: false, { builder.ensure(dist::Analysis { - compiler: builder.compiler(self.stage, self.host), + // Find the actual compiler (handling the full bootstrap option) which + // produced the save-analysis data because that data isn't copied + // through the sysroot uplifting. + compiler: builder.compiler_for(builder.top_stage, builder.config.build, self.target), target: self.target }); - install_analysis(builder, self.stage, self.target); + install_analysis(builder, self.compiler.stage, self.target); }; Rustc, "src/librustc", true, only_hosts: true, { builder.ensure(dist::Rustc { - compiler: builder.compiler(self.stage, self.target), + compiler: self.compiler, }); - install_rustc(builder, self.stage, self.target); + install_rustc(builder, self.compiler.stage, self.target); }; ); @@ -264,15 +279,12 @@ impl Step for Src { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let config = &run.builder.config; - let cond = config.extended && - config.tools.as_ref().map_or(true, |t| t.contains("src")); + let cond = config.extended && config.tools.as_ref().map_or(true, |t| t.contains("src")); run.path("src").default_condition(cond) } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Src { - stage: run.builder.top_stage, - }); + run.builder.ensure(Src { stage: run.builder.top_stage }); } fn run(self, builder: &Builder<'_>) { diff --git a/src/bootstrap/job.rs b/src/bootstrap/job.rs index df492e0fdfd1c..6867d62a480bd 100644 --- a/src/bootstrap/job.rs +++ b/src/bootstrap/job.rs @@ -32,6 +32,7 @@ use std::env; use std::io; use std::mem; +use std::ptr; use crate::Build; type HANDLE = *mut u8; @@ -118,8 +119,8 @@ pub unsafe fn setup(build: &mut Build) { SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX); // Create a new job object for us to use - let job = CreateJobObjectW(0 as *mut _, 0 as *const _); - assert!(job != 0 as *mut _, "{}", io::Error::last_os_error()); + let job = CreateJobObjectW(ptr::null_mut(), ptr::null()); + assert!(!job.is_null(), "{}", io::Error::last_os_error()); // Indicate that when all handles to the job object are gone that all // process in the object should be killed. Note that this includes our @@ -166,8 +167,8 @@ pub unsafe fn setup(build: &mut Build) { }; let parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid.parse().unwrap()); - assert!(parent != 0 as *mut _, "{}", io::Error::last_os_error()); - let mut parent_handle = 0 as *mut _; + assert!(!parent.is_null(), "{}", io::Error::last_os_error()); + let mut parent_handle = ptr::null_mut(); let r = DuplicateHandle(GetCurrentProcess(), job, parent, &mut parent_handle, 0, FALSE, DUPLICATE_SAME_ACCESS); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 84e2c5aab54a3..4d297fa918a11 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -108,17 +108,6 @@ #![feature(core_intrinsics)] #![feature(drain_filter)] -#[macro_use] -extern crate build_helper; -#[macro_use] -extern crate serde_derive; -#[macro_use] -extern crate lazy_static; - -#[cfg(test)] -#[macro_use] -extern crate pretty_assertions; - use std::cell::{RefCell, Cell}; use std::collections::{HashSet, HashMap}; use std::env; @@ -134,7 +123,9 @@ use std::os::unix::fs::symlink as symlink_file; #[cfg(windows)] use std::os::windows::fs::symlink_file; -use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime}; +use build_helper::{ + mtime, output, run_silent, run_suppressed, t, try_run_silent, try_run_suppressed, +}; use filetime::FileTime; use crate::util::{exe, libdir, OutputFolder, CiEnv}; @@ -190,6 +181,7 @@ const LLVM_TOOLS: &[&str] = &[ "llvm-readobj", // used to get information from ELFs/objects that the other tools don't provide "llvm-size", // used to prints the size of the linker sections of a program "llvm-strip", // used to discard symbols from binary files to reduce their size + "llvm-ar" // used for creating and modifying archive files ]; /// A structure representing a Rust compiler. @@ -205,11 +197,11 @@ pub struct Compiler { #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub enum DocTests { - // Default, run normal tests and doc tests. + /// Run normal tests and doc tests (default). Yes, - // Do not run any doc tests. + /// Do not run any doc tests. No, - // Only run doc tests. + /// Only run doc tests. Only, } @@ -229,10 +221,10 @@ pub enum GitRepo { /// methods specifically on this structure itself (to make it easier to /// organize). pub struct Build { - // User-specified configuration via config.toml + /// User-specified configuration from `config.toml`. config: Config, - // Derived properties from the above two configurations + // Properties derived from the above configuration src: PathBuf, out: PathBuf, rust_info: channel::GitInfo, @@ -241,17 +233,19 @@ pub struct Build { clippy_info: channel::GitInfo, miri_info: channel::GitInfo, rustfmt_info: channel::GitInfo, + in_tree_llvm_info: channel::GitInfo, + emscripten_llvm_info: channel::GitInfo, local_rebuild: bool, fail_fast: bool, doc_tests: DocTests, verbosity: usize, - // Targets for which to build. + // Targets for which to build build: Interned, hosts: Vec>, targets: Vec>, - // Stage 0 (downloaded) compiler and cargo or their local rust equivalents. + // Stage 0 (downloaded) compiler and cargo or their local rust equivalents initial_rustc: PathBuf, initial_cargo: PathBuf, @@ -261,7 +255,7 @@ pub struct Build { cxx: HashMap, cc::Tool>, ar: HashMap, PathBuf>, ranlib: HashMap, PathBuf>, - // Misc + // Miscellaneous crates: HashMap, Crate>, is_sudo: bool, ci_env: CiEnv, @@ -276,14 +270,9 @@ pub struct Build { #[derive(Debug)] struct Crate { name: Interned, - version: String, deps: HashSet>, id: String, path: PathBuf, - doc_step: String, - build_step: String, - test_step: String, - bench_step: String, } impl Crate { @@ -357,12 +346,18 @@ impl Build { } None => false, }; - let rust_info = channel::GitInfo::new(&config, &src); - let cargo_info = channel::GitInfo::new(&config, &src.join("src/tools/cargo")); - let rls_info = channel::GitInfo::new(&config, &src.join("src/tools/rls")); - let clippy_info = channel::GitInfo::new(&config, &src.join("src/tools/clippy")); - let miri_info = channel::GitInfo::new(&config, &src.join("src/tools/miri")); - let rustfmt_info = channel::GitInfo::new(&config, &src.join("src/tools/rustfmt")); + + let ignore_git = config.ignore_git; + let rust_info = channel::GitInfo::new(ignore_git, &src); + let cargo_info = channel::GitInfo::new(ignore_git, &src.join("src/tools/cargo")); + let rls_info = channel::GitInfo::new(ignore_git, &src.join("src/tools/rls")); + let clippy_info = channel::GitInfo::new(ignore_git, &src.join("src/tools/clippy")); + let miri_info = channel::GitInfo::new(ignore_git, &src.join("src/tools/miri")); + let rustfmt_info = channel::GitInfo::new(ignore_git, &src.join("src/tools/rustfmt")); + + // we always try to use git for LLVM builds + let in_tree_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-project")); + let emscripten_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-emscripten")); let mut build = Build { initial_rustc: config.initial_rustc.clone(), @@ -386,6 +381,8 @@ impl Build { clippy_info, miri_info, rustfmt_info, + in_tree_llvm_info, + emscripten_llvm_info, cc: HashMap::new(), cxx: HashMap::new(), ar: HashMap::new(), @@ -495,6 +492,9 @@ impl Build { fn std_features(&self) -> String { let mut features = "panic-unwind".to_string(); + if self.config.llvm_libunwind { + features.push_str(" llvm-libunwind"); + } if self.config.backtrace { features.push_str(" backtrace"); } @@ -720,6 +720,17 @@ impl Build { } } + pub fn is_verbose_than(&self, level: usize) -> bool { + self.verbosity > level + } + + /// Prints a message if this build is configured in more verbose mode than `level`. + fn verbose_than(&self, level: usize, msg: &str) { + if self.is_verbose_than(level) { + println!("{}", msg); + } + } + fn info(&self, msg: &str) { if self.config.dry_run { return; } println!("{}", msg); @@ -843,6 +854,13 @@ impl Build { .map(|p| &**p) } + /// Returns the sysroot for the wasi target, if defined + fn wasi_root(&self, target: Interned) -> Option<&Path> { + self.config.target_config.get(&target) + .and_then(|t| t.wasi_root.as_ref()) + .map(|p| &**p) + } + /// Returns `true` if this is a no-std `target`, if defined fn no_std(&self, target: Interned) -> Option { self.config.target_config.get(&target) @@ -1017,7 +1035,7 @@ impl Build { } fn llvm_tools_package_vers(&self) -> String { - self.package_vers(&self.rust_version()) + self.package_vers(channel::CFG_RELEASE_NUM) } fn llvm_tools_vers(&self) -> String { @@ -1025,7 +1043,7 @@ impl Build { } fn lldb_package_vers(&self) -> String { - self.package_vers(&self.rust_version()) + self.package_vers(channel::CFG_RELEASE_NUM) } fn lldb_vers(&self) -> String { @@ -1093,8 +1111,6 @@ impl Build { /// `rust.save-toolstates` in `config.toml`. If unspecified, nothing will be /// done. The file is updated immediately after this function completes. pub fn save_toolstate(&self, tool: &str, state: ToolState) { - use std::io::{Seek, SeekFrom}; - if let Some(ref path) = self.config.save_toolstates { let mut file = t!(fs::OpenOptions::new() .create(true) @@ -1129,7 +1145,7 @@ impl Build { ret } - fn read_stamp_file(&self, stamp: &Path) -> Vec { + fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, bool)> { if self.config.dry_run { return Vec::new(); } @@ -1142,8 +1158,9 @@ impl Build { if part.is_empty() { continue } - let path = PathBuf::from(t!(str::from_utf8(part))); - paths.push(path); + let host = part[0] as char == 'h'; + let path = PathBuf::from(t!(str::from_utf8(&part[1..]))); + paths.push((path, host)); } paths } @@ -1151,6 +1168,7 @@ impl Build { /// Copies a file from `src` to `dst` pub fn copy(&self, src: &Path, dst: &Path) { if self.config.dry_run { return; } + self.verbose_than(1, &format!("Copy {:?} to {:?}", src, dst)); let _ = fs::remove_file(&dst); let metadata = t!(src.symlink_metadata()); if metadata.file_type().is_symlink() { @@ -1191,8 +1209,7 @@ impl Build { /// when this function is called. pub fn cp_r(&self, src: &Path, dst: &Path) { if self.config.dry_run { return; } - for f in t!(fs::read_dir(src)) { - let f = t!(f); + for f in self.read_dir(src) { let path = f.path(); let name = path.file_name().unwrap(); let dst = dst.join(name); @@ -1244,6 +1261,7 @@ impl Build { fn install(&self, src: &Path, dstdir: &Path, perms: u32) { if self.config.dry_run { return; } let dst = dstdir.join(src.file_name().unwrap()); + self.verbose_than(1, &format!("Install {:?} to {:?}", src, dst)); t!(fs::create_dir_all(dstdir)); drop(fs::remove_file(&dst)); { diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 7fa377f310b4f..b622b3682a777 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -4,6 +4,7 @@ use std::path::PathBuf; use std::collections::HashSet; use build_helper::output; +use serde::Deserialize; use serde_json; use crate::{Build, Crate}; @@ -19,7 +20,6 @@ struct Output { struct Package { id: String, name: String, - version: String, source: Option, manifest_path: String, } @@ -83,12 +83,7 @@ fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec 0 { + enabled_llvm_projects.sort(); + enabled_llvm_projects.dedup(); + cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";")); + } + if let Some(num_linkers) = builder.config.llvm_link_jobs { if num_linkers > 0 { cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string()); @@ -231,7 +257,21 @@ impl Step for Llvm { } if let Some(ref suffix) = builder.config.llvm_version_suffix { - cfg.define("LLVM_VERSION_SUFFIX", suffix); + // Allow version-suffix="" to not define a version suffix at all. + if !suffix.is_empty() { + cfg.define("LLVM_VERSION_SUFFIX", suffix); + } + } else { + let mut default_suffix = format!( + "-rust-{}-{}", + channel::CFG_RELEASE_NUM, + builder.config.channel, + ); + if let Some(sha) = llvm_info.sha_short() { + default_suffix.push_str("-"); + default_suffix.push_str(sha); + } + cfg.define("LLVM_VERSION_SUFFIX", default_suffix); } if let Some(ref linker) = builder.config.llvm_use_linker { @@ -259,7 +299,9 @@ impl Step for Llvm { cfg.build(); - t!(fs::write(&done_stamp, &rebuild_trigger_contents)); + if let Some(llvm_commit) = llvm_info.sha() { + t!(fs::write(&done_stamp, llvm_commit)); + } build_llvm_config } @@ -289,6 +331,10 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { fn configure_cmake(builder: &Builder<'_>, target: Interned, cfg: &mut cmake::Config) { + // Do not print installation messages for up-to-date files. + // LLVM and LLD builds can produce a lot of those and hit CI limits on log size. + cfg.define("CMAKE_INSTALL_MESSAGE", "LAZY"); + if builder.config.ninja { cfg.generator("Ninja"); } @@ -370,7 +416,7 @@ fn configure_cmake(builder: &Builder<'_>, cfg.build_arg("-j").build_arg(builder.jobs().to_string()); let mut cflags = builder.cflags(target, GitRepo::Llvm).join(" "); - if let Some(ref s) = builder.config.llvm_cxxflags { + if let Some(ref s) = builder.config.llvm_cflags { cflags.push_str(&format!(" {}", s)); } cfg.define("CMAKE_C_FLAGS", cflags); @@ -408,7 +454,7 @@ fn configure_cmake(builder: &Builder<'_>, } if env::var_os("SCCACHE_ERROR_LOG").is_some() { - cfg.env("RUST_LOG", "sccache=warn"); + cfg.env("RUSTC_LOG", "sccache=warn"); } } diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index ff4fb85bbfad3..dc65fb9b79706 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -15,7 +15,7 @@ use std::fs; use std::path::PathBuf; use std::process::Command; -use build_helper::output; +use build_helper::{output, t}; use crate::Build; @@ -34,15 +34,17 @@ impl Finder { fn maybe_have>(&mut self, cmd: S) -> Option { let cmd: OsString = cmd.as_ref().into(); - let path = self.path.clone(); + let path = &self.path; self.cache.entry(cmd.clone()).or_insert_with(|| { - for path in env::split_paths(&path) { + for path in env::split_paths(path) { let target = path.join(&cmd); - let mut cmd_alt = cmd.clone(); - cmd_alt.push(".exe"); - if target.is_file() || // some/path/git - target.with_extension("exe").exists() || // some/path/git.exe - target.join(&cmd_alt).exists() { // some/path/git/git.exe + let mut cmd_exe = cmd.clone(); + cmd_exe.push(".exe"); + + if target.is_file() // some/path/git + || path.join(&cmd_exe).exists() // some/path/git.exe + || target.join(&cmd_exe).exists() // some/path/git/git.exe + { return Some(target); } } @@ -107,9 +109,9 @@ pub fn check(build: &mut Build) { } build.config.python = build.config.python.take().map(|p| cmd_finder.must_have(p)) - .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py .or_else(|| cmd_finder.maybe_have("python2.7")) .or_else(|| cmd_finder.maybe_have("python2")) + .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py .or_else(|| Some(cmd_finder.must_have("python"))); build.config.nodejs = build.config.nodejs.take().map(|p| cmd_finder.must_have(p)) @@ -129,6 +131,11 @@ pub fn check(build: &mut Build) { continue; } + // We don't use a C compiler on wasm32 + if target.contains("wasm32") { + continue; + } + if !build.config.dry_run { cmd_finder.must_have(build.cc(*target)); if let Some(ar) = build.ar(*target) { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 51412f79c3d0c..1d54ca16a315b 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -11,7 +11,7 @@ use std::iter; use std::path::{Path, PathBuf}; use std::process::Command; -use build_helper::{self, output}; +use build_helper::{self, output, t}; use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; @@ -177,7 +177,7 @@ impl Step for Cargotest { cmd.arg(&builder.initial_cargo) .arg(&out_dir) .env("RUSTC", builder.rustc(compiler)) - .env("RUSTDOC", builder.rustdoc(compiler.host)), + .env("RUSTDOC", builder.rustdoc(compiler)), ); } } @@ -414,7 +414,6 @@ impl Step for Miri { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct CompiletestTest { - stage: u32, host: Interned, } @@ -427,16 +426,14 @@ impl Step for CompiletestTest { fn make_run(run: RunConfig<'_>) { run.builder.ensure(CompiletestTest { - stage: run.builder.top_stage, host: run.target, }); } /// Runs `cargo test` for compiletest. fn run(self, builder: &Builder<'_>) { - let stage = self.stage; let host = self.host; - let compiler = builder.compiler(stage, host); + let compiler = builder.compiler(0, host); let mut cargo = tool::prepare_tool_cargo(builder, compiler, @@ -563,7 +560,7 @@ impl Step for RustdocTheme { builder.sysroot_libdir(self.compiler, self.compiler.host), ) .env("CFG_RELEASE_CHANNEL", &builder.config.channel) - .env("RUSTDOC_REAL", builder.rustdoc(self.compiler.host)) + .env("RUSTDOC_REAL", builder.rustdoc(self.compiler)) .env("RUSTDOC_CRATE_VERSION", builder.rust_version()) .env("RUSTC_BOOTSTRAP", "1"); if let Some(linker) = builder.linker(self.compiler.host) { @@ -574,22 +571,22 @@ impl Step for RustdocTheme { } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub struct RustdocJS { +pub struct RustdocJSStd { pub host: Interned, pub target: Interned, } -impl Step for RustdocJS { +impl Step for RustdocJSStd { type Output = (); const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/test/rustdoc-js") + run.path("src/test/rustdoc-js-std") } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(RustdocJS { + run.builder.ensure(RustdocJSStd { host: run.host, target: run.target, }); @@ -598,12 +595,55 @@ impl Step for RustdocJS { fn run(self, builder: &Builder<'_>) { if let Some(ref nodejs) = builder.config.nodejs { let mut command = Command::new(nodejs); - command.args(&["src/tools/rustdoc-js/tester.js", &*self.host]); + command.args(&["src/tools/rustdoc-js-std/tester.js", &*self.host]); builder.ensure(crate::doc::Std { target: self.target, stage: builder.top_stage, }); builder.run(&mut command); + } else { + builder.info( + "No nodejs found, skipping \"src/test/rustdoc-js-std\" tests" + ); + } + } +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct RustdocJSNotStd { + pub host: Interned, + pub target: Interned, + pub compiler: Compiler, +} + +impl Step for RustdocJSNotStd { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/test/rustdoc-js") + } + + fn make_run(run: RunConfig<'_>) { + let compiler = run.builder.compiler(run.builder.top_stage, run.host); + run.builder.ensure(RustdocJSNotStd { + host: run.host, + target: run.target, + compiler, + }); + } + + fn run(self, builder: &Builder<'_>) { + if builder.config.nodejs.is_some() { + builder.ensure(Compiletest { + compiler: self.compiler, + target: self.target, + mode: "js-doc-test", + suite: "rustdoc-js", + path: None, + compare_mode: None, + }); } else { builder.info( "No nodejs found, skipping \"src/test/rustdoc-js\" tests" @@ -643,7 +683,7 @@ impl Step for RustdocUi { target: self.target, mode: "ui", suite: "rustdoc-ui", - path: None, + path: Some("src/test/rustdoc-ui"), compare_mode: None, }) } @@ -669,8 +709,8 @@ impl Step for Tidy { if !builder.config.vendor { cmd.arg("--no-vendor"); } - if !builder.config.verbose_tests { - cmd.arg("--quiet"); + if builder.is_verbose() { + cmd.arg("--verbose"); } let _folder = builder.fold_output(|| "tidy"); @@ -854,12 +894,10 @@ host_test!(Rustdoc { suite: "rustdoc" }); -test!(Pretty { +host_test!(Pretty { path: "src/test/pretty", mode: "pretty", - suite: "pretty", - default: false, - host: true + suite: "pretty" }); test!(RunPassPretty { path: "src/test/run-pass/pretty", @@ -895,6 +933,12 @@ host_test!(RunMakeFullDeps { suite: "run-make-fulldeps" }); +default_test!(Assembly { + path: "src/test/assembly", + mode: "assembly", + suite: "assembly" +}); + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] struct Compiletest { compiler: Compiler, @@ -932,14 +976,10 @@ impl Step for Compiletest { } if suite == "debuginfo" { - // Skip debuginfo tests on MSVC - if builder.config.build.contains("msvc") { - return; - } - + let msvc = builder.config.build.contains("msvc"); if mode == "debuginfo" { return builder.ensure(Compiletest { - mode: "debuginfo-both", + mode: if msvc { "debuginfo-cdb" } else { "debuginfo-gdb+lldb" }, ..self }); } @@ -950,11 +990,7 @@ impl Step for Compiletest { }); } - if suite.ends_with("fulldeps") || - // FIXME: Does pretty need librustc compiled? Note that there are - // fulldeps test suites with mode = pretty as well. - mode == "pretty" - { + if suite.ends_with("fulldeps") { builder.ensure(compile::Rustc { compiler, target }); } @@ -976,7 +1012,10 @@ impl Step for Compiletest { // Also provide `rust_test_helpers` for the host. builder.ensure(native::TestHelpers { target: compiler.host }); - builder.ensure(native::TestHelpers { target }); + // wasm32 can't build the test helpers + if !target.contains("wasm32") { + builder.ensure(native::TestHelpers { target }); + } builder.ensure(RemoteCopyLibs { compiler, target }); let mut cmd = builder.tool_cmd(Tool::Compiletest); @@ -990,15 +1029,16 @@ impl Step for Compiletest { .arg(builder.sysroot_libdir(compiler, target)); cmd.arg("--rustc-path").arg(builder.rustc(compiler)); - let is_rustdoc_ui = suite.ends_with("rustdoc-ui"); + let is_rustdoc = suite.ends_with("rustdoc-ui") || suite.ends_with("rustdoc-js"); // Avoid depending on rustdoc when we don't need it. if mode == "rustdoc" || (mode == "run-make" && suite.ends_with("fulldeps")) - || (mode == "ui" && is_rustdoc_ui) + || (mode == "ui" && is_rustdoc) + || mode == "js-doc-test" { cmd.arg("--rustdoc-path") - .arg(builder.rustdoc(compiler.host)); + .arg(builder.rustdoc(compiler)); } cmd.arg("--src-base") @@ -1025,23 +1065,26 @@ 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); } - let mut flags = if is_rustdoc_ui { + let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] }; - if !is_rustdoc_ui { + if !is_rustdoc { if builder.config.rust_optimize_tests { flags.push("-O".to_string()); } - if builder.config.rust_debuginfo_tests { - flags.push("-g".to_string()); - } } + flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests)); flags.push("-Zunstable-options".to_string()); flags.push(builder.config.cmd.rustc_args().join(" ")); @@ -1105,24 +1148,9 @@ impl Step for Compiletest { } } - if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") { - match &var.to_string_lossy().to_lowercase()[..] { - "1" | "yes" | "on" => { - assert!(builder.config.lldb_enabled, - "RUSTBUILD_FORCE_CLANG_BASED_TESTS needs Clang/LLDB to \ - be built."); - let clang_exe = builder.llvm_out(target).join("bin").join("clang"); - cmd.arg("--run-clang-based-tests-with").arg(clang_exe); - } - "0" | "no" | "off" => { - // Nothing to do. - } - other => { - // Let's make sure typos don't get unnoticed - panic!("Unrecognized option '{}' set in \ - RUSTBUILD_FORCE_CLANG_BASED_TESTS", other); - } - } + if util::forcing_clang_based_tests() { + let clang_exe = builder.llvm_out(target).join("bin").join("clang"); + cmd.arg("--run-clang-based-tests-with").arg(clang_exe); } // Get paths from cmd args @@ -1140,8 +1168,19 @@ impl Step for Compiletest { Err(_) => p, } }) - .filter(|p| p.starts_with(suite_path) && p.is_file()) - .map(|p| p.strip_prefix(suite_path).unwrap().to_str().unwrap()) + .filter(|p| p.starts_with(suite_path) && (p.is_dir() || p.is_file())) + .filter_map(|p| { + // Since test suite paths are themselves directories, if we don't + // specify a directory or file, we'll get an empty string here + // (the result of the test suite directory without its suite prefix). + // Therefore, we need to filter these out, as only the first --test-args + // flag is respected, so providing an empty --test-args conflicts with + // any following it. + match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) { + Some(s) if s != "" => Some(s), + _ => None, + } + }) .collect(); test_args.append(&mut builder.config.cmd.test_args()); @@ -1156,7 +1195,7 @@ impl Step for Compiletest { cmd.arg("--quiet"); } - if builder.config.llvm_enabled { + if builder.config.llvm_enabled() { let llvm_config = builder.ensure(native::Llvm { target: builder.config.build, emscripten: false, @@ -1187,14 +1226,30 @@ impl Step for Compiletest { if let Some(ar) = builder.ar(target) { cmd.arg("--ar").arg(ar); } + + // The llvm/bin directory contains many useful cross-platform + // tools. Pass the path to run-make tests so they can use them. + let llvm_bin_path = llvm_config.parent() + .expect("Expected llvm-config to be contained in directory"); + assert!(llvm_bin_path.is_dir()); + cmd.arg("--llvm-bin-dir").arg(llvm_bin_path); + + // If LLD is available, add it to the PATH + if builder.config.lld_enabled { + let lld_install_root = builder.ensure(native::Lld { + target: builder.config.build, + }); + + let lld_bin_path = lld_install_root.join("bin"); + + let old_path = env::var_os("PATH").unwrap_or_default(); + let new_path = env::join_paths(std::iter::once(lld_bin_path) + .chain(env::split_paths(&old_path))) + .expect("Could not add LLD bin path to PATH"); + cmd.env("PATH", new_path); + } } } - if suite == "run-make-fulldeps" && !builder.config.llvm_enabled { - builder.info( - "Ignoring run-make test suite as they generally don't work without LLVM" - ); - return; - } if suite != "run-make-fulldeps" { cmd.arg("--cc") @@ -1230,11 +1285,11 @@ impl Step for Compiletest { builder.add_rust_test_threads(&mut cmd); if builder.config.sanitizers { - cmd.env("SANITIZER_SUPPORT", "1"); + cmd.env("RUSTC_SANITIZER_SUPPORT", "1"); } if builder.config.profiler { - cmd.env("PROFILER_SUPPORT", "1"); + cmd.env("RUSTC_PROFILER_SUPPORT", "1"); } cmd.env("RUST_TEST_TMPDIR", builder.out.join("tmp")); @@ -1249,6 +1304,10 @@ impl Step for Compiletest { cmd.arg("--android-cross-path").arg(""); } + if builder.config.cmd.rustfix_coverage() { + cmd.arg("--rustfix-coverage"); + } + builder.ci_env.force_coloring_in_ci(&mut cmd); let _folder = builder.fold_output(|| format!("test_{}", suite)); @@ -1386,6 +1445,7 @@ test_book!( EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false; TheBook, "src/doc/book", "book", default=false; UnstableBook, "src/doc/unstable-book", "unstable-book", default=true; + EditionGuide, "src/doc/edition-guide", "edition-guide", default=false; ); #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -1426,7 +1486,10 @@ impl Step for ErrorIndex { t!(fs::create_dir_all(&dir)); let output = dir.join("error-index.md"); - let mut tool = builder.tool_cmd(Tool::ErrorIndex); + let mut tool = tool::ErrorIndex::command( + builder, + builder.compiler(compiler.stage, builder.config.build), + ); tool.arg("markdown") .arg(&output) .env("CFG_BUILD", &builder.config.build) @@ -1451,7 +1514,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> } builder.info(&format!("doc tests for: {}", markdown.display())); - let mut cmd = builder.rustdoc_cmd(compiler.host); + let mut cmd = builder.rustdoc_cmd(compiler); builder.add_rust_test_threads(&mut cmd); cmd.arg("--test"); cmd.arg(markdown); @@ -1632,15 +1695,11 @@ impl Step for Crate { builder.ensure(compile::Test { compiler, target }); builder.ensure(RemoteCopyLibs { compiler, target }); - // If we're not doing a full bootstrap but we're testing a stage2 version of - // libstd, then what we're actually testing is the libstd produced in - // stage1. Reflect that here by updating the compiler that we're working - // with automatically. - let compiler = if builder.force_use_stage1(compiler, target) { - builder.compiler(1, compiler.host) - } else { - compiler.clone() - }; + // If we're not doing a full bootstrap but we're testing a stage2 + // version of libstd, then what we're actually testing is the libstd + // produced in stage1. Reflect that here by updating the compiler that + // we're working with automatically. + let compiler = builder.compiler_for(compiler.stage, compiler.host, target); let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand()); match mode { @@ -1802,6 +1861,10 @@ impl Step for CrateRustdoc { cargo.arg("--"); cargo.args(&builder.config.cmd.test_args()); + if self.host.contains("musl") { + cargo.arg("'-Ctarget-feature=-crt-static'"); + } + if !builder.config.verbose_tests { cargo.arg("--quiet"); } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index fc1a17d546675..bd77f7a91d94a 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -4,12 +4,13 @@ use std::path::PathBuf; use std::process::{Command, exit}; use std::collections::HashSet; +use build_helper::t; + use crate::Mode; use crate::Compiler; use crate::builder::{Step, RunConfig, ShouldRun, Builder}; use crate::util::{exe, add_lib_path}; use crate::compile; -use crate::native; use crate::channel::GitInfo; use crate::channel; use crate::cache::Interned; @@ -76,13 +77,14 @@ impl Step for ToolBuild { let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool)); builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target)); let mut duplicates = Vec::new(); - let is_expected = compile::stream_cargo(builder, &mut cargo, &mut |msg| { + let is_expected = compile::stream_cargo(builder, &mut cargo, vec![], &mut |msg| { // Only care about big things like the RLS/Cargo for now match tool { | "rls" | "cargo" | "clippy-driver" | "miri" + | "rustfmt" => {} _ => return, @@ -91,7 +93,8 @@ impl Step for ToolBuild { compile::CargoMessage::CompilerArtifact { package_id, features, - filenames + filenames, + target: _, } => { (package_id, features, filenames) } @@ -234,7 +237,7 @@ pub fn prepare_tool_cargo( cargo.env("CFG_VERSION", builder.rust_version()); cargo.env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM); - let info = GitInfo::new(&builder.config, &dir); + let info = GitInfo::new(builder.config.ignore_git, &dir); if let Some(sha) = info.sha() { cargo.env("CFG_COMMIT_HASH", sha); } @@ -250,9 +253,9 @@ pub fn prepare_tool_cargo( cargo } -macro_rules! tool { +macro_rules! bootstrap_tool { ($( - $name:ident, $path:expr, $tool_name:expr, $mode:expr + $name:ident, $path:expr, $tool_name:expr $(,llvm_tools = $llvm:expr)* $(,is_external_tool = $external:expr)* ; @@ -265,13 +268,6 @@ macro_rules! tool { } impl Tool { - pub fn get_mode(&self) -> Mode { - let mode = match self { - $(Tool::$name => $mode,)+ - }; - mode - } - /// Whether this tool requires LLVM to run pub fn uses_llvm_tools(&self) -> bool { match self { @@ -282,27 +278,15 @@ macro_rules! tool { impl<'a> Builder<'a> { pub fn tool_exe(&self, tool: Tool) -> PathBuf { - let stage = self.tool_default_stage(tool); match tool { $(Tool::$name => self.ensure($name { - compiler: self.compiler(stage, self.config.build), + compiler: self.compiler(0, self.config.build), target: self.config.build, }), )+ } } - - pub fn tool_default_stage(&self, tool: Tool) -> u32 { - // Compile the error-index in the same stage as rustdoc to avoid - // recompiling rustdoc twice if we can. Otherwise compile - // everything else in stage0 as there's no need to rebootstrap - // everything. - match tool { - Tool::ErrorIndex if self.top_stage >= 2 => self.top_stage, - _ => 0, - } - } } $( @@ -321,7 +305,8 @@ macro_rules! tool { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + // snapshot compiler + compiler: run.builder.compiler(0, run.builder.config.build), target: run.target, }); } @@ -331,7 +316,7 @@ macro_rules! tool { compiler: self.compiler, target: self.target, tool: $tool_name, - mode: $mode, + mode: Mode::ToolBootstrap, path: $path, is_optional_tool: false, source_type: if false $(|| $external)* { @@ -347,21 +332,67 @@ macro_rules! tool { } } -tool!( - Rustbook, "src/tools/rustbook", "rustbook", Mode::ToolBootstrap; - ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::ToolRustc; - UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::ToolBootstrap; - Tidy, "src/tools/tidy", "tidy", Mode::ToolBootstrap; - Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::ToolBootstrap; - CargoTest, "src/tools/cargotest", "cargotest", Mode::ToolBootstrap; - Compiletest, "src/tools/compiletest", "compiletest", Mode::ToolBootstrap, llvm_tools = true; - BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::ToolBootstrap; - RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::ToolBootstrap; - RustInstaller, "src/tools/rust-installer", "fabricate", Mode::ToolBootstrap, - is_external_tool = true; - RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes", Mode::ToolBootstrap; +bootstrap_tool!( + Rustbook, "src/tools/rustbook", "rustbook"; + UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen"; + Tidy, "src/tools/tidy", "tidy"; + Linkchecker, "src/tools/linkchecker", "linkchecker"; + CargoTest, "src/tools/cargotest", "cargotest"; + Compiletest, "src/tools/compiletest", "compiletest", llvm_tools = true; + BuildManifest, "src/tools/build-manifest", "build-manifest"; + RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; + RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true; + RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes"; ); +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct ErrorIndex { + pub compiler: Compiler, +} + +impl ErrorIndex { + pub fn command(builder: &Builder<'_>, compiler: Compiler) -> Command { + let mut cmd = Command::new(builder.ensure(ErrorIndex { + compiler + })); + add_lib_path( + vec![PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host))], + &mut cmd, + ); + cmd + } +} + +impl Step for ErrorIndex { + type Output = PathBuf; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/error_index_generator") + } + + fn make_run(run: RunConfig<'_>) { + // Compile the error-index in the same stage as rustdoc to avoid + // recompiling rustdoc twice if we can. + let stage = if run.builder.top_stage >= 2 { run.builder.top_stage } else { 0 }; + run.builder.ensure(ErrorIndex { + compiler: run.builder.compiler(stage, run.builder.config.build), + }); + } + + fn run(self, builder: &Builder<'_>) -> PathBuf { + builder.ensure(ToolBuild { + compiler: self.compiler, + target: self.compiler.host, + tool: "error_index_generator", + mode: Mode::ToolRustc, + path: "src/tools/error_index_generator", + is_optional_tool: false, + source_type: SourceType::InTree, + extra_features: Vec::new(), + }).expect("expected to build -- essential tool") + } +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RemoteTestServer { pub compiler: Compiler, @@ -398,7 +429,9 @@ impl Step for RemoteTestServer { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustdoc { - pub host: Interned, + /// This should only ever be 0 or 2. + /// We sometimes want to reference the "bootstrap" rustdoc, which is why this option is here. + pub compiler: Compiler, } impl Step for Rustdoc { @@ -412,12 +445,12 @@ impl Step for Rustdoc { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Rustdoc { - host: run.host, + compiler: run.builder.compiler(run.builder.top_stage, run.host), }); } fn run(self, builder: &Builder<'_>) -> PathBuf { - let target_compiler = builder.compiler(builder.top_stage, self.host); + let target_compiler = self.compiler; if target_compiler.stage == 0 { if !target_compiler.is_snapshot(builder) { panic!("rustdoc in stage 0 must be snapshot rustdoc"); @@ -449,10 +482,6 @@ impl Step for Rustdoc { &[], ); - // Most tools don't get debuginfo, but rustdoc should. - cargo.env("RUSTC_DEBUGINFO", builder.config.rust_debuginfo.to_string()) - .env("RUSTC_DEBUGINFO_LINES", builder.config.rust_debuginfo_lines.to_string()); - let _folder = builder.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage)); builder.info(&format!("Building rustdoc for stage{} ({})", target_compiler.stage, target_compiler.host)); @@ -503,9 +532,9 @@ impl Step for Cargo { } fn run(self, builder: &Builder<'_>) -> PathBuf { - // Cargo depends on procedural macros, which requires a full host - // compiler to be available, so we need to depend on that. - builder.ensure(compile::Rustc { + // Cargo depends on procedural macros, so make sure the host + // libstd/libproc_macro is available. + builder.ensure(compile::Test { compiler: self.compiler, target: builder.config.build, }); @@ -577,26 +606,26 @@ macro_rules! tool_extended { tool_extended!((self, builder), Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", {}; CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", { - // Clippy depends on procedural macros (serde), which requires a full host - // compiler to be available, so we need to depend on that. - builder.ensure(compile::Rustc { + // Clippy depends on procedural macros, so make sure that's built for + // the compiler itself. + builder.ensure(compile::Test { compiler: self.compiler, target: builder.config.build, }); }; Clippy, clippy, "src/tools/clippy", "clippy-driver", { - // Clippy depends on procedural macros (serde), which requires a full host - // compiler to be available, so we need to depend on that. - builder.ensure(compile::Rustc { + // Clippy depends on procedural macros, so make sure that's built for + // the compiler itself. + builder.ensure(compile::Test { compiler: self.compiler, target: builder.config.build, }); }; Miri, miri, "src/tools/miri", "miri", {}; CargoMiri, miri, "src/tools/miri", "cargo-miri", { - // Miri depends on procedural macros (serde), which requires a full host - // compiler to be available, so we need to depend on that. - builder.ensure(compile::Rustc { + // Miri depends on procedural macros, so make sure that's built for + // the compiler itself. + builder.ensure(compile::Test { compiler: self.compiler, target: builder.config.build, }); @@ -610,9 +639,9 @@ tool_extended!((self, builder), if clippy.is_some() { self.extra_features.push("clippy".to_owned()); } - // RLS depends on procedural macros, which requires a full host - // compiler to be available, so we need to depend on that. - builder.ensure(compile::Rustc { + // RLS depends on procedural macros, so make sure that's built for + // the compiler itself. + builder.ensure(compile::Test { compiler: self.compiler, target: builder.config.build, }); @@ -625,24 +654,15 @@ impl<'a> Builder<'a> { /// `host`. pub fn tool_cmd(&self, tool: Tool) -> Command { let mut cmd = Command::new(self.tool_exe(tool)); - let compiler = self.compiler(self.tool_default_stage(tool), self.config.build); - self.prepare_tool_cmd(compiler, tool, &mut cmd); - cmd - } - - /// Prepares the `cmd` provided to be able to run the `compiler` provided. - /// - /// Notably this munges the dynamic library lookup path to point to the - /// right location to run `compiler`. - fn prepare_tool_cmd(&self, compiler: Compiler, tool: Tool, cmd: &mut Command) { + let compiler = self.compiler(0, self.config.build); let host = &compiler.host; + // Prepares the `cmd` provided to be able to run the `compiler` provided. + // + // Notably this munges the dynamic library lookup path to point to the + // right location to run `compiler`. let mut lib_paths: Vec = vec![ - if compiler.stage == 0 && tool != Tool::ErrorIndex { - self.build.rustc_snapshot_libdir() - } else { - PathBuf::from(&self.sysroot_libdir(compiler, compiler.host)) - }, - self.cargo_out(compiler, tool.get_mode(), *host).join("deps"), + self.build.rustc_snapshot_libdir(), + self.cargo_out(compiler, Mode::ToolBootstrap, *host).join("deps"), ]; // On MSVC a tool may invoke a C compiler (e.g., compiletest in run-make @@ -663,56 +683,7 @@ impl<'a> Builder<'a> { } } - // Add the llvm/bin directory to PATH since it contains lots of - // useful, platform-independent tools - if tool.uses_llvm_tools() && !self.config.dry_run { - let mut additional_paths = vec![]; - - if let Some(llvm_bin_path) = self.llvm_bin_path() { - additional_paths.push(llvm_bin_path); - } - - // If LLD is available, add that too. - if self.config.lld_enabled { - let lld_install_root = self.ensure(native::Lld { - target: self.config.build, - }); - - let lld_bin_path = lld_install_root.join("bin"); - additional_paths.push(lld_bin_path); - } - - if host.contains("windows") { - // On Windows, PATH and the dynamic library path are the same, - // so we just add the LLVM bin path to lib_path - lib_paths.extend(additional_paths); - } else { - let old_path = env::var_os("PATH").unwrap_or_default(); - let new_path = env::join_paths(additional_paths.into_iter() - .chain(env::split_paths(&old_path))) - .expect("Could not add LLVM bin path to PATH"); - cmd.env("PATH", new_path); - } - } - - add_lib_path(lib_paths, cmd); - } - - fn llvm_bin_path(&self) -> Option { - if self.config.llvm_enabled { - let llvm_config = self.ensure(native::Llvm { - target: self.config.build, - emscripten: false, - }); - - // Add the llvm/bin directory to PATH since it contains lots of - // useful, platform-independent tools - let llvm_bin_path = llvm_config.parent() - .expect("Expected llvm-config to be contained in directory"); - assert!(llvm_bin_path.is_dir()); - Some(llvm_bin_path.to_path_buf()) - } else { - None - } + add_lib_path(lib_paths, &mut cmd); + cmd } } diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index 8ff7c09fc2996..e86209be91fe1 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + #[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] /// Whether a tool can be compiled, tested or neither diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index bda1e56e1e73b..47f5edd15631a 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -11,6 +11,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::time::{SystemTime, Instant}; +use build_helper::t; + use crate::config::Config; use crate::builder::Builder; @@ -207,7 +209,7 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> { let h = CreateFileW(path.as_ptr(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - 0 as *mut _, + ptr::null_mut(), OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, ptr::null_mut()); @@ -324,6 +326,8 @@ pub enum CiEnv { Travis, /// The AppVeyor environment, for Windows builds. AppVeyor, + /// The Azure Pipelines environment, for Linux (including Docker), Windows, and macOS builds. + AzurePipelines, } impl CiEnv { @@ -333,6 +337,8 @@ impl CiEnv { CiEnv::Travis } else if env::var("APPVEYOR").ok().map_or(false, |e| &*e == "True") { CiEnv::AppVeyor + } else if env::var("TF_BUILD").ok().map_or(false, |e| &*e == "True") { + CiEnv::AzurePipelines } else { CiEnv::None } @@ -350,3 +356,19 @@ impl CiEnv { } } } + +pub fn forcing_clang_based_tests() -> bool { + if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") { + match &var.to_string_lossy().to_lowercase()[..] { + "1" | "yes" | "on" => true, + "0" | "no" | "off" => false, + other => { + // Let's make sure typos don't go unnoticed + panic!("Unrecognized option '{}' set in \ + RUSTBUILD_FORCE_CLANG_BASED_TESTS", other) + } + } + } else { + false + } +} diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index bd99dc118e66a..8b00c1d81b08c 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -113,7 +113,7 @@ pub fn gnu_target(target: &str) -> &str { } pub fn make(host: &str) -> PathBuf { - if host.contains("bitrig") || host.contains("dragonfly") || host.contains("freebsd") + if host.contains("dragonfly") || host.contains("freebsd") || host.contains("netbsd") || host.contains("openbsd") { PathBuf::from("gmake") @@ -288,9 +288,9 @@ pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) } else { format!("static={}", link_name) }; - // The source for `compiler-rt` comes from the `compiler-builtins` crate, so - // load our env var set by cargo to find the source code. - let dir = env::var_os("DEP_COMPILER_RT_COMPILER_RT").unwrap(); + // This env var is provided by rustbuild to tell us where `compiler-rt` + // lives. + let dir = env::var_os("RUST_COMPILER_RT_ROOT").unwrap(); let lib = native_lib_boilerplate( dir.as_ref(), sanitizer_name, diff --git a/src/ci/awscli-requirements.txt b/src/ci/awscli-requirements.txt new file mode 100644 index 0000000000000..c1ffa525a1b41 --- /dev/null +++ b/src/ci/awscli-requirements.txt @@ -0,0 +1,13 @@ +awscli==1.16.201 +botocore==1.12.191 +colorama==0.3.9 +docutils==0.14 +jmespath==0.9.4 +pyasn1==0.4.5 +python-dateutil==2.8.0 +PyYAML==5.1 +rsa==3.4.2 +s3transfer==0.2.1 +six==1.12.0 +urllib3==1.25.3 +futures==3.3.0; python_version < '3.0' diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml new file mode 100644 index 0000000000000..2e6c3b7a992af --- /dev/null +++ b/src/ci/azure-pipelines/auto.yml @@ -0,0 +1,350 @@ +# +# Azure Pipelines "auto" branch build for Rust on Linux, macOS, and Windows. +# + +pr: none +trigger: + - auto + +variables: +- group: real-prod-credentials + +jobs: +- job: Linux + timeoutInMinutes: 600 + pool: + vmImage: ubuntu-16.04 + steps: + - template: steps/run.yml + strategy: + matrix: + x86_64-gnu-llvm-6.0: + IMAGE: x86_64-gnu-llvm-6.0 + RUST_BACKTRACE: 1 + + dist-x86_64-linux: + IMAGE: dist-x86_64-linux + DEPLOY: 1 + + # "alternate" deployments, these are "nightlies" but have LLVM assertions + # turned on, they're deployed to a different location primarily for + # additional testing. + dist-x86_64-linux-alt: + IMAGE: dist-x86_64-linux + DEPLOY_ALT: 1 + + # Linux builders, remaining docker images + arm-android: + IMAGE: arm-android + + armhf-gnu: + IMAGE: armhf-gnu + + dist-various-1: + IMAGE: dist-various-1 + DEPLOY: 1 + + dist-various-2: + IMAGE: dist-various-2 + DEPLOY: 1 + + dist-aarch64-linux: + IMAGE: dist-aarch64-linux + DEPLOY: 1 + + dist-android: + IMAGE: dist-android + DEPLOY: 1 + + dist-arm-linux: + IMAGE: dist-arm-linux + DEPLOY: 1 + + dist-armhf-linux: + IMAGE: dist-armhf-linux + DEPLOY: 1 + + dist-armv7-linux: + IMAGE: dist-armv7-linux + DEPLOY: 1 + + dist-i586-gnu-i586-i686-musl: + IMAGE: dist-i586-gnu-i586-i686-musl + DEPLOY: 1 + + dist-i686-freebsd: + IMAGE: dist-i686-freebsd + DEPLOY: 1 + + dist-i686-linux: + IMAGE: dist-i686-linux + DEPLOY: 1 + + dist-mips-linux: + IMAGE: dist-mips-linux + DEPLOY: 1 + + dist-mips64-linux: + IMAGE: dist-mips64-linux + DEPLOY: 1 + + dist-mips64el-linux: + IMAGE: dist-mips64el-linux + DEPLOY: 1 + + dist-mipsel-linux: + IMAGE: dist-mipsel-linux + DEPLOY: 1 + + dist-powerpc-linux: + IMAGE: dist-powerpc-linux + DEPLOY: 1 + + dist-powerpc64-linux: + IMAGE: dist-powerpc64-linux + DEPLOY: 1 + + dist-powerpc64le-linux: + IMAGE: dist-powerpc64le-linux + DEPLOY: 1 + + dist-s390x-linux: + IMAGE: dist-s390x-linux + DEPLOY: 1 + + dist-x86_64-freebsd: + IMAGE: dist-x86_64-freebsd + DEPLOY: 1 + + dist-x86_64-musl: + IMAGE: dist-x86_64-musl + DEPLOY: 1 + + dist-x86_64-netbsd: + IMAGE: dist-x86_64-netbsd + DEPLOY: 1 + + asmjs: + IMAGE: asmjs + i686-gnu: + IMAGE: i686-gnu + i686-gnu-nopt: + IMAGE: i686-gnu-nopt + test-various: + IMAGE: test-various + x86_64-gnu: + IMAGE: x86_64-gnu + x86_64-gnu-full-bootstrap: + IMAGE: x86_64-gnu-full-bootstrap + x86_64-gnu-aux: + IMAGE: x86_64-gnu-aux + x86_64-gnu-tools: + IMAGE: x86_64-gnu-tools + x86_64-gnu-debug: + IMAGE: x86_64-gnu-debug + x86_64-gnu-nopt: + IMAGE: x86_64-gnu-nopt + x86_64-gnu-distcheck: + IMAGE: x86_64-gnu-distcheck + mingw-check: + IMAGE: mingw-check + +- job: macOS + timeoutInMinutes: 600 + pool: + vmImage: macos-10.13 + steps: + - template: steps/run.yml + strategy: + matrix: + # OSX builders running tests, these run the full test suite. + # NO_DEBUG_ASSERTIONS=1 to make them go faster, but also do have some + # runners that run `//ignore-debug` tests. + # + # Note that the compiler is compiled to target 10.8 here because the Xcode + # version that we're using, 8.2, cannot compile LLVM for OSX 10.7. + x86_64-apple: + SCRIPT: ./x.py test + RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + + dist-x86_64-apple: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --enable-lldb --set rust.jemalloc + DEPLOY: 1 + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + + dist-x86_64-apple-alt: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --enable-lldb --set rust.jemalloc + DEPLOY_ALT: 1 + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + + i686-apple: + SCRIPT: ./x.py test + RUST_CONFIGURE_ARGS: --build=i686-apple-darwin --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + + dist-i686-apple: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --build=i686-apple-darwin --enable-full-tools --enable-profiler --enable-lldb --set rust.jemalloc + DEPLOY: 1 + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + + + +- job: Windows + timeoutInMinutes: 600 + pool: + vmImage: 'vs2017-win2016' + steps: + - template: steps/run.yml + strategy: + matrix: + # 32/64 bit MSVC tests + x86_64-msvc-1: + MSYS_BITS: 64 + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler + SCRIPT: make ci-subset-1 + # FIXME(#59637) + NO_DEBUG_ASSERTIONS: 1 + NO_LLVM_ASSERTIONS: 1 + x86_64-msvc-2: + MSYS_BITS: 64 + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler + SCRIPT: make ci-subset-2 + i686-msvc-1: + MSYS_BITS: 32 + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc + SCRIPT: make ci-subset-1 + i686-msvc-2: + MSYS_BITS: 32 + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc + SCRIPT: make ci-subset-2 + # MSVC aux tests + x86_64-msvc-aux: + MSYS_BITS: 64 + RUST_CHECK_TARGET: check-aux EXCLUDE_CARGO=1 + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc + x86_64-msvc-cargo: + MSYS_BITS: 64 + SCRIPT: python x.py test src/tools/cargotest src/tools/cargo + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc + VCVARS_BAT: vcvars64.bat + # MSVC tools tests + x86_64-msvc-tools: + MSYS_BITS: 64 + SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstates.json windows + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstates.json --enable-test-miri + + # 32/64-bit MinGW builds. + # + # We are using MinGW with posix threads since LLVM does not compile with + # the win32 threads version due to missing support for C++'s std::thread. + # + # Instead of relying on the MinGW version installed on appveryor we download + # and install one ourselves so we won't be surprised by changes to appveyor's + # build image. + # + # Finally, note that the downloads below are all in the `rust-lang-ci` S3 + # bucket, but they cleraly didn't originate there! The downloads originally + # came from the mingw-w64 SourceForge download site. Unfortunately + # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. + i686-mingw-1: + MSYS_BITS: 32 + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu + SCRIPT: make ci-subset-1 + MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror + MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z + MINGW_DIR: mingw32 + # FIXME(#59637) + NO_DEBUG_ASSERTIONS: 1 + NO_LLVM_ASSERTIONS: 1 + i686-mingw-2: + MSYS_BITS: 32 + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu + SCRIPT: make ci-subset-2 + MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror + MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z + MINGW_DIR: mingw32 + x86_64-mingw-1: + MSYS_BITS: 64 + SCRIPT: make ci-subset-1 + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu + MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror + MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z + MINGW_DIR: mingw64 + # FIXME(#59637) + NO_DEBUG_ASSERTIONS: 1 + NO_LLVM_ASSERTIONS: 1 + x86_64-mingw-2: + MSYS_BITS: 64 + SCRIPT: make ci-subset-2 + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu + MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror + MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z + MINGW_DIR: mingw64 + + # 32/64 bit MSVC and GNU deployment + dist-x86_64-msvc: + RUST_CONFIGURE_ARGS: > + --build=x86_64-pc-windows-msvc + --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc + --enable-full-tools + --enable-profiler + SCRIPT: python x.py dist + DIST_REQUIRE_ALL_TOOLS: 1 + DEPLOY: 1 + dist-i686-msvc: + RUST_CONFIGURE_ARGS: > + --build=i686-pc-windows-msvc + --target=i586-pc-windows-msvc + --enable-full-tools + --enable-profiler + SCRIPT: python x.py dist + DIST_REQUIRE_ALL_TOOLS: 1 + DEPLOY: 1 + dist-i686-mingw: + MSYS_BITS: 32 + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler + SCRIPT: python x.py dist + MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror + MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z + MINGW_DIR: mingw32 + DIST_REQUIRE_ALL_TOOLS: 1 + DEPLOY: 1 + dist-x86_64-mingw: + MSYS_BITS: 64 + SCRIPT: python x.py dist + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler + MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror + MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z + MINGW_DIR: mingw64 + DIST_REQUIRE_ALL_TOOLS: 1 + DEPLOY: 1 + + # "alternate" deployment, see .travis.yml for more info + dist-x86_64-msvc-alt: + MSYS_BITS: 64 + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler + SCRIPT: python x.py dist + DEPLOY_ALT: 1 diff --git a/src/ci/azure-pipelines/master.yml b/src/ci/azure-pipelines/master.yml new file mode 100644 index 0000000000000..9742c71965851 --- /dev/null +++ b/src/ci/azure-pipelines/master.yml @@ -0,0 +1,25 @@ +# +# Azure Pipelines job to publish toolstate. Only triggers on pushes to master. +# + +pr: none +trigger: + - master + +variables: +- group: real-prod-credentials + +pool: + vmImage: ubuntu-16.04 + +steps: +- checkout: self + fetchDepth: 2 + +- script: | + export MESSAGE_FILE=$(mktemp -t msg.XXXXXX) + . src/ci/docker/x86_64-gnu-tools/repo.sh + commit_toolstate_change "$MESSAGE_FILE" "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "$MESSAGE_FILE" "$TOOLSTATE_REPO_ACCESS_TOKEN" + displayName: Publish toolstate + env: + TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN) diff --git a/src/ci/azure-pipelines/pr.yml b/src/ci/azure-pipelines/pr.yml new file mode 100644 index 0000000000000..88b5067b4a330 --- /dev/null +++ b/src/ci/azure-pipelines/pr.yml @@ -0,0 +1,33 @@ +# +# Azure Pipelines pull request build for Rust +# + +trigger: none +pr: +- master + +jobs: +- job: Linux + timeoutInMinutes: 600 + pool: + vmImage: ubuntu-16.04 + steps: + - template: steps/run.yml + strategy: + matrix: + x86_64-gnu-llvm-6.0: + IMAGE: x86_64-gnu-llvm-6.0 + mingw-check: + IMAGE: mingw-check + +# TODO: enable this job if the commit message matches this regex, need tools +# figure out how to get the current commit message on azure and stick it in a +# condition somewhere +# if: commit_message =~ /(?i:^update.*\b(rls|rustfmt|clippy|miri|cargo)\b)/ +# - job: Linux-x86_64-gnu-tools +# pool: +# vmImage: ubuntu-16.04 +# steps: +# - template: steps/run.yml +# variables: +# IMAGE: x86_64-gnu-tools diff --git a/src/ci/azure-pipelines/steps/install-clang.yml b/src/ci/azure-pipelines/steps/install-clang.yml new file mode 100644 index 0000000000000..0cd6f24e32c7c --- /dev/null +++ b/src/ci/azure-pipelines/steps/install-clang.yml @@ -0,0 +1,40 @@ +steps: + +- bash: | + set -e + curl -f http://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz | tar xJf - + + export CC=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang + echo "##vso[task.setvariable variable=CC]$CC" + + export CXX=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang++ + echo "##vso[task.setvariable variable=CXX]$CXX" + + # Configure `AR` specifically so rustbuild doesn't try to infer it as + # `clang-ar` by accident. + echo "##vso[task.setvariable variable=AR]ar" + displayName: Install clang (OSX) + condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin')) + +# If we're compiling for MSVC then we, like most other distribution builders, +# switch to clang as the compiler. This'll allow us eventually to enable LTO +# amongst LLVM and rustc. Note that we only do this on MSVC as I don't think +# clang has an output mode compatible with MinGW that we need. If it does we +# should switch to clang for MinGW as well! +# +# Note that the LLVM installer is an NSIS installer +# +# Original downloaded here came from +# http://releases.llvm.org/7.0.0/LLVM-7.0.0-win64.exe +- script: | + powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf %TEMP%\LLVM-7.0.0-win64.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/LLVM-7.0.0-win64.exe" + set CLANG_DIR=%CD%\citools\clang-rust + %TEMP%\LLVM-7.0.0-win64.exe /S /NCRC /D=%CLANG_DIR% + set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --set llvm.clang-cl=%CLANG_DIR%\bin\clang-cl.exe + echo ##vso[task.setvariable variable=RUST_CONFIGURE_ARGS]%RUST_CONFIGURE_ARGS% + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['MINGW_URL'],'')) + displayName: Install clang (Windows) + +# Note that we don't install clang on Linux since its compiler story is just so +# different. Each container has its own toolchain configured appropriately +# already. diff --git a/src/ci/azure-pipelines/steps/install-sccache.yml b/src/ci/azure-pipelines/steps/install-sccache.yml new file mode 100644 index 0000000000000..427e50f571f76 --- /dev/null +++ b/src/ci/azure-pipelines/steps/install-sccache.yml @@ -0,0 +1,21 @@ +steps: + +- bash: | + set -e + curl -fo /usr/local/bin/sccache https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-02-sccache-x86_64-apple-darwin + chmod +x /usr/local/bin/sccache + displayName: Install sccache (OSX) + condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin')) + +- script: | + md sccache + powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf sccache\sccache.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-26-sccache-x86_64-pc-windows-msvc" + echo ##vso[task.prependpath]%CD%\sccache + displayName: Install sccache (Windows) + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) + +# Note that we don't install sccache on Linux since it's installed elsewhere +# through all the containers. +# +# FIXME: we should probably install sccache outside the containers and then +# mount it inside the containers so we can centralize all installation here. diff --git a/src/ci/azure-pipelines/steps/install-windows-build-deps.yml b/src/ci/azure-pipelines/steps/install-windows-build-deps.yml new file mode 100644 index 0000000000000..ed06679464c06 --- /dev/null +++ b/src/ci/azure-pipelines/steps/install-windows-build-deps.yml @@ -0,0 +1,94 @@ +steps: +# We've had issues with the default drive in use running out of space during a +# build, and it looks like the `C:` drive has more space than the default `D:` +# drive. We should probably confirm this with the azure pipelines team at some +# point, but this seems to fix our "disk space full" problems. +- script: | + mkdir c:\MORE_SPACE + mklink /J build c:\MORE_SPACE + displayName: "Ensure build happens on C:/ instead of D:/" + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) + +- bash: git config --replace-all --global core.autocrlf false + displayName: "Disable git automatic line ending conversion (on C:/)" + +# Download and install MSYS2, needed primarily for the test suite (run-make) but +# also used by the MinGW toolchain for assembling things. +# +# FIXME: we should probe the default azure image and see if we can use the MSYS2 +# toolchain there. (if there's even one there). For now though this gets the job +# done. +- script: | + set MSYS_PATH=%CD%\citools\msys64 + choco install msys2 --params="/InstallDir:%MSYS_PATH% /NoPath" -y + set PATH=%MSYS_PATH%\usr\bin;%PATH% + pacman -S --noconfirm --needed base-devel ca-certificates make diffutils tar + IF "%MINGW_URL%"=="" ( + IF "%MSYS_BITS%"=="32" pacman -S --noconfirm --needed mingw-w64-i686-toolchain mingw-w64-i686-cmake mingw-w64-i686-gcc mingw-w64-i686-python2 + IF "%MSYS_BITS%"=="64" pacman -S --noconfirm --needed mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-x86_64-python2 + ) + where rev + rev --help + where make + + echo ##vso[task.setvariable variable=MSYS_PATH]%MSYS_PATH% + echo ##vso[task.prependpath]%MSYS_PATH%\usr\bin + displayName: Install msys2 + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) + +# If we need to download a custom MinGW, do so here and set the path +# appropriately. +# +# Here we also do a pretty heinous thing which is to mangle the MinGW +# installation we just downloaded. Currently, as of this writing, we're using +# MinGW-w64 builds of gcc, and that's currently at 6.3.0. We use 6.3.0 as it +# appears to be the first version which contains a fix for #40546, builds +# randomly failing during LLVM due to ar.exe/ranlib.exe failures. +# +# Unfortunately, though, 6.3.0 *also* is the first version of MinGW-w64 builds +# to contain a regression in gdb (#40184). As a result if we were to use the +# gdb provided (7.11.1) then we would fail all debuginfo tests. +# +# In order to fix spurious failures (pretty high priority) we use 6.3.0. To +# avoid disabling gdb tests we download an *old* version of gdb, specifically +# that found inside the 6.2.0 distribution. We then overwrite the 6.3.0 gdb +# with the 6.2.0 gdb to get tests passing. +# +# Note that we don't literally overwrite the gdb.exe binary because it appears +# to just use gdborig.exe, so that's the binary we deal with instead. +- script: | + powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf %MINGW_ARCHIVE% %MINGW_URL%/%MINGW_ARCHIVE%" + 7z x -y %MINGW_ARCHIVE% > nul + powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_URL%/2017-04-20-%MSYS_BITS%bit-gdborig.exe" + mv 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_DIR%\bin\gdborig.exe + echo ##vso[task.prependpath]%CD%\%MINGW_DIR%\bin + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), ne(variables['MINGW_URL'],'')) + displayName: Download custom MinGW + +# Otherwise pull in the MinGW installed on appveyor +- script: | + echo ##vso[task.prependpath]%MSYS_PATH%\mingw%MSYS_BITS%\bin + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['MINGW_URL'],'')) + displayName: Add MinGW to path + +# Make sure we use the native python interpreter instead of some msys equivalent +# one way or another. The msys interpreters seem to have weird path conversions +# baked in which break LLVM's build system one way or another, so let's use the +# native version which keeps everything as native as possible. +- script: | + copy C:\Python27amd64\python.exe C:\Python27amd64\python2.7.exe + echo ##vso[task.prependpath]C:\Python27amd64 + displayName: Prefer the "native" Python as LLVM has trouble building with MSYS sometimes + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) + +# Note that this is originally from the github releases patch of Ninja +- script: | + md ninja + powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf 2017-03-15-ninja-win.zip https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2017-03-15-ninja-win.zip" + 7z x -oninja 2017-03-15-ninja-win.zip + del 2017-03-15-ninja-win.zip + set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --enable-ninja + echo ##vso[task.setvariable variable=RUST_CONFIGURE_ARGS]%RUST_CONFIGURE_ARGS% + echo ##vso[task.prependpath]%CD%\ninja + displayName: Download and install ninja + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml new file mode 100644 index 0000000000000..ab990575f93b3 --- /dev/null +++ b/src/ci/azure-pipelines/steps/run.yml @@ -0,0 +1,209 @@ +# FIXME(linux): need to configure core dumps, enable them, and then dump +# backtraces on failure from all core dumps: +# +# - bash: sudo apt install gdb +# - bash: sudo sh -c 'echo "/checkout/obj/cores/core.%p.%E" > /proc/sys/kernel/core_pattern' +# +# Check travis config for `gdb --batch` command to print all crash logs + +steps: + +# 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. +# +# Note that we do this a couple times during the build as the PATH and current +# user/directory change, e.g. when mingw is enabled. +- bash: git config --global core.autocrlf false + displayName: "Disable git automatic line ending conversion" + +- checkout: self + fetchDepth: 2 + +# Spawn a background process to collect CPU usage statistics which we'll upload +# at the end of the build. See the comments in the script here for more +# information. +- bash: python src/ci/cpu-usage-over-time.py &> cpu-usage.csv & + displayName: "Collect CPU-usage statistics in the background" + +- bash: printenv | sort + displayName: Show environment variables + +# Log the date, even on failure. Attempting to debug SSL certificate errors. +- bash: date + displayName: Print out date (before build) + +- bash: | + set -e + df -h + du . | sort -nr | head -n100 + displayName: Show disk usage + # FIXME: this hasn't been tested, but maybe it works on Windows? Should test! + condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT')) + +- template: install-sccache.yml +- template: install-clang.yml + +# Install some dependencies needed to build LLDB/Clang, currently only needed +# during the `dist` target +- bash: | + set -e + brew update + brew install xz + brew install swig@3 + brew link --force swig@3 + displayName: Install build dependencies (OSX) + condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'), eq(variables['SCRIPT'],'./x.py dist')) + +# Switch to XCode 9.3 on OSX since it seems to be the last version that supports +# i686-apple-darwin. We'll eventually want to upgrade this and it will probably +# force us to drop i686-apple-darwin, but let's keep the wheels turning for now. +- bash: | + set -e + sudo xcode-select --switch /Applications/Xcode_9.3.app + displayName: Switch to Xcode 9.3 (OSX) + condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin')) + +- template: install-windows-build-deps.yml + +# Looks like docker containers have IPv6 disabled by default, so let's turn it +# on since libstd tests require it +- bash: | + set -e + sudo mkdir -p /etc/docker + echo '{"ipv6":true,"fixed-cidr-v6":"fd9a:8454:6789:13f7::/64"}' | sudo tee /etc/docker/daemon.json + sudo service docker restart + displayName: Enable IPv6 + condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) + +# Disable automatic line ending conversion (again). On Windows, when we're +# installing dependencies, something switches the git configuration directory or +# re-enables autocrlf. We've not tracked down the exact cause -- and there may +# be multiple -- but this should ensure submodules are checked out with the +# appropriate line endings. +- bash: git config --replace-all --global core.autocrlf false + displayName: "Disable git automatic line ending conversion" + +# Check out all our submodules, but more quickly than using git by using one of +# our custom scripts +- bash: | + set -e + mkdir -p $HOME/rustsrc + $BUILD_SOURCESDIRECTORY/src/ci/init_repo.sh . $HOME/rustsrc + condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT')) + displayName: Check out submodules (Unix) +- script: | + if not exist D:\cache\rustsrc\NUL mkdir D:\cache\rustsrc + sh src/ci/init_repo.sh . /d/cache/rustsrc + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) + displayName: Check out submodules (Windows) + +# See also the disable for autocrlf above, this just checks that it worked +# +# We check both in rust-lang/rust and in a submodule to make sure both are +# accurate. Submodules are checked out significantly later than the main +# repository in this script, so settings can (and do!) change between then. +# +# Linux (and maybe macOS) builders don't currently have dos2unix so just only +# run this step on Windows. +- bash: | + set -x + # print out the git configuration so we can better investigate failures in + # the following + git config --list --show-origin + dos2unix -ih Cargo.lock src/tools/rust-installer/install-template.sh + endings=$(dos2unix -ic Cargo.lock src/tools/rust-installer/install-template.sh) + # if endings has non-zero length, error out + if [ -n "$endings" ]; then exit 1 ; fi + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) + displayName: Verify line endings are LF + +# Ensure the `aws` CLI is installed so we can deploy later on, cache docker +# images, etc. +- bash: | + set -e + source src/ci/shared.sh + sudo apt-get install -y python3-setuptools + retry pip3 install -r src/ci/awscli-requirements.txt --upgrade --user + echo "##vso[task.prependpath]$HOME/.local/bin" + displayName: Install awscli (Linux) + condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) +- script: pip install -r src/ci/awscli-requirements.txt + displayName: Install awscli (non-Linux) + condition: and(succeeded(), ne(variables['Agent.OS'], 'Linux')) + +# Configure our CI_JOB_NAME variable which log analyzers can use for the main +# step to see what's going on. +- bash: echo "##vso[task.setvariable variable=CI_JOB_NAME]$SYSTEM_JOBNAME" + displayName: Configure Job Name + +# As a quick smoke check on the otherwise very fast mingw-check linux builder +# check our own internal scripts. +- bash: | + set -e + git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git + cd rust-toolstate + python2.7 "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "" "" + cd .. + rm -rf rust-toolstate + condition: and(succeeded(), eq(variables['IMAGE'], 'mingw-check')) + displayName: Verify the publish_toolstate script works + +- bash: | + set -e + # Remove any preexisting rustup installation since it can interfere + # with the cargotest step and its auto-detection of things like Clippy in + # the environment + rustup self uninstall -y || true + if [ "$IMAGE" = "" ]; then + src/ci/run.sh + else + src/ci/docker/run.sh $IMAGE + fi + #timeoutInMinutes: 180 + timeoutInMinutes: 600 + env: + CI: true + SRC: . + AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) + TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN) + displayName: Run build + +# If we're a deploy builder, use the `aws` command to publish everything to our +# bucket. +- bash: | + set -e + source src/ci/shared.sh + if [ "$AGENT_OS" = "Linux" ]; then + rm -rf obj/build/dist/doc + upload_dir=obj/build/dist + else + rm -rf build/dist/doc + upload_dir=build/dist + fi + ls -la $upload_dir + deploy_dir=rustc-builds + if [ "$DEPLOY_ALT" == "1" ]; then + deploy_dir=rustc-builds-alt + fi + retry aws s3 cp --no-progress --recursive --acl public-read ./$upload_dir s3://$DEPLOY_BUCKET/$deploy_dir/$BUILD_SOURCEVERSION + env: + AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) + condition: and(succeeded(), or(eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1'))) + displayName: Upload artifacts + +# Upload CPU usage statistics that we've been gathering this whole time. Always +# execute this step in case we want to inspect failed builds, but don't let +# errors here ever fail the build since this is just informational. +- bash: aws s3 cp --acl public-read cpu-usage.csv s3://$DEPLOY_BUCKET/rustc-builds/$BUILD_SOURCEVERSION/cpu-$SYSTEM_JOBNAME.csv + env: + AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) + condition: variables['AWS_SECRET_ACCESS_KEY'] + continueOnError: true + displayName: Upload CPU usage statistics + +# Log the date, even on failure. Attempting to debug SSL certificate errors. +- bash: date + continueOnError: true + displayName: Print out date (after build) diff --git a/src/ci/azure-pipelines/try.yml b/src/ci/azure-pipelines/try.yml new file mode 100644 index 0000000000000..6a22e57c12406 --- /dev/null +++ b/src/ci/azure-pipelines/try.yml @@ -0,0 +1,78 @@ +pr: none +trigger: +- try + +variables: +- group: real-prod-credentials + +jobs: +- job: Linux + timeoutInMinutes: 600 + pool: + vmImage: ubuntu-16.04 + steps: + - template: steps/run.yml + strategy: + matrix: + dist-x86_64-linux: + IMAGE: dist-x86_64-linux + DEPLOY: 1 + + dist-x86_64-linux-alt: + IMAGE: dist-x86_64-linux + DEPLOY_ALT: 1 + +# The macOS and Windows builds here are currently disabled due to them not being +# overly necessary on `try` builds. We also don't actually have anything that +# consumes the artifacts currently. Perhaps one day we can reenable, but for now +# it helps free up capacity on Azure. +# - job: macOS +# timeoutInMinutes: 600 +# pool: +# vmImage: macos-10.13 +# steps: +# - template: steps/run.yml +# strategy: +# matrix: +# dist-x86_64-apple: +# SCRIPT: ./x.py dist +# RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --enable-lldb --set rust.jemalloc +# DEPLOY: 1 +# RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 +# MACOSX_DEPLOYMENT_TARGET: 10.7 +# NO_LLVM_ASSERTIONS: 1 +# NO_DEBUG_ASSERTIONS: 1 +# DIST_REQUIRE_ALL_TOOLS: 1 +# +# dist-x86_64-apple-alt: +# SCRIPT: ./x.py dist +# RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --enable-lldb --set rust.jemalloc +# DEPLOY_ALT: 1 +# RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 +# MACOSX_DEPLOYMENT_TARGET: 10.7 +# NO_LLVM_ASSERTIONS: 1 +# NO_DEBUG_ASSERTIONS: 1 +# +# - job: Windows +# timeoutInMinutes: 600 +# pool: +# vmImage: 'vs2017-win2016' +# steps: +# - template: steps/run.yml +# strategy: +# matrix: +# dist-x86_64-msvc: +# RUST_CONFIGURE_ARGS: > +# --build=x86_64-pc-windows-msvc +# --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc +# --enable-full-tools +# --enable-profiler +# SCRIPT: python x.py dist +# DIST_REQUIRE_ALL_TOOLS: 1 +# DEPLOY: 1 +# +# dist-x86_64-msvc-alt: +# MSYS_BITS: 64 +# RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler +# SCRIPT: python x.py dist +# DEPLOY_ALT: 1 diff --git a/src/ci/cpu-usage-over-time.py b/src/ci/cpu-usage-over-time.py new file mode 100644 index 0000000000000..daf21670b3339 --- /dev/null +++ b/src/ci/cpu-usage-over-time.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +# ignore-tidy-linelength + +# This is a small script that we use on CI to collect CPU usage statistics of +# our builders. By seeing graphs of CPU usage over time we hope to correlate +# that with possible improvements to Rust's own build system, ideally diagnosing +# that either builders are always fully using their CPU resources or they're +# idle for long stretches of time. +# +# This script is relatively simple, but it's platform specific. Each platform +# (OSX/Windows/Linux) has a different way of calculating the current state of +# CPU at a point in time. We then compare two captured states to determine the +# percentage of time spent in one state versus another. The state capturing is +# all platform-specific but the loop at the bottom is the cross platform part +# that executes everywhere. +# +# # Viewing statistics +# +# All builders will upload their CPU statistics as CSV files to our S3 buckets. +# These URLS look like: +# +# https://$bucket.s3.amazonaws.com/rustc-builds/$commit/cpu-$builder.csv +# +# for example +# +# https://rust-lang-ci2.s3.amazonaws.com/rustc-builds/68baada19cd5340f05f0db15a3e16d6671609bcc/cpu-x86_64-apple.csv +# +# Each CSV file has two columns. The first is the timestamp of the measurement +# and the second column is the % of idle cpu time in that time slice. Ideally +# the second column is always zero. +# +# Once you've downloaded a file there's various ways to plot it and visualize +# it. For command line usage you use the `src/etc/cpu-usage-over-time-plot.sh` +# script in this repository. + +import datetime +import sys +import time + +if sys.platform == 'linux2': + class State: + def __init__(self): + with open('/proc/stat', 'r') as file: + data = file.readline().split() + if data[0] != 'cpu': + raise Exception('did not start with "cpu"') + self.user = int(data[1]) + self.nice = int(data[2]) + self.system = int(data[3]) + self.idle = int(data[4]) + self.iowait = int(data[5]) + self.irq = int(data[6]) + self.softirq = int(data[7]) + self.steal = int(data[8]) + self.guest = int(data[9]) + self.guest_nice = int(data[10]) + + def idle_since(self, prev): + user = self.user - prev.user + nice = self.nice - prev.nice + system = self.system - prev.system + idle = self.idle - prev.idle + iowait = self.iowait - prev.iowait + irq = self.irq - prev.irq + softirq = self.softirq - prev.softirq + steal = self.steal - prev.steal + guest = self.guest - prev.guest + guest_nice = self.guest_nice - prev.guest_nice + total = user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice + return float(idle) / float(total) * 100 + +elif sys.platform == 'win32': + from ctypes.wintypes import DWORD + from ctypes import Structure, windll, WinError, GetLastError, byref + + class FILETIME(Structure): + _fields_ = [ + ("dwLowDateTime", DWORD), + ("dwHighDateTime", DWORD), + ] + + class State: + def __init__(self): + idle, kernel, user = FILETIME(), FILETIME(), FILETIME() + + success = windll.kernel32.GetSystemTimes( + byref(idle), + byref(kernel), + byref(user), + ) + + assert success, WinError(GetLastError())[1] + + self.idle = (idle.dwHighDateTime << 32) | idle.dwLowDateTime + self.kernel = (kernel.dwHighDateTime << 32) | kernel.dwLowDateTime + self.user = (user.dwHighDateTime << 32) | user.dwLowDateTime + + def idle_since(self, prev): + idle = self.idle - prev.idle + user = self.user - prev.user + kernel = self.kernel - prev.kernel + return float(idle) / float(user + kernel) * 100 + +elif sys.platform == 'darwin': + from ctypes import * + libc = cdll.LoadLibrary('/usr/lib/libc.dylib') + + PROESSOR_CPU_LOAD_INFO = c_int(2) + CPU_STATE_USER = 0 + CPU_STATE_SYSTEM = 1 + CPU_STATE_IDLE = 2 + CPU_STATE_NICE = 3 + c_int_p = POINTER(c_int) + + class State: + def __init__(self): + num_cpus_u = c_uint(0) + cpu_info = c_int_p() + cpu_info_cnt = c_int(0) + err = libc.host_processor_info( + libc.mach_host_self(), + PROESSOR_CPU_LOAD_INFO, + byref(num_cpus_u), + byref(cpu_info), + byref(cpu_info_cnt), + ) + assert err == 0 + self.user = 0 + self.system = 0 + self.idle = 0 + self.nice = 0 + cur = 0 + while cur < cpu_info_cnt.value: + self.user += cpu_info[cur + CPU_STATE_USER] + self.system += cpu_info[cur + CPU_STATE_SYSTEM] + self.idle += cpu_info[cur + CPU_STATE_IDLE] + self.nice += cpu_info[cur + CPU_STATE_NICE] + cur += num_cpus_u.value + + def idle_since(self, prev): + user = self.user - prev.user + system = self.system - prev.system + idle = self.idle - prev.idle + nice = self.nice - prev.nice + return float(idle) / float(user + system + idle + nice) * 100.0 + +else: + print('unknown platform', sys.platform) + sys.exit(1) + +cur_state = State(); +print("Time,Idle") +while True: + time.sleep(1); + next_state = State(); + now = datetime.datetime.utcnow().isoformat() + idle = next_state.idle_since(cur_state) + print("%s,%s" % (now, idle)) + sys.stdout.flush() + cur_state = next_state diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile index e10ccd56a4a54..b934d1ce97124 100644 --- a/src/ci/docker/arm-android/Dockerfile +++ b/src/ci/docker/arm-android/Dockerfile @@ -7,23 +7,21 @@ COPY scripts/android-ndk.sh /scripts/ RUN . /scripts/android-ndk.sh && \ download_and_make_toolchain android-ndk-r15c-linux-x86_64.zip arm 14 -# Note: -# Do not upgrade to `openjdk-9-jre-headless`, as it will cause certificate error -# when installing the Android SDK (see PR #45193). This is unfortunate, but -# every search result suggested either disabling HTTPS or replacing JDK 9 by -# JDK 8 as the solution (e.g. https://stackoverflow.com/q/41421340). :| RUN dpkg --add-architecture i386 && \ apt-get update && \ apt-get install -y --no-install-recommends \ libgl1-mesa-glx \ libpulse0 \ libstdc++6:i386 \ - openjdk-8-jre-headless \ - tzdata + openjdk-9-jre-headless \ + tzdata \ + wget \ + python3 COPY scripts/android-sdk.sh /scripts/ -RUN . /scripts/android-sdk.sh && \ - download_and_create_avd 4333796 armeabi-v7a 18 +COPY scripts/android-sdk-manager.py /scripts/ +COPY arm-android/android-sdk.lock /android/sdk/android-sdk.lock +RUN /scripts/android-sdk.sh ENV PATH=$PATH:/android/sdk/emulator ENV PATH=$PATH:/android/sdk/tools diff --git a/src/ci/docker/arm-android/android-sdk.lock b/src/ci/docker/arm-android/android-sdk.lock new file mode 100644 index 0000000000000..a1be8a4346b6d --- /dev/null +++ b/src/ci/docker/arm-android/android-sdk.lock @@ -0,0 +1,6 @@ +emulator emulator-linux-5264690.zip 48c1cda2bdf3095d9d9d5c010fbfb3d6d673e3ea +patcher;v4 3534162-studio.sdk-patcher.zip 046699c5e2716ae11d77e0bad814f7f33fab261e +platform-tools platform-tools_r28.0.2-linux.zip 46a4c02a9b8e4e2121eddf6025da3c979bf02e28 +platforms;android-18 android-18_r03.zip e6b09b3505754cbbeb4a5622008b907262ee91cb +system-images;android-18;default;armeabi-v7a sys-img/android/armeabi-v7a-18_r05.zip 580b583720f7de671040d5917c8c9db0c7aa03fd +tools sdk-tools-linux-4333796.zip 8c7c28554a32318461802c1291d76fccfafde054 diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile index 2b7624d53ee05..235920833f839 100644 --- a/src/ci/docker/armhf-gnu/Dockerfile +++ b/src/ci/docker/armhf-gnu/Dockerfile @@ -71,7 +71,8 @@ COPY scripts/qemu-bare-bones-addentropy.c /tmp/addentropy.c RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static # TODO: What is this?! -RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb +# Source of the file: https://github.com/vfdev-5/qemu-rpi2-vexpress/raw/master/vexpress-v2p-ca15-tc1.dtb +RUN curl -O https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/vexpress-v2p-ca15-tc1.dtb COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/asmjs/Dockerfile b/src/ci/docker/asmjs/Dockerfile index 9eaffbf83eb4e..01d6fce34186a 100644 --- a/src/ci/docker/asmjs/Dockerfile +++ b/src/ci/docker/asmjs/Dockerfile @@ -37,3 +37,11 @@ ENV SCRIPT python2.7 ../x.py test --target $TARGETS \ src/libstd \ src/liballoc \ src/libcore + +# Debug assertions in rustc are largely covered by other builders, and LLVM +# assertions cause this builder to slow down by quite a large amount and don't +# buy us a huge amount over other builders (not sure if we've ever seen an +# asmjs-specific backend assertion trip), so disable assertions for these +# tests. +ENV NO_LLVM_ASSERTIONS=1 +ENV NO_DEBUG_ASSERTIONS=1 diff --git a/src/ci/docker/disabled/dist-x86_64-redox/Dockerfile b/src/ci/docker/disabled/dist-x86_64-redox/Dockerfile index f4c25f791bc39..11a3acd68e3e8 100644 --- a/src/ci/docker/disabled/dist-x86_64-redox/Dockerfile +++ b/src/ci/docker/disabled/dist-x86_64-redox/Dockerfile @@ -7,8 +7,8 @@ COPY scripts/crosstool-ng.sh /scripts/ RUN sh /scripts/crosstool-ng.sh WORKDIR /tmp -COPY cross/install-x86_64-redox.sh /tmp/ -RUN ./install-x86_64-redox.sh +COPY dist-various-1/install-x86_64-redox.sh /scripts/ +RUN sh /scripts/install-x86_64-redox.sh COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/dist-aarch64-linux/Dockerfile b/src/ci/docker/dist-aarch64-linux/Dockerfile index cddfa557f6aed..f5eb66ed7142f 100644 --- a/src/ci/docker/dist-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-aarch64-linux/Dockerfile @@ -32,5 +32,8 @@ ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-gcc \ ENV HOSTS=aarch64-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS \ + --enable-extended \ + --enable-profiler \ + --disable-docs ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh b/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh index f7aa2cd326832..fc53849a2ada4 100755 --- a/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh +++ b/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh @@ -3,9 +3,29 @@ set -ex source shared.sh +BINUTILS=2.32 +TARGET=powerpc64-unknown-linux-gnu +PREFIX=/x-tools/$TARGET +SYSROOT=$PREFIX/$TARGET/sysroot + mkdir build cd build cp ../powerpc64-linux-gnu.config .config hide_output ct-ng build cd .. rm -rf build + +chmod -R u+w $PREFIX + +# Next, download and build newer binutils. +mkdir binutils-$TARGET +pushd binutils-$TARGET +curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf - +mkdir binutils-build +cd binutils-build +hide_output ../binutils-$BINUTILS/configure --target=$TARGET \ + --prefix=$PREFIX --with-sysroot=$SYSROOT +hide_output make -j10 +hide_output make install +popd +rm -rf binutils-$TARGET diff --git a/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh index a01803d9c8f45..f866a24287f9e 100755 --- a/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh +++ b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh @@ -4,7 +4,7 @@ set -ex source shared.sh -BINUTILS=2.25.1 +BINUTILS=2.32 GCC=5.3.0 TARGET=powerpc64le-linux-gnu SYSROOT=/usr/local/$TARGET/sysroot diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index f80293b182e97..5ab4be328a9f7 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -109,7 +109,9 @@ ENV TARGETS=$TARGETS,thumbv6m-none-eabi ENV TARGETS=$TARGETS,thumbv7m-none-eabi ENV TARGETS=$TARGETS,thumbv7em-none-eabi ENV TARGETS=$TARGETS,thumbv7em-none-eabihf +ENV TARGETS=$TARGETS,thumbv8m.base-none-eabi ENV TARGETS=$TARGETS,thumbv8m.main-none-eabi +ENV TARGETS=$TARGETS,thumbv8m.main-none-eabihf ENV TARGETS=$TARGETS,riscv32imc-unknown-none-elf ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf ENV TARGETS=$TARGETS,riscv64imac-unknown-none-elf @@ -124,7 +126,6 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \ CC_sparc64_unknown_linux_gnu=sparc64-linux-gnu-gcc \ CC_x86_64_unknown_redox=x86_64-unknown-redox-gcc \ - CC_armebv7r_none_eabi=arm-none-eabi-gcc \ CC_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc \ AR_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-ar \ CXX_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++ diff --git a/src/ci/docker/dist-various-1/install-mips-musl.sh b/src/ci/docker/dist-various-1/install-mips-musl.sh index 8d05a046959d8..60a96e3b8e952 100755 --- a/src/ci/docker/dist-various-1/install-mips-musl.sh +++ b/src/ci/docker/dist-various-1/install-mips-musl.sh @@ -5,7 +5,7 @@ mkdir /usr/local/mips-linux-musl # originally from # https://downloads.openwrt.org/snapshots/trunk/ar71xx/generic/ # OpenWrt-Toolchain-ar71xx-generic_gcc-5.3.0_musl-1.1.16.Linux-x86_64.tar.bz2 -URL="https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror" +URL="https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror" FILE="OpenWrt-Toolchain-ar71xx-generic_gcc-5.3.0_musl-1.1.16.Linux-x86_64.tar.bz2" curl -L "$URL/$FILE" | tar xjf - -C /usr/local/mips-linux-musl --strip-components=2 diff --git a/src/ci/docker/dist-various-1/install-mipsel-musl.sh b/src/ci/docker/dist-various-1/install-mipsel-musl.sh index 2c414744bf47b..9ae41218ee4fb 100755 --- a/src/ci/docker/dist-various-1/install-mipsel-musl.sh +++ b/src/ci/docker/dist-various-1/install-mipsel-musl.sh @@ -5,7 +5,7 @@ mkdir /usr/local/mipsel-linux-musl # Note that this originally came from: # https://downloads.openwrt.org/snapshots/trunk/malta/generic/ # OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2 -URL="https://s3-us-west-1.amazonaws.com/rust-lang-ci2/libc" +URL="https://rust-lang-ci2.s3.amazonaws.com/libc" FILE="OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2" curl -L "$URL/$FILE" | tar xjf - -C /usr/local/mipsel-linux-musl --strip-components=2 diff --git a/src/ci/docker/dist-various-1/install-x86_64-redox.sh b/src/ci/docker/dist-various-1/install-x86_64-redox.sh index c39be14941c90..dad9792233847 100755 --- a/src/ci/docker/dist-various-1/install-x86_64-redox.sh +++ b/src/ci/docker/dist-various-1/install-x86_64-redox.sh @@ -1,13 +1,6 @@ #!/usr/bin/env bash -# ignore-tidy-linelength set -ex -apt-get update -apt-get install -y --no-install-recommends software-properties-common apt-transport-https - -apt-key adv --batch --yes --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys AA12E97F0881517F -add-apt-repository -y 'deb https://static.redox-os.org/toolchain/apt /' - -apt-get update -apt-get install -y x86-64-unknown-redox-gcc +curl https://static.redox-os.org/toolchain/x86_64-unknown-redox/relibc-install.tar.gz | \ +tar --extract --gzip --directory /usr/local diff --git a/src/ci/docker/dist-various-2/Dockerfile b/src/ci/docker/dist-various-2/Dockerfile index e2710a18bdae3..53523d41a5580 100644 --- a/src/ci/docker/dist-various-2/Dockerfile +++ b/src/ci/docker/dist-various-2/Dockerfile @@ -1,9 +1,12 @@ -FROM ubuntu:17.10 +FROM ubuntu:18.04 COPY scripts/cross-apt-packages.sh /scripts/ RUN sh /scripts/cross-apt-packages.sh -RUN apt-get build-dep -y clang llvm && apt-get install -y --no-install-recommends \ +# Enable source repositories, which are disabled by default on Ubuntu >= 18.04 +RUN sed -i 's/^# deb-src/deb-src/' /etc/apt/sources.list + +RUN apt-get update && apt-get build-dep -y clang llvm && apt-get install -y --no-install-recommends \ build-essential \ gcc-multilib \ libedit-dev \ @@ -15,10 +18,13 @@ RUN apt-get build-dep -y clang llvm && apt-get install -y --no-install-recommend nodejs \ python2.7-dev \ software-properties-common \ - unzip + unzip \ + # Needed for apt-key to work: + dirmngr \ + gpg-agent RUN apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys 74DA7924C5513486 -RUN add-apt-repository -y 'deb http://apt.dilos.org/dilos dilos2-testing main' +RUN add-apt-repository -y 'deb http://apt.dilos.org/dilos dilos2 main' WORKDIR /tmp COPY dist-various-2/shared.sh /tmp/ @@ -34,6 +40,9 @@ COPY dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/ # Any update to the commit id here, should cause the container image to be re-built from this point on. RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "53b586346f2c7870e20b170decdc30729d97c42b" +COPY dist-various-2/build-wasi-toolchain.sh /tmp/ +RUN /tmp/build-wasi-toolchain.sh + COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -64,8 +73,9 @@ ENV CARGO_TARGET_AARCH64_FUCHSIA_RUSTFLAGS \ ENV TARGETS=x86_64-fuchsia ENV TARGETS=$TARGETS,aarch64-fuchsia -ENV TARGETS=$TARGETS,sparcv9-sun-solaris ENV TARGETS=$TARGETS,wasm32-unknown-unknown +ENV TARGETS=$TARGETS,wasm32-wasi +ENV TARGETS=$TARGETS,sparcv9-sun-solaris ENV TARGETS=$TARGETS,x86_64-sun-solaris ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32 ENV TARGETS=$TARGETS,x86_64-unknown-cloudabi @@ -74,5 +84,6 @@ ENV TARGETS=$TARGETS,nvptx64-nvidia-cuda ENV X86_FORTANIX_SGX_LIBS="/x86_64-fortanix-unknown-sgx/lib/" -ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --disable-docs \ + --set target.wasm32-wasi.wasi-root=/wasm32-wasi ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh b/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh index ef486075ff9d8..73acdf5be6356 100755 --- a/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh +++ b/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh @@ -1,7 +1,5 @@ #!/usr/bin/env bash -# ignore-tidy-linelength - set -ex source shared.sh @@ -12,7 +10,7 @@ pushd zircon > /dev/null # Download sources git init -git remote add origin https://fuchsia.googlesource.com/zircon +git remote add origin https://github.com/rust-lang-nursery/mirror-google-fuchsia-zircon git fetch --depth=1 origin $ZIRCON git reset --hard FETCH_HEAD diff --git a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh new file mode 100755 index 0000000000000..7bf8946c4f136 --- /dev/null +++ b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# +# ignore-tidy-linelength + +set -ex + +# Originally from https://releases.llvm.org/8.0.0/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz +curl https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/clang%2Bllvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz | \ + tar xJf - +export PATH=`pwd`/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04/bin:$PATH + +git clone https://github.com/CraneStation/wasi-sysroot + +cd wasi-sysroot +git reset --hard e5f14be38362f1ab83302895a6e74b2ffd0e2302 +make -j$(nproc) INSTALL_DIR=/wasm32-wasi install + +cd .. +rm -rf reference-sysroot-wasi +rm -rf clang+llvm* diff --git a/src/ci/docker/dist-x86_64-linux/build-gcc.sh b/src/ci/docker/dist-x86_64-linux/build-gcc.sh index 7f6e94d326ddf..ddc2066537cef 100755 --- a/src/ci/docker/dist-x86_64-linux/build-gcc.sh +++ b/src/ci/docker/dist-x86_64-linux/build-gcc.sh @@ -32,6 +32,7 @@ hide_output ../gcc-$GCC/configure \ --enable-languages=c,c++ hide_output make -j10 hide_output make install +ln -s gcc /rustroot/bin/cc cd .. rm -rf gcc-build diff --git a/src/ci/docker/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/dist-x86_64-linux/build-openssl.sh index 7e391e21d13eb..13dae6169053a 100755 --- a/src/ci/docker/dist-x86_64-linux/build-openssl.sh +++ b/src/ci/docker/dist-x86_64-linux/build-openssl.sh @@ -4,7 +4,7 @@ set -ex source shared.sh VERSION=1.0.2k -URL=https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/openssl-$VERSION.tar.gz +URL=https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/openssl-$VERSION.tar.gz curl $URL | tar xzf - diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index 06f8a2fbba836..385eefde846c2 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -4,6 +4,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ file \ + wget \ curl \ ca-certificates \ python2.7 \ @@ -18,29 +19,32 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ WORKDIR /build/ -COPY scripts/musl.sh /build/ +COPY scripts/musl-toolchain.sh /build/ # We need to mitigate rust-lang/rust#34978 when compiling musl itself as well -RUN CC=gcc \ - CFLAGS="-Wa,-mrelax-relocations=no" \ - CXX=g++ \ - CXXFLAGS="-Wa,-mrelax-relocations=no" \ - bash musl.sh x86_64 && rm -rf /build +RUN CFLAGS="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \ + CXXFLAGS="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \ + REPLACE_CC=1 bash musl-toolchain.sh x86_64 && rm -rf build COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +ENV HOSTS=x86_64-unknown-linux-musl + ENV RUST_CONFIGURE_ARGS \ - --musl-root-x86_64=/musl-x86_64 \ + --musl-root-x86_64=/usr/local/x86_64-linux-musl \ --enable-extended \ - --disable-docs + --disable-docs \ + --set target.x86_64-unknown-linux-musl.crt-static=false \ + --build $HOSTS # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our # way to produce "super compatible" binaries. # # See: https://github.com/rust-lang/rust/issues/34978 -ENV CFLAGS_x86_64_unknown_linux_musl=-Wa,-mrelax-relocations=no +# And: https://github.com/rust-lang/rust/issues/59411 +ENV CFLAGS_x86_64_unknown_linux_musl="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none \ + -Wl,--compress-debug-sections=none" -ENV SCRIPT \ - python2.7 ../x.py test --target x86_64-unknown-linux-musl && \ - python2.7 ../x.py dist --target x86_64-unknown-linux-musl +# To run native tests replace `dist` below with `test` +ENV SCRIPT python2.7 ../x.py dist --build $HOSTS diff --git a/src/ci/docker/dist-x86_64-netbsd/Dockerfile b/src/ci/docker/dist-x86_64-netbsd/Dockerfile index 4fe7e2cca2b60..44b1aaa24b19d 100644 --- a/src/ci/docker/dist-x86_64-netbsd/Dockerfile +++ b/src/ci/docker/dist-x86_64-netbsd/Dockerfile @@ -3,23 +3,8 @@ FROM ubuntu:16.04 COPY scripts/cross-apt-packages.sh /scripts/ RUN sh /scripts/cross-apt-packages.sh -# Ubuntu 16.04 (this container) ships with make 4, but something in the -# toolchains we build below chokes on that, so go back to make 3 -COPY scripts/make3.sh /scripts/ -RUN sh /scripts/make3.sh - -COPY scripts/crosstool-ng.sh /scripts/ -RUN sh /scripts/crosstool-ng.sh - -COPY scripts/rustbuild-setup.sh /scripts/ -RUN sh /scripts/rustbuild-setup.sh -USER rustbuild -WORKDIR /tmp - COPY dist-x86_64-netbsd/build-netbsd-toolchain.sh /tmp/ -RUN ./build-netbsd-toolchain.sh - -USER root +RUN /tmp/build-netbsd-toolchain.sh COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -33,6 +18,5 @@ ENV \ ENV HOSTS=x86_64-unknown-netbsd -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \ - --set llvm.allow-old-toolchain +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh index ac92d68a1f501..2e9b9dcc2344e 100755 --- a/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh +++ b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh @@ -25,18 +25,18 @@ cd netbsd mkdir -p /x-tools/x86_64-unknown-netbsd/sysroot -URL=https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror +URL=https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror # Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/source/sets/*.tgz -curl $URL/2017-03-17-netbsd-src.tgz | tar xzf - -curl $URL/2017-03-17-netbsd-gnusrc.tgz | tar xzf - -curl $URL/2017-03-17-netbsd-sharesrc.tgz | tar xzf - -curl $URL/2017-03-17-netbsd-syssrc.tgz | tar xzf - +curl $URL/2018-03-01-netbsd-src.tgz | tar xzf - +curl $URL/2018-03-01-netbsd-gnusrc.tgz | tar xzf - +curl $URL/2018-03-01-netbsd-sharesrc.tgz | tar xzf - +curl $URL/2018-03-01-netbsd-syssrc.tgz | tar xzf - # Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/amd64/binary/sets/*.tgz -curl $URL/2017-03-17-netbsd-base.tgz | \ +curl $URL/2018-03-01-netbsd-base.tgz | \ tar xzf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib ./lib -curl $URL/2017-03-17-netbsd-comp.tgz | \ +curl $URL/2018-03-01-netbsd-comp.tgz | \ tar xzf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib cd usr/src diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile index 5a83bd318c4d9..2041ba50bc9a0 100644 --- a/src/ci/docker/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/i686-gnu-nopt/Dockerfile @@ -18,4 +18,4 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests -ENV RUST_CHECK_TARGET check +ENV SCRIPT python2.7 ../x.py test diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile index daa24e0e8186d..17441ddb4546b 100644 --- a/src/ci/docker/i686-gnu/Dockerfile +++ b/src/ci/docker/i686-gnu/Dockerfile @@ -18,4 +18,10 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu -ENV SCRIPT python2.7 ../x.py test +# Exclude some tests that are unlikely to be platform specific, to speed up +# this slow job. +ENV SCRIPT python2.7 ../x.py test \ + --exclude src/bootstrap \ + --exclude src/test/rustdoc-js \ + --exclude src/tools/error_index_generator \ + --exclude src/tools/linkchecker diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index b4426bbfb962c..e6cd794887c0a 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -12,6 +12,9 @@ ci_dir="`dirname $docker_dir`" src_dir="`dirname $ci_dir`" root_dir="`dirname $src_dir`" +objdir=$root_dir/obj +dist=$objdir/build/dist + source "$ci_dir/shared.sh" travis_fold start build_docker @@ -22,13 +25,27 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then hash_key=/tmp/.docker-hash-key.txt rm -f "${hash_key}" echo $image >> $hash_key - find $docker_dir -type f | sort | xargs cat >> $hash_key + + cat "$docker_dir/$image/Dockerfile" >> $hash_key + # Look for all source files involves in the COPY command + copied_files=/tmp/.docker-copied-files.txt + rm -f "$copied_files" + for i in $(sed -n -e 's/^COPY \(.*\) .*$/\1/p' "$docker_dir/$image/Dockerfile"); do + # List the file names + find "$docker_dir/$i" -type f >> $copied_files + done + # Sort the file names and cat the content into the hash key + sort $copied_files | xargs cat >> $hash_key + docker --version >> $hash_key cksum=$(sha512sum $hash_key | \ awk '{print $1}') + s3url="s3://$SCCACHE_BUCKET/docker/$cksum" - url="https://s3-us-west-1.amazonaws.com/$SCCACHE_BUCKET/docker/$cksum" - echo "Attempting to download $s3url" + url="https://$SCCACHE_BUCKET.s3.amazonaws.com/docker/$cksum" + upload="aws s3 cp - $s3url" + + echo "Attempting to download $url" rm -f /tmp/rustci_docker_cache set +e retry curl -y 30 -Y 10 --connect-timeout 30 -f -L -C - -o /tmp/rustci_docker_cache "$url" @@ -51,25 +68,30 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then -f "$dockerfile" \ "$context" - if [ "$s3url" != "" ]; then + if [ "$upload" != "" ]; then digest=$(docker inspect rust-ci --format '{{.Id}}') echo "Built container $digest" if ! grep -q "$digest" <(echo "$loaded_images"); then - echo "Uploading finished image to $s3url" + echo "Uploading finished image to $url" set +e docker history -q rust-ci | \ grep -v missing | \ xargs docker save | \ gzip | \ - aws s3 cp - $s3url + $upload set -e else echo "Looks like docker image is the same as before, not uploading" fi + # Record the container image for reuse, e.g. by rustup.rs builds + info="$dist/image-$image.txt" + mkdir -p "$dist" + echo "$url" >"$info" + echo "$digest" >>"$info" fi elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then - if [ -n "$TRAVIS_OS_NAME" ]; then - echo Cannot run disabled images on travis! + if isCI; then + echo Cannot run disabled images on CI! exit 1 fi # retry messes with the pipe from tar to docker. Not needed on non-travis @@ -88,8 +110,6 @@ fi travis_fold end build_docker travis_time_finish -objdir=$root_dir/obj - mkdir -p $HOME/.cargo mkdir -p $objdir/tmp mkdir -p $objdir/cores @@ -123,9 +143,13 @@ exec docker \ --env DEPLOY \ --env DEPLOY_ALT \ --env LOCAL_USER_ID=`id -u` \ + --env CI \ --env TRAVIS \ --env TRAVIS_BRANCH \ + --env TF_BUILD \ + --env BUILD_SOURCEBRANCHNAME \ --env TOOLSTATE_REPO_ACCESS_TOKEN \ + --env TOOLSTATE_REPO \ --env CI_JOB_NAME="${CI_JOB_NAME-$IMAGE}" \ --volume "$HOME/.cargo:/cargo" \ --volume "$HOME/rustsrc:$HOME/rustsrc" \ diff --git a/src/ci/docker/scripts/android-sdk-manager.py b/src/ci/docker/scripts/android-sdk-manager.py new file mode 100755 index 0000000000000..7c9a8b82e9282 --- /dev/null +++ b/src/ci/docker/scripts/android-sdk-manager.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python3 +# Simpler reimplementation of Android's sdkmanager +# Extra features of this implementation are pinning and mirroring + +# These URLs are the Google repositories containing the list of available +# packages and their versions. The list has been generated by listing the URLs +# fetched while executing `tools/bin/sdkmanager --list` +BASE_REPOSITORY = "https://dl.google.com/android/repository/" +REPOSITORIES = [ + "sys-img/android/sys-img2-1.xml", + "sys-img/android-wear/sys-img2-1.xml", + "sys-img/android-wear-cn/sys-img2-1.xml", + "sys-img/android-tv/sys-img2-1.xml", + "sys-img/google_apis/sys-img2-1.xml", + "sys-img/google_apis_playstore/sys-img2-1.xml", + "addon2-1.xml", + "glass/addon2-1.xml", + "extras/intel/addon2-1.xml", + "repository2-1.xml", +] + +# Available hosts: linux, macosx and windows +HOST_OS = "linux" + +# Mirroring options +MIRROR_BUCKET = "rust-lang-ci2" +MIRROR_BASE_DIR = "rust-ci-mirror/android/" + +import argparse +import hashlib +import os +import subprocess +import sys +import tempfile +import urllib.request +import xml.etree.ElementTree as ET + +class Package: + def __init__(self, path, url, sha1, deps=None): + if deps is None: + deps = [] + self.path = path.strip() + self.url = url.strip() + self.sha1 = sha1.strip() + self.deps = deps + + def download(self, base_url): + _, file = tempfile.mkstemp() + url = base_url + self.url + subprocess.run(["curl", "-o", file, url], check=True) + # Ensure there are no hash mismatches + with open(file, "rb") as f: + sha1 = hashlib.sha1(f.read()).hexdigest() + if sha1 != self.sha1: + raise RuntimeError( + "hash mismatch for package " + self.path + ": " + + sha1 + " vs " + self.sha1 + " (known good)" + ) + return file + + def __repr__(self): + return " /dev/null - yes | sdkmanager platform-tools emulator \ - "platforms;android-$api" \ - "system-images;android-$api;default;$abi" > /dev/null -} - -create_avd() { - abi=$1 - api=$2 - - # See https://developer.android.com/studio/command-line/avdmanager.html for - # usage of `avdmanager`. - echo no | avdmanager create avd \ - -n "$abi-$api" \ - -k "system-images;android-$api;default;$abi" -} - -download_and_create_avd() { - download_sdk $1 - download_sysimage $2 $3 - create_avd $2 $3 -} - -# Usage: +# To add a new packages to the SDK or to update an existing one you need to +# run the command: +# +# android-sdk-manager.py add-to-lockfile $LOCKFILE +# +# Then, after every lockfile update the mirror has to be synchronized as well: # -# setup_android_sdk 4333796 armeabi-v7a 18 +# android-sdk-manager.py update-mirror $LOCKFILE # -# 4333796 => -# SDK tool version. -# Copy from https://developer.android.com/studio/index.html#command-tools -# armeabi-v7a => -# System image ABI -# 18 => -# Android API Level (18 = Android 4.3 = Jelly Bean MR2) +/scripts/android-sdk-manager.py install "${LOCKFILE}" "${ANDROID_HOME}" + +details=$(cat "${LOCKFILE}" \ + | grep system-images \ + | sed 's/^system-images;android-\([0-9]\+\);default;\([a-z0-9-]\+\) /\1 \2 /g') +api="$(echo "${details}" | awk '{print($1)}')" +abi="$(echo "${details}" | awk '{print($2)}')" + +# See https://developer.android.com/studio/command-line/avdmanager.html for +# usage of `avdmanager`. +echo no | avdmanager create avd \ + -n "$abi-$api" \ + -k "system-images;android-$api;default;$abi" diff --git a/src/ci/docker/scripts/emscripten.sh b/src/ci/docker/scripts/emscripten.sh index d3b1cded6f589..47196e8939626 100644 --- a/src/ci/docker/scripts/emscripten.sh +++ b/src/ci/docker/scripts/emscripten.sh @@ -18,7 +18,7 @@ exit 1 } cd / -curl -fL https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz | \ +curl -fL https://mozilla-games.s3.amazonaws.com/emscripten/releases/emsdk-portable.tar.gz | \ tar -xz cd /emsdk-portable diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 04483e249257e..8cef69d9c26bb 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -1,4 +1,6 @@ #!/bin/bash +# ignore-tidy-linelength + set -eux arch=$1 @@ -55,7 +57,9 @@ for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared; do files_to_extract=("${files_to_extract[@]}" "./usr/lib/lib${lib}.*") done -URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz +# Originally downloaded from: +# https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz +URL=https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2019-04-04-freebsd-${freebsd_arch}-${freebsd_version}-RELEASE-base.txz curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # Fix up absolute symlinks from the system image. This can be removed diff --git a/src/ci/docker/scripts/musl-toolchain.sh b/src/ci/docker/scripts/musl-toolchain.sh new file mode 100644 index 0000000000000..55899fa6c3e69 --- /dev/null +++ b/src/ci/docker/scripts/musl-toolchain.sh @@ -0,0 +1,82 @@ +# This script runs `musl-cross-make` to prepare C toolchain (Binutils, GCC, musl itself) +# and builds static libunwind that we distribute for static target. +# +# Versions of the toolchain components are configurable in `musl-cross-make/Makefile` and +# musl unlike GLIBC is forward compatible so upgrading it shouldn't break old distributions. +# Right now we have: Binutils 2.27, GCC 6.4.0, musl 1.1.22. +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + rm /tmp/build.log + set -x +} + +ARCH=$1 +TARGET=$ARCH-linux-musl + +OUTPUT=/usr/local +shift + +# Ancient binutils versions don't understand debug symbols produced by more recent tools. +# Apparently applying `-fPIC` everywhere allows them to link successfully. +export CFLAGS="-fPIC $CFLAGS" + +git clone https://github.com/richfelker/musl-cross-make -b v0.9.8 +cd musl-cross-make + +hide_output make -j$(nproc) TARGET=$TARGET +hide_output make install TARGET=$TARGET OUTPUT=$OUTPUT + +cd - + +# Install musl library to make binaries executable +ln -s $OUTPUT/$TARGET/lib/libc.so /lib/ld-musl-$ARCH.so.1 +echo $OUTPUT/$TARGET/lib >> /etc/ld-musl-$ARCH.path + +# Now when musl bootstraps itself create proper toolchain symlinks to make build and tests easier +if [ "$REPLACE_CC" = "1" ]; then + for exec in cc gcc; do + ln -s $TARGET-gcc /usr/local/bin/$exec + done + for exec in cpp c++ g++; do + ln -s $TARGET-g++ /usr/local/bin/$exec + done +fi + +export CC=$TARGET-gcc +export CXX=$TARGET-g++ + +LLVM=70 + +# may have been downloaded in a previous run +if [ ! -d libunwind-release_$LLVM ]; then + curl -L https://github.com/llvm-mirror/llvm/archive/release_$LLVM.tar.gz | tar xzf - + curl -L https://github.com/llvm-mirror/libunwind/archive/release_$LLVM.tar.gz | tar xzf - +fi + +# fixme(mati865): Replace it with https://github.com/rust-lang/rust/pull/59089 +mkdir libunwind-build +cd libunwind-build +cmake ../libunwind-release_$LLVM \ + -DLLVM_PATH=/build/llvm-release_$LLVM \ + -DLIBUNWIND_ENABLE_SHARED=0 \ + -DCMAKE_C_COMPILER=$CC \ + -DCMAKE_CXX_COMPILER=$CXX \ + -DCMAKE_C_FLAGS="$CFLAGS" \ + -DCMAKE_CXX_FLAGS="$CXXFLAGS" + +hide_output make -j$(nproc) +cp lib/libunwind.a $OUTPUT/$TARGET/lib +cd - && rm -rf libunwind-build diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh index 116c16b2f35cd..c2cf77d56cb3b 100644 --- a/src/ci/docker/scripts/musl.sh +++ b/src/ci/docker/scripts/musl.sh @@ -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 diff --git a/src/ci/docker/scripts/sccache.sh b/src/ci/docker/scripts/sccache.sh index e05246201dd0c..194de3c339f8c 100644 --- a/src/ci/docker/scripts/sccache.sh +++ b/src/ci/docker/scripts/sccache.sh @@ -1,8 +1,6 @@ -# ignore-tidy-linelength - set -ex 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-unknown-linux-musl + https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-02-sccache-x86_64-unknown-linux-musl chmod +x /usr/local/bin/sccache diff --git a/src/ci/docker/test-various/Dockerfile b/src/ci/docker/test-various/Dockerfile index 6c419e13c9f05..c45b1a9a0f1d6 100644 --- a/src/ci/docker/test-various/Dockerfile +++ b/src/ci/docker/test-various/Dockerfile @@ -11,19 +11,23 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ cmake \ sudo \ gdb \ - xz-utils - -# FIXME: build the `ptx-linker` instead. -RUN curl -sL https://github.com/denzp/rust-ptx-linker/releases/download/v0.9.0-alpha.2/rust-ptx-linker.linux64.tar.gz | \ - tar -xzvC /usr/bin + xz-utils \ + wget \ + patch RUN curl -sL https://nodejs.org/dist/v9.2.0/node-v9.2.0-linux-x64.tar.xz | \ tar -xJ +WORKDIR /build/ +COPY scripts/musl-toolchain.sh /build/ +RUN bash musl-toolchain.sh x86_64 && rm -rf build +WORKDIR / + COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS \ + --musl-root-x86_64=/usr/local/x86_64-linux-musl \ --set build.nodejs=/node-v9.2.0-linux-x64/bin/node \ --set rust.lld @@ -45,6 +49,12 @@ ENV WASM_SCRIPT python2.7 /checkout/x.py test --target $WASM_TARGETS \ ENV NVPTX_TARGETS=nvptx64-nvidia-cuda ENV NVPTX_SCRIPT python2.7 /checkout/x.py test --target $NVPTX_TARGETS \ - src/test/run-make + src/test/run-make \ + src/test/assembly + +ENV MUSL_TARGETS=x86_64-unknown-linux-musl \ + CC_x86_64_unknown_linux_musl=x86_64-linux-musl-gcc \ + CXX_x86_64_unknown_linux_musl=x86_64-linux-musl-g++ +ENV MUSL_SCRIPT python2.7 /checkout/x.py test --target $MUSL_TARGETS -ENV SCRIPT $WASM_SCRIPT && $NVPTX_SCRIPT +ENV SCRIPT $WASM_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index 1c7eff68adc15..7a503ea4e98c5 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.10 +FROM ubuntu:19.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ diff --git a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile index f16dd9809981e..364f45aba2c00 100644 --- a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile @@ -21,3 +21,10 @@ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false ENV SCRIPT python2.7 ../x.py test distcheck ENV DIST_SRC 1 + +# The purpose of this builder is to test that we can `./x.py test` successfully +# from a tarball, not to test LLVM/rustc's own set of assertions. These cause a +# significant hit to CI compile time (over a half hour as observed in #61185), +# so disable assertions for this builder. +ENV NO_LLVM_ASSERTIONS=1 +ENV NO_DEBUG_ASSERTIONS=1 diff --git a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile index 70390c2ac1df1..a157fee16cfd5 100644 --- a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile +++ b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile @@ -20,3 +20,9 @@ ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --enable-full-bootstrap ENV SCRIPT python2.7 ../x.py build + +# In general this just slows down the build and we're just a smoke test that +# a full bootstrap works in general, so there's not much need to take this +# penalty in build times. +ENV NO_LLVM_ASSERTIONS 1 +ENV NO_DEBUG_ASSERTIONS 1 diff --git a/src/ci/docker/x86_64-gnu-llvm-6.0/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-6.0/Dockerfile index 160b23e0b00d1..ef97f59cafd83 100644 --- a/src/ci/docker/x86_64-gnu-llvm-6.0/Dockerfile +++ b/src/ci/docker/x86_64-gnu-llvm-6.0/Dockerfile @@ -24,4 +24,10 @@ ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --llvm-root=/usr/lib/llvm-6.0 \ --enable-llvm-link-shared -ENV RUST_CHECK_TARGET check +ENV SCRIPT python2.7 ../x.py test src/tools/tidy && python2.7 ../x.py test + +# The purpose of this container isn't to test with debug assertions and +# this is run on all PRs, so let's get speedier builds by disabling these extra +# checks. +ENV NO_DEBUG_ASSERTIONS=1 +ENV NO_LLVM_ASSERTIONS=1 diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile index b0780fdf32a59..d0b244c9b7671 100644 --- a/src/ci/docker/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile @@ -19,4 +19,4 @@ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \ --disable-optimize-tests \ --set rust.test-compare-mode -ENV RUST_CHECK_TARGET check +ENV SCRIPT python2.7 ../x.py test diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index 3343716419ff4..978732e3c089f 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -24,6 +24,7 @@ python2.7 "$X_PY" test --no-fail-fast \ src/doc/reference \ src/doc/rust-by-example \ src/doc/embedded-book \ + src/doc/edition-guide \ src/tools/clippy \ src/tools/rls \ src/tools/rustfmt \ @@ -34,12 +35,17 @@ set -e cat "$TOOLSTATE_FILE" echo +# This function checks if a particular tool is *not* in status "test-pass". +check_tool_failed() { + grep -vq '"'"$1"'":"test-pass"' "$TOOLSTATE_FILE" +} + # This function checks that if a tool's submodule changed, the tool's state must improve verify_status() { echo "Verifying status of $1..." if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then echo "This PR updated '$2', verifying if status is 'test-pass'..." - if grep -vq '"'"$1"'":"test-pass"' "$TOOLSTATE_FILE"; then + if check_tool_failed "$1"; then echo echo "⚠️ We detected that this PR updated '$1', but its tests failed." echo @@ -54,14 +60,16 @@ verify_status() { fi } -# deduplicates the submodule check and the assertion that on beta some tools MUST be passing +# deduplicates the submodule check and the assertion that on beta some tools MUST be passing. +# $1 should be "submodule_changed" to only check tools that got changed by this PR, +# or "beta_required" to check all tools that have $2 set to "beta". check_dispatch() { if [ "$1" = submodule_changed ]; then # ignore $2 (branch id) verify_status $3 $4 elif [ "$2" = beta ]; then echo "Requiring test passing for $3..." - if grep -q '"'"$3"'":"\(test\|build\)-fail"' "$TOOLSTATE_FILE"; then + if check_tool_failed "$3"; then exit 4 fi fi @@ -73,11 +81,13 @@ status_check() { check_dispatch $1 beta nomicon src/doc/nomicon check_dispatch $1 beta reference src/doc/reference check_dispatch $1 beta rust-by-example src/doc/rust-by-example + check_dispatch $1 beta edition-guide src/doc/edition-guide check_dispatch $1 beta rls src/tools/rls check_dispatch $1 beta rustfmt src/tools/rustfmt check_dispatch $1 beta clippy-driver src/tools/clippy # these tools are not required for beta to successfully branch check_dispatch $1 nightly miri src/tools/miri + check_dispatch $1 nightly embedded-book src/doc/embedded-book } # If this PR is intended to update one of these tools, do not let the build pass diff --git a/src/ci/docker/x86_64-gnu-tools/repo.sh b/src/ci/docker/x86_64-gnu-tools/repo.sh index 6364bc2aabf93..741d4dcbd9a45 100644 --- a/src/ci/docker/x86_64-gnu-tools/repo.sh +++ b/src/ci/docker/x86_64-gnu-tools/repo.sh @@ -55,7 +55,7 @@ commit_toolstate_change() { git config --global credential.helper store printf 'https://%s:x-oauth-basic@github.com\n' "$TOOLSTATE_REPO_ACCESS_TOKEN" \ > "$HOME/.git-credentials" - git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git + git clone --depth=1 $TOOLSTATE_REPO cd rust-toolstate FAILURE=1 diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile index dd94f2652b4c9..c3519a0077872 100644 --- a/src/ci/docker/x86_64-gnu/Dockerfile +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.10 +FROM ubuntu:19.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh index 3dfd338157617..8b635810825f1 100755 --- a/src/ci/init_repo.sh +++ b/src/ci/init_repo.sh @@ -1,5 +1,9 @@ #!/usr/bin/env bash +# FIXME(61301): we need to debug spurious failures with this on Windows on +# Azure, so let's print more information in the logs. +set -x + set -o errexit set -o pipefail set -o nounset diff --git a/src/ci/run.sh b/src/ci/run.sh index 42d0d7db5964c..f19bd4e7ec79f 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -23,7 +23,9 @@ fi ci_dir=`cd $(dirname $0) && pwd` source "$ci_dir/shared.sh" -if [ "$TRAVIS" != "true" ] || [ "$TRAVIS_BRANCH" == "auto" ]; then +branch_name=$(getCIBranch) + +if [ ! isCI ] || [ "$branch_name" = "auto" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests" fi @@ -43,11 +45,12 @@ fi # # FIXME: need a scheme for changing this `nightly` value to `beta` and `stable` # either automatically or manually. -export RUST_RELEASE_CHANNEL=nightly -if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then +export RUST_RELEASE_CHANNEL=stable +if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo" + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level-std=1" if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions" @@ -109,7 +112,7 @@ travis_time_finish # Display the CPU and memory information. This helps us know why the CI timing # is fluctuating. travis_fold start log-system-info -if [ "$TRAVIS_OS_NAME" = "osx" ]; then +if isOSX; then system_profiler SPHardwareDataType || true sysctl hw || true ncpus=$(sysctl -n hw.ncpu) @@ -134,7 +137,7 @@ else return $retval } - do_make tidy - do_make all do_make "$RUST_CHECK_TARGET" fi + +sccache --show-stats || true diff --git a/src/ci/shared.sh b/src/ci/shared.sh index 3ba64ad412064..323d53f2bec85 100644 --- a/src/ci/shared.sh +++ b/src/ci/shared.sh @@ -24,6 +24,24 @@ function retry { done } +function isCI { + [ "$CI" = "true" ] || [ "$TRAVIS" = "true" ] || [ "$TF_BUILD" = "True" ] +} + +function isOSX { + [ "$TRAVIS_OS_NAME" = "osx" ] || [ "$AGENT_OS" = "Darwin" ] +} + +function getCIBranch { + if [ "$TRAVIS" = "true" ]; then + echo "$TRAVIS_BRANCH" + elif [ "$APPVEYOR" = "True" ]; then + echo "$APPVEYOR_REPO_BRANCH" + else + echo "$BUILD_SOURCEBRANCHNAME" + fi; +} + if ! declare -F travis_fold; then if [ "${TRAVIS-false}" = 'true' ]; then # This is a trimmed down copy of diff --git a/src/doc/book b/src/doc/book index fab9419503f0e..6c0d83499c8e7 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit fab9419503f0e34c1a06f9350a6705d0ce741dc6 +Subproject commit 6c0d83499c8e77e06a71d28c5e1adccec278d4f3 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 5f3cc2a561870..f8072acde5ce2 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 5f3cc2a5618700efcde3bc00799744f21fa9ad2e +Subproject commit f8072acde5ce29c7570d7986180bbded2d22e287 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index bd2778f304989..ef27b517dcd0b 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit bd2778f304989ee52be8201504d6ec621dd60ca9 +Subproject commit ef27b517dcd0b990c888c0d7caeff52a5a115619 diff --git a/src/doc/man/rustc.1 b/src/doc/man/rustc.1 index 8f611063dbe5d..3788e3c864e82 100644 --- a/src/doc/man/rustc.1 +++ b/src/doc/man/rustc.1 @@ -261,12 +261,12 @@ full debug info with variable and type information. .RE .TP \fBopt\-level\fR=\fIVAL\fR -Optimize with possible levels 0\[en]3 +Optimize with possible levels 0\[en]3, s (optimize for size), or z (for minimal size) .SH ENVIRONMENT -Some of these affect the output of the compiler, while others affect programs -which link to the standard library. +Some of these affect only test harness programs (generated via rustc --test); +others affect all programs which link to the Rust standard library. .TP \fBRUST_TEST_THREADS\fR diff --git a/src/doc/nomicon b/src/doc/nomicon index b7eb4a087207a..341c221116a8b 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit b7eb4a087207af2405c0669fa577f8545b894c66 +Subproject commit 341c221116a8b9f1010cf1eece952b80c5ec7f54 diff --git a/src/doc/redirect.inc b/src/doc/redirect.inc new file mode 100644 index 0000000000000..33e3860c2a434 --- /dev/null +++ b/src/doc/redirect.inc @@ -0,0 +1,2 @@ + + diff --git a/src/doc/reference b/src/doc/reference index 1c775a1dc5e29..7a5aab5fd50d6 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 1c775a1dc5e29bc44b36604b510d6196d98077fa +Subproject commit 7a5aab5fd50d6290679beb4cf42fa5f46ed22aec diff --git a/src/doc/robots.txt b/src/doc/robots.txt new file mode 100644 index 0000000000000..61ee12739fb37 --- /dev/null +++ b/src/doc/robots.txt @@ -0,0 +1,27 @@ +# NB: This file is not automatically deployed. After changes, it needs to be uploaded manually to doc.rust-lang.org +User-agent: * +Disallow: /0.3/ +Disallow: /0.4/ +Disallow: /0.5/ +Disallow: /0.6/ +Disallow: /0.7/ +Disallow: /0.8/ +Disallow: /0.9/ +Disallow: /0.10/ +Disallow: /0.11.0/ +Disallow: /0.12.0/ +Disallow: /1.0.0-alpha/ +Disallow: /1.0.0-alpha.2/ +Disallow: /1.0.0-beta/ +Disallow: /1.0.0-beta.2/ +Disallow: /1.0.0-beta.3/ +Disallow: /1.0.0-beta.4/ +Disallow: /1.0.0-beta.5/ +Disallow: /book/first-edition/ +Disallow: /book/second-edition/ +Disallow: /stable/book/first-edition/ +Disallow: /stable/book/second-edition/ +Disallow: /beta/book/first-edition/ +Disallow: /beta/book/second-edition/ +Disallow: /nightly/book/first-edition/ +Disallow: /nightly/book/second-edition/ diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 2ce92beabb912..62b3ff2cb44dd 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 2ce92beabb912d417a7314d6da83ac9b50dc2afb +Subproject commit 62b3ff2cb44dd8b648c3ef2a9347c3706d148014 diff --git a/src/doc/rust.css b/src/doc/rust.css index 631f64a11dbae..a92d4ff54db83 100644 --- a/src/doc/rust.css +++ b/src/doc/rust.css @@ -14,19 +14,19 @@ font-family: 'Source Serif Pro'; font-style: normal; font-weight: 400; - src: local('Source Serif Pro'), url("SourceSerifPro-Regular.woff") format('woff'); + src: local('Source Serif Pro'), url("SourceSerifPro-Regular.ttf.woff") format('woff'); } @font-face { font-family: 'Source Serif Pro'; font-style: italic; font-weight: 400; - src: url("Heuristica-Italic.woff") format('woff'); + src: url("SourceSerifPro-It.ttf.woff") format('woff'); } @font-face { font-family: 'Source Serif Pro'; font-style: normal; font-weight: 700; - src: local('Source Serif Pro Bold'), url("SourceSerifPro-Bold.woff") format('woff'); + src: local('Source Serif Pro Bold'), url("SourceSerifPro-Bold.ttf.woff") format('woff'); } @font-face { font-family: 'Source Code Pro'; diff --git a/src/doc/rustc-guide b/src/doc/rustc-guide index 344c4e437ba4c..abf512fc9cc96 160000 --- a/src/doc/rustc-guide +++ b/src/doc/rustc-guide @@ -1 +1 @@ -Subproject commit 344c4e437ba4cfa5c14db643ec4d6b68dcd164c5 +Subproject commit abf512fc9cc969dcbea69aa15b44586bbeb13c2d diff --git a/src/doc/rustc-ux-guidelines.md b/src/doc/rustc-ux-guidelines.md index 93e94e5586302..e3684fc9f320a 100644 --- a/src/doc/rustc-ux-guidelines.md +++ b/src/doc/rustc-ux-guidelines.md @@ -61,17 +61,17 @@ for details on how to format and write long error codes. * All of them are accessible [online](http://doc.rust-lang.org/error-index.html), which are auto-generated from rustc source code in different places: - [librustc](https://github.com/rust-lang/rust/blob/master/src/librustc/diagnostics.rs), - [libsyntax](https://github.com/rust-lang/rust/blob/master/src/libsyntax/diagnostics.rs), - [librustc_borrowck](https://github.com/rust-lang/rust/blob/master/src/librustc_borrowck/diagnostics.rs), - [librustc_metadata](https://github.com/rust-lang/rust/blob/master/src/librustc_metadata/diagnostics.rs), - [librustc_mir](https://github.com/rust-lang/rust/blob/master/src/librustc_mir/diagnostics.rs), - [librustc_passes](https://github.com/rust-lang/rust/blob/master/src/librustc_passes/diagnostics.rs), - [librustc_privacy](https://github.com/rust-lang/rust/blob/master/src/librustc_privacy/diagnostics.rs), - [librustc_resolve](https://github.com/rust-lang/rust/blob/master/src/librustc_resolve/diagnostics.rs), - [librustc_codegen_llvm](https://github.com/rust-lang/rust/blob/master/src/librustc_codegen_llvm/diagnostics.rs), - [librustc_plugin](https://github.com/rust-lang/rust/blob/master/src/librustc_plugin/diagnostics.rs), - [librustc_typeck](https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/diagnostics.rs). + [librustc](https://github.com/rust-lang/rust/blob/master/src/librustc/error_codes.rs), + [libsyntax](https://github.com/rust-lang/rust/blob/master/src/libsyntax/error_codes.rs), + [librustc_borrowck](https://github.com/rust-lang/rust/blob/master/src/librustc_borrowck/error_codes.rs), + [librustc_metadata](https://github.com/rust-lang/rust/blob/master/src/librustc_metadata/error_codes.rs), + [librustc_mir](https://github.com/rust-lang/rust/blob/master/src/librustc_mir/error_codes.rs), + [librustc_passes](https://github.com/rust-lang/rust/blob/master/src/librustc_passes/error_codes.rs), + [librustc_privacy](https://github.com/rust-lang/rust/blob/master/src/librustc_privacy/error_codes.rs), + [librustc_resolve](https://github.com/rust-lang/rust/blob/master/src/librustc_resolve/error_codes.rs), + [librustc_codegen_llvm](https://github.com/rust-lang/rust/blob/master/src/librustc_codegen_llvm/error_codes.rs), + [librustc_plugin](https://github.com/rust-lang/rust/blob/master/src/librustc_plugin/error_codes.rs), + [librustc_typeck](https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/error_codes.rs). * Explanations have full markdown support. Use it, especially to highlight code with backticks. * When talking about the compiler, call it `the compiler`, not `Rust` or diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 34708d1847f6b..3cda8d927973c 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -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) diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index a616409d9a400..3773a7783020f 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -214,3 +214,20 @@ This option lets you control what happens when the code panics. ## incremental This flag allows you to enable incremental compilation. + +## profile-generate + +This flag allows for creating instrumented binaries that will collect +profiling data for use with profile-guided optimization (PGO). The flag takes +an optional argument which is the path to a directory into which the +instrumented binary will emit the collected data. See the chapter on +[profile-guided optimization](profile-guided-optimization.html) for more +information. + +## profile-use + +This flag specifies the profiling data file to be used for profile-guided +optimization (PGO). The flag takes a mandatory argument which is the path +to a valid `.profdata` file. See the chapter on +[profile-guided optimization](profile-guided-optimization.html) for more +information. diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index d7e789b5a11f7..bd7f6630ea2ad 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -17,28 +17,147 @@ to `#[cfg(verbose)]` and `#[cfg(feature = "serde")]` respectively. ## `-L`: add a directory to the library search path -When looking for external crates, a directory passed to this flag will be searched. +When looking for external crates or libraries, a directory passed to this flag +will be searched. + +The kind of search path can optionally be specified with the form `-L +KIND=PATH` where `KIND` may be one of: + +- `dependency` — Only search for transitive dependencies in this directory. +- `crate` — Only search for this crate's direct dependencies in this + directory. +- `native` — Only search for native libraries in this directory. +- `framework` — Only search for macOS frameworks in this directory. +- `all` — Search for all library kinds in this directory. This is the default + if `KIND` is not specified. ## `-l`: link the generated crate to a native library This flag allows you to specify linking to a specific native library when building a crate. +The kind of library can optionally be specified with the form `-l KIND=lib` +where `KIND` may be one of: + +- `dylib` — A native dynamic library. +- `static` — A native static library (such as a `.a` archive). +- `framework` — A macOS framework. + +The kind of library can be specified in a [`#[link]` +attribute][link-attribute]. If the kind is not specified in the `link` +attribute or on the command-line, it will link a dynamic library if available, +otherwise it will use a static library. If the kind is specified on the +command-line, it will override the kind specified in a `link` attribute. + +The name used in a `link` attribute may be overridden using the form `-l +ATTR_NAME:LINK_NAME` where `ATTR_NAME` is the name in the `link` attribute, +and `LINK_NAME` is the name of the actual library that will be linked. + +[link-attribute]: ../reference/items/external-blocks.html#the-link-attribute + ## `--crate-type`: a list of types of crates for the compiler to emit -This instructs `rustc` on which crate type to build. +This instructs `rustc` on which crate type to build. This flag accepts a +comma-separated list of values, and may be specified multiple times. The valid +crate types are: + +- `lib` — Generates a library kind preferred by the compiler, currently + defaults to `rlib`. +- `rlib` — A Rust static library. +- `staticlib` — A native static library. +- `dylib` — A Rust dynamic library. +- `cdylib` — A native dynamic library. +- `bin` — A runnable executable program. +- `proc-macro` — Generates a format suitable for a procedural macro library + that may be loaded by the compiler. + +The crate type may be specified with the [`crate_type` attribute][crate_type]. +The `--crate-type` command-line value will override the `crate_type` +attribute. + +More details may be found in the [linkage chapter] of the reference. + +[linkage chapter]: ../reference/linkage.html +[crate_type]: ../reference/linkage.html ## `--crate-name`: specify the name of the crate being built This informs `rustc` of the name of your crate. -## `--emit`: emit output other than a crate - -Instead of producing a crate, this flag can print out things like the assembly or LLVM-IR. +## `--edition`: specify the edition to use + +This flag takes a value of `2015` or `2018`. The default is `2015`. More +information about editions may be found in the [edition guide]. + +[edition guide]: ../edition-guide/introduction.html + +## `--emit`: specifies the types of output files to generate + +This flag controls the types of output files generated by the compiler. It +accepts a comma-separated list of values, and may be specified multiple times. +The valid emit kinds are: + +- `asm` — Generates a file with the crate's assembly code. The default output + filename is `CRATE_NAME.s`. +- `dep-info` — Generates a file with Makefile syntax that indicates all the + source files that were loaded to generate the crate. The default output + filename is `CRATE_NAME.d`. +- `link` — Generates the crates specified by `--crate-type`. The default + output filenames depend on the crate type and platform. This is the default + if `--emit` is not specified. +- `llvm-bc` — Generates a binary file containing the [LLVM bitcode]. The + default output filename is `CRATE_NAME.bc`. +- `llvm-ir` — Generates a file containing [LLVM IR]. The default output + filename is `CRATE_NAME.ll`. +- `metadata` — Generates a file containing metadata about the crate. The + default output filename is `CRATE_NAME.rmeta`. +- `mir` — Generates a file containing rustc's mid-level intermediate + representation. The default output filename is `CRATE_NAME.mir`. +- `obj` — Generates a native object file. The default output filename is + `CRATE_NAME.o`. + +The output filename can be set with the `-o` flag. A suffix may be added to +the filename with the `-C extra-filename` flag. The files are written to the +current directory unless the `--out-dir` flag is used. Each emission type may +also specify the output filename with the form `KIND=PATH`, which takes +precedence over the `-o` flag. + +[LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html +[LLVM IR]: https://llvm.org/docs/LangRef.html ## `--print`: print compiler information -This flag prints out various information about the compiler. +This flag prints out various information about the compiler. This flag may be +specified multiple times, and the information is printed in the order the +flags are specified. Specifying a `--print` flag will usually disable the +`--emit` step and will only print the requested information. The valid types +of print values are: + +- `crate-name` — The name of the crate. +- `file-names` — The names of the files created by the `link` emit kind. +- `sysroot` — Path to the sysroot. +- `cfg` — List of cfg values. See [conditional compilation] for more + information about cfg values. +- `target-list` — List of known targets. The target may be selected with the + `--target` flag. +- `target-cpus` — List of available CPU values for the current target. The + target CPU may be selected with the `-C target-cpu=val` flag. +- `target-features` — List of available target features for the current + target. Target features may be enabled with the `-C target-feature=val` + flag. +- `relocation-models` — List of relocation models. Relocation models may be + selected with the `-C relocation-model=val` flag. +- `code-models` — List of code models. Code models may be selected with the + `-C code-model=val` flag. +- `tls-models` — List of Thread Local Storage models supported. The model may + be selected with the `-Z tls-model=val` flag. +- `native-static-libs` — This may be used when creating a `staticlib` crate + type. If this is the only flag, it will perform a full compilation and + include a diagnostic note that indicates the linker flags to use when + linking the resulting static library. The note starts with the text + `native-static-libs:` to make it easier to fetch the output. + +[conditional compilation]: ../reference/conditional-compilation.html ## `-g`: include debug information @@ -54,7 +173,8 @@ This flag controls the output filename. ## `--out-dir`: directory to write the output in -The outputted crate will be written to this directory. +The outputted crate will be written to this directory. This flag is ignored if +the `-o` flag is used. ## `--explain`: provide a detailed explanation of an error message @@ -86,6 +206,13 @@ This flag will set which lints should be set to the [deny level](lints/levels.ht This flag will set which lints should be set to the [forbid level](lints/levels.html#forbid). +## `-Z`: set unstable options + +This flag will allow you to set unstable options of rustc. In order to set multiple options, +the -Z flag can be used multiple times. For example: `rustc -Z verbose -Z time`. +Specifying options with -Z is only available on nightly. To view all available options +run: `rustc -Z help`. + ## `--cap-lints`: set the most restrictive lint level This flag lets you 'cap' lints, for more, [see here](lints/levels.html#capping-lints). @@ -104,8 +231,9 @@ This flag, when combined with other flags, makes them produce extra output. ## `--extern`: specify where an external library is located -This flag allows you to pass the name and location of an external crate that will -be linked into the crate you're buildling. +This flag allows you to pass the name and location of an external crate that +will be linked into the crate you are building. This flag may be specified +multiple times. The format of the value should be `CRATENAME=PATH`. ## `--sysroot`: Override the system root @@ -114,8 +242,32 @@ distribution; this flag allows that to be overridden. ## `--error-format`: control how errors are produced -This flag lets you control the format of errors. +This flag lets you control the format of messages. Messages are printed to +stderr. The valid options are: + +- `human` — Human-readable output. This is the default. +- `json` — Structured JSON output. +- `short` — Short, one-line messages. ## `--color`: configure coloring of output -This flag lets you control color settings of the output. +This flag lets you control color settings of the output. The valid options +are: + +- `auto` — Use colors if output goes to a tty. This is the default. +- `always` — Always use colors. +- `never` — Never colorize output. + +## `--remap-path-prefix`: remap source names in output + +Remap source path prefixes in all output, including compiler diagnostics, +debug information, macro expansions, etc. It takes a value of the form +`FROM=TO` where a path prefix equal to `FROM` is rewritten to the value `TO`. +The `FROM` may itself contain an `=` symbol, but the `TO` value may not. This +flag may be specified multiple times. + +This is useful for normalizing build products, for example by removing the +current directory out of pathnames emitted into the object files. The +replacement is purely textual, with no consideration of the current system's +pathname syntax. For example `--remap-path-prefix foo=bar` will match +`foo/lib.rs` but not `./foo/lib.rs`. diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index 73a2efcb33a75..2ae726c4ba61d 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -100,9 +100,10 @@ LLVM. However, the approximation is usually reliable. The following table shows known good combinations of toolchain versions. -| | Clang 7 | Clang 8 | +| | Clang 7 | Clang 8 | |-----------|-----------|-----------| | Rust 1.34 | ✗ | ✓ | -| Rust 1.35 | ✗ | ✓(?) | +| Rust 1.35 | ✗ | ✓ | +| Rust 1.36 | ✗ | ✓ | Note that the compatibility policy for this feature might change in the future. diff --git a/src/doc/rustc/src/lints/groups.md b/src/doc/rustc/src/lints/groups.md index 46b717f3387d2..049e59b651722 100644 --- a/src/doc/rustc/src/lints/groups.md +++ b/src/doc/rustc/src/lints/groups.md @@ -21,9 +21,9 @@ Here's a list of each lint group, and the lints that they are made up of: | edition-2018 | Lints that will be turned into errors in Rust 2018 | tyvar-behind-raw-pointer | | rust-2018-idioms | Lints to nudge you toward idiomatic features of Rust 2018 | bare-trait-object, unreachable-pub | | unused | These lints detect things being declared but not used | unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comment, unused-extern-crates, unused-features, unused-parens | -| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, incoherent-fundamental-impls, tyvar-behind-raw-pointer, unstable-name-collision | +| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, tyvar-behind-raw-pointer, unstable-name-collision | Additionally, there's a `bad-style` lint group that's a deprecated alias for `nonstandard-style`. Finally, you can also see the table above by invoking `rustc -W help`. This will give you the exact values for the specific -compiler you have installed. \ No newline at end of file +compiler you have installed. diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md index fa62d1a03f53b..c1740f272ed26 100644 --- a/src/doc/rustc/src/lints/listing/deny-by-default.md +++ b/src/doc/rustc/src/lints/listing/deny-by-default.md @@ -222,44 +222,3 @@ error: invalid `crate_type` value | ^^^^^^^^^^^^^^^^^^^^ | ``` - -## incoherent-fundamental-impls - -This lint detects potentially-conflicting impls that were erroneously allowed. Some -example code that triggers this lint: - -```rust,ignore -pub trait Trait1 { - type Output; -} - -pub trait Trait2 {} - -pub struct A; - -impl Trait1 for T where T: Trait2 { - type Output = (); -} - -impl Trait1> for A { - type Output = i32; -} -``` - -This will produce: - -```text -error: conflicting implementations of trait `Trait1>` for type `A`: (E0119) - --> src/main.rs:13:1 - | -9 | impl Trait1 for T where T: Trait2 { - | --------------------------------------------- first implementation here -... -13 | impl Trait1> for A { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A` - | - = note: #[deny(incoherent_fundamental_impls)] on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46205 - = note: downstream crates may implement trait `Trait2>` for type `A` -``` diff --git a/src/doc/rustc/src/lints/listing/warn-by-default.md b/src/doc/rustc/src/lints/listing/warn-by-default.md index ba927b1ef3b57..6d4aa024c75b4 100644 --- a/src/doc/rustc/src/lints/listing/warn-by-default.md +++ b/src/doc/rustc/src/lints/listing/warn-by-default.md @@ -529,18 +529,21 @@ This lint detects bounds in type aliases. These are not currently enforced. Some example code that triggers this lint: ```rust +#[allow(dead_code)] type SendVec = Vec; ``` This will produce: ```text -warning: type alias is never used: `SendVec` - --> src/main.rs:1:1 +warning: bounds on generic parameters are not enforced in type aliases + --> src/lib.rs:2:17 | -1 | type SendVec = Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 | type SendVec = Vec; + | ^^^^ | + = note: #[warn(type_alias_bounds)] on by default + = help: the bound will not be checked when the type alias is used, and should be removed ``` ## tyvar-behind-raw-pointer @@ -725,19 +728,17 @@ This lint detects attributes that were not used by the compiler. Some example code that triggers this lint: ```rust -#![feature(custom_attribute)] - -#![mutable_doc] +#![macro_export] ``` This will produce: ```text warning: unused attribute - --> src/main.rs:4:1 + --> src/main.rs:1:1 | -4 | #![mutable_doc] - | ^^^^^^^^^^^^^^^ +1 | #![macro_export] + | ^^^^^^^^^^^^^^^^ | ``` diff --git a/src/doc/rustc/src/profile-guided-optimization.md b/src/doc/rustc/src/profile-guided-optimization.md new file mode 100644 index 0000000000000..38be07a6440da --- /dev/null +++ b/src/doc/rustc/src/profile-guided-optimization.md @@ -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_.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//lib/rustlib//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 diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index aba485f752ab2..b21defaedc313 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -178,7 +178,7 @@ $ rustdoc src/lib.rs --passes strip-priv-imports An argument of "list" will print a list of possible "rustdoc passes", and other arguments will be the name of which passes to run in addition to the defaults. -For more details on passes, see [the chapter on them](passes.html). +For more details on passes, see [the chapter on them](passes.md). See also `--no-defaults`. @@ -194,7 +194,7 @@ By default, `rustdoc` will run several passes over your code. This removes those defaults, allowing you to use `--passes` to specify exactly which passes you want. -For more details on passes, see [the chapter on them](passes.html). +For more details on passes, see [the chapter on them](passes.md). See also `--passes`. @@ -207,7 +207,7 @@ $ rustdoc src/lib.rs --test ``` This flag will run your code examples as tests. For more, see [the chapter -on documentation tests](documentation-tests.html). +on documentation tests](documentation-tests.md). See also `--test-args`. @@ -220,7 +220,7 @@ $ rustdoc src/lib.rs --test --test-args ignored ``` This flag will pass options to the test runner when running documentation tests. -For more, see [the chapter on documentation tests](documentation-tests.html). +For more, see [the chapter on documentation tests](documentation-tests.md). See also `--test`. diff --git a/src/doc/rustdoc/src/passes.md b/src/doc/rustdoc/src/passes.md index 615b3dca199f1..12d4ea205b31e 100644 --- a/src/doc/rustdoc/src/passes.md +++ b/src/doc/rustdoc/src/passes.md @@ -5,8 +5,8 @@ Rustdoc has a concept called "passes". These are transformations that In addition to the passes below, check out the docs for these flags: -* [`--passes`](command-line-arguments.html#a--passes-add-more-rustdoc-passes) -* [`--no-defaults`](command-line-arguments.html#a--no-defaults-dont-run-default-passes) +* [`--passes`](command-line-arguments.md#--passes-add-more-rustdoc-passes) +* [`--no-defaults`](command-line-arguments.md#--no-defaults-dont-run-default-passes) ## Default passes diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md index 61e5b3d0133ff..80ac405eb2f2a 100644 --- a/src/doc/rustdoc/src/the-doc-attribute.md +++ b/src/doc/rustdoc/src/the-doc-attribute.md @@ -92,6 +92,21 @@ the tracking issue. #![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] ``` +### `html_root_url` + +The `#[doc(html_root_url = "…")]` attribute value indicates the URL for +generating links to external crates. When rustdoc needs to generate a link to +an item in an external crate, it will first check if the extern crate has been +documented locally on-disk, and if so link directly to it. Failing that, it +will use the URL given by the `--extern-html-root-url` command-line flag if +available. If that is not available, then it will use the `html_root_url` +value in the extern crate if it is available. If that is not available, then +the extern items will not be linked. + +```rust,ignore +#![doc(html_root_url = "https://docs.rs/serde/1.0")] +``` + ### `html_no_source` By default, `rustdoc` will include the source code of your program, with links @@ -187,7 +202,7 @@ mod bar { Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere. One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will -not eagerly inline it as a module unless you add `#[doc(inline)}`. +not eagerly inline it as a module unless you add `#[doc(inline)]`. ## `#[doc(hidden)]` diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 3463cdb126cc6..3938df1a68267 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -53,7 +53,7 @@ For example, in the following code: ```rust /// Does the thing. pub fn do_the_thing(_: SomeType) { - println!("Let's do the thing!"); + println!("Let's do the thing!"); } /// Token you use to [`do_the_thing`]. @@ -66,15 +66,15 @@ target out also works: ```rust pub mod some_module { - /// Token you use to do the thing. - pub struct SomeStruct; + /// Token you use to do the thing. + pub struct SomeStruct; } /// Does the thing. Requires one [`SomeStruct`] for the thing to work. /// /// [`SomeStruct`]: some_module::SomeStruct pub fn do_the_thing(_: some_module::SomeStruct) { - println!("Let's do the thing!"); + println!("Let's do the thing!"); } ``` @@ -428,3 +428,30 @@ $ rustdoc src/lib.rs --test -Z unstable-options --persist-doctests target/rustdo This flag allows you to keep doctest executables around after they're compiled or run. Usually, rustdoc will immediately discard a compiled doctest after it's been tested, but with this option, you can keep those binaries around for farther testing. + +### `--show-coverage`: calculate the percentage of items with documentation + +Using this flag looks like this: + +```bash +$ rustdoc src/lib.rs -Z unstable-options --show-coverage +``` + +If you want to determine how many items in your crate are documented, pass this flag to rustdoc. +When it receives this flag, it will count the public items in your crate that have documentation, +and print out the counts and a percentage instead of generating docs. + +Some methodology notes about what rustdoc counts in this metric: + +* Rustdoc will only count items from your crate (i.e. items re-exported from other crates don't + count). +* Docs written directly onto inherent impl blocks are not counted, even though their doc comments + are displayed, because the common pattern in Rust code is to write all inherent methods into the + same impl block. +* Items in a trait implementation are not counted, as those impls will inherit any docs from the + trait itself. +* By default, only public items are counted. To count private items as well, pass + `--document-private-items` at the same time. + +Public items that are not documented can be seen with the built-in `missing_docs` lint. Private +items that are not documented can be seen with Clippy's `missing_docs_in_private_items` lint. diff --git a/src/doc/rustdoc/src/what-is-rustdoc.md b/src/doc/rustdoc/src/what-is-rustdoc.md index 54472e35b1b2c..bbcacb7f3d5d9 100644 --- a/src/doc/rustdoc/src/what-is-rustdoc.md +++ b/src/doc/rustdoc/src/what-is-rustdoc.md @@ -98,21 +98,21 @@ documentation for them as well! `rustdoc` can also generate HTML from standalone Markdown files. Let's give it a try: create a `README.md` file with these contents: -```text - # Docs +````text +# Docs - This is a project to test out `rustdoc`. +This is a project to test out `rustdoc`. - [Here is a link!](https://www.rust-lang.org) +[Here is a link!](https://www.rust-lang.org) - ## Subheading +## Subheading - ```rust - fn foo() -> i32 { - 1 + 1 - } - ``` +```rust +fn foo() -> i32 { + 1 + 1 +} ``` +```` And call `rustdoc` on it: diff --git a/src/doc/unstable-book/book.toml b/src/doc/unstable-book/book.toml new file mode 100644 index 0000000000000..5b2e19bd7aa78 --- /dev/null +++ b/src/doc/unstable-book/book.toml @@ -0,0 +1,3 @@ +[book] +title = "The Rust Unstable Book" +author = "The Rust Community" diff --git a/src/doc/unstable-book/src/language-features/arbitrary-enum-discriminant.md b/src/doc/unstable-book/src/language-features/arbitrary-enum-discriminant.md new file mode 100644 index 0000000000000..e0bb782270e22 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/arbitrary-enum-discriminant.md @@ -0,0 +1,37 @@ +# `arbitrary_enum_discriminant` + +The tracking issue for this feature is: [#60553] + +[#60553]: https://github.com/rust-lang/rust/issues/60553 + +------------------------ + +The `arbitrary_enum_discriminant` feature permits tuple-like and +struct-like enum variants with `#[repr()]` to have explicit discriminants. + +## Examples + +```rust +#![feature(arbitrary_enum_discriminant)] + +#[allow(dead_code)] +#[repr(u8)] +enum Enum { + Unit = 3, + Tuple(u16) = 2, + Struct { + a: u8, + b: u16, + } = 1, +} + +impl Enum { + fn tag(&self) -> u8 { + unsafe { *(self as *const Self as *const u8) } + } +} + +assert_eq!(3, Enum::Unit.tag()); +assert_eq!(2, Enum::Tuple(5).tag()); +assert_eq!(1, Enum::Struct{a: 7, b: 11}.tag()); +``` diff --git a/src/doc/unstable-book/src/language-features/asm.md b/src/doc/unstable-book/src/language-features/asm.md index f22095fe5de2e..2a1b6397781f9 100644 --- a/src/doc/unstable-book/src/language-features/asm.md +++ b/src/doc/unstable-book/src/language-features/asm.md @@ -190,4 +190,4 @@ constraints, etc. [llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions If you need more power and don't mind losing some of the niceties of -`asm!`, check out [global_asm](language-features/global-asm.html). +`asm!`, check out [global_asm](global-asm.md). diff --git a/src/doc/unstable-book/src/language-features/box-patterns.md b/src/doc/unstable-book/src/language-features/box-patterns.md index 0896627acae1b..bf0819ec920b7 100644 --- a/src/doc/unstable-book/src/language-features/box-patterns.md +++ b/src/doc/unstable-book/src/language-features/box-patterns.md @@ -4,7 +4,7 @@ The tracking issue for this feature is: [#29641] [#29641]: https://github.com/rust-lang/rust/issues/29641 -See also [`box_syntax`](language-features/box-syntax.html) +See also [`box_syntax`](box-syntax.md) ------------------------ diff --git a/src/doc/unstable-book/src/language-features/box-syntax.md b/src/doc/unstable-book/src/language-features/box-syntax.md index 414dc48e557d3..9569974d22ca2 100644 --- a/src/doc/unstable-book/src/language-features/box-syntax.md +++ b/src/doc/unstable-book/src/language-features/box-syntax.md @@ -4,7 +4,7 @@ The tracking issue for this feature is: [#49733] [#49733]: https://github.com/rust-lang/rust/issues/49733 -See also [`box_patterns`](language-features/box-patterns.html) +See also [`box_patterns`](box-patterns.md) ------------------------ diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md index 426fc01a6b051..97cf58e57e605 100644 --- a/src/doc/unstable-book/src/language-features/generators.md +++ b/src/doc/unstable-book/src/language-features/generators.md @@ -146,7 +146,7 @@ closure-like semantics. Namely: generators also depend on variables live across suspension points. This means that although the ambient environment may be `Send` or `Sync`, the generator itself may not be due to internal variables live across `yield` points being - not-`Send` or not-`Sync`. Note that generators, like closures, do + not-`Send` or not-`Sync`. Note that generators do not implement traits like `Copy` or `Clone` automatically. * Whenever a generator is dropped it will drop all captured environment diff --git a/src/doc/unstable-book/src/language-features/global-asm.md b/src/doc/unstable-book/src/language-features/global-asm.md index f1ef74a63b513..bc55fe80fa64c 100644 --- a/src/doc/unstable-book/src/language-features/global-asm.md +++ b/src/doc/unstable-book/src/language-features/global-asm.md @@ -75,4 +75,4 @@ usages and placed the larger, single usage in the crate root. If you don't need quite as much power and flexibility as `global_asm!` provides, and you don't mind restricting your inline assembly to `fn` bodies only, you might try the -[asm](language-features/asm.html) feature instead. +[asm](asm.md) feature instead. diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index b16739b4743a9..3ee024c6b5883 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -192,7 +192,7 @@ such as "```undefined reference to `__rust_probestack'```". Using this crate also requires enabling the library feature `compiler_builtins_lib`. You can read more about this [here][compiler-builtins-lib]. -[compiler-builtins-lib]: library-features/compiler-builtins-lib.html +[compiler-builtins-lib]: ../library-features/compiler-builtins-lib.md ## More about the language items diff --git a/src/doc/unstable-book/src/language-features/member-constraints.md b/src/doc/unstable-book/src/language-features/member-constraints.md new file mode 100644 index 0000000000000..0d11c31aca6e9 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/member-constraints.md @@ -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 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. diff --git a/src/doc/unstable-book/src/language-features/non-ascii-idents.md b/src/doc/unstable-book/src/language-features/non-ascii-idents.md index 46957c00bf95c..22dae0c89a6ff 100644 --- a/src/doc/unstable-book/src/language-features/non-ascii-idents.md +++ b/src/doc/unstable-book/src/language-features/non-ascii-idents.md @@ -45,4 +45,4 @@ that does _not_ occur in the set of [strict keywords]. [`XID_start`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Start%3A%5D&abb=on&g=&i= [`XID_continue`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Continue%3A%5D&abb=on&g=&i= -[strict keywords]: ../reference/keywords.html#strict-keywords +[strict keywords]: ../../reference/keywords.md#strict-keywords diff --git a/src/doc/unstable-book/src/language-features/non-exhaustive.md b/src/doc/unstable-book/src/language-features/non-exhaustive.md index f9840e1b83f2b..907147c17ef8e 100644 --- a/src/doc/unstable-book/src/language-features/non-exhaustive.md +++ b/src/doc/unstable-book/src/language-features/non-exhaustive.md @@ -7,10 +7,12 @@ The tracking issue for this feature is: [#44109] ------------------------ The `non_exhaustive` gate allows you to use the `#[non_exhaustive]` attribute -on structs and enums. When applied within a crate, users of the crate will need -to use the `_` pattern when matching enums and use the `..` pattern when -matching structs. Structs marked as `non_exhaustive` will not be able to be -created normally outside of the defining crate. This is demonstrated below: +on structs, enums and enum variants. When applied within a crate, users of the +crate will need to use the `_` pattern when matching enums and use the `..` +pattern when matching structs. Enum variants cannot be matched against. +Structs and enum variants marked as `non_exhaustive` will not be able to +be created normally outside of the defining crate. This is demonstrated +below: ```rust,ignore (pseudo-Rust) use std::error::Error as StdError; @@ -72,4 +74,3 @@ let config = Config { window_width: 640, window_height: 480 }; // when marked non_exhaustive. let &Config { window_width, window_height, .. } = config; ``` - diff --git a/src/doc/unstable-book/src/language-features/on-unimplemented.md b/src/doc/unstable-book/src/language-features/on-unimplemented.md index f787f629756f3..a770ab65c26f8 100644 --- a/src/doc/unstable-book/src/language-features/on-unimplemented.md +++ b/src/doc/unstable-book/src/language-features/on-unimplemented.md @@ -138,3 +138,16 @@ error[E0277]: `&str` is not an iterator = help: the trait `std::iter::Iterator` is not implemented for `&str` = note: required by `std::iter::IntoIterator::into_iter` ``` + +If you need to filter on multiple attributes, you can use `all`, `any` or +`not` in the following way: + +```rust,compile_fail +#[rustc_on_unimplemented( + on( + all(_Self="&str", T="std::string::String"), + note="you can coerce a `{T}` into a `{Self}` by writing `&*variable`" + ) +)] +pub trait From: Sized { /* ... */ } +``` diff --git a/src/doc/unstable-book/src/language-features/plugin-registrar.md b/src/doc/unstable-book/src/language-features/plugin-registrar.md index b16e2ac2d221c..bf5dd81d735af 100644 --- a/src/doc/unstable-book/src/language-features/plugin-registrar.md +++ b/src/doc/unstable-book/src/language-features/plugin-registrar.md @@ -8,6 +8,6 @@ This feature is part of "compiler plugins." It will often be used with the [`plugin`] and `rustc_private` features as well. For more details, see their docs. -[`plugin`]: language-features/plugin.html +[`plugin`]: plugin.md ------------------------ diff --git a/src/doc/unstable-book/src/language-features/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md index cab350381d2bd..0e38e2865d893 100644 --- a/src/doc/unstable-book/src/language-features/plugin.md +++ b/src/doc/unstable-book/src/language-features/plugin.md @@ -8,7 +8,7 @@ The tracking issue for this feature is: [#29597] This feature is part of "compiler plugins." It will often be used with the [`plugin_registrar`] and `rustc_private` features. -[`plugin_registrar`]: language-features/plugin-registrar.html +[`plugin_registrar`]: plugin-registrar.md ------------------------ @@ -39,7 +39,7 @@ of a library. Plugins can extend Rust's syntax in various ways. One kind of syntax extension is the procedural macro. These are invoked the same way as [ordinary -macros](../book/macros.html), but the expansion is performed by arbitrary Rust +macros](../../book/macros.md), but the expansion is performed by arbitrary Rust code that manipulates syntax trees at compile time. @@ -56,7 +56,7 @@ extern crate syntax_pos; extern crate rustc; extern crate rustc_plugin; -use syntax::parse::token; +use syntax::parse::token::{self, Token}; use syntax::tokenstream::TokenTree; use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; use syntax::ext::build::AstBuilder; // A trait for expr_usize. @@ -64,7 +64,7 @@ use syntax_pos::Span; use rustc_plugin::Registry; fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) - -> Box { + -> Box { static NUMERALS: &'static [(&'static str, usize)] = &[ ("M", 1000), ("CM", 900), ("D", 500), ("CD", 400), @@ -80,7 +80,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) } let text = match args[0] { - TokenTree::Token(_, token::Ident(s)) => s.to_string(), + TokenTree::Token(Token { kind: token::Ident(s, _), .. }) => s.to_string(), _ => { cx.span_err(sp, "argument should be a single identifier"); return DummyResult::any(sp); @@ -130,9 +130,9 @@ The advantages over a simple `fn(&str) -> u32` are: a way to define new literal syntax for any data type. In addition to procedural macros, you can define new -[`derive`](../reference/attributes.html#derive)-like attributes and other kinds +[`derive`](../../reference/attributes/derive.md)-like attributes and other kinds of extensions. See `Registry::register_syntax_extension` and the -`SyntaxExtension` enum. For a more involved macro example, see +`SyntaxExtension` struct. For a more involved macro example, see [`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs). @@ -174,7 +174,7 @@ quasiquote as an ordinary plugin library. # Lint plugins Plugins can extend [Rust's lint -infrastructure](../reference/attributes.html#lint-check-attributes) with +infrastructure](../../reference/attributes/diagnostics.md#lint-check-attributes) with additional checks for code style, safety, etc. Now let's write a plugin [`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/ui-fulldeps/auxiliary/lint_plugin_test.rs) that warns about any item named `lintme`. @@ -253,7 +253,7 @@ mostly use the same infrastructure as lint plugins, and provide examples of how to access type information. Lints defined by plugins are controlled by the usual [attributes and compiler -flags](../reference/attributes.html#lint-check-attributes), e.g. +flags](../../reference/attributes/diagnostics.md#lint-check-attributes), e.g. `#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the first argument to `declare_lint!`, with appropriate case and punctuation conversion. diff --git a/src/doc/unstable-book/src/language-features/repr-align-enum.md b/src/doc/unstable-book/src/language-features/repr-align-enum.md deleted file mode 100644 index 415c6ebe8b4bc..0000000000000 --- a/src/doc/unstable-book/src/language-features/repr-align-enum.md +++ /dev/null @@ -1,42 +0,0 @@ -# `repr_align_enum` - -The tracking issue for this feature is: [#57996] - -[#57996]: https://github.com/rust-lang/rust/issues/57996 - ------------------------- - -The `repr_align_enum` feature allows using the `#[repr(align(x))]` attribute -on enums, similarly to structs. - -# Examples - -```rust -#![feature(repr_align_enum)] - -#[repr(align(8))] -enum Aligned { - Foo, - Bar { value: u32 }, -} - -fn main() { - assert_eq!(std::mem::align_of::(), 8); -} -``` - -This is equivalent to using an aligned wrapper struct everywhere: - -```rust -#[repr(align(8))] -struct Aligned(Unaligned); - -enum Unaligned { - Foo, - Bar { value: u32 }, -} - -fn main() { - assert_eq!(std::mem::align_of::(), 8); -} -``` diff --git a/src/doc/unstable-book/src/language-features/transparent-enums.md b/src/doc/unstable-book/src/language-features/transparent-enums.md new file mode 100644 index 0000000000000..862411ab39203 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/transparent-enums.md @@ -0,0 +1,93 @@ +# `transparent_enums` + +The tracking issue for this feature is [#60405] + +[60405]: https://github.com/rust-lang/rust/issues/60405 + +---- + +The `transparent_enums` feature allows you mark `enum`s as +`#[repr(transparent)]`. An `enum` may be `#[repr(transparent)]` if it has +exactly one variant, and that variant matches the same conditions which `struct` +requires for transparency. Some concrete illustrations follow. + +```rust +#![feature(transparent_enums)] + +// This enum has the same representation as `f32`. +#[repr(transparent)] +enum SingleFieldEnum { + Variant(f32) +} + +// This enum has the same representation as `usize`. +#[repr(transparent)] +enum MultiFieldEnum { + Variant { field: usize, nothing: () }, +} +``` + +For consistency with transparent `struct`s, `enum`s must have exactly one +non-zero-sized field. If all fields are zero-sized, the `enum` must not be +`#[repr(transparent)]`: + +```rust +#![feature(transparent_enums)] + +// This (non-transparent) enum is already valid in stable Rust: +pub enum GoodEnum { + Nothing, +} + +// Error: transparent enum needs exactly one non-zero-sized field, but has 0 +// #[repr(transparent)] +// pub enum BadEnum { +// Nothing(()), +// } + +// Error: transparent enum needs exactly one non-zero-sized field, but has 0 +// #[repr(transparent)] +// pub enum BadEmptyEnum { +// Nothing, +// } +``` + +The one exception is if the `enum` is generic over `T` and has a field of type +`T`, it may be `#[repr(transparent)]` even if `T` is a zero-sized type: + +```rust +#![feature(transparent_enums)] + +// This enum has the same representation as `T`. +#[repr(transparent)] +pub enum GenericEnum { + Variant(T, ()), +} + +// This is okay even though `()` is a zero-sized type. +pub const THIS_IS_OKAY: GenericEnum<()> = GenericEnum::Variant((), ()); +``` + +Transparent `enum`s require exactly one variant: + +```rust +// Error: transparent enum needs exactly one variant, but has 0 +// #[repr(transparent)] +// pub enum TooFewVariants { +// } + +// Error: transparent enum needs exactly one variant, but has 2 +// #[repr(transparent)] +// pub enum TooManyVariants { +// First(usize), +// Second, +// } +``` + +Like transarent `struct`s, a transparent `enum` of type `E` has the same layout, +size, and ABI as its single non-ZST field. If it is generic over a type `T`, and +all its fields are ZSTs except for exactly one field of type `T`, then it has +the same layout and ABI as `T` (even if `T` is a ZST when monomorphized). + +Like transparent `struct`s, transparent `enum`s are FFI-safe if and only if +their underlying representation type is also FFI-safe. diff --git a/src/doc/unstable-book/src/language-features/transparent-unions.md b/src/doc/unstable-book/src/language-features/transparent-unions.md new file mode 100644 index 0000000000000..b731c9ea6d012 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/transparent-unions.md @@ -0,0 +1,83 @@ +# `transparent_unions` + +The tracking issue for this feature is [#60405] + +[60405]: https://github.com/rust-lang/rust/issues/60405 + +---- + +The `transparent_unions` feature allows you mark `union`s as +`#[repr(transparent)]`. A `union` may be `#[repr(transparent)]` in exactly the +same conditions in which a `struct` may be `#[repr(transparent)]` (generally, +this means the `union` must have exactly one non-zero-sized field). Some +concrete illustrations follow. + +```rust +#![feature(transparent_unions)] + +// This union has the same representation as `f32`. +#[repr(transparent)] +union SingleFieldUnion { + field: f32, +} + +// This union has the same representation as `usize`. +#[repr(transparent)] +union MultiFieldUnion { + field: usize, + nothing: (), +} +``` + +For consistency with transparent `struct`s, `union`s must have exactly one +non-zero-sized field. If all fields are zero-sized, the `union` must not be +`#[repr(transparent)]`: + +```rust +#![feature(transparent_unions)] + +// This (non-transparent) union is already valid in stable Rust: +pub union GoodUnion { + pub nothing: (), +} + +// Error: transparent union needs exactly one non-zero-sized field, but has 0 +// #[repr(transparent)] +// pub union BadUnion { +// pub nothing: (), +// } +``` + +The one exception is if the `union` is generic over `T` and has a field of type +`T`, it may be `#[repr(transparent)]` even if `T` is a zero-sized type: + +```rust +#![feature(transparent_unions)] + +// This union has the same representation as `T`. +#[repr(transparent)] +pub union GenericUnion { // Unions with non-`Copy` fields are unstable. + pub field: T, + pub nothing: (), +} + +// This is okay even though `()` is a zero-sized type. +pub const THIS_IS_OKAY: GenericUnion<()> = GenericUnion { field: () }; +``` + +Like transarent `struct`s, a transparent `union` of type `U` has the same +layout, size, and ABI as its single non-ZST field. If it is generic over a type +`T`, and all its fields are ZSTs except for exactly one field of type `T`, then +it has the same layout and ABI as `T` (even if `T` is a ZST when monomorphized). + +Like transparent `struct`s, transparent `union`s are FFI-safe if and only if +their underlying representation type is also FFI-safe. + +A `union` may not be eligible for the same nonnull-style optimizations that a +`struct` or `enum` (with the same fields) are eligible for. Adding +`#[repr(transparent)]` to `union` does not change this. To give a more concrete +example, it is unspecified whether `size_of::()` is equal to +`size_of::>()`, where `T` is a `union` (regardless of whether or not +it is transparent). The Rust compiler is free to perform this optimization if +possible, but is not required to, and different compiler versions may differ in +their application of these optimizations. diff --git a/src/doc/unstable-book/src/language-features/type-alias-enum-variants.md b/src/doc/unstable-book/src/language-features/type-alias-enum-variants.md deleted file mode 100644 index bcdeafc4b1137..0000000000000 --- a/src/doc/unstable-book/src/language-features/type-alias-enum-variants.md +++ /dev/null @@ -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 } => {} - } -} -``` diff --git a/src/doc/unstable-book/src/language-features/unboxed-closures.md b/src/doc/unstable-book/src/language-features/unboxed-closures.md index d845c99a88a69..71003fba00ba2 100644 --- a/src/doc/unstable-book/src/language-features/unboxed-closures.md +++ b/src/doc/unstable-book/src/language-features/unboxed-closures.md @@ -2,7 +2,7 @@ The tracking issue for this feature is [#29625] -See Also: [`fn_traits`](library-features/fn-traits.html) +See Also: [`fn_traits`](../library-features/fn-traits.md) [#29625]: https://github.com/rust-lang/rust/issues/29625 diff --git a/src/doc/unstable-book/src/language-features/unsized-locals.md b/src/doc/unstable-book/src/language-features/unsized-locals.md index edc039f896b2c..343084b7db501 100644 --- a/src/doc/unstable-book/src/language-features/unsized-locals.md +++ b/src/doc/unstable-book/src/language-features/unsized-locals.md @@ -117,9 +117,7 @@ fn main () { } ``` -One of the objectives of this feature is to allow `Box`, instead of `Box` in the future. See [#28796] for details. - -[#28796]: https://github.com/rust-lang/rust/issues/28796 +One of the objectives of this feature is to allow `Box`. ## Variable length arrays diff --git a/src/doc/unstable-book/src/library-features/fn-traits.md b/src/doc/unstable-book/src/library-features/fn-traits.md index 72a3f36c10b69..29a8aecee6c2f 100644 --- a/src/doc/unstable-book/src/library-features/fn-traits.md +++ b/src/doc/unstable-book/src/library-features/fn-traits.md @@ -2,7 +2,7 @@ The tracking issue for this feature is [#29625] -See Also: [`unboxed_closures`](language-features/unboxed-closures.html) +See Also: [`unboxed_closures`](../language-features/unboxed-closures.md) [#29625]: https://github.com/rust-lang/rust/issues/29625 diff --git a/src/doc/unstable-book/src/the-unstable-book.md b/src/doc/unstable-book/src/the-unstable-book.md index 604b449f16379..554c52c3c9c27 100644 --- a/src/doc/unstable-book/src/the-unstable-book.md +++ b/src/doc/unstable-book/src/the-unstable-book.md @@ -14,7 +14,7 @@ fn main() { The `box_syntax` feature [has a chapter][box] describing how to use it. -[box]: language-features/box-syntax.html +[box]: language-features/box-syntax.md Because this documentation relates to unstable features, we make no guarantees that what is contained here is accurate or up to date. It's developed on a diff --git a/src/etc/cpu-usage-over-time-plot.sh b/src/etc/cpu-usage-over-time-plot.sh new file mode 100755 index 0000000000000..724a21c3fc269 --- /dev/null +++ b/src/etc/cpu-usage-over-time-plot.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# A small script to help visualizing CPU usage over time data collected on CI +# using `gnuplot`. +# +# This script is expected to be called with two arguments. The first is the full +# commit SHA of the build you're interested in, and the second is the name of +# the builder. For example: +# +# ./src/etc/cpu-usage-over-time-plot.sh e699ea096fcc2fc9ce8e8bcf884e11496a31cc9f i686-mingw-1 +# +# That will generate `$builder.png` in the current directory which you can open +# up to see a hopefully pretty graph. +# +# Improvements to this script are greatly appreciated! + +set -ex + +bucket=rust-lang-ci-evalazure +commit=$1 +builder=$2 + +curl -O https://$bucket.s3.amazonaws.com/rustc-builds/$commit/cpu-$builder.csv + +gnuplot <<-EOF +reset +set timefmt '%Y-%m-%dT%H:%M:%S' +set xdata time +set ylabel "CPU Usage %" +set xlabel "Time" +set datafile sep ',' +set term png size 3000,1000 +set output "$builder.png" +set grid + +f(x) = mean_y +fit f(x) 'cpu-$builder.csv' using 1:(100-\$2) via mean_y + +set label 1 gprintf("Average = %g%%", mean_y) center font ",18" +set label 1 at graph 0.50, 0.25 +set xtics rotate by 45 offset -2,-2.4 300 +set ytics 10 +set boxwidth 0.5 + +plot \\ + mean_y with lines linetype 1 linecolor rgb "#ff0000" title "average", \\ + "cpu-$builder.csv" using 1:(100-\$2) with points pointtype 7 pointsize 0.4 title "$builder", \\ + "" using 1:(100-\$2) smooth bezier linewidth 3 title "bezier" +EOF diff --git a/src/etc/lldb_rust_formatters.py b/src/etc/lldb_rust_formatters.py index 2c651c90f82eb..fdc1c4fa0cc38 100644 --- a/src/etc/lldb_rust_formatters.py +++ b/src/etc/lldb_rust_formatters.py @@ -290,6 +290,8 @@ def render_element(i): def read_utf8_string(ptr_val, byte_count): + if byte_count == 0: + return '""' error = lldb.SBError() process = ptr_val.get_wrapped_value().GetProcess() data = process.ReadMemory(ptr_val.as_integer(), byte_count, error) diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis index e3d99e34b3579..de30b58526a13 100644 --- a/src/etc/natvis/liballoc.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -7,11 +7,11 @@ buf.cap len - buf.ptr.pointer.__0 + buf.ptr.pointer - + {{ size={tail <= head ? head - tail : buf.cap - tail + head} }} tail <= head ? head - tail : buf.cap - tail + head @@ -24,19 +24,19 @@ - buf.ptr.pointer.__0 + i + buf.ptr.pointer[i] i = (i + 1 == buf.cap ? 0 : i + 1) - + {{ size={len} }} len - *(alloc::linked_list::Node<$T1> **)&head - *(alloc::linked_list::Node<$T1> **)&next + *(alloc::collections::linked_list::Node<$T1> **)&head + *(alloc::collections::linked_list::Node<$T1> **)&next element diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 37d64be1ce963..0e703b3b95026 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -1,15 +1,15 @@ - {{ Unique {*pointer.__0} }} + {{ Unique {pointer} }} - pointer.__0 + pointer - {{ Shared {*pointer.__0} }} + {{ Shared {pointer} }} - pointer.__0 + pointer diff --git a/src/etc/rust-lldb b/src/etc/rust-lldb index 424302d495f3e..0eb99423df576 100755 --- a/src/etc/rust-lldb +++ b/src/etc/rust-lldb @@ -31,7 +31,7 @@ category_definition="type summary add --no-value --python-function lldb_rust_for category_enable="type category enable Rust" # Call LLDB with the commands added to the argument list -exec "$lldb" --one-line-before-file="$script_import" \ - --one-line-before-file="$category_definition" \ - --one-line-before-file="$category_enable" \ +exec "$lldb" --one-line-before-file "$script_import" \ + --one-line-before-file "$category_definition" \ + --one-line-before-file "$category_enable" \ "$@" diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index f6d6c1de8f511..bcb27bb5161e2 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -12,7 +12,7 @@ path = "lib.rs" [dependencies] core = { path = "../libcore" } -compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.10", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = "0.6" @@ -33,3 +33,4 @@ harness = false [features] compiler-builtins-mem = ['compiler_builtins/mem'] +compiler-builtins-c = ["compiler_builtins/c"] diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index f3877e51a6633..755feb8496203 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -15,7 +15,8 @@ extern "Rust" { // them from the `#[global_allocator]` attribute if there is one, or uses the // default implementations in libstd (`__rdl_alloc` etc in `src/libstd/alloc.rs`) // otherwise. - #[allocator] + #[cfg_attr(bootstrap, allocator)] + #[cfg_attr(not(bootstrap), rustc_allocator)] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize) -> *mut u8; #[rustc_allocator_nounwind] @@ -37,6 +38,8 @@ extern "Rust" { /// /// Note: while this type is unstable, the functionality it provides can be /// accessed through the [free functions in `alloc`](index.html#functions). +/// +/// [`Alloc`]: trait.Alloc.html #[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Default, Debug)] pub struct Global; @@ -54,6 +57,10 @@ pub struct Global; /// /// See [`GlobalAlloc::alloc`]. /// +/// [`Global`]: struct.Global.html +/// [`Alloc`]: trait.Alloc.html +/// [`GlobalAlloc::alloc`]: trait.GlobalAlloc.html#tymethod.alloc +/// /// # Examples /// /// ``` @@ -87,6 +94,10 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { /// # Safety /// /// See [`GlobalAlloc::dealloc`]. +/// +/// [`Global`]: struct.Global.html +/// [`Alloc`]: trait.Alloc.html +/// [`GlobalAlloc::dealloc`]: trait.GlobalAlloc.html#tymethod.dealloc #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { @@ -105,6 +116,10 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { /// # Safety /// /// See [`GlobalAlloc::realloc`]. +/// +/// [`Global`]: struct.Global.html +/// [`Alloc`]: trait.Alloc.html +/// [`GlobalAlloc::realloc`]: trait.GlobalAlloc.html#method.realloc #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { @@ -124,6 +139,10 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 /// /// See [`GlobalAlloc::alloc_zeroed`]. /// +/// [`Global`]: struct.Global.html +/// [`Alloc`]: trait.Alloc.html +/// [`GlobalAlloc::alloc_zeroed`]: trait.GlobalAlloc.html#method.alloc_zeroed +/// /// # Examples /// /// ``` @@ -252,6 +271,7 @@ mod tests { } #[bench] + #[cfg(not(miri))] // Miri does not support benchmarks fn alloc_owned_small(b: &mut Bencher) { b.iter(|| { let _: Box<_> = box 10; diff --git a/src/liballoc/benches/btree/set.rs b/src/liballoc/benches/btree/set.rs index 08e1db5fbb74d..6357ea3ea11bd 100644 --- a/src/liballoc/benches/btree/set.rs +++ b/src/liballoc/benches/btree/set.rs @@ -3,59 +3,49 @@ use std::collections::BTreeSet; use rand::{thread_rng, Rng}; use test::{black_box, Bencher}; -fn random(n1: u32, n2: u32) -> [BTreeSet; 2] { +fn random(n: usize) -> BTreeSet { let mut rng = thread_rng(); - let mut set1 = BTreeSet::new(); - let mut set2 = BTreeSet::new(); - for _ in 0..n1 { - let i = rng.gen::(); - set1.insert(i); + let mut set = BTreeSet::new(); + while set.len() < n { + set.insert(rng.gen()); } - for _ in 0..n2 { - let i = rng.gen::(); - set2.insert(i); - } - [set1, set2] + assert_eq!(set.len(), n); + set } -fn staggered(n1: u32, n2: u32) -> [BTreeSet; 2] { - let mut even = BTreeSet::new(); - let mut odd = BTreeSet::new(); - for i in 0..n1 { - even.insert(i * 2); - } - for i in 0..n2 { - odd.insert(i * 2 + 1); +fn neg(n: usize) -> BTreeSet { + let mut set = BTreeSet::new(); + for i in -(n as i32)..=-1 { + set.insert(i); } - [even, odd] + assert_eq!(set.len(), n); + set } -fn neg_vs_pos(n1: u32, n2: u32) -> [BTreeSet; 2] { - let mut neg = BTreeSet::new(); - let mut pos = BTreeSet::new(); - for i in -(n1 as i32)..=-1 { - neg.insert(i); - } - for i in 1..=(n2 as i32) { - pos.insert(i); +fn pos(n: usize) -> BTreeSet { + let mut set = BTreeSet::new(); + for i in 1..=(n as i32) { + set.insert(i); } - [neg, pos] + assert_eq!(set.len(), n); + set } -fn pos_vs_neg(n1: u32, n2: u32) -> [BTreeSet; 2] { - let mut neg = BTreeSet::new(); - let mut pos = BTreeSet::new(); - for i in -(n1 as i32)..=-1 { - neg.insert(i); - } - for i in 1..=(n2 as i32) { - pos.insert(i); + +fn stagger(n1: usize, factor: usize) -> [BTreeSet; 2] { + let n2 = n1 * factor; + let mut sets = [BTreeSet::new(), BTreeSet::new()]; + for i in 0..(n1 + n2) { + let b = i % (factor + 1) != 0; + sets[b as usize].insert(i as u32); } - [pos, neg] + assert_eq!(sets[0].len(), n1); + assert_eq!(sets[1].len(), n2); + sets } -macro_rules! set_intersection_bench { - ($name: ident, $sets: expr) => { +macro_rules! set_bench { + ($name: ident, $set_func: ident, $result_func: ident, $sets: expr) => { #[bench] pub fn $name(b: &mut Bencher) { // setup @@ -63,26 +53,36 @@ macro_rules! set_intersection_bench { // measure b.iter(|| { - let x = sets[0].intersection(&sets[1]).count(); + let x = sets[0].$set_func(&sets[1]).$result_func(); black_box(x); }) } }; } -set_intersection_bench! {intersect_random_100, random(100, 100)} -set_intersection_bench! {intersect_random_10k, random(10_000, 10_000)} -set_intersection_bench! {intersect_random_10_vs_10k, random(10, 10_000)} -set_intersection_bench! {intersect_random_10k_vs_10, random(10_000, 10)} -set_intersection_bench! {intersect_staggered_100, staggered(100, 100)} -set_intersection_bench! {intersect_staggered_10k, staggered(10_000, 10_000)} -set_intersection_bench! {intersect_staggered_10_vs_10k, staggered(10, 10_000)} -set_intersection_bench! {intersect_staggered_10k_vs_10, staggered(10_000, 10)} -set_intersection_bench! {intersect_neg_vs_pos_100, neg_vs_pos(100, 100)} -set_intersection_bench! {intersect_neg_vs_pos_10k, neg_vs_pos(10_000, 10_000)} -set_intersection_bench! {intersect_neg_vs_pos_10_vs_10k,neg_vs_pos(10, 10_000)} -set_intersection_bench! {intersect_neg_vs_pos_10k_vs_10,neg_vs_pos(10_000, 10)} -set_intersection_bench! {intersect_pos_vs_neg_100, pos_vs_neg(100, 100)} -set_intersection_bench! {intersect_pos_vs_neg_10k, pos_vs_neg(10_000, 10_000)} -set_intersection_bench! {intersect_pos_vs_neg_10_vs_10k,pos_vs_neg(10, 10_000)} -set_intersection_bench! {intersect_pos_vs_neg_10k_vs_10,pos_vs_neg(10_000, 10)} +set_bench! {intersection_100_neg_vs_100_pos, intersection, count, [neg(100), pos(100)]} +set_bench! {intersection_100_neg_vs_10k_pos, intersection, count, [neg(100), pos(10_000)]} +set_bench! {intersection_100_pos_vs_100_neg, intersection, count, [pos(100), neg(100)]} +set_bench! {intersection_100_pos_vs_10k_neg, intersection, count, [pos(100), neg(10_000)]} +set_bench! {intersection_10k_neg_vs_100_pos, intersection, count, [neg(10_000), pos(100)]} +set_bench! {intersection_10k_neg_vs_10k_pos, intersection, count, [neg(10_000), pos(10_000)]} +set_bench! {intersection_10k_pos_vs_100_neg, intersection, count, [pos(10_000), neg(100)]} +set_bench! {intersection_10k_pos_vs_10k_neg, intersection, count, [pos(10_000), neg(10_000)]} +set_bench! {intersection_random_100_vs_100, intersection, count, [random(100), random(100)]} +set_bench! {intersection_random_100_vs_10k, intersection, count, [random(100), random(10_000)]} +set_bench! {intersection_random_10k_vs_100, intersection, count, [random(10_000), random(100)]} +set_bench! {intersection_random_10k_vs_10k, intersection, count, [random(10_000), random(10_000)]} +set_bench! {intersection_staggered_100_vs_100, intersection, count, stagger(100, 1)} +set_bench! {intersection_staggered_10k_vs_10k, intersection, count, stagger(10_000, 1)} +set_bench! {intersection_staggered_100_vs_10k, intersection, count, stagger(100, 100)} +set_bench! {difference_random_100_vs_100, difference, count, [random(100), random(100)]} +set_bench! {difference_random_100_vs_10k, difference, count, [random(100), random(10_000)]} +set_bench! {difference_random_10k_vs_100, difference, count, [random(10_000), random(100)]} +set_bench! {difference_random_10k_vs_10k, difference, count, [random(10_000), random(10_000)]} +set_bench! {difference_staggered_100_vs_100, difference, count, stagger(100, 1)} +set_bench! {difference_staggered_10k_vs_10k, difference, count, stagger(10_000, 1)} +set_bench! {difference_staggered_100_vs_10k, difference, count, stagger(100, 100)} +set_bench! {is_subset_100_vs_100, is_subset, clone, [pos(100), pos(100)]} +set_bench! {is_subset_100_vs_10k, is_subset, clone, [pos(100), pos(10_000)]} +set_bench! {is_subset_10k_vs_100, is_subset, clone, [pos(10_000), pos(100)]} +set_bench! {is_subset_10k_vs_10k, is_subset, clone, [pos(10_000), pos(10_000)]} diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index 74c80a08b12ab..d5e15b3719c2e 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -32,6 +32,7 @@ impl<'a, B: ?Sized> Borrow for Cow<'a, B> /// from any borrow of a given type. #[stable(feature = "rust1", since = "1.0.0")] pub trait ToOwned { + /// The resulting type after obtaining ownership. #[stable(feature = "rust1", since = "1.0.0")] type Owned: Borrow; @@ -135,7 +136,7 @@ impl ToOwned for T /// Another example showing how to keep `Cow` in a struct: /// /// ``` -/// use std::borrow::{Cow, ToOwned}; +/// use std::borrow::Cow; /// /// struct Items<'a, X: 'a> where [X]: ToOwned> { /// values: Cow<'a, [X]>, diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 74325a69e15ef..9109a730cce2d 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -4,16 +4,6 @@ //! heap allocation in Rust. Boxes provide ownership for this allocation, and //! drop their contents when they go out of scope. //! -//! For non-zero-sized values, a [`Box`] will use the [`Global`] allocator for -//! its allocation. It is valid to convert both ways between a [`Box`] and a -//! raw pointer allocated with the [`Global`] allocator, given that the -//! [`Layout`] used with the allocator is correct for the type. More precisely, -//! a `value: *mut T` that has been allocated with the [`Global`] allocator -//! with `Layout::for_value(&*value)` may be converted into a box using -//! `Box::::from_raw(value)`. Conversely, the memory backing a `value: *mut -//! T` obtained from `Box::::into_raw` may be deallocated using the -//! [`Global`] allocator with `Layout::for_value(&*value)`. -//! //! # Examples //! //! Move a value from the stack to the heap by creating a [`Box`]: @@ -61,8 +51,23 @@ //! for a `Cons`. By introducing a `Box`, which has a defined size, we know how //! big `Cons` needs to be. //! +//! # Memory layout +//! +//! For non-zero-sized values, a [`Box`] will use the [`Global`] allocator for +//! its allocation. It is valid to convert both ways between a [`Box`] and a +//! raw pointer allocated with the [`Global`] allocator, given that the +//! [`Layout`] used with the allocator is correct for the type. More precisely, +//! a `value: *mut T` that has been allocated with the [`Global`] allocator +//! with `Layout::for_value(&*value)` may be converted into a box using +//! `Box::::from_raw(value)`. Conversely, the memory backing a `value: *mut +//! T` obtained from `Box::::into_raw` may be deallocated using the +//! [`Global`] allocator with `Layout::for_value(&*value)`. +//! +//! //! [dereferencing]: ../../std/ops/trait.Deref.html //! [`Box`]: struct.Box.html +//! [`Global`]: ../alloc/struct.Global.html +//! [`Layout`]: ../alloc/struct.Layout.html #![stable(feature = "rust1", since = "1.0.0")] @@ -81,7 +86,7 @@ use core::ops::{ CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState }; use core::ptr::{self, NonNull, Unique}; -use core::task::{Waker, Poll}; +use core::task::{Context, Poll}; use crate::vec::Vec; use crate::raw_vec::RawVec; @@ -125,24 +130,38 @@ impl Box { /// /// After calling this function, the raw pointer is owned by the /// resulting `Box`. Specifically, the `Box` destructor will call - /// the destructor of `T` and free the allocated memory. Since the - /// way `Box` allocates and releases memory is unspecified, the - /// only valid pointer to pass to this function is the one taken - /// from another `Box` via the [`Box::into_raw`] function. + /// the destructor of `T` and free the allocated memory. For this + /// to be safe, the memory must have been allocated in accordance + /// with the [memory layout] used by `Box` . + /// + /// # Safety /// /// This function is unsafe because improper use may lead to /// memory problems. For example, a double-free may occur if the /// function is called twice on the same raw pointer. /// - /// [`Box::into_raw`]: struct.Box.html#method.into_raw - /// /// # Examples - /// + /// Recreate a `Box` which was previously converted to a raw pointer + /// using [`Box::into_raw`]: /// ``` /// let x = Box::new(5); /// let ptr = Box::into_raw(x); /// let x = unsafe { Box::from_raw(ptr) }; /// ``` + /// Manually create a `Box` from scratch by using the global allocator: + /// ``` + /// use std::alloc::{alloc, Layout}; + /// + /// unsafe { + /// let ptr = alloc(Layout::new::()) as *mut i32; + /// *ptr = 5; + /// let x = Box::from_raw(ptr); + /// } + /// ``` + /// + /// [memory layout]: index.html#memory-layout + /// [`Layout`]: ../alloc/struct.Layout.html + /// [`Box::into_raw`]: struct.Box.html#method.into_raw #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub unsafe fn from_raw(raw: *mut T) -> Self { @@ -155,22 +174,40 @@ impl Box { /// /// After calling this function, the caller is responsible for the /// memory previously managed by the `Box`. In particular, the - /// caller should properly destroy `T` and release the memory. The - /// proper way to do so is to convert the raw pointer back into a - /// `Box` with the [`Box::from_raw`] function. + /// caller should properly destroy `T` and release the memory, taking + /// into account the [memory layout] used by `Box`. The easiest way to + /// do this is to convert the raw pointer back into a `Box` with the + /// [`Box::from_raw`] function, allowing the `Box` destructor to perform + /// the cleanup. /// /// Note: this is an associated function, which means that you have /// to call it as `Box::into_raw(b)` instead of `b.into_raw()`. This /// is so that there is no conflict with a method on the inner type. /// - /// [`Box::from_raw`]: struct.Box.html#method.from_raw - /// /// # Examples - /// + /// Converting the raw pointer back into a `Box` with [`Box::from_raw`] + /// for automatic cleanup: /// ``` - /// let x = Box::new(5); + /// let x = Box::new(String::from("Hello")); /// let ptr = Box::into_raw(x); + /// let x = unsafe { Box::from_raw(ptr) }; + /// ``` + /// Manual cleanup by explicitly running the destructor and deallocating + /// the memory: /// ``` + /// use std::alloc::{dealloc, Layout}; + /// use std::ptr; + /// + /// let x = Box::new(String::from("Hello")); + /// let p = Box::into_raw(x); + /// unsafe { + /// ptr::drop_in_place(p); + /// dealloc(p as *mut u8, Layout::new::()); + /// } + /// ``` + /// + /// [memory layout]: index.html#memory-layout + /// [`Box::from_raw`]: struct.Box.html#method.from_raw #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub fn into_raw(b: Box) -> *mut T { @@ -182,7 +219,7 @@ impl Box { /// After calling this function, the caller is responsible for the /// memory previously managed by the `Box`. In particular, the /// caller should properly destroy `T` and release the memory. The - /// proper way to do so is to convert the `NonNull` pointer + /// easiest way to do so is to convert the `NonNull` pointer /// into a raw pointer and back into a `Box` with the [`Box::from_raw`] /// function. /// @@ -201,6 +238,10 @@ impl Box { /// fn main() { /// let x = Box::new(5); /// let ptr = Box::into_raw_non_null(x); + /// + /// // Clean up the memory by converting the NonNull pointer back + /// // into a Box and letting the Box be dropped. + /// let x = unsafe { Box::from_raw(ptr.as_ptr()) }; /// } /// ``` #[unstable(feature = "box_into_raw_non_null", issue = "47336")] @@ -212,15 +253,16 @@ impl Box { #[unstable(feature = "ptr_internals", issue = "0", reason = "use into_raw_non_null instead")] #[inline] #[doc(hidden)] - pub fn into_unique(mut b: Box) -> Unique { + pub fn into_unique(b: Box) -> Unique { + let mut unique = b.0; + mem::forget(b); // Box is kind-of a library type, but recognized as a "unique pointer" by // Stacked Borrows. This function here corresponds to "reborrowing to // a raw pointer", but there is no actual reborrow here -- so // without some care, the pointer we are returning here still carries - // the `Uniq` tag. We round-trip through a mutable reference to avoid that. - let unique = unsafe { b.0.as_mut() as *mut T }; - mem::forget(b); - unsafe { Unique::new_unchecked(unique) } + // the tag of `b`, with `Unique` permission. + // We round-trip through a mutable reference to avoid that. + unsafe { Unique::new_unchecked(unique.as_mut() as *mut T) } } /// Consumes and leaks the `Box`, returning a mutable reference, @@ -353,11 +395,10 @@ impl Clone for Box { #[stable(feature = "box_slice_clone", since = "1.3.0")] impl Clone for Box { fn clone(&self) -> Self { - let len = self.len(); - let buf = RawVec::with_capacity(len); + // this makes a copy of the data + let buf: Box<[u8]> = self.as_bytes().into(); unsafe { - ptr::copy_nonoverlapping(self.as_ptr(), buf.ptr(), len); - from_boxed_utf8_unchecked(buf.into_box()) + from_boxed_utf8_unchecked(buf) } } } @@ -489,7 +530,7 @@ impl From> for Pin> { } #[stable(feature = "box_from_slice", since = "1.17.0")] -impl<'a, T: Copy> From<&'a [T]> for Box<[T]> { +impl From<&[T]> for Box<[T]> { /// Converts a `&[T]` into a `Box<[T]>` /// /// This conversion allocates on the heap @@ -503,15 +544,18 @@ impl<'a, T: Copy> From<&'a [T]> for Box<[T]> { /// /// println!("{:?}", boxed_slice); /// ``` - fn from(slice: &'a [T]) -> Box<[T]> { - let mut boxed = unsafe { RawVec::with_capacity(slice.len()).into_box() }; - boxed.copy_from_slice(slice); - boxed + fn from(slice: &[T]) -> Box<[T]> { + let len = slice.len(); + let buf = RawVec::with_capacity(len); + unsafe { + ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len); + buf.into_box() + } } } #[stable(feature = "box_from_slice", since = "1.17.0")] -impl<'a> From<&'a str> for Box { +impl From<&str> for Box { /// Converts a `&str` into a `Box` /// /// This conversion allocates on the heap @@ -523,7 +567,7 @@ impl<'a> From<&'a str> for Box { /// println!("{}", boxed); /// ``` #[inline] - fn from(s: &'a str) -> Box { + fn from(s: &str) -> Box { unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) } } } @@ -677,6 +721,9 @@ impl DoubleEndedIterator for Box { fn next_back(&mut self) -> Option { (**self).next_back() } + fn nth_back(&mut self, n: usize) -> Option { + (**self).nth_back(n) + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Box { @@ -691,82 +738,26 @@ impl ExactSizeIterator for Box { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Box {} +#[stable(feature = "boxed_closure_impls", since = "1.35.0")] +impl + ?Sized> FnOnce for Box { + type Output = >::Output; -/// `FnBox` is a version of the `FnOnce` intended for use with boxed -/// closure objects. The idea is that where one would normally store a -/// `Box` in a data structure, you should use -/// `Box`. The two traits behave essentially the same, except -/// that a `FnBox` closure can only be called if it is boxed. (Note -/// that `FnBox` may be deprecated in the future if `Box` -/// closures become directly usable.) -/// -/// # Examples -/// -/// Here is a snippet of code which creates a hashmap full of boxed -/// once closures and then removes them one by one, calling each -/// closure as it is removed. Note that the type of the closures -/// stored in the map is `Box i32>` and not `Box i32>`. -/// -/// ``` -/// #![feature(fnbox)] -/// -/// use std::boxed::FnBox; -/// use std::collections::HashMap; -/// -/// fn make_map() -> HashMap i32>> { -/// let mut map: HashMap i32>> = HashMap::new(); -/// map.insert(1, Box::new(|| 22)); -/// map.insert(2, Box::new(|| 44)); -/// map -/// } -/// -/// fn main() { -/// let mut map = make_map(); -/// for i in &[1, 2] { -/// let f = map.remove(&i).unwrap(); -/// assert_eq!(f(), i * 22); -/// } -/// } -/// ``` -#[rustc_paren_sugar] -#[unstable(feature = "fnbox", - reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] -pub trait FnBox { - type Output; - - fn call_box(self: Box, args: A) -> Self::Output; -} - -#[unstable(feature = "fnbox", - reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] -impl FnBox for F - where F: FnOnce -{ - type Output = F::Output; - - fn call_box(self: Box, args: A) -> F::Output { - self.call_once(args) + extern "rust-call" fn call_once(self, args: A) -> Self::Output { + >::call_once(*self, args) } } -#[unstable(feature = "fnbox", - reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] -impl FnOnce for Box + '_> { - type Output = R; - - extern "rust-call" fn call_once(self, args: A) -> R { - self.call_box(args) +#[stable(feature = "boxed_closure_impls", since = "1.35.0")] +impl + ?Sized> FnMut for Box { + extern "rust-call" fn call_mut(&mut self, args: A) -> Self::Output { + >::call_mut(self, args) } } -#[unstable(feature = "fnbox", - reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] -impl FnOnce for Box + Send + '_> { - type Output = R; - - extern "rust-call" fn call_once(self, args: A) -> R { - self.call_box(args) +#[stable(feature = "boxed_closure_impls", since = "1.35.0")] +impl + ?Sized> Fn for Box { + extern "rust-call" fn call(&self, args: A) -> Self::Output { + >::call(self, args) } } @@ -907,11 +898,11 @@ impl Generator for Pin> { } } -#[unstable(feature = "futures_api", issue = "50547")] +#[stable(feature = "futures_api", since = "1.36.0")] impl Future for Box { type Output = F::Output; - fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll { - F::poll(Pin::new(&mut *self), waker) + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + F::poll(Pin::new(&mut *self), cx) } } diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index a171f128c24d6..c898f064fd09f 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -207,6 +207,44 @@ use super::SpecExtend; /// // The heap should now be empty. /// assert!(heap.is_empty()) /// ``` +/// +/// ## Min-heap +/// +/// Either `std::cmp::Reverse` or a custom `Ord` implementation can be used to +/// make `BinaryHeap` a min-heap. This makes `heap.pop()` return the smallest +/// value instead of the greatest one. +/// +/// ``` +/// use std::collections::BinaryHeap; +/// use std::cmp::Reverse; +/// +/// let mut heap = BinaryHeap::new(); +/// +/// // Wrap values in `Reverse` +/// heap.push(Reverse(1)); +/// heap.push(Reverse(5)); +/// heap.push(Reverse(2)); +/// +/// // If we pop these scores now, they should come back in the reverse order. +/// assert_eq!(heap.pop(), Some(Reverse(1))); +/// assert_eq!(heap.pop(), Some(Reverse(2))); +/// assert_eq!(heap.pop(), Some(Reverse(5))); +/// assert_eq!(heap.pop(), None); +/// ``` +/// +/// # Time complexity +/// +/// | [push] | [pop] | [peek]/[peek\_mut] | +/// |--------|----------|--------------------| +/// | O(1)~ | O(log n) | O(1) | +/// +/// The value for `push` is an expected cost; the method documentation gives a +/// more detailed analysis. +/// +/// [push]: #method.push +/// [pop]: #method.pop +/// [peek]: #method.peek +/// [peek\_mut]: #method.peek_mut #[stable(feature = "rust1", since = "1.0.0")] pub struct BinaryHeap { data: Vec, @@ -360,6 +398,10 @@ impl BinaryHeap { /// } /// assert_eq!(heap.peek(), Some(&2)); /// ``` + /// + /// # Time complexity + /// + /// Cost is O(1) in the worst case. #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub fn peek_mut(&mut self) -> Option> { if self.is_empty() { @@ -387,6 +429,11 @@ impl BinaryHeap { /// assert_eq!(heap.pop(), Some(1)); /// assert_eq!(heap.pop(), None); /// ``` + /// + /// # Time complexity + /// + /// The worst case cost of `pop` on a heap containing *n* elements is O(log + /// n). #[stable(feature = "rust1", since = "1.0.0")] pub fn pop(&mut self) -> Option { self.data.pop().map(|mut item| { @@ -414,6 +461,22 @@ impl BinaryHeap { /// assert_eq!(heap.len(), 3); /// assert_eq!(heap.peek(), Some(&5)); /// ``` + /// + /// # Time complexity + /// + /// The expected cost of `push`, averaged over every possible ordering of + /// the elements being pushed, and over a sufficiently large number of + /// pushes, is O(1). This is the most meaningful cost metric when pushing + /// elements that are *not* already in any sorted pattern. + /// + /// The time complexity degrades if elements are pushed in predominantly + /// ascending order. In the worst case, elements are pushed in ascending + /// sorted order and the amortized cost per push is O(log n) against a heap + /// containing *n* elements. + /// + /// The worst case cost of a *single* call to `push` is O(n). The worst case + /// occurs when capacity is exhausted and needs a resize. The resize cost + /// has been amortized in the previous figures. #[stable(feature = "rust1", since = "1.0.0")] pub fn push(&mut self, item: T) { let old_len = self.len(); @@ -626,6 +689,10 @@ impl BinaryHeap { /// assert_eq!(heap.peek(), Some(&5)); /// /// ``` + /// + /// # Time complexity + /// + /// Cost is O(1) in the worst case. #[stable(feature = "rust1", since = "1.0.0")] pub fn peek(&self) -> Option<&T> { self.data.get(0) @@ -1177,9 +1244,7 @@ impl BinaryHeap { self.reserve(lower); - for elem in iterator { - self.push(elem); - } + iterator.for_each(move |elem| self.push(elem)); } } diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index ce29978856ffd..6b079fc87cc78 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1727,9 +1727,9 @@ impl FromIterator<(K, V)> for BTreeMap { impl Extend<(K, V)> for BTreeMap { #[inline] fn extend>(&mut self, iter: T) { - for (k, v) in iter { + iter.into_iter().for_each(move |(k, v)| { self.insert(k, v); - } + }); } } diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index 66d619b1298b4..581c66c7086a5 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -109,7 +109,7 @@ impl LeafNode { keys: uninitialized_array![_; CAPACITY], vals: uninitialized_array![_; CAPACITY], parent: ptr::null(), - parent_idx: MaybeUninit::uninitialized(), + parent_idx: MaybeUninit::uninit(), len: 0 } } @@ -129,7 +129,7 @@ unsafe impl Sync for NodeHeader<(), ()> {} // ever take a pointer past the first key. static EMPTY_ROOT_NODE: NodeHeader<(), ()> = NodeHeader { parent: ptr::null(), - parent_idx: MaybeUninit::uninitialized(), + parent_idx: MaybeUninit::uninit(), len: 0, keys_start: [], }; @@ -261,7 +261,7 @@ impl Root { -> NodeRef, K, V, marker::Internal> { debug_assert!(!self.is_shared_root()); let mut new_node = Box::new(unsafe { InternalNode::new() }); - new_node.edges[0].set(unsafe { BoxedNode::from_ptr(self.node.as_ptr()) }); + new_node.edges[0].write(unsafe { BoxedNode::from_ptr(self.node.as_ptr()) }); self.node = BoxedNode::from_internal(new_node); self.height += 1; @@ -737,7 +737,7 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { unsafe { ptr::write(self.keys_mut().get_unchecked_mut(idx), key); ptr::write(self.vals_mut().get_unchecked_mut(idx), val); - self.as_internal_mut().edges.get_unchecked_mut(idx + 1).set(edge.node); + self.as_internal_mut().edges.get_unchecked_mut(idx + 1).write(edge.node); (*self.as_leaf_mut()).len += 1; @@ -1080,7 +1080,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: let mut child = self.descend(); unsafe { (*child.as_leaf_mut()).parent = ptr; - (*child.as_leaf_mut()).parent_idx.set(idx); + (*child.as_leaf_mut()).parent_idx.write(idx); } } diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index 2be6455ad5903..16a96ca19b824 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -3,7 +3,7 @@ use core::borrow::Borrow; use core::cmp::Ordering::{self, Less, Greater, Equal}; -use core::cmp::{min, max}; +use core::cmp::max; use core::fmt::{self, Debug}; use core::iter::{Peekable, FromIterator, FusedIterator}; use core::ops::{BitOr, BitAnd, BitXor, Sub, RangeBounds}; @@ -118,17 +118,36 @@ pub struct Range<'a, T: 'a> { /// [`difference`]: struct.BTreeSet.html#method.difference #[stable(feature = "rust1", since = "1.0.0")] pub struct Difference<'a, T: 'a> { - a: Peekable>, - b: Peekable>, + inner: DifferenceInner<'a, T>, +} +enum DifferenceInner<'a, T: 'a> { + Stitch { + self_iter: Iter<'a, T>, + other_iter: Peekable>, + }, + Search { + self_iter: Iter<'a, T>, + other_set: &'a BTreeSet, + }, } #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for Difference<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Difference") - .field(&self.a) - .field(&self.b) - .finish() + match &self.inner { + DifferenceInner::Stitch { + self_iter, + other_iter, + } => f + .debug_tuple("Difference") + .field(&self_iter) + .field(&other_iter) + .finish(), + DifferenceInner::Search { + self_iter, + other_set: _, + } => f.debug_tuple("Difference").field(&self_iter).finish(), + } } } @@ -164,17 +183,36 @@ impl fmt::Debug for SymmetricDifference<'_, T> { /// [`intersection`]: struct.BTreeSet.html#method.intersection #[stable(feature = "rust1", since = "1.0.0")] pub struct Intersection<'a, T: 'a> { - a: Peekable>, - b: Peekable>, + inner: IntersectionInner<'a, T>, +} +enum IntersectionInner<'a, T: 'a> { + Stitch { + small_iter: Iter<'a, T>, // for size_hint, should be the smaller of the sets + other_iter: Iter<'a, T>, + }, + Search { + small_iter: Iter<'a, T>, + large_set: &'a BTreeSet, + }, } #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for Intersection<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Intersection") - .field(&self.a) - .field(&self.b) - .finish() + match &self.inner { + IntersectionInner::Stitch { + small_iter, + other_iter, + } => f + .debug_tuple("Intersection") + .field(&small_iter) + .field(&other_iter) + .finish(), + IntersectionInner::Search { + small_iter, + large_set: _, + } => f.debug_tuple("Intersection").field(&small_iter).finish(), + } } } @@ -201,6 +239,14 @@ impl fmt::Debug for Union<'_, T> { } } +// This constant is used by functions that compare two sets. +// It estimates the relative size at which searching performs better +// than iterating, based on the benchmarks in +// https://github.com/ssomers/rust_bench_btreeset_intersection; +// It's used to divide rather than multiply sizes, to rule out overflow, +// and it's a power of two to make that division cheap. +const ITER_PERFORMANCE_TIPPING_SIZE_DIFF: usize = 16; + impl BTreeSet { /// Makes a new `BTreeSet` with a reasonable choice of B. /// @@ -268,9 +314,24 @@ impl BTreeSet { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn difference<'a>(&'a self, other: &'a BTreeSet) -> Difference<'a, T> { - Difference { - a: self.iter().peekable(), - b: other.iter().peekable(), + if self.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + // Self is bigger than or not much smaller than other set. + // Iterate both sets jointly, spotting matches along the way. + Difference { + inner: DifferenceInner::Stitch { + self_iter: self.iter(), + other_iter: other.iter().peekable(), + }, + } + } else { + // Self is much smaller than other set, or both sets are empty. + // Iterate the small set, searching for matches in the large set. + Difference { + inner: DifferenceInner::Search { + self_iter: self.iter(), + other_set: other, + }, + } } } @@ -326,9 +387,29 @@ impl BTreeSet { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn intersection<'a>(&'a self, other: &'a BTreeSet) -> Intersection<'a, T> { - Intersection { - a: self.iter().peekable(), - b: other.iter().peekable(), + let (small, other) = if self.len() <= other.len() { + (self, other) + } else { + (other, self) + }; + if small.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + // Small set is not much smaller than other set. + // Iterate both sets jointly, spotting matches along the way. + Intersection { + inner: IntersectionInner::Stitch { + small_iter: small.iter(), + other_iter: other.iter(), + }, + } + } else { + // Big difference in number of elements, or both sets are empty. + // Iterate the small set, searching for matches in the large set. + Intersection { + inner: IntersectionInner::Search { + small_iter: small.iter(), + large_set: other, + }, + } } } @@ -462,28 +543,44 @@ impl BTreeSet { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_subset(&self, other: &BTreeSet) -> bool { - // Stolen from TreeMap - let mut x = self.iter(); - let mut y = other.iter(); - let mut a = x.next(); - let mut b = y.next(); - while a.is_some() { - if b.is_none() { - return false; - } + // Same result as self.difference(other).next().is_none() + // but the 3 paths below are faster (in order: hugely, 20%, 5%). + if self.len() > other.len() { + false + } else if self.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + // Self is not much smaller than other set. + // Stolen from TreeMap + let mut x = self.iter(); + let mut y = other.iter(); + let mut a = x.next(); + let mut b = y.next(); + while a.is_some() { + if b.is_none() { + return false; + } - let a1 = a.unwrap(); - let b1 = b.unwrap(); + let a1 = a.unwrap(); + let b1 = b.unwrap(); - match b1.cmp(a1) { - Less => (), - Greater => return false, - Equal => a = x.next(), - } + match b1.cmp(a1) { + Less => (), + Greater => return false, + Equal => a = x.next(), + } - b = y.next(); + b = y.next(); + } + true + } else { + // Big difference in number of elements, or both sets are empty. + // Iterate the small set, searching for matches in the large set. + for next in self { + if !other.contains(next) { + return false; + } + } + true } - true } /// Returns `true` if the set is a superset of another, @@ -786,9 +883,9 @@ impl<'a, T> IntoIterator for &'a BTreeSet { impl Extend for BTreeSet { #[inline] fn extend>(&mut self, iter: Iter) { - for elem in iter { + iter.into_iter().for_each(move |elem| { self.insert(elem); - } + }); } } @@ -1001,8 +1098,22 @@ fn cmp_opt(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering impl Clone for Difference<'_, T> { fn clone(&self) -> Self { Difference { - a: self.a.clone(), - b: self.b.clone(), + inner: match &self.inner { + DifferenceInner::Stitch { + self_iter, + other_iter, + } => DifferenceInner::Stitch { + self_iter: self_iter.clone(), + other_iter: other_iter.clone(), + }, + DifferenceInner::Search { + self_iter, + other_set, + } => DifferenceInner::Search { + self_iter: self_iter.clone(), + other_set, + }, + }, } } } @@ -1011,24 +1122,52 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { - loop { - match cmp_opt(self.a.peek(), self.b.peek(), Less, Less) { - Less => return self.a.next(), - Equal => { - self.a.next(); - self.b.next(); - } - Greater => { - self.b.next(); + match &mut self.inner { + DifferenceInner::Stitch { + self_iter, + other_iter, + } => { + let mut self_next = self_iter.next()?; + loop { + match other_iter + .peek() + .map_or(Less, |other_next| Ord::cmp(self_next, other_next)) + { + Less => return Some(self_next), + Equal => { + self_next = self_iter.next()?; + other_iter.next(); + } + Greater => { + other_iter.next(); + } + } } } + DifferenceInner::Search { + self_iter, + other_set, + } => loop { + let self_next = self_iter.next()?; + if !other_set.contains(&self_next) { + return Some(self_next); + } + }, } } fn size_hint(&self) -> (usize, Option) { - let a_len = self.a.len(); - let b_len = self.b.len(); - (a_len.saturating_sub(b_len), Some(a_len)) + let (self_len, other_len) = match &self.inner { + DifferenceInner::Stitch { + self_iter, + other_iter + } => (self_iter.len(), other_iter.len()), + DifferenceInner::Search { + self_iter, + other_set + } => (self_iter.len(), other_set.len()), + }; + (self_len.saturating_sub(other_len), Some(self_len)) } } @@ -1073,8 +1212,22 @@ impl FusedIterator for SymmetricDifference<'_, T> {} impl Clone for Intersection<'_, T> { fn clone(&self) -> Self { Intersection { - a: self.a.clone(), - b: self.b.clone(), + inner: match &self.inner { + IntersectionInner::Stitch { + small_iter, + other_iter, + } => IntersectionInner::Stitch { + small_iter: small_iter.clone(), + other_iter: other_iter.clone(), + }, + IntersectionInner::Search { + small_iter, + large_set, + } => IntersectionInner::Search { + small_iter: small_iter.clone(), + large_set, + }, + }, } } } @@ -1083,24 +1236,39 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { - loop { - match Ord::cmp(self.a.peek()?, self.b.peek()?) { - Less => { - self.a.next(); - } - Equal => { - self.b.next(); - return self.a.next(); - } - Greater => { - self.b.next(); + match &mut self.inner { + IntersectionInner::Stitch { + small_iter, + other_iter, + } => { + let mut small_next = small_iter.next()?; + let mut other_next = other_iter.next()?; + loop { + match Ord::cmp(small_next, other_next) { + Less => small_next = small_iter.next()?, + Greater => other_next = other_iter.next()?, + Equal => return Some(small_next), + } } } + IntersectionInner::Search { + small_iter, + large_set, + } => loop { + let small_next = small_iter.next()?; + if large_set.contains(&small_next) { + return Some(small_next); + } + }, } } fn size_hint(&self) -> (usize, Option) { - (0, Some(min(self.a.len(), self.b.len()))) + let min_len = match &self.inner { + IntersectionInner::Stitch { small_iter, .. } => small_iter.len(), + IntersectionInner::Search { small_iter, .. } => small_iter.len(), + }; + (0, Some(min_len)) } } diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index c2ee2e63156cf..40a82d6feaa98 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -86,6 +86,9 @@ impl Clone for Iter<'_, T> { /// [`LinkedList`]: struct.LinkedList.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { + // We do *not* exclusively own the entire list here, references to node's `element` + // have been handed out by the iterator! So be careful when using this; the methods + // called must be aware that there can be aliasing pointers to `element`. list: &'a mut LinkedList, head: Option>>, tail: Option>>, @@ -143,6 +146,8 @@ impl LinkedList { /// Adds the given node to the front of the list. #[inline] fn push_front_node(&mut self, mut node: Box>) { + // This method takes care not to create mutable references to whole nodes, + // to maintain validity of aliasing pointers into `element`. unsafe { node.next = self.head; node.prev = None; @@ -150,7 +155,8 @@ impl LinkedList { match self.head { None => self.tail = node, - Some(mut head) => head.as_mut().prev = node, + // Not creating new mutable (unique!) references overlapping `element`. + Some(head) => (*head.as_ptr()).prev = node, } self.head = node; @@ -161,13 +167,16 @@ impl LinkedList { /// Removes and returns the node at the front of the list. #[inline] fn pop_front_node(&mut self) -> Option>> { + // This method takes care not to create mutable references to whole nodes, + // to maintain validity of aliasing pointers into `element`. self.head.map(|node| unsafe { let node = Box::from_raw(node.as_ptr()); self.head = node.next; match self.head { None => self.tail = None, - Some(mut head) => head.as_mut().prev = None, + // Not creating new mutable (unique!) references overlapping `element`. + Some(head) => (*head.as_ptr()).prev = None, } self.len -= 1; @@ -178,6 +187,8 @@ impl LinkedList { /// Adds the given node to the back of the list. #[inline] fn push_back_node(&mut self, mut node: Box>) { + // This method takes care not to create mutable references to whole nodes, + // to maintain validity of aliasing pointers into `element`. unsafe { node.next = None; node.prev = self.tail; @@ -185,7 +196,8 @@ impl LinkedList { match self.tail { None => self.head = node, - Some(mut tail) => tail.as_mut().next = node, + // Not creating new mutable (unique!) references overlapping `element`. + Some(tail) => (*tail.as_ptr()).next = node, } self.tail = node; @@ -196,13 +208,16 @@ impl LinkedList { /// Removes and returns the node at the back of the list. #[inline] fn pop_back_node(&mut self) -> Option>> { + // This method takes care not to create mutable references to whole nodes, + // to maintain validity of aliasing pointers into `element`. self.tail.map(|node| unsafe { let node = Box::from_raw(node.as_ptr()); self.tail = node.prev; match self.tail { None => self.head = None, - Some(mut tail) => tail.as_mut().next = None, + // Not creating new mutable (unique!) references overlapping `element`. + Some(tail) => (*tail.as_ptr()).next = None, } self.len -= 1; @@ -213,18 +228,22 @@ impl LinkedList { /// Unlinks the specified node from the current list. /// /// Warning: this will not check that the provided node belongs to the current list. + /// + /// This method takes care not to create mutable references to `element`, to + /// maintain validity of aliasing pointers. #[inline] unsafe fn unlink_node(&mut self, mut node: NonNull>) { - let node = node.as_mut(); + let node = node.as_mut(); // this one is ours now, we can create an &mut. + // Not creating new mutable (unique!) references overlapping `element`. match node.prev { - Some(mut prev) => prev.as_mut().next = node.next.clone(), + Some(prev) => (*prev.as_ptr()).next = node.next.clone(), // this node is the head node None => self.head = node.next.clone(), }; match node.next { - Some(mut next) => next.as_mut().prev = node.prev.clone(), + Some(next) => (*next.as_ptr()).prev = node.prev.clone(), // this node is the tail node None => self.tail = node.prev.clone(), }; @@ -297,6 +316,8 @@ impl LinkedList { match self.tail { None => mem::swap(self, other), Some(mut tail) => { + // `as_mut` is okay here because we have exclusive access to the entirety + // of both lists. if let Some(mut other_head) = other.head.take() { unsafe { tail.as_mut().next = Some(other_head); @@ -916,9 +937,11 @@ impl IterMut<'_, T> { issue = "27794")] pub fn insert_next(&mut self, element: T) { match self.head { + // `push_back` is okay with aliasing `element` references None => self.list.push_back(element), - Some(mut head) => unsafe { - let mut prev = match head.as_ref().prev { + Some(head) => unsafe { + let prev = match head.as_ref().prev { + // `push_front` is okay with aliasing nodes None => return self.list.push_front(element), Some(prev) => prev, }; @@ -929,8 +952,10 @@ impl IterMut<'_, T> { element, })); - prev.as_mut().next = node; - head.as_mut().prev = node; + // Not creating references to entire nodes to not invalidate the + // reference to `element` we handed to the user. + (*prev.as_ptr()).next = node; + (*head.as_ptr()).prev = node; self.list.len += 1; }, @@ -994,6 +1019,7 @@ impl Iterator for DrainFilter<'_, T, F> self.idx += 1; if (self.pred)(&mut node.as_mut().element) { + // `unlink_node` is okay with aliasing `element` references. self.list.unlink_node(node); return Some(Box::from_raw(node.as_ptr()).element); } @@ -1107,9 +1133,7 @@ impl Extend for LinkedList { impl SpecExtend for LinkedList { default fn spec_extend(&mut self, iter: I) { - for elt in iter { - self.push_back(elt); - } + iter.into_iter().for_each(move |elt| self.push_back(elt)); } } @@ -1356,6 +1380,7 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] + #[cfg(not(miri))] // Miri does not support threads fn test_send() { let n = list_from(&[1, 2, 3]); thread::spawn(move || { @@ -1373,6 +1398,7 @@ mod tests { for _ in 0..25 { fuzz_test(3); fuzz_test(16); + #[cfg(not(miri))] // Miri is too slow fuzz_test(189); } } diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 4e90f783ec6a5..71faf672962b3 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + //! A double-ended queue implemented with a growable ring buffer. //! //! This queue has `O(1)` amortized inserts and removals from both ends of the @@ -367,7 +369,7 @@ impl VecDeque { VecDeque::with_capacity(INITIAL_CAPACITY) } - /// Creates an empty `VecDeque` with space for at least `n` elements. + /// Creates an empty `VecDeque` with space for at least `capacity` elements. /// /// # Examples /// @@ -377,10 +379,10 @@ impl VecDeque { /// let vector: VecDeque = VecDeque::with_capacity(10); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(n: usize) -> VecDeque { + pub fn with_capacity(capacity: usize) -> VecDeque { // +1 since the ringbuffer always leaves one space empty - let cap = cmp::max(n + 1, MINIMUM_CAPACITY + 1).next_power_of_two(); - assert!(cap > n, "capacity overflow"); + let cap = cmp::max(capacity + 1, MINIMUM_CAPACITY + 1).next_power_of_two(); + assert!(cap > capacity, "capacity overflow"); VecDeque { tail: 0, @@ -1833,8 +1835,8 @@ impl VecDeque { /// Retains only the elements specified by the predicate. /// /// In other words, remove all elements `e` such that `f(&e)` returns false. - /// This method operates in place and preserves the order of the retained - /// elements. + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. /// /// # Examples /// @@ -1846,6 +1848,20 @@ impl VecDeque { /// buf.retain(|&x| x%2 == 0); /// assert_eq!(buf, [2, 4]); /// ``` + /// + /// The exact order may be useful for tracking external state, like an index. + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.extend(1..6); + /// + /// let keep = [false, true, true, false, true]; + /// let mut i = 0; + /// buf.retain(|_| (keep[i], i += 1).0); + /// assert_eq!(buf, [2, 3, 5]); + /// ``` #[stable(feature = "vec_deque_retain", since = "1.4.0")] pub fn retain(&mut self, mut f: F) where F: FnMut(&T) -> bool @@ -1932,8 +1948,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(vecdeque_rotate)] - /// /// use std::collections::VecDeque; /// /// let mut buf: VecDeque<_> = (0..10).collect(); @@ -1947,7 +1961,7 @@ impl VecDeque { /// } /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); /// ``` - #[unstable(feature = "vecdeque_rotate", issue = "56686")] + #[stable(feature = "vecdeque_rotate", since = "1.36.0")] pub fn rotate_left(&mut self, mid: usize) { assert!(mid <= self.len()); let k = self.len() - mid; @@ -1977,8 +1991,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(vecdeque_rotate)] - /// /// use std::collections::VecDeque; /// /// let mut buf: VecDeque<_> = (0..10).collect(); @@ -1992,7 +2004,7 @@ impl VecDeque { /// } /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); /// ``` - #[unstable(feature = "vecdeque_rotate", issue = "56686")] + #[stable(feature = "vecdeque_rotate", since = "1.36.0")] pub fn rotate_right(&mut self, k: usize) { assert!(k <= self.len()); let mid = self.len() - k; @@ -2677,9 +2689,7 @@ impl<'a, T> IntoIterator for &'a mut VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl Extend for VecDeque { fn extend>(&mut self, iter: T) { - for elt in iter { - self.push_back(elt); - } + iter.into_iter().for_each(move |elt| self.push_back(elt)); } } @@ -2699,6 +2709,11 @@ impl fmt::Debug for VecDeque { #[stable(feature = "vecdeque_vec_conversions", since = "1.10.0")] impl From> for VecDeque { + /// Turn a [`Vec`] into a [`VecDeque`]. + /// + /// This avoids reallocating where possible, but the conditions for that are + /// strict, and subject to change, and so shouldn't be relied upon unless the + /// `Vec` came from `From>` and hasn't been reallocated. fn from(mut other: Vec) -> Self { unsafe { let other_buf = other.as_mut_ptr(); @@ -2725,6 +2740,32 @@ impl From> for VecDeque { #[stable(feature = "vecdeque_vec_conversions", since = "1.10.0")] impl From> for Vec { + /// Turn a [`VecDeque`] into a [`Vec`]. + /// + /// This never needs to re-allocate, but does need to do O(n) data movement if + /// the circular buffer doesn't happen to be at the beginning of the allocation. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// // This one is O(1). + /// let deque: VecDeque<_> = (1..5).collect(); + /// let ptr = deque.as_slices().0.as_ptr(); + /// let vec = Vec::from(deque); + /// assert_eq!(vec, [1, 2, 3, 4]); + /// assert_eq!(vec.as_ptr(), ptr); + /// + /// // This one needs data rearranging. + /// let mut deque: VecDeque<_> = (1..5).collect(); + /// deque.push_front(9); + /// deque.push_front(8); + /// let ptr = deque.as_slices().1.as_ptr(); + /// let vec = Vec::from(deque); + /// assert_eq!(vec, [8, 9, 1, 2, 3, 4]); + /// assert_eq!(vec.as_ptr(), ptr); + /// ``` fn from(other: VecDeque) -> Self { unsafe { let buf = other.buf.ptr(); @@ -2801,6 +2842,7 @@ mod tests { use super::VecDeque; #[bench] + #[cfg(not(miri))] // Miri does not support benchmarks fn bench_push_back_100(b: &mut test::Bencher) { let mut deq = VecDeque::with_capacity(101); b.iter(|| { @@ -2813,6 +2855,7 @@ mod tests { } #[bench] + #[cfg(not(miri))] // Miri does not support benchmarks fn bench_push_front_100(b: &mut test::Bencher) { let mut deq = VecDeque::with_capacity(101); b.iter(|| { @@ -2825,6 +2868,7 @@ mod tests { } #[bench] + #[cfg(not(miri))] // Miri does not support benchmarks fn bench_pop_back_100(b: &mut test::Bencher) { let mut deq = VecDeque::::with_capacity(101); @@ -2838,6 +2882,7 @@ mod tests { } #[bench] + #[cfg(not(miri))] // Miri does not support benchmarks fn bench_pop_front_100(b: &mut test::Bencher) { let mut deq = VecDeque::::with_capacity(101); @@ -3105,7 +3150,12 @@ mod tests { assert!(vec.into_iter().eq(vd)); } - for cap_pwr in 0..7 { + #[cfg(not(miri))] // Miri is too slow + let max_pwr = 7; + #[cfg(miri)] + let max_pwr = 5; + + for cap_pwr in 0..max_pwr { // Make capacity as a (2^x)-1, so that the ring size is 2^x let cap = (2i32.pow(cap_pwr) - 1) as usize; diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs index d2ba9b001916c..68cbc366d7bc2 100644 --- a/src/liballoc/fmt.rs +++ b/src/liballoc/fmt.rs @@ -343,9 +343,10 @@ //! * `^` - the argument is center-aligned in `width` columns //! * `>` - the argument is right-aligned in `width` columns //! -//! Note that alignment may not be implemented by some types. A good way -//! to ensure padding is applied is to format your input, then use this -//! resulting string to pad your output. +//! Note that alignment may not be implemented by some types. In particular, it +//! is not generally implemented for the `Debug` trait. A good way to ensure +//! padding is applied is to format your input, then use this resulting string +//! to pad your output. //! //! ## Sign/`#`/`0` //! diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 440ce8ac5e842..5fc58c8ab5a7b 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -51,22 +51,20 @@ //! default global allocator. It is not compatible with the libc allocator API. #![allow(unused_attributes)] -#![unstable(feature = "alloc", - reason = "this library is unlikely to be stabilized in its current \ - form or name", - issue = "27783")] +#![stable(feature = "alloc", since = "1.36.0")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] #![no_std] #![needs_allocator] -#![deny(rust_2018_idioms)] -#![allow(explicit_outlives_requirements)] - #![warn(deprecated_in_future)] -#![warn(intra_doc_link_resolution_failure)] +#![warn(missing_docs)] #![warn(missing_debug_implementations)] +#![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings + +#![deny(rust_2018_idioms)] +#![allow(explicit_outlives_requirements)] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(test))] @@ -81,16 +79,14 @@ #![feature(coerce_unsized)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] -#![feature(custom_attribute)] +#![cfg_attr(bootstrap, feature(custom_attribute))] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(fundamental)] -#![feature(futures_api)] #![feature(lang_items)] #![feature(libc)] -#![feature(needs_allocator)] #![feature(nll)] #![feature(optin_builtin_traits)] #![feature(pattern)] @@ -107,12 +103,13 @@ #![feature(unboxed_closures)] #![feature(unicode_internals)] #![feature(unsize)] +#![feature(unsized_locals)] #![feature(allocator_internals)] #![feature(on_unimplemented)] #![feature(rustc_const_unstable)] #![feature(const_vec_new)] #![feature(slice_partition_dedup)] -#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)] +#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_array)] #![feature(alloc_layout_extra)] #![feature(try_trait)] @@ -144,7 +141,7 @@ mod boxed { pub use std::boxed::Box; } #[cfg(test)] -mod boxed_test; +mod tests; pub mod collections; #[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))] pub mod sync; diff --git a/src/liballoc/macros.rs b/src/liballoc/macros.rs index eb3410078513d..250c419c531f8 100644 --- a/src/liballoc/macros.rs +++ b/src/liballoc/macros.rs @@ -34,8 +34,7 @@ #[cfg(not(test))] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(stage0), allow_internal_unstable(box_syntax))] -#[cfg_attr(stage0, allow_internal_unstable)] +#[allow_internal_unstable(box_syntax)] macro_rules! vec { ($elem:expr; $n:expr) => ( $crate::vec::from_elem($elem, $n) @@ -43,7 +42,7 @@ macro_rules! vec { ($($x:expr),*) => ( <[_]>::into_vec(box [$($x),*]) ); - ($($x:expr,)*) => (vec![$($x),*]) + ($($x:expr,)*) => ($crate::vec![$($x),*]) } // HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is diff --git a/src/liballoc/prelude.rs b/src/liballoc/prelude.rs deleted file mode 100644 index 6767cf89f73ba..0000000000000 --- a/src/liballoc/prelude.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! The alloc Prelude -//! -//! The purpose of this module is to alleviate imports of commonly-used -//! items of the `alloc` crate by adding a glob import to the top of modules: -//! -//! ``` -//! # #![allow(unused_imports)] -//! # #![feature(alloc)] -//! extern crate alloc; -//! use alloc::prelude::*; -//! ``` - -#![unstable(feature = "alloc", issue = "27783")] - -#[unstable(feature = "alloc", issue = "27783")] pub use crate::borrow::ToOwned; -#[unstable(feature = "alloc", issue = "27783")] pub use crate::boxed::Box; -#[unstable(feature = "alloc", issue = "27783")] pub use crate::slice::SliceConcatExt; -#[unstable(feature = "alloc", issue = "27783")] pub use crate::string::{String, ToString}; -#[unstable(feature = "alloc", issue = "27783")] pub use crate::vec::Vec; diff --git a/src/liballoc/prelude/mod.rs b/src/liballoc/prelude/mod.rs new file mode 100644 index 0000000000000..0534ad3edc79d --- /dev/null +++ b/src/liballoc/prelude/mod.rs @@ -0,0 +1,15 @@ +//! The alloc Prelude +//! +//! The purpose of this module is to alleviate imports of commonly-used +//! items of the `alloc` crate by adding a glob import to the top of modules: +//! +//! ``` +//! # #![allow(unused_imports)] +//! #![feature(alloc_prelude)] +//! extern crate alloc; +//! use alloc::prelude::v1::*; +//! ``` + +#![unstable(feature = "alloc_prelude", issue = "58935")] + +pub mod v1; diff --git a/src/liballoc/prelude/v1.rs b/src/liballoc/prelude/v1.rs new file mode 100644 index 0000000000000..b6b01395ad632 --- /dev/null +++ b/src/liballoc/prelude/v1.rs @@ -0,0 +1,11 @@ +//! The first version of the prelude of `alloc` crate. +//! +//! See the [module-level documentation](../index.html) for more. + +#![unstable(feature = "alloc_prelude", issue = "58935")] + +#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::borrow::ToOwned; +#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::boxed::Box; +#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::slice::SliceConcatExt; +#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::string::{String, ToString}; +#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::vec::Vec; diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index fe28fe5095cce..0454a56443579 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -256,7 +256,7 @@ impl RawVec { /// # Examples /// /// ``` - /// # #![feature(alloc, raw_vec_internals)] + /// # #![feature(raw_vec_internals)] /// # extern crate alloc; /// # use std::ptr; /// # use alloc::raw_vec::RawVec; @@ -460,7 +460,7 @@ impl RawVec { /// # Examples /// /// ``` - /// # #![feature(alloc, raw_vec_internals)] + /// # #![feature(raw_vec_internals)] /// # extern crate alloc; /// # use std::ptr; /// # use alloc::raw_vec::RawVec; @@ -685,12 +685,14 @@ impl RawVec { impl RawVec { /// Converts the entire buffer into `Box<[T]>`. /// - /// While it is not *strictly* Undefined Behavior to call - /// this procedure while some of the RawVec is uninitialized, - /// it certainly makes it trivial to trigger it. - /// /// Note that this will correctly reconstitute any `cap` changes /// that may have been performed. (see description of type for details) + /// + /// # Undefined Behavior + /// + /// All elements of `RawVec` must be initialized. Notice that + /// the rules around uninitialized boxed values are not finalized yet, + /// but until they are, it is advisable to avoid them. pub unsafe fn into_box(self) -> Box<[T]> { // NOTE: not calling `cap()` here, actually using the real `cap` field! let slice = slice::from_raw_parts_mut(self.ptr(), self.cap); diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 12f75d84211e6..ee78839f7f003 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -239,7 +239,7 @@ use core::fmt; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; use core::marker::{self, Unpin, Unsize, PhantomData}; -use core::mem::{self, align_of_val, forget, size_of_val}; +use core::mem::{self, align_of, align_of_val, forget, size_of_val}; use core::ops::{Deref, Receiver, CoerceUnsized, DispatchFromDyn}; use core::pin::Pin; use core::ptr::{self, NonNull}; @@ -375,9 +375,9 @@ impl Rc { /// ``` /// use std::rc::Rc; /// - /// let x = Rc::new(10); + /// let x = Rc::new("hello".to_owned()); /// let x_ptr = Rc::into_raw(x); - /// assert_eq!(unsafe { *x_ptr }, 10); + /// assert_eq!(unsafe { &*x_ptr }, "hello"); /// ``` #[stable(feature = "rc_raw", since = "1.17.0")] pub fn into_raw(this: Self) -> *const T { @@ -401,13 +401,13 @@ impl Rc { /// ``` /// use std::rc::Rc; /// - /// let x = Rc::new(10); + /// let x = Rc::new("hello".to_owned()); /// let x_ptr = Rc::into_raw(x); /// /// unsafe { /// // Convert back to an `Rc` to prevent leak. /// let x = Rc::from_raw(x_ptr); - /// assert_eq!(*x, 10); + /// assert_eq!(&*x, "hello"); /// /// // Further calls to `Rc::from_raw(x_ptr)` would be memory unsafe. /// } @@ -416,11 +416,7 @@ impl Rc { /// ``` #[stable(feature = "rc_raw", since = "1.17.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { - // Align the unsized value to the end of the RcBox. - // Because it is ?Sized, it will always be the last field in memory. - let align = align_of_val(&*ptr); - let layout = Layout::new::>(); - let offset = (layout.size() + layout.padding_needed_for(align)) as isize; + let offset = data_offset(ptr); // Reverse the offset to find the original RcBox. let fake_ptr = ptr as *mut RcBox; @@ -441,10 +437,10 @@ impl Rc { /// /// use std::rc::Rc; /// - /// let x = Rc::new(10); + /// let x = Rc::new("hello".to_owned()); /// let ptr = Rc::into_raw_non_null(x); - /// let deref = unsafe { *ptr.as_ref() }; - /// assert_eq!(deref, 10); + /// let deref = unsafe { ptr.as_ref() }; + /// assert_eq!(deref, "hello"); /// ``` #[unstable(feature = "rc_into_raw_non_null", issue = "47336")] #[inline] @@ -584,15 +580,18 @@ impl Rc { impl Rc { /// Makes a mutable reference into the given `Rc`. /// - /// If there are other `Rc` or [`Weak`][weak] pointers to the same value, - /// then `make_mut` will invoke [`clone`][clone] on the inner value to - /// ensure unique ownership. This is also referred to as clone-on-write. + /// If there are other `Rc` pointers to the same value, then `make_mut` will + /// [`clone`] the inner value to ensure unique ownership. This is also + /// referred to as clone-on-write. /// - /// See also [`get_mut`][get_mut], which will fail rather than cloning. + /// If there are no other `Rc` pointers to this value, then [`Weak`] + /// pointers to this value will be dissassociated. /// - /// [weak]: struct.Weak.html - /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone - /// [get_mut]: struct.Rc.html#method.get_mut + /// See also [`get_mut`], which will fail rather than cloning. + /// + /// [`Weak`]: struct.Weak.html + /// [`clone`]: ../../std/clone/trait.Clone.html#tymethod.clone + /// [`get_mut`]: struct.Rc.html#method.get_mut /// /// # Examples /// @@ -611,6 +610,23 @@ impl Rc { /// assert_eq!(*data, 8); /// assert_eq!(*other_data, 12); /// ``` + /// + /// [`Weak`] pointers will be dissassociated: + /// + /// ``` + /// use std::rc::Rc; + /// + /// let mut data = Rc::new(75); + /// let weak = Rc::downgrade(&data); + /// + /// assert!(75 == *data); + /// assert!(75 == *weak.upgrade().unwrap()); + /// + /// *Rc::make_mut(&mut data) += 1; + /// + /// assert!(76 == *data); + /// assert!(weak.upgrade().is_none()); + /// ``` #[inline] #[stable(feature = "rc_unique", since = "1.4.0")] pub fn make_mut(this: &mut Self) -> &mut T { @@ -932,6 +948,11 @@ impl RcEqIdent for Rc { } } +/// We're doing this specialization here, and not as a more general optimization on `&T`, because it +/// would otherwise add a cost to all equality checks on refs. We assume that `Rc`s are used to +/// store large values, that are slow to clone, but also heavy to check for equality, causing this +/// cost to pay off more easily. It's also more likely to have two `Rc` clones, that point to +/// the same value, than two `&T`s. #[stable(feature = "rust1", since = "1.0.0")] impl RcEqIdent for Rc { #[inline] @@ -1145,7 +1166,7 @@ impl From for Rc { } #[stable(feature = "shared_from_slice", since = "1.21.0")] -impl<'a, T: Clone> From<&'a [T]> for Rc<[T]> { +impl From<&[T]> for Rc<[T]> { #[inline] fn from(v: &[T]) -> Rc<[T]> { >::from_slice(v) @@ -1153,7 +1174,7 @@ impl<'a, T: Clone> From<&'a [T]> for Rc<[T]> { } #[stable(feature = "shared_from_slice", since = "1.21.0")] -impl<'a> From<&'a str> for Rc { +impl From<&str> for Rc { #[inline] fn from(v: &str) -> Rc { let rc = Rc::<[u8]>::from(v.as_bytes()); @@ -1257,6 +1278,143 @@ impl Weak { ptr: NonNull::new(usize::MAX as *mut RcBox).expect("MAX is not 0"), } } + + /// Returns a raw pointer to the object `T` pointed to by this `Weak`. + /// + /// It is up to the caller to ensure that the object is still alive when accessing it through + /// the pointer. + /// + /// The pointer may be [`null`] or be dangling in case the object has already been destroyed. + /// + /// # Examples + /// + /// ``` + /// #![feature(weak_into_raw)] + /// + /// use std::rc::{Rc, Weak}; + /// use std::ptr; + /// + /// let strong = Rc::new("hello".to_owned()); + /// let weak = Rc::downgrade(&strong); + /// // Both point to the same object + /// assert!(ptr::eq(&*strong, Weak::as_raw(&weak))); + /// // The strong here keeps it alive, so we can still access the object. + /// assert_eq!("hello", unsafe { &*Weak::as_raw(&weak) }); + /// + /// drop(strong); + /// // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to + /// // undefined behaviour. + /// // assert_eq!("hello", unsafe { &*Weak::as_raw(&weak) }); + /// ``` + /// + /// [`null`]: ../../std/ptr/fn.null.html + #[unstable(feature = "weak_into_raw", issue = "60728")] + pub fn as_raw(this: &Self) -> *const T { + match this.inner() { + None => ptr::null(), + Some(inner) => { + let offset = data_offset_sized::(); + let ptr = inner as *const RcBox; + // Note: while the pointer we create may already point to dropped value, the + // allocation still lives (it must hold the weak point as long as we are alive). + // Therefore, the offset is OK to do, it won't get out of the allocation. + let ptr = unsafe { (ptr as *const u8).offset(offset) }; + ptr as *const T + } + } + } + + /// Consumes the `Weak` and turns it into a raw pointer. + /// + /// This converts the weak pointer into a raw pointer, preserving the original weak count. It + /// can be turned back into the `Weak` with [`from_raw`]. + /// + /// The same restrictions of accessing the target of the pointer as with + /// [`as_raw`] apply. + /// + /// # Examples + /// + /// ``` + /// #![feature(weak_into_raw)] + /// + /// use std::rc::{Rc, Weak}; + /// + /// let strong = Rc::new("hello".to_owned()); + /// let weak = Rc::downgrade(&strong); + /// let raw = Weak::into_raw(weak); + /// + /// assert_eq!(1, Rc::weak_count(&strong)); + /// assert_eq!("hello", unsafe { &*raw }); + /// + /// drop(unsafe { Weak::from_raw(raw) }); + /// assert_eq!(0, Rc::weak_count(&strong)); + /// ``` + /// + /// [`from_raw`]: struct.Weak.html#method.from_raw + /// [`as_raw`]: struct.Weak.html#method.as_raw + #[unstable(feature = "weak_into_raw", issue = "60728")] + pub fn into_raw(this: Self) -> *const T { + let result = Self::as_raw(&this); + mem::forget(this); + result + } + + /// Converts a raw pointer previously created by [`into_raw`] back into `Weak`. + /// + /// This can be used to safely get a strong reference (by calling [`upgrade`] + /// later) or to deallocate the weak count by dropping the `Weak`. + /// + /// It takes ownership of one weak count. In case a [`null`] is passed, a dangling [`Weak`] is + /// returned. + /// + /// # Safety + /// + /// The pointer must represent one valid weak count. In other words, it must point to `T` which + /// is or *was* managed by an [`Rc`] and the weak count of that [`Rc`] must not have reached + /// 0. It is allowed for the strong count to be 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(weak_into_raw)] + /// + /// use std::rc::{Rc, Weak}; + /// + /// let strong = Rc::new("hello".to_owned()); + /// + /// let raw_1 = Weak::into_raw(Rc::downgrade(&strong)); + /// let raw_2 = Weak::into_raw(Rc::downgrade(&strong)); + /// + /// assert_eq!(2, Rc::weak_count(&strong)); + /// + /// assert_eq!("hello", &*Weak::upgrade(&unsafe { Weak::from_raw(raw_1) }).unwrap()); + /// assert_eq!(1, Rc::weak_count(&strong)); + /// + /// drop(strong); + /// + /// // Decrement the last weak count. + /// assert!(Weak::upgrade(&unsafe { Weak::from_raw(raw_2) }).is_none()); + /// ``` + /// + /// [`null`]: ../../std/ptr/fn.null.html + /// [`into_raw`]: struct.Weak.html#method.into_raw + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`Rc`]: struct.Rc.html + /// [`Weak`]: struct.Weak.html + #[unstable(feature = "weak_into_raw", issue = "60728")] + pub unsafe fn from_raw(ptr: *const T) -> Self { + if ptr.is_null() { + Self::new() + } else { + // See Rc::from_raw for details + let offset = data_offset(ptr); + let fake_ptr = ptr as *mut RcBox; + let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + Weak { + ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw"), + } + } + } } pub(crate) fn is_dangling(ptr: NonNull) -> bool { @@ -1357,18 +1515,18 @@ impl Weak { /// /// ``` /// #![feature(weak_ptr_eq)] - /// use std::rc::{Rc, Weak}; + /// use std::rc::Rc; /// /// let first_rc = Rc::new(5); /// let first = Rc::downgrade(&first_rc); /// let second = Rc::downgrade(&first_rc); /// - /// assert!(Weak::ptr_eq(&first, &second)); + /// assert!(first.ptr_eq(&second)); /// /// let third_rc = Rc::new(5); /// let third = Rc::downgrade(&third_rc); /// - /// assert!(!Weak::ptr_eq(&first, &third)); + /// assert!(!first.ptr_eq(&third)); /// ``` /// /// Comparing `Weak::new`. @@ -1379,16 +1537,16 @@ impl Weak { /// /// let first = Weak::new(); /// let second = Weak::new(); - /// assert!(Weak::ptr_eq(&first, &second)); + /// assert!(first.ptr_eq(&second)); /// /// let third_rc = Rc::new(()); /// let third = Rc::downgrade(&third_rc); - /// assert!(!Weak::ptr_eq(&first, &third)); + /// assert!(!first.ptr_eq(&third)); /// ``` #[inline] #[unstable(feature = "weak_ptr_eq", issue = "55981")] - pub fn ptr_eq(this: &Self, other: &Self) -> bool { - this.ptr.as_ptr() == other.ptr.as_ptr() + pub fn ptr_eq(&self, other: &Self) -> bool { + self.ptr.as_ptr() == other.ptr.as_ptr() } } @@ -2002,3 +2160,20 @@ impl AsRef for Rc { #[stable(feature = "pin", since = "1.33.0")] impl Unpin for Rc { } + +unsafe fn data_offset(ptr: *const T) -> isize { + // Align the unsized value to the end of the RcBox. + // Because it is ?Sized, it will always be the last field in memory. + let align = align_of_val(&*ptr); + let layout = Layout::new::>(); + (layout.size() + layout.padding_needed_for(align)) as isize +} + +/// Computes the offset of the data field within ArcInner. +/// +/// Unlike [`data_offset`], this doesn't need the pointer, but it works only on `T: Sized`. +fn data_offset_sized() -> isize { + let align = align_of::(); + let layout = Layout::new::>(); + (layout.size() + layout.padding_needed_for(align)) as isize +} diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index f4b2d463778a9..f7b0a5e703cc3 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -123,12 +123,12 @@ pub use core::slice::{RChunks, RChunksMut, RChunksExact, RChunksExactMut}; //////////////////////////////////////////////////////////////////////////////// // HACK(japaric) needed for the implementation of `vec!` macro during testing -// NB see the hack module in this file for more details +// N.B., see the `hack` module in this file for more details. #[cfg(test)] pub use hack::into_vec; // HACK(japaric) needed for the implementation of `Vec::clone` during testing -// NB see the hack module in this file for more details +// N.B., see the `hack` module in this file for more details. #[cfg(test)] pub use hack::to_vec; @@ -137,17 +137,16 @@ pub use hack::to_vec; // `core::slice::SliceExt` - we need to supply these functions for the // `test_permutations` test mod hack { - use core::mem; - use crate::boxed::Box; use crate::vec::Vec; #[cfg(test)] use crate::string::ToString; - pub fn into_vec(mut b: Box<[T]>) -> Vec { + pub fn into_vec(b: Box<[T]>) -> Vec { unsafe { - let xs = Vec::from_raw_parts(b.as_mut_ptr(), b.len(), b.len()); - mem::forget(b); + let len = b.len(); + let b = Box::into_raw(b); + let xs = Vec::from_raw_parts(b as *mut T, len, len); xs } } @@ -376,7 +375,7 @@ impl [T] { pub fn to_vec(&self) -> Vec where T: Clone { - // NB see hack module in this file + // N.B., see the `hack` module in this file for more details. hack::to_vec(self) } @@ -397,7 +396,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn into_vec(self: Box) -> Vec { - // NB see hack module in this file + // N.B., see the `hack` module in this file for more details. hack::into_vec(self) } @@ -570,9 +569,21 @@ pub trait SliceConcatExt { #[stable(feature = "rename_connect_to_join", since = "1.3.0")] fn join(&self, sep: &T) -> Self::Output; + /// Flattens a slice of `T` into a single value `Self::Output`, placing a + /// given separator between each. + /// + /// # Examples + /// + /// ``` + /// # #![allow(deprecated)] + /// assert_eq!(["hello", "world"].connect(" "), "hello world"); + /// assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.3.0", reason = "renamed to join")] - fn connect(&self, sep: &T) -> Self::Output; + fn connect(&self, sep: &T) -> Self::Output { + self.join(sep) + } } #[unstable(feature = "slice_concat_ext", @@ -606,10 +617,6 @@ impl> SliceConcatExt for [V] { } result } - - fn connect(&self, sep: &T) -> Vec { - self.join(sep) - } } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index a36804bddff32..40104554fe574 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -28,7 +28,7 @@ // It's cleaner to just turn off the unused_imports warning than to fix them. #![allow(unused_imports)] -use core::borrow::Borrow; +use core::borrow::{Borrow, BorrowMut}; use core::str::pattern::{Pattern, Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; use core::ptr; @@ -68,6 +68,8 @@ pub use core::str::pattern; pub use core::str::EncodeUtf16; #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] pub use core::str::SplitAsciiWhitespace; +#[stable(feature = "str_escape", since = "1.34.0")] +pub use core::str::{EscapeDebug, EscapeDefault, EscapeUnicode}; #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", @@ -84,10 +86,6 @@ impl> SliceConcatExt for [S] { String::from_utf8_unchecked( join_generic_copy(self, sep.as_bytes()) ) } } - - fn connect(&self, sep: &str) -> String { - self.join(sep) - } } macro_rules! spezialize_for_lengths { @@ -188,6 +186,14 @@ impl Borrow for String { } } +#[stable(feature = "string_borrow_mut", since = "1.36.0")] +impl BorrowMut for String { + #[inline] + fn borrow_mut(&mut self) -> &mut str { + &mut self[..] + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for str { type Owned = String; @@ -421,6 +427,13 @@ impl str { /// /// assert_eq!(new_year, new_year.to_uppercase()); /// ``` + /// + /// One character can become multiple: + /// ``` + /// let s = "tschüß"; + /// + /// assert_eq!("TSCHÜSS", s.to_uppercase()); + /// ``` #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_uppercase(&self) -> String { let mut s = String::with_capacity(self.len()); @@ -571,4 +584,3 @@ impl str { pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box { Box::from_raw(Box::into_raw(v) as *mut str) } - diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index b714df5d36b6a..7f7722548f581 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1200,8 +1200,8 @@ impl String { /// Retains only the characters specified by the predicate. /// /// In other words, remove all characters `c` such that `f(c)` returns `false`. - /// This method operates in place and preserves the order of the retained - /// characters. + /// This method operates in place, visiting each character exactly once in the + /// original order, and preserves the order of the retained characters. /// /// # Examples /// @@ -1212,6 +1212,16 @@ impl String { /// /// assert_eq!(s, "foobar"); /// ``` + /// + /// The exact order may be useful for tracking external state, like an index. + /// + /// ``` + /// let mut s = String::from("abcde"); + /// let keep = [false, true, true, false, true]; + /// let mut i = 0; + /// s.retain(|_| (keep[i], i += 1).0); + /// assert_eq!(s, "bce"); + /// ``` #[inline] #[stable(feature = "string_retain", since = "1.26.0")] pub fn retain(&mut self, mut f: F) @@ -2172,13 +2182,21 @@ impl AsRef<[u8]> for String { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a> From<&'a str> for String { +impl From<&str> for String { #[inline] - fn from(s: &'a str) -> String { + fn from(s: &str) -> String { s.to_owned() } } +#[stable(feature = "from_ref_string", since = "1.35.0")] +impl From<&String> for String { + #[inline] + fn from(s: &String) -> String { + s.clone() + } +} + // note: test pulls in libstd, which causes errors here #[cfg(not(test))] #[stable(feature = "string_from_box", since = "1.18.0")] diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index b7d7995b540ba..6c23b3179ed68 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -13,7 +13,7 @@ use core::borrow; use core::fmt; use core::cmp::{self, Ordering}; use core::intrinsics::abort; -use core::mem::{self, align_of_val, size_of_val}; +use core::mem::{self, align_of, align_of_val, size_of_val}; use core::ops::{Deref, Receiver, CoerceUnsized, DispatchFromDyn}; use core::pin::Pin; use core::ptr::{self, NonNull}; @@ -356,9 +356,9 @@ impl Arc { /// ``` /// use std::sync::Arc; /// - /// let x = Arc::new(10); + /// let x = Arc::new("hello".to_owned()); /// let x_ptr = Arc::into_raw(x); - /// assert_eq!(unsafe { *x_ptr }, 10); + /// assert_eq!(unsafe { &*x_ptr }, "hello"); /// ``` #[stable(feature = "rc_raw", since = "1.17.0")] pub fn into_raw(this: Self) -> *const T { @@ -382,13 +382,13 @@ impl Arc { /// ``` /// use std::sync::Arc; /// - /// let x = Arc::new(10); + /// let x = Arc::new("hello".to_owned()); /// let x_ptr = Arc::into_raw(x); /// /// unsafe { /// // Convert back to an `Arc` to prevent leak. /// let x = Arc::from_raw(x_ptr); - /// assert_eq!(*x, 10); + /// assert_eq!(&*x, "hello"); /// /// // Further calls to `Arc::from_raw(x_ptr)` would be memory unsafe. /// } @@ -397,11 +397,7 @@ impl Arc { /// ``` #[stable(feature = "rc_raw", since = "1.17.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { - // Align the unsized value to the end of the ArcInner. - // Because it is ?Sized, it will always be the last field in memory. - let align = align_of_val(&*ptr); - let layout = Layout::new::>(); - let offset = (layout.size() + layout.padding_needed_for(align)) as isize; + let offset = data_offset(ptr); // Reverse the offset to find the original ArcInner. let fake_ptr = ptr as *mut ArcInner; @@ -422,10 +418,10 @@ impl Arc { /// /// use std::sync::Arc; /// - /// let x = Arc::new(10); + /// let x = Arc::new("hello".to_owned()); /// let ptr = Arc::into_raw_non_null(x); - /// let deref = unsafe { *ptr.as_ref() }; - /// assert_eq!(deref, 10); + /// let deref = unsafe { ptr.as_ref() }; + /// assert_eq!(deref, "hello"); /// ``` #[unstable(feature = "rc_into_raw_non_null", issue = "47336")] #[inline] @@ -1071,6 +1067,144 @@ impl Weak { ptr: NonNull::new(usize::MAX as *mut ArcInner).expect("MAX is not 0"), } } + + /// Returns a raw pointer to the object `T` pointed to by this `Weak`. + /// + /// It is up to the caller to ensure that the object is still alive when accessing it through + /// the pointer. + /// + /// The pointer may be [`null`] or be dangling in case the object has already been destroyed. + /// + /// # Examples + /// + /// ``` + /// #![feature(weak_into_raw)] + /// + /// use std::sync::{Arc, Weak}; + /// use std::ptr; + /// + /// let strong = Arc::new("hello".to_owned()); + /// let weak = Arc::downgrade(&strong); + /// // Both point to the same object + /// assert!(ptr::eq(&*strong, Weak::as_raw(&weak))); + /// // The strong here keeps it alive, so we can still access the object. + /// assert_eq!("hello", unsafe { &*Weak::as_raw(&weak) }); + /// + /// drop(strong); + /// // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to + /// // undefined behaviour. + /// // assert_eq!("hello", unsafe { &*Weak::as_raw(&weak) }); + /// ``` + /// + /// [`null`]: ../../std/ptr/fn.null.html + #[unstable(feature = "weak_into_raw", issue = "60728")] + pub fn as_raw(this: &Self) -> *const T { + match this.inner() { + None => ptr::null(), + Some(inner) => { + let offset = data_offset_sized::(); + let ptr = inner as *const ArcInner; + // Note: while the pointer we create may already point to dropped value, the + // allocation still lives (it must hold the weak point as long as we are alive). + // Therefore, the offset is OK to do, it won't get out of the allocation. + let ptr = unsafe { (ptr as *const u8).offset(offset) }; + ptr as *const T + } + } + } + + /// Consumes the `Weak` and turns it into a raw pointer. + /// + /// This converts the weak pointer into a raw pointer, preserving the original weak count. It + /// can be turned back into the `Weak` with [`from_raw`]. + /// + /// The same restrictions of accessing the target of the pointer as with + /// [`as_raw`] apply. + /// + /// # Examples + /// + /// ``` + /// #![feature(weak_into_raw)] + /// + /// use std::sync::{Arc, Weak}; + /// + /// let strong = Arc::new("hello".to_owned()); + /// let weak = Arc::downgrade(&strong); + /// let raw = Weak::into_raw(weak); + /// + /// assert_eq!(1, Arc::weak_count(&strong)); + /// assert_eq!("hello", unsafe { &*raw }); + /// + /// drop(unsafe { Weak::from_raw(raw) }); + /// assert_eq!(0, Arc::weak_count(&strong)); + /// ``` + /// + /// [`from_raw`]: struct.Weak.html#method.from_raw + /// [`as_raw`]: struct.Weak.html#method.as_raw + #[unstable(feature = "weak_into_raw", issue = "60728")] + pub fn into_raw(this: Self) -> *const T { + let result = Self::as_raw(&this); + mem::forget(this); + result + } + + /// Converts a raw pointer previously created by [`into_raw`] back into + /// `Weak`. + /// + /// This can be used to safely get a strong reference (by calling [`upgrade`] + /// later) or to deallocate the weak count by dropping the `Weak`. + /// + /// It takes ownership of one weak count. In case a [`null`] is passed, a dangling [`Weak`] is + /// returned. + /// + /// # Safety + /// + /// The pointer must represent one valid weak count. In other words, it must point to `T` which + /// is or *was* managed by an [`Arc`] and the weak count of that [`Arc`] must not have reached + /// 0. It is allowed for the strong count to be 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(weak_into_raw)] + /// + /// use std::sync::{Arc, Weak}; + /// + /// let strong = Arc::new("hello".to_owned()); + /// + /// let raw_1 = Weak::into_raw(Arc::downgrade(&strong)); + /// let raw_2 = Weak::into_raw(Arc::downgrade(&strong)); + /// + /// assert_eq!(2, Arc::weak_count(&strong)); + /// + /// assert_eq!("hello", &*Weak::upgrade(&unsafe { Weak::from_raw(raw_1) }).unwrap()); + /// assert_eq!(1, Arc::weak_count(&strong)); + /// + /// drop(strong); + /// + /// // Decrement the last weak count. + /// assert!(Weak::upgrade(&unsafe { Weak::from_raw(raw_2) }).is_none()); + /// ``` + /// + /// [`null`]: ../../std/ptr/fn.null.html + /// [`into_raw`]: struct.Weak.html#method.into_raw + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`Weak`]: struct.Weak.html + /// [`Arc`]: struct.Arc.html + #[unstable(feature = "weak_into_raw", issue = "60728")] + pub unsafe fn from_raw(ptr: *const T) -> Self { + if ptr.is_null() { + Self::new() + } else { + // See Arc::from_raw for details + let offset = data_offset(ptr); + let fake_ptr = ptr as *mut ArcInner; + let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + Weak { + ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw"), + } + } + } } impl Weak { @@ -1215,18 +1349,18 @@ impl Weak { /// /// ``` /// #![feature(weak_ptr_eq)] - /// use std::sync::{Arc, Weak}; + /// use std::sync::Arc; /// /// let first_rc = Arc::new(5); /// let first = Arc::downgrade(&first_rc); /// let second = Arc::downgrade(&first_rc); /// - /// assert!(Weak::ptr_eq(&first, &second)); + /// assert!(first.ptr_eq(&second)); /// /// let third_rc = Arc::new(5); /// let third = Arc::downgrade(&third_rc); /// - /// assert!(!Weak::ptr_eq(&first, &third)); + /// assert!(!first.ptr_eq(&third)); /// ``` /// /// Comparing `Weak::new`. @@ -1237,16 +1371,16 @@ impl Weak { /// /// let first = Weak::new(); /// let second = Weak::new(); - /// assert!(Weak::ptr_eq(&first, &second)); + /// assert!(first.ptr_eq(&second)); /// /// let third_rc = Arc::new(()); /// let third = Arc::downgrade(&third_rc); - /// assert!(!Weak::ptr_eq(&first, &third)); + /// assert!(!first.ptr_eq(&third)); /// ``` #[inline] #[unstable(feature = "weak_ptr_eq", issue = "55981")] - pub fn ptr_eq(this: &Self, other: &Self) -> bool { - this.ptr.as_ptr() == other.ptr.as_ptr() + pub fn ptr_eq(&self, other: &Self) -> bool { + self.ptr.as_ptr() == other.ptr.as_ptr() } } @@ -1377,6 +1511,11 @@ impl ArcEqIdent for Arc { } } +/// We're doing this specialization here, and not as a more general optimization on `&T`, because it +/// would otherwise add a cost to all equality checks on refs. We assume that `Arc`s are used to +/// store large values, that are slow to clone, but also heavy to check for equality, causing this +/// cost to pay off more easily. It's also more likely to have two `Arc` clones, that point to +/// the same value, than two `&T`s. #[stable(feature = "rust1", since = "1.0.0")] impl ArcEqIdent for Arc { #[inline] @@ -1678,6 +1817,7 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] + #[cfg(not(miri))] // Miri does not support threads fn manually_share_arc() { let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let arc_v = Arc::new(v); @@ -1982,6 +2122,7 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] + #[cfg(not(miri))] // Miri does not support threads fn test_weak_count_locked() { let mut a = Arc::new(atomic::AtomicBool::new(false)); let a2 = a.clone(); @@ -2143,3 +2284,21 @@ impl AsRef for Arc { #[stable(feature = "pin", since = "1.33.0")] impl Unpin for Arc { } + +/// Computes the offset of the data field within ArcInner. +unsafe fn data_offset(ptr: *const T) -> isize { + // Align the unsized value to the end of the ArcInner. + // Because it is ?Sized, it will always be the last field in memory. + let align = align_of_val(&*ptr); + let layout = Layout::new::>(); + (layout.size() + layout.padding_needed_for(align)) as isize +} + +/// Computes the offset of the data field within ArcInner. +/// +/// Unlike [`data_offset`], this doesn't need the pointer, but it works only on `T: Sized`. +fn data_offset_sized() -> isize { + let align = align_of::(); + let layout = Layout::new::>(); + (layout.size() + layout.padding_needed_for(align)) as isize +} diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/tests.rs similarity index 100% rename from src/liballoc/boxed_test.rs rename to src/liballoc/tests.rs diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs index 1d4a3edc1ac42..0685fa943c0b8 100644 --- a/src/liballoc/tests/binary_heap.rs +++ b/src/liballoc/tests/binary_heap.rs @@ -282,7 +282,7 @@ fn assert_covariance() { // // Destructors must be called exactly once per element. #[test] -#[cfg(not(miri))] // Miri does not support panics +#[cfg(not(miri))] // Miri does not support catching panics fn panic_safe() { static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index f14750089c956..844afe870766b 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -226,7 +226,6 @@ fn test_range_equal_empty_cases() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_range_equal_excluded() { let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); map.range((Excluded(2), Excluded(2))); @@ -234,7 +233,6 @@ fn test_range_equal_excluded() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_range_backwards_1() { let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); map.range((Included(3), Included(2))); @@ -242,7 +240,6 @@ fn test_range_backwards_1() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_range_backwards_2() { let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); map.range((Included(3), Excluded(2))); @@ -250,7 +247,6 @@ fn test_range_backwards_2() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_range_backwards_3() { let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); map.range((Excluded(3), Included(2))); @@ -258,7 +254,6 @@ fn test_range_backwards_3() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_range_backwards_4() { let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); map.range((Excluded(3), Excluded(2))); diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 4f5168f1ce572..989beb3b1bfd9 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -69,6 +69,20 @@ fn test_intersection() { check_intersection(&[11, 1, 3, 77, 103, 5, -5], &[2, 11, 77, -9, -42, 5, 3], &[3, 5, 11, 77]); + let large = (0..1000).collect::>(); + check_intersection(&[], &large, &[]); + check_intersection(&large, &[], &[]); + check_intersection(&[-1], &large, &[]); + check_intersection(&large, &[-1], &[]); + check_intersection(&[0], &large, &[0]); + check_intersection(&large, &[0], &[0]); + check_intersection(&[999], &large, &[999]); + check_intersection(&large, &[999], &[999]); + check_intersection(&[1000], &large, &[]); + check_intersection(&large, &[1000], &[]); + check_intersection(&[11, 5000, 1, 3, 77, 8924, 103], + &large, + &[1, 3, 11, 77, 103]); } #[test] @@ -84,6 +98,18 @@ fn test_difference() { check_difference(&[-5, 11, 22, 33, 40, 42], &[-12, -5, 14, 23, 34, 38, 39, 50], &[11, 22, 33, 40, 42]); + let large = (0..1000).collect::>(); + check_difference(&[], &large, &[]); + check_difference(&[-1], &large, &[-1]); + check_difference(&[0], &large, &[]); + check_difference(&[999], &large, &[]); + check_difference(&[1000], &large, &[1000]); + check_difference(&[11, 5000, 1, 3, 77, 8924, 103], + &large, + &[5000, 8924]); + check_difference(&large, &[], &large); + check_difference(&large, &[-1], &large); + check_difference(&large, &[1000], &large); } #[test] @@ -114,6 +140,41 @@ fn test_union() { &[-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]); } +#[test] +// Only tests the simple function definition with respect to intersection +fn test_is_disjoint() { + let one = [1].iter().collect::>(); + let two = [2].iter().collect::>(); + assert!(one.is_disjoint(&two)); +} + +#[test] +// Also tests the trivial function definition of is_superset +fn test_is_subset() { + fn is_subset(a: &[i32], b: &[i32]) -> bool { + let set_a = a.iter().collect::>(); + let set_b = b.iter().collect::>(); + set_a.is_subset(&set_b) + } + + assert_eq!(is_subset(&[], &[]), true); + assert_eq!(is_subset(&[], &[1, 2]), true); + assert_eq!(is_subset(&[0], &[1, 2]), false); + assert_eq!(is_subset(&[1], &[1, 2]), true); + assert_eq!(is_subset(&[2], &[1, 2]), true); + assert_eq!(is_subset(&[3], &[1, 2]), false); + assert_eq!(is_subset(&[1, 2], &[1]), false); + assert_eq!(is_subset(&[1, 2], &[1, 2]), true); + assert_eq!(is_subset(&[1, 2], &[2, 3]), false); + let large = (0..1000).collect::>(); + assert_eq!(is_subset(&[], &large), true); + assert_eq!(is_subset(&large, &[]), false); + assert_eq!(is_subset(&[-1], &large), false); + assert_eq!(is_subset(&[0], &large), true); + assert_eq!(is_subset(&[1, 2], &large), true); + assert_eq!(is_subset(&[999, 1000], &large), false); +} + #[test] fn test_zip() { let mut x = BTreeSet::new(); diff --git a/src/liballoc/tests/cow_str.rs b/src/liballoc/tests/cow_str.rs index eb6adb159b0fd..6f357eda9b83b 100644 --- a/src/liballoc/tests/cow_str.rs +++ b/src/liballoc/tests/cow_str.rs @@ -7,9 +7,9 @@ fn check_cow_add_cow() { let borrowed2 = Cow::Borrowed("World!"); let borrow_empty = Cow::Borrowed(""); - let owned1: Cow = Cow::Owned(String::from("Hi, ")); - let owned2: Cow = Cow::Owned(String::from("Rustaceans!")); - let owned_empty: Cow = Cow::Owned(String::new()); + let owned1: Cow<'_, str> = Cow::Owned(String::from("Hi, ")); + let owned2: Cow<'_, str> = Cow::Owned(String::from("Rustaceans!")); + let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); assert_eq!("Hello, World!", borrowed1.clone() + borrowed2.clone()); assert_eq!("Hello, Rustaceans!", borrowed1.clone() + owned2.clone()); @@ -36,8 +36,8 @@ fn check_cow_add_str() { let borrowed = Cow::Borrowed("Hello, "); let borrow_empty = Cow::Borrowed(""); - let owned: Cow = Cow::Owned(String::from("Hi, ")); - let owned_empty: Cow = Cow::Owned(String::new()); + let owned: Cow<'_, str> = Cow::Owned(String::from("Hi, ")); + let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); assert_eq!("Hello, World!", borrowed.clone() + "World!"); @@ -60,9 +60,9 @@ fn check_cow_add_assign_cow() { let borrowed2 = Cow::Borrowed("World!"); let borrow_empty = Cow::Borrowed(""); - let mut owned1: Cow = Cow::Owned(String::from("Hi, ")); - let owned2: Cow = Cow::Owned(String::from("Rustaceans!")); - let owned_empty: Cow = Cow::Owned(String::new()); + let mut owned1: Cow<'_, str> = Cow::Owned(String::from("Hi, ")); + let owned2: Cow<'_, str> = Cow::Owned(String::from("Rustaceans!")); + let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); let mut s = borrowed1.clone(); s += borrow_empty.clone(); @@ -101,8 +101,8 @@ fn check_cow_add_assign_str() { let mut borrowed = Cow::Borrowed("Hello, "); let borrow_empty = Cow::Borrowed(""); - let mut owned: Cow = Cow::Owned(String::from("Hi, ")); - let owned_empty: Cow = Cow::Owned(String::new()); + let mut owned: Cow<'_, str> = Cow::Owned(String::from("Hi, ")); + let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); let mut s = borrowed.clone(); s += ""; @@ -132,10 +132,10 @@ fn check_cow_add_assign_str() { #[test] fn check_cow_clone_from() { - let mut c1: Cow = Cow::Owned(String::with_capacity(25)); + let mut c1: Cow<'_, str> = Cow::Owned(String::with_capacity(25)); let s: String = "hi".to_string(); assert!(s.capacity() < 25); - let c2: Cow = Cow::Owned(s); + let c2: Cow<'_, str> = Cow::Owned(s); c1.clone_from(&c2); assert!(c1.into_owned().capacity() >= 25); } diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 90921b6af9f34..ddb3120e89d78 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -6,7 +6,7 @@ #![feature(repeat_generic_slice)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(vecdeque_rotate)] +#![deny(rust_2018_idioms)] use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index feba46b0fad78..ad2cd7c95eb8f 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -258,7 +258,6 @@ fn test_swap_remove() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_swap_remove_fail() { let mut v = vec![1]; let _ = v.swap_remove(0); @@ -390,7 +389,7 @@ fn test_reverse() { } #[test] -#[cfg(not(miri))] // Miri does not support entropy +#[cfg(not(miri))] // Miri is too slow fn test_sort() { let mut rng = thread_rng(); @@ -467,10 +466,19 @@ fn test_sort() { } #[test] -#[cfg(not(miri))] // Miri does not support entropy fn test_sort_stability() { - for len in (2..25).chain(500..510) { - for _ in 0..10 { + #[cfg(not(miri))] // Miri is too slow + let large_range = 500..510; + #[cfg(not(miri))] // Miri is too slow + let rounds = 10; + + #[cfg(miri)] + let large_range = 0..0; // empty range + #[cfg(miri)] + let rounds = 1; + + for len in (2..25).chain(large_range) { + for _ in 0..rounds { let mut counts = [0; 10]; // create a vector like [(6, 1), (5, 1), (6, 2), ...], @@ -632,7 +640,6 @@ fn test_insert() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_insert_oob() { let mut a = vec![1, 2, 3]; a.insert(4, 5); @@ -657,7 +664,6 @@ fn test_remove() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_remove_fail() { let mut a = vec![1]; let _ = a.remove(0); @@ -939,7 +945,6 @@ fn test_windowsator() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_windowsator_0() { let v = &[1, 2, 3, 4]; let _it = v.windows(0); @@ -964,7 +969,6 @@ fn test_chunksator() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_chunksator_0() { let v = &[1, 2, 3, 4]; let _it = v.chunks(0); @@ -989,7 +993,6 @@ fn test_chunks_exactator() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_chunks_exactator_0() { let v = &[1, 2, 3, 4]; let _it = v.chunks_exact(0); @@ -1014,7 +1017,6 @@ fn test_rchunksator() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_rchunksator_0() { let v = &[1, 2, 3, 4]; let _it = v.rchunks(0); @@ -1039,7 +1041,6 @@ fn test_rchunks_exactator() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_rchunks_exactator_0() { let v = &[1, 2, 3, 4]; let _it = v.rchunks_exact(0); @@ -1092,7 +1093,6 @@ fn test_vec_default() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_overflow_does_not_cause_segfault() { let mut v = vec![]; v.reserve_exact(!0); @@ -1102,7 +1102,6 @@ fn test_overflow_does_not_cause_segfault() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_overflow_does_not_cause_segfault_managed() { let mut v = vec![Rc::new(1)]; v.reserve_exact(!0); @@ -1278,7 +1277,6 @@ fn test_mut_chunks_rev() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mut_chunks_0() { let mut v = [1, 2, 3, 4]; let _it = v.chunks_mut(0); @@ -1311,7 +1309,6 @@ fn test_mut_chunks_exact_rev() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mut_chunks_exact_0() { let mut v = [1, 2, 3, 4]; let _it = v.chunks_exact_mut(0); @@ -1344,7 +1341,6 @@ fn test_mut_rchunks_rev() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mut_rchunks_0() { let mut v = [1, 2, 3, 4]; let _it = v.rchunks_mut(0); @@ -1377,7 +1373,6 @@ fn test_mut_rchunks_exact_rev() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mut_rchunks_exact_0() { let mut v = [1, 2, 3, 4]; let _it = v.rchunks_exact_mut(0); @@ -1411,7 +1406,7 @@ fn test_box_slice_clone() { #[test] #[allow(unused_must_use)] // here, we care about the side effects of `.clone()` #[cfg_attr(target_os = "emscripten", ignore)] -#[cfg(not(miri))] // Miri does not support panics +#[cfg(not(miri))] // Miri does not support threads fn test_box_slice_clone_panics() { use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -1476,7 +1471,6 @@ fn test_copy_from_slice() { #[test] #[should_panic(expected = "destination and source slices have different lengths")] -#[cfg(not(miri))] // Miri does not support panics fn test_copy_from_slice_dst_longer() { let src = [0, 1, 2, 3]; let mut dst = [0; 5]; @@ -1485,7 +1479,6 @@ fn test_copy_from_slice_dst_longer() { #[test] #[should_panic(expected = "destination and source slices have different lengths")] -#[cfg(not(miri))] // Miri does not support panics fn test_copy_from_slice_dst_shorter() { let src = [0, 1, 2, 3]; let mut dst = [0; 3]; @@ -1605,7 +1598,7 @@ thread_local!(static SILENCE_PANIC: Cell = Cell::new(false)); #[test] #[cfg_attr(target_os = "emscripten", ignore)] // no threads -#[cfg(not(miri))] // Miri does not support panics +#[cfg(not(miri))] // Miri does not support threads fn panic_safe() { let prev = panic::take_hook(); panic::set_hook(Box::new(move |info| { diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index b33a564218888..b197516403f78 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -7,7 +7,7 @@ fn test_le() { assert!("" <= ""); assert!("" <= "foo"); assert!("foo" <= "foo"); - assert!("foo" != "bar"); + assert_ne!("foo", "bar"); } #[test] @@ -351,7 +351,6 @@ mod slice_index { // to be used in `should_panic`) #[test] #[should_panic(expected = "out of bounds")] - #[cfg(not(miri))] // Miri does not support panics fn assert_range_eq_can_fail_by_panic() { assert_range_eq!("abc", 0..5, "abc"); } @@ -361,7 +360,6 @@ mod slice_index { // to be used in `should_panic`) #[test] #[should_panic(expected = "==")] - #[cfg(not(miri))] // Miri does not support panics fn assert_range_eq_can_fail_by_inequality() { assert_range_eq!("abc", 0..2, "abc"); } @@ -409,7 +407,6 @@ mod slice_index { #[test] #[should_panic(expected = $expect_msg)] - #[cfg(not(miri))] // Miri does not support panics fn index_fail() { let v: String = $data.into(); let v: &str = &v; @@ -418,7 +415,6 @@ mod slice_index { #[test] #[should_panic(expected = $expect_msg)] - #[cfg(not(miri))] // Miri does not support panics fn index_mut_fail() { let mut v: String = $data.into(); let v: &mut str = &mut v; @@ -514,7 +510,6 @@ mod slice_index { #[test] #[should_panic] - #[cfg(not(miri))] // Miri does not support panics fn test_slice_fail() { &"中华Việt Nam"[0..2]; } @@ -666,14 +661,12 @@ mod slice_index { // check the panic includes the prefix of the sliced string #[test] #[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")] - #[cfg(not(miri))] // Miri does not support panics fn test_slice_fail_truncated_1() { &LOREM_PARAGRAPH[..1024]; } // check the truncation in the panic message #[test] #[should_panic(expected="luctus, im`[...]")] - #[cfg(not(miri))] // Miri does not support panics fn test_slice_fail_truncated_2() { &LOREM_PARAGRAPH[..1024]; } @@ -688,7 +681,6 @@ fn test_str_slice_rangetoinclusive_ok() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_str_slice_rangetoinclusive_notok() { let s = "abcαβγ"; &s[..=3]; @@ -704,7 +696,6 @@ fn test_str_slicemut_rangetoinclusive_ok() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_str_slicemut_rangetoinclusive_notok() { let mut s = "abcαβγ".to_owned(); let s: &mut str = &mut s; @@ -894,7 +885,6 @@ fn test_as_bytes() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_as_bytes_fail() { // Don't double free. (I'm not sure if this exercises the // original problem code path anymore.) @@ -984,7 +974,6 @@ fn test_split_at_mut() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_split_at_boundscheck() { let s = "ศไทย中华Việt Nam"; s.split_at(1); diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 7e93d84fe3b97..765210e5aa6b3 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -54,11 +54,11 @@ fn test_from_utf8() { #[test] fn test_from_utf8_lossy() { let xs = b"hello"; - let ys: Cow = "hello".into_cow(); + let ys: Cow<'_, str> = "hello".into_cow(); assert_eq!(String::from_utf8_lossy(xs), ys); let xs = "ศไทย中华Việt Nam".as_bytes(); - let ys: Cow = "ศไทย中华Việt Nam".into_cow(); + let ys: Cow<'_, str> = "ศไทย中华Việt Nam".into_cow(); assert_eq!(String::from_utf8_lossy(xs), ys); let xs = b"Hello\xC2 There\xFF Goodbye"; @@ -231,7 +231,6 @@ fn test_split_off_empty() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_split_off_past_end() { let orig = "Hello, world!"; let mut split = String::from(orig); @@ -240,7 +239,6 @@ fn test_split_off_past_end() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_split_off_mid_char() { let mut orig = String::from("山"); orig.split_off(1); @@ -289,7 +287,6 @@ fn test_str_truncate_invalid_len() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_str_truncate_split_codepoint() { let mut s = String::from("\u{FC}"); // ü s.truncate(1); @@ -324,7 +321,6 @@ fn remove() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn remove_bad() { "ศ".to_string().remove(1); } @@ -360,13 +356,11 @@ fn insert() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn insert_bad1() { "".to_string().insert(1, 't'); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn insert_bad2() { "ệ".to_string().insert(1, 't'); } @@ -447,7 +441,6 @@ fn test_replace_range() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_replace_range_char_boundary() { let mut s = "Hello, 世界!".to_owned(); s.replace_range(..8, ""); @@ -464,7 +457,6 @@ fn test_replace_range_inclusive_range() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_replace_range_out_of_bounds() { let mut s = String::from("12345"); s.replace_range(5..6, "789"); @@ -472,7 +464,6 @@ fn test_replace_range_out_of_bounds() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_replace_range_inclusive_out_of_bounds() { let mut s = String::from("12345"); s.replace_range(5..=5, "789"); diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 6e4ca1d90e642..5ddac673c9ff1 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -1,5 +1,3 @@ -#![cfg(not(miri))] - use std::borrow::Cow; use std::mem::size_of; use std::{usize, isize}; @@ -368,7 +366,6 @@ fn test_vec_truncate_drop() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_vec_truncate_fail() { struct BadElem(i32); impl Drop for BadElem { @@ -392,7 +389,6 @@ fn test_index() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_index_out_of_bounds() { let vec = vec![1, 2, 3]; let _ = vec[3]; @@ -400,7 +396,6 @@ fn test_index_out_of_bounds() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_slice_out_of_bounds_1() { let x = vec![1, 2, 3, 4, 5]; &x[!0..]; @@ -408,7 +403,6 @@ fn test_slice_out_of_bounds_1() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_slice_out_of_bounds_2() { let x = vec![1, 2, 3, 4, 5]; &x[..6]; @@ -416,7 +410,6 @@ fn test_slice_out_of_bounds_2() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_slice_out_of_bounds_3() { let x = vec![1, 2, 3, 4, 5]; &x[!0..4]; @@ -424,7 +417,6 @@ fn test_slice_out_of_bounds_3() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_slice_out_of_bounds_4() { let x = vec![1, 2, 3, 4, 5]; &x[1..6]; @@ -432,7 +424,6 @@ fn test_slice_out_of_bounds_4() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_slice_out_of_bounds_5() { let x = vec![1, 2, 3, 4, 5]; &x[3..2]; @@ -440,7 +431,6 @@ fn test_slice_out_of_bounds_5() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_swap_remove_empty() { let mut vec = Vec::::new(); vec.swap_remove(0); @@ -511,7 +501,6 @@ fn test_drain_items_zero_sized() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_drain_out_of_bounds() { let mut v = vec![1, 2, 3, 4, 5]; v.drain(5..6); @@ -585,7 +574,6 @@ fn test_drain_max_vec_size() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_drain_inclusive_out_of_bounds() { let mut v = vec![1, 2, 3, 4, 5]; v.drain(5..=5); @@ -615,7 +603,6 @@ fn test_splice_inclusive_range() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_splice_out_of_bounds() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; @@ -624,7 +611,6 @@ fn test_splice_out_of_bounds() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_splice_inclusive_out_of_bounds() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; @@ -775,6 +761,7 @@ fn from_into_inner() { it.next().unwrap(); let vec = it.collect::>(); assert_eq!(vec, [2, 3]); + #[cfg(not(miri))] // Miri does not support comparing dangling pointers assert!(ptr != vec.as_ptr()); } @@ -983,6 +970,7 @@ fn test_reserve_exact() { } #[test] +#[cfg(not(miri))] // Miri does not support signalling OOM fn test_try_reserve() { // These are the interesting cases: @@ -1085,6 +1073,7 @@ fn test_try_reserve() { } #[test] +#[cfg(not(miri))] // Miri does not support signalling OOM fn test_try_reserve_exact() { // This is exactly the same as test_try_reserve with the method changed. @@ -1163,3 +1152,24 @@ fn test_try_reserve_exact() { } } + +#[test] +fn test_stable_push_pop() { + // Test that, if we reserved enough space, adding and removing elements does not + // invalidate references into the vector (such as `v0`). This test also + // runs in Miri, which would detect such problems. + let mut v = Vec::with_capacity(10); + v.push(13); + + // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + let v0 = unsafe { &*(&v[0] as *const _) }; + + // Now do a bunch of things and occasionally use `v0` again to assert it is still valid. + v.push(1); + v.push(2); + v.insert(1, 1); + assert_eq!(*v0, 13); + v.remove(1); + v.pop().unwrap(); + assert_eq!(*v0, 13); +} diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 16ddc1444fcf9..e0fe10a55f55c 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -108,7 +108,6 @@ fn test_index() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_index_out_of_bounds() { let mut deq = VecDeque::new(); for i in 1..4 { diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 229dafc5fdc3a..92fe0834dd029 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -735,6 +735,75 @@ impl Vec { self } + /// Returns a raw pointer to the vector's buffer. + /// + /// The caller must ensure that the vector outlives the pointer this + /// function returns, or else it will end up pointing to garbage. + /// Modifying the vector may cause its buffer to be reallocated, + /// which would also make any pointers to it invalid. + /// + /// The caller must also ensure that the memory the pointer (non-transitively) points to + /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer + /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`]. + /// + /// # Examples + /// + /// ``` + /// let x = vec![1, 2, 4]; + /// let x_ptr = x.as_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// assert_eq!(*x_ptr.add(i), 1 << i); + /// } + /// } + /// ``` + /// + /// [`as_mut_ptr`]: #method.as_mut_ptr + #[stable(feature = "vec_as_ptr", since = "1.37.0")] + #[inline] + pub fn as_ptr(&self) -> *const T { + // We shadow the slice method of the same name to avoid going through + // `deref`, which creates an intermediate reference. + let ptr = self.buf.ptr(); + unsafe { assume(!ptr.is_null()); } + ptr + } + + /// Returns an unsafe mutable pointer to the vector's buffer. + /// + /// The caller must ensure that the vector outlives the pointer this + /// function returns, or else it will end up pointing to garbage. + /// Modifying the vector may cause its buffer to be reallocated, + /// which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// // Allocate vector big enough for 4 elements. + /// let size = 4; + /// let mut x: Vec = Vec::with_capacity(size); + /// let x_ptr = x.as_mut_ptr(); + /// + /// // Initialize elements via raw pointer writes, then set length. + /// unsafe { + /// for i in 0..size { + /// *x_ptr.add(i) = i as i32; + /// } + /// x.set_len(size); + /// } + /// assert_eq!(&*x, &[0,1,2,3]); + /// ``` + #[stable(feature = "vec_as_ptr", since = "1.37.0")] + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut T { + // We shadow the slice method of the same name to avoid going through + // `deref_mut`, which creates an intermediate reference. + let ptr = self.buf.ptr(); + unsafe { assume(!ptr.is_null()); } + ptr + } + /// Forces the length of the vector to `new_len`. /// /// This is a low-level operation that maintains none of the normal @@ -937,8 +1006,8 @@ impl Vec { /// Retains only the elements specified by the predicate. /// /// In other words, remove all elements `e` such that `f(&e)` returns `false`. - /// This method operates in place and preserves the order of the retained - /// elements. + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. /// /// # Examples /// @@ -947,6 +1016,16 @@ impl Vec { /// vec.retain(|&x| x%2 == 0); /// assert_eq!(vec, [2, 4]); /// ``` + /// + /// The exact order may be useful for tracking external state, like an index. + /// + /// ``` + /// let mut vec = vec![1, 2, 3, 4, 5]; + /// let keep = [false, true, true, false, true]; + /// let mut i = 0; + /// vec.retain(|_| (keep[i], i += 1).0); + /// assert_eq!(vec, [2, 3, 5]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn retain(&mut self, mut f: F) where F: FnMut(&T) -> bool @@ -1084,7 +1163,7 @@ impl Vec { let count = (*other).len(); self.reserve(count); let len = self.len(); - ptr::copy_nonoverlapping(other as *const T, self.get_unchecked_mut(len), count); + ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count); self.len += count; } @@ -1260,7 +1339,7 @@ impl Vec { /// This method uses a closure to create new values on every push. If /// you'd rather [`Clone`] a given value, use [`resize`]. If you want /// to use the [`Default`] trait to generate values, you can pass - /// [`Default::default()`] as the second argument.. + /// [`Default::default()`] as the second argument. /// /// # Examples /// @@ -1696,9 +1775,7 @@ impl ops::Deref for Vec { fn deref(&self) -> &[T] { unsafe { - let p = self.buf.ptr(); - assume(!p.is_null()); - slice::from_raw_parts(p, self.len) + slice::from_raw_parts(self.as_ptr(), self.len) } } } @@ -1707,9 +1784,7 @@ impl ops::Deref for Vec { impl ops::DerefMut for Vec { fn deref_mut(&mut self) -> &mut [T] { unsafe { - let ptr = self.buf.ptr(); - assume(!ptr.is_null()); - slice::from_raw_parts_mut(ptr, self.len) + slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } } } @@ -1744,7 +1819,6 @@ impl IntoIterator for Vec { fn into_iter(mut self) -> IntoIter { unsafe { let begin = self.as_mut_ptr(); - assume(!begin.is_null()); let end = if mem::size_of::() == 0 { arith_offset(begin as *const i8, self.len() as isize) as *const T } else { @@ -1944,16 +2018,14 @@ impl Vec { /// with the given `replace_with` iterator and yields the removed items. /// `replace_with` does not need to be the same length as `range`. /// - /// Note 1: The element range is removed even if the iterator is not - /// consumed until the end. + /// The element range is removed even if the iterator is not consumed until the end. /// - /// Note 2: It is unspecified how many elements are removed from the vector, + /// It is unspecified how many elements are removed from the vector /// if the `Splice` value is leaked. /// - /// Note 3: The input iterator `replace_with` is only consumed - /// when the `Splice` value is dropped. + /// The input iterator `replace_with` is only consumed when the `Splice` value is dropped. /// - /// Note 4: This is optimal if: + /// This is optimal if: /// /// * The tail (elements in the vector after `range`) is empty, /// * or `replace_with` yields fewer elements than `range`’s length @@ -2182,25 +2254,25 @@ impl AsMut<[T]> for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: Clone> From<&'a [T]> for Vec { +impl From<&[T]> for Vec { #[cfg(not(test))] - fn from(s: &'a [T]) -> Vec { + fn from(s: &[T]) -> Vec { s.to_vec() } #[cfg(test)] - fn from(s: &'a [T]) -> Vec { + fn from(s: &[T]) -> Vec { crate::slice::to_vec(s) } } #[stable(feature = "vec_from_mut", since = "1.19.0")] -impl<'a, T: Clone> From<&'a mut [T]> for Vec { +impl From<&mut [T]> for Vec { #[cfg(not(test))] - fn from(s: &'a mut [T]) -> Vec { + fn from(s: &mut [T]) -> Vec { s.to_vec() } #[cfg(test)] - fn from(s: &'a mut [T]) -> Vec { + fn from(s: &mut [T]) -> Vec { crate::slice::to_vec(s) } } @@ -2231,8 +2303,8 @@ impl From> for Box<[T]> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a> From<&'a str> for Vec { - fn from(s: &'a str) -> Vec { +impl From<&str> for Vec { + fn from(s: &str) -> Vec { From::from(s.as_bytes()) } } @@ -2468,6 +2540,25 @@ impl fmt::Debug for Drain<'_, T> { } } +impl<'a, T> Drain<'a, T> { + /// Returns the remaining items of this iterator as a slice. + /// + /// # Examples + /// + /// ``` + /// # #![feature(vec_drain_as_slice)] + /// let mut vec = vec!['a', 'b', 'c']; + /// let mut drain = vec.drain(..); + /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']); + /// let _ = drain.next().unwrap(); + /// assert_eq!(drain.as_slice(), &['b', 'c']); + /// ``` + #[unstable(feature = "vec_drain_as_slice", reason = "recently added", issue = "58957")] + pub fn as_slice(&self) -> &[T] { + self.iter.as_slice() + } +} + #[stable(feature = "drain", since = "1.6.0")] unsafe impl Sync for Drain<'_, T> {} #[stable(feature = "drain", since = "1.6.0")] diff --git a/src/libarena/Cargo.toml b/src/libarena/Cargo.toml index 82fc64ba64e33..aa1bf38b99597 100644 --- a/src/libarena/Cargo.toml +++ b/src/libarena/Cargo.toml @@ -11,3 +11,4 @@ crate-type = ["dylib"] [dependencies] rustc_data_structures = { path = "../librustc_data_structures" } +smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 8ae046c0796bc..3d16e335cd8f1 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -12,8 +12,9 @@ test(no_crate_inject, attr(deny(warnings))))] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] -#![feature(alloc)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(raw_vec_internals)] @@ -23,7 +24,9 @@ extern crate alloc; +use rustc_data_structures::cold_path; use rustc_data_structures::sync::MTLock; +use smallvec::SmallVec; use std::cell::{Cell, RefCell}; use std::cmp; @@ -55,6 +58,8 @@ pub struct TypedArena { struct TypedArenaChunk { /// The raw storage for the arena chunk. storage: RawVec, + /// The number of valid entries in the chunk. + entries: usize, } impl TypedArenaChunk { @@ -62,6 +67,7 @@ impl TypedArenaChunk { unsafe fn new(capacity: usize) -> TypedArenaChunk { TypedArenaChunk { storage: RawVec::with_capacity(capacity), + entries: 0, } } @@ -108,8 +114,8 @@ impl Default for TypedArena { TypedArena { // We set both `ptr` and `end` to 0 so that the first call to // alloc() will trigger a grow(). - ptr: Cell::new(0 as *mut T), - end: Cell::new(0 as *mut T), + ptr: Cell::new(ptr::null_mut()), + end: Cell::new(ptr::null_mut()), chunks: RefCell::new(vec![]), _own: PhantomData, } @@ -149,6 +155,34 @@ impl TypedArena { } } + #[inline] + fn can_allocate(&self, len: usize) -> bool { + let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize; + let at_least_bytes = len.checked_mul(mem::size_of::()).unwrap(); + available_capacity_bytes >= at_least_bytes + } + + /// Ensures there's enough space in the current chunk to fit `len` objects. + #[inline] + fn ensure_capacity(&self, len: usize) { + if !self.can_allocate(len) { + self.grow(len); + debug_assert!(self.can_allocate(len)); + } + } + + #[inline] + unsafe fn alloc_raw_slice(&self, len: usize) -> *mut T { + assert!(mem::size_of::() != 0); + assert!(len != 0); + + self.ensure_capacity(len); + + let start_ptr = self.ptr.get(); + self.ptr.set(start_ptr.add(len)); + start_ptr + } + /// Allocates a slice of objects that are copied into the `TypedArena`, returning a mutable /// reference to it. Will panic if passed a zero-sized types. /// @@ -161,21 +195,64 @@ impl TypedArena { where T: Copy, { + unsafe { + let len = slice.len(); + let start_ptr = self.alloc_raw_slice(len); + slice.as_ptr().copy_to_nonoverlapping(start_ptr, len); + slice::from_raw_parts_mut(start_ptr, len) + } + } + + #[inline] + pub fn alloc_from_iter>(&self, iter: I) -> &mut [T] { assert!(mem::size_of::() != 0); - assert!(slice.len() != 0); + let mut iter = iter.into_iter(); + let size_hint = iter.size_hint(); - let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize; - let at_least_bytes = slice.len() * mem::size_of::(); - if available_capacity_bytes < at_least_bytes { - self.grow(slice.len()); - } + match size_hint { + (min, Some(max)) if min == max => { + // We know the exact number of elements the iterator will produce here + let len = min; - unsafe { - let start_ptr = self.ptr.get(); - let arena_slice = slice::from_raw_parts_mut(start_ptr, slice.len()); - self.ptr.set(start_ptr.add(arena_slice.len())); - arena_slice.copy_from_slice(slice); - arena_slice + if len == 0 { + return &mut []; + } + + self.ensure_capacity(len); + + let slice = self.ptr.get(); + + unsafe { + let mut ptr = self.ptr.get(); + for _ in 0..len { + // Write into uninitialized memory. + ptr::write(ptr, iter.next().unwrap()); + // Advance the pointer. + ptr = ptr.offset(1); + // Update the pointer per iteration so if `iter.next()` panics + // we destroy the correct amount + self.ptr.set(ptr); + } + slice::from_raw_parts_mut(slice, len) + } + } + _ => { + cold_path(move || -> &mut [T] { + let mut vec: SmallVec<[_; 8]> = iter.collect(); + if vec.is_empty() { + return &mut []; + } + // Move the content to the arena by copying it and then forgetting + // the content of the SmallVec + unsafe { + let len = vec.len(); + let start_ptr = self.alloc_raw_slice(len); + vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); + vec.set_len(0); + slice::from_raw_parts_mut(start_ptr, len) + } + }) + } } } @@ -189,6 +266,7 @@ impl TypedArena { if let Some(last_chunk) = chunks.last_mut() { let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize; let currently_used_cap = used_bytes / mem::size_of::(); + last_chunk.entries = currently_used_cap; if last_chunk.storage.reserve_in_place(currently_used_cap, n) { self.end.set(last_chunk.end()); return; @@ -222,8 +300,7 @@ impl TypedArena { let len = chunks_borrow.len(); // If `T` is ZST, code below has no effect. for mut chunk in chunks_borrow.drain(..len-1) { - let cap = chunk.storage.cap(); - chunk.destroy(cap); + chunk.destroy(chunk.entries); } } } @@ -265,8 +342,7 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena { self.clear_last_chunk(&mut last_chunk); // The last chunk will be dropped. Destroy all other chunks. for chunk in chunks_borrow.iter_mut() { - let cap = chunk.storage.cap(); - chunk.destroy(cap); + chunk.destroy(chunk.entries); } } // RawVec handles deallocation of `last_chunk` and `self.chunks`. @@ -294,8 +370,8 @@ impl Default for DroplessArena { #[inline] fn default() -> DroplessArena { DroplessArena { - ptr: Cell::new(0 as *mut u8), - end: Cell::new(0 as *mut u8), + ptr: Cell::new(ptr::null_mut()), + end: Cell::new(ptr::null_mut()), chunks: Default::default(), } } @@ -410,6 +486,73 @@ impl DroplessArena { arena_slice } } + + #[inline] + unsafe fn write_from_iter>( + &self, + mut iter: I, + len: usize, + mem: *mut T, + ) -> &mut [T] { + let mut i = 0; + // Use a manual loop since LLVM manages to optimize it better for + // slice iterators + loop { + let value = iter.next(); + if i >= len || value.is_none() { + // We only return as many items as the iterator gave us, even + // though it was supposed to give us `len` + return slice::from_raw_parts_mut(mem, i); + } + ptr::write(mem.offset(i as isize), value.unwrap()); + i += 1; + } + } + + #[inline] + pub fn alloc_from_iter>(&self, iter: I) -> &mut [T] { + let iter = iter.into_iter(); + assert!(mem::size_of::() != 0); + assert!(!mem::needs_drop::()); + + let size_hint = iter.size_hint(); + + match size_hint { + (min, Some(max)) if min == max => { + // We know the exact number of elements the iterator will produce here + let len = min; + + if len == 0 { + return &mut [] + } + let size = len.checked_mul(mem::size_of::()).unwrap(); + let mem = self.alloc_raw(size, mem::align_of::()) as *mut _ as *mut T; + unsafe { + self.write_from_iter(iter, len, mem) + } + } + (_, _) => { + cold_path(move || -> &mut [T] { + let mut vec: SmallVec<[_; 8]> = iter.collect(); + if vec.is_empty() { + return &mut []; + } + // Move the content to the arena by copying it and then forgetting + // the content of the SmallVec + unsafe { + let len = vec.len(); + let start_ptr = self.alloc_raw( + len * mem::size_of::(), + mem::align_of::() + ) as *mut _ as *mut T; + vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); + vec.set_len(0); + slice::from_raw_parts_mut(start_ptr, len) + } + }) + } + } + } } #[derive(Default)] @@ -474,218 +617,4 @@ impl SyncDroplessArena { } #[cfg(test)] -mod tests { - extern crate test; - use test::Bencher; - use super::TypedArena; - use std::cell::Cell; - - #[allow(dead_code)] - #[derive(Debug, Eq, PartialEq)] - struct Point { - x: i32, - y: i32, - z: i32, - } - - #[test] - pub fn test_unused() { - let arena: TypedArena = TypedArena::default(); - assert!(arena.chunks.borrow().is_empty()); - } - - #[test] - fn test_arena_alloc_nested() { - struct Inner { - value: u8, - } - struct Outer<'a> { - inner: &'a Inner, - } - enum EI<'e> { - I(Inner), - O(Outer<'e>), - } - - struct Wrap<'a>(TypedArena>); - - impl<'a> Wrap<'a> { - fn alloc_inner Inner>(&self, f: F) -> &Inner { - let r: &EI<'_> = self.0.alloc(EI::I(f())); - if let &EI::I(ref i) = r { - i - } else { - panic!("mismatch"); - } - } - fn alloc_outer Outer<'a>>(&self, f: F) -> &Outer<'_> { - let r: &EI<'_> = self.0.alloc(EI::O(f())); - if let &EI::O(ref o) = r { - o - } else { - panic!("mismatch"); - } - } - } - - let arena = Wrap(TypedArena::default()); - - let result = arena.alloc_outer(|| Outer { - inner: arena.alloc_inner(|| Inner { value: 10 }), - }); - - assert_eq!(result.inner.value, 10); - } - - #[test] - pub fn test_copy() { - let arena = TypedArena::default(); - for _ in 0..100000 { - arena.alloc(Point { x: 1, y: 2, z: 3 }); - } - } - - #[bench] - pub fn bench_copy(b: &mut Bencher) { - let arena = TypedArena::default(); - b.iter(|| arena.alloc(Point { x: 1, y: 2, z: 3 })) - } - - #[bench] - pub fn bench_copy_nonarena(b: &mut Bencher) { - b.iter(|| { - let _: Box<_> = Box::new(Point { x: 1, y: 2, z: 3 }); - }) - } - - #[allow(dead_code)] - struct Noncopy { - string: String, - array: Vec, - } - - #[test] - pub fn test_noncopy() { - let arena = TypedArena::default(); - for _ in 0..100000 { - arena.alloc(Noncopy { - string: "hello world".to_string(), - array: vec![1, 2, 3, 4, 5], - }); - } - } - - #[test] - pub fn test_typed_arena_zero_sized() { - let arena = TypedArena::default(); - for _ in 0..100000 { - arena.alloc(()); - } - } - - #[test] - pub fn test_typed_arena_clear() { - let mut arena = TypedArena::default(); - for _ in 0..10 { - arena.clear(); - for _ in 0..10000 { - arena.alloc(Point { x: 1, y: 2, z: 3 }); - } - } - } - - #[bench] - pub fn bench_typed_arena_clear(b: &mut Bencher) { - let mut arena = TypedArena::default(); - b.iter(|| { - arena.alloc(Point { x: 1, y: 2, z: 3 }); - arena.clear(); - }) - } - - // Drop tests - - struct DropCounter<'a> { - count: &'a Cell, - } - - impl Drop for DropCounter<'_> { - fn drop(&mut self) { - self.count.set(self.count.get() + 1); - } - } - - #[test] - fn test_typed_arena_drop_count() { - let counter = Cell::new(0); - { - let arena: TypedArena> = TypedArena::default(); - for _ in 0..100 { - // Allocate something with drop glue to make sure it doesn't leak. - arena.alloc(DropCounter { count: &counter }); - } - }; - assert_eq!(counter.get(), 100); - } - - #[test] - fn test_typed_arena_drop_on_clear() { - let counter = Cell::new(0); - let mut arena: TypedArena> = TypedArena::default(); - for i in 0..10 { - for _ in 0..100 { - // Allocate something with drop glue to make sure it doesn't leak. - arena.alloc(DropCounter { count: &counter }); - } - arena.clear(); - assert_eq!(counter.get(), i * 100 + 100); - } - } - - thread_local! { - static DROP_COUNTER: Cell = Cell::new(0) - } - - struct SmallDroppable; - - impl Drop for SmallDroppable { - fn drop(&mut self) { - DROP_COUNTER.with(|c| c.set(c.get() + 1)); - } - } - - #[test] - fn test_typed_arena_drop_small_count() { - DROP_COUNTER.with(|c| c.set(0)); - { - let arena: TypedArena = TypedArena::default(); - for _ in 0..100 { - // Allocate something with drop glue to make sure it doesn't leak. - arena.alloc(SmallDroppable); - } - // dropping - }; - assert_eq!(DROP_COUNTER.with(|c| c.get()), 100); - } - - #[bench] - pub fn bench_noncopy(b: &mut Bencher) { - let arena = TypedArena::default(); - b.iter(|| { - arena.alloc(Noncopy { - string: "hello world".to_string(), - array: vec![1, 2, 3, 4, 5], - }) - }) - } - - #[bench] - pub fn bench_noncopy_nonarena(b: &mut Bencher) { - b.iter(|| { - let _: Box<_> = Box::new(Noncopy { - string: "hello world".to_string(), - array: vec![1, 2, 3, 4, 5], - }); - }) - } -} +mod tests; diff --git a/src/libarena/tests.rs b/src/libarena/tests.rs new file mode 100644 index 0000000000000..fa4189409d0e8 --- /dev/null +++ b/src/libarena/tests.rs @@ -0,0 +1,213 @@ +extern crate test; +use test::Bencher; +use super::TypedArena; +use std::cell::Cell; + +#[allow(dead_code)] +#[derive(Debug, Eq, PartialEq)] +struct Point { + x: i32, + y: i32, + z: i32, +} + +#[test] +pub fn test_unused() { + let arena: TypedArena = TypedArena::default(); + assert!(arena.chunks.borrow().is_empty()); +} + +#[test] +fn test_arena_alloc_nested() { + struct Inner { + value: u8, + } + struct Outer<'a> { + inner: &'a Inner, + } + enum EI<'e> { + I(Inner), + O(Outer<'e>), + } + + struct Wrap<'a>(TypedArena>); + + impl<'a> Wrap<'a> { + fn alloc_inner Inner>(&self, f: F) -> &Inner { + let r: &EI<'_> = self.0.alloc(EI::I(f())); + if let &EI::I(ref i) = r { + i + } else { + panic!("mismatch"); + } + } + fn alloc_outer Outer<'a>>(&self, f: F) -> &Outer<'_> { + let r: &EI<'_> = self.0.alloc(EI::O(f())); + if let &EI::O(ref o) = r { + o + } else { + panic!("mismatch"); + } + } + } + + let arena = Wrap(TypedArena::default()); + + let result = arena.alloc_outer(|| Outer { + inner: arena.alloc_inner(|| Inner { value: 10 }), + }); + + assert_eq!(result.inner.value, 10); +} + +#[test] +pub fn test_copy() { + let arena = TypedArena::default(); + for _ in 0..100000 { + arena.alloc(Point { x: 1, y: 2, z: 3 }); + } +} + +#[bench] +pub fn bench_copy(b: &mut Bencher) { + let arena = TypedArena::default(); + b.iter(|| arena.alloc(Point { x: 1, y: 2, z: 3 })) +} + +#[bench] +pub fn bench_copy_nonarena(b: &mut Bencher) { + b.iter(|| { + let _: Box<_> = Box::new(Point { x: 1, y: 2, z: 3 }); + }) +} + +#[allow(dead_code)] +struct Noncopy { + string: String, + array: Vec, +} + +#[test] +pub fn test_noncopy() { + let arena = TypedArena::default(); + for _ in 0..100000 { + arena.alloc(Noncopy { + string: "hello world".to_string(), + array: vec![1, 2, 3, 4, 5], + }); + } +} + +#[test] +pub fn test_typed_arena_zero_sized() { + let arena = TypedArena::default(); + for _ in 0..100000 { + arena.alloc(()); + } +} + +#[test] +pub fn test_typed_arena_clear() { + let mut arena = TypedArena::default(); + for _ in 0..10 { + arena.clear(); + for _ in 0..10000 { + arena.alloc(Point { x: 1, y: 2, z: 3 }); + } + } +} + +#[bench] +pub fn bench_typed_arena_clear(b: &mut Bencher) { + let mut arena = TypedArena::default(); + b.iter(|| { + arena.alloc(Point { x: 1, y: 2, z: 3 }); + arena.clear(); + }) +} + +// Drop tests + +struct DropCounter<'a> { + count: &'a Cell, +} + +impl Drop for DropCounter<'_> { + fn drop(&mut self) { + self.count.set(self.count.get() + 1); + } +} + +#[test] +fn test_typed_arena_drop_count() { + let counter = Cell::new(0); + { + let arena: TypedArena> = TypedArena::default(); + for _ in 0..100 { + // Allocate something with drop glue to make sure it doesn't leak. + arena.alloc(DropCounter { count: &counter }); + } + }; + assert_eq!(counter.get(), 100); +} + +#[test] +fn test_typed_arena_drop_on_clear() { + let counter = Cell::new(0); + let mut arena: TypedArena> = TypedArena::default(); + for i in 0..10 { + for _ in 0..100 { + // Allocate something with drop glue to make sure it doesn't leak. + arena.alloc(DropCounter { count: &counter }); + } + arena.clear(); + assert_eq!(counter.get(), i * 100 + 100); + } +} + +thread_local! { + static DROP_COUNTER: Cell = Cell::new(0) +} + +struct SmallDroppable; + +impl Drop for SmallDroppable { + fn drop(&mut self) { + DROP_COUNTER.with(|c| c.set(c.get() + 1)); + } +} + +#[test] +fn test_typed_arena_drop_small_count() { + DROP_COUNTER.with(|c| c.set(0)); + { + let arena: TypedArena = TypedArena::default(); + for _ in 0..100 { + // Allocate something with drop glue to make sure it doesn't leak. + arena.alloc(SmallDroppable); + } + // dropping + }; + assert_eq!(DROP_COUNTER.with(|c| c.get()), 100); +} + +#[bench] +pub fn bench_noncopy(b: &mut Bencher) { + let arena = TypedArena::default(); + b.iter(|| { + arena.alloc(Noncopy { + string: "hello world".to_string(), + array: vec![1, 2, 3, 4, 5], + }) + }) +} + +#[bench] +pub fn bench_noncopy_nonarena(b: &mut Bencher) { + b.iter(|| { + let _: Box<_> = Box::new(Noncopy { + string: "hello world".to_string(), + array: vec![1, 2, 3, 4, 5], + }); + }) +} diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index fa2ab11243b6c..ede5fff5f4a0e 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -4,6 +4,7 @@ name = "core" version = "0.0.0" autotests = false autobenches = false +edition = "2018" [lib] name = "core" diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index e842020561d35..f25631e028eec 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -2,12 +2,12 @@ #![stable(feature = "alloc_module", since = "1.28.0")] -use cmp; -use fmt; -use mem; -use usize; -use ptr::{self, NonNull}; -use num::NonZeroUsize; +use crate::cmp; +use crate::fmt; +use crate::mem; +use crate::usize; +use crate::ptr::{self, NonNull}; +use crate::num::NonZeroUsize; /// Represents the combination of a starting address and /// a total capacity of the returned block. @@ -99,7 +99,7 @@ impl Layout { /// [`Layout::from_size_align`](#method.from_size_align). #[stable(feature = "alloc_layout", since = "1.28.0")] #[inline] - pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { + pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) } } @@ -338,7 +338,7 @@ pub struct LayoutErr { // (we need this for downstream impl of trait Error) #[stable(feature = "alloc_layout", since = "1.28.0")] impl fmt::Display for LayoutErr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("invalid parameters to Layout::from_size_align") } } @@ -354,7 +354,7 @@ pub struct AllocErr; // (we need this for downstream impl of trait Error) #[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for AllocErr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("memory allocation failed") } } @@ -376,7 +376,7 @@ impl CannotReallocInPlace { // (we need this for downstream impl of trait Error) #[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for CannotReallocInPlace { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.description()) } } @@ -480,7 +480,7 @@ pub unsafe trait GlobalAlloc { /// this allocator, /// /// * `layout` must be the same layout that was used - /// to allocated that block of memory, + /// to allocate that block of memory, #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); @@ -535,7 +535,7 @@ pub unsafe trait GlobalAlloc { /// * `ptr` must be currently allocated via this allocator, /// /// * `layout` must be the same layout that was used - /// to allocated that block of memory, + /// to allocate that block of memory, /// /// * `new_size` must be greater than zero. /// diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 01ab523a4c3f6..d043ce34effcd 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -61,8 +61,8 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fmt; -use intrinsics; +use crate::fmt; +use crate::intrinsics; /////////////////////////////////////////////////////////////////////////////// // Any trait @@ -107,7 +107,7 @@ impl Any for T { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for dyn Any { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Any") } } @@ -117,14 +117,14 @@ impl fmt::Debug for dyn Any { // dispatch works with upcasting. #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for dyn Any + Send { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Any") } } #[stable(feature = "any_send_sync_methods", since = "1.28.0")] impl fmt::Debug for dyn Any + Send + Sync { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Any") } } diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 9c6ecc4350246..03094bfd33374 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -4,18 +4,15 @@ //! //! *[See also the array primitive type](../../std/primitive.array.html).* -#![unstable(feature = "fixed_size_array", - reason = "traits and impls are better expressed through generic \ - integer constants", - issue = "27778")] - -use borrow::{Borrow, BorrowMut}; -use cmp::Ordering; -use convert::TryFrom; -use fmt; -use hash::{Hash, self}; -use marker::Unsize; -use slice::{Iter, IterMut}; +#![stable(feature = "core_array", since = "1.36.0")] + +use crate::borrow::{Borrow, BorrowMut}; +use crate::cmp::Ordering; +use crate::convert::{Infallible, TryFrom}; +use crate::fmt; +use crate::hash::{Hash, self}; +use crate::marker::Unsize; +use crate::slice::{Iter, IterMut}; /// Utility trait implemented only on arrays of fixed size /// @@ -30,13 +27,17 @@ use slice::{Iter, IterMut}; /// Note that the traits AsRef and AsMut provide similar methods for types that /// may not be fixed-size arrays. Implementors should prefer those traits /// instead. +#[unstable(feature = "fixed_size_array", issue = "27778")] pub unsafe trait FixedSizeArray { /// Converts the array to immutable slice + #[unstable(feature = "fixed_size_array", issue = "27778")] fn as_slice(&self) -> &[T]; /// Converts the array to mutable slice + #[unstable(feature = "fixed_size_array", issue = "27778")] fn as_mut_slice(&mut self) -> &mut [T]; } +#[unstable(feature = "fixed_size_array", issue = "27778")] unsafe impl> FixedSizeArray for A { #[inline] fn as_slice(&self) -> &[T] { @@ -53,9 +54,10 @@ unsafe impl> FixedSizeArray for A { #[derive(Debug, Copy, Clone)] pub struct TryFromSliceError(()); +#[stable(feature = "core_array", since = "1.36.0")] impl fmt::Display for TryFromSliceError { #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self.__description(), f) } } @@ -72,6 +74,13 @@ impl TryFromSliceError { } } +#[stable(feature = "try_from_slice_error", since = "1.36.0")] +impl From for TryFromSliceError { + fn from(x: Infallible) -> TryFromSliceError { + match x {} + } +} + macro_rules! __impl_slice_eq1 { ($Lhs: ty, $Rhs: ty) => { __impl_slice_eq1! { $Lhs, $Rhs, Sized } @@ -139,7 +148,7 @@ macro_rules! array_impls { } #[stable(feature = "try_from", since = "1.34.0")] - impl<'a, T> TryFrom<&'a [T]> for [T; $N] where T: Copy { + impl TryFrom<&[T]> for [T; $N] where T: Copy { type Error = TryFromSliceError; fn try_from(slice: &[T]) -> Result<[T; $N], TryFromSliceError> { @@ -184,7 +193,7 @@ macro_rules! array_impls { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for [T; $N] { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&&self[..], f) } } diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index 7a06aa2b0d397..c0ab364380fbd 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -11,9 +11,9 @@ #![stable(feature = "core_ascii", since = "1.26.0")] -use fmt; -use ops::Range; -use iter::FusedIterator; +use crate::fmt; +use crate::ops::Range; +use crate::iter::FusedIterator; /// An iterator over the escaped version of a byte. /// @@ -131,7 +131,7 @@ impl FusedIterator for EscapeDefault {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for EscapeDefault { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("EscapeDefault { .. }") } } diff --git a/src/libcore/benches/ascii.rs b/src/libcore/benches/ascii.rs new file mode 100644 index 0000000000000..a337c46713133 --- /dev/null +++ b/src/libcore/benches/ascii.rs @@ -0,0 +1,349 @@ +// Lower-case ASCII 'a' is the first byte that has its highest bit set +// after wrap-adding 0x1F: +// +// b'a' + 0x1F == 0x80 == 0b1000_0000 +// b'z' + 0x1F == 0x98 == 0b1001_1000 +// +// Lower-case ASCII 'z' is the last byte that has its highest bit unset +// after wrap-adding 0x05: +// +// b'a' + 0x05 == 0x66 == 0b0110_0110 +// b'z' + 0x05 == 0x7F == 0b0111_1111 +// +// … except for 0xFB to 0xFF, but those are in the range of bytes +// that have the highest bit unset again after adding 0x1F. +// +// So `(byte + 0x1f) & !(byte + 5)` has its highest bit set +// iff `byte` is a lower-case ASCII letter. +// +// Lower-case ASCII letters all have the 0x20 bit set. +// (Two positions right of 0x80, the highest bit.) +// Unsetting that bit produces the same letter, in upper-case. +// +// Therefore: +fn branchless_to_ascii_upper_case(byte: u8) -> u8 { + byte & + !( + ( + byte.wrapping_add(0x1f) & + !byte.wrapping_add(0x05) & + 0x80 + ) >> 2 + ) +} + + +macro_rules! benches { + ($( fn $name: ident($arg: ident: &mut [u8]) $body: block )+ @iter $( $is_: ident, )+) => { + benches! {@ + $( fn $name($arg: &mut [u8]) $body )+ + $( fn $is_(bytes: &mut [u8]) { bytes.iter().all(u8::$is_) } )+ + } + }; + + (@$( fn $name: ident($arg: ident: &mut [u8]) $body: block )+) => { + benches!(mod short SHORT $($name $arg $body)+); + benches!(mod medium MEDIUM $($name $arg $body)+); + benches!(mod long LONG $($name $arg $body)+); + }; + + (mod $mod_name: ident $input: ident $($name: ident $arg: ident $body: block)+) => { + mod $mod_name { + use super::*; + + $( + #[bench] + fn $name(bencher: &mut Bencher) { + bencher.bytes = $input.len() as u64; + bencher.iter(|| { + let mut vec = $input.as_bytes().to_vec(); + { + let $arg = &mut vec[..]; + black_box($body); + } + vec + }) + } + )+ + } + } +} + +use test::black_box; +use test::Bencher; + +benches! { + fn case00_alloc_only(_bytes: &mut [u8]) {} + + fn case01_black_box_read_each_byte(bytes: &mut [u8]) { + for byte in bytes { + black_box(*byte); + } + } + + fn case02_lookup_table(bytes: &mut [u8]) { + for byte in bytes { + *byte = ASCII_UPPERCASE_MAP[*byte as usize] + } + } + + fn case03_branch_and_subtract(bytes: &mut [u8]) { + for byte in bytes { + *byte = if b'a' <= *byte && *byte <= b'z' { + *byte - b'a' + b'A' + } else { + *byte + } + } + } + + fn case04_branch_and_mask(bytes: &mut [u8]) { + for byte in bytes { + *byte = if b'a' <= *byte && *byte <= b'z' { + *byte & !0x20 + } else { + *byte + } + } + } + + fn case05_branchless(bytes: &mut [u8]) { + for byte in bytes { + *byte = branchless_to_ascii_upper_case(*byte) + } + } + + fn case06_libcore(bytes: &mut [u8]) { + bytes.make_ascii_uppercase() + } + + fn case07_fake_simd_u32(bytes: &mut [u8]) { + let (before, aligned, after) = unsafe { + bytes.align_to_mut::() + }; + for byte in before { + *byte = branchless_to_ascii_upper_case(*byte) + } + for word in aligned { + // FIXME: this is incorrect for some byte values: + // addition within a byte can carry/overflow into the next byte. + // Test case: b"\xFFz " + *word &= !( + ( + word.wrapping_add(0x1f1f1f1f) & + !word.wrapping_add(0x05050505) & + 0x80808080 + ) >> 2 + ) + } + for byte in after { + *byte = branchless_to_ascii_upper_case(*byte) + } + } + + fn case08_fake_simd_u64(bytes: &mut [u8]) { + let (before, aligned, after) = unsafe { + bytes.align_to_mut::() + }; + for byte in before { + *byte = branchless_to_ascii_upper_case(*byte) + } + for word in aligned { + // FIXME: like above, this is incorrect for some byte values. + *word &= !( + ( + word.wrapping_add(0x1f1f1f1f_1f1f1f1f) & + !word.wrapping_add(0x05050505_05050505) & + 0x80808080_80808080 + ) >> 2 + ) + } + for byte in after { + *byte = branchless_to_ascii_upper_case(*byte) + } + } + + fn case09_mask_mult_bool_branchy_lookup_table(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + if b >= 0x80 { return false } + match ASCII_CHARACTER_CLASS[b as usize] { + L | Lx => true, + _ => false, + } + } + for byte in bytes { + *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8)) + } + } + + fn case10_mask_mult_bool_lookup_table(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match ASCII_CHARACTER_CLASS[b as usize] { + L | Lx => true, + _ => false + } + } + for byte in bytes { + *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8)) + } + } + + fn case11_mask_mult_bool_match_range(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match b { + b'a'..=b'z' => true, + _ => false + } + } + for byte in bytes { + *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8)) + } + } + + fn case12_mask_shifted_bool_match_range(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match b { + b'a'..=b'z' => true, + _ => false + } + } + for byte in bytes { + *byte &= !((is_ascii_lowercase(*byte) as u8) << 5) + } + } + + fn case13_subtract_shifted_bool_match_range(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match b { + b'a'..=b'z' => true, + _ => false + } + } + for byte in bytes { + *byte -= (is_ascii_lowercase(*byte) as u8) << 5 + } + } + + fn case14_subtract_multiplied_bool_match_range(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match b { + b'a'..=b'z' => true, + _ => false + } + } + for byte in bytes { + *byte -= (b'a' - b'A') * is_ascii_lowercase(*byte) as u8 + } + } + + @iter + + is_ascii, + is_ascii_alphabetic, + is_ascii_uppercase, + is_ascii_lowercase, + is_ascii_alphanumeric, + is_ascii_digit, + is_ascii_hexdigit, + is_ascii_punctuation, + is_ascii_graphic, + is_ascii_whitespace, + is_ascii_control, +} + +macro_rules! repeat { + ($s: expr) => { concat!($s, $s, $s, $s, $s, $s, $s, $s, $s, $s) } +} + +const SHORT: &'static str = "Alice's"; +const MEDIUM: &'static str = "Alice's Adventures in Wonderland"; +const LONG: &'static str = repeat!(r#" + La Guida di Bragia, a Ballad Opera for the Marionette Theatre (around 1850) + Alice's Adventures in Wonderland (1865) + Phantasmagoria and Other Poems (1869) + Through the Looking-Glass, and What Alice Found There + (includes "Jabberwocky" and "The Walrus and the Carpenter") (1871) + The Hunting of the Snark (1876) + Rhyme? And Reason? (1883) – shares some contents with the 1869 collection, + including the long poem "Phantasmagoria" + A Tangled Tale (1885) + Sylvie and Bruno (1889) + Sylvie and Bruno Concluded (1893) + Pillow Problems (1893) + What the Tortoise Said to Achilles (1895) + Three Sunsets and Other Poems (1898) + The Manlet (1903)[106] +"#); + +const ASCII_UPPERCASE_MAP: [u8; 256] = [ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', + b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', + b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', + b'8', b'9', b':', b';', b'<', b'=', b'>', b'?', + b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G', + b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', + b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', + b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_', + b'`', + + b'A', b'B', b'C', b'D', b'E', b'F', b'G', + b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', + b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', + b'X', b'Y', b'Z', + + b'{', b'|', b'}', b'~', 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +]; + +enum AsciiCharacterClass { + C, // control + Cw, // control whitespace + W, // whitespace + D, // digit + L, // lowercase + Lx, // lowercase hex digit + U, // uppercase + Ux, // uppercase hex digit + P, // punctuation + N, // Non-ASCII +} +use self::AsciiCharacterClass::*; + +static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [ +// _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f + C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_ + C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_ + W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_ + D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_ + P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_ + U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_ + P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_ + L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_ + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, +]; diff --git a/src/libcore/benches/iter.rs b/src/libcore/benches/iter.rs index fe852e42b5cd3..7dcfad8306fce 100644 --- a/src/libcore/benches/iter.rs +++ b/src/libcore/benches/iter.rs @@ -35,7 +35,7 @@ fn scatter(x: i32) -> i32 { (x * 31) % 127 } fn bench_max_by_key(b: &mut Bencher) { b.iter(|| { let it = 0..100; - it.max_by_key(|&x| scatter(x)) + it.map(black_box).max_by_key(|&x| scatter(x)) }) } @@ -56,7 +56,7 @@ fn bench_max_by_key2(b: &mut Bencher) { fn bench_max(b: &mut Bencher) { b.iter(|| { let it = 0..100; - it.map(scatter).max() + it.map(black_box).map(scatter).max() }) } @@ -185,13 +185,13 @@ bench_sums! { bench_sums! { bench_filter_sum, bench_filter_ref_sum, - (0i64..1000000).filter(|x| x % 2 == 0) + (0i64..1000000).filter(|x| x % 3 == 0) } bench_sums! { bench_filter_chain_sum, bench_filter_chain_ref_sum, - (0i64..1000000).chain(0..1000000).filter(|x| x % 2 == 0) + (0i64..1000000).chain(0..1000000).filter(|x| x % 3 == 0) } bench_sums! { @@ -306,3 +306,41 @@ fn bench_skip_then_zip(b: &mut Bencher) { assert_eq!(s, 2009900); }); } + +#[bench] +fn bench_filter_count(b: &mut Bencher) { + b.iter(|| { + (0i64..1000000).map(black_box).filter(|x| x % 3 == 0).count() + }) +} + +#[bench] +fn bench_filter_ref_count(b: &mut Bencher) { + b.iter(|| { + (0i64..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count() + }) +} + +#[bench] +fn bench_filter_chain_count(b: &mut Bencher) { + b.iter(|| { + (0i64..1000000).chain(0..1000000).map(black_box).filter(|x| x % 3 == 0).count() + }) +} + +#[bench] +fn bench_filter_chain_ref_count(b: &mut Bencher) { + b.iter(|| { + (0i64..1000000).chain(0..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count() + }) +} + +#[bench] +fn bench_partial_cmp(b: &mut Bencher) { + b.iter(|| (0..100000).map(black_box).partial_cmp((0..100000).map(black_box))) +} + +#[bench] +fn bench_lt(b: &mut Bencher) { + b.iter(|| (0..100000).map(black_box).lt((0..100000).map(black_box))) +} diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs index 48572af611a5b..dea2963d9ac83 100644 --- a/src/libcore/benches/lib.rs +++ b/src/libcore/benches/lib.rs @@ -1,10 +1,10 @@ #![feature(flt2dec)] #![feature(test)] -extern crate core; extern crate test; mod any; +mod ascii; mod char; mod hash; mod iter; diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 89668dc06505b..4d58aaca94183 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -32,6 +32,10 @@ /// on the identical behavior of these additional trait implementations. /// These traits will likely appear as additional trait bounds. /// +/// In particular `Eq`, `Ord` and `Hash` must be equivalent for +/// borrowed and owned values: `x.borrow() == y.borrow()` should give the +/// same result as `x == y`. +/// /// If generic code merely needs to work for all types that can /// provide a reference to related type `T`, it is often better to use /// [`AsRef`] as more types can safely implement it. diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 8383d305518ab..beafddc5a1019 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -11,7 +11,7 @@ //! mutate it. //! //! Shareable mutable containers exist to permit mutability in a controlled manner, even in the -//! presence of aliasing. Both `Cell` and `RefCell` allows to do this in a single threaded +//! presence of aliasing. Both `Cell` and `RefCell` allow doing this in a single-threaded //! way. However, neither `Cell` nor `RefCell` are thread safe (they do not implement //! `Sync`). If you need to do aliasing and mutation between multiple threads it is possible to //! use [`Mutex`](../../std/sync/struct.Mutex.html), @@ -67,16 +67,26 @@ //! mutability: //! //! ``` +//! use std::cell::{RefCell, RefMut}; //! use std::collections::HashMap; -//! use std::cell::RefCell; //! use std::rc::Rc; //! //! fn main() { //! let shared_map: Rc> = Rc::new(RefCell::new(HashMap::new())); -//! shared_map.borrow_mut().insert("africa", 92388); -//! shared_map.borrow_mut().insert("kyoto", 11837); -//! shared_map.borrow_mut().insert("piccadilly", 11826); -//! shared_map.borrow_mut().insert("marbles", 38); +//! // Create a new block to limit the scope of the dynamic borrow +//! { +//! let mut map: RefMut<_> = shared_map.borrow_mut(); +//! map.insert("africa", 92388); +//! map.insert("kyoto", 11837); +//! map.insert("piccadilly", 11826); +//! map.insert("marbles", 38); +//! } +//! +//! // Note that if we had not let the previous borrow of the cache fall out +//! // of scope then the subsequent borrow would cause a dynamic thread panic. +//! // This is the major hazard of using `RefCell`. +//! let total: i32 = shared_map.borrow().values().sum(); +//! println!("{}", total); //! } //! ``` //! @@ -102,27 +112,15 @@ //! //! impl Graph { //! fn minimum_spanning_tree(&self) -> Vec<(i32, i32)> { -//! // Create a new scope to contain the lifetime of the -//! // dynamic borrow -//! { -//! // Take a reference to the inside of cache cell -//! let mut cache = self.span_tree_cache.borrow_mut(); -//! if cache.is_some() { -//! return cache.as_ref().unwrap().clone(); -//! } -//! -//! let span_tree = self.calc_span_tree(); -//! *cache = Some(span_tree); -//! } +//! self.span_tree_cache.borrow_mut() +//! .get_or_insert_with(|| self.calc_span_tree()) +//! .clone() +//! } //! -//! // Recursive call to return the just-cached value. -//! // Note that if we had not let the previous borrow -//! // of the cache fall out of scope then the subsequent -//! // recursive borrow would cause a dynamic thread panic. -//! // This is the major hazard of using `RefCell`. -//! self.minimum_spanning_tree() +//! fn calc_span_tree(&self) -> Vec<(i32, i32)> { +//! // Expensive computation goes here +//! vec![] //! } -//! # fn calc_span_tree(&self) -> Vec<(i32, i32)> { vec![] } //! } //! ``` //! @@ -186,12 +184,12 @@ #![stable(feature = "rust1", since = "1.0.0")] -use cmp::Ordering; -use fmt::{self, Debug, Display}; -use marker::Unsize; -use mem; -use ops::{Deref, DerefMut, CoerceUnsized}; -use ptr; +use crate::cmp::Ordering; +use crate::fmt::{self, Debug, Display}; +use crate::marker::Unsize; +use crate::mem; +use crate::ops::{Deref, DerefMut, CoerceUnsized}; +use crate::ptr; /// A mutable memory location. /// @@ -496,7 +494,6 @@ impl Cell { /// # Examples /// /// ``` - /// #![feature(as_cell)] /// use std::cell::Cell; /// /// let slice: &mut [i32] = &mut [1, 2, 3]; @@ -506,7 +503,7 @@ impl Cell { /// assert_eq!(slice_cell.len(), 3); /// ``` #[inline] - #[unstable(feature = "as_cell", issue="43038")] + #[stable(feature = "as_cell", since = "1.37.0")] pub fn from_mut(t: &mut T) -> &Cell { unsafe { &*(t as *mut T as *const Cell) @@ -543,7 +540,6 @@ impl Cell<[T]> { /// # Examples /// /// ``` - /// #![feature(as_cell)] /// use std::cell::Cell; /// /// let slice: &mut [i32] = &mut [1, 2, 3]; @@ -552,7 +548,7 @@ impl Cell<[T]> { /// /// assert_eq!(slice_cell.len(), 3); /// ``` - #[unstable(feature = "as_cell", issue="43038")] + #[stable(feature = "as_cell", since = "1.37.0")] pub fn as_slice_of_cells(&self) -> &[Cell] { unsafe { &*(self as *const Cell<[T]> as *const [Cell]) @@ -577,14 +573,14 @@ pub struct BorrowError { #[stable(feature = "try_borrow", since = "1.13.0")] impl Debug for BorrowError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("BorrowError").finish() } } #[stable(feature = "try_borrow", since = "1.13.0")] impl Display for BorrowError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt("already mutably borrowed", f) } } @@ -597,14 +593,14 @@ pub struct BorrowMutError { #[stable(feature = "try_borrow", since = "1.13.0")] impl Debug for BorrowMutError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("BorrowMutError").finish() } } #[stable(feature = "try_borrow", since = "1.13.0")] impl Display for BorrowMutError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt("already borrowed", f) } } @@ -702,8 +698,6 @@ impl RefCell { /// Replaces the wrapped value with a new one computed from `f`, returning /// the old value, without deinitializing either one. /// - /// This function corresponds to [`std::mem::replace`](../mem/fn.replace.html). - /// /// # Panics /// /// Panics if the value is currently borrowed. @@ -711,7 +705,6 @@ impl RefCell { /// # Examples /// /// ``` - /// #![feature(refcell_replace_swap)] /// use std::cell::RefCell; /// let cell = RefCell::new(5); /// let old_value = cell.replace_with(|&mut old| old + 1); @@ -719,7 +712,7 @@ impl RefCell { /// assert_eq!(cell, RefCell::new(6)); /// ``` #[inline] - #[unstable(feature = "refcell_replace_swap", issue="43570")] + #[stable(feature = "refcell_replace_swap", since="1.35.0")] pub fn replace_with T>(&self, f: F) -> T { let mut_borrow = &mut *self.borrow_mut(); let replacement = f(mut_borrow); @@ -791,7 +784,7 @@ impl RefCell { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn borrow(&self) -> Ref { + pub fn borrow(&self) -> Ref<'_, T> { self.try_borrow().expect("already mutably borrowed") } @@ -822,7 +815,7 @@ impl RefCell { /// ``` #[stable(feature = "try_borrow", since = "1.13.0")] #[inline] - pub fn try_borrow(&self) -> Result, BorrowError> { + pub fn try_borrow(&self) -> Result, BorrowError> { match BorrowRef::new(&self.borrow) { Some(b) => Ok(Ref { value: unsafe { &*self.value.get() }, @@ -872,7 +865,7 @@ impl RefCell { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn borrow_mut(&self) -> RefMut { + pub fn borrow_mut(&self) -> RefMut<'_, T> { self.try_borrow_mut().expect("already borrowed") } @@ -900,7 +893,7 @@ impl RefCell { /// ``` #[stable(feature = "try_borrow", since = "1.13.0")] #[inline] - pub fn try_borrow_mut(&self) -> Result, BorrowMutError> { + pub fn try_borrow_mut(&self) -> Result, BorrowMutError> { match BorrowRefMut::new(&self.borrow) { Some(b) => Ok(RefMut { value: unsafe { &mut *self.value.get() }, @@ -958,6 +951,43 @@ impl RefCell { &mut *self.value.get() } } + + /// Immutably borrows the wrapped value, returning an error if the value is + /// currently mutably borrowed. + /// + /// # Safety + /// + /// Unlike `RefCell::borrow`, this method is unsafe because it does not + /// return a `Ref`, thus leaving the borrow flag untouched. Mutably + /// borrowing the `RefCell` while the reference returned by this method + /// is alive is undefined behaviour. + /// + /// # Examples + /// + /// ``` + /// use std::cell::RefCell; + /// + /// let c = RefCell::new(5); + /// + /// { + /// let m = c.borrow_mut(); + /// assert!(unsafe { c.try_borrow_unguarded() }.is_err()); + /// } + /// + /// { + /// let m = c.borrow(); + /// assert!(unsafe { c.try_borrow_unguarded() }.is_ok()); + /// } + /// ``` + #[stable(feature = "borrow_state", since = "1.37.0")] + #[inline] + pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> { + if !is_writing(self.borrow.get()) { + Ok(&*self.value.get()) + } else { + Err(BorrowError { _private: () }) + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1186,7 +1216,6 @@ impl<'b, T: ?Sized> Ref<'b, T> { /// # Examples /// /// ``` - /// #![feature(refcell_map_split)] /// use std::cell::{Ref, RefCell}; /// /// let cell = RefCell::new([1, 2, 3, 4]); @@ -1195,7 +1224,7 @@ impl<'b, T: ?Sized> Ref<'b, T> { /// assert_eq!(*begin, [1, 2]); /// assert_eq!(*end, [3, 4]); /// ``` - #[unstable(feature = "refcell_map_split", issue = "51476")] + #[stable(feature = "refcell_map_split", since = "1.35.0")] #[inline] pub fn map_split(orig: Ref<'b, T>, f: F) -> (Ref<'b, U>, Ref<'b, V>) where F: FnOnce(&T) -> (&U, &V) @@ -1211,7 +1240,7 @@ impl<'b, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for Ref<'b, #[stable(feature = "std_guard_impls", since = "1.20.0")] impl fmt::Display for Ref<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.value.fmt(f) } } @@ -1268,7 +1297,6 @@ impl<'b, T: ?Sized> RefMut<'b, T> { /// # Examples /// /// ``` - /// #![feature(refcell_map_split)] /// use std::cell::{RefCell, RefMut}; /// /// let cell = RefCell::new([1, 2, 3, 4]); @@ -1279,7 +1307,7 @@ impl<'b, T: ?Sized> RefMut<'b, T> { /// begin.copy_from_slice(&[4, 3]); /// end.copy_from_slice(&[2, 1]); /// ``` - #[unstable(feature = "refcell_map_split", issue = "51476")] + #[stable(feature = "refcell_map_split", since = "1.35.0")] #[inline] pub fn map_split( orig: RefMut<'b, T>, f: F @@ -1321,7 +1349,7 @@ impl<'b> BorrowRefMut<'b> { } } - // Clone a `BorrowRefMut`. + // Clones a `BorrowRefMut`. // // This is only valid if each `BorrowRefMut` is used to track a mutable // reference to a distinct, nonoverlapping range of the original object. @@ -1369,7 +1397,7 @@ impl<'b, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for RefM #[stable(feature = "std_guard_impls", since = "1.20.0")] impl fmt::Display for RefMut<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.value.fmt(f) } } @@ -1423,7 +1451,6 @@ impl fmt::Display for RefMut<'_, T> { /// /// ``` /// use std::cell::UnsafeCell; -/// use std::marker::Sync; /// /// # #[allow(dead_code)] /// struct NotThreadSafe { diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs index 6a5abfb408f5b..0a870c67518c7 100644 --- a/src/libcore/char/convert.rs +++ b/src/libcore/char/convert.rs @@ -1,9 +1,10 @@ //! Character conversions. -use convert::TryFrom; -use fmt; -use mem::transmute; -use str::FromStr; +use crate::convert::TryFrom; +use crate::fmt; +use crate::mem::transmute; +use crate::str::FromStr; + use super::MAX; /// Converts a `u32` to a `char`. @@ -122,7 +123,7 @@ impl From for u32 { } } -/// Maps a byte in 0x00...0xFF to a `char` whose code point has the same value, in U+0000 to U+00FF. +/// Maps a byte in 0x00..=0xFF to a `char` whose code point has the same value, in U+0000..=U+00FF. /// /// Unicode is designed such that this effectively decodes bytes /// with the character encoding that IANA calls ISO-8859-1. @@ -192,7 +193,7 @@ enum CharErrorKind { #[stable(feature = "char_from_str", since = "1.20.0")] impl fmt::Display for ParseCharError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.__description().fmt(f) } } @@ -239,7 +240,7 @@ pub struct CharTryFromError(()); #[stable(feature = "try_from", since = "1.34.0")] impl fmt::Display for CharTryFromError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "converted integer out of range for `char`".fmt(f) } } @@ -315,4 +316,3 @@ pub fn from_digit(num: u32, radix: u32) -> Option { None } } - diff --git a/src/libcore/char/decode.rs b/src/libcore/char/decode.rs index 133c9169df858..23059243c61d7 100644 --- a/src/libcore/char/decode.rs +++ b/src/libcore/char/decode.rs @@ -1,6 +1,7 @@ //! UTF-8 and UTF-16 decoding iterators -use fmt; +use crate::fmt; + use super::from_u32_unchecked; /// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. @@ -127,7 +128,7 @@ impl DecodeUtf16Error { #[stable(feature = "decode_utf16", since = "1.9.0")] impl fmt::Display for DecodeUtf16Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "unpaired surrogate found: {:x}", self.code) } } diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 122e5f3affdc2..e843303380ad0 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -1,10 +1,11 @@ //! impl char {} -use slice; -use str::from_utf8_unchecked_mut; +use crate::slice; +use crate::str::from_utf8_unchecked_mut; +use crate::unicode::printable::is_printable; +use crate::unicode::tables::{conversions, derived_property, general_category, property}; + use super::*; -use unicode::printable::is_printable; -use unicode::tables::{conversions, derived_property, general_category, property}; #[lang = "char"] impl char { @@ -336,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()); @@ -1041,8 +1042,8 @@ impl char { /// Checks if the value is an ASCII alphabetic character: /// - /// - U+0041 'A' ... U+005A 'Z', or - /// - U+0061 'a' ... U+007A 'z'. + /// - U+0041 'A' ..= U+005A 'Z', or + /// - U+0061 'a' ..= U+007A 'z'. /// /// # Examples /// @@ -1074,7 +1075,7 @@ impl char { } /// Checks if the value is an ASCII uppercase character: - /// U+0041 'A' ... U+005A 'Z'. + /// U+0041 'A' ..= U+005A 'Z'. /// /// # Examples /// @@ -1106,7 +1107,7 @@ impl char { } /// Checks if the value is an ASCII lowercase character: - /// U+0061 'a' ... U+007A 'z'. + /// U+0061 'a' ..= U+007A 'z'. /// /// # Examples /// @@ -1139,9 +1140,9 @@ impl char { /// Checks if the value is an ASCII alphanumeric character: /// - /// - U+0041 'A' ... U+005A 'Z', or - /// - U+0061 'a' ... U+007A 'z', or - /// - U+0030 '0' ... U+0039 '9'. + /// - U+0041 'A' ..= U+005A 'Z', or + /// - U+0061 'a' ..= U+007A 'z', or + /// - U+0030 '0' ..= U+0039 '9'. /// /// # Examples /// @@ -1173,7 +1174,7 @@ impl char { } /// Checks if the value is an ASCII decimal digit: - /// U+0030 '0' ... U+0039 '9'. + /// U+0030 '0' ..= U+0039 '9'. /// /// # Examples /// @@ -1206,9 +1207,9 @@ impl char { /// Checks if the value is an ASCII hexadecimal digit: /// - /// - U+0030 '0' ... U+0039 '9', or - /// - U+0041 'A' ... U+0046 'F', or - /// - U+0061 'a' ... U+0066 'f'. + /// - U+0030 '0' ..= U+0039 '9', or + /// - U+0041 'A' ..= U+0046 'F', or + /// - U+0061 'a' ..= U+0066 'f'. /// /// # Examples /// @@ -1241,10 +1242,10 @@ impl char { /// Checks if the value is an ASCII punctuation character: /// - /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or - /// - U+003A ... U+0040 `: ; < = > ? @`, or - /// - U+005B ... U+0060 ``[ \ ] ^ _ ` ``, or - /// - U+007B ... U+007E `{ | } ~` + /// - U+0021 ..= U+002F `! " # $ % & ' ( ) * + , - . /`, or + /// - U+003A ..= U+0040 `: ; < = > ? @`, or + /// - U+005B ..= U+0060 ``[ \ ] ^ _ ` ``, or + /// - U+007B ..= U+007E `{ | } ~` /// /// # Examples /// @@ -1276,7 +1277,7 @@ impl char { } /// Checks if the value is an ASCII graphic character: - /// U+0021 '!' ... U+007E '~'. + /// U+0021 '!' ..= U+007E '~'. /// /// # Examples /// @@ -1357,7 +1358,7 @@ impl char { } /// Checks if the value is an ASCII control character: - /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE. + /// U+0000 NUL ..= U+001F UNIT SEPARATOR, or U+007F DELETE. /// Note that most ASCII whitespace characters are control /// characters, but SPACE is not. /// diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index f3369c4d94010..dedd2f758b6cb 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -37,12 +37,12 @@ pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; // unstable re-exports #[unstable(feature = "unicode_version", issue = "49726")] -pub use unicode::tables::UNICODE_VERSION; +pub use crate::unicode::tables::UNICODE_VERSION; #[unstable(feature = "unicode_version", issue = "49726")] -pub use unicode::version::UnicodeVersion; +pub use crate::unicode::version::UnicodeVersion; -use fmt::{self, Write}; -use iter::FusedIterator; +use crate::fmt::{self, Write}; +use crate::iter::FusedIterator; // UTF-8 ranges and tags for encoding characters const TAG_CONT: u8 = 0b1000_0000; @@ -220,7 +220,7 @@ impl FusedIterator for EscapeUnicode {} #[stable(feature = "char_struct_display", since = "1.16.0")] impl fmt::Display for EscapeUnicode { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for c in self.clone() { f.write_char(c)?; } @@ -333,7 +333,7 @@ impl FusedIterator for EscapeDefault {} #[stable(feature = "char_struct_display", since = "1.16.0")] impl fmt::Display for EscapeDefault { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for c in self.clone() { f.write_char(c)?; } @@ -367,7 +367,7 @@ impl FusedIterator for EscapeDebug {} #[stable(feature = "char_escape_debug", since = "1.20.0")] impl fmt::Display for EscapeDebug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } @@ -389,11 +389,17 @@ impl Iterator for ToLowercase { fn next(&mut self) -> Option { self.0.next() } + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } } #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ToLowercase {} +#[stable(feature = "exact_size_case_mapping_iter", since = "1.35.0")] +impl ExactSizeIterator for ToLowercase {} + /// Returns an iterator that yields the uppercase equivalent of a `char`. /// /// This `struct` is created by the [`to_uppercase`] method on [`char`]. See @@ -411,11 +417,17 @@ impl Iterator for ToUppercase { fn next(&mut self) -> Option { self.0.next() } + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } } #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ToUppercase {} +#[stable(feature = "exact_size_case_mapping_iter", since = "1.35.0")] +impl ExactSizeIterator for ToUppercase {} + #[derive(Debug, Clone)] enum CaseMappingIter { Three(char, char, char), @@ -457,10 +469,20 @@ impl Iterator for CaseMappingIter { CaseMappingIter::Zero => None, } } + + fn size_hint(&self) -> (usize, Option) { + let size = match self { + CaseMappingIter::Three(..) => 3, + CaseMappingIter::Two(..) => 2, + CaseMappingIter::One(_) => 1, + CaseMappingIter::Zero => 0, + }; + (size, Some(size)) + } } impl fmt::Display for CaseMappingIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { CaseMappingIter::Three(a, b, c) => { f.write_char(a)?; @@ -481,14 +503,14 @@ impl fmt::Display for CaseMappingIter { #[stable(feature = "char_struct_display", since = "1.16.0")] impl fmt::Display for ToLowercase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } #[stable(feature = "char_struct_display", since = "1.16.0")] impl fmt::Display for ToUppercase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index ed90b7de26417..9e32acb97d360 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -142,13 +142,13 @@ pub trait Clone : Sized { #[unstable(feature = "derive_clone_copy", reason = "deriving hack, should not be public", issue = "0")] -pub struct AssertParamIsClone { _field: ::marker::PhantomData } +pub struct AssertParamIsClone { _field: crate::marker::PhantomData } #[doc(hidden)] #[allow(missing_debug_implementations)] #[unstable(feature = "derive_clone_copy", reason = "deriving hack, should not be public", issue = "0")] -pub struct AssertParamIsCopy { _field: ::marker::PhantomData } +pub struct AssertParamIsCopy { _field: crate::marker::PhantomData } /// Implementations of `Clone` for primitive types. /// diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 81fcdeee12d29..59088e4329177 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -72,7 +72,7 @@ use self::Ordering::*; /// } /// /// impl PartialEq for Book { -/// fn eq(&self, other: &Book) -> bool { +/// fn eq(&self, other: &Self) -> bool { /// self.isbn == other.isbn /// } /// } @@ -233,7 +233,7 @@ pub trait PartialEq { /// format: BookFormat, /// } /// impl PartialEq for Book { -/// fn eq(&self, other: &Book) -> bool { +/// fn eq(&self, other: &Self) -> bool { /// self.isbn == other.isbn /// } /// } @@ -265,7 +265,7 @@ pub trait Eq: PartialEq { #[unstable(feature = "derive_eq", reason = "deriving hack, should not be public", issue = "0")] -pub struct AssertParamIsEq { _field: ::marker::PhantomData } +pub struct AssertParamIsEq { _field: crate::marker::PhantomData } /// An `Ordering` is the result of a comparison between two values. /// @@ -286,13 +286,13 @@ pub struct AssertParamIsEq { _field: ::marker::PhantomData } #[derive(Clone, Copy, PartialEq, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Ordering { - /// An ordering where a compared value is less [than another]. + /// An ordering where a compared value is less than another. #[stable(feature = "rust1", since = "1.0.0")] Less = -1, - /// An ordering where a compared value is equal [to another]. + /// An ordering where a compared value is equal to another. #[stable(feature = "rust1", since = "1.0.0")] Equal = 0, - /// An ordering where a compared value is greater [than another]. + /// An ordering where a compared value is greater than another. #[stable(feature = "rust1", since = "1.0.0")] Greater = 1, } @@ -493,19 +493,19 @@ impl Ord for Reverse { /// } /// /// impl Ord for Person { -/// fn cmp(&self, other: &Person) -> Ordering { +/// fn cmp(&self, other: &Self) -> Ordering { /// self.height.cmp(&other.height) /// } /// } /// /// impl PartialOrd for Person { -/// fn partial_cmp(&self, other: &Person) -> Option { +/// fn partial_cmp(&self, other: &Self) -> Option { /// Some(self.cmp(other)) /// } /// } /// /// impl PartialEq for Person { -/// fn eq(&self, other: &Person) -> bool { +/// fn eq(&self, other: &Self) -> bool { /// self.height == other.height /// } /// } @@ -567,6 +567,37 @@ pub trait Ord: Eq + PartialOrd { where Self: Sized { if self <= other { self } else { other } } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where Self: Sized { + assert!(min <= max); + if self < min { + min + } else if self > max { + max + } else { + self + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -665,13 +696,13 @@ impl PartialOrd for Ordering { /// } /// /// impl PartialOrd for Person { -/// fn partial_cmp(&self, other: &Person) -> Option { +/// fn partial_cmp(&self, other: &Self) -> Option { /// self.height.partial_cmp(&other.height) /// } /// } /// /// impl PartialEq for Person { -/// fn eq(&self, other: &Person) -> bool { +/// fn eq(&self, other: &Self) -> bool { /// self.height == other.height /// } /// } @@ -853,7 +884,7 @@ pub fn max(v1: T, v2: T) -> T { // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types mod impls { - use cmp::Ordering::{self, Less, Greater, Equal}; + use crate::cmp::Ordering::{self, Less, Greater, Equal}; macro_rules! partial_eq_impl { ($($t:ty)*) => ($( @@ -1004,26 +1035,26 @@ mod impls { // & pointers #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A: ?Sized, B: ?Sized> PartialEq<&'b B> for &'a A where A: PartialEq { + impl PartialEq<&B> for &A where A: PartialEq { #[inline] - fn eq(&self, other: & &'b B) -> bool { PartialEq::eq(*self, *other) } + fn eq(&self, other: & &B) -> bool { PartialEq::eq(*self, *other) } #[inline] - fn ne(&self, other: & &'b B) -> bool { PartialEq::ne(*self, *other) } + fn ne(&self, other: & &B) -> bool { PartialEq::ne(*self, *other) } } #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A: ?Sized, B: ?Sized> PartialOrd<&'b B> for &'a A where A: PartialOrd { + impl PartialOrd<&B> for &A where A: PartialOrd { #[inline] - fn partial_cmp(&self, other: &&'b B) -> Option { + fn partial_cmp(&self, other: &&B) -> Option { PartialOrd::partial_cmp(*self, *other) } #[inline] - fn lt(&self, other: & &'b B) -> bool { PartialOrd::lt(*self, *other) } + fn lt(&self, other: & &B) -> bool { PartialOrd::lt(*self, *other) } #[inline] - fn le(&self, other: & &'b B) -> bool { PartialOrd::le(*self, *other) } + fn le(&self, other: & &B) -> bool { PartialOrd::le(*self, *other) } #[inline] - fn ge(&self, other: & &'b B) -> bool { PartialOrd::ge(*self, *other) } + fn ge(&self, other: & &B) -> bool { PartialOrd::ge(*self, *other) } #[inline] - fn gt(&self, other: & &'b B) -> bool { PartialOrd::gt(*self, *other) } + fn gt(&self, other: & &B) -> bool { PartialOrd::gt(*self, *other) } } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for &A where A: Ord { @@ -1036,26 +1067,26 @@ mod impls { // &mut pointers #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A: ?Sized, B: ?Sized> PartialEq<&'b mut B> for &'a mut A where A: PartialEq { + impl PartialEq<&mut B> for &mut A where A: PartialEq { #[inline] - fn eq(&self, other: &&'b mut B) -> bool { PartialEq::eq(*self, *other) } + fn eq(&self, other: &&mut B) -> bool { PartialEq::eq(*self, *other) } #[inline] - fn ne(&self, other: &&'b mut B) -> bool { PartialEq::ne(*self, *other) } + fn ne(&self, other: &&mut B) -> bool { PartialEq::ne(*self, *other) } } #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A: ?Sized, B: ?Sized> PartialOrd<&'b mut B> for &'a mut A where A: PartialOrd { + impl PartialOrd<&mut B> for &mut A where A: PartialOrd { #[inline] - fn partial_cmp(&self, other: &&'b mut B) -> Option { + fn partial_cmp(&self, other: &&mut B) -> Option { PartialOrd::partial_cmp(*self, *other) } #[inline] - fn lt(&self, other: &&'b mut B) -> bool { PartialOrd::lt(*self, *other) } + fn lt(&self, other: &&mut B) -> bool { PartialOrd::lt(*self, *other) } #[inline] - fn le(&self, other: &&'b mut B) -> bool { PartialOrd::le(*self, *other) } + fn le(&self, other: &&mut B) -> bool { PartialOrd::le(*self, *other) } #[inline] - fn ge(&self, other: &&'b mut B) -> bool { PartialOrd::ge(*self, *other) } + fn ge(&self, other: &&mut B) -> bool { PartialOrd::ge(*self, *other) } #[inline] - fn gt(&self, other: &&'b mut B) -> bool { PartialOrd::gt(*self, *other) } + fn gt(&self, other: &&mut B) -> bool { PartialOrd::gt(*self, *other) } } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for &mut A where A: Ord { @@ -1066,18 +1097,18 @@ mod impls { impl Eq for &mut A where A: Eq {} #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A: ?Sized, B: ?Sized> PartialEq<&'b mut B> for &'a A where A: PartialEq { + impl PartialEq<&mut B> for &A where A: PartialEq { #[inline] - fn eq(&self, other: &&'b mut B) -> bool { PartialEq::eq(*self, *other) } + fn eq(&self, other: &&mut B) -> bool { PartialEq::eq(*self, *other) } #[inline] - fn ne(&self, other: &&'b mut B) -> bool { PartialEq::ne(*self, *other) } + fn ne(&self, other: &&mut B) -> bool { PartialEq::ne(*self, *other) } } #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A: ?Sized, B: ?Sized> PartialEq<&'b B> for &'a mut A where A: PartialEq { + impl PartialEq<&B> for &mut A where A: PartialEq { #[inline] - fn eq(&self, other: &&'b B) -> bool { PartialEq::eq(*self, *other) } + fn eq(&self, other: &&B) -> bool { PartialEq::eq(*self, *other) } #[inline] - fn ne(&self, other: &&'b B) -> bool { PartialEq::ne(*self, *other) } + fn ne(&self, other: &&B) -> bool { PartialEq::ne(*self, *other) } } } diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 5ecfa9cde032e..a697b7bd6e589 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -1,26 +1,25 @@ //! Traits for conversions between types. //! -//! The traits in this module provide a general way to talk about conversions -//! from one type to another. They follow the standard Rust conventions of -//! `as`/`into`/`from`. +//! The traits in this module provide a way to convert from one type to another type. +//! Each trait serves a different purpose: //! -//! Like many traits, these are often used as bounds for generic functions, to -//! support arguments of multiple types. +//! - Implement the [`AsRef`] trait for cheap reference-to-reference conversions +//! - Implement the [`AsMut`] trait for cheap mutable-to-mutable conversions +//! - Implement the [`From`] trait for consuming value-to-value conversions +//! - Implement the [`Into`] trait for consuming value-to-value conversions to types +//! outside the current crate +//! - The [`TryFrom`] and [`TryInto`] traits behave like [`From`] and [`Into`], +//! but should be implemented when the conversion can fail. //! -//! - Implement the `As*` traits for reference-to-reference conversions -//! - Implement the [`Into`] trait when you want to consume the value in the conversion -//! - The [`From`] trait is the most flexible, useful for value _and_ reference conversions -//! - The [`TryFrom`] and [`TryInto`] traits behave like [`From`] and [`Into`], but allow for the -//! conversion to fail +//! The traits in this module are often used as trait bounds for generic functions such that to +//! arguments of multiple types are supported. See the documentation of each trait for examples. //! -//! As a library author, you should prefer implementing [`From`][`From`] or +//! As a library author, you should always prefer implementing [`From`][`From`] or //! [`TryFrom`][`TryFrom`] rather than [`Into`][`Into`] or [`TryInto`][`TryInto`], //! as [`From`] and [`TryFrom`] provide greater flexibility and offer //! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a -//! blanket implementation in the standard library. However, there are some cases -//! where this is not possible, such as creating conversions into a type defined -//! outside your library, so implementing [`Into`] instead of [`From`] is -//! sometimes necessary. +//! blanket implementation in the standard library. Only implement [`Into`] or [`TryInto`] +//! when a conversion to a type outside the current crate is required. //! //! # Generic Implementations //! @@ -41,7 +40,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fmt; +use crate::fmt; /// An identity function. /// @@ -99,28 +98,23 @@ use fmt; #[inline] pub const fn identity(x: T) -> T { x } -/// A cheap reference-to-reference conversion. Used to convert a value to a -/// reference value within generic code. +/// Used to do a cheap reference-to-reference conversion. /// -/// `AsRef` is very similar to, but serves a slightly different purpose than, -/// [`Borrow`]. +/// This trait is similar to [`AsMut`] which is used for converting between mutable references. +/// If you need to do a costly conversion it is better to implement [`From`] with type +/// `&T` or write a custom function. /// -/// `AsRef` is to be used when wishing to convert to a reference of another -/// type. -/// `Borrow` is more related to the notion of taking the reference. It is -/// useful when wishing to abstract over the type of reference -/// (`&T`, `&mut T`) or allow both the referenced and owned type to be treated -/// in the same manner. +/// `AsRef` has the same signature as [`Borrow`], but `Borrow` is different in few aspects: /// -/// The key difference between the two traits is the intention: -/// -/// - Use `AsRef` when the goal is to simply convert into a reference -/// - Use `Borrow` when the goal is related to writing code that is agnostic to -/// the type of borrow and whether it is a reference or value +/// - Unlike `AsRef`, `Borrow` has a blanket impl for any `T`, and can be used to accept either +/// a reference or a value. +/// - `Borrow` also requires that `Hash`, `Eq` and `Ord` for borrowed value are +/// equivalent to those of the owned value. For this reason, if you want to +/// borrow only a single field of a struct you can implement `AsRef`, but not `Borrow`. /// /// [`Borrow`]: ../../std/borrow/trait.Borrow.html /// -/// **Note: this trait must not fail**. If the conversion can fail, use a +/// **Note: This trait must not fail**. If the conversion can fail, use a /// dedicated method which returns an [`Option`] or a [`Result`]. /// /// [`Option`]: ../../std/option/enum.Option.html @@ -134,7 +128,12 @@ pub const fn identity(x: T) -> T { x } /// /// # Examples /// -/// Both [`String`] and `&str` implement `AsRef`: +/// By using trait bounds we can accept arguments of different types as long as they can be +/// converted to the specified type `T`. +/// +/// For example: By creating a generic function that takes an `AsRef` we express that we +/// want to accept all references that can be converted to `&str` as an argument. +/// Since both [`String`] and `&str` implement `AsRef` we can accept both as input argument. /// /// [`String`]: ../../std/string/struct.String.html /// @@ -149,7 +148,6 @@ pub const fn identity(x: T) -> T { x } /// let s = "hello".to_string(); /// is_hello(s); /// ``` -/// #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRef { /// Performs the conversion. @@ -157,12 +155,13 @@ pub trait AsRef { fn as_ref(&self) -> &T; } -/// A cheap, mutable reference-to-mutable reference conversion. +/// Used to do a cheap mutable-to-mutable reference conversion. /// -/// This trait is similar to `AsRef` but used for converting between mutable -/// references. +/// This trait is similar to [`AsRef`] but used for converting between mutable +/// references. If you need to do a costly conversion it is better to +/// implement [`From`] with type `&mut T` or write a custom function. /// -/// **Note: this trait must not fail**. If the conversion can fail, use a +/// **Note: This trait must not fail**. If the conversion can fail, use a /// dedicated method which returns an [`Option`] or a [`Result`]. /// /// [`Option`]: ../../std/option/enum.Option.html @@ -176,9 +175,11 @@ pub trait AsRef { /// /// # Examples /// -/// [`Box`] implements `AsMut`: -/// -/// [`Box`]: ../../std/boxed/struct.Box.html +/// Using `AsMut` as trait bound for a generic function we can accept all mutable references +/// that can be converted to type `&mut T`. Because [`Box`] implements `AsMut` we can +/// write a function `add_one` that takes all arguments that can be converted to `&mut u64`. +/// Because [`Box`] implements `AsMut`, `add_one` accepts arguments of type +/// `&mut Box` as well: /// /// ``` /// fn add_one>(num: &mut T) { @@ -190,7 +191,7 @@ pub trait AsRef { /// assert_eq!(*boxed_num, 1); /// ``` /// -/// +/// [`Box`]: ../../std/boxed/struct.Box.html #[stable(feature = "rust1", since = "1.0.0")] pub trait AsMut { /// Performs the conversion. @@ -198,29 +199,27 @@ pub trait AsMut { fn as_mut(&mut self) -> &mut T; } -/// A conversion that consumes `self`, which may or may not be expensive. The -/// reciprocal of [`From`][From]. +/// A value-to-value conversion that consumes the input value. The +/// opposite of [`From`]. /// -/// **Note: this trait must not fail**. If the conversion can fail, use -/// [`TryInto`] or a dedicated method which returns an [`Option`] or a -/// [`Result`]. +/// One should only implement [`Into`] if a conversion to a type outside the current crate is +/// required. Otherwise one should always prefer implementing [`From`] over [`Into`] because +/// implementing [`From`] automatically provides one with a implementation of [`Into`] thanks to +/// the blanket implementation in the standard library. [`From`] cannot do these type of +/// conversions because of Rust's orphaning rules. /// -/// Library authors should not directly implement this trait, but should prefer -/// implementing the [`From`][From] trait, which offers greater flexibility and -/// provides an equivalent `Into` implementation for free, thanks to a blanket -/// implementation in the standard library. +/// **Note: This trait must not fail**. If the conversion can fail, use [`TryInto`]. /// /// # Generic Implementations /// -/// - [`From`][From]` for U` implies `Into for T` -/// - [`into`] is reflexive, which means that `Into for T` is implemented +/// - [`From`]` for U` implies `Into for T` +/// - [`Into`] is reflexive, which means that `Into for T` is implemented /// -/// # Implementing `Into` +/// # Implementing [`Into`] for conversions to external types /// -/// There is one exception to implementing `Into`, and it's kind of esoteric. -/// If the destination type is not part of the current crate, and it uses a -/// generic variable, then you can't implement `From` directly. For example, -/// take this crate: +/// If the destination type is not part of the current crate +/// then you can't implement [`From`] directly. +/// For example, take this code: /// /// ```compile_fail /// struct Wrapper(Vec); @@ -230,8 +229,9 @@ pub trait AsMut { /// } /// } /// ``` -/// -/// To fix this, you can implement `Into` directly: +/// This will fail to compile because we cannot implement a trait for a type +/// if both the trait and the type are not defined by the current crate. +/// This is due to Rust's orphaning rules. To bypass this, you can implement [`Into`] directly: /// /// ``` /// struct Wrapper(Vec); @@ -242,17 +242,22 @@ pub trait AsMut { /// } /// ``` /// -/// This won't always allow the conversion: for example, `try!` and `?` -/// always use `From`. However, in most cases, people use `Into` to do the -/// conversions, and this will allow that. +/// It is important to understand that [`Into`] does not provide a [`From`] implementation +/// (as [`From`] does with [`Into`]). Therefore, you should always try to implement [`From`] +/// and then fall back to [`Into`] if [`From`] can't be implemented. /// -/// In almost all cases, you should try to implement `From`, then fall back -/// to `Into` if `From` can't be implemented. +/// Prefer using [`Into`] over [`From`] when specifying trait bounds on a generic function +/// to ensure that types that only implement [`Into`] can be used as well. /// /// # Examples /// /// [`String`] implements `Into>`: /// +/// 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`]``. +/// For example: The function `is_hello` takes all arguments that can be converted into a +/// `Vec`. +/// /// ``` /// fn is_hello>>(s: T) { /// let bytes = b"hello".to_vec(); @@ -267,8 +272,8 @@ pub trait AsMut { /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// [`String`]: ../../std/string/struct.String.html -/// [From]: trait.From.html -/// [`into`]: trait.Into.html#tymethod.into +/// [`From`]: trait.From.html +/// [`Into`]: trait.Into.html #[stable(feature = "rust1", since = "1.0.0")] pub trait Into: Sized { /// Performs the conversion. @@ -276,36 +281,39 @@ pub trait Into: Sized { fn into(self) -> T; } -/// Simple and safe type conversions in to `Self`. It is the reciprocal of -/// `Into`. +/// Used to do value-to-value conversions while consuming the input value. It is the reciprocal of +/// [`Into`]. /// -/// This trait is useful when performing error handling as described by -/// [the book][book] and is closely related to the `?` operator. +/// One should always prefer implementing `From` over [`Into`] +/// because implementing `From` automatically provides one with a implementation of [`Into`] +/// thanks to the blanket implementation in the standard library. /// -/// When constructing a function that is capable of failing the return type -/// will generally be of the form `Result`. +/// Only implement [`Into`] if a conversion to a type outside the current crate is required. +/// `From` cannot do these type of conversions because of Rust's orphaning rules. +/// See [`Into`] for more details. /// -/// The `From` trait allows for simplification of error handling by providing a -/// means of returning a single error type that encapsulates numerous possible -/// erroneous situations. +/// Prefer using [`Into`] over using `From` when specifying trait bounds on a generic function. +/// This way, types that directly implement [`Into`] can be used as arguments as well. /// -/// This trait is not limited to error handling, rather the general case for -/// this trait would be in any type conversions to have an explicit definition -/// of how they are performed. +/// The `From` is also very useful when performing error handling. When constructing a function +/// that is capable of failing, the return type will generally be of the form `Result`. +/// The `From` trait simplifies error handling by allowing a function to return a single error type +/// that encapsulate multiple error types. See the "Examples" section and [the book][book] for more +/// details. /// -/// **Note: this trait must not fail**. If the conversion can fail, use -/// [`TryFrom`] or a dedicated method which returns an [`Option`] or a -/// [`Result`]. +/// **Note: This trait must not fail**. If the conversion can fail, use [`TryFrom`]. /// /// # Generic Implementations /// -/// - `From for U` implies [`Into`]` for T` -/// - [`from`] is reflexive, which means that `From for T` is implemented +/// - `From for U` implies [`Into`]` for T` +/// - `From` is reflexive, which means that `From for T` is implemented /// /// # Examples /// /// [`String`] implements `From<&str>`: /// +/// An explicit conversion from a `&str` to a String is done as follows: +/// /// ``` /// let string = "hello".to_string(); /// let other_string = String::from("hello"); @@ -313,7 +321,12 @@ pub trait Into: Sized { /// assert_eq!(string, other_string); /// ``` /// -/// An example usage for error handling: +/// While performing error handling it is often useful to implement `From` for your own error type. +/// By converting underlying error types to our own custom error type that encapsulates the +/// underlying error type, we can return a single error type without losing information on the +/// underlying cause. The '?' operator automatically converts the underlying error type to our +/// custom error type by calling `Into::into` which is automatically provided when +/// implementing `From`. The compiler then infers which implementation of `Into` should be used. /// /// ``` /// use std::fs; @@ -348,10 +361,16 @@ pub trait Into: Sized { /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// [`String`]: ../../std/string/struct.String.html -/// [`Into`]: trait.Into.html +/// [`Into`]: trait.Into.html /// [`from`]: trait.From.html#tymethod.from /// [book]: ../../book/ch09-00-error-handling.html #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented( + on( + all(_Self="&str", T="std::string::String"), + note="to coerce a `{T}` into a `{Self}`, use `&*` as a prefix", + ) +)] pub trait From: Sized { /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] @@ -361,11 +380,17 @@ pub trait From: Sized { /// An attempted conversion that consumes `self`, which may or may not be /// expensive. /// -/// Library authors should not directly implement this trait, but should prefer -/// implementing the [`TryFrom`] trait, which offers greater flexibility and -/// provides an equivalent `TryInto` implementation for free, thanks to a -/// blanket implementation in the standard library. For more information on this, -/// see the documentation for [`Into`]. +/// Library authors should usually not directly implement this trait, +/// but should prefer implementing the [`TryFrom`] trait, which offers +/// greater flexibility and provides an equivalent `TryInto` +/// implementation for free, thanks to a blanket implementation in the +/// standard library. For more information on this, see the +/// documentation for [`Into`]. +/// +/// # Implementing `TryInto` +/// +/// This suffers the same restrictions and reasoning as implementing +/// [`Into`], see there for details. /// /// [`TryFrom`]: trait.TryFrom.html /// [`Into`]: trait.Into.html @@ -380,7 +405,75 @@ pub trait TryInto: Sized { fn try_into(self) -> Result; } -/// Attempt to construct `Self` via a conversion. +/// Simple and safe type conversions that may fail in a controlled +/// way under some circumstances. It is the reciprocal of [`TryInto`]. +/// +/// 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 perfect conversions, so the `TryFrom` trait informs the +/// programmer when a type conversion could go bad and lets them +/// decide how to handle it. +/// +/// # Generic Implementations +/// +/// - `TryFrom for U` implies [`TryInto`]` for T` +/// - [`try_from`] is reflexive, which means that `TryFrom 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 +/// equivalent. +/// +/// `TryFrom` can be implemented as follows: +/// +/// ``` +/// use std::convert::TryFrom; +/// +/// struct SuperiorThanZero(i32); +/// +/// impl TryFrom for SuperiorThanZero { +/// type Error = &'static str; +/// +/// fn try_from(value: i32) -> Result { +/// if value < 0 { +/// Err("SuperiorThanZero only accepts value superior than zero!") +/// } else { +/// Ok(SuperiorThanZero(value)) +/// } +/// } +/// } +/// ``` +/// +/// # Examples +/// +/// As described, [`i32`] implements `TryFrom`: +/// +/// ``` +/// use std::convert::TryFrom; +/// +/// let big_number = 1_000_000_000_000i64; +/// // Silently truncates `big_number`, requires detecting +/// // and handling the truncation after the fact. +/// let smaller_number = big_number as i32; +/// assert_eq!(smaller_number, -727379968); +/// +/// // Returns an error because `big_number` is too big to +/// // fit in an `i32`. +/// let try_smaller_number = i32::try_from(big_number); +/// assert!(try_smaller_number.is_err()); +/// +/// // Returns `Ok(3)`. +/// let try_successful_smaller_number = i32::try_from(3); +/// assert!(try_successful_smaller_number.is_ok()); +/// ``` +/// +/// [`try_from`]: trait.TryFrom.html#tymethod.try_from +/// [`TryInto`]: trait.TryInto.html #[stable(feature = "try_from", since = "1.34.0")] pub trait TryFrom: Sized { /// The type returned in the event of a conversion error. diff --git a/src/libcore/ffi.rs b/src/libcore/ffi.rs index d88793f2801e7..49090fb8e4378 100644 --- a/src/libcore/ffi.rs +++ b/src/libcore/ffi.rs @@ -4,7 +4,9 @@ //! Utilities related to FFI bindings. -use ::fmt; +use crate::fmt; +use crate::marker::PhantomData; +use crate::ops::{Deref, DerefMut}; /// Equivalent to C's `void` type when used as a [pointer]. /// @@ -39,51 +41,62 @@ pub enum c_void { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for c_void { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("c_void") } } /// Basic implementation of a `va_list`. +// The name is WIP, using `VaListImpl` for now. #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), - not(target_arch = "x86_64")), - all(target_arch = "aarch4", target_os = "ios"), + not(target_arch = "x86_64"), not(target_arch = "asmjs")), + all(target_arch = "aarch64", target_os = "ios"), windows))] +#[repr(transparent)] #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930")] -extern { - type VaListImpl; +#[lang = "va_list"] +pub struct VaListImpl<'f> { + ptr: *mut c_void, + _marker: PhantomData<&'f c_void>, } #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), - not(target_arch = "x86_64")), + not(target_arch = "x86_64"), not(target_arch = "asmjs")), + all(target_arch = "aarch64", target_os = "ios"), windows))] -impl fmt::Debug for VaListImpl { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "va_list* {:p}", self) +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +impl<'f> fmt::Debug for VaListImpl<'f> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "va_list* {:p}", self.ptr) } } /// AArch64 ABI implementation of a `va_list`. See the -/// [Aarch64 Procedure Call Standard] for more details. +/// [AArch64 Procedure Call Standard] for more details. /// /// [AArch64 Procedure Call Standard]: /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf -#[cfg(all(target_arch = "aarch64", not(windows)))] +#[cfg(all(target_arch = "aarch64", not(target_os = "ios"), not(windows)))] #[repr(C)] #[derive(Debug)] #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930")] -struct VaListImpl { - stack: *mut (), - gr_top: *mut (), - vr_top: *mut (), +#[lang = "va_list"] +pub struct VaListImpl<'f> { + stack: *mut c_void, + gr_top: *mut c_void, + vr_top: *mut c_void, gr_offs: i32, vr_offs: i32, + _marker: PhantomData<&'f c_void>, } /// PowerPC ABI implementation of a `va_list`. @@ -94,12 +107,14 @@ struct VaListImpl { reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930")] -struct VaListImpl { +#[lang = "va_list"] +pub struct VaListImpl<'f> { gpr: u8, fpr: u8, reserved: u16, - overflow_arg_area: *mut (), - reg_save_area: *mut (), + overflow_arg_area: *mut c_void, + reg_save_area: *mut c_void, + _marker: PhantomData<&'f c_void>, } /// x86_64 ABI implementation of a `va_list`. @@ -110,22 +125,131 @@ struct VaListImpl { reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930")] -struct VaListImpl { +#[lang = "va_list"] +pub struct VaListImpl<'f> { gp_offset: i32, fp_offset: i32, - overflow_arg_area: *mut (), - reg_save_area: *mut (), + overflow_arg_area: *mut c_void, + reg_save_area: *mut c_void, + _marker: PhantomData<&'f c_void>, } -/// A wrapper for a `va_list` +/// asm.js ABI implementation of a `va_list`. +// asm.js uses the PNaCl ABI, which specifies that a `va_list` is +// an array of 4 32-bit integers, according to the old PNaCl docs at +// https://web.archive.org/web/20130518054430/https://www.chromium.org/nativeclient/pnacl/bitcode-abi#TOC-Derived-Types +// and clang does the same in `CreatePNaClABIBuiltinVaListDecl` from `lib/AST/ASTContext.cpp` +#[cfg(all(target_arch = "asmjs", not(windows)))] +#[repr(C)] +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] #[lang = "va_list"] -#[derive(Debug)] +pub struct VaListImpl<'f> { + inner: [crate::mem::MaybeUninit; 4], + _marker: PhantomData<&'f c_void>, +} + +#[cfg(all(target_arch = "asmjs", not(windows)))] #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930")] +impl<'f> fmt::Debug for VaListImpl<'f> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + unsafe { + write!(f, "va_list* [{:#x}, {:#x}, {:#x}, {:#x}]", + self.inner[0].read(), self.inner[1].read(), + self.inner[2].read(), self.inner[3].read()) + } + } +} + +/// A wrapper for a `va_list` #[repr(transparent)] -pub struct VaList<'a>(&'a mut VaListImpl); +#[derive(Debug)] +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +pub struct VaList<'a, 'f: 'a> { + #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), + not(target_arch = "x86_64"), not(target_arch = "asmjs")), + all(target_arch = "aarch64", target_os = "ios"), + windows))] + inner: VaListImpl<'f>, + + #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", + target_arch = "x86_64", target_arch = "asmjs"), + any(not(target_arch = "aarch64"), not(target_os = "ios")), + not(windows)))] + inner: &'a mut VaListImpl<'f>, + + _marker: PhantomData<&'a mut VaListImpl<'f>>, +} + +#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), + not(target_arch = "x86_64"), not(target_arch = "asmjs")), + all(target_arch = "aarch64", target_os = "ios"), + windows))] +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +impl<'f> VaListImpl<'f> { + /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`. + #[inline] + pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { + VaList { + inner: VaListImpl { ..*self }, + _marker: PhantomData, + } + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", + target_arch = "x86_64", target_arch = "asmjs"), + any(not(target_arch = "aarch64"), not(target_os = "ios")), + not(windows)))] +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +impl<'f> VaListImpl<'f> { + /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`. + #[inline] + pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { + VaList { + inner: self, + _marker: PhantomData, + } + } +} + +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +impl<'a, 'f: 'a> Deref for VaList<'a, 'f> { + type Target = VaListImpl<'f>; + + #[inline] + fn deref(&self) -> &VaListImpl<'f> { + &self.inner + } +} + +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> { + #[inline] + fn deref_mut(&mut self) -> &mut VaListImpl<'f> { + &mut self.inner + } +} // The VaArgSafe trait needs to be used in public interfaces, however, the trait // itself must not be allowed to be used outside this module. Allowing users to @@ -174,55 +298,76 @@ impl sealed_trait::VaArgSafe for *mut T {} issue = "44930")] impl sealed_trait::VaArgSafe for *const T {} -impl<'a> VaList<'a> { +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +#[cfg(not(bootstrap))] +impl<'f> VaListImpl<'f> { /// Advance to the next arg. - #[unstable(feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930")] + #[inline] pub unsafe fn arg(&mut self) -> T { va_arg(self) } /// Copies the `va_list` at the current location. - #[unstable(feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930")] - pub unsafe fn copy(&self, f: F) -> R - where F: for<'copy> FnOnce(VaList<'copy>) -> R { - #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), - not(target_arch = "x86_64")), - all(target_arch = "aarch4", target_os = "ios"), - windows))] - let mut ap = va_copy(self); - #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"), - not(windows)))] - let mut ap_inner = va_copy(self); - #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"), - not(windows)))] - let mut ap = VaList(&mut ap_inner); - let ret = f(VaList(ap.0)); + pub unsafe fn with_copy(&self, f: F) -> R + where F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R { + let mut ap = self.clone(); + let ret = f(ap.as_va_list()); va_end(&mut ap); ret } } +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +#[cfg(not(bootstrap))] +impl<'f> Clone for VaListImpl<'f> { + #[inline] + fn clone(&self) -> Self { + let mut dest = crate::mem::MaybeUninit::uninit(); + unsafe { + va_copy(dest.as_mut_ptr(), self); + dest.assume_init() + } + } +} + +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +#[cfg(not(bootstrap))] +impl<'f> Drop for VaListImpl<'f> { + fn drop(&mut self) { + // FIXME: this should call `va_end`, but there's no clean way to + // guarantee that `drop` always gets inlined into its caller, + // so the `va_end` would get directly called from the same function as + // the corresponding `va_copy`. `man va_end` states that C requires this, + // and LLVM basically follows the C semantics, so we need to make sure + // that `va_end` is always called from the same function as `va_copy`. + // For more details, see https://github.com/rust-lang/rust/pull/59625 + // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic. + // + // This works for now, since `va_end` is a no-op on all current LLVM targets. + } +} + extern "rust-intrinsic" { /// Destroy the arglist `ap` after initialization with `va_start` or /// `va_copy`. - fn va_end(ap: &mut VaList); + #[cfg(not(bootstrap))] + fn va_end(ap: &mut VaListImpl<'_>); /// Copies the current location of arglist `src` to the arglist `dst`. - #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), - not(target_arch = "x86_64")), - windows))] - fn va_copy<'a>(src: &VaList<'a>) -> VaList<'a>; - #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"), - not(windows)))] - fn va_copy(src: &VaList) -> VaListImpl; + #[cfg(not(bootstrap))] + fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); /// Loads an argument of type `T` from the `va_list` `ap` and increment the /// argument `ap` points to. - fn va_arg(ap: &mut VaList) -> T; + #[cfg(not(bootstrap))] + fn va_arg(ap: &mut VaListImpl<'_>) -> T; } diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index 45994c2b4f0f0..df86da5fc3906 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -1,4 +1,4 @@ -use fmt; +use crate::fmt; struct PadAdapter<'a> { buf: &'a mut (dyn fmt::Write + 'a), @@ -6,12 +6,12 @@ struct PadAdapter<'a> { } impl<'a> PadAdapter<'a> { - fn wrap<'b, 'c: 'a+'b>(fmt: &'c mut fmt::Formatter, slot: &'b mut Option) + fn wrap<'b, 'c: 'a+'b>(fmt: &'c mut fmt::Formatter<'_>, slot: &'b mut Option) -> fmt::Formatter<'b> { fmt.wrap_buf(move |buf| { *slot = Some(PadAdapter { buf, - on_newline: false, + on_newline: true, }); slot.as_mut().unwrap() }) @@ -128,22 +128,21 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { #[stable(feature = "debug_builders", since = "1.2.0")] pub fn field(&mut self, name: &str, value: &dyn fmt::Debug) -> &mut DebugStruct<'a, 'b> { self.result = self.result.and_then(|_| { - let prefix = if self.has_fields { - "," - } else { - " {" - }; - if self.is_pretty() { + if !self.has_fields { + self.fmt.write_str(" {\n")?; + } let mut slot = None; let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot); - writer.write_str(prefix)?; - writer.write_str("\n")?; writer.write_str(name)?; writer.write_str(": ")?; - value.fmt(&mut writer) + value.fmt(&mut writer)?; + writer.write_str(",\n") } else { - write!(self.fmt, "{} {}: ", prefix, name)?; + let prefix = if self.has_fields { ", " } else { " { " }; + self.fmt.write_str(prefix)?; + self.fmt.write_str(name)?; + self.fmt.write_str(": ")?; value.fmt(self.fmt) } }); @@ -184,7 +183,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { if self.has_fields { self.result = self.result.and_then(|_| { if self.is_pretty() { - self.fmt.write_str("\n}") + self.fmt.write_str("}") } else { self.fmt.write_str(" }") } @@ -275,21 +274,17 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { #[stable(feature = "debug_builders", since = "1.2.0")] pub fn field(&mut self, value: &dyn fmt::Debug) -> &mut DebugTuple<'a, 'b> { self.result = self.result.and_then(|_| { - let (prefix, space) = if self.fields > 0 { - (",", " ") - } else { - ("(", "") - }; - if self.is_pretty() { + if self.fields == 0 { + self.fmt.write_str("(\n")?; + } let mut slot = None; let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot); - writer.write_str(prefix)?; - writer.write_str("\n")?; - value.fmt(&mut writer) + value.fmt(&mut writer)?; + writer.write_str(",\n") } else { + let prefix = if self.fields == 0 { "(" } else { ", " }; self.fmt.write_str(prefix)?; - self.fmt.write_str(space)?; value.fmt(self.fmt) } }); @@ -326,10 +321,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { pub fn finish(&mut self) -> fmt::Result { if self.fields > 0 { self.result = self.result.and_then(|_| { - if self.is_pretty() { - self.fmt.write_str("\n")?; - } - if self.fields == 1 && self.empty_name { + if self.fields == 1 && self.empty_name && !self.is_pretty() { self.fmt.write_str(",")?; } self.fmt.write_str(")") @@ -353,14 +345,13 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> { fn entry(&mut self, entry: &dyn fmt::Debug) { self.result = self.result.and_then(|_| { if self.is_pretty() { + if !self.has_fields { + self.fmt.write_str("\n")?; + } let mut slot = None; let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot); - writer.write_str(if self.has_fields { - ",\n" - } else { - "\n" - })?; - entry.fmt(&mut writer) + entry.fmt(&mut writer)?; + writer.write_str(",\n") } else { if self.has_fields { self.fmt.write_str(", ")? @@ -372,15 +363,6 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> { self.has_fields = true; } - pub fn finish(&mut self) { - let prefix = if self.is_pretty() && self.has_fields { - "\n" - } else { - "" - }; - self.result = self.result.and_then(|_| self.fmt.write_str(prefix)); - } - fn is_pretty(&self) -> bool { self.fmt.alternate() } @@ -421,7 +403,7 @@ pub struct DebugSet<'a, 'b: 'a> { } pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b> { - let result = write!(fmt, "{{"); + let result = fmt.write_str("{"); DebugSet { inner: DebugInner { fmt, @@ -519,7 +501,6 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { - self.inner.finish(); self.inner.result.and_then(|_| self.inner.fmt.write_str("}")) } } @@ -559,7 +540,7 @@ pub struct DebugList<'a, 'b: 'a> { } pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, 'b> { - let result = write!(fmt, "["); + let result = fmt.write_str("["); DebugList { inner: DebugInner { fmt, @@ -657,7 +638,6 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { - self.inner.finish(); self.inner.result.and_then(|_| self.inner.fmt.write_str("]")) } } @@ -699,7 +679,7 @@ pub struct DebugMap<'a, 'b: 'a> { } pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b> { - let result = write!(fmt, "{{"); + let result = fmt.write_str("{"); DebugMap { fmt, result, @@ -734,16 +714,15 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { pub fn entry(&mut self, key: &dyn fmt::Debug, value: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> { self.result = self.result.and_then(|_| { if self.is_pretty() { + if !self.has_fields { + self.fmt.write_str("\n")?; + } let mut slot = None; let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot); - writer.write_str(if self.has_fields { - ",\n" - } else { - "\n" - })?; key.fmt(&mut writer)?; writer.write_str(": ")?; - value.fmt(&mut writer) + value.fmt(&mut writer)?; + writer.write_str(",\n") } else { if self.has_fields { self.fmt.write_str(", ")? @@ -818,12 +797,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { - let prefix = if self.is_pretty() && self.has_fields { - "\n" - } else { - "" - }; - self.result.and_then(|_| write!(self.fmt, "{}}}", prefix)) + self.result.and_then(|_| self.fmt.write_str("}")) } fn is_pretty(&self) -> bool { diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index 20c626cef1b16..4bd7d3b4b22e3 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -1,20 +1,21 @@ -use fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug}; -use mem::MaybeUninit; -use num::flt2dec; +use crate::fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug}; +use crate::mem::MaybeUninit; +use crate::num::flt2dec; // Don't inline this so callers don't use the stack space this function // requires unless they have to. #[inline(never)] -fn float_to_decimal_common_exact(fmt: &mut Formatter, num: &T, +fn float_to_decimal_common_exact(fmt: &mut Formatter<'_>, num: &T, sign: flt2dec::Sign, precision: usize) -> Result where T: flt2dec::DecodableFloat { unsafe { - let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64 - let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized(); + let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64 + let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 4]>::uninit(); // FIXME(#53491): Technically, this is calling `get_mut` on an uninitialized // `MaybeUninit` (here and elsewhere in this file). Revisit this once // we decided whether that is valid or not. + // Using `freeze` is *not enough*; `flt2dec::Part` is an enum! let formatted = flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, *num, sign, precision, false, buf.get_mut(), parts.get_mut()); @@ -25,14 +26,15 @@ fn float_to_decimal_common_exact(fmt: &mut Formatter, num: &T, // Don't inline this so callers that call both this and the above won't wind // up using the combined stack space of both functions in some cases. #[inline(never)] -fn float_to_decimal_common_shortest(fmt: &mut Formatter, num: &T, +fn float_to_decimal_common_shortest(fmt: &mut Formatter<'_>, num: &T, sign: flt2dec::Sign, precision: usize) -> Result where T: flt2dec::DecodableFloat { unsafe { // enough for f32 and f64 - let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized(); - let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized(); + let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit(); + let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 4]>::uninit(); + // FIXME(#53491) let formatted = flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign, precision, false, buf.get_mut(), parts.get_mut()); @@ -41,7 +43,7 @@ fn float_to_decimal_common_shortest(fmt: &mut Formatter, num: &T, } // Common code of floating point Debug and Display. -fn float_to_decimal_common(fmt: &mut Formatter, num: &T, +fn float_to_decimal_common(fmt: &mut Formatter<'_>, num: &T, negative_zero: bool, min_precision: usize) -> Result where T: flt2dec::DecodableFloat { @@ -63,14 +65,15 @@ fn float_to_decimal_common(fmt: &mut Formatter, num: &T, // Don't inline this so callers don't use the stack space this function // requires unless they have to. #[inline(never)] -fn float_to_exponential_common_exact(fmt: &mut Formatter, num: &T, +fn float_to_exponential_common_exact(fmt: &mut Formatter<'_>, num: &T, sign: flt2dec::Sign, precision: usize, upper: bool) -> Result where T: flt2dec::DecodableFloat { unsafe { - let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64 - let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized(); + let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64 + let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 6]>::uninit(); + // FIXME(#53491) let formatted = flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign, precision, upper, buf.get_mut(), parts.get_mut()); @@ -81,15 +84,16 @@ fn float_to_exponential_common_exact(fmt: &mut Formatter, num: &T, // Don't inline this so callers that call both this and the above won't wind // up using the combined stack space of both functions in some cases. #[inline(never)] -fn float_to_exponential_common_shortest(fmt: &mut Formatter, +fn float_to_exponential_common_shortest(fmt: &mut Formatter<'_>, num: &T, sign: flt2dec::Sign, upper: bool) -> Result where T: flt2dec::DecodableFloat { unsafe { // enough for f32 and f64 - let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized(); - let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized(); + let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit(); + let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 6]>::uninit(); + // FIXME(#53491) let formatted = flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign, (0, 0), upper, buf.get_mut(), parts.get_mut()); @@ -98,7 +102,7 @@ fn float_to_exponential_common_shortest(fmt: &mut Formatter, } // Common code of floating point LowerExp and UpperExp. -fn float_to_exponential_common(fmt: &mut Formatter, num: &T, upper: bool) -> Result +fn float_to_exponential_common(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result where T: flt2dec::DecodableFloat { let force_sign = fmt.sign_plus(); @@ -119,28 +123,28 @@ macro_rules! floating { ($ty:ident) => ( #[stable(feature = "rust1", since = "1.0.0")] impl Debug for $ty { - fn fmt(&self, fmt: &mut Formatter) -> Result { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { float_to_decimal_common(fmt, self, true, 1) } } #[stable(feature = "rust1", since = "1.0.0")] impl Display for $ty { - fn fmt(&self, fmt: &mut Formatter) -> Result { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { float_to_decimal_common(fmt, self, false, 0) } } #[stable(feature = "rust1", since = "1.0.0")] impl LowerExp for $ty { - fn fmt(&self, fmt: &mut Formatter) -> Result { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { float_to_exponential_common(fmt, self, false) } } #[stable(feature = "rust1", since = "1.0.0")] impl UpperExp for $ty { - fn fmt(&self, fmt: &mut Formatter) -> Result { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { float_to_exponential_common(fmt, self, true) } } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 7efb7f31298bf..17ea58438810e 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -2,14 +2,14 @@ #![stable(feature = "rust1", since = "1.0.0")] -use cell::{UnsafeCell, Cell, RefCell, Ref, RefMut}; -use marker::PhantomData; -use mem; -use num::flt2dec; -use ops::Deref; -use result; -use slice; -use str; +use crate::cell::{UnsafeCell, Cell, RefCell, Ref, RefMut}; +use crate::marker::PhantomData; +use crate::mem; +use crate::num::flt2dec; +use crate::ops::Deref; +use crate::result; +use crate::slice; +use crate::str; mod float; mod num; @@ -55,7 +55,7 @@ pub mod rt { /// } /// /// impl fmt::Display for Triangle { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "({}, {}, {})", self.a, self.b, self.c) /// } /// } @@ -191,7 +191,7 @@ pub trait Write { /// assert_eq!(&buf, "world"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn write_fmt(mut self: &mut Self, args: Arguments) -> Result { + fn write_fmt(mut self: &mut Self, args: Arguments<'_>) -> Result { write(&mut self, args) } } @@ -206,7 +206,7 @@ impl Write for &mut W { (**self).write_char(c) } - fn write_fmt(&mut self, args: Arguments) -> Result { + fn write_fmt(&mut self, args: Arguments<'_>) -> Result { (**self).write_fmt(args) } } @@ -238,7 +238,7 @@ pub struct Formatter<'a> { } // NB. Argument is essentially an optimized partially applied formatting function, -// equivalent to `exists T.(&T, fn(&T, &mut Formatter) -> Result`. +// equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`. struct Void { _priv: (), @@ -263,12 +263,12 @@ struct Void { #[doc(hidden)] pub struct ArgumentV1<'a> { value: &'a Void, - formatter: fn(&Void, &mut Formatter) -> Result, + formatter: fn(&Void, &mut Formatter<'_>) -> Result, } impl<'a> ArgumentV1<'a> { #[inline(never)] - fn show_usize(x: &usize, f: &mut Formatter) -> Result { + fn show_usize(x: &usize, f: &mut Formatter<'_>) -> Result { Display::fmt(x, f) } @@ -276,7 +276,7 @@ impl<'a> ArgumentV1<'a> { #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "0")] pub fn new<'b, T>(x: &'b T, - f: fn(&T, &mut Formatter) -> Result) -> ArgumentV1<'b> { + f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> { unsafe { ArgumentV1 { formatter: mem::transmute(f), @@ -288,7 +288,7 @@ impl<'a> ArgumentV1<'a> { #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "0")] - pub fn from_usize(x: &usize) -> ArgumentV1 { + pub fn from_usize(x: &usize) -> ArgumentV1<'_> { ArgumentV1::new(x, ArgumentV1::show_usize) } @@ -406,14 +406,14 @@ pub struct Arguments<'a> { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for Arguments<'_> { - fn fmt(&self, fmt: &mut Formatter) -> Result { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { Display::fmt(self, fmt) } } #[stable(feature = "rust1", since = "1.0.0")] impl Display for Arguments<'_> { - fn fmt(&self, fmt: &mut Formatter) -> Result { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { write(fmt.buf, *self) } } @@ -463,7 +463,7 @@ impl Display for Arguments<'_> { /// } /// /// impl fmt::Debug for Point { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y) /// } /// } @@ -533,7 +533,7 @@ pub trait Debug { /// } /// /// impl fmt::Debug for Position { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "({:?}, {:?})", self.longitude, self.latitude) /// } /// } @@ -542,7 +542,7 @@ pub trait Debug { /// format!("{:?}", Position { longitude: 1.987, latitude: 2.983, })); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn fmt(&self, f: &mut Formatter) -> Result; + fn fmt(&self, f: &mut Formatter<'_>) -> Result; } /// Format trait for an empty format, `{}`. @@ -569,7 +569,7 @@ pub trait Debug { /// } /// /// impl fmt::Display for Point { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "({}, {})", self.x, self.y) /// } /// } @@ -605,7 +605,7 @@ pub trait Display { /// } /// /// impl fmt::Display for Position { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "({}, {})", self.longitude, self.latitude) /// } /// } @@ -614,7 +614,7 @@ pub trait Display { /// format!("{}", Position { longitude: 1.987, latitude: 2.983, })); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn fmt(&self, f: &mut Formatter) -> Result; + fn fmt(&self, f: &mut Formatter<'_>) -> Result; } /// `o` formatting. @@ -651,7 +651,7 @@ pub trait Display { /// struct Length(i32); /// /// impl fmt::Octal for Length { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// let val = self.0; /// /// write!(f, "{:o}", val) // delegate to i32's implementation @@ -666,7 +666,7 @@ pub trait Display { pub trait Octal { /// Formats the value using the given formatter. #[stable(feature = "rust1", since = "1.0.0")] - fn fmt(&self, f: &mut Formatter) -> Result; + fn fmt(&self, f: &mut Formatter<'_>) -> Result; } /// `b` formatting. @@ -701,7 +701,7 @@ pub trait Octal { /// struct Length(i32); /// /// impl fmt::Binary for Length { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// let val = self.0; /// /// write!(f, "{:b}", val) // delegate to i32's implementation @@ -722,7 +722,7 @@ pub trait Octal { pub trait Binary { /// Formats the value using the given formatter. #[stable(feature = "rust1", since = "1.0.0")] - fn fmt(&self, f: &mut Formatter) -> Result; + fn fmt(&self, f: &mut Formatter<'_>) -> Result; } /// `x` formatting. @@ -760,7 +760,7 @@ pub trait Binary { /// struct Length(i32); /// /// impl fmt::LowerHex for Length { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// let val = self.0; /// /// write!(f, "{:x}", val) // delegate to i32's implementation @@ -775,7 +775,7 @@ pub trait Binary { pub trait LowerHex { /// Formats the value using the given formatter. #[stable(feature = "rust1", since = "1.0.0")] - fn fmt(&self, f: &mut Formatter) -> Result; + fn fmt(&self, f: &mut Formatter<'_>) -> Result; } /// `X` formatting. @@ -813,7 +813,7 @@ pub trait LowerHex { /// struct Length(i32); /// /// impl fmt::UpperHex for Length { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// let val = self.0; /// /// write!(f, "{:X}", val) // delegate to i32's implementation @@ -828,7 +828,7 @@ pub trait LowerHex { pub trait UpperHex { /// Formats the value using the given formatter. #[stable(feature = "rust1", since = "1.0.0")] - fn fmt(&self, f: &mut Formatter) -> Result; + fn fmt(&self, f: &mut Formatter<'_>) -> Result; } /// `p` formatting. @@ -858,7 +858,7 @@ pub trait UpperHex { /// struct Length(i32); /// /// impl fmt::Pointer for Length { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// // use `as` to convert to a `*const T`, which implements Pointer, which we can use /// /// write!(f, "{:p}", self as *const Length) @@ -873,7 +873,7 @@ pub trait UpperHex { pub trait Pointer { /// Formats the value using the given formatter. #[stable(feature = "rust1", since = "1.0.0")] - fn fmt(&self, f: &mut Formatter) -> Result; + fn fmt(&self, f: &mut Formatter<'_>) -> Result; } /// `e` formatting. @@ -886,7 +886,7 @@ pub trait Pointer { /// /// # Examples /// -/// Basic usage with `i32`: +/// Basic usage with `f64`: /// /// ``` /// let x = 42.0; // 42.0 is '4.2e1' in scientific notation @@ -902,7 +902,7 @@ pub trait Pointer { /// struct Length(i32); /// /// impl fmt::LowerExp for Length { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// let val = self.0; /// write!(f, "{}e1", val / 10) /// } @@ -916,7 +916,7 @@ pub trait Pointer { pub trait LowerExp { /// Formats the value using the given formatter. #[stable(feature = "rust1", since = "1.0.0")] - fn fmt(&self, f: &mut Formatter) -> Result; + fn fmt(&self, f: &mut Formatter<'_>) -> Result; } /// `E` formatting. @@ -929,7 +929,7 @@ pub trait LowerExp { /// /// # Examples /// -/// Basic usage with `f32`: +/// Basic usage with `f64`: /// /// ``` /// let x = 42.0; // 42.0 is '4.2E1' in scientific notation @@ -945,7 +945,7 @@ pub trait LowerExp { /// struct Length(i32); /// /// impl fmt::UpperExp for Length { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// let val = self.0; /// write!(f, "{}E1", val / 10) /// } @@ -959,7 +959,7 @@ pub trait LowerExp { pub trait UpperExp { /// Formats the value using the given formatter. #[stable(feature = "rust1", since = "1.0.0")] - fn fmt(&self, f: &mut Formatter) -> Result; + fn fmt(&self, f: &mut Formatter<'_>) -> Result; } /// The `write` function takes an output stream, and an `Arguments` struct @@ -994,7 +994,7 @@ pub trait UpperExp { /// /// [`write!`]: ../../std/macro.write.html #[stable(feature = "rust1", since = "1.0.0")] -pub fn write(output: &mut dyn Write, args: Arguments) -> Result { +pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { let mut formatter = Formatter { flags: 0, width: None, @@ -1183,7 +1183,7 @@ impl<'a> Formatter<'a> { // Writes the sign if it exists, and then the prefix if it was requested #[inline(never)] - fn write_prefix(f: &mut Formatter, sign: Option, prefix: Option<&str>) -> Result { + fn write_prefix(f: &mut Formatter<'_>, sign: Option, prefix: Option<&str>) -> Result { if let Some(c) = sign { f.buf.write_char(c)?; } @@ -1331,7 +1331,7 @@ impl<'a> Formatter<'a> { /// Takes the formatted parts and applies the padding. /// Assumes that the caller already has rendered the parts with required precision, /// so that `self.precision` can be ignored. - fn pad_formatted_parts(&mut self, formatted: &flt2dec::Formatted) -> Result { + fn pad_formatted_parts(&mut self, formatted: &flt2dec::Formatted<'_>) -> Result { if let Some(mut width) = self.width { // for the sign-aware zero padding, we render the sign first and // behave as if we had no sign from the beginning. @@ -1370,7 +1370,7 @@ impl<'a> Formatter<'a> { } } - fn write_formatted_parts(&mut self, formatted: &flt2dec::Formatted) -> Result { + fn write_formatted_parts(&mut self, formatted: &flt2dec::Formatted<'_>) -> Result { fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result { buf.write_str(unsafe { str::from_utf8_unchecked(s) }) } @@ -1453,7 +1453,7 @@ impl<'a> Formatter<'a> { /// assert_eq!(&format!("{:0>8}", Foo(2)), "Foo 2"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn write_fmt(&mut self, fmt: Arguments) -> Result { + pub fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result { write(self.buf, fmt) } @@ -1892,14 +1892,14 @@ impl Write for Formatter<'_> { self.buf.write_char(c) } - fn write_fmt(&mut self, args: Arguments) -> Result { + fn write_fmt(&mut self, args: Arguments<'_>) -> Result { write(self.buf, args) } } #[stable(feature = "rust1", since = "1.0.0")] impl Display for Error { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { Display::fmt("an error occurred when formatting an argument", f) } } @@ -1911,11 +1911,11 @@ macro_rules! fmt_refs { $( #[stable(feature = "rust1", since = "1.0.0")] impl $tr for &T { - fn fmt(&self, f: &mut Formatter) -> Result { $tr::fmt(&**self, f) } + fn fmt(&self, f: &mut Formatter<'_>) -> Result { $tr::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl $tr for &mut T { - fn fmt(&self, f: &mut Formatter) -> Result { $tr::fmt(&**self, f) } + fn fmt(&self, f: &mut Formatter<'_>) -> Result { $tr::fmt(&**self, f) } } )* } @@ -1925,14 +1925,14 @@ fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperEx #[unstable(feature = "never_type", issue = "35121")] impl Debug for ! { - fn fmt(&self, _: &mut Formatter) -> Result { + fn fmt(&self, _: &mut Formatter<'_>) -> Result { *self } } #[unstable(feature = "never_type", issue = "35121")] impl Display for ! { - fn fmt(&self, _: &mut Formatter) -> Result { + fn fmt(&self, _: &mut Formatter<'_>) -> Result { *self } } @@ -1940,21 +1940,21 @@ impl Display for ! { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for bool { #[inline] - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { Display::fmt(self, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl Display for bool { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { Display::fmt(if *self { "true" } else { "false" }, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for str { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.write_char('"')?; let mut from = 0; for (i, c) in self.char_indices() { @@ -1975,14 +1975,14 @@ impl Debug for str { #[stable(feature = "rust1", since = "1.0.0")] impl Display for str { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.pad(self) } } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for char { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.write_char('\'')?; for c in self.escape_debug() { f.write_char(c)? @@ -1993,7 +1993,7 @@ impl Debug for char { #[stable(feature = "rust1", since = "1.0.0")] impl Display for char { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { if f.width.is_none() && f.precision.is_none() { f.write_char(*self) } else { @@ -2004,7 +2004,7 @@ impl Display for char { #[stable(feature = "rust1", since = "1.0.0")] impl Pointer for *const T { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { let old_width = f.width; let old_flags = f.flags; @@ -2032,21 +2032,21 @@ impl Pointer for *const T { #[stable(feature = "rust1", since = "1.0.0")] impl Pointer for *mut T { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { Pointer::fmt(&(*self as *const T), f) } } #[stable(feature = "rust1", since = "1.0.0")] impl Pointer for &T { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { Pointer::fmt(&(*self as *const T), f) } } #[stable(feature = "rust1", since = "1.0.0")] impl Pointer for &mut T { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { Pointer::fmt(&(&**self as *const T), f) } } @@ -2055,11 +2055,11 @@ impl Pointer for &mut T { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for *const T { - fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) } + fn fmt(&self, f: &mut Formatter<'_>) -> Result { Pointer::fmt(self, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for *mut T { - fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) } + fn fmt(&self, f: &mut Formatter<'_>) -> Result { Pointer::fmt(self, f) } } macro_rules! peel { @@ -2070,19 +2070,19 @@ macro_rules! tuple { () => (); ( $($name:ident,)+ ) => ( #[stable(feature = "rust1", since = "1.0.0")] - impl<$($name:Debug),*> Debug for ($($name,)*) where last_type!($($name,)+): ?Sized { + impl<$($name:Debug),+> Debug for ($($name,)+) where last_type!($($name,)+): ?Sized { #[allow(non_snake_case, unused_assignments)] - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { let mut builder = f.debug_tuple(""); - let ($(ref $name,)*) = *self; + let ($(ref $name,)+) = *self; $( builder.field(&$name); - )* + )+ builder.finish() } } - peel! { $($name,)* } + peel! { $($name,)+ } ) } @@ -2095,7 +2095,7 @@ tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for [T] { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.debug_list().entries(self.iter()).finish() } } @@ -2103,20 +2103,20 @@ impl Debug for [T] { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for () { #[inline] - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.pad("()") } } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for PhantomData { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.pad("PhantomData") } } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for Cell { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.debug_struct("Cell") .field("value", &self.get()) .finish() @@ -2125,7 +2125,7 @@ impl Debug for Cell { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for RefCell { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { match self.try_borrow() { Ok(borrow) => { f.debug_struct("RefCell") @@ -2138,7 +2138,7 @@ impl Debug for RefCell { struct BorrowedPlaceholder; impl Debug for BorrowedPlaceholder { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.write_str("") } } @@ -2153,21 +2153,21 @@ impl Debug for RefCell { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for Ref<'_, T> { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { Debug::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for RefMut<'_, T> { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { Debug::fmt(&*(self.deref()), f) } } #[stable(feature = "core_impl_debug", since = "1.9.0")] impl Debug for UnsafeCell { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.pad("UnsafeCell") } } diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index b9fa364037108..f9b4c26496cdc 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -1,12 +1,12 @@ //! Integer and floating-point number formatting -use fmt; -use ops::{Div, Rem, Sub}; -use str; -use slice; -use ptr; -use mem::MaybeUninit; +use crate::fmt; +use crate::ops::{Div, Rem, Sub}; +use crate::str; +use crate::slice; +use crate::ptr; +use crate::mem::MaybeUninit; #[doc(hidden)] trait Int: PartialEq + PartialOrd + Div + Rem + @@ -46,7 +46,7 @@ trait GenericRadix { fn digit(x: u8) -> u8; /// Format an integer using the radix using a formatter. - fn fmt_int(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt_int(&self, mut x: T, f: &mut fmt::Formatter<'_>) -> fmt::Result { // The radix can be as low as 2, so we need a buffer of at least 128 // characters for a base 2 number. let zero = T::zero(); @@ -60,7 +60,7 @@ trait GenericRadix { for byte in buf.iter_mut().rev() { let n = x % base; // Get the current place value. x = x / base; // Deaccumulate the number. - byte.set(Self::digit(n.to_u8())); // Store the digit in the buffer. + byte.write(Self::digit(n.to_u8())); // Store the digit in the buffer. curr -= 1; if x == zero { // No more digits left to accumulate. @@ -72,7 +72,7 @@ trait GenericRadix { for byte in buf.iter_mut().rev() { let n = zero - (x % base); // Get the current place value. x = x / base; // Deaccumulate the number. - byte.set(Self::digit(n.to_u8())); // Store the digit in the buffer. + byte.write(Self::digit(n.to_u8())); // Store the digit in the buffer. curr -= 1; if x == zero { // No more digits left to accumulate. @@ -131,7 +131,7 @@ macro_rules! int_base { ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::$Trait for $T { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { $Radix.fmt_int(*self as $U, f) } } @@ -143,7 +143,7 @@ macro_rules! debug { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for $T { #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if f.debug_lower_hex() { fmt::LowerHex::fmt(self, f) } else if f.debug_upper_hex() { @@ -188,7 +188,7 @@ static DEC_DIGITS_LUT: &[u8; 200] = macro_rules! impl_Display { ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => { - fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter) -> fmt::Result { + fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut buf = uninitialized_array![u8; 39]; let mut curr = buf.len() as isize; let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf); @@ -196,7 +196,7 @@ macro_rules! impl_Display { unsafe { // need at least 16 bits for the 4-characters-at-a-time to work. - assert!(::mem::size_of::<$u>() >= 2); + assert!(crate::mem::size_of::<$u>() >= 2); // eagerly decode 4 characters at a time while n >= 10000 { @@ -243,7 +243,7 @@ macro_rules! impl_Display { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for $t { #[allow(unused_comparisons)] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let is_nonnegative = *self >= 0; let n = if is_nonnegative { self.$conv_fn() diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index a143b54a61f54..acca8d7ba1533 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -1,11 +1,9 @@ -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#![stable(feature = "futures_api", since = "1.36.0")] -use marker::Unpin; -use ops; -use pin::Pin; -use task::{Poll, Waker}; +use crate::marker::Unpin; +use crate::ops; +use crate::pin::Pin; +use crate::task::{Context, Poll}; /// A future represents an asynchronous computation. /// @@ -18,16 +16,19 @@ use task::{Poll, Waker}; /// The core method of future, `poll`, *attempts* to resolve the future into a /// final value. This method does not block if the value is not ready. Instead, /// the current task is scheduled to be woken up when it's possible to make -/// further progress by `poll`ing again. The wake up is performed using -/// the `waker` argument of the `poll()` method, which is a handle for waking -/// up the current task. +/// further progress by `poll`ing again. The `context` passed to the `poll` +/// method can provide a `Waker`, which is a handle for waking up the current +/// task. /// /// When using a future, you generally won't call `poll` directly, but instead -/// `await!` the value. +/// `.await` the value. #[doc(spotlight)] -#[must_use = "futures do nothing unless polled"] +#[must_use = "futures do nothing unless you `.await` or poll them"] +#[stable(feature = "futures_api", since = "1.36.0")] +#[cfg_attr(not(bootstrap), lang = "future_trait")] pub trait Future { /// The type of value produced on completion. + #[stable(feature = "futures_api", since = "1.36.0")] type Output; /// Attempt to resolve the future to a final value, registering @@ -44,17 +45,18 @@ pub trait Future { /// Once a future has finished, clients should not `poll` it again. /// /// When a future is not ready yet, `poll` returns `Poll::Pending` and - /// stores a clone of the [`Waker`] to be woken once the future can - /// make progress. For example, a future waiting for a socket to become + /// stores a clone of the [`Waker`] copied from the current [`Context`]. + /// This [`Waker`] is then woken once the future can make progress. + /// For example, a future waiting for a socket to become /// readable would call `.clone()` on the [`Waker`] and store it. /// When a signal arrives elsewhere indicating that the socket is readable, - /// `[Waker::wake]` is called and the socket future's task is awoken. + /// [`Waker::wake`] is called and the socket future's task is awoken. /// Once a task has been woken up, it should attempt to `poll` the future /// again, which may or may not produce a final value. /// - /// Note that on multiple calls to `poll`, only the most recent - /// [`Waker`] passed to `poll` should be scheduled to receive a - /// wakeup. + /// Note that on multiple calls to `poll`, only the [`Waker`] from the + /// [`Context`] passed to the most recent call should be scheduled to + /// receive a wakeup. /// /// # Runtime characteristics /// @@ -76,31 +78,35 @@ pub trait Future { /// thread pool (or something similar) to ensure that `poll` can return /// quickly. /// - /// An implementation of `poll` may also never cause memory unsafety. - /// /// # Panics /// - /// Once a future has completed (returned `Ready` from `poll`), - /// then any future calls to `poll` may panic, block forever, or otherwise - /// cause any kind of bad behavior except causing memory unsafety. - /// The `Future` trait itself provides no guarantees about the behavior - /// of `poll` after a future has completed. + /// Once a future has completed (returned `Ready` from `poll`), calling its + /// `poll` method again may panic, block forever, or cause other kinds of + /// problems; the `Future` trait places no requirements on the effects of + /// such a call. However, as the `poll` method is not marked `unsafe`, + /// Rust's usual rules apply: calls must never cause undefined behavior + /// (memory corruption, incorrect use of `unsafe` functions, or the like), + /// regardless of the future's state. /// /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready + /// [`Context`]: ../task/struct.Context.html /// [`Waker`]: ../task/struct.Waker.html /// [`Waker::wake`]: ../task/struct.Waker.html#method.wake - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll; + #[stable(feature = "futures_api", since = "1.36.0")] + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } +#[stable(feature = "futures_api", since = "1.36.0")] impl Future for &mut F { type Output = F::Output; - fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll { - F::poll(Pin::new(&mut **self), waker) + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + F::poll(Pin::new(&mut **self), cx) } } +#[stable(feature = "futures_api", since = "1.36.0")] impl

Future for Pin

where P: Unpin + ops::DerefMut, @@ -108,7 +114,7 @@ where { type Output = <

`]: ../pin/struct.Pin.html /// [`pin module`]: ../../std/pin/index.html #[stable(feature = "pin", since = "1.33.0")] -#[cfg_attr(not(stage0), lang = "unpin")] +#[lang = "unpin"] pub auto trait Unpin {} /// A marker type which does not implement `Unpin`. diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs deleted file mode 100644 index f41d293e80ad3..0000000000000 --- a/src/libcore/mem.rs +++ /dev/null @@ -1,1230 +0,0 @@ -//! Basic functions for dealing with memory. -//! -//! This module contains functions for querying the size and alignment of -//! types, initializing and manipulating memory. - -#![stable(feature = "rust1", since = "1.0.0")] - -use clone; -use cmp; -use fmt; -use hash; -use intrinsics; -use marker::{Copy, PhantomData, Sized}; -use ptr; -use ops::{Deref, DerefMut}; - -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(inline)] -pub use intrinsics::transmute; - -/// Takes ownership and "forgets" about the value **without running its destructor**. -/// -/// Any resources the value manages, such as heap memory or a file handle, will linger -/// forever in an unreachable state. However, it does not guarantee that pointers -/// to this memory will remain valid. -/// -/// * If you want to leak memory, see [`Box::leak`][leak]. -/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw]. -/// * If you want to dispose of a value properly, running its destructor, see -/// [`mem::drop`][drop]. -/// -/// # Safety -/// -/// `forget` is not marked as `unsafe`, because Rust's safety guarantees -/// do not include a guarantee that destructors will always run. For example, -/// a program can create a reference cycle using [`Rc`][rc], or call -/// [`process::exit`][exit] to exit without running destructors. Thus, allowing -/// `mem::forget` from safe code does not fundamentally change Rust's safety -/// guarantees. -/// -/// That said, leaking resources such as memory or I/O objects is usually undesirable, -/// so `forget` is only recommended for specialized use cases like those shown below. -/// -/// Because forgetting a value is allowed, any `unsafe` code you write must -/// allow for this possibility. You cannot return a value and expect that the -/// caller will necessarily run the value's destructor. -/// -/// [rc]: ../../std/rc/struct.Rc.html -/// [exit]: ../../std/process/fn.exit.html -/// -/// # Examples -/// -/// Leak an I/O object, never closing the file: -/// -/// ```no_run -/// use std::mem; -/// use std::fs::File; -/// -/// let file = File::open("foo.txt").unwrap(); -/// mem::forget(file); -/// ``` -/// -/// The practical use cases for `forget` are rather specialized and mainly come -/// up in unsafe or FFI code. -/// -/// ## Use case 1 -/// -/// You have created an uninitialized value using [`mem::uninitialized`][uninit]. -/// You must either initialize or `forget` it on every computation path before -/// Rust drops it automatically, like at the end of a scope or after a panic. -/// Running the destructor on an uninitialized value would be [undefined behavior][ub]. -/// -/// ``` -/// use std::mem; -/// use std::ptr; -/// -/// # let some_condition = false; -/// unsafe { -/// let mut uninit_vec: Vec = mem::uninitialized(); -/// -/// if some_condition { -/// // Initialize the variable. -/// ptr::write(&mut uninit_vec, Vec::new()); -/// } else { -/// // Forget the uninitialized value so its destructor doesn't run. -/// mem::forget(uninit_vec); -/// } -/// } -/// ``` -/// -/// ## Use case 2 -/// -/// You have duplicated the bytes making up a value, without doing a proper -/// [`Clone`][clone]. You need the value's destructor to run only once, -/// because a double `free` is undefined behavior. -/// -/// An example is a possible implementation of [`mem::swap`][swap]: -/// -/// ``` -/// use std::mem; -/// use std::ptr; -/// -/// # #[allow(dead_code)] -/// fn swap(x: &mut T, y: &mut T) { -/// unsafe { -/// // Give ourselves some scratch space to work with -/// let mut t: T = mem::uninitialized(); -/// -/// // Perform the swap, `&mut` pointers never alias -/// ptr::copy_nonoverlapping(&*x, &mut t, 1); -/// ptr::copy_nonoverlapping(&*y, x, 1); -/// ptr::copy_nonoverlapping(&t, y, 1); -/// -/// // y and t now point to the same thing, but we need to completely -/// // forget `t` because we do not want to run the destructor for `T` -/// // on its value, which is still owned somewhere outside this function. -/// mem::forget(t); -/// } -/// } -/// ``` -/// -/// [drop]: fn.drop.html -/// [uninit]: fn.uninitialized.html -/// [clone]: ../clone/trait.Clone.html -/// [swap]: fn.swap.html -/// [box]: ../../std/boxed/struct.Box.html -/// [leak]: ../../std/boxed/struct.Box.html#method.leak -/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw -/// [ub]: ../../reference/behavior-considered-undefined.html -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn forget(t: T) { - ManuallyDrop::new(t); -} - -/// Like [`forget`], but also accepts unsized values. -/// -/// This function is just a shim intended to be removed when the `unsized_locals` feature gets -/// stabilized. -/// -/// [`forget`]: fn.forget.html -#[inline] -#[unstable(feature = "forget_unsized", issue = "0")] -pub fn forget_unsized(t: T) { - unsafe { intrinsics::forget(t) } -} - -/// Returns the size of a type in bytes. -/// -/// More specifically, this is the offset in bytes between successive elements -/// in an array with that item type including alignment padding. Thus, for any -/// type `T` and length `n`, `[T; n]` has a size of `n * size_of::()`. -/// -/// In general, the size of a type is not stable across compilations, but -/// specific types such as primitives are. -/// -/// The following table gives the size for primitives. -/// -/// Type | size_of::\() -/// ---- | --------------- -/// () | 0 -/// bool | 1 -/// u8 | 1 -/// u16 | 2 -/// u32 | 4 -/// u64 | 8 -/// u128 | 16 -/// i8 | 1 -/// i16 | 2 -/// i32 | 4 -/// i64 | 8 -/// i128 | 16 -/// f32 | 4 -/// f64 | 8 -/// char | 4 -/// -/// Furthermore, `usize` and `isize` have the same size. -/// -/// The types `*const T`, `&T`, `Box`, `Option<&T>`, and `Option>` all have -/// the same size. If `T` is Sized, all of those types have the same size as `usize`. -/// -/// The mutability of a pointer does not change its size. As such, `&T` and `&mut T` -/// have the same size. Likewise for `*const T` and `*mut T`. -/// -/// # Size of `#[repr(C)]` items -/// -/// The `C` representation for items has a defined layout. With this layout, -/// the size of items is also stable as long as all fields have a stable size. -/// -/// ## Size of Structs -/// -/// For `structs`, the size is determined by the following algorithm. -/// -/// For each field in the struct ordered by declaration order: -/// -/// 1. Add the size of the field. -/// 2. Round up the current size to the nearest multiple of the next field's [alignment]. -/// -/// Finally, round the size of the struct to the nearest multiple of its [alignment]. -/// The alignment of the struct is usually the largest alignment of all its -/// fields; this can be changed with the use of `repr(align(N))`. -/// -/// Unlike `C`, zero sized structs are not rounded up to one byte in size. -/// -/// ## Size of Enums -/// -/// Enums that carry no data other than the discriminant have the same size as C enums -/// on the platform they are compiled for. -/// -/// ## Size of Unions -/// -/// The size of a union is the size of its largest field. -/// -/// Unlike `C`, zero sized unions are not rounded up to one byte in size. -/// -/// # Examples -/// -/// ``` -/// use std::mem; -/// -/// // Some primitives -/// assert_eq!(4, mem::size_of::()); -/// assert_eq!(8, mem::size_of::()); -/// assert_eq!(0, mem::size_of::<()>()); -/// -/// // Some arrays -/// assert_eq!(8, mem::size_of::<[i32; 2]>()); -/// assert_eq!(12, mem::size_of::<[i32; 3]>()); -/// assert_eq!(0, mem::size_of::<[i32; 0]>()); -/// -/// -/// // Pointer size equality -/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<*const i32>()); -/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::>()); -/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::>()); -/// assert_eq!(mem::size_of::>(), mem::size_of::>>()); -/// ``` -/// -/// Using `#[repr(C)]`. -/// -/// ``` -/// use std::mem; -/// -/// #[repr(C)] -/// struct FieldStruct { -/// first: u8, -/// second: u16, -/// third: u8 -/// } -/// -/// // The size of the first field is 1, so add 1 to the size. Size is 1. -/// // The alignment of the second field is 2, so add 1 to the size for padding. Size is 2. -/// // The size of the second field is 2, so add 2 to the size. Size is 4. -/// // The alignment of the third field is 1, so add 0 to the size for padding. Size is 4. -/// // The size of the third field is 1, so add 1 to the size. Size is 5. -/// // Finally, the alignment of the struct is 2 (because the largest alignment amongst its -/// // fields is 2), so add 1 to the size for padding. Size is 6. -/// assert_eq!(6, mem::size_of::()); -/// -/// #[repr(C)] -/// struct TupleStruct(u8, u16, u8); -/// -/// // Tuple structs follow the same rules. -/// assert_eq!(6, mem::size_of::()); -/// -/// // Note that reordering the fields can lower the size. We can remove both padding bytes -/// // by putting `third` before `second`. -/// #[repr(C)] -/// struct FieldStructOptimized { -/// first: u8, -/// third: u8, -/// second: u16 -/// } -/// -/// assert_eq!(4, mem::size_of::()); -/// -/// // Union size is the size of the largest field. -/// #[repr(C)] -/// union ExampleUnion { -/// smaller: u8, -/// larger: u16 -/// } -/// -/// assert_eq!(2, mem::size_of::()); -/// ``` -/// -/// [alignment]: ./fn.align_of.html -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_promotable] -pub const fn size_of() -> usize { - intrinsics::size_of::() -} - -/// Returns the size of the pointed-to value in bytes. -/// -/// This is usually the same as `size_of::()`. However, when `T` *has* no -/// statically-known size, e.g., a slice [`[T]`][slice] or a [trait object], -/// then `size_of_val` can be used to get the dynamically-known size. -/// -/// [slice]: ../../std/primitive.slice.html -/// [trait object]: ../../book/ch17-02-trait-objects.html -/// -/// # Examples -/// -/// ``` -/// use std::mem; -/// -/// assert_eq!(4, mem::size_of_val(&5i32)); -/// -/// let x: [u8; 13] = [0; 13]; -/// let y: &[u8] = &x; -/// assert_eq!(13, mem::size_of_val(y)); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn size_of_val(val: &T) -> usize { - unsafe { intrinsics::size_of_val(val) } -} - -/// Returns the [ABI]-required minimum alignment of a type. -/// -/// Every reference to a value of the type `T` must be a multiple of this number. -/// -/// This is the alignment used for struct fields. It may be smaller than the preferred alignment. -/// -/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface -/// -/// # Examples -/// -/// ``` -/// # #![allow(deprecated)] -/// use std::mem; -/// -/// assert_eq!(4, mem::min_align_of::()); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")] -pub fn min_align_of() -> usize { - intrinsics::min_align_of::() -} - -/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. -/// -/// Every reference to a value of the type `T` must be a multiple of this number. -/// -/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface -/// -/// # Examples -/// -/// ``` -/// # #![allow(deprecated)] -/// use std::mem; -/// -/// assert_eq!(4, mem::min_align_of_val(&5i32)); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(reason = "use `align_of_val` instead", since = "1.2.0")] -pub fn min_align_of_val(val: &T) -> usize { - unsafe { intrinsics::min_align_of_val(val) } -} - -/// Returns the [ABI]-required minimum alignment of a type. -/// -/// Every reference to a value of the type `T` must be a multiple of this number. -/// -/// This is the alignment used for struct fields. It may be smaller than the preferred alignment. -/// -/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface -/// -/// # Examples -/// -/// ``` -/// use std::mem; -/// -/// assert_eq!(4, mem::align_of::()); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_promotable] -pub const fn align_of() -> usize { - intrinsics::min_align_of::() -} - -/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. -/// -/// Every reference to a value of the type `T` must be a multiple of this number. -/// -/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface -/// -/// # Examples -/// -/// ``` -/// use std::mem; -/// -/// assert_eq!(4, mem::align_of_val(&5i32)); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn align_of_val(val: &T) -> usize { - unsafe { intrinsics::min_align_of_val(val) } -} - -/// Returns `true` if dropping values of type `T` matters. -/// -/// This is purely an optimization hint, and may be implemented conservatively: -/// it may return `true` for types that don't actually need to be dropped. -/// As such always returning `true` would be a valid implementation of -/// this function. However if this function actually returns `false`, then you -/// can be certain dropping `T` has no side effect. -/// -/// Low level implementations of things like collections, which need to manually -/// drop their data, should use this function to avoid unnecessarily -/// trying to drop all their contents when they are destroyed. This might not -/// make a difference in release builds (where a loop that has no side-effects -/// is easily detected and eliminated), but is often a big win for debug builds. -/// -/// Note that `ptr::drop_in_place` already performs this check, so if your workload -/// can be reduced to some small number of drop_in_place calls, using this is -/// unnecessary. In particular note that you can drop_in_place a slice, and that -/// will do a single needs_drop check for all the values. -/// -/// Types like Vec therefore just `drop_in_place(&mut self[..])` without using -/// needs_drop explicitly. Types like HashMap, on the other hand, have to drop -/// values one at a time and should use this API. -/// -/// -/// # Examples -/// -/// Here's an example of how a collection might make use of needs_drop: -/// -/// ``` -/// use std::{mem, ptr}; -/// -/// pub struct MyCollection { -/// # data: [T; 1], -/// /* ... */ -/// } -/// # impl MyCollection { -/// # fn iter_mut(&mut self) -> &mut [T] { &mut self.data } -/// # fn free_buffer(&mut self) {} -/// # } -/// -/// impl Drop for MyCollection { -/// fn drop(&mut self) { -/// unsafe { -/// // drop the data -/// if mem::needs_drop::() { -/// for x in self.iter_mut() { -/// ptr::drop_in_place(x); -/// } -/// } -/// self.free_buffer(); -/// } -/// } -/// } -/// ``` -#[inline] -#[stable(feature = "needs_drop", since = "1.21.0")] -#[rustc_const_unstable(feature = "const_needs_drop")] -pub const fn needs_drop() -> bool { - intrinsics::needs_drop::() -} - -/// Creates a value whose bytes are all zero. -/// -/// This has the same effect as allocating space with -/// [`mem::uninitialized`][uninit] and then zeroing it out. It is useful for -/// FFI sometimes, but should generally be avoided. -/// -/// There is no guarantee that an all-zero byte-pattern represents a valid value of -/// some type `T`. If `T` has a destructor and the value is destroyed (due to -/// a panic or the end of a scope) before being initialized, then the destructor -/// will run on zeroed data, likely leading to [undefined behavior][ub]. -/// -/// See also the documentation for [`mem::uninitialized`][uninit], which has -/// many of the same caveats. -/// -/// [uninit]: fn.uninitialized.html -/// [ub]: ../../reference/behavior-considered-undefined.html -/// -/// # Examples -/// -/// ``` -/// use std::mem; -/// -/// let x: i32 = unsafe { mem::zeroed() }; -/// assert_eq!(0, x); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn zeroed() -> T { - intrinsics::panic_if_uninhabited::(); - intrinsics::init() -} - -/// Bypasses Rust's normal memory-initialization checks by pretending to -/// produce a value of type `T`, while doing nothing at all. -/// -/// **This is incredibly dangerous and should not be done lightly. Deeply -/// consider initializing your memory with a default value instead.** -/// -/// This is useful for FFI functions and initializing arrays sometimes, -/// but should generally be avoided. -/// -/// # Undefined behavior -/// -/// It is [undefined behavior][ub] to read uninitialized memory, even just an -/// uninitialized boolean. For instance, if you branch on the value of such -/// a boolean, your program may take one, both, or neither of the branches. -/// -/// Writing to the uninitialized value is similarly dangerous. Rust believes the -/// value is initialized, and will therefore try to [`Drop`] the uninitialized -/// value and its fields if you try to overwrite it in a normal manner. The only way -/// to safely initialize an uninitialized value is with [`ptr::write`][write], -/// [`ptr::copy`][copy], or [`ptr::copy_nonoverlapping`][copy_no]. -/// -/// If the value does implement [`Drop`], it must be initialized before -/// it goes out of scope (and therefore would be dropped). Note that this -/// includes a `panic` occurring and unwinding the stack suddenly. -/// -/// If you partially initialize an array, you may need to use -/// [`ptr::drop_in_place`][drop_in_place] to remove the elements you have fully -/// initialized followed by [`mem::forget`][mem_forget] to prevent drop running -/// on the array. If a partially allocated array is dropped this will lead to -/// undefined behaviour. -/// -/// # Examples -/// -/// Here's how to safely initialize an array of [`Vec`]s. -/// -/// ``` -/// use std::mem; -/// use std::ptr; -/// -/// // Only declare the array. This safely leaves it -/// // uninitialized in a way that Rust will track for us. -/// // However we can't initialize it element-by-element -/// // safely, and we can't use the `[value; 1000]` -/// // constructor because it only works with `Copy` data. -/// let mut data: [Vec; 1000]; -/// -/// unsafe { -/// // So we need to do this to initialize it. -/// data = mem::uninitialized(); -/// -/// // DANGER ZONE: if anything panics or otherwise -/// // incorrectly reads the array here, we will have -/// // Undefined Behavior. -/// -/// // It's ok to mutably iterate the data, since this -/// // doesn't involve reading it at all. -/// // (ptr and len are statically known for arrays) -/// for elem in &mut data[..] { -/// // *elem = Vec::new() would try to drop the -/// // uninitialized memory at `elem` -- bad! -/// // -/// // Vec::new doesn't allocate or do really -/// // anything. It's only safe to call here -/// // because we know it won't panic. -/// ptr::write(elem, Vec::new()); -/// } -/// -/// // SAFE ZONE: everything is initialized. -/// } -/// -/// println!("{:?}", &data[0]); -/// ``` -/// -/// This example emphasizes exactly how delicate and dangerous using `mem::uninitialized` -/// can be. Note that the [`vec!`] macro *does* let you initialize every element with a -/// value that is only [`Clone`], so the following is semantically equivalent and -/// vastly less dangerous, as long as you can live with an extra heap -/// allocation: -/// -/// ``` -/// let data: Vec> = vec![Vec::new(); 1000]; -/// println!("{:?}", &data[0]); -/// ``` -/// -/// This example shows how to handle partially initialized arrays, which could -/// be found in low-level datastructures. -/// -/// ``` -/// use std::mem; -/// use std::ptr; -/// -/// // Count the number of elements we have assigned. -/// let mut data_len: usize = 0; -/// let mut data: [String; 1000]; -/// -/// unsafe { -/// data = mem::uninitialized(); -/// -/// for elem in &mut data[0..500] { -/// ptr::write(elem, String::from("hello")); -/// data_len += 1; -/// } -/// -/// // For each item in the array, drop if we allocated it. -/// for i in &mut data[0..data_len] { -/// ptr::drop_in_place(i); -/// } -/// } -/// // Forget the data. If this is allowed to drop, you may see a crash such as: -/// // 'mem_uninit_test(2457,0x7fffb55dd380) malloc: *** error for object -/// // 0x7ff3b8402920: pointer being freed was not allocated' -/// mem::forget(data); -/// ``` -/// -/// [`Vec`]: ../../std/vec/struct.Vec.html -/// [`vec!`]: ../../std/macro.vec.html -/// [`Clone`]: ../../std/clone/trait.Clone.html -/// [ub]: ../../reference/behavior-considered-undefined.html -/// [write]: ../ptr/fn.write.html -/// [drop_in_place]: ../ptr/fn.drop_in_place.html -/// [mem_zeroed]: fn.zeroed.html -/// [mem_forget]: fn.forget.html -/// [copy]: ../intrinsics/fn.copy.html -/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html -/// [`Drop`]: ../ops/trait.Drop.html -#[inline] -#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninitialized` instead")] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn uninitialized() -> T { - intrinsics::panic_if_uninhabited::(); - intrinsics::uninit() -} - -/// Swaps the values at two mutable locations, without deinitializing either one. -/// -/// # Examples -/// -/// ``` -/// use std::mem; -/// -/// let mut x = 5; -/// let mut y = 42; -/// -/// mem::swap(&mut x, &mut y); -/// -/// assert_eq!(42, x); -/// assert_eq!(5, y); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn swap(x: &mut T, y: &mut T) { - unsafe { - ptr::swap_nonoverlapping_one(x, y); - } -} - -/// Moves `src` into the referenced `dest`, returning the previous `dest` value. -/// -/// Neither value is dropped. -/// -/// # Examples -/// -/// A simple example: -/// -/// ``` -/// use std::mem; -/// -/// let mut v: Vec = vec![1, 2]; -/// -/// let old_v = mem::replace(&mut v, vec![3, 4, 5]); -/// assert_eq!(2, old_v.len()); -/// assert_eq!(3, v.len()); -/// ``` -/// -/// `replace` allows consumption of a struct field by replacing it with another value. -/// Without `replace` you can run into issues like these: -/// -/// ```compile_fail,E0507 -/// struct Buffer { buf: Vec } -/// -/// impl Buffer { -/// fn get_and_reset(&mut self) -> Vec { -/// // error: cannot move out of dereference of `&mut`-pointer -/// let buf = self.buf; -/// self.buf = Vec::new(); -/// buf -/// } -/// } -/// ``` -/// -/// 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 -/// `self`, allowing it to be returned: -/// -/// ``` -/// # #![allow(dead_code)] -/// use std::mem; -/// -/// # struct Buffer { buf: Vec } -/// impl Buffer { -/// fn get_and_reset(&mut self) -> Vec { -/// mem::replace(&mut self.buf, Vec::new()) -/// } -/// } -/// ``` -/// -/// [`Clone`]: ../../std/clone/trait.Clone.html -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn replace(dest: &mut T, mut src: T) -> T { - swap(dest, &mut src); - src -} - -/// Disposes of a value. -/// -/// This does call the argument's implementation of [`Drop`][drop]. -/// -/// This effectively does nothing for types which implement `Copy`, e.g. -/// integers. Such values are copied and _then_ moved into the function, so the -/// value persists after this function call. -/// -/// This function is not magic; it is literally defined as -/// -/// ``` -/// pub fn drop(_x: T) { } -/// ``` -/// -/// Because `_x` is moved into the function, it is automatically dropped before -/// the function returns. -/// -/// [drop]: ../ops/trait.Drop.html -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// let v = vec![1, 2, 3]; -/// -/// drop(v); // explicitly drop the vector -/// ``` -/// -/// Since [`RefCell`] enforces the borrow rules at runtime, `drop` can -/// release a [`RefCell`] borrow: -/// -/// ``` -/// use std::cell::RefCell; -/// -/// let x = RefCell::new(1); -/// -/// let mut mutable_borrow = x.borrow_mut(); -/// *mutable_borrow = 1; -/// -/// drop(mutable_borrow); // relinquish the mutable borrow on this slot -/// -/// let borrow = x.borrow(); -/// println!("{}", *borrow); -/// ``` -/// -/// Integers and other types implementing [`Copy`] are unaffected by `drop`. -/// -/// ``` -/// #[derive(Copy, Clone)] -/// struct Foo(u8); -/// -/// let x = 1; -/// let y = Foo(2); -/// drop(x); // a copy of `x` is moved and dropped -/// drop(y); // a copy of `y` is moved and dropped -/// -/// println!("x: {}, y: {}", x, y.0); // still available -/// ``` -/// -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// [`Copy`]: ../../std/marker/trait.Copy.html -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn drop(_x: T) { } - -/// Interprets `src` as having type `&U`, and then reads `src` without moving -/// the contained value. -/// -/// This function will unsafely assume the pointer `src` is valid for -/// [`size_of::`][size_of] bytes by transmuting `&T` to `&U` and then reading -/// the `&U`. It will also unsafely create a copy of the contained value instead of -/// moving out of `src`. -/// -/// It is not a compile-time error if `T` and `U` have different sizes, but it -/// is highly encouraged to only invoke this function where `T` and `U` have the -/// same size. This function triggers [undefined behavior][ub] if `U` is larger than -/// `T`. -/// -/// [ub]: ../../reference/behavior-considered-undefined.html -/// [size_of]: fn.size_of.html -/// -/// # Examples -/// -/// ``` -/// use std::mem; -/// -/// #[repr(packed)] -/// struct Foo { -/// bar: u8, -/// } -/// -/// let foo_slice = [10u8]; -/// -/// unsafe { -/// // Copy the data from 'foo_slice' and treat it as a 'Foo' -/// let mut foo_struct: Foo = mem::transmute_copy(&foo_slice); -/// assert_eq!(foo_struct.bar, 10); -/// -/// // Modify the copied data -/// foo_struct.bar = 20; -/// assert_eq!(foo_struct.bar, 20); -/// } -/// -/// // The contents of 'foo_slice' should not have changed -/// assert_eq!(foo_slice, [10]); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn transmute_copy(src: &T) -> U { - ptr::read_unaligned(src as *const T as *const U) -} - -/// Opaque type representing the discriminant of an enum. -/// -/// See the [`discriminant`] function in this module for more information. -/// -/// [`discriminant`]: fn.discriminant.html -#[stable(feature = "discriminant_value", since = "1.21.0")] -pub struct Discriminant(u64, PhantomData T>); - -// N.B. These trait implementations cannot be derived because we don't want any bounds on T. - -#[stable(feature = "discriminant_value", since = "1.21.0")] -impl Copy for Discriminant {} - -#[stable(feature = "discriminant_value", since = "1.21.0")] -impl clone::Clone for Discriminant { - fn clone(&self) -> Self { - *self - } -} - -#[stable(feature = "discriminant_value", since = "1.21.0")] -impl cmp::PartialEq for Discriminant { - fn eq(&self, rhs: &Self) -> bool { - self.0 == rhs.0 - } -} - -#[stable(feature = "discriminant_value", since = "1.21.0")] -impl cmp::Eq for Discriminant {} - -#[stable(feature = "discriminant_value", since = "1.21.0")] -impl hash::Hash for Discriminant { - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - -#[stable(feature = "discriminant_value", since = "1.21.0")] -impl fmt::Debug for Discriminant { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_tuple("Discriminant") - .field(&self.0) - .finish() - } -} - -/// Returns a value uniquely identifying the enum variant in `v`. -/// -/// If `T` is not an enum, calling this function will not result in undefined behavior, but the -/// return value is unspecified. -/// -/// # Stability -/// -/// The discriminant of an enum variant may change if the enum definition changes. A discriminant -/// of some variant will not change between compilations with the same compiler. -/// -/// # Examples -/// -/// This can be used to compare enums that carry data, while disregarding -/// the actual data: -/// -/// ``` -/// use std::mem; -/// -/// enum Foo { A(&'static str), B(i32), C(i32) } -/// -/// assert!(mem::discriminant(&Foo::A("bar")) == mem::discriminant(&Foo::A("baz"))); -/// assert!(mem::discriminant(&Foo::B(1)) == mem::discriminant(&Foo::B(2))); -/// assert!(mem::discriminant(&Foo::B(3)) != mem::discriminant(&Foo::C(3))); -/// ``` -#[stable(feature = "discriminant_value", since = "1.21.0")] -pub fn discriminant(v: &T) -> Discriminant { - unsafe { - Discriminant(intrinsics::discriminant_value(v), PhantomData) - } -} - -/// A wrapper to inhibit compiler from automatically calling `T`’s destructor. -/// -/// This wrapper is 0-cost. -/// -/// # Examples -/// -/// This wrapper helps with explicitly documenting the drop order dependencies between fields of -/// the type: -/// -/// ```rust -/// use std::mem::ManuallyDrop; -/// struct Peach; -/// struct Banana; -/// struct Melon; -/// struct FruitBox { -/// // Immediately clear there’s something non-trivial going on with these fields. -/// peach: ManuallyDrop, -/// melon: Melon, // Field that’s independent of the other two. -/// banana: ManuallyDrop, -/// } -/// -/// impl Drop for FruitBox { -/// fn drop(&mut self) { -/// unsafe { -/// // Explicit ordering in which field destructors are run specified in the intuitive -/// // location – the destructor of the structure containing the fields. -/// // Moreover, one can now reorder fields within the struct however much they want. -/// ManuallyDrop::drop(&mut self.peach); -/// ManuallyDrop::drop(&mut self.banana); -/// } -/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets -/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. -/// } -/// } -/// ``` -#[stable(feature = "manually_drop", since = "1.20.0")] -#[lang = "manually_drop"] -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[repr(transparent)] -pub struct ManuallyDrop { - value: T, -} - -impl ManuallyDrop { - /// Wrap a value to be manually dropped. - /// - /// # Examples - /// - /// ```rust - /// use std::mem::ManuallyDrop; - /// ManuallyDrop::new(Box::new(())); - /// ``` - #[stable(feature = "manually_drop", since = "1.20.0")] - #[inline(always)] - pub const fn new(value: T) -> ManuallyDrop { - ManuallyDrop { value } - } - - /// Extracts the value from the `ManuallyDrop` container. - /// - /// This allows the value to be dropped again. - /// - /// # Examples - /// - /// ```rust - /// use std::mem::ManuallyDrop; - /// let x = ManuallyDrop::new(Box::new(())); - /// let _: Box<()> = ManuallyDrop::into_inner(x); // This drops the `Box`. - /// ``` - #[stable(feature = "manually_drop", since = "1.20.0")] - #[inline(always)] - pub const fn into_inner(slot: ManuallyDrop) -> T { - slot.value - } - - /// Takes the contained value out. - /// - /// This method is primarily intended for moving out values in drop. - /// Instead of using [`ManuallyDrop::drop`] to manually drop the value, - /// you can use this method to take the value and use it however desired. - /// `Drop` will be invoked on the returned value following normal end-of-scope rules. - /// - /// If you have ownership of the container, you can use [`ManuallyDrop::into_inner`] instead. - /// - /// # Safety - /// - /// This function semantically moves out the contained value without preventing further usage. - /// It is up to the user of this method to ensure that this container is not used again. - /// - /// [`ManuallyDrop::drop`]: #method.drop - /// [`ManuallyDrop::into_inner`]: #method.into_inner - #[must_use = "if you don't need the value, you can use `ManuallyDrop::drop` instead"] - #[unstable(feature = "manually_drop_take", issue = "55422")] - #[inline] - pub unsafe fn take(slot: &mut ManuallyDrop) -> T { - ManuallyDrop::into_inner(ptr::read(slot)) - } -} - -impl ManuallyDrop { - /// Manually drops the contained value. - /// - /// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead. - /// - /// # Safety - /// - /// This function runs the destructor of the contained value and thus the wrapped value - /// now represents uninitialized data. It is up to the user of this method to ensure the - /// uninitialized data is not actually used. - /// - /// [`ManuallyDrop::into_inner`]: #method.into_inner - #[stable(feature = "manually_drop", since = "1.20.0")] - #[inline] - pub unsafe fn drop(slot: &mut ManuallyDrop) { - ptr::drop_in_place(&mut slot.value) - } -} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl Deref for ManuallyDrop { - type Target = T; - #[inline(always)] - fn deref(&self) -> &T { - &self.value - } -} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl DerefMut for ManuallyDrop { - #[inline(always)] - fn deref_mut(&mut self) -> &mut T { - &mut self.value - } -} - -/// A newtype to construct uninitialized instances of `T`. -/// -/// The compiler, in general, assumes that variables are properly initialized -/// at their respective type. For example, a variable of reference type must -/// be aligned and non-NULL. This is an invariant that must *always* be upheld, -/// even in unsafe code. As a consequence, zero-initializing a variable of reference -/// type causes instantaneous undefined behavior, no matter whether that reference -/// ever gets used to access memory: -/// -/// ```rust,no_run -/// #![feature(maybe_uninit)] -/// use std::mem::{self, MaybeUninit}; -/// -/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior! -/// // equivalent code with `MaybeUninit` -/// let x: &i32 = unsafe { MaybeUninit::zeroed().into_initialized() }; // undefined behavior! -/// ``` -/// -/// This is exploited by the compiler for various optimizations, such as eliding -/// run-time checks and optimizing `enum` layout. -/// -/// Not initializing memory at all (instead of zero-initializing it) causes the same -/// issue: after all, the initial value of the variable might just happen to be -/// one that violates the invariant. Moreover, uninitialized memory is special -/// in that the compiler knows that it does not have a fixed value. This makes -/// it undefined behavior to have uninitialized data in a variable even if that -/// variable has otherwise no restrictions about which values are valid: -/// -/// ```rust,no_run -/// #![feature(maybe_uninit)] -/// use std::mem::{self, MaybeUninit}; -/// -/// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior! -/// // equivalent code with `MaybeUninit` -/// let x: i32 = unsafe { MaybeUninit::uninitialized().into_initialized() }; // undefined behavior! -/// ``` -/// (Notice that the rules around uninitialized integers are not finalized yet, but -/// until they are, it is advisable to avoid them.) -/// -/// `MaybeUninit` serves to enable unsafe code to deal with uninitialized data: -/// it is a signal to the compiler indicating that the data here might *not* -/// be initialized: -/// -/// ```rust -/// #![feature(maybe_uninit)] -/// use std::mem::MaybeUninit; -/// -/// // Create an explicitly uninitialized reference. The compiler knows that data inside -/// // a `MaybeUninit` may be invalid, and hence this is not UB: -/// let mut x = MaybeUninit::<&i32>::uninitialized(); -/// // Set it to a valid value. -/// x.set(&0); -/// // Extract the initialized data -- this is only allowed *after* properly -/// // initializing `x`! -/// let x = unsafe { x.into_initialized() }; -/// ``` -/// -/// The compiler then knows to not optimize this code. -// FIXME before stabilizing, explain how to initialize a struct field-by-field. -#[allow(missing_debug_implementations)] -#[unstable(feature = "maybe_uninit", issue = "53491")] -// NOTE after stabilizing `MaybeUninit` proceed to deprecate `mem::{uninitialized,zeroed}` -pub union MaybeUninit { - uninit: (), - value: ManuallyDrop, -} - -impl MaybeUninit { - /// Create a new `MaybeUninit` initialized with the given value. - /// - /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. - /// It is your responsibility to make sure `T` gets dropped if it got initialized. - #[unstable(feature = "maybe_uninit", issue = "53491")] - #[inline(always)] - pub const fn new(val: T) -> MaybeUninit { - MaybeUninit { value: ManuallyDrop::new(val) } - } - - /// Creates a new `MaybeUninit` in an uninitialized state. - /// - /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. - /// It is your responsibility to make sure `T` gets dropped if it got initialized. - #[unstable(feature = "maybe_uninit", issue = "53491")] - #[inline(always)] - pub const fn uninitialized() -> MaybeUninit { - MaybeUninit { uninit: () } - } - - /// Creates a new `MaybeUninit` in an uninitialized state, with the memory being - /// filled with `0` bytes. It depends on `T` whether that already makes for - /// proper initialization. For example, `MaybeUninit::zeroed()` is initialized, - /// but `MaybeUninit<&'static i32>::zeroed()` is not because references must not - /// be null. - /// - /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. - /// It is your responsibility to make sure `T` gets dropped if it got initialized. - #[unstable(feature = "maybe_uninit", issue = "53491")] - #[inline] - pub fn zeroed() -> MaybeUninit { - let mut u = MaybeUninit::::uninitialized(); - unsafe { - u.as_mut_ptr().write_bytes(0u8, 1); - } - u - } - - /// Sets the value of the `MaybeUninit`. This overwrites any previous value without dropping it. - /// For your convenience, this also returns a mutable reference to the (now safely initialized) - /// contents of `self`. - #[unstable(feature = "maybe_uninit", issue = "53491")] - #[inline(always)] - pub fn set(&mut self, val: T) -> &mut T { - unsafe { - self.value = ManuallyDrop::new(val); - self.get_mut() - } - } - - /// Gets a pointer to the contained value. Reading from this pointer or turning it - /// into a reference will be undefined behavior unless the `MaybeUninit` is initialized. - #[unstable(feature = "maybe_uninit", issue = "53491")] - #[inline(always)] - pub fn as_ptr(&self) -> *const T { - unsafe { &*self.value as *const T } - } - - /// Gets a mutable pointer to the contained value. Reading from this pointer or turning it - /// into a reference will be undefined behavior unless the `MaybeUninit` is initialized. - #[unstable(feature = "maybe_uninit", issue = "53491")] - #[inline(always)] - pub fn as_mut_ptr(&mut self) -> *mut T { - unsafe { &mut *self.value as *mut T } - } - - /// Extracts the value from the `MaybeUninit` container. This is a great way - /// to ensure that the data will get dropped, because the resulting `T` is - /// subject to the usual drop handling. - /// - /// # Safety - /// - /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. - #[unstable(feature = "maybe_uninit", issue = "53491")] - #[inline(always)] - pub unsafe fn into_initialized(self) -> T { - intrinsics::panic_if_uninhabited::(); - ManuallyDrop::into_inner(self.value) - } - - /// Gets a reference to the contained value. - /// - /// # Safety - /// - /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. - #[unstable(feature = "maybe_uninit_ref", issue = "53491")] - #[inline(always)] - pub unsafe fn get_ref(&self) -> &T { - &*self.value - } - - /// Gets a mutable reference to the contained value. - /// - /// # Safety - /// - /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. - // FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references - // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make - // a final decision about the rules before stabilization. - #[unstable(feature = "maybe_uninit_ref", issue = "53491")] - #[inline(always)] - pub unsafe fn get_mut(&mut self) -> &mut T { - &mut *self.value - } - - /// Gets a pointer to the first element of the array. - #[unstable(feature = "maybe_uninit_slice", issue = "53491")] - #[inline(always)] - pub fn first_ptr(this: &[MaybeUninit]) -> *const T { - this as *const [MaybeUninit] as *const T - } - - /// Gets a mutable pointer to the first element of the array. - #[unstable(feature = "maybe_uninit_slice", issue = "53491")] - #[inline(always)] - pub fn first_ptr_mut(this: &mut [MaybeUninit]) -> *mut T { - this as *mut [MaybeUninit] as *mut T - } -} diff --git a/src/libcore/mem/manually_drop.rs b/src/libcore/mem/manually_drop.rs new file mode 100644 index 0000000000000..3ad1223e331ec --- /dev/null +++ b/src/libcore/mem/manually_drop.rs @@ -0,0 +1,146 @@ +use crate::ptr; +use crate::ops::{Deref, DerefMut}; + +/// A wrapper to inhibit compiler from automatically calling `T`’s destructor. +/// +/// This wrapper is 0-cost. +/// +/// `ManuallyDrop` is subject to the same layout optimizations as `T`. +/// As a consequence, it has *no effect* on the assumptions that the compiler makes +/// about all values being initialized at their type. In particular, initializing +/// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior. +/// If you need to handle uninitialized data, use [`MaybeUninit`] instead. +/// +/// # Examples +/// +/// This wrapper helps with explicitly documenting the drop order dependencies between fields of +/// the type: +/// +/// ```rust +/// use std::mem::ManuallyDrop; +/// struct Peach; +/// struct Banana; +/// struct Melon; +/// struct FruitBox { +/// // Immediately clear there’s something non-trivial going on with these fields. +/// peach: ManuallyDrop, +/// melon: Melon, // Field that’s independent of the other two. +/// banana: ManuallyDrop, +/// } +/// +/// impl Drop for FruitBox { +/// fn drop(&mut self) { +/// unsafe { +/// // Explicit ordering in which field destructors are run specified in the intuitive +/// // location – the destructor of the structure containing the fields. +/// // Moreover, one can now reorder fields within the struct however much they want. +/// ManuallyDrop::drop(&mut self.peach); +/// ManuallyDrop::drop(&mut self.banana); +/// } +/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets +/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. +/// } +/// } +/// ``` +/// +/// [`mem::zeroed`]: fn.zeroed.html +/// [`MaybeUninit`]: union.MaybeUninit.html +#[stable(feature = "manually_drop", since = "1.20.0")] +#[lang = "manually_drop"] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct ManuallyDrop { + value: T, +} + +impl ManuallyDrop { + /// Wrap a value to be manually dropped. + /// + /// # Examples + /// + /// ```rust + /// use std::mem::ManuallyDrop; + /// ManuallyDrop::new(Box::new(())); + /// ``` + #[stable(feature = "manually_drop", since = "1.20.0")] + #[inline(always)] + pub const fn new(value: T) -> ManuallyDrop { + ManuallyDrop { value } + } + + /// Extracts the value from the `ManuallyDrop` container. + /// + /// This allows the value to be dropped again. + /// + /// # Examples + /// + /// ```rust + /// use std::mem::ManuallyDrop; + /// let x = ManuallyDrop::new(Box::new(())); + /// let _: Box<()> = ManuallyDrop::into_inner(x); // This drops the `Box`. + /// ``` + #[stable(feature = "manually_drop", since = "1.20.0")] + #[inline(always)] + pub const fn into_inner(slot: ManuallyDrop) -> T { + slot.value + } + + /// Takes the contained value out. + /// + /// This method is primarily intended for moving out values in drop. + /// Instead of using [`ManuallyDrop::drop`] to manually drop the value, + /// you can use this method to take the value and use it however desired. + /// `Drop` will be invoked on the returned value following normal end-of-scope rules. + /// + /// If you have ownership of the container, you can use [`ManuallyDrop::into_inner`] instead. + /// + /// # Safety + /// + /// This function semantically moves out the contained value without preventing further usage. + /// It is up to the user of this method to ensure that this container is not used again. + /// + /// [`ManuallyDrop::drop`]: #method.drop + /// [`ManuallyDrop::into_inner`]: #method.into_inner + #[must_use = "if you don't need the value, you can use `ManuallyDrop::drop` instead"] + #[unstable(feature = "manually_drop_take", issue = "55422")] + #[inline] + pub unsafe fn take(slot: &mut ManuallyDrop) -> T { + ManuallyDrop::into_inner(ptr::read(slot)) + } +} + +impl ManuallyDrop { + /// Manually drops the contained value. + /// + /// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead. + /// + /// # Safety + /// + /// This function runs the destructor of the contained value and thus the wrapped value + /// now represents uninitialized data. It is up to the user of this method to ensure the + /// uninitialized data is not actually used. + /// + /// [`ManuallyDrop::into_inner`]: #method.into_inner + #[stable(feature = "manually_drop", since = "1.20.0")] + #[inline] + pub unsafe fn drop(slot: &mut ManuallyDrop) { + ptr::drop_in_place(&mut slot.value) + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl Deref for ManuallyDrop { + type Target = T; + #[inline(always)] + fn deref(&self) -> &T { + &self.value + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl DerefMut for ManuallyDrop { + #[inline(always)] + fn deref_mut(&mut self) -> &mut T { + &mut self.value + } +} diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs new file mode 100644 index 0000000000000..28e1e22ba7ff2 --- /dev/null +++ b/src/libcore/mem/maybe_uninit.rs @@ -0,0 +1,533 @@ +use crate::intrinsics; +use crate::mem::ManuallyDrop; + +/// A wrapper type to construct uninitialized instances of `T`. +/// +/// # Initialization invariant +/// +/// The compiler, in general, assumes that variables are properly initialized +/// at their respective type. For example, a variable of reference type must +/// be aligned and non-NULL. This is an invariant that must *always* be upheld, +/// even in unsafe code. As a consequence, zero-initializing a variable of reference +/// type causes instantaneous [undefined behavior][ub], no matter whether that reference +/// ever gets used to access memory: +/// +/// ```rust,no_run +/// use std::mem::{self, MaybeUninit}; +/// +/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior! +/// // The equivalent code with `MaybeUninit<&i32>`: +/// let x: &i32 = unsafe { MaybeUninit::zeroed().assume_init() }; // undefined behavior! +/// ``` +/// +/// This is exploited by the compiler for various optimizations, such as eliding +/// run-time checks and optimizing `enum` layout. +/// +/// Similarly, entirely uninitialized memory may have any content, while a `bool` must +/// always be `true` or `false`. Hence, creating an uninitialized `bool` is undefined behavior: +/// +/// ```rust,no_run +/// use std::mem::{self, MaybeUninit}; +/// +/// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior! +/// // The equivalent code with `MaybeUninit`: +/// let b: bool = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! +/// ``` +/// +/// Moreover, uninitialized memory is special in that the compiler knows that +/// it does not have a fixed value. This makes it undefined behavior to have +/// uninitialized data in a variable even if that variable has an integer type, +/// which otherwise can hold any *fixed* bit pattern: +/// +/// ```rust,no_run +/// use std::mem::{self, MaybeUninit}; +/// +/// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior! +/// // The equivalent code with `MaybeUninit`: +/// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! +/// ``` +/// (Notice that the rules around uninitialized integers are not finalized yet, but +/// until they are, it is advisable to avoid them.) +/// +/// On top of that, remember that most types have additional invariants beyond merely +/// being considered initialized at the type level. For example, a `1`-initialized [`Vec`] +/// is considered initialized because the only requirement the compiler knows about it +/// is that the data pointer must be non-null. Creating such a `Vec` does not cause +/// *immediate* undefined behavior, but will cause undefined behavior with most +/// safe operations (including dropping it). +/// +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// +/// # Examples +/// +/// `MaybeUninit` serves to enable unsafe code to deal with uninitialized data. +/// It is a signal to the compiler indicating that the data here might *not* +/// be initialized: +/// +/// ```rust +/// use std::mem::MaybeUninit; +/// +/// // Create an explicitly uninitialized reference. The compiler knows that data inside +/// // a `MaybeUninit` may be invalid, and hence this is not UB: +/// let mut x = MaybeUninit::<&i32>::uninit(); +/// // Set it to a valid value. +/// unsafe { x.as_mut_ptr().write(&0); } +/// // Extract the initialized data -- this is only allowed *after* properly +/// // initializing `x`! +/// let x = unsafe { x.assume_init() }; +/// ``` +/// +/// The compiler then knows to not make any incorrect assumptions or optimizations on this code. +/// +/// You can think of `MaybeUninit` as being a bit like `Option` but without +/// any of the run-time tracking and without any of the safety checks. +/// +/// ## out-pointers +/// +/// You can use `MaybeUninit` to implement "out-pointers": instead of returning data +/// from a function, pass it a pointer to some (uninitialized) memory to put the +/// result into. This can be useful when it is important for the caller to control +/// how the memory the result is stored in gets allocated, and you want to avoid +/// unnecessary moves. +/// +/// ``` +/// use std::mem::MaybeUninit; +/// +/// unsafe fn make_vec(out: *mut Vec) { +/// // `write` does not drop the old contents, which is important. +/// out.write(vec![1, 2, 3]); +/// } +/// +/// let mut v = MaybeUninit::uninit(); +/// unsafe { make_vec(v.as_mut_ptr()); } +/// // Now we know `v` is initialized! This also makes sure the vector gets +/// // properly dropped. +/// let v = unsafe { v.assume_init() }; +/// assert_eq!(&v, &[1, 2, 3]); +/// ``` +/// +/// ## Initializing an array element-by-element +/// +/// `MaybeUninit` can be used to initialize a large array element-by-element: +/// +/// ``` +/// use std::mem::{self, MaybeUninit}; +/// use std::ptr; +/// +/// let data = { +/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is +/// // safe because the type we are claiming to have initialized here is a +/// // bunch of `MaybeUninit`s, which do not require initialization. +/// let mut data: [MaybeUninit>; 1000] = unsafe { +/// MaybeUninit::uninit().assume_init() +/// }; +/// +/// // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop, +/// // we have a memory leak, but there is no memory safety issue. +/// for elem in &mut data[..] { +/// unsafe { ptr::write(elem.as_mut_ptr(), vec![42]); } +/// } +/// +/// // Everything is initialized. Transmute the array to the +/// // initialized type. +/// unsafe { mem::transmute::<_, [Vec; 1000]>(data) } +/// }; +/// +/// assert_eq!(&data[0], &[42]); +/// ``` +/// +/// You can also work with partially initialized arrays, which could +/// be found in low-level datastructures. +/// +/// ``` +/// use std::mem::MaybeUninit; +/// use std::ptr; +/// +/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is +/// // safe because the type we are claiming to have initialized here is a +/// // bunch of `MaybeUninit`s, which do not require initialization. +/// let mut data: [MaybeUninit; 1000] = unsafe { MaybeUninit::uninit().assume_init() }; +/// // Count the number of elements we have assigned. +/// let mut data_len: usize = 0; +/// +/// for elem in &mut data[0..500] { +/// unsafe { ptr::write(elem.as_mut_ptr(), String::from("hello")); } +/// data_len += 1; +/// } +/// +/// // For each item in the array, drop if we allocated it. +/// for elem in &mut data[0..data_len] { +/// unsafe { ptr::drop_in_place(elem.as_mut_ptr()); } +/// } +/// ``` +/// +/// ## Initializing a struct field-by-field +/// +/// There is currently no supported way to create a raw pointer or reference +/// to a field of a struct inside `MaybeUninit`. That means it is not possible +/// to create a struct by calling `MaybeUninit::uninit::()` and then writing +/// to its fields. +/// +/// [ub]: ../../reference/behavior-considered-undefined.html +/// +/// # Layout +/// +/// `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as `T`: +/// +/// ```rust +/// use std::mem::{MaybeUninit, size_of, align_of}; +/// assert_eq!(size_of::>(), size_of::()); +/// assert_eq!(align_of::>(), align_of::()); +/// ``` +/// +/// However remember that a type *containing* a `MaybeUninit` is not necessarily the same +/// layout; Rust does not in general guarantee that the fields of a `Foo` have the same order as +/// a `Foo` even if `T` and `U` have the same size and alignment. Furthermore because any bit +/// value is valid for a `MaybeUninit` the compiler can't apply non-zero/niche-filling +/// optimizations, potentially resulting in a larger size: +/// +/// ```rust +/// # use std::mem::{MaybeUninit, size_of}; +/// assert_eq!(size_of::>(), 1); +/// assert_eq!(size_of::>>(), 2); +/// ``` +/// +/// If `T` is FFI-safe, then so is `MaybeUninit`. +/// +/// While `MaybeUninit` is `#[repr(transparent)]` (indicating it guarantees the same size, +/// alignment, and ABI as `T`), this does *not* change any of the previous caveats. `Option` and +/// `Option>` may still have different sizes, and types containing a field of type +/// `T` may be laid out (and sized) differently than if that field were `MaybeUninit`. +/// `MaybeUninit` is a union type, and `#[repr(transparent)]` on unions is unstable (see [the +/// tracking issue](https://github.com/rust-lang/rust/issues/60405)). Over time, the exact +/// guarantees of `#[repr(transparent)]` on unions may evolve, and `MaybeUninit` may or may not +/// remain `#[repr(transparent)]`. That said, `MaybeUninit` will *always* guarantee that it has +/// the same size, alignment, and ABI as `T`; it's just that the way `MaybeUninit` implements that +/// guarantee may evolve. +#[allow(missing_debug_implementations)] +#[stable(feature = "maybe_uninit", since = "1.36.0")] +#[derive(Copy)] +#[cfg_attr(not(bootstrap), repr(transparent))] +pub union MaybeUninit { + uninit: (), + value: ManuallyDrop, +} + +#[stable(feature = "maybe_uninit", since = "1.36.0")] +impl Clone for MaybeUninit { + #[inline(always)] + fn clone(&self) -> Self { + // Not calling `T::clone()`, we cannot know if we are initialized enough for that. + *self + } +} + +impl MaybeUninit { + /// Creates a new `MaybeUninit` initialized with the given value. + /// It is safe to call [`assume_init`] on the return value of this function. + /// + /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. + /// It is your responsibility to make sure `T` gets dropped if it got initialized. + /// + /// [`assume_init`]: #method.assume_init + #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[inline(always)] + pub const fn new(val: T) -> MaybeUninit { + MaybeUninit { value: ManuallyDrop::new(val) } + } + + /// Creates a new `MaybeUninit` in an uninitialized state. + /// + /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. + /// It is your responsibility to make sure `T` gets dropped if it got initialized. + /// + /// See the [type-level documentation][type] for some examples. + /// + /// [type]: union.MaybeUninit.html + #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[inline(always)] + pub const fn uninit() -> MaybeUninit { + MaybeUninit { uninit: () } + } + + /// Creates a new `MaybeUninit` in an uninitialized state, with the memory being + /// filled with `0` bytes. It depends on `T` whether that already makes for + /// proper initialization. For example, `MaybeUninit::zeroed()` is initialized, + /// but `MaybeUninit<&'static i32>::zeroed()` is not because references must not + /// be null. + /// + /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. + /// It is your responsibility to make sure `T` gets dropped if it got initialized. + /// + /// # Example + /// + /// Correct usage of this function: initializing a struct with zero, where all + /// fields of the struct can hold the bit-pattern 0 as a valid value. + /// + /// ```rust + /// use std::mem::MaybeUninit; + /// + /// let x = MaybeUninit::<(u8, bool)>::zeroed(); + /// let x = unsafe { x.assume_init() }; + /// assert_eq!(x, (0, false)); + /// ``` + /// + /// *Incorrect* usage of this function: initializing a struct with zero, where some fields + /// cannot hold 0 as a valid value. + /// + /// ```rust,no_run + /// use std::mem::MaybeUninit; + /// + /// enum NotZero { One = 1, Two = 2 }; + /// + /// let x = MaybeUninit::<(u8, NotZero)>::zeroed(); + /// let x = unsafe { x.assume_init() }; + /// // Inside a pair, we create a `NotZero` that does not have a valid discriminant. + /// // This is undefined behavior. + /// ``` + #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[inline] + pub fn zeroed() -> MaybeUninit { + let mut u = MaybeUninit::::uninit(); + unsafe { + u.as_mut_ptr().write_bytes(0u8, 1); + } + u + } + + /// Sets the value of the `MaybeUninit`. This overwrites any previous value + /// without dropping it, so be careful not to use this twice unless you want to + /// skip running the destructor. For your convenience, this also returns a mutable + /// reference to the (now safely initialized) contents of `self`. + #[unstable(feature = "maybe_uninit_extra", issue = "53491")] + #[inline(always)] + pub fn write(&mut self, val: T) -> &mut T { + unsafe { + self.value = ManuallyDrop::new(val); + self.get_mut() + } + } + + /// Gets a pointer to the contained value. Reading from this pointer or turning it + /// into a reference is undefined behavior unless the `MaybeUninit` is initialized. + /// Writing to memory that this pointer (non-transitively) points to is undefined behavior + /// (except inside an `UnsafeCell`). + /// + /// # Examples + /// + /// Correct usage of this method: + /// + /// ```rust + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::>::uninit(); + /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); } + /// // Create a reference into the `MaybeUninit`. This is okay because we initialized it. + /// let x_vec = unsafe { &*x.as_ptr() }; + /// assert_eq!(x_vec.len(), 3); + /// ``` + /// + /// *Incorrect* usage of this method: + /// + /// ```rust,no_run + /// use std::mem::MaybeUninit; + /// + /// let x = MaybeUninit::>::uninit(); + /// let x_vec = unsafe { &*x.as_ptr() }; + /// // We have created a reference to an uninitialized vector! This is undefined behavior. + /// ``` + /// + /// (Notice that the rules around references to uninitialized data are not finalized yet, but + /// until they are, it is advisable to avoid them.) + #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[inline(always)] + pub fn as_ptr(&self) -> *const T { + unsafe { &*self.value as *const T } + } + + /// Gets a mutable pointer to the contained value. Reading from this pointer or turning it + /// into a reference is undefined behavior unless the `MaybeUninit` is initialized. + /// + /// # Examples + /// + /// Correct usage of this method: + /// + /// ```rust + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::>::uninit(); + /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); } + /// // Create a reference into the `MaybeUninit>`. + /// // This is okay because we initialized it. + /// let x_vec = unsafe { &mut *x.as_mut_ptr() }; + /// x_vec.push(3); + /// assert_eq!(x_vec.len(), 4); + /// ``` + /// + /// *Incorrect* usage of this method: + /// + /// ```rust,no_run + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::>::uninit(); + /// let x_vec = unsafe { &mut *x.as_mut_ptr() }; + /// // We have created a reference to an uninitialized vector! This is undefined behavior. + /// ``` + /// + /// (Notice that the rules around references to uninitialized data are not finalized yet, but + /// until they are, it is advisable to avoid them.) + #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[inline(always)] + pub fn as_mut_ptr(&mut self) -> *mut T { + unsafe { &mut *self.value as *mut T } + } + + /// Extracts the value from the `MaybeUninit` container. This is a great way + /// to ensure that the data will get dropped, because the resulting `T` is + /// subject to the usual drop handling. + /// + /// # Safety + /// + /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized + /// state. Calling this when the content is not yet fully initialized causes immediate undefined + /// behavior. The [type-level documentation][inv] contains more information about + /// this initialization invariant. + /// + /// [inv]: #initialization-invariant + /// + /// # Examples + /// + /// Correct usage of this method: + /// + /// ```rust + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::::uninit(); + /// unsafe { x.as_mut_ptr().write(true); } + /// let x_init = unsafe { x.assume_init() }; + /// assert_eq!(x_init, true); + /// ``` + /// + /// *Incorrect* usage of this method: + /// + /// ```rust,no_run + /// use std::mem::MaybeUninit; + /// + /// let x = MaybeUninit::>::uninit(); + /// let x_init = unsafe { x.assume_init() }; + /// // `x` had not been initialized yet, so this last line caused undefined behavior. + /// ``` + #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[inline(always)] + pub unsafe fn assume_init(self) -> T { + intrinsics::panic_if_uninhabited::(); + ManuallyDrop::into_inner(self.value) + } + + /// Reads the value from the `MaybeUninit` container. The resulting `T` is subject + /// to the usual drop handling. + /// + /// Whenever possible, it is preferrable to use [`assume_init`] instead, which + /// prevents duplicating the content of the `MaybeUninit`. + /// + /// # Safety + /// + /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized + /// state. Calling this when the content is not yet fully initialized causes undefined + /// behavior. The [type-level documentation][inv] contains more information about + /// this initialization invariant. + /// + /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit`. When using + /// multiple copies of the data (by calling `read` multiple times, or first + /// calling `read` and then [`assume_init`]), it is your responsibility + /// to ensure that that data may indeed be duplicated. + /// + /// [inv]: #initialization-invariant + /// [`assume_init`]: #method.assume_init + /// + /// # Examples + /// + /// Correct usage of this method: + /// + /// ```rust + /// #![feature(maybe_uninit_extra)] + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::::uninit(); + /// x.write(13); + /// let x1 = unsafe { x.read() }; + /// // `u32` is `Copy`, so we may read multiple times. + /// let x2 = unsafe { x.read() }; + /// assert_eq!(x1, x2); + /// + /// let mut x = MaybeUninit::>>::uninit(); + /// x.write(None); + /// let x1 = unsafe { x.read() }; + /// // Duplicating a `None` value is okay, so we may read multiple times. + /// let x2 = unsafe { x.read() }; + /// assert_eq!(x1, x2); + /// ``` + /// + /// *Incorrect* usage of this method: + /// + /// ```rust,no_run + /// #![feature(maybe_uninit_extra)] + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::>>::uninit(); + /// x.write(Some(vec![0,1,2])); + /// let x1 = unsafe { x.read() }; + /// let x2 = unsafe { x.read() }; + /// // We now created two copies of the same vector, leading to a double-free when + /// // they both get dropped! + /// ``` + #[unstable(feature = "maybe_uninit_extra", issue = "53491")] + #[inline(always)] + pub unsafe fn read(&self) -> T { + intrinsics::panic_if_uninhabited::(); + self.as_ptr().read() + } + + /// Gets a reference to the contained value. + /// + /// # Safety + /// + /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized + /// state. Calling this when the content is not yet fully initialized causes undefined + /// behavior. + #[unstable(feature = "maybe_uninit_ref", issue = "53491")] + #[inline(always)] + pub unsafe fn get_ref(&self) -> &T { + &*self.value + } + + /// Gets a mutable reference to the contained value. + /// + /// # Safety + /// + /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized + /// state. Calling this when the content is not yet fully initialized causes undefined + /// behavior. + // FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references + // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make + // a final decision about the rules before stabilization. + #[unstable(feature = "maybe_uninit_ref", issue = "53491")] + #[inline(always)] + pub unsafe fn get_mut(&mut self) -> &mut T { + &mut *self.value + } + + /// Gets a pointer to the first element of the array. + #[unstable(feature = "maybe_uninit_slice", issue = "53491")] + #[inline(always)] + pub fn first_ptr(this: &[MaybeUninit]) -> *const T { + this as *const [MaybeUninit] as *const T + } + + /// Gets a mutable pointer to the first element of the array. + #[unstable(feature = "maybe_uninit_slice", issue = "53491")] + #[inline(always)] + pub fn first_ptr_mut(this: &mut [MaybeUninit]) -> *mut T { + this as *mut [MaybeUninit] as *mut T + } +} diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs new file mode 100644 index 0000000000000..e110e93a95412 --- /dev/null +++ b/src/libcore/mem/mod.rs @@ -0,0 +1,810 @@ +//! Basic functions for dealing with memory. +//! +//! This module contains functions for querying the size and alignment of +//! types, initializing and manipulating memory. + +#![stable(feature = "rust1", since = "1.0.0")] + +use crate::clone; +use crate::cmp; +use crate::fmt; +use crate::hash; +use crate::intrinsics; +use crate::marker::{Copy, PhantomData, Sized}; +use crate::ptr; + +mod manually_drop; +#[stable(feature = "manually_drop", since = "1.20.0")] +pub use manually_drop::ManuallyDrop; + +mod maybe_uninit; +#[stable(feature = "maybe_uninit", since = "1.36.0")] +pub use maybe_uninit::MaybeUninit; + +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(inline)] +pub use crate::intrinsics::transmute; + +/// Takes ownership and "forgets" about the value **without running its destructor**. +/// +/// Any resources the value manages, such as heap memory or a file handle, will linger +/// forever in an unreachable state. However, it does not guarantee that pointers +/// to this memory will remain valid. +/// +/// * If you want to leak memory, see [`Box::leak`][leak]. +/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw]. +/// * If you want to dispose of a value properly, running its destructor, see +/// [`mem::drop`][drop]. +/// +/// # Safety +/// +/// `forget` is not marked as `unsafe`, because Rust's safety guarantees +/// do not include a guarantee that destructors will always run. For example, +/// a program can create a reference cycle using [`Rc`][rc], or call +/// [`process::exit`][exit] to exit without running destructors. Thus, allowing +/// `mem::forget` from safe code does not fundamentally change Rust's safety +/// guarantees. +/// +/// That said, leaking resources such as memory or I/O objects is usually undesirable, +/// so `forget` is only recommended for specialized use cases like those shown below. +/// +/// Because forgetting a value is allowed, any `unsafe` code you write must +/// allow for this possibility. You cannot return a value and expect that the +/// caller will necessarily run the value's destructor. +/// +/// [rc]: ../../std/rc/struct.Rc.html +/// [exit]: ../../std/process/fn.exit.html +/// +/// # Examples +/// +/// Leak an I/O object, never closing the file: +/// +/// ```no_run +/// use std::mem; +/// use std::fs::File; +/// +/// let file = File::open("foo.txt").unwrap(); +/// mem::forget(file); +/// ``` +/// +/// The practical use cases for `forget` are rather specialized and mainly come +/// up in unsafe or FFI code. +/// +/// [drop]: fn.drop.html +/// [uninit]: fn.uninitialized.html +/// [clone]: ../clone/trait.Clone.html +/// [swap]: fn.swap.html +/// [box]: ../../std/boxed/struct.Box.html +/// [leak]: ../../std/boxed/struct.Box.html#method.leak +/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw +/// [ub]: ../../reference/behavior-considered-undefined.html +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn forget(t: T) { + ManuallyDrop::new(t); +} + +/// Like [`forget`], but also accepts unsized values. +/// +/// This function is just a shim intended to be removed when the `unsized_locals` feature gets +/// stabilized. +/// +/// [`forget`]: fn.forget.html +#[inline] +#[unstable(feature = "forget_unsized", issue = "0")] +pub fn forget_unsized(t: T) { + unsafe { intrinsics::forget(t) } +} + +/// Returns the size of a type in bytes. +/// +/// More specifically, this is the offset in bytes between successive elements +/// in an array with that item type including alignment padding. Thus, for any +/// type `T` and length `n`, `[T; n]` has a size of `n * size_of::()`. +/// +/// In general, the size of a type is not stable across compilations, but +/// specific types such as primitives are. +/// +/// The following table gives the size for primitives. +/// +/// Type | size_of::\() +/// ---- | --------------- +/// () | 0 +/// bool | 1 +/// u8 | 1 +/// u16 | 2 +/// u32 | 4 +/// u64 | 8 +/// u128 | 16 +/// i8 | 1 +/// i16 | 2 +/// i32 | 4 +/// i64 | 8 +/// i128 | 16 +/// f32 | 4 +/// f64 | 8 +/// char | 4 +/// +/// Furthermore, `usize` and `isize` have the same size. +/// +/// The types `*const T`, `&T`, `Box`, `Option<&T>`, and `Option>` all have +/// the same size. If `T` is Sized, all of those types have the same size as `usize`. +/// +/// The mutability of a pointer does not change its size. As such, `&T` and `&mut T` +/// have the same size. Likewise for `*const T` and `*mut T`. +/// +/// # Size of `#[repr(C)]` items +/// +/// The `C` representation for items has a defined layout. With this layout, +/// the size of items is also stable as long as all fields have a stable size. +/// +/// ## Size of Structs +/// +/// For `structs`, the size is determined by the following algorithm. +/// +/// For each field in the struct ordered by declaration order: +/// +/// 1. Add the size of the field. +/// 2. Round up the current size to the nearest multiple of the next field's [alignment]. +/// +/// Finally, round the size of the struct to the nearest multiple of its [alignment]. +/// The alignment of the struct is usually the largest alignment of all its +/// fields; this can be changed with the use of `repr(align(N))`. +/// +/// Unlike `C`, zero sized structs are not rounded up to one byte in size. +/// +/// ## Size of Enums +/// +/// Enums that carry no data other than the discriminant have the same size as C enums +/// on the platform they are compiled for. +/// +/// ## Size of Unions +/// +/// The size of a union is the size of its largest field. +/// +/// Unlike `C`, zero sized unions are not rounded up to one byte in size. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// // Some primitives +/// assert_eq!(4, mem::size_of::()); +/// assert_eq!(8, mem::size_of::()); +/// assert_eq!(0, mem::size_of::<()>()); +/// +/// // Some arrays +/// assert_eq!(8, mem::size_of::<[i32; 2]>()); +/// assert_eq!(12, mem::size_of::<[i32; 3]>()); +/// assert_eq!(0, mem::size_of::<[i32; 0]>()); +/// +/// +/// // Pointer size equality +/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<*const i32>()); +/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::>()); +/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::>()); +/// assert_eq!(mem::size_of::>(), mem::size_of::>>()); +/// ``` +/// +/// Using `#[repr(C)]`. +/// +/// ``` +/// use std::mem; +/// +/// #[repr(C)] +/// struct FieldStruct { +/// first: u8, +/// second: u16, +/// third: u8 +/// } +/// +/// // The size of the first field is 1, so add 1 to the size. Size is 1. +/// // The alignment of the second field is 2, so add 1 to the size for padding. Size is 2. +/// // The size of the second field is 2, so add 2 to the size. Size is 4. +/// // The alignment of the third field is 1, so add 0 to the size for padding. Size is 4. +/// // The size of the third field is 1, so add 1 to the size. Size is 5. +/// // Finally, the alignment of the struct is 2 (because the largest alignment amongst its +/// // fields is 2), so add 1 to the size for padding. Size is 6. +/// assert_eq!(6, mem::size_of::()); +/// +/// #[repr(C)] +/// struct TupleStruct(u8, u16, u8); +/// +/// // Tuple structs follow the same rules. +/// assert_eq!(6, mem::size_of::()); +/// +/// // Note that reordering the fields can lower the size. We can remove both padding bytes +/// // by putting `third` before `second`. +/// #[repr(C)] +/// struct FieldStructOptimized { +/// first: u8, +/// third: u8, +/// second: u16 +/// } +/// +/// assert_eq!(4, mem::size_of::()); +/// +/// // Union size is the size of the largest field. +/// #[repr(C)] +/// union ExampleUnion { +/// smaller: u8, +/// larger: u16 +/// } +/// +/// assert_eq!(2, mem::size_of::()); +/// ``` +/// +/// [alignment]: ./fn.align_of.html +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_promotable] +pub const fn size_of() -> usize { + intrinsics::size_of::() +} + +/// Returns the size of the pointed-to value in bytes. +/// +/// This is usually the same as `size_of::()`. However, when `T` *has* no +/// statically-known size, e.g., a slice [`[T]`][slice] or a [trait object], +/// then `size_of_val` can be used to get the dynamically-known size. +/// +/// [slice]: ../../std/primitive.slice.html +/// [trait object]: ../../book/ch17-02-trait-objects.html +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::size_of_val(&5i32)); +/// +/// let x: [u8; 13] = [0; 13]; +/// let y: &[u8] = &x; +/// assert_eq!(13, mem::size_of_val(y)); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn size_of_val(val: &T) -> usize { + unsafe { intrinsics::size_of_val(val) } +} + +/// Returns the [ABI]-required minimum alignment of a type. +/// +/// Every reference to a value of the type `T` must be a multiple of this number. +/// +/// This is the alignment used for struct fields. It may be smaller than the preferred alignment. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// +/// # Examples +/// +/// ``` +/// # #![allow(deprecated)] +/// use std::mem; +/// +/// assert_eq!(4, mem::min_align_of::()); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")] +pub fn min_align_of() -> usize { + intrinsics::min_align_of::() +} + +/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. +/// +/// Every reference to a value of the type `T` must be a multiple of this number. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// +/// # Examples +/// +/// ``` +/// # #![allow(deprecated)] +/// use std::mem; +/// +/// assert_eq!(4, mem::min_align_of_val(&5i32)); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_deprecated(reason = "use `align_of_val` instead", since = "1.2.0")] +pub fn min_align_of_val(val: &T) -> usize { + unsafe { intrinsics::min_align_of_val(val) } +} + +/// Returns the [ABI]-required minimum alignment of a type. +/// +/// Every reference to a value of the type `T` must be a multiple of this number. +/// +/// This is the alignment used for struct fields. It may be smaller than the preferred alignment. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::align_of::()); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_promotable] +pub const fn align_of() -> usize { + intrinsics::min_align_of::() +} + +/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. +/// +/// Every reference to a value of the type `T` must be a multiple of this number. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::align_of_val(&5i32)); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn align_of_val(val: &T) -> usize { + unsafe { intrinsics::min_align_of_val(val) } +} + +/// Returns `true` if dropping values of type `T` matters. +/// +/// This is purely an optimization hint, and may be implemented conservatively: +/// it may return `true` for types that don't actually need to be dropped. +/// As such always returning `true` would be a valid implementation of +/// this function. However if this function actually returns `false`, then you +/// can be certain dropping `T` has no side effect. +/// +/// Low level implementations of things like collections, which need to manually +/// drop their data, should use this function to avoid unnecessarily +/// trying to drop all their contents when they are destroyed. This might not +/// make a difference in release builds (where a loop that has no side-effects +/// is easily detected and eliminated), but is often a big win for debug builds. +/// +/// Note that `ptr::drop_in_place` already performs this check, so if your workload +/// can be reduced to some small number of drop_in_place calls, using this is +/// unnecessary. In particular note that you can drop_in_place a slice, and that +/// will do a single needs_drop check for all the values. +/// +/// Types like Vec therefore just `drop_in_place(&mut self[..])` without using +/// needs_drop explicitly. Types like `HashMap`, on the other hand, have to drop +/// values one at a time and should use this API. +/// +/// +/// # Examples +/// +/// Here's an example of how a collection might make use of `needs_drop`: +/// +/// ``` +/// use std::{mem, ptr}; +/// +/// pub struct MyCollection { +/// # data: [T; 1], +/// /* ... */ +/// } +/// # impl MyCollection { +/// # fn iter_mut(&mut self) -> &mut [T] { &mut self.data } +/// # fn free_buffer(&mut self) {} +/// # } +/// +/// impl Drop for MyCollection { +/// fn drop(&mut self) { +/// unsafe { +/// // drop the data +/// if mem::needs_drop::() { +/// for x in self.iter_mut() { +/// ptr::drop_in_place(x); +/// } +/// } +/// self.free_buffer(); +/// } +/// } +/// } +/// ``` +#[inline] +#[stable(feature = "needs_drop", since = "1.21.0")] +pub const fn needs_drop() -> bool { + intrinsics::needs_drop::() +} + +/// Creates a value whose bytes are all zero. +/// +/// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed]. +/// It is useful for FFI sometimes, but should generally be avoided. +/// +/// There is no guarantee that an all-zero byte-pattern represents a valid value of +/// some type `T`. For example, the all-zero byte-pattern is not a valid value +/// for reference types (`&T` and `&mut T`). Using `zeroed` on such types +/// causes immediate [undefined behavior][ub] because [the Rust compiler assumes][inv] +/// that there always is a valid value in a variable it considers initialized. +/// +/// [zeroed]: union.MaybeUninit.html#method.zeroed +/// [ub]: ../../reference/behavior-considered-undefined.html +/// [inv]: union.MaybeUninit.html#initialization-invariant +/// +/// # Examples +/// +/// Correct usage of this function: initializing an integer with zero. +/// +/// ``` +/// use std::mem; +/// +/// let x: i32 = unsafe { mem::zeroed() }; +/// assert_eq!(0, x); +/// ``` +/// +/// *Incorrect* usage of this function: initializing a reference with zero. +/// +/// ```no_run +/// use std::mem; +/// +/// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior! +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn zeroed() -> T { + intrinsics::panic_if_uninhabited::(); + intrinsics::init() +} + +/// Bypasses Rust's normal memory-initialization checks by pretending to +/// produce a value of type `T`, while doing nothing at all. +/// +/// **This functon is deprecated.** Use [`MaybeUninit`] instead. +/// +/// The reason for deprecation is that the function basically cannot be used +/// correctly: [the Rust compiler assumes][inv] that values are properly initialized. +/// As a consequence, calling e.g. `mem::uninitialized::()` causes immediate +/// undefined behavior for returning a `bool` that is not definitely either `true` +/// or `false`. Worse, truly uninitialized memory like what gets returned here +/// is special in that the compiler knows that it does not have a fixed value. +/// This makes it undefined behavior to have uninitialized data in a variable even +/// if that variable has an integer type. +/// (Notice that the rules around uninitialized integers are not finalized yet, but +/// until they are, it is advisable to avoid them.) +/// +/// [`MaybeUninit`]: union.MaybeUninit.html +/// [inv]: union.MaybeUninit.html#initialization-invariant +#[inline] +#[rustc_deprecated(since = "1.38.0", reason = "use `mem::MaybeUninit` instead")] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn uninitialized() -> T { + intrinsics::panic_if_uninhabited::(); + intrinsics::uninit() +} + +/// Swaps the values at two mutable locations, without deinitializing either one. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// let mut x = 5; +/// let mut y = 42; +/// +/// mem::swap(&mut x, &mut y); +/// +/// assert_eq!(42, x); +/// assert_eq!(5, y); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn swap(x: &mut T, y: &mut T) { + unsafe { + ptr::swap_nonoverlapping_one(x, y); + } +} + +/// Replace `dest` with the default value of `T`, and return the previous `dest` value. +/// +/// # Examples +/// +/// A simple example: +/// +/// ``` +/// #![feature(mem_take)] +/// +/// use std::mem; +/// +/// let mut v: Vec = vec![1, 2]; +/// +/// let old_v = mem::take(&mut v); +/// assert_eq!(vec![1, 2], old_v); +/// assert!(v.is_empty()); +/// ``` +/// +/// `take` allows taking ownership of a struct field by replacing it with an "empty" value. +/// Without `take` you can run into issues like these: +/// +/// ```compile_fail,E0507 +/// struct Buffer { buf: Vec } +/// +/// impl Buffer { +/// fn get_and_reset(&mut self) -> Vec { +/// // error: cannot move out of dereference of `&mut`-pointer +/// let buf = self.buf; +/// self.buf = Vec::new(); +/// buf +/// } +/// } +/// ``` +/// +/// Note that `T` does not necessarily implement [`Clone`], so it can't even clone and reset +/// `self.buf`. But `take` can be used to disassociate the original value of `self.buf` from +/// `self`, allowing it to be returned: +/// +/// ``` +/// #![feature(mem_take)] +/// +/// use std::mem; +/// +/// # struct Buffer { buf: Vec } +/// impl Buffer { +/// fn get_and_reset(&mut self) -> Vec { +/// mem::take(&mut self.buf) +/// } +/// } +/// ``` +/// +/// [`Clone`]: ../../std/clone/trait.Clone.html +#[inline] +#[unstable(feature = "mem_take", issue = "61129")] +pub fn take(dest: &mut T) -> T { + replace(dest, T::default()) +} + +/// Moves `src` into the referenced `dest`, returning the previous `dest` value. +/// +/// Neither value is dropped. +/// +/// # Examples +/// +/// A simple example: +/// +/// ``` +/// use std::mem; +/// +/// let mut v: Vec = vec![1, 2]; +/// +/// let old_v = mem::replace(&mut v, vec![3, 4, 5]); +/// assert_eq!(vec![1, 2], old_v); +/// assert_eq!(vec![3, 4, 5], v); +/// ``` +/// +/// `replace` allows consumption of a struct field by replacing it with another value. +/// Without `replace` you can run into issues like these: +/// +/// ```compile_fail,E0507 +/// struct Buffer { buf: Vec } +/// +/// impl Buffer { +/// fn get_and_reset(&mut self) -> Vec { +/// // error: cannot move out of dereference of `&mut`-pointer +/// let buf = self.buf; +/// self.buf = Vec::new(); +/// buf +/// } +/// } +/// ``` +/// +/// 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 +/// `self`, allowing it to be returned: +/// +/// ``` +/// # #![allow(dead_code)] +/// use std::mem; +/// +/// # struct Buffer { buf: Vec } +/// impl Buffer { +/// fn get_and_reset(&mut self) -> Vec { +/// mem::replace(&mut self.buf, Vec::new()) +/// } +/// } +/// ``` +/// +/// [`Clone`]: ../../std/clone/trait.Clone.html +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn replace(dest: &mut T, mut src: T) -> T { + swap(dest, &mut src); + src +} + +/// Disposes of a value. +/// +/// This does call the argument's implementation of [`Drop`][drop]. +/// +/// This effectively does nothing for types which implement `Copy`, e.g. +/// integers. Such values are copied and _then_ moved into the function, so the +/// value persists after this function call. +/// +/// This function is not magic; it is literally defined as +/// +/// ``` +/// pub fn drop(_x: T) { } +/// ``` +/// +/// Because `_x` is moved into the function, it is automatically dropped before +/// the function returns. +/// +/// [drop]: ../ops/trait.Drop.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let v = vec![1, 2, 3]; +/// +/// drop(v); // explicitly drop the vector +/// ``` +/// +/// Since [`RefCell`] enforces the borrow rules at runtime, `drop` can +/// release a [`RefCell`] borrow: +/// +/// ``` +/// use std::cell::RefCell; +/// +/// let x = RefCell::new(1); +/// +/// let mut mutable_borrow = x.borrow_mut(); +/// *mutable_borrow = 1; +/// +/// drop(mutable_borrow); // relinquish the mutable borrow on this slot +/// +/// let borrow = x.borrow(); +/// println!("{}", *borrow); +/// ``` +/// +/// Integers and other types implementing [`Copy`] are unaffected by `drop`. +/// +/// ``` +/// #[derive(Copy, Clone)] +/// struct Foo(u8); +/// +/// let x = 1; +/// let y = Foo(2); +/// drop(x); // a copy of `x` is moved and dropped +/// drop(y); // a copy of `y` is moved and dropped +/// +/// println!("x: {}, y: {}", x, y.0); // still available +/// ``` +/// +/// [`RefCell`]: ../../std/cell/struct.RefCell.html +/// [`Copy`]: ../../std/marker/trait.Copy.html +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn drop(_x: T) { } + +/// Interprets `src` as having type `&U`, and then reads `src` without moving +/// the contained value. +/// +/// This function will unsafely assume the pointer `src` is valid for +/// [`size_of::`][size_of] bytes by transmuting `&T` to `&U` and then reading +/// the `&U`. It will also unsafely create a copy of the contained value instead of +/// moving out of `src`. +/// +/// It is not a compile-time error if `T` and `U` have different sizes, but it +/// is highly encouraged to only invoke this function where `T` and `U` have the +/// same size. This function triggers [undefined behavior][ub] if `U` is larger than +/// `T`. +/// +/// [ub]: ../../reference/behavior-considered-undefined.html +/// [size_of]: fn.size_of.html +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// #[repr(packed)] +/// struct Foo { +/// bar: u8, +/// } +/// +/// let foo_slice = [10u8]; +/// +/// unsafe { +/// // Copy the data from 'foo_slice' and treat it as a 'Foo' +/// let mut foo_struct: Foo = mem::transmute_copy(&foo_slice); +/// assert_eq!(foo_struct.bar, 10); +/// +/// // Modify the copied data +/// foo_struct.bar = 20; +/// assert_eq!(foo_struct.bar, 20); +/// } +/// +/// // The contents of 'foo_slice' should not have changed +/// assert_eq!(foo_slice, [10]); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn transmute_copy(src: &T) -> U { + ptr::read_unaligned(src as *const T as *const U) +} + +/// Opaque type representing the discriminant of an enum. +/// +/// See the [`discriminant`] function in this module for more information. +/// +/// [`discriminant`]: fn.discriminant.html +#[stable(feature = "discriminant_value", since = "1.21.0")] +pub struct Discriminant(u64, PhantomData T>); + +// N.B. These trait implementations cannot be derived because we don't want any bounds on T. + +#[stable(feature = "discriminant_value", since = "1.21.0")] +impl Copy for Discriminant {} + +#[stable(feature = "discriminant_value", since = "1.21.0")] +impl clone::Clone for Discriminant { + fn clone(&self) -> Self { + *self + } +} + +#[stable(feature = "discriminant_value", since = "1.21.0")] +impl cmp::PartialEq for Discriminant { + fn eq(&self, rhs: &Self) -> bool { + self.0 == rhs.0 + } +} + +#[stable(feature = "discriminant_value", since = "1.21.0")] +impl cmp::Eq for Discriminant {} + +#[stable(feature = "discriminant_value", since = "1.21.0")] +impl hash::Hash for Discriminant { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + +#[stable(feature = "discriminant_value", since = "1.21.0")] +impl fmt::Debug for Discriminant { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Discriminant") + .field(&self.0) + .finish() + } +} + +/// Returns a value uniquely identifying the enum variant in `v`. +/// +/// If `T` is not an enum, calling this function will not result in undefined behavior, but the +/// return value is unspecified. +/// +/// # Stability +/// +/// The discriminant of an enum variant may change if the enum definition changes. A discriminant +/// of some variant will not change between compilations with the same compiler. +/// +/// # Examples +/// +/// This can be used to compare enums that carry data, while disregarding +/// the actual data: +/// +/// ``` +/// use std::mem; +/// +/// enum Foo { A(&'static str), B(i32), C(i32) } +/// +/// assert!(mem::discriminant(&Foo::A("bar")) == mem::discriminant(&Foo::A("baz"))); +/// assert!(mem::discriminant(&Foo::B(1)) == mem::discriminant(&Foo::B(2))); +/// assert!(mem::discriminant(&Foo::B(3)) != mem::discriminant(&Foo::C(3))); +/// ``` +#[stable(feature = "discriminant_value", since = "1.21.0")] +pub fn discriminant(v: &T) -> Discriminant { + unsafe { + Discriminant(intrinsics::discriminant_value(v), PhantomData) + } +} diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index c3a42a0fc0494..342ac69748d92 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -17,8 +17,8 @@ issue = "0")] #![macro_use] -use mem; -use intrinsics; +use crate::mem; +use crate::intrinsics; /// Arithmetic operations required by bignums. pub trait FullOps: Sized { @@ -128,7 +128,7 @@ macro_rules! define_bignum { /// Makes a bignum from `u64` value. pub fn from_u64(mut v: u64) -> $name { - use mem; + use crate::mem; let mut base = [0; $n]; let mut sz = 0; @@ -150,7 +150,7 @@ macro_rules! define_bignum { /// Returns the `i`-th bit where bit 0 is the least significant one. /// In other words, the bit with weight `2^i`. pub fn get_bit(&self, i: usize) -> u8 { - use mem; + use crate::mem; let digitbits = mem::size_of::<$ty>() * 8; let d = i / digitbits; @@ -166,7 +166,7 @@ macro_rules! define_bignum { /// Returns the number of bits necessary to represent this value. Note that zero /// is considered to need 0 bits. pub fn bit_length(&self) -> usize { - use mem; + use crate::mem; // Skip over the most significant digits which are zero. let digits = self.digits(); @@ -190,8 +190,8 @@ macro_rules! define_bignum { /// Adds `other` to itself and returns its own mutable reference. pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name { - use cmp; - use num::bignum::FullOps; + use crate::cmp; + use crate::num::bignum::FullOps; let mut sz = cmp::max(self.size, other.size); let mut carry = false; @@ -209,7 +209,7 @@ macro_rules! define_bignum { } pub fn add_small(&mut self, other: $ty) -> &mut $name { - use num::bignum::FullOps; + use crate::num::bignum::FullOps; let (mut carry, v) = self.base[0].full_add(other, false); self.base[0] = v; @@ -228,8 +228,8 @@ macro_rules! define_bignum { /// Subtracts `other` from itself and returns its own mutable reference. pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name { - use cmp; - use num::bignum::FullOps; + use crate::cmp; + use crate::num::bignum::FullOps; let sz = cmp::max(self.size, other.size); let mut noborrow = true; @@ -246,7 +246,7 @@ macro_rules! define_bignum { /// Multiplies itself by a digit-sized `other` and returns its own /// mutable reference. pub fn mul_small(&mut self, other: $ty) -> &mut $name { - use num::bignum::FullOps; + use crate::num::bignum::FullOps; let mut sz = self.size; let mut carry = 0; @@ -265,7 +265,7 @@ macro_rules! define_bignum { /// Multiplies itself by `2^bits` and returns its own mutable reference. pub fn mul_pow2(&mut self, bits: usize) -> &mut $name { - use mem; + use crate::mem; let digitbits = mem::size_of::<$ty>() * 8; let digits = bits / digitbits; @@ -306,8 +306,8 @@ macro_rules! define_bignum { /// Multiplies itself by `5^e` and returns its own mutable reference. pub fn mul_pow5(&mut self, mut e: usize) -> &mut $name { - use mem; - use num::bignum::SMALL_POW5; + use crate::mem; + use crate::num::bignum::SMALL_POW5; // There are exactly n trailing zeros on 2^n, and the only relevant digit sizes // are consecutive powers of two, so this is well suited index for the table. @@ -338,7 +338,7 @@ macro_rules! define_bignum { pub fn mul_digits<'a>(&'a mut self, other: &[$ty]) -> &'a mut $name { // the internal routine. works best when aa.len() <= bb.len(). fn mul_inner(ret: &mut [$ty; $n], aa: &[$ty], bb: &[$ty]) -> usize { - use num::bignum::FullOps; + use crate::num::bignum::FullOps; let mut retsz = 0; for (i, &a) in aa.iter().enumerate() { @@ -375,7 +375,7 @@ macro_rules! define_bignum { /// Divides itself by a digit-sized `other` and returns its own /// mutable reference *and* the remainder. pub fn div_rem_small(&mut self, other: $ty) -> (&mut $name, $ty) { - use num::bignum::FullOps; + use crate::num::bignum::FullOps; assert!(other > 0); @@ -392,7 +392,7 @@ macro_rules! define_bignum { /// Divide self by another bignum, overwriting `q` with the quotient and `r` with the /// remainder. pub fn div_rem(&self, d: &$name, q: &mut $name, r: &mut $name) { - use mem; + use crate::mem; // Stupid slow base-2 long division taken from // https://en.wikipedia.org/wiki/Division_algorithm @@ -429,22 +429,22 @@ macro_rules! define_bignum { } } - impl ::cmp::PartialEq for $name { + impl crate::cmp::PartialEq for $name { fn eq(&self, other: &$name) -> bool { self.base[..] == other.base[..] } } - impl ::cmp::Eq for $name { + impl crate::cmp::Eq for $name { } - impl ::cmp::PartialOrd for $name { - fn partial_cmp(&self, other: &$name) -> ::option::Option<::cmp::Ordering> { - ::option::Option::Some(self.cmp(other)) + impl crate::cmp::PartialOrd for $name { + fn partial_cmp(&self, other: &$name) -> crate::option::Option { + crate::option::Option::Some(self.cmp(other)) } } - impl ::cmp::Ord for $name { - fn cmp(&self, other: &$name) -> ::cmp::Ordering { - use cmp::max; + impl crate::cmp::Ord for $name { + fn cmp(&self, other: &$name) -> crate::cmp::Ordering { + use crate::cmp::max; let sz = max(self.size, other.size); let lhs = self.base[..sz].iter().cloned().rev(); let rhs = other.base[..sz].iter().cloned().rev(); @@ -452,15 +452,15 @@ macro_rules! define_bignum { } } - impl ::clone::Clone for $name { + impl crate::clone::Clone for $name { fn clone(&self) -> $name { $name { size: self.size, base: self.base } } } - impl ::fmt::Debug for $name { - fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { - use mem; + impl crate::fmt::Debug for $name { + fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { + use crate::mem; let sz = if self.size < 1 {1} else {self.size}; let digitlen = mem::size_of::<$ty>() * 2; @@ -469,7 +469,7 @@ macro_rules! define_bignum { for &v in self.base[..sz-1].iter().rev() { write!(f, "_{:01$x}", v, digitlen)?; } - ::result::Result::Ok(()) + crate::result::Result::Ok(()) } } ) diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs index 3b57bb7544b35..fa3c8075378ca 100644 --- a/src/libcore/num/dec2flt/algorithm.rs +++ b/src/libcore/num/dec2flt/algorithm.rs @@ -1,11 +1,11 @@ //! The various algorithms from the paper. -use cmp::min; -use cmp::Ordering::{Less, Equal, Greater}; -use num::diy_float::Fp; -use num::dec2flt::table; -use num::dec2flt::rawfp::{self, Unpacked, RawFloat, fp_to_float, next_float, prev_float}; -use num::dec2flt::num::{self, Big}; +use crate::cmp::min; +use crate::cmp::Ordering::{Less, Equal, Greater}; +use crate::num::diy_float::Fp; +use crate::num::dec2flt::table; +use crate::num::dec2flt::rawfp::{self, Unpacked, RawFloat, fp_to_float, next_float, prev_float}; +use crate::num::dec2flt::num::{self, Big}; /// Number of significand bits in Fp const P: u32 = 64; @@ -35,7 +35,7 @@ mod fpu_precision { // computations are performed in the desired precision. #[cfg(all(target_arch="x86", not(target_feature="sse2")))] mod fpu_precision { - use mem::size_of; + use crate::mem::size_of; /// A structure used to preserve the original value of the FPU control word, so that it can be /// restored when the structure is dropped. @@ -326,7 +326,7 @@ pub fn algorithm_m(f: &Big, e: i16) -> T { round_by_remainder(v, rem, q, z) } -/// Skip over most Algorithm M iterations by checking the bit length. +/// Skips over most Algorithm M iterations by checking the bit length. fn quick_start(u: &mut Big, v: &mut Big, k: &mut i16) { // The bit length is an estimate of the base two logarithm, and log(u / v) = log(u) - log(v). // The estimate is off by at most 1, but always an under-estimate, so the error on log(u) diff --git a/src/libcore/num/dec2flt/mod.rs b/src/libcore/num/dec2flt/mod.rs index 47ea5aa5ff000..4536bbc94ad80 100644 --- a/src/libcore/num/dec2flt/mod.rs +++ b/src/libcore/num/dec2flt/mod.rs @@ -82,8 +82,8 @@ reason = "internal routines only exposed for testing", issue = "0")] -use fmt; -use str::FromStr; +use crate::fmt; +use crate::str::FromStr; use self::parse::{parse_decimal, Decimal, Sign, ParseResult}; use self::num::digits_to_big; @@ -196,7 +196,7 @@ impl ParseFloatError { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for ParseFloatError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.__description().fmt(f) } } @@ -244,7 +244,7 @@ fn dec2flt(s: &str) -> Result { /// The main workhorse for the decimal-to-float conversion: Orchestrate all the preprocessing /// and figure out which algorithm should do the actual conversion. -fn convert(mut decimal: Decimal) -> Result { +fn convert(mut decimal: Decimal<'_>) -> Result { simplify(&mut decimal); if let Some(x) = trivial_cases(&decimal) { return Ok(x); @@ -281,7 +281,7 @@ fn convert(mut decimal: Decimal) -> Result { /// Strip zeros where possible, even when this requires changing the exponent #[inline(always)] -fn simplify(decimal: &mut Decimal) { +fn simplify(decimal: &mut Decimal<'_>) { let is_zero = &|&&d: &&u8| -> bool { d == b'0' }; // Trimming these zeros does not change anything but may enable the fast path (< 15 digits). let leading_zeros = decimal.integral.iter().take_while(is_zero).count(); @@ -304,9 +304,9 @@ fn simplify(decimal: &mut Decimal) { } } -/// Quick and dirty upper bound on the size (log10) of the largest value that Algorithm R and -/// Algorithm M will compute while working on the given decimal. -fn bound_intermediate_digits(decimal: &Decimal, e: i64) -> u64 { +/// Returns a quick-an-dirty upper bound on the size (log10) of the largest value that Algorithm R +/// and Algorithm M will compute while working on the given decimal. +fn bound_intermediate_digits(decimal: &Decimal<'_>, e: i64) -> u64 { // We don't need to worry too much about overflow here thanks to trivial_cases() and the // parser, which filter out the most extreme inputs for us. let f_len: u64 = decimal.integral.len() as u64 + decimal.fractional.len() as u64; @@ -324,8 +324,8 @@ fn bound_intermediate_digits(decimal: &Decimal, e: i64) -> u64 { } } -/// Detect obvious overflows and underflows without even looking at the decimal digits. -fn trivial_cases(decimal: &Decimal) -> Option { +/// Detects obvious overflows and underflows without even looking at the decimal digits. +fn trivial_cases(decimal: &Decimal<'_>) -> Option { // There were zeros but they were stripped by simplify() if decimal.integral.is_empty() && decimal.fractional.is_empty() { return Some(T::ZERO); diff --git a/src/libcore/num/dec2flt/num.rs b/src/libcore/num/dec2flt/num.rs index 126713185711b..4d50516ce546b 100644 --- a/src/libcore/num/dec2flt/num.rs +++ b/src/libcore/num/dec2flt/num.rs @@ -2,9 +2,9 @@ // FIXME This module's name is a bit unfortunate, since other modules also import `core::num`. -use cmp::Ordering::{self, Less, Equal, Greater}; +use crate::cmp::Ordering::{self, Less, Equal, Greater}; -pub use num::bignum::Big32x40 as Big; +pub use crate::num::bignum::Big32x40 as Big; /// Test whether truncating all bits less significant than `ones_place` introduces /// a relative error less, equal, or greater than 0.5 ULP. diff --git a/src/libcore/num/dec2flt/parse.rs b/src/libcore/num/dec2flt/parse.rs index 933f8c1d3f781..cf3664a874886 100644 --- a/src/libcore/num/dec2flt/parse.rs +++ b/src/libcore/num/dec2flt/parse.rs @@ -44,7 +44,7 @@ pub enum ParseResult<'a> { /// Checks if the input string is a valid floating point number and if so, locate the integral /// part, the fractional part, and the exponent in it. Does not handle signs. -pub fn parse_decimal(s: &str) -> ParseResult { +pub fn parse_decimal(s: &str) -> ParseResult<'_> { if s.is_empty() { return Invalid; } @@ -78,7 +78,7 @@ pub fn parse_decimal(s: &str) -> ParseResult { } } -/// Carve off decimal digits up to the first non-digit character. +/// Carves off decimal digits up to the first non-digit character. fn eat_digits(s: &[u8]) -> (&[u8], &[u8]) { let mut i = 0; while i < s.len() && b'0' <= s[i] && s[i] <= b'9' { diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index b65f539b29c97..fdbdaa238e0f2 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -17,15 +17,15 @@ //! Many functions in this module only handle normal numbers. The dec2flt routines conservatively //! take the universally-correct slow path (Algorithm M) for very small and very large numbers. //! That algorithm needs only next_float() which does handle subnormals and zeros. -use cmp::Ordering::{Less, Equal, Greater}; -use convert::{TryFrom, TryInto}; -use ops::{Add, Mul, Div, Neg}; -use fmt::{Debug, LowerExp}; -use num::diy_float::Fp; -use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan}; -use num::FpCategory; -use num::dec2flt::num::{self, Big}; -use num::dec2flt::table; +use crate::cmp::Ordering::{Less, Equal, Greater}; +use crate::convert::{TryFrom, TryInto}; +use crate::ops::{Add, Mul, Div, Neg}; +use crate::fmt::{Debug, LowerExp}; +use crate::num::diy_float::Fp; +use crate::num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan}; +use crate::num::FpCategory; +use crate::num::dec2flt::num::{self, Big}; +use crate::num::dec2flt::table; #[derive(Copy, Clone, Debug)] pub struct Unpacked { diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index dc0580764acb7..0bcd371b528e4 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -7,8 +7,11 @@ #![stable(feature = "rust1", since = "1.0.0")] -use mem; -use num::FpCategory; +#[cfg(not(test))] +use crate::intrinsics; + +use crate::mem; +use crate::num::FpCategory; /// The radix or base of the internal representation of `f32`. #[stable(feature = "rust1", since = "1.0.0")] @@ -372,15 +375,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn max(self, other: f32) -> f32 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if self.is_nan() || self < other { other } else { self }) * 1.0 + intrinsics::maxnumf32(self, other) } /// Returns the minimum of the two numbers. @@ -396,15 +391,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn min(self, other: f32) -> f32 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if other.is_nan() || self < other { self } else { other }) * 1.0 + intrinsics::minnumf32(self, other) } /// Raw transmutation to `u32`. diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index c3677f8c8faea..4d4a2c9c5a97c 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -7,8 +7,11 @@ #![stable(feature = "rust1", since = "1.0.0")] -use mem; -use num::FpCategory; +#[cfg(not(test))] +use crate::intrinsics; + +use crate::mem; +use crate::num::FpCategory; /// The radix or base of the internal representation of `f64`. #[stable(feature = "rust1", since = "1.0.0")] @@ -385,15 +388,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn max(self, other: f64) -> f64 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if self.is_nan() || self < other { other } else { self }) * 1.0 + intrinsics::maxnumf64(self, other) } /// Returns the minimum of the two numbers. @@ -409,15 +404,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn min(self, other: f64) -> f64 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if other.is_nan() || self < other { self } else { other }) * 1.0 + intrinsics::minnumf64(self, other) } /// Raw transmutation to `u64`. diff --git a/src/libcore/num/flt2dec/decoder.rs b/src/libcore/num/flt2dec/decoder.rs index a3bf783976bbd..ee0f18ba295e9 100644 --- a/src/libcore/num/flt2dec/decoder.rs +++ b/src/libcore/num/flt2dec/decoder.rs @@ -1,8 +1,8 @@ //! Decodes a floating-point value into individual parts and error ranges. -use {f32, f64}; -use num::FpCategory; -use num::dec2flt::rawfp::RawFloat; +use crate::{f32, f64}; +use crate::num::FpCategory; +use crate::num::dec2flt::rawfp::RawFloat; /// Decoded unsigned finite value, such that: /// @@ -10,7 +10,7 @@ use num::dec2flt::rawfp::RawFloat; /// /// - Any number from `(mant - minus) * 2^exp` to `(mant + plus) * 2^exp` will /// round to the original value. The range is inclusive only when -/// `inclusive` is true. +/// `inclusive` is `true`. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Decoded { /// The scaled mantissa. @@ -86,4 +86,3 @@ pub fn decode(v: T) -> (/*negative?*/ bool, FullDecoded) { }; (sign < 0, decoded) } - diff --git a/src/libcore/num/flt2dec/mod.rs b/src/libcore/num/flt2dec/mod.rs index f9b46a12f7fef..6d42a77744966 100644 --- a/src/libcore/num/flt2dec/mod.rs +++ b/src/libcore/num/flt2dec/mod.rs @@ -120,7 +120,7 @@ functions. reason = "internal routines only exposed for testing", issue = "0")] -use i16; +use crate::i16; pub use self::decoder::{decode, DecodableFloat, FullDecoded, Decoded}; pub mod estimator; @@ -239,10 +239,8 @@ impl<'a> Formatted<'a> { let mut written = self.sign.len(); for part in self.parts { - match part.write(&mut out[written..]) { - Some(len) => { written += len; } - None => { return None; } - } + let len = part.write(&mut out[written..])?; + written += len; } Some(written) } @@ -315,15 +313,15 @@ fn digits_to_dec_str<'a>(buf: &'a [u8], exp: i16, frac_digits: usize, } } -/// Formats given decimal digits `0.<...buf...> * 10^exp` into the exponential form -/// with at least given number of significant digits. When `upper` is true, +/// Formats the given decimal digits `0.<...buf...> * 10^exp` into the exponential +/// form with at least the given number of significant digits. When `upper` is `true`, /// the exponent will be prefixed by `E`; otherwise that's `e`. The result is /// stored to the supplied parts array and a slice of written parts is returned. /// /// `min_digits` can be less than the number of actual significant digits in `buf`; /// it will be ignored and full digits will be printed. It is only used to print -/// additional zeroes after rendered digits. Thus `min_digits` of 0 means that -/// it will only print given digits and nothing else. +/// additional zeroes after rendered digits. Thus, `min_digits == 0` means that +/// it will only print the given digits and nothing else. fn digits_to_exp_str<'a>(buf: &'a [u8], exp: i16, min_ndigits: usize, upper: bool, parts: &'a mut [Part<'a>]) -> &'a [Part<'a>] { assert!(!buf.is_empty()); @@ -384,7 +382,7 @@ fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static } } -/// Formats given floating point number into the decimal form with at least +/// Formats the given floating point number into the decimal form with at least /// given number of fractional digits. The result is stored to the supplied parts /// array while utilizing given byte buffer as a scratch. `upper` is currently /// unused but left for the future decision to change the case of non-finite values, @@ -438,7 +436,7 @@ pub fn to_shortest_str<'a, T, F>(mut format_shortest: F, v: T, } } -/// Formats given floating point number into the decimal form or +/// Formats the given floating point number into the decimal form or /// the exponential form, depending on the resulting exponent. The result is /// stored to the supplied parts array while utilizing given byte buffer /// as a scratch. `upper` is used to determine the case of non-finite values @@ -497,7 +495,7 @@ pub fn to_shortest_exp_str<'a, T, F>(mut format_shortest: F, v: T, } } -/// Returns rather crude approximation (upper bound) for the maximum buffer size +/// Returns a rather crude approximation (upper bound) for the maximum buffer size /// calculated from the given decoded exponent. /// /// The exact limit is: diff --git a/src/libcore/num/flt2dec/strategy/dragon.rs b/src/libcore/num/flt2dec/strategy/dragon.rs index 582fe22f85406..35fb4b927589f 100644 --- a/src/libcore/num/flt2dec/strategy/dragon.rs +++ b/src/libcore/num/flt2dec/strategy/dragon.rs @@ -4,12 +4,12 @@ //! [^1]: Burger, R. G. and Dybvig, R. K. 1996. Printing floating-point numbers //! quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116. -use cmp::Ordering; +use crate::cmp::Ordering; -use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; -use num::flt2dec::estimator::estimate_scaling_factor; -use num::bignum::Digit32 as Digit; -use num::bignum::Big32x40 as Big; +use crate::num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; +use crate::num::flt2dec::estimator::estimate_scaling_factor; +use crate::num::bignum::Digit32 as Digit; +use crate::num::bignum::Big32x40 as Big; static POW10: [Digit; 10] = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000]; diff --git a/src/libcore/num/flt2dec/strategy/grisu.rs b/src/libcore/num/flt2dec/strategy/grisu.rs index aa21fcffa5c61..61b50ec8ca566 100644 --- a/src/libcore/num/flt2dec/strategy/grisu.rs +++ b/src/libcore/num/flt2dec/strategy/grisu.rs @@ -5,8 +5,8 @@ //! [^1]: Florian Loitsch. 2010. Printing floating-point numbers quickly and //! accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243. -use num::diy_float::Fp; -use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; +use crate::num::diy_float::Fp; +use crate::num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; // see the comments in `format_shortest_opt` for the rationale. @@ -418,7 +418,7 @@ pub fn format_shortest_opt(d: &Decoded, /// /// This should be used for most cases. pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp*/ i16) { - use num::flt2dec::strategy::dragon::format_shortest as fallback; + use crate::num::flt2dec::strategy::dragon::format_shortest as fallback; match format_shortest_opt(d, buf) { Some(ret) => ret, None => fallback(d, buf), @@ -675,7 +675,7 @@ pub fn format_exact_opt(d: &Decoded, buf: &mut [u8], limit: i16) /// /// This should be used for most cases. pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usize, /*exp*/ i16) { - use num::flt2dec::strategy::dragon::format_exact as fallback; + use crate::num::flt2dec::strategy::dragon::format_exact as fallback; match format_exact_opt(d, buf, limit) { Some(ret) => ret, None => fallback(d, buf, limit), diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 6708a195f88c5..d70f55670116c 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1,13 +1,15 @@ +// ignore-tidy-filelength + //! Numeric traits and functions for the built-in numeric types. #![stable(feature = "rust1", since = "1.0.0")] -use convert::{TryFrom, Infallible}; -use fmt; -use intrinsics; -use mem; -use ops; -use str::FromStr; +use crate::convert::{TryFrom, Infallible}; +use crate::fmt; +use crate::intrinsics; +use crate::mem; +use crate::ops; +use crate::str::FromStr; macro_rules! impl_nonzero_fmt { ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { @@ -15,7 +17,7 @@ macro_rules! impl_nonzero_fmt { #[$stability] impl fmt::$Trait for $Ty { #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.get().fmt(f) } } @@ -48,6 +50,7 @@ assert_eq!(size_of::>(), size_of::<", s #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] + #[cfg_attr(not(bootstrap), rustc_nonnull_optimization_guaranteed)] pub struct $Ty($Int); } @@ -112,6 +115,24 @@ nonzero_integers! { #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); } +macro_rules! from_str_radix_nzint_impl { + ($($t:ty)*) => {$( + #[stable(feature = "nonzero_parse", since = "1.35.0")] + impl FromStr for $t { + type Err = ParseIntError; + fn from_str(src: &str) -> Result { + Self::new(from_str_radix(src, 10)?) + .ok_or(ParseIntError { + kind: IntErrorKind::Zero + }) + } + } + )*} +} + +from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize + NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize } + /// Provides intentionally-wrapped arithmetic on `T`. /// /// Operations like `+` on `u32` values is intended to never overflow, @@ -146,42 +167,42 @@ pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } #[stable(feature = "wrapping_display", since = "1.10.0")] impl fmt::Display for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } #[stable(feature = "wrapping_fmt", since = "1.11.0")] impl fmt::Binary for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } #[stable(feature = "wrapping_fmt", since = "1.11.0")] impl fmt::Octal for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } #[stable(feature = "wrapping_fmt", since = "1.11.0")] impl fmt::LowerHex for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } #[stable(feature = "wrapping_fmt", since = "1.11.0")] impl fmt::UpperHex for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } @@ -194,11 +215,31 @@ pub mod diy_float; mod wrapping; +macro_rules! usize_isize_to_xe_bytes_doc { + () => {" + +**Note**: This function returns an array of length 2, 4 or 8 bytes +depending on the target pointer size. + +"} +} + + +macro_rules! usize_isize_from_xe_bytes_doc { + () => {" + +**Note**: This function takes an array of length 2, 4 or 8 bytes +depending on the target pointer size. + +"} +} + // `Int` + `SignedInt` implemented for signed integers macro_rules! int_impl { ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr, $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, - $reversed:expr, $le_bytes:expr, $be_bytes:expr) => { + $reversed:expr, $le_bytes:expr, $be_bytes:expr, + $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { doc_comment! { concat!("Returns the smallest value that can be represented by this integer type. @@ -359,6 +400,8 @@ let m = ", $rot_result, "; assert_eq!(n.rotate_left(", $rot, "), m); ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn rotate_left(self, n: u32) -> Self { (self as $UnsignedT).rotate_left(n) as Self @@ -383,6 +426,8 @@ let m = ", $rot_op, "; assert_eq!(n.rotate_right(", $rot, "), m); ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn rotate_right(self, n: u32) -> Self { (self as $UnsignedT).rotate_right(n) as Self @@ -418,16 +463,14 @@ assert_eq!(m, ", $swapped, "); Basic usage: ``` -#![feature(reverse_bits)] - let n = ", $swap_op, stringify!($SelfT), "; let m = n.reverse_bits(); assert_eq!(m, ", $reversed, "); ```"), - #[unstable(feature = "reverse_bits", issue = "48763")] - #[rustc_const_unstable(feature = "const_int_conversion")] + #[stable(feature = "reverse_bits", since = "1.37.0")] #[inline] + #[must_use] pub const fn reverse_bits(self) -> Self { (self as $UnsignedT).reverse_bits() as Self } @@ -580,6 +623,8 @@ assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_add(self, rhs: Self) -> Option { let (a, b) = self.overflowing_add(rhs); @@ -602,6 +647,8 @@ assert_eq!((", stringify!($SelfT), "::min_value() + 2).checked_sub(3), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_sub(self, rhs: Self) -> Option { let (a, b) = self.overflowing_sub(rhs); @@ -624,6 +671,8 @@ assert_eq!(", stringify!($SelfT), "::max_value().checked_mul(2), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_mul(self, rhs: Self) -> Option { let (a, b) = self.overflowing_mul(rhs); @@ -647,6 +696,8 @@ assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_div(self, rhs: Self) -> Option { if rhs == 0 || (self == Self::min_value() && rhs == -1) { @@ -673,6 +724,8 @@ assert_eq!(", stringify!($SelfT), "::min_value().checked_div_euclid(-1), None); assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_div_euclid(self, rhs: Self) -> Option { if rhs == 0 || (self == Self::min_value() && rhs == -1) { @@ -700,6 +753,8 @@ assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_rem(self, rhs: Self) -> Option { if rhs == 0 || (self == Self::min_value() && rhs == -1) { @@ -727,6 +782,8 @@ assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_rem_euclid(self, rhs: Self) -> Option { if rhs == 0 || (self == Self::min_value() && rhs == -1) { @@ -773,6 +830,8 @@ assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_shl(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shl(rhs); @@ -794,6 +853,8 @@ assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_shr(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shr(rhs); @@ -842,6 +903,8 @@ $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_pow(self, mut exp: u32) -> Option { let mut base = self; @@ -880,89 +943,95 @@ assert_eq!(", stringify!($SelfT), "::max_value().saturating_add(100), ", stringi "::max_value());", $EndFeature, " ```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_saturating_int_methods")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] - #[cfg(stage0)] - pub fn saturating_add(self, rhs: Self) -> Self { - match self.checked_add(rhs) { - Some(x) => x, - None if rhs >= 0 => Self::max_value(), - None => Self::min_value(), - } + pub const fn saturating_add(self, rhs: Self) -> Self { + intrinsics::saturating_add(self, rhs) } - } + doc_comment! { - concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric -bounds instead of overflowing. + concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the +numeric bounds instead of overflowing. # Examples Basic usage: ``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); -assert_eq!(", stringify!($SelfT), "::max_value().saturating_add(100), ", stringify!($SelfT), -"::max_value());", +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); +assert_eq!(", stringify!($SelfT), "::min_value().saturating_sub(100), ", stringify!($SelfT), +"::min_value());", $EndFeature, " ```"), - #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_saturating_int_methods")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] - #[cfg(not(stage0))] - pub const fn saturating_add(self, rhs: Self) -> Self { - intrinsics::saturating_add(self, rhs) + pub const fn saturating_sub(self, rhs: Self) -> Self { + intrinsics::saturating_sub(self, rhs) } } doc_comment! { - concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the -numeric bounds instead of overflowing. + concat!("Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` +instead of overflowing. # Examples Basic usage: ``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); -assert_eq!(", stringify!($SelfT), "::min_value().saturating_sub(100), ", stringify!($SelfT), -"::min_value());", +", $Feature, "#![feature(saturating_neg)] +assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100); +assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100); +assert_eq!(", stringify!($SelfT), "::min_value().saturating_neg(), ", stringify!($SelfT), +"::max_value()); +assert_eq!(", stringify!($SelfT), "::max_value().saturating_neg(), ", stringify!($SelfT), +"::min_value() + 1);", $EndFeature, " ```"), - #[stable(feature = "rust1", since = "1.0.0")] + + #[unstable(feature = "saturating_neg", issue = "59983")] #[inline] - #[cfg(stage0)] - pub fn saturating_sub(self, rhs: Self) -> Self { - match self.checked_sub(rhs) { - Some(x) => x, - None if rhs >= 0 => Self::min_value(), - None => Self::max_value(), - } + pub fn saturating_neg(self) -> Self { + intrinsics::saturating_sub(0, self) } } doc_comment! { - concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the -numeric bounds instead of overflowing. + concat!("Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self == +MIN` instead of overflowing. # Examples Basic usage: ``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); -assert_eq!(", stringify!($SelfT), "::min_value().saturating_sub(100), ", stringify!($SelfT), -"::min_value());", +", $Feature, "#![feature(saturating_neg)] +assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100); +assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100); +assert_eq!(", stringify!($SelfT), "::min_value().saturating_abs(), ", stringify!($SelfT), +"::max_value()); +assert_eq!((", stringify!($SelfT), "::min_value() + 1).saturating_abs(), ", stringify!($SelfT), +"::max_value());", $EndFeature, " ```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_saturating_int_methods")] + + #[unstable(feature = "saturating_neg", issue = "59983")] #[inline] - #[cfg(not(stage0))] - pub const fn saturating_sub(self, rhs: Self) -> Self { - intrinsics::saturating_sub(self, rhs) + pub fn saturating_abs(self) -> Self { + if self.is_negative() { + self.saturating_neg() + } else { + self + } } } @@ -983,6 +1052,8 @@ assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($Self $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn saturating_mul(self, rhs: Self) -> Self { self.checked_mul(rhs).unwrap_or_else(|| { @@ -1012,6 +1083,8 @@ assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn saturating_pow(self, exp: u32) -> Self { match self.checked_pow(exp) { @@ -1037,6 +1110,8 @@ assert_eq!(", stringify!($SelfT), "::max_value().wrapping_add(2), ", stringify!( $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn wrapping_add(self, rhs: Self) -> Self { intrinsics::overflowing_add(self, rhs) @@ -1058,6 +1133,8 @@ stringify!($SelfT), "::max_value());", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn wrapping_sub(self, rhs: Self) -> Self { intrinsics::overflowing_sub(self, rhs) @@ -1078,6 +1155,8 @@ assert_eq!(11i8.wrapping_mul(12), -124);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn wrapping_mul(self, rhs: Self) -> Self { intrinsics::overflowing_mul(self, rhs) @@ -1106,6 +1185,8 @@ assert_eq!((-128i8).wrapping_div(-1), -128);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn wrapping_div(self, rhs: Self) -> Self { self.overflowing_div(rhs).0 @@ -1134,6 +1215,8 @@ assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); assert_eq!((-128i8).wrapping_div_euclid(-1), -128); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn wrapping_div_euclid(self, rhs: Self) -> Self { self.overflowing_div_euclid(rhs).0 @@ -1162,6 +1245,8 @@ assert_eq!((-128i8).wrapping_rem(-1), 0);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn wrapping_rem(self, rhs: Self) -> Self { self.overflowing_rem(rhs).0 @@ -1189,6 +1274,8 @@ assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); assert_eq!((-128i8).wrapping_rem_euclid(-1), 0); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn wrapping_rem_euclid(self, rhs: Self) -> Self { self.overflowing_rem_euclid(rhs).0 @@ -1239,6 +1326,8 @@ assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn wrapping_shl(self, rhs: u32) -> Self { unsafe { @@ -1266,6 +1355,8 @@ assert_eq!((-128i16).wrapping_shr(64), -128);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn wrapping_shr(self, rhs: u32) -> Self { unsafe { @@ -1320,6 +1411,8 @@ assert_eq!(3i8.wrapping_pow(6), -39);", $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn wrapping_pow(self, mut exp: u32) -> Self { let mut base = self; @@ -1362,6 +1455,8 @@ assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($Sel "::MIN, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); @@ -1387,6 +1482,8 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($Sel "::MAX, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); @@ -1410,6 +1507,8 @@ assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); @@ -1441,6 +1540,8 @@ $EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub fn overflowing_div(self, rhs: Self) -> (Self, bool) { if self == Self::min_value() && rhs == -1 { (self, true) @@ -1474,6 +1575,8 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringi ```"), #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { if self == Self::min_value() && rhs == -1 { (self, true) @@ -1506,6 +1609,8 @@ $EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) { if self == Self::min_value() && rhs == -1 { (0, true) @@ -1538,6 +1643,8 @@ assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true)); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { if self == Self::min_value() && rhs == -1 { @@ -1591,6 +1698,8 @@ assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) @@ -1614,6 +1723,8 @@ assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) @@ -1666,6 +1777,8 @@ assert_eq!(3i8.overflowing_pow(5), (-13, true));", $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { let mut base = self; @@ -1713,6 +1826,8 @@ assert_eq!(x.pow(5), 32);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] pub fn pow(self, mut exp: u32) -> Self { @@ -1768,6 +1883,8 @@ assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2 assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2 ```"), #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] pub fn div_euclid(self, rhs: Self) -> Self { @@ -1806,6 +1923,8 @@ assert_eq!(a.rem_euclid(-b), 3); assert_eq!((-a).rem_euclid(-b), 1); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] pub fn rem_euclid(self, rhs: Self) -> Self { @@ -1874,13 +1993,10 @@ assert_eq!((-10", stringify!($SelfT), ").signum(), -1);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_sign")] #[inline] - pub fn signum(self) -> Self { - match self { - n if n > 0 => 1, - 0 => 0, - _ => -1, - } + pub const fn signum(self) -> Self { + (self > 0) as Self - (self < 0) as Self } } @@ -1923,7 +2039,9 @@ $EndFeature, " doc_comment! { concat!("Return the memory representation of this integer as a byte array in big-endian (network) byte order. - +", +$to_xe_bytes_doc, +" # Examples ``` @@ -1941,7 +2059,9 @@ assert_eq!(bytes, ", $be_bytes, "); doc_comment! { concat!("Return the memory representation of this integer as a byte array in little-endian byte order. - +", +$to_xe_bytes_doc, +" # Examples ``` @@ -1964,7 +2084,9 @@ native byte order. As the target platform's native endianness is used, portable code should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead. - +", +$to_xe_bytes_doc, +" [`to_be_bytes`]: #method.to_be_bytes [`to_le_bytes`]: #method.to_le_bytes @@ -1989,7 +2111,9 @@ assert_eq!(bytes, if cfg!(target_endian = \"big\") { doc_comment! { concat!("Create an integer value from its representation as a byte array in big endian. - +", +$from_xe_bytes_doc, +" # Examples ``` @@ -2020,7 +2144,9 @@ doc_comment! { concat!(" Create an integer value from its representation as a byte array in little endian. - +", +$from_xe_bytes_doc, +" # Examples ``` @@ -2033,10 +2159,10 @@ When starting from a slice rather than an array, fallible conversion APIs can be ``` use std::convert::TryInto; -fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { +fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); *input = rest; - ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) + ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] @@ -2057,7 +2183,9 @@ appropriate instead. [`from_be_bytes`]: #method.from_be_bytes [`from_le_bytes`]: #method.from_le_bytes - +", +$from_xe_bytes_doc, +" # Examples ``` @@ -2074,10 +2202,10 @@ When starting from a slice rather than an array, fallible conversion APIs can be ``` use std::convert::TryInto; -fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { +fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); *input = rest; - ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) + ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] @@ -2093,20 +2221,20 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), #[lang = "i8"] impl i8 { int_impl! { i8, i8, u8, 8, -128, 127, "", "", 2, "-0x7e", "0xa", "0x12", "0x12", "0x48", - "[0x12]", "[0x12]" } + "[0x12]", "[0x12]", "", "" } } #[lang = "i16"] impl i16 { int_impl! { i16, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", - "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]" } + "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } } #[lang = "i32"] impl i32 { int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78]" } + "[0x12, 0x34, 0x56, 0x78]", "", "" } } #[lang = "i64"] @@ -2114,7 +2242,7 @@ impl i64 { int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]" } + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" } } #[lang = "i128"] @@ -2126,14 +2254,15 @@ impl i128 { "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \ 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \ - 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]" } + 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "" } } #[cfg(target_pointer_width = "16")] #[lang = "isize"] impl isize { int_impl! { isize, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", - "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]" } + "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } #[cfg(target_pointer_width = "32")] @@ -2141,7 +2270,8 @@ impl isize { impl isize { int_impl! { isize, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78]" } + "[0x12, 0x34, 0x56, 0x78]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } #[cfg(target_pointer_width = "64")] @@ -2150,14 +2280,16 @@ impl isize { int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]" } + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } // `Int` + `UnsignedInt` implemented for unsigned integers macro_rules! uint_impl { ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, - $reversed:expr, $le_bytes:expr, $be_bytes:expr) => { + $reversed:expr, $le_bytes:expr, $be_bytes:expr, + $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { doc_comment! { concat!("Returns the smallest value that can be represented by this integer type. @@ -2313,6 +2445,8 @@ let m = ", $rot_result, "; assert_eq!(n.rotate_left(", $rot, "), m); ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn rotate_left(self, n: u32) -> Self { intrinsics::rotate_left(self, n as $SelfT) @@ -2337,6 +2471,8 @@ let m = ", $rot_op, "; assert_eq!(n.rotate_right(", $rot, "), m); ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn rotate_right(self, n: u32) -> Self { intrinsics::rotate_right(self, n as $SelfT) @@ -2372,15 +2508,14 @@ assert_eq!(m, ", $swapped, "); Basic usage: ``` -#![feature(reverse_bits)] - let n = ", $swap_op, stringify!($SelfT), "; let m = n.reverse_bits(); assert_eq!(m, ", $reversed, "); ```"), - #[unstable(feature = "reverse_bits", issue = "48763")] + #[stable(feature = "reverse_bits", since = "1.37.0")] #[inline] + #[must_use] pub const fn reverse_bits(self) -> Self { intrinsics::bitreverse(self as $ActualT) as Self } @@ -2532,6 +2667,8 @@ Basic usage: assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_add(self, rhs: Self) -> Option { let (a, b) = self.overflowing_add(rhs); @@ -2552,6 +2689,8 @@ Basic usage: assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_sub(self, rhs: Self) -> Option { let (a, b) = self.overflowing_sub(rhs); @@ -2572,6 +2711,8 @@ Basic usage: assert_eq!(", stringify!($SelfT), "::max_value().checked_mul(2), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_mul(self, rhs: Self) -> Option { let (a, b) = self.overflowing_mul(rhs); @@ -2592,6 +2733,8 @@ Basic usage: assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_div(self, rhs: Self) -> Option { match rhs { @@ -2615,6 +2758,8 @@ assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64)); assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_div_euclid(self, rhs: Self) -> Option { if rhs == 0 { @@ -2639,6 +2784,8 @@ Basic usage: assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_rem(self, rhs: Self) -> Option { if rhs == 0 { @@ -2663,6 +2810,8 @@ assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_rem_euclid(self, rhs: Self) -> Option { if rhs == 0 { @@ -2708,6 +2857,8 @@ Basic usage: assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_shl(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shl(rhs); @@ -2728,6 +2879,8 @@ Basic usage: assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_shr(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shr(rhs); @@ -2748,6 +2901,8 @@ Basic usage: assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);", $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn checked_pow(self, mut exp: u32) -> Option { let mut base = self; @@ -2780,38 +2935,16 @@ the numeric bounds instead of overflowing. Basic usage: -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); -assert_eq!(200u8.saturating_add(127), 255);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - #[cfg(stage0)] - pub fn saturating_add(self, rhs: Self) -> Self { - match self.checked_add(rhs) { - Some(x) => x, - None => Self::max_value(), - } - } - } - - doc_comment! { - concat!("Saturating integer addition. Computes `self + rhs`, saturating at -the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - ``` ", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); assert_eq!(200u8.saturating_add(127), 255);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[rustc_const_unstable(feature = "const_saturating_int_methods")] #[inline] - #[cfg(not(stage0))] pub const fn saturating_add(self, rhs: Self) -> Self { intrinsics::saturating_add(self, rhs) } @@ -2830,32 +2963,10 @@ Basic usage: assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - #[cfg(stage0)] - pub fn saturating_sub(self, rhs: Self) -> Self { - match self.checked_sub(rhs) { - Some(x) => x, - None => Self::min_value(), - } - } - } - - doc_comment! { - concat!("Saturating integer subtraction. Computes `self - rhs`, saturating -at the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73); -assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[rustc_const_unstable(feature = "const_saturating_int_methods")] #[inline] - #[cfg(not(stage0))] pub const fn saturating_sub(self, rhs: Self) -> Self { intrinsics::saturating_sub(self, rhs) } @@ -2877,6 +2988,8 @@ assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($Se "::MAX);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn saturating_mul(self, rhs: Self) -> Self { self.checked_mul(rhs).unwrap_or(Self::max_value()) @@ -2899,6 +3012,8 @@ assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn saturating_pow(self, exp: u32) -> Self { match self.checked_pow(exp) { @@ -2922,6 +3037,8 @@ assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::ma $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn wrapping_add(self, rhs: Self) -> Self { intrinsics::overflowing_add(self, rhs) @@ -2942,6 +3059,8 @@ assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::ma $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn wrapping_sub(self, rhs: Self) -> Self { intrinsics::overflowing_sub(self, rhs) @@ -2963,6 +3082,8 @@ $EndFeature, " /// assert_eq!(25u8.wrapping_mul(12), 44); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn wrapping_mul(self, rhs: Self) -> Self { intrinsics::overflowing_mul(self, rhs) @@ -2983,6 +3104,8 @@ Basic usage: ", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn wrapping_div(self, rhs: Self) -> Self { self / rhs @@ -3008,6 +3131,8 @@ Basic usage: assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn wrapping_div_euclid(self, rhs: Self) -> Self { self / rhs @@ -3030,6 +3155,8 @@ Basic usage: ", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn wrapping_rem(self, rhs: Self) -> Self { self % rhs @@ -3056,6 +3183,8 @@ Basic usage: assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn wrapping_rem_euclid(self, rhs: Self) -> Self { self % rhs @@ -3110,6 +3239,8 @@ Basic usage: assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn wrapping_shl(self, rhs: u32) -> Self { unsafe { @@ -3139,6 +3270,8 @@ Basic usage: assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn wrapping_shr(self, rhs: u32) -> Self { unsafe { @@ -3160,6 +3293,8 @@ Basic usage: assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn wrapping_pow(self, mut exp: u32) -> Self { let mut base = self; @@ -3202,6 +3337,8 @@ assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); @@ -3228,6 +3365,8 @@ assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); @@ -3253,6 +3392,8 @@ $EndFeature, " /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true)); /// ``` #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); @@ -3280,6 +3421,8 @@ Basic usage ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub fn overflowing_div(self, rhs: Self) -> (Self, bool) { (self / rhs, false) } @@ -3310,6 +3453,8 @@ assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); ```"), #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { (self / rhs, false) } @@ -3336,6 +3481,8 @@ Basic usage ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) { (self % rhs, false) } @@ -3366,6 +3513,8 @@ assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); ```"), #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { (self % rhs, false) } @@ -3413,6 +3562,8 @@ Basic usage assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) @@ -3437,6 +3588,8 @@ Basic usage assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) @@ -3458,6 +3611,8 @@ Basic usage: assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { let mut base = self; @@ -3502,6 +3657,8 @@ Basic usage: ", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] pub fn pow(self, mut exp: u32) -> Self { @@ -3543,6 +3700,8 @@ Basic usage: assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type ```"), #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] pub fn div_euclid(self, rhs: Self) -> Self { @@ -3567,6 +3726,8 @@ Basic usage: assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type ```"), #[unstable(feature = "euclidean_division", issue = "49048")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] pub fn rem_euclid(self, rhs: Self) -> Self { @@ -3687,7 +3848,9 @@ $EndFeature, " doc_comment! { concat!("Return the memory representation of this integer as a byte array in big-endian (network) byte order. - +", +$to_xe_bytes_doc, +" # Examples ``` @@ -3705,7 +3868,9 @@ assert_eq!(bytes, ", $be_bytes, "); doc_comment! { concat!("Return the memory representation of this integer as a byte array in little-endian byte order. - +", +$to_xe_bytes_doc, +" # Examples ``` @@ -3728,7 +3893,9 @@ native byte order. As the target platform's native endianness is used, portable code should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead. - +", +$to_xe_bytes_doc, +" [`to_be_bytes`]: #method.to_be_bytes [`to_le_bytes`]: #method.to_le_bytes @@ -3753,7 +3920,9 @@ assert_eq!(bytes, if cfg!(target_endian = \"big\") { doc_comment! { concat!("Create an integer value from its representation as a byte array in big endian. - +", +$from_xe_bytes_doc, +" # Examples ``` @@ -3784,7 +3953,9 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), concat!(" Create an integer value from its representation as a byte array in little endian. - +", +$from_xe_bytes_doc, +" # Examples ``` @@ -3797,10 +3968,10 @@ When starting from a slice rather than an array, fallible conversion APIs can be ``` use std::convert::TryInto; -fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { +fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); *input = rest; - ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) + ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] @@ -3821,7 +3992,9 @@ appropriate instead. [`from_be_bytes`]: #method.from_be_bytes [`from_le_bytes`]: #method.from_le_bytes - +", +$from_xe_bytes_doc, +" # Examples ``` @@ -3838,10 +4011,10 @@ When starting from a slice rather than an array, fallible conversion APIs can be ``` use std::convert::TryInto; -fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { +fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); *input = rest; - ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) + ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] @@ -3857,7 +4030,7 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), #[lang = "u8"] impl u8 { uint_impl! { u8, u8, 8, 255, "", "", 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", - "[0x12]" } + "[0x12]", "", "" } /// Checks if the value is within the ASCII range. @@ -3896,7 +4069,8 @@ impl u8 { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_uppercase(&self) -> u8 { - ASCII_UPPERCASE_MAP[*self as usize] + // Unset the fith bit if this is a lowercase letter + *self & !((self.is_ascii_lowercase() as u8) << 5) } /// Makes a copy of the value in its ASCII lower case equivalent. @@ -3918,7 +4092,8 @@ impl u8 { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_lowercase(&self) -> u8 { - ASCII_LOWERCASE_MAP[*self as usize] + // Set the fith bit if this is an uppercase letter + *self | ((self.is_ascii_uppercase() as u8) << 5) } /// Checks that two values are an ASCII case-insensitive match. @@ -3991,8 +4166,8 @@ impl u8 { /// Checks if the value is an ASCII alphabetic character: /// - /// - U+0041 'A' ... U+005A 'Z', or - /// - U+0061 'a' ... U+007A 'z'. + /// - U+0041 'A' ..= U+005A 'Z', or + /// - U+0061 'a' ..= U+007A 'z'. /// /// # Examples /// @@ -4020,15 +4195,14 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_alphabetic(&self) -> bool { - if *self >= 0x80 { return false; } - match ASCII_CHARACTER_CLASS[*self as usize] { - L | Lx | U | Ux => true, + match *self { + b'A'..=b'Z' | b'a'..=b'z' => true, _ => false } } /// Checks if the value is an ASCII uppercase character: - /// U+0041 'A' ... U+005A 'Z'. + /// U+0041 'A' ..= U+005A 'Z'. /// /// # Examples /// @@ -4056,15 +4230,14 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_uppercase(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - U | Ux => true, + match *self { + b'A'..=b'Z' => true, _ => false } } /// Checks if the value is an ASCII lowercase character: - /// U+0061 'a' ... U+007A 'z'. + /// U+0061 'a' ..= U+007A 'z'. /// /// # Examples /// @@ -4092,18 +4265,17 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_lowercase(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - L | Lx => true, + match *self { + b'a'..=b'z' => true, _ => false } } /// Checks if the value is an ASCII alphanumeric character: /// - /// - U+0041 'A' ... U+005A 'Z', or - /// - U+0061 'a' ... U+007A 'z', or - /// - U+0030 '0' ... U+0039 '9'. + /// - U+0041 'A' ..= U+005A 'Z', or + /// - U+0061 'a' ..= U+007A 'z', or + /// - U+0030 '0' ..= U+0039 '9'. /// /// # Examples /// @@ -4131,15 +4303,14 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_alphanumeric(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - D | L | Lx | U | Ux => true, + match *self { + b'0'..=b'9' | b'A'..=b'Z' | b'a'..=b'z' => true, _ => false } } /// Checks if the value is an ASCII decimal digit: - /// U+0030 '0' ... U+0039 '9'. + /// U+0030 '0' ..= U+0039 '9'. /// /// # Examples /// @@ -4167,18 +4338,17 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_digit(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - D => true, + match *self { + b'0'..=b'9' => true, _ => false } } /// Checks if the value is an ASCII hexadecimal digit: /// - /// - U+0030 '0' ... U+0039 '9', or - /// - U+0041 'A' ... U+0046 'F', or - /// - U+0061 'a' ... U+0066 'f'. + /// - U+0030 '0' ..= U+0039 '9', or + /// - U+0041 'A' ..= U+0046 'F', or + /// - U+0061 'a' ..= U+0066 'f'. /// /// # Examples /// @@ -4206,19 +4376,18 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_hexdigit(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - D | Lx | Ux => true, + match *self { + b'0'..=b'9' | b'A'..=b'F' | b'a'..=b'f' => true, _ => false } } /// Checks if the value is an ASCII punctuation character: /// - /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or - /// - U+003A ... U+0040 `: ; < = > ? @`, or - /// - U+005B ... U+0060 ``[ \ ] ^ _ ` ``, or - /// - U+007B ... U+007E `{ | } ~` + /// - U+0021 ..= U+002F `! " # $ % & ' ( ) * + , - . /`, or + /// - U+003A ..= U+0040 `: ; < = > ? @`, or + /// - U+005B ..= U+0060 ``[ \ ] ^ _ ` ``, or + /// - U+007B ..= U+007E `{ | } ~` /// /// # Examples /// @@ -4246,15 +4415,14 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_punctuation(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - P => true, + match *self { + b'!'..=b'/' | b':'..=b'@' | b'['..=b'`' | b'{'..=b'~' => true, _ => false } } /// Checks if the value is an ASCII graphic character: - /// U+0021 '!' ... U+007E '~'. + /// U+0021 '!' ..= U+007E '~'. /// /// # Examples /// @@ -4282,9 +4450,8 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_graphic(&self) -> bool { - if *self >= 0x80 { return false; } - match ASCII_CHARACTER_CLASS[*self as usize] { - Ux | U | Lx | L | D | P => true, + match *self { + b'!'..=b'~' => true, _ => false } } @@ -4335,15 +4502,14 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_whitespace(&self) -> bool { - if *self >= 0x80 { return false; } - match ASCII_CHARACTER_CLASS[*self as usize] { - Cw | W => true, + match *self { + b'\t' | b'\n' | b'\x0C' | b'\r' | b' ' => true, _ => false } } /// Checks if the value is an ASCII control character: - /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE. + /// U+0000 NUL ..= U+001F UNIT SEPARATOR, or U+007F DELETE. /// Note that most ASCII whitespace characters are control /// characters, but SPACE is not. /// @@ -4373,9 +4539,8 @@ impl u8 { #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[inline] pub fn is_ascii_control(&self) -> bool { - if *self >= 0x80 { return false; } - match ASCII_CHARACTER_CLASS[*self as usize] { - C | Cw => true, + match *self { + b'\0'..=b'\x1F' | b'\x7F' => true, _ => false } } @@ -4384,13 +4549,13 @@ impl u8 { #[lang = "u16"] impl u16 { uint_impl! { u16, u16, 16, 65535, "", "", 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", - "[0x34, 0x12]", "[0x12, 0x34]" } + "[0x34, 0x12]", "[0x12, 0x34]", "", "" } } #[lang = "u32"] impl u32 { uint_impl! { u32, u32, 32, 4294967295, "", "", 8, "0x10000b3", "0xb301", "0x12345678", - "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]" } + "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } } #[lang = "u64"] @@ -4398,7 +4563,8 @@ impl u64 { uint_impl! { u64, u64, 64, 18446744073709551615, "", "", 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]" } + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", + "", ""} } #[lang = "u128"] @@ -4409,20 +4575,23 @@ impl u128 { "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \ 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \ - 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]" } + 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", + "", ""} } #[cfg(target_pointer_width = "16")] #[lang = "usize"] impl usize { - uint_impl! { usize, u16, 16, 65536, "", "", 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", - "[0x34, 0x12]", "[0x12, 0x34]" } + uint_impl! { usize, u16, 16, 65535, "", "", 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", + "[0x34, 0x12]", "[0x12, 0x34]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } #[cfg(target_pointer_width = "32")] #[lang = "usize"] impl usize { uint_impl! { usize, u32, 32, 4294967295, "", "", 8, "0x10000b3", "0xb301", "0x12345678", - "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]" } + "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } #[cfg(target_pointer_width = "64")] @@ -4431,7 +4600,8 @@ impl usize { uint_impl! { usize, u64, 64, 18446744073709551615, "", "", 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]" } + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } /// A classification of floating point numbers. @@ -4515,7 +4685,7 @@ impl TryFromIntError { #[stable(feature = "try_from", since = "1.34.0")] impl fmt::Display for TryFromIntError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { self.__description().fmt(fmt) } } @@ -4544,6 +4714,9 @@ macro_rules! try_from_unbounded { impl TryFrom<$source> for $target { type Error = TryFromIntError; + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. #[inline] fn try_from(value: $source) -> Result { Ok(value as $target) @@ -4559,6 +4732,9 @@ macro_rules! try_from_lower_bounded { impl TryFrom<$source> for $target { type Error = TryFromIntError; + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. #[inline] fn try_from(u: $source) -> Result<$target, TryFromIntError> { if u >= 0 { @@ -4578,6 +4754,9 @@ macro_rules! try_from_upper_bounded { impl TryFrom<$source> for $target { type Error = TryFromIntError; + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. #[inline] fn try_from(u: $source) -> Result<$target, TryFromIntError> { if u > (<$target>::max_value() as $source) { @@ -4597,6 +4776,9 @@ macro_rules! try_from_both_bounded { impl TryFrom<$source> for $target { type Error = TryFromIntError; + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. #[inline] fn try_from(u: $source) -> Result<$target, TryFromIntError> { let min = <$target>::min_value() as $source; @@ -4617,7 +4799,7 @@ macro_rules! rev { )*} } -/// intra-sign conversions +// intra-sign conversions try_from_upper_bounded!(u16, u8); try_from_upper_bounded!(u32, u16, u8); try_from_upper_bounded!(u64, u32, u16, u8); @@ -4653,7 +4835,7 @@ try_from_lower_bounded!(isize, usize); #[cfg(target_pointer_width = "16")] mod ptr_try_from_impls { use super::TryFromIntError; - use convert::TryFrom; + use crate::convert::TryFrom; try_from_upper_bounded!(usize, u8); try_from_unbounded!(usize, u16, u32, u64, u128); @@ -4676,7 +4858,7 @@ mod ptr_try_from_impls { #[cfg(target_pointer_width = "32")] mod ptr_try_from_impls { use super::TryFromIntError; - use convert::TryFrom; + use crate::convert::TryFrom; try_from_upper_bounded!(usize, u8, u16); try_from_unbounded!(usize, u32, u64, u128); @@ -4702,7 +4884,7 @@ mod ptr_try_from_impls { #[cfg(target_pointer_width = "64")] mod ptr_try_from_impls { use super::TryFromIntError; - use convert::TryFrom; + use crate::convert::TryFrom; try_from_upper_bounded!(usize, u8, u16, u32); try_from_unbounded!(usize, u64, u128); @@ -4866,6 +5048,11 @@ pub enum IntErrorKind { Overflow, /// Integer is too small to store in target integer type. Underflow, + /// Value was Zero + /// + /// This variant will be emitted when the parsing string has a value of zero, which + /// would be illegal for non-zero types. + Zero, } impl ParseIntError { @@ -4888,19 +5075,20 @@ impl ParseIntError { IntErrorKind::InvalidDigit => "invalid digit found in string", IntErrorKind::Overflow => "number too large to fit in target type", IntErrorKind::Underflow => "number too small to fit in target type", + IntErrorKind::Zero => "number would be zero for non-zero type", } } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for ParseIntError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.__description().fmt(f) } } #[stable(feature = "rust1", since = "1.0.0")] -pub use num::dec2flt::ParseFloatError; +pub use crate::num::dec2flt::ParseFloatError; // Conversion traits for primitive integer and float types // Conversions T -> T are covered by a blanket impl and therefore excluded @@ -5029,106 +5217,3 @@ impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0" // Float -> Float impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } - -static ASCII_LOWERCASE_MAP: [u8; 256] = [ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', - b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', - b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', - b'8', b'9', b':', b';', b'<', b'=', b'>', b'?', - b'@', - - b'a', b'b', b'c', b'd', b'e', b'f', b'g', - b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', - b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', - b'x', b'y', b'z', - - b'[', b'\\', b']', b'^', b'_', - b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g', - b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', - b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', - b'x', b'y', b'z', b'{', b'|', b'}', b'~', 0x7f, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, -]; - -static ASCII_UPPERCASE_MAP: [u8; 256] = [ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', - b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', - b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', - b'8', b'9', b':', b';', b'<', b'=', b'>', b'?', - b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G', - b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', - b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', - b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_', - b'`', - - b'A', b'B', b'C', b'D', b'E', b'F', b'G', - b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', - b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', - b'X', b'Y', b'Z', - - b'{', b'|', b'}', b'~', 0x7f, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, -]; - -enum AsciiCharacterClass { - C, // control - Cw, // control whitespace - W, // whitespace - D, // digit - L, // lowercase - Lx, // lowercase hex digit - U, // uppercase - Ux, // uppercase hex digit - P, // punctuation -} -use self::AsciiCharacterClass::*; - -static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 128] = [ -// _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f - C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_ - C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_ - W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_ - D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_ - P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_ - U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_ - P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_ - L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_ -]; diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 9cd5108ade411..fd129a306d1c5 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -1,6 +1,6 @@ use super::Wrapping; -use ops::*; +use crate::ops::*; #[allow(unused_macros)] macro_rules! sh_impl_signed { @@ -511,7 +511,6 @@ assert_eq!(n.trailing_zeros(), 3); /// Basic usage: /// /// ``` - /// #![feature(reverse_bits)] /// use std::num::Wrapping; /// /// let n = Wrapping(0b0000000_01010101i16); @@ -522,8 +521,9 @@ assert_eq!(n.trailing_zeros(), 3); /// assert_eq!(m.0 as u16, 0b10101010_00000000); /// assert_eq!(m, Wrapping(-22016)); /// ``` - #[unstable(feature = "reverse_bits", issue = "48763")] + #[stable(feature = "reverse_bits", since = "1.37.0")] #[inline] + #[must_use] pub const fn reverse_bits(self) -> Self { Wrapping(self.0.reverse_bits()) } diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index 0252edee23125..3c009d644c64e 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -1,6 +1,6 @@ /// The addition operator `+`. /// -/// Note that `RHS` is `Self` by default, but this is not mandatory. For +/// Note that `Rhs` is `Self` by default, but this is not mandatory. For /// example, [`std::time::SystemTime`] implements `Add`, which permits /// operations of the form `SystemTime = SystemTime + Duration`. /// @@ -20,10 +20,10 @@ /// } /// /// impl Add for Point { -/// type Output = Point; +/// type Output = Self; /// -/// fn add(self, other: Point) -> Point { -/// Point { +/// fn add(self, other: Self) -> Self { +/// Self { /// x: self.x + other.x, /// y: self.y + other.y, /// } @@ -50,10 +50,10 @@ /// /// // Notice that the implementation uses the associated type `Output`. /// impl> Add for Point { -/// type Output = Point; +/// type Output = Self; /// -/// fn add(self, other: Point) -> Point { -/// Point { +/// fn add(self, other: Self) -> Self::Output { +/// Self { /// x: self.x + other.x, /// y: self.y + other.y, /// } @@ -67,18 +67,18 @@ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( - all(_Self="{integer}", RHS="{float}"), + all(_Self="{integer}", Rhs="{float}"), message="cannot add a float to an integer", ), on( - all(_Self="{float}", RHS="{integer}"), + all(_Self="{float}", Rhs="{integer}"), message="cannot add an integer to a float", ), - message="cannot add `{RHS}` to `{Self}`", - label="no implementation for `{Self} + {RHS}`", + message="cannot add `{Rhs}` to `{Self}`", + label="no implementation for `{Self} + {Rhs}`", )] #[doc(alias = "+")] -pub trait Add { +pub trait Add { /// The resulting type after applying the `+` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; @@ -86,7 +86,7 @@ pub trait Add { /// Performs the `+` operation. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - fn add(self, rhs: RHS) -> Self::Output; + fn add(self, rhs: Rhs) -> Self::Output; } macro_rules! add_impl { @@ -108,7 +108,7 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// The subtraction operator `-`. /// -/// Note that `RHS` is `Self` by default, but this is not mandatory. For +/// Note that `Rhs` is `Self` by default, but this is not mandatory. For /// example, [`std::time::SystemTime`] implements `Sub`, which permits /// operations of the form `SystemTime = SystemTime - Duration`. /// @@ -158,9 +158,9 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// /// // Notice that the implementation uses the associated type `Output`. /// impl> Sub for Point { -/// type Output = Point; +/// type Output = Self; /// -/// fn sub(self, other: Point) -> Point { +/// fn sub(self, other: Self) -> Self::Output { /// Point { /// x: self.x - other.x, /// y: self.y - other.y, @@ -173,10 +173,10 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented(message="cannot subtract `{RHS}` from `{Self}`", - label="no implementation for `{Self} - {RHS}`")] +#[rustc_on_unimplemented(message="cannot subtract `{Rhs}` from `{Self}`", + label="no implementation for `{Self} - {Rhs}`")] #[doc(alias = "-")] -pub trait Sub { +pub trait Sub { /// The resulting type after applying the `-` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; @@ -184,7 +184,7 @@ pub trait Sub { /// Performs the `-` operation. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - fn sub(self, rhs: RHS) -> Self::Output; + fn sub(self, rhs: Rhs) -> Self::Output; } macro_rules! sub_impl { @@ -206,7 +206,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// The multiplication operator `*`. /// -/// Note that `RHS` is `Self` by default, but this is not mandatory. +/// Note that `Rhs` is `Self` by default, but this is not mandatory. /// /// # Examples /// @@ -220,21 +220,21 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// // derive `Eq` and `PartialEq`. /// #[derive(Debug, Eq, PartialEq)] /// struct Rational { -/// nominator: usize, +/// numerator: usize, /// denominator: usize, /// } /// /// impl Rational { -/// fn new(nominator: usize, denominator: usize) -> Self { +/// fn new(numerator: usize, denominator: usize) -> Self { /// if denominator == 0 { /// panic!("Zero is an invalid denominator!"); /// } /// /// // Reduce to lowest terms by dividing by the greatest common /// // divisor. -/// let gcd = gcd(nominator, denominator); +/// let gcd = gcd(numerator, denominator); /// Rational { -/// nominator: nominator / gcd, +/// numerator: numerator / gcd, /// denominator: denominator / gcd, /// } /// } @@ -245,9 +245,9 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// type Output = Self; /// /// fn mul(self, rhs: Self) -> Self { -/// let nominator = self.nominator * rhs.nominator; +/// let numerator = self.numerator * rhs.numerator; /// let denominator = self.denominator * rhs.denominator; -/// Rational::new(nominator, denominator) +/// Rational::new(numerator, denominator) /// } /// } /// @@ -280,9 +280,9 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// struct Vector { value: Vec } /// /// impl Mul for Vector { -/// type Output = Vector; +/// type Output = Self; /// -/// fn mul(self, rhs: Scalar) -> Vector { +/// fn mul(self, rhs: Scalar) -> Self::Output { /// Vector { value: self.value.iter().map(|v| v * rhs.value).collect() } /// } /// } @@ -293,10 +293,10 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "mul"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented(message="cannot multiply `{RHS}` to `{Self}`", - label="no implementation for `{Self} * {RHS}`")] +#[rustc_on_unimplemented(message="cannot multiply `{Rhs}` to `{Self}`", + label="no implementation for `{Self} * {Rhs}`")] #[doc(alias = "*")] -pub trait Mul { +pub trait Mul { /// The resulting type after applying the `*` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; @@ -304,7 +304,7 @@ pub trait Mul { /// Performs the `*` operation. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - fn mul(self, rhs: RHS) -> Self::Output; + fn mul(self, rhs: Rhs) -> Self::Output; } macro_rules! mul_impl { @@ -326,7 +326,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// The division operator `/`. /// -/// Note that `RHS` is `Self` by default, but this is not mandatory. +/// Note that `Rhs` is `Self` by default, but this is not mandatory. /// /// # Examples /// @@ -340,21 +340,21 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// // derive `Eq` and `PartialEq`. /// #[derive(Debug, Eq, PartialEq)] /// struct Rational { -/// nominator: usize, +/// numerator: usize, /// denominator: usize, /// } /// /// impl Rational { -/// fn new(nominator: usize, denominator: usize) -> Self { +/// fn new(numerator: usize, denominator: usize) -> Self { /// if denominator == 0 { /// panic!("Zero is an invalid denominator!"); /// } /// /// // Reduce to lowest terms by dividing by the greatest common /// // divisor. -/// let gcd = gcd(nominator, denominator); +/// let gcd = gcd(numerator, denominator); /// Rational { -/// nominator: nominator / gcd, +/// numerator: numerator / gcd, /// denominator: denominator / gcd, /// } /// } @@ -364,14 +364,14 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// // The division of rational numbers is a closed operation. /// type Output = Self; /// -/// fn div(self, rhs: Self) -> Self { -/// if rhs.nominator == 0 { +/// fn div(self, rhs: Self) -> Self::Output { +/// if rhs.numerator == 0 { /// panic!("Cannot divide by zero-valued `Rational`!"); /// } /// -/// let nominator = self.nominator * rhs.denominator; -/// let denominator = self.denominator * rhs.nominator; -/// Rational::new(nominator, denominator) +/// let numerator = self.numerator * rhs.denominator; +/// let denominator = self.denominator * rhs.numerator; +/// Rational::new(numerator, denominator) /// } /// } /// @@ -404,9 +404,9 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// struct Vector { value: Vec } /// /// impl Div for Vector { -/// type Output = Vector; +/// type Output = Self; /// -/// fn div(self, rhs: Scalar) -> Vector { +/// fn div(self, rhs: Scalar) -> Self::Output { /// Vector { value: self.value.iter().map(|v| v / rhs.value).collect() } /// } /// } @@ -417,10 +417,10 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "div"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented(message="cannot divide `{Self}` by `{RHS}`", - label="no implementation for `{Self} / {RHS}`")] +#[rustc_on_unimplemented(message="cannot divide `{Self}` by `{Rhs}`", + label="no implementation for `{Self} / {Rhs}`")] #[doc(alias = "/")] -pub trait Div { +pub trait Div { /// The resulting type after applying the `/` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; @@ -428,7 +428,7 @@ pub trait Div { /// Performs the `/` operation. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - fn div(self, rhs: RHS) -> Self::Output; + fn div(self, rhs: Rhs) -> Self::Output; } macro_rules! div_impl_integer { @@ -467,7 +467,7 @@ div_impl_float! { f32 f64 } /// The remainder operator `%`. /// -/// Note that `RHS` is `Self` by default, but this is not mandatory. +/// Note that `Rhs` is `Self` by default, but this is not mandatory. /// /// # Examples /// @@ -485,9 +485,9 @@ div_impl_float! { f32 f64 } /// } /// /// impl<'a, T> Rem for SplitSlice<'a, T> { -/// type Output = SplitSlice<'a, T>; +/// type Output = Self; /// -/// fn rem(self, modulus: usize) -> Self { +/// fn rem(self, modulus: usize) -> Self::Output { /// let len = self.slice.len(); /// let rem = len % modulus; /// let start = len - rem; @@ -502,18 +502,18 @@ div_impl_float! { f32 f64 } /// ``` #[lang = "rem"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented(message="cannot mod `{Self}` by `{RHS}`", - label="no implementation for `{Self} % {RHS}`")] +#[rustc_on_unimplemented(message="cannot mod `{Self}` by `{Rhs}`", + label="no implementation for `{Self} % {Rhs}`")] #[doc(alias = "%")] -pub trait Rem { +pub trait Rem { /// The resulting type after applying the `%` operator. #[stable(feature = "rust1", since = "1.0.0")] - type Output = Self; + type Output; /// Performs the `%` operation. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - fn rem(self, rhs: RHS) -> Self::Output; + fn rem(self, rhs: Rhs) -> Self::Output; } macro_rules! rem_impl_integer { @@ -537,6 +537,21 @@ rem_impl_integer! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } macro_rules! rem_impl_float { ($($t:ty)*) => ($( + + /// The remainder from the division of two floats. + /// + /// The remainder has the same sign as the dividend and is computed as: + /// `x - (x / y).trunc() * y`. + /// + /// # Examples + /// ``` + /// let x: f32 = 50.50; + /// let y: f32 = 8.125; + /// let remainder = x - (x / y).trunc() * y; + /// + /// // The answer to both operations is 1.75 + /// assert_eq!(x % y, remainder); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] impl Rem for $t { type Output = $t; @@ -571,7 +586,7 @@ rem_impl_float! { f32 f64 } /// impl Neg for Sign { /// type Output = Sign; /// -/// fn neg(self) -> Sign { +/// fn neg(self) -> Self::Output { /// match self { /// Sign::Negative => Sign::Positive, /// Sign::Zero => Sign::Zero, @@ -650,8 +665,8 @@ neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } /// } /// /// impl AddAssign for Point { -/// fn add_assign(&mut self, other: Point) { -/// *self = Point { +/// fn add_assign(&mut self, other: Self) { +/// *self = Self { /// x: self.x + other.x, /// y: self.y + other.y, /// }; @@ -706,8 +721,8 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// } /// /// impl SubAssign for Point { -/// fn sub_assign(&mut self, other: Point) { -/// *self = Point { +/// fn sub_assign(&mut self, other: Self) { +/// *self = Self { /// x: self.x - other.x, /// y: self.y - other.y, /// }; diff --git a/src/libcore/ops/bit.rs b/src/libcore/ops/bit.rs index 2c9bf248633c4..a8f862f6c05a5 100644 --- a/src/libcore/ops/bit.rs +++ b/src/libcore/ops/bit.rs @@ -17,7 +17,7 @@ /// impl Not for Answer { /// type Output = Answer; /// -/// fn not(self) -> Answer { +/// fn not(self) -> Self::Output { /// match self { /// Answer::Yes => Answer::No, /// Answer::No => Answer::Yes @@ -59,7 +59,7 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// The bitwise AND operator `&`. /// -/// Note that `RHS` is `Self` by default, but this is not mandatory. +/// Note that `Rhs` is `Self` by default, but this is not mandatory. /// /// # Examples /// @@ -75,7 +75,7 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// type Output = Self; /// /// // rhs is the "right-hand side" of the expression `a & b` -/// fn bitand(self, rhs: Self) -> Self { +/// fn bitand(self, rhs: Self) -> Self::Output { /// Scalar(self.0 & rhs.0) /// } /// } @@ -97,7 +97,7 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl BitAnd for BooleanVector { /// type Output = Self; /// -/// fn bitand(self, BooleanVector(rhs): Self) -> Self { +/// fn bitand(self, BooleanVector(rhs): Self) -> Self::Output { /// let BooleanVector(lhs) = self; /// assert_eq!(lhs.len(), rhs.len()); /// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x && *y).collect()) @@ -112,9 +112,9 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[lang = "bitand"] #[doc(alias = "&")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented(message="no implementation for `{Self} & {RHS}`", - label="no implementation for `{Self} & {RHS}`")] -pub trait BitAnd { +#[rustc_on_unimplemented(message="no implementation for `{Self} & {Rhs}`", + label="no implementation for `{Self} & {Rhs}`")] +pub trait BitAnd { /// The resulting type after applying the `&` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; @@ -122,7 +122,7 @@ pub trait BitAnd { /// Performs the `&` operation. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - fn bitand(self, rhs: RHS) -> Self::Output; + fn bitand(self, rhs: Rhs) -> Self::Output; } macro_rules! bitand_impl { @@ -143,7 +143,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// The bitwise OR operator `|`. /// -/// Note that `RHS` is `Self` by default, but this is not mandatory. +/// Note that `Rhs` is `Self` by default, but this is not mandatory. /// /// # Examples /// @@ -181,7 +181,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl BitOr for BooleanVector { /// type Output = Self; /// -/// fn bitor(self, BooleanVector(rhs): Self) -> Self { +/// fn bitor(self, BooleanVector(rhs): Self) -> Self::Output { /// let BooleanVector(lhs) = self; /// assert_eq!(lhs.len(), rhs.len()); /// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x || *y).collect()) @@ -196,9 +196,9 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[lang = "bitor"] #[doc(alias = "|")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented(message="no implementation for `{Self} | {RHS}`", - label="no implementation for `{Self} | {RHS}`")] -pub trait BitOr { +#[rustc_on_unimplemented(message="no implementation for `{Self} | {Rhs}`", + label="no implementation for `{Self} | {Rhs}`")] +pub trait BitOr { /// The resulting type after applying the `|` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; @@ -206,7 +206,7 @@ pub trait BitOr { /// Performs the `|` operation. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - fn bitor(self, rhs: RHS) -> Self::Output; + fn bitor(self, rhs: Rhs) -> Self::Output; } macro_rules! bitor_impl { @@ -227,7 +227,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// The bitwise XOR operator `^`. /// -/// Note that `RHS` is `Self` by default, but this is not mandatory. +/// Note that `Rhs` is `Self` by default, but this is not mandatory. /// /// # Examples /// @@ -243,7 +243,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// type Output = Self; /// /// // rhs is the "right-hand side" of the expression `a ^ b` -/// fn bitxor(self, rhs: Self) -> Self { +/// fn bitxor(self, rhs: Self) -> Self::Output { /// Scalar(self.0 ^ rhs.0) /// } /// } @@ -265,7 +265,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl BitXor for BooleanVector { /// type Output = Self; /// -/// fn bitxor(self, BooleanVector(rhs): Self) -> Self { +/// fn bitxor(self, BooleanVector(rhs): Self) -> Self::Output { /// let BooleanVector(lhs) = self; /// assert_eq!(lhs.len(), rhs.len()); /// BooleanVector(lhs.iter() @@ -283,9 +283,9 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[lang = "bitxor"] #[doc(alias = "^")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented(message="no implementation for `{Self} ^ {RHS}`", - label="no implementation for `{Self} ^ {RHS}`")] -pub trait BitXor { +#[rustc_on_unimplemented(message="no implementation for `{Self} ^ {Rhs}`", + label="no implementation for `{Self} ^ {Rhs}`")] +pub trait BitXor { /// The resulting type after applying the `^` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; @@ -293,7 +293,7 @@ pub trait BitXor { /// Performs the `^` operation. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - fn bitxor(self, rhs: RHS) -> Self::Output; + fn bitxor(self, rhs: Rhs) -> Self::Output; } macro_rules! bitxor_impl { @@ -355,7 +355,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl Shl for SpinVector { /// type Output = Self; /// -/// fn shl(self, rhs: usize) -> SpinVector { +/// fn shl(self, rhs: usize) -> Self::Output { /// // Rotate the vector by `rhs` places. /// let (a, b) = self.vec.split_at(rhs); /// let mut spun_vector: Vec = vec![]; @@ -371,9 +371,9 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[lang = "shl"] #[doc(alias = "<<")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented(message="no implementation for `{Self} << {RHS}`", - label="no implementation for `{Self} << {RHS}`")] -pub trait Shl { +#[rustc_on_unimplemented(message="no implementation for `{Self} << {Rhs}`", + label="no implementation for `{Self} << {Rhs}`")] +pub trait Shl { /// The resulting type after applying the `<<` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; @@ -381,7 +381,7 @@ pub trait Shl { /// Performs the `<<` operation. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - fn shl(self, rhs: RHS) -> Self::Output; + fn shl(self, rhs: Rhs) -> Self::Output; } macro_rules! shl_impl { @@ -464,7 +464,7 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// impl Shr for SpinVector { /// type Output = Self; /// -/// fn shr(self, rhs: usize) -> SpinVector { +/// fn shr(self, rhs: usize) -> Self::Output { /// // Rotate the vector by `rhs` places. /// let (a, b) = self.vec.split_at(self.vec.len() - rhs); /// let mut spun_vector: Vec = vec![]; @@ -480,9 +480,9 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } #[lang = "shr"] #[doc(alias = ">>")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented(message="no implementation for `{Self} >> {RHS}`", - label="no implementation for `{Self} >> {RHS}`")] -pub trait Shr { +#[rustc_on_unimplemented(message="no implementation for `{Self} >> {Rhs}`", + label="no implementation for `{Self} >> {Rhs}`")] +pub trait Shr { /// The resulting type after applying the `>>` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; @@ -490,7 +490,7 @@ pub trait Shr { /// Performs the `>>` operation. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - fn shr(self, rhs: RHS) -> Self::Output; + fn shr(self, rhs: Rhs) -> Self::Output; } macro_rules! shr_impl { diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index eb76c2de11bec..ce0d3fd01f78f 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -23,9 +23,9 @@ /// * Values of type `&T` are coerced to values of type `&U` /// * `T` implicitly implements all the (immutable) methods of the type `U`. /// -/// For more details, visit [the chapter in *The Rust Programming Language*] -/// [book] as well as the reference sections on [the dereference operator] -/// [ref-deref-op], [method resolution] and [type coercions]. +/// For more details, visit [the chapter in *The Rust Programming Language*][book] +/// as well as the reference sections on [the dereference operator][ref-deref-op], +/// [method resolution] and [type coercions]. /// /// [book]: ../../book/ch15-02-deref.html /// [`DerefMut`]: trait.DerefMut.html @@ -49,7 +49,7 @@ /// impl Deref for DerefExample { /// type Target = T; /// -/// fn deref(&self) -> &T { +/// fn deref(&self) -> &Self::Target { /// &self.value /// } /// } @@ -113,9 +113,9 @@ impl Deref for &mut T { /// * Values of type `&mut T` are coerced to values of type `&mut U` /// * `T` implicitly implements all the (mutable) methods of the type `U`. /// -/// For more details, visit [the chapter in *The Rust Programming Language*] -/// [book] as well as the reference sections on [the dereference operator] -/// [ref-deref-op], [method resolution] and [type coercions]. +/// For more details, visit [the chapter in *The Rust Programming Language*][book] +/// as well as the reference sections on [the dereference operator][ref-deref-op], +/// [method resolution] and [type coercions]. /// /// [book]: ../../book/ch15-02-deref.html /// [`Deref`]: trait.Deref.html @@ -139,13 +139,13 @@ impl Deref for &mut T { /// impl Deref for DerefMutExample { /// type Target = T; /// -/// fn deref(&self) -> &T { +/// fn deref(&self) -> &Self::Target { /// &self.value /// } /// } /// /// impl DerefMut for DerefMutExample { -/// fn deref_mut(&mut self) -> &mut T { +/// fn deref_mut(&mut self) -> &mut Self::Target { /// &mut self.value /// } /// } diff --git a/src/libcore/ops/index.rs b/src/libcore/ops/index.rs index d4ed86142768d..3158f58e95806 100644 --- a/src/libcore/ops/index.rs +++ b/src/libcore/ops/index.rs @@ -33,7 +33,7 @@ /// impl Index for NucleotideCount { /// type Output = usize; /// -/// fn index(&self, nucleotide: Nucleotide) -> &usize { +/// fn index(&self, nucleotide: Nucleotide) -> &Self::Output { /// match nucleotide { /// Nucleotide::A => &self.a, /// Nucleotide::C => &self.c, @@ -105,7 +105,7 @@ pub trait Index { /// impl Index for Balance { /// type Output = Weight; /// -/// fn index<'a>(&'a self, index: Side) -> &'a Weight { +/// fn index<'a>(&'a self, index: Side) -> &'a Self::Output { /// println!("Accessing {:?}-side of balance immutably", index); /// match index { /// Side::Left => &self.left, @@ -115,7 +115,7 @@ pub trait Index { /// } /// /// impl IndexMut for Balance { -/// fn index_mut<'a>(&'a mut self, index: Side) -> &'a mut Weight { +/// fn index_mut<'a>(&'a mut self, index: Side) -> &'a mut Self::Output { /// println!("Accessing {:?}-side of balance mutably", index); /// match index { /// Side::Left => &mut self.left, diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 0ca64f28ff309..5d1d3efd4120f 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -152,7 +152,7 @@ mod function; mod generator; mod index; mod range; -mod try; +mod r#try; mod unsize; #[stable(feature = "rust1", since = "1.0.0")] @@ -187,7 +187,7 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; pub use self::range::{RangeInclusive, RangeToInclusive, RangeBounds, Bound}; #[unstable(feature = "try_trait", issue = "42327")] -pub use self::try::Try; +pub use self::r#try::Try; #[unstable(feature = "generator_trait", issue = "43122")] pub use self::generator::{Generator, GeneratorState}; diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 998b597d5e113..1b4c4218cc15b 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -1,5 +1,5 @@ -use fmt; -use hash::{Hash, Hasher}; +use crate::fmt; +use crate::hash::{Hash, Hasher}; /// An unbounded range (`..`). /// @@ -26,11 +26,13 @@ use hash::{Hash, Hasher}; /// Used as a [slicing index], `RangeFull` produces the full array as a slice. /// /// ``` -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); // RangeFull -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); +/// let arr = [0, 1, 2, 3, 4]; +/// assert_eq!(arr[ .. ], [0,1,2,3,4]); // RangeFull +/// assert_eq!(arr[ .. 3], [0,1,2 ]); +/// assert_eq!(arr[ ..=3], [0,1,2,3 ]); +/// assert_eq!(arr[1.. ], [ 1,2,3,4]); +/// assert_eq!(arr[1.. 3], [ 1,2 ]); +/// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` /// /// [`IntoIterator`]: ../iter/trait.Iterator.html @@ -43,7 +45,7 @@ pub struct RangeFull; #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for RangeFull { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "..") } } @@ -60,14 +62,16 @@ impl fmt::Debug for RangeFull { /// assert_eq!((3..5), std::ops::Range { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, (3..6).sum()); /// -/// let arr = ['a', 'b', 'c', 'd']; -/// assert_eq!(arr[ .. ], ['a', 'b', 'c', 'd']); -/// assert_eq!(arr[ ..3], ['a', 'b', 'c', ]); -/// assert_eq!(arr[1.. ], [ 'b', 'c', 'd']); -/// assert_eq!(arr[1..3], [ 'b', 'c' ]); // Range +/// let arr = [0, 1, 2, 3, 4]; +/// assert_eq!(arr[ .. ], [0,1,2,3,4]); +/// assert_eq!(arr[ .. 3], [0,1,2 ]); +/// assert_eq!(arr[ ..=3], [0,1,2,3 ]); +/// assert_eq!(arr[1.. ], [ 1,2,3,4]); +/// assert_eq!(arr[1.. 3], [ 1,2 ]); // Range +/// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` #[doc(alias = "..")] -#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct Range { /// The lower bound of the range (inclusive). @@ -80,8 +84,11 @@ pub struct Range { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Range { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}..{:?}", self.start, self.end) + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.start.fmt(fmt)?; + write!(fmt, "..")?; + self.end.fmt(fmt)?; + Ok(()) } } @@ -91,8 +98,6 @@ impl> Range { /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!(!(3..5).contains(&2)); @@ -108,7 +113,7 @@ impl> Range { /// assert!(!(0.0..f32::NAN).contains(&0.5)); /// assert!(!(f32::NAN..1.0).contains(&0.5)); /// ``` - #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + #[stable(feature = "range_contains", since = "1.35.0")] pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, @@ -160,16 +165,18 @@ impl> Range { /// assert_eq!((2..), std::ops::RangeFrom { start: 2 }); /// assert_eq!(2 + 3 + 4, (2..).take(3).sum()); /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); // RangeFrom -/// assert_eq!(arr[1..3], [ 1,2 ]); +/// let arr = [0, 1, 2, 3, 4]; +/// assert_eq!(arr[ .. ], [0,1,2,3,4]); +/// assert_eq!(arr[ .. 3], [0,1,2 ]); +/// assert_eq!(arr[ ..=3], [0,1,2,3 ]); +/// assert_eq!(arr[1.. ], [ 1,2,3,4]); // RangeFrom +/// assert_eq!(arr[1.. 3], [ 1,2 ]); +/// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` /// /// [`Iterator`]: ../iter/trait.IntoIterator.html #[doc(alias = "..")] -#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFrom { /// The lower bound of the range (inclusive). @@ -179,8 +186,10 @@ pub struct RangeFrom { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for RangeFrom { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}..", self.start) + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.start.fmt(fmt)?; + write!(fmt, "..")?; + Ok(()) } } @@ -190,8 +199,6 @@ impl> RangeFrom { /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!(!(3..).contains(&2)); @@ -202,7 +209,7 @@ impl> RangeFrom { /// assert!(!(0.0..).contains(&f32::NAN)); /// assert!(!(f32::NAN..).contains(&0.5)); /// ``` - #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + #[stable(feature = "range_contains", since = "1.35.0")] pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, @@ -240,11 +247,13 @@ impl> RangeFrom { /// elements before the index indicated by `end`. /// /// ``` -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); -/// assert_eq!(arr[ ..3], [0,1,2 ]); // RangeTo -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); +/// let arr = [0, 1, 2, 3, 4]; +/// assert_eq!(arr[ .. ], [0,1,2,3,4]); +/// assert_eq!(arr[ .. 3], [0,1,2 ]); // RangeTo +/// assert_eq!(arr[ ..=3], [0,1,2,3 ]); +/// assert_eq!(arr[1.. ], [ 1,2,3,4]); +/// assert_eq!(arr[1.. 3], [ 1,2 ]); +/// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` /// /// [`IntoIterator`]: ../iter/trait.Iterator.html @@ -261,8 +270,10 @@ pub struct RangeTo { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for RangeTo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "..{:?}", self.end) + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "..")?; + self.end.fmt(fmt)?; + Ok(()) } } @@ -272,8 +283,6 @@ impl> RangeTo { /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!( (..5).contains(&-1_000_000_000)); @@ -284,7 +293,7 @@ impl> RangeTo { /// assert!(!(..1.0).contains(&f32::NAN)); /// assert!(!(..f32::NAN).contains(&0.5)); /// ``` - #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + #[stable(feature = "range_contains", since = "1.35.0")] pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, @@ -312,12 +321,16 @@ impl> RangeTo { /// assert_eq!((3..=5), std::ops::RangeInclusive::new(3, 5)); /// assert_eq!(3 + 4 + 5, (3..=5).sum()); /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ ..=2], [0,1,2 ]); -/// assert_eq!(arr[1..=2], [ 1,2 ]); // RangeInclusive +/// let arr = [0, 1, 2, 3, 4]; +/// assert_eq!(arr[ .. ], [0,1,2,3,4]); +/// assert_eq!(arr[ .. 3], [0,1,2 ]); +/// assert_eq!(arr[ ..=3], [0,1,2,3 ]); +/// assert_eq!(arr[1.. ], [ 1,2,3,4]); +/// assert_eq!(arr[1.. 3], [ 1,2 ]); +/// assert_eq!(arr[1..=3], [ 1,2,3 ]); // RangeInclusive /// ``` #[doc(alias = "..=")] -#[derive(Clone)] // not Copy -- see #27186 +#[derive(Clone)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeInclusive { pub(crate) start: Idx, @@ -353,7 +366,8 @@ impl RangeInclusiveEquality for T { impl PartialEq for RangeInclusive { #[inline] fn eq(&self, other: &Self) -> bool { - self.start == other.start && self.end == other.end + self.start == other.start + && self.end == other.end && RangeInclusiveEquality::canonicalized_is_empty(self) == RangeInclusiveEquality::canonicalized_is_empty(other) } @@ -385,7 +399,11 @@ impl RangeInclusive { #[inline] #[rustc_promotable] pub const fn new(start: Idx, end: Idx) -> Self { - Self { start, end, is_empty: None } + Self { + start, + end, + is_empty: None, + } } /// Returns the lower bound of the range (inclusive). @@ -455,8 +473,11 @@ impl RangeInclusive { #[stable(feature = "inclusive_range", since = "1.26.0")] impl fmt::Debug for RangeInclusive { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}..={:?}", self.start, self.end) + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.start.fmt(fmt)?; + write!(fmt, "..=")?; + self.end.fmt(fmt)?; + Ok(()) } } @@ -466,8 +487,6 @@ impl> RangeInclusive { /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!(!(3..=5).contains(&2)); @@ -484,7 +503,7 @@ impl> RangeInclusive { /// assert!(!(0.0..=f32::NAN).contains(&0.0)); /// assert!(!(f32::NAN..=1.0).contains(&1.0)); /// ``` - #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + #[stable(feature = "range_contains", since = "1.35.0")] pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, @@ -569,9 +588,13 @@ impl> RangeInclusive { /// array elements up to and including the index indicated by `end`. /// /// ``` -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ ..=2], [0,1,2 ]); // RangeToInclusive -/// assert_eq!(arr[1..=2], [ 1,2 ]); +/// let arr = [0, 1, 2, 3, 4]; +/// assert_eq!(arr[ .. ], [0,1,2,3,4]); +/// assert_eq!(arr[ .. 3], [0,1,2 ]); +/// assert_eq!(arr[ ..=3], [0,1,2,3 ]); // RangeToInclusive +/// assert_eq!(arr[1.. ], [ 1,2,3,4]); +/// assert_eq!(arr[1.. 3], [ 1,2 ]); +/// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` /// /// [`IntoIterator`]: ../iter/trait.Iterator.html @@ -588,20 +611,19 @@ pub struct RangeToInclusive { #[stable(feature = "inclusive_range", since = "1.26.0")] impl fmt::Debug for RangeToInclusive { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "..={:?}", self.end) + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "..=")?; + self.end.fmt(fmt)?; + Ok(()) } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeToInclusive { /// Returns `true` if `item` is contained in the range. /// /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!( (..=5).contains(&-1_000_000_000)); @@ -612,7 +634,7 @@ impl> RangeToInclusive { /// assert!(!(..=1.0).contains(&f32::NAN)); /// assert!(!(..=f32::NAN).contains(&0.5)); /// ``` - #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + #[stable(feature = "range_contains", since = "1.35.0")] pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, @@ -674,9 +696,32 @@ pub enum Bound { Unbounded, } +impl Bound<&T> { + /// Map a `Bound<&T>` to a `Bound` by cloning the contents of the bound. + /// + /// # Examples + /// + /// ``` + /// #![feature(bound_cloned)] + /// use std::ops::Bound::*; + /// use std::ops::RangeBounds; + /// + /// assert_eq!((1..12).start_bound(), Included(&1)); + /// assert_eq!((1..12).start_bound().cloned(), Included(1)); + /// ``` + #[unstable(feature = "bound_cloned", issue = "61356")] + pub fn cloned(self) -> Bound { + match self { + Bound::Unbounded => Bound::Unbounded, + Bound::Included(x) => Bound::Included(x.clone()), + Bound::Excluded(x) => Bound::Excluded(x.clone()), + } + } +} + #[stable(feature = "collections_range", since = "1.28.0")] /// `RangeBounds` is implemented by Rust's built-in range types, produced -/// by range syntax like `..`, `a..`, `..b` or `c..d`. +/// by range syntax like `..`, `a..`, `..b`, `..=c`, `d..e`, or `f..=g`. pub trait RangeBounds { /// Start index bound. /// @@ -714,14 +759,11 @@ pub trait RangeBounds { #[stable(feature = "collections_range", since = "1.28.0")] fn end_bound(&self) -> Bound<&T>; - /// Returns `true` if `item` is contained in the range. /// /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!( (3..5).contains(&4)); @@ -731,7 +773,7 @@ pub trait RangeBounds { /// assert!(!(0.0..1.0).contains(&f32::NAN)); /// assert!(!(0.0..f32::NAN).contains(&0.5)); /// assert!(!(f32::NAN..1.0).contains(&0.5)); - #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + #[stable(feature = "range_contains", since = "1.35.0")] fn contains(&self, item: &U) -> bool where T: PartialOrd, @@ -741,9 +783,7 @@ pub trait RangeBounds { Included(ref start) => *start <= item, Excluded(ref start) => *start < item, Unbounded => true, - }) - && - (match self.end_bound() { + }) && (match self.end_bound() { Included(ref end) => item <= *end, Excluded(ref end) => item < *end, Unbounded => true, @@ -819,7 +859,7 @@ impl RangeBounds for (Bound, Bound) { match *self { (Included(ref start), _) => Included(start), (Excluded(ref start), _) => Excluded(start), - (Unbounded, _) => Unbounded, + (Unbounded, _) => Unbounded, } } @@ -827,7 +867,7 @@ impl RangeBounds for (Bound, Bound) { match *self { (_, Included(ref end)) => Included(end), (_, Excluded(ref end)) => Excluded(end), - (_, Unbounded) => Unbounded, + (_, Unbounded) => Unbounded, } } } diff --git a/src/libcore/ops/unsize.rs b/src/libcore/ops/unsize.rs index bd95ddf060ee4..8e46830084642 100644 --- a/src/libcore/ops/unsize.rs +++ b/src/libcore/ops/unsize.rs @@ -1,4 +1,4 @@ -use marker::Unsize; +use crate::marker::Unsize; /// Trait that indicates that this is a pointer or a wrapper for one, /// where unsizing can be performed on the pointee. @@ -71,7 +71,7 @@ impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} /// This is used for object safety, to check that a method's receiver type can be dispatched on. /// -/// example impl: +/// An example implementation of the trait: /// /// ``` /// # #![feature(dispatch_from_dyn, unsize)] @@ -100,4 +100,3 @@ impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} // *mut T -> *mut U #[unstable(feature = "dispatch_from_dyn", issue = "0")] impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} - diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 60aed7ce09d7f..eec4b149ddc78 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -135,9 +135,9 @@ #![stable(feature = "rust1", since = "1.0.0")] -use iter::{FromIterator, FusedIterator, TrustedLen}; -use {hint, mem, ops::{self, Deref}}; -use pin::Pin; +use crate::iter::{FromIterator, FusedIterator, TrustedLen}; +use crate::{convert, hint, mem, ops::{self, Deref}}; +use crate::pin::Pin; // Note that this is not a lang item per se, but it has a hidden dependency on // `Iterator`, which is one. The compiler assumes that the `next` method of @@ -145,7 +145,7 @@ use pin::Pin; // which basically means it must be `Option`. /// The `Option` type. See [the module level documentation](index.html) for more. -#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] +#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Option { /// No value @@ -178,6 +178,7 @@ impl Option { /// ``` /// /// [`Some`]: #variant.Some + #[must_use] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_some(&self) -> bool { @@ -200,6 +201,7 @@ impl Option { /// ``` /// /// [`None`]: #variant.None + #[must_use] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_none(&self) -> bool { @@ -210,7 +212,7 @@ impl Option { // Adapter for working with references ///////////////////////////////////////////////////////////////////////// - /// Converts from `Option` to `Option<&T>`. + /// Converts from `&Option` to `Option<&T>`. /// /// # Examples /// @@ -239,7 +241,7 @@ impl Option { } } - /// Converts from `Option` to `Option<&mut T>`. + /// Converts from `&mut Option` to `Option<&mut T>`. /// /// # Examples /// @@ -536,7 +538,7 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, T> { Iter { inner: Item { opt: self.as_ref() } } } @@ -557,7 +559,7 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter_mut(&mut self) -> IterMut { + pub fn iter_mut(&mut self) -> IterMut<'_, T> { IterMut { inner: Item { opt: self.as_mut() } } } @@ -723,8 +725,6 @@ impl Option { /// # Examples /// /// ``` - /// #![feature(option_xor)] - /// /// let x = Some(2); /// let y: Option = None; /// assert_eq!(x.xor(y), Some(2)); @@ -742,7 +742,7 @@ impl Option { /// assert_eq!(x.xor(y), None); /// ``` #[inline] - #[unstable(feature = "option_xor", issue = "50512")] + #[stable(feature = "option_xor", since = "1.37.0")] pub fn xor(self, optb: Option) -> Option { match (self, optb) { (Some(a), None) => Some(a), @@ -881,15 +881,13 @@ impl Option<&T> { /// # Examples /// /// ``` - /// #![feature(copied)] - /// /// let x = 12; /// let opt_x = Some(&x); /// assert_eq!(opt_x, Some(&12)); /// let copied = opt_x.copied(); /// assert_eq!(copied, Some(12)); /// ``` - #[unstable(feature = "copied", issue = "57126")] + #[stable(feature = "copied", since = "1.35.0")] pub fn copied(self) -> Option { self.map(|&t| t) } @@ -902,15 +900,13 @@ impl Option<&mut T> { /// # Examples /// /// ``` - /// #![feature(copied)] - /// /// let mut x = 12; /// let opt_x = Some(&mut x); /// assert_eq!(opt_x, Some(&mut 12)); /// let copied = opt_x.copied(); /// assert_eq!(copied, Some(12)); /// ``` - #[unstable(feature = "copied", issue = "57126")] + #[stable(feature = "copied", since = "1.35.0")] pub fn copied(self) -> Option { self.map(|&mut t| t) } @@ -1042,6 +1038,25 @@ fn expect_failed(msg: &str) -> ! { // Trait implementations ///////////////////////////////////////////////////////////////////////////// +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Option { + #[inline] + fn clone(&self) -> Self { + match self { + Some(x) => Some(x.clone()), + None => None, + } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + match (self, source) { + (Some(to), Some(from)) => to.clone_from(from), + (to, from) => *to = from.clone(), + } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Default for Option { /// Returns [`None`][Option::None]. @@ -1286,7 +1301,7 @@ impl> FromIterator> for Option { /// # Examples /// /// Here is an example which increments every integer in a vector. - /// `We use the checked variant of `add` that returns `None` when the + /// We use the checked variant of `add` that returns `None` when the /// calculation would result in an overflow. /// /// ``` @@ -1319,6 +1334,26 @@ impl> FromIterator> for Option { /// Since the last element is zero, it would underflow. Thus, the resulting /// value is `None`. /// + /// Here is a variation on the previous example, showing that no + /// further elements are taken from `iter` after the first `None`. + /// + /// ``` + /// let items = vec![3_u16, 2, 1, 10]; + /// + /// let mut shared = 0; + /// + /// let res: Option> = items + /// .iter() + /// .map(|x| { shared += x; x.checked_sub(2) }) + /// .collect(); + /// + /// assert_eq!(res, None); + /// assert_eq!(shared, 6); + /// ``` + /// + /// Since the third element caused an underflow, no further elements were taken, + /// so the final value of `shared` is 6 (= `3 + 2 + 1`), not 16. + /// /// [`Iterator`]: ../iter/trait.Iterator.html #[inline] fn from_iter>>(iter: I) -> Option { @@ -1395,3 +1430,33 @@ impl ops::Try for Option { None } } + +impl Option> { + /// Converts from `Option>` to `Option` + /// + /// # Examples + /// Basic usage: + /// ``` + /// #![feature(option_flattening)] + /// let x: Option> = Some(Some(6)); + /// assert_eq!(Some(6), x.flatten()); + /// + /// let x: Option> = Some(None); + /// assert_eq!(None, x.flatten()); + /// + /// let x: Option> = None; + /// assert_eq!(None, x.flatten()); + /// ``` + /// Flattening once only removes one level of nesting: + /// ``` + /// #![feature(option_flattening)] + /// let x: Option>> = Some(Some(Some(6))); + /// assert_eq!(Some(Some(6)), x.flatten()); + /// assert_eq!(Some(6), x.flatten().flatten()); + /// ``` + #[inline] + #[unstable(feature = "option_flattening", issue = "60258")] + pub fn flatten(self) -> Option { + self.and_then(convert::identity) + } +} diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 1abc0a18a9cc9..989fc96732a5a 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -4,8 +4,8 @@ reason = "newly available in libcore", issue = "44489")] -use any::Any; -use fmt; +use crate::any::Any; +use crate::fmt; /// A struct providing information about a panic. /// @@ -86,7 +86,7 @@ impl<'a> PanicInfo<'a> { /// /// [`fmt::write`]: ../fmt/fn.write.html #[unstable(feature = "panic_info_message", issue = "44489")] - pub fn message(&self) -> Option<&fmt::Arguments> { + pub fn message(&self) -> Option<&fmt::Arguments<'_>> { self.message } @@ -115,7 +115,7 @@ impl<'a> PanicInfo<'a> { /// panic!("Normal panic"); /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn location(&self) -> Option<&Location> { + pub fn location(&self) -> Option<&Location<'_>> { // NOTE: If this is changed to sometimes return None, // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt. Some(&self.location) @@ -124,7 +124,7 @@ impl<'a> PanicInfo<'a> { #[stable(feature = "panic_hook_display", since = "1.26.0")] impl fmt::Display for PanicInfo<'_> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("panicked at ")?; if let Some(message) = self.message { write!(formatter, "'{}', ", message)? @@ -249,7 +249,7 @@ impl<'a> Location<'a> { #[stable(feature = "panic_hook_display", since = "1.26.0")] impl fmt::Display for Location<'_> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { write!(formatter, "{}:{}:{}", self.file, self.line, self.col) } } diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index d9cdb2a2b8a9f..15b7d69c58d24 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -26,8 +26,8 @@ and related macros", issue = "0")] -use fmt; -use panic::{Location, PanicInfo}; +use crate::fmt; +use crate::panic::{Location, PanicInfo}; #[cold] // never inline unless panic_immediate_abort to avoid code @@ -65,7 +65,7 @@ fn panic_bounds_check(file_line_col: &(&'static str, u32, u32), #[cold] #[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] #[cfg_attr( feature="panic_immediate_abort" ,inline)] -pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { +pub fn panic_fmt(fmt: fmt::Arguments<'_>, file_line_col: &(&'static str, u32, u32)) -> ! { if cfg!(feature = "panic_immediate_abort") { unsafe { super::intrinsics::abort() } } @@ -74,7 +74,7 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) #[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe extern "Rust" { #[lang = "panic_impl"] - fn panic_impl(pi: &PanicInfo) -> !; + fn panic_impl(pi: &PanicInfo<'_>) -> !; } let (file, line, col) = *file_line_col; diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index f9f20dcea9e2e..c063cee52270e 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -1,10 +1,10 @@ -//! Types which pin data to its location in memory +//! Types that pin data to its location in memory. //! -//! It is sometimes useful to have objects that are guaranteed to not move, +//! It is sometimes useful to have objects that are guaranteed not to move, //! in the sense that their placement in memory does not change, and can thus be relied upon. //! A prime example of such a scenario would be building self-referential structs, -//! since moving an object with pointers to itself will invalidate them, -//! which could cause undefined behavior. +//! as moving an object with pointers to itself will invalidate them, which could cause undefined +//! behavior. //! //! A [`Pin

`] ensures that the pointee of any pointer type `P` has a stable location in memory, //! meaning it cannot be moved elsewhere and its memory cannot be deallocated @@ -15,9 +15,10 @@ //! moving the values they contain: you can move out of a `Box`, or you can use [`mem::swap`]. //! [`Pin

`] wraps a pointer type `P`, so `Pin>` functions much like a regular `Box`: //! when a `Pin>` gets dropped, so do its contents, and the memory gets deallocated. -//! Similarily, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin

`] does not let clients +//! Similarly, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin

`] does not let clients //! actually obtain a `Box` or `&mut T` to pinned data, which implies that you cannot use //! operations such as [`mem::swap`]: +//! //! ``` //! use std::pin::Pin; //! fn swap_pins(x: Pin<&mut T>, y: Pin<&mut T>) { @@ -39,19 +40,19 @@ //! as a "`P`-style pointer" to a pinned `P::Target` -- so, a `Pin>` is //! an owned pointer to a pinned `T`, and a `Pin>` is a reference-counted //! pointer to a pinned `T`. -//! For correctness, [`Pin

`] relies on the [`Deref`] and [`DerefMut`] implementations -//! to not move out of their `self` parameter, and to only ever return a pointer -//! to pinned data when they are called on a pinned pointer. +//! For correctness, [`Pin

`] relies on the implementations of [`Deref`] and +//! [`DerefMut`] not to move out of their `self` parameter, and only ever to +//! return a pointer to pinned data when they are called on a pinned pointer. //! //! # `Unpin` //! -//! However, these restrictions are usually not necessary. Many types are always freely -//! movable, even when pinned, because they do not rely on having a stable address. -//! This includes all the basic types (like `bool`, `i32`, references) -//! as well as types consisting solely of these types. -//! Types that do not care about pinning implement the [`Unpin`] auto-trait, which -//! cancels the effect of [`Pin

`]. For `T: Unpin`, `Pin>` and `Box` function -//! identically, as do `Pin<&mut T>` and `&mut T`. +//! Many types are always freely movable, even when pinned, because they do not +//! rely on having a stable address. This includes all the basic types (like +//! `bool`, `i32`, and references) as well as types consisting solely of these +//! types. Types that do not care about pinning implement the [`Unpin`] +//! auto-trait, which cancels the effect of [`Pin

`]. For `T: Unpin`, +//! `Pin>` and `Box` function identically, as do `Pin<&mut T>` and +//! `&mut T`. //! //! Note that pinning and `Unpin` only affect the pointed-to type `P::Target`, not the pointer //! type `P` itself that got wrapped in `Pin

`. For example, whether or not `Box` is @@ -65,11 +66,11 @@ //! use std::marker::PhantomPinned; //! use std::ptr::NonNull; //! -//! // This is a self-referential struct since the slice field points to the data field. +//! // This is a self-referential struct because the slice field points to the data field. //! // We cannot inform the compiler about that with a normal reference, -//! // since this pattern cannot be described with the usual borrowing rules. -//! // Instead we use a raw pointer, though one which is known to not be null, -//! // since we know it's pointing at the string. +//! // as this pattern cannot be described with the usual borrowing rules. +//! // Instead we use a raw pointer, though one which is known not to be null, +//! // as we know it's pointing at the string. //! struct Unmovable { //! data: String, //! slice: NonNull, @@ -109,7 +110,7 @@ //! assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data)); //! //! // Since our type doesn't implement Unpin, this will fail to compile: -//! // let new_unmoved = Unmovable::new("world".to_string()); +//! // let mut new_unmoved = Unmovable::new("world".to_string()); //! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved); //! ``` //! @@ -137,16 +138,17 @@ //! To make this work, not just moving the data is restricted; deallocating, repurposing, or //! otherwise invalidating the memory used to store the data is restricted, too. //! Concretely, for pinned data you have to maintain the invariant -//! that *its memory will not get invalidated from the moment it gets pinned until +//! that *its memory will not get invalidated or repurposed from the moment it gets pinned until //! when `drop` is called*. Memory can be invalidated by deallocation, but also by //! replacing a [`Some(v)`] by [`None`], or calling [`Vec::set_len`] to "kill" some elements -//! off of a vector. +//! off of a vector. It can be repurposed by using [`ptr::write`] to overwrite it without +//! calling the destructor first. //! //! This is exactly the kind of guarantee that the intrusive linked list from the previous //! section needs to function correctly. //! //! Notice that this guarantee does *not* mean that memory does not leak! It is still -//! completely okay not to ever call `drop` on a pinned element (e.g., you can still +//! completely okay not ever to call `drop` on a pinned element (e.g., you can still //! call [`mem::forget`] on a `Pin>`). In the example of the doubly-linked //! list, that element would just stay in the list. However you may not free or reuse the storage //! *without calling `drop`*. @@ -158,64 +160,141 @@ //! is called *even if your type was previously pinned*! It is as if the //! compiler automatically called `get_unchecked_mut`. //! -//! This can never cause a problem in safe code because implementing a type that relies on pinning -//! requires unsafe code, but be aware that deciding to make use of pinning -//! in your type (for example by implementing some operation on `Pin<&[mut] Self>`) -//! has consequences for your `Drop` implementation as well: if an element -//! of your type could have been pinned, you must treat Drop as implicitly taking -//! `Pin<&mut Self>`. +//! This can never cause a problem in safe code because implementing a type that +//! relies on pinning requires unsafe code, but be aware that deciding to make +//! use of pinning in your type (for example by implementing some operation on +//! `Pin<&Self>` or `Pin<&mut Self>`) has consequences for your `Drop` +//! implementation as well: if an element of your type could have been pinned, +//! you must treat Drop as implicitly taking `Pin<&mut Self>`. +//! +//! For example, you could implement `Drop` as follows: +//! ```rust,no_run +//! # use std::pin::Pin; +//! # struct Type { } +//! impl Drop for Type { +//! fn drop(&mut self) { +//! // `new_unchecked` is okay because we know this value is never used +//! // again after being dropped. +//! inner_drop(unsafe { Pin::new_unchecked(self)}); +//! fn inner_drop(this: Pin<&mut Type>) { +//! // Actual drop code goes here. +//! } +//! } +//! } +//! ``` +//! The function `inner_drop` has the type that `drop` *should* have, so this makes sure that +//! you do not accidentally use `self`/`this` in a way that is in conflict with pinning. //! -//! In particular, if your type is `#[repr(packed)]`, the compiler will automatically +//! Moreover, if your type is `#[repr(packed)]`, the compiler will automatically //! move fields around to be able to drop them. As a consequence, you cannot use //! pinning with a `#[repr(packed)]` type. //! //! # Projections and Structural Pinning //! -//! One interesting question arises when considering the interaction of pinning and -//! the fields of a struct. When can a struct have a "pinning projection", i.e., -//! an operation with type `fn(Pin<&[mut] Struct>) -> Pin<&[mut] Field>`? -//! In a similar vein, when can a generic wrapper type (such as `Vec`, `Box`, or `RefCell`) -//! have an operation with type `fn(Pin<&[mut] Wrapper>) -> Pin<&[mut] T>`? +//! When working with pinned structs, the question arises how one can access the +//! fields of that struct in a method that takes just `Pin<&mut Struct>`. +//! The usual approach is to write helper methods (so called *projections*) +//! that turn `Pin<&mut Struct>` into a reference to the field, but what +//! type should that reference have? Is it `Pin<&mut Field>` or `&mut Field`? +//! The same question arises with the fields of an `enum`, and also when considering +//! container/wrapper types such as [`Vec`], [`Box`], or [`RefCell`]. +//! (This question applies to both mutable and shared references, we just +//! use the more common case of mutable references here for illustration.) +//! +//! It turns out that it is actually up to the author of the data structure +//! to decide whether the pinned projection for a particular field turns +//! `Pin<&mut Struct>` into `Pin<&mut Field>` or `&mut Field`. There are some +//! constraints though, and the most important constraint is *consistency*: +//! every field can be *either* projected to a pinned reference, *or* have +//! pinning removed as part of the projection. If both are done for the same field, +//! that will likely be unsound! +//! +//! As the author of a data structure you get to decide for each field whether pinning +//! "propagates" to this field or not. Pinning that propagates is also called "structural", +//! because it follows the structure of the type. +//! In the following subsections, we describe the considerations that have to be made +//! for either choice. +//! +//! ## Pinning *is not* structural for `field` +//! +//! It may seem counter-intuitive that the field of a pinned struct might not be pinned, +//! but that is actually the easiest choice: if a `Pin<&mut Field>` is never created, +//! nothing can go wrong! So, if you decide that some field does not have structural pinning, +//! all you have to ensure is that you never create a pinned reference to that field. +//! +//! Fields without structural pinning may have a projection method that turns +//! `Pin<&mut Struct>` into `&mut Field`: +//! ```rust,no_run +//! # use std::pin::Pin; +//! # type Field = i32; +//! # struct Struct { field: Field } +//! impl Struct { +//! fn pin_get_field<'a>(self: Pin<&'a mut Self>) -> &'a mut Field { +//! // This is okay because `field` is never considered pinned. +//! unsafe { &mut self.get_unchecked_mut().field } +//! } +//! } +//! ``` //! -//! Having a pinning projection for some field means that pinning is "structural": -//! when the wrapper is pinned, the field must be considered pinned, too. -//! After all, the pinning projection lets us get a `Pin<&[mut] Field>`. +//! You may also `impl Unpin for Struct` *even if* the type of `field` +//! is not `Unpin`. What that type thinks about pinning is not relevant +//! when no `Pin<&mut Field>` is ever created. +//! +//! ## Pinning *is* structural for `field` +//! +//! The other option is to decide that pinning is "structural" for `field`, +//! meaning that if the struct is pinned then so is the field. +//! +//! This allows writing a projection that creates a `Pin<&mut Field>`, thus +//! witnessing that the field is pinned: +//! ```rust,no_run +//! # use std::pin::Pin; +//! # type Field = i32; +//! # struct Struct { field: Field } +//! impl Struct { +//! fn pin_get_field<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut Field> { +//! // This is okay because `field` is pinned when `self` is. +//! unsafe { self.map_unchecked_mut(|s| &mut s.field) } +//! } +//! } +//! ``` //! -//! However, structural pinning comes with a few extra requirements, so not all -//! wrappers can be structural and hence not all wrappers can offer pinning projections: +//! However, structural pinning comes with a few extra requirements: //! -//! 1. The wrapper must only be [`Unpin`] if all the structural fields are +//! 1. The struct must only be [`Unpin`] if all the structural fields are //! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of -//! the wrapper it is your responsibility *not* to add something like -//! `impl Unpin for Wrapper`. (Notice that adding a projection operation -//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break +//! the struct it is your responsibility *not* to add something like +//! `impl Unpin for Struct`. (Notice that adding a projection operation +//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break //! the principle that you only have to worry about any of this if you use `unsafe`.) -//! 2. The destructor of the wrapper must not move structural fields out of its argument. This +//! 2. The destructor of the struct must not move structural fields out of its argument. This //! is the exact point that was raised in the [previous section][drop-impl]: `drop` takes -//! `&mut self`, but the wrapper (and hence its fields) might have been pinned before. +//! `&mut self`, but the struct (and hence its fields) might have been pinned before. //! You have to guarantee that you do not move a field inside your `Drop` implementation. -//! In particular, as explained previously, this means that your wrapper type must *not* +//! In particular, as explained previously, this means that your struct must *not* //! be `#[repr(packed)]`. +//! See that section for how to write `drop` in a way that the compiler can help you +//! not accidentally break pinning. //! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: -//! once your wrapper is pinned, the memory that contains the +//! once your struct is pinned, the memory that contains the //! content is not overwritten or deallocated without calling the content's destructors. -//! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail -//! to call `drop` on all elements if one of the destructors panics. This violates the +//! This can be tricky, as witnessed by [`VecDeque`]: the destructor of `VecDeque` +//! can fail to call `drop` on all elements if one of the destructors panics. This violates the //! `Drop` guarantee, because it can lead to elements being deallocated without //! their destructor being called. (`VecDeque` has no pinning projections, so this //! does not cause unsoundness.) //! 4. You must not offer any other operations that could lead to data being moved out of -//! the fields when your type is pinned. For example, if the wrapper contains an +//! the structural fields when your type is pinned. For example, if the struct contains an //! `Option` and there is a `take`-like operation with type -//! `fn(Pin<&mut Wrapper>) -> Option`, -//! that operation can be used to move a `T` out of a pinned `Wrapper` -- which means -//! pinning cannot be structural. +//! `fn(Pin<&mut Struct>) -> Option`, +//! that operation can be used to move a `T` out of a pinned `Struct` -- which means +//! pinning cannot be structural for the field holding this data. //! -//! For a more complex example of moving data out of a pinned type, imagine if `RefCell` +//! For a more complex example of moving data out of a pinned type, imagine if [`RefCell`] //! had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`. //! Then we could do the following: //! ```compile_fail -//! fn exploit_ref_cell(rc: Pin<&mut RefCell) { +//! fn exploit_ref_cell(rc: Pin<&mut RefCell>) { //! { let p = rc.as_mut().get_pin_mut(); } // Here we get pinned access to the `T`. //! let rc_shr: &RefCell = rc.into_ref().get_ref(); //! let b = rc_shr.borrow_mut(); @@ -226,13 +305,16 @@ //! (using `RefCell::get_pin_mut`) and then move that content using the mutable //! reference we got later. //! -//! For a type like `Vec`, both possibilites (structural pinning or not) make sense, -//! and the choice is up to the author. A `Vec` with structural pinning could -//! have `get_pin`/`get_pin_mut` projections. However, it could *not* allow calling +//! ## Examples +//! +//! For a type like [`Vec`], both possibilites (structural pinning or not) make sense. +//! A `Vec` with structural pinning could have `get_pin`/`get_pin_mut` methods to get +//! pinned references to elements. However, it could *not* allow calling //! `pop` on a pinned `Vec` because that would move the (structurally pinned) contents! //! Nor could it allow `push`, which might reallocate and thus also move the contents. //! A `Vec` without structural pinning could `impl Unpin for Vec`, because the contents //! are never pinned and the `Vec` itself is fine with being moved as well. +//! At that point pinning just has no effect on the vector at all. //! //! In the standard library, pointer types generally do not have structural pinning, //! and thus they do not offer pinning projections. This is why `Box: Unpin` holds for all `T`. @@ -244,25 +326,37 @@ //! whether the content is pinned is entirely independent of whether the pointer is //! pinned, meaning pinning is *not* structural. //! +//! When implementing a [`Future`] combinator, you will usually need structural pinning +//! for the nested futures, as you need to get pinned references to them to call `poll`. +//! But if your combinator contains any other data that does not need to be pinned, +//! you can make those fields not structural and hence freely access them with a +//! mutable reference even when you just have `Pin<&mut Self>` (such as in your own +//! `poll` implementation). +//! //! [`Pin

`]: struct.Pin.html -//! [`Unpin`]: ../../std/marker/trait.Unpin.html -//! [`Deref`]: ../../std/ops/trait.Deref.html -//! [`DerefMut`]: ../../std/ops/trait.DerefMut.html -//! [`mem::swap`]: ../../std/mem/fn.swap.html -//! [`mem::forget`]: ../../std/mem/fn.forget.html +//! [`Unpin`]: ../marker/trait.Unpin.html +//! [`Deref`]: ../ops/trait.Deref.html +//! [`DerefMut`]: ../ops/trait.DerefMut.html +//! [`mem::swap`]: ../mem/fn.swap.html +//! [`mem::forget`]: ../mem/fn.forget.html //! [`Box`]: ../../std/boxed/struct.Box.html +//! [`Vec`]: ../../std/vec/struct.Vec.html //! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len -//! [`None`]: ../../std/option/enum.Option.html#variant.None -//! [`Some(v)`]: ../../std/option/enum.Option.html#variant.Some +//! [`VecDeque`]: ../../std/collections/struct.VecDeque.html +//! [`RefCell`]: ../cell/struct.RefCell.html +//! [`None`]: ../option/enum.Option.html#variant.None +//! [`Some(v)`]: ../option/enum.Option.html#variant.Some +//! [`ptr::write`]: ../ptr/fn.write.html +//! [`Future`]: ../future/trait.Future.html //! [drop-impl]: #drop-implementation //! [drop-guarantee]: #drop-guarantee #![stable(feature = "pin", since = "1.33.0")] -use fmt; -use marker::{Sized, Unpin}; -use cmp::{self, PartialEq, PartialOrd}; -use ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn}; +use crate::fmt; +use crate::marker::{Sized, Unpin}; +use crate::cmp::{self, PartialEq, PartialOrd}; +use crate::ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn}; /// A pinned pointer. /// @@ -270,7 +364,7 @@ use ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn}; /// value in place, preventing the value referenced by that pointer from being moved /// unless it implements [`Unpin`]. /// -/// See the [`pin` module] documentation for further explanation on pinning. +/// *See the [`pin` module] documentation for an explanation of pinning.* /// /// [`Unpin`]: ../../std/marker/trait.Unpin.html /// [`pin` module]: ../../std/pin/index.html @@ -279,7 +373,7 @@ use ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn}; // implementations, are allowed because they all only use `&P`, so they cannot move // the value behind `pointer`. #[stable(feature = "pin", since = "1.33.0")] -#[cfg_attr(not(stage0), lang = "pin")] +#[lang = "pin"] #[fundamental] #[repr(transparent)] #[derive(Copy, Clone, Hash, Eq, Ord)] @@ -345,6 +439,18 @@ where // around pinning. unsafe { Pin::new_unchecked(pointer) } } + + /// Unwraps this `Pin

` returning the underlying pointer. + /// + /// This requires that the data inside this `Pin` is [`Unpin`] so that we + /// can ignore the pinning invariants when unwrapping it. + /// + /// [`Unpin`]: ../../std/marker/trait.Unpin.html + #[unstable(feature = "pin_into_inner", issue = "60245")] + #[inline(always)] + pub fn into_inner(pin: Pin

) -> P { + pin.pointer + } } impl Pin

{ @@ -430,6 +536,28 @@ impl Pin

{ pub fn as_ref(self: &Pin

) -> Pin<&P::Target> { unsafe { Pin::new_unchecked(&*self.pointer) } } + + /// Unwraps this `Pin

` returning the underlying pointer. + /// + /// # Safety + /// + /// This function is unsafe. You must guarantee that you will continue to + /// treat the pointer `P` as pinned after you call this function, so that + /// the invariants on the `Pin` type can be upheld. If the code using the + /// resulting `P` does not continue to maintain the pinning invariants that + /// is a violation of the API contract and may lead to undefined behavior in + /// later (safe) operations. + /// + /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used + /// instead. + /// + /// [`Unpin`]: ../../std/marker/trait.Unpin.html + /// [`Pin::into_inner`]: #method.into_inner + #[unstable(feature = "pin_into_inner", issue = "60245")] + #[inline(always)] + pub unsafe fn into_inner_unchecked(pin: Pin

) -> P { + pin.pointer + } } impl Pin

{ @@ -598,21 +726,21 @@ impl Receiver for Pin

{} #[stable(feature = "pin", since = "1.33.0")] impl fmt::Debug for Pin

{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.pointer, f) } } #[stable(feature = "pin", since = "1.33.0")] impl fmt::Display for Pin

{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.pointer, f) } } #[stable(feature = "pin", since = "1.33.0")] impl fmt::Pointer for Pin

{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Pointer::fmt(&self.pointer, f) } } diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index b53494edbf401..501a41d0d1c76 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -9,38 +9,38 @@ // Re-exported core operators #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] -pub use marker::{Copy, Send, Sized, Sync, Unpin}; +pub use crate::marker::{Copy, Send, Sized, Sync, Unpin}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] -pub use ops::{Drop, Fn, FnMut, FnOnce}; +pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; // Re-exported functions #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] -pub use mem::drop; +pub use crate::mem::drop; // Re-exported types and traits #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] -pub use clone::Clone; +pub use crate::clone::Clone; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] -pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; +pub use crate::cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] -pub use convert::{AsRef, AsMut, Into, From}; +pub use crate::convert::{AsRef, AsMut, Into, From}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] -pub use default::Default; +pub use crate::default::Default; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] -pub use iter::{Iterator, Extend, IntoIterator}; +pub use crate::iter::{Iterator, Extend, IntoIterator}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] -pub use iter::{DoubleEndedIterator, ExactSizeIterator}; +pub use crate::iter::{DoubleEndedIterator, ExactSizeIterator}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] -pub use option::Option::{self, Some, None}; +pub use crate::option::Option::{self, Some, None}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] -pub use result::Result::{self, Ok, Err}; +pub use crate::result::Result::{self, Ok, Err}; diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs deleted file mode 100644 index 866c8d0896b3c..0000000000000 --- a/src/libcore/ptr.rs +++ /dev/null @@ -1,3063 +0,0 @@ -//! Manually manage memory through raw pointers. -//! -//! *[See also the pointer primitive types](../../std/primitive.pointer.html).* -//! -//! # Safety -//! -//! Many functions in this module take raw pointers as arguments and read from -//! or write to them. For this to be safe, these pointers must be *valid*. -//! Whether a pointer is valid depends on the operation it is used for -//! (read or write), and the extent of the memory that is accessed (i.e., -//! how many bytes are read/written). Most functions use `*mut T` and `*const T` -//! to access only a single value, in which case the documentation omits the size -//! and implicitly assumes it to be `size_of::()` bytes. -//! -//! The precise rules for validity are not determined yet. The guarantees that are -//! provided at this point are very minimal: -//! -//! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst]. -//! * All pointers (except for the null pointer) are valid for all operations of -//! [size zero][zst]. -//! * All accesses performed by functions in this module are *non-atomic* in the sense -//! of [atomic operations] used to synchronize between threads. This means it is -//! undefined behavior to perform two concurrent accesses to the same location from different -//! threads unless both accesses only read from memory. Notice that this explicitly -//! includes [`read_volatile`] and [`write_volatile`]: Volatile accesses cannot -//! be used for inter-thread synchronization. -//! * The result of casting a reference to a pointer is valid for as long as the -//! underlying object is live and no reference (just raw pointers) is used to -//! access the same memory. -//! -//! These axioms, along with careful use of [`offset`] for pointer arithmetic, -//! are enough to correctly implement many useful things in unsafe code. Stronger guarantees -//! will be provided eventually, as the [aliasing] rules are being determined. For more -//! information, see the [book] as well as the section in the reference devoted -//! to [undefined behavior][ub]. -//! -//! ## Alignment -//! -//! Valid raw pointers as defined above are not necessarily properly aligned (where -//! "proper" alignment is defined by the pointee type, i.e., `*const T` must be -//! aligned to `mem::align_of::()`). However, most functions require their -//! arguments to be properly aligned, and will explicitly state -//! this requirement in their documentation. Notable exceptions to this are -//! [`read_unaligned`] and [`write_unaligned`]. -//! -//! When a function requires proper alignment, it does so even if the access -//! has size 0, i.e., even if memory is not actually touched. Consider using -//! [`NonNull::dangling`] in such cases. -//! -//! [aliasing]: ../../nomicon/aliasing.html -//! [book]: ../../book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer -//! [ub]: ../../reference/behavior-considered-undefined.html -//! [null]: ./fn.null.html -//! [zst]: ../../nomicon/exotic-sizes.html#zero-sized-types-zsts -//! [atomic operations]: ../../std/sync/atomic/index.html -//! [`copy`]: ../../std/ptr/fn.copy.html -//! [`offset`]: ../../std/primitive.pointer.html#method.offset -//! [`read_unaligned`]: ./fn.read_unaligned.html -//! [`write_unaligned`]: ./fn.write_unaligned.html -//! [`read_volatile`]: ./fn.read_volatile.html -//! [`write_volatile`]: ./fn.write_volatile.html -//! [`NonNull::dangling`]: ./struct.NonNull.html#method.dangling - -#![stable(feature = "rust1", since = "1.0.0")] - -use convert::From; -use intrinsics; -use ops::{CoerceUnsized, DispatchFromDyn}; -use fmt; -use hash; -use marker::{PhantomData, Unsize}; -use mem::{self, MaybeUninit}; - -use cmp::Ordering::{self, Less, Equal, Greater}; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use intrinsics::copy_nonoverlapping; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use intrinsics::copy; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use intrinsics::write_bytes; - -/// Executes the destructor (if any) of the pointed-to value. -/// -/// This is semantically equivalent to calling [`ptr::read`] and discarding -/// the result, but has the following advantages: -/// -/// * It is *required* to use `drop_in_place` to drop unsized types like -/// trait objects, because they can't be read out onto the stack and -/// dropped normally. -/// -/// * It is friendlier to the optimizer to do this over [`ptr::read`] when -/// dropping manually allocated memory (e.g., when writing Box/Rc/Vec), -/// as the compiler doesn't need to prove that it's sound to elide the -/// copy. -/// -/// [`ptr::read`]: ../ptr/fn.read.html -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `to_drop` must be [valid] for reads. -/// -/// * `to_drop` must be properly aligned. See the example below for how to drop -/// an unaligned pointer. -/// -/// Additionally, if `T` is not [`Copy`], using the pointed-to value after -/// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop = -/// foo` counts as a use because it will cause the value to be dropped -/// again. [`write`] can be used to overwrite data without causing it to be -/// dropped. -/// -/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. -/// -/// [valid]: ../ptr/index.html#safety -/// [`Copy`]: ../marker/trait.Copy.html -/// [`write`]: ../ptr/fn.write.html -/// -/// # Examples -/// -/// Manually remove the last item from a vector: -/// -/// ``` -/// use std::ptr; -/// use std::rc::Rc; -/// -/// let last = Rc::new(1); -/// let weak = Rc::downgrade(&last); -/// -/// let mut v = vec![Rc::new(0), last]; -/// -/// unsafe { -/// // Get a raw pointer to the last element in `v`. -/// let ptr = &mut v[1] as *mut _; -/// // Shorten `v` to prevent the last item from being dropped. We do that first, -/// // to prevent issues if the `drop_in_place` below panics. -/// v.set_len(1); -/// // Without a call `drop_in_place`, the last item would never be dropped, -/// // and the memory it manages would be leaked. -/// ptr::drop_in_place(ptr); -/// } -/// -/// assert_eq!(v, &[0.into()]); -/// -/// // Ensure that the last item was dropped. -/// 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; -/// -/// unsafe fn drop_after_copy(to_drop: *mut T) { -/// let mut copy: T = mem::uninitialized(); -/// ptr::copy(to_drop, &mut copy, 1); -/// drop(copy); -/// } -/// -/// #[repr(packed, C)] -/// struct Packed { -/// _padding: u8, -/// unaligned: Vec, -/// } -/// -/// 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. -#[stable(feature = "drop_in_place", since = "1.8.0")] -#[inline(always)] -pub unsafe fn drop_in_place(to_drop: *mut T) { - real_drop_in_place(&mut *to_drop) -} - -// The real `drop_in_place` -- the one that gets called implicitly when variables go -// out of scope -- should have a safe reference and not a raw pointer as argument -// type. When we drop a local variable, we access it with a pointer that behaves -// like a safe reference; transmuting that to a raw pointer does not mean we can -// actually access it with raw pointers. -#[lang = "drop_in_place"] -#[allow(unconditional_recursion)] -unsafe fn real_drop_in_place(to_drop: &mut T) { - // Code here does not matter - this is replaced by the - // real drop glue by the compiler. - real_drop_in_place(to_drop) -} - -/// Creates a null raw pointer. -/// -/// # Examples -/// -/// ``` -/// use std::ptr; -/// -/// let p: *const i32 = ptr::null(); -/// assert!(p.is_null()); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_promotable] -pub const fn null() -> *const T { 0 as *const T } - -/// Creates a null mutable raw pointer. -/// -/// # Examples -/// -/// ``` -/// use std::ptr; -/// -/// let p: *mut i32 = ptr::null_mut(); -/// assert!(p.is_null()); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_promotable] -pub const fn null_mut() -> *mut T { 0 as *mut T } - -/// Swaps the values at two mutable locations of the same type, without -/// deinitializing either. -/// -/// But for the following two exceptions, this function is semantically -/// equivalent to [`mem::swap`]: -/// -/// * It operates on raw pointers instead of references. When references are -/// available, [`mem::swap`] should be preferred. -/// -/// * The two pointed-to values may overlap. If the values do overlap, then the -/// overlapping region of memory from `x` will be used. This is demonstrated -/// in the second example below. -/// -/// [`mem::swap`]: ../mem/fn.swap.html -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * Both `x` and `y` must be [valid] for reads and writes. -/// -/// * Both `x` and `y` must be properly aligned. -/// -/// Note that even if `T` has size `0`, the pointers must be non-NULL and properly aligned. -/// -/// [valid]: ../ptr/index.html#safety -/// -/// # Examples -/// -/// Swapping two non-overlapping regions: -/// -/// ``` -/// use std::ptr; -/// -/// let mut array = [0, 1, 2, 3]; -/// -/// let x = array[0..].as_mut_ptr() as *mut [u32; 2]; // this is `array[0..2]` -/// let y = array[2..].as_mut_ptr() as *mut [u32; 2]; // this is `array[2..4]` -/// -/// unsafe { -/// ptr::swap(x, y); -/// assert_eq!([2, 3, 0, 1], array); -/// } -/// ``` -/// -/// Swapping two overlapping regions: -/// -/// ``` -/// use std::ptr; -/// -/// let mut array = [0, 1, 2, 3]; -/// -/// let x = array[0..].as_mut_ptr() as *mut [u32; 3]; // this is `array[0..3]` -/// let y = array[1..].as_mut_ptr() as *mut [u32; 3]; // this is `array[1..4]` -/// -/// unsafe { -/// ptr::swap(x, y); -/// // The indices `1..3` of the slice overlap between `x` and `y`. -/// // Reasonable results would be for to them be `[2, 3]`, so that indices `0..3` are -/// // `[1, 2, 3]` (matching `y` before the `swap`); or for them to be `[0, 1]` -/// // so that indices `1..4` are `[0, 1, 2]` (matching `x` before the `swap`). -/// // This implementation is defined to make the latter choice. -/// assert_eq!([1, 0, 1, 2], array); -/// } -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn swap(x: *mut T, y: *mut T) { - // Give ourselves some scratch space to work with. - // We do not have to worry about drops: `MaybeUninit` does nothing when dropped. - let mut tmp = MaybeUninit::::uninitialized(); - - // Perform the swap - copy_nonoverlapping(x, tmp.as_mut_ptr(), 1); - copy(y, x, 1); // `x` and `y` may overlap - copy_nonoverlapping(tmp.get_ref(), y, 1); -} - -/// Swaps `count * size_of::()` bytes between the two regions of memory -/// beginning at `x` and `y`. The two regions must *not* overlap. -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * Both `x` and `y` must be [valid] for reads and writes of `count * -/// size_of::()` bytes. -/// -/// * Both `x` and `y` must be properly aligned. -/// -/// * The region of memory beginning at `x` with a size of `count * -/// size_of::()` bytes must *not* overlap with the region of memory -/// beginning at `y` with the same size. -/// -/// Note that even if the effectively copied size (`count * size_of::()`) is `0`, -/// the pointers must be non-NULL and properly aligned. -/// -/// [valid]: ../ptr/index.html#safety -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::ptr; -/// -/// let mut x = [1, 2, 3, 4]; -/// let mut y = [7, 8, 9]; -/// -/// unsafe { -/// ptr::swap_nonoverlapping(x.as_mut_ptr(), y.as_mut_ptr(), 2); -/// } -/// -/// assert_eq!(x, [7, 8, 3, 4]); -/// assert_eq!(y, [1, 2, 9]); -/// ``` -#[inline] -#[stable(feature = "swap_nonoverlapping", since = "1.27.0")] -pub unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { - let x = x as *mut u8; - let y = y as *mut u8; - let len = mem::size_of::() * count; - swap_nonoverlapping_bytes(x, y, len) -} - -#[inline] -pub(crate) unsafe fn swap_nonoverlapping_one(x: *mut T, y: *mut T) { - // For types smaller than the block optimization below, - // just swap directly to avoid pessimizing codegen. - if mem::size_of::() < 32 { - let z = read(x); - copy_nonoverlapping(y, x, 1); - write(y, z); - } else { - swap_nonoverlapping(x, y, 1); - } -} - -#[inline] -unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { - // The approach here is to utilize simd to swap x & y efficiently. Testing reveals - // that swapping either 32 bytes or 64 bytes at a time is most efficient for Intel - // Haswell E processors. LLVM is more able to optimize if we give a struct a - // #[repr(simd)], even if we don't actually use this struct directly. - // - // FIXME repr(simd) broken on emscripten and redox - // It's also broken on big-endian powerpc64 and s390x. #42778 - #[cfg_attr(not(any(target_os = "emscripten", target_os = "redox", - target_endian = "big")), - repr(simd))] - struct Block(u64, u64, u64, u64); - struct UnalignedBlock(u64, u64, u64, u64); - - let block_size = mem::size_of::(); - - // Loop through x & y, copying them `Block` at a time - // The optimizer should unroll the loop fully for most types - // N.B. We can't use a for loop as the `range` impl calls `mem::swap` recursively - let mut i = 0; - while i + block_size <= len { - // Create some uninitialized memory as scratch space - // Declaring `t` here avoids aligning the stack when this loop is unused - let mut t = mem::MaybeUninit::::uninitialized(); - let t = t.as_mut_ptr() as *mut u8; - let x = x.add(i); - let y = y.add(i); - - // Swap a block of bytes of x & y, using t as a temporary buffer - // This should be optimized into efficient SIMD operations where available - copy_nonoverlapping(x, t, block_size); - copy_nonoverlapping(y, x, block_size); - copy_nonoverlapping(t, y, block_size); - i += block_size; - } - - if i < len { - // Swap any remaining bytes - let mut t = mem::MaybeUninit::::uninitialized(); - let rem = len - i; - - let t = t.as_mut_ptr() as *mut u8; - let x = x.add(i); - let y = y.add(i); - - copy_nonoverlapping(x, t, rem); - copy_nonoverlapping(y, x, rem); - copy_nonoverlapping(t, y, rem); - } -} - -/// Moves `src` into the pointed `dst`, returning the previous `dst` value. -/// -/// Neither value is dropped. -/// -/// This function is semantically equivalent to [`mem::replace`] except that it -/// operates on raw pointers instead of references. When references are -/// available, [`mem::replace`] should be preferred. -/// -/// [`mem::replace`]: ../mem/fn.replace.html -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `dst` must be [valid] for writes. -/// -/// * `dst` must be properly aligned. -/// -/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. -/// -/// [valid]: ../ptr/index.html#safety -/// -/// # Examples -/// -/// ``` -/// use std::ptr; -/// -/// let mut rust = vec!['b', 'u', 's', 't']; -/// -/// // `mem::replace` would have the same effect without requiring the unsafe -/// // block. -/// let b = unsafe { -/// ptr::replace(&mut rust[0], 'r') -/// }; -/// -/// assert_eq!(b, 'b'); -/// assert_eq!(rust, &['r', 'u', 's', 't']); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn replace(dst: *mut T, mut src: T) -> T { - mem::swap(&mut *dst, &mut src); // cannot overlap - src -} - -/// Reads the value from `src` without moving it. This leaves the -/// memory in `src` unchanged. -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `src` must be [valid] for reads. -/// -/// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the -/// case. -/// -/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// let x = 12; -/// let y = &x as *const i32; -/// -/// unsafe { -/// assert_eq!(std::ptr::read(y), 12); -/// } -/// ``` -/// -/// Manually implement [`mem::swap`]: -/// -/// ``` -/// use std::ptr; -/// -/// fn swap(a: &mut T, b: &mut T) { -/// unsafe { -/// // Create a bitwise copy of the value at `a` in `tmp`. -/// let tmp = ptr::read(a); -/// -/// // Exiting at this point (either by explicitly returning or by -/// // calling a function which panics) would cause the value in `tmp` to -/// // be dropped while the same value is still referenced by `a`. This -/// // could trigger undefined behavior if `T` is not `Copy`. -/// -/// // Create a bitwise copy of the value at `b` in `a`. -/// // This is safe because mutable references cannot alias. -/// ptr::copy_nonoverlapping(b, a, 1); -/// -/// // As above, exiting here could trigger undefined behavior because -/// // the same value is referenced by `a` and `b`. -/// -/// // Move `tmp` into `b`. -/// ptr::write(b, tmp); -/// -/// // `tmp` has been moved (`write` takes ownership of its second argument), -/// // so nothing is dropped implicitly here. -/// } -/// } -/// -/// let mut foo = "foo".to_owned(); -/// let mut bar = "bar".to_owned(); -/// -/// swap(&mut foo, &mut bar); -/// -/// assert_eq!(foo, "bar"); -/// assert_eq!(bar, "foo"); -/// ``` -/// -/// ## Ownership of the Returned Value -/// -/// `read` creates a bitwise copy of `T`, regardless of whether `T` is [`Copy`]. -/// If `T` is not [`Copy`], using both the returned value and the value at -/// `*src` can violate memory safety. Note that assigning to `*src` counts as a -/// use because it will attempt to drop the value at `*src`. -/// -/// [`write`] can be used to overwrite data without causing it to be dropped. -/// -/// ``` -/// use std::ptr; -/// -/// let mut s = String::from("foo"); -/// unsafe { -/// // `s2` now points to the same underlying memory as `s`. -/// let mut s2: String = ptr::read(&s); -/// -/// assert_eq!(s2, "foo"); -/// -/// // Assigning to `s2` causes its original value to be dropped. Beyond -/// // this point, `s` must no longer be used, as the underlying memory has -/// // been freed. -/// s2 = String::default(); -/// assert_eq!(s2, ""); -/// -/// // Assigning to `s` would cause the old value to be dropped again, -/// // resulting in undefined behavior. -/// // s = String::from("bar"); // ERROR -/// -/// // `ptr::write` can be used to overwrite a value without dropping it. -/// ptr::write(&mut s, String::from("bar")); -/// } -/// -/// assert_eq!(s, "bar"); -/// ``` -/// -/// [`mem::swap`]: ../mem/fn.swap.html -/// [valid]: ../ptr/index.html#safety -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read_unaligned`]: ./fn.read_unaligned.html -/// [`write`]: ./fn.write.html -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn read(src: *const T) -> T { - let mut tmp = MaybeUninit::::uninitialized(); - copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); - tmp.into_initialized() -} - -/// Reads the value from `src` without moving it. This leaves the -/// memory in `src` unchanged. -/// -/// Unlike [`read`], `read_unaligned` works with unaligned pointers. -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `src` must be [valid] for reads. -/// -/// Like [`read`], `read_unaligned` creates a bitwise copy of `T`, regardless of -/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned -/// value and the value at `*src` can [violate memory safety][read-ownership]. -/// -/// Note that even if `T` has size `0`, the pointer must be non-NULL. -/// -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read`]: ./fn.read.html -/// [`write_unaligned`]: ./fn.write_unaligned.html -/// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value -/// [valid]: ../ptr/index.html#safety -/// -/// # Examples -/// -/// Access members of a packed struct by reference: -/// -/// ``` -/// use std::ptr; -/// -/// #[repr(packed, C)] -/// struct Packed { -/// _padding: u8, -/// unaligned: u32, -/// } -/// -/// let x = Packed { -/// _padding: 0x00, -/// unaligned: 0x01020304, -/// }; -/// -/// let v = unsafe { -/// // Take the address of a 32-bit integer which is not aligned. -/// // This must be done as a raw pointer; unaligned references are invalid. -/// let unaligned = &x.unaligned as *const u32; -/// -/// // Dereferencing normally will emit an aligned load instruction, -/// // causing undefined behavior. -/// // let v = *unaligned; // ERROR -/// -/// // Instead, use `read_unaligned` to read improperly aligned values. -/// let v = ptr::read_unaligned(unaligned); -/// -/// v -/// }; -/// -/// // Accessing unaligned values directly is safe. -/// assert!(x.unaligned == v); -/// ``` -#[inline] -#[stable(feature = "ptr_unaligned", since = "1.17.0")] -pub unsafe fn read_unaligned(src: *const T) -> T { - let mut tmp = MaybeUninit::::uninitialized(); - copy_nonoverlapping(src as *const u8, - tmp.as_mut_ptr() as *mut u8, - mem::size_of::()); - tmp.into_initialized() -} - -/// Overwrites a memory location with the given value without reading or -/// dropping the old value. -/// -/// `write` does not drop the contents of `dst`. This is safe, but it could leak -/// allocations or resources, so care should be taken not to overwrite an object -/// that should be dropped. -/// -/// Additionally, it does not drop `src`. Semantically, `src` is moved into the -/// location pointed to by `dst`. -/// -/// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been [`read`] from. -/// -/// [`read`]: ./fn.read.html -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `dst` must be [valid] for writes. -/// -/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the -/// case. -/// -/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. -/// -/// [valid]: ../ptr/index.html#safety -/// [`write_unaligned`]: ./fn.write_unaligned.html -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// let mut x = 0; -/// let y = &mut x as *mut i32; -/// let z = 12; -/// -/// unsafe { -/// std::ptr::write(y, z); -/// assert_eq!(std::ptr::read(y), 12); -/// } -/// ``` -/// -/// Manually implement [`mem::swap`]: -/// -/// ``` -/// use std::ptr; -/// -/// fn swap(a: &mut T, b: &mut T) { -/// unsafe { -/// // Create a bitwise copy of the value at `a` in `tmp`. -/// let tmp = ptr::read(a); -/// -/// // Exiting at this point (either by explicitly returning or by -/// // calling a function which panics) would cause the value in `tmp` to -/// // be dropped while the same value is still referenced by `a`. This -/// // could trigger undefined behavior if `T` is not `Copy`. -/// -/// // Create a bitwise copy of the value at `b` in `a`. -/// // This is safe because mutable references cannot alias. -/// ptr::copy_nonoverlapping(b, a, 1); -/// -/// // As above, exiting here could trigger undefined behavior because -/// // the same value is referenced by `a` and `b`. -/// -/// // Move `tmp` into `b`. -/// ptr::write(b, tmp); -/// -/// // `tmp` has been moved (`write` takes ownership of its second argument), -/// // so nothing is dropped implicitly here. -/// } -/// } -/// -/// let mut foo = "foo".to_owned(); -/// let mut bar = "bar".to_owned(); -/// -/// swap(&mut foo, &mut bar); -/// -/// assert_eq!(foo, "bar"); -/// assert_eq!(bar, "foo"); -/// ``` -/// -/// [`mem::swap`]: ../mem/fn.swap.html -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn write(dst: *mut T, src: T) { - intrinsics::move_val_init(&mut *dst, src) -} - -/// Overwrites a memory location with the given value without reading or -/// dropping the old value. -/// -/// Unlike [`write`], the pointer may be unaligned. -/// -/// `write_unaligned` does not drop the contents of `dst`. This is safe, but it -/// could leak allocations or resources, so care should be taken not to overwrite -/// an object that should be dropped. -/// -/// Additionally, it does not drop `src`. Semantically, `src` is moved into the -/// location pointed to by `dst`. -/// -/// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been read with [`read_unaligned`]. -/// -/// [`write`]: ./fn.write.html -/// [`read_unaligned`]: ./fn.read_unaligned.html -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `dst` must be [valid] for writes. -/// -/// Note that even if `T` has size `0`, the pointer must be non-NULL. -/// -/// [valid]: ../ptr/index.html#safety -/// -/// # Examples -/// -/// Access fields in a packed struct: -/// -/// ``` -/// use std::{mem, ptr}; -/// -/// #[repr(packed, C)] -/// #[derive(Default)] -/// struct Packed { -/// _padding: u8, -/// unaligned: u32, -/// } -/// -/// let v = 0x01020304; -/// let mut x: Packed = unsafe { mem::zeroed() }; -/// -/// unsafe { -/// // Take a reference to a 32-bit integer which is not aligned. -/// let unaligned = &mut x.unaligned as *mut u32; -/// -/// // Dereferencing normally will emit an aligned store instruction, -/// // causing undefined behavior because the pointer is not aligned. -/// // *unaligned = v; // ERROR -/// -/// // Instead, use `write_unaligned` to write improperly aligned values. -/// ptr::write_unaligned(unaligned, v); -/// } -/// -/// // Accessing unaligned values directly is safe. -/// assert!(x.unaligned == v); -/// ``` -#[inline] -#[stable(feature = "ptr_unaligned", since = "1.17.0")] -pub unsafe fn write_unaligned(dst: *mut T, src: T) { - copy_nonoverlapping(&src as *const T as *const u8, - dst as *mut u8, - mem::size_of::()); - mem::forget(src); -} - -/// Performs a volatile read of the value from `src` without moving it. This -/// leaves the memory in `src` unchanged. -/// -/// Volatile operations are intended to act on I/O memory, and are guaranteed -/// to not be elided or reordered by the compiler across other volatile -/// operations. -/// -/// Memory accessed with `read_volatile` or [`write_volatile`] should not be -/// accessed with non-volatile operations. -/// -/// [`write_volatile`]: ./fn.write_volatile.html -/// -/// # Notes -/// -/// Rust does not currently have a rigorously and formally defined memory model, -/// so the precise semantics of what "volatile" means here is subject to change -/// over time. That being said, the semantics will almost always end up pretty -/// similar to [C11's definition of volatile][c11]. -/// -/// The compiler shouldn't change the relative order or number of volatile -/// memory operations. However, volatile memory operations on zero-sized types -/// (e.g., if a zero-sized type is passed to `read_volatile`) are noops -/// and may be ignored. -/// -/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `src` must be [valid] for reads. -/// -/// * `src` must be properly aligned. -/// -/// Like [`read`], `read_unaligned` creates a bitwise copy of `T`, regardless of -/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned -/// value and the value at `*src` can [violate memory safety][read-ownership]. -/// However, storing non-[`Copy`] types in volatile memory is almost certainly -/// incorrect. -/// -/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. -/// -/// [valid]: ../ptr/index.html#safety -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read`]: ./fn.read.html -/// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value -/// -/// Just like in C, whether an operation is volatile has no bearing whatsoever -/// on questions involving concurrent access from multiple threads. Volatile -/// accesses behave exactly like non-atomic accesses in that regard. In particular, -/// a race between a `read_volatile` and any write operation to the same location -/// is undefined behavior. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// let x = 12; -/// let y = &x as *const i32; -/// -/// unsafe { -/// assert_eq!(std::ptr::read_volatile(y), 12); -/// } -/// ``` -#[inline] -#[stable(feature = "volatile", since = "1.9.0")] -pub unsafe fn read_volatile(src: *const T) -> T { - intrinsics::volatile_load(src) -} - -/// Performs a volatile write of a memory location with the given value without -/// reading or dropping the old value. -/// -/// Volatile operations are intended to act on I/O memory, and are guaranteed -/// to not be elided or reordered by the compiler across other volatile -/// operations. -/// -/// Memory accessed with [`read_volatile`] or `write_volatile` should not be -/// accessed with non-volatile operations. -/// -/// `write_volatile` does not drop the contents of `dst`. This is safe, but it -/// could leak allocations or resources, so care should be taken not to overwrite -/// an object that should be dropped. -/// -/// Additionally, it does not drop `src`. Semantically, `src` is moved into the -/// location pointed to by `dst`. -/// -/// [`read_volatile`]: ./fn.read_volatile.html -/// -/// # Notes -/// -/// Rust does not currently have a rigorously and formally defined memory model, -/// so the precise semantics of what "volatile" means here is subject to change -/// over time. That being said, the semantics will almost always end up pretty -/// similar to [C11's definition of volatile][c11]. -/// -/// The compiler shouldn't change the relative order or number of volatile -/// memory operations. However, volatile memory operations on zero-sized types -/// (e.g., if a zero-sized type is passed to `write_volatile`) are noops -/// and may be ignored. -/// -/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `dst` must be [valid] for writes. -/// -/// * `dst` must be properly aligned. -/// -/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. -/// -/// [valid]: ../ptr/index.html#safety -/// -/// Just like in C, whether an operation is volatile has no bearing whatsoever -/// on questions involving concurrent access from multiple threads. Volatile -/// accesses behave exactly like non-atomic accesses in that regard. In particular, -/// a race between a `write_volatile` and any other operation (reading or writing) -/// on the same location is undefined behavior. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// let mut x = 0; -/// let y = &mut x as *mut i32; -/// let z = 12; -/// -/// unsafe { -/// std::ptr::write_volatile(y, z); -/// assert_eq!(std::ptr::read_volatile(y), 12); -/// } -/// ``` -#[inline] -#[stable(feature = "volatile", since = "1.9.0")] -pub unsafe fn write_volatile(dst: *mut T, src: T) { - intrinsics::volatile_store(dst, src); -} - -#[lang = "const_ptr"] -impl *const T { - /// Returns `true` if the pointer is null. - /// - /// Note that unsized types have many possible null pointers, as only the - /// raw data pointer is considered, not their length, vtable, etc. - /// Therefore, two pointers that are null may still not compare equal to - /// each other. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s: &str = "Follow the rabbit"; - /// let ptr: *const u8 = s.as_ptr(); - /// assert!(!ptr.is_null()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_null(self) -> bool { - // Compare via a cast to a thin pointer, so fat pointers are only - // considering their "data" part for null-ness. - (self as *const u8) == null() - } - - /// Returns `None` if the pointer is null, or else returns a reference to - /// the value wrapped in `Some`. - /// - /// # Safety - /// - /// While this method and its mutable counterpart are useful for - /// null-safety, it is important to note that this is still an unsafe - /// operation because the returned value could be pointing to invalid - /// memory. - /// - /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does - /// not necessarily reflect the actual lifetime of the data. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let ptr: *const u8 = &10u8 as *const u8; - /// - /// unsafe { - /// if let Some(val_back) = ptr.as_ref() { - /// println!("We got back the value: {}!", val_back); - /// } - /// } - /// ``` - /// - /// # Null-unchecked version - /// - /// If you are sure the pointer can never be null and are looking for some kind of - /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can - /// dereference the pointer directly. - /// - /// ``` - /// let ptr: *const u8 = &10u8 as *const u8; - /// - /// unsafe { - /// let val_back = &*ptr; - /// println!("We got back the value: {}!", val_back); - /// } - /// ``` - #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[inline] - pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { - if self.is_null() { - None - } else { - Some(&*self) - } - } - - /// Calculates the offset from a pointer. - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. - /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using `wrapping_offset` instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s: &str = "123"; - /// let ptr: *const u8 = s.as_ptr(); - /// - /// unsafe { - /// println!("{}", *ptr.offset(1) as char); - /// println!("{}", *ptr.offset(2) as char); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub unsafe fn offset(self, count: isize) -> *const T where T: Sized { - intrinsics::offset(self, count) - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// In particular, the resulting pointer may *not* be used to access a - /// different allocated object than the one `self` points to. In other - /// words, `x.wrapping_offset(y.wrapping_offset_from(x))` is - /// *not* the same as `y`, and dereferencing it is undefined behavior - /// unless `x` and `y` point into the same allocated object. - /// - /// Always use `.offset(count)` instead when possible, because `offset` - /// allows the compiler to optimize better. If you need to cross object - /// boundaries, cast the pointer to an integer and do the arithmetic there. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // Iterate using a raw pointer in increments of two elements - /// let data = [1u8, 2, 3, 4, 5]; - /// let mut ptr: *const u8 = data.as_ptr(); - /// let step = 2; - /// let end_rounded_up = ptr.wrapping_offset(6); - /// - /// // This loop prints "1, 3, 5, " - /// while ptr != end_rounded_up { - /// unsafe { - /// print!("{}, ", *ptr); - /// } - /// ptr = ptr.wrapping_offset(step); - /// } - /// ``` - #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] - #[inline] - pub fn wrapping_offset(self, count: isize) -> *const T where T: Sized { - unsafe { - intrinsics::arith_offset(self, count) - } - } - - /// Calculates the distance between two pointers. The returned value is in - /// units of T: the distance in bytes is divided by `mem::size_of::()`. - /// - /// This function is the inverse of [`offset`]. - /// - /// [`offset`]: #method.offset - /// [`wrapping_offset_from`]: #method.wrapping_offset_from - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and other pointer must be either in bounds or one - /// byte past the end of the same allocated object. - /// - /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. - /// - /// * The distance between the pointers, in bytes, must be an exact multiple - /// of the size of `T`. - /// - /// * The distance being in bounds cannot rely on "wrapping around" the address space. - /// - /// The compiler and standard library generally try to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `ptr_into_vec.offset_from(vec.as_ptr())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using [`wrapping_offset_from`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// # Panics - /// - /// This function panics if `T` is a Zero-Sized Type ("ZST"). - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(ptr_offset_from)] - /// - /// let a = [0; 5]; - /// let ptr1: *const i32 = &a[1]; - /// let ptr2: *const i32 = &a[3]; - /// unsafe { - /// assert_eq!(ptr2.offset_from(ptr1), 2); - /// assert_eq!(ptr1.offset_from(ptr2), -2); - /// assert_eq!(ptr1.offset(2), ptr2); - /// assert_eq!(ptr2.offset(-2), ptr1); - /// } - /// ``` - #[unstable(feature = "ptr_offset_from", issue = "41079")] - #[inline] - pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { - let pointee_size = mem::size_of::(); - assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); - - // This is the same sequence that Clang emits for pointer subtraction. - // It can be neither `nsw` nor `nuw` because the input is treated as - // unsigned but then the output is treated as signed, so neither works. - let d = isize::wrapping_sub(self as _, origin as _); - intrinsics::exact_div(d, pointee_size as _) - } - - /// Calculates the distance between two pointers. The returned value is in - /// units of T: the distance in bytes is divided by `mem::size_of::()`. - /// - /// If the address different between the two pointers is not a multiple of - /// `mem::size_of::()` then the result of the division is rounded towards - /// zero. - /// - /// Though this method is safe for any two pointers, note that its result - /// will be mostly useless if the two pointers aren't into the same allocated - /// object, for example if they point to two different local variables. - /// - /// # Panics - /// - /// This function panics if `T` is a zero-sized type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(ptr_wrapping_offset_from)] - /// - /// let a = [0; 5]; - /// let ptr1: *const i32 = &a[1]; - /// let ptr2: *const i32 = &a[3]; - /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); - /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); - /// assert_eq!(ptr1.wrapping_offset(2), ptr2); - /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); - /// - /// let ptr1: *const i32 = 3 as _; - /// let ptr2: *const i32 = 13 as _; - /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); - /// ``` - #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] - #[inline] - pub fn wrapping_offset_from(self, origin: *const T) -> isize where T: Sized { - let pointee_size = mem::size_of::(); - assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); - - let d = isize::wrapping_sub(self as _, origin as _); - d.wrapping_div(pointee_size as _) - } - - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. - /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a `usize`. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using `wrapping_offset` instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s: &str = "123"; - /// let ptr: *const u8 = s.as_ptr(); - /// - /// unsafe { - /// println!("{}", *ptr.add(1) as char); - /// println!("{}", *ptr.add(2) as char); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn add(self, count: usize) -> Self - where T: Sized, - { - self.offset(count as isize) - } - - /// Calculates the offset from a pointer (convenience for - /// `.offset((count as isize).wrapping_neg())`). - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. - /// - /// * The computed offset cannot exceed `isize::MAX` **bytes**. - /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a usize. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using `wrapping_offset` instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s: &str = "123"; - /// - /// unsafe { - /// let end: *const u8 = s.as_ptr().add(3); - /// println!("{}", *end.sub(1) as char); - /// println!("{}", *end.sub(2) as char); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn sub(self, count: usize) -> Self - where T: Sized, - { - self.offset((count as isize).wrapping_neg()) - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset(count as isize)`) - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// - /// Always use `.add(count)` instead when possible, because `add` - /// allows the compiler to optimize better. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // Iterate using a raw pointer in increments of two elements - /// let data = [1u8, 2, 3, 4, 5]; - /// let mut ptr: *const u8 = data.as_ptr(); - /// let step = 2; - /// let end_rounded_up = ptr.wrapping_add(6); - /// - /// // This loop prints "1, 3, 5, " - /// while ptr != end_rounded_up { - /// unsafe { - /// print!("{}, ", *ptr); - /// } - /// ptr = ptr.wrapping_add(step); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub fn wrapping_add(self, count: usize) -> Self - where T: Sized, - { - self.wrapping_offset(count as isize) - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`) - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// - /// Always use `.sub(count)` instead when possible, because `sub` - /// allows the compiler to optimize better. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // Iterate using a raw pointer in increments of two elements (backwards) - /// let data = [1u8, 2, 3, 4, 5]; - /// let mut ptr: *const u8 = data.as_ptr(); - /// let start_rounded_down = ptr.wrapping_sub(2); - /// ptr = ptr.wrapping_add(4); - /// let step = 2; - /// // This loop prints "5, 3, 1, " - /// while ptr != start_rounded_down { - /// unsafe { - /// print!("{}, ", *ptr); - /// } - /// ptr = ptr.wrapping_sub(step); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub fn wrapping_sub(self, count: usize) -> Self - where T: Sized, - { - self.wrapping_offset((count as isize).wrapping_neg()) - } - - /// Reads the value from `self` without moving it. This leaves the - /// memory in `self` unchanged. - /// - /// See [`ptr::read`] for safety concerns and examples. - /// - /// [`ptr::read`]: ./ptr/fn.read.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn read(self) -> T - where T: Sized, - { - read(self) - } - - /// Performs a volatile read of the value from `self` without moving it. This - /// leaves the memory in `self` unchanged. - /// - /// Volatile operations are intended to act on I/O memory, and are guaranteed - /// to not be elided or reordered by the compiler across other volatile - /// operations. - /// - /// See [`ptr::read_volatile`] for safety concerns and examples. - /// - /// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn read_volatile(self) -> T - where T: Sized, - { - read_volatile(self) - } - - /// Reads the value from `self` without moving it. This leaves the - /// memory in `self` unchanged. - /// - /// Unlike `read`, the pointer may be unaligned. - /// - /// See [`ptr::read_unaligned`] for safety concerns and examples. - /// - /// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn read_unaligned(self) -> T - where T: Sized, - { - read_unaligned(self) - } - - /// Copies `count * size_of` bytes from `self` to `dest`. The source - /// and destination may overlap. - /// - /// NOTE: this has the *same* argument order as [`ptr::copy`]. - /// - /// See [`ptr::copy`] for safety concerns and examples. - /// - /// [`ptr::copy`]: ./ptr/fn.copy.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn copy_to(self, dest: *mut T, count: usize) - where T: Sized, - { - copy(self, dest, count) - } - - /// Copies `count * size_of` bytes from `self` to `dest`. The source - /// and destination may *not* overlap. - /// - /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. - /// - /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. - /// - /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) - where T: Sized, - { - copy_nonoverlapping(self, dest, count) - } - - /// Computes the offset that needs to be applied to the pointer in order to make it aligned to - /// `align`. - /// - /// If it is not possible to align the pointer, the implementation returns - /// `usize::max_value()`. - /// - /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be - /// used with the `offset` or `offset_to` methods. - /// - /// There are no guarantees whatsover that offsetting the pointer will not overflow or go - /// beyond the allocation that the pointer points into. It is up to the caller to ensure that - /// the returned offset is correct in all terms other than alignment. - /// - /// # Panics - /// - /// The function panics if `align` is not a power-of-two. - /// - /// # Examples - /// - /// Accessing adjacent `u8` as `u16` - /// - /// ``` - /// # #![feature(align_offset)] - /// # fn foo(n: usize) { - /// # use std::mem::align_of; - /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = &x[n] as *const u8; - /// let offset = ptr.align_offset(align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; - /// assert_ne!(*u16_ptr, 500); - /// } else { - /// // while the pointer can be aligned via `offset`, it would point - /// // outside the allocation - /// } - /// # } } - /// ``` - #[unstable(feature = "align_offset", issue = "44488")] - pub fn align_offset(self, align: usize) -> usize where T: Sized { - if !align.is_power_of_two() { - panic!("align_offset: align is not a power-of-two"); - } - unsafe { - align_offset(self, align) - } - } -} - - -#[lang = "mut_ptr"] -impl *mut T { - /// Returns `true` if the pointer is null. - /// - /// Note that unsized types have many possible null pointers, as only the - /// raw data pointer is considered, not their length, vtable, etc. - /// Therefore, two pointers that are null may still not compare equal to - /// each other. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut s = [1, 2, 3]; - /// let ptr: *mut u32 = s.as_mut_ptr(); - /// assert!(!ptr.is_null()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_null(self) -> bool { - // Compare via a cast to a thin pointer, so fat pointers are only - // considering their "data" part for null-ness. - (self as *mut u8) == null_mut() - } - - /// Returns `None` if the pointer is null, or else returns a reference to - /// the value wrapped in `Some`. - /// - /// # Safety - /// - /// While this method and its mutable counterpart are useful for - /// null-safety, it is important to note that this is still an unsafe - /// operation because the returned value could be pointing to invalid - /// memory. - /// - /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does - /// not necessarily reflect the actual lifetime of the data. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let ptr: *mut u8 = &mut 10u8 as *mut u8; - /// - /// unsafe { - /// if let Some(val_back) = ptr.as_ref() { - /// println!("We got back the value: {}!", val_back); - /// } - /// } - /// ``` - /// - /// # Null-unchecked version - /// - /// If you are sure the pointer can never be null and are looking for some kind of - /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can - /// dereference the pointer directly. - /// - /// ``` - /// let ptr: *mut u8 = &mut 10u8 as *mut u8; - /// - /// unsafe { - /// let val_back = &*ptr; - /// println!("We got back the value: {}!", val_back); - /// } - /// ``` - #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[inline] - pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { - if self.is_null() { - None - } else { - Some(&*self) - } - } - - /// Calculates the offset from a pointer. - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. - /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using `wrapping_offset` instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut s = [1, 2, 3]; - /// let ptr: *mut u32 = s.as_mut_ptr(); - /// - /// unsafe { - /// println!("{}", *ptr.offset(1)); - /// println!("{}", *ptr.offset(2)); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub unsafe fn offset(self, count: isize) -> *mut T where T: Sized { - intrinsics::offset(self, count) as *mut T - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// In particular, the resulting pointer may *not* be used to access a - /// different allocated object than the one `self` points to. In other - /// words, `x.wrapping_offset(y.wrapping_offset_from(x))` is - /// *not* the same as `y`, and dereferencing it is undefined behavior - /// unless `x` and `y` point into the same allocated object. - /// - /// Always use `.offset(count)` instead when possible, because `offset` - /// allows the compiler to optimize better. If you need to cross object - /// boundaries, cast the pointer to an integer and do the arithmetic there. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // Iterate using a raw pointer in increments of two elements - /// let mut data = [1u8, 2, 3, 4, 5]; - /// let mut ptr: *mut u8 = data.as_mut_ptr(); - /// let step = 2; - /// let end_rounded_up = ptr.wrapping_offset(6); - /// - /// while ptr != end_rounded_up { - /// unsafe { - /// *ptr = 0; - /// } - /// ptr = ptr.wrapping_offset(step); - /// } - /// assert_eq!(&data, &[0, 2, 0, 4, 0]); - /// ``` - #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] - #[inline] - pub fn wrapping_offset(self, count: isize) -> *mut T where T: Sized { - unsafe { - intrinsics::arith_offset(self, count) as *mut T - } - } - - /// Returns `None` if the pointer is null, or else returns a mutable - /// reference to the value wrapped in `Some`. - /// - /// # Safety - /// - /// As with `as_ref`, this is unsafe because it cannot verify the validity - /// of the returned pointer, nor can it ensure that the lifetime `'a` - /// returned is indeed a valid lifetime for the contained data. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut s = [1, 2, 3]; - /// let ptr: *mut u32 = s.as_mut_ptr(); - /// let first_value = unsafe { ptr.as_mut().unwrap() }; - /// *first_value = 4; - /// println!("{:?}", s); // It'll print: "[4, 2, 3]". - /// ``` - #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[inline] - pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> { - if self.is_null() { - None - } else { - Some(&mut *self) - } - } - - /// Calculates the distance between two pointers. The returned value is in - /// units of T: the distance in bytes is divided by `mem::size_of::()`. - /// - /// This function is the inverse of [`offset`]. - /// - /// [`offset`]: #method.offset-1 - /// [`wrapping_offset_from`]: #method.wrapping_offset_from-1 - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and other pointer must be either in bounds or one - /// byte past the end of the same allocated object. - /// - /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. - /// - /// * The distance between the pointers, in bytes, must be an exact multiple - /// of the size of `T`. - /// - /// * The distance being in bounds cannot rely on "wrapping around" the address space. - /// - /// The compiler and standard library generally try to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `ptr_into_vec.offset_from(vec.as_ptr())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using [`wrapping_offset_from`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// # Panics - /// - /// This function panics if `T` is a Zero-Sized Type ("ZST"). - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(ptr_offset_from)] - /// - /// let mut a = [0; 5]; - /// let ptr1: *mut i32 = &mut a[1]; - /// let ptr2: *mut i32 = &mut a[3]; - /// unsafe { - /// assert_eq!(ptr2.offset_from(ptr1), 2); - /// assert_eq!(ptr1.offset_from(ptr2), -2); - /// assert_eq!(ptr1.offset(2), ptr2); - /// assert_eq!(ptr2.offset(-2), ptr1); - /// } - /// ``` - #[unstable(feature = "ptr_offset_from", issue = "41079")] - #[inline] - pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { - (self as *const T).offset_from(origin) - } - - /// Calculates the distance between two pointers. The returned value is in - /// units of T: the distance in bytes is divided by `mem::size_of::()`. - /// - /// If the address different between the two pointers is not a multiple of - /// `mem::size_of::()` then the result of the division is rounded towards - /// zero. - /// - /// Though this method is safe for any two pointers, note that its result - /// will be mostly useless if the two pointers aren't into the same allocated - /// object, for example if they point to two different local variables. - /// - /// # Panics - /// - /// This function panics if `T` is a zero-sized type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(ptr_wrapping_offset_from)] - /// - /// let mut a = [0; 5]; - /// let ptr1: *mut i32 = &mut a[1]; - /// let ptr2: *mut i32 = &mut a[3]; - /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); - /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); - /// assert_eq!(ptr1.wrapping_offset(2), ptr2); - /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); - /// - /// let ptr1: *mut i32 = 3 as _; - /// let ptr2: *mut i32 = 13 as _; - /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); - /// ``` - #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] - #[inline] - pub fn wrapping_offset_from(self, origin: *const T) -> isize where T: Sized { - (self as *const T).wrapping_offset_from(origin) - } - - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. - /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a `usize`. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using `wrapping_offset` instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s: &str = "123"; - /// let ptr: *const u8 = s.as_ptr(); - /// - /// unsafe { - /// println!("{}", *ptr.add(1) as char); - /// println!("{}", *ptr.add(2) as char); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn add(self, count: usize) -> Self - where T: Sized, - { - self.offset(count as isize) - } - - /// Calculates the offset from a pointer (convenience for - /// `.offset((count as isize).wrapping_neg())`). - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. - /// - /// * The computed offset cannot exceed `isize::MAX` **bytes**. - /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a usize. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// - /// Consider using `wrapping_offset` instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s: &str = "123"; - /// - /// unsafe { - /// let end: *const u8 = s.as_ptr().add(3); - /// println!("{}", *end.sub(1) as char); - /// println!("{}", *end.sub(2) as char); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn sub(self, count: usize) -> Self - where T: Sized, - { - self.offset((count as isize).wrapping_neg()) - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset(count as isize)`) - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// - /// Always use `.add(count)` instead when possible, because `add` - /// allows the compiler to optimize better. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // Iterate using a raw pointer in increments of two elements - /// let data = [1u8, 2, 3, 4, 5]; - /// let mut ptr: *const u8 = data.as_ptr(); - /// let step = 2; - /// let end_rounded_up = ptr.wrapping_add(6); - /// - /// // This loop prints "1, 3, 5, " - /// while ptr != end_rounded_up { - /// unsafe { - /// print!("{}, ", *ptr); - /// } - /// ptr = ptr.wrapping_add(step); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub fn wrapping_add(self, count: usize) -> Self - where T: Sized, - { - self.wrapping_offset(count as isize) - } - - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`) - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). - /// - /// Always use `.sub(count)` instead when possible, because `sub` - /// allows the compiler to optimize better. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // Iterate using a raw pointer in increments of two elements (backwards) - /// let data = [1u8, 2, 3, 4, 5]; - /// let mut ptr: *const u8 = data.as_ptr(); - /// let start_rounded_down = ptr.wrapping_sub(2); - /// ptr = ptr.wrapping_add(4); - /// let step = 2; - /// // This loop prints "5, 3, 1, " - /// while ptr != start_rounded_down { - /// unsafe { - /// print!("{}, ", *ptr); - /// } - /// ptr = ptr.wrapping_sub(step); - /// } - /// ``` - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub fn wrapping_sub(self, count: usize) -> Self - where T: Sized, - { - self.wrapping_offset((count as isize).wrapping_neg()) - } - - /// Reads the value from `self` without moving it. This leaves the - /// memory in `self` unchanged. - /// - /// See [`ptr::read`] for safety concerns and examples. - /// - /// [`ptr::read`]: ./ptr/fn.read.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn read(self) -> T - where T: Sized, - { - read(self) - } - - /// Performs a volatile read of the value from `self` without moving it. This - /// leaves the memory in `self` unchanged. - /// - /// Volatile operations are intended to act on I/O memory, and are guaranteed - /// to not be elided or reordered by the compiler across other volatile - /// operations. - /// - /// See [`ptr::read_volatile`] for safety concerns and examples. - /// - /// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn read_volatile(self) -> T - where T: Sized, - { - read_volatile(self) - } - - /// Reads the value from `self` without moving it. This leaves the - /// memory in `self` unchanged. - /// - /// Unlike `read`, the pointer may be unaligned. - /// - /// See [`ptr::read_unaligned`] for safety concerns and examples. - /// - /// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn read_unaligned(self) -> T - where T: Sized, - { - read_unaligned(self) - } - - /// Copies `count * size_of` bytes from `self` to `dest`. The source - /// and destination may overlap. - /// - /// NOTE: this has the *same* argument order as [`ptr::copy`]. - /// - /// See [`ptr::copy`] for safety concerns and examples. - /// - /// [`ptr::copy`]: ./ptr/fn.copy.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn copy_to(self, dest: *mut T, count: usize) - where T: Sized, - { - copy(self, dest, count) - } - - /// Copies `count * size_of` bytes from `self` to `dest`. The source - /// and destination may *not* overlap. - /// - /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. - /// - /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. - /// - /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) - where T: Sized, - { - copy_nonoverlapping(self, dest, count) - } - - /// Copies `count * size_of` bytes from `src` to `self`. The source - /// and destination may overlap. - /// - /// NOTE: this has the *opposite* argument order of [`ptr::copy`]. - /// - /// See [`ptr::copy`] for safety concerns and examples. - /// - /// [`ptr::copy`]: ./ptr/fn.copy.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn copy_from(self, src: *const T, count: usize) - where T: Sized, - { - copy(src, self, count) - } - - /// Copies `count * size_of` bytes from `src` to `self`. The source - /// and destination may *not* overlap. - /// - /// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`]. - /// - /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. - /// - /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize) - where T: Sized, - { - copy_nonoverlapping(src, self, count) - } - - /// Executes the destructor (if any) of the pointed-to value. - /// - /// See [`ptr::drop_in_place`] for safety concerns and examples. - /// - /// [`ptr::drop_in_place`]: ./ptr/fn.drop_in_place.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn drop_in_place(self) { - drop_in_place(self) - } - - /// Overwrites a memory location with the given value without reading or - /// dropping the old value. - /// - /// See [`ptr::write`] for safety concerns and examples. - /// - /// [`ptr::write`]: ./ptr/fn.write.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn write(self, val: T) - where T: Sized, - { - write(self, val) - } - - /// Invokes memset on the specified pointer, setting `count * size_of::()` - /// bytes of memory starting at `self` to `val`. - /// - /// See [`ptr::write_bytes`] for safety concerns and examples. - /// - /// [`ptr::write_bytes`]: ./ptr/fn.write_bytes.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn write_bytes(self, val: u8, count: usize) - where T: Sized, - { - write_bytes(self, val, count) - } - - /// Performs a volatile write of a memory location with the given value without - /// reading or dropping the old value. - /// - /// Volatile operations are intended to act on I/O memory, and are guaranteed - /// to not be elided or reordered by the compiler across other volatile - /// operations. - /// - /// See [`ptr::write_volatile`] for safety concerns and examples. - /// - /// [`ptr::write_volatile`]: ./ptr/fn.write_volatile.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn write_volatile(self, val: T) - where T: Sized, - { - write_volatile(self, val) - } - - /// Overwrites a memory location with the given value without reading or - /// dropping the old value. - /// - /// Unlike `write`, the pointer may be unaligned. - /// - /// See [`ptr::write_unaligned`] for safety concerns and examples. - /// - /// [`ptr::write_unaligned`]: ./ptr/fn.write_unaligned.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn write_unaligned(self, val: T) - where T: Sized, - { - write_unaligned(self, val) - } - - /// Replaces the value at `self` with `src`, returning the old - /// value, without dropping either. - /// - /// See [`ptr::replace`] for safety concerns and examples. - /// - /// [`ptr::replace`]: ./ptr/fn.replace.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn replace(self, src: T) -> T - where T: Sized, - { - replace(self, src) - } - - /// Swaps the values at two mutable locations of the same type, without - /// deinitializing either. They may overlap, unlike `mem::swap` which is - /// otherwise equivalent. - /// - /// See [`ptr::swap`] for safety concerns and examples. - /// - /// [`ptr::swap`]: ./ptr/fn.swap.html - #[stable(feature = "pointer_methods", since = "1.26.0")] - #[inline] - pub unsafe fn swap(self, with: *mut T) - where T: Sized, - { - swap(self, with) - } - - /// Computes the offset that needs to be applied to the pointer in order to make it aligned to - /// `align`. - /// - /// If it is not possible to align the pointer, the implementation returns - /// `usize::max_value()`. - /// - /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be - /// used with the `offset` or `offset_to` methods. - /// - /// There are no guarantees whatsover that offsetting the pointer will not overflow or go - /// beyond the allocation that the pointer points into. It is up to the caller to ensure that - /// the returned offset is correct in all terms other than alignment. - /// - /// # Panics - /// - /// The function panics if `align` is not a power-of-two. - /// - /// # Examples - /// - /// Accessing adjacent `u8` as `u16` - /// - /// ``` - /// # #![feature(align_offset)] - /// # fn foo(n: usize) { - /// # use std::mem::align_of; - /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = &x[n] as *const u8; - /// let offset = ptr.align_offset(align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; - /// assert_ne!(*u16_ptr, 500); - /// } else { - /// // while the pointer can be aligned via `offset`, it would point - /// // outside the allocation - /// } - /// # } } - /// ``` - #[unstable(feature = "align_offset", issue = "44488")] - pub fn align_offset(self, align: usize) -> usize where T: Sized { - if !align.is_power_of_two() { - panic!("align_offset: align is not a power-of-two"); - } - unsafe { - align_offset(self, align) - } - } -} - -/// Align pointer `p`. -/// -/// Calculate offset (in terms of elements of `stride` stride) that has to be applied -/// to pointer `p` so that pointer `p` would get aligned to `a`. -/// -/// Note: This implementation has been carefully tailored to not panic. It is UB for this to panic. -/// The only real change that can be made here is change of `INV_TABLE_MOD_16` and associated -/// constants. -/// -/// If we ever decide to make it possible to call the intrinsic with `a` that is not a -/// power-of-two, it will probably be more prudent to just change to a naive implementation rather -/// than trying to adapt this to accommodate that change. -/// -/// Any questions go to @nagisa. -#[lang="align_offset"] -pub(crate) unsafe fn align_offset(p: *const T, a: usize) -> usize { - /// Calculate multiplicative modular inverse of `x` modulo `m`. - /// - /// This implementation is tailored for align_offset and has following preconditions: - /// - /// * `m` is a power-of-two; - /// * `x < m`; (if `x ≥ m`, pass in `x % m` instead) - /// - /// Implementation of this function shall not panic. Ever. - #[inline] - fn mod_inv(x: usize, m: usize) -> usize { - /// Multiplicative modular inverse table modulo 2⁴ = 16. - /// - /// Note, that this table does not contain values where inverse does not exist (i.e., for - /// `0⁻¹ mod 16`, `2⁻¹ mod 16`, etc.) - const INV_TABLE_MOD_16: [u8; 8] = [1, 11, 13, 7, 9, 3, 5, 15]; - /// Modulo for which the `INV_TABLE_MOD_16` is intended. - const INV_TABLE_MOD: usize = 16; - /// INV_TABLE_MOD² - const INV_TABLE_MOD_SQUARED: usize = INV_TABLE_MOD * INV_TABLE_MOD; - - let table_inverse = INV_TABLE_MOD_16[(x & (INV_TABLE_MOD - 1)) >> 1] as usize; - if m <= INV_TABLE_MOD { - table_inverse & (m - 1) - } else { - // We iterate "up" using the following formula: - // - // $$ xy ≡ 1 (mod 2ⁿ) → xy (2 - xy) ≡ 1 (mod 2²ⁿ) $$ - // - // until 2²ⁿ ≥ m. Then we can reduce to our desired `m` by taking the result `mod m`. - let mut inverse = table_inverse; - let mut going_mod = INV_TABLE_MOD_SQUARED; - loop { - // y = y * (2 - xy) mod n - // - // Note, that we use wrapping operations here intentionally – the original formula - // uses e.g., subtraction `mod n`. It is entirely fine to do them `mod - // usize::max_value()` instead, because we take the result `mod n` at the end - // anyway. - inverse = inverse.wrapping_mul( - 2usize.wrapping_sub(x.wrapping_mul(inverse)) - ) & (going_mod - 1); - if going_mod > m { - return inverse & (m - 1); - } - going_mod = going_mod.wrapping_mul(going_mod); - } - } - } - - let stride = ::mem::size_of::(); - let a_minus_one = a.wrapping_sub(1); - let pmoda = p as usize & a_minus_one; - - if pmoda == 0 { - // Already aligned. Yay! - return 0; - } - - if stride <= 1 { - return if stride == 0 { - // If the pointer is not aligned, and the element is zero-sized, then no amount of - // elements will ever align the pointer. - !0 - } else { - a.wrapping_sub(pmoda) - }; - } - - let smoda = stride & a_minus_one; - // a is power-of-two so cannot be 0. stride = 0 is handled above. - let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a)); - let gcd = 1usize << gcdpow; - - if p as usize & (gcd - 1) == 0 { - // This branch solves for the following linear congruence equation: - // - // $$ p + so ≡ 0 mod a $$ - // - // $p$ here is the pointer value, $s$ – stride of `T`, $o$ offset in `T`s, and $a$ – the - // requested alignment. - // - // g = gcd(a, s) - // o = (a - (p mod a))/g * ((s/g)⁻¹ mod a) - // - // The first term is “the relative alignment of p to a”, the second term is “how does - // incrementing p by s bytes change the relative alignment of p”. Division by `g` is - // necessary to make this equation well formed if $a$ and $s$ are not co-prime. - // - // Furthermore, the result produced by this solution is not “minimal”, so it is necessary - // to take the result $o mod lcm(s, a)$. We can replace $lcm(s, a)$ with just a $a / g$. - let j = a.wrapping_sub(pmoda) >> gcdpow; - let k = smoda >> gcdpow; - return intrinsics::unchecked_rem(j.wrapping_mul(mod_inv(k, a)), a >> gcdpow); - } - - // Cannot be aligned at all. - usize::max_value() -} - - - -// Equality for pointers -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for *const T { - #[inline] - fn eq(&self, other: &*const T) -> bool { *self == *other } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for *const T {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for *mut T { - #[inline] - fn eq(&self, other: &*mut T) -> bool { *self == *other } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for *mut T {} - -/// Compares raw pointers for equality. -/// -/// This is the same as using the `==` operator, but less generic: -/// the arguments have to be `*const T` raw pointers, -/// not anything that implements `PartialEq`. -/// -/// This can be used to compare `&T` references (which coerce to `*const T` implicitly) -/// by their address rather than comparing the values they point to -/// (which is what the `PartialEq for &T` implementation does). -/// -/// # Examples -/// -/// ``` -/// use std::ptr; -/// -/// let five = 5; -/// let other_five = 5; -/// let five_ref = &five; -/// let same_five_ref = &five; -/// let other_five_ref = &other_five; -/// -/// assert!(five_ref == same_five_ref); -/// assert!(five_ref == other_five_ref); -/// -/// assert!(ptr::eq(five_ref, same_five_ref)); -/// assert!(!ptr::eq(five_ref, other_five_ref)); -/// ``` -#[stable(feature = "ptr_eq", since = "1.17.0")] -#[inline] -pub fn eq(a: *const T, b: *const T) -> bool { - a == b -} - -/// Hash a raw pointer. -/// -/// This can be used to hash a `&T` reference (which coerces to `*const T` implicitly) -/// by its address rather than the value it points to -/// (which is what the `Hash for &T` implementation does). -/// -/// # Examples -/// -/// ``` -/// #![feature(ptr_hash)] -/// use std::collections::hash_map::DefaultHasher; -/// use std::hash::{Hash, Hasher}; -/// use std::ptr; -/// -/// let five = 5; -/// let five_ref = &five; -/// -/// let mut hasher = DefaultHasher::new(); -/// ptr::hash(five_ref, &mut hasher); -/// let actual = hasher.finish(); -/// -/// let mut hasher = DefaultHasher::new(); -/// (five_ref as *const i32).hash(&mut hasher); -/// let expected = hasher.finish(); -/// -/// assert_eq!(actual, expected); -/// ``` -#[unstable(feature = "ptr_hash", reason = "newly added", issue = "56286")] -pub fn hash(hashee: *const T, into: &mut S) { - use hash::Hash; - hashee.hash(into); -} - -// Impls for function pointers -macro_rules! fnptr_impls_safety_abi { - ($FnTy: ty, $($Arg: ident),*) => { - #[stable(feature = "fnptr_impls", since = "1.4.0")] - impl PartialEq for $FnTy { - #[inline] - fn eq(&self, other: &Self) -> bool { - *self as usize == *other as usize - } - } - - #[stable(feature = "fnptr_impls", since = "1.4.0")] - impl Eq for $FnTy {} - - #[stable(feature = "fnptr_impls", since = "1.4.0")] - impl PartialOrd for $FnTy { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - (*self as usize).partial_cmp(&(*other as usize)) - } - } - - #[stable(feature = "fnptr_impls", since = "1.4.0")] - impl Ord for $FnTy { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - (*self as usize).cmp(&(*other as usize)) - } - } - - #[stable(feature = "fnptr_impls", since = "1.4.0")] - impl hash::Hash for $FnTy { - fn hash(&self, state: &mut HH) { - state.write_usize(*self as usize) - } - } - - #[stable(feature = "fnptr_impls", since = "1.4.0")] - impl fmt::Pointer for $FnTy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Pointer::fmt(&(*self as *const ()), f) - } - } - - #[stable(feature = "fnptr_impls", since = "1.4.0")] - impl fmt::Debug for $FnTy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Pointer::fmt(&(*self as *const ()), f) - } - } - } -} - -macro_rules! fnptr_impls_args { - ($($Arg: ident),+) => { - fnptr_impls_safety_abi! { extern "Rust" fn($($Arg),*) -> Ret, $($Arg),* } - fnptr_impls_safety_abi! { extern "C" fn($($Arg),*) -> Ret, $($Arg),* } - fnptr_impls_safety_abi! { extern "C" fn($($Arg),* , ...) -> Ret, $($Arg),* } - fnptr_impls_safety_abi! { unsafe extern "Rust" fn($($Arg),*) -> Ret, $($Arg),* } - fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),*) -> Ret, $($Arg),* } - fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),* , ...) -> Ret, $($Arg),* } - }; - () => { - // No variadic functions with 0 parameters - fnptr_impls_safety_abi! { extern "Rust" fn() -> Ret, } - fnptr_impls_safety_abi! { extern "C" fn() -> Ret, } - fnptr_impls_safety_abi! { unsafe extern "Rust" fn() -> Ret, } - fnptr_impls_safety_abi! { unsafe extern "C" fn() -> Ret, } - }; -} - -fnptr_impls_args! { } -fnptr_impls_args! { A } -fnptr_impls_args! { A, B } -fnptr_impls_args! { A, B, C } -fnptr_impls_args! { A, B, C, D } -fnptr_impls_args! { A, B, C, D, E } -fnptr_impls_args! { A, B, C, D, E, F } -fnptr_impls_args! { A, B, C, D, E, F, G } -fnptr_impls_args! { A, B, C, D, E, F, G, H } -fnptr_impls_args! { A, B, C, D, E, F, G, H, I } -fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J } -fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K } -fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L } - -// Comparison for pointers -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for *const T { - #[inline] - fn cmp(&self, other: &*const T) -> Ordering { - if self < other { - Less - } else if self == other { - Equal - } else { - Greater - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for *const T { - #[inline] - fn partial_cmp(&self, other: &*const T) -> Option { - Some(self.cmp(other)) - } - - #[inline] - fn lt(&self, other: &*const T) -> bool { *self < *other } - - #[inline] - fn le(&self, other: &*const T) -> bool { *self <= *other } - - #[inline] - fn gt(&self, other: &*const T) -> bool { *self > *other } - - #[inline] - fn ge(&self, other: &*const T) -> bool { *self >= *other } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for *mut T { - #[inline] - fn cmp(&self, other: &*mut T) -> Ordering { - if self < other { - Less - } else if self == other { - Equal - } else { - Greater - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for *mut T { - #[inline] - fn partial_cmp(&self, other: &*mut T) -> Option { - Some(self.cmp(other)) - } - - #[inline] - fn lt(&self, other: &*mut T) -> bool { *self < *other } - - #[inline] - fn le(&self, other: &*mut T) -> bool { *self <= *other } - - #[inline] - fn gt(&self, other: &*mut T) -> bool { *self > *other } - - #[inline] - fn ge(&self, other: &*mut T) -> bool { *self >= *other } -} - -/// A wrapper around a raw non-null `*mut T` that indicates that the possessor -/// of this wrapper owns the referent. Useful for building abstractions like -/// `Box`, `Vec`, `String`, and `HashMap`. -/// -/// Unlike `*mut T`, `Unique` behaves "as if" it were an instance of `T`. -/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies -/// the kind of strong aliasing guarantees an instance of `T` can expect: -/// the referent of the pointer should not be modified without a unique path to -/// its owning Unique. -/// -/// If you're uncertain of whether it's correct to use `Unique` for your purposes, -/// consider using `NonNull`, which has weaker semantics. -/// -/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer -/// is never dereferenced. This is so that enums may use this forbidden value -/// as a discriminant -- `Option>` has the same size as `Unique`. -/// However the pointer may still dangle if it isn't dereferenced. -/// -/// Unlike `*mut T`, `Unique` is covariant over `T`. This should always be correct -/// for any type which upholds Unique's aliasing requirements. -#[unstable(feature = "ptr_internals", issue = "0", - reason = "use NonNull instead and consider PhantomData \ - (if you also use #[may_dangle]), Send, and/or Sync")] -#[doc(hidden)] -#[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(1)] -pub struct Unique { - pointer: *const T, - // NOTE: this marker has no consequences for variance, but is necessary - // for dropck to understand that we logically own a `T`. - // - // For details, see: - // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data - _marker: PhantomData, -} - -#[unstable(feature = "ptr_internals", issue = "0")] -impl fmt::Debug for Unique { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Pointer::fmt(&self.as_ptr(), f) - } -} - -/// `Unique` pointers are `Send` if `T` is `Send` because the data they -/// reference is unaliased. Note that this aliasing invariant is -/// unenforced by the type system; the abstraction using the -/// `Unique` must enforce it. -#[unstable(feature = "ptr_internals", issue = "0")] -unsafe impl Send for Unique { } - -/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they -/// reference is unaliased. Note that this aliasing invariant is -/// unenforced by the type system; the abstraction using the -/// `Unique` must enforce it. -#[unstable(feature = "ptr_internals", issue = "0")] -unsafe impl Sync for Unique { } - -#[unstable(feature = "ptr_internals", issue = "0")] -impl Unique { - /// Creates a new `Unique` that is dangling, but well-aligned. - /// - /// This is useful for initializing types which lazily allocate, like - /// `Vec::new` does. - /// - /// Note that the pointer value may potentially represent a valid pointer to - /// a `T`, which means this must not be used as a "not yet initialized" - /// sentinel value. Types that lazily allocate must track initialization by - /// some other means. - // FIXME: rename to dangling() to match NonNull? - pub const fn empty() -> Self { - unsafe { - Unique::new_unchecked(mem::align_of::() as *mut T) - } - } -} - -#[unstable(feature = "ptr_internals", issue = "0")] -impl Unique { - /// Creates a new `Unique`. - /// - /// # Safety - /// - /// `ptr` must be non-null. - pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { - Unique { pointer: ptr as _, _marker: PhantomData } - } - - /// Creates a new `Unique` if `ptr` is non-null. - pub fn new(ptr: *mut T) -> Option { - if !ptr.is_null() { - Some(unsafe { Unique { pointer: ptr as _, _marker: PhantomData } }) - } else { - None - } - } - - /// Acquires the underlying `*mut` pointer. - pub fn as_ptr(self) -> *mut T { - self.pointer as *mut T - } - - /// Dereferences the content. - /// - /// The resulting lifetime is bound to self so this behaves "as if" - /// it were actually an instance of T that is getting borrowed. If a longer - /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. - pub unsafe fn as_ref(&self) -> &T { - &*self.as_ptr() - } - - /// Mutably dereferences the content. - /// - /// The resulting lifetime is bound to self so this behaves "as if" - /// it were actually an instance of T that is getting borrowed. If a longer - /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. - pub unsafe fn as_mut(&mut self) -> &mut T { - &mut *self.as_ptr() - } -} - -#[unstable(feature = "ptr_internals", issue = "0")] -impl Clone for Unique { - fn clone(&self) -> Self { - *self - } -} - -#[unstable(feature = "ptr_internals", issue = "0")] -impl Copy for Unique { } - -#[unstable(feature = "ptr_internals", issue = "0")] -impl CoerceUnsized> for Unique where T: Unsize { } - -#[unstable(feature = "ptr_internals", issue = "0")] -impl DispatchFromDyn> for Unique where T: Unsize { } - -#[unstable(feature = "ptr_internals", issue = "0")] -impl fmt::Pointer for Unique { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Pointer::fmt(&self.as_ptr(), f) - } -} - -#[unstable(feature = "ptr_internals", issue = "0")] -impl<'a, T: ?Sized> From<&'a mut T> for Unique { - fn from(reference: &'a mut T) -> Self { - unsafe { Unique { pointer: reference as *mut T, _marker: PhantomData } } - } -} - -#[unstable(feature = "ptr_internals", issue = "0")] -impl<'a, T: ?Sized> From<&'a T> for Unique { - fn from(reference: &'a T) -> Self { - unsafe { Unique { pointer: reference as *const T, _marker: PhantomData } } - } -} - -#[unstable(feature = "ptr_internals", issue = "0")] -impl<'a, T: ?Sized> From> for Unique { - fn from(p: NonNull) -> Self { - unsafe { Unique { pointer: p.pointer, _marker: PhantomData } } - } -} - -/// `*mut T` but non-zero and covariant. -/// -/// This is often the correct thing to use when building data structures using -/// raw pointers, but is ultimately more dangerous to use because of its additional -/// properties. If you're not sure if you should use `NonNull`, just use `*mut T`! -/// -/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer -/// is never dereferenced. This is so that enums may use this forbidden value -/// as a discriminant -- `Option>` has the same size as `*mut T`. -/// However the pointer may still dangle if it isn't dereferenced. -/// -/// Unlike `*mut T`, `NonNull` is covariant over `T`. If this is incorrect -/// for your use case, you should include some PhantomData in your type to -/// provide invariance, such as `PhantomData>` or `PhantomData<&'a mut T>`. -/// Usually this won't be necessary; covariance is correct for most safe abstractions, -/// such as Box, Rc, Arc, Vec, and LinkedList. This is the case because they -/// provide a public API that follows the normal shared XOR mutable rules of Rust. -#[stable(feature = "nonnull", since = "1.25.0")] -#[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(1)] -pub struct NonNull { - pointer: *const T, -} - -/// `NonNull` pointers are not `Send` because the data they reference may be aliased. -// N.B., this impl is unnecessary, but should provide better error messages. -#[stable(feature = "nonnull", since = "1.25.0")] -impl !Send for NonNull { } - -/// `NonNull` pointers are not `Sync` because the data they reference may be aliased. -// N.B., this impl is unnecessary, but should provide better error messages. -#[stable(feature = "nonnull", since = "1.25.0")] -impl !Sync for NonNull { } - -impl NonNull { - /// Creates a new `NonNull` that is dangling, but well-aligned. - /// - /// This is useful for initializing types which lazily allocate, like - /// `Vec::new` does. - /// - /// Note that the pointer value may potentially represent a valid pointer to - /// a `T`, which means this must not be used as a "not yet initialized" - /// sentinel value. Types that lazily allocate must track initialization by - /// some other means. - #[stable(feature = "nonnull", since = "1.25.0")] - #[inline] - pub fn dangling() -> Self { - unsafe { - let ptr = mem::align_of::() as *mut T; - NonNull::new_unchecked(ptr) - } - } -} - -impl NonNull { - /// Creates a new `NonNull`. - /// - /// # Safety - /// - /// `ptr` must be non-null. - #[stable(feature = "nonnull", since = "1.25.0")] - #[inline] - pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { - NonNull { pointer: ptr as _ } - } - - /// Creates a new `NonNull` if `ptr` is non-null. - #[stable(feature = "nonnull", since = "1.25.0")] - #[inline] - pub fn new(ptr: *mut T) -> Option { - if !ptr.is_null() { - Some(unsafe { Self::new_unchecked(ptr) }) - } else { - None - } - } - - /// Acquires the underlying `*mut` pointer. - #[stable(feature = "nonnull", since = "1.25.0")] - #[inline] - pub const fn as_ptr(self) -> *mut T { - self.pointer as *mut T - } - - /// Dereferences the content. - /// - /// The resulting lifetime is bound to self so this behaves "as if" - /// it were actually an instance of T that is getting borrowed. If a longer - /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. - #[stable(feature = "nonnull", since = "1.25.0")] - #[inline] - pub unsafe fn as_ref(&self) -> &T { - &*self.as_ptr() - } - - /// Mutably dereferences the content. - /// - /// The resulting lifetime is bound to self so this behaves "as if" - /// it were actually an instance of T that is getting borrowed. If a longer - /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. - #[stable(feature = "nonnull", since = "1.25.0")] - #[inline] - pub unsafe fn as_mut(&mut self) -> &mut T { - &mut *self.as_ptr() - } - - /// Cast to a pointer of another type - #[stable(feature = "nonnull_cast", since = "1.27.0")] - #[inline] - pub fn cast(self) -> NonNull { - unsafe { - NonNull::new_unchecked(self.as_ptr() as *mut U) - } - } -} - -#[stable(feature = "nonnull", since = "1.25.0")] -impl Clone for NonNull { - fn clone(&self) -> Self { - *self - } -} - -#[stable(feature = "nonnull", since = "1.25.0")] -impl Copy for NonNull { } - -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl CoerceUnsized> for NonNull where T: Unsize { } - -#[unstable(feature = "dispatch_from_dyn", issue = "0")] -impl DispatchFromDyn> for NonNull where T: Unsize { } - -#[stable(feature = "nonnull", since = "1.25.0")] -impl fmt::Debug for NonNull { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Pointer::fmt(&self.as_ptr(), f) - } -} - -#[stable(feature = "nonnull", since = "1.25.0")] -impl fmt::Pointer for NonNull { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Pointer::fmt(&self.as_ptr(), f) - } -} - -#[stable(feature = "nonnull", since = "1.25.0")] -impl Eq for NonNull {} - -#[stable(feature = "nonnull", since = "1.25.0")] -impl PartialEq for NonNull { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.as_ptr() == other.as_ptr() - } -} - -#[stable(feature = "nonnull", since = "1.25.0")] -impl Ord for NonNull { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - self.as_ptr().cmp(&other.as_ptr()) - } -} - -#[stable(feature = "nonnull", since = "1.25.0")] -impl PartialOrd for NonNull { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - self.as_ptr().partial_cmp(&other.as_ptr()) - } -} - -#[stable(feature = "nonnull", since = "1.25.0")] -impl hash::Hash for NonNull { - #[inline] - fn hash(&self, state: &mut H) { - self.as_ptr().hash(state) - } -} - -#[unstable(feature = "ptr_internals", issue = "0")] -impl From> for NonNull { - #[inline] - fn from(unique: Unique) -> Self { - unsafe { NonNull { pointer: unique.pointer } } - } -} - -#[stable(feature = "nonnull", since = "1.25.0")] -impl<'a, T: ?Sized> From<&'a mut T> for NonNull { - #[inline] - fn from(reference: &'a mut T) -> Self { - unsafe { NonNull { pointer: reference as *mut T } } - } -} - -#[stable(feature = "nonnull", since = "1.25.0")] -impl<'a, T: ?Sized> From<&'a T> for NonNull { - #[inline] - fn from(reference: &'a T) -> Self { - unsafe { NonNull { pointer: reference as *const T } } - } -} diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs new file mode 100644 index 0000000000000..fccb00d768cd8 --- /dev/null +++ b/src/libcore/ptr/mod.rs @@ -0,0 +1,2825 @@ +//! Manually manage memory through raw pointers. +//! +//! *[See also the pointer primitive types](../../std/primitive.pointer.html).* +//! +//! # Safety +//! +//! Many functions in this module take raw pointers as arguments and read from +//! or write to them. For this to be safe, these pointers must be *valid*. +//! Whether a pointer is valid depends on the operation it is used for +//! (read or write), and the extent of the memory that is accessed (i.e., +//! how many bytes are read/written). Most functions use `*mut T` and `*const T` +//! to access only a single value, in which case the documentation omits the size +//! and implicitly assumes it to be `size_of::()` bytes. +//! +//! The precise rules for validity are not determined yet. The guarantees that are +//! provided at this point are very minimal: +//! +//! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst]. +//! * All pointers (except for the null pointer) are valid for all operations of +//! [size zero][zst]. +//! * All accesses performed by functions in this module are *non-atomic* in the sense +//! of [atomic operations] used to synchronize between threads. This means it is +//! undefined behavior to perform two concurrent accesses to the same location from different +//! threads unless both accesses only read from memory. Notice that this explicitly +//! includes [`read_volatile`] and [`write_volatile`]: Volatile accesses cannot +//! be used for inter-thread synchronization. +//! * The result of casting a reference to a pointer is valid for as long as the +//! underlying object is live and no reference (just raw pointers) is used to +//! access the same memory. +//! +//! These axioms, along with careful use of [`offset`] for pointer arithmetic, +//! are enough to correctly implement many useful things in unsafe code. Stronger guarantees +//! will be provided eventually, as the [aliasing] rules are being determined. For more +//! information, see the [book] as well as the section in the reference devoted +//! to [undefined behavior][ub]. +//! +//! ## Alignment +//! +//! Valid raw pointers as defined above are not necessarily properly aligned (where +//! "proper" alignment is defined by the pointee type, i.e., `*const T` must be +//! aligned to `mem::align_of::()`). However, most functions require their +//! arguments to be properly aligned, and will explicitly state +//! this requirement in their documentation. Notable exceptions to this are +//! [`read_unaligned`] and [`write_unaligned`]. +//! +//! When a function requires proper alignment, it does so even if the access +//! has size 0, i.e., even if memory is not actually touched. Consider using +//! [`NonNull::dangling`] in such cases. +//! +//! [aliasing]: ../../nomicon/aliasing.html +//! [book]: ../../book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer +//! [ub]: ../../reference/behavior-considered-undefined.html +//! [null]: ./fn.null.html +//! [zst]: ../../nomicon/exotic-sizes.html#zero-sized-types-zsts +//! [atomic operations]: ../../std/sync/atomic/index.html +//! [`copy`]: ../../std/ptr/fn.copy.html +//! [`offset`]: ../../std/primitive.pointer.html#method.offset +//! [`read_unaligned`]: ./fn.read_unaligned.html +//! [`write_unaligned`]: ./fn.write_unaligned.html +//! [`read_volatile`]: ./fn.read_volatile.html +//! [`write_volatile`]: ./fn.write_volatile.html +//! [`NonNull::dangling`]: ./struct.NonNull.html#method.dangling + +#![stable(feature = "rust1", since = "1.0.0")] + +use crate::intrinsics; +use crate::fmt; +use crate::hash; +use crate::mem::{self, MaybeUninit}; +use crate::cmp::Ordering::{self, Less, Equal, Greater}; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::intrinsics::copy_nonoverlapping; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::intrinsics::copy; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::intrinsics::write_bytes; + +mod non_null; +#[stable(feature = "nonnull", since = "1.25.0")] +pub use non_null::NonNull; + +mod unique; +#[unstable(feature = "ptr_internals", issue = "0")] +pub use unique::Unique; + +/// Executes the destructor (if any) of the pointed-to value. +/// +/// This is semantically equivalent to calling [`ptr::read`] and discarding +/// the result, but has the following advantages: +/// +/// * It is *required* to use `drop_in_place` to drop unsized types like +/// trait objects, because they can't be read out onto the stack and +/// dropped normally. +/// +/// * It is friendlier to the optimizer to do this over [`ptr::read`] when +/// dropping manually allocated memory (e.g., when writing Box/Rc/Vec), +/// as the compiler doesn't need to prove that it's sound to elide the +/// copy. +/// +/// [`ptr::read`]: ../ptr/fn.read.html +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `to_drop` must be [valid] for reads. +/// +/// * `to_drop` must be properly aligned. See the example below for how to drop +/// an unaligned pointer. +/// +/// Additionally, if `T` is not [`Copy`], using the pointed-to value after +/// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop = +/// foo` counts as a use because it will cause the value to be dropped +/// again. [`write`] can be used to overwrite data without causing it to be +/// dropped. +/// +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. +/// +/// [valid]: ../ptr/index.html#safety +/// [`Copy`]: ../marker/trait.Copy.html +/// [`write`]: ../ptr/fn.write.html +/// +/// # Examples +/// +/// Manually remove the last item from a vector: +/// +/// ``` +/// use std::ptr; +/// use std::rc::Rc; +/// +/// let last = Rc::new(1); +/// let weak = Rc::downgrade(&last); +/// +/// let mut v = vec![Rc::new(0), last]; +/// +/// unsafe { +/// // Get a raw pointer to the last element in `v`. +/// let ptr = &mut v[1] as *mut _; +/// // Shorten `v` to prevent the last item from being dropped. We do that first, +/// // to prevent issues if the `drop_in_place` below panics. +/// v.set_len(1); +/// // Without a call `drop_in_place`, the last item would never be dropped, +/// // and the memory it manages would be leaked. +/// ptr::drop_in_place(ptr); +/// } +/// +/// assert_eq!(v, &[0.into()]); +/// +/// // Ensure that the last item was dropped. +/// 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(to_drop: *mut T) { +/// let mut copy: MaybeUninit = MaybeUninit::uninit(); +/// ptr::copy(to_drop, copy.as_mut_ptr(), 1); +/// drop(copy.assume_init()); +/// } +/// +/// #[repr(packed, C)] +/// struct Packed { +/// _padding: u8, +/// unaligned: Vec, +/// } +/// +/// 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. +#[stable(feature = "drop_in_place", since = "1.8.0")] +#[inline(always)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + real_drop_in_place(&mut *to_drop) +} + +// The real `drop_in_place` -- the one that gets called implicitly when variables go +// out of scope -- should have a safe reference and not a raw pointer as argument +// type. When we drop a local variable, we access it with a pointer that behaves +// like a safe reference; transmuting that to a raw pointer does not mean we can +// actually access it with raw pointers. +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +unsafe fn real_drop_in_place(to_drop: &mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + real_drop_in_place(to_drop) +} + +/// Creates a null raw pointer. +/// +/// # Examples +/// +/// ``` +/// use std::ptr; +/// +/// let p: *const i32 = ptr::null(); +/// assert!(p.is_null()); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_promotable] +pub const fn null() -> *const T { 0 as *const T } + +/// Creates a null mutable raw pointer. +/// +/// # Examples +/// +/// ``` +/// use std::ptr; +/// +/// let p: *mut i32 = ptr::null_mut(); +/// assert!(p.is_null()); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_promotable] +pub const fn null_mut() -> *mut T { 0 as *mut T } + +#[repr(C)] +pub(crate) union Repr { + pub(crate) rust: *const [T], + rust_mut: *mut [T], + pub(crate) raw: FatPtr, +} + +#[repr(C)] +pub(crate) struct FatPtr { + data: *const T, + pub(crate) len: usize, +} + +/// Forms a slice from a pointer and a length. +/// +/// The `len` argument is the number of **elements**, not the number of bytes. +/// +/// # Examples +/// +/// ```rust +/// #![feature(slice_from_raw_parts)] +/// use std::ptr; +/// +/// // create a slice pointer when starting out with a pointer to the first element +/// let mut x = [5, 6, 7]; +/// let ptr = &mut x[0] as *mut _; +/// let slice = ptr::slice_from_raw_parts_mut(ptr, 3); +/// assert_eq!(unsafe { &*slice }[2], 7); +/// ``` +#[inline] +#[unstable(feature = "slice_from_raw_parts", reason = "recently added", issue = "36925")] +pub fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { + unsafe { Repr { raw: FatPtr { data, len } }.rust } +} + +/// Performs the same functionality as [`from_raw_parts`], except that a +/// mutable slice is returned. +/// +/// See the documentation of [`from_raw_parts`] for more details. +/// +/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html +#[inline] +#[unstable(feature = "slice_from_raw_parts", reason = "recently added", issue = "36925")] +pub fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { + unsafe { Repr { raw: FatPtr { data, len } }.rust_mut } +} + +/// Swaps the values at two mutable locations of the same type, without +/// deinitializing either. +/// +/// But for the following two exceptions, this function is semantically +/// equivalent to [`mem::swap`]: +/// +/// * It operates on raw pointers instead of references. When references are +/// available, [`mem::swap`] should be preferred. +/// +/// * The two pointed-to values may overlap. If the values do overlap, then the +/// overlapping region of memory from `x` will be used. This is demonstrated +/// in the second example below. +/// +/// [`mem::swap`]: ../mem/fn.swap.html +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * Both `x` and `y` must be [valid] for reads and writes. +/// +/// * Both `x` and `y` must be properly aligned. +/// +/// Note that even if `T` has size `0`, the pointers must be non-NULL and properly aligned. +/// +/// [valid]: ../ptr/index.html#safety +/// +/// # Examples +/// +/// Swapping two non-overlapping regions: +/// +/// ``` +/// use std::ptr; +/// +/// let mut array = [0, 1, 2, 3]; +/// +/// let x = array[0..].as_mut_ptr() as *mut [u32; 2]; // this is `array[0..2]` +/// let y = array[2..].as_mut_ptr() as *mut [u32; 2]; // this is `array[2..4]` +/// +/// unsafe { +/// ptr::swap(x, y); +/// assert_eq!([2, 3, 0, 1], array); +/// } +/// ``` +/// +/// Swapping two overlapping regions: +/// +/// ``` +/// use std::ptr; +/// +/// let mut array = [0, 1, 2, 3]; +/// +/// let x = array[0..].as_mut_ptr() as *mut [u32; 3]; // this is `array[0..3]` +/// let y = array[1..].as_mut_ptr() as *mut [u32; 3]; // this is `array[1..4]` +/// +/// unsafe { +/// ptr::swap(x, y); +/// // The indices `1..3` of the slice overlap between `x` and `y`. +/// // Reasonable results would be for to them be `[2, 3]`, so that indices `0..3` are +/// // `[1, 2, 3]` (matching `y` before the `swap`); or for them to be `[0, 1]` +/// // so that indices `1..4` are `[0, 1, 2]` (matching `x` before the `swap`). +/// // This implementation is defined to make the latter choice. +/// assert_eq!([1, 0, 1, 2], array); +/// } +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn swap(x: *mut T, y: *mut T) { + // Give ourselves some scratch space to work with. + // We do not have to worry about drops: `MaybeUninit` does nothing when dropped. + let mut tmp = MaybeUninit::::uninit(); + + // Perform the swap + copy_nonoverlapping(x, tmp.as_mut_ptr(), 1); + copy(y, x, 1); // `x` and `y` may overlap + copy_nonoverlapping(tmp.as_ptr(), y, 1); +} + +/// Swaps `count * size_of::()` bytes between the two regions of memory +/// beginning at `x` and `y`. The two regions must *not* overlap. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * Both `x` and `y` must be [valid] for reads and writes of `count * +/// size_of::()` bytes. +/// +/// * Both `x` and `y` must be properly aligned. +/// +/// * The region of memory beginning at `x` with a size of `count * +/// size_of::()` bytes must *not* overlap with the region of memory +/// beginning at `y` with the same size. +/// +/// Note that even if the effectively copied size (`count * size_of::()`) is `0`, +/// the pointers must be non-NULL and properly aligned. +/// +/// [valid]: ../ptr/index.html#safety +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::ptr; +/// +/// let mut x = [1, 2, 3, 4]; +/// let mut y = [7, 8, 9]; +/// +/// unsafe { +/// ptr::swap_nonoverlapping(x.as_mut_ptr(), y.as_mut_ptr(), 2); +/// } +/// +/// assert_eq!(x, [7, 8, 3, 4]); +/// assert_eq!(y, [1, 2, 9]); +/// ``` +#[inline] +#[stable(feature = "swap_nonoverlapping", since = "1.27.0")] +pub unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { + let x = x as *mut u8; + let y = y as *mut u8; + let len = mem::size_of::() * count; + swap_nonoverlapping_bytes(x, y, len) +} + +#[inline] +pub(crate) unsafe fn swap_nonoverlapping_one(x: *mut T, y: *mut T) { + // For types smaller than the block optimization below, + // just swap directly to avoid pessimizing codegen. + if mem::size_of::() < 32 { + let z = read(x); + copy_nonoverlapping(y, x, 1); + write(y, z); + } else { + swap_nonoverlapping(x, y, 1); + } +} + +#[inline] +unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { + // The approach here is to utilize simd to swap x & y efficiently. Testing reveals + // that swapping either 32 bytes or 64 bytes at a time is most efficient for Intel + // Haswell E processors. LLVM is more able to optimize if we give a struct a + // #[repr(simd)], even if we don't actually use this struct directly. + // + // FIXME repr(simd) broken on emscripten and redox + #[cfg_attr(not(any(target_os = "emscripten", target_os = "redox")), repr(simd))] + struct Block(u64, u64, u64, u64); + struct UnalignedBlock(u64, u64, u64, u64); + + let block_size = mem::size_of::(); + + // Loop through x & y, copying them `Block` at a time + // The optimizer should unroll the loop fully for most types + // N.B. We can't use a for loop as the `range` impl calls `mem::swap` recursively + let mut i = 0; + while i + block_size <= len { + // Create some uninitialized memory as scratch space + // Declaring `t` here avoids aligning the stack when this loop is unused + let mut t = mem::MaybeUninit::::uninit(); + let t = t.as_mut_ptr() as *mut u8; + let x = x.add(i); + let y = y.add(i); + + // Swap a block of bytes of x & y, using t as a temporary buffer + // This should be optimized into efficient SIMD operations where available + copy_nonoverlapping(x, t, block_size); + copy_nonoverlapping(y, x, block_size); + copy_nonoverlapping(t, y, block_size); + i += block_size; + } + + if i < len { + // Swap any remaining bytes + let mut t = mem::MaybeUninit::::uninit(); + let rem = len - i; + + let t = t.as_mut_ptr() as *mut u8; + let x = x.add(i); + let y = y.add(i); + + copy_nonoverlapping(x, t, rem); + copy_nonoverlapping(y, x, rem); + copy_nonoverlapping(t, y, rem); + } +} + +/// Moves `src` into the pointed `dst`, returning the previous `dst` value. +/// +/// Neither value is dropped. +/// +/// This function is semantically equivalent to [`mem::replace`] except that it +/// operates on raw pointers instead of references. When references are +/// available, [`mem::replace`] should be preferred. +/// +/// [`mem::replace`]: ../mem/fn.replace.html +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dst` must be [valid] for writes. +/// +/// * `dst` must be properly aligned. +/// +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. +/// +/// [valid]: ../ptr/index.html#safety +/// +/// # Examples +/// +/// ``` +/// use std::ptr; +/// +/// let mut rust = vec!['b', 'u', 's', 't']; +/// +/// // `mem::replace` would have the same effect without requiring the unsafe +/// // block. +/// let b = unsafe { +/// ptr::replace(&mut rust[0], 'r') +/// }; +/// +/// assert_eq!(b, 'b'); +/// assert_eq!(rust, &['r', 'u', 's', 't']); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn replace(dst: *mut T, mut src: T) -> T { + mem::swap(&mut *dst, &mut src); // cannot overlap + src +} + +/// Reads the value from `src` without moving it. This leaves the +/// memory in `src` unchanged. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads. +/// +/// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the +/// case. +/// +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let x = 12; +/// let y = &x as *const i32; +/// +/// unsafe { +/// assert_eq!(std::ptr::read(y), 12); +/// } +/// ``` +/// +/// Manually implement [`mem::swap`]: +/// +/// ``` +/// use std::ptr; +/// +/// fn swap(a: &mut T, b: &mut T) { +/// unsafe { +/// // Create a bitwise copy of the value at `a` in `tmp`. +/// let tmp = ptr::read(a); +/// +/// // Exiting at this point (either by explicitly returning or by +/// // calling a function which panics) would cause the value in `tmp` to +/// // be dropped while the same value is still referenced by `a`. This +/// // could trigger undefined behavior if `T` is not `Copy`. +/// +/// // Create a bitwise copy of the value at `b` in `a`. +/// // This is safe because mutable references cannot alias. +/// ptr::copy_nonoverlapping(b, a, 1); +/// +/// // As above, exiting here could trigger undefined behavior because +/// // the same value is referenced by `a` and `b`. +/// +/// // Move `tmp` into `b`. +/// ptr::write(b, tmp); +/// +/// // `tmp` has been moved (`write` takes ownership of its second argument), +/// // so nothing is dropped implicitly here. +/// } +/// } +/// +/// let mut foo = "foo".to_owned(); +/// let mut bar = "bar".to_owned(); +/// +/// swap(&mut foo, &mut bar); +/// +/// assert_eq!(foo, "bar"); +/// assert_eq!(bar, "foo"); +/// ``` +/// +/// ## Ownership of the Returned Value +/// +/// `read` creates a bitwise copy of `T`, regardless of whether `T` is [`Copy`]. +/// If `T` is not [`Copy`], using both the returned value and the value at +/// `*src` can violate memory safety. Note that assigning to `*src` counts as a +/// use because it will attempt to drop the value at `*src`. +/// +/// [`write`] can be used to overwrite data without causing it to be dropped. +/// +/// ``` +/// use std::ptr; +/// +/// let mut s = String::from("foo"); +/// unsafe { +/// // `s2` now points to the same underlying memory as `s`. +/// let mut s2: String = ptr::read(&s); +/// +/// assert_eq!(s2, "foo"); +/// +/// // Assigning to `s2` causes its original value to be dropped. Beyond +/// // this point, `s` must no longer be used, as the underlying memory has +/// // been freed. +/// s2 = String::default(); +/// assert_eq!(s2, ""); +/// +/// // Assigning to `s` would cause the old value to be dropped again, +/// // resulting in undefined behavior. +/// // s = String::from("bar"); // ERROR +/// +/// // `ptr::write` can be used to overwrite a value without dropping it. +/// ptr::write(&mut s, String::from("bar")); +/// } +/// +/// assert_eq!(s, "bar"); +/// ``` +/// +/// [`mem::swap`]: ../mem/fn.swap.html +/// [valid]: ../ptr/index.html#safety +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read_unaligned`]: ./fn.read_unaligned.html +/// [`write`]: ./fn.write.html +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn read(src: *const T) -> T { + let mut tmp = MaybeUninit::::uninit(); + copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); + tmp.assume_init() +} + +/// Reads the value from `src` without moving it. This leaves the +/// memory in `src` unchanged. +/// +/// Unlike [`read`], `read_unaligned` works with unaligned pointers. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads. +/// +/// Like [`read`], `read_unaligned` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned +/// value and the value at `*src` can [violate memory safety][read-ownership]. +/// +/// Note that even if `T` has size `0`, the pointer must be non-NULL. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read`]: ./fn.read.html +/// [`write_unaligned`]: ./fn.write_unaligned.html +/// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value +/// [valid]: ../ptr/index.html#safety +/// +/// # Examples +/// +/// Access members of a packed struct by reference: +/// +/// ``` +/// use std::ptr; +/// +/// #[repr(packed, C)] +/// struct Packed { +/// _padding: u8, +/// unaligned: u32, +/// } +/// +/// let x = Packed { +/// _padding: 0x00, +/// unaligned: 0x01020304, +/// }; +/// +/// let v = unsafe { +/// // Take the address of a 32-bit integer which is not aligned. +/// // This must be done as a raw pointer; unaligned references are invalid. +/// let unaligned = &x.unaligned as *const u32; +/// +/// // Dereferencing normally will emit an aligned load instruction, +/// // causing undefined behavior. +/// // let v = *unaligned; // ERROR +/// +/// // Instead, use `read_unaligned` to read improperly aligned values. +/// let v = ptr::read_unaligned(unaligned); +/// +/// v +/// }; +/// +/// // Accessing unaligned values directly is safe. +/// assert!(x.unaligned == v); +/// ``` +#[inline] +#[stable(feature = "ptr_unaligned", since = "1.17.0")] +pub unsafe fn read_unaligned(src: *const T) -> T { + let mut tmp = MaybeUninit::::uninit(); + copy_nonoverlapping(src as *const u8, + tmp.as_mut_ptr() as *mut u8, + mem::size_of::()); + tmp.assume_init() +} + +/// Overwrites a memory location with the given value without reading or +/// dropping the old value. +/// +/// `write` does not drop the contents of `dst`. This is safe, but it could leak +/// allocations or resources, so care should be taken not to overwrite an object +/// that should be dropped. +/// +/// Additionally, it does not drop `src`. Semantically, `src` is moved into the +/// location pointed to by `dst`. +/// +/// This is appropriate for initializing uninitialized memory, or overwriting +/// memory that has previously been [`read`] from. +/// +/// [`read`]: ./fn.read.html +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dst` must be [valid] for writes. +/// +/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the +/// case. +/// +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. +/// +/// [valid]: ../ptr/index.html#safety +/// [`write_unaligned`]: ./fn.write_unaligned.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let mut x = 0; +/// let y = &mut x as *mut i32; +/// let z = 12; +/// +/// unsafe { +/// std::ptr::write(y, z); +/// assert_eq!(std::ptr::read(y), 12); +/// } +/// ``` +/// +/// Manually implement [`mem::swap`]: +/// +/// ``` +/// use std::ptr; +/// +/// fn swap(a: &mut T, b: &mut T) { +/// unsafe { +/// // Create a bitwise copy of the value at `a` in `tmp`. +/// let tmp = ptr::read(a); +/// +/// // Exiting at this point (either by explicitly returning or by +/// // calling a function which panics) would cause the value in `tmp` to +/// // be dropped while the same value is still referenced by `a`. This +/// // could trigger undefined behavior if `T` is not `Copy`. +/// +/// // Create a bitwise copy of the value at `b` in `a`. +/// // This is safe because mutable references cannot alias. +/// ptr::copy_nonoverlapping(b, a, 1); +/// +/// // As above, exiting here could trigger undefined behavior because +/// // the same value is referenced by `a` and `b`. +/// +/// // Move `tmp` into `b`. +/// ptr::write(b, tmp); +/// +/// // `tmp` has been moved (`write` takes ownership of its second argument), +/// // so nothing is dropped implicitly here. +/// } +/// } +/// +/// let mut foo = "foo".to_owned(); +/// let mut bar = "bar".to_owned(); +/// +/// swap(&mut foo, &mut bar); +/// +/// assert_eq!(foo, "bar"); +/// assert_eq!(bar, "foo"); +/// ``` +/// +/// [`mem::swap`]: ../mem/fn.swap.html +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn write(dst: *mut T, src: T) { + intrinsics::move_val_init(&mut *dst, src) +} + +/// Overwrites a memory location with the given value without reading or +/// dropping the old value. +/// +/// Unlike [`write`], the pointer may be unaligned. +/// +/// `write_unaligned` does not drop the contents of `dst`. This is safe, but it +/// could leak allocations or resources, so care should be taken not to overwrite +/// an object that should be dropped. +/// +/// Additionally, it does not drop `src`. Semantically, `src` is moved into the +/// location pointed to by `dst`. +/// +/// This is appropriate for initializing uninitialized memory, or overwriting +/// memory that has previously been read with [`read_unaligned`]. +/// +/// [`write`]: ./fn.write.html +/// [`read_unaligned`]: ./fn.read_unaligned.html +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dst` must be [valid] for writes. +/// +/// Note that even if `T` has size `0`, the pointer must be non-NULL. +/// +/// [valid]: ../ptr/index.html#safety +/// +/// # Examples +/// +/// Access fields in a packed struct: +/// +/// ``` +/// use std::{mem, ptr}; +/// +/// #[repr(packed, C)] +/// #[derive(Default)] +/// struct Packed { +/// _padding: u8, +/// unaligned: u32, +/// } +/// +/// let v = 0x01020304; +/// let mut x: Packed = unsafe { mem::zeroed() }; +/// +/// unsafe { +/// // Take a reference to a 32-bit integer which is not aligned. +/// let unaligned = &mut x.unaligned as *mut u32; +/// +/// // Dereferencing normally will emit an aligned store instruction, +/// // causing undefined behavior because the pointer is not aligned. +/// // *unaligned = v; // ERROR +/// +/// // Instead, use `write_unaligned` to write improperly aligned values. +/// ptr::write_unaligned(unaligned, v); +/// } +/// +/// // Accessing unaligned values directly is safe. +/// assert!(x.unaligned == v); +/// ``` +#[inline] +#[stable(feature = "ptr_unaligned", since = "1.17.0")] +pub unsafe fn write_unaligned(dst: *mut T, src: T) { + copy_nonoverlapping(&src as *const T as *const u8, + dst as *mut u8, + mem::size_of::()); + mem::forget(src); +} + +/// Performs a volatile read of the value from `src` without moving it. This +/// leaves the memory in `src` unchanged. +/// +/// Volatile operations are intended to act on I/O memory, and are guaranteed +/// to not be elided or reordered by the compiler across other volatile +/// operations. +/// +/// [`write_volatile`]: ./fn.write_volatile.html +/// +/// # Notes +/// +/// Rust does not currently have a rigorously and formally defined memory model, +/// so the precise semantics of what "volatile" means here is subject to change +/// over time. That being said, the semantics will almost always end up pretty +/// similar to [C11's definition of volatile][c11]. +/// +/// The compiler shouldn't change the relative order or number of volatile +/// memory operations. However, volatile memory operations on zero-sized types +/// (e.g., if a zero-sized type is passed to `read_volatile`) are noops +/// and may be ignored. +/// +/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads. +/// +/// * `src` must be properly aligned. +/// +/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned +/// value and the value at `*src` can [violate memory safety][read-ownership]. +/// However, storing non-[`Copy`] types in volatile memory is almost certainly +/// incorrect. +/// +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. +/// +/// [valid]: ../ptr/index.html#safety +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read`]: ./fn.read.html +/// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value +/// +/// Just like in C, whether an operation is volatile has no bearing whatsoever +/// on questions involving concurrent access from multiple threads. Volatile +/// accesses behave exactly like non-atomic accesses in that regard. In particular, +/// a race between a `read_volatile` and any write operation to the same location +/// is undefined behavior. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let x = 12; +/// let y = &x as *const i32; +/// +/// unsafe { +/// assert_eq!(std::ptr::read_volatile(y), 12); +/// } +/// ``` +#[inline] +#[stable(feature = "volatile", since = "1.9.0")] +pub unsafe fn read_volatile(src: *const T) -> T { + intrinsics::volatile_load(src) +} + +/// Performs a volatile write of a memory location with the given value without +/// reading or dropping the old value. +/// +/// Volatile operations are intended to act on I/O memory, and are guaranteed +/// to not be elided or reordered by the compiler across other volatile +/// operations. +/// +/// `write_volatile` does not drop the contents of `dst`. This is safe, but it +/// could leak allocations or resources, so care should be taken not to overwrite +/// an object that should be dropped. +/// +/// Additionally, it does not drop `src`. Semantically, `src` is moved into the +/// location pointed to by `dst`. +/// +/// [`read_volatile`]: ./fn.read_volatile.html +/// +/// # Notes +/// +/// Rust does not currently have a rigorously and formally defined memory model, +/// so the precise semantics of what "volatile" means here is subject to change +/// over time. That being said, the semantics will almost always end up pretty +/// similar to [C11's definition of volatile][c11]. +/// +/// The compiler shouldn't change the relative order or number of volatile +/// memory operations. However, volatile memory operations on zero-sized types +/// (e.g., if a zero-sized type is passed to `write_volatile`) are noops +/// and may be ignored. +/// +/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dst` must be [valid] for writes. +/// +/// * `dst` must be properly aligned. +/// +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. +/// +/// [valid]: ../ptr/index.html#safety +/// +/// Just like in C, whether an operation is volatile has no bearing whatsoever +/// on questions involving concurrent access from multiple threads. Volatile +/// accesses behave exactly like non-atomic accesses in that regard. In particular, +/// a race between a `write_volatile` and any other operation (reading or writing) +/// on the same location is undefined behavior. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let mut x = 0; +/// let y = &mut x as *mut i32; +/// let z = 12; +/// +/// unsafe { +/// std::ptr::write_volatile(y, z); +/// assert_eq!(std::ptr::read_volatile(y), 12); +/// } +/// ``` +#[inline] +#[stable(feature = "volatile", since = "1.9.0")] +pub unsafe fn write_volatile(dst: *mut T, src: T) { + intrinsics::volatile_store(dst, src); +} + +#[lang = "const_ptr"] +impl *const T { + /// Returns `true` if the pointer is null. + /// + /// Note that unsized types have many possible null pointers, as only the + /// raw data pointer is considered, not their length, vtable, etc. + /// Therefore, two pointers that are null may still not compare equal to + /// each other. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s: &str = "Follow the rabbit"; + /// let ptr: *const u8 = s.as_ptr(); + /// assert!(!ptr.is_null()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_null(self) -> bool { + // Compare via a cast to a thin pointer, so fat pointers are only + // considering their "data" part for null-ness. + (self as *const u8) == null() + } + + /// Cast to a pointer to a different type + #[unstable(feature = "ptr_cast", issue = "60602")] + #[inline] + pub const fn cast(self) -> *const U { + self as _ + } + + /// Returns `None` if the pointer is null, or else returns a reference to + /// the value wrapped in `Some`. + /// + /// # Safety + /// + /// While this method and its mutable counterpart are useful for + /// null-safety, it is important to note that this is still an unsafe + /// operation because the returned value could be pointing to invalid + /// memory. + /// + /// When calling this method, you have to ensure that if the pointer is + /// non-NULL, then it is properly aligned, dereferencable (for the whole + /// size of `T`) and points to an initialized instance of `T`. This applies + /// even if the result of this method is unused! + /// (The part about being initialized is not yet fully decided, but until + /// it is, the only safe approach is to ensure that they are indeed initialized.) + /// + /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does + /// not necessarily reflect the actual lifetime of the data. It is up to the + /// caller to ensure that for the duration of this lifetime, the memory this + /// pointer points to does not get written to outside of `UnsafeCell`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let ptr: *const u8 = &10u8 as *const u8; + /// + /// unsafe { + /// if let Some(val_back) = ptr.as_ref() { + /// println!("We got back the value: {}!", val_back); + /// } + /// } + /// ``` + /// + /// # Null-unchecked version + /// + /// If you are sure the pointer can never be null and are looking for some kind of + /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can + /// dereference the pointer directly. + /// + /// ``` + /// let ptr: *const u8 = &10u8 as *const u8; + /// + /// unsafe { + /// let val_back = &*ptr; + /// println!("We got back the value: {}!", val_back); + /// } + /// ``` + #[stable(feature = "ptr_as_ref", since = "1.9.0")] + #[inline] + pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { + if self.is_null() { + None + } else { + Some(&*self) + } + } + + /// Calculates the offset from a pointer. + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same allocated object. + /// + /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using `wrapping_offset` instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s: &str = "123"; + /// let ptr: *const u8 = s.as_ptr(); + /// + /// unsafe { + /// println!("{}", *ptr.offset(1) as char); + /// println!("{}", *ptr.offset(2) as char); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub unsafe fn offset(self, count: isize) -> *const T where T: Sized { + intrinsics::offset(self, count) + } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// In particular, the resulting pointer may *not* be used to access a + /// different allocated object than the one `self` points to. In other + /// words, `x.wrapping_offset(y.wrapping_offset_from(x))` is + /// *not* the same as `y`, and dereferencing it is undefined behavior + /// unless `x` and `y` point into the same allocated object. + /// + /// Always use `.offset(count)` instead when possible, because `offset` + /// allows the compiler to optimize better. If you need to cross object + /// boundaries, cast the pointer to an integer and do the arithmetic there. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // Iterate using a raw pointer in increments of two elements + /// let data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *const u8 = data.as_ptr(); + /// let step = 2; + /// let end_rounded_up = ptr.wrapping_offset(6); + /// + /// // This loop prints "1, 3, 5, " + /// while ptr != end_rounded_up { + /// unsafe { + /// print!("{}, ", *ptr); + /// } + /// ptr = ptr.wrapping_offset(step); + /// } + /// ``` + #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] + #[inline] + pub fn wrapping_offset(self, count: isize) -> *const T where T: Sized { + unsafe { + intrinsics::arith_offset(self, count) + } + } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// This function is the inverse of [`offset`]. + /// + /// [`offset`]: #method.offset + /// [`wrapping_offset_from`]: #method.wrapping_offset_from + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and other pointer must be either in bounds or one + /// byte past the end of the same allocated object. + /// + /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. + /// + /// * The distance between the pointers, in bytes, must be an exact multiple + /// of the size of `T`. + /// + /// * The distance being in bounds cannot rely on "wrapping around" the address space. + /// + /// The compiler and standard library generally try to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `ptr_into_vec.offset_from(vec.as_ptr())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_offset_from`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Panics + /// + /// This function panics if `T` is a Zero-Sized Type ("ZST"). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_offset_from)] + /// + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// unsafe { + /// assert_eq!(ptr2.offset_from(ptr1), 2); + /// assert_eq!(ptr1.offset_from(ptr2), -2); + /// assert_eq!(ptr1.offset(2), ptr2); + /// assert_eq!(ptr2.offset(-2), ptr1); + /// } + /// ``` + #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[inline] + pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { + let pointee_size = mem::size_of::(); + assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); + + // This is the same sequence that Clang emits for pointer subtraction. + // It can be neither `nsw` nor `nuw` because the input is treated as + // unsigned but then the output is treated as signed, so neither works. + let d = isize::wrapping_sub(self as _, origin as _); + intrinsics::exact_div(d, pointee_size as _) + } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// If the address different between the two pointers is not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// Though this method is safe for any two pointers, note that its result + /// will be mostly useless if the two pointers aren't into the same allocated + /// object, for example if they point to two different local variables. + /// + /// # Panics + /// + /// This function panics if `T` is a zero-sized type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_wrapping_offset_from)] + /// + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); + /// assert_eq!(ptr1.wrapping_offset(2), ptr2); + /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); + /// + /// let ptr1: *const i32 = 3 as _; + /// let ptr2: *const i32 = 13 as _; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// ``` + #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] + #[inline] + pub fn wrapping_offset_from(self, origin: *const T) -> isize where T: Sized { + let pointee_size = mem::size_of::(); + assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); + + let d = isize::wrapping_sub(self as _, origin as _); + d.wrapping_div(pointee_size as _) + } + + /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same allocated object. + /// + /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum must fit in a `usize`. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using `wrapping_offset` instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s: &str = "123"; + /// let ptr: *const u8 = s.as_ptr(); + /// + /// unsafe { + /// println!("{}", *ptr.add(1) as char); + /// println!("{}", *ptr.add(2) as char); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn add(self, count: usize) -> Self + where T: Sized, + { + self.offset(count as isize) + } + + /// Calculates the offset from a pointer (convenience for + /// `.offset((count as isize).wrapping_neg())`). + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same allocated object. + /// + /// * The computed offset cannot exceed `isize::MAX` **bytes**. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum must fit in a usize. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using `wrapping_offset` instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s: &str = "123"; + /// + /// unsafe { + /// let end: *const u8 = s.as_ptr().add(3); + /// println!("{}", *end.sub(1) as char); + /// println!("{}", *end.sub(2) as char); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn sub(self, count: usize) -> Self + where T: Sized, + { + self.offset((count as isize).wrapping_neg()) + } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// (convenience for `.wrapping_offset(count as isize)`) + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// Always use `.add(count)` instead when possible, because `add` + /// allows the compiler to optimize better. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // Iterate using a raw pointer in increments of two elements + /// let data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *const u8 = data.as_ptr(); + /// let step = 2; + /// let end_rounded_up = ptr.wrapping_add(6); + /// + /// // This loop prints "1, 3, 5, " + /// while ptr != end_rounded_up { + /// unsafe { + /// print!("{}, ", *ptr); + /// } + /// ptr = ptr.wrapping_add(step); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub fn wrapping_add(self, count: usize) -> Self + where T: Sized, + { + self.wrapping_offset(count as isize) + } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`) + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// Always use `.sub(count)` instead when possible, because `sub` + /// allows the compiler to optimize better. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // Iterate using a raw pointer in increments of two elements (backwards) + /// let data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *const u8 = data.as_ptr(); + /// let start_rounded_down = ptr.wrapping_sub(2); + /// ptr = ptr.wrapping_add(4); + /// let step = 2; + /// // This loop prints "5, 3, 1, " + /// while ptr != start_rounded_down { + /// unsafe { + /// print!("{}, ", *ptr); + /// } + /// ptr = ptr.wrapping_sub(step); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub fn wrapping_sub(self, count: usize) -> Self + where T: Sized, + { + self.wrapping_offset((count as isize).wrapping_neg()) + } + + /// Reads the value from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// See [`ptr::read`] for safety concerns and examples. + /// + /// [`ptr::read`]: ./ptr/fn.read.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn read(self) -> T + where T: Sized, + { + read(self) + } + + /// Performs a volatile read of the value from `self` without moving it. This + /// leaves the memory in `self` unchanged. + /// + /// Volatile operations are intended to act on I/O memory, and are guaranteed + /// to not be elided or reordered by the compiler across other volatile + /// operations. + /// + /// See [`ptr::read_volatile`] for safety concerns and examples. + /// + /// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn read_volatile(self) -> T + where T: Sized, + { + read_volatile(self) + } + + /// Reads the value from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// Unlike `read`, the pointer may be unaligned. + /// + /// See [`ptr::read_unaligned`] for safety concerns and examples. + /// + /// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn read_unaligned(self) -> T + where T: Sized, + { + read_unaligned(self) + } + + /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// and destination may overlap. + /// + /// NOTE: this has the *same* argument order as [`ptr::copy`]. + /// + /// See [`ptr::copy`] for safety concerns and examples. + /// + /// [`ptr::copy`]: ./ptr/fn.copy.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn copy_to(self, dest: *mut T, count: usize) + where T: Sized, + { + copy(self, dest, count) + } + + /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// and destination may *not* overlap. + /// + /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. + /// + /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. + /// + /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) + where T: Sized, + { + copy_nonoverlapping(self, dest, count) + } + + /// Computes the offset that needs to be applied to the pointer in order to make it aligned to + /// `align`. + /// + /// If it is not possible to align the pointer, the implementation returns + /// `usize::max_value()`. + /// + /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be + /// used with the `offset` or `offset_to` methods. + /// + /// There are no guarantees whatsover that offsetting the pointer will not overflow or go + /// beyond the allocation that the pointer points into. It is up to the caller to ensure that + /// the returned offset is correct in all terms other than alignment. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two. + /// + /// # Examples + /// + /// Accessing adjacent `u8` as `u16` + /// + /// ``` + /// # fn foo(n: usize) { + /// # use std::mem::align_of; + /// # unsafe { + /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; + /// let ptr = &x[n] as *const u8; + /// let offset = ptr.align_offset(align_of::()); + /// if offset < x.len() - n - 1 { + /// let u16_ptr = ptr.add(offset) as *const u16; + /// assert_ne!(*u16_ptr, 500); + /// } else { + /// // while the pointer can be aligned via `offset`, it would point + /// // outside the allocation + /// } + /// # } } + /// ``` + #[stable(feature = "align_offset", since = "1.36.0")] + pub fn align_offset(self, align: usize) -> usize where T: Sized { + if !align.is_power_of_two() { + panic!("align_offset: align is not a power-of-two"); + } + unsafe { + align_offset(self, align) + } + } +} + + +#[lang = "mut_ptr"] +impl *mut T { + /// Returns `true` if the pointer is null. + /// + /// Note that unsized types have many possible null pointers, as only the + /// raw data pointer is considered, not their length, vtable, etc. + /// Therefore, two pointers that are null may still not compare equal to + /// each other. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = [1, 2, 3]; + /// let ptr: *mut u32 = s.as_mut_ptr(); + /// assert!(!ptr.is_null()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_null(self) -> bool { + // Compare via a cast to a thin pointer, so fat pointers are only + // considering their "data" part for null-ness. + (self as *mut u8) == null_mut() + } + + /// Cast to a pointer to a different type + #[unstable(feature = "ptr_cast", issue = "60602")] + #[inline] + pub const fn cast(self) -> *mut U { + self as _ + } + + /// Returns `None` if the pointer is null, or else returns a reference to + /// the value wrapped in `Some`. + /// + /// # Safety + /// + /// While this method and its mutable counterpart are useful for + /// null-safety, it is important to note that this is still an unsafe + /// operation because the returned value could be pointing to invalid + /// memory. + /// + /// When calling this method, you have to ensure that if the pointer is + /// non-NULL, then it is properly aligned, dereferencable (for the whole + /// size of `T`) and points to an initialized instance of `T`. This applies + /// even if the result of this method is unused! + /// (The part about being initialized is not yet fully decided, but until + /// it is, the only safe approach is to ensure that they are indeed initialized.) + /// + /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does + /// not necessarily reflect the actual lifetime of the data. It is up to the + /// caller to ensure that for the duration of this lifetime, the memory this + /// pointer points to does not get written to outside of `UnsafeCell`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let ptr: *mut u8 = &mut 10u8 as *mut u8; + /// + /// unsafe { + /// if let Some(val_back) = ptr.as_ref() { + /// println!("We got back the value: {}!", val_back); + /// } + /// } + /// ``` + /// + /// # Null-unchecked version + /// + /// If you are sure the pointer can never be null and are looking for some kind of + /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can + /// dereference the pointer directly. + /// + /// ``` + /// let ptr: *mut u8 = &mut 10u8 as *mut u8; + /// + /// unsafe { + /// let val_back = &*ptr; + /// println!("We got back the value: {}!", val_back); + /// } + /// ``` + #[stable(feature = "ptr_as_ref", since = "1.9.0")] + #[inline] + pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { + if self.is_null() { + None + } else { + Some(&*self) + } + } + + /// Calculates the offset from a pointer. + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same allocated object. + /// + /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using `wrapping_offset` instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = [1, 2, 3]; + /// let ptr: *mut u32 = s.as_mut_ptr(); + /// + /// unsafe { + /// println!("{}", *ptr.offset(1)); + /// println!("{}", *ptr.offset(2)); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub unsafe fn offset(self, count: isize) -> *mut T where T: Sized { + intrinsics::offset(self, count) as *mut T + } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// In particular, the resulting pointer may *not* be used to access a + /// different allocated object than the one `self` points to. In other + /// words, `x.wrapping_offset(y.wrapping_offset_from(x))` is + /// *not* the same as `y`, and dereferencing it is undefined behavior + /// unless `x` and `y` point into the same allocated object. + /// + /// Always use `.offset(count)` instead when possible, because `offset` + /// allows the compiler to optimize better. If you need to cross object + /// boundaries, cast the pointer to an integer and do the arithmetic there. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // Iterate using a raw pointer in increments of two elements + /// let mut data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *mut u8 = data.as_mut_ptr(); + /// let step = 2; + /// let end_rounded_up = ptr.wrapping_offset(6); + /// + /// while ptr != end_rounded_up { + /// unsafe { + /// *ptr = 0; + /// } + /// ptr = ptr.wrapping_offset(step); + /// } + /// assert_eq!(&data, &[0, 2, 0, 4, 0]); + /// ``` + #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] + #[inline] + pub fn wrapping_offset(self, count: isize) -> *mut T where T: Sized { + unsafe { + intrinsics::arith_offset(self, count) as *mut T + } + } + + /// Returns `None` if the pointer is null, or else returns a mutable + /// reference to the value wrapped in `Some`. + /// + /// # Safety + /// + /// As with [`as_ref`], this is unsafe because it cannot verify the validity + /// of the returned pointer, nor can it ensure that the lifetime `'a` + /// returned is indeed a valid lifetime for the contained data. + /// + /// When calling this method, you have to ensure that if the pointer is + /// non-NULL, then it is properly aligned, dereferencable (for the whole + /// size of `T`) and points to an initialized instance of `T`. This applies + /// even if the result of this method is unused! + /// (The part about being initialized is not yet fully decided, but until + /// it is the only safe approach is to ensure that they are indeed initialized.) + /// + /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does + /// not necessarily reflect the actual lifetime of the data. It is up to the + /// caller to ensure that for the duration of this lifetime, the memory this + /// pointer points to does not get accessed through any other pointer. + /// + /// [`as_ref`]: #method.as_ref + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = [1, 2, 3]; + /// let ptr: *mut u32 = s.as_mut_ptr(); + /// let first_value = unsafe { ptr.as_mut().unwrap() }; + /// *first_value = 4; + /// println!("{:?}", s); // It'll print: "[4, 2, 3]". + /// ``` + #[stable(feature = "ptr_as_ref", since = "1.9.0")] + #[inline] + pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> { + if self.is_null() { + None + } else { + Some(&mut *self) + } + } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// This function is the inverse of [`offset`]. + /// + /// [`offset`]: #method.offset-1 + /// [`wrapping_offset_from`]: #method.wrapping_offset_from-1 + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and other pointer must be either in bounds or one + /// byte past the end of the same allocated object. + /// + /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. + /// + /// * The distance between the pointers, in bytes, must be an exact multiple + /// of the size of `T`. + /// + /// * The distance being in bounds cannot rely on "wrapping around" the address space. + /// + /// The compiler and standard library generally try to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `ptr_into_vec.offset_from(vec.as_ptr())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_offset_from`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Panics + /// + /// This function panics if `T` is a Zero-Sized Type ("ZST"). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_offset_from)] + /// + /// let mut a = [0; 5]; + /// let ptr1: *mut i32 = &mut a[1]; + /// let ptr2: *mut i32 = &mut a[3]; + /// unsafe { + /// assert_eq!(ptr2.offset_from(ptr1), 2); + /// assert_eq!(ptr1.offset_from(ptr2), -2); + /// assert_eq!(ptr1.offset(2), ptr2); + /// assert_eq!(ptr2.offset(-2), ptr1); + /// } + /// ``` + #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[inline] + pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { + (self as *const T).offset_from(origin) + } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// If the address different between the two pointers is not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// Though this method is safe for any two pointers, note that its result + /// will be mostly useless if the two pointers aren't into the same allocated + /// object, for example if they point to two different local variables. + /// + /// # Panics + /// + /// This function panics if `T` is a zero-sized type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_wrapping_offset_from)] + /// + /// let mut a = [0; 5]; + /// let ptr1: *mut i32 = &mut a[1]; + /// let ptr2: *mut i32 = &mut a[3]; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); + /// assert_eq!(ptr1.wrapping_offset(2), ptr2); + /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); + /// + /// let ptr1: *mut i32 = 3 as _; + /// let ptr2: *mut i32 = 13 as _; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// ``` + #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] + #[inline] + pub fn wrapping_offset_from(self, origin: *const T) -> isize where T: Sized { + (self as *const T).wrapping_offset_from(origin) + } + + /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same allocated object. + /// + /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum must fit in a `usize`. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using `wrapping_offset` instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s: &str = "123"; + /// let ptr: *const u8 = s.as_ptr(); + /// + /// unsafe { + /// println!("{}", *ptr.add(1) as char); + /// println!("{}", *ptr.add(2) as char); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn add(self, count: usize) -> Self + where T: Sized, + { + self.offset(count as isize) + } + + /// Calculates the offset from a pointer (convenience for + /// `.offset((count as isize).wrapping_neg())`). + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same allocated object. + /// + /// * The computed offset cannot exceed `isize::MAX` **bytes**. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum must fit in a usize. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using `wrapping_offset` instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s: &str = "123"; + /// + /// unsafe { + /// let end: *const u8 = s.as_ptr().add(3); + /// println!("{}", *end.sub(1) as char); + /// println!("{}", *end.sub(2) as char); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn sub(self, count: usize) -> Self + where T: Sized, + { + self.offset((count as isize).wrapping_neg()) + } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// (convenience for `.wrapping_offset(count as isize)`) + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// Always use `.add(count)` instead when possible, because `add` + /// allows the compiler to optimize better. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // Iterate using a raw pointer in increments of two elements + /// let data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *const u8 = data.as_ptr(); + /// let step = 2; + /// let end_rounded_up = ptr.wrapping_add(6); + /// + /// // This loop prints "1, 3, 5, " + /// while ptr != end_rounded_up { + /// unsafe { + /// print!("{}, ", *ptr); + /// } + /// ptr = ptr.wrapping_add(step); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub fn wrapping_add(self, count: usize) -> Self + where T: Sized, + { + self.wrapping_offset(count as isize) + } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`) + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// Always use `.sub(count)` instead when possible, because `sub` + /// allows the compiler to optimize better. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // Iterate using a raw pointer in increments of two elements (backwards) + /// let data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *const u8 = data.as_ptr(); + /// let start_rounded_down = ptr.wrapping_sub(2); + /// ptr = ptr.wrapping_add(4); + /// let step = 2; + /// // This loop prints "5, 3, 1, " + /// while ptr != start_rounded_down { + /// unsafe { + /// print!("{}, ", *ptr); + /// } + /// ptr = ptr.wrapping_sub(step); + /// } + /// ``` + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub fn wrapping_sub(self, count: usize) -> Self + where T: Sized, + { + self.wrapping_offset((count as isize).wrapping_neg()) + } + + /// Reads the value from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// See [`ptr::read`] for safety concerns and examples. + /// + /// [`ptr::read`]: ./ptr/fn.read.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn read(self) -> T + where T: Sized, + { + read(self) + } + + /// Performs a volatile read of the value from `self` without moving it. This + /// leaves the memory in `self` unchanged. + /// + /// Volatile operations are intended to act on I/O memory, and are guaranteed + /// to not be elided or reordered by the compiler across other volatile + /// operations. + /// + /// See [`ptr::read_volatile`] for safety concerns and examples. + /// + /// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn read_volatile(self) -> T + where T: Sized, + { + read_volatile(self) + } + + /// Reads the value from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// Unlike `read`, the pointer may be unaligned. + /// + /// See [`ptr::read_unaligned`] for safety concerns and examples. + /// + /// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn read_unaligned(self) -> T + where T: Sized, + { + read_unaligned(self) + } + + /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// and destination may overlap. + /// + /// NOTE: this has the *same* argument order as [`ptr::copy`]. + /// + /// See [`ptr::copy`] for safety concerns and examples. + /// + /// [`ptr::copy`]: ./ptr/fn.copy.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn copy_to(self, dest: *mut T, count: usize) + where T: Sized, + { + copy(self, dest, count) + } + + /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// and destination may *not* overlap. + /// + /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. + /// + /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. + /// + /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) + where T: Sized, + { + copy_nonoverlapping(self, dest, count) + } + + /// Copies `count * size_of` bytes from `src` to `self`. The source + /// and destination may overlap. + /// + /// NOTE: this has the *opposite* argument order of [`ptr::copy`]. + /// + /// See [`ptr::copy`] for safety concerns and examples. + /// + /// [`ptr::copy`]: ./ptr/fn.copy.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn copy_from(self, src: *const T, count: usize) + where T: Sized, + { + copy(src, self, count) + } + + /// Copies `count * size_of` bytes from `src` to `self`. The source + /// and destination may *not* overlap. + /// + /// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`]. + /// + /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. + /// + /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize) + where T: Sized, + { + copy_nonoverlapping(src, self, count) + } + + /// Executes the destructor (if any) of the pointed-to value. + /// + /// See [`ptr::drop_in_place`] for safety concerns and examples. + /// + /// [`ptr::drop_in_place`]: ./ptr/fn.drop_in_place.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn drop_in_place(self) { + drop_in_place(self) + } + + /// Overwrites a memory location with the given value without reading or + /// dropping the old value. + /// + /// See [`ptr::write`] for safety concerns and examples. + /// + /// [`ptr::write`]: ./ptr/fn.write.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn write(self, val: T) + where T: Sized, + { + write(self, val) + } + + /// Invokes memset on the specified pointer, setting `count * size_of::()` + /// bytes of memory starting at `self` to `val`. + /// + /// See [`ptr::write_bytes`] for safety concerns and examples. + /// + /// [`ptr::write_bytes`]: ./ptr/fn.write_bytes.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn write_bytes(self, val: u8, count: usize) + where T: Sized, + { + write_bytes(self, val, count) + } + + /// Performs a volatile write of a memory location with the given value without + /// reading or dropping the old value. + /// + /// Volatile operations are intended to act on I/O memory, and are guaranteed + /// to not be elided or reordered by the compiler across other volatile + /// operations. + /// + /// See [`ptr::write_volatile`] for safety concerns and examples. + /// + /// [`ptr::write_volatile`]: ./ptr/fn.write_volatile.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn write_volatile(self, val: T) + where T: Sized, + { + write_volatile(self, val) + } + + /// Overwrites a memory location with the given value without reading or + /// dropping the old value. + /// + /// Unlike `write`, the pointer may be unaligned. + /// + /// See [`ptr::write_unaligned`] for safety concerns and examples. + /// + /// [`ptr::write_unaligned`]: ./ptr/fn.write_unaligned.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn write_unaligned(self, val: T) + where T: Sized, + { + write_unaligned(self, val) + } + + /// Replaces the value at `self` with `src`, returning the old + /// value, without dropping either. + /// + /// See [`ptr::replace`] for safety concerns and examples. + /// + /// [`ptr::replace`]: ./ptr/fn.replace.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn replace(self, src: T) -> T + where T: Sized, + { + replace(self, src) + } + + /// Swaps the values at two mutable locations of the same type, without + /// deinitializing either. They may overlap, unlike `mem::swap` which is + /// otherwise equivalent. + /// + /// See [`ptr::swap`] for safety concerns and examples. + /// + /// [`ptr::swap`]: ./ptr/fn.swap.html + #[stable(feature = "pointer_methods", since = "1.26.0")] + #[inline] + pub unsafe fn swap(self, with: *mut T) + where T: Sized, + { + swap(self, with) + } + + /// Computes the offset that needs to be applied to the pointer in order to make it aligned to + /// `align`. + /// + /// If it is not possible to align the pointer, the implementation returns + /// `usize::max_value()`. + /// + /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be + /// used with the `offset` or `offset_to` methods. + /// + /// There are no guarantees whatsover that offsetting the pointer will not overflow or go + /// beyond the allocation that the pointer points into. It is up to the caller to ensure that + /// the returned offset is correct in all terms other than alignment. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two. + /// + /// # Examples + /// + /// Accessing adjacent `u8` as `u16` + /// + /// ``` + /// # fn foo(n: usize) { + /// # use std::mem::align_of; + /// # unsafe { + /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; + /// let ptr = &x[n] as *const u8; + /// let offset = ptr.align_offset(align_of::()); + /// if offset < x.len() - n - 1 { + /// let u16_ptr = ptr.add(offset) as *const u16; + /// assert_ne!(*u16_ptr, 500); + /// } else { + /// // while the pointer can be aligned via `offset`, it would point + /// // outside the allocation + /// } + /// # } } + /// ``` + #[stable(feature = "align_offset", since = "1.36.0")] + pub fn align_offset(self, align: usize) -> usize where T: Sized { + if !align.is_power_of_two() { + panic!("align_offset: align is not a power-of-two"); + } + unsafe { + align_offset(self, align) + } + } +} + +/// Align pointer `p`. +/// +/// Calculate offset (in terms of elements of `stride` stride) that has to be applied +/// to pointer `p` so that pointer `p` would get aligned to `a`. +/// +/// Note: This implementation has been carefully tailored to not panic. It is UB for this to panic. +/// The only real change that can be made here is change of `INV_TABLE_MOD_16` and associated +/// constants. +/// +/// If we ever decide to make it possible to call the intrinsic with `a` that is not a +/// power-of-two, it will probably be more prudent to just change to a naive implementation rather +/// than trying to adapt this to accommodate that change. +/// +/// Any questions go to @nagisa. +#[lang="align_offset"] +pub(crate) unsafe fn align_offset(p: *const T, a: usize) -> usize { + /// Calculate multiplicative modular inverse of `x` modulo `m`. + /// + /// This implementation is tailored for align_offset and has following preconditions: + /// + /// * `m` is a power-of-two; + /// * `x < m`; (if `x ≥ m`, pass in `x % m` instead) + /// + /// Implementation of this function shall not panic. Ever. + #[inline] + fn mod_inv(x: usize, m: usize) -> usize { + /// Multiplicative modular inverse table modulo 2⁴ = 16. + /// + /// Note, that this table does not contain values where inverse does not exist (i.e., for + /// `0⁻¹ mod 16`, `2⁻¹ mod 16`, etc.) + const INV_TABLE_MOD_16: [u8; 8] = [1, 11, 13, 7, 9, 3, 5, 15]; + /// Modulo for which the `INV_TABLE_MOD_16` is intended. + const INV_TABLE_MOD: usize = 16; + /// INV_TABLE_MOD² + const INV_TABLE_MOD_SQUARED: usize = INV_TABLE_MOD * INV_TABLE_MOD; + + let table_inverse = INV_TABLE_MOD_16[(x & (INV_TABLE_MOD - 1)) >> 1] as usize; + if m <= INV_TABLE_MOD { + table_inverse & (m - 1) + } else { + // We iterate "up" using the following formula: + // + // $$ xy ≡ 1 (mod 2ⁿ) → xy (2 - xy) ≡ 1 (mod 2²ⁿ) $$ + // + // until 2²ⁿ ≥ m. Then we can reduce to our desired `m` by taking the result `mod m`. + let mut inverse = table_inverse; + let mut going_mod = INV_TABLE_MOD_SQUARED; + loop { + // y = y * (2 - xy) mod n + // + // Note, that we use wrapping operations here intentionally – the original formula + // uses e.g., subtraction `mod n`. It is entirely fine to do them `mod + // usize::max_value()` instead, because we take the result `mod n` at the end + // anyway. + inverse = inverse.wrapping_mul( + 2usize.wrapping_sub(x.wrapping_mul(inverse)) + ) & (going_mod - 1); + if going_mod > m { + return inverse & (m - 1); + } + going_mod = going_mod.wrapping_mul(going_mod); + } + } + } + + let stride = mem::size_of::(); + let a_minus_one = a.wrapping_sub(1); + let pmoda = p as usize & a_minus_one; + + if pmoda == 0 { + // Already aligned. Yay! + return 0; + } + + if stride <= 1 { + return if stride == 0 { + // If the pointer is not aligned, and the element is zero-sized, then no amount of + // elements will ever align the pointer. + !0 + } else { + a.wrapping_sub(pmoda) + }; + } + + let smoda = stride & a_minus_one; + // a is power-of-two so cannot be 0. stride = 0 is handled above. + let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a)); + let gcd = 1usize << gcdpow; + + if p as usize & (gcd - 1) == 0 { + // This branch solves for the following linear congruence equation: + // + // $$ p + so ≡ 0 mod a $$ + // + // $p$ here is the pointer value, $s$ – stride of `T`, $o$ offset in `T`s, and $a$ – the + // requested alignment. + // + // g = gcd(a, s) + // o = (a - (p mod a))/g * ((s/g)⁻¹ mod a) + // + // The first term is “the relative alignment of p to a”, the second term is “how does + // incrementing p by s bytes change the relative alignment of p”. Division by `g` is + // necessary to make this equation well formed if $a$ and $s$ are not co-prime. + // + // Furthermore, the result produced by this solution is not “minimal”, so it is necessary + // to take the result $o mod lcm(s, a)$. We can replace $lcm(s, a)$ with just a $a / g$. + let j = a.wrapping_sub(pmoda) >> gcdpow; + let k = smoda >> gcdpow; + return intrinsics::unchecked_rem(j.wrapping_mul(mod_inv(k, a)), a >> gcdpow); + } + + // Cannot be aligned at all. + usize::max_value() +} + + + +// Equality for pointers +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for *const T { + #[inline] + fn eq(&self, other: &*const T) -> bool { *self == *other } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for *const T {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for *mut T { + #[inline] + fn eq(&self, other: &*mut T) -> bool { *self == *other } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for *mut T {} + +/// Compares raw pointers for equality. +/// +/// This is the same as using the `==` operator, but less generic: +/// the arguments have to be `*const T` raw pointers, +/// not anything that implements `PartialEq`. +/// +/// This can be used to compare `&T` references (which coerce to `*const T` implicitly) +/// by their address rather than comparing the values they point to +/// (which is what the `PartialEq for &T` implementation does). +/// +/// # Examples +/// +/// ``` +/// use std::ptr; +/// +/// let five = 5; +/// let other_five = 5; +/// let five_ref = &five; +/// let same_five_ref = &five; +/// let other_five_ref = &other_five; +/// +/// assert!(five_ref == same_five_ref); +/// assert!(ptr::eq(five_ref, same_five_ref)); +/// +/// assert!(five_ref == other_five_ref); +/// assert!(!ptr::eq(five_ref, other_five_ref)); +/// ``` +/// +/// Slices are also compared by their length (fat pointers): +/// +/// ``` +/// let a = [1, 2, 3]; +/// assert!(std::ptr::eq(&a[..3], &a[..3])); +/// assert!(!std::ptr::eq(&a[..2], &a[..3])); +/// assert!(!std::ptr::eq(&a[0..2], &a[1..3])); +/// ``` +/// +/// Traits are also compared by their implementation: +/// +/// ``` +/// #[repr(transparent)] +/// struct Wrapper { member: i32 } +/// +/// trait Trait {} +/// impl Trait for Wrapper {} +/// impl Trait for i32 {} +/// +/// fn main() { +/// let wrapper = Wrapper { member: 10 }; +/// +/// // Pointers have equal addresses. +/// assert!(std::ptr::eq( +/// &wrapper as *const Wrapper as *const u8, +/// &wrapper.member as *const i32 as *const u8 +/// )); +/// +/// // Objects have equal addresses, but `Trait` has different implementations. +/// assert!(!std::ptr::eq( +/// &wrapper as &dyn Trait, +/// &wrapper.member as &dyn Trait, +/// )); +/// assert!(!std::ptr::eq( +/// &wrapper as &dyn Trait as *const dyn Trait, +/// &wrapper.member as &dyn Trait as *const dyn Trait, +/// )); +/// +/// // Converting the reference to a `*const u8` compares by address. +/// assert!(std::ptr::eq( +/// &wrapper as &dyn Trait as *const dyn Trait as *const u8, +/// &wrapper.member as &dyn Trait as *const dyn Trait as *const u8, +/// )); +/// } +/// ``` +#[stable(feature = "ptr_eq", since = "1.17.0")] +#[inline] +pub fn eq(a: *const T, b: *const T) -> bool { + a == b +} + +/// Hash a raw pointer. +/// +/// This can be used to hash a `&T` reference (which coerces to `*const T` implicitly) +/// by its address rather than the value it points to +/// (which is what the `Hash for &T` implementation does). +/// +/// # Examples +/// +/// ``` +/// use std::collections::hash_map::DefaultHasher; +/// use std::hash::{Hash, Hasher}; +/// use std::ptr; +/// +/// let five = 5; +/// let five_ref = &five; +/// +/// let mut hasher = DefaultHasher::new(); +/// ptr::hash(five_ref, &mut hasher); +/// let actual = hasher.finish(); +/// +/// let mut hasher = DefaultHasher::new(); +/// (five_ref as *const i32).hash(&mut hasher); +/// let expected = hasher.finish(); +/// +/// assert_eq!(actual, expected); +/// ``` +#[stable(feature = "ptr_hash", since = "1.35.0")] +pub fn hash(hashee: *const T, into: &mut S) { + use crate::hash::Hash; + hashee.hash(into); +} + +// Impls for function pointers +macro_rules! fnptr_impls_safety_abi { + ($FnTy: ty, $($Arg: ident),*) => { + #[stable(feature = "fnptr_impls", since = "1.4.0")] + impl PartialEq for $FnTy { + #[inline] + fn eq(&self, other: &Self) -> bool { + *self as usize == *other as usize + } + } + + #[stable(feature = "fnptr_impls", since = "1.4.0")] + impl Eq for $FnTy {} + + #[stable(feature = "fnptr_impls", since = "1.4.0")] + impl PartialOrd for $FnTy { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + (*self as usize).partial_cmp(&(*other as usize)) + } + } + + #[stable(feature = "fnptr_impls", since = "1.4.0")] + impl Ord for $FnTy { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + (*self as usize).cmp(&(*other as usize)) + } + } + + #[stable(feature = "fnptr_impls", since = "1.4.0")] + impl hash::Hash for $FnTy { + fn hash(&self, state: &mut HH) { + state.write_usize(*self as usize) + } + } + + #[stable(feature = "fnptr_impls", since = "1.4.0")] + impl fmt::Pointer for $FnTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&(*self as *const ()), f) + } + } + + #[stable(feature = "fnptr_impls", since = "1.4.0")] + impl fmt::Debug for $FnTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&(*self as *const ()), f) + } + } + } +} + +macro_rules! fnptr_impls_args { + ($($Arg: ident),+) => { + fnptr_impls_safety_abi! { extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ } + fnptr_impls_safety_abi! { extern "C" fn($($Arg),+) -> Ret, $($Arg),+ } + fnptr_impls_safety_abi! { extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ } + fnptr_impls_safety_abi! { unsafe extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ } + fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+) -> Ret, $($Arg),+ } + fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ } + }; + () => { + // No variadic functions with 0 parameters + fnptr_impls_safety_abi! { extern "Rust" fn() -> Ret, } + fnptr_impls_safety_abi! { extern "C" fn() -> Ret, } + fnptr_impls_safety_abi! { unsafe extern "Rust" fn() -> Ret, } + fnptr_impls_safety_abi! { unsafe extern "C" fn() -> Ret, } + }; +} + +fnptr_impls_args! { } +fnptr_impls_args! { A } +fnptr_impls_args! { A, B } +fnptr_impls_args! { A, B, C } +fnptr_impls_args! { A, B, C, D } +fnptr_impls_args! { A, B, C, D, E } +fnptr_impls_args! { A, B, C, D, E, F } +fnptr_impls_args! { A, B, C, D, E, F, G } +fnptr_impls_args! { A, B, C, D, E, F, G, H } +fnptr_impls_args! { A, B, C, D, E, F, G, H, I } +fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J } +fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K } +fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L } + +// Comparison for pointers +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for *const T { + #[inline] + fn cmp(&self, other: &*const T) -> Ordering { + if self < other { + Less + } else if self == other { + Equal + } else { + Greater + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for *const T { + #[inline] + fn partial_cmp(&self, other: &*const T) -> Option { + Some(self.cmp(other)) + } + + #[inline] + fn lt(&self, other: &*const T) -> bool { *self < *other } + + #[inline] + fn le(&self, other: &*const T) -> bool { *self <= *other } + + #[inline] + fn gt(&self, other: &*const T) -> bool { *self > *other } + + #[inline] + fn ge(&self, other: &*const T) -> bool { *self >= *other } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for *mut T { + #[inline] + fn cmp(&self, other: &*mut T) -> Ordering { + if self < other { + Less + } else if self == other { + Equal + } else { + Greater + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for *mut T { + #[inline] + fn partial_cmp(&self, other: &*mut T) -> Option { + Some(self.cmp(other)) + } + + #[inline] + fn lt(&self, other: &*mut T) -> bool { *self < *other } + + #[inline] + fn le(&self, other: &*mut T) -> bool { *self <= *other } + + #[inline] + fn gt(&self, other: &*mut T) -> bool { *self > *other } + + #[inline] + fn ge(&self, other: &*mut T) -> bool { *self >= *other } +} diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs new file mode 100644 index 0000000000000..46dde7c1da589 --- /dev/null +++ b/src/libcore/ptr/non_null.rs @@ -0,0 +1,226 @@ +use crate::convert::From; +use crate::ops::{CoerceUnsized, DispatchFromDyn}; +use crate::fmt; +use crate::hash; +use crate::marker::Unsize; +use crate::mem; +use crate::ptr::Unique; +use crate::cmp::Ordering; + +/// `*mut T` but non-zero and covariant. +/// +/// This is often the correct thing to use when building data structures using +/// raw pointers, but is ultimately more dangerous to use because of its additional +/// properties. If you're not sure if you should use `NonNull`, just use `*mut T`! +/// +/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer +/// is never dereferenced. This is so that enums may use this forbidden value +/// as a discriminant -- `Option>` has the same size as `*mut T`. +/// However the pointer may still dangle if it isn't dereferenced. +/// +/// Unlike `*mut T`, `NonNull` is covariant over `T`. If this is incorrect +/// for your use case, you should include some [`PhantomData`] in your type to +/// provide invariance, such as `PhantomData>` or `PhantomData<&'a mut T>`. +/// Usually this won't be necessary; covariance is correct for most safe abstractions, +/// such as `Box`, `Rc`, `Arc`, `Vec`, and `LinkedList`. This is the case because they +/// provide a public API that follows the normal shared XOR mutable rules of Rust. +/// +/// Notice that `NonNull` has a `From` instance for `&T`. However, this does +/// not change the fact that mutating through a (pointer derived from a) shared +/// reference is undefined behavior unless the mutation happens inside an +/// [`UnsafeCell`]. The same goes for creating a mutable reference from a shared +/// reference. When using this `From` instance without an `UnsafeCell`, +/// it is your responsibility to ensure that `as_mut` is never called, and `as_ptr` +/// is never used for mutation. +/// +/// [`PhantomData`]: ../marker/struct.PhantomData.html +/// [`UnsafeCell`]: ../cell/struct.UnsafeCell.html +#[stable(feature = "nonnull", since = "1.25.0")] +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(1)] +#[cfg_attr(not(bootstrap), rustc_nonnull_optimization_guaranteed)] +pub struct NonNull { + pointer: *const T, +} + +/// `NonNull` pointers are not `Send` because the data they reference may be aliased. +// N.B., this impl is unnecessary, but should provide better error messages. +#[stable(feature = "nonnull", since = "1.25.0")] +impl !Send for NonNull { } + +/// `NonNull` pointers are not `Sync` because the data they reference may be aliased. +// N.B., this impl is unnecessary, but should provide better error messages. +#[stable(feature = "nonnull", since = "1.25.0")] +impl !Sync for NonNull { } + +impl NonNull { + /// Creates a new `NonNull` that is dangling, but well-aligned. + /// + /// This is useful for initializing types which lazily allocate, like + /// `Vec::new` does. + /// + /// Note that the pointer value may potentially represent a valid pointer to + /// a `T`, which means this must not be used as a "not yet initialized" + /// sentinel value. Types that lazily allocate must track initialization by + /// some other means. + #[stable(feature = "nonnull", since = "1.25.0")] + #[inline] + pub const fn dangling() -> Self { + unsafe { + let ptr = mem::align_of::() as *mut T; + NonNull::new_unchecked(ptr) + } + } +} + +impl NonNull { + /// Creates a new `NonNull`. + /// + /// # Safety + /// + /// `ptr` must be non-null. + #[stable(feature = "nonnull", since = "1.25.0")] + #[inline] + pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { + NonNull { pointer: ptr as _ } + } + + /// Creates a new `NonNull` if `ptr` is non-null. + #[stable(feature = "nonnull", since = "1.25.0")] + #[inline] + pub fn new(ptr: *mut T) -> Option { + if !ptr.is_null() { + Some(unsafe { Self::new_unchecked(ptr) }) + } else { + None + } + } + + /// Acquires the underlying `*mut` pointer. + #[stable(feature = "nonnull", since = "1.25.0")] + #[inline] + pub const fn as_ptr(self) -> *mut T { + self.pointer as *mut T + } + + /// Dereferences the content. + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. + #[stable(feature = "nonnull", since = "1.25.0")] + #[inline] + pub unsafe fn as_ref(&self) -> &T { + &*self.as_ptr() + } + + /// Mutably dereferences the content. + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. + #[stable(feature = "nonnull", since = "1.25.0")] + #[inline] + pub unsafe fn as_mut(&mut self) -> &mut T { + &mut *self.as_ptr() + } + + /// Cast to a pointer of another type + #[stable(feature = "nonnull_cast", since = "1.27.0")] + #[inline] + pub const fn cast(self) -> NonNull { + unsafe { + NonNull::new_unchecked(self.as_ptr() as *mut U) + } + } +} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl Clone for NonNull { + #[inline] + fn clone(&self) -> Self { + *self + } +} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl Copy for NonNull { } + +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl CoerceUnsized> for NonNull where T: Unsize { } + +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl DispatchFromDyn> for NonNull where T: Unsize { } + +#[stable(feature = "nonnull", since = "1.25.0")] +impl fmt::Debug for NonNull { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&self.as_ptr(), f) + } +} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl fmt::Pointer for NonNull { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&self.as_ptr(), f) + } +} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl Eq for NonNull {} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl PartialEq for NonNull { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.as_ptr() == other.as_ptr() + } +} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl Ord for NonNull { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.as_ptr().cmp(&other.as_ptr()) + } +} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl PartialOrd for NonNull { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + self.as_ptr().partial_cmp(&other.as_ptr()) + } +} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl hash::Hash for NonNull { + #[inline] + fn hash(&self, state: &mut H) { + self.as_ptr().hash(state) + } +} + +#[unstable(feature = "ptr_internals", issue = "0")] +impl From> for NonNull { + #[inline] + fn from(unique: Unique) -> Self { + unsafe { NonNull::new_unchecked(unique.as_ptr()) } + } +} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl From<&mut T> for NonNull { + #[inline] + fn from(reference: &mut T) -> Self { + unsafe { NonNull { pointer: reference as *mut T } } + } +} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl From<&T> for NonNull { + #[inline] + fn from(reference: &T) -> Self { + unsafe { NonNull { pointer: reference as *const T } } + } +} diff --git a/src/libcore/ptr/unique.rs b/src/libcore/ptr/unique.rs new file mode 100644 index 0000000000000..5911518919e6d --- /dev/null +++ b/src/libcore/ptr/unique.rs @@ -0,0 +1,180 @@ +use crate::convert::From; +use crate::ops::{CoerceUnsized, DispatchFromDyn}; +use crate::fmt; +use crate::marker::{PhantomData, Unsize}; +use crate::mem; +use crate::ptr::NonNull; + +/// A wrapper around a raw non-null `*mut T` that indicates that the possessor +/// of this wrapper owns the referent. Useful for building abstractions like +/// `Box`, `Vec`, `String`, and `HashMap`. +/// +/// Unlike `*mut T`, `Unique` behaves "as if" it were an instance of `T`. +/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies +/// the kind of strong aliasing guarantees an instance of `T` can expect: +/// the referent of the pointer should not be modified without a unique path to +/// its owning Unique. +/// +/// If you're uncertain of whether it's correct to use `Unique` for your purposes, +/// consider using `NonNull`, which has weaker semantics. +/// +/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer +/// is never dereferenced. This is so that enums may use this forbidden value +/// as a discriminant -- `Option>` has the same size as `Unique`. +/// However the pointer may still dangle if it isn't dereferenced. +/// +/// Unlike `*mut T`, `Unique` is covariant over `T`. This should always be correct +/// for any type which upholds Unique's aliasing requirements. +#[unstable(feature = "ptr_internals", issue = "0", + reason = "use NonNull instead and consider PhantomData \ + (if you also use #[may_dangle]), Send, and/or Sync")] +#[doc(hidden)] +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(1)] +pub struct Unique { + pointer: *const T, + // NOTE: this marker has no consequences for variance, but is necessary + // for dropck to understand that we logically own a `T`. + // + // For details, see: + // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data + _marker: PhantomData, +} + +/// `Unique` pointers are `Send` if `T` is `Send` because the data they +/// reference is unaliased. Note that this aliasing invariant is +/// unenforced by the type system; the abstraction using the +/// `Unique` must enforce it. +#[unstable(feature = "ptr_internals", issue = "0")] +unsafe impl Send for Unique { } + +/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they +/// reference is unaliased. Note that this aliasing invariant is +/// unenforced by the type system; the abstraction using the +/// `Unique` must enforce it. +#[unstable(feature = "ptr_internals", issue = "0")] +unsafe impl Sync for Unique { } + +#[unstable(feature = "ptr_internals", issue = "0")] +impl Unique { + /// Creates a new `Unique` that is dangling, but well-aligned. + /// + /// This is useful for initializing types which lazily allocate, like + /// `Vec::new` does. + /// + /// Note that the pointer value may potentially represent a valid pointer to + /// a `T`, which means this must not be used as a "not yet initialized" + /// sentinel value. Types that lazily allocate must track initialization by + /// some other means. + // FIXME: rename to dangling() to match NonNull? + #[inline] + pub const fn empty() -> Self { + unsafe { + Unique::new_unchecked(mem::align_of::() as *mut T) + } + } +} + +#[unstable(feature = "ptr_internals", issue = "0")] +impl Unique { + /// Creates a new `Unique`. + /// + /// # Safety + /// + /// `ptr` must be non-null. + #[inline] + pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { + Unique { pointer: ptr as _, _marker: PhantomData } + } + + /// Creates a new `Unique` if `ptr` is non-null. + #[inline] + pub fn new(ptr: *mut T) -> Option { + if !ptr.is_null() { + Some(unsafe { Unique { pointer: ptr as _, _marker: PhantomData } }) + } else { + None + } + } + + /// Acquires the underlying `*mut` pointer. + #[inline] + pub const fn as_ptr(self) -> *mut T { + self.pointer as *mut T + } + + /// Dereferences the content. + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. + #[inline] + pub unsafe fn as_ref(&self) -> &T { + &*self.as_ptr() + } + + /// Mutably dereferences the content. + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. + #[inline] + pub unsafe fn as_mut(&mut self) -> &mut T { + &mut *self.as_ptr() + } +} + +#[unstable(feature = "ptr_internals", issue = "0")] +impl Clone for Unique { + #[inline] + fn clone(&self) -> Self { + *self + } +} + +#[unstable(feature = "ptr_internals", issue = "0")] +impl Copy for Unique { } + +#[unstable(feature = "ptr_internals", issue = "0")] +impl CoerceUnsized> for Unique where T: Unsize { } + +#[unstable(feature = "ptr_internals", issue = "0")] +impl DispatchFromDyn> for Unique where T: Unsize { } + +#[unstable(feature = "ptr_internals", issue = "0")] +impl fmt::Debug for Unique { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&self.as_ptr(), f) + } +} + +#[unstable(feature = "ptr_internals", issue = "0")] +impl fmt::Pointer for Unique { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&self.as_ptr(), f) + } +} + +#[unstable(feature = "ptr_internals", issue = "0")] +impl From<&mut T> for Unique { + #[inline] + fn from(reference: &mut T) -> Self { + unsafe { Unique { pointer: reference as *mut T, _marker: PhantomData } } + } +} + +#[unstable(feature = "ptr_internals", issue = "0")] +impl From<&T> for Unique { + #[inline] + fn from(reference: &T) -> Self { + unsafe { Unique { pointer: reference as *const T, _marker: PhantomData } } + } +} + +#[unstable(feature = "ptr_internals", issue = "0")] +impl<'a, T: ?Sized> From> for Unique { + #[inline] + fn from(p: NonNull) -> Self { + unsafe { Unique::new_unchecked(p.as_ptr()) } + } +} diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index 155429b0e4f54..75c329a7d6c10 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -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, diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 92d29f6ee8a30..8a09877ce1f4b 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -230,9 +230,9 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fmt; -use iter::{FromIterator, FusedIterator, TrustedLen}; -use ops::{self, Deref}; +use crate::fmt; +use crate::iter::{FromIterator, FusedIterator, TrustedLen}; +use crate::ops::{self, Deref}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). /// @@ -240,7 +240,7 @@ use ops::{self, Deref}; /// /// [`Ok`]: enum.Result.html#variant.Ok /// [`Err`]: enum.Result.html#variant.Err -#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] +#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[must_use = "this `Result` may be an `Err` variant, which should be handled"] #[stable(feature = "rust1", since = "1.0.0")] pub enum Result { @@ -277,6 +277,7 @@ impl Result { /// let x: Result = Err("Some error message"); /// assert_eq!(x.is_ok(), false); /// ``` + #[must_use] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_ok(&self) -> bool { @@ -301,6 +302,7 @@ impl Result { /// let x: Result = Err("Some error message"); /// assert_eq!(x.is_err(), true); /// ``` + #[must_use] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_err(&self) -> bool { @@ -369,7 +371,7 @@ impl Result { // Adapter for working with references ///////////////////////////////////////////////////////////////////////// - /// Converts from `Result` to `Result<&T, &E>`. + /// Converts from `&Result` to `Result<&T, &E>`. /// /// Produces a new `Result`, containing a reference /// into the original, leaving the original in place. @@ -394,7 +396,7 @@ impl Result { } } - /// Converts from `Result` to `Result<&mut T, &mut E>`. + /// Converts from `&mut Result` to `Result<&mut T, &mut E>`. /// /// # Examples /// @@ -542,7 +544,7 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, T> { Iter { inner: self.as_ref().ok() } } @@ -567,7 +569,7 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter_mut(&mut self) -> IterMut { + pub fn iter_mut(&mut self) -> IterMut<'_, T> { IterMut { inner: self.as_mut().ok() } } @@ -1001,6 +1003,27 @@ fn unwrap_failed(msg: &str, error: E) -> ! { // Trait implementations ///////////////////////////////////////////////////////////////////////////// +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Result { + #[inline] + fn clone(&self) -> Self { + match self { + Ok(x) => Ok(x.clone()), + Err(x) => Err(x.clone()), + } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + match (self, source) { + (Ok(to), Ok(from)) => to.clone_from(from), + (Err(to), Err(from)) => to.clone_from(from), + (to, from) => *to = from.clone(), + } + } +} + + #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for Result { type Item = T; @@ -1200,8 +1223,36 @@ impl> FromIterator> for Result { /// let res: Result, &'static str> = v.iter().map(|x: &u32| /// x.checked_add(1).ok_or("Overflow!") /// ).collect(); - /// assert!(res == Ok(vec![2, 3])); + /// assert_eq!(res, Ok(vec![2, 3])); /// ``` + /// + /// Here is another example that tries to subtract one from another list + /// of integers, this time checking for underflow: + /// + /// ``` + /// let v = vec![1, 2, 0]; + /// let res: Result, &'static str> = v.iter().map(|x: &u32| + /// x.checked_sub(1).ok_or("Underflow!") + /// ).collect(); + /// assert_eq!(res, Err("Underflow!")); + /// ``` + /// + /// Here is a variation on the previous example, showing that no + /// further elements are taken from `iter` after the first `Err`. + /// + /// ``` + /// let v = vec![3, 2, 1, 10]; + /// let mut shared = 0; + /// let res: Result, &'static str> = v.iter().map(|x: &u32| { + /// shared += x; + /// x.checked_sub(2).ok_or("Underflow!") + /// }).collect(); + /// assert_eq!(res, Err("Underflow!")); + /// assert_eq!(shared, 6); + /// ``` + /// + /// Since the third element caused an underflow, no further elements were taken, + /// so the final value of `shared` is 6 (= `3 + 2 + 1`), not 16. #[inline] fn from_iter>>(iter: I) -> Result { // FIXME(#11084): This could be replaced with Iterator::scan when this diff --git a/src/libcore/slice/memchr.rs b/src/libcore/slice/memchr.rs index cbba546b8daba..45ab016c49628 100644 --- a/src/libcore/slice/memchr.rs +++ b/src/libcore/slice/memchr.rs @@ -1,8 +1,8 @@ // Original implementation taken from rust-memchr. // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch -use cmp; -use mem; +use crate::cmp; +use crate::mem; const LO_U64: u64 = 0x0101010101010101; const HI_U64: u64 = 0x8080808080808080; @@ -32,7 +32,7 @@ fn repeat_byte(b: u8) -> usize { #[cfg(not(target_pointer_width = "16"))] #[inline] fn repeat_byte(b: u8) -> usize { - (b as usize) * (::usize::MAX / 255) + (b as usize) * (crate::usize::MAX / 255) } /// Returns the first index matching the byte `x` in `text`. diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 2063f8ffaf65a..c6d44324ef5ee 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + //! Slice management and manipulation. //! //! For more details see [`std::slice`]. @@ -20,20 +22,20 @@ // * The `raw` and `bytes` submodules. // * Boilerplate trait implementations. -use cmp::Ordering::{self, Less, Equal, Greater}; -use cmp; -use fmt; -use intrinsics::assume; -use isize; -use iter::*; -use ops::{FnMut, Try, self}; -use option::Option; -use option::Option::{None, Some}; -use result::Result; -use result::Result::{Ok, Err}; -use ptr; -use mem; -use marker::{Copy, Send, Sync, Sized, self}; +use crate::cmp::Ordering::{self, Less, Equal, Greater}; +use crate::cmp; +use crate::fmt; +use crate::intrinsics::{assume, exact_div, unchecked_sub}; +use crate::isize; +use crate::iter::*; +use crate::ops::{FnMut, Try, self}; +use crate::option::Option; +use crate::option::Option::{None, Some}; +use crate::result::Result; +use crate::result::Result::{Ok, Err}; +use crate::ptr; +use crate::mem; +use crate::marker::{Copy, Send, Sync, Sized, self}; #[unstable(feature = "slice_internals", issue = "0", reason = "exposed from core to be reused in std; use the memchr crate")] @@ -43,19 +45,6 @@ pub mod memchr; mod rotate; mod sort; -#[repr(C)] -union Repr<'a, T: 'a> { - rust: &'a [T], - rust_mut: &'a mut [T], - raw: FatPtr, -} - -#[repr(C)] -struct FatPtr { - data: *const T, - len: usize, -} - // // Extension traits // @@ -76,7 +65,7 @@ impl [T] { #[rustc_const_unstable(feature = "const_slice_len")] pub const fn len(&self) -> usize { unsafe { - Repr { rust: self }.raw.len + crate::ptr::Repr { rust: self }.raw.len } } @@ -357,6 +346,10 @@ impl [T] { /// The caller must ensure that the slice outlives the pointer this /// function returns, or else it will end up pointing to garbage. /// + /// The caller must also ensure that the memory the pointer (non-transitively) points to + /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer + /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`]. + /// /// Modifying the container referenced by this slice may cause its buffer /// to be reallocated, which would also make any pointers to it invalid. /// @@ -372,6 +365,8 @@ impl [T] { /// } /// } /// ``` + /// + /// [`as_mut_ptr`]: #method.as_mut_ptr #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub const fn as_ptr(&self) -> *const T { @@ -524,7 +519,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, T> { unsafe { let ptr = self.as_ptr(); assume(!ptr.is_null()); @@ -556,7 +551,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn iter_mut(&mut self) -> IterMut { + pub fn iter_mut(&mut self) -> IterMut<'_, T> { unsafe { let ptr = self.as_mut_ptr(); assume(!ptr.is_null()); @@ -603,7 +598,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn windows(&self, size: usize) -> Windows { + pub fn windows(&self, size: usize) -> Windows<'_, T> { assert!(size != 0); Windows { v: self, size } } @@ -637,7 +632,7 @@ impl [T] { /// [`rchunks`]: #method.rchunks #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn chunks(&self, chunk_size: usize) -> Chunks { + pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> { assert!(chunk_size != 0); Chunks { v: self, chunk_size } } @@ -675,7 +670,7 @@ impl [T] { /// [`rchunks_mut`]: #method.rchunks_mut #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut { + pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> { assert!(chunk_size != 0); ChunksMut { v: self, chunk_size } } @@ -712,7 +707,7 @@ impl [T] { /// [`rchunks_exact`]: #method.rchunks_exact #[stable(feature = "chunks_exact", since = "1.31.0")] #[inline] - pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact { + pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> { assert!(chunk_size != 0); let rem = self.len() % chunk_size; let len = self.len() - rem; @@ -757,7 +752,7 @@ impl [T] { /// [`rchunks_exact_mut`]: #method.rchunks_exact_mut #[stable(feature = "chunks_exact", since = "1.31.0")] #[inline] - pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut { + pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> { assert!(chunk_size != 0); let rem = self.len() % chunk_size; let len = self.len() - rem; @@ -794,7 +789,7 @@ impl [T] { /// [`chunks`]: #method.chunks #[stable(feature = "rchunks", since = "1.31.0")] #[inline] - pub fn rchunks(&self, chunk_size: usize) -> RChunks { + pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> { assert!(chunk_size != 0); RChunks { v: self, chunk_size } } @@ -832,13 +827,13 @@ impl [T] { /// [`chunks_mut`]: #method.chunks_mut #[stable(feature = "rchunks", since = "1.31.0")] #[inline] - pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut { + pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> { assert!(chunk_size != 0); RChunksMut { v: self, chunk_size } } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the - /// beginning of the slice. + /// end of the slice. /// /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the /// slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved @@ -849,7 +844,7 @@ impl [T] { /// /// See [`rchunks`] for a variant of this iterator that also returns the remainder as a smaller /// chunk, and [`chunks_exact`] for the same iterator but starting at the beginning of the - /// slice of the slice. + /// slice. /// /// # Panics /// @@ -871,7 +866,7 @@ impl [T] { /// [`chunks_exact`]: #method.chunks_exact #[stable(feature = "rchunks", since = "1.31.0")] #[inline] - pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact { + pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> { assert!(chunk_size != 0); let rem = self.len() % chunk_size; let (fst, snd) = self.split_at(rem); @@ -890,7 +885,7 @@ impl [T] { /// /// See [`rchunks_mut`] for a variant of this iterator that also returns the remainder as a /// smaller chunk, and [`chunks_exact_mut`] for the same iterator but starting at the beginning - /// of the slice of the slice. + /// of the slice. /// /// # Panics /// @@ -916,7 +911,7 @@ impl [T] { /// [`chunks_exact_mut`]: #method.chunks_exact_mut #[stable(feature = "rchunks", since = "1.31.0")] #[inline] - pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut { + pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> { assert!(chunk_size != 0); let rem = self.len() % chunk_size; let (fst, snd) = self.split_at_mut(rem); @@ -1042,7 +1037,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn split(&self, pred: F) -> Split + pub fn split(&self, pred: F) -> Split<'_, T, F> where F: FnMut(&T) -> bool { Split { @@ -1067,7 +1062,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn split_mut(&mut self, pred: F) -> SplitMut + pub fn split_mut(&mut self, pred: F) -> SplitMut<'_, T, F> where F: FnMut(&T) -> bool { SplitMut { v: self, pred, finished: false } @@ -1102,7 +1097,7 @@ impl [T] { /// ``` #[stable(feature = "slice_rsplit", since = "1.27.0")] #[inline] - pub fn rsplit(&self, pred: F) -> RSplit + pub fn rsplit(&self, pred: F) -> RSplit<'_, T, F> where F: FnMut(&T) -> bool { RSplit { inner: self.split(pred) } @@ -1127,7 +1122,7 @@ impl [T] { /// #[stable(feature = "slice_rsplit", since = "1.27.0")] #[inline] - pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut + pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut<'_, T, F> where F: FnMut(&T) -> bool { RSplitMut { inner: self.split_mut(pred) } @@ -1154,7 +1149,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn splitn(&self, n: usize, pred: F) -> SplitN + pub fn splitn(&self, n: usize, pred: F) -> SplitN<'_, T, F> where F: FnMut(&T) -> bool { SplitN { @@ -1184,7 +1179,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut + pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut<'_, T, F> where F: FnMut(&T) -> bool { SplitNMut { @@ -1217,7 +1212,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN + pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN<'_, T, F> where F: FnMut(&T) -> bool { RSplitN { @@ -1248,7 +1243,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut + pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut<'_, T, F> where F: FnMut(&T) -> bool { RSplitNMut { @@ -1585,6 +1580,153 @@ impl [T] { sort::quicksort(self, |a, b| f(a).lt(&f(b))); } + /// Reorder the slice such that the element at `index` is at its final sorted position. + /// + /// This reordering has the additional property that any value at position `i < index` will be + /// less than or equal to any value at a position `j > index`. Additionally, this reordering is + /// unstable (i.e. any number of equal elements may end up at position `index`), in-place + /// (i.e. does not allocate), and `O(n)` worst-case. This function is also/ known as "kth + /// element" in other libraries. It returns a triplet of the following values: all elements less + /// than the one at the given index, the value at the given index, and all elements greater than + /// the one at the given index. + /// + /// # Current implementation + /// + /// The current algorithm is based on the quickselect portion of the same quicksort algorithm + /// used for [`sort_unstable`]. + /// + /// [`sort_unstable`]: #method.sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_at_index)] + /// + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// // Find the median + /// v.partition_at_index(2); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [-3, -5, 1, 2, 4] || + /// v == [-5, -3, 1, 2, 4] || + /// v == [-3, -5, 1, 4, 2] || + /// v == [-5, -3, 1, 4, 2]); + /// ``` + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[inline] + pub fn partition_at_index(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) + where T: Ord + { + let mut f = |a: &T, b: &T| a.lt(b); + sort::partition_at_index(self, index, &mut f) + } + + /// Reorder the slice with a comparator function such that the element at `index` is at its + /// final sorted position. + /// + /// This reordering has the additional property that any value at position `i < index` will be + /// less than or equal to any value at a position `j > index` using the comparator function. + /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at + /// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function + /// is also known as "kth element" in other libraries. It returns a triplet of the following + /// values: all elements less than the one at the given index, the value at the given index, + /// and all elements greater than the one at the given index, using the provided comparator + /// function. + /// + /// # Current implementation + /// + /// The current algorithm is based on the quickselect portion of the same quicksort algorithm + /// used for [`sort_unstable`]. + /// + /// [`sort_unstable`]: #method.sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_at_index)] + /// + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// // Find the median as if the slice were sorted in descending order. + /// v.partition_at_index_by(2, |a, b| b.cmp(a)); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [2, 4, 1, -5, -3] || + /// v == [2, 4, 1, -3, -5] || + /// v == [4, 2, 1, -5, -3] || + /// v == [4, 2, 1, -3, -5]); + /// ``` + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[inline] + pub fn partition_at_index_by(&mut self, index: usize, mut compare: F) + -> (&mut [T], &mut T, &mut [T]) + where F: FnMut(&T, &T) -> Ordering + { + let mut f = |a: &T, b: &T| compare(a, b) == Less; + sort::partition_at_index(self, index, &mut f) + } + + /// Reorder the slice with a key extraction function such that the element at `index` is at its + /// final sorted position. + /// + /// This reordering has the additional property that any value at position `i < index` will be + /// less than or equal to any value at a position `j > index` using the key extraction function. + /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at + /// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function + /// is also known as "kth element" in other libraries. It returns a triplet of the following + /// values: all elements less than the one at the given index, the value at the given index, and + /// all elements greater than the one at the given index, using the provided key extraction + /// function. + /// + /// # Current implementation + /// + /// The current algorithm is based on the quickselect portion of the same quicksort algorithm + /// used for [`sort_unstable`]. + /// + /// [`sort_unstable`]: #method.sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_at_index)] + /// + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// // Return the median as if the array were sorted according to absolute value. + /// v.partition_at_index_by_key(2, |a| a.abs()); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [1, 2, -3, 4, -5] || + /// v == [1, 2, -3, -5, 4] || + /// v == [2, 1, -3, 4, -5] || + /// v == [2, 1, -3, -5, 4]); + /// ``` + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[inline] + pub fn partition_at_index_by_key(&mut self, index: usize, mut f: F) + -> (&mut [T], &mut T, &mut [T]) + where F: FnMut(&T) -> K, K: Ord + { + let mut g = |a: &T, b: &T| f(a).lt(&f(b)); + sort::partition_at_index(self, index, &mut g) + } + /// Moves all consecutive repeated elements to the end of the slice according to the /// [`PartialEq`] trait implementation. /// @@ -1991,14 +2133,13 @@ impl [T] { /// Copying four bytes within a slice: /// /// ``` - /// # #![feature(copy_within)] /// let mut bytes = *b"Hello, World!"; /// /// bytes.copy_within(1..5, 8); /// /// assert_eq!(&bytes, b"Hello, Wello!"); /// ``` - #[unstable(feature = "copy_within", issue = "54236")] + #[stable(feature = "copy_within", since = "1.37.0")] pub fn copy_within>(&mut self, src: R, dest: usize) where T: Copy, @@ -2023,8 +2164,8 @@ impl [T] { assert!(dest <= self.len() - count, "dest is out of bounds"); unsafe { ptr::copy( - self.get_unchecked(src_start), - self.get_unchecked_mut(dest), + self.as_ptr().add(src_start), + self.as_mut_ptr().add(dest), count, ); } @@ -2109,13 +2250,14 @@ impl [T] { // Luckily since all this is constant-evaluated... performance here matters not! #[inline] fn gcd(a: usize, b: usize) -> usize { + use crate::intrinsics; // iterative stein’s algorithm // We should still make this `const fn` (and revert to recursive algorithm if we do) // because relying on llvm to consteval all this is… well, it makes me uncomfortable. let (ctz_a, mut ctz_b) = unsafe { if a == 0 { return b; } if b == 0 { return a; } - (::intrinsics::cttz_nonzero(a), ::intrinsics::cttz_nonzero(b)) + (intrinsics::cttz_nonzero(a), intrinsics::cttz_nonzero(b)) }; let k = ctz_a.min(ctz_b); let mut a = a >> ctz_a; @@ -2124,21 +2266,21 @@ impl [T] { // remove all factors of 2 from b b >>= ctz_b; if a > b { - ::mem::swap(&mut a, &mut b); + mem::swap(&mut a, &mut b); } b = b - a; unsafe { if b == 0 { break; } - ctz_b = ::intrinsics::cttz_nonzero(b); + ctz_b = intrinsics::cttz_nonzero(b); } } a << k } - let gcd: usize = gcd(::mem::size_of::(), ::mem::size_of::()); - let ts: usize = ::mem::size_of::() / gcd; - let us: usize = ::mem::size_of::() / gcd; + let gcd: usize = gcd(mem::size_of::(), mem::size_of::()); + let ts: usize = mem::size_of::() / gcd; + let us: usize = mem::size_of::() / gcd; // Armed with this knowledge, we can find how many `U`s we can fit! let us_len = self.len() / ts * us; @@ -2179,7 +2321,7 @@ impl [T] { #[stable(feature = "slice_align_to", since = "1.30.0")] pub unsafe fn align_to(&self) -> (&[T], &[U], &[T]) { // Note that most of this function will be constant-evaluated, - if ::mem::size_of::() == 0 || ::mem::size_of::() == 0 { + if mem::size_of::() == 0 || mem::size_of::() == 0 { // handle ZSTs specially, which is – don't handle them at all. return (self, &[], &[]); } @@ -2187,7 +2329,7 @@ impl [T] { // First, find at what point do we split between the first and 2nd slice. Easy with // ptr.align_offset. let ptr = self.as_ptr(); - let offset = ::ptr::align_offset(ptr, ::mem::align_of::()); + let offset = crate::ptr::align_offset(ptr, mem::align_of::()); if offset > self.len() { (self, &[], &[]) } else { @@ -2232,7 +2374,7 @@ impl [T] { #[stable(feature = "slice_align_to", since = "1.30.0")] pub unsafe fn align_to_mut(&mut self) -> (&mut [T], &mut [U], &mut [T]) { // Note that most of this function will be constant-evaluated, - if ::mem::size_of::() == 0 || ::mem::size_of::() == 0 { + if mem::size_of::() == 0 || mem::size_of::() == 0 { // handle ZSTs specially, which is – don't handle them at all. return (self, &mut [], &mut []); } @@ -2240,7 +2382,7 @@ impl [T] { // First, find at what point do we split between the first and 2nd slice. Easy with // ptr.align_offset. let ptr = self.as_ptr(); - let offset = ::ptr::align_offset(ptr, ::mem::align_of::()); + let offset = crate::ptr::align_offset(ptr, mem::align_of::()); if offset > self.len() { (self, &mut [], &mut []) } else { @@ -2843,14 +2985,27 @@ macro_rules! is_empty { // unexpected way. (Tested by `codegen/slice-position-bounds-check`.) macro_rules! len { ($self: ident) => {{ + #![allow(unused_unsafe)] // we're sometimes used within an unsafe block + let start = $self.ptr; - let diff = ($self.end as usize).wrapping_sub(start as usize); let size = size_from_ptr(start); if size == 0 { + // This _cannot_ use `unchecked_sub` because we depend on wrapping + // to represent the length of long ZST slice iterators. + let diff = ($self.end as usize).wrapping_sub(start as usize); diff } else { - // Using division instead of `offset_from` helps LLVM remove bounds checks - diff / size + // We know that `start <= end`, so can do better than `offset_from`, + // which needs to deal in signed. By setting appropriate flags here + // we can tell LLVM this, which helps it remove bounds checks. + // SAFETY: By the type invariant, `start <= end` + let diff = unsafe { unchecked_sub($self.end as usize, start as usize) }; + // By also telling LLVM that the pointers are apart by an exact + // multiple of the type size, it can optimize `len() == 0` down to + // `start == end` instead of `(end - start) < size`. + // SAFETY: By the type invariant, the pointers are aligned so the + // distance between them must be a multiple of pointee size + unsafe { exact_div(diff, size) } } }} } @@ -2864,6 +3019,28 @@ macro_rules! iterator { {$( $mut_:tt )*}, {$($extra:tt)*} ) => { + // Returns the first element and moves the start of the iterator forwards by 1. + // Greatly improves performance compared to an inlined function. The iterator + // must not be empty. + macro_rules! next_unchecked { + ($self: ident) => {& $( $mut_ )* *$self.post_inc_start(1)} + } + + // Returns the last element and moves the end of the iterator backwards by 1. + // Greatly improves performance compared to an inlined function. The iterator + // must not be empty. + macro_rules! next_back_unchecked { + ($self: ident) => {& $( $mut_ )* *$self.pre_dec_end(1)} + } + + // Shrinks the iterator when T is a ZST, by moving the end of the iterator + // backwards by `n`. `n` must not exceed `self.len()`. + macro_rules! zst_shrink { + ($self: ident, $n: ident) => { + $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T; + } + } + impl<'a, T> $name<'a, T> { // Helper function for creating a slice from the iterator. #[inline(always)] @@ -2873,12 +3050,11 @@ macro_rules! iterator { // Helper function for moving the start of the iterator forwards by `offset` elements, // returning the old start. - // Unsafe because the offset must be in-bounds or one-past-the-end. + // Unsafe because the offset must not exceed `self.len()`. #[inline(always)] unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T { if mem::size_of::() == 0 { - // This is *reducing* the length. `ptr` never changes with ZST. - self.end = (self.end as * $raw_mut u8).wrapping_offset(-offset) as * $raw_mut T; + zst_shrink!(self, offset); self.ptr } else { let old = self.ptr; @@ -2889,11 +3065,11 @@ macro_rules! iterator { // Helper function for moving the end of the iterator backwards by `offset` elements, // returning the new end. - // Unsafe because the offset must be in-bounds or one-past-the-end. + // Unsafe because the offset must not exceed `self.len()`. #[inline(always)] unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T { if mem::size_of::() == 0 { - self.end = (self.end as * $raw_mut u8).wrapping_offset(-offset) as * $raw_mut T; + zst_shrink!(self, offset); self.ptr } else { self.end = self.end.offset(-offset); @@ -2930,7 +3106,7 @@ macro_rules! iterator { if is_empty!(self) { None } else { - Some(& $( $mut_ )* *self.post_inc_start(1)) + Some(next_unchecked!(self)) } } } @@ -2959,11 +3135,10 @@ macro_rules! iterator { } return None; } - // We are in bounds. `offset` does the right thing even for ZSTs. + // We are in bounds. `post_inc_start` does the right thing even for ZSTs. unsafe { - let elem = Some(& $( $mut_ )* *self.ptr.add(n)); - self.post_inc_start((n as isize).wrapping_add(1)); - elem + self.post_inc_start(n as isize); + Some(next_unchecked!(self)) } } @@ -2980,13 +3155,13 @@ macro_rules! iterator { let mut accum = init; unsafe { while len!(self) >= 4 { - accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?; - accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?; - accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?; - accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?; + accum = f(accum, next_unchecked!(self))?; + accum = f(accum, next_unchecked!(self))?; + accum = f(accum, next_unchecked!(self))?; + accum = f(accum, next_unchecked!(self))?; } while !is_empty!(self) { - accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?; + accum = f(accum, next_unchecked!(self))?; } } Try::from_ok(accum) @@ -3057,11 +3232,25 @@ macro_rules! iterator { if is_empty!(self) { None } else { - Some(& $( $mut_ )* *self.pre_dec_end(1)) + Some(next_back_unchecked!(self)) } } } + #[inline] + fn nth_back(&mut self, n: usize) -> Option<$elem> { + if n >= len!(self) { + // This iterator is now empty. + self.end = self.ptr; + return None; + } + // We are in bounds. `pre_dec_end` does the right thing even for ZSTs. + unsafe { + self.pre_dec_end(n as isize); + Some(next_back_unchecked!(self)) + } + } + #[inline] fn try_rfold(&mut self, init: B, mut f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try @@ -3070,14 +3259,14 @@ macro_rules! iterator { let mut accum = init; unsafe { while len!(self) >= 4 { - accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?; - accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?; - accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?; - accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?; + accum = f(accum, next_back_unchecked!(self))?; + accum = f(accum, next_back_unchecked!(self))?; + accum = f(accum, next_back_unchecked!(self))?; + accum = f(accum, next_back_unchecked!(self))?; } // inlining is_empty everywhere makes a huge performance difference while !is_empty!(self) { - accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?; + accum = f(accum, next_back_unchecked!(self))?; } } Try::from_ok(accum) @@ -3136,7 +3325,7 @@ pub struct Iter<'a, T: 'a> { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for Iter<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Iter") .field(&self.as_slice()) .finish() @@ -3238,7 +3427,7 @@ pub struct IterMut<'a, T: 'a> { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for IterMut<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("IterMut") .field(&self.make_slice()) .finish() @@ -3288,6 +3477,34 @@ impl<'a, T> IterMut<'a, T> { pub fn into_slice(self) -> &'a mut [T] { unsafe { from_raw_parts_mut(self.ptr, len!(self)) } } + + /// Views the underlying data as a subslice of the original data. + /// + /// To avoid creating `&mut [T]` references that alias, the returned slice + /// borrows its lifetime from the iterator the method is applied on. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(slice_iter_mut_as_slice)] + /// let mut slice: &mut [usize] = &mut [1, 2, 3]; + /// + /// // First, we get the iterator: + /// let mut iter = slice.iter_mut(); + /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]": + /// assert_eq!(iter.as_slice(), &[1, 2, 3]); + /// + /// // Next, we move to the second element of the slice: + /// iter.next(); + /// // Now `as_slice` returns "[2, 3]": + /// assert_eq!(iter.as_slice(), &[2, 3]); + /// ``` + #[unstable(feature = "slice_iter_mut_as_slice", reason = "recently added", issue = "58957")] + pub fn as_slice(&self) -> &[T] { + self.make_slice() + } } iterator!{struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}} @@ -3317,7 +3534,7 @@ pub struct Split<'a, T:'a, P> where P: FnMut(&T) -> bool { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for Split<'_, T, P> where P: FnMut(&T) -> bool { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Split") .field("v", &self.v) .field("finished", &self.finished) @@ -3408,7 +3625,7 @@ pub struct SplitMut<'a, T:'a, P> where P: FnMut(&T) -> bool { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for SplitMut<'_, T, P> where P: FnMut(&T) -> bool { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitMut") .field("v", &self.v) .field("finished", &self.finished) @@ -3505,7 +3722,7 @@ pub struct RSplit<'a, T:'a, P> where P: FnMut(&T) -> bool { #[stable(feature = "slice_rsplit", since = "1.27.0")] impl fmt::Debug for RSplit<'_, T, P> where P: FnMut(&T) -> bool { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RSplit") .field("v", &self.inner.v) .field("finished", &self.inner.finished) @@ -3561,7 +3778,7 @@ pub struct RSplitMut<'a, T:'a, P> where P: FnMut(&T) -> bool { #[stable(feature = "slice_rsplit", since = "1.27.0")] impl fmt::Debug for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RSplitMut") .field("v", &self.inner.v) .field("finished", &self.inner.finished) @@ -3647,7 +3864,7 @@ pub struct SplitN<'a, T: 'a, P> where P: FnMut(&T) -> bool { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for SplitN<'_, T, P> where P: FnMut(&T) -> bool { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitN") .field("inner", &self.inner) .finish() @@ -3669,7 +3886,7 @@ pub struct RSplitN<'a, T: 'a, P> where P: FnMut(&T) -> bool { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for RSplitN<'_, T, P> where P: FnMut(&T) -> bool { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RSplitN") .field("inner", &self.inner) .finish() @@ -3690,7 +3907,7 @@ pub struct SplitNMut<'a, T: 'a, P> where P: FnMut(&T) -> bool { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for SplitNMut<'_, T, P> where P: FnMut(&T) -> bool { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitNMut") .field("inner", &self.inner) .finish() @@ -3712,7 +3929,7 @@ pub struct RSplitNMut<'a, T: 'a, P> where P: FnMut(&T) -> bool { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for RSplitNMut<'_, T, P> where P: FnMut(&T) -> bool { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RSplitNMut") .field("inner", &self.inner) .finish() @@ -3839,6 +4056,19 @@ impl<'a, T> DoubleEndedIterator for Windows<'a, T> { ret } } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let (end, overflow) = self.v.len().overflowing_sub(n); + if end < self.size || overflow { + self.v = &[]; + None + } else { + let ret = &self.v[end-self.size..end]; + self.v = &self.v[..end-1]; + Some(ret) + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -3961,6 +4191,24 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { Some(snd) } } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + Some(res) => cmp::min(res, self.v.len()), + None => self.v.len(), + }; + let nth_back = &self.v[start..end]; + self.v = &self.v[..start]; + Some(nth_back) + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -4452,6 +4700,23 @@ impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { Some(fst) } } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + // can't underflow because `n < len` + let offset_from_end = (len - 1 - n) * self.chunk_size; + let end = self.v.len() - offset_from_end; + let start = end.saturating_sub(self.chunk_size); + let nth_back = &self.v[start..end]; + self.v = &self.v[end..]; + Some(nth_back) + } + } } #[stable(feature = "rchunks", since = "1.31.0")] @@ -4577,6 +4842,24 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { Some(head) } } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + // can't underflow because `n < len` + let offset_from_end = (len - 1 - n) * self.chunk_size; + let end = self.v.len() - offset_from_end; + let start = end.saturating_sub(self.chunk_size); + let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (_, nth_back) = tmp.split_at_mut(start); + self.v = tail; + Some(nth_back) + } + } } #[stable(feature = "rchunks", since = "1.31.0")] @@ -4701,6 +4984,24 @@ impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { Some(fst) } } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + // now that we know that `n` corresponds to a chunk, + // none of these operations can underflow/overflow + let offset = (len - n) * self.chunk_size; + let start = self.v.len() - offset; + let end = start + self.chunk_size; + let nth_back = &self.v[start..end]; + self.v = &self.v[end..]; + Some(nth_back) + } + } } #[stable(feature = "rchunks", since = "1.31.0")] @@ -4819,6 +5120,25 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { Some(head) } } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + // now that we know that `n` corresponds to a chunk, + // none of these operations can underflow/overflow + let offset = (len - n) * self.chunk_size; + let start = self.v.len() - offset; + let end = start + self.chunk_size; + let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (_, nth_back) = tmp.split_at_mut(start); + self.v = tail; + Some(nth_back) + } + } } #[stable(feature = "rchunks", since = "1.31.0")] @@ -4896,7 +5216,7 @@ pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { debug_assert!(data as usize % mem::align_of::() == 0, "attempt to create unaligned slice"); debug_assert!(mem::size_of::().saturating_mul(len) <= isize::MAX as usize, "attempt to create slice covering half the address space"); - Repr { raw: FatPtr { data, len } }.rust + &*ptr::slice_from_raw_parts(data, len) } /// Performs the same functionality as [`from_raw_parts`], except that a @@ -4917,7 +5237,7 @@ pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] debug_assert!(data as usize % mem::align_of::() == 0, "attempt to create unaligned slice"); debug_assert!(mem::size_of::().saturating_mul(len) <= isize::MAX as usize, "attempt to create slice covering half the address space"); - Repr { raw: FatPtr { data, len } }.rust_mut + &mut *ptr::slice_from_raw_parts_mut(data, len) } /// Converts a reference to T into a slice of length 1 (without copying). @@ -5133,7 +5453,7 @@ macro_rules! impl_marker_for { } impl_marker_for!(BytewiseEquality, - u8 i8 u16 i16 u32 i32 u64 i64 usize isize char bool); + u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool); #[doc(hidden)] unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { diff --git a/src/libcore/slice/rotate.rs b/src/libcore/slice/rotate.rs index 9b35b51349a02..f69b219715aa1 100644 --- a/src/libcore/slice/rotate.rs +++ b/src/libcore/slice/rotate.rs @@ -1,6 +1,6 @@ -use cmp; -use mem::{self, MaybeUninit}; -use ptr; +use crate::cmp; +use crate::mem::{self, MaybeUninit}; +use crate::ptr; /// Rotation is much faster if it has access to a little bit of memory. This /// union provides a RawVec-like interface, but to a fixed-size stack buffer. @@ -72,7 +72,7 @@ pub unsafe fn ptr_rotate(mut left: usize, mid: *mut T, mut right: usize) { } } - let mut rawarray = MaybeUninit::>::uninitialized(); + let mut rawarray = MaybeUninit::>::uninit(); let buf = &mut (*rawarray.as_mut_ptr()).typed as *mut [T; 2] as *mut T; let dim = mid.sub(left).add(right); diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 3f84faa049939..c293b1900187e 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -6,9 +6,9 @@ //! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our //! stable sorting implementation. -use cmp; -use mem::{self, MaybeUninit}; -use ptr; +use crate::cmp; +use crate::mem::{self, MaybeUninit}; +use crate::ptr; /// When dropped, copies from `src` into `dest`. struct CopyOnDrop { @@ -691,3 +691,92 @@ pub fn quicksort(v: &mut [T], mut is_less: F) recurse(v, &mut is_less, None, limit); } + +fn partition_at_index_loop<'a, T, F>( mut v: &'a mut [T], mut index: usize, is_less: &mut F + , mut pred: Option<&'a T>) where F: FnMut(&T, &T) -> bool +{ + loop { + // For slices of up to this length it's probably faster to simply sort them. + const MAX_INSERTION: usize = 10; + if v.len() <= MAX_INSERTION { + insertion_sort(v, is_less); + return; + } + + // Choose a pivot + let (pivot, _) = choose_pivot(v, is_less); + + // If the chosen pivot is equal to the predecessor, then it's the smallest element in the + // slice. Partition the slice into elements equal to and elements greater than the pivot. + // This case is usually hit when the slice contains many duplicate elements. + if let Some(p) = pred { + if !is_less(p, &v[pivot]) { + let mid = partition_equal(v, pivot, is_less); + + // If we've passed our index, then we're good. + if mid > index { + return; + } + + // Otherwise, continue sorting elements greater than the pivot. + v = &mut v[mid..]; + index = index - mid; + pred = None; + continue; + } + } + + let (mid, _) = partition(v, pivot, is_less); + + // Split the slice into `left`, `pivot`, and `right`. + let (left, right) = {v}.split_at_mut(mid); + let (pivot, right) = right.split_at_mut(1); + let pivot = &pivot[0]; + + if mid < index { + v = right; + index = index - mid - 1; + pred = Some(pivot); + } else if mid > index { + v = left; + } else { + // If mid == index, then we're done, since partition() guaranteed that all elements + // after mid are greater than or equal to mid. + return; + } + } +} + +pub fn partition_at_index(v: &mut [T], index: usize, mut is_less: F) + -> (&mut [T], &mut T, &mut [T]) where F: FnMut(&T, &T) -> bool +{ + use cmp::Ordering::Less; + use cmp::Ordering::Greater; + + if index >= v.len() { + panic!("partition_at_index index {} greater than length of slice {}", index, v.len()); + } + + if mem::size_of::() == 0 { + // Sorting has no meaningful behavior on zero-sized types. Do nothing. + } else if index == v.len() - 1 { + // Find max element and place it in the last position of the array. We're free to use + // `unwrap()` here because we know v must not be empty. + let (max_index, _) = v.iter().enumerate().max_by( + |&(_, x), &(_, y)| if is_less(x, y) { Less } else { Greater }).unwrap(); + v.swap(max_index, index); + } else if index == 0 { + // Find min element and place it in the first position of the array. We're free to use + // `unwrap()` here because we know v must not be empty. + let (min_index, _) = v.iter().enumerate().min_by( + |&(_, x), &(_, y)| if is_less(x, y) { Less } else { Greater }).unwrap(); + v.swap(min_index, index); + } else { + partition_at_index_loop(v, index, &mut is_less, None); + } + + let (left, right) = v.split_at_mut(index); + let (pivot, right) = right.split_at_mut(1); + let pivot = &mut pivot[0]; + (left, pivot, right) +} diff --git a/src/libcore/str/lossy.rs b/src/libcore/str/lossy.rs index b3e8527c4ae0b..b291579553a64 100644 --- a/src/libcore/str/lossy.rs +++ b/src/libcore/str/lossy.rs @@ -1,8 +1,7 @@ -use char; -use str as core_str; -use fmt; -use fmt::Write; -use mem; +use crate::char; +use crate::str as core_str; +use crate::fmt::{self, Write}; +use crate::mem; /// Lossy UTF-8 string. #[unstable(feature = "str_internals", issue = "0")] @@ -19,7 +18,7 @@ impl Utf8Lossy { unsafe { mem::transmute(bytes) } } - pub fn chunks(&self) -> Utf8LossyChunksIter { + pub fn chunks(&self) -> Utf8LossyChunksIter<'_> { Utf8LossyChunksIter { source: &self.bytes } } } @@ -139,7 +138,7 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> { impl fmt::Display for Utf8Lossy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // If we're the empty string then our iterator won't actually yield // anything, so perform the formatting manually if self.bytes.len() == 0 { @@ -165,7 +164,7 @@ impl fmt::Display for Utf8Lossy { } impl fmt::Debug for Utf8Lossy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_char('"')?; for Utf8LossyChunk { valid, broken } in self.chunks() { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 8b51d8465141a..34f2d8917ea47 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + //! String manipulation. //! //! For more details, see the `std::str` module. @@ -7,14 +9,14 @@ use self::pattern::Pattern; use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; -use char; -use fmt::{self, Write}; -use iter::{Map, Cloned, FusedIterator, TrustedLen, TrustedRandomAccess, Filter}; -use iter::{Flatten, FlatMap, Chain}; -use slice::{self, SliceIndex, Split as SliceSplit}; -use mem; -use ops::Try; -use option; +use crate::char; +use crate::fmt::{self, Write}; +use crate::iter::{Map, Cloned, FusedIterator, TrustedLen, TrustedRandomAccess, Filter}; +use crate::iter::{Flatten, FlatMap, Chain}; +use crate::slice::{self, SliceIndex, Split as SliceSplit}; +use crate::mem; +use crate::ops::Try; +use crate::option; pub mod pattern; @@ -146,7 +148,7 @@ pub struct ParseBoolError { _priv: () } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for ParseBoolError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "provided string was not `true` or `false`".fmt(f) } } @@ -439,7 +441,7 @@ pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Utf8Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(error_len) = self.error_len { write!(f, "invalid utf-8 sequence of {} bytes from index {}", error_len, self.valid_up_to) @@ -795,6 +797,11 @@ impl DoubleEndedIterator for Bytes<'_> { self.0.next_back() } + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.0.nth_back(n) + } + #[inline] fn rfind

(&mut self, predicate: P) -> Option where P: FnMut(&Self::Item) -> bool @@ -914,7 +921,7 @@ macro_rules! generate_pattern_iterators { impl<'a, P: Pattern<'a>> fmt::Debug for $forward_iterator<'a, P> where P::Searcher: fmt::Debug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple(stringify!($forward_iterator)) .field(&self.0) .finish() @@ -948,7 +955,7 @@ macro_rules! generate_pattern_iterators { impl<'a, P: Pattern<'a>> fmt::Debug for $reverse_iterator<'a, P> where P::Searcher: fmt::Debug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple(stringify!($reverse_iterator)) .field(&self.0) .finish() @@ -1033,7 +1040,7 @@ struct SplitInternal<'a, P: Pattern<'a>> { } impl<'a, P: Pattern<'a>> fmt::Debug for SplitInternal<'a, P> where P::Searcher: fmt::Debug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitInternal") .field("start", &self.start) .field("end", &self.end) @@ -1150,7 +1157,7 @@ struct SplitNInternal<'a, P: Pattern<'a>> { } impl<'a, P: Pattern<'a>> fmt::Debug for SplitNInternal<'a, P> where P::Searcher: fmt::Debug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitNInternal") .field("iter", &self.iter) .field("count", &self.count) @@ -1206,7 +1213,7 @@ derive_pattern_clone!{ struct MatchIndicesInternal<'a, P: Pattern<'a>>(P::Searcher); impl<'a, P: Pattern<'a>> fmt::Debug for MatchIndicesInternal<'a, P> where P::Searcher: fmt::Debug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("MatchIndicesInternal") .field(&self.0) .finish() @@ -1257,7 +1264,7 @@ derive_pattern_clone!{ struct MatchesInternal<'a, P: Pattern<'a>>(P::Searcher); impl<'a, P: Pattern<'a>> fmt::Debug for MatchesInternal<'a, P> where P::Searcher: fmt::Debug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("MatchesInternal") .field(&self.0) .finish() @@ -1557,9 +1564,9 @@ Section: Trait implementations */ mod traits { - use cmp::Ordering; - use ops; - use slice::{self, SliceIndex}; + use crate::cmp::Ordering; + use crate::ops; + use crate::slice::{self, SliceIndex}; /// Implements ordering of strings. /// @@ -2181,7 +2188,11 @@ impl str { /// [`u8`]. This pointer will be pointing to the first byte of the string /// slice. /// + /// The caller must ensure that the returned pointer is never written to. + /// If you need to mutate the contents of the string slice, use [`as_mut_ptr`]. + /// /// [`u8`]: primitive.u8.html + /// [`as_mut_ptr`]: #method.as_mut_ptr /// /// # Examples /// @@ -2207,7 +2218,7 @@ impl str { /// modified in a way that it remains valid UTF-8. /// /// [`u8`]: primitive.u8.html - #[unstable(feature = "str_as_mut_ptr", issue = "58215")] + #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] #[inline] pub fn as_mut_ptr(&mut self) -> *mut u8 { self as *mut str as *mut u8 @@ -2559,7 +2570,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn chars(&self) -> Chars { + pub fn chars(&self) -> Chars<'_> { Chars{iter: self.as_bytes().iter()} } @@ -2614,7 +2625,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn char_indices(&self) -> CharIndices { + pub fn char_indices(&self) -> CharIndices<'_> { CharIndices { front_offset: 0, iter: self.chars() } } @@ -2639,7 +2650,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn bytes(&self) -> Bytes { + pub fn bytes(&self) -> Bytes<'_> { Bytes(self.as_bytes().iter().cloned()) } @@ -2682,7 +2693,7 @@ impl str { /// ``` #[stable(feature = "split_whitespace", since = "1.1.0")] #[inline] - pub fn split_whitespace(&self) -> SplitWhitespace { + pub fn split_whitespace(&self) -> SplitWhitespace<'_> { SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } } @@ -2712,7 +2723,7 @@ impl str { /// All kinds of ASCII whitespace are considered: /// /// ``` - /// let mut iter = " Mary had\ta little \n\t lamb".split_whitespace(); + /// let mut iter = " Mary had\ta little \n\t lamb".split_ascii_whitespace(); /// assert_eq!(Some("Mary"), iter.next()); /// assert_eq!(Some("had"), iter.next()); /// assert_eq!(Some("a"), iter.next()); @@ -2723,7 +2734,7 @@ impl str { /// ``` #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] #[inline] - pub fn split_ascii_whitespace(&self) -> SplitAsciiWhitespace { + pub fn split_ascii_whitespace(&self) -> SplitAsciiWhitespace<'_> { let inner = self .as_bytes() .split(IsAsciiWhitespace) @@ -2770,7 +2781,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn lines(&self) -> Lines { + pub fn lines(&self) -> Lines<'_> { Lines(self.split_terminator('\n').map(LinesAnyMap)) } @@ -2779,7 +2790,7 @@ impl str { #[rustc_deprecated(since = "1.4.0", reason = "use lines() instead now")] #[inline] #[allow(deprecated)] - pub fn lines_any(&self) -> LinesAny { + pub fn lines_any(&self) -> LinesAny<'_> { LinesAny(self.lines()) } @@ -2798,7 +2809,7 @@ impl str { /// assert!(utf16_len <= utf8_len); /// ``` #[stable(feature = "encode_utf16", since = "1.8.0")] - pub fn encode_utf16(&self) -> EncodeUtf16 { + pub fn encode_utf16(&self) -> EncodeUtf16<'_> { EncodeUtf16 { chars: self.chars(), extra: 0 } } @@ -2968,7 +2979,7 @@ impl str { /// /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. + /// elements. This is true for, e.g., [`char`], but not for `&str`. /// /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html /// @@ -3143,7 +3154,7 @@ impl str { /// /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. + /// elements. This is true for, e.g., [`char`], but not for `&str`. /// /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html /// @@ -3326,7 +3337,7 @@ impl str { /// /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. + /// elements. This is true for, e.g., [`char`], but not for `&str`. /// /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html /// @@ -3402,7 +3413,7 @@ impl str { /// /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. + /// elements. This is true for, e.g., [`char`], but not for `&str`. /// /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html /// @@ -3601,7 +3612,11 @@ impl str { /// assert!(Some('ע') == s.trim_left().chars().next()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(reason = "superseded by `trim_start`", since = "1.33.0")] + #[rustc_deprecated( + since = "1.33.0", + reason = "superseded by `trim_start`", + suggestion = "trim_start", + )] pub fn trim_left(&self) -> &str { self.trim_start() } @@ -3638,7 +3653,11 @@ impl str { /// assert!(Some('ת') == s.trim_right().chars().rev().next()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(reason = "superseded by `trim_end`", since = "1.33.0")] + #[rustc_deprecated( + since = "1.33.0", + reason = "superseded by `trim_end`", + suggestion = "trim_end", + )] pub fn trim_right(&self) -> &str { self.trim_end() } @@ -3802,7 +3821,11 @@ impl str { /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(reason = "superseded by `trim_start_matches`", since = "1.33.0")] + #[rustc_deprecated( + since = "1.33.0", + reason = "superseded by `trim_start_matches`", + suggestion = "trim_start_matches", + )] pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { self.trim_start_matches(pat) } @@ -3840,7 +3863,11 @@ impl str { /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(reason = "superseded by `trim_end_matches`", since = "1.33.0")] + #[rustc_deprecated( + since = "1.33.0", + reason = "superseded by `trim_end_matches`", + suggestion = "trim_end_matches", + )] pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str where P::Searcher: ReverseSearcher<'a> { @@ -3944,6 +3971,16 @@ impl str { /// [`to_ascii_uppercase`]. /// /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + /// + /// # Examples + /// + /// ``` + /// let mut s = String::from("Grüße, Jürgen ❤"); + /// + /// s.make_ascii_uppercase(); + /// + /// assert_eq!("GRüßE, JüRGEN ❤", s); + /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] pub fn make_ascii_uppercase(&mut self) { let me = unsafe { self.as_bytes_mut() }; @@ -3959,13 +3996,23 @@ impl str { /// [`to_ascii_lowercase`]. /// /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + /// + /// # Examples + /// + /// ``` + /// let mut s = String::from("GRÜßE, JÜRGEN ❤"); + /// + /// s.make_ascii_lowercase(); + /// + /// assert_eq!("grÜße, jÜrgen ❤", s); + /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] pub fn make_ascii_lowercase(&mut self) { let me = unsafe { self.as_bytes_mut() }; me.make_ascii_lowercase() } - /// Return an iterator that escapes each char in `s` with [`char::escape_debug`]. + /// Return an iterator that escapes each char in `self` with [`char::escape_debug`]. /// /// Note: only extended grapheme codepoints that begin the string will be /// escaped. @@ -4002,7 +4049,7 @@ impl str { /// assert_eq!("❤\n!".escape_debug().to_string(), "❤\\n!"); /// ``` #[stable(feature = "str_escape", since = "1.34.0")] - pub fn escape_debug(&self) -> EscapeDebug { + pub fn escape_debug(&self) -> EscapeDebug<'_> { let mut chars = self.chars(); EscapeDebug { inner: chars.next() @@ -4013,7 +4060,7 @@ impl str { } } - /// Return an iterator that escapes each char in `s` with [`char::escape_default`]. + /// Return an iterator that escapes each char in `self` with [`char::escape_default`]. /// /// [`char::escape_default`]: ../std/primitive.char.html#method.escape_default /// @@ -4038,7 +4085,7 @@ impl str { /// Both are equivalent to: /// /// ``` - /// println!("\\u{{2764}}\n!"); + /// println!("\\u{{2764}}\\n!"); /// ``` /// /// Using `to_string`: @@ -4047,11 +4094,11 @@ impl str { /// assert_eq!("❤\n!".escape_default().to_string(), "\\u{2764}\\n!"); /// ``` #[stable(feature = "str_escape", since = "1.34.0")] - pub fn escape_default(&self) -> EscapeDefault { + pub fn escape_default(&self) -> EscapeDefault<'_> { EscapeDefault { inner: self.chars().flat_map(CharEscapeDefault) } } - /// Return an iterator that escapes each char in `s` with [`char::escape_unicode`]. + /// Return an iterator that escapes each char in `self` with [`char::escape_unicode`]. /// /// [`char::escape_unicode`]: ../std/primitive.char.html#method.escape_unicode /// @@ -4085,7 +4132,7 @@ impl str { /// assert_eq!("❤\n!".escape_unicode().to_string(), "\\u{2764}\\u{a}\\u{21}"); /// ``` #[stable(feature = "str_escape", since = "1.34.0")] - pub fn escape_unicode(&self) -> EscapeUnicode { + pub fn escape_unicode(&self) -> EscapeUnicode<'_> { EscapeUnicode { inner: self.chars().flat_map(CharEscapeUnicode) } } } @@ -4251,7 +4298,7 @@ pub struct EncodeUtf16<'a> { #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for EncodeUtf16<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("EncodeUtf16 { .. }") } } @@ -4325,7 +4372,7 @@ macro_rules! escape_types_impls { ($( $Name: ident ),+) => {$( #[stable(feature = "str_escape", since = "1.34.0")] impl<'a> fmt::Display for $Name<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.clone().try_for_each(|c| f.write_char(c)) } } diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 2571780ad0bab..ad9d956fda1c8 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -7,10 +7,10 @@ reason = "API not fully fleshed out and ready to be stabilized", issue = "27721")] -use cmp; -use fmt; -use slice::memchr; -use usize; +use crate::cmp; +use crate::fmt; +use crate::slice::memchr; +use crate::usize; // Pattern @@ -658,7 +658,7 @@ pub struct CharPredicateSearcher<'a, F>( as Pattern<'a>>:: impl fmt::Debug for CharPredicateSearcher<'_, F> where F: FnMut(char) -> bool { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CharPredicateSearcher") .field("haystack", &self.0.haystack) .field("char_indices", &self.0.char_indices) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index d0ee5fa9e6b31..8dfb19fa03296 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -118,21 +118,34 @@ use self::Ordering::*; -use intrinsics; -use cell::UnsafeCell; -use fmt; +use crate::intrinsics; +use crate::cell::UnsafeCell; +use crate::fmt; -use hint::spin_loop; +use crate::hint::spin_loop; -/// Save power or switch hyperthreads in a busy-wait spin-loop. +/// Signals the processor that it is entering a busy-wait spin-loop. /// -/// This function is deliberately more primitive than -/// [`std::thread::yield_now`](../../../std/thread/fn.yield_now.html) and -/// does not directly yield to the system's scheduler. -/// In some cases it might be useful to use a combination of both functions. -/// Careful benchmarking is advised. +/// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving +/// power or switching hyper-threads. /// -/// On some platforms this function may not do anything at all. +/// This function is different than [`std::thread::yield_now`] which directly yields to the +/// system's scheduler, whereas `spin_loop_hint` only signals the processor that it is entering a +/// busy-wait spin-loop without yielding control to the system's scheduler. +/// +/// Using a busy-wait spin-loop with `spin_loop_hint` is ideally used in situations where a +/// contended lock is held by another thread executed on a different CPU and where the waiting +/// times are relatively small. Because entering busy-wait spin-loop does not trigger the system's +/// scheduler, no overhead for switching threads occurs. However, if the thread holding the +/// contended lock is running on the same CPU, the spin-loop is likely to occupy an entire CPU slice +/// before switching to the thread that holds the lock. If the contending lock is held by a thread +/// on the same CPU or if the waiting times for acquiring the lock are longer, it is often better to +/// use [`std::thread::yield_now`]. +/// +/// **Note**: On platforms that do not support receiving spin-loop hints this function does not +/// do anything at all. +/// +/// [`std::thread::yield_now`]: ../../../std/thread/fn.yield_now.html #[inline] #[stable(feature = "spin_loop_hint", since = "1.24.0")] pub fn spin_loop_hint() { @@ -182,7 +195,7 @@ pub struct AtomicPtr { impl Default for AtomicPtr { /// Creates a null `AtomicPtr`. fn default() -> AtomicPtr { - AtomicPtr::new(::ptr::null_mut()) + AtomicPtr::new(crate::ptr::null_mut()) } } @@ -290,15 +303,11 @@ pub enum Ordering { /// [`AtomicBool`]: struct.AtomicBool.html #[cfg(target_has_atomic = "8")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(stage0), rustc_deprecated( +#[rustc_deprecated( since = "1.34.0", reason = "the `new` function is now preferred", suggestion = "AtomicBool::new(false)", -))] -#[cfg_attr(stage0, rustc_deprecated( - since = "1.34.0", - reason = "the `new` function is now preferred", -))] +)] pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false); #[cfg(target_has_atomic = "8")] @@ -1158,15 +1167,11 @@ macro_rules! atomic_int { /// An atomic integer initialized to `0`. #[$stable_init_const] - #[cfg_attr(stage0, rustc_deprecated( - since = "1.34.0", - reason = "the `new` function is now preferred", - ))] - #[cfg_attr(not(stage0), rustc_deprecated( + #[rustc_deprecated( since = "1.34.0", reason = "the `new` function is now preferred", suggestion = $atomic_new, - ))] + )] pub const $atomic_init: $atomic_type = $atomic_type::new(0); #[$stable] @@ -1188,7 +1193,7 @@ macro_rules! atomic_int { #[$stable_debug] impl fmt::Debug for $atomic_type { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.load(Ordering::SeqCst), f) } } @@ -1894,7 +1899,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), "i8", "../../../std/primitive.i8.html", - "#![feature(integer_atomics)]\n\n", + "", atomic_min, atomic_max, 1, "AtomicI8::new(0)", @@ -1910,7 +1915,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), "u8", "../../../std/primitive.u8.html", - "#![feature(integer_atomics)]\n\n", + "", atomic_umin, atomic_umax, 1, "AtomicU8::new(0)", @@ -1926,7 +1931,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), "i16", "../../../std/primitive.i16.html", - "#![feature(integer_atomics)]\n\n", + "", atomic_min, atomic_max, 2, "AtomicI16::new(0)", @@ -1942,7 +1947,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), "u16", "../../../std/primitive.u16.html", - "#![feature(integer_atomics)]\n\n", + "", atomic_umin, atomic_umax, 2, "AtomicU16::new(0)", @@ -1958,7 +1963,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), "i32", "../../../std/primitive.i32.html", - "#![feature(integer_atomics)]\n\n", + "", atomic_min, atomic_max, 4, "AtomicI32::new(0)", @@ -1974,7 +1979,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), "u32", "../../../std/primitive.u32.html", - "#![feature(integer_atomics)]\n\n", + "", atomic_umin, atomic_umax, 4, "AtomicU32::new(0)", @@ -1990,7 +1995,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), "i64", "../../../std/primitive.i64.html", - "#![feature(integer_atomics)]\n\n", + "", atomic_min, atomic_max, 8, "AtomicI64::new(0)", @@ -2006,7 +2011,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), "u64", "../../../std/primitive.u64.html", - "#![feature(integer_atomics)]\n\n", + "", atomic_umin, atomic_umax, 8, "AtomicU64::new(0)", @@ -2501,7 +2506,7 @@ pub fn compiler_fence(order: Ordering) { #[cfg(target_has_atomic = "8")] #[stable(feature = "atomic_debug", since = "1.3.0")] impl fmt::Debug for AtomicBool { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.load(Ordering::SeqCst), f) } } @@ -2509,7 +2514,7 @@ impl fmt::Debug for AtomicBool { #[cfg(target_has_atomic = "ptr")] #[stable(feature = "atomic_debug", since = "1.3.0")] impl fmt::Debug for AtomicPtr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.load(Ordering::SeqCst), f) } } @@ -2517,7 +2522,7 @@ impl fmt::Debug for AtomicPtr { #[cfg(target_has_atomic = "ptr")] #[stable(feature = "atomic_pointer", since = "1.24.0")] impl fmt::Pointer for AtomicPtr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Pointer::fmt(&self.load(Ordering::SeqCst), f) } } diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 9b8f598116200..ef090928392cd 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -1,11 +1,11 @@ -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#![stable(feature = "futures_api", since = "1.36.0")] //! Types and Traits for working with asynchronous tasks. mod poll; +#[stable(feature = "futures_api", since = "1.36.0")] pub use self::poll::Poll; mod wake; -pub use self::wake::{Waker, RawWaker, RawWakerVTable}; +#[stable(feature = "futures_api", since = "1.36.0")] +pub use self::wake::{Context, Waker, RawWaker, RawWakerVTable}; diff --git a/src/libcore/task/poll.rs b/src/libcore/task/poll.rs index c811f96ace3ba..3db70d5e7645f 100644 --- a/src/libcore/task/poll.rs +++ b/src/libcore/task/poll.rs @@ -1,28 +1,33 @@ -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#![stable(feature = "futures_api", since = "1.36.0")] -use ops::Try; -use result::Result; +use crate::ops::Try; +use crate::result::Result; /// Indicates whether a value is available or if the current task has been /// scheduled to receive a wakeup instead. #[must_use = "this `Poll` may be a `Pending` variant, which should be handled"] #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[stable(feature = "futures_api", since = "1.36.0")] pub enum Poll { /// Represents that a value is immediately ready. - Ready(T), + #[stable(feature = "futures_api", since = "1.36.0")] + Ready( + #[stable(feature = "futures_api", since = "1.36.0")] + T + ), /// Represents that a value is not ready yet. /// /// When a function returns `Pending`, the function *must* also /// ensure that the current task is scheduled to be awoken when /// progress can be made. + #[stable(feature = "futures_api", since = "1.36.0")] Pending, } impl Poll { /// Changes the ready value of this `Poll` with the closure provided. + #[stable(feature = "futures_api", since = "1.36.0")] pub fn map(self, f: F) -> Poll where F: FnOnce(T) -> U { @@ -34,6 +39,7 @@ impl Poll { /// Returns `true` if this is `Poll::Ready` #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] pub fn is_ready(&self) -> bool { match *self { Poll::Ready(_) => true, @@ -43,6 +49,7 @@ impl Poll { /// Returns `true` if this is `Poll::Pending` #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] pub fn is_pending(&self) -> bool { !self.is_ready() } @@ -50,6 +57,7 @@ impl Poll { impl Poll> { /// Changes the success value of this `Poll` with the closure provided. + #[stable(feature = "futures_api", since = "1.36.0")] pub fn map_ok(self, f: F) -> Poll> where F: FnOnce(T) -> U { @@ -61,6 +69,7 @@ impl Poll> { } /// Changes the error value of this `Poll` with the closure provided. + #[stable(feature = "futures_api", since = "1.36.0")] pub fn map_err(self, f: F) -> Poll> where F: FnOnce(E) -> U { @@ -72,12 +81,14 @@ impl Poll> { } } +#[stable(feature = "futures_api", since = "1.36.0")] impl From for Poll { fn from(t: T) -> Poll { Poll::Ready(t) } } +#[stable(feature = "futures_api", since = "1.36.0")] impl Try for Poll> { type Ok = Poll; type Error = E; @@ -102,6 +113,7 @@ impl Try for Poll> { } } +#[stable(feature = "futures_api", since = "1.36.0")] impl Try for Poll>> { type Ok = Poll>; type Error = E; diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index 21f0a8cea4168..f1247239f4f50 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -1,9 +1,7 @@ -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#![stable(feature = "futures_api", since = "1.36.0")] -use fmt; -use marker::Unpin; +use crate::fmt; +use crate::marker::{PhantomData, Unpin}; /// A `RawWaker` allows the implementor of a task executor to create a [`Waker`] /// which provides customized wakeup behavior. @@ -12,7 +10,10 @@ use marker::Unpin; /// /// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that /// customizes the behavior of the `RawWaker`. +/// +/// [`Waker`]: struct.Waker.html #[derive(PartialEq, Debug)] +#[stable(feature = "futures_api", since = "1.36.0")] pub struct RawWaker { /// A data pointer, which can be used to store arbitrary data as required /// by the executor. This could be e.g. a type-erased pointer to an `Arc` @@ -36,6 +37,8 @@ impl RawWaker { /// The `vtable` customizes the behavior of a `Waker` which gets created /// from a `RawWaker`. For each operation on the `Waker`, the associated /// function in the `vtable` of the underlying `RawWaker` will be called. + #[rustc_promotable] + #[stable(feature = "futures_api", since = "1.36.0")] pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker { RawWaker { data, @@ -54,6 +57,9 @@ impl RawWaker { /// pointer of a properly constructed [`RawWaker`] object from inside the /// [`RawWaker`] implementation. Calling one of the contained functions using /// any other `data` pointer will cause undefined behavior. +/// +/// [`RawWaker`]: struct.RawWaker.html +#[stable(feature = "futures_api", since = "1.36.0")] #[derive(PartialEq, Copy, Clone, Debug)] pub struct RawWakerVTable { /// This function will be called when the [`RawWaker`] gets cloned, e.g. when @@ -63,21 +69,146 @@ pub struct RawWakerVTable { /// required for this additional instance of a [`RawWaker`] and associated /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup /// of the same task that would have been awoken by the original [`RawWaker`]. - pub clone: unsafe fn(*const ()) -> RawWaker, + /// + /// [`Waker`]: struct.Waker.html + /// [`RawWaker`]: struct.RawWaker.html + clone: unsafe fn(*const ()) -> RawWaker, /// This function will be called when `wake` is called on the [`Waker`]. /// It must wake up the task associated with this [`RawWaker`]. /// - /// The implemention of this function must not consume the provided data + /// The implementation of this function must make sure to release any + /// resources that are associated with this instance of a [`RawWaker`] and + /// associated task. + /// + /// [`Waker`]: struct.Waker.html + /// [`RawWaker`]: struct.RawWaker.html + wake: unsafe fn(*const ()), + + /// This function will be called when `wake_by_ref` is called on the [`Waker`]. + /// It must wake up the task associated with this [`RawWaker`]. + /// + /// This function is similar to `wake`, but must not consume the provided data /// pointer. - pub wake: unsafe fn(*const ()), + /// + /// [`Waker`]: struct.Waker.html + /// [`RawWaker`]: struct.RawWaker.html + wake_by_ref: unsafe fn(*const ()), /// This function gets called when a [`RawWaker`] gets dropped. /// /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. - pub drop: unsafe fn(*const ()), + /// + /// [`RawWaker`]: struct.RawWaker.html + drop: unsafe fn(*const ()), +} + +impl RawWakerVTable { + /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`, + /// `wake_by_ref`, and `drop` functions. + /// + /// # `clone` + /// + /// This function will be called when the [`RawWaker`] gets cloned, e.g. when + /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned. + /// + /// The implementation of this function must retain all resources that are + /// required for this additional instance of a [`RawWaker`] and associated + /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup + /// of the same task that would have been awoken by the original [`RawWaker`]. + /// + /// # `wake` + /// + /// This function will be called when `wake` is called on the [`Waker`]. + /// It must wake up the task associated with this [`RawWaker`]. + /// + /// The implementation of this function must make sure to release any + /// resources that are associated with this instance of a [`RawWaker`] and + /// associated task. + /// + /// # `wake_by_ref` + /// + /// This function will be called when `wake_by_ref` is called on the [`Waker`]. + /// It must wake up the task associated with this [`RawWaker`]. + /// + /// This function is similar to `wake`, but must not consume the provided data + /// pointer. + /// + /// # `drop` + /// + /// This function gets called when a [`RawWaker`] gets dropped. + /// + /// The implementation of this function must make sure to release any + /// resources that are associated with this instance of a [`RawWaker`] and + /// associated task. + /// + /// [`Waker`]: struct.Waker.html + /// [`RawWaker`]: struct.RawWaker.html + #[rustc_promotable] + #[stable(feature = "futures_api", since = "1.36.0")] + // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else + // without first consulting with T-Lang. + // + // FIXME: remove whenever we have a stable way to accept fn pointers from const fn + // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062) + #[rustc_allow_const_fn_ptr] + pub const fn new( + clone: unsafe fn(*const ()) -> RawWaker, + wake: unsafe fn(*const ()), + wake_by_ref: unsafe fn(*const ()), + drop: unsafe fn(*const ()), + ) -> Self { + Self { + clone, + wake, + wake_by_ref, + drop, + } + } +} + +/// The `Context` of an asynchronous task. +/// +/// Currently, `Context` only serves to provide access to a `&Waker` +/// which can be used to wake the current task. +#[stable(feature = "futures_api", since = "1.36.0")] +pub struct Context<'a> { + waker: &'a Waker, + // Ensure we future-proof against variance changes by forcing + // the lifetime to be invariant (argument-position lifetimes + // are contravariant while return-position lifetimes are + // covariant). + _marker: PhantomData &'a ()>, +} + +impl<'a> Context<'a> { + /// Create a new `Context` from a `&Waker`. + #[stable(feature = "futures_api", since = "1.36.0")] + #[inline] + pub fn from_waker(waker: &'a Waker) -> Self { + Context { + waker, + _marker: PhantomData, + } + } + + /// Returns a reference to the `Waker` for the current task. + #[stable(feature = "futures_api", since = "1.36.0")] + #[inline] + pub fn waker(&self) -> &'a Waker { + &self.waker + } +} + +#[stable(feature = "futures_api", since = "1.36.0")] +impl fmt::Debug for Context<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Context") + .field("waker", &self.waker) + .finish() + } } /// A `Waker` is a handle for waking up a task by notifying its executor that it @@ -87,34 +218,64 @@ pub struct RawWakerVTable { /// executor-specific wakeup behavior. /// /// Implements [`Clone`], [`Send`], and [`Sync`]. +/// +/// [`RawWaker`]: struct.RawWaker.html #[repr(transparent)] +#[stable(feature = "futures_api", since = "1.36.0")] pub struct Waker { waker: RawWaker, } +#[stable(feature = "futures_api", since = "1.36.0")] impl Unpin for Waker {} +#[stable(feature = "futures_api", since = "1.36.0")] unsafe impl Send for Waker {} +#[stable(feature = "futures_api", since = "1.36.0")] unsafe impl Sync for Waker {} impl Waker { /// Wake up the task associated with this `Waker`. - pub fn wake(&self) { + #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] + pub fn wake(self) { // The actual wakeup call is delegated through a virtual function call // to the implementation which is defined by the executor. + let wake = self.waker.vtable.wake; + let data = self.waker.data; - // SAFETY: This is safe because `Waker::new_unchecked` is the only way + // Don't call `drop` -- the waker will be consumed by `wake`. + crate::mem::forget(self); + + // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `wake` and `data` requiring the user to acknowledge // that the contract of `RawWaker` is upheld. - unsafe { (self.waker.vtable.wake)(self.waker.data) } + unsafe { (wake)(data) }; + } + + /// Wake up the task associated with this `Waker` without consuming the `Waker`. + /// + /// This is similar to `wake`, but may be slightly less efficient in the case + /// where an owned `Waker` is available. This method should be preferred to + /// calling `waker.clone().wake()`. + #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] + pub fn wake_by_ref(&self) { + // The actual wakeup call is delegated through a virtual function call + // to the implementation which is defined by the executor. + + // SAFETY: see `wake` + unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) } } - /// Returns whether or not this `Waker` and other `Waker` have awaken the same task. + /// Returns `true` if this `Waker` and another `Waker` have awoken the same task. /// /// This function works on a best-effort basis, and may return false even /// when the `Waker`s would awaken the same task. However, if this function /// returns `true`, it is guaranteed that the `Waker`s will awaken the same task. /// /// This function is primarily used for optimization purposes. + #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] pub fn will_wake(&self, other: &Waker) -> bool { self.waker == other.waker } @@ -124,17 +285,24 @@ impl Waker { /// The behavior of the returned `Waker` is undefined if the contract defined /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld. /// Therefore this method is unsafe. - pub unsafe fn new_unchecked(waker: RawWaker) -> Waker { + /// + /// [`RawWaker`]: struct.RawWaker.html + /// [`RawWakerVTable`]: struct.RawWakerVTable.html + #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] + pub unsafe fn from_raw(waker: RawWaker) -> Waker { Waker { waker, } } } +#[stable(feature = "futures_api", since = "1.36.0")] impl Clone for Waker { + #[inline] fn clone(&self) -> Self { Waker { - // SAFETY: This is safe because `Waker::new_unchecked` is the only way + // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `clone` and `data` requiring the user to acknowledge // that the contract of [`RawWaker`] is upheld. waker: unsafe { (self.waker.vtable.clone)(self.waker.data) }, @@ -142,17 +310,20 @@ impl Clone for Waker { } } +#[stable(feature = "futures_api", since = "1.36.0")] impl Drop for Waker { + #[inline] fn drop(&mut self) { - // SAFETY: This is safe because `Waker::new_unchecked` is the only way + // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `drop` and `data` requiring the user to acknowledge // that the contract of `RawWaker` is upheld. unsafe { (self.waker.vtable.drop)(self.waker.data) } } } +#[stable(feature = "futures_api", since = "1.36.0")] impl fmt::Debug for Waker { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let vtable_ptr = self.waker.vtable as *const RawWakerVTable; f.debug_struct("Waker") .field("data", &self.waker.data) diff --git a/src/libcore/tests/alloc.rs b/src/libcore/tests/alloc.rs new file mode 100644 index 0000000000000..63537ba23d84d --- /dev/null +++ b/src/libcore/tests/alloc.rs @@ -0,0 +1,10 @@ +use core::alloc::Layout; + +#[test] +fn const_unchecked_layout() { + const SIZE: usize = 0x2000; + const ALIGN: usize = 0x1000; + const LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(SIZE, ALIGN) }; + assert_eq!(LAYOUT.size(), SIZE); + assert_eq!(LAYOUT.align(), ALIGN); +} diff --git a/src/libcore/tests/cell.rs b/src/libcore/tests/cell.rs index b16416022c04e..4dfd884d2377c 100644 --- a/src/libcore/tests/cell.rs +++ b/src/libcore/tests/cell.rs @@ -5,15 +5,15 @@ use std::mem::drop; #[test] fn smoketest_cell() { let x = Cell::new(10); - assert!(x == Cell::new(10)); - assert!(x.get() == 10); + assert_eq!(x, Cell::new(10)); + assert_eq!(x.get(), 10); x.set(20); - assert!(x == Cell::new(20)); - assert!(x.get() == 20); + assert_eq!(x, Cell::new(20)); + assert_eq!(x.get(), 20); let y = Cell::new((30, 40)); - assert!(y == Cell::new((30, 40))); - assert!(y.get() == (30, 40)); + assert_eq!(y, Cell::new((30, 40))); + assert_eq!(y.get(), (30, 40)); } #[test] @@ -109,7 +109,6 @@ fn double_borrow_single_release_no_borrow_mut() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn discard_doesnt_unborrow() { let x = RefCell::new(0); let _b = x.borrow(); @@ -140,11 +139,11 @@ fn ref_clone_updates_flag() { fn ref_map_does_not_update_flag() { let x = RefCell::new(Some(5)); { - let b1: Ref> = x.borrow(); + let b1: Ref<'_, Option> = x.borrow(); assert!(x.try_borrow().is_ok()); assert!(x.try_borrow_mut().is_err()); { - let b2: Ref = Ref::map(b1, |o| o.as_ref().unwrap()); + let b2: Ref<'_, u32> = Ref::map(b1, |o| o.as_ref().unwrap()); assert_eq!(*b2, 5); assert!(x.try_borrow().is_ok()); assert!(x.try_borrow_mut().is_err()); @@ -218,12 +217,12 @@ fn ref_mut_map_split() { fn ref_map_accessor() { struct X(RefCell<(u32, char)>); impl X { - fn accessor(&self) -> Ref { + fn accessor(&self) -> Ref<'_, u32> { Ref::map(self.0.borrow(), |tuple| &tuple.0) } } let x = X(RefCell::new((7, 'z'))); - let d: Ref = x.accessor(); + let d: Ref<'_, u32> = x.accessor(); assert_eq!(*d, 7); } @@ -231,13 +230,13 @@ fn ref_map_accessor() { fn ref_mut_map_accessor() { struct X(RefCell<(u32, char)>); impl X { - fn accessor(&self) -> RefMut { + fn accessor(&self) -> RefMut<'_, u32> { RefMut::map(self.0.borrow_mut(), |tuple| &mut tuple.0) } } let x = X(RefCell::new((7, 'z'))); { - let mut d: RefMut = x.accessor(); + let mut d: RefMut<'_ ,u32> = x.accessor(); assert_eq!(*d, 7); *d += 1; } @@ -334,23 +333,22 @@ fn refcell_unsized() { fn refcell_ref_coercion() { let cell: RefCell<[i32; 3]> = RefCell::new([1, 2, 3]); { - let mut cellref: RefMut<[i32; 3]> = cell.borrow_mut(); + let mut cellref: RefMut<'_, [i32; 3]> = cell.borrow_mut(); cellref[0] = 4; - let mut coerced: RefMut<[i32]> = cellref; + let mut coerced: RefMut<'_, [i32]> = cellref; coerced[2] = 5; } { let comp: &mut [i32] = &mut [4, 2, 5]; - let cellref: Ref<[i32; 3]> = cell.borrow(); + let cellref: Ref<'_, [i32; 3]> = cell.borrow(); assert_eq!(&*cellref, comp); - let coerced: Ref<[i32]> = cellref; + let coerced: Ref<'_, [i32]> = cellref; assert_eq!(&*coerced, comp); } } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn refcell_swap_borrows() { let x = RefCell::new(0); let _b = x.borrow(); @@ -360,7 +358,6 @@ fn refcell_swap_borrows() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn refcell_replace_borrows() { let x = RefCell::new(0); let _b = x.borrow(); diff --git a/src/libcore/tests/char.rs b/src/libcore/tests/char.rs index 61856242c5706..57e9f4e384e0f 100644 --- a/src/libcore/tests/char.rs +++ b/src/libcore/tests/char.rs @@ -76,6 +76,8 @@ fn test_to_digit() { #[test] fn test_to_lowercase() { fn lower(c: char) -> String { + let to_lowercase = c.to_lowercase(); + assert_eq!(to_lowercase.len(), to_lowercase.count()); let iter: String = c.to_lowercase().collect(); let disp: String = c.to_lowercase().to_string(); assert_eq!(iter, disp); @@ -101,6 +103,8 @@ fn test_to_lowercase() { #[test] fn test_to_uppercase() { fn upper(c: char) -> String { + let to_uppercase = c.to_uppercase(); + assert_eq!(to_uppercase.len(), to_uppercase.count()); let iter: String = c.to_uppercase().collect(); let disp: String = c.to_uppercase().to_string(); assert_eq!(iter, disp); diff --git a/src/libcore/tests/fmt/builders.rs b/src/libcore/tests/fmt/builders.rs index fd7192cc15119..62fe09c5eb32c 100644 --- a/src/libcore/tests/fmt/builders.rs +++ b/src/libcore/tests/fmt/builders.rs @@ -6,7 +6,7 @@ mod debug_struct { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("Foo").finish() } } @@ -20,7 +20,7 @@ mod debug_struct { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("Foo") .field("bar", &true) .finish() @@ -30,7 +30,7 @@ mod debug_struct { assert_eq!("Foo { bar: true }", format!("{:?}", Foo)); assert_eq!( "Foo { - bar: true + bar: true, }", format!("{:#?}", Foo)); } @@ -40,7 +40,7 @@ mod debug_struct { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("Foo") .field("bar", &true) .field("baz", &format_args!("{}/{}", 10, 20)) @@ -52,7 +52,7 @@ mod debug_struct { assert_eq!( "Foo { bar: true, - baz: 10/20 + baz: 10/20, }", format!("{:#?}", Foo)); } @@ -62,7 +62,7 @@ mod debug_struct { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("Foo") .field("bar", &true) .field("baz", &format_args!("{}/{}", 10, 20)) @@ -73,7 +73,7 @@ mod debug_struct { struct Bar; impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("Bar") .field("foo", &Foo) .field("hello", &"world") @@ -87,9 +87,9 @@ mod debug_struct { "Bar { foo: Foo { bar: true, - baz: 10/20 + baz: 10/20, }, - hello: \"world\" + hello: \"world\", }", format!("{:#?}", Bar)); } @@ -103,7 +103,7 @@ mod debug_tuple { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_tuple("Foo").finish() } } @@ -117,7 +117,7 @@ mod debug_tuple { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_tuple("Foo") .field(&true) .finish() @@ -127,7 +127,7 @@ mod debug_tuple { assert_eq!("Foo(true)", format!("{:?}", Foo)); assert_eq!( "Foo( - true + true, )", format!("{:#?}", Foo)); } @@ -137,7 +137,7 @@ mod debug_tuple { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_tuple("Foo") .field(&true) .field(&format_args!("{}/{}", 10, 20)) @@ -149,7 +149,7 @@ mod debug_tuple { assert_eq!( "Foo( true, - 10/20 + 10/20, )", format!("{:#?}", Foo)); } @@ -159,7 +159,7 @@ mod debug_tuple { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_tuple("Foo") .field(&true) .field(&format_args!("{}/{}", 10, 20)) @@ -170,7 +170,7 @@ mod debug_tuple { struct Bar; impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_tuple("Bar") .field(&Foo) .field(&"world") @@ -184,9 +184,9 @@ mod debug_tuple { "Bar( Foo( true, - 10/20 + 10/20, ), - \"world\" + \"world\", )", format!("{:#?}", Bar)); } @@ -200,7 +200,7 @@ mod debug_map { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_map().finish() } } @@ -214,7 +214,7 @@ mod debug_map { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_map() .entry(&"bar", &true) .finish() @@ -224,7 +224,7 @@ mod debug_map { assert_eq!("{\"bar\": true}", format!("{:?}", Foo)); assert_eq!( "{ - \"bar\": true + \"bar\": true, }", format!("{:#?}", Foo)); } @@ -234,7 +234,7 @@ mod debug_map { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_map() .entry(&"bar", &true) .entry(&10, &format_args!("{}/{}", 10, 20)) @@ -246,7 +246,7 @@ mod debug_map { assert_eq!( "{ \"bar\": true, - 10: 10/20 + 10: 10/20, }", format!("{:#?}", Foo)); } @@ -256,7 +256,7 @@ mod debug_map { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_map() .entry(&"bar", &true) .entry(&10, &format_args!("{}/{}", 10, 20)) @@ -267,7 +267,7 @@ mod debug_map { struct Bar; impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_map() .entry(&"foo", &Foo) .entry(&Foo, &"world") @@ -282,12 +282,12 @@ mod debug_map { "{ \"foo\": { \"bar\": true, - 10: 10/20 + 10: 10/20, }, { \"bar\": true, - 10: 10/20 - }: \"world\" + 10: 10/20, + }: \"world\", }", format!("{:#?}", Bar)); } @@ -301,7 +301,7 @@ mod debug_set { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_set().finish() } } @@ -315,7 +315,7 @@ mod debug_set { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_set() .entry(&true) .finish() @@ -325,7 +325,7 @@ mod debug_set { assert_eq!("{true}", format!("{:?}", Foo)); assert_eq!( "{ - true + true, }", format!("{:#?}", Foo)); } @@ -335,7 +335,7 @@ mod debug_set { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_set() .entry(&true) .entry(&format_args!("{}/{}", 10, 20)) @@ -347,7 +347,7 @@ mod debug_set { assert_eq!( "{ true, - 10/20 + 10/20, }", format!("{:#?}", Foo)); } @@ -357,7 +357,7 @@ mod debug_set { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_set() .entry(&true) .entry(&format_args!("{}/{}", 10, 20)) @@ -368,7 +368,7 @@ mod debug_set { struct Bar; impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_set() .entry(&Foo) .entry(&"world") @@ -382,9 +382,9 @@ mod debug_set { "{ { true, - 10/20 + 10/20, }, - \"world\" + \"world\", }", format!("{:#?}", Bar)); } @@ -398,7 +398,7 @@ mod debug_list { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list().finish() } } @@ -412,7 +412,7 @@ mod debug_list { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list() .entry(&true) .finish() @@ -422,7 +422,7 @@ mod debug_list { assert_eq!("[true]", format!("{:?}", Foo)); assert_eq!( "[ - true + true, ]", format!("{:#?}", Foo)); } @@ -432,7 +432,7 @@ mod debug_list { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list() .entry(&true) .entry(&format_args!("{}/{}", 10, 20)) @@ -444,7 +444,7 @@ mod debug_list { assert_eq!( "[ true, - 10/20 + 10/20, ]", format!("{:#?}", Foo)); } @@ -454,7 +454,7 @@ mod debug_list { struct Foo; impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list() .entry(&true) .entry(&format_args!("{}/{}", 10, 20)) @@ -465,7 +465,7 @@ mod debug_list { struct Bar; impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list() .entry(&Foo) .entry(&"world") @@ -479,9 +479,9 @@ mod debug_list { "[ [ true, - 10/20 + 10/20, ], - \"world\" + \"world\", ]", format!("{:#?}", Bar)); } @@ -513,31 +513,31 @@ fn test_formatting_parameters_are_forwarded() { assert_eq!(format!("{:#03?}", struct_), " Foo { bar: 1024, - baz: 007 + baz: 007, } ".trim()); assert_eq!(format!("{:#03?}", tuple), " ( 1024, - 007 + 007, ) ".trim()); assert_eq!(format!("{:#03?}", list), " [ 1024, - 007 + 007, ] ".trim()); assert_eq!(format!("{:#03?}", map), r#" { "bar": 1024, - "baz": 007 + "baz": 007, } "#.trim()); assert_eq!(format!("{:#03?}", set), " { 007, - 1024 + 1024, } ".trim()); } diff --git a/src/libcore/tests/fmt/num.rs b/src/libcore/tests/fmt/num.rs index 6d9494ec289aa..10fcf8b76ccb4 100644 --- a/src/libcore/tests/fmt/num.rs +++ b/src/libcore/tests/fmt/num.rs @@ -3,146 +3,146 @@ fn test_format_int() { // Formatting integers should select the right implementation based off // the type of the argument. Also, hex/octal/binary should be defined // for integers, but they shouldn't emit the negative sign. - assert!(format!("{}", 1isize) == "1"); - assert!(format!("{}", 1i8) == "1"); - assert!(format!("{}", 1i16) == "1"); - assert!(format!("{}", 1i32) == "1"); - assert!(format!("{}", 1i64) == "1"); - assert!(format!("{}", -1isize) == "-1"); - assert!(format!("{}", -1i8) == "-1"); - assert!(format!("{}", -1i16) == "-1"); - assert!(format!("{}", -1i32) == "-1"); - assert!(format!("{}", -1i64) == "-1"); - assert!(format!("{:?}", 1isize) == "1"); - assert!(format!("{:?}", 1i8) == "1"); - assert!(format!("{:?}", 1i16) == "1"); - assert!(format!("{:?}", 1i32) == "1"); - assert!(format!("{:?}", 1i64) == "1"); - assert!(format!("{:b}", 1isize) == "1"); - assert!(format!("{:b}", 1i8) == "1"); - assert!(format!("{:b}", 1i16) == "1"); - assert!(format!("{:b}", 1i32) == "1"); - assert!(format!("{:b}", 1i64) == "1"); - assert!(format!("{:x}", 1isize) == "1"); - assert!(format!("{:x}", 1i8) == "1"); - assert!(format!("{:x}", 1i16) == "1"); - assert!(format!("{:x}", 1i32) == "1"); - assert!(format!("{:x}", 1i64) == "1"); - assert!(format!("{:X}", 1isize) == "1"); - assert!(format!("{:X}", 1i8) == "1"); - assert!(format!("{:X}", 1i16) == "1"); - assert!(format!("{:X}", 1i32) == "1"); - assert!(format!("{:X}", 1i64) == "1"); - assert!(format!("{:o}", 1isize) == "1"); - assert!(format!("{:o}", 1i8) == "1"); - assert!(format!("{:o}", 1i16) == "1"); - assert!(format!("{:o}", 1i32) == "1"); - assert!(format!("{:o}", 1i64) == "1"); + assert_eq!(format!("{}", 1isize), "1"); + assert_eq!(format!("{}", 1i8), "1"); + assert_eq!(format!("{}", 1i16), "1"); + assert_eq!(format!("{}", 1i32), "1"); + assert_eq!(format!("{}", 1i64), "1"); + assert_eq!(format!("{}", -1isize), "-1"); + assert_eq!(format!("{}", -1i8), "-1"); + assert_eq!(format!("{}", -1i16), "-1"); + assert_eq!(format!("{}", -1i32), "-1"); + assert_eq!(format!("{}", -1i64), "-1"); + assert_eq!(format!("{:?}", 1isize), "1"); + assert_eq!(format!("{:?}", 1i8), "1"); + assert_eq!(format!("{:?}", 1i16), "1"); + assert_eq!(format!("{:?}", 1i32), "1"); + assert_eq!(format!("{:?}", 1i64), "1"); + assert_eq!(format!("{:b}", 1isize), "1"); + assert_eq!(format!("{:b}", 1i8), "1"); + assert_eq!(format!("{:b}", 1i16), "1"); + assert_eq!(format!("{:b}", 1i32), "1"); + assert_eq!(format!("{:b}", 1i64), "1"); + assert_eq!(format!("{:x}", 1isize), "1"); + assert_eq!(format!("{:x}", 1i8), "1"); + assert_eq!(format!("{:x}", 1i16), "1"); + assert_eq!(format!("{:x}", 1i32), "1"); + assert_eq!(format!("{:x}", 1i64), "1"); + assert_eq!(format!("{:X}", 1isize), "1"); + assert_eq!(format!("{:X}", 1i8), "1"); + assert_eq!(format!("{:X}", 1i16), "1"); + assert_eq!(format!("{:X}", 1i32), "1"); + assert_eq!(format!("{:X}", 1i64), "1"); + assert_eq!(format!("{:o}", 1isize), "1"); + assert_eq!(format!("{:o}", 1i8), "1"); + assert_eq!(format!("{:o}", 1i16), "1"); + assert_eq!(format!("{:o}", 1i32), "1"); + assert_eq!(format!("{:o}", 1i64), "1"); - assert!(format!("{}", 1usize) == "1"); - assert!(format!("{}", 1u8) == "1"); - assert!(format!("{}", 1u16) == "1"); - assert!(format!("{}", 1u32) == "1"); - assert!(format!("{}", 1u64) == "1"); - assert!(format!("{:?}", 1usize) == "1"); - assert!(format!("{:?}", 1u8) == "1"); - assert!(format!("{:?}", 1u16) == "1"); - assert!(format!("{:?}", 1u32) == "1"); - assert!(format!("{:?}", 1u64) == "1"); - assert!(format!("{:b}", 1usize) == "1"); - assert!(format!("{:b}", 1u8) == "1"); - assert!(format!("{:b}", 1u16) == "1"); - assert!(format!("{:b}", 1u32) == "1"); - assert!(format!("{:b}", 1u64) == "1"); - assert!(format!("{:x}", 1usize) == "1"); - assert!(format!("{:x}", 1u8) == "1"); - assert!(format!("{:x}", 1u16) == "1"); - assert!(format!("{:x}", 1u32) == "1"); - assert!(format!("{:x}", 1u64) == "1"); - assert!(format!("{:X}", 1usize) == "1"); - assert!(format!("{:X}", 1u8) == "1"); - assert!(format!("{:X}", 1u16) == "1"); - assert!(format!("{:X}", 1u32) == "1"); - assert!(format!("{:X}", 1u64) == "1"); - assert!(format!("{:o}", 1usize) == "1"); - assert!(format!("{:o}", 1u8) == "1"); - assert!(format!("{:o}", 1u16) == "1"); - assert!(format!("{:o}", 1u32) == "1"); - assert!(format!("{:o}", 1u64) == "1"); + assert_eq!(format!("{}", 1usize), "1"); + assert_eq!(format!("{}", 1u8), "1"); + assert_eq!(format!("{}", 1u16), "1"); + assert_eq!(format!("{}", 1u32), "1"); + assert_eq!(format!("{}", 1u64), "1"); + assert_eq!(format!("{:?}", 1usize), "1"); + assert_eq!(format!("{:?}", 1u8), "1"); + assert_eq!(format!("{:?}", 1u16), "1"); + assert_eq!(format!("{:?}", 1u32), "1"); + assert_eq!(format!("{:?}", 1u64), "1"); + assert_eq!(format!("{:b}", 1usize), "1"); + assert_eq!(format!("{:b}", 1u8), "1"); + assert_eq!(format!("{:b}", 1u16), "1"); + assert_eq!(format!("{:b}", 1u32), "1"); + assert_eq!(format!("{:b}", 1u64), "1"); + assert_eq!(format!("{:x}", 1usize), "1"); + assert_eq!(format!("{:x}", 1u8), "1"); + assert_eq!(format!("{:x}", 1u16), "1"); + assert_eq!(format!("{:x}", 1u32), "1"); + assert_eq!(format!("{:x}", 1u64), "1"); + assert_eq!(format!("{:X}", 1usize), "1"); + assert_eq!(format!("{:X}", 1u8), "1"); + assert_eq!(format!("{:X}", 1u16), "1"); + assert_eq!(format!("{:X}", 1u32), "1"); + assert_eq!(format!("{:X}", 1u64), "1"); + assert_eq!(format!("{:o}", 1usize), "1"); + assert_eq!(format!("{:o}", 1u8), "1"); + assert_eq!(format!("{:o}", 1u16), "1"); + assert_eq!(format!("{:o}", 1u32), "1"); + assert_eq!(format!("{:o}", 1u64), "1"); // Test a larger number - assert!(format!("{:b}", 55) == "110111"); - assert!(format!("{:o}", 55) == "67"); - assert!(format!("{}", 55) == "55"); - assert!(format!("{:x}", 55) == "37"); - assert!(format!("{:X}", 55) == "37"); + assert_eq!(format!("{:b}", 55), "110111"); + assert_eq!(format!("{:o}", 55), "67"); + assert_eq!(format!("{}", 55), "55"); + assert_eq!(format!("{:x}", 55), "37"); + assert_eq!(format!("{:X}", 55), "37"); } #[test] fn test_format_int_zero() { - assert!(format!("{}", 0) == "0"); - assert!(format!("{:?}", 0) == "0"); - assert!(format!("{:b}", 0) == "0"); - assert!(format!("{:o}", 0) == "0"); - assert!(format!("{:x}", 0) == "0"); - assert!(format!("{:X}", 0) == "0"); + assert_eq!(format!("{}", 0), "0"); + assert_eq!(format!("{:?}", 0), "0"); + assert_eq!(format!("{:b}", 0), "0"); + assert_eq!(format!("{:o}", 0), "0"); + assert_eq!(format!("{:x}", 0), "0"); + assert_eq!(format!("{:X}", 0), "0"); - assert!(format!("{}", 0u32) == "0"); - assert!(format!("{:?}", 0u32) == "0"); - assert!(format!("{:b}", 0u32) == "0"); - assert!(format!("{:o}", 0u32) == "0"); - assert!(format!("{:x}", 0u32) == "0"); - assert!(format!("{:X}", 0u32) == "0"); + assert_eq!(format!("{}", 0u32), "0"); + assert_eq!(format!("{:?}", 0u32), "0"); + assert_eq!(format!("{:b}", 0u32), "0"); + assert_eq!(format!("{:o}", 0u32), "0"); + assert_eq!(format!("{:x}", 0u32), "0"); + assert_eq!(format!("{:X}", 0u32), "0"); } #[test] fn test_format_int_flags() { - assert!(format!("{:3}", 1) == " 1"); - assert!(format!("{:>3}", 1) == " 1"); - assert!(format!("{:>+3}", 1) == " +1"); - assert!(format!("{:<3}", 1) == "1 "); - assert!(format!("{:#}", 1) == "1"); - assert!(format!("{:#x}", 10) == "0xa"); - assert!(format!("{:#X}", 10) == "0xA"); - assert!(format!("{:#5x}", 10) == " 0xa"); - assert!(format!("{:#o}", 10) == "0o12"); - assert!(format!("{:08x}", 10) == "0000000a"); - assert!(format!("{:8x}", 10) == " a"); - assert!(format!("{:<8x}", 10) == "a "); - assert!(format!("{:>8x}", 10) == " a"); - assert!(format!("{:#08x}", 10) == "0x00000a"); - assert!(format!("{:08}", -10) == "-0000010"); - assert!(format!("{:x}", !0u8) == "ff"); - assert!(format!("{:X}", !0u8) == "FF"); - assert!(format!("{:b}", !0u8) == "11111111"); - assert!(format!("{:o}", !0u8) == "377"); - assert!(format!("{:#x}", !0u8) == "0xff"); - assert!(format!("{:#X}", !0u8) == "0xFF"); - assert!(format!("{:#b}", !0u8) == "0b11111111"); - assert!(format!("{:#o}", !0u8) == "0o377"); + assert_eq!(format!("{:3}", 1), " 1"); + assert_eq!(format!("{:>3}", 1), " 1"); + assert_eq!(format!("{:>+3}", 1), " +1"); + assert_eq!(format!("{:<3}", 1), "1 "); + assert_eq!(format!("{:#}", 1), "1"); + assert_eq!(format!("{:#x}", 10), "0xa"); + assert_eq!(format!("{:#X}", 10), "0xA"); + assert_eq!(format!("{:#5x}", 10), " 0xa"); + assert_eq!(format!("{:#o}", 10), "0o12"); + assert_eq!(format!("{:08x}", 10), "0000000a"); + assert_eq!(format!("{:8x}", 10), " a"); + assert_eq!(format!("{:<8x}", 10), "a "); + assert_eq!(format!("{:>8x}", 10), " a"); + assert_eq!(format!("{:#08x}", 10), "0x00000a"); + assert_eq!(format!("{:08}", -10), "-0000010"); + assert_eq!(format!("{:x}", !0u8), "ff"); + assert_eq!(format!("{:X}", !0u8), "FF"); + assert_eq!(format!("{:b}", !0u8), "11111111"); + assert_eq!(format!("{:o}", !0u8), "377"); + assert_eq!(format!("{:#x}", !0u8), "0xff"); + assert_eq!(format!("{:#X}", !0u8), "0xFF"); + assert_eq!(format!("{:#b}", !0u8), "0b11111111"); + assert_eq!(format!("{:#o}", !0u8), "0o377"); } #[test] fn test_format_int_sign_padding() { - assert!(format!("{:+5}", 1) == " +1"); - assert!(format!("{:+5}", -1) == " -1"); - assert!(format!("{:05}", 1) == "00001"); - assert!(format!("{:05}", -1) == "-0001"); - assert!(format!("{:+05}", 1) == "+0001"); - assert!(format!("{:+05}", -1) == "-0001"); + assert_eq!(format!("{:+5}", 1), " +1"); + assert_eq!(format!("{:+5}", -1), " -1"); + assert_eq!(format!("{:05}", 1), "00001"); + assert_eq!(format!("{:05}", -1), "-0001"); + assert_eq!(format!("{:+05}", 1), "+0001"); + assert_eq!(format!("{:+05}", -1), "-0001"); } #[test] fn test_format_int_twos_complement() { - use core::{i8, i16, i32, i64}; - assert!(format!("{}", i8::MIN) == "-128"); - assert!(format!("{}", i16::MIN) == "-32768"); - assert!(format!("{}", i32::MIN) == "-2147483648"); - assert!(format!("{}", i64::MIN) == "-9223372036854775808"); + use core::{i16, i32, i64, i8}; + assert_eq!(format!("{}", i8::MIN), "-128"); + assert_eq!(format!("{}", i16::MIN), "-32768"); + assert_eq!(format!("{}", i32::MIN), "-2147483648"); + assert_eq!(format!("{}", i64::MIN), "-9223372036854775808"); } #[test] fn test_format_debug_hex() { - assert!(format!("{:02x?}", b"Foo\0") == "[46, 6f, 6f, 00]"); - assert!(format!("{:02X?}", b"Foo\0") == "[46, 6F, 6F, 00]"); + assert_eq!(format!("{:02x?}", b"Foo\0"), "[46, 6f, 6f, 00]"); + assert_eq!(format!("{:02X?}", b"Foo\0"), "[46, 6F, 6F, 00]"); } diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index d880abb181c20..4d840ef24c8e6 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1,4 +1,5 @@ use core::cell::Cell; +use core::convert::TryFrom; use core::iter::*; use core::{i8, i16, isize}; use core::usize; @@ -253,7 +254,6 @@ fn test_iterator_step_by_nth_overflow() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_iterator_step_by_zero() { let mut it = (0..).step_by(0); it.next(); @@ -389,6 +389,24 @@ fn test_iterator_enumerate_nth() { assert_eq!(i, 3); } +#[test] +fn test_iterator_enumerate_nth_back() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().enumerate(); + while let Some((i, &x)) = it.nth_back(0) { + assert_eq!(i, x); + } + + let mut it = xs.iter().enumerate(); + while let Some((i, &x)) = it.nth_back(1) { + assert_eq!(i, x); + } + + let (i, &x) = xs.iter().enumerate().nth_back(3).unwrap(); + assert_eq!(i, x); + assert_eq!(i, 2); +} + #[test] fn test_iterator_enumerate_count() { let xs = [0, 1, 2, 3, 4, 5]; @@ -549,12 +567,12 @@ fn test_iterator_peekable_fold() { /// This is an iterator that follows the Iterator contract, /// but it is not fused. After having returned None once, it will start /// producing elements if .next() is called again. -pub struct CycleIter<'a, T: 'a> { +pub struct CycleIter<'a, T> { index: usize, data: &'a [T], } -pub fn cycle(data: &[T]) -> CycleIter { +pub fn cycle(data: &[T]) -> CycleIter<'_, T> { CycleIter { index: 0, data, @@ -1066,6 +1084,14 @@ fn test_iterator_sum_result() { assert_eq!(v.iter().cloned().sum::>(), Err(())); } +#[test] +fn test_iterator_sum_option() { + let v: &[Option] = &[Some(1), Some(2), Some(3), Some(4)]; + assert_eq!(v.iter().cloned().sum::>(), Some(10)); + let v: &[Option] = &[Some(1), None, Some(3), Some(4)]; + assert_eq!(v.iter().cloned().sum::>(), None); +} + #[test] fn test_iterator_product() { let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; @@ -1082,12 +1108,47 @@ fn test_iterator_product_result() { assert_eq!(v.iter().cloned().product::>(), Err(())); } +/// A wrapper struct that implements `Eq` and `Ord` based on the wrapped +/// integer modulo 3. Used to test that `Iterator::max` and `Iterator::min` +/// return the correct element if some of them are equal. +#[derive(Debug)] +struct Mod3(i32); + +impl PartialEq for Mod3 { + fn eq(&self, other: &Self) -> bool { + self.0 % 3 == other.0 % 3 + } +} + +impl Eq for Mod3 {} + +impl PartialOrd for Mod3 { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Mod3 { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + (self.0 % 3).cmp(&(other.0 % 3)) + } +} + +#[test] +fn test_iterator_product_option() { + let v: &[Option] = &[Some(1), Some(2), Some(3), Some(4)]; + assert_eq!(v.iter().cloned().product::>(), Some(24)); + let v: &[Option] = &[Some(1), None, Some(3), Some(4)]; + assert_eq!(v.iter().cloned().product::>(), None); +} + #[test] fn test_iterator_max() { let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; assert_eq!(v[..4].iter().cloned().max(), Some(3)); assert_eq!(v.iter().cloned().max(), Some(10)); assert_eq!(v[..0].iter().cloned().max(), None); + assert_eq!(v.iter().cloned().map(Mod3).max().map(|x| x.0), Some(8)); } #[test] @@ -1096,6 +1157,7 @@ fn test_iterator_min() { assert_eq!(v[..4].iter().cloned().min(), Some(0)); assert_eq!(v.iter().cloned().min(), Some(0)); assert_eq!(v[..0].iter().cloned().min(), None); + assert_eq!(v.iter().cloned().map(Mod3).min().map(|x| x.0), Some(0)); } #[test] @@ -1414,7 +1476,6 @@ fn test_rposition() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_rposition_panic() { let v: [(Box<_>, Box<_>); 4] = [(box 0, box 0), (box 0, box 0), @@ -1596,6 +1657,23 @@ fn test_range_nth() { assert_eq!(r, 20..20); } +#[test] +fn test_range_nth_back() { + assert_eq!((10..15).nth_back(0), Some(14)); + assert_eq!((10..15).nth_back(1), Some(13)); + assert_eq!((10..15).nth_back(4), Some(10)); + assert_eq!((10..15).nth_back(5), None); + assert_eq!((-120..80_i8).nth_back(199), Some(-120)); + + let mut r = 10..20; + assert_eq!(r.nth_back(2), Some(17)); + assert_eq!(r, 10..17); + assert_eq!(r.nth_back(2), Some(14)); + assert_eq!(r, 10..14); + assert_eq!(r.nth_back(10), None); + assert_eq!(r, 10..10); +} + #[test] fn test_range_from_nth() { assert_eq!((10..).nth(0), Some(10)); @@ -1653,6 +1731,26 @@ fn test_range_inclusive_nth() { assert_eq!(ExactSizeIterator::is_empty(&r), true); } +#[test] +fn test_range_inclusive_nth_back() { + assert_eq!((10..=15).nth_back(0), Some(15)); + assert_eq!((10..=15).nth_back(1), Some(14)); + assert_eq!((10..=15).nth_back(5), Some(10)); + assert_eq!((10..=15).nth_back(6), None); + assert_eq!((-120..=80_i8).nth_back(200), Some(-120)); + + let mut r = 10_u8..=20; + assert_eq!(r.nth_back(2), Some(18)); + assert_eq!(r, 10..=17); + assert_eq!(r.nth_back(2), Some(15)); + assert_eq!(r, 10..=14); + assert_eq!(r.is_empty(), false); + assert_eq!(ExactSizeIterator::is_empty(&r), false); + assert_eq!(r.nth_back(10), None); + assert_eq!(r.is_empty(), true); + assert_eq!(ExactSizeIterator::is_empty(&r), true); +} + #[test] fn test_range_step() { #![allow(deprecated)] @@ -1774,6 +1872,66 @@ fn test_range_inclusive_folds() { assert!(it.is_empty()); } +#[test] +fn test_range_size_hint() { + use core::usize::MAX as UMAX; + assert_eq!((0..0usize).size_hint(), (0, Some(0))); + assert_eq!((0..100usize).size_hint(), (100, Some(100))); + assert_eq!((0..UMAX).size_hint(), (UMAX, Some(UMAX))); + + let umax = u128::try_from(UMAX).unwrap(); + assert_eq!((0..0u128).size_hint(), (0, Some(0))); + assert_eq!((0..100u128).size_hint(), (100, Some(100))); + assert_eq!((0..umax).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((0..umax + 1).size_hint(), (UMAX, None)); + + use core::isize::{MAX as IMAX, MIN as IMIN}; + assert_eq!((0..0isize).size_hint(), (0, Some(0))); + assert_eq!((-100..100isize).size_hint(), (200, Some(200))); + assert_eq!((IMIN..IMAX).size_hint(), (UMAX, Some(UMAX))); + + let imin = i128::try_from(IMIN).unwrap(); + let imax = i128::try_from(IMAX).unwrap(); + assert_eq!((0..0i128).size_hint(), (0, Some(0))); + assert_eq!((-100..100i128).size_hint(), (200, Some(200))); + assert_eq!((imin..imax).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((imin..imax + 1).size_hint(), (UMAX, None)); +} + +#[test] +fn test_range_inclusive_size_hint() { + use core::usize::MAX as UMAX; + assert_eq!((1..=0usize).size_hint(), (0, Some(0))); + assert_eq!((0..=0usize).size_hint(), (1, Some(1))); + assert_eq!((0..=100usize).size_hint(), (101, Some(101))); + assert_eq!((0..=UMAX - 1).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((0..=UMAX).size_hint(), (UMAX, None)); + + let umax = u128::try_from(UMAX).unwrap(); + assert_eq!((1..=0u128).size_hint(), (0, Some(0))); + assert_eq!((0..=0u128).size_hint(), (1, Some(1))); + assert_eq!((0..=100u128).size_hint(), (101, Some(101))); + assert_eq!((0..=umax - 1).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((0..=umax).size_hint(), (UMAX, None)); + assert_eq!((0..=umax + 1).size_hint(), (UMAX, None)); + + use core::isize::{MAX as IMAX, MIN as IMIN}; + assert_eq!((0..=-1isize).size_hint(), (0, Some(0))); + assert_eq!((0..=0isize).size_hint(), (1, Some(1))); + assert_eq!((-100..=100isize).size_hint(), (201, Some(201))); + assert_eq!((IMIN..=IMAX - 1).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((IMIN..=IMAX).size_hint(), (UMAX, None)); + + let imin = i128::try_from(IMIN).unwrap(); + let imax = i128::try_from(IMAX).unwrap(); + assert_eq!((0..=-1i128).size_hint(), (0, Some(0))); + assert_eq!((0..=0i128).size_hint(), (1, Some(1))); + assert_eq!((-100..=100i128).size_hint(), (201, Some(201))); + assert_eq!((imin..=imax - 1).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((imin..=imax).size_hint(), (UMAX, None)); + assert_eq!((imin..=imax + 1).size_hint(), (UMAX, None)); +} + #[test] fn test_repeat() { let mut it = repeat(42); @@ -2175,6 +2333,40 @@ fn test_skip_try_folds() { assert_eq!(iter.next_back(), Some(24)); } +#[test] +fn test_skip_nth_back() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().skip(2); + assert_eq!(it.nth_back(0), Some(&5)); + assert_eq!(it.nth_back(1), Some(&3)); + assert_eq!(it.nth_back(0), Some(&2)); + assert_eq!(it.nth_back(0), None); + + let ys = [2, 3, 4, 5]; + let mut ity = ys.iter(); + let mut it = xs.iter().skip(2); + assert_eq!(it.nth_back(1), ity.nth_back(1)); + assert_eq!(it.clone().nth(0), ity.clone().nth(0)); + assert_eq!(it.nth_back(0), ity.nth_back(0)); + assert_eq!(it.clone().nth(0), ity.clone().nth(0)); + assert_eq!(it.nth_back(0), ity.nth_back(0)); + assert_eq!(it.clone().nth(0), ity.clone().nth(0)); + assert_eq!(it.nth_back(0), ity.nth_back(0)); + assert_eq!(it.clone().nth(0), ity.clone().nth(0)); + + let mut it = xs.iter().skip(2); + assert_eq!(it.nth_back(4), None); + assert_eq!(it.nth_back(0), None); + + let mut it = xs.iter(); + it.by_ref().skip(2).nth_back(3); + assert_eq!(it.next_back(), Some(&1)); + + let mut it = xs.iter(); + it.by_ref().skip(2).nth_back(10); + assert_eq!(it.next_back(), Some(&1)); +} + #[test] fn test_take_try_folds() { let f = &|acc, x| i32::checked_add(2*acc, x); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index d002137638977..bf072a9243b51 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -1,6 +1,6 @@ +#![feature(bound_cloned)] #![feature(box_syntax)] #![feature(cell_update)] -#![feature(copied)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] #![feature(dec2flt)] @@ -11,33 +11,30 @@ #![feature(fmt_internals)] #![feature(hashmap_internals)] #![feature(is_sorted)] -#![feature(iter_copied)] -#![feature(iter_nth_back)] #![feature(iter_once_with)] #![feature(pattern)] #![feature(range_is_empty)] #![feature(raw)] -#![feature(refcell_map_split)] -#![feature(refcell_replace_swap)] +#![feature(saturating_neg)] #![feature(slice_patterns)] #![feature(sort_internals)] +#![feature(slice_partition_at_index)] #![feature(specialization)] #![feature(step_trait)] #![feature(str_internals)] #![feature(test)] #![feature(trusted_len)] #![feature(try_trait)] -#![feature(align_offset)] -#![feature(reverse_bits)] #![feature(inner_deref)] #![feature(slice_internals)] #![feature(slice_partition_dedup)] -#![feature(copy_within)] +#![feature(int_error_matching)] +#![feature(const_fn)] +#![warn(rust_2018_idioms)] -extern crate core; extern crate test; -extern crate rand; +mod alloc; mod any; mod array; mod ascii; diff --git a/src/libcore/tests/nonzero.rs b/src/libcore/tests/nonzero.rs index 4532568ee0c16..77e484601bc22 100644 --- a/src/libcore/tests/nonzero.rs +++ b/src/libcore/tests/nonzero.rs @@ -1,6 +1,5 @@ -use core::num::{NonZeroU32, NonZeroI32}; -use core::option::Option; -use core::option::Option::{Some, None}; +use core::num::{IntErrorKind, NonZeroI32, NonZeroI8, NonZeroU32, NonZeroU8}; +use core::option::Option::{self, None, Some}; use std::mem::size_of; #[test] @@ -126,3 +125,24 @@ fn test_from_signed_nonzero() { let num: i32 = nz.into(); assert_eq!(num, 1i32); } + +#[test] +fn test_from_str() { + assert_eq!("123".parse::(), Ok(NonZeroU8::new(123).unwrap())); + assert_eq!( + "0".parse::().err().map(|e| e.kind().clone()), + Some(IntErrorKind::Zero) + ); + assert_eq!( + "-1".parse::().err().map(|e| e.kind().clone()), + Some(IntErrorKind::InvalidDigit) + ); + assert_eq!( + "-129".parse::().err().map(|e| e.kind().clone()), + Some(IntErrorKind::Underflow) + ); + assert_eq!( + "257".parse::().err().map(|e| e.kind().clone()), + Some(IntErrorKind::Overflow) + ); +} diff --git a/src/libcore/tests/num/bignum.rs b/src/libcore/tests/num/bignum.rs index 956c22c998219..b9e15ec5c0763 100644 --- a/src/libcore/tests/num/bignum.rs +++ b/src/libcore/tests/num/bignum.rs @@ -3,7 +3,6 @@ use core::num::bignum::tests::Big8x3 as Big; #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_from_u64_overflow() { Big::from_u64(0x1000000); } @@ -20,14 +19,12 @@ fn test_add() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_add_overflow_1() { Big::from_small(1).add(&Big::from_u64(0xffffff)); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_add_overflow_2() { Big::from_u64(0xffffff).add(&Big::from_small(1)); } @@ -45,7 +42,6 @@ fn test_add_small() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_add_small_overflow() { Big::from_u64(0xffffff).add_small(1); } @@ -61,14 +57,12 @@ fn test_sub() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_sub_underflow_1() { Big::from_u64(0x10665).sub(&Big::from_u64(0x10666)); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_sub_underflow_2() { Big::from_small(0).sub(&Big::from_u64(0x123456)); } @@ -82,7 +76,6 @@ fn test_mul_small() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_small_overflow() { Big::from_u64(0x800000).mul_small(2); } @@ -101,14 +94,12 @@ fn test_mul_pow2() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_pow2_overflow_1() { Big::from_u64(0x1).mul_pow2(24); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_pow2_overflow_2() { Big::from_u64(0x123).mul_pow2(16); } @@ -127,14 +118,12 @@ fn test_mul_pow5() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_pow5_overflow_1() { Big::from_small(1).mul_pow5(12); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_pow5_overflow_2() { Big::from_small(230).mul_pow5(8); } @@ -152,14 +141,12 @@ fn test_mul_digits() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_digits_overflow_1() { Big::from_u64(0x800000).mul_digits(&[2]); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_digits_overflow_2() { Big::from_u64(0x1000).mul_digits(&[0, 0x10]); } @@ -219,7 +206,6 @@ fn test_get_bit() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_get_bit_out_of_range() { Big::from_small(42).get_bit(24); } @@ -250,4 +236,3 @@ fn test_fmt() { assert_eq!(format!("{:?}", Big::from_u64(0x12345)), "0x1_23_45"); assert_eq!(format!("{:?}", Big::from_u64(0x123456)), "0x12_34_56"); } - diff --git a/src/libcore/tests/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs index faeaabbf95ada..0e71426c64108 100644 --- a/src/libcore/tests/num/dec2flt/mod.rs +++ b/src/libcore/tests/num/dec2flt/mod.rs @@ -31,6 +31,7 @@ fn ordinary() { test_literal!(0.1); test_literal!(12345.); test_literal!(0.9999999); + #[cfg(not(miri))] // Miri is too slow test_literal!(2.2250738585072014e-308); } @@ -77,6 +78,7 @@ fn zero() { test_literal!(0.0); test_literal!(1e-325); test_literal!(1e-326); + #[cfg(not(miri))] // Miri is too slow test_literal!(1e-500); } diff --git a/src/libcore/tests/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs index fb0888e2720a9..2dbb8e3a5f06e 100644 --- a/src/libcore/tests/num/flt2dec/estimator.rs +++ b/src/libcore/tests/num/flt2dec/estimator.rs @@ -47,4 +47,3 @@ fn test_estimate_scaling_factor() { assert_almost_eq!(estimate_scaling_factor(1, i as i16), expected as i16); } } - diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs index d362c7994d806..f42f500c2df1d 100644 --- a/src/libcore/tests/num/flt2dec/mod.rs +++ b/src/libcore/tests/num/flt2dec/mod.rs @@ -1107,4 +1107,3 @@ pub fn to_exact_fixed_str_test(mut f_: F) format!("0.0000000000000000000099999999999999994515327145420957165172950370\ 2787392447107715776066783064379706047475337982177734375{:0>79881}", "")); } - diff --git a/src/libcore/tests/num/flt2dec/random.rs b/src/libcore/tests/num/flt2dec/random.rs index 1c36af6af0ee4..35e3fbcbb7870 100644 --- a/src/libcore/tests/num/flt2dec/random.rs +++ b/src/libcore/tests/num/flt2dec/random.rs @@ -152,4 +152,3 @@ fn exact_f64_random_equivalence_test() { |d, buf| fallback(d, buf, i16::MIN), k, 1_000); } } - diff --git a/src/libcore/tests/num/flt2dec/strategy/dragon.rs b/src/libcore/tests/num/flt2dec/strategy/dragon.rs index 1803e39b46df3..5e4cc23d33c8c 100644 --- a/src/libcore/tests/num/flt2dec/strategy/dragon.rs +++ b/src/libcore/tests/num/flt2dec/strategy/dragon.rs @@ -62,4 +62,3 @@ fn test_to_exact_exp_str() { fn test_to_exact_fixed_str() { to_exact_fixed_str_test(format_exact); } - diff --git a/src/libcore/tests/num/flt2dec/strategy/grisu.rs b/src/libcore/tests/num/flt2dec/strategy/grisu.rs index 53e9f12ae0f14..f1afd7d4bf86f 100644 --- a/src/libcore/tests/num/flt2dec/strategy/grisu.rs +++ b/src/libcore/tests/num/flt2dec/strategy/grisu.rs @@ -64,4 +64,3 @@ fn test_to_exact_exp_str() { fn test_to_exact_fixed_str() { to_exact_fixed_str_test(format_exact); } - diff --git a/src/libcore/tests/num/int_macros.rs b/src/libcore/tests/num/int_macros.rs index 5c6ee8f8ba038..0475aeb96ab53 100644 --- a/src/libcore/tests/num/int_macros.rs +++ b/src/libcore/tests/num/int_macros.rs @@ -6,13 +6,13 @@ mod tests { use core::ops::{Shl, Shr, Not, BitXor, BitAnd, BitOr}; use core::mem; - use num; + use crate::num; #[test] fn test_overflows() { assert!(MAX > 0); assert!(MIN <= 0); - assert!(MIN + MAX + 1 == 0); + assert_eq!(MIN + MAX + 1, 0); } #[test] @@ -22,22 +22,22 @@ mod tests { #[test] fn test_rem_euclid() { - assert!((-1 as $T).rem_euclid(MIN) == MAX); + assert_eq!((-1 as $T).rem_euclid(MIN), MAX); } #[test] pub fn test_abs() { - assert!((1 as $T).abs() == 1 as $T); - assert!((0 as $T).abs() == 0 as $T); - assert!((-1 as $T).abs() == 1 as $T); + assert_eq!((1 as $T).abs(), 1 as $T); + assert_eq!((0 as $T).abs(), 0 as $T); + assert_eq!((-1 as $T).abs(), 1 as $T); } #[test] fn test_signum() { - assert!((1 as $T).signum() == 1 as $T); - assert!((0 as $T).signum() == 0 as $T); - assert!((-0 as $T).signum() == 0 as $T); - assert!((-1 as $T).signum() == -1 as $T); + assert_eq!((1 as $T).signum(), 1 as $T); + assert_eq!((0 as $T).signum(), 0 as $T); + assert_eq!((-0 as $T).signum(), 0 as $T); + assert_eq!((-1 as $T).signum(), -1 as $T); } #[test] @@ -58,12 +58,12 @@ mod tests { #[test] fn test_bitwise_operators() { - assert!(0b1110 as $T == (0b1100 as $T).bitor(0b1010 as $T)); - assert!(0b1000 as $T == (0b1100 as $T).bitand(0b1010 as $T)); - assert!(0b0110 as $T == (0b1100 as $T).bitxor(0b1010 as $T)); - assert!(0b1110 as $T == (0b0111 as $T).shl(1)); - assert!(0b0111 as $T == (0b1110 as $T).shr(1)); - assert!(-(0b11 as $T) - (1 as $T) == (0b11 as $T).not()); + assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(0b1010 as $T)); + assert_eq!(0b1000 as $T, (0b1100 as $T).bitand(0b1010 as $T)); + assert_eq!(0b0110 as $T, (0b1100 as $T).bitxor(0b1010 as $T)); + assert_eq!(0b1110 as $T, (0b0111 as $T).shl(1)); + assert_eq!(0b0111 as $T, (0b1110 as $T).shr(1)); + assert_eq!(-(0b11 as $T) - (1 as $T), (0b11 as $T).not()); } const A: $T = 0b0101100; @@ -75,17 +75,17 @@ mod tests { #[test] fn test_count_ones() { - assert!(A.count_ones() == 3); - assert!(B.count_ones() == 2); - assert!(C.count_ones() == 5); + assert_eq!(A.count_ones(), 3); + assert_eq!(B.count_ones(), 2); + assert_eq!(C.count_ones(), 5); } #[test] fn test_count_zeros() { let bits = mem::size_of::<$T>() * 8; - assert!(A.count_zeros() == bits as u32 - 3); - assert!(B.count_zeros() == bits as u32 - 2); - assert!(C.count_zeros() == bits as u32 - 5); + assert_eq!(A.count_zeros(), bits as u32 - 3); + assert_eq!(B.count_zeros(), bits as u32 - 2); + assert_eq!(C.count_zeros(), bits as u32 - 5); } #[test] @@ -148,9 +148,35 @@ mod tests { #[test] fn test_signed_checked_div() { - assert!((10 as $T).checked_div(2) == Some(5)); - assert!((5 as $T).checked_div(0) == None); - assert!(isize::MIN.checked_div(-1) == None); + assert_eq!((10 as $T).checked_div(2), Some(5)); + assert_eq!((5 as $T).checked_div(0), None); + assert_eq!(isize::MIN.checked_div(-1), None); + } + + #[test] + fn test_saturating_abs() { + assert_eq!((0 as $T).saturating_abs(), 0); + assert_eq!((123 as $T).saturating_abs(), 123); + assert_eq!((-123 as $T).saturating_abs(), 123); + assert_eq!((MAX - 2).saturating_abs(), MAX - 2); + assert_eq!((MAX - 1).saturating_abs(), MAX - 1); + assert_eq!(MAX.saturating_abs(), MAX); + assert_eq!((MIN + 2).saturating_abs(), MAX - 1); + assert_eq!((MIN + 1).saturating_abs(), MAX); + assert_eq!(MIN.saturating_abs(), MAX); + } + + #[test] + fn test_saturating_neg() { + assert_eq!((0 as $T).saturating_neg(), 0); + assert_eq!((123 as $T).saturating_neg(), -123); + assert_eq!((-123 as $T).saturating_neg(), 123); + assert_eq!((MAX - 2).saturating_neg(), MIN + 3); + assert_eq!((MAX - 1).saturating_neg(), MIN + 2); + assert_eq!(MAX.saturating_neg(), MIN + 1); + assert_eq!((MIN + 2).saturating_neg(), MAX - 1); + assert_eq!((MIN + 1).saturating_neg(), MAX); + assert_eq!(MIN.saturating_neg(), MAX); } #[test] diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs index 6e81542b6ec88..04ed14f3d0897 100644 --- a/src/libcore/tests/num/uint_macros.rs +++ b/src/libcore/tests/num/uint_macros.rs @@ -2,11 +2,12 @@ macro_rules! uint_module { ($T:ident, $T_i:ident) => ( #[cfg(test)] mod tests { use core::$T_i::*; - use num; use core::ops::{BitOr, BitAnd, BitXor, Shl, Shr, Not}; use std::str::FromStr; use std::mem; + use crate::num; + #[test] fn test_overflows() { assert!(MAX > 0); diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs index 401644e120d16..48755ae4c1641 100644 --- a/src/libcore/tests/ops.rs +++ b/src/libcore/tests/ops.rs @@ -1,4 +1,4 @@ -use core::ops::{Range, RangeFull, RangeFrom, RangeTo, RangeInclusive}; +use core::ops::{Bound, Range, RangeFull, RangeFrom, RangeTo, RangeInclusive}; // Test the Range structs without the syntactic sugar. @@ -7,11 +7,11 @@ fn test_range() { let r = Range { start: 2, end: 10 }; let mut count = 0; for (i, ri) in r.enumerate() { - assert!(ri == i + 2); + assert_eq!(ri, i + 2); assert!(ri >= 2 && ri < 10); count += 1; } - assert!(count == 8); + assert_eq!(count, 8); } #[test] @@ -19,11 +19,11 @@ fn test_range_from() { let r = RangeFrom { start: 2 }; let mut count = 0; for (i, ri) in r.take(10).enumerate() { - assert!(ri == i + 2); + assert_eq!(ri, i + 2); assert!(ri >= 2 && ri < 12); count += 1; } - assert!(count == 10); + assert_eq!(count, 10); } #[test] @@ -82,3 +82,18 @@ fn test_range_is_empty() { assert!( (NAN ..= EPSILON).is_empty()); assert!( (NAN ..= NAN).is_empty()); } + +#[test] +fn test_bound_cloned_unbounded() { + assert_eq!(Bound::<&u32>::Unbounded.cloned(), Bound::Unbounded); +} + +#[test] +fn test_bound_cloned_included() { + assert_eq!(Bound::Included(&3).cloned(), Bound::Included(3)); +} + +#[test] +fn test_bound_cloned_excluded() { + assert_eq!(Bound::Excluded(&3).cloned(), Bound::Excluded(3)); +} diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index 87ce2720c5918..b059b134868d9 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -69,7 +69,6 @@ fn test_option_dance() { } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_option_too_much_dance() { struct A; let mut y = Some(A); @@ -130,7 +129,6 @@ fn test_unwrap() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_unwrap_panic1() { let x: Option = None; x.unwrap(); @@ -138,7 +136,6 @@ fn test_unwrap_panic1() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_unwrap_panic2() { let x: Option = None; x.unwrap(); diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index bbc8568517667..1fab07526a07f 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -117,7 +117,6 @@ fn test_unwrap_or_else() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics pub fn test_unwrap_or_else_panic() { fn handler(msg: &'static str) -> isize { if msg == "I got this." { @@ -139,7 +138,6 @@ pub fn test_expect_ok() { } #[test] #[should_panic(expected="Got expected error: \"All good\"")] -#[cfg(not(miri))] // Miri does not support panics pub fn test_expect_err() { let err: Result = Err("All good"); err.expect("Got expected error"); @@ -153,7 +151,6 @@ pub fn test_expect_err_err() { } #[test] #[should_panic(expected="Got expected ok: \"All good\"")] -#[cfg(not(miri))] // Miri does not support panics pub fn test_expect_err_ok() { let err: Result<&'static str, isize> = Ok("All good"); err.expect_err("Got expected ok"); diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 31d16e0e32057..03e65d2fe0b81 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -88,6 +88,19 @@ fn test_iterator_nth() { assert_eq!(iter.nth(1).unwrap(), &v[4]); } +#[test] +fn test_iterator_nth_back() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - i - 1]); + } + assert_eq!(v.iter().nth_back(v.len()), None); + + let mut iter = v.iter(); + assert_eq!(iter.nth_back(2).unwrap(), &v[2]); + assert_eq!(iter.nth_back(1).unwrap(), &v[0]); +} + #[test] fn test_iterator_last() { let v: &[_] = &[0, 1, 2, 3, 4]; @@ -134,6 +147,30 @@ fn test_chunks_nth() { assert_eq!(c2.next(), None); } +#[test] +fn test_chunks_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.chunks(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(3); + assert_eq!(c2.nth_back(1).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(10); + assert_eq!(c3.nth_back(0).unwrap(), &[0, 1, 2, 3, 4]); + assert_eq!(c3.next(), None); + + let v4: &[i32] = &[0, 1, 2]; + let mut c4 = v4.chunks(10); + assert_eq!(c4.nth_back(1_000_000_000usize), None); +} + #[test] fn test_chunks_last() { let v: &[i32] = &[0, 1, 2, 3, 4, 5]; @@ -356,6 +393,19 @@ fn test_rchunks_nth() { assert_eq!(c2.next(), None); } +#[test] +fn test_rchunks_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next_back().unwrap(), &[4, 5]); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let mut c2 = v2.rchunks(3); + assert_eq!(c2.nth_back(1).unwrap(), &[2, 3, 4]); + assert_eq!(c2.next_back(), None); +} + #[test] fn test_rchunks_last() { let v: &[i32] = &[0, 1, 2, 3, 4, 5]; @@ -407,6 +457,19 @@ fn test_rchunks_mut_nth() { assert_eq!(c2.next(), None); } +#[test] +fn test_rchunks_mut_nth_back() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_mut(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next_back().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c2 = v2.rchunks_mut(3); + assert_eq!(c2.nth_back(1).unwrap(), &[2, 3, 4]); + assert_eq!(c2.next_back(), None); +} + #[test] fn test_rchunks_mut_last() { let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; @@ -460,6 +523,19 @@ fn test_rchunks_exact_nth() { assert_eq!(c2.next(), None); } +#[test] +fn test_rchunks_exact_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_exact(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next_back().unwrap(), &[4, 5]); + + let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.rchunks_exact(3); + assert_eq!(c2.nth_back(1).unwrap(), &[4, 5, 6]); + assert_eq!(c2.next(), None); +} + #[test] fn test_rchunks_exact_last() { let v: &[i32] = &[0, 1, 2, 3, 4, 5]; @@ -518,6 +594,19 @@ fn test_rchunks_exact_mut_nth() { assert_eq!(c2.next(), None); } +#[test] +fn test_rchunks_exact_mut_nth_back() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_exact_mut(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next_back().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.rchunks_exact_mut(3); + assert_eq!(c2.nth_back(1).unwrap(), &[4, 5, 6]); + assert_eq!(c2.next(), None); +} + #[test] fn test_rchunks_exact_mut_last() { let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; @@ -578,6 +667,19 @@ fn test_windows_nth() { assert_eq!(c2.next(), None); } +#[test] +fn test_windows_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.windows(2); + assert_eq!(c.nth_back(2).unwrap()[0], 2); + assert_eq!(c.next_back().unwrap()[1], 2); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let mut c2 = v2.windows(4); + assert_eq!(c2.nth_back(1).unwrap()[1], 1); + assert_eq!(c2.next_back(), None); +} + #[test] fn test_windows_last() { let v: &[i32] = &[0, 1, 2, 3, 4, 5]; @@ -782,7 +884,6 @@ mod slice_index { // to be used in `should_panic`) #[test] #[should_panic(expected = "out of range")] - #[cfg(not(miri))] // Miri does not support panics fn assert_range_eq_can_fail_by_panic() { assert_range_eq!([0, 1, 2], 0..5, [0, 1, 2]); } @@ -792,7 +893,6 @@ mod slice_index { // to be used in `should_panic`) #[test] #[should_panic(expected = "==")] - #[cfg(not(miri))] // Miri does not support panics fn assert_range_eq_can_fail_by_inequality() { assert_range_eq!([0, 1, 2], 0..2, [0, 1, 2]); } @@ -842,7 +942,6 @@ mod slice_index { #[test] #[should_panic(expected = $expect_msg)] - #[cfg(not(miri))] // Miri does not support panics fn index_fail() { let v = $data; let v: &[_] = &v; @@ -851,7 +950,6 @@ mod slice_index { #[test] #[should_panic(expected = $expect_msg)] - #[cfg(not(miri))] // Miri does not support panics fn index_mut_fail() { let mut v = $data; let v: &mut [_] = &mut v; @@ -1015,22 +1113,31 @@ fn test_rotate_right() { #[test] #[cfg(not(target_arch = "wasm32"))] -#[cfg(not(miri))] // Miri does not support entropy fn sort_unstable() { use core::cmp::Ordering::{Equal, Greater, Less}; use core::slice::heapsort; use rand::{FromEntropy, Rng, rngs::SmallRng, seq::SliceRandom}; + #[cfg(not(miri))] // Miri is too slow + let large_range = 500..510; + #[cfg(not(miri))] // Miri is too slow + let rounds = 100; + + #[cfg(miri)] + let large_range = 0..0; // empty range + #[cfg(miri)] + let rounds = 1; + let mut v = [0; 600]; let mut tmp = [0; 600]; let mut rng = SmallRng::from_entropy(); - for len in (2..25).chain(500..510) { + for len in (2..25).chain(large_range) { let v = &mut v[0..len]; let tmp = &mut tmp[0..len]; for &modulus in &[5, 10, 100, 1000] { - for _ in 0..100 { + for _ in 0..rounds { for i in 0..len { v[i] = rng.gen::() % modulus; } @@ -1084,6 +1191,124 @@ fn sort_unstable() { assert!(v == [0xDEADBEEF]); } +#[test] +#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(miri))] // Miri is too slow +fn partition_at_index() { + use core::cmp::Ordering::{Equal, Greater, Less}; + use rand::rngs::SmallRng; + use rand::seq::SliceRandom; + use rand::{FromEntropy, Rng}; + + let mut rng = SmallRng::from_entropy(); + + for len in (2..21).chain(500..501) { + let mut orig = vec![0; len]; + + for &modulus in &[5, 10, 1000] { + for _ in 0..10 { + for i in 0..len { + orig[i] = rng.gen::() % modulus; + } + + let v_sorted = { + let mut v = orig.clone(); + v.sort(); + v + }; + + // Sort in default order. + for pivot in 0..len { + let mut v = orig.clone(); + v.partition_at_index(pivot); + + assert_eq!(v_sorted[pivot], v[pivot]); + for i in 0..pivot { + for j in pivot..len { + assert!(v[i] <= v[j]); + } + } + } + + // Sort in ascending order. + for pivot in 0..len { + let mut v = orig.clone(); + let (left, pivot, right) = v.partition_at_index_by(pivot, |a, b| a.cmp(b)); + + assert_eq!(left.len() + right.len(), len - 1); + + for l in left { + assert!(l <= pivot); + for r in right.iter_mut() { + assert!(l <= r); + assert!(pivot <= r); + } + } + } + + // Sort in descending order. + let sort_descending_comparator = |a: &i32, b: &i32| b.cmp(a); + let v_sorted_descending = { + let mut v = orig.clone(); + v.sort_by(sort_descending_comparator); + v + }; + + for pivot in 0..len { + let mut v = orig.clone(); + v.partition_at_index_by(pivot, sort_descending_comparator); + + assert_eq!(v_sorted_descending[pivot], v[pivot]); + for i in 0..pivot { + for j in pivot..len { + assert!(v[j] <= v[i]); + } + } + } + } + } + } + + // Sort at index using a completely random comparison function. + // This will reorder the elements *somehow*, but won't panic. + let mut v = [0; 500]; + for i in 0..v.len() { + v[i] = i as i32; + } + + for pivot in 0..v.len() { + v.partition_at_index_by(pivot, |_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap()); + v.sort(); + for i in 0..v.len() { + assert_eq!(v[i], i as i32); + } + } + + // Should not panic. + [(); 10].partition_at_index(0); + [(); 10].partition_at_index(5); + [(); 10].partition_at_index(9); + [(); 100].partition_at_index(0); + [(); 100].partition_at_index(50); + [(); 100].partition_at_index(99); + + let mut v = [0xDEADBEEFu64]; + v.partition_at_index(0); + assert!(v == [0xDEADBEEF]); +} + +#[test] +#[should_panic(expected = "index 0 greater than length of slice")] +fn partition_at_index_zero_length() { + [0i32; 0].partition_at_index(0); +} + +#[test] +#[should_panic(expected = "index 20 greater than length of slice")] +fn partition_at_index_past_length() { + [0i32; 10].partition_at_index(20); +} + pub mod memchr { use core::slice::memchr::{memchr, memrchr}; @@ -1300,11 +1525,17 @@ fn test_copy_within() { let mut bytes = *b"Hello, World!"; bytes.copy_within(.., 0); assert_eq!(&bytes, b"Hello, World!"); + + // Ensure that copying at the end of slice won't cause UB. + let mut bytes = *b"Hello, World!"; + bytes.copy_within(13..13, 5); + assert_eq!(&bytes, b"Hello, World!"); + bytes.copy_within(5..5, 13); + assert_eq!(&bytes, b"Hello, World!"); } #[test] #[should_panic(expected = "src is out of bounds")] -#[cfg(not(miri))] // Miri does not support panics fn test_copy_within_panics_src_too_long() { let mut bytes = *b"Hello, World!"; // The length is only 13, so 14 is out of bounds. @@ -1313,7 +1544,6 @@ fn test_copy_within_panics_src_too_long() { #[test] #[should_panic(expected = "dest is out of bounds")] -#[cfg(not(miri))] // Miri does not support panics fn test_copy_within_panics_dest_too_long() { let mut bytes = *b"Hello, World!"; // The length is only 13, so a slice of length 4 starting at index 10 is out of bounds. @@ -1321,12 +1551,18 @@ fn test_copy_within_panics_dest_too_long() { } #[test] #[should_panic(expected = "src end is before src start")] -#[cfg(not(miri))] // Miri does not support panics fn test_copy_within_panics_src_inverted() { let mut bytes = *b"Hello, World!"; // 2 is greater than 1, so this range is invalid. bytes.copy_within(2..1, 0); } +#[test] +#[should_panic(expected = "attempted to index slice up to maximum usize")] +fn test_copy_within_panics_src_out_of_bounds() { + let mut bytes = *b"Hello, World!"; + // an inclusive range ending at usize::max_value() would make src_end overflow + bytes.copy_within(usize::max_value()..=usize::max_value(), 0); +} #[test] fn test_is_sorted() { diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs index 09aae4583482f..6efd22572dc18 100644 --- a/src/libcore/tests/time.rs +++ b/src/libcore/tests/time.rs @@ -107,14 +107,12 @@ fn checked_sub() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn sub_bad1() { let _ = Duration::new(0, 0) - Duration::new(0, 1); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn sub_bad2() { let _ = Duration::new(0, 0) - Duration::new(1, 0); } diff --git a/src/libcore/tests/tuple.rs b/src/libcore/tests/tuple.rs index a4c171eb4243b..c7ed1612dd5ea 100644 --- a/src/libcore/tests/tuple.rs +++ b/src/libcore/tests/tuple.rs @@ -1,4 +1,5 @@ use std::cmp::Ordering::{Equal, Less, Greater}; +use std::f64::NAN; #[test] fn test_clone() { @@ -8,18 +9,18 @@ fn test_clone() { } #[test] -fn test_tuple_cmp() { +fn test_partial_eq() { let (small, big) = ((1, 2, 3), (3, 2, 1)); - - let nan = 0.0f64/0.0; - - // PartialEq assert_eq!(small, small); assert_eq!(big, big); - assert!(small != big); - assert!(big != small); + assert_ne!(small, big); + assert_ne!(big, small); +} + +#[test] +fn test_partial_ord() { + let (small, big) = ((1, 2, 3), (3, 2, 1)); - // PartialOrd assert!(small < big); assert!(!(small < small)); assert!(!(big < small)); @@ -33,18 +34,21 @@ fn test_tuple_cmp() { assert!(big >= small); assert!(big >= big); - assert!(!((1.0f64, 2.0f64) < (nan, 3.0))); - assert!(!((1.0f64, 2.0f64) <= (nan, 3.0))); - assert!(!((1.0f64, 2.0f64) > (nan, 3.0))); - assert!(!((1.0f64, 2.0f64) >= (nan, 3.0))); - assert!(((1.0f64, 2.0f64) < (2.0, nan))); - assert!(!((2.0f64, 2.0f64) < (2.0, nan))); - - // Ord - assert!(small.cmp(&small) == Equal); - assert!(big.cmp(&big) == Equal); - assert!(small.cmp(&big) == Less); - assert!(big.cmp(&small) == Greater); + assert!(!((1.0f64, 2.0f64) < (NAN, 3.0))); + assert!(!((1.0f64, 2.0f64) <= (NAN, 3.0))); + assert!(!((1.0f64, 2.0f64) > (NAN, 3.0))); + assert!(!((1.0f64, 2.0f64) >= (NAN, 3.0))); + assert!(((1.0f64, 2.0f64) < (2.0, NAN))); + assert!(!((2.0f64, 2.0f64) < (2.0, NAN))); +} + +#[test] +fn test_ord() { + let (small, big) = ((1, 2, 3), (3, 2, 1)); + assert_eq!(small.cmp(&small), Equal); + assert_eq!(big.cmp(&big), Equal); + assert_eq!(small.cmp(&big), Less); + assert_eq!(big.cmp(&small), Greater); } #[test] diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 91161ca477e39..0f5f91f41a8cd 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -12,16 +12,15 @@ //! assert_eq!(Duration::new(5, 0), Duration::from_secs(5)); //! ``` -use {fmt, u64}; -use iter::Sum; -use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign}; +use crate::{fmt, u64}; +use crate::iter::Sum; +use crate::ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign}; const NANOS_PER_SEC: u32 = 1_000_000_000; const NANOS_PER_MILLI: u32 = 1_000_000; const NANOS_PER_MICRO: u32 = 1_000; const MILLIS_PER_SEC: u64 = 1_000; const MICROS_PER_SEC: u64 = 1_000_000; -const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f64; /// A `Duration` type to represent a span of time, typically used for system /// timeouts. @@ -510,15 +509,34 @@ impl Duration { /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); - /// assert_eq!(dur.as_float_secs(), 2.7); + /// assert_eq!(dur.as_secs_f64(), 2.7); /// ``` #[unstable(feature = "duration_float", issue = "54361")] #[inline] - pub const fn as_float_secs(&self) -> f64 { + pub const fn as_secs_f64(&self) -> f64 { (self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64) } - /// Creates a new `Duration` from the specified number of seconds. + /// Returns the number of seconds contained by this `Duration` as `f32`. + /// + /// The returned value does include the fractional (nanosecond) part of the duration. + /// + /// # Examples + /// ``` + /// #![feature(duration_float)] + /// use std::time::Duration; + /// + /// let dur = Duration::new(2, 700_000_000); + /// assert_eq!(dur.as_secs_f32(), 2.7); + /// ``` + #[unstable(feature = "duration_float", issue = "54361")] + #[inline] + pub const fn as_secs_f32(&self) -> f32 { + (self.secs as f32) + (self.nanos as f32) / (NANOS_PER_SEC as f32) + } + + /// Creates a new `Duration` from the specified number of seconds represented + /// as `f64`. /// /// # Panics /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`. @@ -528,12 +546,14 @@ impl Duration { /// #![feature(duration_float)] /// use std::time::Duration; /// - /// let dur = Duration::from_float_secs(2.7); + /// let dur = Duration::from_secs_f64(2.7); /// assert_eq!(dur, Duration::new(2, 700_000_000)); /// ``` #[unstable(feature = "duration_float", issue = "54361")] #[inline] - pub fn from_float_secs(secs: f64) -> Duration { + pub fn from_secs_f64(secs: f64) -> Duration { + const MAX_NANOS_F64: f64 = + ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f64; let nanos = secs * (NANOS_PER_SEC as f64); if !nanos.is_finite() { panic!("got non-finite value when converting float to duration"); @@ -551,6 +571,42 @@ impl Duration { } } + /// Creates a new `Duration` from the specified number of seconds represented + /// as `f32`. + /// + /// # Panics + /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`. + /// + /// # Examples + /// ``` + /// #![feature(duration_float)] + /// use std::time::Duration; + /// + /// let dur = Duration::from_secs_f32(2.7); + /// assert_eq!(dur, Duration::new(2, 700_000_000)); + /// ``` + #[unstable(feature = "duration_float", issue = "54361")] + #[inline] + pub fn from_secs_f32(secs: f32) -> Duration { + const MAX_NANOS_F32: f32 = + ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f32; + let nanos = secs * (NANOS_PER_SEC as f32); + if !nanos.is_finite() { + panic!("got non-finite value when converting float to duration"); + } + if nanos >= MAX_NANOS_F32 { + panic!("overflow when converting float to duration"); + } + if nanos < 0.0 { + panic!("underflow when converting float to duration"); + } + let nanos = nanos as u128; + Duration { + secs: (nanos / (NANOS_PER_SEC as u128)) as u64, + nanos: (nanos % (NANOS_PER_SEC as u128)) as u32, + } + } + /// Multiplies `Duration` by `f64`. /// /// # Panics @@ -568,7 +624,29 @@ impl Duration { #[unstable(feature = "duration_float", issue = "54361")] #[inline] pub fn mul_f64(self, rhs: f64) -> Duration { - Duration::from_float_secs(rhs * self.as_float_secs()) + Duration::from_secs_f64(rhs * self.as_secs_f64()) + } + + /// Multiplies `Duration` by `f32`. + /// + /// # Panics + /// This method will panic if result is not finite, negative or overflows `Duration`. + /// + /// # Examples + /// ``` + /// #![feature(duration_float)] + /// use std::time::Duration; + /// + /// let dur = Duration::new(2, 700_000_000); + /// // note that due to rounding errors result is slightly different + /// // from 8.478 and 847800.0 + /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640)); + /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256)); + /// ``` + #[unstable(feature = "duration_float", issue = "54361")] + #[inline] + pub fn mul_f32(self, rhs: f32) -> Duration { + Duration::from_secs_f32(rhs * self.as_secs_f32()) } /// Divide `Duration` by `f64`. @@ -589,7 +667,30 @@ impl Duration { #[unstable(feature = "duration_float", issue = "54361")] #[inline] pub fn div_f64(self, rhs: f64) -> Duration { - Duration::from_float_secs(self.as_float_secs() / rhs) + Duration::from_secs_f64(self.as_secs_f64() / rhs) + } + + /// Divide `Duration` by `f32`. + /// + /// # Panics + /// This method will panic if result is not finite, negative or overflows `Duration`. + /// + /// # Examples + /// ``` + /// #![feature(duration_float)] + /// use std::time::Duration; + /// + /// let dur = Duration::new(2, 700_000_000); + /// // note that due to rounding errors result is slightly + /// // different from 0.859_872_611 + /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_576)); + /// // note that truncation is used, not rounding + /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598)); + /// ``` + #[unstable(feature = "duration_float", issue = "54361")] + #[inline] + pub fn div_f32(self, rhs: f32) -> Duration { + Duration::from_secs_f32(self.as_secs_f32() / rhs) } /// Divide `Duration` by `Duration` and return `f64`. @@ -601,12 +702,29 @@ impl Duration { /// /// let dur1 = Duration::new(2, 700_000_000); /// let dur2 = Duration::new(5, 400_000_000); - /// assert_eq!(dur1.div_duration(dur2), 0.5); + /// assert_eq!(dur1.div_duration_f64(dur2), 0.5); + /// ``` + #[unstable(feature = "duration_float", issue = "54361")] + #[inline] + pub fn div_duration_f64(self, rhs: Duration) -> f64 { + self.as_secs_f64() / rhs.as_secs_f64() + } + + /// Divide `Duration` by `Duration` and return `f32`. + /// + /// # Examples + /// ``` + /// #![feature(duration_float)] + /// use std::time::Duration; + /// + /// let dur1 = Duration::new(2, 700_000_000); + /// let dur2 = Duration::new(5, 400_000_000); + /// assert_eq!(dur1.div_duration_f32(dur2), 0.5); /// ``` #[unstable(feature = "duration_float", issue = "54361")] #[inline] - pub fn div_duration(self, rhs: Duration) -> f64 { - self.as_float_secs() / rhs.as_float_secs() + pub fn div_duration_f32(self, rhs: Duration) -> f32 { + self.as_secs_f32() / rhs.as_secs_f32() } } @@ -729,7 +847,7 @@ impl<'a> Sum<&'a Duration> for Duration { #[stable(feature = "duration_debug_impl", since = "1.27.0")] impl fmt::Debug for Duration { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// Formats a floating point number in decimal notation. /// /// The number is given as the `integer_part` and a fractional part. @@ -741,7 +859,7 @@ impl fmt::Debug for Duration { /// of 10, everything else doesn't make sense. `fractional_part` has /// to be less than `10 * divisor`! fn fmt_decimal( - f: &mut fmt::Formatter, + f: &mut fmt::Formatter<'_>, mut integer_part: u64, mut fractional_part: u32, mut divisor: u32, @@ -803,7 +921,7 @@ impl fmt::Debug for Duration { // Determine the end of the buffer: if precision is set, we just // use as many digits from the buffer (capped to 9). If it isn't // set, we only use all digits up to the last non-zero one. - let end = f.precision().map(|p| ::cmp::min(p, 9)).unwrap_or(pos); + let end = f.precision().map(|p| crate::cmp::min(p, 9)).unwrap_or(pos); // If we haven't emitted a single fractional digit and the precision // wasn't set to a non-zero value, we don't print the decimal point. @@ -813,7 +931,7 @@ impl fmt::Debug for Duration { // We are only writing ASCII digits into the buffer and it was // initialized with '0's, so it contains valid UTF8. let s = unsafe { - ::str::from_utf8_unchecked(&buf[..end]) + crate::str::from_utf8_unchecked(&buf[..end]) }; // If the user request a precision > 9, we pad '0's at the end. diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index a82666d8f70f8..f05780f4a6270 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -1,7 +1,7 @@ // See src/libstd/primitive_docs.rs for documentation. -use cmp::*; -use cmp::Ordering::*; +use crate::cmp::*; +use crate::cmp::Ordering::*; // macro for implementing n-ary tuple functions and operations macro_rules! tuple_impls { diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs index 3b86246269f62..272727def61d6 100644 --- a/src/libcore/unicode/mod.rs +++ b/src/libcore/unicode/mod.rs @@ -8,13 +8,13 @@ pub(crate) mod version; // For use in liballoc, not re-exported in libstd. pub mod derived_property { - pub use unicode::tables::derived_property::{Case_Ignorable, Cased}; + pub use crate::unicode::tables::derived_property::{Case_Ignorable, Cased}; } pub mod conversions { - pub use unicode::tables::conversions::{to_lower, to_upper}; + pub use crate::unicode::tables::conversions::{to_lower, to_upper}; } // For use in libsyntax pub mod property { - pub use unicode::tables::property::Pattern_White_Space; + pub use crate::unicode::tables::property::Pattern_White_Space; } diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs index edef4ca361e4f..758cdb0b7cfba 100644 --- a/src/libcore/unicode/tables.rs +++ b/src/libcore/unicode/tables.rs @@ -2,8 +2,8 @@ #![allow(missing_docs, non_upper_case_globals, non_snake_case)] -use unicode::version::UnicodeVersion; -use unicode::bool_trie::{BoolTrie, SmallBoolTrie}; +use crate::unicode::version::UnicodeVersion; +use crate::unicode::bool_trie::{BoolTrie, SmallBoolTrie}; /// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of /// `char` and `str` methods are based on. diff --git a/src/libcore/unit.rs b/src/libcore/unit.rs index 540025d77bb4c..bf01ceb8b2d3e 100644 --- a/src/libcore/unit.rs +++ b/src/libcore/unit.rs @@ -1,4 +1,4 @@ -use iter::FromIterator; +use crate::iter::FromIterator; /// Collapses all unit items from an iterator into one. /// diff --git a/src/libfmt_macros/Cargo.toml b/src/libfmt_macros/Cargo.toml index 50779a2d9ad08..fc32f21ec4e0a 100644 --- a/src/libfmt_macros/Cargo.toml +++ b/src/libfmt_macros/Cargo.toml @@ -8,3 +8,6 @@ edition = "2018" name = "fmt_macros" path = "lib.rs" crate-type = ["dylib"] + +[dependencies] +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index aacd6cec565a5..f6e9143dd0583 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -9,6 +9,8 @@ test(attr(deny(warnings))))] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] #![feature(nll)] #![feature(rustc_private)] @@ -23,6 +25,17 @@ use std::str; use std::string; use std::iter; +use syntax_pos::{InnerSpan, Symbol}; + +#[derive(Copy, Clone)] +struct InnerOffset(usize); + +impl InnerOffset { + fn to(self, end: InnerOffset) -> InnerSpan { + InnerSpan::new(self.0, end.0) + } +} + /// A piece is a portion of the format string which represents the next part /// to emit. These are emitted as a stream by the `Parser` class. #[derive(Copy, Clone, PartialEq)] @@ -38,7 +51,7 @@ pub enum Piece<'a> { #[derive(Copy, Clone, PartialEq)] pub struct Argument<'a> { /// Where to find this argument - pub position: Position<'a>, + pub position: Position, /// How to format the argument pub format: FormatSpec<'a>, } @@ -53,9 +66,9 @@ pub struct FormatSpec<'a> { /// Packed version of various flags provided pub flags: u32, /// The integer precision to use - pub precision: Count<'a>, + pub precision: Count, /// The string width requested for the resulting format - pub width: Count<'a>, + pub width: Count, /// The descriptor string representing the name of the format desired for /// this argument, this can be empty or any number of characters, although /// it is required to be one word. @@ -64,16 +77,16 @@ pub struct FormatSpec<'a> { /// Enum describing where an argument for a format can be located. #[derive(Copy, Clone, PartialEq)] -pub enum Position<'a> { +pub enum Position { /// The argument is implied to be located at an index ArgumentImplicitlyIs(usize), /// The argument is located at a specific index given in the format ArgumentIs(usize), /// The argument has a name. - ArgumentNamed(&'a str), + ArgumentNamed(Symbol), } -impl Position<'_> { +impl Position { pub fn index(&self) -> Option { match self { ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i), @@ -118,11 +131,11 @@ pub enum Flag { /// A count is used for the precision and width parameters of an integer, and /// can reference either an argument or a literal integer. #[derive(Copy, Clone, PartialEq)] -pub enum Count<'a> { +pub enum Count { /// The count is specified explicitly. CountIs(usize), /// The count is specified by the argument with the given name. - CountIsName(&'a str), + CountIsName(Symbol), /// The count is specified by the argument at the given index. CountIsParam(usize), /// The count is implied and cannot be explicitly specified. @@ -133,9 +146,8 @@ pub struct ParseError { pub description: string::String, pub note: Option, pub label: string::String, - pub start: SpanIndex, - pub end: SpanIndex, - pub secondary_label: Option<(string::String, SpanIndex, SpanIndex)>, + pub span: InnerSpan, + pub secondary_label: Option<(string::String, InnerSpan)>, } /// The parser structure for interpreting the input format string. This is @@ -154,24 +166,15 @@ pub struct Parser<'a> { /// `Some(raw count)` when the string is "raw", used to position spans correctly style: Option, /// Start and end byte offset of every successfully parsed argument - pub arg_places: Vec<(SpanIndex, SpanIndex)>, + pub arg_places: Vec, /// Characters that need to be shifted skips: Vec, - /// Span offset of the last opening brace seen, used for error reporting - last_opening_brace_pos: Option, + /// Span of the last opening brace seen, used for error reporting + last_opening_brace: Option, /// Wether the source string is comes from `println!` as opposed to `format!` or `print!` append_newline: bool, } -#[derive(Clone, Copy, Debug)] -pub struct SpanIndex(pub usize); - -impl SpanIndex { - pub fn unwrap(self) -> usize { - self.0 - } -} - impl<'a> Iterator for Parser<'a> { type Item = Piece<'a>; @@ -179,19 +182,20 @@ impl<'a> Iterator for Parser<'a> { if let Some(&(pos, c)) = self.cur.peek() { match c { '{' => { - let curr_last_brace = self.last_opening_brace_pos; - self.last_opening_brace_pos = Some(self.to_span_index(pos)); + let curr_last_brace = self.last_opening_brace; + let byte_pos = self.to_span_index(pos); + self.last_opening_brace = Some(byte_pos.to(InnerOffset(byte_pos.0 + 1))); self.cur.next(); if self.consume('{') { - self.last_opening_brace_pos = curr_last_brace; + self.last_opening_brace = curr_last_brace; Some(String(self.string(pos + 1))) } else { let arg = self.argument(); - if let Some(arg_pos) = self.must_consume('}').map(|end| { - (self.to_span_index(pos), self.to_span_index(end + 1)) - }) { - self.arg_places.push(arg_pos); + if let Some(end) = self.must_consume('}') { + let start = self.to_span_index(pos); + let end = self.to_span_index(end + 1); + self.arg_places.push(start.to(end)); } Some(NextArgument(arg)) } @@ -206,8 +210,7 @@ impl<'a> Iterator for Parser<'a> { "unmatched `}` found", "unmatched `}`", "if you intended to print `}`, you can escape it using `}}`", - err_pos, - err_pos, + err_pos.to(err_pos), ); None } @@ -239,7 +242,7 @@ impl<'a> Parser<'a> { style, arg_places: vec![], skips, - last_opening_brace_pos: None, + last_opening_brace: None, append_newline, } } @@ -251,15 +254,13 @@ impl<'a> Parser<'a> { &mut self, description: S1, label: S2, - start: SpanIndex, - end: SpanIndex, + span: InnerSpan, ) { self.errors.push(ParseError { description: description.into(), note: None, label: label.into(), - start, - end, + span, secondary_label: None, }); } @@ -272,15 +273,13 @@ impl<'a> Parser<'a> { description: S1, label: S2, note: S3, - start: SpanIndex, - end: SpanIndex, + span: InnerSpan, ) { self.errors.push(ParseError { description: description.into(), note: Some(note.into()), label: label.into(), - start, - end, + span, secondary_label: None, }); } @@ -301,22 +300,21 @@ impl<'a> Parser<'a> { } } - fn raw(&self) -> usize { - self.style.map(|raw| raw + 1).unwrap_or(0) - } - - fn to_span_index(&self, pos: usize) -> SpanIndex { + fn to_span_index(&self, pos: usize) -> InnerOffset { let mut pos = pos; + // This handles the raw string case, the raw argument is the number of # + // in r###"..."### (we need to add one because of the `r`). + let raw = self.style.map(|raw| raw + 1).unwrap_or(0); for skip in &self.skips { if pos > *skip { pos += 1; - } else if pos == *skip && self.raw() == 0 { + } else if pos == *skip && raw == 0 { pos += 1; } else { break; } } - SpanIndex(self.raw() + pos + 1) + InnerOffset(raw + pos + 1) } /// Forces consumption of the specified character. If the character is not @@ -334,8 +332,8 @@ impl<'a> Parser<'a> { let label = "expected `}`".to_owned(); let (note, secondary_label) = if c == '}' { (Some("if you intended to print `{`, you can escape it using `{{`".to_owned()), - self.last_opening_brace_pos.map(|pos| { - ("because of this opening brace".to_owned(), pos, pos) + self.last_opening_brace.map(|sp| { + ("because of this opening brace".to_owned(), sp) })) } else { (None, None) @@ -344,8 +342,7 @@ impl<'a> Parser<'a> { description, note, label, - start: pos, - end: pos, + span: pos.to(pos), secondary_label, }); None @@ -359,8 +356,8 @@ impl<'a> Parser<'a> { let label = format!("expected `{:?}`", c); let (note, secondary_label) = if c == '}' { (Some("if you intended to print `{`, you can escape it using `{{`".to_owned()), - self.last_opening_brace_pos.map(|pos| { - ("because of this opening brace".to_owned(), pos, pos) + self.last_opening_brace.map(|sp| { + ("because of this opening brace".to_owned(), sp) })) } else { (None, None) @@ -369,12 +366,11 @@ impl<'a> Parser<'a> { description, note, label, - start: pos, - end: pos, + span: pos.to(pos), secondary_label, }); } else { - self.err(description, format!("expected `{:?}`", c), pos, pos); + self.err(description, format!("expected `{:?}`", c), pos.to(pos)); } None } @@ -433,20 +429,24 @@ impl<'a> Parser<'a> { /// integer index of an argument, a named argument, or a blank string. /// Returns `Some(parsed_position)` if the position is not implicitly /// consuming a macro argument, `None` if it's the case. - fn position(&mut self) -> Option> { + fn position(&mut self) -> Option { if let Some(i) = self.integer() { Some(ArgumentIs(i)) } else { match self.cur.peek() { - Some(&(_, c)) if c.is_alphabetic() => Some(ArgumentNamed(self.word())), + Some(&(_, c)) if c.is_alphabetic() => { + Some(ArgumentNamed(Symbol::intern(self.word()))) + } Some(&(pos, c)) if c == '_' => { let invalid_name = self.string(pos); self.err_with_note(format!("invalid argument name `{}`", invalid_name), "invalid argument name", "argument names cannot start with an underscore", - self.to_span_index(pos), - self.to_span_index(pos + invalid_name.len())); - Some(ArgumentNamed(invalid_name)) + self.to_span_index(pos).to( + self.to_span_index(pos + invalid_name.len()) + ), + ); + Some(ArgumentNamed(Symbol::intern(invalid_name))) }, // This is an `ArgumentNext`. @@ -554,7 +554,7 @@ impl<'a> Parser<'a> { /// Parses a Count parameter at the current position. This does not check /// for 'CountIsNextParam' because that is only used in precision, not /// width. - fn count(&mut self) -> Count<'a> { + fn count(&mut self) -> Count { if let Some(i) = self.integer() { if self.consume('$') { CountIsParam(i) @@ -568,7 +568,7 @@ impl<'a> Parser<'a> { self.cur = tmp; CountImplied } else if self.consume('$') { - CountIsName(word) + CountIsName(Symbol::intern(word)) } else { self.cur = tmp; CountImplied @@ -622,245 +622,4 @@ impl<'a> Parser<'a> { } #[cfg(test)] -mod tests { - use super::*; - - fn same(fmt: &'static str, p: &[Piece<'static>]) { - let parser = Parser::new(fmt, None, vec![], false); - assert!(parser.collect::>>() == p); - } - - fn fmtdflt() -> FormatSpec<'static> { - return FormatSpec { - fill: None, - align: AlignUnknown, - flags: 0, - precision: CountImplied, - width: CountImplied, - ty: "", - }; - } - - fn musterr(s: &str) { - let mut p = Parser::new(s, None, vec![], false); - p.next(); - assert!(!p.errors.is_empty()); - } - - #[test] - fn simple() { - same("asdf", &[String("asdf")]); - same("a{{b", &[String("a"), String("{b")]); - same("a}}b", &[String("a"), String("}b")]); - same("a}}", &[String("a"), String("}")]); - same("}}", &[String("}")]); - same("\\}}", &[String("\\"), String("}")]); - } - - #[test] - fn invalid01() { - musterr("{") - } - #[test] - fn invalid02() { - musterr("}") - } - #[test] - fn invalid04() { - musterr("{3a}") - } - #[test] - fn invalid05() { - musterr("{:|}") - } - #[test] - fn invalid06() { - musterr("{:>>>}") - } - - #[test] - fn format_nothing() { - same("{}", - &[NextArgument(Argument { - position: ArgumentImplicitlyIs(0), - format: fmtdflt(), - })]); - } - #[test] - fn format_position() { - same("{3}", - &[NextArgument(Argument { - position: ArgumentIs(3), - format: fmtdflt(), - })]); - } - #[test] - fn format_position_nothing_else() { - same("{3:}", - &[NextArgument(Argument { - position: ArgumentIs(3), - format: fmtdflt(), - })]); - } - #[test] - fn format_type() { - same("{3:a}", - &[NextArgument(Argument { - position: ArgumentIs(3), - format: FormatSpec { - fill: None, - align: AlignUnknown, - flags: 0, - precision: CountImplied, - width: CountImplied, - ty: "a", - }, - })]); - } - #[test] - fn format_align_fill() { - same("{3:>}", - &[NextArgument(Argument { - position: ArgumentIs(3), - format: FormatSpec { - fill: None, - align: AlignRight, - flags: 0, - precision: CountImplied, - width: CountImplied, - ty: "", - }, - })]); - same("{3:0<}", - &[NextArgument(Argument { - position: ArgumentIs(3), - format: FormatSpec { - fill: Some('0'), - align: AlignLeft, - flags: 0, - precision: CountImplied, - width: CountImplied, - ty: "", - }, - })]); - same("{3:*]) { + let parser = Parser::new(fmt, None, vec![], false); + assert!(parser.collect::>>() == p); +} + +fn fmtdflt() -> FormatSpec<'static> { + return FormatSpec { + fill: None, + align: AlignUnknown, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "", + }; +} + +fn musterr(s: &str) { + let mut p = Parser::new(s, None, vec![], false); + p.next(); + assert!(!p.errors.is_empty()); +} + +#[test] +fn simple() { + same("asdf", &[String("asdf")]); + same("a{{b", &[String("a"), String("{b")]); + same("a}}b", &[String("a"), String("}b")]); + same("a}}", &[String("a"), String("}")]); + same("}}", &[String("}")]); + same("\\}}", &[String("\\"), String("}")]); +} + +#[test] +fn invalid01() { + musterr("{") +} +#[test] +fn invalid02() { + musterr("}") +} +#[test] +fn invalid04() { + musterr("{3a}") +} +#[test] +fn invalid05() { + musterr("{:|}") +} +#[test] +fn invalid06() { + musterr("{:>>>}") +} + +#[test] +fn format_nothing() { + same("{}", + &[NextArgument(Argument { + position: ArgumentImplicitlyIs(0), + format: fmtdflt(), + })]); +} +#[test] +fn format_position() { + same("{3}", + &[NextArgument(Argument { + position: ArgumentIs(3), + format: fmtdflt(), + })]); +} +#[test] +fn format_position_nothing_else() { + same("{3:}", + &[NextArgument(Argument { + position: ArgumentIs(3), + format: fmtdflt(), + })]); +} +#[test] +fn format_type() { + same("{3:a}", + &[NextArgument(Argument { + position: ArgumentIs(3), + format: FormatSpec { + fill: None, + align: AlignUnknown, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "a", + }, + })]); +} +#[test] +fn format_align_fill() { + same("{3:>}", + &[NextArgument(Argument { + position: ArgumentIs(3), + format: FormatSpec { + fill: None, + align: AlignRight, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "", + }, + })]); + same("{3:0<}", + &[NextArgument(Argument { + position: ArgumentIs(3), + format: FormatSpec { + fill: Some('0'), + align: AlignLeft, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "", + }, + })]); + same("{3:*(g: &'a G, } #[cfg(test)] -mod tests { - use NodeLabels::*; - use super::{Id, Labeller, Nodes, Edges, GraphWalk, render, Style}; - use super::LabelText::{self, LabelStr, EscStr, HtmlStr}; - use std::io; - use std::io::prelude::*; - - /// each node is an index in a vector in the graph. - type Node = usize; - struct Edge { - from: usize, - to: usize, - label: &'static str, - style: Style, - } - - fn edge(from: usize, to: usize, label: &'static str, style: Style) -> Edge { - Edge { - from, - to, - label, - style, - } - } - - struct LabelledGraph { - /// The name for this graph. Used for labeling generated `digraph`. - name: &'static str, - - /// Each node is an index into `node_labels`; these labels are - /// used as the label text for each node. (The node *names*, - /// which are unique identifiers, are derived from their index - /// in this array.) - /// - /// If a node maps to None here, then just use its name as its - /// text. - node_labels: Vec>, - - node_styles: Vec - - -

- ").unwrap(); - - let mut idx = 0; - for thread in threads.iter() { - for timing in &thread.timings { - let colors = timing.work_package_kind.0; - let height = TIME_LINE_HEIGHT_STRIDE_IN_PX * timing.events.len(); - writeln!(file, "
", - idx, - colors[idx % colors.len()], - height).unwrap(); - idx += 1; - let max = distance(timing.start, timing.end); - for (i, &(ref event, time)) in timing.events.iter().enumerate() { - let i = i as u64; - let time = distance(timing.start, time); - let at = normalize(time, max, OUTPUT_WIDTH_IN_PX); - writeln!(file, "{}", - at, - TIME_LINE_HEIGHT_IN_PX * i, - event).unwrap(); - } - writeln!(file, "
").unwrap(); - } - } - - writeln!(file, " - - - ").unwrap(); - } -} - -impl Timeline { - pub fn noop() -> Timeline { - Timeline { token: None } - } - - /// Record an event which happened at this moment on this timeline. - /// - /// Events are displayed in the eventual HTML output where you can click on - /// a particular timeline and it'll expand to all of the events that - /// happened on that timeline. This can then be used to drill into a - /// particular timeline and see what events are happening and taking the - /// most time. - pub fn record(&mut self, name: &str) { - if let Some(ref mut token) = self.token { - token.events.push((name.to_string(), Instant::now())); - } - } -} - -fn distance(zero: Instant, x: Instant) -> u64 { - - let duration = x.duration_since(zero); - (duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64) // / div -} - -fn normalize(distance: u64, max: u64, max_pixels: u64) -> u64 { - (max_pixels * distance) / max -} - diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 758a0d63886b1..d402b0ddf6e85 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -14,12 +14,12 @@ use syntax::{ base::{ExtCtxt, Resolver}, build::AstBuilder, expand::ExpansionConfig, - hygiene::{self, Mark, SyntaxContext}, + hygiene::{Mark, SyntaxContext}, }, mut_visit::{self, MutVisitor}, parse::ParseSess, ptr::P, - symbol::Symbol + symbol::{kw, sym} }; use syntax_pos::Span; @@ -58,11 +58,10 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> { fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { debug!("in submodule {}", self.in_submod); - let name = if attr::contains_name(&item.attrs, "global_allocator") { - "global_allocator" - } else { + if !attr::contains_name(&item.attrs, sym::global_allocator) { return mut_visit::noop_flat_map_item(item, self); - }; + } + match item.node { ItemKind::Static(..) => {} _ => { @@ -87,17 +86,9 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> { // Create a fresh Mark for the new macro expansion we are about to do let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(ExpnInfo { - call_site: item.span, // use the call site of the static - def_site: None, - format: MacroAttribute(Symbol::intern(name)), - allow_internal_unstable: Some(vec![ - Symbol::intern("rustc_attrs"), - ].into()), - allow_internal_unsafe: false, - local_inner_macros: false, - edition: hygiene::default_edition(), - }); + mark.set_expn_info(ExpnInfo::with_unstable( + MacroAttribute(sym::global_allocator), item.span, self.sess.edition, &[sym::rustc_attrs] + )); // Tie the span to the macro expansion info we just created let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark)); @@ -110,13 +101,13 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> { span, kind: AllocatorKind::Global, global: item.ident, - core: Ident::from_str("core"), + core: Ident::with_empty_ctxt(sym::core), cx: ExtCtxt::new(self.sess, ecfg, self.resolver), }; // We will generate a new submodule. To `use` the static from that module, we need to get // the `super::...` path. - let super_path = f.cx.path(f.span, vec![Ident::from_str("super"), f.global]); + let super_path = f.cx.path(f.span, vec![Ident::with_empty_ctxt(kw::Super), f.global]); // Generate the items in the submodule let mut items = vec![ @@ -139,7 +130,7 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> { // Generate the submodule itself let name = f.kind.fn_name("allocator_abi"); - let allocator_abi = Ident::with_empty_ctxt(Symbol::gensym(&name)); + let allocator_abi = Ident::from_str(&name).gensym(); let module = f.cx.item_mod(span, span, allocator_abi, Vec::new(), items); let module = f.cx.monotonic_expander().flat_map_item(module).pop().unwrap(); @@ -223,7 +214,7 @@ impl AllocFnFactory<'_> { } fn attrs(&self) -> Vec { - let special = Symbol::intern("rustc_std_internal_symbol"); + let special = sym::rustc_std_internal_symbol; let special = self.cx.meta_word(self.span, special); vec![self.cx.attribute(self.span, special)] } @@ -236,7 +227,7 @@ impl AllocFnFactory<'_> { ) -> P { match *ty { AllocatorTy::Layout => { - let usize = self.cx.path_ident(self.span, Ident::from_str("usize")); + let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize)); let ty_usize = self.cx.ty_path(usize); let size = ident(); let align = ident(); @@ -298,12 +289,12 @@ impl AllocFnFactory<'_> { } fn usize(&self) -> P { - let usize = self.cx.path_ident(self.span, Ident::from_str("usize")); + let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize)); self.cx.ty_path(usize) } fn ptr_u8(&self) -> P { - let u8 = self.cx.path_ident(self.span, Ident::from_str("u8")); + let u8 = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::u8)); let ty_u8 = self.cx.ty_path(u8); self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) } diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index 9d6e728e13557..e7a70895a3023 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -2,6 +2,8 @@ #![feature(rustc_private)] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] pub mod expand; diff --git a/src/librustc_apfloat/tests/ieee.rs b/src/librustc_apfloat/tests/ieee.rs index 108b2114439d4..7158efae8f1ad 100644 --- a/src/librustc_apfloat/tests/ieee.rs +++ b/src/librustc_apfloat/tests/ieee.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + use rustc_apfloat::{Category, ExpInt, IEK_INF, IEK_NAN, IEK_ZERO}; use rustc_apfloat::{Float, FloatConvert, ParseError, Round, Status}; use rustc_apfloat::ieee::{Half, Single, Double, Quad, X87DoubleExtended}; diff --git a/src/librustc_asan/Cargo.toml b/src/librustc_asan/Cargo.toml index 7d9641c83ee7d..df117de8720e0 100644 --- a/src/librustc_asan/Cargo.toml +++ b/src/librustc_asan/Cargo.toml @@ -12,7 +12,7 @@ test = false [build-dependencies] build_helper = { path = "../build_helper" } -cmake = "0.1.18" +cmake = "0.1.38" [dependencies] alloc = { path = "../liballoc" } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index c74d7f00cf516..714b7c27200e3 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -17,7 +17,6 @@ use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::region; use rustc::ty::{self, TyCtxt, RegionKind}; -use syntax::ast; use syntax_pos::Span; use rustc::hir; use rustc::hir::Node; @@ -37,7 +36,7 @@ fn owned_ptr_base_path<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> &'a LoanPath< return match helper(loan_path) { Some(new_loan_path) => new_loan_path, - None => loan_path.clone() + None => loan_path, }; fn helper<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> Option<&'a LoanPath<'tcx>> { @@ -79,10 +78,10 @@ fn owned_ptr_base_path_rc<'tcx>(loan_path: &Rc>) -> Rc { +struct CheckLoanCtxt<'a, 'tcx> { bccx: &'a BorrowckCtxt<'a, 'tcx>, - dfcx_loans: &'a LoanDataFlow<'a, 'tcx>, - move_data: &'a move_data::FlowedMoveData<'a, 'tcx>, + dfcx_loans: &'a LoanDataFlow<'tcx>, + move_data: &'a move_data::FlowedMoveData<'tcx>, all_loans: &'a [Loan<'tcx>], movable_generator: bool, } @@ -177,20 +176,22 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { self.check_assignment(assignment_id.local_id, assignment_span, assignee_cmt); } - fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) { } + fn decl_without_init(&mut self, _id: hir::HirId, _span: Span) { } } -pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - dfcx_loans: &LoanDataFlow<'b, 'tcx>, - move_data: &move_data::FlowedMoveData<'c, 'tcx>, - all_loans: &[Loan<'tcx>], - body: &hir::Body) { +pub fn check_loans<'a, 'tcx>( + bccx: &BorrowckCtxt<'a, 'tcx>, + dfcx_loans: &LoanDataFlow<'tcx>, + move_data: &move_data::FlowedMoveData<'tcx>, + all_loans: &[Loan<'tcx>], + body: &hir::Body, +) { debug!("check_loans(body id={})", body.value.hir_id); let def_id = bccx.tcx.hir().body_owner_def_id(body.id()); - let node_id = bccx.tcx.hir().as_local_node_id(def_id).unwrap(); - let movable_generator = !match bccx.tcx.hir().get(node_id) { + let hir_id = bccx.tcx.hir().as_local_hir_id(def_id).unwrap(); + let movable_generator = !match bccx.tcx.hir().get(hir_id) { Node::Expr(&hir::Expr { node: hir::ExprKind::Closure(.., Some(hir::GeneratorMovability::Static)), .. @@ -209,6 +210,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id); euv::ExprUseVisitor::new(&mut clcx, bccx.tcx, + def_id, param_env, &bccx.region_scope_tree, bccx.tables, @@ -229,7 +231,7 @@ fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind, } impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { - pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.bccx.tcx } + pub fn tcx(&self) -> TyCtxt<'tcx> { self.bccx.tcx } pub fn each_issued_loan(&self, node: hir::ItemLocalId, mut op: F) -> bool where F: FnMut(&Loan<'tcx>) -> bool, @@ -887,11 +889,10 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { // Check for reassignments to (immutable) local variables. This // needs to be done here instead of in check_loans because we // depend on move data. - if let Categorization::Local(local_id) = assignee_cmt.cat { + if let Categorization::Local(hir_id) = assignee_cmt.cat { let lp = opt_loan_path(assignee_cmt).unwrap(); self.move_data.each_assignment_of(assignment_id, &lp, |assign| { if assignee_cmt.mutbl.is_mutable() { - let hir_id = self.bccx.tcx.hir().node_to_hir_id(local_id); self.bccx.used_mut_nodes.borrow_mut().insert(hir_id); } else { self.bccx.report_reassigned_immutable_variable( diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 6b050fd9ba230..658e4307348db 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -11,17 +11,16 @@ use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; use rustc::ty::{self, Ty}; use std::rc::Rc; -use syntax::ast; use syntax_pos::Span; use rustc::hir::*; use rustc::hir::Node; use log::debug; -struct GatherMoveInfo<'c, 'tcx: 'c> { +struct GatherMoveInfo<'c, 'tcx> { id: hir::ItemLocalId, kind: MoveKind, cmt: &'c mc::cmt_<'tcx>, - span_path_opt: Option> + span_path_opt: Option>, } /// Represents the kind of pattern @@ -46,9 +45,9 @@ pub enum PatternSource<'tcx> { /// /// In this latter case, this function will return `PatternSource::LetDecl` /// with a reference to the let -fn get_pattern_source<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &Pat) -> PatternSource<'tcx> { +fn get_pattern_source<'tcx>(tcx: TyCtxt<'tcx>, pat: &Pat) -> PatternSource<'tcx> { - let parent = tcx.hir().get_parent_node(pat.id); + let parent = tcx.hir().get_parent_node(pat.hir_id); match tcx.hir().get(parent) { Node::Expr(ref e) => { @@ -67,11 +66,10 @@ fn get_pattern_source<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &Pat) -> Patte pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, move_data: &MoveData<'tcx>, - var_id: ast::NodeId, + var_id: hir::HirId, var_ty: Ty<'tcx>) { let loan_path = Rc::new(LoanPath::new(LpVar(var_id), var_ty)); - let hir_id = bccx.tcx.hir().node_to_hir_id(var_id); - move_data.add_move(bccx.tcx, loan_path, hir_id.local_id, Declared); + move_data.add_move(bccx.tcx, loan_path, var_id.local_id, Declared); } pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, @@ -93,14 +91,16 @@ pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, gather_move(bccx, move_data, move_error_collector, move_info); } -pub fn gather_move_from_pat<'a, 'c, 'tcx: 'c>(bccx: &BorrowckCtxt<'a, 'tcx>, - move_data: &MoveData<'tcx>, - move_error_collector: &mut MoveErrorCollector<'tcx>, - move_pat: &hir::Pat, - cmt: &'c mc::cmt_<'tcx>) { +pub fn gather_move_from_pat<'a, 'c, 'tcx>( + bccx: &BorrowckCtxt<'a, 'tcx>, + move_data: &MoveData<'tcx>, + move_error_collector: &mut MoveErrorCollector<'tcx>, + move_pat: &hir::Pat, + cmt: &'c mc::cmt_<'tcx>, +) { let source = get_pattern_source(bccx.tcx,move_pat); let pat_span_path_opt = match move_pat.node { - PatKind::Binding(_, _, _, ident, _) => { + PatKind::Binding(_, _, ident, _) => { Some(MovePlace { span: move_pat.span, name: ident.name, @@ -123,10 +123,12 @@ pub fn gather_move_from_pat<'a, 'c, 'tcx: 'c>(bccx: &BorrowckCtxt<'a, 'tcx>, gather_move(bccx, move_data, move_error_collector, move_info); } -fn gather_move<'a, 'c, 'tcx: 'c>(bccx: &BorrowckCtxt<'a, 'tcx>, - move_data: &MoveData<'tcx>, - move_error_collector: &mut MoveErrorCollector<'tcx>, - move_info: GatherMoveInfo<'c, 'tcx>) { +fn gather_move<'a, 'c, 'tcx>( + bccx: &BorrowckCtxt<'a, 'tcx>, + move_data: &MoveData<'tcx>, + move_error_collector: &mut MoveErrorCollector<'tcx>, + move_info: GatherMoveInfo<'c, 'tcx>, +) { debug!("gather_move(move_id={:?}, cmt={:?})", move_info.id, move_info.cmt); diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index ae1d49afd4931..3122a6060fbde 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -2,13 +2,13 @@ //! does not exceed the lifetime of the value being borrowed. use crate::borrowck::*; +use rustc::hir::HirId; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::region; use rustc::ty; -use syntax::ast; use syntax_pos::Span; use log::debug; @@ -38,7 +38,7 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, /////////////////////////////////////////////////////////////////////////// // Private -struct GuaranteeLifetimeContext<'a, 'tcx: 'a> { +struct GuaranteeLifetimeContext<'a, 'tcx> { bccx: &'a BorrowckCtxt<'a, 'tcx>, // the scope of the function body for the enclosing item @@ -51,7 +51,7 @@ struct GuaranteeLifetimeContext<'a, 'tcx: 'a> { } impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { - fn check(&self, cmt: &mc::cmt_<'tcx>, discr_scope: Option) -> R { + fn check(&self, cmt: &mc::cmt_<'tcx>, discr_scope: Option) -> R { //! Main routine. Walks down `cmt` until we find the //! "guarantor". Reports an error if `self.loan_region` is //! larger than scope of `cmt`. @@ -104,14 +104,13 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { Categorization::Upvar(..) => { self.bccx.tcx.mk_region(ty::ReScope(self.item_scope)) } - Categorization::Local(local_id) => { - let hir_id = self.bccx.tcx.hir().node_to_hir_id(local_id); + Categorization::Local(hir_id) => { self.bccx.tcx.mk_region(ty::ReScope( self.bccx.region_scope_tree.var_scope(hir_id.local_id))) } Categorization::StaticItem | Categorization::Deref(_, mc::UnsafePtr(..)) => { - self.bccx.tcx.types.re_static + self.bccx.tcx.lifetimes.re_static } Categorization::Deref(_, mc::BorrowedPtr(_, r)) => { r diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 03af27997d3cb..887011d3476d3 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -14,7 +14,6 @@ use rustc::middle::mem_categorization::Categorization; use rustc::middle::region; use rustc::ty::{self, TyCtxt}; -use syntax::ast; use syntax_pos::Span; use rustc::hir; use log::debug; @@ -45,6 +44,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id); euv::ExprUseVisitor::new(&mut glcx, bccx.tcx, + def_id, param_env, &bccx.region_scope_tree, bccx.tables, @@ -56,7 +56,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, (all_loans, move_data) } -struct GatherLoanCtxt<'a, 'tcx: 'a> { +struct GatherLoanCtxt<'a, 'tcx> { bccx: &'a BorrowckCtxt<'a, 'tcx>, move_data: move_data::MoveData<'tcx>, move_error_collector: move_error::MoveErrorCollector<'tcx>, @@ -141,18 +141,35 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { assignee_cmt: &mc::cmt_<'tcx>, _: euv::MutateMode) { - let node_id = self.bccx.tcx.hir().hir_to_node_id(assignment_id); - self.guarantee_assignment_valid(node_id, + self.guarantee_assignment_valid(assignment_id, assignment_span, assignee_cmt); } - fn decl_without_init(&mut self, id: ast::NodeId, _span: Span) { + fn decl_without_init(&mut self, id: hir::HirId, _span: Span) { let ty = self.bccx .tables - .node_type(self.bccx.tcx.hir().node_to_hir_id(id)); + .node_type(id); gather_moves::gather_decl(self.bccx, &self.move_data, id, ty); } + + fn nested_body(&mut self, body_id: hir::BodyId) { + debug!("nested_body(body_id={:?})", body_id); + // rust-lang/rust#58776: MIR and AST borrow check disagree on where + // certain closure errors are reported. As such migrate borrowck has to + // operate at the level of items, rather than bodies. Check if the + // contained closure had any errors and set `signalled_any_error` if it + // has. + let bccx = self.bccx; + if bccx.tcx.migrate_borrowck() { + if let SignalledError::NoErrorsSeen = bccx.signalled_any_error.get() { + let closure_def_id = bccx.tcx.hir().body_owner_def_id(body_id); + debug!("checking closure: {:?}", closure_def_id); + + bccx.signalled_any_error.set(bccx.tcx.borrowck(closure_def_id).signalled_any_error); + } + } + } } /// Implements the A-* rules in README.md. @@ -234,11 +251,11 @@ fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, } impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { - pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.bccx.tcx } + pub fn tcx(&self) -> TyCtxt<'tcx> { self.bccx.tcx } /// Guarantees that `cmt` is assignable, or reports an error. fn guarantee_assignment_valid(&mut self, - assignment_id: ast::NodeId, + assignment_id: hir::HirId, assignment_span: Span, cmt: &mc::cmt_<'tcx>) { @@ -272,8 +289,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { self.mark_loan_path_as_mutated(&lp); } gather_moves::gather_assignment(self.bccx, &self.move_data, - self.bccx.tcx.hir().node_to_hir_id(assignment_id) - .local_id, + assignment_id.local_id, assignment_span, lp); } @@ -438,9 +454,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { while let Some(current_path) = wrapped_path { wrapped_path = match current_path.kind { - LpVar(local_id) => { + LpVar(hir_id) => { if !through_borrow { - let hir_id = self.bccx.tcx.hir().node_to_hir_id(local_id); self.bccx.used_mut_nodes.borrow_mut().insert(hir_id); } None diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 9a00c43be3fbb..58be2cf76c724 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -88,7 +88,7 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &[MoveErr } } if let NoteClosureEnv(upvar_id) = error.move_from.note { - err.span_label(bccx.tcx.hir().span_by_hir_id(upvar_id.var_path.hir_id), + err.span_label(bccx.tcx.hir().span(upvar_id.var_path.hir_id), "captured outer variable"); } err.emit(); diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 9f4c05a6b255f..371e6c55a7389 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -37,7 +37,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, /////////////////////////////////////////////////////////////////////////// // Private -struct RestrictionsContext<'a, 'tcx: 'a> { +struct RestrictionsContext<'a, 'tcx> { bccx: &'a BorrowckCtxt<'a, 'tcx>, span: Span, loan_region: ty::Region<'tcx>, diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 31189a71bba82..3c7f19f7fbf4f 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -32,9 +32,8 @@ use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::fmt; use std::rc::Rc; -use rustc_data_structures::sync::Lrc; use std::hash::{Hash, Hasher}; -use syntax::ast; +use syntax::source_map::CompilerDesugaringKind; use syntax_pos::{MultiSpan, Span}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use log::debug; @@ -49,14 +48,12 @@ pub mod gather_loans; pub mod move_data; -mod unused; - #[derive(Clone, Copy)] pub struct LoanDataFlowOperator; -pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; +pub type LoanDataFlow<'tcx> = DataFlowContext<'tcx, LoanDataFlowOperator>; -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) { tcx.par_body_owners(|body_owner_def_id| { tcx.ensure().borrowck(body_owner_def_id); }); @@ -70,29 +67,26 @@ pub fn provide(providers: &mut Providers<'_>) { } /// Collection of conclusions determined via borrow checker analyses. -pub struct AnalysisData<'a, 'tcx: 'a> { +pub struct AnalysisData<'tcx> { pub all_loans: Vec>, - pub loans: DataFlowContext<'a, 'tcx, LoanDataFlowOperator>, - pub move_data: move_data::FlowedMoveData<'a, 'tcx>, + pub loans: DataFlowContext<'tcx, LoanDataFlowOperator>, + pub move_data: move_data::FlowedMoveData<'tcx>, } -fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) - -> Lrc -{ +fn borrowck<'tcx>(tcx: TyCtxt<'tcx>, owner_def_id: DefId) -> &'tcx BorrowCheckResult { assert!(tcx.use_ast_borrowck() || tcx.migrate_borrowck()); debug!("borrowck(body_owner_def_id={:?})", owner_def_id); - let owner_id = tcx.hir().as_local_node_id(owner_def_id).unwrap(); + let owner_id = tcx.hir().as_local_hir_id(owner_def_id).unwrap(); match tcx.hir().get(owner_id) { - Node::StructCtor(_) | - Node::Variant(_) => { + Node::Ctor(..) => { // We get invoked with anything that has MIR, but some of // those things (notably the synthesized constructors from // tuple structs/variants) do not have an associated body // and do not need borrowchecking. - return Lrc::new(BorrowCheckResult { + return tcx.arena.alloc(BorrowCheckResult { used_mut_nodes: Default::default(), signalled_any_error: SignalledError::NoErrorsSeen, }) @@ -139,22 +133,20 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) check_loans::check_loans(&mut bccx, &loan_dfcx, &flowed_moves, &all_loans, body); } - if !tcx.use_mir_borrowck() { - unused::check(&mut bccx, body); - } - - Lrc::new(BorrowCheckResult { + tcx.arena.alloc(BorrowCheckResult { used_mut_nodes: bccx.used_mut_nodes.into_inner(), signalled_any_error: bccx.signalled_any_error.into_inner(), }) } -fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tcx>, - force_analysis: bool, - body_id: hir::BodyId, - get_cfg: F) - -> Option> - where F: FnOnce(&mut BorrowckCtxt<'a, 'tcx>) -> &'c cfg::CFG +fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>( + this: &mut BorrowckCtxt<'a, 'tcx>, + force_analysis: bool, + body_id: hir::BodyId, + get_cfg: F, +) -> Option> +where + F: FnOnce(&mut BorrowckCtxt<'a, 'tcx>) -> &'c cfg::CFG, { // Check the body of fn items. let (all_loans, move_data) = @@ -201,13 +193,12 @@ fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tc /// Accessor for introspective clients inspecting `AnalysisData` and /// the `BorrowckCtxt` itself , e.g., the flowgraph visualizer. pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, body_id: hir::BodyId, - cfg: &cfg::CFG) - -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>) -{ + cfg: &cfg::CFG, +) -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'tcx>) { let owner_id = tcx.hir().body_owner(body_id); - let owner_def_id = tcx.hir().local_def_id(owner_id); + let owner_def_id = tcx.hir().local_def_id_from_hir_id(owner_id); let tables = tcx.typeck_tables_of(owner_def_id); let region_scope_tree = tcx.region_scope_tree(owner_def_id); let body = tcx.hir().body(body_id); @@ -228,14 +219,14 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( // ---------------------------------------------------------------------- // Type definitions -pub struct BorrowckCtxt<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub struct BorrowckCtxt<'a, 'tcx> { + tcx: TyCtxt<'tcx>, // tables for the current thing we are checking; set to // Some in `borrowck_fn` and cleared later tables: &'a ty::TypeckTables<'tcx>, - region_scope_tree: Lrc, + region_scope_tree: &'tcx region::ScopeTree, owner_def_id: DefId, @@ -246,14 +237,13 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> { signalled_any_error: Cell, } - -impl<'a, 'tcx: 'a> BorrowckCtxt<'a, 'tcx> { +impl BorrowckCtxt<'_, 'tcx> { fn signal_error(&self) { self.signalled_any_error.set(SignalledError::SawSomeError); } } -impl<'a, 'b, 'tcx: 'b> BorrowckErrors<'a> for &'a BorrowckCtxt<'b, 'tcx> { +impl BorrowckErrors<'a> for &'a BorrowckCtxt<'_, 'tcx> { fn struct_span_err_with_code>(self, sp: S, msg: &str, @@ -335,7 +325,7 @@ impl<'tcx> Hash for LoanPath<'tcx> { #[derive(PartialEq, Eq, Hash, Debug)] pub enum LoanPathKind<'tcx> { - LpVar(ast::NodeId), // `x` in README.md + LpVar(hir::HirId), // `x` in README.md LpUpvar(ty::UpvarId), // `x` captured by-value into closure LpDowncast(Rc>, DefId), // `x` downcast to particular enum variant LpExtend(Rc>, mc::MutabilityCategory, LoanPathElem<'tcx>) @@ -398,13 +388,12 @@ pub enum LoanPathElem<'tcx> { LpInterior(Option, InteriorKind), } -fn closure_to_block(closure_id: LocalDefId, - tcx: TyCtxt<'_, '_, '_>) -> ast::NodeId { - let closure_id = tcx.hir().local_def_id_to_node_id(closure_id); +fn closure_to_block(closure_id: LocalDefId, tcx: TyCtxt<'_>) -> HirId { + let closure_id = tcx.hir().local_def_id_to_hir_id(closure_id); match tcx.hir().get(closure_id) { Node::Expr(expr) => match expr.node { hir::ExprKind::Closure(.., body_id, _, _) => { - tcx.hir().hir_to_node_id(body_id.hir_id) + body_id.hir_id } _ => { bug!("encountered non-closure id: {}", closure_id) @@ -414,17 +403,15 @@ fn closure_to_block(closure_id: LocalDefId, } } -impl<'a, 'tcx> LoanPath<'tcx> { - pub fn kill_scope(&self, bccx: &BorrowckCtxt<'a, 'tcx>) -> region::Scope { +impl LoanPath<'tcx> { + pub fn kill_scope(&self, bccx: &BorrowckCtxt<'_, 'tcx>) -> region::Scope { match self.kind { - LpVar(local_id) => { - let hir_id = bccx.tcx.hir().node_to_hir_id(local_id); + LpVar(hir_id) => { bccx.region_scope_tree.var_scope(hir_id.local_id) } LpUpvar(upvar_id) => { let block_id = closure_to_block(upvar_id.closure_expr_id, bccx.tcx); - let hir_id = bccx.tcx.hir().node_to_hir_id(block_id); - region::Scope { id: hir_id.local_id, data: region::ScopeData::Node } + region::Scope { id: block_id.local_id, data: region::ScopeData::Node } } LpDowncast(ref base, _) | LpExtend(ref base, ..) => base.kill_scope(bccx), @@ -565,7 +552,7 @@ pub enum bckerr_code<'tcx> { // Combination of an error code and the categorization of the expression // that caused it #[derive(Debug, PartialEq)] -pub struct BckError<'c, 'tcx: 'c> { +pub struct BckError<'c, 'tcx> { span: Span, cause: AliasableViolationKind, cmt: &'c mc::cmt_<'tcx>, @@ -587,7 +574,7 @@ pub enum MovedValueUseKind { /////////////////////////////////////////////////////////////////////////// // Misc -impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { +impl BorrowckCtxt<'_, 'tcx> { pub fn is_subregion_of(&self, r_sub: ty::Region<'tcx>, r_sup: ty::Region<'tcx>) @@ -682,8 +669,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { Origin::Ast); let need_note = match lp.ty.sty { ty::Closure(id, _) => { - let node_id = self.tcx.hir().as_local_node_id(id).unwrap(); - let hir_id = self.tcx.hir().node_to_hir_id(node_id); + let hir_id = self.tcx.hir().as_local_hir_id(id).unwrap(); if let Some((span, name)) = self.tables.closure_kind_origins().get(hir_id) { err.span_note(*span, &format!( "closure cannot be invoked more than once because \ @@ -713,10 +699,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } move_data::MoveExpr | - move_data::MovePat => (self.tcx.hir().span_by_hir_id(hir_id), ""), + move_data::MovePat => (self.tcx.hir().span(hir_id), ""), move_data::Captured => - (match self.tcx.hir().expect_expr_by_hir_id(hir_id).node { + (match self.tcx.hir().expect_expr(hir_id).node { hir::ExprKind::Closure(.., fn_decl_span, _) => fn_decl_span, ref r => bug!("Captured({:?}) maps to non-closure: {:?}", the_move.id, r), @@ -748,6 +734,19 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { }, moved_lp.ty)); } + if let (Some(CompilerDesugaringKind::ForLoop), Ok(snippet)) = ( + move_span.compiler_desugaring_kind(), + self.tcx.sess.source_map().span_to_snippet(move_span), + ) { + if !snippet.starts_with("&") { + err.span_suggestion( + move_span, + "consider borrowing this to avoid moving it into the for loop", + format!("&{}", snippet), + Applicability::MaybeIncorrect, + ); + } + } // Note: we used to suggest adding a `ref binding` or calling // `clone` but those suggestions have been removed because @@ -829,7 +828,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let mut db = self.cannot_assign(error_span, &descr, Origin::Ast); if let mc::NoteClosureEnv(upvar_id) = err.cmt.note { let hir_id = upvar_id.var_path.hir_id; - let sp = self.tcx.hir().span_by_hir_id(hir_id); + let sp = self.tcx.hir().span(hir_id); let fn_closure_msg = "`Fn` closures cannot capture their enclosing \ environment for modifications"; match (self.tcx.sess.source_map().span_to_snippet(sp), &err.cmt.cat) { @@ -888,8 +887,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.cannot_borrow_path_as_mutable(error_span, &descr, Origin::Ast) } BorrowViolation(euv::ClosureInvocation) => { - span_bug!(err.span, - "err_mutbl with a closure invocation"); + span_bug!(err.span, "err_mutbl with a closure invocation"); } }; @@ -898,8 +896,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { // to implement two traits for "one operator" is not very intuitive for // many programmers. if err.cmt.note == mc::NoteIndex { - let node_id = self.tcx.hir().hir_to_node_id(err.cmt.hir_id); - let node = self.tcx.hir().get(node_id); + let node = self.tcx.hir().get(err.cmt.hir_id); // This pattern probably always matches. if let Node::Expr( @@ -919,7 +916,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.note_immutability_blame( &mut db, err.cmt.immutability_blame(), - self.tcx.hir().hir_to_node_id(err.cmt.hir_id) + err.cmt.hir_id ); db.emit(); self.signal_error(); @@ -1024,8 +1021,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } if let ty::ReScope(scope) = *super_scope { - let node_id = scope.node_id(self.tcx, &self.region_scope_tree); - match self.tcx.hir().find(node_id) { + let hir_id = scope.hir_id(&self.region_scope_tree); + match self.tcx.hir().find(hir_id) { Some(Node::Stmt(_)) => { if *sub_scope != ty::ReStatic { db.note("consider using a `let` binding to increase its lifetime"); @@ -1087,7 +1084,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { BorrowViolation(euv::MatchDiscriminant) => { "cannot borrow data mutably" } - BorrowViolation(euv::ClosureInvocation) => { is_closure = true; "closure invocation" @@ -1121,7 +1117,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { "consider changing this closure to take self by mutable reference" }; let hir_id = self.tcx.hir().local_def_id_to_hir_id(id); - let help_span = self.tcx.hir().span_by_hir_id(hir_id); + let help_span = self.tcx.hir().span(hir_id); self.cannot_act_on_capture_in_sharable_fn(span, prefix, (help_span, help_msg), @@ -1135,7 +1131,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.note_immutability_blame( &mut err, blame, - self.tcx.hir().hir_to_node_id(cmt.hir_id) + cmt.hir_id ); if is_closure { @@ -1175,8 +1171,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - fn local_binding_mode(&self, node_id: ast::NodeId) -> ty::BindingMode { - let pat = match self.tcx.hir().get(node_id) { + fn local_binding_mode(&self, hir_id: hir::HirId) -> ty::BindingMode { + let pat = match self.tcx.hir().get(hir_id) { Node::Binding(pat) => pat, node => bug!("bad node for local: {:?}", node) }; @@ -1192,8 +1188,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - fn local_ty(&self, node_id: ast::NodeId) -> (Option<&hir::Ty>, bool) { - let parent = self.tcx.hir().get_parent_node(node_id); + fn local_ty(&self, hir_id: hir::HirId) -> (Option<&hir::Ty>, bool) { + let parent = self.tcx.hir().get_parent_node(hir_id); let parent_node = self.tcx.hir().get(parent); // The parent node is like a fn @@ -1201,7 +1197,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { // `nid`'s parent's `Body` let fn_body = self.tcx.hir().body(fn_like.body()); // Get the position of `node_id` in the arguments list - let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id); + let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.hir_id == hir_id); if let Some(i) = arg_pos { // The argument's `Ty` (Some(&fn_like.decl().inputs[i]), @@ -1217,17 +1213,17 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { fn note_immutability_blame(&self, db: &mut DiagnosticBuilder<'_>, blame: Option>, - error_node_id: ast::NodeId) { + error_hir_id: hir::HirId) { match blame { None => {} Some(ImmutabilityBlame::ClosureEnv(_)) => {} - Some(ImmutabilityBlame::ImmLocal(node_id)) => { - self.note_immutable_local(db, error_node_id, node_id) + Some(ImmutabilityBlame::ImmLocal(hir_id)) => { + self.note_immutable_local(db, error_hir_id, hir_id) } - Some(ImmutabilityBlame::LocalDeref(node_id)) => { - match self.local_binding_mode(node_id) { + Some(ImmutabilityBlame::LocalDeref(hir_id)) => { + match self.local_binding_mode(hir_id) { ty::BindByReference(..) => { - let let_span = self.tcx.hir().span(node_id); + let let_span = self.tcx.hir().span(hir_id); let suggestion = suggest_ref_mut(self.tcx, let_span); if let Some(replace_str) = suggestion { db.span_suggestion( @@ -1244,7 +1240,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } ty::BindByValue(..) => { - if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) { + if let (Some(local_ty), is_implicit_self) = self.local_ty(hir_id) { if let Some(msg) = self.suggest_mut_for_immutable(local_ty, is_implicit_self) { db.span_label(local_ty.span, msg); @@ -1254,12 +1250,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } Some(ImmutabilityBlame::AdtFieldDeref(_, field)) => { - let node_id = match self.tcx.hir().as_local_node_id(field.did) { - Some(node_id) => node_id, + let hir_id = match self.tcx.hir().as_local_hir_id(field.did) { + Some(hir_id) => hir_id, None => return }; - if let Node::Field(ref field) = self.tcx.hir().get(node_id) { + if let Node::Field(ref field) = self.tcx.hir().get(hir_id) { if let Some(msg) = self.suggest_mut_for_immutable(&field.ty, false) { db.span_label(field.ty.span, msg); } @@ -1273,12 +1269,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { // not a mutable reference) or to avoid borrowing altogether fn note_immutable_local(&self, db: &mut DiagnosticBuilder<'_>, - borrowed_node_id: ast::NodeId, - binding_node_id: ast::NodeId) { - let let_span = self.tcx.hir().span(binding_node_id); - if let ty::BindByValue(..) = self.local_binding_mode(binding_node_id) { + borrowed_hir_id: hir::HirId, + binding_hir_id: hir::HirId) { + let let_span = self.tcx.hir().span(binding_hir_id); + if let ty::BindByValue(..) = self.local_binding_mode(binding_hir_id) { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(let_span) { - let (ty, is_implicit_self) = self.local_ty(binding_node_id); + let (ty, is_implicit_self) = self.local_ty(binding_hir_id); if is_implicit_self && snippet != "self" { // avoid suggesting `mut &self`. return @@ -1291,7 +1287,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { }, )) = ty.map(|t| &t.node) { - let borrow_expr_id = self.tcx.hir().get_parent_node(borrowed_node_id); + let borrow_expr_id = self.tcx.hir().get_parent_node(borrowed_hir_id); db.span_suggestion( self.tcx.hir().span(borrow_expr_id), "consider removing the `&mut`, as it is an \ @@ -1364,7 +1360,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if *kind == ty::ClosureKind::Fn { let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id); - db.span_help(self.tcx.hir().span_by_hir_id(closure_hir_id), + db.span_help(self.tcx.hir().span(closure_hir_id), "consider changing this closure to take \ self by mutable reference"); } @@ -1398,7 +1394,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { out: &mut String) { match loan_path.kind { LpUpvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id: id }, closure_expr_id: _ }) => { - out.push_str(&self.tcx.hir().name_by_hir_id(id).as_str()); + out.push_str(&self.tcx.hir().name(id).as_str()); } LpVar(id) => { out.push_str(&self.tcx.hir().name(id).as_str()); @@ -1408,7 +1404,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { out.push('('); self.append_loan_path_to_string(&lp_base, out); out.push_str(DOWNCAST_PRINTED_OPERATOR); - out.push_str(&self.tcx.item_path_str(variant_def_id)); + out.push_str(&self.tcx.def_path_str(variant_def_id)); out.push(')'); } @@ -1445,7 +1441,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { out.push('('); self.append_autoderefd_loan_path_to_string(&lp_base, out); out.push_str(DOWNCAST_PRINTED_OPERATOR); - out.push_str(&self.tcx.item_path_str(variant_def_id)); + out.push_str(&self.tcx.def_path_str(variant_def_id)); out.push(')'); } @@ -1487,7 +1483,7 @@ impl DataFlowOperator for LoanDataFlowOperator { } } -impl<'tcx> fmt::Debug for InteriorKind { +impl fmt::Debug for InteriorKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { InteriorField(mc::FieldIndex(_, info)) => write!(f, "{}", info), @@ -1517,15 +1513,14 @@ impl<'tcx> fmt::Debug for LoanPath<'tcx> { LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath {hir_id: var_id}, closure_expr_id }) => { let s = ty::tls::with(|tcx| { - let var_node_id = tcx.hir().hir_to_node_id(var_id); - tcx.hir().node_to_string(var_node_id) + tcx.hir().node_to_string(var_id) }); write!(f, "$({} captured by id={:?})", s, closure_expr_id) } LpDowncast(ref lp, variant_def_id) => { let variant_str = if variant_def_id.is_local() { - ty::tls::with(|tcx| tcx.item_path_str(variant_def_id)) + ty::tls::with(|tcx| tcx.def_path_str(variant_def_id)) } else { format!("{:?}", variant_def_id) }; @@ -1547,20 +1542,19 @@ impl<'tcx> fmt::Display for LoanPath<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.kind { LpVar(id) => { - write!(f, "$({})", ty::tls::with(|tcx| tcx.hir().node_to_user_string(id))) + write!(f, "$({})", ty::tls::with(|tcx| tcx.hir().hir_to_user_string(id))) } LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath { hir_id }, closure_expr_id: _ }) => { let s = ty::tls::with(|tcx| { - let var_node_id = tcx.hir().hir_to_node_id(hir_id); - tcx.hir().node_to_string(var_node_id) + tcx.hir().node_to_string(hir_id) }); write!(f, "$({} captured by closure)", s) } LpDowncast(ref lp, variant_def_id) => { let variant_str = if variant_def_id.is_local() { - ty::tls::with(|tcx| tcx.item_path_str(variant_def_id)) + ty::tls::with(|tcx| tcx.def_path_str(variant_def_id)) } else { format!("{:?}", variant_def_id) }; diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 325d3559f0ab6..9feea64f18235 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -39,15 +39,15 @@ pub struct MoveData<'tcx> { pub path_assignments: RefCell>, } -pub struct FlowedMoveData<'a, 'tcx: 'a> { +pub struct FlowedMoveData<'tcx> { pub move_data: MoveData<'tcx>, - pub dfcx_moves: MoveDataFlow<'a, 'tcx>, + pub dfcx_moves: MoveDataFlow<'tcx>, // We could (and maybe should, for efficiency) combine both move // and assign data flow into one, but this way it's easier to // distinguish the bits that correspond to moves and assignments. - pub dfcx_assign: AssignDataFlow<'a, 'tcx> + pub dfcx_assign: AssignDataFlow<'tcx>, } /// Index into `MoveData.paths`, used like a pointer @@ -139,12 +139,12 @@ pub struct Assignment { #[derive(Clone, Copy)] pub struct MoveDataFlowOperator; -pub type MoveDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, MoveDataFlowOperator>; +pub type MoveDataFlow<'tcx> = DataFlowContext<'tcx, MoveDataFlowOperator>; #[derive(Clone, Copy)] pub struct AssignDataFlowOperator; -pub type AssignDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, AssignDataFlowOperator>; +pub type AssignDataFlow<'tcx> = DataFlowContext<'tcx, AssignDataFlowOperator>; fn loan_path_is_precise(loan_path: &LoanPath<'_>) -> bool { match loan_path.kind { @@ -167,7 +167,7 @@ fn loan_path_is_precise(loan_path: &LoanPath<'_>) -> bool { } } -impl<'a, 'tcx> MoveData<'tcx> { +impl MoveData<'tcx> { /// Returns `true` if there are no trackable assignments or moves /// in this move data -- that means that there is nothing that /// could cause a borrow error. @@ -223,8 +223,7 @@ impl<'a, 'tcx> MoveData<'tcx> { /// Returns the existing move path index for `lp`, if any, and otherwise adds a new index for /// `lp` and any of its base paths that do not yet have an index. - pub fn move_path(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - lp: Rc>) -> MovePathIndex { + pub fn move_path(&self, tcx: TyCtxt<'tcx>, lp: Rc>) -> MovePathIndex { if let Some(&index) = self.path_map.borrow().get(&lp) { return index; } @@ -311,10 +310,13 @@ impl<'a, 'tcx> MoveData<'tcx> { } /// Adds a new move entry for a move of `lp` that occurs at location `id` with kind `kind`. - pub fn add_move(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - orig_lp: Rc>, - id: hir::ItemLocalId, - kind: MoveKind) { + pub fn add_move( + &self, + tcx: TyCtxt<'tcx>, + orig_lp: Rc>, + id: hir::ItemLocalId, + kind: MoveKind, + ) { // Moving one union field automatically moves all its fields. Also move siblings of // all parent union fields, moves do not propagate upwards automatically. let mut lp = orig_lp.clone(); @@ -340,10 +342,13 @@ impl<'a, 'tcx> MoveData<'tcx> { self.add_move_helper(tcx, orig_lp, id, kind); } - fn add_move_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - lp: Rc>, - id: hir::ItemLocalId, - kind: MoveKind) { + fn add_move_helper( + &self, + tcx: TyCtxt<'tcx>, + lp: Rc>, + id: hir::ItemLocalId, + kind: MoveKind, + ) { debug!("add_move(lp={:?}, id={:?}, kind={:?})", lp, id, @@ -365,10 +370,13 @@ impl<'a, 'tcx> MoveData<'tcx> { /// Adds a new record for an assignment to `lp` that occurs at location `id` with the given /// `span`. - pub fn add_assignment(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - lp: Rc>, - assign_id: hir::ItemLocalId, - span: Span) { + pub fn add_assignment( + &self, + tcx: TyCtxt<'tcx>, + lp: Rc>, + assign_id: hir::ItemLocalId, + span: Span, + ) { // Assigning to one union field automatically assigns to all its fields. if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind { if let ty::Adt(adt_def, _) = base_lp.ty.sty { @@ -395,10 +403,13 @@ impl<'a, 'tcx> MoveData<'tcx> { self.add_assignment_helper(tcx, lp, assign_id, span); } - fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - lp: Rc>, - assign_id: hir::ItemLocalId, - span: Span) { + fn add_assignment_helper( + &self, + tcx: TyCtxt<'tcx>, + lp: Rc>, + assign_id: hir::ItemLocalId, + span: Span, + ) { debug!("add_assignment(lp={:?}, assign_id={:?}", lp, assign_id); let path_index = self.move_path(tcx, lp.clone()); @@ -427,10 +438,12 @@ impl<'a, 'tcx> MoveData<'tcx> { /// Moves are generated by moves and killed by assignments and /// scoping. Assignments are generated by assignment to variables and /// killed by scoping. See `README.md` for more details. - fn add_gen_kills(&self, - bccx: &BorrowckCtxt<'a, 'tcx>, - dfcx_moves: &mut MoveDataFlow<'_, '_>, - dfcx_assign: &mut AssignDataFlow<'_, '_>) { + fn add_gen_kills( + &self, + bccx: &BorrowckCtxt<'_, 'tcx>, + dfcx_moves: &mut MoveDataFlow<'_>, + dfcx_assign: &mut AssignDataFlow<'_>, + ) { for (i, the_move) in self.moves.borrow().iter().enumerate() { dfcx_moves.add_gen(the_move.id, i); } @@ -534,11 +547,13 @@ impl<'a, 'tcx> MoveData<'tcx> { ret } - fn kill_moves(&self, - path: MovePathIndex, - kill_id: hir::ItemLocalId, - kill_kind: KillFrom, - dfcx_moves: &mut MoveDataFlow<'_, '_>) { + fn kill_moves( + &self, + path: MovePathIndex, + kill_id: hir::ItemLocalId, + kill_kind: KillFrom, + dfcx_moves: &mut MoveDataFlow<'_>, + ) { // We can only perform kills for paths that refer to a unique location, // since otherwise we may kill a move from one location with an // assignment referring to another location. @@ -555,12 +570,13 @@ impl<'a, 'tcx> MoveData<'tcx> { } } -impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> { - pub fn new(move_data: MoveData<'tcx>, - bccx: &BorrowckCtxt<'a, 'tcx>, - cfg: &cfg::CFG, - body: &hir::Body) - -> FlowedMoveData<'a, 'tcx> { +impl<'tcx> FlowedMoveData<'tcx> { + pub fn new( + move_data: MoveData<'tcx>, + bccx: &BorrowckCtxt<'_, 'tcx>, + cfg: &cfg::CFG, + body: &hir::Body, + ) -> FlowedMoveData<'tcx> { let tcx = bccx.tcx; let mut dfcx_moves = diff --git a/src/librustc_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs deleted file mode 100644 index 60a9c18e95ee9..0000000000000 --- a/src/librustc_borrowck/borrowck/unused.rs +++ /dev/null @@ -1,116 +0,0 @@ -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use rustc::hir::{self, HirId}; -use rustc::lint::builtin::UNUSED_MUT; -use rustc::ty; -use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use errors::Applicability; -use std::slice; -use syntax::ptr::P; - -use crate::borrowck::BorrowckCtxt; - -pub fn check<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, body: &'tcx hir::Body) { - let mut used_mut = bccx.used_mut_nodes.borrow().clone(); - UsedMutFinder { - bccx, - set: &mut used_mut, - }.visit_expr(&body.value); - let mut cx = UnusedMutCx { bccx, used_mut }; - for arg in body.arguments.iter() { - cx.check_unused_mut_pat(slice::from_ref(&arg.pat)); - } - cx.visit_expr(&body.value); -} - -struct UsedMutFinder<'a, 'tcx: 'a> { - bccx: &'a BorrowckCtxt<'a, 'tcx>, - set: &'a mut FxHashSet, -} - -struct UnusedMutCx<'a, 'tcx: 'a> { - bccx: &'a BorrowckCtxt<'a, 'tcx>, - used_mut: FxHashSet, -} - -impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> { - fn check_unused_mut_pat(&self, pats: &[P]) { - let tcx = self.bccx.tcx; - let mut mutables: FxHashMap<_, Vec<_>> = Default::default(); - for p in pats { - p.each_binding(|_, hir_id, span, ident| { - // Skip anything that looks like `_foo` - if ident.as_str().starts_with("_") { - return; - } - - // Skip anything that looks like `&foo` or `&mut foo`, only look - // for by-value bindings - if let Some(&bm) = self.bccx.tables.pat_binding_modes().get(hir_id) { - match bm { - ty::BindByValue(hir::MutMutable) => {} - _ => return, - } - - mutables.entry(ident.name).or_default().push((hir_id, span)); - } else { - tcx.sess.delay_span_bug(span, "missing binding mode"); - } - }); - } - - for (_name, ids) in mutables { - // If any id for this name was used mutably then consider them all - // ok, so move on to the next - if ids.iter().any(|&(ref hir_id, _)| self.used_mut.contains(hir_id)) { - continue; - } - - let (hir_id, span) = ids[0]; - if span.compiler_desugaring_kind().is_some() { - // If the `mut` arises as part of a desugaring, we should ignore it. - continue; - } - - // Ok, every name wasn't used mutably, so issue a warning that this - // didn't need to be mutable. - let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); - tcx.struct_span_lint_hir(UNUSED_MUT, - hir_id, - span, - "variable does not need to be mutable") - .span_suggestion_short( - mut_span, - "remove this `mut`", - String::new(), - Applicability::MachineApplicable, - ) - .emit(); - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for UnusedMutCx<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::OnlyBodies(&self.bccx.tcx.hir()) - } - - fn visit_arm(&mut self, arm: &hir::Arm) { - self.check_unused_mut_pat(&arm.pats) - } - - fn visit_local(&mut self, local: &hir::Local) { - self.check_unused_mut_pat(slice::from_ref(&local.pat)); - } -} - -impl<'a, 'tcx> Visitor<'tcx> for UsedMutFinder<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::OnlyBodies(&self.bccx.tcx.hir()) - } - - fn visit_nested_body(&mut self, id: hir::BodyId) { - let def_id = self.bccx.tcx.hir().body_owner_def_id(id); - self.set.extend(self.bccx.tcx.borrowck(def_id).used_mut_nodes.iter().cloned()); - self.visit_body(self.bccx.tcx.hir().body(id)); - } -} diff --git a/src/librustc_borrowck/dataflow.rs b/src/librustc_borrowck/dataflow.rs index de2a3c4cb22a8..f5d311b35d738 100644 --- a/src/librustc_borrowck/dataflow.rs +++ b/src/librustc_borrowck/dataflow.rs @@ -19,7 +19,6 @@ use rustc::hir; use rustc::hir::intravisit; use rustc::hir::print as pprust; - #[derive(Copy, Clone, Debug)] pub enum EntryOrExit { Entry, @@ -27,8 +26,8 @@ pub enum EntryOrExit { } #[derive(Clone)] -pub struct DataFlowContext<'a, 'tcx: 'a, O> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub struct DataFlowContext<'tcx, O> { + tcx: TyCtxt<'tcx>, /// a name for the analysis using this dataflow instance analysis_name: &'static str, @@ -52,7 +51,6 @@ pub struct DataFlowContext<'a, 'tcx: 'a, O> { // `id_range`, there is a range of words equal to `words_per_id`. // So, to access the bits for any given id, you take a slice of // the full vector (see the method `compute_id_range()`). - /// bits generated as we exit the cfg node. Updated by `add_gen()`. gens: Vec, @@ -81,9 +79,9 @@ pub trait DataFlowOperator : BitwiseOperator { fn initial_value(&self) -> bool; } -struct PropagationContext<'a, 'b: 'a, 'tcx: 'b, O> { - dfcx: &'a mut DataFlowContext<'b, 'tcx, O>, - changed: bool +struct PropagationContext<'a, 'tcx, O> { + dfcx: &'a mut DataFlowContext<'tcx, O>, + changed: bool, } fn get_cfg_indices<'a>(id: hir::ItemLocalId, @@ -92,14 +90,14 @@ fn get_cfg_indices<'a>(id: hir::ItemLocalId, index.get(&id).map_or(&[], |v| &v[..]) } -impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { +impl<'tcx, O: DataFlowOperator> DataFlowContext<'tcx, O> { fn has_bitset_for_local_id(&self, n: hir::ItemLocalId) -> bool { assert!(n != hir::DUMMY_ITEM_LOCAL_ID); self.local_id_to_index.contains_key(&n) } } -impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O> { +impl<'tcx, O: DataFlowOperator> pprust::PpAnn for DataFlowContext<'tcx, O> { fn nested(&self, state: &mut pprust::State<'_>, nested: pprust::Nested) -> io::Result<()> { pprust::PpAnn::nested(self.tcx.hir(), state, nested) } @@ -225,13 +223,15 @@ pub enum KillFrom { Execution, } -impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, - analysis_name: &'static str, - body: Option<&hir::Body>, - cfg: &cfg::CFG, - oper: O, - bits_per_id: usize) -> DataFlowContext<'a, 'tcx, O> { +impl<'tcx, O: DataFlowOperator> DataFlowContext<'tcx, O> { + pub fn new( + tcx: TyCtxt<'tcx>, + analysis_name: &'static str, + body: Option<&hir::Body>, + cfg: &cfg::CFG, + oper: O, + bits_per_id: usize, + ) -> DataFlowContext<'tcx, O> { let usize_bits = mem::size_of::() * 8; let words_per_id = (bits_per_id + usize_bits - 1) / usize_bits; let num_nodes = cfg.graph.all_nodes().len(); @@ -500,8 +500,8 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { } } -impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> { -// ^^^^^^^^^^^^^ only needed for pretty printing +// N.B. `Clone + 'static` only needed for pretty printing. +impl<'tcx, O: DataFlowOperator + Clone + 'static> DataFlowContext<'tcx, O> { pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Body) { //! Performs the data flow analysis. @@ -538,7 +538,7 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> { } } -impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> { +impl PropagationContext<'_, 'tcx, O> { fn walk_cfg(&mut self, cfg: &cfg::CFG, nodes_po: &[CFGIndex], @@ -547,7 +547,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> { bits_to_string(in_out), self.dfcx.analysis_name); assert!(self.dfcx.bits_per_id > 0); - // Iterate over nodes in reverse postorder + // Iterate over nodes in reverse post-order. for &node_index in nodes_po.iter().rev() { let node = cfg.graph.node(node_index); debug!("DataFlowContext::walk_cfg idx={:?} id={:?} begin in_out={}", @@ -631,9 +631,9 @@ fn bits_to_string(words: &[usize]) -> String { } #[inline] -fn bitwise(out_vec: &mut [usize], - in_vec: &[usize], - op: &Op) -> bool { +fn bitwise(out_vec: &mut [usize], + in_vec: &[usize], + op: &Op) -> bool { assert_eq!(out_vec.len(), in_vec.len()); let mut changed = false; for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) { diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/error_codes.rs similarity index 100% rename from src/librustc_borrowck/diagnostics.rs rename to src/librustc_borrowck/error_codes.rs diff --git a/src/librustc_borrowck/graphviz.rs b/src/librustc_borrowck/graphviz.rs index 77056d4d3eb15..7a8a23ca76afc 100644 --- a/src/librustc_borrowck/graphviz.rs +++ b/src/librustc_borrowck/graphviz.rs @@ -30,11 +30,11 @@ impl Variant { } } -pub struct DataflowLabeller<'a, 'tcx: 'a> { +pub struct DataflowLabeller<'a, 'tcx> { pub inner: cfg_dot::LabelledCFG<'a, 'tcx>, pub variants: Vec, pub borrowck_ctxt: &'a BorrowckCtxt<'a, 'tcx>, - pub analysis_data: &'a borrowck::AnalysisData<'a, 'tcx>, + pub analysis_data: &'a borrowck::AnalysisData<'tcx>, } impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> { @@ -61,11 +61,14 @@ impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> { } } - fn build_set(&self, - e: EntryOrExit, - cfgidx: CFGIndex, - dfcx: &DataFlowContext<'a, 'tcx, O>, - mut to_lp: F) -> String where + fn build_set( + &self, + e: EntryOrExit, + cfgidx: CFGIndex, + dfcx: &DataFlowContext<'tcx, O>, + mut to_lp: F, + ) -> String + where F: FnMut(usize) -> Rc>, { let mut saw_some = false; diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index cf4669db87e5e..98e629ce046bb 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -2,7 +2,10 @@ #![allow(non_camel_case_types)] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] +#![feature(in_band_lifetimes)] #![feature(nll)] #![recursion_limit="256"] diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml index 841cf98164eb4..4ae8303c76d3c 100644 --- a/src/librustc_codegen_llvm/Cargo.toml +++ b/src/librustc_codegen_llvm/Cargo.toml @@ -13,7 +13,7 @@ test = false [dependencies] cc = "1.0.1" # Used to locate MSVC num_cpus = "1.0" -rustc-demangle = "0.1.4" +rustc-demangle = "0.1.15" rustc_llvm = { path = "../librustc_llvm" } memmap = "0.6" diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 49c9555a2c682..38d4b7e3f9d85 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -2,8 +2,8 @@ use crate::llvm::{self, AttributePlace}; use crate::builder::Builder; use crate::context::CodegenCx; use crate::type_::Type; -use crate::type_of::{LayoutLlvmExt, PointerKind}; use crate::value::Value; +use crate::type_of::{LayoutLlvmExt}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::mir::operand::OperandValue; @@ -11,9 +11,9 @@ use rustc_target::abi::call::ArgType; use rustc_codegen_ssa::traits::*; -use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, Abi as LayoutAbi}; -use rustc::ty::{self, Ty, Instance}; -use rustc::ty::layout; +use rustc_target::abi::{HasDataLayout, LayoutOf}; +use rustc::ty::{Ty}; +use rustc::ty::layout::{self}; use libc::c_uint; @@ -266,7 +266,8 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> { OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); } PassMode::Direct(_) | PassMode::Indirect(_, None) | PassMode::Cast(_) => { - self.store(bx, next(), dst); + let next_arg = next(); + self.store(bx, next_arg, dst); } } } @@ -293,23 +294,7 @@ impl ArgTypeMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } -pub trait FnTypeExt<'tcx> { - fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self; - fn new(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self; - fn new_vtable(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self; - fn new_internal( - cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>], - mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, - ) -> Self; - fn adjust_for_abi(&mut self, - cx: &CodegenCx<'ll, 'tcx>, - abi: Abi); +pub trait FnTypeLlvmExt<'tcx> { fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type; fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type; fn llvm_cconv(&self) -> llvm::CallConv; @@ -317,356 +302,7 @@ pub trait FnTypeExt<'tcx> { fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value); } -impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { - fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self { - let sig = instance.fn_sig(cx.tcx); - let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - FnType::new(cx, sig, &[]) - } - - fn new(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self { - FnType::new_internal(cx, sig, extra_args, |ty, _| { - ArgType::new(cx.layout_of(ty)) - }) - } - - fn new_vtable(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self { - FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| { - let mut layout = cx.layout_of(ty); - // Don't pass the vtable, it's not an argument of the virtual fn. - // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` - // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen - if arg_idx == Some(0) { - let fat_pointer_ty = if layout.is_unsized() { - // unsized `self` is passed as a pointer to `self` - // FIXME (mikeyhew) change this to use &own if it is ever added to the language - cx.tcx.mk_mut_ptr(layout.ty) - } else { - match layout.abi { - LayoutAbi::ScalarPair(..) => (), - _ => bug!("receiver type has unsupported layout: {:?}", layout) - } - - // In the case of Rc, we need to explicitly pass a *mut RcBox - // with a Scalar (not ScalarPair) ABI. This is a hack that is understood - // elsewhere in the compiler as a method on a `dyn Trait`. - // To get the type `*mut RcBox`, we just keep unwrapping newtypes until we - // get a built-in pointer type - let mut fat_pointer_layout = layout; - 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() - && !fat_pointer_layout.ty.is_region_ptr() - { - 'iter_fields: for i in 0..fat_pointer_layout.fields.count() { - let field_layout = fat_pointer_layout.field(cx, i); - - if !field_layout.is_zst() { - fat_pointer_layout = field_layout; - continue 'descend_newtypes - } - } - - bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout); - } - - fat_pointer_layout.ty - }; - - // we now have a type like `*mut RcBox` - // change its layout to that of `*mut ()`, a thin pointer, but keep the same type - // this is understood as a special case elsewhere in the compiler - let unit_pointer_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_unit()); - layout = cx.layout_of(unit_pointer_ty); - layout.ty = fat_pointer_ty; - } - ArgType::new(layout) - }) - } - - fn new_internal( - cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>], - mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, - ) -> Self { - debug!("FnType::new_internal({:?}, {:?})", sig, extra_args); - - use self::Abi::*; - let conv = match cx.sess().target.target.adjust_abi(sig.abi) { - RustIntrinsic | PlatformIntrinsic | - Rust | RustCall => Conv::C, - - // It's the ABI's job to select this, not ours. - System => bug!("system abi should be selected elsewhere"), - - Stdcall => Conv::X86Stdcall, - Fastcall => Conv::X86Fastcall, - Vectorcall => Conv::X86VectorCall, - Thiscall => Conv::X86ThisCall, - C => Conv::C, - Unadjusted => Conv::C, - Win64 => Conv::X86_64Win64, - SysV64 => Conv::X86_64SysV, - Aapcs => Conv::ArmAapcs, - PtxKernel => Conv::PtxKernel, - Msp430Interrupt => Conv::Msp430Intr, - X86Interrupt => Conv::X86Intr, - AmdGpuKernel => Conv::AmdGpuKernel, - - // These API constants ought to be more specific... - Cdecl => Conv::C, - }; - - let mut inputs = sig.inputs(); - let extra_args = if sig.abi == RustCall { - assert!(!sig.c_variadic && extra_args.is_empty()); - - match sig.inputs().last().unwrap().sty { - ty::Tuple(ref tupled_arguments) => { - inputs = &sig.inputs()[0..sig.inputs().len() - 1]; - tupled_arguments - } - _ => { - bug!("argument to function with \"rust-call\" ABI \ - is not a tuple"); - } - } - } else { - assert!(sig.c_variadic || extra_args.is_empty()); - extra_args - }; - - let target = &cx.sess().target.target; - let win_x64_gnu = target.target_os == "windows" - && target.arch == "x86_64" - && target.target_env == "gnu"; - let linux_s390x = target.target_os == "linux" - && target.arch == "s390x" - && target.target_env == "gnu"; - let linux_sparc64 = target.target_os == "linux" - && target.arch == "sparc64" - && target.target_env == "gnu"; - let rust_abi = match sig.abi { - RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true, - _ => false - }; - - // Handle safe Rust thin and fat pointers. - let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, - scalar: &layout::Scalar, - layout: TyLayout<'tcx, Ty<'tcx>>, - offset: Size, - is_return: bool| { - // Booleans are always an i1 that needs to be zero-extended. - if scalar.is_bool() { - attrs.set(ArgAttribute::ZExt); - return; - } - - // Only pointer types handled below. - if scalar.value != layout::Pointer { - return; - } - - if scalar.valid_range.start() < scalar.valid_range.end() { - if *scalar.valid_range.start() > 0 { - attrs.set(ArgAttribute::NonNull); - } - } - - if let Some(pointee) = layout.pointee_info_at(cx, offset) { - if let Some(kind) = pointee.safe { - attrs.pointee_size = pointee.size; - attrs.pointee_align = Some(pointee.align); - - // `Box` pointer parameters never alias because ownership is transferred - // `&mut` pointer parameters never alias other parameters, - // or mutable global data - // - // `&T` where `T` contains no `UnsafeCell` is immutable, - // and can be marked as both `readonly` and `noalias`, as - // LLVM's definition of `noalias` is based solely on memory - // dependencies rather than pointer equality - let no_alias = match kind { - PointerKind::Shared => false, - PointerKind::UniqueOwned => true, - PointerKind::Frozen | - PointerKind::UniqueBorrowed => !is_return - }; - if no_alias { - attrs.set(ArgAttribute::NoAlias); - } - - if kind == PointerKind::Frozen && !is_return { - attrs.set(ArgAttribute::ReadOnly); - } - } - } - }; - - // Store the index of the last argument. This is useful for working with - // C-compatible variadic arguments. - let last_arg_idx = if sig.inputs().is_empty() { - None - } else { - Some(sig.inputs().len() - 1) - }; - - let arg_of = |ty: Ty<'tcx>, arg_idx: Option| { - let is_return = arg_idx.is_none(); - let mut arg = mk_arg_type(ty, arg_idx); - if arg.layout.is_zst() { - // For some forsaken reason, x86_64-pc-windows-gnu - // doesn't ignore zero-sized struct arguments. - // The same is true for s390x-unknown-linux-gnu - // and sparc64-unknown-linux-gnu. - if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) { - arg.mode = PassMode::Ignore(IgnoreMode::Zst); - } - } - - // If this is a C-variadic function, this is not the return value, - // and there is one or more fixed arguments; ensure that the `VaList` - // is ignored as an argument. - if sig.c_variadic { - match (last_arg_idx, arg_idx) { - (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => { - let va_list_did = match cx.tcx.lang_items().va_list() { - Some(did) => did, - None => bug!("`va_list` lang item required for C-variadic functions"), - }; - match ty.sty { - ty::Adt(def, _) if def.did == va_list_did => { - // This is the "spoofed" `VaList`. Set the arguments mode - // so that it will be ignored. - arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs); - }, - _ => (), - } - } - _ => {} - } - } - - // FIXME(eddyb) other ABIs don't have logic for scalar pairs. - if !is_return && rust_abi { - if let layout::Abi::ScalarPair(ref a, ref b) = arg.layout.abi { - let mut a_attrs = ArgAttributes::new(); - let mut b_attrs = ArgAttributes::new(); - adjust_for_rust_scalar(&mut a_attrs, - a, - arg.layout, - Size::ZERO, - false); - adjust_for_rust_scalar(&mut b_attrs, - b, - arg.layout, - a.value.size(cx).align_to(b.value.align(cx).abi), - false); - arg.mode = PassMode::Pair(a_attrs, b_attrs); - return arg; - } - } - - if let layout::Abi::Scalar(ref scalar) = arg.layout.abi { - if let PassMode::Direct(ref mut attrs) = arg.mode { - adjust_for_rust_scalar(attrs, - scalar, - arg.layout, - Size::ZERO, - is_return); - } - } - - arg - }; - - let mut fn_ty = FnType { - ret: arg_of(sig.output(), None), - args: inputs.iter().chain(extra_args).enumerate().map(|(i, ty)| { - arg_of(ty, Some(i)) - }).collect(), - c_variadic: sig.c_variadic, - conv, - }; - fn_ty.adjust_for_abi(cx, sig.abi); - fn_ty - } - - fn adjust_for_abi(&mut self, - cx: &CodegenCx<'ll, 'tcx>, - abi: Abi) { - if abi == Abi::Unadjusted { return } - - if abi == Abi::Rust || abi == Abi::RustCall || - abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| { - if arg.is_ignore() { return; } - - match arg.layout.abi { - layout::Abi::Aggregate { .. } => {} - - // This is a fun case! The gist of what this is doing is - // that we want callers and callees to always agree on the - // ABI of how they pass SIMD arguments. If we were to *not* - // make these arguments indirect then they'd be immediates - // in LLVM, which means that they'd used whatever the - // appropriate ABI is for the callee and the caller. That - // means, for example, if the caller doesn't have AVX - // enabled but the callee does, then passing an AVX argument - // across this boundary would cause corrupt data to show up. - // - // This problem is fixed by unconditionally passing SIMD - // arguments through memory between callers and callees - // which should get them all to agree on ABI regardless of - // target feature sets. Some more information about this - // issue can be found in #44367. - // - // Note that the platform intrinsic ABI is exempt here as - // that's how we connect up to LLVM and it's unstable - // anyway, we control all calls to it in libstd. - layout::Abi::Vector { .. } - if abi != Abi::PlatformIntrinsic && - cx.sess().target.target.options.simd_types_indirect => - { - arg.make_indirect(); - return - } - - _ => return - } - - let size = arg.layout.size; - if arg.layout.is_unsized() || size > layout::Pointer.size(cx) { - arg.make_indirect(); - } else { - // We want to pass small aggregates as immediates, but using - // a LLVM aggregate type for this leads to bad optimizations, - // so we pick an appropriately sized integer type instead. - arg.cast_to(Reg { - kind: RegKind::Integer, - size - }); - } - }; - fixup(&mut self.ret); - for arg in &mut self.args { - fixup(arg); - } - if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { - attrs.set(ArgAttribute::StructRet); - } - return; - } - - if let Err(msg) = self.adjust_for_cabi(cx, abi) { - cx.sess().fatal(&msg); - } - } - +impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> { fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type { let args_capacity: usize = self.args.iter().map(|arg| if arg.pad.is_some() { 1 } else { 0 } + @@ -835,22 +471,6 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { } } -impl AbiMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn new_fn_type(&self, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>> { - FnType::new(&self, sig, extra_args) - } - fn new_vtable( - &self, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>] - ) -> FnType<'tcx, Ty<'tcx>> { - FnType::new_vtable(&self, sig, extra_args) - } - fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>> { - FnType::of_instance(&self, instance) - } -} - impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { fn apply_attrs_callsite( &mut self, @@ -859,4 +479,8 @@ impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { ) { ty.apply_attrs_callsite(self, callsite) } + + fn get_param(&self, index: usize) -> Self::Value { + llvm::get_param(self.llfn(), index as c_uint) + } } diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs index 1fe020561dde1..02a05fd110200 100644 --- a/src/librustc_codegen_llvm/allocator.rs +++ b/src/librustc_codegen_llvm/allocator.rs @@ -9,7 +9,7 @@ use rustc_allocator::{ALLOCATOR_METHODS, AllocatorTy}; use crate::ModuleLlvm; use crate::llvm::{self, False, True}; -pub(crate) unsafe fn codegen(tcx: TyCtxt<'_, '_, '_>, mods: &mut ModuleLlvm, kind: AllocatorKind) { +pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: AllocatorKind) { let llcx = &*mods.llcx; let llmod = mods.llmod(); let usize = match &tcx.sess.target.target.target_pointer_width[..] { diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs index 4427308f4155d..81acc16b7abec 100644 --- a/src/librustc_codegen_llvm/asm.rs +++ b/src/librustc_codegen_llvm/asm.rs @@ -10,7 +10,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::mir::operand::OperandValue; -use std::ffi::CString; +use std::ffi::{CStr, CString}; use libc::{c_uint, c_char}; @@ -73,7 +73,8 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { let asm = CString::new(ia.asm.as_str().as_bytes()).unwrap(); let constraint_cstr = CString::new(all_constraints).unwrap(); - let r = self.inline_asm_call( + let r = inline_asm_call( + self, &asm, &constraint_cstr, &inputs, @@ -111,7 +112,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } -impl AsmMethods<'tcx> for CodegenCx<'ll, 'tcx> { +impl AsmMethods for CodegenCx<'ll, 'tcx> { fn codegen_global_asm(&self, ga: &hir::GlobalAsm) { let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap(); unsafe { @@ -119,3 +120,46 @@ impl AsmMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } } + +fn inline_asm_call( + bx: &mut Builder<'a, 'll, 'tcx>, + asm: &CStr, + cons: &CStr, + inputs: &[&'ll Value], + output: &'ll llvm::Type, + volatile: bool, + alignstack: bool, + dia: ::syntax::ast::AsmDialect, +) -> Option<&'ll Value> { + let volatile = if volatile { llvm::True } + else { llvm::False }; + let alignstack = if alignstack { llvm::True } + else { llvm::False }; + + let argtys = inputs.iter().map(|v| { + debug!("Asm Input Type: {:?}", *v); + bx.cx.val_ty(*v) + }).collect::>(); + + debug!("Asm Output Type: {:?}", output); + let fty = bx.cx.type_func(&argtys[..], output); + unsafe { + // Ask LLVM to verify that the constraints are well-formed. + let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr()); + debug!("Constraint verification result: {:?}", constraints_ok); + if constraints_ok { + let v = llvm::LLVMRustInlineAsm( + fty, + asm.as_ptr(), + cons.as_ptr(), + volatile, + alignstack, + llvm::AsmDialect::from_generic(dia), + ); + Some(bx.call(v, inputs, None)) + } else { + // LLVM has detected an issue with our constraints, bail out + None + } + } +} diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 71e7535313f77..94abf1796d366 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -10,7 +10,6 @@ use rustc::ty::{self, TyCtxt, PolyFnSig}; use rustc::ty::layout::HasTyCtxt; use rustc::ty::query::Providers; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_data_structures::sync::Lrc; use rustc_data_structures::fx::FxHashMap; use rustc_target::spec::PanicStrategy; use rustc_codegen_ssa::traits::*; @@ -77,9 +76,15 @@ pub fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { if cx.sess().instrument_mcount() { // Similar to `clang -pg` behavior. Handled by the // `post-inline-ee-instrument` LLVM pass. + + // The function name varies on platforms. + // See test/CodeGen/mcount.c in clang. + let mcount_name = CString::new( + cx.sess().target.target.options.target_mcount.as_str().as_bytes()).unwrap(); + llvm::AddFunctionAttrStringValue( llfn, llvm::AttributePlace::Function, - const_cstr!("instrument-function-entry-inlined"), const_cstr!("mcount")); + const_cstr!("instrument-function-entry-inlined"), &mcount_name); } } @@ -97,8 +102,8 @@ pub fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { return } - // probestack doesn't play nice either with pgo-gen. - if cx.sess().opts.debugging_opts.pgo_gen.is_some() { + // probestack doesn't play nice either with `-C profile-generate`. + if cx.sess().opts.cg.profile_generate.enabled() { return; } @@ -314,13 +319,13 @@ pub fn provide(providers: &mut Providers<'_>) { if tcx.sess.opts.actually_rustdoc { // rustdoc needs to be able to document functions that use all the features, so // whitelist them all - Lrc::new(llvm_util::all_known_features() - .map(|(a, b)| (a.to_string(), b.map(|s| s.to_string()))) + tcx.arena.alloc(llvm_util::all_known_features() + .map(|(a, b)| (a.to_string(), b)) .collect()) } else { - Lrc::new(llvm_util::target_feature_whitelist(tcx.sess) + tcx.arena.alloc(llvm_util::target_feature_whitelist(tcx.sess) .iter() - .map(|&(a, b)| (a.to_string(), b.map(|s| s.to_string()))) + .map(|&(a, b)| (a.to_string(), b)) .collect()) } }; @@ -358,11 +363,11 @@ pub fn provide_extern(providers: &mut Providers<'_>) { })); } - Lrc::new(ret) + tcx.arena.alloc(ret) }; } -fn wasm_import_module(tcx: TyCtxt<'_, '_, '_>, id: DefId) -> Option { +fn wasm_import_module(tcx: TyCtxt<'_>, id: DefId) -> Option { tcx.wasm_import_module_map(id.krate) .get(&id) .map(|s| CString::new(&s[..]).unwrap()) diff --git a/src/librustc_codegen_llvm/back/archive.rs b/src/librustc_codegen_llvm/back/archive.rs index 3fb9d4b5b776b..e0e26e9af2537 100644 --- a/src/librustc_codegen_llvm/back/archive.rs +++ b/src/librustc_codegen_llvm/back/archive.rs @@ -7,14 +7,13 @@ use std::path::{Path, PathBuf}; use std::ptr; use std::str; -use crate::back::bytecode::RLIB_BYTECODE_EXTENSION; use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind}; -use crate::metadata::METADATA_FILENAME; -use rustc_codegen_ssa::back::archive::find_library; +use rustc_codegen_ssa::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION}; +use rustc_codegen_ssa::back::archive::{ArchiveBuilder, find_library}; use rustc::session::Session; -pub struct ArchiveConfig<'a> { +struct ArchiveConfig<'a> { pub sess: &'a Session, pub dst: PathBuf, pub src: Option, @@ -23,7 +22,7 @@ pub struct ArchiveConfig<'a> { /// Helper for adding many files to an archive. #[must_use = "must call build() to finish building the archive"] -pub struct ArchiveBuilder<'a> { +pub struct LlvmArchiveBuilder<'a> { config: ArchiveConfig<'a>, removals: Vec, additions: Vec, @@ -49,11 +48,26 @@ fn is_relevant_child(c: &Child<'_>) -> bool { } } -impl<'a> ArchiveBuilder<'a> { +fn archive_config<'a>(sess: &'a Session, + output: &Path, + input: Option<&Path>) -> ArchiveConfig<'a> { + use rustc_codegen_ssa::back::link::archive_search_paths; + ArchiveConfig { + sess, + dst: output.to_path_buf(), + src: input.map(|p| p.to_path_buf()), + lib_search_paths: archive_search_paths(sess), + } +} + +impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { /// Creates a new static archive, ready for modifying the archive specified /// by `config`. - pub fn new(config: ArchiveConfig<'a>) -> ArchiveBuilder<'a> { - ArchiveBuilder { + fn new(sess: &'a Session, + output: &Path, + input: Option<&Path>) -> LlvmArchiveBuilder<'a> { + let config = archive_config(sess, output, input); + LlvmArchiveBuilder { config, removals: Vec::new(), additions: Vec::new(), @@ -63,12 +77,12 @@ impl<'a> ArchiveBuilder<'a> { } /// Removes a file from this archive - pub fn remove_file(&mut self, file: &str) { + fn remove_file(&mut self, file: &str) { self.removals.push(file.to_string()); } /// Lists all files in an archive - pub fn src_files(&mut self) -> Vec { + fn src_files(&mut self) -> Vec { if self.src_archive().is_none() { return Vec::new() } @@ -84,18 +98,9 @@ impl<'a> ArchiveBuilder<'a> { .collect() } - fn src_archive(&mut self) -> Option<&ArchiveRO> { - if let Some(ref a) = self.src_archive { - return a.as_ref() - } - let src = self.config.src.as_ref()?; - self.src_archive = Some(ArchiveRO::open(src).ok()); - self.src_archive.as_ref().unwrap().as_ref() - } - /// Adds all of the contents of a native library to this archive. This will /// search in the relevant locations for a library named `name`. - pub fn add_native_library(&mut self, name: &str) { + fn add_native_library(&mut self, name: &str) { let location = find_library(name, &self.config.lib_search_paths, self.config.sess); self.add_archive(&location, |_| false).unwrap_or_else(|e| { @@ -109,7 +114,7 @@ impl<'a> ArchiveBuilder<'a> { /// /// This ignores adding the bytecode from the rlib, and if LTO is enabled /// then the object file also isn't added. - pub fn add_rlib(&mut self, + fn add_rlib(&mut self, rlib: &Path, name: &str, lto: bool, @@ -141,23 +146,8 @@ impl<'a> ArchiveBuilder<'a> { }) } - fn add_archive(&mut self, archive: &Path, skip: F) - -> io::Result<()> - where F: FnMut(&str) -> bool + 'static - { - let archive = match ArchiveRO::open(archive) { - Ok(ar) => ar, - Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), - }; - self.additions.push(Addition::Archive { - archive, - skip: Box::new(skip), - }); - Ok(()) - } - /// Adds an arbitrary file to this archive - pub fn add_file(&mut self, file: &Path) { + fn add_file(&mut self, file: &Path) { let name = file.file_name().unwrap().to_str().unwrap(); self.additions.push(Addition::File { path: file.to_path_buf(), @@ -167,13 +157,13 @@ impl<'a> ArchiveBuilder<'a> { /// Indicate that the next call to `build` should update all symbols in /// the archive (equivalent to running 'ar s' over it). - pub fn update_symbols(&mut self) { + fn update_symbols(&mut self) { self.should_update_symbols = true; } /// Combine the provided files, rlibs, and native libraries into a single /// `Archive`. - pub fn build(&mut self) { + fn build(mut self) { let kind = self.llvm_archive_kind().unwrap_or_else(|kind| self.config.sess.fatal(&format!("Don't know how to build archive of type: {}", kind))); @@ -182,6 +172,32 @@ impl<'a> ArchiveBuilder<'a> { } } +} + +impl<'a> LlvmArchiveBuilder<'a> { + fn src_archive(&mut self) -> Option<&ArchiveRO> { + if let Some(ref a) = self.src_archive { + return a.as_ref() + } + let src = self.config.src.as_ref()?; + self.src_archive = Some(ArchiveRO::open(src).ok()); + self.src_archive.as_ref().unwrap().as_ref() + } + + fn add_archive(&mut self, archive: &Path, skip: F) + -> io::Result<()> + where F: FnMut(&str) -> bool + 'static + { + let archive = match ArchiveRO::open(archive) { + Ok(ar) => ar, + Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), + }; + self.additions.push(Addition::Archive { + archive, + skip: Box::new(skip), + }); + Ok(()) + } fn llvm_archive_kind(&self) -> Result { let kind = &*self.config.sess.target.target.options.archive_format; diff --git a/src/librustc_codegen_llvm/back/bytecode.rs b/src/librustc_codegen_llvm/back/bytecode.rs index 8b288c45336b7..397cdecbb6f77 100644 --- a/src/librustc_codegen_llvm/back/bytecode.rs +++ b/src/librustc_codegen_llvm/back/bytecode.rs @@ -37,8 +37,6 @@ pub const RLIB_BYTECODE_OBJECT_MAGIC: &[u8] = b"RUST_OBJECT"; // The version number this compiler will write to bytecode objects in rlibs pub const RLIB_BYTECODE_OBJECT_VERSION: u8 = 2; -pub const RLIB_BYTECODE_EXTENSION: &str = "bc.z"; - pub fn encode(identifier: &str, bytecode: &[u8]) -> Vec { let mut encoded = Vec::new(); diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs deleted file mode 100644 index 6c175ff4247ca..0000000000000 --- a/src/librustc_codegen_llvm/back/link.rs +++ /dev/null @@ -1,1498 +0,0 @@ -use super::archive::{ArchiveBuilder, ArchiveConfig}; -use super::bytecode::RLIB_BYTECODE_EXTENSION; -use super::rpath::RPathConfig; -use super::rpath; -use crate::back::wasm; -use crate::metadata::METADATA_FILENAME; -use crate::context::get_reloc_model; -use crate::llvm; -use rustc_codegen_ssa::back::linker::Linker; -use rustc_codegen_ssa::back::link::{remove, ignored_for_lto, each_linked_rlib, linker_and_flavor, - get_linker}; -use rustc_codegen_ssa::back::command::Command; -use rustc::session::config::{self, DebugInfo, OutputFilenames, OutputType, PrintRequest}; -use rustc::session::config::{RUST_CGU_EXT, Lto, Sanitizer}; -use rustc::session::filesearch; -use rustc::session::search_paths::PathKind; -use rustc::session::Session; -use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind}; -use rustc::middle::dependency_format::Linkage; -use rustc_codegen_ssa::CodegenResults; -use rustc::util::common::time; -use rustc_fs_util::fix_windows_verbatim_for_gcc; -use rustc::hir::def_id::CrateNum; -use tempfile::{Builder as TempFileBuilder, TempDir}; -use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor}; -use rustc_data_structures::fx::FxHashSet; - -use std::ascii; -use std::char; -use std::env; -use std::fmt; -use std::fs; -use std::io; -use std::iter; -use std::path::{Path, PathBuf}; -use std::process::{Output, Stdio}; -use std::str; -use syntax::attr; - -pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default_output_for_target, - invalid_output_for_target, filename_for_metadata, - out_filename, check_file_is_writeable}; - - -/// Performs the linkage portion of the compilation phase. This will generate all -/// of the requested outputs for this compilation session. -pub(crate) fn link_binary(sess: &Session, - codegen_results: &CodegenResults, - outputs: &OutputFilenames, - crate_name: &str) -> Vec { - let mut out_filenames = Vec::new(); - for &crate_type in sess.crate_types.borrow().iter() { - // Ignore executable crates if we have -Z no-codegen, as they will error. - let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); - if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) && - !output_metadata && - crate_type == config::CrateType::Executable { - continue; - } - - if invalid_output_for_target(sess, crate_type) { - bug!("invalid output type `{:?}` for target os `{}`", - crate_type, sess.opts.target_triple); - } - let out_files = link_binary_output(sess, - codegen_results, - crate_type, - outputs, - crate_name); - out_filenames.extend(out_files); - } - - // Remove the temporary object file and metadata if we aren't saving temps - if !sess.opts.cg.save_temps { - if sess.opts.output_types.should_codegen() && !preserve_objects_for_their_debuginfo(sess) { - for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { - remove(sess, obj); - } - } - for obj in codegen_results.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) { - remove(sess, obj); - } - if let Some(ref obj) = codegen_results.metadata_module.object { - remove(sess, obj); - } - if let Some(ref allocator) = codegen_results.allocator_module { - if let Some(ref obj) = allocator.object { - remove(sess, obj); - } - if let Some(ref bc) = allocator.bytecode_compressed { - remove(sess, bc); - } - } - } - - out_filenames -} - -/// Returns a boolean indicating whether we should preserve the object files on -/// the filesystem for their debug information. This is often useful with -/// split-dwarf like schemes. -fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { - // If the objects don't have debuginfo there's nothing to preserve. - if sess.opts.debuginfo == DebugInfo::None { - return false - } - - // If we're only producing artifacts that are archives, no need to preserve - // the objects as they're losslessly contained inside the archives. - let output_linked = sess.crate_types.borrow() - .iter() - .any(|&x| x != config::CrateType::Rlib && x != config::CrateType::Staticlib); - if !output_linked { - return false - } - - // If we're on OSX then the equivalent of split dwarf is turned on by - // default. The final executable won't actually have any debug information - // except it'll have pointers to elsewhere. Historically we've always run - // `dsymutil` to "link all the dwarf together" but this is actually sort of - // a bummer for incremental compilation! (the whole point of split dwarf is - // that you don't do this sort of dwarf link). - // - // Basically as a result this just means that if we're on OSX and we're - // *not* running dsymutil then the object files are the only source of truth - // for debug information, so we must preserve them. - if sess.target.target.options.is_like_osx { - match sess.opts.debugging_opts.run_dsymutil { - // dsymutil is not being run, preserve objects - Some(false) => return true, - - // dsymutil is being run, no need to preserve the objects - Some(true) => return false, - - // The default historical behavior was to always run dsymutil, so - // we're preserving that temporarily, but we're likely to switch the - // default soon. - None => return false, - } - } - - false -} - -fn link_binary_output(sess: &Session, - codegen_results: &CodegenResults, - crate_type: config::CrateType, - outputs: &OutputFilenames, - crate_name: &str) -> Vec { - for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { - check_file_is_writeable(obj, sess); - } - - let mut out_filenames = vec![]; - - if outputs.outputs.contains_key(&OutputType::Metadata) { - let out_filename = filename_for_metadata(sess, crate_name, outputs); - // To avoid races with another rustc process scanning the output directory, - // we need to write the file somewhere else and atomically move it to its - // final destination, with a `fs::rename` call. In order for the rename to - // always succeed, the temporary file needs to be on the same filesystem, - // which is why we create it inside the output directory specifically. - let metadata_tmpdir = TempFileBuilder::new() - .prefix("rmeta") - .tempdir_in(out_filename.parent().unwrap()) - .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err))); - let metadata = emit_metadata(sess, codegen_results, &metadata_tmpdir); - if let Err(e) = fs::rename(metadata, &out_filename) { - sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); - } - out_filenames.push(out_filename); - } - - let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err| - sess.fatal(&format!("couldn't create a temp dir: {}", err))); - - if outputs.outputs.should_codegen() { - let out_filename = out_filename(sess, crate_type, outputs, crate_name); - match crate_type { - config::CrateType::Rlib => { - link_rlib(sess, - codegen_results, - RlibFlavor::Normal, - &out_filename, - &tmpdir).build(); - } - config::CrateType::Staticlib => { - link_staticlib(sess, codegen_results, &out_filename, &tmpdir); - } - _ => { - link_natively(sess, crate_type, &out_filename, codegen_results, tmpdir.path()); - } - } - out_filenames.push(out_filename); - } - - if sess.opts.cg.save_temps { - let _ = tmpdir.into_path(); - } - - out_filenames -} - -fn archive_search_paths(sess: &Session) -> Vec { - sess.target_filesearch(PathKind::Native).search_path_dirs() -} - -fn archive_config<'a>(sess: &'a Session, - output: &Path, - input: Option<&Path>) -> ArchiveConfig<'a> { - ArchiveConfig { - sess, - dst: output.to_path_buf(), - src: input.map(|p| p.to_path_buf()), - lib_search_paths: archive_search_paths(sess), - } -} - -/// We use a temp directory here to avoid races between concurrent rustc processes, -/// such as builds in the same directory using the same filename for metadata while -/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a -/// directory being searched for `extern crate` (observing an incomplete file). -/// The returned path is the temporary file containing the complete metadata. -fn emit_metadata<'a>( - sess: &'a Session, - codegen_results: &CodegenResults, - tmpdir: &TempDir -) -> PathBuf { - let out_filename = tmpdir.path().join(METADATA_FILENAME); - let result = fs::write(&out_filename, &codegen_results.metadata.raw_data); - - if let Err(e) = result { - sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); - } - - out_filename -} - -enum RlibFlavor { - Normal, - StaticlibBase, -} - -// Create an 'rlib' -// -// An rlib in its current incarnation is essentially a renamed .a file. The -// rlib primarily contains the object file of the crate, but it also contains -// all of the object files from native libraries. This is done by unzipping -// native libraries and inserting all of the contents into this archive. -fn link_rlib<'a>(sess: &'a Session, - codegen_results: &CodegenResults, - flavor: RlibFlavor, - out_filename: &Path, - tmpdir: &TempDir) -> ArchiveBuilder<'a> { - info!("preparing rlib to {:?}", out_filename); - let mut ab = ArchiveBuilder::new(archive_config(sess, out_filename, None)); - - for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { - ab.add_file(obj); - } - - // Note that in this loop we are ignoring the value of `lib.cfg`. That is, - // we may not be configured to actually include a static library if we're - // adding it here. That's because later when we consume this rlib we'll - // decide whether we actually needed the static library or not. - // - // To do this "correctly" we'd need to keep track of which libraries added - // which object files to the archive. We don't do that here, however. The - // #[link(cfg(..))] feature is unstable, though, and only intended to get - // liblibc working. In that sense the check below just indicates that if - // there are any libraries we want to omit object files for at link time we - // just exclude all custom object files. - // - // Eventually if we want to stabilize or flesh out the #[link(cfg(..))] - // feature then we'll need to figure out how to record what objects were - // loaded from the libraries found here and then encode that into the - // metadata of the rlib we're generating somehow. - for lib in codegen_results.crate_info.used_libraries.iter() { - match lib.kind { - NativeLibraryKind::NativeStatic => {} - NativeLibraryKind::NativeStaticNobundle | - NativeLibraryKind::NativeFramework | - NativeLibraryKind::NativeUnknown => continue, - } - if let Some(name) = lib.name { - ab.add_native_library(&name.as_str()); - } - } - - // After adding all files to the archive, we need to update the - // symbol table of the archive. - ab.update_symbols(); - - // Note that it is important that we add all of our non-object "magical - // files" *after* all of the object files in the archive. The reason for - // this is as follows: - // - // * When performing LTO, this archive will be modified to remove - // objects from above. The reason for this is described below. - // - // * When the system linker looks at an archive, it will attempt to - // determine the architecture of the archive in order to see whether its - // linkable. - // - // The algorithm for this detection is: iterate over the files in the - // archive. Skip magical SYMDEF names. Interpret the first file as an - // object file. Read architecture from the object file. - // - // * As one can probably see, if "metadata" and "foo.bc" were placed - // before all of the objects, then the architecture of this archive would - // not be correctly inferred once 'foo.o' is removed. - // - // Basically, all this means is that this code should not move above the - // code above. - match flavor { - RlibFlavor::Normal => { - // Instead of putting the metadata in an object file section, rlibs - // contain the metadata in a separate file. - ab.add_file(&emit_metadata(sess, codegen_results, tmpdir)); - - // For LTO purposes, the bytecode of this library is also inserted - // into the archive. - for bytecode in codegen_results - .modules - .iter() - .filter_map(|m| m.bytecode_compressed.as_ref()) - { - ab.add_file(bytecode); - } - - // After adding all files to the archive, we need to update the - // symbol table of the archive. This currently dies on macOS (see - // #11162), and isn't necessary there anyway - if !sess.target.target.options.is_like_osx { - ab.update_symbols(); - } - } - - RlibFlavor::StaticlibBase => { - let obj = codegen_results.allocator_module - .as_ref() - .and_then(|m| m.object.as_ref()); - if let Some(obj) = obj { - ab.add_file(obj); - } - } - } - - ab -} - -// Create a static archive -// -// This is essentially the same thing as an rlib, but it also involves adding -// all of the upstream crates' objects into the archive. This will slurp in -// all of the native libraries of upstream dependencies as well. -// -// Additionally, there's no way for us to link dynamic libraries, so we warn -// about all dynamic library dependencies that they're not linked in. -// -// There's no need to include metadata in a static archive, so ensure to not -// link in the metadata object file (and also don't prepare the archive with a -// metadata file). -fn link_staticlib(sess: &Session, - codegen_results: &CodegenResults, - out_filename: &Path, - tempdir: &TempDir) { - let mut ab = link_rlib(sess, - codegen_results, - RlibFlavor::StaticlibBase, - out_filename, - tempdir); - let mut all_native_libs = vec![]; - - let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| { - let name = &codegen_results.crate_info.crate_name[&cnum]; - let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; - - // Here when we include the rlib into our staticlib we need to make a - // decision whether to include the extra object files along the way. - // These extra object files come from statically included native - // libraries, but they may be cfg'd away with #[link(cfg(..))]. - // - // This unstable feature, though, only needs liblibc to work. The only - // use case there is where musl is statically included in liblibc.rlib, - // so if we don't want the included version we just need to skip it. As - // a result the logic here is that if *any* linked library is cfg'd away - // we just skip all object files. - // - // Clearly this is not sufficient for a general purpose feature, and - // we'd want to read from the library's metadata to determine which - // object files come from where and selectively skip them. - let skip_object_files = native_libs.iter().any(|lib| { - lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) - }); - ab.add_rlib(path, - &name.as_str(), - are_upstream_rust_objects_already_included(sess) && - !ignored_for_lto(sess, &codegen_results.crate_info, cnum), - skip_object_files).unwrap(); - - all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned()); - }); - if let Err(e) = res { - sess.fatal(&e); - } - - ab.update_symbols(); - ab.build(); - - if !all_native_libs.is_empty() { - if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) { - print_native_static_libs(sess, &all_native_libs); - } - } -} - -fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) { - let lib_args: Vec<_> = all_native_libs.iter() - .filter(|l| relevant_lib(sess, l)) - .filter_map(|lib| { - let name = lib.name?; - match lib.kind { - NativeLibraryKind::NativeStaticNobundle | - NativeLibraryKind::NativeUnknown => { - if sess.target.target.options.is_like_msvc { - Some(format!("{}.lib", name)) - } else { - Some(format!("-l{}", name)) - } - }, - NativeLibraryKind::NativeFramework => { - // ld-only syntax, since there are no frameworks in MSVC - Some(format!("-framework {}", name)) - }, - // These are included, no need to print them - NativeLibraryKind::NativeStatic => None, - } - }) - .collect(); - if !lib_args.is_empty() { - sess.note_without_error("Link against the following native artifacts when linking \ - against this static library. The order and any duplication \ - can be significant on some platforms."); - // Prefix for greppability - sess.note_without_error(&format!("native-static-libs: {}", &lib_args.join(" "))); - } -} - -fn get_file_path(sess: &Session, name: &str) -> PathBuf { - let fs = sess.target_filesearch(PathKind::Native); - let file_path = fs.get_lib_path().join(name); - if file_path.exists() { - return file_path - } - for search_path in fs.search_paths() { - let file_path = search_path.dir.join(name); - if file_path.exists() { - return file_path - } - } - PathBuf::from(name) -} - -// Create a dynamic library or executable -// -// This will invoke the system linker/cc to create the resulting file. This -// links to all upstream files as well. -fn link_natively(sess: &Session, - crate_type: config::CrateType, - out_filename: &Path, - codegen_results: &CodegenResults, - tmpdir: &Path) { - info!("preparing {:?} to {:?}", crate_type, out_filename); - let (linker, flavor) = linker_and_flavor(sess); - - // The invocations of cc share some flags across platforms - let (pname, mut cmd) = get_linker(sess, &linker, flavor); - - if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) { - cmd.args(args); - } - if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) { - if sess.crt_static() { - cmd.args(args); - } - } - if let Some(ref args) = sess.opts.debugging_opts.pre_link_args { - cmd.args(args); - } - cmd.args(&sess.opts.debugging_opts.pre_link_arg); - - if sess.target.target.options.is_like_fuchsia { - let prefix = match sess.opts.debugging_opts.sanitizer { - Some(Sanitizer::Address) => "asan/", - _ => "", - }; - cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix)); - } - - let pre_link_objects = if crate_type == config::CrateType::Executable { - &sess.target.target.options.pre_link_objects_exe - } else { - &sess.target.target.options.pre_link_objects_dll - }; - for obj in pre_link_objects { - cmd.arg(get_file_path(sess, obj)); - } - - if crate_type == config::CrateType::Executable && sess.crt_static() { - for obj in &sess.target.target.options.pre_link_objects_exe_crt { - cmd.arg(get_file_path(sess, obj)); - } - } - - if sess.target.target.options.is_like_emscripten { - cmd.arg("-s"); - cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort { - "DISABLE_EXCEPTION_CATCHING=1" - } else { - "DISABLE_EXCEPTION_CATCHING=0" - }); - } - - { - let target_cpu = crate::llvm_util::target_cpu(sess); - let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor, target_cpu); - link_args(&mut *linker, flavor, sess, crate_type, tmpdir, - out_filename, codegen_results); - cmd = linker.finalize(); - } - if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { - cmd.args(args); - } - for obj in &sess.target.target.options.post_link_objects { - cmd.arg(get_file_path(sess, obj)); - } - if sess.crt_static() { - for obj in &sess.target.target.options.post_link_objects_crt { - cmd.arg(get_file_path(sess, obj)); - } - } - if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) { - cmd.args(args); - } - for &(ref k, ref v) in &sess.target.target.options.link_env { - cmd.env(k, v); - } - - if sess.opts.debugging_opts.print_link_args { - println!("{:?}", &cmd); - } - - // May have not found libraries in the right formats. - sess.abort_if_errors(); - - // Invoke the system linker - // - // Note that there's a terribly awful hack that really shouldn't be present - // in any compiler. Here an environment variable is supported to - // automatically retry the linker invocation if the linker looks like it - // segfaulted. - // - // Gee that seems odd, normally segfaults are things we want to know about! - // Unfortunately though in rust-lang/rust#38878 we're experiencing the - // linker segfaulting on Travis quite a bit which is causing quite a bit of - // pain to land PRs when they spuriously fail due to a segfault. - // - // The issue #38878 has some more debugging information on it as well, but - // this unfortunately looks like it's just a race condition in macOS's linker - // with some thread pool working in the background. It seems that no one - // currently knows a fix for this so in the meantime we're left with this... - info!("{:?}", &cmd); - let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok(); - let mut prog; - let mut i = 0; - loop { - i += 1; - prog = time(sess, "running linker", || { - exec_linker(sess, &mut cmd, out_filename, tmpdir) - }); - let output = match prog { - Ok(ref output) => output, - Err(_) => break, - }; - if output.status.success() { - break - } - let mut out = output.stderr.clone(); - out.extend(&output.stdout); - let out = String::from_utf8_lossy(&out); - - // Check to see if the link failed with "unrecognized command line option: - // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so, - // reperform the link step without the -no-pie option. This is safe because - // if the linker doesn't support -no-pie then it should not default to - // linking executables as pie. Different versions of gcc seem to use - // different quotes in the error message so don't check for them. - if sess.target.target.options.linker_is_gnu && - flavor != LinkerFlavor::Ld && - (out.contains("unrecognized command line option") || - out.contains("unknown argument")) && - out.contains("-no-pie") && - cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie") { - info!("linker output: {:?}", out); - warn!("Linker does not support -no-pie command line option. Retrying without."); - for arg in cmd.take_args() { - if arg.to_string_lossy() != "-no-pie" { - cmd.arg(arg); - } - } - info!("{:?}", &cmd); - continue; - } - if !retry_on_segfault || i > 3 { - break - } - let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11"; - let msg_bus = "clang: error: unable to execute command: Bus error: 10"; - if !(out.contains(msg_segv) || out.contains(msg_bus)) { - break - } - - warn!( - "looks like the linker segfaulted when we tried to call it, \ - automatically retrying again. cmd = {:?}, out = {}.", - cmd, - out, - ); - } - - match prog { - Ok(prog) => { - fn escape_string(s: &[u8]) -> String { - str::from_utf8(s).map(|s| s.to_owned()) - .unwrap_or_else(|_| { - let mut x = "Non-UTF-8 output: ".to_string(); - x.extend(s.iter() - .flat_map(|&b| ascii::escape_default(b)) - .map(char::from)); - x - }) - } - if !prog.status.success() { - let mut output = prog.stderr.clone(); - output.extend_from_slice(&prog.stdout); - sess.struct_err(&format!("linking with `{}` failed: {}", - pname.display(), - prog.status)) - .note(&format!("{:?}", &cmd)) - .note(&escape_string(&output)) - .emit(); - sess.abort_if_errors(); - } - info!("linker stderr:\n{}", escape_string(&prog.stderr)); - info!("linker stdout:\n{}", escape_string(&prog.stdout)); - }, - Err(e) => { - let linker_not_found = e.kind() == io::ErrorKind::NotFound; - - let mut linker_error = { - if linker_not_found { - sess.struct_err(&format!("linker `{}` not found", pname.display())) - } else { - sess.struct_err(&format!("could not exec the linker `{}`", pname.display())) - } - }; - - linker_error.note(&e.to_string()); - - if !linker_not_found { - linker_error.note(&format!("{:?}", &cmd)); - } - - linker_error.emit(); - - if sess.target.target.options.is_like_msvc && linker_not_found { - sess.note_without_error("the msvc targets depend on the msvc linker \ - but `link.exe` was not found"); - sess.note_without_error("please ensure that VS 2013, VS 2015 or VS 2017 \ - was installed with the Visual C++ option"); - } - sess.abort_if_errors(); - } - } - - - // On macOS, debuggers need this utility to get run to do some munging of - // the symbols. Note, though, that if the object files are being preserved - // for their debug information there's no need for us to run dsymutil. - if sess.target.target.options.is_like_osx && - sess.opts.debuginfo != DebugInfo::None && - !preserve_objects_for_their_debuginfo(sess) - { - if let Err(e) = Command::new("dsymutil").arg(out_filename).output() { - sess.fatal(&format!("failed to run dsymutil: {}", e)) - } - } - - if sess.opts.target_triple.triple() == "wasm32-unknown-unknown" { - wasm::add_producer_section( - &out_filename, - &sess.edition().to_string(), - option_env!("CFG_VERSION").unwrap_or("unknown"), - ); - } -} - -fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &Path) - -> io::Result -{ - // When attempting to spawn the linker we run a risk of blowing out the - // size limits for spawning a new process with respect to the arguments - // we pass on the command line. - // - // Here we attempt to handle errors from the OS saying "your list of - // arguments is too big" by reinvoking the linker again with an `@`-file - // that contains all the arguments. The theory is that this is then - // accepted on all linkers and the linker will read all its options out of - // there instead of looking at the command line. - if !cmd.very_likely_to_exceed_some_spawn_limit() { - match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() { - Ok(child) => { - let output = child.wait_with_output(); - flush_linked_file(&output, out_filename)?; - return output; - } - Err(ref e) if command_line_too_big(e) => { - info!("command line to linker was too big: {}", e); - } - Err(e) => return Err(e) - } - } - - info!("falling back to passing arguments to linker via an @-file"); - let mut cmd2 = cmd.clone(); - let mut args = String::new(); - for arg in cmd2.take_args() { - args.push_str(&Escape { - arg: arg.to_str().unwrap(), - is_like_msvc: sess.target.target.options.is_like_msvc, - }.to_string()); - args.push_str("\n"); - } - let file = tmpdir.join("linker-arguments"); - let bytes = if sess.target.target.options.is_like_msvc { - let mut out = Vec::with_capacity((1 + args.len()) * 2); - // start the stream with a UTF-16 BOM - for c in iter::once(0xFEFF).chain(args.encode_utf16()) { - // encode in little endian - out.push(c as u8); - out.push((c >> 8) as u8); - } - out - } else { - args.into_bytes() - }; - fs::write(&file, &bytes)?; - cmd2.arg(format!("@{}", file.display())); - info!("invoking linker {:?}", cmd2); - let output = cmd2.output(); - flush_linked_file(&output, out_filename)?; - return output; - - #[cfg(unix)] - fn flush_linked_file(_: &io::Result, _: &Path) -> io::Result<()> { - Ok(()) - } - - #[cfg(windows)] - fn flush_linked_file(command_output: &io::Result, out_filename: &Path) - -> io::Result<()> - { - // On Windows, under high I/O load, output buffers are sometimes not flushed, - // even long after process exit, causing nasty, non-reproducible output bugs. - // - // File::sync_all() calls FlushFileBuffers() down the line, which solves the problem. - // - // А full writeup of the original Chrome bug can be found at - // randomascii.wordpress.com/2018/02/25/compiler-bug-linker-bug-windows-kernel-bug/amp - - if let &Ok(ref out) = command_output { - if out.status.success() { - if let Ok(of) = fs::OpenOptions::new().write(true).open(out_filename) { - of.sync_all()?; - } - } - } - - Ok(()) - } - - #[cfg(unix)] - fn command_line_too_big(err: &io::Error) -> bool { - err.raw_os_error() == Some(::libc::E2BIG) - } - - #[cfg(windows)] - fn command_line_too_big(err: &io::Error) -> bool { - const ERROR_FILENAME_EXCED_RANGE: i32 = 206; - err.raw_os_error() == Some(ERROR_FILENAME_EXCED_RANGE) - } - - struct Escape<'a> { - arg: &'a str, - is_like_msvc: bool, - } - - impl<'a> fmt::Display for Escape<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.is_like_msvc { - // This is "documented" at - // https://msdn.microsoft.com/en-us/library/4xdcbak7.aspx - // - // Unfortunately there's not a great specification of the - // syntax I could find online (at least) but some local - // testing showed that this seemed sufficient-ish to catch - // at least a few edge cases. - write!(f, "\"")?; - for c in self.arg.chars() { - match c { - '"' => write!(f, "\\{}", c)?, - c => write!(f, "{}", c)?, - } - } - write!(f, "\"")?; - } else { - // This is documented at https://linux.die.net/man/1/ld, namely: - // - // > Options in file are separated by whitespace. A whitespace - // > character may be included in an option by surrounding the - // > entire option in either single or double quotes. Any - // > character (including a backslash) may be included by - // > prefixing the character to be included with a backslash. - // - // We put an argument on each line, so all we need to do is - // ensure the line is interpreted as one whole argument. - for c in self.arg.chars() { - match c { - '\\' | ' ' => write!(f, "\\{}", c)?, - c => write!(f, "{}", c)?, - } - } - } - Ok(()) - } - } -} - -fn link_args(cmd: &mut dyn Linker, - flavor: LinkerFlavor, - sess: &Session, - crate_type: config::CrateType, - tmpdir: &Path, - out_filename: &Path, - codegen_results: &CodegenResults) { - - // Linker plugins should be specified early in the list of arguments - cmd.linker_plugin_lto(); - - // The default library location, we need this to find the runtime. - // The location of crates will be determined as needed. - let lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); - - // target descriptor - let t = &sess.target.target; - - cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); - for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { - cmd.add_object(obj); - } - cmd.output_filename(out_filename); - - if crate_type == config::CrateType::Executable && - sess.target.target.options.is_like_windows { - if let Some(ref s) = codegen_results.windows_subsystem { - cmd.subsystem(s); - } - } - - // If we're building a dynamic library then some platforms need to make sure - // that all symbols are exported correctly from the dynamic library. - if crate_type != config::CrateType::Executable || - sess.target.target.options.is_like_emscripten { - cmd.export_symbols(tmpdir, crate_type); - } - - // When linking a dynamic library, we put the metadata into a section of the - // executable. This metadata is in a separate object file from the main - // object file, so we link that in here. - if crate_type == config::CrateType::Dylib || - crate_type == config::CrateType::ProcMacro { - if let Some(obj) = codegen_results.metadata_module.object.as_ref() { - cmd.add_object(obj); - } - } - - let obj = codegen_results.allocator_module - .as_ref() - .and_then(|m| m.object.as_ref()); - if let Some(obj) = obj { - cmd.add_object(obj); - } - - // Try to strip as much out of the generated object by removing unused - // sections if possible. See more comments in linker.rs - if !sess.opts.cg.link_dead_code { - let keep_metadata = crate_type == config::CrateType::Dylib; - cmd.gc_sections(keep_metadata); - } - - let used_link_args = &codegen_results.crate_info.link_args; - - if crate_type == config::CrateType::Executable { - let mut position_independent_executable = false; - - if t.options.position_independent_executables { - let empty_vec = Vec::new(); - let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec); - let more_args = &sess.opts.cg.link_arg; - let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter()); - - if get_reloc_model(sess) == llvm::RelocMode::PIC - && !sess.crt_static() && !args.any(|x| *x == "-static") { - position_independent_executable = true; - } - } - - if position_independent_executable { - cmd.position_independent_executable(); - } else { - // recent versions of gcc can be configured to generate position - // independent executables by default. We have to pass -no-pie to - // explicitly turn that off. Not applicable to ld. - if sess.target.target.options.linker_is_gnu - && flavor != LinkerFlavor::Ld { - cmd.no_position_independent_executable(); - } - } - } - - let relro_level = match sess.opts.debugging_opts.relro_level { - Some(level) => level, - None => t.options.relro_level, - }; - match relro_level { - RelroLevel::Full => { - cmd.full_relro(); - }, - RelroLevel::Partial => { - cmd.partial_relro(); - }, - RelroLevel::Off => { - cmd.no_relro(); - }, - RelroLevel::None => { - }, - } - - // Pass optimization flags down to the linker. - cmd.optimize(); - - // Pass debuginfo flags down to the linker. - cmd.debuginfo(); - - // We want to, by default, prevent the compiler from accidentally leaking in - // any system libraries, so we may explicitly ask linkers to not link to any - // libraries by default. Note that this does not happen for windows because - // windows pulls in some large number of libraries and I couldn't quite - // figure out which subset we wanted. - // - // This is all naturally configurable via the standard methods as well. - if !sess.opts.cg.default_linker_libraries.unwrap_or(false) && - t.options.no_default_libraries - { - cmd.no_default_libraries(); - } - - // Take careful note of the ordering of the arguments we pass to the linker - // here. Linkers will assume that things on the left depend on things to the - // right. Things on the right cannot depend on things on the left. This is - // all formally implemented in terms of resolving symbols (libs on the right - // resolve unknown symbols of libs on the left, but not vice versa). - // - // For this reason, we have organized the arguments we pass to the linker as - // such: - // - // 1. The local object that LLVM just generated - // 2. Local native libraries - // 3. Upstream rust libraries - // 4. Upstream native libraries - // - // The rationale behind this ordering is that those items lower down in the - // list can't depend on items higher up in the list. For example nothing can - // depend on what we just generated (e.g., that'd be a circular dependency). - // Upstream rust libraries are not allowed to depend on our local native - // libraries as that would violate the structure of the DAG, in that - // scenario they are required to link to them as well in a shared fashion. - // - // Note that upstream rust libraries may contain native dependencies as - // well, but they also can't depend on what we just started to add to the - // link line. And finally upstream native libraries can't depend on anything - // in this DAG so far because they're only dylibs and dylibs can only depend - // on other dylibs (e.g., other native deps). - add_local_native_libraries(cmd, sess, codegen_results); - add_upstream_rust_crates(cmd, sess, codegen_results, crate_type, tmpdir); - add_upstream_native_libraries(cmd, sess, codegen_results, crate_type); - - // Tell the linker what we're doing. - if crate_type != config::CrateType::Executable { - cmd.build_dylib(out_filename); - } - if crate_type == config::CrateType::Executable && sess.crt_static() { - cmd.build_static_executable(); - } - - if sess.opts.debugging_opts.pgo_gen.is_some() { - cmd.pgo_gen(); - } - - // FIXME (#2397): At some point we want to rpath our guesses as to - // where extern libraries might live, based on the - // addl_lib_search_paths - if sess.opts.cg.rpath { - let target_triple = sess.opts.target_triple.triple(); - let mut get_install_prefix_lib_path = || { - let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX"); - let tlib = filesearch::relative_target_lib_path(&sess.sysroot, target_triple); - let mut path = PathBuf::from(install_prefix); - path.push(&tlib); - - path - }; - let mut rpath_config = RPathConfig { - used_crates: &codegen_results.crate_info.used_crates_dynamic, - out_filename: out_filename.to_path_buf(), - has_rpath: sess.target.target.options.has_rpath, - is_like_osx: sess.target.target.options.is_like_osx, - linker_is_gnu: sess.target.target.options.linker_is_gnu, - get_install_prefix_lib_path: &mut get_install_prefix_lib_path, - }; - cmd.args(&rpath::get_rpath_flags(&mut rpath_config)); - } - - // Finally add all the linker arguments provided on the command line along - // with any #[link_args] attributes found inside the crate - if let Some(ref args) = sess.opts.cg.link_args { - cmd.args(args); - } - cmd.args(&sess.opts.cg.link_arg); - cmd.args(&used_link_args); -} - -// # Native library linking -// -// User-supplied library search paths (-L on the command line). These are -// the same paths used to find Rust crates, so some of them may have been -// added already by the previous crate linking code. This only allows them -// to be found at compile time so it is still entirely up to outside -// forces to make sure that library can be found at runtime. -// -// Also note that the native libraries linked here are only the ones located -// in the current crate. Upstream crates with native library dependencies -// may have their native library pulled in above. -fn add_local_native_libraries(cmd: &mut dyn Linker, - sess: &Session, - codegen_results: &CodegenResults) { - let filesearch = sess.target_filesearch(PathKind::All); - for search_path in filesearch.search_paths() { - match search_path.kind { - PathKind::Framework => { cmd.framework_path(&search_path.dir); } - _ => { cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir)); } - } - } - - let relevant_libs = codegen_results.crate_info.used_libraries.iter().filter(|l| { - relevant_lib(sess, l) - }); - - let search_path = archive_search_paths(sess); - for lib in relevant_libs { - let name = match lib.name { - Some(ref l) => l, - None => continue, - }; - match lib.kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()), - NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()), - NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&name.as_str()), - NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&name.as_str(), - &search_path) - } - } -} - -// # Rust Crate linking -// -// Rust crates are not considered at all when creating an rlib output. All -// dependencies will be linked when producing the final output (instead of -// the intermediate rlib version) -fn add_upstream_rust_crates(cmd: &mut dyn Linker, - sess: &Session, - codegen_results: &CodegenResults, - crate_type: config::CrateType, - tmpdir: &Path) { - // All of the heavy lifting has previously been accomplished by the - // dependency_format module of the compiler. This is just crawling the - // output of that module, adding crates as necessary. - // - // Linking to a rlib involves just passing it to the linker (the linker - // will slurp up the object files inside), and linking to a dynamic library - // involves just passing the right -l flag. - - let formats = sess.dependency_formats.borrow(); - let data = formats.get(&crate_type).unwrap(); - - // Invoke get_used_crates to ensure that we get a topological sorting of - // crates. - let deps = &codegen_results.crate_info.used_crates_dynamic; - - // There's a few internal crates in the standard library (aka libcore and - // libstd) which actually have a circular dependence upon one another. This - // currently arises through "weak lang items" where libcore requires things - // like `rust_begin_unwind` but libstd ends up defining it. To get this - // circular dependence to work correctly in all situations we'll need to be - // sure to correctly apply the `--start-group` and `--end-group` options to - // GNU linkers, otherwise if we don't use any other symbol from the standard - // library it'll get discarded and the whole application won't link. - // - // In this loop we're calculating the `group_end`, after which crate to - // pass `--end-group` and `group_start`, before which crate to pass - // `--start-group`. We currently do this by passing `--end-group` after - // the first crate (when iterating backwards) that requires a lang item - // defined somewhere else. Once that's set then when we've defined all the - // necessary lang items we'll pass `--start-group`. - // - // Note that this isn't amazing logic for now but it should do the trick - // for the current implementation of the standard library. - let mut group_end = None; - let mut group_start = None; - let mut end_with = FxHashSet::default(); - let info = &codegen_results.crate_info; - for &(cnum, _) in deps.iter().rev() { - if let Some(missing) = info.missing_lang_items.get(&cnum) { - end_with.extend(missing.iter().cloned()); - if end_with.len() > 0 && group_end.is_none() { - group_end = Some(cnum); - } - } - end_with.retain(|item| info.lang_item_to_crate.get(item) != Some(&cnum)); - if end_with.len() == 0 && group_end.is_some() { - group_start = Some(cnum); - break - } - } - - // If we didn't end up filling in all lang items from upstream crates then - // we'll be filling it in with our crate. This probably means we're the - // standard library itself, so skip this for now. - if group_end.is_some() && group_start.is_none() { - group_end = None; - } - - let mut compiler_builtins = None; - - for &(cnum, _) in deps.iter() { - if group_start == Some(cnum) { - cmd.group_start(); - } - - // We may not pass all crates through to the linker. Some crates may - // appear statically in an existing dylib, meaning we'll pick up all the - // symbols from the dylib. - let src = &codegen_results.crate_info.used_crate_source[&cnum]; - match data[cnum.as_usize() - 1] { - _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => { - add_static_crate(cmd, sess, codegen_results, tmpdir, crate_type, cnum); - } - _ if codegen_results.crate_info.sanitizer_runtime == Some(cnum) => { - link_sanitizer_runtime(cmd, sess, codegen_results, tmpdir, cnum); - } - // compiler-builtins are always placed last to ensure that they're - // linked correctly. - _ if codegen_results.crate_info.compiler_builtins == Some(cnum) => { - assert!(compiler_builtins.is_none()); - compiler_builtins = Some(cnum); - } - Linkage::NotLinked | - Linkage::IncludedFromDylib => {} - Linkage::Static => { - add_static_crate(cmd, sess, codegen_results, tmpdir, crate_type, cnum); - } - Linkage::Dynamic => { - add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0) - } - } - - if group_end == Some(cnum) { - cmd.group_end(); - } - } - - // compiler-builtins are always placed last to ensure that they're - // linked correctly. - // We must always link the `compiler_builtins` crate statically. Even if it - // was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic` - // is used) - if let Some(cnum) = compiler_builtins { - add_static_crate(cmd, sess, codegen_results, tmpdir, crate_type, cnum); - } - - // Converts a library file-stem into a cc -l argument - fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str { - if stem.starts_with("lib") && !config.target.options.is_like_windows { - &stem[3..] - } else { - stem - } - } - - // We must link the sanitizer runtime using -Wl,--whole-archive but since - // it's packed in a .rlib, it contains stuff that are not objects that will - // make the linker error. So we must remove those bits from the .rlib before - // linking it. - fn link_sanitizer_runtime(cmd: &mut dyn Linker, - sess: &Session, - codegen_results: &CodegenResults, - tmpdir: &Path, - cnum: CrateNum) { - let src = &codegen_results.crate_info.used_crate_source[&cnum]; - let cratepath = &src.rlib.as_ref().unwrap().0; - - if sess.target.target.options.is_like_osx { - // On Apple platforms, the sanitizer is always built as a dylib, and - // LLVM will link to `@rpath/*.dylib`, so we need to specify an - // rpath to the library as well (the rpath should be absolute, see - // PR #41352 for details). - // - // FIXME: Remove this logic into librustc_*san once Cargo supports it - let rpath = cratepath.parent().unwrap(); - let rpath = rpath.to_str().expect("non-utf8 component in path"); - cmd.args(&["-Wl,-rpath".into(), "-Xlinker".into(), rpath.into()]); - } - - let dst = tmpdir.join(cratepath.file_name().unwrap()); - let cfg = archive_config(sess, &dst, Some(cratepath)); - let mut archive = ArchiveBuilder::new(cfg); - archive.update_symbols(); - - for f in archive.src_files() { - if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME { - archive.remove_file(&f); - } - } - - archive.build(); - - cmd.link_whole_rlib(&dst); - } - - // Adds the static "rlib" versions of all crates to the command line. - // There's a bit of magic which happens here specifically related to LTO and - // dynamic libraries. Specifically: - // - // * For LTO, we remove upstream object files. - // * For dylibs we remove metadata and bytecode from upstream rlibs - // - // When performing LTO, almost(*) all of the bytecode from the upstream - // libraries has already been included in our object file output. As a - // result we need to remove the object files in the upstream libraries so - // the linker doesn't try to include them twice (or whine about duplicate - // symbols). We must continue to include the rest of the rlib, however, as - // it may contain static native libraries which must be linked in. - // - // (*) Crates marked with `#![no_builtins]` don't participate in LTO and - // their bytecode wasn't included. The object files in those libraries must - // still be passed to the linker. - // - // When making a dynamic library, linkers by default don't include any - // object files in an archive if they're not necessary to resolve the link. - // We basically want to convert the archive (rlib) to a dylib, though, so we - // *do* want everything included in the output, regardless of whether the - // linker thinks it's needed or not. As a result we must use the - // --whole-archive option (or the platform equivalent). When using this - // option the linker will fail if there are non-objects in the archive (such - // as our own metadata and/or bytecode). All in all, for rlibs to be - // entirely included in dylibs, we need to remove all non-object files. - // - // Note, however, that if we're not doing LTO or we're not producing a dylib - // (aka we're making an executable), we can just pass the rlib blindly to - // the linker (fast) because it's fine if it's not actually included as - // we're at the end of the dependency chain. - fn add_static_crate(cmd: &mut dyn Linker, - sess: &Session, - codegen_results: &CodegenResults, - tmpdir: &Path, - crate_type: config::CrateType, - cnum: CrateNum) { - let src = &codegen_results.crate_info.used_crate_source[&cnum]; - let cratepath = &src.rlib.as_ref().unwrap().0; - - // See the comment above in `link_staticlib` and `link_rlib` for why if - // there's a static library that's not relevant we skip all object - // files. - let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; - let skip_native = native_libs.iter().any(|lib| { - lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) - }); - - if (!are_upstream_rust_objects_already_included(sess) || - ignored_for_lto(sess, &codegen_results.crate_info, cnum)) && - crate_type != config::CrateType::Dylib && - !skip_native { - cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); - return - } - - let dst = tmpdir.join(cratepath.file_name().unwrap()); - let name = cratepath.file_name().unwrap().to_str().unwrap(); - let name = &name[3..name.len() - 5]; // chop off lib/.rlib - - time(sess, &format!("altering {}.rlib", name), || { - let cfg = archive_config(sess, &dst, Some(cratepath)); - let mut archive = ArchiveBuilder::new(cfg); - archive.update_symbols(); - - let mut any_objects = false; - for f in archive.src_files() { - if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME { - archive.remove_file(&f); - continue - } - - let canonical = f.replace("-", "_"); - let canonical_name = name.replace("-", "_"); - - // Look for `.rcgu.o` at the end of the filename to conclude - // that this is a Rust-related object file. - fn looks_like_rust(s: &str) -> bool { - let path = Path::new(s); - let ext = path.extension().and_then(|s| s.to_str()); - if ext != Some(OutputType::Object.extension()) { - return false - } - let ext2 = path.file_stem() - .and_then(|s| Path::new(s).extension()) - .and_then(|s| s.to_str()); - ext2 == Some(RUST_CGU_EXT) - } - - let is_rust_object = - canonical.starts_with(&canonical_name) && - looks_like_rust(&f); - - // If we've been requested to skip all native object files - // (those not generated by the rust compiler) then we can skip - // this file. See above for why we may want to do this. - let skip_because_cfg_say_so = skip_native && !is_rust_object; - - // If we're performing LTO and this is a rust-generated object - // file, then we don't need the object file as it's part of the - // LTO module. Note that `#![no_builtins]` is excluded from LTO, - // though, so we let that object file slide. - let skip_because_lto = are_upstream_rust_objects_already_included(sess) && - is_rust_object && - (sess.target.target.options.no_builtins || - !codegen_results.crate_info.is_no_builtins.contains(&cnum)); - - if skip_because_cfg_say_so || skip_because_lto { - archive.remove_file(&f); - } else { - any_objects = true; - } - } - - if !any_objects { - return - } - archive.build(); - - // If we're creating a dylib, then we need to include the - // whole of each object in our archive into that artifact. This is - // because a `dylib` can be reused as an intermediate artifact. - // - // Note, though, that we don't want to include the whole of a - // compiler-builtins crate (e.g., compiler-rt) because it'll get - // repeatedly linked anyway. - if crate_type == config::CrateType::Dylib && - codegen_results.crate_info.compiler_builtins != Some(cnum) { - cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst)); - } else { - cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst)); - } - }); - } - - // Same thing as above, but for dynamic crates instead of static crates. - fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { - // If we're performing LTO, then it should have been previously required - // that all upstream rust dependencies were available in an rlib format. - assert!(!are_upstream_rust_objects_already_included(sess)); - - // Just need to tell the linker about where the library lives and - // what its name is - let parent = cratepath.parent(); - if let Some(dir) = parent { - cmd.include_path(&fix_windows_verbatim_for_gcc(dir)); - } - let filestem = cratepath.file_stem().unwrap().to_str().unwrap(); - cmd.link_rust_dylib(&unlib(&sess.target, filestem), - parent.unwrap_or(Path::new(""))); - } -} - -// Link in all of our upstream crates' native dependencies. Remember that -// all of these upstream native dependencies are all non-static -// dependencies. We've got two cases then: -// -// 1. The upstream crate is an rlib. In this case we *must* link in the -// native dependency because the rlib is just an archive. -// -// 2. The upstream crate is a dylib. In order to use the dylib, we have to -// have the dependency present on the system somewhere. Thus, we don't -// gain a whole lot from not linking in the dynamic dependency to this -// crate as well. -// -// The use case for this is a little subtle. In theory the native -// dependencies of a crate are purely an implementation detail of the crate -// itself, but the problem arises with generic and inlined functions. If a -// generic function calls a native function, then the generic function must -// be instantiated in the target crate, meaning that the native symbol must -// also be resolved in the target crate. -fn add_upstream_native_libraries(cmd: &mut dyn Linker, - sess: &Session, - codegen_results: &CodegenResults, - crate_type: config::CrateType) { - // Be sure to use a topological sorting of crates because there may be - // interdependencies between native libraries. When passing -nodefaultlibs, - // for example, almost all native libraries depend on libc, so we have to - // make sure that's all the way at the right (liblibc is near the base of - // the dependency chain). - // - // This passes RequireStatic, but the actual requirement doesn't matter, - // we're just getting an ordering of crate numbers, we're not worried about - // the paths. - let formats = sess.dependency_formats.borrow(); - let data = formats.get(&crate_type).unwrap(); - - let crates = &codegen_results.crate_info.used_crates_static; - for &(cnum, _) in crates { - for lib in codegen_results.crate_info.native_libraries[&cnum].iter() { - let name = match lib.name { - Some(ref l) => l, - None => continue, - }; - if !relevant_lib(sess, &lib) { - continue - } - match lib.kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()), - NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()), - NativeLibraryKind::NativeStaticNobundle => { - // Link "static-nobundle" native libs only if the crate they originate from - // is being linked statically to the current crate. If it's linked dynamically - // or is an rlib already included via some other dylib crate, the symbols from - // native libs will have already been included in that dylib. - if data[cnum.as_usize() - 1] == Linkage::Static { - cmd.link_staticlib(&name.as_str()) - } - }, - // ignore statically included native libraries here as we've - // already included them when we included the rust library - // previously - NativeLibraryKind::NativeStatic => {} - } - } - } -} - -fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { - match lib.cfg { - Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None), - None => true, - } -} - -fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { - match sess.lto() { - Lto::Fat => true, - Lto::Thin => { - // If we defer LTO to the linker, we haven't run LTO ourselves, so - // any upstream object files have not been copied yet. - !sess.opts.cg.linker_plugin_lto.enabled() - } - Lto::No | - Lto::ThinLocal => false, - } -} diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 944569c8b744b..5d3cc0c0a255f 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -1,9 +1,8 @@ -use crate::back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION}; +use crate::back::bytecode::DecodedBytecode; use crate::back::write::{self, DiagnosticHandlers, with_llvm_pmb, save_temp_bitcode, to_llvm_opt_settings}; use crate::llvm::archive_ro::ArchiveRO; use crate::llvm::{self, True, False}; -use crate::time_graph::Timeline; use crate::{ModuleLlvm, LlvmCodegenBackend}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{ModuleConfig, CodegenContext, FatLTOInput}; @@ -17,7 +16,7 @@ use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::session::config::{self, Lto}; use rustc::util::common::time_ext; use rustc_data_structures::fx::FxHashMap; -use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; +use rustc_codegen_ssa::{RLIB_BYTECODE_EXTENSION, ModuleCodegen, ModuleKind}; use std::ffi::{CStr, CString}; use std::ptr; @@ -37,7 +36,6 @@ pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool { } fn prepare_lto(cgcx: &CodegenContext, - timeline: &mut Timeline, diag_handler: &Handler) -> Result<(Vec, Vec<(SerializedModule, CString)>), FatalError> { @@ -68,7 +66,7 @@ fn prepare_lto(cgcx: &CodegenContext, .iter() .filter_map(symbol_filter) .collect::>(); - timeline.record("whitelist"); + let _timer = cgcx.profile_activity("generate_symbol_white_list_for_thinlto"); info!("{} symbols to preserve in this crate", symbol_white_list.len()); // If we're performing LTO for the entire crate graph, then for each of our @@ -97,6 +95,7 @@ fn prepare_lto(cgcx: &CodegenContext, } for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { + let _timer = cgcx.profile_activity(format!("load: {}", path.display())); let exported_symbols = cgcx.exported_symbols .as_ref().expect("needs exported symbols for LTO"); symbol_white_list.extend( @@ -121,7 +120,6 @@ fn prepare_lto(cgcx: &CodegenContext, let bc = SerializedModule::FromRlib(bc); upstream_modules.push((bc, CString::new(id).unwrap())); } - timeline.record(&format!("load: {}", path.display())); } } @@ -132,12 +130,11 @@ fn prepare_lto(cgcx: &CodegenContext, /// for further optimization. pub(crate) fn run_fat(cgcx: &CodegenContext, modules: Vec>, - cached_modules: Vec<(SerializedModule, WorkProduct)>, - timeline: &mut Timeline) + cached_modules: Vec<(SerializedModule, WorkProduct)>) -> Result, FatalError> { let diag_handler = cgcx.create_diag_handler(); - let (symbol_white_list, upstream_modules) = prepare_lto(cgcx, timeline, &diag_handler)?; + let (symbol_white_list, upstream_modules) = prepare_lto(cgcx, &diag_handler)?; let symbol_white_list = symbol_white_list.iter() .map(|c| c.as_ptr()) .collect::>(); @@ -148,7 +145,6 @@ pub(crate) fn run_fat(cgcx: &CodegenContext, cached_modules, upstream_modules, &symbol_white_list, - timeline, ) } @@ -157,12 +153,11 @@ pub(crate) fn run_fat(cgcx: &CodegenContext, /// can simply be copied over from the incr. comp. cache. pub(crate) fn run_thin(cgcx: &CodegenContext, modules: Vec<(String, ThinBuffer)>, - cached_modules: Vec<(SerializedModule, WorkProduct)>, - timeline: &mut Timeline) + cached_modules: Vec<(SerializedModule, WorkProduct)>) -> Result<(Vec>, Vec), FatalError> { let diag_handler = cgcx.create_diag_handler(); - let (symbol_white_list, upstream_modules) = prepare_lto(cgcx, timeline, &diag_handler)?; + let (symbol_white_list, upstream_modules) = prepare_lto(cgcx, &diag_handler)?; let symbol_white_list = symbol_white_list.iter() .map(|c| c.as_ptr()) .collect::>(); @@ -175,8 +170,7 @@ pub(crate) fn run_thin(cgcx: &CodegenContext, modules, upstream_modules, cached_modules, - &symbol_white_list, - timeline) + &symbol_white_list) } pub(crate) fn prepare_thin( @@ -192,8 +186,7 @@ fn fat_lto(cgcx: &CodegenContext, mut modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, - symbol_white_list: &[*const libc::c_char], - timeline: &mut Timeline) + symbol_white_list: &[*const libc::c_char]) -> Result, FatalError> { info!("going for a fat lto"); @@ -286,7 +279,7 @@ fn fat_lto(cgcx: &CodegenContext, } })); serialized_modules.extend(cached_modules.into_iter().map(|(buffer, wp)| { - (buffer, CString::new(wp.cgu_name.clone()).unwrap()) + (buffer, CString::new(wp.cgu_name).unwrap()) })); // For all serialized bitcode files we parse them and link them in as we did @@ -303,7 +296,6 @@ fn fat_lto(cgcx: &CodegenContext, write::llvm_err(&diag_handler, &msg) }) })?; - timeline.record(&format!("link {:?}", name)); serialized_bitcode.push(bc_decoded); } drop(linker); @@ -325,7 +317,6 @@ fn fat_lto(cgcx: &CodegenContext, } save_temp_bitcode(&cgcx, &module, "lto.after-nounwind"); } - timeline.record("passes"); } Ok(LtoModuleCodegen::Fat { @@ -395,8 +386,7 @@ fn thin_lto(cgcx: &CodegenContext, modules: Vec<(String, ThinBuffer)>, serialized_modules: Vec<(SerializedModule, CString)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - symbol_white_list: &[*const libc::c_char], - timeline: &mut Timeline) + symbol_white_list: &[*const libc::c_char]) -> Result<(Vec>, Vec), FatalError> { unsafe { @@ -422,7 +412,6 @@ fn thin_lto(cgcx: &CodegenContext, }); thin_buffers.push(buffer); module_names.push(cname); - timeline.record(&name); } // FIXME: All upstream crates are deserialized internally in the @@ -475,7 +464,6 @@ fn thin_lto(cgcx: &CodegenContext, })?; info!("thin LTO data created"); - timeline.record("data"); let import_map = if cgcx.incr_comp_session_dir.is_some() { ThinLTOImports::from_thin_lto_data(data) @@ -486,7 +474,6 @@ fn thin_lto(cgcx: &CodegenContext, ThinLTOImports::default() }; info!("thin LTO import map loaded"); - timeline.record("import-map-loaded"); let data = ThinData(data); @@ -691,7 +678,6 @@ impl Drop for ThinBuffer { pub unsafe fn optimize_thin_module( thin_module: &mut ThinModule, cgcx: &CodegenContext, - timeline: &mut Timeline ) -> Result, FatalError> { let diag_handler = cgcx.create_diag_handler(); let tm = (cgcx.tm_factory.0)().map_err(|e| { @@ -738,9 +724,9 @@ pub unsafe fn optimize_thin_module( // Like with "fat" LTO, get some better optimizations if landing pads // are disabled by removing all landing pads. if cgcx.no_landing_pads { + let _timer = cgcx.profile_activity("LLVM_remove_landing_pads"); llvm::LLVMRustMarkAllFunctionsNounwind(llmod); save_temp_bitcode(&cgcx, &module, "thin-lto-after-nounwind"); - timeline.record("nounwind"); } // Up next comes the per-module local analyses that we do for Thin LTO. @@ -756,25 +742,21 @@ pub unsafe fn optimize_thin_module( return Err(write::llvm_err(&diag_handler, msg)) } save_temp_bitcode(cgcx, &module, "thin-lto-after-rename"); - timeline.record("rename"); if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) { let msg = "failed to prepare thin LTO module"; return Err(write::llvm_err(&diag_handler, msg)) } save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve"); - timeline.record("resolve"); if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) { let msg = "failed to prepare thin LTO module"; return Err(write::llvm_err(&diag_handler, msg)) } save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize"); - timeline.record("internalize"); if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) { let msg = "failed to prepare thin LTO module"; return Err(write::llvm_err(&diag_handler, msg)) } save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); - timeline.record("import"); // Ok now this is a bit unfortunate. This is also something you won't // find upstream in LLVM's ThinLTO passes! This is a hack for now to @@ -807,7 +789,6 @@ pub unsafe fn optimize_thin_module( // fixed in LLVM. llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1); save_temp_bitcode(cgcx, &module, "thin-lto-after-patch"); - timeline.record("patch"); // Alright now that we've done everything related to the ThinLTO // analysis it's time to run some optimizations! Here we use the same @@ -818,7 +799,6 @@ pub unsafe fn optimize_thin_module( let config = cgcx.config(module.kind); run_pass_manager(cgcx, &module, config, true); save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); - timeline.record("thin-done"); } Ok(module) } diff --git a/src/librustc_codegen_llvm/back/rpath.rs b/src/librustc_codegen_llvm/back/rpath.rs deleted file mode 100644 index 2b7abcb52bef8..0000000000000 --- a/src/librustc_codegen_llvm/back/rpath.rs +++ /dev/null @@ -1,270 +0,0 @@ -use rustc_data_structures::fx::FxHashSet; -use std::env; -use std::path::{Path, PathBuf}; -use std::fs; - -use rustc::hir::def_id::CrateNum; -use rustc::middle::cstore::LibSource; - -pub struct RPathConfig<'a> { - pub used_crates: &'a [(CrateNum, LibSource)], - pub out_filename: PathBuf, - pub is_like_osx: bool, - pub has_rpath: bool, - pub linker_is_gnu: bool, - pub get_install_prefix_lib_path: &'a mut dyn FnMut() -> PathBuf, -} - -pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec { - // No rpath on windows - if !config.has_rpath { - return Vec::new(); - } - - debug!("preparing the RPATH!"); - - let libs = config.used_crates.clone(); - let libs = libs.iter().filter_map(|&(_, ref l)| l.option()).collect::>(); - let rpaths = get_rpaths(config, &libs); - let mut flags = rpaths_to_flags(&rpaths); - - // Use DT_RUNPATH instead of DT_RPATH if available - if config.linker_is_gnu { - flags.push("-Wl,--enable-new-dtags".to_owned()); - } - - flags -} - -fn rpaths_to_flags(rpaths: &[String]) -> Vec { - let mut ret = Vec::with_capacity(rpaths.len()); // the minimum needed capacity - - for rpath in rpaths { - if rpath.contains(',') { - ret.push("-Wl,-rpath".into()); - ret.push("-Xlinker".into()); - ret.push(rpath.clone()); - } else { - ret.push(format!("-Wl,-rpath,{}", &(*rpath))); - } - } - - ret -} - -fn get_rpaths(config: &mut RPathConfig<'_>, libs: &[PathBuf]) -> Vec { - debug!("output: {:?}", config.out_filename.display()); - debug!("libs:"); - for libpath in libs { - debug!(" {:?}", libpath.display()); - } - - // Use relative paths to the libraries. Binaries can be moved - // as long as they maintain the relative relationship to the - // crates they depend on. - let rel_rpaths = get_rpaths_relative_to_output(config, libs); - - // And a final backup rpath to the global library location. - let fallback_rpaths = vec![get_install_prefix_rpath(config)]; - - fn log_rpaths(desc: &str, rpaths: &[String]) { - debug!("{} rpaths:", desc); - for rpath in rpaths { - debug!(" {}", *rpath); - } - } - - log_rpaths("relative", &rel_rpaths); - log_rpaths("fallback", &fallback_rpaths); - - let mut rpaths = rel_rpaths; - rpaths.extend_from_slice(&fallback_rpaths); - - // Remove duplicates - let rpaths = minimize_rpaths(&rpaths); - - rpaths -} - -fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>, - libs: &[PathBuf]) -> Vec { - libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect() -} - -fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> String { - // Mac doesn't appear to support $ORIGIN - let prefix = if config.is_like_osx { - "@loader_path" - } else { - "$ORIGIN" - }; - - let cwd = env::current_dir().unwrap(); - let mut lib = fs::canonicalize(&cwd.join(lib)).unwrap_or_else(|_| cwd.join(lib)); - lib.pop(); // strip filename - let mut output = cwd.join(&config.out_filename); - output.pop(); // strip filename - let output = fs::canonicalize(&output).unwrap_or(output); - let relative = path_relative_from(&lib, &output).unwrap_or_else(|| - panic!("couldn't create relative path from {:?} to {:?}", output, lib)); - // FIXME (#9639): This needs to handle non-utf8 paths - format!("{}/{}", prefix, relative.to_str().expect("non-utf8 component in path")) -} - -// This routine is adapted from the *old* Path's `path_relative_from` -// function, which works differently from the new `relative_from` function. -// In particular, this handles the case on unix where both paths are -// absolute but with only the root as the common directory. -fn path_relative_from(path: &Path, base: &Path) -> Option { - use std::path::Component; - - if path.is_absolute() != base.is_absolute() { - if path.is_absolute() { - Some(PathBuf::from(path)) - } else { - None - } - } else { - let mut ita = path.components(); - let mut itb = base.components(); - let mut comps: Vec> = vec![]; - loop { - match (ita.next(), itb.next()) { - (None, None) => break, - (Some(a), None) => { - comps.push(a); - comps.extend(ita.by_ref()); - break; - } - (None, _) => comps.push(Component::ParentDir), - (Some(a), Some(b)) if comps.is_empty() && a == b => (), - (Some(a), Some(b)) if b == Component::CurDir => comps.push(a), - (Some(_), Some(b)) if b == Component::ParentDir => return None, - (Some(a), Some(_)) => { - comps.push(Component::ParentDir); - comps.extend(itb.map(|_| Component::ParentDir)); - comps.push(a); - comps.extend(ita.by_ref()); - break; - } - } - } - Some(comps.iter().map(|c| c.as_os_str()).collect()) - } -} - - -fn get_install_prefix_rpath(config: &mut RPathConfig<'_>) -> String { - let path = (config.get_install_prefix_lib_path)(); - let path = env::current_dir().unwrap().join(&path); - // FIXME (#9639): This needs to handle non-utf8 paths - path.to_str().expect("non-utf8 component in rpath").to_owned() -} - -fn minimize_rpaths(rpaths: &[String]) -> Vec { - let mut set = FxHashSet::default(); - let mut minimized = Vec::new(); - for rpath in rpaths { - if set.insert(rpath) { - minimized.push(rpath.clone()); - } - } - minimized -} - -#[cfg(all(unix, test))] -mod tests { - use super::{RPathConfig}; - use super::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output}; - use std::path::{Path, PathBuf}; - - #[test] - fn test_rpaths_to_flags() { - let flags = rpaths_to_flags(&[ - "path1".to_string(), - "path2".to_string() - ]); - assert_eq!(flags, - ["-Wl,-rpath,path1", - "-Wl,-rpath,path2"]); - } - - #[test] - fn test_minimize1() { - let res = minimize_rpaths(&[ - "rpath1".to_string(), - "rpath2".to_string(), - "rpath1".to_string() - ]); - assert!(res == [ - "rpath1", - "rpath2", - ]); - } - - #[test] - fn test_minimize2() { - let res = minimize_rpaths(&[ - "1a".to_string(), - "2".to_string(), - "2".to_string(), - "1a".to_string(), - "4a".to_string(), - "1a".to_string(), - "2".to_string(), - "3".to_string(), - "4a".to_string(), - "3".to_string() - ]); - assert!(res == [ - "1a", - "2", - "4a", - "3", - ]); - } - - #[test] - fn test_rpath_relative() { - if cfg!(target_os = "macos") { - let config = &mut RPathConfig { - used_crates: Vec::new(), - has_rpath: true, - is_like_osx: true, - linker_is_gnu: false, - out_filename: PathBuf::from("bin/rustc"), - get_install_prefix_lib_path: &mut || panic!(), - }; - let res = get_rpath_relative_to_output(config, - Path::new("lib/libstd.so")); - assert_eq!(res, "@loader_path/../lib"); - } else { - let config = &mut RPathConfig { - used_crates: Vec::new(), - out_filename: PathBuf::from("bin/rustc"), - get_install_prefix_lib_path: &mut || panic!(), - has_rpath: true, - is_like_osx: false, - linker_is_gnu: true, - }; - let res = get_rpath_relative_to_output(config, - Path::new("lib/libstd.so")); - assert_eq!(res, "$ORIGIN/../lib"); - } - } - - #[test] - fn test_xlinker() { - let args = rpaths_to_flags(&[ - "a/normal/path".to_string(), - "a,comma,path".to_string() - ]); - - assert_eq!(args, vec![ - "-Wl,-rpath,a/normal/path".to_string(), - "-Wl,-rpath".to_string(), - "-Xlinker".to_string(), - "a,comma,path".to_string() - ]); - } -} diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index db5430a4219a0..3638730707f3f 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -1,9 +1,8 @@ use crate::attributes; -use crate::back::bytecode::{self, RLIB_BYTECODE_EXTENSION}; +use crate::back::bytecode; use crate::back::lto::ThinBuffer; use crate::base; use crate::consts; -use crate::time_graph::Timeline; use crate::llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic}; use crate::llvm_util; use crate::ModuleLlvm; @@ -11,13 +10,13 @@ use crate::type_::Type; use crate::context::{is_pie_binary, get_reloc_model}; use crate::common; use crate::LlvmCodegenBackend; +use rustc::hir::def_id::LOCAL_CRATE; use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, run_assembler}; use rustc_codegen_ssa::traits::*; -use rustc::hir::def_id::LOCAL_CRATE; -use rustc::session::config::{self, OutputType, Passes, Lto}; +use rustc::session::config::{self, OutputType, Passes, Lto, SwitchWithOptPath}; use rustc::session::Session; use rustc::ty::TyCtxt; -use rustc_codegen_ssa::{ModuleCodegen, CompiledModule}; +use rustc_codegen_ssa::{RLIB_BYTECODE_EXTENSION, ModuleCodegen, CompiledModule}; use rustc::util::common::time_ext; use rustc_fs_util::{path_to_c_string, link_or_copy}; use rustc_data_structures::small_c_str::SmallCStr; @@ -26,7 +25,7 @@ use errors::{Handler, FatalError}; use std::ffi::{CString, CStr}; use std::fs; use std::io::{self, Write}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::str; use std::sync::Arc; use std::slice; @@ -73,23 +72,13 @@ pub fn write_output_file( unsafe { let output_c = path_to_c_string(output); let result = llvm::LLVMRustWriteOutputFile(target, pm, m, output_c.as_ptr(), file_type); - if result.into_result().is_err() { + result.into_result().map_err(|()| { let msg = format!("could not write output to {}", output.display()); - Err(llvm_err(handler, &msg)) - } else { - Ok(()) - } + llvm_err(handler, &msg) + }) } } -pub fn create_target_machine( - tcx: TyCtxt<'_, '_, '_>, - find_features: bool, -) -> &'static mut llvm::TargetMachine { - target_machine_factory(tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE), find_features)() - .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise() ) -} - pub fn create_informational_target_machine( sess: &Session, find_features: bool, @@ -99,6 +88,15 @@ pub fn create_informational_target_machine( }) } +pub fn create_target_machine( + tcx: TyCtxt<'_>, + find_features: bool, +) -> &'static mut llvm::TargetMachine { + target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE), find_features)() + .unwrap_or_else(|err| { + llvm_err(tcx.sess.diagnostic(), &err).raise() + }) +} pub fn to_llvm_opt_settings(cfg: config::OptLevel) -> (llvm::CodeGenOptLevel, llvm::CodeGenOptSize) { @@ -305,8 +303,7 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void pub(crate) unsafe fn optimize(cgcx: &CodegenContext, diag_handler: &Handler, module: &ModuleCodegen, - config: &ModuleConfig, - timeline: &mut Timeline) + config: &ModuleConfig) -> Result<(), FatalError> { let llmod = module.module_llvm.llmod(); @@ -415,19 +412,24 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext, diag_handler.abort_if_errors(); // Finally, run the actual optimization passes - time_ext(config.time_passes, - None, - &format!("llvm function passes [{}]", module_name.unwrap()), - || { - llvm::LLVMRustRunFunctionPassManager(fpm, llmod) - }); - timeline.record("fpm"); - time_ext(config.time_passes, - None, - &format!("llvm module passes [{}]", module_name.unwrap()), - || { - llvm::LLVMRunPassManager(mpm, llmod) - }); + { + let _timer = cgcx.profile_activity("LLVM_function_passes"); + time_ext(config.time_passes, + None, + &format!("llvm function passes [{}]", module_name.unwrap()), + || { + llvm::LLVMRustRunFunctionPassManager(fpm, llmod) + }); + } + { + let _timer = cgcx.profile_activity("LLVM_module_passes"); + time_ext(config.time_passes, + None, + &format!("llvm module passes [{}]", module_name.unwrap()), + || { + llvm::LLVMRunPassManager(mpm, llmod) + }); + } // Deallocate managers that we're now done with llvm::LLVMDisposePassManager(fpm); @@ -439,11 +441,10 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext, pub(crate) unsafe fn codegen(cgcx: &CodegenContext, diag_handler: &Handler, module: ModuleCodegen, - config: &ModuleConfig, - timeline: &mut Timeline) + config: &ModuleConfig) -> Result { - timeline.record("codegen"); + let _timer = cgcx.profile_activity("codegen"); { let llmod = module.module_llvm.llmod(); let llcx = &*module.module_llvm.llcx; @@ -494,29 +495,31 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, if write_bc || config.emit_bc_compressed || config.embed_bitcode { + let _timer = cgcx.profile_activity("LLVM_make_bitcode"); let thin = ThinBuffer::new(llmod); let data = thin.data(); - timeline.record("make-bc"); if write_bc { + let _timer = cgcx.profile_activity("LLVM_emit_bitcode"); if let Err(e) = fs::write(&bc_out, data) { - diag_handler.err(&format!("failed to write bytecode: {}", e)); + let msg = format!("failed to write bytecode to {}: {}", bc_out.display(), e); + diag_handler.err(&msg); } - timeline.record("write-bc"); } if config.embed_bitcode { + let _timer = cgcx.profile_activity("LLVM_embed_bitcode"); embed_bitcode(cgcx, llcx, llmod, Some(data)); - timeline.record("embed-bc"); } if config.emit_bc_compressed { + let _timer = cgcx.profile_activity("LLVM_compress_bitcode"); let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION); let data = bytecode::encode(&module.name, data); if let Err(e) = fs::write(&dst, data) { - diag_handler.err(&format!("failed to write bytecode: {}", e)); + let msg = format!("failed to write bytecode to {}: {}", dst.display(), e); + diag_handler.err(&msg); } - timeline.record("compress-bc"); } } else if config.embed_bitcode_marker { embed_bitcode(cgcx, llcx, llmod, None); @@ -525,8 +528,9 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()), || -> Result<(), FatalError> { if config.emit_ir { + let _timer = cgcx.profile_activity("LLVM_emit_ir"); let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); - let out = path_to_c_string(&out); + let out_c = path_to_c_string(&out); extern "C" fn demangle_callback(input_ptr: *const c_char, input_len: size_t, @@ -560,13 +564,18 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, } with_codegen(tm, llmod, config.no_builtins, |cpm| { - llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback); + let result = + llvm::LLVMRustPrintModule(cpm, llmod, out_c.as_ptr(), demangle_callback); llvm::LLVMDisposePassManager(cpm); - }); - timeline.record("ir"); + result.into_result().map_err(|()| { + let msg = format!("failed to write LLVM IR to {}", out.display()); + llvm_err(diag_handler, &msg) + }) + })?; } if config.emit_asm || asm_to_obj { + let _timer = cgcx.profile_activity("LLVM_emit_asm"); let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); // We can't use the same module for asm and binary output, because that triggers @@ -581,19 +590,18 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, write_output_file(diag_handler, tm, cpm, llmod, &path, llvm::FileType::AssemblyFile) })?; - timeline.record("asm"); } if write_obj { + let _timer = cgcx.profile_activity("LLVM_emit_obj"); with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file(diag_handler, tm, cpm, llmod, &obj_out, llvm::FileType::ObjectFile) })?; - timeline.record("obj"); } else if asm_to_obj { + let _timer = cgcx.profile_activity("LLVM_asm_to_obj"); let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); run_assembler(cgcx, diag_handler, &assembly, &obj_out); - timeline.record("asm_to_obj"); if !config.emit_asm && !cgcx.save_temps { drop(fs::remove_file(&assembly)); @@ -698,17 +706,25 @@ pub unsafe fn with_llvm_pmb(llmod: &llvm::Module, .unwrap_or(llvm::CodeGenOptSizeNone); let inline_threshold = config.inline_threshold; - let pgo_gen_path = config.pgo_gen.as_ref().map(|s| { - let s = if s.is_empty() { "default_%m.profraw" } else { s }; - CString::new(s.as_bytes()).unwrap() - }); + let pgo_gen_path = match config.pgo_gen { + SwitchWithOptPath::Enabled(ref opt_dir_path) => { + let path = if let Some(dir_path) = opt_dir_path { + dir_path.join("default_%m.profraw") + } else { + PathBuf::from("default_%m.profraw") + }; - let pgo_use_path = if config.pgo_use.is_empty() { - None - } else { - Some(CString::new(config.pgo_use.as_bytes()).unwrap()) + Some(CString::new(format!("{}", path.display())).unwrap()) + } + SwitchWithOptPath::Disabled => { + None + } }; + let pgo_use_path = config.pgo_use.as_ref().map(|path_buf| { + CString::new(path_buf.to_string_lossy().as_bytes()).unwrap() + }); + llvm::LLVMRustConfigurePassManagerBuilder( builder, opt_level, @@ -777,14 +793,15 @@ fn create_msvc_imps( return } // The x86 ABI seems to require that leading underscores are added to symbol - // names, so we need an extra underscore on 32-bit. There's also a leading + // names, so we need an extra underscore on x86. There's also a leading // '\x01' here which disables LLVM's symbol mangling (e.g., no extra // underscores added in front). - let prefix = if cgcx.target_pointer_width == "32" { + let prefix = if cgcx.target_arch == "x86" { "\x01__imp__" } else { "\x01__imp_" }; + unsafe { let i8p_ty = Type::i8p_llcx(llcx); let globals = base::iter_globals(llmod) @@ -792,14 +809,23 @@ fn create_msvc_imps( llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage && llvm::LLVMIsDeclaration(val) == 0 }) - .map(move |val| { + .filter_map(|val| { + // Exclude some symbols that we know are not Rust symbols. let name = CStr::from_ptr(llvm::LLVMGetValueName(val)); + if ignored(name.to_bytes()) { + None + } else { + Some((val, name)) + } + }) + .map(move |(val, name)| { let mut imp_name = prefix.as_bytes().to_vec(); imp_name.extend(name.to_bytes()); let imp_name = CString::new(imp_name).unwrap(); (imp_name, val) }) .collect::>(); + for (imp_name, val) in globals { let imp = llvm::LLVMAddGlobal(llmod, i8p_ty, @@ -808,4 +834,10 @@ fn create_msvc_imps( llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage); } } + + // Use this function to exclude certain symbols from `__imp` generation. + fn ignored(symbol_name: &[u8]) -> bool { + // These are symbols generated by LLVM's profiling instrumentation + symbol_name.starts_with(b"__llvm_profile_") + } } diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 1dac1557707c9..04645dacfec58 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -13,23 +13,21 @@ //! but one `llvm::Type` corresponds to many `Ty`s; for instance, `tup(int, int, //! int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`. -use super::ModuleLlvm; +use super::{LlvmCodegenBackend, ModuleLlvm}; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; use rustc_codegen_ssa::base::maybe_create_entry_wrapper; -use super::LlvmCodegenBackend; use crate::llvm; use crate::metadata; use crate::builder::Builder; use crate::common; use crate::context::CodegenCx; -use crate::monomorphize::partitioning::CodegenUnitExt; use rustc::dep_graph; -use rustc::mir::mono::{Linkage, Visibility, Stats}; +use rustc::mir::mono::{Linkage, Visibility}; use rustc::middle::cstore::{EncodedMetadata}; use rustc::ty::TyCtxt; use rustc::middle::exported_symbols; -use rustc::session::config::{self, DebugInfo}; +use rustc::session::config::DebugInfo; use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_data_structures::small_c_str::SmallCStr; @@ -43,47 +41,16 @@ use rustc::hir::CodegenFnAttrs; use crate::value::Value; - -pub fn write_metadata<'a, 'gcx>( - tcx: TyCtxt<'a, 'gcx, 'gcx>, - llvm_module: &mut ModuleLlvm -) -> EncodedMetadata { +pub fn write_compressed_metadata<'tcx>( + tcx: TyCtxt<'tcx>, + metadata: &EncodedMetadata, + llvm_module: &mut ModuleLlvm, +) { use std::io::Write; use flate2::Compression; use flate2::write::DeflateEncoder; let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod()); - - #[derive(PartialEq, Eq, PartialOrd, Ord)] - enum MetadataKind { - None, - Uncompressed, - Compressed - } - - let kind = tcx.sess.crate_types.borrow().iter().map(|ty| { - match *ty { - config::CrateType::Executable | - config::CrateType::Staticlib | - config::CrateType::Cdylib => MetadataKind::None, - - config::CrateType::Rlib => MetadataKind::Uncompressed, - - config::CrateType::Dylib | - config::CrateType::ProcMacro => MetadataKind::Compressed, - } - }).max().unwrap_or(MetadataKind::None); - - if kind == MetadataKind::None { - return EncodedMetadata::new(); - } - - let metadata = tcx.encode_metadata(); - if kind == MetadataKind::Uncompressed { - return metadata; - } - - assert!(kind == MetadataKind::Compressed); let mut compressed = tcx.metadata_encoding_version(); DeflateEncoder::new(&mut compressed, Compression::fast()) .write_all(&metadata.raw_data).unwrap(); @@ -108,7 +75,6 @@ pub fn write_metadata<'a, 'gcx>( let directive = CString::new(directive).unwrap(); llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr()) } - return metadata; } pub struct ValueIter<'ll> { @@ -137,17 +103,17 @@ pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> { } } -pub fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - cgu_name: InternedString) - -> Stats { +pub fn compile_codegen_unit(tcx: TyCtxt<'tcx>, cgu_name: InternedString) { let start_time = Instant::now(); let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); - let ((stats, module), _) = tcx.dep_graph.with_task(dep_node, - tcx, - cgu_name, - module_codegen, - dep_graph::hash_result); + let (module, _) = tcx.dep_graph.with_task( + dep_node, + tcx, + cgu_name, + module_codegen, + dep_graph::hash_result, + ); let time_to_codegen = start_time.elapsed(); // We assume that the cost to run LLVM on a CGU is proportional to @@ -156,18 +122,15 @@ pub fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, time_to_codegen.subsec_nanos() as u64; submit_codegened_module_to_llvm(&LlvmCodegenBackend(()), tcx, module, cost); - return stats; - - fn module_codegen<'ll, 'tcx>( - tcx: TyCtxt<'ll, 'tcx, 'tcx>, - cgu_name: InternedString) - -> (Stats, ModuleCodegen) - { - let backend = LlvmCodegenBackend(()); + + fn module_codegen<'tcx>( + tcx: TyCtxt<'tcx>, + cgu_name: InternedString, + ) -> ModuleCodegen { let cgu = tcx.codegen_unit(cgu_name); // Instantiate monomorphizations without filling out definitions yet... - let llvm_module = backend.new_metadata(tcx, &cgu_name.as_str()); - let stats = { + let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str()); + { let cx = CodegenCx::new(tcx, cgu, &llvm_module); let mono_items = cx.codegen_unit .items_in_deterministic_order(cx.tcx); @@ -203,15 +166,13 @@ pub fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if cx.sess().opts.debuginfo != DebugInfo::None { cx.debuginfo_finalize(); } + } - cx.consume_stats().into_inner() - }; - - (stats, ModuleCodegen { + ModuleCodegen { name: cgu_name.to_string(), module_llvm: llvm_module, kind: ModuleKind::Regular, - }) + } } } diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index d4d38a464576d..0709368ad860e 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -1,10 +1,11 @@ -use crate::llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; +use crate::llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope}; use crate::llvm::{self, False, BasicBlock}; use crate::common::Funclet; use crate::context::CodegenCx; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; +use syntax::symbol::LocalInternedString; use rustc_codegen_ssa::common::{IntPredicate, TypeKind, RealPredicate}; use rustc_codegen_ssa::MemFlags; use libc::{c_uint, c_char}; @@ -17,14 +18,16 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::base::to_immediate; use rustc_codegen_ssa::mir::operand::{OperandValue, OperandRef}; use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_target::spec::{HasTargetSpec, Target}; use std::borrow::Cow; use std::ffi::CStr; use std::ops::{Deref, Range}; use std::ptr; +use std::iter::TrustedLen; // All Builders must have an llfn associated with them #[must_use] -pub struct Builder<'a, 'll: 'a, 'tcx: 'll> { +pub struct Builder<'a, 'll, 'tcx> { pub llbuilder: &'ll mut llvm::Builder<'ll>, pub cx: &'a CodegenCx<'ll, 'tcx>, } @@ -37,12 +40,15 @@ impl Drop for Builder<'a, 'll, 'tcx> { } } -// This is a really awful way to get a zero-length c-string, but better (and a -// lot more efficient) than doing str::as_c_str("", ...) every time. -fn noname() -> *const c_char { - static CNULL: c_char = 0; - &CNULL -} +// FIXME(eddyb) use a checked constructor when they become `const fn`. +const EMPTY_C_STR: &CStr = unsafe { + CStr::from_bytes_with_nul_unchecked(b"\0") +}; + +/// Empty string, to be used where LLVM expects an instruction name, indicating +/// that the instruction is to be left unnamed (i.e. numbered, in textual IR). +// FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer. +const UNNAMED: *const c_char = EMPTY_C_STR.as_ptr(); impl BackendTypes for Builder<'_, 'll, 'tcx> { type Value = as BackendTypes>::Value; @@ -60,11 +66,23 @@ impl ty::layout::HasDataLayout for Builder<'_, '_, '_> { } impl ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.cx.tcx } } +impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.cx.param_env() + } +} + +impl HasTargetSpec for Builder<'_, '_, 'tcx> { + fn target_spec(&self) -> &Target { + &self.cx.target_spec() + } +} + impl ty::layout::LayoutOf for Builder<'_, '_, 'tcx> { type Ty = Ty<'tcx>; type TyLayout = TyLayout<'tcx>; @@ -86,6 +104,16 @@ impl HasCodegen<'tcx> for Builder<'_, 'll, 'tcx> { type CodegenCx = CodegenCx<'ll, 'tcx>; } +macro_rules! builder_methods_for_value_instructions { + ($($name:ident($($arg:ident),*) => $llvm_capi:ident),+ $(,)?) => { + $(fn $name(&mut self, $($arg: &'ll Value),*) -> &'ll Value { + unsafe { + llvm::$llvm_capi(self.llbuilder, $($arg,)* UNNAMED) + } + })+ + } +} + impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn new_block<'b>( cx: &'a CodegenCx<'ll, 'tcx>, @@ -120,66 +148,31 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { Builder::new_block(self.cx, self.llfn(), name) } - fn llfn(&self) -> &'ll Value { - unsafe { - llvm::LLVMGetBasicBlockParent(self.llbb()) - } - } - fn llbb(&self) -> &'ll BasicBlock { unsafe { llvm::LLVMGetInsertBlock(self.llbuilder) } } - fn count_insn(&self, category: &str) { - if self.sess().codegen_stats() { - self.stats.borrow_mut().n_llvm_insns += 1; - } - if self.sess().count_llvm_insns() { - *self.stats - .borrow_mut() - .llvm_insns - .entry(category.to_string()) - .or_insert(0) += 1; - } - } - - fn set_value_name(&mut self, value: &'ll Value, name: &str) { - let cname = SmallCStr::new(name); - unsafe { - llvm::LLVMSetValueName(value, cname.as_ptr()); - } - } - fn position_at_end(&mut self, llbb: &'ll BasicBlock) { unsafe { llvm::LLVMPositionBuilderAtEnd(self.llbuilder, llbb); } } - fn position_at_start(&mut self, llbb: &'ll BasicBlock) { - unsafe { - llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb); - } - } - fn ret_void(&mut self) { - self.count_insn("retvoid"); unsafe { llvm::LLVMBuildRetVoid(self.llbuilder); } } fn ret(&mut self, v: &'ll Value) { - self.count_insn("ret"); unsafe { llvm::LLVMBuildRet(self.llbuilder, v); } } fn br(&mut self, dest: &'ll BasicBlock) { - self.count_insn("br"); unsafe { llvm::LLVMBuildBr(self.llbuilder, dest); } @@ -191,7 +184,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { then_llbb: &'ll BasicBlock, else_llbb: &'ll BasicBlock, ) { - self.count_insn("condbr"); unsafe { llvm::LLVMBuildCondBr(self.llbuilder, cond, then_llbb, else_llbb); } @@ -201,10 +193,16 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { &mut self, v: &'ll Value, else_llbb: &'ll BasicBlock, - num_cases: usize, - ) -> &'ll Value { - unsafe { - llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, num_cases as c_uint) + cases: impl ExactSizeIterator + TrustedLen, + ) { + let switch = unsafe { + llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, cases.len() as c_uint) + }; + for (on_val, dest) in cases { + let on_val = self.const_uint_big(self.val_ty(v), on_val); + unsafe { + llvm::LLVMAddCase(switch, on_val, dest) + } } } @@ -216,7 +214,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { catch: &'ll BasicBlock, funclet: Option<&Funclet<'ll>>, ) -> &'ll Value { - self.count_insn("invoke"); debug!("Invoke {:?} with args ({:?})", llfn, @@ -234,225 +231,88 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { then, catch, bundle, - noname()) + UNNAMED) } } fn unreachable(&mut self) { - self.count_insn("unreachable"); unsafe { llvm::LLVMBuildUnreachable(self.llbuilder); } } - /* Arithmetic */ - fn add(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("add"); - unsafe { - llvm::LLVMBuildAdd(self.llbuilder, lhs, rhs, noname()) - } - } - - fn fadd(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("fadd"); - unsafe { - llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname()) - } + builder_methods_for_value_instructions! { + add(a, b) => LLVMBuildAdd, + fadd(a, b) => LLVMBuildFAdd, + sub(a, b) => LLVMBuildSub, + fsub(a, b) => LLVMBuildFSub, + mul(a, b) => LLVMBuildMul, + fmul(a, b) => LLVMBuildFMul, + udiv(a, b) => LLVMBuildUDiv, + exactudiv(a, b) => LLVMBuildExactUDiv, + sdiv(a, b) => LLVMBuildSDiv, + exactsdiv(a, b) => LLVMBuildExactSDiv, + fdiv(a, b) => LLVMBuildFDiv, + urem(a, b) => LLVMBuildURem, + srem(a, b) => LLVMBuildSRem, + frem(a, b) => LLVMBuildFRem, + shl(a, b) => LLVMBuildShl, + lshr(a, b) => LLVMBuildLShr, + ashr(a, b) => LLVMBuildAShr, + and(a, b) => LLVMBuildAnd, + or(a, b) => LLVMBuildOr, + xor(a, b) => LLVMBuildXor, + neg(x) => LLVMBuildNeg, + fneg(x) => LLVMBuildFNeg, + not(x) => LLVMBuildNot, + unchecked_sadd(x, y) => LLVMBuildNSWAdd, + unchecked_uadd(x, y) => LLVMBuildNUWAdd, + unchecked_ssub(x, y) => LLVMBuildNSWSub, + unchecked_usub(x, y) => LLVMBuildNUWSub, + unchecked_smul(x, y) => LLVMBuildNSWMul, + unchecked_umul(x, y) => LLVMBuildNUWMul, } fn fadd_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("fadd"); unsafe { - let instr = llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname()); + let instr = llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, UNNAMED); llvm::LLVMRustSetHasUnsafeAlgebra(instr); instr } } - fn sub(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("sub"); - unsafe { - llvm::LLVMBuildSub(self.llbuilder, lhs, rhs, noname()) - } - } - - fn fsub(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("fsub"); - unsafe { - llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname()) - } - } - fn fsub_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("fsub"); unsafe { - let instr = llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname()); + let instr = llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, UNNAMED); llvm::LLVMRustSetHasUnsafeAlgebra(instr); instr } } - fn mul(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("mul"); - unsafe { - llvm::LLVMBuildMul(self.llbuilder, lhs, rhs, noname()) - } - } - - fn fmul(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("fmul"); - unsafe { - llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname()) - } - } - fn fmul_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("fmul"); unsafe { - let instr = llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname()); + let instr = llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, UNNAMED); llvm::LLVMRustSetHasUnsafeAlgebra(instr); instr } } - - fn udiv(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("udiv"); - unsafe { - llvm::LLVMBuildUDiv(self.llbuilder, lhs, rhs, noname()) - } - } - - fn exactudiv(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("exactudiv"); - unsafe { - llvm::LLVMBuildExactUDiv(self.llbuilder, lhs, rhs, noname()) - } - } - - fn sdiv(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("sdiv"); - unsafe { - llvm::LLVMBuildSDiv(self.llbuilder, lhs, rhs, noname()) - } - } - - fn exactsdiv(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("exactsdiv"); - unsafe { - llvm::LLVMBuildExactSDiv(self.llbuilder, lhs, rhs, noname()) - } - } - - fn fdiv(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("fdiv"); - unsafe { - llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname()) - } - } - fn fdiv_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("fdiv"); unsafe { - let instr = llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname()); + let instr = llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, UNNAMED); llvm::LLVMRustSetHasUnsafeAlgebra(instr); instr } } - fn urem(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("urem"); - unsafe { - llvm::LLVMBuildURem(self.llbuilder, lhs, rhs, noname()) - } - } - - fn srem(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("srem"); - unsafe { - llvm::LLVMBuildSRem(self.llbuilder, lhs, rhs, noname()) - } - } - - fn frem(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("frem"); - unsafe { - llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname()) - } - } - fn frem_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("frem"); unsafe { - let instr = llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname()); + let instr = llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, UNNAMED); llvm::LLVMRustSetHasUnsafeAlgebra(instr); instr } } - fn shl(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("shl"); - unsafe { - llvm::LLVMBuildShl(self.llbuilder, lhs, rhs, noname()) - } - } - - fn lshr(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("lshr"); - unsafe { - llvm::LLVMBuildLShr(self.llbuilder, lhs, rhs, noname()) - } - } - - fn ashr(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("ashr"); - unsafe { - llvm::LLVMBuildAShr(self.llbuilder, lhs, rhs, noname()) - } - } - - fn and(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("and"); - unsafe { - llvm::LLVMBuildAnd(self.llbuilder, lhs, rhs, noname()) - } - } - - fn or(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("or"); - unsafe { - llvm::LLVMBuildOr(self.llbuilder, lhs, rhs, noname()) - } - } - - fn xor(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("xor"); - unsafe { - llvm::LLVMBuildXor(self.llbuilder, lhs, rhs, noname()) - } - } - - fn neg(&mut self, v: &'ll Value) -> &'ll Value { - self.count_insn("neg"); - unsafe { - llvm::LLVMBuildNeg(self.llbuilder, v, noname()) - } - } - - fn fneg(&mut self, v: &'ll Value) -> &'ll Value { - self.count_insn("fneg"); - unsafe { - llvm::LLVMBuildFNeg(self.llbuilder, v, noname()) - } - } - - fn not(&mut self, v: &'ll Value) -> &'ll Value { - self.count_insn("not"); - unsafe { - llvm::LLVMBuildNot(self.llbuilder, v, noname()) - } - } - fn checked_binop( &mut self, oop: OverflowOp, @@ -536,10 +396,9 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn dynamic_alloca(&mut self, ty: &'ll Type, name: &str, align: Align) -> &'ll Value { - self.count_insn("alloca"); unsafe { let alloca = if name.is_empty() { - llvm::LLVMBuildAlloca(self.llbuilder, ty, noname()) + llvm::LLVMBuildAlloca(self.llbuilder, ty, UNNAMED) } else { let name = SmallCStr::new(name); llvm::LLVMBuildAlloca(self.llbuilder, ty, @@ -555,10 +414,9 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { len: &'ll Value, name: &str, align: Align) -> &'ll Value { - self.count_insn("alloca"); unsafe { let alloca = if name.is_empty() { - llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, noname()) + llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, UNNAMED) } else { let name = SmallCStr::new(name); llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, @@ -570,20 +428,18 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn load(&mut self, ptr: &'ll Value, align: Align) -> &'ll Value { - self.count_insn("load"); unsafe { - let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname()); + let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, UNNAMED); llvm::LLVMSetAlignment(load, align.bytes() as c_uint); load } } fn volatile_load(&mut self, ptr: &'ll Value) -> &'ll Value { - self.count_insn("load.volatile"); unsafe { - let insn = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname()); - llvm::LLVMSetVolatile(insn, llvm::True); - insn + let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, UNNAMED); + llvm::LLVMSetVolatile(load, llvm::True); + load } } @@ -593,12 +449,11 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { order: rustc_codegen_ssa::common::AtomicOrdering, size: Size, ) -> &'ll Value { - self.count_insn("load.atomic"); unsafe { let load = llvm::LLVMRustBuildAtomicLoad( self.llbuilder, ptr, - noname(), + UNNAMED, AtomicOrdering::from_generic(order), ); // LLVM requires the alignment of atomic loads to be at least the size of the type. @@ -616,7 +471,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { assert_eq!(place.llextra.is_some(), place.layout.is_unsized()); if place.layout.is_zst() { - return OperandRef::new_zst(self.cx(), place.layout); + return OperandRef::new_zst(self, place.layout); } fn scalar_load_metadata<'a, 'll, 'tcx>( @@ -683,7 +538,37 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { OperandRef { val, layout: place.layout } } + fn write_operand_repeatedly( + mut self, + cg_elem: OperandRef<'tcx, &'ll Value>, + count: u64, + dest: PlaceRef<'tcx, &'ll Value>, + ) -> Self { + let zero = self.const_usize(0); + let count = self.const_usize(count); + let start = dest.project_index(&mut self, zero).llval; + let end = dest.project_index(&mut self, count).llval; + + let mut header_bx = self.build_sibling_block("repeat_loop_header"); + let mut body_bx = self.build_sibling_block("repeat_loop_body"); + let next_bx = self.build_sibling_block("repeat_loop_next"); + self.br(header_bx.llbb()); + let current = header_bx.phi(self.val_ty(start), &[start], &[self.llbb()]); + + let keep_going = header_bx.icmp(IntPredicate::IntNE, current, end); + header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb()); + + let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size); + cg_elem.val.store(&mut body_bx, + PlaceRef::new_sized(current, cg_elem.layout, align)); + + let next = body_bx.inbounds_gep(current, &[self.const_usize(1)]); + body_bx.br(header_bx.llbb()); + header_bx.add_incoming_to_phi(current, next, body_bx.llbb()); + + next_bx + } fn range_metadata(&mut self, load: &'ll Value, range: Range) { if self.sess().target.target.arch == "amdgpu" { @@ -727,7 +612,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { flags: MemFlags, ) -> &'ll Value { debug!("Store {:?} -> {:?} ({:?})", val, ptr, flags); - self.count_insn("store"); let ptr = self.check_store(val, ptr); unsafe { let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr); @@ -756,7 +640,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn atomic_store(&mut self, val: &'ll Value, ptr: &'ll Value, order: rustc_codegen_ssa::common::AtomicOrdering, size: Size) { debug!("Store {:?} -> {:?}", val, ptr); - self.count_insn("store.atomic"); let ptr = self.check_store(val, ptr); unsafe { let store = llvm::LLVMRustBuildAtomicStore( @@ -771,189 +654,121 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn gep(&mut self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value { - self.count_insn("gep"); unsafe { llvm::LLVMBuildGEP(self.llbuilder, ptr, indices.as_ptr(), - indices.len() as c_uint, noname()) + indices.len() as c_uint, UNNAMED) } } fn inbounds_gep(&mut self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value { - self.count_insn("inboundsgep"); unsafe { llvm::LLVMBuildInBoundsGEP( - self.llbuilder, ptr, indices.as_ptr(), indices.len() as c_uint, noname()) + self.llbuilder, ptr, indices.as_ptr(), indices.len() as c_uint, UNNAMED) + } + } + + fn struct_gep(&mut self, ptr: &'ll Value, idx: u64) -> &'ll Value { + assert_eq!(idx as c_uint as u64, idx); + unsafe { + llvm::LLVMBuildStructGEP(self.llbuilder, ptr, idx as c_uint, UNNAMED) } } /* Casts */ fn trunc(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.count_insn("trunc"); unsafe { - llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty, noname()) + llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty, UNNAMED) } } fn sext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.count_insn("sext"); unsafe { - llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty, noname()) + llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty, UNNAMED) } } fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.count_insn("fptoui"); unsafe { - llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty, noname()) + llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty, UNNAMED) } } fn fptosi(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.count_insn("fptosi"); unsafe { - llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty,noname()) + llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty,UNNAMED) } } fn uitofp(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.count_insn("uitofp"); unsafe { - llvm::LLVMBuildUIToFP(self.llbuilder, val, dest_ty, noname()) + llvm::LLVMBuildUIToFP(self.llbuilder, val, dest_ty, UNNAMED) } } fn sitofp(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.count_insn("sitofp"); unsafe { - llvm::LLVMBuildSIToFP(self.llbuilder, val, dest_ty, noname()) + llvm::LLVMBuildSIToFP(self.llbuilder, val, dest_ty, UNNAMED) } } fn fptrunc(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.count_insn("fptrunc"); unsafe { - llvm::LLVMBuildFPTrunc(self.llbuilder, val, dest_ty, noname()) + llvm::LLVMBuildFPTrunc(self.llbuilder, val, dest_ty, UNNAMED) } } fn fpext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.count_insn("fpext"); unsafe { - llvm::LLVMBuildFPExt(self.llbuilder, val, dest_ty, noname()) + llvm::LLVMBuildFPExt(self.llbuilder, val, dest_ty, UNNAMED) } } fn ptrtoint(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.count_insn("ptrtoint"); unsafe { - llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty, noname()) + llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty, UNNAMED) } } fn inttoptr(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.count_insn("inttoptr"); unsafe { - llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty, noname()) + llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty, UNNAMED) } } fn bitcast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.count_insn("bitcast"); unsafe { - llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, noname()) + llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED) } } fn intcast(&mut self, val: &'ll Value, dest_ty: &'ll Type, is_signed: bool) -> &'ll Value { - self.count_insn("intcast"); unsafe { llvm::LLVMRustBuildIntCast(self.llbuilder, val, dest_ty, is_signed) } } fn pointercast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.count_insn("pointercast"); unsafe { - llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty, noname()) + llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty, UNNAMED) } } /* Comparisons */ fn icmp(&mut self, op: IntPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("icmp"); let op = llvm::IntPredicate::from_generic(op); unsafe { - llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, noname()) + llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, UNNAMED) } } fn fcmp(&mut self, op: RealPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("fcmp"); unsafe { - llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, noname()) + llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, UNNAMED) } } /* Miscellaneous instructions */ - fn empty_phi(&mut self, ty: &'ll Type) -> &'ll Value { - self.count_insn("emptyphi"); - unsafe { - llvm::LLVMBuildPhi(self.llbuilder, ty, noname()) - } - } - - fn phi(&mut self, ty: &'ll Type, vals: &[&'ll Value], bbs: &[&'ll BasicBlock]) -> &'ll Value { - assert_eq!(vals.len(), bbs.len()); - let phi = self.empty_phi(ty); - self.count_insn("addincoming"); - unsafe { - llvm::LLVMAddIncoming(phi, vals.as_ptr(), - bbs.as_ptr(), - vals.len() as c_uint); - phi - } - } - - fn inline_asm_call(&mut self, asm: &CStr, cons: &CStr, - inputs: &[&'ll Value], output: &'ll Type, - volatile: bool, alignstack: bool, - dia: syntax::ast::AsmDialect) -> Option<&'ll Value> { - self.count_insn("inlineasm"); - - let volatile = if volatile { llvm::True } - else { llvm::False }; - let alignstack = if alignstack { llvm::True } - else { llvm::False }; - - let argtys = inputs.iter().map(|v| { - debug!("Asm Input Type: {:?}", *v); - self.cx.val_ty(*v) - }).collect::>(); - - debug!("Asm Output Type: {:?}", output); - let fty = self.type_func(&argtys[..], output); - unsafe { - // Ask LLVM to verify that the constraints are well-formed. - let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr()); - debug!("Constraint verification result: {:?}", constraints_ok); - if constraints_ok { - let v = llvm::LLVMRustInlineAsm( - fty, - asm.as_ptr(), - cons.as_ptr(), - volatile, - alignstack, - AsmDialect::from_generic(dia), - ); - Some(self.call(v, inputs, None)) - } else { - // LLVM has detected an issue with our constraints, bail out - None - } - } - } - fn memcpy(&mut self, dst: &'ll Value, dst_align: Align, src: &'ll Value, src_align: Align, size: &'ll Value, flags: MemFlags) { @@ -1011,56 +826,26 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { self.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None); } - fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("minnum"); - unsafe { llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) } - } - fn maxnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { - self.count_insn("maxnum"); - unsafe { llvm::LLVMRustBuildMaxNum(self.llbuilder, lhs, rhs) } - } - fn select( &mut self, cond: &'ll Value, then_val: &'ll Value, else_val: &'ll Value, ) -> &'ll Value { - self.count_insn("select"); unsafe { - llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, noname()) + llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, UNNAMED) } } #[allow(dead_code)] fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value { - self.count_insn("vaarg"); unsafe { - llvm::LLVMBuildVAArg(self.llbuilder, list, ty, noname()) + llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) } } fn extract_element(&mut self, vec: &'ll Value, idx: &'ll Value) -> &'ll Value { - self.count_insn("extractelement"); - unsafe { - llvm::LLVMBuildExtractElement(self.llbuilder, vec, idx, noname()) - } - } - - fn insert_element( - &mut self, vec: &'ll Value, - elt: &'ll Value, - idx: &'ll Value, - ) -> &'ll Value { - self.count_insn("insertelement"); unsafe { - llvm::LLVMBuildInsertElement(self.llbuilder, vec, elt, idx, noname()) - } - } - - fn shuffle_vector(&mut self, v1: &'ll Value, v2: &'ll Value, mask: &'ll Value) -> &'ll Value { - self.count_insn("shufflevector"); - unsafe { - llvm::LLVMBuildShuffleVector(self.llbuilder, v1, v2, mask, noname()) + llvm::LLVMBuildExtractElement(self.llbuilder, vec, idx, UNNAMED) } } @@ -1074,123 +859,37 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } - fn vector_reduce_fadd_fast(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { - self.count_insn("vector.reduce.fadd_fast"); - unsafe { - // FIXME: add a non-fast math version once - // https://bugs.llvm.org/show_bug.cgi?id=36732 - // is fixed. - let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src); - llvm::LLVMRustSetHasUnsafeAlgebra(instr); - instr - } - } - fn vector_reduce_fmul_fast(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { - self.count_insn("vector.reduce.fmul_fast"); - unsafe { - // FIXME: add a non-fast math version once - // https://bugs.llvm.org/show_bug.cgi?id=36732 - // is fixed. - let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src); - llvm::LLVMRustSetHasUnsafeAlgebra(instr); - instr - } - } - fn vector_reduce_add(&mut self, src: &'ll Value) -> &'ll Value { - self.count_insn("vector.reduce.add"); - unsafe { llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src) } - } - fn vector_reduce_mul(&mut self, src: &'ll Value) -> &'ll Value { - self.count_insn("vector.reduce.mul"); - unsafe { llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src) } - } - fn vector_reduce_and(&mut self, src: &'ll Value) -> &'ll Value { - self.count_insn("vector.reduce.and"); - unsafe { llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src) } - } - fn vector_reduce_or(&mut self, src: &'ll Value) -> &'ll Value { - self.count_insn("vector.reduce.or"); - unsafe { llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src) } - } - fn vector_reduce_xor(&mut self, src: &'ll Value) -> &'ll Value { - self.count_insn("vector.reduce.xor"); - unsafe { llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src) } - } - fn vector_reduce_fmin(&mut self, src: &'ll Value) -> &'ll Value { - self.count_insn("vector.reduce.fmin"); - unsafe { llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ false) } - } - fn vector_reduce_fmax(&mut self, src: &'ll Value) -> &'ll Value { - self.count_insn("vector.reduce.fmax"); - unsafe { llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ false) } - } - fn vector_reduce_fmin_fast(&mut self, src: &'ll Value) -> &'ll Value { - self.count_insn("vector.reduce.fmin_fast"); - unsafe { - let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ true); - llvm::LLVMRustSetHasUnsafeAlgebra(instr); - instr - } - } - fn vector_reduce_fmax_fast(&mut self, src: &'ll Value) -> &'ll Value { - self.count_insn("vector.reduce.fmax_fast"); - unsafe { - let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ true); - llvm::LLVMRustSetHasUnsafeAlgebra(instr); - instr - } - } - fn vector_reduce_min(&mut self, src: &'ll Value, is_signed: bool) -> &'ll Value { - self.count_insn("vector.reduce.min"); - unsafe { llvm::LLVMRustBuildVectorReduceMin(self.llbuilder, src, is_signed) } - } - fn vector_reduce_max(&mut self, src: &'ll Value, is_signed: bool) -> &'ll Value { - self.count_insn("vector.reduce.max"); - unsafe { llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed) } - } - fn extract_value(&mut self, agg_val: &'ll Value, idx: u64) -> &'ll Value { - self.count_insn("extractvalue"); assert_eq!(idx as c_uint as u64, idx); unsafe { - llvm::LLVMBuildExtractValue(self.llbuilder, agg_val, idx as c_uint, noname()) + llvm::LLVMBuildExtractValue(self.llbuilder, agg_val, idx as c_uint, UNNAMED) } } fn insert_value(&mut self, agg_val: &'ll Value, elt: &'ll Value, idx: u64) -> &'ll Value { - self.count_insn("insertvalue"); assert_eq!(idx as c_uint as u64, idx); unsafe { llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint, - noname()) + UNNAMED) } } fn landing_pad(&mut self, ty: &'ll Type, pers_fn: &'ll Value, num_clauses: usize) -> &'ll Value { - self.count_insn("landingpad"); unsafe { llvm::LLVMBuildLandingPad(self.llbuilder, ty, pers_fn, - num_clauses as c_uint, noname()) - } - } - - fn add_clause(&mut self, landing_pad: &'ll Value, clause: &'ll Value) { - unsafe { - llvm::LLVMAddClause(landing_pad, clause); + num_clauses as c_uint, UNNAMED) } } fn set_cleanup(&mut self, landing_pad: &'ll Value) { - self.count_insn("setcleanup"); unsafe { llvm::LLVMSetCleanup(landing_pad, llvm::True); } } fn resume(&mut self, exn: &'ll Value) -> &'ll Value { - self.count_insn("resume"); unsafe { llvm::LLVMBuildResume(self.llbuilder, exn) } @@ -1199,7 +898,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn cleanup_pad(&mut self, parent: Option<&'ll Value>, args: &[&'ll Value]) -> Funclet<'ll> { - self.count_insn("cleanuppad"); let name = const_cstr!("cleanuppad"); let ret = unsafe { llvm::LLVMRustBuildCleanupPad(self.llbuilder, @@ -1215,7 +913,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { &mut self, funclet: &Funclet<'ll>, unwind: Option<&'ll BasicBlock>, ) -> &'ll Value { - self.count_insn("cleanupret"); let ret = unsafe { llvm::LLVMRustBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind) }; @@ -1225,7 +922,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn catch_pad(&mut self, parent: &'ll Value, args: &[&'ll Value]) -> Funclet<'ll> { - self.count_insn("catchpad"); let name = const_cstr!("catchpad"); let ret = unsafe { llvm::LLVMRustBuildCatchPad(self.llbuilder, parent, @@ -1235,21 +931,12 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { Funclet::new(ret.expect("LLVM does not have support for catchpad")) } - fn catch_ret(&mut self, funclet: &Funclet<'ll>, unwind: &'ll BasicBlock) -> &'ll Value { - self.count_insn("catchret"); - let ret = unsafe { - llvm::LLVMRustBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) - }; - ret.expect("LLVM does not have support for catchret") - } - fn catch_switch( &mut self, parent: Option<&'ll Value>, unwind: Option<&'ll BasicBlock>, num_handlers: usize, ) -> &'ll Value { - self.count_insn("catchswitch"); let name = const_cstr!("catchswitch"); let ret = unsafe { llvm::LLVMRustBuildCatchSwitch(self.llbuilder, parent, unwind, @@ -1326,29 +1013,222 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } - fn add_case(&mut self, s: &'ll Value, on_val: &'ll Value, dest: &'ll BasicBlock) { + fn set_invariant_load(&mut self, load: &'ll Value) { unsafe { - llvm::LLVMAddCase(s, on_val, dest) + llvm::LLVMSetMetadata(load, llvm::MD_invariant_load as c_uint, + llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0)); } } - fn add_incoming_to_phi(&mut self, phi: &'ll Value, val: &'ll Value, bb: &'ll BasicBlock) { - self.count_insn("addincoming"); + fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) { + self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size); + } + + fn lifetime_end(&mut self, ptr: &'ll Value, size: Size) { + self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size); + } + + fn call( + &mut self, + llfn: &'ll Value, + args: &[&'ll Value], + funclet: Option<&Funclet<'ll>>, + ) -> &'ll Value { + + debug!("Call {:?} with args ({:?})", + llfn, + args); + + let args = self.check_call("call", llfn, args); + let bundle = funclet.map(|funclet| funclet.bundle()); + let bundle = bundle.as_ref().map(|b| &*b.raw); + unsafe { - llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint); + llvm::LLVMRustBuildCall( + self.llbuilder, + llfn, + args.as_ptr() as *const &llvm::Value, + args.len() as c_uint, + bundle, UNNAMED + ) } } - fn set_invariant_load(&mut self, load: &'ll Value) { + fn zext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { unsafe { - llvm::LLVMSetMetadata(load, llvm::MD_invariant_load as c_uint, - llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0)); + llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty, UNNAMED) + } + } + + + fn cx(&self) -> &CodegenCx<'ll, 'tcx> { + self.cx + } + + unsafe fn delete_basic_block(&mut self, bb: &'ll BasicBlock) { + llvm::LLVMDeleteBasicBlock(bb); + } + + fn do_not_inline(&mut self, llret: &'ll Value) { + llvm::Attribute::NoInline.apply_callsite(llvm::AttributePlace::Function, llret); + } +} + +impl StaticBuilderMethods for Builder<'a, 'll, 'tcx> { + fn get_static(&mut self, def_id: DefId) -> &'ll Value { + // Forward to the `get_static` method of `CodegenCx` + self.cx().get_static(def_id) + } + + fn static_panic_msg( + &mut self, + msg: Option, + filename: LocalInternedString, + line: Self::Value, + col: Self::Value, + kind: &str, + ) -> Self::Value { + let align = self.tcx.data_layout.aggregate_align.abi + .max(self.tcx.data_layout.i32_align.abi) + .max(self.tcx.data_layout.pointer_align.abi); + + let filename = self.const_str_slice(filename); + + let with_msg_components; + let without_msg_components; + + let components = if let Some(msg) = msg { + let msg = self.const_str_slice(msg); + with_msg_components = [msg, filename, line, col]; + &with_msg_components as &[_] + } else { + without_msg_components = [filename, line, col]; + &without_msg_components as &[_] + }; + + let struct_ = self.const_struct(&components, false); + self.static_addr_of(struct_, align, Some(kind)) + } +} + +impl Builder<'a, 'll, 'tcx> { + pub fn llfn(&self) -> &'ll Value { + unsafe { + llvm::LLVMGetBasicBlockParent(self.llbb()) + } + } + + fn position_at_start(&mut self, llbb: &'ll BasicBlock) { + unsafe { + llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb); + } + } + + pub fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { + unsafe { llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) } + } + + pub fn maxnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { + unsafe { llvm::LLVMRustBuildMaxNum(self.llbuilder, lhs, rhs) } + } + + pub fn insert_element( + &mut self, vec: &'ll Value, + elt: &'ll Value, + idx: &'ll Value, + ) -> &'ll Value { + unsafe { + llvm::LLVMBuildInsertElement(self.llbuilder, vec, elt, idx, UNNAMED) + } + } + + pub fn shuffle_vector( + &mut self, + v1: &'ll Value, + v2: &'ll Value, + mask: &'ll Value, + ) -> &'ll Value { + unsafe { + llvm::LLVMBuildShuffleVector(self.llbuilder, v1, v2, mask, UNNAMED) + } + } + + pub fn vector_reduce_fadd_fast(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { + unsafe { + // FIXME: add a non-fast math version once + // https://bugs.llvm.org/show_bug.cgi?id=36732 + // is fixed. + let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src); + llvm::LLVMRustSetHasUnsafeAlgebra(instr); + instr + } + } + pub fn vector_reduce_fmul_fast(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { + unsafe { + // FIXME: add a non-fast math version once + // https://bugs.llvm.org/show_bug.cgi?id=36732 + // is fixed. + let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src); + llvm::LLVMRustSetHasUnsafeAlgebra(instr); + instr + } + } + pub fn vector_reduce_add(&mut self, src: &'ll Value) -> &'ll Value { + unsafe { llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src) } + } + pub fn vector_reduce_mul(&mut self, src: &'ll Value) -> &'ll Value { + unsafe { llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src) } + } + pub fn vector_reduce_and(&mut self, src: &'ll Value) -> &'ll Value { + unsafe { llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src) } + } + pub fn vector_reduce_or(&mut self, src: &'ll Value) -> &'ll Value { + unsafe { llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src) } + } + pub fn vector_reduce_xor(&mut self, src: &'ll Value) -> &'ll Value { + unsafe { llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src) } + } + pub fn vector_reduce_fmin(&mut self, src: &'ll Value) -> &'ll Value { + unsafe { llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ false) } + } + pub fn vector_reduce_fmax(&mut self, src: &'ll Value) -> &'ll Value { + unsafe { llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ false) } + } + pub fn vector_reduce_fmin_fast(&mut self, src: &'ll Value) -> &'ll Value { + unsafe { + let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ true); + llvm::LLVMRustSetHasUnsafeAlgebra(instr); + instr + } + } + pub fn vector_reduce_fmax_fast(&mut self, src: &'ll Value) -> &'ll Value { + unsafe { + let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ true); + llvm::LLVMRustSetHasUnsafeAlgebra(instr); + instr + } + } + pub fn vector_reduce_min(&mut self, src: &'ll Value, is_signed: bool) -> &'ll Value { + unsafe { llvm::LLVMRustBuildVectorReduceMin(self.llbuilder, src, is_signed) } + } + pub fn vector_reduce_max(&mut self, src: &'ll Value, is_signed: bool) -> &'ll Value { + unsafe { llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed) } + } + + pub fn add_clause(&mut self, landing_pad: &'ll Value, clause: &'ll Value) { + unsafe { + llvm::LLVMAddClause(landing_pad, clause); } } - fn check_store<'b>(&mut self, - val: &'ll Value, - ptr: &'ll Value) -> &'ll Value { + pub fn catch_ret(&mut self, funclet: &Funclet<'ll>, unwind: &'ll BasicBlock) -> &'ll Value { + let ret = unsafe { + llvm::LLVMRustBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) + }; + ret.expect("LLVM does not have support for catchret") + } + + fn check_store(&mut self, val: &'ll Value, ptr: &'ll Value) -> &'ll Value { let dest_ptr_ty = self.cx.val_ty(ptr); let stored_ty = self.cx.val_ty(val); let stored_ptr_ty = self.cx.type_ptr_to(stored_ty); @@ -1407,76 +1287,12 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { Cow::Owned(casted_args) } - fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) { - self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size); - } - - fn lifetime_end(&mut self, ptr: &'ll Value, size: Size) { - self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size); - } - - fn call( - &mut self, - llfn: &'ll Value, - args: &[&'ll Value], - funclet: Option<&Funclet<'ll>>, - ) -> &'ll Value { - self.count_insn("call"); - - debug!("Call {:?} with args ({:?})", - llfn, - args); - - let args = self.check_call("call", llfn, args); - let bundle = funclet.map(|funclet| funclet.bundle()); - let bundle = bundle.as_ref().map(|b| &*b.raw); - + pub fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value { unsafe { - llvm::LLVMRustBuildCall( - self.llbuilder, - llfn, - args.as_ptr() as *const &llvm::Value, - args.len() as c_uint, - bundle, noname() - ) + llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) } } - fn zext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { - self.count_insn("zext"); - unsafe { - llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty, noname()) - } - } - - fn struct_gep(&mut self, ptr: &'ll Value, idx: u64) -> &'ll Value { - self.count_insn("structgep"); - assert_eq!(idx as c_uint as u64, idx); - unsafe { - llvm::LLVMBuildStructGEP(self.llbuilder, ptr, idx as c_uint, noname()) - } - } - - fn cx(&self) -> &CodegenCx<'ll, 'tcx> { - self.cx - } - - unsafe fn delete_basic_block(&mut self, bb: &'ll BasicBlock) { - llvm::LLVMDeleteBasicBlock(bb); - } - - fn do_not_inline(&mut self, llret: &'ll Value) { - llvm::Attribute::NoInline.apply_callsite(llvm::AttributePlace::Function, llret); - } -} - -impl StaticBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { - fn get_static(&self, def_id: DefId) -> &'ll Value { - self.cx().get_static(def_id) - } -} - -impl Builder<'a, 'll, 'tcx> { fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) { if self.cx.sess().opts.optimize == config::OptLevel::No { return; @@ -1492,4 +1308,23 @@ impl Builder<'a, 'll, 'tcx> { let ptr = self.pointercast(ptr, self.cx.type_i8p()); self.call(lifetime_intrinsic, &[self.cx.const_u64(size), ptr], None); } + + fn phi(&mut self, ty: &'ll Type, vals: &[&'ll Value], bbs: &[&'ll BasicBlock]) -> &'ll Value { + assert_eq!(vals.len(), bbs.len()); + let phi = unsafe { + llvm::LLVMBuildPhi(self.llbuilder, ty, UNNAMED) + }; + unsafe { + llvm::LLVMAddIncoming(phi, vals.as_ptr(), + bbs.as_ptr(), + vals.len() as c_uint); + phi + } + } + + fn add_incoming_to_phi(&mut self, phi: &'ll Value, val: &'ll Value, bb: &'ll BasicBlock) { + unsafe { + llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint); + } + } } diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index 43a5767e5c68d..2c0a6f631b739 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -6,12 +6,11 @@ use crate::attributes; use crate::llvm; -use crate::monomorphize::Instance; use crate::context::CodegenCx; use crate::value::Value; use rustc_codegen_ssa::traits::*; -use rustc::ty::TypeFoldable; +use rustc::ty::{TypeFoldable, Instance}; use rustc::ty::layout::{LayoutOf, HasTyCtxt}; /// Codegens a reference to a fn/method item, monomorphizing and @@ -113,7 +112,7 @@ pub fn get_fn( unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); - let is_generic = instance.substs.types().next().is_some(); + let is_generic = instance.substs.non_erasable_generics().next().is_some(); if is_generic { // This is a monomorphization. Its expected visibility depends diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs index 4bd036ea3b17a..f21f203fcc99f 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/src/librustc_codegen_llvm/common.rs @@ -11,8 +11,8 @@ use crate::value::Value; use rustc_codegen_ssa::traits::*; use crate::consts::const_alloc_to_llvm; -use rustc::ty::layout::{HasDataLayout, LayoutOf, self, TyLayout, Size}; -use rustc::mir::interpret::{Scalar, AllocKind, Allocation}; +use rustc::ty::layout::{HasDataLayout, LayoutOf, self, TyLayout, Size, Align}; +use rustc::mir::interpret::{Scalar, GlobalAlloc, Allocation}; use rustc_codegen_ssa::mir::place::PlaceRef; use libc::{c_uint, c_char}; @@ -93,6 +93,100 @@ impl BackendTypes for CodegenCx<'ll, 'tcx> { type DIScope = &'ll llvm::debuginfo::DIScope; } +impl CodegenCx<'ll, 'tcx> { + pub fn const_fat_ptr( + &self, + ptr: &'ll Value, + meta: &'ll Value + ) -> &'ll Value { + assert_eq!(abi::FAT_PTR_ADDR, 0); + assert_eq!(abi::FAT_PTR_EXTRA, 1); + self.const_struct(&[ptr, meta], false) + } + + pub fn const_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value { + unsafe { + return llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint); + } + } + + pub fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value { + unsafe { + return llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint); + } + } + + pub fn const_bytes(&self, bytes: &[u8]) -> &'ll Value { + bytes_in_context(self.llcx, bytes) + } + + fn const_cstr( + &self, + s: LocalInternedString, + null_terminated: bool, + ) -> &'ll Value { + unsafe { + if let Some(&llval) = self.const_cstr_cache.borrow().get(&s) { + return llval; + } + + let sc = llvm::LLVMConstStringInContext(self.llcx, + s.as_ptr() as *const c_char, + s.len() as c_uint, + !null_terminated as Bool); + let sym = self.generate_local_symbol_name("str"); + let g = self.define_global(&sym[..], self.val_ty(sc)).unwrap_or_else(||{ + bug!("symbol `{}` is already defined", sym); + }); + llvm::LLVMSetInitializer(g, sc); + llvm::LLVMSetGlobalConstant(g, True); + llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage); + + self.const_cstr_cache.borrow_mut().insert(s, g); + g + } + } + + pub fn const_str_slice(&self, s: LocalInternedString) -> &'ll Value { + let len = s.len(); + let cs = consts::ptrcast(self.const_cstr(s, false), + self.type_ptr_to(self.layout_of(self.tcx.mk_str()).llvm_type(self))); + self.const_fat_ptr(cs, self.const_usize(len as u64)) + } + + pub fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value { + unsafe { + assert_eq!(idx as c_uint as u64, idx); + let us = &[idx as c_uint]; + let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint); + + debug!("const_get_elt(v={:?}, idx={}, r={:?})", + v, idx, r); + + r + } + } + + pub fn const_get_real(&self, v: &'ll Value) -> Option<(f64, bool)> { + unsafe { + if self.is_const_real(v) { + let mut loses_info: llvm::Bool = ::std::mem::uninitialized(); + let r = llvm::LLVMConstRealGetDouble(v, &mut loses_info); + let loses_info = if loses_info == 1 { true } else { false }; + Some((r, loses_info)) + } else { + None + } + } + } + + fn is_const_real(&self, v: &'ll Value) -> bool { + unsafe { + llvm::LLVMIsAConstantFP(v).is_some() + } + } +} + impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn const_null(&self, t: &'ll Type) -> &'ll Value { unsafe { @@ -155,50 +249,6 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.const_uint(self.type_i8(), i as u64) } - fn const_cstr( - &self, - s: LocalInternedString, - null_terminated: bool, - ) -> &'ll Value { - unsafe { - if let Some(&llval) = self.const_cstr_cache.borrow().get(&s) { - return llval; - } - - let sc = llvm::LLVMConstStringInContext(self.llcx, - s.as_ptr() as *const c_char, - s.len() as c_uint, - !null_terminated as Bool); - let sym = self.generate_local_symbol_name("str"); - let g = self.define_global(&sym[..], self.val_ty(sc)).unwrap_or_else(||{ - bug!("symbol `{}` is already defined", sym); - }); - llvm::LLVMSetInitializer(g, sc); - llvm::LLVMSetGlobalConstant(g, True); - llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage); - - self.const_cstr_cache.borrow_mut().insert(s, g); - g - } - } - - fn const_str_slice(&self, s: LocalInternedString) -> &'ll Value { - let len = s.len(); - let cs = consts::ptrcast(self.const_cstr(s, false), - self.type_ptr_to(self.layout_of(self.tcx.mk_str()).llvm_type(self))); - self.const_fat_ptr(cs, self.const_usize(len as u64)) - } - - fn const_fat_ptr( - &self, - ptr: &'ll Value, - meta: &'ll Value - ) -> &'ll Value { - assert_eq!(abi::FAT_PTR_ADDR, 0); - assert_eq!(abi::FAT_PTR_EXTRA, 1); - self.const_struct(&[ptr, meta], false) - } - fn const_struct( &self, elts: &[&'ll Value], @@ -207,48 +257,6 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { struct_in_context(self.llcx, elts, packed) } - fn const_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value { - unsafe { - return llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint); - } - } - - fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value { - unsafe { - return llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint); - } - } - - fn const_bytes(&self, bytes: &[u8]) -> &'ll Value { - bytes_in_context(self.llcx, bytes) - } - - fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value { - unsafe { - assert_eq!(idx as c_uint as u64, idx); - let us = &[idx as c_uint]; - let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint); - - debug!("const_get_elt(v={:?}, idx={}, r={:?})", - v, idx, r); - - r - } - } - - fn const_get_real(&self, v: &'ll Value) -> Option<(f64, bool)> { - unsafe { - if self.is_const_real(v) { - let mut loses_info: llvm::Bool = ::std::mem::uninitialized(); - let r = llvm::LLVMConstRealGetDouble(v, &mut loses_info); - let loses_info = if loses_info == 1 { true } else { false }; - Some((r, loses_info)) - } else { - None - } - } - } - fn const_to_uint(&self, v: &'ll Value) -> u64 { unsafe { llvm::LLVMConstIntGetZExtValue(v) @@ -261,12 +269,6 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn is_const_real(&self, v: &'ll Value) -> bool { - unsafe { - llvm::LLVMIsAConstantFP(v).is_some() - } - } - fn const_to_opt_u128(&self, v: &'ll Value, sign_ext: bool) -> Option { unsafe { if self.is_const_integral(v) { @@ -292,13 +294,13 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { ) -> &'ll Value { let bitsize = if layout.is_bool() { 1 } else { layout.value.size(self).bits() }; match cv { - Scalar::Bits { size: 0, .. } => { + Scalar::Raw { size: 0, .. } => { assert_eq!(0, layout.value.size(self).bytes()); self.const_undef(self.type_ix(0)) }, - Scalar::Bits { bits, size } => { + Scalar::Raw { data, size } => { assert_eq!(size as u64, layout.value.size(self).bytes()); - let llval = self.const_uint_big(self.type_ix(bitsize), bits); + let llval = self.const_uint_big(self.type_ix(bitsize), data); if layout.value == layout::Pointer { unsafe { llvm::LLVMConstIntToPtr(llval, llty) } } else { @@ -308,7 +310,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { Scalar::Ptr(ptr) => { let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id); let base_addr = match alloc_kind { - Some(AllocKind::Memory(alloc)) => { + Some(GlobalAlloc::Memory(alloc)) => { let init = const_alloc_to_llvm(self, alloc); if alloc.mutability == Mutability::Mutable { self.static_addr_of_mut(init, alloc.align, None) @@ -316,11 +318,11 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.static_addr_of(init, alloc.align, None) } } - Some(AllocKind::Function(fn_instance)) => { + Some(GlobalAlloc::Function(fn_instance)) => { self.get_fn(fn_instance) } - Some(AllocKind::Static(def_id)) => { - assert!(self.tcx.is_static(def_id).is_some()); + Some(GlobalAlloc::Static(def_id)) => { + assert!(self.tcx.is_static(def_id)); self.get_static(def_id) } None => bug!("missing allocation {:?}", ptr.alloc_id), @@ -342,11 +344,12 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn from_const_alloc( &self, layout: TyLayout<'tcx>, + align: Align, alloc: &Allocation, offset: Size, ) -> PlaceRef<'tcx, &'ll Value> { let init = const_alloc_to_llvm(self, alloc); - let base_addr = self.static_addr_of(init, layout.align.abi, None); + let base_addr = self.static_addr_of(init, align, None); let llval = unsafe { llvm::LLVMConstInBoundsGEP( self.const_bitcast(base_addr, self.type_i8p()), @@ -354,7 +357,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { 1, )}; let llval = self.const_bitcast(llval, self.type_ptr_to(layout.llvm_type(self))); - PlaceRef::new_sized(llval, layout, alloc.align) + PlaceRef::new_sized(llval, layout, align) } fn const_ptrcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index 4c88d4f0e63ca..e02d14a151e62 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -1,8 +1,6 @@ use crate::llvm::{self, SetUnnamedAddr, True}; use crate::debuginfo; -use crate::monomorphize::MonoItem; use crate::common::CodegenCx; -use crate::monomorphize::Instance; use crate::base; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; @@ -11,11 +9,13 @@ use libc::c_uint; use rustc::hir::def_id::DefId; use rustc::mir::interpret::{ConstValue, Allocation, read_target_uint, Pointer, ErrorHandled, GlobalId}; +use rustc::mir::mono::MonoItem; use rustc::hir::Node; use syntax_pos::Span; use rustc_target::abi::HasDataLayout; +use syntax::symbol::sym; use syntax_pos::symbol::LocalInternedString; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, Instance}; use rustc_codegen_ssa::traits::*; use rustc::ty::layout::{self, Size, Align, LayoutOf}; @@ -71,7 +71,11 @@ pub fn codegen_static_initializer( let static_ = cx.tcx.const_eval(param_env.and(cid))?; let alloc = match static_.val { - ConstValue::ByRef(ptr, alloc) if ptr.offset.bytes() == 0 => alloc, + ConstValue::ByRef { + offset, align, alloc, + } if offset.bytes() == 0 && align == alloc.align => { + alloc + }, _ => bug!("static const eval returned {:#?}", static_), }; Ok((const_alloc_to_llvm(cx, alloc), alloc)) @@ -101,7 +105,7 @@ fn check_and_apply_linkage( attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: LocalInternedString, - span: Option + span: Span ) -> &'ll Value { let llty = cx.layout_of(ty).llvm_type(cx); if let Some(linkage) = attrs.linkage { @@ -115,11 +119,8 @@ fn check_and_apply_linkage( let llty2 = if let ty::RawPtr(ref mt) = ty.sty { cx.layout_of(mt.ty).llvm_type(cx) } else { - if let Some(span) = span { - cx.sess().span_fatal(span, "must have type `*const T` or `*mut T`") - } else { - bug!("must have type `*const T` or `*mut T`") - } + cx.sess().span_fatal( + span, "must have type `*const T` or `*mut T` due to `#[linkage]` attribute") }; unsafe { // Declare a symbol `foo` with the desired linkage. @@ -135,14 +136,7 @@ fn check_and_apply_linkage( let mut real_name = "_rust_extern_with_linkage_".to_string(); real_name.push_str(&sym); let g2 = cx.define_global(&real_name, llty).unwrap_or_else(||{ - if let Some(span) = span { - cx.sess().span_fatal( - span, - &format!("symbol `{}` is already defined", &sym) - ) - } else { - bug!("symbol `{}` is already defined", &sym) - } + cx.sess().span_fatal(span, &format!("symbol `{}` is already defined", &sym)) }); llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); @@ -213,7 +207,7 @@ impl CodegenCx<'ll, 'tcx> { debug!("get_static: sym={} instance={:?}", sym, instance); - let g = if let Some(id) = self.tcx.hir().as_local_node_id(def_id) { + let g = if let Some(id) = self.tcx.hir().as_local_hir_id(def_id) { let llty = self.layout_of(ty).llvm_type(self); let (g, attrs) = match self.tcx.hir().get(id) { @@ -239,7 +233,7 @@ impl CodegenCx<'ll, 'tcx> { ref attrs, span, node: hir::ForeignItemKind::Static(..), .. }) => { let fn_attrs = self.tcx.codegen_fn_attrs(def_id); - (check_and_apply_linkage(&self, &fn_attrs, ty, sym, Some(span)), attrs) + (check_and_apply_linkage(&self, &fn_attrs, ty, sym, span), attrs) } item => bug!("get_static: expected static, found {:?}", item) @@ -248,7 +242,7 @@ impl CodegenCx<'ll, 'tcx> { debug!("get_static: sym={} attrs={:?}", sym, attrs); for attr in attrs { - if attr.check_name("thread_local") { + if attr.check_name(sym::thread_local) { llvm::set_thread_local_mode(g, self.tls_model); } } @@ -259,7 +253,8 @@ impl CodegenCx<'ll, 'tcx> { debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id)); let attrs = self.tcx.codegen_fn_attrs(def_id); - let g = check_and_apply_linkage(&self, &attrs, ty, sym, None); + let span = self.tcx.def_span(def_id); + let g = check_and_apply_linkage(&self, &attrs, ty, sym, span); // Thread-local statics in some other crate need to *always* be linked // against in a thread-local fashion, so we need to be sure to apply the diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 23e3a8425d370..6a61b180de430 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -1,24 +1,22 @@ use crate::attributes; use crate::llvm; use crate::debuginfo; -use crate::monomorphize::Instance; use crate::value::Value; use rustc::dep_graph::DepGraphSafe; use rustc::hir; -use crate::monomorphize::partitioning::CodegenUnit; use crate::type_::Type; -use crate::type_of::PointeeInfo; use rustc_codegen_ssa::traits::*; -use libc::c_uint; use rustc_data_structures::base_n; use rustc_data_structures::small_c_str::SmallCStr; -use rustc::mir::mono::Stats; +use rustc::mir::mono::CodegenUnit; use rustc::session::config::{self, DebugInfo}; use rustc::session::Session; -use rustc::ty::layout::{LayoutError, LayoutOf, Size, TyLayout, VariantIdx}; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::layout::{ + LayoutError, LayoutOf, PointeeInfo, Size, TyLayout, VariantIdx, HasParamEnv +}; +use rustc::ty::{self, Ty, TyCtxt, Instance}; use rustc::util::nodemap::FxHashMap; use rustc_target::spec::{HasTargetSpec, Target}; use rustc_codegen_ssa::callee::resolve_and_get_fn; @@ -36,22 +34,21 @@ use crate::abi::Abi; /// There is one `CodegenCx` per compilation unit. Each one has its own LLVM /// `llvm::Context` so that several compilation units may be optimized in parallel. /// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`. -pub struct CodegenCx<'ll, 'tcx: 'll> { - pub tcx: TyCtxt<'ll, 'tcx, 'tcx>, +pub struct CodegenCx<'ll, 'tcx> { + pub tcx: TyCtxt<'tcx>, pub check_overflow: bool, pub use_dll_storage_attrs: bool, pub tls_model: llvm::ThreadLocalMode, pub llmod: &'ll llvm::Module, pub llcx: &'ll llvm::Context, - pub stats: RefCell, pub codegen_unit: Arc>, /// Cache instances of monomorphic and polymorphic items pub instances: RefCell, &'ll Value>>, /// Cache generated vtables - pub vtables: RefCell, Option>), &'ll Value>>, + pub vtables: + RefCell, Option>), &'ll Value>>, /// Cache of constant strings, pub const_cstr_cache: RefCell>, @@ -144,7 +141,7 @@ pub fn is_pie_binary(sess: &Session) -> bool { } pub unsafe fn create_module( - tcx: TyCtxt<'_, '_, '_>, + tcx: TyCtxt<'_>, llcx: &'ll llvm::Context, mod_name: &str, ) -> &'ll llvm::Module { @@ -154,7 +151,7 @@ pub unsafe fn create_module( // Ensure the data-layout values hardcoded remain the defaults. if sess.target.target.options.is_builtin { - let tm = crate::back::write::create_target_machine(tcx, false); + let tm = crate::back::write::create_informational_target_machine(&tcx.sess, false); llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm); llvm::LLVMRustDisposeTargetMachine(tm); @@ -210,10 +207,11 @@ pub unsafe fn create_module( } impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { - crate fn new(tcx: TyCtxt<'ll, 'tcx, 'tcx>, - codegen_unit: Arc>, - llvm_module: &'ll crate::ModuleLlvm) - -> Self { + crate fn new( + tcx: TyCtxt<'tcx>, + codegen_unit: Arc>, + llvm_module: &'ll crate::ModuleLlvm, + ) -> Self { // An interesting part of Windows which MSVC forces our hand on (and // apparently MinGW didn't) is the usage of `dllimport` and `dllexport` // attributes in LLVM IR as well as native dependencies (in C these @@ -284,7 +282,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { tls_model, llmod, llcx, - stats: RefCell::new(Stats::default()), codegen_unit, instances: Default::default(), vtables: Default::default(), @@ -326,10 +323,6 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { get_fn(self, instance) } - fn get_param(&self, llfn: &'ll Value, index: c_uint) -> &'ll Value { - llvm::get_param(llfn, index) - } - fn eh_personality(&self) -> &'ll Value { // The exception handling personality function. // @@ -377,7 +370,6 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { // Returns a Value of the "eh_unwind_resume" lang item if one is defined, // otherwise declares it as an external function. fn eh_unwind_resume(&self) -> &'ll Value { - use crate::attributes; let unwresume = &self.eh_unwind_resume; if let Some(llfn) = unwresume.get() { return llfn; @@ -413,14 +405,6 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.check_overflow } - fn stats(&self) -> &RefCell { - &self.stats - } - - fn consume_stats(self) -> RefCell { - self.stats - } - fn codegen_unit(&self) -> &Arc> { &self.codegen_unit } @@ -475,7 +459,7 @@ impl CodegenCx<'b, 'tcx> { }; let f = self.declare_cfn(name, fn_ty); llvm::SetUnnamedAddr(f, false); - self.intrinsics.borrow_mut().insert(name, f.clone()); + self.intrinsics.borrow_mut().insert(name, f); f } @@ -662,6 +646,11 @@ impl CodegenCx<'b, 'tcx> { ifn!("llvm.fabs.v4f64", fn(t_v4f64) -> t_v4f64); ifn!("llvm.fabs.v8f64", fn(t_v8f64) -> t_v8f64); + ifn!("llvm.minnum.f32", fn(t_f32, t_f32) -> t_f32); + ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64); + ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32); + ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64); + ifn!("llvm.floor.f32", fn(t_f32) -> t_f32); ifn!("llvm.floor.v2f32", fn(t_v2f32) -> t_v2f32); ifn!("llvm.floor.v4f32", fn(t_v4f32) -> t_v4f32); @@ -850,7 +839,7 @@ impl HasTargetSpec for CodegenCx<'ll, 'tcx> { } impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } } @@ -868,3 +857,9 @@ impl LayoutOf for CodegenCx<'ll, 'tcx> { }) } } + +impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx> { + ty::ParamEnv::reveal_all() + } +} diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs index c8ddf733ecf1f..8b3ed5b0c623a 100644 --- a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs +++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs @@ -5,7 +5,7 @@ use super::utils::{DIB, span_start}; use crate::llvm; use crate::llvm::debuginfo::{DIScope, DISubprogram}; use crate::common::CodegenCx; -use rustc::mir::{Mir, SourceScope}; +use rustc::mir::{Body, SourceScope}; use libc::c_uint; @@ -20,7 +20,7 @@ use syntax_pos::BytePos; /// If debuginfo is disabled, the returned vector is empty. pub fn create_mir_scopes( cx: &CodegenCx<'ll, '_>, - mir: &Mir<'_>, + mir: &Body<'_>, debug_context: &FunctionDebugContext<&'ll DISubprogram>, ) -> IndexVec> { let null_scope = MirDebugScope { @@ -55,7 +55,7 @@ pub fn create_mir_scopes( } fn make_mir_scope(cx: &CodegenCx<'ll, '_>, - mir: &Mir<'_>, + mir: &Body<'_>, has_variables: &BitSet, debug_context: &FunctionDebugContextData<&'ll DISubprogram>, scope: SourceScope, diff --git a/src/librustc_codegen_llvm/debuginfo/doc.rs b/src/librustc_codegen_llvm/debuginfo/doc.rs index cf18b995b61da..daccfc9b242f9 100644 --- a/src/librustc_codegen_llvm/debuginfo/doc.rs +++ b/src/librustc_codegen_llvm/debuginfo/doc.rs @@ -1,13 +1,13 @@ //! # Debug Info Module //! //! This module serves the purpose of generating debug symbols. We use LLVM's -//! [source level debugging](http://!llvm.org/docs/SourceLevelDebugging.html) +//! [source level debugging](https://llvm.org/docs/SourceLevelDebugging.html) //! features for generating the debug information. The general principle is //! this: //! //! Given the right metadata in the LLVM IR, the LLVM code generator is able to //! create DWARF debug symbols for the given code. The -//! [metadata](http://!llvm.org/docs/LangRef.html#metadata-type) is structured +//! [metadata](https://llvm.org/docs/LangRef.html#metadata-type) is structured //! much like DWARF *debugging information entries* (DIE), representing type //! information such as datatype layout, function signatures, block layout, //! variable location and scope information, etc. It is the purpose of this @@ -15,7 +15,7 @@ //! //! As the exact format of metadata trees may change between different LLVM //! versions, we now use LLVM -//! [DIBuilder](http://!llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html) +//! [DIBuilder](https://llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html) //! to create metadata where possible. This will hopefully ease the adaption of //! this module to future LLVM versions. //! diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs index 91496ffbe557a..04c9e93c7a527 100644 --- a/src/librustc_codegen_llvm/debuginfo/gdb.rs +++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs @@ -9,6 +9,7 @@ use rustc::session::config::DebugInfo; use rustc_codegen_ssa::traits::*; use syntax::attr; +use syntax::symbol::sym; /// Inserts a side-effect free instruction sequence that makes sure that the @@ -66,8 +67,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>) pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { let omit_gdb_pretty_printer_section = - attr::contains_name(&cx.tcx.hir().krate_attrs(), - "omit_gdb_pretty_printer_section"); + attr::contains_name(&cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section); !omit_gdb_pretty_printer_section && cx.sess().opts.debuginfo != DebugInfo::None && diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index ddcbf29da832b..fbeda43af42b0 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -22,19 +22,23 @@ use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def::CtorKind; use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; use rustc::ich::NodeIdHashingMode; +use rustc::mir::Field; +use rustc::mir::GeneratorLayout; +use rustc::mir::interpret::truncate; use rustc_data_structures::fingerprint::Fingerprint; use rustc::ty::Instance; use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; use rustc::ty::layout::{self, Align, Integer, IntegerExt, LayoutOf, - PrimitiveExt, Size, TyLayout}; + PrimitiveExt, Size, TyLayout, VariantIdx}; use rustc::ty::subst::UnpackedKind; -use rustc::session::config; +use rustc::session::config::{self, DebugInfo}; use rustc::util::nodemap::FxHashMap; use rustc_fs_util::path_to_c_string; use rustc_data_structures::small_c_str::SmallCStr; use rustc_target::abi::HasDataLayout; use libc::{c_uint, c_longlong}; +use std::collections::hash_map::Entry; use std::ffi::CString; use std::fmt::{self, Write}; use std::hash::{Hash, Hasher}; @@ -42,7 +46,7 @@ use std::iter; use std::ptr; use std::path::{Path, PathBuf}; use syntax::ast; -use syntax::symbol::{Interner, InternedString, Symbol}; +use syntax::symbol::{Interner, InternedString}; use syntax_pos::{self, Span, FileName}; impl PartialEq for llvm::Metadata { @@ -116,6 +120,32 @@ impl TypeMap<'ll, 'tcx> { } } + // Removes a Ty to metadata mapping + // This is useful when computing the metadata for a potentially + // recursive type (e.g. a function ptr of the form: + // + // fn foo() -> impl Copy { foo } + // + // This kind of type cannot be properly represented + // via LLVM debuginfo. As a workaround, + // we register a temporary Ty to metadata mapping + // for the function before we compute its actual metadata. + // If the metadata computation ends up recursing back to the + // original function, it will use the temporary mapping + // for the inner self-reference, preventing us from + // recursing forever. + // + // This function is used to remove the temporary metadata + // mapping after we've computed the actual metadata + fn remove_type( + &mut self, + type_: Ty<'tcx>, + ) { + if self.type_to_metadata.remove(type_).is_none() { + bug!("Type metadata Ty '{}' is not in the TypeMap!", type_); + } + } + // Adds a UniqueTypeId to metadata mapping to the TypeMap. The method will // fail if the mapping already exists. fn register_unique_id_with_metadata( @@ -188,6 +218,16 @@ impl TypeMap<'ll, 'tcx> { let interner_key = self.unique_id_interner.intern(&enum_variant_type_id); UniqueTypeId(interner_key) } + + // Get the unique type id string for an enum variant part. + // Variant parts are not types and shouldn't really have their own id, + // but it makes set_members_of_composite_type() simpler. + fn get_unique_type_id_str_of_enum_variant_part(&mut self, enum_type_id: UniqueTypeId) -> &str { + let variant_part_type_id = format!("{}_variant_part", + self.get_unique_type_id_as_string(enum_type_id)); + let interner_key = self.unique_id_interner.intern(&variant_part_type_id); + self.unique_id_interner.get(interner_key) + } } // A description of some recursive type. It can either be already finished (as @@ -301,9 +341,7 @@ fn fixed_vec_metadata( let (size, align) = cx.size_and_align_of(array_or_slice_type); let upper_bound = match array_or_slice_type.sty { - ty::Array(_, len) => { - len.unwrap_usize(cx.tcx) as c_longlong - } + ty::Array(_, len) => len.unwrap_usize(cx.tcx) as c_longlong, _ => -1 }; @@ -337,7 +375,7 @@ fn vec_slice_metadata( return_if_metadata_created_in_meantime!(cx, unique_type_id); - let slice_type_name = compute_debuginfo_type_name(cx, slice_ptr_type, true); + let slice_type_name = compute_debuginfo_type_name(cx.tcx, slice_ptr_type, true); let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type); let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize); @@ -440,7 +478,7 @@ fn trait_pointer_metadata( let trait_object_type = trait_object_type.unwrap_or(trait_type); let trait_type_name = - compute_debuginfo_type_name(cx, trait_object_type, false); + compute_debuginfo_type_name(cx.tcx, trait_object_type, false); let file_metadata = unknown_file_metadata(cx); @@ -596,10 +634,7 @@ pub fn type_metadata( } } ty::FnDef(..) | ty::FnPtr(_) => { - let fn_metadata = subroutine_type_metadata(cx, - unique_type_id, - t.fn_sig(cx.tcx), - usage_site_span).metadata; + if let Some(metadata) = debug_context(cx).type_map .borrow() .find_metadata_for_unique_id(unique_type_id) @@ -607,6 +642,41 @@ pub fn type_metadata( return metadata; } + // It's possible to create a self-referential + // type in Rust by using 'impl trait': + // + // fn foo() -> impl Copy { foo } + // + // See TypeMap::remove_type for more detals + // about the workaround + + let temp_type = { + unsafe { + // The choice of type here is pretty arbitrary - + // anything reading the debuginfo for a recursive + // type is going to see *somthing* weird - the only + // question is what exactly it will see + let (size, align) = cx.size_and_align_of(t); + llvm::LLVMRustDIBuilderCreateBasicType( + DIB(cx), + SmallCStr::new("").as_ptr(), + size.bits(), + align.bits() as u32, + DW_ATE_unsigned) + } + }; + + let type_map = &debug_context(cx).type_map; + type_map.borrow_mut().register_type_with_metadata(t, temp_type); + + let fn_metadata = subroutine_type_metadata(cx, + unique_type_id, + t.fn_sig(cx.tcx), + usage_site_span).metadata; + + type_map.borrow_mut().remove_type(t); + + // This is actually a function pointer, so wrap it in pointer DI MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) @@ -620,14 +690,15 @@ pub fn type_metadata( usage_site_span).finalize(cx) } ty::Generator(def_id, substs, _) => { - let upvar_tys : Vec<_> = substs.field_tys(def_id, cx.tcx).map(|t| { + let upvar_tys : Vec<_> = substs.prefix_tys(def_id, cx.tcx).map(|t| { cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t) }).collect(); - prepare_tuple_metadata(cx, - t, - &upvar_tys, - unique_type_id, - usage_site_span).finalize(cx) + prepare_enum_metadata(cx, + t, + def_id, + unique_type_id, + usage_site_span, + upvar_tys).finalize(cx) } ty::Adt(def, ..) => match def.adt_kind() { AdtKind::Struct => { @@ -647,13 +718,15 @@ pub fn type_metadata( t, def.did, unique_type_id, - usage_site_span).finalize(cx) + usage_site_span, + vec![]).finalize(cx) } }, ty::Tuple(ref elements) => { + let tys: Vec<_> = elements.iter().map(|k| k.expect_ty()).collect(); prepare_tuple_metadata(cx, t, - &elements[..], + &tys, unique_type_id, usage_site_span).finalize(cx) } @@ -712,45 +785,48 @@ pub fn file_metadata(cx: &CodegenCx<'ll, '_>, file_name, defining_crate); + let file_name = Some(file_name.to_string()); let directory = if defining_crate == LOCAL_CRATE { - &cx.sess().working_dir.0 + Some(cx.sess().working_dir.0.to_string_lossy().to_string()) } else { // If the path comes from an upstream crate we assume it has been made // independent of the compiler's working directory one way or another. - Path::new("") + None }; - - file_metadata_raw(cx, &file_name.to_string(), &directory.to_string_lossy()) + file_metadata_raw(cx, file_name, directory) } pub fn unknown_file_metadata(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile { - file_metadata_raw(cx, "", "") + file_metadata_raw(cx, None, None) } fn file_metadata_raw(cx: &CodegenCx<'ll, '_>, - file_name: &str, - directory: &str) + file_name: Option, + directory: Option) -> &'ll DIFile { - let key = (Symbol::intern(file_name), Symbol::intern(directory)); + let key = (file_name, directory); + + match debug_context(cx).created_files.borrow_mut().entry(key) { + Entry::Occupied(o) => return o.get(), + Entry::Vacant(v) => { + let (file_name, directory) = v.key(); + debug!("file_metadata: file_name: {:?}, directory: {:?}", file_name, directory); + + let file_name = SmallCStr::new( + if let Some(file_name) = file_name { &file_name } else { "" }); + let directory = SmallCStr::new( + if let Some(directory) = directory { &directory } else { "" }); + + let file_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateFile(DIB(cx), + file_name.as_ptr(), + directory.as_ptr()) + }; - if let Some(file_metadata) = debug_context(cx).created_files.borrow().get(&key) { - return *file_metadata; + v.insert(file_metadata); + file_metadata + } } - - debug!("file_metadata: file_name: {}, directory: {}", file_name, directory); - - let file_name = SmallCStr::new(file_name); - let directory = SmallCStr::new(directory); - - let file_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateFile(DIB(cx), - file_name.as_ptr(), - directory.as_ptr()) - }; - - let mut created_files = debug_context(cx).created_files.borrow_mut(); - created_files.insert(key, file_metadata); - file_metadata } fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { @@ -795,7 +871,7 @@ fn foreign_type_metadata( ) -> &'ll DIType { debug!("foreign_type_metadata: {:?}", t); - let name = compute_debuginfo_type_name(cx, t, false); + let name = compute_debuginfo_type_name(cx.tcx, t, false); create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA) } @@ -805,7 +881,7 @@ fn pointer_type_metadata( pointee_type_metadata: &'ll DIType, ) -> &'ll DIType { let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type); - let name = compute_debuginfo_type_name(cx, pointer_type, false); + let name = compute_debuginfo_type_name(cx.tcx, pointer_type, false); let name = SmallCStr::new(&name); unsafe { llvm::LLVMRustDIBuilderCreatePointerType( @@ -817,10 +893,11 @@ fn pointer_type_metadata( } } -pub fn compile_unit_metadata(tcx: TyCtxt<'_, '_, '_>, - codegen_unit_name: &str, - debug_context: &CrateDebugContext<'ll, '_>) - -> &'ll DIDescriptor { +pub fn compile_unit_metadata( + tcx: TyCtxt<'_>, + codegen_unit_name: &str, + debug_context: &CrateDebugContext<'ll, '_>, +) -> &'ll DIDescriptor { let mut name_in_debuginfo = match tcx.sess.local_crate_source_file { Some(ref path) => path.clone(), None => PathBuf::from(&*tcx.crate_name(LOCAL_CRATE).as_str()), @@ -846,7 +923,26 @@ pub fn compile_unit_metadata(tcx: TyCtxt<'_, '_, '_>, let producer = CString::new(producer).unwrap(); let flags = "\0"; let split_name = "\0"; - let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo); + + // FIXME(#60020): + // + // This should actually be + // + // ``` + // let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo); + // ``` + // + // that is, we should set LLVM's emission kind to `LineTablesOnly` if + // we are compiling with "limited" debuginfo. However, some of the + // existing tools relied on slightly more debuginfo being generated than + // would be the case with `LineTablesOnly`, and we did not want to break + // these tools in a "drive-by fix", without a good idea or plan about + // what limited debuginfo should exactly look like. So for now we keep + // the emission kind as `FullDebug`. + // + // See https://github.com/rust-lang/rust/issues/60020 for details. + let kind = DebugEmissionKind::FullDebug; + assert!(tcx.sess.opts.debuginfo != DebugInfo::None); unsafe { let file_metadata = llvm::LLVMRustDIBuilderCreateFile( @@ -924,6 +1020,31 @@ struct MemberDescription<'ll> { discriminant: Option, } +impl<'ll> MemberDescription<'ll> { + fn into_metadata(self, + cx: &CodegenCx<'ll, '_>, + composite_type_metadata: &'ll DIScope) -> &'ll DIType { + let member_name = CString::new(self.name).unwrap(); + unsafe { + llvm::LLVMRustDIBuilderCreateVariantMemberType( + DIB(cx), + composite_type_metadata, + member_name.as_ptr(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + self.size.bits(), + self.align.bits() as u32, + self.offset.bits(), + match self.discriminant { + None => None, + Some(value) => Some(cx.const_u64(value)), + }, + self.flags, + self.type_metadata) + } + } +} + // A factory for MemberDescriptions. It produces a list of member descriptions // for some record-like type. MemberDescriptionFactories are used to defer the // creation of type member descriptions in order to break cycles arising from @@ -1001,7 +1122,7 @@ fn prepare_struct_metadata( unique_type_id: UniqueTypeId, span: Span, ) -> RecursiveTypeDescription<'ll, 'tcx> { - let struct_name = compute_debuginfo_type_name(cx, struct_type, false); + let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false); let (struct_def_id, variant) = match struct_type.sty { ty::Adt(def, _) => (def.did, def.non_enum_variant()), @@ -1067,7 +1188,7 @@ fn prepare_tuple_metadata( unique_type_id: UniqueTypeId, span: Span, ) -> RecursiveTypeDescription<'ll, 'tcx> { - let tuple_name = compute_debuginfo_type_name(cx, tuple_type, false); + let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false); let struct_stub = create_struct_stub(cx, tuple_type, @@ -1123,7 +1244,7 @@ fn prepare_union_metadata( unique_type_id: UniqueTypeId, span: Span, ) -> RecursiveTypeDescription<'ll, 'tcx> { - let union_name = compute_debuginfo_type_name(cx, union_type, false); + let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false); let (union_def_id, variant) = match union_type.sty { ty::Adt(def, _) => (def.did, def.non_enum_variant()), @@ -1156,12 +1277,14 @@ fn prepare_union_metadata( // Enums //=----------------------------------------------------------------------------- -// DWARF variant support is only available starting in LLVM 7. +// DWARF variant support is only available starting in LLVM 8. // Although the earlier enum debug info output did not work properly // in all situations, it is better for the time being to continue to // sometimes emit the old style rather than emit something completely -// useless when rust is compiled against LLVM 6 or older. This -// function decides which representation will be emitted. +// useless when rust is compiled against LLVM 6 or older. LLVM 7 +// contains an early version of the DWARF variant support, and will +// crash when handling the new debug info format. This function +// decides which representation will be emitted. fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool { // On MSVC we have to use the fallback mode, because LLVM doesn't // lower variant parts to PDB. @@ -1188,7 +1311,16 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> { impl EnumMemberDescriptionFactory<'ll, 'tcx> { fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec> { - let adt = &self.enum_type.ty_adt_def().unwrap(); + let variant_info_for = |index: VariantIdx| { + match &self.enum_type.sty { + ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]), + ty::Generator(def_id, substs, _) => { + let generator_layout = cx.tcx.generator_layout(*def_id); + VariantInfo::Generator(*substs, generator_layout, index) + } + _ => bug!(), + } + }; // This will always find the metadata in the type map. let fallback = use_enum_fallback(cx); @@ -1199,12 +1331,18 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { }; match self.layout.variants { - layout::Variants::Single { .. } if adt.variants.is_empty() => vec![], layout::Variants::Single { index } => { + if let ty::Adt(adt, _) = &self.enum_type.sty { + if adt.variants.is_empty() { + return vec![]; + } + } + + let variant_info = variant_info_for(index); let (variant_type_metadata, member_description_factory) = describe_enum_variant(cx, self.layout, - &adt.variants[index], + variant_info, NoDiscriminant, self_metadata, self.span); @@ -1221,7 +1359,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { name: if fallback { String::new() } else { - adt.variants[index].ident.as_str().to_string() + variant_info.variant_name() }, type_metadata: variant_type_metadata, offset: Size::ZERO, @@ -1232,20 +1370,28 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } ] } - layout::Variants::Tagged { ref variants, .. } => { + layout::Variants::Multiple { + discr_kind: layout::DiscriminantKind::Tag, + discr_index, + ref variants, + .. + } => { let discriminant_info = if fallback { - RegularDiscriminant(self.discriminant_type_metadata - .expect("")) + RegularDiscriminant { + discr_field: Field::from(discr_index), + discr_type_metadata: self.discriminant_type_metadata.unwrap() + } } else { // This doesn't matter in this case. NoDiscriminant }; variants.iter_enumerated().map(|(i, _)| { let variant = self.layout.for_variant(cx, i); + let variant_info = variant_info_for(i); let (variant_type_metadata, member_desc_factory) = describe_enum_variant(cx, variant, - &adt.variants[i], + variant_info, discriminant_info, self_metadata, self.span); @@ -1257,29 +1403,33 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { self.enum_type, variant_type_metadata, member_descriptions); + MemberDescription { name: if fallback { String::new() } else { - adt.variants[i].ident.as_str().to_string() + variant_info.variant_name() }, type_metadata: variant_type_metadata, offset: Size::ZERO, size: self.layout.size, align: self.layout.align.abi, flags: DIFlags::FlagZero, - discriminant: Some(self.layout.ty.ty_adt_def().unwrap() - .discriminant_for_variant(cx.tcx, i) - .val as u64), + discriminant: Some( + self.layout.ty.discriminant_for_variant(cx.tcx, i).unwrap().val as u64 + ), } }).collect() } - layout::Variants::NicheFilling { - ref niche_variants, - niche_start, + layout::Variants::Multiple { + discr_kind: layout::DiscriminantKind::Niche { + ref niche_variants, + niche_start, + dataful_variant, + }, + ref discr, ref variants, - dataful_variant, - ref niche, + discr_index, } => { if fallback { let variant = self.layout.for_variant(cx, dataful_variant); @@ -1287,7 +1437,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { let (variant_type_metadata, member_description_factory) = describe_enum_variant(cx, variant, - &adt.variants[dataful_variant], + variant_info_for(dataful_variant), OptimizedDiscriminant, self.containing_scope, self.span); @@ -1325,9 +1475,11 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } compute_field_path(cx, &mut name, self.layout, - self.layout.fields.offset(0), - self.layout.field(cx, 0).size); - name.push_str(&adt.variants[*niche_variants.start()].ident.as_str()); + self.layout.fields.offset(discr_index), + self.layout.field(cx, discr_index).size); + variant_info_for(*niche_variants.start()).map_struct_name(|variant_name| { + name.push_str(variant_name); + }); // Create the (singleton) list of descriptions of union members. vec![ @@ -1344,10 +1496,11 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } else { variants.iter_enumerated().map(|(i, _)| { let variant = self.layout.for_variant(cx, i); + let variant_info = variant_info_for(i); let (variant_type_metadata, member_desc_factory) = describe_enum_variant(cx, variant, - &adt.variants[i], + variant_info, OptimizedDiscriminant, self_metadata, self.span); @@ -1366,12 +1519,16 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { let value = (i.as_u32() as u128) .wrapping_sub(niche_variants.start().as_u32() as u128) .wrapping_add(niche_start); - let value = value & ((1u128 << niche.value.size(cx).bits()) - 1); + let value = truncate(value, discr.value.size(cx)); + // NOTE(eddyb) do *NOT* remove this assert, until + // we pass the full 128-bit value to LLVM, otherwise + // truncation will be silent and remain undetected. + assert_eq!(value as u64 as u128, value); Some(value as u64) }; MemberDescription { - name: adt.variants[i].ident.as_str().to_string(), + name: variant_info.variant_name(), type_metadata: variant_type_metadata, offset: Size::ZERO, size: self.layout.size, @@ -1404,6 +1561,8 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { name: name.to_string(), type_metadata: if use_enum_fallback(cx) { match self.discriminant_type_metadata { + // Discriminant is always the first field of our variant + // when using the enum fallback. Some(metadata) if i == 0 => metadata, _ => type_metadata(cx, ty, self.span) } @@ -1422,11 +1581,54 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { #[derive(Copy, Clone)] enum EnumDiscriminantInfo<'ll> { - RegularDiscriminant(&'ll DIType), + RegularDiscriminant{ discr_field: Field, discr_type_metadata: &'ll DIType }, OptimizedDiscriminant, NoDiscriminant } +#[derive(Copy, Clone)] +enum VariantInfo<'tcx> { + Adt(&'tcx ty::VariantDef), + Generator(ty::GeneratorSubsts<'tcx>, &'tcx GeneratorLayout<'tcx>, VariantIdx), +} + +impl<'tcx> VariantInfo<'tcx> { + fn map_struct_name(&self, f: impl FnOnce(&str) -> R) -> R { + match self { + VariantInfo::Adt(variant) => f(&variant.ident.as_str()), + VariantInfo::Generator(substs, _, variant_index) => + f(&substs.variant_name(*variant_index)), + } + } + + fn variant_name(&self) -> String { + match self { + VariantInfo::Adt(variant) => variant.ident.to_string(), + VariantInfo::Generator(_, _, variant_index) => { + // Since GDB currently prints out the raw discriminant along + // with every variant, make each variant name be just the value + // of the discriminant. The struct name for the variant includes + // the actual variant description. + format!("{}", variant_index.as_usize()) + } + } + } + + fn field_name(&self, i: usize) -> String { + let field_name = match self { + VariantInfo::Adt(variant) if variant.ctor_kind != CtorKind::Fn => + Some(variant.fields[i].ident.to_string()), + VariantInfo::Generator(_, generator_layout, variant_index) => { + let field = generator_layout.variant_fields[*variant_index][i.into()]; + let decl = &generator_layout.__local_debuginfo_codegen_only_do_not_use[field]; + decl.name.map(|name| name.to_string()) + } + _ => None, + }; + field_name.unwrap_or_else(|| format!("__{}", i)) + } +} + // Returns a tuple of (1) type_metadata_stub of the variant, (2) a // MemberDescriptionFactory for producing the descriptions of the // fields of the variant. This is a rudimentary version of a full @@ -1434,34 +1636,37 @@ enum EnumDiscriminantInfo<'ll> { fn describe_enum_variant( cx: &CodegenCx<'ll, 'tcx>, layout: layout::TyLayout<'tcx>, - variant: &'tcx ty::VariantDef, + variant: VariantInfo<'tcx>, discriminant_info: EnumDiscriminantInfo<'ll>, containing_scope: &'ll DIScope, span: Span, ) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) { - let variant_name = variant.ident.as_str(); - let unique_type_id = debug_context(cx).type_map - .borrow_mut() - .get_unique_type_id_of_enum_variant( - cx, - layout.ty, - &variant_name); - - let metadata_stub = create_struct_stub(cx, - layout.ty, - &variant_name, - unique_type_id, - Some(containing_scope)); + let metadata_stub = variant.map_struct_name(|variant_name| { + let unique_type_id = debug_context(cx).type_map + .borrow_mut() + .get_unique_type_id_of_enum_variant( + cx, + layout.ty, + &variant_name); + create_struct_stub(cx, + layout.ty, + &variant_name, + unique_type_id, + Some(containing_scope)) + }); // Build an array of (field name, field type) pairs to be captured in the factory closure. let (offsets, args) = if use_enum_fallback(cx) { // If this is not a univariant enum, there is also the discriminant field. let (discr_offset, discr_arg) = match discriminant_info { - RegularDiscriminant(_) => { + RegularDiscriminant { discr_field, .. } => { // We have the layout of an enum variant, we need the layout of the outer enum let enum_layout = cx.layout_of(layout.ty); - (Some(enum_layout.fields.offset(0)), - Some(("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, 0).ty))) + let offset = enum_layout.fields.offset(discr_field.as_usize()); + let args = ( + "RUST$ENUM$DISR".to_owned(), + enum_layout.field(cx, discr_field.as_usize()).ty); + (Some(offset), Some(args)) } _ => (None, None), }; @@ -1470,12 +1675,7 @@ fn describe_enum_variant( layout.fields.offset(i) })).collect(), discr_arg.into_iter().chain((0..layout.fields.count()).map(|i| { - let name = if variant.ctor_kind == CtorKind::Fn { - format!("__{}", i) - } else { - variant.fields[i].ident.to_string() - }; - (name, layout.field(cx, i).ty) + (variant.field_name(i), layout.field(cx, i).ty) })).collect() ) } else { @@ -1484,12 +1684,7 @@ fn describe_enum_variant( layout.fields.offset(i) }).collect(), (0..layout.fields.count()).map(|i| { - let name = if variant.ctor_kind == CtorKind::Fn { - format!("__{}", i) - } else { - variant.fields[i].ident.to_string() - }; - (name, layout.field(cx, i).ty) + (variant.field_name(i), layout.field(cx, i).ty) }).collect() ) }; @@ -1499,8 +1694,8 @@ fn describe_enum_variant( offsets, args, discriminant_type_metadata: match discriminant_info { - RegularDiscriminant(discriminant_type_metadata) => { - Some(discriminant_type_metadata) + RegularDiscriminant { discr_type_metadata, .. } => { + Some(discr_type_metadata) } _ => None }, @@ -1516,8 +1711,9 @@ fn prepare_enum_metadata( enum_def_id: DefId, unique_type_id: UniqueTypeId, span: Span, + outer_field_tys: Vec>, ) -> RecursiveTypeDescription<'ll, 'tcx> { - let enum_name = compute_debuginfo_type_name(cx, enum_type, false); + let enum_name = compute_debuginfo_type_name(cx.tcx, enum_type, false); let containing_scope = get_namespace_for_item(cx, enum_def_id); // FIXME: This should emit actual file metadata for the enum, but we @@ -1529,20 +1725,36 @@ fn prepare_enum_metadata( let file_metadata = unknown_file_metadata(cx); let discriminant_type_metadata = |discr: layout::Primitive| { - let def = enum_type.ty_adt_def().unwrap(); - let enumerators_metadata: Vec<_> = def.discriminants(cx.tcx) - .zip(&def.variants) - .map(|((_, discr), v)| { - let name = SmallCStr::new(&v.ident.as_str()); - unsafe { - Some(llvm::LLVMRustDIBuilderCreateEnumerator( - DIB(cx), - name.as_ptr(), - // FIXME: what if enumeration has i128 discriminant? - discr.val as u64)) - } - }) - .collect(); + let enumerators_metadata: Vec<_> = match enum_type.sty { + ty::Adt(def, _) => def + .discriminants(cx.tcx) + .zip(&def.variants) + .map(|((_, discr), v)| { + let name = SmallCStr::new(&v.ident.as_str()); + unsafe { + Some(llvm::LLVMRustDIBuilderCreateEnumerator( + DIB(cx), + name.as_ptr(), + // FIXME: what if enumeration has i128 discriminant? + discr.val as u64)) + } + }) + .collect(), + ty::Generator(_, substs, _) => substs + .variant_range(enum_def_id, cx.tcx) + .map(|variant_index| { + let name = SmallCStr::new(&substs.variant_name(variant_index)); + unsafe { + Some(llvm::LLVMRustDIBuilderCreateEnumerator( + DIB(cx), + name.as_ptr(), + // FIXME: what if enumeration has i128 discriminant? + variant_index.as_usize() as u64)) + } + }) + .collect(), + _ => bug!(), + }; let disr_type_key = (enum_def_id, discr); let cached_discriminant_type_metadata = debug_context(cx).created_enum_disr_types @@ -1555,14 +1767,18 @@ fn prepare_enum_metadata( (discr.size(cx), discr.align(cx)); let discriminant_base_type_metadata = type_metadata(cx, discr.to_ty(cx.tcx), syntax_pos::DUMMY_SP); - let discriminant_name = get_enum_discriminant_name(cx, enum_def_id).as_str(); - let name = SmallCStr::new(&discriminant_name); + let discriminant_name = match enum_type.sty { + ty::Adt(..) => SmallCStr::new(&cx.tcx.item_name(enum_def_id).as_str()), + ty::Generator(..) => SmallCStr::new(&enum_name), + _ => bug!(), + }; + let discriminant_type_metadata = unsafe { llvm::LLVMRustDIBuilderCreateEnumerationType( DIB(cx), containing_scope, - name.as_ptr(), + discriminant_name.as_ptr(), file_metadata, UNKNOWN_LINE_NUMBER, discriminant_size.bits(), @@ -1583,8 +1799,11 @@ fn prepare_enum_metadata( let layout = cx.layout_of(enum_type); match (&layout.abi, &layout.variants) { - (&layout::Abi::Scalar(_), &layout::Variants::Tagged {ref tag, .. }) => - return FinalMetadata(discriminant_type_metadata(tag.value)), + (&layout::Abi::Scalar(_), &layout::Variants::Multiple { + discr_kind: layout::DiscriminantKind::Tag, + ref discr, + .. + }) => return FinalMetadata(discriminant_type_metadata(discr.value)), _ => {} } @@ -1596,9 +1815,16 @@ fn prepare_enum_metadata( if use_enum_fallback(cx) { let discriminant_type_metadata = match layout.variants { layout::Variants::Single { .. } | - layout::Variants::NicheFilling { .. } => None, - layout::Variants::Tagged { ref tag, .. } => { - Some(discriminant_type_metadata(tag.value)) + layout::Variants::Multiple { + discr_kind: layout::DiscriminantKind::Niche { .. }, + .. + } => None, + layout::Variants::Multiple { + discr_kind: layout::DiscriminantKind::Tag, + ref discr, + .. + } => { + Some(discriminant_type_metadata(discr.value)) } }; @@ -1633,16 +1859,26 @@ fn prepare_enum_metadata( ); } - let discriminator_metadata = match &layout.variants { + let discriminator_name = match &enum_type.sty { + ty::Generator(..) => Some(SmallCStr::new(&"__state")), + _ => None, + }; + let discriminator_name = discriminator_name.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()); + let discriminator_metadata = match layout.variants { // A single-variant enum has no discriminant. - &layout::Variants::Single { .. } => None, - - &layout::Variants::NicheFilling { ref niche, .. } => { + layout::Variants::Single { .. } => None, + + layout::Variants::Multiple { + discr_kind: layout::DiscriminantKind::Niche { .. }, + ref discr, + discr_index, + .. + } => { // Find the integer type of the correct size. - let size = niche.value.size(cx); - let align = niche.value.align(cx); + let size = discr.value.size(cx); + let align = discr.value.align(cx); - let discr_type = match niche.value { + let discr_type = match discr.value { layout::Int(t, _) => t, layout::Float(layout::FloatTy::F32) => Integer::I32, layout::Float(layout::FloatTy::F64) => Integer::I64, @@ -1654,19 +1890,24 @@ fn prepare_enum_metadata( Some(llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), containing_scope, - ptr::null_mut(), + discriminator_name, file_metadata, UNKNOWN_LINE_NUMBER, size.bits(), align.abi.bits() as u32, - layout.fields.offset(0).bits(), + layout.fields.offset(discr_index).bits(), DIFlags::FlagArtificial, discr_metadata)) } }, - &layout::Variants::Tagged { ref tag, .. } => { - let discr_type = tag.value.to_ty(cx.tcx); + layout::Variants::Multiple { + discr_kind: layout::DiscriminantKind::Tag, + ref discr, + discr_index, + .. + } => { + let discr_type = discr.value.to_ty(cx.tcx); let (size, align) = cx.size_and_align_of(discr_type); let discr_metadata = basic_type_metadata(cx, discr_type); @@ -1674,18 +1915,39 @@ fn prepare_enum_metadata( Some(llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), containing_scope, - ptr::null_mut(), + discriminator_name, file_metadata, UNKNOWN_LINE_NUMBER, size.bits(), align.bits() as u32, - layout.fields.offset(0).bits(), + layout.fields.offset(discr_index).bits(), DIFlags::FlagArtificial, discr_metadata)) } }, }; + let mut outer_fields = match layout.variants { + layout::Variants::Single { .. } => vec![], + layout::Variants::Multiple { .. } => { + let tuple_mdf = TupleMemberDescriptionFactory { + ty: enum_type, + component_types: outer_field_tys, + span + }; + tuple_mdf + .create_member_descriptions(cx) + .into_iter() + .map(|desc| Some(desc.into_metadata(cx, containing_scope))) + .collect() + } + }; + + let variant_part_unique_type_id_str = SmallCStr::new( + debug_context(cx).type_map + .borrow_mut() + .get_unique_type_id_str_of_enum_variant_part(unique_type_id) + ); let empty_array = create_DIArray(DIB(cx), &[]); let variant_part = unsafe { llvm::LLVMRustDIBuilderCreateVariantPart( @@ -1699,11 +1961,12 @@ fn prepare_enum_metadata( DIFlags::FlagZero, discriminator_metadata, empty_array, - unique_type_id_str.as_ptr()) + variant_part_unique_type_id_str.as_ptr()) }; + outer_fields.push(Some(variant_part)); // The variant part must be wrapped in a struct according to DWARF. - let type_array = create_DIArray(DIB(cx), &[Some(variant_part)]); + let type_array = create_DIArray(DIB(cx), &outer_fields); let struct_wrapper = unsafe { llvm::LLVMRustDIBuilderCreateStructType( DIB(cx), @@ -1735,12 +1998,6 @@ fn prepare_enum_metadata( span, }), ); - - fn get_enum_discriminant_name(cx: &CodegenCx<'_, '_>, - def_id: DefId) - -> InternedString { - cx.tcx.item_name(def_id) - } } /// Creates debug information for a composite type, that is, anything that @@ -1798,26 +2055,7 @@ fn set_members_of_composite_type(cx: &CodegenCx<'ll, 'tcx>, let member_metadata: Vec<_> = member_descriptions .into_iter() - .map(|member_description| { - let member_name = CString::new(member_description.name).unwrap(); - unsafe { - Some(llvm::LLVMRustDIBuilderCreateVariantMemberType( - DIB(cx), - composite_type_metadata, - member_name.as_ptr(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, - member_description.size.bits(), - member_description.align.bits() as u32, - member_description.offset.bits(), - match member_description.discriminant { - None => None, - Some(value) => Some(cx.const_u64(value)), - }, - member_description.flags, - member_description.type_metadata)) - } - }) + .map(|desc| Some(desc.into_metadata(cx, composite_type_metadata))) .collect(); let type_params = compute_type_parameters(cx, composite_type); @@ -2019,11 +2257,7 @@ pub fn create_global_var_metadata( /// given type. /// /// Adds the created metadata nodes directly to the crate's IR. -pub fn create_vtable_metadata( - cx: &CodegenCx<'ll, 'tcx>, - ty: ty::Ty<'tcx>, - vtable: &'ll Value, -) { +pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: &'ll Value) { if cx.dbg_cx.is_none() { return; } diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index c0869bb889afa..548ea0b1036e0 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -20,31 +20,29 @@ use rustc::ty::subst::{SubstsRef, UnpackedKind}; use crate::abi::Abi; use crate::common::CodegenCx; use crate::builder::Builder; -use crate::monomorphize::Instance; use crate::value::Value; -use rustc::ty::{self, ParamEnv, Ty, InstanceDef}; +use rustc::ty::{self, ParamEnv, Ty, InstanceDef, Instance}; use rustc::mir; use rustc::session::config::{self, DebugInfo}; use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::indexed_vec::IndexVec; use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess, - VariableKind, FunctionDebugContextData}; + VariableKind, FunctionDebugContextData, type_names}; use libc::c_uint; -use std::cell::{Cell, RefCell}; +use std::cell::RefCell; use std::ffi::CString; use syntax_pos::{self, Span, Pos}; use syntax::ast; -use syntax::symbol::{Symbol, InternedString}; +use syntax::symbol::InternedString; use rustc::ty::layout::{self, LayoutOf, HasTyCtxt}; use rustc_codegen_ssa::traits::*; pub mod gdb; mod utils; mod namespace; -mod type_names; pub mod metadata; mod create_scope_map; mod source_loc; @@ -64,7 +62,7 @@ pub struct CrateDebugContext<'a, 'tcx> { llcontext: &'a llvm::Context, llmod: &'a llvm::Module, builder: &'a mut DIBuilder<'a>, - created_files: RefCell>, + created_files: RefCell, Option), &'a DIFile>>, created_enum_disr_types: RefCell>, type_map: RefCell>, @@ -158,7 +156,7 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { variable_kind: VariableKind, span: Span, ) { - assert!(!dbg_context.get_ref(span).source_locations_enabled.get()); + assert!(!dbg_context.get_ref(span).source_locations_enabled); let cx = self.cx(); let file = span_start(cx, span).file; @@ -216,7 +214,7 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { fn set_source_location( &mut self, - debug_context: &FunctionDebugContext<&'ll DISubprogram>, + debug_context: &mut FunctionDebugContext<&'ll DISubprogram>, scope: Option<&'ll DIScope>, span: Span, ) { @@ -225,6 +223,13 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { gdb::insert_reference_to_gdb_debug_scripts_section_global(self) } + + fn set_value_name(&mut self, value: &'ll Value, name: &str) { + let cname = SmallCStr::new(name); + unsafe { + llvm::LLVMSetValueName(value, cname.as_ptr()); + } + } } impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { @@ -233,7 +238,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { instance: Instance<'tcx>, sig: ty::FnSig<'tcx>, llfn: &'ll Value, - mir: &mir::Mir<'_>, + mir: &mir::Body<'_>, ) -> FunctionDebugContext<&'ll DISubprogram> { if self.sess().opts.debuginfo == DebugInfo::None { return FunctionDebugContext::DebugInfoDisabled; @@ -289,12 +294,6 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let mut flags = DIFlags::FlagPrototyped; - if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) { - if id == def_id { - flags |= DIFlags::FlagMainSubprogram; - } - } - if self.layout_of(sig.output()).abi.is_uninhabited() { flags |= DIFlags::FlagNoReturn; } @@ -306,6 +305,11 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { if self.sess().opts.optimize != config::OptLevel::No { spflags |= DISPFlags::SPFlagOptimized; } + if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) { + if id == def_id { + spflags |= DISPFlags::SPFlagMainSubprogram; + } + } let fn_metadata = unsafe { llvm::LLVMRustDIBuilderCreateFunction( @@ -327,7 +331,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // Initialize fn debug context (including scope map and namespace map) let fn_debug_context = FunctionDebugContextData { fn_metadata, - source_locations_enabled: Cell::new(false), + source_locations_enabled: false, defining_crate: def_id.krate, }; @@ -387,7 +391,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { if let ty::Tuple(args) = sig.inputs()[sig.inputs().len() - 1].sty { signature.extend( args.iter().map(|argument_type| { - Some(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP)) + Some(type_metadata(cx, argument_type.expect_ty(), syntax_pos::DUMMY_SP)) }) ); } @@ -416,7 +420,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type); // Add actual type name to <...> clause of function name - let actual_type_name = compute_debuginfo_type_name(cx, + let actual_type_name = compute_debuginfo_type_name(cx.tcx(), actual_type, true); name_to_append_suffix_to.push_str(&actual_type_name[..]); @@ -518,8 +522,8 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn create_mir_scopes( &self, - mir: &mir::Mir<'_>, - debug_context: &FunctionDebugContext<&'ll DISubprogram>, + mir: &mir::Body<'_>, + debug_context: &mut FunctionDebugContext<&'ll DISubprogram>, ) -> IndexVec> { create_scope_map::create_mir_scopes(self, mir, debug_context) } @@ -537,7 +541,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { finalize(self) } - fn debuginfo_upvar_decls_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4] { + fn debuginfo_upvar_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4] { unsafe { [llvm::LLVMRustDIBuilderCreateOpDeref(), llvm::LLVMRustDIBuilderCreateOpPlusUconst(), diff --git a/src/librustc_codegen_llvm/debuginfo/namespace.rs b/src/librustc_codegen_llvm/debuginfo/namespace.rs index f7c377adf3529..889984749fdf7 100644 --- a/src/librustc_codegen_llvm/debuginfo/namespace.rs +++ b/src/librustc_codegen_llvm/debuginfo/namespace.rs @@ -2,8 +2,7 @@ use super::metadata::{unknown_file_metadata, UNKNOWN_LINE_NUMBER}; use super::utils::{DIB, debug_context}; -use crate::monomorphize::Instance; -use rustc::ty; +use rustc::ty::{self, Instance}; use crate::llvm; use crate::llvm::debuginfo::DIScope; diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs index f7620e11c233d..dec93a65dbaf4 100644 --- a/src/librustc_codegen_llvm/debuginfo/source_loc.rs +++ b/src/librustc_codegen_llvm/debuginfo/source_loc.rs @@ -30,7 +30,7 @@ pub fn set_source_location( FunctionDebugContext::RegularContext(ref data) => data }; - let dbg_loc = if function_debug_context.source_locations_enabled.get() { + let dbg_loc = if function_debug_context.source_locations_enabled { debug!("set_source_location: {}", bx.sess().source_map().span_to_string(span)); let loc = span_start(bx.cx(), span); InternalDebugLocation::new(scope.unwrap(), loc.line, loc.col.to_usize()) diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs deleted file mode 100644 index 8b218ab39d99b..0000000000000 --- a/src/librustc_codegen_llvm/debuginfo/type_names.rs +++ /dev/null @@ -1,220 +0,0 @@ -// Type Names for Debug Info. - -use crate::common::CodegenCx; -use rustc::hir::def_id::DefId; -use rustc::ty::subst::SubstsRef; -use rustc::ty::{self, Ty}; -use rustc_codegen_ssa::traits::*; - -use rustc::hir; - -// Compute the name of the type as it should be stored in debuginfo. Does not do -// any caching, i.e., calling the function twice with the same type will also do -// the work twice. The `qualified` parameter only affects the first level of the -// type name, further levels (i.e., type parameters) are always fully qualified. -pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - t: Ty<'tcx>, - qualified: bool) - -> String { - let mut result = String::with_capacity(64); - push_debuginfo_type_name(cx, t, qualified, &mut result); - result -} - -// Pushes the name of the type as it should be stored in debuginfo on the -// `output` String. See also compute_debuginfo_type_name(). -pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - t: Ty<'tcx>, - qualified: bool, - output: &mut String) { - // When targeting MSVC, emit C++ style type names for compatibility with - // .natvis visualizers (and perhaps other existing native debuggers?) - let cpp_like_names = cx.sess().target.target.options.is_like_msvc; - - match t.sty { - ty::Bool => output.push_str("bool"), - ty::Char => output.push_str("char"), - ty::Str => output.push_str("str"), - ty::Never => output.push_str("!"), - ty::Int(int_ty) => output.push_str(int_ty.ty_to_string()), - ty::Uint(uint_ty) => output.push_str(uint_ty.ty_to_string()), - ty::Float(float_ty) => output.push_str(float_ty.ty_to_string()), - ty::Foreign(def_id) => push_item_name(cx, def_id, qualified, output), - ty::Adt(def, substs) => { - push_item_name(cx, def.did, qualified, output); - push_type_params(cx, substs, output); - }, - ty::Tuple(component_types) => { - output.push('('); - for &component_type in component_types { - push_debuginfo_type_name(cx, component_type, true, output); - output.push_str(", "); - } - if !component_types.is_empty() { - output.pop(); - output.pop(); - } - output.push(')'); - }, - ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { - if !cpp_like_names { - output.push('*'); - } - match mutbl { - hir::MutImmutable => output.push_str("const "), - hir::MutMutable => output.push_str("mut "), - } - - push_debuginfo_type_name(cx, inner_type, true, output); - - if cpp_like_names { - output.push('*'); - } - }, - ty::Ref(_, inner_type, mutbl) => { - if !cpp_like_names { - output.push('&'); - } - if mutbl == hir::MutMutable { - output.push_str("mut "); - } - - push_debuginfo_type_name(cx, inner_type, true, output); - - if cpp_like_names { - output.push('*'); - } - }, - ty::Array(inner_type, len) => { - output.push('['); - push_debuginfo_type_name(cx, inner_type, true, output); - output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx))); - output.push(']'); - }, - ty::Slice(inner_type) => { - if cpp_like_names { - output.push_str("slice<"); - } else { - output.push('['); - } - - push_debuginfo_type_name(cx, inner_type, true, output); - - if cpp_like_names { - output.push('>'); - } else { - output.push(']'); - } - }, - ty::Dynamic(ref trait_data, ..) => { - if let Some(principal) = trait_data.principal() { - let principal = cx.tcx.normalize_erasing_late_bound_regions( - ty::ParamEnv::reveal_all(), - &principal, - ); - push_item_name(cx, principal.def_id, false, output); - push_type_params(cx, principal.substs, output); - } else { - output.push_str("dyn '_"); - } - }, - ty::FnDef(..) | ty::FnPtr(_) => { - let sig = t.fn_sig(cx.tcx); - if sig.unsafety() == hir::Unsafety::Unsafe { - output.push_str("unsafe "); - } - - let abi = sig.abi(); - if abi != crate::abi::Abi::Rust { - output.push_str("extern \""); - output.push_str(abi.name()); - output.push_str("\" "); - } - - output.push_str("fn("); - - let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - if !sig.inputs().is_empty() { - for ¶meter_type in sig.inputs() { - push_debuginfo_type_name(cx, parameter_type, true, output); - output.push_str(", "); - } - output.pop(); - output.pop(); - } - - if sig.c_variadic { - if !sig.inputs().is_empty() { - output.push_str(", ..."); - } else { - output.push_str("..."); - } - } - - output.push(')'); - - if !sig.output().is_unit() { - output.push_str(" -> "); - push_debuginfo_type_name(cx, sig.output(), true, output); - } - }, - ty::Closure(..) => { - output.push_str("closure"); - } - ty::Generator(..) => { - output.push_str("generator"); - } - ty::Error | - ty::Infer(_) | - ty::Placeholder(..) | - ty::UnnormalizedProjection(..) | - ty::Projection(..) | - ty::Bound(..) | - ty::Opaque(..) | - ty::GeneratorWitness(..) | - ty::Param(_) => { - bug!("debuginfo: Trying to create type name for \ - unexpected type: {:?}", t); - } - } - - fn push_item_name(cx: &CodegenCx<'_, '_>, - def_id: DefId, - qualified: bool, - output: &mut String) { - if qualified { - output.push_str(&cx.tcx.crate_name(def_id.krate).as_str()); - for path_element in cx.tcx.def_path(def_id).data { - output.push_str("::"); - output.push_str(&path_element.data.as_interned_str().as_str()); - } - } else { - output.push_str(&cx.tcx.item_name(def_id).as_str()); - } - } - - // Pushes the type parameters in the given `InternalSubsts` to the output string. - // This ignores region parameters, since they can't reliably be - // reconstructed for items from non-local crates. For local crates, this - // would be possible but with inlining and LTO we have to use the least - // common denominator - otherwise we would run into conflicts. - fn push_type_params<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - substs: SubstsRef<'tcx>, - output: &mut String) { - if substs.types().next().is_none() { - return; - } - - output.push('<'); - - for type_parameter in substs.types() { - push_debuginfo_type_name(cx, type_parameter, true, output); - output.push_str(", "); - } - - output.pop(); - output.pop(); - - output.push('>'); - } -} diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs index 3febcb019ce29..bcb14b8899ec2 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/src/librustc_codegen_llvm/declare.rs @@ -13,13 +13,13 @@ use crate::llvm; use crate::llvm::AttributePlace::Function; -use crate::abi::{FnType, FnTypeExt}; +use crate::abi::{FnType, FnTypeLlvmExt}; use crate::attributes; use crate::context::CodegenCx; use crate::type_::Type; use crate::value::Value; use rustc::ty::{self, PolyFnSig}; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{FnTypeExt, LayoutOf}; use rustc::session::config::Sanitizer; use rustc_data_structures::small_c_str::SmallCStr; use rustc_codegen_ssa::traits::*; diff --git a/src/librustc_codegen_llvm/diagnostics.rs b/src/librustc_codegen_llvm/error_codes.rs similarity index 100% rename from src/librustc_codegen_llvm/diagnostics.rs rename to src/librustc_codegen_llvm/error_codes.rs diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 3268af396a2f4..7831c200114a5 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -20,7 +20,6 @@ use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc::hir; use syntax::ast::{self, FloatTy}; -use syntax::symbol::Symbol; use rustc_codegen_ssa::traits::*; @@ -56,6 +55,10 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Valu "fmaf64" => "llvm.fma.f64", "fabsf32" => "llvm.fabs.f32", "fabsf64" => "llvm.fabs.f64", + "minnumf32" => "llvm.minnum.f32", + "minnumf64" => "llvm.minnum.f64", + "maxnumf32" => "llvm.maxnum.f32", + "maxnumf64" => "llvm.maxnum.f64", "copysignf32" => "llvm.copysign.f32", "copysignf64" => "llvm.copysign.f64", "floorf32" => "llvm.floor.f32", @@ -143,15 +146,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.va_end(args[0].immediate()) } "va_copy" => { - let va_list = match (tcx.lang_items().va_list(), &result.layout.ty.sty) { - (Some(did), ty::Adt(def, _)) if def.did == did => args[0].immediate(), - (Some(_), _) => self.load(args[0].immediate(), - tcx.data_layout.pointer_align.abi), - (None, _) => bug!("`va_list` language item must be defined") - }; let intrinsic = self.cx().get_intrinsic(&("llvm.va_copy")); - self.call(intrinsic, &[llresult, va_list], None); - return; + self.call(intrinsic, &[args[0].immediate(), args[1].immediate()], None) } "va_arg" => { match fn_ty.ret.layout.abi { @@ -213,8 +209,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } "type_name" => { let tp_ty = substs.type_at(0); - let ty_name = Symbol::intern(&tp_ty.to_string()).as_str(); - self.const_str_slice(ty_name) + let ty_name = self.tcx.type_name(tp_ty); + OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self) } "type_id" => { self.const_u64(self.tcx.type_id_hash(substs.type_at(0))) @@ -335,7 +331,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" | "bitreverse" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" | - "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" | + "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | + "unchecked_add" | "unchecked_sub" | "unchecked_mul" | "exact_div" | "rotate_left" | "rotate_right" | "saturating_add" | "saturating_sub" => { let ty = arg_tys[0]; match int_type_width_signed(ty, self) { @@ -431,6 +428,27 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } else { self.lshr(args[0].immediate(), args[1].immediate()) }, + "unchecked_add" => { + if signed { + self.unchecked_sadd(args[0].immediate(), args[1].immediate()) + } else { + self.unchecked_uadd(args[0].immediate(), args[1].immediate()) + } + }, + "unchecked_sub" => { + if signed { + self.unchecked_ssub(args[0].immediate(), args[1].immediate()) + } else { + self.unchecked_usub(args[0].immediate(), args[1].immediate()) + } + }, + "unchecked_mul" => { + if signed { + self.unchecked_smul(args[0].immediate(), args[1].immediate()) + } else { + self.unchecked_umul(args[0].immediate(), args[1].immediate()) + } + }, "rotate_left" | "rotate_right" => { let is_left = name == "rotate_left"; let val = args[0].immediate(); @@ -513,8 +531,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { }, "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { - let sty = &arg_tys[0].sty; - match float_type_width(sty) { + match float_type_width(arg_tys[0]) { Some(_width) => match name { "fadd_fast" => self.fadd_fast(args[0].immediate(), args[1].immediate()), @@ -528,7 +545,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { span_invalid_monomorphization_error( tcx.sess, span, &format!("invalid monomorphization of `{}` intrinsic: \ - expected basic float type, found `{}`", name, sty)); + expected basic float type, found `{}`", name, arg_tys[0])); return; } } @@ -719,37 +736,12 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.call(expect, &[cond, self.const_bool(expected)], None) } - fn va_start(&mut self, list: &'ll Value) -> &'ll Value { - let target = &self.cx.tcx.sess.target.target; - let arch = &target.arch; - // A pointer to the architecture specific structure is passed to this - // function. For pointer variants (i686, RISC-V, Windows, etc), we - // should do do nothing, as the address to the pointer is needed. For - // architectures with a architecture specific structure (`Aarch64`, - // `X86_64`, etc), this function should load the structure from the - // address provided. - let va_list = match &**arch { - _ if target.options.is_like_windows => list, - "aarch64" if target.target_os == "ios" => list, - "aarch64" | "x86_64" | "powerpc" => - self.load(list, self.tcx().data_layout.pointer_align.abi), - _ => list, - }; + fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value { let intrinsic = self.cx().get_intrinsic("llvm.va_start"); self.call(intrinsic, &[va_list], None) } - fn va_end(&mut self, list: &'ll Value) -> &'ll Value { - let target = &self.cx.tcx.sess.target.target; - let arch = &target.arch; - // See the comment in `va_start` for the purpose of the following. - let va_list = match &**arch { - _ if target.options.is_like_windows => list, - "aarch64" if target.target_os == "ios" => list, - "aarch64" | "x86_64" | "powerpc" => - self.load(list, self.tcx().data_layout.pointer_align.abi), - _ => list, - }; + fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value { let intrinsic = self.cx().get_intrinsic("llvm.va_end"); self.call(intrinsic, &[va_list], None) } @@ -917,8 +909,8 @@ fn codegen_msvc_try( bx.store(ret, dest, i32_align); } -// Definition of the standard "try" function for Rust using the GNU-like model -// of exceptions (e.g., the normal semantics of LLVM's landingpad and invoke +// Definition of the standard `try` function for Rust using the GNU-like model +// of exceptions (e.g., the normal semantics of LLVM's `landingpad` and `invoke` // instructions). // // This codegen is a little surprising because we always call a shim @@ -1393,7 +1385,7 @@ fn generic_simd_intrinsic( // FIXME: use: // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182 // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81 - fn llvm_vector_str(elem_ty: ty::Ty<'_>, vec_len: usize, no_pointers: usize) -> String { + fn llvm_vector_str(elem_ty: Ty<'_>, vec_len: usize, no_pointers: usize) -> String { let p0s: String = "p0".repeat(no_pointers); match elem_ty.sty { ty::Int(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), @@ -1403,7 +1395,7 @@ fn generic_simd_intrinsic( } } - fn llvm_vector_ty(cx: &CodegenCx<'ll, '_>, elem_ty: ty::Ty<'_>, vec_len: usize, + fn llvm_vector_ty(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: usize, mut no_pointers: usize) -> &'ll Type { // FIXME: use cx.layout_of(ty).llvm_type() ? let mut elem_ty = match elem_ty.sty { @@ -1449,7 +1441,7 @@ fn generic_simd_intrinsic( in_ty, ret_ty); // This counts how many pointers - fn ptr_count(t: ty::Ty<'_>) -> usize { + fn ptr_count(t: Ty<'_>) -> usize { match t.sty { ty::RawPtr(p) => 1 + ptr_count(p.ty), _ => 0, @@ -1457,7 +1449,7 @@ fn generic_simd_intrinsic( } // Non-ptr type - fn non_ptr(t: ty::Ty<'_>) -> ty::Ty<'_> { + fn non_ptr(t: Ty<'_>) -> Ty<'_> { match t.sty { ty::RawPtr(p) => non_ptr(p.ty), _ => t, @@ -1473,8 +1465,8 @@ fn generic_simd_intrinsic( require!(false, "expected element type `{}` of second argument `{}` \ to be a pointer to the element type `{}` of the first \ argument `{}`, found `{}` != `*_ {}`", - arg_tys[1].simd_type(tcx).sty, arg_tys[1], in_elem, in_ty, - arg_tys[1].simd_type(tcx).sty, in_elem); + arg_tys[1].simd_type(tcx), arg_tys[1], in_elem, in_ty, + arg_tys[1].simd_type(tcx), in_elem); unreachable!(); } }; @@ -1488,7 +1480,7 @@ fn generic_simd_intrinsic( _ => { require!(false, "expected element type `{}` of third argument `{}` \ to be a signed integer type", - arg_tys[2].simd_type(tcx).sty, arg_tys[2]); + arg_tys[2].simd_type(tcx), arg_tys[2]); } } @@ -1548,7 +1540,7 @@ fn generic_simd_intrinsic( arg_tys[2].simd_size(tcx)); // This counts how many pointers - fn ptr_count(t: ty::Ty<'_>) -> usize { + fn ptr_count(t: Ty<'_>) -> usize { match t.sty { ty::RawPtr(p) => 1 + ptr_count(p.ty), _ => 0, @@ -1556,7 +1548,7 @@ fn generic_simd_intrinsic( } // Non-ptr type - fn non_ptr(t: ty::Ty<'_>) -> ty::Ty<'_> { + fn non_ptr(t: Ty<'_>) -> Ty<'_> { match t.sty { ty::RawPtr(p) => non_ptr(p.ty), _ => t, @@ -1573,8 +1565,8 @@ fn generic_simd_intrinsic( require!(false, "expected element type `{}` of second argument `{}` \ to be a pointer to the element type `{}` of the first \ argument `{}`, found `{}` != `*mut {}`", - arg_tys[1].simd_type(tcx).sty, arg_tys[1], in_elem, in_ty, - arg_tys[1].simd_type(tcx).sty, in_elem); + arg_tys[1].simd_type(tcx), arg_tys[1], in_elem, in_ty, + arg_tys[1].simd_type(tcx), in_elem); unreachable!(); } }; @@ -1588,7 +1580,7 @@ fn generic_simd_intrinsic( _ => { require!(false, "expected element type `{}` of third argument `{}` \ to be a signed integer type", - arg_tys[2].simd_type(tcx).sty, arg_tys[2]); + arg_tys[2].simd_type(tcx), arg_tys[2]); } } @@ -1904,7 +1896,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, return_error!( "expected element type `{}` of vector type `{}` \ to be a signed or unsigned integer type", - arg_tys[0].simd_type(tcx).sty, arg_tys[0] + arg_tys[0].simd_type(tcx), arg_tys[0] ); } }; @@ -1954,10 +1946,10 @@ fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, boo } } -// Returns the width of a float TypeVariant +// Returns the width of a float Ty // Returns None if the type is not a float -fn float_type_width<'tcx>(sty: &ty::TyKind<'tcx>) -> Option { - match *sty { +fn float_type_width(ty: Ty<'_>) -> Option { + match ty.sty { ty::Float(t) => Some(t.bit_width() as u64), _ => None, } diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 5b8c7461bcb60..7283aa95b3027 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -8,30 +8,30 @@ #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(const_cstr_unchecked)] #![feature(crate_visibility_modifier)] -#![feature(custom_attribute)] #![feature(extern_types)] #![feature(in_band_lifetimes)] #![allow(unused_attributes)] #![feature(libc)] #![feature(nll)] -#![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(optin_builtin_traits)] #![feature(concat_idents)] #![feature(link_args)] #![feature(static_nobundle)] +#![feature(trusted_len)] #![deny(rust_2018_idioms)] -#![allow(explicit_outlives_requirements)] +#![deny(internal)] +#![deny(unused_lifetimes)] -use back::write::create_target_machine; +use back::write::{create_target_machine, create_informational_target_machine}; use syntax_pos::symbol::Symbol; extern crate flate2; #[macro_use] extern crate bitflags; extern crate libc; #[macro_use] extern crate rustc; -extern crate rustc_mir; extern crate rustc_allocator; extern crate rustc_target; #[macro_use] extern crate rustc_data_structures; @@ -44,8 +44,6 @@ extern crate rustc_fs_util; #[macro_use] extern crate syntax; extern crate syntax_pos; extern crate rustc_errors as errors; -extern crate serialize; -extern crate tempfile; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, FatLTOInput}; @@ -53,9 +51,7 @@ use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinModul use rustc_codegen_ssa::CompiledModule; use errors::{FatalError, Handler}; use rustc::dep_graph::WorkProduct; -use rustc::util::time_graph::Timeline; use syntax_pos::symbol::InternedString; -use rustc::mir::mono::Stats; pub use llvm_util::target_features; use std::any::Any; use std::sync::{mpsc, Arc}; @@ -63,25 +59,20 @@ use std::sync::{mpsc, Arc}; use rustc::dep_graph::DepGraph; use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; -use rustc::session::{Session, CompileIncomplete}; +use rustc::session::Session; use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel}; use rustc::ty::{self, TyCtxt}; -use rustc::util::time_graph; -use rustc::util::profiling::ProfileCategory; -use rustc_mir::monomorphize; +use rustc::util::common::ErrorReported; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_utils::codegen_backend::CodegenBackend; -mod diagnostics; +mod error_codes; mod back { - mod archive; + pub mod archive; pub mod bytecode; - pub mod link; pub mod lto; pub mod write; - mod rpath; - pub mod wasm; } mod abi; @@ -113,30 +104,28 @@ mod va_arg; pub struct LlvmCodegenBackend(()); impl ExtraBackendMethods for LlvmCodegenBackend { - fn new_metadata(&self, tcx: TyCtxt<'_, '_, '_>, mod_name: &str) -> ModuleLlvm { - ModuleLlvm::new(tcx, mod_name) + fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm { + ModuleLlvm::new_metadata(tcx, mod_name) } - fn write_metadata<'b, 'gcx>( + + fn write_compressed_metadata<'tcx>( &self, - tcx: TyCtxt<'b, 'gcx, 'gcx>, - metadata: &mut ModuleLlvm - ) -> EncodedMetadata { - base::write_metadata(tcx, metadata) + tcx: TyCtxt<'tcx>, + metadata: &EncodedMetadata, + llvm_module: &mut ModuleLlvm, + ) { + base::write_compressed_metadata(tcx, metadata, llvm_module) } - fn codegen_allocator( + fn codegen_allocator<'tcx>( &self, - tcx: TyCtxt<'_, '_, '_>, + tcx: TyCtxt<'tcx>, mods: &mut ModuleLlvm, - kind: AllocatorKind + kind: AllocatorKind, ) { unsafe { allocator::codegen(tcx, mods, kind) } } - fn compile_codegen_unit<'a, 'tcx: 'a>( - &self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cgu_name: InternedString, - ) -> Stats { - base::compile_codegen_unit(tcx, cgu_name) + fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: InternedString) { + base::compile_codegen_unit(tcx, cgu_name); } fn target_machine_factory( &self, @@ -166,42 +155,37 @@ impl WriteBackendMethods for LlvmCodegenBackend { cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - timeline: &mut Timeline ) -> Result, FatalError> { - back::lto::run_fat(cgcx, modules, cached_modules, timeline) + back::lto::run_fat(cgcx, modules, cached_modules) } fn run_thin_lto( cgcx: &CodegenContext, modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - timeline: &mut Timeline ) -> Result<(Vec>, Vec), FatalError> { - back::lto::run_thin(cgcx, modules, cached_modules, timeline) + back::lto::run_thin(cgcx, modules, cached_modules) } unsafe fn optimize( cgcx: &CodegenContext, diag_handler: &Handler, module: &ModuleCodegen, config: &ModuleConfig, - timeline: &mut Timeline ) -> Result<(), FatalError> { - back::write::optimize(cgcx, diag_handler, module, config, timeline) + back::write::optimize(cgcx, diag_handler, module, config) } unsafe fn optimize_thin( cgcx: &CodegenContext, thin: &mut ThinModule, - timeline: &mut Timeline ) -> Result, FatalError> { - back::lto::optimize_thin_module(thin, cgcx, timeline) + back::lto::optimize_thin_module(thin, cgcx) } unsafe fn codegen( cgcx: &CodegenContext, diag_handler: &Handler, module: ModuleCodegen, config: &ModuleConfig, - timeline: &mut Timeline ) -> Result { - back::write::codegen(cgcx, diag_handler, module, config, timeline) + back::write::codegen(cgcx, diag_handler, module, config) } fn prepare_thin( module: ModuleCodegen @@ -297,12 +281,15 @@ impl CodegenBackend for LlvmCodegenBackend { attributes::provide_extern(providers); } - fn codegen_crate<'b, 'tcx>( + fn codegen_crate<'tcx>( &self, - tcx: TyCtxt<'b, 'tcx, 'tcx>, - rx: mpsc::Receiver> + tcx: TyCtxt<'tcx>, + metadata: EncodedMetadata, + need_metadata_module: bool, + rx: mpsc::Receiver>, ) -> Box { - box rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx, rx) + box rustc_codegen_ssa::base::codegen_crate( + LlvmCodegenBackend(()), tcx, metadata, need_metadata_module, rx) } fn join_codegen_and_link( @@ -311,7 +298,7 @@ impl CodegenBackend for LlvmCodegenBackend { sess: &Session, dep_graph: &DepGraph, outputs: &OutputFilenames, - ) -> Result<(), CompileIncomplete>{ + ) -> Result<(), ErrorReported> { use rustc::util::common::time; let (codegen_results, work_products) = ongoing_codegen.downcast:: @@ -335,12 +322,21 @@ impl CodegenBackend for LlvmCodegenBackend { // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - sess.profiler(|p| p.start_activity(ProfileCategory::Linking)); + sess.profiler(|p| p.start_activity("link_crate")); time(sess, "linking", || { - back::link::link_binary(sess, &codegen_results, - outputs, &codegen_results.crate_name.as_str()); + use rustc_codegen_ssa::back::link::link_binary; + use crate::back::archive::LlvmArchiveBuilder; + + let target_cpu = crate::llvm_util::target_cpu(sess); + link_binary::>( + sess, + &codegen_results, + outputs, + &codegen_results.crate_name.as_str(), + target_cpu, + ); }); - sess.profiler(|p| p.end_activity(ProfileCategory::Linking)); + sess.profiler(|p| p.end_activity("link_crate")); // Now that we won't touch anything in the incremental compilation directory // any more, we can finalize it (which involves renaming it) @@ -366,11 +362,10 @@ unsafe impl Send for ModuleLlvm { } unsafe impl Sync for ModuleLlvm { } impl ModuleLlvm { - fn new(tcx: TyCtxt<'_, '_, '_>, mod_name: &str) -> Self { + fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self { unsafe { let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names()); let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _; - ModuleLlvm { llmod_raw, llcx, @@ -379,6 +374,18 @@ impl ModuleLlvm { } } + fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self { + unsafe { + let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names()); + let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _; + ModuleLlvm { + llmod_raw, + llcx, + tm: create_informational_target_machine(&tcx.sess, false), + } + } + } + fn parse( cgcx: &CodegenContext, name: &str, diff --git a/src/librustc_codegen_llvm/llvm/diagnostic.rs b/src/librustc_codegen_llvm/llvm/diagnostic.rs index a8d272f157ce3..04e65ac423300 100644 --- a/src/librustc_codegen_llvm/llvm/diagnostic.rs +++ b/src/librustc_codegen_llvm/llvm/diagnostic.rs @@ -88,7 +88,7 @@ impl OptimizationDiagnostic<'ll> { pub struct InlineAsmDiagnostic<'ll> { pub cookie: c_uint, pub message: &'ll Twine, - pub instruction: &'ll Value, + pub instruction: Option<&'ll Value>, } impl InlineAsmDiagnostic<'ll> { @@ -107,7 +107,7 @@ impl InlineAsmDiagnostic<'ll> { InlineAsmDiagnostic { cookie, message: message.unwrap(), - instruction: instruction.unwrap(), + instruction, } } } diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 2ad6d9c053a20..a5c295cd4525c 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -564,7 +564,7 @@ pub mod debuginfo { // These values **must** match with LLVMRustDIFlags!! bitflags! { - #[repr(C)] + #[repr(transparent)] #[derive(Default)] pub struct DIFlags: ::libc::uint32_t { const FlagZero = 0; @@ -588,13 +588,12 @@ pub mod debuginfo { const FlagIntroducedVirtual = (1 << 18); const FlagBitField = (1 << 19); const FlagNoReturn = (1 << 20); - const FlagMainSubprogram = (1 << 21); } } // These values **must** match with LLVMRustDISPFlags!! bitflags! { - #[repr(C)] + #[repr(transparent)] #[derive(Default)] pub struct DISPFlags: ::libc::uint32_t { const SPFlagZero = 0; @@ -603,6 +602,7 @@ pub mod debuginfo { const SPFlagLocalToUnit = (1 << 2); const SPFlagDefinition = (1 << 3); const SPFlagOptimized = (1 << 4); + const SPFlagMainSubprogram = (1 << 5); } } @@ -1002,6 +1002,36 @@ extern "C" { RHS: &'a Value, Name: *const c_char) -> &'a Value; + pub fn LLVMBuildNSWAdd(B: &Builder<'a>, + LHS: &'a Value, + RHS: &'a Value, + Name: *const c_char) + -> &'a Value; + pub fn LLVMBuildNUWAdd(B: &Builder<'a>, + LHS: &'a Value, + RHS: &'a Value, + Name: *const c_char) + -> &'a Value; + pub fn LLVMBuildNSWSub(B: &Builder<'a>, + LHS: &'a Value, + RHS: &'a Value, + Name: *const c_char) + -> &'a Value; + pub fn LLVMBuildNUWSub(B: &Builder<'a>, + LHS: &'a Value, + RHS: &'a Value, + Name: *const c_char) + -> &'a Value; + pub fn LLVMBuildNSWMul(B: &Builder<'a>, + LHS: &'a Value, + RHS: &'a Value, + Name: *const c_char) + -> &'a Value; + pub fn LLVMBuildNUWMul(B: &Builder<'a>, + LHS: &'a Value, + RHS: &'a Value, + Name: *const c_char) + -> &'a Value; pub fn LLVMBuildAnd(B: &Builder<'a>, LHS: &'a Value, RHS: &'a Value, @@ -1382,7 +1412,6 @@ extern "C" { pub fn LLVMRustDebugMetadataVersion() -> u32; pub fn LLVMRustVersionMajor() -> u32; pub fn LLVMRustVersionMinor() -> u32; - pub fn LLVMRustIsRustLLVM() -> bool; pub fn LLVMRustAddModuleFlag(M: &Module, name: *const c_char, value: u32); @@ -1687,7 +1716,8 @@ extern "C" { Demangle: extern fn(*const c_char, size_t, *mut c_char, - size_t) -> size_t); + size_t) -> size_t, + ) -> LLVMRustResult; pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char); pub fn LLVMRustPrintPasses(); pub fn LLVMRustSetNormalizedTarget(M: &Module, triple: *const c_char); diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 5fea9c8747e0f..274c89659628d 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -7,6 +7,7 @@ use rustc_target::spec::MergeFunctions; use libc::c_int; use std::ffi::CString; use syntax::feature_gate::UnstableFeatures; +use syntax::symbol::sym; use std::str; use std::slice; @@ -61,7 +62,7 @@ unsafe fn configure_llvm(sess: &Session) { if sess.opts.debugging_opts.disable_instrumentation_preinliner { add("-disable-preinline"); } - if llvm::LLVMRustIsRustLLVM() { + if get_major_version() >= 8 { match sess.opts.debugging_opts.merge_functions .unwrap_or(sess.target.target.options.merge_functions) { MergeFunctions::Disabled | @@ -93,104 +94,106 @@ unsafe fn configure_llvm(sess: &Session) { // to LLVM or the feature detection code will walk past the end of the feature // array, leading to crashes. -const ARM_WHITELIST: &[(&str, Option<&str>)] = &[ - ("aclass", Some("arm_target_feature")), - ("mclass", Some("arm_target_feature")), - ("rclass", Some("arm_target_feature")), - ("dsp", Some("arm_target_feature")), - ("neon", Some("arm_target_feature")), - ("v5te", Some("arm_target_feature")), - ("v6", Some("arm_target_feature")), - ("v6k", Some("arm_target_feature")), - ("v6t2", Some("arm_target_feature")), - ("v7", Some("arm_target_feature")), - ("v8", Some("arm_target_feature")), - ("vfp2", Some("arm_target_feature")), - ("vfp3", Some("arm_target_feature")), - ("vfp4", Some("arm_target_feature")), +const ARM_WHITELIST: &[(&str, Option)] = &[ + ("aclass", Some(sym::arm_target_feature)), + ("mclass", Some(sym::arm_target_feature)), + ("rclass", Some(sym::arm_target_feature)), + ("dsp", Some(sym::arm_target_feature)), + ("neon", Some(sym::arm_target_feature)), + ("v5te", Some(sym::arm_target_feature)), + ("v6", Some(sym::arm_target_feature)), + ("v6k", Some(sym::arm_target_feature)), + ("v6t2", Some(sym::arm_target_feature)), + ("v7", Some(sym::arm_target_feature)), + ("v8", Some(sym::arm_target_feature)), + ("vfp2", Some(sym::arm_target_feature)), + ("vfp3", Some(sym::arm_target_feature)), + ("vfp4", Some(sym::arm_target_feature)), ]; -const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[ - ("fp", Some("aarch64_target_feature")), - ("neon", Some("aarch64_target_feature")), - ("sve", Some("aarch64_target_feature")), - ("crc", Some("aarch64_target_feature")), - ("crypto", Some("aarch64_target_feature")), - ("ras", Some("aarch64_target_feature")), - ("lse", Some("aarch64_target_feature")), - ("rdm", Some("aarch64_target_feature")), - ("fp16", Some("aarch64_target_feature")), - ("rcpc", Some("aarch64_target_feature")), - ("dotprod", Some("aarch64_target_feature")), - ("v8.1a", Some("aarch64_target_feature")), - ("v8.2a", Some("aarch64_target_feature")), - ("v8.3a", Some("aarch64_target_feature")), +const AARCH64_WHITELIST: &[(&str, Option)] = &[ + ("fp", Some(sym::aarch64_target_feature)), + ("neon", Some(sym::aarch64_target_feature)), + ("sve", Some(sym::aarch64_target_feature)), + ("crc", Some(sym::aarch64_target_feature)), + ("crypto", Some(sym::aarch64_target_feature)), + ("ras", Some(sym::aarch64_target_feature)), + ("lse", Some(sym::aarch64_target_feature)), + ("rdm", Some(sym::aarch64_target_feature)), + ("fp16", Some(sym::aarch64_target_feature)), + ("rcpc", Some(sym::aarch64_target_feature)), + ("dotprod", Some(sym::aarch64_target_feature)), + ("v8.1a", Some(sym::aarch64_target_feature)), + ("v8.2a", Some(sym::aarch64_target_feature)), + ("v8.3a", Some(sym::aarch64_target_feature)), ]; -const X86_WHITELIST: &[(&str, Option<&str>)] = &[ - ("adx", Some("adx_target_feature")), +const X86_WHITELIST: &[(&str, Option)] = &[ + ("adx", Some(sym::adx_target_feature)), ("aes", None), ("avx", None), ("avx2", None), - ("avx512bw", Some("avx512_target_feature")), - ("avx512cd", Some("avx512_target_feature")), - ("avx512dq", Some("avx512_target_feature")), - ("avx512er", Some("avx512_target_feature")), - ("avx512f", Some("avx512_target_feature")), - ("avx512ifma", Some("avx512_target_feature")), - ("avx512pf", Some("avx512_target_feature")), - ("avx512vbmi", Some("avx512_target_feature")), - ("avx512vl", Some("avx512_target_feature")), - ("avx512vpopcntdq", Some("avx512_target_feature")), + ("avx512bw", Some(sym::avx512_target_feature)), + ("avx512cd", Some(sym::avx512_target_feature)), + ("avx512dq", Some(sym::avx512_target_feature)), + ("avx512er", Some(sym::avx512_target_feature)), + ("avx512f", Some(sym::avx512_target_feature)), + ("avx512ifma", Some(sym::avx512_target_feature)), + ("avx512pf", Some(sym::avx512_target_feature)), + ("avx512vbmi", Some(sym::avx512_target_feature)), + ("avx512vl", Some(sym::avx512_target_feature)), + ("avx512vpopcntdq", Some(sym::avx512_target_feature)), ("bmi1", None), ("bmi2", None), - ("cmpxchg16b", Some("cmpxchg16b_target_feature")), + ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)), + ("f16c", Some(sym::f16c_target_feature)), ("fma", None), ("fxsr", None), ("lzcnt", None), - ("mmx", Some("mmx_target_feature")), - ("movbe", Some("movbe_target_feature")), + ("mmx", Some(sym::mmx_target_feature)), + ("movbe", Some(sym::movbe_target_feature)), ("pclmulqdq", None), ("popcnt", None), ("rdrand", None), ("rdseed", None), + ("rtm", Some(sym::rtm_target_feature)), ("sha", None), ("sse", None), ("sse2", None), ("sse3", None), ("sse4.1", None), ("sse4.2", None), - ("sse4a", Some("sse4a_target_feature")), + ("sse4a", Some(sym::sse4a_target_feature)), ("ssse3", None), - ("tbm", Some("tbm_target_feature")), + ("tbm", Some(sym::tbm_target_feature)), ("xsave", None), ("xsavec", None), ("xsaveopt", None), ("xsaves", None), ]; -const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[ - ("hvx", Some("hexagon_target_feature")), - ("hvx-double", Some("hexagon_target_feature")), +const HEXAGON_WHITELIST: &[(&str, Option)] = &[ + ("hvx", Some(sym::hexagon_target_feature)), + ("hvx-double", Some(sym::hexagon_target_feature)), ]; -const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[ - ("altivec", Some("powerpc_target_feature")), - ("power8-altivec", Some("powerpc_target_feature")), - ("power9-altivec", Some("powerpc_target_feature")), - ("power8-vector", Some("powerpc_target_feature")), - ("power9-vector", Some("powerpc_target_feature")), - ("vsx", Some("powerpc_target_feature")), +const POWERPC_WHITELIST: &[(&str, Option)] = &[ + ("altivec", Some(sym::powerpc_target_feature)), + ("power8-altivec", Some(sym::powerpc_target_feature)), + ("power9-altivec", Some(sym::powerpc_target_feature)), + ("power8-vector", Some(sym::powerpc_target_feature)), + ("power9-vector", Some(sym::powerpc_target_feature)), + ("vsx", Some(sym::powerpc_target_feature)), ]; -const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[ - ("fp64", Some("mips_target_feature")), - ("msa", Some("mips_target_feature")), +const MIPS_WHITELIST: &[(&str, Option)] = &[ + ("fp64", Some(sym::mips_target_feature)), + ("msa", Some(sym::mips_target_feature)), ]; -const WASM_WHITELIST: &[(&str, Option<&str>)] = &[ - ("simd128", Some("wasm_target_feature")), - ("atomics", Some("wasm_target_feature")), +const WASM_WHITELIST: &[(&str, Option)] = &[ + ("simd128", Some(sym::wasm_target_feature)), + ("atomics", Some(sym::wasm_target_feature)), ]; /// When rustdoc is running, provide a list of all known features so that all their respective @@ -198,7 +201,7 @@ const WASM_WHITELIST: &[(&str, Option<&str>)] = &[ /// /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this /// iterator! -pub fn all_known_features() -> impl Iterator)> { +pub fn all_known_features() -> impl Iterator)> { ARM_WHITELIST.iter().cloned() .chain(AARCH64_WHITELIST.iter().cloned()) .chain(X86_WHITELIST.iter().cloned()) @@ -245,7 +248,7 @@ pub fn target_features(sess: &Session) -> Vec { } pub fn target_feature_whitelist(sess: &Session) - -> &'static [(&'static str, Option<&'static str>)] + -> &'static [(&'static str, Option)] { match &*sess.target.target.arch { "arm" => ARM_WHITELIST, diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs index a2df687d58f5a..7cf497cb5d036 100644 --- a/src/librustc_codegen_llvm/metadata.rs +++ b/src/librustc_codegen_llvm/metadata.rs @@ -5,6 +5,8 @@ use rustc::middle::cstore::MetadataLoader; use rustc_target::spec::Target; use rustc_data_structures::owning_ref::OwningRef; +use rustc_codegen_ssa::METADATA_FILENAME; + use std::path::Path; use std::ptr; use std::slice; @@ -12,8 +14,6 @@ use rustc_fs_util::path_to_c_string; pub use rustc_data_structures::sync::MetadataRef; -pub const METADATA_FILENAME: &str = "rust.metadata.bin"; - pub struct LlvmMetadataLoader; impl MetadataLoader for LlvmMetadataLoader { diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs index 7f0cdb9f58008..c1703ffd0c753 100644 --- a/src/librustc_codegen_llvm/mono_item.rs +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -2,11 +2,10 @@ use crate::attributes; use crate::base; use crate::context::CodegenCx; use crate::llvm; -use crate::monomorphize::Instance; use crate::type_of::LayoutLlvmExt; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::mir::mono::{Linkage, Visibility}; -use rustc::ty::TypeFoldable; +use rustc::ty::{TypeFoldable, Instance}; use rustc::ty::layout::{LayoutOf, HasTyCtxt}; use rustc_codegen_ssa::traits::*; diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs index d5424fa459166..2c167256ad56c 100644 --- a/src/librustc_codegen_llvm/type_.rs +++ b/src/librustc_codegen_llvm/type_.rs @@ -10,16 +10,15 @@ use rustc_codegen_ssa::traits::*; use crate::common; use crate::type_of::LayoutLlvmExt; -use crate::abi::{LlvmType, FnTypeExt}; -use rustc::util::nodemap::FxHashMap; +use crate::abi::{LlvmType, FnTypeLlvmExt}; +use syntax::ast; use rustc::ty::Ty; -use rustc::ty::layout::TyLayout; +use rustc::ty::layout::{self, Align, Size, TyLayout}; use rustc_target::abi::call::{CastTarget, FnType, Reg}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_codegen_ssa::common::TypeKind; use std::fmt; -use std::cell::RefCell; use std::ptr; use libc::c_uint; @@ -52,21 +51,116 @@ impl CodegenCx<'ll, 'tcx> { els.len() as c_uint, packed as Bool) } } -} -impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn type_void(&self) -> &'ll Type { + crate fn type_void(&self) -> &'ll Type { unsafe { llvm::LLVMVoidTypeInContext(self.llcx) } } - fn type_metadata(&self) -> &'ll Type { + crate fn type_metadata(&self) -> &'ll Type { unsafe { llvm::LLVMRustMetadataTypeInContext(self.llcx) } } + ///x Creates an integer type with the given number of bits, e.g., i24 + crate fn type_ix(&self, num_bits: u64) -> &'ll Type { + unsafe { + llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint) + } + } + + crate fn type_x86_mmx(&self) -> &'ll Type { + unsafe { + llvm::LLVMX86MMXTypeInContext(self.llcx) + } + } + + crate fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { + unsafe { + llvm::LLVMVectorType(ty, len as c_uint) + } + } + + crate fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> { + unsafe { + let n_args = llvm::LLVMCountParamTypes(ty) as usize; + let mut args = Vec::with_capacity(n_args); + llvm::LLVMGetParamTypes(ty, args.as_mut_ptr()); + args.set_len(n_args); + args + } + } + + crate fn type_bool(&self) -> &'ll Type { + self.type_i8() + } + + crate fn type_int_from_ty(&self, t: ast::IntTy) -> &'ll Type { + match t { + ast::IntTy::Isize => self.type_isize(), + ast::IntTy::I8 => self.type_i8(), + ast::IntTy::I16 => self.type_i16(), + ast::IntTy::I32 => self.type_i32(), + ast::IntTy::I64 => self.type_i64(), + ast::IntTy::I128 => self.type_i128(), + } + } + + crate fn type_uint_from_ty(&self, t: ast::UintTy) -> &'ll Type { + match t { + ast::UintTy::Usize => self.type_isize(), + ast::UintTy::U8 => self.type_i8(), + ast::UintTy::U16 => self.type_i16(), + ast::UintTy::U32 => self.type_i32(), + ast::UintTy::U64 => self.type_i64(), + ast::UintTy::U128 => self.type_i128(), + } + } + + crate fn type_float_from_ty(&self, t: ast::FloatTy) -> &'ll Type { + match t { + ast::FloatTy::F32 => self.type_f32(), + ast::FloatTy::F64 => self.type_f64(), + } + } + + crate fn type_pointee_for_align(&self, align: Align) -> &'ll Type { + // FIXME(eddyb) We could find a better approximation if ity.align < align. + let ity = layout::Integer::approximate_align(self, align); + self.type_from_integer(ity) + } + + /// Return a LLVM type that has at most the required alignment, + /// and exactly the required size, as a best-effort padding array. + crate fn type_padding_filler(&self, size: Size, align: Align) -> &'ll Type { + let unit = layout::Integer::approximate_align(self, align); + let size = size.bytes(); + let unit_size = unit.size().bytes(); + assert_eq!(size % unit_size, 0); + self.type_array(self.type_from_integer(unit), size / unit_size) + } + + crate fn type_variadic_func( + &self, + args: &[&'ll Type], + ret: &'ll Type + ) -> &'ll Type { + unsafe { + llvm::LLVMFunctionType(ret, args.as_ptr(), + args.len() as c_uint, True) + } + } + + crate fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type { + unsafe { + llvm::LLVMRustArrayType(ty, len) + } + } +} + +impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn type_i1(&self) -> &'ll Type { unsafe { llvm::LLVMInt1TypeInContext(self.llcx) @@ -104,12 +198,6 @@ impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn type_ix(&self, num_bits: u64) -> &'ll Type { - unsafe { - llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint) - } - } - fn type_isize(&self) -> &'ll Type { self.isize_ty } @@ -126,12 +214,6 @@ impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn type_x86_mmx(&self) -> &'ll Type { - unsafe { - llvm::LLVMX86MMXTypeInContext(self.llcx) - } - } - fn type_func( &self, args: &[&'ll Type], @@ -143,17 +225,6 @@ impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn type_variadic_func( - &self, - args: &[&'ll Type], - ret: &'ll Type - ) -> &'ll Type { - unsafe { - llvm::LLVMFunctionType(ret, args.as_ptr(), - args.len() as c_uint, True) - } - } - fn type_struct( &self, els: &[&'ll Type], @@ -166,19 +237,6 @@ impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - - fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type { - unsafe { - llvm::LLVMRustArrayType(ty, len) - } - } - - fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { - unsafe { - llvm::LLVMVectorType(ty, len as c_uint) - } - } - fn type_kind(&self, ty: &'ll Type) -> TypeKind { unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() @@ -203,16 +261,6 @@ impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> { - unsafe { - let n_args = llvm::LLVMCountParamTypes(ty) as usize; - let mut args = Vec::with_capacity(n_args); - llvm::LLVMGetParamTypes(ty, args.as_mut_ptr()); - args.set_len(n_args); - args - } - } - fn float_width(&self, ty: &'ll Type) -> usize { match self.type_kind(ty) { TypeKind::Float => 32, @@ -232,10 +280,6 @@ impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn val_ty(&self, v: &'ll Value) -> &'ll Type { common::val_ty(v) } - - fn scalar_lltypes(&self) -> &RefCell, Self::Type>> { - &self.scalar_lltypes - } } impl Type { @@ -283,7 +327,7 @@ impl LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn backend_field_index(&self, layout: TyLayout<'tcx>, index: usize) -> u64 { layout.llvm_field_index(index) } - fn scalar_pair_element_backend_type<'a>( + fn scalar_pair_element_backend_type( &self, layout: TyLayout<'tcx>, index: usize, @@ -294,9 +338,6 @@ impl LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn cast_backend_type(&self, ty: &CastTarget) -> &'ll Type { ty.llvm_type(self) } - fn fn_backend_type(&self, ty: &FnType<'tcx, Ty<'tcx>>) -> &'ll Type { - ty.llvm_type(self) - } fn fn_ptr_backend_type(&self, ty: &FnType<'tcx, Ty<'tcx>>) -> &'ll Type { ty.ptr_to_llvm_type(self) } diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index fb5624d56078e..36a9ff0a2d2e5 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -1,11 +1,10 @@ -use crate::abi::{FnType, FnTypeExt}; +use crate::abi::{FnType}; use crate::common::*; use crate::type_::Type; -use rustc::hir; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout}; -use rustc_target::abi::FloatTy; -use rustc_mir::monomorphize::item::DefPathBasedNames; +use rustc::ty::layout::{self, Align, LayoutOf, FnTypeExt, PointeeInfo, Size, TyLayout}; +use rustc_target::abi::{FloatTy, TyLayoutMethods}; +use rustc::ty::print::obsolete::DefPathBasedNames; use rustc_codegen_ssa::traits::*; use std::fmt::Write; @@ -63,6 +62,11 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, write!(&mut name, "::{}", def.variants[index].ident).unwrap(); } } + if let (&ty::Generator(_, substs, _), &layout::Variants::Single { index }) + = (&layout.ty.sty, &layout.variants) + { + write!(&mut name, "::{}", substs.variant_name(index)).unwrap(); + } Some(name) } _ => None @@ -169,31 +173,9 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> { } } -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum PointerKind { - /// Most general case, we know no restrictions to tell LLVM. - Shared, - - /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`. - Frozen, - - /// `&mut T`, when we know `noalias` is safe for LLVM. - UniqueBorrowed, - - /// `Box`, unlike `UniqueBorrowed`, it also has `noalias` on returns. - UniqueOwned -} - -#[derive(Copy, Clone)] -pub struct PointeeInfo { - pub size: Size, - pub align: Align, - pub safe: Option, -} - pub trait LayoutLlvmExt<'tcx> { fn is_llvm_immediate(&self) -> bool; - fn is_llvm_scalar_pair<'a>(&self) -> bool; + fn is_llvm_scalar_pair(&self) -> bool; fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type; fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type; fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, @@ -216,7 +198,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { } } - fn is_llvm_scalar_pair<'a>(&self) -> bool { + fn is_llvm_scalar_pair(&self) -> bool { match self.abi { layout::Abi::ScalarPair(..) => true, layout::Abi::Uninhabited | @@ -401,110 +383,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { return pointee; } - let mut result = None; - match self.ty.sty { - ty::RawPtr(mt) if offset.bytes() == 0 => { - let (size, align) = cx.size_and_align_of(mt.ty); - result = Some(PointeeInfo { - size, - align, - safe: None - }); - } - - ty::Ref(_, ty, mt) if offset.bytes() == 0 => { - let (size, align) = cx.size_and_align_of(ty); - - let kind = match mt { - hir::MutImmutable => if cx.type_is_freeze(ty) { - PointerKind::Frozen - } else { - PointerKind::Shared - }, - hir::MutMutable => { - // Previously we would only emit noalias annotations for LLVM >= 6 or in - // panic=abort mode. That was deemed right, as prior versions had many bugs - // in conjunction with unwinding, but later versions didn’t seem to have - // said issues. See issue #31681. - // - // Alas, later on we encountered a case where noalias would generate wrong - // code altogether even with recent versions of LLVM in *safe* code with no - // unwinding involved. See #54462. - // - // For now, do not enable mutable_noalias by default at all, while the - // issue is being figured out. - let mutable_noalias = cx.tcx.sess.opts.debugging_opts.mutable_noalias - .unwrap_or(false); - if mutable_noalias { - PointerKind::UniqueBorrowed - } else { - PointerKind::Shared - } - } - }; - - result = Some(PointeeInfo { - size, - align, - safe: Some(kind) - }); - } - - _ => { - let mut data_variant = match self.variants { - layout::Variants::NicheFilling { dataful_variant, .. } => { - // Only the niche itself is always initialized, - // so only check for a pointer at its offset. - // - // If the niche is a pointer, it's either valid - // (according to its type), or null (which the - // niche field's scalar validity range encodes). - // This allows using `dereferenceable_or_null` - // for e.g., `Option<&T>`, and this will continue - // to work as long as we don't start using more - // niches than just null (e.g., the first page - // of the address space, or unaligned pointers). - if self.fields.offset(0) == offset { - Some(self.for_variant(cx, dataful_variant)) - } else { - None - } - } - _ => Some(*self) - }; - - if let Some(variant) = data_variant { - // We're not interested in any unions. - if let layout::FieldPlacement::Union(_) = variant.fields { - data_variant = None; - } - } - - if let Some(variant) = data_variant { - let ptr_end = offset + layout::Pointer.size(cx); - for i in 0..variant.fields.count() { - let field_start = variant.fields.offset(i); - if field_start <= offset { - let field = variant.field(cx, i); - if ptr_end <= field_start + field.size { - // We found the right field, look inside it. - result = field.pointee_info_at(cx, offset - field_start); - break; - } - } - } - } - - // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. - if let Some(ref mut pointee) = result { - if let ty::Adt(def, _) = self.ty.sty { - if def.is_box() && offset.bytes() == 0 { - pointee.safe = Some(PointerKind::UniqueOwned); - } - } - } - } - } + let result = Ty::pointee_info_at(*self, cx, offset); cx.pointee_infos.borrow_mut().insert((self.ty, offset), result); result diff --git a/src/librustc_codegen_llvm/va_arg.rs b/src/librustc_codegen_llvm/va_arg.rs index 7aceaea4510ce..86b0ad761af6a 100644 --- a/src/librustc_codegen_llvm/va_arg.rs +++ b/src/librustc_codegen_llvm/va_arg.rs @@ -108,12 +108,12 @@ pub(super) fn emit_va_arg( emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(4).unwrap(), true) } - // Windows Aarch64 + // Windows AArch64 ("aarch64", true) => { emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), false) } - // iOS Aarch64 + // iOS AArch64 ("aarch64", _) if target.target_os == "ios" => { emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), true) @@ -132,17 +132,6 @@ pub(super) fn emit_va_arg( // For all other architecture/OS combinations fall back to using // the LLVM va_arg instruction. // https://llvm.org/docs/LangRef.html#va-arg-instruction - _ => { - let va_list = if (target.arch == "aarch64" || - target.arch == "x86_64" || - target.arch == "powerpc") && - !target.options.is_like_windows { - bx.load(addr.immediate(), bx.tcx().data_layout.pointer_align.abi) - } else { - addr.immediate() - }; - bx.va_arg(va_list, bx.cx.layout_of(target_ty).llvm_type(bx.cx)) - } + _ => bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx)) } } - diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml index 0aba43580f1f6..a4cb517fafed6 100644 --- a/src/librustc_codegen_ssa/Cargo.toml +++ b/src/librustc_codegen_ssa/Cargo.toml @@ -14,11 +14,13 @@ test = false bitflags = "1.0.4" cc = "1.0.1" num_cpus = "1.0" -rustc-demangle = "0.1.4" +rustc-demangle = "0.1.15" memmap = "0.6" log = "0.4.5" libc = "0.2.44" jobserver = "0.1.11" +parking_lot = "0.7" +tempfile = "3.0.5" serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } @@ -31,5 +33,4 @@ rustc_data_structures = { path = "../librustc_data_structures"} rustc_errors = { path = "../librustc_errors" } rustc_fs_util = { path = "../librustc_fs_util" } rustc_incremental = { path = "../librustc_incremental" } -rustc_mir = { path = "../librustc_mir" } rustc_target = { path = "../librustc_target" } diff --git a/src/librustc_codegen_ssa/README.md b/src/librustc_codegen_ssa/README.md index 9e1d429180367..c8bb2e7ee9965 100644 --- a/src/librustc_codegen_ssa/README.md +++ b/src/librustc_codegen_ssa/README.md @@ -26,14 +26,14 @@ While the LLVM-specific code will be left in `rustc_codegen_llvm`, all the new t @irinagpopa started to parametrize the types of `rustc_codegen_llvm` by a generic `Value` type, implemented in LLVM by a reference `&'ll Value`. This work has been extended to all structures inside the `mir` folder and elsewhere, as well as for LLVM's `BasicBlock` and `Type` types. -The two most important structures for the LLVM codegen are `CodegenCx` and `Builder`. They are parametrized by multiple liftime parameters and the type for `Value`. +The two most important structures for the LLVM codegen are `CodegenCx` and `Builder`. They are parametrized by multiple lifetime parameters and the type for `Value`. ```rust -struct CodegenCx<'ll, 'tcx: 'll> { +struct CodegenCx<'ll, 'tcx> { /* ... */ } -struct Builder<'a, 'll: 'a, 'tcx: 'll> { +struct Builder<'a, 'll, 'tcx> { cx: &'a CodegenCx<'ll, 'tcx>, /* ... */ } @@ -49,7 +49,7 @@ The code in `rustc_codegen_llvm` has to deal with multiple explicit lifetime par Although there are already many lifetime parameters in the code, making it generic uncovered situations where the borrow-checker was passing only due to the special nature of the LLVM objects manipulated (they are extern pointers). For instance, a additional lifetime parameter had to be added to `LocalAnalyser` in `analyse.rs`, leading to the definition: ```rust -struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a> { +struct LocalAnalyzer<'mir, 'a, 'tcx> { /* ... */ } ``` @@ -61,7 +61,7 @@ However, the two most important structures `CodegenCx` and `Builder` are not def Because they have to be defined by the backend, `CodegenCx` and `Builder` will be the structures implementing all the traits defining the backend's interface. These traits are defined in the folder `rustc_codegen_ssa/traits` and all the backend-agnostic code is parametrized by them. For instance, let us explain how a function in `base.rs` is parametrized: ```rust -pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn codegen_instance<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, instance: Instance<'tcx> ) { @@ -74,7 +74,7 @@ In this signature, we have the two lifetime parameters explained earlier and the On the trait side, here is an example with part of the definition of `BuilderMethods` in `traits/builder.rs`: ```rust -pub trait BuilderMethods<'a, 'tcx: 'a>: +pub trait BuilderMethods<'a, 'tcx>: HasCodegen<'tcx> + DebugInfoBuilderMethods<'tcx> + ArgTypeMethods<'tcx> diff --git a/src/librustc_codegen_ssa/back/archive.rs b/src/librustc_codegen_ssa/back/archive.rs index 0a16d1b03e2a1..23d580ef08b2d 100644 --- a/src/librustc_codegen_ssa/back/archive.rs +++ b/src/librustc_codegen_ssa/back/archive.rs @@ -1,6 +1,7 @@ use rustc::session::Session; -use std::path::PathBuf; +use std::io; +use std::path::{Path, PathBuf}; pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session) -> PathBuf { @@ -24,3 +25,23 @@ pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session) sess.fatal(&format!("could not find native static library `{}`, \ perhaps an -L flag is missing?", name)); } + +pub trait ArchiveBuilder<'a> { + fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self; + + fn add_file(&mut self, path: &Path); + fn remove_file(&mut self, name: &str); + fn src_files(&mut self) -> Vec; + + fn add_rlib( + &mut self, + path: &Path, + name: &str, + lto: bool, + skip_objects: bool, + ) -> io::Result<()>; + fn add_native_library(&mut self, name: &str); + fn update_symbols(&mut self); + + fn build(self); +} diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 7f1aebace8fc6..e3d297e78623e 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -1,21 +1,40 @@ /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. -use rustc::session::{Session, config}; +use rustc::session::{Session, filesearch}; +use rustc::session::config::{ + self, RUST_CGU_EXT, DebugInfo, OutputFilenames, OutputType, PrintRequest, Sanitizer +}; use rustc::session::search_paths::PathKind; use rustc::middle::dependency_format::Linkage; -use rustc::middle::cstore::LibSource; -use rustc_target::spec::LinkerFlavor; +use rustc::middle::cstore::{EncodedMetadata, LibSource, NativeLibrary, NativeLibraryKind}; +use rustc::util::common::{time, time_ext}; use rustc::hir::def_id::CrateNum; +use rustc_data_structures::fx::FxHashSet; +use rustc_fs_util::fix_windows_verbatim_for_gcc; +use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor}; +use crate::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION, CrateInfo, CodegenResults}; +use super::archive::ArchiveBuilder; use super::command::Command; -use crate::CrateInfo; +use super::linker::Linker; +use super::rpath::{self, RPathConfig}; use cc::windows_registry; +use tempfile::{Builder as TempFileBuilder, TempDir}; + +use std::ascii; +use std::char; +use std::fmt; use std::fs; +use std::io; use std::path::{Path, PathBuf}; +use std::process::{Output, Stdio, ExitStatus}; +use std::str; use std::env; +pub use rustc_codegen_utils::link::*; + pub fn remove(sess: &Session, path: &Path) { if let Err(e) = fs::remove_file(path) { sess.err(&format!("failed to remove {}: {}", @@ -24,6 +43,94 @@ pub fn remove(sess: &Session, path: &Path) { } } +/// Performs the linkage portion of the compilation phase. This will generate all +/// of the requested outputs for this compilation session. +pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, + codegen_results: &CodegenResults, + outputs: &OutputFilenames, + crate_name: &str, + target_cpu: &str) { + let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); + for &crate_type in sess.crate_types.borrow().iter() { + // Ignore executable crates if we have -Z no-codegen, as they will error. + if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) && + !output_metadata && + crate_type == config::CrateType::Executable { + continue; + } + + if invalid_output_for_target(sess, crate_type) { + bug!("invalid output type `{:?}` for target os `{}`", + crate_type, sess.opts.target_triple); + } + + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { + check_file_is_writeable(obj, sess); + } + + let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err| + sess.fatal(&format!("couldn't create a temp dir: {}", err))); + + if outputs.outputs.should_codegen() { + let out_filename = out_filename(sess, crate_type, outputs, crate_name); + match crate_type { + config::CrateType::Rlib => { + link_rlib::(sess, + codegen_results, + RlibFlavor::Normal, + &out_filename, + &tmpdir).build(); + } + config::CrateType::Staticlib => { + link_staticlib::(sess, codegen_results, &out_filename, &tmpdir); + } + _ => { + link_natively::( + sess, + crate_type, + &out_filename, + codegen_results, + tmpdir.path(), + target_cpu, + ); + } + } + if sess.opts.debugging_opts.emit_artifact_notifications { + sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename, "link"); + } + } + + if sess.opts.cg.save_temps { + let _ = tmpdir.into_path(); + } + } + + // Remove the temporary object file and metadata if we aren't saving temps + if !sess.opts.cg.save_temps { + if sess.opts.output_types.should_codegen() && !preserve_objects_for_their_debuginfo(sess) { + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { + remove(sess, obj); + } + } + for obj in codegen_results.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) { + remove(sess, obj); + } + if let Some(ref metadata_module) = codegen_results.metadata_module { + if let Some(ref obj) = metadata_module.object { + remove(sess, obj); + } + } + if let Some(ref allocator_module) = codegen_results.allocator_module { + if let Some(ref obj) = allocator_module.object { + remove(sess, obj); + } + if let Some(ref bc) = allocator_module.bytecode_compressed { + remove(sess, bc); + } + } + } +} + // The third parameter is for env vars, used on windows to set up the // path for MSVC to find its DLLs, and gcc to find its bundled // toolchain @@ -116,6 +223,467 @@ pub fn each_linked_rlib(sess: &Session, Ok(()) } +/// We use a temp directory here to avoid races between concurrent rustc processes, +/// such as builds in the same directory using the same filename for metadata while +/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a +/// directory being searched for `extern crate` (observing an incomplete file). +/// The returned path is the temporary file containing the complete metadata. +pub fn emit_metadata<'a>( + sess: &'a Session, + metadata: &EncodedMetadata, + tmpdir: &TempDir +) -> PathBuf { + let out_filename = tmpdir.path().join(METADATA_FILENAME); + let result = fs::write(&out_filename, &metadata.raw_data); + + if let Err(e) = result { + sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); + } + + out_filename +} + +// Create an 'rlib' +// +// An rlib in its current incarnation is essentially a renamed .a file. The +// rlib primarily contains the object file of the crate, but it also contains +// all of the object files from native libraries. This is done by unzipping +// native libraries and inserting all of the contents into this archive. +fn link_rlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, + codegen_results: &CodegenResults, + flavor: RlibFlavor, + out_filename: &Path, + tmpdir: &TempDir) -> B { + info!("preparing rlib to {:?}", out_filename); + let mut ab = ::new(sess, out_filename, None); + + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { + ab.add_file(obj); + } + + // Note that in this loop we are ignoring the value of `lib.cfg`. That is, + // we may not be configured to actually include a static library if we're + // adding it here. That's because later when we consume this rlib we'll + // decide whether we actually needed the static library or not. + // + // To do this "correctly" we'd need to keep track of which libraries added + // which object files to the archive. We don't do that here, however. The + // #[link(cfg(..))] feature is unstable, though, and only intended to get + // liblibc working. In that sense the check below just indicates that if + // there are any libraries we want to omit object files for at link time we + // just exclude all custom object files. + // + // Eventually if we want to stabilize or flesh out the #[link(cfg(..))] + // feature then we'll need to figure out how to record what objects were + // loaded from the libraries found here and then encode that into the + // metadata of the rlib we're generating somehow. + for lib in codegen_results.crate_info.used_libraries.iter() { + match lib.kind { + NativeLibraryKind::NativeStatic => {} + NativeLibraryKind::NativeStaticNobundle | + NativeLibraryKind::NativeFramework | + NativeLibraryKind::NativeUnknown => continue, + } + if let Some(name) = lib.name { + ab.add_native_library(&name.as_str()); + } + } + + // After adding all files to the archive, we need to update the + // symbol table of the archive. + ab.update_symbols(); + + // Note that it is important that we add all of our non-object "magical + // files" *after* all of the object files in the archive. The reason for + // this is as follows: + // + // * When performing LTO, this archive will be modified to remove + // objects from above. The reason for this is described below. + // + // * When the system linker looks at an archive, it will attempt to + // determine the architecture of the archive in order to see whether its + // linkable. + // + // The algorithm for this detection is: iterate over the files in the + // archive. Skip magical SYMDEF names. Interpret the first file as an + // object file. Read architecture from the object file. + // + // * As one can probably see, if "metadata" and "foo.bc" were placed + // before all of the objects, then the architecture of this archive would + // not be correctly inferred once 'foo.o' is removed. + // + // Basically, all this means is that this code should not move above the + // code above. + match flavor { + RlibFlavor::Normal => { + // Instead of putting the metadata in an object file section, rlibs + // contain the metadata in a separate file. + ab.add_file(&emit_metadata(sess, &codegen_results.metadata, tmpdir)); + + // For LTO purposes, the bytecode of this library is also inserted + // into the archive. + for bytecode in codegen_results + .modules + .iter() + .filter_map(|m| m.bytecode_compressed.as_ref()) + { + ab.add_file(bytecode); + } + + // After adding all files to the archive, we need to update the + // symbol table of the archive. This currently dies on macOS (see + // #11162), and isn't necessary there anyway + if !sess.target.target.options.is_like_osx { + ab.update_symbols(); + } + } + + RlibFlavor::StaticlibBase => { + let obj = codegen_results.allocator_module + .as_ref() + .and_then(|m| m.object.as_ref()); + if let Some(obj) = obj { + ab.add_file(obj); + } + } + } + + ab +} + +// Create a static archive +// +// This is essentially the same thing as an rlib, but it also involves adding +// all of the upstream crates' objects into the archive. This will slurp in +// all of the native libraries of upstream dependencies as well. +// +// Additionally, there's no way for us to link dynamic libraries, so we warn +// about all dynamic library dependencies that they're not linked in. +// +// There's no need to include metadata in a static archive, so ensure to not +// link in the metadata object file (and also don't prepare the archive with a +// metadata file). +fn link_staticlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, + codegen_results: &CodegenResults, + out_filename: &Path, + tempdir: &TempDir) { + let mut ab = link_rlib::(sess, + codegen_results, + RlibFlavor::StaticlibBase, + out_filename, + tempdir); + let mut all_native_libs = vec![]; + + let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| { + let name = &codegen_results.crate_info.crate_name[&cnum]; + let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; + + // Here when we include the rlib into our staticlib we need to make a + // decision whether to include the extra object files along the way. + // These extra object files come from statically included native + // libraries, but they may be cfg'd away with #[link(cfg(..))]. + // + // This unstable feature, though, only needs liblibc to work. The only + // use case there is where musl is statically included in liblibc.rlib, + // so if we don't want the included version we just need to skip it. As + // a result the logic here is that if *any* linked library is cfg'd away + // we just skip all object files. + // + // Clearly this is not sufficient for a general purpose feature, and + // we'd want to read from the library's metadata to determine which + // object files come from where and selectively skip them. + let skip_object_files = native_libs.iter().any(|lib| { + lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) + }); + ab.add_rlib(path, + &name.as_str(), + are_upstream_rust_objects_already_included(sess) && + !ignored_for_lto(sess, &codegen_results.crate_info, cnum), + skip_object_files).unwrap(); + + all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned()); + }); + if let Err(e) = res { + sess.fatal(&e); + } + + ab.update_symbols(); + ab.build(); + + if !all_native_libs.is_empty() { + if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) { + print_native_static_libs(sess, &all_native_libs); + } + } +} + +// Create a dynamic library or executable +// +// This will invoke the system linker/cc to create the resulting file. This +// links to all upstream files as well. +fn link_natively<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, + crate_type: config::CrateType, + out_filename: &Path, + codegen_results: &CodegenResults, + tmpdir: &Path, + target_cpu: &str) { + info!("preparing {:?} to {:?}", crate_type, out_filename); + let (linker, flavor) = linker_and_flavor(sess); + + // The invocations of cc share some flags across platforms + let (pname, mut cmd) = get_linker(sess, &linker, flavor); + + if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) { + cmd.args(args); + } + if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) { + if sess.crt_static() { + cmd.args(args); + } + } + if let Some(ref args) = sess.opts.debugging_opts.pre_link_args { + cmd.args(args); + } + cmd.args(&sess.opts.debugging_opts.pre_link_arg); + + if sess.target.target.options.is_like_fuchsia { + let prefix = match sess.opts.debugging_opts.sanitizer { + Some(Sanitizer::Address) => "asan/", + _ => "", + }; + cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix)); + } + + let pre_link_objects = if crate_type == config::CrateType::Executable { + &sess.target.target.options.pre_link_objects_exe + } else { + &sess.target.target.options.pre_link_objects_dll + }; + for obj in pre_link_objects { + cmd.arg(get_file_path(sess, obj)); + } + + if crate_type == config::CrateType::Executable && sess.crt_static() { + for obj in &sess.target.target.options.pre_link_objects_exe_crt { + cmd.arg(get_file_path(sess, obj)); + } + } + + if sess.target.target.options.is_like_emscripten { + cmd.arg("-s"); + cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort { + "DISABLE_EXCEPTION_CATCHING=1" + } else { + "DISABLE_EXCEPTION_CATCHING=0" + }); + } + + { + let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor, target_cpu); + link_args::(&mut *linker, flavor, sess, crate_type, tmpdir, + out_filename, codegen_results); + cmd = linker.finalize(); + } + if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { + cmd.args(args); + } + for obj in &sess.target.target.options.post_link_objects { + cmd.arg(get_file_path(sess, obj)); + } + if sess.crt_static() { + for obj in &sess.target.target.options.post_link_objects_crt { + cmd.arg(get_file_path(sess, obj)); + } + } + if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) { + cmd.args(args); + } + for &(ref k, ref v) in &sess.target.target.options.link_env { + cmd.env(k, v); + } + + if sess.opts.debugging_opts.print_link_args { + println!("{:?}", &cmd); + } + + // May have not found libraries in the right formats. + sess.abort_if_errors(); + + // Invoke the system linker + info!("{:?}", &cmd); + let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok(); + let mut prog; + let mut i = 0; + loop { + i += 1; + prog = time(sess, "running linker", || { + exec_linker(sess, &mut cmd, out_filename, tmpdir) + }); + let output = match prog { + Ok(ref output) => output, + Err(_) => break, + }; + if output.status.success() { + break + } + let mut out = output.stderr.clone(); + out.extend(&output.stdout); + let out = String::from_utf8_lossy(&out); + + // Check to see if the link failed with "unrecognized command line option: + // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so, + // reperform the link step without the -no-pie option. This is safe because + // if the linker doesn't support -no-pie then it should not default to + // linking executables as pie. Different versions of gcc seem to use + // different quotes in the error message so don't check for them. + if sess.target.target.options.linker_is_gnu && + flavor != LinkerFlavor::Ld && + (out.contains("unrecognized command line option") || + out.contains("unknown argument")) && + out.contains("-no-pie") && + cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie") { + info!("linker output: {:?}", out); + warn!("Linker does not support -no-pie command line option. Retrying without."); + for arg in cmd.take_args() { + if arg.to_string_lossy() != "-no-pie" { + cmd.arg(arg); + } + } + info!("{:?}", &cmd); + continue; + } + + // Here's a terribly awful hack that really shouldn't be present in any + // compiler. Here an environment variable is supported to automatically + // retry the linker invocation if the linker looks like it segfaulted. + // + // Gee that seems odd, normally segfaults are things we want to know + // about! Unfortunately though in rust-lang/rust#38878 we're + // experiencing the linker segfaulting on Travis quite a bit which is + // causing quite a bit of pain to land PRs when they spuriously fail + // due to a segfault. + // + // The issue #38878 has some more debugging information on it as well, + // but this unfortunately looks like it's just a race condition in + // macOS's linker with some thread pool working in the background. It + // seems that no one currently knows a fix for this so in the meantime + // we're left with this... + if !retry_on_segfault || i > 3 { + break + } + let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11"; + let msg_bus = "clang: error: unable to execute command: Bus error: 10"; + if out.contains(msg_segv) || out.contains(msg_bus) { + warn!( + "looks like the linker segfaulted when we tried to call it, \ + automatically retrying again. cmd = {:?}, out = {}.", + cmd, + out, + ); + continue; + } + + if is_illegal_instruction(&output.status) { + warn!( + "looks like the linker hit an illegal instruction when we \ + tried to call it, automatically retrying again. cmd = {:?}, ]\ + out = {}, status = {}.", + cmd, + out, + output.status, + ); + continue; + } + + #[cfg(unix)] + fn is_illegal_instruction(status: &ExitStatus) -> bool { + use std::os::unix::prelude::*; + status.signal() == Some(libc::SIGILL) + } + + #[cfg(windows)] + fn is_illegal_instruction(_status: &ExitStatus) -> bool { + false + } + } + + match prog { + Ok(prog) => { + fn escape_string(s: &[u8]) -> String { + str::from_utf8(s).map(|s| s.to_owned()) + .unwrap_or_else(|_| { + let mut x = "Non-UTF-8 output: ".to_string(); + x.extend(s.iter() + .flat_map(|&b| ascii::escape_default(b)) + .map(char::from)); + x + }) + } + if !prog.status.success() { + let mut output = prog.stderr.clone(); + output.extend_from_slice(&prog.stdout); + sess.struct_err(&format!("linking with `{}` failed: {}", + pname.display(), + prog.status)) + .note(&format!("{:?}", &cmd)) + .note(&escape_string(&output)) + .emit(); + sess.abort_if_errors(); + } + info!("linker stderr:\n{}", escape_string(&prog.stderr)); + info!("linker stdout:\n{}", escape_string(&prog.stdout)); + }, + Err(e) => { + let linker_not_found = e.kind() == io::ErrorKind::NotFound; + + let mut linker_error = { + if linker_not_found { + sess.struct_err(&format!("linker `{}` not found", pname.display())) + } else { + sess.struct_err(&format!("could not exec the linker `{}`", pname.display())) + } + }; + + linker_error.note(&e.to_string()); + + if !linker_not_found { + linker_error.note(&format!("{:?}", &cmd)); + } + + linker_error.emit(); + + if sess.target.target.options.is_like_msvc && linker_not_found { + sess.note_without_error("the msvc targets depend on the msvc linker \ + but `link.exe` was not found"); + sess.note_without_error("please ensure that VS 2013, VS 2015 or VS 2017 \ + was installed with the Visual C++ option"); + } + sess.abort_if_errors(); + } + } + + + // On macOS, debuggers need this utility to get run to do some munging of + // the symbols. Note, though, that if the object files are being preserved + // for their debug information there's no need for us to run dsymutil. + if sess.target.target.options.is_like_osx && + sess.opts.debuginfo != DebugInfo::None && + !preserve_objects_for_their_debuginfo(sess) + { + if let Err(e) = Command::new("dsymutil").arg(out_filename).output() { + sess.fatal(&format!("failed to run dsymutil: {}", e)) + } + } + + if sess.opts.target_triple.triple() == "wasm32-unknown-unknown" { + super::wasm::add_producer_section( + &out_filename, + &sess.edition().to_string(), + option_env!("CFG_VERSION").unwrap_or("unknown"), + ); + } +} + /// Returns a boolean indicating whether the specified crate should be ignored /// during LTO. /// @@ -152,17 +720,20 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { LinkerFlavor::PtxLinker => "rust-ptx-linker", }), flavor)), (Some(linker), None) => { - let stem = if linker.extension().and_then(|ext| ext.to_str()) == Some("exe") { - linker.file_stem().and_then(|stem| stem.to_str()) - } else { - linker.to_str() - }.unwrap_or_else(|| { - sess.fatal("couldn't extract file stem from specified linker"); - }).to_owned(); + let stem = linker + .file_stem() + .and_then(|stem| stem.to_str()) + .unwrap_or_else(|| { + sess.fatal("couldn't extract file stem from specified linker") + }); let flavor = if stem == "emcc" { LinkerFlavor::Em - } else if stem == "gcc" || stem.ends_with("-gcc") { + } else if stem == "gcc" + || stem.ends_with("-gcc") + || stem == "clang" + || stem.ends_with("-clang") + { LinkerFlavor::Gcc } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") { LinkerFlavor::Ld @@ -197,3 +768,899 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { bug!("Not enough information provided to determine how to invoke the linker"); } + +/// Returns a boolean indicating whether we should preserve the object files on +/// the filesystem for their debug information. This is often useful with +/// split-dwarf like schemes. +pub fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { + // If the objects don't have debuginfo there's nothing to preserve. + if sess.opts.debuginfo == config::DebugInfo::None { + return false + } + + // If we're only producing artifacts that are archives, no need to preserve + // the objects as they're losslessly contained inside the archives. + let output_linked = sess.crate_types.borrow() + .iter() + .any(|&x| x != config::CrateType::Rlib && x != config::CrateType::Staticlib); + if !output_linked { + return false + } + + // If we're on OSX then the equivalent of split dwarf is turned on by + // default. The final executable won't actually have any debug information + // except it'll have pointers to elsewhere. Historically we've always run + // `dsymutil` to "link all the dwarf together" but this is actually sort of + // a bummer for incremental compilation! (the whole point of split dwarf is + // that you don't do this sort of dwarf link). + // + // Basically as a result this just means that if we're on OSX and we're + // *not* running dsymutil then the object files are the only source of truth + // for debug information, so we must preserve them. + if sess.target.target.options.is_like_osx { + match sess.opts.debugging_opts.run_dsymutil { + // dsymutil is not being run, preserve objects + Some(false) => return true, + + // dsymutil is being run, no need to preserve the objects + Some(true) => return false, + + // The default historical behavior was to always run dsymutil, so + // we're preserving that temporarily, but we're likely to switch the + // default soon. + None => return false, + } + } + + false +} + +pub fn archive_search_paths(sess: &Session) -> Vec { + sess.target_filesearch(PathKind::Native).search_path_dirs() +} + +enum RlibFlavor { + Normal, + StaticlibBase, +} + +pub fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) { + let lib_args: Vec<_> = all_native_libs.iter() + .filter(|l| relevant_lib(sess, l)) + .filter_map(|lib| { + let name = lib.name?; + match lib.kind { + NativeLibraryKind::NativeStaticNobundle | + NativeLibraryKind::NativeUnknown => { + if sess.target.target.options.is_like_msvc { + Some(format!("{}.lib", name)) + } else { + Some(format!("-l{}", name)) + } + }, + NativeLibraryKind::NativeFramework => { + // ld-only syntax, since there are no frameworks in MSVC + Some(format!("-framework {}", name)) + }, + // These are included, no need to print them + NativeLibraryKind::NativeStatic => None, + } + }) + .collect(); + if !lib_args.is_empty() { + sess.note_without_error("Link against the following native artifacts when linking \ + against this static library. The order and any duplication \ + can be significant on some platforms."); + // Prefix for greppability + sess.note_without_error(&format!("native-static-libs: {}", &lib_args.join(" "))); + } +} + +pub fn get_file_path(sess: &Session, name: &str) -> PathBuf { + let fs = sess.target_filesearch(PathKind::Native); + let file_path = fs.get_lib_path().join(name); + if file_path.exists() { + return file_path + } + for search_path in fs.search_paths() { + let file_path = search_path.dir.join(name); + if file_path.exists() { + return file_path + } + } + PathBuf::from(name) +} + +pub fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &Path) + -> io::Result +{ + // When attempting to spawn the linker we run a risk of blowing out the + // size limits for spawning a new process with respect to the arguments + // we pass on the command line. + // + // Here we attempt to handle errors from the OS saying "your list of + // arguments is too big" by reinvoking the linker again with an `@`-file + // that contains all the arguments. The theory is that this is then + // accepted on all linkers and the linker will read all its options out of + // there instead of looking at the command line. + if !cmd.very_likely_to_exceed_some_spawn_limit() { + match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() { + Ok(child) => { + let output = child.wait_with_output(); + flush_linked_file(&output, out_filename)?; + return output; + } + Err(ref e) if command_line_too_big(e) => { + info!("command line to linker was too big: {}", e); + } + Err(e) => return Err(e) + } + } + + info!("falling back to passing arguments to linker via an @-file"); + let mut cmd2 = cmd.clone(); + let mut args = String::new(); + for arg in cmd2.take_args() { + args.push_str(&Escape { + arg: arg.to_str().unwrap(), + is_like_msvc: sess.target.target.options.is_like_msvc, + }.to_string()); + args.push_str("\n"); + } + let file = tmpdir.join("linker-arguments"); + let bytes = if sess.target.target.options.is_like_msvc { + let mut out = Vec::with_capacity((1 + args.len()) * 2); + // start the stream with a UTF-16 BOM + for c in std::iter::once(0xFEFF).chain(args.encode_utf16()) { + // encode in little endian + out.push(c as u8); + out.push((c >> 8) as u8); + } + out + } else { + args.into_bytes() + }; + fs::write(&file, &bytes)?; + cmd2.arg(format!("@{}", file.display())); + info!("invoking linker {:?}", cmd2); + let output = cmd2.output(); + flush_linked_file(&output, out_filename)?; + return output; + + #[cfg(unix)] + fn flush_linked_file(_: &io::Result, _: &Path) -> io::Result<()> { + Ok(()) + } + + #[cfg(windows)] + fn flush_linked_file(command_output: &io::Result, out_filename: &Path) + -> io::Result<()> + { + // On Windows, under high I/O load, output buffers are sometimes not flushed, + // even long after process exit, causing nasty, non-reproducible output bugs. + // + // File::sync_all() calls FlushFileBuffers() down the line, which solves the problem. + // + // А full writeup of the original Chrome bug can be found at + // randomascii.wordpress.com/2018/02/25/compiler-bug-linker-bug-windows-kernel-bug/amp + + if let &Ok(ref out) = command_output { + if out.status.success() { + if let Ok(of) = fs::OpenOptions::new().write(true).open(out_filename) { + of.sync_all()?; + } + } + } + + Ok(()) + } + + #[cfg(unix)] + fn command_line_too_big(err: &io::Error) -> bool { + err.raw_os_error() == Some(::libc::E2BIG) + } + + #[cfg(windows)] + fn command_line_too_big(err: &io::Error) -> bool { + const ERROR_FILENAME_EXCED_RANGE: i32 = 206; + err.raw_os_error() == Some(ERROR_FILENAME_EXCED_RANGE) + } + + struct Escape<'a> { + arg: &'a str, + is_like_msvc: bool, + } + + impl<'a> fmt::Display for Escape<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.is_like_msvc { + // This is "documented" at + // https://msdn.microsoft.com/en-us/library/4xdcbak7.aspx + // + // Unfortunately there's not a great specification of the + // syntax I could find online (at least) but some local + // testing showed that this seemed sufficient-ish to catch + // at least a few edge cases. + write!(f, "\"")?; + for c in self.arg.chars() { + match c { + '"' => write!(f, "\\{}", c)?, + c => write!(f, "{}", c)?, + } + } + write!(f, "\"")?; + } else { + // This is documented at https://linux.die.net/man/1/ld, namely: + // + // > Options in file are separated by whitespace. A whitespace + // > character may be included in an option by surrounding the + // > entire option in either single or double quotes. Any + // > character (including a backslash) may be included by + // > prefixing the character to be included with a backslash. + // + // We put an argument on each line, so all we need to do is + // ensure the line is interpreted as one whole argument. + for c in self.arg.chars() { + match c { + '\\' | ' ' => write!(f, "\\{}", c)?, + c => write!(f, "{}", c)?, + } + } + } + Ok(()) + } + } +} + +fn link_args<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, + flavor: LinkerFlavor, + sess: &'a Session, + crate_type: config::CrateType, + tmpdir: &Path, + out_filename: &Path, + codegen_results: &CodegenResults) { + + // Linker plugins should be specified early in the list of arguments + cmd.linker_plugin_lto(); + + // The default library location, we need this to find the runtime. + // The location of crates will be determined as needed. + let lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); + + // target descriptor + let t = &sess.target.target; + + cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { + cmd.add_object(obj); + } + cmd.output_filename(out_filename); + + if crate_type == config::CrateType::Executable && + sess.target.target.options.is_like_windows { + if let Some(ref s) = codegen_results.windows_subsystem { + cmd.subsystem(s); + } + } + + // If we're building something like a dynamic library then some platforms + // need to make sure that all symbols are exported correctly from the + // dynamic library. + cmd.export_symbols(tmpdir, crate_type); + + // When linking a dynamic library, we put the metadata into a section of the + // executable. This metadata is in a separate object file from the main + // object file, so we link that in here. + if crate_type == config::CrateType::Dylib || + crate_type == config::CrateType::ProcMacro { + let obj = codegen_results.metadata_module + .as_ref() + .and_then(|m| m.object.as_ref()); + if let Some(obj) = obj { + cmd.add_object(obj); + } + } + + let obj = codegen_results.allocator_module + .as_ref() + .and_then(|m| m.object.as_ref()); + if let Some(obj) = obj { + cmd.add_object(obj); + } + + // Try to strip as much out of the generated object by removing unused + // sections if possible. See more comments in linker.rs + if !sess.opts.cg.link_dead_code { + let keep_metadata = crate_type == config::CrateType::Dylib; + cmd.gc_sections(keep_metadata); + } + + let used_link_args = &codegen_results.crate_info.link_args; + + if crate_type == config::CrateType::Executable { + let mut position_independent_executable = false; + + if t.options.position_independent_executables { + let empty_vec = Vec::new(); + let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec); + let more_args = &sess.opts.cg.link_arg; + let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter()); + + if is_pic(sess) && !sess.crt_static() && !args.any(|x| *x == "-static") { + position_independent_executable = true; + } + } + + if position_independent_executable { + cmd.position_independent_executable(); + } else { + // recent versions of gcc can be configured to generate position + // independent executables by default. We have to pass -no-pie to + // explicitly turn that off. Not applicable to ld. + if sess.target.target.options.linker_is_gnu + && flavor != LinkerFlavor::Ld { + cmd.no_position_independent_executable(); + } + } + } + + let relro_level = match sess.opts.debugging_opts.relro_level { + Some(level) => level, + None => t.options.relro_level, + }; + match relro_level { + RelroLevel::Full => { + cmd.full_relro(); + }, + RelroLevel::Partial => { + cmd.partial_relro(); + }, + RelroLevel::Off => { + cmd.no_relro(); + }, + RelroLevel::None => { + }, + } + + // Pass optimization flags down to the linker. + cmd.optimize(); + + // Pass debuginfo flags down to the linker. + cmd.debuginfo(); + + // We want to, by default, prevent the compiler from accidentally leaking in + // any system libraries, so we may explicitly ask linkers to not link to any + // libraries by default. Note that this does not happen for windows because + // windows pulls in some large number of libraries and I couldn't quite + // figure out which subset we wanted. + // + // This is all naturally configurable via the standard methods as well. + if !sess.opts.cg.default_linker_libraries.unwrap_or(false) && + t.options.no_default_libraries + { + cmd.no_default_libraries(); + } + + // Take careful note of the ordering of the arguments we pass to the linker + // here. Linkers will assume that things on the left depend on things to the + // right. Things on the right cannot depend on things on the left. This is + // all formally implemented in terms of resolving symbols (libs on the right + // resolve unknown symbols of libs on the left, but not vice versa). + // + // For this reason, we have organized the arguments we pass to the linker as + // such: + // + // 1. The local object that LLVM just generated + // 2. Local native libraries + // 3. Upstream rust libraries + // 4. Upstream native libraries + // + // The rationale behind this ordering is that those items lower down in the + // list can't depend on items higher up in the list. For example nothing can + // depend on what we just generated (e.g., that'd be a circular dependency). + // Upstream rust libraries are not allowed to depend on our local native + // libraries as that would violate the structure of the DAG, in that + // scenario they are required to link to them as well in a shared fashion. + // + // Note that upstream rust libraries may contain native dependencies as + // well, but they also can't depend on what we just started to add to the + // link line. And finally upstream native libraries can't depend on anything + // in this DAG so far because they're only dylibs and dylibs can only depend + // on other dylibs (e.g., other native deps). + add_local_native_libraries(cmd, sess, codegen_results); + add_upstream_rust_crates::(cmd, sess, codegen_results, crate_type, tmpdir); + add_upstream_native_libraries(cmd, sess, codegen_results, crate_type); + + // Tell the linker what we're doing. + if crate_type != config::CrateType::Executable { + cmd.build_dylib(out_filename); + } + if crate_type == config::CrateType::Executable && sess.crt_static() { + cmd.build_static_executable(); + } + + if sess.opts.cg.profile_generate.enabled() { + cmd.pgo_gen(); + } + + // FIXME (#2397): At some point we want to rpath our guesses as to + // where extern libraries might live, based on the + // addl_lib_search_paths + if sess.opts.cg.rpath { + let target_triple = sess.opts.target_triple.triple(); + let mut get_install_prefix_lib_path = || { + let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX"); + let tlib = filesearch::relative_target_lib_path(&sess.sysroot, target_triple); + let mut path = PathBuf::from(install_prefix); + path.push(&tlib); + + path + }; + let mut rpath_config = RPathConfig { + used_crates: &codegen_results.crate_info.used_crates_dynamic, + out_filename: out_filename.to_path_buf(), + has_rpath: sess.target.target.options.has_rpath, + is_like_osx: sess.target.target.options.is_like_osx, + linker_is_gnu: sess.target.target.options.linker_is_gnu, + get_install_prefix_lib_path: &mut get_install_prefix_lib_path, + }; + cmd.args(&rpath::get_rpath_flags(&mut rpath_config)); + } + + // Finally add all the linker arguments provided on the command line along + // with any #[link_args] attributes found inside the crate + if let Some(ref args) = sess.opts.cg.link_args { + cmd.args(args); + } + cmd.args(&sess.opts.cg.link_arg); + cmd.args(&used_link_args); +} + +// # Native library linking +// +// User-supplied library search paths (-L on the command line). These are +// the same paths used to find Rust crates, so some of them may have been +// added already by the previous crate linking code. This only allows them +// to be found at compile time so it is still entirely up to outside +// forces to make sure that library can be found at runtime. +// +// Also note that the native libraries linked here are only the ones located +// in the current crate. Upstream crates with native library dependencies +// may have their native library pulled in above. +pub fn add_local_native_libraries(cmd: &mut dyn Linker, + sess: &Session, + codegen_results: &CodegenResults) { + let filesearch = sess.target_filesearch(PathKind::All); + for search_path in filesearch.search_paths() { + match search_path.kind { + PathKind::Framework => { cmd.framework_path(&search_path.dir); } + _ => { cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir)); } + } + } + + let relevant_libs = codegen_results.crate_info.used_libraries.iter().filter(|l| { + relevant_lib(sess, l) + }); + + let search_path = archive_search_paths(sess); + for lib in relevant_libs { + let name = match lib.name { + Some(ref l) => l, + None => continue, + }; + match lib.kind { + NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()), + NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()), + NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&name.as_str()), + NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&name.as_str(), + &search_path) + } + } +} + +// # Rust Crate linking +// +// Rust crates are not considered at all when creating an rlib output. All +// dependencies will be linked when producing the final output (instead of +// the intermediate rlib version) +fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, + sess: &'a Session, + codegen_results: &CodegenResults, + crate_type: config::CrateType, + tmpdir: &Path) { + // All of the heavy lifting has previously been accomplished by the + // dependency_format module of the compiler. This is just crawling the + // output of that module, adding crates as necessary. + // + // Linking to a rlib involves just passing it to the linker (the linker + // will slurp up the object files inside), and linking to a dynamic library + // involves just passing the right -l flag. + + let formats = sess.dependency_formats.borrow(); + let data = formats.get(&crate_type).unwrap(); + + // Invoke get_used_crates to ensure that we get a topological sorting of + // crates. + let deps = &codegen_results.crate_info.used_crates_dynamic; + + // There's a few internal crates in the standard library (aka libcore and + // libstd) which actually have a circular dependence upon one another. This + // currently arises through "weak lang items" where libcore requires things + // like `rust_begin_unwind` but libstd ends up defining it. To get this + // circular dependence to work correctly in all situations we'll need to be + // sure to correctly apply the `--start-group` and `--end-group` options to + // GNU linkers, otherwise if we don't use any other symbol from the standard + // library it'll get discarded and the whole application won't link. + // + // In this loop we're calculating the `group_end`, after which crate to + // pass `--end-group` and `group_start`, before which crate to pass + // `--start-group`. We currently do this by passing `--end-group` after + // the first crate (when iterating backwards) that requires a lang item + // defined somewhere else. Once that's set then when we've defined all the + // necessary lang items we'll pass `--start-group`. + // + // Note that this isn't amazing logic for now but it should do the trick + // for the current implementation of the standard library. + let mut group_end = None; + let mut group_start = None; + let mut end_with = FxHashSet::default(); + let info = &codegen_results.crate_info; + for &(cnum, _) in deps.iter().rev() { + if let Some(missing) = info.missing_lang_items.get(&cnum) { + end_with.extend(missing.iter().cloned()); + if end_with.len() > 0 && group_end.is_none() { + group_end = Some(cnum); + } + } + end_with.retain(|item| info.lang_item_to_crate.get(item) != Some(&cnum)); + if end_with.len() == 0 && group_end.is_some() { + group_start = Some(cnum); + break + } + } + + // If we didn't end up filling in all lang items from upstream crates then + // we'll be filling it in with our crate. This probably means we're the + // standard library itself, so skip this for now. + if group_end.is_some() && group_start.is_none() { + group_end = None; + } + + let mut compiler_builtins = None; + + for &(cnum, _) in deps.iter() { + if group_start == Some(cnum) { + cmd.group_start(); + } + + // We may not pass all crates through to the linker. Some crates may + // appear statically in an existing dylib, meaning we'll pick up all the + // symbols from the dylib. + let src = &codegen_results.crate_info.used_crate_source[&cnum]; + match data[cnum.as_usize() - 1] { + _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => { + add_static_crate::(cmd, sess, codegen_results, tmpdir, crate_type, cnum); + } + _ if codegen_results.crate_info.sanitizer_runtime == Some(cnum) => { + link_sanitizer_runtime::(cmd, sess, codegen_results, tmpdir, cnum); + } + // compiler-builtins are always placed last to ensure that they're + // linked correctly. + _ if codegen_results.crate_info.compiler_builtins == Some(cnum) => { + assert!(compiler_builtins.is_none()); + compiler_builtins = Some(cnum); + } + Linkage::NotLinked | + Linkage::IncludedFromDylib => {} + Linkage::Static => { + add_static_crate::(cmd, sess, codegen_results, tmpdir, crate_type, cnum); + } + Linkage::Dynamic => { + add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0) + } + } + + if group_end == Some(cnum) { + cmd.group_end(); + } + } + + // compiler-builtins are always placed last to ensure that they're + // linked correctly. + // We must always link the `compiler_builtins` crate statically. Even if it + // was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic` + // is used) + if let Some(cnum) = compiler_builtins { + add_static_crate::(cmd, sess, codegen_results, tmpdir, crate_type, cnum); + } + + // Converts a library file-stem into a cc -l argument + fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str { + if stem.starts_with("lib") && !config.target.options.is_like_windows { + &stem[3..] + } else { + stem + } + } + + // We must link the sanitizer runtime using -Wl,--whole-archive but since + // it's packed in a .rlib, it contains stuff that are not objects that will + // make the linker error. So we must remove those bits from the .rlib before + // linking it. + fn link_sanitizer_runtime<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, + sess: &'a Session, + codegen_results: &CodegenResults, + tmpdir: &Path, + cnum: CrateNum) { + let src = &codegen_results.crate_info.used_crate_source[&cnum]; + let cratepath = &src.rlib.as_ref().unwrap().0; + + if sess.target.target.options.is_like_osx { + // On Apple platforms, the sanitizer is always built as a dylib, and + // LLVM will link to `@rpath/*.dylib`, so we need to specify an + // rpath to the library as well (the rpath should be absolute, see + // PR #41352 for details). + // + // FIXME: Remove this logic into librustc_*san once Cargo supports it + let rpath = cratepath.parent().unwrap(); + let rpath = rpath.to_str().expect("non-utf8 component in path"); + cmd.args(&["-Wl,-rpath".into(), "-Xlinker".into(), rpath.into()]); + } + + let dst = tmpdir.join(cratepath.file_name().unwrap()); + let mut archive = ::new(sess, &dst, Some(cratepath)); + archive.update_symbols(); + + for f in archive.src_files() { + if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME { + archive.remove_file(&f); + } + } + + archive.build(); + + cmd.link_whole_rlib(&dst); + } + + // Adds the static "rlib" versions of all crates to the command line. + // There's a bit of magic which happens here specifically related to LTO and + // dynamic libraries. Specifically: + // + // * For LTO, we remove upstream object files. + // * For dylibs we remove metadata and bytecode from upstream rlibs + // + // When performing LTO, almost(*) all of the bytecode from the upstream + // libraries has already been included in our object file output. As a + // result we need to remove the object files in the upstream libraries so + // the linker doesn't try to include them twice (or whine about duplicate + // symbols). We must continue to include the rest of the rlib, however, as + // it may contain static native libraries which must be linked in. + // + // (*) Crates marked with `#![no_builtins]` don't participate in LTO and + // their bytecode wasn't included. The object files in those libraries must + // still be passed to the linker. + // + // When making a dynamic library, linkers by default don't include any + // object files in an archive if they're not necessary to resolve the link. + // We basically want to convert the archive (rlib) to a dylib, though, so we + // *do* want everything included in the output, regardless of whether the + // linker thinks it's needed or not. As a result we must use the + // --whole-archive option (or the platform equivalent). When using this + // option the linker will fail if there are non-objects in the archive (such + // as our own metadata and/or bytecode). All in all, for rlibs to be + // entirely included in dylibs, we need to remove all non-object files. + // + // Note, however, that if we're not doing LTO or we're not producing a dylib + // (aka we're making an executable), we can just pass the rlib blindly to + // the linker (fast) because it's fine if it's not actually included as + // we're at the end of the dependency chain. + fn add_static_crate<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, + sess: &'a Session, + codegen_results: &CodegenResults, + tmpdir: &Path, + crate_type: config::CrateType, + cnum: CrateNum) { + let src = &codegen_results.crate_info.used_crate_source[&cnum]; + let cratepath = &src.rlib.as_ref().unwrap().0; + + // See the comment above in `link_staticlib` and `link_rlib` for why if + // there's a static library that's not relevant we skip all object + // files. + let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; + let skip_native = native_libs.iter().any(|lib| { + lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) + }); + + if (!are_upstream_rust_objects_already_included(sess) || + ignored_for_lto(sess, &codegen_results.crate_info, cnum)) && + crate_type != config::CrateType::Dylib && + !skip_native { + cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); + return + } + + let dst = tmpdir.join(cratepath.file_name().unwrap()); + let name = cratepath.file_name().unwrap().to_str().unwrap(); + let name = &name[3..name.len() - 5]; // chop off lib/.rlib + + time_ext(sess.time_extended(), Some(sess), &format!("altering {}.rlib", name), || { + let mut archive = ::new(sess, &dst, Some(cratepath)); + archive.update_symbols(); + + let mut any_objects = false; + for f in archive.src_files() { + if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME { + archive.remove_file(&f); + continue + } + + let canonical = f.replace("-", "_"); + let canonical_name = name.replace("-", "_"); + + // Look for `.rcgu.o` at the end of the filename to conclude + // that this is a Rust-related object file. + fn looks_like_rust(s: &str) -> bool { + let path = Path::new(s); + let ext = path.extension().and_then(|s| s.to_str()); + if ext != Some(OutputType::Object.extension()) { + return false + } + let ext2 = path.file_stem() + .and_then(|s| Path::new(s).extension()) + .and_then(|s| s.to_str()); + ext2 == Some(RUST_CGU_EXT) + } + + let is_rust_object = + canonical.starts_with(&canonical_name) && + looks_like_rust(&f); + + // If we've been requested to skip all native object files + // (those not generated by the rust compiler) then we can skip + // this file. See above for why we may want to do this. + let skip_because_cfg_say_so = skip_native && !is_rust_object; + + // If we're performing LTO and this is a rust-generated object + // file, then we don't need the object file as it's part of the + // LTO module. Note that `#![no_builtins]` is excluded from LTO, + // though, so we let that object file slide. + let skip_because_lto = are_upstream_rust_objects_already_included(sess) && + is_rust_object && + (sess.target.target.options.no_builtins || + !codegen_results.crate_info.is_no_builtins.contains(&cnum)); + + if skip_because_cfg_say_so || skip_because_lto { + archive.remove_file(&f); + } else { + any_objects = true; + } + } + + if !any_objects { + return + } + archive.build(); + + // If we're creating a dylib, then we need to include the + // whole of each object in our archive into that artifact. This is + // because a `dylib` can be reused as an intermediate artifact. + // + // Note, though, that we don't want to include the whole of a + // compiler-builtins crate (e.g., compiler-rt) because it'll get + // repeatedly linked anyway. + if crate_type == config::CrateType::Dylib && + codegen_results.crate_info.compiler_builtins != Some(cnum) { + cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst)); + } else { + cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst)); + } + }); + } + + // Same thing as above, but for dynamic crates instead of static crates. + fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { + // Just need to tell the linker about where the library lives and + // what its name is + let parent = cratepath.parent(); + if let Some(dir) = parent { + cmd.include_path(&fix_windows_verbatim_for_gcc(dir)); + } + let filestem = cratepath.file_stem().unwrap().to_str().unwrap(); + cmd.link_rust_dylib(&unlib(&sess.target, filestem), + parent.unwrap_or(Path::new(""))); + } +} + +// Link in all of our upstream crates' native dependencies. Remember that +// all of these upstream native dependencies are all non-static +// dependencies. We've got two cases then: +// +// 1. The upstream crate is an rlib. In this case we *must* link in the +// native dependency because the rlib is just an archive. +// +// 2. The upstream crate is a dylib. In order to use the dylib, we have to +// have the dependency present on the system somewhere. Thus, we don't +// gain a whole lot from not linking in the dynamic dependency to this +// crate as well. +// +// The use case for this is a little subtle. In theory the native +// dependencies of a crate are purely an implementation detail of the crate +// itself, but the problem arises with generic and inlined functions. If a +// generic function calls a native function, then the generic function must +// be instantiated in the target crate, meaning that the native symbol must +// also be resolved in the target crate. +pub fn add_upstream_native_libraries(cmd: &mut dyn Linker, + sess: &Session, + codegen_results: &CodegenResults, + crate_type: config::CrateType) { + // Be sure to use a topological sorting of crates because there may be + // interdependencies between native libraries. When passing -nodefaultlibs, + // for example, almost all native libraries depend on libc, so we have to + // make sure that's all the way at the right (liblibc is near the base of + // the dependency chain). + // + // This passes RequireStatic, but the actual requirement doesn't matter, + // we're just getting an ordering of crate numbers, we're not worried about + // the paths. + let formats = sess.dependency_formats.borrow(); + let data = formats.get(&crate_type).unwrap(); + + let crates = &codegen_results.crate_info.used_crates_static; + for &(cnum, _) in crates { + for lib in codegen_results.crate_info.native_libraries[&cnum].iter() { + let name = match lib.name { + Some(ref l) => l, + None => continue, + }; + if !relevant_lib(sess, &lib) { + continue + } + match lib.kind { + NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()), + NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()), + NativeLibraryKind::NativeStaticNobundle => { + // Link "static-nobundle" native libs only if the crate they originate from + // is being linked statically to the current crate. If it's linked dynamically + // or is an rlib already included via some other dylib crate, the symbols from + // native libs will have already been included in that dylib. + if data[cnum.as_usize() - 1] == Linkage::Static { + cmd.link_staticlib(&name.as_str()) + } + }, + // ignore statically included native libraries here as we've + // already included them when we included the rust library + // previously + NativeLibraryKind::NativeStatic => {} + } + } + } +} + +pub fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { + match lib.cfg { + Some(ref cfg) => syntax::attr::cfg_matches(cfg, &sess.parse_sess, None), + None => true, + } +} + +pub fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { + match sess.lto() { + config::Lto::Fat => true, + config::Lto::Thin => { + // If we defer LTO to the linker, we haven't run LTO ourselves, so + // any upstream object files have not been copied yet. + !sess.opts.cg.linker_plugin_lto.enabled() + } + config::Lto::No | + config::Lto::ThinLocal => false, + } +} + +fn is_pic(sess: &Session) -> bool { + let reloc_model_arg = match sess.opts.cg.relocation_model { + Some(ref s) => &s[..], + None => &sess.target.target.options.relocation_model[..], + }; + + reloc_model_arg == "pic" +} diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index 1f4c5543fa9aa..32696d46cd577 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -25,7 +25,7 @@ pub struct LinkerInfo { } impl LinkerInfo { - pub fn new(tcx: TyCtxt<'_, '_, '_>) -> LinkerInfo { + pub fn new(tcx: TyCtxt<'_>) -> LinkerInfo { LinkerInfo { exports: tcx.sess.crate_types.borrow().iter().map(|&c| { (c, exported_symbols(tcx, c)) @@ -160,7 +160,16 @@ impl<'a> GccLinker<'a> { } fn takes_hints(&self) -> bool { - !self.sess.target.target.options.is_like_osx + // Really this function only returns true if the underlying linker + // configured for a compiler is binutils `ld.bfd` and `ld.gold`. We + // don't really have a foolproof way to detect that, so rule out some + // platforms where currently this is guaranteed to *not* be the case: + // + // * On OSX they have their own linker, not binutils' + // * For WebAssembly the only functional linker is LLD, which doesn't + // support hint flags + !self.sess.target.target.options.is_like_osx && + self.sess.target.target.arch != "wasm32" } // Some platforms take hints about whether a library is static or dynamic. @@ -363,15 +372,20 @@ impl<'a> Linker for GccLinker<'a> { } fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { - // If we're compiling a dylib, then we let symbol visibility in object - // files to take care of whether they're exported or not. - // - // If we're compiling a cdylib, however, we manually create a list of - // exported symbols to ensure we don't expose any more. The object files - // have far more public symbols than we actually want to export, so we - // hide them all here. - if crate_type == CrateType::Dylib || - crate_type == CrateType::ProcMacro { + // Symbol visibility in object files typically takes care of this. + if crate_type == CrateType::Executable { + return; + } + + // We manually create a list of exported symbols to ensure we don't expose any more. + // The object files have far more public symbols than we actually want to export, + // so we hide them all here. + + if !self.sess.target.target.options.limit_rdylib_exports { + return; + } + + if crate_type == CrateType::ProcMacro { return } @@ -382,20 +396,19 @@ impl<'a> Linker for GccLinker<'a> { if self.sess.target.target.options.is_like_osx { // Write a plain, newline-separated list of symbols - let res = (|| -> io::Result<()> { + let res: io::Result<()> = try { let mut f = BufWriter::new(File::create(&path)?); for sym in self.info.exports[&crate_type].iter() { debug!(" _{}", sym); writeln!(f, "_{}", sym)?; } - Ok(()) - })(); + }; if let Err(e) = res { self.sess.fatal(&format!("failed to write lib.def file: {}", e)); } } else { // Write an LD version script - let res = (|| -> io::Result<()> { + let res: io::Result<()> = try { let mut f = BufWriter::new(File::create(&path)?); writeln!(f, "{{\n global:")?; for sym in self.info.exports[&crate_type].iter() { @@ -403,8 +416,7 @@ impl<'a> Linker for GccLinker<'a> { writeln!(f, " {};", sym)?; } writeln!(f, "\n local:\n *;\n}};")?; - Ok(()) - })(); + }; if let Err(e) = res { self.sess.fatal(&format!("failed to write version script: {}", e)); } @@ -443,13 +455,13 @@ impl<'a> Linker for GccLinker<'a> { } fn group_start(&mut self) { - if !self.sess.target.target.options.is_like_osx { + if self.takes_hints() { self.linker_arg("--start-group"); } } fn group_end(&mut self) { - if !self.sess.target.target.options.is_like_osx { + if self.takes_hints() { self.linker_arg("--end-group"); } } @@ -598,18 +610,6 @@ impl<'a> Linker for MsvcLinker<'a> { // This will cause the Microsoft linker to embed .natvis info into the PDB file let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc"); if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { - // LLVM 5.0.0's lld-link frontend doesn't yet recognize, and chokes - // on, the /NATVIS:... flags. LLVM 6 (or earlier) should at worst ignore - // them, eventually mooting this workaround, per this landed patch: - // https://github.com/llvm-mirror/lld/commit/27b9c4285364d8d76bb43839daa100 - if let Some(ref linker_path) = self.sess.opts.cg.linker { - if let Some(linker_name) = Path::new(&linker_path).file_stem() { - if linker_name.to_str().unwrap().to_lowercase() == "lld-link" { - self.sess.warn("not embedding natvis: lld-link may not support the flag"); - return; - } - } - } for entry in natvis_dir { match entry { Ok(entry) => { @@ -643,8 +643,13 @@ impl<'a> Linker for MsvcLinker<'a> { fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { + // Symbol visibility takes care of this typically + if crate_type == CrateType::Executable { + return; + } + let path = tmpdir.join("lib.def"); - let res = (|| -> io::Result<()> { + let res: io::Result<()> = try { let mut f = BufWriter::new(File::create(&path)?); // Start off with the standard module name header and then go @@ -655,8 +660,7 @@ impl<'a> Linker for MsvcLinker<'a> { debug!(" _{}", symbol); writeln!(f, " {}", symbol)?; } - Ok(()) - })(); + }; if let Err(e) = res { self.sess.fatal(&format!("failed to write lib.def file: {}", e)); } @@ -877,59 +881,7 @@ pub struct WasmLd<'a> { } impl<'a> WasmLd<'a> { - fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> { - // There have been reports in the wild (rustwasm/wasm-bindgen#119) of - // using threads causing weird hangs and bugs. Disable it entirely as - // this isn't yet the bottleneck of compilation at all anyway. - cmd.arg("--no-threads"); - - // By default LLD only gives us one page of stack (64k) which is a - // little small. Default to a larger stack closer to other PC platforms - // (1MB) and users can always inject their own link-args to override this. - cmd.arg("-z").arg("stack-size=1048576"); - - // By default LLD's memory layout is: - // - // 1. First, a blank page - // 2. Next, all static data - // 3. Finally, the main stack (which grows down) - // - // This has the unfortunate consequence that on stack overflows you - // corrupt static data and can cause some exceedingly weird bugs. To - // help detect this a little sooner we instead request that the stack is - // placed before static data. - // - // This means that we'll generate slightly larger binaries as references - // to static data will take more bytes in the ULEB128 encoding, but - // stack overflow will be guaranteed to trap as it underflows instead of - // corrupting static data. - cmd.arg("--stack-first"); - - // FIXME we probably shouldn't pass this but instead pass an explicit - // whitelist of symbols we'll allow to be undefined. Unfortunately - // though we can't handle symbols like `log10` that LLVM injects at a - // super late date without actually parsing object files. For now let's - // stick to this and hopefully fix it before stabilization happens. - cmd.arg("--allow-undefined"); - - // For now we just never have an entry symbol - cmd.arg("--no-entry"); - - // Rust code should never have warnings, and warnings are often - // indicative of bugs, let's prevent them. - cmd.arg("--fatal-warnings"); - - // The symbol visibility story is a bit in flux right now with LLD. - // It's... not entirely clear to me what's going on, but this looks to - // make everything work when `export_symbols` isn't otherwise called for - // things like executables. - cmd.arg("--export-dynamic"); - - // LLD only implements C++-like demangling, which doesn't match our own - // mangling scheme. Tell LLD to not demangle anything and leave it up to - // us to demangle these symbols later. - cmd.arg("--no-demangle"); - + fn new(cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> { WasmLd { cmd, sess, info } } } @@ -1025,6 +977,7 @@ impl<'a> Linker for WasmLd<'a> { } fn build_dylib(&mut self, _out_filename: &Path) { + self.cmd.arg("--no-entry"); } fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) { @@ -1052,7 +1005,7 @@ impl<'a> Linker for WasmLd<'a> { } } -fn exported_symbols(tcx: TyCtxt<'_, '_, '_>, crate_type: CrateType) -> Vec { +fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec { if let Some(ref exports) = tcx.sess.target.target.options.override_export_symbols { return exports.clone() } diff --git a/src/librustc_codegen_ssa/back/lto.rs b/src/librustc_codegen_ssa/back/lto.rs index 7f0eba7b0850b..47e5d9af33ba4 100644 --- a/src/librustc_codegen_ssa/back/lto.rs +++ b/src/librustc_codegen_ssa/back/lto.rs @@ -2,7 +2,6 @@ use super::write::CodegenContext; use crate::traits::*; use crate::ModuleCodegen; -use rustc::util::time_graph::Timeline; use rustc_errors::FatalError; use std::sync::Arc; @@ -67,7 +66,6 @@ impl LtoModuleCodegen { pub unsafe fn optimize( &mut self, cgcx: &CodegenContext, - timeline: &mut Timeline ) -> Result, FatalError> { match *self { LtoModuleCodegen::Fat { ref mut module, .. } => { @@ -75,11 +73,10 @@ impl LtoModuleCodegen { { let config = cgcx.config(module.kind); B::run_lto_pass_manager(cgcx, &module, config, false); - timeline.record("fat-done"); } Ok(module) } - LtoModuleCodegen::Thin(ref mut thin) => B::optimize_thin(cgcx, thin, timeline), + LtoModuleCodegen::Thin(ref mut thin) => B::optimize_thin(cgcx, thin), } } diff --git a/src/librustc_codegen_ssa/back/mod.rs b/src/librustc_codegen_ssa/back/mod.rs index 888108408fbe3..a16d099ee3e4d 100644 --- a/src/librustc_codegen_ssa/back/mod.rs +++ b/src/librustc_codegen_ssa/back/mod.rs @@ -5,3 +5,5 @@ pub mod link; pub mod command; pub mod symbol_export; pub mod archive; +pub mod rpath; +pub mod wasm; diff --git a/src/librustc_codegen_ssa/back/rpath.rs b/src/librustc_codegen_ssa/back/rpath.rs new file mode 100644 index 0000000000000..e27cb6d8dda89 --- /dev/null +++ b/src/librustc_codegen_ssa/back/rpath.rs @@ -0,0 +1,176 @@ +use rustc_data_structures::fx::FxHashSet; +use std::env; +use std::path::{Path, PathBuf}; +use std::fs; + +use rustc::hir::def_id::CrateNum; +use rustc::middle::cstore::LibSource; + +pub struct RPathConfig<'a> { + pub used_crates: &'a [(CrateNum, LibSource)], + pub out_filename: PathBuf, + pub is_like_osx: bool, + pub has_rpath: bool, + pub linker_is_gnu: bool, + pub get_install_prefix_lib_path: &'a mut dyn FnMut() -> PathBuf, +} + +pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec { + // No rpath on windows + if !config.has_rpath { + return Vec::new(); + } + + debug!("preparing the RPATH!"); + + let libs = config.used_crates.clone(); + let libs = libs.iter().filter_map(|&(_, ref l)| l.option()).collect::>(); + let rpaths = get_rpaths(config, &libs); + let mut flags = rpaths_to_flags(&rpaths); + + // Use DT_RUNPATH instead of DT_RPATH if available + if config.linker_is_gnu { + flags.push("-Wl,--enable-new-dtags".to_owned()); + } + + flags +} + +fn rpaths_to_flags(rpaths: &[String]) -> Vec { + let mut ret = Vec::with_capacity(rpaths.len()); // the minimum needed capacity + + for rpath in rpaths { + if rpath.contains(',') { + ret.push("-Wl,-rpath".into()); + ret.push("-Xlinker".into()); + ret.push(rpath.clone()); + } else { + ret.push(format!("-Wl,-rpath,{}", &(*rpath))); + } + } + + ret +} + +fn get_rpaths(config: &mut RPathConfig<'_>, libs: &[PathBuf]) -> Vec { + debug!("output: {:?}", config.out_filename.display()); + debug!("libs:"); + for libpath in libs { + debug!(" {:?}", libpath.display()); + } + + // Use relative paths to the libraries. Binaries can be moved + // as long as they maintain the relative relationship to the + // crates they depend on. + let rel_rpaths = get_rpaths_relative_to_output(config, libs); + + // And a final backup rpath to the global library location. + let fallback_rpaths = vec![get_install_prefix_rpath(config)]; + + fn log_rpaths(desc: &str, rpaths: &[String]) { + debug!("{} rpaths:", desc); + for rpath in rpaths { + debug!(" {}", *rpath); + } + } + + log_rpaths("relative", &rel_rpaths); + log_rpaths("fallback", &fallback_rpaths); + + let mut rpaths = rel_rpaths; + rpaths.extend_from_slice(&fallback_rpaths); + + // Remove duplicates + let rpaths = minimize_rpaths(&rpaths); + + rpaths +} + +fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>, + libs: &[PathBuf]) -> Vec { + libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect() +} + +fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> String { + // Mac doesn't appear to support $ORIGIN + let prefix = if config.is_like_osx { + "@loader_path" + } else { + "$ORIGIN" + }; + + let cwd = env::current_dir().unwrap(); + let mut lib = fs::canonicalize(&cwd.join(lib)).unwrap_or_else(|_| cwd.join(lib)); + lib.pop(); // strip filename + let mut output = cwd.join(&config.out_filename); + output.pop(); // strip filename + let output = fs::canonicalize(&output).unwrap_or(output); + let relative = path_relative_from(&lib, &output).unwrap_or_else(|| + panic!("couldn't create relative path from {:?} to {:?}", output, lib)); + // FIXME (#9639): This needs to handle non-utf8 paths + format!("{}/{}", prefix, relative.to_str().expect("non-utf8 component in path")) +} + +// This routine is adapted from the *old* Path's `path_relative_from` +// function, which works differently from the new `relative_from` function. +// In particular, this handles the case on unix where both paths are +// absolute but with only the root as the common directory. +fn path_relative_from(path: &Path, base: &Path) -> Option { + use std::path::Component; + + if path.is_absolute() != base.is_absolute() { + if path.is_absolute() { + Some(PathBuf::from(path)) + } else { + None + } + } else { + let mut ita = path.components(); + let mut itb = base.components(); + let mut comps: Vec> = vec![]; + loop { + match (ita.next(), itb.next()) { + (None, None) => break, + (Some(a), None) => { + comps.push(a); + comps.extend(ita.by_ref()); + break; + } + (None, _) => comps.push(Component::ParentDir), + (Some(a), Some(b)) if comps.is_empty() && a == b => (), + (Some(a), Some(b)) if b == Component::CurDir => comps.push(a), + (Some(_), Some(b)) if b == Component::ParentDir => return None, + (Some(a), Some(_)) => { + comps.push(Component::ParentDir); + comps.extend(itb.map(|_| Component::ParentDir)); + comps.push(a); + comps.extend(ita.by_ref()); + break; + } + } + } + Some(comps.iter().map(|c| c.as_os_str()).collect()) + } +} + + +fn get_install_prefix_rpath(config: &mut RPathConfig<'_>) -> String { + let path = (config.get_install_prefix_lib_path)(); + let path = env::current_dir().unwrap().join(&path); + // FIXME (#9639): This needs to handle non-utf8 paths + path.to_str().expect("non-utf8 component in rpath").to_owned() +} + +fn minimize_rpaths(rpaths: &[String]) -> Vec { + let mut set = FxHashSet::default(); + let mut minimized = Vec::new(); + for rpath in rpaths { + if set.insert(rpath) { + minimized.push(rpath.clone()); + } + } + minimized +} + +#[cfg(all(unix, test))] +mod tests; diff --git a/src/librustc_codegen_ssa/back/rpath/tests.rs b/src/librustc_codegen_ssa/back/rpath/tests.rs new file mode 100644 index 0000000000000..e42a878d7e45e --- /dev/null +++ b/src/librustc_codegen_ssa/back/rpath/tests.rs @@ -0,0 +1,93 @@ +use super::{RPathConfig}; +use super::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output}; +use std::path::{Path, PathBuf}; + +#[test] +fn test_rpaths_to_flags() { + let flags = rpaths_to_flags(&[ + "path1".to_string(), + "path2".to_string() + ]); + assert_eq!(flags, + ["-Wl,-rpath,path1", + "-Wl,-rpath,path2"]); +} + +#[test] +fn test_minimize1() { + let res = minimize_rpaths(&[ + "rpath1".to_string(), + "rpath2".to_string(), + "rpath1".to_string() + ]); + assert!(res == [ + "rpath1", + "rpath2", + ]); +} + +#[test] +fn test_minimize2() { + let res = minimize_rpaths(&[ + "1a".to_string(), + "2".to_string(), + "2".to_string(), + "1a".to_string(), + "4a".to_string(), + "1a".to_string(), + "2".to_string(), + "3".to_string(), + "4a".to_string(), + "3".to_string() + ]); + assert!(res == [ + "1a", + "2", + "4a", + "3", + ]); +} + +#[test] +fn test_rpath_relative() { + if cfg!(target_os = "macos") { + let config = &mut RPathConfig { + used_crates: Vec::new(), + has_rpath: true, + is_like_osx: true, + linker_is_gnu: false, + out_filename: PathBuf::from("bin/rustc"), + get_install_prefix_lib_path: &mut || panic!(), + }; + let res = get_rpath_relative_to_output(config, + Path::new("lib/libstd.so")); + assert_eq!(res, "@loader_path/../lib"); + } else { + let config = &mut RPathConfig { + used_crates: Vec::new(), + out_filename: PathBuf::from("bin/rustc"), + get_install_prefix_lib_path: &mut || panic!(), + has_rpath: true, + is_like_osx: false, + linker_is_gnu: true, + }; + let res = get_rpath_relative_to_output(config, + Path::new("lib/libstd.so")); + assert_eq!(res, "$ORIGIN/../lib"); + } +} + +#[test] +fn test_xlinker() { + let args = rpaths_to_flags(&[ + "a/normal/path".to_string(), + "a,comma,path".to_string() + ]); + + assert_eq!(args, vec![ + "-Wl,-rpath,a/normal/path".to_string(), + "-Wl,-rpath".to_string(), + "-Xlinker".to_string(), + "a,comma,path".to_string() + ]); +} diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index 4b01e264f19ed..3e0f030527f43 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -1,4 +1,3 @@ -use rustc_data_structures::sync::Lrc; use std::sync::Arc; use rustc::ty::Instance; @@ -22,7 +21,7 @@ pub type ExportedSymbols = FxHashMap< Arc>, >; -pub fn threshold(tcx: TyCtxt<'_, '_, '_>) -> SymbolExportLevel { +pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { crates_export_threshold(&tcx.sess.crate_types.borrow()) } @@ -47,14 +46,14 @@ pub fn crates_export_threshold(crate_types: &[config::CrateType]) -> SymbolExpor } } -fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - cnum: CrateNum) - -> Lrc> -{ +fn reachable_non_generics_provider<'tcx>( + tcx: TyCtxt<'tcx>, + cnum: CrateNum, +) -> &'tcx DefIdMap { assert_eq!(cnum, LOCAL_CRATE); if !tcx.sess.opts.output_types.should_codegen() { - return Default::default(); + return tcx.arena.alloc(Default::default()); } // Check to see if this crate is a "special runtime crate". These @@ -69,7 +68,7 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut reachable_non_generics: DefIdMap<_> = tcx.reachable_set(LOCAL_CRATE).0 .iter() - .filter_map(|&node_id| { + .filter_map(|&hir_id| { // We want to ignore some FFI functions that are not exposed from // this crate. Reachable FFI functions can be lumped into two // categories: @@ -83,9 +82,9 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // // As a result, if this id is an FFI item (foreign item) then we only // let it through if it's included statically. - match tcx.hir().get(node_id) { + match tcx.hir().get(hir_id) { Node::ForeignItem(..) => { - let def_id = tcx.hir().local_def_id(node_id); + let def_id = tcx.hir().local_def_id_from_hir_id(hir_id); if tcx.is_statically_included_foreign_item(def_id) { Some(def_id) } else { @@ -105,7 +104,7 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node: hir::ImplItemKind::Method(..), .. }) => { - let def_id = tcx.hir().local_def_id(node_id); + let def_id = tcx.hir().local_def_id_from_hir_id(hir_id); let generics = tcx.generics_of(def_id); if !generics.requires_monomorphization(tcx) && // Functions marked with #[inline] are only ever codegened @@ -155,12 +154,10 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reachable_non_generics.insert(id, SymbolExportLevel::C); } - Lrc::new(reachable_non_generics) + tcx.arena.alloc(reachable_non_generics) } -fn is_reachable_non_generic_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> bool { +fn is_reachable_non_generic_provider_local<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { let export_threshold = threshold(tcx); if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) { @@ -170,17 +167,14 @@ fn is_reachable_non_generic_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx> } } -fn is_reachable_non_generic_provider_extern<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> bool { +fn is_reachable_non_generic_provider_extern<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { tcx.reachable_non_generics(def_id.krate).contains_key(&def_id) } -fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - cnum: CrateNum) - -> Arc, - SymbolExportLevel)>> -{ +fn exported_symbols_provider_local<'tcx>( + tcx: TyCtxt<'tcx>, + cnum: CrateNum, +) -> Arc, SymbolExportLevel)>> { assert_eq!(cnum, LOCAL_CRATE); if !tcx.sess.opts.output_types.should_codegen() { @@ -209,7 +203,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - if tcx.sess.opts.debugging_opts.pgo_gen.is_some() { + if tcx.sess.opts.cg.profile_generate.enabled() { // These are weak symbols that point to the profile version and the // profile name, which need to be treated as exported so LTO doesn't nix // them. @@ -263,7 +257,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def: InstanceDef::Item(def_id), substs, }) = mono_item { - if substs.types().next().is_some() { + if substs.non_erasable_generics().next().is_some() { symbols.push((ExportedSymbol::Generic(def_id, substs), SymbolExportLevel::Rust)); } @@ -279,11 +273,10 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Arc::new(symbols) } -fn upstream_monomorphizations_provider<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cnum: CrateNum) - -> Lrc, CrateNum>>>> -{ +fn upstream_monomorphizations_provider<'tcx>( + tcx: TyCtxt<'tcx>, + cnum: CrateNum, +) -> &'tcx DefIdMap, CrateNum>> { debug_assert!(cnum == LOCAL_CRATE); let cnums = tcx.all_crate_nums(LOCAL_CRATE); @@ -326,25 +319,20 @@ fn upstream_monomorphizations_provider<'a, 'tcx>( } } - Lrc::new(instances.into_iter() - .map(|(key, value)| (key, Lrc::new(value))) - .collect()) + tcx.arena.alloc(instances) } -fn upstream_monomorphizations_for_provider<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> Option, CrateNum>>> -{ +fn upstream_monomorphizations_for_provider<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> Option<&'tcx FxHashMap, CrateNum>> { debug_assert!(!def_id.is_local()); - tcx.upstream_monomorphizations(LOCAL_CRATE) - .get(&def_id) - .cloned() + tcx.upstream_monomorphizations(LOCAL_CRATE).get(&def_id) } -fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> bool { - if let Some(node_id) = tcx.hir().as_local_node_id(def_id) { - !tcx.reachable_set(LOCAL_CRATE).0.contains(&node_id) +fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { + !tcx.reachable_set(LOCAL_CRATE).0.contains(&hir_id) } else { bug!("is_unreachable_local_definition called with non-local DefId: {:?}", def_id) @@ -364,7 +352,7 @@ pub fn provide_extern(providers: &mut Providers<'_>) { providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider; } -fn symbol_export_level(tcx: TyCtxt<'_, '_, '_>, sym_def_id: DefId) -> SymbolExportLevel { +fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel { // We export anything that's not mangled at the "C" layer as it probably has // to do with ABI concerns. We do not, however, apply such treatment to // special symbols in the standard library for various plumbing between diff --git a/src/librustc_codegen_llvm/back/wasm.rs b/src/librustc_codegen_ssa/back/wasm.rs similarity index 100% rename from src/librustc_codegen_llvm/back/wasm.rs rename to src/librustc_codegen_ssa/back/wasm.rs diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 908ee95efcba3..6364843d77267 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -12,13 +12,14 @@ use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir, use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind}; use rustc::dep_graph::cgu_reuse_tracker::CguReuseTracker; use rustc::middle::cstore::EncodedMetadata; -use rustc::session::config::{self, OutputFilenames, OutputType, Passes, Sanitizer, Lto}; +use rustc::session::config::{self, OutputFilenames, OutputType, Passes, Lto, + Sanitizer, SwitchWithOptPath}; use rustc::session::Session; use rustc::util::nodemap::FxHashMap; -use rustc::util::time_graph::{self, TimeGraph, Timeline}; use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::ty::TyCtxt; use rustc::util::common::{time_depth, set_time_depth, print_time_passes_entry}; +use rustc::util::profiling::SelfProfiler; use rustc_fs_util::link_or_copy; use rustc_data_structures::svh::Svh; use rustc_errors::{Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId}; @@ -27,10 +28,11 @@ use rustc_target::spec::MergeFunctions; use syntax::attr; use syntax::ext::hygiene::Mark; use syntax_pos::MultiSpan; -use syntax_pos::symbol::Symbol; +use syntax_pos::symbol::{Symbol, sym}; use jobserver::{Client, Acquired}; use std::any::Any; +use std::borrow::Cow; use std::fs; use std::io; use std::mem; @@ -54,8 +56,8 @@ pub struct ModuleConfig { /// Some(level) to optimize binary size, or None to not affect program size. pub opt_size: Option, - pub pgo_gen: Option, - pub pgo_use: String, + pub pgo_gen: SwitchWithOptPath, + pub pgo_use: Option, // Flags indicating which outputs to produce. pub emit_pre_lto_bc: bool, @@ -92,8 +94,8 @@ impl ModuleConfig { opt_level: None, opt_size: None, - pgo_gen: None, - pgo_use: String::new(), + pgo_gen: SwitchWithOptPath::Disabled, + pgo_use: None, emit_no_opt_bc: false, emit_pre_lto_bc: false, @@ -123,7 +125,7 @@ impl ModuleConfig { self.verify_llvm_ir = sess.verify_llvm_ir(); self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes; self.no_builtins = no_builtins || sess.target.target.options.no_builtins; - self.time_passes = sess.time_passes(); + self.time_passes = sess.time_extended(); self.inline_threshold = sess.opts.cg.inline_threshold; self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled(); @@ -195,12 +197,42 @@ impl Clone for TargetMachineFactory { } } +pub struct ProfileGenericActivityTimer { + profiler: Option>, + label: Cow<'static, str>, +} + +impl ProfileGenericActivityTimer { + pub fn start( + profiler: Option>, + label: Cow<'static, str>, + ) -> ProfileGenericActivityTimer { + if let Some(profiler) = &profiler { + profiler.start_activity(label.clone()); + } + + ProfileGenericActivityTimer { + profiler, + label, + } + } +} + +impl Drop for ProfileGenericActivityTimer { + fn drop(&mut self) { + if let Some(profiler) = &self.profiler { + profiler.end_activity(self.label.clone()); + } + } +} + /// Additional resources used by optimize_and_codegen (not module specific) #[derive(Clone)] pub struct CodegenContext { // Resources needed when running LTO pub backend: B, pub time_passes: bool, + pub profiler: Option>, pub lto: Lto, pub no_landing_pads: bool, pub save_temps: bool, @@ -216,6 +248,7 @@ pub struct CodegenContext { pub tm_factory: TargetMachineFactory, pub msvc_imps_needed: bool, pub target_pointer_width: String, + pub target_arch: String, pub debuginfo: config::DebugInfo, // Number of cgus excluding the allocator/metadata modules @@ -235,16 +268,13 @@ pub struct CodegenContext { pub cgu_reuse_tracker: CguReuseTracker, // Channel back to the main control thread to send messages to pub coordinator_send: Sender>, - // A reference to the TimeGraph so we can register timings. None means that - // measuring is disabled. - pub time_graph: Option, // The assembler command if no_integrated_as option is enabled, None otherwise pub assembler_cmd: Option> } impl CodegenContext { pub fn create_diag_handler(&self) -> Handler { - Handler::with_emitter(true, false, Box::new(self.diag_emitter.clone())) + Handler::with_emitter(true, None, Box::new(self.diag_emitter.clone())) } pub fn config(&self, kind: ModuleKind) -> &ModuleConfig { @@ -254,6 +284,31 @@ impl CodegenContext { ModuleKind::Allocator => &self.allocator_module_config, } } + + #[inline(never)] + #[cold] + fn profiler_active ()>(&self, f: F) { + match &self.profiler { + None => bug!("profiler_active() called but there was no profiler active"), + Some(profiler) => { + f(&*profiler); + } + } + } + + #[inline(always)] + pub fn profile ()>(&self, f: F) { + if unlikely!(self.profiler.is_some()) { + self.profiler_active(f) + } + } + + pub fn profile_activity( + &self, + label: impl Into>, + ) -> ProfileGenericActivityTimer { + ProfileGenericActivityTimer::start(self.profiler.clone(), label.into()) + } } fn generate_lto_work( @@ -262,11 +317,7 @@ fn generate_lto_work( needs_thin_lto: Vec<(String, B::ThinBuffer)>, import_only_modules: Vec<(SerializedModule, WorkProduct)> ) -> Vec<(WorkItem, u64)> { - let mut timeline = cgcx.time_graph.as_ref().map(|tg| { - tg.start(CODEGEN_WORKER_TIMELINE, - CODEGEN_WORK_PACKAGE_KIND, - "generate lto") - }).unwrap_or(Timeline::noop()); + cgcx.profile(|p| p.start_activity("codegen_run_lto")); let (lto_modules, copy_jobs) = if !needs_fat_lto.is_empty() { assert!(needs_thin_lto.is_empty()); @@ -274,17 +325,16 @@ fn generate_lto_work( cgcx, needs_fat_lto, import_only_modules, - &mut timeline, ) .unwrap_or_else(|e| e.raise()); (vec![lto_module], vec![]) } else { assert!(needs_fat_lto.is_empty()); - B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules, &mut timeline) + B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules) .unwrap_or_else(|e| e.raise()) }; - lto_modules.into_iter().map(|module| { + let result = lto_modules.into_iter().map(|module| { let cost = module.cost(); (WorkItem::LTO(module), cost) }).chain(copy_jobs.into_iter().map(|wp| { @@ -292,12 +342,16 @@ fn generate_lto_work( name: wp.cgu_name.clone(), source: wp, }), 0) - })).collect() + })).collect(); + + cgcx.profile(|p| p.end_activity("codegen_run_lto")); + + result } pub struct CompiledModules { pub modules: Vec, - pub metadata_module: CompiledModule, + pub metadata_module: Option, pub allocator_module: Option, } @@ -321,20 +375,19 @@ fn need_pre_lto_bitcode_for_incr_comp(sess: &Session) -> bool { pub fn start_async_codegen( backend: B, - tcx: TyCtxt<'_, '_, '_>, - time_graph: Option, + tcx: TyCtxt<'_>, metadata: EncodedMetadata, coordinator_receive: Receiver>, - total_cgus: usize + total_cgus: usize, ) -> OngoingCodegen { let sess = tcx.sess; let crate_name = tcx.crate_name(LOCAL_CRATE); let crate_hash = tcx.crate_hash(LOCAL_CRATE); - let no_builtins = attr::contains_name(&tcx.hir().krate().attrs, "no_builtins"); + let no_builtins = attr::contains_name(&tcx.hir().krate().attrs, sym::no_builtins); let subsystem = attr::first_attr_value_str_by_name(&tcx.hir().krate().attrs, - "windows_subsystem"); + sym::windows_subsystem); let windows_subsystem = subsystem.map(|subsystem| { - if subsystem != "windows" && subsystem != "console" { + if subsystem != sym::windows && subsystem != sym::console { tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \ `windows` and `console` are allowed", subsystem)); @@ -370,8 +423,8 @@ pub fn start_async_codegen( modules_config.passes.push("insert-gcov-profiling".to_owned()) } - modules_config.pgo_gen = sess.opts.debugging_opts.pgo_gen.clone(); - modules_config.pgo_use = sess.opts.debugging_opts.pgo_use.clone(); + modules_config.pgo_gen = sess.opts.cg.profile_generate.clone(); + modules_config.pgo_use = sess.opts.cg.profile_use.clone(); modules_config.opt_level = Some(sess.opts.optimize); modules_config.opt_size = Some(sess.opts.optimize); @@ -446,7 +499,6 @@ pub fn start_async_codegen( coordinator_receive, total_cgus, sess.jobserver.clone(), - time_graph.clone(), Arc::new(modules_config), Arc::new(metadata_config), Arc::new(allocator_config)); @@ -460,7 +512,6 @@ pub fn start_async_codegen( linker_info, crate_info, - time_graph, coordinator_send: tcx.tx_to_llvm_workers.lock().clone(), codegen_worker_receive, shared_emitter_main, @@ -632,8 +683,10 @@ fn produce_final_output_artifacts(sess: &Session, } if !user_wants_bitcode { - if let Some(ref path) = compiled_modules.metadata_module.bytecode { - remove(sess, &path); + if let Some(ref metadata_module) = compiled_modules.metadata_module { + if let Some(ref path) = metadata_module.bytecode { + remove(sess, &path); + } } if let Some(ref allocator_module) = compiled_modules.allocator_module { @@ -705,19 +758,18 @@ pub enum FatLTOInput { fn execute_work_item( cgcx: &CodegenContext, work_item: WorkItem, - timeline: &mut Timeline ) -> Result, FatalError> { let module_config = cgcx.config(work_item.module_kind()); match work_item { WorkItem::Optimize(module) => { - execute_optimize_work_item(cgcx, module, module_config, timeline) + execute_optimize_work_item(cgcx, module, module_config) } WorkItem::CopyPostLtoArtifacts(module) => { - execute_copy_from_cache_work_item(cgcx, module, module_config, timeline) + execute_copy_from_cache_work_item(cgcx, module, module_config) } WorkItem::LTO(module) => { - execute_lto_work_item(cgcx, module, module_config, timeline) + execute_lto_work_item(cgcx, module, module_config) } } } @@ -733,12 +785,11 @@ fn execute_optimize_work_item( cgcx: &CodegenContext, module: ModuleCodegen, module_config: &ModuleConfig, - timeline: &mut Timeline ) -> Result, FatalError> { let diag_handler = cgcx.create_diag_handler(); unsafe { - B::optimize(cgcx, &diag_handler, &module, module_config, timeline)?; + B::optimize(cgcx, &diag_handler, &module, module_config)?; } // After we've done the initial round of optimizations we need to @@ -795,7 +846,7 @@ fn execute_optimize_work_item( Ok(match lto_type { ComputedLtoType::No => { let module = unsafe { - B::codegen(cgcx, &diag_handler, module, module_config, timeline)? + B::codegen(cgcx, &diag_handler, module, module_config)? }; WorkItemResult::Compiled(module) } @@ -831,7 +882,6 @@ fn execute_copy_from_cache_work_item( cgcx: &CodegenContext, module: CachedModuleCodegen, module_config: &ModuleConfig, - _: &mut Timeline ) -> Result, FatalError> { let incr_comp_session_dir = cgcx.incr_comp_session_dir .as_ref() @@ -893,13 +943,12 @@ fn execute_lto_work_item( cgcx: &CodegenContext, mut module: lto::LtoModuleCodegen, module_config: &ModuleConfig, - timeline: &mut Timeline ) -> Result, FatalError> { let diag_handler = cgcx.create_diag_handler(); unsafe { - let module = module.optimize(cgcx, timeline)?; - let module = B::codegen(cgcx, &diag_handler, module, module_config, timeline)?; + let module = module.optimize(cgcx)?; + let module = B::codegen(cgcx, &diag_handler, module, module_config)?; Ok(WorkItemResult::Compiled(module)) } } @@ -947,17 +996,16 @@ enum MainThreadWorkerState { fn start_executing_work( backend: B, - tcx: TyCtxt<'_, '_, '_>, + tcx: TyCtxt<'_>, crate_info: &CrateInfo, shared_emitter: SharedEmitter, codegen_worker_send: Sender>, coordinator_receive: Receiver>, total_cgus: usize, jobserver: Client, - time_graph: Option, modules_config: Arc, metadata_config: Arc, - allocator_config: Arc + allocator_config: Arc, ) -> thread::JoinHandle> { let coordinator_send = tcx.tx_to_llvm_workers.lock().clone(); let sess = tcx.sess; @@ -1022,7 +1070,13 @@ fn start_executing_work( None }; - let ol = tcx.backend_optimization_level(LOCAL_CRATE); + let ol = if tcx.sess.opts.debugging_opts.no_codegen + || !tcx.sess.opts.output_types.should_codegen() { + // If we know that we won’t be doing codegen, create target machines without optimisation. + config::OptLevel::No + } else { + tcx.backend_optimization_level(LOCAL_CRATE) + }; let cgcx = CodegenContext:: { backend: backend.clone(), crate_types: sess.crate_types.borrow().clone(), @@ -1032,7 +1086,8 @@ fn start_executing_work( fewer_names: sess.fewer_names(), save_temps: sess.opts.cg.save_temps, opts: Arc::new(sess.opts.clone()), - time_passes: sess.time_passes(), + time_passes: sess.time_extended(), + profiler: sess.self_profiling.clone(), exported_symbols, plugin_passes: sess.plugin_llvm_passes.borrow().clone(), remark: sess.opts.cg.remark.clone(), @@ -1041,7 +1096,6 @@ fn start_executing_work( cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(), coordinator_send, diag_emitter: shared_emitter.clone(), - time_graph, output_filenames: tcx.output_filenames(LOCAL_CRATE), regular_module_config: modules_config, metadata_module_config: metadata_config, @@ -1050,6 +1104,7 @@ fn start_executing_work( total_cgus, msvc_imps_needed: msvc_imps_needed(tcx), target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(), + target_arch: tcx.sess.target.target.arch.clone(), debuginfo: tcx.sess.opts.debuginfo, assembler_cmd, }; @@ -1513,9 +1568,6 @@ fn start_executing_work( // out deterministic results. compiled_modules.sort_by(|a, b| a.name.cmp(&b.name)); - let compiled_metadata_module = compiled_metadata_module - .expect("Metadata module not compiled?"); - Ok(CompiledModules { modules: compiled_modules, metadata_module: compiled_metadata_module, @@ -1546,12 +1598,6 @@ fn start_executing_work( } pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX; -pub const CODEGEN_WORKER_TIMELINE: time_graph::TimelineId = - time_graph::TimelineId(CODEGEN_WORKER_ID); -pub const CODEGEN_WORK_PACKAGE_KIND: time_graph::WorkPackageKind = - time_graph::WorkPackageKind(&["#DE9597", "#FED1D3", "#FDC5C7", "#B46668", "#88494B"]); -const LLVM_WORK_PACKAGE_KIND: time_graph::WorkPackageKind = - time_graph::WorkPackageKind(&["#7DB67A", "#C6EEC4", "#ACDAAA", "#579354", "#3E6F3C"]); fn spawn_work( cgcx: CodegenContext, @@ -1601,13 +1647,12 @@ fn spawn_work( // as a diagnostic was already sent off to the main thread - just // surface that there was an error in this worker. bomb.result = { - let timeline = cgcx.time_graph.as_ref().map(|tg| { - tg.start(time_graph::TimelineId(cgcx.worker), - LLVM_WORK_PACKAGE_KIND, - &work.name()) - }); - let mut timeline = timeline.unwrap_or(Timeline::noop()); - execute_work_item(&cgcx, work, &mut timeline).ok() + let label = work.name(); + cgcx.profile(|p| p.start_activity(label.clone())); + let result = execute_work_item(&cgcx, work).ok(); + cgcx.profile(|p| p.end_activity(label)); + + result }; }); } @@ -1683,7 +1728,7 @@ impl SharedEmitter { } impl Emitter for SharedEmitter { - fn emit(&mut self, db: &DiagnosticBuilder<'_>) { + fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { msg: db.message(), code: db.code.clone(), @@ -1761,7 +1806,6 @@ pub struct OngoingCodegen { pub windows_subsystem: Option, pub linker_info: LinkerInfo, pub crate_info: CrateInfo, - pub time_graph: Option, pub coordinator_send: Sender>, pub codegen_worker_receive: Receiver>, pub shared_emitter_main: SharedEmitterMain, @@ -1790,10 +1834,6 @@ impl OngoingCodegen { sess.abort_if_errors(); - if let Some(time_graph) = self.time_graph { - time_graph.dump(&format!("{}-timings", self.crate_name)); - } - let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess, &compiled_modules); @@ -1821,18 +1861,20 @@ impl OngoingCodegen { }, work_products) } - pub fn submit_pre_codegened_module_to_llvm(&self, - tcx: TyCtxt<'_, '_, '_>, - module: ModuleCodegen) { + pub fn submit_pre_codegened_module_to_llvm( + &self, + tcx: TyCtxt<'_>, + module: ModuleCodegen, + ) { self.wait_for_signal_to_codegen_item(); self.check_for_errors(tcx.sess); - // These are generally cheap and won't through off scheduling. + // These are generally cheap and won't throw off scheduling. let cost = 0; submit_codegened_module_to_llvm(&self.backend, tcx, module, cost); } - pub fn codegen_finished(&self, tcx: TyCtxt<'_, '_, '_>) { + pub fn codegen_finished(&self, tcx: TyCtxt<'_>) { self.wait_for_signal_to_codegen_item(); self.check_for_errors(tcx.sess); drop(self.coordinator_send.send(Box::new(Message::CodegenComplete::))); @@ -1871,9 +1913,9 @@ impl OngoingCodegen { pub fn submit_codegened_module_to_llvm( _backend: &B, - tcx: TyCtxt<'_, '_, '_>, + tcx: TyCtxt<'_>, module: ModuleCodegen, - cost: u64 + cost: u64, ) { let llvm_work_item = WorkItem::Optimize(module); drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::CodegenDone:: { @@ -1884,8 +1926,8 @@ pub fn submit_codegened_module_to_llvm( pub fn submit_post_lto_module_to_llvm( _backend: &B, - tcx: TyCtxt<'_, '_, '_>, - module: CachedModuleCodegen + tcx: TyCtxt<'_>, + module: CachedModuleCodegen, ) { let llvm_work_item = WorkItem::CopyPostLtoArtifacts(module); drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::CodegenDone:: { @@ -1896,8 +1938,8 @@ pub fn submit_post_lto_module_to_llvm( pub fn submit_pre_lto_module_to_llvm( _backend: &B, - tcx: TyCtxt<'_, '_, '_>, - module: CachedModuleCodegen + tcx: TyCtxt<'_>, + module: CachedModuleCodegen, ) { let filename = pre_lto_bitcode_filename(&module.name); let bc_path = in_incr_comp_dir_sess(tcx.sess, &filename); @@ -1921,7 +1963,7 @@ pub fn pre_lto_bitcode_filename(module_name: &str) -> String { format!("{}.{}", module_name, PRE_LTO_BC_EXT) } -fn msvc_imps_needed(tcx: TyCtxt<'_, '_, '_>) -> bool { +fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool { // This should never be true (because it's not supported). If it is true, // something is wrong with commandline arg validation. assert!(!(tcx.sess.opts.cg.linker_plugin_lto.enabled() && diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 39ce15e477296..47b383fddbc31 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -17,24 +17,19 @@ use crate::{ModuleCodegen, ModuleKind, CachedModuleCodegen}; use rustc::dep_graph::cgu_reuse_tracker::CguReuse; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::middle::cstore::EncodedMetadata; use rustc::middle::lang_items::StartFnLangItem; use rustc::middle::weak_lang_items; -use rustc::mir::mono::{Stats, CodegenUnitNameBuilder}; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::mir::mono::{CodegenUnitNameBuilder, CodegenUnit, MonoItem}; +use rustc::ty::{self, Ty, TyCtxt, Instance}; use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt}; use rustc::ty::query::Providers; use rustc::middle::cstore::{self, LinkagePreference}; use rustc::util::common::{time, print_time_passes_entry}; -use rustc::util::profiling::ProfileCategory; use rustc::session::config::{self, EntryFnType, Lto}; use rustc::session::Session; -use rustc_mir::monomorphize::item::DefPathBasedNames; -use rustc::util::time_graph; -use rustc_mir::monomorphize::Instance; -use rustc_mir::monomorphize::partitioning::{CodegenUnit, CodegenUnitExt}; use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_vec::Idx; -use rustc_data_structures::sync::Lrc; use rustc_codegen_utils::{symbol_names_test, check_for_rustc_errors_attr}; use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; use crate::mir::place::PlaceRef; @@ -45,7 +40,6 @@ use crate::callee; use crate::common::{RealPredicate, TypeKind, IntPredicate}; use crate::meth; use crate::mir; -use crate::mono_item::MonoItem; use crate::traits::*; @@ -60,40 +54,6 @@ use rustc::hir; use crate::mir::operand::OperandValue; -use std::marker::PhantomData; - -pub struct StatRecorder<'a, 'tcx, Cx: 'a + CodegenMethods<'tcx>> { - cx: &'a Cx, - name: Option, - istart: usize, - _marker: PhantomData<&'tcx ()>, -} - -impl<'a, 'tcx, Cx: CodegenMethods<'tcx>> StatRecorder<'a, 'tcx, Cx> { - pub fn new(cx: &'a Cx, name: String) -> Self { - let istart = cx.stats().borrow().n_llvm_insns; - StatRecorder { - cx, - name: Some(name), - istart, - _marker: PhantomData, - } - } -} - -impl<'a, 'tcx, Cx: CodegenMethods<'tcx>> Drop for StatRecorder<'a, 'tcx, Cx> { - fn drop(&mut self) { - if self.cx.sess().codegen_stats() { - let mut stats = self.cx.stats().borrow_mut(); - let iend = stats.n_llvm_insns; - stats.fn_stats.push((self.name.take().unwrap(), iend - self.istart)); - stats.n_fns += 1; - // Reset LLVM insn count to avoid compound costs. - stats.n_llvm_insns = self.istart; - } - } -} - pub fn bin_op_to_icmp_predicate(op: hir::BinOpKind, signed: bool) -> IntPredicate { @@ -128,13 +88,13 @@ pub fn bin_op_to_fcmp_predicate(op: hir::BinOpKind) -> RealPredicate { } } -pub fn compare_simd_types<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, lhs: Bx::Value, rhs: Bx::Value, t: Ty<'tcx>, ret_ty: Bx::Type, - op: hir::BinOpKind + op: hir::BinOpKind, ) -> Bx::Value { let signed = match t.sty { ty::Float(_) => { @@ -192,11 +152,11 @@ pub fn unsized_info<'tcx, Cx: CodegenMethods<'tcx>>( } /// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer. -pub fn unsize_thin_ptr<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, src: Bx::Value, src_ty: Ty<'tcx>, - dst_ty: Ty<'tcx> + dst_ty: Ty<'tcx>, ) -> (Bx::Value, Bx::Value) { debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty); match (&src_ty.sty, &dst_ty.sty) { @@ -247,11 +207,11 @@ pub fn unsize_thin_ptr<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( /// Coerce `src`, which is a reference to a value of type `src_ty`, /// to a value of type `dst_ty` and store the result in `dst` -pub fn coerce_unsized_into<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, src: PlaceRef<'tcx, Bx::Value>, - dst: PlaceRef<'tcx, Bx::Value> -) { + dst: PlaceRef<'tcx, Bx::Value>, +) { let src_ty = src.layout.ty; let dst_ty = dst.layout.ty; let mut coerce_ptr = || { @@ -306,16 +266,16 @@ pub fn coerce_unsized_into<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( } } -pub fn cast_shift_expr_rhs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, op: hir::BinOpKind, lhs: Bx::Value, - rhs: Bx::Value + rhs: Bx::Value, ) -> Bx::Value { cast_shift_rhs(bx, op, lhs, rhs) } -fn cast_shift_rhs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +fn cast_shift_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, op: hir::BinOpKind, lhs: Bx::Value, @@ -356,9 +316,9 @@ pub fn wants_msvc_seh(sess: &Session) -> bool { sess.target.target.options.is_like_msvc } -pub fn from_immediate<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn from_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, - val: Bx::Value + val: Bx::Value, ) -> Bx::Value { if bx.cx().val_ty(val) == bx.cx().type_i1() { bx.zext(val, bx.cx().type_i8()) @@ -367,7 +327,7 @@ pub fn from_immediate<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( } } -pub fn to_immediate<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn to_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, val: Bx::Value, layout: layout::TyLayout<'_>, @@ -378,7 +338,7 @@ pub fn to_immediate<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( val } -pub fn to_immediate_scalar<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn to_immediate_scalar<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, val: Bx::Value, scalar: &layout::Scalar, @@ -389,7 +349,7 @@ pub fn to_immediate_scalar<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( val } -pub fn memcpy_ty<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, dst: Bx::Value, dst_align: Align, @@ -410,15 +370,6 @@ pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, instance: Instance<'tcx>, ) { - let _s = if cx.sess().codegen_stats() { - let mut instance_name = String::new(); - DefPathBasedNames::new(cx.tcx(), true, true) - .push_def_path(instance.def_id(), &mut instance_name); - Some(StatRecorder::new(cx, instance_name)) - } else { - None - }; - // this is an info! to allow collecting monomorphization statistics // and to allow finding the last function before LLVM aborts from // release builds. @@ -430,17 +381,13 @@ pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( let lldecl = cx.instances().borrow().get(&instance).cloned().unwrap_or_else(|| bug!("Instance `{:?}` not already declared", instance)); - cx.stats().borrow_mut().n_closures += 1; - let mir = cx.tcx().instance_mir(instance.def); mir::codegen_mir::(cx, lldecl, &mir, instance, sig); } /// Creates the `main` function which will initialize the rust runtime and call /// users main function. -pub fn maybe_create_entry_wrapper<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( - cx: &'a Bx::CodegenCx -) { +pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'a Bx::CodegenCx) { let (main_def_id, span) = match cx.tcx().entry_fn(LOCAL_CRATE) { Some((def_id, _)) => { (def_id, cx.tcx().def_span(def_id)) }, None => return, @@ -463,7 +410,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( None => {} // Do nothing. } - fn create_entry_fn<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( + fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, sp: Span, rust_main: Bx::Value, @@ -502,8 +449,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( bx.insert_reference_to_gdb_debug_scripts_section_global(); // Params from native main() used as args for rust start function - let param_argc = cx.get_param(llfn, 0); - let param_argv = cx.get_param(llfn, 1); + let param_argc = bx.get_param(0); + let param_argv = bx.get_param(1); let arg_argc = bx.intcast(param_argc, cx.type_isize(), true); let arg_argv = param_argv; @@ -528,59 +475,26 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( } pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX; -pub const CODEGEN_WORKER_TIMELINE: time_graph::TimelineId = - time_graph::TimelineId(CODEGEN_WORKER_ID); -pub const CODEGEN_WORK_PACKAGE_KIND: time_graph::WorkPackageKind = - time_graph::WorkPackageKind(&["#DE9597", "#FED1D3", "#FDC5C7", "#B46668", "#88494B"]); - pub fn codegen_crate( backend: B, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - rx: mpsc::Receiver> + tcx: TyCtxt<'tcx>, + metadata: EncodedMetadata, + need_metadata_module: bool, + rx: mpsc::Receiver>, ) -> OngoingCodegen { - check_for_rustc_errors_attr(tcx); - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); - - // Codegen the metadata. - tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen)); - - let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE, - &["crate"], - Some("metadata")).as_str() - .to_string(); - let mut metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name); - let metadata = time(tcx.sess, "write metadata", || { - backend.write_metadata(tcx, &mut metadata_llvm_module) - }); - tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen)); - - let metadata_module = ModuleCodegen { - name: metadata_cgu_name, - module_llvm: metadata_llvm_module, - kind: ModuleKind::Metadata, - }; - - let time_graph = if tcx.sess.opts.debugging_opts.codegen_time_graph { - Some(time_graph::TimeGraph::new()) - } else { - None - }; - // Skip crate items and just output metadata in -Z no-codegen mode. if tcx.sess.opts.debugging_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { let ongoing_codegen = start_async_codegen( backend, tcx, - time_graph, metadata, rx, 1); - ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module); ongoing_codegen.codegen_finished(tcx); assert_and_save_dep_graph(tcx); @@ -590,6 +504,8 @@ pub fn codegen_crate( return ongoing_codegen; } + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); + // Run the monomorphization collector and partition the collected items into // codegen units. let codegen_units = tcx.collect_and_partition_mono_items(LOCAL_CRATE).1; @@ -609,7 +525,6 @@ pub fn codegen_crate( let ongoing_codegen = start_async_codegen( backend.clone(), tcx, - time_graph.clone(), metadata, rx, codegen_units.len()); @@ -654,7 +569,28 @@ pub fn codegen_crate( ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module); } - ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module); + if need_metadata_module { + // Codegen the encoded metadata. + tcx.sess.profiler(|p| p.start_activity("codegen crate metadata")); + + let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE, + &["crate"], + Some("metadata")).as_str() + .to_string(); + let mut metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name); + time(tcx.sess, "write compressed metadata", || { + backend.write_compressed_metadata(tcx, &ongoing_codegen.metadata, + &mut metadata_llvm_module); + }); + tcx.sess.profiler(|p| p.end_activity("codegen crate metadata")); + + let metadata_module = ModuleCodegen { + name: metadata_cgu_name, + module_llvm: metadata_llvm_module, + kind: ModuleKind::Metadata, + }; + ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module); + } // We sort the codegen units by size. This way we can schedule work for LLVM // a bit more efficiently. @@ -665,7 +601,6 @@ pub fn codegen_crate( }; let mut total_codegen_time = Duration::new(0, 0); - let mut all_stats = Stats::default(); for cgu in codegen_units.into_iter() { ongoing_codegen.wait_for_signal_to_codegen_item(); @@ -676,15 +611,11 @@ pub fn codegen_crate( match cgu_reuse { CguReuse::No => { - let _timing_guard = time_graph.as_ref().map(|time_graph| { - time_graph.start(CODEGEN_WORKER_TIMELINE, - CODEGEN_WORK_PACKAGE_KIND, - &format!("codegen {}", cgu.name())) - }); + tcx.sess.profiler(|p| p.start_activity(format!("codegen {}", cgu.name()))); let start_time = Instant::now(); - let stats = backend.compile_codegen_unit(tcx, *cgu.name()); - all_stats.extend(stats); + backend.compile_codegen_unit(tcx, *cgu.name()); total_codegen_time += start_time.elapsed(); + tcx.sess.profiler(|p| p.end_activity(format!("codegen {}", cgu.name()))); false } CguReuse::PreLto => { @@ -716,28 +647,6 @@ pub fn codegen_crate( symbol_names_test::report_symbol_names(tcx); - if tcx.sess.codegen_stats() { - println!("--- codegen stats ---"); - println!("n_glues_created: {}", all_stats.n_glues_created); - println!("n_null_glues: {}", all_stats.n_null_glues); - println!("n_real_glues: {}", all_stats.n_real_glues); - - println!("n_fns: {}", all_stats.n_fns); - println!("n_inlines: {}", all_stats.n_inlines); - println!("n_closures: {}", all_stats.n_closures); - println!("fn stats:"); - all_stats.fn_stats.sort_by_key(|&(_, insns)| insns); - for &(ref name, insns) in all_stats.fn_stats.iter() { - println!("{} insns, {}", insns, *name); - } - } - - if tcx.sess.count_llvm_insns() { - for (k, v) in all_stats.llvm_insns.iter() { - println!("{:7} {}", *v, *k); - } - } - ongoing_codegen.check_for_errors(tcx.sess); assert_and_save_dep_graph(tcx); @@ -791,7 +700,7 @@ impl Drop for AbortCodegenOnDrop { } } -fn assert_and_save_dep_graph<'ll, 'tcx>(tcx: TyCtxt<'ll, 'tcx, 'tcx>) { +fn assert_and_save_dep_graph<'tcx>(tcx: TyCtxt<'tcx>) { time(tcx.sess, "assert dep graph", || ::rustc_incremental::assert_dep_graph(tcx)); @@ -802,7 +711,7 @@ fn assert_and_save_dep_graph<'ll, 'tcx>(tcx: TyCtxt<'ll, 'tcx, 'tcx>) { } impl CrateInfo { - pub fn new(tcx: TyCtxt<'_, '_, '_>) -> CrateInfo { + pub fn new(tcx: TyCtxt<'_>) -> CrateInfo { let mut info = CrateInfo { panic_runtime: None, compiler_builtins: None, @@ -864,11 +773,11 @@ impl CrateInfo { info.missing_lang_items.insert(cnum, missing); } - return info + return info; } } -fn is_codegened_item(tcx: TyCtxt<'_, '_, '_>, id: DefId) -> bool { +fn is_codegened_item(tcx: TyCtxt<'_>, id: DefId) -> bool { let (all_mono_items, _) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); all_mono_items.contains(&id) @@ -930,7 +839,7 @@ pub fn provide_both(providers: &mut Providers<'_>) { .map(|id| &module_map[&id]) .flat_map(|module| module.foreign_items.iter().cloned()) .collect(); - Lrc::new(dllimports) + tcx.arena.alloc(dllimports) }; providers.is_dllimport_foreign_item = |tcx, def_id| { @@ -938,9 +847,7 @@ pub fn provide_both(providers: &mut Providers<'_>) { }; } -fn determine_cgu_reuse<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - cgu: &CodegenUnit<'tcx>) - -> CguReuse { +fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse { if !tcx.dep_graph.is_fully_enabled() { return CguReuse::No } diff --git a/src/librustc_codegen_ssa/common.rs b/src/librustc_codegen_ssa/common.rs index db77074deef94..6376512ca4025 100644 --- a/src/librustc_codegen_ssa/common.rs +++ b/src/librustc_codegen_ssa/common.rs @@ -1,7 +1,7 @@ #![allow(non_camel_case_types, non_snake_case)] -use rustc::ty::{self, Ty, TyCtxt}; -use syntax_pos::{DUMMY_SP, Span}; +use rustc::ty::{Ty, TyCtxt}; +use syntax_pos::Span; use rustc::hir::def_id::DefId; use rustc::middle::lang_items::LangItem; @@ -11,18 +11,6 @@ use crate::traits::*; use rustc::hir; use crate::traits::BuilderMethods; -pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) -} - -pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.is_sized(tcx.at(DUMMY_SP), ty::ParamEnv::reveal_all()) -} - -pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.is_freeze(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP) -} - pub enum IntPredicate { IntEQ, IntNE, @@ -134,11 +122,7 @@ mod temp_stable_hash_impls { } } -pub fn langcall(tcx: TyCtxt<'_, '_, '_>, - span: Option, - msg: &str, - li: LangItem) - -> DefId { +pub fn langcall(tcx: TyCtxt<'_>, span: Option, msg: &str, li: LangItem) -> DefId { tcx.lang_items().require(li).unwrap_or_else(|s| { let msg = format!("{} {}", msg, s); match span { @@ -153,10 +137,10 @@ pub fn langcall(tcx: TyCtxt<'_, '_, '_>, // all shifts). For 32- and 64-bit types, this matches the semantics // of Java. (See related discussion on #1877 and #10183.) -pub fn build_unchecked_lshift<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn build_unchecked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, lhs: Bx::Value, - rhs: Bx::Value + rhs: Bx::Value, ) -> Bx::Value { let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shl, lhs, rhs); // #1877, #10183: Ensure that input is always valid @@ -164,11 +148,11 @@ pub fn build_unchecked_lshift<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( bx.shl(lhs, rhs) } -pub fn build_unchecked_rshift<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn build_unchecked_rshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, lhs_t: Ty<'tcx>, lhs: Bx::Value, - rhs: Bx::Value + rhs: Bx::Value, ) -> Bx::Value { let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shr, lhs, rhs); // #1877, #10183: Ensure that input is always valid @@ -181,20 +165,20 @@ pub fn build_unchecked_rshift<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( } } -fn shift_mask_rhs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +fn shift_mask_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, - rhs: Bx::Value + rhs: Bx::Value, ) -> Bx::Value { let rhs_llty = bx.val_ty(rhs); let shift_val = shift_mask_val(bx, rhs_llty, rhs_llty, false); bx.and(rhs, shift_val) } -pub fn shift_mask_val<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, llty: Bx::Type, mask_llty: Bx::Type, - invert: bool + invert: bool, ) -> Bx::Value { let kind = bx.type_kind(llty); match kind { diff --git a/src/librustc_codegen_ssa/debuginfo.rs b/src/librustc_codegen_ssa/debuginfo.rs deleted file mode 100644 index c4531ff90ae7c..0000000000000 --- a/src/librustc_codegen_ssa/debuginfo.rs +++ /dev/null @@ -1,81 +0,0 @@ -use syntax_pos::{BytePos, Span}; -use rustc::hir::def_id::CrateNum; -use std::cell::Cell; - -pub enum FunctionDebugContext { - RegularContext(FunctionDebugContextData), - DebugInfoDisabled, - FunctionWithoutDebugInfo, -} - -impl FunctionDebugContext { - pub fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData { - match *self { - FunctionDebugContext::RegularContext(ref data) => data, - FunctionDebugContext::DebugInfoDisabled => { - span_bug!( - span, - "debuginfo: Error trying to access FunctionDebugContext \ - although debug info is disabled!", - ); - } - FunctionDebugContext::FunctionWithoutDebugInfo => { - span_bug!( - span, - "debuginfo: Error trying to access FunctionDebugContext \ - for function that should be ignored by debug info!", - ); - } - } - } -} - -/// Enables emitting source locations for the given functions. -/// -/// Since we don't want source locations to be emitted for the function prelude, -/// they are disabled when beginning to codegen a new function. This functions -/// switches source location emitting on and must therefore be called before the -/// first real statement/expression of the function is codegened. -pub fn start_emitting_source_locations(dbg_context: &FunctionDebugContext) { - match *dbg_context { - FunctionDebugContext::RegularContext(ref data) => { - data.source_locations_enabled.set(true) - }, - _ => { /* safe to ignore */ } - } -} - -pub struct FunctionDebugContextData { - pub fn_metadata: D, - pub source_locations_enabled: Cell, - pub defining_crate: CrateNum, -} - -pub enum VariableAccess<'a, V> { - // The llptr given is an alloca containing the variable's value - DirectVariable { alloca: V }, - // The llptr given is an alloca containing the start of some pointer chain - // leading to the variable's content. - IndirectVariable { alloca: V, address_operations: &'a [i64] } -} - -pub enum VariableKind { - ArgumentVariable(usize /*index*/), - LocalVariable, -} - - -#[derive(Clone, Copy, Debug)] -pub struct MirDebugScope { - pub scope_metadata: Option, - // Start and end offsets of the file to which this DIScope belongs. - // These are used to quickly determine whether some span refers to the same file. - pub file_start_pos: BytePos, - pub file_end_pos: BytePos, -} - -impl MirDebugScope { - pub fn is_valid(&self) -> bool { - !self.scope_metadata.is_none() - } -} diff --git a/src/librustc_codegen_ssa/debuginfo/mod.rs b/src/librustc_codegen_ssa/debuginfo/mod.rs new file mode 100644 index 0000000000000..d60a2e0cb1358 --- /dev/null +++ b/src/librustc_codegen_ssa/debuginfo/mod.rs @@ -0,0 +1,82 @@ +use syntax_pos::{BytePos, Span}; +use rustc::hir::def_id::CrateNum; + +pub mod type_names; + +pub enum FunctionDebugContext { + RegularContext(FunctionDebugContextData), + DebugInfoDisabled, + FunctionWithoutDebugInfo, +} + +impl FunctionDebugContext { + pub fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData { + match *self { + FunctionDebugContext::RegularContext(ref data) => data, + FunctionDebugContext::DebugInfoDisabled => { + span_bug!( + span, + "debuginfo: Error trying to access FunctionDebugContext \ + although debug info is disabled!", + ); + } + FunctionDebugContext::FunctionWithoutDebugInfo => { + span_bug!( + span, + "debuginfo: Error trying to access FunctionDebugContext \ + for function that should be ignored by debug info!", + ); + } + } + } +} + +/// Enables emitting source locations for the given functions. +/// +/// Since we don't want source locations to be emitted for the function prelude, +/// they are disabled when beginning to codegen a new function. This functions +/// switches source location emitting on and must therefore be called before the +/// first real statement/expression of the function is codegened. +pub fn start_emitting_source_locations(dbg_context: &mut FunctionDebugContext) { + match *dbg_context { + FunctionDebugContext::RegularContext(ref mut data) => { + data.source_locations_enabled = true; + }, + _ => { /* safe to ignore */ } + } +} + +pub struct FunctionDebugContextData { + pub fn_metadata: D, + pub source_locations_enabled: bool, + pub defining_crate: CrateNum, +} + +pub enum VariableAccess<'a, V> { + // The llptr given is an alloca containing the variable's value + DirectVariable { alloca: V }, + // The llptr given is an alloca containing the start of some pointer chain + // leading to the variable's content. + IndirectVariable { alloca: V, address_operations: &'a [i64] } +} + +pub enum VariableKind { + ArgumentVariable(usize /*index*/), + LocalVariable, +} + + +#[derive(Clone, Copy, Debug)] +pub struct MirDebugScope { + pub scope_metadata: Option, + // Start and end offsets of the file to which this DIScope belongs. + // These are used to quickly determine whether some span refers to the same file. + pub file_start_pos: BytePos, + pub file_end_pos: BytePos, +} + +impl MirDebugScope { + pub fn is_valid(&self) -> bool { + !self.scope_metadata.is_none() + } +} diff --git a/src/librustc_codegen_ssa/debuginfo/type_names.rs b/src/librustc_codegen_ssa/debuginfo/type_names.rs new file mode 100644 index 0000000000000..8f0bb6ee19837 --- /dev/null +++ b/src/librustc_codegen_ssa/debuginfo/type_names.rs @@ -0,0 +1,252 @@ +// Type Names for Debug Info. + +use rustc::hir::{self, def_id::DefId}; +use rustc::ty::{self, Ty, TyCtxt, subst::SubstsRef}; +use rustc_data_structures::fx::FxHashSet; + +// Compute the name of the type as it should be stored in debuginfo. Does not do +// any caching, i.e., calling the function twice with the same type will also do +// the work twice. The `qualified` parameter only affects the first level of the +// type name, further levels (i.e., type parameters) are always fully qualified. +pub fn compute_debuginfo_type_name<'tcx>( + tcx: TyCtxt<'tcx>, + t: Ty<'tcx>, + qualified: bool, +) -> String { + let mut result = String::with_capacity(64); + let mut visited = FxHashSet::default(); + push_debuginfo_type_name(tcx, t, qualified, &mut result, &mut visited); + result +} + +// Pushes the name of the type as it should be stored in debuginfo on the +// `output` String. See also compute_debuginfo_type_name(). +pub fn push_debuginfo_type_name<'tcx>( + tcx: TyCtxt<'tcx>, + t: Ty<'tcx>, + qualified: bool, + output: &mut String, + visited: &mut FxHashSet>, +) { + // When targeting MSVC, emit C++ style type names for compatibility with + // .natvis visualizers (and perhaps other existing native debuggers?) + let cpp_like_names = tcx.sess.target.target.options.is_like_msvc; + + match t.sty { + ty::Bool => output.push_str("bool"), + ty::Char => output.push_str("char"), + ty::Str => output.push_str("str"), + ty::Never => output.push_str("!"), + ty::Int(int_ty) => output.push_str(int_ty.ty_to_string()), + ty::Uint(uint_ty) => output.push_str(uint_ty.ty_to_string()), + ty::Float(float_ty) => output.push_str(float_ty.ty_to_string()), + ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output), + ty::Adt(def, substs) => { + push_item_name(tcx, def.did, qualified, output); + push_type_params(tcx, substs, output, visited); + }, + ty::Tuple(component_types) => { + output.push('('); + for &component_type in component_types { + push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited); + output.push_str(", "); + } + if !component_types.is_empty() { + output.pop(); + output.pop(); + } + output.push(')'); + }, + ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { + if !cpp_like_names { + output.push('*'); + } + match mutbl { + hir::MutImmutable => output.push_str("const "), + hir::MutMutable => output.push_str("mut "), + } + + push_debuginfo_type_name(tcx, inner_type, true, output, visited); + + if cpp_like_names { + output.push('*'); + } + }, + ty::Ref(_, inner_type, mutbl) => { + if !cpp_like_names { + output.push('&'); + } + if mutbl == hir::MutMutable { + output.push_str("mut "); + } + + push_debuginfo_type_name(tcx, inner_type, true, output, visited); + + if cpp_like_names { + output.push('*'); + } + }, + ty::Array(inner_type, len) => { + output.push('['); + push_debuginfo_type_name(tcx, inner_type, true, output, visited); + output.push_str(&format!("; {}", len.unwrap_usize(tcx))); + output.push(']'); + }, + ty::Slice(inner_type) => { + if cpp_like_names { + output.push_str("slice<"); + } else { + output.push('['); + } + + push_debuginfo_type_name(tcx, inner_type, true, output, visited); + + if cpp_like_names { + output.push('>'); + } else { + output.push(']'); + } + }, + ty::Dynamic(ref trait_data, ..) => { + if let Some(principal) = trait_data.principal() { + let principal = tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &principal, + ); + push_item_name(tcx, principal.def_id, false, output); + push_type_params(tcx, principal.substs, output, visited); + } else { + output.push_str("dyn '_"); + } + }, + ty::FnDef(..) | ty::FnPtr(_) => { + // We've encountered a weird 'recursive type' + // Currently, the only way to generate such a type + // is by using 'impl trait': + // + // fn foo() -> impl Copy { foo } + // + // There's not really a sensible name we can generate, + // since we don't include 'impl trait' types (e.g. ty::Opaque) + // in the output + // + // Since we need to generate *something*, we just + // use a dummy string that should make it clear + // that something unusual is going on + if !visited.insert(t) { + output.push_str(""); + return; + } + + + let sig = t.fn_sig(tcx); + if sig.unsafety() == hir::Unsafety::Unsafe { + output.push_str("unsafe "); + } + + let abi = sig.abi(); + if abi != rustc_target::spec::abi::Abi::Rust { + output.push_str("extern \""); + output.push_str(abi.name()); + output.push_str("\" "); + } + + output.push_str("fn("); + + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + if !sig.inputs().is_empty() { + for ¶meter_type in sig.inputs() { + push_debuginfo_type_name(tcx, parameter_type, true, output, visited); + output.push_str(", "); + } + output.pop(); + output.pop(); + } + + if sig.c_variadic { + if !sig.inputs().is_empty() { + output.push_str(", ..."); + } else { + output.push_str("..."); + } + } + + output.push(')'); + + if !sig.output().is_unit() { + output.push_str(" -> "); + push_debuginfo_type_name(tcx, sig.output(), true, output, visited); + } + + + // We only keep the type in 'visited' + // for the duration of the body of this method. + // It's fine for a particular function type + // to show up multiple times in one overall type + // (e.g. MyType u8, fn() -> u8> + // + // We only care about avoiding recursing + // directly back to the type we're currently + // processing + visited.remove(t); + }, + ty::Closure(..) => { + output.push_str("closure"); + } + ty::Generator(..) => { + output.push_str("generator"); + } + ty::Error | + ty::Infer(_) | + ty::Placeholder(..) | + ty::UnnormalizedProjection(..) | + ty::Projection(..) | + ty::Bound(..) | + ty::Opaque(..) | + ty::GeneratorWitness(..) | + ty::Param(_) => { + bug!("debuginfo: Trying to create type name for \ + unexpected type: {:?}", t); + } + } + + fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) { + if qualified { + output.push_str(&tcx.crate_name(def_id.krate).as_str()); + for path_element in tcx.def_path(def_id).data { + output.push_str("::"); + output.push_str(&path_element.data.as_interned_str().as_str()); + } + } else { + output.push_str(&tcx.item_name(def_id).as_str()); + } + } + + // Pushes the type parameters in the given `InternalSubsts` to the output string. + // This ignores region parameters, since they can't reliably be + // reconstructed for items from non-local crates. For local crates, this + // would be possible but with inlining and LTO we have to use the least + // common denominator - otherwise we would run into conflicts. + fn push_type_params<'tcx>( + tcx: TyCtxt<'tcx>, + substs: SubstsRef<'tcx>, + output: &mut String, + visited: &mut FxHashSet>, + ) { + if substs.types().next().is_none() { + return; + } + + output.push('<'); + + for type_parameter in substs.types() { + push_debuginfo_type_name(tcx, type_parameter, true, output, visited); + output.push_str(", "); + } + + output.pop(); + output.pop(); + + output.push('>'); + } +} diff --git a/src/librustc_codegen_ssa/diagnostics.rs b/src/librustc_codegen_ssa/error_codes.rs similarity index 100% rename from src/librustc_codegen_ssa/diagnostics.rs rename to src/librustc_codegen_ssa/error_codes.rs diff --git a/src/librustc_codegen_ssa/glue.rs b/src/librustc_codegen_ssa/glue.rs index e2b49de05bd11..7fd9f67e2f45b 100644 --- a/src/librustc_codegen_ssa/glue.rs +++ b/src/librustc_codegen_ssa/glue.rs @@ -7,10 +7,10 @@ use crate::common::IntPredicate; use crate::meth; use crate::traits::*; -pub fn size_and_align_of_dst<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, t: Ty<'tcx>, - info: Option + info: Option, ) -> (Bx::Value, Bx::Value) { let layout = bx.layout_of(t); debug!("size_and_align_of_dst(ty={}, info={:?}): layout: {:?}", diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index f38b22aa04171..b76f098773f0b 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -2,15 +2,19 @@ #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(custom_attribute)] +#![feature(core_intrinsics)] #![feature(libc)] #![feature(rustc_diagnostic_macros)] +#![feature(stmt_expr_attributes)] +#![feature(try_blocks)] #![feature(in_band_lifetimes)] #![feature(nll)] +#![feature(trusted_len)] #![allow(unused_attributes)] #![allow(dead_code)] #![deny(rust_2018_idioms)] -#![allow(explicit_outlives_requirements)] +#![deny(internal)] +#![deny(unused_lifetimes)] #![recursion_limit="256"] @@ -20,6 +24,7 @@ #[macro_use] extern crate log; #[macro_use] extern crate rustc; +#[macro_use] extern crate rustc_data_structures; #[macro_use] extern crate syntax; use std::path::PathBuf; @@ -35,7 +40,7 @@ use syntax_pos::symbol::Symbol; // N.B., this module needs to be declared first so diagnostics are // registered before they are used. -mod diagnostics; +mod error_codes; pub mod common; pub mod traits; @@ -60,6 +65,7 @@ pub struct ModuleCodegen { pub kind: ModuleKind, } +pub const METADATA_FILENAME: &str = "rust.metadata.bin"; pub const RLIB_BYTECODE_EXTENSION: &str = "bc.z"; impl ModuleCodegen { @@ -147,7 +153,7 @@ pub struct CodegenResults { pub crate_name: Symbol, pub modules: Vec, pub allocator_module: Option, - pub metadata_module: CompiledModule, + pub metadata_module: Option, pub crate_hash: Svh, pub metadata: rustc::middle::cstore::EncodedMetadata, pub windows_subsystem: Option, diff --git a/src/librustc_codegen_ssa/meth.rs b/src/librustc_codegen_ssa/meth.rs index 49f3c87ee2d9d..7fe9f5f25130a 100644 --- a/src/librustc_codegen_ssa/meth.rs +++ b/src/librustc_codegen_ssa/meth.rs @@ -1,10 +1,9 @@ use rustc_target::abi::call::FnType; -use rustc_mir::monomorphize; use crate::callee; use crate::traits::*; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, Instance}; #[derive(Copy, Clone, Debug)] pub struct VirtualIndex(u64); @@ -13,7 +12,7 @@ pub const DESTRUCTOR: VirtualIndex = VirtualIndex(0); pub const SIZE: VirtualIndex = VirtualIndex(1); pub const ALIGN: VirtualIndex = VirtualIndex(2); -impl<'a, 'tcx: 'a> VirtualIndex { +impl<'a, 'tcx> VirtualIndex { pub fn from_index(index: usize) -> Self { VirtualIndex(index as u64 + 3) } @@ -103,7 +102,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( // `get_vtable` in rust_mir/interpret/traits.rs // ///////////////////////////////////////////////////////////////////////////////////////////// let components: Vec<_> = [ - cx.get_fn(monomorphize::resolve_drop_in_place(cx.tcx(), ty)), + cx.get_fn(Instance::resolve_drop_in_place(cx.tcx(), ty)), cx.const_usize(layout.size.bytes()), cx.const_usize(layout.align.abi.bytes()) ].iter().cloned().chain(methods).collect(); diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index facae9a979706..0289150a5e42a 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -12,13 +12,13 @@ use rustc::ty::layout::{LayoutOf, HasTyCtxt}; use super::FunctionCx; use crate::traits::*; -pub fn non_ssa_locals<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( - fx: &FunctionCx<'a, 'tcx, Bx> +pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + fx: &FunctionCx<'a, 'tcx, Bx>, ) -> BitSet { let mir = fx.mir; let mut analyzer = LocalAnalyzer::new(fx); - analyzer.visit_mir(mir); + analyzer.visit_body(mir); for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() { let ty = fx.monomorphize(&ty); @@ -43,13 +43,13 @@ pub fn non_ssa_locals<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( analyzer.non_ssa_locals } -struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> { +struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { fx: &'mir FunctionCx<'a, 'tcx, Bx>, dominators: Dominators, non_ssa_locals: BitSet, // The location of the first visited direct assignment to each // local, or an invalid location (out of bounds `block` index). - first_assignment: IndexVec + first_assignment: IndexVec, } impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { @@ -94,14 +94,14 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { } } -impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> - for LocalAnalyzer<'mir, 'a, 'tcx, Bx> { +impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> + for LocalAnalyzer<'mir, 'a, 'tcx, Bx> +{ fn visit_assign(&mut self, - block: mir::BasicBlock, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'tcx>, location: Location) { - debug!("visit_assign(block={:?}, place={:?}, rvalue={:?})", block, place, rvalue); + debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue); if let mir::Place::Base(mir::PlaceBase::Local(index)) = *place { self.assign(index, location); @@ -120,7 +120,6 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> } fn visit_terminator_kind(&mut self, - block: mir::BasicBlock, kind: &mir::TerminatorKind<'tcx>, location: Location) { let check = match *kind { @@ -148,12 +147,12 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> } } - self.super_terminator_kind(block, kind, location); + self.super_terminator_kind(kind, location); } fn visit_place(&mut self, place: &mir::Place<'tcx>, - context: PlaceContext<'tcx>, + context: PlaceContext, location: Location) { debug!("visit_place(place={:?}, context={:?})", place, context); let cx = self.fx.cx; @@ -172,14 +171,14 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> // ZSTs don't require any actual memory access. let elem_ty = base_ty .projection_ty(cx.tcx(), &proj.elem) - .to_ty(cx.tcx()); + .ty; let elem_ty = self.fx.monomorphize(&elem_ty); if cx.layout_of(elem_ty).is_zst() { return; } if let mir::ProjectionElem::Field(..) = proj.elem { - let layout = cx.layout_of(base_ty.to_ty(cx.tcx())); + let layout = cx.layout_of(base_ty.ty); if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { // Recurse with the same context, instead of `Projection`, // potentially stopping at non-operand projections, @@ -205,7 +204,7 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> fn visit_local(&mut self, &local: &mir::Local, - context: PlaceContext<'tcx>, + context: PlaceContext, location: Location) { match context { PlaceContext::MutatingUse(MutatingUseContext::Call) => { @@ -235,19 +234,18 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) | PlaceContext::MutatingUse(MutatingUseContext::Store) | PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) | - PlaceContext::MutatingUse(MutatingUseContext::Borrow(..)) | + PlaceContext::MutatingUse(MutatingUseContext::Borrow) | PlaceContext::MutatingUse(MutatingUseContext::Projection) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow(..)) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => { self.not_ssa(local); } PlaceContext::MutatingUse(MutatingUseContext::Drop) => { - let ty = mir::Place::Base(mir::PlaceBase::Local(local)).ty(self.fx.mir, - self.fx.cx.tcx()); - let ty = self.fx.monomorphize(&ty.to_ty(self.fx.cx.tcx())); + let ty = self.fx.mir.local_decls[local].ty; + let ty = self.fx.monomorphize(&ty); // Only need the place if we're actually dropping it. if self.fx.cx.type_needs_drop(ty) { @@ -275,9 +273,9 @@ impl CleanupKind { } } -pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec { +pub fn cleanup_kinds<'tcx>(mir: &mir::Body<'tcx>) -> IndexVec { fn discover_masters<'tcx>(result: &mut IndexVec, - mir: &mir::Mir<'tcx>) { + mir: &mir::Body<'tcx>) { for (bb, data) in mir.basic_blocks().iter_enumerated() { match data.terminator().kind { TerminatorKind::Goto { .. } | @@ -307,7 +305,7 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec(result: &mut IndexVec, - mir: &mir::Mir<'tcx>) { + mir: &mir::Body<'tcx>) { let mut funclet_succs = IndexVec::from_elem(None, mir.basic_blocks()); let mut set_successor = |funclet: mir::BasicBlock, succ| { diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 02086c7730cee..941166ccfab09 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -1,11 +1,10 @@ use rustc::middle::lang_items; -use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::layout::{self, LayoutOf, HasTyCtxt}; -use rustc::mir; -use rustc::mir::interpret::EvalErrorKind; +use rustc::ty::{self, Ty, TypeFoldable, Instance}; +use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt}; +use rustc::mir::{self, Place, PlaceBase, Static, StaticKind}; +use rustc::mir::interpret::InterpError; use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode}; use rustc_target::spec::abi::Abi; -use rustc_mir::monomorphize; use crate::base; use crate::MemFlags; use crate::common::{self, IntPredicate}; @@ -15,12 +14,12 @@ use crate::traits::*; use std::borrow::Cow; -use syntax::symbol::Symbol; +use syntax::symbol::LocalInternedString; use syntax_pos::Pos; use super::{FunctionCx, LocalRef}; use super::place::PlaceRef; -use super::operand::{OperandValue, OperandRef}; +use super::operand::OperandRef; use super::operand::OperandValue::{Pair, Ref, Immediate}; /// Used by `FunctionCx::codegen_terminator` for emitting common patterns @@ -152,7 +151,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'a, 'tcx> { } /// Codegen implementations for some terminator variants. -impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// Generates code for a `Resume` terminator. fn codegen_resume_terminator<'b>( &mut self, @@ -214,29 +213,34 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } else { let (otherwise, targets) = targets.split_last().unwrap(); - let switch = bx.switch(discr.immediate(), - helper.llblock(self, *otherwise), - values.len()); - let switch_llty = bx.immediate_backend_type( - bx.layout_of(switch_ty) + bx.switch( + discr.immediate(), + helper.llblock(self, *otherwise), + values.iter().zip(targets).map(|(&value, target)| { + (value, helper.llblock(self, *target)) + }) ); - for (&value, target) in values.iter().zip(targets) { - let llval = bx.const_uint_big(switch_llty, value); - let llbb = helper.llblock(self, *target); - bx.add_case(switch, llval, llbb) - } } } - fn codegen_return_terminator<'b>( - &mut self, - mut bx: Bx, - ) { + fn codegen_return_terminator(&mut self, mut bx: Bx) { if self.fn_ty.c_variadic { - if let Some(va_list) = self.va_list_ref { - bx.va_end(va_list.llval); + match self.va_list_ref { + Some(va_list) => { + bx.va_end(va_list.llval); + } + None => { + bug!("C-variadic function must have a `va_list_ref`"); + } } } + if self.fn_ty.ret.layout.abi.is_uninhabited() { + // Functions with uninhabited return values are marked `noreturn`, + // so we should make sure that we never actually do. + bx.abort(); + bx.unreachable(); + return; + } let llval = match self.fn_ty.ret.mode { PassMode::Ignore(IgnoreMode::Zst) | PassMode::Indirect(..) => { bx.ret_void(); @@ -300,9 +304,9 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { target: mir::BasicBlock, unwind: Option, ) { - let ty = location.ty(self.mir, bx.tcx()).to_ty(bx.tcx()); + let ty = location.ty(self.mir, bx.tcx()).ty; let ty = self.monomorphize(&ty); - let drop_fn = monomorphize::resolve_drop_in_place(bx.tcx(), ty); + let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty); if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { // we don't actually need to drop anything. @@ -326,14 +330,14 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ty::ParamEnv::reveal_all(), &sig, ); - let fn_ty = bx.new_vtable(sig, &[]); + let fn_ty = FnType::new_vtable(&bx, sig, &[]); let vtable = args[1]; args = &args[..1]; (meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_ty), fn_ty) } _ => { (bx.get_fn(drop_fn), - bx.fn_type_of_instance(&drop_fn)) + FnType::of_instance(&bx, &drop_fn)) } }; helper.do_call(self, &mut bx, fn_ty, drop_fn, args, @@ -364,7 +368,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // checked operation, just a comparison with the minimum // value, so we have to check for the assert message. if !bx.check_overflow() { - if let mir::interpret::EvalErrorKind::OverflowNeg = *msg { + if let mir::interpret::InterpError::OverflowNeg = *msg { const_cond = Some(expected); } } @@ -393,51 +397,45 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Get the location information. let loc = bx.sess().source_map().lookup_char_pos(span.lo()); - let filename = Symbol::intern(&loc.file.name.to_string()).as_str(); - let filename = bx.const_str_slice(filename); + let filename = LocalInternedString::intern(&loc.file.name.to_string()); let line = bx.const_u32(loc.line as u32); let col = bx.const_u32(loc.col.to_usize() as u32 + 1); - let align = self.cx.tcx().data_layout.aggregate_align.abi - .max(self.cx.tcx().data_layout.i32_align.abi) - .max(self.cx.tcx().data_layout.pointer_align.abi); // Put together the arguments to the panic entry point. let (lang_item, args) = match *msg { - EvalErrorKind::BoundsCheck { ref len, ref index } => { + InterpError::BoundsCheck { ref len, ref index } => { let len = self.codegen_operand(&mut bx, len).immediate(); let index = self.codegen_operand(&mut bx, index).immediate(); - let file_line_col = bx.const_struct(&[filename, line, col], false); - let file_line_col = bx.static_addr_of( - file_line_col, - align, - Some("panic_bounds_check_loc") + let file_line_col = bx.static_panic_msg( + None, + filename, + line, + col, + "panic_bounds_check_loc", ); (lang_items::PanicBoundsCheckFnLangItem, - vec![file_line_col, index, len]) + vec![file_line_col, index, len]) } _ => { let str = msg.description(); - let msg_str = Symbol::intern(str).as_str(); - let msg_str = bx.const_str_slice(msg_str); - let msg_file_line_col = bx.const_struct( - &[msg_str, filename, line, col], - false - ); - let msg_file_line_col = bx.static_addr_of( - msg_file_line_col, - align, - Some("panic_loc") + let msg_str = LocalInternedString::intern(str); + let msg_file_line_col = bx.static_panic_msg( + Some(msg_str), + filename, + line, + col, + "panic_loc", ); (lang_items::PanicFnLangItem, - vec![msg_file_line_col]) + vec![msg_file_line_col]) } }; // Obtain the panic entry point. let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item); let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_ty = bx.fn_type_of_instance(&instance); + let fn_ty = FnType::of_instance(&bx, &instance); let llfn = bx.get_fn(instance); // Codegen the actual panic invoke/call. @@ -505,7 +503,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - // The "spoofed" `VaList` added to a C-variadic functions signature + // The "spoofed" `VaListImpl` added to a C-variadic functions signature // should not be included in the `extra_args` calculation. let extra_args_start_idx = sig.inputs().len() - if sig.c_variadic { 1 } else { 0 }; let extra_args = &args[extra_args_start_idx..]; @@ -516,7 +514,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let fn_ty = match def { Some(ty::InstanceDef::Virtual(..)) => { - bx.new_vtable(sig, &extra_args) + FnType::new_vtable(&bx, sig, &extra_args) } Some(ty::InstanceDef::DropGlue(_, None)) => { // Empty drop glue; a no-op. @@ -524,7 +522,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { helper.funclet_br(self, &mut bx, target); return; } - _ => bx.new_fn_type(sig, &extra_args) + _ => FnType::new(&bx, sig, &extra_args) }; // Emit a panic or a no-op for `panic_if_uninhabited`. @@ -533,35 +531,28 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let layout = bx.layout_of(ty); if layout.abi.is_uninhabited() { let loc = bx.sess().source_map().lookup_char_pos(span.lo()); - let filename = Symbol::intern(&loc.file.name.to_string()).as_str(); - let filename = bx.const_str_slice(filename); + let filename = LocalInternedString::intern(&loc.file.name.to_string()); let line = bx.const_u32(loc.line as u32); let col = bx.const_u32(loc.col.to_usize() as u32 + 1); - let align = self.cx.tcx().data_layout.aggregate_align.abi - .max(self.cx.tcx().data_layout.i32_align.abi) - .max(self.cx.tcx().data_layout.pointer_align.abi); let str = format!( "Attempted to instantiate uninhabited type {}", ty ); - let msg_str = Symbol::intern(&str).as_str(); - let msg_str = bx.const_str_slice(msg_str); - let msg_file_line_col = bx.const_struct( - &[msg_str, filename, line, col], - false, - ); - let msg_file_line_col = bx.static_addr_of( - msg_file_line_col, - align, - Some("panic_loc"), + let msg_str = LocalInternedString::intern(&str); + let msg_file_line_col = bx.static_panic_msg( + Some(msg_str), + filename, + line, + col, + "panic_loc", ); // Obtain the panic entry point. let def_id = common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_ty = bx.fn_type_of_instance(&instance); + let fn_ty = FnType::of_instance(&bx, &instance); let llfn = bx.get_fn(instance); // Codegen the actual panic invoke/call. @@ -616,15 +607,23 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // but specified directly in the code. This means it gets promoted // and we can then extract the value by evaluating the promoted. mir::Operand::Copy( - mir::Place::Base(mir::PlaceBase::Promoted(box(index, ty))) + Place::Base( + PlaceBase::Static( + box Static { kind: StaticKind::Promoted(promoted), ty } + ) + ) ) | mir::Operand::Move( - mir::Place::Base(mir::PlaceBase::Promoted(box(index, ty))) + Place::Base( + PlaceBase::Static( + box Static { kind: StaticKind::Promoted(promoted), ty } + ) + ) ) => { let param_env = ty::ParamEnv::reveal_all(); let cid = mir::interpret::GlobalId { instance: self.instance, - promoted: Some(index), + promoted: Some(promoted), }; let c = bx.tcx().const_eval(param_env.and(cid)); let (llval, ty) = self.simd_shuffle_indices( @@ -644,7 +643,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { span_bug!(span, "shuffle indices must be constant"); } mir::Operand::Constant(ref constant) => { - let c = self.eval_mir_constant(&bx, constant); + let c = self.eval_mir_constant(constant); let (llval, ty) = self.simd_shuffle_indices( &bx, constant.span, @@ -688,7 +687,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (&args[..], None) }; - // Useful determining if the current argument is the "spoofed" `VaList` + // Useful determining if the current argument is the "spoofed" `VaListImpl` let last_arg_idx = if sig.inputs().is_empty() { None } else { @@ -696,21 +695,10 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; 'make_args: for (i, arg) in first_args.iter().enumerate() { // If this is a C-variadic function the function signature contains - // an "spoofed" `VaList`. This argument is ignored, but we need to + // an "spoofed" `VaListImpl`. This argument is ignored, but we need to // populate it with a dummy operand so that the users real arguments // are not overwritten. - let i = if sig.c_variadic && last_arg_idx.map(|x| x == i).unwrap_or(false) { - let layout = match self.cx.tcx().lang_items().va_list() { - Some(did) => bx.cx().layout_of(bx.tcx().type_of(did)), - None => bug!("`va_list` language item required for C-variadics"), - }; - let op = OperandRef { - val: OperandValue::Immediate( - bx.cx().const_undef(bx.cx().immediate_backend_type(layout) - )), - layout: layout, - }; - self.codegen_argument(&mut bx, op, &mut llargs, &fn_ty.args[i]); + let i = if sig.c_variadic && last_arg_idx.map(|x| i >= x).unwrap_or(false) { if i + 1 < fn_ty.args.len() { i + 1 } else { @@ -800,7 +788,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } -impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn codegen_block( &mut self, bb: mir::BasicBlock, @@ -976,7 +964,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.range_metadata(llval, 0..2); } } - // We store bools as i8 so we need to truncate to i1. + // We store bools as `i8` so we need to truncate to `i1`. llval = base::to_immediate(bx, llval, arg.layout); } } @@ -1106,7 +1094,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_ret: &ArgType<'tcx, Ty<'tcx>>, llargs: &mut Vec, is_intrinsic: bool ) -> ReturnDest<'tcx, Bx::Value> { - // If the return is ignored, we can just return a do-nothing ReturnDest + // If the return is ignored, we can just return a do-nothing `ReturnDest`. if fn_ret.is_ignore() { return ReturnDest::Nothing; } @@ -1115,8 +1103,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Place(dest) => dest, LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), LocalRef::Operand(None) => { - // Handle temporary places, specifically Operand ones, as - // they don't have allocas + // Handle temporary places, specifically `Operand` ones, as + // they don't have `alloca`s. return if fn_ret.is_indirect() { // Odd, but possible, case, we have an operand temporary, // but the calling convention has an indirect return. @@ -1126,8 +1114,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ReturnDest::IndirectOperand(tmp, index) } else if is_intrinsic { // Currently, intrinsics always need a location to store - // the result. so we create a temporary alloca for the - // result + // the result, so we create a temporary `alloca` for the + // result. let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret"); tmp.storage_live(bx); ReturnDest::IndirectOperand(tmp, index) @@ -1146,7 +1134,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if dest.align < dest.layout.align.abi { // Currently, MIR code generation does not create calls // that store directly to fields of packed structs (in - // fact, the calls it creates write only to temps), + // fact, the calls it creates write only to temps). // // If someone changes that, please update this code path // to create a temporary. @@ -1241,12 +1229,12 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } enum ReturnDest<'tcx, V> { - // Do nothing, the return value is indirect or ignored + // Do nothing; the return value is indirect or ignored. Nothing, - // Store the return value to the pointer + // Store the return value to the pointer. Store(PlaceRef<'tcx, V>), - // Stores an indirect return value to an operand local place + // Store an indirect return value to an operand local place. IndirectOperand(PlaceRef<'tcx, V>, mir::Local), - // Stores a direct return value to an operand local place + // Store a direct return value to an operand local place. DirectOperand(mir::Local) } diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 6bc69efa4a7d5..d6951b923bf7d 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -1,84 +1,69 @@ use rustc::mir::interpret::ErrorHandled; -use rustc_mir::const_eval::const_field; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; -use rustc::mir::interpret::GlobalId; use rustc::ty::{self, Ty}; -use rustc::ty::layout; +use rustc::ty::layout::{self, HasTyCtxt}; use syntax::source_map::Span; use crate::traits::*; use super::FunctionCx; -impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - fn fully_evaluate( +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { + pub fn eval_mir_constant( &mut self, - bx: &Bx, - constant: &'tcx ty::LazyConst<'tcx>, - ) -> Result, ErrorHandled> { - match *constant { - ty::LazyConst::Unevaluated(def_id, ref substs) => { - let tcx = bx.tcx(); - let param_env = ty::ParamEnv::reveal_all(); - let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap(); - let cid = GlobalId { + constant: &mir::Constant<'tcx>, + ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> { + match constant.literal.val { + mir::interpret::ConstValue::Unevaluated(def_id, ref substs) => { + let substs = self.monomorphize(substs); + let instance = ty::Instance::resolve( + self.cx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs, + ).unwrap(); + let cid = mir::interpret::GlobalId { instance, promoted: None, }; - tcx.const_eval(param_env.and(cid)) + self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid)) }, - ty::LazyConst::Evaluated(constant) => Ok(constant), + _ => Ok(self.monomorphize(&constant.literal)), } } - pub fn eval_mir_constant( - &mut self, - bx: &Bx, - constant: &mir::Constant<'tcx>, - ) -> Result, ErrorHandled> { - let c = self.monomorphize(&constant.literal); - self.fully_evaluate(bx, c) - } - /// process constant containing SIMD shuffle indices pub fn simd_shuffle_indices( &mut self, bx: &Bx, span: Span, ty: Ty<'tcx>, - constant: Result, ErrorHandled>, + constant: Result<&'tcx ty::Const<'tcx>, ErrorHandled>, ) -> (Bx::Value, Ty<'tcx>) { constant - .and_then(|c| { + .map(|c| { let field_ty = c.ty.builtin_index().unwrap(); let fields = match c.ty.sty { ty::Array(_, n) => n.unwrap_usize(bx.tcx()), - ref other => bug!("invalid simd shuffle type: {}", other), + _ => bug!("invalid simd shuffle type: {}", c.ty), }; - let values: Result, ErrorHandled> = (0..fields).map(|field| { - let field = const_field( - bx.tcx(), - ty::ParamEnv::reveal_all(), - None, - mir::Field::new(field as usize), - c, - )?; + let values: Vec<_> = (0..fields).map(|field| { + let field = bx.tcx().const_field( + ty::ParamEnv::reveal_all().and((&c, mir::Field::new(field as usize))) + ); if let Some(prim) = field.val.try_to_scalar() { let layout = bx.layout_of(field_ty); let scalar = match layout.abi { layout::Abi::Scalar(ref x) => x, _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) }; - Ok(bx.scalar_to_backend( + bx.scalar_to_backend( prim, scalar, bx.immediate_backend_type(layout), - )) + ) } else { bug!("simd shuffle field {:?}", field) } }).collect(); - let llval = bx.const_struct(&values?, false); - Ok((llval, c.ty)) + let llval = bx.const_struct(&values, false); + (llval, c.ty) }) .unwrap_or_else(|_| { bx.tcx().sess.span_err( diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 870b97401f47a..e7517d6999195 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -1,17 +1,15 @@ -use libc::c_uint; -use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts}; -use rustc::ty::layout::{TyLayout, HasTyCtxt}; -use rustc::mir::{self, Mir}; -use rustc::ty::subst::SubstsRef; +use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts, Instance}; +use rustc::ty::layout::{TyLayout, HasTyCtxt, FnTypeExt}; +use rustc::mir::{self, Body}; use rustc::session::config::DebugInfo; -use rustc_mir::monomorphize::Instance; use rustc_target::abi::call::{FnType, PassMode, IgnoreMode}; +use rustc_target::abi::{Variants, VariantIdx}; use crate::base; use crate::debuginfo::{self, VariableAccess, VariableKind, FunctionDebugContext}; use crate::traits::*; use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span}; -use syntax::symbol::keywords; +use syntax::symbol::kw; use std::iter; @@ -25,10 +23,10 @@ use rustc::mir::traversal; use self::operand::{OperandRef, OperandValue}; /// Master context for codegenning from MIR. -pub struct FunctionCx<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> { +pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { instance: Instance<'tcx>, - mir: &'a mir::Mir<'tcx>, + mir: &'a mir::Body<'tcx>, debug_context: FunctionDebugContext, @@ -45,7 +43,7 @@ pub struct FunctionCx<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> { /// don't really care about it very much. Anyway, this value /// contains an alloca into which the personality is stored and /// then later loaded when generating the DIVERGE_BLOCK. - personality_slot: Option>, + personality_slot: Option>, /// A `Block` for each MIR `BasicBlock` blocks: IndexVec, @@ -84,20 +82,17 @@ pub struct FunctionCx<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> { /// Debug information for MIR scopes. scopes: IndexVec>, - /// If this function is being monomorphized, this contains the type substitutions used. - param_substs: SubstsRef<'tcx>, - /// If this function is a C-variadic function, this contains the `PlaceRef` of the - /// "spoofed" `VaList`. + /// "spoofed" `VaListImpl`. va_list_ref: Option>, } -impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn monomorphize(&self, value: &T) -> T where T: TypeFoldable<'tcx> { self.cx.tcx().subst_and_normalize_erasing_regions( - self.param_substs, + self.instance.substs, ty::ParamEnv::reveal_all(), value, ) @@ -109,7 +104,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { source_info: mir::SourceInfo ) { let (scope, span) = self.debug_loc(source_info); - bx.set_source_location(&self.debug_context, scope, span); + bx.set_source_location(&mut self.debug_context, scope, span); } pub fn debug_loc(&self, source_info: mir::SourceInfo) -> (Option, Span) { @@ -133,14 +128,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Walk up the macro expansion chain until we reach a non-expanded span. // We also stop at the function body level because no line stepping can occur // at the level above that. - let mut span = source_info.span; - while span.ctxt() != NO_EXPANSION && span.ctxt() != self.mir.span.ctxt() { - if let Some(info) = span.ctxt().outer().expn_info() { - span = info.call_site; - } else { - break; - } - } + let span = syntax_pos::hygiene::walk_chain(source_info.span, self.mir.span.ctxt()); let scope = self.scope_metadata_for_loc(source_info.scope, span.lo()); // Use span of the outermost expansion site, while keeping the original lexical scope. (scope, span) @@ -179,16 +167,16 @@ enum LocalRef<'tcx, V> { Operand(Option>), } -impl<'tcx, V: CodegenObject> LocalRef<'tcx, V> { - fn new_operand>( - cx: &Cx, +impl<'a, 'tcx, V: CodegenObject> LocalRef<'tcx, V> { + fn new_operand>( + bx: &mut Bx, layout: TyLayout<'tcx>, ) -> LocalRef<'tcx, V> { if layout.is_zst() { // Zero-size temporaries aren't always initialized, which // doesn't matter because they don't contain data, but // we need something in the operand. - LocalRef::Operand(Some(OperandRef::new_zst(cx, layout))) + LocalRef::Operand(Some(OperandRef::new_zst(bx, layout))) } else { LocalRef::Operand(None) } @@ -197,16 +185,18 @@ impl<'tcx, V: CodegenObject> LocalRef<'tcx, V> { /////////////////////////////////////////////////////////////////////////// -pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, llfn: Bx::Value, - mir: &'a Mir<'tcx>, + mir: &'a Body<'tcx>, instance: Instance<'tcx>, sig: ty::FnSig<'tcx>, ) { - let fn_ty = cx.new_fn_type(sig, &[]); + assert!(!instance.substs.needs_infer()); + + let fn_ty = FnType::new(cx, sig, &[]); debug!("fn_ty: {:?}", fn_ty); - let debug_context = + let mut debug_context = cx.create_function_debug_context(instance, sig, llfn, mir); let mut bx = Bx::new_block(cx, llfn, "start"); @@ -228,7 +218,7 @@ pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( }).collect(); // Compute debuginfo scopes from MIR scopes. - let scopes = cx.create_mir_scopes(mir, &debug_context); + let scopes = cx.create_mir_scopes(mir, &mut debug_context); let (landing_pads, funclets) = create_funclets(mir, &mut bx, &cleanup_kinds, &block_bxs); let mut fx = FunctionCx { @@ -246,10 +236,6 @@ pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( scopes, locals: IndexVec::new(), debug_context, - param_substs: { - assert!(!instance.substs.needs_infer()); - instance.substs - }, va_list_ref: None, }; @@ -260,7 +246,7 @@ pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( // FIXME(dlrobertson): This is ugly. Find a better way of getting the `PlaceRef` or // `LocalRef` from `arg_local_refs` let mut va_list_ref = None; - let args = arg_local_refs(&mut bx, &fx, &fx.scopes, &memory_locals, &mut va_list_ref); + let args = arg_local_refs(&mut bx, &fx, &memory_locals, &mut va_list_ref); fx.va_list_ref = va_list_ref; let mut allocate_local = |local| { @@ -276,7 +262,7 @@ pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( if !memory_locals.contains(local) && !dbg { debug!("alloc: {:?} ({}) -> operand", local, name); - return LocalRef::new_operand(bx.cx(), layout); + return LocalRef::new_operand(&mut bx, layout); } debug!("alloc: {:?} ({}) -> place", local, name); @@ -302,7 +288,7 @@ pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( // Temporary or return place if local == mir::RETURN_PLACE && fx.fn_ty.ret.is_indirect() { debug!("alloc: {:?} (return place) -> place", local); - let llretptr = fx.cx.get_param(llfn, 0); + let llretptr = bx.get_param(0); LocalRef::Place(PlaceRef::new_sized(llretptr, layout, layout.align.abi)) } else if memory_locals.contains(local) { debug!("alloc: {:?} -> place", local); @@ -321,7 +307,7 @@ pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( // alloca in advance. Instead we wait until we see the // definition and update the operand there. debug!("alloc: {:?} -> operand", local); - LocalRef::new_operand(bx.cx(), layout) + LocalRef::new_operand(&mut bx, layout) } } }; @@ -341,7 +327,7 @@ pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( // Up until here, IR instructions for this function have explicitly not been annotated with // source code location, so we don't step into call setup code. From here on, source location // emitting should be enabled. - debuginfo::start_emitting_source_locations(&fx.debug_context); + debuginfo::start_emitting_source_locations(&mut fx.debug_context); let rpo = traversal::reverse_postorder(&mir); let mut visited = BitSet::new_empty(mir.basic_blocks().len()); @@ -365,14 +351,15 @@ pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( } } -fn create_funclets<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( - mir: &'a Mir<'tcx>, +fn create_funclets<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + mir: &'a Body<'tcx>, bx: &mut Bx, cleanup_kinds: &IndexVec, - block_bxs: &IndexVec) - -> (IndexVec>, - IndexVec>) -{ + block_bxs: &IndexVec, +) -> ( + IndexVec>, + IndexVec>, +) { block_bxs.iter_enumerated().zip(cleanup_kinds).map(|((bb, &llbb), cleanup_kind)| { match *cleanup_kind { CleanupKind::Funclet if base::wants_msvc_seh(bx.sess()) => {} @@ -434,13 +421,9 @@ fn create_funclets<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( /// Produces, for each argument, a `Value` pointing at the /// argument's value. As arguments are places, these are always /// indirect. -fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, fx: &FunctionCx<'a, 'tcx, Bx>, - scopes: &IndexVec< - mir::SourceScope, - debuginfo::MirDebugScope - >, memory_locals: &BitSet, va_list_ref: &mut Option>, ) -> Vec> { @@ -450,7 +433,7 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( let mut llarg_idx = fx.fn_ty.ret.is_indirect() as usize; // Get the argument scope, if it exists and if we need it. - let arg_scope = scopes[mir::OUTERMOST_SOURCE_SCOPE]; + let arg_scope = fx.scopes[mir::OUTERMOST_SOURCE_SCOPE]; let arg_scope = if bx.sess().opts.debuginfo == DebugInfo::Full { arg_scope.scope_metadata } else { @@ -506,7 +489,7 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( }; bx.declare_local( &fx.debug_context, - arg_decl.name.unwrap_or(keywords::Invalid.name()), + arg_decl.name.unwrap_or(kw::Invalid), arg_ty, scope, variable_access, VariableKind::ArgumentVariable(arg_index + 1), @@ -530,28 +513,22 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( let local = |op| LocalRef::Operand(Some(op)); match arg.mode { PassMode::Ignore(IgnoreMode::Zst) => { - return local(OperandRef::new_zst(bx.cx(), arg.layout)); - } - PassMode::Ignore(IgnoreMode::CVarArgs) => { - let backend_type = bx.cx().immediate_backend_type(arg.layout); - return local(OperandRef { - val: OperandValue::Immediate(bx.cx().const_undef(backend_type)), - layout: arg.layout, - }); + return local(OperandRef::new_zst(bx, arg.layout)); } + PassMode::Ignore(IgnoreMode::CVarArgs) => {} PassMode::Direct(_) => { - let llarg = bx.get_param(bx.llfn(), llarg_idx as c_uint); + let llarg = bx.get_param(llarg_idx); bx.set_value_name(llarg, &name); llarg_idx += 1; return local( OperandRef::from_immediate_or_packed_pair(bx, llarg, arg.layout)); } PassMode::Pair(..) => { - let a = bx.get_param(bx.llfn(), llarg_idx as c_uint); + let a = bx.get_param(llarg_idx); bx.set_value_name(a, &(name.clone() + ".0")); llarg_idx += 1; - let b = bx.get_param(bx.llfn(), llarg_idx as c_uint); + let b = bx.get_param(llarg_idx); bx.set_value_name(b, &(name + ".1")); llarg_idx += 1; @@ -568,16 +545,16 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( // Don't copy an indirect argument to an alloca, the caller // already put it in a temporary alloca and gave it up. // FIXME: lifetimes - let llarg = bx.get_param(bx.llfn(), llarg_idx as c_uint); + let llarg = bx.get_param(llarg_idx); bx.set_value_name(llarg, &name); llarg_idx += 1; PlaceRef::new_sized(llarg, arg.layout, arg.layout.align.abi) } else if arg.is_unsized_indirect() { // As the storage for the indirect argument lives during // the whole function call, we just copy the fat pointer. - let llarg = bx.get_param(bx.llfn(), llarg_idx as c_uint); + let llarg = bx.get_param(llarg_idx); llarg_idx += 1; - let llextra = bx.get_param(bx.llfn(), llarg_idx as c_uint); + let llextra = bx.get_param(llarg_idx); llarg_idx += 1; let indirect_operand = OperandValue::Pair(llarg, llextra); @@ -585,39 +562,29 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( indirect_operand.store(bx, tmp); tmp } else { + let tmp = PlaceRef::alloca(bx, arg.layout, &name); if fx.fn_ty.c_variadic && last_arg_idx.map(|idx| arg_index == idx).unwrap_or(false) { - let va_list_impl = match arg_decl.ty.ty_adt_def() { - Some(adt) => adt.non_enum_variant(), - None => bug!("`va_list` language item improperly constructed") + let va_list_did = match tcx.lang_items().va_list() { + Some(did) => did, + None => bug!("`va_list` lang item required for C-variadic functions"), }; - match tcx.type_of(va_list_impl.fields[0].did).sty { - ty::Ref(_, ty, _) => { - // If the underlying structure the `VaList` contains is a structure, - // we need to allocate it (e.g., X86_64 on Linux). - let tmp = PlaceRef::alloca(bx, arg.layout, &name); - if let ty::Adt(..) = ty.sty { - let layout = bx.layout_of(ty); - // Create an unnamed allocation for the backing structure - // and store it in the the spoofed `VaList`. - let backing = PlaceRef::alloca(bx, layout, ""); - bx.store(backing.llval, tmp.llval, layout.align.abi); - } - // Call `va_start` on the spoofed `VaList`. + match arg_decl.ty.sty { + ty::Adt(def, _) if def.did == va_list_did => { + // Call `va_start` on the spoofed `VaListImpl`. bx.va_start(tmp.llval); *va_list_ref = Some(tmp); - tmp - } - _ => bug!("improperly constructed `va_list` lang item"), + }, + _ => bug!("last argument of variadic function is not a `va_list`") } } else { - let tmp = PlaceRef::alloca(bx, arg.layout, &name); bx.store_fn_arg(arg, &mut llarg_idx, tmp); - tmp } + tmp }; + let upvar_debuginfo = &mir.__upvar_debuginfo_codegen_only_do_not_use; arg_scope.map(|scope| { // Is this a regular argument? - if arg_index > 0 || mir.upvar_decls.is_empty() { + if arg_index > 0 || upvar_debuginfo.is_empty() { // The Rust ABI passes indirect variables using a pointer and a manual copy, so we // need to insert a deref here, but the C ABI uses a pointer and a copy using the // byval attribute, for which LLVM always does the deref itself, @@ -628,7 +595,7 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( bx.declare_local( &fx.debug_context, - arg_decl.name.unwrap_or(keywords::Invalid.name()), + arg_decl.name.unwrap_or(kw::Invalid), arg.layout.ty, scope, variable_access, @@ -655,16 +622,18 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( let (def_id, upvar_substs) = match closure_layout.ty.sty { ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), - _ => bug!("upvar_decls with non-closure arg0 type `{}`", closure_layout.ty) + _ => bug!("upvar debuginfo with non-closure arg0 type `{}`", closure_layout.ty) }; let upvar_tys = upvar_substs.upvar_tys(def_id, tcx); let extra_locals = { - let upvars = mir.upvar_decls + let upvars = upvar_debuginfo .iter() .zip(upvar_tys) .enumerate() - .map(|(i, (decl, ty))| (i, decl.debug_name, decl.by_ref, ty)); + .map(|(i, (upvar, ty))| { + (None, i, upvar.debug_name, upvar.by_ref, ty, scope, DUMMY_SP) + }); let generator_fields = mir.generator_layout.as_ref().map(|generator_layout| { let (def_id, gen_substs) = match closure_layout.ty.sty { @@ -673,23 +642,50 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( }; let state_tys = gen_substs.state_tys(def_id, tcx); - let upvar_count = mir.upvar_decls.len(); - generator_layout.fields - .iter() + generator_layout.variant_fields.iter() .zip(state_tys) .enumerate() - .filter_map(move |(i, (decl, ty))| { - decl.name.map(|name| (i + upvar_count + 1, name, false, ty)) + .flat_map(move |(variant_idx, (fields, tys))| { + let variant_idx = Some(VariantIdx::from(variant_idx)); + fields.iter() + .zip(tys) + .enumerate() + .filter_map(move |(i, (field, ty))| { + let decl = &generator_layout. + __local_debuginfo_codegen_only_do_not_use[*field]; + if let Some(name) = decl.name { + let ty = fx.monomorphize(&ty); + let (var_scope, var_span) = fx.debug_loc(mir::SourceInfo { + span: decl.source_info.span, + scope: decl.visibility_scope, + }); + let var_scope = var_scope.unwrap_or(scope); + Some((variant_idx, i, name, false, ty, var_scope, var_span)) + } else { + None + } + }) }) }).into_iter().flatten(); upvars.chain(generator_fields) }; - for (field, name, by_ref, ty) in extra_locals { - let byte_offset_of_var_in_env = closure_layout.fields.offset(field).bytes(); + for (variant_idx, field, name, by_ref, ty, var_scope, var_span) in extra_locals { + let fields = match variant_idx { + Some(variant_idx) => { + match &closure_layout.variants { + Variants::Multiple { variants, .. } => { + &variants[variant_idx].fields + }, + _ => bug!("variant index on univariant layout"), + } + } + None => &closure_layout.fields, + }; + let byte_offset_of_var_in_env = fields.offset(field).bytes(); - let ops = bx.debuginfo_upvar_decls_ops_sequence(byte_offset_of_var_in_env); + let ops = bx.debuginfo_upvar_ops_sequence(byte_offset_of_var_in_env); // The environment and the capture can each be indirect. let mut ops = if env_ref { &ops[..] } else { &ops[1..] }; @@ -709,10 +705,10 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( &fx.debug_context, name, ty, - scope, + var_scope, variable_access, VariableKind::LocalVariable, - DUMMY_SP + var_span ); } }); diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index 0a6549851f446..4a6752fec3556 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -1,7 +1,7 @@ -use rustc::mir::interpret::{ConstValue, ErrorHandled}; +use rustc::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar}; use rustc::mir; use rustc::ty; -use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; +use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, Size}; use crate::base; use crate::MemFlags; @@ -53,63 +53,71 @@ impl fmt::Debug for OperandRef<'tcx, V> { } } -impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { - pub fn new_zst>( - cx: &Cx, +impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { + pub fn new_zst>( + bx: &mut Bx, layout: TyLayout<'tcx> ) -> OperandRef<'tcx, V> { assert!(layout.is_zst()); OperandRef { - val: OperandValue::Immediate(cx.const_undef(cx.immediate_backend_type(layout))), + val: OperandValue::Immediate(bx.const_undef(bx.immediate_backend_type(layout))), layout } } pub fn from_const>( bx: &mut Bx, - val: ty::Const<'tcx> - ) -> Result { - let layout = bx.cx().layout_of(val.ty); + val: &'tcx ty::Const<'tcx> + ) -> Self { + let layout = bx.layout_of(val.ty); if layout.is_zst() { - return Ok(OperandRef::new_zst(bx.cx(), layout)); + return OperandRef::new_zst(bx, layout); } let val = match val.val { + ConstValue::Unevaluated(..) => bug!("unevaluated constant in `OperandRef::from_const`"), + ConstValue::Param(_) => bug!("encountered a ConstValue::Param in codegen"), + ConstValue::Infer(_) => bug!("encountered a ConstValue::Infer in codegen"), + ConstValue::Placeholder(_) => bug!("encountered a ConstValue::Placeholder in codegen"), ConstValue::Scalar(x) => { let scalar = match layout.abi { layout::Abi::Scalar(ref x) => x, _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) }; - let llval = bx.cx().scalar_to_backend( + let llval = bx.scalar_to_backend( x, scalar, - bx.cx().immediate_backend_type(layout), + bx.immediate_backend_type(layout), ); OperandValue::Immediate(llval) }, - ConstValue::Slice(a, b) => { + ConstValue::Slice { data, start, end } => { let a_scalar = match layout.abi { layout::Abi::ScalarPair(ref a, _) => a, _ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout) }; - let a_llval = bx.cx().scalar_to_backend( + let a = Scalar::from(Pointer::new( + bx.tcx().alloc_map.lock().create_memory_alloc(data), + Size::from_bytes(start as u64), + )).into(); + let a_llval = bx.scalar_to_backend( a, a_scalar, - bx.cx().scalar_pair_element_backend_type(layout, 0, true), + bx.scalar_pair_element_backend_type(layout, 0, true), ); - let b_llval = bx.cx().const_usize(b); + let b_llval = bx.const_usize((end - start) as u64); OperandValue::Pair(a_llval, b_llval) }, - ConstValue::ByRef(ptr, alloc) => { - return Ok(bx.load_operand(bx.cx().from_const_alloc(layout, alloc, ptr.offset))); + ConstValue::ByRef { offset, align, alloc } => { + return bx.load_operand(bx.from_const_alloc(layout, align, alloc, offset)); }, }; - Ok(OperandRef { + OperandRef { val, layout - }) + } } /// Asserts that this operand refers to a scalar and returns @@ -121,7 +129,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { } } - pub fn deref>( + pub fn deref>( self, cx: &Cx ) -> PlaceRef<'tcx, V> { @@ -196,7 +204,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { let mut val = match (self.val, &self.layout.abi) { // If the field is ZST, it has no data. _ if field.is_zst() => { - return OperandRef::new_zst(bx.cx(), field); + return OperandRef::new_zst(bx, field); } // Newtype of a scalar, scalar pair or vector. @@ -258,7 +266,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { } } -impl<'a, 'tcx: 'a, V: CodegenObject> OperandValue { +impl<'a, 'tcx, V: CodegenObject> OperandValue { pub fn store>( self, bx: &mut Bx, @@ -368,7 +376,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandValue { } } -impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn maybe_codegen_consume_direct( &mut self, bx: &mut Bx, @@ -376,45 +384,47 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Option> { debug!("maybe_codegen_consume_direct(place={:?})", place); - // watch out for locals that do not have an - // alloca; they are handled somewhat differently - if let mir::Place::Base(mir::PlaceBase::Local(index)) = *place { - match self.locals[index] { - LocalRef::Operand(Some(o)) => { - return Some(o); - } - LocalRef::Operand(None) => { - bug!("use of {:?} before def", place); - } - LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => { - // use path below - } - } - } + place.iterate(|place_base, place_projection| { + if let mir::PlaceBase::Local(index) = place_base { + match self.locals[*index] { + LocalRef::Operand(Some(mut o)) => { + // Moves out of scalar and scalar pair fields are trivial. + for proj in place_projection { + match proj.elem { + mir::ProjectionElem::Field(ref f, _) => { + o = o.extract_field(bx, f.index()); + } + mir::ProjectionElem::Index(_) | + mir::ProjectionElem::ConstantIndex { .. } => { + // ZSTs don't require any actual memory access. + // FIXME(eddyb) deduplicate this with the identical + // checks in `codegen_consume` and `extract_field`. + let elem = o.layout.field(bx.cx(), 0); + if elem.is_zst() { + o = OperandRef::new_zst(bx, elem); + } else { + return None; + } + } + _ => return None, + } + } - // Moves out of scalar and scalar pair fields are trivial. - if let &mir::Place::Projection(ref proj) = place { - if let Some(o) = self.maybe_codegen_consume_direct(bx, &proj.base) { - match proj.elem { - mir::ProjectionElem::Field(ref f, _) => { - return Some(o.extract_field(bx, f.index())); + Some(o) } - mir::ProjectionElem::Index(_) | - mir::ProjectionElem::ConstantIndex { .. } => { - // ZSTs don't require any actual memory access. - // FIXME(eddyb) deduplicate this with the identical - // checks in `codegen_consume` and `extract_field`. - let elem = o.layout.field(bx.cx(), 0); - if elem.is_zst() { - return Some(OperandRef::new_zst(bx.cx(), elem)); - } + LocalRef::Operand(None) => { + bug!("use of {:?} before def", place); + } + LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => { + // watch out for locals that do not have an + // alloca; they are handled somewhat differently + None } - _ => {} } + } else { + None } - } - - None + }) } pub fn codegen_consume( @@ -429,7 +439,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // ZSTs don't require any actual memory access. if layout.is_zst() { - return OperandRef::new_zst(bx.cx(), layout); + return OperandRef::new_zst(bx, layout); } if let Some(o) = self.maybe_codegen_consume_direct(bx, place) { @@ -457,8 +467,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Operand::Constant(ref constant) => { let ty = self.monomorphize(&constant.ty); - self.eval_mir_constant(bx, constant) - .and_then(|c| OperandRef::from_const(bx, c)) + self.eval_mir_constant(constant) + .map(|c| OperandRef::from_const(bx, c)) .unwrap_or_else(|err| { match err { // errored or at least linted diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 0408ccf039f34..be5d7b09965d4 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -26,7 +26,7 @@ pub struct PlaceRef<'tcx, V> { pub align: Align, } -impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { +impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { pub fn new_sized( llval: V, layout: TyLayout<'tcx>, @@ -80,7 +80,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { Self::alloca(bx, ptr_layout, name) } - pub fn len>( + pub fn len>( &self, cx: &Cx ) -> V { @@ -98,7 +98,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { } -impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { +impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { /// Access a field, at a point when the value's case is known. pub fn project_field>( self, bx: &mut Bx, @@ -120,7 +120,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { bx.struct_gep(self.llval, bx.cx().backend_field_index(self.layout, ix)) }; PlaceRef { - // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. + // HACK(eddyb): have to bitcast pointers until LLVM removes pointee types. llval: bx.pointercast(llval, bx.cx().type_ptr_to(bx.cx().backend_type(field))), llextra: if bx.cx().type_has_metadata(field.ty) { self.llextra @@ -134,7 +134,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { // Simple cases, which don't need DST adjustment: // * no metadata available - just log the case - // * known alignment - sized types, [T], str or a foreign type + // * known alignment - sized types, `[T]`, `str` or a foreign type // * packed struct - there is no alignment padding match field.ty.sty { _ if self.llextra.is_none() => { @@ -156,18 +156,19 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { } // We need to get the pointer manually now. - // We do this by casting to a *i8, then offsetting it by the appropriate amount. + // We do this by casting to a `*i8`, then offsetting it by the appropriate amount. // We do this instead of, say, simply adjusting the pointer from the result of a GEP // because the field may have an arbitrary alignment in the LLVM representation // anyway. // // To demonstrate: - // struct Foo { - // x: u16, - // y: T - // } // - // The type Foo> is represented in LLVM as { u16, { u16, u8 }}, meaning that + // struct Foo { + // x: u16, + // y: T + // } + // + // The type `Foo>` is represented in LLVM as `{ u16, { u16, u8 }}`, meaning that // the `y` field has 16-bit alignment. let meta = self.llextra; @@ -180,9 +181,9 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { // Bump the unaligned offset up to the appropriate alignment using the // following expression: // - // (unaligned offset + (align - 1)) & -align + // (unaligned offset + (align - 1)) & -align - // Calculate offset + // Calculate offset. let align_sub_1 = bx.sub(unsized_align, bx.cx().const_usize(1u64)); let and_lhs = bx.add(unaligned_offset, align_sub_1); let and_rhs = bx.neg(unsized_align); @@ -190,11 +191,11 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { debug!("struct_field_ptr: DST field offset: {:?}", offset); - // Cast and adjust pointer + // Cast and adjust pointer. let byte_ptr = bx.pointercast(self.llval, bx.cx().type_i8p()); let byte_ptr = bx.gep(byte_ptr, &[offset]); - // Finally, cast back to the type expected + // Finally, cast back to the type expected. let ll_fty = bx.cx().backend_type(field); debug!("struct_field_ptr: Field type is {:?}", ll_fty); @@ -216,43 +217,41 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { if self.layout.abi.is_uninhabited() { return bx.cx().const_undef(cast_to); } - match self.layout.variants { + let (discr_scalar, discr_kind, discr_index) = match self.layout.variants { layout::Variants::Single { index } => { - let discr_val = self.layout.ty.ty_adt_def().map_or( - index.as_u32() as u128, - |def| def.discriminant_for_variant(bx.cx().tcx(), index).val); + let discr_val = self.layout.ty.discriminant_for_variant(bx.cx().tcx(), index) + .map_or(index.as_u32() as u128, |discr| discr.val); return bx.cx().const_uint_big(cast_to, discr_val); } - layout::Variants::Tagged { .. } | - layout::Variants::NicheFilling { .. } => {}, - } + layout::Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => { + (discr, discr_kind, discr_index) + } + }; - let discr = self.project_field(bx, 0); + let discr = self.project_field(bx, discr_index); let lldiscr = bx.load_operand(discr).immediate(); - match self.layout.variants { - layout::Variants::Single { .. } => bug!(), - layout::Variants::Tagged { ref tag, .. } => { - let signed = match tag.value { + match *discr_kind { + layout::DiscriminantKind::Tag => { + let signed = match discr_scalar.value { // We use `i1` for bytes that are always `0` or `1`, // e.g., `#[repr(i8)] enum E { A, B }`, but we can't // let LLVM interpret the `i1` as signed, because - // then `i1 1` (i.e., E::B) is effectively `i8 -1`. - layout::Int(_, signed) => !tag.is_bool() && signed, + // then `i1 1` (i.e., `E::B`) is effectively `i8 -1`. + layout::Int(_, signed) => !discr_scalar.is_bool() && signed, _ => false }; bx.intcast(lldiscr, cast_to, signed) } - layout::Variants::NicheFilling { + layout::DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start, - .. } => { let niche_llty = bx.cx().immediate_backend_type(discr.layout); if niche_variants.start() == niche_variants.end() { - // FIXME(eddyb) Check the actual primitive type here. + // FIXME(eddyb): check the actual primitive type here. let niche_llval = if niche_start == 0 { - // HACK(eddyb) Using `c_null` as it works on all types. + // HACK(eddyb): using `c_null` as it works on all types. bx.cx().const_null(niche_llty) } else { bx.cx().const_uint_big(niche_llty, niche_start) @@ -291,40 +290,46 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { layout::Variants::Single { index } => { assert_eq!(index, variant_index); } - layout::Variants::Tagged { .. } => { - let ptr = self.project_field(bx, 0); - let to = self.layout.ty.ty_adt_def().unwrap() - .discriminant_for_variant(bx.tcx(), variant_index) - .val; + layout::Variants::Multiple { + discr_kind: layout::DiscriminantKind::Tag, + discr_index, + .. + } => { + let ptr = self.project_field(bx, discr_index); + let to = + self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val; bx.store( bx.cx().const_uint_big(bx.cx().backend_type(ptr.layout), to), ptr.llval, ptr.align); } - layout::Variants::NicheFilling { - dataful_variant, - ref niche_variants, - niche_start, + layout::Variants::Multiple { + discr_kind: layout::DiscriminantKind::Niche { + dataful_variant, + ref niche_variants, + niche_start, + }, + discr_index, .. } => { if variant_index != dataful_variant { if bx.cx().sess().target.target.arch == "arm" || bx.cx().sess().target.target.arch == "aarch64" { - // Issue #34427: As workaround for LLVM bug on ARM, + // FIXME(#34427): as workaround for LLVM bug on ARM, // use memset of 0 before assigning niche value. let fill_byte = bx.cx().const_u8(0); let size = bx.cx().const_usize(self.layout.size.bytes()); bx.memset(self.llval, fill_byte, size, self.align, MemFlags::empty()); } - let niche = self.project_field(bx, 0); + let niche = self.project_field(bx, discr_index); let niche_llty = bx.cx().immediate_backend_type(niche.layout); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); let niche_value = (niche_value as u128) .wrapping_add(niche_start); - // FIXME(eddyb) Check the actual primitive type here. + // FIXME(eddyb): check the actual primitive type here. let niche_llval = if niche_value == 0 { - // HACK(eddyb) Using `c_null` as it works on all types. + // HACK(eddyb): using `c_null` as it works on all types. bx.cx().const_null(niche_llty) } else { bx.cx().const_uint_big(niche_llty, niche_value) @@ -381,7 +386,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { } } -impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn codegen_place( &mut self, bx: &mut Bx, @@ -392,41 +397,43 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cx = self.cx; let tcx = self.cx.tcx(); - if let mir::Place::Base(mir::PlaceBase::Local(index)) = *place { - match self.locals[index] { - LocalRef::Place(place) => { - return place; - } - LocalRef::UnsizedPlace(place) => { - return bx.load_operand(place).deref(cx); - } - LocalRef::Operand(..) => { - bug!("using operand local {:?} as place", place); + let result = match *place { + mir::Place::Base(mir::PlaceBase::Local(index)) => { + match self.locals[index] { + LocalRef::Place(place) => { + return place; + } + LocalRef::UnsizedPlace(place) => { + return bx.load_operand(place).deref(cx); + } + LocalRef::Operand(..) => { + bug!("using operand local {:?} as place", place); + } } } - } - - let result = match *place { - mir::Place::Base(mir::PlaceBase::Local(_)) => bug!(), // handled above - mir::Place::Base(mir::PlaceBase::Promoted(box (index, ty))) => { + mir::Place::Base( + mir::PlaceBase::Static( + box mir::Static { ty, kind: mir::StaticKind::Promoted(promoted) } + ) + ) => { let param_env = ty::ParamEnv::reveal_all(); let cid = mir::interpret::GlobalId { instance: self.instance, - promoted: Some(index), + promoted: Some(promoted), }; let layout = cx.layout_of(self.monomorphize(&ty)); match bx.tcx().const_eval(param_env.and(cid)) { Ok(val) => match val.val { - mir::interpret::ConstValue::ByRef(ptr, alloc) => { - bx.cx().from_const_alloc(layout, alloc, ptr.offset) + mir::interpret::ConstValue::ByRef { offset, align, alloc } => { + bx.cx().from_const_alloc(layout, align, alloc, offset) } _ => bug!("promoteds should have an allocation: {:?}", val), }, Err(_) => { - // this is unreachable as long as runtime + // This is unreachable as long as runtime // and compile-time agree on values - // With floats that won't always be true - // so we generate an abort + // With floats that won't always be true, + // so we generate an abort. bx.abort(); let llval = bx.cx().const_undef( bx.cx().type_ptr_to(bx.cx().backend_type(layout)) @@ -435,11 +442,16 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } - mir::Place::Base(mir::PlaceBase::Static(box mir::Static { def_id, ty })) => { + mir::Place::Base( + mir::PlaceBase::Static( + box mir::Static { ty, kind: mir::StaticKind::Static(def_id) } + ) + ) => { // NB: The layout of a static may be unsized as is the case when working // with a static that is an extern_type. let layout = cx.layout_of(self.monomorphize(&ty)); - PlaceRef::new_thin_place(bx, bx.get_static(def_id), layout, layout.align.abi) + let static_ = bx.get_static(def_id); + PlaceRef::new_thin_place(bx, static_, layout, layout.align.abi) }, mir::Place::Projection(box mir::Projection { ref base, @@ -458,7 +470,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::ProjectionElem::Index(index) => { let index = &mir::Operand::Copy( - mir::Place::Base(mir::PlaceBase::Local(index)) + mir::Place::from(index) ); let index = self.codegen_operand(bx, index); let llindex = index.immediate(); @@ -481,8 +493,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::ProjectionElem::Subslice { from, to } => { let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(from as u64)); - let projected_ty = PlaceTy::Ty { ty: cg_base.layout.ty } - .projection_ty(tcx, &projection.elem).to_ty(tcx); + let projected_ty = PlaceTy::from_ty(cg_base.layout.ty) + .projection_ty(tcx, &projection.elem).ty; subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty)); if subslice.layout.is_unsized() { @@ -491,7 +503,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } // Cast the place pointer type to the new - // array or slice type (*[%_; new_len]). + // array or slice type (`*[%_; new_len]`). subslice.llval = bx.pointercast(subslice.llval, bx.cx().type_ptr_to(bx.cx().backend_type(subslice.layout))); @@ -510,6 +522,6 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn monomorphized_place_ty(&self, place: &mir::Place<'tcx>) -> Ty<'tcx> { let tcx = self.cx.tcx(); let place_ty = place.ty(self.mir, tcx); - self.monomorphize(&place_ty.to_ty(tcx)) + self.monomorphize(&place_ty.ty) } } diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index b0c667a965daa..4a1971e3e2ee0 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -1,16 +1,16 @@ -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, adjustment::{PointerCast}, Instance}; use rustc::ty::cast::{CastTy, IntTy}; use rustc::ty::layout::{self, LayoutOf, HasTyCtxt}; use rustc::mir; use rustc::middle::lang_items::ExchangeMallocFnLangItem; use rustc_apfloat::{ieee, Float, Status, Round}; use std::{u128, i128}; +use syntax::symbol::sym; use crate::base; use crate::MemFlags; use crate::callee; use crate::common::{self, RealPredicate, IntPredicate}; -use rustc_mir::monomorphize; use crate::traits::*; @@ -18,7 +18,7 @@ use super::{FunctionCx, LocalRef}; use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; -impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn codegen_rvalue( &mut self, mut bx: Bx, @@ -37,7 +37,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx } - mir::Rvalue::Cast(mir::CastKind::Unsize, ref source, _) => { + mir::Rvalue::Cast(mir::CastKind::Pointer(PointerCast::Unsize), ref source, _) => { // The destination necessarily contains a fat pointer, so if // it's a scalar pair, it's a fat pointer or newtype thereof. if bx.cx().is_backend_scalar_pair(dest.layout) { @@ -87,11 +87,11 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if dest.layout.is_zst() { return bx; } - let zero = bx.cx().const_usize(0); - let start = dest.project_index(&mut bx, zero).llval; if let OperandValue::Immediate(v) = cg_elem.val { - let size = bx.cx().const_usize(dest.layout.size.bytes()); + let zero = bx.const_usize(0); + let start = dest.project_index(&mut bx, zero).llval; + let size = bx.const_usize(dest.layout.size.bytes()); // Use llvm.memset.p0i8.* to initialize all zero arrays if bx.cx().is_const_integral(v) && bx.cx().const_to_uint(v) == 0 { @@ -108,28 +108,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - let count = bx.cx().const_usize(count); - let end = dest.project_index(&mut bx, count).llval; - - let mut header_bx = bx.build_sibling_block("repeat_loop_header"); - let mut body_bx = bx.build_sibling_block("repeat_loop_body"); - let next_bx = bx.build_sibling_block("repeat_loop_next"); - - bx.br(header_bx.llbb()); - let current = header_bx.phi(bx.cx().val_ty(start), &[start], &[bx.llbb()]); - - let keep_going = header_bx.icmp(IntPredicate::IntNE, current, end); - header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb()); - - let align = dest.align.restrict_for_offset(dest.layout.field(bx.cx(), 0).size); - cg_elem.val.store(&mut body_bx, - PlaceRef::new_sized(current, cg_elem.layout, align)); - - let next = body_bx.inbounds_gep(current, &[bx.cx().const_usize(1)]); - body_bx.br(header_bx.llbb()); - header_bx.add_incoming_to_phi(current, next, body_bx.llbb()); - - next_bx + bx.write_operand_repeatedly(cg_elem, count, dest) } mir::Rvalue::Aggregate(ref kind, ref operands) => { @@ -199,12 +178,11 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cast = bx.cx().layout_of(self.monomorphize(&mir_cast_ty)); let val = match *kind { - mir::CastKind::ReifyFnPointer => { + mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => { match operand.layout.ty.sty { ty::FnDef(def_id, substs) => { - if bx.cx().tcx().has_attr(def_id, "rustc_args_required_const") { - bug!("reifying a fn ptr that requires \ - const arguments"); + if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) { + bug!("reifying a fn ptr that requires const arguments"); } OperandValue::Immediate( callee::resolve_and_get_fn(bx.cx(), def_id, substs)) @@ -214,10 +192,10 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } - mir::CastKind::ClosureFnPointer => { + mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)) => { match operand.layout.ty.sty { ty::Closure(def_id, substs) => { - let instance = monomorphize::resolve_closure( + let instance = Instance::resolve_closure( bx.cx().tcx(), def_id, substs, ty::ClosureKind::FnOnce); OperandValue::Immediate(bx.cx().get_fn(instance)) } @@ -226,11 +204,11 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } - mir::CastKind::UnsafeFnPointer => { + mir::CastKind::Pointer(PointerCast::UnsafeFnPointer) => { // this is a no-op at the LLVM level operand.val } - mir::CastKind::Unsize => { + mir::CastKind::Pointer(PointerCast::Unsize) => { assert!(bx.cx().is_backend_scalar_pair(cast)); match operand.val { OperandValue::Pair(lldata, llextra) => { @@ -257,7 +235,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } - mir::CastKind::Misc if bx.cx().is_backend_scalar_pair(operand.layout) => { + mir::CastKind::Pointer(PointerCast::MutToConstPointer) + | mir::CastKind::Misc if bx.cx().is_backend_scalar_pair(operand.layout) => { if let OperandValue::Pair(data_ptr, meta) = operand.val { if bx.cx().is_backend_scalar_pair(cast) { let data_cast = bx.pointercast(data_ptr, @@ -274,7 +253,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("Unexpected non-Pair operand") } } - mir::CastKind::Misc => { + mir::CastKind::Pointer(PointerCast::MutToConstPointer) + | mir::CastKind::Misc => { assert!(bx.cx().is_backend_immediate(cast)); let ll_t_out = bx.cx().immediate_backend_type(cast); if operand.layout.abi.is_uninhabited() { @@ -290,19 +270,17 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ll_t_in = bx.cx().immediate_backend_type(operand.layout); match operand.layout.variants { layout::Variants::Single { index } => { - if let Some(def) = operand.layout.ty.ty_adt_def() { - let discr_val = def - .discriminant_for_variant(bx.cx().tcx(), index) - .val; - let discr = bx.cx().const_uint_big(ll_t_out, discr_val); + if let Some(discr) = + operand.layout.ty.discriminant_for_variant(bx.tcx(), index) + { + let discr_val = bx.cx().const_uint_big(ll_t_out, discr.val); return (bx, OperandRef { - val: OperandValue::Immediate(discr), + val: OperandValue::Immediate(discr_val), layout: cast, }); } } - layout::Variants::Tagged { .. } | - layout::Variants::NicheFilling { .. } => {}, + layout::Variants::Multiple { .. } => {}, } let llval = operand.immediate(); @@ -391,7 +369,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (bx, OperandRef { val, layout: self.cx.layout_of(self.cx.tcx().mk_ref( - self.cx.tcx().types.re_erased, + self.cx.tcx().lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() } )), }) @@ -451,7 +429,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::UnaryOp(op, ref operand) => { let operand = self.codegen_operand(&mut bx, operand); let lloperand = operand.immediate(); - let is_float = operand.layout.ty.is_fp(); + let is_float = operand.layout.ty.is_floating_point(); let llval = match op { mir::UnOp::Not => bx.not(lloperand), mir::UnOp::Neg => if is_float { @@ -521,8 +499,11 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // According to `rvalue_creates_operand`, only ZST // aggregate rvalues are allowed to be operands. let ty = rvalue.ty(self.mir, self.cx.tcx()); - (bx, OperandRef::new_zst(self.cx, - self.cx.layout_of(self.monomorphize(&ty)))) + let operand = OperandRef::new_zst( + &mut bx, + self.cx.layout_of(self.monomorphize(&ty)), + ); + (bx, operand) } } } @@ -555,7 +536,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { rhs: Bx::Value, input_ty: Ty<'tcx>, ) -> Bx::Value { - let is_float = input_ty.is_fp(); + let is_float = input_ty.is_floating_point(); let is_signed = input_ty.is_signed(); let is_unit = input_ty.is_unit(); match op { @@ -706,7 +687,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } -impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool { match *rvalue { mir::Rvalue::Ref(..) | @@ -731,7 +712,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } -fn cast_int_to_float<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +fn cast_int_to_float<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, signed: bool, x: Bx::Value, @@ -748,7 +729,6 @@ fn cast_int_to_float<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( // All inputs greater or equal to (f32::MAX + 0.5 ULP) are rounded to infinity, // and for everything else LLVM's uitofp works just fine. use rustc_apfloat::ieee::Single; - use rustc_apfloat::Float; const MAX_F32_PLUS_HALF_ULP: u128 = ((1 << (Single::PRECISION + 1)) - 1) << (Single::MAX_EXP - Single::PRECISION as i16); let max = bx.cx().const_uint_big(int_ty, MAX_F32_PLUS_HALF_ULP); @@ -766,7 +746,7 @@ fn cast_int_to_float<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( } } -fn cast_float_to_int<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( +fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, signed: bool, x: Bx::Value, diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index 97729e8aeb35f..750b2f5b1a50f 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -6,7 +6,7 @@ use super::LocalRef; use super::OperandValue; use crate::traits::*; -impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn codegen_statement( &mut self, mut bx: Bx, @@ -68,13 +68,13 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } bx } - mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => { - let outputs = outputs.iter().map(|output| { + mir::StatementKind::InlineAsm(ref asm) => { + let outputs = asm.outputs.iter().map(|output| { self.codegen_place(&mut bx, output) }).collect(); - let input_vals = inputs.iter() - .fold(Vec::with_capacity(inputs.len()), |mut acc, (span, input)| { + let input_vals = asm.inputs.iter() + .fold(Vec::with_capacity(asm.inputs.len()), |mut acc, (span, input)| { let op = self.codegen_operand(&mut bx, input); if let OperandValue::Immediate(_) = op.val { acc.push(op.immediate()); @@ -85,8 +85,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { acc }); - if input_vals.len() == inputs.len() { - let res = bx.codegen_inline_asm(asm, outputs, input_vals); + if input_vals.len() == asm.inputs.len() { + let res = bx.codegen_inline_asm(&asm.asm, outputs, input_vals); if !res { span_err!(bx.sess(), statement.source_info.span, E0668, "malformed inline assembly"); diff --git a/src/librustc_codegen_ssa/mono_item.rs b/src/librustc_codegen_ssa/mono_item.rs index bfb6a9153809a..4446f1a3a5ce2 100644 --- a/src/librustc_codegen_ssa/mono_item.rs +++ b/src/librustc_codegen_ssa/mono_item.rs @@ -1,38 +1,35 @@ use rustc::hir; -use rustc::hir::def::Def; use rustc::mir::mono::{Linkage, Visibility}; use rustc::ty::layout::HasTyCtxt; -use std::fmt; use crate::base; use crate::traits::*; -pub use rustc::mir::mono::MonoItem; +use rustc::mir::mono::MonoItem; -pub use rustc_mir::monomorphize::item::MonoItemExt as BaseMonoItemExt; +pub trait MonoItemExt<'a, 'tcx> { + fn define>(&self, cx: &'a Bx::CodegenCx); + fn predefine>( + &self, + cx: &'a Bx::CodegenCx, + linkage: Linkage, + visibility: Visibility + ); + fn to_raw_string(&self) -> String; +} -pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { +impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { fn define>(&self, cx: &'a Bx::CodegenCx) { debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}", self.to_string(cx.tcx(), true), self.to_raw_string(), cx.codegen_unit().name()); - match *self.as_mono_item() { + match *self { MonoItem::Static(def_id) => { - let tcx = cx.tcx(); - let is_mutable = match tcx.describe_def(def_id) { - Some(Def::Static(_, is_mutable)) => is_mutable, - Some(other) => { - bug!("Expected Def::Static, found {:?}", other) - } - None => { - bug!("Expected Def::Static for {:?}, found nothing", def_id) - } - }; - cx.codegen_static(def_id, is_mutable); + cx.codegen_static(def_id, cx.tcx().is_mutable_static(def_id)); } - MonoItem::GlobalAsm(node_id) => { - let item = cx.tcx().hir().expect_item(node_id); + MonoItem::GlobalAsm(hir_id) => { + let item = cx.tcx().hir().expect_item(hir_id); if let hir::ItemKind::GlobalAsm(ref ga) = item.node { cx.codegen_global_asm(ga); } else { @@ -65,7 +62,7 @@ pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { debug!("symbol {}", &symbol_name); - match *self.as_mono_item() { + match *self { MonoItem::Static(def_id) => { cx.predefine_static(def_id, linkage, visibility, &symbol_name); } @@ -82,7 +79,7 @@ pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { } fn to_raw_string(&self) -> String { - match *self.as_mono_item() { + match *self { MonoItem::Fn(instance) => { format!("Fn({:?}, {})", instance.def, @@ -97,5 +94,3 @@ pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { } } } - -impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {} diff --git a/src/librustc_codegen_ssa/traits/abi.rs b/src/librustc_codegen_ssa/traits/abi.rs index 8f7fa199b057a..509255c37be70 100644 --- a/src/librustc_codegen_ssa/traits/abi.rs +++ b/src/librustc_codegen_ssa/traits/abi.rs @@ -1,13 +1,8 @@ use super::BackendTypes; -use rustc::ty::{FnSig, Instance, Ty}; +use rustc::ty::{Ty}; use rustc_target::abi::call::FnType; -pub trait AbiMethods<'tcx> { - fn new_fn_type(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>; - fn new_vtable(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>; - fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>>; -} - pub trait AbiBuilderMethods<'tcx>: BackendTypes { fn apply_attrs_callsite(&mut self, ty: &FnType<'tcx, Ty<'tcx>>, callsite: Self::Value); + fn get_param(&self, index: usize) -> Self::Value; } diff --git a/src/librustc_codegen_ssa/traits/asm.rs b/src/librustc_codegen_ssa/traits/asm.rs index a95bf3af5bf27..fd3c868bbc507 100644 --- a/src/librustc_codegen_ssa/traits/asm.rs +++ b/src/librustc_codegen_ssa/traits/asm.rs @@ -12,6 +12,6 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes { ) -> bool; } -pub trait AsmMethods<'tcx> { +pub trait AsmMethods { fn codegen_global_asm(&self, ga: &GlobalAsm); } diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/src/librustc_codegen_ssa/traits/backend.rs index 00eae9098e74f..414871be6116e 100644 --- a/src/librustc_codegen_ssa/traits/backend.rs +++ b/src/librustc_codegen_ssa/traits/backend.rs @@ -5,7 +5,6 @@ use super::write::WriteBackendMethods; use super::CodegenObject; use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::EncodedMetadata; -use rustc::mir::mono::Stats; use rustc::session::{Session, config}; use rustc::ty::TyCtxt; use rustc_codegen_utils::codegen_backend::CodegenBackend; @@ -32,23 +31,20 @@ impl<'tcx, T> Backend<'tcx> for T where } pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send { - fn new_metadata(&self, sess: TyCtxt<'_, '_, '_>, mod_name: &str) -> Self::Module; - fn write_metadata<'b, 'gcx>( + fn new_metadata(&self, sess: TyCtxt<'_>, mod_name: &str) -> Self::Module; + fn write_compressed_metadata<'tcx>( &self, - tcx: TyCtxt<'b, 'gcx, 'gcx>, - metadata: &mut Self::Module, - ) -> EncodedMetadata; - fn codegen_allocator( + tcx: TyCtxt<'tcx>, + metadata: &EncodedMetadata, + llvm_module: &mut Self::Module, + ); + fn codegen_allocator<'tcx>( &self, - tcx: TyCtxt<'_, '_, '_>, + tcx: TyCtxt<'tcx>, mods: &mut Self::Module, - kind: AllocatorKind + kind: AllocatorKind, ); - fn compile_codegen_unit<'a, 'tcx: 'a>( - &self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cgu_name: InternedString, - ) -> Stats; + fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: InternedString); // If find_features is true this won't access `sess.crate_types` by assuming // that `is_pie_binary` is false. When we discover LLVM target features // `sess.crate_types` is uninitialized so we cannot access it. diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs index 5099107a39303..1c80e614db8d5 100644 --- a/src/librustc_codegen_ssa/traits/builder.rs +++ b/src/librustc_codegen_ssa/traits/builder.rs @@ -10,12 +10,10 @@ use crate::mir::operand::OperandRef; use crate::mir::place::PlaceRef; use crate::MemFlags; use rustc::ty::Ty; -use rustc::ty::layout::{Align, Size}; -use std::ffi::CStr; - -use std::borrow::Cow; +use rustc::ty::layout::{Align, Size, HasParamEnv}; +use rustc_target::spec::{HasTargetSpec}; use std::ops::Range; -use syntax::ast::AsmDialect; +use std::iter::TrustedLen; #[derive(Copy, Clone)] pub enum OverflowOp { @@ -24,26 +22,25 @@ pub enum OverflowOp { Mul, } -pub trait BuilderMethods<'a, 'tcx: 'a>: +pub trait BuilderMethods<'a, 'tcx>: HasCodegen<'tcx> + DebugInfoBuilderMethods<'tcx> + ArgTypeMethods<'tcx> + AbiBuilderMethods<'tcx> + IntrinsicCallMethods<'tcx> + AsmBuilderMethods<'tcx> - + StaticBuilderMethods<'tcx> + + StaticBuilderMethods + + HasParamEnv<'tcx> + + HasTargetSpec + { fn new_block<'b>(cx: &'a Self::CodegenCx, llfn: Self::Value, name: &'b str) -> Self; fn with_cx(cx: &'a Self::CodegenCx) -> Self; fn build_sibling_block<'b>(&self, name: &'b str) -> Self; fn cx(&self) -> &Self::CodegenCx; - fn llfn(&self) -> Self::Value; fn llbb(&self) -> Self::BasicBlock; - fn count_insn(&self, category: &str); - fn set_value_name(&mut self, value: Self::Value, name: &str); fn position_at_end(&mut self, llbb: Self::BasicBlock); - fn position_at_start(&mut self, llbb: Self::BasicBlock); fn ret_void(&mut self); fn ret(&mut self, v: Self::Value); fn br(&mut self, dest: Self::BasicBlock); @@ -57,8 +54,8 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: &mut self, v: Self::Value, else_llbb: Self::BasicBlock, - num_cases: usize, - ) -> Self::Value; + cases: impl ExactSizeIterator + TrustedLen, + ); fn invoke( &mut self, llfn: Self::Value, @@ -68,6 +65,7 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: funclet: Option<&Self::Funclet>, ) -> Self::Value; fn unreachable(&mut self); + fn add(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fadd_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; @@ -90,6 +88,12 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: fn shl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn lshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn ashr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + fn unchecked_sadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + fn unchecked_uadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + fn unchecked_ssub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + fn unchecked_usub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + fn unchecked_smul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + fn unchecked_umul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn and(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn or(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn xor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; @@ -121,6 +125,14 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: fn load_operand(&mut self, place: PlaceRef<'tcx, Self::Value>) -> OperandRef<'tcx, Self::Value>; + /// Called for Rvalue::Repeat when the elem is neither a ZST nor optimizable using memset. + fn write_operand_repeatedly( + self, + elem: OperandRef<'tcx, Self::Value>, + count: u64, + dest: PlaceRef<'tcx, Self::Value>, + ) -> Self; + fn range_metadata(&mut self, load: Self::Value, range: Range); fn nonnull_metadata(&mut self, load: Self::Value); @@ -161,24 +173,6 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: fn icmp(&mut self, op: IntPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fcmp(&mut self, op: RealPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn empty_phi(&mut self, ty: Self::Type) -> Self::Value; - fn phi( - &mut self, - ty: Self::Type, - vals: &[Self::Value], - bbs: &[Self::BasicBlock], - ) -> Self::Value; - fn inline_asm_call( - &mut self, - asm: &CStr, - cons: &CStr, - inputs: &[Self::Value], - output: Self::Type, - volatile: bool, - alignstack: bool, - dia: AsmDialect, - ) -> Option; - fn memcpy( &mut self, dst: Self::Value, @@ -206,8 +200,6 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: flags: MemFlags, ); - fn minnum(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn maxnum(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn select( &mut self, cond: Self::Value, @@ -217,32 +209,7 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: fn va_arg(&mut self, list: Self::Value, ty: Self::Type) -> Self::Value; fn extract_element(&mut self, vec: Self::Value, idx: Self::Value) -> Self::Value; - fn insert_element( - &mut self, - vec: Self::Value, - elt: Self::Value, - idx: Self::Value, - ) -> Self::Value; - fn shuffle_vector( - &mut self, - v1: Self::Value, - v2: Self::Value, - mask: Self::Value, - ) -> Self::Value; fn vector_splat(&mut self, num_elts: usize, elt: Self::Value) -> Self::Value; - fn vector_reduce_fadd_fast(&mut self, acc: Self::Value, src: Self::Value) -> Self::Value; - fn vector_reduce_fmul_fast(&mut self, acc: Self::Value, src: Self::Value) -> Self::Value; - fn vector_reduce_add(&mut self, src: Self::Value) -> Self::Value; - fn vector_reduce_mul(&mut self, src: Self::Value) -> Self::Value; - fn vector_reduce_and(&mut self, src: Self::Value) -> Self::Value; - fn vector_reduce_or(&mut self, src: Self::Value) -> Self::Value; - fn vector_reduce_xor(&mut self, src: Self::Value) -> Self::Value; - fn vector_reduce_fmin(&mut self, src: Self::Value) -> Self::Value; - fn vector_reduce_fmax(&mut self, src: Self::Value) -> Self::Value; - fn vector_reduce_fmin_fast(&mut self, src: Self::Value) -> Self::Value; - fn vector_reduce_fmax_fast(&mut self, src: Self::Value) -> Self::Value; - fn vector_reduce_min(&mut self, src: Self::Value, is_signed: bool) -> Self::Value; - fn vector_reduce_max(&mut self, src: Self::Value, is_signed: bool) -> Self::Value; fn extract_value(&mut self, agg_val: Self::Value, idx: u64) -> Self::Value; fn insert_value(&mut self, agg_val: Self::Value, elt: Self::Value, idx: u64) -> Self::Value; @@ -252,7 +219,6 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: pers_fn: Self::Value, num_clauses: usize, ) -> Self::Value; - fn add_clause(&mut self, landing_pad: Self::Value, clause: Self::Value); fn set_cleanup(&mut self, landing_pad: Self::Value); fn resume(&mut self, exn: Self::Value) -> Self::Value; fn cleanup_pad(&mut self, parent: Option, args: &[Self::Value]) -> Self::Funclet; @@ -262,7 +228,6 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: unwind: Option, ) -> Self::Value; fn catch_pad(&mut self, parent: Self::Value, args: &[Self::Value]) -> Self::Funclet; - fn catch_ret(&mut self, funclet: &Self::Funclet, unwind: Self::BasicBlock) -> Self::Value; fn catch_switch( &mut self, parent: Option, @@ -289,23 +254,8 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: order: AtomicOrdering, ) -> Self::Value; fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope); - fn add_case(&mut self, s: Self::Value, on_val: Self::Value, dest: Self::BasicBlock); - fn add_incoming_to_phi(&mut self, phi: Self::Value, val: Self::Value, bb: Self::BasicBlock); fn set_invariant_load(&mut self, load: Self::Value); - /// Returns the ptr value that should be used for storing `val`. - fn check_store(&mut self, val: Self::Value, ptr: Self::Value) -> Self::Value; - - /// Returns the args that should be used for a call to `llfn`. - fn check_call<'b>( - &mut self, - typ: &str, - llfn: Self::Value, - args: &'b [Self::Value], - ) -> Cow<'b, [Self::Value]> - where - [Self::Value]: ToOwned; - /// Called for `StorageLive` fn lifetime_start(&mut self, ptr: Self::Value, size: Size); diff --git a/src/librustc_codegen_ssa/traits/consts.rs b/src/librustc_codegen_ssa/traits/consts.rs index 319f4b4e5e4b5..46286b5329e43 100644 --- a/src/librustc_codegen_ssa/traits/consts.rs +++ b/src/librustc_codegen_ssa/traits/consts.rs @@ -3,7 +3,6 @@ use crate::mir::place::PlaceRef; use rustc::mir::interpret::Allocation; use rustc::mir::interpret::Scalar; use rustc::ty::layout; -use syntax::symbol::LocalInternedString; pub trait ConstMethods<'tcx>: BackendTypes { // Constant constructors @@ -19,24 +18,12 @@ pub trait ConstMethods<'tcx>: BackendTypes { fn const_usize(&self, i: u64) -> Self::Value; fn const_u8(&self, i: u8) -> Self::Value; - // This is a 'c-like' raw string, which differs from - // our boxed-and-length-annotated strings. - fn const_cstr(&self, s: LocalInternedString, null_terminated: bool) -> Self::Value; - - fn const_str_slice(&self, s: LocalInternedString) -> Self::Value; - fn const_fat_ptr(&self, ptr: Self::Value, meta: Self::Value) -> Self::Value; fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value; - fn const_array(&self, ty: Self::Type, elts: &[Self::Value]) -> Self::Value; - fn const_vector(&self, elts: &[Self::Value]) -> Self::Value; - fn const_bytes(&self, bytes: &[u8]) -> Self::Value; - fn const_get_elt(&self, v: Self::Value, idx: u64) -> Self::Value; - fn const_get_real(&self, v: Self::Value) -> Option<(f64, bool)>; fn const_to_uint(&self, v: Self::Value) -> u64; fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option; fn is_const_integral(&self, v: Self::Value) -> bool; - fn is_const_real(&self, v: Self::Value) -> bool; fn scalar_to_backend( &self, @@ -47,6 +34,7 @@ pub trait ConstMethods<'tcx>: BackendTypes { fn from_const_alloc( &self, layout: layout::TyLayout<'tcx>, + align: layout::Align, alloc: &Allocation, offset: layout::Size, ) -> PlaceRef<'tcx, Self::Value>; diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/src/librustc_codegen_ssa/traits/debuginfo.rs index 135188e98c71c..be2fa7279aa7c 100644 --- a/src/librustc_codegen_ssa/traits/debuginfo.rs +++ b/src/librustc_codegen_ssa/traits/debuginfo.rs @@ -2,9 +2,8 @@ use super::BackendTypes; use crate::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess, VariableKind}; use rustc::hir::def_id::CrateNum; use rustc::mir; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, Instance}; use rustc_data_structures::indexed_vec::IndexVec; -use rustc_mir::monomorphize::Instance; use syntax::ast::Name; use syntax_pos::{SourceFile, Span}; @@ -22,13 +21,13 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes { instance: Instance<'tcx>, sig: ty::FnSig<'tcx>, llfn: Self::Value, - mir: &mir::Mir<'_>, + mir: &mir::Body<'_>, ) -> FunctionDebugContext; fn create_mir_scopes( &self, - mir: &mir::Mir<'_>, - debug_context: &FunctionDebugContext, + mir: &mir::Body<'_>, + debug_context: &mut FunctionDebugContext, ) -> IndexVec>; fn extend_scope_to_file( &self, @@ -37,7 +36,7 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes { defining_crate: CrateNum, ) -> Self::DIScope; fn debuginfo_finalize(&self); - fn debuginfo_upvar_decls_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4]; + fn debuginfo_upvar_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4]; } pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes { @@ -53,9 +52,10 @@ pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes { ); fn set_source_location( &mut self, - debug_context: &FunctionDebugContext, + debug_context: &mut FunctionDebugContext, scope: Option, span: Span, ); fn insert_reference_to_gdb_debug_scripts_section_global(&mut self); + fn set_value_name(&mut self, value: Self::Value, name: &str); } diff --git a/src/librustc_codegen_ssa/traits/declare.rs b/src/librustc_codegen_ssa/traits/declare.rs index 6a400a7d7a45d..624a982b619ee 100644 --- a/src/librustc_codegen_ssa/traits/declare.rs +++ b/src/librustc_codegen_ssa/traits/declare.rs @@ -1,8 +1,7 @@ use super::BackendTypes; use rustc::hir::def_id::DefId; use rustc::mir::mono::{Linkage, Visibility}; -use rustc::ty; -use rustc_mir::monomorphize::Instance; +use rustc::ty::{self, Instance}; pub trait DeclareMethods<'tcx>: BackendTypes { /// Declare a global value. diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/src/librustc_codegen_ssa/traits/intrinsic.rs index cd5278989778f..ede30a0bed756 100644 --- a/src/librustc_codegen_ssa/traits/intrinsic.rs +++ b/src/librustc_codegen_ssa/traits/intrinsic.rs @@ -20,10 +20,10 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { fn abort(&mut self); fn assume(&mut self, val: Self::Value); fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; - /// Trait method used to inject `va_start` on the "spoofed" `VaList` in + /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in /// Rust defined C-variadic functions. fn va_start(&mut self, val: Self::Value) -> Self::Value; - /// Trait method used to inject `va_end` on the "spoofed" `VaList` before + /// Trait method used to inject `va_end` on the "spoofed" `VaListImpl` before /// Rust defined C-variadic functions return. fn va_end(&mut self, val: Self::Value) -> Self::Value; } diff --git a/src/librustc_codegen_ssa/traits/misc.rs b/src/librustc_codegen_ssa/traits/misc.rs index b23155563665d..46c88a6113ebe 100644 --- a/src/librustc_codegen_ssa/traits/misc.rs +++ b/src/librustc_codegen_ssa/traits/misc.rs @@ -1,10 +1,8 @@ use super::BackendTypes; -use libc::c_uint; -use rustc::mir::mono::Stats; +use rustc::mir::mono::CodegenUnit; use rustc::session::Session; use rustc::ty::{self, Instance, Ty}; use rustc::util::nodemap::FxHashMap; -use rustc_mir::monomorphize::partitioning::CodegenUnit; use std::cell::RefCell; use std::sync::Arc; @@ -15,12 +13,9 @@ pub trait MiscMethods<'tcx>: BackendTypes { fn check_overflow(&self) -> bool; fn instances(&self) -> &RefCell, Self::Value>>; fn get_fn(&self, instance: Instance<'tcx>) -> Self::Value; - fn get_param(&self, llfn: Self::Value, index: c_uint) -> Self::Value; fn eh_personality(&self) -> Self::Value; fn eh_unwind_resume(&self) -> Self::Value; fn sess(&self) -> &Session; - fn stats(&self) -> &RefCell; - fn consume_stats(self) -> RefCell; fn codegen_unit(&self) -> &Arc>; fn used_statics(&self) -> &RefCell>; fn set_frame_pointer_elimination(&self, llfn: Self::Value); diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/src/librustc_codegen_ssa/traits/mod.rs index 8fe8b7ecd4709..efe4a25570104 100644 --- a/src/librustc_codegen_ssa/traits/mod.rs +++ b/src/librustc_codegen_ssa/traits/mod.rs @@ -27,7 +27,7 @@ mod statics; mod type_; mod write; -pub use self::abi::{AbiBuilderMethods, AbiMethods}; +pub use self::abi::{AbiBuilderMethods}; pub use self::asm::{AsmBuilderMethods, AsmMethods}; pub use self::backend::{Backend, BackendTypes, ExtraBackendMethods}; pub use self::builder::{BuilderMethods, OverflowOp}; @@ -41,6 +41,9 @@ pub use self::type_::{ ArgTypeMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods, }; pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; +use rustc::ty::layout::{HasParamEnv, HasTyCtxt}; +use rustc_target::spec::{HasTargetSpec}; + use std::fmt; @@ -54,10 +57,12 @@ pub trait CodegenMethods<'tcx>: + ConstMethods<'tcx> + StaticMethods + DebugInfoMethods<'tcx> - + AbiMethods<'tcx> + DeclareMethods<'tcx> - + AsmMethods<'tcx> + + AsmMethods + PreDefineMethods<'tcx> + + HasParamEnv<'tcx> + + HasTyCtxt<'tcx> + + HasTargetSpec { } @@ -68,10 +73,12 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where + ConstMethods<'tcx> + StaticMethods + DebugInfoMethods<'tcx> - + AbiMethods<'tcx> + DeclareMethods<'tcx> - + AsmMethods<'tcx> + + AsmMethods + PreDefineMethods<'tcx> + + HasParamEnv<'tcx> + + HasTyCtxt<'tcx> + + HasTargetSpec { } diff --git a/src/librustc_codegen_ssa/traits/statics.rs b/src/librustc_codegen_ssa/traits/statics.rs index c4e7fe703c219..6983311d797dc 100644 --- a/src/librustc_codegen_ssa/traits/statics.rs +++ b/src/librustc_codegen_ssa/traits/statics.rs @@ -1,4 +1,5 @@ use super::BackendTypes; +use syntax_pos::symbol::LocalInternedString; use rustc::hir::def_id::DefId; use rustc::ty::layout::Align; @@ -7,6 +8,14 @@ pub trait StaticMethods: BackendTypes { fn codegen_static(&self, def_id: DefId, is_mutable: bool); } -pub trait StaticBuilderMethods<'tcx>: BackendTypes { - fn get_static(&self, def_id: DefId) -> Self::Value; +pub trait StaticBuilderMethods: BackendTypes { + fn get_static(&mut self, def_id: DefId) -> Self::Value; + fn static_panic_msg( + &mut self, + msg: Option, + filename: LocalInternedString, + line: Self::Value, + col: Self::Value, + kind: &str, + ) -> Self::Value; } diff --git a/src/librustc_codegen_ssa/traits/type_.rs b/src/librustc_codegen_ssa/traits/type_.rs index 7c5e615f22452..aa38d8d51848d 100644 --- a/src/librustc_codegen_ssa/traits/type_.rs +++ b/src/librustc_codegen_ssa/traits/type_.rs @@ -1,40 +1,29 @@ use super::misc::MiscMethods; use super::Backend; use super::HasCodegen; -use crate::common::{self, TypeKind}; +use crate::common::TypeKind; use crate::mir::place::PlaceRef; -use rustc::ty::layout::{self, Align, Size, TyLayout}; use rustc::ty::{self, Ty}; -use rustc::util::nodemap::FxHashMap; +use rustc::ty::layout::{self, TyLayout}; use rustc_target::abi::call::{ArgType, CastTarget, FnType, Reg}; -use std::cell::RefCell; -use syntax::ast; +use syntax_pos::DUMMY_SP; // This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use // `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves. pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { - fn type_void(&self) -> Self::Type; - fn type_metadata(&self) -> Self::Type; fn type_i1(&self) -> Self::Type; fn type_i8(&self) -> Self::Type; fn type_i16(&self) -> Self::Type; fn type_i32(&self) -> Self::Type; fn type_i64(&self) -> Self::Type; fn type_i128(&self) -> Self::Type; - - // Creates an integer type with the given number of bits, e.g., i24 - fn type_ix(&self, num_bits: u64) -> Self::Type; fn type_isize(&self) -> Self::Type; fn type_f32(&self) -> Self::Type; fn type_f64(&self) -> Self::Type; - fn type_x86_mmx(&self) -> Self::Type; fn type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type; - fn type_variadic_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type; fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type; - fn type_array(&self, ty: Self::Type, len: u64) -> Self::Type; - fn type_vector(&self, ty: Self::Type, len: u64) -> Self::Type; fn type_kind(&self, ty: Self::Type) -> TypeKind; fn type_ptr_to(&self, ty: Self::Type) -> Self::Type; fn element_type(&self, ty: Self::Type) -> Self::Type; @@ -42,21 +31,15 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { /// Returns the number of elements in `self` if it is a LLVM vector type. fn vector_length(&self, ty: Self::Type) -> usize; - fn func_params_types(&self, ty: Self::Type) -> Vec; fn float_width(&self, ty: Self::Type) -> usize; /// Retrieves the bit width of the integer type `self`. fn int_width(&self, ty: Self::Type) -> u64; fn val_ty(&self, v: Self::Value) -> Self::Type; - fn scalar_lltypes(&self) -> &RefCell, Self::Type>>; } pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { - fn type_bool(&self) -> Self::Type { - self.type_i8() - } - fn type_i8p(&self) -> Self::Type { self.type_ptr_to(self.type_i8()) } @@ -70,35 +53,6 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { } } - fn type_int_from_ty(&self, t: ast::IntTy) -> Self::Type { - match t { - ast::IntTy::Isize => self.type_isize(), - ast::IntTy::I8 => self.type_i8(), - ast::IntTy::I16 => self.type_i16(), - ast::IntTy::I32 => self.type_i32(), - ast::IntTy::I64 => self.type_i64(), - ast::IntTy::I128 => self.type_i128(), - } - } - - fn type_uint_from_ty(&self, t: ast::UintTy) -> Self::Type { - match t { - ast::UintTy::Usize => self.type_isize(), - ast::UintTy::U8 => self.type_i8(), - ast::UintTy::U16 => self.type_i16(), - ast::UintTy::U32 => self.type_i32(), - ast::UintTy::U64 => self.type_i64(), - ast::UintTy::U128 => self.type_i128(), - } - } - - fn type_float_from_ty(&self, t: ast::FloatTy) -> Self::Type { - match t { - ast::FloatTy::F32 => self.type_f32(), - ast::FloatTy::F64 => self.type_f64(), - } - } - fn type_from_integer(&self, i: layout::Integer) -> Self::Type { use rustc::ty::layout::Integer::*; match i { @@ -110,36 +64,19 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { } } - fn type_pointee_for_align(&self, align: Align) -> Self::Type { - // FIXME(eddyb) We could find a better approximation if ity.align < align. - let ity = layout::Integer::approximate_align(self, align); - self.type_from_integer(ity) - } - - /// Return a LLVM type that has at most the required alignment, - /// and exactly the required size, as a best-effort padding array. - fn type_padding_filler(&self, size: Size, align: Align) -> Self::Type { - let unit = layout::Integer::approximate_align(self, align); - let size = size.bytes(); - let unit_size = unit.size().bytes(); - assert_eq!(size % unit_size, 0); - self.type_array(self.type_from_integer(unit), size / unit_size) - } - fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { - common::type_needs_drop(self.tcx(), ty) + ty.needs_drop(self.tcx(), ty::ParamEnv::reveal_all()) } fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - common::type_is_sized(self.tcx(), ty) + ty.is_sized(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all()) } fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - common::type_is_freeze(self.tcx(), ty) + ty.is_freeze(self.tcx(), ty::ParamEnv::reveal_all(), DUMMY_SP) } fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { - use syntax_pos::DUMMY_SP; if ty.is_sized(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all()) { return false; } @@ -148,7 +85,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { match tail.sty { ty::Foreign(..) => false, ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, - _ => bug!("unexpected unsized tail: {:?}", tail.sty), + _ => bug!("unexpected unsized tail: {:?}", tail), } } } @@ -158,14 +95,13 @@ impl DerivedTypeMethods<'tcx> for T where Self: BaseTypeMethods<'tcx> + MiscM pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { fn backend_type(&self, layout: TyLayout<'tcx>) -> Self::Type; fn cast_backend_type(&self, ty: &CastTarget) -> Self::Type; - fn fn_backend_type(&self, ty: &FnType<'tcx, Ty<'tcx>>) -> Self::Type; fn fn_ptr_backend_type(&self, ty: &FnType<'tcx, Ty<'tcx>>) -> Self::Type; fn reg_backend_type(&self, ty: &Reg) -> Self::Type; fn immediate_backend_type(&self, layout: TyLayout<'tcx>) -> Self::Type; fn is_backend_immediate(&self, layout: TyLayout<'tcx>) -> bool; fn is_backend_scalar_pair(&self, layout: TyLayout<'tcx>) -> bool; fn backend_field_index(&self, layout: TyLayout<'tcx>, index: usize) -> u64; - fn scalar_pair_element_backend_type<'a>( + fn scalar_pair_element_backend_type( &self, layout: TyLayout<'tcx>, index: usize, diff --git a/src/librustc_codegen_ssa/traits/write.rs b/src/librustc_codegen_ssa/traits/write.rs index d8fb7c608c8af..23bb7179557b9 100644 --- a/src/librustc_codegen_ssa/traits/write.rs +++ b/src/librustc_codegen_ssa/traits/write.rs @@ -3,7 +3,6 @@ use crate::back::write::{CodegenContext, ModuleConfig, FatLTOInput}; use crate::{CompiledModule, ModuleCodegen}; use rustc::dep_graph::WorkProduct; -use rustc::util::time_graph::Timeline; use rustc_errors::{FatalError, Handler}; pub trait WriteBackendMethods: 'static + Sized + Clone { @@ -20,7 +19,6 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - timeline: &mut Timeline, ) -> Result, FatalError>; /// Performs thin LTO by performing necessary global analysis and returning two /// lists, one of the modules that need optimization and another for modules that @@ -29,7 +27,6 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { cgcx: &CodegenContext, modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - timeline: &mut Timeline, ) -> Result<(Vec>, Vec), FatalError>; fn print_pass_timings(&self); unsafe fn optimize( @@ -37,19 +34,16 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { diag_handler: &Handler, module: &ModuleCodegen, config: &ModuleConfig, - timeline: &mut Timeline, ) -> Result<(), FatalError>; unsafe fn optimize_thin( cgcx: &CodegenContext, thin: &mut ThinModule, - timeline: &mut Timeline, ) -> Result, FatalError>; unsafe fn codegen( cgcx: &CodegenContext, diag_handler: &Handler, module: ModuleCodegen, config: &ModuleConfig, - timeline: &mut Timeline, ) -> Result; fn prepare_thin( module: ModuleCodegen diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index 5f241eb20fb55..b218d18a06ba7 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -13,6 +13,8 @@ test = false [dependencies] flate2 = "1.0" log = "0.4" +punycode = "0.4.0" +rustc-demangle = "0.1.15" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } @@ -20,5 +22,3 @@ rustc = { path = "../librustc" } rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_metadata = { path = "../librustc_metadata" } -rustc_mir = { path = "../librustc_mir" } -rustc_incremental = { path = "../librustc_incremental" } diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs index 28d7d18422841..7a7a50a25faf0 100644 --- a/src/librustc_codegen_utils/codegen_backend.rs +++ b/src/librustc_codegen_utils/codegen_backend.rs @@ -6,30 +6,19 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] - #![feature(box_syntax)] use std::any::Any; -use std::io::Write; -use std::fs; -use std::path::Path; -use std::sync::{mpsc, Arc}; - -use rustc_data_structures::owning_ref::OwningRef; -use flate2::Compression; -use flate2::write::DeflateEncoder; +use std::sync::mpsc; use syntax::symbol::Symbol; -use rustc::hir::def_id::LOCAL_CRATE; -use rustc::session::{Session, CompileIncomplete}; -use rustc::session::config::{CrateType, OutputFilenames, PrintRequest}; +use rustc::session::Session; +use rustc::util::common::ErrorReported; +use rustc::session::config::{OutputFilenames, PrintRequest}; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; -use rustc::middle::cstore::EncodedMetadata; -use rustc::middle::cstore::MetadataLoader; +use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; use rustc::dep_graph::DepGraph; -use rustc_target::spec::Target; -use crate::link::out_filename; pub use rustc_data_structures::sync::MetadataRef; @@ -44,10 +33,12 @@ pub trait CodegenBackend { fn metadata_loader(&self) -> Box; fn provide(&self, _providers: &mut Providers<'_>); fn provide_extern(&self, _providers: &mut Providers<'_>); - fn codegen_crate<'a, 'tcx>( + fn codegen_crate<'tcx>( &self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - rx: mpsc::Receiver> + tcx: TyCtxt<'tcx>, + metadata: EncodedMetadata, + need_metadata_module: bool, + rx: mpsc::Receiver>, ) -> Box; /// This is called on the returned `Box` from `codegen_backend` @@ -61,136 +52,5 @@ pub trait CodegenBackend { sess: &Session, dep_graph: &DepGraph, outputs: &OutputFilenames, - ) -> Result<(), CompileIncomplete>; -} - -pub struct NoLlvmMetadataLoader; - -impl MetadataLoader for NoLlvmMetadataLoader { - fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result { - let buf = fs::read(filename).map_err(|e| format!("metadata file open err: {:?}", e))?; - let buf: OwningRef, [u8]> = OwningRef::new(buf); - Ok(rustc_erase_owner!(buf.map_owner_box())) - } - - fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result { - self.get_rlib_metadata(target, filename) - } -} - -pub struct MetadataOnlyCodegenBackend(()); -pub struct OngoingCodegen { - metadata: EncodedMetadata, - metadata_version: Vec, - crate_name: Symbol, -} - -impl MetadataOnlyCodegenBackend { - pub fn boxed() -> Box { - box MetadataOnlyCodegenBackend(()) - } -} - -impl CodegenBackend for MetadataOnlyCodegenBackend { - fn init(&self, sess: &Session) { - for cty in sess.opts.crate_types.iter() { - match *cty { - CrateType::Rlib | CrateType::Dylib | CrateType::Executable => {}, - _ => { - sess.diagnostic().warn( - &format!("LLVM unsupported, so output type {} is not supported", cty) - ); - }, - } - } - } - - fn metadata_loader(&self) -> Box { - box NoLlvmMetadataLoader - } - - fn provide(&self, providers: &mut Providers<'_>) { - crate::symbol_names::provide(providers); - - providers.target_features_whitelist = |_tcx, _cnum| { - Default::default() // Just a dummy - }; - providers.is_reachable_non_generic = |_tcx, _defid| true; - providers.exported_symbols = |_tcx, _crate| Arc::new(Vec::new()); - } - fn provide_extern(&self, providers: &mut Providers<'_>) { - providers.is_reachable_non_generic = |_tcx, _defid| true; - } - - fn codegen_crate<'a, 'tcx>( - &self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _rx: mpsc::Receiver> - ) -> Box { - use rustc_mir::monomorphize::item::MonoItem; - - crate::check_for_rustc_errors_attr(tcx); - crate::symbol_names_test::report_symbol_names(tcx); - rustc_incremental::assert_dep_graph(tcx); - rustc_incremental::assert_module_sources::assert_module_sources(tcx); - // FIXME: Fix this - // rustc::middle::dependency_format::calculate(tcx); - let _ = tcx.link_args(LOCAL_CRATE); - let _ = tcx.native_libraries(LOCAL_CRATE); - let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); - for (mono_item, _) in cgus.iter().flat_map(|cgu| cgu.items().iter()) { - if let MonoItem::Fn(inst) = mono_item { - let def_id = inst.def_id(); - if def_id.is_local() { - let _ = tcx.codegen_fn_attrs(def_id); - } - } - } - tcx.sess.abort_if_errors(); - - let metadata = tcx.encode_metadata(); - - box OngoingCodegen { - metadata, - metadata_version: tcx.metadata_encoding_version().to_vec(), - crate_name: tcx.crate_name(LOCAL_CRATE), - } - } - - fn join_codegen_and_link( - &self, - ongoing_codegen: Box, - sess: &Session, - _dep_graph: &DepGraph, - outputs: &OutputFilenames, - ) -> Result<(), CompileIncomplete> { - let ongoing_codegen = ongoing_codegen.downcast::() - .expect("Expected MetadataOnlyCodegenBackend's OngoingCodegen, found Box"); - for &crate_type in sess.opts.crate_types.iter() { - if crate_type != CrateType::Rlib && - crate_type != CrateType::Dylib { - continue; - } - let output_name = - out_filename(sess, crate_type, &outputs, &ongoing_codegen.crate_name.as_str()); - let mut compressed = ongoing_codegen.metadata_version.clone(); - let metadata = if crate_type == CrateType::Dylib { - DeflateEncoder::new(&mut compressed, Compression::fast()) - .write_all(&ongoing_codegen.metadata.raw_data) - .unwrap(); - &compressed - } else { - &ongoing_codegen.metadata.raw_data - }; - fs::write(&output_name, metadata).unwrap(); - } - - sess.abort_if_errors(); - if !sess.opts.crate_types.contains(&CrateType::Rlib) - && !sess.opts.crate_types.contains(&CrateType::Dylib) - { - sess.fatal("Executables are not supported by the metadata-only backend."); - } - Ok(()) - } + ) -> Result<(), ErrorReported>; } diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs index 2b70141894be9..942c2d13fac87 100644 --- a/src/librustc_codegen_utils/lib.rs +++ b/src/librustc_codegen_utils/lib.rs @@ -4,9 +4,11 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(arbitrary_self_types)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(custom_attribute)] +#![feature(core_intrinsics)] +#![feature(never_type)] #![feature(nll)] #![allow(unused_attributes)] #![feature(rustc_diagnostic_macros)] @@ -15,13 +17,15 @@ #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] #[macro_use] extern crate rustc; -#[macro_use] extern crate rustc_data_structures; use rustc::ty::TyCtxt; use rustc::hir::def_id::LOCAL_CRATE; +use syntax::symbol::sym; pub mod link; pub mod codegen_backend; @@ -32,9 +36,9 @@ pub mod symbol_names_test; /// error in codegen. This is used to write compile-fail tests /// that actually test that compilation succeeds without /// reporting an error. -pub fn check_for_rustc_errors_attr(tcx: TyCtxt<'_, '_, '_>) { +pub fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) { if let Some((def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - if tcx.has_attr(def_id, "rustc_error") { + if tcx.has_attr(def_id, sym::rustc_error) { tcx.sess.span_fatal(tcx.def_span(def_id), "compilation successful"); } } diff --git a/src/librustc_codegen_utils/link.rs b/src/librustc_codegen_utils/link.rs index f3a1b219f8a84..a2ac64fa7e0c6 100644 --- a/src/librustc_codegen_utils/link.rs +++ b/src/librustc_codegen_utils/link.rs @@ -2,6 +2,7 @@ use rustc::session::config::{self, OutputFilenames, Input, OutputType}; use rustc::session::Session; use std::path::{Path, PathBuf}; use syntax::{ast, attr}; +use syntax::symbol::sym; use syntax_pos::Span; pub fn out_filename(sess: &Session, @@ -49,13 +50,13 @@ pub fn find_crate_name(sess: Option<&Session>, // as used. After doing this, however, we still prioritize a crate name from // the command line over one found in the #[crate_name] attribute. If we // find both we ensure that they're the same later on as well. - let attr_crate_name = attr::find_by_name(attrs, "crate_name") + let attr_crate_name = attr::find_by_name(attrs, sym::crate_name) .and_then(|at| at.value_str().map(|s| (at, s))); if let Some(sess) = sess { if let Some(ref s) = sess.opts.crate_name { if let Some((attr, name)) = attr_crate_name { - if name != &**s { + if name.as_str() != *s { let msg = format!("--crate-name and #[crate_name] are \ required to match, but `{}` != `{}`", s, name); diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index f529cf30a62ea..7ccd024769f75 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -87,176 +87,54 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::def_id::LOCAL_CRATE; use rustc::hir::Node; use rustc::hir::CodegenFnAttrFlags; -use rustc::hir::map::definitions::DefPathData; -use rustc::ich::NodeIdHashingMode; -use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; +use rustc::session::config::SymbolManglingVersion; use rustc::ty::query::Providers; -use rustc::ty::subst::SubstsRef; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::util::common::record_time; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_mir::monomorphize::item::{InstantiationMode, MonoItem, MonoItemExt}; -use rustc_mir::monomorphize::Instance; +use rustc::ty::{self, TyCtxt, Instance}; +use rustc::mir::mono::{MonoItem, InstantiationMode}; -use syntax_pos::symbol::Symbol; +use syntax_pos::symbol::InternedString; use log::debug; -use std::fmt::Write; -use std::mem::discriminant; +mod legacy; +mod v0; pub fn provide(providers: &mut Providers<'_>) { *providers = Providers { - def_symbol_name, - symbol_name, + symbol_name: |tcx, instance| ty::SymbolName { + name: symbol_name(tcx, instance), + }, ..*providers }; } -fn get_symbol_hash<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - - // the DefId of the item this name is for - def_id: DefId, - - // instance this name will be for - instance: Instance<'tcx>, - - // type of the item, without any generic - // parameters substituted; this is - // included in the hash as a kind of - // safeguard. - item_type: Ty<'tcx>, - - // values for generic type parameters, - // if any. - substs: SubstsRef<'tcx>, -) -> u64 { - debug!( - "get_symbol_hash(def_id={:?}, parameters={:?})", - def_id, substs - ); - - let mut hasher = StableHasher::::new(); - let mut hcx = tcx.create_stable_hashing_context(); - - record_time(&tcx.sess.perf_stats.symbol_hash_time, || { - // the main symbol name is not necessarily unique; hash in the - // compiler's internal def-path, guaranteeing each symbol has a - // truly unique path - tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher); - - // Include the main item-type. Note that, in this case, the - // assertions about `needs_subst` may not hold, but this item-type - // ought to be the same for every reference anyway. - assert!(!item_type.has_erasable_regions()); - hcx.while_hashing_spans(false, |hcx| { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - item_type.hash_stable(hcx, &mut hasher); - }); - }); - - // If this is a function, we hash the signature as well. - // This is not *strictly* needed, but it may help in some - // situations, see the `run-make/a-b-a-linker-guard` test. - if let ty::FnDef(..) = item_type.sty { - item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher); - } - - // also include any type parameters (for generic items) - assert!(!substs.has_erasable_regions()); - assert!(!substs.needs_subst()); - substs.hash_stable(&mut hcx, &mut hasher); - - let is_generic = substs.types().next().is_some(); - let avoid_cross_crate_conflicts = - // If this is an instance of a generic function, we also hash in - // the ID of the instantiating crate. This avoids symbol conflicts - // in case the same instances is emitted in two crates of the same - // project. - is_generic || - - // If we're dealing with an instance of a function that's inlined from - // another crate but we're marking it as globally shared to our - // compliation (aka we're not making an internal copy in each of our - // codegen units) then this symbol may become an exported (but hidden - // visibility) symbol. This means that multiple crates may do the same - // and we want to be sure to avoid any symbol conflicts here. - match MonoItem::Fn(instance).instantiation_mode(tcx) { - InstantiationMode::GloballyShared { may_conflict: true } => true, - _ => false, - }; - - if avoid_cross_crate_conflicts { - let instantiating_crate = if is_generic { - if !def_id.is_local() && tcx.sess.opts.share_generics() { - // If we are re-using a monomorphization from another crate, - // we have to compute the symbol hash accordingly. - let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id); - - upstream_monomorphizations - .and_then(|monos| monos.get(&substs).cloned()) - .unwrap_or(LOCAL_CRATE) - } else { - LOCAL_CRATE - } - } else { - LOCAL_CRATE - }; - - (&tcx.original_crate_name(instantiating_crate).as_str()[..]) - .hash_stable(&mut hcx, &mut hasher); - (&tcx.crate_disambiguator(instantiating_crate)).hash_stable(&mut hcx, &mut hasher); - } - - // We want to avoid accidental collision between different types of instances. - // Especially, VtableShim may overlap with its original instance without this. - discriminant(&instance.def).hash_stable(&mut hcx, &mut hasher); - }); - - // 64 bits should be enough to avoid collisions. - hasher.finish() -} - -fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::SymbolName { - let mut buffer = SymbolPathBuffer::new(tcx); - item_path::with_forced_absolute_paths(|| { - tcx.push_item_path(&mut buffer, def_id, false); - }); - buffer.into_interned() -} - -fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) -> ty::SymbolName { - ty::SymbolName { - name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_interned_str(), - } -} - -fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) -> String { +fn symbol_name(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> InternedString { let def_id = instance.def_id(); let substs = instance.substs; debug!("symbol_name(def_id={:?}, substs={:?})", def_id, substs); - let node_id = tcx.hir().as_local_node_id(def_id); + let hir_id = tcx.hir().as_local_hir_id(def_id); if def_id.is_local() { if tcx.plugin_registrar_fn(LOCAL_CRATE) == Some(def_id) { let disambiguator = tcx.sess.local_crate_disambiguator(); - return tcx.sess.generate_plugin_registrar_symbol(disambiguator); + return + InternedString::intern(&tcx.sess.generate_plugin_registrar_symbol(disambiguator)); } if tcx.proc_macro_decls_static(LOCAL_CRATE) == Some(def_id) { let disambiguator = tcx.sess.local_crate_disambiguator(); - return tcx.sess.generate_proc_macro_decls_symbol(disambiguator); + return + InternedString::intern(&tcx.sess.generate_proc_macro_decls_symbol(disambiguator)); } } // FIXME(eddyb) Precompute a custom symbol name based on attributes. - let is_foreign = if let Some(id) = node_id { + let is_foreign = if let Some(id) = hir_id { match tcx.hir().get(id) { Node::ForeignItem(_) => true, _ => false, @@ -268,200 +146,81 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance let attrs = tcx.codegen_fn_attrs(def_id); if is_foreign { if let Some(name) = attrs.link_name { - return name.to_string(); + return name.as_interned_str(); } // Don't mangle foreign items. - return tcx.item_name(def_id).to_string(); + return tcx.item_name(def_id).as_interned_str(); } if let Some(name) = &attrs.export_name { // Use provided name - return name.to_string(); + return name.as_interned_str(); } if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { // Don't mangle - return tcx.item_name(def_id).to_string(); + return tcx.item_name(def_id).as_interned_str(); } - // We want to compute the "type" of this item. Unfortunately, some - // kinds of items (e.g., closures) don't have an entry in the - // item-type array. So walk back up the find the closest parent - // that DOES have an entry. - let mut ty_def_id = def_id; - let instance_ty; - loop { - let key = tcx.def_key(ty_def_id); - match key.disambiguated_data.data { - DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { - instance_ty = tcx.type_of(ty_def_id); - break; - } - _ => { - // if we're making a symbol for something, there ought - // to be a value or type-def or something in there - // *somewhere* - ty_def_id.index = key.parent.unwrap_or_else(|| { - bug!( - "finding type for {:?}, encountered def-id {:?} with no \ - parent", - def_id, - ty_def_id - ); - }); - } - } - } - - // Erase regions because they may not be deterministic when hashed - // and should not matter anyhow. - let instance_ty = tcx.erase_regions(&instance_ty); - - let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs); - - let mut buf = SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id), tcx); - - if instance.is_vtable_shim() { - buf.push("{{vtable-shim}}"); - } - buf.finish(hash) -} - -// Follow C++ namespace-mangling style, see -// http://en.wikipedia.org/wiki/Name_mangling for more info. -// -// It turns out that on macOS you can actually have arbitrary symbols in -// function names (at least when given to LLVM), but this is not possible -// when using unix's linker. Perhaps one day when we just use a linker from LLVM -// we won't need to do this name mangling. The problem with name mangling is -// that it seriously limits the available characters. For example we can't -// have things like &T in symbol names when one would theoretically -// want them for things like impls of traits on that type. -// -// To be able to work on all platforms and get *some* reasonable output, we -// use C++ name-mangling. -#[derive(Debug)] -struct SymbolPathBuffer { - result: String, - temp_buf: String, - strict_naming: bool, -} - -impl SymbolPathBuffer { - fn new(tcx: TyCtxt<'_, '_, '_>) -> Self { - let mut result = SymbolPathBuffer { - result: String::with_capacity(64), - temp_buf: String::with_capacity(16), - strict_naming: tcx.has_strict_asm_symbol_naming(), - }; - result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested - result - } - - fn from_interned(symbol: ty::SymbolName, tcx: TyCtxt<'_, '_, '_>) -> Self { - let mut result = SymbolPathBuffer { - result: String::with_capacity(64), - temp_buf: String::with_capacity(16), - strict_naming: tcx.has_strict_asm_symbol_naming(), + let is_generic = substs.non_erasable_generics().next().is_some(); + let avoid_cross_crate_conflicts = + // If this is an instance of a generic function, we also hash in + // the ID of the instantiating crate. This avoids symbol conflicts + // in case the same instances is emitted in two crates of the same + // project. + is_generic || + + // If we're dealing with an instance of a function that's inlined from + // another crate but we're marking it as globally shared to our + // compliation (aka we're not making an internal copy in each of our + // codegen units) then this symbol may become an exported (but hidden + // visibility) symbol. This means that multiple crates may do the same + // and we want to be sure to avoid any symbol conflicts here. + match MonoItem::Fn(instance).instantiation_mode(tcx) { + InstantiationMode::GloballyShared { may_conflict: true } => true, + _ => false, }; - result.result.push_str(&symbol.as_str()); - result - } - - fn into_interned(self) -> ty::SymbolName { - ty::SymbolName { - name: Symbol::intern(&self.result).as_interned_str(), - } - } - - fn finish(mut self, hash: u64) -> String { - // E = end name-sequence - let _ = write!(self.result, "17h{:016x}E", hash); - self.result - } - - // Name sanitation. LLVM will happily accept identifiers with weird names, but - // gas doesn't! - // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $ - // NVPTX assembly has more strict naming rules than gas, so additionally, dots - // are replaced with '$' there. - fn sanitize_and_append(&mut self, s: &str) { - self.temp_buf.clear(); - - for c in s.chars() { - match c { - // Escape these with $ sequences - '@' => self.temp_buf.push_str("$SP$"), - '*' => self.temp_buf.push_str("$BP$"), - '&' => self.temp_buf.push_str("$RF$"), - '<' => self.temp_buf.push_str("$LT$"), - '>' => self.temp_buf.push_str("$GT$"), - '(' => self.temp_buf.push_str("$LP$"), - ')' => self.temp_buf.push_str("$RP$"), - ',' => self.temp_buf.push_str("$C$"), - - '-' | ':' => if self.strict_naming { - // NVPTX doesn't support these characters in symbol names. - self.temp_buf.push('$') - } - else { - // '.' doesn't occur in types and functions, so reuse it - // for ':' and '-' - self.temp_buf.push('.') - }, - - '.' => if self.strict_naming { - self.temp_buf.push('$') - } - else { - self.temp_buf.push('.') - }, - // These are legal symbols - 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '$' => self.temp_buf.push(c), + let instantiating_crate = if avoid_cross_crate_conflicts { + Some(if is_generic { + if !def_id.is_local() && tcx.sess.opts.share_generics() { + // If we are re-using a monomorphization from another crate, + // we have to compute the symbol hash accordingly. + let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id); - _ => { - self.temp_buf.push('$'); - for c in c.escape_unicode().skip(1) { - match c { - '{' => {} - '}' => self.temp_buf.push('$'), - c => self.temp_buf.push(c), - } - } - } + upstream_monomorphizations + .and_then(|monos| monos.get(&substs).cloned()) + .unwrap_or(LOCAL_CRATE) + } else { + LOCAL_CRATE } - } - - let need_underscore = { - // Underscore-qualify anything that didn't start as an ident. - !self.temp_buf.is_empty() - && self.temp_buf.as_bytes()[0] != '_' as u8 - && !(self.temp_buf.as_bytes()[0] as char).is_xid_start() - }; - - let _ = write!( - self.result, - "{}", - self.temp_buf.len() + (need_underscore as usize) - ); - - if need_underscore { - self.result.push('_'); - } + } else { + LOCAL_CRATE + }) + } else { + None + }; - self.result.push_str(&self.temp_buf); - } -} + // Pick the crate responsible for the symbol mangling version, which has to: + // 1. be stable for each instance, whether it's being defined or imported + // 2. obey each crate's own `-Z symbol-mangling-version`, as much as possible + // We solve these as follows: + // 1. because symbol names depend on both `def_id` and `instantiating_crate`, + // both their `CrateNum`s are stable for any given instance, so we can pick + // either and have a stable choice of symbol mangling version + // 2. we favor `instantiating_crate` where possible (i.e. when `Some`) + let mangling_version_crate = instantiating_crate.unwrap_or(def_id.krate); + let mangling_version = if mangling_version_crate == LOCAL_CRATE { + tcx.sess.opts.debugging_opts.symbol_mangling_version + } else { + tcx.symbol_mangling_version(mangling_version_crate) + }; -impl ItemPathBuffer for SymbolPathBuffer { - fn root_mode(&self) -> &RootMode { - const ABSOLUTE: &RootMode = &RootMode::Absolute; - ABSOLUTE - } + let mangled = match mangling_version { + SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate), + SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate), + }; - fn push(&mut self, text: &str) { - self.sanitize_and_append(text); - } + InternedString::intern(&mangled) } diff --git a/src/librustc_codegen_utils/symbol_names/legacy.rs b/src/librustc_codegen_utils/symbol_names/legacy.rs new file mode 100644 index 0000000000000..22b7e0a2fb0c9 --- /dev/null +++ b/src/librustc_codegen_utils/symbol_names/legacy.rs @@ -0,0 +1,460 @@ +use rustc::hir::def_id::CrateNum; +use rustc::hir::map::{DefPathData, DisambiguatedDefPathData}; +use rustc::ich::NodeIdHashingMode; +use rustc::mir::interpret::{ConstValue, Scalar}; +use rustc::ty::print::{PrettyPrinter, Printer, Print}; +use rustc::ty::subst::{Kind, UnpackedKind}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Instance}; +use rustc::util::common::record_time; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; + +use log::debug; + +use std::fmt::{self, Write}; +use std::mem::{self, discriminant}; + +pub(super) fn mangle( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + instantiating_crate: Option, +) -> String { + let def_id = instance.def_id(); + + // We want to compute the "type" of this item. Unfortunately, some + // kinds of items (e.g., closures) don't have an entry in the + // item-type array. So walk back up the find the closest parent + // that DOES have an entry. + let mut ty_def_id = def_id; + let instance_ty; + loop { + let key = tcx.def_key(ty_def_id); + match key.disambiguated_data.data { + DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { + instance_ty = tcx.type_of(ty_def_id); + break; + } + _ => { + // if we're making a symbol for something, there ought + // to be a value or type-def or something in there + // *somewhere* + ty_def_id.index = key.parent.unwrap_or_else(|| { + bug!( + "finding type for {:?}, encountered def-id {:?} with no \ + parent", + def_id, + ty_def_id + ); + }); + } + } + } + + // Erase regions because they may not be deterministic when hashed + // and should not matter anyhow. + let instance_ty = tcx.erase_regions(&instance_ty); + + let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate); + + let mut printer = SymbolPrinter { + tcx, + path: SymbolPath::new(), + keep_within_component: false, + }.print_def_path(def_id, &[]).unwrap(); + + if instance.is_vtable_shim() { + let _ = printer.write_str("{{vtable-shim}}"); + } + + printer.path.finish(hash) +} + +fn get_symbol_hash<'tcx>( + tcx: TyCtxt<'tcx>, + + // instance this name will be for + instance: Instance<'tcx>, + + // type of the item, without any generic + // parameters substituted; this is + // included in the hash as a kind of + // safeguard. + item_type: Ty<'tcx>, + + instantiating_crate: Option, +) -> u64 { + let def_id = instance.def_id(); + let substs = instance.substs; + debug!( + "get_symbol_hash(def_id={:?}, parameters={:?})", + def_id, substs + ); + + let mut hasher = StableHasher::::new(); + let mut hcx = tcx.create_stable_hashing_context(); + + record_time(&tcx.sess.perf_stats.symbol_hash_time, || { + // the main symbol name is not necessarily unique; hash in the + // compiler's internal def-path, guaranteeing each symbol has a + // truly unique path + tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher); + + // Include the main item-type. Note that, in this case, the + // assertions about `needs_subst` may not hold, but this item-type + // ought to be the same for every reference anyway. + assert!(!item_type.has_erasable_regions()); + hcx.while_hashing_spans(false, |hcx| { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + item_type.hash_stable(hcx, &mut hasher); + }); + }); + + // If this is a function, we hash the signature as well. + // This is not *strictly* needed, but it may help in some + // situations, see the `run-make/a-b-a-linker-guard` test. + if let ty::FnDef(..) = item_type.sty { + item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher); + } + + // also include any type parameters (for generic items) + assert!(!substs.has_erasable_regions()); + assert!(!substs.needs_subst()); + substs.hash_stable(&mut hcx, &mut hasher); + + if let Some(instantiating_crate) = instantiating_crate { + (&tcx.original_crate_name(instantiating_crate).as_str()[..]) + .hash_stable(&mut hcx, &mut hasher); + (&tcx.crate_disambiguator(instantiating_crate)).hash_stable(&mut hcx, &mut hasher); + } + + // We want to avoid accidental collision between different types of instances. + // Especially, VtableShim may overlap with its original instance without this. + discriminant(&instance.def).hash_stable(&mut hcx, &mut hasher); + }); + + // 64 bits should be enough to avoid collisions. + hasher.finish() +} + +// Follow C++ namespace-mangling style, see +// http://en.wikipedia.org/wiki/Name_mangling for more info. +// +// It turns out that on macOS you can actually have arbitrary symbols in +// function names (at least when given to LLVM), but this is not possible +// when using unix's linker. Perhaps one day when we just use a linker from LLVM +// we won't need to do this name mangling. The problem with name mangling is +// that it seriously limits the available characters. For example we can't +// have things like &T in symbol names when one would theoretically +// want them for things like impls of traits on that type. +// +// To be able to work on all platforms and get *some* reasonable output, we +// use C++ name-mangling. +#[derive(Debug)] +struct SymbolPath { + result: String, + temp_buf: String, +} + +impl SymbolPath { + fn new() -> Self { + let mut result = SymbolPath { + result: String::with_capacity(64), + temp_buf: String::with_capacity(16), + }; + result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested + result + } + + fn finalize_pending_component(&mut self) { + if !self.temp_buf.is_empty() { + let _ = write!(self.result, "{}{}", self.temp_buf.len(), self.temp_buf); + self.temp_buf.clear(); + } + } + + fn finish(mut self, hash: u64) -> String { + self.finalize_pending_component(); + // E = end name-sequence + let _ = write!(self.result, "17h{:016x}E", hash); + self.result + } +} + +struct SymbolPrinter<'tcx> { + tcx: TyCtxt<'tcx>, + path: SymbolPath, + + // When `true`, `finalize_pending_component` isn't used. + // This is needed when recursing into `path_qualified`, + // or `path_generic_args`, as any nested paths are + // logically within one component. + keep_within_component: bool, +} + +// HACK(eddyb) this relies on using the `fmt` interface to get +// `PrettyPrinter` aka pretty printing of e.g. types in paths, +// symbol names should have their own printing machinery. + +impl Printer<'tcx> for SymbolPrinter<'tcx> { + type Error = fmt::Error; + + type Path = Self; + type Region = Self; + type Type = Self; + type DynExistential = Self; + type Const = Self; + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn print_region( + self, + _region: ty::Region<'_>, + ) -> Result { + Ok(self) + } + + fn print_type( + self, + ty: Ty<'tcx>, + ) -> Result { + match ty.sty { + // Print all nominal types as paths (unlike `pretty_print_type`). + ty::FnDef(def_id, substs) | + ty::Opaque(def_id, substs) | + ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) | + ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) | + ty::Closure(def_id, ty::ClosureSubsts { substs }) | + ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) => { + self.print_def_path(def_id, substs) + } + _ => self.pretty_print_type(ty), + } + } + + fn print_dyn_existential( + mut self, + predicates: &'tcx ty::List>, + ) -> Result { + let mut first = true; + for p in predicates { + if !first { + write!(self, "+")?; + } + first = false; + self = p.print(self)?; + } + Ok(self) + } + + fn print_const( + mut self, + ct: &'tcx ty::Const<'tcx>, + ) -> Result { + // only print integers + if let ConstValue::Scalar(Scalar::Raw { .. }) = ct.val { + if ct.ty.is_integral() { + return self.pretty_print_const(ct); + } + } + self.write_str("_")?; + Ok(self) + } + + fn path_crate( + mut self, + cnum: CrateNum, + ) -> Result { + self.write_str(&self.tcx.original_crate_name(cnum).as_str())?; + Ok(self) + } + fn path_qualified( + self, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + // Similar to `pretty_path_qualified`, but for the other + // types that are printed as paths (see `print_type` above). + match self_ty.sty { + ty::FnDef(..) | + ty::Opaque(..) | + ty::Projection(_) | + ty::UnnormalizedProjection(_) | + ty::Closure(..) | + ty::Generator(..) + if trait_ref.is_none() => + { + self.print_type(self_ty) + } + + _ => self.pretty_path_qualified(self_ty, trait_ref) + } + } + + fn path_append_impl( + self, + print_prefix: impl FnOnce(Self) -> Result, + _disambiguated_data: &DisambiguatedDefPathData, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + self.pretty_path_append_impl( + |mut cx| { + cx = print_prefix(cx)?; + + if cx.keep_within_component { + // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it. + cx.write_str("::")?; + } else { + cx.path.finalize_pending_component(); + } + + Ok(cx) + }, + self_ty, + trait_ref, + ) + } + fn path_append( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + disambiguated_data: &DisambiguatedDefPathData, + ) -> Result { + self = print_prefix(self)?; + + // Skip `::{{constructor}}` on tuple/unit structs. + match disambiguated_data.data { + DefPathData::Ctor => return Ok(self), + _ => {} + } + + if self.keep_within_component { + // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it. + self.write_str("::")?; + } else { + self.path.finalize_pending_component(); + } + + self.write_str(&disambiguated_data.data.as_interned_str().as_str())?; + Ok(self) + } + fn path_generic_args( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + args: &[Kind<'tcx>], + ) -> Result { + self = print_prefix(self)?; + + let args = args.iter().cloned().filter(|arg| { + match arg.unpack() { + UnpackedKind::Lifetime(_) => false, + _ => true, + } + }); + + if args.clone().next().is_some() { + self.generic_delimiters(|cx| cx.comma_sep(args)) + } else { + Ok(self) + } + } +} + +impl PrettyPrinter<'tcx> for SymbolPrinter<'tcx> { + fn region_should_not_be_omitted( + &self, + _region: ty::Region<'_>, + ) -> bool { + false + } + fn comma_sep(mut self, mut elems: impl Iterator) -> Result + where + T: Print<'tcx, Self, Output = Self, Error = Self::Error>, + { + if let Some(first) = elems.next() { + self = first.print(self)?; + for elem in elems { + self.write_str(",")?; + self = elem.print(self)?; + } + } + Ok(self) + } + + fn generic_delimiters( + mut self, + f: impl FnOnce(Self) -> Result, + ) -> Result { + write!(self, "<")?; + + let kept_within_component = + mem::replace(&mut self.keep_within_component, true); + self = f(self)?; + self.keep_within_component = kept_within_component; + + write!(self, ">")?; + + Ok(self) + } +} + +impl fmt::Write for SymbolPrinter<'_> { + fn write_str(&mut self, s: &str) -> fmt::Result { + // Name sanitation. LLVM will happily accept identifiers with weird names, but + // gas doesn't! + // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $ + // NVPTX assembly has more strict naming rules than gas, so additionally, dots + // are replaced with '$' there. + + for c in s.chars() { + if self.path.temp_buf.is_empty() { + match c { + 'a'..='z' | 'A'..='Z' | '_' => {} + _ => { + // Underscore-qualify anything that didn't start as an ident. + self.path.temp_buf.push('_'); + } + } + } + match c { + // Escape these with $ sequences + '@' => self.path.temp_buf.push_str("$SP$"), + '*' => self.path.temp_buf.push_str("$BP$"), + '&' => self.path.temp_buf.push_str("$RF$"), + '<' => self.path.temp_buf.push_str("$LT$"), + '>' => self.path.temp_buf.push_str("$GT$"), + '(' => self.path.temp_buf.push_str("$LP$"), + ')' => self.path.temp_buf.push_str("$RP$"), + ',' => self.path.temp_buf.push_str("$C$"), + + '-' | ':' | '.' if self.tcx.has_strict_asm_symbol_naming() => { + // NVPTX doesn't support these characters in symbol names. + self.path.temp_buf.push('$') + } + + // '.' doesn't occur in types and functions, so reuse it + // for ':' and '-' + '-' | ':' => self.path.temp_buf.push('.'), + + // Avoid crashing LLVM in certain (LTO-related) situations, see #60925. + 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$u6d$"), + + // These are legal symbols + 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => self.path.temp_buf.push(c), + + _ => { + self.path.temp_buf.push('$'); + for c in c.escape_unicode().skip(1) { + match c { + '{' => {} + '}' => self.path.temp_buf.push('$'), + c => self.path.temp_buf.push(c), + } + } + } + } + } + + Ok(()) + } +} diff --git a/src/librustc_codegen_utils/symbol_names/v0.rs b/src/librustc_codegen_utils/symbol_names/v0.rs new file mode 100644 index 0000000000000..8a54fb6bbc4ca --- /dev/null +++ b/src/librustc_codegen_utils/symbol_names/v0.rs @@ -0,0 +1,656 @@ +use rustc::hir; +use rustc::hir::def_id::{CrateNum, DefId}; +use rustc::hir::map::{DefPathData, DisambiguatedDefPathData}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Instance}; +use rustc::ty::print::{Printer, Print}; +use rustc::ty::subst::{Kind, Subst, UnpackedKind}; +use rustc_data_structures::base_n; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_target::spec::abi::Abi; +use syntax::ast::{IntTy, UintTy, FloatTy}; + +use std::fmt::Write; +use std::ops::Range; + +pub(super) fn mangle( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + instantiating_crate: Option, +) -> String { + let def_id = instance.def_id(); + // FIXME(eddyb) this should ideally not be needed. + let substs = + tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), instance.substs); + + let prefix = "_R"; + let mut cx = SymbolMangler { + tcx, + compress: Some(Box::new(CompressionCaches { + start_offset: prefix.len(), + + paths: FxHashMap::default(), + types: FxHashMap::default(), + consts: FxHashMap::default(), + })), + binders: vec![], + out: String::from(prefix), + }; + cx = if instance.is_vtable_shim() { + cx.path_append_ns( + |cx| cx.print_def_path(def_id, substs), + 'S', + 0, + "", + ).unwrap() + } else { + cx.print_def_path(def_id, substs).unwrap() + }; + if let Some(instantiating_crate) = instantiating_crate { + cx = cx.print_def_path(instantiating_crate.as_def_id(), &[]).unwrap(); + } + cx.out +} + +struct CompressionCaches<'tcx> { + // The length of the prefix in `out` (e.g. 2 for `_R`). + start_offset: usize, + + // The values are start positions in `out`, in bytes. + paths: FxHashMap<(DefId, &'tcx [Kind<'tcx>]), usize>, + types: FxHashMap, usize>, + consts: FxHashMap<&'tcx ty::Const<'tcx>, usize>, +} + +struct BinderLevel { + /// The range of distances from the root of what's + /// being printed, to the lifetimes in a binder. + /// Specifically, a `BrAnon(i)` lifetime has depth + /// `lifetime_depths.start + i`, going away from the + /// the root and towards its use site, as `i` increases. + /// This is used to flatten rustc's pairing of `BrAnon` + /// (intra-binder disambiguation) with a `DebruijnIndex` + /// (binder addressing), to "true" de Bruijn indices, + /// by subtracting the depth of a certain lifetime, from + /// the innermost depth at its use site. + lifetime_depths: Range, +} + +struct SymbolMangler<'tcx> { + tcx: TyCtxt<'tcx>, + compress: Option>>, + binders: Vec, + out: String, +} + +impl SymbolMangler<'tcx> { + fn push(&mut self, s: &str) { + self.out.push_str(s); + } + + /// Push a `_`-terminated base 62 integer, using the format + /// specified in the RFC as ``, that is: + /// * `x = 0` is encoded as just the `"_"` terminator + /// * `x > 0` is encoded as `x - 1` in base 62, followed by `"_"`, + /// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc. + fn push_integer_62(&mut self, x: u64) { + if let Some(x) = x.checked_sub(1) { + base_n::push_str(x as u128, 62, &mut self.out); + } + self.push("_"); + } + + /// Push a `tag`-prefixed base 62 integer, when larger than `0`, that is: + /// * `x = 0` is encoded as `""` (nothing) + /// * `x > 0` is encoded as the `tag` followed by `push_integer_62(x - 1)` + /// e.g. `1` becomes `tag + "_"`, `2` becomes `tag + "0_"`, etc. + fn push_opt_integer_62(&mut self, tag: &str, x: u64) { + if let Some(x) = x.checked_sub(1) { + self.push(tag); + self.push_integer_62(x); + } + } + + fn push_disambiguator(&mut self, dis: u64) { + self.push_opt_integer_62("s", dis); + } + + fn push_ident(&mut self, ident: &str) { + let mut use_punycode = false; + for b in ident.bytes() { + match b { + b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => {} + 0x80..=0xff => use_punycode = true, + _ => bug!("symbol_names: bad byte {} in ident {:?}", b, ident), + } + } + + let punycode_string; + let ident = if use_punycode { + self.push("u"); + + // FIXME(eddyb) we should probably roll our own punycode implementation. + let mut punycode_bytes = match ::punycode::encode(ident) { + Ok(s) => s.into_bytes(), + Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident), + }; + + // Replace `-` with `_`. + if let Some(c) = punycode_bytes.iter_mut().rfind(|&&mut c| c == b'-') { + *c = b'_'; + } + + // FIXME(eddyb) avoid rechecking UTF-8 validity. + punycode_string = String::from_utf8(punycode_bytes).unwrap(); + &punycode_string + } else { + ident + }; + + let _ = write!(self.out, "{}", ident.len()); + + // Write a separating `_` if necessary (leading digit or `_`). + match ident.chars().next() { + Some('_') | Some('0'..='9') => { + self.push("_"); + } + _ => {} + } + + self.push(ident); + } + + fn path_append_ns( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + ns: char, + disambiguator: u64, + name: &str, + ) -> Result { + self.push("N"); + self.out.push(ns); + self = print_prefix(self)?; + self.push_disambiguator(disambiguator as u64); + self.push_ident(name); + Ok(self) + } + + fn print_backref(mut self, i: usize) -> Result { + self.push("B"); + self.push_integer_62((i - self.compress.as_ref().unwrap().start_offset) as u64); + Ok(self) + } + + fn in_binder( + mut self, + value: &ty::Binder, + print_value: impl FnOnce(Self, &T) -> Result + ) -> Result + where T: TypeFoldable<'tcx> + { + let regions = if value.has_late_bound_regions() { + self.tcx.collect_referenced_late_bound_regions(value) + } else { + FxHashSet::default() + }; + + let mut lifetime_depths = + self.binders.last().map(|b| b.lifetime_depths.end).map_or(0..0, |i| i..i); + + let lifetimes = regions.into_iter().map(|br| { + match br { + ty::BrAnon(i) => i + 1, + _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value), + } + }).max().unwrap_or(0); + + self.push_opt_integer_62("G", lifetimes as u64); + lifetime_depths.end += lifetimes; + + self.binders.push(BinderLevel { lifetime_depths }); + self = print_value(self, value.skip_binder())?; + self.binders.pop(); + + Ok(self) + } +} + +impl Printer<'tcx> for SymbolMangler<'tcx> { + type Error = !; + + type Path = Self; + type Region = Self; + type Type = Self; + type DynExistential = Self; + type Const = Self; + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn print_def_path( + mut self, + def_id: DefId, + substs: &'tcx [Kind<'tcx>], + ) -> Result { + if let Some(&i) = self.compress.as_ref().and_then(|c| c.paths.get(&(def_id, substs))) { + return self.print_backref(i); + } + let start = self.out.len(); + + self = self.default_print_def_path(def_id, substs)?; + + // Only cache paths that do not refer to an enclosing + // binder (which would change depending on context). + if !substs.iter().any(|k| k.has_escaping_bound_vars()) { + if let Some(c) = &mut self.compress { + c.paths.insert((def_id, substs), start); + } + } + Ok(self) + } + + fn print_impl_path( + self, + impl_def_id: DefId, + substs: &'tcx [Kind<'tcx>], + mut self_ty: Ty<'tcx>, + mut impl_trait_ref: Option>, + ) -> Result { + let key = self.tcx.def_key(impl_def_id); + let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id }; + + let mut param_env = self.tcx.param_env(impl_def_id) + .with_reveal_all(); + if !substs.is_empty() { + param_env = param_env.subst(self.tcx, substs); + } + + match &mut impl_trait_ref { + Some(impl_trait_ref) => { + assert_eq!(impl_trait_ref.self_ty(), self_ty); + *impl_trait_ref = + self.tcx.normalize_erasing_regions(param_env, *impl_trait_ref); + self_ty = impl_trait_ref.self_ty(); + } + None => { + self_ty = self.tcx.normalize_erasing_regions(param_env, self_ty); + } + } + + self.path_append_impl( + |cx| cx.print_def_path(parent_def_id, &[]), + &key.disambiguated_data, + self_ty, + impl_trait_ref, + ) + } + + fn print_region( + mut self, + region: ty::Region<'_>, + ) -> Result { + let i = match *region { + // Erased lifetimes use the index 0, for a + // shorter mangling of `L_`. + ty::ReErased => 0, + + // Late-bound lifetimes use indices starting at 1, + // see `BinderLevel` for more details. + ty::ReLateBound(debruijn, ty::BrAnon(i)) => { + let binder = &self.binders[self.binders.len() - 1 - debruijn.index()]; + let depth = binder.lifetime_depths.start + i; + + 1 + (self.binders.last().unwrap().lifetime_depths.end - 1 - depth) + } + + _ => bug!("symbol_names: non-erased region `{:?}`", region), + }; + self.push("L"); + self.push_integer_62(i as u64); + Ok(self) + } + + fn print_type( + mut self, + ty: Ty<'tcx>, + ) -> Result { + // Basic types, never cached (single-character). + let basic_type = match ty.sty { + ty::Bool => "b", + ty::Char => "c", + ty::Str => "e", + ty::Tuple(_) if ty.is_unit() => "u", + ty::Int(IntTy::I8) => "a", + ty::Int(IntTy::I16) => "s", + ty::Int(IntTy::I32) => "l", + ty::Int(IntTy::I64) => "x", + ty::Int(IntTy::I128) => "n", + ty::Int(IntTy::Isize) => "i", + ty::Uint(UintTy::U8) => "h", + ty::Uint(UintTy::U16) => "t", + ty::Uint(UintTy::U32) => "m", + ty::Uint(UintTy::U64) => "y", + ty::Uint(UintTy::U128) => "o", + ty::Uint(UintTy::Usize) => "j", + ty::Float(FloatTy::F32) => "f", + ty::Float(FloatTy::F64) => "d", + ty::Never => "z", + + // Placeholders (should be demangled as `_`). + ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | + ty::Infer(_) | ty::Error => "p", + + _ => "", + }; + if !basic_type.is_empty() { + self.push(basic_type); + return Ok(self); + } + + if let Some(&i) = self.compress.as_ref().and_then(|c| c.types.get(&ty)) { + return self.print_backref(i); + } + let start = self.out.len(); + + match ty.sty { + // Basic types, handled above. + ty::Bool | ty::Char | ty::Str | + ty::Int(_) | ty::Uint(_) | ty::Float(_) | + ty::Never => unreachable!(), + ty::Tuple(_) if ty.is_unit() => unreachable!(), + + // Placeholders, also handled as part of basic types. + ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | + ty::Infer(_) | ty::Error => unreachable!(), + + ty::Ref(r, ty, mutbl) => { + self.push(match mutbl { + hir::MutImmutable => "R", + hir::MutMutable => "Q", + }); + if *r != ty::ReErased { + self = r.print(self)?; + } + self = ty.print(self)?; + } + + ty::RawPtr(mt) => { + self.push(match mt.mutbl { + hir::MutImmutable => "P", + hir::MutMutable => "O", + }); + self = mt.ty.print(self)?; + } + + ty::Array(ty, len) => { + self.push("A"); + self = ty.print(self)?; + self = self.print_const(len)?; + } + ty::Slice(ty) => { + self.push("S"); + self = ty.print(self)?; + } + + ty::Tuple(tys) => { + self.push("T"); + for ty in tys.iter().map(|k| k.expect_ty()) { + self = ty.print(self)?; + } + self.push("E"); + } + + // Mangle all nominal types as paths. + ty::Adt(&ty::AdtDef { did: def_id, .. }, substs) | + ty::FnDef(def_id, substs) | + ty::Opaque(def_id, substs) | + ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) | + ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) | + ty::Closure(def_id, ty::ClosureSubsts { substs }) | + ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) => { + self = self.print_def_path(def_id, substs)?; + } + ty::Foreign(def_id) => { + self = self.print_def_path(def_id, &[])?; + } + + ty::FnPtr(sig) => { + self.push("F"); + self = self.in_binder(&sig, |mut cx, sig| { + if sig.unsafety == hir::Unsafety::Unsafe { + cx.push("U"); + } + match sig.abi { + Abi::Rust => {} + Abi::C => cx.push("KC"), + abi => { + cx.push("K"); + let name = abi.name(); + if name.contains('-') { + cx.push_ident(&name.replace('-', "_")); + } else { + cx.push_ident(name); + } + } + } + for &ty in sig.inputs() { + cx = ty.print(cx)?; + } + if sig.c_variadic { + cx.push("v"); + } + cx.push("E"); + sig.output().print(cx) + })?; + } + + ty::Dynamic(predicates, r) => { + self.push("D"); + self = self.in_binder(&predicates, |cx, predicates| { + cx.print_dyn_existential(predicates) + })?; + self = r.print(self)?; + } + + ty::GeneratorWitness(_) => { + bug!("symbol_names: unexpected `GeneratorWitness`") + } + } + + // Only cache types that do not refer to an enclosing + // binder (which would change depending on context). + if !ty.has_escaping_bound_vars() { + if let Some(c) = &mut self.compress { + c.types.insert(ty, start); + } + } + Ok(self) + } + + fn print_dyn_existential( + mut self, + predicates: &'tcx ty::List>, + ) -> Result { + for predicate in predicates { + match *predicate { + ty::ExistentialPredicate::Trait(trait_ref) => { + // Use a type that can't appear in defaults of type parameters. + let dummy_self = self.tcx.mk_ty_infer(ty::FreshTy(0)); + let trait_ref = trait_ref.with_self_ty(self.tcx, dummy_self); + self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; + } + ty::ExistentialPredicate::Projection(projection) => { + let name = self.tcx.associated_item(projection.item_def_id).ident; + self.push("p"); + self.push_ident(&name.as_str()); + self = projection.ty.print(self)?; + } + ty::ExistentialPredicate::AutoTrait(def_id) => { + self = self.print_def_path(def_id, &[])?; + } + } + } + self.push("E"); + Ok(self) + } + + fn print_const( + mut self, + ct: &'tcx ty::Const<'tcx>, + ) -> Result { + if let Some(&i) = self.compress.as_ref().and_then(|c| c.consts.get(&ct)) { + return self.print_backref(i); + } + let start = self.out.len(); + + match ct.ty.sty { + ty::Uint(_) => {} + _ => { + bug!("symbol_names: unsupported constant of type `{}` ({:?})", + ct.ty, ct); + } + } + self = ct.ty.print(self)?; + + if let Some(bits) = ct.assert_bits(self.tcx, ty::ParamEnv::empty().and(ct.ty)) { + let _ = write!(self.out, "{:x}_", bits); + } else { + // NOTE(eddyb) despite having the path, we need to + // encode a placeholder, as the path could refer + // back to e.g. an `impl` using the constant. + self.push("p"); + } + + // Only cache consts that do not refer to an enclosing + // binder (which would change depending on context). + if !ct.has_escaping_bound_vars() { + if let Some(c) = &mut self.compress { + c.consts.insert(ct, start); + } + } + Ok(self) + } + + fn path_crate( + mut self, + cnum: CrateNum, + ) -> Result { + self.push("C"); + let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint(); + self.push_disambiguator(fingerprint.to_smaller_hash()); + let name = self.tcx.original_crate_name(cnum).as_str(); + self.push_ident(&name); + Ok(self) + } + fn path_qualified( + mut self, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + assert!(trait_ref.is_some()); + let trait_ref = trait_ref.unwrap(); + + self.push("Y"); + self = self_ty.print(self)?; + self.print_def_path(trait_ref.def_id, trait_ref.substs) + } + + fn path_append_impl( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + disambiguated_data: &DisambiguatedDefPathData, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + self.push(match trait_ref { + Some(_) => "X", + None => "M", + }); + self.push_disambiguator(disambiguated_data.disambiguator as u64); + self = print_prefix(self)?; + self = self_ty.print(self)?; + if let Some(trait_ref) = trait_ref { + self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; + } + Ok(self) + } + fn path_append( + self, + print_prefix: impl FnOnce(Self) -> Result, + disambiguated_data: &DisambiguatedDefPathData, + ) -> Result { + let ns = match disambiguated_data.data { + // Uppercase categories are more stable than lowercase ones. + DefPathData::TypeNs(_) => 't', + DefPathData::ValueNs(_) => 'v', + DefPathData::ClosureExpr => 'C', + DefPathData::Ctor => 'c', + DefPathData::AnonConst => 'k', + DefPathData::ImplTrait => 'i', + + // These should never show up as `path_append` arguments. + DefPathData::CrateRoot + | DefPathData::Misc + | DefPathData::Impl + | DefPathData::MacroNs(_) + | DefPathData::LifetimeNs(_) + | DefPathData::GlobalMetaData(_) => { + bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data) + } + }; + + let name = disambiguated_data.data.get_opt_name().map(|s| s.as_str()); + + self.path_append_ns( + print_prefix, + ns, + disambiguated_data.disambiguator as u64, + name.as_ref().map_or("", |s| &s[..]) + ) + } + fn path_generic_args( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + args: &[Kind<'tcx>], + ) -> Result { + // Don't print any regions if they're all erased. + let print_regions = args.iter().any(|arg| { + match arg.unpack() { + UnpackedKind::Lifetime(r) => *r != ty::ReErased, + _ => false, + } + }); + let args = args.iter().cloned().filter(|arg| { + match arg.unpack() { + UnpackedKind::Lifetime(_) => print_regions, + _ => true, + } + }); + + if args.clone().next().is_none() { + return print_prefix(self); + } + + self.push("I"); + self = print_prefix(self)?; + for arg in args { + match arg.unpack() { + UnpackedKind::Lifetime(lt) => { + self = lt.print(self)?; + } + UnpackedKind::Type(ty) => { + self = ty.print(self)?; + } + UnpackedKind::Const(c) => { + self.push("K"); + // FIXME(const_generics) implement `ty::print::Print` on `ty::Const`. + // self = c.print(self)?; + self = self.print_const(c)?; + } + } + } + self.push("E"); + + Ok(self) + } +} diff --git a/src/librustc_codegen_utils/symbol_names_test.rs b/src/librustc_codegen_utils/symbol_names_test.rs index c495268154664..f48d1f2853c52 100644 --- a/src/librustc_codegen_utils/symbol_names_test.rs +++ b/src/librustc_codegen_utils/symbol_names_test.rs @@ -1,18 +1,17 @@ //! Walks the crate looking for items/impl-items/trait-items that have -//! either a `rustc_symbol_name` or `rustc_item_path` attribute and +//! either a `rustc_symbol_name` or `rustc_def_path` attribute and //! generates an error giving, respectively, the symbol name or -//! item-path. This is used for unit testing the code that generates +//! def-path. This is used for unit testing the code that generates //! paths etc in all kinds of annoying scenarios. use rustc::hir; -use rustc::ty::TyCtxt; +use rustc::ty::{TyCtxt, Instance}; +use syntax::symbol::{Symbol, sym}; -use rustc_mir::monomorphize::Instance; +const SYMBOL_NAME: Symbol = sym::rustc_symbol_name; +const DEF_PATH: Symbol = sym::rustc_def_path; -const SYMBOL_NAME: &'static str = "rustc_symbol_name"; -const ITEM_PATH: &'static str = "rustc_item_path"; - -pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn report_symbol_names<'tcx>(tcx: TyCtxt<'tcx>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. @@ -26,11 +25,11 @@ pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { }) } -struct SymbolNamesTest<'a, 'tcx:'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct SymbolNamesTest<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { +impl SymbolNamesTest<'tcx> { fn process_attrs(&mut self, hir_id: hir::HirId) { let tcx = self.tcx; @@ -39,11 +38,15 @@ impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { if attr.check_name(SYMBOL_NAME) { // for now, can only use on monomorphic names let instance = Instance::mono(tcx, def_id); - let name = self.tcx.symbol_name(instance); - tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); - } else if attr.check_name(ITEM_PATH) { - let path = tcx.item_path_str(def_id); - tcx.sess.span_err(attr.span, &format!("item-path({})", path)); + let mangled = self.tcx.symbol_name(instance); + tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled)); + if let Ok(demangling) = rustc_demangle::try_demangle(&mangled.as_str()) { + tcx.sess.span_err(attr.span, &format!("demangling({})", demangling)); + tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling)); + } + } else if attr.check_name(DEF_PATH) { + let path = tcx.def_path_str(def_id); + tcx.sess.span_err(attr.span, &format!("def-path({})", path)); } // (*) The formatting of `tag({})` is chosen so that tests can elect @@ -53,7 +56,7 @@ impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { } } -impl<'a, 'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for SymbolNamesTest<'a, 'tcx> { +impl hir::itemlikevisit::ItemLikeVisitor<'tcx> for SymbolNamesTest<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { self.process_attrs(item.hir_id); } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 6002bf69b7069..cd792d31187bd 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -10,17 +10,18 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -ena = "0.11" +ena = "0.13" +indexmap = "1" log = "0.4" -jobserver_crate = { version = "0.1", package = "jobserver" } +jobserver_crate = { version = "0.1.13", package = "jobserver" } lazy_static = "1" rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } serialize = { path = "../libserialize" } graphviz = { path = "../libgraphviz" } cfg-if = "0.1.2" stable_deref_trait = "1.0.0" -rayon = { version = "0.1.2", package = "rustc-rayon" } -rayon-core = { version = "0.1.2", package = "rustc-rayon-core" } +rayon = { version = "0.2.0", package = "rustc-rayon" } +rayon-core = { version = "0.2.0", package = "rustc-rayon-core" } rustc-hash = "1.0.1" smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/librustc_data_structures/binary_search_util/mod.rs b/src/librustc_data_structures/binary_search_util/mod.rs new file mode 100644 index 0000000000000..32aa1cb6b1d36 --- /dev/null +++ b/src/librustc_data_structures/binary_search_util/mod.rs @@ -0,0 +1,49 @@ +#[cfg(test)] +mod test; + +/// Uses a sorted slice `data: &[E]` as a kind of "multi-map". The +/// `key_fn` extracts a key of type `K` from the data, and this +/// function finds the range of elements that match the key. `data` +/// must have been sorted as if by a call to `sort_by_key` for this to +/// work. +pub fn binary_search_slice(data: &'d [E], key_fn: impl Fn(&E) -> K, key: &K) -> &'d [E] +where + K: Ord, +{ + let mid = match data.binary_search_by_key(key, &key_fn) { + Ok(mid) => mid, + Err(_) => return &[], + }; + + // We get back *some* element with the given key -- so + // search backwards to find the *first* one. + // + // (It'd be more efficient to use a "galloping" search + // here, but it's not really worth it for small-ish + // amounts of data.) + let mut start = mid; + while start > 0 { + if key_fn(&data[start - 1]) == *key { + start -= 1; + } else { + break; + } + } + + // Now search forward to find the *last* one. + // + // (It'd be more efficient to use a "galloping" search + // here, but it's not really worth it for small-ish + // amounts of data.) + let mut end = mid + 1; + let max = data.len(); + while end < max { + if key_fn(&data[end]) == *key { + end += 1; + } else { + break; + } + } + + &data[start..end] +} diff --git a/src/librustc_data_structures/binary_search_util/test.rs b/src/librustc_data_structures/binary_search_util/test.rs new file mode 100644 index 0000000000000..d74febb5c0fc4 --- /dev/null +++ b/src/librustc_data_structures/binary_search_util/test.rs @@ -0,0 +1,23 @@ +use super::*; + +type Element = (usize, &'static str); + +fn test_map() -> Vec { + let mut data = vec![(3, "three-a"), (0, "zero"), (3, "three-b"), (22, "twenty-two")]; + data.sort_by_key(get_key); + data +} + +fn get_key(data: &Element) -> usize { + data.0 +} + +#[test] +fn binary_search_slice_test() { + let map = test_map(); + assert_eq!(binary_search_slice(&map, get_key, &0), &[(0, "zero")]); + assert_eq!(binary_search_slice(&map, get_key, &1), &[]); + assert_eq!(binary_search_slice(&map, get_key, &3), &[(3, "three-a"), (3, "three-b")]); + assert_eq!(binary_search_slice(&map, get_key, &22), &[(22, "twenty-two")]); + assert_eq!(binary_search_slice(&map, get_key, &23), &[]); +} diff --git a/src/librustc_data_structures/bit_set.rs b/src/librustc_data_structures/bit_set.rs index ff7964646d608..5d8388d89f5b3 100644 --- a/src/librustc_data_structures/bit_set.rs +++ b/src/librustc_data_structures/bit_set.rs @@ -5,6 +5,10 @@ use std::iter; use std::marker::PhantomData; use std::mem; use std::slice; +#[cfg(test)] +extern crate test; +#[cfg(test)] +use test::Bencher; pub type Word = u64; pub const WORD_BYTES: usize = mem::size_of::(); @@ -177,6 +181,45 @@ impl BitSet { // Note: we currently don't bother trying to make a Sparse set. HybridBitSet::Dense(self.to_owned()) } + + /// Set `self = self | other`. In contrast to `union` returns `true` if the set contains at + /// least one bit that is not in `other` (i.e. `other` is not a superset of `self`). + /// + /// This is an optimization for union of a hybrid bitset. + fn reverse_union_sparse(&mut self, sparse: &SparseBitSet) -> bool { + assert!(sparse.domain_size == self.domain_size); + self.clear_excess_bits(); + + let mut not_already = false; + // Index of the current word not yet merged. + let mut current_index = 0; + // Mask of bits that came from the sparse set in the current word. + let mut new_bit_mask = 0; + for (word_index, mask) in sparse.iter().map(|x| word_index_and_mask(*x)) { + // Next bit is in a word not inspected yet. + if word_index > current_index { + self.words[current_index] |= new_bit_mask; + // Were there any bits in the old word that did not occur in the sparse set? + not_already |= (self.words[current_index] ^ new_bit_mask) != 0; + // Check all words we skipped for any set bit. + not_already |= self.words[current_index+1..word_index].iter().any(|&x| x != 0); + // Update next word. + current_index = word_index; + // Reset bit mask, no bits have been merged yet. + new_bit_mask = 0; + } + // Add bit and mark it as coming from the sparse set. + // self.words[word_index] |= mask; + new_bit_mask |= mask; + } + self.words[current_index] |= new_bit_mask; + // Any bits in the last inspected word that were not in the sparse set? + not_already |= (self.words[current_index] ^ new_bit_mask) != 0; + // Any bits in the tail? Note `clear_excess_bits` before. + not_already |= self.words[current_index+1..].iter().any(|&x| x != 0); + + not_already + } } /// This is implemented by all the bitsets so that BitSet::union() can be @@ -273,11 +316,6 @@ impl<'a, T: Idx> Iterator for BitIter<'a, T> { } } -pub trait BitSetOperator { - /// Combine one bitset into another. - fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool; -} - #[inline] fn bitwise(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool where Op: Fn(Word, Word) -> Word @@ -514,10 +552,22 @@ impl HybridBitSet { changed } HybridBitSet::Dense(other_dense) => { - // `self` is sparse and `other` is dense. Densify - // `self` and then do the bitwise union. - let mut new_dense = self_sparse.to_dense(); - let changed = new_dense.union(other_dense); + // `self` is sparse and `other` is dense. To + // merge them, we have two available strategies: + // * Densify `self` then merge other + // * Clone other then integrate bits from `self` + // The second strategy requires dedicated method + // since the usual `union` returns the wrong + // result. In the dedicated case the computation + // is slightly faster if the bits of the sparse + // bitset map to only few words of the dense + // representation, i.e. indices are near each + // other. + // + // Benchmarking seems to suggest that the second + // option is worth it. + let mut new_dense = other_dense.clone(); + let changed = new_dense.reverse_union_sparse(self_sparse); *self = HybridBitSet::Dense(new_dense); changed } @@ -607,8 +657,8 @@ impl GrowableBitSet { GrowableBitSet { bit_set: BitSet::new_empty(0) } } - pub fn with_capacity(bits: usize) -> GrowableBitSet { - GrowableBitSet { bit_set: BitSet::new_empty(bits) } + pub fn with_capacity(capacity: usize) -> GrowableBitSet { + GrowableBitSet { bit_set: BitSet::new_empty(capacity) } } /// Returns `true` if the set has changed. @@ -636,7 +686,7 @@ impl GrowableBitSet { /// /// All operations that involve a row and/or column index will panic if the /// index exceeds the relevant bound. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq, RustcDecodable, RustcEncodable)] pub struct BitMatrix { num_rows: usize, num_columns: usize, @@ -658,6 +708,23 @@ impl BitMatrix { } } + /// Creates a new matrix, with `row` used as the value for every row. + pub fn from_row_n(row: &BitSet, num_rows: usize) -> BitMatrix { + let num_columns = row.domain_size(); + let words_per_row = num_words(num_columns); + assert_eq!(words_per_row, row.words().len()); + BitMatrix { + num_rows, + num_columns, + words: iter::repeat(row.words()).take(num_rows).flatten().cloned().collect(), + marker: PhantomData, + } + } + + pub fn rows(&self) -> impl Iterator { + (0..self.num_rows).map(R::new) + } + /// The range of bits for a given row. fn range(&self, row: R) -> (usize, usize) { let words_per_row = num_words(self.num_columns); @@ -737,6 +804,49 @@ impl BitMatrix { changed } + /// Adds the bits from `with` to the bits from row `write`, and + /// returns `true` if anything changed. + pub fn union_row_with(&mut self, with: &BitSet, write: R) -> bool { + assert!(write.index() < self.num_rows); + assert_eq!(with.domain_size(), self.num_columns); + let (write_start, write_end) = self.range(write); + let mut changed = false; + for (read_index, write_index) in (0..with.words().len()).zip(write_start..write_end) { + let word = self.words[write_index]; + let new_word = word | with.words()[read_index]; + self.words[write_index] = new_word; + changed |= word != new_word; + } + changed + } + + /// Sets every cell in `row` to true. + pub fn insert_all_into_row(&mut self, row: R) { + assert!(row.index() < self.num_rows); + let (start, end) = self.range(row); + let words = &mut self.words[..]; + for index in start..end { + words[index] = !0; + } + self.clear_excess_bits(row); + } + + /// Clear excess bits in the final word of the row. + fn clear_excess_bits(&mut self, row: R) { + let num_bits_in_final_word = self.num_columns % WORD_BITS; + if num_bits_in_final_word > 0 { + let mask = (1 << num_bits_in_final_word) - 1; + let (_, end) = self.range(row); + let final_word_idx = end - 1; + self.words[final_word_idx] &= mask; + } + } + + /// Gets a slice of the underlying words. + pub fn words(&self) -> &[Word] { + &self.words + } + /// Iterates through all the columns set to true in a given row of /// the matrix. pub fn iter<'a>(&'a self, row: R) -> BitIter<'a, C> { @@ -748,6 +858,12 @@ impl BitMatrix { marker: PhantomData, } } + + /// Returns the number of elements in `row`. + pub fn count(&self, row: R) -> usize { + let (start, end) = self.range(row); + self.words[start..end].iter().map(|e| e.count_ones() as usize).sum() + } } /// A fixed-column-size, variable-row-size 2D bit matrix with a moderately @@ -1057,6 +1173,7 @@ fn matrix_iter() { matrix.insert(2, 99); matrix.insert(4, 0); matrix.union_rows(3, 5); + matrix.insert_all_into_row(6); let expected = [99]; let mut iter = expected.iter(); @@ -1068,6 +1185,7 @@ fn matrix_iter() { let expected = [22, 75]; let mut iter = expected.iter(); + assert_eq!(matrix.count(3), expected.len()); for i in matrix.iter(3) { let j = *iter.next().unwrap(); assert_eq!(i, j); @@ -1076,6 +1194,7 @@ fn matrix_iter() { let expected = [0]; let mut iter = expected.iter(); + assert_eq!(matrix.count(4), expected.len()); for i in matrix.iter(4) { let j = *iter.next().unwrap(); assert_eq!(i, j); @@ -1084,11 +1203,24 @@ fn matrix_iter() { let expected = [22, 75]; let mut iter = expected.iter(); + assert_eq!(matrix.count(5), expected.len()); for i in matrix.iter(5) { let j = *iter.next().unwrap(); assert_eq!(i, j); } assert!(iter.next().is_none()); + + assert_eq!(matrix.count(6), 100); + let mut count = 0; + for (idx, i) in matrix.iter(6).enumerate() { + assert_eq!(idx, i); + count += 1; + } + assert_eq!(count, 100); + + if let Some(i) = matrix.iter(7).next() { + panic!("expected no elements in row, but contains element {:?}", i); + } } #[test] @@ -1132,3 +1264,87 @@ fn sparse_matrix_iter() { } assert!(iter.next().is_none()); } + +/// Merge dense hybrid set into empty sparse hybrid set. +#[bench] +fn union_hybrid_sparse_empty_to_dense(b: &mut Bencher) { + let mut pre_dense: HybridBitSet = HybridBitSet::new_empty(256); + for i in 0..10 { + assert!(pre_dense.insert(i)); + } + let pre_sparse: HybridBitSet = HybridBitSet::new_empty(256); + b.iter(|| { + let dense = pre_dense.clone(); + let mut sparse = pre_sparse.clone(); + sparse.union(&dense); + }) +} + +/// Merge dense hybrid set into full hybrid set with same indices. +#[bench] +fn union_hybrid_sparse_full_to_dense(b: &mut Bencher) { + let mut pre_dense: HybridBitSet = HybridBitSet::new_empty(256); + for i in 0..10 { + assert!(pre_dense.insert(i)); + } + let mut pre_sparse: HybridBitSet = HybridBitSet::new_empty(256); + for i in 0..SPARSE_MAX { + assert!(pre_sparse.insert(i)); + } + b.iter(|| { + let dense = pre_dense.clone(); + let mut sparse = pre_sparse.clone(); + sparse.union(&dense); + }) +} + +/// Merge dense hybrid set into full hybrid set with indices over the whole domain. +#[bench] +fn union_hybrid_sparse_domain_to_dense(b: &mut Bencher) { + let mut pre_dense: HybridBitSet = HybridBitSet::new_empty(SPARSE_MAX*64); + for i in 0..10 { + assert!(pre_dense.insert(i)); + } + let mut pre_sparse: HybridBitSet = HybridBitSet::new_empty(SPARSE_MAX*64); + for i in 0..SPARSE_MAX { + assert!(pre_sparse.insert(i*64)); + } + b.iter(|| { + let dense = pre_dense.clone(); + let mut sparse = pre_sparse.clone(); + sparse.union(&dense); + }) +} + +/// Merge dense hybrid set into empty hybrid set where the domain is very small. +#[bench] +fn union_hybrid_sparse_empty_small_domain(b: &mut Bencher) { + let mut pre_dense: HybridBitSet = HybridBitSet::new_empty(SPARSE_MAX); + for i in 0..SPARSE_MAX { + assert!(pre_dense.insert(i)); + } + let pre_sparse: HybridBitSet = HybridBitSet::new_empty(SPARSE_MAX); + b.iter(|| { + let dense = pre_dense.clone(); + let mut sparse = pre_sparse.clone(); + sparse.union(&dense); + }) +} + +/// Merge dense hybrid set into full hybrid set where the domain is very small. +#[bench] +fn union_hybrid_sparse_full_small_domain(b: &mut Bencher) { + let mut pre_dense: HybridBitSet = HybridBitSet::new_empty(SPARSE_MAX); + for i in 0..SPARSE_MAX { + assert!(pre_dense.insert(i)); + } + let mut pre_sparse: HybridBitSet = HybridBitSet::new_empty(SPARSE_MAX); + for i in 0..SPARSE_MAX { + assert!(pre_sparse.insert(i)); + } + b.iter(|| { + let dense = pre_dense.clone(); + let mut sparse = pre_sparse.clone(); + sparse.union(&dense); + }) +} diff --git a/src/librustc_data_structures/box_region.rs b/src/librustc_data_structures/box_region.rs new file mode 100644 index 0000000000000..278dcdf2bee42 --- /dev/null +++ b/src/librustc_data_structures/box_region.rs @@ -0,0 +1,172 @@ +use std::cell::Cell; +use std::marker::PhantomData; +use std::pin::Pin; +use std::ops::{Generator, GeneratorState}; + +#[derive(Copy, Clone)] +pub struct AccessAction(*mut dyn FnMut()); + +impl AccessAction { + pub fn get(self) -> *mut dyn FnMut() { + self.0 + } +} + +#[derive(Copy, Clone)] +pub enum Action { + Access(AccessAction), + Complete, +} + +thread_local!(pub static BOX_REGION_ARG: Cell = Cell::new(Action::Complete)); + +pub struct PinnedGenerator { + generator: Pin, Return = R>>> +} + +impl PinnedGenerator { + pub fn new< + T: Generator, Return = R> + 'static + >(generator: T) -> (I, Self) { + let mut result = PinnedGenerator { + generator: Box::pin(generator) + }; + + // Run it to the first yield to set it up + let init = match Pin::new(&mut result.generator).resume() { + GeneratorState::Yielded( + YieldType::Initial(y) + ) => y, + _ => panic!() + }; + + (init, result) + } + + pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) { + BOX_REGION_ARG.with(|i| { + i.set(Action::Access(AccessAction(closure))); + }); + + // Call the generator, which in turn will call the closure in BOX_REGION_ARG + if let GeneratorState::Complete(_) = Pin::new(&mut self.generator).resume() { + panic!() + } + } + + pub fn complete(&mut self) -> R { + // Tell the generator we want it to complete, consuming it and yielding a result + BOX_REGION_ARG.with(|i| { + i.set(Action::Complete) + }); + + let result = Pin::new(&mut self.generator).resume(); + if let GeneratorState::Complete(r) = result { + r + } else { + panic!() + } + } +} + +#[derive(PartialEq)] +pub struct Marker(PhantomData); + +impl Marker { + pub unsafe fn new() -> Self { + Marker(PhantomData) + } +} + +pub enum YieldType { + Initial(I), + Accessor(Marker), +} + +#[macro_export] +#[allow_internal_unstable(fn_traits)] +macro_rules! declare_box_region_type { + (impl $v:vis + $name: ident, + $yield_type:ty, + for($($lifetimes:tt)*), + ($($args:ty),*) -> ($reti:ty, $retc:ty) + ) => { + $v struct $name($crate::box_region::PinnedGenerator< + $reti, + for<$($lifetimes)*> fn(($($args,)*)), + $retc + >); + + impl $name { + fn new + 'static>( + generator: T + ) -> ($reti, Self) { + let (initial, pinned) = $crate::box_region::PinnedGenerator::new(generator); + (initial, $name(pinned)) + } + + $v fn access FnOnce($($args,)*) -> R, R>(&mut self, f: F) -> R { + // Turn the FnOnce closure into *mut dyn FnMut() + // so we can pass it in to the generator using the BOX_REGION_ARG thread local + let mut r = None; + let mut f = Some(f); + let mut_f: &mut dyn for<$($lifetimes)*> FnMut(($($args,)*)) = + &mut |args| { + let f = f.take().unwrap(); + r = Some(FnOnce::call_once(f, args)); + }; + let mut_f = mut_f as *mut dyn for<$($lifetimes)*> FnMut(($($args,)*)); + + // Get the generator to call our closure + unsafe { + self.0.access(::std::mem::transmute(mut_f)); + } + + // Unwrap the result + r.unwrap() + } + + $v fn complete(mut self) -> $retc { + self.0.complete() + } + + fn initial_yield(value: $reti) -> $yield_type { + $crate::box_region::YieldType::Initial(value) + } + } + }; + + ($v:vis $name: ident, for($($lifetimes:tt)*), ($($args:ty),*) -> ($reti:ty, $retc:ty)) => { + declare_box_region_type!( + impl $v $name, + $crate::box_region::YieldType<$reti, for<$($lifetimes)*> fn(($($args,)*))>, + for($($lifetimes)*), + ($($args),*) -> ($reti, $retc) + ); + }; +} + +#[macro_export] +#[allow_internal_unstable(fn_traits)] +macro_rules! box_region_allow_access { + (for($($lifetimes:tt)*), ($($args:ty),*), ($($exprs:expr),*) ) => { + loop { + match $crate::box_region::BOX_REGION_ARG.with(|i| i.get()) { + $crate::box_region::Action::Access(accessor) => { + let accessor: &mut dyn for<$($lifetimes)*> FnMut($($args),*) = unsafe { + ::std::mem::transmute(accessor.get()) + }; + (*accessor)(($($exprs),*)); + unsafe { + let marker = $crate::box_region::Marker::< + for<$($lifetimes)*> fn(($($args,)*)) + >::new(); + yield $crate::box_region::YieldType::Accessor(marker) + }; + } + $crate::box_region::Action::Complete => break, + } + } + } +} diff --git a/src/librustc_data_structures/fingerprint.rs b/src/librustc_data_structures/fingerprint.rs index c4c0db5801209..7975c62b90fb6 100644 --- a/src/librustc_data_structures/fingerprint.rs +++ b/src/librustc_data_structures/fingerprint.rs @@ -39,8 +39,8 @@ impl Fingerprint { // you want. #[inline] pub fn combine_commutative(self, other: Fingerprint) -> Fingerprint { - let a = (self.1 as u128) << 64 | self.0 as u128; - let b = (other.1 as u128) << 64 | other.0 as u128; + let a = u128::from(self.1) << 64 | u128::from(self.0); + let b = u128::from(other.1) << 64 | u128::from(other.0); let c = a.wrapping_add(b); diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index 255c5fd7fe7ec..b63701dbc0967 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -44,7 +44,6 @@ cfg_if! { } #[cfg(any(target_os = "dragonfly", - target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] mod os { diff --git a/src/librustc_data_structures/fx.rs b/src/librustc_data_structures/fx.rs index a2afeffe73050..cf73fe8cf85ce 100644 --- a/src/librustc_data_structures/fx.rs +++ b/src/librustc_data_structures/fx.rs @@ -1 +1,6 @@ +use std::hash::BuildHasherDefault; + pub use rustc_hash::{FxHasher, FxHashMap, FxHashSet}; + +pub type FxIndexMap = indexmap::IndexMap>; +pub type FxIndexSet = indexmap::IndexSet>; diff --git a/src/librustc_data_structures/graph/dominators/mod.rs b/src/librustc_data_structures/graph/dominators/mod.rs index aaed41d9fa362..93a2a261c6fde 100644 --- a/src/librustc_data_structures/graph/dominators/mod.rs +++ b/src/librustc_data_structures/graph/dominators/mod.rs @@ -8,8 +8,6 @@ use super::super::indexed_vec::{Idx, IndexVec}; use super::iterate::reverse_post_order; use super::ControlFlowGraph; -use std::fmt; - #[cfg(test)] mod test; @@ -158,48 +156,3 @@ impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> { } } } - -pub struct DominatorTree { - root: N, - children: IndexVec>, -} - -impl DominatorTree { - pub fn children(&self, node: Node) -> &[Node] { - &self.children[node] - } -} - -impl fmt::Debug for DominatorTree { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt( - &DominatorTreeNode { - tree: self, - node: self.root, - }, - fmt, - ) - } -} - -struct DominatorTreeNode<'tree, Node: Idx> { - tree: &'tree DominatorTree, - node: Node, -} - -impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let subtrees: Vec<_> = self.tree - .children(self.node) - .iter() - .map(|&child| DominatorTreeNode { - tree: self.tree, - node: child, - }) - .collect(); - fmt.debug_tuple("") - .field(&self.node) - .field(&subtrees) - .finish() - } -} diff --git a/src/librustc_data_structures/graph/iterate/mod.rs b/src/librustc_data_structures/graph/iterate/mod.rs index c09364b0a5395..5612778ce07ed 100644 --- a/src/librustc_data_structures/graph/iterate/mod.rs +++ b/src/librustc_data_structures/graph/iterate/mod.rs @@ -1,5 +1,6 @@ use super::super::indexed_vec::IndexVec; -use super::{DirectedGraph, WithSuccessors, WithNumNodes}; +use super::{DirectedGraph, WithNumNodes, WithSuccessors}; +use crate::bit_set::BitSet; #[cfg(test)] mod test; @@ -51,3 +52,36 @@ pub fn reverse_post_order( vec.reverse(); vec } + +/// A "depth-first search" iterator for a directed graph. +pub struct DepthFirstSearch<'graph, G> +where + G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, +{ + graph: &'graph G, + stack: Vec, + visited: BitSet, +} + +impl DepthFirstSearch<'graph, G> +where + G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, +{ + pub fn new(graph: &'graph G, start_node: G::Node) -> Self { + Self { graph, stack: vec![start_node], visited: BitSet::new_empty(graph.num_nodes()) } + } +} + +impl Iterator for DepthFirstSearch<'_, G> +where + G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, +{ + type Item = G::Node; + + fn next(&mut self) -> Option { + let DepthFirstSearch { stack, visited, graph } = self; + let n = stack.pop()?; + stack.extend(graph.successors(n).filter(|&m| visited.insert(m))); + Some(n) + } +} diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 3d47b7d49fb96..2787fa3c6b1e4 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -5,6 +5,7 @@ pub mod implementation; pub mod iterate; mod reference; pub mod scc; +pub mod vec_graph; #[cfg(test)] mod test; @@ -17,6 +18,10 @@ pub trait WithNumNodes: DirectedGraph { fn num_nodes(&self) -> usize; } +pub trait WithNumEdges: DirectedGraph { + fn num_edges(&self) -> usize; +} + pub trait WithSuccessors: DirectedGraph where Self: for<'graph> GraphSuccessors<'graph, Item = ::Node>, @@ -25,6 +30,13 @@ where &'graph self, node: Self::Node, ) -> >::Iter; + + fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self> + where + Self: WithNumNodes, + { + iterate::DepthFirstSearch::new(self, from) + } } pub trait GraphSuccessors<'graph> { diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs index 24c5448639e7d..78554cda77b44 100644 --- a/src/librustc_data_structures/graph/scc/mod.rs +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -4,7 +4,8 @@ //! O(n) time. use crate::fx::FxHashSet; -use crate::graph::{DirectedGraph, WithNumNodes, WithSuccessors}; +use crate::graph::{DirectedGraph, WithNumNodes, WithNumEdges, WithSuccessors, GraphSuccessors}; +use crate::graph::vec_graph::VecGraph; use crate::indexed_vec::{Idx, IndexVec}; use std::ops::Range; @@ -58,6 +59,49 @@ impl Sccs { pub fn successors(&self, scc: S) -> &[S] { self.scc_data.successors(scc) } + + /// Construct the reverse graph of the SCC graph. + pub fn reverse(&self) -> VecGraph { + VecGraph::new( + self.num_sccs(), + self.all_sccs() + .flat_map(|source| self.successors(source).iter().map(move |&target| { + (target, source) + })) + .collect(), + ) + } +} + +impl DirectedGraph for Sccs { + type Node = S; +} + +impl WithNumNodes for Sccs { + fn num_nodes(&self) -> usize { + self.num_sccs() + } +} + +impl WithNumEdges for Sccs { + fn num_edges(&self) -> usize { + self.scc_data.all_successors.len() + } +} + +impl GraphSuccessors<'graph> for Sccs { + type Item = S; + + type Iter = std::iter::Cloned>; +} + +impl WithSuccessors for Sccs { + fn successors<'graph>( + &'graph self, + node: S + ) -> >::Iter { + self.successors(node).iter().cloned() + } } impl SccData { diff --git a/src/librustc_data_structures/graph/vec_graph/mod.rs b/src/librustc_data_structures/graph/vec_graph/mod.rs new file mode 100644 index 0000000000000..6fb1bb42d2cfd --- /dev/null +++ b/src/librustc_data_structures/graph/vec_graph/mod.rs @@ -0,0 +1,113 @@ +use crate::indexed_vec::{Idx, IndexVec}; +use crate::graph::{DirectedGraph, WithNumNodes, WithNumEdges, WithSuccessors, GraphSuccessors}; + +#[cfg(test)] +mod test; + +pub struct VecGraph { + /// Maps from a given node to an index where the set of successors + /// for that node starts. The index indexes into the `edges` + /// vector. To find the range for a given node, we look up the + /// start for that node and then the start for the next node + /// (i.e., with an index 1 higher) and get the range between the + /// two. This vector always has an extra entry so that this works + /// even for the max element. + node_starts: IndexVec, + + edge_targets: Vec, +} + +impl VecGraph { + pub fn new( + num_nodes: usize, + mut edge_pairs: Vec<(N, N)>, + ) -> Self { + // Sort the edges by the source -- this is important. + edge_pairs.sort(); + + let num_edges = edge_pairs.len(); + + // Store the *target* of each edge into `edge_targets`. + let edge_targets: Vec = edge_pairs.iter().map(|&(_, target)| target).collect(); + + // Create the *edge starts* array. We are iterating over over + // the (sorted) edge pairs. We maintain the invariant that the + // length of the `node_starts` arary is enough to store the + // current source node -- so when we see that the source node + // for an edge is greater than the current length, we grow the + // edge-starts array by just enough. + let mut node_starts = IndexVec::with_capacity(num_edges); + for (index, &(source, _)) in edge_pairs.iter().enumerate() { + // If we have a list like `[(0, x), (2, y)]`: + // + // - Start out with `node_starts` of `[]` + // - Iterate to `(0, x)` at index 0: + // - Push one entry because `node_starts.len()` (0) is <= the source (0) + // - Leaving us with `node_starts` of `[0]` + // - Iterate to `(2, y)` at index 1: + // - Push one entry because `node_starts.len()` (1) is <= the source (2) + // - Push one entry because `node_starts.len()` (2) is <= the source (2) + // - Leaving us with `node_starts` of `[0, 1, 1]` + // - Loop terminates + while node_starts.len() <= source.index() { + node_starts.push(index); + } + } + + // Pad out the `node_starts` array so that it has `num_nodes + + // 1` entries. Continuing our example above, if `num_nodes` is + // be `3`, we would push one more index: `[0, 1, 1, 2]`. + // + // Interpretation of that vector: + // + // [0, 1, 1, 2] + // ---- range for N=2 + // ---- range for N=1 + // ---- range for N=0 + while node_starts.len() <= num_nodes { + node_starts.push(edge_targets.len()); + } + + assert_eq!(node_starts.len(), num_nodes + 1); + + Self { node_starts, edge_targets } + } + + /// Gets the successors for `source` as a slice. + pub fn successors(&self, source: N) -> &[N] { + let start_index = self.node_starts[source]; + let end_index = self.node_starts[source.plus(1)]; + &self.edge_targets[start_index..end_index] + } +} + +impl DirectedGraph for VecGraph { + type Node = N; +} + +impl WithNumNodes for VecGraph { + fn num_nodes(&self) -> usize { + self.node_starts.len() - 1 + } +} + +impl WithNumEdges for VecGraph { + fn num_edges(&self) -> usize { + self.edge_targets.len() + } +} + +impl GraphSuccessors<'graph> for VecGraph { + type Item = N; + + type Iter = std::iter::Cloned>; +} + +impl WithSuccessors for VecGraph { + fn successors<'graph>( + &'graph self, + node: N + ) -> >::Iter { + self.successors(node).iter().cloned() + } +} diff --git a/src/librustc_data_structures/graph/vec_graph/test.rs b/src/librustc_data_structures/graph/vec_graph/test.rs new file mode 100644 index 0000000000000..97a9bd2ad0b08 --- /dev/null +++ b/src/librustc_data_structures/graph/vec_graph/test.rs @@ -0,0 +1,51 @@ +use super::*; + +fn create_graph() -> VecGraph { + // Create a simple graph + // + // 5 + // | + // V + // 0 --> 1 --> 2 + // | + // v + // 3 --> 4 + // + // 6 + + VecGraph::new( + 7, + vec![ + (0, 1), + (1, 2), + (1, 3), + (3, 4), + (5, 1), + ], + ) +} + +#[test] +fn num_nodes() { + let graph = create_graph(); + assert_eq!(graph.num_nodes(), 7); +} + +#[test] +fn succesors() { + let graph = create_graph(); + assert_eq!(graph.successors(0), &[1]); + assert_eq!(graph.successors(1), &[2, 3]); + assert_eq!(graph.successors(2), &[]); + assert_eq!(graph.successors(3), &[4]); + assert_eq!(graph.successors(4), &[]); + assert_eq!(graph.successors(5), &[1]); + assert_eq!(graph.successors(6), &[]); +} + +#[test] +fn dfs() { + let graph = create_graph(); + let dfs: Vec<_> = graph.depth_first_search(0).collect(); + assert_eq!(dfs, vec![0, 1, 3, 4, 2]); +} diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 09aec50e4bb11..b3a810a622d03 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -19,8 +19,11 @@ pub trait Idx: Copy + 'static + Ord + Debug + Hash { fn index(self) -> usize; fn increment_by(&mut self, amount: usize) { - let v = self.index() + amount; - *self = Self::new(v); + *self = self.plus(amount); + } + + fn plus(self, amount: usize) -> Self { + Self::new(self.index() + amount) } } @@ -58,9 +61,10 @@ macro_rules! newtype_index { // ---- public rules ---- // Use default constants - ($v:vis struct $name:ident { .. }) => ( + ($(#[$attrs:meta])* $v:vis struct $name:ident { .. }) => ( newtype_index!( // Leave out derives marker so we can use its absence to ensure it comes first + @attrs [$(#[$attrs])*] @type [$name] // shave off 256 indices at the end to allow space for packing these indices into enums @max [0xFFFF_FF00] @@ -69,9 +73,10 @@ macro_rules! newtype_index { ); // Define any constants - ($v:vis struct $name:ident { $($tokens:tt)+ }) => ( + ($(#[$attrs:meta])* $v:vis struct $name:ident { $($tokens:tt)+ }) => ( newtype_index!( // Leave out derives marker so we can use its absence to ensure it comes first + @attrs [$(#[$attrs])*] @type [$name] // shave off 256 indices at the end to allow space for packing these indices into enums @max [0xFFFF_FF00] @@ -84,10 +89,12 @@ macro_rules! newtype_index { // Base case, user-defined constants (if any) have already been defined (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] @type [$type:ident] @max [$max:expr] @vis [$v:vis] @debug_format [$debug_format:tt]) => ( + $(#[$attrs])* #[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)] #[rustc_layout_scalar_valid_range_end($max)] $v struct $type { @@ -163,6 +170,14 @@ macro_rules! newtype_index { } } + impl std::ops::Add for $type { + type Output = Self; + + fn add(self, other: usize) -> Self { + Self::new(self.index() + other) + } + } + impl Idx for $type { #[inline] fn new(value: usize) -> Self { @@ -208,6 +223,11 @@ macro_rules! newtype_index { fn add_usize(&self, u: usize) -> Option { Idx::index(*self).checked_add(u).map(Self::new) } + + #[inline] + fn sub_usize(&self, u: usize) -> Option { + Idx::index(*self).checked_sub(u).map(Self::new) + } } impl From<$type> for u32 { @@ -282,13 +302,15 @@ macro_rules! newtype_index { ); // Append comma to end of derives list if it's missing - (@type [$type:ident] + (@attrs [$(#[$attrs:meta])*] + @type [$type:ident] @max [$max:expr] @vis [$v:vis] @debug_format [$debug_format:tt] derive [$($derives:ident),*] $($tokens:tt)*) => ( newtype_index!( + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -299,7 +321,8 @@ macro_rules! newtype_index { // By not including the @derives marker in this list nor in the default args, we can force it // to come first if it exists. When encodable is custom, just use the derives list as-is. - (@type [$type:ident] + (@attrs [$(#[$attrs:meta])*] + @type [$type:ident] @max [$max:expr] @vis [$v:vis] @debug_format [$debug_format:tt] @@ -307,6 +330,7 @@ macro_rules! newtype_index { ENCODABLE = custom $($tokens:tt)*) => ( newtype_index!( + @attrs [$(#[$attrs])*] @derives [$($derives,)+] @type [$type] @max [$max] @@ -317,7 +341,8 @@ macro_rules! newtype_index { // By not including the @derives marker in this list nor in the default args, we can force it // to come first if it exists. When encodable isn't custom, add serialization traits by default. - (@type [$type:ident] + (@attrs [$(#[$attrs:meta])*] + @type [$type:ident] @max [$max:expr] @vis [$v:vis] @debug_format [$debug_format:tt] @@ -325,6 +350,7 @@ macro_rules! newtype_index { $($tokens:tt)*) => ( newtype_index!( @derives [$($derives,)+ RustcEncodable,] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -335,7 +361,8 @@ macro_rules! newtype_index { // The case where no derives are added, but encodable is overridden. Don't // derive serialization traits - (@type [$type:ident] + (@attrs [$(#[$attrs:meta])*] + @type [$type:ident] @max [$max:expr] @vis [$v:vis] @debug_format [$debug_format:tt] @@ -343,6 +370,7 @@ macro_rules! newtype_index { $($tokens:tt)*) => ( newtype_index!( @derives [] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -351,13 +379,15 @@ macro_rules! newtype_index { ); // The case where no derives are added, add serialization derives by default - (@type [$type:ident] + (@attrs [$(#[$attrs:meta])*] + @type [$type:ident] @max [$max:expr] @vis [$v:vis] @debug_format [$debug_format:tt] $($tokens:tt)*) => ( newtype_index!( @derives [RustcEncodable,] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -384,6 +414,7 @@ macro_rules! newtype_index { // Rewrite final without comma to one that includes comma (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] @type [$type:ident] @max [$max:expr] @vis [$v:vis] @@ -391,6 +422,7 @@ macro_rules! newtype_index { $name:ident = $constant:expr) => ( newtype_index!( @derives [$($derives,)*] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -400,14 +432,16 @@ macro_rules! newtype_index { // Rewrite final const without comma to one that includes comma (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] @type [$type:ident] - @max [$_max:expr] + @max [$max:expr] @vis [$v:vis] @debug_format [$debug_format:tt] $(#[doc = $doc:expr])* const $name:ident = $constant:expr) => ( newtype_index!( @derives [$($derives,)*] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -417,6 +451,7 @@ macro_rules! newtype_index { // Replace existing default for max (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] @type [$type:ident] @max [$_max:expr] @vis [$v:vis] @@ -425,6 +460,7 @@ macro_rules! newtype_index { $($tokens:tt)*) => ( newtype_index!( @derives [$($derives,)*] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -434,6 +470,7 @@ macro_rules! newtype_index { // Replace existing default for debug_format (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] @type [$type:ident] @max [$max:expr] @vis [$v:vis] @@ -442,6 +479,7 @@ macro_rules! newtype_index { $($tokens:tt)*) => ( newtype_index!( @derives [$($derives,)*] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -451,6 +489,7 @@ macro_rules! newtype_index { // Assign a user-defined constant (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] @type [$type:ident] @max [$max:expr] @vis [$v:vis] @@ -462,6 +501,7 @@ macro_rules! newtype_index { pub const $name: $type = $type::from_u32_const($constant); newtype_index!( @derives [$($derives,)*] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] diff --git a/src/librustc_data_structures/jobserver.rs b/src/librustc_data_structures/jobserver.rs index 48ac8125a0d66..b42ccb932b9dc 100644 --- a/src/librustc_data_structures/jobserver.rs +++ b/src/librustc_data_structures/jobserver.rs @@ -1,89 +1,5 @@ -use jobserver_crate::{Client, HelperThread, Acquired}; +use jobserver_crate::Client; use lazy_static::lazy_static; -use std::sync::{Condvar, Arc, Mutex}; -use std::mem; - -#[derive(Default)] -struct LockedProxyData { - /// The number of free thread tokens, this may include the implicit token given to the process - free: usize, - - /// The number of threads waiting for a token - waiters: usize, - - /// The number of tokens we requested from the server - requested: usize, - - /// Stored tokens which will be dropped when we no longer need them - tokens: Vec, -} - -impl LockedProxyData { - fn request_token(&mut self, thread: &Mutex) { - self.requested += 1; - thread.lock().unwrap().request_token(); - } - - fn release_token(&mut self, cond_var: &Condvar) { - if self.waiters > 0 { - self.free += 1; - cond_var.notify_one(); - } else { - if self.tokens.is_empty() { - // We are returning the implicit token - self.free += 1; - } else { - // Return a real token to the server - self.tokens.pop().unwrap(); - } - } - } - - fn take_token(&mut self, thread: &Mutex) -> bool { - if self.free > 0 { - self.free -= 1; - self.waiters -= 1; - - // We stole some token reqested by someone else - // Request another one - if self.requested + self.free < self.waiters { - self.request_token(thread); - } - - true - } else { - false - } - } - - fn new_requested_token(&mut self, token: Acquired, cond_var: &Condvar) { - self.requested -= 1; - - // Does anything need this token? - if self.waiters > 0 { - self.free += 1; - self.tokens.push(token); - cond_var.notify_one(); - } else { - // Otherwise we'll just drop it - mem::drop(token); - } - } -} - -#[derive(Default)] -struct ProxyData { - lock: Mutex, - cond_var: Condvar, -} - -/// A helper type which makes managing jobserver tokens easier. -/// It also allows you to treat the implicit token given to the process -/// in the same manner as requested tokens. -struct Proxy { - thread: Mutex, - data: Arc, -} lazy_static! { // We can only call `from_env` once per process @@ -105,20 +21,12 @@ lazy_static! { // per-process. static ref GLOBAL_CLIENT: Client = unsafe { Client::from_env().unwrap_or_else(|| { - Client::new(32).expect("failed to create jobserver") + let client = Client::new(32).expect("failed to create jobserver"); + // Acquire a token for the main thread which we can release later + client.acquire_raw().ok(); + client }) }; - - static ref GLOBAL_PROXY: Proxy = { - let data = Arc::new(ProxyData::default()); - - Proxy { - data: data.clone(), - thread: Mutex::new(client().into_helper_thread(move |token| { - data.lock.lock().unwrap().new_requested_token(token.unwrap(), &data.cond_var); - }).unwrap()), - } - }; } pub fn client() -> Client { @@ -126,31 +34,9 @@ pub fn client() -> Client { } pub fn acquire_thread() { - GLOBAL_PROXY.acquire_token(); + GLOBAL_CLIENT.acquire_raw().ok(); } pub fn release_thread() { - GLOBAL_PROXY.release_token(); -} - -impl Proxy { - fn release_token(&self) { - self.data.lock.lock().unwrap().release_token(&self.data.cond_var); - } - - fn acquire_token(&self) { - let mut data = self.data.lock.lock().unwrap(); - data.waiters += 1; - if data.take_token(&self.thread) { - return; - } - // Request a token for us - data.request_token(&self.thread); - loop { - data = self.data.cond_var.wait(data).unwrap(); - if data.take_token(&self.thread) { - return; - } - } - } + GLOBAL_CLIENT.release_raw().ok(); } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 09482340b1a1d..98c809f7e2595 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -10,6 +10,8 @@ #![feature(in_band_lifetimes)] #![feature(unboxed_closures)] +#![feature(generators)] +#![feature(generator_trait)] #![feature(fn_traits)] #![feature(unsize)] #![feature(specialization)] @@ -70,7 +72,9 @@ macro_rules! unlikely { pub mod macros; pub mod svh; pub mod base_n; +pub mod binary_search_util; pub mod bit_set; +pub mod box_region; pub mod const_cstr; pub mod flock; pub mod fx; diff --git a/src/librustc_data_structures/macros.rs b/src/librustc_data_structures/macros.rs index af1f2910461ec..6e7a8e98853c0 100644 --- a/src/librustc_data_structures/macros.rs +++ b/src/librustc_data_structures/macros.rs @@ -1,13 +1,21 @@ -/// A simple static assertion macro. The first argument should be a unique -/// ALL_CAPS identifier that describes the condition. +/// A simple static assertion macro. #[macro_export] -#[cfg_attr(stage0, allow_internal_unstable)] -#[cfg_attr(not(stage0), allow_internal_unstable(type_ascription))] +#[cfg_attr(bootstrap, allow_internal_unstable(type_ascription, underscore_const_names))] +#[cfg_attr(not(bootstrap), allow_internal_unstable(type_ascription))] macro_rules! static_assert { - ($name:ident: $test:expr) => { + ($test:expr) => { // Use the bool to access an array such that if the bool is false, the access // is out-of-bounds. #[allow(dead_code)] - static $name: () = [()][!($test: bool) as usize]; + const _: () = [()][!($test: bool) as usize]; + } +} + +/// Type size assertion. The first argument is a type and the second argument is its expected size. +#[macro_export] +#[cfg_attr(bootstrap, allow_internal_unstable(underscore_const_names))] +macro_rules! static_assert_size { + ($ty:ty, $size:expr) => { + const _: [(); $size] = [(); ::std::mem::size_of::<$ty>()]; } } diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 4490e5f86d2bd..557e5e2186f11 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -263,7 +263,7 @@ impl ObligationForest { done_cache: Default::default(), waiting_cache: Default::default(), scratch: Some(vec![]), - obligation_tree_id_generator: (0..).map(|i| ObligationTreeId(i)), + obligation_tree_id_generator: (0..).map(ObligationTreeId), error_cache: Default::default(), } } diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/src/librustc_data_structures/owning_ref/mod.rs index 236559dcd7c10..a7af615fa5000 100644 --- a/src/librustc_data_structures/owning_ref/mod.rs +++ b/src/librustc_data_structures/owning_ref/mod.rs @@ -1221,717 +1221,4 @@ pub type ErasedArcRef = OwningRef, U>; pub type ErasedBoxRefMut = OwningRefMut, U>; #[cfg(test)] -mod tests { - mod owning_ref { - use super::super::OwningRef; - use super::super::{RcRef, BoxRef, Erased, ErasedBoxRef}; - use std::cmp::{PartialEq, Ord, PartialOrd, Ordering}; - use std::hash::{Hash, Hasher}; - use std::collections::hash_map::DefaultHasher; - use std::collections::HashMap; - use std::rc::Rc; - - #[derive(Debug, PartialEq)] - struct Example(u32, String, [u8; 3]); - fn example() -> Example { - Example(42, "hello world".to_string(), [1, 2, 3]) - } - - #[test] - fn new_deref() { - let or: OwningRef, ()> = OwningRef::new(Box::new(())); - assert_eq!(&*or, &()); - } - - #[test] - fn into() { - let or: OwningRef, ()> = Box::new(()).into(); - assert_eq!(&*or, &()); - } - - #[test] - fn map_offset_ref() { - let or: BoxRef = Box::new(example()).into(); - let or: BoxRef<_, u32> = or.map(|x| &x.0); - assert_eq!(&*or, &42); - - let or: BoxRef = Box::new(example()).into(); - let or: BoxRef<_, u8> = or.map(|x| &x.2[1]); - assert_eq!(&*or, &2); - } - - #[test] - fn map_heap_ref() { - let or: BoxRef = Box::new(example()).into(); - let or: BoxRef<_, str> = or.map(|x| &x.1[..5]); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_static_ref() { - let or: BoxRef<()> = Box::new(()).into(); - let or: BoxRef<_, str> = or.map(|_| "hello"); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_chained() { - let or: BoxRef = Box::new(example().1).into(); - let or: BoxRef<_, str> = or.map(|x| &x[1..5]); - let or: BoxRef<_, str> = or.map(|x| &x[..2]); - assert_eq!(&*or, "el"); - } - - #[test] - fn map_chained_inference() { - let or = BoxRef::new(Box::new(example().1)) - .map(|x| &x[..5]) - .map(|x| &x[1..3]); - assert_eq!(&*or, "el"); - } - - #[test] - fn owner() { - let or: BoxRef = Box::new(example().1).into(); - let or = or.map(|x| &x[..5]); - assert_eq!(&*or, "hello"); - assert_eq!(&**or.owner(), "hello world"); - } - - #[test] - fn into_inner() { - let or: BoxRef = Box::new(example().1).into(); - let or = or.map(|x| &x[..5]); - assert_eq!(&*or, "hello"); - let s = *or.into_inner(); - assert_eq!(&s, "hello world"); - } - - #[test] - fn fmt_debug() { - let or: BoxRef = Box::new(example().1).into(); - let or = or.map(|x| &x[..5]); - let s = format!("{:?}", or); - assert_eq!(&s, "OwningRef { owner: \"hello world\", reference: \"hello\" }"); - } - - #[test] - fn erased_owner() { - let o1: BoxRef = BoxRef::new(Box::new(example())) - .map(|x| &x.1[..]); - - let o2: BoxRef = BoxRef::new(Box::new(example().1)) - .map(|x| &x[..]); - - let os: Vec> = vec![o1.erase_owner(), o2.erase_owner()]; - assert!(os.iter().all(|e| &e[..] == "hello world")); - } - - #[test] - fn raii_locks() { - use super::super::{RefRef, RefMutRef}; - use std::cell::RefCell; - use super::super::{MutexGuardRef, RwLockReadGuardRef, RwLockWriteGuardRef}; - use std::sync::{Mutex, RwLock}; - - { - let a = RefCell::new(1); - let a = { - let a = RefRef::new(a.borrow()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = RefCell::new(1); - let a = { - let a = RefMutRef::new(a.borrow_mut()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = Mutex::new(1); - let a = { - let a = MutexGuardRef::new(a.lock().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = RwLock::new(1); - let a = { - let a = RwLockReadGuardRef::new(a.read().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = RwLock::new(1); - let a = { - let a = RwLockWriteGuardRef::new(a.write().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - } - - #[test] - fn eq() { - let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - assert_eq!(or1.eq(&or2), true); - } - - #[test] - fn cmp() { - let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice()); - assert_eq!(or1.cmp(&or2), Ordering::Less); - } - - #[test] - fn partial_cmp() { - let or1: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice()); - let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater)); - } - - #[test] - fn hash() { - let mut h1 = DefaultHasher::new(); - let mut h2 = DefaultHasher::new(); - - let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - - or1.hash(&mut h1); - or2.hash(&mut h2); - - assert_eq!(h1.finish(), h2.finish()); - } - - #[test] - fn borrow() { - let mut hash = HashMap::new(); - let key = RcRef::::new(Rc::new("foo-bar".to_string())).map(|s| &s[..]); - - hash.insert(key.clone().map(|s| &s[..3]), 42); - hash.insert(key.clone().map(|s| &s[4..]), 23); - - assert_eq!(hash.get("foo"), Some(&42)); - assert_eq!(hash.get("bar"), Some(&23)); - } - - #[test] - fn total_erase() { - let a: OwningRef, [u8]> - = OwningRef::new(vec![]).map(|x| &x[..]); - let b: OwningRef, [u8]> - = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]); - - let c: OwningRef>, [u8]> = unsafe {a.map_owner(Rc::new)}; - let d: OwningRef>, [u8]> = unsafe {b.map_owner(Rc::new)}; - - let e: OwningRef, [u8]> = c.erase_owner(); - let f: OwningRef, [u8]> = d.erase_owner(); - - let _g = e.clone(); - let _h = f.clone(); - } - - #[test] - fn total_erase_box() { - let a: OwningRef, [u8]> - = OwningRef::new(vec![]).map(|x| &x[..]); - let b: OwningRef, [u8]> - = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]); - - let c: OwningRef>, [u8]> = a.map_owner_box(); - let d: OwningRef>, [u8]> = b.map_owner_box(); - - let _e: OwningRef, [u8]> = c.erase_owner(); - let _f: OwningRef, [u8]> = d.erase_owner(); - } - - #[test] - fn try_map1() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - OwningRef::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_ok(); - } - - #[test] - fn try_map2() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - OwningRef::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_err(); - } - } - - mod owning_handle { - use super::super::OwningHandle; - use super::super::RcRef; - use std::rc::Rc; - use std::cell::RefCell; - use std::sync::Arc; - use std::sync::RwLock; - - #[test] - fn owning_handle() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let mut handle = OwningHandle::new_with_fn(cell_ref, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); - assert_eq!(*handle, 2); - *handle = 3; - assert_eq!(*handle, 3); - } - - #[test] - fn try_owning_handle_ok() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let mut handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| { - Ok(unsafe { - x.as_ref() - }.unwrap().borrow_mut()) - }).unwrap(); - assert_eq!(*handle, 2); - *handle = 3; - assert_eq!(*handle, 3); - } - - #[test] - fn try_owning_handle_err() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| { - if false { - return Ok(unsafe { - x.as_ref() - }.unwrap().borrow_mut()) - } - Err(()) - }); - assert!(handle.is_err()); - } - - #[test] - fn nested() { - use std::cell::RefCell; - use std::sync::{Arc, RwLock}; - - let result = { - let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString")))); - let curr = RcRef::new(complex); - let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); - let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap()); - assert_eq!(*curr, "someString"); - *curr = "someOtherString"; - curr - }; - assert_eq!(*result, "someOtherString"); - } - - #[test] - fn owning_handle_safe() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let handle = OwningHandle::new(cell_ref); - assert_eq!(*handle, 2); - } - - #[test] - fn owning_handle_mut_safe() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let mut handle = OwningHandle::new_mut(cell_ref); - assert_eq!(*handle, 2); - *handle = 3; - assert_eq!(*handle, 3); - } - - #[test] - fn owning_handle_safe_2() { - let result = { - let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString")))); - let curr = RcRef::new(complex); - let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); - let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap()); - assert_eq!(*curr, "someString"); - *curr = "someOtherString"; - curr - }; - assert_eq!(*result, "someOtherString"); - } - } - - mod owning_ref_mut { - use super::super::{OwningRefMut, BoxRefMut, Erased, ErasedBoxRefMut}; - use super::super::BoxRef; - use std::cmp::{PartialEq, Ord, PartialOrd, Ordering}; - use std::hash::{Hash, Hasher}; - use std::collections::hash_map::DefaultHasher; - use std::collections::HashMap; - - #[derive(Debug, PartialEq)] - struct Example(u32, String, [u8; 3]); - fn example() -> Example { - Example(42, "hello world".to_string(), [1, 2, 3]) - } - - #[test] - fn new_deref() { - let or: OwningRefMut, ()> = OwningRefMut::new(Box::new(())); - assert_eq!(&*or, &()); - } - - #[test] - fn new_deref_mut() { - let mut or: OwningRefMut, ()> = OwningRefMut::new(Box::new(())); - assert_eq!(&mut *or, &mut ()); - } - - #[test] - fn mutate() { - let mut or: OwningRefMut, usize> = OwningRefMut::new(Box::new(0)); - assert_eq!(&*or, &0); - *or = 1; - assert_eq!(&*or, &1); - } - - #[test] - fn into() { - let or: OwningRefMut, ()> = Box::new(()).into(); - assert_eq!(&*or, &()); - } - - #[test] - fn map_offset_ref() { - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRef<_, u32> = or.map(|x| &mut x.0); - assert_eq!(&*or, &42); - - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRef<_, u8> = or.map(|x| &mut x.2[1]); - assert_eq!(&*or, &2); - } - - #[test] - fn map_heap_ref() { - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRef<_, str> = or.map(|x| &mut x.1[..5]); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_static_ref() { - let or: BoxRefMut<()> = Box::new(()).into(); - let or: BoxRef<_, str> = or.map(|_| "hello"); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_mut_offset_ref() { - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRefMut<_, u32> = or.map_mut(|x| &mut x.0); - assert_eq!(&*or, &42); - - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRefMut<_, u8> = or.map_mut(|x| &mut x.2[1]); - assert_eq!(&*or, &2); - } - - #[test] - fn map_mut_heap_ref() { - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x.1[..5]); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_mut_static_ref() { - static mut MUT_S: [u8; 5] = *b"hello"; - - let mut_s: &'static mut [u8] = unsafe { &mut MUT_S }; - - let or: BoxRefMut<()> = Box::new(()).into(); - let or: BoxRefMut<_, [u8]> = or.map_mut(move |_| mut_s); - assert_eq!(&*or, b"hello"); - } - - #[test] - fn map_mut_chained() { - let or: BoxRefMut = Box::new(example().1).into(); - let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[1..5]); - let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[..2]); - assert_eq!(&*or, "el"); - } - - #[test] - fn map_chained_inference() { - let or = BoxRefMut::new(Box::new(example().1)) - .map_mut(|x| &mut x[..5]) - .map_mut(|x| &mut x[1..3]); - assert_eq!(&*or, "el"); - } - - #[test] - fn try_map_mut() { - let or: BoxRefMut = Box::new(example().1).into(); - let or: Result, ()> = or.try_map_mut(|x| Ok(&mut x[1..5])); - assert_eq!(&*or.unwrap(), "ello"); - - let or: BoxRefMut = Box::new(example().1).into(); - let or: Result, ()> = or.try_map_mut(|_| Err(())); - assert!(or.is_err()); - } - - #[test] - fn owner() { - let or: BoxRefMut = Box::new(example().1).into(); - let or = or.map_mut(|x| &mut x[..5]); - assert_eq!(&*or, "hello"); - assert_eq!(&**or.owner(), "hello world"); - } - - #[test] - fn into_inner() { - let or: BoxRefMut = Box::new(example().1).into(); - let or = or.map_mut(|x| &mut x[..5]); - assert_eq!(&*or, "hello"); - let s = *or.into_inner(); - assert_eq!(&s, "hello world"); - } - - #[test] - fn fmt_debug() { - let or: BoxRefMut = Box::new(example().1).into(); - let or = or.map_mut(|x| &mut x[..5]); - let s = format!("{:?}", or); - assert_eq!(&s, - "OwningRefMut { owner: \"hello world\", reference: \"hello\" }"); - } - - #[test] - fn erased_owner() { - let o1: BoxRefMut = BoxRefMut::new(Box::new(example())) - .map_mut(|x| &mut x.1[..]); - - let o2: BoxRefMut = BoxRefMut::new(Box::new(example().1)) - .map_mut(|x| &mut x[..]); - - let os: Vec> = vec![o1.erase_owner(), o2.erase_owner()]; - assert!(os.iter().all(|e| &e[..] == "hello world")); - } - - #[test] - fn raii_locks() { - use super::super::RefMutRefMut; - use std::cell::RefCell; - use super::super::{MutexGuardRefMut, RwLockWriteGuardRefMut}; - use std::sync::{Mutex, RwLock}; - - { - let a = RefCell::new(1); - let a = { - let a = RefMutRefMut::new(a.borrow_mut()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = Mutex::new(1); - let a = { - let a = MutexGuardRefMut::new(a.lock().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = RwLock::new(1); - let a = { - let a = RwLockWriteGuardRefMut::new(a.write().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - } - - #[test] - fn eq() { - let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - assert_eq!(or1.eq(&or2), true); - } - - #[test] - fn cmp() { - let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice()); - assert_eq!(or1.cmp(&or2), Ordering::Less); - } - - #[test] - fn partial_cmp() { - let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice()); - let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater)); - } - - #[test] - fn hash() { - let mut h1 = DefaultHasher::new(); - let mut h2 = DefaultHasher::new(); - - let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - - or1.hash(&mut h1); - or2.hash(&mut h2); - - assert_eq!(h1.finish(), h2.finish()); - } - - #[test] - fn borrow() { - let mut hash = HashMap::new(); - let key1 = BoxRefMut::::new(Box::new("foo".to_string())).map(|s| &s[..]); - let key2 = BoxRefMut::::new(Box::new("bar".to_string())).map(|s| &s[..]); - - hash.insert(key1, 42); - hash.insert(key2, 23); - - assert_eq!(hash.get("foo"), Some(&42)); - assert_eq!(hash.get("bar"), Some(&23)); - } - - #[test] - fn total_erase() { - let a: OwningRefMut, [u8]> - = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]); - let b: OwningRefMut, [u8]> - = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]); - - let c: OwningRefMut>, [u8]> = unsafe {a.map_owner(Box::new)}; - let d: OwningRefMut>, [u8]> = unsafe {b.map_owner(Box::new)}; - - let _e: OwningRefMut, [u8]> = c.erase_owner(); - let _f: OwningRefMut, [u8]> = d.erase_owner(); - } - - #[test] - fn total_erase_box() { - let a: OwningRefMut, [u8]> - = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]); - let b: OwningRefMut, [u8]> - = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]); - - let c: OwningRefMut>, [u8]> = a.map_owner_box(); - let d: OwningRefMut>, [u8]> = b.map_owner_box(); - - let _e: OwningRefMut, [u8]> = c.erase_owner(); - let _f: OwningRefMut, [u8]> = d.erase_owner(); - } - - #[test] - fn try_map1() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).is_ok(); - } - - #[test] - fn try_map2() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).is_err(); - } - - #[test] - fn try_map3() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - OwningRefMut::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_ok(); - } - - #[test] - fn try_map4() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - OwningRefMut::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_err(); - } - - #[test] - fn into_owning_ref() { - use super::super::BoxRef; - - let or: BoxRefMut<()> = Box::new(()).into(); - let or: BoxRef<()> = or.into(); - assert_eq!(&*or, &()); - } - - struct Foo { - u: u32, - } - struct Bar { - f: Foo, - } - - #[test] - fn ref_mut() { - use std::cell::RefCell; - - let a = RefCell::new(Bar { f: Foo { u: 42 } }); - let mut b = OwningRefMut::new(a.borrow_mut()); - assert_eq!(b.f.u, 42); - b.f.u = 43; - let mut c = b.map_mut(|x| &mut x.f); - assert_eq!(c.u, 43); - c.u = 44; - let mut d = c.map_mut(|x| &mut x.u); - assert_eq!(*d, 44); - *d = 45; - assert_eq!(*d, 45); - } - } -} +mod tests; diff --git a/src/librustc_data_structures/owning_ref/tests.rs b/src/librustc_data_structures/owning_ref/tests.rs new file mode 100644 index 0000000000000..d368219cab3eb --- /dev/null +++ b/src/librustc_data_structures/owning_ref/tests.rs @@ -0,0 +1,712 @@ +mod owning_ref { + use super::super::OwningRef; + use super::super::{RcRef, BoxRef, Erased, ErasedBoxRef}; + use std::cmp::{PartialEq, Ord, PartialOrd, Ordering}; + use std::hash::{Hash, Hasher}; + use std::collections::hash_map::DefaultHasher; + use std::collections::HashMap; + use std::rc::Rc; + + #[derive(Debug, PartialEq)] + struct Example(u32, String, [u8; 3]); + fn example() -> Example { + Example(42, "hello world".to_string(), [1, 2, 3]) + } + + #[test] + fn new_deref() { + let or: OwningRef, ()> = OwningRef::new(Box::new(())); + assert_eq!(&*or, &()); + } + + #[test] + fn into() { + let or: OwningRef, ()> = Box::new(()).into(); + assert_eq!(&*or, &()); + } + + #[test] + fn map_offset_ref() { + let or: BoxRef = Box::new(example()).into(); + let or: BoxRef<_, u32> = or.map(|x| &x.0); + assert_eq!(&*or, &42); + + let or: BoxRef = Box::new(example()).into(); + let or: BoxRef<_, u8> = or.map(|x| &x.2[1]); + assert_eq!(&*or, &2); + } + + #[test] + fn map_heap_ref() { + let or: BoxRef = Box::new(example()).into(); + let or: BoxRef<_, str> = or.map(|x| &x.1[..5]); + assert_eq!(&*or, "hello"); + } + + #[test] + fn map_static_ref() { + let or: BoxRef<()> = Box::new(()).into(); + let or: BoxRef<_, str> = or.map(|_| "hello"); + assert_eq!(&*or, "hello"); + } + + #[test] + fn map_chained() { + let or: BoxRef = Box::new(example().1).into(); + let or: BoxRef<_, str> = or.map(|x| &x[1..5]); + let or: BoxRef<_, str> = or.map(|x| &x[..2]); + assert_eq!(&*or, "el"); + } + + #[test] + fn map_chained_inference() { + let or = BoxRef::new(Box::new(example().1)) + .map(|x| &x[..5]) + .map(|x| &x[1..3]); + assert_eq!(&*or, "el"); + } + + #[test] + fn owner() { + let or: BoxRef = Box::new(example().1).into(); + let or = or.map(|x| &x[..5]); + assert_eq!(&*or, "hello"); + assert_eq!(&**or.owner(), "hello world"); + } + + #[test] + fn into_inner() { + let or: BoxRef = Box::new(example().1).into(); + let or = or.map(|x| &x[..5]); + assert_eq!(&*or, "hello"); + let s = *or.into_inner(); + assert_eq!(&s, "hello world"); + } + + #[test] + fn fmt_debug() { + let or: BoxRef = Box::new(example().1).into(); + let or = or.map(|x| &x[..5]); + let s = format!("{:?}", or); + assert_eq!(&s, "OwningRef { owner: \"hello world\", reference: \"hello\" }"); + } + + #[test] + fn erased_owner() { + let o1: BoxRef = BoxRef::new(Box::new(example())) + .map(|x| &x.1[..]); + + let o2: BoxRef = BoxRef::new(Box::new(example().1)) + .map(|x| &x[..]); + + let os: Vec> = vec![o1.erase_owner(), o2.erase_owner()]; + assert!(os.iter().all(|e| &e[..] == "hello world")); + } + + #[test] + fn raii_locks() { + use super::super::{RefRef, RefMutRef}; + use std::cell::RefCell; + use super::super::{MutexGuardRef, RwLockReadGuardRef, RwLockWriteGuardRef}; + use std::sync::{Mutex, RwLock}; + + { + let a = RefCell::new(1); + let a = { + let a = RefRef::new(a.borrow()); + assert_eq!(*a, 1); + a + }; + assert_eq!(*a, 1); + drop(a); + } + { + let a = RefCell::new(1); + let a = { + let a = RefMutRef::new(a.borrow_mut()); + assert_eq!(*a, 1); + a + }; + assert_eq!(*a, 1); + drop(a); + } + { + let a = Mutex::new(1); + let a = { + let a = MutexGuardRef::new(a.lock().unwrap()); + assert_eq!(*a, 1); + a + }; + assert_eq!(*a, 1); + drop(a); + } + { + let a = RwLock::new(1); + let a = { + let a = RwLockReadGuardRef::new(a.read().unwrap()); + assert_eq!(*a, 1); + a + }; + assert_eq!(*a, 1); + drop(a); + } + { + let a = RwLock::new(1); + let a = { + let a = RwLockWriteGuardRef::new(a.write().unwrap()); + assert_eq!(*a, 1); + a + }; + assert_eq!(*a, 1); + drop(a); + } + } + + #[test] + fn eq() { + let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); + let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); + assert_eq!(or1.eq(&or2), true); + } + + #[test] + fn cmp() { + let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); + let or2: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice()); + assert_eq!(or1.cmp(&or2), Ordering::Less); + } + + #[test] + fn partial_cmp() { + let or1: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice()); + let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); + assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater)); + } + + #[test] + fn hash() { + let mut h1 = DefaultHasher::new(); + let mut h2 = DefaultHasher::new(); + + let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); + let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); + + or1.hash(&mut h1); + or2.hash(&mut h2); + + assert_eq!(h1.finish(), h2.finish()); + } + + #[test] + fn borrow() { + let mut hash = HashMap::new(); + let key = RcRef::::new(Rc::new("foo-bar".to_string())).map(|s| &s[..]); + + hash.insert(key.clone().map(|s| &s[..3]), 42); + hash.insert(key.clone().map(|s| &s[4..]), 23); + + assert_eq!(hash.get("foo"), Some(&42)); + assert_eq!(hash.get("bar"), Some(&23)); + } + + #[test] + fn total_erase() { + let a: OwningRef, [u8]> + = OwningRef::new(vec![]).map(|x| &x[..]); + let b: OwningRef, [u8]> + = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]); + + let c: OwningRef>, [u8]> = unsafe {a.map_owner(Rc::new)}; + let d: OwningRef>, [u8]> = unsafe {b.map_owner(Rc::new)}; + + let e: OwningRef, [u8]> = c.erase_owner(); + let f: OwningRef, [u8]> = d.erase_owner(); + + let _g = e.clone(); + let _h = f.clone(); + } + + #[test] + fn total_erase_box() { + let a: OwningRef, [u8]> + = OwningRef::new(vec![]).map(|x| &x[..]); + let b: OwningRef, [u8]> + = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]); + + let c: OwningRef>, [u8]> = a.map_owner_box(); + let d: OwningRef>, [u8]> = b.map_owner_box(); + + let _e: OwningRef, [u8]> = c.erase_owner(); + let _f: OwningRef, [u8]> = d.erase_owner(); + } + + #[test] + fn try_map1() { + use std::any::Any; + + let x = Box::new(123_i32); + let y: Box = x; + + assert!(OwningRef::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_ok()); + } + + #[test] + fn try_map2() { + use std::any::Any; + + let x = Box::new(123_i32); + let y: Box = x; + + assert!(!OwningRef::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_err()); + } +} + +mod owning_handle { + use super::super::OwningHandle; + use super::super::RcRef; + use std::rc::Rc; + use std::cell::RefCell; + use std::sync::Arc; + use std::sync::RwLock; + + #[test] + fn owning_handle() { + use std::cell::RefCell; + let cell = Rc::new(RefCell::new(2)); + let cell_ref = RcRef::new(cell); + let mut handle = OwningHandle::new_with_fn(cell_ref, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); + assert_eq!(*handle, 2); + *handle = 3; + assert_eq!(*handle, 3); + } + + #[test] + fn try_owning_handle_ok() { + use std::cell::RefCell; + let cell = Rc::new(RefCell::new(2)); + let cell_ref = RcRef::new(cell); + let mut handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| { + Ok(unsafe { + x.as_ref() + }.unwrap().borrow_mut()) + }).unwrap(); + assert_eq!(*handle, 2); + *handle = 3; + assert_eq!(*handle, 3); + } + + #[test] + fn try_owning_handle_err() { + use std::cell::RefCell; + let cell = Rc::new(RefCell::new(2)); + let cell_ref = RcRef::new(cell); + let handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| { + if false { + return Ok(unsafe { + x.as_ref() + }.unwrap().borrow_mut()) + } + Err(()) + }); + assert!(handle.is_err()); + } + + #[test] + fn nested() { + use std::cell::RefCell; + use std::sync::{Arc, RwLock}; + + let result = { + let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString")))); + let curr = RcRef::new(complex); + let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); + let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap()); + assert_eq!(*curr, "someString"); + *curr = "someOtherString"; + curr + }; + assert_eq!(*result, "someOtherString"); + } + + #[test] + fn owning_handle_safe() { + use std::cell::RefCell; + let cell = Rc::new(RefCell::new(2)); + let cell_ref = RcRef::new(cell); + let handle = OwningHandle::new(cell_ref); + assert_eq!(*handle, 2); + } + + #[test] + fn owning_handle_mut_safe() { + use std::cell::RefCell; + let cell = Rc::new(RefCell::new(2)); + let cell_ref = RcRef::new(cell); + let mut handle = OwningHandle::new_mut(cell_ref); + assert_eq!(*handle, 2); + *handle = 3; + assert_eq!(*handle, 3); + } + + #[test] + fn owning_handle_safe_2() { + let result = { + let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString")))); + let curr = RcRef::new(complex); + let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); + let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap()); + assert_eq!(*curr, "someString"); + *curr = "someOtherString"; + curr + }; + assert_eq!(*result, "someOtherString"); + } +} + +mod owning_ref_mut { + use super::super::{OwningRefMut, BoxRefMut, Erased, ErasedBoxRefMut}; + use super::super::BoxRef; + use std::cmp::{PartialEq, Ord, PartialOrd, Ordering}; + use std::hash::{Hash, Hasher}; + use std::collections::hash_map::DefaultHasher; + use std::collections::HashMap; + + #[derive(Debug, PartialEq)] + struct Example(u32, String, [u8; 3]); + fn example() -> Example { + Example(42, "hello world".to_string(), [1, 2, 3]) + } + + #[test] + fn new_deref() { + let or: OwningRefMut, ()> = OwningRefMut::new(Box::new(())); + assert_eq!(&*or, &()); + } + + #[test] + fn new_deref_mut() { + let mut or: OwningRefMut, ()> = OwningRefMut::new(Box::new(())); + assert_eq!(&mut *or, &mut ()); + } + + #[test] + fn mutate() { + let mut or: OwningRefMut, usize> = OwningRefMut::new(Box::new(0)); + assert_eq!(&*or, &0); + *or = 1; + assert_eq!(&*or, &1); + } + + #[test] + fn into() { + let or: OwningRefMut, ()> = Box::new(()).into(); + assert_eq!(&*or, &()); + } + + #[test] + fn map_offset_ref() { + let or: BoxRefMut = Box::new(example()).into(); + let or: BoxRef<_, u32> = or.map(|x| &mut x.0); + assert_eq!(&*or, &42); + + let or: BoxRefMut = Box::new(example()).into(); + let or: BoxRef<_, u8> = or.map(|x| &mut x.2[1]); + assert_eq!(&*or, &2); + } + + #[test] + fn map_heap_ref() { + let or: BoxRefMut = Box::new(example()).into(); + let or: BoxRef<_, str> = or.map(|x| &mut x.1[..5]); + assert_eq!(&*or, "hello"); + } + + #[test] + fn map_static_ref() { + let or: BoxRefMut<()> = Box::new(()).into(); + let or: BoxRef<_, str> = or.map(|_| "hello"); + assert_eq!(&*or, "hello"); + } + + #[test] + fn map_mut_offset_ref() { + let or: BoxRefMut = Box::new(example()).into(); + let or: BoxRefMut<_, u32> = or.map_mut(|x| &mut x.0); + assert_eq!(&*or, &42); + + let or: BoxRefMut = Box::new(example()).into(); + let or: BoxRefMut<_, u8> = or.map_mut(|x| &mut x.2[1]); + assert_eq!(&*or, &2); + } + + #[test] + fn map_mut_heap_ref() { + let or: BoxRefMut = Box::new(example()).into(); + let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x.1[..5]); + assert_eq!(&*or, "hello"); + } + + #[test] + fn map_mut_static_ref() { + static mut MUT_S: [u8; 5] = *b"hello"; + + let mut_s: &'static mut [u8] = unsafe { &mut MUT_S }; + + let or: BoxRefMut<()> = Box::new(()).into(); + let or: BoxRefMut<_, [u8]> = or.map_mut(move |_| mut_s); + assert_eq!(&*or, b"hello"); + } + + #[test] + fn map_mut_chained() { + let or: BoxRefMut = Box::new(example().1).into(); + let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[1..5]); + let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[..2]); + assert_eq!(&*or, "el"); + } + + #[test] + fn map_chained_inference() { + let or = BoxRefMut::new(Box::new(example().1)) + .map_mut(|x| &mut x[..5]) + .map_mut(|x| &mut x[1..3]); + assert_eq!(&*or, "el"); + } + + #[test] + fn try_map_mut() { + let or: BoxRefMut = Box::new(example().1).into(); + let or: Result, ()> = or.try_map_mut(|x| Ok(&mut x[1..5])); + assert_eq!(&*or.unwrap(), "ello"); + + let or: BoxRefMut = Box::new(example().1).into(); + let or: Result, ()> = or.try_map_mut(|_| Err(())); + assert!(or.is_err()); + } + + #[test] + fn owner() { + let or: BoxRefMut = Box::new(example().1).into(); + let or = or.map_mut(|x| &mut x[..5]); + assert_eq!(&*or, "hello"); + assert_eq!(&**or.owner(), "hello world"); + } + + #[test] + fn into_inner() { + let or: BoxRefMut = Box::new(example().1).into(); + let or = or.map_mut(|x| &mut x[..5]); + assert_eq!(&*or, "hello"); + let s = *or.into_inner(); + assert_eq!(&s, "hello world"); + } + + #[test] + fn fmt_debug() { + let or: BoxRefMut = Box::new(example().1).into(); + let or = or.map_mut(|x| &mut x[..5]); + let s = format!("{:?}", or); + assert_eq!(&s, + "OwningRefMut { owner: \"hello world\", reference: \"hello\" }"); + } + + #[test] + fn erased_owner() { + let o1: BoxRefMut = BoxRefMut::new(Box::new(example())) + .map_mut(|x| &mut x.1[..]); + + let o2: BoxRefMut = BoxRefMut::new(Box::new(example().1)) + .map_mut(|x| &mut x[..]); + + let os: Vec> = vec![o1.erase_owner(), o2.erase_owner()]; + assert!(os.iter().all(|e| &e[..] == "hello world")); + } + + #[test] + fn raii_locks() { + use super::super::RefMutRefMut; + use std::cell::RefCell; + use super::super::{MutexGuardRefMut, RwLockWriteGuardRefMut}; + use std::sync::{Mutex, RwLock}; + + { + let a = RefCell::new(1); + let a = { + let a = RefMutRefMut::new(a.borrow_mut()); + assert_eq!(*a, 1); + a + }; + assert_eq!(*a, 1); + drop(a); + } + { + let a = Mutex::new(1); + let a = { + let a = MutexGuardRefMut::new(a.lock().unwrap()); + assert_eq!(*a, 1); + a + }; + assert_eq!(*a, 1); + drop(a); + } + { + let a = RwLock::new(1); + let a = { + let a = RwLockWriteGuardRefMut::new(a.write().unwrap()); + assert_eq!(*a, 1); + a + }; + assert_eq!(*a, 1); + drop(a); + } + } + + #[test] + fn eq() { + let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); + let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); + assert_eq!(or1.eq(&or2), true); + } + + #[test] + fn cmp() { + let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); + let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice()); + assert_eq!(or1.cmp(&or2), Ordering::Less); + } + + #[test] + fn partial_cmp() { + let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice()); + let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); + assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater)); + } + + #[test] + fn hash() { + let mut h1 = DefaultHasher::new(); + let mut h2 = DefaultHasher::new(); + + let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); + let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); + + or1.hash(&mut h1); + or2.hash(&mut h2); + + assert_eq!(h1.finish(), h2.finish()); + } + + #[test] + fn borrow() { + let mut hash = HashMap::new(); + let key1 = BoxRefMut::::new(Box::new("foo".to_string())).map(|s| &s[..]); + let key2 = BoxRefMut::::new(Box::new("bar".to_string())).map(|s| &s[..]); + + hash.insert(key1, 42); + hash.insert(key2, 23); + + assert_eq!(hash.get("foo"), Some(&42)); + assert_eq!(hash.get("bar"), Some(&23)); + } + + #[test] + fn total_erase() { + let a: OwningRefMut, [u8]> + = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]); + let b: OwningRefMut, [u8]> + = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]); + + let c: OwningRefMut>, [u8]> = unsafe {a.map_owner(Box::new)}; + let d: OwningRefMut>, [u8]> = unsafe {b.map_owner(Box::new)}; + + let _e: OwningRefMut, [u8]> = c.erase_owner(); + let _f: OwningRefMut, [u8]> = d.erase_owner(); + } + + #[test] + fn total_erase_box() { + let a: OwningRefMut, [u8]> + = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]); + let b: OwningRefMut, [u8]> + = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]); + + let c: OwningRefMut>, [u8]> = a.map_owner_box(); + let d: OwningRefMut>, [u8]> = b.map_owner_box(); + + let _e: OwningRefMut, [u8]> = c.erase_owner(); + let _f: OwningRefMut, [u8]> = d.erase_owner(); + } + + #[test] + fn try_map1() { + use std::any::Any; + + let x = Box::new(123_i32); + let y: Box = x; + + assert!(OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).is_ok()); + } + + #[test] + fn try_map2() { + use std::any::Any; + + let x = Box::new(123_i32); + let y: Box = x; + + assert!(!OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).is_err()); + } + + #[test] + fn try_map3() { + use std::any::Any; + + let x = Box::new(123_i32); + let y: Box = x; + + assert!(OwningRefMut::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_ok()); + } + + #[test] + fn try_map4() { + use std::any::Any; + + let x = Box::new(123_i32); + let y: Box = x; + + assert!(!OwningRefMut::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_err()); + } + + #[test] + fn into_owning_ref() { + use super::super::BoxRef; + + let or: BoxRefMut<()> = Box::new(()).into(); + let or: BoxRef<()> = or.into(); + assert_eq!(&*or, &()); + } + + struct Foo { + u: u32, + } + struct Bar { + f: Foo, + } + + #[test] + fn ref_mut() { + use std::cell::RefCell; + + let a = RefCell::new(Bar { f: Foo { u: 42 } }); + let mut b = OwningRefMut::new(a.borrow_mut()); + assert_eq!(b.f.u, 42); + b.f.u = 43; + let mut c = b.map_mut(|x| &mut x.f); + assert_eq!(c.u, 43); + c.u = 44; + let mut d = c.map_mut(|x| &mut x.u); + assert_eq!(*d, 44); + *d = 45; + assert_eq!(*d, 45); + } +} diff --git a/src/librustc_data_structures/sip128.rs b/src/librustc_data_structures/sip128.rs index 06f157f972932..e5de359e4759e 100644 --- a/src/librustc_data_structures/sip128.rs +++ b/src/librustc_data_structures/sip128.rs @@ -70,15 +70,15 @@ unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { let mut i = 0; // current byte index (from LSB) in the output u64 let mut out = 0; if i + 3 < len { - out = load_int_le!(buf, start + i, u32) as u64; + out = u64::from(load_int_le!(buf, start + i, u32)); i += 4; } if i + 1 < len { - out |= (load_int_le!(buf, start + i, u16) as u64) << (i * 8); + out |= u64::from(load_int_le!(buf, start + i, u16)) << (i * 8); i += 2 } if i < len { - out |= (*buf.get_unchecked(start + i) as u64) << (i * 8); + out |= u64::from(*buf.get_unchecked(start + i)) << (i * 8); i += 1; } debug_assert_eq!(i, len); @@ -237,7 +237,7 @@ impl Hasher for SipHasher128 { if self.ntail != 0 { needed = 8 - self.ntail; - self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << 8 * self.ntail; + self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail); if length < needed { self.ntail += length; return diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs index 1f674c1c664e4..fb819dd18a8d6 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/src/librustc_data_structures/sorted_map.rs @@ -305,204 +305,4 @@ impl FromIterator<(K, V)> for SortedMap { } #[cfg(test)] -mod tests { - use super::SortedMap; - - #[test] - fn test_insert_and_iter() { - let mut map = SortedMap::new(); - let mut expected = Vec::new(); - - for x in 0 .. 100 { - assert_eq!(map.iter().cloned().collect::>(), expected); - - let x = 1000 - x * 2; - map.insert(x, x); - expected.insert(0, (x, x)); - } - } - - #[test] - fn test_get_and_index() { - let mut map = SortedMap::new(); - let mut expected = Vec::new(); - - for x in 0 .. 100 { - let x = 1000 - x; - if x & 1 == 0 { - map.insert(x, x); - } - expected.push(x); - } - - for mut x in expected { - if x & 1 == 0 { - assert_eq!(map.get(&x), Some(&x)); - assert_eq!(map.get_mut(&x), Some(&mut x)); - assert_eq!(map[&x], x); - assert_eq!(&mut map[&x], &mut x); - } else { - assert_eq!(map.get(&x), None); - assert_eq!(map.get_mut(&x), None); - } - } - } - - #[test] - fn test_range() { - let mut map = SortedMap::new(); - map.insert(1, 1); - map.insert(3, 3); - map.insert(6, 6); - map.insert(9, 9); - - let keys = |s: &[(_, _)]| { - s.into_iter().map(|e| e.0).collect::>() - }; - - for start in 0 .. 11 { - for end in 0 .. 11 { - if end < start { - continue - } - - let mut expected = vec![1, 3, 6, 9]; - expected.retain(|&x| x >= start && x < end); - - assert_eq!(keys(map.range(start..end)), expected, "range = {}..{}", start, end); - } - } - } - - - #[test] - fn test_offset_keys() { - let mut map = SortedMap::new(); - map.insert(1, 1); - map.insert(3, 3); - map.insert(6, 6); - - map.offset_keys(|k| *k += 1); - - let mut expected = SortedMap::new(); - expected.insert(2, 1); - expected.insert(4, 3); - expected.insert(7, 6); - - assert_eq!(map, expected); - } - - fn keys(s: SortedMap) -> Vec { - s.into_iter().map(|(k, _)| k).collect::>() - } - - fn elements(s: SortedMap) -> Vec<(u32, u32)> { - s.into_iter().collect::>() - } - - #[test] - fn test_remove_range() { - let mut map = SortedMap::new(); - map.insert(1, 1); - map.insert(3, 3); - map.insert(6, 6); - map.insert(9, 9); - - for start in 0 .. 11 { - for end in 0 .. 11 { - if end < start { - continue - } - - let mut expected = vec![1, 3, 6, 9]; - expected.retain(|&x| x < start || x >= end); - - let mut map = map.clone(); - map.remove_range(start .. end); - - assert_eq!(keys(map), expected, "range = {}..{}", start, end); - } - } - } - - #[test] - fn test_remove() { - let mut map = SortedMap::new(); - let mut expected = Vec::new(); - - for x in 0..10 { - map.insert(x, x); - expected.push((x, x)); - } - - for x in 0 .. 10 { - let mut map = map.clone(); - let mut expected = expected.clone(); - - assert_eq!(map.remove(&x), Some(x)); - expected.remove(x as usize); - - assert_eq!(map.iter().cloned().collect::>(), expected); - } - } - - #[test] - fn test_insert_presorted_non_overlapping() { - let mut map = SortedMap::new(); - map.insert(2, 0); - map.insert(8, 0); - - map.insert_presorted(vec![(3, 0), (7, 0)]); - - let expected = vec![2, 3, 7, 8]; - assert_eq!(keys(map), expected); - } - - #[test] - fn test_insert_presorted_first_elem_equal() { - let mut map = SortedMap::new(); - map.insert(2, 2); - map.insert(8, 8); - - map.insert_presorted(vec![(2, 0), (7, 7)]); - - let expected = vec![(2, 0), (7, 7), (8, 8)]; - assert_eq!(elements(map), expected); - } - - #[test] - fn test_insert_presorted_last_elem_equal() { - let mut map = SortedMap::new(); - map.insert(2, 2); - map.insert(8, 8); - - map.insert_presorted(vec![(3, 3), (8, 0)]); - - let expected = vec![(2, 2), (3, 3), (8, 0)]; - assert_eq!(elements(map), expected); - } - - #[test] - fn test_insert_presorted_shuffle() { - let mut map = SortedMap::new(); - map.insert(2, 2); - map.insert(7, 7); - - map.insert_presorted(vec![(1, 1), (3, 3), (8, 8)]); - - let expected = vec![(1, 1), (2, 2), (3, 3), (7, 7), (8, 8)]; - assert_eq!(elements(map), expected); - } - - #[test] - fn test_insert_presorted_at_end() { - let mut map = SortedMap::new(); - map.insert(1, 1); - map.insert(2, 2); - - map.insert_presorted(vec![(3, 3), (8, 8)]); - - let expected = vec![(1, 1), (2, 2), (3, 3), (8, 8)]; - assert_eq!(elements(map), expected); - } -} +mod tests; diff --git a/src/librustc_data_structures/sorted_map/tests.rs b/src/librustc_data_structures/sorted_map/tests.rs new file mode 100644 index 0000000000000..f970409cc3d58 --- /dev/null +++ b/src/librustc_data_structures/sorted_map/tests.rs @@ -0,0 +1,199 @@ +use super::SortedMap; + +#[test] +fn test_insert_and_iter() { + let mut map = SortedMap::new(); + let mut expected = Vec::new(); + + for x in 0 .. 100 { + assert_eq!(map.iter().cloned().collect::>(), expected); + + let x = 1000 - x * 2; + map.insert(x, x); + expected.insert(0, (x, x)); + } +} + +#[test] +fn test_get_and_index() { + let mut map = SortedMap::new(); + let mut expected = Vec::new(); + + for x in 0 .. 100 { + let x = 1000 - x; + if x & 1 == 0 { + map.insert(x, x); + } + expected.push(x); + } + + for mut x in expected { + if x & 1 == 0 { + assert_eq!(map.get(&x), Some(&x)); + assert_eq!(map.get_mut(&x), Some(&mut x)); + assert_eq!(map[&x], x); + assert_eq!(&mut map[&x], &mut x); + } else { + assert_eq!(map.get(&x), None); + assert_eq!(map.get_mut(&x), None); + } + } +} + +#[test] +fn test_range() { + let mut map = SortedMap::new(); + map.insert(1, 1); + map.insert(3, 3); + map.insert(6, 6); + map.insert(9, 9); + + let keys = |s: &[(_, _)]| { + s.into_iter().map(|e| e.0).collect::>() + }; + + for start in 0 .. 11 { + for end in 0 .. 11 { + if end < start { + continue + } + + let mut expected = vec![1, 3, 6, 9]; + expected.retain(|&x| x >= start && x < end); + + assert_eq!(keys(map.range(start..end)), expected, "range = {}..{}", start, end); + } + } +} + + +#[test] +fn test_offset_keys() { + let mut map = SortedMap::new(); + map.insert(1, 1); + map.insert(3, 3); + map.insert(6, 6); + + map.offset_keys(|k| *k += 1); + + let mut expected = SortedMap::new(); + expected.insert(2, 1); + expected.insert(4, 3); + expected.insert(7, 6); + + assert_eq!(map, expected); +} + +fn keys(s: SortedMap) -> Vec { + s.into_iter().map(|(k, _)| k).collect::>() +} + +fn elements(s: SortedMap) -> Vec<(u32, u32)> { + s.into_iter().collect::>() +} + +#[test] +fn test_remove_range() { + let mut map = SortedMap::new(); + map.insert(1, 1); + map.insert(3, 3); + map.insert(6, 6); + map.insert(9, 9); + + for start in 0 .. 11 { + for end in 0 .. 11 { + if end < start { + continue + } + + let mut expected = vec![1, 3, 6, 9]; + expected.retain(|&x| x < start || x >= end); + + let mut map = map.clone(); + map.remove_range(start .. end); + + assert_eq!(keys(map), expected, "range = {}..{}", start, end); + } + } +} + +#[test] +fn test_remove() { + let mut map = SortedMap::new(); + let mut expected = Vec::new(); + + for x in 0..10 { + map.insert(x, x); + expected.push((x, x)); + } + + for x in 0 .. 10 { + let mut map = map.clone(); + let mut expected = expected.clone(); + + assert_eq!(map.remove(&x), Some(x)); + expected.remove(x as usize); + + assert_eq!(map.iter().cloned().collect::>(), expected); + } +} + +#[test] +fn test_insert_presorted_non_overlapping() { + let mut map = SortedMap::new(); + map.insert(2, 0); + map.insert(8, 0); + + map.insert_presorted(vec![(3, 0), (7, 0)]); + + let expected = vec![2, 3, 7, 8]; + assert_eq!(keys(map), expected); +} + +#[test] +fn test_insert_presorted_first_elem_equal() { + let mut map = SortedMap::new(); + map.insert(2, 2); + map.insert(8, 8); + + map.insert_presorted(vec![(2, 0), (7, 7)]); + + let expected = vec![(2, 0), (7, 7), (8, 8)]; + assert_eq!(elements(map), expected); +} + +#[test] +fn test_insert_presorted_last_elem_equal() { + let mut map = SortedMap::new(); + map.insert(2, 2); + map.insert(8, 8); + + map.insert_presorted(vec![(3, 3), (8, 0)]); + + let expected = vec![(2, 2), (3, 3), (8, 0)]; + assert_eq!(elements(map), expected); +} + +#[test] +fn test_insert_presorted_shuffle() { + let mut map = SortedMap::new(); + map.insert(2, 2); + map.insert(7, 7); + + map.insert_presorted(vec![(1, 1), (3, 3), (8, 8)]); + + let expected = vec![(1, 1), (2, 2), (3, 3), (7, 7), (8, 8)]; + assert_eq!(elements(map), expected); +} + +#[test] +fn test_insert_presorted_at_end() { + let mut map = SortedMap::new(); + map.insert(1, 1); + map.insert(2, 2); + + map.insert_presorted(vec![(3, 3), (8, 8)]); + + let expected = vec![(1, 1), (2, 2), (3, 3), (8, 8)]; + assert_eq!(elements(map), expected); +} diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 19343a9250df3..47dfc1d1688d0 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -1,6 +1,7 @@ use std::hash::{Hash, Hasher, BuildHasher}; use std::marker::PhantomData; use std::mem; +use smallvec::SmallVec; use crate::sip128::SipHasher128; use crate::indexed_vec; use crate::bit_set; @@ -14,7 +15,6 @@ use crate::bit_set; /// extended to 64 bits if needed. pub struct StableHasher { state: SipHasher128, - bytes_hashed: u64, width: PhantomData, } @@ -32,7 +32,6 @@ impl StableHasher { pub fn new() -> Self { StableHasher { state: SipHasher128::new_with_keys(0, 0), - bytes_hashed: 0, width: PhantomData, } } @@ -45,7 +44,7 @@ impl StableHasher { impl StableHasherResult for u128 { fn finish(hasher: StableHasher) -> Self { let (_0, _1) = hasher.finalize(); - (_0 as u128) | ((_1 as u128) << 64) + u128::from(_0) | (u128::from(_1) << 64) } } @@ -60,11 +59,6 @@ impl StableHasher { pub fn finalize(self) -> (u64, u64) { self.state.finish128() } - - #[inline] - pub fn bytes_hashed(&self) -> u64 { - self.bytes_hashed - } } impl Hasher for StableHasher { @@ -75,37 +69,31 @@ impl Hasher for StableHasher { #[inline] fn write(&mut self, bytes: &[u8]) { self.state.write(bytes); - self.bytes_hashed += bytes.len() as u64; } #[inline] fn write_u8(&mut self, i: u8) { self.state.write_u8(i); - self.bytes_hashed += 1; } #[inline] fn write_u16(&mut self, i: u16) { self.state.write_u16(i.to_le()); - self.bytes_hashed += 2; } #[inline] fn write_u32(&mut self, i: u32) { self.state.write_u32(i.to_le()); - self.bytes_hashed += 4; } #[inline] fn write_u64(&mut self, i: u64) { self.state.write_u64(i.to_le()); - self.bytes_hashed += 8; } #[inline] fn write_u128(&mut self, i: u128) { self.state.write_u128(i.to_le()); - self.bytes_hashed += 16; } #[inline] @@ -114,37 +102,31 @@ impl Hasher for StableHasher { // platforms. This is important for symbol hashes when cross compiling, // for example. self.state.write_u64((i as u64).to_le()); - self.bytes_hashed += 8; } #[inline] fn write_i8(&mut self, i: i8) { self.state.write_i8(i); - self.bytes_hashed += 1; } #[inline] fn write_i16(&mut self, i: i16) { self.state.write_i16(i.to_le()); - self.bytes_hashed += 2; } #[inline] fn write_i32(&mut self, i: i32) { self.state.write_i32(i.to_le()); - self.bytes_hashed += 4; } #[inline] fn write_i64(&mut self, i: i64) { self.state.write_i64(i.to_le()); - self.bytes_hashed += 8; } #[inline] fn write_i128(&mut self, i: i128) { self.state.write_i128(i.to_le()); - self.bytes_hashed += 16; } #[inline] @@ -153,12 +135,35 @@ impl Hasher for StableHasher { // platforms. This is important for symbol hashes when cross compiling, // for example. self.state.write_i64((i as i64).to_le()); - self.bytes_hashed += 8; } } /// Something that implements `HashStable` can be hashed in a way that is /// stable across multiple compilation sessions. +/// +/// Note that `HashStable` imposes rather more strict requirements than usual +/// hash functions: +/// +/// - Stable hashes are sometimes used as identifiers. Therefore they must +/// conform to the corresponding `PartialEq` implementations: +/// +/// - `x == y` implies `hash_stable(x) == hash_stable(y)`, and +/// - `x != y` implies `hash_stable(x) != hash_stable(y)`. +/// +/// That second condition is usually not required for hash functions +/// (e.g. `Hash`). In practice this means that `hash_stable` must feed any +/// information into the hasher that a `PartialEq` comparision takes into +/// account. See [#49300](https://github.com/rust-lang/rust/issues/49300) +/// for an example where violating this invariant has caused trouble in the +/// past. +/// +/// - `hash_stable()` must be independent of the current +/// compilation session. E.g. they must not hash memory addresses or other +/// things that are "randomly" assigned per compilation session. +/// +/// - `hash_stable()` must be independent of the host architecture. The +/// `StableHasher` takes care of endianness and `isize`/`usize` platform +/// differences. pub trait HashStable { fn hash_stable(&self, hcx: &mut CTX, @@ -318,6 +323,46 @@ impl, CTX> HashStable for Vec { } } +impl HashStable for indexmap::IndexMap + where K: HashStable + Eq + Hash, + V: HashStable, + R: BuildHasher, +{ + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for kv in self { + kv.hash_stable(ctx, hasher); + } + } +} + +impl HashStable for indexmap::IndexSet + where K: HashStable + Eq + Hash, + R: BuildHasher, +{ + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for key in self { + key.hash_stable(ctx, hasher); + } + } +} + +impl HashStable for SmallVec<[A; 1]> where A: HashStable { + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (&self[..]).hash_stable(ctx, hasher); + } +} + impl, CTX> HashStable for Box { #[inline] fn hash_stable(&self, @@ -458,6 +503,16 @@ impl HashStable for bit_set::BitSet } } +impl HashStable +for bit_set::BitMatrix +{ + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.words().hash_stable(ctx, hasher); + } +} + impl_stable_hash_via_hash!(::std::path::Path); impl_stable_hash_via_hash!(::std::path::PathBuf); diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index ba1f6eb56fe88..73247c1469efd 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -65,6 +65,7 @@ cfg_if! { } use std::ops::Add; + use std::panic::{resume_unwind, catch_unwind, AssertUnwindSafe}; #[derive(Debug)] pub struct Atomic(Cell); @@ -130,7 +131,21 @@ cfg_if! { #[macro_export] macro_rules! parallel { ($($blocks:tt),*) => { - $($blocks)*; + // We catch panics here ensuring that all the blocks execute. + // This makes behavior consistent with the parallel compiler. + let mut panic = None; + $( + if let Err(p) = ::std::panic::catch_unwind( + ::std::panic::AssertUnwindSafe(|| $blocks) + ) { + if panic.is_none() { + panic = Some(p); + } + } + )* + if let Some(panic) = panic { + ::std::panic::resume_unwind(panic); + } } } @@ -140,6 +155,26 @@ cfg_if! { t.into_iter() } + pub fn par_for_each_in( + t: T, + for_each: + impl Fn(<::IntoIter as Iterator>::Item) + Sync + Send + ) { + // We catch panics here ensuring that all the loop iterations execute. + // This makes behavior consistent with the parallel compiler. + let mut panic = None; + t.into_iter().for_each(|i| { + if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) { + if panic.is_none() { + panic = Some(p); + } + } + }); + if let Some(panic) = panic { + resume_unwind(panic); + } + } + pub type MetadataRef = OwningRef, [u8]>; pub use std::rc::Rc as Lrc; @@ -278,23 +313,26 @@ cfg_if! { use std::thread; pub use rayon::{join, scope}; + /// Runs a list of blocks in parallel. The first block is executed immediately on + /// the current thread. Use that for the longest running block. #[macro_export] macro_rules! parallel { - (impl [$($c:tt,)*] [$block:tt $(, $rest:tt)*]) => { - parallel!(impl [$block, $($c,)*] [$($rest),*]) + (impl $fblock:tt [$($c:tt,)*] [$block:tt $(, $rest:tt)*]) => { + parallel!(impl $fblock [$block, $($c,)*] [$($rest),*]) }; - (impl [$($blocks:tt,)*] []) => { + (impl $fblock:tt [$($blocks:tt,)*] []) => { ::rustc_data_structures::sync::scope(|s| { $( s.spawn(|_| $blocks); )* + $fblock; }) }; - ($($blocks:tt),*) => { - // Reverse the order of the blocks since Rayon executes them in reverse order + ($fblock:tt, $($blocks:tt),*) => { + // Reverse the order of the later blocks since Rayon executes them in reverse order // when using a single thread. This ensures the execution order matches that // of a single threaded rustc - parallel!(impl [] [$($blocks),*]); + parallel!(impl $fblock [] [$($blocks),*]); }; } @@ -307,6 +345,15 @@ cfg_if! { t.into_par_iter() } + pub fn par_for_each_in( + t: T, + for_each: impl Fn( + <::Iter as ParallelIterator>::Item + ) + Sync + Send + ) { + t.into_par_iter().for_each(for_each) + } + pub type MetadataRef = OwningRef, [u8]>; /// This makes locks panic if they are already held. diff --git a/src/librustc_data_structures/thin_vec.rs b/src/librustc_data_structures/thin_vec.rs index ed57c528f51e0..6692903cd4fe9 100644 --- a/src/librustc_data_structures/thin_vec.rs +++ b/src/librustc_data_structures/thin_vec.rs @@ -1,3 +1,5 @@ +use crate::stable_hasher::{StableHasher, StableHasherResult, HashStable}; + /// A vector type optimized for cases where this size is usually 0 (cf. `SmallVector`). /// The `Option>` wrapping allows us to represent a zero sized vector with `None`, /// which uses only a single (null) pointer. @@ -56,3 +58,17 @@ impl Extend for ThinVec { } } } + +impl, CTX> HashStable for ThinVec { + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + (**self).hash_stable(hcx, hasher) + } +} + +impl Default for ThinVec { + fn default() -> Self { + Self(None) + } +} diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index 0974607fabea8..d7cbd1e2e4b47 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -58,6 +58,10 @@ impl TransitiveRelation { self.edges.is_empty() } + pub fn elements(&self) -> impl Iterator { + self.elements.iter() + } + fn index(&self, a: &T) -> Option { self.map.get(a).cloned() } diff --git a/src/librustc_data_structures/vec_linked_list.rs b/src/librustc_data_structures/vec_linked_list.rs index c00c707a43542..0fb8060031843 100644 --- a/src/librustc_data_structures/vec_linked_list.rs +++ b/src/librustc_data_structures/vec_linked_list.rs @@ -8,7 +8,7 @@ where Ls: Links, { VecLinkedListIterator { - links: links, + links, current: first, } } diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index a77e497af7b87..b28b015db7573 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustc_driver" version = "0.0.0" +edition = "2018" [lib] name = "rustc_driver" @@ -13,14 +14,14 @@ arena = { path = "../libarena" } graphviz = { path = "../libgraphviz" } log = "0.4" env_logger = { version = "0.5", default-features = false } -rustc-rayon = "0.1.2" +rayon = { version = "0.2.0", package = "rustc-rayon" } scoped-tls = "1.0" rustc = { path = "../librustc" } rustc_allocator = { path = "../librustc_allocator" } rustc_target = { path = "../librustc_target" } rustc_borrowck = { path = "../librustc_borrowck" } rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } +errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_incremental = { path = "../librustc_incremental" } rustc_lint = { path = "../librustc_lint" } rustc_metadata = { path = "../librustc_metadata" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs deleted file mode 100644 index 858a5602e7b7f..0000000000000 --- a/src/librustc_driver/driver.rs +++ /dev/null @@ -1,1252 +0,0 @@ -use rustc::dep_graph::DepGraph; -use rustc::hir; -use rustc::hir::lowering::lower_crate; -use rustc::hir::map as hir_map; -use rustc::hir::def_id::LOCAL_CRATE; -use rustc::lint; -use rustc::middle::{self, reachable, resolve_lifetime, stability}; -use rustc::ty::{self, AllArenas, Resolutions, TyCtxt}; -use rustc::traits; -use rustc::util::common::{install_panic_hook, time, ErrorReported}; -use rustc::util::profiling::ProfileCategory; -use rustc::session::{CompileResult, Session}; -use rustc::session::CompileIncomplete; -use rustc::session::config::{self, Input, OutputFilenames, OutputType}; -use rustc::session::search_paths::PathKind; -use rustc_allocator as allocator; -use rustc_borrowck as borrowck; -use rustc_codegen_utils::codegen_backend::CodegenBackend; -use rustc_data_structures::sync::{self, Lock}; -#[cfg(parallel_compiler)] -use rustc_data_structures::jobserver; -use rustc_incremental; -use rustc_metadata::creader::CrateLoader; -use rustc_metadata::cstore::{self, CStore}; -use rustc_mir as mir; -use rustc_passes::{self, ast_validation, hir_stats}; -use rustc_plugin as plugin; -use rustc_plugin::registry::Registry; -use rustc_privacy; -use rustc_resolve::{Resolver, ResolverArenas}; -use rustc_traits; -use rustc_typeck as typeck; -use syntax::{self, ast, diagnostics, visit}; -use syntax::early_buffered_lints::BufferedEarlyLint; -use syntax::ext::base::ExtCtxt; -use syntax::mut_visit::MutVisitor; -use syntax::parse::{self, PResult}; -use syntax::util::node_count::NodeCounter; -use syntax_pos::hygiene; -use syntax_ext; - -use serialize::json; - -use std::any::Any; -use std::env; -use std::ffi::OsString; -use std::fs; -use std::iter; -use std::path::{Path, PathBuf}; -use std::sync::mpsc; - -use rustc_interface::{util, profile, passes}; -use super::Compilation; - -#[cfg(not(parallel_compiler))] -pub fn spawn_thread_pool R + sync::Send, R: sync::Send>( - opts: config::Options, - f: F -) -> R { - ty::tls::GCX_PTR.set(&Lock::new(0), || { - f(opts) - }) -} - -#[cfg(parallel_compiler)] -pub fn spawn_thread_pool R + sync::Send, R: sync::Send>( - opts: config::Options, - f: F -) -> R { - use syntax; - use syntax_pos; - use rayon::{ThreadPoolBuilder, ThreadPool}; - - let gcx_ptr = &Lock::new(0); - - let config = ThreadPoolBuilder::new() - .acquire_thread_handler(jobserver::acquire_thread) - .release_thread_handler(jobserver::release_thread) - .num_threads(Session::threads_from_count(opts.debugging_opts.threads)) - .deadlock_handler(|| unsafe { ty::query::handle_deadlock() }) - .stack_size(::STACK_SIZE); - - let with_pool = move |pool: &ThreadPool| { - pool.install(move || f(opts)) - }; - - syntax::GLOBALS.with(|syntax_globals| { - syntax_pos::GLOBALS.with(|syntax_pos_globals| { - // The main handler run for each Rayon worker thread and sets up - // the thread local rustc uses. syntax_globals and syntax_pos_globals are - // captured and set on the new threads. ty::tls::with_thread_locals sets up - // thread local callbacks from libsyntax - let main_handler = move |worker: &mut dyn FnMut()| { - syntax::GLOBALS.set(syntax_globals, || { - syntax_pos::GLOBALS.set(syntax_pos_globals, || { - ty::tls::with_thread_locals(|| { - ty::tls::GCX_PTR.set(gcx_ptr, || { - worker() - }) - }) - }) - }) - }; - - ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap() - }) - }) -} - -pub fn compile_input( - codegen_backend: Box, - sess: &Session, - cstore: &CStore, - input_path: &Option, - input: &Input, - outdir: &Option, - output: &Option, - addl_plugins: Option>, - control: &CompileController, -) -> CompileResult { - macro_rules! controller_entry_point { - ($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{ - let state = &mut $make_state; - let phase_result: &CompileResult = &$phase_result; - if phase_result.is_ok() || control.$point.run_callback_on_error { - (control.$point.callback)(state); - } - - if control.$point.stop == Compilation::Stop { - // FIXME: shouldn't this return Err(CompileIncomplete::Stopped) - // if there are no errors? - return $tsess.compile_status(); - } - }} - } - - if sess.profile_queries() { - profile::begin(sess); - } - - // We need nested scopes here, because the intermediate results can keep - // large chunks of memory alive and we want to free them as soon as - // possible to keep the peak memory usage low - let (outputs, ongoing_codegen, dep_graph) = { - let krate = match phase_1_parse_input(control, sess, input) { - Ok(krate) => krate, - Err(mut parse_error) => { - parse_error.emit(); - return Err(CompileIncomplete::Errored(ErrorReported)); - } - }; - - let (krate, registry) = { - let mut compile_state = - CompileState::state_after_parse(input, sess, outdir, output, krate, &cstore); - controller_entry_point!(after_parse, sess, compile_state, Ok(())); - - (compile_state.krate.unwrap(), compile_state.registry) - }; - - let outputs = util::build_output_filenames(input, outdir, output, &krate.attrs, sess); - let crate_name = - ::rustc_codegen_utils::link::find_crate_name(Some(sess), &krate.attrs, input); - install_panic_hook(); - - let ExpansionResult { - expanded_crate, - defs, - resolutions, - mut hir_forest, - } = { - phase_2_configure_and_expand( - sess, - &cstore, - krate, - registry, - &crate_name, - addl_plugins, - |expanded_crate| { - let mut state = CompileState::state_after_expand( - input, - sess, - outdir, - output, - &cstore, - expanded_crate, - &crate_name, - ); - controller_entry_point!(after_expand, sess, state, Ok(())); - Ok(()) - }, - )? - }; - - let output_paths = passes::generated_output_paths( - sess, - &outputs, - output.is_some(), - &crate_name - ); - - // Ensure the source file isn't accidentally overwritten during compilation. - if let Some(ref input_path) = *input_path { - if sess.opts.will_create_output_file() { - if passes::output_contains_path(&output_paths, input_path) { - sess.err(&format!( - "the input file \"{}\" would be overwritten by the generated \ - executable", - input_path.display() - )); - return Err(CompileIncomplete::Stopped); - } - if let Some(dir_path) = passes::output_conflicts_with_dir(&output_paths) { - sess.err(&format!( - "the generated executable for the input file \"{}\" conflicts with the \ - existing directory \"{}\"", - input_path.display(), - dir_path.display() - )); - return Err(CompileIncomplete::Stopped); - } - } - } - - passes::write_out_deps(sess, &outputs, &output_paths); - if sess.opts.output_types.contains_key(&OutputType::DepInfo) - && sess.opts.output_types.len() == 1 - { - return Ok(()); - } - - if let &Some(ref dir) = outdir { - if fs::create_dir_all(dir).is_err() { - sess.err("failed to find or create the directory specified by --out-dir"); - return Err(CompileIncomplete::Stopped); - } - } - - // Construct the HIR map - let hir_map = time(sess, "indexing hir", || { - hir_map::map_crate(sess, cstore, &mut hir_forest, &defs) - }); - - { - hir_map.dep_graph.assert_ignored(); - controller_entry_point!( - after_hir_lowering, - sess, - CompileState::state_after_hir_lowering( - input, - sess, - outdir, - output, - &cstore, - &hir_map, - &resolutions, - &expanded_crate, - &hir_map.krate(), - &outputs, - &crate_name - ), - Ok(()) - ); - } - - let opt_crate = if control.keep_ast { - Some(&expanded_crate) - } else { - drop(expanded_crate); - None - }; - - let mut arenas = AllArenas::new(); - - phase_3_run_analysis_passes( - &*codegen_backend, - control, - sess, - cstore, - hir_map, - resolutions, - &mut arenas, - &crate_name, - &outputs, - |tcx, rx, result| { - { - // Eventually, we will want to track plugins. - tcx.dep_graph.with_ignore(|| { - let mut state = CompileState::state_after_analysis( - input, - sess, - outdir, - output, - opt_crate, - tcx.hir().krate(), - tcx, - &crate_name, - ); - (control.after_analysis.callback)(&mut state); - }); - - // Plugins like clippy and rust-semverver stop the analysis early, - // but want to still return an error if errors during the analysis - // happened: - tcx.sess.compile_status()?; - - if control.after_analysis.stop == Compilation::Stop { - return result.and_then(|_| Err(CompileIncomplete::Stopped)); - } - } - - result?; - - if log_enabled!(::log::Level::Info) { - println!("Pre-codegen"); - tcx.print_debug_stats(); - } - - let ongoing_codegen = phase_4_codegen(&*codegen_backend, tcx, rx); - - if log_enabled!(::log::Level::Info) { - println!("Post-codegen"); - tcx.print_debug_stats(); - } - - if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { - if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, &outputs) { - sess.err(&format!("could not emit MIR: {}", e)); - sess.abort_if_errors(); - } - } - - if tcx.sess.opts.debugging_opts.query_stats { - tcx.queries.print_stats(); - } - - Ok((outputs.clone(), ongoing_codegen, tcx.dep_graph.clone())) - }, - )? - }; - - if sess.opts.debugging_opts.print_type_sizes { - sess.code_stats.borrow().print_type_sizes(); - } - - codegen_backend.join_codegen_and_link(ongoing_codegen, sess, &dep_graph, &outputs)?; - - if sess.opts.debugging_opts.perf_stats { - sess.print_perf_stats(); - } - - if sess.opts.debugging_opts.self_profile { - sess.print_profiler_results(); - } - - if sess.opts.debugging_opts.profile_json { - sess.save_json_results(); - } - - controller_entry_point!( - compilation_done, - sess, - CompileState::state_when_compilation_done(input, sess, outdir, output), - Ok(()) - ); - - Ok(()) -} - -/// CompileController is used to customize compilation, it allows compilation to -/// be stopped and/or to call arbitrary code at various points in compilation. -/// It also allows for various flags to be set to influence what information gets -/// collected during compilation. -/// -/// This is a somewhat higher level controller than a Session - the Session -/// controls what happens in each phase, whereas the CompileController controls -/// whether a phase is run at all and whether other code (from outside the -/// compiler) is run between phases. -/// -/// Note that if compilation is set to stop and a callback is provided for a -/// given entry point, the callback is called before compilation is stopped. -/// -/// Expect more entry points to be added in the future. -pub struct CompileController<'a> { - pub after_parse: PhaseController<'a>, - pub after_expand: PhaseController<'a>, - pub after_hir_lowering: PhaseController<'a>, - pub after_analysis: PhaseController<'a>, - pub compilation_done: PhaseController<'a>, - - // FIXME we probably want to group the below options together and offer a - // better API, rather than this ad-hoc approach. - // Whether the compiler should keep the ast beyond parsing. - pub keep_ast: bool, - // -Zcontinue-parse-after-error - pub continue_parse_after_error: bool, - - /// Allows overriding default rustc query providers, - /// after `default_provide` has installed them. - pub provide: Box, - /// Same as `provide`, but only for non-local crates, - /// applied after `default_provide_extern`. - pub provide_extern: Box, -} - -impl<'a> CompileController<'a> { - pub fn basic() -> CompileController<'a> { - sync::assert_send::(); - CompileController { - after_parse: PhaseController::basic(), - after_expand: PhaseController::basic(), - after_hir_lowering: PhaseController::basic(), - after_analysis: PhaseController::basic(), - compilation_done: PhaseController::basic(), - keep_ast: false, - continue_parse_after_error: false, - provide: box |_| {}, - provide_extern: box |_| {}, - } - } -} - -/// This implementation makes it easier to create a custom driver when you only want to hook -/// into callbacks from `CompileController`. -/// -/// # Example -/// -/// ```no_run -/// # extern crate rustc_driver; -/// # use rustc_driver::driver::CompileController; -/// let mut controller = CompileController::basic(); -/// controller.after_analysis.callback = Box::new(move |_state| {}); -/// rustc_driver::run_compiler(&[], Box::new(controller), None, None); -/// ``` -impl<'a> ::CompilerCalls<'a> for CompileController<'a> { - fn early_callback( - &mut self, - matches: &::getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - descriptions: &::errors::registry::Registry, - output: ::ErrorOutputType, - ) -> Compilation { - ::RustcDefaultCalls.early_callback( - matches, - sopts, - cfg, - descriptions, - output, - ) - } - fn no_input( - &mut self, - matches: &::getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - odir: &Option, - ofile: &Option, - descriptions: &::errors::registry::Registry, - ) -> Option<(Input, Option)> { - ::RustcDefaultCalls.no_input( - matches, - sopts, - cfg, - odir, - ofile, - descriptions, - ) - } - fn late_callback( - &mut self, - codegen_backend: &dyn (::CodegenBackend), - matches: &::getopts::Matches, - sess: &Session, - cstore: &CStore, - input: &Input, - odir: &Option, - ofile: &Option, - ) -> Compilation { - ::RustcDefaultCalls - .late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) - } - fn build_controller( - self: Box, - _: &Session, - _: &::getopts::Matches - ) -> CompileController<'a> { - *self - } -} - -pub struct PhaseController<'a> { - pub stop: Compilation, - // If true then the compiler will try to run the callback even if the phase - // ends with an error. Note that this is not always possible. - pub run_callback_on_error: bool, - pub callback: Box, -} - -impl<'a> PhaseController<'a> { - pub fn basic() -> PhaseController<'a> { - PhaseController { - stop: Compilation::Continue, - run_callback_on_error: false, - callback: box |_| {}, - } - } -} - -/// State that is passed to a callback. What state is available depends on when -/// during compilation the callback is made. See the various constructor methods -/// (`state_*`) in the impl to see which data is provided for any given entry point. -pub struct CompileState<'a, 'tcx: 'a> { - pub input: &'a Input, - pub session: &'tcx Session, - pub krate: Option, - pub registry: Option>, - pub cstore: Option<&'tcx CStore>, - pub crate_name: Option<&'a str>, - pub output_filenames: Option<&'a OutputFilenames>, - pub out_dir: Option<&'a Path>, - pub out_file: Option<&'a Path>, - pub expanded_crate: Option<&'a ast::Crate>, - pub hir_crate: Option<&'a hir::Crate>, - pub hir_map: Option<&'a hir_map::Map<'tcx>>, - pub resolutions: Option<&'a Resolutions>, - pub tcx: Option>, -} - -impl<'a, 'tcx> CompileState<'a, 'tcx> { - fn empty(input: &'a Input, session: &'tcx Session, out_dir: &'a Option) -> Self { - CompileState { - input, - session, - out_dir: out_dir.as_ref().map(|s| &**s), - out_file: None, - krate: None, - registry: None, - cstore: None, - crate_name: None, - output_filenames: None, - expanded_crate: None, - hir_crate: None, - hir_map: None, - resolutions: None, - tcx: None, - } - } - - fn state_after_parse( - input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option, - out_file: &'a Option, - krate: ast::Crate, - cstore: &'tcx CStore, - ) -> Self { - CompileState { - // Initialize the registry before moving `krate` - registry: Some(Registry::new(&session, krate.span)), - krate: Some(krate), - cstore: Some(cstore), - out_file: out_file.as_ref().map(|s| &**s), - ..CompileState::empty(input, session, out_dir) - } - } - - fn state_after_expand( - input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option, - out_file: &'a Option, - cstore: &'tcx CStore, - expanded_crate: &'a ast::Crate, - crate_name: &'a str, - ) -> Self { - CompileState { - crate_name: Some(crate_name), - cstore: Some(cstore), - expanded_crate: Some(expanded_crate), - out_file: out_file.as_ref().map(|s| &**s), - ..CompileState::empty(input, session, out_dir) - } - } - - fn state_after_hir_lowering( - input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option, - out_file: &'a Option, - cstore: &'tcx CStore, - hir_map: &'a hir_map::Map<'tcx>, - resolutions: &'a Resolutions, - krate: &'a ast::Crate, - hir_crate: &'a hir::Crate, - output_filenames: &'a OutputFilenames, - crate_name: &'a str, - ) -> Self { - CompileState { - crate_name: Some(crate_name), - cstore: Some(cstore), - hir_map: Some(hir_map), - resolutions: Some(resolutions), - expanded_crate: Some(krate), - hir_crate: Some(hir_crate), - output_filenames: Some(output_filenames), - out_file: out_file.as_ref().map(|s| &**s), - ..CompileState::empty(input, session, out_dir) - } - } - - fn state_after_analysis( - input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option, - out_file: &'a Option, - krate: Option<&'a ast::Crate>, - hir_crate: &'a hir::Crate, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - crate_name: &'a str, - ) -> Self { - CompileState { - tcx: Some(tcx), - expanded_crate: krate, - hir_crate: Some(hir_crate), - crate_name: Some(crate_name), - out_file: out_file.as_ref().map(|s| &**s), - ..CompileState::empty(input, session, out_dir) - } - } - - fn state_when_compilation_done( - input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option, - out_file: &'a Option, - ) -> Self { - CompileState { - out_file: out_file.as_ref().map(|s| &**s), - ..CompileState::empty(input, session, out_dir) - } - } -} - -pub fn phase_1_parse_input<'a>( - control: &CompileController, - sess: &'a Session, - input: &Input, -) -> PResult<'a, ast::Crate> { - sess.diagnostic() - .set_continue_after_error(control.continue_parse_after_error); - hygiene::set_default_edition(sess.edition()); - - if sess.profile_queries() { - profile::begin(sess); - } - - sess.profiler(|p| p.start_activity(ProfileCategory::Parsing)); - let krate = time(sess, "parsing", || match *input { - Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess), - Input::Str { - ref input, - ref name, - } => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess), - })?; - sess.profiler(|p| p.end_activity(ProfileCategory::Parsing)); - - sess.diagnostic().set_continue_after_error(true); - - if sess.opts.debugging_opts.ast_json_noexpand { - println!("{}", json::as_json(&krate)); - } - - if sess.opts.debugging_opts.input_stats { - println!( - "Lines of code: {}", - sess.source_map().count_lines() - ); - println!("Pre-expansion node count: {}", count_nodes(&krate)); - } - - if let Some(ref s) = sess.opts.debugging_opts.show_span { - syntax::show_span::run(sess.diagnostic(), s, &krate); - } - - if sess.opts.debugging_opts.hir_stats { - hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS"); - } - - Ok(krate) -} - -fn count_nodes(krate: &ast::Crate) -> usize { - let mut counter = NodeCounter::new(); - visit::walk_crate(&mut counter, krate); - counter.count -} - -// For continuing compilation after a parsed crate has been -// modified - -pub struct ExpansionResult { - pub expanded_crate: ast::Crate, - pub defs: hir_map::Definitions, - pub resolutions: Resolutions, - pub hir_forest: hir_map::Forest, -} - -pub struct InnerExpansionResult<'a> { - pub expanded_crate: ast::Crate, - pub resolver: Resolver<'a>, - pub hir_forest: hir_map::Forest, -} - -/// Runs the "early phases" of the compiler: initial `cfg` processing, -/// loading compiler plugins (including those from `addl_plugins`), -/// syntax expansion, secondary `cfg` expansion, synthesis of a test -/// harness if one is to be provided, injection of a dependency on the -/// standard library and prelude, and name resolution. -/// -/// Returns `None` if we're aborting after handling -W help. -pub fn phase_2_configure_and_expand( - sess: &Session, - cstore: &CStore, - krate: ast::Crate, - registry: Option, - crate_name: &str, - addl_plugins: Option>, - after_expand: F, -) -> Result -where - F: FnOnce(&ast::Crate) -> CompileResult, -{ - // Currently, we ignore the name resolution data structures for the purposes of dependency - // tracking. Instead we will run name resolution and include its output in the hash of each - // item, much like we do for macro expansion. In other words, the hash reflects not just - // its contents but the results of name resolution on those contents. Hopefully we'll push - // this back at some point. - let mut crate_loader = CrateLoader::new(sess, &cstore, &crate_name); - let resolver_arenas = Resolver::arenas(); - let result = phase_2_configure_and_expand_inner( - sess, - cstore, - krate, - registry, - crate_name, - addl_plugins, - &resolver_arenas, - &mut crate_loader, - after_expand, - ); - match result { - Ok(InnerExpansionResult { - expanded_crate, - resolver, - hir_forest, - }) => Ok(ExpansionResult { - expanded_crate, - defs: resolver.definitions, - hir_forest, - resolutions: Resolutions { - freevars: resolver.freevars, - export_map: resolver.export_map, - trait_map: resolver.trait_map, - glob_map: resolver.glob_map, - maybe_unused_trait_imports: resolver.maybe_unused_trait_imports, - maybe_unused_extern_crates: resolver.maybe_unused_extern_crates, - extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { - (ident.name, entry.introduced_by_item) - }).collect(), - }, - }), - Err(x) => Err(x), - } -} - -/// Same as phase_2_configure_and_expand, but doesn't let you keep the resolver -/// around -pub fn phase_2_configure_and_expand_inner<'a, F>( - sess: &'a Session, - cstore: &'a CStore, - mut krate: ast::Crate, - registry: Option, - crate_name: &str, - addl_plugins: Option>, - resolver_arenas: &'a ResolverArenas<'a>, - crate_loader: &'a mut CrateLoader<'a>, - after_expand: F, -) -> Result, CompileIncomplete> -where - F: FnOnce(&ast::Crate) -> CompileResult, -{ - krate = time(sess, "attributes injection", || { - syntax::attr::inject(krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr) - }); - - let (mut krate, features) = syntax::config::features( - krate, - &sess.parse_sess, - sess.edition(), - ); - // these need to be set "early" so that expansion sees `quote` if enabled. - sess.init_features(features); - - let crate_types = util::collect_crate_types(sess, &krate.attrs); - sess.crate_types.set(crate_types); - - let disambiguator = util::compute_crate_disambiguator(sess); - sess.crate_disambiguator.set(disambiguator); - rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator); - - if sess.opts.incremental.is_some() { - time(sess, "garbage collect incremental cache directory", || { - if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) { - warn!( - "Error while trying to garbage collect incremental \ - compilation cache directory: {}", - e - ); - } - }); - } - - // If necessary, compute the dependency graph (in the background). - let future_dep_graph = if sess.opts.build_dep_graph() { - Some(rustc_incremental::load_dep_graph(sess)) - } else { - None - }; - - time(sess, "recursion limit", || { - middle::recursion_limit::update_limits(sess, &krate); - }); - - krate = time(sess, "crate injection", || { - let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| &**s); - syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name, sess.edition()) - }); - - let mut addl_plugins = Some(addl_plugins); - let registrars = time(sess, "plugin loading", || { - plugin::load::load_plugins( - sess, - &cstore, - &krate, - crate_name, - addl_plugins.take().unwrap(), - ) - }); - - let mut registry = registry.unwrap_or_else(|| Registry::new(sess, krate.span)); - - time(sess, "plugin registration", || { - if sess.features_untracked().rustc_diagnostic_macros { - registry.register_macro( - "__diagnostic_used", - diagnostics::plugin::expand_diagnostic_used, - ); - registry.register_macro( - "__register_diagnostic", - diagnostics::plugin::expand_register_diagnostic, - ); - registry.register_macro( - "__build_diagnostic_array", - diagnostics::plugin::expand_build_diagnostic_array, - ); - } - - for registrar in registrars { - registry.args_hidden = Some(registrar.args); - (registrar.fun)(&mut registry); - } - }); - - let Registry { - syntax_exts, - early_lint_passes, - late_lint_passes, - lint_groups, - llvm_passes, - attributes, - .. - } = registry; - - sess.track_errors(|| { - let mut ls = sess.lint_store.borrow_mut(); - for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, false, pass); - } - for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, pass); - } - - for (name, (to, deprecated_name)) in lint_groups { - ls.register_group(Some(sess), true, name, deprecated_name, to); - } - - *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; - *sess.plugin_attributes.borrow_mut() = attributes.clone(); - })?; - - // Lint plugins are registered; now we can process command line flags. - if sess.opts.describe_lints { - super::describe_lints(&sess, &sess.lint_store.borrow(), true); - return Err(CompileIncomplete::Stopped); - } - - time(sess, "pre ast expansion lint checks", || { - lint::check_ast_crate( - sess, - &krate, - true, - rustc_lint::BuiltinCombinedPreExpansionLintPass::new()); - }); - - let mut resolver = Resolver::new( - sess, - cstore, - &krate, - crate_name, - crate_loader, - &resolver_arenas, - ); - syntax_ext::register_builtins(&mut resolver, syntax_exts); - - // Expand all macros - sess.profiler(|p| p.start_activity(ProfileCategory::Expansion)); - krate = time(sess, "expansion", || { - // Windows dlls do not have rpaths, so they don't know how to find their - // dependencies. It's up to us to tell the system where to find all the - // dependent dlls. Note that this uses cfg!(windows) as opposed to - // targ_cfg because syntax extensions are always loaded for the host - // compiler, not for the target. - // - // This is somewhat of an inherently racy operation, however, as - // multiple threads calling this function could possibly continue - // extending PATH far beyond what it should. To solve this for now we - // just don't add any new elements to PATH which are already there - // within PATH. This is basically a targeted fix at #17360 for rustdoc - // which runs rustc in parallel but has been seen (#33844) to cause - // problems with PATH becoming too long. - let mut old_path = OsString::new(); - if cfg!(windows) { - old_path = env::var_os("PATH").unwrap_or(old_path); - let mut new_path = sess.host_filesearch(PathKind::All).search_path_dirs(); - for path in env::split_paths(&old_path) { - if !new_path.contains(&path) { - new_path.push(path); - } - } - env::set_var( - "PATH", - &env::join_paths( - new_path - .iter() - .filter(|p| env::join_paths(iter::once(p)).is_ok()), - ).unwrap(), - ); - } - - // Create the config for macro expansion - let features = sess.features_untracked(); - let cfg = syntax::ext::expand::ExpansionConfig { - features: Some(&features), - recursion_limit: *sess.recursion_limit.get(), - trace_mac: sess.opts.debugging_opts.trace_macros, - should_test: sess.opts.test, - ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string()) - }; - - let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver); - - // Expand macros now! - let krate = time(sess, "expand crate", || { - ecx.monotonic_expander().expand_crate(krate) - }); - - // The rest is error reporting - - time(sess, "check unused macros", || { - ecx.check_unused_macros(); - }); - - let mut missing_fragment_specifiers: Vec<_> = ecx.parse_sess - .missing_fragment_specifiers - .borrow() - .iter() - .cloned() - .collect(); - missing_fragment_specifiers.sort(); - - for span in missing_fragment_specifiers { - let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER; - let msg = "missing fragment specifier"; - sess.buffer_lint(lint, ast::CRATE_NODE_ID, span, msg); - } - if cfg!(windows) { - env::set_var("PATH", &old_path); - } - krate - }); - sess.profiler(|p| p.end_activity(ProfileCategory::Expansion)); - - time(sess, "maybe building test harness", || { - syntax::test::modify_for_testing( - &sess.parse_sess, - &mut resolver, - sess.opts.test, - &mut krate, - sess.diagnostic(), - &sess.features_untracked(), - ) - }); - - // If we're actually rustdoc then there's no need to actually compile - // anything, so switch everything to just looping - if sess.opts.actually_rustdoc { - util::ReplaceBodyWithLoop::new(sess).visit_crate(&mut krate); - } - - let (has_proc_macro_decls, has_global_allocator) = time(sess, "AST validation", || { - ast_validation::check_crate(sess, &krate) - }); - - // If we're in rustdoc we're always compiling as an rlib, but that'll trip a - // bunch of checks in the `modify` function below. For now just skip this - // step entirely if we're rustdoc as it's not too useful anyway. - if !sess.opts.actually_rustdoc { - krate = time(sess, "maybe creating a macro crate", || { - let crate_types = sess.crate_types.borrow(); - let num_crate_types = crate_types.len(); - let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro); - let is_test_crate = sess.opts.test; - syntax_ext::proc_macro_decls::modify( - &sess.parse_sess, - &mut resolver, - krate, - is_proc_macro_crate, - has_proc_macro_decls, - is_test_crate, - num_crate_types, - sess.diagnostic(), - ) - }); - } - - if has_global_allocator { - // Expand global allocators, which are treated as an in-tree proc macro - time(sess, "creating allocators", || { - allocator::expand::modify( - &sess.parse_sess, - &mut resolver, - &mut krate, - crate_name.to_string(), - sess.diagnostic(), - ) - }); - } - - // Done with macro expansion! - - after_expand(&krate)?; - - if sess.opts.debugging_opts.input_stats { - println!("Post-expansion node count: {}", count_nodes(&krate)); - } - - if sess.opts.debugging_opts.hir_stats { - hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS"); - } - - if sess.opts.debugging_opts.ast_json { - println!("{}", json::as_json(&krate)); - } - - time(sess, "name resolution", || { - resolver.resolve_crate(&krate); - }); - - // Needs to go *after* expansion to be able to check the results of macro expansion. - time(sess, "complete gated feature checking", || { - syntax::feature_gate::check_crate( - &krate, - &sess.parse_sess, - &sess.features_untracked(), - &attributes, - sess.opts.unstable_features, - ); - }); - - // Add all buffered lints from the `ParseSess` to the `Session`. - sess.parse_sess.buffered_lints.with_lock(|buffered_lints| { - info!("{} parse sess buffered_lints", buffered_lints.len()); - for BufferedEarlyLint{id, span, msg, lint_id} in buffered_lints.drain(..) { - let lint = lint::Lint::from_parser_lint_id(lint_id); - sess.buffer_lint(lint, id, span, &msg); - } - }); - - // Lower ast -> hir. - // First, we need to collect the dep_graph. - let dep_graph = match future_dep_graph { - None => DepGraph::new_disabled(), - Some(future) => { - let (prev_graph, prev_work_products) = - time(sess, "blocked while dep-graph loading finishes", || { - future - .open() - .unwrap_or_else(|e| rustc_incremental::LoadResult::Error { - message: format!("could not decode incremental cache: {:?}", e), - }) - .open(sess) - }); - DepGraph::new(prev_graph, prev_work_products) - } - }; - let hir_forest = time(sess, "lowering ast -> hir", || { - let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, &mut resolver); - - if sess.opts.debugging_opts.hir_stats { - hir_stats::print_hir_stats(&hir_crate); - } - - hir_map::Forest::new(hir_crate, &dep_graph) - }); - - time(sess, "early lint checks", || { - lint::check_ast_crate(sess, &krate, false, rustc_lint::BuiltinCombinedEarlyLintPass::new()) - }); - - // Discard hygiene data, which isn't required after lowering to HIR. - if !sess.opts.debugging_opts.keep_hygiene_data { - syntax::ext::hygiene::clear_markings(); - } - - Ok(InnerExpansionResult { - expanded_crate: krate, - resolver, - hir_forest, - }) -} - -pub fn default_provide(providers: &mut ty::query::Providers) { - rustc_interface::passes::provide(providers); - plugin::build::provide(providers); - hir::provide(providers); - borrowck::provide(providers); - mir::provide(providers); - reachable::provide(providers); - resolve_lifetime::provide(providers); - rustc_privacy::provide(providers); - typeck::provide(providers); - ty::provide(providers); - traits::provide(providers); - stability::provide(providers); - middle::intrinsicck::provide(providers); - middle::liveness::provide(providers); - reachable::provide(providers); - rustc_passes::provide(providers); - rustc_traits::provide(providers); - middle::region::provide(providers); - middle::entry::provide(providers); - cstore::provide(providers); - lint::provide(providers); -} - -pub fn default_provide_extern(providers: &mut ty::query::Providers) { - cstore::provide_extern(providers); -} - -/// Runs the resolution, type-checking, region checking and other -/// miscellaneous analysis passes on the crate. Return various -/// structures carrying the results of the analysis. -pub fn phase_3_run_analysis_passes<'tcx, F, R>( - codegen_backend: &dyn CodegenBackend, - control: &CompileController, - sess: &'tcx Session, - cstore: &'tcx CStore, - hir_map: hir_map::Map<'tcx>, - resolutions: Resolutions, - arenas: &'tcx mut AllArenas<'tcx>, - name: &str, - output_filenames: &OutputFilenames, - f: F, -) -> R -where - F: for<'a> FnOnce( - TyCtxt<'a, 'tcx, 'tcx>, - mpsc::Receiver>, - CompileResult, - ) -> R, -{ - let query_result_on_disk_cache = time(sess, "load query result cache", || { - rustc_incremental::load_query_result_cache(sess) - }); - - let mut local_providers = ty::query::Providers::default(); - default_provide(&mut local_providers); - codegen_backend.provide(&mut local_providers); - (control.provide)(&mut local_providers); - - let mut extern_providers = local_providers; - default_provide_extern(&mut extern_providers); - codegen_backend.provide_extern(&mut extern_providers); - (control.provide_extern)(&mut extern_providers); - - let (tx, rx) = mpsc::channel(); - - TyCtxt::create_and_enter( - sess, - cstore, - local_providers, - extern_providers, - arenas, - resolutions, - hir_map, - query_result_on_disk_cache, - name, - tx, - output_filenames, - |tcx| { - // Do some initialization of the DepGraph that can only be done with the - // tcx available. - time(sess, "dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx)); - - tcx.analysis(LOCAL_CRATE).ok(); - - f(tcx, rx, tcx.sess.compile_status()) - }, - ) -} - -/// Runs the codegen backend, after which the AST and analysis can -/// be discarded. -pub fn phase_4_codegen<'a, 'tcx>( - codegen_backend: &dyn CodegenBackend, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - rx: mpsc::Receiver>, -) -> Box { - time(tcx.sess, "resolving dependency formats", || { - ::rustc::middle::dependency_format::calculate(tcx) - }); - - tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen)); - let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx)); - tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen)); - if tcx.sess.profile_queries() { - profile::dump(&tcx.sess, "profile_queries".to_string()) - } - - codegen -} diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 52dbb618d0d11..5fb6ed31b0693 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -16,95 +16,64 @@ #![recursion_limit="256"] -extern crate arena; +#![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] + pub extern crate getopts; -extern crate graphviz; -extern crate env_logger; #[cfg(unix)] extern crate libc; -extern crate rustc_rayon as rayon; -extern crate rustc; -extern crate rustc_allocator; -extern crate rustc_target; -extern crate rustc_borrowck; -extern crate rustc_data_structures; -extern crate rustc_errors as errors; -extern crate rustc_passes; -extern crate rustc_lint; -extern crate rustc_plugin; -extern crate rustc_privacy; -extern crate rustc_incremental; -extern crate rustc_metadata; -extern crate rustc_mir; -extern crate rustc_resolve; -extern crate rustc_save_analysis; -extern crate rustc_traits; -extern crate rustc_codegen_utils; -extern crate rustc_typeck; -extern crate rustc_interface; -extern crate scoped_tls; -extern crate serialize; -extern crate smallvec; #[macro_use] extern crate log; -extern crate syntax; -extern crate syntax_ext; -extern crate syntax_pos; -use driver::CompileController; use pretty::{PpMode, UserIdentifiedItem}; +//use rustc_resolve as resolve; use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; -use rustc_data_structures::sync::{self, Lrc, Ordering::SeqCst}; -use rustc_data_structures::OnDrop; -use rustc::session::{self, config, Session, build_session, CompileResult, DiagnosticOutput}; -use rustc::session::CompileIncomplete; -use rustc::session::config::{Input, PrintRequest, ErrorOutputType}; +use rustc::session::{config, Session, DiagnosticOutput}; +use rustc::session::config::{Input, PrintRequest, ErrorOutputType, OutputType}; use rustc::session::config::nightly_options; use rustc::session::{early_error, early_warn}; use rustc::lint::Lint; use rustc::lint; +use rustc::hir::def_id::LOCAL_CRATE; +use rustc::util::common::{time, ErrorReported, install_panic_hook}; use rustc_metadata::locator; use rustc_metadata::cstore::CStore; -use rustc::util::common::{time, ErrorReported}; use rustc_codegen_utils::codegen_backend::CodegenBackend; -use rustc_interface::util::{self, get_codegen_sysroot}; +use rustc_interface::interface; +use rustc_interface::util::get_codegen_sysroot; +use rustc_data_structures::sync::SeqCst; use serialize::json::ToJson; -use std::any::Any; use std::borrow::Cow; use std::cmp::max; use std::default::Default; use std::env; -use std::error::Error; use std::ffi::OsString; -use std::fmt::{self, Display}; use std::io::{self, Read, Write}; -use std::panic; +use std::panic::{self, catch_unwind}; use std::path::PathBuf; use std::process::{self, Command, Stdio}; use std::str; -use std::thread; +use std::mem; use syntax::ast; -use syntax::source_map::{SourceMap, FileLoader, RealFileLoader}; +use syntax::source_map::FileLoader; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult}; +use syntax::symbol::sym; use syntax_pos::{DUMMY_SP, MultiSpan, FileName}; -#[cfg(test)] -mod test; - -pub mod driver; pub mod pretty; /// Exit status code used for successful compilation and help output. -pub const EXIT_SUCCESS: isize = 0; +pub const EXIT_SUCCESS: i32 = 0; /// Exit status code used for compilation failures and invalid flags. -pub const EXIT_FAILURE: isize = 1; +pub const EXIT_FAILURE: i32 = 1; const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\ md#bug-reports"; @@ -115,168 +84,295 @@ const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &[&str] = &["incremental"]; -pub fn abort_on_err(result: Result, sess: &Session) -> T { +pub fn source_name(input: &Input) -> FileName { + match *input { + Input::File(ref ifile) => ifile.clone().into(), + Input::Str { ref name, .. } => name.clone(), + } +} + +pub fn abort_on_err(result: Result, sess: &Session) -> T { match result { - Err(CompileIncomplete::Errored(ErrorReported)) => { + Err(..) => { sess.abort_if_errors(); panic!("error reported but abort_if_errors didn't abort???"); } - Err(CompileIncomplete::Stopped) => { - sess.fatal("compilation terminated"); - } Ok(x) => x, } } -pub fn run(run_compiler: F) -> isize - where F: FnOnce() -> (CompileResult, Option) + Send + 'static -{ - let result = monitor(move || { - syntax::with_globals(|| { - let (result, session) = run_compiler(); - if let Err(CompileIncomplete::Errored(_)) = result { - match session { - Some(sess) => { - sess.abort_if_errors(); - panic!("error reported but abort_if_errors didn't abort???"); - } - None => { - let emitter = - errors::emitter::EmitterWriter::stderr( - errors::ColorConfig::Auto, - None, - true, - false - ); - let handler = errors::Handler::with_emitter(true, false, Box::new(emitter)); - handler.emit(&MultiSpan::new(), - "aborting due to previous error(s)", - errors::Level::Fatal); - panic::resume_unwind(Box::new(errors::FatalErrorMarker)); - } - } - } - }); - }); - - match result { - Ok(()) => EXIT_SUCCESS, - Err(_) => EXIT_FAILURE, +pub trait Callbacks { + /// Called before creating the compiler instance + fn config(&mut self, _config: &mut interface::Config) {} + /// Called after parsing and returns true to continue execution + fn after_parsing(&mut self, _compiler: &interface::Compiler) -> bool { + true + } + /// Called after analysis and returns true to continue execution + fn after_analysis(&mut self, _compiler: &interface::Compiler) -> bool { + true } } +pub struct DefaultCallbacks; + +impl Callbacks for DefaultCallbacks {} + // Parse args and run the compiler. This is the primary entry point for rustc. // See comments on CompilerCalls below for details about the callbacks argument. // The FileLoader provides a way to load files from sources other than the file system. -pub fn run_compiler<'a>(args: &[String], - callbacks: Box + sync::Send + 'a>, - file_loader: Option>, - emitter_dest: Option>) - -> (CompileResult, Option) -{ +pub fn run_compiler( + args: &[String], + callbacks: &mut (dyn Callbacks + Send), + file_loader: Option>, + emitter: Option> +) -> interface::Result<()> { + let diagnostic_output = emitter.map(|emitter| DiagnosticOutput::Raw(emitter)) + .unwrap_or(DiagnosticOutput::Default); let matches = match handle_options(args) { Some(matches) => matches, - None => return (Ok(()), None), + None => return Ok(()), }; - let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); + install_panic_hook(); - driver::spawn_thread_pool(sopts, |sopts| { - run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest) - }) -} - -fn run_compiler_with_pool<'a>( - matches: getopts::Matches, - sopts: config::Options, - cfg: ast::CrateConfig, - mut callbacks: Box + sync::Send + 'a>, - file_loader: Option>, - emitter_dest: Option> -) -> (CompileResult, Option) { - macro_rules! do_or_return {($expr: expr, $sess: expr) => { - match $expr { - Compilation::Stop => return (Ok(()), $sess), - Compilation::Continue => {} - } - }} + let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); - let descriptions = diagnostics_registry(); + let mut dummy_config = |sopts, cfg, diagnostic_output| { + let mut config = interface::Config { + opts: sopts, + crate_cfg: cfg, + input: Input::File(PathBuf::new()), + input_path: None, + output_file: None, + output_dir: None, + file_loader: None, + diagnostic_output, + stderr: None, + crate_name: None, + lint_caps: Default::default(), + }; + callbacks.config(&mut config); + config + }; - do_or_return!(callbacks.early_callback(&matches, - &sopts, - &cfg, - &descriptions, - sopts.error_format), - None); + if let Some(ref code) = matches.opt_str("explain") { + handle_explain(code, sopts.error_format); + return Ok(()); + } let (odir, ofile) = make_output(&matches); let (input, input_file_path, input_err) = match make_input(&matches.free) { - Some((input, input_file_path, input_err)) => { - let (input, input_file_path) = callbacks.some_input(input, input_file_path); - (input, input_file_path, input_err) - }, - None => match callbacks.no_input(&matches, &sopts, &cfg, &odir, &ofile, &descriptions) { - Some((input, input_file_path)) => (input, input_file_path, None), - None => return (Ok(()), None), - }, - }; + Some(v) => v, + None => { + match matches.free.len() { + 0 => { + let config = dummy_config(sopts, cfg, diagnostic_output); + interface::run_compiler(config, |compiler| { + let sopts = &compiler.session().opts; + if sopts.describe_lints { + describe_lints( + compiler.session(), + &*compiler.session().lint_store.borrow(), + false + ); + return; + } + let should_stop = RustcDefaultCalls::print_crate_info( + &***compiler.codegen_backend(), + compiler.session(), + None, + &odir, + &ofile + ); - let loader = file_loader.unwrap_or(box RealFileLoader); - let source_map = Lrc::new(SourceMap::with_file_loader(loader, sopts.file_path_mapping())); - let mut sess = session::build_session_with_source_map( - sopts, - input_file_path.clone(), - descriptions, - source_map, - emitter_dest.map(|e| DiagnosticOutput::Raw(e)).unwrap_or(DiagnosticOutput::Default), - Default::default(), - ); + if should_stop == Compilation::Stop { + return; + } + early_error(sopts.error_format, "no input filename given") + }); + return Ok(()); + } + 1 => panic!("make_input should have provided valid inputs"), + _ => early_error(sopts.error_format, &format!( + "multiple input filenames provided (first two filenames are `{}` and `{}`)", + matches.free[0], + matches.free[1], + )), + } + } + }; if let Some(err) = input_err { // Immediately stop compilation if there was an issue reading // the input (for example if the input stream is not UTF-8). - sess.err(&err.to_string()); - return (Err(CompileIncomplete::Stopped), Some(sess)); + interface::run_compiler(dummy_config(sopts, cfg, diagnostic_output), |compiler| { + compiler.session().err(&err.to_string()); + }); + return Err(ErrorReported); } - let codegen_backend = util::get_codegen_backend(&sess); + let mut config = interface::Config { + opts: sopts, + crate_cfg: cfg, + input, + input_path: input_file_path, + output_file: ofile, + output_dir: odir, + file_loader, + diagnostic_output, + stderr: None, + crate_name: None, + lint_caps: Default::default(), + }; - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); + callbacks.config(&mut config); + + interface::run_compiler(config, |compiler| { + let sess = compiler.session(); + let should_stop = RustcDefaultCalls::print_crate_info( + &***compiler.codegen_backend(), + sess, + Some(compiler.input()), + compiler.output_dir(), + compiler.output_file(), + ).and_then(|| RustcDefaultCalls::list_metadata( + sess, + compiler.cstore(), + &matches, + compiler.input() + )); + + if should_stop == Compilation::Stop { + return sess.compile_status(); + } - let mut cfg = config::build_configuration(&sess, cfg); - util::add_configuration(&mut cfg, &sess, &*codegen_backend); - sess.parse_sess.config = cfg; + let pretty_info = parse_pretty(sess, &matches); - let result = { - let plugins = sess.opts.debugging_opts.extra_plugins.clone(); + compiler.parse()?; - let cstore = CStore::new(codegen_backend.metadata_loader()); + if let Some((ppm, opt_uii)) = pretty_info { + if ppm.needs_ast_map(&opt_uii) { + pretty::visit_crate(sess, &mut compiler.parse()?.peek_mut(), ppm); + compiler.global_ctxt()?.peek_mut().enter(|tcx| { + let expanded_crate = compiler.expansion()?.take().0; + pretty::print_after_hir_lowering( + tcx, + compiler.input(), + &expanded_crate, + ppm, + opt_uii.clone(), + compiler.output_file().as_ref().map(|p| &**p), + ); + Ok(()) + })?; + return sess.compile_status(); + } else { + let mut krate = compiler.parse()?.take(); + pretty::visit_crate(sess, &mut krate, ppm); + pretty::print_after_parsing( + sess, + &compiler.input(), + &krate, + ppm, + compiler.output_file().as_ref().map(|p| &**p), + ); + return sess.compile_status(); + } + } - do_or_return!(callbacks.late_callback(&*codegen_backend, - &matches, - &sess, - &cstore, - &input, - &odir, - &ofile), Some(sess)); + if !callbacks.after_parsing(compiler) { + return sess.compile_status(); + } - let _sess_abort_error = OnDrop(|| sess.diagnostic().print_error_count()); + if sess.opts.debugging_opts.parse_only || + sess.opts.debugging_opts.show_span.is_some() || + sess.opts.debugging_opts.ast_json_noexpand { + return sess.compile_status(); + } - let control = callbacks.build_controller(&sess, &matches); + compiler.register_plugins()?; - driver::compile_input(codegen_backend, - &sess, - &cstore, - &input_file_path, - &input, - &odir, - &ofile, - Some(plugins), - &control) - }; + // Lint plugins are registered; now we can process command line flags. + if sess.opts.describe_lints { + describe_lints(&sess, &sess.lint_store.borrow(), true); + return sess.compile_status(); + } + + compiler.prepare_outputs()?; + + if sess.opts.output_types.contains_key(&OutputType::DepInfo) + && sess.opts.output_types.len() == 1 + { + return sess.compile_status(); + } + + compiler.global_ctxt()?; + + if sess.opts.debugging_opts.no_analysis || + sess.opts.debugging_opts.ast_json { + return sess.compile_status(); + } + + if sess.opts.debugging_opts.save_analysis { + let expanded_crate = &compiler.expansion()?.peek().0; + let crate_name = compiler.crate_name()?.peek().clone(); + compiler.global_ctxt()?.peek_mut().enter(|tcx| { + let result = tcx.analysis(LOCAL_CRATE); + + time(sess, "save analysis", || { + save::process_crate( + tcx, + &expanded_crate, + &crate_name, + &compiler.input(), + None, + DumpHandler::new(compiler.output_dir().as_ref().map(|p| &**p), &crate_name) + ) + }); + + result + // AST will be dropped *after* the `after_analysis` callback + // (needed by the RLS) + })?; + } else { + // Drop AST after creating GlobalCtxt to free memory + mem::drop(compiler.expansion()?.take()); + } + + compiler.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?; + + if !callbacks.after_analysis(compiler) { + return sess.compile_status(); + } + + if sess.opts.debugging_opts.save_analysis { + mem::drop(compiler.expansion()?.take()); + } + + compiler.ongoing_codegen()?; + + // Drop GlobalCtxt after starting codegen to free memory + mem::drop(compiler.global_ctxt()?.take()); + + if sess.opts.debugging_opts.print_type_sizes { + sess.code_stats.borrow().print_type_sizes(); + } + + compiler.link()?; + + if sess.opts.debugging_opts.perf_stats { + sess.print_perf_stats(); + } - (result, Some(sess)) + if sess.print_fuel_crate.is_some() { + eprintln!("Fuel used by {}: {}", + sess.print_fuel_crate.as_ref().unwrap(), + sess.print_fuel.load(SeqCst)); + } + + Ok(()) + }) } #[cfg(unix)] @@ -359,72 +455,6 @@ impl Compilation { } } -/// A trait for customizing the compilation process. Offers a number of hooks for -/// executing custom code or customizing input. -pub trait CompilerCalls<'a> { - /// Hook for a callback early in the process of handling arguments. This will - /// be called straight after options have been parsed but before anything - /// else (e.g., selecting input and output). - fn early_callback(&mut self, - _: &getopts::Matches, - _: &config::Options, - _: &ast::CrateConfig, - _: &errors::registry::Registry, - _: ErrorOutputType) - -> Compilation { - Compilation::Continue - } - - /// Hook for a callback late in the process of handling arguments. This will - /// be called just before actual compilation starts (and before build_controller - /// is called), after all arguments etc. have been completely handled. - fn late_callback(&mut self, - _: &dyn CodegenBackend, - _: &getopts::Matches, - _: &Session, - _: &CStore, - _: &Input, - _: &Option, - _: &Option) - -> Compilation { - Compilation::Continue - } - - /// Called after we extract the input from the arguments. Gives the implementer - /// an opportunity to change the inputs or to add some custom input handling. - /// The default behaviour is to simply pass through the inputs. - fn some_input(&mut self, - input: Input, - input_path: Option) - -> (Input, Option) { - (input, input_path) - } - - /// Called after we extract the input from the arguments if there is no valid - /// input. Gives the implementer an opportunity to supply alternate input (by - /// returning a Some value) or to add custom behaviour for this error such as - /// emitting error messages. Returning None will cause compilation to stop - /// at this point. - fn no_input(&mut self, - _: &getopts::Matches, - _: &config::Options, - _: &ast::CrateConfig, - _: &Option, - _: &Option, - _: &errors::registry::Registry) - -> Option<(Input, Option)> { - None - } - - // Create a CompilController struct for controlling the behaviour of - // compilation. - fn build_controller( - self: Box, - _: &Session, - _: &getopts::Matches - ) -> CompileController<'a>; -} - /// CompilerCalls instance for a regular rustc build. #[derive(Copy, Clone)] pub struct RustcDefaultCalls; @@ -528,178 +558,6 @@ fn show_content_with_pager(content: &String) { } } -impl<'a> CompilerCalls<'a> for RustcDefaultCalls { - fn early_callback(&mut self, - matches: &getopts::Matches, - _: &config::Options, - _: &ast::CrateConfig, - _: &errors::registry::Registry, - output: ErrorOutputType) - -> Compilation { - if let Some(ref code) = matches.opt_str("explain") { - handle_explain(code, output); - return Compilation::Stop; - } - - Compilation::Continue - } - - fn no_input(&mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - odir: &Option, - ofile: &Option, - descriptions: &errors::registry::Registry) - -> Option<(Input, Option)> { - match matches.free.len() { - 0 => { - let mut sess = build_session(sopts.clone(), - None, - descriptions.clone()); - if sopts.describe_lints { - let mut ls = lint::LintStore::new(); - rustc_lint::register_builtins(&mut ls, Some(&sess)); - describe_lints(&sess, &ls, false); - return None; - } - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - let mut cfg = config::build_configuration(&sess, cfg.clone()); - let codegen_backend = util::get_codegen_backend(&sess); - util::add_configuration(&mut cfg, &sess, &*codegen_backend); - sess.parse_sess.config = cfg; - let should_stop = RustcDefaultCalls::print_crate_info( - &*codegen_backend, - &sess, - None, - odir, - ofile - ); - - if should_stop == Compilation::Stop { - return None; - } - early_error(sopts.error_format, "no input filename given"); - } - 1 => panic!("make_input should have provided valid inputs"), - _ => - early_error( - sopts.error_format, - &format!( - "multiple input filenames provided (first two filenames are `{}` and `{}`)", - matches.free[0], - matches.free[1], - ), - ) - } - } - - fn late_callback(&mut self, - codegen_backend: &dyn CodegenBackend, - matches: &getopts::Matches, - sess: &Session, - cstore: &CStore, - input: &Input, - odir: &Option, - ofile: &Option) - -> Compilation { - RustcDefaultCalls::print_crate_info(codegen_backend, sess, Some(input), odir, ofile) - .and_then(|| RustcDefaultCalls::list_metadata(sess, cstore, matches, input)) - } - - fn build_controller(self: Box, - sess: &Session, - matches: &getopts::Matches) - -> CompileController<'a> { - let mut control = CompileController::basic(); - - control.keep_ast = sess.opts.debugging_opts.keep_ast; - control.continue_parse_after_error = sess.opts.debugging_opts.continue_parse_after_error; - - if let Some((ppm, opt_uii)) = parse_pretty(sess, matches) { - if ppm.needs_ast_map(&opt_uii) { - control.after_hir_lowering.stop = Compilation::Stop; - - control.after_parse.callback = box move |state| { - let mut krate = state.krate.take().unwrap(); - pretty::visit_crate(state.session, &mut krate, ppm); - state.krate = Some(krate); - }; - control.after_hir_lowering.callback = box move |state| { - pretty::print_after_hir_lowering(state.session, - state.cstore.unwrap(), - state.hir_map.unwrap(), - state.resolutions.unwrap(), - state.input, - &state.expanded_crate.take().unwrap(), - state.crate_name.unwrap(), - ppm, - state.output_filenames.unwrap(), - opt_uii.clone(), - state.out_file); - }; - } else { - control.after_parse.stop = Compilation::Stop; - - control.after_parse.callback = box move |state| { - let mut krate = state.krate.take().unwrap(); - pretty::visit_crate(state.session, &mut krate, ppm); - pretty::print_after_parsing(state.session, - state.input, - &krate, - ppm, - state.out_file); - }; - } - - return control; - } - - if sess.opts.debugging_opts.parse_only || - sess.opts.debugging_opts.show_span.is_some() || - sess.opts.debugging_opts.ast_json_noexpand { - control.after_parse.stop = Compilation::Stop; - } - - if sess.opts.debugging_opts.no_analysis || - sess.opts.debugging_opts.ast_json { - control.after_hir_lowering.stop = Compilation::Stop; - } - - if sess.opts.debugging_opts.save_analysis { - enable_save_analysis(&mut control); - } - - if sess.print_fuel_crate.is_some() { - let old_callback = control.compilation_done.callback; - control.compilation_done.callback = box move |state| { - old_callback(state); - let sess = state.session; - eprintln!("Fuel used by {}: {}", - sess.print_fuel_crate.as_ref().unwrap(), - sess.print_fuel.load(SeqCst)); - } - } - control - } -} - -pub fn enable_save_analysis(control: &mut CompileController) { - control.keep_ast = true; - control.after_analysis.callback = box |state| { - time(state.session, "save analysis", || { - save::process_crate(state.tcx.unwrap(), - state.expanded_crate.unwrap(), - state.crate_name.unwrap(), - state.input, - None, - DumpHandler::new(state.out_dir, - state.crate_name.unwrap())) - }); - }; - control.after_analysis.run_callback_on_error = true; -} - impl RustcDefaultCalls { pub fn list_metadata(sess: &Session, cstore: &CStore, @@ -798,7 +656,7 @@ impl RustcDefaultCalls { let mut cfgs = sess.parse_sess.config.iter().filter_map(|&(name, ref value)| { let gated_cfg = GatedCfg::gate(&ast::MetaItem { - ident: ast::Path::from_ident(ast::Ident::with_empty_ctxt(name)), + path: ast::Path::from_ident(ast::Ident::with_empty_ctxt(name)), node: ast::MetaItemKind::Word, span: DUMMY_SP, }); @@ -813,7 +671,7 @@ impl RustcDefaultCalls { // through to build scripts. let value = value.as_ref().map(|s| s.as_str()); let value = value.as_ref().map(|s| s.as_ref()); - if name != "target_feature" || value != Some("crt-static") { + if name != sym::target_feature || value != Some("crt-static") { if !allow_unstable_cfg && gated_cfg.is_some() { return None } @@ -888,7 +746,7 @@ fn usage(verbose: bool, include_unstable_options: bool) { } let message = "Usage: rustc [OPTIONS] INPUT"; let nightly_help = if nightly_options::is_nightly_build() { - "\n -Z help Print internal options for debugging rustc" + "\n -Z help Print unstable compiler options" } else { "" }; @@ -1036,7 +894,7 @@ Available lint options: } fn describe_debug_flags() { - println!("\nAvailable debug options:\n"); + println!("\nAvailable options:\n"); print_flag_list("-Z", config::DB_OPTIONS); } @@ -1195,49 +1053,6 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec(name: String, f: F) -> Result> - where F: FnOnce() -> R + Send + 'static, - R: Send + 'static, -{ - // We need a thread for soundness of thread local storage in rustc. For debugging purposes - // we allow an escape hatch where everything runs on the main thread. - if env::var_os("RUSTC_UNSTABLE_NO_MAIN_THREAD").is_none() { - let mut cfg = thread::Builder::new().name(name); - - // If the env is trying to override the stack size then *don't* set it explicitly. - // The libstd thread impl will fetch the `RUST_MIN_STACK` env var itself. - if env::var_os("RUST_MIN_STACK").is_none() { - cfg = cfg.stack_size(STACK_SIZE); - } - - let thread = cfg.spawn(f); - thread.unwrap().join() - } else { - let f = panic::AssertUnwindSafe(f); - panic::catch_unwind(f) - } -} - -/// Runs `f` in a suitable thread for running `rustc`; returns a -/// `Result` with either the return value of `f` or -- if a panic -/// occurs -- the panic value. -pub fn in_rustc_thread(f: F) -> Result> - where F: FnOnce() -> R + Send + 'static, - R: Send + 'static, -{ - in_named_rustc_thread("rustc".to_string(), f) -} - /// Gets a list of extra command-line flags provided by the user, as strings. /// /// This function is used during ICEs to show more information useful for @@ -1292,28 +1107,15 @@ fn extra_compiler_flags() -> Option<(Vec, bool)> { } } -#[derive(Debug)] -pub struct CompilationFailure; - -impl Error for CompilationFailure {} - -impl Display for CompilationFailure { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "compilation had errors") - } -} - /// Runs a procedure which will detect panics in the compiler and print nicer /// error messages rather than just failing the test. /// /// The diagnostic emitter yielded to the procedure should be used for reporting /// errors of the compiler. -pub fn monitor(f: F) -> Result<(), CompilationFailure> { - in_rustc_thread(move || { - f() - }).map_err(|value| { +pub fn report_ices_to_stderr_if_any R, R>(f: F) -> Result { + catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| { if value.is::() { - CompilationFailure + ErrorReported } else { // Thread panicked without emitting a fatal diagnostic eprintln!(""); @@ -1323,7 +1125,7 @@ pub fn monitor(f: F) -> Result<(), CompilationFail None, false, false)); - let handler = errors::Handler::with_emitter(true, false, emitter); + let handler = errors::Handler::with_emitter(true, None, emitter); // a .span_bug or .bug call has already printed what // it wants to print. @@ -1360,44 +1162,25 @@ pub fn monitor(f: F) -> Result<(), CompilationFail }) } -pub fn diagnostics_registry() -> errors::registry::Registry { - use errors::registry::Registry; - - let mut all_errors = Vec::new(); - all_errors.extend_from_slice(&rustc::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS); - // FIXME: need to figure out a way to get these back in here - // all_errors.extend_from_slice(get_codegen_backend(sess).diagnostics()); - all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_mir::DIAGNOSTICS); - all_errors.extend_from_slice(&syntax::DIAGNOSTICS); - - Registry::new(&all_errors) -} - /// This allows tools to enable rust logging without having to magically match rustc's /// log crate version pub fn init_rustc_env_logger() { - env_logger::init(); + env_logger::init_from_env("RUSTC_LOG"); } pub fn main() { init_rustc_env_logger(); - let result = run(|| { + let result = report_ices_to_stderr_if_any(|| { let args = env::args_os().enumerate() .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| { early_error(ErrorOutputType::default(), &format!("Argument {} is not valid Unicode: {:?}", i, arg)) })) .collect::>(); - run_compiler(&args, - Box::new(RustcDefaultCalls), - None, - None) + run_compiler(&args, &mut DefaultCallbacks, None, None) + }).and_then(|result| result); + process::exit(match result { + Ok(_) => EXIT_SUCCESS, + Err(_) => EXIT_FAILURE, }); - process::exit(result as i32); } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index ac2f6da0c6084..d92f3aafa1c7e 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -6,13 +6,14 @@ use rustc::hir; use rustc::hir::map as hir_map; use rustc::hir::map::blocks; use rustc::hir::print as pprust_hir; +use rustc::hir::def_id::LOCAL_CRATE; use rustc::session::Session; -use rustc::session::config::{Input, OutputFilenames}; -use rustc::ty::{self, TyCtxt, Resolutions, AllArenas}; -use rustc_interface::util; +use rustc::session::config::Input; +use rustc::ty::{self, TyCtxt}; +use rustc::util::common::ErrorReported; +use rustc_interface::util::ReplaceBodyWithLoop; use rustc_borrowck as borrowck; use rustc_borrowck::graphviz as borrowck_dot; -use rustc_metadata::cstore::CStore; use rustc_mir::util::{write_mir_pretty, write_mir_graphviz}; use syntax::ast; @@ -34,8 +35,9 @@ pub use self::UserIdentifiedItem::*; pub use self::PpSourceMode::*; pub use self::PpMode::*; use self::NodesMatchingUII::*; -use abort_on_err; -use driver; +use crate::abort_on_err; + +use crate::source_name; #[derive(Copy, Clone, PartialEq, Debug)] pub enum PpSourceMode { @@ -152,18 +154,20 @@ pub fn parse_pretty(sess: &Session, impl PpSourceMode { /// Constructs a `PrinterSupport` object and passes it to `f`. - fn call_with_pp_support<'tcx, A, F>(&self, - sess: &'tcx Session, - hir_map: Option<&hir_map::Map<'tcx>>, - f: F) - -> A - where F: FnOnce(&dyn PrinterSupport) -> A + fn call_with_pp_support<'tcx, A, F>( + &self, + sess: &'tcx Session, + tcx: Option>, + f: F, + ) -> A + where + F: FnOnce(&dyn PrinterSupport) -> A, { match *self { PpmNormal | PpmEveryBodyLoops | PpmExpanded => { let annotation = NoAnn { sess, - hir_map: hir_map.map(|m| m.clone()), + tcx, }; f(&annotation) } @@ -171,7 +175,7 @@ impl PpSourceMode { PpmIdentified | PpmExpandedIdentified => { let annotation = IdentifiedAnnotation { sess, - hir_map: hir_map.map(|m| m.clone()), + tcx, }; f(&annotation) } @@ -184,57 +188,36 @@ impl PpSourceMode { _ => panic!("Should use call_with_pp_support_hir"), } } - fn call_with_pp_support_hir<'tcx, A, F>( - &self, - sess: &'tcx Session, - cstore: &'tcx CStore, - hir_map: &hir_map::Map<'tcx>, - resolutions: &Resolutions, - output_filenames: &OutputFilenames, - id: &str, - f: F - ) -> A - where F: FnOnce(&dyn HirPrinterSupport, &hir::Crate) -> A + fn call_with_pp_support_hir<'tcx, A, F>(&self, tcx: TyCtxt<'tcx>, f: F) -> A + where + F: FnOnce(&dyn HirPrinterSupport<'_>, &hir::Crate) -> A, { match *self { PpmNormal => { let annotation = NoAnn { - sess, - hir_map: Some(hir_map.clone()), + sess: tcx.sess, + tcx: Some(tcx), }; - f(&annotation, hir_map.forest.krate()) + f(&annotation, tcx.hir().forest.krate()) } PpmIdentified => { let annotation = IdentifiedAnnotation { - sess, - hir_map: Some(hir_map.clone()), + sess: tcx.sess, + tcx: Some(tcx), }; - f(&annotation, hir_map.forest.krate()) + f(&annotation, tcx.hir().forest.krate()) } PpmTyped => { - let control = &driver::CompileController::basic(); - let codegen_backend = util::get_codegen_backend(sess); - let mut arenas = AllArenas::new(); - driver::phase_3_run_analysis_passes(&*codegen_backend, - control, - sess, - cstore, - hir_map.clone(), - resolutions.clone(), - &mut arenas, - id, - output_filenames, - |tcx, _, result| { - abort_on_err(result, tcx.sess); - let empty_tables = ty::TypeckTables::empty(None); - let annotation = TypedAnnotation { - tcx, - tables: Cell::new(&empty_tables) - }; - tcx.dep_graph.with_ignore(|| { - f(&annotation, hir_map.forest.krate()) - }) + abort_on_err(tcx.analysis(LOCAL_CRATE), tcx.sess); + + let empty_tables = ty::TypeckTables::empty(None); + let annotation = TypedAnnotation { + tcx, + tables: Cell::new(&empty_tables) + }; + tcx.dep_graph.with_ignore(|| { + f(&annotation, tcx.hir().forest.krate()) }) } _ => panic!("Should use call_with_pp_support"), @@ -270,8 +253,10 @@ trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn; /// Computes an user-readable representation of a path, if possible. - fn node_path(&self, id: ast::NodeId) -> Option { - self.hir_map().and_then(|map| map.def_path_from_id(id)).map(|path| { + fn node_path(&self, id: hir::HirId) -> Option { + self.hir_map().and_then(|map| { + map.def_path_from_hir_id(id) + }).map(|path| { path.data .into_iter() .map(|elem| elem.data.to_string()) @@ -283,7 +268,7 @@ trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { struct NoAnn<'hir> { sess: &'hir Session, - hir_map: Option>, + tcx: Option>, } impl<'hir> PrinterSupport for NoAnn<'hir> { @@ -302,7 +287,7 @@ impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> { } fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> { - self.hir_map.as_ref() + self.tcx.map(|tcx| tcx.hir()) } fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn { @@ -312,10 +297,10 @@ impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> { impl<'hir> pprust::PpAnn for NoAnn<'hir> {} impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { - fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested) + fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) -> io::Result<()> { - if let Some(ref map) = self.hir_map { - pprust_hir::PpAnn::nested(map, state, nested) + if let Some(tcx) = self.tcx { + pprust_hir::PpAnn::nested(tcx.hir(), state, nested) } else { Ok(()) } @@ -324,7 +309,7 @@ impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { struct IdentifiedAnnotation<'hir> { sess: &'hir Session, - hir_map: Option>, + tcx: Option>, } impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> { @@ -338,13 +323,13 @@ impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> { } impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> { - fn pre(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { + fn pre(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) -> io::Result<()> { match node { pprust::AnnNode::Expr(_) => s.popen(), _ => Ok(()), } } - fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { + fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) -> io::Result<()> { match node { pprust::AnnNode::Ident(_) | pprust::AnnNode::Name(_) => Ok(()), @@ -380,7 +365,7 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { } fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> { - self.hir_map.as_ref() + self.tcx.map(|tcx| tcx.hir()) } fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn { @@ -389,27 +374,27 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { } impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { - fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested) + fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) -> io::Result<()> { - if let Some(ref map) = self.hir_map { - pprust_hir::PpAnn::nested(map, state, nested) + if let Some(ref tcx) = self.tcx { + pprust_hir::PpAnn::nested(tcx.hir(), state, nested) } else { Ok(()) } } - fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { + fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> io::Result<()> { match node { pprust_hir::AnnNode::Expr(_) => s.popen(), _ => Ok(()), } } - fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { + fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> io::Result<()> { match node { pprust_hir::AnnNode::Name(_) => Ok(()), pprust_hir::AnnNode::Item(item) => { s.s.space()?; - s.synth_comment(format!("node_id: {} hir local_id: {}", - item.id, item.hir_id.local_id.as_u32())) + s.synth_comment(format!("hir_id: {} hir local_id: {}", + item.hir_id, item.hir_id.local_id.as_u32())) } pprust_hir::AnnNode::SubItem(id) => { s.s.space()?; @@ -428,8 +413,8 @@ impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { } pprust_hir::AnnNode::Pat(pat) => { s.s.space()?; - s.synth_comment(format!("pat node_id: {} hir local_id: {}", - pat.id, pat.hir_id.local_id.as_u32())) + s.synth_comment(format!("pat hir_id: {} hir local_id: {}", + pat.hir_id, pat.hir_id.local_id.as_u32())) } } } @@ -450,7 +435,7 @@ impl<'a> PrinterSupport for HygieneAnnotation<'a> { } impl<'a> pprust::PpAnn for HygieneAnnotation<'a> { - fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { + fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) -> io::Result<()> { match node { pprust::AnnNode::Ident(&ast::Ident { name, span }) => { s.s.space()?; @@ -467,9 +452,8 @@ impl<'a> pprust::PpAnn for HygieneAnnotation<'a> { } } - -struct TypedAnnotation<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct TypedAnnotation<'a, 'tcx> { + tcx: TyCtxt<'tcx>, tables: Cell<&'a ty::TypeckTables<'tcx>>, } @@ -486,13 +470,13 @@ impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> { self } - fn node_path(&self, id: ast::NodeId) -> Option { - Some(self.tcx.node_path_str(id)) + fn node_path(&self, id: hir::HirId) -> Option { + Some(self.tcx.def_path_str(self.tcx.hir().local_def_id_from_hir_id(id))) } } impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> { - fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested) + fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) -> io::Result<()> { let old_tables = self.tables.get(); if let pprust_hir::Nested::Body(id) = nested { @@ -502,13 +486,13 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> { self.tables.set(old_tables); Ok(()) } - fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { + fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> io::Result<()> { match node { pprust_hir::AnnNode::Expr(_) => s.popen(), _ => Ok(()), } } - fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { + fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> io::Result<()> { match node { pprust_hir::AnnNode::Expr(expr) => { s.s.space()?; @@ -556,12 +540,12 @@ impl FromStr for UserIdentifiedItem { } } -enum NodesMatchingUII<'a, 'hir: 'a> { +enum NodesMatchingUII<'a> { NodesMatchingDirect(option::IntoIter), - NodesMatchingSuffix(hir_map::NodesMatchingSuffix<'a, 'hir>), + NodesMatchingSuffix(Box + 'a>), } -impl<'a, 'hir> Iterator for NodesMatchingUII<'a, 'hir> { +impl<'a> Iterator for NodesMatchingUII<'a> { type Item = ast::NodeId; fn next(&mut self) -> Option { @@ -589,14 +573,20 @@ impl UserIdentifiedItem { fn all_matching_node_ids<'a, 'hir>(&'a self, map: &'a hir_map::Map<'hir>) - -> NodesMatchingUII<'a, 'hir> { + -> NodesMatchingUII<'a> { match *self { ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()), - ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts)), + ItemViaPath(ref parts) => { + NodesMatchingSuffix(Box::new(map.nodes_matching_suffix(&parts))) + } } } - fn to_one_node_id(self, user_option: &str, sess: &Session, map: &hir_map::Map) -> ast::NodeId { + fn to_one_node_id(self, + user_option: &str, + sess: &Session, + map: &hir_map::Map<'_>) + -> ast::NodeId { let fail_because = |is_wrong_because| -> ast::NodeId { let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \ {}, which {}", @@ -624,22 +614,23 @@ impl UserIdentifiedItem { } } -fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - code: blocks::Code<'tcx>, - mode: PpFlowGraphMode, - mut out: W) - -> io::Result<()> { +fn print_flowgraph<'tcx, W: Write>( + variants: Vec, + tcx: TyCtxt<'tcx>, + code: blocks::Code<'tcx>, + mode: PpFlowGraphMode, + mut out: W, +) -> io::Result<()> { let body_id = match code { blocks::Code::Expr(expr) => { // Find the function this expression is from. let mut hir_id = expr.hir_id; loop { - let node = tcx.hir().get_by_hir_id(hir_id); + let node = tcx.hir().get(hir_id); if let Some(n) = hir::map::blocks::FnLikeNode::from_node(node) { break n.body(); } - let parent = tcx.hir().get_parent_node_by_hir_id(hir_id); + let parent = tcx.hir().get_parent_node(hir_id); assert_ne!(hir_id, parent); hir_id = parent; } @@ -649,10 +640,19 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, let body = tcx.hir().body(body_id); let cfg = cfg::CFG::new(tcx, &body); let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; + let hir_id = code.id(); + // We have to disassemble the hir_id because name must be ASCII + // alphanumeric. This does not appear in the rendered graph, so it does not + // have to be user friendly. + let name = format!( + "hir_id_{}_{}", + hir_id.owner.index(), + hir_id.local_id.index(), + ); let lcfg = LabelledCFG { tcx, cfg: &cfg, - name: format!("node_{}", code.id()), + name, labelled_edges, }; @@ -691,12 +691,12 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, pub fn visit_crate(sess: &Session, krate: &mut ast::Crate, ppm: PpMode) { if let PpmSource(PpmEveryBodyLoops) = ppm { - util::ReplaceBodyWithLoop::new(sess).visit_crate(krate); + ReplaceBodyWithLoop::new(sess).visit_crate(krate); } } fn get_source(input: &Input, sess: &Session) -> (Vec, FileName) { - let src_name = input.source_name(); + let src_name = source_name(input); let src = sess.source_map() .get_source_file(&src_name) .unwrap() @@ -752,31 +752,25 @@ pub fn print_after_parsing(sess: &Session, write_output(out, ofile); } -pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, - cstore: &'tcx CStore, - hir_map: &hir_map::Map<'tcx>, - resolutions: &Resolutions, - input: &Input, - krate: &ast::Crate, - crate_name: &str, - ppm: PpMode, - output_filenames: &OutputFilenames, - opt_uii: Option, - ofile: Option<&Path>) { +pub fn print_after_hir_lowering<'tcx>( + tcx: TyCtxt<'tcx>, + input: &Input, + krate: &ast::Crate, + ppm: PpMode, + opt_uii: Option, + ofile: Option<&Path>, +) { if ppm.needs_analysis() { - print_with_analysis(sess, - cstore, - hir_map, - resolutions, - crate_name, - output_filenames, - ppm, - opt_uii, - ofile); + abort_on_err(print_with_analysis( + tcx, + ppm, + opt_uii, + ofile + ), tcx.sess); return; } - let (src, src_name) = get_source(input, sess); + let (src, src_name) = get_source(input, tcx.sess); let mut rdr = &src[..]; let mut out = Vec::new(); @@ -785,7 +779,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, (PpmSource(s), _) => { // Silently ignores an identified node. let out: &mut dyn Write = &mut out; - s.call_with_pp_support(sess, Some(hir_map), move |annotation| { + s.call_with_pp_support(tcx.sess, Some(tcx), move |annotation| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); pprust::print_crate(sess.source_map(), @@ -801,13 +795,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, (PpmHir(s), None) => { let out: &mut dyn Write = &mut out; - s.call_with_pp_support_hir(sess, - cstore, - hir_map, - resolutions, - output_filenames, - crate_name, - move |annotation, krate| { + s.call_with_pp_support_hir(tcx, move |annotation, krate| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); pprust_hir::print_crate(sess.source_map(), @@ -816,20 +804,13 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, src_name, &mut rdr, box out, - annotation.pp_ann(), - true) + annotation.pp_ann()) }) } (PpmHirTree(s), None) => { let out: &mut dyn Write = &mut out; - s.call_with_pp_support_hir(sess, - cstore, - hir_map, - resolutions, - output_filenames, - crate_name, - move |_annotation, krate| { + s.call_with_pp_support_hir(tcx, move |_annotation, krate| { debug!("pretty printing source code {:?}", s); write!(out, "{:#?}", krate) }) @@ -837,13 +818,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, (PpmHir(s), Some(uii)) => { let out: &mut dyn Write = &mut out; - s.call_with_pp_support_hir(sess, - cstore, - hir_map, - resolutions, - output_filenames, - crate_name, - move |annotation, _| { + s.call_with_pp_support_hir(tcx, move |annotation, _| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); let hir_map = annotation.hir_map().expect("-Z unpretty missing HIR map"); @@ -852,13 +827,13 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, src_name, &mut rdr, box out, - annotation.pp_ann(), - true); + annotation.pp_ann()); for node_id in uii.all_matching_node_ids(hir_map) { - let node = hir_map.get(node_id); + let hir_id = tcx.hir().node_to_hir_id(node_id); + let node = hir_map.get(hir_id); pp_state.print_node(node)?; pp_state.s.space()?; - let path = annotation.node_path(node_id) + let path = annotation.node_path(hir_id) .expect("-Z unpretty missing node paths"); pp_state.synth_comment(path)?; pp_state.s.hardbreak()?; @@ -869,16 +844,11 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, (PpmHirTree(s), Some(uii)) => { let out: &mut dyn Write = &mut out; - s.call_with_pp_support_hir(sess, - cstore, - hir_map, - resolutions, - output_filenames, - crate_name, - move |_annotation, _krate| { + s.call_with_pp_support_hir(tcx, move |_annotation, _krate| { debug!("pretty printing source code {:?}", s); - for node_id in uii.all_matching_node_ids(hir_map) { - let node = hir_map.get(node_id); + for node_id in uii.all_matching_node_ids(tcx.hir()) { + let hir_id = tcx.hir().node_to_hir_id(node_id); + let node = tcx.hir().get(hir_id); write!(out, "{:#?}", node)?; } Ok(()) @@ -896,18 +866,15 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, // analysis is performed. However, we want to call `phase_3_run_analysis_passes` // with a different callback than the standard driver, so that isn't easy. // Instead, we call that function ourselves. -fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, - cstore: &'a CStore, - hir_map: &hir_map::Map<'tcx>, - resolutions: &Resolutions, - crate_name: &str, - output_filenames: &OutputFilenames, - ppm: PpMode, - uii: Option, - ofile: Option<&Path>) { +fn print_with_analysis<'tcx>( + tcx: TyCtxt<'tcx>, + ppm: PpMode, + uii: Option, + ofile: Option<&Path>, +) -> Result<(), ErrorReported> { let nodeid = if let Some(uii) = uii { debug!("pretty printing for {:?}", uii); - Some(uii.to_one_node_id("-Z unpretty", sess, &hir_map)) + Some(uii.to_one_node_id("-Z unpretty", tcx.sess, tcx.hir())) } else { debug!("pretty printing for whole crate"); None @@ -915,66 +882,59 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, let mut out = Vec::new(); - let control = &driver::CompileController::basic(); - let codegen_backend = util::get_codegen_backend(sess); - let mut arenas = AllArenas::new(); - driver::phase_3_run_analysis_passes(&*codegen_backend, - control, - sess, - cstore, - hir_map.clone(), - resolutions.clone(), - &mut arenas, - crate_name, - output_filenames, - |tcx, _, result| { - abort_on_err(result, tcx.sess); - match ppm { - PpmMir | PpmMirCFG => { - if let Some(nodeid) = nodeid { - let def_id = tcx.hir().local_def_id(nodeid); - match ppm { - PpmMir => write_mir_pretty(tcx, Some(def_id), &mut out), - PpmMirCFG => write_mir_graphviz(tcx, Some(def_id), &mut out), - _ => unreachable!(), - }?; - } else { - match ppm { - PpmMir => write_mir_pretty(tcx, None, &mut out), - PpmMirCFG => write_mir_graphviz(tcx, None, &mut out), - _ => unreachable!(), - }?; - } - Ok(()) + tcx.analysis(LOCAL_CRATE)?; + + let mut print = || match ppm { + PpmMir | PpmMirCFG => { + if let Some(nodeid) = nodeid { + let def_id = tcx.hir().local_def_id(nodeid); + match ppm { + PpmMir => write_mir_pretty(tcx, Some(def_id), &mut out), + PpmMirCFG => write_mir_graphviz(tcx, Some(def_id), &mut out), + _ => unreachable!(), + }?; + } else { + match ppm { + PpmMir => write_mir_pretty(tcx, None, &mut out), + PpmMirCFG => write_mir_graphviz(tcx, None, &mut out), + _ => unreachable!(), + }?; } - PpmFlowGraph(mode) => { - let nodeid = - nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or unique path \ - suffix (b::c::d)"); - let node = tcx.hir().find(nodeid).unwrap_or_else(|| { - tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) - }); - - match blocks::Code::from_node(&tcx.hir(), nodeid) { - Some(code) => { - let variants = gather_flowgraph_variants(tcx.sess); - - let out: &mut dyn Write = &mut out; - - print_flowgraph(variants, tcx, code, mode, out) - } - None => { - let message = format!("--pretty=flowgraph needs block, fn, or method; \ - got {:?}", - node); + Ok(()) + } + PpmFlowGraph(mode) => { + let nodeid = + nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or unique path \ + suffix (b::c::d)"); + let hir_id = tcx.hir().node_to_hir_id(nodeid); + let node = tcx.hir().find(hir_id).unwrap_or_else(|| { + tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) + }); + + match blocks::Code::from_node(&tcx.hir(), hir_id) { + Some(code) => { + let variants = gather_flowgraph_variants(tcx.sess); + + let out: &mut dyn Write = &mut out; + + print_flowgraph(variants, tcx, code, mode, out) + } + None => { + let message = format!("--pretty=flowgraph needs block, fn, or method; \ + got {:?}", + node); - tcx.sess.span_fatal(tcx.hir().span(nodeid), &message) - } + let hir_id = tcx.hir().node_to_hir_id(nodeid); + tcx.sess.span_fatal(tcx.hir().span(hir_id), &message) } } - _ => unreachable!(), } - }).unwrap(); + _ => unreachable!(), + }; + + print().unwrap(); write_output(out, ofile); + + Ok(()) } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs deleted file mode 100644 index 309a9f7b52522..0000000000000 --- a/src/librustc_driver/test.rs +++ /dev/null @@ -1,670 +0,0 @@ -//! Standalone tests for the inference module. - -use driver; -use errors; -use errors::emitter::Emitter; -use errors::{DiagnosticBuilder, Level}; -use rustc::hir; -use rustc::hir::map as hir_map; -use rustc::infer::outlives::env::OutlivesEnvironment; -use rustc::infer::{self, InferOk, InferResult, SuppressRegionErrors}; -use rustc::middle::region; -use rustc::session::config::{OutputFilenames, OutputTypes}; -use rustc::session::{self, config}; -use rustc::traits::ObligationCause; -use rustc::ty::query::OnDiskCache; -use rustc::ty::subst::Subst; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_data_structures::sync::{self, Lrc}; -use rustc_interface::util; -use rustc_lint; -use rustc_metadata::cstore::CStore; -use rustc_target::spec::abi::Abi; -use syntax; -use syntax::ast; -use syntax::feature_gate::UnstableFeatures; -use syntax::source_map::{FileName, FilePathMapping, SourceMap}; -use syntax::symbol::Symbol; - -use std::path::PathBuf; -use std::sync::mpsc; - -struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>, - region_scope_tree: &'a mut region::ScopeTree, - param_env: ty::ParamEnv<'tcx>, -} - -struct RH<'a> { - id: hir::ItemLocalId, - sub: &'a [RH<'a>], -} - -const EMPTY_SOURCE_STR: &'static str = "#![feature(no_core)] #![no_core]"; - -struct ExpectErrorEmitter { - messages: Vec, -} - -fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) { - match lvl { - Level::Bug | Level::Fatal | Level::Error => {} - _ => { - return; - } - } - - debug!("Error: {}", msg); - match e.messages.iter().position(|m| msg.contains(m)) { - Some(i) => { - e.messages.remove(i); - } - None => { - debug!("Unexpected error: {} Expected: {:?}", msg, e.messages); - panic!("Unexpected error: {} Expected: {:?}", msg, e.messages); - } - } -} - -impl Emitter for ExpectErrorEmitter { - fn emit(&mut self, db: &DiagnosticBuilder) { - remove_message(self, &db.message(), db.level); - for child in &db.children { - remove_message(self, &child.message(), child.level); - } - } -} - -fn errors(msgs: &[&str]) -> (Box, usize) { - let v = msgs.iter().map(|m| m.to_string()).collect(); - ( - box ExpectErrorEmitter { messages: v } as Box, - msgs.len(), - ) -} - -fn test_env(source_string: &str, args: (Box, usize), body: F) -where - F: FnOnce(Env) + sync::Send, -{ - syntax::with_globals(|| { - let mut options = config::Options::default(); - options.debugging_opts.verbose = true; - options.unstable_features = UnstableFeatures::Allow; - - // When we're compiling this library with `--test` it'll run as a binary but - // not actually exercise much functionality. - // As a result most of the logic loading the codegen backend is defunkt - // (it assumes we're a dynamic library in a sysroot) - // so let's just use the metadata only backend which doesn't need to load any libraries. - options.debugging_opts.codegen_backend = Some("metadata_only".to_owned()); - - driver::spawn_thread_pool(options, |options| { - test_env_with_pool(options, source_string, args, body) - }) - }); -} - -fn test_env_with_pool( - options: config::Options, - source_string: &str, - (emitter, expected_err_count): (Box, usize), - body: F, -) where - F: FnOnce(Env), -{ - let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter); - let sess = session::build_session_( - options, - None, - diagnostic_handler, - Lrc::new(SourceMap::new(FilePathMapping::empty())), - Default::default(), - ); - let cstore = CStore::new(util::get_codegen_backend(&sess).metadata_loader()); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - let input = config::Input::Str { - name: FileName::anon_source_code(&source_string), - input: source_string.to_string(), - }; - let krate = - driver::phase_1_parse_input(&driver::CompileController::basic(), &sess, &input).unwrap(); - let driver::ExpansionResult { - defs, - resolutions, - mut hir_forest, - .. - } = { - driver::phase_2_configure_and_expand( - &sess, - &cstore, - krate, - None, - "test", - None, - |_| Ok(()), - ).expect("phase 2 aborted") - }; - - let mut arenas = ty::AllArenas::new(); - let hir_map = hir_map::map_crate(&sess, &cstore, &mut hir_forest, &defs); - - // Run just enough stuff to build a tcx. - let (tx, _rx) = mpsc::channel(); - let outputs = OutputFilenames { - out_directory: PathBuf::new(), - out_filestem: String::new(), - single_output_file: None, - extra: String::new(), - outputs: OutputTypes::new(&[]), - }; - TyCtxt::create_and_enter( - &sess, - &cstore, - ty::query::Providers::default(), - ty::query::Providers::default(), - &mut arenas, - resolutions, - hir_map, - OnDiskCache::new_empty(sess.source_map()), - "test_crate", - tx, - &outputs, - |tcx| { - tcx.infer_ctxt().enter(|infcx| { - let mut region_scope_tree = region::ScopeTree::default(); - let param_env = ty::ParamEnv::empty(); - body(Env { - infcx: &infcx, - region_scope_tree: &mut region_scope_tree, - param_env: param_env, - }); - let outlives_env = OutlivesEnvironment::new(param_env); - let def_id = tcx.hir().local_def_id(ast::CRATE_NODE_ID); - infcx.resolve_regions_and_report_errors( - def_id, - ®ion_scope_tree, - &outlives_env, - SuppressRegionErrors::default(), - ); - assert_eq!(tcx.sess.err_count(), expected_err_count); - }); - }, - ); -} - -fn d1() -> ty::DebruijnIndex { - ty::INNERMOST -} - -fn d2() -> ty::DebruijnIndex { - d1().shifted_in(1) -} - -impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { - pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { - self.infcx.tcx - } - - pub fn create_region_hierarchy( - &mut self, - rh: &RH, - parent: (region::Scope, region::ScopeDepth), - ) { - let me = region::Scope { - id: rh.id, - data: region::ScopeData::Node, - }; - self.region_scope_tree.record_scope_parent(me, Some(parent)); - for child_rh in rh.sub { - self.create_region_hierarchy(child_rh, (me, parent.1 + 1)); - } - } - - pub fn create_simple_region_hierarchy(&mut self) { - // Creates a region hierarchy where 1 is root, 10 and 11 are - // children of 1, etc. - - let dscope = region::Scope { - id: hir::ItemLocalId::from_u32(1), - data: region::ScopeData::Destruction, - }; - self.region_scope_tree.record_scope_parent(dscope, None); - self.create_region_hierarchy( - &RH { - id: hir::ItemLocalId::from_u32(1), - sub: &[ - RH { - id: hir::ItemLocalId::from_u32(10), - sub: &[], - }, - RH { - id: hir::ItemLocalId::from_u32(11), - sub: &[], - }, - ], - }, - (dscope, 1), - ); - } - - #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now - pub fn lookup_item(&self, names: &[String]) -> ast::NodeId { - return match search_mod(self, &self.infcx.tcx.hir().krate().module, 0, names) { - Some(id) => id, - None => { - panic!("no item found: `{}`", names.join("::")); - } - }; - - fn search_mod( - this: &Env, - m: &hir::Mod, - idx: usize, - names: &[String], - ) -> Option { - assert!(idx < names.len()); - for item in &m.item_ids { - let item = this.infcx.tcx.hir().expect_item(item.id); - if item.ident.to_string() == names[idx] { - return search(this, item, idx + 1, names); - } - } - return None; - } - - fn search(this: &Env, it: &hir::Item, idx: usize, names: &[String]) -> Option { - if idx == names.len() { - return Some(it.id); - } - - return match it.node { - hir::ItemKind::Use(..) - | hir::ItemKind::ExternCrate(..) - | hir::ItemKind::Const(..) - | hir::ItemKind::Static(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::ForeignMod(..) - | hir::ItemKind::GlobalAsm(..) - | hir::ItemKind::Existential(..) - | hir::ItemKind::Ty(..) => None, - - hir::ItemKind::Enum(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Union(..) - | hir::ItemKind::Trait(..) - | hir::ItemKind::TraitAlias(..) - | hir::ItemKind::Impl(..) => None, - - hir::ItemKind::Mod(ref m) => search_mod(this, m, idx, names), - }; - } - } - - pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match self.infcx - .at(&ObligationCause::dummy(), self.param_env) - .sub(a, b) - { - Ok(_) => true, - Err(ref e) => panic!("Encountered error: {}", e), - } - } - - pub fn is_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - self.infcx.can_sub(self.param_env, a, b).is_ok() - } - - pub fn assert_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) { - if !self.is_subtype(a, b) { - panic!("{} is not a subtype of {}, but it should be", a, b); - } - } - - pub fn assert_eq(&self, a: Ty<'tcx>, b: Ty<'tcx>) { - self.assert_subtype(a, b); - self.assert_subtype(b, a); - } - - pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> { - self.infcx - .tcx - .mk_fn_ptr(ty::Binder::bind(self.infcx.tcx.mk_fn_sig( - input_tys.iter().cloned(), - output_ty, - false, - hir::Unsafety::Normal, - Abi::Rust, - ))) - } - - pub fn t_nil(&self) -> Ty<'tcx> { - self.infcx.tcx.mk_unit() - } - - pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> { - self.infcx.tcx.intern_tup(&[ty1, ty2]) - } - - pub fn t_param(&self, index: u32) -> Ty<'tcx> { - let name = format!("T{}", index); - self.infcx - .tcx - .mk_ty_param(index, Symbol::intern(&name).as_interned_str()) - } - - pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> { - let name = Symbol::intern(name).as_interned_str(); - self.infcx - .tcx - .mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { - def_id: self.infcx.tcx.hir().local_def_id(ast::CRATE_NODE_ID), - index, - name, - })) - } - - pub fn re_late_bound_with_debruijn( - &self, - id: u32, - debruijn: ty::DebruijnIndex, - ) -> ty::Region<'tcx> { - self.infcx - .tcx - .mk_region(ty::ReLateBound(debruijn, ty::BrAnon(id))) - } - - pub fn t_rptr(&self, r: ty::Region<'tcx>) -> Ty<'tcx> { - self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) - } - - pub fn t_rptr_late_bound(&self, id: u32) -> Ty<'tcx> { - let r = self.re_late_bound_with_debruijn(id, d1()); - self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) - } - - pub fn t_rptr_late_bound_with_debruijn( - &self, - id: u32, - debruijn: ty::DebruijnIndex, - ) -> Ty<'tcx> { - let r = self.re_late_bound_with_debruijn(id, debruijn); - self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) - } - - pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> { - let r = ty::ReScope(region::Scope { - id: hir::ItemLocalId::from_u32(id), - data: region::ScopeData::Node, - }); - self.infcx - .tcx - .mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) - } - - pub fn re_free(&self, id: u32) -> ty::Region<'tcx> { - self.infcx.tcx.mk_region(ty::ReFree(ty::FreeRegion { - scope: self.infcx.tcx.hir().local_def_id(ast::CRATE_NODE_ID), - bound_region: ty::BrAnon(id), - })) - } - - pub fn t_rptr_free(&self, id: u32) -> Ty<'tcx> { - let r = self.re_free(id); - self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) - } - - pub fn sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, ()> { - self.infcx - .at(&ObligationCause::dummy(), self.param_env) - .sub(t1, t2) - } - - /// Checks that `t1 <: t2` is true (this may register additional - /// region checks). - pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { - match self.sub(t1, t2) { - Ok(InferOk { - obligations, - value: (), - }) => { - // None of these tests should require nested obligations. - assert!(obligations.is_empty()); - } - Err(ref e) => { - panic!("unexpected error computing sub({:?},{:?}): {}", t1, t2, e); - } - } - } -} - -#[test] -fn contravariant_region_ptr_ok() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { - env.create_simple_region_hierarchy(); - let t_rptr1 = env.t_rptr_scope(1); - let t_rptr10 = env.t_rptr_scope(10); - env.assert_eq(t_rptr1, t_rptr1); - env.assert_eq(t_rptr10, t_rptr10); - env.make_subtype(t_rptr1, t_rptr10); - }) -} - -#[test] -fn contravariant_region_ptr_err() { - test_env(EMPTY_SOURCE_STR, errors(&["mismatched types"]), |mut env| { - env.create_simple_region_hierarchy(); - let t_rptr1 = env.t_rptr_scope(1); - let t_rptr10 = env.t_rptr_scope(10); - env.assert_eq(t_rptr1, t_rptr1); - env.assert_eq(t_rptr10, t_rptr10); - - // This will cause an error when regions are resolved. - env.make_subtype(t_rptr10, t_rptr1); - }) -} - -#[test] -fn sub_bound_free_true() { - //! Test that: - //! - //! for<'a> fn(&'a isize) <: fn(&'b isize) - //! - //! *does* hold. - - test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { - env.create_simple_region_hierarchy(); - let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_rptr_free1 = env.t_rptr_free(1); - env.check_sub( - env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), - env.t_fn(&[t_rptr_free1], env.tcx().types.isize), - ); - }) -} - -/// Test substituting a bound region into a function, which introduces another level of binding. -/// This requires adjusting the Debruijn index. -#[test] -fn subst_ty_renumber_bound() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - // Situation: - // Theta = [A -> &'a foo] - - let t_rptr_bound1 = env.t_rptr_late_bound(1); - - // t_source = fn(A) - let t_source = { - let t_param = env.t_param(0); - env.t_fn(&[t_param], env.t_nil()) - }; - - let substs = env.infcx.tcx.intern_substs(&[t_rptr_bound1.into()]); - let t_substituted = t_source.subst(env.infcx.tcx, substs); - - // t_expected = fn(&'a isize) - let t_expected = { - let t_ptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, d2()); - env.t_fn(&[t_ptr_bound2], env.t_nil()) - }; - - debug!( - "subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}", - t_source, substs, t_substituted, t_expected - ); - - assert_eq!(t_substituted, t_expected); - }) -} - -/// Tests substituting a bound region into a function, which introduces another level of binding. -/// This requires adjusting the De Bruijn index. -#[test] -fn subst_ty_renumber_some_bounds() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - // Situation: - // `Theta = [A -> &'a foo]` - - let t_rptr_bound1 = env.t_rptr_late_bound(1); - - // `t_source = (A, fn(A))` - let t_source = { - let t_param = env.t_param(0); - env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil())) - }; - - let substs = env.infcx.tcx.intern_substs(&[t_rptr_bound1.into()]); - let t_substituted = t_source.subst(env.infcx.tcx, substs); - - // `t_expected = (&'a isize, fn(&'a isize))` - // - // However, note that the Debruijn index is different in the different cases. - let t_expected = { - let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, d2()); - env.t_pair(t_rptr_bound1, env.t_fn(&[t_rptr_bound2], env.t_nil())) - }; - - debug!( - "subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}", - t_source, substs, t_substituted, t_expected - ); - - assert_eq!(t_substituted, t_expected); - }) -} - -/// Tests that we correctly compute whether a type has escaping regions or not. -#[test] -fn escaping() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { - // Situation: - // `Theta = [A -> &'a foo]` - env.create_simple_region_hierarchy(); - - assert!(!env.t_nil().has_escaping_bound_vars()); - - let t_rptr_free1 = env.t_rptr_free(1); - assert!(!t_rptr_free1.has_escaping_bound_vars()); - - let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, d1()); - assert!(t_rptr_bound1.has_escaping_bound_vars()); - - let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, d2()); - assert!(t_rptr_bound2.has_escaping_bound_vars()); - - // `t_fn = fn(A)` - let t_param = env.t_param(0); - assert!(!t_param.has_escaping_bound_vars()); - let t_fn = env.t_fn(&[t_param], env.t_nil()); - assert!(!t_fn.has_escaping_bound_vars()); - }) -} - -/// Tests applying a substitution where the value being substituted for an early-bound region is a -/// late-bound region. -#[test] -fn subst_region_renumber_region() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let re_bound1 = env.re_late_bound_with_debruijn(1, d1()); - - // `type t_source<'a> = fn(&'a isize)` - let t_source = { - let re_early = env.re_early_bound(0, "'a"); - env.t_fn(&[env.t_rptr(re_early)], env.t_nil()) - }; - - let substs = env.infcx.tcx.intern_substs(&[re_bound1.into()]); - let t_substituted = t_source.subst(env.infcx.tcx, substs); - - // `t_expected = fn(&'a isize)` - // - // but not that the Debruijn index is different in the different cases. - let t_expected = { - let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, d2()); - env.t_fn(&[t_rptr_bound2], env.t_nil()) - }; - - debug!( - "subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}", - t_source, substs, t_substituted, t_expected - ); - - assert_eq!(t_substituted, t_expected); - }) -} - -#[test] -fn walk_ty() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let tcx = env.infcx.tcx; - let int_ty = tcx.types.isize; - let usize_ty = tcx.types.usize; - let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty]); - let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty]); - let walked: Vec<_> = tup2_ty.walk().collect(); - assert_eq!( - walked, - [ - tup2_ty, tup1_ty, int_ty, usize_ty, int_ty, usize_ty, tup1_ty, int_ty, usize_ty, - int_ty, usize_ty, usize_ty - ] - ); - }) -} - -#[test] -fn walk_ty_skip_subtree() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let tcx = env.infcx.tcx; - let int_ty = tcx.types.isize; - let usize_ty = tcx.types.usize; - let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty]); - let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty]); - - // types we expect to see (in order), plus a boolean saying - // whether to skip the subtree. - let mut expected = vec![ - (tup2_ty, false), - (tup1_ty, false), - (int_ty, false), - (usize_ty, false), - (int_ty, false), - (usize_ty, false), - (tup1_ty, true), // skip the isize/usize/isize/usize - (usize_ty, false), - ]; - expected.reverse(); - - let mut walker = tup2_ty.walk(); - while let Some(t) = walker.next() { - debug!("walked to {:?}", t); - let (expected_ty, skip) = expected.pop().unwrap(); - assert_eq!(t, expected_ty); - if skip { - walker.skip_current_subtree(); - } - } - - assert!(expected.is_empty()); - }) -} diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index 02c011857bd2a..3689a463a5c84 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -18,3 +18,4 @@ rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } unicode-width = "0.1.4" atty = "0.2" termcolor = "1.0" +annotate-snippets = "0.5.0" diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/src/librustc_errors/annotate_snippet_emitter_writer.rs new file mode 100644 index 0000000000000..3641d355ef19c --- /dev/null +++ b/src/librustc_errors/annotate_snippet_emitter_writer.rs @@ -0,0 +1,212 @@ +//! Emit diagnostics using the `annotate-snippets` library +//! +//! This is the equivalent of `./emitter.rs` but making use of the +//! [`annotate-snippets`][annotate_snippets] library instead of building the output ourselves. +//! +//! [annotate_snippets]: https://docs.rs/crate/annotate-snippets/ + +use syntax_pos::{SourceFile, MultiSpan, Loc}; +use crate::{ + Level, CodeSuggestion, DiagnosticBuilder, Emitter, + SourceMapperDyn, SubDiagnostic, DiagnosticId +}; +use crate::emitter::FileWithAnnotatedLines; +use rustc_data_structures::sync::Lrc; +use crate::snippet::Line; +use annotate_snippets::snippet::*; +use annotate_snippets::display_list::DisplayList; +use annotate_snippets::formatter::DisplayListFormatter; + + +/// Generates diagnostics using annotate-snippet +pub struct AnnotateSnippetEmitterWriter { + source_map: Option>, + /// If true, hides the longer explanation text + short_message: bool, + /// If true, will normalize line numbers with LL to prevent noise in UI test diffs. + ui_testing: bool, +} + +impl Emitter for AnnotateSnippetEmitterWriter { + /// The entry point for the diagnostics generation + fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { + let primary_span = db.span.clone(); + let children = db.children.clone(); + // FIXME(#59346): Collect suggestions (see emitter.rs) + let suggestions: &[_] = &[]; + + // FIXME(#59346): Add `fix_multispans_in_std_macros` function from emitter.rs + + self.emit_messages_default(&db.level, + db.message(), + &db.code, + &primary_span, + &children, + &suggestions); + } + + fn should_show_explain(&self) -> bool { + !self.short_message + } +} + +/// Collects all the data needed to generate the data structures needed for the +/// `annotate-snippets` library. +struct DiagnosticConverter<'a> { + source_map: Option>, + level: Level, + message: String, + code: Option, + msp: MultiSpan, + #[allow(dead_code)] + children: &'a [SubDiagnostic], + #[allow(dead_code)] + suggestions: &'a [CodeSuggestion] +} + +impl<'a> DiagnosticConverter<'a> { + /// Turns rustc Diagnostic information into a `annotate_snippets::snippet::Snippet`. + fn to_annotation_snippet(&self) -> Option { + if let Some(source_map) = &self.source_map { + // Make sure our primary file comes first + let primary_lo = if let Some(ref primary_span) = + self.msp.primary_span().as_ref() { + source_map.lookup_char_pos(primary_span.lo()) + } else { + // FIXME(#59346): Not sure when this is the case and what + // should be done if it happens + return None + }; + let annotated_files = FileWithAnnotatedLines::collect_annotations( + &self.msp, + &self.source_map + ); + let slices = self.slices_for_files(annotated_files, primary_lo); + + Some(Snippet { + title: Some(Annotation { + label: Some(self.message.to_string()), + id: self.code.clone().map(|c| { + match c { + DiagnosticId::Error(val) | DiagnosticId::Lint(val) => val + } + }), + annotation_type: Self::annotation_type_for_level(self.level), + }), + footer: vec![], + slices, + }) + } else { + // FIXME(#59346): Is it ok to return None if there's no source_map? + None + } + } + + fn slices_for_files( + &self, + annotated_files: Vec, + primary_lo: Loc + ) -> Vec { + // FIXME(#59346): Provide a test case where `annotated_files` is > 1 + annotated_files.iter().flat_map(|annotated_file| { + annotated_file.lines.iter().map(|line| { + let line_source = Self::source_string(annotated_file.file.clone(), &line); + Slice { + source: line_source, + line_start: line.line_index, + origin: Some(primary_lo.file.name.to_string()), + // FIXME(#59346): Not really sure when `fold` should be true or false + fold: false, + annotations: line.annotations.iter().map(|a| { + self.annotation_to_source_annotation(a.clone()) + }).collect(), + } + }).collect::>() + }).collect::>() + } + + /// Turns a `crate::snippet::Annotation` into a `SourceAnnotation` + fn annotation_to_source_annotation( + &self, + annotation: crate::snippet::Annotation + ) -> SourceAnnotation { + SourceAnnotation { + range: (annotation.start_col, annotation.end_col), + label: annotation.label.unwrap_or("".to_string()), + annotation_type: Self::annotation_type_for_level(self.level) + } + } + + /// Provides the source string for the given `line` of `file` + fn source_string( + file: Lrc, + line: &Line + ) -> String { + file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or(String::new()) + } + + /// Maps `Diagnostic::Level` to `snippet::AnnotationType` + fn annotation_type_for_level(level: Level) -> AnnotationType { + match level { + Level::Bug | Level::Fatal | Level::PhaseFatal | Level::Error => AnnotationType::Error, + Level::Warning => AnnotationType::Warning, + Level::Note => AnnotationType::Note, + Level::Help => AnnotationType::Help, + // FIXME(#59346): Not sure how to map these two levels + Level::Cancelled | Level::FailureNote => AnnotationType::Error + } + } +} + +impl AnnotateSnippetEmitterWriter { + pub fn new( + source_map: Option>, + short_message: bool + ) -> Self { + Self { + source_map, + short_message, + ui_testing: false, + } + } + + /// Allows to modify `Self` to enable or disable the `ui_testing` flag. + /// + /// If this is set to true, line numbers will be normalized as `LL` in the output. + // FIXME(#59346): This method is used via the public interface, but setting the `ui_testing` + // flag currently does not anonymize line numbers. We would have to add the `maybe_anonymized` + // method from `emitter.rs` and implement rust-lang/annotate-snippets-rs#2 in order to + // anonymize line numbers. + pub fn ui_testing(mut self, ui_testing: bool) -> Self { + self.ui_testing = ui_testing; + self + } + + fn emit_messages_default( + &mut self, + level: &Level, + message: String, + code: &Option, + msp: &MultiSpan, + children: &[SubDiagnostic], + suggestions: &[CodeSuggestion] + ) { + let converter = DiagnosticConverter { + source_map: self.source_map.clone(), + level: level.clone(), + message, + code: code.clone(), + msp: msp.clone(), + children, + suggestions + }; + if let Some(snippet) = converter.to_annotation_snippet() { + let dl = DisplayList::from(snippet); + let dlf = DisplayListFormatter::new(true); + // FIXME(#59346): Figure out if we can _always_ print to stderr or not. + // `emitter.rs` has the `Destination` enum that lists various possible output + // destinations. + eprintln!("{}", dlf.format(&dl)); + }; + } +} diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 851b19e8177b5..424d7c0038389 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -366,7 +366,7 @@ impl Diagnostic { }], }], msg: msg.to_owned(), - style: SuggestionStyle::HideCodeInline, + style: SuggestionStyle::HideCodeAlways, applicability, }); self @@ -388,7 +388,7 @@ impl Diagnostic { }], msg: msg.to_owned(), style: SuggestionStyle::CompletelyHidden, - applicability: applicability, + applicability, }); self } diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 0c808a07f9bac..fc74e43ff5739 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -100,10 +100,24 @@ impl<'a> DiagnosticBuilder<'a> { self.cancel(); } + /// Emit the diagnostic unless `delay` is true, + /// in which case the emission will be delayed as a bug. + /// + /// See `emit` and `delay_as_bug` for details. + pub fn emit_unless(&mut self, delay: bool) { + if delay { + self.delay_as_bug() + } else { + self.emit() + } + } + /// Buffers the diagnostic for later emission, unless handler /// has disabled such buffering. pub fn buffer(mut self, buffered_diagnostics: &mut Vec) { - if self.handler.flags.dont_buffer_diagnostics || self.handler.flags.treat_err_as_bug { + if self.handler.flags.dont_buffer_diagnostics || + self.handler.flags.treat_err_as_bug.is_some() + { self.emit(); return; } @@ -182,7 +196,7 @@ impl<'a> DiagnosticBuilder<'a> { ) -> &mut Self); forward!(pub fn warn(&mut self, msg: &str) -> &mut Self); forward!(pub fn span_warn>(&mut self, sp: S, msg: &str) -> &mut Self); - forward!(pub fn help(&mut self , msg: &str) -> &mut Self); + forward!(pub fn help(&mut self, msg: &str) -> &mut Self); forward!(pub fn span_help>(&mut self, sp: S, msg: &str, @@ -334,7 +348,7 @@ impl<'a> DiagnosticBuilder<'a> { /// Convenience function for internal use, clients should use one of the /// struct_* methods on Handler. - pub fn new_with_code(handler: &'a Handler, + crate fn new_with_code(handler: &'a Handler, level: Level, code: Option, message: &str) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index e9f269b6e2410..a2717ab7ad8a9 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -1,3 +1,12 @@ +//! The current rustc diagnostics emitter. +//! +//! An `Emitter` takes care of generating the output from a `DiagnosticBuilder` struct. +//! +//! There are various `Emitter` implementations that generate different output formats such as +//! JSON and human readable output. +//! +//! The output types are defined in `librustc::session::config::ErrorOutputType`. + use Destination::*; use syntax_pos::{SourceFile, Span, MultiSpan}; @@ -6,6 +15,7 @@ use crate::{ Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, SuggestionStyle, SourceMapperDyn, DiagnosticId, }; +use crate::Level::Error; use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style}; use crate::styled_buffer::StyledBuffer; @@ -15,15 +25,49 @@ use std::borrow::Cow; use std::io::prelude::*; use std::io; use std::cmp::{min, Reverse}; -use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter}; +use std::path::Path; +use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi}; use termcolor::{WriteColor, Color, Buffer}; +/// Describes the way the content of the `rendered` field of the json output is generated +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum HumanReadableErrorType { + Default(ColorConfig), + AnnotateSnippet(ColorConfig), + Short(ColorConfig), +} + +impl HumanReadableErrorType { + /// Returns a (`short`, `color`) tuple + pub fn unzip(self) -> (bool, ColorConfig) { + match self { + HumanReadableErrorType::Default(cc) => (false, cc), + HumanReadableErrorType::Short(cc) => (true, cc), + HumanReadableErrorType::AnnotateSnippet(cc) => (false, cc), + } + } + pub fn new_emitter( + self, + dst: Box, + source_map: Option>, + teach: bool, + ) -> EmitterWriter { + let (short, color_config) = self.unzip(); + EmitterWriter::new(dst, source_map, short, teach, color_config.suggests_using_colors()) + } +} + const ANONYMIZED_LINE_NUM: &str = "LL"; /// Emitter trait for emitting errors. pub trait Emitter { /// Emit a structured diagnostic. - fn emit(&mut self, db: &DiagnosticBuilder<'_>); + fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>); + + /// Emit a notification that an artifact has been output. + /// This is currently only supported for the JSON format, + /// other formats can, and will, simply ignore it. + fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {} /// Checks if should show explanations about "rustc --explain" fn should_show_explain(&self) -> bool { @@ -32,7 +76,7 @@ pub trait Emitter { } impl Emitter for EmitterWriter { - fn emit(&mut self, db: &DiagnosticBuilder<'_>) { + fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { let mut primary_span = db.span.clone(); let mut children = db.children.clone(); let mut suggestions: &[_] = &[]; @@ -72,6 +116,7 @@ impl Emitter for EmitterWriter { self.fix_multispans_in_std_macros(&mut primary_span, &mut children, + &db.level, db.handler.flags.external_macro_backtrace); self.emit_messages_default(&db.level, @@ -102,8 +147,8 @@ pub enum ColorConfig { } impl ColorConfig { - fn to_color_choice(&self) -> ColorChoice { - match *self { + fn to_color_choice(self) -> ColorChoice { + match self { ColorConfig::Always => { if atty::is(atty::Stream::Stderr) { ColorChoice::Always @@ -118,8 +163,17 @@ impl ColorConfig { ColorConfig::Auto => ColorChoice::Never, } } + fn suggests_using_colors(self) -> bool { + match self { + | ColorConfig::Always + | ColorConfig::Auto + => true, + ColorConfig::Never => false, + } + } } +/// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short` pub struct EmitterWriter { dst: Destination, sm: Option>, @@ -128,9 +182,10 @@ pub struct EmitterWriter { ui_testing: bool, } -struct FileWithAnnotatedLines { - file: Lrc, - lines: Vec, +#[derive(Debug)] +pub struct FileWithAnnotatedLines { + pub file: Lrc, + pub lines: Vec, multiline_depth: usize, } @@ -150,13 +205,15 @@ impl EmitterWriter { } } - pub fn new(dst: Box, - source_map: Option>, - short_message: bool, - teach: bool) - -> EmitterWriter { + pub fn new( + dst: Box, + source_map: Option>, + short_message: bool, + teach: bool, + colored: bool, + ) -> EmitterWriter { EmitterWriter { - dst: Raw(dst), + dst: Raw(dst, colored), sm: source_map, short_message, teach, @@ -177,136 +234,6 @@ impl EmitterWriter { } } - fn preprocess_annotations(&mut self, msp: &MultiSpan) -> Vec { - fn add_annotation_to_file(file_vec: &mut Vec, - file: Lrc, - line_index: usize, - ann: Annotation) { - - for slot in file_vec.iter_mut() { - // Look through each of our files for the one we're adding to - if slot.file.name == file.name { - // See if we already have a line for it - for line_slot in &mut slot.lines { - if line_slot.line_index == line_index { - line_slot.annotations.push(ann); - return; - } - } - // We don't have a line yet, create one - slot.lines.push(Line { - line_index, - annotations: vec![ann], - }); - slot.lines.sort(); - return; - } - } - // This is the first time we're seeing the file - file_vec.push(FileWithAnnotatedLines { - file, - lines: vec![Line { - line_index, - annotations: vec![ann], - }], - multiline_depth: 0, - }); - } - - let mut output = vec![]; - let mut multiline_annotations = vec![]; - - if let Some(ref sm) = self.sm { - for span_label in msp.span_labels() { - if span_label.span.is_dummy() { - continue; - } - - let lo = sm.lookup_char_pos(span_label.span.lo()); - let mut hi = sm.lookup_char_pos(span_label.span.hi()); - - // Watch out for "empty spans". If we get a span like 6..6, we - // want to just display a `^` at 6, so convert that to - // 6..7. This is degenerate input, but it's best to degrade - // gracefully -- and the parser likes to supply a span like - // that for EOF, in particular. - if lo.col_display == hi.col_display && lo.line == hi.line { - hi.col_display += 1; - } - - let ann_type = if lo.line != hi.line { - let ml = MultilineAnnotation { - depth: 1, - line_start: lo.line, - line_end: hi.line, - start_col: lo.col_display, - end_col: hi.col_display, - is_primary: span_label.is_primary, - label: span_label.label.clone(), - }; - multiline_annotations.push((lo.file.clone(), ml.clone())); - AnnotationType::Multiline(ml) - } else { - AnnotationType::Singleline - }; - let ann = Annotation { - start_col: lo.col_display, - end_col: hi.col_display, - is_primary: span_label.is_primary, - label: span_label.label.clone(), - annotation_type: ann_type, - }; - - if !ann.is_multiline() { - add_annotation_to_file(&mut output, - lo.file, - lo.line, - ann); - } - } - } - - // Find overlapping multiline annotations, put them at different depths - multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, ml.line_end)); - for item in multiline_annotations.clone() { - let ann = item.1; - for item in multiline_annotations.iter_mut() { - let ref mut a = item.1; - // Move all other multiline annotations overlapping with this one - // one level to the right. - if &ann != a && - num_overlap(ann.line_start, ann.line_end, a.line_start, a.line_end, true) - { - a.increase_depth(); - } else { - break; - } - } - } - - let mut max_depth = 0; // max overlapping multiline spans - for (file, ann) in multiline_annotations { - if ann.depth > max_depth { - max_depth = ann.depth; - } - add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start()); - let middle = min(ann.line_start + 4, ann.line_end); - for line in ann.line_start + 1..middle { - add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); - } - if middle < ann.line_end - 1 { - for line in ann.line_end - 1..ann.line_end { - add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); - } - } - add_annotation_to_file(&mut output, file, ann.line_end, ann.as_end()); - } - for file_vec in output.iter_mut() { - file_vec.multiline_depth = max_depth; - } - output - } - fn render_source_line(&self, buffer: &mut StyledBuffer, file: Lrc, @@ -477,6 +404,15 @@ impl EmitterWriter { && j > i // multiline lines). && p == 0 // We're currently on the first line, move the label one line down { + // If we're overlapping with an un-labelled annotation with the same span + // we can just merge them in the output + if next.start_col == annotation.start_col + && next.end_col == annotation.end_col + && !next.has_label() + { + continue; + } + // This annotation needs a new line in the output. p += 1; break; @@ -856,18 +792,27 @@ impl EmitterWriter { fn fix_multispans_in_std_macros(&mut self, span: &mut MultiSpan, children: &mut Vec, + level: &Level, backtrace: bool) { let mut spans_updated = self.fix_multispan_in_std_macros(span, backtrace); for child in children.iter_mut() { spans_updated |= self.fix_multispan_in_std_macros(&mut child.span, backtrace); } + let msg = if level == &Error { + "this error originates in a macro outside of the current crate \ + (in Nightly builds, run with -Z external-macro-backtrace \ + for more info)".to_string() + } else { + "this warning originates in a macro outside of the current crate \ + (in Nightly builds, run with -Z external-macro-backtrace \ + for more info)".to_string() + }; + if spans_updated { children.push(SubDiagnostic { level: Level::Note, message: vec![ - ("this error originates in a macro outside of the current crate \ - (in Nightly builds, run with -Z external-macro-backtrace \ - for more info)".to_string(), + (msg, Style::NoStyle), ], span: MultiSpan::new(), @@ -998,9 +943,7 @@ impl EmitterWriter { } } - // Preprocess all the annotations so that they are grouped by file and by line number - // This helps us quickly iterate over the whole message (including secondary file spans) - let mut annotated_files = self.preprocess_annotations(msp); + let mut annotated_files = FileWithAnnotatedLines::collect_annotations(msp, &self.sm); // Make sure our primary file comes first let (primary_lo, sm) = if let (Some(sm), Some(ref primary_span)) = @@ -1396,7 +1339,7 @@ impl EmitterWriter { } let mut dst = self.dst.writable(); - match write!(dst, "\n") { + match writeln!(dst) { Err(e) => panic!("failed to emit error: {}", e), _ => { match dst.flush() { @@ -1408,6 +1351,176 @@ impl EmitterWriter { } } +impl FileWithAnnotatedLines { + /// Preprocess all the annotations so that they are grouped by file and by line number + /// This helps us quickly iterate over the whole message (including secondary file spans) + pub fn collect_annotations( + msp: &MultiSpan, + source_map: &Option> + ) -> Vec { + fn add_annotation_to_file(file_vec: &mut Vec, + file: Lrc, + line_index: usize, + ann: Annotation) { + + for slot in file_vec.iter_mut() { + // Look through each of our files for the one we're adding to + if slot.file.name == file.name { + // See if we already have a line for it + for line_slot in &mut slot.lines { + if line_slot.line_index == line_index { + line_slot.annotations.push(ann); + return; + } + } + // We don't have a line yet, create one + slot.lines.push(Line { + line_index, + annotations: vec![ann], + }); + slot.lines.sort(); + return; + } + } + // This is the first time we're seeing the file + file_vec.push(FileWithAnnotatedLines { + file, + lines: vec![Line { + line_index, + annotations: vec![ann], + }], + multiline_depth: 0, + }); + } + + let mut output = vec![]; + let mut multiline_annotations = vec![]; + + if let Some(ref sm) = source_map { + for span_label in msp.span_labels() { + if span_label.span.is_dummy() { + continue; + } + + let lo = sm.lookup_char_pos(span_label.span.lo()); + let mut hi = sm.lookup_char_pos(span_label.span.hi()); + + // Watch out for "empty spans". If we get a span like 6..6, we + // want to just display a `^` at 6, so convert that to + // 6..7. This is degenerate input, but it's best to degrade + // gracefully -- and the parser likes to supply a span like + // that for EOF, in particular. + + if lo.col_display == hi.col_display && lo.line == hi.line { + hi.col_display += 1; + } + + let ann_type = if lo.line != hi.line { + let ml = MultilineAnnotation { + depth: 1, + line_start: lo.line, + line_end: hi.line, + start_col: lo.col_display, + end_col: hi.col_display, + is_primary: span_label.is_primary, + label: span_label.label.clone(), + overlaps_exactly: false, + }; + multiline_annotations.push((lo.file.clone(), ml.clone())); + AnnotationType::Multiline(ml) + } else { + AnnotationType::Singleline + }; + let ann = Annotation { + start_col: lo.col_display, + end_col: hi.col_display, + is_primary: span_label.is_primary, + label: span_label.label.clone(), + annotation_type: ann_type, + }; + + if !ann.is_multiline() { + add_annotation_to_file(&mut output, lo.file, lo.line, ann); + } + } + } + + // Find overlapping multiline annotations, put them at different depths + multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, ml.line_end)); + for item in multiline_annotations.clone() { + let ann = item.1; + for item in multiline_annotations.iter_mut() { + let ref mut a = item.1; + // Move all other multiline annotations overlapping with this one + // one level to the right. + if !(ann.same_span(a)) && + num_overlap(ann.line_start, ann.line_end, a.line_start, a.line_end, true) + { + a.increase_depth(); + } else if ann.same_span(a) && &ann != a { + a.overlaps_exactly = true; + } else { + break; + } + } + } + + let mut max_depth = 0; // max overlapping multiline spans + for (file, ann) in multiline_annotations { + if ann.depth > max_depth { + max_depth = ann.depth; + } + let mut end_ann = ann.as_end(); + if !ann.overlaps_exactly { + // avoid output like + // + // | foo( + // | _____^ + // | |_____| + // | || bar, + // | || ); + // | || ^ + // | ||______| + // | |______foo + // | baz + // + // and instead get + // + // | foo( + // | _____^ + // | | bar, + // | | ); + // | | ^ + // | | | + // | |______foo + // | baz + add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start()); + // 4 is the minimum vertical length of a multiline span when presented: two lines + // of code and two lines of underline. This is not true for the special case where + // the beginning doesn't have an underline, but the current logic seems to be + // working correctly. + let middle = min(ann.line_start + 4, ann.line_end); + for line in ann.line_start + 1..middle { + // Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`). + add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); + } + if middle < ann.line_end - 1 { + for line in ann.line_end - 1..ann.line_end { + add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); + } + } + } else { + end_ann.annotation_type = AnnotationType::Singleline; + } + add_annotation_to_file(&mut output, file, ann.line_end, end_ann); + } + for file_vec in output.iter_mut() { + file_vec.multiline_depth = max_depth; + } + output + } +} + fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { buffer.puts(line, col, "| ", Style::LineNumber); } @@ -1485,7 +1598,7 @@ fn emit_to_destination(rendered_buffer: &[Vec], dst.reset()?; } if !short_message && (!lvl.is_failure_note() || pos != rendered_buffer.len() - 1) { - write!(dst, "\n")?; + writeln!(dst)?; } } dst.flush()?; @@ -1495,13 +1608,15 @@ fn emit_to_destination(rendered_buffer: &[Vec], pub enum Destination { Terminal(StandardStream), Buffered(BufferWriter), - Raw(Box), + // The bool denotes whether we should be emitting ansi color codes or not + Raw(Box<(dyn Write + Send)>, bool), } pub enum WritableDst<'a> { Terminal(&'a mut StandardStream), Buffered(&'a mut BufferWriter, Buffer), - Raw(&'a mut Box), + Raw(&'a mut (dyn Write + Send)), + ColoredRaw(Ansi<&'a mut (dyn Write + Send)>), } impl Destination { @@ -1527,7 +1642,8 @@ impl Destination { let buf = t.buffer(); WritableDst::Buffered(t, buf) } - Destination::Raw(ref mut t) => WritableDst::Raw(t), + Destination::Raw(ref mut t, false) => WritableDst::Raw(t), + Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)), } } } @@ -1547,7 +1663,7 @@ impl<'a> WritableDst<'a> { } } Style::Quotation => {} - Style::OldSchoolNoteText | Style::MainHeaderMsg => { + Style::MainHeaderMsg => { spec.set_bold(true); if cfg!(windows) { spec.set_intense(true) @@ -1585,6 +1701,7 @@ impl<'a> WritableDst<'a> { match *self { WritableDst::Terminal(ref mut t) => t.set_color(color), WritableDst::Buffered(_, ref mut t) => t.set_color(color), + WritableDst::ColoredRaw(ref mut t) => t.set_color(color), WritableDst::Raw(_) => Ok(()) } } @@ -1593,6 +1710,7 @@ impl<'a> WritableDst<'a> { match *self { WritableDst::Terminal(ref mut t) => t.reset(), WritableDst::Buffered(_, ref mut t) => t.reset(), + WritableDst::ColoredRaw(ref mut t) => t.reset(), WritableDst::Raw(_) => Ok(()), } } @@ -1604,6 +1722,7 @@ impl<'a> Write for WritableDst<'a> { WritableDst::Terminal(ref mut t) => t.write(bytes), WritableDst::Buffered(_, ref mut buf) => buf.write(bytes), WritableDst::Raw(ref mut w) => w.write(bytes), + WritableDst::ColoredRaw(ref mut t) => t.write(bytes), } } @@ -1612,6 +1731,7 @@ impl<'a> Write for WritableDst<'a> { WritableDst::Terminal(ref mut t) => t.flush(), WritableDst::Buffered(_, ref mut buf) => buf.flush(), WritableDst::Raw(ref mut w) => w.flush(), + WritableDst::ColoredRaw(ref mut w) => w.flush(), } } } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 87b4751526835..70bd25a9d5772 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -1,12 +1,17 @@ +//! Diagnostics creation and emission for `rustc`. +//! +//! This module contains the code for creating and emitting diagnostics. + #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(custom_attribute)] +#![feature(crate_visibility_modifier)] #![allow(unused_attributes)] -#![feature(range_contains)] #![cfg_attr(unix, feature(libc))] #![feature(nll)] #![feature(optin_builtin_traits)] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] #[allow(unused_extern_crates)] extern crate serialize as rustc_serialize; // used by deriving @@ -16,6 +21,7 @@ pub use emitter::ColorConfig; use Level::*; use emitter::{Emitter, EmitterWriter}; +use registry::Registry; use rustc_data_structures::sync::{self, Lrc, Lock, AtomicUsize, AtomicBool, SeqCst}; use rustc_data_structures::fx::FxHashSet; @@ -25,12 +31,14 @@ use std::borrow::Cow; use std::cell::Cell; use std::{error, fmt}; use std::panic; +use std::path::Path; use termcolor::{ColorSpec, Color}; mod diagnostic; mod diagnostic_builder; pub mod emitter; +pub mod annotate_snippet_emitter_writer; mod snippet; pub mod registry; mod styled_buffer; @@ -156,7 +164,7 @@ impl CodeSuggestion { /// Returns the assembled code suggestions and whether they should be shown with an underline. pub fn splice_lines(&self, cm: &SourceMapperDyn) -> Vec<(String, Vec)> { - use syntax_pos::{CharPos, Loc, Pos}; + use syntax_pos::{CharPos, Pos}; fn push_trailing(buf: &mut String, line_opt: Option<&Cow<'_, str>>, @@ -293,28 +301,33 @@ impl error::Error for ExplicitBug { pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString, DiagnosticId}; pub use diagnostic_builder::DiagnosticBuilder; -/// A handler deals with errors; certain errors -/// (fatal, bug, unimpl) may cause immediate exit, +/// A handler deals with errors and other compiler output. +/// Certain errors (fatal, bug, unimpl) may cause immediate exit, /// others log errors for later reporting. pub struct Handler { pub flags: HandlerFlags, + /// The number of errors that have been emitted, including duplicates. + /// + /// This is not necessarily the count that's reported to the user once + /// compilation ends. err_count: AtomicUsize, + deduplicated_err_count: AtomicUsize, emitter: Lock>, continue_after_error: AtomicBool, delayed_span_bugs: Lock>, - // This set contains the `DiagnosticId` of all emitted diagnostics to avoid - // emitting the same diagnostic with extended help (`--teach`) twice, which - // would be uneccessary repetition. + /// This set contains the `DiagnosticId` of all emitted diagnostics to avoid + /// emitting the same diagnostic with extended help (`--teach`) twice, which + /// would be uneccessary repetition. taught_diagnostics: Lock>, /// Used to suggest rustc --explain emitted_diagnostic_codes: Lock>, - // This set contains a hash of every diagnostic that has been emitted by - // this handler. These hashes is used to avoid emitting the same error - // twice. + /// This set contains a hash of every diagnostic that has been emitted by + /// this handler. These hashes is used to avoid emitting the same error + /// twice. emitted_diagnostics: Lock>, } @@ -330,7 +343,7 @@ pub struct HandlerFlags { pub can_emit_warnings: bool, /// If true, error-level diagnostics are upgraded to bug-level. /// (rustc: see `-Z treat-err-as-bug`) - pub treat_err_as_bug: bool, + pub treat_err_as_bug: Option, /// If true, immediately emit diagnostics that would otherwise be buffered. /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`) pub dont_buffer_diagnostics: bool, @@ -344,7 +357,7 @@ pub struct HandlerFlags { impl Drop for Handler { fn drop(&mut self) { - if self.err_count() == 0 { + if !self.has_errors() { let mut bugs = self.delayed_span_bugs.borrow_mut(); let has_bugs = !bugs.is_empty(); for bug in bugs.drain(..) { @@ -360,7 +373,7 @@ impl Drop for Handler { impl Handler { pub fn with_tty_emitter(color_config: ColorConfig, can_emit_warnings: bool, - treat_err_as_bug: bool, + treat_err_as_bug: Option, cm: Option>) -> Handler { Handler::with_tty_emitter_and_flags( @@ -382,7 +395,7 @@ impl Handler { } pub fn with_emitter(can_emit_warnings: bool, - treat_err_as_bug: bool, + treat_err_as_bug: Option, e: Box) -> Handler { Handler::with_emitter_and_flags( @@ -399,6 +412,7 @@ impl Handler { Handler { flags, err_count: AtomicUsize::new(0), + deduplicated_err_count: AtomicUsize::new(0), emitter: Lock::new(e), continue_after_error: AtomicBool::new(true), delayed_span_bugs: Lock::new(Vec::new()), @@ -420,6 +434,7 @@ impl Handler { pub fn reset_err_count(&self) { // actually frees the underlying memory (which `clear` would not do) *self.emitted_diagnostics.borrow_mut() = Default::default(); + self.deduplicated_err_count.store(0, SeqCst); self.err_count.store(0, SeqCst); } @@ -516,8 +531,20 @@ impl Handler { } fn panic_if_treat_err_as_bug(&self) { - if self.flags.treat_err_as_bug { - panic!("encountered error with `-Z treat_err_as_bug"); + if self.treat_err_as_bug() { + let s = match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) { + (0, _) => return, + (1, 1) => "aborting due to `-Z treat-err-as-bug=1`".to_string(), + (1, _) => return, + (count, as_bug) => { + format!( + "aborting after {} errors due to `-Z treat-err-as-bug={}`", + count, + as_bug, + ) + } + }; + panic!(s); } } @@ -558,7 +585,7 @@ impl Handler { panic!(ExplicitBug); } pub fn delay_span_bug>(&self, sp: S, msg: &str) { - if self.flags.treat_err_as_bug { + if self.treat_err_as_bug() { // FIXME: don't abort here if report_delayed_bugs is off self.span_bug(sp, msg); } @@ -593,14 +620,14 @@ impl Handler { DiagnosticBuilder::new(self, FailureNote, msg).emit() } pub fn fatal(&self, msg: &str) -> FatalError { - if self.flags.treat_err_as_bug { + if self.treat_err_as_bug() { self.bug(msg); } DiagnosticBuilder::new(self, Fatal, msg).emit(); FatalError } pub fn err(&self, msg: &str) { - if self.flags.treat_err_as_bug { + if self.treat_err_as_bug() { self.bug(msg); } let mut db = DiagnosticBuilder::new(self, Error, msg); @@ -610,6 +637,9 @@ impl Handler { let mut db = DiagnosticBuilder::new(self, Warning, msg); db.emit(); } + fn treat_err_as_bug(&self) -> bool { + self.flags.treat_err_as_bug.map(|c| self.err_count() >= c).unwrap_or(false) + } pub fn note_without_error(&self, msg: &str) { let mut db = DiagnosticBuilder::new(self, Note, msg); db.emit(); @@ -624,8 +654,8 @@ impl Handler { } fn bump_err_count(&self) { - self.panic_if_treat_err_as_bug(); self.err_count.fetch_add(1, SeqCst); + self.panic_if_treat_err_as_bug(); } pub fn err_count(&self) -> usize { @@ -636,31 +666,37 @@ impl Handler { self.err_count() > 0 } - pub fn print_error_count(&self) { - let s = match self.err_count() { + pub fn print_error_count(&self, registry: &Registry) { + let s = match self.deduplicated_err_count.load(SeqCst) { 0 => return, 1 => "aborting due to previous error".to_string(), - _ => format!("aborting due to {} previous errors", self.err_count()) + count => format!("aborting due to {} previous errors", count) }; + if self.treat_err_as_bug() { + return; + } let _ = self.fatal(&s); let can_show_explain = self.emitter.borrow().should_show_explain(); let are_there_diagnostics = !self.emitted_diagnostic_codes.borrow().is_empty(); if can_show_explain && are_there_diagnostics { - let mut error_codes = - self.emitted_diagnostic_codes.borrow() - .iter() - .filter_map(|x| match *x { - DiagnosticId::Error(ref s) => Some(s.clone()), - _ => None, - }) - .collect::>(); + let mut error_codes = self + .emitted_diagnostic_codes + .borrow() + .iter() + .filter_map(|x| match &x { + DiagnosticId::Error(s) if registry.find_description(s).is_some() => { + Some(s.clone()) + } + _ => None, + }) + .collect::>(); if !error_codes.is_empty() { error_codes.sort(); if error_codes.len() > 1 { let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() }; - self.failure(&format!("Some errors occurred: {}{}", + self.failure(&format!("Some errors have detailed explanations: {}{}", error_codes[..limit].join(", "), if error_codes.len() > 9 { "..." } else { "." })); self.failure(&format!("For more information about an error, try \ @@ -676,10 +712,9 @@ impl Handler { } pub fn abort_if_errors(&self) { - if self.err_count() == 0 { - return; + if self.has_errors() { + FatalError.raise(); } - FatalError.raise(); } pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) { if lvl == Warning && !self.flags.can_emit_warnings { @@ -714,7 +749,7 @@ impl Handler { } pub fn force_print_db(&self, mut db: DiagnosticBuilder<'_>) { - self.emitter.borrow_mut().emit(&db); + self.emitter.borrow_mut().emit_diagnostic(&db); db.cancel(); } @@ -739,14 +774,20 @@ impl Handler { // Only emit the diagnostic if we haven't already emitted an equivalent // one: if self.emitted_diagnostics.borrow_mut().insert(diagnostic_hash) { - self.emitter.borrow_mut().emit(db); + self.emitter.borrow_mut().emit_diagnostic(db); if db.is_error() { - self.bump_err_count(); + self.deduplicated_err_count.fetch_add(1, SeqCst); } } + if db.is_error() { + self.bump_err_count(); + } } -} + pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) { + self.emitter.borrow_mut().emit_artifact_notification(path, artifact_type); + } +} #[derive(Copy, PartialEq, Clone, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum Level { diff --git a/src/librustc_errors/lock.rs b/src/librustc_errors/lock.rs index f731791efe6e1..25a27d2cbd884 100644 --- a/src/librustc_errors/lock.rs +++ b/src/librustc_errors/lock.rs @@ -64,7 +64,7 @@ pub fn acquire_global_lock(name: &str) -> Box { // // This will silently create one if it doesn't already exist, or it'll // open up a handle to one if it already exists. - let mutex = CreateMutexA(0 as *mut _, 0, cname.as_ptr() as *const u8); + let mutex = CreateMutexA(std::ptr::null_mut(), 0, cname.as_ptr() as *const u8); if mutex.is_null() { panic!("failed to create global mutex named `{}`: {}", name, diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index 0c62ff0ff89b2..47ba22d3d25af 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -18,6 +18,7 @@ pub struct MultilineAnnotation { pub end_col: usize, pub is_primary: bool, pub label: Option, + pub overlaps_exactly: bool, } impl MultilineAnnotation { @@ -25,6 +26,12 @@ impl MultilineAnnotation { self.depth += 1; } + /// Compare two `MultilineAnnotation`s considering only the `Span` they cover. + pub fn same_span(&self, other: &MultilineAnnotation) -> bool { + self.line_start == other.line_start && self.line_end == other.line_end + && self.start_col == other.start_col && self.end_col == other.end_col + } + pub fn as_start(&self) -> Annotation { Annotation { start_col: self.start_col, @@ -181,7 +188,6 @@ pub enum Style { UnderlineSecondary, LabelPrimary, LabelSecondary, - OldSchoolNoteText, NoStyle, Level(Level), Highlight, diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml index 10b448b7fec3f..df971ec5bdb85 100644 --- a/src/librustc_incremental/Cargo.toml +++ b/src/librustc_incremental/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["dylib"] [dependencies] graphviz = { path = "../libgraphviz" } log = "0.4" -rand = "0.5" +rand = "0.6" rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } serialize = { path = "../libserialize" } diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 1f69d617c83b7..a43347a2197c3 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -51,7 +51,7 @@ use std::io::Write; use syntax::ast; use syntax_pos::Span; -pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn assert_dep_graph<'tcx>(tcx: TyCtxt<'tcx>) { tcx.dep_graph.with_ignore(|| { if tcx.sess.opts.debugging_opts.dump_dep_graph { dump_graph(tcx); @@ -89,22 +89,22 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { type Sources = Vec<(Span, DefId, DepNode)>; type Targets = Vec<(Span, ast::Name, hir::HirId, DepNode)>; -struct IfThisChanged<'a, 'tcx:'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct IfThisChanged<'tcx> { + tcx: TyCtxt<'tcx>, if_this_changed: Sources, then_this_would_need: Targets, } -impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { +impl IfThisChanged<'tcx> { fn argument(&self, attr: &ast::Attribute) -> Option { let mut value = None; for list_item in attr.meta_item_list().unwrap_or_default() { - match list_item.word() { - Some(word) if value.is_none() => - value = Some(word.name()), + match list_item.ident() { + Some(ident) if list_item.is_word() && value.is_none() => + value = Some(ident.name), _ => // FIXME better-encapsulate meta_item (don't directly access `node`) - span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node), + span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item), } } value @@ -158,7 +158,7 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for IfThisChanged<'a, 'tcx> { +impl Visitor<'tcx> for IfThisChanged<'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::OnlyBodies(&self.tcx.hir()) } @@ -184,10 +184,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IfThisChanged<'a, 'tcx> { } } -fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - if_this_changed: &Sources, - then_this_would_need: &Targets) -{ +fn check_paths<'tcx>(tcx: TyCtxt<'tcx>, if_this_changed: &Sources, then_this_would_need: &Targets) { // Return early here so as not to construct the query, which is not cheap. if if_this_changed.is_empty() { for &(target_span, _, _, _) in then_this_would_need { @@ -206,7 +203,7 @@ fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.sess.span_err( target_span, &format!("no path from `{}` to `{}`", - tcx.item_path_str(source_def_id), + tcx.def_path_str(source_def_id), target_pass)); } else { tcx.sess.span_err( @@ -217,7 +214,7 @@ fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn dump_graph(tcx: TyCtxt<'_, '_, '_>) { +fn dump_graph(tcx: TyCtxt<'_>) { let path: String = env::var("RUST_DEP_GRAPH").unwrap_or_else(|_| "dep_graph".to_string()); let query = tcx.dep_graph.query(); @@ -258,7 +255,7 @@ fn dump_graph(tcx: TyCtxt<'_, '_, '_>) { pub struct GraphvizDepGraph<'q>(FxHashSet<&'q DepNode>, Vec<(&'q DepNode, &'q DepNode)>); -impl<'a, 'tcx, 'q> dot::GraphWalk<'a> for GraphvizDepGraph<'q> { +impl<'a, 'q> dot::GraphWalk<'a> for GraphvizDepGraph<'q> { type Node = &'q DepNode; type Edge = (&'q DepNode, &'q DepNode); fn nodes(&self) -> dot::Nodes<'_, &'q DepNode> { @@ -276,7 +273,7 @@ impl<'a, 'tcx, 'q> dot::GraphWalk<'a> for GraphvizDepGraph<'q> { } } -impl<'a, 'tcx, 'q> dot::Labeller<'a> for GraphvizDepGraph<'q> { +impl<'a, 'q> dot::Labeller<'a> for GraphvizDepGraph<'q> { type Node = &'q DepNode; type Edge = (&'q DepNode, &'q DepNode); fn graph_id(&self) -> dot::Id<'_> { diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index 5cbb412052dda..f502d0475460e 100644 --- a/src/librustc_incremental/assert_module_sources.rs +++ b/src/librustc_incremental/assert_module_sources.rs @@ -27,14 +27,15 @@ use rustc::mir::mono::CodegenUnitNameBuilder; use rustc::ty::TyCtxt; use std::collections::BTreeSet; use syntax::ast; +use syntax::symbol::{Symbol, sym}; use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_CODEGENED, ATTR_EXPECTED_CGU_REUSE}; -const MODULE: &str = "module"; -const CFG: &str = "cfg"; -const KIND: &str = "kind"; +const MODULE: Symbol = sym::module; +const CFG: Symbol = sym::cfg; +const KIND: Symbol = sym::kind; -pub fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn assert_module_sources<'tcx>(tcx: TyCtxt<'tcx>) { tcx.dep_graph.with_ignore(|| { if tcx.sess.opts.incremental.is_none() { return; @@ -58,12 +59,12 @@ pub fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { }) } -struct AssertModuleSource<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct AssertModuleSource<'tcx> { + tcx: TyCtxt<'tcx>, available_cgus: BTreeSet, } -impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { +impl AssertModuleSource<'tcx> { fn check_attr(&self, attr: &ast::Attribute) { let (expected_reuse, comp_kind) = if attr.check_name(ATTR_PARTITION_REUSED) { (CguReuse::PreLto, ComparisonKind::AtLeast) @@ -146,14 +147,14 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { comp_kind); } - fn field(&self, attr: &ast::Attribute, name: &str) -> ast::Name { + fn field(&self, attr: &ast::Attribute, name: Symbol) -> ast::Name { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(name) { if let Some(value) = item.value_str() { return value; } else { self.tcx.sess.span_fatal( - item.span, + item.span(), &format!("associated value expected for `{}`", name)); } } diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 346ddaa485804..ffea495d3ebdb 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -2,12 +2,15 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(in_band_lifetimes)] #![feature(nll)] #![feature(specialization)] #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] #[macro_use] extern crate rustc; #[allow(unused_extern_crates)] @@ -21,7 +24,7 @@ mod persist; pub use assert_dep_graph::assert_dep_graph; pub use persist::dep_graph_tcx_init; -pub use persist::load_dep_graph; +pub use persist::{DepGraphFuture, load_dep_graph}; pub use persist::load_query_result_cache; pub use persist::LoadResult; pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir; diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 2794b6c556ff2..5296ed0ffd0b8 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -3,9 +3,9 @@ //! we will compare the fingerprint from the current and from the previous //! compilation session as appropriate: //! -//! - `#[rustc_clean(cfg="rev2", except="TypeckTables")]` if we are +//! - `#[rustc_clean(cfg="rev2", except="typeck_tables_of")]` if we are //! in `#[cfg(rev2)]`, then the fingerprints associated with -//! `DepNode::TypeckTables(X)` must be DIFFERENT (`X` is the `DefId` of the +//! `DepNode::typeck_tables_of(X)` must be DIFFERENT (`X` is the `DefId` of the //! current node). //! - `#[rustc_clean(cfg="rev2")]` same as above, except that the //! fingerprints must be the SAME (along with all other fingerprints). @@ -23,33 +23,34 @@ use rustc::hir::def_id::DefId; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::intravisit; use rustc::ich::{ATTR_DIRTY, ATTR_CLEAN}; -use syntax::ast::{self, Attribute, NestedMetaItem}; +use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashSet; +use syntax::ast::{self, Attribute, NestedMetaItem}; +use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; -use rustc::ty::TyCtxt; -const EXCEPT: &str = "except"; -const LABEL: &str = "label"; -const CFG: &str = "cfg"; +const EXCEPT: Symbol = sym::except; +const LABEL: Symbol = sym::label; +const CFG: Symbol = sym::cfg; // Base and Extra labels to build up the labels /// For typedef, constants, and statics const BASE_CONST: &[&str] = &[ - label_strs::TypeOfItem, + label_strs::type_of, ]; /// DepNodes for functions + methods const BASE_FN: &[&str] = &[ // Callers will depend on the signature of these items, so we better test - label_strs::FnSignature, - label_strs::GenericsOfItem, - label_strs::PredicatesOfItem, - label_strs::TypeOfItem, + label_strs::fn_sig, + label_strs::generics_of, + label_strs::predicates_of, + label_strs::type_of, // And a big part of compilation (that we eventually want to cache) is type inference // information: - label_strs::TypeckTables, + label_strs::typeck_tables_of, ]; /// DepNodes for Hir, which is pretty much everything @@ -61,16 +62,16 @@ const BASE_HIR: &[&str] = &[ /// `impl` implementation of struct/trait const BASE_IMPL: &[&str] = &[ - label_strs::AssociatedItemDefIds, - label_strs::GenericsOfItem, - label_strs::ImplTraitRef, + label_strs::associated_item_def_ids, + label_strs::generics_of, + label_strs::impl_trait_ref, ]; -/// DepNodes for MirBuilt/Optimized, which is relevant in "executable" +/// DepNodes for mir_built/Optimized, which is relevant in "executable" /// code, i.e., functions+methods const BASE_MIR: &[&str] = &[ - label_strs::MirOptimized, - label_strs::MirBuilt, + label_strs::optimized_mir, + label_strs::mir_built, ]; /// Struct, Enum and Union DepNodes @@ -78,29 +79,29 @@ const BASE_MIR: &[&str] = &[ /// Note that changing the type of a field does not change the type of the struct or enum, but /// adding/removing fields or changing a fields name or visibility does. const BASE_STRUCT: &[&str] = &[ - label_strs::GenericsOfItem, - label_strs::PredicatesOfItem, - label_strs::TypeOfItem, + label_strs::generics_of, + label_strs::predicates_of, + label_strs::type_of, ]; /// Trait definition `DepNode`s. const BASE_TRAIT_DEF: &[&str] = &[ - label_strs::AssociatedItemDefIds, - label_strs::GenericsOfItem, - label_strs::ObjectSafety, - label_strs::PredicatesOfItem, - label_strs::SpecializationGraph, - label_strs::TraitDefOfItem, - label_strs::TraitImpls, + label_strs::associated_item_def_ids, + label_strs::generics_of, + label_strs::is_object_safe, + label_strs::predicates_of, + label_strs::specialization_graph_of, + label_strs::trait_def, + label_strs::trait_impls_of, ]; /// Extra `DepNode`s for functions and methods. const EXTRA_ASSOCIATED: &[&str] = &[ - label_strs::AssociatedItems, + label_strs::associated_item, ]; const EXTRA_TRAIT: &[&str] = &[ - label_strs::TraitOfItem, + label_strs::trait_of_item, ]; // Fully Built Labels @@ -179,7 +180,7 @@ const LABELS_TRAIT: &[&[&str]] = &[ // Fields are kind of separate from their containers, as they can change independently from // them. We should at least check // -// TypeOfItem for these. +// type_of for these. type Labels = FxHashSet; @@ -205,7 +206,7 @@ impl Assertion { } } -pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn check_dirty_clean_annotations<'tcx>(tcx: TyCtxt<'tcx>) { // can't add `#[rustc_dirty]` etc without opting in to this feature if !tcx.features().rustc_attrs { return; @@ -233,13 +234,12 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { }) } -pub struct DirtyCleanVisitor<'a, 'tcx:'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub struct DirtyCleanVisitor<'tcx> { + tcx: TyCtxt<'tcx>, checked_attrs: FxHashSet, } -impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { - +impl DirtyCleanVisitor<'tcx> { /// Possibly "deserialize" the attribute into a clean/dirty assertion fn assertion_maybe(&mut self, item_id: hir::HirId, attr: &Attribute) -> Option @@ -322,7 +322,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { /// Return all DepNode labels that should be asserted for this item. /// index=0 is the "name" used for error messages fn auto_labels(&mut self, item_id: hir::HirId, attr: &Attribute) -> (&'static str, Labels) { - let node = self.tcx.hir().get_by_hir_id(item_id); + let node = self.tcx.hir().get(item_id); let (name, labels) = match node { HirNode::Item(item) => { match item.node { @@ -430,13 +430,13 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { if DepNode::has_label_string(label) { if out.contains(label) { self.tcx.sess.span_fatal( - item.span, + item.span(), &format!("dep-node label `{}` is repeated", label)); } out.insert(label.to_string()); } else { self.tcx.sess.span_fatal( - item.span, + item.span(), &format!("dep-node label `{}` not recognized", label)); } } @@ -463,7 +463,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { if let Some(def_id) = dep_node.extract_def_id(self.tcx) { format!("{:?}({})", dep_node.kind, - self.tcx.item_path_str(def_id)) + self.tcx.def_path_str(def_id)) } else { format!("{:?}({:?})", dep_node.kind, dep_node.hash) } @@ -517,7 +517,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { +impl ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { self.check_item(item.hir_id, item.span); } @@ -537,7 +537,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { /// /// Also make sure that the `label` and `except` fields do not /// both exist. -fn check_config(tcx: TyCtxt<'_, '_, '_>, attr: &Attribute) -> bool { +fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { debug!("check_config(attr={:?})", attr); let config = &tcx.sess.parse_sess.config; debug!("check_config: config={:?}", config); @@ -572,34 +572,33 @@ fn check_config(tcx: TyCtxt<'_, '_, '_>, attr: &Attribute) -> bool { } } -fn expect_associated_value(tcx: TyCtxt<'_, '_, '_>, item: &NestedMetaItem) -> ast::Name { +fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> ast::Name { if let Some(value) = item.value_str() { value } else { - let msg = if let Some(name) = item.name() { - format!("associated value expected for `{}`", name) + let msg = if let Some(ident) = item.ident() { + format!("associated value expected for `{}`", ident) } else { "expected an associated value".to_string() }; - tcx.sess.span_fatal(item.span, &msg); + tcx.sess.span_fatal(item.span(), &msg); } } // A visitor that collects all #[rustc_dirty]/#[rustc_clean] attributes from // the HIR. It is used to verfiy that we really ran checks for all annotated // nodes. -pub struct FindAllAttrs<'a, 'tcx:'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - attr_names: Vec<&'static str>, +pub struct FindAllAttrs<'tcx> { + tcx: TyCtxt<'tcx>, + attr_names: Vec, found_attrs: Vec<&'tcx Attribute>, } -impl<'a, 'tcx> FindAllAttrs<'a, 'tcx> { - +impl FindAllAttrs<'tcx> { fn is_active_attr(&mut self, attr: &Attribute) -> bool { for attr_name in &self.attr_names { - if attr.check_name(attr_name) && check_config(self.tcx, attr) { + if attr.check_name(*attr_name) && check_config(self.tcx, attr) { return true; } } @@ -617,7 +616,7 @@ impl<'a, 'tcx> FindAllAttrs<'a, 'tcx> { } } -impl<'a, 'tcx> intravisit::Visitor<'tcx> for FindAllAttrs<'a, 'tcx> { +impl intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> { fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { intravisit::NestedVisitorMap::All(&self.tcx.hir()) } diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 7dcd5c94bf298..7f697b5448464 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -886,7 +886,10 @@ fn safe_remove_dir_all(p: &Path) -> io::Result<()> { fn safe_remove_file(p: &Path) -> io::Result<()> { if p.exists() { let canonicalized = p.canonicalize()?; - std_fs::remove_file(canonicalized) + match std_fs::remove_file(canonicalized) { + Err(ref err) if err.kind() == io::ErrorKind::NotFound => Ok(()), + result => result, + } } else { Ok(()) } diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index ecf8bc4a88084..d9bcc0b2a83c7 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -15,13 +15,12 @@ use super::fs::*; use super::file_format; use super::work_product; -pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn dep_graph_tcx_init<'tcx>(tcx: TyCtxt<'tcx>) { if !tcx.dep_graph.is_fully_enabled() { return } tcx.allocate_metadata_dep_nodes(); - tcx.precompute_in_scope_traits_hashes(); } type WorkProductMap = FxHashMap; @@ -94,10 +93,10 @@ impl MaybeAsync { } } +pub type DepGraphFuture = MaybeAsync>; + /// Launch a thread and load the dependency graph in the background. -pub fn load_dep_graph(sess: &Session) -> - MaybeAsync> -{ +pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { // Since `sess` isn't `Sync`, we perform all accesses to `sess` // before we fire the background thread. diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index 3aad4f5abb884..bf404140f18d5 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -16,7 +16,7 @@ pub use fs::in_incr_comp_dir; pub use fs::in_incr_comp_dir_sess; pub use fs::prepare_session_directory; pub use load::dep_graph_tcx_init; -pub use load::load_dep_graph; +pub use load::{DepGraphFuture, load_dep_graph}; pub use load::load_query_result_cache; pub use load::LoadResult; pub use save::save_dep_graph; diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 34fe2f1c25d04..49c79ec09f5e2 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -15,7 +15,7 @@ use super::dirty_clean; use super::file_format; use super::work_product; -pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn save_dep_graph<'tcx>(tcx: TyCtxt<'tcx>) { debug!("save_dep_graph()"); tcx.dep_graph.with_ignore(|| { let sess = tcx.sess; @@ -129,8 +129,7 @@ fn save_in(sess: &Session, path_buf: PathBuf, encode: F) } } -fn encode_dep_graph(tcx: TyCtxt<'_, '_, '_>, - encoder: &mut Encoder) { +fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut Encoder) { // First encode the commandline arguments hash tcx.sess.opts.dep_tracking_hash().encode(encoder).unwrap(); @@ -234,8 +233,7 @@ fn encode_work_product_index(work_products: &FxHashMap, - encoder: &mut Encoder) { +fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut Encoder) { time(tcx.sess, "serialize query result cache", || { tcx.serialize_query_result_cache(encoder).unwrap(); }) diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index 1acd3dfc7656a..bcaa4216109aa 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustc_interface" version = "0.0.0" +edition = "2018" [lib] name = "rustc_interface" @@ -10,9 +11,9 @@ crate-type = ["dylib"] [dependencies] log = "0.4" -rustc-rayon = "0.1.1" +rayon = { version = "0.2.0", package = "rustc-rayon" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } -scoped-tls = { version = "0.1.1", features = ["nightly"] } +scoped-tls = "1.0" syntax = { path = "../libsyntax" } syntax_ext = { path = "../libsyntax_ext" } syntax_pos = { path = "../libsyntax_pos" } @@ -23,6 +24,7 @@ rustc_borrowck = { path = "../librustc_borrowck" } rustc_incremental = { path = "../librustc_incremental" } rustc_traits = { path = "../librustc_traits" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_metadata = { path = "../librustc_metadata" } rustc_mir = { path = "../librustc_mir" } @@ -33,3 +35,4 @@ rustc_errors = { path = "../librustc_errors" } rustc_plugin = { path = "../librustc_plugin" } rustc_privacy = { path = "../librustc_privacy" } rustc_resolve = { path = "../librustc_resolve" } +tempfile = "3.0.5" diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs new file mode 100644 index 0000000000000..674b2b60e44a2 --- /dev/null +++ b/src/librustc_interface/interface.rs @@ -0,0 +1,152 @@ +use crate::queries::Queries; +use crate::util; +use crate::profile; +pub use crate::passes::BoxedResolver; + +use rustc::lint; +use rustc::session::config::{self, Input}; +use rustc::session::{DiagnosticOutput, Session}; +use rustc::util::common::ErrorReported; +use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_data_structures::OnDrop; +use rustc_data_structures::sync::Lrc; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use rustc_metadata::cstore::CStore; +use std::io::Write; +use std::path::PathBuf; +use std::result; +use std::sync::{Arc, Mutex}; +use syntax; +use syntax::source_map::{FileLoader, SourceMap}; +use syntax_pos::edition; + +pub type Result = result::Result; + +/// Represents a compiler session. +/// Can be used run `rustc_interface` queries. +/// Created by passing `Config` to `run_compiler`. +pub struct Compiler { + pub(crate) sess: Lrc, + codegen_backend: Lrc>, + source_map: Lrc, + pub(crate) input: Input, + pub(crate) input_path: Option, + pub(crate) output_dir: Option, + pub(crate) output_file: Option, + pub(crate) queries: Queries, + pub(crate) cstore: Lrc, + pub(crate) crate_name: Option, +} + +impl Compiler { + pub fn session(&self) -> &Lrc { + &self.sess + } + pub fn codegen_backend(&self) -> &Lrc> { + &self.codegen_backend + } + pub fn cstore(&self) -> &Lrc { + &self.cstore + } + pub fn source_map(&self) -> &Lrc { + &self.source_map + } + pub fn input(&self) -> &Input { + &self.input + } + pub fn output_dir(&self) -> &Option { + &self.output_dir + } + pub fn output_file(&self) -> &Option { + &self.output_file + } +} + +/// The compiler configuration +pub struct Config { + /// Command line options + pub opts: config::Options, + + /// cfg! configuration in addition to the default ones + pub crate_cfg: FxHashSet<(String, Option)>, + + pub input: Input, + pub input_path: Option, + pub output_dir: Option, + pub output_file: Option, + pub file_loader: Option>, + pub diagnostic_output: DiagnosticOutput, + + /// Set to capture stderr output during compiler execution + pub stderr: Option>>>, + + pub crate_name: Option, + pub lint_caps: FxHashMap, +} + +pub fn run_compiler_in_existing_thread_pool(config: Config, f: F) -> R +where + F: FnOnce(&Compiler) -> R, +{ + let (sess, codegen_backend, source_map) = util::create_session( + config.opts, + config.crate_cfg, + config.diagnostic_output, + config.file_loader, + config.input_path.clone(), + config.lint_caps, + ); + + let cstore = Lrc::new(CStore::new(codegen_backend.metadata_loader())); + + let compiler = Compiler { + sess, + codegen_backend, + source_map, + cstore, + input: config.input, + input_path: config.input_path, + output_dir: config.output_dir, + output_file: config.output_file, + queries: Default::default(), + crate_name: config.crate_name, + }; + + let _sess_abort_error = OnDrop(|| { + compiler.sess.diagnostic().print_error_count(&util::diagnostics_registry()); + }); + + if compiler.sess.profile_queries() { + profile::begin(&compiler.sess); + } + + let r = f(&compiler); + + if compiler.sess.profile_queries() { + profile::dump(&compiler.sess, "profile_queries".to_string()) + } + + r +} + +pub fn run_compiler(mut config: Config, f: F) -> R +where + F: FnOnce(&Compiler) -> R + Send, + R: Send, +{ + let stderr = config.stderr.take(); + util::spawn_thread_pool( + config.opts.edition, + config.opts.debugging_opts.threads, + &stderr, + || run_compiler_in_existing_thread_pool(config, f), + ) +} + +pub fn default_thread_pool(edition: edition::Edition, f: F) -> R +where + F: FnOnce() -> R + Send, + R: Send, +{ + util::spawn_thread_pool(edition, None, &None, f) +} diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs index e5c7c35a36d75..7fc311d40c3d0 100644 --- a/src/librustc_interface/lib.rs +++ b/src/librustc_interface/lib.rs @@ -3,41 +3,25 @@ #![feature(nll)] #![feature(arbitrary_self_types)] #![feature(generator_trait)] +#![feature(generators)] #![cfg_attr(unix, feature(libc))] +#![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] + #![allow(unused_imports)] #![recursion_limit="256"] #[cfg(unix)] extern crate libc; -#[macro_use] -extern crate log; -extern crate rustc; -extern crate rustc_codegen_utils; -extern crate rustc_allocator; -extern crate rustc_borrowck; -extern crate rustc_incremental; -extern crate rustc_traits; -#[macro_use] -extern crate rustc_data_structures; -extern crate rustc_errors; -extern crate rustc_lint; -extern crate rustc_metadata; -extern crate rustc_mir; -extern crate rustc_passes; -extern crate rustc_plugin; -extern crate rustc_privacy; -extern crate rustc_rayon as rayon; -extern crate rustc_resolve; -extern crate rustc_typeck; -extern crate smallvec; -extern crate serialize; -extern crate syntax; -extern crate syntax_pos; -extern crate syntax_ext; -pub mod passes; -pub mod profile; +pub mod interface; +mod passes; +mod queries; pub mod util; -pub mod proc_macro_decls; +mod proc_macro_decls; +mod profile; + +pub use interface::{run_compiler, Config}; diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 16ced6956380b..c1b6e3409c915 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -1,6 +1,8 @@ -use util; -use proc_macro_decls; +use crate::interface::{Compiler, Result}; +use crate::util; +use crate::proc_macro_decls; +use log::{debug, info, warn, log_enabled}; use rustc::dep_graph::DepGraph; use rustc::hir; use rustc::hir::lowering::lower_crate; @@ -8,21 +10,25 @@ use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::lint; use rustc::middle::{self, reachable, resolve_lifetime, stability}; use rustc::middle::privacy::AccessLevels; -use rustc::ty::{self, AllArenas, Resolutions, TyCtxt}; +use rustc::ty::{self, AllArenas, Resolutions, TyCtxt, GlobalCtxt}; use rustc::ty::steal::Steal; use rustc::traits; use rustc::util::common::{time, ErrorReported}; use rustc::util::profiling::ProfileCategory; use rustc::session::{CompileResult, CrateDisambiguator, Session}; -use rustc::session::config::{self, Input, OutputFilenames, OutputType}; +use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; use rustc_allocator as allocator; use rustc_borrowck as borrowck; +use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_codegen_utils::link::filename_for_metadata; +use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::StableHasher; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{Lrc, ParallelIterator, par_iter}; use rustc_incremental; +use rustc_incremental::DepGraphFuture; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::{self, CStore}; use rustc_mir as mir; @@ -35,16 +41,18 @@ use rustc_traits; use rustc_typeck as typeck; use syntax::{self, ast, attr, diagnostics, visit}; use syntax::early_buffered_lints::BufferedEarlyLint; -use syntax::ext::base::ExtCtxt; +use syntax::ext::base::{NamedSyntaxExtension, ExtCtxt}; use syntax::mut_visit::MutVisitor; use syntax::parse::{self, PResult}; use syntax::util::node_count::NodeCounter; use syntax::util::lev_distance::find_best_match_for_name; use syntax::symbol::Symbol; -use syntax_pos::{FileName, hygiene}; +use syntax::feature_gate::AttributeType; +use syntax_pos::{FileName, edition::Edition, hygiene}; use syntax_ext; use serialize::json; +use tempfile::Builder as TempFileBuilder; use std::any::Any; use std::env; @@ -59,8 +67,519 @@ use std::rc::Rc; use std::mem; use std::ops::Generator; -/// Returns all the paths that correspond to generated files. -pub fn generated_output_paths( +pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { + sess.diagnostic() + .set_continue_after_error(sess.opts.debugging_opts.continue_parse_after_error); + sess.profiler(|p| p.start_activity("parsing")); + let krate = time(sess, "parsing", || match *input { + Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess), + Input::Str { + ref input, + ref name, + } => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess), + })?; + sess.profiler(|p| p.end_activity("parsing")); + + sess.diagnostic().set_continue_after_error(true); + + if sess.opts.debugging_opts.ast_json_noexpand { + println!("{}", json::as_json(&krate)); + } + + if sess.opts.debugging_opts.input_stats { + println!( + "Lines of code: {}", + sess.source_map().count_lines() + ); + println!("Pre-expansion node count: {}", count_nodes(&krate)); + } + + if let Some(ref s) = sess.opts.debugging_opts.show_span { + syntax::show_span::run(sess.diagnostic(), s, &krate); + } + + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS"); + } + + Ok(krate) +} + +fn count_nodes(krate: &ast::Crate) -> usize { + let mut counter = NodeCounter::new(); + visit::walk_crate(&mut counter, krate); + counter.count +} + +declare_box_region_type!( + pub BoxedResolver, + for(), + (&mut Resolver<'_>) -> (Result, ExpansionResult) +); + +/// Runs the "early phases" of the compiler: initial `cfg` processing, +/// loading compiler plugins (including those from `addl_plugins`), +/// syntax expansion, secondary `cfg` expansion, synthesis of a test +/// harness if one is to be provided, injection of a dependency on the +/// standard library and prelude, and name resolution. +/// +/// Returns `None` if we're aborting after handling -W help. +pub fn configure_and_expand( + sess: Lrc, + cstore: Lrc, + krate: ast::Crate, + crate_name: &str, + plugin_info: PluginInfo, +) -> Result<(ast::Crate, BoxedResolver)> { + // Currently, we ignore the name resolution data structures for the purposes of dependency + // tracking. Instead we will run name resolution and include its output in the hash of each + // item, much like we do for macro expansion. In other words, the hash reflects not just + // its contents but the results of name resolution on those contents. Hopefully we'll push + // this back at some point. + let crate_name = crate_name.to_string(); + let (result, resolver) = BoxedResolver::new(static move || { + let sess = &*sess; + let mut crate_loader = CrateLoader::new(sess, &*cstore, &crate_name); + let resolver_arenas = Resolver::arenas(); + let res = configure_and_expand_inner( + sess, + &*cstore, + krate, + &crate_name, + &resolver_arenas, + &mut crate_loader, + plugin_info, + ); + let mut resolver = match res { + Err(v) => { + yield BoxedResolver::initial_yield(Err(v)); + panic!() + } + Ok((krate, resolver)) => { + yield BoxedResolver::initial_yield(Ok(krate)); + resolver + } + }; + box_region_allow_access!(for(), (&mut Resolver<'_>), (&mut resolver)); + ExpansionResult::from_owned_resolver(resolver) + }); + result.map(|k| (k, resolver)) +} + +pub struct ExpansionResult { + pub defs: Steal, + pub resolutions: Steal, +} + +impl ExpansionResult { + fn from_owned_resolver( + resolver: Resolver<'_>, + ) -> Self { + ExpansionResult { + defs: Steal::new(resolver.definitions), + resolutions: Steal::new(Resolutions { + export_map: resolver.export_map, + trait_map: resolver.trait_map, + glob_map: resolver.glob_map, + maybe_unused_trait_imports: resolver.maybe_unused_trait_imports, + maybe_unused_extern_crates: resolver.maybe_unused_extern_crates, + extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { + (ident.name, entry.introduced_by_item) + }).collect(), + }), + } + } + + pub fn from_resolver_ref( + resolver: &Resolver<'_>, + ) -> Self { + ExpansionResult { + defs: Steal::new(resolver.definitions.clone()), + resolutions: Steal::new(Resolutions { + export_map: resolver.export_map.clone(), + trait_map: resolver.trait_map.clone(), + glob_map: resolver.glob_map.clone(), + maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(), + maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(), + extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { + (ident.name, entry.introduced_by_item) + }).collect(), + }), + } + } +} + +impl BoxedResolver { + pub fn to_expansion_result( + mut resolver: Rc>>, + ) -> ExpansionResult { + if let Some(resolver) = Rc::get_mut(&mut resolver) { + mem::replace(resolver, None).unwrap().into_inner().complete() + } else { + let resolver = &*resolver; + resolver.as_ref().unwrap().borrow_mut().access(|resolver| { + ExpansionResult::from_resolver_ref(resolver) + }) + } + } +} + +pub struct PluginInfo { + syntax_exts: Vec, + attributes: Vec<(Symbol, AttributeType)>, +} + +pub fn register_plugins<'a>( + compiler: &Compiler, + sess: &'a Session, + cstore: &'a CStore, + mut krate: ast::Crate, + crate_name: &str, +) -> Result<(ast::Crate, PluginInfo)> { + krate = time(sess, "attributes injection", || { + syntax::attr::inject(krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr) + }); + + let (mut krate, features) = syntax::config::features( + krate, + &sess.parse_sess, + sess.edition(), + &sess.opts.debugging_opts.allow_features, + ); + // these need to be set "early" so that expansion sees `quote` if enabled. + sess.init_features(features); + + let crate_types = util::collect_crate_types(sess, &krate.attrs); + sess.crate_types.set(crate_types); + + let disambiguator = util::compute_crate_disambiguator(sess); + sess.crate_disambiguator.set(disambiguator); + rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator); + + if sess.opts.incremental.is_some() { + time(sess, "garbage collect incremental cache directory", || { + if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) { + warn!( + "Error while trying to garbage collect incremental \ + compilation cache directory: {}", + e + ); + } + }); + } + + // If necessary, compute the dependency graph (in the background). + compiler.dep_graph_future().ok(); + + time(sess, "recursion limit", || { + middle::recursion_limit::update_limits(sess, &krate); + }); + + krate = time(sess, "crate injection", || { + let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| &**s); + syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name, sess.edition()) + }); + + let registrars = time(sess, "plugin loading", || { + plugin::load::load_plugins( + sess, + &cstore, + &krate, + crate_name, + Some(sess.opts.debugging_opts.extra_plugins.clone()), + ) + }); + + let mut registry = Registry::new(sess, krate.span); + + time(sess, "plugin registration", || { + if sess.features_untracked().rustc_diagnostic_macros { + registry.register_macro( + "__diagnostic_used", + diagnostics::plugin::expand_diagnostic_used, + ); + registry.register_macro( + "__register_diagnostic", + diagnostics::plugin::expand_register_diagnostic, + ); + registry.register_macro( + "__build_diagnostic_array", + diagnostics::plugin::expand_build_diagnostic_array, + ); + } + + for registrar in registrars { + registry.args_hidden = Some(registrar.args); + (registrar.fun)(&mut registry); + } + }); + + let Registry { + syntax_exts, + early_lint_passes, + late_lint_passes, + lint_groups, + llvm_passes, + attributes, + .. + } = registry; + + let mut ls = sess.lint_store.borrow_mut(); + for pass in early_lint_passes { + ls.register_early_pass(Some(sess), true, false, pass); + } + for pass in late_lint_passes { + ls.register_late_pass(Some(sess), true, false, false, pass); + } + + for (name, (to, deprecated_name)) in lint_groups { + ls.register_group(Some(sess), true, name, deprecated_name, to); + } + + *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; + *sess.plugin_attributes.borrow_mut() = attributes.clone(); + + Ok((krate, PluginInfo { + syntax_exts, + attributes, + })) +} + +fn configure_and_expand_inner<'a>( + sess: &'a Session, + cstore: &'a CStore, + mut krate: ast::Crate, + crate_name: &str, + resolver_arenas: &'a ResolverArenas<'a>, + crate_loader: &'a mut CrateLoader<'a>, + plugin_info: PluginInfo, +) -> Result<(ast::Crate, Resolver<'a>)> { + let attributes = plugin_info.attributes; + time(sess, "pre ast expansion lint checks", || { + lint::check_ast_crate( + sess, + &krate, + true, + rustc_lint::BuiltinCombinedPreExpansionLintPass::new()); + }); + + let mut resolver = Resolver::new( + sess, + cstore, + &krate, + crate_name, + crate_loader, + &resolver_arenas, + ); + syntax_ext::register_builtins(&mut resolver, plugin_info.syntax_exts, sess.edition()); + + // Expand all macros + sess.profiler(|p| p.start_activity("macro expansion")); + krate = time(sess, "expansion", || { + // Windows dlls do not have rpaths, so they don't know how to find their + // dependencies. It's up to us to tell the system where to find all the + // dependent dlls. Note that this uses cfg!(windows) as opposed to + // targ_cfg because syntax extensions are always loaded for the host + // compiler, not for the target. + // + // This is somewhat of an inherently racy operation, however, as + // multiple threads calling this function could possibly continue + // extending PATH far beyond what it should. To solve this for now we + // just don't add any new elements to PATH which are already there + // within PATH. This is basically a targeted fix at #17360 for rustdoc + // which runs rustc in parallel but has been seen (#33844) to cause + // problems with PATH becoming too long. + let mut old_path = OsString::new(); + if cfg!(windows) { + old_path = env::var_os("PATH").unwrap_or(old_path); + let mut new_path = sess.host_filesearch(PathKind::All).search_path_dirs(); + for path in env::split_paths(&old_path) { + if !new_path.contains(&path) { + new_path.push(path); + } + } + env::set_var( + "PATH", + &env::join_paths( + new_path + .iter() + .filter(|p| env::join_paths(iter::once(p)).is_ok()), + ).unwrap(), + ); + } + + // Create the config for macro expansion + let features = sess.features_untracked(); + let cfg = syntax::ext::expand::ExpansionConfig { + features: Some(&features), + recursion_limit: *sess.recursion_limit.get(), + trace_mac: sess.opts.debugging_opts.trace_macros, + should_test: sess.opts.test, + ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string()) + }; + + let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver); + + // Expand macros now! + let krate = time(sess, "expand crate", || { + ecx.monotonic_expander().expand_crate(krate) + }); + + // The rest is error reporting + + time(sess, "check unused macros", || { + ecx.check_unused_macros(); + }); + + let mut missing_fragment_specifiers: Vec<_> = ecx.parse_sess + .missing_fragment_specifiers + .borrow() + .iter() + .cloned() + .collect(); + missing_fragment_specifiers.sort(); + + for span in missing_fragment_specifiers { + let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER; + let msg = "missing fragment specifier"; + sess.buffer_lint(lint, ast::CRATE_NODE_ID, span, msg); + } + if cfg!(windows) { + env::set_var("PATH", &old_path); + } + krate + }); + sess.profiler(|p| p.end_activity("macro expansion")); + + time(sess, "maybe building test harness", || { + syntax::test::modify_for_testing( + &sess.parse_sess, + &mut resolver, + sess.opts.test, + &mut krate, + sess.diagnostic(), + &sess.features_untracked(), + ) + }); + + // If we're actually rustdoc then there's no need to actually compile + // anything, so switch everything to just looping + if sess.opts.actually_rustdoc { + util::ReplaceBodyWithLoop::new(sess).visit_crate(&mut krate); + } + + let (has_proc_macro_decls, has_global_allocator) = time(sess, "AST validation", || { + ast_validation::check_crate(sess, &krate) + }); + + // If we're in rustdoc we're always compiling as an rlib, but that'll trip a + // bunch of checks in the `modify` function below. For now just skip this + // step entirely if we're rustdoc as it's not too useful anyway. + if !sess.opts.actually_rustdoc { + krate = time(sess, "maybe creating a macro crate", || { + let crate_types = sess.crate_types.borrow(); + let num_crate_types = crate_types.len(); + let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro); + let is_test_crate = sess.opts.test; + syntax_ext::proc_macro_decls::modify( + &sess.parse_sess, + &mut resolver, + krate, + is_proc_macro_crate, + has_proc_macro_decls, + is_test_crate, + num_crate_types, + sess.diagnostic(), + ) + }); + } + + if has_global_allocator { + // Expand global allocators, which are treated as an in-tree proc macro + time(sess, "creating allocators", || { + allocator::expand::modify( + &sess.parse_sess, + &mut resolver, + &mut krate, + crate_name.to_string(), + sess.diagnostic(), + ) + }); + } + + // Done with macro expansion! + + if sess.opts.debugging_opts.input_stats { + println!("Post-expansion node count: {}", count_nodes(&krate)); + } + + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS"); + } + + if sess.opts.debugging_opts.ast_json { + println!("{}", json::as_json(&krate)); + } + + time(sess, "name resolution", || { + resolver.resolve_crate(&krate); + }); + + // Needs to go *after* expansion to be able to check the results of macro expansion. + time(sess, "complete gated feature checking", || { + syntax::feature_gate::check_crate( + &krate, + &sess.parse_sess, + &sess.features_untracked(), + &attributes, + sess.opts.unstable_features, + ); + }); + + // Add all buffered lints from the `ParseSess` to the `Session`. + sess.parse_sess.buffered_lints.with_lock(|buffered_lints| { + info!("{} parse sess buffered_lints", buffered_lints.len()); + for BufferedEarlyLint{id, span, msg, lint_id} in buffered_lints.drain(..) { + let lint = lint::Lint::from_parser_lint_id(lint_id); + sess.buffer_lint(lint, id, span, &msg); + } + }); + + Ok((krate, resolver)) +} + +pub fn lower_to_hir( + sess: &Session, + cstore: &CStore, + resolver: &mut Resolver<'_>, + dep_graph: &DepGraph, + krate: &ast::Crate, +) -> Result { + // Lower ast -> hir + let hir_forest = time(sess, "lowering ast -> hir", || { + let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, resolver); + + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_hir_stats(&hir_crate); + } + + hir::map::Forest::new(hir_crate, &dep_graph) + }); + + time(sess, "early lint checks", || { + lint::check_ast_crate(sess, &krate, false, rustc_lint::BuiltinCombinedEarlyLintPass::new()) + }); + + // Discard hygiene data, which isn't required after lowering to HIR. + if !sess.opts.debugging_opts.keep_hygiene_data { + syntax::ext::hygiene::clear_markings(); + } + + Ok(hir_forest) +} + +// Returns all the paths that correspond to generated files. +fn generated_output_paths( sess: &Session, outputs: &OutputFilenames, exact_name: bool, @@ -106,7 +625,7 @@ where None } -pub fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool { +fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool { let input_path = input_path.canonicalize().ok(); if input_path.is_none() { return false; @@ -121,7 +640,7 @@ pub fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> b check_output(output_paths, check).is_some() } -pub fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option { +fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option { let check = |output_path: &PathBuf| { if output_path.is_dir() { Some(output_path.clone()) @@ -138,7 +657,7 @@ fn escape_dep_filename(filename: &FileName) -> String { filename.to_string().replace(" ", "\\ ") } -pub fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &[PathBuf]) { +fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &[PathBuf]) { // Write out dependency rules to the dep-info file if requested if !sess.opts.output_types.contains_key(&OutputType::DepInfo) { return; @@ -178,81 +697,250 @@ pub fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: } } -pub fn provide(providers: &mut ty::query::Providers) { +pub fn prepare_outputs( + sess: &Session, + compiler: &Compiler, + krate: &ast::Crate, + crate_name: &str +) -> Result { + // FIXME: rustdoc passes &[] instead of &krate.attrs here + let outputs = util::build_output_filenames( + &compiler.input, + &compiler.output_dir, + &compiler.output_file, + &krate.attrs, + sess + ); + + let output_paths = generated_output_paths( + sess, + &outputs, + compiler.output_file.is_some(), + &crate_name, + ); + + // Ensure the source file isn't accidentally overwritten during compilation. + if let Some(ref input_path) = compiler.input_path { + if sess.opts.will_create_output_file() { + if output_contains_path(&output_paths, input_path) { + sess.err(&format!( + "the input file \"{}\" would be overwritten by the generated \ + executable", + input_path.display() + )); + return Err(ErrorReported); + } + if let Some(dir_path) = output_conflicts_with_dir(&output_paths) { + sess.err(&format!( + "the generated executable for the input file \"{}\" conflicts with the \ + existing directory \"{}\"", + input_path.display(), + dir_path.display() + )); + return Err(ErrorReported); + } + } + } + + write_out_deps(sess, &outputs, &output_paths); + + let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo) + && sess.opts.output_types.len() == 1; + + if !only_dep_info { + if let Some(ref dir) = compiler.output_dir { + if fs::create_dir_all(dir).is_err() { + sess.err("failed to find or create the directory specified by --out-dir"); + return Err(ErrorReported); + } + } + } + + Ok(outputs) +} + +pub fn default_provide(providers: &mut ty::query::Providers<'_>) { providers.analysis = analysis; proc_macro_decls::provide(providers); + plugin::build::provide(providers); + hir::provide(providers); + borrowck::provide(providers); + mir::provide(providers); + reachable::provide(providers); + resolve_lifetime::provide(providers); + rustc_privacy::provide(providers); + typeck::provide(providers); + ty::provide(providers); + traits::provide(providers); + stability::provide(providers); + middle::intrinsicck::provide(providers); + middle::liveness::provide(providers); + reachable::provide(providers); + rustc_passes::provide(providers); + rustc_traits::provide(providers); + middle::region::provide(providers); + middle::entry::provide(providers); + cstore::provide(providers); + lint::provide(providers); + rustc_lint::provide(providers); } -fn analysis<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, - cnum: CrateNum, -) -> Result<(), ErrorReported> { - assert_eq!(cnum, LOCAL_CRATE); +pub fn default_provide_extern(providers: &mut ty::query::Providers<'_>) { + cstore::provide_extern(providers); +} - let sess = tcx.sess; +declare_box_region_type!( + pub BoxedGlobalCtxt, + for('tcx), + (&'tcx GlobalCtxt<'tcx>) -> ((), ()) +); - parallel!({ - time(sess, "looking for entry point", || { - middle::entry::find_entry_point(tcx) - }); +impl BoxedGlobalCtxt { + pub fn enter(&mut self, f: F) -> R + where + F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R, + { + self.access(|gcx| ty::tls::enter_global(gcx, |tcx| f(tcx))) + } +} - time(sess, "looking for plugin registrar", || { - plugin::build::find_plugin_registrar(tcx) +pub fn create_global_ctxt( + compiler: &Compiler, + mut hir_forest: hir::map::Forest, + defs: hir::map::Definitions, + resolutions: Resolutions, + outputs: OutputFilenames, + tx: mpsc::Sender>, + crate_name: &str, +) -> BoxedGlobalCtxt { + let sess = compiler.session().clone(); + let cstore = compiler.cstore.clone(); + let codegen_backend = compiler.codegen_backend().clone(); + let crate_name = crate_name.to_string(); + + let ((), result) = BoxedGlobalCtxt::new(static move || { + let sess = &*sess; + let cstore = &*cstore; + + let global_ctxt: Option>; + let arenas = AllArenas::new(); + + // Construct the HIR map + let hir_map = time(sess, "indexing hir", || { + hir::map::map_crate(sess, cstore, &mut hir_forest, &defs) }); - time(sess, "looking for derive registrar", || { - proc_macro_decls::find(tcx) + let query_result_on_disk_cache = time(sess, "load query result cache", || { + rustc_incremental::load_query_result_cache(sess) }); - }, { - time(sess, "loop checking", || loops::check_crate(tcx)); - }, { - time(sess, "attribute checking", || { - hir::check_attr::check_crate(tcx) + + let mut local_providers = ty::query::Providers::default(); + default_provide(&mut local_providers); + codegen_backend.provide(&mut local_providers); + + let mut extern_providers = local_providers; + default_provide_extern(&mut extern_providers); + codegen_backend.provide_extern(&mut extern_providers); + + let gcx = TyCtxt::create_global_ctxt( + sess, + cstore, + local_providers, + extern_providers, + &arenas, + resolutions, + hir_map, + query_result_on_disk_cache, + &crate_name, + tx, + &outputs + ); + + global_ctxt = Some(gcx); + let gcx = global_ctxt.as_ref().unwrap(); + + ty::tls::enter_global(gcx, |tcx| { + // Do some initialization of the DepGraph that can only be done with the + // tcx available. + time(tcx.sess, "dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx)); }); - }, { - time(sess, "stability checking", || { - stability::check_unstable_api_usage(tcx) + + yield BoxedGlobalCtxt::initial_yield(()); + box_region_allow_access!(for('tcx), (&'tcx GlobalCtxt<'tcx>), (gcx)); + + if sess.opts.debugging_opts.query_stats { + gcx.queries.print_stats(); + } + }); + + result +} + +/// Runs the resolution, type-checking, region checking and other +/// miscellaneous analysis passes on the crate. +fn analysis<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> Result<()> { + assert_eq!(cnum, LOCAL_CRATE); + + let sess = tcx.sess; + let mut entry_point = None; + + time(sess, "misc checking 1", || { + parallel!({ + entry_point = time(sess, "looking for entry point", || { + middle::entry::find_entry_point(tcx) + }); + + time(sess, "looking for plugin registrar", || { + plugin::build::find_plugin_registrar(tcx) + }); + + time(sess, "looking for derive registrar", || { + proc_macro_decls::find(tcx) + }); + }, { + par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { + tcx.ensure().check_mod_loops(tcx.hir().local_def_id(module)); + tcx.ensure().check_mod_attrs(tcx.hir().local_def_id(module)); + tcx.ensure().check_mod_unstable_api_usage(tcx.hir().local_def_id(module)); + }); }); }); // passes are timed inside typeck typeck::check_crate(tcx)?; - time(sess, "misc checking", || { + time(sess, "misc checking 2", || { parallel!({ - time(sess, "rvalue promotion", || { - rvalue_promotion::check_crate(tcx) + time(sess, "rvalue promotion + match checking", || { + tcx.par_body_owners(|def_id| { + tcx.ensure().const_is_rvalue_promotable_to_static(def_id); + tcx.ensure().check_match(def_id); + }); }); }, { - time(sess, "intrinsic checking", || { - middle::intrinsicck::check_crate(tcx) - }); - }, { - time(sess, "match checking", || mir::matchck_crate(tcx)); - }, { - // this must run before MIR dump, because - // "not all control paths return a value" is reported here. - // - // maybe move the check to a MIR pass? - time(sess, "liveness checking", || { - middle::liveness::check_crate(tcx) + time(sess, "liveness checking + intrinsic checking", || { + par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { + // this must run before MIR dump, because + // "not all control paths return a value" is reported here. + // + // maybe move the check to a MIR pass? + tcx.ensure().check_mod_liveness(tcx.hir().local_def_id(module)); + + tcx.ensure().check_mod_intrinsics(tcx.hir().local_def_id(module)); + }); }); }); }); - // Abort so we don't try to construct MIR with liveness errors. - // We also won't want to continue with errors from rvalue promotion - tcx.sess.abort_if_errors(); - time(sess, "borrow checking", || { if tcx.use_ast_borrowck() { borrowck::check_crate(tcx); } }); - time(sess, - "MIR borrow checking", - || tcx.par_body_owners(|def_id| { tcx.ensure().mir_borrowck(def_id); })); + time(sess, "MIR borrow checking", || { + tcx.par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id)); + }); time(sess, "dumping chalk-like clauses", || { rustc_traits::lowering::dump_program_clauses(tcx); @@ -267,30 +955,144 @@ fn analysis<'tcx>( time(sess, "layout testing", || layout_test::test_layout(tcx)); // Avoid overwhelming user with errors if borrow checking failed. - // I'm not sure how helpful this is, to be honest, but it avoids - // a + // I'm not sure how helpful this is, to be honest, but it avoids a // lot of annoying errors in the compile-fail tests (basically, // lint warnings and so on -- kindck used to do this abort, but // kindck is gone now). -nmatsakis - if sess.err_count() > 0 { + if sess.has_errors() { return Err(ErrorReported); } - time(sess, "misc checking", || { + time(sess, "misc checking 3", || { parallel!({ - time(sess, "privacy checking", || { - rustc_privacy::check_crate(tcx) + time(sess, "privacy access levels", || { + tcx.ensure().privacy_access_levels(LOCAL_CRATE); }); - }, { - time(sess, "death checking", || middle::dead::check_crate(tcx)); - }, { - time(sess, "unused lib feature checking", || { - stability::check_unused_or_stable_features(tcx) + parallel!({ + time(sess, "private in public", || { + tcx.ensure().check_private_in_public(LOCAL_CRATE); + }); + }, { + time(sess, "death checking", || middle::dead::check_crate(tcx)); + }, { + time(sess, "unused lib feature checking", || { + stability::check_unused_or_stable_features(tcx) + }); + }, { + time(sess, "lint checking", || { + lint::check_crate(tcx, || rustc_lint::BuiltinCombinedLateLintPass::new()); + }); }); }, { - time(sess, "lint checking", || lint::check_crate(tcx)); + time(sess, "privacy checking modules", || { + par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { + tcx.ensure().check_mod_privacy(tcx.hir().local_def_id(module)); + }); + }); }); }); Ok(()) } + +fn encode_and_write_metadata<'tcx>( + tcx: TyCtxt<'tcx>, + outputs: &OutputFilenames, +) -> (middle::cstore::EncodedMetadata, bool) { + #[derive(PartialEq, Eq, PartialOrd, Ord)] + enum MetadataKind { + None, + Uncompressed, + Compressed + } + + let metadata_kind = tcx.sess.crate_types.borrow().iter().map(|ty| { + match *ty { + CrateType::Executable | + CrateType::Staticlib | + CrateType::Cdylib => MetadataKind::None, + + CrateType::Rlib => MetadataKind::Uncompressed, + + CrateType::Dylib | + CrateType::ProcMacro => MetadataKind::Compressed, + } + }).max().unwrap_or(MetadataKind::None); + + let metadata = match metadata_kind { + MetadataKind::None => middle::cstore::EncodedMetadata::new(), + MetadataKind::Uncompressed | + MetadataKind::Compressed => tcx.encode_metadata(), + }; + + let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata); + if need_metadata_file { + let crate_name = &tcx.crate_name(LOCAL_CRATE).as_str(); + let out_filename = filename_for_metadata(tcx.sess, crate_name, outputs); + // To avoid races with another rustc process scanning the output directory, + // we need to write the file somewhere else and atomically move it to its + // final destination, with an `fs::rename` call. In order for the rename to + // always succeed, the temporary file needs to be on the same filesystem, + // which is why we create it inside the output directory specifically. + let metadata_tmpdir = TempFileBuilder::new() + .prefix("rmeta") + .tempdir_in(out_filename.parent().unwrap()) + .unwrap_or_else(|err| { + tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)) + }); + let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir); + if let Err(e) = fs::rename(&metadata_filename, &out_filename) { + tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); + } + if tcx.sess.opts.debugging_opts.emit_artifact_notifications { + tcx.sess.parse_sess.span_diagnostic + .emit_artifact_notification(&out_filename, "metadata"); + } + } + + let need_metadata_module = metadata_kind == MetadataKind::Compressed; + + (metadata, need_metadata_module) +} + +/// Runs the codegen backend, after which the AST and analysis can +/// be discarded. +pub fn start_codegen<'tcx>( + codegen_backend: &dyn CodegenBackend, + tcx: TyCtxt<'tcx>, + rx: mpsc::Receiver>, + outputs: &OutputFilenames, +) -> Box { + if log_enabled!(::log::Level::Info) { + println!("Pre-codegen"); + tcx.print_debug_stats(); + } + + time(tcx.sess, "resolving dependency formats", || { + middle::dependency_format::calculate(tcx) + }); + + let (metadata, need_metadata_module) = time(tcx.sess, "metadata encoding and writing", || { + encode_and_write_metadata(tcx, outputs) + }); + + tcx.sess.profiler(|p| p.start_activity("codegen crate")); + let codegen = time(tcx.sess, "codegen", move || { + codegen_backend.codegen_crate(tcx, metadata, need_metadata_module, rx) + }); + tcx.sess.profiler(|p| p.end_activity("codegen crate")); + + if log_enabled!(::log::Level::Info) { + println!("Post-codegen"); + tcx.print_debug_stats(); + } + + if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { + if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, outputs) { + tcx.sess.err(&format!("could not emit MIR: {}", e)); + tcx.sess.abort_if_errors(); + } + } + + codegen +} diff --git a/src/librustc_interface/proc_macro_decls.rs b/src/librustc_interface/proc_macro_decls.rs index 093d15b7e3c57..9e1ef6b022d9b 100644 --- a/src/librustc_interface/proc_macro_decls.rs +++ b/src/librustc_interface/proc_macro_decls.rs @@ -3,33 +3,30 @@ use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; -use syntax::ast; use syntax::attr; +use syntax::symbol::sym; -pub fn find<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> Option { +pub fn find<'tcx>(tcx: TyCtxt<'tcx>) -> Option { tcx.proc_macro_decls_static(LOCAL_CRATE) } -fn proc_macro_decls_static<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, - cnum: CrateNum, -) -> Option { +fn proc_macro_decls_static<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> Option { assert_eq!(cnum, LOCAL_CRATE); let mut finder = Finder { decls: None }; tcx.hir().krate().visit_all_item_likes(&mut finder); - finder.decls.map(|id| tcx.hir().local_def_id(id)) + finder.decls.map(|id| tcx.hir().local_def_id_from_hir_id(id)) } struct Finder { - decls: Option, + decls: Option, } impl<'v> ItemLikeVisitor<'v> for Finder { fn visit_item(&mut self, item: &hir::Item) { - if attr::contains_name(&item.attrs, "rustc_proc_macro_decls") { - self.decls = Some(item.id); + if attr::contains_name(&item.attrs, sym::rustc_proc_macro_decls) { + self.decls = Some(item.hir_id); } } diff --git a/src/librustc_interface/profile/mod.rs b/src/librustc_interface/profile/mod.rs index eb13a5668f927..2e71d46f4154c 100644 --- a/src/librustc_interface/profile/mod.rs +++ b/src/librustc_interface/profile/mod.rs @@ -1,8 +1,9 @@ +use log::debug; +use rustc::dep_graph::DepNode; use rustc::session::Session; use rustc::util::common::{ProfQDumpParams, ProfileQueriesMsg, profq_msg, profq_set_chan}; use std::sync::mpsc::{Receiver}; use std::io::{Write}; -use rustc::dep_graph::{DepNode}; use std::time::{Duration, Instant}; pub mod trace; @@ -61,7 +62,6 @@ fn total_duration(traces: &[trace::Rec]) -> Duration { fn profile_queries_thread(r: Receiver) { use self::trace::*; use std::fs::File; - use std::time::{Instant}; let mut profq_msgs: Vec = vec![]; let mut frame: StackFrame = StackFrame { parse_st: ParseState::Clear, traces: vec![] }; diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs new file mode 100644 index 0000000000000..570509ffb2b8c --- /dev/null +++ b/src/librustc_interface/queries.rs @@ -0,0 +1,303 @@ +use crate::interface::{Compiler, Result}; +use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo}; + +use rustc_incremental::DepGraphFuture; +use rustc_data_structures::sync::Lrc; +use rustc::session::config::{Input, OutputFilenames, OutputType}; +use rustc::session::Session; +use rustc::util::common::{time, ErrorReported}; +use rustc::util::profiling::ProfileCategory; +use rustc::lint; +use rustc::hir; +use rustc::hir::def_id::LOCAL_CRATE; +use rustc::ty; +use rustc::ty::steal::Steal; +use rustc::dep_graph::DepGraph; +use rustc_passes::hir_stats; +use rustc_plugin::registry::Registry; +use serialize::json; +use std::cell::{Ref, RefMut, RefCell}; +use std::ops::Deref; +use std::rc::Rc; +use std::sync::mpsc; +use std::any::Any; +use std::mem; +use syntax::parse::{self, PResult}; +use syntax::util::node_count::NodeCounter; +use syntax::{self, ast, attr, diagnostics, visit}; +use syntax_pos::hygiene; + +/// Represent the result of a query. +/// This result can be stolen with the `take` method and returned with the `give` method. +pub struct Query { + result: RefCell>>, +} + +impl Query { + fn compute Result>(&self, f: F) -> Result<&Query> { + let mut result = self.result.borrow_mut(); + if result.is_none() { + *result = Some(f()); + } + result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err) + } + + /// Takes ownership of the query result. Further attempts to take or peek the query + /// result will panic unless it is returned by calling the `give` method. + pub fn take(&self) -> T { + self.result + .borrow_mut() + .take() + .expect("missing query result") + .unwrap() + } + + /// Returns a stolen query result. Panics if there's already a result. + pub fn give(&self, value: T) { + let mut result = self.result.borrow_mut(); + assert!(result.is_none(), "a result already exists"); + *result = Some(Ok(value)); + } + + /// Borrows the query result using the RefCell. Panics if the result is stolen. + pub fn peek(&self) -> Ref<'_, T> { + Ref::map(self.result.borrow(), |r| { + r.as_ref().unwrap().as_ref().expect("missing query result") + }) + } + + /// Mutably borrows the query result using the RefCell. Panics if the result is stolen. + pub fn peek_mut(&self) -> RefMut<'_, T> { + RefMut::map(self.result.borrow_mut(), |r| { + r.as_mut().unwrap().as_mut().expect("missing query result") + }) + } +} + +impl Default for Query { + fn default() -> Self { + Query { + result: RefCell::new(None), + } + } +} + +#[derive(Default)] +pub(crate) struct Queries { + dep_graph_future: Query>, + parse: Query, + crate_name: Query, + register_plugins: Query<(ast::Crate, PluginInfo)>, + expansion: Query<(ast::Crate, Rc>>)>, + dep_graph: Query, + lower_to_hir: Query<(Steal, ExpansionResult)>, + prepare_outputs: Query, + codegen_channel: Query<(Steal>>, + Steal>>)>, + global_ctxt: Query, + ongoing_codegen: Query>, + link: Query<()>, +} + +impl Compiler { + pub fn dep_graph_future(&self) -> Result<&Query>> { + self.queries.dep_graph_future.compute(|| { + Ok(if self.session().opts.build_dep_graph() { + Some(rustc_incremental::load_dep_graph(self.session())) + } else { + None + }) + }) + } + + pub fn parse(&self) -> Result<&Query> { + self.queries.parse.compute(|| { + passes::parse(self.session(), &self.input).map_err( + |mut parse_error| { + parse_error.emit(); + ErrorReported + }, + ) + }) + } + + pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo)>> { + self.queries.register_plugins.compute(|| { + let crate_name = self.crate_name()?.peek().clone(); + let krate = self.parse()?.take(); + + passes::register_plugins( + self, + self.session(), + self.cstore(), + krate, + &crate_name, + ) + }) + } + + pub fn crate_name(&self) -> Result<&Query> { + self.queries.crate_name.compute(|| { + let parse_result = self.parse()?; + let krate = parse_result.peek(); + let result = match self.crate_name { + Some(ref crate_name) => crate_name.clone(), + None => rustc_codegen_utils::link::find_crate_name( + Some(self.session()), + &krate.attrs, + &self.input + ), + }; + Ok(result) + }) + } + + pub fn expansion( + &self + ) -> Result<&Query<(ast::Crate, Rc>>)>> { + self.queries.expansion.compute(|| { + let crate_name = self.crate_name()?.peek().clone(); + let (krate, plugin_info) = self.register_plugins()?.take(); + passes::configure_and_expand( + self.sess.clone(), + self.cstore().clone(), + krate, + &crate_name, + plugin_info, + ).map(|(krate, resolver)| (krate, Rc::new(Some(RefCell::new(resolver))))) + }) + } + + pub fn dep_graph(&self) -> Result<&Query> { + self.queries.dep_graph.compute(|| { + Ok(match self.dep_graph_future()?.take() { + None => DepGraph::new_disabled(), + Some(future) => { + let (prev_graph, prev_work_products) = + time(self.session(), "blocked while dep-graph loading finishes", || { + future.open().unwrap_or_else(|e| rustc_incremental::LoadResult::Error { + message: format!("could not decode incremental cache: {:?}", e), + }).open(self.session()) + }); + DepGraph::new(prev_graph, prev_work_products) + } + }) + }) + } + + pub fn lower_to_hir(&self) -> Result<&Query<(Steal, ExpansionResult)>> { + self.queries.lower_to_hir.compute(|| { + let expansion_result = self.expansion()?; + let (krate, resolver) = expansion_result.take(); + let resolver_ref = &*resolver; + let hir = Steal::new(resolver_ref.as_ref().unwrap().borrow_mut().access(|resolver| { + passes::lower_to_hir( + self.session(), + self.cstore(), + resolver, + &*self.dep_graph()?.peek(), + &krate + ) + })?); + expansion_result.give((krate, Rc::new(None))); + Ok((hir, BoxedResolver::to_expansion_result(resolver))) + }) + } + + pub fn prepare_outputs(&self) -> Result<&Query> { + self.queries.prepare_outputs.compute(|| { + self.lower_to_hir()?; + let krate = self.expansion()?; + let krate = krate.peek(); + let crate_name = self.crate_name()?; + let crate_name = crate_name.peek(); + passes::prepare_outputs(self.session(), self, &krate.0, &*crate_name) + }) + } + + pub fn codegen_channel(&self) -> Result<&Query<(Steal>>, + Steal>>)>> { + self.queries.codegen_channel.compute(|| { + let (tx, rx) = mpsc::channel(); + Ok((Steal::new(tx), Steal::new(rx))) + }) + } + + pub fn global_ctxt(&self) -> Result<&Query> { + self.queries.global_ctxt.compute(|| { + let crate_name = self.crate_name()?.peek().clone(); + let outputs = self.prepare_outputs()?.peek().clone(); + let hir = self.lower_to_hir()?; + let hir = hir.peek(); + let (ref hir_forest, ref expansion) = *hir; + let tx = self.codegen_channel()?.peek().0.steal(); + Ok(passes::create_global_ctxt( + self, + hir_forest.steal(), + expansion.defs.steal(), + expansion.resolutions.steal(), + outputs, + tx, + &crate_name)) + }) + } + + pub fn ongoing_codegen(&self) -> Result<&Query>> { + self.queries.ongoing_codegen.compute(|| { + let rx = self.codegen_channel()?.peek().1.steal(); + let outputs = self.prepare_outputs()?; + self.global_ctxt()?.peek_mut().enter(|tcx| { + tcx.analysis(LOCAL_CRATE).ok(); + + // Don't do code generation if there were any errors + self.session().compile_status()?; + + Ok(passes::start_codegen( + &***self.codegen_backend(), + tcx, + rx, + &*outputs.peek() + )) + }) + }) + } + + pub fn link(&self) -> Result<&Query<()>> { + self.queries.link.compute(|| { + let sess = self.session(); + + let ongoing_codegen = self.ongoing_codegen()?.take(); + + self.codegen_backend().join_codegen_and_link( + ongoing_codegen, + sess, + &*self.dep_graph()?.peek(), + &*self.prepare_outputs()?.peek(), + ).map_err(|_| ErrorReported)?; + + Ok(()) + }) + } + + pub fn compile(&self) -> Result<()> { + self.prepare_outputs()?; + + if self.session().opts.output_types.contains_key(&OutputType::DepInfo) + && self.session().opts.output_types.len() == 1 + { + return Ok(()) + } + + self.global_ctxt()?; + + // Drop AST after creating GlobalCtxt to free memory + mem::drop(self.expansion()?.take()); + + self.ongoing_codegen()?; + + // Drop GlobalCtxt after starting codegen to free memory + mem::drop(self.global_ctxt()?.take()); + + self.link().map(|_| ()) + } +} diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 6f92c30446215..a86d3cc43948d 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -1,9 +1,12 @@ +use log::info; use rustc::session::config::{Input, OutputFilenames, ErrorOutputType}; use rustc::session::{self, config, early_error, filesearch, Session, DiagnosticOutput}; use rustc::session::CrateDisambiguator; use rustc::ty; use rustc::lint; use rustc_codegen_utils::codegen_backend::CodegenBackend; +#[cfg(parallel_compiler)] +use rustc_data_structures::jobserver; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::fingerprint::Fingerprint; @@ -18,7 +21,6 @@ use rustc_plugin; use rustc_privacy; use rustc_resolve; use rustc_typeck; -use std::collections::HashSet; use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::io::{self, Write}; @@ -33,8 +35,9 @@ use syntax::mut_visit::{*, MutVisitor, visit_clobber}; use syntax::ast::BlockCheckMode; use syntax::util::lev_distance::find_best_match_for_name; use syntax::source_map::{FileLoader, RealFileLoader, SourceMap}; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax::{self, ast, attr}; +use syntax_pos::edition::Edition; #[cfg(not(parallel_compiler))] use std::{thread, panic}; @@ -65,7 +68,7 @@ pub fn add_configuration( sess: &Session, codegen_backend: &dyn CodegenBackend, ) { - let tf = Symbol::intern("target_feature"); + let tf = sym::target_feature; cfg.extend( codegen_backend @@ -79,6 +82,170 @@ pub fn add_configuration( } } +pub fn create_session( + sopts: config::Options, + cfg: FxHashSet<(String, Option)>, + diagnostic_output: DiagnosticOutput, + file_loader: Option>, + input_path: Option, + lint_caps: FxHashMap, +) -> (Lrc, Lrc>, Lrc) { + let descriptions = diagnostics_registry(); + + let loader = file_loader.unwrap_or(box RealFileLoader); + let source_map = Lrc::new(SourceMap::with_file_loader( + loader, + sopts.file_path_mapping(), + )); + let mut sess = session::build_session_with_source_map( + sopts, + input_path, + descriptions, + source_map.clone(), + diagnostic_output, + lint_caps, + ); + + let codegen_backend = get_codegen_backend(&sess); + + rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); + if sess.unstable_options() { + rustc_lint::register_internals(&mut sess.lint_store.borrow_mut(), Some(&sess)); + } + + let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg)); + add_configuration(&mut cfg, &sess, &*codegen_backend); + sess.parse_sess.config = cfg; + + (Lrc::new(sess), Lrc::new(codegen_backend), source_map) +} + +// Temporarily have stack size set to 32MB to deal with various crates with long method +// chains or deep syntax trees, except when on Haiku. +// FIXME(oli-obk): get https://github.com/rust-lang/rust/pull/55617 the finish line +#[cfg(not(target_os = "haiku"))] +const STACK_SIZE: usize = 32 * 1024 * 1024; + +#[cfg(target_os = "haiku")] +const STACK_SIZE: usize = 16 * 1024 * 1024; + +fn get_stack_size() -> Option { + // FIXME: Hacks on hacks. If the env is trying to override the stack size + // then *don't* set it explicitly. + if env::var_os("RUST_MIN_STACK").is_none() { + Some(STACK_SIZE) + } else { + None + } +} + +struct Sink(Arc>>); +impl Write for Sink { + fn write(&mut self, data: &[u8]) -> io::Result { + Write::write(&mut *self.0.lock().unwrap(), data) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +#[cfg(not(parallel_compiler))] +pub fn scoped_thread R + Send, R: Send>(cfg: thread::Builder, f: F) -> R { + struct Ptr(*mut ()); + unsafe impl Send for Ptr {} + unsafe impl Sync for Ptr {} + + let mut f = Some(f); + let run = Ptr(&mut f as *mut _ as *mut ()); + let mut result = None; + let result_ptr = Ptr(&mut result as *mut _ as *mut ()); + + let thread = cfg.spawn(move || { + let run = unsafe { (*(run.0 as *mut Option)).take().unwrap() }; + let result = unsafe { &mut *(result_ptr.0 as *mut Option) }; + *result = Some(run()); + }); + + match thread.unwrap().join() { + Ok(()) => result.unwrap(), + Err(p) => panic::resume_unwind(p), + } +} + +#[cfg(not(parallel_compiler))] +pub fn spawn_thread_pool R + Send, R: Send>( + edition: Edition, + _threads: Option, + stderr: &Option>>>, + f: F, +) -> R { + let mut cfg = thread::Builder::new().name("rustc".to_string()); + + if let Some(size) = get_stack_size() { + cfg = cfg.stack_size(size); + } + + scoped_thread(cfg, || { + syntax::with_globals(edition, || { + ty::tls::GCX_PTR.set(&Lock::new(0), || { + if let Some(stderr) = stderr { + io::set_panic(Some(box Sink(stderr.clone()))); + } + ty::tls::with_thread_locals(|| f()) + }) + }) + }) +} + +#[cfg(parallel_compiler)] +pub fn spawn_thread_pool R + Send, R: Send>( + edition: Edition, + threads: Option, + stderr: &Option>>>, + f: F, +) -> R { + use rayon::{ThreadPool, ThreadPoolBuilder}; + use syntax; + use syntax_pos; + + let gcx_ptr = &Lock::new(0); + + let mut config = ThreadPoolBuilder::new() + .acquire_thread_handler(jobserver::acquire_thread) + .release_thread_handler(jobserver::release_thread) + .num_threads(Session::threads_from_count(threads)) + .deadlock_handler(|| unsafe { ty::query::handle_deadlock() }); + + if let Some(size) = get_stack_size() { + config = config.stack_size(size); + } + + let with_pool = move |pool: &ThreadPool| pool.install(move || f()); + + syntax::with_globals(edition, || { + syntax::GLOBALS.with(|syntax_globals| { + syntax_pos::GLOBALS.with(|syntax_pos_globals| { + // The main handler runs for each Rayon worker thread and sets up + // the thread local rustc uses. syntax_globals and syntax_pos_globals are + // captured and set on the new threads. ty::tls::with_thread_locals sets up + // thread local callbacks from libsyntax + let main_handler = move |worker: &mut dyn FnMut()| { + syntax::GLOBALS.set(syntax_globals, || { + syntax_pos::GLOBALS.set(syntax_pos_globals, || { + if let Some(stderr) = stderr { + io::set_panic(Some(box Sink(stderr.clone()))); + } + ty::tls::with_thread_locals(|| { + ty::tls::GCX_PTR.set(gcx_ptr, || worker()) + }) + }) + }) + }; + + ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap() + }) + }) + }) +} + fn load_backend_from_dylib(path: &Path) -> fn() -> Box { let lib = DynamicLibrary::open(Some(path)).unwrap_or_else(|err| { let err = format!("couldn't load codegen backend {:?}: {:?}", path, err); @@ -109,9 +276,6 @@ pub fn get_codegen_backend(sess: &Session) -> Box { let codegen_name = sess.opts.debugging_opts.codegen_backend.as_ref() .unwrap_or(&sess.target.target.options.codegen_backend); let backend = match &codegen_name[..] { - "metadata_only" => { - rustc_codegen_utils::codegen_backend::MetadataOnlyCodegenBackend::boxed - } filename if filename.contains(".") => { load_backend_from_dylib(filename.as_ref()) } @@ -297,7 +461,7 @@ pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box CrateDisambiguator { +pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator { use std::hash::Hasher; // The crate_disambiguator is a 128 bit hash. The disambiguator is fed @@ -338,24 +502,24 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec = attrs .iter() .filter_map(|a| { - if a.check_name("crate_type") { + if a.check_name(sym::crate_type) { match a.value_str() { - Some(ref n) if *n == "rlib" => Some(config::CrateType::Rlib), - Some(ref n) if *n == "dylib" => Some(config::CrateType::Dylib), - Some(ref n) if *n == "cdylib" => Some(config::CrateType::Cdylib), - Some(ref n) if *n == "lib" => Some(config::default_lib_output()), - Some(ref n) if *n == "staticlib" => Some(config::CrateType::Staticlib), - Some(ref n) if *n == "proc-macro" => Some(config::CrateType::ProcMacro), - Some(ref n) if *n == "bin" => Some(config::CrateType::Executable), - Some(ref n) => { + Some(sym::rlib) => Some(config::CrateType::Rlib), + Some(sym::dylib) => Some(config::CrateType::Dylib), + Some(sym::cdylib) => Some(config::CrateType::Cdylib), + Some(sym::lib) => Some(config::default_lib_output()), + Some(sym::staticlib) => Some(config::CrateType::Staticlib), + Some(sym::proc_dash_macro) => Some(config::CrateType::ProcMacro), + Some(sym::bin) => Some(config::CrateType::Executable), + Some(n) => { let crate_types = vec![ - Symbol::intern("rlib"), - Symbol::intern("dylib"), - Symbol::intern("cdylib"), - Symbol::intern("lib"), - Symbol::intern("staticlib"), - Symbol::intern("proc-macro"), - Symbol::intern("bin") + sym::rlib, + sym::dylib, + sym::cdylib, + sym::lib, + sym::staticlib, + sym::proc_dash_macro, + sym::bin ]; if let ast::MetaItemKind::NameValue(spanned) = a.meta().unwrap().node { @@ -557,7 +721,13 @@ impl<'a> ReplaceBodyWithLoop<'a> { _ => None, }); any_involves_impl_trait(types.into_iter()) || - any_involves_impl_trait(data.bindings.iter().map(|b| &b.ty)) + data.constraints.iter().any(|c| { + match c.kind { + ast::AssocTyConstraintKind::Bound { .. } => true, + ast::AssocTyConstraintKind::Equality { ref ty } => + involves_impl_trait(ty), + } + }) }, Some(&ast::GenericArgs::Parenthesized(ref data)) => { any_involves_impl_trait(data.inputs.iter()) || diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 4d484a64f47df..12719c3b9d303 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -21,12 +21,12 @@ //! If you define a new `LateLintPass`, you will also need to add it to the //! `late_lint_methods!` invocation in `lib.rs`. -use rustc::hir::def::Def; +use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::{lint, util}; use hir::Node; -use util::nodemap::NodeSet; +use util::nodemap::HirIdSet; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext}; @@ -36,17 +36,16 @@ use syntax::tokenstream::{TokenTree, TokenStream}; use syntax::ast; use syntax::ptr::P; use syntax::ast::Expr; -use syntax::attr; +use syntax::attr::{self, HasAttrs}; use syntax::source_map::Spanned; use syntax::edition::Edition; use syntax::feature_gate::{AttributeGate, AttributeTemplate, AttributeType}; use syntax::feature_gate::{Stability, deprecated_attributes}; use syntax_pos::{BytePos, Span, SyntaxContext}; -use syntax::symbol::keywords; +use syntax::symbol::{Symbol, kw, sym}; use syntax::errors::{Applicability, DiagnosticBuilder}; use syntax::print::pprust::expr_to_string; use syntax::visit::FnKind; -use syntax::struct_span_err; use rustc::hir::{self, GenericParamKind, PatKind}; @@ -63,18 +62,7 @@ declare_lint! { "suggest using `loop { }` instead of `while true { }`" } -#[derive(Copy, Clone)] -pub struct WhileTrue; - -impl LintPass for WhileTrue { - fn name(&self) -> &'static str { - "WhileTrue" - } - - fn get_lints(&self) -> LintArray { - lint_array!(WHILE_TRUE) - } -} +declare_lint_pass!(WhileTrue => [WHILE_TRUE]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for WhileTrue { fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr) { @@ -105,11 +93,10 @@ declare_lint! { "use of owned (Box type) heap memory" } -#[derive(Copy, Clone)] -pub struct BoxPointers; +declare_lint_pass!(BoxPointers => [BOX_POINTERS]); impl BoxPointers { - fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'_, '_>, span: Span, ty: Ty<'_>) { + fn check_heap_type(&self, cx: &LateContext<'_, '_>, span: Span, ty: Ty<'_>) { for leaf_ty in ty.walk() { if leaf_ty.is_box() { let m = format!("type uses owned (Box type) pointers: {}", ty); @@ -119,16 +106,6 @@ impl BoxPointers { } } -impl LintPass for BoxPointers { - fn name(&self) -> &'static str { - "BoxPointers" - } - - fn get_lints(&self) -> LintArray { - lint_array!(BOX_POINTERS) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { match it.node { @@ -137,7 +114,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers { hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { - let def_id = cx.tcx.hir().local_def_id(it.id); + let def_id = cx.tcx.hir().local_def_id_from_hir_id(it.hir_id); self.check_heap_type(cx, it.span, cx.tcx.type_of(def_id)) } _ => () @@ -148,7 +125,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers { hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { for struct_field in struct_def.fields() { - let def_id = cx.tcx.hir().local_def_id(struct_field.id); + let def_id = cx.tcx.hir().local_def_id_from_hir_id(struct_field.hir_id); self.check_heap_type(cx, struct_field.span, cx.tcx.type_of(def_id)); } @@ -169,36 +146,25 @@ declare_lint! { "using `Struct { x: x }` instead of `Struct { x }` in a pattern" } -#[derive(Copy, Clone)] -pub struct NonShorthandFieldPatterns; - -impl LintPass for NonShorthandFieldPatterns { - fn name(&self) -> &'static str { - "NonShorthandFieldPatterns" - } - - fn get_lints(&self) -> LintArray { - lint_array!(NON_SHORTHAND_FIELD_PATTERNS) - } -} +declare_lint_pass!(NonShorthandFieldPatterns => [NON_SHORTHAND_FIELD_PATTERNS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns { fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat) { if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.node { let variant = cx.tables.pat_ty(pat).ty_adt_def() .expect("struct pattern type is not an ADT") - .variant_of_def(cx.tables.qpath_def(qpath, pat.hir_id)); + .variant_of_res(cx.tables.qpath_res(qpath, pat.hir_id)); for fieldpat in field_pats { if fieldpat.node.is_shorthand { continue; } - if fieldpat.span.ctxt().outer().expn_info().is_some() { + if fieldpat.span.ctxt().outer_expn_info().is_some() { // Don't lint if this is a macro expansion: macro authors // shouldn't have to worry about this kind of style issue // (Issue #49588) continue; } - if let PatKind::Binding(_, _, _, ident, None) = fieldpat.node.pat.node { + if let PatKind::Binding(_, _, ident, None) = fieldpat.node.pat.node { if cx.tcx.find_field_index(ident, &variant) == Some(cx.tcx.field_index(fieldpat.node.hir_id, cx.tables)) { let mut err = cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, @@ -226,22 +192,11 @@ declare_lint! { "usage of `unsafe` code" } -#[derive(Copy, Clone)] -pub struct UnsafeCode; - -impl LintPass for UnsafeCode { - fn name(&self) -> &'static str { - "UnsafeCode" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNSAFE_CODE) - } -} +declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]); impl UnsafeCode { fn report_unsafe(&self, cx: &EarlyContext<'_>, span: Span, desc: &'static str) { - // This comes from a macro that has #[allow_internal_unsafe]. + // This comes from a macro that has `#[allow_internal_unsafe]`. if span.allows_unsafe() { return; } @@ -252,7 +207,7 @@ impl UnsafeCode { impl EarlyLintPass for UnsafeCode { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { - if attr.check_name("allow_internal_unsafe") { + if attr.check_name(sym::allow_internal_unsafe) { self.report_unsafe(cx, attr.span, "`allow_internal_unsafe` allows defining \ macros using unsafe without triggering \ the `unsafe_code` lint at their call site"); @@ -261,7 +216,7 @@ impl EarlyLintPass for UnsafeCode { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { if let ast::ExprKind::Block(ref blk, _) = e.node { - // Don't warn about generated blocks, that'll just pollute the output. + // Don't warn about generated blocks; that'll just pollute the output. if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) { self.report_unsafe(cx, blk.span, "usage of an `unsafe` block"); } @@ -327,8 +282,10 @@ pub struct MissingDoc { private_traits: FxHashSet, } +impl_lint_pass!(MissingDoc => [MISSING_DOCS]); + fn has_doc(attr: &ast::Attribute) -> bool { - if !attr.check_name("doc") { + if !attr.check_name(sym::doc) { return false; } @@ -338,7 +295,7 @@ fn has_doc(attr: &ast::Attribute) -> bool { if let Some(list) = attr.meta_item_list() { for meta in list { - if meta.check_name("include") || meta.check_name("hidden") { + if meta.check_name(sym::include) || meta.check_name(sym::hidden) { return true; } } @@ -378,10 +335,9 @@ impl MissingDoc { // Only check publicly-visible items, using the result from the privacy pass. // It's an option so the crate root can also use this function (it doesn't - // have a NodeId). + // have a `NodeId`). if let Some(id) = id { - let node_id = cx.tcx.hir().hir_to_node_id(id); - if !cx.access_levels.is_exported(node_id) { + if !cx.access_levels.is_exported(id) { return; } } @@ -395,24 +351,14 @@ impl MissingDoc { } } -impl LintPass for MissingDoc { - fn name(&self) -> &'static str { - "MissingDoc" - } - - fn get_lints(&self) -> LintArray { - lint_array!(MISSING_DOCS) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { fn enter_lint_attrs(&mut self, _: &LateContext<'_, '_>, attrs: &[ast::Attribute]) { let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { - attr.check_name("doc") && + attr.check_name(sym::doc) && match attr.meta_item_list() { None => false, - Some(l) => attr::list_contains_name(&l, "hidden"), + Some(l) => attr::list_contains_name(&l, sym::hidden), } }); self.doc_hidden_stack.push(doc_hidden); @@ -443,12 +389,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { hir::ItemKind::Struct(..) => "a struct", hir::ItemKind::Union(..) => "a union", hir::ItemKind::Trait(.., ref trait_item_refs) => { - // Issue #11592, traits are always considered exported, even when private. + // Issue #11592: traits are always considered exported, even when private. if let hir::VisibilityKind::Inherited = it.vis.node { self.private_traits.insert(it.hir_id); for trait_item_ref in trait_item_refs { - let hir_id = cx.tcx.hir().node_to_hir_id(trait_item_ref.id.node_id); - self.private_traits.insert(hir_id); + self.private_traits.insert(trait_item_ref.id.hir_id); } return; } @@ -456,17 +401,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { } hir::ItemKind::Ty(..) => "a type alias", hir::ItemKind::Impl(.., Some(ref trait_ref), _, ref impl_item_refs) => { - // If the trait is private, add the impl items to private_traits so they don't get + // If the trait is private, add the impl items to `private_traits` so they don't get // reported for missing docs. - let real_trait = trait_ref.path.def.def_id(); - if let Some(node_id) = cx.tcx.hir().as_local_node_id(real_trait) { - match cx.tcx.hir().find(node_id) { + let real_trait = trait_ref.path.res.def_id(); + if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(real_trait) { + match cx.tcx.hir().find(hir_id) { Some(Node::Item(item)) => { if let hir::VisibilityKind::Inherited = item.vis.node { for impl_item_ref in impl_item_refs { - let hir_id = cx.tcx.hir().node_to_hir_id( - impl_item_ref.id.node_id); - self.private_traits.insert(hir_id); + self.private_traits.insert(impl_item_ref.id.hir_id); } } } @@ -532,7 +475,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant, _: &hir::Generics) { self.check_missing_docs_attrs(cx, - Some(v.node.data.hir_id()), + Some(v.node.id), &v.node.attrs, v.span, "a variant"); @@ -545,22 +488,11 @@ declare_lint! { "detects potentially-forgotten implementations of `Copy`" } -#[derive(Copy, Clone)] -pub struct MissingCopyImplementations; - -impl LintPass for MissingCopyImplementations { - fn name(&self) -> &'static str { - "MissingCopyImplementations" - } - - fn get_lints(&self) -> LintArray { - lint_array!(MISSING_COPY_IMPLEMENTATIONS) - } -} +declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) { - if !cx.access_levels.is_reachable(item.id) { + if !cx.access_levels.is_reachable(item.hir_id) { return; } let (def, ty) = match item.node { @@ -568,21 +500,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { if !ast_generics.params.is_empty() { return; } - let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.id)); + let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id_from_hir_id(item.hir_id)); (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } hir::ItemKind::Union(_, ref ast_generics) => { if !ast_generics.params.is_empty() { return; } - let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.id)); + let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id_from_hir_id(item.hir_id)); (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } hir::ItemKind::Enum(_, ref ast_generics) => { if !ast_generics.params.is_empty() { return; } - let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.id)); + let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id_from_hir_id(item.hir_id)); (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } _ => return, @@ -609,29 +541,16 @@ declare_lint! { "detects missing implementations of fmt::Debug" } +#[derive(Default)] pub struct MissingDebugImplementations { - impling_types: Option, + impling_types: Option, } -impl MissingDebugImplementations { - pub fn new() -> MissingDebugImplementations { - MissingDebugImplementations { impling_types: None } - } -} - -impl LintPass for MissingDebugImplementations { - fn name(&self) -> &'static str { - "MissingDebugImplementations" - } - - fn get_lints(&self) -> LintArray { - lint_array!(MISSING_DEBUG_IMPLEMENTATIONS) - } -} +impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations { fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) { - if !cx.access_levels.is_reachable(item.id) { + if !cx.access_levels.is_reachable(item.hir_id) { return; } @@ -648,11 +567,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations { }; if self.impling_types.is_none() { - let mut impls = NodeSet::default(); + let mut impls = HirIdSet::default(); cx.tcx.for_each_impl(debug, |d| { if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() { - if let Some(node_id) = cx.tcx.hir().as_local_node_id(ty_def.did) { - impls.insert(node_id); + if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(ty_def.did) { + impls.insert(hir_id); } } }); @@ -661,7 +580,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations { debug!("{:?}", self.impling_types); } - if !self.impling_types.as_ref().unwrap().contains(&item.id) { + if !self.impling_types.as_ref().unwrap().contains(&item.hir_id) { cx.span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, "type does not implement `fmt::Debug`; consider adding #[derive(Debug)] \ @@ -676,19 +595,10 @@ declare_lint! { "detects anonymous parameters" } -/// Checks for use of anonymous parameters (RFC 1685). -#[derive(Copy, Clone)] -pub struct AnonymousParameters; - -impl LintPass for AnonymousParameters { - fn name(&self) -> &'static str { - "AnonymousParameters" - } - - fn get_lints(&self) -> LintArray { - lint_array!(ANONYMOUS_PARAMETERS) - } -} +declare_lint_pass!( + /// Checks for use of anonymous parameters (RFC 1685). + AnonymousParameters => [ANONYMOUS_PARAMETERS] +); impl EarlyLintPass for AnonymousParameters { fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::TraitItem) { @@ -697,7 +607,7 @@ impl EarlyLintPass for AnonymousParameters { for arg in sig.decl.inputs.iter() { match arg.pat.node { ast::PatKind::Ident(_, ident, None) => { - if ident.name == keywords::Invalid.name() { + if ident.name == kw::Invalid { let ty_snip = cx .sess .source_map() @@ -737,9 +647,11 @@ impl EarlyLintPass for AnonymousParameters { pub struct DeprecatedAttr { // This is not free to compute, so we want to keep it around, rather than // compute it for every attribute. - depr_attrs: Vec<&'static (&'static str, AttributeType, AttributeTemplate, AttributeGate)>, + depr_attrs: Vec<&'static (Symbol, AttributeType, AttributeTemplate, AttributeGate)>, } +impl_lint_pass!(DeprecatedAttr => []); + impl DeprecatedAttr { pub fn new() -> DeprecatedAttr { DeprecatedAttr { @@ -748,20 +660,10 @@ impl DeprecatedAttr { } } -impl LintPass for DeprecatedAttr { - fn name(&self) -> &'static str { - "DeprecatedAttr" - } - - fn get_lints(&self) -> LintArray { - lint_array!() - } -} - impl EarlyLintPass for DeprecatedAttr { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { for &&(n, _, _, ref g) in &self.depr_attrs { - if attr.name() == n { + if attr.ident().map(|ident| ident.name) == Some(n) { if let &AttributeGate::Gated(Stability::Deprecated(link, suggestion), ref name, ref reason, @@ -789,41 +691,84 @@ declare_lint! { "detects doc comments that aren't used by rustdoc" } -#[derive(Copy, Clone)] -pub struct UnusedDocComment; +declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]); -impl LintPass for UnusedDocComment { - fn name(&self) -> &'static str { - "UnusedDocComment" - } +impl UnusedDocComment { + fn warn_if_doc( + &self, + cx: &EarlyContext<'_>, + node_span: Span, + node_kind: &str, + is_macro_expansion: bool, + attrs: &[ast::Attribute] + ) { + let mut attrs = attrs.into_iter().peekable(); + + // Accumulate a single span for sugared doc comments. + let mut sugared_span: Option = None; + + while let Some(attr) = attrs.next() { + if attr.is_sugared_doc { + sugared_span = Some( + sugared_span.map_or_else( + || attr.span, + |span| span.with_hi(attr.span.hi()), + ), + ); + } - fn get_lints(&self) -> LintArray { - lint_array![UNUSED_DOC_COMMENTS] - } -} + if attrs.peek().map(|next_attr| next_attr.is_sugared_doc).unwrap_or_default() { + continue; + } -impl UnusedDocComment { - fn warn_if_doc<'a, 'tcx, - I: Iterator, - C: LintContext<'tcx>>(&self, mut attrs: I, cx: &C) { - if let Some(attr) = attrs.find(|a| a.is_value_str() && a.check_name("doc")) { - cx.struct_span_lint(UNUSED_DOC_COMMENTS, attr.span, "doc comment not used by rustdoc") - .emit(); + let span = sugared_span.take().unwrap_or_else(|| attr.span); + + if attr.check_name(sym::doc) { + let mut err = cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, "unused doc comment"); + + err.span_label( + node_span, + format!("rustdoc does not generate documentation for {}", node_kind) + ); + + if is_macro_expansion { + err.help("to document an item produced by a macro, \ + the macro must produce the documentation as part of its expansion"); + } + + err.emit(); + } } } } impl EarlyLintPass for UnusedDocComment { - fn check_local(&mut self, cx: &EarlyContext<'_>, decl: &ast::Local) { - self.warn_if_doc(decl.attrs.iter(), cx); + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { + if let ast::ItemKind::Mac(..) = item.node { + self.warn_if_doc(cx, item.span, "macro expansions", true, &item.attrs); + } + } + + fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) { + let (kind, is_macro_expansion) = match stmt.node { + ast::StmtKind::Local(..) => ("statements", false), + ast::StmtKind::Item(..) => ("inner items", false), + ast::StmtKind::Mac(..) => ("macro expansions", true), + // expressions will be reported by `check_expr`. + ast::StmtKind::Semi(..) | + ast::StmtKind::Expr(..) => return, + }; + + self.warn_if_doc(cx, stmt.span, kind, is_macro_expansion, stmt.node.attrs()); } fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) { - self.warn_if_doc(arm.attrs.iter(), cx); + let arm_span = arm.pats[0].span.with_hi(arm.body.span.hi()); + self.warn_if_doc(cx, arm_span, "match arms", false, &arm.attrs); } fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { - self.warn_if_doc(expr.attrs.iter(), cx); + self.warn_if_doc(cx, expr.span, "expressions", false, &expr.attrs); } } @@ -833,18 +778,7 @@ declare_lint! { "compiler plugin used as ordinary library in non-plugin crate" } -#[derive(Copy, Clone)] -pub struct PluginAsLibrary; - -impl LintPass for PluginAsLibrary { - fn name(&self) -> &'static str { - "PluginAsLibrary" - } - - fn get_lints(&self) -> LintArray { - lint_array![PLUGIN_AS_LIBRARY] - } -} +declare_lint_pass!(PluginAsLibrary => [PLUGIN_AS_LIBRARY]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PluginAsLibrary { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { @@ -858,7 +792,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PluginAsLibrary { _ => return, }; - let def_id = cx.tcx.hir().local_def_id(it.id); + let def_id = cx.tcx.hir().local_def_id_from_hir_id(it.hir_id); let prfn = match cx.tcx.extern_mod_stmt_cnum(def_id) { Some(cnum) => cx.tcx.plugin_registrar_fn(cnum), None => { @@ -889,25 +823,13 @@ declare_lint! { "generic items must be mangled" } -#[derive(Copy, Clone)] -pub struct InvalidNoMangleItems; - -impl LintPass for InvalidNoMangleItems { - fn name(&self) -> &'static str { - "InvalidNoMangleItems" - } - - fn get_lints(&self) -> LintArray { - lint_array!(NO_MANGLE_CONST_ITEMS, - NO_MANGLE_GENERIC_ITEMS) - } -} +declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { match it.node { hir::ItemKind::Fn(.., ref generics, _) => { - if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, "no_mangle") { + if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { for param in &generics.params { match param.kind { GenericParamKind::Lifetime { .. } => {} @@ -934,7 +856,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { } } hir::ItemKind::Const(..) => { - if attr::contains_name(&it.attrs, "no_mangle") { + if attr::contains_name(&it.attrs, sym::no_mangle) { // Const items do not refer to a particular location in memory, and therefore // don't have anything to attach a symbol to let msg = "const items should never be #[no_mangle]"; @@ -960,24 +882,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { } } -#[derive(Clone, Copy)] -pub struct MutableTransmutes; - declare_lint! { MUTABLE_TRANSMUTES, Deny, "mutating transmuted &mut T from &T may cause undefined behavior" } -impl LintPass for MutableTransmutes { - fn name(&self) -> &'static str { - "MutableTransmutes" - } - - fn get_lints(&self) -> LintArray { - lint_array!(MUTABLE_TRANSMUTES) - } -} +declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &hir::Expr) { @@ -985,7 +896,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \ consider instead using an UnsafeCell"; - match get_transmute_from_to(cx, expr) { + match get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (&ty1.sty, &ty2.sty)) { Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) => { if to_mt == hir::Mutability::MutMutable && from_mt == hir::Mutability::MutImmutable { @@ -998,54 +909,45 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { fn get_transmute_from_to<'a, 'tcx> (cx: &LateContext<'a, 'tcx>, expr: &hir::Expr) - -> Option<(&'tcx ty::TyKind<'tcx>, &'tcx ty::TyKind<'tcx>)> { + -> Option<(Ty<'tcx>, Ty<'tcx>)> { let def = if let hir::ExprKind::Path(ref qpath) = expr.node { - cx.tables.qpath_def(qpath, expr.hir_id) + cx.tables.qpath_res(qpath, expr.hir_id) } else { return None; }; - if let Def::Fn(did) = def { + if let Res::Def(DefKind::Fn, did) = def { if !def_id_is_transmute(cx, did) { return None; } let sig = cx.tables.node_type(expr.hir_id).fn_sig(cx.tcx); let from = sig.inputs().skip_binder()[0]; let to = *sig.output().skip_binder(); - return Some((&from.sty, &to.sty)); + return Some((from, to)); } None } fn def_id_is_transmute(cx: &LateContext<'_, '_>, def_id: DefId) -> bool { cx.tcx.fn_sig(def_id).abi() == RustIntrinsic && - cx.tcx.item_name(def_id) == "transmute" + cx.tcx.item_name(def_id) == sym::transmute } } } -/// Forbids using the `#[feature(...)]` attribute -#[derive(Copy, Clone)] -pub struct UnstableFeatures; - declare_lint! { UNSTABLE_FEATURES, Allow, "enabling unstable features (deprecated. do not use)" } -impl LintPass for UnstableFeatures { - fn name(&self) -> &'static str { - "UnstableFeatures" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNSTABLE_FEATURES) - } -} +declare_lint_pass!( + /// Forbids using the `#[feature(...)]` attribute + UnstableFeatures => [UNSTABLE_FEATURES] +); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures { fn check_attribute(&mut self, ctx: &LateContext<'_, '_>, attr: &ast::Attribute) { - if attr.check_name("feature") { + if attr.check_name(sym::feature) { if let Some(items) = attr.meta_item_list() { for item in items { ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature"); @@ -1055,30 +957,23 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures { } } -/// Lint for unions that contain fields with possibly non-trivial destructors. -pub struct UnionsWithDropFields; - declare_lint! { UNIONS_WITH_DROP_FIELDS, Warn, "use of unions that contain fields with possibly non-trivial drop code" } -impl LintPass for UnionsWithDropFields { - fn name(&self) -> &'static str { - "UnionsWithDropFields" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNIONS_WITH_DROP_FIELDS) - } -} +declare_lint_pass!( + /// Lint for unions that contain fields with possibly non-trivial destructors. + UnionsWithDropFields => [UNIONS_WITH_DROP_FIELDS] +); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { fn check_item(&mut self, ctx: &LateContext<'_, '_>, item: &hir::Item) { if let hir::ItemKind::Union(ref vdata, _) = item.node { for field in vdata.fields() { - let field_ty = ctx.tcx.type_of(ctx.tcx.hir().local_def_id(field.id)); + let field_ty = ctx.tcx.type_of( + ctx.tcx.hir().local_def_id_from_hir_id(field.hir_id)); if field_ty.needs_drop(ctx.tcx, ctx.param_env) { ctx.span_lint(UNIONS_WITH_DROP_FIELDS, field.span, @@ -1091,34 +986,24 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { } } -/// Lint for items marked `pub` that aren't reachable from other crates. -#[derive(Copy, Clone)] -pub struct UnreachablePub; - declare_lint! { pub UNREACHABLE_PUB, Allow, "`pub` items not reachable from crate root" } -impl LintPass for UnreachablePub { - fn name(&self) -> &'static str { - "UnreachablePub" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNREACHABLE_PUB) - } -} +declare_lint_pass!( + /// Lint for items marked `pub` that aren't reachable from other crates. + UnreachablePub => [UNREACHABLE_PUB] +); impl UnreachablePub { fn perform_lint(&self, cx: &LateContext<'_, '_>, what: &str, id: hir::HirId, vis: &hir::Visibility, span: Span, exportable: bool) { let mut applicability = Applicability::MachineApplicable; - let node_id = cx.tcx.hir().hir_to_node_id(id); match vis.node { - hir::VisibilityKind::Public if !cx.access_levels.is_reachable(node_id) => { - if span.ctxt().outer().expn_info().is_some() { + hir::VisibilityKind::Public if !cx.access_levels.is_reachable(id) => { + if span.ctxt().outer_expn_info().is_some() { applicability = Applicability::MaybeIncorrect; } let def_span = cx.tcx.sess.source_map().def_span(span); @@ -1146,7 +1031,6 @@ impl UnreachablePub { } } - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub { fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) { self.perform_lint(cx, "item", item.hir_id, &item.vis, item.span, true); @@ -1166,27 +1050,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub { } } -/// Lint for trait and lifetime bounds in type aliases being mostly ignored. -/// They are relevant when using associated types, but otherwise neither checked -/// at definition site nor enforced at use site. - -pub struct TypeAliasBounds; - declare_lint! { TYPE_ALIAS_BOUNDS, Warn, "bounds in type aliases are not enforced" } -impl LintPass for TypeAliasBounds { - fn name(&self) -> &'static str { - "TypeAliasBounds" - } - - fn get_lints(&self) -> LintArray { - lint_array!(TYPE_ALIAS_BOUNDS) - } -} +declare_lint_pass!( + /// Lint for trait and lifetime bounds in type aliases being mostly ignored. + /// They are relevant when using associated types, but otherwise neither checked + /// at definition site nor enforced at use site. + TypeAliasBounds => [TYPE_ALIAS_BOUNDS] +); impl TypeAliasBounds { fn is_type_variable_assoc(qpath: &hir::QPath) -> bool { @@ -1195,8 +1070,8 @@ impl TypeAliasBounds { // If this is a type variable, we found a `T::Assoc`. match ty.node { hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { - match path.def { - Def::TyParam(_) => true, + match path.res { + Res::Def(DefKind::TyParam, _) => true, _ => false } } @@ -1213,7 +1088,7 @@ impl TypeAliasBounds { // We use a HIR visitor to walk the type. use rustc::hir::intravisit::{self, Visitor}; - struct WalkAssocTypes<'a, 'db> where 'db: 'a { + struct WalkAssocTypes<'a, 'db> { err: &'a mut DiagnosticBuilder<'db> } impl<'a, 'db, 'v> Visitor<'v> for WalkAssocTypes<'a, 'db> { @@ -1280,25 +1155,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeAliasBounds { } } -/// Lint constants that are erroneous. -/// Without this lint, we might not get any diagnostic if the constant is -/// unused within this crate, even though downstream crates can't use it -/// without producing an error. -pub struct UnusedBrokenConst; - -impl LintPass for UnusedBrokenConst { - fn name(&self) -> &'static str { - "UnusedBrokenConst" - } +declare_lint_pass!( + /// Lint constants that are erroneous. + /// Without this lint, we might not get any diagnostic if the constant is + /// unused within this crate, even though downstream crates can't use it + /// without producing an error. + UnusedBrokenConst => [] +); - fn get_lints(&self) -> LintArray { - lint_array!() - } -} fn check_const(cx: &LateContext<'_, '_>, body_id: hir::BodyId) { let def_id = cx.tcx.hir().body_owner_def_id(body_id); - let is_static = cx.tcx.is_static(def_id).is_some(); - let param_env = if is_static { + let param_env = if cx.tcx.is_static(def_id) { // Use the same param_env as `codegen_static_initializer`, to reuse the cache. ty::ParamEnv::reveal_all() } else { @@ -1309,6 +1176,7 @@ fn check_const(cx: &LateContext<'_, '_>, body_id: hir::BodyId) { promoted: None }; // trigger the query once for all constants since that will already report the errors + // FIXME: Use ensure here let _ = cx.tcx.const_eval(param_env.and(cid)); } @@ -1326,25 +1194,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst { } } -/// Lint for trait and lifetime bounds that don't depend on type parameters -/// which either do nothing, or stop the item from being used. -pub struct TrivialConstraints; - declare_lint! { TRIVIAL_BOUNDS, Warn, "these bounds don't depend on an type parameters" } -impl LintPass for TrivialConstraints { - fn name(&self) -> &'static str { - "TrivialConstraints" - } - - fn get_lints(&self) -> LintArray { - lint_array!(TRIVIAL_BOUNDS) - } -} +declare_lint_pass!( + /// Lint for trait and lifetime bounds that don't depend on type parameters + /// which either do nothing, or stop the item from being used. + TrivialConstraints => [TRIVIAL_BOUNDS] +); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { fn check_item( @@ -1355,9 +1215,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { use rustc::ty::fold::TypeFoldable; use rustc::ty::Predicate::*; - if cx.tcx.features().trivial_bounds { - let def_id = cx.tcx.hir().local_def_id(item.id); + let def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id); let predicates = cx.tcx.predicates_of(def_id); for &(predicate, span) in &predicates.predicates { let predicate_kind_name = match predicate { @@ -1388,62 +1247,53 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { } } - -/// Does nothing as a lint pass, but registers some `Lint`s -/// which are used by other parts of the compiler. -#[derive(Copy, Clone)] -pub struct SoftLints; - -impl LintPass for SoftLints { - fn name(&self) -> &'static str { - "SoftLints" - } - - fn get_lints(&self) -> LintArray { - lint_array!( - WHILE_TRUE, - BOX_POINTERS, - NON_SHORTHAND_FIELD_PATTERNS, - UNSAFE_CODE, - MISSING_DOCS, - MISSING_COPY_IMPLEMENTATIONS, - MISSING_DEBUG_IMPLEMENTATIONS, - ANONYMOUS_PARAMETERS, - UNUSED_DOC_COMMENTS, - PLUGIN_AS_LIBRARY, - NO_MANGLE_CONST_ITEMS, - NO_MANGLE_GENERIC_ITEMS, - MUTABLE_TRANSMUTES, - UNSTABLE_FEATURES, - UNIONS_WITH_DROP_FIELDS, - UNREACHABLE_PUB, - TYPE_ALIAS_BOUNDS, - TRIVIAL_BOUNDS - ) - } -} +declare_lint_pass!( + /// Does nothing as a lint pass, but registers some `Lint`s + /// which are used by other parts of the compiler. + SoftLints => [ + WHILE_TRUE, + BOX_POINTERS, + NON_SHORTHAND_FIELD_PATTERNS, + UNSAFE_CODE, + MISSING_DOCS, + MISSING_COPY_IMPLEMENTATIONS, + MISSING_DEBUG_IMPLEMENTATIONS, + ANONYMOUS_PARAMETERS, + UNUSED_DOC_COMMENTS, + PLUGIN_AS_LIBRARY, + NO_MANGLE_CONST_ITEMS, + NO_MANGLE_GENERIC_ITEMS, + MUTABLE_TRANSMUTES, + UNSTABLE_FEATURES, + UNIONS_WITH_DROP_FIELDS, + UNREACHABLE_PUB, + TYPE_ALIAS_BOUNDS, + TRIVIAL_BOUNDS + ] +); declare_lint! { pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, - Allow, + Warn, "`...` range patterns are deprecated" } - -pub struct EllipsisInclusiveRangePatterns; - -impl LintPass for EllipsisInclusiveRangePatterns { - fn name(&self) -> &'static str { - "EllipsisInclusiveRangePatterns" - } - - fn get_lints(&self) -> LintArray { - lint_array!(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS) - } +#[derive(Default)] +pub struct EllipsisInclusiveRangePatterns { + /// If `Some(_)`, suppress all subsequent pattern + /// warnings for better diagnostics. + node_id: Option, } +impl_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]); + impl EarlyLintPass for EllipsisInclusiveRangePatterns { - fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat, visit_subpats: &mut bool) { + fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) { + if self.node_id.is_some() { + // Don't recursively warn about patterns inside range endpoints. + return + } + use self::ast::{PatKind, RangeEnd, RangeSyntax::DotDotDot}; /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span @@ -1466,7 +1316,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { let msg = "`...` range patterns are deprecated"; let suggestion = "use `..=` for an inclusive range"; if parenthesise { - *visit_subpats = false; + self.node_id = Some(pat.id); let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg); err.span_suggestion( pat.span, @@ -1487,6 +1337,14 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { }; } } + + fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) { + if let Some(node_id) = self.node_id { + if pat.id == node_id { + self.node_id = None + } + } + } } declare_lint! { @@ -1497,41 +1355,33 @@ declare_lint! { } pub struct UnnameableTestItems { - boundary: ast::NodeId, // NodeId of the item under which things are not nameable + boundary: hir::HirId, // HirId of the item under which things are not nameable items_nameable: bool, } +impl_lint_pass!(UnnameableTestItems => [UNNAMEABLE_TEST_ITEMS]); + impl UnnameableTestItems { pub fn new() -> Self { Self { - boundary: ast::DUMMY_NODE_ID, + boundary: hir::DUMMY_HIR_ID, items_nameable: true } } } -impl LintPass for UnnameableTestItems { - fn name(&self) -> &'static str { - "UnnameableTestItems" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNNAMEABLE_TEST_ITEMS) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestItems { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { if self.items_nameable { if let hir::ItemKind::Mod(..) = it.node {} else { self.items_nameable = false; - self.boundary = it.id; + self.boundary = it.hir_id; } return; } - if let Some(attr) = attr::find_by_name(&it.attrs, "rustc_test_marker") { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::rustc_test_marker) { cx.struct_span_lint( UNNAMEABLE_TEST_ITEMS, attr.span, @@ -1541,7 +1391,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestItems { } fn check_item_post(&mut self, _cx: &LateContext<'_, '_>, it: &hir::Item) { - if !self.items_nameable && self.boundary == it.id { + if !self.items_nameable && self.boundary == it.hir_id { self.items_nameable = true; } } @@ -1553,33 +1403,20 @@ declare_lint! { "detects edition keywords being used as an identifier" } -/// Check for uses of edition keywords used as an identifier. -#[derive(Copy, Clone)] -pub struct KeywordIdents; - -impl LintPass for KeywordIdents { - fn name(&self) -> &'static str { - "KeywordIdents" - } +declare_lint_pass!( + /// Check for uses of edition keywords used as an identifier. + KeywordIdents => [KEYWORD_IDENTS] +); - fn get_lints(&self) -> LintArray { - lint_array!(KEYWORD_IDENTS) - } -} +struct UnderMacro(bool); impl KeywordIdents { fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: TokenStream) { for tt in tokens.into_trees() { match tt { - TokenTree::Token(span, tok) => match tok.ident() { - // only report non-raw idents - Some((ident, false)) => { - self.check_ident(cx, ast::Ident { - span: span.substitute_dummy(ident.span), - ..ident - }); - } - _ => {}, + // Only report non-raw idents. + TokenTree::Token(token) => if let Some((ident, false)) = token.ident() { + self.check_ident_token(cx, UnderMacro(true), ident); } TokenTree::Delimited(_, _, tts) => { self.check_tokens(cx, tts) @@ -1587,62 +1424,41 @@ impl KeywordIdents { } } } -} -impl EarlyLintPass for KeywordIdents { - fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef, _id: ast::NodeId) { - self.check_tokens(cx, mac_def.stream()); - } - fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::Mac) { - self.check_tokens(cx, mac.node.tts.clone().into()); - } - fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) { - let ident_str = &ident.as_str()[..]; - let cur_edition = cx.sess.edition(); - let is_raw_ident = |ident: ast::Ident| { - cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) - }; - let next_edition = match cur_edition { + fn check_ident_token(&mut self, + cx: &EarlyContext<'_>, + UnderMacro(under_macro): UnderMacro, + ident: ast::Ident) + { + let next_edition = match cx.sess.edition() { Edition::Edition2015 => { - match ident_str { - "async" | "try" | "dyn" => Edition::Edition2018, - // Only issue warnings for `await` if the `async_await` - // feature isn't being used. Otherwise, users need - // to keep using `await` for the macro exposed by std. - "await" if !cx.sess.features_untracked().async_await => Edition::Edition2018, + match ident.name { + kw::Async | kw::Await | kw::Try => Edition::Edition2018, + + // rust-lang/rust#56327: Conservatively do not + // attempt to report occurrences of `dyn` within + // macro definitions or invocations, because `dyn` + // can legitimately occur as a contextual keyword + // in 2015 code denoting its 2018 meaning, and we + // do not want rustfix to inject bugs into working + // code by rewriting such occurrences. + // + // But if we see `dyn` outside of a macro, we know + // its precise role in the parsed AST and thus are + // assured this is truly an attempt to use it as + // an identifier. + kw::Dyn if !under_macro => Edition::Edition2018, + _ => return, } } // There are no new keywords yet for the 2018 edition and beyond. - // However, `await` is a "false" keyword in the 2018 edition, - // and can only be used if the `async_await` feature is enabled. - // Otherwise, we emit an error. - _ => { - if "await" == ident_str - && !cx.sess.features_untracked().async_await - && !is_raw_ident(ident) - { - let mut err = struct_span_err!( - cx.sess, - ident.span, - E0721, - "`await` is a keyword in the {} edition", cur_edition, - ); - err.span_suggestion( - ident.span, - "you can use a raw identifier to stay compatible", - "r#await".to_string(), - Applicability::MachineApplicable, - ); - err.emit(); - } - return - }, + _ => return, }; - // don't lint `r#foo` - if is_raw_ident(ident) { + // Don't lint `r#foo`. + if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) { return; } @@ -1663,72 +1479,122 @@ impl EarlyLintPass for KeywordIdents { } } +impl EarlyLintPass for KeywordIdents { + fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef, _id: ast::NodeId) { + self.check_tokens(cx, mac_def.stream()); + } + fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::Mac) { + self.check_tokens(cx, mac.node.tts.clone().into()); + } + fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) { + self.check_ident_token(cx, UnderMacro(false), ident); + } +} -pub struct ExplicitOutlivesRequirements; +declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMENTS]); -impl LintPass for ExplicitOutlivesRequirements { - fn name(&self) -> &'static str { - "ExplicitOutlivesRequirements" +impl ExplicitOutlivesRequirements { + fn lifetimes_outliving_lifetime<'tcx>( + inferred_outlives: &'tcx [ty::Predicate<'tcx>], + index: u32, + ) -> Vec> { + inferred_outlives.iter().filter_map(|pred| { + match pred { + ty::Predicate::RegionOutlives(outlives) => { + let outlives = outlives.skip_binder(); + match outlives.0 { + ty::ReEarlyBound(ebr) if ebr.index == index => { + Some(outlives.1) + } + _ => None, + } + } + _ => None + } + }).collect() + } + + fn lifetimes_outliving_type<'tcx>( + inferred_outlives: &'tcx [ty::Predicate<'tcx>], + index: u32, + ) -> Vec> { + inferred_outlives.iter().filter_map(|pred| { + match pred { + ty::Predicate::TypeOutlives(outlives) => { + let outlives = outlives.skip_binder(); + if outlives.0.is_param(index) { + Some(outlives.1) + } else { + None + } + } + _ => None + } + }).collect() } - fn get_lints(&self) -> LintArray { - lint_array![EXPLICIT_OUTLIVES_REQUIREMENTS] + fn collect_outlived_lifetimes<'tcx>( + &self, + param: &'tcx hir::GenericParam, + tcx: TyCtxt<'tcx>, + inferred_outlives: &'tcx [ty::Predicate<'tcx>], + ty_generics: &'tcx ty::Generics, + ) -> Vec> { + let index = ty_generics.param_def_id_to_index[ + &tcx.hir().local_def_id_from_hir_id(param.hir_id)]; + + match param.kind { + hir::GenericParamKind::Lifetime { .. } => { + Self::lifetimes_outliving_lifetime(inferred_outlives, index) + } + hir::GenericParamKind::Type { .. } => { + Self::lifetimes_outliving_type(inferred_outlives, index) + } + hir::GenericParamKind::Const { .. } => Vec::new(), + } } -} -impl ExplicitOutlivesRequirements { - fn collect_outlives_bound_spans( + + fn collect_outlives_bound_spans<'tcx>( &self, - cx: &LateContext<'_, '_>, - item_def_id: DefId, - param_name: &str, + tcx: TyCtxt<'tcx>, bounds: &hir::GenericBounds, - infer_static: bool + inferred_outlives: &[ty::Region<'tcx>], + infer_static: bool, ) -> Vec<(usize, Span)> { - // For lack of a more elegant strategy for comparing the `ty::Predicate`s - // returned by this query with the params/bounds grabbed from the HIR—and - // with some regrets—we're going to covert the param/lifetime names to - // strings - let inferred_outlives = cx.tcx.inferred_outlives_of(item_def_id); - - let ty_lt_names = inferred_outlives.iter().filter_map(|pred| { - let binder = match pred { - ty::Predicate::TypeOutlives(binder) => binder, - _ => { return None; } - }; - let ty_outlives_pred = binder.skip_binder(); - let ty_name = match ty_outlives_pred.0.sty { - ty::Param(param) => param.name.to_string(), - _ => { return None; } - }; - let lt_name = match ty_outlives_pred.1 { - ty::RegionKind::ReEarlyBound(region) => { - region.name.to_string() - }, - _ => { return None; } - }; - Some((ty_name, lt_name)) - }).collect::>(); - - let mut bound_spans = Vec::new(); - for (i, bound) in bounds.iter().enumerate() { - if let hir::GenericBound::Outlives(lifetime) = bound { - let is_static = match lifetime.name { - hir::LifetimeName::Static => true, - _ => false - }; - if is_static && !infer_static { - // infer-outlives for 'static is still feature-gated (tracking issue #44493) - continue; - } - - let lt_name = &lifetime.name.ident().to_string(); - if ty_lt_names.contains(&(param_name.to_owned(), lt_name.to_owned())) { - bound_spans.push((i, bound.span())); + use rustc::middle::resolve_lifetime::Region; + + bounds + .iter() + .enumerate() + .filter_map(|(i, bound)| { + if let hir::GenericBound::Outlives(lifetime) = bound { + let is_inferred = match tcx.named_region(lifetime.hir_id) { + Some(Region::Static) if infer_static => { + inferred_outlives.iter() + .any(|r| if let ty::ReStatic = r { true } else { false }) + } + Some(Region::EarlyBound(index, ..)) => inferred_outlives + .iter() + .any(|r| { + if let ty::ReEarlyBound(ebr) = r { + ebr.index == index + } else { + false + } + }), + _ => false, + }; + if is_inferred { + Some((i, bound.span())) + } else { + None + } + } else { + None } - } - } - bound_spans + }) + .collect() } fn consolidate_outlives_bound_spans( @@ -1752,7 +1618,7 @@ impl ExplicitOutlivesRequirements { let mut from_start = true; for (i, bound_span) in bound_spans { match last_merged_i { - // If the first bound is inferable, our span should also eat the trailing `+` + // If the first bound is inferable, our span should also eat the leading `+`. None if i == 0 => { merged.push(bound_span.to(bounds[1].span().shrink_to_lo())); last_merged_i = Some(0); @@ -1790,26 +1656,48 @@ impl ExplicitOutlivesRequirements { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements { fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { + use rustc::middle::resolve_lifetime::Region; + let infer_static = cx.tcx.features().infer_static_outlives_requirements; - let def_id = cx.tcx.hir().local_def_id(item.id); - if let hir::ItemKind::Struct(_, ref generics) = item.node { + let def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id); + if let hir::ItemKind::Struct(_, ref hir_generics) + | hir::ItemKind::Enum(_, ref hir_generics) + | hir::ItemKind::Union(_, ref hir_generics) = item.node + { + let inferred_outlives = cx.tcx.inferred_outlives_of(def_id); + if inferred_outlives.is_empty() { + return; + } + + let ty_generics = cx.tcx.generics_of(def_id); + let mut bound_count = 0; let mut lint_spans = Vec::new(); - for param in &generics.params { - let param_name = match param.kind { - hir::GenericParamKind::Lifetime { .. } => continue, - hir::GenericParamKind::Type { .. } => { - match param.name { - hir::ParamName::Fresh(_) => continue, - hir::ParamName::Error => continue, - hir::ParamName::Plain(name) => name.to_string(), - } + for param in &hir_generics.params { + let has_lifetime_bounds = param.bounds.iter().any(|bound| { + if let hir::GenericBound::Outlives(_) = bound { + true + } else { + false } - hir::GenericParamKind::Const { .. } => continue, - }; + }); + if !has_lifetime_bounds { + continue; + } + + let relevant_lifetimes = self.collect_outlived_lifetimes( + param, + cx.tcx, + inferred_outlives, + ty_generics, + ); + if relevant_lifetimes.is_empty() { + continue; + } + let bound_spans = self.collect_outlives_bound_spans( - cx, def_id, ¶m_name, ¶m.bounds, infer_static + cx.tcx, ¶m.bounds, &relevant_lifetimes, infer_static, ); bound_count += bound_spans.len(); lint_spans.extend( @@ -1821,54 +1709,93 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements { let mut where_lint_spans = Vec::new(); let mut dropped_predicate_count = 0; - let num_predicates = generics.where_clause.predicates.len(); - for (i, where_predicate) in generics.where_clause.predicates.iter().enumerate() { - if let hir::WherePredicate::BoundPredicate(predicate) = where_predicate { - let param_name = match predicate.bounded_ty.node { - hir::TyKind::Path(ref qpath) => { - if let hir::QPath::Resolved(None, ty_param_path) = qpath { - ty_param_path.segments[0].ident.to_string() - } else { - continue; - } - }, - _ => { continue; } - }; - let bound_spans = self.collect_outlives_bound_spans( - cx, def_id, ¶m_name, &predicate.bounds, infer_static - ); - bound_count += bound_spans.len(); - - let drop_predicate = bound_spans.len() == predicate.bounds.len(); - if drop_predicate { - dropped_predicate_count += 1; - } - - // If all the bounds on a predicate were inferable and there are - // further predicates, we want to eat the trailing comma - if drop_predicate && i + 1 < num_predicates { - let next_predicate_span = generics.where_clause.predicates[i+1].span(); - where_lint_spans.push( - predicate.span.to(next_predicate_span.shrink_to_lo()) - ); - } else { - where_lint_spans.extend( - self.consolidate_outlives_bound_spans( - predicate.span.shrink_to_lo(), + let num_predicates = hir_generics.where_clause.predicates.len(); + for (i, where_predicate) in hir_generics.where_clause.predicates.iter().enumerate() { + let (relevant_lifetimes, bounds, span) = match where_predicate { + hir::WherePredicate::RegionPredicate(predicate) => { + if let Some(Region::EarlyBound(index, ..)) + = cx.tcx.named_region(predicate.lifetime.hir_id) + { + ( + Self::lifetimes_outliving_lifetime(inferred_outlives, index), &predicate.bounds, - bound_spans + predicate.span, ) - ); + } else { + continue; + } + } + hir::WherePredicate::BoundPredicate(predicate) => { + // FIXME we can also infer bounds on associated types, + // and should check for them here. + match predicate.bounded_ty.node { + hir::TyKind::Path(hir::QPath::Resolved( + None, + ref path, + )) => { + if let Res::Def(DefKind::TyParam, def_id) = path.res { + let index = ty_generics.param_def_id_to_index[&def_id]; + ( + Self::lifetimes_outliving_type(inferred_outlives, index), + &predicate.bounds, + predicate.span, + ) + } else { + continue; + } + }, + _ => { continue; } + } } + _ => continue, + }; + if relevant_lifetimes.is_empty() { + continue; + } + + let bound_spans = self.collect_outlives_bound_spans( + cx.tcx, bounds, &relevant_lifetimes, infer_static, + ); + bound_count += bound_spans.len(); + + let drop_predicate = bound_spans.len() == bounds.len(); + if drop_predicate { + dropped_predicate_count += 1; + } + + // If all the bounds on a predicate were inferable and there are + // further predicates, we want to eat the trailing comma. + if drop_predicate && i + 1 < num_predicates { + let next_predicate_span = hir_generics.where_clause.predicates[i + 1].span(); + where_lint_spans.push( + span.to(next_predicate_span.shrink_to_lo()) + ); + } else { + where_lint_spans.extend( + self.consolidate_outlives_bound_spans( + span.shrink_to_lo(), + bounds, + bound_spans + ) + ); } } // If all predicates are inferable, drop the entire clause // (including the `where`) if num_predicates > 0 && dropped_predicate_count == num_predicates { - let full_where_span = generics.span.shrink_to_hi() - .to(generics.where_clause.span() - .expect("span of (nonempty) where clause should exist")); + let where_span = hir_generics.where_clause.span() + .expect("span of (nonempty) where clause should exist"); + // Extend the where clause back to the closing `>` of the + // generics, except for tuple struct, which have the `where` + // after the fields of the struct. + let full_where_span = if let hir::ItemKind::Struct(hir::VariantData::Tuple(..), _) + = item.node + { + where_span + } else { + hir_generics.span.shrink_to_hi().to(where_span) + }; lint_spans.push( full_where_span ); @@ -1893,8 +1820,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements { ); err.emit(); } - } } - } diff --git a/src/librustc_lint/diagnostics.rs b/src/librustc_lint/error_codes.rs similarity index 100% rename from src/librustc_lint/diagnostics.rs rename to src/librustc_lint/error_codes.rs diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 5c243e1389073..d808a15982e37 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -20,11 +20,13 @@ #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] #[macro_use] extern crate rustc; -mod diagnostics; +mod error_codes; mod nonstandard_style; pub mod builtin; mod types; @@ -40,11 +42,13 @@ use rustc::lint::builtin::{ INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS, - parser::QUESTION_MARK_MACRO_SEP, parser::ILL_FORMED_ATTRIBUTE_INPUT, }; use rustc::session; use rustc::hir; +use rustc::hir::def_id::DefId; +use rustc::ty::query::Providers; +use rustc::ty::TyCtxt; use syntax::ast; use syntax::edition::Edition; @@ -58,14 +62,27 @@ use nonstandard_style::*; use builtin::*; use types::*; use unused::*; +use rustc::lint::internal::*; /// Useful for other parts of the compiler. pub use builtin::SoftLints; +pub fn provide(providers: &mut Providers<'_>) { + *providers = Providers { + lint_mod, + ..*providers + }; +} + +fn lint_mod<'tcx>(tcx: TyCtxt<'tcx>, module_def_id: DefId) { + lint::late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new()); +} + macro_rules! pre_expansion_lint_passes { ($macro:path, $args:tt) => ( $macro!($args, [ KeywordIdents: KeywordIdents, + UnusedDocComment: UnusedDocComment, ]); ) } @@ -77,8 +94,7 @@ macro_rules! early_lint_passes { UnusedImportBraces: UnusedImportBraces, UnsafeCode: UnsafeCode, AnonymousParameters: AnonymousParameters, - UnusedDocComment: UnusedDocComment, - EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns, + EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), NonCamelCaseTypes: NonCamelCaseTypes, DeprecatedAttr: DeprecatedAttr::new(), ]); @@ -94,6 +110,88 @@ macro_rules! declare_combined_early_pass { pre_expansion_lint_passes!(declare_combined_early_pass, [BuiltinCombinedPreExpansionLintPass]); early_lint_passes!(declare_combined_early_pass, [BuiltinCombinedEarlyLintPass]); +macro_rules! late_lint_passes { + ($macro:path, $args:tt) => ( + $macro!($args, [ + // FIXME: Look into regression when this is used as a module lint + // May Depend on constants elsewhere + UnusedBrokenConst: UnusedBrokenConst, + + // Uses attr::is_used which is untracked, can't be an incremental module pass. + UnusedAttributes: UnusedAttributes::new(), + + // Needs to run after UnusedAttributes as it marks all `feature` attributes as used. + UnstableFeatures: UnstableFeatures, + + // Tracks state across modules + UnnameableTestItems: UnnameableTestItems::new(), + + // Tracks attributes of parents + MissingDoc: MissingDoc::new(), + + // Depends on access levels + // FIXME: Turn the computation of types which implement Debug into a query + // and change this to a module lint pass + MissingDebugImplementations: MissingDebugImplementations::default(), + ]); + ) +} + +macro_rules! late_lint_mod_passes { + ($macro:path, $args:tt) => ( + $macro!($args, [ + HardwiredLints: HardwiredLints, + WhileTrue: WhileTrue, + ImproperCTypes: ImproperCTypes, + VariantSizeDifferences: VariantSizeDifferences, + BoxPointers: BoxPointers, + PathStatements: PathStatements, + + // Depends on referenced function signatures in expressions + UnusedResults: UnusedResults, + + NonUpperCaseGlobals: NonUpperCaseGlobals, + NonShorthandFieldPatterns: NonShorthandFieldPatterns, + UnusedAllocation: UnusedAllocation, + + // Depends on types used in type definitions + MissingCopyImplementations: MissingCopyImplementations, + + PluginAsLibrary: PluginAsLibrary, + + // Depends on referenced function signatures in expressions + MutableTransmutes: MutableTransmutes, + + // Depends on types of fields, checks if they implement Drop + UnionsWithDropFields: UnionsWithDropFields, + + TypeAliasBounds: TypeAliasBounds, + + TrivialConstraints: TrivialConstraints, + TypeLimits: TypeLimits::new(), + + NonSnakeCase: NonSnakeCase, + InvalidNoMangleItems: InvalidNoMangleItems, + + // Depends on access levels + UnreachablePub: UnreachablePub, + + ExplicitOutlivesRequirements: ExplicitOutlivesRequirements, + ]); + ) +} + +macro_rules! declare_combined_late_pass { + ([$v:vis $name:ident], $passes:tt) => ( + late_lint_methods!(declare_combined_late_lint_pass, [$v $name, $passes], ['tcx]); + ) +} + +// FIXME: Make a separate lint type which do not require typeck tables +late_lint_passes!(declare_combined_late_pass, [pub BuiltinCombinedLateLintPass]); + +late_lint_mod_passes!(declare_combined_late_pass, [BuiltinCombinedModuleLateLintPass]); + /// Tell the `LintStore` about all the built-in lints (the ones /// defined in this crate and the ones defined in /// `rustc::lint::builtin`). @@ -104,17 +202,25 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { ) } + macro_rules! register_pass { + ($method:ident, $constructor:expr, [$($args:expr),*]) => ( + store.$method(sess, false, false, $($args,)* box $constructor); + ) + } + macro_rules! register_passes { - ([$method:ident], [$($passes:ident: $constructor:expr,)*]) => ( + ([$method:ident, $args:tt], [$($passes:ident: $constructor:expr,)*]) => ( $( - store.$method(sess, false, false, box $constructor); + register_pass!($method, $constructor, $args); )* ) } if sess.map(|sess| sess.opts.debugging_opts.no_interleave_lints).unwrap_or(false) { - pre_expansion_lint_passes!(register_passes, [register_pre_expansion_pass]); - early_lint_passes!(register_passes, [register_early_pass]); + pre_expansion_lint_passes!(register_passes, [register_pre_expansion_pass, []]); + early_lint_passes!(register_passes, [register_early_pass, []]); + late_lint_passes!(register_passes, [register_late_pass, [false]]); + late_lint_mod_passes!(register_passes, [register_late_pass, [true]]); } else { store.register_pre_expansion_pass( sess, @@ -123,40 +229,14 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { box BuiltinCombinedPreExpansionLintPass::new() ); store.register_early_pass(sess, false, true, box BuiltinCombinedEarlyLintPass::new()); + store.register_late_pass( + sess, false, true, true, box BuiltinCombinedModuleLateLintPass::new() + ); + store.register_late_pass( + sess, false, true, false, box BuiltinCombinedLateLintPass::new() + ); } - late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedLateLintPass, [ - HardwiredLints: HardwiredLints, - WhileTrue: WhileTrue, - ImproperCTypes: ImproperCTypes, - VariantSizeDifferences: VariantSizeDifferences, - BoxPointers: BoxPointers, - UnusedAttributes: UnusedAttributes, - PathStatements: PathStatements, - UnusedResults: UnusedResults, - NonSnakeCase: NonSnakeCase, - NonUpperCaseGlobals: NonUpperCaseGlobals, - NonShorthandFieldPatterns: NonShorthandFieldPatterns, - UnusedAllocation: UnusedAllocation, - MissingCopyImplementations: MissingCopyImplementations, - UnstableFeatures: UnstableFeatures, - InvalidNoMangleItems: InvalidNoMangleItems, - PluginAsLibrary: PluginAsLibrary, - MutableTransmutes: MutableTransmutes, - UnionsWithDropFields: UnionsWithDropFields, - UnreachablePub: UnreachablePub, - UnnameableTestItems: UnnameableTestItems::new(), - TypeAliasBounds: TypeAliasBounds, - UnusedBrokenConst: UnusedBrokenConst, - TrivialConstraints: TrivialConstraints, - TypeLimits: TypeLimits::new(), - MissingDoc: MissingDoc::new(), - MissingDebugImplementations: MissingDebugImplementations::new(), - ExplicitOutlivesRequirements: ExplicitOutlivesRequirements, - ]], ['tcx]); - - store.register_late_pass(sess, false, box BuiltinCombinedLateLintPass::new()); - add_lint_group!(sess, "nonstandard_style", NON_CAMEL_CASE_TYPES, @@ -291,11 +371,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { reference: "issue #46043 ", edition: None, }, - FutureIncompatibleInfo { - id: LintId::of(INCOHERENT_FUNDAMENTAL_IMPLS), - reference: "issue #46205 ", - edition: None, - }, FutureIncompatibleInfo { id: LintId::of(ORDER_DEPENDENT_TRAIT_OBJECTS), reference: "issue #56484 ", @@ -328,11 +403,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { reference: "issue #50504 ", edition: None, }, - FutureIncompatibleInfo { - id: LintId::of(QUESTION_MARK_MACRO_SEP), - reference: "issue #48075 ", - edition: Some(Edition::Edition2018), - }, FutureIncompatibleInfo { id: LintId::of(MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS), reference: "issue #52234 ", @@ -349,10 +419,15 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { edition: None, }, FutureIncompatibleInfo { - id: LintId::of(DUPLICATE_MATCHER_BINDING_NAME), - reference: "issue #57593 ", + id: LintId::of(NESTED_IMPL_TRAIT), + reference: "issue #59014 ", edition: None, }, + FutureIncompatibleInfo { + id: LintId::of(MUTABLE_BORROW_RESERVATION_CONFLICT), + reference: "issue #59159 ", + edition: None, + } ]); // Register renamed and removed lints. @@ -404,4 +479,25 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { "no longer a warning, #[no_mangle] statics always exported"); store.register_removed("bad_repr", "replaced with a generic attribute input check"); + store.register_removed("duplicate_matcher_binding_name", + "converted into hard error, see https://github.com/rust-lang/rust/issues/57742"); + store.register_removed("incoherent_fundamental_impls", + "converted into hard error, see https://github.com/rust-lang/rust/issues/46205"); +} + +pub fn register_internals(store: &mut lint::LintStore, sess: Option<&Session>) { + store.register_early_pass(sess, false, false, box DefaultHashTypes::new()); + store.register_late_pass(sess, false, false, false, box TyTyKind); + store.register_group( + sess, + false, + "internal", + None, + vec![ + LintId::of(DEFAULT_HASH_TYPES), + LintId::of(USAGE_OF_TY_TYKIND), + LintId::of(TY_PASS_BY_REFERENCE), + LintId::of(USAGE_OF_QUALIFIED_TY), + ], + ); } diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index 4c4032a36956d..b221b8ed30c59 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -1,5 +1,5 @@ use rustc::hir::{self, GenericParamKind, PatKind}; -use rustc::hir::def::Def; +use rustc::hir::def::{Res, DefKind}; use rustc::hir::intravisit::FnKind; use rustc::lint; use rustc::ty; @@ -9,6 +9,7 @@ use lint::{EarlyLintPass, LintPass, LateLintPass}; use syntax::ast; use syntax::attr; use syntax::errors::Applicability; +use syntax::symbol::sym; use syntax_pos::{BytePos, symbol::Ident, Span}; #[derive(PartialEq)] @@ -38,6 +39,8 @@ declare_lint! { "types, variants, traits and type parameters should have camel case names" } +declare_lint_pass!(NonCamelCaseTypes => [NON_CAMEL_CASE_TYPES]); + fn char_has_case(c: char) -> bool { c.is_lowercase() || c.is_uppercase() } @@ -105,9 +108,6 @@ fn to_camel_case(s: &str) -> String { .0 } -#[derive(Copy, Clone)] -pub struct NonCamelCaseTypes; - impl NonCamelCaseTypes { fn check_case(&self, cx: &EarlyContext<'_>, sort: &str, ident: &Ident) { let name = &ident.name.as_str(); @@ -126,16 +126,6 @@ impl NonCamelCaseTypes { } } -impl LintPass for NonCamelCaseTypes { - fn name(&self) -> &'static str { - "NonCamelCaseTypes" - } - - fn get_lints(&self) -> LintArray { - lint_array!(NON_CAMEL_CASE_TYPES) - } -} - impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { let has_repr_c = it.attrs @@ -173,8 +163,7 @@ declare_lint! { "variables, methods, functions, lifetime parameters and modules should have snake case names" } -#[derive(Copy, Clone)] -pub struct NonSnakeCase; +declare_lint_pass!(NonSnakeCase => [NON_SNAKE_CASE]); impl NonSnakeCase { fn to_snake_case(mut str: &str) -> String { @@ -256,22 +245,16 @@ impl NonSnakeCase { } } -impl LintPass for NonSnakeCase { - fn name(&self) -> &'static str { - "NonSnakeCase" - } - - fn get_lints(&self) -> LintArray { - lint_array!(NON_SNAKE_CASE) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { - fn check_crate(&mut self, cx: &LateContext<'_, '_>, cr: &hir::Crate) { + fn check_mod(&mut self, cx: &LateContext<'_, '_>, _: &'tcx hir::Mod, _: Span, id: hir::HirId) { + if id != hir::CRATE_HIR_ID { + return; + } + let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name { Some(Ident::from_str(name)) } else { - attr::find_by_name(&cr.attrs, "crate_name") + attr::find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name) .and_then(|attr| attr.meta()) .and_then(|meta| { meta.name_value_literal().and_then(|lit| { @@ -333,7 +316,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { } FnKind::ItemFn(ident, _, header, _, attrs) => { // Skip foreign-ABI #[no_mangle] functions (Issue #31924) - if header.abi != Abi::Rust && attr::contains_name(attrs, "no_mangle") { + if header.abi != Abi::Rust && attr::contains_name(attrs, sym::no_mangle) { return; } self.check_snake_case(cx, "function", ident); @@ -358,7 +341,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { } fn check_pat(&mut self, cx: &LateContext<'_, '_>, p: &hir::Pat) { - if let &PatKind::Binding(_, _, _, ident, _) = &p.node { + if let &PatKind::Binding(_, _, ident, _) = &p.node { self.check_snake_case(cx, "variable", &ident); } } @@ -383,8 +366,7 @@ declare_lint! { "static constants should have uppercase identifiers" } -#[derive(Copy, Clone)] -pub struct NonUpperCaseGlobals; +declare_lint_pass!(NonUpperCaseGlobals => [NON_UPPER_CASE_GLOBALS]); impl NonUpperCaseGlobals { fn check_upper_case(cx: &LateContext<'_, '_>, sort: &str, ident: &Ident) { @@ -406,20 +388,10 @@ impl NonUpperCaseGlobals { } } -impl LintPass for NonUpperCaseGlobals { - fn name(&self) -> &'static str { - "NonUpperCaseGlobals" - } - - fn get_lints(&self) -> LintArray { - lint_array!(NON_UPPER_CASE_GLOBALS) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { match it.node { - hir::ItemKind::Static(..) if !attr::contains_name(&it.attrs, "no_mangle") => { + hir::ItemKind::Static(..) if !attr::contains_name(&it.attrs, sym::no_mangle) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident); } hir::ItemKind::Const(..) => { @@ -444,7 +416,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { fn check_pat(&mut self, cx: &LateContext<'_, '_>, p: &hir::Pat) { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node { - if let Def::Const(..) = path.def { + if let Res::Def(DefKind::Const, _) = path.res { if path.segments.len() == 1 { NonUpperCaseGlobals::check_upper_case( cx, @@ -468,26 +440,4 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { } #[cfg(test)] -mod tests { - use super::{is_camel_case, to_camel_case}; - - #[test] - fn camel_case() { - assert!(!is_camel_case("userData")); - assert_eq!(to_camel_case("userData"), "UserData"); - - assert!(is_camel_case("X86_64")); - - assert!(!is_camel_case("X86__64")); - assert_eq!(to_camel_case("X86__64"), "X86_64"); - - assert!(!is_camel_case("Abc_123")); - assert_eq!(to_camel_case("Abc_123"), "Abc123"); - - assert!(!is_camel_case("A1_b2_c3")); - assert_eq!(to_camel_case("A1_b2_c3"), "A1B2C3"); - - assert!(!is_camel_case("ONE_TWO_THREE")); - assert_eq!(to_camel_case("ONE_TWO_THREE"), "OneTwoThree"); - } -} +mod tests; diff --git a/src/librustc_lint/nonstandard_style/tests.rs b/src/librustc_lint/nonstandard_style/tests.rs new file mode 100644 index 0000000000000..39c525b8623d0 --- /dev/null +++ b/src/librustc_lint/nonstandard_style/tests.rs @@ -0,0 +1,21 @@ +use super::{is_camel_case, to_camel_case}; + +#[test] +fn camel_case() { + assert!(!is_camel_case("userData")); + assert_eq!(to_camel_case("userData"), "UserData"); + + assert!(is_camel_case("X86_64")); + + assert!(!is_camel_case("X86__64")); + assert_eq!(to_camel_case("X86__64"), "X86_64"); + + assert!(!is_camel_case("Abc_123")); + assert_eq!(to_camel_case("Abc_123"), "Abc123"); + + assert!(!is_camel_case("A1_b2_c3")); + assert_eq!(to_camel_case("A1_b2_c3"), "A1B2C3"); + + assert!(!is_camel_case("ONE_TWO_THREE")); + assert_eq!(to_camel_case("ONE_TWO_THREE"), "OneTwoThree"); +} diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 35489ab42e730..d0258ca30c507 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -1,9 +1,11 @@ #![allow(non_snake_case)] -use rustc::hir::Node; +use rustc::hir::{ExprKind, Node}; +use crate::hir::def_id::DefId; +use rustc::hir::lowering::is_range_literal; use rustc::ty::subst::SubstsRef; use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; -use rustc::ty::layout::{self, IntegerExt, LayoutOf, VariantIdx}; +use rustc::ty::layout::{self, IntegerExt, LayoutOf, VariantIdx, SizeSkeleton}; use rustc::{lint, util}; use rustc_data_structures::indexed_vec::Idx; use util::nodemap::FxHashSet; @@ -13,11 +15,11 @@ use lint::{LintPass, LateLintPass}; use std::cmp; use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; -use syntax::{ast, attr}; +use syntax::{ast, attr, source_map}; use syntax::errors::Applicability; +use syntax::symbol::sym; use rustc_target::spec::abi::Abi; use syntax_pos::Span; -use syntax::source_map; use rustc::hir; @@ -49,20 +51,348 @@ pub struct TypeLimits { negated_expr_id: hir::HirId, } +impl_lint_pass!(TypeLimits => [UNUSED_COMPARISONS, OVERFLOWING_LITERALS]); + impl TypeLimits { pub fn new() -> TypeLimits { TypeLimits { negated_expr_id: hir::DUMMY_HIR_ID } } } -impl LintPass for TypeLimits { - fn name(&self) -> &'static str { - "TypeLimits" +/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint. +/// Returns `true` iff the lint was overridden. +fn lint_overflowing_range_endpoint<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + lit: &hir::Lit, + lit_val: u128, + max: u128, + expr: &'tcx hir::Expr, + parent_expr: &'tcx hir::Expr, + ty: impl std::fmt::Debug, +) -> bool { + // We only want to handle exclusive (`..`) ranges, + // which are represented as `ExprKind::Struct`. + if let ExprKind::Struct(_, eps, _) = &parent_expr.node { + debug_assert_eq!(eps.len(), 2); + // We can suggest using an inclusive range + // (`..=`) instead only if it is the `end` that is + // overflowing and only by 1. + if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max { + let mut err = cx.struct_span_lint( + OVERFLOWING_LITERALS, + parent_expr.span, + &format!("range endpoint is out of range for `{:?}`", ty), + ); + if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) { + use ast::{LitKind, LitIntType}; + // We need to preserve the literal's suffix, + // as it may determine typing information. + let suffix = match lit.node { + LitKind::Int(_, LitIntType::Signed(s)) => format!("{}", s), + LitKind::Int(_, LitIntType::Unsigned(s)) => format!("{}", s), + LitKind::Int(_, LitIntType::Unsuffixed) => "".to_owned(), + _ => bug!(), + }; + let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); + err.span_suggestion( + parent_expr.span, + &"use an inclusive range instead", + suggestion, + Applicability::MachineApplicable, + ); + err.emit(); + return true; + } + } } - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_COMPARISONS, - OVERFLOWING_LITERALS) + false +} + +// For `isize` & `usize`, be conservative with the warnings, so that the +// warnings are consistent between 32- and 64-bit platforms. +fn int_ty_range(int_ty: ast::IntTy) -> (i128, i128) { + match int_ty { + ast::IntTy::Isize => (i64::min_value() as i128, i64::max_value() as i128), + ast::IntTy::I8 => (i8::min_value() as i64 as i128, i8::max_value() as i128), + ast::IntTy::I16 => (i16::min_value() as i64 as i128, i16::max_value() as i128), + ast::IntTy::I32 => (i32::min_value() as i64 as i128, i32::max_value() as i128), + ast::IntTy::I64 => (i64::min_value() as i128, i64::max_value() as i128), + ast::IntTy::I128 =>(i128::min_value() as i128, i128::max_value()), + } +} + +fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) { + match uint_ty { + ast::UintTy::Usize => (u64::min_value() as u128, u64::max_value() as u128), + ast::UintTy::U8 => (u8::min_value() as u128, u8::max_value() as u128), + ast::UintTy::U16 => (u16::min_value() as u128, u16::max_value() as u128), + ast::UintTy::U32 => (u32::min_value() as u128, u32::max_value() as u128), + ast::UintTy::U64 => (u64::min_value() as u128, u64::max_value() as u128), + ast::UintTy::U128 => (u128::min_value(), u128::max_value()), + } +} + +fn get_bin_hex_repr(cx: &LateContext<'_, '_>, lit: &hir::Lit) -> Option { + let src = cx.sess().source_map().span_to_snippet(lit.span).ok()?; + let firstch = src.chars().next()?; + + if firstch == '0' { + match src.chars().nth(1) { + Some('x') | Some('b') => return Some(src), + _ => return None, + } + } + + None +} + +fn report_bin_hex_error( + cx: &LateContext<'_, '_>, + expr: &hir::Expr, + ty: attr::IntType, + repr_str: String, + val: u128, + negative: bool, +) { + let size = layout::Integer::from_attr(&cx.tcx, ty).size(); + let (t, actually) = match ty { + attr::IntType::SignedInt(t) => { + let actually = sign_extend(val, size) as i128; + (format!("{:?}", t), actually.to_string()) + } + attr::IntType::UnsignedInt(t) => { + let actually = truncate(val, size); + (format!("{:?}", t), actually.to_string()) + } + }; + let mut err = cx.struct_span_lint( + OVERFLOWING_LITERALS, + expr.span, + &format!("literal out of range for {}", t), + ); + err.note(&format!( + "the literal `{}` (decimal `{}`) does not fit into \ + an `{}` and will become `{}{}`", + repr_str, val, t, actually, t + )); + if let Some(sugg_ty) = + get_type_suggestion(&cx.tables.node_type(expr.hir_id), val, negative) + { + if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { + let (sans_suffix, _) = repr_str.split_at(pos); + err.span_suggestion( + expr.span, + &format!("consider using `{}` instead", sugg_ty), + format!("{}{}", sans_suffix, sugg_ty), + Applicability::MachineApplicable + ); + } else { + err.help(&format!("consider using `{}` instead", sugg_ty)); + } + } + + err.emit(); +} + +// This function finds the next fitting type and generates a suggestion string. +// It searches for fitting types in the following way (`X < Y`): +// - `iX`: if literal fits in `uX` => `uX`, else => `iY` +// - `-iX` => `iY` +// - `uX` => `uY` +// +// No suggestion for: `isize`, `usize`. +fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option { + use syntax::ast::IntTy::*; + use syntax::ast::UintTy::*; + macro_rules! find_fit { + ($ty:expr, $val:expr, $negative:expr, + $($type:ident => [$($utypes:expr),*] => [$($itypes:expr),*]),+) => { + { + let _neg = if negative { 1 } else { 0 }; + match $ty { + $($type => { + $(if !negative && val <= uint_ty_range($utypes).1 { + return Some(format!("{:?}", $utypes)) + })* + $(if val <= int_ty_range($itypes).1 as u128 + _neg { + return Some(format!("{:?}", $itypes)) + })* + None + },)+ + _ => None + } + } + } + } + match t.sty { + ty::Int(i) => find_fit!(i, val, negative, + I8 => [U8] => [I16, I32, I64, I128], + I16 => [U16] => [I32, I64, I128], + I32 => [U32] => [I64, I128], + I64 => [U64] => [I128], + I128 => [U128] => []), + ty::Uint(u) => find_fit!(u, val, negative, + U8 => [U8, U16, U32, U64, U128] => [], + U16 => [U16, U32, U64, U128] => [], + U32 => [U32, U64, U128] => [], + U64 => [U64, U128] => [], + U128 => [U128] => []), + _ => None, + } +} + +fn lint_int_literal<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + type_limits: &TypeLimits, + e: &'tcx hir::Expr, + lit: &hir::Lit, + t: ast::IntTy, + v: u128, +) { + let int_type = if let ast::IntTy::Isize = t { + cx.sess().target.isize_ty + } else { + t + }; + + let (_, max) = int_ty_range(int_type); + let max = max as u128; + let negative = type_limits.negated_expr_id == e.hir_id; + + // Detect literal value out of range [min, max] inclusive + // avoiding use of -min to prevent overflow/panic + if (negative && v > max + 1) || (!negative && v > max) { + if let Some(repr_str) = get_bin_hex_repr(cx, lit) { + report_bin_hex_error( + cx, + e, + attr::IntType::SignedInt(t), + repr_str, + v, + negative, + ); + return; + } + + let par_id = cx.tcx.hir().get_parent_node(e.hir_id); + if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) { + if let hir::ExprKind::Struct(..) = par_e.node { + if is_range_literal(cx.sess(), par_e) + && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t) + { + // The overflowing literal lint was overridden. + return; + } + } + } + + cx.span_lint( + OVERFLOWING_LITERALS, + e.span, + &format!("literal out of range for `{:?}`", t), + ); + } +} + +fn lint_uint_literal<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + e: &'tcx hir::Expr, + lit: &hir::Lit, + t: ast::UintTy, +) { + let uint_type = if let ast::UintTy::Usize = t { + cx.sess().target.usize_ty + } else { + t + }; + let (min, max) = uint_ty_range(uint_type); + let lit_val: u128 = match lit.node { + // _v is u8, within range by definition + ast::LitKind::Byte(_v) => return, + ast::LitKind::Int(v, _) => v, + _ => bug!(), + }; + if lit_val < min || lit_val > max { + let parent_id = cx.tcx.hir().get_parent_node(e.hir_id); + if let Node::Expr(par_e) = cx.tcx.hir().get(parent_id) { + match par_e.node { + hir::ExprKind::Cast(..) => { + if let ty::Char = cx.tables.expr_ty(par_e).sty { + let mut err = cx.struct_span_lint( + OVERFLOWING_LITERALS, + par_e.span, + "only `u8` can be cast into `char`", + ); + err.span_suggestion( + par_e.span, + &"use a `char` literal instead", + format!("'\\u{{{:X}}}'", lit_val), + Applicability::MachineApplicable, + ); + err.emit(); + return; + } + } + hir::ExprKind::Struct(..) + if is_range_literal(cx.sess(), par_e) => { + if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) { + // The overflowing literal lint was overridden. + return; + } + } + _ => {} + } + } + if let Some(repr_str) = get_bin_hex_repr(cx, lit) { + report_bin_hex_error(cx, e, attr::IntType::UnsignedInt(t), repr_str, lit_val, false); + return; + } + cx.span_lint( + OVERFLOWING_LITERALS, + e.span, + &format!("literal out of range for `{:?}`", t), + ); + } +} + +fn lint_literal<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + type_limits: &TypeLimits, + e: &'tcx hir::Expr, + lit: &hir::Lit, +) { + match cx.tables.node_type(e.hir_id).sty { + ty::Int(t) => { + match lit.node { + ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | + ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => { + lint_int_literal(cx, type_limits, e, lit, t, v) + } + _ => bug!(), + }; + } + ty::Uint(t) => { + lint_uint_literal(cx, e, lit, t) + } + ty::Float(t) => { + let is_infinite = match lit.node { + ast::LitKind::Float(v, _) | + ast::LitKind::FloatUnsuffixed(v) => { + match t { + ast::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite), + ast::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite), + } + } + _ => bug!(), + }; + if is_infinite == Ok(true) { + cx.span_lint(OVERFLOWING_LITERALS, + e.span, + &format!("literal out of range for `{:?}`", t)); + } + } + _ => {} } } @@ -82,118 +412,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { "comparison is useless due to type limits"); } } - hir::ExprKind::Lit(ref lit) => { - match cx.tables.node_type(e.hir_id).sty { - ty::Int(t) => { - match lit.node { - ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | - ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => { - let int_type = if let ast::IntTy::Isize = t { - cx.sess().target.isize_ty - } else { - t - }; - let (_, max) = int_ty_range(int_type); - let max = max as u128; - let negative = self.negated_expr_id == e.hir_id; - - // Detect literal value out of range [min, max] inclusive - // avoiding use of -min to prevent overflow/panic - if (negative && v > max + 1) || (!negative && v > max) { - if let Some(repr_str) = get_bin_hex_repr(cx, lit) { - report_bin_hex_error( - cx, - e, - ty::Int(t), - repr_str, - v, - negative, - ); - return; - } - cx.span_lint( - OVERFLOWING_LITERALS, - e.span, - &format!("literal out of range for {:?}", t), - ); - return; - } - } - _ => bug!(), - }; - } - ty::Uint(t) => { - let uint_type = if let ast::UintTy::Usize = t { - cx.sess().target.usize_ty - } else { - t - }; - let (min, max) = uint_ty_range(uint_type); - let lit_val: u128 = match lit.node { - // _v is u8, within range by definition - ast::LitKind::Byte(_v) => return, - ast::LitKind::Int(v, _) => v, - _ => bug!(), - }; - if lit_val < min || lit_val > max { - let parent_id = cx.tcx.hir().get_parent_node_by_hir_id(e.hir_id); - if let Node::Expr(parent_expr) = cx.tcx.hir().get_by_hir_id(parent_id) { - if let hir::ExprKind::Cast(..) = parent_expr.node { - if let ty::Char = cx.tables.expr_ty(parent_expr).sty { - let mut err = cx.struct_span_lint( - OVERFLOWING_LITERALS, - parent_expr.span, - "only u8 can be cast into char"); - err.span_suggestion( - parent_expr.span, - &"use a char literal instead", - format!("'\\u{{{:X}}}'", lit_val), - Applicability::MachineApplicable - ); - err.emit(); - return - } - } - } - if let Some(repr_str) = get_bin_hex_repr(cx, lit) { - report_bin_hex_error( - cx, - e, - ty::Uint(t), - repr_str, - lit_val, - false, - ); - return; - } - cx.span_lint( - OVERFLOWING_LITERALS, - e.span, - &format!("literal out of range for {:?}", t), - ); - } - } - ty::Float(t) => { - let is_infinite = match lit.node { - ast::LitKind::Float(v, _) | - ast::LitKind::FloatUnsuffixed(v) => { - match t { - ast::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite), - ast::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite), - } - } - _ => bug!(), - }; - if is_infinite == Ok(true) { - cx.span_lint(OVERFLOWING_LITERALS, - e.span, - &format!("literal out of range for {:?}", t)); - } - } - _ => (), - }; - } - _ => (), + hir::ExprKind::Lit(ref lit) => lint_literal(cx, self, e, lit), + _ => {} }; fn is_valid(binop: hir::BinOp, v: T, min: T, max: T) -> bool { @@ -218,30 +438,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { }) } - // for isize & usize, be conservative with the warnings, so that the - // warnings are consistent between 32- and 64-bit platforms - fn int_ty_range(int_ty: ast::IntTy) -> (i128, i128) { - match int_ty { - ast::IntTy::Isize => (i64::min_value() as i128, i64::max_value() as i128), - ast::IntTy::I8 => (i8::min_value() as i64 as i128, i8::max_value() as i128), - ast::IntTy::I16 => (i16::min_value() as i64 as i128, i16::max_value() as i128), - ast::IntTy::I32 => (i32::min_value() as i64 as i128, i32::max_value() as i128), - ast::IntTy::I64 => (i64::min_value() as i128, i64::max_value() as i128), - ast::IntTy::I128 =>(i128::min_value() as i128, i128::max_value()), - } - } - - fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) { - match uint_ty { - ast::UintTy::Usize => (u64::min_value() as u128, u64::max_value() as u128), - ast::UintTy::U8 => (u8::min_value() as u128, u8::max_value() as u128), - ast::UintTy::U16 => (u16::min_value() as u128, u16::max_value() as u128), - ast::UintTy::U32 => (u32::min_value() as u128, u32::max_value() as u128), - ast::UintTy::U64 => (u64::min_value() as u128, u64::max_value() as u128), - ast::UintTy::U128 => (u128::min_value(), u128::max_value()), - } - } - fn check_limits(cx: &LateContext<'_, '_>, binop: hir::BinOp, l: &hir::Expr, @@ -298,123 +494,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { _ => false, } } - - fn get_bin_hex_repr(cx: &LateContext<'_, '_>, lit: &ast::Lit) -> Option { - let src = cx.sess().source_map().span_to_snippet(lit.span).ok()?; - let firstch = src.chars().next()?; - - if firstch == '0' { - match src.chars().nth(1) { - Some('x') | Some('b') => return Some(src), - _ => return None, - } - } - - None - } - - // This function finds the next fitting type and generates a suggestion string. - // It searches for fitting types in the following way (`X < Y`): - // - `iX`: if literal fits in `uX` => `uX`, else => `iY` - // - `-iX` => `iY` - // - `uX` => `uY` - // - // No suggestion for: `isize`, `usize`. - fn get_type_suggestion<'a>( - t: &ty::TyKind<'_>, - val: u128, - negative: bool, - ) -> Option { - use syntax::ast::IntTy::*; - use syntax::ast::UintTy::*; - macro_rules! find_fit { - ($ty:expr, $val:expr, $negative:expr, - $($type:ident => [$($utypes:expr),*] => [$($itypes:expr),*]),+) => { - { - let _neg = if negative { 1 } else { 0 }; - match $ty { - $($type => { - $(if !negative && val <= uint_ty_range($utypes).1 { - return Some(format!("{:?}", $utypes)) - })* - $(if val <= int_ty_range($itypes).1 as u128 + _neg { - return Some(format!("{:?}", $itypes)) - })* - None - },)* - _ => None - } - } - } - } - match t { - &ty::Int(i) => find_fit!(i, val, negative, - I8 => [U8] => [I16, I32, I64, I128], - I16 => [U16] => [I32, I64, I128], - I32 => [U32] => [I64, I128], - I64 => [U64] => [I128], - I128 => [U128] => []), - &ty::Uint(u) => find_fit!(u, val, negative, - U8 => [U8, U16, U32, U64, U128] => [], - U16 => [U16, U32, U64, U128] => [], - U32 => [U32, U64, U128] => [], - U64 => [U64, U128] => [], - U128 => [U128] => []), - _ => None, - } - } - - fn report_bin_hex_error( - cx: &LateContext<'_, '_>, - expr: &hir::Expr, - ty: ty::TyKind<'_>, - repr_str: String, - val: u128, - negative: bool, - ) { - let (t, actually) = match ty { - ty::Int(t) => { - let ity = attr::IntType::SignedInt(t); - let size = layout::Integer::from_attr(&cx.tcx, ity).size(); - let actually = sign_extend(val, size) as i128; - (format!("{:?}", t), actually.to_string()) - } - ty::Uint(t) => { - let ity = attr::IntType::UnsignedInt(t); - let size = layout::Integer::from_attr(&cx.tcx, ity).size(); - let actually = truncate(val, size); - (format!("{:?}", t), actually.to_string()) - } - _ => bug!(), - }; - let mut err = cx.struct_span_lint( - OVERFLOWING_LITERALS, - expr.span, - &format!("literal out of range for {}", t), - ); - err.note(&format!( - "the literal `{}` (decimal `{}`) does not fit into \ - an `{}` and will become `{}{}`", - repr_str, val, t, actually, t - )); - if let Some(sugg_ty) = - get_type_suggestion(&cx.tables.node_type(expr.hir_id).sty, val, negative) - { - if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { - let (sans_suffix, _) = repr_str.split_at(pos); - err.span_suggestion( - expr.span, - &format!("consider using `{}` instead", sugg_ty), - format!("{}{}", sans_suffix, sugg_ty), - Applicability::MachineApplicable - ); - } else { - err.help(&format!("consider using `{}` instead", sugg_ty)); - } - } - - err.emit(); - } } } @@ -424,7 +503,9 @@ declare_lint! { "proper use of libc types in foreign modules" } -struct ImproperCTypesVisitor<'a, 'tcx: 'a> { +declare_lint_pass!(ImproperCTypes => [IMPROPER_CTYPES]); + +struct ImproperCTypesVisitor<'a, 'tcx> { cx: &'a LateContext<'a, 'tcx>, } @@ -438,42 +519,80 @@ enum FfiResult<'tcx> { }, } -/// Check if this enum can be safely exported based on the -/// "nullable pointer optimization". Currently restricted -/// to function pointers and references, but could be -/// expanded to cover NonZero raw pointers and newtypes. -/// FIXME: This duplicates code in codegen. -fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def: &'tcx ty::AdtDef, - substs: SubstsRef<'tcx>) - -> bool { - if def.variants.len() == 2 { - let data_idx; - - let zero = VariantIdx::new(0); - let one = VariantIdx::new(1); - - if def.variants[zero].fields.is_empty() { - data_idx = one; - } else if def.variants[one].fields.is_empty() { - data_idx = zero; - } else { - return false; - } +fn is_zst<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, ty: Ty<'tcx>) -> bool { + tcx.layout_of(tcx.param_env(did).and(ty)).map(|layout| layout.is_zst()).unwrap_or(false) +} - if def.variants[data_idx].fields.len() == 1 { - match def.variants[data_idx].fields[0].ty(tcx, substs).sty { - ty::FnPtr(_) => { - return true; +fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.sty { + ty::FnPtr(_) => true, + ty::Ref(..) => true, + ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => { + for field in field_def.all_fields() { + let field_ty = tcx.normalize_erasing_regions( + ParamEnv::reveal_all(), + field.ty(tcx, substs), + ); + if is_zst(tcx, field.did, field_ty) { + continue; } - ty::Ref(..) => { + + let attrs = tcx.get_attrs(field_def.did); + if attrs.iter().any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed)) || + ty_is_known_nonnull(tcx, field_ty) { return true; } - _ => {} } + + false } + _ => false, } - false +} + +/// Check if this enum can be safely exported based on the +/// "nullable pointer optimization". Currently restricted +/// to function pointers, references, core::num::NonZero*, +/// core::ptr::NonNull, and #[repr(transparent)] newtypes. +/// FIXME: This duplicates code in codegen. +fn is_repr_nullable_ptr<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + ty_def: &'tcx ty::AdtDef, + substs: SubstsRef<'tcx>, +) -> bool { + if ty_def.variants.len() != 2 { + return false; + } + + let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields; + let variant_fields = [get_variant_fields(0), get_variant_fields(1)]; + let fields = if variant_fields[0].is_empty() { + &variant_fields[1] + } else if variant_fields[1].is_empty() { + &variant_fields[0] + } else { + return false; + }; + + if fields.len() != 1 { + return false; + } + + let field_ty = fields[0].ty(tcx, substs); + if !ty_is_known_nonnull(tcx, field_ty) { + return false; + } + + // At this point, the field's type is known to be nonnull and the parent enum is Option-like. + // If the computed size for the field and the enum are different, the nonnull optimization isn't + // being applied (and we've got a problem somewhere). + let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, ParamEnv::reveal_all()).unwrap(); + if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) { + bug!("improper_ctypes: Option nonnull optimization not applied?"); + } + + true } impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { @@ -505,8 +624,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiUnsafe { ty: ty, reason: "this struct has unspecified layout", - help: Some("consider adding a #[repr(C)] or #[repr(transparent)] \ - attribute to this struct"), + help: Some("consider adding a `#[repr(C)]` or \ + `#[repr(transparent)]` attribute to this struct"), }; } @@ -528,14 +647,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ); // repr(transparent) types are allowed to have arbitrary ZSTs, not just // PhantomData -- skip checking all ZST fields - if def.repr.transparent() { - let is_zst = cx - .layout_of(cx.param_env(field.did).and(field_ty)) - .map(|layout| layout.is_zst()) - .unwrap_or(false); - if is_zst { - continue; - } + if def.repr.transparent() && is_zst(cx, field.did, field_ty) { + continue; } let r = self.check_type_for_ffi(cache, field_ty); match r { @@ -552,11 +665,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if all_phantom { FfiPhantom(ty) } else { FfiSafe } } AdtKind::Union => { - if !def.repr.c() { + if !def.repr.c() && !def.repr.transparent() { return FfiUnsafe { ty: ty, reason: "this union has unspecified layout", - help: Some("consider adding a #[repr(C)] attribute to this union"), + help: Some("consider adding a `#[repr(C)]` or \ + `#[repr(transparent)]` attribute to this union"), }; } @@ -574,6 +688,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ParamEnv::reveal_all(), field.ty(cx, substs), ); + // repr(transparent) types are allowed to have arbitrary ZSTs, not just + // PhantomData -- skip checking all ZST fields. + if def.repr.transparent() && is_zst(cx, field.did, field_ty) { + continue; + } let r = self.check_type_for_ffi(cache, field_ty); match r { FfiSafe => { @@ -596,14 +715,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Check for a repr() attribute to specify the size of the // discriminant. - if !def.repr.c() && def.repr.int.is_none() { + if !def.repr.c() && !def.repr.transparent() && def.repr.int.is_none() { // Special-case types like `Option`. - if !is_repr_nullable_ptr(cx, def, substs) { + if !is_repr_nullable_ptr(cx, ty, def, substs) { return FfiUnsafe { ty: ty, reason: "enum has no representation hint", - help: Some("consider adding a #[repr(...)] attribute \ - to this enum"), + help: Some("consider adding a `#[repr(C)]`, \ + `#[repr(transparent)]`, or integer `#[repr(...)]` \ + attribute to this enum"), }; } } @@ -611,11 +731,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Check the contained variants. for variant in &def.variants { for field in &variant.fields { - let arg = cx.normalize_erasing_regions( + let field_ty = cx.normalize_erasing_regions( ParamEnv::reveal_all(), field.ty(cx, substs), ); - let r = self.check_type_for_ffi(cache, arg); + // repr(transparent) types are allowed to have arbitrary ZSTs, not + // just PhantomData -- skip checking all ZST fields. + if def.repr.transparent() && is_zst(cx, field.did, field_ty) { + continue; + } + let r = self.check_type_for_ffi(cache, field_ty); match r { FfiSafe => {} FfiUnsafe { .. } => { @@ -762,12 +887,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - fn check_foreign_fn(&mut self, id: ast::NodeId, decl: &hir::FnDecl) { - let def_id = self.cx.tcx.hir().local_def_id(id); + fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl) { + let def_id = self.cx.tcx.hir().local_def_id_from_hir_id(id); let sig = self.cx.tcx.fn_sig(def_id); let sig = self.cx.tcx.erase_late_bound_regions(&sig); let inputs = if sig.c_variadic { - // Don't include the spoofed `VaList` in the functions list + // Don't include the spoofed `VaListImpl` in the functions list // of inputs. &sig.inputs()[..sig.inputs().len() - 1] } else { @@ -786,37 +911,24 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - fn check_foreign_static(&mut self, id: ast::NodeId, span: Span) { - let def_id = self.cx.tcx.hir().local_def_id(id); + fn check_foreign_static(&mut self, id: hir::HirId, span: Span) { + let def_id = self.cx.tcx.hir().local_def_id_from_hir_id(id); let ty = self.cx.tcx.type_of(def_id); self.check_type_for_ffi_and_report_errors(span, ty); } } -#[derive(Copy, Clone)] -pub struct ImproperCTypes; - -impl LintPass for ImproperCTypes { - fn name(&self) -> &'static str { - "ImproperCTypes" - } - - fn get_lints(&self) -> LintArray { - lint_array!(IMPROPER_CTYPES) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes { fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ForeignItem) { let mut vis = ImproperCTypesVisitor { cx }; - let abi = cx.tcx.hir().get_foreign_abi(it.id); + let abi = cx.tcx.hir().get_foreign_abi(it.hir_id); if abi != Abi::RustIntrinsic && abi != Abi::PlatformIntrinsic { match it.node { hir::ForeignItemKind::Fn(ref decl, _, _) => { - vis.check_foreign_fn(it.id, decl); + vis.check_foreign_fn(it.hir_id, decl); } hir::ForeignItemKind::Static(ref ty, _) => { - vis.check_foreign_static(it.id, ty.span); + vis.check_foreign_static(it.hir_id, ty.span); } hir::ForeignItemKind::Type => () } @@ -824,69 +936,65 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes { } } -pub struct VariantSizeDifferences; - -impl LintPass for VariantSizeDifferences { - fn name(&self) -> &'static str { - "VariantSizeDifferences" - } - - fn get_lints(&self) -> LintArray { - lint_array!(VARIANT_SIZE_DIFFERENCES) - } -} +declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { if let hir::ItemKind::Enum(ref enum_definition, _) = it.node { - let item_def_id = cx.tcx.hir().local_def_id(it.id); + let item_def_id = cx.tcx.hir().local_def_id_from_hir_id(it.hir_id); let t = cx.tcx.type_of(item_def_id); let ty = cx.tcx.erase_regions(&t); - match cx.layout_of(ty) { - Ok(layout) => { - let variants = &layout.variants; - if let layout::Variants::Tagged { ref variants, ref tag, .. } = variants { - let discr_size = tag.value.size(&cx.tcx).bytes(); - - debug!("enum `{}` is {} bytes large with layout:\n{:#?}", - t, layout.size.bytes(), layout); - - let (largest, slargest, largest_index) = enum_definition.variants - .iter() - .zip(variants) - .map(|(variant, variant_layout)| { - // Subtract the size of the enum discriminant. - let bytes = variant_layout.size.bytes().saturating_sub(discr_size); - - debug!("- variant `{}` is {} bytes large", - variant.node.ident, - bytes); - bytes - }) - .enumerate() - .fold((0, 0, 0), |(l, s, li), (idx, size)| if size > l { - (size, l, idx) - } else if size > s { - (l, size, li) - } else { - (l, s, li) - }); - - // We only warn if the largest variant is at least thrice as large as - // the second-largest. - if largest > slargest * 3 && slargest > 0 { - cx.span_lint(VARIANT_SIZE_DIFFERENCES, - enum_definition.variants[largest_index].span, - &format!("enum variant is more than three times \ - larger ({} bytes) than the next largest", - largest)); - } - } - } + let layout = match cx.layout_of(ty) { + Ok(layout) => layout, Err(ty::layout::LayoutError::Unknown(_)) => return, Err(err @ ty::layout::LayoutError::SizeOverflow(_)) => { bug!("failed to get layout for `{}`: {}", t, err); } + }; + let (variants, tag) = match layout.variants { + layout::Variants::Multiple { + discr_kind: layout::DiscriminantKind::Tag, + ref discr, + ref variants, + .. + } => (variants, discr), + _ => return, + }; + + let discr_size = tag.value.size(&cx.tcx).bytes(); + + debug!("enum `{}` is {} bytes large with layout:\n{:#?}", + t, layout.size.bytes(), layout); + + let (largest, slargest, largest_index) = enum_definition.variants + .iter() + .zip(variants) + .map(|(variant, variant_layout)| { + // Subtract the size of the enum discriminant. + let bytes = variant_layout.size.bytes().saturating_sub(discr_size); + + debug!("- variant `{}` is {} bytes large", + variant.node.ident, + bytes); + bytes + }) + .enumerate() + .fold((0, 0, 0), |(l, s, li), (idx, size)| if size > l { + (size, l, idx) + } else if size > s { + (l, size, li) + } else { + (l, s, li) + }); + + // We only warn if the largest variant is at least thrice as large as + // the second-largest. + if largest > slargest * 3 && slargest > 0 { + cx.span_lint(VARIANT_SIZE_DIFFERENCES, + enum_definition.variants[largest_index].span, + &format!("enum variant is more than three times \ + larger ({} bytes) than the next largest", + largest)); } } } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 86b8b276eafe5..2db2e0bc0da96 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -1,17 +1,19 @@ -use rustc::hir::def::Def; +use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::DefId; use rustc::lint; -use rustc::ty; +use rustc::ty::{self, Ty}; use rustc::ty::adjustment; +use rustc_data_structures::fx::FxHashMap; use lint::{LateContext, EarlyContext, LintContext, LintArray}; use lint::{LintPass, EarlyLintPass, LateLintPass}; use syntax::ast; use syntax::attr; use syntax::errors::Applicability; -use syntax::feature_gate::{BUILTIN_ATTRIBUTES, AttributeType}; +use syntax::feature_gate::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use syntax::print::pprust; -use syntax::symbol::keywords; +use syntax::symbol::{kw, sym}; +use syntax::symbol::Symbol; use syntax::util::parser; use syntax_pos::Span; @@ -32,18 +34,7 @@ declare_lint! { "unused result of an expression in a statement" } -#[derive(Copy, Clone)] -pub struct UnusedResults; - -impl LintPass for UnusedResults { - fn name(&self) -> &'static str { - "UnusedResults" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_MUST_USE, UNUSED_RESULTS) - } -} +declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt) { @@ -56,54 +47,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { return; } - let t = cx.tables.expr_ty(&expr); - let type_permits_lack_of_use = if t.is_unit() - || cx.tcx.is_ty_uninhabited_from( - cx.tcx.hir().get_module_parent_by_hir_id(expr.hir_id), t) - { - true - } else { - match t.sty { - ty::Adt(def, _) => check_must_use(cx, def.did, s.span, "", ""), - ty::Opaque(def, _) => { - let mut must_use = false; - for (predicate, _) in &cx.tcx.predicates_of(def).predicates { - if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate { - let trait_ref = poly_trait_predicate.skip_binder().trait_ref; - if check_must_use(cx, trait_ref.def_id, s.span, "implementer of ", "") { - must_use = true; - break; - } - } - } - must_use - } - ty::Dynamic(binder, _) => { - let mut must_use = false; - for predicate in binder.skip_binder().iter() { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { - if check_must_use(cx, trait_ref.def_id, s.span, "", " trait object") { - must_use = true; - break; - } - } - } - must_use - } - _ => false, - } - }; + let ty = cx.tables.expr_ty(&expr); + let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", false); let mut fn_warned = false; let mut op_warned = false; - let maybe_def = match expr.node { + let maybe_def_id = match expr.node { hir::ExprKind::Call(ref callee, _) => { match callee.node { hir::ExprKind::Path(ref qpath) => { - let def = cx.tables.qpath_def(qpath, callee.hir_id); - match def { - Def::Fn(_) | Def::Method(_) => Some(def), - // `Def::Local` if it was a closure, for which we + match cx.tables.qpath_res(qpath, callee.hir_id) { + Res::Def(DefKind::Fn, def_id) + | Res::Def(DefKind::Method, def_id) => Some(def_id), + // `Res::Local` if it was a closure, for which we // do not currently support must-use linting _ => None } @@ -112,13 +68,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { } }, hir::ExprKind::MethodCall(..) => { - cx.tables.type_dependent_defs().get(expr.hir_id).cloned() + cx.tables.type_dependent_def_id(expr.hir_id) }, _ => None }; - if let Some(def) = maybe_def { - let def_id = def.def_id(); - fn_warned = check_must_use(cx, def_id, s.span, "return value of ", ""); + if let Some(def_id) = maybe_def_id { + fn_warned = check_must_use_def(cx, def_id, s.span, "return value of ", ""); } else if type_permits_lack_of_use { // We don't warn about unused unit or uninhabited types. // (See https://github.com/rust-lang/rust/issues/43806 for details.) @@ -172,18 +127,117 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { cx.span_lint(UNUSED_RESULTS, s.span, "unused result"); } - fn check_must_use( + // Returns whether an error has been emitted (and thus another does not need to be later). + fn check_must_use_ty<'tcx>( + cx: &LateContext<'_, 'tcx>, + ty: Ty<'tcx>, + expr: &hir::Expr, + span: Span, + descr_pre: &str, + descr_post: &str, + plural: bool, + ) -> bool { + if ty.is_unit() || cx.tcx.is_ty_uninhabited_from( + cx.tcx.hir().get_module_parent(expr.hir_id), ty) + { + return true; + } + + let plural_suffix = if plural { "s" } else { "" }; + + match ty.sty { + ty::Adt(..) if ty.is_box() => { + let boxed_ty = ty.boxed_ty(); + let descr_pre = &format!("{}boxed ", descr_pre); + check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural) + } + ty::Adt(def, _) => { + check_must_use_def(cx, def.did, span, descr_pre, descr_post) + } + ty::Opaque(def, _) => { + let mut has_emitted = false; + for (predicate, _) in &cx.tcx.predicates_of(def).predicates { + if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate { + let trait_ref = poly_trait_predicate.skip_binder().trait_ref; + let def_id = trait_ref.def_id; + let descr_pre = &format!( + "{}implementer{} of ", + descr_pre, + plural_suffix, + ); + if check_must_use_def(cx, def_id, span, descr_pre, descr_post) { + has_emitted = true; + break; + } + } + } + has_emitted + } + ty::Dynamic(binder, _) => { + let mut has_emitted = false; + for predicate in binder.skip_binder().iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { + let def_id = trait_ref.def_id; + let descr_post = &format!( + " trait object{}{}", + plural_suffix, + descr_post, + ); + if check_must_use_def(cx, def_id, span, descr_pre, descr_post) { + has_emitted = true; + break; + } + } + } + has_emitted + } + ty::Tuple(ref tys) => { + let mut has_emitted = false; + let spans = if let hir::ExprKind::Tup(comps) = &expr.node { + debug_assert_eq!(comps.len(), tys.len()); + comps.iter().map(|e| e.span).collect() + } else { + vec![] + }; + for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() { + let descr_post = &format!(" in tuple element {}", i); + let span = *spans.get(i).unwrap_or(&span); + if check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, plural) { + has_emitted = true; + } + } + has_emitted + } + ty::Array(ty, len) => match len.assert_usize(cx.tcx) { + // If the array is definitely non-empty, we can do `#[must_use]` checking. + Some(n) if n != 0 => { + let descr_pre = &format!( + "{}array{} of ", + descr_pre, + plural_suffix, + ); + check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, true) + } + // Otherwise, we don't lint, to avoid false positives. + _ => false, + } + _ => false, + } + } + + // Returns whether an error has been emitted (and thus another does not need to be later). + fn check_must_use_def( cx: &LateContext<'_, '_>, def_id: DefId, - sp: Span, + span: Span, descr_pre_path: &str, descr_post_path: &str, ) -> bool { for attr in cx.tcx.get_attrs(def_id).iter() { - if attr.check_name("must_use") { + if attr.check_name(sym::must_use) { let msg = format!("unused {}`{}`{} that must be used", - descr_pre_path, cx.tcx.item_path_str(def_id), descr_post_path); - let mut err = cx.struct_span_lint(UNUSED_MUST_USE, sp, &msg); + descr_pre_path, cx.tcx.def_path_str(def_id), descr_post_path); + let mut err = cx.struct_span_lint(UNUSED_MUST_USE, span, &msg); // check for #[must_use = "..."] if let Some(note) = attr.value_str() { err.note(¬e.as_str()); @@ -203,18 +257,7 @@ declare_lint! { "path statements with no effect" } -#[derive(Copy, Clone)] -pub struct PathStatements; - -impl LintPass for PathStatements { - fn name(&self) -> &'static str { - "PathStatements" - } - - fn get_lints(&self) -> LintArray { - lint_array!(PATH_STATEMENTS) - } -} +declare_lint_pass!(PathStatements => [PATH_STATEMENTS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements { fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt) { @@ -233,53 +276,57 @@ declare_lint! { } #[derive(Copy, Clone)] -pub struct UnusedAttributes; - -impl LintPass for UnusedAttributes { - fn name(&self) -> &'static str { - "UnusedAttributes" - } +pub struct UnusedAttributes { + builtin_attributes: &'static FxHashMap, +} - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_ATTRIBUTES) +impl UnusedAttributes { + pub fn new() -> Self { + UnusedAttributes { + builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP, + } } } +impl_lint_pass!(UnusedAttributes => [UNUSED_ATTRIBUTES]); + impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { fn check_attribute(&mut self, cx: &LateContext<'_, '_>, attr: &ast::Attribute) { debug!("checking attribute: {:?}", attr); - // Note that check_name() marks the attribute as used if it matches. - for &(name, ty, ..) in BUILTIN_ATTRIBUTES { + + let attr_info = attr.ident().and_then(|ident| self.builtin_attributes.get(&ident.name)); + + if let Some(&&(name, ty, ..)) = attr_info { match ty { - AttributeType::Whitelisted if attr.check_name(name) => { + AttributeType::Whitelisted => { debug!("{:?} is Whitelisted", name); - break; + return; } _ => (), } } let plugin_attributes = cx.sess().plugin_attributes.borrow_mut(); - for &(ref name, ty) in plugin_attributes.iter() { - if ty == AttributeType::Whitelisted && attr.check_name(&name) { + for &(name, ty) in plugin_attributes.iter() { + if ty == AttributeType::Whitelisted && attr.check_name(name) { debug!("{:?} (plugin attr) is whitelisted with ty {:?}", name, ty); break; } } - let name = attr.name(); + let name = attr.name_or_empty(); if !attr::is_used(attr) { debug!("Emitting warning for: {:?}", attr); cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); // Is it a builtin attribute that must be used at the crate level? - let known_crate = BUILTIN_ATTRIBUTES.iter() - .find(|&&(builtin, ty, ..)| name == builtin && ty == AttributeType::CrateLevel) - .is_some(); + let known_crate = attr_info.map(|&&(_, ty, ..)| { + ty == AttributeType::CrateLevel + }).unwrap_or(false); // Has a plugin registered this attribute as one that must be used at // the crate level? let plugin_crate = plugin_attributes.iter() - .find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t) + .find(|&&(x, t)| name == x && AttributeType::CrateLevel == t) .is_some(); if known_crate || plugin_crate { let msg = match attr.style { @@ -303,8 +350,7 @@ declare_lint! { "`if`, `match`, `while` and `return` do not need parentheses" } -#[derive(Copy, Clone)] -pub struct UnusedParens; +declare_lint_pass!(UnusedParens => [UNUSED_PARENS]); impl UnusedParens { fn check_unused_parens_expr(&self, @@ -312,20 +358,28 @@ impl UnusedParens { value: &ast::Expr, msg: &str, followed_by_block: bool) { - if let ast::ExprKind::Paren(ref inner) = value.node { - let necessary = followed_by_block && match inner.node { - ast::ExprKind::Ret(_) | ast::ExprKind::Break(..) => true, - _ => parser::contains_exterior_struct_lit(&inner), - }; - if !necessary { - let expr_text = if let Ok(snippet) = cx.sess().source_map() - .span_to_snippet(value.span) { - snippet - } else { - pprust::expr_to_string(value) - }; - Self::remove_outer_parens(cx, value.span, &expr_text, msg); + match value.node { + ast::ExprKind::Paren(ref inner) => { + let necessary = followed_by_block && match inner.node { + ast::ExprKind::Ret(_) | ast::ExprKind::Break(..) => true, + _ => parser::contains_exterior_struct_lit(&inner), + }; + if !necessary { + let expr_text = if let Ok(snippet) = cx.sess().source_map() + .span_to_snippet(value.span) { + snippet + } else { + pprust::expr_to_string(value) + }; + Self::remove_outer_parens(cx, value.span, &expr_text, msg); + } } + ast::ExprKind::Let(_, ref expr) => { + // FIXME(#60336): Properly handle `let true = (false && true)` + // actually needing the parenthesis. + self.check_unused_parens_expr(cx, expr, "`let` head expression", followed_by_block); + } + _ => {} } } @@ -381,24 +435,12 @@ impl UnusedParens { } } -impl LintPass for UnusedParens { - fn name(&self) -> &'static str { - "UnusedParens" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_PARENS) - } -} - impl EarlyLintPass for UnusedParens { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { use syntax::ast::ExprKind::*; let (value, msg, followed_by_block) = match e.node { If(ref cond, ..) => (cond, "`if` condition", true), While(ref cond, ..) => (cond, "`while` condition", true), - IfLet(_, ref cond, ..) => (cond, "`if let` head expression", true), - WhileLet(_, ref cond, ..) => (cond, "`while let` head expression", true), ForLoop(_, ref cond, ..) => (cond, "`for` head expression", true), Match(ref head, _) => (head, "`match` head expression", true), Ret(Some(ref value)) => (value, "`return` value", false), @@ -419,9 +461,8 @@ impl EarlyLintPass for UnusedParens { // trigger in situations that macro authors shouldn't have to care about, e.g., // when a parenthesized token tree matched in one macro expansion is matched as // an expression in another and used as a fn/method argument (Issue #47775) - if e.span.ctxt().outer().expn_info() - .map_or(false, |info| info.call_site.ctxt().outer() - .expn_info().is_some()) { + if e.span.ctxt().outer_expn_info() + .map_or(false, |info| info.call_site.ctxt().outer_expn_info().is_some()) { return; } let msg = format!("{} argument", call_kind); @@ -434,7 +475,7 @@ impl EarlyLintPass for UnusedParens { self.check_unused_parens_expr(cx, &value, msg, followed_by_block); } - fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat, _: &mut bool) { + fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) { use ast::PatKind::{Paren, Range}; // The lint visitor will visit each subpattern of `p`. We do not want to lint any range // pattern no matter where it occurs in the pattern. For something like `&(a..=b)`, there @@ -463,8 +504,7 @@ declare_lint! { "unnecessary braces around an imported item" } -#[derive(Copy, Clone)] -pub struct UnusedImportBraces; +declare_lint_pass!(UnusedImportBraces => [UNUSED_IMPORT_BRACES]); impl UnusedImportBraces { fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &ast::Item) { @@ -484,7 +524,7 @@ impl UnusedImportBraces { match items[0].0.kind { ast::UseTreeKind::Simple(rename, ..) => { let orig_ident = items[0].0.prefix.segments.last().unwrap().ident; - if orig_ident.name == keywords::SelfLower.name() { + if orig_ident.name == kw::SelfLower { return; } node_ident = rename.unwrap_or(orig_ident); @@ -503,16 +543,6 @@ impl UnusedImportBraces { } } -impl LintPass for UnusedImportBraces { - fn name(&self) -> &'static str { - "UnusedImportBraces" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_IMPORT_BRACES) - } -} - impl EarlyLintPass for UnusedImportBraces { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { if let ast::ItemKind::Use(ref use_tree) = item.node { @@ -527,18 +557,7 @@ declare_lint! { "detects unnecessary allocations that can be eliminated" } -#[derive(Copy, Clone)] -pub struct UnusedAllocation; - -impl LintPass for UnusedAllocation { - fn name(&self) -> &'static str { - "UnusedAllocation" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_ALLOCATION) - } -} +declare_lint_pass!(UnusedAllocation => [UNUSED_ALLOCATION]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation { fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr) { diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 1d2e1d9ac6210..d31195762368b 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -234,6 +234,21 @@ fn main() { } } + // Some LLVM linker flags (-L and -l) may be needed even when linking + // librustc_llvm, for example when using static libc++, we may need to + // manually specify the library search path and -ldl -lpthread as link + // dependencies. + let llvm_linker_flags = env::var_os("LLVM_LINKER_FLAGS"); + if let Some(s) = llvm_linker_flags { + for lib in s.into_string().unwrap().split_whitespace() { + if lib.starts_with("-l") { + println!("cargo:rustc-link-lib={}", &lib[2..]); + } else if lib.starts_with("-L") { + println!("cargo:rustc-link-search=native={}", &lib[2..]); + } + } + } + let llvm_static_stdcpp = env::var_os("LLVM_STATIC_STDCPP"); let llvm_use_libcxx = env::var_os("LLVM_USE_LIBCXX"); diff --git a/src/librustc_lsan/Cargo.toml b/src/librustc_lsan/Cargo.toml index 9ad53ee6d0958..9a24361f44e64 100644 --- a/src/librustc_lsan/Cargo.toml +++ b/src/librustc_lsan/Cargo.toml @@ -12,7 +12,7 @@ test = false [build-dependencies] build_helper = { path = "../build_helper" } -cmake = "0.1.18" +cmake = "0.1.38" [dependencies] alloc = { path = "../liballoc" } diff --git a/src/librustc_macros/Cargo.toml b/src/librustc_macros/Cargo.toml new file mode 100644 index 0000000000000..f989ebc6dfd8e --- /dev/null +++ b/src/librustc_macros/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rustc_macros" +version = "0.1.0" +authors = ["The Rust Project Developers"] +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +synstructure = "0.10.2" +syn = { version = "0.15.22", features = ["full"] } +proc-macro2 = "0.4.24" +quote = "0.6.10" +itertools = "0.8" diff --git a/src/librustc_macros/src/hash_stable.rs b/src/librustc_macros/src/hash_stable.rs new file mode 100644 index 0000000000000..6d7590c7d1cd3 --- /dev/null +++ b/src/librustc_macros/src/hash_stable.rs @@ -0,0 +1,87 @@ +use synstructure; +use syn::{self, Meta, NestedMeta, parse_quote}; +use proc_macro2::{self, Ident}; +use quote::quote; + +struct Attributes { + ignore: bool, + project: Option, +} + +fn parse_attributes(field: &syn::Field) -> Attributes { + let mut attrs = Attributes { + ignore: false, + project: None, + }; + for attr in &field.attrs { + if let Ok(meta) = attr.parse_meta() { + if &meta.name().to_string() != "stable_hasher" { + continue; + } + let mut any_attr = false; + if let Meta::List(list) = meta { + for nested in list.nested.iter() { + if let NestedMeta::Meta(meta) = nested { + if &meta.name().to_string() == "ignore" { + attrs.ignore = true; + any_attr = true; + } + if &meta.name().to_string() == "project" { + if let Meta::List(list) = meta { + if let Some(nested) = list.nested.iter().next() { + if let NestedMeta::Meta(meta) = nested { + attrs.project = Some(meta.name()); + any_attr = true; + } + } + } + } + } + } + } + if !any_attr { + panic!("error parsing stable_hasher"); + } + } + } + attrs +} + +pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + let generic: syn::GenericParam = parse_quote!('__ctx); + s.add_bounds(synstructure::AddBounds::Generics); + s.add_impl_generic(generic); + let body = s.each(|bi| { + let attrs = parse_attributes(bi.ast()); + if attrs.ignore { + quote!{} + } else if let Some(project) = attrs.project { + quote!{ + &#bi.#project.hash_stable(__hcx, __hasher); + } + } else { + quote!{ + #bi.hash_stable(__hcx, __hasher); + } + } + }); + + let discriminant = match s.ast().data { + syn::Data::Enum(_) => quote! { + ::std::mem::discriminant(self).hash_stable(__hcx, __hasher); + }, + syn::Data::Struct(_) => quote! {}, + syn::Data::Union(_) => panic!("cannot derive on union"), + }; + + s.bound_impl(quote!(::rustc_data_structures::stable_hasher::HashStable + <::rustc::ich::StableHashingContext<'__ctx>>), quote!{ + fn hash_stable<__W: ::rustc_data_structures::stable_hasher::StableHasherResult>( + &self, + __hcx: &mut ::rustc::ich::StableHashingContext<'__ctx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<__W>) { + #discriminant + match *self { #body } + } + }) +} diff --git a/src/librustc_macros/src/lib.rs b/src/librustc_macros/src/lib.rs new file mode 100644 index 0000000000000..e9cf7bca25c4b --- /dev/null +++ b/src/librustc_macros/src/lib.rs @@ -0,0 +1,26 @@ +#![feature(proc_macro_hygiene)] +#![deny(rust_2018_idioms)] + +#![recursion_limit="128"] + +extern crate proc_macro; + +use synstructure::decl_derive; + +use proc_macro::TokenStream; + +mod hash_stable; +mod query; +mod symbols; + +#[proc_macro] +pub fn rustc_queries(input: TokenStream) -> TokenStream { + query::rustc_queries(input) +} + +#[proc_macro] +pub fn symbols(input: TokenStream) -> TokenStream { + symbols::symbols(input) +} + +decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive); diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs new file mode 100644 index 0000000000000..d47bd0580d6ca --- /dev/null +++ b/src/librustc_macros/src/query.rs @@ -0,0 +1,568 @@ +use proc_macro::TokenStream; +use proc_macro2::{TokenTree, Delimiter}; +use syn::{ + Token, Ident, Type, Attribute, ReturnType, Expr, Block, Error, + braced, parenthesized, parse_macro_input, +}; +use syn::spanned::Spanned; +use syn::parse::{Result, Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn; +use quote::quote; +use itertools::Itertools; + +#[allow(non_camel_case_types)] +mod kw { + syn::custom_keyword!(query); +} + +/// Ident or a wildcard `_`. +struct IdentOrWild(Ident); + +impl Parse for IdentOrWild { + fn parse(input: ParseStream<'_>) -> Result { + Ok(if input.peek(Token![_]) { + let underscore = input.parse::()?; + IdentOrWild(Ident::new("_", underscore.span())) + } else { + IdentOrWild(input.parse()?) + }) + } +} + +/// A modifier for a query +enum QueryModifier { + /// The description of the query. + Desc(Option, Punctuated), + + /// Cache the query to disk if the `Expr` returns true. + Cache(Option<(IdentOrWild, IdentOrWild)>, Block), + + /// Custom code to load the query from disk. + LoadCached(Ident, Ident, Block), + + /// A cycle error for this query aborting the compilation with a fatal error. + FatalCycle, + + /// A cycle error results in a delay_bug call + CycleDelayBug, + + /// Don't hash the result, instead just mark a query red if it runs + NoHash, + + /// Don't force the query + NoForce, + + /// Generate a dep node based on the dependencies of the query + Anon, + + /// Always evaluate the query, ignoring its depdendencies + EvalAlways, +} + +impl Parse for QueryModifier { + fn parse(input: ParseStream<'_>) -> Result { + let modifier: Ident = input.parse()?; + if modifier == "desc" { + // Parse a description modifier like: + // `desc { |tcx| "foo {}", tcx.item_path(key) }` + let attr_content; + braced!(attr_content in input); + let tcx = if attr_content.peek(Token![|]) { + attr_content.parse::()?; + let tcx = attr_content.parse()?; + attr_content.parse::()?; + Some(tcx) + } else { + None + }; + let desc = attr_content.parse_terminated(Expr::parse)?; + Ok(QueryModifier::Desc(tcx, desc)) + } else if modifier == "cache_on_disk_if" { + // Parse a cache modifier like: + // `cache(tcx, value) { |tcx| key.is_local() }` + let has_args = if let TokenTree::Group(group) = input.fork().parse()? { + group.delimiter() == Delimiter::Parenthesis + } else { + false + }; + let args = if has_args { + let args; + parenthesized!(args in input); + let tcx = args.parse()?; + args.parse::()?; + let value = args.parse()?; + Some((tcx, value)) + } else { + None + }; + let block = input.parse()?; + Ok(QueryModifier::Cache(args, block)) + } else if modifier == "load_cached" { + // Parse a load_cached modifier like: + // `load_cached(tcx, id) { tcx.queries.on_disk_cache.try_load_query_result(tcx, id) }` + let args; + parenthesized!(args in input); + let tcx = args.parse()?; + args.parse::()?; + let id = args.parse()?; + let block = input.parse()?; + Ok(QueryModifier::LoadCached(tcx, id, block)) + } else if modifier == "fatal_cycle" { + Ok(QueryModifier::FatalCycle) + } else if modifier == "cycle_delay_bug" { + Ok(QueryModifier::CycleDelayBug) + } else if modifier == "no_hash" { + Ok(QueryModifier::NoHash) + } else if modifier == "no_force" { + Ok(QueryModifier::NoForce) + } else if modifier == "anon" { + Ok(QueryModifier::Anon) + } else if modifier == "eval_always" { + Ok(QueryModifier::EvalAlways) + } else { + Err(Error::new(modifier.span(), "unknown query modifier")) + } + } +} + +/// Ensures only doc comment attributes are used +fn check_attributes(attrs: Vec) -> Result<()> { + for attr in attrs { + if !attr.path.is_ident("doc") { + return Err(Error::new(attr.span(), "attributes not supported on queries")); + } + } + Ok(()) +} + +/// A compiler query. `query ... { ... }` +struct Query { + modifiers: List, + name: Ident, + key: IdentOrWild, + arg: Type, + result: ReturnType, +} + +impl Parse for Query { + fn parse(input: ParseStream<'_>) -> Result { + check_attributes(input.call(Attribute::parse_outer)?)?; + + // Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>` + input.parse::()?; + let name: Ident = input.parse()?; + let arg_content; + parenthesized!(arg_content in input); + let key = arg_content.parse()?; + arg_content.parse::()?; + let arg = arg_content.parse()?; + let result = input.parse()?; + + // Parse the query modifiers + let content; + braced!(content in input); + let modifiers = content.parse()?; + + Ok(Query { + modifiers, + name, + key, + arg, + result, + }) + } +} + +/// A type used to greedily parse another type until the input is empty. +struct List(Vec); + +impl Parse for List { + fn parse(input: ParseStream<'_>) -> Result { + let mut list = Vec::new(); + while !input.is_empty() { + list.push(input.parse()?); + } + Ok(List(list)) + } +} + +/// A named group containing queries. +struct Group { + name: Ident, + queries: List, +} + +impl Parse for Group { + fn parse(input: ParseStream<'_>) -> Result { + let name: Ident = input.parse()?; + let content; + braced!(content in input); + Ok(Group { + name, + queries: content.parse()?, + }) + } +} + +struct QueryModifiers { + /// The description of the query. + desc: Option<(Option, Punctuated)>, + + /// Cache the query to disk if the `Block` returns true. + cache: Option<(Option<(IdentOrWild, IdentOrWild)>, Block)>, + + /// Custom code to load the query from disk. + load_cached: Option<(Ident, Ident, Block)>, + + /// A cycle error for this query aborting the compilation with a fatal error. + fatal_cycle: bool, + + /// A cycle error results in a delay_bug call + cycle_delay_bug: bool, + + /// Don't hash the result, instead just mark a query red if it runs + no_hash: bool, + + /// Don't force the query + no_force: bool, + + /// Generate a dep node based on the dependencies of the query + anon: bool, + + // Always evaluate the query, ignoring its depdendencies + eval_always: bool, +} + +/// Process query modifiers into a struct, erroring on duplicates +fn process_modifiers(query: &mut Query) -> QueryModifiers { + let mut load_cached = None; + let mut cache = None; + let mut desc = None; + let mut fatal_cycle = false; + let mut cycle_delay_bug = false; + let mut no_hash = false; + let mut no_force = false; + let mut anon = false; + let mut eval_always = false; + for modifier in query.modifiers.0.drain(..) { + match modifier { + QueryModifier::LoadCached(tcx, id, block) => { + if load_cached.is_some() { + panic!("duplicate modifier `load_cached` for query `{}`", query.name); + } + load_cached = Some((tcx, id, block)); + } + QueryModifier::Cache(args, expr) => { + if cache.is_some() { + panic!("duplicate modifier `cache` for query `{}`", query.name); + } + cache = Some((args, expr)); + } + QueryModifier::Desc(tcx, list) => { + if desc.is_some() { + panic!("duplicate modifier `desc` for query `{}`", query.name); + } + desc = Some((tcx, list)); + } + QueryModifier::FatalCycle => { + if fatal_cycle { + panic!("duplicate modifier `fatal_cycle` for query `{}`", query.name); + } + fatal_cycle = true; + } + QueryModifier::CycleDelayBug => { + if cycle_delay_bug { + panic!("duplicate modifier `cycle_delay_bug` for query `{}`", query.name); + } + cycle_delay_bug = true; + } + QueryModifier::NoHash => { + if no_hash { + panic!("duplicate modifier `no_hash` for query `{}`", query.name); + } + no_hash = true; + } + QueryModifier::NoForce => { + if no_force { + panic!("duplicate modifier `no_force` for query `{}`", query.name); + } + no_force = true; + } + QueryModifier::Anon => { + if anon { + panic!("duplicate modifier `anon` for query `{}`", query.name); + } + anon = true; + } + QueryModifier::EvalAlways => { + if eval_always { + panic!("duplicate modifier `eval_always` for query `{}`", query.name); + } + eval_always = true; + } + } + } + QueryModifiers { + load_cached, + cache, + desc, + fatal_cycle, + cycle_delay_bug, + no_hash, + no_force, + anon, + eval_always, + } +} + +/// Add the impl of QueryDescription for the query to `impls` if one is requested +fn add_query_description_impl( + query: &Query, + modifiers: QueryModifiers, + impls: &mut proc_macro2::TokenStream, +) { + let name = &query.name; + let arg = &query.arg; + let key = &query.key.0; + + // Find out if we should cache the query on disk + let cache = modifiers.cache.as_ref().map(|(args, expr)| { + let try_load_from_disk = if let Some((tcx, id, block)) = modifiers.load_cached.as_ref() { + // Use custom code to load the query from disk + quote! { + #[inline] + fn try_load_from_disk( + #tcx: TyCtxt<'tcx>, + #id: SerializedDepNodeIndex + ) -> Option { + #block + } + } + } else { + // Use the default code to load the query from disk + quote! { + #[inline] + fn try_load_from_disk( + tcx: TyCtxt<'tcx>, + id: SerializedDepNodeIndex + ) -> Option { + tcx.queries.on_disk_cache.try_load_query_result(tcx, id) + } + } + }; + + let tcx = args.as_ref().map(|t| { + let t = &(t.0).0; + quote! { #t } + }).unwrap_or(quote! { _ }); + let value = args.as_ref().map(|t| { + let t = &(t.1).0; + quote! { #t } + }).unwrap_or(quote! { _ }); + quote! { + #[inline] + #[allow(unused_variables)] + fn cache_on_disk( + #tcx: TyCtxt<'tcx>, + #key: Self::Key, + #value: Option<&Self::Value> + ) -> bool { + #expr + } + + #try_load_from_disk + } + }); + + if cache.is_none() && modifiers.load_cached.is_some() { + panic!("load_cached modifier on query `{}` without a cache modifier", name); + } + + let desc = modifiers.desc.as_ref().map(|(tcx, desc)| { + let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ }); + quote! { + #[allow(unused_variables)] + fn describe( + #tcx: TyCtxt<'_>, + #key: #arg, + ) -> Cow<'static, str> { + format!(#desc).into() + } + } + }); + + if desc.is_some() || cache.is_some() { + let cache = cache.unwrap_or(quote! {}); + let desc = desc.unwrap_or(quote! {}); + + impls.extend(quote! { + impl<'tcx> QueryDescription<'tcx> for queries::#name<'tcx> { + #desc + #cache + } + }); + } +} + +pub fn rustc_queries(input: TokenStream) -> TokenStream { + let groups = parse_macro_input!(input as List); + + let mut query_stream = quote! {}; + let mut query_description_stream = quote! {}; + let mut dep_node_def_stream = quote! {}; + let mut dep_node_force_stream = quote! {}; + let mut try_load_from_on_disk_cache_stream = quote! {}; + let mut no_force_queries = Vec::new(); + + for group in groups.0 { + let mut group_stream = quote! {}; + for mut query in group.queries.0 { + let modifiers = process_modifiers(&mut query); + let name = &query.name; + let arg = &query.arg; + let result_full = &query.result; + let result = match query.result { + ReturnType::Default => quote! { -> () }, + _ => quote! { #result_full }, + }; + + if modifiers.cache.is_some() && !modifiers.no_force { + try_load_from_on_disk_cache_stream.extend(quote! { + DepKind::#name => { + debug_assert!(tcx.dep_graph + .node_color(self) + .map(|c| c.is_green()) + .unwrap_or(false)); + + let key = RecoverKey::recover(tcx.global_tcx(), self).unwrap(); + if queries::#name::cache_on_disk(tcx.global_tcx(), key, None) { + let _ = tcx.#name(key); + } + } + }); + } + + let mut attributes = Vec::new(); + + // Pass on the fatal_cycle modifier + if modifiers.fatal_cycle { + attributes.push(quote! { fatal_cycle }); + }; + // Pass on the cycle_delay_bug modifier + if modifiers.cycle_delay_bug { + attributes.push(quote! { cycle_delay_bug }); + }; + // Pass on the no_hash modifier + if modifiers.no_hash { + attributes.push(quote! { no_hash }); + }; + // Pass on the anon modifier + if modifiers.anon { + attributes.push(quote! { anon }); + }; + // Pass on the eval_always modifier + if modifiers.eval_always { + attributes.push(quote! { eval_always }); + }; + + let mut attribute_stream = quote! {}; + for e in attributes.into_iter().intersperse(quote! {,}) { + attribute_stream.extend(e); + } + + // Add the query to the group + group_stream.extend(quote! { + [#attribute_stream] fn #name: #name(#arg) #result, + }); + + // Create a dep node for the query + dep_node_def_stream.extend(quote! { + [#attribute_stream] #name(#arg), + }); + + if modifiers.no_force { + no_force_queries.push(name.clone()); + } else { + // Add a match arm to force the query given the dep node + dep_node_force_stream.extend(quote! { + DepKind::#name => { + if let Some(key) = RecoverKey::recover($tcx, $dep_node) { + force_ex!($tcx, #name, key); + } else { + return false; + } + } + }); + } + + add_query_description_impl( + &query, + modifiers, + &mut query_description_stream, + ); + } + let name = &group.name; + query_stream.extend(quote! { + #name { #group_stream }, + }); + } + + // Add an arm for the no force queries to panic when trying to force them + for query in no_force_queries { + dep_node_force_stream.extend(quote! { + DepKind::#query | + }); + } + dep_node_force_stream.extend(quote! { + DepKind::Null => { + bug!("Cannot force dep node: {:?}", $dep_node) + } + }); + + TokenStream::from(quote! { + macro_rules! rustc_query_append { + ([$($macro:tt)*][$($other:tt)*]) => { + $($macro)* { + $($other)* + + #query_stream + + } + } + } + macro_rules! rustc_dep_node_append { + ([$($macro:tt)*][$($other:tt)*]) => { + $($macro)*( + $($other)* + + #dep_node_def_stream + ); + } + } + macro_rules! rustc_dep_node_force { + ([$dep_node:expr, $tcx:expr] $($other:tt)*) => { + match $dep_node.kind { + $($other)* + + #dep_node_force_stream + } + } + } + #query_description_stream + + impl DepNode { + /// Check whether the query invocation corresponding to the given + /// DepNode is eligible for on-disk-caching. If so, this is method + /// will execute the query corresponding to the given DepNode. + /// Also, as a sanity check, it expects that the corresponding query + /// invocation has been marked as green already. + pub fn try_load_from_on_disk_cache(&self, tcx: TyCtxt<'_>) { + match self.kind { + #try_load_from_on_disk_cache_stream + _ => (), + } + } + } + }) +} diff --git a/src/librustc_macros/src/symbols.rs b/src/librustc_macros/src/symbols.rs new file mode 100644 index 0000000000000..1f6e54807d8cb --- /dev/null +++ b/src/librustc_macros/src/symbols.rs @@ -0,0 +1,185 @@ +use proc_macro::TokenStream; +use syn::{ + Token, Ident, LitStr, + braced, parse_macro_input, +}; +use syn::parse::{Result, Parse, ParseStream}; +use syn; +use std::collections::HashSet; +use quote::quote; + +#[allow(non_camel_case_types)] +mod kw { + syn::custom_keyword!(Keywords); + syn::custom_keyword!(Symbols); +} + +struct Keyword { + name: Ident, + value: LitStr, +} + +impl Parse for Keyword { + fn parse(input: ParseStream<'_>) -> Result { + let name = input.parse()?; + input.parse::()?; + let value = input.parse()?; + input.parse::()?; + + Ok(Keyword { + name, + value, + }) + } +} + +struct Symbol { + name: Ident, + value: Option, +} + +impl Parse for Symbol { + fn parse(input: ParseStream<'_>) -> Result { + let name = input.parse()?; + let value = match input.parse::() { + Ok(_) => Some(input.parse()?), + Err(_) => None, + }; + input.parse::()?; + + Ok(Symbol { + name, + value, + }) + } +} + +/// A type used to greedily parse another type until the input is empty. +struct List(Vec); + +impl Parse for List { + fn parse(input: ParseStream<'_>) -> Result { + let mut list = Vec::new(); + while !input.is_empty() { + list.push(input.parse()?); + } + Ok(List(list)) + } +} + +struct Input { + keywords: List, + symbols: List, +} + +impl Parse for Input { + fn parse(input: ParseStream<'_>) -> Result { + input.parse::()?; + let content; + braced!(content in input); + let keywords = content.parse()?; + + input.parse::()?; + let content; + braced!(content in input); + let symbols = content.parse()?; + + Ok(Input { + keywords, + symbols, + }) + } +} + +pub fn symbols(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as Input); + + let mut keyword_stream = quote! {}; + let mut symbols_stream = quote! {}; + let mut digits_stream = quote! {}; + let mut prefill_stream = quote! {}; + let mut counter = 0u32; + let mut keys = HashSet::::new(); + + let mut check_dup = |str: &str| { + if !keys.insert(str.to_string()) { + panic!("Symbol `{}` is duplicated", str); + } + }; + + // Generate the listed keywords. + for keyword in &input.keywords.0 { + let name = &keyword.name; + let value = &keyword.value; + check_dup(&value.value()); + prefill_stream.extend(quote! { + #value, + }); + keyword_stream.extend(quote! { + pub const #name: Symbol = Symbol::new(#counter); + }); + counter += 1; + } + + // Generate the listed symbols. + for symbol in &input.symbols.0 { + let name = &symbol.name; + let value = match &symbol.value { + Some(value) => value.value(), + None => name.to_string(), + }; + check_dup(&value); + prefill_stream.extend(quote! { + #value, + }); + symbols_stream.extend(quote! { + pub const #name: Symbol = Symbol::new(#counter); + }); + counter += 1; + } + + // Generate symbols for the strings "0", "1", ..., "9". + for n in 0..10 { + let n = n.to_string(); + check_dup(&n); + prefill_stream.extend(quote! { + #n, + }); + digits_stream.extend(quote! { + Symbol::new(#counter), + }); + counter += 1; + } + + let tt = TokenStream::from(quote! { + macro_rules! keywords { + () => { + #keyword_stream + } + } + + macro_rules! symbols { + () => { + #symbols_stream + + pub const digits_array: &[Symbol; 10] = &[ + #digits_stream + ]; + } + } + + impl Interner { + pub fn fresh() -> Self { + Interner::prefill(&[ + #prefill_stream + ]) + } + } + }); + + // To see the generated code generated, uncomment this line, recompile, and + // run the resulting output through `rustfmt`. + //eprintln!("{}", tt); + + tt +} diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index e234f4f880703..76aba33b6a404 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -13,6 +13,7 @@ crate-type = ["dylib"] flate2 = "1.0" log = "0.4" memmap = "0.6" +smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } errors = { path = "../librustc_errors", package = "rustc_errors" } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 6f2718381c2ec..2073b317939d7 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -26,8 +26,8 @@ use std::{cmp, fs}; use syntax::ast; use syntax::attr; -use syntax::ext::base::SyntaxExtension; -use syntax::symbol::Symbol; +use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind}; +use syntax::symbol::{Symbol, sym}; use syntax::visit; use syntax::{span_err, span_fatal}; use syntax_pos::{Span, DUMMY_SP}; @@ -95,7 +95,7 @@ enum LoadError<'a> { impl<'a> LoadError<'a> { fn report(self) -> ! { match self { - LoadError::LocatorError(mut locate_ctxt) => locate_ctxt.report_errs(), + LoadError::LocatorError(locate_ctxt) => locate_ctxt.report_errs(), } } } @@ -131,9 +131,9 @@ impl<'a> CrateLoader<'a> { // `source` stores paths which are normalized which may be different // from the strings on the command line. let source = &self.cstore.get_crate_data(cnum).source; - if let Some(locs) = self.sess.opts.externs.get(&*name.as_str()) { + if let Some(entry) = self.sess.opts.externs.get(&*name.as_str()) { // Only use `--extern crate_name=path` here, not `--extern crate_name`. - let found = locs.iter().filter_map(|l| l.as_ref()).any(|l| { + let found = entry.locations.iter().filter_map(|l| l.as_ref()).any(|l| { let l = fs::canonicalize(l).ok(); source.dylib.as_ref().map(|p| &p.0) == l.as_ref() || source.rlib.as_ref().map(|p| &p.0) == l.as_ref() @@ -162,7 +162,7 @@ impl<'a> CrateLoader<'a> { fn verify_no_symbol_conflicts(&self, span: Span, - root: &CrateRoot) { + root: &CrateRoot<'_>) { // Check for (potential) conflicts with the local crate if self.local_crate_name == root.name && self.sess.local_crate_disambiguator() == root.disambiguator { @@ -188,17 +188,27 @@ impl<'a> CrateLoader<'a> { }); } - fn register_crate(&mut self, - root: &Option, - ident: Symbol, - span: Span, - lib: Library, - dep_kind: DepKind) - -> (CrateNum, Lrc) { + fn register_crate( + &mut self, + host_lib: Option, + root: &Option, + ident: Symbol, + span: Span, + lib: Library, + dep_kind: DepKind, + name: Symbol + ) -> (CrateNum, Lrc) { let crate_root = lib.metadata.get_root(); - info!("register crate `extern crate {} as {}`", crate_root.name, ident); self.verify_no_symbol_conflicts(span, &crate_root); + let private_dep = self.sess.opts.externs.get(&name.as_str()) + .map(|e| e.is_private_dep) + .unwrap_or(false); + + info!("register crate `extern crate {} as {}` (private_dep = {})", + crate_root.name, ident, private_dep); + + // Claim this crate number and cache it let cnum = self.cstore.alloc_new_crate_num(); @@ -222,7 +232,16 @@ impl<'a> CrateLoader<'a> { let dependencies: Vec = cnum_map.iter().cloned().collect(); let proc_macros = crate_root.proc_macro_decls_static.map(|_| { - self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span) + if self.sess.opts.debugging_opts.dual_proc_macros { + let host_lib = host_lib.unwrap(); + self.load_derive_macros( + &host_lib.metadata.get_root(), + host_lib.dylib.map(|p| p.0), + span + ) + } else { + self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span) + } }); let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || { @@ -261,7 +280,8 @@ impl<'a> CrateLoader<'a> { dylib, rlib, rmeta, - } + }, + private_dep }; let cmeta = Lrc::new(cmeta); @@ -269,6 +289,61 @@ impl<'a> CrateLoader<'a> { (cnum, cmeta) } + fn load_proc_macro<'b>( + &mut self, + locate_ctxt: &mut locator::Context<'b>, + path_kind: PathKind, + ) -> Option<(LoadResult, Option)> + where + 'a: 'b, + { + // Use a new locator Context so trying to load a proc macro doesn't affect the error + // message we emit + let mut proc_macro_locator = locate_ctxt.clone(); + + // Try to load a proc macro + proc_macro_locator.is_proc_macro = Some(true); + + // Load the proc macro crate for the target + let (locator, target_result) = if self.sess.opts.debugging_opts.dual_proc_macros { + proc_macro_locator.reset(); + let result = match self.load(&mut proc_macro_locator)? { + LoadResult::Previous(cnum) => return Some((LoadResult::Previous(cnum), None)), + LoadResult::Loaded(library) => Some(LoadResult::Loaded(library)) + }; + // Don't look for a matching hash when looking for the host crate. + // It won't be the same as the target crate hash + locate_ctxt.hash = None; + // Use the locate_ctxt when looking for the host proc macro crate, as that is required + // so we want it to affect the error message + (locate_ctxt, result) + } else { + (&mut proc_macro_locator, None) + }; + + // Load the proc macro crate for the host + + locator.reset(); + locator.is_proc_macro = Some(true); + locator.target = &self.sess.host; + locator.triple = TargetTriple::from_triple(config::host_triple()); + locator.filesearch = self.sess.host_filesearch(path_kind); + + let host_result = self.load(locator)?; + + Some(if self.sess.opts.debugging_opts.dual_proc_macros { + let host_result = match host_result { + LoadResult::Previous(..) => { + panic!("host and target proc macros must be loaded in lock-step") + } + LoadResult::Loaded(library) => library + }; + (target_result.unwrap(), Some(host_result)) + } else { + (host_result, None) + }) + } + fn resolve_crate<'b>( &'b mut self, root: &'b Option, @@ -282,7 +357,7 @@ impl<'a> CrateLoader<'a> { ) -> Result<(CrateNum, Lrc), LoadError<'b>> { info!("resolving crate `extern crate {} as {}`", name, ident); let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) { - LoadResult::Previous(cnum) + (LoadResult::Previous(cnum), None) } else { info!("falling back to a load"); let mut locate_ctxt = locator::Context { @@ -290,11 +365,11 @@ impl<'a> CrateLoader<'a> { span, ident, crate_name: name, - hash: hash.map(|a| &*a), - extra_filename: extra_filename, + hash, + extra_filename, filesearch: self.sess.target_filesearch(path_kind), target: &self.sess.target.target, - triple: &self.sess.opts.target_triple, + triple: self.sess.opts.target_triple.clone(), root, rejected_via_hash: vec![], rejected_via_triple: vec![], @@ -306,28 +381,14 @@ impl<'a> CrateLoader<'a> { metadata_loader: &*self.cstore.metadata_loader, }; - self.load(&mut locate_ctxt).or_else(|| { + self.load(&mut locate_ctxt).map(|r| (r, None)).or_else(|| { dep_kind = DepKind::UnexportedMacrosOnly; - - let mut proc_macro_locator = locator::Context { - target: &self.sess.host, - triple: &TargetTriple::from_triple(config::host_triple()), - filesearch: self.sess.host_filesearch(path_kind), - rejected_via_hash: vec![], - rejected_via_triple: vec![], - rejected_via_kind: vec![], - rejected_via_version: vec![], - rejected_via_filename: vec![], - is_proc_macro: Some(true), - ..locate_ctxt - }; - - self.load(&mut proc_macro_locator) + self.load_proc_macro(&mut locate_ctxt, path_kind) }).ok_or_else(move || LoadError::LocatorError(locate_ctxt))? }; match result { - LoadResult::Previous(cnum) => { + (LoadResult::Previous(cnum), None) => { let data = self.cstore.get_crate_data(cnum); if data.root.proc_macro_decls_static.is_some() { dep_kind = DepKind::UnexportedMacrosOnly; @@ -337,9 +398,10 @@ impl<'a> CrateLoader<'a> { }); Ok((cnum, data)) } - LoadResult::Loaded(library) => { - Ok(self.register_crate(root, ident, span, library, dep_kind)) + (LoadResult::Loaded(library), host_library) => { + Ok(self.register_crate(host_library, root, ident, span, library, dep_kind, name)) } + _ => panic!() } } @@ -355,7 +417,7 @@ impl<'a> CrateLoader<'a> { // don't want to match a host crate against an equivalent target one // already loaded. let root = library.metadata.get_root(); - if locate_ctxt.triple == &self.sess.opts.target_triple { + if locate_ctxt.triple == self.sess.opts.target_triple { let mut result = LoadResult::Loaded(library); self.cstore.iter_crate_data(|cnum, data| { if data.root.name == root.name && root.hash == data.root.hash { @@ -414,7 +476,7 @@ impl<'a> CrateLoader<'a> { // Go through the crate metadata and load any crates that it references fn resolve_crate_deps(&mut self, root: &Option, - crate_root: &CrateRoot, + crate_root: &CrateRoot<'_>, metadata: &MetadataBlob, krate: CrateNum, span: Span, @@ -451,9 +513,9 @@ impl<'a> CrateLoader<'a> { fn read_extension_crate(&mut self, span: Span, orig_name: Symbol, rename: Symbol) -> ExtensionCrate { info!("read extension crate `extern crate {} as {}`", orig_name, rename); - let target_triple = &self.sess.opts.target_triple; + let target_triple = self.sess.opts.target_triple.clone(); let host_triple = TargetTriple::from_triple(config::host_triple()); - let is_cross = target_triple != &host_triple; + let is_cross = target_triple != host_triple; let mut target_only = false; let mut locate_ctxt = locator::Context { sess: self.sess, @@ -464,7 +526,7 @@ impl<'a> CrateLoader<'a> { extra_filename: None, filesearch: self.sess.host_filesearch(PathKind::Crate), target: &self.sess.host, - triple: &host_triple, + triple: host_triple, root: &None, rejected_via_hash: vec![], rejected_via_triple: vec![], @@ -520,7 +582,7 @@ impl<'a> CrateLoader<'a> { /// implemented as dynamic libraries, but we have a possible future where /// custom derive (and other macro-1.1 style features) are implemented via /// executables and custom IPC. - fn load_derive_macros(&mut self, root: &CrateRoot, dylib: Option, span: Span) + fn load_derive_macros(&mut self, root: &CrateRoot<'_>, dylib: Option, span: Span) -> Vec<(ast::Name, Lrc)> { use std::{env, mem}; use crate::dynamic_lib::DynamicLibrary; @@ -549,33 +611,31 @@ impl<'a> CrateLoader<'a> { }; let extensions = decls.iter().map(|&decl| { - match decl { + let (name, kind, helper_attrs) = match decl { ProcMacro::CustomDerive { trait_name, attributes, client } => { - let attrs = attributes.iter().cloned().map(Symbol::intern).collect::>(); - (trait_name, SyntaxExtension::ProcMacroDerive( - Box::new(ProcMacroDerive { - client, - attrs: attrs.clone(), - }), - attrs, - root.edition, - )) - } - ProcMacro::Attr { name, client } => { - (name, SyntaxExtension::AttrProcMacro( - Box::new(AttrProcMacro { client }), - root.edition, - )) + let helper_attrs = + attributes.iter().cloned().map(Symbol::intern).collect::>(); + ( + trait_name, + SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive { + client, attrs: helper_attrs.clone() + })), + helper_attrs, + ) } - ProcMacro::Bang { name, client } => { - (name, SyntaxExtension::ProcMacro { - expander: Box::new(BangProcMacro { client }), - allow_internal_unstable: None, - edition: root.edition, - }) - } - } - }).map(|(name, ext)| (Symbol::intern(name), Lrc::new(ext))).collect(); + ProcMacro::Attr { name, client } => ( + name, SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client })), Vec::new() + ), + ProcMacro::Bang { name, client } => ( + name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new() + ) + }; + + (Symbol::intern(name), Lrc::new(SyntaxExtension { + helper_attrs, + ..SyntaxExtension::default(kind, root.edition) + })) + }).collect(); // Intentionally leak the dynamic library. We can't ever unload it // since the library can make things that will live arbitrarily long. @@ -588,9 +648,8 @@ impl<'a> CrateLoader<'a> { /// SVH and DefIndex of the registrar function. pub fn find_plugin_registrar(&mut self, span: Span, - name: &str) + name: Symbol) -> Option<(PathBuf, CrateDisambiguator)> { - let name = Symbol::intern(name); let ekrate = self.read_extension_crate(span, name, name); if ekrate.target_only { @@ -642,7 +701,7 @@ impl<'a> CrateLoader<'a> { let desired_strategy = self.sess.panic_strategy(); let mut runtime_found = false; let mut needs_panic_runtime = attr::contains_name(&krate.attrs, - "needs_panic_runtime"); + sym::needs_panic_runtime); self.cstore.iter_crate_data(|cnum, data| { needs_panic_runtime = needs_panic_runtime || @@ -721,7 +780,7 @@ impl<'a> CrateLoader<'a> { Sanitizer::Leak => LSAN_SUPPORTED_TARGETS, Sanitizer::Memory => MSAN_SUPPORTED_TARGETS, }; - if !supported_targets.contains(&&*self.sess.target.target.llvm_target) { + if !supported_targets.contains(&&*self.sess.opts.target_triple.triple()) { self.sess.err(&format!("{:?}Sanitizer only works with the `{}` target", sanitizer, supported_targets.join("` or `") @@ -732,7 +791,7 @@ impl<'a> CrateLoader<'a> { // firstyear 2017 - during testing I was unable to access an OSX machine // to make this work on different crate types. As a result, today I have // only been able to test and support linux as a target. - if self.sess.target.target.llvm_target == "x86_64-unknown-linux-gnu" { + if self.sess.opts.target_triple.triple() == "x86_64-unknown-linux-gnu" { if !self.sess.crate_types.borrow().iter().all(|ct| { match *ct { // Link the runtime @@ -775,7 +834,7 @@ impl<'a> CrateLoader<'a> { let mut uses_std = false; self.cstore.iter_crate_data(|_, data| { - if data.name == "std" { + if data.name == sym::std { uses_std = true; } }); @@ -809,7 +868,7 @@ impl<'a> CrateLoader<'a> { fn inject_profiler_runtime(&mut self) { if self.sess.opts.debugging_opts.profile || - self.sess.opts.debugging_opts.pgo_gen.is_some() + self.sess.opts.cg.profile_generate.enabled() { info!("loading profiler"); @@ -836,7 +895,7 @@ impl<'a> CrateLoader<'a> { // about through the `#![needs_allocator]` attribute and is typically // written down in liballoc. let mut needs_allocator = attr::contains_name(&krate.attrs, - "needs_allocator"); + sym::needs_allocator); self.cstore.iter_crate_data(|_, data| { needs_allocator = needs_allocator || data.root.needs_allocator; }); @@ -902,7 +961,7 @@ impl<'a> CrateLoader<'a> { // allocator. At this point our allocator request is typically fulfilled // by the standard library, denoted by the `#![default_lib_allocator]` // attribute. - let mut has_default = attr::contains_name(&krate.attrs, "default_lib_allocator"); + let mut has_default = attr::contains_name(&krate.attrs, sym::default_lib_allocator); self.cstore.iter_crate_data(|_, data| { if data.root.has_default_lib_allocator { has_default = true; @@ -925,7 +984,7 @@ impl<'a> CrateLoader<'a> { impl<'ast> visit::Visitor<'ast> for Finder { fn visit_item(&mut self, i: &'ast ast::Item) { - if attr::contains_name(&i.attrs, "global_allocator") { + if attr::contains_name(&i.attrs, sym::global_allocator) { self.0 = true; } visit::walk_item(self, i) @@ -1003,7 +1062,7 @@ impl<'a> CrateLoader<'a> { } None => item.ident.name, }; - let dep_kind = if attr::contains_name(&item.attrs, "no_link") { + let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) { DepKind::UnexportedMacrosOnly } else { DepKind::Explicit diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index d646879b4d45d..5d8fabc7e69ae 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -64,7 +64,11 @@ pub struct CrateMetadata { /// Used for decoding interpret::AllocIds in a cached & thread-safe manner. pub alloc_decoding_state: AllocDecodingState, - pub root: schema::CrateRoot, + // NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this + // lifetime is only used behind `Lazy` / `LazySeq`, and therefore + // acts like an universal (`for<'tcx>`), that is paired up with + // whichever `TyCtxt` is being used to decode those values. + pub root: schema::CrateRoot<'static>, /// For each public item in this crate, we encode a key. When the /// crate is loaded, we read all the keys and put them in this @@ -79,6 +83,10 @@ pub struct CrateMetadata { pub source: CrateSource, pub proc_macros: Option)>>, + + /// Whether or not this crate should be consider a private dependency + /// for purposes of the 'exported_private_dependencies' lint + pub private_dep: bool } pub struct CStore { @@ -114,7 +122,8 @@ impl CStore { } pub(super) fn get_crate_data(&self, cnum: CrateNum) -> Lrc { - self.metas.borrow()[cnum].clone().unwrap() + self.metas.borrow()[cnum].clone() + .unwrap_or_else(|| panic!("Failed to get crate data for {:?}", cnum)) } pub(super) fn set_crate_data(&self, cnum: CrateNum, data: Lrc) { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index f49b88f14e60e..04a9c4e9a1a11 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -11,6 +11,7 @@ use rustc::middle::cstore::{CrateStore, DepKind, use rustc::middle::exported_symbols::ExportedSymbol; use rustc::middle::stability::DeprecationEntry; use rustc::hir::def; +use rustc::hir; use rustc::session::{CrateDisambiguator, Session}; use rustc::ty::{self, TyCtxt}; use rustc::ty::query::Providers; @@ -20,6 +21,7 @@ use rustc::hir::map::definitions::DefPathTable; use rustc::util::nodemap::DefIdMap; use rustc_data_structures::svh::Svh; +use smallvec::SmallVec; use std::any::Any; use rustc_data_structures::sync::Lrc; use std::sync::Arc; @@ -28,9 +30,11 @@ use syntax::ast; use syntax::attr; use syntax::source_map; use syntax::edition::Edition; +use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind}; use syntax::parse::source_file_to_stream; use syntax::parse::parser::emit_unclosed_delims; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; +use syntax_ext::proc_macro_impl::BangProcMacro; use syntax_pos::{Span, NO_EXPANSION, FileName}; use rustc_data_structures::bit_set::BitSet; @@ -38,11 +42,12 @@ macro_rules! provide { (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $($name:ident => $compute:block)*) => { pub fn provide_extern<$lt>(providers: &mut Providers<$lt>) { - $(fn $name<'a, $lt:$lt, T>($tcx: TyCtxt<'a, $lt, $lt>, def_id_arg: T) - -> as - QueryConfig<$lt>>::Value - where T: IntoArgs, - { + // HACK(eddyb) `$lt: $lt` forces `$lt` to be early-bound, which + // allows the associated type in the return type to be normalized. + $(fn $name<$lt: $lt, T: IntoArgs>( + $tcx: TyCtxt<$lt>, + def_id_arg: T, + ) -> as QueryConfig<$lt>>::Value { #[allow(unused_variables)] let ($def_id, $other) = def_id_arg.into_args(); assert!(!$def_id.is_local()); @@ -92,25 +97,27 @@ impl IntoArgs for (CrateNum, DefId) { provide! { <'tcx> tcx, def_id, other, cdata, type_of => { cdata.get_type(def_id.index, tcx) } generics_of => { - tcx.alloc_generics(cdata.get_generics(def_id.index, tcx.sess)) + tcx.arena.alloc(cdata.get_generics(def_id.index, tcx.sess)) + } + predicates_of => { tcx.arena.alloc(cdata.get_predicates(def_id.index, tcx)) } + predicates_defined_on => { + tcx.arena.alloc(cdata.get_predicates_defined_on(def_id.index, tcx)) } - predicates_of => { Lrc::new(cdata.get_predicates(def_id.index, tcx)) } - predicates_defined_on => { Lrc::new(cdata.get_predicates_defined_on(def_id.index, tcx)) } - super_predicates_of => { Lrc::new(cdata.get_super_predicates(def_id.index, tcx)) } + super_predicates_of => { tcx.arena.alloc(cdata.get_super_predicates(def_id.index, tcx)) } trait_def => { - tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx.sess)) + tcx.arena.alloc(cdata.get_trait_def(def_id.index, tcx.sess)) } adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { let _ = cdata; tcx.calculate_dtor(def_id, &mut |_,_| Ok(())) } - variances_of => { Lrc::new(cdata.get_item_variances(def_id.index)) } + variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) } associated_item_def_ids => { - let mut result = vec![]; + let mut result = SmallVec::<[_; 8]>::new(); cdata.each_child_of_item(def_id.index, - |child| result.push(child.def.def_id()), tcx.sess); - Lrc::new(result) + |child| result.push(child.res.def_id()), tcx.sess); + tcx.arena.alloc_slice(&result) } associated_item => { cdata.get_associated_item(def_id.index) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } @@ -125,18 +132,19 @@ provide! { <'tcx> tcx, def_id, other, cdata, bug!("get_optimized_mir: missing MIR for `{:?}`", def_id) }); - let mir = tcx.alloc_mir(mir); + let mir = tcx.arena.alloc(mir); mir } mir_const_qualif => { - (cdata.mir_const_qualif(def_id.index), Lrc::new(BitSet::new_empty(0))) + (cdata.mir_const_qualif(def_id.index), tcx.arena.alloc(BitSet::new_empty(0))) } fn_sig => { cdata.fn_sig(def_id.index, tcx) } - inherent_impls => { Lrc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } + inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } is_const_fn_raw => { cdata.is_const_fn_raw(def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) } - describe_def => { cdata.get_def(def_id.index) } + static_mutability => { cdata.static_mutability(def_id.index) } + def_kind => { cdata.def_kind(def_id.index) } def_span => { cdata.get_span(def_id.index, &tcx.sess) } lookup_stability => { cdata.get_stability(def_id.index).map(|s| tcx.intern_stability(s)) @@ -158,7 +166,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, } is_mir_available => { cdata.is_item_mir_available(def_id.index) } - dylib_dependency_formats => { Lrc::new(cdata.get_dylib_dependency_formats()) } + dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) } is_panic_runtime => { cdata.root.panic_runtime } is_compiler_builtins => { cdata.root.compiler_builtins } has_global_allocator => { cdata.root.has_global_allocator } @@ -167,10 +175,11 @@ provide! { <'tcx> tcx, def_id, other, cdata, is_profiler_runtime => { cdata.root.profiler_runtime } panic_strategy => { cdata.root.panic_strategy } extern_crate => { - let r = Lrc::new(*cdata.extern_crate.lock()); - r + let r = *cdata.extern_crate.lock(); + r.map(|c| &*tcx.arena.alloc(c)) } is_no_builtins => { cdata.root.no_builtins } + symbol_mangling_version => { cdata.root.symbol_mangling_version } impl_defaultness => { cdata.get_impl_defaultness(def_id.index) } reachable_non_generics => { let reachable_non_generics = tcx @@ -185,10 +194,10 @@ provide! { <'tcx> tcx, def_id, other, cdata, }) .collect(); - Lrc::new(reachable_non_generics) + tcx.arena.alloc(reachable_non_generics) } native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess)) } - foreign_modules => { Lrc::new(cdata.get_foreign_modules(tcx.sess)) } + foreign_modules => { cdata.get_foreign_modules(tcx) } plugin_registrar_fn => { cdata.root.plugin_registrar_fn.map(|index| { DefId { krate: def_id.krate, index } @@ -205,18 +214,12 @@ provide! { <'tcx> tcx, def_id, other, cdata, extra_filename => { cdata.root.extra_filename.clone() } - implementations_of_trait => { - let mut result = vec![]; - let filter = Some(other); - cdata.get_implementations_for_trait(filter, &mut result); - Lrc::new(result) + cdata.get_implementations_for_trait(tcx, Some(other)) } all_trait_implementations => { - let mut result = vec![]; - cdata.get_implementations_for_trait(None, &mut result); - Lrc::new(result) + cdata.get_implementations_for_trait(tcx, None) } visibility => { cdata.get_visibility(def_id.index) } @@ -226,13 +229,13 @@ provide! { <'tcx> tcx, def_id, other, cdata, } crate_name => { cdata.name } item_children => { - let mut result = vec![]; + let mut result = SmallVec::<[_; 8]>::new(); cdata.each_child_of_item(def_id.index, |child| result.push(child), tcx.sess); - Lrc::new(result) + tcx.arena.alloc_slice(&result) } - defined_lib_features => { Lrc::new(cdata.get_lib_features()) } - defined_lang_items => { Lrc::new(cdata.get_lang_items()) } - missing_lang_items => { Lrc::new(cdata.get_missing_lang_items()) } + defined_lib_features => { cdata.get_lib_features(tcx) } + defined_lang_items => { cdata.get_lang_items(tcx) } + missing_lang_items => { cdata.get_missing_lang_items(tcx) } missing_extern_crate_item => { let r = match *cdata.extern_crate.borrow() { @@ -244,12 +247,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, used_crate_source => { Lrc::new(cdata.source.clone()) } - exported_symbols => { - let cnum = cdata.cnum; - assert!(cnum != LOCAL_CRATE); - - Arc::new(cdata.exported_symbols(tcx)) - } + exported_symbols => { Arc::new(cdata.exported_symbols(tcx)) } } pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { @@ -291,7 +289,7 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { }, foreign_modules: |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - Lrc::new(foreign_modules::collect(tcx)) + &tcx.arena.alloc(foreign_modules::collect(tcx))[..] }, link_args: |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); @@ -328,7 +326,7 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { // which is to say, its not deterministic in general. But // we believe that libstd is consistently assigned crate // num 1, so it should be enough to resolve #46112. - let mut crates: Vec = (*tcx.crates()).clone(); + let mut crates: Vec = (*tcx.crates()).to_owned(); crates.sort(); for &cnum in crates.iter() { @@ -347,26 +345,26 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { { let visible_parent_map = &mut visible_parent_map; let mut add_child = |bfs_queue: &mut VecDeque<_>, - child: &def::Export, + child: &def::Export, parent: DefId| { if child.vis != ty::Visibility::Public { return; } - let child = child.def.def_id(); - - match visible_parent_map.entry(child) { - Entry::Occupied(mut entry) => { - // If `child` is defined in crate `cnum`, ensure - // that it is mapped to a parent in `cnum`. - if child.krate == cnum && entry.get().krate != cnum { + if let Some(child) = child.res.opt_def_id() { + match visible_parent_map.entry(child) { + Entry::Occupied(mut entry) => { + // If `child` is defined in crate `cnum`, ensure + // that it is mapped to a parent in `cnum`. + if child.krate == cnum && entry.get().krate != cnum { + entry.insert(parent); + } + } + Entry::Vacant(entry) => { entry.insert(parent); + bfs_queue.push_back(child); } } - Entry::Vacant(entry) => { - entry.insert(parent); - bfs_queue.push_back(child); - } } }; @@ -377,7 +375,7 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { } } - Lrc::new(visible_parent_map) + tcx.arena.alloc(visible_parent_map) }, ..*providers @@ -407,7 +405,19 @@ impl cstore::CStore { self.get_crate_data(def.krate).get_struct_field_names(def.index) } - pub fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec { + pub fn ctor_kind_untracked(&self, def: DefId) -> def::CtorKind { + self.get_crate_data(def.krate).get_ctor_kind(def.index) + } + + pub fn item_attrs_untracked(&self, def: DefId, sess: &Session) -> Lrc<[ast::Attribute]> { + self.get_crate_data(def.krate).get_item_attrs(def.index, sess) + } + + pub fn item_children_untracked( + &self, + def_id: DefId, + sess: &Session + ) -> Vec> { let mut result = vec![]; self.get_crate_data(def_id.krate) .each_child_of_item(def_id.index, |child| result.push(child), sess); @@ -418,17 +428,12 @@ impl cstore::CStore { let data = self.get_crate_data(id.krate); if let Some(ref proc_macros) = data.proc_macros { return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone()); - } else if data.name == "proc_macro" && data.item_name(id.index) == "quote" { - use syntax::ext::base::SyntaxExtension; - use syntax_ext::proc_macro_impl::BangProcMacro; - + } else if data.name == sym::proc_macro && data.item_name(id.index) == sym::quote { let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote); - let ext = SyntaxExtension::ProcMacro { - expander: Box::new(BangProcMacro { client }), - allow_internal_unstable: Some(vec![ - Symbol::intern("proc_macro_def_site"), - ].into()), - edition: data.root.edition, + let kind = SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })); + let ext = SyntaxExtension { + allow_internal_unstable: Some([sym::proc_macro_def_site][..].into()), + ..SyntaxExtension::default(kind, data.root.edition) }; return LoadedMacro::ProcMacro(Lrc::new(ext)); } @@ -439,8 +444,8 @@ impl cstore::CStore { let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body); let local_span = Span::new(source_file.start_pos, source_file.end_pos, NO_EXPANSION); - let (body, errors) = source_file_to_stream(&sess.parse_sess, source_file, None); - emit_unclosed_delims(&errors, &sess.diagnostic()); + let (body, mut errors) = source_file_to_stream(&sess.parse_sess, source_file, None); + emit_unclosed_delims(&mut errors, &sess.diagnostic()); // Mark the attrs as used let attrs = data.get_item_attrs(id.index, sess); @@ -467,7 +472,7 @@ impl cstore::CStore { }) } - pub fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem { + pub fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssocItem { self.get_crate_data(def.krate).get_associated_item(def.index) } } @@ -486,6 +491,10 @@ impl CrateStore for cstore::CStore { self.get_crate_data(cnum).name } + fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool { + self.get_crate_data(cnum).private_dep + } + fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator { self.get_crate_data(cnum).root.disambiguator @@ -541,10 +550,7 @@ impl CrateStore for cstore::CStore { self.do_postorder_cnums_untracked() } - fn encode_metadata<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> EncodedMetadata - { + fn encode_metadata<'tcx>(&self, tcx: TyCtxt<'tcx>) -> EncodedMetadata { encoder::encode_metadata(tcx) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 1c4e3bc6a50e7..6a5f62aec1537 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -8,9 +8,8 @@ use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash, Definitions}; use rustc::hir; use rustc::middle::cstore::LinkagePreference; use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; -use rustc::hir::def::{self, Def, CtorKind}; -use rustc::hir::def_id::{CrateNum, DefId, DefIndex, DefIndexAddressSpace, - CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId}; +use rustc::hir::def::{self, Res, DefKind, CtorOf, CtorKind}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::hir::map::definitions::DefPathTable; use rustc_data_structures::fingerprint::Fingerprint; use rustc::middle::lang_items; @@ -19,7 +18,7 @@ use rustc::mir::interpret::AllocDecodingSession; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::codec::TyDecoder; -use rustc::mir::Mir; +use rustc::mir::Body; use rustc::util::captures::Captures; use std::io; @@ -30,17 +29,17 @@ use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; use syntax::attr; use syntax::ast::{self, Ident}; use syntax::source_map; -use syntax::symbol::InternedString; +use syntax::symbol::{Symbol, sym}; use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::hygiene::Mark; use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, NO_EXPANSION}; use log::debug; -pub struct DecodeContext<'a, 'tcx: 'a> { +pub struct DecodeContext<'a, 'tcx> { opaque: opaque::Decoder<'a>, cdata: Option<&'a CrateMetadata>, - sess: Option<&'a Session>, - tcx: Option>, + sess: Option<&'tcx Session>, + tcx: Option>, // Cache the last used source_file for translating spans as an optimization. last_source_file_index: usize, @@ -55,8 +54,8 @@ pub struct DecodeContext<'a, 'tcx: 'a> { pub trait Metadata<'a, 'tcx>: Copy { fn raw_bytes(self) -> &'a [u8]; fn cdata(self) -> Option<&'a CrateMetadata> { None } - fn sess(self) -> Option<&'a Session> { None } - fn tcx(self) -> Option> { None } + fn sess(self) -> Option<&'tcx Session> { None } + fn tcx(self) -> Option> { None } fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> { let tcx = self.tcx(); @@ -81,13 +80,13 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob { } -impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a MetadataBlob, &'a Session) { +impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a MetadataBlob, &'tcx Session) { fn raw_bytes(self) -> &'a [u8] { let (blob, _) = self; &blob.0 } - fn sess(self) -> Option<&'a Session> { + fn sess(self) -> Option<&'tcx Session> { let (_, sess) = self; Some(sess) } @@ -103,31 +102,31 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadata { } } -impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, &'a Session) { +impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, &'tcx Session) { fn raw_bytes(self) -> &'a [u8] { self.0.raw_bytes() } fn cdata(self) -> Option<&'a CrateMetadata> { Some(self.0) } - fn sess(self) -> Option<&'a Session> { + fn sess(self) -> Option<&'tcx Session> { Some(&self.1) } } -impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>) { +impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'tcx>) { fn raw_bytes(self) -> &'a [u8] { self.0.raw_bytes() } fn cdata(self) -> Option<&'a CrateMetadata> { Some(self.0) } - fn tcx(self) -> Option> { + fn tcx(self) -> Option> { Some(self.1) } } -impl<'a, 'tcx: 'a, T: Decodable> Lazy { +impl<'a, 'tcx, T: Decodable> Lazy { pub fn decode>(self, meta: M) -> T { let mut dcx = meta.decoder(self.position); dcx.lazy_state = LazyState::NodeStart(self.position); @@ -135,11 +134,11 @@ impl<'a, 'tcx: 'a, T: Decodable> Lazy { } } -impl<'a, 'tcx: 'a, T: Decodable> LazySeq { +impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable> LazySeq { pub fn decode>( self, meta: M, - ) -> impl Iterator + Captures<'tcx> + 'a { + ) -> impl Iterator + Captures<'a> + Captures<'tcx> + 'x { let mut dcx = meta.decoder(self.position); dcx.lazy_state = LazyState::NodeStart(self.position); (0..self.len).map(move |_| T::decode(&mut dcx).unwrap()) @@ -147,7 +146,7 @@ impl<'a, 'tcx: 'a, T: Decodable> LazySeq { } impl<'a, 'tcx> DecodeContext<'a, 'tcx> { - pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { + pub fn tcx(&self) -> TyCtxt<'tcx> { self.tcx.expect("missing TyCtxt in DecodeContext") } @@ -170,10 +169,9 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { } } -impl<'a, 'tcx: 'a> TyDecoder<'a, 'tcx> for DecodeContext<'a, 'tcx> { - +impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { #[inline] - fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx.expect("missing TyCtxt in DecodeContext") } @@ -265,7 +263,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { #[inline] fn specialized_decode(&mut self) -> Result { - Ok(DefIndex::from_raw_u32(self.read_u32()?)) + Ok(DefIndex::from_u32(self.read_u32()?)) } } @@ -366,7 +364,7 @@ for DecodeContext<'a, 'tcx> { implement_ty_decoder!( DecodeContext<'a, 'tcx> ); -impl<'a, 'tcx> MetadataBlob { +impl<'tcx> MetadataBlob { pub fn is_compatible(&self) -> bool { self.raw_bytes().starts_with(METADATA_HEADER) } @@ -375,7 +373,7 @@ impl<'a, 'tcx> MetadataBlob { Lazy::with_position(METADATA_HEADER.len() + 4).decode(self) } - pub fn get_root(&self) -> CrateRoot { + pub fn get_root(&self) -> CrateRoot<'tcx> { let slice = self.raw_bytes(); let offset = METADATA_HEADER.len(); let pos = (((slice[offset + 0] as u32) << 24) | ((slice[offset + 1] as u32) << 16) | @@ -399,30 +397,32 @@ impl<'a, 'tcx> MetadataBlob { } impl<'tcx> EntryKind<'tcx> { - fn to_def(&self, did: DefId) -> Option { + fn def_kind(&self) -> Option { Some(match *self { - EntryKind::Const(..) => Def::Const(did), - EntryKind::AssociatedConst(..) => Def::AssociatedConst(did), + EntryKind::Const(..) => DefKind::Const, + EntryKind::AssocConst(..) => DefKind::AssocConst, EntryKind::ImmStatic | - EntryKind::ForeignImmStatic => Def::Static(did, false), EntryKind::MutStatic | - EntryKind::ForeignMutStatic => Def::Static(did, true), - EntryKind::Struct(_, _) => Def::Struct(did), - EntryKind::Union(_, _) => Def::Union(did), + EntryKind::ForeignImmStatic | + EntryKind::ForeignMutStatic => DefKind::Static, + EntryKind::Struct(_, _) => DefKind::Struct, + EntryKind::Union(_, _) => DefKind::Union, EntryKind::Fn(_) | - EntryKind::ForeignFn(_) => Def::Fn(did), - EntryKind::Method(_) => Def::Method(did), - EntryKind::Type => Def::TyAlias(did), - EntryKind::Existential => Def::Existential(did), - EntryKind::AssociatedType(_) => Def::AssociatedTy(did), - EntryKind::AssociatedExistential(_) => Def::AssociatedExistential(did), - EntryKind::Mod(_) => Def::Mod(did), - EntryKind::Variant(_) => Def::Variant(did), - EntryKind::Trait(_) => Def::Trait(did), - EntryKind::TraitAlias(_) => Def::TraitAlias(did), - EntryKind::Enum(..) => Def::Enum(did), - EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang), - EntryKind::ForeignType => Def::ForeignTy(did), + EntryKind::ForeignFn(_) => DefKind::Fn, + EntryKind::Method(_) => DefKind::Method, + EntryKind::Type => DefKind::TyAlias, + EntryKind::TypeParam => DefKind::TyParam, + EntryKind::ConstParam => DefKind::ConstParam, + EntryKind::Existential => DefKind::Existential, + EntryKind::AssocType(_) => DefKind::AssocTy, + EntryKind::AssocExistential(_) => DefKind::AssocExistential, + EntryKind::Mod(_) => DefKind::Mod, + EntryKind::Variant(_) => DefKind::Variant, + EntryKind::Trait(_) => DefKind::Trait, + EntryKind::TraitAlias(_) => DefKind::TraitAlias, + EntryKind::Enum(..) => DefKind::Enum, + EntryKind::MacroDef(_) => DefKind::Macro(MacroKind::Bang), + EntryKind::ForeignType => DefKind::ForeignTy, EntryKind::ForeignMod | EntryKind::GlobalAsm | @@ -443,11 +443,11 @@ impl<'tcx> EntryKind<'tcx> { /// |- proc macro #0 (DefIndex 1:N) /// |- proc macro #1 (DefIndex 1:N+1) /// \- ... -crate fn proc_macro_def_path_table(crate_root: &CrateRoot, +crate fn proc_macro_def_path_table(crate_root: &CrateRoot<'_>, proc_macros: &[(ast::Name, Lrc)]) -> DefPathTable { - let mut definitions = Definitions::new(); + let mut definitions = Definitions::default(); let name = crate_root.name.as_str(); let disambiguator = crate_root.disambiguator; @@ -457,8 +457,7 @@ crate fn proc_macro_def_path_table(crate_root: &CrateRoot, let def_index = definitions.create_def_with_parent( crate_root, ast::DUMMY_NODE_ID, - DefPathData::MacroDef(name.as_interned_str()), - DefIndexAddressSpace::High, + DefPathData::MacroNs(name.as_interned_str()), Mark::root(), DUMMY_SP); debug!("definition for {:?} is {:?}", name, def_index); @@ -475,7 +474,7 @@ impl<'a, 'tcx> CrateMetadata { fn maybe_entry(&self, item_id: DefIndex) -> Option>> { assert!(!self.is_proc_macro(item_id)); - self.root.index.lookup(self.blob.raw_bytes(), item_id) + self.root.entries_index.lookup(self.blob.raw_bytes(), item_id) } fn entry(&self, item_id: DefIndex) -> Entry<'tcx> { @@ -497,20 +496,22 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn item_name(&self, item_index: DefIndex) -> InternedString { + pub fn item_name(&self, item_index: DefIndex) -> Symbol { self.def_key(item_index) .disambiguated_data .data .get_opt_name() .expect("no name in item_name") + .as_symbol() } - pub fn get_def(&self, index: DefIndex) -> Option { + pub fn def_kind(&self, index: DefIndex) -> Option { if !self.is_proc_macro(index) { - self.entry(index).kind.to_def(self.local_def_id(index)) + self.entry(index).kind.def_kind() } else { - let kind = self.proc_macros.as_ref().unwrap()[index.to_proc_macro_index()].1.kind(); - Some(Def::Macro(self.local_def_id(index), kind)) + Some(DefKind::Macro( + self.proc_macros.as_ref().unwrap()[index.to_proc_macro_index()].1.macro_kind() + )) } } @@ -544,13 +545,14 @@ impl<'a, 'tcx> CrateMetadata { } } - fn get_variant(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - item: &Entry<'_>, - index: DefIndex, - adt_kind: ty::AdtKind) - -> ty::VariantDef - { + fn get_variant( + &self, + tcx: TyCtxt<'tcx>, + item: &Entry<'_>, + index: DefIndex, + parent_did: DefId, + adt_kind: ty::AdtKind, + ) -> ty::VariantDef { let data = match item.kind { EntryKind::Variant(data) | EntryKind::Struct(data, _) | @@ -558,32 +560,35 @@ impl<'a, 'tcx> CrateMetadata { _ => bug!(), }; - let def_id = self.local_def_id(data.struct_ctor.unwrap_or(index)); - let attribute_def_id = self.local_def_id(index); + let variant_did = if adt_kind == ty::AdtKind::Enum { + Some(self.local_def_id(index)) + } else { + None + }; + let ctor_did = data.ctor.map(|index| self.local_def_id(index)); ty::VariantDef::new( tcx, - def_id, - Ident::from_interned_str(self.item_name(index)), + Ident::with_empty_ctxt(self.item_name(index)), + variant_did, + ctor_did, data.discr, item.children.decode(self).map(|index| { let f = self.entry(index); ty::FieldDef { did: self.local_def_id(index), - ident: Ident::from_interned_str(self.item_name(index)), + ident: Ident::with_empty_ctxt(self.item_name(index)), vis: f.visibility.decode(self) } }).collect(), - adt_kind, data.ctor_kind, - attribute_def_id + adt_kind, + parent_did, + false, ) } - pub fn get_adt_def(&self, - item_id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> &'tcx ty::AdtDef { + pub fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef { let item = self.entry(item_id); let did = self.local_def_id(item_id); @@ -598,34 +603,37 @@ impl<'a, 'tcx> CrateMetadata { item.children .decode(self) .map(|index| { - self.get_variant(tcx, &self.entry(index), index, kind) + self.get_variant(tcx, &self.entry(index), index, did, kind) }) .collect() } else { - std::iter::once(self.get_variant(tcx, &item, item_id, kind)).collect() + std::iter::once(self.get_variant(tcx, &item, item_id, did, kind)).collect() }; tcx.alloc_adt_def(did, kind, variants, repr) } - pub fn get_predicates(&self, - item_id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::GenericPredicates<'tcx> { + pub fn get_predicates( + &self, + item_id: DefIndex, + tcx: TyCtxt<'tcx>, + ) -> ty::GenericPredicates<'tcx> { self.entry(item_id).predicates.unwrap().decode((self, tcx)) - } +} - pub fn get_predicates_defined_on(&self, - item_id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::GenericPredicates<'tcx> { + pub fn get_predicates_defined_on( + &self, + item_id: DefIndex, + tcx: TyCtxt<'tcx>, + ) -> ty::GenericPredicates<'tcx> { self.entry(item_id).predicates_defined_on.unwrap().decode((self, tcx)) } - pub fn get_super_predicates(&self, - item_id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::GenericPredicates<'tcx> { + pub fn get_super_predicates( + &self, + item_id: DefIndex, + tcx: TyCtxt<'tcx>, + ) -> ty::GenericPredicates<'tcx> { let super_predicates = match self.entry(item_id).kind { EntryKind::Trait(data) => data.decode(self).super_predicates, EntryKind::TraitAlias(data) => data.decode(self).super_predicates, @@ -642,13 +650,13 @@ impl<'a, 'tcx> CrateMetadata { self.entry(item_id).generics.unwrap().decode((self, sess)) } - pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { + pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { self.entry(id).ty.unwrap().decode((self, tcx)) } pub fn get_stability(&self, id: DefIndex) -> Option { match self.is_proc_macro(id) { - true => None, + true => self.root.proc_macro_stability.clone(), false => self.entry(id).stability.map(|stab| stab.decode(self)), } } @@ -692,40 +700,35 @@ impl<'a, 'tcx> CrateMetadata { self.get_impl_data(id).coerce_unsized_info } - pub fn get_impl_trait(&self, - id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Option> { + pub fn get_impl_trait(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option> { self.get_impl_data(id).trait_ref.map(|tr| tr.decode((self, tcx))) } /// Iterates over all the stability attributes in the given crate. - pub fn get_lib_features(&self) -> Vec<(ast::Name, Option)> { + pub fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(ast::Name, Option)] { // FIXME: For a proc macro crate, not sure whether we should return the "host" // features or an empty Vec. Both don't cause ICEs. - self.root + tcx.arena.alloc_from_iter(self.root .lib_features - .decode(self) - .collect() + .decode(self)) } /// Iterates over the language items in the given crate. - pub fn get_lang_items(&self) -> Vec<(DefId, usize)> { + pub fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] { if self.proc_macros.is_some() { // Proc macro crates do not export any lang-items to the target. - vec![] + &[] } else { - self.root + tcx.arena.alloc_from_iter(self.root .lang_items .decode(self) - .map(|(def_index, index)| (self.local_def_id(def_index), index)) - .collect() + .map(|(def_index, index)| (self.local_def_id(def_index), index))) } } /// Iterates over each child of the given item. pub fn each_child_of_item(&self, id: DefIndex, mut callback: F, sess: &Session) - where F: FnMut(def::Export) + where F: FnMut(def::Export) { if let Some(ref proc_macros) = self.proc_macros { /* If we are loading as a proc macro, we want to return the view of this crate @@ -734,17 +737,14 @@ impl<'a, 'tcx> CrateMetadata { */ if id == CRATE_DEF_INDEX { for (id, &(name, ref ext)) in proc_macros.iter().enumerate() { - let def = Def::Macro( - DefId { - krate: self.cnum, - index: DefIndex::from_proc_macro_index(id), - }, - ext.kind() + let res = Res::Def( + DefKind::Macro(ext.macro_kind()), + self.local_def_id(DefIndex::from_proc_macro_index(id)), ); let ident = Ident::with_empty_ctxt(name); callback(def::Export { ident: ident, - def: def, + res: res, vis: ty::Visibility::Public, span: DUMMY_SP, }); @@ -780,10 +780,10 @@ impl<'a, 'tcx> CrateMetadata { // FIXME(eddyb) Don't encode these in children. EntryKind::ForeignMod => { for child_index in child.children.decode((self, sess)) { - if let Some(def) = self.get_def(child_index) { + if let Some(kind) = self.def_kind(child_index) { callback(def::Export { - def, - ident: Ident::from_interned_str(self.item_name(child_index)), + res: Res::Def(kind, self.local_def_id(child_index)), + ident: Ident::with_empty_ctxt(self.item_name(child_index)), vis: self.get_visibility(child_index), span: self.entry(child_index).span.decode((self, sess)), }); @@ -798,32 +798,51 @@ impl<'a, 'tcx> CrateMetadata { let def_key = self.def_key(child_index); let span = child.span.decode((self, sess)); - if let (Some(def), Some(name)) = - (self.get_def(child_index), def_key.disambiguated_data.data.get_opt_name()) { + if let (Some(kind), Some(name)) = + (self.def_kind(child_index), def_key.disambiguated_data.data.get_opt_name()) { let ident = Ident::from_interned_str(name); let vis = self.get_visibility(child_index); - callback(def::Export { def, ident, vis, span }); + let def_id = self.local_def_id(child_index); + let res = Res::Def(kind, def_id); + callback(def::Export { res, ident, vis, span }); // For non-re-export structs and variants add their constructors to children. // Re-export lists automatically contain constructors when necessary. - match def { - Def::Struct(..) => { - if let Some(ctor_def_id) = self.get_struct_ctor_def_id(child_index) { + match kind { + DefKind::Struct => { + if let Some(ctor_def_id) = self.get_ctor_def_id(child_index) { let ctor_kind = self.get_ctor_kind(child_index); - let ctor_def = Def::StructCtor(ctor_def_id, ctor_kind); - callback(def::Export { - def: ctor_def, - vis: self.get_visibility(ctor_def_id.index), - ident, span, - }); + let ctor_res = Res::Def( + DefKind::Ctor(CtorOf::Struct, ctor_kind), + ctor_def_id, + ); + let vis = self.get_visibility(ctor_def_id.index); + callback(def::Export { res: ctor_res, vis, ident, span }); } } - Def::Variant(def_id) => { + DefKind::Variant => { // Braced variants, unlike structs, generate unusable names in // value namespace, they are reserved for possible future use. + // It's ok to use the variant's id as a ctor id since an + // error will be reported on any use of such resolution anyway. + let ctor_def_id = self.get_ctor_def_id(child_index).unwrap_or(def_id); let ctor_kind = self.get_ctor_kind(child_index); - let ctor_def = Def::VariantCtor(def_id, ctor_kind); - let vis = self.get_visibility(child_index); - callback(def::Export { def: ctor_def, ident, vis, span }); + let ctor_res = Res::Def( + DefKind::Ctor(CtorOf::Variant, ctor_kind), + ctor_def_id, + ); + let mut vis = self.get_visibility(ctor_def_id.index); + if ctor_def_id == def_id && vis == ty::Visibility::Public { + // For non-exhaustive variants lower the constructor visibility to + // within the crate. We only need this for fictive constructors, + // for other constructors correct visibilities + // were already encoded in metadata. + let attrs = self.get_item_attrs(def_id.index, sess); + if attr::contains_name(&attrs, sym::non_exhaustive) { + let crate_def_id = self.local_def_id(CRATE_DEF_INDEX); + vis = ty::Visibility::Restricted(crate_def_id); + } + } + callback(def::Export { res: ctor_res, ident, vis, span }); } _ => {} } @@ -833,8 +852,8 @@ impl<'a, 'tcx> CrateMetadata { if let EntryKind::Mod(data) = item.kind { for exp in data.decode((self, sess)).reexports.decode((self, sess)) { - match exp.def { - Def::Macro(..) => {} + match exp.res { + Res::Def(DefKind::Macro(..), _) => {} _ if macros_only => continue, _ => {} } @@ -845,7 +864,7 @@ impl<'a, 'tcx> CrateMetadata { pub fn const_is_rvalue_promotable_to_static(&self, id: DefIndex) -> bool { match self.entry(id).kind { - EntryKind::AssociatedConst(_, data, _) | + EntryKind::AssocConst(_, data, _) | EntryKind::Const(data, _) => data.ast_promotable, _ => bug!(), } @@ -856,10 +875,7 @@ impl<'a, 'tcx> CrateMetadata { self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some() } - pub fn maybe_get_optimized_mir(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: DefIndex) - -> Option> { + pub fn maybe_get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Option> { match self.is_proc_macro(id) { true => None, false => self.entry(id).mir.map(|mir| mir.decode((self, tcx))), @@ -869,38 +885,38 @@ impl<'a, 'tcx> CrateMetadata { pub fn mir_const_qualif(&self, id: DefIndex) -> u8 { match self.entry(id).kind { EntryKind::Const(qualif, _) | - EntryKind::AssociatedConst(AssociatedContainer::ImplDefault, qualif, _) | - EntryKind::AssociatedConst(AssociatedContainer::ImplFinal, qualif, _) => { + EntryKind::AssocConst(AssocContainer::ImplDefault, qualif, _) | + EntryKind::AssocConst(AssocContainer::ImplFinal, qualif, _) => { qualif.mir } _ => bug!(), } } - pub fn get_associated_item(&self, id: DefIndex) -> ty::AssociatedItem { + pub fn get_associated_item(&self, id: DefIndex) -> ty::AssocItem { let item = self.entry(id); let def_key = self.def_key(id); let parent = self.local_def_id(def_key.parent.unwrap()); let name = def_key.disambiguated_data.data.get_opt_name().unwrap(); let (kind, container, has_self) = match item.kind { - EntryKind::AssociatedConst(container, _, _) => { - (ty::AssociatedKind::Const, container, false) + EntryKind::AssocConst(container, _, _) => { + (ty::AssocKind::Const, container, false) } EntryKind::Method(data) => { let data = data.decode(self); - (ty::AssociatedKind::Method, data.container, data.has_self) + (ty::AssocKind::Method, data.container, data.has_self) } - EntryKind::AssociatedType(container) => { - (ty::AssociatedKind::Type, container, false) + EntryKind::AssocType(container) => { + (ty::AssocKind::Type, container, false) } - EntryKind::AssociatedExistential(container) => { - (ty::AssociatedKind::Existential, container, false) + EntryKind::AssocExistential(container) => { + (ty::AssocKind::Existential, container, false) } _ => bug!("cannot get associated-item of `{:?}`", def_key) }; - ty::AssociatedItem { + ty::AssocItem { ident: Ident::from_interned_str(name), kind, vis: item.visibility.decode(self), @@ -924,10 +940,13 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option { + pub fn get_ctor_def_id(&self, node_id: DefIndex) -> Option { match self.entry(node_id).kind { EntryKind::Struct(data, _) => { - data.decode(self).struct_ctor.map(|index| self.local_def_id(index)) + data.decode(self).ctor.map(|index| self.local_def_id(index)) + } + EntryKind::Variant(data) => { + data.decode(self).ctor.map(|index| self.local_def_id(index)) } _ => None, } @@ -938,11 +957,11 @@ impl<'a, 'tcx> CrateMetadata { return Lrc::new([]); } - // The attributes for a tuple struct are attached to the definition, not the ctor; + // The attributes for a tuple struct/variant are attached to the definition, not the ctor; // we assume that someone passing in a tuple struct ctor is actually wanting to // look at the definition let def_key = self.def_key(node_id); - let item_id = if def_key.disambiguated_data.data == DefPathData::StructCtor { + let item_id = if def_key.disambiguated_data.data == DefPathData::Ctor { def_key.parent.unwrap() } else { node_id @@ -956,7 +975,7 @@ impl<'a, 'tcx> CrateMetadata { self.entry(id) .children .decode(self) - .map(|index| self.item_name(index).as_symbol()) + .map(|index| self.item_name(index)) .collect() } @@ -986,39 +1005,45 @@ impl<'a, 'tcx> CrateMetadata { None } - pub fn get_inherent_implementations_for_type(&self, id: DefIndex) -> Vec { - self.entry(id) - .inherent_impls - .decode(self) - .map(|index| self.local_def_id(index)) - .collect() + pub fn get_inherent_implementations_for_type( + &self, + tcx: TyCtxt<'tcx>, + id: DefIndex, + ) -> &'tcx [DefId] { + tcx.arena.alloc_from_iter(self.entry(id) + .inherent_impls + .decode(self) + .map(|index| self.local_def_id(index))) } - pub fn get_implementations_for_trait(&self, - filter: Option, - result: &mut Vec) { + pub fn get_implementations_for_trait( + &self, + tcx: TyCtxt<'tcx>, + filter: Option, + ) -> &'tcx [DefId] { if self.proc_macros.is_some() { // proc-macro crates export no trait impls. - return + return &[] } // Do a reverse lookup beforehand to avoid touching the crate_num // hash map in the loop below. let filter = match filter.map(|def_id| self.reverse_translate_def_id(def_id)) { Some(Some(def_id)) => Some((def_id.krate.as_u32(), def_id.index)), - Some(None) => return, + Some(None) => return &[], None => None, }; if let Some(filter) = filter { - if let Some(impls) = self.trait_impls - .get(&filter) { - result.extend(impls.decode(self).map(|idx| self.local_def_id(idx))); + if let Some(impls) = self.trait_impls.get(&filter) { + tcx.arena.alloc_from_iter(impls.decode(self).map(|idx| self.local_def_id(idx))) + } else { + &[] } } else { - for impls in self.trait_impls.values() { - result.extend(impls.decode(self).map(|idx| self.local_def_id(idx))); - } + tcx.arena.alloc_from_iter(self.trait_impls.values().flat_map(|impls| { + impls.decode(self).map(|idx| self.local_def_id(idx)) + })) } } @@ -1048,36 +1073,37 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_foreign_modules(&self, sess: &Session) -> Vec { + pub fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ForeignModule] { if self.proc_macros.is_some() { // Proc macro crates do not have any *target* foreign modules. - vec![] + &[] } else { - self.root.foreign_modules.decode((self, sess)).collect() + tcx.arena.alloc_from_iter(self.root.foreign_modules.decode((self, tcx.sess))) } } - pub fn get_dylib_dependency_formats(&self) -> Vec<(CrateNum, LinkagePreference)> { - self.root + pub fn get_dylib_dependency_formats( + &self, + tcx: TyCtxt<'tcx>, + ) -> &'tcx [(CrateNum, LinkagePreference)] { + tcx.arena.alloc_from_iter(self.root .dylib_dependency_formats .decode(self) .enumerate() .flat_map(|(i, link)| { let cnum = CrateNum::new(i + 1); link.map(|link| (self.cnum_map[cnum], link)) - }) - .collect() + })) } - pub fn get_missing_lang_items(&self) -> Vec { + pub fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] { if self.proc_macros.is_some() { // Proc macro crates do not depend on any target weak lang-items. - vec![] + &[] } else { - self.root + tcx.arena.alloc_from_iter(self.root .lang_items_missing - .decode(self) - .collect() + .decode(self)) } } @@ -1091,25 +1117,23 @@ impl<'a, 'tcx> CrateMetadata { arg_names.decode(self).collect() } - pub fn exported_symbols(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)> { + pub fn exported_symbols( + &self, + tcx: TyCtxt<'tcx>, + ) -> Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)> { if self.proc_macros.is_some() { // If this crate is a custom derive crate, then we're not even going to // link those in so we skip those crates. vec![] } else { - let lazy_seq: LazySeq<(ExportedSymbol<'tcx>, SymbolExportLevel)> = - LazySeq::with_position_and_length(self.root.exported_symbols.position, - self.root.exported_symbols.len); - lazy_seq.decode((self, tcx)).collect() + self.root.exported_symbols.decode((self, tcx)).collect() } } pub fn get_rendered_const(&self, id: DefIndex) -> String { match self.entry(id).kind { EntryKind::Const(_, data) | - EntryKind::AssociatedConst(_, _, data) => data.decode(self).0, + EntryKind::AssocConst(_, _, data) => data.decode(self).0, _ => bug!(), } } @@ -1126,6 +1150,7 @@ impl<'a, 'tcx> CrateMetadata { let constness = match self.entry(id).kind { EntryKind::Method(data) => data.decode(self).fn_data.constness, EntryKind::Fn(data) => data.decode(self).constness, + EntryKind::Variant(..) | EntryKind::Struct(..) => hir::Constness::Const, _ => hir::Constness::NotConst, }; constness == hir::Constness::Const @@ -1140,10 +1165,17 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn fn_sig(&self, - id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::PolyFnSig<'tcx> { + crate fn static_mutability(&self, id: DefIndex) -> Option { + match self.entry(id).kind { + EntryKind::ImmStatic | + EntryKind::ForeignImmStatic => Some(hir::MutImmutable), + EntryKind::MutStatic | + EntryKind::ForeignMutStatic => Some(hir::MutMutable), + _ => None, + } + } + + pub fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { let sig = match self.entry(id).kind { EntryKind::Fn(data) | EntryKind::ForeignFn(data) => data.decode(self).sig, diff --git a/src/librustc_metadata/dynamic_lib.rs b/src/librustc_metadata/dynamic_lib.rs index 9dd160c24c373..4c279361ff5e1 100644 --- a/src/librustc_metadata/dynamic_lib.rs +++ b/src/librustc_metadata/dynamic_lib.rs @@ -74,55 +74,7 @@ impl DynamicLibrary { } #[cfg(test)] -mod tests { - use super::*; - use std::mem; - - #[test] - fn test_loading_atoi() { - if cfg!(windows) { - return - } - - // The C library does not need to be loaded since it is already linked in - let lib = match DynamicLibrary::open(None) { - Err(error) => panic!("Could not load self as module: {}", error), - Ok(lib) => lib - }; - - let atoi: extern fn(*const libc::c_char) -> libc::c_int = unsafe { - match lib.symbol("atoi") { - Err(error) => panic!("Could not load function atoi: {}", error), - Ok(atoi) => mem::transmute::<*mut u8, _>(atoi) - } - }; - - let argument = CString::new("1383428980").unwrap(); - let expected_result = 0x52757374; - let result = atoi(argument.as_ptr()); - if result != expected_result { - panic!("atoi({:?}) != {} but equaled {} instead", argument, - expected_result, result) - } - } - - #[test] - fn test_errors_do_not_crash() { - use std::path::Path; - - if !cfg!(unix) { - return - } - - // Open /dev/null as a library to get an error, and make sure - // that only causes an error, and not a crash. - let path = Path::new("/dev/null"); - match DynamicLibrary::open(Some(&path)) { - Err(_) => {} - Ok(_) => panic!("Successfully opened the empty library.") - } - } -} +mod tests; #[cfg(unix)] mod dl { @@ -161,9 +113,9 @@ mod dl { pub fn check_for_errors_in(f: F) -> Result where F: FnOnce() -> T, { - use std::sync::{Mutex, Once, ONCE_INIT}; - static INIT: Once = ONCE_INIT; - static mut LOCK: *mut Mutex<()> = 0 as *mut _; + use std::sync::{Mutex, Once}; + static INIT: Once = Once::new(); + static mut LOCK: *mut Mutex<()> = ptr::null_mut(); unsafe { INIT.call_once(|| { LOCK = Box::into_raw(Box::new(Mutex::new(()))); diff --git a/src/librustc_metadata/dynamic_lib/tests.rs b/src/librustc_metadata/dynamic_lib/tests.rs new file mode 100644 index 0000000000000..b2302f2f1b5b7 --- /dev/null +++ b/src/librustc_metadata/dynamic_lib/tests.rs @@ -0,0 +1,47 @@ +use super::*; +use std::mem; + +#[test] +fn test_loading_atoi() { + if cfg!(windows) { + return + } + + // The C library does not need to be loaded since it is already linked in + let lib = match DynamicLibrary::open(None) { + Err(error) => panic!("Could not load self as module: {}", error), + Ok(lib) => lib + }; + + let atoi: extern fn(*const libc::c_char) -> libc::c_int = unsafe { + match lib.symbol("atoi") { + Err(error) => panic!("Could not load function atoi: {}", error), + Ok(atoi) => mem::transmute::<*mut u8, _>(atoi) + } + }; + + let argument = CString::new("1383428980").unwrap(); + let expected_result = 0x52757374; + let result = atoi(argument.as_ptr()); + if result != expected_result { + panic!("atoi({:?}) != {} but equaled {} instead", argument, + expected_result, result) + } +} + +#[test] +fn test_errors_do_not_crash() { + use std::path::Path; + + if !cfg!(unix) { + return + } + + // Open /dev/null as a library to get an error, and make sure + // that only causes an error, and not a crash. + let path = Path::new("/dev/null"); + match DynamicLibrary::open(Some(&path)) { + Err(_) => {} + Ok(_) => panic!("Successfully opened the empty library.") + } +} diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index b4a71b887dc37..b52b6dfbb5e12 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1,12 +1,11 @@ use crate::index::Index; -use crate::index_builder::{FromId, IndexBuilder, Untracked}; -use crate::isolated_encoder::IsolatedEncoder; use crate::schema::*; use rustc::middle::cstore::{LinkagePreference, NativeLibrary, EncodedMetadata, ForeignModule}; use rustc::hir::def::CtorKind; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LocalDefId, LOCAL_CRATE}; +use rustc::hir::GenericParamKind; use rustc::hir::map::definitions::DefPathTable; use rustc_data_structures::fingerprint::Fingerprint; use rustc::middle::dependency_format::Linkage; @@ -29,11 +28,11 @@ use std::hash::Hash; use std::path::Path; use rustc_data_structures::sync::Lrc; use std::u32; -use syntax::ast::{self, CRATE_NODE_ID}; +use syntax::ast; use syntax::attr; use syntax::source_map::Spanned; -use syntax::symbol::keywords; -use syntax_pos::{self, hygiene, FileName, SourceFile, Span}; +use syntax::symbol::{kw, sym}; +use syntax_pos::{self, FileName, SourceFile, Span}; use log::{debug, trace}; use rustc::hir::{self, PatKind}; @@ -41,9 +40,11 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; use rustc::hir::intravisit; -pub struct EncodeContext<'a, 'tcx: 'a> { +pub struct EncodeContext<'tcx> { opaque: opaque::Encoder, - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + pub tcx: TyCtxt<'tcx>, + + entries_index: Index<'tcx>, lazy_state: LazyState, type_shorthands: FxHashMap, usize>, @@ -64,7 +65,7 @@ macro_rules! encoder_methods { } } -impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> { +impl<'tcx> Encoder for EncodeContext<'tcx> { type Error = ::Error; fn emit_unit(&mut self) -> Result<(), Self::Error> { @@ -94,13 +95,13 @@ impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> { } } -impl<'a, 'tcx, T> SpecializedEncoder> for EncodeContext<'a, 'tcx> { +impl<'tcx, T> SpecializedEncoder> for EncodeContext<'tcx> { fn specialized_encode(&mut self, lazy: &Lazy) -> Result<(), Self::Error> { self.emit_lazy_distance(lazy.position, Lazy::::min_size()) } } -impl<'a, 'tcx, T> SpecializedEncoder> for EncodeContext<'a, 'tcx> { +impl<'tcx, T> SpecializedEncoder> for EncodeContext<'tcx> { fn specialized_encode(&mut self, seq: &LazySeq) -> Result<(), Self::Error> { self.emit_usize(seq.len)?; if seq.len == 0 { @@ -110,14 +111,14 @@ impl<'a, 'tcx, T> SpecializedEncoder> for EncodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { +impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { #[inline] fn specialized_encode(&mut self, cnum: &CrateNum) -> Result<(), Self::Error> { self.emit_u32(cnum.as_u32()) } } -impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { +impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { #[inline] fn specialized_encode(&mut self, def_id: &DefId) -> Result<(), Self::Error> { let DefId { @@ -130,14 +131,14 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { +impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { #[inline] fn specialized_encode(&mut self, def_index: &DefIndex) -> Result<(), Self::Error> { - self.emit_u32(def_index.as_raw_u32()) + self.emit_u32(def_index.as_u32()) } } -impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { +impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> { if span.is_dummy() { return TAG_INVALID_SPAN.encode(self) @@ -172,20 +173,20 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { +impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { #[inline] fn specialized_encode(&mut self, def_id: &LocalDefId) -> Result<(), Self::Error> { self.specialized_encode(&def_id.to_def_id()) } } -impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { +impl<'tcx> SpecializedEncoder> for EncodeContext<'tcx> { fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> { ty_codec::encode_with_shorthand(self, ty, |ecx| &mut ecx.type_shorthands) } } -impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { +impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { use std::collections::hash_map::Entry; let index = match self.interpret_allocs.entry(*alloc_id) { @@ -202,7 +203,7 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx } } -impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { +impl<'tcx> SpecializedEncoder> for EncodeContext<'tcx> { fn specialized_encode(&mut self, predicates: &ty::GenericPredicates<'tcx>) -> Result<(), Self::Error> { @@ -210,14 +211,13 @@ impl<'a, 'tcx> SpecializedEncoder> for EncodeContext } } -impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { +impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> { f.encode_opaque(&mut self.opaque) } } -impl<'a, 'tcx, T: Encodable> SpecializedEncoder> -for EncodeContext<'a, 'tcx> { +impl<'tcx, T: Encodable> SpecializedEncoder> for EncodeContext<'tcx> { fn specialized_encode(&mut self, _: &mir::ClearCrossCrate) -> Result<(), Self::Error> { @@ -225,14 +225,13 @@ for EncodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> { +impl<'tcx> TyEncoder for EncodeContext<'tcx> { fn position(&self) -> usize { self.opaque.position() } } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - +impl<'tcx> EncodeContext<'tcx> { fn emit_node R, R>(&mut self, f: F) -> R { assert_eq!(self.lazy_state, LazyState::NoNode); let pos = self.position(); @@ -299,28 +298,34 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) } - // Encodes something that corresponds to a single DepNode::GlobalMetaData - // and registers the Fingerprint in the `metadata_hashes` map. - pub fn tracked<'x, DATA, R>(&'x mut self, - op: fn(&mut IsolatedEncoder<'x, 'a, 'tcx>, DATA) -> R, - data: DATA) - -> R { - op(&mut IsolatedEncoder::new(self), data) + /// Emit the data for a `DefId` to the metadata. The function to + /// emit the data is `op`, and it will be given `data` as + /// arguments. This `record` function will call `op` to generate + /// the `Entry` (which may point to other encoded information) + /// and will then record the `Lazy` for use in the index. + // FIXME(eddyb) remove this. + pub fn record(&mut self, + id: DefId, + op: impl FnOnce(&mut Self, DATA) -> Entry<'tcx>, + data: DATA) + { + assert!(id.is_local()); + + let entry = op(self, data); + let entry = self.lazy(&entry); + self.entries_index.record(id, entry); } - fn encode_info_for_items(&mut self) -> Index { + fn encode_info_for_items(&mut self) { let krate = self.tcx.hir().krate(); - let mut index = IndexBuilder::new(self); let vis = Spanned { span: syntax_pos::DUMMY_SP, node: hir::VisibilityKind::Public }; - index.record(DefId::local(CRATE_DEF_INDEX), - IsolatedEncoder::encode_info_for_mod, - FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &vis))); - let mut visitor = EncodeVisitor { index }; - krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); + self.record(DefId::local(CRATE_DEF_INDEX), + EncodeContext::encode_info_for_mod, + (hir::CRATE_HIR_ID, &krate.module, &krate.attrs, &vis)); + krate.visit_all_item_likes(&mut self.as_deep_visitor()); for macro_def in &krate.exported_macros { - visitor.visit_macro_def(macro_def); + self.visit_macro_def(macro_def); } - visitor.index.into_items() } fn encode_def_path_table(&mut self) -> Lazy { @@ -370,38 +375,30 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_seq_ref(adapted.iter().map(|rc| &**rc)) } - fn encode_crate_root(&mut self) -> Lazy { + fn encode_crate_root(&mut self) -> Lazy> { let mut i = self.position(); - let crate_deps = self.tracked(IsolatedEncoder::encode_crate_deps, ()); - let dylib_dependency_formats = self.tracked( - IsolatedEncoder::encode_dylib_dependency_formats, - ()); + let crate_deps = self.encode_crate_deps(); + let dylib_dependency_formats = self.encode_dylib_dependency_formats(); let dep_bytes = self.position() - i; // Encode the lib features. i = self.position(); - let lib_features = self.tracked(IsolatedEncoder::encode_lib_features, ()); + let lib_features = self.encode_lib_features(); let lib_feature_bytes = self.position() - i; // Encode the language items. i = self.position(); - let lang_items = self.tracked(IsolatedEncoder::encode_lang_items, ()); - let lang_items_missing = self.tracked( - IsolatedEncoder::encode_lang_items_missing, - ()); + let lang_items = self.encode_lang_items(); + let lang_items_missing = self.encode_lang_items_missing(); let lang_item_bytes = self.position() - i; // Encode the native libraries used i = self.position(); - let native_libraries = self.tracked( - IsolatedEncoder::encode_native_libraries, - ()); + let native_libraries = self.encode_native_libraries(); let native_lib_bytes = self.position() - i; - let foreign_modules = self.tracked( - IsolatedEncoder::encode_foreign_modules, - ()); + let foreign_modules = self.encode_foreign_modules(); // Encode source_map i = self.position(); @@ -415,22 +412,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encode the def IDs of impls, for coherence checking. i = self.position(); - let impls = self.tracked(IsolatedEncoder::encode_impls, ()); + let impls = self.encode_impls(); let impl_bytes = self.position() - i; // Encode exported symbols info. i = self.position(); let exported_symbols = self.tcx.exported_symbols(LOCAL_CRATE); - let exported_symbols = self.tracked( - IsolatedEncoder::encode_exported_symbols, - &exported_symbols); + let exported_symbols = self.encode_exported_symbols(&exported_symbols); let exported_symbols_bytes = self.position() - i; let tcx = self.tcx; // Encode the items. i = self.position(); - let items = self.encode_info_for_items(); + self.encode_info_for_items(); let item_bytes = self.position() - i; // Encode the allocation index @@ -461,14 +456,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_seq(interpret_alloc_index) }; - // Index the items i = self.position(); - let index = items.write_index(&mut self.opaque); - let index_bytes = self.position() - i; + let entries_index = self.entries_index.write_index(&mut self.opaque); + let entries_index_bytes = self.position() - i; let attrs = tcx.hir().krate_attrs(); let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro); - let has_default_lib_allocator = attr::contains_name(&attrs, "default_lib_allocator"); + let has_default_lib_allocator = attr::contains_name(&attrs, sym::default_lib_allocator); let has_global_allocator = *tcx.sess.has_global_allocator.get(); let has_panic_handler = *tcx.sess.has_panic_handler.try_get().unwrap_or(&false); @@ -479,7 +473,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hash: tcx.crate_hash(LOCAL_CRATE), disambiguator: tcx.sess.local_crate_disambiguator(), panic_strategy: tcx.sess.panic_strategy(), - edition: hygiene::default_edition(), + edition: tcx.sess.edition(), has_global_allocator: has_global_allocator, has_panic_handler: has_panic_handler, has_default_lib_allocator: has_default_lib_allocator, @@ -490,14 +484,19 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { None }, - - compiler_builtins: attr::contains_name(&attrs, "compiler_builtins"), - needs_allocator: attr::contains_name(&attrs, "needs_allocator"), - needs_panic_runtime: attr::contains_name(&attrs, "needs_panic_runtime"), - no_builtins: attr::contains_name(&attrs, "no_builtins"), - panic_runtime: attr::contains_name(&attrs, "panic_runtime"), - profiler_runtime: attr::contains_name(&attrs, "profiler_runtime"), - sanitizer_runtime: attr::contains_name(&attrs, "sanitizer_runtime"), + proc_macro_stability: if is_proc_macro { + tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).map(|stab| stab.clone()) + } else { + None + }, + compiler_builtins: attr::contains_name(&attrs, sym::compiler_builtins), + needs_allocator: attr::contains_name(&attrs, sym::needs_allocator), + needs_panic_runtime: attr::contains_name(&attrs, sym::needs_panic_runtime), + no_builtins: attr::contains_name(&attrs, sym::no_builtins), + panic_runtime: attr::contains_name(&attrs, sym::panic_runtime), + profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime), + sanitizer_runtime: attr::contains_name(&attrs, sym::sanitizer_runtime), + symbol_mangling_version: tcx.sess.opts.debugging_opts.symbol_mangling_version, crate_deps, dylib_dependency_formats, @@ -511,7 +510,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { impls, exported_symbols, interpret_alloc_index, - index, + entries_index, }); let total_bytes = self.position(); @@ -534,7 +533,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { println!(" exp. symbols bytes: {}", exported_symbols_bytes); println!(" def-path table bytes: {}", def_path_table_bytes); println!(" item bytes: {}", item_bytes); - println!(" index bytes: {}", index_bytes); + println!(" entries index bytes: {}", entries_index_bytes); println!(" zero bytes: {}", zero_bytes); println!(" total bytes: {}", total_bytes); } @@ -543,52 +542,43 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } -// These are methods for encoding various things. They are meant to be used with -// IndexBuilder::record() and EncodeContext::tracked(). They actually -// would not have to be methods of IsolatedEncoder (free standing functions -// taking IsolatedEncoder as first argument would be just fine) but by making -// them methods we don't have to repeat the lengthy `<'a, 'b: 'a, 'tcx: 'b>` -// clause again and again. -impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { +impl EncodeContext<'tcx> { fn encode_variances_of(&mut self, def_id: DefId) -> LazySeq { - debug!("IsolatedEncoder::encode_variances_of({:?})", def_id); + debug!("EncodeContext::encode_variances_of({:?})", def_id); let tcx = self.tcx; - self.lazy_seq_from_slice(&tcx.variances_of(def_id)) + self.lazy_seq_ref(&tcx.variances_of(def_id)[..]) } fn encode_item_type(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; let ty = tcx.type_of(def_id); - debug!("IsolatedEncoder::encode_item_type({:?}) => {:?}", def_id, ty); + debug!("EncodeContext::encode_item_type({:?}) => {:?}", def_id, ty); self.lazy(&ty) } - /// Encode data for the given variant of the given ADT. The - /// index of the variant is untracked: this is ok because we - /// will have to lookup the adt-def by its id, and that gives us - /// the right to access any information in the adt-def (including, - /// e.g., the length of the various vectors). - fn encode_enum_variant_info(&mut self, - (enum_did, Untracked(index)): (DefId, Untracked)) - -> Entry<'tcx> { + fn encode_enum_variant_info( + &mut self, + (enum_did, index): (DefId, VariantIdx), + ) -> Entry<'tcx> { let tcx = self.tcx; let def = tcx.adt_def(enum_did); let variant = &def.variants[index]; - let def_id = variant.did; - debug!("IsolatedEncoder::encode_enum_variant_info({:?})", def_id); + let def_id = variant.def_id; + debug!("EncodeContext::encode_enum_variant_info({:?})", def_id); let data = VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - struct_ctor: None, + // FIXME(eddyb) deduplicate these with `encode_enum_variant_ctor`. + ctor: variant.ctor_def_id.map(|did| did.index), ctor_sig: if variant.ctor_kind == CtorKind::Fn { - Some(self.lazy(&tcx.fn_sig(def_id))) + variant.ctor_def_id.map(|ctor_def_id| self.lazy(&tcx.fn_sig(ctor_def_id))) } else { None - } + }, }; - let enum_id = tcx.hir().as_local_node_id(enum_did).unwrap(); + let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap(); let enum_vis = &tcx.hir().expect_item(enum_id).vis; Entry { @@ -618,18 +608,71 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } } - fn encode_info_for_mod(&mut self, - FromId(id, (md, attrs, vis)): FromId<(&hir::Mod, - &[ast::Attribute], - &hir::Visibility)>) - -> Entry<'tcx> { + fn encode_enum_variant_ctor( + &mut self, + (enum_did, index): (DefId, VariantIdx), + ) -> Entry<'tcx> { let tcx = self.tcx; - let def_id = tcx.hir().local_def_id(id); - debug!("IsolatedEncoder::encode_info_for_mod({:?})", def_id); + let def = tcx.adt_def(enum_did); + let variant = &def.variants[index]; + let def_id = variant.ctor_def_id.unwrap(); + debug!("EncodeContext::encode_enum_variant_ctor({:?})", def_id); + + let data = VariantData { + ctor_kind: variant.ctor_kind, + discr: variant.discr, + ctor: Some(def_id.index), + ctor_sig: if variant.ctor_kind == CtorKind::Fn { + Some(self.lazy(&tcx.fn_sig(def_id))) + } else { + None + } + }; + + // Variant constructors have the same visibility as the parent enums, unless marked as + // non-exhaustive, in which case they are lowered to `pub(crate)`. + let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap(); + let enum_vis = &tcx.hir().expect_item(enum_id).vis; + let mut ctor_vis = ty::Visibility::from_hir(enum_vis, enum_id, tcx); + if variant.is_field_list_non_exhaustive() && ctor_vis == ty::Visibility::Public { + ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); + } + + Entry { + kind: EntryKind::Variant(self.lazy(&data)), + visibility: self.lazy(&ctor_vis), + span: self.lazy(&tcx.def_span(def_id)), + attributes: LazySeq::empty(), + children: LazySeq::empty(), + stability: self.encode_stability(def_id), + deprecation: self.encode_deprecation(def_id), + + ty: Some(self.encode_item_type(def_id)), + inherent_impls: LazySeq::empty(), + variances: if variant.ctor_kind == CtorKind::Fn { + self.encode_variances_of(def_id) + } else { + LazySeq::empty() + }, + generics: Some(self.encode_generics(def_id)), + predicates: Some(self.encode_predicates(def_id)), + predicates_defined_on: None, + + mir: self.encode_optimized_mir(def_id), + } + } + + fn encode_info_for_mod( + &mut self, + (id, md, attrs, vis): (hir::HirId, &hir::Mod, &[ast::Attribute], &hir::Visibility), + ) -> Entry<'tcx> { + let tcx = self.tcx; + let def_id = tcx.hir().local_def_id_from_hir_id(id); + debug!("EncodeContext::encode_info_for_mod({:?})", def_id); let data = ModData { reexports: match tcx.module_exports(def_id) { - Some(ref exports) => self.lazy_seq_from_slice(exports.as_slice()), + Some(exports) => self.lazy_seq_ref(exports), _ => LazySeq::empty(), }, }; @@ -640,7 +683,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { span: self.lazy(&tcx.def_span(def_id)), attributes: self.encode_attributes(attrs), children: self.lazy_seq(md.item_ids.iter().map(|item_id| { - tcx.hir().local_def_id(item_id.id).index + tcx.hir().local_def_id_from_hir_id(item_id.id).index })), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), @@ -656,25 +699,18 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } } - /// Encode data for the given field of the given variant of the - /// given ADT. The indices of the variant/field are untracked: - /// this is ok because we will have to lookup the adt-def by its - /// id, and that gives us the right to access any information in - /// the adt-def (including, e.g., the length of the various - /// vectors). - fn encode_field(&mut self, - (adt_def_id, Untracked((variant_index, field_index))): (DefId, - Untracked<(VariantIdx, - usize)>)) - -> Entry<'tcx> { + fn encode_field( + &mut self, + (adt_def_id, variant_index, field_index): (DefId, VariantIdx, usize), + ) -> Entry<'tcx> { let tcx = self.tcx; let variant = &tcx.adt_def(adt_def_id).variants[variant_index]; let field = &variant.fields[field_index]; let def_id = field.did; - debug!("IsolatedEncoder::encode_field({:?})", def_id); + debug!("EncodeContext::encode_field({:?})", def_id); - let variant_id = tcx.hir().as_local_hir_id(variant.did).unwrap(); + let variant_id = tcx.hir().as_local_hir_id(variant.def_id).unwrap(); let variant_data = tcx.hir().expect_variant_data(variant_id); Entry { @@ -698,7 +734,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<'tcx> { - debug!("IsolatedEncoder::encode_struct_ctor({:?})", def_id); + debug!("EncodeContext::encode_struct_ctor({:?})", def_id); let tcx = self.tcx; let adt_def = tcx.adt_def(adt_def_id); let variant = adt_def.non_enum_variant(); @@ -706,7 +742,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let data = VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - struct_ctor: Some(def_id.index), + ctor: Some(def_id.index), ctor_sig: if variant.ctor_kind == CtorKind::Fn { Some(self.lazy(&tcx.fn_sig(def_id))) } else { @@ -714,7 +750,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } }; - let struct_id = tcx.hir().as_local_node_id(adt_def_id).unwrap(); + let struct_id = tcx.hir().as_local_hir_id(adt_def_id).unwrap(); let struct_vis = &tcx.hir().expect_item(struct_id).vis; let mut ctor_vis = ty::Visibility::from_hir(struct_vis, struct_id, tcx); for field in &variant.fields { @@ -731,7 +767,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); } - let repr_options = get_repr_options(&tcx, adt_def_id); + let repr_options = get_repr_options(tcx, adt_def_id); Entry { kind: EntryKind::Struct(self.lazy(&data), repr_options), @@ -758,42 +794,42 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } fn encode_generics(&mut self, def_id: DefId) -> Lazy { - debug!("IsolatedEncoder::encode_generics({:?})", def_id); + debug!("EncodeContext::encode_generics({:?})", def_id); let tcx = self.tcx; self.lazy(tcx.generics_of(def_id)) } fn encode_predicates(&mut self, def_id: DefId) -> Lazy> { - debug!("IsolatedEncoder::encode_predicates({:?})", def_id); + debug!("EncodeContext::encode_predicates({:?})", def_id); let tcx = self.tcx; self.lazy(&tcx.predicates_of(def_id)) } fn encode_predicates_defined_on(&mut self, def_id: DefId) -> Lazy> { - debug!("IsolatedEncoder::encode_predicates_defined_on({:?})", def_id); + debug!("EncodeContext::encode_predicates_defined_on({:?})", def_id); let tcx = self.tcx; self.lazy(&tcx.predicates_defined_on(def_id)) } fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> { - debug!("IsolatedEncoder::encode_info_for_trait_item({:?})", def_id); + debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id); let tcx = self.tcx; - let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); - let ast_item = tcx.hir().expect_trait_item(node_id); + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let ast_item = tcx.hir().expect_trait_item(hir_id); let trait_item = tcx.associated_item(def_id); let container = match trait_item.defaultness { hir::Defaultness::Default { has_value: true } => - AssociatedContainer::TraitWithDefault, + AssocContainer::TraitWithDefault, hir::Defaultness::Default { has_value: false } => - AssociatedContainer::TraitRequired, + AssocContainer::TraitRequired, hir::Defaultness::Final => span_bug!(ast_item.span, "traits cannot have final items"), }; let kind = match trait_item.kind { - ty::AssociatedKind::Const => { + ty::AssocKind::Const => { let const_qualif = if let hir::TraitItemKind::Const(_, Some(body)) = ast_item.node { self.const_qualif(0, body) @@ -805,9 +841,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { hir::print::to_string(self.tcx.hir(), |s| s.print_trait_item(ast_item)); let rendered_const = self.lazy(&RenderedConst(rendered)); - EntryKind::AssociatedConst(container, const_qualif, rendered_const) + EntryKind::AssocConst(container, const_qualif, rendered_const) } - ty::AssociatedKind::Method => { + ty::AssocKind::Method => { let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node { let arg_names = match *m { hir::TraitMethod::Required(ref names) => { @@ -831,8 +867,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { has_self: trait_item.method_has_self_argument, })) } - ty::AssociatedKind::Type => EntryKind::AssociatedType(container), - ty::AssociatedKind::Existential => + ty::AssocKind::Type => EntryKind::AssocType(container), + ty::AssocKind::Existential => span_bug!(ast_item.span, "existential type in trait"), }; @@ -846,21 +882,21 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { deprecation: self.encode_deprecation(def_id), ty: match trait_item.kind { - ty::AssociatedKind::Const | - ty::AssociatedKind::Method => { + ty::AssocKind::Const | + ty::AssocKind::Method => { Some(self.encode_item_type(def_id)) } - ty::AssociatedKind::Type => { + ty::AssocKind::Type => { if trait_item.defaultness.has_value() { Some(self.encode_item_type(def_id)) } else { None } } - ty::AssociatedKind::Existential => unreachable!(), + ty::AssocKind::Existential => unreachable!(), }, inherent_impls: LazySeq::empty(), - variances: if trait_item.kind == ty::AssociatedKind::Method { + variances: if trait_item.kind == ty::AssocKind::Method { self.encode_variances_of(def_id) } else { LazySeq::empty() @@ -886,33 +922,33 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> { - debug!("IsolatedEncoder::encode_info_for_impl_item({:?})", def_id); + debug!("EncodeContext::encode_info_for_impl_item({:?})", def_id); let tcx = self.tcx; - let node_id = self.tcx.hir().as_local_node_id(def_id).unwrap(); - let ast_item = self.tcx.hir().expect_impl_item(node_id); + let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap(); + let ast_item = self.tcx.hir().expect_impl_item(hir_id); let impl_item = self.tcx.associated_item(def_id); let container = match impl_item.defaultness { - hir::Defaultness::Default { has_value: true } => AssociatedContainer::ImplDefault, - hir::Defaultness::Final => AssociatedContainer::ImplFinal, + hir::Defaultness::Default { has_value: true } => AssocContainer::ImplDefault, + hir::Defaultness::Final => AssocContainer::ImplFinal, hir::Defaultness::Default { has_value: false } => span_bug!(ast_item.span, "impl items always have values (currently)"), }; let kind = match impl_item.kind { - ty::AssociatedKind::Const => { + ty::AssocKind::Const => { if let hir::ImplItemKind::Const(_, body_id) = ast_item.node { let mir = self.tcx.at(ast_item.span).mir_const_qualif(def_id).0; - EntryKind::AssociatedConst(container, + EntryKind::AssocConst(container, self.const_qualif(mir, body_id), self.encode_rendered_const_for_body(body_id)) } else { bug!() } } - ty::AssociatedKind::Method => { + ty::AssocKind::Method => { let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node { FnData { constness: sig.header.constness, @@ -928,8 +964,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { has_self: impl_item.method_has_self_argument, })) } - ty::AssociatedKind::Existential => EntryKind::AssociatedExistential(container), - ty::AssociatedKind::Type => EntryKind::AssociatedType(container) + ty::AssocKind::Existential => EntryKind::AssocExistential(container), + ty::AssocKind::Type => EntryKind::AssocType(container) }; let mir = @@ -959,7 +995,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { ty: Some(self.encode_item_type(def_id)), inherent_impls: LazySeq::empty(), - variances: if impl_item.kind == ty::AssociatedKind::Method { + variances: if impl_item.kind == ty::AssocKind::Method { self.encode_variances_of(def_id) } else { LazySeq::empty() @@ -978,8 +1014,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let body = self.tcx.hir().body(body_id); self.lazy_seq(body.arguments.iter().map(|arg| { match arg.pat.node { - PatKind::Binding(_, _, _, ident, _) => ident.name, - _ => keywords::Invalid.name(), + PatKind::Binding(_, _, ident, _) => ident.name, + _ => kw::Invalid, } })) }) @@ -989,7 +1025,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { self.lazy_seq(param_names.iter().map(|ident| ident.name)) } - fn encode_optimized_mir(&mut self, def_id: DefId) -> Option>> { + fn encode_optimized_mir(&mut self, def_id: DefId) -> Option>> { debug!("EntryBuilder::encode_mir({:?})", def_id); if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) { let mir = self.tcx.optimized_mir(def_id); @@ -1001,7 +1037,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { // Encodes the inherent implementations of a structure, enumeration, or trait. fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq { - debug!("IsolatedEncoder::encode_inherent_implementations({:?})", def_id); + debug!("EncodeContext::encode_inherent_implementations({:?})", def_id); let implementations = self.tcx.inherent_impls(def_id); if implementations.is_empty() { LazySeq::empty() @@ -1014,12 +1050,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } fn encode_stability(&mut self, def_id: DefId) -> Option> { - debug!("IsolatedEncoder::encode_stability({:?})", def_id); + debug!("EncodeContext::encode_stability({:?})", def_id); self.tcx.lookup_stability(def_id).map(|stab| self.lazy(stab)) } fn encode_deprecation(&mut self, def_id: DefId) -> Option> { - debug!("IsolatedEncoder::encode_deprecation({:?})", def_id); + debug!("EncodeContext::encode_deprecation({:?})", def_id); self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr)) } @@ -1033,7 +1069,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> Entry<'tcx> { let tcx = self.tcx; - debug!("IsolatedEncoder::encode_info_for_item({:?})", def_id); + debug!("EncodeContext::encode_info_for_item({:?})", def_id); let kind = match item.node { hir::ItemKind::Static(_, hir::MutMutable, _) => EntryKind::MutStatic, @@ -1055,42 +1091,39 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { EntryKind::Fn(self.lazy(&data)) } hir::ItemKind::Mod(ref m) => { - return self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, &item.vis))); + return self.encode_info_for_mod((item.hir_id, m, &item.attrs, &item.vis)); } hir::ItemKind::ForeignMod(_) => EntryKind::ForeignMod, hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm, hir::ItemKind::Ty(..) => EntryKind::Type, hir::ItemKind::Existential(..) => EntryKind::Existential, - hir::ItemKind::Enum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)), + hir::ItemKind::Enum(..) => EntryKind::Enum(get_repr_options(tcx, def_id)), hir::ItemKind::Struct(ref struct_def, _) => { let variant = tcx.adt_def(def_id).non_enum_variant(); // Encode def_ids for each field and method // for methods, write all the stuff get_trait_method // needs to know - let struct_ctor = if !struct_def.is_struct() { - Some(tcx.hir().local_def_id(struct_def.id()).index) - } else { - None - }; + let ctor = struct_def.ctor_hir_id() + .map(|ctor_hir_id| tcx.hir().local_def_id_from_hir_id(ctor_hir_id).index); - let repr_options = get_repr_options(&tcx, def_id); + let repr_options = get_repr_options(tcx, def_id); EntryKind::Struct(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - struct_ctor, + ctor, ctor_sig: None, }), repr_options) } hir::ItemKind::Union(..) => { let variant = tcx.adt_def(def_id).non_enum_variant(); - let repr_options = get_repr_options(&tcx, def_id); + let repr_options = get_repr_options(tcx, def_id); EntryKind::Union(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - struct_ctor: None, + ctor: None, ctor_sig: None, }), repr_options) } @@ -1154,20 +1187,21 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { Entry { kind, - visibility: self.lazy(&ty::Visibility::from_hir(&item.vis, item.id, tcx)), + visibility: self.lazy(&ty::Visibility::from_hir(&item.vis, item.hir_id, tcx)), span: self.lazy(&item.span), attributes: self.encode_attributes(&item.attrs), children: match item.node { hir::ItemKind::ForeignMod(ref fm) => { self.lazy_seq(fm.items .iter() - .map(|foreign_item| tcx.hir().local_def_id(foreign_item.id).index)) + .map(|foreign_item| tcx.hir().local_def_id_from_hir_id( + foreign_item.hir_id).index)) } hir::ItemKind::Enum(..) => { let def = self.tcx.adt_def(def_id); self.lazy_seq(def.variants.iter().map(|v| { - assert!(v.did.is_local()); - v.did.index + assert!(v.def_id.is_local()); + v.def_id.index })) } hir::ItemKind::Struct(..) | @@ -1302,25 +1336,22 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } } - fn encode_info_for_ty_param(&mut self, - (def_id, Untracked(has_default)): (DefId, Untracked)) - -> Entry<'tcx> { - debug!("IsolatedEncoder::encode_info_for_ty_param({:?})", def_id); + fn encode_info_for_generic_param( + &mut self, + def_id: DefId, + entry_kind: EntryKind<'tcx>, + encode_type: bool, + ) -> Entry<'tcx> { let tcx = self.tcx; Entry { - kind: EntryKind::Type, + kind: entry_kind, visibility: self.lazy(&ty::Visibility::Public), span: self.lazy(&tcx.def_span(def_id)), attributes: LazySeq::empty(), children: LazySeq::empty(), stability: None, deprecation: None, - - ty: if has_default { - Some(self.encode_item_type(def_id)) - } else { - None - }, + ty: if encode_type { Some(self.encode_item_type(def_id)) } else { None }, inherent_impls: LazySeq::empty(), variances: LazySeq::empty(), generics: None, @@ -1331,36 +1362,28 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } } - fn encode_info_for_const_param(&mut self, def_id: DefId) -> Entry<'tcx> { - debug!("IsolatedEncoder::encode_info_for_const_param({:?})", def_id); - let tcx = self.tcx; - Entry { - kind: EntryKind::Type, - visibility: self.lazy(&ty::Visibility::Public), - span: self.lazy(&tcx.def_span(def_id)), - attributes: LazySeq::empty(), - children: LazySeq::empty(), - stability: None, - deprecation: None, - - ty: Some(self.encode_item_type(def_id)), - inherent_impls: LazySeq::empty(), - variances: LazySeq::empty(), - generics: None, - predicates: None, - predicates_defined_on: None, + fn encode_info_for_ty_param( + &mut self, + (def_id, encode_type): (DefId, bool), + ) -> Entry<'tcx> { + debug!("EncodeContext::encode_info_for_ty_param({:?})", def_id); + self.encode_info_for_generic_param(def_id, EntryKind::TypeParam, encode_type) + } - mir: None, - } + fn encode_info_for_const_param( + &mut self, + def_id: DefId, + ) -> Entry<'tcx> { + debug!("EncodeContext::encode_info_for_const_param({:?})", def_id); + self.encode_info_for_generic_param(def_id, EntryKind::ConstParam, true) } fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> { - debug!("IsolatedEncoder::encode_info_for_closure({:?})", def_id); + debug!("EncodeContext::encode_info_for_closure({:?})", def_id); let tcx = self.tcx; let tables = self.tcx.typeck_tables_of(def_id); - let node_id = self.tcx.hir().as_local_node_id(def_id).unwrap(); - let hir_id = self.tcx.hir().node_to_hir_id(node_id); + let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap(); let kind = match tables.node_type(hir_id).sty { ty::Generator(def_id, ..) => { let layout = self.tcx.generator_layout(def_id); @@ -1400,9 +1423,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } fn encode_info_for_anon_const(&mut self, def_id: DefId) -> Entry<'tcx> { - debug!("IsolatedEncoder::encode_info_for_anon_const({:?})", def_id); + debug!("EncodeContext::encode_info_for_anon_const({:?})", def_id); let tcx = self.tcx; - let id = tcx.hir().as_local_node_id(def_id).unwrap(); + let id = tcx.hir().as_local_hir_id(def_id).unwrap(); let body_id = tcx.hir().body_owned_by(id); let const_data = self.encode_rendered_const_for_body(body_id); let mir = tcx.mir_const_qualif(def_id).0; @@ -1428,23 +1451,20 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { - // NOTE: This must use lazy_seq_from_slice(), not lazy_seq() because - // we rely on the HashStable specialization for [Attribute] - // to properly filter things out. - self.lazy_seq_from_slice(attrs) + self.lazy_seq_ref(attrs) } - fn encode_native_libraries(&mut self, _: ()) -> LazySeq { + fn encode_native_libraries(&mut self) -> LazySeq { let used_libraries = self.tcx.native_libraries(LOCAL_CRATE); self.lazy_seq(used_libraries.iter().cloned()) } - fn encode_foreign_modules(&mut self, _: ()) -> LazySeq { + fn encode_foreign_modules(&mut self) -> LazySeq { let foreign_modules = self.tcx.foreign_modules(LOCAL_CRATE); self.lazy_seq(foreign_modules.iter().cloned()) } - fn encode_crate_deps(&mut self, _: ()) -> LazySeq { + fn encode_crate_deps(&mut self) -> LazySeq { let crates = self.tcx.crates(); let mut deps = crates @@ -1478,13 +1498,13 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { self.lazy_seq_ref(deps.iter().map(|&(_, ref dep)| dep)) } - fn encode_lib_features(&mut self, _: ()) -> LazySeq<(ast::Name, Option)> { + fn encode_lib_features(&mut self) -> LazySeq<(ast::Name, Option)> { let tcx = self.tcx; let lib_features = tcx.lib_features(); self.lazy_seq(lib_features.to_vec()) } - fn encode_lang_items(&mut self, _: ()) -> LazySeq<(DefIndex, usize)> { + fn encode_lang_items(&mut self) -> LazySeq<(DefIndex, usize)> { let tcx = self.tcx; let lang_items = tcx.lang_items(); let lang_items = lang_items.items().iter(); @@ -1498,14 +1518,14 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { })) } - fn encode_lang_items_missing(&mut self, _: ()) -> LazySeq { + fn encode_lang_items_missing(&mut self) -> LazySeq { let tcx = self.tcx; self.lazy_seq_ref(&tcx.lang_items().missing) } /// Encodes an index, mapping each trait to its (local) implementations. - fn encode_impls(&mut self, _: ()) -> LazySeq { - debug!("IsolatedEncoder::encode_impls()"); + fn encode_impls(&mut self) -> LazySeq { + debug!("EncodeContext::encode_impls()"); let tcx = self.tcx; let mut visitor = ImplVisitor { tcx, @@ -1530,12 +1550,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { TraitImpls { trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index), - impls: self.lazy_seq_from_slice(&impls[..]), + impls: self.lazy_seq_ref(&impls), } }) .collect(); - self.lazy_seq_from_slice(&all_impls[..]) + self.lazy_seq_ref(&all_impls) } // Encodes all symbols exported from this crate into the metadata. @@ -1545,13 +1565,13 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { // symbol associated with them (they weren't translated) or if they're an FFI // definition (as that's not defined in this crate). fn encode_exported_symbols(&mut self, - exported_symbols: &[(ExportedSymbol<'_>, SymbolExportLevel)]) - -> EncodedExportedSymbols { + exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportLevel)]) + -> LazySeq<(ExportedSymbol<'tcx>, SymbolExportLevel)> { // The metadata symbol name is special. It should not show up in // downstream crates. let metadata_symbol_name = SymbolName::new(&metadata_symbol_name(self.tcx)); - let lazy_seq = self.lazy_seq(exported_symbols + self.lazy_seq(exported_symbols .iter() .filter(|&&(ref exported_symbol, _)| { match *exported_symbol { @@ -1561,15 +1581,10 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { _ => true, } }) - .cloned()); - - EncodedExportedSymbols { - len: lazy_seq.len, - position: lazy_seq.position, - } + .cloned()) } - fn encode_dylib_dependency_formats(&mut self, _: ()) -> LazySeq> { + fn encode_dylib_dependency_formats(&mut self) -> LazySeq> { match self.tcx.sess.dependency_formats.borrow().get(&config::CrateType::Dylib) { Some(arr) => { self.lazy_seq(arr.iter().map(|slot| { @@ -1591,7 +1606,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { -> Entry<'tcx> { let tcx = self.tcx; - debug!("IsolatedEncoder::encode_info_for_foreign_item({:?})", def_id); + debug!("EncodeContext::encode_info_for_foreign_item({:?})", def_id); let kind = match nitem.node { hir::ForeignItemKind::Fn(_, ref names, _) => { @@ -1602,14 +1617,14 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { }; EntryKind::ForeignFn(self.lazy(&data)) } - hir::ForeignItemKind::Static(_, true) => EntryKind::ForeignMutStatic, - hir::ForeignItemKind::Static(_, false) => EntryKind::ForeignImmStatic, + hir::ForeignItemKind::Static(_, hir::MutMutable) => EntryKind::ForeignMutStatic, + hir::ForeignItemKind::Static(_, hir::MutImmutable) => EntryKind::ForeignImmStatic, hir::ForeignItemKind::Type => EntryKind::ForeignType, }; Entry { kind, - visibility: self.lazy(&ty::Visibility::from_hir(&nitem.vis, nitem.id, tcx)), + visibility: self.lazy(&ty::Visibility::from_hir(&nitem.vis, nitem.hir_id, tcx)), span: self.lazy(&nitem.span), attributes: self.encode_attributes(&nitem.attrs), children: LazySeq::empty(), @@ -1631,33 +1646,29 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } } -struct EncodeVisitor<'a, 'b: 'a, 'tcx: 'b> { - index: IndexBuilder<'a, 'b, 'tcx>, -} - -impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { +impl Visitor<'tcx> for EncodeContext<'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::OnlyBodies(&self.index.tcx.hir()) + NestedVisitorMap::OnlyBodies(&self.tcx.hir()) } fn visit_expr(&mut self, ex: &'tcx hir::Expr) { intravisit::walk_expr(self, ex); - self.index.encode_info_for_expr(ex); + self.encode_info_for_expr(ex); } fn visit_item(&mut self, item: &'tcx hir::Item) { intravisit::walk_item(self, item); - let def_id = self.index.tcx.hir().local_def_id(item.id); + let def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); match item.node { hir::ItemKind::ExternCrate(_) | - hir::ItemKind::Use(..) => (), // ignore these - _ => self.index.record(def_id, IsolatedEncoder::encode_info_for_item, (def_id, item)), + hir::ItemKind::Use(..) => {} // ignore these + _ => self.record(def_id, EncodeContext::encode_info_for_item, (def_id, item)), } - self.index.encode_addl_info_for_item(item); + self.encode_addl_info_for_item(item); } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { intravisit::walk_foreign_item(self, ni); - let def_id = self.index.tcx.hir().local_def_id(ni.id); - self.index.record(def_id, - IsolatedEncoder::encode_info_for_foreign_item, + let def_id = self.tcx.hir().local_def_id_from_hir_id(ni.hir_id); + self.record(def_id, + EncodeContext::encode_info_for_foreign_item, (def_id, ni)); } fn visit_variant(&mut self, @@ -1667,50 +1678,50 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { intravisit::walk_variant(self, v, g, id); if let Some(ref discr) = v.node.disr_expr { - let def_id = self.index.tcx.hir().local_def_id_from_hir_id(discr.hir_id); - self.index.record(def_id, IsolatedEncoder::encode_info_for_anon_const, def_id); + let def_id = self.tcx.hir().local_def_id_from_hir_id(discr.hir_id); + self.record(def_id, EncodeContext::encode_info_for_anon_const, def_id); } } fn visit_generics(&mut self, generics: &'tcx hir::Generics) { intravisit::walk_generics(self, generics); - self.index.encode_info_for_generics(generics); + self.encode_info_for_generics(generics); } fn visit_ty(&mut self, ty: &'tcx hir::Ty) { intravisit::walk_ty(self, ty); - self.index.encode_info_for_ty(ty); + self.encode_info_for_ty(ty); } fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef) { - let def_id = self.index.tcx.hir().local_def_id_from_hir_id(macro_def.hir_id); - self.index.record(def_id, IsolatedEncoder::encode_info_for_macro_def, macro_def); + let def_id = self.tcx.hir().local_def_id_from_hir_id(macro_def.hir_id); + self.record(def_id, EncodeContext::encode_info_for_macro_def, macro_def); } } -impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { +impl EncodeContext<'tcx> { fn encode_fields(&mut self, adt_def_id: DefId) { let def = self.tcx.adt_def(adt_def_id); for (variant_index, variant) in def.variants.iter_enumerated() { for (field_index, field) in variant.fields.iter().enumerate() { self.record(field.did, - IsolatedEncoder::encode_field, - (adt_def_id, Untracked((variant_index, field_index)))); + EncodeContext::encode_field, + (adt_def_id, variant_index, field_index)); } } } fn encode_info_for_generics(&mut self, generics: &hir::Generics) { for param in &generics.params { + let def_id = self.tcx.hir().local_def_id_from_hir_id(param.hir_id); match param.kind { - hir::GenericParamKind::Lifetime { .. } => {} - hir::GenericParamKind::Type { ref default, .. } => { - let def_id = self.tcx.hir().local_def_id_from_hir_id(param.hir_id); - let has_default = Untracked(default.is_some()); - let encode_info = IsolatedEncoder::encode_info_for_ty_param; - self.record(def_id, encode_info, (def_id, has_default)); + GenericParamKind::Lifetime { .. } => continue, + GenericParamKind::Type { ref default, .. } => { + self.record( + def_id, + EncodeContext::encode_info_for_ty_param, + (def_id, default.is_some()), + ); } - hir::GenericParamKind::Const { .. } => { - let def_id = self.tcx.hir().local_def_id_from_hir_id(param.hir_id); - let encode_info = IsolatedEncoder::encode_info_for_const_param; - self.record(def_id, encode_info, def_id); + GenericParamKind::Const { .. } => { + self.record(def_id, EncodeContext::encode_info_for_const_param, def_id); } } } @@ -1720,7 +1731,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { match ty.node { hir::TyKind::Array(_, ref length) => { let def_id = self.tcx.hir().local_def_id_from_hir_id(length.hir_id); - self.record(def_id, IsolatedEncoder::encode_info_for_anon_const, def_id); + self.record(def_id, EncodeContext::encode_info_for_anon_const, def_id); } _ => {} } @@ -1730,7 +1741,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { match expr.node { hir::ExprKind::Closure(..) => { let def_id = self.tcx.hir().local_def_id_from_hir_id(expr.hir_id); - self.record(def_id, IsolatedEncoder::encode_info_for_closure, def_id); + self.record(def_id, EncodeContext::encode_info_for_closure, def_id); } _ => {} } @@ -1741,7 +1752,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { /// so it's easier to do that here then to wait until we would encounter /// normally in the visitor walk. fn encode_addl_info_for_item(&mut self, item: &hir::Item) { - let def_id = self.tcx.hir().local_def_id(item.id); + let def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); match item.node { hir::ItemKind::Static(..) | hir::ItemKind::Const(..) | @@ -1761,19 +1772,25 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { let def = self.tcx.adt_def(def_id); for (i, variant) in def.variants.iter_enumerated() { - self.record(variant.did, - IsolatedEncoder::encode_enum_variant_info, - (def_id, Untracked(i))); + self.record(variant.def_id, + EncodeContext::encode_enum_variant_info, + (def_id, i)); + + if let Some(ctor_def_id) = variant.ctor_def_id { + self.record(ctor_def_id, + EncodeContext::encode_enum_variant_ctor, + (def_id, i)); + } } } hir::ItemKind::Struct(ref struct_def, _) => { self.encode_fields(def_id); // If the struct has a constructor, encode it. - if !struct_def.is_struct() { - let ctor_def_id = self.tcx.hir().local_def_id(struct_def.id()); + if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { + let ctor_def_id = self.tcx.hir().local_def_id_from_hir_id(ctor_hir_id); self.record(ctor_def_id, - IsolatedEncoder::encode_struct_ctor, + EncodeContext::encode_struct_ctor, (def_id, ctor_def_id)); } } @@ -1783,14 +1800,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { hir::ItemKind::Impl(..) => { for &trait_item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(trait_item_def_id, - IsolatedEncoder::encode_info_for_impl_item, + EncodeContext::encode_info_for_impl_item, trait_item_def_id); } } hir::ItemKind::Trait(..) => { for &item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(item_def_id, - IsolatedEncoder::encode_info_for_trait_item, + EncodeContext::encode_info_for_trait_item, item_def_id); } } @@ -1798,15 +1815,15 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { } } -struct ImplVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct ImplVisitor<'tcx> { + tcx: TyCtxt<'tcx>, impls: FxHashMap>, } -impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> { +impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> { fn visit_item(&mut self, item: &hir::Item) { if let hir::ItemKind::Impl(..) = item.node { - let impl_id = self.tcx.hir().local_def_id(item.id); + let impl_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id) { self.impls .entry(trait_ref.def_id) @@ -1846,19 +1863,20 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> { // will allow us to slice the metadata to the precise length that we just // generated regardless of trailing bytes that end up in it. -pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> EncodedMetadata -{ +pub fn encode_metadata<'tcx>(tcx: TyCtxt<'tcx>) -> EncodedMetadata { let mut encoder = opaque::Encoder::new(vec![]); encoder.emit_raw_bytes(METADATA_HEADER); // Will be filled with the root position after encoding everything. encoder.emit_raw_bytes(&[0, 0, 0, 0]); - let (root, mut result) = { + // Since encoding metadata is not in a query, and nothing is cached, + // there's no need to do dep-graph tracking for any of it. + let (root, mut result) = tcx.dep_graph.with_ignore(move || { let mut ecx = EncodeContext { opaque: encoder, tcx, + entries_index: Index::new(tcx.hir().definitions().def_index_count()), lazy_state: LazyState::NoNode, type_shorthands: Default::default(), predicate_shorthands: Default::default(), @@ -1874,7 +1892,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) // culminating in the `CrateRoot` which points to all of it. let root = ecx.encode_crate_root(); (root, ecx.opaque.into_inner()) - }; + }); // Encode the root position. let header = METADATA_HEADER.len(); @@ -1887,7 +1905,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) EncodedMetadata { raw_data: result } } -pub fn get_repr_options<'a, 'tcx, 'gcx>(tcx: &TyCtxt<'a, 'tcx, 'gcx>, did: DefId) -> ReprOptions { +pub fn get_repr_options<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> ReprOptions { let ty = tcx.type_of(did); match ty.sty { ty::Adt(ref def, _) => return def.repr, diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/error_codes.rs similarity index 100% rename from src/librustc_metadata/diagnostics.rs rename to src/librustc_metadata/error_codes.rs diff --git a/src/librustc_metadata/foreign_modules.rs b/src/librustc_metadata/foreign_modules.rs index 2c03bd6659f27..0ce103cfa40dc 100644 --- a/src/librustc_metadata/foreign_modules.rs +++ b/src/librustc_metadata/foreign_modules.rs @@ -3,21 +3,21 @@ use rustc::hir; use rustc::middle::cstore::ForeignModule; use rustc::ty::TyCtxt; -pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec { +pub fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> Vec { let mut collector = Collector { tcx, modules: Vec::new(), }; tcx.hir().krate().visit_all_item_likes(&mut collector); - return collector.modules + return collector.modules; } -struct Collector<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct Collector<'tcx> { + tcx: TyCtxt<'tcx>, modules: Vec, } -impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> { +impl ItemLikeVisitor<'tcx> for Collector<'tcx> { fn visit_item(&mut self, it: &'tcx hir::Item) { let fm = match it.node { hir::ItemKind::ForeignMod(ref fm) => fm, @@ -25,11 +25,11 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> { }; let foreign_items = fm.items.iter() - .map(|it| self.tcx.hir().local_def_id(it.id)) + .map(|it| self.tcx.hir().local_def_id_from_hir_id(it.hir_id)) .collect(); self.modules.push(ForeignModule { foreign_items, - def_id: self.tcx.hir().local_def_id(it.id), + def_id: self.tcx.hir().local_def_id_from_hir_id(it.hir_id), }); } diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index 18f30383090cd..dd2f59922ef92 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -1,11 +1,73 @@ use crate::schema::*; -use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace}; +use rustc::hir::def_id::{DefId, DefIndex}; use rustc_serialize::opaque::Encoder; -use std::slice; +use std::marker::PhantomData; use std::u32; use log::debug; +/// Helper trait, for encoding to, and decoding from, a fixed number of bytes. +pub trait FixedSizeEncoding { + const BYTE_LEN: usize; + + // FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead, + // once that starts being allowed by the compiler (i.e. lazy normalization). + fn from_bytes(b: &[u8]) -> Self; + fn write_to_bytes(self, b: &mut [u8]); + + // FIXME(eddyb) make these generic functions, or at least defaults here. + // (same problem as above, needs `[u8; Self::BYTE_LEN]`) + // For now, a macro (`fixed_size_encoding_byte_len_and_defaults`) is used. + fn read_from_bytes_at(b: &[u8], i: usize) -> Self; + fn write_to_bytes_at(self, b: &mut [u8], i: usize); +} + +// HACK(eddyb) this shouldn't be needed (see comments on the methods above). +macro_rules! fixed_size_encoding_byte_len_and_defaults { + ($byte_len:expr) => { + const BYTE_LEN: usize = $byte_len; + fn read_from_bytes_at(b: &[u8], i: usize) -> Self { + const BYTE_LEN: usize = $byte_len; + // HACK(eddyb) ideally this would be done with fully safe code, + // but slicing `[u8]` with `i * N..` is optimized worse, due to the + // possibility of `i * N` overflowing, than indexing `[[u8; N]]`. + let b = unsafe { + std::slice::from_raw_parts( + b.as_ptr() as *const [u8; BYTE_LEN], + b.len() / BYTE_LEN, + ) + }; + Self::from_bytes(&b[i]) + } + fn write_to_bytes_at(self, b: &mut [u8], i: usize) { + const BYTE_LEN: usize = $byte_len; + // HACK(eddyb) ideally this would be done with fully safe code, + // see similar comment in `read_from_bytes_at` for why it can't yet. + let b = unsafe { + std::slice::from_raw_parts_mut( + b.as_mut_ptr() as *mut [u8; BYTE_LEN], + b.len() / BYTE_LEN, + ) + }; + self.write_to_bytes(&mut b[i]); + } + } +} + +impl FixedSizeEncoding for u32 { + fixed_size_encoding_byte_len_and_defaults!(4); + + fn from_bytes(b: &[u8]) -> Self { + let mut bytes = [0; Self::BYTE_LEN]; + bytes.copy_from_slice(&b[..Self::BYTE_LEN]); + Self::from_le_bytes(bytes) + } + + fn write_to_bytes(self, b: &mut [u8]) { + b[..Self::BYTE_LEN].copy_from_slice(&self.to_le_bytes()); + } +} + /// While we are generating the metadata, we also track the position /// of each DefIndex. It is not required that all definitions appear /// in the metadata, nor that they are serialized in order, and @@ -13,75 +75,61 @@ use log::debug; /// `u32::MAX`. Whenever an index is visited, we fill in the /// appropriate spot by calling `record_position`. We should never /// visit the same index twice. -pub struct Index { - positions: [Vec; 2] +pub struct Index<'tcx> { + positions: Vec, + _marker: PhantomData<&'tcx ()>, } -impl Index { - pub fn new((max_index_lo, max_index_hi): (usize, usize)) -> Index { +impl Index<'tcx> { + pub fn new(max_index: usize) -> Self { Index { - positions: [vec![u32::MAX; max_index_lo], - vec![u32::MAX; max_index_hi]], + positions: vec![0xff; max_index * 4], + _marker: PhantomData, } } - pub fn record(&mut self, def_id: DefId, entry: Lazy>) { + pub fn record(&mut self, def_id: DefId, entry: Lazy>) { assert!(def_id.is_local()); self.record_index(def_id.index, entry); } - pub fn record_index(&mut self, item: DefIndex, entry: Lazy>) { + pub fn record_index(&mut self, item: DefIndex, entry: Lazy>) { assert!(entry.position < (u32::MAX as usize)); let position = entry.position as u32; - let space_index = item.address_space().index(); - let array_index = item.as_array_index(); + let array_index = item.index(); - assert!(self.positions[space_index][array_index] == u32::MAX, + let positions = &mut self.positions; + assert!(u32::read_from_bytes_at(positions, array_index) == u32::MAX, "recorded position for item {:?} twice, first at {:?} and now at {:?}", item, - self.positions[space_index][array_index], + u32::read_from_bytes_at(positions, array_index), position); - self.positions[space_index][array_index] = position.to_le(); + position.write_to_bytes_at(positions, array_index) } - pub fn write_index(&self, buf: &mut Encoder) -> LazySeq { + pub fn write_index(&self, buf: &mut Encoder) -> LazySeq { let pos = buf.position(); // First we write the length of the lower range ... - buf.emit_raw_bytes(words_to_bytes(&[(self.positions[0].len() as u32).to_le()])); - // ... then the values in the lower range ... - buf.emit_raw_bytes(words_to_bytes(&self.positions[0][..])); - // ... then the values in the higher range. - buf.emit_raw_bytes(words_to_bytes(&self.positions[1][..])); - LazySeq::with_position_and_length(pos as usize, - self.positions[0].len() + self.positions[1].len() + 1) + buf.emit_raw_bytes(&(self.positions.len() as u32 / 4).to_le_bytes()); + // ... then the values. + buf.emit_raw_bytes(&self.positions); + LazySeq::with_position_and_length(pos as usize, self.positions.len() / 4 + 1) } } -impl<'tcx> LazySeq { +impl LazySeq> { /// Given the metadata, extract out the offset of a particular /// DefIndex (if any). #[inline(never)] pub fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option>> { - let words = &bytes_to_words(&bytes[self.position..])[..self.len]; - - debug!("Index::lookup: index={:?} words.len={:?}", + let bytes = &bytes[self.position..]; + debug!("Index::lookup: index={:?} len={:?}", def_index, - words.len()); - - let positions = match def_index.address_space() { - DefIndexAddressSpace::Low => &words[1..], - DefIndexAddressSpace::High => { - // This is a DefIndex in the higher range, so find out where - // that starts: - let lo_count = u32::from_le(words[0].get()) as usize; - &words[lo_count + 1 .. ] - } - }; - - let array_index = def_index.as_array_index(); - let position = u32::from_le(positions[array_index].get()); + self.len); + + let position = u32::read_from_bytes_at(bytes, 1 + def_index.index()); if position == u32::MAX { debug!("Index::lookup: position=u32::MAX"); None @@ -91,27 +139,3 @@ impl<'tcx> LazySeq { } } } - -#[repr(packed)] -#[derive(Copy)] -struct Unaligned(T); - -// The derived Clone impl is unsafe for this packed struct since it needs to pass a reference to -// the field to `T::clone`, but this reference may not be properly aligned. -impl Clone for Unaligned { - fn clone(&self) -> Self { - *self - } -} - -impl Unaligned { - fn get(self) -> T { self.0 } -} - -fn bytes_to_words(b: &[u8]) -> &[Unaligned] { - unsafe { slice::from_raw_parts(b.as_ptr() as *const Unaligned, b.len() / 4) } -} - -fn words_to_bytes(w: &[u32]) -> &[u8] { - unsafe { slice::from_raw_parts(w.as_ptr() as *const u8, w.len() * 4) } -} diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs deleted file mode 100644 index 3e2571fc0b39c..0000000000000 --- a/src/librustc_metadata/index_builder.rs +++ /dev/null @@ -1,224 +0,0 @@ -//! Builder types for generating the "item data" section of the -//! metadata. This section winds up looking like this: -//! -//! ``` -//! // big list of item-like things... -//! // ...for most `DefId`s, there is an entry. -//! -//! -//! ``` -//! -//! As we generate this listing, we collect the offset of each -//! `data_item` entry and store it in an index. Then, when we load the -//! metadata, we can skip right to the metadata for a particular item. -//! -//! In addition to the offset, we need to track the data that was used -//! to generate the contents of each `data_item`. This is so that we -//! can figure out which HIR nodes contributed to that data for -//! incremental compilation purposes. -//! -//! The `IndexBuilder` facilitates both of these. It is created -//! with an `EncodingContext` (`ecx`), which it encapsulates. -//! It has one main method, `record()`. You invoke `record` -//! like so to create a new `data_item` element in the list: -//! -//! ``` -//! index.record(some_def_id, callback_fn, data) -//! ``` -//! -//! What record will do is to (a) record the current offset, (b) emit -//! the `common::data_item` tag, and then call `callback_fn` with the -//! given data as well as the `EncodingContext`. Once `callback_fn` -//! returns, the `common::data_item` tag will be closed. -//! -//! `EncodingContext` does not offer the `record` method, so that we -//! can ensure that `common::data_item` elements are never nested. -//! -//! In addition, while the `callback_fn` is executing, we will push a -//! task `MetaData(some_def_id)`, which can then observe the -//! reads/writes that occur in the task. For this reason, the `data` -//! argument that is given to the `callback_fn` must implement the -//! trait `DepGraphRead`, which indicates how to register reads on the -//! data in this new task (note that many types of data, such as -//! `DefId`, do not currently require any reads to be registered, -//! since they are not derived from a HIR node). This is also why we -//! give a callback fn, rather than taking a closure: it allows us to -//! easily control precisely what data is given to that fn. - -use crate::encoder::EncodeContext; -use crate::index::Index; -use crate::schema::*; -use crate::isolated_encoder::IsolatedEncoder; - -use rustc::hir; -use rustc::hir::def_id::DefId; -use rustc::ty::TyCtxt; -use syntax::ast; - -use std::ops::{Deref, DerefMut}; - -/// Builder that can encode new items, adding them into the index. -/// Item encoding cannot be nested. -pub struct IndexBuilder<'a, 'b: 'a, 'tcx: 'b> { - items: Index, - pub ecx: &'a mut EncodeContext<'b, 'tcx>, -} - -impl<'a, 'b, 'tcx> Deref for IndexBuilder<'a, 'b, 'tcx> { - type Target = EncodeContext<'b, 'tcx>; - fn deref(&self) -> &Self::Target { - self.ecx - } -} - -impl<'a, 'b, 'tcx> DerefMut for IndexBuilder<'a, 'b, 'tcx> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.ecx - } -} - -impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { - pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self { - IndexBuilder { - items: Index::new(ecx.tcx.hir().definitions().def_index_counts_lo_hi()), - ecx, - } - } - - /// Emit the data for a `DefId` to the metadata. The function to - /// emit the data is `op`, and it will be given `data` as - /// arguments. This `record` function will call `op` to generate - /// the `Entry` (which may point to other encoded information) - /// and will then record the `Lazy` for use in the index. - /// - /// In addition, it will setup a dep-graph task to track what data - /// `op` accesses to generate the metadata, which is later used by - /// incremental compilation to compute a hash for the metadata and - /// track changes. - /// - /// The reason that `op` is a function pointer, and not a closure, - /// is that we want to be able to completely track all data it has - /// access to, so that we can be sure that `DATA: DepGraphRead` - /// holds, and that it is therefore not gaining "secret" access to - /// bits of HIR or other state that would not be trackd by the - /// content system. - pub fn record<'x, DATA>(&'x mut self, - id: DefId, - op: fn(&mut IsolatedEncoder<'x, 'b, 'tcx>, DATA) -> Entry<'tcx>, - data: DATA) - where DATA: DepGraphRead - { - assert!(id.is_local()); - - // We don't track this since we are explicitly computing the incr. comp. - // hashes anyway. In theory we could do some tracking here and use it to - // avoid rehashing things (and instead cache the hashes) but it's - // unclear whether that would be a win since hashing is cheap enough. - self.ecx.tcx.dep_graph.with_ignore(move || { - let mut entry_builder = IsolatedEncoder::new(self.ecx); - let entry = op(&mut entry_builder, data); - let entry = entry_builder.lazy(&entry); - - self.items.record(id, entry); - }) - } - - pub fn into_items(self) -> Index { - self.items - } -} - -/// Trait used for data that can be passed from outside a dep-graph -/// task. The data must either be of some safe type, such as a -/// `DefId` index, or implement the `read` method so that it can add -/// a read of whatever dep-graph nodes are appropriate. -pub trait DepGraphRead { - fn read(&self, tcx: TyCtxt<'_, '_, '_>); -} - -impl DepGraphRead for DefId { - fn read(&self, _tcx: TyCtxt<'_, '_, '_>) {} -} - -impl DepGraphRead for ast::NodeId { - fn read(&self, _tcx: TyCtxt<'_, '_, '_>) {} -} - -impl DepGraphRead for Option - where T: DepGraphRead -{ - fn read(&self, tcx: TyCtxt<'_, '_, '_>) { - match *self { - Some(ref v) => v.read(tcx), - None => (), - } - } -} - -impl DepGraphRead for [T] - where T: DepGraphRead -{ - fn read(&self, tcx: TyCtxt<'_, '_, '_>) { - for i in self { - i.read(tcx); - } - } -} - -macro_rules! read_tuple { - ($($name:ident),*) => { - impl<$($name),*> DepGraphRead for ($($name),*) - where $($name: DepGraphRead),* - { - #[allow(non_snake_case)] - fn read(&self, tcx: TyCtxt<'_, '_, '_>) { - let &($(ref $name),*) = self; - $($name.read(tcx);)* - } - } - } -} -read_tuple!(A, B); -read_tuple!(A, B, C); - -macro_rules! read_hir { - ($t:ty) => { - impl<'tcx> DepGraphRead for &'tcx $t { - fn read(&self, tcx: TyCtxt<'_, '_, '_>) { - tcx.hir().read_by_hir_id(self.hir_id); - } - } - } -} -read_hir!(hir::Item); -read_hir!(hir::ImplItem); -read_hir!(hir::TraitItem); -read_hir!(hir::ForeignItem); -read_hir!(hir::MacroDef); - -/// Leaks access to a value of type T without any tracking. This is -/// suitable for ambiguous types like `usize`, which *could* represent -/// tracked data (e.g., if you read it out of a HIR node) or might not -/// (e.g., if it's an index). Adding in an `Untracked` is an -/// assertion, essentially, that the data does not need to be tracked -/// (or that read edges will be added by some other way). -/// -/// A good idea is to add to each use of `Untracked` an explanation of -/// why this value is ok. -pub struct Untracked(pub T); - -impl DepGraphRead for Untracked { - fn read(&self, _tcx: TyCtxt<'_, '_, '_>) {} -} - -/// Newtype that can be used to package up misc data extracted from a -/// HIR node that doesn't carry its own ID. This will allow an -/// arbitrary `T` to be passed in, but register a read on the given -/// `NodeId`. -pub struct FromId(pub ast::NodeId, pub T); - -impl DepGraphRead for FromId { - fn read(&self, tcx: TyCtxt<'_, '_, '_>) { - tcx.hir().read(self.0); - } -} diff --git a/src/librustc_metadata/isolated_encoder.rs b/src/librustc_metadata/isolated_encoder.rs deleted file mode 100644 index e879a73e650bb..0000000000000 --- a/src/librustc_metadata/isolated_encoder.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::encoder::EncodeContext; -use crate::schema::{Lazy, LazySeq}; -use rustc::ty::TyCtxt; -use rustc_serialize::Encodable; - -/// The IsolatedEncoder provides facilities to write to crate metadata while -/// making sure that anything going through it is also feed into an ICH hasher. -pub struct IsolatedEncoder<'a, 'b: 'a, 'tcx: 'b> { - pub tcx: TyCtxt<'b, 'tcx, 'tcx>, - ecx: &'a mut EncodeContext<'b, 'tcx>, -} - -impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { - - pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self { - let tcx = ecx.tcx; - IsolatedEncoder { - tcx, - ecx, - } - } - - pub fn lazy(&mut self, value: &T) -> Lazy - where T: Encodable - { - self.ecx.lazy(value) - } - - pub fn lazy_seq(&mut self, iter: I) -> LazySeq - where I: IntoIterator, - T: Encodable - { - self.ecx.lazy_seq(iter) - } - - pub fn lazy_seq_ref<'x, I, T>(&mut self, iter: I) -> LazySeq - where I: IntoIterator, - T: 'x + Encodable - { - self.ecx.lazy_seq_ref(iter) - } - - pub fn lazy_seq_from_slice(&mut self, slice: &[T]) -> LazySeq - where T: Encodable - { - self.ecx.lazy_seq_ref(slice.iter()) - } -} diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index b4f68399d9feb..e49ca8acf6702 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -1,6 +1,8 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(box_patterns)] +#![feature(drain_filter)] +#![feature(in_band_lifetimes)] #![feature(libc)] #![feature(nll)] #![feature(proc_macro_internals)] @@ -13,6 +15,8 @@ #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] extern crate libc; #[allow(unused_extern_crates)] @@ -24,14 +28,12 @@ extern crate rustc; #[macro_use] extern crate rustc_data_structures; -mod diagnostics; +mod error_codes; -mod index_builder; mod index; mod encoder; mod decoder; mod cstore_impl; -mod isolated_encoder; mod schema; mod native_libs; mod link_args; diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs index 6741b5235db36..cd6270046faab 100644 --- a/src/librustc_metadata/link_args.rs +++ b/src/librustc_metadata/link_args.rs @@ -2,22 +2,23 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; use rustc::ty::TyCtxt; use rustc_target::spec::abi::Abi; +use syntax::symbol::sym; -pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec { +pub fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> Vec { let mut collector = Collector { args: Vec::new(), }; tcx.hir().krate().visit_all_item_likes(&mut collector); for attr in tcx.hir().krate().attrs.iter() { - if attr.path == "link_args" { + if attr.path == sym::link_args { if let Some(linkarg) = attr.value_str() { collector.add_link_args(&linkarg.as_str()); } } } - return collector.args + return collector.args; } struct Collector { @@ -37,7 +38,7 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector { } // First, add all of the custom #[link_args] attributes - for m in it.attrs.iter().filter(|a| a.check_name("link_args")) { + for m in it.attrs.iter().filter(|a| a.check_name(sym::link_args)) { if let Some(linkarg) = m.value_str() { self.add_link_args(&linkarg.as_str()); } diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 6a1aada5ac706..3832c8ee227de 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -225,7 +225,7 @@ use rustc::session::search_paths::PathKind; use rustc::util::nodemap::FxHashMap; use errors::DiagnosticBuilder; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax::struct_span_err; use syntax_pos::Span; use rustc_target::spec::{Target, TargetTriple}; @@ -244,11 +244,13 @@ use rustc_data_structures::owning_ref::OwningRef; use log::{debug, info, warn}; +#[derive(Clone)] pub struct CrateMismatch { path: PathBuf, got: String, } +#[derive(Clone)] pub struct Context<'a> { pub sess: &'a Session, pub span: Span, @@ -258,7 +260,7 @@ pub struct Context<'a> { pub extra_filename: Option<&'a str>, // points to either self.sess.target.target or self.sess.host, must match triple pub target: &'a Target, - pub triple: &'a TargetTriple, + pub triple: TargetTriple, pub filesearch: FileSearch<'a>, pub root: &'a Option, pub rejected_via_hash: Vec, @@ -302,6 +304,14 @@ impl CratePaths { } impl<'a> Context<'a> { + pub fn reset(&mut self) { + self.rejected_via_hash.clear(); + self.rejected_via_triple.clear(); + self.rejected_via_kind.clear(); + self.rejected_via_version.clear(); + self.rejected_via_filename.clear(); + } + pub fn maybe_load_library_crate(&mut self) -> Option { let mut seen_paths = FxHashSet::default(); match self.extra_filename { @@ -311,7 +321,7 @@ impl<'a> Context<'a> { } } - pub fn report_errs(&mut self) -> ! { + pub fn report_errs(self) -> ! { let add = match self.root { &None => String::new(), &Some(ref r) => format!(" which `{}` depends on", r.ident), @@ -398,8 +408,8 @@ impl<'a> Context<'a> { self.ident, add); - if (self.ident == "std" || self.ident == "core") - && self.triple != &TargetTriple::from_triple(config::host_triple()) { + if (self.ident == sym::std || self.ident == sym::core) + && self.triple != TargetTriple::from_triple(config::host_triple()) { err.note(&format!("the `{}` target may not be installed", self.triple)); } err.span_label(self.span, "can't find crate"); @@ -432,11 +442,11 @@ impl<'a> Context<'a> { // must be loaded via -L plus some filtering. if self.hash.is_none() { self.should_match_name = false; - if let Some(s) = self.sess.opts.externs.get(&self.crate_name.as_str()) { + if let Some(entry) = self.sess.opts.externs.get(&self.crate_name.as_str()) { // Only use `--extern crate_name=path` here, not `--extern crate_name`. - if s.iter().any(|l| l.is_some()) { + if entry.locations.iter().any(|l| l.is_some()) { return self.find_commandline_library( - s.iter().filter_map(|l| l.as_ref()), + entry.locations.iter().filter_map(|l| l.as_ref()), ); } } @@ -718,7 +728,7 @@ impl<'a> Context<'a> { } } - if &root.triple != self.triple { + if root.triple != self.triple { info!("Rejecting via crate triple: expected {} got {}", self.triple, root.triple); @@ -891,8 +901,7 @@ fn get_metadata_section_imp(target: &Target, let mut inflated = Vec::new(); match DeflateDecoder::new(compressed_bytes).read_to_end(&mut inflated) { Ok(_) => { - let buf = unsafe { OwningRef::new_assert_stable_address(inflated) }; - rustc_erase_owner!(buf.map_owner_box()) + rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()) } Err(_) => { return Err(format!("failed to decompress metadata: {}", filename.display())); diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index 118fb203c69a1..7b335b3b4832d 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -8,17 +8,17 @@ use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::source_map::Span; use syntax::feature_gate::{self, GateIssue}; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax::{span_err, struct_span_err}; -pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec { +pub fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> Vec { let mut collector = Collector { tcx, libs: Vec::new(), }; tcx.hir().krate().visit_all_item_likes(&mut collector); collector.process_command_line(); - return collector.libs + return collector.libs; } pub fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { @@ -28,12 +28,12 @@ pub fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { } } -struct Collector<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct Collector<'tcx> { + tcx: TyCtxt<'tcx>, libs: Vec, } -impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> { +impl ItemLikeVisitor<'tcx> for Collector<'tcx> { fn visit_item(&mut self, it: &'tcx hir::Item) { let fm = match it.node { hir::ItemKind::ForeignMod(ref fm) => fm, @@ -47,7 +47,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> { } // Process all of the #[link(..)]-style arguments - for m in it.attrs.iter().filter(|a| a.check_name("link")) { + for m in it.attrs.iter().filter(|a| a.check_name(sym::link)) { let items = match m.meta_item_list() { Some(item) => item, None => continue, @@ -56,13 +56,13 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> { name: None, kind: cstore::NativeUnknown, cfg: None, - foreign_module: Some(self.tcx.hir().local_def_id(it.id)), + foreign_module: Some(self.tcx.hir().local_def_id_from_hir_id(it.hir_id)), wasm_import_module: None, }; let mut kind_specified = false; for item in items.iter() { - if item.check_name("kind") { + if item.check_name(sym::kind) { kind_specified = true; let kind = match item.value_str() { Some(name) => name, @@ -74,15 +74,16 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> { "dylib" => cstore::NativeUnknown, "framework" => cstore::NativeFramework, k => { - struct_span_err!(self.tcx.sess, m.span, E0458, + struct_span_err!(self.tcx.sess, item.span(), E0458, "unknown kind: `{}`", k) - .span_label(item.span, "unknown kind").emit(); + .span_label(item.span(), "unknown kind") + .span_label(m.span, "").emit(); cstore::NativeUnknown } }; - } else if item.check_name("name") { + } else if item.check_name(sym::name) { lib.name = item.value_str(); - } else if item.check_name("cfg") { + } else if item.check_name(sym::cfg) { let cfg = match item.meta_item_list() { Some(list) => list, None => continue, // skip like historical compilers @@ -97,7 +98,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> { } else { self.tcx.sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`"); } - } else if item.check_name("wasm_import_module") { + } else if item.check_name(sym::wasm_import_module) { match item.value_str() { Some(s) => lib.wasm_import_module = Some(s), None => { @@ -129,7 +130,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> { fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem) {} } -impl<'a, 'tcx> Collector<'a, 'tcx> { +impl Collector<'tcx> { fn register_native_lib(&mut self, span: Option, lib: NativeLibrary) { if lib.name.as_ref().map(|s| s.as_str().is_empty()).unwrap_or(false) { match span { @@ -155,7 +156,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { } if lib.cfg.is_some() && !self.tcx.features().link_cfg { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, - "link_cfg", + sym::link_cfg, span.unwrap(), GateIssue::Language, "is feature gated"); @@ -163,7 +164,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { if lib.kind == cstore::NativeStaticNobundle && !self.tcx.features().static_nobundle { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, - "static_nobundle", + sym::static_nobundle, span.unwrap_or_else(|| syntax_pos::DUMMY_SP), GateIssue::Language, "kind=\"static-nobundle\" is feature gated"); @@ -180,7 +181,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { let any_duplicate = self.libs .iter() .filter_map(|lib| lib.name.as_ref()) - .any(|n| n == name); + .any(|n| n.as_str() == *name); if new_name.is_empty() { self.tcx.sess.err( &format!("an empty renaming target was specified for library `{}`",name)); @@ -199,34 +200,31 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { } // Update kind and, optionally, the name of all native libraries - // (there may be more than one) with the specified name. + // (there may be more than one) with the specified name. If any + // library is mentioned more than once, keep the latest mention + // of it, so that any possible dependent libraries appear before + // it. (This ensures that the linker is able to see symbols from + // all possible dependent libraries before linking in the library + // in question.) for &(ref name, ref new_name, kind) in &self.tcx.sess.opts.libs { - let mut found = false; - for lib in self.libs.iter_mut() { - let lib_name = match lib.name { - Some(n) => n, - None => continue, - }; - if lib_name == name as &str { - let mut changed = false; - if let Some(k) = kind { - lib.kind = k; - changed = true; - } - if let &Some(ref new_name) = new_name { - lib.name = Some(Symbol::intern(new_name)); - changed = true; - } - if !changed { - let msg = format!("redundant linker flag specified for \ - library `{}`", name); - self.tcx.sess.warn(&msg); + // If we've already added any native libraries with the same + // name, they will be pulled out into `existing`, so that we + // can move them to the end of the list below. + let mut existing = self.libs.drain_filter(|lib| { + if let Some(lib_name) = lib.name { + if lib_name.as_str() == *name { + if let Some(k) = kind { + lib.kind = k; + } + if let &Some(ref new_name) = new_name { + lib.name = Some(Symbol::intern(new_name)); + } + return true; } - - found = true; } - } - if !found { + false + }).collect::>(); + if existing.is_empty() { // Add if not found let new_name = new_name.as_ref().map(|s| &**s); // &Option -> Option<&str> let lib = NativeLibrary { @@ -237,6 +235,10 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { wasm_import_module: None, }; self.register_native_lib(None, lib); + } else { + // Move all existing libraries with the same name to the + // end of the command line. + self.libs.append(&mut existing); } } } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index af79ea37dff55..8d1de4fd6c392 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -2,12 +2,13 @@ use crate::index; use rustc::hir; use rustc::hir::def::{self, CtorKind}; -use rustc::hir::def_id::{DefIndex, DefId, CrateNum}; -use rustc::ich::StableHashingContext; +use rustc::hir::def_id::{DefIndex, DefId}; +use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary, ForeignModule}; use rustc::middle::lang_items; use rustc::mir; use rustc::session::CrateDisambiguator; +use rustc::session::config::SymbolManglingVersion; use rustc::ty::{self, Ty, ReprOptions}; use rustc_target::spec::{PanicStrategy, TargetTriple}; use rustc_data_structures::svh::Svh; @@ -19,10 +20,6 @@ use syntax::symbol::Symbol; use syntax_pos::{self, Span}; use std::marker::PhantomData; -use std::mem; - -use rustc_data_structures::stable_hasher::{StableHasher, HashStable, - StableHasherResult}; pub fn rustc_version() -> String { format!("rustc {}", @@ -91,15 +88,6 @@ impl Clone for Lazy { impl serialize::UseSpecializedEncodable for Lazy {} impl serialize::UseSpecializedDecodable for Lazy {} -impl HashStable for Lazy { - fn hash_stable(&self, - _: &mut CTX, - _: &mut StableHasher) { - // There's nothing to do. Whatever got encoded within this Lazy<> - // wrapper has already been hashed. - } -} - /// A sequence of type T referred to by its absolute position /// in the metadata and length, and which can be decoded lazily. /// The sequence is a single node for the purposes of `Lazy`. @@ -148,15 +136,6 @@ impl Clone for LazySeq { impl serialize::UseSpecializedEncodable for LazySeq {} impl serialize::UseSpecializedDecodable for LazySeq {} -impl HashStable for LazySeq { - fn hash_stable(&self, - _: &mut CTX, - _: &mut StableHasher) { - // There's nothing to do. Whatever got encoded within this Lazy<> - // wrapper has already been hashed. - } -} - /// Encoding / decoding state for `Lazy` and `LazySeq`. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum LazyState { @@ -174,7 +153,7 @@ pub enum LazyState { } #[derive(RustcEncodable, RustcDecodable)] -pub struct CrateRoot { +pub struct CrateRoot<'tcx> { pub name: Symbol, pub triple: TargetTriple, pub extra_filename: String, @@ -187,6 +166,7 @@ pub struct CrateRoot { pub has_default_lib_allocator: bool, pub plugin_registrar_fn: Option, pub proc_macro_decls_static: Option, + pub proc_macro_stability: Option, pub crate_deps: LazySeq, pub dylib_dependency_formats: LazySeq>, @@ -198,10 +178,10 @@ pub struct CrateRoot { pub source_map: LazySeq, pub def_path_table: Lazy, pub impls: LazySeq, - pub exported_symbols: EncodedExportedSymbols, + pub exported_symbols: LazySeq<(ExportedSymbol<'tcx>, SymbolExportLevel)>, pub interpret_alloc_index: LazySeq, - pub index: LazySeq, + pub entries_index: LazySeq>, pub compiler_builtins: bool, pub needs_allocator: bool, @@ -210,6 +190,7 @@ pub struct CrateRoot { pub panic_runtime: bool, pub profiler_runtime: bool, pub sanitizer_runtime: bool, + pub symbol_mangling_version: SymbolManglingVersion, } #[derive(RustcEncodable, RustcDecodable)] @@ -220,36 +201,12 @@ pub struct CrateDep { pub extra_filename: String, } -impl_stable_hash_for!(struct CrateDep { - name, - hash, - kind, - extra_filename -}); - #[derive(RustcEncodable, RustcDecodable)] pub struct TraitImpls { pub trait_id: (u32, DefIndex), pub impls: LazySeq, } -impl<'a, 'gcx> HashStable> for TraitImpls { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let TraitImpls { - trait_id: (krate, def_index), - ref impls, - } = *self; - - DefId { - krate: CrateNum::from_u32(krate), - index: def_index - }.hash_stable(hcx, hasher); - impls.hash_stable(hcx, hasher); - } -} - #[derive(RustcEncodable, RustcDecodable)] pub struct Entry<'tcx> { pub kind: EntryKind<'tcx>, @@ -267,26 +224,9 @@ pub struct Entry<'tcx> { pub predicates: Option>>, pub predicates_defined_on: Option>>, - pub mir: Option>>, + pub mir: Option>>, } -impl_stable_hash_for!(struct Entry<'tcx> { - kind, - visibility, - span, - attributes, - children, - stability, - deprecation, - ty, - inherent_impls, - variances, - generics, - predicates, - predicates_defined_on, - mir -}); - #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub enum EntryKind<'tcx> { Const(ConstQualif, Lazy), @@ -298,6 +238,8 @@ pub enum EntryKind<'tcx> { ForeignType, GlobalAsm, Type, + TypeParam, + ConstParam, Existential, Enum(ReprOptions), Field, @@ -313,124 +255,35 @@ pub enum EntryKind<'tcx> { Trait(Lazy>), Impl(Lazy>), Method(Lazy>), - AssociatedType(AssociatedContainer), - AssociatedExistential(AssociatedContainer), - AssociatedConst(AssociatedContainer, ConstQualif, Lazy), + AssocType(AssocContainer), + AssocExistential(AssocContainer), + AssocConst(AssocContainer, ConstQualif, Lazy), TraitAlias(Lazy>), } -impl<'a, 'gcx> HashStable> for EntryKind<'gcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - EntryKind::ImmStatic | - EntryKind::MutStatic | - EntryKind::ForeignImmStatic | - EntryKind::ForeignMutStatic | - EntryKind::ForeignMod | - EntryKind::GlobalAsm | - EntryKind::ForeignType | - EntryKind::Field | - EntryKind::Existential | - EntryKind::Type => { - // Nothing else to hash here. - } - EntryKind::Const(qualif, ref const_data) => { - qualif.hash_stable(hcx, hasher); - const_data.hash_stable(hcx, hasher); - } - EntryKind::Enum(ref repr_options) => { - repr_options.hash_stable(hcx, hasher); - } - EntryKind::Variant(ref variant_data) => { - variant_data.hash_stable(hcx, hasher); - } - EntryKind::Struct(ref variant_data, ref repr_options) | - EntryKind::Union(ref variant_data, ref repr_options) => { - variant_data.hash_stable(hcx, hasher); - repr_options.hash_stable(hcx, hasher); - } - EntryKind::Fn(ref fn_data) | - EntryKind::ForeignFn(ref fn_data) => { - fn_data.hash_stable(hcx, hasher); - } - EntryKind::Mod(ref mod_data) => { - mod_data.hash_stable(hcx, hasher); - } - EntryKind::MacroDef(ref macro_def) => { - macro_def.hash_stable(hcx, hasher); - } - EntryKind::Generator(data) => { - data.hash_stable(hcx, hasher); - } - EntryKind::Closure(closure_data) => { - closure_data.hash_stable(hcx, hasher); - } - EntryKind::Trait(ref trait_data) => { - trait_data.hash_stable(hcx, hasher); - } - EntryKind::TraitAlias(ref trait_alias_data) => { - trait_alias_data.hash_stable(hcx, hasher); - } - EntryKind::Impl(ref impl_data) => { - impl_data.hash_stable(hcx, hasher); - } - EntryKind::Method(ref method_data) => { - method_data.hash_stable(hcx, hasher); - } - EntryKind::AssociatedExistential(associated_container) | - EntryKind::AssociatedType(associated_container) => { - associated_container.hash_stable(hcx, hasher); - } - EntryKind::AssociatedConst(associated_container, qualif, ref const_data) => { - associated_container.hash_stable(hcx, hasher); - qualif.hash_stable(hcx, hasher); - const_data.hash_stable(hcx, hasher); - } - } - } -} - -/// Additional data for EntryKind::Const and EntryKind::AssociatedConst +/// Additional data for EntryKind::Const and EntryKind::AssocConst #[derive(Clone, Copy, RustcEncodable, RustcDecodable)] pub struct ConstQualif { pub mir: u8, pub ast_promotable: bool, } -impl_stable_hash_for!(struct ConstQualif { mir, ast_promotable }); - /// Contains a constant which has been rendered to a String. /// Used by rustdoc. #[derive(RustcEncodable, RustcDecodable)] pub struct RenderedConst(pub String); -impl<'a> HashStable> for RenderedConst { - #[inline] - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - self.0.hash_stable(hcx, hasher); - } -} - #[derive(RustcEncodable, RustcDecodable)] pub struct ModData { - pub reexports: LazySeq, + pub reexports: LazySeq>, } -impl_stable_hash_for!(struct ModData { reexports }); - #[derive(RustcEncodable, RustcDecodable)] pub struct MacroDef { pub body: String, pub legacy: bool, } -impl_stable_hash_for!(struct MacroDef { body, legacy }); - #[derive(RustcEncodable, RustcDecodable)] pub struct FnData<'tcx> { pub constness: hir::Constness, @@ -438,29 +291,17 @@ pub struct FnData<'tcx> { pub sig: Lazy>, } -impl_stable_hash_for!(struct FnData<'tcx> { constness, arg_names, sig }); - #[derive(RustcEncodable, RustcDecodable)] pub struct VariantData<'tcx> { pub ctor_kind: CtorKind, pub discr: ty::VariantDiscr, - - /// If this is a struct's only variant, this - /// is the index of the "struct ctor" item. - pub struct_ctor: Option, - + /// If this is unit or tuple-variant/struct, then this is the index of the ctor id. + pub ctor: Option, /// If this is a tuple struct or variant /// ctor, this is its "function" signature. pub ctor_sig: Option>>, } -impl_stable_hash_for!(struct VariantData<'tcx> { - ctor_kind, - discr, - struct_ctor, - ctor_sig -}); - #[derive(RustcEncodable, RustcDecodable)] pub struct TraitData<'tcx> { pub unsafety: hir::Unsafety, @@ -470,23 +311,11 @@ pub struct TraitData<'tcx> { pub super_predicates: Lazy>, } -impl_stable_hash_for!(struct TraitData<'tcx> { - unsafety, - paren_sugar, - has_auto_impl, - is_marker, - super_predicates -}); - #[derive(RustcEncodable, RustcDecodable)] pub struct TraitAliasData<'tcx> { pub super_predicates: Lazy>, } -impl_stable_hash_for!(struct TraitAliasData<'tcx> { - super_predicates -}); - #[derive(RustcEncodable, RustcDecodable)] pub struct ImplData<'tcx> { pub polarity: hir::ImplPolarity, @@ -498,56 +327,41 @@ pub struct ImplData<'tcx> { pub trait_ref: Option>>, } -impl_stable_hash_for!(struct ImplData<'tcx> { - polarity, - defaultness, - parent_impl, - coerce_unsized_info, - trait_ref -}); - /// Describes whether the container of an associated item /// is a trait or an impl and whether, in a trait, it has /// a default, or an in impl, whether it's marked "default". #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] -pub enum AssociatedContainer { +pub enum AssocContainer { TraitRequired, TraitWithDefault, ImplDefault, ImplFinal, } -impl_stable_hash_for!(enum crate::schema::AssociatedContainer { - TraitRequired, - TraitWithDefault, - ImplDefault, - ImplFinal -}); - -impl AssociatedContainer { - pub fn with_def_id(&self, def_id: DefId) -> ty::AssociatedItemContainer { +impl AssocContainer { + pub fn with_def_id(&self, def_id: DefId) -> ty::AssocItemContainer { match *self { - AssociatedContainer::TraitRequired | - AssociatedContainer::TraitWithDefault => ty::TraitContainer(def_id), + AssocContainer::TraitRequired | + AssocContainer::TraitWithDefault => ty::TraitContainer(def_id), - AssociatedContainer::ImplDefault | - AssociatedContainer::ImplFinal => ty::ImplContainer(def_id), + AssocContainer::ImplDefault | + AssocContainer::ImplFinal => ty::ImplContainer(def_id), } } pub fn defaultness(&self) -> hir::Defaultness { match *self { - AssociatedContainer::TraitRequired => hir::Defaultness::Default { + AssocContainer::TraitRequired => hir::Defaultness::Default { has_value: false, }, - AssociatedContainer::TraitWithDefault | - AssociatedContainer::ImplDefault => hir::Defaultness::Default { + AssocContainer::TraitWithDefault | + AssocContainer::ImplDefault => hir::Defaultness::Default { has_value: true, }, - AssociatedContainer::ImplFinal => hir::Defaultness::Final, + AssocContainer::ImplFinal => hir::Defaultness::Final, } } } @@ -555,29 +369,20 @@ impl AssociatedContainer { #[derive(RustcEncodable, RustcDecodable)] pub struct MethodData<'tcx> { pub fn_data: FnData<'tcx>, - pub container: AssociatedContainer, + pub container: AssocContainer, pub has_self: bool, } -impl_stable_hash_for!(struct MethodData<'tcx> { fn_data, container, has_self }); #[derive(RustcEncodable, RustcDecodable)] pub struct ClosureData<'tcx> { pub sig: Lazy>, } -impl_stable_hash_for!(struct ClosureData<'tcx> { sig }); #[derive(RustcEncodable, RustcDecodable)] pub struct GeneratorData<'tcx> { pub layout: mir::GeneratorLayout<'tcx>, } -impl_stable_hash_for!(struct GeneratorData<'tcx> { layout }); // Tags used for encoding Spans: pub const TAG_VALID_SPAN: u8 = 0; pub const TAG_INVALID_SPAN: u8 = 1; - -#[derive(RustcEncodable, RustcDecodable)] -pub struct EncodedExportedSymbols { - pub position: usize, - pub len: usize, -} diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index c32bafa99205f..5de5f5e757119 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -15,7 +15,7 @@ either = "1.5.0" dot = { path = "../libgraphviz", package = "graphviz" } log = "0.4" log_settings = "0.1.1" -polonius-engine = "0.6.2" +polonius-engine = "0.7.0" rustc = { path = "../librustc" } rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index cbef7a7f6c481..40d8173ce400a 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -1,10 +1,11 @@ use crate::borrow_check::place_ext::PlaceExt; use crate::borrow_check::nll::ToRegionVid; +use crate::borrow_check::path_utils::allow_two_phase_borrow; use crate::dataflow::indexes::BorrowIndex; use crate::dataflow::move_paths::MoveData; use rustc::mir::traversal; use rustc::mir::visit::{PlaceContext, Visitor, NonUseContext, MutatingUseContext}; -use rustc::mir::{self, Location, Mir, Local}; +use rustc::mir::{self, Location, Body, Local}; use rustc::ty::{RegionVid, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::IndexVec; @@ -52,7 +53,7 @@ crate enum TwoPhaseActivation { ActivatedAt(Location), } -#[derive(Debug)] +#[derive(Debug, Clone)] crate struct BorrowData<'tcx> { /// Location where the borrow reservation starts. /// In many cases, this will be equal to the activation location but not always. @@ -89,13 +90,13 @@ crate enum LocalsStateAtExit { impl LocalsStateAtExit { fn build( locals_are_invalidated_at_exit: bool, - mir: &Mir<'tcx>, + body: &Body<'tcx>, move_data: &MoveData<'tcx> ) -> Self { struct HasStorageDead(BitSet); impl<'tcx> Visitor<'tcx> for HasStorageDead { - fn visit_local(&mut self, local: &Local, ctx: PlaceContext<'tcx>, _: Location) { + fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) { if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) { self.0.insert(*local); } @@ -105,8 +106,8 @@ impl LocalsStateAtExit { if locals_are_invalidated_at_exit { LocalsStateAtExit::AllAreInvalidated } else { - let mut has_storage_dead = HasStorageDead(BitSet::new_empty(mir.local_decls.len())); - has_storage_dead.visit_mir(mir); + let mut has_storage_dead = HasStorageDead(BitSet::new_empty(body.local_decls.len())); + has_storage_dead.visit_body(body); let mut has_storage_dead_or_moved = has_storage_dead.0; for move_out in &move_data.moves { if let Some(index) = move_data.base_local(move_out.path) { @@ -121,25 +122,24 @@ impl LocalsStateAtExit { impl<'tcx> BorrowSet<'tcx> { pub fn build( - tcx: TyCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, locals_are_invalidated_at_exit: bool, - move_data: &MoveData<'tcx> + move_data: &MoveData<'tcx>, ) -> Self { - let mut visitor = GatherBorrows { tcx, - mir, + body, idx_vec: IndexVec::new(), location_map: Default::default(), activation_map: Default::default(), local_map: Default::default(), pending_activations: Default::default(), locals_state_at_exit: - LocalsStateAtExit::build(locals_are_invalidated_at_exit, mir, move_data), + LocalsStateAtExit::build(locals_are_invalidated_at_exit, body, move_data), }; - for (block, block_data) in traversal::preorder(mir) { + for (block, block_data) in traversal::preorder(body) { visitor.visit_basic_block_data(block, block_data); } @@ -160,9 +160,9 @@ impl<'tcx> BorrowSet<'tcx> { } } -struct GatherBorrows<'a, 'gcx: 'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, +struct GatherBorrows<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, idx_vec: IndexVec>, location_map: FxHashMap, activation_map: FxHashMap>, @@ -181,17 +181,16 @@ struct GatherBorrows<'a, 'gcx: 'tcx, 'tcx: 'a> { locals_state_at_exit: LocalsStateAtExit, } -impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { fn visit_assign( &mut self, - block: mir::BasicBlock, assigned_place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'tcx>, location: mir::Location, ) { if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue { if borrowed_place.ignore_borrow( - self.tcx, self.mir, &self.locals_state_at_exit) { + self.tcx, self.body, &self.locals_state_at_exit) { return; } @@ -210,18 +209,18 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx); - if let Some(local) = borrowed_place.root_local() { + if let Some(local) = borrowed_place.base_local() { self.local_map.entry(local).or_default().insert(idx); } } - self.super_assign(block, assigned_place, rvalue, location) + self.super_assign(assigned_place, rvalue, location) } fn visit_local( &mut self, temp: &Local, - context: PlaceContext<'tcx>, + context: PlaceContext, location: Location, ) { if !context.is_use() { @@ -246,7 +245,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { if let TwoPhaseActivation::ActivatedAt(other_location) = borrow_data.activation_location { span_bug!( - self.mir.source_info(location).span, + self.body.source_info(location).span, "found two uses for 2-phase borrow temporary {:?}: \ {:?} and {:?}", temp, @@ -287,26 +286,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { return self.super_rvalue(rvalue, location); } - - fn visit_statement( - &mut self, - block: mir::BasicBlock, - statement: &mir::Statement<'tcx>, - location: Location, - ) { - return self.super_statement(block, statement, location); - } } -impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> { - /// Returns `true` if the borrow represented by `kind` is - /// allowed to be split into separate Reservation and - /// Activation phases. - fn allow_two_phase_borrow(&self, kind: mir::BorrowKind) -> bool { - self.tcx.two_phase_borrows() - && (kind.allows_two_phase_borrow() - || self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref) - } +impl<'a, 'tcx> GatherBorrows<'a, 'tcx> { /// If this is a two-phase borrow, then we will record it /// as "pending" until we find the activating use. @@ -322,7 +304,7 @@ impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> { start_location, assigned_place, borrow_index, ); - if !self.allow_two_phase_borrow(kind) { + if !allow_two_phase_borrow(kind) { debug!(" -> {:?}", start_location); return; } @@ -337,7 +319,7 @@ impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> { temp } else { span_bug!( - self.mir.source_info(start_location).span, + self.body.source_info(start_location).span, "expected 2-phase borrow to assign to a local, not `{:?}`", assigned_place, ); @@ -356,7 +338,7 @@ impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> { // assignment. let old_value = self.pending_activations.insert(temp, borrow_index); if let Some(old_index) = old_value { - span_bug!(self.mir.source_info(start_location).span, + span_bug!(self.body.source_info(start_location).span, "found already pending activation for temp: {:?} \ at borrow_index: {:?} with associated data {:?}", temp, old_index, self.idx_vec[old_index]); diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs new file mode 100644 index 0000000000000..b9cd1f07e8394 --- /dev/null +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -0,0 +1,1976 @@ +use rustc::hir; +use rustc::hir::def_id::DefId; +use rustc::mir::{ + self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local, + LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, Projection, + ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm, +}; +use rustc::ty::{self, Ty}; +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::indexed_vec::Idx; +use rustc_errors::{Applicability, DiagnosticBuilder}; +use syntax_pos::Span; +use syntax::source_map::CompilerDesugaringKind; + +use super::nll::explain_borrow::BorrowExplanation; +use super::nll::region_infer::{RegionName, RegionNameSource}; +use super::prefixes::IsPrefixOf; +use super::WriteKind; +use super::borrow_set::BorrowData; +use super::MirBorrowckCtxt; +use super::{InitializationRequiringAction, PrefixSet}; +use super::error_reporting::{IncludingDowncast, UseSpans}; +use crate::dataflow::drop_flag_effects; +use crate::dataflow::indexes::{MovePathIndex, MoveOutIndex}; +use crate::util::borrowck_errors::{BorrowckErrors, Origin}; + +#[derive(Debug)] +struct MoveSite { + /// Index of the "move out" that we found. The `MoveData` can + /// then tell us where the move occurred. + moi: MoveOutIndex, + + /// `true` if we traversed a back edge while walking from the point + /// of error to the move site. + traversed_back_edge: bool +} + +/// Which case a StorageDeadOrDrop is for. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum StorageDeadOrDrop<'tcx> { + LocalStorageDead, + BoxedStorageDead, + Destructor(Ty<'tcx>), +} + +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { + pub(super) fn report_use_of_moved_or_uninitialized( + &mut self, + location: Location, + desired_action: InitializationRequiringAction, + (moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span), + mpi: MovePathIndex, + ) { + debug!( + "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \ + moved_place={:?} used_place={:?} span={:?} mpi={:?}", + location, desired_action, moved_place, used_place, span, mpi + ); + + let use_spans = self.move_spans(moved_place, location) + .or_else(|| self.borrow_spans(span, location)); + let span = use_spans.args_or_use(); + + let move_site_vec = self.get_moved_indexes(location, mpi); + debug!( + "report_use_of_moved_or_uninitialized: move_site_vec={:?}", + move_site_vec + ); + let move_out_indices: Vec<_> = move_site_vec + .iter() + .map(|move_site| move_site.moi) + .collect(); + + if move_out_indices.is_empty() { + let root_place = self.prefixes(&used_place, PrefixSet::All).last().unwrap(); + + if self.uninitialized_error_reported.contains(root_place) { + debug!( + "report_use_of_moved_or_uninitialized place: error about {:?} suppressed", + root_place + ); + return; + } + + self.uninitialized_error_reported.insert(root_place.clone()); + + let item_msg = match self.describe_place_with_options(used_place, + IncludingDowncast(true)) { + Some(name) => format!("`{}`", name), + None => "value".to_owned(), + }; + let mut err = self.infcx.tcx.cannot_act_on_uninitialized_variable( + span, + desired_action.as_noun(), + &self.describe_place_with_options(moved_place, IncludingDowncast(true)) + .unwrap_or_else(|| "_".to_owned()), + Origin::Mir, + ); + err.span_label(span, format!("use of possibly uninitialized {}", item_msg)); + + use_spans.var_span_label( + &mut err, + format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), + ); + + err.buffer(&mut self.errors_buffer); + } else { + if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) { + if self.prefixes(&reported_place, PrefixSet::All) + .any(|p| p == used_place) + { + debug!( + "report_use_of_moved_or_uninitialized place: error suppressed \ + mois={:?}", + move_out_indices + ); + return; + } + } + + let msg = ""; //FIXME: add "partially " or "collaterally " + + let mut err = self.infcx.tcx.cannot_act_on_moved_value( + span, + desired_action.as_noun(), + msg, + self.describe_place_with_options(&moved_place, IncludingDowncast(true)), + Origin::Mir, + ); + + self.add_moved_or_invoked_closure_note( + location, + used_place, + &mut err, + ); + + let mut is_loop_move = false; + let is_partial_move = move_site_vec.iter().any(|move_site| { + let move_out = self.move_data.moves[(*move_site).moi]; + let moved_place = &self.move_data.move_paths[move_out.path].place; + used_place != moved_place && used_place.is_prefix_of(moved_place) + }); + for move_site in &move_site_vec { + let move_out = self.move_data.moves[(*move_site).moi]; + let moved_place = &self.move_data.move_paths[move_out.path].place; + + let move_spans = self.move_spans(moved_place, move_out.source); + let move_span = move_spans.args_or_use(); + + let move_msg = if move_spans.for_closure() { + " into closure" + } else { + "" + }; + + if span == move_span { + err.span_label( + span, + format!("value moved{} here, in previous iteration of loop", move_msg), + ); + is_loop_move = true; + } else if move_site.traversed_back_edge { + err.span_label( + move_span, + format!( + "value moved{} here, in previous iteration of loop", + move_msg + ), + ); + } else { + err.span_label(move_span, format!("value moved{} here", move_msg)); + move_spans.var_span_label( + &mut err, + format!("variable moved due to use{}", move_spans.describe()), + ); + } + if Some(CompilerDesugaringKind::ForLoop) == move_span.compiler_desugaring_kind() { + if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { + err.span_suggestion( + move_span, + "consider borrowing to avoid moving into the for loop", + format!("&{}", snippet), + Applicability::MaybeIncorrect, + ); + } + } + } + + use_spans.var_span_label( + &mut err, + format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), + ); + + if !is_loop_move { + err.span_label( + span, + format!( + "value {} here {}", + desired_action.as_verb_in_past_tense(), + if is_partial_move { "after partial move" } else { "after move" }, + ), + ); + } + + let ty = used_place.ty(self.body, self.infcx.tcx).ty; + let needs_note = match ty.sty { + ty::Closure(id, _) => { + let tables = self.infcx.tcx.typeck_tables_of(id); + let hir_id = self.infcx.tcx.hir().as_local_hir_id(id).unwrap(); + + tables.closure_kind_origins().get(hir_id).is_none() + } + _ => true, + }; + + if needs_note { + let mpi = self.move_data.moves[move_out_indices[0]].path; + let place = &self.move_data.move_paths[mpi].place; + + let ty = place.ty(self.body, self.infcx.tcx).ty; + let opt_name = self.describe_place_with_options(place, IncludingDowncast(true)); + let note_msg = match opt_name { + Some(ref name) => format!("`{}`", name), + None => "value".to_owned(), + }; + if let ty::Param(param_ty) = ty.sty { + let tcx = self.infcx.tcx; + let generics = tcx.generics_of(self.mir_def_id); + let def_id = generics.type_param(¶m_ty, tcx).def_id; + if let Some(sp) = tcx.hir().span_if_local(def_id) { + err.span_label( + sp, + "consider adding a `Copy` constraint to this type argument", + ); + } + } + let span = if let Place::Base(PlaceBase::Local(local)) = place { + let decl = &self.body.local_decls[*local]; + Some(decl.source_info.span) + } else { + None + }; + self.note_type_does_not_implement_copy( + &mut err, + ¬e_msg, + ty, + span, + ); + } + + if let Some((_, mut old_err)) = self.move_error_reported + .insert(move_out_indices, (used_place.clone(), err)) + { + // Cancel the old error so it doesn't ICE. + old_err.cancel(); + } + } + } + + pub(super) fn report_move_out_while_borrowed( + &mut self, + location: Location, + (place, span): (&Place<'tcx>, Span), + borrow: &BorrowData<'tcx>, + ) { + debug!( + "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}", + location, place, span, borrow + ); + let tcx = self.infcx.tcx; + let value_msg = match self.describe_place(place) { + Some(name) => format!("`{}`", name), + None => "value".to_owned(), + }; + let borrow_msg = match self.describe_place(&borrow.borrowed_place) { + Some(name) => format!("`{}`", name), + None => "value".to_owned(), + }; + + let borrow_spans = self.retrieve_borrow_spans(borrow); + let borrow_span = borrow_spans.args_or_use(); + + let move_spans = self.move_spans(place, location); + let span = move_spans.args_or_use(); + + let mut err = tcx.cannot_move_when_borrowed( + span, + &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), + Origin::Mir, + ); + err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg)); + err.span_label(span, format!("move out of {} occurs here", value_msg)); + + borrow_spans.var_span_label( + &mut err, + format!("borrow occurs due to use{}", borrow_spans.describe()) + ); + + move_spans.var_span_label( + &mut err, + format!("move occurs due to use{}", move_spans.describe()) + ); + + self.explain_why_borrow_contains_point( + location, + borrow, + None, + ).add_explanation_to_diagnostic(self.infcx.tcx, self.body, &mut err, "", Some(borrow_span)); + err.buffer(&mut self.errors_buffer); + } + + pub(super) fn report_use_while_mutably_borrowed( + &mut self, + location: Location, + (place, _span): (&Place<'tcx>, Span), + borrow: &BorrowData<'tcx>, + ) -> DiagnosticBuilder<'cx> { + let tcx = self.infcx.tcx; + + let borrow_spans = self.retrieve_borrow_spans(borrow); + let borrow_span = borrow_spans.args_or_use(); + + // Conflicting borrows are reported separately, so only check for move + // captures. + let use_spans = self.move_spans(place, location); + let span = use_spans.var_or_use(); + + let mut err = tcx.cannot_use_when_mutably_borrowed( + span, + &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), + borrow_span, + &self.describe_place(&borrow.borrowed_place) + .unwrap_or_else(|| "_".to_owned()), + Origin::Mir, + ); + + borrow_spans.var_span_label(&mut err, { + let place = &borrow.borrowed_place; + let desc_place = self.describe_place(place).unwrap_or_else(|| "_".to_owned()); + + format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe()) + }); + + self.explain_why_borrow_contains_point(location, borrow, None) + .add_explanation_to_diagnostic(self.infcx.tcx, self.body, &mut err, "", None); + err + } + + pub(super) fn report_conflicting_borrow( + &mut self, + location: Location, + (place, span): (&Place<'tcx>, Span), + gen_borrow_kind: BorrowKind, + issued_borrow: &BorrowData<'tcx>, + ) -> DiagnosticBuilder<'cx> { + let issued_spans = self.retrieve_borrow_spans(issued_borrow); + let issued_span = issued_spans.args_or_use(); + + let borrow_spans = self.borrow_spans(span, location); + let span = borrow_spans.args_or_use(); + + let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() { + "generator" + } else { + "closure" + }; + + let (desc_place, msg_place, msg_borrow, union_type_name) = + self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place); + + let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None); + let second_borrow_desc = if explanation.is_explained() { + "second " + } else { + "" + }; + + // FIXME: supply non-"" `opt_via` when appropriate + let tcx = self.infcx.tcx; + let first_borrow_desc; + let mut err = match ( + gen_borrow_kind, + "immutable", + "mutable", + issued_borrow.kind, + "immutable", + "mutable", + ) { + (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) => { + first_borrow_desc = "mutable "; + tcx.cannot_reborrow_already_borrowed( + span, + &desc_place, + &msg_place, + lft, + issued_span, + "it", + rgt, + &msg_borrow, + None, + Origin::Mir, + ) + } + (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => { + first_borrow_desc = "immutable "; + tcx.cannot_reborrow_already_borrowed( + span, + &desc_place, + &msg_place, + lft, + issued_span, + "it", + rgt, + &msg_borrow, + None, + Origin::Mir, + ) + } + + (BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => { + first_borrow_desc = "first "; + tcx.cannot_mutably_borrow_multiply( + span, + &desc_place, + &msg_place, + issued_span, + &msg_borrow, + None, + Origin::Mir, + ) + } + + (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => { + first_borrow_desc = "first "; + tcx.cannot_uniquely_borrow_by_two_closures( + span, + &desc_place, + issued_span, + None, + Origin::Mir, + ) + } + + (BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _) + | (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => { + let mut err = tcx.cannot_mutate_in_match_guard( + span, + issued_span, + &desc_place, + "mutably borrow", + Origin::Mir, + ); + borrow_spans.var_span_label( + &mut err, + format!( + "borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe() + ), + ); + + return err; + } + + (BorrowKind::Unique, _, _, _, _, _) => { + first_borrow_desc = "first "; + tcx.cannot_uniquely_borrow_by_one_closure( + span, + container_name, + &desc_place, + "", + issued_span, + "it", + "", + None, + Origin::Mir, + ) + }, + + (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => { + first_borrow_desc = "first "; + tcx.cannot_reborrow_already_uniquely_borrowed( + span, + container_name, + &desc_place, + "", + lft, + issued_span, + "", + None, + second_borrow_desc, + Origin::Mir, + ) + } + + (BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => { + first_borrow_desc = "first "; + tcx.cannot_reborrow_already_uniquely_borrowed( + span, + container_name, + &desc_place, + "", + lft, + issued_span, + "", + None, + second_borrow_desc, + Origin::Mir, + ) + } + + (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) + | (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _) + | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) + | (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _) + | (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _) + | (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(), + }; + + if issued_spans == borrow_spans { + borrow_spans.var_span_label( + &mut err, + format!("borrows occur due to use of `{}`{}", desc_place, borrow_spans.describe()), + ); + } else { + let borrow_place = &issued_borrow.borrowed_place; + let borrow_place_desc = self.describe_place(borrow_place) + .unwrap_or_else(|| "_".to_owned()); + issued_spans.var_span_label( + &mut err, + format!( + "first borrow occurs due to use of `{}`{}", + borrow_place_desc, + issued_spans.describe(), + ), + ); + + borrow_spans.var_span_label( + &mut err, + format!( + "second borrow occurs due to use of `{}`{}", + desc_place, + borrow_spans.describe(), + ), + ); + } + + if union_type_name != "" { + err.note(&format!( + "`{}` is a field of the union `{}`, so it overlaps the field `{}`", + msg_place, union_type_name, msg_borrow, + )); + } + + explanation.add_explanation_to_diagnostic( + self.infcx.tcx, + self.body, + &mut err, + first_borrow_desc, + None, + ); + + err + } + + /// Returns the description of the root place for a conflicting borrow and the full + /// descriptions of the places that caused the conflict. + /// + /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is + /// attempted while a shared borrow is live, then this function will return: + /// + /// ("x", "", "") + /// + /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while + /// a shared borrow of another field `x.y`, then this function will return: + /// + /// ("x", "x.z", "x.y") + /// + /// In the more complex union case, where the union is a field of a struct, then if a mutable + /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of + /// another field `x.u.y`, then this function will return: + /// + /// ("x.u", "x.u.z", "x.u.y") + /// + /// This is used when creating error messages like below: + /// + /// > cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as + /// > mutable (via `a.u.s.b`) [E0502] + pub(super) fn describe_place_for_conflicting_borrow( + &self, + first_borrowed_place: &Place<'tcx>, + second_borrowed_place: &Place<'tcx>, + ) -> (String, String, String, String) { + // Define a small closure that we can use to check if the type of a place + // is a union. + let union_ty = |place: &Place<'tcx>| -> Option> { + let ty = place.ty(self.body, self.infcx.tcx).ty; + ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty) + }; + let describe_place = |place| self.describe_place(place).unwrap_or_else(|| "_".to_owned()); + + // Start with an empty tuple, so we can use the functions on `Option` to reduce some + // code duplication (particularly around returning an empty description in the failure + // case). + Some(()) + .filter(|_| { + // If we have a conflicting borrow of the same place, then we don't want to add + // an extraneous "via x.y" to our diagnostics, so filter out this case. + first_borrowed_place != second_borrowed_place + }) + .and_then(|_| { + // We're going to want to traverse the first borrowed place to see if we can find + // field access to a union. If we find that, then we will keep the place of the + // union being accessed and the field that was being accessed so we can check the + // second borrowed place for the same union and a access to a different field. + let mut current = first_borrowed_place; + while let Place::Projection(box Projection { base, elem }) = current { + match elem { + ProjectionElem::Field(field, _) if union_ty(base).is_some() => { + return Some((base, field)); + }, + _ => current = base, + } + } + None + }) + .and_then(|(target_base, target_field)| { + // With the place of a union and a field access into it, we traverse the second + // borrowed place and look for a access to a different field of the same union. + let mut current = second_borrowed_place; + while let Place::Projection(box Projection { base, elem }) = current { + if let ProjectionElem::Field(field, _) = elem { + if let Some(union_ty) = union_ty(base) { + if field != target_field && base == target_base { + return Some(( + describe_place(base), + describe_place(first_borrowed_place), + describe_place(second_borrowed_place), + union_ty.to_string(), + )); + } + } + } + + current = base; + } + None + }) + .unwrap_or_else(|| { + // If we didn't find a field access into a union, or both places match, then + // only return the description of the first place. + ( + describe_place(first_borrowed_place), + "".to_string(), + "".to_string(), + "".to_string(), + ) + }) + } + + /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`. + /// + /// This means that some data referenced by `borrow` needs to live + /// past the point where the StorageDeadOrDrop of `place` occurs. + /// This is usually interpreted as meaning that `place` has too + /// short a lifetime. (But sometimes it is more useful to report + /// it as a more direct conflict between the execution of a + /// `Drop::drop` with an aliasing borrow.) + pub(super) fn report_borrowed_value_does_not_live_long_enough( + &mut self, + location: Location, + borrow: &BorrowData<'tcx>, + place_span: (&Place<'tcx>, Span), + kind: Option, + ) { + debug!( + "report_borrowed_value_does_not_live_long_enough(\ + {:?}, {:?}, {:?}, {:?}\ + )", + location, borrow, place_span, kind + ); + + let drop_span = place_span.1; + let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All) + .last() + .unwrap(); + + let borrow_spans = self.retrieve_borrow_spans(borrow); + let borrow_span = borrow_spans.var_or_use(); + + let proper_span = match *root_place { + Place::Base(PlaceBase::Local(local)) => self.body.local_decls[local].source_info.span, + _ => drop_span, + }; + + if self.access_place_error_reported + .contains(&(root_place.clone(), borrow_span)) + { + debug!( + "suppressing access_place error when borrow doesn't live long enough for {:?}", + borrow_span + ); + return; + } + + self.access_place_error_reported + .insert((root_place.clone(), borrow_span)); + + if let StorageDeadOrDrop::Destructor(dropped_ty) = + self.classify_drop_access_kind(&borrow.borrowed_place) + { + // If a borrow of path `B` conflicts with drop of `D` (and + // we're not in the uninteresting case where `B` is a + // prefix of `D`), then report this as a more interesting + // destructor conflict. + if !borrow.borrowed_place.is_prefix_of(place_span.0) { + self.report_borrow_conflicts_with_destructor( + location, borrow, place_span, kind, dropped_ty, + ); + return; + } + } + + let place_desc = self.describe_place(&borrow.borrowed_place); + + let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0)); + let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place); + + let err = match (place_desc, explanation) { + (Some(_), _) if self.is_place_thread_local(root_place) => { + self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span) + } + // If the outlives constraint comes from inside the closure, + // for example: + // + // let x = 0; + // let y = &x; + // Box::new(|| y) as Box &'static i32> + // + // then just use the normal error. The closure isn't escaping + // and `move` will not help here. + ( + Some(ref name), + BorrowExplanation::MustBeValidFor { + category: category @ ConstraintCategory::Return, + from_closure: false, + ref region_name, + span, + .. + }, + ) + | ( + Some(ref name), + BorrowExplanation::MustBeValidFor { + category: category @ ConstraintCategory::CallArgument, + from_closure: false, + ref region_name, + span, + .. + }, + ) if borrow_spans.for_closure() => self.report_escaping_closure_capture( + borrow_spans.args_or_use(), + borrow_span, + region_name, + category, + span, + &format!("`{}`", name), + ), + ( + ref name, + BorrowExplanation::MustBeValidFor { + category: ConstraintCategory::Assignment, + from_closure: false, + region_name: RegionName { + source: RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name), + .. + }, + span, + .. + }, + ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span), + (Some(name), explanation) => self.report_local_value_does_not_live_long_enough( + location, + &name, + &borrow, + drop_span, + borrow_spans, + explanation, + ), + (None, explanation) => self.report_temporary_value_does_not_live_long_enough( + location, + &borrow, + drop_span, + borrow_spans, + proper_span, + explanation, + ), + }; + + err.buffer(&mut self.errors_buffer); + } + + fn report_local_value_does_not_live_long_enough( + &mut self, + location: Location, + name: &str, + borrow: &BorrowData<'tcx>, + drop_span: Span, + borrow_spans: UseSpans, + explanation: BorrowExplanation, + ) -> DiagnosticBuilder<'cx> { + debug!( + "report_local_value_does_not_live_long_enough(\ + {:?}, {:?}, {:?}, {:?}, {:?}\ + )", + location, name, borrow, drop_span, borrow_spans + ); + + let borrow_span = borrow_spans.var_or_use(); + if let BorrowExplanation::MustBeValidFor { + category, + span, + ref opt_place_desc, + from_closure: false, + .. + } = explanation { + if let Some(diag) = self.try_report_cannot_return_reference_to_local( + borrow, + borrow_span, + span, + category, + opt_place_desc.as_ref(), + ) { + return diag; + } + } + + let mut err = self.infcx.tcx.path_does_not_live_long_enough( + borrow_span, + &format!("`{}`", name), + Origin::Mir, + ); + + if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) { + let region_name = annotation.emit(self, &mut err); + + err.span_label( + borrow_span, + format!("`{}` would have to be valid for `{}`...", name, region_name), + ); + + if let Some(fn_hir_id) = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id) { + err.span_label( + drop_span, + format!( + "...but `{}` will be dropped here, when the function `{}` returns", + name, + self.infcx.tcx.hir().name(fn_hir_id), + ), + ); + + err.note( + "functions cannot return a borrow to data owned within the function's scope, \ + functions can only return borrows to data passed as arguments", + ); + err.note( + "to learn more, visit ", + ); + } else { + err.span_label( + drop_span, + format!("...but `{}` dropped here while still borrowed", name), + ); + } + + if let BorrowExplanation::MustBeValidFor { .. } = explanation { + } else { + explanation.add_explanation_to_diagnostic( + self.infcx.tcx, + self.body, + &mut err, + "", + None, + ); + } + } else { + err.span_label(borrow_span, "borrowed value does not live long enough"); + err.span_label( + drop_span, + format!("`{}` dropped here while still borrowed", name), + ); + + let within = if borrow_spans.for_generator() { + " by generator" + } else { + "" + }; + + borrow_spans.args_span_label( + &mut err, + format!("value captured here{}", within), + ); + + explanation.add_explanation_to_diagnostic( + self.infcx.tcx, self.body, &mut err, "", None); + } + + err + } + + fn report_borrow_conflicts_with_destructor( + &mut self, + location: Location, + borrow: &BorrowData<'tcx>, + (place, drop_span): (&Place<'tcx>, Span), + kind: Option, + dropped_ty: Ty<'tcx>, + ) { + debug!( + "report_borrow_conflicts_with_destructor(\ + {:?}, {:?}, ({:?}, {:?}), {:?}\ + )", + location, borrow, place, drop_span, kind, + ); + + let borrow_spans = self.retrieve_borrow_spans(borrow); + let borrow_span = borrow_spans.var_or_use(); + + let mut err = self.infcx + .tcx + .cannot_borrow_across_destructor(borrow_span, Origin::Mir); + + let what_was_dropped = match self.describe_place(place) { + Some(name) => format!("`{}`", name.as_str()), + None => String::from("temporary value"), + }; + + let label = match self.describe_place(&borrow.borrowed_place) { + Some(borrowed) => format!( + "here, drop of {D} needs exclusive access to `{B}`, \ + because the type `{T}` implements the `Drop` trait", + D = what_was_dropped, + T = dropped_ty, + B = borrowed + ), + None => format!( + "here is drop of {D}; whose type `{T}` implements the `Drop` trait", + D = what_was_dropped, + T = dropped_ty + ), + }; + err.span_label(drop_span, label); + + // Only give this note and suggestion if they could be relevant. + let explanation = + self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place))); + match explanation { + BorrowExplanation::UsedLater { .. } + | BorrowExplanation::UsedLaterWhenDropped { .. } => { + err.note("consider using a `let` binding to create a longer lived value"); + } + _ => {} + } + + explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.body, &mut err, "", None); + + err.buffer(&mut self.errors_buffer); + } + + fn report_thread_local_value_does_not_live_long_enough( + &mut self, + drop_span: Span, + borrow_span: Span, + ) -> DiagnosticBuilder<'cx> { + debug!( + "report_thread_local_value_does_not_live_long_enough(\ + {:?}, {:?}\ + )", + drop_span, borrow_span + ); + + let mut err = self.infcx + .tcx + .thread_local_value_does_not_live_long_enough(borrow_span, Origin::Mir); + + err.span_label( + borrow_span, + "thread-local variables cannot be borrowed beyond the end of the function", + ); + err.span_label(drop_span, "end of enclosing function is here"); + + err + } + + fn report_temporary_value_does_not_live_long_enough( + &mut self, + location: Location, + borrow: &BorrowData<'tcx>, + drop_span: Span, + borrow_spans: UseSpans, + proper_span: Span, + explanation: BorrowExplanation, + ) -> DiagnosticBuilder<'cx> { + debug!( + "report_temporary_value_does_not_live_long_enough(\ + {:?}, {:?}, {:?}, {:?}\ + )", + location, borrow, drop_span, proper_span + ); + + if let BorrowExplanation::MustBeValidFor { + category, + span, + from_closure: false, + .. + } = explanation { + if let Some(diag) = self.try_report_cannot_return_reference_to_local( + borrow, + proper_span, + span, + category, + None, + ) { + return diag; + } + } + + let tcx = self.infcx.tcx; + let mut err = tcx.temporary_value_borrowed_for_too_long(proper_span, Origin::Mir); + err.span_label( + proper_span, + "creates a temporary which is freed while still in use", + ); + err.span_label( + drop_span, + "temporary value is freed at the end of this statement", + ); + + match explanation { + BorrowExplanation::UsedLater(..) + | BorrowExplanation::UsedLaterInLoop(..) + | BorrowExplanation::UsedLaterWhenDropped { .. } => { + // Only give this note and suggestion if it could be relevant. + err.note("consider using a `let` binding to create a longer lived value"); + } + _ => {} + } + explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.body, &mut err, "", None); + + let within = if borrow_spans.for_generator() { + " by generator" + } else { + "" + }; + + borrow_spans.args_span_label( + &mut err, + format!("value captured here{}", within), + ); + + err + } + + fn try_report_cannot_return_reference_to_local( + &self, + borrow: &BorrowData<'tcx>, + borrow_span: Span, + return_span: Span, + category: ConstraintCategory, + opt_place_desc: Option<&String>, + ) -> Option> { + let tcx = self.infcx.tcx; + + let return_kind = match category { + ConstraintCategory::Return => "return", + ConstraintCategory::Yield => "yield", + _ => return None, + }; + + // FIXME use a better heuristic than Spans + let reference_desc = if return_span == self.body.source_info(borrow.reserve_location).span { + "reference to" + } else { + "value referencing" + }; + + let (place_desc, note) = if let Some(place_desc) = opt_place_desc { + let local_kind = match borrow.borrowed_place { + Place::Base(PlaceBase::Local(local)) => { + match self.body.local_kind(local) { + LocalKind::ReturnPointer + | LocalKind::Temp => bug!("temporary or return pointer with a name"), + LocalKind::Var => "local variable ", + LocalKind::Arg + if !self.upvars.is_empty() + && local == Local::new(1) => { + "variable captured by `move` " + } + LocalKind::Arg => { + "function parameter " + } + } + } + _ => "local data ", + }; + ( + format!("{}`{}`", local_kind, place_desc), + format!("`{}` is borrowed here", place_desc), + ) + } else { + let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All) + .last() + .unwrap(); + let local = if let Place::Base(PlaceBase::Local(local)) = *root_place { + local + } else { + bug!("try_report_cannot_return_reference_to_local: not a local") + }; + match self.body.local_kind(local) { + LocalKind::ReturnPointer | LocalKind::Temp => ( + "temporary value".to_string(), + "temporary value created here".to_string(), + ), + LocalKind::Arg => ( + "function parameter".to_string(), + "function parameter borrowed here".to_string(), + ), + LocalKind::Var => ( + "local binding".to_string(), + "local binding introduced here".to_string(), + ), + } + }; + + let mut err = tcx.cannot_return_reference_to_local( + return_span, + return_kind, + reference_desc, + &place_desc, + Origin::Mir, + ); + + if return_span != borrow_span { + err.span_label(borrow_span, note); + } + + Some(err) + } + + fn report_escaping_closure_capture( + &mut self, + args_span: Span, + var_span: Span, + fr_name: &RegionName, + category: ConstraintCategory, + constraint_span: Span, + captured_var: &str, + ) -> DiagnosticBuilder<'cx> { + let tcx = self.infcx.tcx; + + let mut err = tcx.cannot_capture_in_long_lived_closure( + args_span, + captured_var, + var_span, + Origin::Mir, + ); + + let suggestion = match tcx.sess.source_map().span_to_snippet(args_span) { + Ok(string) => format!("move {}", string), + Err(_) => "move || ".to_string() + }; + + err.span_suggestion( + args_span, + &format!("to force the closure to take ownership of {} (and any \ + other referenced variables), use the `move` keyword", + captured_var), + suggestion, + Applicability::MachineApplicable, + ); + + match category { + ConstraintCategory::Return => { + err.span_note(constraint_span, "closure is returned here"); + } + ConstraintCategory::CallArgument => { + fr_name.highlight_region_name(&mut err); + err.span_note( + constraint_span, + &format!("function requires argument type to outlive `{}`", fr_name), + ); + } + _ => bug!("report_escaping_closure_capture called with unexpected constraint \ + category: `{:?}`", category), + } + err + } + + fn report_escaping_data( + &mut self, + borrow_span: Span, + name: &Option, + upvar_span: Span, + upvar_name: &str, + escape_span: Span, + ) -> DiagnosticBuilder<'cx> { + let tcx = self.infcx.tcx; + + let escapes_from = if tcx.is_closure(self.mir_def_id) { + let tables = tcx.typeck_tables_of(self.mir_def_id); + let mir_hir_id = tcx.hir().def_index_to_hir_id(self.mir_def_id.index); + match tables.node_type(mir_hir_id).sty { + ty::Closure(..) => "closure", + ty::Generator(..) => "generator", + _ => bug!("Closure body doesn't have a closure or generator type"), + } + } else { + "function" + }; + + let mut err = tcx.borrowed_data_escapes_closure(escape_span, escapes_from, Origin::Mir); + + err.span_label( + upvar_span, + format!( + "`{}` is declared here, outside of the {} body", + upvar_name, escapes_from + ), + ); + + err.span_label( + borrow_span, + format!( + "borrow is only valid in the {} body", + escapes_from + ), + ); + + if let Some(name) = name { + err.span_label( + escape_span, + format!("reference to `{}` escapes the {} body here", name, escapes_from), + ); + } else { + err.span_label( + escape_span, + format!("reference escapes the {} body here", escapes_from), + ); + } + + err + } + + fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec { + let body = self.body; + + let mut stack = Vec::new(); + stack.extend(body.predecessor_locations(location).map(|predecessor| { + let is_back_edge = location.dominates(predecessor, &self.dominators); + (predecessor, is_back_edge) + })); + + let mut visited = FxHashSet::default(); + let mut result = vec![]; + + 'dfs: while let Some((location, is_back_edge)) = stack.pop() { + debug!( + "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})", + location, is_back_edge + ); + + if !visited.insert(location) { + continue; + } + + // check for moves + let stmt_kind = body[location.block] + .statements + .get(location.statement_index) + .map(|s| &s.kind); + if let Some(StatementKind::StorageDead(..)) = stmt_kind { + // this analysis only tries to find moves explicitly + // written by the user, so we ignore the move-outs + // created by `StorageDead` and at the beginning + // of a function. + } else { + // If we are found a use of a.b.c which was in error, then we want to look for + // moves not only of a.b.c but also a.b and a. + // + // Note that the moves data already includes "parent" paths, so we don't have to + // worry about the other case: that is, if there is a move of a.b.c, it is already + // marked as a move of a.b and a as well, so we will generate the correct errors + // there. + let mut mpis = vec![mpi]; + let move_paths = &self.move_data.move_paths; + mpis.extend(move_paths[mpi].parents(move_paths)); + + for moi in &self.move_data.loc_map[location] { + debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi); + if mpis.contains(&self.move_data.moves[*moi].path) { + debug!("report_use_of_moved_or_uninitialized: found"); + result.push(MoveSite { + moi: *moi, + traversed_back_edge: is_back_edge, + }); + + // Strictly speaking, we could continue our DFS here. There may be + // other moves that can reach the point of error. But it is kind of + // confusing to highlight them. + // + // Example: + // + // ``` + // let a = vec![]; + // let b = a; + // let c = a; + // drop(a); // <-- current point of error + // ``` + // + // Because we stop the DFS here, we only highlight `let c = a`, + // and not `let b = a`. We will of course also report an error at + // `let c = a` which highlights `let b = a` as the move. + continue 'dfs; + } + } + } + + // check for inits + let mut any_match = false; + drop_flag_effects::for_location_inits( + self.infcx.tcx, + self.body, + self.move_data, + location, + |m| { + if m == mpi { + any_match = true; + } + }, + ); + if any_match { + continue 'dfs; + } + + stack.extend(body.predecessor_locations(location).map(|predecessor| { + let back_edge = location.dominates(predecessor, &self.dominators); + (predecessor, is_back_edge || back_edge) + })); + } + + result + } + + pub(super) fn report_illegal_mutation_of_borrowed( + &mut self, + location: Location, + (place, span): (&Place<'tcx>, Span), + loan: &BorrowData<'tcx>, + ) { + let loan_spans = self.retrieve_borrow_spans(loan); + let loan_span = loan_spans.args_or_use(); + + let tcx = self.infcx.tcx; + if loan.kind == BorrowKind::Shallow { + let mut err = tcx.cannot_mutate_in_match_guard( + span, + loan_span, + &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), + "assign", + Origin::Mir, + ); + loan_spans.var_span_label( + &mut err, + format!("borrow occurs due to use{}", loan_spans.describe()), + ); + + err.buffer(&mut self.errors_buffer); + + return; + } + + let mut err = tcx.cannot_assign_to_borrowed( + span, + loan_span, + &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), + Origin::Mir, + ); + + loan_spans.var_span_label( + &mut err, + format!("borrow occurs due to use{}", loan_spans.describe()), + ); + + self.explain_why_borrow_contains_point(location, loan, None) + .add_explanation_to_diagnostic(self.infcx.tcx, self.body, &mut err, "", None); + + err.buffer(&mut self.errors_buffer); + } + + /// Reports an illegal reassignment; for example, an assignment to + /// (part of) a non-`mut` local that occurs potentially after that + /// local has already been initialized. `place` is the path being + /// assigned; `err_place` is a place providing a reason why + /// `place` is not mutable (e.g., the non-`mut` local `x` in an + /// assignment to `x.f`). + pub(super) fn report_illegal_reassignment( + &mut self, + _location: Location, + (place, span): (&Place<'tcx>, Span), + assigned_span: Span, + err_place: &Place<'tcx>, + ) { + let (from_arg, local_decl) = if let Place::Base(PlaceBase::Local(local)) = *err_place { + if let LocalKind::Arg = self.body.local_kind(local) { + (true, Some(&self.body.local_decls[local])) + } else { + (false, Some(&self.body.local_decls[local])) + } + } else { + (false, None) + }; + + // If root local is initialized immediately (everything apart from let + // PATTERN;) then make the error refer to that local, rather than the + // place being assigned later. + let (place_description, assigned_span) = match local_decl { + Some(LocalDecl { + is_user_variable: Some(ClearCrossCrate::Clear), + .. + }) + | Some(LocalDecl { + is_user_variable: + Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + opt_match_place: None, + .. + }))), + .. + }) + | Some(LocalDecl { + is_user_variable: None, + .. + }) + | None => (self.describe_place(place), assigned_span), + Some(decl) => (self.describe_place(err_place), decl.source_info.span), + }; + + let mut err = self.infcx.tcx.cannot_reassign_immutable( + span, + place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"), + from_arg, + Origin::Mir, + ); + let msg = if from_arg { + "cannot assign to immutable argument" + } else { + "cannot assign twice to immutable variable" + }; + if span != assigned_span { + if !from_arg { + let value_msg = match place_description { + Some(name) => format!("`{}`", name), + None => "value".to_owned(), + }; + err.span_label(assigned_span, format!("first assignment to {}", value_msg)); + } + } + if let Some(decl) = local_decl { + if let Some(name) = decl.name { + if decl.can_be_made_mutable() { + err.span_suggestion( + decl.source_info.span, + "make this binding mutable", + format!("mut {}", name), + Applicability::MachineApplicable, + ); + } + } + } + err.span_label(span, msg); + err.buffer(&mut self.errors_buffer); + } + + fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> { + let tcx = self.infcx.tcx; + match place { + Place::Base(PlaceBase::Local(_)) | + Place::Base(PlaceBase::Static(_)) => { + StorageDeadOrDrop::LocalStorageDead + } + Place::Projection(box Projection { base, elem }) => { + let base_access = self.classify_drop_access_kind(base); + match elem { + ProjectionElem::Deref => match base_access { + StorageDeadOrDrop::LocalStorageDead + | StorageDeadOrDrop::BoxedStorageDead => { + assert!( + base.ty(self.body, tcx).ty.is_box(), + "Drop of value behind a reference or raw pointer" + ); + StorageDeadOrDrop::BoxedStorageDead + } + StorageDeadOrDrop::Destructor(_) => base_access, + }, + ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { + let base_ty = base.ty(self.body, tcx).ty; + match base_ty.sty { + ty::Adt(def, _) if def.has_dtor(tcx) => { + // Report the outermost adt with a destructor + match base_access { + StorageDeadOrDrop::Destructor(_) => base_access, + StorageDeadOrDrop::LocalStorageDead + | StorageDeadOrDrop::BoxedStorageDead => { + StorageDeadOrDrop::Destructor(base_ty) + } + } + } + _ => base_access, + } + } + + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Index(_) => base_access, + } + } + } + } + + /// Annotate argument and return type of function and closure with (synthesized) lifetime for + /// borrow of local value that does not live long enough. + fn annotate_argument_and_return_for_borrow( + &self, + borrow: &BorrowData<'tcx>, + ) -> Option> { + // Define a fallback for when we can't match a closure. + let fallback = || { + let is_closure = self.infcx.tcx.is_closure(self.mir_def_id); + if is_closure { + None + } else { + let ty = self.infcx.tcx.type_of(self.mir_def_id); + match ty.sty { + ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig( + self.mir_def_id, + self.infcx.tcx.fn_sig(self.mir_def_id), + ), + _ => None, + } + } + }; + + // In order to determine whether we need to annotate, we need to check whether the reserve + // place was an assignment into a temporary. + // + // If it was, we check whether or not that temporary is eventually assigned into the return + // place. If it was, we can add annotations about the function's return type and arguments + // and it'll make sense. + let location = borrow.reserve_location; + debug!( + "annotate_argument_and_return_for_borrow: location={:?}", + location + ); + if let Some(&Statement { kind: StatementKind::Assign(ref reservation, _), ..}) + = &self.body[location.block].statements.get(location.statement_index) + { + debug!( + "annotate_argument_and_return_for_borrow: reservation={:?}", + reservation + ); + // Check that the initial assignment of the reserve location is into a temporary. + let mut target = *match reservation { + Place::Base(PlaceBase::Local(local)) + if self.body.local_kind(*local) == LocalKind::Temp => local, + _ => return None, + }; + + // Next, look through the rest of the block, checking if we are assigning the + // `target` (that is, the place that contains our borrow) to anything. + let mut annotated_closure = None; + for stmt in &self.body[location.block].statements[location.statement_index + 1..] { + debug!( + "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}", + target, stmt + ); + if let StatementKind::Assign( + Place::Base(PlaceBase::Local(assigned_to)), + box rvalue + ) = &stmt.kind { + debug!( + "annotate_argument_and_return_for_borrow: assigned_to={:?} \ + rvalue={:?}", + assigned_to, rvalue + ); + // Check if our `target` was captured by a closure. + if let Rvalue::Aggregate( + box AggregateKind::Closure(def_id, substs), + operands, + ) = rvalue + { + for operand in operands { + let assigned_from = match operand { + Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { + assigned_from + } + _ => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: assigned_from={:?}", + assigned_from + ); + + // Find the local from the operand. + let assigned_from_local = match assigned_from.local_or_deref_local() { + Some(local) => local, + None => continue, + }; + + if assigned_from_local != target { + continue; + } + + // If a closure captured our `target` and then assigned + // into a place then we should annotate the closure in + // case it ends up being assigned into the return place. + annotated_closure = self.annotate_fn_sig( + *def_id, + self.infcx.closure_sig(*def_id, *substs), + ); + debug!( + "annotate_argument_and_return_for_borrow: \ + annotated_closure={:?} assigned_from_local={:?} \ + assigned_to={:?}", + annotated_closure, assigned_from_local, assigned_to + ); + + if *assigned_to == mir::RETURN_PLACE { + // If it was assigned directly into the return place, then + // return now. + return annotated_closure; + } else { + // Otherwise, update the target. + target = *assigned_to; + } + } + + // If none of our closure's operands matched, then skip to the next + // statement. + continue; + } + + // Otherwise, look at other types of assignment. + let assigned_from = match rvalue { + Rvalue::Ref(_, _, assigned_from) => assigned_from, + Rvalue::Use(operand) => match operand { + Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { + assigned_from + } + _ => continue, + }, + _ => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: \ + assigned_from={:?}", + assigned_from, + ); + + // Find the local from the rvalue. + let assigned_from_local = match assigned_from.local_or_deref_local() { + Some(local) => local, + None => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: \ + assigned_from_local={:?}", + assigned_from_local, + ); + + // Check if our local matches the target - if so, we've assigned our + // borrow to a new place. + if assigned_from_local != target { + continue; + } + + // If we assigned our `target` into a new place, then we should + // check if it was the return place. + debug!( + "annotate_argument_and_return_for_borrow: \ + assigned_from_local={:?} assigned_to={:?}", + assigned_from_local, assigned_to + ); + if *assigned_to == mir::RETURN_PLACE { + // If it was then return the annotated closure if there was one, + // else, annotate this function. + return annotated_closure.or_else(fallback); + } + + // If we didn't assign into the return place, then we just update + // the target. + target = *assigned_to; + } + } + + // Check the terminator if we didn't find anything in the statements. + let terminator = &self.body[location.block].terminator(); + debug!( + "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}", + target, terminator + ); + if let TerminatorKind::Call { + destination: Some((Place::Base(PlaceBase::Local(assigned_to)), _)), + args, + .. + } = &terminator.kind + { + debug!( + "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}", + assigned_to, args + ); + for operand in args { + let assigned_from = match operand { + Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { + assigned_from + } + _ => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: assigned_from={:?}", + assigned_from, + ); + + if let Some(assigned_from_local) = assigned_from.local_or_deref_local() { + debug!( + "annotate_argument_and_return_for_borrow: assigned_from_local={:?}", + assigned_from_local, + ); + + if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target { + return annotated_closure.or_else(fallback); + } + } + } + } + } + + // If we haven't found an assignment into the return place, then we need not add + // any annotations. + debug!("annotate_argument_and_return_for_borrow: none found"); + None + } + + /// Annotate the first argument and return type of a function signature if they are + /// references. + fn annotate_fn_sig( + &self, + did: DefId, + sig: ty::PolyFnSig<'tcx>, + ) -> Option> { + debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig); + let is_closure = self.infcx.tcx.is_closure(did); + let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(did)?; + let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?; + + // We need to work out which arguments to highlight. We do this by looking + // at the return type, where there are three cases: + // + // 1. If there are named arguments, then we should highlight the return type and + // highlight any of the arguments that are also references with that lifetime. + // If there are no arguments that have the same lifetime as the return type, + // then don't highlight anything. + // 2. The return type is a reference with an anonymous lifetime. If this is + // the case, then we can take advantage of (and teach) the lifetime elision + // rules. + // + // We know that an error is being reported. So the arguments and return type + // must satisfy the elision rules. Therefore, if there is a single argument + // then that means the return type and first (and only) argument have the same + // lifetime and the borrow isn't meeting that, we can highlight the argument + // and return type. + // + // If there are multiple arguments then the first argument must be self (else + // it would not satisfy the elision rules), so we can highlight self and the + // return type. + // 3. The return type is not a reference. In this case, we don't highlight + // anything. + let return_ty = sig.output(); + match return_ty.skip_binder().sty { + ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => { + // This is case 1 from above, return type is a named reference so we need to + // search for relevant arguments. + let mut arguments = Vec::new(); + for (index, argument) in sig.inputs().skip_binder().iter().enumerate() { + if let ty::Ref(argument_region, _, _) = argument.sty { + if argument_region == return_region { + // Need to use the `rustc::ty` types to compare against the + // `return_region`. Then use the `rustc::hir` type to get only + // the lifetime span. + if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].node { + // With access to the lifetime, we can get + // the span of it. + arguments.push((*argument, lifetime.span)); + } else { + bug!("ty type is a ref but hir type is not"); + } + } + } + } + + // We need to have arguments. This shouldn't happen, but it's worth checking. + if arguments.is_empty() { + return None; + } + + // We use a mix of the HIR and the Ty types to get information + // as the HIR doesn't have full types for closure arguments. + let return_ty = *sig.output().skip_binder(); + let mut return_span = fn_decl.output.span(); + if let hir::FunctionRetTy::Return(ty) = &fn_decl.output { + if let hir::TyKind::Rptr(lifetime, _) = ty.node { + return_span = lifetime.span; + } + } + + Some(AnnotatedBorrowFnSignature::NamedFunction { + arguments, + return_ty, + return_span, + }) + } + ty::Ref(_, _, _) if is_closure => { + // This is case 2 from above but only for closures, return type is anonymous + // reference so we select + // the first argument. + let argument_span = fn_decl.inputs.first()?.span; + let argument_ty = sig.inputs().skip_binder().first()?; + + // Closure arguments are wrapped in a tuple, so we need to get the first + // from that. + if let ty::Tuple(elems) = argument_ty.sty { + let argument_ty = elems.first()?.expect_ty(); + if let ty::Ref(_, _, _) = argument_ty.sty { + return Some(AnnotatedBorrowFnSignature::Closure { + argument_ty, + argument_span, + }); + } + } + + None + } + ty::Ref(_, _, _) => { + // This is also case 2 from above but for functions, return type is still an + // anonymous reference so we select the first argument. + let argument_span = fn_decl.inputs.first()?.span; + let argument_ty = sig.inputs().skip_binder().first()?; + + let return_span = fn_decl.output.span(); + let return_ty = *sig.output().skip_binder(); + + // We expect the first argument to be a reference. + match argument_ty.sty { + ty::Ref(_, _, _) => {} + _ => return None, + } + + Some(AnnotatedBorrowFnSignature::AnonymousFunction { + argument_ty, + argument_span, + return_ty, + return_span, + }) + } + _ => { + // This is case 3 from above, return type is not a reference so don't highlight + // anything. + None + } + } + } +} + +#[derive(Debug)] +enum AnnotatedBorrowFnSignature<'tcx> { + NamedFunction { + arguments: Vec<(Ty<'tcx>, Span)>, + return_ty: Ty<'tcx>, + return_span: Span, + }, + AnonymousFunction { + argument_ty: Ty<'tcx>, + argument_span: Span, + return_ty: Ty<'tcx>, + return_span: Span, + }, + Closure { + argument_ty: Ty<'tcx>, + argument_span: Span, + }, +} + +impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { + /// Annotate the provided diagnostic with information about borrow from the fn signature that + /// helps explain. + pub(super) fn emit( + &self, + cx: &mut MirBorrowckCtxt<'_, 'tcx>, + diag: &mut DiagnosticBuilder<'_>, + ) -> String { + match self { + AnnotatedBorrowFnSignature::Closure { + argument_ty, + argument_span, + } => { + diag.span_label( + *argument_span, + format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)), + ); + + cx.get_region_name_for_ty(argument_ty, 0) + } + AnnotatedBorrowFnSignature::AnonymousFunction { + argument_ty, + argument_span, + return_ty, + return_span, + } => { + let argument_ty_name = cx.get_name_for_ty(argument_ty, 0); + diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name)); + + let return_ty_name = cx.get_name_for_ty(return_ty, 0); + let types_equal = return_ty_name == argument_ty_name; + diag.span_label( + *return_span, + format!( + "{}has type `{}`", + if types_equal { "also " } else { "" }, + return_ty_name, + ), + ); + + diag.note( + "argument and return type have the same lifetime due to lifetime elision rules", + ); + diag.note( + "to learn more, visit ", + ); + + cx.get_region_name_for_ty(return_ty, 0) + } + AnnotatedBorrowFnSignature::NamedFunction { + arguments, + return_ty, + return_span, + } => { + // Region of return type and arguments checked to be the same earlier. + let region_name = cx.get_region_name_for_ty(return_ty, 0); + for (_, argument_span) in arguments { + diag.span_label(*argument_span, format!("has lifetime `{}`", region_name)); + } + + diag.span_label( + *return_span, + format!("also has lifetime `{}`", region_name,), + ); + + diag.help(&format!( + "use data from the highlighted arguments which match the `{}` lifetime of \ + the return type", + region_name, + )); + + region_name + } + } + } +} diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index dc1979b6380b1..10c9a439bf70f 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -1,1473 +1,24 @@ -use crate::borrow_check::nll::explain_borrow::BorrowExplanation; -use crate::borrow_check::nll::region_infer::{RegionName, RegionNameSource}; -use crate::borrow_check::prefixes::IsPrefixOf; -use crate::borrow_check::WriteKind; use rustc::hir; +use rustc::hir::def::Namespace; use rustc::hir::def_id::DefId; -use rustc::middle::region::ScopeTree; use rustc::mir::{ - self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, Constant, - ConstraintCategory, Field, Local, LocalDecl, LocalKind, Location, Operand, - Place, PlaceBase, PlaceProjection, ProjectionElem, Rvalue, Statement, StatementKind, - TerminatorKind, VarBindingForm, + AggregateKind, Constant, Field, Local, LocalKind, Location, Operand, + Place, PlaceBase, ProjectionElem, Rvalue, Statement, StatementKind, Static, + StaticKind, TerminatorKind, }; -use rustc::ty::{self, DefIdTree}; -use rustc::util::ppaux::RegionHighlightMode; -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::indexed_vec::Idx; -use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc::ty::{self, DefIdTree, Ty}; +use rustc::ty::layout::VariantIdx; +use rustc::ty::print::Print; +use rustc_errors::DiagnosticBuilder; use syntax_pos::Span; +use syntax::symbol::sym; use super::borrow_set::BorrowData; -use super::{Context, MirBorrowckCtxt}; -use super::{InitializationRequiringAction, PrefixSet}; -use crate::dataflow::drop_flag_effects; -use crate::dataflow::move_paths::indexes::MoveOutIndex; -use crate::dataflow::move_paths::MovePathIndex; -use crate::util::borrowck_errors::{BorrowckErrors, Origin}; +use super::{MirBorrowckCtxt}; -#[derive(Debug)] -struct MoveSite { - /// Index of the "move out" that we found. The `MoveData` can - /// then tell us where the move occurred. - moi: MoveOutIndex, - - /// `true` if we traversed a back edge while walking from the point - /// of error to the move site. - traversed_back_edge: bool -} - -impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { - pub(super) fn report_use_of_moved_or_uninitialized( - &mut self, - context: Context, - desired_action: InitializationRequiringAction, - (moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span), - mpi: MovePathIndex, - ) { - debug!( - "report_use_of_moved_or_uninitialized: context={:?} desired_action={:?} \ - moved_place={:?} used_place={:?} span={:?} mpi={:?}", - context, desired_action, moved_place, used_place, span, mpi - ); - - let use_spans = self.move_spans(moved_place, context.loc) - .or_else(|| self.borrow_spans(span, context.loc)); - let span = use_spans.args_or_use(); - - let move_site_vec = self.get_moved_indexes(context, mpi); - debug!( - "report_use_of_moved_or_uninitialized: move_site_vec={:?}", - move_site_vec - ); - let move_out_indices: Vec<_> = move_site_vec - .iter() - .map(|move_site| move_site.moi) - .collect(); - - if move_out_indices.is_empty() { - let root_place = self.prefixes(&used_place, PrefixSet::All).last().unwrap(); - - if self.uninitialized_error_reported.contains(root_place) { - debug!( - "report_use_of_moved_or_uninitialized place: error about {:?} suppressed", - root_place - ); - return; - } - - self.uninitialized_error_reported.insert(root_place.clone()); - - let item_msg = match self.describe_place_with_options(used_place, - IncludingDowncast(true)) { - Some(name) => format!("`{}`", name), - None => "value".to_owned(), - }; - let mut err = self.infcx.tcx.cannot_act_on_uninitialized_variable( - span, - desired_action.as_noun(), - &self.describe_place_with_options(moved_place, IncludingDowncast(true)) - .unwrap_or_else(|| "_".to_owned()), - Origin::Mir, - ); - err.span_label(span, format!("use of possibly uninitialized {}", item_msg)); - - use_spans.var_span_label( - &mut err, - format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), - ); - - err.buffer(&mut self.errors_buffer); - } else { - if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) { - if self.prefixes(&reported_place, PrefixSet::All) - .any(|p| p == used_place) - { - debug!( - "report_use_of_moved_or_uninitialized place: error suppressed \ - mois={:?}", - move_out_indices - ); - return; - } - } - - let msg = ""; //FIXME: add "partially " or "collaterally " - - let mut err = self.infcx.tcx.cannot_act_on_moved_value( - span, - desired_action.as_noun(), - msg, - self.describe_place_with_options(&moved_place, IncludingDowncast(true)), - Origin::Mir, - ); - - self.add_moved_or_invoked_closure_note( - context.loc, - used_place, - &mut err, - ); - - let mut is_loop_move = false; - let is_partial_move = move_site_vec.iter().any(|move_site| { - let move_out = self.move_data.moves[(*move_site).moi]; - let moved_place = &self.move_data.move_paths[move_out.path].place; - used_place != moved_place && used_place.is_prefix_of(moved_place) - }); - for move_site in &move_site_vec { - let move_out = self.move_data.moves[(*move_site).moi]; - let moved_place = &self.move_data.move_paths[move_out.path].place; - - let move_spans = self.move_spans(moved_place, move_out.source); - let move_span = move_spans.args_or_use(); - - let move_msg = if move_spans.for_closure() { - " into closure" - } else { - "" - }; - - if span == move_span { - err.span_label( - span, - format!("value moved{} here, in previous iteration of loop", move_msg), - ); - is_loop_move = true; - } else if move_site.traversed_back_edge { - err.span_label( - move_span, - format!( - "value moved{} here, in previous iteration of loop", - move_msg - ), - ); - } else { - err.span_label(move_span, format!("value moved{} here", move_msg)); - move_spans.var_span_label( - &mut err, - format!("variable moved due to use{}", move_spans.describe()), - ); - }; - } - - use_spans.var_span_label( - &mut err, - format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), - ); - - if !is_loop_move { - err.span_label( - span, - format!( - "value {} here {}", - desired_action.as_verb_in_past_tense(), - if is_partial_move { "after partial move" } else { "after move" }, - ), - ); - } - - let ty = used_place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); - let needs_note = match ty.sty { - ty::Closure(id, _) => { - let tables = self.infcx.tcx.typeck_tables_of(id); - let node_id = self.infcx.tcx.hir().as_local_node_id(id).unwrap(); - let hir_id = self.infcx.tcx.hir().node_to_hir_id(node_id); - - tables.closure_kind_origins().get(hir_id).is_none() - } - _ => true, - }; - - if needs_note { - let mpi = self.move_data.moves[move_out_indices[0]].path; - let place = &self.move_data.move_paths[mpi].place; - - let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); - let opt_name = self.describe_place_with_options(place, IncludingDowncast(true)); - let note_msg = match opt_name { - Some(ref name) => format!("`{}`", name), - None => "value".to_owned(), - }; - if let ty::TyKind::Param(param_ty) = ty.sty { - let tcx = self.infcx.tcx; - let generics = tcx.generics_of(self.mir_def_id); - let def_id = generics.type_param(¶m_ty, tcx).def_id; - if let Some(sp) = tcx.hir().span_if_local(def_id) { - err.span_label( - sp, - "consider adding a `Copy` constraint to this type argument", - ); - } - } - if let Place::Base(PlaceBase::Local(local)) = place { - let decl = &self.mir.local_decls[*local]; - err.span_label( - decl.source_info.span, - format!( - "move occurs because {} has type `{}`, \ - which does not implement the `Copy` trait", - note_msg, ty, - )); - } else { - err.note(&format!( - "move occurs because {} has type `{}`, \ - which does not implement the `Copy` trait", - note_msg, ty - )); - } - } - - if let Some((_, mut old_err)) = self.move_error_reported - .insert(move_out_indices, (used_place.clone(), err)) - { - // Cancel the old error so it doesn't ICE. - old_err.cancel(); - } - } - } - - pub(super) fn report_move_out_while_borrowed( - &mut self, - context: Context, - (place, span): (&Place<'tcx>, Span), - borrow: &BorrowData<'tcx>, - ) { - debug!( - "report_move_out_while_borrowed: context={:?} place={:?} span={:?} borrow={:?}", - context, place, span, borrow - ); - let tcx = self.infcx.tcx; - let value_msg = match self.describe_place(place) { - Some(name) => format!("`{}`", name), - None => "value".to_owned(), - }; - let borrow_msg = match self.describe_place(&borrow.borrowed_place) { - Some(name) => format!("`{}`", name), - None => "value".to_owned(), - }; - - let borrow_spans = self.retrieve_borrow_spans(borrow); - let borrow_span = borrow_spans.args_or_use(); - - let move_spans = self.move_spans(place, context.loc); - let span = move_spans.args_or_use(); - - let mut err = tcx.cannot_move_when_borrowed( - span, - &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), - Origin::Mir, - ); - err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg)); - err.span_label(span, format!("move out of {} occurs here", value_msg)); - - borrow_spans.var_span_label( - &mut err, - format!("borrow occurs due to use{}", borrow_spans.describe()) - ); - - move_spans.var_span_label( - &mut err, - format!("move occurs due to use{}", move_spans.describe()) - ); - - self.explain_why_borrow_contains_point(context, borrow, None) - .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, ""); - err.buffer(&mut self.errors_buffer); - } - - pub(super) fn report_use_while_mutably_borrowed( - &mut self, - context: Context, - (place, _span): (&Place<'tcx>, Span), - borrow: &BorrowData<'tcx>, - ) { - let tcx = self.infcx.tcx; - - let borrow_spans = self.retrieve_borrow_spans(borrow); - let borrow_span = borrow_spans.args_or_use(); - - // Conflicting borrows are reported separately, so only check for move - // captures. - let use_spans = self.move_spans(place, context.loc); - let span = use_spans.var_or_use(); - - let mut err = tcx.cannot_use_when_mutably_borrowed( - span, - &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), - borrow_span, - &self.describe_place(&borrow.borrowed_place) - .unwrap_or_else(|| "_".to_owned()), - Origin::Mir, - ); - - borrow_spans.var_span_label(&mut err, { - let place = &borrow.borrowed_place; - let desc_place = self.describe_place(place).unwrap_or_else(|| "_".to_owned()); - - format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe()) - }); - - self.explain_why_borrow_contains_point(context, borrow, None) - .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, ""); - err.buffer(&mut self.errors_buffer); - } - - pub(super) fn report_conflicting_borrow( - &mut self, - context: Context, - (place, span): (&Place<'tcx>, Span), - gen_borrow_kind: BorrowKind, - issued_borrow: &BorrowData<'tcx>, - ) { - let issued_spans = self.retrieve_borrow_spans(issued_borrow); - let issued_span = issued_spans.args_or_use(); - - let borrow_spans = self.borrow_spans(span, context.loc); - let span = borrow_spans.args_or_use(); - - let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() { - "generator" - } else { - "closure" - }; - - let (desc_place, msg_place, msg_borrow, union_type_name) = - self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place); - - let explanation = self.explain_why_borrow_contains_point(context, issued_borrow, None); - let second_borrow_desc = if explanation.is_explained() { - "second " - } else { - "" - }; - - // FIXME: supply non-"" `opt_via` when appropriate - let tcx = self.infcx.tcx; - let first_borrow_desc; - let mut err = match ( - gen_borrow_kind, - "immutable", - "mutable", - issued_borrow.kind, - "immutable", - "mutable", - ) { - (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) => { - first_borrow_desc = "mutable "; - tcx.cannot_reborrow_already_borrowed( - span, - &desc_place, - &msg_place, - lft, - issued_span, - "it", - rgt, - &msg_borrow, - None, - Origin::Mir, - ) - } - (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => { - first_borrow_desc = "immutable "; - tcx.cannot_reborrow_already_borrowed( - span, - &desc_place, - &msg_place, - lft, - issued_span, - "it", - rgt, - &msg_borrow, - None, - Origin::Mir, - ) - } - - (BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => { - first_borrow_desc = "first "; - tcx.cannot_mutably_borrow_multiply( - span, - &desc_place, - &msg_place, - issued_span, - &msg_borrow, - None, - Origin::Mir, - ) - } - - (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => { - first_borrow_desc = "first "; - tcx.cannot_uniquely_borrow_by_two_closures( - span, - &desc_place, - issued_span, - None, - Origin::Mir, - ) - } - - (BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _) - | (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => { - let mut err = tcx.cannot_mutate_in_match_guard( - span, - issued_span, - &desc_place, - "mutably borrow", - Origin::Mir, - ); - borrow_spans.var_span_label( - &mut err, - format!( - "borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe() - ), - ); - err.buffer(&mut self.errors_buffer); - - return; - } - - (BorrowKind::Unique, _, _, _, _, _) => { - first_borrow_desc = "first "; - tcx.cannot_uniquely_borrow_by_one_closure( - span, - container_name, - &desc_place, - "", - issued_span, - "it", - "", - None, - Origin::Mir, - ) - }, - - (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => { - first_borrow_desc = "first "; - tcx.cannot_reborrow_already_uniquely_borrowed( - span, - container_name, - &desc_place, - "", - lft, - issued_span, - "", - None, - second_borrow_desc, - Origin::Mir, - ) - } - - (BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => { - first_borrow_desc = "first "; - tcx.cannot_reborrow_already_uniquely_borrowed( - span, - container_name, - &desc_place, - "", - lft, - issued_span, - "", - None, - second_borrow_desc, - Origin::Mir, - ) - } - - (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _) - | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) => { - // Shallow borrows are uses from the user's point of view. - self.report_use_while_mutably_borrowed(context, (place, span), issued_borrow); - return; - } - (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) - | (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _) - | (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _) - | (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(), - }; - - if issued_spans == borrow_spans { - borrow_spans.var_span_label( - &mut err, - format!("borrows occur due to use of `{}`{}", desc_place, borrow_spans.describe()), - ); - } else { - let borrow_place = &issued_borrow.borrowed_place; - let borrow_place_desc = self.describe_place(borrow_place) - .unwrap_or_else(|| "_".to_owned()); - issued_spans.var_span_label( - &mut err, - format!( - "first borrow occurs due to use of `{}`{}", - borrow_place_desc, - issued_spans.describe(), - ), - ); - - borrow_spans.var_span_label( - &mut err, - format!( - "second borrow occurs due to use of `{}`{}", - desc_place, - borrow_spans.describe(), - ), - ); - } - - if union_type_name != "" { - err.note(&format!( - "`{}` is a field of the union `{}`, so it overlaps the field `{}`", - msg_place, union_type_name, msg_borrow, - )); - } - - explanation - .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, first_borrow_desc); - - err.buffer(&mut self.errors_buffer); - } - - /// Returns the description of the root place for a conflicting borrow and the full - /// descriptions of the places that caused the conflict. - /// - /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is - /// attempted while a shared borrow is live, then this function will return: - /// - /// ("x", "", "") - /// - /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while - /// a shared borrow of another field `x.y`, then this function will return: - /// - /// ("x", "x.z", "x.y") - /// - /// In the more complex union case, where the union is a field of a struct, then if a mutable - /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of - /// another field `x.u.y`, then this function will return: - /// - /// ("x.u", "x.u.z", "x.u.y") - /// - /// This is used when creating error messages like below: - /// - /// > cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as - /// > mutable (via `a.u.s.b`) [E0502] - pub(super) fn describe_place_for_conflicting_borrow( - &self, - first_borrowed_place: &Place<'tcx>, - second_borrowed_place: &Place<'tcx>, - ) -> (String, String, String, String) { - // Define a small closure that we can use to check if the type of a place - // is a union. - let is_union = |place: &Place<'tcx>| -> bool { - place.ty(self.mir, self.infcx.tcx) - .to_ty(self.infcx.tcx) - .ty_adt_def() - .map(|adt| adt.is_union()) - .unwrap_or(false) - }; - - // Start with an empty tuple, so we can use the functions on `Option` to reduce some - // code duplication (particularly around returning an empty description in the failure - // case). - Some(()) - .filter(|_| { - // If we have a conflicting borrow of the same place, then we don't want to add - // an extraneous "via x.y" to our diagnostics, so filter out this case. - first_borrowed_place != second_borrowed_place - }) - .and_then(|_| { - // We're going to want to traverse the first borrowed place to see if we can find - // field access to a union. If we find that, then we will keep the place of the - // union being accessed and the field that was being accessed so we can check the - // second borrowed place for the same union and a access to a different field. - let mut current = first_borrowed_place; - while let Place::Projection(box PlaceProjection { base, elem }) = current { - match elem { - ProjectionElem::Field(field, _) if is_union(base) => { - return Some((base, field)); - }, - _ => current = base, - } - } - None - }) - .and_then(|(target_base, target_field)| { - // With the place of a union and a field access into it, we traverse the second - // borrowed place and look for a access to a different field of the same union. - let mut current = second_borrowed_place; - while let Place::Projection(box PlaceProjection { base, elem }) = current { - match elem { - ProjectionElem::Field(field, _) if { - is_union(base) && field != target_field && base == target_base - } => { - let desc_base = self.describe_place(base) - .unwrap_or_else(|| "_".to_owned()); - let desc_first = self.describe_place(first_borrowed_place) - .unwrap_or_else(|| "_".to_owned()); - let desc_second = self.describe_place(second_borrowed_place) - .unwrap_or_else(|| "_".to_owned()); - - // Also compute the name of the union type, eg. `Foo` so we - // can add a helpful note with it. - let ty = base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); - - return Some((desc_base, desc_first, desc_second, ty.to_string())); - }, - _ => current = base, - } - } - None - }) - .unwrap_or_else(|| { - // If we didn't find a field access into a union, or both places match, then - // only return the description of the first place. - let desc_place = self.describe_place(first_borrowed_place) - .unwrap_or_else(|| "_".to_owned()); - (desc_place, "".to_string(), "".to_string(), "".to_string()) - }) - } - - /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`. - /// - /// This means that some data referenced by `borrow` needs to live - /// past the point where the StorageDeadOrDrop of `place` occurs. - /// This is usually interpreted as meaning that `place` has too - /// short a lifetime. (But sometimes it is more useful to report - /// it as a more direct conflict between the execution of a - /// `Drop::drop` with an aliasing borrow.) - pub(super) fn report_borrowed_value_does_not_live_long_enough( - &mut self, - context: Context, - borrow: &BorrowData<'tcx>, - place_span: (&Place<'tcx>, Span), - kind: Option, - ) { - debug!( - "report_borrowed_value_does_not_live_long_enough(\ - {:?}, {:?}, {:?}, {:?}\ - )", - context, borrow, place_span, kind - ); - - let drop_span = place_span.1; - let scope_tree = self.infcx.tcx.region_scope_tree(self.mir_def_id); - let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All) - .last() - .unwrap(); - - let borrow_spans = self.retrieve_borrow_spans(borrow); - let borrow_span = borrow_spans.var_or_use(); - - let proper_span = match *root_place { - Place::Base(PlaceBase::Local(local)) => self.mir.local_decls[local].source_info.span, - _ => drop_span, - }; - - if self.access_place_error_reported - .contains(&(root_place.clone(), borrow_span)) - { - debug!( - "suppressing access_place error when borrow doesn't live long enough for {:?}", - borrow_span - ); - return; - } - - self.access_place_error_reported - .insert((root_place.clone(), borrow_span)); - - if let StorageDeadOrDrop::Destructor(dropped_ty) = - self.classify_drop_access_kind(&borrow.borrowed_place) - { - // If a borrow of path `B` conflicts with drop of `D` (and - // we're not in the uninteresting case where `B` is a - // prefix of `D`), then report this as a more interesting - // destructor conflict. - if !borrow.borrowed_place.is_prefix_of(place_span.0) { - self.report_borrow_conflicts_with_destructor( - context, borrow, place_span, kind, dropped_ty, - ); - return; - } - } - - let place_desc = self.describe_place(&borrow.borrowed_place); - - let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0)); - let explanation = self.explain_why_borrow_contains_point(context, &borrow, kind_place); - - let err = match (place_desc, explanation) { - (Some(_), _) if self.is_place_thread_local(root_place) => { - self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span) - } - // If the outlives constraint comes from inside the closure, - // for example: - // - // let x = 0; - // let y = &x; - // Box::new(|| y) as Box &'static i32> - // - // then just use the normal error. The closure isn't escaping - // and `move` will not help here. - ( - Some(ref name), - BorrowExplanation::MustBeValidFor { - category: category @ ConstraintCategory::Return, - from_closure: false, - ref region_name, - span, - .. - }, - ) - | ( - Some(ref name), - BorrowExplanation::MustBeValidFor { - category: category @ ConstraintCategory::CallArgument, - from_closure: false, - ref region_name, - span, - .. - }, - ) if borrow_spans.for_closure() => self.report_escaping_closure_capture( - borrow_spans.args_or_use(), - borrow_span, - region_name, - category, - span, - &format!("`{}`", name), - ), - ( - ref name, - BorrowExplanation::MustBeValidFor { - category: ConstraintCategory::Assignment, - from_closure: false, - region_name: RegionName { - source: RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name), - .. - }, - span, - .. - }, - ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span), - (Some(name), explanation) => self.report_local_value_does_not_live_long_enough( - context, - &name, - &scope_tree, - &borrow, - drop_span, - borrow_spans, - explanation, - ), - (None, explanation) => self.report_temporary_value_does_not_live_long_enough( - context, - &scope_tree, - &borrow, - drop_span, - borrow_spans, - proper_span, - explanation, - ), - }; - - err.buffer(&mut self.errors_buffer); - } - - fn report_local_value_does_not_live_long_enough( - &mut self, - context: Context, - name: &str, - scope_tree: &Lrc, - borrow: &BorrowData<'tcx>, - drop_span: Span, - borrow_spans: UseSpans, - explanation: BorrowExplanation, - ) -> DiagnosticBuilder<'cx> { - debug!( - "report_local_value_does_not_live_long_enough(\ - {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\ - )", - context, name, scope_tree, borrow, drop_span, borrow_spans - ); - - let borrow_span = borrow_spans.var_or_use(); - if let BorrowExplanation::MustBeValidFor { - category: ConstraintCategory::Return, - span, - ref opt_place_desc, - from_closure: false, - .. - } = explanation { - return self.report_cannot_return_reference_to_local( - borrow, - borrow_span, - span, - opt_place_desc.as_ref(), - ); - } - - let mut err = self.infcx.tcx.path_does_not_live_long_enough( - borrow_span, - &format!("`{}`", name), - Origin::Mir, - ); - - if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) { - let region_name = annotation.emit(&mut err); - - err.span_label( - borrow_span, - format!("`{}` would have to be valid for `{}`...", name, region_name), - ); - - if let Some(fn_hir_id) = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id) { - err.span_label( - drop_span, - format!( - "...but `{}` will be dropped here, when the function `{}` returns", - name, - self.infcx.tcx.hir().name_by_hir_id(fn_hir_id), - ), - ); - - err.note( - "functions cannot return a borrow to data owned within the function's scope, \ - functions can only return borrows to data passed as arguments", - ); - err.note( - "to learn more, visit ", - ); - } else { - err.span_label( - drop_span, - format!("...but `{}` dropped here while still borrowed", name), - ); - } - - if let BorrowExplanation::MustBeValidFor { .. } = explanation { - } else { - explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, ""); - } - } else { - err.span_label(borrow_span, "borrowed value does not live long enough"); - err.span_label( - drop_span, - format!("`{}` dropped here while still borrowed", name), - ); - - let within = if borrow_spans.for_generator() { - " by generator" - } else { - "" - }; - - borrow_spans.args_span_label( - &mut err, - format!("value captured here{}", within), - ); - - explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, ""); - } - - err - } - - fn report_borrow_conflicts_with_destructor( - &mut self, - context: Context, - borrow: &BorrowData<'tcx>, - (place, drop_span): (&Place<'tcx>, Span), - kind: Option, - dropped_ty: ty::Ty<'tcx>, - ) { - debug!( - "report_borrow_conflicts_with_destructor(\ - {:?}, {:?}, ({:?}, {:?}), {:?}\ - )", - context, borrow, place, drop_span, kind, - ); - - let borrow_spans = self.retrieve_borrow_spans(borrow); - let borrow_span = borrow_spans.var_or_use(); - - let mut err = self.infcx - .tcx - .cannot_borrow_across_destructor(borrow_span, Origin::Mir); - - let what_was_dropped = match self.describe_place(place) { - Some(name) => format!("`{}`", name.as_str()), - None => String::from("temporary value"), - }; - - let label = match self.describe_place(&borrow.borrowed_place) { - Some(borrowed) => format!( - "here, drop of {D} needs exclusive access to `{B}`, \ - because the type `{T}` implements the `Drop` trait", - D = what_was_dropped, - T = dropped_ty, - B = borrowed - ), - None => format!( - "here is drop of {D}; whose type `{T}` implements the `Drop` trait", - D = what_was_dropped, - T = dropped_ty - ), - }; - err.span_label(drop_span, label); - - // Only give this note and suggestion if they could be relevant. - let explanation = - self.explain_why_borrow_contains_point(context, borrow, kind.map(|k| (k, place))); - match explanation { - BorrowExplanation::UsedLater { .. } - | BorrowExplanation::UsedLaterWhenDropped { .. } => { - err.note("consider using a `let` binding to create a longer lived value"); - } - _ => {} - } - - explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, ""); - - err.buffer(&mut self.errors_buffer); - } - - fn report_thread_local_value_does_not_live_long_enough( - &mut self, - drop_span: Span, - borrow_span: Span, - ) -> DiagnosticBuilder<'cx> { - debug!( - "report_thread_local_value_does_not_live_long_enough(\ - {:?}, {:?}\ - )", - drop_span, borrow_span - ); - - let mut err = self.infcx - .tcx - .thread_local_value_does_not_live_long_enough(borrow_span, Origin::Mir); - - err.span_label( - borrow_span, - "thread-local variables cannot be borrowed beyond the end of the function", - ); - err.span_label(drop_span, "end of enclosing function is here"); - - err - } - - fn report_temporary_value_does_not_live_long_enough( - &mut self, - context: Context, - scope_tree: &Lrc, - borrow: &BorrowData<'tcx>, - drop_span: Span, - borrow_spans: UseSpans, - proper_span: Span, - explanation: BorrowExplanation, - ) -> DiagnosticBuilder<'cx> { - debug!( - "report_temporary_value_does_not_live_long_enough(\ - {:?}, {:?}, {:?}, {:?}, {:?}\ - )", - context, scope_tree, borrow, drop_span, proper_span - ); - - if let BorrowExplanation::MustBeValidFor { - category: ConstraintCategory::Return, - span, - from_closure: false, - .. - } = explanation { - return self.report_cannot_return_reference_to_local( - borrow, - proper_span, - span, - None, - ); - } - - let tcx = self.infcx.tcx; - let mut err = tcx.temporary_value_borrowed_for_too_long(proper_span, Origin::Mir); - err.span_label( - proper_span, - "creates a temporary which is freed while still in use", - ); - err.span_label( - drop_span, - "temporary value is freed at the end of this statement", - ); - - match explanation { - BorrowExplanation::UsedLater(..) - | BorrowExplanation::UsedLaterInLoop(..) - | BorrowExplanation::UsedLaterWhenDropped { .. } => { - // Only give this note and suggestion if it could be relevant. - err.note("consider using a `let` binding to create a longer lived value"); - } - _ => {} - } - explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, ""); - - let within = if borrow_spans.for_generator() { - " by generator" - } else { - "" - }; - - borrow_spans.args_span_label( - &mut err, - format!("value captured here{}", within), - ); - - err - } - - fn report_cannot_return_reference_to_local( - &self, - borrow: &BorrowData<'tcx>, - borrow_span: Span, - return_span: Span, - opt_place_desc: Option<&String>, - ) -> DiagnosticBuilder<'cx> { - let tcx = self.infcx.tcx; - - // FIXME use a better heuristic than Spans - let reference_desc = if return_span == self.mir.source_info(borrow.reserve_location).span { - "reference to" - } else { - "value referencing" - }; - - let (place_desc, note) = if let Some(place_desc) = opt_place_desc { - let local_kind = match borrow.borrowed_place { - Place::Base(PlaceBase::Local(local)) => { - match self.mir.local_kind(local) { - LocalKind::ReturnPointer - | LocalKind::Temp => bug!("temporary or return pointer with a name"), - LocalKind::Var => "local variable ", - LocalKind::Arg - if !self.mir.upvar_decls.is_empty() - && local == Local::new(1) => { - "variable captured by `move` " - } - LocalKind::Arg => { - "function parameter " - } - } - } - _ => "local data ", - }; - ( - format!("{}`{}`", local_kind, place_desc), - format!("`{}` is borrowed here", place_desc), - ) - } else { - let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All) - .last() - .unwrap(); - let local = if let Place::Base(PlaceBase::Local(local)) = *root_place { - local - } else { - bug!("report_cannot_return_reference_to_local: not a local") - }; - match self.mir.local_kind(local) { - LocalKind::ReturnPointer | LocalKind::Temp => { - ( - "temporary value".to_string(), - "temporary value created here".to_string(), - ) - } - LocalKind::Arg => { - ( - "function parameter".to_string(), - "function parameter borrowed here".to_string(), - ) - }, - LocalKind::Var => bug!("local variable without a name"), - } - }; - - let mut err = tcx.cannot_return_reference_to_local( - return_span, - reference_desc, - &place_desc, - Origin::Mir, - ); - - if return_span != borrow_span { - err.span_label(borrow_span, note); - } - - err - } - - fn report_escaping_closure_capture( - &mut self, - args_span: Span, - var_span: Span, - fr_name: &RegionName, - category: ConstraintCategory, - constraint_span: Span, - captured_var: &str, - ) -> DiagnosticBuilder<'cx> { - let tcx = self.infcx.tcx; - - let mut err = tcx.cannot_capture_in_long_lived_closure( - args_span, - captured_var, - var_span, - Origin::Mir, - ); - - let suggestion = match tcx.sess.source_map().span_to_snippet(args_span) { - Ok(string) => format!("move {}", string), - Err(_) => "move || ".to_string() - }; - - err.span_suggestion( - args_span, - &format!("to force the closure to take ownership of {} (and any \ - other referenced variables), use the `move` keyword", - captured_var), - suggestion, - Applicability::MachineApplicable, - ); - - match category { - ConstraintCategory::Return => { - err.span_note(constraint_span, "closure is returned here"); - } - ConstraintCategory::CallArgument => { - fr_name.highlight_region_name(&mut err); - err.span_note( - constraint_span, - &format!("function requires argument type to outlive `{}`", fr_name), - ); - } - _ => bug!("report_escaping_closure_capture called with unexpected constraint \ - category: `{:?}`", category), - } - err - } - - fn report_escaping_data( - &mut self, - borrow_span: Span, - name: &Option, - upvar_span: Span, - upvar_name: &str, - escape_span: Span, - ) -> DiagnosticBuilder<'cx> { - let tcx = self.infcx.tcx; - - let escapes_from = if tcx.is_closure(self.mir_def_id) { - let tables = tcx.typeck_tables_of(self.mir_def_id); - let mir_hir_id = tcx.hir().def_index_to_hir_id(self.mir_def_id.index); - match tables.node_type(mir_hir_id).sty { - ty::Closure(..) => "closure", - ty::Generator(..) => "generator", - _ => bug!("Closure body doesn't have a closure or generator type"), - } - } else { - "function" - }; - - let mut err = tcx.borrowed_data_escapes_closure(escape_span, escapes_from, Origin::Mir); - - err.span_label( - upvar_span, - format!( - "`{}` is declared here, outside of the {} body", - upvar_name, escapes_from - ), - ); - - err.span_label( - borrow_span, - format!( - "borrow is only valid in the {} body", - escapes_from - ), - ); - - if let Some(name) = name { - err.span_label( - escape_span, - format!("reference to `{}` escapes the {} body here", name, escapes_from), - ); - } else { - err.span_label( - escape_span, - format!("reference escapes the {} body here", escapes_from), - ); - } - - err - } - - fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec { - let mir = self.mir; - - let mut stack = Vec::new(); - stack.extend(mir.predecessor_locations(context.loc).map(|predecessor| { - let is_back_edge = context.loc.dominates(predecessor, &self.dominators); - (predecessor, is_back_edge) - })); - - let mut visited = FxHashSet::default(); - let mut result = vec![]; - - 'dfs: while let Some((location, is_back_edge)) = stack.pop() { - debug!( - "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})", - location, is_back_edge - ); - - if !visited.insert(location) { - continue; - } - - // check for moves - let stmt_kind = mir[location.block] - .statements - .get(location.statement_index) - .map(|s| &s.kind); - if let Some(StatementKind::StorageDead(..)) = stmt_kind { - // this analysis only tries to find moves explicitly - // written by the user, so we ignore the move-outs - // created by `StorageDead` and at the beginning - // of a function. - } else { - // If we are found a use of a.b.c which was in error, then we want to look for - // moves not only of a.b.c but also a.b and a. - // - // Note that the moves data already includes "parent" paths, so we don't have to - // worry about the other case: that is, if there is a move of a.b.c, it is already - // marked as a move of a.b and a as well, so we will generate the correct errors - // there. - let mut mpis = vec![mpi]; - let move_paths = &self.move_data.move_paths; - mpis.extend(move_paths[mpi].parents(move_paths)); - - for moi in &self.move_data.loc_map[location] { - debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi); - if mpis.contains(&self.move_data.moves[*moi].path) { - debug!("report_use_of_moved_or_uninitialized: found"); - result.push(MoveSite { - moi: *moi, - traversed_back_edge: is_back_edge, - }); - - // Strictly speaking, we could continue our DFS here. There may be - // other moves that can reach the point of error. But it is kind of - // confusing to highlight them. - // - // Example: - // - // ``` - // let a = vec![]; - // let b = a; - // let c = a; - // drop(a); // <-- current point of error - // ``` - // - // Because we stop the DFS here, we only highlight `let c = a`, - // and not `let b = a`. We will of course also report an error at - // `let c = a` which highlights `let b = a` as the move. - continue 'dfs; - } - } - } - - // check for inits - let mut any_match = false; - drop_flag_effects::for_location_inits( - self.infcx.tcx, - self.mir, - self.move_data, - location, - |m| { - if m == mpi { - any_match = true; - } - }, - ); - if any_match { - continue 'dfs; - } - - stack.extend(mir.predecessor_locations(location).map(|predecessor| { - let back_edge = location.dominates(predecessor, &self.dominators); - (predecessor, is_back_edge || back_edge) - })); - } - - result - } - - pub(super) fn report_illegal_mutation_of_borrowed( - &mut self, - context: Context, - (place, span): (&Place<'tcx>, Span), - loan: &BorrowData<'tcx>, - ) { - let loan_spans = self.retrieve_borrow_spans(loan); - let loan_span = loan_spans.args_or_use(); - - let tcx = self.infcx.tcx; - if loan.kind == BorrowKind::Shallow { - let mut err = tcx.cannot_mutate_in_match_guard( - span, - loan_span, - &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), - "assign", - Origin::Mir, - ); - loan_spans.var_span_label( - &mut err, - format!("borrow occurs due to use{}", loan_spans.describe()), - ); - - err.buffer(&mut self.errors_buffer); - - return; - } - - let mut err = tcx.cannot_assign_to_borrowed( - span, - loan_span, - &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), - Origin::Mir, - ); - - loan_spans.var_span_label( - &mut err, - format!("borrow occurs due to use{}", loan_spans.describe()), - ); - - self.explain_why_borrow_contains_point(context, loan, None) - .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, ""); - - err.buffer(&mut self.errors_buffer); - } - - /// Reports an illegal reassignment; for example, an assignment to - /// (part of) a non-`mut` local that occurs potentially after that - /// local has already been initialized. `place` is the path being - /// assigned; `err_place` is a place providing a reason why - /// `place` is not mutable (e.g., the non-`mut` local `x` in an - /// assignment to `x.f`). - pub(super) fn report_illegal_reassignment( - &mut self, - _context: Context, - (place, span): (&Place<'tcx>, Span), - assigned_span: Span, - err_place: &Place<'tcx>, - ) { - let (from_arg, local_decl) = if let Place::Base(PlaceBase::Local(local)) = *err_place { - if let LocalKind::Arg = self.mir.local_kind(local) { - (true, Some(&self.mir.local_decls[local])) - } else { - (false, Some(&self.mir.local_decls[local])) - } - } else { - (false, None) - }; - - // If root local is initialized immediately (everything apart from let - // PATTERN;) then make the error refer to that local, rather than the - // place being assigned later. - let (place_description, assigned_span) = match local_decl { - Some(LocalDecl { - is_user_variable: Some(ClearCrossCrate::Clear), - .. - }) - | Some(LocalDecl { - is_user_variable: - Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - opt_match_place: None, - .. - }))), - .. - }) - | Some(LocalDecl { - is_user_variable: None, - .. - }) - | None => (self.describe_place(place), assigned_span), - Some(decl) => (self.describe_place(err_place), decl.source_info.span), - }; - - let mut err = self.infcx.tcx.cannot_reassign_immutable( - span, - place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"), - from_arg, - Origin::Mir, - ); - let msg = if from_arg { - "cannot assign to immutable argument" - } else { - "cannot assign twice to immutable variable" - }; - if span != assigned_span { - if !from_arg { - let value_msg = match place_description { - Some(name) => format!("`{}`", name), - None => "value".to_owned(), - }; - err.span_label(assigned_span, format!("first assignment to {}", value_msg)); - } - } - if let Some(decl) = local_decl { - if let Some(name) = decl.name { - if decl.can_be_made_mutable() { - err.span_suggestion( - decl.source_info.span, - "make this binding mutable", - format!("mut {}", name), - Applicability::MachineApplicable, - ); - } - } - } - err.span_label(span, msg); - err.buffer(&mut self.errors_buffer); - } -} - -pub(super) struct IncludingDowncast(bool); - -/// Which case a StorageDeadOrDrop is for. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum StorageDeadOrDrop<'tcx> { - LocalStorageDead, - BoxedStorageDead, - Destructor(ty::Ty<'tcx>), -} - -impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { +pub(super) struct IncludingDowncast(pub(super) bool); +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure /// is moved after being invoked. /// @@ -1486,29 +37,29 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { diag: &mut DiagnosticBuilder<'_>, ) { debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place); - let mut target = place.local(); - for stmt in &self.mir[location.block].statements[location.statement_index..] { + let mut target = place.local_or_deref_local(); + for stmt in &self.body[location.block].statements[location.statement_index..] { debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target); if let StatementKind::Assign(into, box Rvalue::Use(from)) = &stmt.kind { debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from); match from { Operand::Copy(ref place) | - Operand::Move(ref place) if target == place.local() => - target = into.local(), + Operand::Move(ref place) if target == place.local_or_deref_local() => + target = into.local_or_deref_local(), _ => {}, } } } // Check if we are attempting to call a closure after it has been invoked. - let terminator = self.mir[location.block].terminator(); + let terminator = self.body[location.block].terminator(); debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator); if let TerminatorKind::Call { func: Operand::Constant(box Constant { - literal: ty::LazyConst::Evaluated(ty::Const { - ty: &ty::TyS { sty: ty::TyKind::FnDef(id, _), .. }, + literal: ty::Const { + ty: &ty::TyS { sty: ty::FnDef(id, _), .. }, .. - }), + }, .. }), args, @@ -1518,15 +69,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() { let closure = match args.first() { Some(Operand::Copy(ref place)) | - Some(Operand::Move(ref place)) if target == place.local() => - place.local().unwrap(), + Some(Operand::Move(ref place)) if target == place.local_or_deref_local() => + place.local_or_deref_local().unwrap(), _ => return, }; debug!("add_moved_or_invoked_closure_note: closure={:?}", closure); - if let ty::TyKind::Closure(did, _) = self.mir.local_decls[closure].ty.sty { - let node_id = self.infcx.tcx.hir().as_local_node_id(did).unwrap(); - let hir_id = self.infcx.tcx.hir().node_to_hir_id(node_id); + if let ty::Closure(did, _) = self.body.local_decls[closure].ty.sty { + let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap(); if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did) .closure_kind_origins() @@ -1548,9 +98,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Check if we are just moving a closure after it has been invoked. if let Some(target) = target { - if let ty::TyKind::Closure(did, _) = self.mir.local_decls[target].ty.sty { - let node_id = self.infcx.tcx.hir().as_local_node_id(did).unwrap(); - let hir_id = self.infcx.tcx.hir().node_to_hir_id(node_id); + if let ty::Closure(did, _) = self.body.local_decls[target].ty.sty { + let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap(); if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did) .closure_kind_origins() @@ -1600,24 +149,24 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { including_downcast: &IncludingDowncast, ) -> Result<(), ()> { match *place { - Place::Base(PlaceBase::Promoted(_)) => { - buf.push_str("promoted"); - } Place::Base(PlaceBase::Local(local)) => { self.append_local_to_string(local, buf)?; } - Place::Base(PlaceBase::Static(ref static_)) => { - buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string()); + Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => { + buf.push_str("promoted"); + } + Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => { + buf.push_str(&self.infcx.tcx.item_name(def_id).to_string()); } Place::Projection(ref proj) => { match proj.elem { ProjectionElem::Deref => { let upvar_field_projection = - place.is_upvar_field_projection(self.mir, &self.infcx.tcx); + self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { let var_index = field.index(); - let name = self.mir.upvar_decls[var_index].debug_name.to_string(); - if self.mir.upvar_decls[var_index].by_ref { + let name = self.upvars[var_index].name.to_string(); + if self.upvars[var_index].by_ref { buf.push_str(&name); } else { buf.push_str(&format!("*{}", &name)); @@ -1631,9 +180,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { &including_downcast, )?; } else if let Place::Base(PlaceBase::Local(local)) = proj.base { - if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) = - self.mir.local_decls[local].is_user_variable - { + if self.body.local_decls[local].is_ref_for_guard() { self.append_place_to_string( &proj.base, buf, @@ -1675,10 +222,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { autoderef = true; let upvar_field_projection = - place.is_upvar_field_projection(self.mir, &self.infcx.tcx); + self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { let var_index = field.index(); - let name = self.mir.upvar_decls[var_index].debug_name.to_string(); + let name = self.upvars[var_index].name.to_string(); buf.push_str(&name); } else { let field_name = self.describe_field(&proj.base, field); @@ -1727,35 +274,35 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have - /// a name, then `Err` is returned + /// a name, or its name was generated by the compiler, then `Err` is returned fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result<(), ()> { - let local = &self.mir.local_decls[local_index]; + let local = &self.body.local_decls[local_index]; match local.name { - Some(name) => { - buf.push_str(&name.to_string()); + Some(name) if !local.from_compiler_desugaring() => { + buf.push_str(name.as_str().get()); Ok(()) } - None => Err(()), + _ => Err(()), } } /// End-user visible description of the `field`nth field of `base` - fn describe_field(&self, base: &Place<'_>, field: Field) -> String { + fn describe_field(&self, base: &Place<'tcx>, field: Field) -> String { match *base { Place::Base(PlaceBase::Local(local)) => { - let local = &self.mir.local_decls[local]; - self.describe_field_from_ty(&local.ty, field) + let local = &self.body.local_decls[local]; + self.describe_field_from_ty(&local.ty, field, None) } - Place::Base(PlaceBase::Promoted(ref prom)) => - self.describe_field_from_ty(&prom.1, field), Place::Base(PlaceBase::Static(ref static_)) => - self.describe_field_from_ty(&static_.ty, field), + self.describe_field_from_ty(&static_.ty, field, None), Place::Projection(ref proj) => match proj.elem { ProjectionElem::Deref => self.describe_field(&proj.base, field), - ProjectionElem::Downcast(def, variant_index) => - def.variants[variant_index].fields[field.index()].ident.to_string(), + ProjectionElem::Downcast(_, variant_index) => { + let base_ty = base.ty(self.body, self.infcx.tcx).ty; + self.describe_field_from_ty(&base_ty, field, Some(variant_index)) + } ProjectionElem::Field(_, field_type) => { - self.describe_field_from_ty(&field_type, field) + self.describe_field_from_ty(&field_type, field, None) } ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } @@ -1767,42 +314,49 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } /// End-user visible description of the `field_index`nth field of `ty` - fn describe_field_from_ty(&self, ty: &ty::Ty<'_>, field: Field) -> String { + fn describe_field_from_ty( + &self, + ty: Ty<'_>, + field: Field, + variant_index: Option + ) -> String { if ty.is_box() { // If the type is a box, the field is described from the boxed type - self.describe_field_from_ty(&ty.boxed_ty(), field) + self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index) } else { match ty.sty { - ty::Adt(def, _) => if def.is_enum() { - field.index().to_string() - } else { - def.non_enum_variant().fields[field.index()] + ty::Adt(def, _) => { + let variant = if let Some(idx) = variant_index { + assert!(def.is_enum()); + &def.variants[idx] + } else { + def.non_enum_variant() + }; + variant.fields[field.index()] .ident .to_string() }, ty::Tuple(_) => field.index().to_string(), ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { - self.describe_field_from_ty(&ty, field) + self.describe_field_from_ty(&ty, field, variant_index) } - ty::Array(ty, _) | ty::Slice(ty) => self.describe_field_from_ty(&ty, field), + ty::Array(ty, _) | ty::Slice(ty) => + self.describe_field_from_ty(&ty, field, variant_index), ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { - // Convert the def-id into a node-id. node-ids are only valid for - // the local code in the current crate, so this returns an `Option` in case + // `tcx.upvars(def_id)` returns an `Option`, which is `None` in case // the closure comes from another crate. But in that case we wouldn't // be borrowck'ing it, so we can just unwrap: - let node_id = self.infcx.tcx.hir().as_local_node_id(def_id).unwrap(); - let freevar = self.infcx - .tcx - .with_freevars(node_id, |fv| fv[field.index()]); + let (&var_id, _) = self.infcx.tcx.upvars(def_id).unwrap() + .get_index(field.index()).unwrap(); - self.infcx.tcx.hir().name(freevar.var_id()).to_string() + self.infcx.tcx.hir().name(var_id).to_string() } _ => { // Might need a revision when the fields in trait RFC is implemented // (https://github.com/rust-lang/rfcs/pull/1546) bug!( "End-user description not implemented for field access on `{:?}`", - ty.sty + ty ); } } @@ -1811,9 +365,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// Checks if a place is a thread-local static. pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool { - if let Place::Base(PlaceBase::Static(statik)) = place { - let attrs = self.infcx.tcx.get_attrs(statik.def_id); - let is_thread_local = attrs.iter().any(|attr| attr.check_name("thread_local")); + if let Place::Base( + PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) + ) = place { + let attrs = self.infcx.tcx.get_attrs(*def_id); + let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local)); debug!( "is_place_thread_local: attrs={:?} is_thread_local={:?}", @@ -1826,532 +382,74 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } - fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> { - let tcx = self.infcx.tcx; - match place { - Place::Base(PlaceBase::Local(_)) | - Place::Base(PlaceBase::Static(_)) | - Place::Base(PlaceBase::Promoted(_)) => { - StorageDeadOrDrop::LocalStorageDead - } - Place::Projection(box PlaceProjection { base, elem }) => { - let base_access = self.classify_drop_access_kind(base); - match elem { - ProjectionElem::Deref => match base_access { - StorageDeadOrDrop::LocalStorageDead - | StorageDeadOrDrop::BoxedStorageDead => { - assert!( - base.ty(self.mir, tcx).to_ty(tcx).is_box(), - "Drop of value behind a reference or raw pointer" - ); - StorageDeadOrDrop::BoxedStorageDead - } - StorageDeadOrDrop::Destructor(_) => base_access, - }, - ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { - let base_ty = base.ty(self.mir, tcx).to_ty(tcx); - match base_ty.sty { - ty::Adt(def, _) if def.has_dtor(tcx) => { - // Report the outermost adt with a destructor - match base_access { - StorageDeadOrDrop::Destructor(_) => base_access, - StorageDeadOrDrop::LocalStorageDead - | StorageDeadOrDrop::BoxedStorageDead => { - StorageDeadOrDrop::Destructor(base_ty) - } - } - } - _ => base_access, - } - } - - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Index(_) => base_access, - } - } - } - } - - /// Annotate argument and return type of function and closure with (synthesized) lifetime for - /// borrow of local value that does not live long enough. - fn annotate_argument_and_return_for_borrow( + /// Add a note that a type does not implement `Copy` + pub(super) fn note_type_does_not_implement_copy( &self, - borrow: &BorrowData<'tcx>, - ) -> Option> { - // Define a fallback for when we can't match a closure. - let fallback = || { - let is_closure = self.infcx.tcx.is_closure(self.mir_def_id); - if is_closure { - None - } else { - let ty = self.infcx.tcx.type_of(self.mir_def_id); - match ty.sty { - ty::TyKind::FnDef(_, _) | ty::TyKind::FnPtr(_) => self.annotate_fn_sig( - self.mir_def_id, - self.infcx.tcx.fn_sig(self.mir_def_id), - ), - _ => None, - } - } - }; - - // In order to determine whether we need to annotate, we need to check whether the reserve - // place was an assignment into a temporary. - // - // If it was, we check whether or not that temporary is eventually assigned into the return - // place. If it was, we can add annotations about the function's return type and arguments - // and it'll make sense. - let location = borrow.reserve_location; - debug!( - "annotate_argument_and_return_for_borrow: location={:?}", - location + err: &mut DiagnosticBuilder<'a>, + place_desc: &str, + ty: Ty<'tcx>, + span: Option, + ) { + let message = format!( + "move occurs because {} has type `{}`, which does not implement the `Copy` trait", + place_desc, + ty, ); - if let Some(&Statement { kind: StatementKind::Assign(ref reservation, _), ..}) - = &self.mir[location.block].statements.get(location.statement_index) - { - debug!( - "annotate_argument_and_return_for_borrow: reservation={:?}", - reservation - ); - // Check that the initial assignment of the reserve location is into a temporary. - let mut target = *match reservation { - Place::Base(PlaceBase::Local(local)) - if self.mir.local_kind(*local) == LocalKind::Temp => local, - _ => return None, - }; - - // Next, look through the rest of the block, checking if we are assigning the - // `target` (that is, the place that contains our borrow) to anything. - let mut annotated_closure = None; - for stmt in &self.mir[location.block].statements[location.statement_index + 1..] { - debug!( - "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}", - target, stmt - ); - if let StatementKind::Assign( - Place::Base(PlaceBase::Local(assigned_to)), - box rvalue - ) = &stmt.kind { - debug!( - "annotate_argument_and_return_for_borrow: assigned_to={:?} \ - rvalue={:?}", - assigned_to, rvalue - ); - // Check if our `target` was captured by a closure. - if let Rvalue::Aggregate( - box AggregateKind::Closure(def_id, substs), - operands, - ) = rvalue - { - for operand in operands { - let assigned_from = match operand { - Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { - assigned_from - } - _ => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: assigned_from={:?}", - assigned_from - ); - - // Find the local from the operand. - let assigned_from_local = match assigned_from.local() { - Some(local) => local, - None => continue, - }; - - if assigned_from_local != target { - continue; - } - - // If a closure captured our `target` and then assigned - // into a place then we should annotate the closure in - // case it ends up being assigned into the return place. - annotated_closure = self.annotate_fn_sig( - *def_id, - self.infcx.closure_sig(*def_id, *substs), - ); - debug!( - "annotate_argument_and_return_for_borrow: \ - annotated_closure={:?} assigned_from_local={:?} \ - assigned_to={:?}", - annotated_closure, assigned_from_local, assigned_to - ); - - if *assigned_to == mir::RETURN_PLACE { - // If it was assigned directly into the return place, then - // return now. - return annotated_closure; - } else { - // Otherwise, update the target. - target = *assigned_to; - } - } - - // If none of our closure's operands matched, then skip to the next - // statement. - continue; - } - - // Otherwise, look at other types of assignment. - let assigned_from = match rvalue { - Rvalue::Ref(_, _, assigned_from) => assigned_from, - Rvalue::Use(operand) => match operand { - Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { - assigned_from - } - _ => continue, - }, - _ => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from={:?}", - assigned_from, - ); - - // Find the local from the rvalue. - let assigned_from_local = match assigned_from.local() { - Some(local) => local, - None => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from_local={:?}", - assigned_from_local, - ); - - // Check if our local matches the target - if so, we've assigned our - // borrow to a new place. - if assigned_from_local != target { - continue; - } - - // If we assigned our `target` into a new place, then we should - // check if it was the return place. - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from_local={:?} assigned_to={:?}", - assigned_from_local, assigned_to - ); - if *assigned_to == mir::RETURN_PLACE { - // If it was then return the annotated closure if there was one, - // else, annotate this function. - return annotated_closure.or_else(fallback); - } - - // If we didn't assign into the return place, then we just update - // the target. - target = *assigned_to; - } - } - - // Check the terminator if we didn't find anything in the statements. - let terminator = &self.mir[location.block].terminator(); - debug!( - "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}", - target, terminator - ); - if let TerminatorKind::Call { - destination: Some((Place::Base(PlaceBase::Local(assigned_to)), _)), - args, - .. - } = &terminator.kind - { - debug!( - "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}", - assigned_to, args - ); - for operand in args { - let assigned_from = match operand { - Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { - assigned_from - } - _ => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: assigned_from={:?}", - assigned_from, - ); - - if let Some(assigned_from_local) = assigned_from.local() { - debug!( - "annotate_argument_and_return_for_borrow: assigned_from_local={:?}", - assigned_from_local, - ); - - if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target { - return annotated_closure.or_else(fallback); - } - } - } - } - } - - // If we haven't found an assignment into the return place, then we need not add - // any annotations. - debug!("annotate_argument_and_return_for_borrow: none found"); - None - } - - /// Annotate the first argument and return type of a function signature if they are - /// references. - fn annotate_fn_sig( - &self, - did: DefId, - sig: ty::PolyFnSig<'tcx>, - ) -> Option> { - debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig); - let is_closure = self.infcx.tcx.is_closure(did); - let fn_node_id = self.infcx.tcx.hir().as_local_node_id(did)?; - let fn_decl = self.infcx.tcx.hir().fn_decl(fn_node_id)?; - - // We need to work out which arguments to highlight. We do this by looking - // at the return type, where there are three cases: - // - // 1. If there are named arguments, then we should highlight the return type and - // highlight any of the arguments that are also references with that lifetime. - // If there are no arguments that have the same lifetime as the return type, - // then don't highlight anything. - // 2. The return type is a reference with an anonymous lifetime. If this is - // the case, then we can take advantage of (and teach) the lifetime elision - // rules. - // - // We know that an error is being reported. So the arguments and return type - // must satisfy the elision rules. Therefore, if there is a single argument - // then that means the return type and first (and only) argument have the same - // lifetime and the borrow isn't meeting that, we can highlight the argument - // and return type. - // - // If there are multiple arguments then the first argument must be self (else - // it would not satisfy the elision rules), so we can highlight self and the - // return type. - // 3. The return type is not a reference. In this case, we don't highlight - // anything. - let return_ty = sig.output(); - match return_ty.skip_binder().sty { - ty::TyKind::Ref(return_region, _, _) if return_region.has_name() && !is_closure => { - // This is case 1 from above, return type is a named reference so we need to - // search for relevant arguments. - let mut arguments = Vec::new(); - for (index, argument) in sig.inputs().skip_binder().iter().enumerate() { - if let ty::TyKind::Ref(argument_region, _, _) = argument.sty { - if argument_region == return_region { - // Need to use the `rustc::ty` types to compare against the - // `return_region`. Then use the `rustc::hir` type to get only - // the lifetime span. - if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].node { - // With access to the lifetime, we can get - // the span of it. - arguments.push((*argument, lifetime.span)); - } else { - bug!("ty type is a ref but hir type is not"); - } - } - } - } - - // We need to have arguments. This shouldn't happen, but it's worth checking. - if arguments.is_empty() { - return None; - } - - // We use a mix of the HIR and the Ty types to get information - // as the HIR doesn't have full types for closure arguments. - let return_ty = *sig.output().skip_binder(); - let mut return_span = fn_decl.output.span(); - if let hir::FunctionRetTy::Return(ty) = fn_decl.output { - if let hir::TyKind::Rptr(lifetime, _) = ty.into_inner().node { - return_span = lifetime.span; - } - } - - Some(AnnotatedBorrowFnSignature::NamedFunction { - arguments, - return_ty, - return_span, - }) - } - ty::TyKind::Ref(_, _, _) if is_closure => { - // This is case 2 from above but only for closures, return type is anonymous - // reference so we select - // the first argument. - let argument_span = fn_decl.inputs.first()?.span; - let argument_ty = sig.inputs().skip_binder().first()?; - - // Closure arguments are wrapped in a tuple, so we need to get the first - // from that. - if let ty::TyKind::Tuple(elems) = argument_ty.sty { - let argument_ty = elems.first()?; - if let ty::TyKind::Ref(_, _, _) = argument_ty.sty { - return Some(AnnotatedBorrowFnSignature::Closure { - argument_ty, - argument_span, - }); - } - } - - None - } - ty::TyKind::Ref(_, _, _) => { - // This is also case 2 from above but for functions, return type is still an - // anonymous reference so we select the first argument. - let argument_span = fn_decl.inputs.first()?.span; - let argument_ty = sig.inputs().skip_binder().first()?; - - let return_span = fn_decl.output.span(); - let return_ty = *sig.output().skip_binder(); - - // We expect the first argument to be a reference. - match argument_ty.sty { - ty::TyKind::Ref(_, _, _) => {} - _ => return None, - } - - Some(AnnotatedBorrowFnSignature::AnonymousFunction { - argument_ty, - argument_span, - return_ty, - return_span, - }) - } - _ => { - // This is case 3 from above, return type is not a reference so don't highlight - // anything. - None - } + if let Some(span) = span { + err.span_label(span, message); + } else { + err.note(&message); } } } -#[derive(Debug)] -enum AnnotatedBorrowFnSignature<'tcx> { - NamedFunction { - arguments: Vec<(ty::Ty<'tcx>, Span)>, - return_ty: ty::Ty<'tcx>, - return_span: Span, - }, - AnonymousFunction { - argument_ty: ty::Ty<'tcx>, - argument_span: Span, - return_ty: ty::Ty<'tcx>, - return_span: Span, - }, - Closure { - argument_ty: ty::Ty<'tcx>, - argument_span: Span, - }, -} - -impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { - /// Annotate the provided diagnostic with information about borrow from the fn signature that - /// helps explain. - fn emit(&self, diag: &mut DiagnosticBuilder<'_>) -> String { - match self { - AnnotatedBorrowFnSignature::Closure { - argument_ty, - argument_span, - } => { - diag.span_label( - *argument_span, - format!("has type `{}`", self.get_name_for_ty(argument_ty, 0)), - ); - - self.get_region_name_for_ty(argument_ty, 0) - } - AnnotatedBorrowFnSignature::AnonymousFunction { - argument_ty, - argument_span, - return_ty, - return_span, - } => { - let argument_ty_name = self.get_name_for_ty(argument_ty, 0); - diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name)); - - let return_ty_name = self.get_name_for_ty(return_ty, 0); - let types_equal = return_ty_name == argument_ty_name; - diag.span_label( - *return_span, - format!( - "{}has type `{}`", - if types_equal { "also " } else { "" }, - return_ty_name, - ), - ); - - diag.note( - "argument and return type have the same lifetime due to lifetime elision rules", - ); - diag.note( - "to learn more, visit ", - ); - - self.get_region_name_for_ty(return_ty, 0) - } - AnnotatedBorrowFnSignature::NamedFunction { - arguments, - return_ty, - return_span, - } => { - // Region of return type and arguments checked to be the same earlier. - let region_name = self.get_region_name_for_ty(return_ty, 0); - for (_, argument_span) in arguments { - diag.span_label(*argument_span, format!("has lifetime `{}`", region_name)); - } - - diag.span_label( - *return_span, - format!("also has lifetime `{}`", region_name,), - ); - - diag.help(&format!( - "use data from the highlighted arguments which match the `{}` lifetime of \ - the return type", - region_name, - )); - - region_name - } - } - } - +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime /// name where required. - fn get_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String { + pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String { + let mut s = String::new(); + let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS); + // We need to add synthesized lifetimes where appropriate. We do // this by hooking into the pretty printer and telling it to label the // lifetimes without names with the value `'0`. match ty.sty { - ty::TyKind::Ref(ty::RegionKind::ReLateBound(_, br), _, _) - | ty::TyKind::Ref( + ty::Ref(ty::RegionKind::ReLateBound(_, br), _, _) + | ty::Ref( ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), _, _, - ) => RegionHighlightMode::highlighting_bound_region(*br, counter, || ty.to_string()), - _ => ty.to_string(), + ) => printer.region_highlight_mode.highlighting_bound_region(*br, counter), + _ => {} } + + let _ = ty.print(printer); + s } /// Returns the name of the provided `Ty` (that must be a reference)'s region with a /// synthesized lifetime name where required. - fn get_region_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String { - match ty.sty { - ty::TyKind::Ref(region, _, _) => match region { - ty::RegionKind::ReLateBound(_, br) - | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { - RegionHighlightMode::highlighting_bound_region( - *br, - counter, - || region.to_string(), - ) + pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String { + let mut s = String::new(); + let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS); + + let region = match ty.sty { + ty::Ref(region, _, _) => { + match region { + ty::RegionKind::ReLateBound(_, br) + | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { + printer.region_highlight_mode.highlighting_bound_region(*br, counter) + } + _ => {} } - _ => region.to_string(), - }, + + region + } _ => bug!("ty for annotation of borrow region is not a reference"), - } + }; + + let _ = region.print(printer); + s } } @@ -2411,7 +509,7 @@ impl UseSpans { } /// Returns `false` if this place is not used in a closure. - fn for_closure(&self) -> bool { + pub(super) fn for_closure(&self) -> bool { match *self { UseSpans::ClosureUse { is_generator, .. } => !is_generator, _ => false, @@ -2419,7 +517,7 @@ impl UseSpans { } /// Returns `false` if this place is not used in a generator. - fn for_generator(&self) -> bool { + pub(super) fn for_generator(&self) -> bool { match *self { UseSpans::ClosureUse { is_generator, .. } => is_generator, _ => false, @@ -2427,7 +525,7 @@ impl UseSpans { } /// Describe the span associated with a use of a place. - fn describe(&self) -> String { + pub(super) fn describe(&self) -> String { match *self { UseSpans::ClosureUse { is_generator, .. } => if is_generator { " in generator".to_string() @@ -2449,7 +547,7 @@ impl UseSpans { } } -impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Finds the spans associated to a move or copy of move_place at location. pub(super) fn move_spans( &self, @@ -2458,9 +556,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ) -> UseSpans { use self::UseSpans::*; - let stmt = match self.mir[location.block].statements.get(location.statement_index) { + let stmt = match self.body[location.block].statements.get(location.statement_index) { Some(stmt) => stmt, - None => return OtherUse(self.mir.source_info(location).span), + None => return OtherUse(self.body.source_info(location).span), }; debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt); @@ -2498,7 +596,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { use self::UseSpans::*; debug!("borrow_spans: use_span={:?} location={:?}", use_span, location); - let target = match self.mir[location.block] + let target = match self.body[location.block] .statements .get(location.statement_index) { @@ -2509,12 +607,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { _ => return OtherUse(use_span), }; - if self.mir.local_kind(target) != LocalKind::Temp { + if self.body.local_kind(target) != LocalKind::Temp { // operands are always temporaries. return OtherUse(use_span); } - for stmt in &self.mir[location.block].statements[location.statement_index + 1..] { + for stmt in &self.body[location.block].statements[location.statement_index + 1..] { if let StatementKind::Assign( _, box Rvalue::Aggregate(ref kind, ref places) ) = stmt.kind { @@ -2529,7 +627,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { def_id, is_generator, places ); if let Some((args_span, var_span)) = self.closure_span( - *def_id, &Place::Base(PlaceBase::Local(target)), places + *def_id, &Place::from(target), places ) { return ClosureUse { is_generator, @@ -2560,40 +658,31 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { "closure_span: def_id={:?} target_place={:?} places={:?}", def_id, target_place, places ); - let node_id = self.infcx.tcx.hir().as_local_node_id(def_id)?; - let expr = &self.infcx.tcx.hir().expect_expr(node_id).node; - debug!("closure_span: node_id={:?} expr={:?}", node_id, expr); + let hir_id = self.infcx.tcx.hir().as_local_hir_id(def_id)?; + let expr = &self.infcx.tcx.hir().expect_expr(hir_id).node; + debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); if let hir::ExprKind::Closure( .., args_span, _ ) = expr { - let var_span = self.infcx.tcx.with_freevars( - node_id, - |freevars| { - for (v, place) in freevars.iter().zip(places) { - match place { - Operand::Copy(place) | - Operand::Move(place) if target_place == place => { - debug!("closure_span: found captured local {:?}", place); - return Some(v.span); - }, - _ => {} - } - } - - None - }, - )?; + for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) { + match place { + Operand::Copy(place) | + Operand::Move(place) if target_place == place => { + debug!("closure_span: found captured local {:?}", place); + return Some((*args_span, upvar.span)); + }, + _ => {} + } + } - Some((*args_span, var_span)) - } else { - None } + None } /// Helper to retrieve span(s) of given borrow from the current MIR /// representation pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans { - let span = self.mir.source_info(borrow.reserve_location).span; + let span = self.body.source_info(borrow.reserve_location).span; self.borrow_spans(span, borrow.reserve_location) } } diff --git a/src/librustc_mir/borrow_check/flows.rs b/src/librustc_mir/borrow_check/flows.rs index 8de39f0efc1a5..9a9310fbe05f5 100644 --- a/src/librustc_mir/borrow_check/flows.rs +++ b/src/librustc_mir/borrow_check/flows.rs @@ -11,7 +11,7 @@ use crate::borrow_check::location::LocationIndex; use polonius_engine::Output; -use crate::dataflow::move_paths::indexes::BorrowIndex; +use crate::dataflow::indexes::BorrowIndex; use crate::dataflow::move_paths::HasMoveData; use crate::dataflow::Borrows; use crate::dataflow::EverInitializedPlaces; @@ -22,20 +22,20 @@ use std::fmt; use std::rc::Rc; // (forced to be `pub` due to its use as an associated type below.) -crate struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> { - borrows: FlowAtLocation<'tcx, Borrows<'b, 'gcx, 'tcx>>, - pub uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>, - pub ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'gcx, 'tcx>>, +crate struct Flows<'b, 'tcx> { + borrows: FlowAtLocation<'tcx, Borrows<'b, 'tcx>>, + pub uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'tcx>>, + pub ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'tcx>>, /// Polonius Output pub polonius_output: Option>>, } -impl<'b, 'gcx, 'tcx> Flows<'b, 'gcx, 'tcx> { +impl<'b, 'tcx> Flows<'b, 'tcx> { crate fn new( - borrows: FlowAtLocation<'tcx, Borrows<'b, 'gcx, 'tcx>>, - uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>, - ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'gcx, 'tcx>>, + borrows: FlowAtLocation<'tcx, Borrows<'b, 'tcx>>, + uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'tcx>>, + ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'tcx>>, polonius_output: Option>>, ) -> Self { Flows { @@ -70,7 +70,7 @@ macro_rules! each_flow { }; } -impl<'b, 'gcx, 'tcx> FlowsAtLocation for Flows<'b, 'gcx, 'tcx> { +impl<'b, 'tcx> FlowsAtLocation for Flows<'b, 'tcx> { fn reset_to_entry_of(&mut self, bb: BasicBlock) { each_flow!(self, reset_to_entry_of(bb)); } @@ -92,7 +92,7 @@ impl<'b, 'gcx, 'tcx> FlowsAtLocation for Flows<'b, 'gcx, 'tcx> { } } -impl<'b, 'gcx, 'tcx> fmt::Display for Flows<'b, 'gcx, 'tcx> { +impl<'b, 'tcx> fmt::Display for Flows<'b, 'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut s = String::new(); diff --git a/src/librustc_mir/borrow_check/location.rs b/src/librustc_mir/borrow_check/location.rs index 20a477576c95c..cc44dc3f5d46b 100644 --- a/src/librustc_mir/borrow_check/location.rs +++ b/src/librustc_mir/borrow_check/location.rs @@ -1,4 +1,4 @@ -use rustc::mir::{BasicBlock, Location, Mir}; +use rustc::mir::{BasicBlock, Location, Body}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; /// Maps between a MIR Location, which identifies a particular @@ -30,9 +30,9 @@ crate enum RichLocation { } impl LocationTable { - crate fn new(mir: &Mir<'_>) -> Self { + crate fn new(body: &Body<'_>) -> Self { let mut num_points = 0; - let statements_before_block = mir.basic_blocks() + let statements_before_block = body.basic_blocks() .iter() .map(|block_data| { let v = num_points; diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 715ee856a7a62..4872440f5bd4a 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1,14 +1,19 @@ //! This query borrow-checks the MIR to (further) ensure it is not broken. use crate::borrow_check::nll::region_infer::RegionInferenceContext; -use rustc::hir; +use rustc::hir::{self, HirId}; use rustc::hir::Node; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; use rustc::lint::builtin::UNUSED_MUT; +use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT}; use rustc::middle::borrowck::SignalledError; use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; -use rustc::mir::{ClearCrossCrate, Local, Location, Mir, Mutability, Operand, Place, PlaceBase}; +use rustc::mir::{ + ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, Static, + + StaticKind +}; use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind}; use rustc::ty::query::Providers; @@ -16,17 +21,19 @@ use rustc::ty::{self, TyCtxt}; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level}; use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; use smallvec::SmallVec; -use std::rc::Rc; use std::collections::BTreeMap; +use std::mem; +use std::rc::Rc; -use syntax_pos::Span; +use syntax::ast::Name; +use syntax_pos::{Span, DUMMY_SP}; use crate::dataflow::indexes::{BorrowIndex, InitIndex, MoveOutIndex, MovePathIndex}; -use crate::dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MoveError}; +use crate::dataflow::move_paths::{HasMoveData, InitLocation, LookupResult, MoveData, MoveError}; use crate::dataflow::Borrows; use crate::dataflow::DataflowResultsConsumer; use crate::dataflow::FlowAtLocation; @@ -49,6 +56,7 @@ crate mod borrow_set; mod error_reporting; mod flows; mod location; +mod conflict_errors; mod move_errors; mod mutability_errors; mod path_utils; @@ -59,6 +67,19 @@ mod used_muts; pub(crate) mod nll; +// FIXME(eddyb) perhaps move this somewhere more centrally. +#[derive(Debug)] +crate struct Upvar { + name: Name, + + var_hir_id: HirId, + + /// If true, the capture is behind a reference. + by_ref: bool, + + mutability: Mutability, +} + pub fn provide(providers: &mut Providers<'_>) { *providers = Providers { mir_borrowck, @@ -66,61 +87,24 @@ pub fn provide(providers: &mut Providers<'_>) { }; } -fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> BorrowCheckResult<'tcx> { - let input_mir = tcx.mir_validated(def_id); - debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id)); - - let mut return_early; - - // Return early if we are not supposed to use MIR borrow checker for this function. - return_early = !tcx.has_attr(def_id, "rustc_mir") && !tcx.use_mir_borrowck(); - - if tcx.is_struct_constructor(def_id) { - // We are not borrow checking the automatically generated struct constructors - // because we want to accept structs such as this (taken from the `linked-hash-map` - // crate): - // ```rust - // struct Qey(Q); - // ``` - // MIR of this struct constructor looks something like this: - // ```rust - // fn Qey(_1: Q) -> Qey{ - // let mut _0: Qey; // return place - // - // bb0: { - // (_0.0: Q) = move _1; // bb0[0]: scope 0 at src/main.rs:1:1: 1:26 - // return; // bb0[1]: scope 0 at src/main.rs:1:1: 1:26 - // } - // } - // ``` - // The problem here is that `(_0.0: Q) = move _1;` is valid only if `Q` is - // of statically known size, which is not known to be true because of the - // `Q: ?Sized` constraint. However, it is true because the constructor can be - // called only when `Q` is of statically known size. - return_early = true; - } - - if return_early { - return BorrowCheckResult { - closure_requirements: None, - used_mut_upvars: SmallVec::new(), - }; - } +fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BorrowCheckResult<'tcx> { + let input_body = tcx.mir_validated(def_id); + debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id)); let opt_closure_req = tcx.infer_ctxt().enter(|infcx| { - let input_mir: &Mir<'_> = &input_mir.borrow(); - do_mir_borrowck(&infcx, input_mir, def_id) + let input_body: &Body<'_> = &input_body.borrow(); + do_mir_borrowck(&infcx, input_body, def_id) }); debug!("mir_borrowck done"); opt_closure_req } -fn do_mir_borrowck<'a, 'gcx, 'tcx>( - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - input_mir: &Mir<'gcx>, +fn do_mir_borrowck<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + input_body: &Body<'tcx>, def_id: DefId, -) -> BorrowCheckResult<'gcx> { +) -> BorrowCheckResult<'tcx> { debug!("do_mir_borrowck(def_id = {:?})", def_id); let tcx = infcx.tcx; @@ -128,21 +112,50 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( let param_env = tcx.param_env(def_id); let id = tcx .hir() - .as_local_node_id(def_id) + .as_local_hir_id(def_id) .expect("do_mir_borrowck: non-local DefId"); + // Gather the upvars of a closure, if any. + let tables = tcx.typeck_tables_of(def_id); + let upvars: Vec<_> = tables + .upvar_list + .get(&def_id) + .into_iter() + .flat_map(|v| v.values()) + .map(|upvar_id| { + let var_hir_id = upvar_id.var_path.hir_id; + let capture = tables.upvar_capture(*upvar_id); + let by_ref = match capture { + ty::UpvarCapture::ByValue => false, + ty::UpvarCapture::ByRef(..) => true, + }; + let mut upvar = Upvar { + name: tcx.hir().name(var_hir_id), + var_hir_id, + by_ref, + mutability: Mutability::Not, + }; + let bm = *tables.pat_binding_modes().get(var_hir_id) + .expect("missing binding mode"); + if bm == ty::BindByValue(hir::MutMutable) { + upvar.mutability = Mutability::Mut; + } + upvar + }) + .collect(); + // Replace all regions with fresh inference variables. This // requires first making our own copy of the MIR. This copy will // be modified (in place) to contain non-lexical lifetimes. It // will have a lifetime tied to the inference context. - let mut mir: Mir<'tcx> = input_mir.clone(); - let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut mir); - let mir = &mir; // no further changes - let location_table = &LocationTable::new(mir); + let mut body: Body<'tcx> = input_body.clone(); + let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body); + let body = &body; // no further changes + let location_table = &LocationTable::new(body); let mut errors_buffer = Vec::new(); let (move_data, move_errors): (MoveData<'tcx>, Option, MoveError<'tcx>)>>) = - match MoveData::gather_moves(mir, tcx) { + match MoveData::gather_moves(body, tcx) { Ok(move_data) => (move_data, None), Err((move_data, move_errors)) => (move_data, Some(move_errors)), }; @@ -152,27 +165,28 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( param_env: param_env, }; - let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len()); + let dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); let mut flow_inits = FlowAtLocation::new(do_dataflow( tcx, - mir, - id, + body, + def_id, &attributes, &dead_unwinds, - MaybeInitializedPlaces::new(tcx, mir, &mdpe), + MaybeInitializedPlaces::new(tcx, body, &mdpe), |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]), )); let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(id).is_fn_or_closure(); let borrow_set = Rc::new(BorrowSet::build( - tcx, mir, locals_are_invalidated_at_exit, &mdpe.move_data)); + tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data)); // If we are in non-lexical mode, compute the non-lexical lifetimes. let (regioncx, polonius_output, opt_closure_req) = nll::compute_regions( infcx, def_id, free_regions, - mir, + body, + &upvars, location_table, param_env, &mut flow_inits, @@ -190,29 +204,29 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( let flow_borrows = FlowAtLocation::new(do_dataflow( tcx, - mir, - id, + body, + def_id, &attributes, &dead_unwinds, - Borrows::new(tcx, mir, regioncx.clone(), &borrow_set), + Borrows::new(tcx, body, regioncx.clone(), &borrow_set), |rs, i| DebugFormatted::new(&rs.location(i)), )); let flow_uninits = FlowAtLocation::new(do_dataflow( tcx, - mir, - id, + body, + def_id, &attributes, &dead_unwinds, - MaybeUninitializedPlaces::new(tcx, mir, &mdpe), + MaybeUninitializedPlaces::new(tcx, body, &mdpe), |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]), )); let flow_ever_inits = FlowAtLocation::new(do_dataflow( tcx, - mir, - id, + body, + def_id, &attributes, &dead_unwinds, - EverInitializedPlaces::new(tcx, mir, &mdpe), + EverInitializedPlaces::new(tcx, body, &mdpe), |bd, i| DebugFormatted::new(&bd.move_data().inits[i]), )); @@ -224,11 +238,11 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( _ => true, }; - let dominators = mir.dominators(); + let dominators = body.dominators(); let mut mbcx = MirBorrowckCtxt { infcx, - mir, + body, mir_def_id: def_id, move_data: &mdpe.move_data, location_table, @@ -236,6 +250,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( locals_are_invalidated_at_exit, access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), + reservation_warnings: Default::default(), move_error_reported: BTreeMap::new(), uninitialized_error_reported: Default::default(), errors_buffer, @@ -244,6 +259,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( used_mut_upvars: SmallVec::new(), borrow_set, dominators, + upvars, }; let mut state = Flows::new( @@ -258,28 +274,52 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( } mbcx.analyze_results(&mut state); // entry point for DataflowResultsConsumer + // Convert any reservation warnings into lints. + let reservation_warnings = mem::replace(&mut mbcx.reservation_warnings, Default::default()); + for (_, (place, span, location, bk, borrow)) in reservation_warnings { + let mut initial_diag = + mbcx.report_conflicting_borrow(location, (&place, span), bk, &borrow); + + let lint_root = if let ClearCrossCrate::Set(ref vsi) = mbcx.body.source_scope_local_data { + let scope = mbcx.body.source_info(location).scope; + vsi[scope].lint_root + } else { + id + }; + + // Span and message don't matter; we overwrite them below anyway + let mut diag = mbcx.infcx.tcx.struct_span_lint_hir( + MUTABLE_BORROW_RESERVATION_CONFLICT, lint_root, DUMMY_SP, ""); + + diag.message = initial_diag.styled_message().clone(); + diag.span = initial_diag.span.clone(); + + initial_diag.cancel(); + diag.buffer(&mut mbcx.errors_buffer); + } + // For each non-user used mutable variable, check if it's been assigned from // a user-declared local. If so, then put that local into the used_mut set. // Note that this set is expected to be small - only upvars from closures // would have a chance of erroneously adding non-user-defined mutable vars // to the set. let temporary_used_locals: FxHashSet = mbcx.used_mut.iter() - .filter(|&local| mbcx.mir.local_decls[*local].is_user_variable.is_none()) + .filter(|&local| mbcx.body.local_decls[*local].is_user_variable.is_none()) .cloned() .collect(); // For the remaining unused locals that are marked as mutable, we avoid linting any that // were never initialized. These locals may have been removed as unreachable code; or will be // linted as unused variables. - let unused_mut_locals = mbcx.mir.mut_vars_iter() + let unused_mut_locals = mbcx.body.mut_vars_iter() .filter(|local| !mbcx.used_mut.contains(local)) .collect(); mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals); debug!("mbcx.used_mut: {:?}", mbcx.used_mut); let used_mut = mbcx.used_mut; - for local in mbcx.mir.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) { - if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data { - let local_decl = &mbcx.mir.local_decls[local]; + for local in mbcx.body.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) { + if let ClearCrossCrate::Set(ref vsi) = mbcx.body.source_scope_local_data { + let local_decl = &mbcx.body.local_decls[local]; // Skip implicit `self` argument for closures if local.index() == 1 && tcx.is_closure(mbcx.mir_def_id) { @@ -329,46 +369,19 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( // When borrowck=migrate, check if AST-borrowck would // error on the given code. - // rust-lang/rust#55492: loop over parents to ensure that - // errors that AST-borrowck only detects in some parent of - // a closure still allows NLL to signal an error. - let mut curr_def_id = def_id; - let signalled_any_error = loop { - match tcx.borrowck(curr_def_id).signalled_any_error { - SignalledError::NoErrorsSeen => { - // keep traversing (and borrow-checking) parents - } - SignalledError::SawSomeError => { - // stop search here - break SignalledError::SawSomeError; - } - } - - if tcx.is_closure(curr_def_id) { - curr_def_id = tcx.parent_def_id(curr_def_id) - .expect("a closure must have a parent_def_id"); - } else { - break SignalledError::NoErrorsSeen; - } - }; + // rust-lang/rust#55492, rust-lang/rust#58776 check the base def id + // for errors. AST borrowck is responsible for aggregating + // `signalled_any_error` from all of the nested closures here. + let base_def_id = tcx.closure_base_def_id(def_id); - match signalled_any_error { + match tcx.borrowck(base_def_id).signalled_any_error { SignalledError::NoErrorsSeen => { // if AST-borrowck signalled no errors, then // downgrade all the buffered MIR-borrowck errors // to warnings. - for err in &mut mbcx.errors_buffer { - if err.is_error() { - err.level = Level::Warning; - err.warn( - "this error has been downgraded to a warning for backwards \ - compatibility with previous releases", - ); - err.warn( - "this represents potential undefined behavior in your code and \ - this warning will become a hard error in the future", - ); - } + + for err in mbcx.errors_buffer.iter_mut() { + downgrade_if_error(err); } } SignalledError::SawSomeError => { @@ -394,9 +407,24 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( result } -pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { - infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, - mir: &'cx Mir<'tcx>, +fn downgrade_if_error(diag: &mut Diagnostic) { + if diag.is_error() { + diag.level = Level::Warning; + diag.warn( + "this error has been downgraded to a warning for backwards \ + compatibility with previous releases", + ).warn( + "this represents potential undefined behavior in your code and \ + this warning will become a hard error in the future", + ).note( + "for more information, try `rustc --explain E0729`" + ); + } +} + +pub struct MirBorrowckCtxt<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + body: &'cx Body<'tcx>, mir_def_id: DefId, move_data: &'cx MoveData<'tcx>, @@ -426,6 +454,13 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { // but it is currently inconvenient to track down the `BorrowIndex` // at the time we detect and report a reservation error. reservation_error_reported: FxHashSet>, + /// Migration warnings to be reported for #56254. We delay reporting these + /// so that we can suppress the warning if there's a corresponding error + /// for the activation of the borrow. + reservation_warnings: FxHashMap< + BorrowIndex, + (Place<'tcx>, Span, Location, BorrowKind, BorrowData<'tcx>) + >, /// This field keeps track of move errors that are to be reported for given move indicies. /// /// There are situations where many errors can be reported for a single move out (see #53807) @@ -462,6 +497,9 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { /// Dominators for MIR dominators: Dominators, + + /// Information about upvars not necessarily preserved in types or MIR + upvars: Vec, } // Check that: @@ -469,11 +507,11 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { // 2. loans made in overlapping scopes do not conflict // 3. assignments do not affect things loaned out as immutable // 4. moves do not affect things loaned out in any way -impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'gcx, 'tcx> { - type FlowState = Flows<'cx, 'gcx, 'tcx>; +impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> { + type FlowState = Flows<'cx, 'tcx>; - fn mir(&self) -> &'cx Mir<'tcx> { - self.mir + fn body(&self) -> &'cx Body<'tcx> { + self.body } fn visit_block_entry(&mut self, bb: BasicBlock, flow_state: &Self::FlowState) { @@ -497,14 +535,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx match stmt.kind { StatementKind::Assign(ref lhs, ref rhs) => { self.consume_rvalue( - ContextKind::AssignRhs.new(location), - (rhs, span), location, + (rhs, span), flow_state, ); self.mutate_place( - ContextKind::AssignLhs.new(location), + location, (lhs, span), Shallow(None), JustWrite, @@ -523,7 +560,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx // match x {}; // from compiling. self.check_if_path_or_subpath_is_moved( - ContextKind::FakeRead.new(location), + location, InitializationRequiringAction::Use, (place, span), flow_state, @@ -534,39 +571,34 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx variant_index: _, } => { self.mutate_place( - ContextKind::SetDiscrim.new(location), + location, (place, span), Shallow(None), JustWrite, flow_state, ); } - StatementKind::InlineAsm { - ref asm, - ref outputs, - ref inputs, - } => { - let context = ContextKind::InlineAsm.new(location); - for (o, output) in asm.outputs.iter().zip(outputs.iter()) { + StatementKind::InlineAsm(ref asm) => { + for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) { if o.is_indirect { // FIXME(eddyb) indirect inline asm outputs should - // be encoeded through MIR place derefs instead. + // be encoded through MIR place derefs instead. self.access_place( - context, + location, (output, o.span), (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, flow_state, ); self.check_if_path_or_subpath_is_moved( - context, + location, InitializationRequiringAction::Use, (output, o.span), flow_state, ); } else { self.mutate_place( - context, + location, (output, o.span), if o.is_rw { Deep } else { Shallow(None) }, if o.is_rw { WriteAndRead } else { JustWrite }, @@ -574,8 +606,8 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx ); } } - for (_, input) in inputs.iter() { - self.consume_operand(context, (input, span), flow_state); + for (_, input) in asm.inputs.iter() { + self.consume_operand(location, (input, span), flow_state); } } StatementKind::Nop @@ -587,8 +619,8 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx } StatementKind::StorageDead(local) => { self.access_place( - ContextKind::StorageDead.new(location), - (&Place::Base(PlaceBase::Local(local)), span), + location, + (&Place::from(local), span), (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, flow_state, @@ -619,7 +651,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx values: _, targets: _, } => { - self.consume_operand(ContextKind::SwitchInt.new(loc), (discr, span), flow_state); + self.consume_operand(loc, (discr, span), flow_state); } TerminatorKind::Drop { location: ref drop_place, @@ -629,23 +661,22 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx let gcx = self.infcx.tcx.global_tcx(); // Compute the type with accurate region information. - let drop_place_ty = drop_place.ty(self.mir, self.infcx.tcx); + let drop_place_ty = drop_place.ty(self.body, self.infcx.tcx); // Erase the regions. - let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty) - .to_ty(self.infcx.tcx); + let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty).ty; // "Lift" into the gcx -- once regions are erased, this type should be in the // global arenas; this "lift" operation basically just asserts that is true, but // that is useful later. - let drop_place_ty = gcx.lift(&drop_place_ty).unwrap(); + gcx.lift_to_global(&drop_place_ty).unwrap(); debug!("visit_terminator_drop \ loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}", loc, term, drop_place, drop_place_ty, span); self.access_place( - ContextKind::Drop.new(loc), + loc, (drop_place, span), (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, @@ -659,14 +690,14 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx unwind: _, } => { self.mutate_place( - ContextKind::DropAndReplace.new(loc), + loc, (drop_place, span), Deep, JustWrite, flow_state, ); self.consume_operand( - ContextKind::DropAndReplace.new(loc), + loc, (new_value, span), flow_state, ); @@ -678,17 +709,17 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx cleanup: _, from_hir_call: _, } => { - self.consume_operand(ContextKind::CallOperator.new(loc), (func, span), flow_state); + self.consume_operand(loc, (func, span), flow_state); for arg in args { self.consume_operand( - ContextKind::CallOperand.new(loc), + loc, (arg, span), flow_state, ); } if let Some((ref dest, _ /*bb*/)) = *destination { self.mutate_place( - ContextKind::CallDest.new(loc), + loc, (dest, span), Deep, JustWrite, @@ -703,11 +734,11 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx target: _, cleanup: _, } => { - self.consume_operand(ContextKind::Assert.new(loc), (cond, span), flow_state); - use rustc::mir::interpret::EvalErrorKind::BoundsCheck; + self.consume_operand(loc, (cond, span), flow_state); + use rustc::mir::interpret::InterpError::BoundsCheck; if let BoundsCheck { ref len, ref index } = *msg { - self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state); - self.consume_operand(ContextKind::Assert.new(loc), (index, span), flow_state); + self.consume_operand(loc, (len, span), flow_state); + self.consume_operand(loc, (index, span), flow_state); } } @@ -716,7 +747,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx resume: _, drop: _, } => { - self.consume_operand(ContextKind::Yield.new(loc), (value, span), flow_state); + self.consume_operand(loc, (value, span), flow_state); if self.movable_generator { // Look for any active borrows to locals @@ -739,8 +770,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx flow_state.with_outgoing_borrows(|borrows| { for i in borrows { let borrow = &borrow_set[i]; - let context = ContextKind::StorageDead.new(loc); - self.check_for_invalidation_at_exit(context, borrow, span); + self.check_for_invalidation_at_exit(loc, borrow, span); } }); } @@ -749,7 +779,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx | TerminatorKind::Unreachable | TerminatorKind::FalseEdges { real_target: _, - imaginary_targets: _, + imaginary_target: _, } | TerminatorKind::FalseUnwind { real_target: _, @@ -860,7 +890,7 @@ enum InitializationRequiringAction { PartialAssignment, } -struct RootPlace<'d, 'tcx: 'd> { +struct RootPlace<'d, 'tcx> { place: &'d Place<'tcx>, is_local_mutation_allowed: LocalMutationIsAllowed, } @@ -889,7 +919,7 @@ impl InitializationRequiringAction { } } -impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Checks an access to the given place to see if it is allowed. Examines the set of borrows /// that are in scope, as well as which paths have been initialized, to ensure that (a) the /// place is initialized and (b) it is not borrowed in some way that would prevent this @@ -898,11 +928,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// Returns `true` if an error is reported. fn access_place( &mut self, - context: Context, + location: Location, place_span: (&Place<'tcx>, Span), kind: (AccessDepth, ReadOrWrite), is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'cx, 'gcx, 'tcx>, + flow_state: &Flows<'cx, 'tcx>, ) { let (sd, rw) = kind; @@ -937,16 +967,23 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { rw, is_local_mutation_allowed, flow_state, - context.loc, + location, ); let conflict_error = - self.check_access_for_conflict(context, place_span, sd, rw, flow_state); + self.check_access_for_conflict(location, place_span, sd, rw, flow_state); + + if let (Activation(_, borrow_idx), true) = (kind.1, conflict_error) { + // Suppress this warning when there's an error being emited for the + // same borrow: fixing the error is likely to fix the warning. + self.reservation_warnings.remove(&borrow_idx); + } if conflict_error || mutability_error { debug!( "access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind ); + self.access_place_error_reported .insert((place_span.0.clone(), place_span.1)); } @@ -954,30 +991,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn check_access_for_conflict( &mut self, - context: Context, + location: Location, place_span: (&Place<'tcx>, Span), sd: AccessDepth, rw: ReadOrWrite, - flow_state: &Flows<'cx, 'gcx, 'tcx>, + flow_state: &Flows<'cx, 'tcx>, ) -> bool { debug!( - "check_access_for_conflict(context={:?}, place_span={:?}, sd={:?}, rw={:?})", - context, place_span, sd, rw, + "check_access_for_conflict(location={:?}, place_span={:?}, sd={:?}, rw={:?})", + location, place_span, sd, rw, ); let mut error_reported = false; let tcx = self.infcx.tcx; - let mir = self.mir; - let location = self.location_table.start_index(context.loc); + let body = self.body; + let location_table = self.location_table.start_index(location); let borrow_set = self.borrow_set.clone(); each_borrow_involving_path( self, tcx, - mir, - context, + body, + location, (sd, place_span.0), &borrow_set, - flow_state.borrows_in_scope(location), + flow_state.borrows_in_scope(location_table), |this, borrow_index, borrow| match (rw, borrow.kind) { // Obviously an activation is compatible with its own // reservation (or even prior activating uses of same @@ -997,8 +1034,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Control::Continue } - (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) - | (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) + (Read(_), BorrowKind::Shared) + | (Read(_), BorrowKind::Shallow) | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Unique) | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { Control::Continue @@ -1011,29 +1048,54 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { (Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. - if !is_active(&this.dominators, borrow, context.loc) { - assert!(allow_two_phase_borrow(&this.infcx.tcx, borrow.kind)); + if !is_active(&this.dominators, borrow, location) { + assert!(allow_two_phase_borrow(borrow.kind)); return Control::Continue; } error_reported = true; match kind { ReadKind::Copy => { - this.report_use_while_mutably_borrowed(context, place_span, borrow) + this.report_use_while_mutably_borrowed(location, place_span, borrow) + .buffer(&mut this.errors_buffer); } ReadKind::Borrow(bk) => { - this.report_conflicting_borrow(context, place_span, bk, &borrow) + this.report_conflicting_borrow(location, place_span, bk, borrow) + .buffer(&mut this.errors_buffer); } } Control::Break } - (Reservation(kind), BorrowKind::Unique) - | (Reservation(kind), BorrowKind::Mut { .. }) + (Reservation(WriteKind::MutableBorrow(bk)), BorrowKind::Shallow) + | (Reservation(WriteKind::MutableBorrow(bk)), BorrowKind::Shared) if { + tcx.migrate_borrowck() && this.borrow_set.location_map.contains_key(&location) + } => { + let bi = this.borrow_set.location_map[&location]; + debug!( + "recording invalid reservation of place: {:?} with \ + borrow index {:?} as warning", + place_span.0, + bi, + ); + // rust-lang/rust#56254 - This was previously permitted on + // the 2018 edition so we emit it as a warning. We buffer + // these sepately so that we only emit a warning if borrow + // checking was otherwise successful. + this.reservation_warnings.insert( + bi, + (place_span.0.clone(), place_span.1, location, bk, borrow.clone()), + ); + + // Don't suppress actual errors. + Control::Continue + } + + (Reservation(kind), _) | (Activation(kind, _), _) | (Write(kind), _) => { match rw { - Reservation(_) => { + Reservation(..) => { debug!( "recording invalid reservation of \ place: {:?}", @@ -1054,20 +1116,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { error_reported = true; match kind { WriteKind::MutableBorrow(bk) => { - this.report_conflicting_borrow(context, place_span, bk, &borrow) + this.report_conflicting_borrow(location, place_span, bk, borrow) + .buffer(&mut this.errors_buffer); } WriteKind::StorageDeadOrDrop => { this.report_borrowed_value_does_not_live_long_enough( - context, + location, borrow, place_span, Some(kind)) } WriteKind::Mutate => { - this.report_illegal_mutation_of_borrowed(context, place_span, borrow) + this.report_illegal_mutation_of_borrowed(location, place_span, borrow) } WriteKind::Move => { - this.report_move_out_while_borrowed(context, place_span, &borrow) + this.report_move_out_while_borrowed(location, place_span, borrow) } } Control::Break @@ -1080,24 +1143,24 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn mutate_place( &mut self, - context: Context, + location: Location, place_span: (&Place<'tcx>, Span), kind: AccessDepth, mode: MutateMode, - flow_state: &Flows<'cx, 'gcx, 'tcx>, + flow_state: &Flows<'cx, 'tcx>, ) { // Write of P[i] or *P, or WriteAndRead of any P, requires P init'd. match mode { MutateMode::WriteAndRead => { self.check_if_path_or_subpath_is_moved( - context, + location, InitializationRequiringAction::Update, place_span, flow_state, ); } MutateMode::JustWrite => { - self.check_if_assigned_path_is_moved(context, place_span, flow_state); + self.check_if_assigned_path_is_moved(location, place_span, flow_state); } } @@ -1105,10 +1168,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // (e.g., `x = ...`) so long as it has never been initialized // before (at this point in the flow). if let &Place::Base(PlaceBase::Local(local)) = place_span.0 { - if let Mutability::Not = self.mir.local_decls[local].mutability { + if let Mutability::Not = self.body.local_decls[local].mutability { // check for reassignments to immutable local variables self.check_if_reassignment_to_immutable_state( - context, + location, local, place_span, flow_state, @@ -1119,7 +1182,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Otherwise, use the normal access permission rules. self.access_place( - context, + location, place_span, (kind, Write(WriteKind::Mutate)), LocalMutationIsAllowed::No, @@ -1129,10 +1192,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn consume_rvalue( &mut self, - context: Context, + location: Location, (rvalue, span): (&Rvalue<'tcx>, Span), - _location: Location, - flow_state: &Flows<'cx, 'gcx, 'tcx>, + flow_state: &Flows<'cx, 'tcx>, ) { match *rvalue { Rvalue::Ref(_ /*rgn*/, bk, ref place) => { @@ -1143,7 +1205,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), BorrowKind::Unique | BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); - if allow_two_phase_borrow(&self.infcx.tcx, bk) { + if allow_two_phase_borrow(bk) { (Deep, Reservation(wk)) } else { (Deep, Write(wk)) @@ -1152,7 +1214,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { }; self.access_place( - context, + location, (place, span), access_kind, LocalMutationIsAllowed::No, @@ -1166,7 +1228,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { }; self.check_if_path_or_subpath_is_moved( - context, + location, action, (place, span), flow_state, @@ -1177,7 +1239,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | Rvalue::Repeat(ref operand, _) | Rvalue::UnaryOp(_ /*un_op*/, ref operand) | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => { - self.consume_operand(context, (operand, span), flow_state) + self.consume_operand(location, (operand, span), flow_state) } Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => { @@ -1187,14 +1249,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { _ => unreachable!(), }; self.access_place( - context, + location, (place, span), (Shallow(af), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, flow_state, ); self.check_if_path_or_subpath_is_moved( - context, + location, InitializationRequiringAction::Use, (place, span), flow_state, @@ -1203,8 +1265,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2) | Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => { - self.consume_operand(context, (operand1, span), flow_state); - self.consume_operand(context, (operand2, span), flow_state); + self.consume_operand(location, (operand1, span), flow_state); + self.consume_operand(location, (operand2, span), flow_state); } Rvalue::NullaryOp(_op, _ty) => { @@ -1227,27 +1289,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } = self.infcx.tcx.mir_borrowck(def_id); debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars); for field in used_mut_upvars { - // This relies on the current way that by-value - // captures of a closure are copied/moved directly - // when generating MIR. - match operands[field.index()] { - Operand::Move(Place::Base(PlaceBase::Local(local))) - | Operand::Copy(Place::Base(PlaceBase::Local(local))) => { - self.used_mut.insert(local); - } - Operand::Move(ref place @ Place::Projection(_)) - | Operand::Copy(ref place @ Place::Projection(_)) => { - if let Some(field) = place.is_upvar_field_projection( - self.mir, &self.infcx.tcx) { - self.used_mut_upvars.push(field); - } - } - Operand::Move(Place::Base(PlaceBase::Static(..))) - | Operand::Copy(Place::Base(PlaceBase::Static(..))) - | Operand::Move(Place::Base(PlaceBase::Promoted(..))) - | Operand::Copy(Place::Base(PlaceBase::Promoted(..))) - | Operand::Constant(..) => {} - } + self.propagate_closure_used_mut_upvar(&operands[field.index()]); } } AggregateKind::Adt(..) @@ -1256,24 +1298,97 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } for operand in operands { - self.consume_operand(context, (operand, span), flow_state); + self.consume_operand(location, (operand, span), flow_state); } } } } + fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) { + let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| { + match *place { + Place::Projection { .. } => { + if let Some(field) = this.is_upvar_field_projection(place) { + this.used_mut_upvars.push(field); + } + } + Place::Base(PlaceBase::Local(local)) => { + this.used_mut.insert(local); + } + Place::Base(PlaceBase::Static(_)) => {} + } + }; + + // This relies on the current way that by-value + // captures of a closure are copied/moved directly + // when generating MIR. + match *operand { + Operand::Move(Place::Base(PlaceBase::Local(local))) + | Operand::Copy(Place::Base(PlaceBase::Local(local))) + if self.body.local_decls[local].is_user_variable.is_none() => + { + if self.body.local_decls[local].ty.is_mutable_pointer() { + // The variable will be marked as mutable by the borrow. + return; + } + // This is an edge case where we have a `move` closure + // inside a non-move closure, and the inner closure + // contains a mutation: + // + // let mut i = 0; + // || { move || { i += 1; }; }; + // + // In this case our usual strategy of assuming that the + // variable will be captured by mutable reference is + // wrong, since `i` can be copied into the inner + // closure from a shared reference. + // + // As such we have to search for the local that this + // capture comes from and mark it as being used as mut. + + let temp_mpi = self.move_data.rev_lookup.find_local(local); + let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] { + &self.move_data.inits[init_index] + } else { + bug!("temporary should be initialized exactly once") + }; + + let loc = match init.location { + InitLocation::Statement(stmt) => stmt, + _ => bug!("temporary initialized in arguments"), + }; + + let bbd = &self.body[loc.block]; + let stmt = &bbd.statements[loc.statement_index]; + debug!("temporary assigned in: stmt={:?}", stmt); + + if let StatementKind::Assign(_, box Rvalue::Ref(_, _, ref source)) = stmt.kind { + propagate_closure_used_mut_place(self, source); + } else { + bug!("closures should only capture user variables \ + or references to user variables"); + } + } + Operand::Move(ref place) + | Operand::Copy(ref place) => { + propagate_closure_used_mut_place(self, place); + } + Operand::Constant(..) => {} + } + } + fn consume_operand( &mut self, - context: Context, + location: Location, (operand, span): (&Operand<'tcx>, Span), - flow_state: &Flows<'cx, 'gcx, 'tcx>, + flow_state: &Flows<'cx, 'tcx>, ) { match *operand { Operand::Copy(ref place) => { // copy of place: check if this is "copy of frozen path" // (FIXME: see check_loans.rs) self.access_place( - context, + location, (place, span), (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, @@ -1282,7 +1397,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Finally, check if path was already moved. self.check_if_path_or_subpath_is_moved( - context, + location, InitializationRequiringAction::Use, (place, span), flow_state, @@ -1291,7 +1406,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Operand::Move(ref place) => { // move of place: check if this is move of already borrowed path self.access_place( - context, + location, (place, span), (Deep, Write(WriteKind::Move)), LocalMutationIsAllowed::Yes, @@ -1300,7 +1415,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Finally, check if path was already moved. self.check_if_path_or_subpath_is_moved( - context, + location, InitializationRequiringAction::Use, (place, span), flow_state, @@ -1314,7 +1429,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// exits fn check_for_invalidation_at_exit( &mut self, - context: Context, + location: Location, borrow: &BorrowData<'tcx>, span: Span, ) { @@ -1328,12 +1443,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // // FIXME: allow thread-locals to borrow other thread locals? let (might_be_alive, will_be_dropped) = match root_place { - Place::Base(PlaceBase::Promoted(_)) => (true, false), - Place::Base(PlaceBase::Static(_)) => { + Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => { + (true, false) + } + Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(_), .. })) => { // Thread-locals might be dropped after the function exits, but // "true" statics will never be. - let is_thread_local = self.is_place_thread_local(&root_place); - (true, is_thread_local) + (true, self.is_place_thread_local(&root_place)) } Place::Base(PlaceBase::Local(_)) => { // Locals are always dropped at function exit, and if they @@ -1357,7 +1473,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if places_conflict::borrow_conflicts_with_place( self.infcx.tcx, - self.mir, + self.body, place, borrow.kind, root_place, @@ -1369,7 +1485,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // of just a span here. let span = self.infcx.tcx.sess.source_map().end_point(span); self.report_borrowed_value_does_not_live_long_enough( - context, + location, borrow, (place, span), None, @@ -1394,16 +1510,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } - fn check_activations( - &mut self, - location: Location, - span: Span, - flow_state: &Flows<'cx, 'gcx, 'tcx>, - ) { - if !self.infcx.tcx.two_phase_borrows() { - return; - } - + fn check_activations(&mut self, location: Location, span: Span, flow_state: &Flows<'cx, 'tcx>) { // Two-phase borrow support: For each activation that is newly // generated at this statement, check if it interferes with // another borrow. @@ -1418,7 +1525,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { }); self.access_place( - ContextKind::Activation.new(location), + location, (&borrow.borrowed_place, span), ( Deep, @@ -1434,13 +1541,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } -impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn check_if_reassignment_to_immutable_state( &mut self, - context: Context, + location: Location, local: Local, place_span: (&Place<'tcx>, Span), - flow_state: &Flows<'cx, 'gcx, 'tcx>, + flow_state: &Flows<'cx, 'tcx>, ) { debug!("check_if_reassignment_to_immutable_state({:?})", local); @@ -1448,19 +1555,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) { // And, if so, report an error. let init = &self.move_data.inits[init_index]; - let span = init.span(&self.mir); + let span = init.span(&self.body); self.report_illegal_reassignment( - context, place_span, span, place_span.0 + location, place_span, span, place_span.0 ); } } fn check_if_full_path_is_moved( &mut self, - context: Context, + location: Location, desired_action: InitializationRequiringAction, place_span: (&Place<'tcx>, Span), - flow_state: &Flows<'cx, 'gcx, 'tcx>, + flow_state: &Flows<'cx, 'tcx>, ) { let maybe_uninits = &flow_state.uninits; @@ -1504,7 +1611,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Ok((prefix, mpi)) => { if maybe_uninits.contains(mpi) { self.report_use_of_moved_or_uninitialized( - context, + location, desired_action, (prefix, place_span.0, place_span.1), mpi, @@ -1525,10 +1632,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn check_if_path_or_subpath_is_moved( &mut self, - context: Context, + location: Location, desired_action: InitializationRequiringAction, place_span: (&Place<'tcx>, Span), - flow_state: &Flows<'cx, 'gcx, 'tcx>, + flow_state: &Flows<'cx, 'tcx>, ) { let maybe_uninits = &flow_state.uninits; @@ -1547,7 +1654,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // must have been initialized for the use to be sound. // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d` - self.check_if_full_path_is_moved(context, desired_action, place_span, flow_state); + self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state); // A move of any shallow suffix of `place` also interferes // with an attempt to use `place`. This is scenario 3 above. @@ -1562,7 +1669,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if let Some(mpi) = self.move_path_for_place(place_span.0) { if let Some(child_mpi) = maybe_uninits.has_any_child_of(mpi) { self.report_use_of_moved_or_uninitialized( - context, + location, desired_action, (place_span.0, place_span.0, place_span.1), child_mpi, @@ -1596,7 +1703,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { match *last_prefix { Place::Base(PlaceBase::Local(_)) => panic!("should have move path for every Local"), Place::Projection(_) => panic!("PrefixSet::All meant don't stop for Projection"), - Place::Base(PlaceBase::Promoted(_)) | Place::Base(PlaceBase::Static(_)) => Err(NoMovePathFound::ReachedStatic), } } @@ -1614,16 +1720,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn check_if_assigned_path_is_moved( &mut self, - context: Context, + location: Location, (place, span): (&Place<'tcx>, Span), - flow_state: &Flows<'cx, 'gcx, 'tcx>, + flow_state: &Flows<'cx, 'tcx>, ) { debug!("check_if_assigned_path_is_moved place: {:?}", place); // recur down place; dispatch to external checks when necessary let mut place = place; loop { match *place { - Place::Base(PlaceBase::Promoted(_)) | Place::Base(PlaceBase::Local(_)) | Place::Base(PlaceBase::Static(_)) => { // assigning to `x` does not require `x` be initialized. break; @@ -1643,7 +1748,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // assigning to (*P) requires P to be initialized ProjectionElem::Deref => { self.check_if_full_path_is_moved( - context, InitializationRequiringAction::Use, + location, InitializationRequiringAction::Use, (base, span), flow_state); // (base initialized; no need to // recur further) @@ -1651,8 +1756,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } ProjectionElem::Subslice { .. } => { - panic!("we don't allow assignments to subslices, context: {:?}", - context); + panic!("we don't allow assignments to subslices, location: {:?}", + location); } ProjectionElem::Field(..) => { @@ -1660,10 +1765,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // assigning to `P.f` requires `P` itself // be already initialized let tcx = self.infcx.tcx; - match base.ty(self.mir, tcx).to_ty(tcx).sty { + match base.ty(self.body, tcx).ty.sty { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( - context, InitializationRequiringAction::Assignment, + location, InitializationRequiringAction::Assignment, (base, span), flow_state); // (base initialized; no need to @@ -1675,7 +1780,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Once `let s; s.x = V; read(s.x);`, // is allowed, remove this match arm. ty::Adt(..) | ty::Tuple(..) => { - check_parent_of_field(self, context, base, span, flow_state); + check_parent_of_field(self, location, base, span, flow_state); if let Some(local) = place.base_local() { // rust-lang/rust#21232, @@ -1696,17 +1801,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } place = base; - continue; } } } - fn check_parent_of_field<'cx, 'gcx, 'tcx>( - this: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>, - context: Context, + fn check_parent_of_field<'cx, 'tcx>( + this: &mut MirBorrowckCtxt<'cx, 'tcx>, + location: Location, base: &Place<'tcx>, span: Span, - flow_state: &Flows<'cx, 'gcx, 'tcx>, + flow_state: &Flows<'cx, 'tcx>, ) { // rust-lang/rust#21232: Until Rust allows reads from the // initialized parts of partially initialized structs, we @@ -1765,11 +1869,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // no move out from an earlier location) then this is an attempt at initialization // of the union - we should error in that case. let tcx = this.infcx.tcx; - if let ty::TyKind::Adt(def, _) = base.ty(this.mir, tcx).to_ty(tcx).sty { + if let ty::Adt(def, _) = base.ty(this.body, tcx).ty.sty { if def.is_union() { if this.move_data.path_map[mpi].iter().any(|moi| { this.move_data.moves[*moi].source.is_predecessor_of( - context.loc, this.mir, + location, this.body, ) }) { return; @@ -1778,7 +1882,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } this.report_use_of_moved_or_uninitialized( - context, + location, InitializationRequiringAction::PartialAssignment, (prefix, base, span), mpi, @@ -1795,7 +1899,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { (place, span): (&Place<'tcx>, Span), kind: ReadOrWrite, is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'cx, 'gcx, 'tcx>, + flow_state: &Flows<'cx, 'tcx>, location: Location, ) -> bool { debug!( @@ -1924,11 +2028,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { }; } - fn is_local_ever_initialized(&self, - local: Local, - flow_state: &Flows<'cx, 'gcx, 'tcx>) - -> Option - { + fn is_local_ever_initialized( + &self, + local: Local, + flow_state: &Flows<'cx, 'tcx>, + ) -> Option { let mpi = self.move_data.rev_lookup.find_local(local); let ii = &self.move_data.init_path_map[mpi]; for &index in ii { @@ -1940,11 +2044,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } /// Adds the place into the used mutable variables set - fn add_used_mut<'d>( - &mut self, - root_place: RootPlace<'d, 'tcx>, - flow_state: &Flows<'cx, 'gcx, 'tcx>, - ) { + fn add_used_mut<'d>(&mut self, root_place: RootPlace<'d, 'tcx>, flow_state: &Flows<'cx, 'tcx>) { match root_place { RootPlace { place: Place::Base(PlaceBase::Local(local)), @@ -1967,14 +2067,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { place: place @ Place::Projection(_), is_local_mutation_allowed: _, } => { - if let Some(field) = place.is_upvar_field_projection(self.mir, &self.infcx.tcx) { + if let Some(field) = self.is_upvar_field_projection(place) { self.used_mut_upvars.push(field); } } - RootPlace { - place: Place::Base(PlaceBase::Promoted(..)), - is_local_mutation_allowed: _, - } => {} RootPlace { place: Place::Base(PlaceBase::Static(..)), is_local_mutation_allowed: _, @@ -1991,7 +2087,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ) -> Result, &'d Place<'tcx>> { match *place { Place::Base(PlaceBase::Local(local)) => { - let local = &self.mir.local_decls[local]; + let local = &self.body.local_decls[local]; match local.mutability { Mutability::Not => match is_local_mutation_allowed { LocalMutationIsAllowed::Yes => Ok(RootPlace { @@ -2012,12 +2108,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } // The rules for promotion are made by `qualify_consts`, there wouldn't even be a // `Place::Promoted` if the promotion weren't 100% legal. So we just forward this - Place::Base(PlaceBase::Promoted(_)) => Ok(RootPlace { - place, - is_local_mutation_allowed, - }), - Place::Base(PlaceBase::Static(ref static_)) => { - if self.infcx.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) { + Place::Base(PlaceBase::Static(box Static{kind: StaticKind::Promoted(_), ..})) => + Ok(RootPlace { + place, + is_local_mutation_allowed, + }), + Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => { + if !self.infcx.tcx.is_mutable_static(def_id) { Err(place) } else { Ok(RootPlace { @@ -2029,7 +2126,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Place::Projection(ref proj) => { match proj.elem { ProjectionElem::Deref => { - let base_ty = proj.base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let base_ty = proj.base.ty(self.body, self.infcx.tcx).ty; // Check the kind of deref to decide match base_ty.sty { @@ -2040,13 +2137,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Mutably borrowed data is mutable, but only if we have a // unique path to the `&mut` hir::MutMutable => { - let mode = match place.is_upvar_field_projection( - self.mir, &self.infcx.tcx) - { + let mode = match self.is_upvar_field_projection(place) { Some(field) - if { - self.mir.upvar_decls[field.index()].by_ref - } => + if self.upvars[field.index()].by_ref => { is_local_mutation_allowed } @@ -2086,15 +2179,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..) => { - let upvar_field_projection = place.is_upvar_field_projection( - self.mir, &self.infcx.tcx); + let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { - let decl = &self.mir.upvar_decls[field.index()]; + let upvar = &self.upvars[field.index()]; debug!( - "decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}", - decl, is_local_mutation_allowed, place + "upvar.mutability={:?} local_mutation_is_allowed={:?} place={:?}", + upvar, is_local_mutation_allowed, place ); - match (decl.mutability, is_local_mutation_allowed) { + match (upvar.mutability, is_local_mutation_allowed) { (Mutability::Not, LocalMutationIsAllowed::No) | (Mutability::Not, LocalMutationIsAllowed::ExceptUpvars) => { Err(place) @@ -2104,7 +2196,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Subtle: this is an upvar // reference, so it looks like // `self.foo` -- we want to double - // check that the context `*self` + // check that the location `*self` // is mutable (i.e., this is not a // `Fn` closure). But if that // check succeeds, we want to @@ -2142,6 +2234,41 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } } + + /// If `place` is a field projection, and the field is being projected from a closure type, + /// then returns the index of the field being projected. Note that this closure will always + /// be `self` in the current MIR, because that is the only time we directly access the fields + /// of a closure type. + pub fn is_upvar_field_projection(&self, place: &Place<'tcx>) -> Option { + let (place, by_ref) = if let Place::Projection(ref proj) = place { + if let ProjectionElem::Deref = proj.elem { + (&proj.base, true) + } else { + (place, false) + } + } else { + (place, false) + }; + + match place { + Place::Projection(ref proj) => match proj.elem { + ProjectionElem::Field(field, _ty) => { + let tcx = self.infcx.tcx; + let base_ty = proj.base.ty(self.body, tcx).ty; + + if (base_ty.is_closure() || base_ty.is_generator()) && + (!by_ref || self.upvars[field.index()].by_ref) + { + Some(field) + } else { + None + } + }, + _ => None, + } + _ => None, + } + } } #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -2166,37 +2293,3 @@ enum Overlap { /// will also be disjoint. Disjoint, } - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -struct Context { - kind: ContextKind, - loc: Location, -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum ContextKind { - Activation, - AssignLhs, - AssignRhs, - SetDiscrim, - InlineAsm, - SwitchInt, - Drop, - DropAndReplace, - CallOperator, - CallOperand, - CallDest, - Assert, - Yield, - FakeRead, - StorageDead, -} - -impl ContextKind { - fn new(self, loc: Location) -> Context { - Context { - kind: self, - loc, - } - } -} diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index bd4bf67d0b154..d15229367251a 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -1,13 +1,13 @@ use core::unicode::property::Pattern_White_Space; -use std::fmt::{self, Display}; use rustc::mir::*; -use rustc::ty; +use rustc::ty::{self, Ty, TyCtxt}; use rustc_errors::{DiagnosticBuilder,Applicability}; use syntax_pos::Span; use crate::borrow_check::MirBorrowckCtxt; use crate::borrow_check::prefixes::PrefixSet; +use crate::borrow_check::error_reporting::UseSpans; use crate::dataflow::move_paths::{ IllegalMoveOrigin, IllegalMoveOriginKind, InitLocation, LookupResult, MoveError, MovePathIndex, @@ -50,30 +50,76 @@ enum GroupedMoveError<'tcx> { // Everything that isn't from pattern matching. OtherIllegalMove { original_path: Place<'tcx>, - span: Span, + use_spans: UseSpans, kind: IllegalMoveOriginKind<'tcx>, }, } -enum BorrowedContentSource { - Arc, - Rc, +enum BorrowedContentSource<'tcx> { DerefRawPointer, - Other, + DerefMutableRef, + DerefSharedRef, + OverloadedDeref(Ty<'tcx>), + OverloadedIndex(Ty<'tcx>), } -impl Display for BorrowedContentSource { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl BorrowedContentSource<'tcx> { + fn describe_for_unnamed_place(&self) -> String { + match *self { + BorrowedContentSource::DerefRawPointer => format!("a raw pointer"), + BorrowedContentSource::DerefSharedRef => format!("a shared reference"), + BorrowedContentSource::DerefMutableRef => { + format!("a mutable reference") + } + BorrowedContentSource::OverloadedDeref(ty) => { + if ty.is_rc() { + format!("an `Rc`") + } else if ty.is_arc() { + format!("an `Arc`") + } else { + format!("dereference of `{}`", ty) + } + } + BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty), + } + } + + fn describe_for_named_place(&self) -> Option<&'static str> { match *self { - BorrowedContentSource::Arc => write!(f, "an `Arc`"), - BorrowedContentSource::Rc => write!(f, "an `Rc`"), - BorrowedContentSource::DerefRawPointer => write!(f, "dereference of raw pointer"), - BorrowedContentSource::Other => write!(f, "borrowed content"), + BorrowedContentSource::DerefRawPointer => Some("raw pointer"), + BorrowedContentSource::DerefSharedRef => Some("shared reference"), + BorrowedContentSource::DerefMutableRef => Some("mutable reference"), + // Overloaded deref and index operators should be evaluated into a + // temporary. So we don't need a description here. + BorrowedContentSource::OverloadedDeref(_) + | BorrowedContentSource::OverloadedIndex(_) => None + } + } + + fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option { + match func.sty { + ty::FnDef(def_id, substs) => { + let trait_id = tcx.trait_of_item(def_id)?; + + let lang_items = tcx.lang_items(); + if Some(trait_id) == lang_items.deref_trait() + || Some(trait_id) == lang_items.deref_mut_trait() + { + Some(BorrowedContentSource::OverloadedDeref(substs.type_at(0))) + } else if Some(trait_id) == lang_items.index_trait() + || Some(trait_id) == lang_items.index_mut_trait() + { + Some(BorrowedContentSource::OverloadedIndex(substs.type_at(0))) + } else { + None + } + } + _ => None, } } } -impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) { let grouped_errors = self.group_move_errors(move_errors); for error in grouped_errors { @@ -105,7 +151,6 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { MoveError::IllegalMove { cannot_move_out_of: IllegalMoveOrigin { location, kind }, } => { - let stmt_source_info = self.mir.source_info(location); // Note: that the only time we assign a place isn't a temporary // to a user variable is when initializing it. // If that ever stops being the case, then the ever initialized @@ -113,12 +158,12 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { if let Some(StatementKind::Assign( Place::Base(PlaceBase::Local(local)), box Rvalue::Use(Operand::Move(move_from)), - )) = self.mir.basic_blocks()[location.block] + )) = self.body.basic_blocks()[location.block] .statements .get(location.statement_index) .map(|stmt| &stmt.kind) { - let local_decl = &self.mir.local_decls[*local]; + let local_decl = &self.body.local_decls[*local]; // opt_match_place is the // match_span is the span of the expression being matched on // match *x.y { ... } match_place is Some(*x.y) @@ -133,6 +178,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { pat_span: _, }))) = local_decl.is_user_variable { + let stmt_source_info = self.body.source_info(location); self.append_binding_error( grouped_errors, kind, @@ -146,8 +192,10 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { return; } } + + let move_spans = self.move_spans(&original_path, location); grouped_errors.push(GroupedMoveError::OtherIllegalMove { - span: stmt_source_info.span, + use_spans: move_spans, original_path, kind, }); @@ -242,96 +290,40 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { let (mut err, err_span) = { let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind<'_>) = match error { - GroupedMoveError::MovesFromPlace { - span, - ref original_path, - ref kind, - .. - } | - GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } | - GroupedMoveError::OtherIllegalMove { span, ref original_path, ref kind } => { + GroupedMoveError::MovesFromPlace { span, ref original_path, ref kind, .. } | + GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } => { (span, original_path, kind) + } + GroupedMoveError::OtherIllegalMove { + use_spans, + ref original_path, + ref kind + } => { + (use_spans.args_or_use(), original_path, kind) }, }; - let origin = Origin::Mir; debug!("report: original_path={:?} span={:?}, kind={:?} \ original_path.is_upvar_field_projection={:?}", original_path, span, kind, - original_path.is_upvar_field_projection(self.mir, &self.infcx.tcx)); + self.is_upvar_field_projection(original_path)); ( match kind { IllegalMoveOriginKind::Static => { - self.infcx.tcx.cannot_move_out_of(span, "static item", origin) + self.report_cannot_move_from_static(original_path, span) } - IllegalMoveOriginKind::BorrowedContent { target_place: place } => { - // Inspect the type of the content behind the - // borrow to provide feedback about why this - // was a move rather than a copy. - let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); - let is_upvar_field_projection = - self.prefixes(&original_path, PrefixSet::All) - .any(|p| p.is_upvar_field_projection(self.mir, &self.infcx.tcx) - .is_some()); - debug!("report: ty={:?}", ty); - match ty.sty { - ty::Array(..) | ty::Slice(..) => - self.infcx.tcx.cannot_move_out_of_interior_noncopy( - span, ty, None, origin - ), - ty::Closure(def_id, closure_substs) - if !self.mir.upvar_decls.is_empty() && is_upvar_field_projection - => { - let closure_kind_ty = - closure_substs.closure_kind_ty(def_id, self.infcx.tcx); - let closure_kind = closure_kind_ty.to_opt_closure_kind(); - let place_description = match closure_kind { - Some(ty::ClosureKind::Fn) => { - "captured variable in an `Fn` closure" - } - Some(ty::ClosureKind::FnMut) => { - "captured variable in an `FnMut` closure" - } - Some(ty::ClosureKind::FnOnce) => { - bug!("closure kind does not match first argument type") - } - None => bug!("closure kind not inferred by borrowck"), - }; - debug!("report: closure_kind_ty={:?} closure_kind={:?} \ - place_description={:?}", closure_kind_ty, closure_kind, - place_description); - - let mut diag = self.infcx.tcx.cannot_move_out_of( - span, place_description, origin); - - for prefix in self.prefixes(&original_path, PrefixSet::All) { - if let Some(field) = prefix.is_upvar_field_projection( - self.mir, &self.infcx.tcx) { - let upvar_decl = &self.mir.upvar_decls[field.index()]; - let upvar_hir_id = - upvar_decl.var_hir_id.assert_crate_local(); - let upvar_span = self.infcx.tcx.hir().span_by_hir_id( - upvar_hir_id); - diag.span_label(upvar_span, "captured outer variable"); - break; - } - } - - diag - } - _ => { - let source = self.borrowed_content_source(place); - self.infcx.tcx.cannot_move_out_of( - span, &source.to_string(), origin - ) - }, - } + IllegalMoveOriginKind::BorrowedContent { target_place } => { + self.report_cannot_move_from_borrowed_content( + original_path, + target_place, + span, + ) } IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { self.infcx.tcx - .cannot_move_out_of_interior_of_drop(span, ty, origin) + .cannot_move_out_of_interior_of_drop(span, ty, Origin::Mir) } IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => self.infcx.tcx.cannot_move_out_of_interior_noncopy( - span, ty, Some(*is_index), origin + span, ty, Some(*is_index), Origin::Mir ), }, span, @@ -342,6 +334,162 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { err.buffer(&mut self.errors_buffer); } + fn report_cannot_move_from_static( + &mut self, + place: &Place<'tcx>, + span: Span + ) -> DiagnosticBuilder<'a> { + let mut base_static = place; + loop { + match base_static { + Place::Base(_) => break, + Place::Projection(box Projection { base, .. }) => base_static = base, + } + } + + let description = if let Place::Base(_) = place { + format!("static item `{}`", self.describe_place(place).unwrap()) + } else { + format!( + "`{:?}` as `{:?}` is a static item", + self.describe_place(place).unwrap(), + self.describe_place(base_static).unwrap(), + ) + }; + + self.infcx.tcx.cannot_move_out_of(span, &description, Origin::Mir) + } + + fn report_cannot_move_from_borrowed_content( + &mut self, + move_place: &Place<'tcx>, + deref_target_place: &Place<'tcx>, + span: Span, + ) -> DiagnosticBuilder<'a> { + let origin = Origin::Mir; + + // Inspect the type of the content behind the + // borrow to provide feedback about why this + // was a move rather than a copy. + let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty; + let upvar_field = self.prefixes(&move_place, PrefixSet::All) + .find_map(|p| self.is_upvar_field_projection(p)); + + let deref_base = match deref_target_place { + Place::Projection(box Projection { base, elem: ProjectionElem::Deref }) => base, + _ => bug!("deref_target_place is not a deref projection"), + }; + + if let Place::Base(PlaceBase::Local(local)) = *deref_base { + let decl = &self.body.local_decls[local]; + if decl.is_ref_for_guard() { + let mut err = self.infcx.tcx.cannot_move_out_of( + span, + &format!("`{}` in pattern guard", decl.name.unwrap()), + origin, + ); + err.note( + "variables bound in patterns cannot be moved from \ + until after the end of the pattern guard"); + return err; + } + } + + debug!("report: ty={:?}", ty); + let mut err = match ty.sty { + ty::Array(..) | ty::Slice(..) => + self.infcx.tcx.cannot_move_out_of_interior_noncopy( + span, ty, None, origin + ), + ty::Closure(def_id, closure_substs) + if def_id == self.mir_def_id && upvar_field.is_some() + => { + let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.infcx.tcx); + let closure_kind = closure_kind_ty.to_opt_closure_kind(); + let capture_description = match closure_kind { + Some(ty::ClosureKind::Fn) => { + "captured variable in an `Fn` closure" + } + Some(ty::ClosureKind::FnMut) => { + "captured variable in an `FnMut` closure" + } + Some(ty::ClosureKind::FnOnce) => { + bug!("closure kind does not match first argument type") + } + None => bug!("closure kind not inferred by borrowck"), + }; + + let upvar = &self.upvars[upvar_field.unwrap().index()]; + let upvar_hir_id = upvar.var_hir_id; + let upvar_name = upvar.name; + let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id); + + let place_name = self.describe_place(move_place).unwrap(); + + let place_description = if self.is_upvar_field_projection(move_place).is_some() { + format!("`{}`, a {}", place_name, capture_description) + } else { + format!( + "`{}`, as `{}` is a {}", + place_name, + upvar_name, + capture_description, + ) + }; + + debug!( + "report: closure_kind_ty={:?} closure_kind={:?} place_description={:?}", + closure_kind_ty, closure_kind, place_description, + ); + + let mut diag = self.infcx.tcx.cannot_move_out_of(span, &place_description, origin); + + diag.span_label(upvar_span, "captured outer variable"); + + diag + } + _ => { + let source = self.borrowed_content_source(deref_base); + match (self.describe_place(move_place), source.describe_for_named_place()) { + (Some(place_desc), Some(source_desc)) => { + self.infcx.tcx.cannot_move_out_of( + span, + &format!("`{}` which is behind a {}", place_desc, source_desc), + origin, + ) + } + (_, _) => { + self.infcx.tcx.cannot_move_out_of( + span, + &source.describe_for_unnamed_place(), + origin, + ) + } + } + }, + }; + let move_ty = format!( + "{:?}", + move_place.ty(self.body, self.infcx.tcx).ty, + ); + let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap(); + let is_option = move_ty.starts_with("std::option::Option"); + let is_result = move_ty.starts_with("std::result::Result"); + if is_option || is_result { + err.span_suggestion( + span, + &format!("consider borrowing the `{}`'s content", if is_option { + "Option" + } else { + "Result" + }), + format!("{}.as_ref()", snippet), + Applicability::MaybeIncorrect, + ); + } + err + } + fn add_move_hints( &self, error: GroupedMoveError<'tcx>, @@ -355,36 +503,32 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { move_from, .. } => { - let try_remove_deref = match move_from { - Place::Projection(box PlaceProjection { - elem: ProjectionElem::Deref, - .. - }) => true, - _ => false, - }; - if try_remove_deref && snippet.starts_with('*') { - // The snippet doesn't start with `*` in (e.g.) index - // expressions `a[b]`, which roughly desugar to - // `*Index::index(&a, b)` or - // `*IndexMut::index_mut(&mut a, b)`. - err.span_suggestion( - span, - "consider removing the `*`", - snippet[1..].to_owned(), - Applicability::Unspecified, + err.span_suggestion( + span, + "consider borrowing here", + format!("&{}", snippet), + Applicability::Unspecified, + ); + + if binds_to.is_empty() { + let place_ty = move_from.ty(self.body, self.infcx.tcx).ty; + let place_desc = match self.describe_place(&move_from) { + Some(desc) => format!("`{}`", desc), + None => format!("value"), + }; + + self.note_type_does_not_implement_copy( + err, + &place_desc, + place_ty, + Some(span) ); } else { - err.span_suggestion( - span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::Unspecified, - ); - } + binds_to.sort(); + binds_to.dedup(); - binds_to.sort(); - binds_to.dedup(); - self.add_move_error_details(err, &binds_to); + self.add_move_error_details(err, &binds_to); + } } GroupedMoveError::MovesFromValue { mut binds_to, .. } => { binds_to.sort(); @@ -393,7 +537,26 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { self.add_move_error_details(err, &binds_to); } // No binding. Nothing to suggest. - GroupedMoveError::OtherIllegalMove { .. } => (), + GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => { + let span = use_spans.var_or_use(); + let place_ty = original_path.ty(self.body, self.infcx.tcx).ty; + let place_desc = match self.describe_place(original_path) { + Some(desc) => format!("`{}`", desc), + None => format!("value"), + }; + self.note_type_does_not_implement_copy( + err, + &place_desc, + place_ty, + Some(span), + ); + + use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc)); + use_spans.var_span_label( + err, + format!("move occurs due to use{}", use_spans.describe()), + ); + }, } } @@ -404,7 +567,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { ) { let mut suggestions: Vec<(Span, &str, String)> = Vec::new(); for local in binds_to { - let bind_to = &self.mir.local_decls[*local]; + let bind_to = &self.body.local_decls[*local]; if let Some( ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { pat_span, @@ -454,7 +617,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { ) { let mut noncopy_var_spans = Vec::new(); for (j, local) in binds_to.into_iter().enumerate() { - let bind_to = &self.mir.local_decls[*local]; + let bind_to = &self.body.local_decls[*local]; let binding_span = bind_to.source_info.span; if j == 0 { @@ -464,14 +627,11 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { } if binds_to.len() == 1 { - err.span_note( - binding_span, - &format!( - "move occurs because `{}` has type `{}`, \ - which does not implement the `Copy` trait", - bind_to.name.unwrap(), - bind_to.ty - ), + self.note_type_does_not_implement_copy( + err, + &format!("`{}`", bind_to.name.unwrap()), + bind_to.ty, + Some(binding_span) ); } else { noncopy_var_spans.push(binding_span); @@ -487,105 +647,64 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { } } - fn borrowed_content_source(&self, place: &Place<'tcx>) -> BorrowedContentSource { - // Look up the provided place and work out the move path index for it, - // we'll use this to work back through where this value came from and check whether it - // was originally part of an `Rc` or `Arc`. - let initial_mpi = match self.move_data.rev_lookup.find(place) { - LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => mpi, - _ => return BorrowedContentSource::Other, - }; - - let mut queue = vec![initial_mpi]; - let mut visited = Vec::new(); - debug!("borrowed_content_source: queue={:?}", queue); - while let Some(mpi) = queue.pop() { - debug!( - "borrowed_content_source: mpi={:?} queue={:?} visited={:?}", - mpi, queue, visited - ); - - // Don't visit the same path twice. - if visited.contains(&mpi) { - continue; - } - visited.push(mpi); - - for i in &self.move_data.init_path_map[mpi] { - let init = &self.move_data.inits[*i]; - debug!("borrowed_content_source: init={:?}", init); - // We're only interested in statements that initialized a value, not the - // initializations from arguments. - let loc = match init.location { - InitLocation::Statement(stmt) => stmt, - _ => continue, - }; + fn borrowed_content_source(&self, deref_base: &Place<'tcx>) -> BorrowedContentSource<'tcx> { + let tcx = self.infcx.tcx; - let bbd = &self.mir[loc.block]; - let is_terminator = bbd.statements.len() == loc.statement_index; - debug!("borrowed_content_source: loc={:?} is_terminator={:?}", loc, is_terminator); - if !is_terminator { - let stmt = &bbd.statements[loc.statement_index]; - debug!("borrowed_content_source: stmt={:?}", stmt); - // We're only interested in assignments (in particular, where the - // assignment came from - was it an `Rc` or `Arc`?). - if let StatementKind::Assign(_, box Rvalue::Ref(_, _, source)) = &stmt.kind { - let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); - let ty = match ty.sty { - ty::TyKind::Ref(_, ty, _) => ty, - _ => ty, - }; - debug!("borrowed_content_source: ty={:?}", ty); - - if ty.is_arc() { - return BorrowedContentSource::Arc; - } else if ty.is_rc() { - return BorrowedContentSource::Rc; - } else { - queue.push(init.path); - } - } - } else if let Some(Terminator { - kind: TerminatorKind::Call { args, .. }, - .. - }) = &bbd.terminator { - for arg in args { - let source = match arg { - Operand::Copy(place) | Operand::Move(place) => place, - _ => continue, - }; - - let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); - let ty = match ty.sty { - ty::TyKind::Ref(_, ty, _) => ty, - _ => ty, - }; - debug!("borrowed_content_source: ty={:?}", ty); - - if ty.is_arc() { - return BorrowedContentSource::Arc; - } else if ty.is_rc() { - return BorrowedContentSource::Rc; - } else { - queue.push(init.path); + // Look up the provided place and work out the move path index for it, + // we'll use this to check whether it was originally from an overloaded + // operator. + match self.move_data.rev_lookup.find(deref_base) { + LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => { + debug!("borrowed_content_source: mpi={:?}", mpi); + + for i in &self.move_data.init_path_map[mpi] { + let init = &self.move_data.inits[*i]; + debug!("borrowed_content_source: init={:?}", init); + // We're only interested in statements that initialized a value, not the + // initializations from arguments. + let loc = match init.location { + InitLocation::Statement(stmt) => stmt, + _ => continue, + }; + + let bbd = &self.body[loc.block]; + let is_terminator = bbd.statements.len() == loc.statement_index; + debug!( + "borrowed_content_source: loc={:?} is_terminator={:?}", + loc, + is_terminator, + ); + if !is_terminator { + continue; + } else if let Some(Terminator { + kind: TerminatorKind::Call { + ref func, + from_hir_call: false, + .. + }, + .. + }) = bbd.terminator { + if let Some(source) + = BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx) + { + return source; } } } } - } + // Base is a `static` so won't be from an overloaded operator + _ => (), + }; - // If we didn't find an `Arc` or an `Rc`, then check specifically for - // a dereference of a place that has the type of a raw pointer. - // We can't use `place.ty(..).to_ty(..)` here as that strips away the raw pointer. - if let Place::Projection(box Projection { - base, - elem: ProjectionElem::Deref, - }) = place { - if base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx).is_unsafe_ptr() { - return BorrowedContentSource::DerefRawPointer; - } + // If we didn't find an overloaded deref or index, then assume it's a + // built in deref and check the type of the base. + let base_ty = deref_base.ty(self.body, tcx).ty; + if base_ty.is_unsafe_ptr() { + BorrowedContentSource::DerefRawPointer + } else if base_ty.is_mutable_pointer() { + BorrowedContentSource::DerefMutableRef + } else { + BorrowedContentSource::DerefSharedRef } - - BorrowedContentSource::Other } } diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index f68ed4422bca0..92c2e4e01f760 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -1,12 +1,14 @@ use rustc::hir; use rustc::hir::Node; -use rustc::mir::{self, BindingForm, Constant, ClearCrossCrate, Local, Location, Mir}; -use rustc::mir::{Mutability, Operand, Place, PlaceBase, Projection, ProjectionElem, Static}; +use rustc::mir::{self, BindingForm, Constant, ClearCrossCrate, Local, Location, Body}; +use rustc::mir::{ + Mutability, Operand, Place, PlaceBase, Projection, ProjectionElem, Static, StaticKind, +}; use rustc::mir::{Terminator, TerminatorKind}; -use rustc::ty::{self, Const, DefIdTree, TyS, TyKind, TyCtxt}; +use rustc::ty::{self, Const, DefIdTree, Ty, TyS, TyCtxt}; use rustc_data_structures::indexed_vec::Idx; use syntax_pos::Span; -use syntax_pos::symbol::keywords; +use syntax_pos::symbol::kw; use crate::dataflow::move_paths::InitLocation; use crate::borrow_check::MirBorrowckCtxt; @@ -22,7 +24,7 @@ pub(super) enum AccessKind { Move, } -impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { pub(super) fn report_mutability_error( &mut self, access_place: &Place<'tcx>, @@ -50,7 +52,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { if let Place::Base(PlaceBase::Local(_)) = access_place { reason = ", as it is not declared as mutable".to_string(); } else { - let name = self.mir.local_decls[*local] + let name = self.body.local_decls[*local] .name .expect("immutable unnamed local"); reason = format!(", as `{}` is not declared as mutable", name); @@ -62,14 +64,14 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { elem: ProjectionElem::Field(upvar_index, _), }) => { debug_assert!(is_closure_or_generator( - base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) + base.ty(self.body, self.infcx.tcx).ty )); item_msg = format!("`{}`", access_place_desc.unwrap()); - if access_place.is_upvar_field_projection(self.mir, &self.infcx.tcx).is_some() { + if self.is_upvar_field_projection(access_place).is_some() { reason = ", as it is not declared as mutable".to_string(); } else { - let name = self.mir.upvar_decls[upvar_index.index()].debug_name; + let name = self.upvars[upvar_index.index()].name; reason = format!(", as `{}` is not declared as mutable", name); } } @@ -79,27 +81,21 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { elem: ProjectionElem::Deref, }) => { if *base == Place::Base(PlaceBase::Local(Local::new(1))) && - !self.mir.upvar_decls.is_empty() { + !self.upvars.is_empty() { item_msg = format!("`{}`", access_place_desc.unwrap()); - debug_assert!(self.mir.local_decls[Local::new(1)].ty.is_region_ptr()); + debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr()); debug_assert!(is_closure_or_generator( - the_place_err.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) + the_place_err.ty(self.body, self.infcx.tcx).ty )); - reason = if access_place.is_upvar_field_projection(self.mir, - &self.infcx.tcx).is_some() { + reason = if self.is_upvar_field_projection(access_place).is_some() { ", as it is a captured variable in a `Fn` closure".to_string() } else { ", as `Fn` closures cannot mutate their captured variables".to_string() } } else if { if let Place::Base(PlaceBase::Local(local)) = *base { - if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) - = self.mir.local_decls[local].is_user_variable { - true - } else { - false - } + self.body.local_decls[local].is_ref_for_guard() } else { false } @@ -108,7 +104,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { reason = ", as it is immutable for the pattern guard".to_string(); } else { let pointer_type = - if base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx).is_region_ptr() { + if base.ty(self.body, self.infcx.tcx).ty.is_region_ptr() { "`&` reference" } else { "`*const` pointer" @@ -129,9 +125,10 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { } } - Place::Base(PlaceBase::Promoted(_)) => unreachable!(), + Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. })) => + unreachable!(), - Place::Base(PlaceBase::Static(box Static { def_id, ty: _ })) => { + Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. })) => { if let Place::Base(PlaceBase::Static(_)) = access_place { item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); reason = String::new(); @@ -229,7 +226,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { if let Some((span, message)) = annotate_struct_field( self.infcx.tcx, - base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx), + base.ty(self.body, self.infcx.tcx).ty, field, ) { err.span_suggestion( @@ -244,7 +241,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // Suggest removing a `&mut` from the use of a mutable reference. Place::Base(PlaceBase::Local(local)) if { - self.mir.local_decls.get(*local).map(|local_decl| { + self.body.local_decls.get(*local).map(|local_decl| { if let ClearCrossCrate::Set( mir::BindingForm::ImplicitSelf(kind) ) = local_decl.is_user_variable.as_ref().unwrap() { @@ -254,11 +251,11 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // Deliberately fall into this case for all implicit self types, // so that we don't fall in to the next case with them. *kind == mir::ImplicitSelfKind::MutRef - } else if Some(keywords::SelfLower.name()) == local_decl.name { + } else if Some(kw::SelfLower) == local_decl.name { // Otherwise, check if the name is the self kewyord - in which case // we have an explicit self. Do the same thing in this case and check // for a `self: &mut Self` to suggest removing the `&mut`. - if let ty::TyKind::Ref( + if let ty::Ref( _, _, hir::Mutability::MutMutable ) = local_decl.ty.sty { true @@ -278,12 +275,12 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // We want to suggest users use `let mut` for local (user // variable) mutations... Place::Base(PlaceBase::Local(local)) - if self.mir.local_decls[*local].can_be_made_mutable() => { + if self.body.local_decls[*local].can_be_made_mutable() => { // ... but it doesn't make sense to suggest it on // variables that are `ref x`, `ref mut x`, `&self`, // or `&mut self` (such variables are simply not // mutable). - let local_decl = &self.mir.local_decls[*local]; + let local_decl = &self.body.local_decls[*local]; assert_eq!(local_decl.mutability, Mutability::Not); err.span_label(span, format!("cannot {ACT}", ACT = act)); @@ -301,20 +298,17 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { elem: ProjectionElem::Field(upvar_index, _), }) => { debug_assert!(is_closure_or_generator( - base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) + base.ty(self.body, self.infcx.tcx).ty )); err.span_label(span, format!("cannot {ACT}", ACT = act)); - let upvar_hir_id = self.mir.upvar_decls[upvar_index.index()] - .var_hir_id - .assert_crate_local(); - let upvar_node_id = self.infcx.tcx.hir().hir_to_node_id(upvar_hir_id); - if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_node_id) { + let upvar_hir_id = self.upvars[upvar_index.index()].var_hir_id; + if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) + { if let hir::PatKind::Binding( hir::BindingAnnotation::Unannotated, _, - _, upvar_ident, _, ) = pat.node @@ -350,7 +344,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { elem: ProjectionElem::Deref, }) if { if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) = - self.mir.local_decls[*local].is_user_variable + self.body.local_decls[*local].is_user_variable { true } else { @@ -372,9 +366,9 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { Place::Projection(box Projection { base: Place::Base(PlaceBase::Local(local)), elem: ProjectionElem::Deref, - }) if self.mir.local_decls[*local].is_user_variable.is_some() => + }) if self.body.local_decls[*local].is_user_variable.is_some() => { - let local_decl = &self.mir.local_decls[*local]; + let local_decl = &self.body.local_decls[*local]; let suggestion = match local_decl.is_user_variable.as_ref().unwrap() { ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(_)) => { Some(suggest_ampmut_self(self.infcx.tcx, local_decl)) @@ -386,7 +380,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { .. })) => Some(suggest_ampmut( self.infcx.tcx, - self.mir, + self.body, *local, local_decl, *opt_ty_info, @@ -421,28 +415,31 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { ); } - if let Some(name) = local_decl.name { - err.span_label( - span, - format!( - "`{NAME}` is a `{SIGIL}` {DESC}, \ - so the data it refers to cannot be {ACTED_ON}", - NAME = name, - SIGIL = pointer_sigil, - DESC = pointer_desc, - ACTED_ON = acted_on - ), - ); - } else { - err.span_label( - span, - format!( - "cannot {ACT} through `{SIGIL}` {DESC}", - ACT = act, - SIGIL = pointer_sigil, - DESC = pointer_desc - ), - ); + match local_decl.name { + Some(name) if !local_decl.from_compiler_desugaring() => { + err.span_label( + span, + format!( + "`{NAME}` is a `{SIGIL}` {DESC}, \ + so the data it refers to cannot be {ACTED_ON}", + NAME = name, + SIGIL = pointer_sigil, + DESC = pointer_desc, + ACTED_ON = acted_on + ), + ); + } + _ => { + err.span_label( + span, + format!( + "cannot {ACT} through `{SIGIL}` {DESC}", + ACT = act, + SIGIL = pointer_sigil, + DESC = pointer_desc + ), + ); + } } } @@ -450,11 +447,11 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { base, elem: ProjectionElem::Deref, }) if *base == Place::Base(PlaceBase::Local(Local::new(1))) && - !self.mir.upvar_decls.is_empty() => + !self.upvars.is_empty() => { err.span_label(span, format!("cannot {ACT}", ACT = act)); err.span_help( - self.mir.span, + self.body.span, "consider changing this to accept closures that implement `FnMut`" ); } @@ -472,20 +469,20 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { Terminator { kind: TerminatorKind::Call { func: Operand::Constant(box Constant { - literal: ty::LazyConst::Evaluated(Const { + literal: Const { ty: &TyS { - sty: TyKind::FnDef(id, substs), + sty: ty::FnDef(id, substs), .. }, .. - }), + }, .. }), .. }, .. } - ) = &self.mir.basic_blocks()[location.block].terminator { + ) = &self.body.basic_blocks()[location.block].terminator { let index_trait = self.infcx.tcx.lang_items().index_trait(); if self.infcx.tcx.parent(id) == index_trait { let mut found = false; @@ -525,8 +522,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { } } -fn suggest_ampmut_self<'cx, 'gcx, 'tcx>( - tcx: TyCtxt<'cx, 'gcx, 'tcx>, +fn suggest_ampmut_self<'tcx>( + tcx: TyCtxt<'tcx>, local_decl: &mir::LocalDecl<'tcx>, ) -> (Span, String) { let sp = local_decl.source_info.span; @@ -558,16 +555,16 @@ fn suggest_ampmut_self<'cx, 'gcx, 'tcx>( // // This implementation attempts to emulate AST-borrowck prioritization // by trying (3.), then (2.) and finally falling back on (1.). -fn suggest_ampmut<'cx, 'gcx, 'tcx>( - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - mir: &Mir<'tcx>, +fn suggest_ampmut<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, local: Local, local_decl: &mir::LocalDecl<'tcx>, opt_ty_info: Option, ) -> (Span, String) { - let locations = mir.find_assignments(local); + let locations = body.find_assignments(local); if !locations.is_empty() { - let assignment_rhs_span = mir.source_info(locations[0]).span; + let assignment_rhs_span = body.source_info(locations[0]).span; if let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) { if let (true, Some(ws_pos)) = ( src.starts_with("&'"), @@ -614,7 +611,7 @@ fn suggest_ampmut<'cx, 'gcx, 'tcx>( }) } -fn is_closure_or_generator(ty: ty::Ty<'_>) -> bool { +fn is_closure_or_generator(ty: Ty<'_>) -> bool { ty.is_closure() || ty.is_generator() } @@ -626,17 +623,17 @@ fn is_closure_or_generator(ty: ty::Ty<'_>) -> bool { /// | ---------- use `&'a mut String` here to make mutable /// ``` fn annotate_struct_field( - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - ty: ty::Ty<'tcx>, + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, field: &mir::Field, ) -> Option<(Span, String)> { // Expect our local to be a reference to a struct of some kind. - if let ty::TyKind::Ref(_, ty, _) = ty.sty { - if let ty::TyKind::Adt(def, _) = ty.sty { + if let ty::Ref(_, ty, _) = ty.sty { + if let ty::Adt(def, _) = ty.sty { let field = def.all_fields().nth(field.index())?; // Use the HIR types to construct the diagnostic message. - let node_id = tcx.hir().as_local_node_id(field.did)?; - let node = tcx.hir().find(node_id)?; + let hir_id = tcx.hir().as_local_hir_id(field.did)?; + let node = tcx.hir().find(hir_id)?; // Now we're dealing with the actual struct that we're going to suggest a change to, // we can expect a field that is an immutable reference to a type. if let hir::Node::Field(field) = node { diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 375dd6e97f1a2..058cdec5cea69 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -6,19 +6,19 @@ use crate::borrow_check::nll::region_infer::values::LivenessValues; use rustc::infer::InferCtxt; use rustc::mir::visit::TyContext; use rustc::mir::visit::Visitor; -use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, PlaceBase, Rvalue}; +use rustc::mir::{BasicBlock, BasicBlockData, Location, Body, Place, PlaceBase, Rvalue}; use rustc::mir::{SourceInfo, Statement, Terminator}; use rustc::mir::UserTypeProjection; use rustc::ty::fold::TypeFoldable; -use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid}; +use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty}; use rustc::ty::subst::SubstsRef; -pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( - infcx: &InferCtxt<'cx, 'gcx, 'tcx>, +pub(super) fn generate_constraints<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, liveness_constraints: &mut LivenessValues, all_facts: &mut Option, location_table: &LocationTable, - mir: &Mir<'tcx>, + body: &Body<'tcx>, borrow_set: &BorrowSet<'tcx>, ) { let mut cg = ConstraintGeneration { @@ -29,21 +29,21 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( all_facts, }; - for (bb, data) in mir.basic_blocks().iter_enumerated() { + for (bb, data) in body.basic_blocks().iter_enumerated() { cg.visit_basic_block_data(bb, data); } } /// 'cg = the duration of the constraint generation process itself. -struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> { - infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>, +struct ConstraintGeneration<'cg, 'cx, 'tcx> { + infcx: &'cg InferCtxt<'cx, 'tcx>, all_facts: &'cg mut Option, location_table: &'cg LocationTable, liveness_constraints: &'cg mut LivenessValues, borrow_set: &'cg BorrowSet<'tcx>, } -impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> { +impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) { self.super_basic_block_data(bb, data); } @@ -64,7 +64,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx /// We sometimes have `ty` within an rvalue, or within a /// call. Make them live at the location where they appear. - fn visit_ty(&mut self, ty: &ty::Ty<'tcx>, ty_context: TyContext) { + fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: TyContext) { match ty_context { TyContext::ReturnTy(SourceInfo { span, .. }) | TyContext::YieldTy(SourceInfo { span, .. }) @@ -77,7 +77,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx ); } TyContext::Location(location) => { - self.add_regular_live_constraint(*ty, location); + self.add_regular_live_constraint(ty, location); } } @@ -100,7 +100,6 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx fn visit_statement( &mut self, - block: BasicBlock, statement: &Statement<'tcx>, location: Location, ) { @@ -117,12 +116,11 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx )); } - self.super_statement(block, statement, location); + self.super_statement(statement, location); } fn visit_assign( &mut self, - block: BasicBlock, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location, @@ -141,12 +139,11 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx } } - self.super_assign(block, place, rvalue, location); + self.super_assign(place, rvalue, location); } fn visit_terminator( &mut self, - block: BasicBlock, terminator: &Terminator<'tcx>, location: Location, ) { @@ -167,20 +164,20 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx } } - self.super_terminator(block, terminator, location); + self.super_terminator(terminator, location); } fn visit_ascribe_user_ty( &mut self, _place: &Place<'tcx>, _variance: &ty::Variance, - _user_ty: &UserTypeProjection<'tcx>, + _user_ty: &UserTypeProjection, _location: Location, ) { } } -impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { +impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { /// Some variable with type `live_ty` is "regular live" at /// `location` -- i.e., it may be used later. This means that all /// regions appearing in the type `live_ty` must be live at diff --git a/src/librustc_mir/borrow_check/nll/constraints/graph.rs b/src/librustc_mir/borrow_check/nll/constraints/graph.rs index c4b2a5daef89a..1d9e6064c416b 100644 --- a/src/librustc_mir/borrow_check/nll/constraints/graph.rs +++ b/src/librustc_mir/borrow_check/nll/constraints/graph.rs @@ -1,6 +1,6 @@ use crate::borrow_check::nll::type_check::Locations; -use crate::borrow_check::nll::constraints::ConstraintIndex; -use crate::borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint}; +use crate::borrow_check::nll::constraints::OutlivesConstraintIndex; +use crate::borrow_check::nll::constraints::{OutlivesConstraintSet, OutlivesConstraint}; use rustc::mir::ConstraintCategory; use rustc::ty::RegionVid; use rustc_data_structures::graph; @@ -12,8 +12,8 @@ use syntax_pos::DUMMY_SP; /// -> R2` or `R2 -> R1` depending on the direction type `D`. crate struct ConstraintGraph { _direction: D, - first_constraints: IndexVec>, - next_constraints: IndexVec>, + first_constraints: IndexVec>, + next_constraints: IndexVec>, } crate type NormalConstraintGraph = ConstraintGraph; @@ -77,13 +77,13 @@ impl ConstraintGraph { /// reporting. crate fn new( direction: D, - set: &ConstraintSet, + set: &OutlivesConstraintSet, num_region_vars: usize, ) -> Self { let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars); - let mut next_constraints = IndexVec::from_elem(None, &set.constraints); + let mut next_constraints = IndexVec::from_elem(None, &set.outlives); - for (idx, constraint) in set.constraints.iter_enumerated().rev() { + for (idx, constraint) in set.outlives.iter_enumerated().rev() { let head = &mut first_constraints[D::start_region(constraint)]; let next = &mut next_constraints[idx]; debug_assert!(next.is_none()); @@ -103,7 +103,7 @@ impl ConstraintGraph { /// and not constraints. crate fn region_graph<'rg>( &'rg self, - set: &'rg ConstraintSet, + set: &'rg OutlivesConstraintSet, static_region: RegionVid, ) -> RegionGraph<'rg, D> { RegionGraph::new(set, self, static_region) @@ -113,7 +113,7 @@ impl ConstraintGraph { crate fn outgoing_edges<'a>( &'a self, region_sup: RegionVid, - constraints: &'a ConstraintSet, + constraints: &'a OutlivesConstraintSet, static_region: RegionVid, ) -> Edges<'a, D> { //if this is the `'static` region and the graph's direction is normal, @@ -142,8 +142,8 @@ impl ConstraintGraph { crate struct Edges<'s, D: ConstraintGraphDirecton> { graph: &'s ConstraintGraph, - constraints: &'s ConstraintSet, - pointer: Option, + constraints: &'s OutlivesConstraintSet, + pointer: Option, next_static_idx: Option, static_region: RegionVid, } @@ -180,7 +180,7 @@ impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> { /// reverse) constraint graph. It implements the graph traits and is /// usd for doing the SCC computation. crate struct RegionGraph<'s, D: ConstraintGraphDirecton> { - set: &'s ConstraintSet, + set: &'s OutlivesConstraintSet, constraint_graph: &'s ConstraintGraph, static_region: RegionVid, } @@ -191,7 +191,7 @@ impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> { /// construct SCCs for region inference but also for error /// reporting. crate fn new( - set: &'s ConstraintSet, + set: &'s OutlivesConstraintSet, constraint_graph: &'s ConstraintGraph, static_region: RegionVid, ) -> Self { diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/nll/constraints/mod.rs index b1091eb5ac81f..6121ed0cf0d1c 100644 --- a/src/librustc_mir/borrow_check/nll/constraints/mod.rs +++ b/src/librustc_mir/borrow_check/nll/constraints/mod.rs @@ -1,37 +1,40 @@ +use crate::borrow_check::nll::type_check::Locations; use rustc::mir::ConstraintCategory; use rustc::ty::RegionVid; use rustc_data_structures::graph::scc::Sccs; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use crate::borrow_check::nll::type_check::Locations; - use std::fmt; -use std::ops::Deref; +use std::ops::Index; crate mod graph; +/// A set of NLL region constraints. These include "outlives" +/// constraints of the form `R1: R2`. Each constraint is identified by +/// a unique `OutlivesConstraintIndex` and you can index into the set +/// (`constraint_set[i]`) to access the constraint details. #[derive(Clone, Default)] -crate struct ConstraintSet { - constraints: IndexVec, +crate struct OutlivesConstraintSet { + outlives: IndexVec, } -impl ConstraintSet { +impl OutlivesConstraintSet { crate fn push(&mut self, constraint: OutlivesConstraint) { debug!( - "ConstraintSet::push({:?}: {:?} @ {:?}", + "OutlivesConstraintSet::push({:?}: {:?} @ {:?}", constraint.sup, constraint.sub, constraint.locations ); if constraint.sup == constraint.sub { // 'a: 'a is pretty uninteresting return; } - self.constraints.push(constraint); + self.outlives.push(constraint); } /// Constructs a "normal" graph from the constraint set; the graph makes it /// easy to find the constraints affecting a particular region. /// /// N.B., this graph contains a "frozen" view of the current - /// constraints. Any new constraints added to the `ConstraintSet` + /// constraints. Any new constraints added to the `OutlivesConstraintSet` /// after the graph is built will not be present in the graph. crate fn graph(&self, num_region_vars: usize) -> graph::NormalConstraintGraph { graph::ConstraintGraph::new(graph::Normal, self, num_region_vars) @@ -54,13 +57,17 @@ impl ConstraintSet { let region_graph = &constraint_graph.region_graph(self, static_region); Sccs::new(region_graph) } + + crate fn outlives(&self) -> &IndexVec { + &self.outlives + } } -impl Deref for ConstraintSet { - type Target = IndexVec; +impl Index for OutlivesConstraintSet { + type Output = OutlivesConstraint; - fn deref(&self) -> &Self::Target { - &self.constraints + fn index(&self, i: OutlivesConstraintIndex) -> &Self::Output { + &self.outlives[i] } } @@ -94,8 +101,8 @@ impl fmt::Debug for OutlivesConstraint { } newtype_index! { - pub struct ConstraintIndex { - DEBUG_FORMAT = "ConstraintIndex({})" + pub struct OutlivesConstraintIndex { + DEBUG_FORMAT = "OutlivesConstraintIndex({})" } } diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs index 7d6385752c348..7ab069260f940 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs @@ -5,19 +5,19 @@ use crate::borrow_check::nll::region_infer::{Cause, RegionInferenceContext}; use crate::borrow_check::nll::ToRegionVid; use crate::util::liveness::{self, DefUse}; use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor}; -use rustc::mir::{Local, Location, Mir}; +use rustc::mir::{Local, Location, Body}; use rustc::ty::{RegionVid, TyCtxt}; use rustc_data_structures::fx::FxHashSet; crate fn find<'tcx>( - mir: &Mir<'tcx>, + body: &Body<'tcx>, regioncx: &Rc>, - tcx: TyCtxt<'_, '_, 'tcx>, + tcx: TyCtxt<'tcx>, region_vid: RegionVid, start_point: Location, ) -> Option { let mut uf = UseFinder { - mir, + body, regioncx, tcx, region_vid, @@ -27,15 +27,15 @@ crate fn find<'tcx>( uf.find() } -struct UseFinder<'cx, 'gcx: 'tcx, 'tcx: 'cx> { - mir: &'cx Mir<'tcx>, +struct UseFinder<'cx, 'tcx> { + body: &'cx Body<'tcx>, regioncx: &'cx Rc>, - tcx: TyCtxt<'cx, 'gcx, 'tcx>, + tcx: TyCtxt<'tcx>, region_vid: RegionVid, start_point: Location, } -impl<'cx, 'gcx, 'tcx> UseFinder<'cx, 'gcx, 'tcx> { +impl<'cx, 'tcx> UseFinder<'cx, 'tcx> { fn find(&mut self) -> Option { let mut queue = VecDeque::new(); let mut visited = FxHashSet::default(); @@ -50,7 +50,7 @@ impl<'cx, 'gcx, 'tcx> UseFinder<'cx, 'gcx, 'tcx> { continue; } - let block_data = &self.mir[p.block]; + let block_data = &self.body[p.block]; match self.def_use(p, block_data.visitable(p.statement_index)) { Some(DefUseResult::Def) => {} @@ -87,7 +87,7 @@ impl<'cx, 'gcx, 'tcx> UseFinder<'cx, 'gcx, 'tcx> { fn def_use(&self, location: Location, thing: &dyn MirVisitable<'tcx>) -> Option { let mut visitor = DefUseVisitor { - mir: self.mir, + body: self.body, tcx: self.tcx, region_vid: self.region_vid, def_use_result: None, @@ -99,9 +99,9 @@ impl<'cx, 'gcx, 'tcx> UseFinder<'cx, 'gcx, 'tcx> { } } -struct DefUseVisitor<'cx, 'gcx: 'tcx, 'tcx: 'cx> { - mir: &'cx Mir<'tcx>, - tcx: TyCtxt<'cx, 'gcx, 'tcx>, +struct DefUseVisitor<'cx, 'tcx> { + body: &'cx Body<'tcx>, + tcx: TyCtxt<'tcx>, region_vid: RegionVid, def_use_result: Option, } @@ -112,9 +112,9 @@ enum DefUseResult { UseDrop { local: Local }, } -impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'gcx, 'tcx> { - fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, _: Location) { - let local_ty = self.mir.local_decls[local].ty; +impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> { + fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + let local_ty = self.body.local_decls[local].ty; let mut found_it = false; self.tcx.for_each_free_region(&local_ty, |r| { diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 17f8c23f4fddc..ed88b16253584 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -4,12 +4,13 @@ use crate::borrow_check::borrow_set::BorrowData; use crate::borrow_check::error_reporting::UseSpans; use crate::borrow_check::nll::region_infer::{Cause, RegionName}; use crate::borrow_check::nll::ConstraintDescription; -use crate::borrow_check::{Context, MirBorrowckCtxt, WriteKind}; +use crate::borrow_check::{MirBorrowckCtxt, WriteKind}; use rustc::mir::{ - CastKind, ConstraintCategory, FakeReadCause, Local, Location, Mir, Operand, Place, PlaceBase, + CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, PlaceBase, Projection, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, }; use rustc::ty::{self, TyCtxt}; +use rustc::ty::adjustment::{PointerCast}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagnosticBuilder; use syntax_pos::Span; @@ -50,23 +51,29 @@ impl BorrowExplanation { _ => true, } } - pub(in crate::borrow_check) fn add_explanation_to_diagnostic<'cx, 'gcx, 'tcx>( + pub(in crate::borrow_check) fn add_explanation_to_diagnostic<'tcx>( &self, - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - mir: &Mir<'tcx>, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, err: &mut DiagnosticBuilder<'_>, borrow_desc: &str, + borrow_span: Option, ) { match *self { BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => { let message = match later_use_kind { - LaterUseKind::TraitCapture => "borrow later captured here by trait object", - LaterUseKind::ClosureCapture => "borrow later captured here by closure", - LaterUseKind::Call => "borrow later used by call", - LaterUseKind::FakeLetRead => "borrow later stored here", - LaterUseKind::Other => "borrow later used here", + LaterUseKind::TraitCapture => "captured here by trait object", + LaterUseKind::ClosureCapture => "captured here by closure", + LaterUseKind::Call => "used by call", + LaterUseKind::FakeLetRead => "stored here", + LaterUseKind::Other => "used here", }; - err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message)); + if !borrow_span.map(|sp| sp.overlaps(var_or_use_span)).unwrap_or(false) { + err.span_label( + var_or_use_span, + format!("{}borrow later {}", borrow_desc, message), + ); + } } BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => { let message = match later_use_kind { @@ -87,13 +94,13 @@ impl BorrowExplanation { dropped_local, should_note_order, } => { - let local_decl = &mir.local_decls[dropped_local]; + let local_decl = &body.local_decls[dropped_local]; let (dtor_desc, type_desc) = match local_decl.ty.sty { // If type is an ADT that implements Drop, then // simplify output by reporting just the ADT name. ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => ( "`Drop` code", - format!("type `{}`", tcx.item_path_str(adt.did)), + format!("type `{}`", tcx.def_path_str(adt.did)), ), // Otherwise, just report the whole type (and use @@ -105,7 +112,7 @@ impl BorrowExplanation { }; match local_decl.name { - Some(local_name) => { + Some(local_name) if !local_decl.from_compiler_desugaring() => { let message = format!( "{B}borrow might be used here, when `{LOC}` is dropped \ and runs the {DTOR} for {TYPE}", @@ -114,7 +121,7 @@ impl BorrowExplanation { TYPE = type_desc, DTOR = dtor_desc ); - err.span_label(mir.source_info(drop_loc).span, message); + err.span_label(body.source_info(drop_loc).span, message); if should_note_order { err.note( @@ -123,7 +130,7 @@ impl BorrowExplanation { ); } } - None => { + _ => { err.span_label( local_decl.source_info.span, format!( @@ -140,7 +147,7 @@ impl BorrowExplanation { TYPE = type_desc, DTOR = dtor_desc ); - err.span_label(mir.source_info(drop_loc).span, message); + err.span_label(body.source_info(drop_loc).span, message); if let Some(info) = &local_decl.is_block_tail { // FIXME: use span_suggestion instead, highlighting the @@ -200,15 +207,15 @@ impl BorrowExplanation { } } -impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Returns structured explanation for *why* the borrow contains the - /// point from `context`. This is key for the "3-point errors" + /// point from `location`. This is key for the "3-point errors" /// [described in the NLL RFC][d]. /// /// # Parameters /// /// - `borrow`: the borrow in question - /// - `context`: where the borrow occurs + /// - `location`: where the borrow occurs /// - `kind_place`: if Some, this describes the statement that triggered the error. /// - first half is the kind of write, if any, being performed /// - second half is the place being accessed @@ -216,17 +223,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points pub(in crate::borrow_check) fn explain_why_borrow_contains_point( &self, - context: Context, + location: Location, borrow: &BorrowData<'tcx>, kind_place: Option<(WriteKind, &Place<'tcx>)>, ) -> BorrowExplanation { debug!( - "explain_why_borrow_contains_point(context={:?}, borrow={:?}, kind_place={:?})", - context, borrow, kind_place + "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})", + location, borrow, kind_place ); let regioncx = &self.nonlexical_regioncx; - let mir = self.mir; + let body = self.body; let tcx = self.infcx.tcx; let borrow_region_vid = borrow.region; @@ -235,20 +242,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { borrow_region_vid ); - let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, context.loc); + let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, location); debug!( "explain_why_borrow_contains_point: region_sub={:?}", region_sub ); - match find_use::find(mir, regioncx, tcx, region_sub, context.loc) { + match find_use::find(body, regioncx, tcx, region_sub, location) { Some(Cause::LiveVar(local, location)) => { - let span = mir.source_info(location).span; + let span = body.source_info(location).span; let spans = self - .move_spans(&Place::Base(PlaceBase::Local(local)), location) + .move_spans(&Place::from(local), location) .or_else(|| self.borrow_spans(span, location)); - let borrow_location = context.loc; + let borrow_location = location; if self.is_use_in_later_iteration_of_loop(borrow_location, location) { let later_use = self.later_use_kind(borrow, spans, location); BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1) @@ -263,14 +270,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Some(Cause::DropVar(local, location)) => { let mut should_note_order = false; - if mir.local_decls[local].name.is_some() { + if body.local_decls[local].name.is_some() { if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { if let Place::Base(PlaceBase::Local(borrowed_local)) = place { - let dropped_local_scope = mir.local_decls[local].visibility_scope; - let borrowed_local_scope = - mir.local_decls[*borrowed_local].visibility_scope; - - if mir.is_sub_scope(borrowed_local_scope, dropped_local_scope) + if body.local_decls[*borrowed_local].name.is_some() && local != *borrowed_local { should_note_order = true; @@ -290,7 +293,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if let Some(region) = regioncx.to_error_region_vid(borrow_region_vid) { let (category, from_closure, span, region_name) = self.nonlexical_regioncx.free_region_constraint_info( - self.mir, + self.body, + &self.upvars, self.mir_def_id, self.infcx, borrow_region_vid, @@ -306,9 +310,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { opt_place_desc, } } else { + debug!("explain_why_borrow_contains_point: \ + Could not generate a region name"); BorrowExplanation::Unexplained } } else { + debug!("explain_why_borrow_contains_point: \ + Could not generate an error region vid"); BorrowExplanation::Unexplained } } @@ -351,7 +359,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { return outmost_back_edge; } - let block = &self.mir.basic_blocks()[location.block]; + let block = &self.body.basic_blocks()[location.block]; if location.statement_index < block.statements.len() { let successor = location.successor_within_block(); @@ -413,7 +421,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } if loop_head.dominates(from, &self.dominators) { - let block = &self.mir.basic_blocks()[from.block]; + let block = &self.body.basic_blocks()[from.block]; if from.statement_index < block.statements.len() { let successor = from.successor_within_block(); @@ -445,7 +453,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// True if an edge `source -> target` is a backedge -- in other words, if the target /// dominates the source. fn is_back_edge(&self, source: Location, target: Location) -> bool { - target.dominates(source, &self.mir.dominators()) + target.dominates(source, &self.body.dominators()) } /// Determine how the borrow was later used. @@ -461,7 +469,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { (LaterUseKind::ClosureCapture, var_span) } UseSpans::OtherUse(span) => { - let block = &self.mir.basic_blocks()[location.block]; + let block = &self.body.basic_blocks()[location.block]; let kind = if let Some(&Statement { kind: StatementKind::FakeRead(FakeReadCause::ForLet, _), @@ -483,7 +491,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Operand::Constant(c) => c.span, Operand::Copy(Place::Base(PlaceBase::Local(l))) | Operand::Move(Place::Base(PlaceBase::Local(l))) => { - let local_decl = &self.mir.local_decls[*l]; + let local_decl = &self.body.local_decls[*l]; if local_decl.name.is_none() { local_decl.source_info.span } else { @@ -511,7 +519,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool { // Start at the reserve location, find the place that we want to see cast to a trait object. let location = borrow.reserve_location; - let block = &self.mir[location.block]; + let block = &self.body[location.block]; let stmt = block.statements.get(location.statement_index); debug!( "was_captured_by_trait_object: location={:?} stmt={:?}", @@ -538,7 +546,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ); while let Some(current_location) = queue.pop() { debug!("was_captured_by_trait: target={:?}", target); - let block = &self.mir[current_location.block]; + let block = &self.body[current_location.block]; // We need to check the current location to find out if it is a terminator. let is_terminator = current_location.statement_index == block.statements.len(); if !is_terminator { @@ -574,7 +582,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { }, // If we see a unsized cast, then if it is our data we should check // whether it is being cast to a trait object. - Rvalue::Cast(CastKind::Unsize, operand, ty) => match operand { + Rvalue::Cast( + CastKind::Pointer(PointerCast::Unsize), operand, ty + ) => match operand { Operand::Copy(Place::Base(PlaceBase::Local(from))) | Operand::Move(Place::Base(PlaceBase::Local(from))) if *from == target => @@ -583,7 +593,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Check the type for a trait object. return match ty.sty { // `&dyn Trait` - ty::TyKind::Ref(_, ty, _) if ty.is_trait() => true, + ty::Ref(_, ty, _) if ty.is_trait() => true, // `Box` _ if ty.is_box() && ty.boxed_ty().is_trait() => true, // `dyn Trait` diff --git a/src/librustc_mir/borrow_check/nll/facts.rs b/src/librustc_mir/borrow_check/nll/facts.rs index 9714398d9d63a..d84afeac18523 100644 --- a/src/librustc_mir/borrow_check/nll/facts.rs +++ b/src/librustc_mir/borrow_check/nll/facts.rs @@ -15,7 +15,7 @@ crate type AllFacts = PoloniusAllFacts; crate trait AllFactsExt { /// Returns `true` if there is a need to gather `AllFacts` given the /// current `-Z` flags. - fn enabled(tcx: TyCtxt<'_, '_, '_>) -> bool; + fn enabled(tcx: TyCtxt<'_>) -> bool; fn write_to_dir( &self, @@ -26,7 +26,7 @@ crate trait AllFactsExt { impl AllFactsExt for AllFacts { /// Return - fn enabled(tcx: TyCtxt<'_, '_, '_>) -> bool { + fn enabled(tcx: TyCtxt<'_>) -> bool { tcx.sess.opts.debugging_opts.nll_facts || tcx.sess.opts.debugging_opts.polonius } @@ -72,18 +72,6 @@ impl Atom for BorrowIndex { } } -impl From for BorrowIndex { - fn from(i: usize) -> BorrowIndex { - BorrowIndex::new(i) - } -} - -impl From for usize { - fn from(vid: BorrowIndex) -> usize { - Idx::index(vid) - } -} - impl Atom for LocationIndex { fn index(self) -> usize { Idx::index(self) diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index aafbff3577647..c7b4a40305259 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -3,26 +3,25 @@ use crate::borrow_check::location::LocationTable; use crate::borrow_check::{JustWrite, WriteAndRead}; use crate::borrow_check::{AccessDepth, Deep, Shallow}; use crate::borrow_check::{ReadOrWrite, Activation, Read, Reservation, Write}; -use crate::borrow_check::{Context, ContextKind}; use crate::borrow_check::{LocalMutationIsAllowed, MutateMode}; use crate::borrow_check::ArtificialField; use crate::borrow_check::{ReadKind, WriteKind}; use crate::borrow_check::nll::facts::AllFacts; use crate::borrow_check::path_utils::*; -use crate::dataflow::move_paths::indexes::BorrowIndex; +use crate::dataflow::indexes::BorrowIndex; use rustc::ty::TyCtxt; use rustc::mir::visit::Visitor; -use rustc::mir::{BasicBlock, Location, Mir, Place, PlaceBase, Rvalue}; +use rustc::mir::{BasicBlock, Location, Body, Place, Rvalue}; use rustc::mir::{Statement, StatementKind}; -use rustc::mir::{Terminator, TerminatorKind}; +use rustc::mir::TerminatorKind; use rustc::mir::{Operand, BorrowKind}; use rustc_data_structures::graph::dominators::Dominators; -pub(super) fn generate_invalidates<'cx, 'gcx, 'tcx>( - tcx: TyCtxt<'cx, 'gcx, 'tcx>, +pub(super) fn generate_invalidates<'tcx>( + tcx: TyCtxt<'tcx>, all_facts: &mut Option, location_table: &LocationTable, - mir: &Mir<'tcx>, + body: &Body<'tcx>, borrow_set: &BorrowSet<'tcx>, ) { if all_facts.is_none() { @@ -31,34 +30,33 @@ pub(super) fn generate_invalidates<'cx, 'gcx, 'tcx>( } if let Some(all_facts) = all_facts { - let dominators = mir.dominators(); + let dominators = body.dominators(); let mut ig = InvalidationGenerator { all_facts, borrow_set, tcx, location_table, - mir, + body, dominators, }; - ig.visit_mir(mir); + ig.visit_body(body); } } -struct InvalidationGenerator<'cx, 'tcx: 'cx, 'gcx: 'tcx> { - tcx: TyCtxt<'cx, 'gcx, 'tcx>, +struct InvalidationGenerator<'cx, 'tcx> { + tcx: TyCtxt<'tcx>, all_facts: &'cx mut AllFacts, location_table: &'cx LocationTable, - mir: &'cx Mir<'tcx>, + body: &'cx Body<'tcx>, dominators: Dominators, borrow_set: &'cx BorrowSet<'tcx>, } /// Visits the whole MIR and generates `invalidates()` facts. /// Most of the code implementing this was stolen from `borrow_check/mod.rs`. -impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { +impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { fn visit_statement( &mut self, - block: BasicBlock, statement: &Statement<'tcx>, location: Location, ) { @@ -67,12 +65,12 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { match statement.kind { StatementKind::Assign(ref lhs, ref rhs) => { self.consume_rvalue( - ContextKind::AssignRhs.new(location), + location, rhs, ); self.mutate_place( - ContextKind::AssignLhs.new(location), + location, lhs, Shallow(None), JustWrite @@ -86,39 +84,34 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { variant_index: _, } => { self.mutate_place( - ContextKind::SetDiscrim.new(location), + location, place, Shallow(None), JustWrite, ); } - StatementKind::InlineAsm { - ref asm, - ref outputs, - ref inputs, - } => { - let context = ContextKind::InlineAsm.new(location); - for (o, output) in asm.outputs.iter().zip(outputs.iter()) { + StatementKind::InlineAsm(ref asm) => { + for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) { if o.is_indirect { // FIXME(eddyb) indirect inline asm outputs should - // be encoeded through MIR place derefs instead. + // be encoded through MIR place derefs instead. self.access_place( - context, + location, output, (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, ); } else { self.mutate_place( - context, + location, output, if o.is_rw { Deep } else { Shallow(None) }, if o.is_rw { WriteAndRead } else { JustWrite }, ); } } - for (_, input) in inputs.iter() { - self.consume_operand(context, input); + for (_, input) in asm.inputs.iter() { + self.consume_operand(location, input); } } StatementKind::Nop | @@ -130,33 +123,32 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { } StatementKind::StorageDead(local) => { self.access_place( - ContextKind::StorageDead.new(location), - &Place::Base(PlaceBase::Local(local)), + location, + &Place::from(local), (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, ); } } - self.super_statement(block, statement, location); + self.super_statement(statement, location); } - fn visit_terminator( + fn visit_terminator_kind( &mut self, - block: BasicBlock, - terminator: &Terminator<'tcx>, + kind: &TerminatorKind<'tcx>, location: Location ) { self.check_activations(location); - match terminator.kind { + match kind { TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _, } => { - self.consume_operand(ContextKind::SwitchInt.new(location), discr); + self.consume_operand(location, discr); } TerminatorKind::Drop { location: ref drop_place, @@ -164,7 +156,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { unwind: _, } => { self.access_place( - ContextKind::Drop.new(location), + location, drop_place, (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, @@ -177,13 +169,13 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { unwind: _, } => { self.mutate_place( - ContextKind::DropAndReplace.new(location), + location, drop_place, Deep, JustWrite, ); self.consume_operand( - ContextKind::DropAndReplace.new(location), + location, new_value, ); } @@ -194,13 +186,13 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { cleanup: _, from_hir_call: _, } => { - self.consume_operand(ContextKind::CallOperator.new(location), func); + self.consume_operand(location, func); for arg in args { - self.consume_operand(ContextKind::CallOperand.new(location), arg); + self.consume_operand(location, arg); } if let Some((ref dest, _ /*bb*/)) = *destination { self.mutate_place( - ContextKind::CallDest.new(location), + location, dest, Deep, JustWrite, @@ -214,11 +206,11 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { target: _, cleanup: _, } => { - self.consume_operand(ContextKind::Assert.new(location), cond); - use rustc::mir::interpret::EvalErrorKind::BoundsCheck; + self.consume_operand(location, cond); + use rustc::mir::interpret::InterpError::BoundsCheck; if let BoundsCheck { ref len, ref index } = *msg { - self.consume_operand(ContextKind::Assert.new(location), len); - self.consume_operand(ContextKind::Assert.new(location), index); + self.consume_operand(location, len); + self.consume_operand(location, index); } } TerminatorKind::Yield { @@ -226,7 +218,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { resume, drop: _, } => { - self.consume_operand(ContextKind::Yield.new(location), value); + self.consume_operand(location, value); // Invalidate all borrows of local places let borrow_set = self.borrow_set.clone(); @@ -252,7 +244,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { | TerminatorKind::Unreachable | TerminatorKind::FalseEdges { real_target: _, - imaginary_targets: _, + imaginary_target: _, } | TerminatorKind::FalseUnwind { real_target: _, @@ -262,21 +254,21 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { } } - self.super_terminator(block, terminator, location); + self.super_terminator_kind(kind, location); } } -impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { +impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { /// Simulates mutation of a place. fn mutate_place( &mut self, - context: Context, + location: Location, place: &Place<'tcx>, kind: AccessDepth, _mode: MutateMode, ) { self.access_place( - context, + location, place, (kind, Write(WriteKind::Mutate)), LocalMutationIsAllowed::ExceptUpvars, @@ -286,13 +278,13 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { /// Simulates consumption of an operand. fn consume_operand( &mut self, - context: Context, + location: Location, operand: &Operand<'tcx>, ) { match *operand { Operand::Copy(ref place) => { self.access_place( - context, + location, place, (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, @@ -300,7 +292,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { } Operand::Move(ref place) => { self.access_place( - context, + location, place, (Deep, Write(WriteKind::Move)), LocalMutationIsAllowed::Yes, @@ -313,7 +305,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { // Simulates consumption of an rvalue fn consume_rvalue( &mut self, - context: Context, + location: Location, rvalue: &Rvalue<'tcx>, ) { match *rvalue { @@ -325,7 +317,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), BorrowKind::Unique | BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); - if allow_two_phase_borrow(&self.tcx, bk) { + if allow_two_phase_borrow(bk) { (Deep, Reservation(wk)) } else { (Deep, Write(wk)) @@ -334,7 +326,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { }; self.access_place( - context, + location, place, access_kind, LocalMutationIsAllowed::No, @@ -345,7 +337,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { | Rvalue::Repeat(ref operand, _) | Rvalue::UnaryOp(_ /*un_op*/, ref operand) | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => { - self.consume_operand(context, operand) + self.consume_operand(location, operand) } Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => { @@ -355,7 +347,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { _ => unreachable!(), }; self.access_place( - context, + location, place, (Shallow(af), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, @@ -364,8 +356,8 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2) | Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => { - self.consume_operand(context, operand1); - self.consume_operand(context, operand2); + self.consume_operand(location, operand1); + self.consume_operand(location, operand2); } Rvalue::NullaryOp(_op, _ty) => { @@ -373,7 +365,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { Rvalue::Aggregate(_, ref operands) => { for operand in operands { - self.consume_operand(context, operand); + self.consume_operand(location, operand); } } } @@ -382,40 +374,40 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { /// Simulates an access to a place. fn access_place( &mut self, - context: Context, + location: Location, place: &Place<'tcx>, kind: (AccessDepth, ReadOrWrite), _is_local_mutation_allowed: LocalMutationIsAllowed, ) { let (sd, rw) = kind; // note: not doing check_access_permissions checks because they don't generate invalidates - self.check_access_for_conflict(context, place, sd, rw); + self.check_access_for_conflict(location, place, sd, rw); } fn check_access_for_conflict( &mut self, - context: Context, + location: Location, place: &Place<'tcx>, sd: AccessDepth, rw: ReadOrWrite, ) { debug!( - "invalidation::check_access_for_conflict(context={:?}, place={:?}, sd={:?}, \ + "invalidation::check_access_for_conflict(location={:?}, place={:?}, sd={:?}, \ rw={:?})", - context, + location, place, sd, rw, ); let tcx = self.tcx; - let mir = self.mir; + let body = self.body; let borrow_set = self.borrow_set.clone(); let indices = self.borrow_set.borrows.indices(); each_borrow_involving_path( self, tcx, - mir, - context, + body, + location, (sd, place), &borrow_set.clone(), indices, @@ -432,36 +424,35 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { // have already taken the reservation } - (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) - | (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) + (Read(_), BorrowKind::Shallow) + | (Read(_), BorrowKind::Shared) | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Unique) | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { - // Reads/reservations don't invalidate shared or shallow borrows + // Reads don't invalidate shared or shallow borrows } (Read(_), BorrowKind::Unique) | (Read(_), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. - if !is_active(&this.dominators, borrow, context.loc) { + if !is_active(&this.dominators, borrow, location) { // If the borrow isn't active yet, reads don't invalidate it - assert!(allow_two_phase_borrow(&this.tcx, borrow.kind)); + assert!(allow_two_phase_borrow(borrow.kind)); return Control::Continue; } // Unique and mutable borrows are invalidated by reads from any // involved path - this.generate_invalidates(borrow_index, context.loc); + this.generate_invalidates(borrow_index, location); } - (Reservation(_), BorrowKind::Unique) - | (Reservation(_), BorrowKind::Mut { .. }) - | (Activation(_, _), _) - | (Write(_), _) => { - // unique or mutable borrows are invalidated by writes. - // Reservations count as writes since we need to check - // that activating the borrow will be OK - // FIXME(bob_twinkles) is this actually the right thing to do? - this.generate_invalidates(borrow_index, context.loc); - } + (Reservation(_), _) + | (Activation(_, _), _) + | (Write(_), _) => { + // unique or mutable borrows are invalidated by writes. + // Reservations count as writes since we need to check + // that activating the borrow will be OK + // FIXME(bob_twinkles) is this actually the right thing to do? + this.generate_invalidates(borrow_index, location); + } } Control::Continue }, @@ -479,10 +470,6 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { &mut self, location: Location, ) { - if !self.tcx.two_phase_borrows() { - return; - } - // Two-phase borrow support: For each activation that is newly // generated at this statement, check if it interferes with // another borrow. @@ -496,7 +483,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { }); self.access_place( - ContextKind::Activation.new(location), + location, &borrow.borrowed_place, ( Deep, @@ -511,4 +498,3 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { } } } - diff --git a/src/librustc_mir/borrow_check/nll/member_constraints.rs b/src/librustc_mir/borrow_check/nll/member_constraints.rs new file mode 100644 index 0000000000000..b5e2e111f38e5 --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/member_constraints.rs @@ -0,0 +1,235 @@ +use crate::rustc::ty::{self, Ty}; +use rustc::hir::def_id::DefId; +use rustc::infer::region_constraints::MemberConstraint; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use std::hash::Hash; +use std::ops::Index; +use syntax_pos::Span; + +/// Compactly stores a set of `R0 member of [R1...Rn]` constraints, +/// indexed by the region `R0`. +crate struct MemberConstraintSet<'tcx, R> +where + R: Copy + Hash + Eq, +{ + /// Stores the first "member" constraint for a given `R0`. This is an + /// index into the `constraints` vector below. + first_constraints: FxHashMap, + + /// Stores the data about each `R0 member of [R1..Rn]` constraint. + /// These are organized into a linked list, so each constraint + /// contains the index of the next constraint with the same `R0`. + constraints: IndexVec>, + + /// Stores the `R1..Rn` regions for *all* sets. For any given + /// constraint, we keep two indices so that we can pull out a + /// slice. + choice_regions: Vec, +} + +/// Represents a `R0 member of [R1..Rn]` constraint +crate struct NllMemberConstraint<'tcx> { + next_constraint: Option, + + /// The opaque type whose hidden type is being inferred. (Used in error reporting.) + crate opaque_type_def_id: DefId, + + /// The span where the hidden type was instantiated. + crate definition_span: Span, + + /// The hidden type in which `R0` appears. (Used in error reporting.) + crate hidden_ty: Ty<'tcx>, + + /// The region `R0`. + crate member_region_vid: ty::RegionVid, + + /// Index of `R1` in `choice_regions` vector from `MemberConstraintSet`. + start_index: usize, + + /// Index of `Rn` in `choice_regions` vector from `MemberConstraintSet`. + end_index: usize, +} + +newtype_index! { + crate struct NllMemberConstraintIndex { + DEBUG_FORMAT = "MemberConstraintIndex({})" + } +} + +impl Default for MemberConstraintSet<'tcx, ty::RegionVid> { + fn default() -> Self { + Self { + first_constraints: Default::default(), + constraints: Default::default(), + choice_regions: Default::default(), + } + } +} + +impl<'tcx> MemberConstraintSet<'tcx, ty::RegionVid> { + /// Pushes a member constraint into the set. + /// + /// The input member constraint `m_c` is in the form produced by + /// the the `rustc::infer` code. + /// + /// The `to_region_vid` callback fn is used to convert the regions + /// within into `RegionVid` format -- it typically consults the + /// `UniversalRegions` data structure that is known to the caller + /// (but which this code is unaware of). + crate fn push_constraint( + &mut self, + m_c: &MemberConstraint<'tcx>, + mut to_region_vid: impl FnMut(ty::Region<'tcx>) -> ty::RegionVid, + ) { + debug!("push_constraint(m_c={:?})", m_c); + let member_region_vid: ty::RegionVid = to_region_vid(m_c.member_region); + let next_constraint = self.first_constraints.get(&member_region_vid).cloned(); + let start_index = self.choice_regions.len(); + let end_index = start_index + m_c.choice_regions.len(); + debug!("push_constraint: member_region_vid={:?}", member_region_vid); + let constraint_index = self.constraints.push(NllMemberConstraint { + next_constraint, + member_region_vid, + opaque_type_def_id: m_c.opaque_type_def_id, + definition_span: m_c.definition_span, + hidden_ty: m_c.hidden_ty, + start_index, + end_index, + }); + self.first_constraints.insert(member_region_vid, constraint_index); + self.choice_regions.extend(m_c.choice_regions.iter().map(|&r| to_region_vid(r))); + } +} + +impl MemberConstraintSet<'tcx, R1> +where + R1: Copy + Hash + Eq, +{ + /// Remap the "member region" key using `map_fn`, producing a new + /// member constraint set. This is used in the NLL code to map from + /// the original `RegionVid` to an scc index. In some cases, we + /// may have multiple `R1` values mapping to the same `R2` key -- that + /// is ok, the two sets will be merged. + crate fn into_mapped( + self, + mut map_fn: impl FnMut(R1) -> R2, + ) -> MemberConstraintSet<'tcx, R2> + where + R2: Copy + Hash + Eq, + { + // We can re-use most of the original data, just tweaking the + // linked list links a bit. + // + // For example if we had two keys `Ra` and `Rb` that both now + // wind up mapped to the same key `S`, we would append the + // linked list for `Ra` onto the end of the linked list for + // `Rb` (or vice versa) -- this basically just requires + // rewriting the final link from one list to point at the othe + // other (see `append_list`). + + let MemberConstraintSet { first_constraints, mut constraints, choice_regions } = self; + + let mut first_constraints2 = FxHashMap::default(); + first_constraints2.reserve(first_constraints.len()); + + for (r1, start1) in first_constraints { + let r2 = map_fn(r1); + if let Some(&start2) = first_constraints2.get(&r2) { + append_list(&mut constraints, start1, start2); + } + first_constraints2.insert(r2, start1); + } + + MemberConstraintSet { + first_constraints: first_constraints2, + constraints, + choice_regions, + } + } +} + +impl MemberConstraintSet<'tcx, R> +where + R: Copy + Hash + Eq, +{ + crate fn all_indices( + &self, + ) -> impl Iterator { + self.constraints.indices() + } + + /// Iterate down the constraint indices associated with a given + /// peek-region. You can then use `choice_regions` and other + /// methods to access data. + crate fn indices( + &self, + member_region_vid: R, + ) -> impl Iterator + '_ { + let mut next = self.first_constraints.get(&member_region_vid).cloned(); + std::iter::from_fn(move || -> Option { + if let Some(current) = next { + next = self.constraints[current].next_constraint; + Some(current) + } else { + None + } + }) + } + + /// Returns the "choice regions" for a given member + /// constraint. This is the `R1..Rn` from a constraint like: + /// + /// ``` + /// R0 member of [R1..Rn] + /// ``` + crate fn choice_regions(&self, pci: NllMemberConstraintIndex) -> &[ty::RegionVid] { + let NllMemberConstraint { start_index, end_index, .. } = &self.constraints[pci]; + &self.choice_regions[*start_index..*end_index] + } +} + +impl<'tcx, R> Index for MemberConstraintSet<'tcx, R> +where + R: Copy + Hash + Eq, +{ + type Output = NllMemberConstraint<'tcx>; + + fn index(&self, i: NllMemberConstraintIndex) -> &NllMemberConstraint<'tcx> { + &self.constraints[i] + } +} + +/// Given a linked list starting at `source_list` and another linked +/// list starting at `target_list`, modify `target_list` so that it is +/// followed by `source_list`. +/// +/// Before: +/// +/// ``` +/// target_list: A -> B -> C -> (None) +/// source_list: D -> E -> F -> (None) +/// ``` +/// +/// After: +/// +/// ``` +/// target_list: A -> B -> C -> D -> E -> F -> (None) +/// ``` +fn append_list( + constraints: &mut IndexVec>, + target_list: NllMemberConstraintIndex, + source_list: NllMemberConstraintIndex, +) { + let mut p = target_list; + loop { + let mut r = &mut constraints[p]; + match r.next_constraint { + Some(q) => p = q, + None => { + r.next_constraint = Some(source_list); + return; + } + } + } +} diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 84fdbb9423e0a..eb63e0de195e5 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -2,16 +2,16 @@ use crate::borrow_check::borrow_set::BorrowSet; use crate::borrow_check::location::{LocationIndex, LocationTable}; use crate::borrow_check::nll::facts::AllFactsExt; use crate::borrow_check::nll::type_check::{MirTypeckResults, MirTypeckRegionConstraints}; -use crate::borrow_check::nll::type_check::liveness::liveness_map::NllLivenessMap; use crate::borrow_check::nll::region_infer::values::RegionValueElements; use crate::dataflow::indexes::BorrowIndex; use crate::dataflow::move_paths::MoveData; use crate::dataflow::FlowAtLocation; use crate::dataflow::MaybeInitializedPlaces; use crate::transform::MirSource; +use crate::borrow_check::Upvar; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; -use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Mir}; +use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Body}; use rustc::ty::{self, RegionKind, RegionVid}; use rustc_errors::Diagnostic; use std::fmt::Debug; @@ -20,6 +20,7 @@ use std::io; use std::path::PathBuf; use std::rc::Rc; use std::str::FromStr; +use syntax::symbol::sym; use self::mir_util::PassWhere; use polonius_engine::{Algorithm, Output}; @@ -36,6 +37,7 @@ crate mod type_check; mod universal_regions; mod constraints; +mod member_constraints; use self::facts::AllFacts; use self::region_infer::RegionInferenceContext; @@ -45,11 +47,11 @@ use self::universal_regions::UniversalRegions; /// scraping out the set of universal regions (e.g., region parameters) /// declared on the function. That set will need to be given to /// `compute_regions`. -pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'gcx, 'tcx>( - infcx: &InferCtxt<'cx, 'gcx, 'tcx>, +pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, def_id: DefId, param_env: ty::ParamEnv<'tcx>, - mir: &mut Mir<'tcx>, + body: &mut Body<'tcx>, ) -> UniversalRegions<'tcx> { debug!("replace_regions_in_mir(def_id={:?})", def_id); @@ -57,10 +59,10 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'gcx, 'tcx>( let universal_regions = UniversalRegions::new(infcx, def_id, param_env); // Replace all remaining regions with fresh inference variables. - renumber::renumber_mir(infcx, mir); + renumber::renumber_mir(infcx, body); let source = MirSource::item(def_id); - mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, mir, |_, _| Ok(())); + mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body, |_, _| Ok(())); universal_regions } @@ -68,21 +70,22 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'gcx, 'tcx>( /// Computes the (non-lexical) regions from the input MIR. /// /// This may result in errors being reported. -pub(in crate::borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( - infcx: &InferCtxt<'cx, 'gcx, 'tcx>, +pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, def_id: DefId, universal_regions: UniversalRegions<'tcx>, - mir: &Mir<'tcx>, + body: &Body<'tcx>, + upvars: &[Upvar], location_table: &LocationTable, - param_env: ty::ParamEnv<'gcx>, - flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>, + param_env: ty::ParamEnv<'tcx>, + flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'cx, 'tcx>>, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, errors_buffer: &mut Vec, ) -> ( RegionInferenceContext<'tcx>, Option>>, - Option>, + Option>, ) { let mut all_facts = if AllFacts::enabled(infcx.tcx) { Some(AllFacts::default()) @@ -92,7 +95,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( let universal_regions = Rc::new(universal_regions); - let elements = &Rc::new(RegionValueElements::new(mir)); + let elements = &Rc::new(RegionValueElements::new(body)); // Run the MIR type-checker. let MirTypeckResults { @@ -101,7 +104,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( } = type_check::type_check( infcx, param_env, - mir, + body, def_id, &universal_regions, location_table, @@ -127,6 +130,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( placeholder_index_to_region: _, mut liveness_constraints, outlives_constraints, + member_constraints, closure_bounds_mapping, type_tests, } = constraints; @@ -137,7 +141,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( &mut liveness_constraints, &mut all_facts, location_table, - &mir, + &body, borrow_set, ); @@ -146,8 +150,9 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( universal_regions, placeholder_indices, universal_region_relations, - mir, + body, outlives_constraints, + member_constraints, closure_bounds_mapping, type_tests, liveness_constraints, @@ -159,7 +164,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( infcx.tcx, &mut all_facts, location_table, - &mir, + &body, borrow_set, ); @@ -174,7 +179,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( if infcx.tcx.sess.opts.debugging_opts.polonius { let algorithm = env::var("POLONIUS_ALGORITHM") - .unwrap_or_else(|_| String::from("DatafrogOpt")); + .unwrap_or_else(|_| String::from("Hybrid")); let algorithm = Algorithm::from_str(&algorithm).unwrap(); debug!("compute_regions: using polonius algorithm {:?}", algorithm); Some(Rc::new(Output::compute( @@ -188,29 +193,30 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( }); // Solve the region constraints. - let closure_region_requirements = regioncx.solve(infcx, &mir, def_id, errors_buffer); + let closure_region_requirements = + regioncx.solve(infcx, &body, upvars, def_id, errors_buffer); // Dump MIR results into a file, if that is enabled. This let us // write unit-tests, as well as helping with debugging. dump_mir_results( infcx, MirSource::item(def_id), - &mir, + &body, ®ioncx, &closure_region_requirements, ); // We also have a `#[rustc_nll]` annotation that causes us to dump // information - dump_annotation(infcx, &mir, def_id, ®ioncx, &closure_region_requirements, errors_buffer); + dump_annotation(infcx, &body, def_id, ®ioncx, &closure_region_requirements, errors_buffer); (regioncx, polonius_output, closure_region_requirements) } -fn dump_mir_results<'a, 'gcx, 'tcx>( - infcx: &InferCtxt<'a, 'gcx, 'tcx>, +fn dump_mir_results<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, source: MirSource<'tcx>, - mir: &Mir<'tcx>, + body: &Body<'tcx>, regioncx: &RegionInferenceContext<'_>, closure_region_requirements: &Option>, ) { @@ -224,7 +230,7 @@ fn dump_mir_results<'a, 'gcx, 'tcx>( "nll", &0, source, - mir, + body, |pass_where, out| { match pass_where { // Before the CFG, dump out the values for each region variable. @@ -268,9 +274,9 @@ fn dump_mir_results<'a, 'gcx, 'tcx>( }; } -fn dump_annotation<'a, 'gcx, 'tcx>( - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - mir: &Mir<'tcx>, +fn dump_annotation<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + body: &Body<'tcx>, mir_def_id: DefId, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, @@ -278,7 +284,7 @@ fn dump_annotation<'a, 'gcx, 'tcx>( ) { let tcx = infcx.tcx; let base_def_id = tcx.closure_base_def_id(mir_def_id); - if !tcx.has_attr(base_def_id, "rustc_regions") { + if !tcx.has_attr(base_def_id, sym::rustc_regions) { return; } @@ -293,7 +299,7 @@ fn dump_annotation<'a, 'gcx, 'tcx>( let mut err = tcx .sess .diagnostic() - .span_note_diag(mir.span, "External requirements"); + .span_note_diag(body.span, "External requirements"); regioncx.annotate(tcx, &mut err); @@ -314,7 +320,7 @@ fn dump_annotation<'a, 'gcx, 'tcx>( let mut err = tcx .sess .diagnostic() - .span_note_diag(mir.span, "No external requirements"); + .span_note_diag(body.span, "No external requirements"); regioncx.annotate(tcx, &mut err); err.buffer(errors_buffer); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs index 419ee73b28ad3..d4f6ce8801e63 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs @@ -71,7 +71,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - let mut constraints: Vec<_> = self.constraints.iter().collect(); + let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); constraints.sort(); for constraint in &constraints { let OutlivesConstraint { @@ -92,4 +92,3 @@ impl<'tcx> RegionInferenceContext<'tcx> { Ok(()) } } - diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs index 081c458bfc17a..9e08961f440f2 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs @@ -1,20 +1,22 @@ use crate::borrow_check::nll::constraints::OutlivesConstraint; +use crate::borrow_check::nll::region_infer::AppliedMemberConstraint; use crate::borrow_check::nll::region_infer::RegionInferenceContext; use crate::borrow_check::nll::type_check::Locations; use crate::borrow_check::nll::universal_regions::DefiningTy; use crate::borrow_check::nll::ConstraintDescription; use crate::util::borrowck_errors::{BorrowckErrors, Origin}; +use crate::borrow_check::Upvar; use rustc::hir::def_id::DefId; use rustc::infer::error_reporting::nice_region_error::NiceRegionError; use rustc::infer::InferCtxt; use rustc::infer::NLLRegionVariableOrigin; -use rustc::mir::{ConstraintCategory, Location, Mir}; +use rustc::mir::{ConstraintCategory, Location, Body}; use rustc::ty::{self, RegionVid}; use rustc_data_structures::indexed_vec::IndexVec; use rustc_errors::{Diagnostic, DiagnosticBuilder}; use std::collections::VecDeque; use syntax::errors::Applicability; -use syntax::symbol::keywords; +use syntax::symbol::kw; use syntax_pos::Span; mod region_name; @@ -61,7 +63,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// path to blame. fn best_blame_constraint( &self, - mir: &Mir<'tcx>, + body: &Body<'tcx>, from_region: RegionVid, target_test: impl Fn(RegionVid) -> bool, ) -> (ConstraintCategory, bool, Span) { @@ -87,9 +89,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut categorized_path: Vec<(ConstraintCategory, bool, Span)> = path.iter() .map(|constraint| { if constraint.category == ConstraintCategory::ClosureBounds { - self.retrieve_closure_constraint_info(mir, &constraint) + self.retrieve_closure_constraint_info(body, &constraint) } else { - (constraint.category, false, constraint.locations.span(mir)) + (constraint.category, false, constraint.locations.span(body)) } }) .collect(); @@ -132,6 +134,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { } }); if let Some(i) = best_choice { + if let Some(next) = categorized_path.get(i + 1) { + if categorized_path[i].0 == ConstraintCategory::Return + && next.0 == ConstraintCategory::OpaqueType + { + // The return expression is being influenced by the return type being + // impl Trait, point at the return type and not the return expr. + return *next; + } + } return categorized_path[i]; } @@ -185,6 +196,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { Trace::NotVisited => { bug!("found unvisited region {:?} on path to {:?}", p, r) } + Trace::FromOutlivesConstraint(c) => { result.push(c); p = c.sup; @@ -201,10 +213,30 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Otherwise, walk over the outgoing constraints and // enqueue any regions we find, keeping track of how we // reached them. + + // A constraint like `'r: 'x` can come from our constraint + // graph. let fr_static = self.universal_regions.fr_static; - for constraint in self.constraint_graph - .outgoing_edges(r, &self.constraints, fr_static) - { + let outgoing_edges_from_graph = self.constraint_graph + .outgoing_edges(r, &self.constraints, fr_static); + + + // But member constraints can also give rise to `'r: 'x` + // edges that were not part of the graph initially, so + // watch out for those. + let outgoing_edges_from_picks = self.applied_member_constraints(r) + .iter() + .map(|&AppliedMemberConstraint { min_choice, member_constraint_index, .. }| { + let p_c = &self.member_constraints[member_constraint_index]; + OutlivesConstraint { + sup: r, + sub: min_choice, + locations: Locations::All(p_c.definition_span), + category: ConstraintCategory::OpaqueType, + } + }); + + for constraint in outgoing_edges_from_graph.chain(outgoing_edges_from_picks) { debug_assert_eq!(constraint.sup, r); let sub_region = constraint.sub; if let Trace::NotVisited = context[sub_region] { @@ -227,8 +259,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`. pub(super) fn report_error( &self, - mir: &Mir<'tcx>, - infcx: &InferCtxt<'_, '_, 'tcx>, + body: &Body<'tcx>, + upvars: &[Upvar], + infcx: &InferCtxt<'_, 'tcx>, mir_def_id: DefId, fr: RegionVid, outlived_fr: RegionVid, @@ -236,10 +269,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) { debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); - let (category, _, span) = self.best_blame_constraint(mir, fr, |r| { + let (category, _, span) = self.best_blame_constraint(body, fr, |r| { self.provides_universal_region(r, fr, outlived_fr) }); + debug!("report_error: category={:?} {:?}", category, span); // Check if we can use one of the "nice region errors". if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { let tables = infcx.tcx.typeck_tables_of(mir_def_id); @@ -262,7 +296,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { match (category, fr_is_local, outlived_fr_is_local) { (ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) => { self.report_fnmut_error( - mir, + body, + upvars, infcx, mir_def_id, fr, @@ -273,7 +308,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } (ConstraintCategory::Assignment, true, false) | (ConstraintCategory::CallArgument, true, false) => self.report_escaping_data_error( - mir, + body, + upvars, infcx, mir_def_id, fr, @@ -283,7 +319,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { errors_buffer, ), _ => self.report_general_error( - mir, + body, + upvars, infcx, mir_def_id, fr, @@ -342,8 +379,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// ``` fn report_fnmut_error( &self, - mir: &Mir<'tcx>, - infcx: &InferCtxt<'_, '_, 'tcx>, + body: &Body<'tcx>, + upvars: &[Upvar], + infcx: &InferCtxt<'_, 'tcx>, mir_def_id: DefId, _fr: RegionVid, outlived_fr: RegionVid, @@ -367,7 +405,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { diag.span_label(span, message); - match self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, &mut 1).unwrap().source { + match self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_fr, &mut 1) + .unwrap().source + { RegionNameSource::NamedEarlyBoundRegion(fr_span) | RegionNameSource::NamedFreeRegion(fr_span) | RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _) @@ -404,8 +444,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// ``` fn report_escaping_data_error( &self, - mir: &Mir<'tcx>, - infcx: &InferCtxt<'_, '_, 'tcx>, + body: &Body<'tcx>, + upvars: &[Upvar], + infcx: &InferCtxt<'_, 'tcx>, mir_def_id: DefId, fr: RegionVid, outlived_fr: RegionVid, @@ -413,9 +454,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { span: Span, errors_buffer: &mut Vec, ) { - let fr_name_and_span = self.get_var_name_and_span_for_region(infcx.tcx, mir, fr); + let fr_name_and_span = + self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, fr); let outlived_fr_name_and_span = - self.get_var_name_and_span_for_region(infcx.tcx, mir, outlived_fr); + self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, outlived_fr); let escapes_from = match self.universal_regions.defining_ty { DefiningTy::Closure(..) => "closure", @@ -431,7 +473,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { || escapes_from == "const" { return self.report_general_error( - mir, + body, + upvars, infcx, mir_def_id, fr, @@ -493,8 +536,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// ``` fn report_general_error( &self, - mir: &Mir<'tcx>, - infcx: &InferCtxt<'_, '_, 'tcx>, + body: &Body<'tcx>, + upvars: &[Upvar], + infcx: &InferCtxt<'_, 'tcx>, mir_def_id: DefId, fr: RegionVid, fr_is_local: bool, @@ -510,10 +554,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); let counter = &mut 1; - let fr_name = self.give_region_a_name(infcx, mir, mir_def_id, fr, counter).unwrap(); + let fr_name = self.give_region_a_name( + infcx, body, upvars, mir_def_id, fr, counter).unwrap(); fr_name.highlight_region_name(&mut diag); let outlived_fr_name = - self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, counter).unwrap(); + self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_fr, counter).unwrap(); outlived_fr_name.highlight_region_name(&mut diag); let mir_def_name = if infcx.tcx.is_closure(mir_def_id) { @@ -554,7 +599,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Adds a suggestion to errors where a `impl Trait` is returned. /// /// ```text - /// help: to allow this impl Trait to capture borrowed data with lifetime `'1`, add `'_` as + /// help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as /// a constraint /// | /// LL | fn iter_values_anon(&self) -> impl Iterator + 'a { @@ -562,7 +607,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// ``` fn add_static_impl_trait_suggestion( &self, - infcx: &InferCtxt<'_, '_, 'tcx>, + infcx: &InferCtxt<'_, 'tcx>, diag: &mut DiagnosticBuilder<'_>, fr: RegionVid, // We need to pass `fr_name` - computing it again will label it twice. @@ -573,7 +618,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { (self.to_error_region(fr), self.to_error_region(outlived_fr)) { if let Some(ty::TyS { - sty: ty::TyKind::Opaque(did, substs), + sty: ty::Opaque(did, substs), .. }) = infcx .tcx @@ -609,7 +654,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { "add_static_impl_trait_suggestion: has_static_predicate={:?}", has_static_predicate ); - let static_str = keywords::StaticLifetime.name(); + let static_str = kw::StaticLifetime; // If there is a static predicate, then the only sensible suggestion is to replace // fr with `'static`. if has_static_predicate { @@ -630,7 +675,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { diag.span_suggestion( span, &format!( - "to allow this impl Trait to capture borrowed data with lifetime \ + "to allow this `impl Trait` to capture borrowed data with lifetime \ `{}`, add `{}` as a constraint", fr_name, suggestable_fr_name, ), @@ -645,22 +690,30 @@ impl<'tcx> RegionInferenceContext<'tcx> { crate fn free_region_constraint_info( &self, - mir: &Mir<'tcx>, + body: &Body<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, - infcx: &InferCtxt<'_, '_, 'tcx>, + infcx: &InferCtxt<'_, 'tcx>, borrow_region: RegionVid, outlived_region: RegionVid, ) -> (ConstraintCategory, bool, Span, Option) { - let (category, from_closure, span) = - self.best_blame_constraint(mir, borrow_region, |r| r == outlived_region); + let (category, from_closure, span) = self.best_blame_constraint( + body, + borrow_region, + |r| self.provides_universal_region(r, borrow_region, outlived_region) + ); let outlived_fr_name = - self.give_region_a_name(infcx, mir, mir_def_id, outlived_region, &mut 1); + self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_region, &mut 1); (category, from_closure, span, outlived_fr_name) } // Finds some region R such that `fr1: R` and `R` is live at // `elem`. - crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid { + crate fn find_sub_region_live_at( + &self, + fr1: RegionVid, + elem: Location, + ) -> RegionVid { debug!("find_sub_region_live_at(fr1={:?}, elem={:?})", fr1, elem); self.find_constraint_paths_between_regions(fr1, |r| { // First look for some `r` such that `fr1: r` and `r` is live at `elem` @@ -698,18 +751,21 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Finds a good span to blame for the fact that `fr1` outlives `fr2`. crate fn find_outlives_blame_span( &self, - mir: &Mir<'tcx>, + body: &Body<'tcx>, fr1: RegionVid, fr2: RegionVid, ) -> (ConstraintCategory, Span) { - let (category, _, span) = - self.best_blame_constraint(mir, fr1, |r| self.provides_universal_region(r, fr1, fr2)); + let (category, _, span) = self.best_blame_constraint( + body, + fr1, + |r| self.provides_universal_region(r, fr1, fr2), + ); (category, span) } fn retrieve_closure_constraint_info( &self, - mir: &Mir<'tcx>, + body: &Body<'tcx>, constraint: &OutlivesConstraint, ) -> (ConstraintCategory, bool, Span) { let loc = match constraint.locations { @@ -721,11 +777,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub)); opt_span_category .map(|&(category, span)| (category, true, span)) - .unwrap_or((constraint.category, false, mir.source_info(loc).span)) + .unwrap_or((constraint.category, false, body.source_info(loc).span)) } /// Returns `true` if a closure is inferred to be an `FnMut` closure. - crate fn is_closure_fn_mut(&self, infcx: &InferCtxt<'_, '_, 'tcx>, fr: RegionVid) -> bool { + crate fn is_closure_fn_mut(&self, infcx: &InferCtxt<'_, 'tcx>, fr: RegionVid) -> bool { if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) { if let ty::BoundRegion::BrEnv = free_region.bound_region { if let DefiningTy::Closure(def_id, substs) = self.universal_regions.defining_ty { diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index cc01f632e075c..3f5b2f4bce78b 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -2,16 +2,17 @@ use std::fmt::{self, Display}; use crate::borrow_check::nll::region_infer::RegionInferenceContext; use crate::borrow_check::nll::universal_regions::DefiningTy; use crate::borrow_check::nll::ToRegionVid; +use crate::borrow_check::Upvar; use rustc::hir; +use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; -use rustc::mir::Mir; +use rustc::mir::Body; use rustc::ty::subst::{SubstsRef, UnpackedKind}; use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt}; -use rustc::util::ppaux::RegionHighlightMode; +use rustc::ty::print::RegionHighlightMode; use rustc_errors::DiagnosticBuilder; -use syntax::ast::Name; -use syntax::symbol::keywords; +use syntax::symbol::kw; use syntax_pos::Span; use syntax_pos::symbol::InternedString; @@ -32,6 +33,7 @@ crate enum RegionNameSource { MatchedAdtAndSegment(Span), AnonRegionFromUpvar(Span, String), AnonRegionFromOutput(Span, String, String), + AnonRegionFromYieldTy(Span, String), } impl RegionName { @@ -46,7 +48,8 @@ impl RegionName { RegionNameSource::MatchedHirTy(..) | RegionNameSource::MatchedAdtAndSegment(..) | RegionNameSource::AnonRegionFromUpvar(..) | - RegionNameSource::AnonRegionFromOutput(..) => false, + RegionNameSource::AnonRegionFromOutput(..) | + RegionNameSource::AnonRegionFromYieldTy(..) => false, } } @@ -56,8 +59,8 @@ impl RegionName { } #[allow(dead_code)] - crate fn name(&self) -> &InternedString { - &self.name + crate fn name(&self) -> InternedString { + self.name } crate fn highlight_region_name( @@ -103,6 +106,12 @@ impl RegionName { format!("return type{} is {}", mir_description, type_name), ); }, + RegionNameSource::AnonRegionFromYieldTy(span, type_name) => { + diag.span_label( + *span, + format!("yield type is {}", type_name), + ); + } RegionNameSource::Static => {}, } } @@ -142,8 +151,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// and then return the name `'1` for us to use. crate fn give_region_a_name( &self, - infcx: &InferCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, fr: RegionVid, counter: &mut usize, @@ -155,17 +165,22 @@ impl<'tcx> RegionInferenceContext<'tcx> { let value = self.give_name_from_error_region(infcx.tcx, mir_def_id, fr, counter) .or_else(|| { self.give_name_if_anonymous_region_appears_in_arguments( - infcx, mir, mir_def_id, fr, counter, + infcx, body, mir_def_id, fr, counter, ) }) .or_else(|| { self.give_name_if_anonymous_region_appears_in_upvars( - infcx.tcx, mir, fr, counter, + infcx.tcx, upvars, fr, counter, ) }) .or_else(|| { self.give_name_if_anonymous_region_appears_in_output( - infcx, mir, mir_def_id, fr, counter, + infcx, body, mir_def_id, fr, counter, + ) + }) + .or_else(|| { + self.give_name_if_anonymous_region_appears_in_yield_ty( + infcx, body, mir_def_id, fr, counter, ) }); @@ -179,7 +194,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// named variants. fn give_name_from_error_region( &self, - tcx: TyCtxt<'_, '_, 'tcx>, + tcx: TyCtxt<'tcx>, mir_def_id: DefId, fr: RegionVid, counter: &mut usize, @@ -190,7 +205,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { match error_region { ty::ReEarlyBound(ebr) => { if ebr.has_name() { - let span = self.get_named_span(tcx, error_region, &ebr.name); + let span = self.get_named_span(tcx, error_region, ebr.name); Some(RegionName { name: ebr.name, source: RegionNameSource::NamedEarlyBoundRegion(span) @@ -201,13 +216,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { } ty::ReStatic => Some(RegionName { - name: keywords::StaticLifetime.name().as_interned_str(), + name: kw::StaticLifetime.as_interned_str(), source: RegionNameSource::Static }), ty::ReFree(free_region) => match free_region.bound_region { ty::BoundRegion::BrNamed(_, name) => { - let span = self.get_named_span(tcx, error_region, &name); + let span = self.get_named_span(tcx, error_region, name); Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span), @@ -215,14 +230,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { }, ty::BoundRegion::BrEnv => { - let mir_node_id = tcx.hir() - .as_local_node_id(mir_def_id) - .expect("non-local mir"); + let mir_hir_id = tcx.hir() + .as_local_hir_id(mir_def_id) + .expect("non-local mir"); let def_ty = self.universal_regions.defining_ty; if let DefiningTy::Closure(def_id, substs) = def_ty { let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) = - tcx.hir().expect_expr(mir_node_id).node + tcx.hir().expect_expr(mir_hir_id).node { span } else { @@ -259,7 +274,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - ty::BoundRegion::BrAnon(_) | ty::BoundRegion::BrFresh(_) => None, + ty::BoundRegion::BrAnon(_) => None, }, ty::ReLateBound(..) @@ -288,14 +303,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// ``` fn get_named_span( &self, - tcx: TyCtxt<'_, '_, 'tcx>, + tcx: TyCtxt<'tcx>, error_region: &RegionKind, - name: &InternedString, + name: InternedString, ) -> Span { let scope = error_region.free_region_binding_scope(tcx); let node = tcx.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID); - let span = tcx.sess.source_map().def_span(tcx.hir().span_by_hir_id(node)); + let span = tcx.sess.source_map().def_span(tcx.hir().span(node)); if let Some(param) = tcx.hir() .get_generics(scope) .and_then(|generics| generics.get_named(name)) @@ -316,8 +331,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// ``` fn give_name_if_anonymous_region_appears_in_arguments( &self, - infcx: &InferCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, mir_def_id: DefId, fr: RegionVid, counter: &mut usize, @@ -329,7 +344,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index]; if let Some(region_name) = self.give_name_if_we_can_match_hir_ty_from_argument( infcx, - mir, + body, mir_def_id, fr, arg_ty, @@ -339,21 +354,21 @@ impl<'tcx> RegionInferenceContext<'tcx> { return Some(region_name); } - self.give_name_if_we_cannot_match_hir_ty(infcx, mir, fr, arg_ty, counter) + self.give_name_if_we_cannot_match_hir_ty(infcx, body, fr, arg_ty, counter) } fn give_name_if_we_can_match_hir_ty_from_argument( &self, - infcx: &InferCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, mir_def_id: DefId, needle_fr: RegionVid, argument_ty: Ty<'tcx>, argument_index: usize, counter: &mut usize, ) -> Option { - let mir_node_id = infcx.tcx.hir().as_local_node_id(mir_def_id)?; - let fn_decl = infcx.tcx.hir().fn_decl(mir_node_id)?; + let mir_hir_id = infcx.tcx.hir().as_local_hir_id(mir_def_id)?; + let fn_decl = infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?; let argument_hir_ty: &hir::Ty = &fn_decl.inputs[argument_index]; match argument_hir_ty.node { // This indicates a variable with no type annotation, like @@ -361,7 +376,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // must highlight the variable. hir::TyKind::Infer => self.give_name_if_we_cannot_match_hir_ty( infcx, - mir, + body, needle_fr, argument_ty, counter, @@ -390,15 +405,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// ``` fn give_name_if_we_cannot_match_hir_ty( &self, - infcx: &InferCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, needle_fr: RegionVid, argument_ty: Ty<'tcx>, counter: &mut usize, ) -> Option { - let type_name = RegionHighlightMode::highlighting_region_vid(needle_fr, *counter, || { - infcx.extract_type_name(&argument_ty) - }); + let mut highlight = RegionHighlightMode::default(); + highlight.highlighting_region_vid(needle_fr, *counter); + let type_name = infcx.extract_type_name(&argument_ty, Some(highlight)); debug!( "give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", @@ -407,7 +422,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() { // Only add a label if we can confirm that a region was labelled. let argument_index = self.get_argument_index_for_region(infcx.tcx, needle_fr)?; - let (_, span) = self.get_argument_name_and_span_for_region(mir, argument_index); + let (_, span) = self.get_argument_name_and_span_for_region(body, argument_index); Some(RegionName { // This counter value will already have been used, so this function will increment @@ -446,7 +461,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// to highlighting that closest type instead. fn give_name_if_we_can_match_hir_ty( &self, - tcx: TyCtxt<'_, '_, 'tcx>, + tcx: TyCtxt<'tcx>, needle_fr: RegionVid, argument_ty: Ty<'tcx>, argument_hir_ty: &hir::Ty, @@ -489,12 +504,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { ty::Adt(_adt_def, substs), hir::TyKind::Path(hir::QPath::Resolved(None, path)), ) => { - match path.def { + match path.res { // Type parameters of the type alias have no reason to // be the same as those of the ADT. // FIXME: We should be able to do something similar to // match_adt_and_segment in this case. - hir::def::Def::TyAlias(_) => (), + Res::Def(DefKind::TyAlias, _) => (), _ => if let Some(last_segment) = path.segments.last() { if let Some(name) = self.match_adt_and_segment( substs, @@ -513,7 +528,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // just worry about trying to match up the rustc type // with the HIR types: (ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => { - search_stack.extend(elem_tys.iter().cloned().zip(elem_hir_tys)); + search_stack.extend(elem_tys.iter().map(|k| k.expect_ty()).zip(elem_hir_tys)); } (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty)) @@ -604,7 +619,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { search_stack.push((ty, hir_ty)); } - (UnpackedKind::Lifetime(_), _) | (UnpackedKind::Type(_), _) => { + (UnpackedKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => { + // Lifetimes cannot be found in consts, so we don't need + // to search anything here. + } + + (UnpackedKind::Lifetime(_), _) + | (UnpackedKind::Type(_), _) + | (UnpackedKind::Const(_), _) => { // I *think* that HIR lowering should ensure this // doesn't happen, even in erroneous // programs. Else we should use delay-span-bug. @@ -631,14 +653,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// ``` fn give_name_if_anonymous_region_appears_in_upvars( &self, - tcx: TyCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + tcx: TyCtxt<'tcx>, + upvars: &[Upvar], fr: RegionVid, counter: &mut usize, ) -> Option { let upvar_index = self.get_upvar_index_for_region(tcx, fr)?; let (upvar_name, upvar_span) = - self.get_upvar_name_and_span_for_region(tcx, mir, upvar_index); + self.get_upvar_name_and_span_for_region(tcx, upvars, upvar_index); let region_name = self.synthesize_region_name(counter); Some(RegionName { @@ -653,8 +675,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// or be early bound (named, not in argument). fn give_name_if_anonymous_region_appears_in_output( &self, - infcx: &InferCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, mir_def_id: DefId, fr: RegionVid, counter: &mut usize, @@ -666,20 +688,17 @@ impl<'tcx> RegionInferenceContext<'tcx> { "give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty ); - if !infcx - .tcx - .any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) - { + if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) { return None; } - let type_name = RegionHighlightMode::highlighting_region_vid( - fr, *counter, || infcx.extract_type_name(&return_ty), - ); + let mut highlight = RegionHighlightMode::default(); + highlight.highlighting_region_vid(fr, *counter); + let type_name = infcx.extract_type_name(&return_ty, Some(highlight)); - let mir_node_id = tcx.hir().as_local_node_id(mir_def_id).expect("non-local mir"); + let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir"); - let (return_span, mir_description) = match tcx.hir().get(mir_node_id) { + let (return_span, mir_description) = match tcx.hir().get(mir_hir_id) { hir::Node::Expr(hir::Expr { node: hir::ExprKind::Closure(_, return_ty, _, span, gen_move), .. @@ -698,7 +717,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { node: hir::ImplItemKind::Method(method_sig, _), .. }) => (method_sig.decl.output.span(), ""), - _ => (mir.span, ""), + _ => (body.span, ""), }; Some(RegionName { @@ -714,12 +733,63 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) } + fn give_name_if_anonymous_region_appears_in_yield_ty( + &self, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, + mir_def_id: DefId, + fr: RegionVid, + counter: &mut usize, + ) -> Option { + // Note: generators from `async fn` yield `()`, so we don't have to + // worry about them here. + let yield_ty = self.universal_regions.yield_ty?; + debug!( + "give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}", + yield_ty, + ); + + let tcx = infcx.tcx; + + if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) { + return None; + } + + let mut highlight = RegionHighlightMode::default(); + highlight.highlighting_region_vid(fr, *counter); + let type_name = infcx.extract_type_name(&yield_ty, Some(highlight)); + + let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir"); + + let yield_span = match tcx.hir().get(mir_hir_id) { + hir::Node::Expr(hir::Expr { + node: hir::ExprKind::Closure(_, _, _, span, _), + .. + }) => ( + tcx.sess.source_map().end_point(*span) + ), + _ => body.span, + }; + + debug!( + "give_name_if_anonymous_region_appears_in_yield_ty: \ + type_name = {:?}, yield_span = {:?}", + yield_span, + type_name, + ); + + Some(RegionName { + name: self.synthesize_region_name(counter), + source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name), + }) + } + /// Creates a synthetic region named `'1`, incrementing the /// counter. fn synthesize_region_name(&self, counter: &mut usize) -> InternedString { let c = *counter; *counter += 1; - Name::intern(&format!("'{:?}", c)).as_interned_str() + InternedString::intern(&format!("'{:?}", c)) } } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs index f6bbaf2db0383..750a1324faeb3 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs @@ -1,6 +1,7 @@ use crate::borrow_check::nll::region_infer::RegionInferenceContext; use crate::borrow_check::nll::ToRegionVid; -use rustc::mir::{Local, Mir}; +use crate::borrow_check::Upvar; +use rustc::mir::{Local, Body}; use rustc::ty::{RegionVid, TyCtxt}; use rustc_data_structures::indexed_vec::Idx; use syntax::source_map::Span; @@ -9,8 +10,9 @@ use syntax_pos::symbol::Symbol; impl<'tcx> RegionInferenceContext<'tcx> { crate fn get_var_name_and_span_for_region( &self, - tcx: TyCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + upvars: &[Upvar], fr: RegionVid, ) -> Option<(Option, Span)> { debug!("get_var_name_and_span_for_region(fr={:?})", fr); @@ -19,22 +21,19 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("get_var_name_and_span_for_region: attempting upvar"); self.get_upvar_index_for_region(tcx, fr) .map(|index| { - let (name, span) = self.get_upvar_name_and_span_for_region(tcx, mir, index); + let (name, span) = + self.get_upvar_name_and_span_for_region(tcx, upvars, index); (Some(name), span) }) .or_else(|| { debug!("get_var_name_and_span_for_region: attempting argument"); self.get_argument_index_for_region(tcx, fr) - .map(|index| self.get_argument_name_and_span_for_region(mir, index)) + .map(|index| self.get_argument_name_and_span_for_region(body, index)) }) } /// Search the upvars (if any) to find one that references fr. Return its index. - crate fn get_upvar_index_for_region( - &self, - tcx: TyCtxt<'_, '_, 'tcx>, - fr: RegionVid, - ) -> Option { + crate fn get_upvar_index_for_region(&self, tcx: TyCtxt<'tcx>, fr: RegionVid) -> Option { let upvar_index = self .universal_regions .defining_ty @@ -66,15 +65,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// declared. crate fn get_upvar_name_and_span_for_region( &self, - tcx: TyCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + tcx: TyCtxt<'tcx>, + upvars: &[Upvar], upvar_index: usize, ) -> (Symbol, Span) { - let upvar_hir_id = mir.upvar_decls[upvar_index].var_hir_id.assert_crate_local(); + let upvar_hir_id = upvars[upvar_index].var_hir_id; debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id); - let upvar_name = tcx.hir().name_by_hir_id(upvar_hir_id); - let upvar_span = tcx.hir().span_by_hir_id(upvar_hir_id); + let upvar_name = tcx.hir().name(upvar_hir_id); + let upvar_span = tcx.hir().span(upvar_hir_id); debug!("get_upvar_name_and_span_for_region: upvar_name={:?} upvar_span={:?}", upvar_name, upvar_span); @@ -88,7 +87,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// user - in particular, index 0 is not the implicit self parameter. crate fn get_argument_index_for_region( &self, - tcx: TyCtxt<'_, '_, 'tcx>, + tcx: TyCtxt<'tcx>, fr: RegionVid, ) -> Option { let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs(); @@ -117,19 +116,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// declared. crate fn get_argument_name_and_span_for_region( &self, - mir: &Mir<'tcx>, + body: &Body<'tcx>, argument_index: usize, ) -> (Option, Span) { let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs(); let argument_local = Local::new(implicit_inputs + argument_index + 1); debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local); - let argument_name = mir.local_decls[argument_local].name; - let argument_span = mir.local_decls[argument_local].source_info.span; + let argument_name = body.local_decls[argument_local].name; + let argument_span = body.local_decls[argument_local].source_info.span; debug!("get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}", argument_name, argument_span); (argument_name, argument_span) } - } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs index cffc66ac7ddfd..fdf2af9f44ebc 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs @@ -29,7 +29,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } -struct RawConstraints<'a, 'tcx: 'a> { +struct RawConstraints<'a, 'tcx> { regioncx: &'a RegionInferenceContext<'tcx>, } @@ -63,7 +63,7 @@ impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> { vids.into() } fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint> { - (&self.regioncx.constraints.raw[..]).into() + (&self.regioncx.constraints.outlives().raw[..]).into() } // Render `a: b` as `a -> b`, indicating the flow @@ -78,7 +78,7 @@ impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> { } } -struct SccConstraints<'a, 'tcx: 'a> { +struct SccConstraints<'a, 'tcx> { regioncx: &'a RegionInferenceContext<'tcx>, nodes_per_scc: IndexVec>, } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index f0d3a0d2986e5..4e609460c1f70 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -1,24 +1,32 @@ use super::universal_regions::UniversalRegions; use crate::borrow_check::nll::constraints::graph::NormalConstraintGraph; -use crate::borrow_check::nll::constraints::{ConstraintSccIndex, ConstraintSet, OutlivesConstraint}; +use crate::borrow_check::nll::constraints::{ + ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet, +}; +use crate::borrow_check::nll::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}; use crate::borrow_check::nll::region_infer::values::{ - PlaceholderIndices, RegionElement, ToElementIndex + PlaceholderIndices, RegionElement, ToElementIndex, }; use crate::borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; use crate::borrow_check::nll::type_check::Locations; +use crate::borrow_check::Upvar; use rustc::hir::def_id::DefId; -use rustc::infer::canonical::QueryRegionConstraint; +use rustc::infer::canonical::QueryOutlivesConstraint; +use rustc::infer::opaque_types; use rustc::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin}; use rustc::mir::{ - ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, - ConstraintCategory, Local, Location, Mir, + Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, + ConstraintCategory, Local, Location, }; use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc::util::common::{self, ErrorReported}; +use rustc_data_structures::binary_search_util; use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::graph::WithSuccessors; use rustc_data_structures::graph::scc::Sccs; +use rustc_data_structures::graph::vec_graph::VecGraph; use rustc_data_structures::indexed_vec::IndexVec; use rustc_errors::{Diagnostic, DiagnosticBuilder}; use syntax_pos::Span; @@ -48,17 +56,31 @@ pub struct RegionInferenceContext<'tcx> { liveness_constraints: LivenessValues, /// The outlives constraints computed by the type-check. - constraints: Rc, + constraints: Rc, /// The constraint-set, but in graph form, making it easy to traverse /// the constraints adjacent to a particular region. Used to construct /// the SCC (see `constraint_sccs`) and for error reporting. constraint_graph: Rc, - /// The SCC computed from `constraints` and the constraint graph. Used to + /// The SCC computed from `constraints` and the constraint + /// graph. We have an edge from SCC A to SCC B if `A: B`. Used to /// compute the values of each region. constraint_sccs: Rc>, + /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` + /// exists if `B: A`. Computed lazilly. + rev_constraint_graph: Option>>, + + /// The "R0 member of [R1..Rn]" constraints, indexed by SCC. + member_constraints: Rc>, + + /// Records the member constraints that we applied to each scc. + /// This is useful for error reporting. Once constraint + /// propagation is done, this vector is sorted according to + /// `member_region_scc`. + member_constraints_applied: Vec, + /// Map closure bounds to a `Span` that should be used for error reporting. closure_bounds_mapping: FxHashMap>, @@ -94,6 +116,32 @@ pub struct RegionInferenceContext<'tcx> { universal_region_relations: Rc>, } +/// Each time that `apply_member_constraint` is successful, it appends +/// one of these structs to the `member_constraints_applied` field. +/// This is used in error reporting to trace out what happened. +/// +/// The way that `apply_member_constraint` works is that it effectively +/// adds a new lower bound to the SCC it is analyzing: so you wind up +/// with `'R: 'O` where `'R` is the pick-region and `'O` is the +/// minimal viable option. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] +struct AppliedMemberConstraint { + /// The SCC that was affected. (The "member region".) + /// + /// The vector if `AppliedMemberConstraint` elements is kept sorted + /// by this field. + member_region_scc: ConstraintSccIndex, + + /// The "best option" that `apply_member_constraint` found -- this was + /// added as an "ad-hoc" lower-bound to `member_region_scc`. + min_choice: ty::RegionVid, + + /// The "member constraint index" -- we can find out details about + /// the constraint from + /// `set.member_constraints[member_constraint_index]`. + member_constraint_index: NllMemberConstraintIndex, +} + struct RegionDefinition<'tcx> { /// What kind of variable is this -- a free region? existential /// variable? etc. (See the `NLLRegionVariableOrigin` for more @@ -184,8 +232,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { universal_regions: Rc>, placeholder_indices: Rc, universal_region_relations: Rc>, - _mir: &Mir<'tcx>, - outlives_constraints: ConstraintSet, + _body: &Body<'tcx>, + outlives_constraints: OutlivesConstraintSet, + member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, closure_bounds_mapping: FxHashMap< Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>, @@ -217,12 +266,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions); + let member_constraints = + Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r))); + let mut result = Self { definitions, liveness_constraints, constraints, constraint_graph, constraint_sccs, + rev_constraint_graph: None, + member_constraints, + member_constraints_applied: Vec::new(), closure_bounds_mapping, scc_universes, scc_representatives, @@ -340,9 +395,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!( "init_free_and_bound_regions: placeholder {:?} is \ not compatible with universe {:?} of its SCC {:?}", - placeholder, - scc_universe, - scc, + placeholder, scc_universe, scc, ); self.add_incompatible_universe(scc); } @@ -369,7 +422,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`. - crate fn annotate(&self, tcx: TyCtxt<'_, '_, 'tcx>, err: &mut DiagnosticBuilder<'_>) { + crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_>) { self.universal_regions.annotate(tcx, err) } @@ -393,46 +446,58 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.scc_universes[scc] } + /// Once region solving has completed, this function will return + /// the member constraints that were applied to the value of a given + /// region `r`. See `AppliedMemberConstraint`. + fn applied_member_constraints(&self, r: impl ToRegionVid) -> &[AppliedMemberConstraint] { + let scc = self.constraint_sccs.scc(r.to_region_vid()); + binary_search_util::binary_search_slice( + &self.member_constraints_applied, + |applied| applied.member_region_scc, + &scc, + ) + } + /// Performs region inference and report errors if we see any /// unsatisfiable constraints. If this is a closure, returns the /// region requirements to propagate to our creator, if any. - pub(super) fn solve<'gcx>( + pub(super) fn solve( &mut self, - infcx: &InferCtxt<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, errors_buffer: &mut Vec, - ) -> Option> { - common::time( - infcx.tcx.sess, + ) -> Option> { + common::time_ext( + infcx.tcx.sess.time_extended(), + Some(infcx.tcx.sess), &format!("solve_nll_region_constraints({:?})", mir_def_id), - || self.solve_inner(infcx, mir, mir_def_id, errors_buffer), + || self.solve_inner(infcx, body, upvars, mir_def_id, errors_buffer), ) } - fn solve_inner<'gcx>( + fn solve_inner( &mut self, - infcx: &InferCtxt<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, errors_buffer: &mut Vec, - ) -> Option> { - self.propagate_constraints(mir); + ) -> Option> { + self.propagate_constraints(body); // If this is a closure, we can propagate unsatisfied // `outlives_requirements` to our creator, so create a vector // to store those. Otherwise, we'll pass in `None` to the // functions below, which will trigger them to report errors // eagerly. - let mut outlives_requirements = if infcx.tcx.is_closure(mir_def_id) { - Some(vec![]) - } else { - None - }; + let mut outlives_requirements = + if infcx.tcx.is_closure(mir_def_id) { Some(vec![]) } else { None }; self.check_type_tests( infcx, - mir, + body, mir_def_id, outlives_requirements.as_mut(), errors_buffer, @@ -440,22 +505,22 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_universal_regions( infcx, - mir, + body, + upvars, mir_def_id, outlives_requirements.as_mut(), errors_buffer, ); + self.check_member_constraints(infcx, mir_def_id, errors_buffer); + let outlives_requirements = outlives_requirements.unwrap_or(vec![]); if outlives_requirements.is_empty() { None } else { let num_external_vids = self.universal_regions.num_global_and_external_regions(); - Some(ClosureRegionRequirements { - num_external_vids, - outlives_requirements, - }) + Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }) } } @@ -463,11 +528,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// for each region variable until all the constraints are /// satisfied. Note that some values may grow **too** large to be /// feasible, but we check this later. - fn propagate_constraints(&mut self, _mir: &Mir<'tcx>) { + fn propagate_constraints(&mut self, _body: &Body<'tcx>) { debug!("propagate_constraints()"); debug!("propagate_constraints: constraints={:#?}", { - let mut constraints: Vec<_> = self.constraints.iter().collect(); + let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); constraints.sort(); constraints .into_iter() @@ -483,8 +548,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { for scc_index in self.constraint_sccs.all_sccs() { self.propagate_constraint_sccs_if_new(scc_index, visited); } + + // Sort the applied member constraints so we can binary search + // through them later. + self.member_constraints_applied.sort_by_key(|applied| applied.member_region_scc); } + /// Computes the value of the SCC `scc_a` if it has not already + /// been computed. The `visited` parameter is a bitset #[inline] fn propagate_constraint_sccs_if_new( &mut self, @@ -496,6 +567,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } + /// Computes the value of the SCC `scc_a`, which has not yet been + /// computed. This works by first computing all successors of the + /// SCC (if they haven't been computed already) and then unioning + /// together their elements. fn propagate_constraint_sccs_new( &mut self, scc_a: ConstraintSccIndex, @@ -505,10 +580,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Walk each SCC `B` such that `A: B`... for &scc_b in constraint_sccs.successors(scc_a) { - debug!( - "propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", - scc_a, scc_b - ); + debug!("propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", scc_a, scc_b); // ...compute the value of `B`... self.propagate_constraint_sccs_if_new(scc_b, visited); @@ -526,6 +598,16 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } + // Now take member constraints into account. + let member_constraints = self.member_constraints.clone(); + for m_c_i in member_constraints.indices(scc_a) { + self.apply_member_constraint( + scc_a, + m_c_i, + member_constraints.choice_regions(m_c_i), + ); + } + debug!( "propagate_constraint_sccs: scc_a = {:?} has value {:?}", scc_a, @@ -533,6 +615,167 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); } + /// Invoked for each `R0 member of [R1..Rn]` constraint. + /// + /// `scc` is the SCC containing R0, and `choice_regions` are the + /// `R1..Rn` regions -- they are always known to be universal + /// regions (and if that's not true, we just don't attempt to + /// enforce the constraint). + /// + /// The current value of `scc` at the time the method is invoked + /// is considered a *lower bound*. If possible, we will modify + /// the constraint to set it equal to one of the option regions. + /// If we make any changes, returns true, else false. + fn apply_member_constraint( + &mut self, + scc: ConstraintSccIndex, + member_constraint_index: NllMemberConstraintIndex, + choice_regions: &[ty::RegionVid], + ) -> bool { + debug!("apply_member_constraint(scc={:?}, choice_regions={:#?})", scc, choice_regions,); + + if let Some(uh_oh) = + choice_regions.iter().find(|&&r| !self.universal_regions.is_universal_region(r)) + { + // FIXME(#61773): This case can only occur with + // `impl_trait_in_bindings`, I believe, and we are just + // opting not to handle it for now. See #61773 for + // details. + bug!( + "member constraint for `{:?}` has an option region `{:?}` \ + that is not a universal region", + self.member_constraints[member_constraint_index].opaque_type_def_id, + uh_oh, + ); + } + + // Create a mutable vector of the options. We'll try to winnow + // them down. + let mut choice_regions: Vec = choice_regions.to_vec(); + + // The 'member region' in a member constraint is part of the + // hidden type, which must be in the root universe. Therefore, + // it cannot have any placeholders in its value. + assert!(self.scc_universes[scc] == ty::UniverseIndex::ROOT); + debug_assert!( + self.scc_values.placeholders_contained_in(scc).next().is_none(), + "scc {:?} in a member constraint has placeholder value: {:?}", + scc, + self.scc_values.region_value_str(scc), + ); + + // The existing value for `scc` is a lower-bound. This will + // consist of some set `{P} + {LB}` of points `{P}` and + // lower-bound free regions `{LB}`. As each choice region `O` + // is a free region, it will outlive the points. But we can + // only consider the option `O` if `O: LB`. + choice_regions.retain(|&o_r| { + self.scc_values + .universal_regions_outlived_by(scc) + .all(|lb| self.universal_region_relations.outlives(o_r, lb)) + }); + debug!("apply_member_constraint: after lb, choice_regions={:?}", choice_regions); + + // Now find all the *upper bounds* -- that is, each UB is a + // free region that must outlive the member region `R0` (`UB: + // R0`). Therefore, we need only keep an option `O` if `UB: O` + // for all UB. + if choice_regions.len() > 1 { + let universal_region_relations = self.universal_region_relations.clone(); + let rev_constraint_graph = self.rev_constraint_graph(); + for ub in self.upper_bounds(scc, &rev_constraint_graph) { + debug!("apply_member_constraint: ub={:?}", ub); + choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r)); + } + debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions); + } + + // If we ruled everything out, we're done. + if choice_regions.is_empty() { + return false; + } + + // Otherwise, we need to find the minimum remaining choice, if + // any, and take that. + debug!("apply_member_constraint: choice_regions remaining are {:#?}", choice_regions); + let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option { + let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2); + let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1); + if r1_outlives_r2 && r2_outlives_r1 { + Some(r1.min(r2)) + } else if r1_outlives_r2 { + Some(r2) + } else if r2_outlives_r1 { + Some(r1) + } else { + None + } + }; + let mut min_choice = choice_regions[0]; + for &other_option in &choice_regions[1..] { + debug!( + "apply_member_constraint: min_choice={:?} other_option={:?}", + min_choice, other_option, + ); + match min(min_choice, other_option) { + Some(m) => min_choice = m, + None => { + debug!( + "apply_member_constraint: {:?} and {:?} are incomparable; no min choice", + min_choice, other_option, + ); + return false; + } + } + } + + let min_choice_scc = self.constraint_sccs.scc(min_choice); + debug!( + "apply_member_constraint: min_choice={:?} best_choice_scc={:?}", + min_choice, + min_choice_scc, + ); + if self.scc_values.add_region(scc, min_choice_scc) { + self.member_constraints_applied.push(AppliedMemberConstraint { + member_region_scc: scc, + min_choice, + member_constraint_index, + }); + + true + } else { + false + } + } + + /// Compute and return the reverse SCC-based constraint graph (lazilly). + fn upper_bounds( + &'a mut self, + scc0: ConstraintSccIndex, + rev_constraint_graph: &'a VecGraph, + ) -> impl Iterator + 'a { + let scc_values = &self.scc_values; + let mut duplicates = FxHashSet::default(); + rev_constraint_graph + .depth_first_search(scc0) + .skip(1) + .flat_map(move |scc1| scc_values.universal_regions_outlived_by(scc1)) + .filter(move |&r| duplicates.insert(r)) + } + + /// Compute and return the reverse SCC-based constraint graph (lazilly). + fn rev_constraint_graph( + &mut self, + ) -> Rc> { + if let Some(g) = &self.rev_constraint_graph { + return g.clone(); + } + + let rev_graph = Rc::new(self.constraint_sccs.reverse()); + self.rev_constraint_graph = Some(rev_graph.clone()); + rev_graph + } + /// Returns `true` if all the elements in the value of `scc_b` are nameable /// in `scc_a`. Used during constraint propagation, and only once /// the value of `scc_b` has been computed. @@ -549,9 +792,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Otherwise, we have to iterate over the universe elements in // B's value, and check whether all of them are nameable // from universe_a - self.scc_values - .placeholders_contained_in(scc_b) - .all(|p| universe_a.can_name(p.universe)) + self.scc_values.placeholders_contained_in(scc_b).all(|p| universe_a.can_name(p.universe)) } /// Extend `scc` so that it can outlive some placeholder region @@ -573,12 +814,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// whether the "type tests" produced by typeck were satisfied; /// type tests encode type-outlives relationships like `T: /// 'a`. See `TypeTest` for more details. - fn check_type_tests<'gcx>( + fn check_type_tests( &self, - infcx: &InferCtxt<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, mir_def_id: DefId, - mut propagated_outlives_requirements: Option<&mut Vec>>, + mut propagated_outlives_requirements: Option<&mut Vec>>, errors_buffer: &mut Vec, ) { let tcx = infcx.tcx; @@ -594,7 +835,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let generic_ty = type_test.generic_kind.to_ty(tcx); if self.eval_verify_bound( tcx, - mir, + body, generic_ty, type_test.lower_bound, &type_test.verify_bound, @@ -605,7 +846,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements { if self.try_promote_type_test( infcx, - mir, + body, type_test, propagated_outlives_requirements, ) { @@ -619,7 +860,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let lower_bound_region = self.to_error_region(type_test.lower_bound); // Skip duplicate-ish errors. - let type_test_span = type_test.locations.span(mir); + let type_test_span = type_test.locations.span(body); let erased_generic_kind = tcx.erase_regions(&type_test.generic_kind); if !deduplicate_errors.insert(( erased_generic_kind, @@ -717,21 +958,16 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// The idea then is to lower the `T: 'X` constraint into multiple /// bounds -- e.g., if `'X` is the union of two free lifetimes, /// `'1` and `'2`, then we would create `T: '1` and `T: '2`. - fn try_promote_type_test<'gcx>( + fn try_promote_type_test( &self, - infcx: &InferCtxt<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, type_test: &TypeTest<'tcx>, - propagated_outlives_requirements: &mut Vec>, + propagated_outlives_requirements: &mut Vec>, ) -> bool { let tcx = infcx.tcx; - let TypeTest { - generic_kind, - lower_bound, - locations, - verify_bound: _, - } = type_test; + let TypeTest { generic_kind, lower_bound, locations, verify_bound: _ } = type_test; let generic_ty = generic_kind.to_ty(tcx); let subject = match self.try_promote_type_test_subject(infcx, generic_ty) { @@ -757,7 +993,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // where `ur` is a local bound -- we are sometimes in a // position to prove things that our caller cannot. See // #53570 for an example. - if self.eval_verify_bound(tcx, mir, generic_ty, ur, &type_test.verify_bound) { + if self.eval_verify_bound(tcx, body, generic_ty, ur, &type_test.verify_bound) { continue; } @@ -777,7 +1013,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let requirement = ClosureOutlivesRequirement { subject, outlived_free_region: upper_bound, - blame_span: locations.span(mir), + blame_span: locations.span(body), category: ConstraintCategory::Boring, }; debug!("try_promote_type_test: pushing {:#?}", requirement); @@ -789,7 +1025,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// When we promote a type test `T: 'r`, we have to convert the /// type `T` into something we can store in a query result (so - /// something allocated for `'gcx`). This is problematic if `ty` + /// something allocated for `'tcx`). This is problematic if `ty` /// contains regions. During the course of NLL region checking, we /// will have replaced all of those regions with fresh inference /// variables. To create a test subject, we want to replace those @@ -798,13 +1034,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// fallible process. Presuming we do find a suitable region, we /// will represent it with a `ReClosureBound`, which is a /// `RegionKind` variant that can be allocated in the gcx. - fn try_promote_type_test_subject<'gcx>( + fn try_promote_type_test_subject( &self, - infcx: &InferCtxt<'_, 'gcx, 'tcx>, + infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>, - ) -> Option> { + ) -> Option> { let tcx = infcx.tcx; - let gcx = tcx.global_tcx(); debug!("try_promote_type_test_subject(ty = {:?})", ty); @@ -858,8 +1093,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { }); debug!("try_promote_type_test_subject: folded ty = {:?}", ty); - // `lift` will only fail if we failed to promote some region. - let ty = gcx.lift(&ty)?; + // `has_local_value` will only be true if we failed to promote some region. + if ty.has_local_value() { + return None; + } Some(ClosureOutlivesSubject::Ty(ty)) } @@ -880,11 +1117,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// except that it converts further takes the non-local upper /// bound of `'y`, so that the final result is non-local. fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid { - debug!( - "non_local_universal_upper_bound(r={:?}={})", - r, - self.region_value_str(r) - ); + debug!("non_local_universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); let lub = self.universal_upper_bound(r); @@ -892,10 +1125,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // creator. let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub); - debug!( - "non_local_universal_upper_bound: non_local_lub={:?}", - non_local_lub - ); + debug!("non_local_universal_upper_bound: non_local_lub={:?}", non_local_lub); non_local_lub } @@ -915,11 +1145,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding /// a result `'y`. fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { - debug!( - "universal_upper_bound(r={:?}={})", - r, - self.region_value_str(r) - ); + debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); // Find the smallest universal region that contains all other // universal regions within `region`. @@ -938,41 +1164,38 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// `point`. fn eval_verify_bound( &self, - tcx: TyCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, generic_ty: Ty<'tcx>, lower_bound: RegionVid, verify_bound: &VerifyBound<'tcx>, ) -> bool { - debug!( - "eval_verify_bound(lower_bound={:?}, verify_bound={:?})", - lower_bound, verify_bound - ); + debug!("eval_verify_bound(lower_bound={:?}, verify_bound={:?})", lower_bound, verify_bound); match verify_bound { VerifyBound::IfEq(test_ty, verify_bound1) => { - self.eval_if_eq(tcx, mir, generic_ty, lower_bound, test_ty, verify_bound1) + self.eval_if_eq(tcx, body, generic_ty, lower_bound, test_ty, verify_bound1) } VerifyBound::OutlivedBy(r) => { let r_vid = self.to_region_vid(r); - self.eval_outlives(mir, r_vid, lower_bound) + self.eval_outlives(r_vid, lower_bound) } VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| { - self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound) + self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound) }), VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| { - self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound) + self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound) }), } } fn eval_if_eq( &self, - tcx: TyCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, generic_ty: Ty<'tcx>, lower_bound: RegionVid, test_ty: Ty<'tcx>, @@ -981,7 +1204,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let generic_ty_normalized = self.normalize_to_scc_representatives(tcx, generic_ty); let test_ty_normalized = self.normalize_to_scc_representatives(tcx, test_ty); if generic_ty_normalized == test_ty_normalized { - self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound) + self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound) } else { false } @@ -1017,7 +1240,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// higher-ranked things and so forth, and right now the inference /// context is not permitted to make more inference variables. So /// we use this kind of hacky solution. - fn normalize_to_scc_representatives(&self, tcx: TyCtxt<'_, '_, 'tcx>, value: T) -> T + fn normalize_to_scc_representatives(&self, tcx: TyCtxt<'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -1029,22 +1252,24 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) } - // Evaluate whether `sup_region: sub_region @ point`. - fn eval_outlives( - &self, - _mir: &Mir<'tcx>, - sup_region: RegionVid, - sub_region: RegionVid, - ) -> bool { + // Evaluate whether `sup_region == sub_region`. + fn eval_equal(&self, r1: RegionVid, r2: RegionVid) -> bool { + self.eval_outlives(r1, r2) && self.eval_outlives(r2, r1) + } + + // Evaluate whether `sup_region: sub_region`. + fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { debug!("eval_outlives({:?}: {:?})", sup_region, sub_region); debug!( - "eval_outlives: sup_region's value = {:?}", + "eval_outlives: sup_region's value = {:?} universal={:?}", self.region_value_str(sup_region), + self.universal_regions.is_universal_region(sup_region), ); debug!( - "eval_outlives: sub_region's value = {:?}", + "eval_outlives: sub_region's value = {:?} universal={:?}", self.region_value_str(sub_region), + self.universal_regions.is_universal_region(sub_region), ); let sub_region_scc = self.constraint_sccs.scc(sub_region); @@ -1056,9 +1281,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { // now). Therefore, the sup-region outlives the sub-region if, // for each universal region R1 in the sub-region, there // exists some region R2 in the sup-region that outlives R1. - let universal_outlives = self.scc_values - .universal_regions_outlived_by(sub_region_scc) - .all(|r1| { + let universal_outlives = + self.scc_values.universal_regions_outlived_by(sub_region_scc).all(|r1| { self.scc_values .universal_regions_outlived_by(sup_region_scc) .any(|r2| self.universal_region_relations.outlives(r2, r1)) @@ -1076,8 +1300,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { return true; } - self.scc_values - .contains_points(sup_region_scc, sub_region_scc) + self.scc_values.contains_points(sup_region_scc, sub_region_scc) } /// Once regions have been propagated, this method is used to see @@ -1097,12 +1320,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// If `propagated_outlives_requirements` is `Some`, then we will /// push unsatisfied obligations into there. Otherwise, we'll /// report them as errors. - fn check_universal_regions<'gcx>( + fn check_universal_regions( &self, - infcx: &InferCtxt<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, - mut propagated_outlives_requirements: Option<&mut Vec>>, + mut propagated_outlives_requirements: Option<&mut Vec>>, errors_buffer: &mut Vec, ) { for (fr, fr_definition) in self.definitions.iter_enumerated() { @@ -1113,7 +1337,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { // for our caller into the `outlives_requirements` vector. self.check_universal_region( infcx, - mir, + body, + upvars, mir_def_id, fr, &mut propagated_outlives_requirements, @@ -1122,7 +1347,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } NLLRegionVariableOrigin::Placeholder(placeholder) => { - self.check_bound_universal_region(infcx, mir, mir_def_id, fr, placeholder); + self.check_bound_universal_region(infcx, body, mir_def_id, fr, placeholder); } NLLRegionVariableOrigin::Existential => { @@ -1140,13 +1365,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// Things that are to be propagated are accumulated into the /// `outlives_requirements` vector. - fn check_universal_region<'gcx>( + fn check_universal_region( &self, - infcx: &InferCtxt<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, longer_fr: RegionVid, - propagated_outlives_requirements: &mut Option<&mut Vec>>, + propagated_outlives_requirements: &mut Option<&mut Vec>>, errors_buffer: &mut Vec, ) { debug!("check_universal_region(fr={:?})", longer_fr); @@ -1156,12 +1382,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Because this free region must be in the ROOT universe, we // know it cannot contain any bound universes. assert!(self.scc_universes[longer_fr_scc] == ty::UniverseIndex::ROOT); - debug_assert!( - self.scc_values - .placeholders_contained_in(longer_fr_scc) - .next() - .is_none() - ); + debug_assert!(self.scc_values.placeholders_contained_in(longer_fr_scc).next().is_none()); // Only check all of the relations for the main representative of each // SCC, otherwise just check that we outlive said representative. This @@ -1175,7 +1396,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { longer_fr, representative, infcx, - mir, + body, + upvars, mir_def_id, propagated_outlives_requirements, errors_buffer, @@ -1190,7 +1412,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { longer_fr, shorter_fr, infcx, - mir, + body, + upvars, mir_def_id, propagated_outlives_requirements, errors_buffer, @@ -1205,16 +1428,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, longer_fr: RegionVid, shorter_fr: RegionVid, - infcx: &InferCtxt<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, - propagated_outlives_requirements: &mut Option<&mut Vec>>, + propagated_outlives_requirements: &mut Option<&mut Vec>>, errors_buffer: &mut Vec, ) -> Option { // If it is known that `fr: o`, carry on. - if self.universal_region_relations - .outlives(longer_fr, shorter_fr) - { + if self.universal_region_relations.outlives(longer_fr, shorter_fr) { return None; } @@ -1228,23 +1450,19 @@ impl<'tcx> RegionInferenceContext<'tcx> { // We'll call it `fr-` -- it's ever so slightly smaller than // `longer_fr`. - if let Some(fr_minus) = self - .universal_region_relations - .non_local_lower_bound(longer_fr) + if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr) { debug!("check_universal_region: fr_minus={:?}", fr_minus); - let blame_span_category = self.find_outlives_blame_span(mir, longer_fr, shorter_fr); + let blame_span_category = + self.find_outlives_blame_span(body, longer_fr, shorter_fr); // Grow `shorter_fr` until we find some non-local regions. (We // always will.) We'll call them `shorter_fr+` -- they're ever // so slightly larger than `shorter_fr`. - let shorter_fr_plus = self.universal_region_relations - .non_local_upper_bounds(&shorter_fr); - debug!( - "check_universal_region: shorter_fr_plus={:?}", - shorter_fr_plus - ); + let shorter_fr_plus = + self.universal_region_relations.non_local_upper_bounds(&shorter_fr); + debug!("check_universal_region: shorter_fr_plus={:?}", shorter_fr_plus); for &&fr in &shorter_fr_plus { // Push the constraint `fr-: shorter_fr+` propagated_outlives_requirements.push(ClosureOutlivesRequirement { @@ -1264,40 +1482,32 @@ impl<'tcx> RegionInferenceContext<'tcx> { // // Note: in this case, we use the unapproximated regions to report the // error. This gives better error messages in some cases. - self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer); + self.report_error(body, upvars, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer); Some(ErrorReported) } - fn check_bound_universal_region<'gcx>( + fn check_bound_universal_region( &self, - infcx: &InferCtxt<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, _mir_def_id: DefId, longer_fr: RegionVid, placeholder: ty::PlaceholderRegion, ) { - debug!( - "check_bound_universal_region(fr={:?}, placeholder={:?})", - longer_fr, placeholder, - ); + debug!("check_bound_universal_region(fr={:?}, placeholder={:?})", longer_fr, placeholder,); let longer_fr_scc = self.constraint_sccs.scc(longer_fr); - debug!( - "check_bound_universal_region: longer_fr_scc={:?}", - longer_fr_scc, - ); + debug!("check_bound_universal_region: longer_fr_scc={:?}", longer_fr_scc,); // If we have some bound universal region `'a`, then the only // elements it can contain is itself -- we don't know anything // else about it! let error_element = match { - self.scc_values - .elements_contained_in(longer_fr_scc) - .find(|element| match element { - RegionElement::Location(_) => true, - RegionElement::RootUniversalRegion(_) => true, - RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1, - }) + self.scc_values.elements_contained_in(longer_fr_scc).find(|element| match element { + RegionElement::Location(_) => true, + RegionElement::RootUniversalRegion(_) => true, + RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1, + }) } { Some(v) => v, None => return, @@ -1308,7 +1518,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { let error_region = match error_element { RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l), RegionElement::RootUniversalRegion(r) => r, - RegionElement::PlaceholderRegion(error_placeholder) => self.definitions + RegionElement::PlaceholderRegion(error_placeholder) => self + .definitions .iter_enumerated() .filter_map(|(r, definition)| match definition.origin { NLLRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r), @@ -1319,19 +1530,57 @@ impl<'tcx> RegionInferenceContext<'tcx> { }; // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. - let (_, span) = self.find_outlives_blame_span(mir, longer_fr, error_region); + let (_, span) = self.find_outlives_blame_span(body, longer_fr, error_region); // Obviously, this error message is far from satisfactory. // At present, though, it only appears in unit tests -- // the AST-based checker uses a more conservative check, // so to even see this error, one must pass in a special // flag. - let mut diag = infcx - .tcx - .sess - .struct_span_err(span, "higher-ranked subtype error"); + let mut diag = infcx.tcx.sess.struct_span_err(span, "higher-ranked subtype error"); diag.emit(); } + + fn check_member_constraints( + &self, + infcx: &InferCtxt<'_, 'tcx>, + mir_def_id: DefId, + errors_buffer: &mut Vec, + ) { + let member_constraints = self.member_constraints.clone(); + for m_c_i in member_constraints.all_indices() { + debug!("check_member_constraint(m_c_i={:?})", m_c_i); + let m_c = &member_constraints[m_c_i]; + let member_region_vid = m_c.member_region_vid; + debug!( + "check_member_constraint: member_region_vid={:?} with value {}", + member_region_vid, + self.region_value_str(member_region_vid), + ); + let choice_regions = member_constraints.choice_regions(m_c_i); + debug!("check_member_constraint: choice_regions={:?}", choice_regions); + + // Did the member region wind up equal to any of the option regions? + if let Some(o) = choice_regions.iter().find(|&&o_r| { + self.eval_equal(o_r, m_c.member_region_vid) + }) { + debug!("check_member_constraint: evaluated as equal to {:?}", o); + continue; + } + + // If not, report an error. + let region_scope_tree = &infcx.tcx.region_scope_tree(mir_def_id); + let member_region = infcx.tcx.mk_region(ty::ReVar(member_region_vid)); + opaque_types::unexpected_hidden_region_diagnostic( + infcx.tcx, + Some(region_scope_tree), + m_c.opaque_type_def_id, + m_c.hidden_ty, + member_region, + ) + .buffer(errors_buffer); + } + } } impl<'tcx> RegionDefinition<'tcx> { @@ -1345,25 +1594,21 @@ impl<'tcx> RegionDefinition<'tcx> { _ => NLLRegionVariableOrigin::Existential, }; - Self { - origin, - universe, - external_name: None, - } + Self { origin, universe, external_name: None } } } -pub trait ClosureRegionRequirementsExt<'gcx, 'tcx> { +pub trait ClosureRegionRequirementsExt<'tcx> { fn apply_requirements( &self, - tcx: TyCtxt<'_, 'gcx, 'tcx>, + tcx: TyCtxt<'tcx>, closure_def_id: DefId, closure_substs: SubstsRef<'tcx>, - ) -> Vec>; + ) -> Vec>; fn subst_closure_mapping( &self, - tcx: TyCtxt<'_, 'gcx, 'tcx>, + tcx: TyCtxt<'tcx>, closure_mapping: &IndexVec>, value: &T, ) -> T @@ -1371,7 +1616,7 @@ pub trait ClosureRegionRequirementsExt<'gcx, 'tcx> { T: TypeFoldable<'tcx>; } -impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequirements<'gcx> { +impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx> { /// Given an instance T of the closure type, this method /// instantiates the "extra" requirements that we computed for the /// closure into the inference context. This has the effect of @@ -1386,10 +1631,10 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi /// requirements. fn apply_requirements( &self, - tcx: TyCtxt<'_, 'gcx, 'tcx>, + tcx: TyCtxt<'tcx>, closure_def_id: DefId, closure_substs: SubstsRef<'tcx>, - ) -> Vec> { + ) -> Vec> { debug!( "apply_requirements(closure_def_id={:?}, closure_substs={:?})", closure_def_id, closure_substs @@ -1441,7 +1686,7 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi fn subst_closure_mapping( &self, - tcx: TyCtxt<'_, 'gcx, 'tcx>, + tcx: TyCtxt<'tcx>, closure_mapping: &IndexVec>, value: &T, ) -> T @@ -1452,10 +1697,7 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi if let ty::ReClosureBound(vid) = r { closure_mapping[*vid] } else { - bug!( - "subst_closure_mapping: encountered non-closure bound free region {:?}", - r - ) + bug!("subst_closure_mapping: encountered non-closure bound free region {:?}", r) } }) } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index c4491778162f4..cfd80cecca510 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -1,4 +1,4 @@ -use rustc::mir::{BasicBlock, Location, Mir}; +use rustc::mir::{BasicBlock, Location, Body}; use rustc::ty::{self, RegionVid}; use rustc_data_structures::bit_set::{HybridBitSet, SparseBitMatrix}; use rustc_data_structures::fx::FxHashMap; @@ -20,9 +20,9 @@ crate struct RegionValueElements { } impl RegionValueElements { - crate fn new(mir: &Mir<'_>) -> Self { + crate fn new(body: &Body<'_>) -> Self { let mut num_points = 0; - let statements_before_block: IndexVec = mir.basic_blocks() + let statements_before_block: IndexVec = body.basic_blocks() .iter() .map(|block_data| { let v = num_points; @@ -37,7 +37,7 @@ impl RegionValueElements { debug!("RegionValueElements: num_points={:#?}", num_points); let mut basic_blocks = IndexVec::with_capacity(num_points); - for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { + for (bb, bb_data) in body.basic_blocks().iter_enumerated() { basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb)); } @@ -92,7 +92,7 @@ impl RegionValueElements { /// Pushes all predecessors of `index` onto `stack`. crate fn push_predecessors( &self, - mir: &Mir<'_>, + body: &Body<'_>, index: PointIndex, stack: &mut Vec, ) { @@ -104,9 +104,9 @@ impl RegionValueElements { // If this is a basic block head, then the predecessors are // the terminators of other basic blocks stack.extend( - mir.predecessors_for(block) + body.predecessors_for(block) .iter() - .map(|&pred_bb| mir.terminator_loc(pred_bb)) + .map(|&pred_bb| body.terminator_loc(pred_bb)) .map(|pred_loc| self.point_from_location(pred_loc)), ); } else { @@ -116,14 +116,14 @@ impl RegionValueElements { } } -/// A single integer representing a `Location` in the MIR control-flow -/// graph. Constructed efficiently from `RegionValueElements`. newtype_index! { + /// A single integer representing a `Location` in the MIR control-flow + /// graph. Constructed efficiently from `RegionValueElements`. pub struct PointIndex { DEBUG_FORMAT = "PointIndex({})" } } -/// A single integer representing a `ty::Placeholder`. newtype_index! { + /// A single integer representing a `ty::Placeholder`. pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" } } diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 0a0a88e694260..c1d1185cf177a 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -1,25 +1,22 @@ use rustc::ty::subst::SubstsRef; use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable}; -use rustc::mir::{Location, Mir}; +use rustc::mir::{Location, Body}; use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; /// Replaces all free regions appearing in the MIR with fresh /// inference variables, returning the number of variables created. -pub fn renumber_mir<'tcx>(infcx: &InferCtxt<'_, '_, 'tcx>, mir: &mut Mir<'tcx>) { +pub fn renumber_mir<'tcx>(infcx: &InferCtxt<'_, 'tcx>, body: &mut Body<'tcx>) { debug!("renumber_mir()"); - debug!("renumber_mir: mir.arg_count={:?}", mir.arg_count); + debug!("renumber_mir: body.arg_count={:?}", body.arg_count); let mut visitor = NLLVisitor { infcx }; - visitor.visit_mir(mir); + visitor.visit_body(body); } /// Replaces all regions appearing in `value` with fresh inference /// variables. -pub fn renumber_regions<'tcx, T>( - infcx: &InferCtxt<'_, '_, 'tcx>, - value: &T, -) -> T +pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: &T) -> T where T: TypeFoldable<'tcx>, { @@ -33,11 +30,11 @@ where }) } -struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, +struct NLLVisitor<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, } -impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> NLLVisitor<'a, 'tcx> { fn renumber_regions(&mut self, value: &T) -> T where T: TypeFoldable<'tcx>, @@ -46,13 +43,13 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { - fn visit_mir(&mut self, mir: &mut Mir<'tcx>) { - for promoted in mir.promoted.iter_mut() { - self.visit_mir(promoted); +impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { + fn visit_body(&mut self, body: &mut Body<'tcx>) { + for promoted in body.promoted.iter_mut() { + self.visit_body(promoted); } - self.super_mir(mir); + self.super_body(body); } fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { @@ -80,7 +77,7 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { debug!("visit_region: region={:?}", region); } - fn visit_const(&mut self, constant: &mut &'tcx ty::LazyConst<'tcx>, _location: Location) { + fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) { *constant = self.renumber_regions(&*constant); } diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs index 1a72205ad7ae1..8de014522dea7 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -3,7 +3,8 @@ use crate::borrow_check::nll::region_infer::TypeTest; use crate::borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints}; use crate::borrow_check::nll::universal_regions::UniversalRegions; use crate::borrow_check::nll::ToRegionVid; -use rustc::infer::canonical::QueryRegionConstraint; +use rustc::infer::canonical::QueryRegionConstraints; +use rustc::infer::canonical::QueryOutlivesConstraint; use rustc::infer::outlives::env::RegionBoundPairs; use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; use rustc::infer::region_constraints::{GenericKind, VerifyBound}; @@ -13,9 +14,9 @@ use rustc::ty::subst::UnpackedKind; use rustc::ty::{self, TyCtxt}; use syntax_pos::DUMMY_SP; -crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> { - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - tcx: TyCtxt<'a, 'gcx, 'tcx>, +crate struct ConstraintConversion<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, + tcx: TyCtxt<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: Option>, @@ -25,9 +26,9 @@ crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> { constraints: &'a mut MirTypeckRegionConstraints<'tcx>, } -impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { crate fn new( - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + infcx: &'a InferCtxt<'a, 'tcx>, universal_regions: &'a UniversalRegions<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: Option>, @@ -49,13 +50,33 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { } } - pub(super) fn convert_all(&mut self, query_constraints: &[QueryRegionConstraint<'tcx>]) { - for query_constraint in query_constraints { + pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) { + debug!("convert_all(query_constraints={:#?})", query_constraints); + + let QueryRegionConstraints { outlives, member_constraints } = query_constraints; + + // Annoying: to invoke `self.to_region_vid`, we need access to + // `self.constraints`, but we also want to be mutating + // `self.member_constraints`. For now, just swap out the value + // we want and replace at the end. + let mut tmp = std::mem::replace( + &mut self.constraints.member_constraints, + Default::default(), + ); + for member_constraint in member_constraints { + tmp.push_constraint( + member_constraint, + |r| self.to_region_vid(r), + ); + } + self.constraints.member_constraints = tmp; + + for query_constraint in outlives { self.convert(query_constraint); } } - pub(super) fn convert(&mut self, query_constraint: &QueryRegionConstraint<'tcx>) { + pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) { debug!("generate: constraints at: {:#?}", self.locations); // Extract out various useful fields we'll need below. @@ -99,6 +120,11 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { param_env, ).type_must_outlive(origin, t1, r2); } + + UnpackedKind::Const(_) => { + // Consts cannot outlive one another, so we + // don't need to handle any relations here. + } } } @@ -145,9 +171,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { } } -impl<'a, 'b, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx> - for &'a mut ConstraintConversion<'b, 'gcx, 'tcx> -{ +impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> { fn push_sub_region_constraint( &mut self, _origin: SubregionOrigin<'tcx>, diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs index 3b663ef6dad61..d18a8e87453a5 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs @@ -2,7 +2,7 @@ use crate::borrow_check::nll::type_check::constraint_conversion; use crate::borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints}; use crate::borrow_check::nll::universal_regions::UniversalRegions; use crate::borrow_check::nll::ToRegionVid; -use rustc::infer::canonical::QueryRegionConstraint; +use rustc::infer::canonical::QueryRegionConstraints; use rustc::infer::outlives::free_region_map::FreeRegionRelations; use rustc::infer::region_constraints::GenericKind; use rustc::infer::InferCtxt; @@ -55,7 +55,7 @@ crate struct CreateResult<'tcx> { } crate fn create( - infcx: &InferCtxt<'_, '_, 'tcx>, + infcx: &InferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, implicit_region_bound: Option>, universal_regions: &Rc>, @@ -219,8 +219,8 @@ impl UniversalRegionRelations<'tcx> { } } -struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> { - infcx: &'this InferCtxt<'this, 'gcx, 'tcx>, +struct UniversalRegionRelationsBuilder<'this, 'tcx> { + infcx: &'this InferCtxt<'this, 'tcx>, param_env: ty::ParamEnv<'tcx>, universal_regions: Rc>, implicit_region_bound: Option>, @@ -231,7 +231,7 @@ struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> { region_bound_pairs: RegionBoundPairs<'tcx>, } -impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { +impl UniversalRegionRelationsBuilder<'cx, 'tcx> { crate fn create(mut self) -> CreateResult<'tcx> { let unnormalized_input_output_tys = self .universal_regions @@ -287,7 +287,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { self.relations.relate_universal_regions(fr, fr_fn_body); } - for data in constraint_sets { + for data in &constraint_sets { constraint_conversion::ConstraintConversion::new( self.infcx, &self.universal_regions, @@ -297,7 +297,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { Locations::All(DUMMY_SP), ConstraintCategory::Internal, &mut self.constraints, - ).convert_all(&data); + ).convert_all(data); } CreateResult { @@ -311,7 +311,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { /// either the return type of the MIR or one of its arguments. At /// the same time, compute and add any implied bounds that come /// from this local. - fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option>>> { + fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option>> { debug!("add_implied_bounds(ty={:?})", ty); let (bounds, constraints) = self.param_env @@ -334,6 +334,13 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { match outlives_bound { OutlivesBound::RegionSubRegion(r1, r2) => { + // `where Type:` is lowered to `where Type: 'empty` so that + // we check `Type` is well formed, but there's no use for + // this bound here. + if let ty::ReEmpty = r1 { + return; + } + // The bound says that `r1 <= r2`; we store `r2: r1`. let r1 = self.universal_regions.to_region_vid(r1); let r2 = self.universal_regions.to_region_vid(r2); diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs index 50828c294fa1b..3954d62ad5c77 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -17,10 +17,10 @@ use syntax_pos::Span; use super::{Locations, TypeChecker}; -impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> TypeChecker<'a, 'tcx> { pub(super) fn equate_inputs_and_outputs( &mut self, - mir: &Mir<'tcx>, + body: &Body<'tcx>, universal_regions: &UniversalRegions<'tcx>, normalized_inputs_and_output: &[Ty<'tcx>], ) { @@ -43,7 +43,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // user-provided signature (e.g., the `_` in the code // above) with fresh variables. let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars( - mir.span, + body.span, &user_provided_poly_sig, ); @@ -53,7 +53,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { Some( self.infcx .replace_bound_vars_with_fresh_vars( - mir.span, + body.span, LateBoundRegionConversionTime::FnCall, &poly_sig, ) @@ -73,8 +73,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { normalized_input_ty ); - let mir_input_ty = mir.local_decls[local].ty; - let mir_input_span = mir.local_decls[local].source_info.span; + let mir_input_ty = body.local_decls[local].ty; + let mir_input_span = body.local_decls[local].source_info.span; self.equate_normalized_input_or_output( normalized_input_ty, mir_input_ty, @@ -89,8 +89,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // In MIR, closures begin an implicit `self`, so // argument N is stored in local N+2. let local = Local::new(argument_index + 2); - let mir_input_ty = mir.local_decls[local].ty; - let mir_input_span = mir.local_decls[local].source_info.span; + let mir_input_ty = body.local_decls[local].ty; + let mir_input_span = body.local_decls[local].source_info.span; // If the user explicitly annotated the input types, enforce those. let user_provided_input_ty = @@ -104,19 +104,19 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } assert!( - mir.yield_ty.is_some() && universal_regions.yield_ty.is_some() - || mir.yield_ty.is_none() && universal_regions.yield_ty.is_none() + body.yield_ty.is_some() && universal_regions.yield_ty.is_some() + || body.yield_ty.is_none() && universal_regions.yield_ty.is_none() ); - if let Some(mir_yield_ty) = mir.yield_ty { + if let Some(mir_yield_ty) = body.yield_ty { let ur_yield_ty = universal_regions.yield_ty.unwrap(); - let yield_span = mir.local_decls[RETURN_PLACE].source_info.span; + let yield_span = body.local_decls[RETURN_PLACE].source_info.span; self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span); } // Return types are a bit more complex. They may contain existential `impl Trait` // types. - let mir_output_ty = mir.local_decls[RETURN_PLACE].ty; - let output_span = mir.local_decls[RETURN_PLACE].source_info.span; + let mir_output_ty = body.local_decls[RETURN_PLACE].ty; + let output_span = body.local_decls[RETURN_PLACE].source_info.span; if let Err(terr) = self.eq_opaque_type_and_type( mir_output_ty, normalized_output_ty, diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs deleted file mode 100644 index b9f9d83161b79..0000000000000 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs +++ /dev/null @@ -1,94 +0,0 @@ -//! For the NLL computation, we need to compute liveness, but only for those -//! local variables whose types contain regions. The others are not of interest -//! to us. This file defines a new index type (LiveVar) that indexes into -//! a list of "variables whose type contain regions". It also defines a map from -//! Local to LiveVar and vice versa -- this map can be given to the -//! liveness code so that it only operates over variables with regions in their -//! types, instead of all variables. - -use crate::borrow_check::nll::ToRegionVid; -use crate::borrow_check::nll::facts::{AllFacts, AllFactsExt}; -use crate::util::liveness::LiveVariableMap; -use rustc::mir::{Local, Mir}; -use rustc::ty::{RegionVid, TyCtxt}; -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; - -/// Map between Local and LiveVar indices: the purpose of this -/// map is to define the subset of local variables for which we need -/// to do a liveness computation. We only need to compute whether a -/// variable `X` is live if that variable contains some region `R` in -/// its type where `R` is not known to outlive a free region (i.e., -/// where `R` may be valid for just a subset of the fn body). -crate struct NllLivenessMap { - /// For each local variable, contains `Some(i)` if liveness is - /// needed for this variable. - pub from_local: IndexVec>, - - /// For each `LiveVar`, maps back to the original `Local` index. - pub to_local: IndexVec, -} - -impl LiveVariableMap for NllLivenessMap { - fn from_local(&self, local: Local) -> Option { - self.from_local[local] - } - - type LiveVar = LiveVar; - - fn from_live_var(&self, local: Self::LiveVar) -> Local { - self.to_local[local] - } - - fn num_variables(&self) -> usize { - self.to_local.len() - } -} - -impl NllLivenessMap { - crate fn compute( - tcx: TyCtxt<'_, '_, 'tcx>, - free_regions: &FxHashSet, - mir: &Mir<'tcx>, - ) -> Self { - let mut to_local = IndexVec::default(); - let facts_enabled = AllFacts::enabled(tcx); - let from_local: IndexVec> = mir.local_decls - .iter_enumerated() - .map(|(local, local_decl)| { - if tcx.all_free_regions_meet(&local_decl.ty, |r| { - free_regions.contains(&r.to_region_vid()) - }) && !facts_enabled { - // If all the regions in the type are free regions - // (or there are no regions), then we don't need - // to track liveness for this variable. - None - } else { - Some(to_local.push(local)) - } - }) - .collect(); - - debug!("{} total variables", mir.local_decls.len()); - debug!("{} variables need liveness", to_local.len()); - debug!("{} regions outlive free regions", free_regions.len()); - - Self { - from_local, - to_local, - } - } - - /// Returns `true` if there are no local variables that need liveness computation. - crate fn is_empty(&self) -> bool { - self.to_local.is_empty() - } -} - -/// Index given to each local variable for which we need to -/// compute liveness information. For many locals, we are able to -/// skip liveness information: for example, those variables whose -/// types contain no regions. -newtype_index! { - pub struct LiveVar { .. } -} diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs index e9765d2798cd7..2a066538cc234 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs @@ -1,34 +1,40 @@ use crate::borrow_check::nll::region_infer::values::{PointIndex, RegionValueElements}; -use crate::borrow_check::nll::type_check::liveness::liveness_map::{LiveVar, NllLivenessMap}; -use crate::util::liveness::{categorize, DefUse, LiveVariableMap}; +use crate::util::liveness::{categorize, DefUse}; use rustc::mir::visit::{PlaceContext, Visitor}; -use rustc::mir::{Local, Location, Mir}; +use rustc::mir::{Local, Location, Body}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::vec_linked_list as vll; /// A map that cross references each local with the locations where it /// is defined (assigned), used, or dropped. Used during liveness /// computation. -crate struct LocalUseMap<'me> { - liveness_map: &'me NllLivenessMap, - +/// +/// We keep track only of `Local`s we'll do the liveness analysis later, +/// this means that our internal `IndexVec`s will only be sparsely populated. +/// In the time-memory trade-off between keeping compact vectors with new +/// indexes (and needing to continuously map the `Local` index to its compact +/// counterpart) and having `IndexVec`s that we only use a fraction of, time +/// (and code simplicity) was favored. The rationale is that we only keep +/// a small number of `IndexVec`s throughout the entire analysis while, in +/// contrast, we're accessing each `Local` *many* times. +crate struct LocalUseMap { /// Head of a linked list of **definitions** of each variable -- /// definition in this context means assignment, e.g., `x` is /// defined in `x = y` but not `y`; that first def is the head of /// a linked list that lets you enumerate all places the variable /// is assigned. - first_def_at: IndexVec>, + first_def_at: IndexVec>, /// Head of a linked list of **uses** of each variable -- use in /// this context means that the existing value of the variable is /// read or modified. e.g., `y` is used in `x = y` but not `x`. /// Note that `DROP(x)` terminators are excluded from this list. - first_use_at: IndexVec>, + first_use_at: IndexVec>, /// Head of a linked list of **drops** of each variable -- these /// are a special category of uses corresponding to the drop that /// we add for each local variable. - first_drop_at: IndexVec>, + first_drop_at: IndexVec>, appearances: IndexVec, } @@ -50,52 +56,68 @@ impl vll::LinkElem for Appearance { } } -impl LocalUseMap<'me> { +impl LocalUseMap { crate fn build( - liveness_map: &'me NllLivenessMap, + live_locals: &Vec, elements: &RegionValueElements, - mir: &Mir<'_>, + body: &Body<'_>, ) -> Self { - let nones = IndexVec::from_elem_n(None, liveness_map.num_variables()); + let nones = IndexVec::from_elem_n(None, body.local_decls.len()); let mut local_use_map = LocalUseMap { - liveness_map, first_def_at: nones.clone(), first_use_at: nones.clone(), first_drop_at: nones, appearances: IndexVec::new(), }; + let mut locals_with_use_data: IndexVec = + IndexVec::from_elem_n(false, body.local_decls.len()); + live_locals + .iter() + .for_each(|&local| locals_with_use_data[local] = true); + LocalUseMapBuild { local_use_map: &mut local_use_map, elements, - }.visit_mir(mir); + locals_with_use_data, + } + .visit_body(body); local_use_map } - crate fn defs(&self, local: LiveVar) -> impl Iterator + '_ { + crate fn defs(&self, local: Local) -> impl Iterator + '_ { vll::iter(self.first_def_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } - crate fn uses(&self, local: LiveVar) -> impl Iterator + '_ { + crate fn uses(&self, local: Local) -> impl Iterator + '_ { vll::iter(self.first_use_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } - crate fn drops(&self, local: LiveVar) -> impl Iterator + '_ { + crate fn drops(&self, local: Local) -> impl Iterator + '_ { vll::iter(self.first_drop_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } } -struct LocalUseMapBuild<'me, 'map: 'me> { - local_use_map: &'me mut LocalUseMap<'map>, +struct LocalUseMapBuild<'me> { + local_use_map: &'me mut LocalUseMap, elements: &'me RegionValueElements, + + // Vector used in `visit_local` to signal which `Local`s do we need + // def/use/drop information on, constructed from `live_locals` (that + // contains the variables we'll do the liveness analysis for). + // This vector serves optimization purposes only: we could have + // obtained the same information from `live_locals` but we want to + // avoid repeatedly calling `Vec::contains()` (see `LocalUseMap` for + // the rationale on the time-memory trade-off we're favoring here). + locals_with_use_data: IndexVec, } -impl LocalUseMapBuild<'_, '_> { - fn insert_def(&mut self, local: LiveVar, location: Location) { +impl LocalUseMapBuild<'_> { + fn insert_def(&mut self, local: Local, location: Location) { Self::insert( self.elements, &mut self.local_use_map.first_def_at[local], @@ -104,7 +126,7 @@ impl LocalUseMapBuild<'_, '_> { ); } - fn insert_use(&mut self, local: LiveVar, location: Location) { + fn insert_use(&mut self, local: Local, location: Location) { Self::insert( self.elements, &mut self.local_use_map.first_use_at[local], @@ -113,7 +135,7 @@ impl LocalUseMapBuild<'_, '_> { ); } - fn insert_drop(&mut self, local: LiveVar, location: Location) { + fn insert_drop(&mut self, local: Local, location: Location) { Self::insert( self.elements, &mut self.local_use_map.first_drop_at[local], @@ -137,13 +159,13 @@ impl LocalUseMapBuild<'_, '_> { } } -impl Visitor<'tcx> for LocalUseMapBuild<'_, '_> { - fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, location: Location) { - if let Some(local_with_region) = self.local_use_map.liveness_map.from_local(local) { +impl Visitor<'tcx> for LocalUseMapBuild<'_> { + fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { + if self.locals_with_use_data[local] { match categorize(context) { - Some(DefUse::Def) => self.insert_def(local_with_region, location), - Some(DefUse::Use) => self.insert_use(local_with_region, location), - Some(DefUse::Drop) => self.insert_drop(local_with_region, location), + Some(DefUse::Def) => self.insert_def(local, location), + Some(DefUse::Use) => self.insert_use(local, location), + Some(DefUse::Drop) => self.insert_drop(local, location), _ => (), } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs index 28a8cad8ca200..4af78fa5e0f42 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs @@ -1,19 +1,19 @@ use crate::borrow_check::location::LocationTable; +use crate::borrow_check::nll::constraints::OutlivesConstraintSet; +use crate::borrow_check::nll::facts::{AllFacts, AllFactsExt}; use crate::borrow_check::nll::region_infer::values::RegionValueElements; -use crate::borrow_check::nll::constraints::ConstraintSet; -use crate::borrow_check::nll::NllLivenessMap; use crate::borrow_check::nll::universal_regions::UniversalRegions; +use crate::borrow_check::nll::ToRegionVid; use crate::dataflow::move_paths::MoveData; -use crate::dataflow::MaybeInitializedPlaces; use crate::dataflow::FlowAtLocation; -use rustc::mir::Mir; -use rustc::ty::RegionVid; +use crate::dataflow::MaybeInitializedPlaces; +use rustc::mir::{Local, Body}; +use rustc::ty::{RegionVid, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use std::rc::Rc; use super::TypeChecker; -crate mod liveness_map; mod local_use_map; mod trace; @@ -25,25 +25,79 @@ mod trace; /// /// N.B., this computation requires normalization; therefore, it must be /// performed before -pub(super) fn generate<'gcx, 'tcx>( - typeck: &mut TypeChecker<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, +pub(super) fn generate<'tcx>( + typeck: &mut TypeChecker<'_, 'tcx>, + body: &Body<'tcx>, elements: &Rc, - flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>, + flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'tcx>>, move_data: &MoveData<'tcx>, location_table: &LocationTable, ) { debug!("liveness::generate"); - let free_regions = { - let borrowck_context = typeck.borrowck_context.as_ref().unwrap(); - regions_that_outlive_free_regions( - typeck.infcx.num_region_vars(), - &borrowck_context.universal_regions, - &borrowck_context.constraints.outlives_constraints, - ) + + let live_locals: Vec = if AllFacts::enabled(typeck.tcx()) { + // If "dump facts from NLL analysis" was requested perform + // the liveness analysis for all `Local`s. This case opens + // the possibility of the variables being analyzed in `trace` + // to be *any* `Local`, not just the "live" ones, so we can't + // make any assumptions past this point as to the characteristics + // of the `live_locals`. + // FIXME: Review "live" terminology past this point, we should + // not be naming the `Local`s as live. + body.local_decls.indices().collect() + } else { + let free_regions = { + regions_that_outlive_free_regions( + typeck.infcx.num_region_vars(), + &typeck.borrowck_context.universal_regions, + &typeck.borrowck_context.constraints.outlives_constraints, + ) + }; + compute_live_locals(typeck.tcx(), &free_regions, body) }; - let liveness_map = NllLivenessMap::compute(typeck.tcx(), &free_regions, mir); - trace::trace(typeck, mir, elements, flow_inits, move_data, &liveness_map, location_table); + + if !live_locals.is_empty() { + trace::trace( + typeck, + body, + elements, + flow_inits, + move_data, + live_locals, + location_table, + ); + } +} + +// The purpose of `compute_live_locals` is to define the subset of `Local` +// variables for which we need to do a liveness computation. We only need +// to compute whether a variable `X` is live if that variable contains +// some region `R` in its type where `R` is not known to outlive a free +// region (i.e., where `R` may be valid for just a subset of the fn body). +fn compute_live_locals( + tcx: TyCtxt<'tcx>, + free_regions: &FxHashSet, + body: &Body<'tcx>, +) -> Vec { + let live_locals: Vec = body + .local_decls + .iter_enumerated() + .filter_map(|(local, local_decl)| { + if tcx.all_free_regions_meet(&local_decl.ty, |r| { + free_regions.contains(&r.to_region_vid()) + }) { + None + } else { + Some(local) + } + }) + .collect(); + + debug!("{} total variables", body.local_decls.len()); + debug!("{} variables need liveness", live_locals.len()); + debug!("{} regions outlive free regions", free_regions.len()); + + live_locals } /// Computes all regions that are (currently) known to outlive free @@ -53,7 +107,7 @@ pub(super) fn generate<'gcx, 'tcx>( fn regions_that_outlive_free_regions( num_region_vars: usize, universal_regions: &UniversalRegions<'tcx>, - constraint_set: &ConstraintSet, + constraint_set: &OutlivesConstraintSet, ) -> FxHashSet { // Build a graph of the outlives constraints thus far. This is // a reverse graph, so for each constraint `R1: R2` we have an diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs index 4a0b4b7c205c6..f160f658f5576 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs @@ -1,15 +1,13 @@ use crate::borrow_check::location::LocationTable; use crate::borrow_check::nll::region_infer::values::{self, PointIndex, RegionValueElements}; -use crate::borrow_check::nll::type_check::liveness::liveness_map::{LiveVar, NllLivenessMap}; use crate::borrow_check::nll::type_check::liveness::local_use_map::LocalUseMap; use crate::borrow_check::nll::type_check::NormalizeLocation; use crate::borrow_check::nll::type_check::TypeChecker; -use crate::dataflow::move_paths::indexes::MovePathIndex; +use crate::dataflow::indexes::MovePathIndex; use crate::dataflow::move_paths::MoveData; use crate::dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces}; -use crate::util::liveness::LiveVariableMap; -use rustc::infer::canonical::QueryRegionConstraint; -use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, Mir}; +use rustc::infer::canonical::QueryRegionConstraints; +use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, Body}; use rustc::traits::query::dropck_outlives::DropckOutlivesResult; use rustc::traits::query::type_op::outlives::DropckOutlives; use rustc::traits::query::type_op::TypeOp; @@ -33,53 +31,42 @@ use std::rc::Rc; /// `dropck_outlives` result of the variable's type (in particular, /// this respects `#[may_dangle]` annotations). pub(super) fn trace( - typeck: &mut TypeChecker<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, + typeck: &mut TypeChecker<'_, 'tcx>, + body: &Body<'tcx>, elements: &Rc, - flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>, + flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'tcx>>, move_data: &MoveData<'tcx>, - liveness_map: &NllLivenessMap, + live_locals: Vec, location_table: &LocationTable, ) { debug!("trace()"); - if liveness_map.is_empty() { - return; - } - - let local_use_map = &LocalUseMap::build(liveness_map, elements, mir); + let local_use_map = &LocalUseMap::build(&live_locals, elements, body); let cx = LivenessContext { typeck, - mir, + body, flow_inits, elements, local_use_map, move_data, - liveness_map, drop_data: FxHashMap::default(), location_table, }; - LivenessResults::new(cx).compute_for_all_locals(); + LivenessResults::new(cx).compute_for_all_locals(live_locals); } /// Contextual state for the type-liveness generator. -struct LivenessContext<'me, 'typeck, 'flow, 'gcx, 'tcx> -where - 'typeck: 'me, - 'flow: 'me, - 'tcx: 'typeck + 'flow, - 'gcx: 'tcx, -{ +struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { /// Current type-checker, giving us our inference context etc. - typeck: &'me mut TypeChecker<'typeck, 'gcx, 'tcx>, + typeck: &'me mut TypeChecker<'typeck, 'tcx>, /// Defines the `PointIndex` mapping elements: &'me RegionValueElements, /// MIR we are analyzing. - mir: &'me Mir<'tcx>, + body: &'me Body<'tcx>, /// Mapping to/from the various indices used for initialization tracking. move_data: &'me MoveData<'tcx>, @@ -89,14 +76,11 @@ where /// Results of dataflow tracking which variables (and paths) have been /// initialized. - flow_inits: &'me mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>, + flow_inits: &'me mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'flow, 'tcx>>, /// Index indicating where each variable is assigned, used, or /// dropped. - local_use_map: &'me LocalUseMap<'me>, - - /// Map tracking which variables need liveness computation. - liveness_map: &'me NllLivenessMap, + local_use_map: &'me LocalUseMap, /// Maps between a MIR Location and a LocationIndex location_table: &'me LocationTable, @@ -104,17 +88,11 @@ where struct DropData<'tcx> { dropck_result: DropckOutlivesResult<'tcx>, - region_constraint_data: Option>>>, + region_constraint_data: Option>>, } -struct LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx> -where - 'typeck: 'me, - 'flow: 'me, - 'tcx: 'typeck + 'flow, - 'gcx: 'tcx, -{ - cx: LivenessContext<'me, 'typeck, 'flow, 'gcx, 'tcx>, +struct LivenessResults<'me, 'typeck, 'flow, 'tcx> { + cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>, /// Set of points that define the current local. defs: HybridBitSet, @@ -135,8 +113,8 @@ where stack: Vec, } -impl LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx> { - fn new(cx: LivenessContext<'me, 'typeck, 'flow, 'gcx, 'tcx>) -> Self { +impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { + fn new(cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>) -> Self { let num_points = cx.elements.num_points(); LivenessResults { cx, @@ -148,17 +126,14 @@ impl LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx> { } } - fn compute_for_all_locals(&mut self) { - for live_local in self.cx.liveness_map.to_local.indices() { - let local = self.cx.liveness_map.from_live_var(live_local); - debug!("local={:?} live_local={:?}", local, live_local); - + fn compute_for_all_locals(&mut self, live_locals: Vec) { + for local in live_locals { self.reset_local_state(); - self.add_defs_for(live_local); - self.compute_use_live_points_for(live_local); - self.compute_drop_live_points_for(live_local); + self.add_defs_for(local); + self.compute_use_live_points_for(local); + self.compute_drop_live_points_for(local); - let local_ty = self.cx.mir.local_decls[local].ty; + let local_ty = self.cx.body.local_decls[local].ty; if !self.use_live_at.is_empty() { self.cx.add_use_live_facts_for(local_ty, &self.use_live_at); @@ -185,8 +160,8 @@ impl LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx> { } /// Adds the definitions of `local` into `self.defs`. - fn add_defs_for(&mut self, live_local: LiveVar) { - for def in self.cx.local_use_map.defs(live_local) { + fn add_defs_for(&mut self, local: Local) { + for def in self.cx.local_use_map.defs(local) { debug!("- defined at {:?}", def); self.defs.insert(def); } @@ -194,14 +169,14 @@ impl LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx> { /// Computes all points where local is "use live" -- meaning its /// current value may be used later (except by a drop). This is - /// done by walking backwards from each use of `live_local` until we + /// done by walking backwards from each use of `local` until we /// find a `def` of local. /// - /// Requires `add_defs_for(live_local)` to have been executed. - fn compute_use_live_points_for(&mut self, live_local: LiveVar) { - debug!("compute_use_live_points_for(live_local={:?})", live_local); + /// Requires `add_defs_for(local)` to have been executed. + fn compute_use_live_points_for(&mut self, local: Local) { + debug!("compute_use_live_points_for(local={:?})", local); - self.stack.extend(self.cx.local_use_map.uses(live_local)); + self.stack.extend(self.cx.local_use_map.uses(local)); while let Some(p) = self.stack.pop() { if self.defs.contains(p) { continue; @@ -210,7 +185,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx> { if self.use_live_at.insert(p) { self.cx .elements - .push_predecessors(self.cx.mir, p, &mut self.stack) + .push_predecessors(self.cx.body, p, &mut self.stack) } } } @@ -224,17 +199,16 @@ impl LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx> { /// /// Requires `compute_use_live_points_for` and `add_defs_for` to /// have been executed. - fn compute_drop_live_points_for(&mut self, live_local: LiveVar) { - debug!("compute_drop_live_points_for(live_local={:?})", live_local); + fn compute_drop_live_points_for(&mut self, local: Local) { + debug!("compute_drop_live_points_for(local={:?})", local); - let local = self.cx.liveness_map.from_live_var(live_local); let mpi = self.cx.move_data.rev_lookup.find_local(local); debug!("compute_drop_live_points_for: mpi = {:?}", mpi); // Find the drops where `local` is initialized. - for drop_point in self.cx.local_use_map.drops(live_local) { + for drop_point in self.cx.local_use_map.drops(local) { let location = self.cx.elements.to_location(drop_point); - debug_assert_eq!(self.cx.mir.terminator_loc(location.block), location,); + debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,); if self.cx.initialized_at_terminator(location.block, mpi) { if self.drop_live_at.insert(drop_point) { @@ -284,7 +258,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx> { // live point. let term_location = self.cx.elements.to_location(term_point); debug_assert_eq!( - self.cx.mir.terminator_loc(term_location.block), + self.cx.body.terminator_loc(term_location.block), term_location, ); let block = term_location.block; @@ -311,7 +285,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx> { } } - for &pred_block in self.cx.mir.predecessors_for(block).iter() { + for &pred_block in self.cx.body.predecessors_for(block).iter() { debug!( "compute_drop_live_points_for_block: pred_block = {:?}", pred_block, @@ -340,7 +314,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx> { continue; } - let pred_term_loc = self.cx.mir.terminator_loc(pred_block); + let pred_term_loc = self.cx.body.terminator_loc(pred_block); let pred_term_point = self.cx.elements.point_from_location(pred_term_loc); // If the terminator of this predecessor either *assigns* @@ -406,7 +380,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx> { } } -impl LivenessContext<'_, '_, '_, '_, 'tcx> { +impl LivenessContext<'_, '_, '_, 'tcx> { /// Returns `true` if the local variable (or some part of it) is initialized in /// the terminator of `block`. We need to check this to determine if a /// DROP of some local variable will have an effect -- note that @@ -417,7 +391,7 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> { // the effects of all statements. This is the only way to get // "just ahead" of a terminator. self.flow_inits.reset_to_entry_of(block); - for statement_index in 0..self.mir[block].statements.len() { + for statement_index in 0..self.body[block].statements.len() { let location = Location { block, statement_index, @@ -499,7 +473,7 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> { drop_data.dropck_result.report_overflows( self.typeck.infcx.tcx, - self.mir.source_info(*drop_locations.first().unwrap()).span, + self.body.source_info(*drop_locations.first().unwrap()).span, dropped_ty, ); @@ -518,7 +492,7 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> { fn make_all_regions_live( elements: &RegionValueElements, - typeck: &mut TypeChecker<'_, '_, 'tcx>, + typeck: &mut TypeChecker<'_, 'tcx>, value: impl TypeFoldable<'tcx>, live_at: &HybridBitSet, location_table: &LocationTable, @@ -531,16 +505,15 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> { let tcx = typeck.tcx(); tcx.for_each_free_region(&value, |live_region| { - let borrowck_context = typeck.borrowck_context.as_mut().unwrap(); - let live_region_vid = borrowck_context + let live_region_vid = typeck.borrowck_context .universal_regions .to_region_vid(live_region); - borrowck_context + typeck.borrowck_context .constraints .liveness_constraints .add_elements(live_region_vid, live_at); - if let Some(facts) = borrowck_context.all_facts { + if let Some(facts) = typeck.borrowck_context.all_facts { for point in live_at.iter() { let loc = elements.to_location(point); facts.region_live_at.push((live_region_vid, location_table.start_index(loc))); @@ -551,7 +524,7 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> { } fn compute_drop_data( - typeck: &mut TypeChecker<'_, 'gcx, 'tcx>, + typeck: &mut TypeChecker<'_, 'tcx>, dropped_ty: Ty<'tcx>, ) -> DropData<'tcx> { debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,); diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 9fa3bf5524739..cdbbe1d02bd92 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -4,7 +4,8 @@ use crate::borrow_check::borrow_set::BorrowSet; use crate::borrow_check::location::LocationTable; -use crate::borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint}; +use crate::borrow_check::nll::constraints::{OutlivesConstraintSet, OutlivesConstraint}; +use crate::borrow_check::nll::member_constraints::MemberConstraintSet; use crate::borrow_check::nll::facts::AllFacts; use crate::borrow_check::nll::region_infer::values::LivenessValues; use crate::borrow_check::nll::region_infer::values::PlaceholderIndex; @@ -20,25 +21,26 @@ use crate::borrow_check::nll::ToRegionVid; use crate::dataflow::move_paths::MoveData; use crate::dataflow::FlowAtLocation; use crate::dataflow::MaybeInitializedPlaces; -use crate::transform::{MirPass, MirSource}; use either::Either; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::infer::canonical::QueryRegionConstraint; +use rustc::infer::canonical::QueryRegionConstraints; use rustc::infer::outlives::env::RegionBoundPairs; use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin}; -use rustc::mir::interpret::EvalErrorKind::BoundsCheck; +use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc::mir::interpret::{InterpError::BoundsCheck, ConstValue}; use rustc::mir::tcx::PlaceTy; -use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext}; +use rustc::mir::visit::{PlaceContext, Visitor, NonMutatingUseContext}; use rustc::mir::*; use rustc::traits::query::type_op; use rustc::traits::query::type_op::custom::CustomTypeOp; use rustc::traits::query::{Fallible, NoSolution}; use rustc::traits::{ObligationCause, PredicateObligations}; +use rustc::ty::adjustment::{PointerCast}; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::{Subst, SubstsRef, UnpackedKind, UserSubsts}; use rustc::ty::{ - self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind, UserType, + self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, UserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, UserTypeAnnotationIndex, }; @@ -108,16 +110,16 @@ mod relate_tys; /// constraints for the regions in the types of variables /// - `flow_inits` -- results of a maybe-init dataflow analysis /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis -pub(crate) fn type_check<'gcx, 'tcx>( - infcx: &InferCtxt<'_, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'gcx>, - mir: &Mir<'tcx>, +pub(crate) fn type_check<'tcx>( + infcx: &InferCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body: &Body<'tcx>, mir_def_id: DefId, universal_regions: &Rc>, location_table: &LocationTable, borrow_set: &BorrowSet<'tcx>, all_facts: &mut Option, - flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'gcx, 'tcx>>, + flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'tcx>>, move_data: &MoveData<'tcx>, elements: &Rc, ) -> MirTypeckResults<'tcx> { @@ -126,7 +128,8 @@ pub(crate) fn type_check<'gcx, 'tcx>( placeholder_indices: PlaceholderIndices::default(), placeholder_index_to_region: IndexVec::default(), liveness_constraints: LivenessValues::new(elements.clone()), - outlives_constraints: ConstraintSet::default(), + outlives_constraints: OutlivesConstraintSet::default(), + member_constraints: MemberConstraintSet::default(), closure_bounds_mapping: Default::default(), type_tests: Vec::default(), }; @@ -155,18 +158,16 @@ pub(crate) fn type_check<'gcx, 'tcx>( infcx, mir_def_id, param_env, - mir, + body, ®ion_bound_pairs, - Some(implicit_region_bound), - Some(&mut borrowck_context), - Some(&universal_region_relations), - |cx| { - cx.equate_inputs_and_outputs(mir, universal_regions, &normalized_inputs_and_output); - liveness::generate(cx, mir, elements, flow_inits, move_data, location_table); - - cx.borrowck_context - .as_mut() - .map(|bcx| translate_outlives_facts(bcx)); + implicit_region_bound, + &mut borrowck_context, + &universal_region_relations, + |mut cx| { + cx.equate_inputs_and_outputs(body, universal_regions, &normalized_inputs_and_output); + liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table); + + translate_outlives_facts(cx.borrowck_context); }, ); @@ -176,20 +177,20 @@ pub(crate) fn type_check<'gcx, 'tcx>( } } -fn type_check_internal<'a, 'gcx, 'tcx, R>( - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, +fn type_check_internal<'a, 'tcx, R>( + infcx: &'a InferCtxt<'a, 'tcx>, mir_def_id: DefId, - param_env: ty::ParamEnv<'gcx>, - mir: &'a Mir<'tcx>, + param_env: ty::ParamEnv<'tcx>, + body: &'a Body<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: Option>, - borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, - universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>, - mut extra: impl FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>) -> R, + implicit_region_bound: ty::Region<'tcx>, + borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, + universal_region_relations: &'a UniversalRegionRelations<'tcx>, + mut extra: impl FnMut(&mut TypeChecker<'a, 'tcx>) -> R, ) -> R where { let mut checker = TypeChecker::new( infcx, - mir, + body, mir_def_id, param_env, region_bound_pairs, @@ -198,14 +199,14 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>( universal_region_relations, ); let errors_reported = { - let mut verifier = TypeVerifier::new(&mut checker, mir); - verifier.visit_mir(mir); + let mut verifier = TypeVerifier::new(&mut checker, body); + verifier.visit_body(body); verifier.errors_reported }; if !errors_reported { // if verifier failed, don't do further checks to avoid ICEs - checker.typeck_mir(mir); + checker.typeck_mir(body); } extra(&mut checker) @@ -216,7 +217,7 @@ fn translate_outlives_facts(cx: &mut BorrowCheckContext<'_, '_>) { let location_table = cx.location_table; facts .outlives - .extend(cx.constraints.outlives_constraints.iter().flat_map( + .extend(cx.constraints.outlives_constraints.outlives().iter().flat_map( |constraint: &OutlivesConstraint| { if let Some(from_location) = constraint.locations.from_location() { Either::Left(iter::once(( @@ -236,7 +237,7 @@ fn translate_outlives_facts(cx: &mut BorrowCheckContext<'_, '_>) { } } -fn mirbug(tcx: TyCtxt<'_, '_, '_>, span: Span, msg: &str) { +fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: &str) { // We sometimes see MIR failures (notably predicate failures) due to // the fact that we check rvalue sized predicates here. So use `delay_span_bug` // to avoid reporting bugs in those cases. @@ -252,22 +253,22 @@ enum FieldAccessError { /// The sanitize_XYZ methods here take an MIR object and compute its /// type, calling `span_mirbug` and returning an error type if there /// is a problem. -struct TypeVerifier<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> { - cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, - mir: &'b Mir<'tcx>, +struct TypeVerifier<'a, 'b, 'tcx> { + cx: &'a mut TypeChecker<'b, 'tcx>, + body: &'b Body<'tcx>, last_span: Span, mir_def_id: DefId, errors_reported: bool, } -impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { +impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { fn visit_span(&mut self, span: &Span) { if !span.is_dummy() { self.last_span = *span; } } - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext<'_>, location: Location) { + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { self.sanitize_place(place, location, context); } @@ -295,44 +296,40 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { ); } } else { - match *constant.literal { - ty::LazyConst::Unevaluated(def_id, substs) => { - if let Err(terr) = self.cx.fully_perform_op( - location.to_locations(), - ConstraintCategory::Boring, - self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( - constant.ty, def_id, UserSubsts { substs, user_self_ty: None }, - )), - ) { - span_mirbug!( - self, - constant, - "bad constant type {:?} ({:?})", - constant, - terr - ); - } - } - ty::LazyConst::Evaluated(lit) => { - if let ty::FnDef(def_id, substs) = lit.ty.sty { - let tcx = self.tcx(); - - let instantiated_predicates = tcx - .predicates_of(def_id) - .instantiate(tcx, substs); - self.cx.normalize_and_prove_instantiated_predicates( - instantiated_predicates, - location.to_locations(), - ); - } + if let ConstValue::Unevaluated(def_id, substs) = constant.literal.val { + if let Err(terr) = self.cx.fully_perform_op( + location.to_locations(), + ConstraintCategory::Boring, + self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( + constant.ty, def_id, UserSubsts { substs, user_self_ty: None }, + )), + ) { + span_mirbug!( + self, + constant, + "bad constant type {:?} ({:?})", + constant, + terr + ); } } + if let ty::FnDef(def_id, substs) = constant.literal.ty.sty { + let tcx = self.tcx(); + + let instantiated_predicates = tcx + .predicates_of(def_id) + .instantiate(tcx, substs); + self.cx.normalize_and_prove_instantiated_predicates( + instantiated_predicates, + location.to_locations(), + ); + } } } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { self.super_rvalue(rvalue, location); - let rval_ty = rvalue.ty(self.mir, self.tcx()); + let rval_ty = rvalue.ty(self.body, self.tcx()); self.sanitize_type(rvalue, rval_ty); } @@ -373,30 +370,30 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } - fn visit_mir(&mut self, mir: &Mir<'tcx>) { - self.sanitize_type(&"return type", mir.return_ty()); - for local_decl in &mir.local_decls { + fn visit_body(&mut self, body: &Body<'tcx>) { + self.sanitize_type(&"return type", body.return_ty()); + for local_decl in &body.local_decls { self.sanitize_type(local_decl, local_decl.ty); } if self.errors_reported { return; } - self.super_mir(mir); + self.super_body(body); } } -impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { - fn new(cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, mir: &'b Mir<'tcx>) -> Self { +impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { + fn new(cx: &'a mut TypeChecker<'b, 'tcx>, body: &'b Body<'tcx>) -> Self { TypeVerifier { - mir, + body, mir_def_id: cx.mir_def_id, cx, - last_span: mir.span, + last_span: body.span, errors_reported: false, } } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.cx.infcx.tcx } @@ -417,10 +414,11 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { constant, location ); - let literal = match constant.literal { - ty::LazyConst::Evaluated(lit) => lit, - ty::LazyConst::Unevaluated(..) => return, - }; + let literal = constant.literal; + + if let ConstValue::Unevaluated(..) = literal.val { + return; + } debug!("sanitize_constant: expected_ty={:?}", literal.ty); @@ -448,167 +446,171 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { &mut self, place: &Place<'tcx>, location: Location, - context: PlaceContext<'_>, + context: PlaceContext, ) -> PlaceTy<'tcx> { debug!("sanitize_place: {:?}", place); - let place_ty = match *place { - Place::Base(PlaceBase::Local(index)) => PlaceTy::Ty { - ty: self.mir.local_decls[index].ty, - }, - Place::Base(PlaceBase::Promoted(box (index, sty))) => { - let sty = self.sanitize_type(place, sty); - if !self.errors_reported { - let promoted_mir = &self.mir.promoted[index]; - self.sanitize_promoted(promoted_mir, location); + place.iterate(|place_base, place_projection| { + let mut place_ty = match place_base { + PlaceBase::Local(index) => + PlaceTy::from_ty(self.body.local_decls[*index].ty), + PlaceBase::Static(box Static { kind, ty: sty }) => { + let sty = self.sanitize_type(place, sty); + let check_err = + |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, + place: &Place<'tcx>, + ty, + sty| { + if let Err(terr) = verifier.cx.eq_types( + sty, + ty, + location.to_locations(), + ConstraintCategory::Boring, + ) { + span_mirbug!( + verifier, + place, + "bad promoted type ({:?}: {:?}): {:?}", + ty, + sty, + terr + ); + }; + }; + match kind { + StaticKind::Promoted(promoted) => { + if !self.errors_reported { + let promoted_body = &self.body.promoted[*promoted]; + self.sanitize_promoted(promoted_body, location); + + let promoted_ty = promoted_body.return_ty(); + check_err(self, place, promoted_ty, sty); + } + } + StaticKind::Static(def_id) => { + let ty = self.tcx().type_of(*def_id); + let ty = self.cx.normalize(ty, location); - let promoted_ty = promoted_mir.return_ty(); + check_err(self, place, ty, sty); + } + } + PlaceTy::from_ty(sty) + } + }; - if let Err(terr) = self.cx.eq_types( - sty, - promoted_ty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - self, - place, - "bad promoted type ({:?}: {:?}): {:?}", - promoted_ty, - sty, - terr - ); + // FIXME use place_projection.is_empty() when is available + if let Place::Base(_) = place { + if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { + let tcx = self.tcx(); + let trait_ref = ty::TraitRef { + def_id: tcx.lang_items().copy_trait().unwrap(), + substs: tcx.mk_substs_trait(place_ty.ty, &[]), }; - } - PlaceTy::Ty { ty: sty } - } - Place::Base(PlaceBase::Static(box Static { def_id, ty: sty })) => { - let sty = self.sanitize_type(place, sty); - let ty = self.tcx().type_of(def_id); - let ty = self.cx.normalize(ty, location); - if let Err(terr) = - self.cx - .eq_types(ty, sty, location.to_locations(), ConstraintCategory::Boring) - { - span_mirbug!( - self, - place, - "bad static type ({:?}: {:?}): {:?}", - ty, - sty, - terr + + // In order to have a Copy operand, the type T of the + // value must be Copy. Note that we prove that T: Copy, + // rather than using the `is_copy_modulo_regions` + // test. This is important because + // `is_copy_modulo_regions` ignores the resulting region + // obligations and assumes they pass. This can result in + // bounds from Copy impls being unsoundly ignored (e.g., + // #29149). Note that we decide to use Copy before knowing + // whether the bounds fully apply: in effect, the rule is + // that if a value of some type could implement Copy, then + // it must. + self.cx.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::CopyBound, ); } - PlaceTy::Ty { ty: sty } } - Place::Projection(ref proj) => { - let base_context = if context.is_mutating_use() { - PlaceContext::MutatingUse(MutatingUseContext::Projection) - } else { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) - }; - let base_ty = self.sanitize_place(&proj.base, location, base_context); - if let PlaceTy::Ty { ty } = base_ty { - if ty.references_error() { + + for proj in place_projection { + if place_ty.variant_index.is_none() { + if place_ty.ty.references_error() { assert!(self.errors_reported); - return PlaceTy::Ty { - ty: self.tcx().types.err, - }; + return PlaceTy::from_ty(self.tcx().types.err); } } - self.sanitize_projection(base_ty, &proj.elem, place, location) + place_ty = self.sanitize_projection(place_ty, &proj.elem, place, location) } - }; - if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { - let tcx = self.tcx(); - let trait_ref = ty::TraitRef { - def_id: tcx.lang_items().copy_trait().unwrap(), - substs: tcx.mk_substs_trait(place_ty.to_ty(tcx), &[]), - }; - // In order to have a Copy operand, the type T of the - // value must be Copy. Note that we prove that T: Copy, - // rather than using the `is_copy_modulo_regions` - // test. This is important because - // `is_copy_modulo_regions` ignores the resulting region - // obligations and assumes they pass. This can result in - // bounds from Copy impls being unsoundly ignored (e.g., - // #29149). Note that we decide to use Copy before knowing - // whether the bounds fully apply: in effect, the rule is - // that if a value of some type could implement Copy, then - // it must. - self.cx.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::CopyBound, - ); - } - place_ty + place_ty + }) } - fn sanitize_promoted(&mut self, promoted_mir: &'b Mir<'tcx>, location: Location) { + fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) { // Determine the constraints from the promoted MIR by running the type // checker on the promoted MIR, then transfer the constraints back to // the main MIR, changing the locations to the provided location. - let parent_mir = mem::replace(&mut self.mir, promoted_mir); + let parent_body = mem::replace(&mut self.body, promoted_body); let all_facts = &mut None; let mut constraints = Default::default(); let mut closure_bounds = Default::default(); - if let Some(ref mut bcx) = self.cx.borrowck_context { - // Don't try to add borrow_region facts for the promoted MIR - mem::swap(bcx.all_facts, all_facts); - - // Use a new sets of constraints and closure bounds so that we can - // modify their locations. - mem::swap(&mut bcx.constraints.outlives_constraints, &mut constraints); - mem::swap(&mut bcx.constraints.closure_bounds_mapping, &mut closure_bounds); - }; + // Don't try to add borrow_region facts for the promoted MIR + mem::swap(self.cx.borrowck_context.all_facts, all_facts); + + // Use a new sets of constraints and closure bounds so that we can + // modify their locations. + mem::swap( + &mut self.cx.borrowck_context.constraints.outlives_constraints, + &mut constraints + ); + mem::swap( + &mut self.cx.borrowck_context.constraints.closure_bounds_mapping, + &mut closure_bounds + ); - self.visit_mir(promoted_mir); + self.visit_body(promoted_body); if !self.errors_reported { // if verifier failed, don't do further checks to avoid ICEs - self.cx.typeck_mir(promoted_mir); + self.cx.typeck_mir(promoted_body); } - self.mir = parent_mir; + self.body = parent_body; // Merge the outlives constraints back in, at the given location. - if let Some(ref mut base_bcx) = self.cx.borrowck_context { - mem::swap(base_bcx.all_facts, all_facts); - mem::swap(&mut base_bcx.constraints.outlives_constraints, &mut constraints); - mem::swap(&mut base_bcx.constraints.closure_bounds_mapping, &mut closure_bounds); - - let locations = location.to_locations(); - for constraint in constraints.iter() { - let mut constraint = *constraint; - constraint.locations = locations; - if let ConstraintCategory::Return - | ConstraintCategory::UseAsConst - | ConstraintCategory::UseAsStatic = constraint.category - { - // "Returning" from a promoted is an assigment to a - // temporary from the user's point of view. - constraint.category = ConstraintCategory::Boring; - } - base_bcx.constraints.outlives_constraints.push(constraint) - } + mem::swap(self.cx.borrowck_context.all_facts, all_facts); + mem::swap( + &mut self.cx.borrowck_context.constraints.outlives_constraints, + &mut constraints + ); + mem::swap( + &mut self.cx.borrowck_context.constraints.closure_bounds_mapping, + &mut closure_bounds + ); - if !closure_bounds.is_empty() { - let combined_bounds_mapping = closure_bounds - .into_iter() - .flat_map(|(_, value)| value) - .collect(); - let existing = base_bcx - .constraints - .closure_bounds_mapping - .insert(location, combined_bounds_mapping); - assert!( - existing.is_none(), - "Multiple promoteds/closures at the same location." - ); + let locations = location.to_locations(); + for constraint in constraints.outlives().iter() { + let mut constraint = *constraint; + constraint.locations = locations; + if let ConstraintCategory::Return + | ConstraintCategory::UseAsConst + | ConstraintCategory::UseAsStatic = constraint.category + { + // "Returning" from a promoted is an assigment to a + // temporary from the user's point of view. + constraint.category = ConstraintCategory::Boring; } + self.cx.borrowck_context.constraints.outlives_constraints.push(constraint) + } + + if !closure_bounds.is_empty() { + let combined_bounds_mapping = closure_bounds + .into_iter() + .flat_map(|(_, value)| value) + .collect(); + let existing = self.cx.borrowck_context + .constraints + .closure_bounds_mapping + .insert(location, combined_bounds_mapping); + assert!( + existing.is_none(), + "Multiple promoteds/closures at the same location." + ); } } @@ -621,40 +623,40 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ) -> PlaceTy<'tcx> { debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place); let tcx = self.tcx(); - let base_ty = base.to_ty(tcx); + let base_ty = base.ty; match *pi { ProjectionElem::Deref => { let deref_ty = base_ty.builtin_deref(true); - PlaceTy::Ty { - ty: deref_ty.map(|t| t.ty).unwrap_or_else(|| { + PlaceTy::from_ty( + deref_ty.map(|t| t.ty).unwrap_or_else(|| { span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty) - }), - } + }) + ) } ProjectionElem::Index(i) => { - let index_ty = Place::Base(PlaceBase::Local(i)).ty(self.mir, tcx).to_ty(tcx); + let index_ty = Place::from(i).ty(self.body, tcx).ty; if index_ty != tcx.types.usize { - PlaceTy::Ty { - ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i), - } + PlaceTy::from_ty( + span_mirbug_and_err!(self, i, "index by non-usize {:?}", i), + ) } else { - PlaceTy::Ty { - ty: base_ty.builtin_index().unwrap_or_else(|| { + PlaceTy::from_ty( + base_ty.builtin_index().unwrap_or_else(|| { span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) }), - } + ) } } ProjectionElem::ConstantIndex { .. } => { // consider verifying in-bounds - PlaceTy::Ty { - ty: base_ty.builtin_index().unwrap_or_else(|| { + PlaceTy::from_ty( + base_ty.builtin_index().unwrap_or_else(|| { span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) }), - } + ) } - ProjectionElem::Subslice { from, to } => PlaceTy::Ty { - ty: match base_ty.sty { + ProjectionElem::Subslice { from, to } => PlaceTy::from_ty( + match base_ty.sty { ty::Array(inner, size) => { let size = size.unwrap_usize(tcx); let min_size = (from as u64) + (to as u64); @@ -672,35 +674,41 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ty::Slice(..) => base_ty, _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty), }, - }, - ProjectionElem::Downcast(adt_def1, index) => match base_ty.sty { - ty::Adt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => { + ), + ProjectionElem::Downcast(maybe_name, index) => match base_ty.sty { + ty::Adt(adt_def, _substs) if adt_def.is_enum() => { if index.as_usize() >= adt_def.variants.len() { - PlaceTy::Ty { - ty: span_mirbug_and_err!( + PlaceTy::from_ty( + span_mirbug_and_err!( self, place, "cast to variant #{:?} but enum only has {:?}", index, adt_def.variants.len() ), - } + ) } else { - PlaceTy::Downcast { - adt_def, - substs, - variant_index: index, + PlaceTy { + ty: base_ty, + variant_index: Some(index), } } } - _ => PlaceTy::Ty { - ty: span_mirbug_and_err!( - self, - place, - "can't downcast {:?} as {:?}", - base_ty, - adt_def1 - ), + // We do not need to handle generators here, because this runs + // before the generator transform stage. + _ => { + let ty = if let Some(name) = maybe_name { + span_mirbug_and_err!( + self, + place, + "can't downcast {:?} as {:?}", + base_ty, + name + ) + } else { + span_mirbug_and_err!(self, place, "can't downcast {:?}", base_ty) + }; + PlaceTy::from_ty(ty) }, }, ProjectionElem::Field(field, fty) => { @@ -729,7 +737,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { field_count ), } - PlaceTy::Ty { ty: fty } + PlaceTy::from_ty(fty) } } } @@ -749,12 +757,28 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { let tcx = self.tcx(); let (variant, substs) = match base_ty { - PlaceTy::Downcast { - adt_def, - substs, - variant_index, - } => (&adt_def.variants[variant_index], substs), - PlaceTy::Ty { ty } => match ty.sty { + PlaceTy { ty, variant_index: Some(variant_index) } => match ty.sty { + ty::Adt(adt_def, substs) => (&adt_def.variants[variant_index], substs), + ty::Generator(def_id, substs, _) => { + let mut variants = substs.state_tys(def_id, tcx); + let mut variant = match variants.nth(variant_index.into()) { + Some(v) => v, + None => { + bug!("variant_index of generator out of range: {:?}/{:?}", + variant_index, + substs.state_tys(def_id, tcx).count()) + } + }; + return match variant.nth(field.index()) { + Some(ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: variant.count(), + }), + } + } + _ => bug!("can't have downcast of non-adt non-generator type"), + } + PlaceTy { ty, variant_index: None } => match ty.sty { ty::Adt(adt_def, substs) if !adt_def.is_enum() => (&adt_def.variants[VariantIdx::new(0)], substs), ty::Closure(def_id, substs) => { @@ -766,23 +790,18 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } ty::Generator(def_id, substs, _) => { - // Try pre-transform fields first (upvars and current state) - if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field.index()) { - return Ok(ty); - } - - // Then try `field_tys` which contains all the fields, but it - // requires the final optimized MIR. - return match substs.field_tys(def_id, tcx).nth(field.index()) { + // Only prefix fields (upvars and current state) are + // accessible without a variant index. + return match substs.prefix_tys(def_id, tcx).nth(field.index()) { Some(ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { - field_count: substs.field_tys(def_id, tcx).count(), + field_count: substs.prefix_tys(def_id, tcx).count(), }), - }; + } } ty::Tuple(tys) => { return match tys.get(field.index()) { - Some(&ty) => Ok(ty), + Some(&ty) => Ok(ty.expect_ty()), None => Err(FieldAccessError::OutOfRange { field_count: tys.len(), }), @@ -813,22 +832,23 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { /// constraints needed for it to be valid and well-typed. Along the /// way, it accrues region constraints -- these can later be used by /// NLL region checking. -struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> { - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'gcx>, +struct TypeChecker<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, last_span: Span, + body: &'a Body<'tcx>, /// User type annotations are shared between the main MIR and the MIR of /// all of the promoted items. user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, mir_def_id: DefId, region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: Option>, + implicit_region_bound: ty::Region<'tcx>, reported_errors: FxHashSet<(Ty<'tcx>, Span)>, - borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, - universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>, + borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, + universal_region_relations: &'a UniversalRegionRelations<'tcx>, } -struct BorrowCheckContext<'a, 'tcx: 'a> { +struct BorrowCheckContext<'a, 'tcx> { universal_regions: &'a UniversalRegions<'tcx>, location_table: &'a LocationTable, all_facts: &'a mut Option, @@ -867,7 +887,9 @@ crate struct MirTypeckRegionConstraints<'tcx> { /// hence it must report on their liveness constraints. crate liveness_constraints: LivenessValues, - crate outlives_constraints: ConstraintSet, + crate outlives_constraints: OutlivesConstraintSet, + + crate member_constraints: MemberConstraintSet<'tcx, RegionVid>, crate closure_bounds_mapping: FxHashMap>, @@ -878,7 +900,7 @@ crate struct MirTypeckRegionConstraints<'tcx> { impl MirTypeckRegionConstraints<'tcx> { fn placeholder_region( &mut self, - infcx: &InferCtxt<'_, '_, 'tcx>, + infcx: &InferCtxt<'_, 'tcx>, placeholder: ty::PlaceholderRegion, ) -> ty::Region<'tcx> { let placeholder_index = self.placeholder_indices.insert(placeholder); @@ -952,30 +974,31 @@ impl Locations { } /// Gets a span representing the location. - pub fn span(&self, mir: &Mir<'_>) -> Span { + pub fn span(&self, body: &Body<'_>) -> Span { match self { Locations::All(span) => *span, - Locations::Single(l) => mir.source_info(*l).span, + Locations::Single(l) => body.source_info(*l).span, } } } -impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn new( - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, + infcx: &'a InferCtxt<'a, 'tcx>, + body: &'a Body<'tcx>, mir_def_id: DefId, - param_env: ty::ParamEnv<'gcx>, + param_env: ty::ParamEnv<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: Option>, - borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, - universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>, + implicit_region_bound: ty::Region<'tcx>, + borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, + universal_region_relations: &'a UniversalRegionRelations<'tcx>, ) -> Self { let mut checker = Self { infcx, last_span: DUMMY_SP, mir_def_id, - user_type_annotations: &mir.user_type_annotations, + body, + user_type_annotations: &body.user_type_annotations, param_env, region_bound_pairs, implicit_region_bound, @@ -1061,7 +1084,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { &mut self, locations: Locations, category: ConstraintCategory, - op: impl type_op::TypeOp<'gcx, 'tcx, Output = R>, + op: impl type_op::TypeOp<'tcx, Output = R>, ) -> Fallible { let (r, opt_data) = op.fully_perform(self.infcx)?; @@ -1076,25 +1099,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { &mut self, locations: Locations, category: ConstraintCategory, - data: &[QueryRegionConstraint<'tcx>], + data: &QueryRegionConstraints<'tcx>, ) { debug!( "push_region_constraints: constraints generated at {:?} are {:#?}", locations, data ); - if let Some(ref mut borrowck_context) = self.borrowck_context { - constraint_conversion::ConstraintConversion::new( - self.infcx, - borrowck_context.universal_regions, - self.region_bound_pairs, - self.implicit_region_bound, - self.param_env, - locations, - category, - &mut borrowck_context.constraints, - ).convert_all(&data); - } + constraint_conversion::ConstraintConversion::new( + self.infcx, + self.borrowck_context.universal_regions, + self.region_bound_pairs, + Some(self.implicit_region_bound), + self.param_env, + locations, + category, + &mut self.borrowck_context.constraints, + ).convert_all(data); } /// Convenient wrapper around `relate_tys::relate_types` -- see @@ -1114,7 +1135,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { b, locations, category, - self.borrowck_context.as_mut().map(|x| &mut **x), + Some(self.borrowck_context), ) } @@ -1140,7 +1161,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { category: ConstraintCategory, ) -> Fallible<()> { if let Err(terr) = self.sub_types(sub, sup, locations, category) { - if let TyKind::Opaque(..) = sup.sty { + if let ty::Opaque(..) = sup.sty { // When you have `let x: impl Foo = ...` in a closure, // the resulting inferend values are stored with the // def-id of the base function. @@ -1167,7 +1188,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { &mut self, a: Ty<'tcx>, v: ty::Variance, - user_ty: &UserTypeProjection<'tcx>, + user_ty: &UserTypeProjection, locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { @@ -1191,7 +1212,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}", user_ty.base, annotated_type, user_ty.projs, curr_projected_ty); - let ty = curr_projected_ty.to_ty(tcx); + let ty = curr_projected_ty.ty; self.relate_types(a, v, ty, locations, category)?; Ok(()) @@ -1214,6 +1235,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let infcx = self.infcx; let tcx = infcx.tcx; let param_env = self.param_env; + let body = self.body; debug!("eq_opaque_type_and_type: mir_def_id={:?}", self.mir_def_id); let opaque_type_map = self.fully_perform_op( locations, @@ -1229,6 +1251,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { dummy_body_id, param_env, &anon_ty, + locations.span(body), )); debug!( "eq_opaque_type_and_type: \ @@ -1248,7 +1271,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { debug!( "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}", opaque_decl.concrete_ty, - infcx.resolve_type_vars_if_possible(&opaque_decl.concrete_ty), + infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty), opaque_defn_ty ); obligations.add(infcx @@ -1267,10 +1290,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ), )?; - let universal_region_relations = match self.universal_region_relations { - Some(rel) => rel, - None => return Ok(()), - }; + let universal_region_relations = self.universal_region_relations; // Finally, if we instantiated the anon types successfully, we // have to solve any bounds (e.g., `-> impl Iterator` needs to @@ -1301,11 +1321,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { Ok(()) } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } - fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Location) { + fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) { debug!("check_stmt: {:?}", stmt); let tcx = self.tcx(); match stmt.kind { @@ -1315,16 +1335,16 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // of lowering. Assignments to other sorts of places *are* interesting // though. let category = match *place { - Place::Base(PlaceBase::Local(RETURN_PLACE)) => if let Some(BorrowCheckContext { + Place::Base(PlaceBase::Local(RETURN_PLACE)) => if let BorrowCheckContext { universal_regions: UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, .. - }) = self.borrowck_context + } = self.borrowck_context { - if tcx.is_static(*def_id).is_some() { + if tcx.is_static(*def_id) { ConstraintCategory::UseAsStatic } else { ConstraintCategory::UseAsConst @@ -1333,14 +1353,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ConstraintCategory::Return }, Place::Base(PlaceBase::Local(l)) - if !mir.local_decls[l].is_user_variable.is_some() => { + if !body.local_decls[l].is_user_variable.is_some() => { ConstraintCategory::Boring } _ => ConstraintCategory::Assignment, }; - let place_ty = place.ty(mir, tcx).to_ty(tcx); - let rv_ty = rv.ty(mir, tcx); + let place_ty = place.ty(body, tcx).ty; + let rv_ty = rv.ty(body, tcx); if let Err(terr) = self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category) { @@ -1374,7 +1394,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - self.check_rvalue(mir, rv, location); + self.check_rvalue(body, rv, location); if !self.tcx().features().unsized_locals { let trait_ref = ty::TraitRef { def_id: tcx.lang_items().sized_trait().unwrap(), @@ -1391,9 +1411,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ref place, variant_index, } => { - let place_type = place.ty(mir, tcx).to_ty(tcx); + let place_type = place.ty(body, tcx).ty; let adt = match place_type.sty { - TyKind::Adt(adt, _) if adt.is_enum() => adt, + ty::Adt(adt, _) if adt.is_enum() => adt, _ => { span_bug!( stmt.source_info.span, @@ -1413,7 +1433,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }; } StatementKind::AscribeUserType(ref place, variance, box ref projection) => { - let place_ty = place.ty(mir, tcx).to_ty(tcx); + let place_ty = place.ty(body, tcx).ty; if let Err(terr) = self.relate_type_and_user_type( place_ty, variance, @@ -1444,7 +1464,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn check_terminator( &mut self, - mir: &Mir<'tcx>, + body: &Body<'tcx>, term: &Terminator<'tcx>, term_location: Location, ) { @@ -1469,8 +1489,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { target: _, unwind: _, } => { - let place_ty = location.ty(mir, tcx).to_ty(tcx); - let rv_ty = value.ty(mir, tcx); + let place_ty = location.ty(body, tcx).ty; + let rv_ty = value.ty(body, tcx); let locations = term_location.to_locations(); if let Err(terr) = @@ -1491,7 +1511,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { switch_ty, .. } => { - let discr_ty = discr.ty(mir, tcx); + let discr_ty = discr.ty(body, tcx); if let Err(terr) = self.sub_types( discr_ty, switch_ty, @@ -1519,7 +1539,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { from_hir_call, .. } => { - let func_ty = func.ty(mir, tcx); + let func_ty = func.ty(body, tcx); debug!("check_terminator: call, func_ty={:?}", func_ty); let sig = match func_ty.sty { ty::FnDef(..) | ty::FnPtr(_) => func_ty.fn_sig(tcx), @@ -1534,7 +1554,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { &sig, ); let sig = self.normalize(sig, term_location); - self.check_call_dest(mir, term, &sig, destination, term_location); + self.check_call_dest(body, term, &sig, destination, term_location); self.prove_predicates( sig.inputs_and_output.iter().map(|ty| ty::Predicate::WellFormed(ty)), @@ -1550,39 +1570,37 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // output) types in the signature must be live, since // all the inputs that fed into it were live. for &late_bound_region in map.values() { - if let Some(ref mut borrowck_context) = self.borrowck_context { - let region_vid = borrowck_context - .universal_regions - .to_region_vid(late_bound_region); - borrowck_context - .constraints - .liveness_constraints - .add_element(region_vid, term_location); - } + let region_vid = self.borrowck_context + .universal_regions + .to_region_vid(late_bound_region); + self.borrowck_context + .constraints + .liveness_constraints + .add_element(region_vid, term_location); } - self.check_call_inputs(mir, term, &sig, args, term_location, from_hir_call); + self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call); } TerminatorKind::Assert { ref cond, ref msg, .. } => { - let cond_ty = cond.ty(mir, tcx); + let cond_ty = cond.ty(body, tcx); if cond_ty != tcx.types.bool { span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); } if let BoundsCheck { ref len, ref index } = *msg { - if len.ty(mir, tcx) != tcx.types.usize { + if len.ty(body, tcx) != tcx.types.usize { span_mirbug!(self, len, "bounds-check length non-usize {:?}", len) } - if index.ty(mir, tcx) != tcx.types.usize { + if index.ty(body, tcx) != tcx.types.usize { span_mirbug!(self, index, "bounds-check index non-usize {:?}", index) } } } TerminatorKind::Yield { ref value, .. } => { - let value_ty = value.ty(mir, tcx); - match mir.yield_ty { + let value_ty = value.ty(body, tcx); + match body.yield_ty { None => span_mirbug!(self, term, "yield in non-generator"), Some(ty) => { if let Err(terr) = self.sub_types( @@ -1608,7 +1626,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn check_call_dest( &mut self, - mir: &Mir<'tcx>, + body: &Body<'tcx>, term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, destination: &Option<(Place<'tcx>, BasicBlock)>, @@ -1617,19 +1635,19 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let tcx = self.tcx(); match *destination { Some((ref dest, _target_block)) => { - let dest_ty = dest.ty(mir, tcx).to_ty(tcx); + let dest_ty = dest.ty(body, tcx).ty; let category = match *dest { Place::Base(PlaceBase::Local(RETURN_PLACE)) => { - if let Some(BorrowCheckContext { + if let BorrowCheckContext { universal_regions: UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, .. - }) = self.borrowck_context + } = self.borrowck_context { - if tcx.is_static(*def_id).is_some() { + if tcx.is_static(*def_id) { ConstraintCategory::UseAsStatic } else { ConstraintCategory::UseAsConst @@ -1639,7 +1657,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } Place::Base(PlaceBase::Local(l)) - if !mir.local_decls[l].is_user_variable.is_some() => { + if !body.local_decls[l].is_user_variable.is_some() => { ConstraintCategory::Boring } _ => ConstraintCategory::Assignment, @@ -1677,7 +1695,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn check_call_inputs( &mut self, - mir: &Mir<'tcx>, + body: &Body<'tcx>, term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, args: &[Operand<'tcx>], @@ -1685,7 +1703,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { from_hir_call: bool, ) { debug!("check_call_inputs({:?}, {:?})", sig, args); - // Do not count the `VaList` argument as a "true" argument to + // Do not count the `VaListImpl` argument as a "true" argument to // a C-variadic function. let inputs = if sig.c_variadic { &sig.inputs()[..sig.inputs().len() - 1] @@ -1696,7 +1714,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); } for (n, (fn_arg, op_arg)) in inputs.iter().zip(args).enumerate() { - let op_arg_ty = op_arg.ty(mir, self.tcx()); + let op_arg_ty = op_arg.ty(body, self.tcx()); let category = if from_hir_call { ConstraintCategory::CallArgument } else { @@ -1718,15 +1736,15 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>) { + fn check_iscleanup(&mut self, body: &Body<'tcx>, block_data: &BasicBlockData<'tcx>) { let is_cleanup = block_data.is_cleanup; self.last_span = block_data.terminator().source_info.span; match block_data.terminator().kind { TerminatorKind::Goto { target } => { - self.assert_iscleanup(mir, block_data, target, is_cleanup) + self.assert_iscleanup(body, block_data, target, is_cleanup) } TerminatorKind::SwitchInt { ref targets, .. } => for target in targets { - self.assert_iscleanup(mir, block_data, *target, is_cleanup); + self.assert_iscleanup(body, block_data, *target, is_cleanup); }, TerminatorKind::Resume => if !is_cleanup { span_mirbug!(self, block_data, "resume on non-cleanup block!") @@ -1744,9 +1762,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { if is_cleanup { span_mirbug!(self, block_data, "yield in cleanup block") } - self.assert_iscleanup(mir, block_data, resume, is_cleanup); + self.assert_iscleanup(body, block_data, resume, is_cleanup); if let Some(drop) = drop { - self.assert_iscleanup(mir, block_data, drop, is_cleanup); + self.assert_iscleanup(body, block_data, drop, is_cleanup); } } TerminatorKind::Unreachable => {} @@ -1757,12 +1775,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { cleanup: unwind, .. } => { - self.assert_iscleanup(mir, block_data, target, is_cleanup); + self.assert_iscleanup(body, block_data, target, is_cleanup); if let Some(unwind) = unwind { if is_cleanup { span_mirbug!(self, block_data, "unwind on cleanup block") } - self.assert_iscleanup(mir, block_data, unwind, true); + self.assert_iscleanup(body, block_data, unwind, true); } } TerminatorKind::Call { @@ -1771,29 +1789,27 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { .. } => { if let &Some((_, target)) = destination { - self.assert_iscleanup(mir, block_data, target, is_cleanup); + self.assert_iscleanup(body, block_data, target, is_cleanup); } if let Some(cleanup) = cleanup { if is_cleanup { span_mirbug!(self, block_data, "cleanup on cleanup block") } - self.assert_iscleanup(mir, block_data, cleanup, true); + self.assert_iscleanup(body, block_data, cleanup, true); } } TerminatorKind::FalseEdges { real_target, - ref imaginary_targets, + imaginary_target, } => { - self.assert_iscleanup(mir, block_data, real_target, is_cleanup); - for target in imaginary_targets { - self.assert_iscleanup(mir, block_data, *target, is_cleanup); - } + self.assert_iscleanup(body, block_data, real_target, is_cleanup); + self.assert_iscleanup(body, block_data, imaginary_target, is_cleanup); } TerminatorKind::FalseUnwind { real_target, unwind, } => { - self.assert_iscleanup(mir, block_data, real_target, is_cleanup); + self.assert_iscleanup(body, block_data, real_target, is_cleanup); if let Some(unwind) = unwind { if is_cleanup { span_mirbug!( @@ -1802,7 +1818,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { "cleanup in cleanup block via false unwind" ); } - self.assert_iscleanup(mir, block_data, unwind, true); + self.assert_iscleanup(body, block_data, unwind, true); } } } @@ -1810,12 +1826,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn assert_iscleanup( &mut self, - mir: &Mir<'tcx>, + body: &Body<'tcx>, ctxt: &dyn fmt::Debug, bb: BasicBlock, iscleanuppad: bool, ) { - if mir[bb].is_cleanup != iscleanuppad { + if body[bb].is_cleanup != iscleanuppad { span_mirbug!( self, ctxt, @@ -1826,8 +1842,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn check_local(&mut self, mir: &Mir<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) { - match mir.local_kind(local) { + fn check_local(&mut self, body: &Body<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) { + match body.local_kind(local) { LocalKind::ReturnPointer | LocalKind::Arg => { // return values of normal functions are required to be // sized by typeck, but return values of ADT constructors are @@ -1856,7 +1872,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // `Sized` bound in no way depends on precise regions, so this // shouldn't affect `is_sized`. let gcx = tcx.global_tcx(); - let erased_ty = gcx.lift(&tcx.erase_regions(&ty)).unwrap(); + let erased_ty = tcx.erase_regions(&ty); if !erased_ty.is_sized(gcx.at(span), self.param_env) { // in current MIR construction, all non-control-flow rvalue // expressions evaluate through `as_temp` or `into` a return @@ -1911,18 +1927,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } AggregateKind::Generator(def_id, substs, _) => { - // Try pre-transform fields first (upvars and current state) - if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field_index) { - Ok(ty) - } else { - // Then try `field_tys` which contains all the fields, but it - // requires the final optimized MIR. - match substs.field_tys(def_id, tcx).nth(field_index) { - Some(ty) => Ok(ty), - None => Err(FieldAccessError::OutOfRange { - field_count: substs.field_tys(def_id, tcx).count(), - }), - } + // It doesn't make sense to look at a field beyond the prefix; + // these require a variant index, and are not initialized in + // aggregate rvalues. + match substs.prefix_tys(def_id, tcx).nth(field_index) { + Some(ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: substs.prefix_tys(def_id, tcx).count(), + }), } } AggregateKind::Array(ty) => Ok(ty), @@ -1932,16 +1944,16 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn check_rvalue(&mut self, mir: &Mir<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { + fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { let tcx = self.tcx(); match rvalue { Rvalue::Aggregate(ak, ops) => { - self.check_aggregate_rvalue(mir, rvalue, ak, ops, location) + self.check_aggregate_rvalue(body, rvalue, ak, ops, location) } Rvalue::Repeat(operand, len) => if *len > 1 { - let operand_ty = operand.ty(mir, tcx); + let operand_ty = operand.ty(body, tcx); let trait_ref = ty::TraitRef { def_id: tcx.lang_items().copy_trait().unwrap(), @@ -1958,7 +1970,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { Rvalue::NullaryOp(_, ty) => { // Even with unsized locals cannot box an unsized value. if self.tcx().features().unsized_locals { - let span = mir.source_info(location).span; + let span = body.source_info(location).span; self.ensure_place_sized(ty, span); } @@ -1976,8 +1988,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { Rvalue::Cast(cast_kind, op, ty) => { match cast_kind { - CastKind::ReifyFnPointer => { - let fn_sig = op.ty(mir, tcx).fn_sig(tcx); + CastKind::Pointer(PointerCast::ReifyFnPointer) => { + let fn_sig = op.ty(body, tcx).fn_sig(tcx); // The type that we see in the fcx is like // `foo::<'a, 'b>`, where `foo` is the path to a @@ -2005,14 +2017,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - CastKind::ClosureFnPointer => { - let sig = match op.ty(mir, tcx).sty { + CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety)) => { + let sig = match op.ty(body, tcx).sty { ty::Closure(def_id, substs) => { substs.closure_sig_ty(def_id, tcx).fn_sig(tcx) } _ => bug!(), }; - let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig); + let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig, *unsafety); if let Err(terr) = self.eq_types( ty_fn_ptr_from, @@ -2031,8 +2043,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - CastKind::UnsafeFnPointer => { - let fn_sig = op.ty(mir, tcx).fn_sig(tcx); + CastKind::Pointer(PointerCast::UnsafeFnPointer) => { + let fn_sig = op.ty(body, tcx).fn_sig(tcx); // The type that we see in the fcx is like // `foo::<'a, 'b>`, where `foo` is the path to a @@ -2060,11 +2072,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - CastKind::Unsize => { + CastKind::Pointer(PointerCast::Unsize) => { let &ty = ty; let trait_ref = ty::TraitRef { def_id: tcx.lang_items().coerce_unsized_trait().unwrap(), - substs: tcx.mk_substs_trait(op.ty(mir, tcx), &[ty.into()]), + substs: tcx.mk_substs_trait(op.ty(body, tcx), &[ty.into()]), }; self.prove_trait_ref( @@ -2074,15 +2086,166 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); } - CastKind::Misc => {} + CastKind::Pointer(PointerCast::MutToConstPointer) => { + let ty_from = match op.ty(body, tcx).sty { + ty::RawPtr(ty::TypeAndMut { + ty: ty_from, + mutbl: hir::MutMutable, + }) => ty_from, + _ => { + span_mirbug!( + self, + rvalue, + "unexpected base type for cast {:?}", + ty, + ); + return; + } + }; + let ty_to = match ty.sty { + ty::RawPtr(ty::TypeAndMut { + ty: ty_to, + mutbl: hir::MutImmutable, + }) => ty_to, + _ => { + span_mirbug!( + self, + rvalue, + "unexpected target type for cast {:?}", + ty, + ); + return; + } + }; + if let Err(terr) = self.sub_types( + ty_from, + ty_to, + location.to_locations(), + ConstraintCategory::Cast, + ) { + span_mirbug!( + self, + rvalue, + "relating {:?} with {:?} yields {:?}", + ty_from, + ty_to, + terr + ) + } + } + + CastKind::Misc => { + if let ty::Ref(_, mut ty_from, _) = op.ty(body, tcx).sty { + let (mut ty_to, mutability) = if let ty::RawPtr(ty::TypeAndMut { + ty: ty_to, + mutbl, + }) = ty.sty { + (ty_to, mutbl) + } else { + span_mirbug!( + self, + rvalue, + "invalid cast types {:?} -> {:?}", + op.ty(body, tcx), + ty, + ); + return; + }; + + // Handle the direct cast from `&[T; N]` to `*const T` by unwrapping + // any array we find. + while let ty::Array(ty_elem_from, _) = ty_from.sty { + ty_from = ty_elem_from; + if let ty::Array(ty_elem_to, _) = ty_to.sty { + ty_to = ty_elem_to; + } else { + break; + } + } + + if let hir::MutMutable = mutability { + if let Err(terr) = self.eq_types( + ty_from, + ty_to, + location.to_locations(), + ConstraintCategory::Cast, + ) { + span_mirbug!( + self, + rvalue, + "equating {:?} with {:?} yields {:?}", + ty_from, + ty_to, + terr + ) + } + } else { + if let Err(terr) = self.sub_types( + ty_from, + ty_to, + location.to_locations(), + ConstraintCategory::Cast, + ) { + span_mirbug!( + self, + rvalue, + "relating {:?} with {:?} yields {:?}", + ty_from, + ty_to, + terr + ) + } + } + } + } } } Rvalue::Ref(region, _borrow_kind, borrowed_place) => { - self.add_reborrow_constraint(mir, location, region, borrowed_place); + self.add_reborrow_constraint(body, location, region, borrowed_place); + } + + Rvalue::BinaryOp(BinOp::Eq, left, right) + | Rvalue::BinaryOp(BinOp::Ne, left, right) + | Rvalue::BinaryOp(BinOp::Lt, left, right) + | Rvalue::BinaryOp(BinOp::Le, left, right) + | Rvalue::BinaryOp(BinOp::Gt, left, right) + | Rvalue::BinaryOp(BinOp::Ge, left, right) => { + let ty_left = left.ty(body, tcx); + if let ty::RawPtr(_) | ty::FnPtr(_) = ty_left.sty { + let ty_right = right.ty(body, tcx); + let common_ty = self.infcx.next_ty_var( + TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: body.source_info(location).span, + } + ); + self.sub_types( + common_ty, + ty_left, + location.to_locations(), + ConstraintCategory::Boring + ).unwrap_or_else(|err| { + bug!("Could not equate type variable with {:?}: {:?}", ty_left, err) + }); + if let Err(terr) = self.sub_types( + common_ty, + ty_right, + location.to_locations(), + ConstraintCategory::Boring + ) { + span_mirbug!( + self, + rvalue, + "unexpected comparison types {:?} and {:?} yields {:?}", + ty_left, + ty_right, + terr + ) + } + } } - // FIXME: These other cases have to be implemented in future PRs Rvalue::Use(..) | Rvalue::Len(..) | Rvalue::BinaryOp(..) @@ -2120,7 +2283,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn check_aggregate_rvalue( &mut self, - mir: &Mir<'tcx>, + body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, aggregate_kind: &AggregateKind<'tcx>, operands: &[Operand<'tcx>], @@ -2149,7 +2312,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { continue; } }; - let operand_ty = operand.ty(mir, tcx); + let operand_ty = operand.ty(body, tcx); if let Err(terr) = self.sub_types( operand_ty, @@ -2178,7 +2341,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { /// - `borrowed_place`: the place `P` being borrowed fn add_reborrow_constraint( &mut self, - mir: &Mir<'tcx>, + body: &Body<'tcx>, location: Location, borrow_region: ty::Region<'tcx>, borrowed_place: &Place<'tcx>, @@ -2190,10 +2353,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { all_facts, constraints, .. - } = match self.borrowck_context { - Some(ref mut borrowck_context) => borrowck_context, - None => return, - }; + } = self.borrowck_context; // In Polonius mode, we also push a `borrow_region` fact // linking the loan to the region (in some cases, though, @@ -2222,13 +2382,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { "add_reborrow_constraint({:?}, {:?}, {:?})", location, borrow_region, borrowed_place ); - while let Place::Projection(box PlaceProjection { base, elem }) = borrowed_place { + while let Place::Projection(box Projection { base, elem }) = borrowed_place { debug!("add_reborrow_constraint - iteration {:?}", borrowed_place); match *elem { ProjectionElem::Deref => { let tcx = self.infcx.tcx; - let base_ty = base.ty(mir, tcx).to_ty(tcx); + let base_ty = base.ty(body, tcx).ty; debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.sty { @@ -2350,54 +2510,62 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn prove_closure_bounds( &mut self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, + tcx: TyCtxt<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, location: Location, ) -> ty::InstantiatedPredicates<'tcx> { if let Some(closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements { - let closure_constraints = - closure_region_requirements.apply_requirements(tcx, def_id, substs); - - if let Some(ref mut borrowck_context) = self.borrowck_context { - let bounds_mapping = closure_constraints - .iter() - .enumerate() - .filter_map(|(idx, constraint)| { - let ty::OutlivesPredicate(k1, r2) = - constraint.no_bound_vars().unwrap_or_else(|| { - bug!("query_constraint {:?} contained bound vars", constraint,); - }); + let closure_constraints = QueryRegionConstraints { + outlives: closure_region_requirements.apply_requirements(tcx, def_id, substs), + + // Presently, closures never propagate member + // constraints to their parents -- they are enforced + // locally. This is largely a non-issue as member + // constraints only come from `-> impl Trait` and + // friends which don't appear (thus far...) in + // closures. + member_constraints: vec![], + }; - match k1.unpack() { - UnpackedKind::Lifetime(r1) => { - // constraint is r1: r2 - let r1_vid = borrowck_context.universal_regions.to_region_vid(r1); - let r2_vid = borrowck_context.universal_regions.to_region_vid(r2); - let outlives_requirements = - &closure_region_requirements.outlives_requirements[idx]; - Some(( - (r1_vid, r2_vid), - ( - outlives_requirements.category, - outlives_requirements.blame_span, - ), - )) - } - UnpackedKind::Type(_) => None, + let bounds_mapping = closure_constraints + .outlives + .iter() + .enumerate() + .filter_map(|(idx, constraint)| { + let ty::OutlivesPredicate(k1, r2) = + constraint.no_bound_vars().unwrap_or_else(|| { + bug!("query_constraint {:?} contained bound vars", constraint,); + }); + + match k1.unpack() { + UnpackedKind::Lifetime(r1) => { + // constraint is r1: r2 + let r1_vid = self.borrowck_context.universal_regions.to_region_vid(r1); + let r2_vid = self.borrowck_context.universal_regions.to_region_vid(r2); + let outlives_requirements = + &closure_region_requirements.outlives_requirements[idx]; + Some(( + (r1_vid, r2_vid), + ( + outlives_requirements.category, + outlives_requirements.blame_span, + ), + )) } - }) - .collect(); - - let existing = borrowck_context - .constraints - .closure_bounds_mapping - .insert(location, bounds_mapping); - assert!( - existing.is_none(), - "Multiple closures at the same location." - ); - } + UnpackedKind::Type(_) | UnpackedKind::Const(_) => None, + } + }) + .collect(); + + let existing = self.borrowck_context + .constraints + .closure_bounds_mapping + .insert(location, bounds_mapping); + assert!( + existing.is_none(), + "Multiple closures at the same location." + ); self.push_region_constraints( location.to_locations(), @@ -2472,15 +2640,15 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }) } - fn typeck_mir(&mut self, mir: &Mir<'tcx>) { - self.last_span = mir.span; - debug!("run_on_mir: {:?}", mir.span); + fn typeck_mir(&mut self, body: &Body<'tcx>) { + self.last_span = body.span; + debug!("run_on_mir: {:?}", body.span); - for (local, local_decl) in mir.local_decls.iter_enumerated() { - self.check_local(mir, local, local_decl); + for (local, local_decl) in body.local_decls.iter_enumerated() { + self.check_local(body, local, local_decl); } - for (block, block_data) in mir.basic_blocks().iter_enumerated() { + for (block, block_data) in body.basic_blocks().iter_enumerated() { let mut location = Location { block, statement_index: 0, @@ -2489,18 +2657,18 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { if !stmt.source_info.span.is_dummy() { self.last_span = stmt.source_info.span; } - self.check_stmt(mir, stmt, location); + self.check_stmt(body, stmt, location); location.statement_index += 1; } - self.check_terminator(mir, block_data.terminator(), location); - self.check_iscleanup(mir, block_data); + self.check_terminator(body, block_data.terminator(), location); + self.check_iscleanup(body, block_data); } } fn normalize(&mut self, value: T, location: impl NormalizeLocation) -> T where - T: type_op::normalize::Normalizable<'gcx, 'tcx> + Copy, + T: type_op::normalize::Normalizable<'tcx> + Copy + 'tcx, { debug!("normalize(value={:?}, location={:?})", value, location); let param_env = self.param_env; @@ -2515,57 +2683,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } -pub struct TypeckMir; - -impl MirPass for TypeckMir { - fn run_pass<'a, 'tcx>( - &self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource<'tcx>, - mir: &mut Mir<'tcx>, - ) { - let def_id = src.def_id(); - debug!("run_pass: {:?}", def_id); - - // When NLL is enabled, the borrow checker runs the typeck - // itself, so we don't need this MIR pass anymore. - if tcx.use_mir_borrowck() { - return; - } - - if tcx.sess.err_count() > 0 { - // compiling a broken program can obviously result in a - // broken MIR, so try not to report duplicate errors. - return; - } - - if tcx.is_struct_constructor(def_id) { - // We just assume that the automatically generated struct constructors are - // correct. See the comment in the `mir_borrowck` implementation for an - // explanation why we need this. - return; - } - - let param_env = tcx.param_env(def_id); - tcx.infer_ctxt().enter(|infcx| { - type_check_internal( - &infcx, - def_id, - param_env, - mir, - &vec![], - None, - None, - None, - |_| (), - ); - - // For verification purposes, we just ignore the resulting - // region constraint sets. Not our problem. =) - }); - } -} - trait NormalizeLocation: fmt::Debug + Copy { fn to_locations(self) -> Locations; } diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 28835b959d76f..2549aa4fbff93 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -17,7 +17,7 @@ use rustc::ty::{self, Ty}; /// N.B., the type `a` is permitted to have unresolved inference /// variables, but not the type `b`. pub(super) fn relate_types<'tcx>( - infcx: &InferCtxt<'_, '_, 'tcx>, + infcx: &InferCtxt<'_, 'tcx>, a: Ty<'tcx>, v: ty::Variance, b: Ty<'tcx>, @@ -34,8 +34,8 @@ pub(super) fn relate_types<'tcx>( Ok(()) } -struct NllTypeRelatingDelegate<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> { - infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, +struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { + infcx: &'me InferCtxt<'me, 'tcx>, borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>, /// Where (and why) is this relation taking place? @@ -45,9 +45,9 @@ struct NllTypeRelatingDelegate<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> { category: ConstraintCategory, } -impl NllTypeRelatingDelegate<'me, 'bccx, 'gcx, 'tcx> { +impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { fn new( - infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, + infcx: &'me InferCtxt<'me, 'tcx>, borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>, locations: Locations, category: ConstraintCategory, @@ -61,7 +61,7 @@ impl NllTypeRelatingDelegate<'me, 'bccx, 'gcx, 'tcx> { } } -impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> { +impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { fn create_next_universe(&mut self) -> ty::UniverseIndex { self.infcx.create_next_universe() } @@ -71,7 +71,7 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> { let origin = NLLRegionVariableOrigin::Existential; self.infcx.next_nll_region_var(origin) } else { - self.infcx.tcx.types.re_erased + self.infcx.tcx.lifetimes.re_erased } } @@ -82,7 +82,7 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> { if let Some(borrowck_context) = &mut self.borrowck_context { borrowck_context.constraints.placeholder_region(self.infcx, placeholder) } else { - self.infcx.tcx.types.re_erased + self.infcx.tcx.lifetimes.re_erased } } diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index 4d9a3775b3123..a85f4776a8bee 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -23,7 +23,6 @@ use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_errors::DiagnosticBuilder; use std::iter; -use syntax::ast; use super::ToRegionVid; @@ -106,8 +105,8 @@ impl<'tcx> DefiningTy<'tcx> { /// Returns a list of all the upvar types for this MIR. If this is /// not a closure or generator, there are no upvars, and hence it /// will be an empty list. The order of types in this list will - /// match up with the `upvar_decls` field of `Mir`. - pub fn upvar_tys(self, tcx: TyCtxt<'_, '_, 'tcx>) -> impl Iterator> + 'tcx { + /// match up with the upvar order in the HIR, typesystem, and MIR. + pub fn upvar_tys(self, tcx: TyCtxt<'tcx>) -> impl Iterator> + 'tcx { match self { DefiningTy::Closure(def_id, substs) => Either::Left(substs.upvar_tys(def_id, tcx)), DefiningTy::Generator(def_id, substs, _) => { @@ -195,17 +194,15 @@ impl<'tcx> UniversalRegions<'tcx> { /// signature. This will also compute the relationships that are /// known between those regions. pub fn new( - infcx: &InferCtxt<'_, '_, 'tcx>, + infcx: &InferCtxt<'_, 'tcx>, mir_def_id: DefId, param_env: ty::ParamEnv<'tcx>, ) -> Self { let tcx = infcx.tcx; - let mir_node_id = tcx.hir().as_local_node_id(mir_def_id).unwrap(); - let mir_hir_id = tcx.hir().node_to_hir_id(mir_node_id); + let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).unwrap(); UniversalRegionsBuilder { infcx, mir_def_id, - mir_node_id, mir_hir_id, param_env, }.build() @@ -221,13 +218,13 @@ impl<'tcx> UniversalRegions<'tcx> { /// `'1: '2`, then the caller would impose the constraint that /// `V[1]: V[2]`. pub fn closure_mapping( - tcx: TyCtxt<'_, '_, 'tcx>, + tcx: TyCtxt<'tcx>, closure_substs: SubstsRef<'tcx>, expected_num_vars: usize, closure_base_def_id: DefId, ) -> IndexVec> { let mut region_mapping = IndexVec::with_capacity(expected_num_vars); - region_mapping.push(tcx.types.re_static); + region_mapping.push(tcx.lifetimes.re_static); tcx.for_each_free_region(&closure_substs, |fr| { region_mapping.push(fr); }); @@ -308,7 +305,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// that this region imposes on others. The methods in this file /// handle the part about dumping the inference context internal /// state. - crate fn annotate(&self, tcx: TyCtxt<'_, '_, 'tcx>, err: &mut DiagnosticBuilder<'_>) { + crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_>) { match self.defining_ty { DefiningTy::Closure(def_id, substs) => { err.note(&format!( @@ -366,17 +363,16 @@ impl<'tcx> UniversalRegions<'tcx> { } } -struct UniversalRegionsBuilder<'cx, 'gcx: 'tcx, 'tcx: 'cx> { - infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, +struct UniversalRegionsBuilder<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, mir_def_id: DefId, mir_hir_id: HirId, - mir_node_id: ast::NodeId, param_env: ty::ParamEnv<'tcx>, } const FR: NLLRegionVariableOrigin = NLLRegionVariableOrigin::FreeRegion; -impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { +impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { fn build(self) -> UniversalRegions<'tcx> { debug!("build(mir_def_id={:?})", self.mir_def_id); @@ -475,7 +471,7 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { let tcx = self.infcx.tcx; let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id); - match tcx.hir().body_owner_kind(self.mir_node_id) { + match tcx.hir().body_owner_kind(self.mir_hir_id) { BodyOwnerKind::Closure | BodyOwnerKind::Fn => { let defining_ty = if self.mir_def_id == closure_base_def_id { @@ -546,7 +542,7 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { DefiningTy::FnDef(_, substs) | DefiningTy::Const(_, substs) => substs, }; - let global_mapping = iter::once((gcx.types.re_static, fr_static)); + let global_mapping = iter::once((gcx.lifetimes.re_static, fr_static)); let subst_mapping = identity_substs .regions() .zip(fr_substs.regions().map(|r| r.to_region_vid())); @@ -584,7 +580,7 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { tcx.mk_type_list( iter::once(closure_ty) - .chain(inputs.iter().cloned()) + .chain(inputs.iter().map(|k| k.expect_ty())) .chain(iter::once(output)), ) }, @@ -643,7 +639,7 @@ trait InferCtxtExt<'tcx> { ); } -impl<'cx, 'gcx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'gcx, 'tcx> { +impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { fn replace_free_regions_with_nll_infer_vars( &self, origin: NLLRegionVariableOrigin, @@ -748,7 +744,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { /// Replaces all free regions in `value` with region vids, as /// returned by `to_region_vid`. - pub fn fold_to_region_vids(&self, tcx: TyCtxt<'_, '_, 'tcx>, value: &T) -> T + pub fn fold_to_region_vids(&self, tcx: TyCtxt<'tcx>, value: &T) -> T where T: TypeFoldable<'tcx>, { @@ -761,7 +757,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { /// Iterates over the late-bound regions defined on fn_def_id and /// invokes `f` with the liberated form of each one. fn for_each_late_bound_region_defined_on<'tcx>( - tcx: TyCtxt<'_, '_, 'tcx>, + tcx: TyCtxt<'tcx>, fn_def_id: DefId, mut f: impl FnMut(ty::Region<'tcx>), ) { @@ -771,7 +767,7 @@ fn for_each_late_bound_region_defined_on<'tcx>( owner: fn_def_id.index, local_id: *late_bound, }; - let name = tcx.hir().name_by_hir_id(hir_id).as_interned_str(); + let name = tcx.hir().name(hir_id).as_interned_str(); let region_def_id = tcx.hir().local_def_id_from_hir_id(hir_id); let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion { scope: fn_def_id, diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index 9e0bb93c33a5d..aa2b177e54ed8 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -1,9 +1,8 @@ use crate::borrow_check::borrow_set::{BorrowSet, BorrowData, TwoPhaseActivation}; use crate::borrow_check::places_conflict; -use crate::borrow_check::Context; use crate::borrow_check::AccessDepth; use crate::dataflow::indexes::BorrowIndex; -use rustc::mir::{BasicBlock, Location, Mir, Place, PlaceBase}; +use rustc::mir::{BasicBlock, Location, Body, Place, PlaceBase}; use rustc::mir::{ProjectionElem, BorrowKind}; use rustc::ty::TyCtxt; use rustc_data_structures::graph::dominators::Dominators; @@ -11,13 +10,8 @@ use rustc_data_structures::graph::dominators::Dominators; /// Returns `true` if the borrow represented by `kind` is /// allowed to be split into separate Reservation and /// Activation phases. -pub(super) fn allow_two_phase_borrow<'a, 'tcx, 'gcx: 'tcx>( - tcx: &TyCtxt<'a, 'gcx, 'tcx>, - kind: BorrowKind -) -> bool { - tcx.two_phase_borrows() - && (kind.allows_two_phase_borrow() - || tcx.sess.opts.debugging_opts.two_phase_beyond_autoref) +pub(super) fn allow_two_phase_borrow(kind: BorrowKind) -> bool { + kind.allows_two_phase_borrow() } /// Control for the path borrow checking code @@ -28,18 +22,18 @@ pub(super) enum Control { } /// Encapsulates the idea of iterating over every borrow that involves a particular path -pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> ( +pub(super) fn each_borrow_involving_path<'tcx, F, I, S>( s: &mut S, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &Mir<'tcx>, - _context: Context, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + _location: Location, access_place: (AccessDepth, &Place<'tcx>), borrow_set: &BorrowSet<'tcx>, candidates: I, mut op: F, ) where F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control, - I: Iterator + I: Iterator, { let (access, place) = access_place; @@ -53,7 +47,7 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> ( if places_conflict::borrow_conflicts_with_place( tcx, - mir, + body, &borrowed.borrowed_place, borrowed.kind, place, @@ -137,23 +131,20 @@ pub(super) fn is_active<'tcx>( /// Determines if a given borrow is borrowing local data /// This is called for all Yield statements on movable generators pub(super) fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool { - match place { - Place::Base(PlaceBase::Promoted(_)) | - Place::Base(PlaceBase::Static(..)) => false, - Place::Base(PlaceBase::Local(..)) => true, - Place::Projection(box proj) => { - match proj.elem { - // Reborrow of already borrowed data is ignored - // Any errors will be caught on the initial borrow - ProjectionElem::Deref => false, + place.iterate(|place_base, place_projection| { + match place_base { + PlaceBase::Static(..) => return false, + PlaceBase::Local(..) => {}, + } - // For interior references and downcasts, find out if the base is local - ProjectionElem::Field(..) - | ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Downcast(..) => borrow_of_local_data(&proj.base), + for proj in place_projection { + // Reborrow of already borrowed data is ignored + // Any errors will be caught on the initial borrow + if proj.elem == ProjectionElem::Deref { + return false; } } - } + + true + }) } diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index c05ee3cf65b36..a8f28b64b4953 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -1,6 +1,6 @@ use rustc::hir; use rustc::mir::ProjectionElem; -use rustc::mir::{Local, Mir, Place, PlaceBase, Mutability}; +use rustc::mir::{Body, Place, PlaceBase, Mutability, Static, StaticKind}; use rustc::ty::{self, TyCtxt}; use crate::borrow_check::borrow_set::LocalsStateAtExit; @@ -12,58 +12,50 @@ crate trait PlaceExt<'tcx> { /// for borrows of raw pointer dereferents as well as shared references. fn ignore_borrow( &self, - tcx: TyCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, locals_state_at_exit: &LocalsStateAtExit, - ) -> bool; - - /// If this is a place like `x.f.g`, returns the local - /// `x`. Returns `None` if this is based in a static. - fn root_local(&self) -> Option; + ) -> bool; } impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { fn ignore_borrow( &self, - tcx: TyCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, locals_state_at_exit: &LocalsStateAtExit, ) -> bool { - match self { - Place::Base(PlaceBase::Promoted(_)) => false, - - // If a local variable is immutable, then we only need to track borrows to guard - // against two kinds of errors: - // * The variable being dropped while still borrowed (e.g., because the fn returns - // a reference to a local variable) - // * The variable being moved while still borrowed - // - // In particular, the variable cannot be mutated -- the "access checks" will fail -- - // so we don't have to worry about mutation while borrowed. - Place::Base(PlaceBase::Local(index)) => { - match locals_state_at_exit { - LocalsStateAtExit::AllAreInvalidated => false, - LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => { - let ignore = !has_storage_dead_or_moved.contains(*index) && - mir.local_decls[*index].mutability == Mutability::Not; - debug!("ignore_borrow: local {:?} => {:?}", index, ignore); - ignore + self.iterate(|place_base, place_projection| { + let ignore = match place_base { + // If a local variable is immutable, then we only need to track borrows to guard + // against two kinds of errors: + // * The variable being dropped while still borrowed (e.g., because the fn returns + // a reference to a local variable) + // * The variable being moved while still borrowed + // + // In particular, the variable cannot be mutated -- the "access checks" will fail -- + // so we don't have to worry about mutation while borrowed. + PlaceBase::Local(index) => { + match locals_state_at_exit { + LocalsStateAtExit::AllAreInvalidated => false, + LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => { + let ignore = !has_storage_dead_or_moved.contains(*index) && + body.local_decls[*index].mutability == Mutability::Not; + debug!("ignore_borrow: local {:?} => {:?}", index, ignore); + ignore + } } } - } - Place::Base(PlaceBase::Static(static_)) => { - tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable) - } - Place::Projection(proj) => match proj.elem { - ProjectionElem::Field(..) - | ProjectionElem::Downcast(..) - | ProjectionElem::Subslice { .. } - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Index(_) => proj.base.ignore_borrow( - tcx, mir, locals_state_at_exit), + PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => + false, + PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => { + tcx.is_mutable_static(*def_id) + } + }; - ProjectionElem::Deref => { - let ty = proj.base.ty(mir, tcx).to_ty(tcx); + for proj in place_projection { + if proj.elem == ProjectionElem::Deref { + let ty = proj.base.ty(body, tcx).ty; match ty.sty { // For both derefs of raw pointers and `&T` // references, the original path is `Copy` and @@ -75,23 +67,13 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { // original path into a new variable and // borrowed *that* one, leaving the original // path unborrowed. - ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => true, - _ => proj.base.ignore_borrow(tcx, mir, locals_state_at_exit), + ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => return true, + _ => {} } } - }, - } - } - - fn root_local(&self) -> Option { - let mut p = self; - loop { - match p { - Place::Projection(pi) => p = &pi.base, - Place::Base(PlaceBase::Promoted(_)) | - Place::Base(PlaceBase::Static(_)) => return None, - Place::Base(PlaceBase::Local(l)) => return Some(*l), } - } + + ignore + }) } } diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 1d18ada1fb69c..64ca00defc9c0 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -2,7 +2,10 @@ use crate::borrow_check::ArtificialField; use crate::borrow_check::Overlap; use crate::borrow_check::{Deep, Shallow, AccessDepth}; use rustc::hir; -use rustc::mir::{BorrowKind, Mir, Place, PlaceBase, Projection, ProjectionElem}; +use rustc::mir::{ + BorrowKind, Body, Place, PlaceBase, Projection, ProjectionElem, ProjectionsIter, + StaticKind +}; use rustc::ty::{self, TyCtxt}; use std::cmp::max; @@ -21,16 +24,16 @@ crate enum PlaceConflictBias { /// Helper function for checking if places conflict with a mutable borrow and deep access depth. /// This is used to check for places conflicting outside of the borrow checking code (such as in /// dataflow). -crate fn places_conflict<'gcx, 'tcx>( - tcx: TyCtxt<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, +crate fn places_conflict<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, borrow_place: &Place<'tcx>, access_place: &Place<'tcx>, bias: PlaceConflictBias, ) -> bool { borrow_conflicts_with_place( tcx, - mir, + body, borrow_place, BorrowKind::Mut { allow_two_phase_borrow: true }, access_place, @@ -43,9 +46,9 @@ crate fn places_conflict<'gcx, 'tcx>( /// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime /// array indices, for example) should be interpreted - this depends on what the caller wants in /// order to make the conservative choice and preserve soundness. -pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>( - tcx: TyCtxt<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, +pub(super) fn borrow_conflicts_with_place<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, borrow_place: &Place<'tcx>, borrow_kind: BorrowKind, access_place: &Place<'tcx>, @@ -65,14 +68,14 @@ pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>( } } - unroll_place(borrow_place, None, |borrow_components| { - unroll_place(access_place, None, |access_components| { + borrow_place.iterate(|borrow_base, borrow_projections| { + access_place.iterate(|access_base, access_projections| { place_components_conflict( tcx, - mir, - borrow_components, + body, + (borrow_base, borrow_projections), borrow_kind, - access_components, + (access_base, access_projections), access, bias, ) @@ -80,12 +83,12 @@ pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>( }) } -fn place_components_conflict<'gcx, 'tcx>( - tcx: TyCtxt<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, - mut borrow_components: PlaceComponentsIter<'_, 'tcx>, +fn place_components_conflict<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + borrow_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>), borrow_kind: BorrowKind, - mut access_components: PlaceComponentsIter<'_, 'tcx>, + access_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>), access: AccessDepth, bias: PlaceConflictBias, ) -> bool { @@ -130,12 +133,34 @@ fn place_components_conflict<'gcx, 'tcx>( // - If we didn't run out of access to match, our borrow and access are comparable // and either equal or disjoint. // - If we did run out of access, the borrow can access a part of it. + + let borrow_base = borrow_projections.0; + let access_base = access_projections.0; + + match place_base_conflict(tcx, borrow_base, access_base) { + Overlap::Arbitrary => { + bug!("Two base can't return Arbitrary"); + } + Overlap::EqualOrDisjoint => { + // This is the recursive case - proceed to the next element. + } + Overlap::Disjoint => { + // We have proven the borrow disjoint - further + // projections will remain disjoint. + debug!("borrow_conflicts_with_place: disjoint"); + return false; + } + } + + let mut borrow_projections = borrow_projections.1; + let mut access_projections = access_projections.1; + loop { // loop invariant: borrow_c is always either equal to access_c or disjoint from it. - if let Some(borrow_c) = borrow_components.next() { + if let Some(borrow_c) = borrow_projections.next() { debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c); - if let Some(access_c) = access_components.next() { + if let Some(access_c) = access_projections.next() { debug!("borrow_conflicts_with_place: access_c = {:?}", access_c); // Borrow and access path both have more components. @@ -150,7 +175,7 @@ fn place_components_conflict<'gcx, 'tcx>( // check whether the components being borrowed vs // accessed are disjoint (as in the second example, // but not the first). - match place_element_conflict(tcx, mir, borrow_c, access_c, bias) { + match place_projection_conflict(tcx, body, borrow_c, access_c, bias) { Overlap::Arbitrary => { // We have encountered different fields of potentially // the same union - the borrow now partially overlaps. @@ -187,11 +212,9 @@ fn place_components_conflict<'gcx, 'tcx>( // our place. This is a conflict if that is a part our // access cares about. - let (base, elem) = match borrow_c { - Place::Projection(box Projection { base, elem }) => (base, elem), - _ => bug!("place has no base?"), - }; - let base_ty = base.ty(mir, tcx).to_ty(tcx); + let base = &borrow_c.base; + let elem = &borrow_c.elem; + let base_ty = base.ty(body, tcx).ty; match (elem, &base_ty.sty, access) { (_, _, Shallow(Some(ArtificialField::ArrayLength))) @@ -261,7 +284,7 @@ fn place_components_conflict<'gcx, 'tcx>( // If the second example, where we did, then we still know // that the borrow can access a *part* of our place that // our access cares about, so we still have a conflict. - if borrow_kind == BorrowKind::Shallow && access_components.next().is_some() { + if borrow_kind == BorrowKind::Shallow && access_projections.next().is_some() { debug!("borrow_conflicts_with_place: shallow borrow"); return false; } else { @@ -272,95 +295,16 @@ fn place_components_conflict<'gcx, 'tcx>( } } -/// A linked list of places running up the stack; begins with the -/// innermost place and extends to projections (e.g., `a.b` would have -/// the place `a` with a "next" pointer to `a.b`). Created by -/// `unroll_place`. -/// -/// N.B., this particular impl strategy is not the most obvious. It was -/// chosen because it makes a measurable difference to NLL -/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot. -struct PlaceComponents<'p, 'tcx: 'p> { - component: &'p Place<'tcx>, - next: Option<&'p PlaceComponents<'p, 'tcx>>, -} - -impl<'p, 'tcx> PlaceComponents<'p, 'tcx> { - /// Converts a list of `Place` components into an iterator; this - /// iterator yields up a never-ending stream of `Option<&Place>`. - /// These begin with the "innermost" place and then with each - /// projection therefrom. So given a place like `a.b.c` it would - /// yield up: - /// - /// ```notrust - /// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ... - /// ``` - fn iter(&self) -> PlaceComponentsIter<'_, 'tcx> { - PlaceComponentsIter { value: Some(self) } - } -} - -/// Iterator over components; see `PlaceComponents::iter` for more -/// information. -/// -/// N.B., this is not a *true* Rust iterator -- the code above just -/// manually invokes `next`. This is because we (sometimes) want to -/// keep executing even after `None` has been returned. -struct PlaceComponentsIter<'p, 'tcx: 'p> { - value: Option<&'p PlaceComponents<'p, 'tcx>>, -} - -impl<'p, 'tcx> PlaceComponentsIter<'p, 'tcx> { - fn next(&mut self) -> Option<&'p Place<'tcx>> { - if let Some(&PlaceComponents { component, next }) = self.value { - self.value = next; - Some(component) - } else { - None - } - } -} - -/// Recursively "unroll" a place into a `PlaceComponents` list, -/// invoking `op` with a `PlaceComponentsIter`. -fn unroll_place<'tcx, R>( - place: &Place<'tcx>, - next: Option<&PlaceComponents<'_, 'tcx>>, - op: impl FnOnce(PlaceComponentsIter<'_, 'tcx>) -> R, -) -> R { - match place { - Place::Projection(interior) => unroll_place( - &interior.base, - Some(&PlaceComponents { - component: place, - next, - }), - op, - ), - - Place::Base(PlaceBase::Promoted(_)) | - Place::Base(PlaceBase::Local(_)) | Place::Base(PlaceBase::Static(_)) => { - let list = PlaceComponents { - component: place, - next, - }; - op(list.iter()) - } - } -} - // Given that the bases of `elem1` and `elem2` are always either equal // or disjoint (and have the same type!), return the overlap situation // between `elem1` and `elem2`. -fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &Mir<'tcx>, - elem1: &Place<'tcx>, - elem2: &Place<'tcx>, - bias: PlaceConflictBias, +fn place_base_conflict<'tcx>( + tcx: TyCtxt<'tcx>, + elem1: &PlaceBase<'tcx>, + elem2: &PlaceBase<'tcx>, ) -> Overlap { match (elem1, elem2) { - (Place::Base(PlaceBase::Local(l1)), Place::Base(PlaceBase::Local(l2))) => { + (PlaceBase::Local(l1), PlaceBase::Local(l2)) => { if l1 == l2 { // the same local - base case, equal debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL"); @@ -371,209 +315,218 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>( Overlap::Disjoint } } - (Place::Base(PlaceBase::Static(static1)), Place::Base(PlaceBase::Static(static2))) => { - if static1.def_id != static2.def_id { - debug!("place_element_conflict: DISJOINT-STATIC"); - Overlap::Disjoint - } else if tcx.is_static(static1.def_id) == Some(hir::Mutability::MutMutable) { - // We ignore mutable statics - they can only be unsafe code. - debug!("place_element_conflict: IGNORE-STATIC-MUT"); - Overlap::Disjoint - } else { - debug!("place_element_conflict: DISJOINT-OR-EQ-STATIC"); - Overlap::EqualOrDisjoint - } - } - (Place::Base(PlaceBase::Promoted(p1)), Place::Base(PlaceBase::Promoted(p2))) => { - if p1.0 == p2.0 { - if let ty::Array(_, size) = p1.1.sty { - if size.unwrap_usize(tcx) == 0 { - // Ignore conflicts with promoted [T; 0]. - debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED"); - return Overlap::Disjoint; - } - } - // the same promoted - base case, equal - debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED"); - Overlap::EqualOrDisjoint - } else { - // different promoteds - base case, disjoint - debug!("place_element_conflict: DISJOINT-PROMOTED"); - Overlap::Disjoint - } - } - (Place::Base(PlaceBase::Local(_)), Place::Base(PlaceBase::Promoted(_))) | - (Place::Base(PlaceBase::Promoted(_)), Place::Base(PlaceBase::Local(_))) | - (Place::Base(PlaceBase::Promoted(_)), Place::Base(PlaceBase::Static(_))) | - (Place::Base(PlaceBase::Static(_)), Place::Base(PlaceBase::Promoted(_))) | - (Place::Base(PlaceBase::Local(_)), Place::Base(PlaceBase::Static(_))) | - (Place::Base(PlaceBase::Static(_)), Place::Base(PlaceBase::Local(_))) => { - debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED"); - Overlap::Disjoint - } - (Place::Projection(pi1), Place::Projection(pi2)) => { - match (&pi1.elem, &pi2.elem) { - (ProjectionElem::Deref, ProjectionElem::Deref) => { - // derefs (e.g., `*x` vs. `*x`) - recur. - debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); - Overlap::EqualOrDisjoint - } - (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => { - if f1 == f2 { - // same field (e.g., `a.y` vs. `a.y`) - recur. - debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); - Overlap::EqualOrDisjoint + (PlaceBase::Static(s1), PlaceBase::Static(s2)) => { + match (&s1.kind, &s2.kind) { + (StaticKind::Static(def_id_1), StaticKind::Static(def_id_2)) => { + if def_id_1 != def_id_2 { + debug!("place_element_conflict: DISJOINT-STATIC"); + Overlap::Disjoint + } else if tcx.is_mutable_static(*def_id_1) { + // We ignore mutable statics - they can only be unsafe code. + debug!("place_element_conflict: IGNORE-STATIC-MUT"); + Overlap::Disjoint } else { - let ty = pi1.base.ty(mir, tcx).to_ty(tcx); - match ty.sty { - ty::Adt(def, _) if def.is_union() => { - // Different fields of a union, we are basically stuck. - debug!("place_element_conflict: STUCK-UNION"); - Overlap::Arbitrary - } - _ => { - // Different fields of a struct (`a.x` vs. `a.y`). Disjoint! - debug!("place_element_conflict: DISJOINT-FIELD"); - Overlap::Disjoint - } - } - } - } - (ProjectionElem::Downcast(_, v1), ProjectionElem::Downcast(_, v2)) => { - // different variants are treated as having disjoint fields, - // even if they occupy the same "space", because it's - // impossible for 2 variants of the same enum to exist - // (and therefore, to be borrowed) at the same time. - // - // Note that this is different from unions - we *do* allow - // this code to compile: - // - // ``` - // fn foo(x: &mut Result) { - // let mut v = None; - // if let Ok(ref mut a) = *x { - // v = Some(a); - // } - // // here, you would *think* that the - // // *entirety* of `x` would be borrowed, - // // but in fact only the `Ok` variant is, - // // so the `Err` variant is *entirely free*: - // if let Err(ref mut a) = *x { - // v = Some(a); - // } - // drop(v); - // } - // ``` - if v1 == v2 { - debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); + debug!("place_element_conflict: DISJOINT-OR-EQ-STATIC"); Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-FIELD"); - Overlap::Disjoint } - } - (ProjectionElem::Index(..), ProjectionElem::Index(..)) - | (ProjectionElem::Index(..), ProjectionElem::ConstantIndex { .. }) - | (ProjectionElem::Index(..), ProjectionElem::Subslice { .. }) - | (ProjectionElem::ConstantIndex { .. }, ProjectionElem::Index(..)) - | (ProjectionElem::Subslice { .. }, ProjectionElem::Index(..)) => { - // Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint - // (if the indexes differ) or equal (if they are the same). - match bias { - PlaceConflictBias::Overlap => { - // If we are biased towards overlapping, then this is the recursive - // case that gives "equal *or* disjoint" its meaning. - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX"); - Overlap::EqualOrDisjoint - } - PlaceConflictBias::NoOverlap => { - // If we are biased towards no overlapping, then this is disjoint. - debug!("place_element_conflict: DISJOINT-ARRAY-INDEX"); - Overlap::Disjoint + }, + (StaticKind::Promoted(promoted_1), StaticKind::Promoted(promoted_2)) => { + if promoted_1 == promoted_2 { + if let ty::Array(_, len) = s1.ty.sty { + if let Some(0) = len.assert_usize(tcx) { + // Ignore conflicts with promoted [T; 0]. + debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED"); + return Overlap::Disjoint; + } } - } - } - (ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: false }, - ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: false }) - | (ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: true }, - ProjectionElem::ConstantIndex { - offset: o2, min_length: _, from_end: true }) => { - if o1 == o2 { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX"); + // the same promoted - base case, equal + debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED"); Overlap::EqualOrDisjoint } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX"); + // different promoteds - base case, disjoint + debug!("place_element_conflict: DISJOINT-PROMOTED"); Overlap::Disjoint } + }, + (_, _) => { + debug!("place_element_conflict: DISJOINT-STATIC-PROMOTED"); + Overlap::Disjoint } - (ProjectionElem::ConstantIndex { - offset: offset_from_begin, min_length: min_length1, from_end: false }, - ProjectionElem::ConstantIndex { - offset: offset_from_end, min_length: min_length2, from_end: true }) - | (ProjectionElem::ConstantIndex { - offset: offset_from_end, min_length: min_length1, from_end: true }, - ProjectionElem::ConstantIndex { - offset: offset_from_begin, min_length: min_length2, from_end: false }) => { - // both patterns matched so it must be at least the greater of the two - let min_length = max(min_length1, min_length2); - // `offset_from_end` can be in range `[1..min_length]`, 1 indicates the last - // element (like -1 in Python) and `min_length` the first. - // Therefore, `min_length - offset_from_end` gives the minimal possible - // offset from the beginning - if *offset_from_begin >= min_length - offset_from_end { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE"); - Overlap::Disjoint + } + } + (PlaceBase::Local(_), PlaceBase::Static(_)) | + (PlaceBase::Static(_), PlaceBase::Local(_)) => { + debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED"); + Overlap::Disjoint + } + } +} + +// Given that the bases of `elem1` and `elem2` are always either equal +// or disjoint (and have the same type!), return the overlap situation +// between `elem1` and `elem2`. +fn place_projection_conflict<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + pi1: &Projection<'tcx>, + pi2: &Projection<'tcx>, + bias: PlaceConflictBias, +) -> Overlap { + match (&pi1.elem, &pi2.elem) { + (ProjectionElem::Deref, ProjectionElem::Deref) => { + // derefs (e.g., `*x` vs. `*x`) - recur. + debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); + Overlap::EqualOrDisjoint + } + (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => { + if f1 == f2 { + // same field (e.g., `a.y` vs. `a.y`) - recur. + debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); + Overlap::EqualOrDisjoint + } else { + let ty = pi1.base.ty(body, tcx).ty; + match ty.sty { + ty::Adt(def, _) if def.is_union() => { + // Different fields of a union, we are basically stuck. + debug!("place_element_conflict: STUCK-UNION"); + Overlap::Arbitrary } - } - (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, - ProjectionElem::Subslice {from, .. }) - | (ProjectionElem::Subslice {from, .. }, - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => { - if offset >= from { - debug!( - "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE"); + _ => { + // Different fields of a struct (`a.x` vs. `a.y`). Disjoint! + debug!("place_element_conflict: DISJOINT-FIELD"); Overlap::Disjoint } } - (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }, - ProjectionElem::Subslice {from: _, to }) - | (ProjectionElem::Subslice {from: _, to }, - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => { - if offset > to { - debug!("place_element_conflict: \ - DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE"); - Overlap::Disjoint - } + } + } + (ProjectionElem::Downcast(_, v1), ProjectionElem::Downcast(_, v2)) => { + // different variants are treated as having disjoint fields, + // even if they occupy the same "space", because it's + // impossible for 2 variants of the same enum to exist + // (and therefore, to be borrowed) at the same time. + // + // Note that this is different from unions - we *do* allow + // this code to compile: + // + // ``` + // fn foo(x: &mut Result) { + // let mut v = None; + // if let Ok(ref mut a) = *x { + // v = Some(a); + // } + // // here, you would *think* that the + // // *entirety* of `x` would be borrowed, + // // but in fact only the `Ok` variant is, + // // so the `Err` variant is *entirely free*: + // if let Err(ref mut a) = *x { + // v = Some(a); + // } + // drop(v); + // } + // ``` + if v1 == v2 { + debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-FIELD"); + Overlap::Disjoint + } + } + (ProjectionElem::Index(..), ProjectionElem::Index(..)) + | (ProjectionElem::Index(..), ProjectionElem::ConstantIndex { .. }) + | (ProjectionElem::Index(..), ProjectionElem::Subslice { .. }) + | (ProjectionElem::ConstantIndex { .. }, ProjectionElem::Index(..)) + | (ProjectionElem::Subslice { .. }, ProjectionElem::Index(..)) => { + // Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint + // (if the indexes differ) or equal (if they are the same). + match bias { + PlaceConflictBias::Overlap => { + // If we are biased towards overlapping, then this is the recursive + // case that gives "equal *or* disjoint" its meaning. + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX"); + Overlap::EqualOrDisjoint } - (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES"); - Overlap::EqualOrDisjoint + PlaceConflictBias::NoOverlap => { + // If we are biased towards no overlapping, then this is disjoint. + debug!("place_element_conflict: DISJOINT-ARRAY-INDEX"); + Overlap::Disjoint } - (ProjectionElem::Deref, _) - | (ProjectionElem::Field(..), _) - | (ProjectionElem::Index(..), _) - | (ProjectionElem::ConstantIndex { .. }, _) - | (ProjectionElem::Subslice { .. }, _) - | (ProjectionElem::Downcast(..), _) => bug!( - "mismatched projections in place_element_conflict: {:?} and {:?}", - elem1, - elem2 - ), } } - (Place::Projection(_), _) | (_, Place::Projection(_)) => bug!( - "unexpected elements in place_element_conflict: {:?} and {:?}", - elem1, - elem2 + (ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: false }, + ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: false }) + | (ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: true }, + ProjectionElem::ConstantIndex { + offset: o2, min_length: _, from_end: true }) => { + if o1 == o2 { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX"); + Overlap::Disjoint + } + } + (ProjectionElem::ConstantIndex { + offset: offset_from_begin, min_length: min_length1, from_end: false }, + ProjectionElem::ConstantIndex { + offset: offset_from_end, min_length: min_length2, from_end: true }) + | (ProjectionElem::ConstantIndex { + offset: offset_from_end, min_length: min_length1, from_end: true }, + ProjectionElem::ConstantIndex { + offset: offset_from_begin, min_length: min_length2, from_end: false }) => { + // both patterns matched so it must be at least the greater of the two + let min_length = max(min_length1, min_length2); + // `offset_from_end` can be in range `[1..min_length]`, 1 indicates the last + // element (like -1 in Python) and `min_length` the first. + // Therefore, `min_length - offset_from_end` gives the minimal possible + // offset from the beginning + if *offset_from_begin >= min_length - offset_from_end { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE"); + Overlap::Disjoint + } + } + (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, + ProjectionElem::Subslice {from, .. }) + | (ProjectionElem::Subslice {from, .. }, + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => { + if offset >= from { + debug!( + "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE"); + Overlap::Disjoint + } + } + (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }, + ProjectionElem::Subslice {from: _, to }) + | (ProjectionElem::Subslice {from: _, to }, + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => { + if offset > to { + debug!("place_element_conflict: \ + DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE"); + Overlap::Disjoint + } + } + (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES"); + Overlap::EqualOrDisjoint + } + (ProjectionElem::Deref, _) + | (ProjectionElem::Field(..), _) + | (ProjectionElem::Index(..), _) + | (ProjectionElem::ConstantIndex { .. }, _) + | (ProjectionElem::Subslice { .. }, _) + | (ProjectionElem::Downcast(..), _) => bug!( + "mismatched projections in place_element_conflict: {:?} and {:?}", + pi1, + pi2 ), } } diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index 384fd5c9987b8..0cc1dfd4def0f 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -11,7 +11,7 @@ use super::MirBorrowckCtxt; use rustc::hir; use rustc::ty::{self, TyCtxt}; -use rustc::mir::{Mir, Place, PlaceBase, ProjectionElem}; +use rustc::mir::{Body, Place, PlaceBase, ProjectionElem}; pub trait IsPrefixOf<'tcx> { fn is_prefix_of(&self, other: &Place<'tcx>) -> bool; @@ -26,7 +26,6 @@ impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> { } match *cursor { - Place::Base(PlaceBase::Promoted(_)) | Place::Base(PlaceBase::Local(_)) | Place::Base(PlaceBase::Static(_)) => return false, Place::Projection(ref proj) => { @@ -37,10 +36,9 @@ impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> { } } - -pub(super) struct Prefixes<'cx, 'gcx: 'tcx, 'tcx: 'cx> { - mir: &'cx Mir<'tcx>, - tcx: TyCtxt<'cx, 'gcx, 'tcx>, +pub(super) struct Prefixes<'cx, 'tcx> { + body: &'cx Body<'tcx>, + tcx: TyCtxt<'tcx>, kind: PrefixSet, next: Option<&'cx Place<'tcx>>, } @@ -57,25 +55,21 @@ pub(super) enum PrefixSet { Supporting, } -impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Returns an iterator over the prefixes of `place` /// (inclusive) from longest to smallest, potentially /// terminating the iteration early based on `kind`. - pub(super) fn prefixes( - &self, - place: &'cx Place<'tcx>, - kind: PrefixSet, - ) -> Prefixes<'cx, 'gcx, 'tcx> { + pub(super) fn prefixes(&self, place: &'cx Place<'tcx>, kind: PrefixSet) -> Prefixes<'cx, 'tcx> { Prefixes { next: Some(place), kind, - mir: self.mir, + body: self.body, tcx: self.infcx.tcx, } } } -impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> { +impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { type Item = &'cx Place<'tcx>; fn next(&mut self) -> Option { let mut cursor = self.next?; @@ -87,7 +81,6 @@ impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> { 'cursor: loop { let proj = match *cursor { - Place::Base(PlaceBase::Promoted(_)) | Place::Base(PlaceBase::Local(_)) | // search yielded this leaf Place::Base(PlaceBase::Static(_)) => { self.next = None; @@ -141,7 +134,7 @@ impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> { // derefs, except we stop at the deref of a shared // reference. - let ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let ty = proj.base.ty(self.body, self.tcx).ty; match ty.sty { ty::RawPtr(_) | ty::Ref( diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index b102bced0e335..9c5569011df4f 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -1,13 +1,13 @@ use rustc::mir::visit::{PlaceContext, Visitor}; use rustc::mir::{ - BasicBlock, Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind + Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind }; use rustc_data_structures::fx::FxHashSet; use crate::borrow_check::MirBorrowckCtxt; -impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes /// of the `unused_mut` lint. /// @@ -34,7 +34,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { never_initialized_mut_locals: &mut never_initialized_mut_locals, mbcx: self, }; - visitor.visit_mir(visitor.mbcx.mir); + visitor.visit_body(visitor.mbcx.body); } // Take the union of the existed `used_mut` set with those variables we've found were @@ -46,30 +46,38 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// MIR visitor for collecting used mutable variables. /// The 'visit lifetime represents the duration of the MIR walk. -struct GatherUsedMutsVisitor<'visit, 'cx: 'visit, 'gcx: 'tcx, 'tcx: 'cx> { +struct GatherUsedMutsVisitor<'visit, 'cx, 'tcx> { temporary_used_locals: FxHashSet, never_initialized_mut_locals: &'visit mut FxHashSet, - mbcx: &'visit mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>, + mbcx: &'visit mut MirBorrowckCtxt<'cx, 'tcx>, } -impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'gcx, 'tcx> { +impl GatherUsedMutsVisitor<'_, '_, '_> { + fn remove_never_initialized_mut_locals(&mut self, into: &Place<'_>) { + // Remove any locals that we found were initialized from the + // `never_initialized_mut_locals` set. At the end, the only remaining locals will + // be those that were never initialized - we will consider those as being used as + // they will either have been removed by unreachable code optimizations; or linted + // as unused variables. + if let Some(local) = into.base_local() { + let _ = self.never_initialized_mut_locals.remove(&local); + } + } +} + +impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tcx> { fn visit_terminator_kind( &mut self, - _block: BasicBlock, kind: &TerminatorKind<'tcx>, _location: Location, ) { debug!("visit_terminator_kind: kind={:?}", kind); match &kind { TerminatorKind::Call { destination: Some((into, _)), .. } => { - if let Some(local) = into.base_local() { - debug!( - "visit_terminator_kind: kind={:?} local={:?} \ - never_initialized_mut_locals={:?}", - kind, local, self.never_initialized_mut_locals - ); - let _ = self.never_initialized_mut_locals.remove(&local); - } + self.remove_never_initialized_mut_locals(&into); + }, + TerminatorKind::DropAndReplace { location, .. } => { + self.remove_never_initialized_mut_locals(&location); }, _ => {}, } @@ -77,25 +85,19 @@ impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'c fn visit_statement( &mut self, - _block: BasicBlock, statement: &Statement<'tcx>, _location: Location, ) { match &statement.kind { StatementKind::Assign(into, _) => { - // Remove any locals that we found were initialized from the - // `never_initialized_mut_locals` set. At the end, the only remaining locals will - // be those that were never initialized - we will consider those as being used as - // they will either have been removed by unreachable code optimizations; or linted - // as unused variables. if let Some(local) = into.base_local() { debug!( "visit_statement: statement={:?} local={:?} \ never_initialized_mut_locals={:?}", statement, local, self.never_initialized_mut_locals ); - let _ = self.never_initialized_mut_locals.remove(&local); } + self.remove_never_initialized_mut_locals(into); }, _ => {}, } @@ -104,7 +106,7 @@ impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'c fn visit_local( &mut self, local: &Local, - place_context: PlaceContext<'tcx>, + place_context: PlaceContext, location: Location, ) { if place_context.is_place_assignment() && self.temporary_used_locals.contains(local) { diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index cba5039122a76..7ea08b15b443d 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -6,7 +6,7 @@ use rustc::mir::*; use rustc::hir; use syntax_pos::Span; -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn ast_block(&mut self, destination: &Place<'tcx>, block: BasicBlock, @@ -23,8 +23,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { safety_mode } = self.hir.mirror(ast_block); - self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), block, move |this| { - this.in_scope((region_scope, source_info), LintLevel::Inherited, block, move |this| { + self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), move |this| { + this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| { if targeted_by_break { // This is a `break`-able block let exit_block = this.cfg.start_new_block(); @@ -78,16 +78,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source_info = this.source_info(span); for stmt in stmts { - let Stmt { kind, opt_destruction_scope, span: stmt_span } = this.hir.mirror(stmt); + let Stmt { kind, opt_destruction_scope } = this.hir.mirror(stmt); match kind { StmtKind::Expr { scope, expr } => { this.block_context.push(BlockFrame::Statement { ignores_expr_result: true }); unpack!(block = this.in_opt_scope( - opt_destruction_scope.map(|de|(de, source_info)), block, |this| { + opt_destruction_scope.map(|de|(de, source_info)), |this| { let si = (scope, source_info); - this.in_scope(si, LintLevel::Inherited, block, |this| { + this.in_scope(si, LintLevel::Inherited, |this| { let expr = this.hir.mirror(expr); - this.stmt_expr(block, expr, Some(stmt_span)) + this.stmt_expr(block, expr, Some(scope)) }) })); } @@ -113,31 +113,39 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let remainder_span = remainder_scope.span(this.hir.tcx(), &this.hir.region_scope_tree); - let scope; + let visibility_scope = + Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None)); // Evaluate the initializer, if present. if let Some(init) = initializer { let initializer_span = init.span(); - scope = this.declare_bindings( - None, - remainder_span, - lint_level, - &pattern, - ArmHasGuard(false), - Some((None, initializer_span)), - ); unpack!(block = this.in_opt_scope( - opt_destruction_scope.map(|de|(de, source_info)), block, |this| { + opt_destruction_scope.map(|de|(de, source_info)), |this| { let scope = (init_scope, source_info); - this.in_scope(scope, lint_level, block, |this| { + this.in_scope(scope, lint_level, |this| { + this.declare_bindings( + visibility_scope, + remainder_span, + &pattern, + ArmHasGuard(false), + Some((None, initializer_span)), + ); this.expr_into_pattern(block, pattern, init) }) })); } else { - scope = this.declare_bindings( - None, remainder_span, lint_level, &pattern, - ArmHasGuard(false), None); + let scope = (init_scope, source_info); + unpack!(this.in_scope(scope, lint_level, |this| { + this.declare_bindings( + visibility_scope, + remainder_span, + &pattern, + ArmHasGuard(false), + None, + ); + block.unit() + })); debug!("ast_block_stmts: pattern={:?}", pattern); this.visit_bindings( @@ -149,8 +157,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }) } - // Enter the source scope, after evaluating the initializer. - if let Some(source_scope) = scope { + // Enter the visibility scope, after evaluating the initializer. + if let Some(source_scope) = visibility_scope { this.source_scope = source_scope; } } @@ -163,7 +171,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Then, the block may have an optional trailing expression which is a “return” value // of the block, which is stored into `destination`. let tcx = this.hir.tcx(); - let destination_ty = destination.ty(&this.local_decls, tcx).to_ty(tcx); + let destination_ty = destination.ty(&this.local_decls, tcx).ty; if let Some(expr) = expr { let tail_result_is_ignored = destination_ty.is_unit() || this.block_context.currently_ignores_tail_results(); diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs index 614668170d5be..5197981a85cb8 100644 --- a/src/librustc_mir/build/expr/as_constant.rs +++ b/src/librustc_mir/build/expr/as_constant.rs @@ -5,7 +5,7 @@ use crate::hair::*; use rustc::mir::*; use rustc::ty::CanonicalUserTypeAnnotation; -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, yielding a compile-time constant. Assumes that /// `expr` is a valid compile-time constant! pub fn as_constant(&mut self, expr: M) -> Constant<'tcx> diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs index e354a2ee8160b..207399fbdcf0e 100644 --- a/src/librustc_mir/build/expr/as_operand.rs +++ b/src/librustc_mir/build/expr/as_operand.rs @@ -6,7 +6,7 @@ use crate::hair::*; use rustc::middle::region; use rustc::mir::*; -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { /// Returns an operand suitable for use until the end of the current /// scope expression. /// @@ -57,7 +57,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); - return this.in_scope(region_scope, lint_level, block, |this| { + return this.in_scope(region_scope, lint_level, |this| { this.as_operand(block, scope, value) }); } @@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } Category::Place | Category::Rvalue(..) => { let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut)); - block.and(Operand::Move(Place::Base(PlaceBase::Local(operand)))) + block.and(Operand::Move(Place::from(operand))) } } } diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 3bea88024b3f9..0640c01d255c2 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -4,13 +4,13 @@ use crate::build::expr::category::Category; use crate::build::ForGuard::{OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; -use rustc::mir::interpret::EvalErrorKind::BoundsCheck; +use rustc::mir::interpret::InterpError::BoundsCheck; use rustc::mir::*; use rustc::ty::{CanonicalUserTypeAnnotation, Variance}; use rustc_data_structures::indexed_vec::Idx; -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, yielding a place that we can move from etc. pub fn as_place(&mut self, block: BasicBlock, expr: M) -> BlockAnd> where @@ -52,7 +52,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { region_scope, lint_level, value, - } => this.in_scope((region_scope, source_info), lint_level, block, |this| { + } => this.in_scope((region_scope, source_info), lint_level, |this| { if mutability == Mutability::Not { this.as_read_only_place(block, value) } else { @@ -98,36 +98,32 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { <, Rvalue::BinaryOp( BinOp::Lt, - Operand::Copy(Place::Base(PlaceBase::Local(idx))), + Operand::Copy(Place::from(idx)), Operand::Copy(len.clone()), ), ); let msg = BoundsCheck { len: Operand::Move(len), - index: Operand::Copy(Place::Base(PlaceBase::Local(idx))), + index: Operand::Copy(Place::from(idx)), }; let success = this.assert(block, Operand::Move(lt), true, msg, expr_span); success.and(slice.index(idx)) } - ExprKind::SelfRef => block.and(Place::Base(PlaceBase::Local(Local::new(1)))), + ExprKind::SelfRef => block.and(Place::from(Local::new(1))), ExprKind::VarRef { id } => { - let place = if this.is_bound_var_in_guard(id) && this - .hir - .tcx() - .all_pat_vars_are_implicit_refs_within_guards() - { + let place = if this.is_bound_var_in_guard(id) { let index = this.var_local_id(id, RefWithinGuard); - Place::Base(PlaceBase::Local(index)).deref() + Place::from(index).deref() } else { let index = this.var_local_id(id, OutsideGuard); - Place::Base(PlaceBase::Local(index)) + Place::from(index) }; block.and(place) } ExprKind::StaticRef { id } => block.and(Place::Base(PlaceBase::Static(Box::new(Static { - def_id: id, ty: expr.ty, + kind: StaticKind::Static(id), })))), ExprKind::PlaceTypeAscription { source, user_ty } => { @@ -172,14 +168,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Statement { source_info, kind: StatementKind::AscribeUserType( - Place::Base(PlaceBase::Local(temp.clone())), + Place::from(temp.clone()), Variance::Invariant, box UserTypeProjection { base: annotation_index, projs: vec![], }, ), }, ); } - block.and(Place::Base(PlaceBase::Local(temp))) + block.and(Place::from(temp)) } ExprKind::Array { .. } @@ -193,13 +189,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::Cast { .. } | ExprKind::Use { .. } | ExprKind::NeverToAny { .. } - | ExprKind::ReifyFnPointer { .. } - | ExprKind::ClosureFnPointer { .. } - | ExprKind::UnsafeFnPointer { .. } - | ExprKind::Unsize { .. } + | ExprKind::Pointer { .. } | ExprKind::Repeat { .. } | ExprKind::Borrow { .. } - | ExprKind::If { .. } | ExprKind::Match { .. } | ExprKind::Loop { .. } | ExprKind::Block { .. } @@ -219,7 +211,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }); let temp = unpack!(block = this.as_temp(block, expr.temp_lifetime, expr, mutability)); - block.and(Place::Base(PlaceBase::Local(temp))) + block.and(Place::from(temp)) } } } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index b00d1c612edf3..17e7b1acc68f0 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -7,12 +7,12 @@ use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; use rustc::middle::region; -use rustc::mir::interpret::EvalErrorKind; +use rustc::mir::interpret::InterpError; use rustc::mir::*; use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, UpvarSubsts}; use syntax_pos::Span; -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { /// See comment on `as_local_operand` pub fn as_local_rvalue(&mut self, block: BasicBlock, expr: M) -> BlockAnd> where @@ -58,7 +58,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value, } => { let region_scope = (region_scope, source_info); - this.in_scope(region_scope, lint_level, block, |this| { + this.in_scope(region_scope, lint_level, |this| { this.as_rvalue(block, scope, value) }) } @@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, arg)), _ => unpack!(block = this.as_place(block, arg)), }; - block.and(Rvalue::Ref(this.hir.tcx().types.re_erased, borrow_kind, arg_place)) + block.and(Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place)) } ExprKind::Binary { op, lhs, rhs } => { let lhs = unpack!(block = this.as_operand(block, scope, lhs)); @@ -101,7 +101,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block, Operand::Move(is_min), false, - EvalErrorKind::OverflowNeg, + InterpError::OverflowNeg, expr_span, ); } @@ -127,7 +127,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.schedule_drop_storage_and_value( expr_span, scope, - &Place::Base(PlaceBase::Local(result)), + result, value.ty, ); } @@ -135,42 +135,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // malloc some memory of suitable type (thus far, uninitialized): let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty); this.cfg - .push_assign(block, source_info, &Place::Base(PlaceBase::Local(result)), box_); + .push_assign(block, source_info, &Place::from(result), box_); // initialize the box contents: unpack!( block = this.into( - &Place::Base(PlaceBase::Local(result)).deref(), + &Place::from(result).deref(), block, value ) ); - block.and(Rvalue::Use(Operand::Move(Place::Base(PlaceBase::Local(result))))) + block.and(Rvalue::Use(Operand::Move(Place::from(result)))) } ExprKind::Cast { source } => { - let source = this.hir.mirror(source); - let source = unpack!(block = this.as_operand(block, scope, source)); block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty)) } - ExprKind::Use { source } => { - let source = unpack!(block = this.as_operand(block, scope, source)); - block.and(Rvalue::Use(source)) - } - ExprKind::ReifyFnPointer { source } => { - let source = unpack!(block = this.as_operand(block, scope, source)); - block.and(Rvalue::Cast(CastKind::ReifyFnPointer, source, expr.ty)) - } - ExprKind::UnsafeFnPointer { source } => { + ExprKind::Pointer { cast, source } => { let source = unpack!(block = this.as_operand(block, scope, source)); - block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty)) - } - ExprKind::ClosureFnPointer { source } => { - let source = unpack!(block = this.as_operand(block, scope, source)); - block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty)) - } - ExprKind::Unsize { source } => { - let source = unpack!(block = this.as_operand(block, scope, source)); - block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty)) + block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty)) } ExprKind::Array { fields } => { // (*) We would (maybe) be closer to codegen if we @@ -225,7 +207,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { movability, } => { // see (*) above - let mut operands: Vec<_> = upvars + let operands: Vec<_> = upvars .into_iter() .map(|upvar| { let upvar = this.hir.mirror(upvar); @@ -266,21 +248,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }).collect(); let result = match substs { UpvarSubsts::Generator(substs) => { + // We implicitly set the discriminant to 0. See + // librustc_mir/transform/deaggregator.rs for details. let movability = movability.unwrap(); - // Add the state operand since it follows the upvars in the generator - // struct. See librustc_mir/transform/generator.rs for more details. - operands.push(Operand::Constant(box Constant { - span: expr_span, - ty: this.hir.tcx().types.u32, - user_ty: None, - literal: this.hir.tcx().mk_lazy_const(ty::LazyConst::Evaluated( - ty::Const::from_bits( - this.hir.tcx(), - 0, - ty::ParamEnv::empty().and(this.hir.tcx().types.u32), - ), - )), - })); box AggregateKind::Generator(closure_id, substs, movability) } UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs), @@ -375,8 +345,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Literal { .. } | ExprKind::Block { .. } | ExprKind::Match { .. } - | ExprKind::If { .. } | ExprKind::NeverToAny { .. } + | ExprKind::Use { .. } | ExprKind::Loop { .. } | ExprKind::LogicalOp { .. } | ExprKind::Call { .. } @@ -431,7 +401,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let val = result_value.clone().field(val_fld, ty); let of = result_value.field(of_fld, bool_ty); - let err = EvalErrorKind::Overflow(op); + let err = InterpError::Overflow(op); block = self.assert(block, Operand::Move(of), false, err, span); @@ -442,9 +412,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // and 2. there are two possible failure cases, divide-by-zero and overflow. let (zero_err, overflow_err) = if op == BinOp::Div { - (EvalErrorKind::DivisionByZero, EvalErrorKind::Overflow(op)) + (InterpError::DivisionByZero, InterpError::Overflow(op)) } else { - (EvalErrorKind::RemainderByZero, EvalErrorKind::Overflow(op)) + (InterpError::RemainderByZero, InterpError::Overflow(op)) }; // Check for / 0 @@ -533,13 +503,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { elem: ProjectionElem::Deref, }) => { debug_assert!( - if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) = - this.local_decls[local].is_user_variable - { - true - } else { - false - }, + this.local_decls[local].is_ref_for_guard(), "Unexpected capture place", ); this.local_decls[local].mutability @@ -558,22 +522,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }) => { // Not projected from the implicit `self` in a closure. debug_assert!( - match *base { - Place::Base(PlaceBase::Local(local)) => local == Local::new(1), - Place::Projection(box Projection { - ref base, - elem: ProjectionElem::Deref, - }) => *base == Place::Base(PlaceBase::Local(Local::new(1))), - _ => false, + match base.local_or_deref_local() { + Some(local) => local == Local::new(1), + None => false, }, "Unexpected capture place" ); // Not in a closure debug_assert!( - this.upvar_decls.len() > upvar_index.index(), + this.upvar_mutbls.len() > upvar_index.index(), "Unexpected capture place" ); - this.upvar_decls[upvar_index.index()].mutability + this.upvar_mutbls[upvar_index.index()] } _ => bug!("Unexpected capture place"), }; @@ -588,8 +548,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.cfg.push_assign( block, source_info, - &Place::Base(PlaceBase::Local(temp)), - Rvalue::Ref(this.hir.tcx().types.re_erased, borrow_kind, arg_place), + &Place::from(temp), + Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place), ); // In constants, temp_lifetime is None. We should not need to drop @@ -599,17 +559,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.schedule_drop_storage_and_value( upvar_span, temp_lifetime, - &Place::Base(PlaceBase::Local(temp)), + temp, upvar_ty, ); } - block.and(Operand::Move(Place::Base(PlaceBase::Local(temp)))) + block.and(Operand::Move(Place::from(temp))) } // Helper to get a `-1` value of the appropriate type fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { - let param_ty = ty::ParamEnv::empty().and(self.hir.tcx().lift_to_global(&ty).unwrap()); + let param_ty = ty::ParamEnv::empty().and(ty); let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits(); let n = (!0u128) >> (128 - bits); let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty); @@ -620,7 +580,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Helper to get the minimum value of the appropriate type fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { assert!(ty.is_signed()); - let param_ty = ty::ParamEnv::empty().and(self.hir.tcx().lift_to_global(&ty).unwrap()); + let param_ty = ty::ParamEnv::empty().and(ty); let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits(); let n = 1 << (bits - 1); let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty); diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index cba771f27065d..1fe6be8bbc82e 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -1,11 +1,12 @@ //! See docs in build/expr/mod.rs use crate::build::{BlockAnd, BlockAndExtension, Builder}; +use crate::build::scope::DropKind; use crate::hair::*; use rustc::middle::region; use rustc::mir::*; -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr` into a fresh temporary. This is used when building /// up rvalues so as to freeze the value that will be consumed. pub fn as_temp( @@ -43,7 +44,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value, } = expr.kind { - return this.in_scope((region_scope, source_info), lint_level, block, |this| { + return this.in_scope((region_scope, source_info), lint_level, |this| { this.as_temp(block, temp_lifetime, value, mutability) }); } @@ -63,6 +64,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } this.local_decls.push(local_decl) }; + let temp_place = &Place::from(temp); + if !expr_ty.is_never() { this.cfg.push( block, @@ -71,25 +74,36 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { kind: StatementKind::StorageLive(temp), }, ); + + // In constants, `temp_lifetime` is `None` for temporaries that live for the + // `'static` lifetime. Thus we do not drop these temporaries and simply leak them. + // This is equivalent to what `let x = &foo();` does in functions. The temporary + // is lifted to their surrounding scope. In a function that means the temporary lives + // until just before the function returns. In constants that means it outlives the + // constant's initialization value computation. Anything outliving a constant + // must have the `'static` lifetime and live forever. + // Anything with a shorter lifetime (e.g the `&foo()` in `bar(&foo())` or anything + // within a block will keep the regular drops just like runtime code. + if let Some(temp_lifetime) = temp_lifetime { + this.schedule_drop( + expr_span, + temp_lifetime, + temp, + expr_ty, + DropKind::Storage, + ); + } } - unpack!(block = this.into(&Place::Base(PlaceBase::Local(temp)), block, expr)); + unpack!(block = this.into(temp_place, block, expr)); - // In constants, temp_lifetime is None for temporaries that live for the - // 'static lifetime. Thus we do not drop these temporaries and simply leak them. - // This is equivalent to what `let x = &foo();` does in functions. The temporary - // is lifted to their surrounding scope. In a function that means the temporary lives - // until just before the function returns. In constants that means it outlives the - // constant's initialization value computation. Anything outliving a constant - // must have the `'static` lifetime and live forever. - // Anything with a shorter lifetime (e.g the `&foo()` in `bar(&foo())` or anything - // within a block will keep the regular drops just like runtime code. if let Some(temp_lifetime) = temp_lifetime { - this.schedule_drop_storage_and_value( + this.schedule_drop( expr_span, temp_lifetime, - &Place::Base(PlaceBase::Local(temp)), + temp, expr_ty, + DropKind::Value, ); } diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs index ca7d435e62229..222ce6d1c968e 100644 --- a/src/librustc_mir/build/expr/category.rs +++ b/src/librustc_mir/build/expr/category.rs @@ -45,9 +45,9 @@ impl Category { | ExprKind::ValueTypeAscription { .. } => Some(Category::Place), ExprKind::LogicalOp { .. } - | ExprKind::If { .. } | ExprKind::Match { .. } | ExprKind::NeverToAny { .. } + | ExprKind::Use { .. } | ExprKind::Call { .. } => Some(Category::Rvalue(RvalueFunc::Into)), ExprKind::Array { .. } @@ -58,11 +58,7 @@ impl Category { | ExprKind::Binary { .. } | ExprKind::Box { .. } | ExprKind::Cast { .. } - | ExprKind::Use { .. } - | ExprKind::ReifyFnPointer { .. } - | ExprKind::ClosureFnPointer { .. } - | ExprKind::UnsafeFnPointer { .. } - | ExprKind::Unsize { .. } + | ExprKind::Pointer { .. } | ExprKind::Repeat { .. } | ExprKind::Borrow { .. } | ExprKind::Assign { .. } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index d9839e0c6ec5a..0a2ea78bfd7ab 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -8,7 +8,7 @@ use rustc::ty; use rustc_target::spec::abi::Abi; -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. pub fn into_expr( @@ -46,7 +46,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value, } => { let region_scope = (region_scope, source_info); - this.in_scope(region_scope, lint_level, block, |this| { + this.in_scope(region_scope, lint_level, |this| { this.into(destination, block, value) }) } @@ -76,43 +76,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { end_block.unit() } } - ExprKind::If { - condition: cond_expr, - then: then_expr, - otherwise: else_expr, - } => { - let operand = unpack!(block = this.as_local_operand(block, cond_expr)); - - let mut then_block = this.cfg.start_new_block(); - let mut else_block = this.cfg.start_new_block(); - let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block); - this.cfg.terminate(block, source_info, term); - - unpack!(then_block = this.into(destination, then_block, then_expr)); - else_block = if let Some(else_expr) = else_expr { - unpack!(this.into(destination, else_block, else_expr)) - } else { - // Body of the `if` expression without an `else` clause must return `()`, thus - // we implicitly generate a `else {}` if it is not specified. - this.cfg - .push_assign_unit(else_block, source_info, destination); - else_block - }; - - let join_block = this.cfg.start_new_block(); - this.cfg.terminate( - then_block, - source_info, - TerminatorKind::Goto { target: join_block }, - ); - this.cfg.terminate( - else_block, - source_info, - TerminatorKind::Goto { target: join_block }, - ); - - join_block.unit() - } ExprKind::LogicalOp { op, lhs, rhs } => { // And: // @@ -216,20 +179,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // conduct the test, if necessary let body_block; if let Some(cond_expr) = opt_cond_expr { - let loop_block_end; - let cond = unpack!( - loop_block_end = this.as_local_operand(loop_block, cond_expr) - ); - body_block = this.cfg.start_new_block(); - let term = - TerminatorKind::if_(this.hir.tcx(), cond, body_block, exit_block); - this.cfg.terminate(loop_block_end, source_info, term); + let cond_expr = this.hir.mirror(cond_expr); + let (true_block, false_block) + = this.test_bool(loop_block, cond_expr, source_info); + body_block = true_block; // if the test is false, there's no `break` to assign `destination`, so - // we have to do it; this overwrites any `break`-assigned value but it's - // always `()` anyway - this.cfg - .push_assign_unit(exit_block, source_info, destination); + // we have to do it + this.cfg.push_assign_unit(false_block, source_info, destination); + this.cfg.terminate( + false_block, + source_info, + TerminatorKind::Goto { target: exit_block }, + ); } else { body_block = this.cfg.start_new_block(); let diverge_cleanup = this.diverge_cleanup(); @@ -295,7 +257,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { is_user_variable: None, is_block_tail: None, }); - let ptr_temp = Place::Base(PlaceBase::Local(ptr_temp)); + let ptr_temp = Place::from(ptr_temp); let block = unpack!(this.into(&ptr_temp, block, ptr)); this.into(&ptr_temp.deref(), block, val) } else { @@ -327,6 +289,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { success.unit() } } + ExprKind::Use { source } => { + this.into(destination, block, source) + } // These cases don't actually need a destination ExprKind::Assign { .. } @@ -379,11 +344,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::Binary { .. } | ExprKind::Box { .. } | ExprKind::Cast { .. } - | ExprKind::Use { .. } - | ExprKind::ReifyFnPointer { .. } - | ExprKind::ClosureFnPointer { .. } - | ExprKind::UnsafeFnPointer { .. } - | ExprKind::Unsize { .. } + | ExprKind::Pointer { .. } | ExprKind::Repeat { .. } | ExprKind::Borrow { .. } | ExprKind::Array { .. } diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 9527a23279570..cf3d8778da193 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -1,21 +1,21 @@ -use crate::build::scope::BreakableScope; +use crate::build::scope::BreakableTarget; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::hair::*; +use rustc::middle::region; use rustc::mir::*; -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { /// Builds a block of MIR statements to evaluate the HAIR `expr`. /// If the original expression was an AST statement, /// (e.g., `some().code(&here());`) then `opt_stmt_span` is the /// span of that statement (including its semicolon, if any). - /// Diagnostics use this span (which may be larger than that of - /// `expr`) to identify when statement temporaries are dropped. - pub fn stmt_expr(&mut self, - mut block: BasicBlock, - expr: Expr<'tcx>, - opt_stmt_span: Option) - -> BlockAnd<()> - { + /// The scope is used if a statement temporary must be dropped. + pub fn stmt_expr( + &mut self, + mut block: BasicBlock, + expr: Expr<'tcx>, + statement_scope: Option, + ) -> BlockAnd<()> { let this = self; let expr_span = expr.span; let source_info = this.source_info(expr.span); @@ -29,8 +29,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value, } => { let value = this.hir.mirror(value); - this.in_scope((region_scope, source_info), lint_level, block, |this| { - this.stmt_expr(block, value, opt_stmt_span) + this.in_scope((region_scope, source_info), lint_level, |this| { + this.stmt_expr(block, value, statement_scope) }) } ExprKind::Assign { lhs, rhs } => { @@ -98,70 +98,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.unit() } ExprKind::Continue { label } => { - let BreakableScope { - continue_block, - region_scope, - .. - } = *this.find_breakable_scope(expr_span, label); - let continue_block = continue_block - .expect("Attempted to continue in non-continuable breakable block"); - this.exit_scope( - expr_span, - (region_scope, source_info), - block, - continue_block, - ); - this.cfg.start_new_block().unit() + this.break_scope(block, None, BreakableTarget::Continue(label), source_info) } ExprKind::Break { label, value } => { - let (break_block, region_scope, destination) = { - let BreakableScope { - break_block, - region_scope, - ref break_destination, - .. - } = *this.find_breakable_scope(expr_span, label); - (break_block, region_scope, break_destination.clone()) - }; - if let Some(value) = value { - debug!("stmt_expr Break val block_context.push(SubExpr) : {:?}", expr2); - this.block_context.push(BlockFrame::SubExpr); - unpack!(block = this.into(&destination, block, value)); - this.block_context.pop(); - } else { - this.cfg.push_assign_unit(block, source_info, &destination) - } - this.exit_scope(expr_span, (region_scope, source_info), block, break_block); - this.cfg.start_new_block().unit() + this.break_scope(block, value, BreakableTarget::Break(label), source_info) } ExprKind::Return { value } => { - block = match value { - Some(value) => { - debug!("stmt_expr Return val block_context.push(SubExpr) : {:?}", expr2); - this.block_context.push(BlockFrame::SubExpr); - let result = unpack!( - this.into( - &Place::RETURN_PLACE, - block, - value - ) - ); - this.block_context.pop(); - result - } - None => { - this.cfg.push_assign_unit( - block, - source_info, - &Place::RETURN_PLACE, - ); - block - } - }; - let region_scope = this.region_scope_of_return_scope(); - let return_block = this.return_block(); - this.exit_scope(expr_span, (region_scope, source_info), block, return_block); - this.cfg.start_new_block().unit() + this.break_scope(block, value, BreakableTarget::Return, source_info) } ExprKind::InlineAsm { asm, @@ -188,18 +131,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block, Statement { source_info, - kind: StatementKind::InlineAsm { - asm: box asm.clone(), + kind: StatementKind::InlineAsm(box InlineAsm { + asm: asm.clone(), outputs, inputs, - }, + }), }, ); this.block_context.pop(); block.unit() } _ => { - let expr_ty = expr.ty; + assert!( + statement_scope.is_some(), + "Should not be calling `stmt_expr` on a general expression \ + without a statement scope", + ); // Issue #54382: When creating temp for the value of // expression like: @@ -208,48 +155,34 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // // it is usually better to focus on `the_value` rather // than the entirety of block(s) surrounding it. - let mut temp_span = expr_span; - let mut temp_in_tail_of_block = false; - if let ExprKind::Block { body } = expr.kind { - if let Some(tail_expr) = &body.expr { - let mut expr = tail_expr; - while let rustc::hir::ExprKind::Block(subblock, _label) = &expr.node { - if let Some(subtail_expr) = &subblock.expr { - expr = subtail_expr - } else { - break; + let adjusted_span = (|| { + if let ExprKind::Block { body } = expr.kind { + if let Some(tail_expr) = &body.expr { + let mut expr = tail_expr; + while let rustc::hir::ExprKind::Block(subblock, _label) = &expr.node { + if let Some(subtail_expr) = &subblock.expr { + expr = subtail_expr + } else { + break; + } } - } - temp_span = expr.span; - temp_in_tail_of_block = true; - } - } - - let temp = { - let mut local_decl = LocalDecl::new_temp(expr.ty.clone(), temp_span); - if temp_in_tail_of_block { - if this.block_context.currently_ignores_tail_results() { - local_decl = local_decl.block_tail(BlockTailInfo { + this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored: true }); + return Some(expr.span); } } - let temp = this.local_decls.push(local_decl); - let place = Place::Base(PlaceBase::Local(temp)); - debug!("created temp {:?} for expr {:?} in block_context: {:?}", - temp, expr, this.block_context); - place - }; - unpack!(block = this.into(&temp, block, expr)); + None + })(); - // Attribute drops of the statement's temps to the - // semicolon at the statement's end. - let drop_point = this.hir.tcx().sess.source_map().end_point(match opt_stmt_span { - None => expr_span, - Some(StatementSpan(span)) => span, - }); + let temp = unpack!(block = + this.as_temp(block, statement_scope, expr, Mutability::Not)); + + if let Some(span) = adjusted_span { + this.local_decls[temp].source_info.span = span; + this.block_context.pop(); + } - unpack!(block = this.build_drop(block, drop_point, temp, expr_ty)); block.unit() } } diff --git a/src/librustc_mir/build/into.rs b/src/librustc_mir/build/into.rs index 67b6540febea8..077840c9ccf17 100644 --- a/src/librustc_mir/build/into.rs +++ b/src/librustc_mir/build/into.rs @@ -9,14 +9,15 @@ use crate::hair::*; use rustc::mir::*; pub(in crate::build) trait EvalInto<'tcx> { - fn eval_into<'a, 'gcx>(self, - builder: &mut Builder<'a, 'gcx, 'tcx>, - destination: &Place<'tcx>, - block: BasicBlock) - -> BlockAnd<()>; + fn eval_into( + self, + builder: &mut Builder<'_, 'tcx>, + destination: &Place<'tcx>, + block: BasicBlock, + ) -> BlockAnd<()>; } -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn into(&mut self, destination: &Place<'tcx>, block: BasicBlock, @@ -29,22 +30,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> { - fn eval_into<'a, 'gcx>(self, - builder: &mut Builder<'a, 'gcx, 'tcx>, - destination: &Place<'tcx>, - block: BasicBlock) - -> BlockAnd<()> { + fn eval_into( + self, + builder: &mut Builder<'_, 'tcx>, + destination: &Place<'tcx>, + block: BasicBlock, + ) -> BlockAnd<()> { let expr = builder.hir.mirror(self); builder.into_expr(destination, block, expr) } } impl<'tcx> EvalInto<'tcx> for Expr<'tcx> { - fn eval_into<'a, 'gcx>(self, - builder: &mut Builder<'a, 'gcx, 'tcx>, - destination: &Place<'tcx>, - block: BasicBlock) - -> BlockAnd<()> { + fn eval_into( + self, + builder: &mut Builder<'_, 'tcx>, + destination: &Place<'tcx>, + block: BasicBlock, + ) -> BlockAnd<()> { builder.into_expr(destination, block, self) } } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 8f1301b743e9d..f831f5105a468 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -5,17 +5,19 @@ //! This also includes code for pattern bindings in `let` statements and //! function parameters. -use crate::build::scope::{CachedBlock, DropKind}; +use crate::build::scope::DropKind; use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode}; use crate::hair::{self, *}; +use rustc::hir::HirId; use rustc::mir::*; +use rustc::middle::region; use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty}; use rustc::ty::layout::VariantIdx; use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use syntax::ast::{Name, NodeId}; +use syntax::ast::Name; use syntax_pos::Span; // helper functions, broken out by category: @@ -25,7 +27,7 @@ mod util; use std::convert::TryFrom; -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { /// Generates MIR for a `match` expression. /// /// The MIR that we generate for a match looks like this. @@ -141,19 +143,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // create binding start block for link them by false edges let candidate_count = arms.iter().map(|c| c.patterns.len()).sum::(); - let pre_binding_blocks: Vec<_> = (0..=candidate_count) + let pre_binding_blocks: Vec<_> = (0..candidate_count) .map(|_| self.cfg.start_new_block()) .collect(); - // There's one more pre_binding block than there are candidates so that - // every candidate can have a `next_candidate_pre_binding_block`. - let outer_source_info = self.source_info(span); - self.cfg.terminate( - *pre_binding_blocks.last().unwrap(), - outer_source_info, - TerminatorKind::Unreachable, - ); - let mut match_has_guard = false; let mut candidate_pre_binding_blocks = pre_binding_blocks.iter(); @@ -169,9 +162,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let arm_candidates: Vec<_> = arm.patterns .iter() .zip(candidate_pre_binding_blocks.by_ref()) - .zip(next_candidate_pre_binding_blocks.by_ref()) .map( - |((pattern, pre_binding_block), next_candidate_pre_binding_block)| { + |(pattern, pre_binding_block)| { Candidate { span: pattern.span, match_pairs: vec![ @@ -186,7 +178,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }, pre_binding_block: *pre_binding_block, next_candidate_pre_binding_block: - *next_candidate_pre_binding_block, + next_candidate_pre_binding_blocks.next().copied(), } }, ) @@ -214,31 +206,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .flat_map(|(_, candidates)| candidates) .collect::>(); + let outer_source_info = self.source_info(span); + // this will generate code to test scrutinee_place and // branch to the appropriate arm block - let otherwise = self.match_candidates( + self.match_candidates( scrutinee_span, + &mut Some(block), + None, candidates, - block, &mut fake_borrows, ); - if !otherwise.is_empty() { - // All matches are exhaustive. However, because some matches - // only have exponentially-large exhaustive decision trees, we - // sometimes generate an inexhaustive decision tree. - // - // In that case, the inexhaustive tips of the decision tree - // can't be reached - terminate them with an `unreachable`. - let mut otherwise = otherwise; - otherwise.sort(); - otherwise.dedup(); // variant switches can introduce duplicate target blocks - for block in otherwise { - self.cfg - .terminate(block, outer_source_info, TerminatorKind::Unreachable); - } - } - // Step 4. Determine the fake borrows that are needed from the above // places. Create the required temporaries for them. @@ -249,38 +228,53 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; // Step 5. Create everything else: the guards and the arms. - - let outer_source_info = self.source_info(span); - let arm_end_blocks: Vec<_> = arm_candidates.into_iter().map(|(arm, candidates)| { - let mut arm_block = self.cfg.start_new_block(); - - let body = self.hir.mirror(arm.body.clone()); - let scope = self.declare_bindings( - None, - body.span, - LintLevel::Inherited, - &arm.patterns[0], - ArmHasGuard(arm.guard.is_some()), - Some((Some(&scrutinee_place), scrutinee_span)), - ); - - for candidate in candidates { - self.bind_and_guard_matched_candidate( - candidate, - arm.guard.clone(), - arm_block, - &fake_borrow_temps, - scrutinee_span, + let arm_end_blocks: Vec<_> = arm_candidates.into_iter().map(|(arm, mut candidates)| { + let arm_source_info = self.source_info(arm.span); + let region_scope = (arm.scope, arm_source_info); + self.in_scope(region_scope, arm.lint_level, |this| { + let body = this.hir.mirror(arm.body.clone()); + let scope = this.declare_bindings( + None, + arm.span, + &arm.patterns[0], + ArmHasGuard(arm.guard.is_some()), + Some((Some(&scrutinee_place), scrutinee_span)), ); - } - if let Some(source_scope) = scope { - self.source_scope = source_scope; - } + let arm_block; + if candidates.len() == 1 { + arm_block = this.bind_and_guard_matched_candidate( + candidates.pop().unwrap(), + arm.guard.clone(), + &fake_borrow_temps, + scrutinee_span, + region_scope, + ); + } else { + arm_block = this.cfg.start_new_block(); + for candidate in candidates { + this.clear_top_scope(arm.scope); + let binding_end = this.bind_and_guard_matched_candidate( + candidate, + arm.guard.clone(), + &fake_borrow_temps, + scrutinee_span, + region_scope, + ); + this.cfg.terminate( + binding_end, + source_info, + TerminatorKind::Goto { target: arm_block }, + ); + } + } - unpack!(arm_block = self.into(destination, arm_block, body)); + if let Some(source_scope) = scope { + this.source_scope = source_scope; + } - arm_block + this.into(destination, arm_block, body) + }) }).collect(); // all the arm blocks will rejoin here @@ -288,7 +282,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { for arm_block in arm_end_blocks { self.cfg.terminate( - arm_block, + unpack!(arm_block), outer_source_info, TerminatorKind::Goto { target: end_block }, ); @@ -373,7 +367,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let ty_source_info = self.source_info(user_ty_span); let user_ty = box pat_ascription_ty.user_ty( &mut self.canonical_user_type_annotations, - place.ty(&self.local_decls, self.hir.tcx()).to_ty(self.hir.tcx()), + place.ty(&self.local_decls, self.hir.tcx()).ty, ty_source_info.span, ); self.cfg.push( @@ -430,7 +424,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // since we don't call `match_candidates`, next fields are unused otherwise_block: None, pre_binding_block: block, - next_candidate_pre_binding_block: block, + next_candidate_pre_binding_block: None, }; // Simplify the candidate. Since the pattern is irrefutable, this should @@ -438,11 +432,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.simplify_candidate(&mut candidate); if !candidate.match_pairs.is_empty() { - span_bug!( + // ICE if no other errors have been emitted. This used to be a hard error that wouldn't + // be reached because `hair::pattern::check_match::check_match` wouldn't have let the + // compiler continue. In our tests this is only ever hit by + // `ui/consts/const-match-check.rs` with `--cfg eval1`, and that file already generates + // a different error before hand. + self.hir.tcx().sess.delay_span_bug( candidate.match_pairs[0].pattern.span, - "match pairs {:?} remaining after simplifying \ - irrefutable pattern", - candidate.match_pairs + &format!( + "match pairs {:?} remaining after simplifying irrefutable pattern", + candidate.match_pairs, + ), ); } @@ -482,16 +482,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { &mut self, mut visibility_scope: Option, scope_span: Span, - lint_level: LintLevel, pattern: &Pattern<'tcx>, has_guard: ArmHasGuard, opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, ) -> Option { - assert!( - !(visibility_scope.is_some() && lint_level.is_explicit()), - "can't have both a visibility and a lint scope at the same time" - ); - let mut scope = self.source_scope; debug!("declare_bindings: pattern={:?}", pattern); self.visit_bindings( &pattern, @@ -500,14 +494,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if visibility_scope.is_none() { visibility_scope = Some(this.new_source_scope(scope_span, LintLevel::Inherited, None)); - // If we have lints, create a new source scope - // that marks the lints for the locals. See the comment - // on the `source_info` field for why this is needed. - if lint_level.is_explicit() { - scope = this.new_source_scope(scope_span, lint_level, None); - } } - let source_info = SourceInfo { span, scope }; + let source_info = SourceInfo { span, scope: this.source_scope }; let visibility_scope = visibility_scope.unwrap(); this.declare_binding( source_info, @@ -530,7 +518,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn storage_live_binding( &mut self, block: BasicBlock, - var: NodeId, + var: HirId, span: Span, for_guard: ForGuard, ) -> Place<'tcx> { @@ -543,43 +531,38 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { kind: StatementKind::StorageLive(local_id), }, ); - let place = Place::Base(PlaceBase::Local(local_id)); let var_ty = self.local_decls[local_id].ty; - let hir_id = self.hir.tcx().hir().node_to_hir_id(var); - let region_scope = self.hir.region_scope_tree.var_scope(hir_id.local_id); - self.schedule_drop(span, region_scope, &place, var_ty, DropKind::Storage); - place + let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); + self.schedule_drop(span, region_scope, local_id, var_ty, DropKind::Storage); + Place::Base(PlaceBase::Local(local_id)) } - pub fn schedule_drop_for_binding(&mut self, var: NodeId, span: Span, for_guard: ForGuard) { + pub fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) { let local_id = self.var_local_id(var, for_guard); let var_ty = self.local_decls[local_id].ty; - let hir_id = self.hir.tcx().hir().node_to_hir_id(var); - let region_scope = self.hir.region_scope_tree.var_scope(hir_id.local_id); + let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); self.schedule_drop( span, region_scope, - &Place::Base(PlaceBase::Local(local_id)), + local_id, var_ty, - DropKind::Value { - cached_block: CachedBlock::default(), - }, + DropKind::Value, ); } pub(super) fn visit_bindings( &mut self, pattern: &Pattern<'tcx>, - pattern_user_ty: UserTypeProjections<'tcx>, + pattern_user_ty: UserTypeProjections, f: &mut impl FnMut( &mut Self, Mutability, Name, BindingMode, - NodeId, + HirId, Span, Ty<'tcx>, - UserTypeProjections<'tcx>, + UserTypeProjections, ), ) { debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty); @@ -677,7 +660,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } #[derive(Debug)] -pub struct Candidate<'pat, 'tcx: 'pat> { +pub struct Candidate<'pat, 'tcx> { // span of the original pattern that gave rise to this candidate span: Span, @@ -695,7 +678,7 @@ pub struct Candidate<'pat, 'tcx: 'pat> { // ...and the blocks for add false edges between candidates pre_binding_block: BasicBlock, - next_candidate_pre_binding_block: BasicBlock, + next_candidate_pre_binding_block: Option, } #[derive(Clone, Debug)] @@ -703,7 +686,7 @@ struct Binding<'tcx> { span: Span, source: Place<'tcx>, name: Name, - var_id: NodeId, + var_id: HirId, var_ty: Ty<'tcx>, mutability: Mutability, binding_mode: BindingMode, @@ -721,7 +704,7 @@ struct Ascription<'tcx> { } #[derive(Clone, Debug)] -pub struct MatchPair<'pat, 'tcx: 'pat> { +pub struct MatchPair<'pat, 'tcx> { // this place... place: Place<'tcx>, @@ -731,29 +714,46 @@ pub struct MatchPair<'pat, 'tcx: 'pat> { #[derive(Clone, Debug, PartialEq)] enum TestKind<'tcx> { - // test the branches of enum + /// Test the branches of enum. Switch { + /// The enum being tested adt_def: &'tcx ty::AdtDef, + /// The set of variants that we should create a branch for. We also + /// create an additional "otherwise" case. variants: BitSet, }, - // test the branches of enum + /// Test what value an `integer`, `bool` or `char` has. SwitchInt { + /// The type of the value that we're testing. switch_ty: Ty<'tcx>, + /// The (ordered) set of values that we test for. + /// + /// For integers and `char`s we create a branch to each of the values in + /// `options`, as well as an "otherwise" branch for all other values, even + /// in the (rare) case that options is exhaustive. + /// + /// For `bool` we always generate two edges, one for `true` and one for + /// `false`. options: Vec, - indices: FxHashMap, usize>, + /// Reverse map used to ensure that the values in `options` are unique. + indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>, }, - // test for equality + /// Test for equality with value, possibly after an unsizing coercion to + /// `ty`, Eq { - value: ty::Const<'tcx>, + value: &'tcx ty::Const<'tcx>, + // Integer types are handled by `SwitchInt`, and constants with ADT + // types are converted back into patterns, so this can only be `&str`, + // `&[T]`, `f32` or `f64`. ty: Ty<'tcx>, }, - // test whether the value falls within an inclusive or exclusive range + /// Test whether the value falls within an inclusive or exclusive range Range(PatternRange<'tcx>), - // test length of the slice is equal to len + /// Test length of the slice is equal to len Len { len: u64, op: BinOp, @@ -774,7 +774,7 @@ pub(crate) struct ArmHasGuard(pub bool); /////////////////////////////////////////////////////////////////////////// // Main matching algorithm -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { /// The main match algorithm. It begins with a set of candidates /// `candidates` and has the job of generating code to determine /// which of these candidates, if any, is the correct one. The @@ -783,11 +783,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// the value, we will generate a branch to the appropriate /// prebinding block. /// - /// The return value is a list of "otherwise" blocks. These are - /// points in execution where we found that *NONE* of the - /// candidates apply. In principle, this means that the input - /// list was not exhaustive, though at present we sometimes are - /// not smart enough to recognize all exhaustive inputs. + /// If we find that *NONE* of the candidates apply, we branch to the + /// `otherwise_block`. In principle, this means that the input list was not + /// exhaustive, though at present we sometimes are not smart enough to + /// recognize all exhaustive inputs. /// /// It might be surprising that the input can be inexhaustive. /// Indeed, initially, it is not, because all matches are @@ -801,13 +800,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn match_candidates<'pat>( &mut self, span: Span, + start_block: &mut Option, + otherwise_block: Option, candidates: &mut [&mut Candidate<'pat, 'tcx>], - mut block: BasicBlock, fake_borrows: &mut Option>>, - ) -> Vec { + ) { debug!( - "matched_candidate(span={:?}, block={:?}, candidates={:?})", - span, block, candidates + "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})", + span, + candidates, + start_block, + otherwise_block, ); // Start by simplifying candidates. Once this process is complete, all @@ -830,52 +833,57 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ); let (matched_candidates, unmatched_candidates) = candidates.split_at_mut(fully_matched); + let block: BasicBlock; + if !matched_candidates.is_empty() { - block = if let Some(last_otherwise_block) = self.select_matched_candidates( + let otherwise_block = self.select_matched_candidates( matched_candidates, - block, + start_block, fake_borrows, - ) { - last_otherwise_block + ); + + if let Some(last_otherwise_block) = otherwise_block { + block = last_otherwise_block } else { // Any remaining candidates are unreachable. if unmatched_candidates.is_empty() { - return Vec::new(); - } else { - self.cfg.start_new_block() + return; } + block = self.cfg.start_new_block(); }; + } else { + block = *start_block.get_or_insert_with(|| self.cfg.start_new_block()); } // If there are no candidates that still need testing, we're // done. Since all matches are exhaustive, execution should // never reach this point. if unmatched_candidates.is_empty() { - return vec![block]; + let source_info = self.source_info(span); + if let Some(otherwise) = otherwise_block { + self.cfg.terminate( + block, + source_info, + TerminatorKind::Goto { target: otherwise }, + ); + } else { + self.cfg.terminate( + block, + source_info, + TerminatorKind::Unreachable, + ) + } + return; } - // Test candidates where possible. - let (otherwise, untested_candidates) = self.test_candidates( + // Test for the remaining candidates. + self.test_candidates( span, unmatched_candidates, block, + otherwise_block, fake_borrows, ); - - // If the target candidates were exhaustive, then we are done. - // But for borrowck continue build decision tree. - if untested_candidates.is_empty() { - return otherwise; - } - - // Otherwise, let's process those remaining candidates. - let join_block = self.join_otherwise_blocks(span, otherwise); - self.match_candidates( - span, - untested_candidates, - join_block, - &mut None, - ) } /// Link up matched candidates. For example, if we have something like @@ -899,7 +907,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn select_matched_candidates( &mut self, matched_candidates: &mut [&mut Candidate<'_, 'tcx>], - block: BasicBlock, + start_block: &mut Option, fake_borrows: &mut Option>>, ) -> Option { debug_assert!( @@ -947,31 +955,29 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { = matched_candidates.split_at_mut(fully_matched_with_guard + 1); let first_candidate = &reachable_candidates[0]; + let first_prebinding_block = first_candidate.pre_binding_block; - let candidate_source_info = self.source_info(first_candidate.span); - - self.cfg.terminate( - block, - candidate_source_info, - TerminatorKind::Goto { - target: first_candidate.pre_binding_block, - }, - ); + if let Some(start_block) = *start_block { + let source_info = self.source_info(first_candidate.span); + self.cfg.terminate( + start_block, + source_info, + TerminatorKind::Goto { target: first_prebinding_block }, + ); + } else { + *start_block = Some(first_prebinding_block); + } for window in reachable_candidates.windows(2) { if let [first_candidate, second_candidate] = window { let source_info = self.source_info(first_candidate.span); if let Some(otherwise_block) = first_candidate.otherwise_block { - self.cfg.terminate( + self.false_edges( otherwise_block, + second_candidate.pre_binding_block, + first_candidate.next_candidate_pre_binding_block, source_info, - TerminatorKind::FalseEdges { - real_target: second_candidate.pre_binding_block, - imaginary_targets: vec![ - first_candidate.next_candidate_pre_binding_block - ], - } - ) + ); } else { bug!("candidate other than the last has no guard"); } @@ -985,13 +991,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(otherwise) = candidate.otherwise_block { let source_info = self.source_info(candidate.span); let unreachable = self.cfg.start_new_block(); - self.cfg.terminate( + self.false_edges( otherwise, + unreachable, + candidate.next_candidate_pre_binding_block, source_info, - TerminatorKind::FalseEdges { - real_target: unreachable, - imaginary_targets: vec![candidate.next_candidate_pre_binding_block], - } ); self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable); } @@ -1002,13 +1006,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(otherwise) = last_candidate.otherwise_block { let source_info = self.source_info(last_candidate.span); let block = self.cfg.start_new_block(); - self.cfg.terminate( + self.false_edges( otherwise, + block, + last_candidate.next_candidate_pre_binding_block, source_info, - TerminatorKind::FalseEdges { - real_target: block, - imaginary_targets: vec![last_candidate.next_candidate_pre_binding_block] - } ); Some(block) } else { @@ -1016,25 +1018,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - fn join_otherwise_blocks(&mut self, span: Span, mut otherwise: Vec) -> BasicBlock { - let source_info = self.source_info(span); - otherwise.sort(); - otherwise.dedup(); // variant switches can introduce duplicate target blocks - if otherwise.len() == 1 { - otherwise[0] - } else { - let join_block = self.cfg.start_new_block(); - for block in otherwise { - self.cfg.terminate( - block, - source_info, - TerminatorKind::Goto { target: join_block }, - ); - } - join_block - } - } - /// This is the most subtle part of the matching algorithm. At /// this point, the input candidates have been fully simplified, /// and so we know that all remaining match-pairs require some @@ -1152,8 +1135,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: Span, mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], block: BasicBlock, + mut otherwise_block: Option, fake_borrows: &mut Option>>, - ) -> (Vec, &'b mut [&'c mut Candidate<'pat, 'tcx>]) { + ) { // extract the match-pair from the highest priority candidate let match_pair = &candidates.first().unwrap().match_pairs[0]; let mut test = self.test(match_pair); @@ -1207,9 +1191,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { "match_candidates: test={:?} match_pair={:?}", test, match_pair ); - let target_blocks = self.perform_test(block, &match_place, &test); let mut target_candidates: Vec>> = vec![]; - target_candidates.resize_with(target_blocks.len(), Default::default); + target_candidates.resize_with(test.targets(), Default::default); let total_candidate_count = candidates.len(); @@ -1231,24 +1214,59 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("tested_candidates: {}", total_candidate_count - candidates.len()); debug!("untested_candidates: {}", candidates.len()); - // For each outcome of test, process the candidates that still - // apply. Collect a list of blocks where control flow will - // branch if one of the `target_candidate` sets is not - // exhaustive. - let otherwise: Vec<_> = target_blocks - .into_iter() - .zip(target_candidates) - .flat_map(|(target_block, mut target_candidates)| { - self.match_candidates( + // HACK(matthewjasper) This is a closure so that we can let the test + // create its blocks before the rest of the match. This currently + // improves the speed of llvm when optimizing long string literal + // matches + let make_target_blocks = move |this: &mut Self| -> Vec { + // For each outcome of test, process the candidates that still + // apply. Collect a list of blocks where control flow will + // branch if one of the `target_candidate` sets is not + // exhaustive. + if !candidates.is_empty() { + let remainder_start = &mut None; + this.match_candidates( span, - &mut *target_candidates, - target_block, + remainder_start, + otherwise_block, + candidates, fake_borrows, - ) - }) - .collect(); + ); + otherwise_block = Some(remainder_start.unwrap()); + }; - (otherwise, candidates) + target_candidates.into_iter().map(|mut candidates| { + if candidates.len() != 0 { + let candidate_start = &mut None; + this.match_candidates( + span, + candidate_start, + otherwise_block, + &mut *candidates, + fake_borrows, + ); + candidate_start.unwrap() + } else { + *otherwise_block.get_or_insert_with(|| { + let unreachable = this.cfg.start_new_block(); + let source_info = this.source_info(span); + this.cfg.terminate( + unreachable, + source_info, + TerminatorKind::Unreachable, + ); + unreachable + }) + } + }).collect() + }; + + self.perform_test( + block, + &match_place, + &test, + make_target_blocks, + ); } // Determine the fake borrows that are needed to ensure that the place @@ -1288,8 +1306,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows); all_fake_borrows.into_iter().map(|matched_place| { - let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).to_ty(tcx); - let fake_borrow_ty = tcx.mk_imm_ref(tcx.types.re_erased, fake_borrow_deref_ty); + let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty; + let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty); let fake_borrow_temp = self.local_decls.push( LocalDecl::new_temp(fake_borrow_ty, temp_span) ); @@ -1302,7 +1320,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /////////////////////////////////////////////////////////////////////////// // Pattern binding - used for `let` and function parameters as well. -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { /// Initializes each of the bindings from the candidate by /// moving/copying/ref'ing the source as appropriate. Tests the guard, if /// any, and then branches to the arm. Returns the block for the case where @@ -1319,26 +1337,37 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { &mut self, candidate: Candidate<'pat, 'tcx>, guard: Option>, - arm_block: BasicBlock, fake_borrows: &Vec<(&Place<'tcx>, Local)>, scrutinee_span: Span, - ) { + region_scope: (region::Scope, SourceInfo), + ) -> BasicBlock { debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate); debug_assert!(candidate.match_pairs.is_empty()); let candidate_source_info = self.source_info(candidate.span); - let mut block = self.cfg.start_new_block(); - self.cfg.terminate( - candidate.pre_binding_block, - candidate_source_info, - TerminatorKind::FalseEdges { - real_target: block, - imaginary_targets: vec![candidate.next_candidate_pre_binding_block], - }, - ); - self.ascribe_types(block, &candidate.ascriptions); + let mut block = candidate.pre_binding_block; + + // If we are adding our own statements, then we need a fresh block. + let create_fresh_block = candidate.next_candidate_pre_binding_block.is_some() + || !candidate.bindings.is_empty() + || !candidate.ascriptions.is_empty() + || guard.is_some(); + + if create_fresh_block { + let fresh_block = self.cfg.start_new_block(); + self.false_edges( + block, + fresh_block, + candidate.next_candidate_pre_binding_block, + candidate_source_info, + ); + block = fresh_block; + self.ascribe_types(block, &candidate.ascriptions); + } else { + return block; + } // rust-lang/rust#27282: The `autoref` business deserves some // explanation here. @@ -1420,28 +1449,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // the reference that we create for the arm. // * So we eagerly create the reference for the arm and then take a // reference to that. - let tcx = self.hir.tcx(); - let autoref = tcx.all_pat_vars_are_implicit_refs_within_guards(); if let Some(guard) = guard { - if autoref { - self.bind_matched_candidate_for_guard( - block, - &candidate.bindings, - ); - let guard_frame = GuardFrame { - locals: candidate - .bindings - .iter() - .map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode)) - .collect(), - }; - debug!("Entering guard building context: {:?}", guard_frame); - self.guard_context.push(guard_frame); - } else { - self.bind_matched_candidate_for_arm_body(block, &candidate.bindings); - } + let tcx = self.hir.tcx(); + + self.bind_matched_candidate_for_guard( + block, + &candidate.bindings, + ); + let guard_frame = GuardFrame { + locals: candidate + .bindings + .iter() + .map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode)) + .collect(), + }; + debug!("Entering guard building context: {:?}", guard_frame); + self.guard_context.push(guard_frame); - let re_erased = tcx.types.re_erased; + let re_erased = tcx.lifetimes.re_erased; let scrutinee_source_info = self.source_info(scrutinee_span); for &(place, temp) in fake_borrows { let borrow = Rvalue::Ref( @@ -1452,7 +1477,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.push_assign( block, scrutinee_source_info, - &Place::Base(PlaceBase::Local(temp)), + &Place::from(temp), borrow, ); } @@ -1464,32 +1489,38 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; let source_info = self.source_info(guard.span); let guard_end = self.source_info(tcx.sess.source_map().end_point(guard.span)); - let cond = unpack!(block = self.as_local_operand(block, guard)); - if autoref { - let guard_frame = self.guard_context.pop().unwrap(); - debug!( - "Exiting guard building context with locals: {:?}", - guard_frame - ); - } + let (post_guard_block, otherwise_post_guard_block) + = self.test_bool(block, guard, source_info); + let guard_frame = self.guard_context.pop().unwrap(); + debug!( + "Exiting guard building context with locals: {:?}", + guard_frame + ); for &(_, temp) in fake_borrows { - self.cfg.push(block, Statement { + self.cfg.push(post_guard_block, Statement { source_info: guard_end, kind: StatementKind::FakeRead( FakeReadCause::ForMatchGuard, - Place::Base(PlaceBase::Local(temp)), + Place::from(temp), ), }); } + self.exit_scope( + source_info.span, + region_scope, + otherwise_post_guard_block, + candidate.otherwise_block.unwrap(), + ); + // We want to ensure that the matched candidates are bound // after we have confirmed this candidate *and* any // associated guard; Binding them on `block` is too soon, // because that would be before we've checked the result // from the guard. // - // But binding them on `arm_block` is *too late*, because + // But binding them on the arm is *too late*, because // then all of the candidates for a single arm would be // bound in the same place, that would cause a case like: // @@ -1509,67 +1540,41 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // ``` // // and that is clearly not correct. - let post_guard_block = self.cfg.start_new_block(); - self.cfg.terminate( - block, - source_info, - TerminatorKind::if_( - self.hir.tcx(), - cond, - post_guard_block, - candidate.otherwise_block.unwrap() - ), - ); - - if autoref { - let by_value_bindings = candidate.bindings.iter().filter(|binding| { - if let BindingMode::ByValue = binding.binding_mode { true } else { false } - }); - // Read all of the by reference bindings to ensure that the - // place they refer to can't be modified by the guard. - for binding in by_value_bindings.clone() { - let local_id = self.var_local_id(binding.var_id, RefWithinGuard); - let place = Place::Base(PlaceBase::Local(local_id)); - self.cfg.push( - block, - Statement { - source_info: guard_end, - kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, place), - }, - ); - } - self.bind_matched_candidate_for_arm_body( + let by_value_bindings = candidate.bindings.iter().filter(|binding| { + if let BindingMode::ByValue = binding.binding_mode { true } else { false } + }); + // Read all of the by reference bindings to ensure that the + // place they refer to can't be modified by the guard. + for binding in by_value_bindings.clone() { + let local_id = self.var_local_id(binding.var_id, RefWithinGuard); + let place = Place::from(local_id); + self.cfg.push( post_guard_block, - by_value_bindings, + Statement { + source_info: guard_end, + kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, place), + }, ); } - - self.cfg.terminate( + self.bind_matched_candidate_for_arm_body( post_guard_block, - source_info, - TerminatorKind::Goto { target: arm_block }, + by_value_bindings, ); + + post_guard_block } else { assert!(candidate.otherwise_block.is_none()); // (Here, it is not too early to bind the matched // candidate on `block`, because there is no guard result // that we have to inspect before we bind them.) self.bind_matched_candidate_for_arm_body(block, &candidate.bindings); - self.cfg.terminate( - block, - candidate_source_info, - TerminatorKind::Goto { target: arm_block }, - ); + block } } /// Append `AscribeUserType` statements onto the end of `block` /// for each ascription - fn ascribe_types<'pat>( - &mut self, - block: BasicBlock, - ascriptions: &[Ascription<'tcx>], - ) { + fn ascribe_types(&mut self, block: BasicBlock, ascriptions: &[Ascription<'tcx>]) { for ascription in ascriptions { let source_info = self.source_info(ascription.span); @@ -1582,7 +1587,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let user_ty = box ascription.user_ty.clone().user_ty( &mut self.canonical_user_type_annotations, - ascription.source.ty(&self.local_decls, self.hir.tcx()).to_ty(self.hir.tcx()), + ascription.source.ty(&self.local_decls, self.hir.tcx()).ty, source_info.span ); self.cfg.push( @@ -1599,8 +1604,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - // Only called when all_pat_vars_are_implicit_refs_within_guards, - // and thus all code/comments assume we are in that context. fn bind_matched_candidate_for_guard( &mut self, block: BasicBlock, @@ -1611,7 +1614,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Assign each of the bindings. Since we are binding for a // guard expression, this will never trigger moves out of the // candidate. - let re_erased = self.hir.tcx().types.re_erased; + let re_erased = self.hir.tcx().lifetimes.re_erased; for binding in bindings { let source_info = self.source_info(binding.span); @@ -1621,11 +1624,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // denotes *R. let ref_for_guard = self.storage_live_binding(block, binding.var_id, binding.span, RefWithinGuard); - // Question: Why schedule drops if bindings are all - // shared-&'s? - // Answer: Because schedule_drop_for_binding also emits - // StorageDead's for those locals. - self.schedule_drop_for_binding(binding.var_id, binding.span, RefWithinGuard); match binding.binding_mode { BindingMode::ByValue => { let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source.clone()); @@ -1639,11 +1637,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { binding.span, OutsideGuard, ); - self.schedule_drop_for_binding( - binding.var_id, - binding.span, - OutsideGuard, - ); let rvalue = Rvalue::Ref(re_erased, borrow_kind, binding.source.clone()); self.cfg @@ -1663,7 +1656,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ) where 'tcx: 'b { debug!("bind_matched_candidate_for_arm_body(block={:?})", block); - let re_erased = self.hir.tcx().types.re_erased; + let re_erased = self.hir.tcx().lifetimes.re_erased; // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { let source_info = self.source_info(binding.span); @@ -1694,9 +1687,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { mutability: Mutability, name: Name, mode: BindingMode, - var_id: NodeId, + var_id: HirId, var_ty: Ty<'tcx>, - user_ty: UserTypeProjections<'tcx>, + user_ty: UserTypeProjections, has_guard: ArmHasGuard, opt_match_place: Option<(Option>, Span)>, pat_span: Span, @@ -1733,13 +1726,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pat_span, }))), }; - let for_arm_body = self.local_decls.push(local.clone()); - let locals = if has_guard.0 && tcx.all_pat_vars_are_implicit_refs_within_guards() { + let for_arm_body = self.local_decls.push(local); + let locals = if has_guard.0 { let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> { // This variable isn't mutated but has a name, so has to be // immutable to avoid the unused mut lint. mutability: Mutability::Not, - ty: tcx.mk_imm_ref(tcx.types.re_erased, var_ty), + ty: tcx.mk_imm_ref(tcx.lifetimes.re_erased, var_ty), user_ty: UserTypeProjections::none(), name: Some(name), source_info, diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 01f8cbfbe8e2b..b1b5233fbc875 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -19,10 +19,11 @@ use rustc::ty; use rustc::ty::layout::{Integer, IntegerExt, Size}; use syntax::attr::{SignedInt, UnsignedInt}; use rustc::hir::RangeEnd; +use rustc::mir::interpret::truncate; use std::mem; -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) { // repeatedly simplify match pairs until fixed point is reached @@ -113,16 +114,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0) } ty::Int(ity) => { - // FIXME(49937): refactor these bit manipulations into interpret. let size = Integer::from_attr(&tcx, SignedInt(ity)).size(); - let max = !0u128 >> (128 - size.bits()); + let max = truncate(u128::max_value(), size); let bias = 1u128 << (size.bits() - 1); (Some((0, max, size)), bias) } ty::Uint(uty) => { - // FIXME(49937): refactor these bit manipulations into interpret. let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size(); - let max = !0u128 >> (128 - size.bits()); + let max = truncate(u128::max_value(), size); (Some((0, max, size)), 0) } _ => (None, 0), @@ -164,7 +163,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { i == variant_index || { self.hir.tcx().features().never_type && self.hir.tcx().features().exhaustive_patterns && - self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs) + !v.uninhabited_from(self.hir.tcx(), substs, adt_def.adt_kind()).is_empty() } }); if irrefutable { diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 72b92444dece9..95e2e52092a91 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -11,15 +11,16 @@ use crate::hair::*; use crate::hair::pattern::compare_const_vals; use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::fx::FxHashMap; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, adjustment::{PointerCast}}; use rustc::ty::util::IntTypeExt; use rustc::ty::layout::VariantIdx; use rustc::mir::*; -use rustc::hir::{RangeEnd, Mutability}; -use syntax_pos::Span; +use rustc::hir::RangeEnd; +use syntax_pos::symbol::sym; + use std::cmp::Ordering; -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { /// Identifies what test is needed to decide if `match_pair` is applicable. /// /// It is a bug to call this with a simplifiable pattern. @@ -98,7 +99,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { candidate: &Candidate<'pat, 'tcx>, switch_ty: Ty<'tcx>, options: &mut Vec, - indices: &mut FxHashMap, usize>) + indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>) -> bool { let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) { @@ -162,43 +163,51 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - /// Generates the code to perform a test. - pub fn perform_test(&mut self, - block: BasicBlock, - place: &Place<'tcx>, - test: &Test<'tcx>) - -> Vec { + pub fn perform_test( + &mut self, + block: BasicBlock, + place: &Place<'tcx>, + test: &Test<'tcx>, + make_target_blocks: impl FnOnce(&mut Self) -> Vec, + ) { debug!("perform_test({:?}, {:?}: {:?}, {:?})", block, place, place.ty(&self.local_decls, self.hir.tcx()), test); + let source_info = self.source_info(test.span); match test.kind { TestKind::Switch { adt_def, ref variants } => { + let target_blocks = make_target_blocks(self); // Variants is a BitVec of indexes into adt_def.variants. let num_enum_variants = adt_def.variants.len(); let used_variants = variants.count(); - let mut otherwise_block = None; - let mut target_blocks = Vec::with_capacity(num_enum_variants); + debug_assert_eq!(target_blocks.len(), num_enum_variants + 1); + let otherwise_block = *target_blocks.last().unwrap(); let mut targets = Vec::with_capacity(used_variants + 1); let mut values = Vec::with_capacity(used_variants); let tcx = self.hir.tcx(); for (idx, discr) in adt_def.discriminants(tcx) { - target_blocks.push(if variants.contains(idx) { + if variants.contains(idx) { + debug_assert_ne!( + target_blocks[idx.index()], + otherwise_block, + "no canididates for tested discriminant: {:?}", + discr, + ); values.push(discr.val); - let block = self.cfg.start_new_block(); - targets.push(block); - block + targets.push(target_blocks[idx.index()]); } else { - *otherwise_block - .get_or_insert_with(|| self.cfg.start_new_block()) - }); + debug_assert_eq!( + target_blocks[idx.index()], + otherwise_block, + "found canididates for untested discriminant: {:?}", + discr, + ); + } } - targets.push( - otherwise_block - .unwrap_or_else(|| self.unreachable_block()), - ); + targets.push(otherwise_block); debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}", num_enum_variants, values, variants); let discr_ty = adt_def.repr.discr_type().to_ty(tcx); @@ -212,177 +221,97 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { values: From::from(values), targets, }); - target_blocks } TestKind::SwitchInt { switch_ty, ref options, indices: _ } => { - let (ret, terminator) = if switch_ty.sty == ty::Bool { + let target_blocks = make_target_blocks(self); + let terminator = if switch_ty.sty == ty::Bool { assert!(options.len() > 0 && options.len() <= 2); - let (true_bb, false_bb) = (self.cfg.start_new_block(), - self.cfg.start_new_block()); - let ret = match options[0] { - 1 => vec![true_bb, false_bb], - 0 => vec![false_bb, true_bb], - v => span_bug!(test.span, "expected boolean value but got {:?}", v) - }; - (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place.clone()), - true_bb, false_bb)) + if let [first_bb, second_bb] = *target_blocks { + let (true_bb, false_bb) = match options[0] { + 1 => (first_bb, second_bb), + 0 => (second_bb, first_bb), + v => span_bug!(test.span, "expected boolean value but got {:?}", v) + }; + TerminatorKind::if_( + self.hir.tcx(), + Operand::Copy(place.clone()), + true_bb, + false_bb, + ) + } else { + bug!("`TestKind::SwitchInt` on `bool` should have two targets") + } } else { - // The switch may be inexhaustive so we - // add a catch all block - let otherwise = self.cfg.start_new_block(); - let targets: Vec<_> = - options.iter() - .map(|_| self.cfg.start_new_block()) - .chain(Some(otherwise)) - .collect(); - (targets.clone(), TerminatorKind::SwitchInt { + // The switch may be inexhaustive so we have a catch all block + debug_assert_eq!(options.len() + 1, target_blocks.len()); + TerminatorKind::SwitchInt { discr: Operand::Copy(place.clone()), switch_ty, values: options.clone().into(), - targets, - }) + targets: target_blocks, + } }; self.cfg.terminate(block, source_info, terminator); - ret } - TestKind::Eq { value, mut ty } => { - let val = Operand::Copy(place.clone()); - let mut expect = self.literal_operand(test.span, ty, value); - // Use `PartialEq::eq` instead of `BinOp::Eq` - // (the binop can only handle primitives) - let fail = self.cfg.start_new_block(); + TestKind::Eq { value, ty } => { if !ty.is_scalar() { - // If we're using `b"..."` as a pattern, we need to insert an - // unsizing coercion, as the byte string has the type `&[u8; N]`. - // - // We want to do this even when the scrutinee is a reference to an - // array, so we can call `<[u8]>::eq` rather than having to find an - // `<[u8; N]>::eq`. - let unsize = |ty: Ty<'tcx>| match ty.sty { - ty::Ref(region, rty, _) => match rty.sty { - ty::Array(inner_ty, n) => Some((region, inner_ty, n)), - _ => None, - }, - _ => None, - }; - let opt_ref_ty = unsize(ty); - let opt_ref_test_ty = unsize(value.ty); - let mut place = place.clone(); - match (opt_ref_ty, opt_ref_test_ty) { - // nothing to do, neither is an array - (None, None) => {}, - (Some((region, elem_ty, _)), _) | - (None, Some((region, elem_ty, _))) => { - let tcx = self.hir.tcx(); - // make both a slice - ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty)); - if opt_ref_ty.is_some() { - place = self.temp(ty, test.span); - self.cfg.push_assign(block, source_info, &place, - Rvalue::Cast(CastKind::Unsize, val, ty)); - } - if opt_ref_test_ty.is_some() { - let array = self.literal_operand( - test.span, - value.ty, - value, - ); - - let slice = self.temp(ty, test.span); - self.cfg.push_assign(block, source_info, &slice, - Rvalue::Cast(CastKind::Unsize, array, ty)); - expect = Operand::Move(slice); - } - }, - } - let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap(); - let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty.into()]); - let method = self.hir.tcx().mk_lazy_const(ty::LazyConst::Evaluated(method)); - - let re_erased = self.hir.tcx().types.re_erased; - // take the argument by reference - let tam = ty::TypeAndMut { + // Use `PartialEq::eq` instead of `BinOp::Eq` + // (the binop can only handle primitives) + self.non_scalar_compare( + block, + make_target_blocks, + source_info, + value, + place, ty, - mutbl: Mutability::MutImmutable, - }; - let ref_ty = self.hir.tcx().mk_ref(re_erased, tam); - - // let lhs_ref_place = &lhs; - let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, place); - let lhs_ref_place = self.temp(ref_ty, test.span); - self.cfg.push_assign(block, source_info, &lhs_ref_place, ref_rvalue); - let val = Operand::Move(lhs_ref_place); - - // let rhs_place = rhs; - let rhs_place = self.temp(ty, test.span); - self.cfg.push_assign(block, source_info, &rhs_place, Rvalue::Use(expect)); - - // let rhs_ref_place = &rhs_place; - let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, rhs_place); - let rhs_ref_place = self.temp(ref_ty, test.span); - self.cfg.push_assign(block, source_info, &rhs_ref_place, ref_rvalue); - let expect = Operand::Move(rhs_ref_place); - - let bool_ty = self.hir.bool_ty(); - let eq_result = self.temp(bool_ty, test.span); - let eq_block = self.cfg.start_new_block(); - let cleanup = self.diverge_cleanup(); - self.cfg.terminate(block, source_info, TerminatorKind::Call { - func: Operand::Constant(box Constant { - span: test.span, - ty: mty, - - // FIXME(#54571): This constant comes from user - // input (a constant in a pattern). Are - // there forms where users can add type - // annotations here? For example, an - // associated constant? Need to - // experiment. - user_ty: None, - - literal: method, - }), - args: vec![val, expect], - destination: Some((eq_result.clone(), eq_block)), - cleanup: Some(cleanup), - from_hir_call: false, - }); - - // check the result - let block = self.cfg.start_new_block(); - self.cfg.terminate(eq_block, source_info, - TerminatorKind::if_(self.hir.tcx(), - Operand::Move(eq_result), - block, fail)); - vec![block, fail] + ); } else { - let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val); - vec![block, fail] + if let [success, fail] = *make_target_blocks(self) { + let val = Operand::Copy(place.clone()); + let expect = self.literal_operand(test.span, ty, value); + self.compare(block, success, fail, source_info, BinOp::Eq, expect, val); + } else { + bug!("`TestKind::Eq` should have two target blocks"); + } } } TestKind::Range(PatternRange { ref lo, ref hi, ty, ref end }) => { + let lower_bound_success = self.cfg.start_new_block(); + let target_blocks = make_target_blocks(self); + // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons. - let lo = self.literal_operand(test.span, ty.clone(), lo.clone()); - let hi = self.literal_operand(test.span, ty.clone(), hi.clone()); + let lo = self.literal_operand(test.span, ty, lo); + let hi = self.literal_operand(test.span, ty, hi); let val = Operand::Copy(place.clone()); - let fail = self.cfg.start_new_block(); - let block = self.compare(block, fail, test.span, BinOp::Le, lo, val.clone()); - let block = match *end { - RangeEnd::Included => self.compare(block, fail, test.span, BinOp::Le, val, hi), - RangeEnd::Excluded => self.compare(block, fail, test.span, BinOp::Lt, val, hi), - }; - - vec![block, fail] + if let [success, fail] = *target_blocks { + self.compare( + block, + lower_bound_success, + fail, + source_info, + BinOp::Le, + lo, + val.clone(), + ); + let op = match *end { + RangeEnd::Included => BinOp::Le, + RangeEnd::Excluded => BinOp::Lt, + }; + self.compare(lower_bound_success, success, fail, source_info, op, val, hi); + } else { + bug!("`TestKind::Range` should have two target blocks"); + } } TestKind::Len { len, op } => { - let (usize_ty, bool_ty) = (self.hir.usize_ty(), self.hir.bool_ty()); - let (actual, result) = (self.temp(usize_ty, test.span), - self.temp(bool_ty, test.span)); + let target_blocks = make_target_blocks(self); + + let usize_ty = self.hir.usize_ty(); + let actual = self.temp(usize_ty, test.span); // actual = len(place) self.cfg.push_assign(block, source_info, @@ -391,44 +320,165 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // expected = let expected = self.push_usize(block, source_info, len); - // result = actual == expected OR result = actual < expected - self.cfg.push_assign(block, source_info, &result, - Rvalue::BinaryOp(op, - Operand::Move(actual), - Operand::Move(expected))); - - // branch based on result - let (false_bb, true_bb) = (self.cfg.start_new_block(), - self.cfg.start_new_block()); - self.cfg.terminate(block, source_info, - TerminatorKind::if_(self.hir.tcx(), Operand::Move(result), - true_bb, false_bb)); - vec![true_bb, false_bb] + if let [true_bb, false_bb] = *target_blocks { + // result = actual == expected OR result = actual < expected + // branch based on result + self.compare( + block, + true_bb, + false_bb, + source_info, + op, + Operand::Move(actual), + Operand::Move(expected), + ); + } else { + bug!("`TestKind::Len` should have two target blocks"); + } } } } - fn compare(&mut self, - block: BasicBlock, - fail_block: BasicBlock, - span: Span, - op: BinOp, - left: Operand<'tcx>, - right: Operand<'tcx>) -> BasicBlock { + /// Compare using the provided built-in comparison operator + fn compare( + &mut self, + block: BasicBlock, + success_block: BasicBlock, + fail_block: BasicBlock, + source_info: SourceInfo, + op: BinOp, + left: Operand<'tcx>, + right: Operand<'tcx>, + ) { let bool_ty = self.hir.bool_ty(); - let result = self.temp(bool_ty, span); + let result = self.temp(bool_ty, source_info.span); // result = op(left, right) - let source_info = self.source_info(span); - self.cfg.push_assign(block, source_info, &result, - Rvalue::BinaryOp(op, left, right)); + self.cfg.push_assign( + block, + source_info, + &result, + Rvalue::BinaryOp(op, left, right), + ); // branch based on result - let target_block = self.cfg.start_new_block(); - self.cfg.terminate(block, source_info, - TerminatorKind::if_(self.hir.tcx(), Operand::Move(result), - target_block, fail_block)); - target_block + self.cfg.terminate( + block, + source_info, + TerminatorKind::if_( + self.hir.tcx(), + Operand::Move(result), + success_block, + fail_block, + ), + ); + } + + /// Compare two `&T` values using `::eq` + fn non_scalar_compare( + &mut self, + block: BasicBlock, + make_target_blocks: impl FnOnce(&mut Self) -> Vec, + source_info: SourceInfo, + value: &'tcx ty::Const<'tcx>, + place: &Place<'tcx>, + mut ty: Ty<'tcx>, + ) { + use rustc::middle::lang_items::EqTraitLangItem; + + let mut expect = self.literal_operand(source_info.span, value.ty, value); + let mut val = Operand::Copy(place.clone()); + + // If we're using `b"..."` as a pattern, we need to insert an + // unsizing coercion, as the byte string has the type `&[u8; N]`. + // + // We want to do this even when the scrutinee is a reference to an + // array, so we can call `<[u8]>::eq` rather than having to find an + // `<[u8; N]>::eq`. + let unsize = |ty: Ty<'tcx>| match ty.sty { + ty::Ref(region, rty, _) => match rty.sty { + ty::Array(inner_ty, n) => Some((region, inner_ty, n)), + _ => None, + }, + _ => None, + }; + let opt_ref_ty = unsize(ty); + let opt_ref_test_ty = unsize(value.ty); + match (opt_ref_ty, opt_ref_test_ty) { + // nothing to do, neither is an array + (None, None) => {}, + (Some((region, elem_ty, _)), _) | + (None, Some((region, elem_ty, _))) => { + let tcx = self.hir.tcx(); + // make both a slice + ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty)); + if opt_ref_ty.is_some() { + let temp = self.temp(ty, source_info.span); + self.cfg.push_assign( + block, source_info, &temp, Rvalue::Cast( + CastKind::Pointer(PointerCast::Unsize), val, ty + ) + ); + val = Operand::Move(temp); + } + if opt_ref_test_ty.is_some() { + let slice = self.temp(ty, source_info.span); + self.cfg.push_assign( + block, source_info, &slice, Rvalue::Cast( + CastKind::Pointer(PointerCast::Unsize), expect, ty + ) + ); + expect = Operand::Move(slice); + } + }, + } + + let deref_ty = match ty.sty { + ty::Ref(_, deref_ty, _) => deref_ty, + _ => bug!("non_scalar_compare called on non-reference type: {}", ty), + }; + + let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem); + let (mty, method) = self.hir.trait_method(eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]); + + let bool_ty = self.hir.bool_ty(); + let eq_result = self.temp(bool_ty, source_info.span); + let eq_block = self.cfg.start_new_block(); + let cleanup = self.diverge_cleanup(); + self.cfg.terminate(block, source_info, TerminatorKind::Call { + func: Operand::Constant(box Constant { + span: source_info.span, + ty: mty, + + // FIXME(#54571): This constant comes from user input (a + // constant in a pattern). Are there forms where users can add + // type annotations here? For example, an associated constant? + // Need to experiment. + user_ty: None, + + literal: method, + }), + args: vec![val, expect], + destination: Some((eq_result.clone(), eq_block)), + cleanup: Some(cleanup), + from_hir_call: false, + }); + + if let [success_block, fail_block] = *make_target_blocks(self) { + // check the result + self.cfg.terminate( + eq_block, + source_info, + TerminatorKind::if_( + self.hir.tcx(), + Operand::Move(eq_result), + success_block, + fail_block, + ), + ); + } else { + bug!("`TestKind::Eq` should have two target blocks") + } } /// Given that we are performing `test` against `test_place`, this job @@ -458,7 +508,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// that it *doesn't* apply. For now, we return false, indicate that the /// test does not apply to this candidate, but it might be we can get /// tighter match code if we do something a bit different. - pub fn sort_candidate<'pat, 'cand>( + pub fn sort_candidate<'pat>( &mut self, test_place: &Place<'tcx>, test: &Test<'tcx>, @@ -693,7 +743,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`, // we want to create a set of derived match-patterns like // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`. - let elem = ProjectionElem::Downcast(adt_def, variant_index); + let elem = ProjectionElem::Downcast( + Some(adt_def.variants[variant_index].ident.name), variant_index); let downcast_place = match_pair.place.elem(elem); // `(x as Variant)` let consequent_match_pairs = subpatterns.iter() @@ -717,7 +768,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn const_range_contains( &self, range: PatternRange<'tcx>, - value: ty::Const<'tcx>, + value: &'tcx ty::Const<'tcx>, ) -> Option { use std::cmp::Ordering::*; @@ -737,7 +788,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn values_not_contained_in_range( &self, range: PatternRange<'tcx>, - indices: &FxHashMap, usize>, + indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>, ) -> Option { for &val in indices.keys() { if self.const_range_contains(range, val)? { @@ -749,6 +800,32 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } +impl Test<'_> { + pub(super) fn targets(&self) -> usize { + match self.kind { + TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } => { + 2 + } + TestKind::Switch { adt_def, .. } => { + // While the switch that we generate doesn't test for all + // variants, we have a target for each variant and the + // otherwise case, and we make sure that all of the cases not + // specified have the same block. + adt_def.variants.len() + 1 + } + TestKind::SwitchInt { switch_ty, ref options, .. } => { + if switch_ty.is_bool() { + // `bool` is special cased in `perform_test` to always + // branch to two blocks. + 2 + } else { + options.len() + 1 + } + } + } + } +} + fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool { ty.is_integral() || ty.is_char() || ty.is_bool() } diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs index 3b90ff7884f01..011b3a8688837 100644 --- a/src/librustc_mir/build/matches/util.rs +++ b/src/librustc_mir/build/matches/util.rs @@ -5,7 +5,7 @@ use rustc::mir::*; use std::u32; use std::convert::TryInto; -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn field_match_pairs<'pat>(&mut self, place: Place<'tcx>, subpatterns: &'pat [FieldPattern<'tcx>]) @@ -65,6 +65,39 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }) ); } + + /// Creates a false edge to `imaginary_target` and a real edge to + /// real_target. If `imaginary_target` is none, or is the same as the real + /// target, a Goto is generated instead to simplify the generated MIR. + pub fn false_edges( + &mut self, + from_block: BasicBlock, + real_target: BasicBlock, + imaginary_target: Option, + source_info: SourceInfo, + ) { + match imaginary_target { + Some(target) if target != real_target => { + self.cfg.terminate( + from_block, + source_info, + TerminatorKind::FalseEdges { + real_target, + imaginary_target: target, + }, + ); + } + _ => { + self.cfg.terminate( + from_block, + source_info, + TerminatorKind::Goto { + target: real_target + } + ); + } + } + } } impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 2692c24806ff7..56025eeaaa922 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -8,7 +8,7 @@ use rustc::ty::{self, Ty}; use rustc::mir::*; use syntax_pos::{Span, DUMMY_SP}; -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Builder<'a, 'tcx> { /// Adds a new temporary value of type `ty` storing the result of /// evaluating `expr`. /// @@ -16,7 +16,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// call `schedule_drop` once the temporary is initialized. pub fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Place<'tcx> { let temp = self.local_decls.push(LocalDecl::new_temp(ty, span)); - let place = Place::Base(PlaceBase::Local(temp)); + let place = Place::from(temp); debug!("temp: created temp {:?} with type {:?}", place, self.local_decls[temp].ty); place @@ -27,13 +27,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn literal_operand(&mut self, span: Span, ty: Ty<'tcx>, - literal: ty::Const<'tcx>) + literal: &'tcx ty::Const<'tcx>) -> Operand<'tcx> { let constant = box Constant { span, ty, user_ty: None, - literal: self.hir.tcx().mk_lazy_const(ty::LazyConst::Evaluated(literal)), + literal, }; Operand::Constant(constant) } @@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> { let tcx = self.hir.tcx(); - let ty = place.ty(&self.local_decls, tcx).to_ty(tcx); + let ty = place.ty(&self.local_decls, tcx).ty; if !self.hir.type_is_copy_modulo_regions(ty, DUMMY_SP) { Operand::Move(place) } else { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index e4f85887841eb..fdc2473b04d09 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -1,8 +1,7 @@ use crate::build; -use crate::build::scope::{CachedBlock, DropKind}; +use crate::build::scope::DropKind; use crate::hair::cx::Cx; use crate::hair::{LintLevel, BindingMode, PatternKind}; -use crate::shim; use crate::transform::MirSource; use crate::util as mir_util; use rustc::hir; @@ -10,33 +9,24 @@ use rustc::hir::Node; use rustc::hir::def_id::DefId; use rustc::middle::region; use rustc::mir::*; -use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::subst::SubstsRef; -use rustc::util::nodemap::NodeMap; +use rustc::util::nodemap::HirIdMap; use rustc_target::spec::PanicStrategy; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -use std::mem; use std::u32; use rustc_target::spec::abi::Abi; -use syntax::ast; use syntax::attr::{self, UnwindAttr}; -use syntax::symbol::keywords; +use syntax::symbol::kw; use syntax_pos::Span; use super::lints; /// Construct the MIR for a given `DefId`. -pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'tcx> { - let id = tcx.hir().as_local_node_id(def_id).unwrap(); +pub fn mir_build<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Body<'tcx> { + let id = tcx.hir().as_local_hir_id(def_id).unwrap(); // Figure out what primary body this item has. let (body_id, return_ty_span) = match tcx.hir().get(id) { - Node::Variant(variant) => - return create_constructor_shim(tcx, id, &variant.node.data), - Node::StructCtor(ctor) => - return create_constructor_shim(tcx, id, ctor), - Node::Expr(hir::Expr { node: hir::ExprKind::Closure(_, decl, body_id, _, _), .. }) | Node::Item(hir::Item { node: hir::ItemKind::Fn(decl, _, _, body_id), .. }) | Node::ImplItem( @@ -65,22 +55,21 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t (*body_id, ty.span) } Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => { - (*body, tcx.hir().span_by_hir_id(*hir_id)) + (*body, tcx.hir().span(*hir_id)) } _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def_id), }; tcx.infer_ctxt().enter(|infcx| { - let fn_hir_id = tcx.hir().node_to_hir_id(id); - let cx = Cx::new(&infcx, fn_hir_id); - let mut mir = if cx.tables().tainted_by_errors { + let cx = Cx::new(&infcx, id); + let body = if cx.tables().tainted_by_errors { build::construct_error(cx, body_id) } else if cx.body_owner_kind.is_fn_or_closure() { // fetch the fully liberated fn signature (that is, all bound // types/lifetimes replaced) - let fn_sig = cx.tables().liberated_fn_sigs()[fn_hir_id].clone(); - let fn_def_id = tcx.hir().local_def_id(id); + let fn_sig = cx.tables().liberated_fn_sigs()[id].clone(); + let fn_def_id = tcx.hir().local_def_id_from_hir_id(id); let ty = tcx.type_of(fn_def_id); let mut abi = fn_sig.abi; @@ -92,7 +81,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t Some(ArgInfo(liberated_closure_env_ty(tcx, id, body_id), None, None, None)) } ty::Generator(..) => { - let gen_ty = tcx.body_tables(body_id).node_type(fn_hir_id); + let gen_ty = tcx.body_tables(body_id).node_type(id); Some(ArgInfo(gen_ty, None, None, None)) } _ => None, @@ -112,9 +101,9 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t let owner_id = tcx.hir().body_owner(body_id); let opt_ty_info; let self_arg; - if let Some(ref fn_decl) = tcx.hir().fn_decl(owner_id) { + if let Some(ref fn_decl) = tcx.hir().fn_decl_by_hir_id(owner_id) { let ty_hir_id = fn_decl.inputs[index].hir_id; - let ty_span = tcx.hir().span_by_hir_id(ty_hir_id); + let ty_span = tcx.hir().span(ty_hir_id); opt_ty_info = Some(ty_span); self_arg = if index == 0 && fn_decl.implicit_self.has_implicit_self() { match fn_decl.implicit_self { @@ -131,17 +120,19 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t opt_ty_info = None; self_arg = None; } + ArgInfo(fn_sig.inputs()[index], opt_ty_info, Some(&*arg.pat), self_arg) }); let arguments = implicit_argument.into_iter().chain(explicit_arguments); - let (yield_ty, return_ty) = if body.is_generator { + let (yield_ty, return_ty) = if body.generator_kind.is_some() { let gen_sig = match ty.sty { ty::Generator(gen_def_id, gen_substs, ..) => gen_substs.sig(gen_def_id, tcx), _ => - span_bug!(tcx.hir().span(id), "generator w/o generator type: {:?}", ty), + span_bug!(tcx.hir().span(id), + "generator w/o generator type: {:?}", ty), }; (Some(gen_sig.yield_ty), gen_sig.return_ty) } else { @@ -151,119 +142,41 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t build::construct_fn(cx, id, arguments, safety, abi, return_ty, yield_ty, return_ty_span, body) } else { - build::construct_const(cx, body_id, return_ty_span) - }; - - // Convert the Mir to global types. - let mut globalizer = GlobalizeMir { - tcx, - span: mir.span - }; - globalizer.visit_mir(&mut mir); - let mir = unsafe { - mem::transmute::, Mir<'tcx>>(mir) + // Get the revealed type of this const. This is *not* the adjusted + // type of its body, which may be a subtype of this type. For + // example: + // + // fn foo(_: &()) {} + // static X: fn(&'static ()) = foo; + // + // The adjusted type of the body of X is `for<'a> fn(&'a ())` which + // is not the same as the type of X. We need the type of the return + // place to be the type of the constant because NLL typeck will + // equate them. + + let return_ty = cx.tables().node_type(id); + + build::construct_const(cx, body_id, return_ty, return_ty_span) }; mir_util::dump_mir(tcx, None, "mir_map", &0, - MirSource::item(def_id), &mir, |_, _| Ok(()) ); + MirSource::item(def_id), &body, |_, _| Ok(()) ); - lints::check(tcx, &mir, def_id); + lints::check(tcx, &body, def_id); - mir + body }) } -/// A pass to lift all the types and substitutions in a MIR -/// to the global tcx. Sadly, we don't have a "folder" that -/// can change `'tcx` so we have to transmute afterwards. -struct GlobalizeMir<'a, 'gcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'gcx>, - span: Span -} - -impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> { - fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) { - if let Some(lifted) = self.tcx.lift(ty) { - *ty = lifted; - } else { - span_bug!(self.span, - "found type `{:?}` with inference types/regions in MIR", - ty); - } - } - - fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) { - if let Some(lifted) = self.tcx.lift(region) { - *region = lifted; - } else { - span_bug!(self.span, - "found region `{:?}` with inference types/regions in MIR", - region); - } - } - - fn visit_const(&mut self, constant: &mut &'tcx ty::LazyConst<'tcx>, _: Location) { - if let Some(lifted) = self.tcx.lift(constant) { - *constant = lifted; - } else { - span_bug!(self.span, - "found constant `{:?}` with inference types/regions in MIR", - constant); - } - } - - fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, _: Location) { - if let Some(lifted) = self.tcx.lift(substs) { - *substs = lifted; - } else { - span_bug!(self.span, - "found substs `{:?}` with inference types/regions in MIR", - substs); - } - } -} - -fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ctor_id: ast::NodeId, - v: &'tcx hir::VariantData) - -> Mir<'tcx> -{ - let span = tcx.hir().span(ctor_id); - if let hir::VariantData::Tuple(ref fields, ctor_id, _) = *v { - tcx.infer_ctxt().enter(|infcx| { - let mut mir = shim::build_adt_ctor(&infcx, ctor_id, fields, span); - - // Convert the Mir to global types. - let tcx = infcx.tcx.global_tcx(); - let mut globalizer = GlobalizeMir { - tcx, - span: mir.span - }; - globalizer.visit_mir(&mut mir); - let mir = unsafe { - mem::transmute::, Mir<'tcx>>(mir) - }; - - mir_util::dump_mir(tcx, None, "mir_map", &0, - MirSource::item(tcx.hir().local_def_id(ctor_id)), - &mir, |_, _| Ok(()) ); - - mir - }) - } else { - span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v); - } -} - /////////////////////////////////////////////////////////////////////////// // BuildMir -- walks a crate, looking for fn items and methods to build MIR from -fn liberated_closure_env_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - closure_expr_id: ast::NodeId, - body_id: hir::BodyId) - -> Ty<'tcx> { - let closure_expr_hir_id = tcx.hir().node_to_hir_id(closure_expr_id); - let closure_ty = tcx.body_tables(body_id).node_type(closure_expr_hir_id); +fn liberated_closure_env_ty<'tcx>( + tcx: TyCtxt<'tcx>, + closure_expr_id: hir::HirId, + body_id: hir::BodyId, +) -> Ty<'tcx> { + let closure_ty = tcx.body_tables(body_id).node_type(closure_expr_id); let (closure_def_id, closure_substs) = match closure_ty.sty { ty::Closure(closure_def_id, closure_substs) => (closure_def_id, closure_substs), @@ -279,9 +192,9 @@ pub enum BlockFrame { /// Evaluation is currently within a statement. /// /// Examples include: - /// 1. `EXPR;` - /// 2. `let _ = EXPR;` - /// 3. `let x = EXPR;` + /// 1. `EXPR;` + /// 2. `let _ = EXPR;` + /// 3. `let x = EXPR;` Statement { /// If true, then statement discards result from evaluating /// the expression (such as examples 1 and 2 above). @@ -328,16 +241,17 @@ impl BlockFrame { #[derive(Debug)] struct BlockContext(Vec); -struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - hir: Cx<'a, 'gcx, 'tcx>, +struct Builder<'a, 'tcx> { + hir: Cx<'a, 'tcx>, cfg: CFG<'tcx>, fn_span: Span, arg_count: usize, + is_generator: bool, /// The current set of scopes, updated as we traverse; /// see the `scope` module for more details. - scopes: Vec>, + scopes: scope::Scopes<'tcx>, /// The block-context: each time we build the code within an hair::Block, /// we push a frame here tracking whether we are building a statement or @@ -360,10 +274,6 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// The number of `push_unsafe_block` levels in scope. push_unsafe_count: usize, - /// The current set of breakables; see the `scope` module for more - /// details. - breakable_scopes: Vec>, - /// The vector of all scopes that we have created thus far; /// we track this for debuginfo later. source_scopes: IndexVec, @@ -375,12 +285,13 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// finish building it. guard_context: Vec, - /// Maps `NodeId`s of variable bindings to the `Local`s created for them. + /// Maps `HirId`s of variable bindings to the `Local`s created for them. /// (A match binding can have two locals; the 2nd is for the arm's guard.) - var_indices: NodeMap, + var_indices: HirIdMap, local_decls: IndexVec>, canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>, - upvar_decls: Vec, + __upvar_debuginfo_codegen_only_do_not_use: Vec, + upvar_mutbls: Vec, unit_temp: Option>, /// Cached block with the `RESUME` terminator; this is created @@ -392,12 +303,12 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { cached_unreachable_block: Option, } -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { - fn is_bound_var_in_guard(&self, id: ast::NodeId) -> bool { +impl<'a, 'tcx> Builder<'a, 'tcx> { + fn is_bound_var_in_guard(&self, id: hir::HirId) -> bool { self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id)) } - fn var_local_id(&self, id: ast::NodeId, for_guard: ForGuard) -> Local { + fn var_local_id(&self, id: hir::HirId, for_guard: ForGuard) -> Local { self.var_indices[&id].local_id(for_guard) } } @@ -453,7 +364,7 @@ impl BlockContext { #[derive(Debug)] enum LocalsForNode { - /// In the usual case, a `NodeId` for an identifier maps to at most + /// In the usual case, a `HirId` for an identifier maps to at most /// one `Local` declaration. One(Local), @@ -472,11 +383,11 @@ enum LocalsForNode { #[derive(Debug)] struct GuardFrameLocal { - id: ast::NodeId, + id: hir::HirId, } impl GuardFrameLocal { - fn new(id: ast::NodeId, _binding_mode: BindingMode) -> Self { + fn new(id: hir::HirId, _binding_mode: BindingMode) -> Self { GuardFrameLocal { id: id, } @@ -574,13 +485,14 @@ macro_rules! unpack { }; } -fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - fn_def_id: DefId, - abi: Abi) - -> bool { +fn should_abort_on_panic<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: DefId, abi: Abi) -> bool { // Not callable from C, so we can safely unwind through these if abi == Abi::Rust || abi == Abi::RustCall { return false; } + // Validate `#[unwind]` syntax regardless of platform-specific panic strategy + let attrs = &tcx.get_attrs(fn_def_id); + let unwind_attr = attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs); + // We never unwind, so it's not relevant to stop an unwind if tcx.sess.panic_strategy() != PanicStrategy::Unwind { return false; } @@ -589,9 +501,8 @@ fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // This is a special case: some functions have a C abi but are meant to // unwind anyway. Don't stop them. - let attrs = &tcx.get_attrs(fn_def_id); - match attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs) { - None => true, + match unwind_attr { + None => false, // FIXME(#58794) Some(UnwindAttr::Allowed) => false, Some(UnwindAttr::Aborts) => true, } @@ -600,22 +511,21 @@ fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, /////////////////////////////////////////////////////////////////////////// /// the main entry point for building MIR for a function -struct ArgInfo<'gcx>(Ty<'gcx>, - Option, - Option<&'gcx hir::Pat>, - Option); - -fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, - fn_id: ast::NodeId, - arguments: A, - safety: Safety, - abi: Abi, - return_ty: Ty<'gcx>, - yield_ty: Option>, - return_ty_span: Span, - body: &'gcx hir::Body) - -> Mir<'tcx> - where A: Iterator> +struct ArgInfo<'tcx>(Ty<'tcx>, Option, Option<&'tcx hir::Pat>, Option); + +fn construct_fn<'a, 'tcx, A>( + hir: Cx<'a, 'tcx>, + fn_id: hir::HirId, + arguments: A, + safety: Safety, + abi: Abi, + return_ty: Ty<'tcx>, + yield_ty: Option>, + return_ty_span: Span, + body: &'tcx hir::Body, +) -> Body<'tcx> +where + A: Iterator> { let arguments: Vec<_> = arguments.collect(); @@ -624,47 +534,46 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let span = tcx_hir.span(fn_id); let hir_tables = hir.tables(); - let fn_def_id = tcx_hir.local_def_id(fn_id); + let fn_def_id = tcx_hir.local_def_id_from_hir_id(fn_id); // Gather the upvars of a closure, if any. + let mut upvar_mutbls = vec![]; // In analyze_closure() in upvar.rs we gathered a list of upvars used by a // closure and we stored in a map called upvar_list in TypeckTables indexed // with the closure's DefId. Here, we run through that vec of UpvarIds for // the given closure and use the necessary information to create UpvarDecl. - let upvar_decls: Vec<_> = hir_tables + let upvar_debuginfo: Vec<_> = hir_tables .upvar_list .get(&fn_def_id) .into_iter() .flatten() - .map(|upvar_id| { - let var_hir_id = upvar_id.var_path.hir_id; - let var_node_id = tcx_hir.hir_to_node_id(var_hir_id); - let capture = hir_tables.upvar_capture(*upvar_id); + .map(|(&var_hir_id, &upvar_id)| { + let capture = hir_tables.upvar_capture(upvar_id); let by_ref = match capture { ty::UpvarCapture::ByValue => false, ty::UpvarCapture::ByRef(..) => true, }; - let mut decl = UpvarDecl { - debug_name: keywords::Invalid.name(), - var_hir_id: ClearCrossCrate::Set(var_hir_id), + let mut debuginfo = UpvarDebuginfo { + debug_name: kw::Invalid, by_ref, - mutability: Mutability::Not, }; - if let Some(Node::Binding(pat)) = tcx_hir.find(var_node_id) { - if let hir::PatKind::Binding(_, _, _, ident, _) = pat.node { - decl.debug_name = ident.name; + let mut mutability = Mutability::Not; + if let Some(Node::Binding(pat)) = tcx_hir.find(var_hir_id) { + if let hir::PatKind::Binding(_, _, ident, _) = pat.node { + debuginfo.debug_name = ident.name; if let Some(&bm) = hir.tables.pat_binding_modes().get(pat.hir_id) { if bm == ty::BindByValue(hir::MutMutable) { - decl.mutability = Mutability::Mut; + mutability = Mutability::Mut; } else { - decl.mutability = Mutability::Not; + mutability = Mutability::Not; } } else { tcx.sess.delay_span_bug(pat.span, "missing binding mode"); } } } - decl + upvar_mutbls.push(mutability); + debuginfo }) .collect(); @@ -674,7 +583,9 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, safety, return_ty, return_ty_span, - upvar_decls); + upvar_debuginfo, + upvar_mutbls, + body.generator_kind.is_some()); let call_site_scope = region::Scope { id: body.value.hir_id.local_id, @@ -687,13 +598,13 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let mut block = START_BLOCK; let source_info = builder.source_info(span); let call_site_s = (call_site_scope, source_info); - unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, block, |builder| { + unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, |builder| { if should_abort_on_panic(tcx, fn_def_id, abi) { builder.schedule_abort(); } let arg_scope_s = (arg_scope, source_info); - unpack!(block = builder.in_scope(arg_scope_s, LintLevel::Inherited, block, |builder| { + unpack!(block = builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { builder.args_and_body(block, &arguments, arg_scope, &body.value) })); // Attribute epilogue to function's closing brace @@ -718,28 +629,37 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, // RustCall pseudo-ABI untuples the last argument. spread_arg = Some(Local::new(arguments.len())); } - let closure_expr_id = tcx_hir.local_def_id(fn_id); - info!("fn_id {:?} has attrs {:?}", closure_expr_id, - tcx.get_attrs(closure_expr_id)); + info!("fn_id {:?} has attrs {:?}", fn_def_id, + tcx.get_attrs(fn_def_id)); - let mut mir = builder.finish(yield_ty); - mir.spread_arg = spread_arg; - mir + let mut body = builder.finish(yield_ty); + body.spread_arg = spread_arg; + body } -fn construct_const<'a, 'gcx, 'tcx>( - hir: Cx<'a, 'gcx, 'tcx>, +fn construct_const<'a, 'tcx>( + hir: Cx<'a, 'tcx>, body_id: hir::BodyId, - ty_span: Span, -) -> Mir<'tcx> { + const_ty: Ty<'tcx>, + const_ty_span: Span, +) -> Body<'tcx> { let tcx = hir.tcx(); - let ast_expr = &tcx.hir().body(body_id).value; - let ty = hir.tables().expr_ty_adjusted(ast_expr); let owner_id = tcx.hir().body_owner(body_id); let span = tcx.hir().span(owner_id); - let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, ty_span,vec![]); + let mut builder = Builder::new( + hir, + span, + 0, + Safety::Safe, + const_ty, + const_ty_span, + vec![], + vec![], + false, + ); let mut block = START_BLOCK; + let ast_expr = &tcx.hir().body(body_id).value; let expr = builder.hir.mirror(ast_expr); unpack!(block = builder.into_expr(&Place::RETURN_PLACE, block, expr)); @@ -759,34 +679,38 @@ fn construct_const<'a, 'gcx, 'tcx>( builder.finish(None) } -fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, - body_id: hir::BodyId) - -> Mir<'tcx> { +fn construct_error<'a, 'tcx>( + hir: Cx<'a, 'tcx>, + body_id: hir::BodyId +) -> Body<'tcx> { let owner_id = hir.tcx().hir().body_owner(body_id); let span = hir.tcx().hir().span(owner_id); let ty = hir.tcx().types.err; - let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, vec![]); + let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, vec![], vec![], false); let source_info = builder.source_info(span); builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); builder.finish(None) } -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { - fn new(hir: Cx<'a, 'gcx, 'tcx>, +impl<'a, 'tcx> Builder<'a, 'tcx> { + fn new(hir: Cx<'a, 'tcx>, span: Span, arg_count: usize, safety: Safety, return_ty: Ty<'tcx>, return_span: Span, - upvar_decls: Vec) - -> Builder<'a, 'gcx, 'tcx> { + __upvar_debuginfo_codegen_only_do_not_use: Vec, + upvar_mutbls: Vec, + is_generator: bool) + -> Builder<'a, 'tcx> { let lint_level = LintLevel::Explicit(hir.root_lint_level); let mut builder = Builder { hir, cfg: CFG { basic_blocks: IndexVec::new() }, fn_span: span, arg_count, - scopes: vec![], + is_generator, + scopes: Default::default(), block_context: BlockContext::new(), source_scopes: IndexVec::new(), source_scope: OUTERMOST_SOURCE_SCOPE, @@ -794,13 +718,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { guard_context: vec![], push_unsafe_count: 0, unpushed_unsafe: safety, - breakable_scopes: vec![], local_decls: IndexVec::from_elem_n( LocalDecl::new_return_place(return_ty, return_span), 1, ), canonical_user_type_annotations: IndexVec::new(), - upvar_decls, + __upvar_debuginfo_codegen_only_do_not_use, + upvar_mutbls, var_indices: Default::default(), unit_temp: None, cached_resume_block: None, @@ -819,14 +743,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn finish(self, yield_ty: Option>) - -> Mir<'tcx> { + -> Body<'tcx> { for (index, block) in self.cfg.basic_blocks.iter().enumerate() { if block.terminator.is_none() { span_bug!(self.fn_span, "no terminator on block {:?}", index); } } - Mir::new( + Body::new( self.cfg.basic_blocks, self.source_scopes, ClearCrossCrate::Set(self.source_scope_local_data), @@ -835,7 +759,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.local_decls, self.canonical_user_type_annotations, self.arg_count, - self.upvar_decls, + self.__upvar_debuginfo_codegen_only_do_not_use, self.fn_span, self.hir.control_flow_destroyed(), ) @@ -843,9 +767,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn args_and_body(&mut self, mut block: BasicBlock, - arguments: &[ArgInfo<'gcx>], + arguments: &[ArgInfo<'tcx>], argument_scope: region::Scope, - ast_body: &'gcx hir::Expr) + ast_body: &'tcx hir::Expr) -> BlockAnd<()> { // Allocate locals for the function arguments @@ -854,21 +778,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // debuginfo and so that error reporting knows that this is a user // variable. For any other pattern the pattern introduces new // variables which will be named instead. - let mut name = None; - if let Some(pat) = pattern { - match pat.node { - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, _, ident, _) - | hir::PatKind::Binding(hir::BindingAnnotation::Mutable, _, _, ident, _) => { - name = Some(ident.name); - } - _ => (), - } - } - - let source_info = SourceInfo { - scope: OUTERMOST_SOURCE_SCOPE, - span: pattern.map_or(self.fn_span, |pat| pat.span) + let (name, span) = if let Some(pat) = pattern { + (pat.simple_ident().map(|ident| ident.name), pat.span) + } else { + (None, self.fn_span) }; + + let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span, }; self.local_decls.push(LocalDecl { mutability: Mutability::Mut, ty, @@ -887,14 +803,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { for (index, arg_info) in arguments.iter().enumerate() { // Function arguments always get the first Local indices after the return place let local = Local::new(index + 1); - let place = Place::Base(PlaceBase::Local(local)); + let place = Place::from(local); let &ArgInfo(ty, opt_ty_info, pattern, ref self_binding) = arg_info; // Make sure we drop (parts of) the argument even when not matched on. self.schedule_drop( pattern.as_ref().map_or(ast_body.span, |pat| pat.span), - argument_scope, &place, ty, - DropKind::Value { cached_block: CachedBlock::default() }, + argument_scope, local, ty, DropKind::Value, ); if let Some(pattern) = pattern { @@ -903,7 +818,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { match *pattern.kind { // Don't introduce extra copies for simple bindings - PatternKind::Binding { mutability, var, mode: BindingMode::ByValue, .. } => { + PatternKind::Binding { + mutability, + var, + mode: BindingMode::ByValue, + subpattern: None, + .. + } => { self.local_decls[local].mutability = mutability; self.local_decls[local].is_user_variable = if let Some(kind) = self_binding { @@ -920,10 +841,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.var_indices.insert(var, LocalsForNode::One(local)); } _ => { - scope = self.declare_bindings(scope, ast_body.span, - LintLevel::Inherited, &pattern, - matches::ArmHasGuard(false), - Some((Some(&place), span))); + scope = self.declare_bindings( + scope, + ast_body.span, + &pattern, + matches::ArmHasGuard(false), + Some((Some(&place), span)), + ); unpack!(block = self.place_into_pattern(block, pattern, &place, false)); } } @@ -936,7 +860,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } let body = self.hir.mirror(ast_body); - self.into(&Place::RETURN_PLACE, block, body) + // `return_block` is called when we evaluate a `return` expression, so + // we just use `START_BLOCK` here. + self.in_breakable_scope(None, START_BLOCK, Place::RETURN_PLACE, |this| { + this.into(&Place::RETURN_PLACE, block, body) + }) } fn get_unit_temp(&mut self) -> Place<'tcx> { @@ -962,17 +890,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } } - - fn unreachable_block(&mut self) -> BasicBlock { - match self.cached_unreachable_block { - Some(ub) => ub, - None => { - let ub = self.cfg.start_new_block(); - self.cached_unreachable_block = Some(ub); - ub - } - } - } } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 4189e3e7ddbb6..1b5fa1c9770f1 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -19,13 +19,18 @@ paragraph). This is because region scopes are tied to them. Eventually, when we shift to non-lexical lifetimes, there should be no need to remember this mapping. -There is one additional wrinkle, actually, that I wanted to hide from -you but duty compels me to mention. In the course of building -matches, it sometimes happen that certain code (namely guards) gets -executed multiple times. This means that the scope lexical scope may -in fact correspond to multiple, disjoint SEME regions. So in fact our +### Not so SEME Regions + +In the course of building matches, it sometimes happens that certain code +(namely guards) gets executed multiple times. This means that the scope lexical +scope may in fact correspond to multiple, disjoint SEME regions. So in fact our mapping is from one scope to a vector of SEME regions. +Also in matches, the scopes assigned to arms are not even SEME regions! Each +arm has a single region with one entry for each pattern. We manually +manipulate the scheduled drops in this scope to avoid dropping things multiple +times, although drop elaboration would clean this up for value drops. + ### Drops The primary purpose for scopes is to insert drops: while building @@ -77,19 +82,19 @@ should go to. */ -use crate::build::{BlockAnd, BlockAndExtension, Builder, CFG}; -use crate::hair::LintLevel; +use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; +use crate::hair::{Expr, ExprRef, LintLevel}; use rustc::middle::region; use rustc::ty::Ty; use rustc::hir; -use rustc::hir::def_id::LOCAL_CRATE; use rustc::mir::*; -use syntax_pos::{Span}; +use syntax_pos::{DUMMY_SP, Span}; use rustc_data_structures::fx::FxHashMap; use std::collections::hash_map::Entry; +use std::mem; #[derive(Debug)] -pub struct Scope<'tcx> { +struct Scope { /// The source scope this scope was created in. source_scope: SourceScope, @@ -108,13 +113,15 @@ pub struct Scope<'tcx> { /// * polluting the cleanup MIR with StorageDead creates /// landing pads even though there's no actual destructors /// * freeing up stack space has no effect during unwinding + /// Note that for generators we do emit StorageDeads, for the + /// use of optimizations in the MIR generator transform. needs_cleanup: bool, /// set of places to drop when exiting this scope. This starts /// out empty but grows as variables are declared during the /// building process. This is a stack, so we always drop from the /// end of the vector (top of the stack) first. - drops: Vec>, + drops: Vec, /// The cache for drop chain on “normal” exit into a particular BasicBlock. cached_exits: FxHashMap<(BasicBlock, region::Scope), BasicBlock>, @@ -126,20 +133,30 @@ pub struct Scope<'tcx> { cached_unwind: CachedBlock, } +#[derive(Debug, Default)] +pub struct Scopes<'tcx> { + scopes: Vec, + /// The current set of breakable scopes. See module comment for more details. + breakable_scopes: Vec>, +} + #[derive(Debug)] -struct DropData<'tcx> { +struct DropData { /// span where drop obligation was incurred (typically where place was declared) span: Span, - /// place to drop - location: Place<'tcx>, + /// local to drop + local: Local, /// Whether this is a value Drop or a StorageDead. kind: DropKind, + + /// The cached blocks for unwinds. + cached_block: CachedBlock, } #[derive(Debug, Default, Clone, Copy)] -pub(crate) struct CachedBlock { +struct CachedBlock { /// The cached block for the cleanups-on-diverge path. This block /// contains code to run the current drop and all the preceding /// drops (i.e., those having lower index in Drop’s Scope drop @@ -157,24 +174,30 @@ pub(crate) struct CachedBlock { #[derive(Debug)] pub(crate) enum DropKind { - Value { - cached_block: CachedBlock, - }, - Storage + Value, + Storage, } #[derive(Clone, Debug)] -pub struct BreakableScope<'tcx> { +struct BreakableScope<'tcx> { /// Region scope of the loop - pub region_scope: region::Scope, + region_scope: region::Scope, /// Where the body of the loop begins. `None` if block - pub continue_block: Option, + continue_block: Option, /// Block to branch into when the loop or block terminates (either by being `break`-en out /// from, or by having its condition to become false) - pub break_block: BasicBlock, + break_block: BasicBlock, /// The destination of the loop/block expression itself (i.e., where to put the result of a /// `break` expression) - pub break_destination: Place<'tcx>, + break_destination: Place<'tcx>, +} + +/// The target of an expression that breaks out of a scope +#[derive(Clone, Copy, Debug)] +pub enum BreakableTarget { + Continue(region::Scope), + Break(region::Scope), + Return, } impl CachedBlock { @@ -200,16 +223,7 @@ impl CachedBlock { } } -impl DropKind { - fn may_panic(&self) -> bool { - match *self { - DropKind::Value { .. } => true, - DropKind::Storage => false - } - } -} - -impl<'tcx> Scope<'tcx> { +impl Scope { /// Invalidates all the cached blocks in the scope. /// /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a @@ -218,25 +232,24 @@ impl<'tcx> Scope<'tcx> { /// `storage_only` controls whether to invalidate only drop paths that run `StorageDead`. /// `this_scope_only` controls whether to invalidate only drop paths that refer to the current /// top-of-scope (as opposed to dependent scopes). - fn invalidate_cache(&mut self, storage_only: bool, this_scope_only: bool) { + fn invalidate_cache(&mut self, storage_only: bool, is_generator: bool, this_scope_only: bool) { // FIXME: maybe do shared caching of `cached_exits` etc. to handle functions // with lots of `try!`? // cached exits drop storage and refer to the top-of-scope self.cached_exits.clear(); - if !storage_only { - // the current generator drop and unwind ignore - // storage but refer to top-of-scope - self.cached_generator_drop = None; + // the current generator drop and unwind refer to top-of-scope + self.cached_generator_drop = None; + + let ignore_unwinds = storage_only && !is_generator; + if !ignore_unwinds { self.cached_unwind.invalidate(); } - if !storage_only && !this_scope_only { + if !ignore_unwinds && !this_scope_only { for drop_data in &mut self.drops { - if let DropKind::Value { ref mut cached_block } = drop_data.kind { - cached_block.invalidate(); - } + drop_data.cached_block.invalidate(); } } } @@ -250,43 +263,141 @@ impl<'tcx> Scope<'tcx> { } } -impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { +impl<'tcx> Scopes<'tcx> { + fn len(&self) -> usize { + self.scopes.len() + } + + fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo), vis_scope: SourceScope) { + debug!("push_scope({:?})", region_scope); + self.scopes.push(Scope { + source_scope: vis_scope, + region_scope: region_scope.0, + region_scope_span: region_scope.1.span, + needs_cleanup: false, + drops: vec![], + cached_generator_drop: None, + cached_exits: Default::default(), + cached_unwind: CachedBlock::default(), + }); + } + + fn pop_scope( + &mut self, + region_scope: (region::Scope, SourceInfo), + ) -> (Scope, Option) { + let scope = self.scopes.pop().unwrap(); + assert_eq!(scope.region_scope, region_scope.0); + let unwind_to = self.scopes.last() + .and_then(|next_scope| next_scope.cached_unwind.get(false)); + (scope, unwind_to) + } + + fn may_panic(&self, scope_count: usize) -> bool { + let len = self.len(); + self.scopes[(len - scope_count)..].iter().any(|s| s.needs_cleanup) + } + + /// Finds the breakable scope for a given label. This is used for + /// resolving `return`, `break` and `continue`. + fn find_breakable_scope( + &self, + span: Span, + target: BreakableTarget, + ) -> (BasicBlock, region::Scope, Option>) { + let get_scope = |scope: region::Scope| { + // find the loop-scope by its `region::Scope`. + self.breakable_scopes.iter() + .rfind(|breakable_scope| breakable_scope.region_scope == scope) + .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found")) + }; + match target { + BreakableTarget::Return => { + let scope = &self.breakable_scopes[0]; + if scope.break_destination != Place::RETURN_PLACE { + span_bug!(span, "`return` in item with no return scope"); + } + (scope.break_block, scope.region_scope, Some(scope.break_destination.clone())) + } + BreakableTarget::Break(scope) => { + let scope = get_scope(scope); + (scope.break_block, scope.region_scope, Some(scope.break_destination.clone())) + } + BreakableTarget::Continue(scope) => { + let scope = get_scope(scope); + let continue_block = scope.continue_block + .unwrap_or_else(|| span_bug!(span, "missing `continue` block")); + (continue_block, scope.region_scope, None) + } + } + } + + fn num_scopes_to(&self, region_scope: (region::Scope, SourceInfo), span: Span) -> usize { + let scope_count = 1 + self.scopes.iter().rev() + .position(|scope| scope.region_scope == region_scope.0) + .unwrap_or_else(|| { + span_bug!(span, "region_scope {:?} does not enclose", region_scope) + }); + let len = self.len(); + assert!(scope_count < len, "should not use `exit_scope` to pop ALL scopes"); + scope_count + } + + fn iter_mut(&mut self) -> impl DoubleEndedIterator + '_ { + self.scopes.iter_mut().rev() + } + + fn top_scopes(&mut self, count: usize) -> impl DoubleEndedIterator + '_ { + let len = self.len(); + self.scopes[len - count..].iter_mut() + } + + /// Returns the topmost active scope, which is known to be alive until + /// the next scope expression. + fn topmost(&self) -> region::Scope { + self.scopes.last().expect("topmost_scope: no scopes present").region_scope + } + + fn source_info(&self, index: usize, span: Span) -> SourceInfo { + self.scopes[self.len() - index].source_info(span) + } +} + +impl<'a, 'tcx> Builder<'a, 'tcx> { // Adding and removing scopes // ========================== - /// Start a breakable scope, which tracks where `continue` and `break` - /// should branch to. See module comment for more details. - /// - /// Returns the might_break attribute of the BreakableScope used. + // Start a breakable scope, which tracks where `continue`, `break` and + // `return` should branch to. pub fn in_breakable_scope(&mut self, loop_block: Option, break_block: BasicBlock, break_destination: Place<'tcx>, f: F) -> R - where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> R + where F: FnOnce(&mut Builder<'a, 'tcx>) -> R { - let region_scope = self.topmost_scope(); + let region_scope = self.scopes.topmost(); let scope = BreakableScope { region_scope, continue_block: loop_block, break_block, break_destination, }; - self.breakable_scopes.push(scope); + self.scopes.breakable_scopes.push(scope); let res = f(self); - let breakable_scope = self.breakable_scopes.pop().unwrap(); + let breakable_scope = self.scopes.breakable_scopes.pop().unwrap(); assert!(breakable_scope.region_scope == region_scope); res } pub fn in_opt_scope(&mut self, opt_scope: Option<(region::Scope, SourceInfo)>, - mut block: BasicBlock, f: F) -> BlockAnd - where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd + where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd { - debug!("in_opt_scope(opt_scope={:?}, block={:?})", opt_scope, block); + debug!("in_opt_scope(opt_scope={:?})", opt_scope); if let Some(region_scope) = opt_scope { self.push_scope(region_scope); } + let mut block; let rv = unpack!(block = f(self)); if let Some(region_scope) = opt_scope { unpack!(block = self.pop_scope(region_scope, block)); @@ -300,28 +411,37 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn in_scope(&mut self, region_scope: (region::Scope, SourceInfo), lint_level: LintLevel, - mut block: BasicBlock, f: F) -> BlockAnd - where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd + where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd { - debug!("in_scope(region_scope={:?}, block={:?})", region_scope, block); + debug!("in_scope(region_scope={:?})", region_scope); let source_scope = self.source_scope; let tcx = self.hir.tcx(); if let LintLevel::Explicit(current_hir_id) = lint_level { - let same_lint_scopes = tcx.dep_graph.with_ignore(|| { - let sets = tcx.lint_levels(LOCAL_CRATE); - let parent_hir_id = self.source_scope_local_data[source_scope].lint_root; - sets.lint_level_set(parent_hir_id) == sets.lint_level_set(current_hir_id) - }); - - if !same_lint_scopes { - self.source_scope = - self.new_source_scope(region_scope.1.span, lint_level, - None); + // Use `maybe_lint_level_root_bounded` with `root_lint_level` as a bound + // to avoid adding Hir dependences on our parents. + // We estimate the true lint roots here to avoid creating a lot of source scopes. + + let parent_root = tcx.maybe_lint_level_root_bounded( + self.source_scope_local_data[source_scope].lint_root, + self.hir.root_lint_level, + ); + let current_root = tcx.maybe_lint_level_root_bounded( + current_hir_id, + self.hir.root_lint_level + ); + + if parent_root != current_root { + self.source_scope = self.new_source_scope( + region_scope.1.span, + LintLevel::Explicit(current_root), + None + ); } } self.push_scope(region_scope); + let mut block; let rv = unpack!(block = f(self)); unpack!(block = self.pop_scope(region_scope, block)); self.source_scope = source_scope; @@ -334,18 +454,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// calls must be paired; using `in_scope` as a convenience /// wrapper maybe preferable. pub fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo)) { - debug!("push_scope({:?})", region_scope); - let vis_scope = self.source_scope; - self.scopes.push(Scope { - source_scope: vis_scope, - region_scope: region_scope.0, - region_scope_span: region_scope.1.span, - needs_cleanup: false, - drops: vec![], - cached_generator_drop: None, - cached_exits: Default::default(), - cached_unwind: CachedBlock::default(), - }); + self.scopes.push_scope(region_scope, self.source_scope); } /// Pops a scope, which should have region scope `region_scope`, @@ -358,20 +467,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("pop_scope({:?}, {:?})", region_scope, block); // If we are emitting a `drop` statement, we need to have the cached // diverge cleanup pads ready in case that drop panics. - let may_panic = - self.scopes.last().unwrap().drops.iter().any(|s| s.kind.may_panic()); - if may_panic { + if self.scopes.may_panic(1) { self.diverge_cleanup(); } - let scope = self.scopes.pop().unwrap(); - assert_eq!(scope.region_scope, region_scope.0); - - let unwind_to = self.scopes.last().and_then(|next_scope| { - next_scope.cached_unwind.get(false) - }).unwrap_or_else(|| self.resume_block()); + let (scope, unwind_to) = self.scopes.pop_scope(region_scope); + let unwind_to = unwind_to.unwrap_or_else(|| self.resume_block()); unpack!(block = build_scope_drops( &mut self.cfg, + self.is_generator, &scope, block, unwind_to, @@ -382,6 +486,37 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.unit() } + pub fn break_scope( + &mut self, + mut block: BasicBlock, + value: Option>, + scope: BreakableTarget, + source_info: SourceInfo, + ) -> BlockAnd<()> { + let (mut target_block, region_scope, destination) + = self.scopes.find_breakable_scope(source_info.span, scope); + if let BreakableTarget::Return = scope { + // We call this now, rather than when we start lowering the + // function so that the return block doesn't precede the entire + // rest of the CFG. Some passes and LLVM prefer blocks to be in + // approximately CFG order. + target_block = self.return_block(); + } + if let Some(destination) = destination { + if let Some(value) = value { + debug!("stmt_expr Break val block_context.push(SubExpr)"); + self.block_context.push(BlockFrame::SubExpr); + unpack!(block = self.into(&destination, block, value)); + self.block_context.pop(); + } else { + self.cfg.push_assign_unit(block, source_info, &destination) + } + } else { + assert!(value.is_none(), "`return` and `break` should have a destination"); + } + self.exit_scope(source_info.span, (region_scope, source_info), block, target_block); + self.cfg.start_new_block().unit() + } /// Branch out of `block` to `target`, exiting all scopes up to /// and including `region_scope`. This will insert whatever drops are @@ -393,22 +528,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { target: BasicBlock) { debug!("exit_scope(region_scope={:?}, block={:?}, target={:?})", region_scope, block, target); - let scope_count = 1 + self.scopes.iter().rev() - .position(|scope| scope.region_scope == region_scope.0) - .unwrap_or_else(|| { - span_bug!(span, "region_scope {:?} does not enclose", region_scope) - }); - let len = self.scopes.len(); - assert!(scope_count < len, "should not use `exit_scope` to pop ALL scopes"); + let scope_count = self.scopes.num_scopes_to(region_scope, span); // If we are emitting a `drop` statement, we need to have the cached // diverge cleanup pads ready in case that drop panics. - let may_panic = self.scopes[(len - scope_count)..].iter().any(|s| s.needs_cleanup); + let may_panic = self.scopes.may_panic(scope_count); if may_panic { self.diverge_cleanup(); } - let mut scopes = self.scopes[(len - scope_count - 1)..].iter_mut().rev(); + let mut scopes = self.scopes.top_scopes(scope_count + 1).rev(); let mut scope = scopes.next().unwrap(); for next_scope in scopes { if scope.drops.is_empty() { @@ -438,6 +567,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { unpack!(block = build_scope_drops( &mut self.cfg, + self.is_generator, scope, block, unwind_to, @@ -448,9 +578,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { scope = next_scope; } - let scope = &self.scopes[len - scope_count]; - self.cfg.terminate(block, scope.source_info(span), - TerminatorKind::Goto { target }); + let source_info = self.scopes.source_info(scope_count, span); + self.cfg.terminate(block, source_info, TerminatorKind::Goto { target }); } /// Creates a path that performs all required cleanup for dropping a generator. @@ -458,24 +587,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// This path terminates in GeneratorDrop. Returns the start of the path. /// None indicates there’s no cleanup to do at this point. pub fn generator_drop_cleanup(&mut self) -> Option { - if !self.scopes.iter().any(|scope| scope.needs_cleanup) { - return None; - } - // Fill in the cache for unwinds self.diverge_cleanup_gen(true); - let src_info = self.scopes[0].source_info(self.fn_span); + let src_info = self.scopes.source_info(self.scopes.len(), self.fn_span); let resume_block = self.resume_block(); - let mut scopes = self.scopes.iter_mut().rev().peekable(); + let mut scopes = self.scopes.iter_mut().peekable(); let mut block = self.cfg.start_new_block(); let result = block; while let Some(scope) = scopes.next() { - if !scope.needs_cleanup { - continue; - } - block = if let Some(b) = scope.cached_generator_drop { self.cfg.terminate(block, src_info, TerminatorKind::Goto { target: b }); @@ -496,6 +617,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { unpack!(block = build_scope_drops( &mut self.cfg, + self.is_generator, scope, block, unwind_to, @@ -536,22 +658,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { scope } - // Finding scopes - // ============== - /// Finds the breakable scope for a given label. This is used for - /// resolving `break` and `continue`. - pub fn find_breakable_scope(&self, - span: Span, - label: region::Scope) - -> &BreakableScope<'tcx> { - // find the loop-scope with the correct id - self.breakable_scopes.iter() - .rev() - .filter(|breakable_scope| breakable_scope.region_scope == label) - .next() - .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found")) - } - /// Given a span and the current source scope, make a SourceInfo. pub fn source_info(&self, span: Span) -> SourceInfo { SourceInfo { @@ -560,25 +666,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - /// Returns the `region::Scope` of the scope which should be exited by a - /// return. - pub fn region_scope_of_return_scope(&self) -> region::Scope { - // The outermost scope (`scopes[0]`) will be the `CallSiteScope`. - // We want `scopes[1]`, which is the `ParameterScope`. - assert!(self.scopes.len() >= 2); - assert!(match self.scopes[1].region_scope.data { - region::ScopeData::Arguments => true, - _ => false, - }); - self.scopes[1].region_scope - } - - /// Returns the topmost active scope, which is known to be alive until - /// the next scope expression. - pub fn topmost_scope(&self) -> region::Scope { - self.scopes.last().expect("topmost_scope: no scopes present").region_scope - } - + // Finding scopes + // ============== /// Returns the scope that we should use as the lifetime of an /// operand. Basically, an operand must live until it is consumed. /// This is similar to, but not quite the same as, the temporary @@ -609,41 +698,32 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { None, hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => - Some(self.topmost_scope()), + Some(self.scopes.topmost()), } } // Schedule an abort block - this is used for some ABIs that cannot unwind pub fn schedule_abort(&mut self) -> BasicBlock { - self.scopes[0].needs_cleanup = true; + let source_info = self.scopes.source_info(self.scopes.len(), self.fn_span); let abortblk = self.cfg.start_new_cleanup_block(); - let source_info = self.scopes[0].source_info(self.fn_span); self.cfg.terminate(abortblk, source_info, TerminatorKind::Abort); self.cached_resume_block = Some(abortblk); abortblk } + // Scheduling drops + // ================ pub fn schedule_drop_storage_and_value( &mut self, span: Span, region_scope: region::Scope, - place: &Place<'tcx>, + local: Local, place_ty: Ty<'tcx>, ) { - self.schedule_drop( - span, region_scope, place, place_ty, - DropKind::Storage, - ); - self.schedule_drop( - span, region_scope, place, place_ty, - DropKind::Value { - cached_block: CachedBlock::default(), - }, - ); + self.schedule_drop(span, region_scope, local, place_ty, DropKind::Storage); + self.schedule_drop(span, region_scope, local, place_ty, DropKind::Value); } - // Scheduling drops - // ================ /// Indicates that `place` should be dropped on exit from /// `region_scope`. /// @@ -653,30 +733,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { &mut self, span: Span, region_scope: region::Scope, - place: &Place<'tcx>, + local: Local, place_ty: Ty<'tcx>, drop_kind: DropKind, ) { let needs_drop = self.hir.needs_drop(place_ty); match drop_kind { - DropKind::Value { .. } => if !needs_drop { return }, + DropKind::Value => if !needs_drop { return }, DropKind::Storage => { - match *place { - Place::Base(PlaceBase::Local(index)) => if index.index() <= self.arg_count { - span_bug!( - span, "`schedule_drop` called with index {} and arg_count {}", - index.index(), - self.arg_count, - ) - }, - _ => span_bug!( - span, "`schedule_drop` called with non-`Local` place {:?}", place - ), + if local.index() <= self.arg_count { + span_bug!( + span, "`schedule_drop` called with local {:?} and arg_count {}", + local, + self.arg_count, + ) } } } - for scope in self.scopes.iter_mut().rev() { + for scope in self.scopes.iter_mut() { let this_scope = scope.region_scope == region_scope; // When building drops, we try to cache chains of drops in such a way so these drops // could be reused by the drops which would branch into the cached (already built) @@ -723,10 +798,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Note that this code iterates scopes from the inner-most to the outer-most, // invalidating caches of each scope visited. This way bare minimum of the // caches gets invalidated. i.e., if a new drop is added into the middle scope, the - // cache of outer scpoe stays intact. - scope.invalidate_cache(!needs_drop, this_scope); + // cache of outer scope stays intact. + scope.invalidate_cache(!needs_drop, self.is_generator, this_scope); if this_scope { - if let DropKind::Value { .. } = drop_kind { + if let DropKind::Value = drop_kind { scope.needs_cleanup = true; } @@ -737,17 +812,84 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { scope.drops.push(DropData { span: scope_end, - location: place.clone(), - kind: drop_kind + local, + kind: drop_kind, + cached_block: CachedBlock::default(), }); return; } } - span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, place); + span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local); } // Other // ===== + /// Branch based on a boolean condition. + /// + /// This is a special case because the temporary for the condition needs to + /// be dropped on both the true and the false arm. + pub fn test_bool( + &mut self, + mut block: BasicBlock, + condition: Expr<'tcx>, + source_info: SourceInfo, + ) -> (BasicBlock, BasicBlock) { + let cond = unpack!(block = self.as_local_operand(block, condition)); + let true_block = self.cfg.start_new_block(); + let false_block = self.cfg.start_new_block(); + let term = TerminatorKind::if_( + self.hir.tcx(), + cond.clone(), + true_block, + false_block, + ); + self.cfg.terminate(block, source_info, term); + + match cond { + // Don't try to drop a constant + Operand::Constant(_) => (), + // If constants and statics, we don't generate StorageLive for this + // temporary, so don't try to generate StorageDead for it either. + _ if self.local_scope().is_none() => (), + Operand::Copy(Place::Base(PlaceBase::Local(cond_temp))) + | Operand::Move(Place::Base(PlaceBase::Local(cond_temp))) => { + // Manually drop the condition on both branches. + let top_scope = self.scopes.scopes.last_mut().unwrap(); + let top_drop_data = top_scope.drops.pop().unwrap(); + + match top_drop_data.kind { + DropKind::Value { .. } => { + bug!("Drop scheduled on top of condition variable") + } + DropKind::Storage => { + let source_info = top_scope.source_info(top_drop_data.span); + let local = top_drop_data.local; + assert_eq!(local, cond_temp, "Drop scheduled on top of condition"); + self.cfg.push( + true_block, + Statement { + source_info, + kind: StatementKind::StorageDead(local) + }, + ); + self.cfg.push( + false_block, + Statement { + source_info, + kind: StatementKind::StorageDead(local) + }, + ); + } + } + + top_scope.invalidate_cache(true, self.is_generator, true); + } + _ => bug!("Expected as_local_operand to produce a temporary"), + } + + (true_block, false_block) + } + /// Creates a path that performs all required cleanup for unwinding. /// /// This path terminates in Resume. Returns the start of the path. @@ -785,42 +927,23 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // to left reading the cached results but never created anything. // Find the last cached block - let (mut target, first_uncached) = if let Some(cached_index) = self.scopes.iter() - .rposition(|scope| scope.cached_unwind.get(generator_drop).is_some()) { - (self.scopes[cached_index].cached_unwind.get(generator_drop).unwrap(), cached_index + 1) - } else { - (self.resume_block(), 0) - }; + debug!("diverge_cleanup_gen(self.scopes = {:?})", self.scopes); + let cached_cleanup = self.scopes.iter_mut().enumerate() + .find_map(|(idx, ref scope)| { + let cached_block = scope.cached_unwind.get(generator_drop)?; + Some((cached_block, idx)) + }); + let (mut target, first_uncached) = cached_cleanup + .unwrap_or_else(|| (self.resume_block(), self.scopes.len())); - for scope in self.scopes[first_uncached..].iter_mut() { + for scope in self.scopes.top_scopes(first_uncached) { target = build_diverge_scope(&mut self.cfg, scope.region_scope_span, - scope, target, generator_drop); + scope, target, generator_drop, self.is_generator); } target } - /// Utility function for *non*-scope code to build their own drops - pub fn build_drop(&mut self, - block: BasicBlock, - span: Span, - location: Place<'tcx>, - ty: Ty<'tcx>) -> BlockAnd<()> { - if !self.hir.needs_drop(ty) { - return block.unit(); - } - let source_info = self.source_info(span); - let next_target = self.cfg.start_new_block(); - let diverge_target = self.diverge_cleanup(); - self.cfg.terminate(block, source_info, - TerminatorKind::Drop { - location, - target: next_target, - unwind: Some(diverge_target), - }); - next_target.unit() - } - /// Utility function for *non*-scope code to build their own drops pub fn build_drop_and_replace(&mut self, block: BasicBlock, @@ -865,18 +988,34 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { success_block } + + // `match` arm scopes + // ================== + /// Unschedules any drops in the top scope. + /// + /// This is only needed for `match` arm scopes, because they have one + /// entrance per pattern, but only one exit. + pub(crate) fn clear_top_scope(&mut self, region_scope: region::Scope) { + let top_scope = self.scopes.scopes.last_mut().unwrap(); + + assert_eq!(top_scope.region_scope, region_scope); + + top_scope.drops.clear(); + top_scope.invalidate_cache(false, self.is_generator, true); + } } /// Builds drops for pop_scope and exit_scope. fn build_scope_drops<'tcx>( cfg: &mut CFG<'tcx>, - scope: &Scope<'tcx>, + is_generator: bool, + scope: &Scope, mut block: BasicBlock, last_unwind_to: BasicBlock, arg_count: usize, generator_drop: bool, ) -> BlockAnd<()> { - debug!("build_scope_drops({:?} -> {:?}", block, scope); + debug!("build_scope_drops({:?} -> {:?})", block, scope); // Build up the drops in evaluation order. The end result will // look like: @@ -890,71 +1029,74 @@ fn build_scope_drops<'tcx>( // The horizontal arrows represent the execution path when the drops return // successfully. The downwards arrows represent the execution path when the // drops panic (panicking while unwinding will abort, so there's no need for - // another set of arrows). The drops for the unwind path should have already - // been generated by `diverge_cleanup_gen`. + // another set of arrows). // - // The code in this function reads from right to left. - // Storage dead drops have to be done left to right (since we can only push - // to the end of a Vec). So, we find the next drop and then call - // push_storage_deads which will iterate backwards through them so that - // they are added in the correct order. - - let mut unwind_blocks = scope.drops.iter().rev().filter_map(|drop_data| { - if let DropKind::Value { cached_block } = drop_data.kind { - Some(cached_block.get(generator_drop).unwrap_or_else(|| { - span_bug!(drop_data.span, "cached block not present?") - })) - } else { - None - } - }); + // For generators, we unwind from a drop on a local to its StorageDead + // statement. For other functions we don't worry about StorageDead. The + // drops for the unwind path should have already been generated by + // `diverge_cleanup_gen`. - // When we unwind from a drop, we start cleaning up from the next one, so - // we don't need this block. - unwind_blocks.next(); - - for drop_data in scope.drops.iter().rev() { + for drop_idx in (0..scope.drops.len()).rev() { + let drop_data = &scope.drops[drop_idx]; let source_info = scope.source_info(drop_data.span); + let local = drop_data.local; match drop_data.kind { - DropKind::Value { .. } => { - let unwind_to = unwind_blocks.next().unwrap_or(last_unwind_to); + DropKind::Value => { + let unwind_to = get_unwind_to(scope, is_generator, drop_idx, generator_drop) + .unwrap_or(last_unwind_to); let next = cfg.start_new_block(); cfg.terminate(block, source_info, TerminatorKind::Drop { - location: drop_data.location.clone(), + location: local.into(), target: next, unwind: Some(unwind_to) }); block = next; } DropKind::Storage => { - // We do not need to emit StorageDead for generator drops - if generator_drop { - continue - } - - // Drop the storage for both value and storage drops. // Only temps and vars need their storage dead. - match drop_data.location { - Place::Base(PlaceBase::Local(index)) if index.index() > arg_count => { - cfg.push(block, Statement { - source_info, - kind: StatementKind::StorageDead(index) - }); - } - _ => unreachable!(), - } + assert!(local.index() > arg_count); + cfg.push(block, Statement { + source_info, + kind: StatementKind::StorageDead(local) + }); } } } block.unit() } +fn get_unwind_to( + scope: &Scope, + is_generator: bool, + unwind_from: usize, + generator_drop: bool, +) -> Option { + for drop_idx in (0..unwind_from).rev() { + let drop_data = &scope.drops[drop_idx]; + match (is_generator, &drop_data.kind) { + (true, DropKind::Storage) => { + return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| { + span_bug!(drop_data.span, "cached block not present for {:?}", drop_data) + })); + } + (false, DropKind::Value) => { + return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| { + span_bug!(drop_data.span, "cached block not present for {:?}", drop_data) + })); + } + _ => (), + } + } + None +} + fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>, span: Span, - scope: &mut Scope<'tcx>, + scope: &mut Scope, mut target: BasicBlock, - generator_drop: bool) + generator_drop: bool, + is_generator: bool) -> BasicBlock { // Build up the drops in **reverse** order. The end result will @@ -973,41 +1115,88 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>, scope: source_scope }; - // Next, build up the drops. Here we iterate the vector in + // We keep track of StorageDead statements to prepend to our current block + // and store them here, in reverse order. + let mut storage_deads = vec![]; + + let mut target_built_by_us = false; + + // Build up the drops. Here we iterate the vector in // *forward* order, so that we generate drops[0] first (right to // left in diagram above). + debug!("build_diverge_scope({:?})", scope.drops); for (j, drop_data) in scope.drops.iter_mut().enumerate() { debug!("build_diverge_scope drop_data[{}]: {:?}", j, drop_data); // Only full value drops are emitted in the diverging path, - // not StorageDead. + // not StorageDead, except in the case of generators. // // Note: This may not actually be what we desire (are we // "freeing" stack storage as we unwind, or merely observing a // frozen stack)? In particular, the intent may have been to // match the behavior of clang, but on inspection eddyb says // this is not what clang does. - let cached_block = match drop_data.kind { - DropKind::Value { ref mut cached_block } => cached_block.ref_mut(generator_drop), - DropKind::Storage => continue - }; - target = if let Some(cached_block) = *cached_block { - cached_block - } else { - let block = cfg.start_new_cleanup_block(); - cfg.terminate(block, source_info(drop_data.span), - TerminatorKind::Drop { - location: drop_data.location.clone(), - target, - unwind: None - }); - *cached_block = Some(block); - block + match drop_data.kind { + DropKind::Storage if is_generator => { + storage_deads.push(Statement { + source_info: source_info(drop_data.span), + kind: StatementKind::StorageDead(drop_data.local) + }); + if !target_built_by_us { + // We cannot add statements to an existing block, so we create a new + // block for our StorageDead statements. + let block = cfg.start_new_cleanup_block(); + let source_info = SourceInfo { span: DUMMY_SP, scope: source_scope }; + cfg.terminate(block, source_info, + TerminatorKind::Goto { target: target }); + target = block; + target_built_by_us = true; + } + *drop_data.cached_block.ref_mut(generator_drop) = Some(target); + } + DropKind::Storage => {} + DropKind::Value => { + let cached_block = drop_data.cached_block.ref_mut(generator_drop); + target = if let Some(cached_block) = *cached_block { + storage_deads.clear(); + target_built_by_us = false; + cached_block + } else { + push_storage_deads(cfg, target, &mut storage_deads); + let block = cfg.start_new_cleanup_block(); + cfg.terminate( + block, + source_info(drop_data.span), + TerminatorKind::Drop { + location: drop_data.local.into(), + target, + unwind: None + }, + ); + *cached_block = Some(block); + target_built_by_us = true; + block + }; + } }; } - + push_storage_deads(cfg, target, &mut storage_deads); *scope.cached_unwind.ref_mut(generator_drop) = Some(target); + assert!(storage_deads.is_empty()); debug!("build_diverge_scope({:?}, {:?}) = {:?}", scope, span, target); target } + +fn push_storage_deads(cfg: &mut CFG<'tcx>, + target: BasicBlock, + storage_deads: &mut Vec>) { + if storage_deads.is_empty() { return; } + let statements = &mut cfg.block_data_mut(target).statements; + storage_deads.reverse(); + debug!("push_storage_deads({:?}), storage_deads={:?}, statements={:?}", + target, storage_deads, statements); + storage_deads.append(statements); + mem::swap(statements, storage_deads); + assert!(storage_deads.is_empty()); +} diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 35ca13891876c..887ef4b520ea3 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -5,27 +5,26 @@ use std::error::Error; use std::borrow::{Borrow, Cow}; use std::hash::Hash; use std::collections::hash_map::Entry; +use std::convert::TryInto; -use rustc::hir::{self, def_id::DefId}; -use rustc::hir::def::Def; -use rustc::mir::interpret::{ConstEvalErr, ErrorHandled}; +use rustc::hir::def::DefKind; +use rustc::hir::def_id::DefId; +use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef}; use rustc::mir; use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{self, LayoutOf, VariantIdx}; use rustc::ty::subst::Subst; use rustc::traits::Reveal; use rustc_data_structures::fx::FxHashMap; -use rustc::util::common::ErrorReported; -use syntax::ast::Mutability; use syntax::source_map::{Span, DUMMY_SP}; use crate::interpret::{self, - PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Immediate, Scalar, Pointer, + PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar, RawConst, ConstValue, - EvalResult, EvalError, EvalErrorKind, GlobalId, EvalContext, StackPopCleanup, - Allocation, AllocId, MemoryKind, - snapshot, RefTracking, + InterpResult, InterpErrorInfo, InterpError, GlobalId, InterpretCx, StackPopCleanup, + Allocation, AllocId, MemoryKind, Memory, + snapshot, RefTracking, intern_const_alloc_recursive, }; /// Number of steps until the detector even starts doing anything. @@ -35,121 +34,134 @@ const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000; /// Should be a power of two for performance reasons. const DETECTOR_SNAPSHOT_PERIOD: isize = 256; -/// The `EvalContext` is only meant to be used to do field and index projections into constants for +/// The `InterpretCx` is only meant to be used to do field and index projections into constants for /// `simd_shuffle` and const patterns in match arms. /// /// The function containing the `match` that is currently being analyzed may have generic bounds /// that inform us about the generic bounds of the constant. E.g., using an associated constant /// of a function's generic parameter will require knowledge about the bounds on the generic /// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. -pub(crate) fn mk_eval_cx<'a, 'mir, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub(crate) fn mk_eval_cx<'mir, 'tcx>( + tcx: TyCtxt<'tcx>, span: Span, param_env: ty::ParamEnv<'tcx>, -) -> CompileTimeEvalContext<'a, 'mir, 'tcx> { +) -> CompileTimeEvalContext<'mir, 'tcx> { debug!("mk_eval_cx: {:?}", param_env); - EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new()) + InterpretCx::new(tcx.at(span), param_env, CompileTimeInterpreter::new()) } -pub(crate) fn eval_promoted<'a, 'mir, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub(crate) fn eval_promoted<'mir, 'tcx>( + tcx: TyCtxt<'tcx>, cid: GlobalId<'tcx>, - mir: &'mir mir::Mir<'tcx>, + body: &'mir mir::Body<'tcx>, param_env: ty::ParamEnv<'tcx>, -) -> EvalResult<'tcx, MPlaceTy<'tcx>> { +) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let span = tcx.def_span(cid.instance.def_id()); let mut ecx = mk_eval_cx(tcx, span, param_env); - eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env) -} - -fn mplace_to_const<'tcx>( - ecx: &CompileTimeEvalContext<'_, '_, 'tcx>, - mplace: MPlaceTy<'tcx>, -) -> EvalResult<'tcx, ty::Const<'tcx>> { - let MemPlace { ptr, align, meta } = *mplace; - // extract alloc-offset pair - assert!(meta.is_none()); - let ptr = ptr.to_ptr()?; - let alloc = ecx.memory.get(ptr.alloc_id)?; - assert!(alloc.align >= align); - assert!(alloc.bytes.len() as u64 - ptr.offset.bytes() >= mplace.layout.size.bytes()); - let mut alloc = alloc.clone(); - alloc.align = align; - // FIXME shouldn't it be the case that `mark_static_initialized` has already - // interned this? I thought that is the entire point of that `FinishStatic` stuff? - let alloc = ecx.tcx.intern_const_alloc(alloc); - let val = ConstValue::ByRef(ptr, alloc); - Ok(ty::Const { val, ty: mplace.layout.ty }) + eval_body_using_ecx(&mut ecx, cid, body, param_env) } fn op_to_const<'tcx>( - ecx: &CompileTimeEvalContext<'_, '_, 'tcx>, + ecx: &CompileTimeEvalContext<'_, 'tcx>, op: OpTy<'tcx>, -) -> EvalResult<'tcx, ty::Const<'tcx>> { - // We do not normalize just any data. Only scalar layout and slices. - let normalize = match op.layout.abi { +) -> &'tcx ty::Const<'tcx> { + // We do not have value optmizations for everything. + // Only scalars and slices, since they are very common. + // Note that further down we turn scalars of undefined bits back to `ByRef`. These can result + // from scalar unions that are initialized with one of their zero sized variants. We could + // instead allow `ConstValue::Scalar` to store `ScalarMaybeUndef`, but that would affect all + // the usual cases of extracting e.g. a `usize`, without there being a real use case for the + // `Undef` situation. + let try_as_immediate = match op.layout.abi { layout::Abi::Scalar(..) => true, - layout::Abi::ScalarPair(..) => op.layout.ty.is_slice(), + layout::Abi::ScalarPair(..) => match op.layout.ty.sty { + ty::Ref(_, inner, _) => match inner.sty { + ty::Slice(elem) => elem == ecx.tcx.types.u8, + ty::Str => true, + _ => false, + }, + _ => false, + }, _ => false, }; - let normalized_op = if normalize { - Err(*ecx.read_immediate(op).expect("normalization works on validated constants")) + let immediate = if try_as_immediate { + Err(ecx.read_immediate(op).expect("normalization works on validated constants")) } else { + // It is guaranteed that any non-slice scalar pair is actually ByRef here. + // When we come back from raw const eval, we are always by-ref. The only way our op here is + // by-val is if we are in const_field, i.e., if this is (a field of) something that we + // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or + // structs containing such. op.try_as_mplace() }; - let val = match normalized_op { - Ok(mplace) => return mplace_to_const(ecx, mplace), - Err(Immediate::Scalar(x)) => - ConstValue::Scalar(x.not_undef()?), - Err(Immediate::ScalarPair(a, b)) => - ConstValue::Slice(a.not_undef()?, b.to_usize(ecx)?), + let val = match immediate { + Ok(mplace) => { + let ptr = mplace.ptr.to_ptr().unwrap(); + let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); + ConstValue::ByRef { offset: ptr.offset, align: mplace.align, alloc } + }, + // see comment on `let try_as_immediate` above + Err(ImmTy { imm: Immediate::Scalar(x), .. }) => match x { + ScalarMaybeUndef::Scalar(s) => ConstValue::Scalar(s), + ScalarMaybeUndef::Undef => { + // When coming out of "normal CTFE", we'll always have an `Indirect` operand as + // argument and we will not need this. The only way we can already have an + // `Immediate` is when we are called from `const_field`, and that `Immediate` + // comes from a constant so it can happen have `Undef`, because the indirect + // memory that was read had undefined bytes. + let mplace = op.to_mem_place(); + let ptr = mplace.ptr.to_ptr().unwrap(); + let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); + ConstValue::ByRef { offset: ptr.offset, align: mplace.align, alloc } + }, + }, + Err(ImmTy { imm: Immediate::ScalarPair(a, b), .. }) => { + let (data, start) = match a.not_undef().unwrap() { + Scalar::Ptr(ptr) => ( + ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), + ptr.offset.bytes(), + ), + Scalar::Raw { .. } => ( + ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes( + b"" as &[u8], + )), + 0, + ), + }; + let len = b.to_usize(&ecx.tcx.tcx).unwrap(); + let start = start.try_into().unwrap(); + let len: usize = len.try_into().unwrap(); + ConstValue::Slice { + data, + start, + end: start + len, + } + }, }; - Ok(ty::Const { val, ty: op.layout.ty }) -} - -fn eval_body_and_ecx<'a, 'mir, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cid: GlobalId<'tcx>, - mir: Option<&'mir mir::Mir<'tcx>>, - param_env: ty::ParamEnv<'tcx>, -) -> (EvalResult<'tcx, MPlaceTy<'tcx>>, CompileTimeEvalContext<'a, 'mir, 'tcx>) { - // we start out with the best span we have - // and try improving it down the road when more information is available - let span = tcx.def_span(cid.instance.def_id()); - let span = mir.map(|mir| mir.span).unwrap_or(span); - let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new()); - let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env); - (r, ecx) + ecx.tcx.mk_const(ty::Const { val, ty: op.layout.ty }) } // Returns a pointer to where the result lives fn eval_body_using_ecx<'mir, 'tcx>( - ecx: &mut CompileTimeEvalContext<'_, 'mir, 'tcx>, + ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, cid: GlobalId<'tcx>, - mir: Option<&'mir mir::Mir<'tcx>>, + body: &'mir mir::Body<'tcx>, param_env: ty::ParamEnv<'tcx>, -) -> EvalResult<'tcx, MPlaceTy<'tcx>> { +) -> InterpResult<'tcx, MPlaceTy<'tcx>> { debug!("eval_body_using_ecx: {:?}, {:?}", cid, param_env); let tcx = ecx.tcx.tcx; - let mut mir = match mir { - Some(mir) => mir, - None => ecx.load_mir(cid.instance.def)?, - }; - if let Some(index) = cid.promoted { - mir = &mir.promoted[index]; - } - let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; + let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ret = ecx.allocate(layout, MemoryKind::Stack); - let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); + let name = ty::tls::with(|tcx| tcx.def_path_str(cid.instance.def_id())); let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom); - assert!(mir.arg_count == 0); + assert!(body.arg_count == 0); ecx.push_stack_frame( cid.instance, - mir.span, - mir, + body.span, + body, Some(ret.into()), StackPopCleanup::None { cleanup: false }, )?; @@ -158,22 +170,20 @@ fn eval_body_using_ecx<'mir, 'tcx>( ecx.run()?; // Intern the result - let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); - let is_static = tcx.is_static(cid.instance.def_id()); - let mutability = if is_static == Some(hir::Mutability::MutMutable) || internally_mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }; - ecx.memory.intern_static(ret.ptr.to_ptr()?.alloc_id, mutability)?; + intern_const_alloc_recursive( + ecx, + cid.instance.def_id(), + ret, + param_env, + )?; debug!("eval_body_using_ecx done: {:?}", *ret); Ok(ret) } -impl<'tcx> Into> for ConstEvalError { - fn into(self) -> EvalError<'tcx> { - EvalErrorKind::MachineError(self.to_string()).into() +impl<'tcx> Into> for ConstEvalError { + fn into(self) -> InterpErrorInfo<'tcx> { + InterpError::MachineError(self.to_string()).into() } } @@ -211,7 +221,7 @@ impl Error for ConstEvalError { } // Extra machine state for CTFE, and the Machine instance -pub struct CompileTimeInterpreter<'a, 'mir, 'tcx: 'a+'mir> { +pub struct CompileTimeInterpreter<'mir, 'tcx> { /// When this value is negative, it indicates the number of interpreter /// steps *until* the loop detector is enabled. When it is positive, it is /// the number of steps after the detector has been enabled modulo the loop @@ -219,10 +229,10 @@ pub struct CompileTimeInterpreter<'a, 'mir, 'tcx: 'a+'mir> { pub(super) steps_since_detector_enabled: isize, /// Extra state to detect loops. - pub(super) loop_detector: snapshot::InfiniteLoopDetector<'a, 'mir, 'tcx>, + pub(super) loop_detector: snapshot::InfiniteLoopDetector<'mir, 'tcx>, } -impl<'a, 'mir, 'tcx> CompileTimeInterpreter<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { fn new() -> Self { CompileTimeInterpreter { loop_detector: Default::default(), @@ -292,8 +302,8 @@ impl interpret::AllocMap for FxHashMap { } } -type CompileTimeEvalContext<'a, 'mir, 'tcx> = - EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>; +crate type CompileTimeEvalContext<'mir, 'tcx> = + InterpretCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>; impl interpret::MayLeak for ! { #[inline(always)] @@ -303,9 +313,7 @@ impl interpret::MayLeak for ! { } } -impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> - for CompileTimeInterpreter<'a, 'mir, 'tcx> -{ +impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> { type MemoryKinds = !; type PointerTag = (); @@ -318,17 +326,17 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> const STATIC_KIND: Option = None; // no copying of statics allowed #[inline(always)] - fn enforce_validity(_ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { + fn enforce_validity(_ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool { false // for now, we don't enforce validity } fn find_fn( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], dest: Option>, ret: Option, - ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { debug!("eval_fn_call: {:?}", instance); // Only check non-glue functions if let ty::InstanceDef::Item(def_id) = instance.def { @@ -349,9 +357,9 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> } // This is a const fn. Call it. Ok(Some(match ecx.load_mir(instance.def) { - Ok(mir) => mir, + Ok(body) => body, Err(err) => { - if let EvalErrorKind::NoMirFor(ref path) = err.kind { + if let InterpError::NoMirFor(ref path) = err.kind { return Err( ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) .into(), @@ -363,11 +371,11 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> } fn call_intrinsic( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], dest: PlaceTy<'tcx>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { if ecx.emulate_intrinsic(instance, args, dest)? { return Ok(()); } @@ -379,11 +387,11 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> } fn ptr_op( - _ecx: &EvalContext<'a, 'mir, 'tcx, Self>, + _ecx: &InterpretCx<'mir, 'tcx, Self>, _bin_op: mir::BinOp, _left: ImmTy<'tcx>, _right: ImmTy<'tcx>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool)> { Err( ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(), ) @@ -391,31 +399,40 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> fn find_foreign_static( _def_id: DefId, - _tcx: TyCtxtAt<'a, 'tcx, 'tcx>, - _memory_extra: &(), - ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { + _tcx: TyCtxtAt<'tcx>, + ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { err!(ReadForeignStatic) } #[inline(always)] - fn adjust_static_allocation<'b>( - alloc: &'b Allocation, - _memory_extra: &(), - ) -> Cow<'b, Allocation> { - // We do not use a tag so we can just cheaply forward the reference - Cow::Borrowed(alloc) + fn tag_allocation<'b>( + _id: AllocId, + alloc: Cow<'b, Allocation>, + _kind: Option>, + _memory: &Memory<'mir, 'tcx, Self>, + ) -> (Cow<'b, Allocation>, Self::PointerTag) { + // We do not use a tag so we can just cheaply forward the allocation + (alloc, ()) + } + + #[inline(always)] + fn tag_static_base_pointer( + _id: AllocId, + _memory: &Memory<'mir, 'tcx, Self>, + ) -> Self::PointerTag { + () } fn box_alloc( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _ecx: &mut InterpretCx<'mir, 'tcx, Self>, _dest: PlaceTy<'tcx>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { Err( ConstEvalError::NeedsRfc("heap allocations via `box` keyword".to_string()).into(), ) } - fn before_terminator(ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> { + fn before_terminator(ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { { let steps = &mut ecx.machine.steps_since_detector_enabled; @@ -432,7 +449,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> let span = ecx.frame().span; ecx.machine.loop_detector.observe_and_analyze( - &ecx.tcx, + *ecx.tcx, span, &ecx.memory, &ecx.stack[..], @@ -440,84 +457,67 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> } #[inline(always)] - fn tag_new_allocation( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ptr: Pointer, - _kind: MemoryKind, - ) -> Pointer { - ptr - } - - #[inline(always)] - fn stack_push( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ) -> EvalResult<'tcx> { + fn stack_push(_ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { Ok(()) } /// Called immediately before a stack frame gets popped. #[inline(always)] - fn stack_pop( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - _extra: (), - ) -> EvalResult<'tcx> { + fn stack_pop(_ecx: &mut InterpretCx<'mir, 'tcx, Self>, _extra: ()) -> InterpResult<'tcx> { Ok(()) } } -/// Projects to a field of a (variant of a) const. -pub fn const_field<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +/// Extracts a field of a (variant of a) const. +// this function uses `unwrap` copiously, because an already validated constant must have valid +// fields and can thus never fail outside of compiler bugs +pub fn const_field<'tcx>( + tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, variant: Option, field: mir::Field, - value: ty::Const<'tcx>, -) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { + value: &'tcx ty::Const<'tcx>, +) -> &'tcx ty::Const<'tcx> { trace!("const_field: {:?}, {:?}", field, value); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env); - let result = (|| { - // get the operand again - let op = ecx.const_to_op(value, None)?; - // downcast - let down = match variant { - None => op, - Some(variant) => ecx.operand_downcast(op, variant)? - }; - // then project - let field = ecx.operand_field(down, field.index() as u64)?; - // and finally move back to the const world, always normalizing because - // this is not called for statics. - op_to_const(&ecx, field) - })(); - result.map_err(|error| { - let err = error_to_const_error(&ecx, error); - err.report_as_error(ecx.tcx, "could not access field of constant"); - ErrorHandled::Reported - }) + // get the operand again + let op = ecx.eval_const_to_op(value, None).unwrap(); + // downcast + let down = match variant { + None => op, + Some(variant) => ecx.operand_downcast(op, variant).unwrap(), + }; + // then project + let field = ecx.operand_field(down, field.index() as u64).unwrap(); + // and finally move back to the const world, always normalizing because + // this is not called for statics. + op_to_const(&ecx, field) } -pub fn const_variant_index<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +// this function uses `unwrap` copiously, because an already validated constant must have valid +// fields and can thus never fail outside of compiler bugs +pub fn const_variant_index<'tcx>( + tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - val: ty::Const<'tcx>, -) -> EvalResult<'tcx, VariantIdx> { + val: &'tcx ty::Const<'tcx>, +) -> VariantIdx { trace!("const_variant_index: {:?}", val); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env); - let op = ecx.const_to_op(val, None)?; - Ok(ecx.read_discriminant(op)?.1) + let op = ecx.eval_const_to_op(val, None).unwrap(); + ecx.read_discriminant(op).unwrap().1 } -pub fn error_to_const_error<'a, 'mir, 'tcx>( - ecx: &EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>, - mut error: EvalError<'tcx> +pub fn error_to_const_error<'mir, 'tcx>( + ecx: &InterpretCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, + mut error: InterpErrorInfo<'tcx>, ) -> ConstEvalErr<'tcx> { error.print_backtrace(); let stacktrace = ecx.generate_stacktrace(None); ConstEvalErr { error: error.kind, stacktrace, span: ecx.tcx.span } } -fn validate_and_turn_into_const<'a, 'tcx>( - tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, +fn validate_and_turn_into_const<'tcx>( + tcx: TyCtxt<'tcx>, constant: RawConst<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { @@ -531,15 +531,24 @@ fn validate_and_turn_into_const<'a, 'tcx>( mplace.into(), path, Some(&mut ref_tracking), - true, // const mode )?; } // Now that we validated, turn this into a proper constant. + // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides + // whether they become immediates. let def_id = cid.instance.def.def_id(); - if tcx.is_static(def_id).is_some() || cid.promoted.is_some() { - mplace_to_const(&ecx, mplace) + if tcx.is_static(def_id) || cid.promoted.is_some() { + let ptr = mplace.ptr.to_ptr()?; + Ok(tcx.mk_const(ty::Const { + val: ConstValue::ByRef { + offset: ptr.offset, + align: mplace.align, + alloc: ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), + }, + ty: mplace.layout.ty, + })) } else { - op_to_const(&ecx, mplace.into()) + Ok(op_to_const(&ecx, mplace.into())) } })(); @@ -559,8 +568,8 @@ fn validate_and_turn_into_const<'a, 'tcx>( }) } -pub fn const_eval_provider<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn const_eval_provider<'tcx>( + tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { // see comment in const_eval_provider for what we're doing here @@ -583,8 +592,8 @@ pub fn const_eval_provider<'a, 'tcx>( }) } -pub fn const_eval_raw_provider<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn const_eval_raw_provider<'tcx>( + tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc::mir::interpret::ConstEvalRawResult<'tcx> { // Because the constant is computed twice (once per value of `Reveal`), we are at risk of @@ -605,38 +614,36 @@ pub fn const_eval_raw_provider<'a, 'tcx>( other => return other, } } - // the first trace is for replicating an ice - // There's no tracking issue, but the next two lines concatenated link to the discussion on - // zulip. It's not really possible to test this, because it doesn't show up in diagnostics - // or MIR. - // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/ - // subject/anon_const_instance_printing/near/135980032 - trace!("const eval: {}", key.value.instance); - trace!("const eval: {:?}", key); + if cfg!(debug_assertions) { + // Make sure we format the instance even if we do not print it. + // This serves as a regression test against an ICE on printing. + // The next two lines concatenated contain some discussion: + // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/ + // subject/anon_const_instance_printing/near/135980032 + let instance = key.value.instance.to_string(); + trace!("const eval: {:?} ({})", key, instance); + } let cid = key.value; let def_id = cid.instance.def.def_id(); - if let Some(id) = tcx.hir().as_local_node_id(def_id) { - let tables = tcx.typeck_tables_of(def_id); - - // Do match-check before building MIR - if let Err(ErrorReported) = tcx.check_match(def_id) { - return Err(ErrorHandled::Reported) - } + if def_id.is_local() && tcx.typeck_tables_of(def_id).tainted_by_errors { + return Err(ErrorHandled::Reported); + } - if let hir::BodyOwnerKind::Const = tcx.hir().body_owner_kind(id) { - tcx.mir_const_qualif(def_id); - } + let span = tcx.def_span(cid.instance.def_id()); + let mut ecx = InterpretCx::new(tcx.at(span), key.param_env, CompileTimeInterpreter::new()); - // Do not continue into miri if typeck errors occurred; it will fail horribly - if tables.tainted_by_errors { - return Err(ErrorHandled::Reported) + let res = ecx.load_mir(cid.instance.def); + res.map(|body| { + if let Some(index) = cid.promoted { + &body.promoted[index] + } else { + body } - }; - - let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env); - res.and_then(|place| { + }).and_then( + |body| eval_body_using_ecx(&mut ecx, cid, body, key.param_env) + ).and_then(|place| { Ok(RawConst { alloc_id: place.to_ptr().expect("we allocated this ptr!").alloc_id, ty: place.layout.ty @@ -644,39 +651,38 @@ pub fn const_eval_raw_provider<'a, 'tcx>( }).map_err(|error| { let err = error_to_const_error(&ecx, error); // errors in statics are always emitted as fatal errors - if tcx.is_static(def_id).is_some() { - let reported_err = err.report_as_error(ecx.tcx, - "could not evaluate static initializer"); + if tcx.is_static(def_id) { // Ensure that if the above error was either `TooGeneric` or `Reported` // an error must be reported. - if tcx.sess.err_count() == 0 { - tcx.sess.delay_span_bug(err.span, - &format!("static eval failure did not emit an error: {:#?}", - reported_err)); - } - reported_err + let v = err.report_as_error(ecx.tcx, "could not evaluate static initializer"); + tcx.sess.delay_span_bug( + err.span, + &format!("static eval failure did not emit an error: {:#?}", v) + ); + v } else if def_id.is_local() { // constant defined in this crate, we can figure out a lint level! - match tcx.describe_def(def_id) { + match tcx.def_kind(def_id) { // constants never produce a hard error at the definition site. Anything else is // a backwards compatibility hazard (and will break old versions of winapi for sure) // // note that validation may still cause a hard error on this very same constant, // because any code that existed before validation could not have failed validation // thus preventing such a hard error from being a backwards compatibility hazard - Some(Def::Const(_)) | Some(Def::AssociatedConst(_)) => { + Some(DefKind::Const) | Some(DefKind::AssocConst) => { let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); err.report_as_lint( tcx.at(tcx.def_span(def_id)), "any use of this value will cause an error", hir_id, + Some(err.span), ) }, // promoting runtime code is only allowed to error if it references broken constants // any other kind of error will be reported to the user as a deny-by-default lint _ => if let Some(p) = cid.promoted { let span = tcx.optimized_mir(def_id).promoted[p].span; - if let EvalErrorKind::ReferencedConstant = err.error { + if let InterpError::ReferencedConstant = err.error { err.report_as_error( tcx.at(span), "evaluation of constant expression failed", @@ -686,6 +692,7 @@ pub fn const_eval_raw_provider<'a, 'tcx>( tcx.at(span), "reaching this expression at runtime will panic or abort", tcx.hir().as_local_hir_id(def_id).unwrap(), + Some(err.span), ) } // anything else (array lengths, enum initializers, constant patterns) are reported diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs index d43fa4257e06c..f0014602e2d6b 100644 --- a/src/librustc_mir/dataflow/at_location.rs +++ b/src/librustc_mir/dataflow/at_location.rs @@ -4,10 +4,11 @@ use rustc::mir::{BasicBlock, Location}; use rustc_data_structures::bit_set::{BitIter, BitSet, HybridBitSet}; -use crate::dataflow::{BitDenotation, BlockSets, DataflowResults}; +use crate::dataflow::{BitDenotation, DataflowResults, GenKillSet}; use crate::dataflow::move_paths::{HasMoveData, MovePathIndex}; use std::iter; +use std::borrow::Borrow; /// A trait for "cartesian products" of multiple FlowAtLocation. /// @@ -60,19 +61,20 @@ pub trait FlowsAtLocation { /// (e.g., via `reconstruct_statement_effect` and /// `reconstruct_terminator_effect`; don't forget to call /// `apply_local_effect`). -pub struct FlowAtLocation<'tcx, BD> +pub struct FlowAtLocation<'tcx, BD, DR = DataflowResults<'tcx, BD>> where BD: BitDenotation<'tcx>, + DR: Borrow>, { - base_results: DataflowResults<'tcx, BD>, + base_results: DR, curr_state: BitSet, - stmt_gen: HybridBitSet, - stmt_kill: HybridBitSet, + stmt_trans: GenKillSet, } -impl<'tcx, BD> FlowAtLocation<'tcx, BD> +impl<'tcx, BD, DR> FlowAtLocation<'tcx, BD, DR> where BD: BitDenotation<'tcx>, + DR: Borrow>, { /// Iterate over each bit set in the current state. pub fn each_state_bit(&self, f: F) @@ -89,25 +91,23 @@ where where F: FnMut(BD::Idx), { - self.stmt_gen.iter().for_each(f) + self.stmt_trans.gen_set.iter().for_each(f) } - pub fn new(results: DataflowResults<'tcx, BD>) -> Self { - let bits_per_block = results.sets().bits_per_block(); + pub fn new(results: DR) -> Self { + let bits_per_block = results.borrow().sets().bits_per_block(); let curr_state = BitSet::new_empty(bits_per_block); - let stmt_gen = HybridBitSet::new_empty(bits_per_block); - let stmt_kill = HybridBitSet::new_empty(bits_per_block); + let stmt_trans = GenKillSet::from_elem(HybridBitSet::new_empty(bits_per_block)); FlowAtLocation { base_results: results, - curr_state: curr_state, - stmt_gen: stmt_gen, - stmt_kill: stmt_kill, + curr_state, + stmt_trans, } } /// Access the underlying operator. pub fn operator(&self) -> &BD { - self.base_results.operator() + self.base_results.borrow().operator() } pub fn contains(&self, x: BD::Idx) -> bool { @@ -127,85 +127,69 @@ where F: FnOnce(BitIter<'_, BD::Idx>), { let mut curr_state = self.curr_state.clone(); - curr_state.union(&self.stmt_gen); - curr_state.subtract(&self.stmt_kill); + self.stmt_trans.apply(&mut curr_state); f(curr_state.iter()); } + + /// Returns a bitset of the elements present in the current state. + pub fn as_dense(&self) -> &BitSet { + &self.curr_state + } } -impl<'tcx, BD> FlowsAtLocation for FlowAtLocation<'tcx, BD> - where BD: BitDenotation<'tcx> +impl<'tcx, BD, DR> FlowsAtLocation for FlowAtLocation<'tcx, BD, DR> +where + BD: BitDenotation<'tcx>, + DR: Borrow>, { fn reset_to_entry_of(&mut self, bb: BasicBlock) { - self.curr_state.overwrite(self.base_results.sets().on_entry_set_for(bb.index())); + self.curr_state.overwrite(self.base_results.borrow().sets().entry_set_for(bb.index())); } fn reset_to_exit_of(&mut self, bb: BasicBlock) { self.reset_to_entry_of(bb); - self.curr_state.union(self.base_results.sets().gen_set_for(bb.index())); - self.curr_state.subtract(self.base_results.sets().kill_set_for(bb.index())); + let trans = self.base_results.borrow().sets().trans_for(bb.index()); + trans.apply(&mut self.curr_state) } fn reconstruct_statement_effect(&mut self, loc: Location) { - self.stmt_gen.clear(); - self.stmt_kill.clear(); - { - let mut sets = BlockSets { - on_entry: &mut self.curr_state, - gen_set: &mut self.stmt_gen, - kill_set: &mut self.stmt_kill, - }; - self.base_results - .operator() - .before_statement_effect(&mut sets, loc); - } - self.apply_local_effect(loc); + self.stmt_trans.clear(); + self.base_results + .borrow() + .operator() + .before_statement_effect(&mut self.stmt_trans, loc); + self.stmt_trans.apply(&mut self.curr_state); - let mut sets = BlockSets { - on_entry: &mut self.curr_state, - gen_set: &mut self.stmt_gen, - kill_set: &mut self.stmt_kill, - }; self.base_results + .borrow() .operator() - .statement_effect(&mut sets, loc); + .statement_effect(&mut self.stmt_trans, loc); } fn reconstruct_terminator_effect(&mut self, loc: Location) { - self.stmt_gen.clear(); - self.stmt_kill.clear(); - { - let mut sets = BlockSets { - on_entry: &mut self.curr_state, - gen_set: &mut self.stmt_gen, - kill_set: &mut self.stmt_kill, - }; - self.base_results - .operator() - .before_terminator_effect(&mut sets, loc); - } - self.apply_local_effect(loc); + self.stmt_trans.clear(); + self.base_results + .borrow() + .operator() + .before_terminator_effect(&mut self.stmt_trans, loc); + self.stmt_trans.apply(&mut self.curr_state); - let mut sets = BlockSets { - on_entry: &mut self.curr_state, - gen_set: &mut self.stmt_gen, - kill_set: &mut self.stmt_kill, - }; self.base_results + .borrow() .operator() - .terminator_effect(&mut sets, loc); + .terminator_effect(&mut self.stmt_trans, loc); } fn apply_local_effect(&mut self, _loc: Location) { - self.curr_state.union(&self.stmt_gen); - self.curr_state.subtract(&self.stmt_kill); + self.stmt_trans.apply(&mut self.curr_state) } } -impl<'tcx, T> FlowAtLocation<'tcx, T> +impl<'tcx, T, DR> FlowAtLocation<'tcx, T, DR> where T: HasMoveData<'tcx> + BitDenotation<'tcx, Idx = MovePathIndex>, + DR: Borrow>, { pub fn has_any_child_of(&self, mpi: T::Idx) -> Option { // We process `mpi` before the loop below, for two reasons: diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index f78c82a93020c..a73ec2ed8e06a 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -1,4 +1,4 @@ -use rustc::mir::{self, Mir, Location}; +use rustc::mir::{self, Body, Location}; use rustc::ty::{self, TyCtxt}; use crate::util::elaborate_drops::DropFlagState; @@ -10,7 +10,7 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, path: MovePathIndex, mut cond: F) -> Option - where F: FnMut(&mir::PlaceProjection<'tcx>) -> bool + where F: FnMut(&mir::Projection<'tcx>) -> bool { let mut next_child = move_data.move_paths[path].first_child; while let Some(child_index) = next_child { @@ -46,10 +46,12 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, /// is no need to maintain separate drop flags to track such state. // // FIXME: we have to do something for moving slice patterns. -fn place_contents_drop_state_cannot_differ<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &Mir<'tcx>, - place: &mir::Place<'tcx>) -> bool { - let ty = place.ty(mir, tcx).to_ty(tcx); +fn place_contents_drop_state_cannot_differ<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + place: &mir::Place<'tcx>, +) -> bool { + let ty = place.ty(body, tcx).ty; match ty.sty { ty::Array(..) => { debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false", @@ -72,80 +74,84 @@ fn place_contents_drop_state_cannot_differ<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, } } -pub(crate) fn on_lookup_result_bits<'a, 'gcx, 'tcx, F>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &Mir<'tcx>, +pub(crate) fn on_lookup_result_bits<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, move_data: &MoveData<'tcx>, lookup_result: LookupResult, - each_child: F) - where F: FnMut(MovePathIndex) + each_child: F, +) where + F: FnMut(MovePathIndex), { match lookup_result { LookupResult::Parent(..) => { // access to untracked value - do not touch children } LookupResult::Exact(e) => { - on_all_children_bits(tcx, mir, move_data, e, each_child) + on_all_children_bits(tcx, body, move_data, e, each_child) } } } -pub(crate) fn on_all_children_bits<'a, 'gcx, 'tcx, F>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &Mir<'tcx>, +pub(crate) fn on_all_children_bits<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, move_data: &MoveData<'tcx>, move_path_index: MovePathIndex, - mut each_child: F) - where F: FnMut(MovePathIndex) + mut each_child: F, +) where + F: FnMut(MovePathIndex), { - fn is_terminal_path<'a, 'gcx, 'tcx>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &Mir<'tcx>, + fn is_terminal_path<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, move_data: &MoveData<'tcx>, - path: MovePathIndex) -> bool - { + path: MovePathIndex, + ) -> bool { place_contents_drop_state_cannot_differ( - tcx, mir, &move_data.move_paths[path].place) + tcx, body, &move_data.move_paths[path].place) } - fn on_all_children_bits<'a, 'gcx, 'tcx, F>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &Mir<'tcx>, + fn on_all_children_bits<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, move_data: &MoveData<'tcx>, move_path_index: MovePathIndex, - each_child: &mut F) - where F: FnMut(MovePathIndex) + each_child: &mut F, + ) where + F: FnMut(MovePathIndex), { each_child(move_path_index); - if is_terminal_path(tcx, mir, move_data, move_path_index) { + if is_terminal_path(tcx, body, move_data, move_path_index) { return } let mut next_child_index = move_data.move_paths[move_path_index].first_child; while let Some(child_index) = next_child_index { - on_all_children_bits(tcx, mir, move_data, child_index, each_child); + on_all_children_bits(tcx, body, move_data, child_index, each_child); next_child_index = move_data.move_paths[child_index].next_sibling; } } - on_all_children_bits(tcx, mir, move_data, move_path_index, &mut each_child); + on_all_children_bits(tcx, body, move_data, move_path_index, &mut each_child); } -pub(crate) fn on_all_drop_children_bits<'a, 'gcx, 'tcx, F>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &Mir<'tcx>, - ctxt: &MoveDataParamEnv<'gcx, 'tcx>, +pub(crate) fn on_all_drop_children_bits<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + ctxt: &MoveDataParamEnv<'tcx>, path: MovePathIndex, - mut each_child: F) - where F: FnMut(MovePathIndex) + mut each_child: F, +) where + F: FnMut(MovePathIndex), { - on_all_children_bits(tcx, mir, &ctxt.move_data, path, |child| { + on_all_children_bits(tcx, body, &ctxt.move_data, path, |child| { let place = &ctxt.move_data.move_paths[path].place; - let ty = place.ty(mir, tcx).to_ty(tcx); + let ty = place.ty(body, tcx).ty; debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty); let gcx = tcx.global_tcx(); - let erased_ty = gcx.lift(&tcx.erase_regions(&ty)).unwrap(); + let erased_ty = tcx.erase_regions(&ty); if erased_ty.needs_drop(gcx, ctxt.param_env) { each_child(child); } else { @@ -154,30 +160,32 @@ pub(crate) fn on_all_drop_children_bits<'a, 'gcx, 'tcx, F>( }) } -pub(crate) fn drop_flag_effects_for_function_entry<'a, 'gcx, 'tcx, F>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &Mir<'tcx>, - ctxt: &MoveDataParamEnv<'gcx, 'tcx>, - mut callback: F) - where F: FnMut(MovePathIndex, DropFlagState) +pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + ctxt: &MoveDataParamEnv<'tcx>, + mut callback: F, +) where + F: FnMut(MovePathIndex, DropFlagState), { let move_data = &ctxt.move_data; - for arg in mir.args_iter() { - let place = mir::Place::Base(mir::PlaceBase::Local(arg)); + for arg in body.args_iter() { + let place = mir::Place::from(arg); let lookup_result = move_data.rev_lookup.find(&place); - on_lookup_result_bits(tcx, mir, move_data, + on_lookup_result_bits(tcx, body, move_data, lookup_result, |mpi| callback(mpi, DropFlagState::Present)); } } -pub(crate) fn drop_flag_effects_for_location<'a, 'gcx, 'tcx, F>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &Mir<'tcx>, - ctxt: &MoveDataParamEnv<'gcx, 'tcx>, +pub(crate) fn drop_flag_effects_for_location<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + ctxt: &MoveDataParamEnv<'tcx>, loc: Location, - mut callback: F) - where F: FnMut(MovePathIndex, DropFlagState) + mut callback: F, +) where + F: FnMut(MovePathIndex, DropFlagState), { let move_data = &ctxt.move_data; debug!("drop_flag_effects_for_location({:?})", loc); @@ -187,7 +195,7 @@ pub(crate) fn drop_flag_effects_for_location<'a, 'gcx, 'tcx, F>( let path = mi.move_path_index(move_data); debug!("moving out of path {:?}", move_data.move_paths[path]); - on_all_children_bits(tcx, mir, move_data, + on_all_children_bits(tcx, body, move_data, path, |mpi| callback(mpi, DropFlagState::Absent)) } @@ -196,20 +204,21 @@ pub(crate) fn drop_flag_effects_for_location<'a, 'gcx, 'tcx, F>( for_location_inits( tcx, - mir, + body, move_data, loc, |mpi| callback(mpi, DropFlagState::Present) ); } -pub(crate) fn for_location_inits<'a, 'gcx, 'tcx, F>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &Mir<'tcx>, +pub(crate) fn for_location_inits<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, move_data: &MoveData<'tcx>, loc: Location, - mut callback: F) - where F: FnMut(MovePathIndex) + mut callback: F, +) where + F: FnMut(MovePathIndex), { for ii in &move_data.init_loc_map[loc] { let init = move_data.inits[*ii]; @@ -217,7 +226,7 @@ pub(crate) fn for_location_inits<'a, 'gcx, 'tcx, F>( InitKind::Deep => { let path = init.path; - on_all_children_bits(tcx, mir, move_data, + on_all_children_bits(tcx, body, move_data, path, &mut callback) }, diff --git a/src/librustc_mir/dataflow/graphviz.rs b/src/librustc_mir/dataflow/graphviz.rs index c7f6983be6192..b0d8581784606 100644 --- a/src/librustc_mir/dataflow/graphviz.rs +++ b/src/librustc_mir/dataflow/graphviz.rs @@ -1,21 +1,23 @@ //! Hook into libgraphviz for rendering dataflow graphs for MIR. -use syntax::ast::NodeId; -use rustc::mir::{BasicBlock, Mir}; +use rustc::hir::def_id::DefId; +use rustc::mir::{BasicBlock, Body}; use std::fs; use std::io; use std::marker::PhantomData; use std::path::Path; +use crate::util::graphviz_safe_def_name; + use super::{BitDenotation, DataflowState}; use super::DataflowBuilder; use super::DebugFormatted; pub trait MirWithFlowState<'tcx> { type BD: BitDenotation<'tcx>; - fn node_id(&self) -> NodeId; - fn mir(&self) -> &Mir<'tcx>; + fn def_id(&self) -> DefId; + fn body(&self) -> &Body<'tcx>; fn flow_state(&self) -> &DataflowState<'tcx, Self::BD>; } @@ -23,12 +25,12 @@ impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation<'tcx> { type BD = BD; - fn node_id(&self) -> NodeId { self.node_id } - fn mir(&self) -> &Mir<'tcx> { self.flow_state.mir() } + fn def_id(&self) -> DefId { self.def_id } + fn body(&self) -> &Body<'tcx> { self.flow_state.body() } fn flow_state(&self) -> &DataflowState<'tcx, Self::BD> { &self.flow_state.flow_state } } -struct Graph<'a, 'tcx, MWF:'a, P> where +struct Graph<'a, 'tcx, MWF, P> where MWF: MirWithFlowState<'tcx> { mbcx: &'a MWF, @@ -47,8 +49,8 @@ pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>( let g = Graph { mbcx, phantom: PhantomData, render_idx }; let mut v = Vec::new(); dot::render(&g, &mut v)?; - debug!("print_borrowck_graph_to path: {} node_id: {}", - path.display(), mbcx.node_id); + debug!("print_borrowck_graph_to path: {} def_id: {:?}", + path.display(), mbcx.def_id); fs::write(path, v) } @@ -57,8 +59,8 @@ pub type Node = BasicBlock; #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Edge { source: BasicBlock, index: usize } -fn outgoing(mir: &Mir<'_>, bb: BasicBlock) -> Vec { - (0..mir[bb].terminator().successors().count()) +fn outgoing(body: &Body<'_>, bb: BasicBlock) -> Vec { + (0..body[bb].terminator().successors().count()) .map(|index| Edge { source: bb, index: index}).collect() } @@ -69,9 +71,8 @@ impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P> type Node = Node; type Edge = Edge; fn graph_id(&self) -> dot::Id<'_> { - dot::Id::new(format!("graph_for_node_{}", - self.mbcx.node_id())) - .unwrap() + let name = graphviz_safe_def_name(self.mbcx.def_id()); + dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap() } fn node_id(&self, n: &Node) -> dot::Id<'_> { @@ -98,7 +99,7 @@ impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P> // | [00-00] | _7 = const Foo::twiddle(move _8) | [0c-00] | [f3-0f] | // +---------+----------------------------------+------------------+------------------+ let mut v = Vec::new(); - self.node_label_internal(n, &mut v, *n, self.mbcx.mir()).unwrap(); + self.node_label_internal(n, &mut v, *n, self.mbcx.body()).unwrap(); dot::LabelText::html(String::from_utf8(v).unwrap()) } @@ -108,7 +109,7 @@ impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P> } fn edge_label(&'a self, e: &Edge) -> dot::LabelText<'a> { - let term = self.mbcx.mir()[e.source].terminator(); + let term = self.mbcx.body()[e.source].terminator(); let label = &term.kind.fmt_successor_labels()[e.index]; dot::LabelText::label(label.clone()) } @@ -123,7 +124,7 @@ where MWF: MirWithFlowState<'tcx>, n: &Node, w: &mut W, block: BasicBlock, - mir: &Mir<'_>) -> io::Result<()> { + body: &Body<'_>) -> io::Result<()> { // Header rows const HDRS: [&str; 4] = ["ENTRY", "MIR", "BLOCK GENS", "BLOCK KILLS"]; const HDR_FMT: &str = "bgcolor=\"grey\""; @@ -136,8 +137,8 @@ where MWF: MirWithFlowState<'tcx>, write!(w, "")?; // Data row - self.node_label_verbose_row(n, w, block, mir)?; - self.node_label_final_row(n, w, block, mir)?; + self.node_label_verbose_row(n, w, block, body)?; + self.node_label_final_row(n, w, block, body)?; write!(w, "")?; Ok(()) @@ -148,7 +149,7 @@ where MWF: MirWithFlowState<'tcx>, n: &Node, w: &mut W, block: BasicBlock, - mir: &Mir<'_>) + body: &Body<'_>) -> io::Result<()> { let i = n.index(); @@ -169,12 +170,12 @@ where MWF: MirWithFlowState<'tcx>, write!(w, "")?; // Entry - dump_set_for!(on_entry_set_for, interpret_set); + dump_set_for!(entry_set_for, interpret_set); // MIR statements write!(w, "")?; { - let data = &mir[block]; + let data = &body[block]; for (i, statement) in data.statements.iter().enumerate() { write!(w, "{}
", dot::escape_html(&format!("{:3}: {:?}", i, statement)))?; @@ -198,7 +199,7 @@ where MWF: MirWithFlowState<'tcx>, n: &Node, w: &mut W, block: BasicBlock, - mir: &Mir<'_>) + body: &Body<'_>) -> io::Result<()> { let i = n.index(); @@ -207,26 +208,23 @@ where MWF: MirWithFlowState<'tcx>, write!(w, "")?; // Entry - let set = flow.sets.on_entry_set_for(i); + let set = flow.sets.entry_set_for(i); write!(w, "{:?}", dot::escape_html(&set.to_string()))?; // Terminator write!(w, "")?; { - let data = &mir[block]; + let data = &body[block]; let mut terminator_head = String::new(); data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); write!(w, "{}", dot::escape_html(&terminator_head))?; } write!(w, "")?; - // Gen - let set = flow.sets.gen_set_for(i); - write!(w, "{:?}", dot::escape_html(&format!("{:?}", set)))?; - - // Kill - let set = flow.sets.kill_set_for(i); - write!(w, "{:?}", dot::escape_html(&format!("{:?}", set)))?; + // Gen/Kill + let trans = flow.sets.trans_for(i); + write!(w, "{:?}", dot::escape_html(&format!("{:?}", trans.gen_set)))?; + write!(w, "{:?}", dot::escape_html(&format!("{:?}", trans.kill_set)))?; write!(w, "")?; @@ -240,7 +238,7 @@ impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P> type Node = Node; type Edge = Edge; fn nodes(&self) -> dot::Nodes<'_, Node> { - self.mbcx.mir() + self.mbcx.body() .basic_blocks() .indices() .collect::>() @@ -248,11 +246,11 @@ impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P> } fn edges(&self) -> dot::Edges<'_, Edge> { - let mir = self.mbcx.mir(); + let body = self.mbcx.body(); - mir.basic_blocks() + body.basic_blocks() .indices() - .flat_map(|bb| outgoing(mir, bb)) + .flat_map(|bb| outgoing(body, bb)) .collect::>() .into() } @@ -262,7 +260,7 @@ impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P> } fn target(&self, edge: &Edge) -> Node { - let mir = self.mbcx.mir(); - *mir[edge.source].terminator().successors().nth(edge.index).unwrap() + let body = self.mbcx.body(); + *body[edge.source].terminator().successors().nth(edge.index).unwrap() } } diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs index b9c8879b3c364..0f7f37f2db8b4 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -2,7 +2,7 @@ pub use super::*; use rustc::mir::*; use rustc::mir::visit::Visitor; -use crate::dataflow::BitDenotation; +use crate::dataflow::{BitDenotation, GenKillSet}; /// This calculates if any part of a MIR local could have previously been borrowed. /// This means that once a local has been borrowed, its bit will be set @@ -11,18 +11,18 @@ use crate::dataflow::BitDenotation; /// This is used to compute which locals are live during a yield expression for /// immovable generators. #[derive(Copy, Clone)] -pub struct HaveBeenBorrowedLocals<'a, 'tcx: 'a> { - mir: &'a Mir<'tcx>, +pub struct HaveBeenBorrowedLocals<'a, 'tcx> { + body: &'a Body<'tcx>, } -impl<'a, 'tcx: 'a> HaveBeenBorrowedLocals<'a, 'tcx> { - pub fn new(mir: &'a Mir<'tcx>) +impl<'a, 'tcx> HaveBeenBorrowedLocals<'a, 'tcx> { + pub fn new(body: &'a Body<'tcx>) -> Self { - HaveBeenBorrowedLocals { mir } + HaveBeenBorrowedLocals { body } } - pub fn mir(&self) -> &Mir<'tcx> { - self.mir + pub fn body(&self) -> &Body<'tcx> { + self.body } } @@ -30,35 +30,46 @@ impl<'a, 'tcx> BitDenotation<'tcx> for HaveBeenBorrowedLocals<'a, 'tcx> { type Idx = Local; fn name() -> &'static str { "has_been_borrowed_locals" } fn bits_per_block(&self) -> usize { - self.mir.local_decls.len() + self.body.local_decls.len() } - fn start_block_effect(&self, _sets: &mut BitSet) { + fn start_block_effect(&self, _on_entry: &mut BitSet) { // Nothing is borrowed on function entry } fn statement_effect(&self, - sets: &mut BlockSets<'_, Local>, + trans: &mut GenKillSet, loc: Location) { - let stmt = &self.mir[loc.block].statements[loc.statement_index]; + let stmt = &self.body[loc.block].statements[loc.statement_index]; BorrowedLocalsVisitor { - sets, - }.visit_statement(loc.block, stmt, loc); + trans, + }.visit_statement(stmt, loc); // StorageDead invalidates all borrows and raw pointers to a local match stmt.kind { - StatementKind::StorageDead(l) => sets.kill(l), + StatementKind::StorageDead(l) => trans.kill(l), _ => (), } } fn terminator_effect(&self, - sets: &mut BlockSets<'_, Local>, + trans: &mut GenKillSet, loc: Location) { + let terminator = self.body[loc.block].terminator(); BorrowedLocalsVisitor { - sets, - }.visit_terminator(loc.block, self.mir[loc.block].terminator(), loc); + trans, + }.visit_terminator(terminator, loc); + match &terminator.kind { + // Drop terminators borrows the location + TerminatorKind::Drop { location, .. } | + TerminatorKind::DropAndReplace { location, .. } => { + if let Some(local) = find_local(location) { + trans.gen(local); + } + } + _ => (), + } } fn propagate_call_return( @@ -72,45 +83,38 @@ impl<'a, 'tcx> BitDenotation<'tcx> for HaveBeenBorrowedLocals<'a, 'tcx> { } } -impl<'a, 'tcx> BitSetOperator for HaveBeenBorrowedLocals<'a, 'tcx> { - #[inline] - fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool { - inout_set.union(in_set) // "maybe" means we union effects of both preds - } -} - -impl<'a, 'tcx> InitialFlow for HaveBeenBorrowedLocals<'a, 'tcx> { - #[inline] - fn bottom_value() -> bool { - false // bottom = unborrowed - } +impl<'a, 'tcx> BottomValue for HaveBeenBorrowedLocals<'a, 'tcx> { + // bottom = unborrowed + const BOTTOM_VALUE: bool = false; } -struct BorrowedLocalsVisitor<'b, 'c: 'b> { - sets: &'b mut BlockSets<'c, Local>, +struct BorrowedLocalsVisitor<'gk> { + trans: &'gk mut GenKillSet, } fn find_local<'tcx>(place: &Place<'tcx>) -> Option { - match *place { - Place::Base(PlaceBase::Local(l)) => Some(l), - Place::Base(PlaceBase::Promoted(_)) | - Place::Base(PlaceBase::Static(..)) => None, - Place::Projection(ref proj) => { - match proj.elem { - ProjectionElem::Deref => None, - _ => find_local(&proj.base) + place.iterate(|place_base, place_projection| { + for proj in place_projection { + if proj.elem == ProjectionElem::Deref { + return None; } } - } + + if let PlaceBase::Local(local) = place_base { + Some(*local) + } else { + None + } + }) } -impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> { +impl<'tcx> Visitor<'tcx> for BorrowedLocalsVisitor<'_> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Ref(_, _, ref place) = *rvalue { if let Some(local) = find_local(place) { - self.sets.gen(local); + self.trans.gen(local); } } diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index b47aff3a4f855..dcc6ba5ca05cc 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -1,22 +1,27 @@ use crate::borrow_check::borrow_set::{BorrowSet, BorrowData}; use crate::borrow_check::place_ext::PlaceExt; -use rustc::mir::{self, Location, Place, PlaceBase, Mir}; +use rustc::mir::{self, Location, Place, PlaceBase, Body}; use rustc::ty::TyCtxt; use rustc::ty::RegionVid; -use rustc_data_structures::bit_set::{BitSet, BitSetOperator}; +use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use crate::dataflow::{BitDenotation, BlockSets, InitialFlow}; -pub use crate::dataflow::indexes::BorrowIndex; +use crate::dataflow::{BitDenotation, BottomValue, GenKillSet}; use crate::borrow_check::nll::region_infer::RegionInferenceContext; use crate::borrow_check::nll::ToRegionVid; use crate::borrow_check::places_conflict; use std::rc::Rc; +newtype_index! { + pub struct BorrowIndex { + DEBUG_FORMAT = "bw{}" + } +} + /// `Borrows` stores the data used in the analyses that track the flow /// of borrows. /// @@ -24,9 +29,9 @@ use std::rc::Rc; /// `BorrowIndex`, and maps each such index to a `BorrowData` /// describing the borrow. These indexes are used for representing the /// borrows in compact bitvectors. -pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, +pub struct Borrows<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, borrow_set: Rc>, borrows_out_of_scope_at_location: FxHashMap>, @@ -43,7 +48,7 @@ struct StackEntry { } fn precompute_borrows_out_of_scope<'tcx>( - mir: &Mir<'tcx>, + body: &Body<'tcx>, regioncx: &Rc>, borrows_out_of_scope_at_location: &mut FxHashMap>, borrow_index: BorrowIndex, @@ -67,7 +72,7 @@ fn precompute_borrows_out_of_scope<'tcx>( stack.push(StackEntry { bb: location.block, lo: location.statement_index, - hi: mir[location.block].statements.len(), + hi: body[location.block].statements.len(), first_part_only: false, }); @@ -90,7 +95,7 @@ fn precompute_borrows_out_of_scope<'tcx>( if !finished_early { // Add successor BBs to the work list, if necessary. - let bb_data = &mir[bb]; + let bb_data = &body[bb]; assert!(hi == bb_data.statements.len()); for &succ_bb in bb_data.terminator.as_ref().unwrap().successors() { visited.entry(succ_bb) @@ -116,7 +121,7 @@ fn precompute_borrows_out_of_scope<'tcx>( stack.push(StackEntry { bb: succ_bb, lo: 0, - hi: mir[succ_bb].statements.len(), + hi: body[succ_bb].statements.len(), first_part_only: false, }); // Insert 0 for this BB, to represent the whole BB @@ -128,10 +133,10 @@ fn precompute_borrows_out_of_scope<'tcx>( } } -impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Borrows<'a, 'tcx> { crate fn new( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, nonlexical_regioncx: Rc>, borrow_set: &Rc>, ) -> Self { @@ -140,14 +145,14 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { let borrow_region = borrow_data.region.to_region_vid(); let location = borrow_set.borrows[borrow_index].reserve_location; - precompute_borrows_out_of_scope(mir, &nonlexical_regioncx, + precompute_borrows_out_of_scope(body, &nonlexical_regioncx, &mut borrows_out_of_scope_at_location, borrow_index, borrow_region, location); } Borrows { tcx: tcx, - mir: mir, + body: body, borrow_set: borrow_set.clone(), borrows_out_of_scope_at_location, _nonlexical_regioncx: nonlexical_regioncx, @@ -163,7 +168,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { /// Add all borrows to the kill set, if those borrows are out of scope at `location`. /// That means they went out of a nonlexical scope fn kill_loans_out_of_scope_at_location(&self, - sets: &mut BlockSets<'_, BorrowIndex>, + trans: &mut GenKillSet, location: Location) { // NOTE: The state associated with a given `location` // reflects the dataflow on entry to the statement. @@ -177,82 +182,80 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { // region, then setting that gen-bit will override any // potential kill introduced here. if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) { - sets.kill_all(indices); + trans.kill_all(indices); } } /// Kill any borrows that conflict with `place`. fn kill_borrows_on_place( &self, - sets: &mut BlockSets<'_, BorrowIndex>, + trans: &mut GenKillSet, place: &Place<'tcx> ) { debug!("kill_borrows_on_place: place={:?}", place); - // Handle the `Place::Local(..)` case first and exit early. - if let Place::Base(PlaceBase::Local(local)) = place { - if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) { - debug!("kill_borrows_on_place: borrow_indices={:?}", borrow_indices); - sets.kill_all(borrow_indices); + + if let Some(local) = place.base_local() { + let other_borrows_of_local = self + .borrow_set + .local_map + .get(&local) + .into_iter() + .flat_map(|bs| bs.into_iter()); + + // If the borrowed place is a local with no projections, all other borrows of this + // local must conflict. This is purely an optimization so we don't have to call + // `places_conflict` for every borrow. + if let Place::Base(PlaceBase::Local(_)) = place { + trans.kill_all(other_borrows_of_local); return; } - } - - // Otherwise, look at all borrows that are live and if they conflict with the assignment - // into our place then we can kill them. - let mut borrows = sets.on_entry.clone(); - let _ = borrows.union(sets.gen_set); - for borrow_index in borrows.iter() { - let borrow_data = &self.borrows()[borrow_index]; - debug!( - "kill_borrows_on_place: borrow_index={:?} borrow_data={:?}", - borrow_index, borrow_data, - ); // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given // pair of array indices are unequal, so that when `places_conflict` returns true, we // will be assured that two places being compared definitely denotes the same sets of // locations. - if places_conflict::places_conflict( - self.tcx, - self.mir, - &borrow_data.borrowed_place, - place, - places_conflict::PlaceConflictBias::NoOverlap, - ) { - debug!( - "kill_borrows_on_place: (kill) borrow_index={:?} borrow_data={:?}", - borrow_index, borrow_data, - ); - sets.kill(borrow_index); - } + let definitely_conflicting_borrows = other_borrows_of_local + .filter(|&&i| { + places_conflict::places_conflict( + self.tcx, + self.body, + &self.borrow_set.borrows[i].borrowed_place, + place, + places_conflict::PlaceConflictBias::NoOverlap) + }); + + trans.kill_all(definitely_conflicting_borrows); } } } -impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> { type Idx = BorrowIndex; fn name() -> &'static str { "borrows" } fn bits_per_block(&self) -> usize { self.borrow_set.borrows.len() * 2 } - fn start_block_effect(&self, _entry_set: &mut BitSet) { + fn start_block_effect(&self, _entry_set: &mut BitSet) { // no borrows of code region_scopes have been taken prior to - // function execution, so this method has no effect on - // `_sets`. + // function execution, so this method has no effect. } fn before_statement_effect(&self, - sets: &mut BlockSets<'_, BorrowIndex>, + trans: &mut GenKillSet, location: Location) { - debug!("Borrows::before_statement_effect sets: {:?} location: {:?}", sets, location); - self.kill_loans_out_of_scope_at_location(sets, location); + debug!("Borrows::before_statement_effect trans: {:?} location: {:?}", + trans, location); + self.kill_loans_out_of_scope_at_location(trans, location); } - fn statement_effect(&self, sets: &mut BlockSets<'_, BorrowIndex>, location: Location) { - debug!("Borrows::statement_effect: sets={:?} location={:?}", sets, location); + fn statement_effect(&self, + trans: &mut GenKillSet, + location: Location) { + debug!("Borrows::statement_effect: trans={:?} location={:?}", + trans, location); - let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| { + let block = &self.body.basic_blocks().get(location.block).unwrap_or_else(|| { panic!("could not find block at location {:?}", location); }); let stmt = block.statements.get(location.statement_index).unwrap_or_else(|| { @@ -264,12 +267,12 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'gcx, 'tcx> { mir::StatementKind::Assign(ref lhs, ref rhs) => { // Make sure there are no remaining borrows for variables // that are assigned over. - self.kill_borrows_on_place(sets, lhs); + self.kill_borrows_on_place(trans, lhs); if let mir::Rvalue::Ref(_, _, ref place) = **rhs { if place.ignore_borrow( self.tcx, - self.mir, + self.body, &self.borrow_set.locals_state_at_exit, ) { return; @@ -278,20 +281,20 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'gcx, 'tcx> { panic!("could not find BorrowIndex for location {:?}", location); }); - sets.gen(*index); + trans.gen(*index); } } mir::StatementKind::StorageDead(local) => { // Make sure there are no remaining borrows for locals that // are gone out of scope. - self.kill_borrows_on_place(sets, &Place::Base(PlaceBase::Local(local))); + self.kill_borrows_on_place(trans, &Place::from(local)); } - mir::StatementKind::InlineAsm { ref outputs, ref asm, .. } => { - for (output, kind) in outputs.iter().zip(&asm.outputs) { + mir::StatementKind::InlineAsm(ref asm) => { + for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) { if !kind.is_indirect && !kind.is_rw { - self.kill_borrows_on_place(sets, output); + self.kill_borrows_on_place(trans, output); } } } @@ -307,13 +310,16 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'gcx, 'tcx> { } fn before_terminator_effect(&self, - sets: &mut BlockSets<'_, BorrowIndex>, + trans: &mut GenKillSet, location: Location) { - debug!("Borrows::before_terminator_effect sets: {:?} location: {:?}", sets, location); - self.kill_loans_out_of_scope_at_location(sets, location); + debug!("Borrows::before_terminator_effect: trans={:?} location={:?}", + trans, location); + self.kill_loans_out_of_scope_at_location(trans, location); } - fn terminator_effect(&self, _: &mut BlockSets<'_, BorrowIndex>, _: Location) {} + fn terminator_effect(&self, + _: &mut GenKillSet, + _: Location) {} fn propagate_call_return( &self, @@ -325,16 +331,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> BitSetOperator for Borrows<'a, 'gcx, 'tcx> { - #[inline] - fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool { - inout_set.union(in_set) // "maybe" means we union effects of both preds - } -} - -impl<'a, 'gcx, 'tcx> InitialFlow for Borrows<'a, 'gcx, 'tcx> { - #[inline] - fn bottom_value() -> bool { - false // bottom = nothing is reserved or activated yet - } +impl<'a, 'tcx> BottomValue for Borrows<'a, 'tcx> { + /// bottom = nothing is reserved or activated yet; + const BOTTOM_VALUE: bool = false; } diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index 4dcfb3f1a7fc3..065cfe8a4e823 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -3,17 +3,16 @@ //! zero-sized structure. use rustc::ty::TyCtxt; -use rustc::mir::{self, Mir, Location}; -use rustc_data_structures::bit_set::{BitSet, BitSetOperator}; +use rustc::mir::{self, Body, Location}; +use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::indexed_vec::Idx; use super::MoveDataParamEnv; use crate::util::elaborate_drops::DropFlagState; -use super::move_paths::{HasMoveData, MoveData, MovePathIndex, InitIndex}; -use super::move_paths::{LookupResult, InitKind}; -use super::{BitDenotation, BlockSets, InitialFlow}; +use super::move_paths::{HasMoveData, MoveData, MovePathIndex, InitIndex, InitKind}; +use super::{BitDenotation, BottomValue, GenKillSet}; use super::drop_flag_effects_for_function_entry; use super::drop_flag_effects_for_location; @@ -64,23 +63,19 @@ pub(super) mod borrows; /// Similarly, at a given `drop` statement, the set-intersection /// between this data and `MaybeUninitializedPlaces` yields the set of /// places that would require a dynamic drop-flag at that statement. -pub struct MaybeInitializedPlaces<'a, 'gcx: 'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>, +pub struct MaybeInitializedPlaces<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, } -impl<'a, 'gcx: 'tcx, 'tcx> MaybeInitializedPlaces<'a, 'gcx, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>) - -> Self - { - MaybeInitializedPlaces { tcx: tcx, mir: mir, mdpe: mdpe } +impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { + MaybeInitializedPlaces { tcx: tcx, body: body, mdpe: mdpe } } } -impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data } } @@ -119,23 +114,19 @@ impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'gcx, 'tcx /// Similarly, at a given `drop` statement, the set-intersection /// between this data and `MaybeInitializedPlaces` yields the set of /// places that would require a dynamic drop-flag at that statement. -pub struct MaybeUninitializedPlaces<'a, 'gcx: 'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>, +pub struct MaybeUninitializedPlaces<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, } -impl<'a, 'gcx, 'tcx> MaybeUninitializedPlaces<'a, 'gcx, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>) - -> Self - { - MaybeUninitializedPlaces { tcx: tcx, mir: mir, mdpe: mdpe } +impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { + MaybeUninitializedPlaces { tcx: tcx, body: body, mdpe: mdpe } } } -impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data } } @@ -173,23 +164,19 @@ impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, 'gcx, 't /// Similarly, at a given `drop` statement, the set-difference between /// this data and `MaybeInitializedPlaces` yields the set of places /// that would require a dynamic drop-flag at that statement. -pub struct DefinitelyInitializedPlaces<'a, 'gcx: 'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>, +pub struct DefinitelyInitializedPlaces<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, } -impl<'a, 'gcx, 'tcx: 'a> DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>) - -> Self - { - DefinitelyInitializedPlaces { tcx: tcx, mir: mir, mdpe: mdpe } +impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { + DefinitelyInitializedPlaces { tcx: tcx, body: body, mdpe: mdpe } } } -impl<'a, 'gcx, 'tcx: 'a> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data } } @@ -222,61 +209,59 @@ impl<'a, 'gcx, 'tcx: 'a> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, ' /// c = S; // {a, b, c, d } /// } /// ``` -pub struct EverInitializedPlaces<'a, 'gcx: 'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>, +pub struct EverInitializedPlaces<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, } -impl<'a, 'gcx: 'tcx, 'tcx: 'a> EverInitializedPlaces<'a, 'gcx, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>) - -> Self - { - EverInitializedPlaces { tcx: tcx, mir: mir, mdpe: mdpe } +impl<'a, 'tcx> EverInitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { + EverInitializedPlaces { tcx: tcx, body: body, mdpe: mdpe } } } -impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'tcx> { fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data } } - -impl<'a, 'gcx, 'tcx> MaybeInitializedPlaces<'a, 'gcx, 'tcx> { - fn update_bits(sets: &mut BlockSets<'_, MovePathIndex>, path: MovePathIndex, +impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { + fn update_bits(trans: &mut GenKillSet, + path: MovePathIndex, state: DropFlagState) { match state { - DropFlagState::Absent => sets.kill(path), - DropFlagState::Present => sets.gen(path), + DropFlagState::Absent => trans.kill(path), + DropFlagState::Present => trans.gen(path), } } } -impl<'a, 'gcx, 'tcx> MaybeUninitializedPlaces<'a, 'gcx, 'tcx> { - fn update_bits(sets: &mut BlockSets<'_, MovePathIndex>, path: MovePathIndex, +impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { + fn update_bits(trans: &mut GenKillSet, + path: MovePathIndex, state: DropFlagState) { match state { - DropFlagState::Absent => sets.gen(path), - DropFlagState::Present => sets.kill(path), + DropFlagState::Absent => trans.gen(path), + DropFlagState::Present => trans.kill(path), } } } -impl<'a, 'gcx, 'tcx> DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> { - fn update_bits(sets: &mut BlockSets<'_, MovePathIndex>, path: MovePathIndex, +impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { + fn update_bits(trans: &mut GenKillSet, + path: MovePathIndex, state: DropFlagState) { match state { - DropFlagState::Absent => sets.kill(path), - DropFlagState::Present => sets.gen(path), + DropFlagState::Absent => trans.kill(path), + DropFlagState::Present => trans.gen(path), } } } -impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { type Idx = MovePathIndex; fn name() -> &'static str { "maybe_init" } fn bits_per_block(&self) -> usize { @@ -285,7 +270,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'gcx, 't fn start_block_effect(&self, entry_set: &mut BitSet) { drop_flag_effects_for_function_entry( - self.tcx, self.mir, self.mdpe, + self.tcx, self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); entry_set.insert(path); @@ -293,24 +278,24 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'gcx, 't } fn statement_effect(&self, - sets: &mut BlockSets<'_, MovePathIndex>, + trans: &mut GenKillSet, location: Location) { drop_flag_effects_for_location( - self.tcx, self.mir, self.mdpe, + self.tcx, self.body, self.mdpe, location, - |path, s| Self::update_bits(sets, path, s) + |path, s| Self::update_bits(trans, path, s) ) } fn terminator_effect(&self, - sets: &mut BlockSets<'_, MovePathIndex>, + trans: &mut GenKillSet, location: Location) { drop_flag_effects_for_location( - self.tcx, self.mir, self.mdpe, + self.tcx, self.body, self.mdpe, location, - |path, s| Self::update_bits(sets, path, s) + |path, s| Self::update_bits(trans, path, s) ) } @@ -323,13 +308,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'gcx, 't ) { // when a call returns successfully, that means we need to set // the bits for that dest_place to 1 (initialized). - on_lookup_result_bits(self.tcx, self.mir, self.move_data(), + on_lookup_result_bits(self.tcx, self.body, self.move_data(), self.move_data().rev_lookup.find(dest_place), |mpi| { in_out.insert(mpi); }); } } -impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { type Idx = MovePathIndex; fn name() -> &'static str { "maybe_uninit" } fn bits_per_block(&self) -> usize { @@ -343,7 +328,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'gcx, entry_set.insert_all(); drop_flag_effects_for_function_entry( - self.tcx, self.mir, self.mdpe, + self.tcx, self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); entry_set.remove(path); @@ -351,24 +336,24 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'gcx, } fn statement_effect(&self, - sets: &mut BlockSets<'_, MovePathIndex>, + trans: &mut GenKillSet, location: Location) { drop_flag_effects_for_location( - self.tcx, self.mir, self.mdpe, + self.tcx, self.body, self.mdpe, location, - |path, s| Self::update_bits(sets, path, s) + |path, s| Self::update_bits(trans, path, s) ) } fn terminator_effect(&self, - sets: &mut BlockSets<'_, MovePathIndex>, + trans: &mut GenKillSet, location: Location) { drop_flag_effects_for_location( - self.tcx, self.mir, self.mdpe, + self.tcx, self.body, self.mdpe, location, - |path, s| Self::update_bits(sets, path, s) + |path, s| Self::update_bits(trans, path, s) ) } @@ -381,13 +366,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'gcx, ) { // when a call returns successfully, that means we need to set // the bits for that dest_place to 0 (initialized). - on_lookup_result_bits(self.tcx, self.mir, self.move_data(), + on_lookup_result_bits(self.tcx, self.body, self.move_data(), self.move_data().rev_lookup.find(dest_place), |mpi| { in_out.remove(mpi); }); } } -impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { type Idx = MovePathIndex; fn name() -> &'static str { "definite_init" } fn bits_per_block(&self) -> usize { @@ -399,7 +384,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'gc entry_set.clear(); drop_flag_effects_for_function_entry( - self.tcx, self.mir, self.mdpe, + self.tcx, self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); entry_set.insert(path); @@ -407,24 +392,24 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'gc } fn statement_effect(&self, - sets: &mut BlockSets<'_, MovePathIndex>, + trans: &mut GenKillSet, location: Location) { drop_flag_effects_for_location( - self.tcx, self.mir, self.mdpe, + self.tcx, self.body, self.mdpe, location, - |path, s| Self::update_bits(sets, path, s) + |path, s| Self::update_bits(trans, path, s) ) } fn terminator_effect(&self, - sets: &mut BlockSets<'_, MovePathIndex>, + trans: &mut GenKillSet, location: Location) { drop_flag_effects_for_location( - self.tcx, self.mir, self.mdpe, + self.tcx, self.body, self.mdpe, location, - |path, s| Self::update_bits(sets, path, s) + |path, s| Self::update_bits(trans, path, s) ) } @@ -437,13 +422,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'gc ) { // when a call returns successfully, that means we need to set // the bits for that dest_place to 1 (initialized). - on_lookup_result_bits(self.tcx, self.mir, self.move_data(), + on_lookup_result_bits(self.tcx, self.body, self.move_data(), self.move_data().rev_lookup.find(dest_place), |mpi| { in_out.insert(mpi); }); } } -impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> { type Idx = InitIndex; fn name() -> &'static str { "ever_init" } fn bits_per_block(&self) -> usize { @@ -451,69 +436,47 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'gcx, 'tc } fn start_block_effect(&self, entry_set: &mut BitSet) { - for arg_init in 0..self.mir.arg_count { + for arg_init in 0..self.body.arg_count { entry_set.insert(InitIndex::new(arg_init)); } } fn statement_effect(&self, - sets: &mut BlockSets<'_, InitIndex>, + trans: &mut GenKillSet, location: Location) { - let (_, mir, move_data) = (self.tcx, self.mir, self.move_data()); - let stmt = &mir[location.block].statements[location.statement_index]; + let (_, body, move_data) = (self.tcx, self.body, self.move_data()); + let stmt = &body[location.block].statements[location.statement_index]; let init_path_map = &move_data.init_path_map; let init_loc_map = &move_data.init_loc_map; let rev_lookup = &move_data.rev_lookup; debug!("statement {:?} at loc {:?} initializes move_indexes {:?}", stmt, location, &init_loc_map[location]); - sets.gen_all(&init_loc_map[location]); + trans.gen_all(&init_loc_map[location]); match stmt.kind { - mir::StatementKind::StorageDead(local) | - mir::StatementKind::StorageLive(local) => { - // End inits for StorageDead and StorageLive, so that an immutable - // variable can be reinitialized on the next iteration of the loop. - // - // FIXME(#46525): We *need* to do this for StorageLive as well as - // StorageDead, because lifetimes of match bindings with guards are - // weird - i.e., this code - // - // ``` - // fn main() { - // match 0 { - // a | a - // if { println!("a={}", a); false } => {} - // _ => {} - // } - // } - // ``` - // - // runs the guard twice, using the same binding for `a`, and only - // storagedeads after everything ends, so if we don't regard the - // storagelive as killing storage, we would have a multiple assignment - // to immutable data error. - if let LookupResult::Exact(mpi) = - rev_lookup.find(&mir::Place::Base(mir::PlaceBase::Local(local))) { - debug!("stmt {:?} at loc {:?} clears the ever initialized status of {:?}", - stmt, location, &init_path_map[mpi]); - sets.kill_all(&init_path_map[mpi]); - } + mir::StatementKind::StorageDead(local) => { + // End inits for StorageDead, so that an immutable variable can + // be reinitialized on the next iteration of the loop. + let move_path_index = rev_lookup.find_local(local); + debug!("stmt {:?} at loc {:?} clears the ever initialized status of {:?}", + stmt, location, &init_path_map[move_path_index]); + trans.kill_all(&init_path_map[move_path_index]); } _ => {} } } fn terminator_effect(&self, - sets: &mut BlockSets<'_, InitIndex>, + trans: &mut GenKillSet, location: Location) { - let (mir, move_data) = (self.mir, self.move_data()); - let term = mir[location.block].terminator(); + let (body, move_data) = (self.body, self.move_data()); + let term = body[location.block].terminator(); let init_loc_map = &move_data.init_loc_map; debug!("terminator {:?} at loc {:?} initializes move_indexes {:?}", term, location, &init_loc_map[location]); - sets.gen_all( + trans.gen_all( init_loc_map[location].iter().filter(|init_index| { move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly }) @@ -533,7 +496,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'gcx, 'tc let call_loc = Location { block: call_bb, - statement_index: self.mir[call_bb].statements.len(), + statement_index: self.body[call_bb].statements.len(), }; for init_index in &init_loc_map[call_loc] { assert!(init_index.index() < bits_per_block); @@ -542,68 +505,22 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'gcx, 'tc } } -impl<'a, 'gcx, 'tcx> BitSetOperator for MaybeInitializedPlaces<'a, 'gcx, 'tcx> { - #[inline] - fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool { - inout_set.union(in_set) // "maybe" means we union effects of both preds - } +impl<'a, 'tcx> BottomValue for MaybeInitializedPlaces<'a, 'tcx> { + /// bottom = uninitialized + const BOTTOM_VALUE: bool = false; } -impl<'a, 'gcx, 'tcx> BitSetOperator for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> { - #[inline] - fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool { - inout_set.union(in_set) // "maybe" means we union effects of both preds - } +impl<'a, 'tcx> BottomValue for MaybeUninitializedPlaces<'a, 'tcx> { + /// bottom = initialized (start_block_effect counters this at outset) + const BOTTOM_VALUE: bool = false; } -impl<'a, 'gcx, 'tcx> BitSetOperator for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> { - #[inline] - fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool { - inout_set.intersect(in_set) // "definitely" means we intersect effects of both preds - } -} - -impl<'a, 'gcx, 'tcx> BitSetOperator for EverInitializedPlaces<'a, 'gcx, 'tcx> { - #[inline] - fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool { - inout_set.union(in_set) // inits from both preds are in scope - } +impl<'a, 'tcx> BottomValue for DefinitelyInitializedPlaces<'a, 'tcx> { + /// bottom = initialized (start_block_effect counters this at outset) + const BOTTOM_VALUE: bool = true; } -// The way that dataflow fixed point iteration works, you want to -// start at bottom and work your way to a fixed point. Control-flow -// merges will apply the `join` operator to each block entry's current -// state (which starts at that bottom value). -// -// This means, for propagation across the graph, that you either want -// to start at all-zeroes and then use Union as your merge when -// propagating, or you start at all-ones and then use Intersect as -// your merge when propagating. - -impl<'a, 'gcx, 'tcx> InitialFlow for MaybeInitializedPlaces<'a, 'gcx, 'tcx> { - #[inline] - fn bottom_value() -> bool { - false // bottom = uninitialized - } -} - -impl<'a, 'gcx, 'tcx> InitialFlow for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> { - #[inline] - fn bottom_value() -> bool { - false // bottom = initialized (start_block_effect counters this at outset) - } -} - -impl<'a, 'gcx, 'tcx> InitialFlow for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> { - #[inline] - fn bottom_value() -> bool { - true // bottom = initialized (start_block_effect counters this at outset) - } -} - -impl<'a, 'gcx, 'tcx> InitialFlow for EverInitializedPlaces<'a, 'gcx, 'tcx> { - #[inline] - fn bottom_value() -> bool { - false // bottom = no initialized variables by default - } +impl<'a, 'tcx> BottomValue for EverInitializedPlaces<'a, 'tcx> { + /// bottom = no initialized variables by default + const BOTTOM_VALUE: bool = false; } diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index 6b8eb6f17f6c1..7fa950cb98d34 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -1,21 +1,27 @@ pub use super::*; use rustc::mir::*; +use rustc::mir::visit::{ + PlaceContext, Visitor, NonMutatingUseContext, +}; +use std::cell::RefCell; use crate::dataflow::BitDenotation; +use crate::dataflow::HaveBeenBorrowedLocals; +use crate::dataflow::{DataflowResults, DataflowResultsCursor, DataflowResultsRefCursor}; #[derive(Copy, Clone)] -pub struct MaybeStorageLive<'a, 'tcx: 'a> { - mir: &'a Mir<'tcx>, +pub struct MaybeStorageLive<'a, 'tcx> { + body: &'a Body<'tcx>, } -impl<'a, 'tcx: 'a> MaybeStorageLive<'a, 'tcx> { - pub fn new(mir: &'a Mir<'tcx>) +impl<'a, 'tcx> MaybeStorageLive<'a, 'tcx> { + pub fn new(body: &'a Body<'tcx>) -> Self { - MaybeStorageLive { mir } + MaybeStorageLive { body } } - pub fn mir(&self) -> &Mir<'tcx> { - self.mir + pub fn body(&self) -> &Body<'tcx> { + self.body } } @@ -23,27 +29,29 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> { type Idx = Local; fn name() -> &'static str { "maybe_storage_live" } fn bits_per_block(&self) -> usize { - self.mir.local_decls.len() + self.body.local_decls.len() } - fn start_block_effect(&self, _sets: &mut BitSet) { - // Nothing is live on function entry + fn start_block_effect(&self, _on_entry: &mut BitSet) { + // Nothing is live on function entry (generators only have a self + // argument, and we don't care about that) + assert_eq!(1, self.body.arg_count); } fn statement_effect(&self, - sets: &mut BlockSets<'_, Local>, + trans: &mut GenKillSet, loc: Location) { - let stmt = &self.mir[loc.block].statements[loc.statement_index]; + let stmt = &self.body[loc.block].statements[loc.statement_index]; match stmt.kind { - StatementKind::StorageLive(l) => sets.gen(l), - StatementKind::StorageDead(l) => sets.kill(l), + StatementKind::StorageLive(l) => trans.gen(l), + StatementKind::StorageDead(l) => trans.kill(l), _ => (), } } fn terminator_effect(&self, - _sets: &mut BlockSets<'_, Local>, + _trans: &mut GenKillSet, _loc: Location) { // Terminators have no effect } @@ -59,16 +67,127 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> { } } -impl<'a, 'tcx> BitSetOperator for MaybeStorageLive<'a, 'tcx> { - #[inline] - fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool { - inout_set.union(in_set) // "maybe" means we union effects of both preds +impl<'a, 'tcx> BottomValue for MaybeStorageLive<'a, 'tcx> { + /// bottom = dead + const BOTTOM_VALUE: bool = false; +} + +/// Dataflow analysis that determines whether each local requires storage at a +/// given location; i.e. whether its storage can go away without being observed. +pub struct RequiresStorage<'mir, 'tcx> { + body: &'mir Body<'tcx>, + borrowed_locals: + RefCell>>, +} + +impl<'mir, 'tcx: 'mir> RequiresStorage<'mir, 'tcx> { + pub fn new( + body: &'mir Body<'tcx>, + borrowed_locals: &'mir DataflowResults<'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>, + ) -> Self { + RequiresStorage { + body, + borrowed_locals: RefCell::new(DataflowResultsCursor::new(borrowed_locals, body)), + } + } + + pub fn body(&self) -> &Body<'tcx> { + self.body + } +} + +impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> { + type Idx = Local; + fn name() -> &'static str { "requires_storage" } + fn bits_per_block(&self) -> usize { + self.body.local_decls.len() + } + + fn start_block_effect(&self, _sets: &mut BitSet) { + // Nothing is live on function entry (generators only have a self + // argument, and we don't care about that) + assert_eq!(1, self.body.arg_count); + } + + fn statement_effect(&self, + sets: &mut GenKillSet, + loc: Location) { + self.check_for_move(sets, loc); + self.check_for_borrow(sets, loc); + + let stmt = &self.body[loc.block].statements[loc.statement_index]; + match stmt.kind { + StatementKind::StorageLive(l) => sets.gen(l), + StatementKind::StorageDead(l) => sets.kill(l), + StatementKind::Assign(ref place, _) + | StatementKind::SetDiscriminant { ref place, .. } => { + place.base_local().map(|l| sets.gen(l)); + } + StatementKind::InlineAsm(box InlineAsm { ref outputs, .. }) => { + for p in &**outputs { + p.base_local().map(|l| sets.gen(l)); + } + } + _ => (), + } + } + + fn terminator_effect(&self, + sets: &mut GenKillSet, + loc: Location) { + self.check_for_move(sets, loc); + self.check_for_borrow(sets, loc); + } + + fn propagate_call_return( + &self, + in_out: &mut BitSet, + _call_bb: mir::BasicBlock, + _dest_bb: mir::BasicBlock, + dest_place: &mir::Place<'tcx>, + ) { + dest_place.base_local().map(|l| in_out.insert(l)); + } +} + +impl<'mir, 'tcx> RequiresStorage<'mir, 'tcx> { + /// Kill locals that are fully moved and have not been borrowed. + fn check_for_move(&self, sets: &mut GenKillSet, loc: Location) { + let mut visitor = MoveVisitor { + sets, + borrowed_locals: &self.borrowed_locals, + }; + visitor.visit_location(self.body, loc); + } + + /// Gen locals that are newly borrowed. This includes borrowing any part of + /// a local (we rely on this behavior of `HaveBeenBorrowedLocals`). + fn check_for_borrow(&self, sets: &mut GenKillSet, loc: Location) { + let mut borrowed_locals = self.borrowed_locals.borrow_mut(); + borrowed_locals.seek(loc); + borrowed_locals.each_gen_bit(|l| sets.gen(l)); } } -impl<'a, 'tcx> InitialFlow for MaybeStorageLive<'a, 'tcx> { - #[inline] - fn bottom_value() -> bool { - false // bottom = dead +impl<'mir, 'tcx> BottomValue for RequiresStorage<'mir, 'tcx> { + /// bottom = dead + const BOTTOM_VALUE: bool = false; +} + +struct MoveVisitor<'a, 'mir, 'tcx> { + borrowed_locals: + &'a RefCell>>, + sets: &'a mut GenKillSet, +} + +impl<'a, 'mir: 'a, 'tcx> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx> { + fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) { + if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { + let mut borrowed_locals = self.borrowed_locals.borrow_mut(); + borrowed_locals.seek(loc); + if !borrowed_locals.contains(*local) { + self.sets.kill(*local); + } + } } } diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index c24a776605cb8..5433a9013aa85 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -1,11 +1,13 @@ use syntax::ast::{self, MetaItem}; +use syntax::symbol::{Symbol, sym}; -use rustc_data_structures::bit_set::{BitSet, BitSetOperator, HybridBitSet}; +use rustc_data_structures::bit_set::{BitSet, HybridBitSet}; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::work_queue::WorkQueue; +use rustc::hir::def_id::DefId; use rustc::ty::{self, TyCtxt}; -use rustc::mir::{self, Mir, BasicBlock, BasicBlockData, Location, Statement, Terminator}; +use rustc::mir::{self, Body, BasicBlock, BasicBlockData, Location, Statement, Terminator}; use rustc::mir::traversal; use rustc::session::Session; @@ -15,7 +17,7 @@ use std::io; use std::path::PathBuf; use std::usize; -pub use self::impls::{MaybeStorageLive}; +pub use self::impls::{MaybeStorageLive, RequiresStorage}; pub use self::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; pub use self::impls::DefinitelyInitializedPlaces; pub use self::impls::EverInitializedPlaces; @@ -32,13 +34,18 @@ mod graphviz; mod impls; pub mod move_paths; -pub(crate) use self::move_paths::indexes; +pub(crate) mod indexes { + pub(crate) use super::{ + move_paths::{MovePathIndex, MoveOutIndex, InitIndex}, + impls::borrows::BorrowIndex, + }; +} -pub(crate) struct DataflowBuilder<'a, 'tcx: 'a, BD> +pub(crate) struct DataflowBuilder<'a, 'tcx, BD> where - BD: BitDenotation<'tcx> + BD: BitDenotation<'tcx>, { - node_id: ast::NodeId, + def_id: DefId, flow_state: DataflowAnalysis<'a, 'tcx, BD>, print_preflow_to: Option, print_postflow_to: Option, @@ -79,9 +86,9 @@ pub(crate) trait Dataflow<'tcx, BD: BitDenotation<'tcx>> { fn propagate(&mut self); } -impl<'a, 'tcx: 'a, BD> Dataflow<'tcx, BD> for DataflowBuilder<'a, 'tcx, BD> +impl<'a, 'tcx, BD> Dataflow<'tcx, BD> for DataflowBuilder<'a, 'tcx, BD> where - BD: BitDenotation<'tcx> + BD: BitDenotation<'tcx>, { fn dataflow

(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> DebugFormatted { self.flow_state.build_sets(); @@ -94,9 +101,9 @@ where fn propagate(&mut self) { self.flow_state.propagate(); } } -pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option { +pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Option { for attr in attrs { - if attr.check_name("rustc_mir") { + if attr.check_name(sym::rustc_mir) { let items = attr.meta_item_list(); for item in items.iter().flat_map(|l| l.iter()) { match item.meta_item() { @@ -109,34 +116,41 @@ pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option return None; } -pub struct MoveDataParamEnv<'gcx, 'tcx> { +pub struct MoveDataParamEnv<'tcx> { pub(crate) move_data: MoveData<'tcx>, - pub(crate) param_env: ty::ParamEnv<'gcx>, -} - -pub(crate) fn do_dataflow<'a, 'gcx, 'tcx, BD, P>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, - node_id: ast::NodeId, - attributes: &[ast::Attribute], - dead_unwinds: &BitSet, - bd: BD, - p: P) - -> DataflowResults<'tcx, BD> - where BD: BitDenotation<'tcx> + InitialFlow, - P: Fn(&BD, BD::Idx) -> DebugFormatted + pub(crate) param_env: ty::ParamEnv<'tcx>, +} + +pub(crate) fn do_dataflow<'a, 'tcx, BD, P>( + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + def_id: DefId, + attributes: &[ast::Attribute], + dead_unwinds: &BitSet, + bd: BD, + p: P, +) -> DataflowResults<'tcx, BD> +where + BD: BitDenotation<'tcx>, + P: Fn(&BD, BD::Idx) -> DebugFormatted, { - let flow_state = DataflowAnalysis::new(mir, dead_unwinds, bd); - flow_state.run(tcx, node_id, attributes, p) + let flow_state = DataflowAnalysis::new(body, dead_unwinds, bd); + flow_state.run(tcx, def_id, attributes, p) } -impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation<'tcx> +impl<'a, 'tcx, BD> DataflowAnalysis<'a, 'tcx, BD> +where + BD: BitDenotation<'tcx>, { - pub(crate) fn run

(self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - node_id: ast::NodeId, - attributes: &[ast::Attribute], - p: P) -> DataflowResults<'tcx, BD> - where P: Fn(&BD, BD::Idx) -> DebugFormatted + pub(crate) fn run

( + self, + tcx: TyCtxt<'tcx>, + def_id: DefId, + attributes: &[ast::Attribute], + p: P, + ) -> DataflowResults<'tcx, BD> + where + P: Fn(&BD, BD::Idx) -> DebugFormatted, { let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option { if let Some(item) = has_rustc_mir_with(attrs, name) { @@ -145,20 +159,18 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitD } else { sess.span_err( item.span, - &format!("{} attribute requires a path", item.ident)); + &format!("{} attribute requires a path", item.path)); return None; } } return None; }; - let print_preflow_to = - name_found(tcx.sess, attributes, "borrowck_graphviz_preflow"); - let print_postflow_to = - name_found(tcx.sess, attributes, "borrowck_graphviz_postflow"); + let print_preflow_to = name_found(tcx.sess, attributes, sym::borrowck_graphviz_preflow); + let print_postflow_to = name_found(tcx.sess, attributes, sym::borrowck_graphviz_postflow); let mut mbcx = DataflowBuilder { - node_id, + def_id, print_preflow_to, print_postflow_to, flow_state: self, }; @@ -167,12 +179,16 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitD } } -struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O> where O: 'b + BitDenotation<'tcx> +struct PropagationContext<'b, 'a, 'tcx, O> +where + O: BitDenotation<'tcx>, { builder: &'b mut DataflowAnalysis<'a, 'tcx, O>, } -impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation<'tcx> +impl<'a, 'tcx, BD> DataflowAnalysis<'a, 'tcx, BD> +where + BD: BitDenotation<'tcx>, { fn propagate(&mut self) { let mut temp = BitSet::new_empty(self.flow_state.sets.bits_per_block); @@ -183,60 +199,61 @@ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation<'t } fn build_sets(&mut self) { - // First we need to build the entry-, gen- and kill-sets. - - { - let sets = &mut self.flow_state.sets.for_block(mir::START_BLOCK.index()); - self.flow_state.operator.start_block_effect(&mut sets.on_entry); - } - - for (bb, data) in self.mir.basic_blocks().iter_enumerated() { + // Build the transfer function for each block. + for (bb, data) in self.body.basic_blocks().iter_enumerated() { let &mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = data; - let mut interim_state; - let sets = &mut self.flow_state.sets.for_block(bb.index()); - let track_intrablock = BD::accumulates_intrablock_state(); - if track_intrablock { - debug!("swapping in mutable on_entry, initially {:?}", sets.on_entry); - interim_state = sets.on_entry.to_owned(); - sets.on_entry = &mut interim_state; - } + let trans = self.flow_state.sets.trans_mut_for(bb.index()); for j_stmt in 0..statements.len() { let location = Location { block: bb, statement_index: j_stmt }; - self.flow_state.operator.before_statement_effect(sets, location); - self.flow_state.operator.statement_effect(sets, location); - if track_intrablock { - sets.apply_local_effect(); - } + self.flow_state.operator.before_statement_effect(trans, location); + self.flow_state.operator.statement_effect(trans, location); } if terminator.is_some() { let location = Location { block: bb, statement_index: statements.len() }; - self.flow_state.operator.before_terminator_effect(sets, location); - self.flow_state.operator.terminator_effect(sets, location); - if track_intrablock { - sets.apply_local_effect(); - } + self.flow_state.operator.before_terminator_effect(trans, location); + self.flow_state.operator.terminator_effect(trans, location); } } + + // Initialize the flow state at entry to the start block. + let on_entry = self.flow_state.sets.entry_set_mut_for(mir::START_BLOCK.index()); + self.flow_state.operator.start_block_effect(on_entry); } } -impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> where BD: BitDenotation<'tcx> +impl<'b, 'a, 'tcx, BD> PropagationContext<'b, 'a, 'tcx, BD> +where + BD: BitDenotation<'tcx>, { fn walk_cfg(&mut self, in_out: &mut BitSet) { + let body = self.builder.body; + + // Initialize the dirty queue in reverse post-order. This makes it more likely that the + // entry state for each basic block will have the effects of its predecessors applied + // before it is processed. In fact, for CFGs without back edges, this guarantees that + // dataflow will converge in exactly `N` iterations, where `N` is the number of basic + // blocks. let mut dirty_queue: WorkQueue = - WorkQueue::with_all(self.builder.mir.basic_blocks().len()); - let mir = self.builder.mir; + WorkQueue::with_none(body.basic_blocks().len()); + for (bb, _) in traversal::reverse_postorder(body) { + dirty_queue.insert(bb); + } + + // Add blocks which are not reachable from START_BLOCK to the work queue. These blocks will + // be processed after the ones added above. + for bb in body.basic_blocks().indices() { + dirty_queue.insert(bb); + } + while let Some(bb) = dirty_queue.pop() { - let bb_data = &mir[bb]; - { - let sets = self.builder.flow_state.sets.for_block(bb.index()); - debug_assert!(in_out.words().len() == sets.on_entry.words().len()); - in_out.overwrite(sets.on_entry); - in_out.union(sets.gen_set); - in_out.subtract(sets.kill_set); - } + let (on_entry, trans) = self.builder.flow_state.sets.get_mut(bb.index()); + debug_assert!(in_out.words().len() == on_entry.words().len()); + in_out.overwrite(on_entry); + trans.apply(in_out); + + let bb_data = &body[bb]; self.builder.propagate_bits_into_graph_successors_of( in_out, (bb, bb_data), &mut dirty_queue); } @@ -253,7 +270,9 @@ fn dataflow_path(context: &str, path: &str) -> PathBuf { path } -impl<'a, 'tcx: 'a, BD> DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation<'tcx> +impl<'a, 'tcx, BD> DataflowBuilder<'a, 'tcx, BD> +where + BD: BitDenotation<'tcx>, { fn pre_dataflow_instrumentation

(&self, p: P) -> io::Result<()> where P: Fn(&BD, BD::Idx) -> DebugFormatted @@ -307,7 +326,7 @@ pub(crate) trait DataflowResultsConsumer<'a, 'tcx: 'a> { fn analyze_results(&mut self, flow_uninit: &mut Self::FlowState) { let flow = flow_uninit; - for (bb, _) in traversal::reverse_postorder(self.mir()) { + for (bb, _) in traversal::reverse_postorder(self.body()) { flow.reset_to_entry_of(bb); self.process_basic_block(bb, flow); } @@ -315,7 +334,7 @@ pub(crate) trait DataflowResultsConsumer<'a, 'tcx: 'a> { fn process_basic_block(&mut self, bb: BasicBlock, flow_state: &mut Self::FlowState) { let BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = - self.mir()[bb]; + self.body()[bb]; let mut location = Location { block: bb, statement_index: 0 }; for stmt in statements.iter() { flow_state.reconstruct_statement_effect(location); @@ -338,57 +357,148 @@ pub(crate) trait DataflowResultsConsumer<'a, 'tcx: 'a> { // Delegated Hooks: Provide access to the MIR and process the flow state. - fn mir(&self) -> &'a Mir<'tcx>; + fn body(&self) -> &'a Body<'tcx>; } -pub fn state_for_location<'tcx, T: BitDenotation<'tcx>>(loc: Location, - analysis: &T, - result: &DataflowResults<'tcx, T>, - mir: &Mir<'tcx>) - -> BitSet { - let mut on_entry = result.sets().on_entry_set_for(loc.block.index()).to_owned(); - let mut kill_set = on_entry.to_hybrid(); - let mut gen_set = kill_set.clone(); +/// Allows iterating dataflow results in a flexible and reasonably fast way. +pub struct DataflowResultsCursor<'mir, 'tcx, BD, DR = DataflowResults<'tcx, BD>> +where + BD: BitDenotation<'tcx>, + DR: Borrow>, +{ + flow_state: FlowAtLocation<'tcx, BD, DR>, - { - let mut sets = BlockSets { - on_entry: &mut on_entry, - kill_set: &mut kill_set, - gen_set: &mut gen_set, + // The statement (or terminator) whose effect has been reconstructed in + // flow_state. + curr_loc: Option, + + body: &'mir Body<'tcx>, +} + +pub type DataflowResultsRefCursor<'mir, 'tcx, BD> = + DataflowResultsCursor<'mir, 'tcx, BD, &'mir DataflowResults<'tcx, BD>>; + +impl<'mir, 'tcx, BD, DR> DataflowResultsCursor<'mir, 'tcx, BD, DR> +where + BD: BitDenotation<'tcx>, + DR: Borrow>, +{ + pub fn new(result: DR, body: &'mir Body<'tcx>) -> Self { + DataflowResultsCursor { + flow_state: FlowAtLocation::new(result), + curr_loc: None, + body, + } + } + + /// Seek to the given location in MIR. This method is fast if you are + /// traversing your MIR statements in order. + /// + /// After calling `seek`, the current state will reflect all effects up to + /// and including the `before_statement_effect` of the statement at location + /// `loc`. The `statement_effect` of the statement at `loc` will be + /// available as the current effect (see e.g. `each_gen_bit`). + /// + /// If `loc.statement_index` equals the number of statements in the block, + /// we will reconstruct the terminator effect in the same way as described + /// above. + pub fn seek(&mut self, loc: Location) { + if self.curr_loc.map(|cur| loc == cur).unwrap_or(false) { + return; + } + + let start_index; + let should_reset = match self.curr_loc { + None => true, + Some(cur) + if loc.block != cur.block || loc.statement_index < cur.statement_index => true, + _ => false, }; + if should_reset { + self.flow_state.reset_to_entry_of(loc.block); + start_index = 0; + } else { + let curr_loc = self.curr_loc.unwrap(); + start_index = curr_loc.statement_index; + // Apply the effect from the last seek to the current state. + self.flow_state.apply_local_effect(curr_loc); + } - for stmt in 0..loc.statement_index { + for stmt in start_index..loc.statement_index { let mut stmt_loc = loc; stmt_loc.statement_index = stmt; - analysis.before_statement_effect(&mut sets, stmt_loc); - analysis.statement_effect(&mut sets, stmt_loc); + self.flow_state.reconstruct_statement_effect(stmt_loc); + self.flow_state.apply_local_effect(stmt_loc); } - // Apply the pre-statement effect of the statement we're evaluating. - if loc.statement_index == mir[loc.block].statements.len() { - analysis.before_terminator_effect(&mut sets, loc); + if loc.statement_index == self.body[loc.block].statements.len() { + self.flow_state.reconstruct_terminator_effect(loc); } else { - analysis.before_statement_effect(&mut sets, loc); + self.flow_state.reconstruct_statement_effect(loc); } + self.curr_loc = Some(loc); + } + + /// Return whether the current state contains bit `x`. + pub fn contains(&self, x: BD::Idx) -> bool { + self.flow_state.contains(x) + } + + /// Iterate over each `gen` bit in the current effect (invoke `seek` first). + pub fn each_gen_bit(&self, f: F) + where + F: FnMut(BD::Idx), + { + self.flow_state.each_gen_bit(f) + } +} + +pub fn state_for_location<'tcx, T: BitDenotation<'tcx>>(loc: Location, + analysis: &T, + result: &DataflowResults<'tcx, T>, + body: &Body<'tcx>) + -> BitSet { + let mut trans = GenKill::from_elem(HybridBitSet::new_empty(analysis.bits_per_block())); + + for stmt in 0..loc.statement_index { + let mut stmt_loc = loc; + stmt_loc.statement_index = stmt; + analysis.before_statement_effect(&mut trans, stmt_loc); + analysis.statement_effect(&mut trans, stmt_loc); + } + + // Apply the pre-statement effect of the statement we're evaluating. + if loc.statement_index == body[loc.block].statements.len() { + analysis.before_terminator_effect(&mut trans, loc); + } else { + analysis.before_statement_effect(&mut trans, loc); } - gen_set.to_dense() + // Apply the transfer function for all preceding statements to the fixpoint + // at the start of the block. + let mut state = result.sets().entry_set_for(loc.block.index()).to_owned(); + trans.apply(&mut state); + state } -pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation<'tcx> +pub struct DataflowAnalysis<'a, 'tcx, O> +where + O: BitDenotation<'tcx>, { flow_state: DataflowState<'tcx, O>, dead_unwinds: &'a BitSet, - mir: &'a Mir<'tcx>, + body: &'a Body<'tcx>, } -impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O> where O: BitDenotation<'tcx> +impl<'a, 'tcx, O> DataflowAnalysis<'a, 'tcx, O> +where + O: BitDenotation<'tcx>, { pub fn results(self) -> DataflowResults<'tcx, O> { DataflowResults(self.flow_state) } - pub fn mir(&self) -> &'a Mir<'tcx> { self.mir } + pub fn body(&self) -> &'a Body<'tcx> { self.body } } pub struct DataflowResults<'tcx, O>(pub(crate) DataflowState<'tcx, O>) where O: BitDenotation<'tcx>; @@ -438,36 +548,8 @@ impl<'tcx, O: BitDenotation<'tcx>> DataflowState<'tcx, O> { } } -#[derive(Debug)] -pub struct AllSets { - /// Analysis bitwidth for each block. - bits_per_block: usize, - - /// For each block, bits valid on entry to the block. - on_entry_sets: Vec>, - - /// For each block, bits generated by executing the statements + - /// terminator in the block -- with one caveat. In particular, for - /// *call terminators*, the effect of storing the destination is - /// not included, since that only takes effect on the **success** - /// edge (and not the unwind edge). - gen_sets: Vec>, - - /// For each block, bits killed by executing the statements + - /// terminator in the block -- with one caveat. In particular, for - /// *call terminators*, the effect of storing the destination is - /// not included, since that only takes effect on the **success** - /// edge (and not the unwind edge). - kill_sets: Vec>, -} - -/// Triple of sets associated with a given block. -/// -/// Generally, one sets up `on_entry`, `gen_set`, and `kill_set` for -/// each block individually, and then runs the dataflow analysis which -/// iteratively modifies the various `on_entry` sets (but leaves the -/// other two sets unchanged, since they represent the effect of the -/// block, which should be invariant over the course of the analysis). +/// A 2-tuple representing the "gen" and "kill" bitsets during +/// dataflow analysis. /// /// It is best to ensure that the intersection of `gen_set` and /// `kill_set` is empty; otherwise the results of the dataflow will @@ -475,21 +557,32 @@ pub struct AllSets { /// killed during the iteration. (This is such a good idea that the /// `fn gen` and `fn kill` methods that set their state enforce this /// for you.) -#[derive(Debug)] -pub struct BlockSets<'a, E: Idx> { - /// Dataflow state immediately before control flow enters the given block. - pub(crate) on_entry: &'a mut BitSet, +#[derive(Debug, Clone, Copy)] +pub struct GenKill { + pub(crate) gen_set: T, + pub(crate) kill_set: T, +} - /// Bits that are set to 1 by the time we exit the given block. Hybrid - /// because it usually contains only 0 or 1 elements. - pub(crate) gen_set: &'a mut HybridBitSet, +type GenKillSet = GenKill>; - /// Bits that are set to 0 by the time we exit the given block. Hybrid - /// because it usually contains only 0 or 1 elements. - pub(crate) kill_set: &'a mut HybridBitSet, +impl GenKill { + /// Creates a new tuple where `gen_set == kill_set == elem`. + pub(crate) fn from_elem(elem: T) -> Self + where T: Clone + { + GenKill { + gen_set: elem.clone(), + kill_set: elem, + } + } } -impl<'a, E:Idx> BlockSets<'a, E> { +impl GenKillSet { + pub(crate) fn clear(&mut self) { + self.gen_set.clear(); + self.kill_set.clear(); + } + fn gen(&mut self, e: E) { self.gen_set.insert(e); self.kill_set.remove(e); @@ -517,73 +610,93 @@ impl<'a, E:Idx> BlockSets<'a, E> { } } - fn apply_local_effect(&mut self) { - self.on_entry.union(self.gen_set); - self.on_entry.subtract(self.kill_set); + /// Computes `(set ∪ gen) - kill` and assigns the result to `set`. + pub(crate) fn apply(&self, set: &mut BitSet) { + set.union(&self.gen_set); + set.subtract(&self.kill_set); } } +#[derive(Debug)] +pub struct AllSets { + /// Analysis bitwidth for each block. + bits_per_block: usize, + + /// For each block, bits valid on entry to the block. + on_entry: Vec>, + + /// The transfer function of each block expressed as the set of bits + /// generated and killed by executing the statements + terminator in the + /// block -- with one caveat. In particular, for *call terminators*, the + /// effect of storing the destination is not included, since that only takes + /// effect on the **success** edge (and not the unwind edge). + trans: Vec>, +} + impl AllSets { pub fn bits_per_block(&self) -> usize { self.bits_per_block } - pub fn for_block(&mut self, block_idx: usize) -> BlockSets<'_, E> { - BlockSets { - on_entry: &mut self.on_entry_sets[block_idx], - gen_set: &mut self.gen_sets[block_idx], - kill_set: &mut self.kill_sets[block_idx], - } + + pub fn get_mut(&mut self, block_idx: usize) -> (&mut BitSet, &mut GenKillSet) { + (&mut self.on_entry[block_idx], &mut self.trans[block_idx]) } - pub fn on_entry_set_for(&self, block_idx: usize) -> &BitSet { - &self.on_entry_sets[block_idx] + pub fn trans_for(&self, block_idx: usize) -> &GenKillSet { + &self.trans[block_idx] + } + pub fn trans_mut_for(&mut self, block_idx: usize) -> &mut GenKillSet { + &mut self.trans[block_idx] + } + pub fn entry_set_for(&self, block_idx: usize) -> &BitSet { + &self.on_entry[block_idx] + } + pub fn entry_set_mut_for(&mut self, block_idx: usize) -> &mut BitSet { + &mut self.on_entry[block_idx] } pub fn gen_set_for(&self, block_idx: usize) -> &HybridBitSet { - &self.gen_sets[block_idx] + &self.trans_for(block_idx).gen_set } pub fn kill_set_for(&self, block_idx: usize) -> &HybridBitSet { - &self.kill_sets[block_idx] + &self.trans_for(block_idx).kill_set } } /// Parameterization for the precise form of data flow that is used. -/// `InitialFlow` handles initializing the bitvectors before any -/// code is inspected by the analysis. Analyses that need more nuanced -/// initialization (e.g., they need to consult the results of some other -/// dataflow analysis to set up the initial bitvectors) should not -/// implement this. -pub trait InitialFlow { - /// Specifies the initial value for each bit in the `on_entry` set - fn bottom_value() -> bool; +/// +/// `BottomValue` determines whether the initial entry set for each basic block is empty or full. +/// This also determines the semantics of the lattice `join` operator used to merge dataflow +/// results, since dataflow works by starting at the bottom and moving monotonically to a fixed +/// point. +/// +/// This means, for propagation across the graph, that you either want to start at all-zeroes and +/// then use Union as your merge when propagating, or you start at all-ones and then use Intersect +/// as your merge when propagating. +pub trait BottomValue { + /// Specifies the initial value for each bit in the entry set for each basic block. + const BOTTOM_VALUE: bool; + + /// Merges `in_set` into `inout_set`, returning `true` if `inout_set` changed. + #[inline] + fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool { + if Self::BOTTOM_VALUE == false { + inout_set.union(in_set) + } else { + inout_set.intersect(in_set) + } + } } -pub trait BitDenotation<'tcx>: BitSetOperator { +/// A specific flavor of dataflow analysis. +/// +/// To run a dataflow analysis, one sets up an initial state for the +/// `START_BLOCK` via `start_block_effect` and a transfer function (`trans`) +/// for each block individually. The entry set for all other basic blocks is +/// initialized to `Self::BOTTOM_VALUE`. The dataflow analysis then +/// iteratively modifies the various entry sets (but leaves the the transfer +/// function unchanged). +pub trait BitDenotation<'tcx>: BottomValue { /// Specifies what index type is used to access the bitvector. type Idx: Idx; - /// Some analyses want to accumulate knowledge within a block when - /// analyzing its statements for building the gen/kill sets. Override - /// this method to return true in such cases. - /// - /// When this returns true, the statement-effect (re)construction - /// will clone the `on_entry` state and pass along a reference via - /// `sets.on_entry` to that local clone into `statement_effect` and - /// `terminator_effect`). - /// - /// When it's false, no local clone is constructed; instead a - /// reference directly into `on_entry` is passed along via - /// `sets.on_entry` instead, which represents the flow state at - /// the block's start, not necessarily the state immediately prior - /// to the statement/terminator under analysis. - /// - /// In either case, the passed reference is mutable, but this is a - /// wart from using the `BlockSets` type in the API; the intention - /// is that the `statement_effect` and `terminator_effect` methods - /// mutate only the gen/kill sets. - // - // FIXME: we should consider enforcing the intention described in - // the previous paragraph by passing the three sets in separate - // parameters to encode their distinct mutabilities. - fn accumulates_intrablock_state() -> bool { false } - /// A name describing the dataflow analysis that this /// `BitDenotation` is supporting. The name should be something /// suitable for plugging in as part of a filename (i.e., avoid @@ -616,7 +729,7 @@ pub trait BitDenotation<'tcx>: BitSetOperator { /// applied, in that order, before moving for the next /// statement. fn before_statement_effect(&self, - _sets: &mut BlockSets<'_, Self::Idx>, + _trans: &mut GenKillSet, _location: Location) {} /// Mutates the block-sets (the flow sets for the given @@ -630,7 +743,7 @@ pub trait BitDenotation<'tcx>: BitSetOperator { /// `bb_data` is the sequence of statements identified by `bb` in /// the MIR. fn statement_effect(&self, - sets: &mut BlockSets<'_, Self::Idx>, + trans: &mut GenKillSet, location: Location); /// Similar to `terminator_effect`, except it applies @@ -645,7 +758,7 @@ pub trait BitDenotation<'tcx>: BitSetOperator { /// applied, in that order, before moving for the next /// terminator. fn before_terminator_effect(&self, - _sets: &mut BlockSets<'_, Self::Idx>, + _trans: &mut GenKillSet, _location: Location) {} /// Mutates the block-sets (the flow sets for the given @@ -659,7 +772,7 @@ pub trait BitDenotation<'tcx>: BitSetOperator { /// The effects applied here cannot depend on which branch the /// terminator took. fn terminator_effect(&self, - sets: &mut BlockSets<'_, Self::Idx>, + trans: &mut GenKillSet, location: Location); /// Mutates the block-sets according to the (flow-dependent) @@ -692,29 +805,27 @@ pub trait BitDenotation<'tcx>: BitSetOperator { impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation<'tcx> { - pub fn new(mir: &'a Mir<'tcx>, + pub fn new(body: &'a Body<'tcx>, dead_unwinds: &'a BitSet, - denotation: D) -> Self where D: InitialFlow { + denotation: D) -> Self { let bits_per_block = denotation.bits_per_block(); - let num_blocks = mir.basic_blocks().len(); + let num_blocks = body.basic_blocks().len(); - let on_entry_sets = if D::bottom_value() { + let on_entry = if D::BOTTOM_VALUE == true { vec![BitSet::new_filled(bits_per_block); num_blocks] } else { vec![BitSet::new_empty(bits_per_block); num_blocks] }; - let gen_sets = vec![HybridBitSet::new_empty(bits_per_block); num_blocks]; - let kill_sets = gen_sets.clone(); + let nop = GenKill::from_elem(HybridBitSet::new_empty(bits_per_block)); DataflowAnalysis { - mir, + body, dead_unwinds, flow_state: DataflowState { sets: AllSets { bits_per_block, - on_entry_sets, - gen_sets, - kill_sets, + on_entry, + trans: vec![nop; num_blocks], }, operator: denotation, } @@ -722,7 +833,10 @@ impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation<'tcx> } } -impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation<'tcx> { +impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> +where + D: BitDenotation<'tcx>, +{ /// Propagates the bits of `in_out` into all the successors of `bb`, /// using bitwise operator denoted by `self.operator`. /// @@ -790,11 +904,9 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation<'tcx> self.propagate_bits_into_entry_set_for(in_out, dest_bb, dirty_list); } } - mir::TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => { + mir::TerminatorKind::FalseEdges { real_target, imaginary_target } => { self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list); - for target in imaginary_targets { - self.propagate_bits_into_entry_set_for(in_out, *target, dirty_list); - } + self.propagate_bits_into_entry_set_for(in_out, imaginary_target, dirty_list); } mir::TerminatorKind::FalseUnwind { real_target, unwind } => { self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list); @@ -811,7 +923,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation<'tcx> in_out: &BitSet, bb: mir::BasicBlock, dirty_queue: &mut WorkQueue) { - let entry_set = &mut self.flow_state.sets.for_block(bb.index()).on_entry; + let entry_set = self.flow_state.sets.entry_set_mut_for(bb.index()); let set_changed = self.flow_state.operator.join(entry_set, &in_out); if set_changed { dirty_queue.insert(bb); diff --git a/src/librustc_mir/dataflow/move_paths/abs_domain.rs b/src/librustc_mir/dataflow/move_paths/abs_domain.rs index 6dcc0325ec1ac..b26547c4ff77e 100644 --- a/src/librustc_mir/dataflow/move_paths/abs_domain.rs +++ b/src/librustc_mir/dataflow/move_paths/abs_domain.rs @@ -18,8 +18,7 @@ use rustc::ty::Ty; pub struct AbstractOperand; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct AbstractType; -pub type AbstractElem<'tcx> = - ProjectionElem<'tcx, AbstractOperand, AbstractType>; +pub type AbstractElem = ProjectionElem; pub trait Lift { type Abstract; @@ -38,7 +37,7 @@ impl<'tcx> Lift for Ty<'tcx> { fn lift(&self) -> Self::Abstract { AbstractType } } impl<'tcx> Lift for PlaceElem<'tcx> { - type Abstract = AbstractElem<'tcx>; + type Abstract = AbstractElem; fn lift(&self) -> Self::Abstract { match *self { ProjectionElem::Deref => @@ -56,7 +55,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> { from_end, }, ProjectionElem::Downcast(a, u) => - ProjectionElem::Downcast(a.clone(), u.clone()), + ProjectionElem::Downcast(a, u.clone()), } } } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 7a9140bce6288..f282c276e0926 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -12,34 +12,34 @@ use super::{LocationMap, MoveData, MovePath, MovePathLookup, MovePathIndex, Move use super::{MoveError, InitIndex, Init, InitLocation, LookupResult, InitKind}; use super::IllegalMoveOriginKind::*; -struct MoveDataBuilder<'a, 'gcx: 'tcx, 'tcx: 'a> { - mir: &'a Mir<'tcx>, - tcx: TyCtxt<'a, 'gcx, 'tcx>, +struct MoveDataBuilder<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, data: MoveData<'tcx>, errors: Vec<(Place<'tcx>, MoveError<'tcx>)>, } -impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> { - fn new(mir: &'a Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self { +impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { + fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>) -> Self { let mut move_paths = IndexVec::new(); let mut path_map = IndexVec::new(); let mut init_path_map = IndexVec::new(); MoveDataBuilder { - mir, + body, tcx, errors: Vec::new(), data: MoveData { moves: IndexVec::new(), - loc_map: LocationMap::new(mir), + loc_map: LocationMap::new(body), rev_lookup: MovePathLookup { - locals: mir.local_decls.indices().map(PlaceBase::Local).map(|v| { + locals: body.local_decls.indices().map(|i| { Self::new_move_path( &mut move_paths, &mut path_map, &mut init_path_map, None, - Place::Base(v), + Place::from(i), ) }).collect(), projections: Default::default(), @@ -47,7 +47,7 @@ impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> { move_paths, path_map, inits: IndexVec::new(), - init_loc_map: LocationMap::new(mir), + init_loc_map: LocationMap::new(body), init_path_map, } } @@ -83,7 +83,7 @@ impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> { } } -impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { +impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { /// This creates a MovePath for a given place, returning an `MovePathError` /// if that place can't be moved from. /// @@ -95,16 +95,80 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { -> Result> { debug!("lookup({:?})", place); - match *place { - Place::Base(PlaceBase::Local(local)) => Ok(self.builder.data.rev_lookup.locals[local]), - Place::Base(PlaceBase::Promoted(..)) | - Place::Base(PlaceBase::Static(..)) => { - Err(MoveError::cannot_move_out_of(self.loc, Static)) - } - Place::Projection(ref proj) => { - self.move_path_for_projection(place, proj) + place.iterate(|place_base, place_projection| { + let mut base = match place_base { + PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[*local], + PlaceBase::Static(..) => { + return Err(MoveError::cannot_move_out_of(self.loc, Static)); + } + }; + + for proj in place_projection { + let body = self.builder.body; + let tcx = self.builder.tcx; + let place_ty = proj.base.ty(body, tcx).ty; + match place_ty.sty { + ty::Ref(..) | ty::RawPtr(..) => + return Err(MoveError::cannot_move_out_of( + self.loc, + BorrowedContent { + target_place: Place::Projection(Box::new(proj.clone())), + })), + ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => + return Err(MoveError::cannot_move_out_of(self.loc, + InteriorOfTypeWithDestructor { + container_ty: place_ty + })), + // move out of union - always move the entire union + ty::Adt(adt, _) if adt.is_union() => + return Err(MoveError::UnionMove { path: base }), + ty::Slice(_) => + return Err(MoveError::cannot_move_out_of( + self.loc, + InteriorOfSliceOrArray { + ty: place_ty, is_index: match proj.elem { + ProjectionElem::Index(..) => true, + _ => false + }, + })), + ty::Array(..) => match proj.elem { + ProjectionElem::Index(..) => + return Err(MoveError::cannot_move_out_of( + self.loc, + InteriorOfSliceOrArray { + ty: place_ty, is_index: true + })), + _ => { + // FIXME: still badly broken + } + }, + _ => {} + }; + + base = match self + .builder + .data + .rev_lookup + .projections + .entry((base, proj.elem.lift())) + { + Entry::Occupied(ent) => *ent.get(), + Entry::Vacant(ent) => { + let path = MoveDataBuilder::new_move_path( + &mut self.builder.data.move_paths, + &mut self.builder.data.path_map, + &mut self.builder.data.init_path_map, + Some(base), + Place::Projection(Box::new(proj.clone())), + ); + ent.insert(path); + path + } + }; } - } + + Ok(base) + }) } fn create_move_path(&mut self, place: &Place<'tcx>) { @@ -112,78 +176,18 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { // drop), so this not being a valid move path is OK. let _ = self.move_path_for(place); } - - fn move_path_for_projection(&mut self, - place: &Place<'tcx>, - proj: &PlaceProjection<'tcx>) - -> Result> - { - let base = self.move_path_for(&proj.base)?; - let mir = self.builder.mir; - let tcx = self.builder.tcx; - let place_ty = proj.base.ty(mir, tcx).to_ty(tcx); - match place_ty.sty { - ty::Ref(..) | ty::RawPtr(..) => - return Err(MoveError::cannot_move_out_of( - self.loc, - BorrowedContent { target_place: place.clone() })), - ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => - return Err(MoveError::cannot_move_out_of(self.loc, - InteriorOfTypeWithDestructor { - container_ty: place_ty - })), - // move out of union - always move the entire union - ty::Adt(adt, _) if adt.is_union() => - return Err(MoveError::UnionMove { path: base }), - ty::Slice(_) => - return Err(MoveError::cannot_move_out_of( - self.loc, - InteriorOfSliceOrArray { - ty: place_ty, is_index: match proj.elem { - ProjectionElem::Index(..) => true, - _ => false - }, - })), - ty::Array(..) => match proj.elem { - ProjectionElem::Index(..) => - return Err(MoveError::cannot_move_out_of( - self.loc, - InteriorOfSliceOrArray { - ty: place_ty, is_index: true - })), - _ => { - // FIXME: still badly broken - } - }, - _ => {} - }; - match self.builder.data.rev_lookup.projections.entry((base, proj.elem.lift())) { - Entry::Occupied(ent) => Ok(*ent.get()), - Entry::Vacant(ent) => { - let path = MoveDataBuilder::new_move_path( - &mut self.builder.data.move_paths, - &mut self.builder.data.path_map, - &mut self.builder.data.init_path_map, - Some(base), - place.clone() - ); - ent.insert(path); - Ok(path) - } - } - } } -impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { fn finalize( self ) -> Result, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> { debug!("{}", { - debug!("moves for {:?}:", self.mir.span); + debug!("moves for {:?}:", self.body.span); for (j, mo) in self.data.moves.iter_enumerated() { debug!(" {:?} = {:?}", j, mo); } - debug!("move paths for {:?}:", self.mir.span); + debug!("move paths for {:?}:", self.body.span); for (j, path) in self.data.move_paths.iter_enumerated() { debug!(" {:?} = {:?}", j, path); } @@ -198,15 +202,15 @@ impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> { } } -pub(super) fn gather_moves<'a, 'gcx, 'tcx>( - mir: &Mir<'tcx>, - tcx: TyCtxt<'a, 'gcx, 'tcx> +pub(super) fn gather_moves<'tcx>( + body: &Body<'tcx>, + tcx: TyCtxt<'tcx>, ) -> Result, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> { - let mut builder = MoveDataBuilder::new(mir, tcx); + let mut builder = MoveDataBuilder::new(body, tcx); builder.gather_args(); - for (bb, block) in mir.basic_blocks().iter_enumerated() { + for (bb, block) in body.basic_blocks().iter_enumerated() { for (i, stmt) in block.statements.iter().enumerate() { let source = Location { block: bb, statement_index: i }; builder.gather_statement(source, stmt); @@ -222,9 +226,9 @@ pub(super) fn gather_moves<'a, 'gcx, 'tcx>( builder.finalize() } -impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { fn gather_args(&mut self) { - for arg in self.mir.args_iter() { + for arg in self.body.args_iter() { let path = self.data.rev_lookup.locals[arg]; let init = self.data.inits.push(Init { @@ -249,12 +253,12 @@ impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> { } } -struct Gatherer<'b, 'a: 'b, 'gcx: 'tcx, 'tcx: 'a> { - builder: &'b mut MoveDataBuilder<'a, 'gcx, 'tcx>, +struct Gatherer<'b, 'a, 'tcx> { + builder: &'b mut MoveDataBuilder<'a, 'tcx>, loc: Location, } -impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { +impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_statement(&mut self, stmt: &Statement<'tcx>) { match stmt.kind { StatementKind::Assign(ref place, ref rval) => { @@ -273,19 +277,19 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { StatementKind::FakeRead(_, ref place) => { self.create_move_path(place); } - StatementKind::InlineAsm { ref outputs, ref inputs, ref asm } => { - for (output, kind) in outputs.iter().zip(&asm.outputs) { + StatementKind::InlineAsm(ref asm) => { + for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) { if !kind.is_indirect { self.gather_init(output, InitKind::Deep); } } - for (_, input) in inputs.iter() { + for (_, input) in asm.inputs.iter() { self.gather_operand(input); } } StatementKind::StorageLive(_) => {} StatementKind::StorageDead(local) => { - self.gather_move(&Place::Base(PlaceBase::Local(local))); + self.gather_move(&Place::from(local)); } StatementKind::SetDiscriminant{ .. } => { span_bug!(stmt.source_info.span, @@ -425,8 +429,8 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { Place::Projection(box Projection { base, elem: ProjectionElem::Field(_, _), - }) if match base.ty(self.builder.mir, self.builder.tcx).to_ty(self.builder.tcx).sty { - ty::TyKind::Adt(def, _) if def.is_union() => true, + }) if match base.ty(self.builder.body, self.builder.tcx).ty.sty { + ty::Adt(def, _) if def.is_union() => true, _ => false, } => base, // Otherwise, lookup the place. diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 0c29ea8ab4afa..938450c63aefc 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -1,7 +1,7 @@ -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{Ty, TyCtxt}; use rustc::mir::*; use rustc::util::nodemap::FxHashMap; -use rustc_data_structures::indexed_vec::{IndexVec}; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use smallvec::SmallVec; use syntax_pos::{Span}; @@ -12,54 +12,23 @@ use self::abs_domain::{AbstractElem, Lift}; mod abs_domain; -// This submodule holds some newtype'd Index wrappers that are using -// NonZero to ensure that Option occupies only a single word. -// They are in a submodule to impose privacy restrictions; namely, to -// ensure that other code does not accidentally access `index.0` -// (which is likely to yield a subtle off-by-one error). -pub(crate) mod indexes { - use std::fmt; - use std::num::NonZeroUsize; - use rustc_data_structures::indexed_vec::Idx; - - macro_rules! new_index { - ($Index:ident, $debug_name:expr) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] - pub struct $Index(NonZeroUsize); - - impl Idx for $Index { - fn new(idx: usize) -> Self { - $Index(NonZeroUsize::new(idx + 1).unwrap()) - } - fn index(self) -> usize { - self.0.get() - 1 - } - } - - impl fmt::Debug for $Index { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{}{}", $debug_name, self.index()) - } - } - } +newtype_index! { + pub struct MovePathIndex { + DEBUG_FORMAT = "mp{}" } +} - /// Index into MovePathData.move_paths - new_index!(MovePathIndex, "mp"); - - /// Index into MoveData.moves. - new_index!(MoveOutIndex, "mo"); - - /// Index into MoveData.inits. - new_index!(InitIndex, "in"); - - /// Index into Borrows.locations - new_index!(BorrowIndex, "bw"); +newtype_index! { + pub struct MoveOutIndex { + DEBUG_FORMAT = "mo{}" + } } -pub use self::indexes::MovePathIndex; -pub use self::indexes::MoveOutIndex; -pub use self::indexes::InitIndex; +newtype_index! { + pub struct InitIndex { + DEBUG_FORMAT = "in{}" + } +} impl MoveOutIndex { pub fn move_path_index(&self, move_data: &MoveData<'_>) -> MovePathIndex { @@ -136,7 +105,7 @@ pub struct MoveData<'tcx> { /// particular path being moved.) pub loc_map: LocationMap>, pub path_map: IndexVec>, - pub rev_lookup: MovePathLookup<'tcx>, + pub rev_lookup: MovePathLookup, pub inits: IndexVec, /// Each Location `l` is mapped to the Inits that are effects /// of executing the code at `l`. @@ -169,9 +138,9 @@ impl IndexMut for LocationMap { } impl LocationMap where T: Default + Clone { - fn new(mir: &Mir<'_>) -> Self { + fn new(body: &Body<'_>) -> Self { LocationMap { - map: mir.basic_blocks().iter().map(|block| { + map: body.basic_blocks().iter().map(|block| { vec![T::default(); block.statements.len()+1] }).collect() } @@ -236,17 +205,17 @@ impl fmt::Debug for Init { } impl Init { - crate fn span<'gcx>(&self, mir: &Mir<'gcx>) -> Span { + crate fn span<'tcx>(&self, body: &Body<'tcx>) -> Span { match self.location { - InitLocation::Argument(local) => mir.local_decls[local].source_info.span, - InitLocation::Statement(location) => mir.source_info(location).span, + InitLocation::Argument(local) => body.local_decls[local].source_info.span, + InitLocation::Statement(location) => body.source_info(location).span, } } } /// Tables mapping from a place to its MovePathIndex. #[derive(Debug)] -pub struct MovePathLookup<'tcx> { +pub struct MovePathLookup { locals: IndexVec, /// projections are made from a base-place and a projection @@ -255,7 +224,7 @@ pub struct MovePathLookup<'tcx> { /// subsequent search so that it is solely relative to that /// base-place). For the remaining lookup, we map the projection /// elem to the associated MovePathIndex. - projections: FxHashMap<(MovePathIndex, AbstractElem<'tcx>), MovePathIndex> + projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex> } mod builder; @@ -266,28 +235,28 @@ pub enum LookupResult { Parent(Option) } -impl<'tcx> MovePathLookup<'tcx> { +impl MovePathLookup { // Unlike the builder `fn move_path_for` below, this lookup // alternative will *not* create a MovePath on the fly for an // unknown place, but will rather return the nearest available // parent. pub fn find(&self, place: &Place<'tcx>) -> LookupResult { - match *place { - Place::Base(PlaceBase::Local(local)) => LookupResult::Exact(self.locals[local]), - Place::Base(PlaceBase::Promoted(_)) | - Place::Base(PlaceBase::Static(..)) => LookupResult::Parent(None), - Place::Projection(ref proj) => { - match self.find(&proj.base) { - LookupResult::Exact(base_path) => { - match self.projections.get(&(base_path, proj.elem.lift())) { - Some(&subpath) => LookupResult::Exact(subpath), - None => LookupResult::Parent(Some(base_path)) - } - } - inexact => inexact + place.iterate(|place_base, place_projection| { + let mut result = match place_base { + PlaceBase::Local(local) => self.locals[*local], + PlaceBase::Static(..) => return LookupResult::Parent(None), + }; + + for proj in place_projection { + if let Some(&subpath) = self.projections.get(&(result, proj.elem.lift())) { + result = subpath; + } else { + return LookupResult::Parent(Some(result)); } } - } + + LookupResult::Exact(result) + }) } pub fn find_local(&self, local: Local) -> MovePathIndex { @@ -317,10 +286,10 @@ pub(crate) enum IllegalMoveOriginKind<'tcx> { /// implements `Drop`. Rust maintains invariant that all `Drop` /// ADT's remain fully-initialized so that user-defined destructor /// can safely read from all of the ADT's fields. - InteriorOfTypeWithDestructor { container_ty: ty::Ty<'tcx> }, + InteriorOfTypeWithDestructor { container_ty: Ty<'tcx> }, /// Illegal move due to attempt to move out of a slice or array. - InteriorOfSliceOrArray { ty: ty::Ty<'tcx>, is_index: bool, }, + InteriorOfSliceOrArray { ty: Ty<'tcx>, is_index: bool, }, } #[derive(Debug)] @@ -336,10 +305,12 @@ impl<'tcx> MoveError<'tcx> { } } -impl<'a, 'gcx, 'tcx> MoveData<'tcx> { - pub fn gather_moves(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) - -> Result, MoveError<'tcx>)>)> { - builder::gather_moves(mir, tcx) +impl<'tcx> MoveData<'tcx> { + pub fn gather_moves( + body: &Body<'tcx>, + tcx: TyCtxt<'tcx>, + ) -> Result, MoveError<'tcx>)>)> { + builder::gather_moves(body, tcx) } /// For the move path `mpi`, returns the root local variable (if any) that starts the path. diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs deleted file mode 100644 index e1b66312da2d3..0000000000000 --- a/src/librustc_mir/diagnostics.rs +++ /dev/null @@ -1,2425 +0,0 @@ -#![allow(non_snake_case)] - -register_long_diagnostics! { - - -E0001: r##" -#### Note: this error code is no longer emitted by the compiler. - -This error suggests that the expression arm corresponding to the noted pattern -will never be reached as for all possible values of the expression being -matched, one of the preceding patterns will match. - -This means that perhaps some of the preceding patterns are too general, this -one is too specific or the ordering is incorrect. - -For example, the following `match` block has too many arms: - -``` -match Some(0) { - Some(bar) => {/* ... */} - x => {/* ... */} // This handles the `None` case - _ => {/* ... */} // All possible cases have already been handled -} -``` - -`match` blocks have their patterns matched in order, so, for example, putting -a wildcard arm above a more specific arm will make the latter arm irrelevant. - -Ensure the ordering of the match arm is correct and remove any superfluous -arms. -"##, - -E0002: r##" -#### Note: this error code is no longer emitted by the compiler. - -This error indicates that an empty match expression is invalid because the type -it is matching on is non-empty (there exist values of this type). In safe code -it is impossible to create an instance of an empty type, so empty match -expressions are almost never desired. This error is typically fixed by adding -one or more cases to the match expression. - -An example of an empty type is `enum Empty { }`. So, the following will work: - -``` -enum Empty {} - -fn foo(x: Empty) { - match x { - // empty - } -} -``` - -However, this won't: - -```compile_fail -fn foo(x: Option) { - match x { - // empty - } -} -``` -"##, - -E0004: r##" -This error indicates that the compiler cannot guarantee a matching pattern for -one or more possible inputs to a match expression. Guaranteed matches are -required in order to assign values to match expressions, or alternatively, -determine the flow of execution. Erroneous code example: - -```compile_fail,E0004 -enum Terminator { - HastaLaVistaBaby, - TalkToMyHand, -} - -let x = Terminator::HastaLaVistaBaby; - -match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered - Terminator::TalkToMyHand => {} -} -``` - -If you encounter this error you must alter your patterns so that every possible -value of the input type is matched. For types with a small number of variants -(like enums) you should probably cover all cases explicitly. Alternatively, the -underscore `_` wildcard pattern can be added after all other patterns to match -"anything else". Example: - -``` -enum Terminator { - HastaLaVistaBaby, - TalkToMyHand, -} - -let x = Terminator::HastaLaVistaBaby; - -match x { - Terminator::TalkToMyHand => {} - Terminator::HastaLaVistaBaby => {} -} - -// or: - -match x { - Terminator::TalkToMyHand => {} - _ => {} -} -``` -"##, - -E0005: r##" -Patterns used to bind names must be irrefutable, that is, they must guarantee -that a name will be extracted in all cases. Erroneous code example: - -```compile_fail,E0005 -let x = Some(1); -let Some(y) = x; -// error: refutable pattern in local binding: `None` not covered -``` - -If you encounter this error you probably need to use a `match` or `if let` to -deal with the possibility of failure. Example: - -``` -let x = Some(1); - -match x { - Some(y) => { - // do something - }, - None => {} -} - -// or: - -if let Some(y) = x { - // do something -} -``` -"##, - -E0007: r##" -This error indicates that the bindings in a match arm would require a value to -be moved into more than one location, thus violating unique ownership. Code -like the following is invalid as it requires the entire `Option` to be -moved into a variable called `op_string` while simultaneously requiring the -inner `String` to be moved into a variable called `s`. - -```compile_fail,E0007 -let x = Some("s".to_string()); - -match x { - op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings - None => {}, -} -``` - -See also the error E0303. -"##, - -E0008: r##" -Names bound in match arms retain their type in pattern guards. As such, if a -name is bound by move in a pattern, it should also be moved to wherever it is -referenced in the pattern guard code. Doing so however would prevent the name -from being available in the body of the match arm. Consider the following: - -```compile_fail,E0008 -match Some("hi".to_string()) { - Some(s) if s.len() == 0 => {}, // use s. - _ => {}, -} -``` - -The variable `s` has type `String`, and its use in the guard is as a variable of -type `String`. The guard code effectively executes in a separate scope to the -body of the arm, so the value would be moved into this anonymous scope and -therefore becomes unavailable in the body of the arm. - -The problem above can be solved by using the `ref` keyword. - -``` -match Some("hi".to_string()) { - Some(ref s) if s.len() == 0 => {}, - _ => {}, -} -``` - -Though this example seems innocuous and easy to solve, the problem becomes clear -when it encounters functions which consume the value: - -```compile_fail,E0008 -struct A{} - -impl A { - fn consume(self) -> usize { - 0 - } -} - -fn main() { - let a = Some(A{}); - match a { - Some(y) if y.consume() > 0 => {} - _ => {} - } -} -``` - -In this situation, even the `ref` keyword cannot solve it, since borrowed -content cannot be moved. This problem cannot be solved generally. If the value -can be cloned, here is a not-so-specific solution: - -``` -#[derive(Clone)] -struct A{} - -impl A { - fn consume(self) -> usize { - 0 - } -} - -fn main() { - let a = Some(A{}); - match a{ - Some(ref y) if y.clone().consume() > 0 => {} - _ => {} - } -} -``` - -If the value will be consumed in the pattern guard, using its clone will not -move its ownership, so the code works. -"##, - -E0009: r##" -In a pattern, all values that don't implement the `Copy` trait have to be bound -the same way. The goal here is to avoid binding simultaneously by-move and -by-ref. - -This limitation may be removed in a future version of Rust. - -Erroneous code example: - -```compile_fail,E0009 -struct X { x: (), } - -let x = Some((X { x: () }, X { x: () })); -match x { - Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the - // same pattern - None => panic!() -} -``` - -You have two solutions: - -Solution #1: Bind the pattern's values the same way. - -``` -struct X { x: (), } - -let x = Some((X { x: () }, X { x: () })); -match x { - Some((ref y, ref z)) => {}, - // or Some((y, z)) => {} - None => panic!() -} -``` - -Solution #2: Implement the `Copy` trait for the `X` structure. - -However, please keep in mind that the first solution should be preferred. - -``` -#[derive(Clone, Copy)] -struct X { x: (), } - -let x = Some((X { x: () }, X { x: () })); -match x { - Some((y, ref z)) => {}, - None => panic!() -} -``` -"##, - -E0030: r##" -When matching against a range, the compiler verifies that the range is -non-empty. Range patterns include both end-points, so this is equivalent to -requiring the start of the range to be less than or equal to the end of the -range. - -For example: - -```compile_fail -match 5u32 { - // This range is ok, albeit pointless. - 1 ..= 1 => {} - // This range is empty, and the compiler can tell. - 1000 ..= 5 => {} -} -``` -"##, - -E0158: r##" -`const` and `static` mean different things. A `const` is a compile-time -constant, an alias for a literal value. This property means you can match it -directly within a pattern. - -The `static` keyword, on the other hand, guarantees a fixed location in memory. -This does not always mean that the value is constant. For example, a global -mutex can be declared `static` as well. - -If you want to match against a `static`, consider using a guard instead: - -``` -static FORTY_TWO: i32 = 42; - -match Some(42) { - Some(x) if x == FORTY_TWO => {} - _ => {} -} -``` -"##, - -E0162: r##" -#### Note: this error code is no longer emitted by the compiler. - -An if-let pattern attempts to match the pattern, and enters the body if the -match was successful. If the match is irrefutable (when it cannot fail to -match), use a regular `let`-binding instead. For instance: - -```compile_pass -struct Irrefutable(i32); -let irr = Irrefutable(0); - -// This fails to compile because the match is irrefutable. -if let Irrefutable(x) = irr { - // This body will always be executed. - // ... -} -``` - -Try this instead: - -``` -struct Irrefutable(i32); -let irr = Irrefutable(0); - -let Irrefutable(x) = irr; -println!("{}", x); -``` -"##, - -E0165: r##" -#### Note: this error code is no longer emitted by the compiler. - -A while-let pattern attempts to match the pattern, and enters the body if the -match was successful. If the match is irrefutable (when it cannot fail to -match), use a regular `let`-binding inside a `loop` instead. For instance: - -```compile_pass,no_run -struct Irrefutable(i32); -let irr = Irrefutable(0); - -// This fails to compile because the match is irrefutable. -while let Irrefutable(x) = irr { - // ... -} -``` - -Try this instead: - -```no_run -struct Irrefutable(i32); -let irr = Irrefutable(0); - -loop { - let Irrefutable(x) = irr; - // ... -} -``` -"##, - -E0170: r##" -Enum variants are qualified by default. For example, given this type: - -``` -enum Method { - GET, - POST, -} -``` - -You would match it using: - -``` -enum Method { - GET, - POST, -} - -let m = Method::GET; - -match m { - Method::GET => {}, - Method::POST => {}, -} -``` - -If you don't qualify the names, the code will bind new variables named "GET" and -"POST" instead. This behavior is likely not what you want, so `rustc` warns when -that happens. - -Qualified names are good practice, and most code works well with them. But if -you prefer them unqualified, you can import the variants into scope: - -``` -use Method::*; -enum Method { GET, POST } -# fn main() {} -``` - -If you want others to be able to import variants from your module directly, use -`pub use`: - -``` -pub use Method::*; -pub enum Method { GET, POST } -# fn main() {} -``` -"##, - - -E0297: r##" -#### Note: this error code is no longer emitted by the compiler. - -Patterns used to bind names must be irrefutable. That is, they must guarantee -that a name will be extracted in all cases. Instead of pattern matching the -loop variable, consider using a `match` or `if let` inside the loop body. For -instance: - -```compile_fail,E0005 -let xs : Vec> = vec![Some(1), None]; - -// This fails because `None` is not covered. -for Some(x) in xs { - // ... -} -``` - -Match inside the loop instead: - -``` -let xs : Vec> = vec![Some(1), None]; - -for item in xs { - match item { - Some(x) => {}, - None => {}, - } -} -``` - -Or use `if let`: - -``` -let xs : Vec> = vec![Some(1), None]; - -for item in xs { - if let Some(x) = item { - // ... - } -} -``` -"##, - -E0301: r##" -Mutable borrows are not allowed in pattern guards, because matching cannot have -side effects. Side effects could alter the matched object or the environment -on which the match depends in such a way, that the match would not be -exhaustive. For instance, the following would not match any arm if mutable -borrows were allowed: - -```compile_fail,E0301 -match Some(()) { - None => { }, - option if option.take().is_none() => { - /* impossible, option is `Some` */ - }, - Some(_) => { } // When the previous match failed, the option became `None`. -} -``` -"##, - -E0302: r##" -Assignments are not allowed in pattern guards, because matching cannot have -side effects. Side effects could alter the matched object or the environment -on which the match depends in such a way, that the match would not be -exhaustive. For instance, the following would not match any arm if assignments -were allowed: - -```compile_fail,E0302 -match Some(()) { - None => { }, - option if { option = None; false } => { }, - Some(_) => { } // When the previous match failed, the option became `None`. -} -``` -"##, - -E0303: r##" -In certain cases it is possible for sub-bindings to violate memory safety. -Updates to the borrow checker in a future version of Rust may remove this -restriction, but for now patterns must be rewritten without sub-bindings. - -Before: - -```compile_fail,E0303 -match Some("hi".to_string()) { - ref op_string_ref @ Some(s) => {}, - None => {}, -} -``` - -After: - -``` -match Some("hi".to_string()) { - Some(ref s) => { - let op_string_ref = &Some(s); - // ... - }, - None => {}, -} -``` - -The `op_string_ref` binding has type `&Option<&String>` in both cases. - -See also https://github.com/rust-lang/rust/issues/14587 -"##, - -E0010: r##" -The value of statics and constants must be known at compile time, and they live -for the entire lifetime of a program. Creating a boxed value allocates memory on -the heap at runtime, and therefore cannot be done at compile time. Erroneous -code example: - -```compile_fail,E0010 -#![feature(box_syntax)] - -const CON : Box = box 0; -``` -"##, - -E0013: r##" -Static and const variables can refer to other const variables. But a const -variable cannot refer to a static variable. For example, `Y` cannot refer to -`X` here: - -```compile_fail,E0013 -static X: i32 = 42; -const Y: i32 = X; -``` - -To fix this, the value can be extracted as a const and then used: - -``` -const A: i32 = 42; -static X: i32 = A; -const Y: i32 = A; -``` -"##, - -// FIXME(#57563) Change the language here when const fn stabilizes -E0015: r##" -The only functions that can be called in static or constant expressions are -`const` functions, and struct/enum constructors. `const` functions are only -available on a nightly compiler. Rust currently does not support more general -compile-time function execution. - -``` -const FOO: Option = Some(1); // enum constructor -struct Bar {x: u8} -const BAR: Bar = Bar {x: 1}; // struct constructor -``` - -See [RFC 911] for more details on the design of `const fn`s. - -[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md -"##, - -E0017: r##" -References in statics and constants may only refer to immutable values. -Erroneous code example: - -```compile_fail,E0017 -static X: i32 = 1; -const C: i32 = 2; - -// these three are not allowed: -const CR: &mut i32 = &mut C; -static STATIC_REF: &'static mut i32 = &mut X; -static CONST_REF: &'static mut i32 = &mut C; -``` - -Statics are shared everywhere, and if they refer to mutable data one might -violate memory safety since holding multiple mutable references to shared data -is not allowed. - -If you really want global mutable state, try using `static mut` or a global -`UnsafeCell`. -"##, - -E0019: r##" -A function call isn't allowed in the const's initialization expression -because the expression's value must be known at compile-time. Erroneous code -example: - -```compile_fail -enum Test { - V1 -} - -impl Test { - fn test(&self) -> i32 { - 12 - } -} - -fn main() { - const FOO: Test = Test::V1; - - const A: i32 = FOO.test(); // You can't call Test::func() here! -} -``` - -Remember: you can't use a function call inside a const's initialization -expression! However, you can totally use it anywhere else: - -``` -enum Test { - V1 -} - -impl Test { - fn func(&self) -> i32 { - 12 - } -} - -fn main() { - const FOO: Test = Test::V1; - - FOO.func(); // here is good - let x = FOO.func(); // or even here! -} -``` -"##, - -E0133: r##" -Unsafe code was used outside of an unsafe function or block. - -Erroneous code example: - -```compile_fail,E0133 -unsafe fn f() { return; } // This is the unsafe code - -fn main() { - f(); // error: call to unsafe function requires unsafe function or block -} -``` - -Using unsafe functionality is potentially dangerous and disallowed by safety -checks. Examples: - -* Dereferencing raw pointers -* Calling functions via FFI -* Calling functions marked unsafe - -These safety checks can be relaxed for a section of the code by wrapping the -unsafe instructions with an `unsafe` block. For instance: - -``` -unsafe fn f() { return; } - -fn main() { - unsafe { f(); } // ok! -} -``` - -See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html -"##, - -E0373: r##" -This error occurs when an attempt is made to use data captured by a closure, -when that data may no longer exist. It's most commonly seen when attempting to -return a closure: - -```compile_fail,E0373 -fn foo() -> Box u32> { - let x = 0u32; - Box::new(|y| x + y) -} -``` - -Notice that `x` is stack-allocated by `foo()`. By default, Rust captures -closed-over data by reference. This means that once `foo()` returns, `x` no -longer exists. An attempt to access `x` within the closure would thus be -unsafe. - -Another situation where this might be encountered is when spawning threads: - -```compile_fail,E0373 -fn foo() { - let x = 0u32; - let y = 1u32; - - let thr = std::thread::spawn(|| { - x + y - }); -} -``` - -Since our new thread runs in parallel, the stack frame containing `x` and `y` -may well have disappeared by the time we try to use them. Even if we call -`thr.join()` within foo (which blocks until `thr` has completed, ensuring the -stack frame won't disappear), we will not succeed: the compiler cannot prove -that this behaviour is safe, and so won't let us do it. - -The solution to this problem is usually to switch to using a `move` closure. -This approach moves (or copies, where possible) data into the closure, rather -than taking references to it. For example: - -``` -fn foo() -> Box u32> { - let x = 0u32; - Box::new(move |y| x + y) -} -``` - -Now that the closure has its own copy of the data, there's no need to worry -about safety. -"##, - -E0381: r##" -It is not allowed to use or capture an uninitialized variable. For example: - -```compile_fail,E0381 -fn main() { - let x: i32; - let y = x; // error, use of possibly uninitialized variable -} -``` - -To fix this, ensure that any declared variables are initialized before being -used. Example: - -``` -fn main() { - let x: i32 = 0; - let y = x; // ok! -} -``` -"##, - -E0382: r##" -This error occurs when an attempt is made to use a variable after its contents -have been moved elsewhere. For example: - -```compile_fail,E0382 -struct MyStruct { s: u32 } - -fn main() { - let mut x = MyStruct{ s: 5u32 }; - let y = x; - x.s = 6; - println!("{}", x.s); -} -``` - -Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out -of `x` when we set `y`. This is fundamental to Rust's ownership system: outside -of workarounds like `Rc`, a value cannot be owned by more than one variable. - -Sometimes we don't need to move the value. Using a reference, we can let another -function borrow the value without changing its ownership. In the example below, -we don't actually have to move our string to `calculate_length`, we can give it -a reference to it with `&` instead. - -``` -fn main() { - let s1 = String::from("hello"); - - let len = calculate_length(&s1); - - println!("The length of '{}' is {}.", s1, len); -} - -fn calculate_length(s: &String) -> usize { - s.len() -} -``` - -A mutable reference can be created with `&mut`. - -Sometimes we don't want a reference, but a duplicate. All types marked `Clone` -can be duplicated by calling `.clone()`. Subsequent changes to a clone do not -affect the original variable. - -Most types in the standard library are marked `Clone`. The example below -demonstrates using `clone()` on a string. `s1` is first set to "many", and then -copied to `s2`. Then the first character of `s1` is removed, without affecting -`s2`. "any many" is printed to the console. - -``` -fn main() { - let mut s1 = String::from("many"); - let s2 = s1.clone(); - s1.remove(0); - println!("{} {}", s1, s2); -} -``` - -If we control the definition of a type, we can implement `Clone` on it ourselves -with `#[derive(Clone)]`. - -Some types have no ownership semantics at all and are trivial to duplicate. An -example is `i32` and the other number types. We don't have to call `.clone()` to -clone them, because they are marked `Copy` in addition to `Clone`. Implicit -cloning is more convenient in this case. We can mark our own types `Copy` if -all their members also are marked `Copy`. - -In the example below, we implement a `Point` type. Because it only stores two -integers, we opt-out of ownership semantics with `Copy`. Then we can -`let p2 = p1` without `p1` being moved. - -``` -#[derive(Copy, Clone)] -struct Point { x: i32, y: i32 } - -fn main() { - let mut p1 = Point{ x: -1, y: 2 }; - let p2 = p1; - p1.x = 1; - println!("p1: {}, {}", p1.x, p1.y); - println!("p2: {}, {}", p2.x, p2.y); -} -``` - -Alternatively, if we don't control the struct's definition, or mutable shared -ownership is truly required, we can use `Rc` and `RefCell`: - -``` -use std::cell::RefCell; -use std::rc::Rc; - -struct MyStruct { s: u32 } - -fn main() { - let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 })); - let y = x.clone(); - x.borrow_mut().s = 6; - println!("{}", x.borrow().s); -} -``` - -With this approach, x and y share ownership of the data via the `Rc` (reference -count type). `RefCell` essentially performs runtime borrow checking: ensuring -that at most one writer or multiple readers can access the data at any one time. - -If you wish to learn more about ownership in Rust, start with the chapter in the -Book: - -https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html -"##, - -E0383: r##" -This error occurs when an attempt is made to partially reinitialize a -structure that is currently uninitialized. - -For example, this can happen when a drop has taken place: - -```compile_fail,E0383 -struct Foo { - a: u32, -} -impl Drop for Foo { - fn drop(&mut self) { /* ... */ } -} - -let mut x = Foo { a: 1 }; -drop(x); // `x` is now uninitialized -x.a = 2; // error, partial reinitialization of uninitialized structure `t` -``` - -This error can be fixed by fully reinitializing the structure in question: - -``` -struct Foo { - a: u32, -} -impl Drop for Foo { - fn drop(&mut self) { /* ... */ } -} - -let mut x = Foo { a: 1 }; -drop(x); -x = Foo { a: 2 }; -``` -"##, - -E0384: r##" -This error occurs when an attempt is made to reassign an immutable variable. -For example: - -```compile_fail,E0384 -fn main() { - let x = 3; - x = 5; // error, reassignment of immutable variable -} -``` - -By default, variables in Rust are immutable. To fix this error, add the keyword -`mut` after the keyword `let` when declaring the variable. For example: - -``` -fn main() { - let mut x = 3; - x = 5; -} -``` -"##, - -/*E0386: r##" -This error occurs when an attempt is made to mutate the target of a mutable -reference stored inside an immutable container. - -For example, this can happen when storing a `&mut` inside an immutable `Box`: - -```compile_fail,E0386 -let mut x: i64 = 1; -let y: Box<_> = Box::new(&mut x); -**y = 2; // error, cannot assign to data in an immutable container -``` - -This error can be fixed by making the container mutable: - -``` -let mut x: i64 = 1; -let mut y: Box<_> = Box::new(&mut x); -**y = 2; -``` - -It can also be fixed by using a type with interior mutability, such as `Cell` -or `RefCell`: - -``` -use std::cell::Cell; - -let x: i64 = 1; -let y: Box> = Box::new(Cell::new(x)); -y.set(2); -``` -"##,*/ - -E0387: r##" -This error occurs when an attempt is made to mutate or mutably reference data -that a closure has captured immutably. Examples of this error are shown below: - -```compile_fail,E0387 -// Accepts a function or a closure that captures its environment immutably. -// Closures passed to foo will not be able to mutate their closed-over state. -fn foo(f: F) { } - -// Attempts to mutate closed-over data. Error message reads: -// `cannot assign to data in a captured outer variable...` -fn mutable() { - let mut x = 0u32; - foo(|| x = 2); -} - -// Attempts to take a mutable reference to closed-over data. Error message -// reads: `cannot borrow data mutably in a captured outer variable...` -fn mut_addr() { - let mut x = 0u32; - foo(|| { let y = &mut x; }); -} -``` - -The problem here is that foo is defined as accepting a parameter of type `Fn`. -Closures passed into foo will thus be inferred to be of type `Fn`, meaning that -they capture their context immutably. - -If the definition of `foo` is under your control, the simplest solution is to -capture the data mutably. This can be done by defining `foo` to take FnMut -rather than Fn: - -``` -fn foo(f: F) { } -``` - -Alternatively, we can consider using the `Cell` and `RefCell` types to achieve -interior mutability through a shared reference. Our example's `mutable` -function could be redefined as below: - -``` -use std::cell::Cell; - -fn foo(f: F) { } - -fn mutable() { - let x = Cell::new(0u32); - foo(|| x.set(2)); -} -``` - -You can read more about cell types in the API documentation: - -https://doc.rust-lang.org/std/cell/ -"##, - -E0388: r##" -E0388 was removed and is no longer issued. -"##, - -E0389: r##" -An attempt was made to mutate data using a non-mutable reference. This -commonly occurs when attempting to assign to a non-mutable reference of a -mutable reference (`&(&mut T)`). - -Example of erroneous code: - -```compile_fail,E0389 -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy = FancyNum{ num: 5 }; - let fancy_ref = &(&mut fancy); - fancy_ref.num = 6; // error: cannot assign to data in a `&` reference - println!("{}", fancy_ref.num); -} -``` - -Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an -immutable reference to a value borrows it immutably. There can be multiple -references of type `&(&mut T)` that point to the same value, so they must be -immutable to prevent multiple mutable references to the same value. - -To fix this, either remove the outer reference: - -``` -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy = FancyNum{ num: 5 }; - - let fancy_ref = &mut fancy; - // `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum) - - fancy_ref.num = 6; // No error! - - println!("{}", fancy_ref.num); -} -``` - -Or make the outer reference mutable: - -``` -struct FancyNum { - num: u8 -} - -fn main() { - let mut fancy = FancyNum{ num: 5 }; - - let fancy_ref = &mut (&mut fancy); - // `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum) - - fancy_ref.num = 6; // No error! - - println!("{}", fancy_ref.num); -} -``` -"##, - -E0161: r##" -A value was moved. However, its size was not known at compile time, and only -values of a known size can be moved. - -Erroneous code example: - -```compile_fail -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<[isize]> = box *array; - // error: cannot move a value of type [isize]: the size of [isize] cannot - // be statically determined -} -``` - -In Rust, you can only move a value when its size is known at compile time. - -To work around this restriction, consider "hiding" the value behind a reference: -either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move -it around as usual. Example: - -``` -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<&[isize]> = box array; // ok! -} -``` -"##, - -E0492: r##" -A borrow of a constant containing interior mutability was attempted. Erroneous -code example: - -```compile_fail,E0492 -use std::sync::atomic::AtomicUsize; - -const A: AtomicUsize = AtomicUsize::new(0); -static B: &'static AtomicUsize = &A; -// error: cannot borrow a constant which may contain interior mutability, -// create a static instead -``` - -A `const` represents a constant value that should never change. If one takes -a `&` reference to the constant, then one is taking a pointer to some memory -location containing the value. Normally this is perfectly fine: most values -can't be changed via a shared `&` pointer, but interior mutability would allow -it. That is, a constant value could be mutated. On the other hand, a `static` is -explicitly a single memory location, which can be mutated at will. - -So, in order to solve this error, either use statics which are `Sync`: - -``` -use std::sync::atomic::AtomicUsize; - -static A: AtomicUsize = AtomicUsize::new(0); -static B: &'static AtomicUsize = &A; // ok! -``` - -You can also have this error while using a cell type: - -```compile_fail,E0492 -use std::cell::Cell; - -const A: Cell = Cell::new(1); -const B: &Cell = &A; -// error: cannot borrow a constant which may contain interior mutability, -// create a static instead - -// or: -struct C { a: Cell } - -const D: C = C { a: Cell::new(1) }; -const E: &Cell = &D.a; // error - -// or: -const F: &C = &D; // error -``` - -This is because cell types do operations that are not thread-safe. Due to this, -they don't implement Sync and thus can't be placed in statics. - -However, if you still wish to use these types, you can achieve this by an unsafe -wrapper: - -``` -use std::cell::Cell; -use std::marker::Sync; - -struct NotThreadSafe { - value: Cell, -} - -unsafe impl Sync for NotThreadSafe {} - -static A: NotThreadSafe = NotThreadSafe { value : Cell::new(1) }; -static B: &'static NotThreadSafe = &A; // ok! -``` - -Remember this solution is unsafe! You will have to ensure that accesses to the -cell are synchronized. -"##, - -E0499: r##" -A variable was borrowed as mutable more than once. Erroneous code example: - -```compile_fail,E0499 -let mut i = 0; -let mut x = &mut i; -let mut a = &mut i; -// error: cannot borrow `i` as mutable more than once at a time -``` - -Please note that in rust, you can either have many immutable references, or one -mutable reference. Take a look at -https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html for more -information. Example: - - -``` -let mut i = 0; -let mut x = &mut i; // ok! - -// or: -let mut i = 0; -let a = &i; // ok! -let b = &i; // still ok! -let c = &i; // still ok! -``` -"##, - -E0500: r##" -A borrowed variable was used in another closure. Example of erroneous code: - -```compile_fail -fn you_know_nothing(jon_snow: &mut i32) { - let nights_watch = || { - *jon_snow = 2; - }; - let starks = || { - *jon_snow = 3; // error: closure requires unique access to `jon_snow` - // but it is already borrowed - }; -} -``` - -In here, `jon_snow` is already borrowed by the `nights_watch` closure, so it -cannot be borrowed by the `starks` closure at the same time. To fix this issue, -you can put the closure in its own scope: - -``` -fn you_know_nothing(jon_snow: &mut i32) { - { - let nights_watch = || { - *jon_snow = 2; - }; - } // At this point, `jon_snow` is free. - let starks = || { - *jon_snow = 3; - }; -} -``` - -Or, if the type implements the `Clone` trait, you can clone it between -closures: - -``` -fn you_know_nothing(jon_snow: &mut i32) { - let mut jon_copy = jon_snow.clone(); - let nights_watch = || { - jon_copy = 2; - }; - let starks = || { - *jon_snow = 3; - }; -} -``` -"##, - -E0501: r##" -This error indicates that a mutable variable is being used while it is still -captured by a closure. Because the closure has borrowed the variable, it is not -available for use until the closure goes out of scope. - -Note that a capture will either move or borrow a variable, but in this -situation, the closure is borrowing the variable. Take a look at -http://rustbyexample.com/fn/closures/capture.html for more information about -capturing. - -Example of erroneous code: - -```compile_fail,E0501 -fn inside_closure(x: &mut i32) { - // Actions which require unique access -} - -fn outside_closure(x: &mut i32) { - // Actions which require unique access -} - -fn foo(a: &mut i32) { - let bar = || { - inside_closure(a) - }; - outside_closure(a); // error: cannot borrow `*a` as mutable because previous - // closure requires unique access. -} -``` - -To fix this error, you can place the closure in its own scope: - -``` -fn inside_closure(x: &mut i32) {} -fn outside_closure(x: &mut i32) {} - -fn foo(a: &mut i32) { - { - let bar = || { - inside_closure(a) - }; - } // borrow on `a` ends. - outside_closure(a); // ok! -} -``` - -Or you can pass the variable as a parameter to the closure: - -``` -fn inside_closure(x: &mut i32) {} -fn outside_closure(x: &mut i32) {} - -fn foo(a: &mut i32) { - let bar = |s: &mut i32| { - inside_closure(s) - }; - outside_closure(a); - bar(a); -} -``` - -It may be possible to define the closure later: - -``` -fn inside_closure(x: &mut i32) {} -fn outside_closure(x: &mut i32) {} - -fn foo(a: &mut i32) { - outside_closure(a); - let bar = || { - inside_closure(a) - }; -} -``` -"##, - -E0502: r##" -This error indicates that you are trying to borrow a variable as mutable when it -has already been borrowed as immutable. - -Example of erroneous code: - -```compile_fail,E0502 -fn bar(x: &mut i32) {} -fn foo(a: &mut i32) { - let ref y = a; // a is borrowed as immutable. - bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed - // as immutable -} -``` - -To fix this error, ensure that you don't have any other references to the -variable before trying to access it mutably: - -``` -fn bar(x: &mut i32) {} -fn foo(a: &mut i32) { - bar(a); - let ref y = a; // ok! -} -``` - -For more information on the rust ownership system, take a look at -https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html. -"##, - -E0503: r##" -A value was used after it was mutably borrowed. - -Example of erroneous code: - -```compile_fail,E0503 -fn main() { - let mut value = 3; - // Create a mutable borrow of `value`. This borrow - // lives until the end of this function. - let _borrow = &mut value; - let _sum = value + 1; // error: cannot use `value` because - // it was mutably borrowed -} -``` - -In this example, `value` is mutably borrowed by `borrow` and cannot be -used to calculate `sum`. This is not possible because this would violate -Rust's mutability rules. - -You can fix this error by limiting the scope of the borrow: - -``` -fn main() { - let mut value = 3; - // By creating a new block, you can limit the scope - // of the reference. - { - let _borrow = &mut value; // Use `_borrow` inside this block. - } - // The block has ended and with it the borrow. - // You can now use `value` again. - let _sum = value + 1; -} -``` - -Or by cloning `value` before borrowing it: - -``` -fn main() { - let mut value = 3; - // We clone `value`, creating a copy. - let value_cloned = value.clone(); - // The mutable borrow is a reference to `value` and - // not to `value_cloned`... - let _borrow = &mut value; - // ... which means we can still use `value_cloned`, - let _sum = value_cloned + 1; - // even though the borrow only ends here. -} -``` - -You can find more information about borrowing in the rust-book: -http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html -"##, - -E0504: r##" -This error occurs when an attempt is made to move a borrowed variable into a -closure. - -Example of erroneous code: - -```compile_fail,E0504 -struct FancyNum { - num: u8, -} - -fn main() { - let fancy_num = FancyNum { num: 5 }; - let fancy_ref = &fancy_num; - - let x = move || { - println!("child function: {}", fancy_num.num); - // error: cannot move `fancy_num` into closure because it is borrowed - }; - - x(); - println!("main function: {}", fancy_ref.num); -} -``` - -Here, `fancy_num` is borrowed by `fancy_ref` and so cannot be moved into -the closure `x`. There is no way to move a value into a closure while it is -borrowed, as that would invalidate the borrow. - -If the closure can't outlive the value being moved, try using a reference -rather than moving: - -``` -struct FancyNum { - num: u8, -} - -fn main() { - let fancy_num = FancyNum { num: 5 }; - let fancy_ref = &fancy_num; - - let x = move || { - // fancy_ref is usable here because it doesn't move `fancy_num` - println!("child function: {}", fancy_ref.num); - }; - - x(); - - println!("main function: {}", fancy_num.num); -} -``` - -If the value has to be borrowed and then moved, try limiting the lifetime of -the borrow using a scoped block: - -``` -struct FancyNum { - num: u8, -} - -fn main() { - let fancy_num = FancyNum { num: 5 }; - - { - let fancy_ref = &fancy_num; - println!("main function: {}", fancy_ref.num); - // `fancy_ref` goes out of scope here - } - - let x = move || { - // `fancy_num` can be moved now (no more references exist) - println!("child function: {}", fancy_num.num); - }; - - x(); -} -``` - -If the lifetime of a reference isn't enough, such as in the case of threading, -consider using an `Arc` to create a reference-counted value: - -``` -use std::sync::Arc; -use std::thread; - -struct FancyNum { - num: u8, -} - -fn main() { - let fancy_ref1 = Arc::new(FancyNum { num: 5 }); - let fancy_ref2 = fancy_ref1.clone(); - - let x = thread::spawn(move || { - // `fancy_ref1` can be moved and has a `'static` lifetime - println!("child thread: {}", fancy_ref1.num); - }); - - x.join().expect("child thread should finish"); - println!("main thread: {}", fancy_ref2.num); -} -``` -"##, - -E0505: r##" -A value was moved out while it was still borrowed. - -Erroneous code example: - -```compile_fail,E0505 -struct Value {} - -fn borrow(val: &Value) {} - -fn eat(val: Value) {} - -fn main() { - let x = Value{}; - let _ref_to_val: &Value = &x; - eat(x); - borrow(_ref_to_val); -} -``` - -Here, the function `eat` takes ownership of `x`. However, -`x` cannot be moved because the borrow to `_ref_to_val` -needs to last till the function `borrow`. -To fix that you can do a few different things: - -* Try to avoid moving the variable. -* Release borrow before move. -* Implement the `Copy` trait on the type. - -Examples: - -``` -struct Value {} - -fn borrow(val: &Value) {} - -fn eat(val: &Value) {} - -fn main() { - let x = Value{}; - let _ref_to_val: &Value = &x; - eat(&x); // pass by reference, if it's possible - borrow(_ref_to_val); -} -``` - -Or: - -``` -struct Value {} - -fn borrow(val: &Value) {} - -fn eat(val: Value) {} - -fn main() { - let x = Value{}; - { - let _ref_to_val: &Value = &x; - borrow(_ref_to_val); - } - eat(x); // release borrow and then move it. -} -``` - -Or: - -``` -#[derive(Clone, Copy)] // implement Copy trait -struct Value {} - -fn borrow(val: &Value) {} - -fn eat(val: Value) {} - -fn main() { - let x = Value{}; - let _ref_to_val: &Value = &x; - eat(x); // it will be copied here. - borrow(_ref_to_val); -} -``` - -You can find more information about borrowing in the rust-book: -http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html -"##, - -E0506: r##" -This error occurs when an attempt is made to assign to a borrowed value. - -Example of erroneous code: - -```compile_fail,E0506 -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy_num = FancyNum { num: 5 }; - let fancy_ref = &fancy_num; - fancy_num = FancyNum { num: 6 }; - // error: cannot assign to `fancy_num` because it is borrowed - - println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num); -} -``` - -Because `fancy_ref` still holds a reference to `fancy_num`, `fancy_num` can't -be assigned to a new value as it would invalidate the reference. - -Alternatively, we can move out of `fancy_num` into a second `fancy_num`: - -``` -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy_num = FancyNum { num: 5 }; - let moved_num = fancy_num; - fancy_num = FancyNum { num: 6 }; - - println!("Num: {}, Moved num: {}", fancy_num.num, moved_num.num); -} -``` - -If the value has to be borrowed, try limiting the lifetime of the borrow using -a scoped block: - -``` -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy_num = FancyNum { num: 5 }; - - { - let fancy_ref = &fancy_num; - println!("Ref: {}", fancy_ref.num); - } - - // Works because `fancy_ref` is no longer in scope - fancy_num = FancyNum { num: 6 }; - println!("Num: {}", fancy_num.num); -} -``` - -Or by moving the reference into a function: - -``` -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy_num = FancyNum { num: 5 }; - - print_fancy_ref(&fancy_num); - - // Works because function borrow has ended - fancy_num = FancyNum { num: 6 }; - println!("Num: {}", fancy_num.num); -} - -fn print_fancy_ref(fancy_ref: &FancyNum){ - println!("Ref: {}", fancy_ref.num); -} -``` -"##, - -E0507: r##" -You tried to move out of a value which was borrowed. Erroneous code example: - -```compile_fail,E0507 -use std::cell::RefCell; - -struct TheDarkKnight; - -impl TheDarkKnight { - fn nothing_is_true(self) {} -} - -fn main() { - let x = RefCell::new(TheDarkKnight); - - x.borrow().nothing_is_true(); // error: cannot move out of borrowed content -} -``` - -Here, the `nothing_is_true` method takes the ownership of `self`. However, -`self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`, -which is a borrow of the content owned by the `RefCell`. To fix this error, -you have three choices: - -* Try to avoid moving the variable. -* Somehow reclaim the ownership. -* Implement the `Copy` trait on the type. - -Examples: - -``` -use std::cell::RefCell; - -struct TheDarkKnight; - -impl TheDarkKnight { - fn nothing_is_true(&self) {} // First case, we don't take ownership -} - -fn main() { - let x = RefCell::new(TheDarkKnight); - - x.borrow().nothing_is_true(); // ok! -} -``` - -Or: - -``` -use std::cell::RefCell; - -struct TheDarkKnight; - -impl TheDarkKnight { - fn nothing_is_true(self) {} -} - -fn main() { - let x = RefCell::new(TheDarkKnight); - let x = x.into_inner(); // we get back ownership - - x.nothing_is_true(); // ok! -} -``` - -Or: - -``` -use std::cell::RefCell; - -#[derive(Clone, Copy)] // we implement the Copy trait -struct TheDarkKnight; - -impl TheDarkKnight { - fn nothing_is_true(self) {} -} - -fn main() { - let x = RefCell::new(TheDarkKnight); - - x.borrow().nothing_is_true(); // ok! -} -``` - -Moving a member out of a mutably borrowed struct will also cause E0507 error: - -```compile_fail,E0507 -struct TheDarkKnight; - -impl TheDarkKnight { - fn nothing_is_true(self) {} -} - -struct Batcave { - knight: TheDarkKnight -} - -fn main() { - let mut cave = Batcave { - knight: TheDarkKnight - }; - let borrowed = &mut cave; - - borrowed.knight.nothing_is_true(); // E0507 -} -``` - -It is fine only if you put something back. `mem::replace` can be used for that: - -``` -# struct TheDarkKnight; -# impl TheDarkKnight { fn nothing_is_true(self) {} } -# struct Batcave { knight: TheDarkKnight } -use std::mem; - -let mut cave = Batcave { - knight: TheDarkKnight -}; -let borrowed = &mut cave; - -mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok! -``` - -You can find more information about borrowing in the rust-book: -http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html -"##, - -E0508: r##" -A value was moved out of a non-copy fixed-size array. - -Example of erroneous code: - -```compile_fail,E0508 -struct NonCopy; - -fn main() { - let array = [NonCopy; 1]; - let _value = array[0]; // error: cannot move out of type `[NonCopy; 1]`, - // a non-copy fixed-size array -} -``` - -The first element was moved out of the array, but this is not -possible because `NonCopy` does not implement the `Copy` trait. - -Consider borrowing the element instead of moving it: - -``` -struct NonCopy; - -fn main() { - let array = [NonCopy; 1]; - let _value = &array[0]; // Borrowing is allowed, unlike moving. -} -``` - -Alternatively, if your type implements `Clone` and you need to own the value, -consider borrowing and then cloning: - -``` -#[derive(Clone)] -struct NonCopy; - -fn main() { - let array = [NonCopy; 1]; - // Now you can clone the array element. - let _value = array[0].clone(); -} -``` -"##, - -E0509: r##" -This error occurs when an attempt is made to move out of a value whose type -implements the `Drop` trait. - -Example of erroneous code: - -```compile_fail,E0509 -struct FancyNum { - num: usize -} - -struct DropStruct { - fancy: FancyNum -} - -impl Drop for DropStruct { - fn drop(&mut self) { - // Destruct DropStruct, possibly using FancyNum - } -} - -fn main() { - let drop_struct = DropStruct{fancy: FancyNum{num: 5}}; - let fancy_field = drop_struct.fancy; // Error E0509 - println!("Fancy: {}", fancy_field.num); - // implicit call to `drop_struct.drop()` as drop_struct goes out of scope -} -``` - -Here, we tried to move a field out of a struct of type `DropStruct` which -implements the `Drop` trait. However, a struct cannot be dropped if one or -more of its fields have been moved. - -Structs implementing the `Drop` trait have an implicit destructor that gets -called when they go out of scope. This destructor may use the fields of the -struct, so moving out of the struct could make it impossible to run the -destructor. Therefore, we must think of all values whose type implements the -`Drop` trait as single units whose fields cannot be moved. - -This error can be fixed by creating a reference to the fields of a struct, -enum, or tuple using the `ref` keyword: - -``` -struct FancyNum { - num: usize -} - -struct DropStruct { - fancy: FancyNum -} - -impl Drop for DropStruct { - fn drop(&mut self) { - // Destruct DropStruct, possibly using FancyNum - } -} - -fn main() { - let drop_struct = DropStruct{fancy: FancyNum{num: 5}}; - let ref fancy_field = drop_struct.fancy; // No more errors! - println!("Fancy: {}", fancy_field.num); - // implicit call to `drop_struct.drop()` as drop_struct goes out of scope -} -``` - -Note that this technique can also be used in the arms of a match expression: - -``` -struct FancyNum { - num: usize -} - -enum DropEnum { - Fancy(FancyNum) -} - -impl Drop for DropEnum { - fn drop(&mut self) { - // Destruct DropEnum, possibly using FancyNum - } -} - -fn main() { - // Creates and enum of type `DropEnum`, which implements `Drop` - let drop_enum = DropEnum::Fancy(FancyNum{num: 10}); - match drop_enum { - // Creates a reference to the inside of `DropEnum::Fancy` - DropEnum::Fancy(ref fancy_field) => // No error! - println!("It was fancy-- {}!", fancy_field.num), - } - // implicit call to `drop_enum.drop()` as drop_enum goes out of scope -} -``` -"##, - -E0510: r##" -Cannot mutate place in this match guard. - -When matching on a variable it cannot be mutated in the match guards, as this -could cause the match to be non-exhaustive: - -```compile_fail,E0510 -#![feature(nll, bind_by_move_pattern_guards)] -let mut x = Some(0); -match x { - None => (), - Some(_) if { x = None; false } => (), - Some(v) => (), // No longer matches -} -``` - -Here executing `x = None` would modify the value being matched and require us -to go "back in time" to the `None` arm. -"##, - -E0579: r##" -When matching against an exclusive range, the compiler verifies that the range -is non-empty. Exclusive range patterns include the start point but not the end -point, so this is equivalent to requiring the start of the range to be less -than the end of the range. - -For example: - -```compile_fail -match 5u32 { - // This range is ok, albeit pointless. - 1 .. 2 => {} - // This range is empty, and the compiler can tell. - 5 .. 5 => {} -} -``` -"##, - -E0515: r##" -Cannot return value that references local variable - -Local variables, function parameters and temporaries are all dropped before the -end of the function body. So a reference to them cannot be returned. - -```compile_fail,E0515 -#![feature(nll)] -fn get_dangling_reference() -> &'static i32 { - let x = 0; - &x -} -``` - -```compile_fail,E0515 -#![feature(nll)] -use std::slice::Iter; -fn get_dangling_iterator<'a>() -> Iter<'a, i32> { - let v = vec![1, 2, 3]; - v.iter() -} -``` - -Consider returning an owned value instead: - -``` -use std::vec::IntoIter; - -fn get_integer() -> i32 { - let x = 0; - x -} - -fn get_owned_iterator() -> IntoIter { - let v = vec![1, 2, 3]; - v.into_iter() -} -``` -"##, - -E0595: r##" -Closures cannot mutate immutable captured variables. - -Erroneous code example: - -```compile_fail,E0595 -let x = 3; // error: closure cannot assign to immutable local variable `x` -let mut c = || { x += 1 }; -``` - -Make the variable binding mutable: - -``` -let mut x = 3; // ok! -let mut c = || { x += 1 }; -``` -"##, - -E0596: r##" -This error occurs because you tried to mutably borrow a non-mutable variable. - -Example of erroneous code: - -```compile_fail,E0596 -let x = 1; -let y = &mut x; // error: cannot borrow mutably -``` - -In here, `x` isn't mutable, so when we try to mutably borrow it in `y`, it -fails. To fix this error, you need to make `x` mutable: - -``` -let mut x = 1; -let y = &mut x; // ok! -``` -"##, - -E0597: r##" -This error occurs because a borrow was made inside a variable which has a -greater lifetime than the borrowed one. - -Example of erroneous code: - -```compile_fail,E0597 -struct Foo<'a> { - x: Option<&'a u32>, -} - -let mut x = Foo { x: None }; -let y = 0; -x.x = Some(&y); // error: `y` does not live long enough -``` - -In here, `x` is created before `y` and therefore has a greater lifetime. Always -keep in mind that values in a scope are dropped in the opposite order they are -created. So to fix the previous example, just make the `y` lifetime greater than -the `x`'s one: - -``` -struct Foo<'a> { - x: Option<&'a u32>, -} - -let y = 0; -let mut x = Foo { x: None }; -x.x = Some(&y); -``` -"##, - -E0626: r##" -This error occurs because a borrow in a generator persists across a -yield point. - -```compile_fail,E0626 -# #![feature(generators, generator_trait, pin)] -# use std::ops::Generator; -# use std::pin::Pin; -let mut b = || { - let a = &String::new(); // <-- This borrow... - yield (); // ...is still in scope here, when the yield occurs. - println!("{}", a); -}; -Pin::new(&mut b).resume(); -``` - -At present, it is not permitted to have a yield that occurs while a -borrow is still in scope. To resolve this error, the borrow must -either be "contained" to a smaller scope that does not overlap the -yield or else eliminated in another way. So, for example, we might -resolve the previous example by removing the borrow and just storing -the integer by value: - -``` -# #![feature(generators, generator_trait, pin)] -# use std::ops::Generator; -# use std::pin::Pin; -let mut b = || { - let a = 3; - yield (); - println!("{}", a); -}; -Pin::new(&mut b).resume(); -``` - -This is a very simple case, of course. In more complex cases, we may -wish to have more than one reference to the value that was borrowed -- -in those cases, something like the `Rc` or `Arc` types may be useful. - -This error also frequently arises with iteration: - -```compile_fail,E0626 -# #![feature(generators, generator_trait, pin)] -# use std::ops::Generator; -# use std::pin::Pin; -let mut b = || { - let v = vec![1,2,3]; - for &x in &v { // <-- borrow of `v` is still in scope... - yield x; // ...when this yield occurs. - } -}; -Pin::new(&mut b).resume(); -``` - -Such cases can sometimes be resolved by iterating "by value" (or using -`into_iter()`) to avoid borrowing: - -``` -# #![feature(generators, generator_trait, pin)] -# use std::ops::Generator; -# use std::pin::Pin; -let mut b = || { - let v = vec![1,2,3]; - for x in v { // <-- Take ownership of the values instead! - yield x; // <-- Now yield is OK. - } -}; -Pin::new(&mut b).resume(); -``` - -If taking ownership is not an option, using indices can work too: - -``` -# #![feature(generators, generator_trait, pin)] -# use std::ops::Generator; -# use std::pin::Pin; -let mut b = || { - let v = vec![1,2,3]; - let len = v.len(); // (*) - for i in 0..len { - let x = v[i]; // (*) - yield x; // <-- Now yield is OK. - } -}; -Pin::new(&mut b).resume(); - -// (*) -- Unfortunately, these temporaries are currently required. -// See . -``` -"##, - -E0712: r##" -This error occurs because a borrow of a thread-local variable was made inside a -function which outlived the lifetime of the function. - -Example of erroneous code: - -```compile_fail,E0712 -#![feature(nll)] -#![feature(thread_local)] - -#[thread_local] -static FOO: u8 = 3; - -fn main() { - let a = &FOO; // error: thread-local variable borrowed past end of function - - std::thread::spawn(move || { - println!("{}", a); - }); -} -``` -"##, - -E0713: r##" -This error occurs when an attempt is made to borrow state past the end of the -lifetime of a type that implements the `Drop` trait. - -Example of erroneous code: - -```compile_fail,E0713 -#![feature(nll)] - -pub struct S<'a> { data: &'a mut String } - -impl<'a> Drop for S<'a> { - fn drop(&mut self) { self.data.push_str("being dropped"); } -} - -fn demo<'a>(s: S<'a>) -> &'a mut String { let p = &mut *s.data; p } -``` - -Here, `demo` tries to borrow the string data held within its -argument `s` and then return that borrow. However, `S` is -declared as implementing `Drop`. - -Structs implementing the `Drop` trait have an implicit destructor that -gets called when they go out of scope. This destructor gets exclusive -access to the fields of the struct when it runs. - -This means that when `s` reaches the end of `demo`, its destructor -gets exclusive access to its `&mut`-borrowed string data. allowing -another borrow of that string data (`p`), to exist across the drop of -`s` would be a violation of the principle that `&mut`-borrows have -exclusive, unaliased access to their referenced data. - -This error can be fixed by changing `demo` so that the destructor does -not run while the string-data is borrowed; for example by taking `S` -by reference: - -``` -#![feature(nll)] - -pub struct S<'a> { data: &'a mut String } - -impl<'a> Drop for S<'a> { - fn drop(&mut self) { self.data.push_str("being dropped"); } -} - -fn demo<'a>(s: &'a mut S<'a>) -> &'a mut String { let p = &mut *(*s).data; p } -``` - -Note that this approach needs a reference to S with lifetime `'a`. -Nothing shorter than `'a` will suffice: a shorter lifetime would imply -that after `demo` finishes executing, something else (such as the -destructor!) could access `s.data` after the end of that shorter -lifetime, which would again violate the `&mut`-borrow's exclusive -access. -"##, - -E0716: r##" -This error indicates that a temporary value is being dropped -while a borrow is still in active use. - -Erroneous code example: - -```compile_fail,E0716 -# #![feature(nll)] -fn foo() -> i32 { 22 } -fn bar(x: &i32) -> &i32 { x } -let p = bar(&foo()); - // ------ creates a temporary -let q = *p; -``` - -Here, the expression `&foo()` is borrowing the expression -`foo()`. As `foo()` is call to a function, and not the name of -a variable, this creates a **temporary** -- that temporary stores -the return value from `foo()` so that it can be borrowed. -So you might imagine that `let p = bar(&foo())` is equivalent -to this: - -```compile_fail,E0597 -# fn foo() -> i32 { 22 } -# fn bar(x: &i32) -> &i32 { x } -let p = { - let tmp = foo(); // the temporary - bar(&tmp) -}; // <-- tmp is freed as we exit this block -let q = p; -``` - -Whenever a temporary is created, it is automatically dropped (freed) -according to fixed rules. Ordinarily, the temporary is dropped -at the end of the enclosing statement -- in this case, after the `let`. -This is illustrated in the example above by showing that `tmp` would -be freed as we exit the block. - -To fix this problem, you need to create a local variable -to store the value in rather than relying on a temporary. -For example, you might change the original program to -the following: - -``` -fn foo() -> i32 { 22 } -fn bar(x: &i32) -> &i32 { x } -let value = foo(); // dropped at the end of the enclosing block -let p = bar(&value); -let q = *p; -``` - -By introducing the explicit `let value`, we allocate storage -that will last until the end of the enclosing block (when `value` -goes out of scope). When we borrow `&value`, we are borrowing a -local variable that already exists, and hence no temporary is created. - -Temporaries are not always dropped at the end of the enclosing -statement. In simple cases where the `&` expression is immediately -stored into a variable, the compiler will automatically extend -the lifetime of the temporary until the end of the enclosing -block. Therefore, an alternative way to fix the original -program is to write `let tmp = &foo()` and not `let tmp = foo()`: - -``` -fn foo() -> i32 { 22 } -fn bar(x: &i32) -> &i32 { x } -let value = &foo(); -let p = bar(value); -let q = *p; -``` - -Here, we are still borrowing `foo()`, but as the borrow is assigned -directly into a variable, the temporary will not be dropped until -the end of the enclosing block. Similar rules apply when temporaries -are stored into aggregate structures like a tuple or struct: - -``` -// Here, two temporaries are created, but -// as they are stored directly into `value`, -// they are not dropped until the end of the -// enclosing block. -fn foo() -> i32 { 22 } -let value = (&foo(), &foo()); -``` -"##, - -E0723: r##" -An feature unstable in `const` contexts was used. - -Erroneous code example: - -```compile_fail,E0723 -trait T {} - -impl T for () {} - -const fn foo() -> impl T { // error: `impl Trait` in const fn is unstable - () -} -``` - -To enable this feature on a nightly version of rustc, add the `const_fn` -feature flag: - -``` -#![feature(const_fn)] - -trait T {} - -impl T for () {} - -const fn foo() -> impl T { - () -} -``` -"##, - -} - -register_diagnostics! { -// E0298, // cannot compare constants -// E0299, // mismatched types between arms -// E0471, // constant evaluation error (in pattern) -// E0385, // {} in an aliasable location - E0493, // destructors cannot be evaluated at compile-time - E0521, // borrowed data escapes outside of closure - E0524, // two closures require unique access to `..` at the same time - E0526, // shuffle indices are not constant - E0594, // cannot assign to {} - E0598, // lifetime of {} is too short to guarantee its contents can be... - E0625, // thread-local statics cannot be accessed at compile-time -} diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs new file mode 100644 index 0000000000000..4807782c66347 --- /dev/null +++ b/src/librustc_mir/error_codes.rs @@ -0,0 +1,2473 @@ +#![allow(non_snake_case)] + +register_long_diagnostics! { + + +E0001: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error suggests that the expression arm corresponding to the noted pattern +will never be reached as for all possible values of the expression being +matched, one of the preceding patterns will match. + +This means that perhaps some of the preceding patterns are too general, this +one is too specific or the ordering is incorrect. + +For example, the following `match` block has too many arms: + +``` +match Some(0) { + Some(bar) => {/* ... */} + x => {/* ... */} // This handles the `None` case + _ => {/* ... */} // All possible cases have already been handled +} +``` + +`match` blocks have their patterns matched in order, so, for example, putting +a wildcard arm above a more specific arm will make the latter arm irrelevant. + +Ensure the ordering of the match arm is correct and remove any superfluous +arms. +"##, + +E0002: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error indicates that an empty match expression is invalid because the type +it is matching on is non-empty (there exist values of this type). In safe code +it is impossible to create an instance of an empty type, so empty match +expressions are almost never desired. This error is typically fixed by adding +one or more cases to the match expression. + +An example of an empty type is `enum Empty { }`. So, the following will work: + +``` +enum Empty {} + +fn foo(x: Empty) { + match x { + // empty + } +} +``` + +However, this won't: + +```compile_fail +fn foo(x: Option) { + match x { + // empty + } +} +``` +"##, + +E0004: r##" +This error indicates that the compiler cannot guarantee a matching pattern for +one or more possible inputs to a match expression. Guaranteed matches are +required in order to assign values to match expressions, or alternatively, +determine the flow of execution. Erroneous code example: + +```compile_fail,E0004 +enum Terminator { + HastaLaVistaBaby, + TalkToMyHand, +} + +let x = Terminator::HastaLaVistaBaby; + +match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered + Terminator::TalkToMyHand => {} +} +``` + +If you encounter this error you must alter your patterns so that every possible +value of the input type is matched. For types with a small number of variants +(like enums) you should probably cover all cases explicitly. Alternatively, the +underscore `_` wildcard pattern can be added after all other patterns to match +"anything else". Example: + +``` +enum Terminator { + HastaLaVistaBaby, + TalkToMyHand, +} + +let x = Terminator::HastaLaVistaBaby; + +match x { + Terminator::TalkToMyHand => {} + Terminator::HastaLaVistaBaby => {} +} + +// or: + +match x { + Terminator::TalkToMyHand => {} + _ => {} +} +``` +"##, + +E0005: r##" +Patterns used to bind names must be irrefutable, that is, they must guarantee +that a name will be extracted in all cases. Erroneous code example: + +```compile_fail,E0005 +let x = Some(1); +let Some(y) = x; +// error: refutable pattern in local binding: `None` not covered +``` + +If you encounter this error you probably need to use a `match` or `if let` to +deal with the possibility of failure. Example: + +``` +let x = Some(1); + +match x { + Some(y) => { + // do something + }, + None => {} +} + +// or: + +if let Some(y) = x { + // do something +} +``` +"##, + +E0007: r##" +This error indicates that the bindings in a match arm would require a value to +be moved into more than one location, thus violating unique ownership. Code +like the following is invalid as it requires the entire `Option` to be +moved into a variable called `op_string` while simultaneously requiring the +inner `String` to be moved into a variable called `s`. + +```compile_fail,E0007 +let x = Some("s".to_string()); + +match x { + op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings + None => {}, +} +``` + +See also the error E0303. +"##, + +E0008: r##" +Names bound in match arms retain their type in pattern guards. As such, if a +name is bound by move in a pattern, it should also be moved to wherever it is +referenced in the pattern guard code. Doing so however would prevent the name +from being available in the body of the match arm. Consider the following: + +```compile_fail,E0008 +match Some("hi".to_string()) { + Some(s) if s.len() == 0 => {}, // use s. + _ => {}, +} +``` + +The variable `s` has type `String`, and its use in the guard is as a variable of +type `String`. The guard code effectively executes in a separate scope to the +body of the arm, so the value would be moved into this anonymous scope and +therefore becomes unavailable in the body of the arm. + +The problem above can be solved by using the `ref` keyword. + +``` +match Some("hi".to_string()) { + Some(ref s) if s.len() == 0 => {}, + _ => {}, +} +``` + +Though this example seems innocuous and easy to solve, the problem becomes clear +when it encounters functions which consume the value: + +```compile_fail,E0008 +struct A{} + +impl A { + fn consume(self) -> usize { + 0 + } +} + +fn main() { + let a = Some(A{}); + match a { + Some(y) if y.consume() > 0 => {} + _ => {} + } +} +``` + +In this situation, even the `ref` keyword cannot solve it, since borrowed +content cannot be moved. This problem cannot be solved generally. If the value +can be cloned, here is a not-so-specific solution: + +``` +#[derive(Clone)] +struct A{} + +impl A { + fn consume(self) -> usize { + 0 + } +} + +fn main() { + let a = Some(A{}); + match a{ + Some(ref y) if y.clone().consume() > 0 => {} + _ => {} + } +} +``` + +If the value will be consumed in the pattern guard, using its clone will not +move its ownership, so the code works. +"##, + +E0009: r##" +In a pattern, all values that don't implement the `Copy` trait have to be bound +the same way. The goal here is to avoid binding simultaneously by-move and +by-ref. + +This limitation may be removed in a future version of Rust. + +Erroneous code example: + +```compile_fail,E0009 +struct X { x: (), } + +let x = Some((X { x: () }, X { x: () })); +match x { + Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the + // same pattern + None => panic!() +} +``` + +You have two solutions: + +Solution #1: Bind the pattern's values the same way. + +``` +struct X { x: (), } + +let x = Some((X { x: () }, X { x: () })); +match x { + Some((ref y, ref z)) => {}, + // or Some((y, z)) => {} + None => panic!() +} +``` + +Solution #2: Implement the `Copy` trait for the `X` structure. + +However, please keep in mind that the first solution should be preferred. + +``` +#[derive(Clone, Copy)] +struct X { x: (), } + +let x = Some((X { x: () }, X { x: () })); +match x { + Some((y, ref z)) => {}, + None => panic!() +} +``` +"##, + +E0030: r##" +When matching against a range, the compiler verifies that the range is +non-empty. Range patterns include both end-points, so this is equivalent to +requiring the start of the range to be less than or equal to the end of the +range. + +For example: + +```compile_fail +match 5u32 { + // This range is ok, albeit pointless. + 1 ..= 1 => {} + // This range is empty, and the compiler can tell. + 1000 ..= 5 => {} +} +``` +"##, + +E0158: r##" +`const` and `static` mean different things. A `const` is a compile-time +constant, an alias for a literal value. This property means you can match it +directly within a pattern. + +The `static` keyword, on the other hand, guarantees a fixed location in memory. +This does not always mean that the value is constant. For example, a global +mutex can be declared `static` as well. + +If you want to match against a `static`, consider using a guard instead: + +``` +static FORTY_TWO: i32 = 42; + +match Some(42) { + Some(x) if x == FORTY_TWO => {} + _ => {} +} +``` +"##, + +E0162: r##" +#### Note: this error code is no longer emitted by the compiler. + +An if-let pattern attempts to match the pattern, and enters the body if the +match was successful. If the match is irrefutable (when it cannot fail to +match), use a regular `let`-binding instead. For instance: + +```compile_pass +struct Irrefutable(i32); +let irr = Irrefutable(0); + +// This fails to compile because the match is irrefutable. +if let Irrefutable(x) = irr { + // This body will always be executed. + // ... +} +``` + +Try this instead: + +``` +struct Irrefutable(i32); +let irr = Irrefutable(0); + +let Irrefutable(x) = irr; +println!("{}", x); +``` +"##, + +E0165: r##" +#### Note: this error code is no longer emitted by the compiler. + +A while-let pattern attempts to match the pattern, and enters the body if the +match was successful. If the match is irrefutable (when it cannot fail to +match), use a regular `let`-binding inside a `loop` instead. For instance: + +```compile_pass,no_run +struct Irrefutable(i32); +let irr = Irrefutable(0); + +// This fails to compile because the match is irrefutable. +while let Irrefutable(x) = irr { + // ... +} +``` + +Try this instead: + +```no_run +struct Irrefutable(i32); +let irr = Irrefutable(0); + +loop { + let Irrefutable(x) = irr; + // ... +} +``` +"##, + +E0170: r##" +Enum variants are qualified by default. For example, given this type: + +``` +enum Method { + GET, + POST, +} +``` + +You would match it using: + +``` +enum Method { + GET, + POST, +} + +let m = Method::GET; + +match m { + Method::GET => {}, + Method::POST => {}, +} +``` + +If you don't qualify the names, the code will bind new variables named "GET" and +"POST" instead. This behavior is likely not what you want, so `rustc` warns when +that happens. + +Qualified names are good practice, and most code works well with them. But if +you prefer them unqualified, you can import the variants into scope: + +``` +use Method::*; +enum Method { GET, POST } +# fn main() {} +``` + +If you want others to be able to import variants from your module directly, use +`pub use`: + +``` +pub use Method::*; +pub enum Method { GET, POST } +# fn main() {} +``` +"##, + + +E0297: r##" +#### Note: this error code is no longer emitted by the compiler. + +Patterns used to bind names must be irrefutable. That is, they must guarantee +that a name will be extracted in all cases. Instead of pattern matching the +loop variable, consider using a `match` or `if let` inside the loop body. For +instance: + +```compile_fail,E0005 +let xs : Vec> = vec![Some(1), None]; + +// This fails because `None` is not covered. +for Some(x) in xs { + // ... +} +``` + +Match inside the loop instead: + +``` +let xs : Vec> = vec![Some(1), None]; + +for item in xs { + match item { + Some(x) => {}, + None => {}, + } +} +``` + +Or use `if let`: + +``` +let xs : Vec> = vec![Some(1), None]; + +for item in xs { + if let Some(x) = item { + // ... + } +} +``` +"##, + +E0301: r##" +Mutable borrows are not allowed in pattern guards, because matching cannot have +side effects. Side effects could alter the matched object or the environment +on which the match depends in such a way, that the match would not be +exhaustive. For instance, the following would not match any arm if mutable +borrows were allowed: + +```compile_fail,E0301 +match Some(()) { + None => { }, + option if option.take().is_none() => { + /* impossible, option is `Some` */ + }, + Some(_) => { } // When the previous match failed, the option became `None`. +} +``` +"##, + +E0302: r##" +Assignments are not allowed in pattern guards, because matching cannot have +side effects. Side effects could alter the matched object or the environment +on which the match depends in such a way, that the match would not be +exhaustive. For instance, the following would not match any arm if assignments +were allowed: + +```compile_fail,E0302 +match Some(()) { + None => { }, + option if { option = None; false } => { }, + Some(_) => { } // When the previous match failed, the option became `None`. +} +``` +"##, + +E0303: r##" +In certain cases it is possible for sub-bindings to violate memory safety. +Updates to the borrow checker in a future version of Rust may remove this +restriction, but for now patterns must be rewritten without sub-bindings. + +Before: + +```compile_fail,E0303 +match Some("hi".to_string()) { + ref op_string_ref @ Some(s) => {}, + None => {}, +} +``` + +After: + +``` +match Some("hi".to_string()) { + Some(ref s) => { + let op_string_ref = &Some(s); + // ... + }, + None => {}, +} +``` + +The `op_string_ref` binding has type `&Option<&String>` in both cases. + +See also https://github.com/rust-lang/rust/issues/14587 +"##, + +E0010: r##" +The value of statics and constants must be known at compile time, and they live +for the entire lifetime of a program. Creating a boxed value allocates memory on +the heap at runtime, and therefore cannot be done at compile time. Erroneous +code example: + +```compile_fail,E0010 +#![feature(box_syntax)] + +const CON : Box = box 0; +``` +"##, + +E0013: r##" +Static and const variables can refer to other const variables. But a const +variable cannot refer to a static variable. For example, `Y` cannot refer to +`X` here: + +```compile_fail,E0013 +static X: i32 = 42; +const Y: i32 = X; +``` + +To fix this, the value can be extracted as a const and then used: + +``` +const A: i32 = 42; +static X: i32 = A; +const Y: i32 = A; +``` +"##, + +// FIXME(#57563) Change the language here when const fn stabilizes +E0015: r##" +The only functions that can be called in static or constant expressions are +`const` functions, and struct/enum constructors. `const` functions are only +available on a nightly compiler. Rust currently does not support more general +compile-time function execution. + +``` +const FOO: Option = Some(1); // enum constructor +struct Bar {x: u8} +const BAR: Bar = Bar {x: 1}; // struct constructor +``` + +See [RFC 911] for more details on the design of `const fn`s. + +[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md +"##, + +E0017: r##" +References in statics and constants may only refer to immutable values. +Erroneous code example: + +```compile_fail,E0017 +static X: i32 = 1; +const C: i32 = 2; + +// these three are not allowed: +const CR: &mut i32 = &mut C; +static STATIC_REF: &'static mut i32 = &mut X; +static CONST_REF: &'static mut i32 = &mut C; +``` + +Statics are shared everywhere, and if they refer to mutable data one might +violate memory safety since holding multiple mutable references to shared data +is not allowed. + +If you really want global mutable state, try using `static mut` or a global +`UnsafeCell`. +"##, + +E0019: r##" +A function call isn't allowed in the const's initialization expression +because the expression's value must be known at compile-time. Erroneous code +example: + +```compile_fail +enum Test { + V1 +} + +impl Test { + fn test(&self) -> i32 { + 12 + } +} + +fn main() { + const FOO: Test = Test::V1; + + const A: i32 = FOO.test(); // You can't call Test::func() here! +} +``` + +Remember: you can't use a function call inside a const's initialization +expression! However, you can totally use it anywhere else: + +``` +enum Test { + V1 +} + +impl Test { + fn func(&self) -> i32 { + 12 + } +} + +fn main() { + const FOO: Test = Test::V1; + + FOO.func(); // here is good + let x = FOO.func(); // or even here! +} +``` +"##, + +E0133: r##" +Unsafe code was used outside of an unsafe function or block. + +Erroneous code example: + +```compile_fail,E0133 +unsafe fn f() { return; } // This is the unsafe code + +fn main() { + f(); // error: call to unsafe function requires unsafe function or block +} +``` + +Using unsafe functionality is potentially dangerous and disallowed by safety +checks. Examples: + +* Dereferencing raw pointers +* Calling functions via FFI +* Calling functions marked unsafe + +These safety checks can be relaxed for a section of the code by wrapping the +unsafe instructions with an `unsafe` block. For instance: + +``` +unsafe fn f() { return; } + +fn main() { + unsafe { f(); } // ok! +} +``` + +See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html +"##, + +E0373: r##" +This error occurs when an attempt is made to use data captured by a closure, +when that data may no longer exist. It's most commonly seen when attempting to +return a closure: + +```compile_fail,E0373 +fn foo() -> Box u32> { + let x = 0u32; + Box::new(|y| x + y) +} +``` + +Notice that `x` is stack-allocated by `foo()`. By default, Rust captures +closed-over data by reference. This means that once `foo()` returns, `x` no +longer exists. An attempt to access `x` within the closure would thus be +unsafe. + +Another situation where this might be encountered is when spawning threads: + +```compile_fail,E0373 +fn foo() { + let x = 0u32; + let y = 1u32; + + let thr = std::thread::spawn(|| { + x + y + }); +} +``` + +Since our new thread runs in parallel, the stack frame containing `x` and `y` +may well have disappeared by the time we try to use them. Even if we call +`thr.join()` within foo (which blocks until `thr` has completed, ensuring the +stack frame won't disappear), we will not succeed: the compiler cannot prove +that this behaviour is safe, and so won't let us do it. + +The solution to this problem is usually to switch to using a `move` closure. +This approach moves (or copies, where possible) data into the closure, rather +than taking references to it. For example: + +``` +fn foo() -> Box u32> { + let x = 0u32; + Box::new(move |y| x + y) +} +``` + +Now that the closure has its own copy of the data, there's no need to worry +about safety. +"##, + +E0381: r##" +It is not allowed to use or capture an uninitialized variable. For example: + +```compile_fail,E0381 +fn main() { + let x: i32; + let y = x; // error, use of possibly uninitialized variable +} +``` + +To fix this, ensure that any declared variables are initialized before being +used. Example: + +``` +fn main() { + let x: i32 = 0; + let y = x; // ok! +} +``` +"##, + +E0382: r##" +This error occurs when an attempt is made to use a variable after its contents +have been moved elsewhere. For example: + +```compile_fail,E0382 +struct MyStruct { s: u32 } + +fn main() { + let mut x = MyStruct{ s: 5u32 }; + let y = x; + x.s = 6; + println!("{}", x.s); +} +``` + +Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out +of `x` when we set `y`. This is fundamental to Rust's ownership system: outside +of workarounds like `Rc`, a value cannot be owned by more than one variable. + +Sometimes we don't need to move the value. Using a reference, we can let another +function borrow the value without changing its ownership. In the example below, +we don't actually have to move our string to `calculate_length`, we can give it +a reference to it with `&` instead. + +``` +fn main() { + let s1 = String::from("hello"); + + let len = calculate_length(&s1); + + println!("The length of '{}' is {}.", s1, len); +} + +fn calculate_length(s: &String) -> usize { + s.len() +} +``` + +A mutable reference can be created with `&mut`. + +Sometimes we don't want a reference, but a duplicate. All types marked `Clone` +can be duplicated by calling `.clone()`. Subsequent changes to a clone do not +affect the original variable. + +Most types in the standard library are marked `Clone`. The example below +demonstrates using `clone()` on a string. `s1` is first set to "many", and then +copied to `s2`. Then the first character of `s1` is removed, without affecting +`s2`. "any many" is printed to the console. + +``` +fn main() { + let mut s1 = String::from("many"); + let s2 = s1.clone(); + s1.remove(0); + println!("{} {}", s1, s2); +} +``` + +If we control the definition of a type, we can implement `Clone` on it ourselves +with `#[derive(Clone)]`. + +Some types have no ownership semantics at all and are trivial to duplicate. An +example is `i32` and the other number types. We don't have to call `.clone()` to +clone them, because they are marked `Copy` in addition to `Clone`. Implicit +cloning is more convenient in this case. We can mark our own types `Copy` if +all their members also are marked `Copy`. + +In the example below, we implement a `Point` type. Because it only stores two +integers, we opt-out of ownership semantics with `Copy`. Then we can +`let p2 = p1` without `p1` being moved. + +``` +#[derive(Copy, Clone)] +struct Point { x: i32, y: i32 } + +fn main() { + let mut p1 = Point{ x: -1, y: 2 }; + let p2 = p1; + p1.x = 1; + println!("p1: {}, {}", p1.x, p1.y); + println!("p2: {}, {}", p2.x, p2.y); +} +``` + +Alternatively, if we don't control the struct's definition, or mutable shared +ownership is truly required, we can use `Rc` and `RefCell`: + +``` +use std::cell::RefCell; +use std::rc::Rc; + +struct MyStruct { s: u32 } + +fn main() { + let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 })); + let y = x.clone(); + x.borrow_mut().s = 6; + println!("{}", x.borrow().s); +} +``` + +With this approach, x and y share ownership of the data via the `Rc` (reference +count type). `RefCell` essentially performs runtime borrow checking: ensuring +that at most one writer or multiple readers can access the data at any one time. + +If you wish to learn more about ownership in Rust, start with the chapter in the +Book: + +https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html +"##, + +E0383: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error occurs when an attempt is made to partially reinitialize a +structure that is currently uninitialized. + +For example, this can happen when a drop has taken place: + +```compile_fail +struct Foo { + a: u32, +} +impl Drop for Foo { + fn drop(&mut self) { /* ... */ } +} + +let mut x = Foo { a: 1 }; +drop(x); // `x` is now uninitialized +x.a = 2; // error, partial reinitialization of uninitialized structure `t` +``` + +This error can be fixed by fully reinitializing the structure in question: + +``` +struct Foo { + a: u32, +} +impl Drop for Foo { + fn drop(&mut self) { /* ... */ } +} + +let mut x = Foo { a: 1 }; +drop(x); +x = Foo { a: 2 }; +``` +"##, + +E0384: r##" +This error occurs when an attempt is made to reassign an immutable variable. +For example: + +```compile_fail,E0384 +fn main() { + let x = 3; + x = 5; // error, reassignment of immutable variable +} +``` + +By default, variables in Rust are immutable. To fix this error, add the keyword +`mut` after the keyword `let` when declaring the variable. For example: + +``` +fn main() { + let mut x = 3; + x = 5; +} +``` +"##, + +/*E0386: r##" +This error occurs when an attempt is made to mutate the target of a mutable +reference stored inside an immutable container. + +For example, this can happen when storing a `&mut` inside an immutable `Box`: + +```compile_fail,E0386 +let mut x: i64 = 1; +let y: Box<_> = Box::new(&mut x); +**y = 2; // error, cannot assign to data in an immutable container +``` + +This error can be fixed by making the container mutable: + +``` +let mut x: i64 = 1; +let mut y: Box<_> = Box::new(&mut x); +**y = 2; +``` + +It can also be fixed by using a type with interior mutability, such as `Cell` +or `RefCell`: + +``` +use std::cell::Cell; + +let x: i64 = 1; +let y: Box> = Box::new(Cell::new(x)); +y.set(2); +``` +"##,*/ + +E0387: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error occurs when an attempt is made to mutate or mutably reference data +that a closure has captured immutably. Examples of this error are shown below: + +```compile_fail +// Accepts a function or a closure that captures its environment immutably. +// Closures passed to foo will not be able to mutate their closed-over state. +fn foo(f: F) { } + +// Attempts to mutate closed-over data. Error message reads: +// `cannot assign to data in a captured outer variable...` +fn mutable() { + let mut x = 0u32; + foo(|| x = 2); +} + +// Attempts to take a mutable reference to closed-over data. Error message +// reads: `cannot borrow data mutably in a captured outer variable...` +fn mut_addr() { + let mut x = 0u32; + foo(|| { let y = &mut x; }); +} +``` + +The problem here is that foo is defined as accepting a parameter of type `Fn`. +Closures passed into foo will thus be inferred to be of type `Fn`, meaning that +they capture their context immutably. + +If the definition of `foo` is under your control, the simplest solution is to +capture the data mutably. This can be done by defining `foo` to take FnMut +rather than Fn: + +``` +fn foo(f: F) { } +``` + +Alternatively, we can consider using the `Cell` and `RefCell` types to achieve +interior mutability through a shared reference. Our example's `mutable` +function could be redefined as below: + +``` +use std::cell::Cell; + +fn foo(f: F) { } + +fn mutable() { + let x = Cell::new(0u32); + foo(|| x.set(2)); +} +``` + +You can read more about cell types in the API documentation: + +https://doc.rust-lang.org/std/cell/ +"##, + +E0388: r##" +E0388 was removed and is no longer issued. +"##, + +E0389: r##" +#### Note: this error code is no longer emitted by the compiler. + +An attempt was made to mutate data using a non-mutable reference. This +commonly occurs when attempting to assign to a non-mutable reference of a +mutable reference (`&(&mut T)`). + +Example of erroneous code: + +```compile_fail +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy = FancyNum{ num: 5 }; + let fancy_ref = &(&mut fancy); + fancy_ref.num = 6; // error: cannot assign to data in a `&` reference + println!("{}", fancy_ref.num); +} +``` + +Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an +immutable reference to a value borrows it immutably. There can be multiple +references of type `&(&mut T)` that point to the same value, so they must be +immutable to prevent multiple mutable references to the same value. + +To fix this, either remove the outer reference: + +``` +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy = FancyNum{ num: 5 }; + + let fancy_ref = &mut fancy; + // `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum) + + fancy_ref.num = 6; // No error! + + println!("{}", fancy_ref.num); +} +``` + +Or make the outer reference mutable: + +``` +struct FancyNum { + num: u8 +} + +fn main() { + let mut fancy = FancyNum{ num: 5 }; + + let fancy_ref = &mut (&mut fancy); + // `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum) + + fancy_ref.num = 6; // No error! + + println!("{}", fancy_ref.num); +} +``` +"##, + +E0161: r##" +A value was moved. However, its size was not known at compile time, and only +values of a known size can be moved. + +Erroneous code example: + +```compile_fail +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<[isize]> = box *array; + // error: cannot move a value of type [isize]: the size of [isize] cannot + // be statically determined +} +``` + +In Rust, you can only move a value when its size is known at compile time. + +To work around this restriction, consider "hiding" the value behind a reference: +either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move +it around as usual. Example: + +``` +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<&[isize]> = box array; // ok! +} +``` +"##, + +E0492: r##" +A borrow of a constant containing interior mutability was attempted. Erroneous +code example: + +```compile_fail,E0492 +use std::sync::atomic::AtomicUsize; + +const A: AtomicUsize = AtomicUsize::new(0); +static B: &'static AtomicUsize = &A; +// error: cannot borrow a constant which may contain interior mutability, +// create a static instead +``` + +A `const` represents a constant value that should never change. If one takes +a `&` reference to the constant, then one is taking a pointer to some memory +location containing the value. Normally this is perfectly fine: most values +can't be changed via a shared `&` pointer, but interior mutability would allow +it. That is, a constant value could be mutated. On the other hand, a `static` is +explicitly a single memory location, which can be mutated at will. + +So, in order to solve this error, either use statics which are `Sync`: + +``` +use std::sync::atomic::AtomicUsize; + +static A: AtomicUsize = AtomicUsize::new(0); +static B: &'static AtomicUsize = &A; // ok! +``` + +You can also have this error while using a cell type: + +```compile_fail,E0492 +use std::cell::Cell; + +const A: Cell = Cell::new(1); +const B: &Cell = &A; +// error: cannot borrow a constant which may contain interior mutability, +// create a static instead + +// or: +struct C { a: Cell } + +const D: C = C { a: Cell::new(1) }; +const E: &Cell = &D.a; // error + +// or: +const F: &C = &D; // error +``` + +This is because cell types do operations that are not thread-safe. Due to this, +they don't implement Sync and thus can't be placed in statics. + +However, if you still wish to use these types, you can achieve this by an unsafe +wrapper: + +``` +use std::cell::Cell; +use std::marker::Sync; + +struct NotThreadSafe { + value: Cell, +} + +unsafe impl Sync for NotThreadSafe {} + +static A: NotThreadSafe = NotThreadSafe { value : Cell::new(1) }; +static B: &'static NotThreadSafe = &A; // ok! +``` + +Remember this solution is unsafe! You will have to ensure that accesses to the +cell are synchronized. +"##, + +E0499: r##" +A variable was borrowed as mutable more than once. Erroneous code example: + +```compile_fail,E0499 +let mut i = 0; +let mut x = &mut i; +let mut a = &mut i; +x; +// error: cannot borrow `i` as mutable more than once at a time +``` + +Please note that in rust, you can either have many immutable references, or one +mutable reference. Take a look at +https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html for more +information. Example: + + +``` +let mut i = 0; +let mut x = &mut i; // ok! + +// or: +let mut i = 0; +let a = &i; // ok! +let b = &i; // still ok! +let c = &i; // still ok! +b; +a; +``` +"##, + +E0500: r##" +A borrowed variable was used by a closure. Example of erroneous code: + +```compile_fail,E0500 +fn you_know_nothing(jon_snow: &mut i32) { + let nights_watch = &jon_snow; + let starks = || { + *jon_snow = 3; // error: closure requires unique access to `jon_snow` + // but it is already borrowed + }; + println!("{}", nights_watch); +} +``` + +In here, `jon_snow` is already borrowed by the `nights_watch` reference, so it +cannot be borrowed by the `starks` closure at the same time. To fix this issue, +you can create the closure after the borrow has ended: + +``` +fn you_know_nothing(jon_snow: &mut i32) { + let nights_watch = &jon_snow; + println!("{}", nights_watch); + let starks = || { + *jon_snow = 3; + }; +} +``` + +Or, if the type implements the `Clone` trait, you can clone it between +closures: + +``` +fn you_know_nothing(jon_snow: &mut i32) { + let mut jon_copy = jon_snow.clone(); + let starks = || { + *jon_snow = 3; + }; + println!("{}", jon_copy); +} +``` +"##, + +E0501: r##" +This error indicates that a mutable variable is being used while it is still +captured by a closure. Because the closure has borrowed the variable, it is not +available for use until the closure goes out of scope. + +Note that a capture will either move or borrow a variable, but in this +situation, the closure is borrowing the variable. Take a look at +http://rustbyexample.com/fn/closures/capture.html for more information about +capturing. + +Example of erroneous code: + +```compile_fail,E0501 +fn inside_closure(x: &mut i32) { + // Actions which require unique access +} + +fn outside_closure(x: &mut i32) { + // Actions which require unique access +} + +fn foo(a: &mut i32) { + let mut bar = || { + inside_closure(a) + }; + outside_closure(a); // error: cannot borrow `*a` as mutable because previous + // closure requires unique access. + bar(); +} +``` + +To fix this error, you can finish using the closure before using the captured +variable: + +``` +fn inside_closure(x: &mut i32) {} +fn outside_closure(x: &mut i32) {} + +fn foo(a: &mut i32) { + let mut bar = || { + inside_closure(a) + }; + bar(); + // borrow on `a` ends. + outside_closure(a); // ok! +} +``` + +Or you can pass the variable as a parameter to the closure: + +``` +fn inside_closure(x: &mut i32) {} +fn outside_closure(x: &mut i32) {} + +fn foo(a: &mut i32) { + let mut bar = |s: &mut i32| { + inside_closure(s) + }; + outside_closure(a); + bar(a); +} +``` + +It may be possible to define the closure later: + +``` +fn inside_closure(x: &mut i32) {} +fn outside_closure(x: &mut i32) {} + +fn foo(a: &mut i32) { + outside_closure(a); + let mut bar = || { + inside_closure(a) + }; + bar(); +} +``` +"##, + +E0502: r##" +This error indicates that you are trying to borrow a variable as mutable when it +has already been borrowed as immutable. + +Example of erroneous code: + +```compile_fail,E0502 +fn bar(x: &mut i32) {} +fn foo(a: &mut i32) { + let ref y = a; // a is borrowed as immutable. + bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed + // as immutable + println!("{}", y); +} +``` + +To fix this error, ensure that you don't have any other references to the +variable before trying to access it mutably: + +``` +fn bar(x: &mut i32) {} +fn foo(a: &mut i32) { + bar(a); + let ref y = a; // ok! + println!("{}", y); +} +``` + +For more information on the rust ownership system, take a look at +https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html. +"##, + +E0503: r##" +A value was used after it was mutably borrowed. + +Example of erroneous code: + +```compile_fail,E0503 +fn main() { + let mut value = 3; + // Create a mutable borrow of `value`. + let borrow = &mut value; + let _sum = value + 1; // error: cannot use `value` because + // it was mutably borrowed + println!("{}", borrow); +} +``` + +In this example, `value` is mutably borrowed by `borrow` and cannot be +used to calculate `sum`. This is not possible because this would violate +Rust's mutability rules. + +You can fix this error by finishing using the borrow before the next use of +the value: + +``` +fn main() { + let mut value = 3; + let borrow = &mut value; + println!("{}", borrow); + // The block has ended and with it the borrow. + // You can now use `value` again. + let _sum = value + 1; +} +``` + +Or by cloning `value` before borrowing it: + +``` +fn main() { + let mut value = 3; + // We clone `value`, creating a copy. + let value_cloned = value.clone(); + // The mutable borrow is a reference to `value` and + // not to `value_cloned`... + let borrow = &mut value; + // ... which means we can still use `value_cloned`, + let _sum = value_cloned + 1; + // even though the borrow only ends here. + println!("{}", borrow); +} +``` + +You can find more information about borrowing in the rust-book: +http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html +"##, + +E0504: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error occurs when an attempt is made to move a borrowed variable into a +closure. + +Example of erroneous code: + +```compile_fail +struct FancyNum { + num: u8, +} + +fn main() { + let fancy_num = FancyNum { num: 5 }; + let fancy_ref = &fancy_num; + + let x = move || { + println!("child function: {}", fancy_num.num); + // error: cannot move `fancy_num` into closure because it is borrowed + }; + + x(); + println!("main function: {}", fancy_ref.num); +} +``` + +Here, `fancy_num` is borrowed by `fancy_ref` and so cannot be moved into +the closure `x`. There is no way to move a value into a closure while it is +borrowed, as that would invalidate the borrow. + +If the closure can't outlive the value being moved, try using a reference +rather than moving: + +``` +struct FancyNum { + num: u8, +} + +fn main() { + let fancy_num = FancyNum { num: 5 }; + let fancy_ref = &fancy_num; + + let x = move || { + // fancy_ref is usable here because it doesn't move `fancy_num` + println!("child function: {}", fancy_ref.num); + }; + + x(); + + println!("main function: {}", fancy_num.num); +} +``` + +If the value has to be borrowed and then moved, try limiting the lifetime of +the borrow using a scoped block: + +``` +struct FancyNum { + num: u8, +} + +fn main() { + let fancy_num = FancyNum { num: 5 }; + + { + let fancy_ref = &fancy_num; + println!("main function: {}", fancy_ref.num); + // `fancy_ref` goes out of scope here + } + + let x = move || { + // `fancy_num` can be moved now (no more references exist) + println!("child function: {}", fancy_num.num); + }; + + x(); +} +``` + +If the lifetime of a reference isn't enough, such as in the case of threading, +consider using an `Arc` to create a reference-counted value: + +``` +use std::sync::Arc; +use std::thread; + +struct FancyNum { + num: u8, +} + +fn main() { + let fancy_ref1 = Arc::new(FancyNum { num: 5 }); + let fancy_ref2 = fancy_ref1.clone(); + + let x = thread::spawn(move || { + // `fancy_ref1` can be moved and has a `'static` lifetime + println!("child thread: {}", fancy_ref1.num); + }); + + x.join().expect("child thread should finish"); + println!("main thread: {}", fancy_ref2.num); +} +``` +"##, + +E0505: r##" +A value was moved out while it was still borrowed. + +Erroneous code example: + +```compile_fail,E0505 +struct Value {} + +fn borrow(val: &Value) {} + +fn eat(val: Value) {} + +fn main() { + let x = Value{}; + let _ref_to_val: &Value = &x; + eat(x); + borrow(_ref_to_val); +} +``` + +Here, the function `eat` takes ownership of `x`. However, +`x` cannot be moved because the borrow to `_ref_to_val` +needs to last till the function `borrow`. +To fix that you can do a few different things: + +* Try to avoid moving the variable. +* Release borrow before move. +* Implement the `Copy` trait on the type. + +Examples: + +``` +struct Value {} + +fn borrow(val: &Value) {} + +fn eat(val: &Value) {} + +fn main() { + let x = Value{}; + + let ref_to_val: &Value = &x; + eat(&x); // pass by reference, if it's possible + borrow(ref_to_val); +} +``` + +Or: + +``` +struct Value {} + +fn borrow(val: &Value) {} + +fn eat(val: Value) {} + +fn main() { + let x = Value{}; + + let ref_to_val: &Value = &x; + borrow(ref_to_val); + // ref_to_val is no longer used. + eat(x); +} +``` + +Or: + +``` +#[derive(Clone, Copy)] // implement Copy trait +struct Value {} + +fn borrow(val: &Value) {} + +fn eat(val: Value) {} + +fn main() { + let x = Value{}; + let ref_to_val: &Value = &x; + eat(x); // it will be copied here. + borrow(ref_to_val); +} +``` + +You can find more information about borrowing in the rust-book: +http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html +"##, + +E0506: r##" +This error occurs when an attempt is made to assign to a borrowed value. + +Example of erroneous code: + +```compile_fail,E0506 +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy_num = FancyNum { num: 5 }; + let fancy_ref = &fancy_num; + fancy_num = FancyNum { num: 6 }; + // error: cannot assign to `fancy_num` because it is borrowed + + println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num); +} +``` + +Because `fancy_ref` still holds a reference to `fancy_num`, `fancy_num` can't +be assigned to a new value as it would invalidate the reference. + +Alternatively, we can move out of `fancy_num` into a second `fancy_num`: + +``` +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy_num = FancyNum { num: 5 }; + let moved_num = fancy_num; + fancy_num = FancyNum { num: 6 }; + + println!("Num: {}, Moved num: {}", fancy_num.num, moved_num.num); +} +``` + +If the value has to be borrowed, try limiting the lifetime of the borrow using +a scoped block: + +``` +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy_num = FancyNum { num: 5 }; + + { + let fancy_ref = &fancy_num; + println!("Ref: {}", fancy_ref.num); + } + + // Works because `fancy_ref` is no longer in scope + fancy_num = FancyNum { num: 6 }; + println!("Num: {}", fancy_num.num); +} +``` + +Or by moving the reference into a function: + +``` +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy_num = FancyNum { num: 5 }; + + print_fancy_ref(&fancy_num); + + // Works because function borrow has ended + fancy_num = FancyNum { num: 6 }; + println!("Num: {}", fancy_num.num); +} + +fn print_fancy_ref(fancy_ref: &FancyNum){ + println!("Ref: {}", fancy_ref.num); +} +``` +"##, + +E0507: r##" +You tried to move out of a value which was borrowed. Erroneous code example: + +```compile_fail,E0507 +use std::cell::RefCell; + +struct TheDarkKnight; + +impl TheDarkKnight { + fn nothing_is_true(self) {} +} + +fn main() { + let x = RefCell::new(TheDarkKnight); + + x.borrow().nothing_is_true(); // error: cannot move out of borrowed content +} +``` + +Here, the `nothing_is_true` method takes the ownership of `self`. However, +`self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`, +which is a borrow of the content owned by the `RefCell`. To fix this error, +you have three choices: + +* Try to avoid moving the variable. +* Somehow reclaim the ownership. +* Implement the `Copy` trait on the type. + +Examples: + +``` +use std::cell::RefCell; + +struct TheDarkKnight; + +impl TheDarkKnight { + fn nothing_is_true(&self) {} // First case, we don't take ownership +} + +fn main() { + let x = RefCell::new(TheDarkKnight); + + x.borrow().nothing_is_true(); // ok! +} +``` + +Or: + +``` +use std::cell::RefCell; + +struct TheDarkKnight; + +impl TheDarkKnight { + fn nothing_is_true(self) {} +} + +fn main() { + let x = RefCell::new(TheDarkKnight); + let x = x.into_inner(); // we get back ownership + + x.nothing_is_true(); // ok! +} +``` + +Or: + +``` +use std::cell::RefCell; + +#[derive(Clone, Copy)] // we implement the Copy trait +struct TheDarkKnight; + +impl TheDarkKnight { + fn nothing_is_true(self) {} +} + +fn main() { + let x = RefCell::new(TheDarkKnight); + + x.borrow().nothing_is_true(); // ok! +} +``` + +Moving a member out of a mutably borrowed struct will also cause E0507 error: + +```compile_fail,E0507 +struct TheDarkKnight; + +impl TheDarkKnight { + fn nothing_is_true(self) {} +} + +struct Batcave { + knight: TheDarkKnight +} + +fn main() { + let mut cave = Batcave { + knight: TheDarkKnight + }; + let borrowed = &mut cave; + + borrowed.knight.nothing_is_true(); // E0507 +} +``` + +It is fine only if you put something back. `mem::replace` can be used for that: + +``` +# struct TheDarkKnight; +# impl TheDarkKnight { fn nothing_is_true(self) {} } +# struct Batcave { knight: TheDarkKnight } +use std::mem; + +let mut cave = Batcave { + knight: TheDarkKnight +}; +let borrowed = &mut cave; + +mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok! +``` + +You can find more information about borrowing in the rust-book: +http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html +"##, + +E0508: r##" +A value was moved out of a non-copy fixed-size array. + +Example of erroneous code: + +```compile_fail,E0508 +struct NonCopy; + +fn main() { + let array = [NonCopy; 1]; + let _value = array[0]; // error: cannot move out of type `[NonCopy; 1]`, + // a non-copy fixed-size array +} +``` + +The first element was moved out of the array, but this is not +possible because `NonCopy` does not implement the `Copy` trait. + +Consider borrowing the element instead of moving it: + +``` +struct NonCopy; + +fn main() { + let array = [NonCopy; 1]; + let _value = &array[0]; // Borrowing is allowed, unlike moving. +} +``` + +Alternatively, if your type implements `Clone` and you need to own the value, +consider borrowing and then cloning: + +``` +#[derive(Clone)] +struct NonCopy; + +fn main() { + let array = [NonCopy; 1]; + // Now you can clone the array element. + let _value = array[0].clone(); +} +``` +"##, + +E0509: r##" +This error occurs when an attempt is made to move out of a value whose type +implements the `Drop` trait. + +Example of erroneous code: + +```compile_fail,E0509 +struct FancyNum { + num: usize +} + +struct DropStruct { + fancy: FancyNum +} + +impl Drop for DropStruct { + fn drop(&mut self) { + // Destruct DropStruct, possibly using FancyNum + } +} + +fn main() { + let drop_struct = DropStruct{fancy: FancyNum{num: 5}}; + let fancy_field = drop_struct.fancy; // Error E0509 + println!("Fancy: {}", fancy_field.num); + // implicit call to `drop_struct.drop()` as drop_struct goes out of scope +} +``` + +Here, we tried to move a field out of a struct of type `DropStruct` which +implements the `Drop` trait. However, a struct cannot be dropped if one or +more of its fields have been moved. + +Structs implementing the `Drop` trait have an implicit destructor that gets +called when they go out of scope. This destructor may use the fields of the +struct, so moving out of the struct could make it impossible to run the +destructor. Therefore, we must think of all values whose type implements the +`Drop` trait as single units whose fields cannot be moved. + +This error can be fixed by creating a reference to the fields of a struct, +enum, or tuple using the `ref` keyword: + +``` +struct FancyNum { + num: usize +} + +struct DropStruct { + fancy: FancyNum +} + +impl Drop for DropStruct { + fn drop(&mut self) { + // Destruct DropStruct, possibly using FancyNum + } +} + +fn main() { + let drop_struct = DropStruct{fancy: FancyNum{num: 5}}; + let ref fancy_field = drop_struct.fancy; // No more errors! + println!("Fancy: {}", fancy_field.num); + // implicit call to `drop_struct.drop()` as drop_struct goes out of scope +} +``` + +Note that this technique can also be used in the arms of a match expression: + +``` +struct FancyNum { + num: usize +} + +enum DropEnum { + Fancy(FancyNum) +} + +impl Drop for DropEnum { + fn drop(&mut self) { + // Destruct DropEnum, possibly using FancyNum + } +} + +fn main() { + // Creates and enum of type `DropEnum`, which implements `Drop` + let drop_enum = DropEnum::Fancy(FancyNum{num: 10}); + match drop_enum { + // Creates a reference to the inside of `DropEnum::Fancy` + DropEnum::Fancy(ref fancy_field) => // No error! + println!("It was fancy-- {}!", fancy_field.num), + } + // implicit call to `drop_enum.drop()` as drop_enum goes out of scope +} +``` +"##, + +E0510: r##" +Cannot mutate place in this match guard. + +When matching on a variable it cannot be mutated in the match guards, as this +could cause the match to be non-exhaustive: + +```compile_fail,E0510 +#![feature(nll, bind_by_move_pattern_guards)] +let mut x = Some(0); +match x { + None => (), + Some(_) if { x = None; false } => (), + Some(v) => (), // No longer matches +} +``` + +Here executing `x = None` would modify the value being matched and require us +to go "back in time" to the `None` arm. +"##, + +E0579: r##" +When matching against an exclusive range, the compiler verifies that the range +is non-empty. Exclusive range patterns include the start point but not the end +point, so this is equivalent to requiring the start of the range to be less +than the end of the range. + +For example: + +```compile_fail +match 5u32 { + // This range is ok, albeit pointless. + 1 .. 2 => {} + // This range is empty, and the compiler can tell. + 5 .. 5 => {} +} +``` +"##, + +E0515: r##" +Cannot return value that references local variable + +Local variables, function parameters and temporaries are all dropped before the +end of the function body. So a reference to them cannot be returned. + +```compile_fail,E0515 +#![feature(nll)] +fn get_dangling_reference() -> &'static i32 { + let x = 0; + &x +} +``` + +```compile_fail,E0515 +#![feature(nll)] +use std::slice::Iter; +fn get_dangling_iterator<'a>() -> Iter<'a, i32> { + let v = vec![1, 2, 3]; + v.iter() +} +``` + +Consider returning an owned value instead: + +``` +use std::vec::IntoIter; + +fn get_integer() -> i32 { + let x = 0; + x +} + +fn get_owned_iterator() -> IntoIter { + let v = vec![1, 2, 3]; + v.into_iter() +} +``` +"##, + +E0595: r##" +#### Note: this error code is no longer emitted by the compiler. + +Closures cannot mutate immutable captured variables. + +Erroneous code example: + +```compile_fail,E0594 +let x = 3; // error: closure cannot assign to immutable local variable `x` +let mut c = || { x += 1 }; +``` + +Make the variable binding mutable: + +``` +let mut x = 3; // ok! +let mut c = || { x += 1 }; +``` +"##, + +E0596: r##" +This error occurs because you tried to mutably borrow a non-mutable variable. + +Example of erroneous code: + +```compile_fail,E0596 +let x = 1; +let y = &mut x; // error: cannot borrow mutably +``` + +In here, `x` isn't mutable, so when we try to mutably borrow it in `y`, it +fails. To fix this error, you need to make `x` mutable: + +``` +let mut x = 1; +let y = &mut x; // ok! +``` +"##, + +E0597: r##" +This error occurs because a value was dropped while it was still borrowed + +Example of erroneous code: + +```compile_fail,E0597 +struct Foo<'a> { + x: Option<&'a u32>, +} + +let mut x = Foo { x: None }; +{ + let y = 0; + x.x = Some(&y); // error: `y` does not live long enough +} +println!("{:?}", x.x); +``` + +In here, `y` is dropped at the end of the inner scope, but it is borrowed by +`x` until the `println`. To fix the previous example, just remove the scope +so that `y` isn't dropped until after the println + +``` +struct Foo<'a> { + x: Option<&'a u32>, +} + +let mut x = Foo { x: None }; + +let y = 0; +x.x = Some(&y); + +println!("{:?}", x.x); +``` +"##, + +E0626: r##" +This error occurs because a borrow in a generator persists across a +yield point. + +```compile_fail,E0626 +# #![feature(generators, generator_trait, pin)] +# use std::ops::Generator; +# use std::pin::Pin; +let mut b = || { + let a = &String::new(); // <-- This borrow... + yield (); // ...is still in scope here, when the yield occurs. + println!("{}", a); +}; +Pin::new(&mut b).resume(); +``` + +At present, it is not permitted to have a yield that occurs while a +borrow is still in scope. To resolve this error, the borrow must +either be "contained" to a smaller scope that does not overlap the +yield or else eliminated in another way. So, for example, we might +resolve the previous example by removing the borrow and just storing +the integer by value: + +``` +# #![feature(generators, generator_trait, pin)] +# use std::ops::Generator; +# use std::pin::Pin; +let mut b = || { + let a = 3; + yield (); + println!("{}", a); +}; +Pin::new(&mut b).resume(); +``` + +This is a very simple case, of course. In more complex cases, we may +wish to have more than one reference to the value that was borrowed -- +in those cases, something like the `Rc` or `Arc` types may be useful. + +This error also frequently arises with iteration: + +```compile_fail,E0626 +# #![feature(generators, generator_trait, pin)] +# use std::ops::Generator; +# use std::pin::Pin; +let mut b = || { + let v = vec![1,2,3]; + for &x in &v { // <-- borrow of `v` is still in scope... + yield x; // ...when this yield occurs. + } +}; +Pin::new(&mut b).resume(); +``` + +Such cases can sometimes be resolved by iterating "by value" (or using +`into_iter()`) to avoid borrowing: + +``` +# #![feature(generators, generator_trait, pin)] +# use std::ops::Generator; +# use std::pin::Pin; +let mut b = || { + let v = vec![1,2,3]; + for x in v { // <-- Take ownership of the values instead! + yield x; // <-- Now yield is OK. + } +}; +Pin::new(&mut b).resume(); +``` + +If taking ownership is not an option, using indices can work too: + +``` +# #![feature(generators, generator_trait, pin)] +# use std::ops::Generator; +# use std::pin::Pin; +let mut b = || { + let v = vec![1,2,3]; + let len = v.len(); // (*) + for i in 0..len { + let x = v[i]; // (*) + yield x; // <-- Now yield is OK. + } +}; +Pin::new(&mut b).resume(); + +// (*) -- Unfortunately, these temporaries are currently required. +// See . +``` +"##, + +E0712: r##" +This error occurs because a borrow of a thread-local variable was made inside a +function which outlived the lifetime of the function. + +Example of erroneous code: + +```compile_fail,E0712 +#![feature(nll)] +#![feature(thread_local)] + +#[thread_local] +static FOO: u8 = 3; + +fn main() { + let a = &FOO; // error: thread-local variable borrowed past end of function + + std::thread::spawn(move || { + println!("{}", a); + }); +} +``` +"##, + +E0713: r##" +This error occurs when an attempt is made to borrow state past the end of the +lifetime of a type that implements the `Drop` trait. + +Example of erroneous code: + +```compile_fail,E0713 +#![feature(nll)] + +pub struct S<'a> { data: &'a mut String } + +impl<'a> Drop for S<'a> { + fn drop(&mut self) { self.data.push_str("being dropped"); } +} + +fn demo<'a>(s: S<'a>) -> &'a mut String { let p = &mut *s.data; p } +``` + +Here, `demo` tries to borrow the string data held within its +argument `s` and then return that borrow. However, `S` is +declared as implementing `Drop`. + +Structs implementing the `Drop` trait have an implicit destructor that +gets called when they go out of scope. This destructor gets exclusive +access to the fields of the struct when it runs. + +This means that when `s` reaches the end of `demo`, its destructor +gets exclusive access to its `&mut`-borrowed string data. allowing +another borrow of that string data (`p`), to exist across the drop of +`s` would be a violation of the principle that `&mut`-borrows have +exclusive, unaliased access to their referenced data. + +This error can be fixed by changing `demo` so that the destructor does +not run while the string-data is borrowed; for example by taking `S` +by reference: + +``` +#![feature(nll)] + +pub struct S<'a> { data: &'a mut String } + +impl<'a> Drop for S<'a> { + fn drop(&mut self) { self.data.push_str("being dropped"); } +} + +fn demo<'a>(s: &'a mut S<'a>) -> &'a mut String { let p = &mut *(*s).data; p } +``` + +Note that this approach needs a reference to S with lifetime `'a`. +Nothing shorter than `'a` will suffice: a shorter lifetime would imply +that after `demo` finishes executing, something else (such as the +destructor!) could access `s.data` after the end of that shorter +lifetime, which would again violate the `&mut`-borrow's exclusive +access. +"##, + +E0716: r##" +This error indicates that a temporary value is being dropped +while a borrow is still in active use. + +Erroneous code example: + +```compile_fail,E0716 +# #![feature(nll)] +fn foo() -> i32 { 22 } +fn bar(x: &i32) -> &i32 { x } +let p = bar(&foo()); + // ------ creates a temporary +let q = *p; +``` + +Here, the expression `&foo()` is borrowing the expression +`foo()`. As `foo()` is a call to a function, and not the name of +a variable, this creates a **temporary** -- that temporary stores +the return value from `foo()` so that it can be borrowed. +You could imagine that `let p = bar(&foo());` is equivalent +to this: + +```compile_fail,E0597 +# fn foo() -> i32 { 22 } +# fn bar(x: &i32) -> &i32 { x } +let p = { + let tmp = foo(); // the temporary + bar(&tmp) +}; // <-- tmp is freed as we exit this block +let q = p; +``` + +Whenever a temporary is created, it is automatically dropped (freed) +according to fixed rules. Ordinarily, the temporary is dropped +at the end of the enclosing statement -- in this case, after the `let`. +This is illustrated in the example above by showing that `tmp` would +be freed as we exit the block. + +To fix this problem, you need to create a local variable +to store the value in rather than relying on a temporary. +For example, you might change the original program to +the following: + +``` +fn foo() -> i32 { 22 } +fn bar(x: &i32) -> &i32 { x } +let value = foo(); // dropped at the end of the enclosing block +let p = bar(&value); +let q = *p; +``` + +By introducing the explicit `let value`, we allocate storage +that will last until the end of the enclosing block (when `value` +goes out of scope). When we borrow `&value`, we are borrowing a +local variable that already exists, and hence no temporary is created. + +Temporaries are not always dropped at the end of the enclosing +statement. In simple cases where the `&` expression is immediately +stored into a variable, the compiler will automatically extend +the lifetime of the temporary until the end of the enclosing +block. Therefore, an alternative way to fix the original +program is to write `let tmp = &foo()` and not `let tmp = foo()`: + +``` +fn foo() -> i32 { 22 } +fn bar(x: &i32) -> &i32 { x } +let value = &foo(); +let p = bar(value); +let q = *p; +``` + +Here, we are still borrowing `foo()`, but as the borrow is assigned +directly into a variable, the temporary will not be dropped until +the end of the enclosing block. Similar rules apply when temporaries +are stored into aggregate structures like a tuple or struct: + +``` +// Here, two temporaries are created, but +// as they are stored directly into `value`, +// they are not dropped until the end of the +// enclosing block. +fn foo() -> i32 { 22 } +let value = (&foo(), &foo()); +``` +"##, + +E0723: r##" +An feature unstable in `const` contexts was used. + +Erroneous code example: + +```compile_fail,E0723 +trait T {} + +impl T for () {} + +const fn foo() -> impl T { // error: `impl Trait` in const fn is unstable + () +} +``` + +To enable this feature on a nightly version of rustc, add the `const_fn` +feature flag: + +``` +#![feature(const_fn)] + +trait T {} + +impl T for () {} + +const fn foo() -> impl T { + () +} +``` +"##, + +E0729: r##" +Support for Non-Lexical Lifetimes (NLL) has been included in the Rust compiler +since 1.31, and has been enabled on the 2015 edition since 1.36. The new borrow +checker for NLL uncovered some bugs in the old borrow checker, which in some +cases allowed unsound code to compile, resulting in memory safety issues. + +### What do I do? + +Change your code so the warning does no longer trigger. For backwards +compatibility, this unsound code may still compile (with a warning) right now. +However, at some point in the future, the compiler will no longer accept this +code and will throw a hard error. + +### Shouldn't you fix the old borrow checker? + +The old borrow checker has known soundness issues that are basically impossible +to fix. The new NLL-based borrow checker is the fix. + +### Can I turn these warnings into errors by denying a lint? + +No. + +### When are these warnings going to turn into errors? + +No formal timeline for turning the warnings into errors has been set. See +[GitHub issue 58781](https://github.com/rust-lang/rust/issues/58781) for more +information. + +### Why do I get this message with code that doesn't involve borrowing? + +There are some known bugs that trigger this message. +"##, +} + +register_diagnostics! { +// E0298, // cannot compare constants +// E0299, // mismatched types between arms +// E0471, // constant evaluation error (in pattern) +// E0385, // {} in an aliasable location + E0493, // destructors cannot be evaluated at compile-time + E0521, // borrowed data escapes outside of closure + E0524, // two closures require unique access to `..` at the same time + E0526, // shuffle indices are not constant + E0594, // cannot assign to {} + E0598, // lifetime of {} is too short to guarantee its contents can be... + E0625, // thread-local statics cannot be accessed at compile-time +} diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs index caadc6055b5c6..bc01e3ee95b97 100644 --- a/src/librustc_mir/hair/constant.rs +++ b/src/librustc_mir/hair/constant.rs @@ -1,5 +1,5 @@ use syntax::ast; -use rustc::ty::{self, Ty, TyCtxt, ParamEnv}; +use rustc::ty::{self, Ty, TyCtxt, ParamEnv, layout::Size}; use syntax_pos::symbol::Symbol; use rustc::mir::interpret::{ConstValue, Scalar}; @@ -9,49 +9,36 @@ crate enum LitToConstError { Reported, } -crate fn lit_to_const<'a, 'gcx, 'tcx>( +crate fn lit_to_const<'tcx>( lit: &'tcx ast::LitKind, - tcx: TyCtxt<'a, 'gcx, 'tcx>, + tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, neg: bool, -) -> Result, LitToConstError> { +) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> { use syntax::ast::*; let trunc = |n| { - let param_ty = ParamEnv::reveal_all().and(tcx.lift_to_global(&ty).unwrap()); + let param_ty = ParamEnv::reveal_all().and(ty); let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size; trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); let result = truncate(n, width); trace!("trunc result: {}", result); - Ok(ConstValue::Scalar(Scalar::Bits { - bits: result, - size: width.bytes() as u8, - })) + Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) }; use rustc::mir::interpret::*; let lit = match *lit { LitKind::Str(ref s, _) => { let s = s.as_str(); - let id = tcx.allocate_bytes(s.as_bytes()); - ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64) - }, - LitKind::Err(ref s) => { - let s = s.as_str(); - let id = tcx.allocate_bytes(s.as_bytes()); - return Ok(ty::Const { - val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64), - ty: tcx.types.err, - }); + let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes()); + let allocation = tcx.intern_const_alloc(allocation); + ConstValue::Slice { data: allocation, start: 0, end: s.len() } }, LitKind::ByteStr(ref data) => { let id = tcx.allocate_bytes(data); ConstValue::Scalar(Scalar::Ptr(id.into())) }, - LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bits { - bits: n as u128, - size: 1, - }), + LitKind::Byte(n) => ConstValue::Scalar(Scalar::from_uint(n, Size::from_bytes(1))), LitKind::Int(n, _) if neg => { let n = n as i128; let n = n.overflowing_neg().0; @@ -70,8 +57,9 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>( } LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)), LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)), + LitKind::Err(_) => unreachable!(), }; - Ok(ty::Const { val: lit, ty }) + Ok(tcx.mk_const(ty::Const { val: lit, ty })) } fn parse_float<'tcx>( @@ -81,8 +69,7 @@ fn parse_float<'tcx>( ) -> Result, ()> { let num = num.as_str(); use rustc_apfloat::ieee::{Single, Double}; - use rustc_apfloat::Float; - let (bits, size) = match fty { + let scalar = match fty { ast::FloatTy::F32 => { num.parse::().map_err(|_| ())?; let mut f = num.parse::().unwrap_or_else(|e| { @@ -91,19 +78,19 @@ fn parse_float<'tcx>( if neg { f = -f; } - (f.to_bits(), 4) + Scalar::from_f32(f) } ast::FloatTy::F64 => { num.parse::().map_err(|_| ())?; let mut f = num.parse::().unwrap_or_else(|e| { - panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e) + panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e) }); if neg { f = -f; } - (f.to_bits(), 8) + Scalar::from_f64(f) } }; - Ok(ConstValue::Scalar(Scalar::Bits { bits, size })) + Ok(ConstValue::Scalar(scalar)) } diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index f58e61915e8c9..9a73842d2f02a 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -10,7 +10,7 @@ use rustc_data_structures::indexed_vec::Idx; impl<'tcx> Mirror<'tcx> for &'tcx hir::Block { type Output = Block<'tcx>; - fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Block<'tcx> { + fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Block<'tcx> { // We have to eagerly lower the "spine" of the statements // in order to get the lexical scoping correctly. let stmts = mirror_stmts(cx, self.hir_id.local_id, &*self.stmts); @@ -40,15 +40,15 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block { } } -fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, - block_id: hir::ItemLocalId, - stmts: &'tcx [hir::Stmt]) - -> Vec> { +fn mirror_stmts<'a, 'tcx>( + cx: &mut Cx<'a, 'tcx>, + block_id: hir::ItemLocalId, + stmts: &'tcx [hir::Stmt], +) -> Vec> { let mut result = vec![]; for (index, stmt) in stmts.iter().enumerate() { let hir_id = stmt.hir_id; let opt_dxn_ext = cx.region_scope_tree.opt_destruction_scope(hir_id.local_id); - let stmt_span = StatementSpan(cx.tcx.hir().span_by_hir_id(hir_id)); match stmt.node { hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => { @@ -61,7 +61,6 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: expr.to_ref(), }, opt_destruction_scope: opt_dxn_ext, - span: stmt_span, }))) } hir::StmtKind::Item(..) => { @@ -103,10 +102,9 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }, pattern, initializer: local.init.to_ref(), - lint_level: cx.lint_level_of(local.hir_id), + lint_level: LintLevel::Explicit(local.hir_id), }, opt_destruction_scope: opt_dxn_ext, - span: stmt_span, }))); } } @@ -114,9 +112,10 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, return result; } -pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, - block: &'tcx hir::Block) - -> ExprRef<'tcx> { +pub fn to_expr_ref<'a, 'tcx>( + cx: &mut Cx<'a, 'tcx>, + block: &'tcx hir::Block, +) -> ExprRef<'tcx> { let block_ty = cx.tables().node_type(block.hir_id); let temp_lifetime = cx.region_scope_tree.temporary_scope(block.hir_id.local_id); let expr = Expr { diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 0751af9b12aff..94b4f6e8dd1c5 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -4,11 +4,10 @@ use crate::hair::cx::block; use crate::hair::cx::to_ref::ToRef; use crate::hair::util::UserAnnotatedTyHelpers; use rustc_data_structures::indexed_vec::Idx; -use rustc::hir::def::{Def, CtorKind}; -use rustc::mir::interpret::{GlobalId, ErrorHandled}; +use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind}; +use rustc::mir::interpret::{GlobalId, ErrorHandled, ConstValue}; use rustc::ty::{self, AdtKind, Ty}; -use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; -use rustc::ty::cast::CastKind as TyCastKind; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability, PointerCast}; use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::hir; use rustc::hir::def_id::LocalDefId; @@ -18,7 +17,7 @@ use syntax_pos::Span; impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { type Output = Expr<'tcx>; - fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> { + fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Expr<'tcx> { let temp_lifetime = cx.region_scope_tree.temporary_scope(self.hir_id.local_id); let expr_scope = region::Scope { id: self.hir_id.local_id, @@ -45,7 +44,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::Scope { region_scope: expr_scope, value: expr.to_ref(), - lint_level: cx.lint_level_of(self.hir_id), + lint_level: LintLevel::Explicit(self.hir_id), }, }; @@ -69,51 +68,51 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { } } -fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, - hir_expr: &'tcx hir::Expr, - mut expr: Expr<'tcx>, - adjustment: &Adjustment<'tcx>) - -> Expr<'tcx> { +fn apply_adjustment<'a, 'tcx>( + cx: &mut Cx<'a, 'tcx>, + hir_expr: &'tcx hir::Expr, + mut expr: Expr<'tcx>, + adjustment: &Adjustment<'tcx> +) -> Expr<'tcx> { let Expr { temp_lifetime, mut span, .. } = expr; - let kind = match adjustment.kind { - Adjust::ReifyFnPointer => { - ExprKind::ReifyFnPointer { source: expr.to_ref() } + + // Adjust the span from the block, to the last expression of the + // block. This is a better span when returning a mutable reference + // with too short a lifetime. The error message will use the span + // from the assignment to the return place, which should only point + // at the returned value, not the entire function body. + // + // fn return_short_lived<'a>(x: &'a mut i32) -> &'static mut i32 { + // x + // // ^ error message points at this expression. + // } + let mut adjust_span = |expr: &mut Expr<'tcx>| { + if let ExprKind::Block { body } = expr.kind { + if let Some(ref last_expr) = body.expr { + span = last_expr.span; + expr.span = span; + } } - Adjust::UnsafeFnPointer => { - ExprKind::UnsafeFnPointer { source: expr.to_ref() } + }; + + let kind = match adjustment.kind { + Adjust::Pointer(PointerCast::Unsize) => { + adjust_span(&mut expr); + ExprKind::Pointer { cast: PointerCast::Unsize, source: expr.to_ref() } } - Adjust::ClosureFnPointer => { - ExprKind::ClosureFnPointer { source: expr.to_ref() } + Adjust::Pointer(cast) => { + ExprKind::Pointer { cast, source: expr.to_ref() } } Adjust::NeverToAny => { ExprKind::NeverToAny { source: expr.to_ref() } } - Adjust::MutToConstPointer => { - ExprKind::Cast { source: expr.to_ref() } - } Adjust::Deref(None) => { - // Adjust the span from the block, to the last expression of the - // block. This is a better span when returning a mutable reference - // with too short a lifetime. The error message will use the span - // from the assignment to the return place, which should only point - // at the returned value, not the entire function body. - // - // fn return_short_lived<'a>(x: &'a mut i32) -> &'static mut i32 { - // x - // // ^ error message points at this expression. - // } - // - // We don't need to do this adjustment in the next match arm since - // deref coercions always start with a built-in deref. - if let ExprKind::Block { body } = expr.kind { - if let Some(ref last_expr) = body.expr { - span = last_expr.span; - expr.span = span; - } - } + adjust_span(&mut expr); ExprKind::Deref { arg: expr.to_ref() } } Adjust::Deref(Some(deref)) => { + // We don't need to do call adjust_span here since + // deref coercions always start with a built-in deref. let call = deref.method_call(cx.tcx(), expr.ty); expr = Expr { @@ -143,7 +142,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // then an unsafe coercion. expr = Expr { temp_lifetime, - ty: cx.tcx.mk_ref(cx.tcx.types.re_erased, + ty: cx.tcx.mk_ref(cx.tcx.lifetimes.re_erased, ty::TypeAndMut { ty: expr.ty, mutbl: m, @@ -188,16 +187,6 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // since they get rid of a borrow implicitly. ExprKind::Use { source: cast_expr.to_ref() } } - Adjust::Unsize => { - // See the above comment for Adjust::Deref - if let ExprKind::Block { body } = expr.kind { - if let Some(ref last_expr) = body.expr { - span = last_expr.span; - expr.span = span; - } - } - ExprKind::Unsize { source: expr.to_ref() } - } }; Expr { @@ -208,9 +197,10 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } -fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, - expr: &'tcx hir::Expr) - -> Expr<'tcx> { +fn make_mirror_unadjusted<'a, 'tcx>( + cx: &mut Cx<'a, 'tcx>, + expr: &'tcx hir::Expr, +) -> Expr<'tcx> { let expr_ty = cx.tables().expr_ty(expr); let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); @@ -261,12 +251,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, { // Tuple-like ADTs are represented as ExprKind::Call. We convert them here. expr_ty.ty_adt_def().and_then(|adt_def| { - match path.def { - Def::VariantCtor(variant_id, CtorKind::Fn) => { - Some((adt_def, adt_def.variant_index_with_id(variant_id))) - } - Def::StructCtor(_, CtorKind::Fn) | - Def::SelfCtor(..) => Some((adt_def, VariantIdx::new(0))), + match path.res { + Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => + Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id))), + Res::SelfCtor(..) => Some((adt_def, VariantIdx::new(0))), _ => None, } }) @@ -343,9 +331,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprKind::Lit(ref lit) => ExprKind::Literal { - literal: cx.tcx.mk_lazy_const(ty::LazyConst::Evaluated( - cx.const_eval_literal(&lit.node, expr_ty, lit.span, false) - )), + literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false), user_ty: None, }, @@ -443,9 +429,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } else { if let hir::ExprKind::Lit(ref lit) = arg.node { ExprKind::Literal { - literal: cx.tcx.mk_lazy_const(ty::LazyConst::Evaluated( - cx.const_eval_literal(&lit.node, expr_ty, lit.span, true) - )), + literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), user_ty: None, } } else { @@ -482,9 +466,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } AdtKind::Enum => { - let def = cx.tables().qpath_def(qpath, expr.hir_id); - match def { - Def::Variant(variant_id) => { + let res = cx.tables().qpath_res(qpath, expr.hir_id); + match res { + Res::Def(DefKind::Variant, variant_id) => { assert!(base.is_none()); let index = adt.variant_index_with_id(variant_id); @@ -505,7 +489,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } _ => { - span_bug!(expr.span, "unexpected def: {:?}", def); + span_bug!(expr.span, "unexpected res: {:?}", res); } } } @@ -530,13 +514,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty); } }; - let expr_node_id = cx.tcx.hir().hir_to_node_id(expr.hir_id); - let upvars = cx.tcx.with_freevars(expr_node_id, |freevars| { - freevars.iter() - .zip(substs.upvar_tys(def_id, cx.tcx)) - .map(|(fv, ty)| capture_freevar(cx, expr, fv, ty)) - .collect() - }); + let upvars = cx.tcx.upvars(def_id).iter() + .flat_map(|upvars| upvars.iter()) + .zip(substs.upvar_tys(def_id, cx.tcx)) + .map(|((&var_hir_id, _), ty)| capture_upvar(cx, expr, var_hir_id, ty)) + .collect(); ExprKind::Closure { closure_id: def_id, substs, @@ -546,8 +528,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprKind::Path(ref qpath) => { - let def = cx.tables().qpath_def(qpath, expr.hir_id); - convert_path_expr(cx, expr, def) + let res = cx.tables().qpath_res(qpath, expr.hir_id); + convert_path_expr(cx, expr, res) } hir::ExprKind::InlineAsm(ref asm, ref outputs, ref inputs) => { @@ -592,7 +574,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, match dest.target_id { Ok(target_id) => ExprKind::Break { label: region::Scope { - id: cx.tcx.hir().node_to_hir_id(target_id).local_id, + id: target_id.local_id, data: region::ScopeData::Node }, value: value.to_ref(), @@ -604,7 +586,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, match dest.target_id { Ok(loop_id) => ExprKind::Continue { label: region::Scope { - id: cx.tcx.hir().node_to_hir_id(loop_id).local_id, + id: loop_id.local_id, data: region::ScopeData::Node }, }, @@ -617,13 +599,6 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arms: arms.iter().map(|a| convert_arm(cx, a)).collect(), } } - hir::ExprKind::If(ref cond, ref then, ref otherwise) => { - ExprKind::If { - condition: cond.to_ref(), - then: then.to_ref(), - otherwise: otherwise.to_ref(), - } - } hir::ExprKind::While(ref cond, ref body, _) => { ExprKind::Loop { condition: Some(cond.to_ref()), @@ -656,11 +631,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // Check to see if this cast is a "coercion cast", where the cast is actually done // using a coercion (or is a no-op). - let cast = if let Some(&TyCastKind::CoercionCast) = - cx.tables() - .cast_kinds() - .get(source.hir_id) - { + let cast = if cx.tables().is_coercion_cast(source.hir_id) { // Convert the lexpr to a vexpr. ExprKind::Use { source: source.to_ref() } } else { @@ -676,15 +647,18 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // The correct solution would be to add symbolic computations to miri, // so we wouldn't have to compute and store the actual value let var = if let hir::ExprKind::Path(ref qpath) = source.node { - let def = cx.tables().qpath_def(qpath, source.hir_id); + let res = cx.tables().qpath_res(qpath, source.hir_id); cx .tables() .node_type(source.hir_id) .ty_adt_def() .and_then(|adt_def| { - match def { - Def::VariantCtor(variant_id, CtorKind::Const) => { - let idx = adt_def.variant_index_with_id(variant_id); + match res { + Res::Def( + DefKind::Ctor(CtorOf::Variant, CtorKind::Const), + variant_ctor_id, + ) => { + let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); let (d, o) = adt_def.discriminant_def_for_variant(idx); use rustc::ty::util::IntTypeExt; let ty = adt_def.repr.discr_type(); @@ -704,21 +678,24 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty: var_ty, span: expr.span, kind: ExprKind::Literal { - literal: cx.tcx.mk_lazy_const(literal), + literal, user_ty: None }, }.to_ref(); - let offset = mk_const(ty::LazyConst::Evaluated(ty::Const::from_bits( + let offset = mk_const(ty::Const::from_bits( cx.tcx, offset as u128, cx.param_env.and(var_ty), - ))); + )); match did { Some(did) => { // in case we are offsetting from a computed discriminant // and not the beginning of discriminants (which is always `0`) let substs = InternalSubsts::identity_for_item(cx.tcx(), did); - let lhs = mk_const(ty::LazyConst::Unevaluated(did, substs)); + let lhs = mk_const(cx.tcx().mk_const(ty::Const { + val: ConstValue::Unevaluated(did, substs), + ty: var_ty, + })); let bin = ExprKind::Binary { op: BinOp::Add, lhs, @@ -775,6 +752,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } } + hir::ExprKind::DropTemps(ref source) => { + ExprKind::Use { source: source.to_ref() } + } hir::ExprKind::Box(ref value) => { ExprKind::Box { value: value.to_ref(), @@ -783,7 +763,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprKind::Array(ref fields) => ExprKind::Array { fields: fields.to_ref() }, hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() }, - hir::ExprKind::Yield(ref v) => ExprKind::Yield { value: v.to_ref() }, + hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: v.to_ref() }, hir::ExprKind::Err => unreachable!(), }; @@ -795,44 +775,43 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } -fn user_substs_applied_to_def( - cx: &mut Cx<'a, 'gcx, 'tcx>, +fn user_substs_applied_to_res( + cx: &mut Cx<'a, 'tcx>, hir_id: hir::HirId, - def: &Def, + res: Res, ) -> Option> { - debug!("user_substs_applied_to_def: def={:?}", def); - let user_provided_type = match def { + debug!("user_substs_applied_to_res: res={:?}", res); + let user_provided_type = match res { // A reference to something callable -- e.g., a fn, method, or // a tuple-struct or tuple-variant. This has the type of a // `Fn` but with the user-given substitutions. - Def::Fn(_) | - Def::Method(_) | - Def::StructCtor(_, CtorKind::Fn) | - Def::VariantCtor(_, CtorKind::Fn) | - Def::Const(_) | - Def::AssociatedConst(_) => cx.tables().user_provided_types().get(hir_id).map(|u_ty| *u_ty), + Res::Def(DefKind::Fn, _) | + Res::Def(DefKind::Method, _) | + Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | + Res::Def(DefKind::Const, _) | + Res::Def(DefKind::AssocConst, _) => + cx.tables().user_provided_types().get(hir_id).map(|u_ty| *u_ty), // A unit struct/variant which is used as a value (e.g., // `None`). This has the type of the enum/struct that defines // this variant -- but with the substitutions given by the // user. - Def::StructCtor(_def_id, CtorKind::Const) | - Def::VariantCtor(_def_id, CtorKind::Const) => + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => cx.user_substs_applied_to_ty_of_hir_id(hir_id), // `Self` is used in expression as a tuple struct constructor or an unit struct constructor - Def::SelfCtor(_) => + Res::SelfCtor(_) => cx.user_substs_applied_to_ty_of_hir_id(hir_id), _ => - bug!("user_substs_applied_to_def: unexpected def {:?} at {:?}", def, hir_id) + bug!("user_substs_applied_to_res: unexpected res {:?} at {:?}", res, hir_id) }; - debug!("user_substs_applied_to_def: user_provided_type={:?}", user_provided_type); + debug!("user_substs_applied_to_res: user_provided_type={:?}", user_provided_type); user_provided_type } -fn method_callee<'a, 'gcx, 'tcx>( - cx: &mut Cx<'a, 'gcx, 'tcx>, +fn method_callee<'a, 'tcx>( + cx: &mut Cx<'a, 'tcx>, expr: &hir::Expr, span: Span, overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, @@ -841,15 +820,13 @@ fn method_callee<'a, 'gcx, 'tcx>( let (def_id, substs, user_ty) = match overloaded_callee { Some((def_id, substs)) => (def_id, substs, None), None => { - let type_dependent_defs = cx.tables().type_dependent_defs(); - let def = type_dependent_defs - .get(expr.hir_id) + let (kind, def_id) = cx.tables().type_dependent_def(expr.hir_id) .unwrap_or_else(|| { span_bug!(expr.span, "no type-dependent def for method callee") }); - let user_ty = user_substs_applied_to_def(cx, expr.hir_id, def); + let user_ty = user_substs_applied_to_res(cx, expr.hir_id, Res::Def(kind, def_id)); debug!("method_callee: user_ty={:?}", user_ty); - (def.def_id(), cx.tables().node_substs(expr.hir_id), user_ty) + (def_id, cx.tables().node_substs(expr.hir_id), user_ty) } }; let ty = cx.tcx().mk_fn_def(def_id, substs); @@ -858,9 +835,7 @@ fn method_callee<'a, 'gcx, 'tcx>( ty, span, kind: ExprKind::Literal { - literal: cx.tcx().mk_lazy_const(ty::LazyConst::Evaluated( - ty::Const::zero_sized(ty) - )), + literal: ty::Const::zero_sized(cx.tcx(), ty), user_ty, }, } @@ -892,7 +867,7 @@ impl ToBorrowKind for hir::Mutability { } } -fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> { +fn convert_arm<'a, 'tcx>(cx: &mut Cx<'a, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> { Arm { patterns: arm.pats.iter().map(|p| cx.pattern_from_hir(p)).collect(), guard: match arm.guard { @@ -900,98 +875,133 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) _ => None, }, body: arm.body.to_ref(), - // BUG: fix this - lint_level: LintLevel::Inherited, + lint_level: LintLevel::Explicit(arm.hir_id), + scope: region::Scope { + id: arm.hir_id.local_id, + data: region::ScopeData::Node + }, + span: arm.span, } } -fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, - expr: &'tcx hir::Expr, - def: Def) - -> ExprKind<'tcx> { +fn convert_path_expr<'a, 'tcx>( + cx: &mut Cx<'a, 'tcx>, + expr: &'tcx hir::Expr, + res: Res, +) -> ExprKind<'tcx> { let substs = cx.tables().node_substs(expr.hir_id); - match def { + match res { // A regular function, constructor function or a constant. - Def::Fn(_) | - Def::Method(_) | - Def::StructCtor(_, CtorKind::Fn) | - Def::VariantCtor(_, CtorKind::Fn) | - Def::SelfCtor(..) => { - let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def); + Res::Def(DefKind::Fn, _) | + Res::Def(DefKind::Method, _) | + Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | + Res::SelfCtor(..) => { + let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res); debug!("convert_path_expr: user_ty={:?}", user_ty); ExprKind::Literal { - literal: cx.tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::zero_sized( + literal: ty::Const::zero_sized( + cx.tcx, cx.tables().node_type(expr.hir_id), - ))), + ), user_ty, } - }, + } - Def::Const(def_id) | - Def::AssociatedConst(def_id) => { - let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def); + Res::Def(DefKind::ConstParam, def_id) => { + let hir_id = cx.tcx.hir().as_local_hir_id(def_id).unwrap(); + let item_id = cx.tcx.hir().get_parent_node(hir_id); + let item_def_id = cx.tcx.hir().local_def_id_from_hir_id(item_id); + let generics = cx.tcx.generics_of(item_def_id); + let local_def_id = cx.tcx.hir().local_def_id_from_hir_id(hir_id); + let index = generics.param_def_id_to_index[&local_def_id]; + let name = cx.tcx.hir().name(hir_id).as_interned_str(); + let val = ConstValue::Param(ty::ParamConst::new(index, name)); + ExprKind::Literal { + literal: cx.tcx.mk_const( + ty::Const { + val, + ty: cx.tables().node_type(expr.hir_id), + } + ), + user_ty: None, + } + } + + Res::Def(DefKind::Const, def_id) | + Res::Def(DefKind::AssocConst, def_id) => { + let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res); debug!("convert_path_expr: (const) user_ty={:?}", user_ty); ExprKind::Literal { - literal: cx.tcx.mk_lazy_const(ty::LazyConst::Unevaluated(def_id, substs)), + literal: cx.tcx.mk_const(ty::Const { + val: ConstValue::Unevaluated(def_id, substs), + ty: cx.tcx.type_of(def_id), + }), user_ty, } }, - Def::StructCtor(def_id, CtorKind::Const) | - Def::VariantCtor(def_id, CtorKind::Const) => { + Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id) => { let user_provided_types = cx.tables.user_provided_types(); let user_provided_type = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty); debug!("convert_path_expr: user_provided_type={:?}", user_provided_type); - match cx.tables().node_type(expr.hir_id).sty { + let ty = cx.tables().node_type(expr.hir_id); + match ty.sty { // A unit struct/variant which is used as a value. // We return a completely different ExprKind here to account for this special case. ty::Adt(adt_def, substs) => { ExprKind::Adt { adt_def, - variant_index: adt_def.variant_index_with_id(def_id), + variant_index: adt_def.variant_index_with_ctor_id(def_id), substs, user_ty: user_provided_type, fields: vec![], base: None, } } - ref sty => bug!("unexpected sty: {:?}", sty), + _ => bug!("unexpected ty: {:?}", ty), } } - Def::Static(node_id, _) => ExprKind::StaticRef { id: node_id }, + Res::Def(DefKind::Static, id) => ExprKind::StaticRef { id }, - Def::Local(..) | Def::Upvar(..) => convert_var(cx, expr, def), + Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id), - _ => span_bug!(expr.span, "def `{:?}` not yet implemented", def), + _ => span_bug!(expr.span, "res `{:?}` not yet implemented", res), } } -fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, - expr: &'tcx hir::Expr, - def: Def) - -> ExprKind<'tcx> { +fn convert_var( + cx: &mut Cx<'_, 'tcx>, + expr: &'tcx hir::Expr, + var_hir_id: hir::HirId, +) -> ExprKind<'tcx> { + let upvar_index = cx.tables().upvar_list.get(&cx.body_owner) + .and_then(|upvars| upvars.get_full(&var_hir_id).map(|(i, _, _)| i)); + + debug!("convert_var({:?}): upvar_index={:?}, body_owner={:?}", + var_hir_id, upvar_index, cx.body_owner); + let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); - match def { - Def::Local(id) => ExprKind::VarRef { id }, + match upvar_index { + None => ExprKind::VarRef { id: var_hir_id }, - Def::Upvar(var_id, index, closure_expr_id) => { - debug!("convert_var(upvar({:?}, {:?}, {:?}))", - var_id, - index, - closure_expr_id); - let var_hir_id = cx.tcx.hir().node_to_hir_id(var_id); + Some(upvar_index) => { + let closure_def_id = cx.body_owner; + let upvar_id = ty::UpvarId { + var_path: ty::UpvarPath {hir_id: var_hir_id}, + closure_expr_id: LocalDefId::from_def_id(closure_def_id), + }; let var_ty = cx.tables().node_type(var_hir_id); // FIXME free regions in closures are not right - let closure_ty = cx.tables() - .node_type(cx.tcx.hir().node_to_hir_id(closure_expr_id)); + let closure_ty = cx.tables().node_type( + cx.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id), + ); // FIXME we're just hard-coding the idea that the // signature will be &self or &mut self and hence will // have a bound region with number 0 - let closure_def_id = cx.tcx.hir().local_def_id(closure_expr_id); let region = ty::ReFree(ty::FreeRegion { scope: closure_def_id, bound_region: ty::BoundRegion::BrAnon(0), @@ -1062,15 +1072,11 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // at this point we have `self.n`, which loads up the upvar let field_kind = ExprKind::Field { lhs: self_expr.to_ref(), - name: Field::new(index), + name: Field::new(upvar_index), }; // ...but the upvar might be an `&T` or `&mut T` capture, at which // point we need an implicit deref - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath {hir_id: var_hir_id}, - closure_expr_id: LocalDefId::from_def_id(closure_def_id), - }; match cx.tables().upvar_capture(upvar_id) { ty::UpvarCapture::ByValue => field_kind, ty::UpvarCapture::ByRef(borrow) => { @@ -1089,8 +1095,6 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } } - - _ => span_bug!(expr.span, "type of & not region"), } } @@ -1117,10 +1121,11 @@ fn bin_op(op: hir::BinOpKind) -> BinOp { } } -fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, - expr: &'tcx hir::Expr, - args: Vec>) - -> ExprKind<'tcx> { +fn overloaded_operator<'a, 'tcx>( + cx: &mut Cx<'a, 'tcx>, + expr: &'tcx hir::Expr, + args: Vec> +) -> ExprKind<'tcx> { let fun = method_callee(cx, expr, expr.span, None); ExprKind::Call { ty: fun.ty, @@ -1130,8 +1135,8 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } -fn overloaded_place<'a, 'gcx, 'tcx>( - cx: &mut Cx<'a, 'gcx, 'tcx>, +fn overloaded_place<'a, 'tcx>( + cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr, place_ty: Ty<'tcx>, overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, @@ -1178,12 +1183,12 @@ fn overloaded_place<'a, 'gcx, 'tcx>( ExprKind::Deref { arg: ref_expr.to_ref() } } -fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, - closure_expr: &'tcx hir::Expr, - freevar: &hir::Freevar, - freevar_ty: Ty<'tcx>) - -> ExprRef<'tcx> { - let var_hir_id = cx.tcx.hir().node_to_hir_id(freevar.var_id()); +fn capture_upvar<'tcx>( + cx: &mut Cx<'_, 'tcx>, + closure_expr: &'tcx hir::Expr, + var_hir_id: hir::HirId, + upvar_ty: Ty<'tcx> +) -> ExprRef<'tcx> { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: cx.tcx.hir().local_def_id_from_hir_id(closure_expr.hir_id).to_local(), @@ -1195,7 +1200,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, temp_lifetime, ty: var_ty, span: closure_expr.span, - kind: convert_var(cx, closure_expr, freevar.def), + kind: convert_var(cx, closure_expr, var_hir_id), }; match upvar_capture { ty::UpvarCapture::ByValue => captured_var.to_ref(), @@ -1207,7 +1212,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; Expr { temp_lifetime, - ty: freevar_ty, + ty: upvar_ty, span: closure_expr.span, kind: ExprKind::Borrow { borrow_kind, @@ -1219,9 +1224,10 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } /// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExprRef. -fn field_refs<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, - fields: &'tcx [hir::Field]) - -> Vec> { +fn field_refs<'a, 'tcx>( + cx: &mut Cx<'a, 'tcx>, + fields: &'tcx [hir::Field] +) -> Vec> { fields.iter() .map(|field| { FieldExprRef { diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 70f04fb892866..a21d900cf5e5e 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -6,7 +6,7 @@ use crate::hair::*; use crate::hair::util::UserAnnotatedTyHelpers; use rustc_data_structures::indexed_vec::Idx; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::def_id::DefId; use rustc::hir::Node; use rustc::middle::region; use rustc::infer::InferCtxt; @@ -16,45 +16,47 @@ use rustc::ty::subst::{Kind, InternalSubsts}; use rustc::ty::layout::VariantIdx; use syntax::ast; use syntax::attr; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use rustc::hir; -use rustc_data_structures::sync::Lrc; use crate::hair::constant::{lit_to_const, LitToConstError}; #[derive(Clone)] -pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, +pub struct Cx<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + infcx: &'a InferCtxt<'a, 'tcx>, pub root_lint_level: hir::HirId, - pub param_env: ty::ParamEnv<'gcx>, + pub param_env: ty::ParamEnv<'tcx>, /// Identity `InternalSubsts` for use with const-evaluation. - pub identity_substs: &'gcx InternalSubsts<'gcx>, + pub identity_substs: &'tcx InternalSubsts<'tcx>, - pub region_scope_tree: Lrc, - pub tables: &'a ty::TypeckTables<'gcx>, + pub region_scope_tree: &'tcx region::ScopeTree, + pub tables: &'a ty::TypeckTables<'tcx>, /// This is `Constness::Const` if we are compiling a `static`, /// `const`, or the body of a `const fn`. constness: hir::Constness, + /// The `DefId` of the owner of this body. + body_owner: DefId, + /// What kind of body is being compiled. pub body_owner_kind: hir::BodyOwnerKind, /// Whether this constant/function needs overflow checks. check_overflow: bool, - /// See field with the same name on `Mir`. + /// See field with the same name on `mir::Body`. control_flow_destroyed: Vec<(Span, String)>, } -impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - src_id: hir::HirId) -> Cx<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Cx<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>, src_id: hir::HirId) -> Cx<'a, 'tcx> { let tcx = infcx.tcx; let src_def_id = tcx.hir().local_def_id_from_hir_id(src_id); - let body_owner_kind = tcx.hir().body_owner_kind_by_hir_id(src_id); + let tables = tcx.typeck_tables_of(src_def_id); + let body_owner_kind = tcx.hir().body_owner_kind(src_id); let constness = match body_owner_kind { hir::BodyOwnerKind::Const | @@ -63,12 +65,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { hir::BodyOwnerKind::Fn => hir::Constness::NotConst, }; - let attrs = tcx.hir().attrs_by_hir_id(src_id); + let attrs = tcx.hir().attrs(src_id); // Some functions always have overflow checks enabled, // however, they may not get codegen'd, depending on // the settings for the crate they are codegened in. - let mut check_overflow = attr::contains_name(attrs, "rustc_inherit_overflow_checks"); + let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks); // Respect -C overflow-checks. check_overflow |= tcx.sess.overflow_checks(); @@ -76,16 +78,16 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { // Constants always need overflow checks. check_overflow |= constness == hir::Constness::Const; - let lint_level = lint_level_for_hir_id(tcx, src_id); Cx { tcx, infcx, - root_lint_level: lint_level, + root_lint_level: src_id, param_env: tcx.param_env(src_def_id), identity_substs: InternalSubsts::identity_for_item(tcx.global_tcx(), src_def_id), region_scope_tree: tcx.region_scope_tree(src_def_id), - tables: tcx.typeck_tables_of(src_def_id), + tables, constness, + body_owner: src_def_id, body_owner_kind, check_overflow, control_flow_destroyed: Vec::new(), @@ -97,7 +99,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Cx<'a, 'tcx> { /// Normalizes `ast` into the appropriate "mirror" type. pub fn mirror>(&mut self, ast: M) -> M::Output { ast.make_mirror(self) @@ -107,8 +109,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { self.tcx.types.usize } - pub fn usize_literal(&mut self, value: u64) -> &'tcx ty::LazyConst<'tcx> { - self.tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_usize(self.tcx, value))) + pub fn usize_literal(&mut self, value: u64) -> &'tcx ty::Const<'tcx> { + ty::Const::from_usize(self.tcx, value) } pub fn bool_ty(&mut self) -> Ty<'tcx> { @@ -119,12 +121,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { self.tcx.mk_unit() } - pub fn true_literal(&mut self) -> &'tcx ty::LazyConst<'tcx> { - self.tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bool(self.tcx, true))) + pub fn true_literal(&mut self) -> &'tcx ty::Const<'tcx> { + ty::Const::from_bool(self.tcx, true) } - pub fn false_literal(&mut self) -> &'tcx ty::LazyConst<'tcx> { - self.tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bool(self.tcx, false))) + pub fn false_literal(&mut self) -> &'tcx ty::Const<'tcx> { + ty::Const::from_bool(self.tcx, false) } pub fn const_eval_literal( @@ -133,7 +135,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { ty: Ty<'tcx>, sp: Span, neg: bool, - ) -> ty::Const<'tcx> { + ) -> &'tcx ty::Const<'tcx> { trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg); match lit_to_const(lit, self.tcx, ty, neg) { @@ -153,7 +155,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn pattern_from_hir(&mut self, p: &hir::Pat) -> Pattern<'tcx> { let tcx = self.tcx.global_tcx(); - let p = match tcx.hir().get(p.id) { + let p = match tcx.hir().get(p.hir_id) { Node::Pat(p) | Node::Binding(p) => p, node => bug!("pattern became {:?}", node) }; @@ -165,17 +167,16 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn trait_method(&mut self, trait_def_id: DefId, - method_name: &str, + method_name: Symbol, self_ty: Ty<'tcx>, params: &[Kind<'tcx>]) - -> (Ty<'tcx>, ty::Const<'tcx>) { - let method_name = Symbol::intern(method_name); + -> (Ty<'tcx>, &'tcx ty::Const<'tcx>) { let substs = self.tcx.mk_substs_trait(self_ty, params); for item in self.tcx.associated_items(trait_def_id) { - if item.kind == ty::AssociatedKind::Method && item.ident.name == method_name { + if item.kind == ty::AssocKind::Method && item.ident.name == method_name { let method_ty = self.tcx.type_of(item.def_id); let method_ty = method_ty.subst(self.tcx, substs); - return (method_ty, ty::Const::zero_sized(method_ty)); + return (method_ty, ty::Const::zero_sized(self.tcx, method_ty)); } } @@ -189,31 +190,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { } pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool { - let (ty, param_env) = self.tcx.lift_to_global(&(ty, self.param_env)).unwrap_or_else(|| { - bug!("MIR: Cx::needs_drop({:?}, {:?}) got \ - type with inference types/regions", - ty, self.param_env); - }); - ty.needs_drop(self.tcx.global_tcx(), param_env) - } - - fn lint_level_of(&self, hir_id: hir::HirId) -> LintLevel { - let has_lint_level = self.tcx.dep_graph.with_ignore(|| { - self.tcx.lint_levels(LOCAL_CRATE).lint_level_set(hir_id).is_some() - }); - - if has_lint_level { - LintLevel::Explicit(hir_id) - } else { - LintLevel::Inherited - } + ty.needs_drop(self.tcx.global_tcx(), self.param_env) } - pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { + pub fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } - pub fn tables(&self) -> &'a ty::TypeckTables<'gcx> { + pub fn tables(&self) -> &'a ty::TypeckTables<'tcx> { self.tables } @@ -226,8 +210,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { } } -impl UserAnnotatedTyHelpers<'gcx, 'tcx> for Cx<'_, 'gcx, 'tcx> { - fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> { +impl UserAnnotatedTyHelpers<'tcx> for Cx<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx() } @@ -236,30 +220,6 @@ impl UserAnnotatedTyHelpers<'gcx, 'tcx> for Cx<'_, 'gcx, 'tcx> { } } -fn lint_level_for_hir_id(tcx: TyCtxt<'_, '_, '_>, mut id: hir::HirId) -> hir::HirId { - // Right now we insert a `with_ignore` node in the dep graph here to - // ignore the fact that `lint_levels` below depends on the entire crate. - // For now this'll prevent false positives of recompiling too much when - // anything changes. - // - // Once red/green incremental compilation lands we should be able to - // remove this because while the crate changes often the lint level map - // will change rarely. - tcx.dep_graph.with_ignore(|| { - let sets = tcx.lint_levels(LOCAL_CRATE); - loop { - if sets.lint_level_set(id).is_some() { - return id - } - let next = tcx.hir().get_parent_node_by_hir_id(id); - if next == id { - bug!("lint traversal reached the root of the crate"); - } - id = next; - } - }) -} - mod block; mod expr; mod to_ref; diff --git a/src/librustc_mir/hair/cx/to_ref.rs b/src/librustc_mir/hair/cx/to_ref.rs index a462c61c2acba..946d66fc91d7d 100644 --- a/src/librustc_mir/hair/cx/to_ref.rs +++ b/src/librustc_mir/hair/cx/to_ref.rs @@ -8,7 +8,7 @@ pub trait ToRef { fn to_ref(self) -> Self::Output; } -impl<'a, 'tcx: 'a> ToRef for &'tcx hir::Expr { +impl<'tcx> ToRef for &'tcx hir::Expr { type Output = ExprRef<'tcx>; fn to_ref(self) -> ExprRef<'tcx> { @@ -16,7 +16,7 @@ impl<'a, 'tcx: 'a> ToRef for &'tcx hir::Expr { } } -impl<'a, 'tcx: 'a> ToRef for &'tcx P { +impl<'tcx> ToRef for &'tcx P { type Output = ExprRef<'tcx>; fn to_ref(self) -> ExprRef<'tcx> { @@ -24,7 +24,7 @@ impl<'a, 'tcx: 'a> ToRef for &'tcx P { } } -impl<'a, 'tcx: 'a> ToRef for Expr<'tcx> { +impl<'tcx> ToRef for Expr<'tcx> { type Output = ExprRef<'tcx>; fn to_ref(self) -> ExprRef<'tcx> { @@ -32,8 +32,9 @@ impl<'a, 'tcx: 'a> ToRef for Expr<'tcx> { } } -impl<'a, 'tcx: 'a, T, U> ToRef for &'tcx Option - where &'tcx T: ToRef +impl<'tcx, T, U> ToRef for &'tcx Option +where + &'tcx T: ToRef, { type Output = Option; @@ -42,8 +43,9 @@ impl<'a, 'tcx: 'a, T, U> ToRef for &'tcx Option } } -impl<'a, 'tcx: 'a, T, U> ToRef for &'tcx Vec - where &'tcx T: ToRef +impl<'tcx, T, U> ToRef for &'tcx Vec +where + &'tcx T: ToRef, { type Output = Vec; @@ -52,8 +54,9 @@ impl<'a, 'tcx: 'a, T, U> ToRef for &'tcx Vec } } -impl<'a, 'tcx: 'a, T, U> ToRef for &'tcx P<[T]> - where &'tcx T: ToRef +impl<'tcx, T, U> ToRef for &'tcx P<[T]> +where + &'tcx T: ToRef, { type Output = Vec; diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 2efdacd7622c9..5431a31c4bb2a 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -9,10 +9,10 @@ use rustc::hir::def_id::DefId; use rustc::infer::canonical::Canonical; use rustc::middle::region; use rustc::ty::subst::SubstsRef; -use rustc::ty::{AdtDef, UpvarSubsts, Ty, Const, LazyConst, UserType}; +use rustc::ty::{AdtDef, UpvarSubsts, Ty, Const, UserType}; +use rustc::ty::adjustment::{PointerCast}; use rustc::ty::layout::VariantIdx; use rustc::hir; -use syntax::ast; use syntax_pos::Span; use self::cx::Cx; @@ -31,15 +31,6 @@ pub enum LintLevel { Explicit(hir::HirId) } -impl LintLevel { - pub fn is_explicit(self) -> bool { - match self { - LintLevel::Inherited => false, - LintLevel::Explicit(_) => true - } - } -} - #[derive(Clone, Debug)] pub struct Block<'tcx> { pub targeted_by_break: bool, @@ -64,14 +55,10 @@ pub enum StmtRef<'tcx> { Mirror(Box>), } -#[derive(Clone, Debug)] -pub struct StatementSpan(pub Span); - #[derive(Clone, Debug)] pub struct Stmt<'tcx> { pub kind: StmtKind<'tcx>, pub opt_destruction_scope: Option, - pub span: StatementSpan, } #[derive(Clone, Debug)] @@ -181,23 +168,10 @@ pub enum ExprKind<'tcx> { NeverToAny { source: ExprRef<'tcx>, }, - ReifyFnPointer { + Pointer { + cast: PointerCast, source: ExprRef<'tcx>, }, - ClosureFnPointer { - source: ExprRef<'tcx>, - }, - UnsafeFnPointer { - source: ExprRef<'tcx>, - }, - Unsize { - source: ExprRef<'tcx>, - }, - If { - condition: ExprRef<'tcx>, - then: ExprRef<'tcx>, - otherwise: Option>, - }, Loop { condition: Option>, body: ExprRef<'tcx>, @@ -227,7 +201,7 @@ pub enum ExprKind<'tcx> { index: ExprRef<'tcx>, }, VarRef { - id: ast::NodeId, + id: hir::HirId, }, /// first argument, used for self in a closure SelfRef, @@ -287,7 +261,7 @@ pub enum ExprKind<'tcx> { movability: Option, }, Literal { - literal: &'tcx LazyConst<'tcx>, + literal: &'tcx Const<'tcx>, user_ty: Option>>, }, InlineAsm { @@ -324,6 +298,8 @@ pub struct Arm<'tcx> { pub guard: Option>, pub body: ExprRef<'tcx>, pub lint_level: LintLevel, + pub scope: region::Scope, + pub span: Span, } #[derive(Clone, Debug)] @@ -364,13 +340,13 @@ impl<'tcx> ExprRef<'tcx> { pub trait Mirror<'tcx> { type Output; - fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Self::Output; + fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Self::Output; } impl<'tcx> Mirror<'tcx> for Expr<'tcx> { type Output = Expr<'tcx>; - fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> { + fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Expr<'tcx> { self } } @@ -378,7 +354,7 @@ impl<'tcx> Mirror<'tcx> for Expr<'tcx> { impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> { type Output = Expr<'tcx>; - fn make_mirror<'a, 'gcx>(self, hir: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> { + fn make_mirror(self, hir: &mut Cx<'a, 'tcx>) -> Expr<'tcx> { match self { ExprRef::Hair(h) => h.make_mirror(hir), ExprRef::Mirror(m) => *m, @@ -389,7 +365,7 @@ impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> { impl<'tcx> Mirror<'tcx> for Stmt<'tcx> { type Output = Stmt<'tcx>; - fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Stmt<'tcx> { + fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> { self } } @@ -397,7 +373,7 @@ impl<'tcx> Mirror<'tcx> for Stmt<'tcx> { impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> { type Output = Stmt<'tcx>; - fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Stmt<'tcx> { + fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> { match self { StmtRef::Mirror(m) => *m, } @@ -407,7 +383,7 @@ impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> { impl<'tcx> Mirror<'tcx> for Block<'tcx> { type Output = Block<'tcx>; - fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Block<'tcx> { + fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Block<'tcx> { self } } diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 9e9a5d0f82ada..fc2951895f3fe 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -168,11 +168,11 @@ use super::{PatternFoldable, PatternFolder, compare_const_vals}; use rustc::hir::def_id::DefId; use rustc::hir::RangeEnd; -use rustc::ty::{self, subst::SubstsRef, Ty, TyCtxt, TypeFoldable, Const}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const}; use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size}; use rustc::mir::Field; -use rustc::mir::interpret::{ConstValue, Scalar}; +use rustc::mir::interpret::{ConstValue, Scalar, truncate, AllocId, Pointer}; use rustc::util::common::ErrorReported; use syntax::attr::{SignedInt, UnsignedInt}; @@ -186,6 +186,7 @@ use std::fmt; use std::iter::{FromIterator, IntoIterator}; use std::ops::RangeInclusive; use std::u128; +use std::convert::TryInto; pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>) -> &'a Pattern<'tcx> @@ -193,11 +194,11 @@ pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx cx.pattern_arena.alloc(LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat)) } -struct LiteralExpander<'a, 'tcx> { - tcx: TyCtxt<'a, 'tcx, 'tcx> +struct LiteralExpander<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx> LiteralExpander<'a, 'tcx> { +impl LiteralExpander<'tcx> { /// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice. /// /// `crty` and `rty` can differ because you can use array constants in the presence of slice @@ -211,33 +212,41 @@ impl<'a, 'tcx> LiteralExpander<'a, 'tcx> { // the constant's pointee type crty: Ty<'tcx>, ) -> ConstValue<'tcx> { + debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty); match (val, &crty.sty, &rty.sty) { // the easy case, deref a reference - (ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => ConstValue::ByRef( - p, - self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id), - ), + (ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => { + let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id); + ConstValue::ByRef { + offset: p.offset, + // FIXME(oli-obk): this should be the type's layout + align: alloc.align, + alloc, + } + }, // unsize array to slice if pattern is array but match value or other patterns are slice (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => { assert_eq!(t, u); - ConstValue::Slice( - Scalar::Ptr(p), - n.map_evaluated(|val| val.val.try_to_scalar()) - .unwrap() - .to_usize(&self.tcx) - .unwrap(), - ) + ConstValue::Slice { + data: self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id), + start: p.offset.bytes().try_into().unwrap(), + end: n.unwrap_usize(self.tcx).try_into().unwrap(), + } }, // fat pointers stay the same - (ConstValue::Slice(..), _, _) => val, + | (ConstValue::Slice { .. }, _, _) + | (_, ty::Slice(_), ty::Slice(_)) + | (_, ty::Str, ty::Str) + => val, // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty), } } } -impl<'a, 'tcx> PatternFolder<'tcx> for LiteralExpander<'a, 'tcx> { +impl PatternFolder<'tcx> for LiteralExpander<'tcx> { fn fold_pattern(&mut self, pat: &Pattern<'tcx>) -> Pattern<'tcx> { + debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.sty, pat.kind); match (&pat.ty.sty, &*pat.kind) { ( &ty::Ref(_, rty, _), @@ -253,10 +262,10 @@ impl<'a, 'tcx> PatternFolder<'tcx> for LiteralExpander<'a, 'tcx> { subpattern: Pattern { ty: rty, span: pat.span, - kind: box PatternKind::Constant { value: Const { - val: self.fold_const_value_deref(val, rty, crty), + kind: box PatternKind::Constant { value: self.tcx.mk_const(Const { + val: self.fold_const_value_deref(*val, rty, crty), ty: rty, - } }, + }) }, } } } @@ -281,7 +290,7 @@ impl<'tcx> Pattern<'tcx> { /// A 2D matrix. Nx1 matrices are very common, which is why `SmallVec[_; 2]` /// works well for each row. -pub struct Matrix<'p, 'tcx: 'p>(Vec; 2]>>); +pub struct Matrix<'p, 'tcx>(Vec; 2]>>); impl<'p, 'tcx> Matrix<'p, 'tcx> { pub fn empty() -> Self { @@ -345,8 +354,8 @@ impl<'p, 'tcx> FromIterator; 2]>> for Matrix<'p, 'tc } } -pub struct MatchCheckCtxt<'a, 'tcx: 'a> { - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub struct MatchCheckCtxt<'a, 'tcx> { + pub tcx: TyCtxt<'tcx>, /// The module in which the match occurs. This is necessary for /// checking inhabited-ness of types because whether a type is (visibly) /// inhabited can depend on whether it was defined in the current module or @@ -361,11 +370,13 @@ pub struct MatchCheckCtxt<'a, 'tcx: 'a> { impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { pub fn create_and_enter( - tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, module: DefId, - f: F) -> R - where F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R + f: F, + ) -> R + where + F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R, { let pattern_arena = TypedArena::default(); @@ -386,6 +397,16 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } + fn is_non_exhaustive_variant<'p>(&self, pattern: &'p Pattern<'tcx>) -> bool { + match *pattern.kind { + PatternKind::Variant { adt_def, variant_index, .. } => { + let ref variant = adt_def.variants[variant_index]; + variant.is_field_list_non_exhaustive() + } + _ => false, + } + } + fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { match ty.sty { ty::Adt(adt_def, ..) => adt_def.is_variant_list_non_exhaustive(), @@ -399,30 +420,18 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { _ => false, } } - - fn is_variant_uninhabited(&self, - variant: &'tcx ty::VariantDef, - substs: SubstsRef<'tcx>) - -> bool - { - if self.tcx.features().exhaustive_patterns { - self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs) - } else { - false - } - } } #[derive(Clone, Debug, PartialEq)] -pub enum Constructor<'tcx> { +enum Constructor<'tcx> { /// The constructor of all patterns that don't vary by constructor, /// e.g., struct patterns and fixed-length arrays. Single, /// Enum variants. Variant(DefId), /// Literal values. - ConstantValue(ty::Const<'tcx>), - /// Ranges of literal values (`2...5` and `2..5`). + ConstantValue(&'tcx ty::Const<'tcx>), + /// Ranges of literal values (`2..=5` and `2..5`). ConstantRange(u128, u128, Ty<'tcx>, RangeEnd), /// Array patterns of length n. Slice(u64), @@ -435,18 +444,12 @@ impl<'tcx> Constructor<'tcx> { adt: &'tcx ty::AdtDef, ) -> VariantIdx { match self { - &Variant(vid) => adt.variant_index_with_id(vid), + &Variant(id) => adt.variant_index_with_id(id), &Single => { assert!(!adt.is_enum()); VariantIdx::new(0) } - &ConstantValue(c) => { - crate::const_eval::const_variant_index( - cx.tcx, - cx.param_env, - c, - ).unwrap() - }, + &ConstantValue(c) => crate::const_eval::const_variant_index(cx.tcx, cx.param_env, c), _ => bug!("bad constructor {:?} for adt {:?}", self, adt) } } @@ -539,7 +542,6 @@ impl<'tcx> Witness<'tcx> { self.apply_constructor(cx, ctor, ty) } - /// Constructs a partial witness for a pattern given a list of /// patterns expanded by the specialization step. /// @@ -635,10 +637,10 @@ impl<'tcx> Witness<'tcx> { /// /// We make sure to omit constructors that are statically impossible. E.g., for /// `Option`, we do not include `Some(_)` in the returned list of constructors. -fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, - pcx: PatternContext<'tcx>) - -> Vec> -{ +fn all_constructors<'a, 'tcx>( + cx: &mut MatchCheckCtxt<'a, 'tcx>, + pcx: PatternContext<'tcx>, +) -> Vec> { debug!("all_constructors({:?})", pcx.ty); let ctors = match pcx.ty.sty { ty::Bool => { @@ -665,8 +667,11 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, } ty::Adt(def, substs) if def.is_enum() => { def.variants.iter() - .filter(|v| !cx.is_variant_uninhabited(v, substs)) - .map(|v| Variant(v.did)) + .filter(|v| { + !cx.tcx.features().exhaustive_patterns || + !v.uninhabited_from(cx.tcx, substs, def.adt_kind()).contains(cx.tcx, cx.module) + }) + .map(|v| Variant(v.def_id)) .collect() } ty::Char => { @@ -685,16 +690,14 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, ] } ty::Int(ity) => { - // FIXME(49937): refactor these bit manipulations into interpret. let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128; let min = 1u128 << (bits - 1); - let max = (1u128 << (bits - 1)) - 1; + let max = min - 1; vec![ConstantRange(min, max, pcx.ty, RangeEnd::Included)] } ty::Uint(uty) => { - // FIXME(49937): refactor these bit manipulations into interpret. - let bits = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size().bits() as u128; - let max = !0u128 >> (128 - bits); + let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size(); + let max = truncate(u128::max_value(), size); vec![ConstantRange(0, max, pcx.ty, RangeEnd::Included)] } _ => { @@ -708,10 +711,10 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, ctors } -fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( - cx: &mut MatchCheckCtxt<'a, 'tcx>, - patterns: I) -> u64 - where I: Iterator> +fn max_slice_length<'p, 'a, 'tcx, I>(cx: &mut MatchCheckCtxt<'a, 'tcx>, patterns: I) -> u64 +where + I: Iterator>, + 'tcx: 'p, { // The exhaustiveness-checking paper does not include any details on // checking variable-length slice patterns. However, they are matched @@ -790,9 +793,9 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( max_fixed_len, n.unwrap_usize(cx.tcx), ), - (ConstValue::Slice(_, n), ty::Slice(_)) => max_fixed_len = cmp::max( + (ConstValue::Slice{ start, end, .. }, ty::Slice(_)) => max_fixed_len = cmp::max( max_fixed_len, - n, + (end - start) as u64, ), _ => {}, } @@ -816,7 +819,7 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( /// `IntRange`s always store a contiguous range. This means that values are /// encoded such that `0` encodes the minimum value for the integer, /// regardless of the signedness. -/// For example, the pattern `-128...127i8` is encoded as `0..=255`. +/// For example, the pattern `-128..=127i8` is encoded as `0..=255`. /// This makes comparisons and arithmetic on interval endpoints much more /// straightforward. See `signed_bias` for details. /// @@ -829,9 +832,7 @@ struct IntRange<'tcx> { } impl<'tcx> IntRange<'tcx> { - fn from_ctor(tcx: TyCtxt<'_, 'tcx, 'tcx>, - ctor: &Constructor<'tcx>) - -> Option> { + fn from_ctor(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>) -> Option> { // Floating-point ranges are permitted and we don't want // to consider them when constructing integer ranges. fn is_integral<'tcx>(ty: Ty<'tcx>) -> bool { @@ -869,9 +870,7 @@ impl<'tcx> IntRange<'tcx> { } } - fn from_pat(tcx: TyCtxt<'_, 'tcx, 'tcx>, - mut pat: &Pattern<'tcx>) - -> Option> { + fn from_pat(tcx: TyCtxt<'tcx>, mut pat: &Pattern<'tcx>) -> Option> { let range = loop { match pat.kind { box PatternKind::Constant { value } => break ConstantValue(value), @@ -891,7 +890,7 @@ impl<'tcx> IntRange<'tcx> { } // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it. - fn signed_bias(tcx: TyCtxt<'_, 'tcx, 'tcx>, ty: Ty<'tcx>) -> u128 { + fn signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> u128 { match ty.sty { ty::Int(ity) => { let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128; @@ -903,7 +902,7 @@ impl<'tcx> IntRange<'tcx> { /// Converts a `RangeInclusive` to a `ConstantValue` or inclusive `ConstantRange`. fn range_to_ctor( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, r: RangeInclusive, ) -> Constructor<'tcx> { @@ -919,10 +918,11 @@ impl<'tcx> IntRange<'tcx> { /// Returns a collection of ranges that spans the values covered by `ranges`, subtracted /// by the values covered by `self`: i.e., `ranges \ self` (in set notation). - fn subtract_from(self, - tcx: TyCtxt<'_, 'tcx, 'tcx>, - ranges: Vec>) - -> Vec> { + fn subtract_from( + self, + tcx: TyCtxt<'tcx>, + ranges: Vec>, + ) -> Vec> { let ranges = ranges.into_iter().filter_map(|r| { IntRange::from_ctor(tcx, &r).map(|i| i.range) }); @@ -988,9 +988,9 @@ enum MissingCtors<'tcx> { // (The split logic gives a performance win, because we always need to know if // the set is empty, but we rarely need the full set, and it can be expensive // to compute the full set.) -fn compute_missing_ctors<'a, 'tcx: 'a>( +fn compute_missing_ctors<'tcx>( info: MissingCtorsInfo, - tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, all_ctors: &Vec>, used_ctors: &Vec>, ) -> MissingCtors<'tcx> { @@ -1060,11 +1060,12 @@ fn compute_missing_ctors<'a, 'tcx: 'a>( /// relation to preceding patterns, it is not reachable) and exhaustiveness /// checking (if a wildcard pattern is useful in relation to a matrix, the /// matrix isn't exhaustive). -pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, - matrix: &Matrix<'p, 'tcx>, - v: &[&Pattern<'tcx>], - witness: WitnessPreference) - -> Usefulness<'tcx> { +pub fn is_useful<'p, 'a, 'tcx>( + cx: &mut MatchCheckCtxt<'a, 'tcx>, + matrix: &Matrix<'p, 'tcx>, + v: &[&Pattern<'tcx>], + witness: WitnessPreference, +) -> Usefulness<'tcx> { let &Matrix(ref rows) = matrix; debug!("is_useful({:#?}, {:#?})", matrix, v); @@ -1113,10 +1114,17 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]); if let Some(constructors) = pat_constructors(cx, v[0], pcx) { - debug!("is_useful - expanding constructors: {:#?}", constructors); - split_grouped_constructors(cx.tcx, constructors, matrix, pcx.ty).into_iter().map(|c| - is_useful_specialized(cx, matrix, v, c, pcx.ty, witness) - ).find(|result| result.is_useful()).unwrap_or(NotUseful) + let is_declared_nonexhaustive = cx.is_non_exhaustive_variant(v[0]) && !cx.is_local(pcx.ty); + debug!("is_useful - expanding constructors: {:#?}, is_declared_nonexhaustive: {:?}", + constructors, is_declared_nonexhaustive); + + if is_declared_nonexhaustive { + Useful + } else { + split_grouped_constructors(cx.tcx, constructors, matrix, pcx.ty).into_iter().map(|c| + is_useful_specialized(cx, matrix, v, c, pcx.ty, witness) + ).find(|result| result.is_useful()).unwrap_or(NotUseful) + } } else { debug!("is_useful - expanding wildcard"); @@ -1263,7 +1271,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, /// A shorthand for the `U(S(c, P), S(c, q))` operation from the paper. I.e., `is_useful` applied /// to the specialised version of both the pattern matrix `P` and the new pattern `q`. -fn is_useful_specialized<'p, 'a: 'p, 'tcx: 'a>( +fn is_useful_specialized<'p, 'a, 'tcx>( cx: &mut MatchCheckCtxt<'a, 'tcx>, &Matrix(ref m): &Matrix<'p, 'tcx>, v: &[&Pattern<'tcx>], @@ -1307,7 +1315,7 @@ fn is_useful_specialized<'p, 'a: 'p, 'tcx: 'a>( /// Returns `None` in case of a catch-all, which can't be specialized. fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>, pat: &Pattern<'tcx>, - pcx: PatternContext<'_>) + pcx: PatternContext<'tcx>) -> Option>> { match *pat.kind { @@ -1316,7 +1324,7 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>, PatternKind::Binding { .. } | PatternKind::Wild => None, PatternKind::Leaf { .. } | PatternKind::Deref { .. } => Some(vec![Single]), PatternKind::Variant { adt_def, variant_index, .. } => { - Some(vec![Variant(adt_def.variants[variant_index].did)]) + Some(vec![Variant(adt_def.variants[variant_index].def_id)]) } PatternKind::Constant { value } => Some(vec![ConstantValue(value)]), PatternKind::Range(PatternRange { lo, hi, ty, end }) => @@ -1369,13 +1377,14 @@ fn constructor_arity(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor<'tcx>, ty /// expanded to. /// /// For instance, a tuple pattern (43u32, 'a') has sub pattern types [u32, char]. -fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, - ctor: &Constructor<'tcx>, - ty: Ty<'tcx>) -> Vec> -{ +fn constructor_sub_pattern_tys<'a, 'tcx>( + cx: &MatchCheckCtxt<'a, 'tcx>, + ctor: &Constructor<'tcx>, + ty: Ty<'tcx>, +) -> Vec> { debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty); match ty.sty { - ty::Tuple(ref fs) => fs.into_iter().map(|t| *t).collect(), + ty::Tuple(ref fs) => fs.into_iter().map(|t| t.expect_ty()).collect(), ty::Slice(ty) | ty::Array(ty, _) => match *ctor { Slice(length) => (0..length).map(|_| ty).collect(), ConstantValue(_) => vec![], @@ -1419,51 +1428,27 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, // meaning all other types will compare unequal and thus equal patterns often do not cause the // second pattern to lint about unreachable match arms. fn slice_pat_covered_by_const<'tcx>( - tcx: TyCtxt<'_, 'tcx, '_>, + tcx: TyCtxt<'tcx>, _span: Span, - const_val: ty::Const<'tcx>, + const_val: &'tcx ty::Const<'tcx>, prefix: &[Pattern<'tcx>], slice: &Option>, - suffix: &[Pattern<'tcx>] + suffix: &[Pattern<'tcx>], ) -> Result { let data: &[u8] = match (const_val.val, &const_val.ty.sty) { - (ConstValue::ByRef(ptr, alloc), ty::Array(t, n)) => { - if *t != tcx.types.u8 { - // FIXME(oli-obk): can't mix const patterns with slice patterns and get - // any sort of exhaustiveness/unreachable check yet - // This solely means that we don't lint about unreachable patterns, even if some - // are definitely unreachable. - return Ok(false); - } + (ConstValue::ByRef { offset, alloc, .. }, ty::Array(t, n)) => { + assert_eq!(*t, tcx.types.u8); let n = n.assert_usize(tcx).unwrap(); + let ptr = Pointer::new(AllocId(0), offset); alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap() }, - // a slice fat pointer to a zero length slice - (ConstValue::Slice(Scalar::Bits { .. }, 0), ty::Slice(t)) => { - if *t != tcx.types.u8 { - // FIXME(oli-obk): can't mix const patterns with slice patterns and get - // any sort of exhaustiveness/unreachable check yet - // This solely means that we don't lint about unreachable patterns, even if some - // are definitely unreachable. - return Ok(false); - } - &[] - }, - // - (ConstValue::Slice(Scalar::Ptr(ptr), n), ty::Slice(t)) => { - if *t != tcx.types.u8 { - // FIXME(oli-obk): can't mix const patterns with slice patterns and get - // any sort of exhaustiveness/unreachable check yet - // This solely means that we don't lint about unreachable patterns, even if some - // are definitely unreachable. - return Ok(false); - } - tcx.alloc_map - .lock() - .unwrap_memory(ptr.alloc_id) - .get_bytes(&tcx, ptr, Size::from_bytes(n)) - .unwrap() + (ConstValue::Slice { data, start, end }, ty::Slice(t)) => { + assert_eq!(*t, tcx.types.u8); + let ptr = Pointer::new(AllocId(0), Size::from_bytes(start as u64)); + data.get_bytes(&tcx, ptr, Size::from_bytes((end - start) as u64)).unwrap() }, + // FIXME(oli-obk): create a way to extract fat pointers from ByRef + (_, ty::Slice(_)) => return Ok(false), _ => bug!( "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}", const_val, prefix, slice, suffix, @@ -1496,7 +1481,7 @@ fn slice_pat_covered_by_const<'tcx>( // Whether to evaluate a constructor using exhaustive integer matching. This is true if the // constructor is a range or constant with an integer type. -fn should_treat_range_exhaustively(tcx: TyCtxt<'_, 'tcx, 'tcx>, ctor: &Constructor<'tcx>) -> bool { +fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>) -> bool { let ty = match ctor { ConstantValue(value) => value.ty, ConstantRange(_, _, ty, _) => ty, @@ -1541,8 +1526,8 @@ fn should_treat_range_exhaustively(tcx: TyCtxt<'_, 'tcx, 'tcx>, ctor: &Construct /// boundaries for each interval range, sort them, then create constructors for each new interval /// between every pair of boundary points. (This essentially sums up to performing the intuitive /// merging operation depicted above.) -fn split_grouped_constructors<'p, 'a: 'p, 'tcx: 'a>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn split_grouped_constructors<'p, 'tcx>( + tcx: TyCtxt<'tcx>, ctors: Vec>, &Matrix(ref m): &Matrix<'p, 'tcx>, ty: Ty<'tcx>, @@ -1619,8 +1604,8 @@ fn split_grouped_constructors<'p, 'a: 'p, 'tcx: 'a>( } /// Checks whether there exists any shared value in either `ctor` or `pat` by intersecting them. -fn constructor_intersects_pattern<'p, 'a: 'p, 'tcx: 'a>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn constructor_intersects_pattern<'p, 'tcx>( + tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>, pat: &'p Pattern<'tcx>, ) -> Option; 2]>> { @@ -1647,8 +1632,8 @@ fn constructor_intersects_pattern<'p, 'a: 'p, 'tcx: 'a>( } } -fn constructor_covered_by_range<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn constructor_covered_by_range<'tcx>( + tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>, pat: &Pattern<'tcx>, ) -> Result { @@ -1709,7 +1694,7 @@ fn constructor_covered_by_range<'a, 'tcx>( } } -fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>( +fn patterns_for_variant<'p, 'tcx>( subpatterns: &'p [FieldPattern<'tcx>], wild_patterns: &[&'p Pattern<'tcx>]) -> SmallVec<[&'p Pattern<'tcx>; 2]> @@ -1732,7 +1717,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>( /// different patterns. /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing /// fields filled with wild patterns. -fn specialize<'p, 'a: 'p, 'tcx: 'a>( +fn specialize<'p, 'a: 'p, 'tcx>( cx: &mut MatchCheckCtxt<'a, 'tcx>, r: &[&'p Pattern<'tcx>], constructor: &Constructor<'tcx>, @@ -1751,11 +1736,9 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { let ref variant = adt_def.variants[variant_index]; - if *constructor == Variant(variant.did) { - Some(patterns_for_variant(subpatterns, wild_patterns)) - } else { - None - } + Some(Variant(variant.def_id)) + .filter(|variant_constructor| variant_constructor == constructor) + .map(|_| patterns_for_variant(subpatterns, wild_patterns)) } PatternKind::Leaf { ref subpatterns } => { @@ -1773,11 +1756,12 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( // necessarily point to memory, they are usually just integers. The only time // they should be pointing to memory is when they are subslices of nonzero // slices - let (opt_ptr, n, ty) = match value.ty.sty { - ty::TyKind::Array(t, n) => { + let (alloc, offset, n, ty) = match value.ty.sty { + ty::Array(t, n) => { match value.val { - ConstValue::ByRef(ptr, alloc) => ( - Some((ptr, alloc)), + ConstValue::ByRef { offset, alloc, .. } => ( + alloc, + offset, n.unwrap_usize(cx.tcx), t, ), @@ -1787,16 +1771,18 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( ), } }, - ty::TyKind::Slice(t) => { + ty::Slice(t) => { match value.val { - ConstValue::Slice(ptr, n) => ( - ptr.to_ptr().ok().map(|ptr| ( - ptr, - cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), - )), - n, + ConstValue::Slice { data, start, end } => ( + data, + Size::from_bytes(start as u64), + (end - start) as u64, t, ), + ConstValue::ByRef { .. } => { + // FIXME(oli-obk): implement `deref` for `ConstValue` + return None; + }, _ => span_bug!( pat.span, "slice pattern constant must be scalar pair but is {:?}", @@ -1813,31 +1799,22 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( }; if wild_patterns.len() as u64 == n { // convert a constant slice/array pattern to a list of patterns. - match (n, opt_ptr) { - (0, _) => Some(SmallVec::new()), - (_, Some((ptr, alloc))) => { - let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?; - (0..n).map(|i| { - let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?; - let scalar = alloc.read_scalar( - &cx.tcx, ptr, layout.size, - ).ok()?; - let scalar = scalar.not_undef().ok()?; - let value = ty::Const::from_scalar(scalar, ty); - let pattern = Pattern { - ty, - span: pat.span, - kind: box PatternKind::Constant { value }, - }; - Some(&*cx.pattern_arena.alloc(pattern)) - }).collect() - }, - (_, None) => span_bug!( - pat.span, - "non zero length slice with const-val {:?}", - value, - ), - } + let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?; + let ptr = Pointer::new(AllocId(0), offset); + (0..n).map(|i| { + let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?; + let scalar = alloc.read_scalar( + &cx.tcx, ptr, layout.size, + ).ok()?; + let scalar = scalar.not_undef().ok()?; + let value = ty::Const::from_scalar(cx.tcx, scalar, ty); + let pattern = Pattern { + ty, + span: pat.span, + kind: box PatternKind::Constant { value }, + }; + Some(&*cx.pattern_arena.alloc(pattern)) + }).collect() } else { None } diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 0f151cd688df9..ed850379af60b 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -14,7 +14,6 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::lint; use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc::util::common::ErrorReported; use rustc::hir::def::*; use rustc::hir::def_id::DefId; @@ -24,44 +23,33 @@ use rustc::hir::{self, Pat, PatKind}; use smallvec::smallvec; use std::slice; -use syntax::ast; use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - for def_id in tcx.body_owners() { - tcx.ensure().check_match(def_id); - } - tcx.sess.abort_if_errors(); -} - -pub(crate) fn check_match<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, -) -> Result<(), ErrorReported> { - let body_id = if let Some(id) = tcx.hir().as_local_node_id(def_id) { +pub(crate) fn check_match<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) { + let body_id = if let Some(id) = tcx.hir().as_local_hir_id(def_id) { tcx.hir().body_owned_by(id) } else { - return Ok(()); + return; }; - tcx.sess.track_errors(|| { - MatchVisitor { - tcx, - tables: tcx.body_tables(body_id), - region_scope_tree: &tcx.region_scope_tree(def_id), - param_env: tcx.param_env(def_id), - identity_substs: InternalSubsts::identity_for_item(tcx, def_id), - }.visit_body(tcx.hir().body(body_id)); - }) + MatchVisitor { + tcx, + body_owner: def_id, + tables: tcx.body_tables(body_id), + region_scope_tree: &tcx.region_scope_tree(def_id), + param_env: tcx.param_env(def_id), + identity_substs: InternalSubsts::identity_for_item(tcx, def_id), + }.visit_body(tcx.hir().body(body_id)); } fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> DiagnosticBuilder<'a> { struct_span_err!(sess, sp, E0004, "{}", &error_message) } -struct MatchVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct MatchVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body_owner: DefId, tables: &'a ty::TypeckTables<'tcx>, param_env: ty::ParamEnv<'tcx>, identity_substs: SubstsRef<'tcx>, @@ -90,6 +78,8 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { self.check_irrefutable(&loc.pat, match loc.source { hir::LocalSource::Normal => "local binding", hir::LocalSource::ForLoopDesugar => "`for` loop binding", + hir::LocalSource::AsyncFn => "async fn binding", + hir::LocalSource::AwaitDesugar => "`await` future binding", }); // Check legality of move bindings and `@` patterns. @@ -114,7 +104,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatternError::StaticInPattern(span) => { self.span_e0158(span, "statics cannot be referenced in patterns") } - PatternError::AssociatedConstInPattern(span) => { + PatternError::AssocConstInPattern(span) => { self.span_e0158(span, "associated consts cannot be referenced in patterns") } PatternError::FloatBug => { @@ -160,7 +150,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { // Second, if there is a guard on each arm, make sure it isn't // assigning or borrowing anything mutably. if let Some(ref guard) = arm.guard { - if self.tcx.check_for_mutation_in_guard_via_ast_walk() { + if !self.tcx.features().bind_by_move_pattern_guards { check_for_mutation_in_guard(self, &guard); } } @@ -171,7 +161,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { } } - let module = self.tcx.hir().get_module_parent_by_hir_id(scrut.hir_id); + let module = self.tcx.hir().get_module_parent(scrut.hir_id); MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { let mut have_errors = false; @@ -203,26 +193,56 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { // Then, if the match has no arms, check whether the scrutinee // is uninhabited. let pat_ty = self.tables.node_type(scrut.hir_id); - let module = self.tcx.hir().get_module_parent_by_hir_id(scrut.hir_id); + let module = self.tcx.hir().get_module_parent(scrut.hir_id); + let mut def_span = None; + let mut missing_variants = vec![]; if inlined_arms.is_empty() { let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns { self.tcx.is_ty_uninhabited_from(module, pat_ty) } else { match pat_ty.sty { ty::Never => true, - ty::Adt(def, _) => def.variants.is_empty(), + ty::Adt(def, _) => { + def_span = self.tcx.hir().span_if_local(def.did); + if def.variants.len() < 4 && !def.variants.is_empty() { + // keep around to point at the definition of non-covered variants + missing_variants = def.variants.iter() + .map(|variant| variant.ident) + .collect(); + } + + let is_non_exhaustive_and_non_local = + def.is_variant_list_non_exhaustive() && !def.did.is_local(); + + !(is_non_exhaustive_and_non_local) && def.variants.is_empty() + }, _ => false } }; if !scrutinee_is_uninhabited { // We know the type is inhabited, so this must be wrong - let mut err = create_e0004(self.tcx.sess, scrut.span, - format!("non-exhaustive patterns: type `{}` \ - is non-empty", - pat_ty)); - span_help!(&mut err, scrut.span, - "ensure that all possible cases are being handled, \ - possibly by adding wildcards or more match arms"); + let mut err = create_e0004( + self.tcx.sess, + scrut.span, + format!("non-exhaustive patterns: {}", match missing_variants.len() { + 0 => format!("type `{}` is non-empty", pat_ty), + 1 => format!( + "pattern `{}` of type `{}` is not handled", + missing_variants[0].name, + pat_ty, + ), + _ => format!("multiple patterns of type `{}` are not handled", pat_ty), + }), + ); + err.help("ensure that all possible cases are being handled, \ + possibly by adding wildcards or more match arms"); + if let Some(sp) = def_span { + err.span_label(sp, format!("`{}` defined here", pat_ty)); + } + // point at the definition of non-covered enum variants + for variant in &missing_variants { + err.span_label(variant.span, "variant not covered"); + } err.emit(); } // If the type *is* uninhabited, it's vacuously exhaustive @@ -241,7 +261,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { } fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) { - let module = self.tcx.hir().get_module_parent(pat.id); + let module = self.tcx.hir().get_module_parent(pat.hir_id); MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { let mut patcx = PatternContext::new(self.tcx, self.param_env.and(self.identity_substs), @@ -264,7 +284,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { }; let pattern_string = witness[0].single_pattern().to_string(); - let mut diag = struct_span_err!( + let mut err = struct_span_err!( self.tcx.sess, pat.span, E0005, "refutable pattern in {}: `{}` not covered", origin, pattern_string @@ -273,19 +293,24 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { PatKind::Path(hir::QPath::Resolved(None, ref path)) if path.segments.len() == 1 && path.segments[0].args.is_none() => { format!("interpreted as {} {} pattern, not new variable", - path.def.article(), path.def.kind_name()) + path.res.article(), path.res.descr()) } _ => format!("pattern `{}` not covered", pattern_string), }; - diag.span_label(pat.span, label_msg); - diag.emit(); + err.span_label(pat.span, label_msg); + if let ty::Adt(def, _) = pattern_ty.sty { + if let Some(sp) = self.tcx.hir().span_if_local(def.did){ + err.span_label(sp, format!("`{}` defined here", pattern_ty)); + } + } + err.emit(); }); } } fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pat) { pat.walk(|p| { - if let PatKind::Binding(_, _, _, ident, None) = p.node { + if let PatKind::Binding(_, _, ident, None) = p.node { if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) { if bm != ty::BindByValue(hir::MutImmutable) { // Nothing to check. @@ -296,7 +321,7 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa if edef.is_enum() && edef.variants.iter().any(|variant| { variant.ident == ident && variant.ctor_kind == CtorKind::Const }) { - let ty_path = cx.tcx.item_path_str(edef.did); + let ty_path = cx.tcx.def_path_str(edef.did); let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, "pattern binding `{}` is named the same as one \ of the variants of the type `{}`", @@ -332,10 +357,11 @@ fn pat_is_catchall(pat: &Pat) -> bool { } // Check for unreachable patterns -fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, - arms: &[(Vec<(&'a Pattern<'tcx>, &hir::Pat)>, Option<&hir::Expr>)], - source: hir::MatchSource) -{ +fn check_arms<'a, 'tcx>( + cx: &mut MatchCheckCtxt<'a, 'tcx>, + arms: &[(Vec<(&'a Pattern<'tcx>, &hir::Pat)>, Option<&hir::Expr>)], + source: hir::MatchSource, +) { let mut seen = Matrix::empty(); let mut catchall = None; for (arm_index, &(ref pats, guard)) in arms.iter().enumerate() { @@ -345,6 +371,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, match is_useful(cx, &seen, &v, LeaveOutWitness) { NotUseful => { match source { + hir::MatchSource::IfDesugar { .. } => bug!(), hir::MatchSource::IfLetDesugar { .. } => { cx.tcx.lint_hir( lint::builtin::IRREFUTABLE_LET_PATTERNS, @@ -393,8 +420,9 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, err.emit(); } - // Unreachable patterns in try expressions occur when one of the arms - // are an uninhabited type. Which is OK. + // Unreachable patterns in try and await expressions occur when one of + // the arms are an uninhabited type. Which is OK. + hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {} } } @@ -411,10 +439,12 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, } } -fn check_exhaustive<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, - scrut_ty: Ty<'tcx>, - sp: Span, - matrix: &Matrix<'p, 'tcx>) { +fn check_exhaustive<'p, 'a, 'tcx>( + cx: &mut MatchCheckCtxt<'a, 'tcx>, + scrut_ty: Ty<'tcx>, + sp: Span, + matrix: &Matrix<'p, 'tcx>, +) { let wild_pattern = Pattern { ty: scrut_ty, span: DUMMY_SP, @@ -448,11 +478,26 @@ fn check_exhaustive<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, 1 => format!("pattern {} not covered", joined_patterns), _ => format!("patterns {} not covered", joined_patterns), }; - create_e0004(cx.tcx.sess, sp, - format!("non-exhaustive patterns: {} not covered", - joined_patterns)) - .span_label(sp, label_text) - .emit(); + let mut err = create_e0004(cx.tcx.sess, sp, format!( + "non-exhaustive patterns: {} not covered", + joined_patterns, + )); + err.span_label(sp, label_text); + // point at the definition of non-covered enum variants + if let ty::Adt(def, _) = scrut_ty.sty { + if let Some(sp) = cx.tcx.hir().span_if_local(def.did){ + err.span_label(sp, format!("`{}` defined here", scrut_ty)); + } + } + let patterns = witnesses.iter().map(|p| (**p).clone()).collect::>>(); + if patterns.len() < 4 { + for sp in maybe_point_at_variant(cx, scrut_ty, patterns.as_slice()) { + err.span_label(sp, "not covered"); + } + } + err.help("ensure that all possible cases are being handled, \ + possibly by adding wildcards or more match arms"); + err.emit(); } NotUseful => { // This is good, wildcard pattern isn't reachable @@ -461,10 +506,49 @@ fn check_exhaustive<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, } } +fn maybe_point_at_variant( + cx: &mut MatchCheckCtxt<'a, 'tcx>, + ty: Ty<'tcx>, + patterns: &[Pattern<'_>], +) -> Vec { + let mut covered = vec![]; + if let ty::Adt(def, _) = ty.sty { + // Don't point at variants that have already been covered due to other patterns to avoid + // visual clutter + for pattern in patterns { + let pk: &PatternKind<'_> = &pattern.kind; + if let PatternKind::Variant { adt_def, variant_index, subpatterns, .. } = pk { + if adt_def.did == def.did { + let sp = def.variants[*variant_index].ident.span; + if covered.contains(&sp) { + continue; + } + covered.push(sp); + let subpatterns = subpatterns.iter() + .map(|field_pattern| field_pattern.pattern.clone()) + .collect::>(); + covered.extend( + maybe_point_at_variant(cx, ty, subpatterns.as_slice()), + ); + } + } + if let PatternKind::Leaf { subpatterns } = pk { + let subpatterns = subpatterns.iter() + .map(|field_pattern| field_pattern.pattern.clone()) + .collect::>(); + covered.extend(maybe_point_at_variant(cx, ty, subpatterns.as_slice())); + } + } + } + covered +} + // Legality of move bindings checking -fn check_legality_of_move_bindings(cx: &MatchVisitor<'_, '_>, - has_guard: bool, - pats: &[P]) { +fn check_legality_of_move_bindings( + cx: &MatchVisitor<'_, '_>, + has_guard: bool, + pats: &[P], +) { let mut by_ref_span = None; for pat in pats { pat.each_binding(|_, hir_id, span, _path| { @@ -487,11 +571,11 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor<'_, '_>, "cannot bind by-move with sub-bindings") .span_label(p.span, "binds an already bound by-move value by moving it") .emit(); - } else if has_guard && !cx.tcx.allow_bind_by_move_patterns_with_guards() { + } else if has_guard && !cx.tcx.features().bind_by_move_pattern_guards { let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008, "cannot bind by-move into a pattern guard"); err.span_label(p.span, "moves value into pattern guard"); - if cx.tcx.sess.opts.unstable_features.is_nightly_build() && cx.tcx.use_mir_borrowck() { + if cx.tcx.sess.opts.unstable_features.is_nightly_build() { err.help("add #![feature(bind_by_move_pattern_guards)] to the \ crate attributes to enable"); } @@ -503,7 +587,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor<'_, '_>, for pat in pats { pat.walk(|p| { - if let PatKind::Binding(_, _, _, _, ref sub) = p.node { + if let PatKind::Binding(_, _, _, ref sub) = p.node { if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) { match bm { ty::BindByValue(..) => { @@ -529,7 +613,9 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor<'_, '_>, E0009, "cannot bind by-move and by-ref in the same pattern", ); - err.span_label(by_ref_span.unwrap(), "both by-ref and by-move used"); + if let Some(by_ref_span) = by_ref_span { + err.span_label(by_ref_span, "both by-ref and by-move used"); + } for span in span_vec.iter(){ err.span_label(*span, "by-move pattern here"); } @@ -548,6 +634,7 @@ fn check_for_mutation_in_guard(cx: &MatchVisitor<'_, '_>, guard: &hir::Guard) { hir::Guard::If(expr) => ExprUseVisitor::new(&mut checker, cx.tcx, + cx.body_owner, cx.param_env, cx.region_scope_tree, cx.tables, @@ -555,7 +642,7 @@ fn check_for_mutation_in_guard(cx: &MatchVisitor<'_, '_>, guard: &hir::Guard) { }; } -struct MutationChecker<'a, 'tcx: 'a> { +struct MutationChecker<'a, 'tcx> { cx: &'a MatchVisitor<'a, 'tcx>, } @@ -575,9 +662,7 @@ impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> { let mut err = struct_span_err!(self.cx.tcx.sess, span, E0301, "cannot mutably borrow in a pattern guard"); err.span_label(span, "borrowed mutably in pattern guard"); - if self.cx.tcx.sess.opts.unstable_features.is_nightly_build() && - self.cx.tcx.use_mir_borrowck() - { + if self.cx.tcx.sess.opts.unstable_features.is_nightly_build() { err.help("add #![feature(bind_by_move_pattern_guards)] to the \ crate attributes to enable"); } @@ -586,7 +671,7 @@ impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> { ty::ImmBorrow | ty::UniqueImmBorrow => {} } } - fn decl_without_init(&mut self, _: ast::NodeId, _: Span) {} + fn decl_without_init(&mut self, _: hir::HirId, _: Span) {} fn mutate(&mut self, _: hir::HirId, span: Span, _: &cmt_<'_>, mode: MutateMode) { match mode { MutateMode::JustWrite | MutateMode::WriteAndRead => { @@ -606,7 +691,7 @@ fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pa AtBindingPatternVisitor { cx: cx, bindings_allowed: true }.visit_pat(pat); } -struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> { +struct AtBindingPatternVisitor<'a, 'b, 'tcx> { cx: &'a MatchVisitor<'b, 'tcx>, bindings_allowed: bool } diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index d5f2e7a7275e8..cf597ce0b6319 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -3,23 +3,22 @@ mod _match; mod check_match; -pub use self::check_match::check_crate; pub(crate) use self::check_match::check_match; -use crate::const_eval::{const_field, const_variant_index}; +use crate::const_eval::const_variant_index; use crate::hair::util::UserAnnotatedTyHelpers; use crate::hair::constant::*; -use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability}; +use rustc::mir::{Field, BorrowKind, Mutability}; use rustc::mir::{UserTypeProjection}; -use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend}; -use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, Lift, UserType}; +use rustc::mir::interpret::{GlobalId, ConstValue, sign_extend, AllocId, Pointer}; +use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree}; use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations}; use rustc::ty::subst::{SubstsRef, Kind}; -use rustc::ty::layout::VariantIdx; +use rustc::ty::layout::{VariantIdx, Size}; use rustc::hir::{self, PatKind, RangeEnd}; -use rustc::hir::def::{Def, CtorKind}; +use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc_data_structures::indexed_vec::Idx; @@ -28,11 +27,12 @@ use std::cmp::Ordering; use std::fmt; use syntax::ast; use syntax::ptr::P; +use syntax::symbol::sym; use syntax_pos::Span; #[derive(Clone, Debug)] pub enum PatternError { - AssociatedConstInPattern(Span), + AssocConstInPattern(Span), StaticInPattern(Span), FloatBug, NonConstPath(Span), @@ -75,7 +75,7 @@ impl<'tcx> PatternTypeProjection<'tcx> { annotations: &mut CanonicalUserTypeAnnotations<'tcx>, inferred_ty: Ty<'tcx>, span: Span, - ) -> UserTypeProjection<'tcx> { + ) -> UserTypeProjection { UserTypeProjection { base: annotations.push(CanonicalUserTypeAnnotation { span, @@ -126,7 +126,7 @@ pub enum PatternKind<'tcx> { mutability: Mutability, name: ast::Name, mode: BindingMode, - var: ast::NodeId, + var: hir::HirId, ty: Ty<'tcx>, subpattern: Option>, }, @@ -152,7 +152,7 @@ pub enum PatternKind<'tcx> { }, Constant { - value: ty::Const<'tcx>, + value: &'tcx ty::Const<'tcx>, }, Range(PatternRange<'tcx>), @@ -176,8 +176,8 @@ pub enum PatternKind<'tcx> { #[derive(Copy, Clone, Debug, PartialEq)] pub struct PatternRange<'tcx> { - pub lo: ty::Const<'tcx>, - pub hi: ty::Const<'tcx>, + pub lo: &'tcx ty::Const<'tcx>, + pub hi: &'tcx ty::Const<'tcx>, pub ty: Ty<'tcx>, pub end: RangeEnd, } @@ -291,15 +291,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { write!(f, "{}", subpattern) } PatternKind::Constant { value } => { - fmt_const_val(f, value) + write!(f, "{}", value) } PatternKind::Range(PatternRange { lo, hi, ty: _, end }) => { - fmt_const_val(f, lo)?; + write!(f, "{}", lo)?; match end { RangeEnd::Included => write!(f, "..=")?, RangeEnd::Excluded => write!(f, "..")?, } - fmt_const_val(f, hi) + write!(f, "{}", hi) } PatternKind::Slice { ref prefix, ref slice, ref suffix } | PatternKind::Array { ref prefix, ref slice, ref suffix } => { @@ -326,8 +326,8 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { } } -pub struct PatternContext<'a, 'tcx: 'a> { - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub struct PatternContext<'a, 'tcx> { + pub tcx: TyCtxt<'tcx>, pub param_env: ty::ParamEnv<'tcx>, pub tables: &'a ty::TypeckTables<'tcx>, pub substs: SubstsRef<'tcx>, @@ -335,10 +335,12 @@ pub struct PatternContext<'a, 'tcx: 'a> { } impl<'a, 'tcx> Pattern<'tcx> { - pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env_and_substs: ty::ParamEnvAnd<'tcx, SubstsRef<'tcx>>, - tables: &'a ty::TypeckTables<'tcx>, - pat: &'tcx hir::Pat) -> Self { + pub fn from_hir( + tcx: TyCtxt<'tcx>, + param_env_and_substs: ty::ParamEnvAnd<'tcx, SubstsRef<'tcx>>, + tables: &'a ty::TypeckTables<'tcx>, + pat: &'tcx hir::Pat, + ) -> Self { let mut pcx = PatternContext::new(tcx, param_env_and_substs, tables); let result = pcx.lower_pattern(pat); if !pcx.errors.is_empty() { @@ -351,9 +353,11 @@ impl<'a, 'tcx> Pattern<'tcx> { } impl<'a, 'tcx> PatternContext<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env_and_substs: ty::ParamEnvAnd<'tcx, SubstsRef<'tcx>>, - tables: &'a ty::TypeckTables<'tcx>) -> Self { + pub fn new( + tcx: TyCtxt<'tcx>, + param_env_and_substs: ty::ParamEnvAnd<'tcx, SubstsRef<'tcx>>, + tables: &'a ty::TypeckTables<'tcx>, + ) -> Self { PatternContext { tcx, param_env: param_env_and_substs.param_env, @@ -428,7 +432,6 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let mut kind = match (lo, hi) { (PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => { - use std::cmp::Ordering; let cmp = compare_const_vals( self.tcx, lo, @@ -530,11 +533,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::Error => { // Avoid ICE return Pattern { span: pat.span, ty, kind: Box::new(PatternKind::Wild) }; } - ref sty => + _ => span_bug!( pat.span, "unexpanded type for vector pattern: {:?}", - sty), + ty), } } @@ -555,11 +558,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::Error => { // Avoid ICE (#50577) return Pattern { span: pat.span, ty, kind: Box::new(PatternKind::Wild) }; } - ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty), + _ => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty), } } - PatKind::Binding(_, id, _, ident, ref sub) => { + PatKind::Binding(_, id, ident, ref sub) => { let var_ty = self.tables.node_type(pat.hir_id); if let ty::Error = var_ty.sty { // Avoid ICE @@ -601,7 +604,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => { - let def = self.tables.qpath_def(qpath, pat.hir_id); + let res = self.tables.qpath_res(qpath, pat.hir_id); let adt_def = match ty.sty { ty::Adt(adt_def, _) => adt_def, ty::Error => { // Avoid ICE (#50585) @@ -609,9 +612,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT {:?}", - ty.sty), + ty), }; - let variant_def = adt_def.variant_of_def(def); + let variant_def = adt_def.variant_of_res(res); let subpatterns = subpatterns.iter() @@ -622,11 +625,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }) .collect(); - self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns) + self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns) } PatKind::Struct(ref qpath, ref fields, _) => { - let def = self.tables.qpath_def(qpath, pat.hir_id); + let res = self.tables.qpath_res(qpath, pat.hir_id); let subpatterns = fields.iter() .map(|field| { @@ -638,7 +641,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }) .collect(); - self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns) + self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns) } }; @@ -728,15 +731,23 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn lower_variant_or_leaf( &mut self, - def: Def, + res: Res, hir_id: hir::HirId, span: Span, ty: Ty<'tcx>, subpatterns: Vec>, ) -> PatternKind<'tcx> { - let mut kind = match def { - Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => { - let enum_id = self.tcx.parent_def_id(variant_id).unwrap(); + let res = match res { + Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => { + let variant_id = self.tcx.parent(variant_ctor_id).unwrap(); + Res::Def(DefKind::Variant, variant_id) + }, + res => res, + }; + + let mut kind = match res { + Res::Def(DefKind::Variant, variant_id) => { + let enum_id = self.tcx.parent(variant_id).unwrap(); let adt_def = self.tcx.adt_def(enum_id); if adt_def.is_enum() { let substs = match ty.sty { @@ -745,7 +756,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::Error => { // Avoid ICE (#50585) return PatternKind::Wild; } - _ => bug!("inappropriate type for def: {:?}", ty.sty), + _ => bug!("inappropriate type for def: {:?}", ty), }; PatternKind::Variant { adt_def, @@ -758,8 +769,13 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } - Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) | - Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) | Def::SelfCtor(..) => { + Res::Def(DefKind::Struct, _) + | Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _) + | Res::Def(DefKind::Union, _) + | Res::Def(DefKind::TyAlias, _) + | Res::Def(DefKind::AssocTy, _) + | Res::SelfTy(..) + | Res::SelfCtor(..) => { PatternKind::Leaf { subpatterns } } @@ -797,13 +813,13 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { span: Span) -> Pattern<'tcx> { let ty = self.tables.node_type(id); - let def = self.tables.qpath_def(qpath, id); - let is_associated_const = match def { - Def::AssociatedConst(_) => true, + let res = self.tables.qpath_res(qpath, id); + let is_associated_const = match res { + Res::Def(DefKind::AssocConst, _) => true, _ => false, }; - let kind = match def { - Def::Const(def_id) | Def::AssociatedConst(def_id) => { + let kind = match res { + Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => { let substs = self.tables.node_substs(id); match ty::Instance::resolve( self.tcx, @@ -857,7 +873,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }, None => { self.errors.push(if is_associated_const { - PatternError::AssociatedConstInPattern(span) + PatternError::AssocConstInPattern(span) } else { PatternError::StaticInPattern(span) }); @@ -865,7 +881,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }, } } - _ => self.lower_variant_or_leaf(def, id, span, ty, vec![]), + _ => self.lower_variant_or_leaf(res, id, span, ty, vec![]), }; Pattern { @@ -930,17 +946,16 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn const_to_pat( &self, instance: ty::Instance<'tcx>, - cv: ty::Const<'tcx>, + cv: &'tcx ty::Const<'tcx>, id: hir::HirId, span: Span, ) -> Pattern<'tcx> { debug!("const_to_pat: cv={:#?} id={:?}", cv, id); let adt_subpattern = |i, variant_opt| { let field = Field::new(i); - let val = const_field( - self.tcx, self.param_env, - variant_opt, field, cv, - ).expect("field access failed"); + let val = crate::const_eval::const_field( + self.tcx, self.param_env, variant_opt, field, cv + ); self.const_to_pat(instance, val, id, span) }; let adt_subpatterns = |n, variant_opt| { @@ -970,18 +985,33 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { self.tcx.sess.span_err(span, "cannot use unions in constant patterns"); PatternKind::Wild } - ty::Adt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => { - let msg = format!("to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - self.tcx.item_path_str(adt_def.did), - self.tcx.item_path_str(adt_def.did)); + ty::Adt(adt_def, _) if !self.tcx.has_attr(adt_def.did, sym::structural_match) => { + let path = self.tcx.def_path_str(adt_def.did); + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, + path, + ); + self.tcx.sess.span_err(span, &msg); + PatternKind::Wild + } + ty::Ref(_, ty::TyS { sty: ty::Adt(adt_def, _), .. }, _) + if !self.tcx.has_attr(adt_def.did, sym::structural_match) => { + // HACK(estebank): Side-step ICE #53708, but anything other than erroring here + // would be wrong. Returnging `PatternKind::Wild` is not technically correct. + let path = self.tcx.def_path_str(adt_def.did); + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, + path, + ); self.tcx.sess.span_err(span, &msg); PatternKind::Wild } ty::Adt(adt_def, substs) if adt_def.is_enum() => { - let variant_index = const_variant_index( - self.tcx, self.param_env, cv - ).expect("const_variant_index failed"); + let variant_index = const_variant_index(self.tcx, self.param_env, cv); let subpatterns = adt_subpatterns( adt_def.variants[variant_index].fields.len(), Some(variant_index), @@ -1028,8 +1058,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } -impl UserAnnotatedTyHelpers<'tcx, 'tcx> for PatternContext<'_, 'tcx> { - fn tcx(&self) -> TyCtxt<'_, 'tcx, 'tcx> { +impl UserAnnotatedTyHelpers<'tcx> for PatternContext<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -1090,10 +1120,10 @@ macro_rules! CloneImpls { } CloneImpls!{ <'tcx> - Span, Field, Mutability, ast::Name, ast::NodeId, usize, ty::Const<'tcx>, + Span, Field, Mutability, ast::Name, hir::HirId, usize, ty::Const<'tcx>, Region<'tcx>, Ty<'tcx>, BindingMode, &'tcx AdtDef, SubstsRef<'tcx>, &'tcx Kind<'tcx>, UserType<'tcx>, - UserTypeProjection<'tcx>, PatternTypeProjection<'tcx> + UserTypeProjection, PatternTypeProjection<'tcx> } impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> { @@ -1181,7 +1211,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { PatternKind::Constant { value } => PatternKind::Constant { - value: value.fold_with(folder) + value, }, PatternKind::Range(PatternRange { lo, @@ -1189,8 +1219,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { ty, end, }) => PatternKind::Range(PatternRange { - lo: lo.fold_with(folder), - hi: hi.fold_with(folder), + lo, + hi, ty: ty.fold_with(folder), end, }), @@ -1216,10 +1246,10 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { } } -pub fn compare_const_vals<'a, 'gcx, 'tcx>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, +pub fn compare_const_vals<'tcx>( + tcx: TyCtxt<'tcx>, + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Option { trace!("compare_const_vals: {:?}, {:?}", a, b); @@ -1239,9 +1269,6 @@ pub fn compare_const_vals<'a, 'gcx, 'tcx>( return fallback(); } - let tcx = tcx.global_tcx(); - let (a, b, ty) = (a, b, ty).lift_to_tcx(tcx).unwrap(); - // FIXME: This should use assert_bits(ty) instead of use_bits // but triggers possibly bugs due to mismatching of arrays and slices if let (Some(a), Some(b)) = (a.to_bits(tcx, ty), b.to_bits(tcx, ty)) { @@ -1257,11 +1284,12 @@ pub fn compare_const_vals<'a, 'gcx, 'tcx>( let r = ::rustc_apfloat::ieee::Double::from_bits(b); l.partial_cmp(&r) } - ty::Int(_) => { - let layout = tcx.layout_of(ty).ok()?; - assert!(layout.abi.is_signed()); - let a = sign_extend(a, layout.size); - let b = sign_extend(b, layout.size); + ty::Int(ity) => { + use rustc::ty::layout::{Integer, IntegerExt}; + use syntax::attr::SignedInt; + let size = Integer::from_attr(&tcx, SignedInt(ity)).size(); + let a = sign_extend(a, size); + let b = sign_extend(b, size); Some((a as i128).cmp(&(b as i128))) } _ => Some(a.cmp(&b)), @@ -1271,22 +1299,25 @@ pub fn compare_const_vals<'a, 'gcx, 'tcx>( if let ty::Str = ty.value.sty { match (a.val, b.val) { ( - ConstValue::Slice( - Scalar::Ptr(ptr_a), - len_a, - ), - ConstValue::Slice( - Scalar::Ptr(ptr_b), - len_b, - ), - ) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => { - if len_a == len_b { - let map = tcx.alloc_map.lock(); - let alloc_a = map.unwrap_memory(ptr_a.alloc_id); - let alloc_b = map.unwrap_memory(ptr_b.alloc_id); - if alloc_a.bytes.len() as u64 == len_a { - return from_bool(alloc_a == alloc_b); - } + ConstValue::Slice { data: alloc_a, start: offset_a, end: end_a }, + ConstValue::Slice { data: alloc_b, start: offset_b, end: end_b }, + ) => { + let len_a = end_a - offset_a; + let len_b = end_b - offset_b; + let a = alloc_a.get_bytes( + &tcx, + // invent a pointer, only the offset is relevant anyway + Pointer::new(AllocId(0), Size::from_bytes(offset_a as u64)), + Size::from_bytes(len_a as u64), + ); + let b = alloc_b.get_bytes( + &tcx, + // invent a pointer, only the offset is relevant anyway + Pointer::new(AllocId(0), Size::from_bytes(offset_b as u64)), + Size::from_bytes(len_b as u64), + ); + if let (Ok(a), Ok(b)) = (a, b) { + return from_bool(a == b); } } _ => (), diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs index 4618cd42686fa..4e014855df5e0 100644 --- a/src/librustc_mir/hair/util.rs +++ b/src/librustc_mir/hair/util.rs @@ -1,8 +1,8 @@ use rustc::hir; use rustc::ty::{self, CanonicalUserType, TyCtxt, UserType}; -crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> { - fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx>; +crate trait UserAnnotatedTyHelpers<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx>; fn tables(&self) -> &ty::TypeckTables<'tcx>; @@ -16,7 +16,8 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> { let user_provided_types = self.tables().user_provided_types(); let mut user_ty = *user_provided_types.get(hir_id)?; debug!("user_subts_applied_to_ty_of_hir_id: user_ty={:?}", user_ty); - match &self.tables().node_type(hir_id).sty { + let ty = self.tables().node_type(hir_id); + match ty.sty { ty::Adt(adt_def, ..) => { if let UserType::TypeOf(ref mut did, _) = &mut user_ty.value { *did = adt_def.did; @@ -24,8 +25,11 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> { Some(user_ty) } ty::FnDef(..) => Some(user_ty), - sty => - bug!("sty: {:?} should not have user provided type {:?} recorded ", sty, user_ty), + _ => bug!( + "ty: {:?} should not have user provided type {:?} recorded ", + ty, + user_ty + ), } } } diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index ce62d79e585a8..fbacdf6cd93bb 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -1,17 +1,19 @@ use rustc::ty::{self, Ty, TypeAndMut}; use rustc::ty::layout::{self, TyLayout, Size}; +use rustc::ty::adjustment::{PointerCast}; use syntax::ast::{FloatTy, IntTy, UintTy}; +use syntax::symbol::sym; use rustc_apfloat::ieee::{Single, Double}; +use rustc_apfloat::{Float, FloatConvert}; use rustc::mir::interpret::{ - Scalar, EvalResult, Pointer, PointerArithmetic, EvalErrorKind, truncate + Scalar, InterpResult, Pointer, PointerArithmetic, InterpError, }; use rustc::mir::CastKind; -use rustc_apfloat::Float; -use super::{EvalContext, Machine, PlaceTy, OpTy, ImmTy, Immediate}; +use super::{InterpretCx, Machine, PlaceTy, OpTy, Immediate}; -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> { fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool { match ty.sty { ty::RawPtr(ty::TypeAndMut { ty, .. }) | @@ -26,14 +28,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> src: OpTy<'tcx, M::PointerTag>, kind: CastKind, dest: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { use rustc::mir::CastKind::*; match kind { - Unsize => { + Pointer(PointerCast::Unsize) => { self.unsize_into(src, dest)?; } - Misc => { + Misc | Pointer(PointerCast::MutToConstPointer) => { let src = self.read_immediate(src)?; if self.type_is_fat_ptr(src.layout.ty) { @@ -53,19 +55,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } else { match src.layout.variants { layout::Variants::Single { index } => { - if let Some(def) = src.layout.ty.ty_adt_def() { + if let Some(discr) = + src.layout.ty.discriminant_for_variant(*self.tcx, index) + { // Cast from a univariant enum assert!(src.layout.is_zst()); - let discr_val = def - .discriminant_for_variant(*self.tcx, index) - .val; return self.write_scalar( - Scalar::from_uint(discr_val, dest.layout.size), + Scalar::from_uint(discr.val, dest.layout.size), dest); } } - layout::Variants::Tagged { .. } | - layout::Variants::NicheFilling { .. } => {}, + layout::Variants::Multiple { .. } => {}, } let dest_val = self.cast_scalar(src.to_scalar()?, src.layout, dest.layout)?; @@ -73,39 +73,38 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } } - ReifyFnPointer => { + Pointer(PointerCast::ReifyFnPointer) => { // The src operand does not matter, just its type match src.layout.ty.sty { ty::FnDef(def_id, substs) => { - if self.tcx.has_attr(def_id, "rustc_args_required_const") { - bug!("reifying a fn ptr that requires \ - const arguments"); + if self.tcx.has_attr(def_id, sym::rustc_args_required_const) { + bug!("reifying a fn ptr that requires const arguments"); } - let instance: EvalResult<'tcx, _> = ty::Instance::resolve( + let instance: InterpResult<'tcx, _> = ty::Instance::resolve( *self.tcx, self.param_env, def_id, substs, - ).ok_or_else(|| EvalErrorKind::TooGeneric.into()); - let fn_ptr = self.memory.create_fn_alloc(instance?).with_default_tag(); + ).ok_or_else(|| InterpError::TooGeneric.into()); + let fn_ptr = self.memory.create_fn_alloc(instance?); self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?; } - ref other => bug!("reify fn pointer on {:?}", other), + _ => bug!("reify fn pointer on {:?}", src.layout.ty), } } - UnsafeFnPointer => { + Pointer(PointerCast::UnsafeFnPointer) => { let src = self.read_immediate(src)?; match dest.layout.ty.sty { ty::FnPtr(_) => { // No change to value self.write_immediate(*src, dest)?; } - ref other => bug!("fn to unsafe fn cast on {:?}", other), + _ => bug!("fn to unsafe fn cast on {:?}", dest.layout.ty), } } - ClosureFnPointer => { + Pointer(PointerCast::ClosureFnPointer(_)) => { // The src operand does not matter, just its type match src.layout.ty.sty { ty::Closure(def_id, substs) => { @@ -116,59 +115,56 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> substs, ty::ClosureKind::FnOnce, ); - let fn_ptr = self.memory.create_fn_alloc(instance).with_default_tag(); + let fn_ptr = self.memory.create_fn_alloc(instance); let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into()); self.write_immediate(val, dest)?; } - ref other => bug!("closure fn pointer on {:?}", other), + _ => bug!("closure fn pointer on {:?}", src.layout.ty), } } } Ok(()) } - pub(super) fn cast_scalar( + fn cast_scalar( &self, val: Scalar, src_layout: TyLayout<'tcx>, dest_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { use rustc::ty::TyKind::*; trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty); - match val { - Scalar::Ptr(ptr) => self.cast_from_ptr(ptr, dest_layout.ty), - Scalar::Bits { bits, size } => { - debug_assert_eq!(size as u64, src_layout.size.bytes()); - debug_assert_eq!(truncate(bits, Size::from_bytes(size.into())), bits, - "Unexpected value of size {} before casting", size); - - let res = match src_layout.ty.sty { - Float(fty) => self.cast_from_float(bits, fty, dest_layout.ty)?, - _ => self.cast_from_int(bits, src_layout, dest_layout)?, - }; - - // Sanity check - match res { - Scalar::Ptr(_) => bug!("Fabricated a ptr value from an int...?"), - Scalar::Bits { bits, size } => { - debug_assert_eq!(size as u64, dest_layout.size.bytes()); - debug_assert_eq!(truncate(bits, Size::from_bytes(size.into())), bits, - "Unexpected value of size {} after casting", size); - } + match src_layout.ty.sty { + // Floating point + Float(FloatTy::F32) => self.cast_from_float(val.to_f32()?, dest_layout.ty), + Float(FloatTy::F64) => self.cast_from_float(val.to_f64()?, dest_layout.ty), + // Integer(-like), including fn ptr casts and casts from enums that + // are represented as integers (this excludes univariant enums, which + // are handled in `cast` directly). + _ => { + assert!( + src_layout.ty.is_bool() || src_layout.ty.is_char() || + src_layout.ty.is_enum() || src_layout.ty.is_integral() || + src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_ptr() || + src_layout.ty.is_region_ptr(), + "Unexpected cast from type {:?}", src_layout.ty + ); + match val.to_bits_or_ptr(src_layout.size, self) { + Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty), + Ok(data) => self.cast_from_int(data, src_layout, dest_layout), } - // Done - Ok(res) } } } fn cast_from_int( &self, - v: u128, + v: u128, // raw bits src_layout: TyLayout<'tcx>, dest_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { + // Let's make sure v is sign-extended *if* it has a signed type. let signed = src_layout.abi.is_signed(); let v = if signed { self.sign_extend(v, src_layout) @@ -178,26 +174,22 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty); use rustc::ty::TyKind::*; match dest_layout.ty.sty { - Int(_) | Uint(_) => { + Int(_) | Uint(_) | RawPtr(_) => { let v = self.truncate(v, dest_layout); Ok(Scalar::from_uint(v, dest_layout.size)) } - Float(FloatTy::F32) if signed => Ok(Scalar::from_uint( - Single::from_i128(v as i128).value.to_bits(), - Size::from_bits(32) + Float(FloatTy::F32) if signed => Ok(Scalar::from_f32( + Single::from_i128(v as i128).value )), - Float(FloatTy::F64) if signed => Ok(Scalar::from_uint( - Double::from_i128(v as i128).value.to_bits(), - Size::from_bits(64) + Float(FloatTy::F64) if signed => Ok(Scalar::from_f64( + Double::from_i128(v as i128).value )), - Float(FloatTy::F32) => Ok(Scalar::from_uint( - Single::from_u128(v).value.to_bits(), - Size::from_bits(32) + Float(FloatTy::F32) => Ok(Scalar::from_f32( + Single::from_u128(v).value )), - Float(FloatTy::F64) => Ok(Scalar::from_uint( - Double::from_u128(v).value.to_bits(), - Size::from_bits(64) + Float(FloatTy::F64) => Ok(Scalar::from_f64( + Double::from_u128(v).value )), Char => { @@ -206,66 +198,41 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> Ok(Scalar::from_uint(v, Size::from_bytes(4))) }, - // No alignment check needed for raw pointers. - // But we have to truncate to target ptr size. - RawPtr(_) => { - Ok(Scalar::from_uint( - self.truncate_to_ptr(v).0, - self.pointer_size(), - )) - }, - // Casts to bool are not permitted by rustc, no need to handle them here. _ => err!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))), } } - fn cast_from_float( + fn cast_from_float( &self, - bits: u128, - fty: FloatTy, + f: F, dest_ty: Ty<'tcx> - ) -> EvalResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> + where F: Float + Into> + FloatConvert + FloatConvert + { use rustc::ty::TyKind::*; - use rustc_apfloat::FloatConvert; match dest_ty.sty { // float -> uint Uint(t) => { let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize); - let v = match fty { - FloatTy::F32 => Single::from_bits(bits).to_u128(width).value, - FloatTy::F64 => Double::from_bits(bits).to_u128(width).value, - }; + let v = f.to_u128(width).value; // This should already fit the bit width Ok(Scalar::from_uint(v, Size::from_bits(width as u64))) }, // float -> int Int(t) => { let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize); - let v = match fty { - FloatTy::F32 => Single::from_bits(bits).to_i128(width).value, - FloatTy::F64 => Double::from_bits(bits).to_i128(width).value, - }; + let v = f.to_i128(width).value; Ok(Scalar::from_int(v, Size::from_bits(width as u64))) }, - // f64 -> f32 - Float(FloatTy::F32) if fty == FloatTy::F64 => { - Ok(Scalar::from_uint( - Single::to_bits(Double::from_bits(bits).convert(&mut false).value), - Size::from_bits(32), - )) - }, - // f32 -> f64 - Float(FloatTy::F64) if fty == FloatTy::F32 => { - Ok(Scalar::from_uint( - Double::to_bits(Single::from_bits(bits).convert(&mut false).value), - Size::from_bits(64), - )) - }, - // identity cast - Float(FloatTy:: F64) => Ok(Scalar::from_uint(bits, Size::from_bits(64))), - Float(FloatTy:: F32) => Ok(Scalar::from_uint(bits, Size::from_bits(32))), - _ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))), + // float -> f32 + Float(FloatTy::F32) => + Ok(Scalar::from_f32(f.convert(&mut false).value)), + // float -> f64 + Float(FloatTy::F64) => + Ok(Scalar::from_f64(f.convert(&mut false).value)), + // That's it. + _ => bug!("invalid float to {:?} cast", dest_ty), } } @@ -273,7 +240,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> &self, ptr: Pointer, ty: Ty<'tcx> - ) -> EvalResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { use rustc::ty::TyKind::*; match ty.sty { // Casting to a reference or fn pointer is not permitted by rustc, @@ -293,7 +260,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // The pointee types sty: Ty<'tcx>, dty: Ty<'tcx>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { // A -> A conversion let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty); @@ -331,7 +298,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> &mut self, src: OpTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { + trace!("Unsizing {:?} into {:?}", src, dest); match (&src.layout.ty.sty, &dest.layout.ty.sty) { (&ty::Ref(_, s, _), &ty::Ref(_, d, _)) | (&ty::Ref(_, s, _), &ty::RawPtr(TypeAndMut { ty: d, .. })) | @@ -361,20 +329,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> if dst_field.layout.is_zst() { continue; } - let src_field = match src.try_as_mplace() { - Ok(mplace) => { - let src_field = self.mplace_field(mplace, i as u64)?; - src_field.into() - } - Err(..) => { - let src_field_layout = src.layout.field(self, i)?; - // this must be a field covering the entire thing - assert_eq!(src.layout.fields.offset(i).bytes(), 0); - assert_eq!(src_field_layout.size, src.layout.size); - // just sawp out the layout - OpTy::from(ImmTy { imm: src.to_immediate(), layout: src_field_layout }) - } - }; + let src_field = self.operand_field(src, i as u64)?; if src_field.layout.ty == dst_field.layout.ty { self.copy_op(src_field, dst_field)?; } else { diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 8a32c3b636c71..c6e762bddd4d9 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -4,7 +4,7 @@ use std::mem; use syntax::source_map::{self, Span, DUMMY_SP}; use rustc::hir::def_id::DefId; -use rustc::hir::def::Def; +use rustc::hir::def::DefKind; use rustc::mir; use rustc::ty::layout::{ self, Size, Align, HasDataLayout, LayoutOf, TyLayout @@ -15,8 +15,8 @@ use rustc::ty::query::TyCtxtAt; use rustc_data_structures::indexed_vec::IndexVec; use rustc::mir::interpret::{ ErrorHandled, - GlobalId, Scalar, FrameInfo, AllocId, - EvalResult, EvalErrorKind, + GlobalId, Scalar, Pointer, FrameInfo, AllocId, + InterpResult, InterpError, truncate, sign_extend, }; use rustc_data_structures::fx::FxHashMap; @@ -26,34 +26,35 @@ use super::{ Memory, Machine }; -pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> { +pub struct InterpretCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// Stores the `Machine` instance. pub machine: M, /// The results of the type checker, from rustc. - pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>, + pub tcx: TyCtxtAt<'tcx>, /// Bounds in scope for polymorphic evaluations. pub(crate) param_env: ty::ParamEnv<'tcx>, /// The virtual memory system. - pub(crate) memory: Memory<'a, 'mir, 'tcx, M>, + pub(crate) memory: Memory<'mir, 'tcx, M>, /// The virtual call stack. pub(crate) stack: Vec>, /// A cache for deduplicating vtables - pub(super) vtables: FxHashMap<(Ty<'tcx>, Option>), AllocId>, + pub(super) vtables: + FxHashMap<(Ty<'tcx>, Option>), Pointer>, } /// A stack frame. #[derive(Clone)] -pub struct Frame<'mir, 'tcx: 'mir, Tag=(), Extra=()> { +pub struct Frame<'mir, 'tcx, Tag=(), Extra=()> { //////////////////////////////////////////////////////////////////////////////// // Function and callsite information //////////////////////////////////////////////////////////////////////////////// /// The MIR for the function called on this frame. - pub mir: &'mir mir::Mir<'tcx>, + pub body: &'mir mir::Body<'tcx>, /// The def_id and substs of the current function. pub instance: ty::Instance<'tcx>, @@ -108,76 +109,95 @@ pub enum StackPopCleanup { /// State of a local variable including a memoized layout #[derive(Clone, PartialEq, Eq)] pub struct LocalState<'tcx, Tag=(), Id=AllocId> { - pub state: LocalValue, + pub value: LocalValue, /// Don't modify if `Some`, this is only used to prevent computing the layout twice pub layout: Cell>>, } -/// State of a local variable -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +/// Current value of a local variable +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum LocalValue { + /// This local is not currently alive, and cannot be used at all. Dead, - // Mostly for convenience, we re-use the `Operand` type here. - // This is an optimization over just always having a pointer here; - // we can thus avoid doing an allocation when the local just stores - // immediate values *and* never has its address taken. + /// This local is alive but not yet initialized. It can be written to + /// but not read from or its address taken. Locals get initialized on + /// first write because for unsized locals, we do not know their size + /// before that. + Uninitialized, + /// A normal, live local. + /// Mostly for convenience, we re-use the `Operand` type here. + /// This is an optimization over just always having a pointer here; + /// we can thus avoid doing an allocation when the local just stores + /// immediate values *and* never has its address taken. Live(Operand), } -impl<'tcx, Tag> LocalState<'tcx, Tag> { - pub fn access(&self) -> EvalResult<'tcx, &Operand> { - match self.state { +impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { + pub fn access(&self) -> InterpResult<'tcx, Operand> { + match self.value { LocalValue::Dead => err!(DeadLocal), - LocalValue::Live(ref val) => Ok(val), + LocalValue::Uninitialized => + bug!("The type checker should prevent reading from a never-written local"), + LocalValue::Live(val) => Ok(val), } } - pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand> { - match self.state { + /// Overwrite the local. If the local can be overwritten in place, return a reference + /// to do so; otherwise return the `MemPlace` to consult instead. + pub fn access_mut( + &mut self, + ) -> InterpResult<'tcx, Result<&mut LocalValue, MemPlace>> { + match self.value { LocalValue::Dead => err!(DeadLocal), - LocalValue::Live(ref mut val) => Ok(val), + LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)), + ref mut local @ LocalValue::Live(Operand::Immediate(_)) | + ref mut local @ LocalValue::Uninitialized => { + Ok(Ok(local)) + } } } } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> HasDataLayout - for EvalContext<'a, 'mir, 'tcx, M> -{ +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpretCx<'mir, 'tcx, M> { #[inline] fn data_layout(&self) -> &layout::TargetDataLayout { &self.tcx.data_layout } } -impl<'a, 'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for EvalContext<'a, 'mir, 'tcx, M> - where M: Machine<'a, 'mir, 'tcx> +impl<'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpretCx<'mir, 'tcx, M> +where + M: Machine<'mir, 'tcx>, { #[inline] - fn tcx<'d>(&'d self) -> TyCtxt<'d, 'tcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { *self.tcx } } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> LayoutOf - for EvalContext<'a, 'mir, 'tcx, M> +impl<'mir, 'tcx, M> layout::HasParamEnv<'tcx> for InterpretCx<'mir, 'tcx, M> +where + M: Machine<'mir, 'tcx>, { + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } +} + +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpretCx<'mir, 'tcx, M> { type Ty = Ty<'tcx>; - type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>; + type TyLayout = InterpResult<'tcx, TyLayout<'tcx>>; #[inline] fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout { self.tcx.layout_of(self.param_env.and(ty)) - .map_err(|layout| EvalErrorKind::Layout(layout).into()) + .map_err(|layout| InterpError::Layout(layout).into()) } } -impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { - pub fn new( - tcx: TyCtxtAt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - machine: M, - ) -> Self { - EvalContext { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> { + pub fn new(tcx: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>, machine: M) -> Self { + InterpretCx { machine, tcx, param_env, @@ -188,15 +208,20 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } #[inline(always)] - pub fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> { + pub fn memory(&self) -> &Memory<'mir, 'tcx, M> { &self.memory } #[inline(always)] - pub fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> { + pub fn memory_mut(&mut self) -> &mut Memory<'mir, 'tcx, M> { &mut self.memory } + #[inline(always)] + pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer { + self.memory.tag_static_base_pointer(ptr) + } + #[inline(always)] pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] { &self.stack @@ -219,14 +244,14 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } #[inline(always)] - pub(super) fn mir(&self) -> &'mir mir::Mir<'tcx> { - self.frame().mir + pub(super) fn body(&self) -> &'mir mir::Body<'tcx> { + self.frame().body } pub(super) fn subst_and_normalize_erasing_regions>( &self, substs: T, - ) -> EvalResult<'tcx, T> { + ) -> InterpResult<'tcx, T> { match self.stack.last() { Some(frame) => Ok(self.tcx.subst_and_normalize_erasing_regions( frame.instance.substs, @@ -245,7 +270,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc &self, def_id: DefId, substs: SubstsRef<'tcx> - ) -> EvalResult<'tcx, ty::Instance<'tcx>> { + ) -> InterpResult<'tcx, ty::Instance<'tcx>> { trace!("resolve: {:?}, {:#?}", def_id, substs); trace!("param_env: {:#?}", self.param_env); let substs = self.subst_and_normalize_erasing_regions(substs)?; @@ -255,7 +280,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc self.param_env, def_id, substs, - ).ok_or_else(|| EvalErrorKind::TooGeneric.into()) + ).ok_or_else(|| InterpError::TooGeneric.into()) } pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { @@ -269,7 +294,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc pub fn load_mir( &self, instance: ty::InstanceDef<'tcx>, - ) -> EvalResult<'tcx, &'tcx mir::Mir<'tcx>> { + ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { // do not continue if typeck errors occurred (can only occur in local crate) let did = instance.def_id(); if did.is_local() @@ -283,7 +308,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc ty::InstanceDef::Item(def_id) => if self.tcx.is_mir_available(did) { Ok(self.tcx.optimized_mir(did)) } else { - err!(NoMirFor(self.tcx.item_path_str(def_id))) + err!(NoMirFor(self.tcx.def_path_str(def_id))) }, _ => Ok(self.tcx.instance_mir(instance)), } @@ -292,9 +317,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc pub(super) fn monomorphize + Subst<'tcx>>( &self, t: T, - ) -> EvalResult<'tcx, T> { + ) -> InterpResult<'tcx, T> { match self.stack.last() { - Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)), + Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)?), None => if t.needs_subst() { err!(TooGeneric).into() } else { @@ -307,11 +332,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc &self, t: T, substs: SubstsRef<'tcx> - ) -> T { + ) -> InterpResult<'tcx, T> { // miri doesn't care about lifetimes, and will choke on some crazy ones // let's simply get rid of them let substituted = t.subst(*self.tcx, substs); - self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted) + + if substituted.needs_subst() { + return err!(TooGeneric); + } + + Ok(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted)) } pub fn layout_of_local( @@ -319,14 +349,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, local: mir::Local, layout: Option>, - ) -> EvalResult<'tcx, TyLayout<'tcx>> { + ) -> InterpResult<'tcx, TyLayout<'tcx>> { match frame.locals[local].layout.get() { None => { let layout = crate::interpret::operand::from_known_layout(layout, || { - let local_ty = frame.mir.local_decls[local].ty; - let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs); + let local_ty = frame.body.local_decls[local].ty; + let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs)?; self.layout_of(local_ty) })?; + // Layouts of locals are requested a lot, so we cache them. frame.locals[local].layout.set(Some(layout)); Ok(layout) } @@ -334,11 +365,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } } - pub fn str_to_immediate(&mut self, s: &str) -> EvalResult<'tcx, Immediate> { - let ptr = self.memory.allocate_static_bytes(s.as_bytes()).with_default_tag(); - Ok(Immediate::new_slice(Scalar::Ptr(ptr), s.len() as u64, self)) - } - /// Returns the actual dynamic size and alignment of the place at the given type. /// Only the "meta" (metadata) part of the place matters. /// This can fail to provide an answer for extern types. @@ -346,7 +372,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc &self, metadata: Option>, layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, Option<(Size, Align)>> { + ) -> InterpResult<'tcx, Option<(Size, Align)>> { if !layout.is_unsized() { return Ok(Some((layout.size, layout.align.abi))); } @@ -416,7 +442,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc Ok(Some((size.align_to(align), align))) } ty::Dynamic(..) => { - let vtable = metadata.expect("dyn trait fat ptr must have vtable").to_ptr()?; + let vtable = metadata.expect("dyn trait fat ptr must have vtable"); // the second entry in the vtable is the dynamic size of the object. Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) } @@ -438,7 +464,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc pub fn size_and_align_of_mplace( &self, mplace: MPlaceTy<'tcx, M::PointerTag> - ) -> EvalResult<'tcx, Option<(Size, Align)>> { + ) -> InterpResult<'tcx, Option<(Size, Align)>> { self.size_and_align_of(mplace.meta, mplace.layout) } @@ -446,11 +472,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc &mut self, instance: ty::Instance<'tcx>, span: source_map::Span, - mir: &'mir mir::Mir<'tcx>, + body: &'mir mir::Body<'tcx>, return_place: Option>, return_to_block: StackPopCleanup, - ) -> EvalResult<'tcx> { - if self.stack.len() > 1 { // FIXME should be "> 0", printing topmost frame crashes rustc... + ) -> InterpResult<'tcx> { + if self.stack.len() > 0 { info!("PAUSING({}) {}", self.cur_frame(), self.frame().instance); } ::log_settings::settings().indentation += 1; @@ -458,7 +484,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc // first push a stack frame so we have access to the local substs let extra = M::stack_push(self)?; self.stack.push(Frame { - mir, + body, block: mir::START_BLOCK, return_to_block, return_place, @@ -472,33 +498,31 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc }); // don't allocate at all for trivial constants - if mir.local_decls.len() > 1 { - // We put some marker immediate into the locals that we later want to initialize. - // This can be anything except for LocalValue::Dead -- because *that* is the - // value we use for things that we know are initially dead. + if body.local_decls.len() > 1 { + // Locals are initially uninitialized. let dummy = LocalState { - state: LocalValue::Live(Operand::Immediate(Immediate::Scalar( - ScalarMaybeUndef::Undef, - ))), + value: LocalValue::Uninitialized, layout: Cell::new(None), }; - let mut locals = IndexVec::from_elem(dummy, &mir.local_decls); + let mut locals = IndexVec::from_elem(dummy, &body.local_decls); // Return place is handled specially by the `eval_place` functions, and the // entry in `locals` should never be used. Make it dead, to be sure. - locals[mir::RETURN_PLACE].state = LocalValue::Dead; + locals[mir::RETURN_PLACE].value = LocalValue::Dead; // Now mark those locals as dead that we do not want to initialize - match self.tcx.describe_def(instance.def_id()) { + match self.tcx.def_kind(instance.def_id()) { // statics and constants don't have `Storage*` statements, no need to look for them - Some(Def::Static(..)) | Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {}, + Some(DefKind::Static) + | Some(DefKind::Const) + | Some(DefKind::AssocConst) => {}, _ => { - trace!("push_stack_frame: {:?}: num_bbs: {}", span, mir.basic_blocks().len()); - for block in mir.basic_blocks() { + trace!("push_stack_frame: {:?}: num_bbs: {}", span, body.basic_blocks().len()); + for block in body.basic_blocks() { for stmt in block.statements.iter() { use rustc::mir::StatementKind::{StorageDead, StorageLive}; match stmt.kind { StorageLive(local) | StorageDead(local) => { - locals[local].state = LocalValue::Dead; + locals[local].value = LocalValue::Dead; } _ => {} } @@ -506,28 +530,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } }, } - // Finally, properly initialize all those that still have the dummy value - for (idx, local) in locals.iter_enumerated_mut() { - match local.state { - LocalValue::Live(_) => { - // This needs to be properly initialized. - let ty = self.monomorphize(mir.local_decls[idx].ty)?; - let layout = self.layout_of(ty)?; - local.state = LocalValue::Live(self.uninit_operand(layout)?); - local.layout = Cell::new(Some(layout)); - } - LocalValue::Dead => { - // Nothing to do - } - } - } // done self.frame_mut().locals = locals; } - if self.stack.len() > 1 { // FIXME no check should be needed, but some instances ICE - info!("ENTERING({}) {}", self.cur_frame(), self.frame().instance); - } + info!("ENTERING({}) {}", self.cur_frame(), self.frame().instance); if self.stack.len() > self.tcx.sess.const_eval_stack_frame_limit { err!(StackFrameLimitReached) @@ -536,10 +543,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } } - pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> { - if self.stack.len() > 1 { // FIXME no check should be needed, but some instances ICE - info!("LEAVING({}) {}", self.cur_frame(), self.frame().instance); - } + pub(super) fn pop_stack_frame(&mut self) -> InterpResult<'tcx> { + info!("LEAVING({}) {}", self.cur_frame(), self.frame().instance); ::log_settings::settings().indentation -= 1; let frame = self.stack.pop().expect( "tried to pop a stack frame, but there were none", @@ -559,7 +564,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } // Deallocate all locals that are backed by an allocation. for local in frame.locals { - self.deallocate_local(local.state)?; + self.deallocate_local(local.value)?; } // Validate the return value. Do this after deallocating so that we catch dangling // references. @@ -576,7 +581,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc self.place_to_op(return_place)?, vec![], None, - /*const_mode*/false, )?; } } else { @@ -591,7 +595,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc StackPopCleanup::None { .. } => {} } - if self.stack.len() > 1 { // FIXME should be "> 0", printing topmost frame crashes rustc... + if self.stack.len() > 0 { info!("CONTINUING({}) {}", self.cur_frame(), self.frame().instance); } @@ -603,14 +607,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc pub fn storage_live( &mut self, local: mir::Local - ) -> EvalResult<'tcx, LocalValue> { + ) -> InterpResult<'tcx, LocalValue> { assert!(local != mir::RETURN_PLACE, "Cannot make return place live"); trace!("{:?} is now live", local); - let layout = self.layout_of_local(self.frame(), local, None)?; - let init = LocalValue::Live(self.uninit_operand(layout)?); - // StorageLive *always* kills the value that's currently stored - Ok(mem::replace(&mut self.frame_mut().locals[local].state, init)) + let local_val = LocalValue::Uninitialized; + // StorageLive *always* kills the value that's currently stored. + // However, we do not error if the variable already is live; + // see . + Ok(mem::replace(&mut self.frame_mut().locals[local].value, local_val)) } /// Returns the old value of the local. @@ -619,13 +624,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc assert!(local != mir::RETURN_PLACE, "Cannot make return place dead"); trace!("{:?} is now dead", local); - mem::replace(&mut self.frame_mut().locals[local].state, LocalValue::Dead) + mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead) } pub(super) fn deallocate_local( &mut self, local: LocalValue, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { // FIXME: should we tell the user that there was a local which was never written to? if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local { trace!("deallocating local"); @@ -639,8 +644,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc pub fn const_eval_raw( &self, gid: GlobalId<'tcx>, - ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - let param_env = if self.tcx.is_static(gid.instance.def_id()).is_some() { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + // FIXME(oli-obk): make this check an assertion that it's not a static here + // FIXME(RalfJ, oli-obk): document that `Place::Static` can never be anything but a static + // and `ConstValue::Unevaluated` can never be a static + let param_env = if self.tcx.is_static(gid.instance.def_id()) { ty::ParamEnv::reveal_all() } else { self.param_env @@ -651,8 +659,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles. let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| { match err { - ErrorHandled::Reported => EvalErrorKind::ReferencedConstant, - ErrorHandled::TooGeneric => EvalErrorKind::TooGeneric, + ErrorHandled::Reported => InterpError::ReferencedConstant, + ErrorHandled::TooGeneric => InterpError::TooGeneric, } })?; self.raw_const_to_mplace(val) @@ -672,31 +680,31 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } write!(msg, ":").unwrap(); - match self.stack[frame].locals[local].access() { - Err(err) => { - if let EvalErrorKind::DeadLocal = err.kind { - write!(msg, " is dead").unwrap(); - } else { - panic!("Failed to access local: {:?}", err); - } - } - Ok(Operand::Indirect(mplace)) => { - let (ptr, align) = mplace.to_scalar_ptr_align(); - match ptr { + match self.stack[frame].locals[local].value { + LocalValue::Dead => write!(msg, " is dead").unwrap(), + LocalValue::Uninitialized => write!(msg, " is uninitialized").unwrap(), + LocalValue::Live(Operand::Indirect(mplace)) => { + match mplace.ptr { Scalar::Ptr(ptr) => { - write!(msg, " by align({}) ref:", align.bytes()).unwrap(); + write!(msg, " by align({}){} ref:", + mplace.align.bytes(), + match mplace.meta { + Some(meta) => format!(" meta({:?})", meta), + None => String::new() + } + ).unwrap(); allocs.push(ptr.alloc_id); } ptr => write!(msg, " by integral ref: {:?}", ptr).unwrap(), } } - Ok(Operand::Immediate(Immediate::Scalar(val))) => { + LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => { write!(msg, " {:?}", val).unwrap(); if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val { allocs.push(ptr.alloc_id); } } - Ok(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => { + LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => { write!(msg, " ({:?}, {:?})", val1, val2).unwrap(); if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val1 { allocs.push(ptr.alloc_id); @@ -725,7 +733,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc pub fn generate_stacktrace(&self, explicit_span: Option) -> Vec> { let mut last_span = None; let mut frames = Vec::new(); - for &Frame { instance, span, mir, block, stmt, .. } in self.stack().iter().rev() { + for &Frame { instance, span, body, block, stmt, .. } in self.stack().iter().rev() { // make sure we don't emit frames that are duplicates of the previous if explicit_span == Some(span) { last_span = Some(span); @@ -738,13 +746,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } else { last_span = Some(span); } - let block = &mir.basic_blocks()[block]; + let block = &body.basic_blocks()[block]; let source_info = if stmt < block.statements.len() { block.statements[stmt].source_info } else { block.terminator().source_info }; - let lint_root = match mir.source_scope_local_data { + let lint_root = match body.source_scope_local_data { mir::ClearCrossCrate::Set(ref ivs) => Some(ivs[source_info.scope].lint_root), mir::ClearCrossCrate::Clear => None, }; @@ -764,4 +772,21 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc pub fn truncate(&self, value: u128, ty: TyLayout<'_>) -> u128 { truncate(value, ty.size) } + + #[inline(always)] + pub fn force_ptr( + &self, + scalar: Scalar, + ) -> InterpResult<'tcx, Pointer> { + self.memory.force_ptr(scalar) + } + + #[inline(always)] + pub fn force_bits( + &self, + scalar: Scalar, + size: Size + ) -> InterpResult<'tcx, u128> { + self.memory.force_bits(scalar, size) + } } diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs new file mode 100644 index 0000000000000..f0d64e217a28f --- /dev/null +++ b/src/librustc_mir/interpret/intern.rs @@ -0,0 +1,335 @@ +//! This module specifies the type based interner for constants. +//! +//! After a const evaluation has computed a value, before we destroy the const evaluator's session +//! memory, we need to extract all memory allocations to the global memory pool so they stay around. + +use rustc::ty::{Ty, TyCtxt, ParamEnv, self}; +use rustc::mir::interpret::{ + InterpResult, ErrorHandled, +}; +use rustc::hir; +use rustc::hir::def_id::DefId; +use super::validity::RefTracking; +use rustc_data_structures::fx::FxHashSet; + +use syntax::ast::Mutability; +use syntax_pos::Span; + +use super::{ + ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, InterpError, Scalar, +}; +use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext}; + +struct InternVisitor<'rt, 'mir, 'tcx> { + /// previously encountered safe references + ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>, + ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>, + param_env: ParamEnv<'tcx>, + /// The root node of the value that we're looking at. This field is never mutated and only used + /// for sanity assertions that will ICE when `const_qualif` screws up. + mode: InternMode, + /// This field stores the mutability of the value *currently* being checked. + /// It is set to mutable when an `UnsafeCell` is encountered + /// When recursing across a reference, we don't recurse but store the + /// value to be checked in `ref_tracking` together with the mutability at which we are checking + /// the value. + /// When encountering an immutable reference, we treat everything as immutable that is behind + /// it. + mutability: Mutability, + /// A list of all encountered relocations. After type-based interning, we traverse this list to + /// also intern allocations that are only referenced by a raw pointer or inside a union. + leftover_relocations: &'rt mut FxHashSet, +} + +#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)] +enum InternMode { + /// Mutable references must in fact be immutable due to their surrounding immutability in a + /// `static`. In a `static mut` we start out as mutable and thus can also contain further `&mut` + /// that will actually be treated as mutable. + Static, + /// UnsafeCell is OK in the value of a constant, but not behind references in a constant + ConstBase, + /// `UnsafeCell` ICEs + Const, +} + +/// Signalling data structure to ensure we don't recurse +/// into the memory of other constants or statics +struct IsStaticOrFn; + +impl<'rt, 'mir, 'tcx> InternVisitor<'rt, 'mir, 'tcx> { + /// Intern an allocation without looking at its children + fn intern_shallow( + &mut self, + ptr: Pointer, + mutability: Mutability, + ) -> InterpResult<'tcx, Option> { + trace!( + "InternVisitor::intern {:?} with {:?}", + ptr, mutability, + ); + // remove allocation + let tcx = self.ecx.tcx; + let memory = self.ecx.memory_mut(); + let (kind, mut alloc) = match memory.alloc_map.remove(&ptr.alloc_id) { + Some(entry) => entry, + None => { + // if the pointer is dangling (neither in local nor global memory), we leave it + // to validation to error. The `delay_span_bug` ensures that we don't forget such + // a check in validation. + if tcx.alloc_map.lock().get(ptr.alloc_id).is_none() { + tcx.sess.delay_span_bug(self.ecx.tcx.span, "tried to intern dangling pointer"); + } + // treat dangling pointers like other statics + // just to stop trying to recurse into them + return Ok(Some(IsStaticOrFn)); + }, + }; + // This match is just a canary for future changes to `MemoryKind`, which most likely need + // changes in this function. + match kind { + MemoryKind::Stack | MemoryKind::Vtable => {}, + } + // Ensure llvm knows to only put this into immutable memory if the value is immutable either + // by being behind a reference or by being part of a static or const without interior + // mutability + alloc.mutability = mutability; + // link the alloc id to the actual allocation + let alloc = tcx.intern_const_alloc(alloc); + self.leftover_relocations.extend(alloc.relocations.iter().map(|&(_, ((), reloc))| reloc)); + tcx.alloc_map.lock().set_alloc_id_memory(ptr.alloc_id, alloc); + Ok(None) + } +} + +impl<'rt, 'mir, 'tcx> + ValueVisitor<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> +for + InternVisitor<'rt, 'mir, 'tcx> +{ + type V = MPlaceTy<'tcx>; + + #[inline(always)] + fn ecx(&self) -> &CompileTimeEvalContext<'mir, 'tcx> { + &self.ecx + } + + fn visit_aggregate( + &mut self, + mplace: MPlaceTy<'tcx>, + fields: impl Iterator>, + ) -> InterpResult<'tcx> { + if let Some(def) = mplace.layout.ty.ty_adt_def() { + if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() { + // We are crossing over an `UnsafeCell`, we can mutate again + let old = std::mem::replace(&mut self.mutability, Mutability::Mutable); + assert_ne!( + self.mode, InternMode::Const, + "UnsafeCells are not allowed behind references in constants. This should have \ + been prevented statically by const qualification. If this were allowed one \ + would be able to change a constant at one use site and other use sites may \ + arbitrarily decide to change, too.", + ); + let walked = self.walk_aggregate(mplace, fields); + self.mutability = old; + return walked; + } + } + self.walk_aggregate(mplace, fields) + } + + fn visit_primitive(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> { + // Handle Reference types, as these are the only relocations supported by const eval. + // Raw pointers (and boxes) are handled by the `leftover_relocations` logic. + let ty = mplace.layout.ty; + if let ty::Ref(_, referenced_ty, mutability) = ty.sty { + let value = self.ecx.read_immediate(mplace.into())?; + // Handle trait object vtables + if let Ok(meta) = value.to_meta() { + if let ty::Dynamic(..) = self.ecx.tcx.struct_tail(referenced_ty).sty { + if let Ok(vtable) = meta.unwrap().to_ptr() { + // explitly choose `Immutable` here, since vtables are immutable, even + // if the reference of the fat pointer is mutable + self.intern_shallow(vtable, Mutability::Immutable)?; + } + } + } + let mplace = self.ecx.ref_to_mplace(value)?; + // Check if we have encountered this pointer+layout combination before. + // Only recurse for allocation-backed pointers. + if let Scalar::Ptr(ptr) = mplace.ptr { + // We do not have any `frozen` logic here, because it's essentially equivalent to + // the mutability except for the outermost item. Only `UnsafeCell` can "unfreeze", + // and we check that in `visit_aggregate`. + // This is not an inherent limitation, but one that we know to be true, because + // const qualification enforces it. We can lift it in the future. + match (self.mode, mutability) { + // immutable references are fine everywhere + (_, hir::Mutability::MutImmutable) => {}, + // all is "good and well" in the unsoundness of `static mut` + + // mutable references are ok in `static`. Either they are treated as immutable + // because they are behind an immutable one, or they are behind an `UnsafeCell` + // and thus ok. + (InternMode::Static, hir::Mutability::MutMutable) => {}, + // we statically prevent `&mut T` via `const_qualif` and double check this here + (InternMode::ConstBase, hir::Mutability::MutMutable) | + (InternMode::Const, hir::Mutability::MutMutable) => { + match referenced_ty.sty { + ty::Array(_, n) if n.unwrap_usize(self.ecx.tcx.tcx) == 0 => {} + ty::Slice(_) + if value.to_meta().unwrap().unwrap().to_usize(self.ecx)? == 0 => {} + _ => bug!("const qualif failed to prevent mutable references"), + } + }, + } + // Compute the mutability with which we'll start visiting the allocation. This is + // what gets changed when we encounter an `UnsafeCell` + let mutability = match (self.mutability, mutability) { + // The only way a mutable reference actually works as a mutable reference is + // by being in a `static mut` directly or behind another mutable reference. + // If there's an immutable reference or we are inside a static, then our + // mutable reference is equivalent to an immutable one. As an example: + // `&&mut Foo` is semantically equivalent to `&&Foo` + (Mutability::Mutable, hir::Mutability::MutMutable) => Mutability::Mutable, + _ => Mutability::Immutable, + }; + // Compute the mutability of the allocation + let intern_mutability = intern_mutability( + self.ecx.tcx.tcx, + self.param_env, + mplace.layout.ty, + self.ecx.tcx.span, + mutability, + ); + // Recursing behind references changes the intern mode for constants in order to + // cause assertions to trigger if we encounter any `UnsafeCell`s. + let mode = match self.mode { + InternMode::ConstBase => InternMode::Const, + other => other, + }; + match self.intern_shallow(ptr, intern_mutability)? { + // No need to recurse, these are interned already and statics may have + // cycles, so we don't want to recurse there + Some(IsStaticOrFn) => {}, + // intern everything referenced by this value. The mutability is taken from the + // reference. It is checked above that mutable references only happen in + // `static mut` + None => self.ref_tracking.track((mplace, mutability, mode), || ()), + } + } + } + Ok(()) + } +} + +/// Figure out the mutability of the allocation. +/// Mutable if it has interior mutability *anywhere* in the type. +fn intern_mutability<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ty: Ty<'tcx>, + span: Span, + mutability: Mutability, +) -> Mutability { + let has_interior_mutability = !ty.is_freeze(tcx, param_env, span); + if has_interior_mutability { + Mutability::Mutable + } else { + mutability + } +} + +pub fn intern_const_alloc_recursive( + ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, + def_id: DefId, + ret: MPlaceTy<'tcx>, + // FIXME(oli-obk): can we scrap the param env? I think we can, the final value of a const eval + // must always be monomorphic, right? + param_env: ty::ParamEnv<'tcx>, +) -> InterpResult<'tcx> { + let tcx = ecx.tcx; + // this `mutability` is the mutability of the place, ignoring the type + let (mutability, base_intern_mode) = match tcx.static_mutability(def_id) { + Some(hir::Mutability::MutImmutable) => (Mutability::Immutable, InternMode::Static), + None => (Mutability::Immutable, InternMode::ConstBase), + // `static mut` doesn't care about interior mutability, it's mutable anyway + Some(hir::Mutability::MutMutable) => (Mutability::Mutable, InternMode::Static), + }; + + // type based interning + let mut ref_tracking = RefTracking::new((ret, mutability, base_intern_mode)); + let leftover_relocations = &mut FxHashSet::default(); + + // This mutability is the combination of the place mutability and the type mutability. If either + // is mutable, `alloc_mutability` is mutable. This exists because the entire allocation needs + // to be mutable if it contains an `UnsafeCell` anywhere. The other `mutability` exists so that + // the visitor does not treat everything outside the `UnsafeCell` as mutable. + let alloc_mutability = intern_mutability( + tcx.tcx, param_env, ret.layout.ty, tcx.span, mutability, + ); + + // start with the outermost allocation + InternVisitor { + ref_tracking: &mut ref_tracking, + ecx, + mode: base_intern_mode, + leftover_relocations, + param_env, + mutability, + }.intern_shallow(ret.ptr.to_ptr()?, alloc_mutability)?; + + while let Some(((mplace, mutability, mode), _)) = ref_tracking.todo.pop() { + let interned = InternVisitor { + ref_tracking: &mut ref_tracking, + ecx, + mode, + leftover_relocations, + param_env, + mutability, + }.visit_value(mplace); + if let Err(error) = interned { + // This can happen when e.g. the tag of an enum is not a valid discriminant. We do have + // to read enum discriminants in order to find references in enum variant fields. + if let InterpError::ValidationFailure(_) = error.kind { + let err = crate::const_eval::error_to_const_error(&ecx, error); + match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") { + Ok(mut diag) => { + diag.note("The rules on what exactly is undefined behavior aren't clear, \ + so this check might be overzealous. Please open an issue on the rust \ + compiler repository if you believe it should not be considered \ + undefined behavior", + ); + diag.emit(); + } + Err(ErrorHandled::TooGeneric) | + Err(ErrorHandled::Reported) => {}, + } + } + } + } + + // Intern the rest of the allocations as mutable. These might be inside unions, padding, raw + // pointers, ... So we can't intern them according to their type rules + + let mut todo: Vec<_> = leftover_relocations.iter().cloned().collect(); + while let Some(alloc_id) = todo.pop() { + if let Some((_, alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) { + // We can't call the `intern` method here, as its logic is tailored to safe references. + // So we hand-roll the interning logic here again + let alloc = tcx.intern_const_alloc(alloc); + tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc); + for &(_, ((), reloc)) in alloc.relocations.iter() { + if leftover_relocations.insert(reloc) { + todo.push(reloc); + } + } + } else if ecx.memory().dead_alloc_map.contains_key(&alloc_id) { + // dangling pointer + return err!(ValidationFailure( + "encountered dangling pointer in final constant".into(), + )) + } + } + Ok(()) +} diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index e002c3fd511d6..beb5049307117 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -7,19 +7,22 @@ use rustc::ty; use rustc::ty::layout::{LayoutOf, Primitive, Size}; use rustc::mir::BinOp; use rustc::mir::interpret::{ - EvalResult, EvalErrorKind, Scalar, + InterpResult, InterpError, Scalar, }; use super::{ - Machine, PlaceTy, OpTy, EvalContext, + Machine, PlaceTy, OpTy, InterpretCx, Immediate, }; +mod type_name; + +pub use type_name::*; fn numeric_intrinsic<'tcx, Tag>( name: &str, bits: u128, kind: Primitive, -) -> EvalResult<'tcx, Scalar> { +) -> InterpResult<'tcx, Scalar> { let size = match kind { Primitive::Int(integer, _) => integer.size(), _ => bug!("invalid `{}` argument: {:?}", name, bits), @@ -36,14 +39,14 @@ fn numeric_intrinsic<'tcx, Tag>( Ok(Scalar::from_uint(bits_out, size)) } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> { /// Returns `true` if emulation happened. pub fn emulate_intrinsic( &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, M::PointerTag>], dest: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, bool> { + ) -> InterpResult<'tcx, bool> { let substs = instance.substs; let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; @@ -75,6 +78,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let id_val = Scalar::from_uint(type_id, dest.layout.size); self.write_scalar(id_val, dest)?; } + + "type_name" => { + let alloc = alloc_type_name(self.tcx.tcx, substs.type_at(0)); + let name_id = self.tcx.alloc_map.lock().create_memory_alloc(alloc); + let id_ptr = self.memory.tag_static_base_pointer(name_id.into()); + let alloc_len = alloc.bytes.len() as u64; + let name_val = Immediate::new_slice(Scalar::Ptr(id_ptr), alloc_len, self); + self.write_immediate(name_val, dest)?; + } + | "ctpop" | "cttz" | "cttz_nonzero" @@ -87,7 +100,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?; let kind = match layout_of.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?, + _ => Err(::rustc::mir::interpret::InterpError::TypeNotPrimitive(ty))?, }; let out_val = if intrinsic_name.ends_with("_nonzero") { if bits == 0 { @@ -191,7 +204,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let raw_shift_bits = self.read_scalar(args[1])?.to_bits(layout.size)?; let width_bits = layout.size.bits() as u128; let shift_bits = raw_shift_bits % width_bits; - let inv_shift_bits = (width_bits - raw_shift_bits) % width_bits; + let inv_shift_bits = (width_bits - shift_bits) % width_bits; let result_bits = if intrinsic_name == "rotate_left" { (val_bits << shift_bits) | (val_bits >> inv_shift_bits) } else { @@ -218,7 +231,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, M::PointerTag>], dest: Option>, - ) -> EvalResult<'tcx, bool> { + ) -> InterpResult<'tcx, bool> { let def_id = instance.def_id(); // Some fn calls are actually BinOp intrinsics if let Some((op, oflo)) = self.tcx.is_binop_lang_item(def_id) { @@ -248,7 +261,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let file = Symbol::intern(self.read_str(file_place)?); let line = self.read_scalar(line.into())?.to_u32()?; let col = self.read_scalar(col.into())?.to_u32()?; - return Err(EvalErrorKind::Panic { msg, file, line, col }.into()); + return Err(InterpError::Panic { msg, file, line, col }.into()); } else if Some(def_id) == self.tcx.lang_items().begin_panic_fn() { assert!(args.len() == 2); // &'static str, &(&'static str, u32, u32) @@ -266,7 +279,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let file = Symbol::intern(self.read_str(file_place)?); let line = self.read_scalar(line.into())?.to_u32()?; let col = self.read_scalar(col.into())?.to_u32()?; - return Err(EvalErrorKind::Panic { msg, file, line, col }.into()); + return Err(InterpError::Panic { msg, file, line, col }.into()); } else { return Ok(false); } diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/src/librustc_mir/interpret/intrinsics/type_name.rs new file mode 100644 index 0000000000000..f207cfc6b39cd --- /dev/null +++ b/src/librustc_mir/interpret/intrinsics/type_name.rs @@ -0,0 +1,235 @@ +use rustc::ty::{ + TyCtxt, Ty, + subst::{UnpackedKind, Kind}, + print::{Printer, PrettyPrinter, Print}, + self, +}; +use rustc::hir::map::{DefPathData, DisambiguatedDefPathData}; +use rustc::hir::def_id::CrateNum; +use std::fmt::Write; +use rustc::mir::interpret::{Allocation, ConstValue}; + +struct AbsolutePathPrinter<'tcx> { + tcx: TyCtxt<'tcx>, + path: String, +} + +impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { + type Error = std::fmt::Error; + + type Path = Self; + type Region = Self; + type Type = Self; + type DynExistential = Self; + type Const = Self; + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn print_region(self, _region: ty::Region<'_>) -> Result { + Ok(self) + } + + fn print_type(mut self, ty: Ty<'tcx>) -> Result { + match ty.sty { + // Types without identity. + | ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnPtr(_) + | ty::Never + | ty::Tuple(_) + | ty::Dynamic(_, _) + => self.pretty_print_type(ty), + + // Placeholders (all printed as `_` to uniformize them). + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(_) + | ty::Error + => { + write!(self, "_")?; + Ok(self) + } + + // Types with identity (print the module path). + | ty::Adt(&ty::AdtDef { did: def_id, .. }, substs) + | ty::FnDef(def_id, substs) + | ty::Opaque(def_id, substs) + | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) + | ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) + | ty::Closure(def_id, ty::ClosureSubsts { substs }) + | ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) + => self.print_def_path(def_id, substs), + ty::Foreign(def_id) => self.print_def_path(def_id, &[]), + + ty::GeneratorWitness(_) => { + bug!("type_name: unexpected `GeneratorWitness`") + } + } + } + + fn print_const( + self, + _: &'tcx ty::Const<'tcx>, + ) -> Result { + // don't print constants to the user + Ok(self) + } + + fn print_dyn_existential( + mut self, + predicates: &'tcx ty::List>, + ) -> Result { + let mut first = true; + for p in predicates { + if !first { + write!(self, "+")?; + } + first = false; + self = p.print(self)?; + } + Ok(self) + } + + fn path_crate(mut self, cnum: CrateNum) -> Result { + self.path.push_str(&self.tcx.original_crate_name(cnum).as_str()); + Ok(self) + } + + fn path_qualified( + self, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + self.pretty_path_qualified(self_ty, trait_ref) + } + + fn path_append_impl( + self, + print_prefix: impl FnOnce(Self) -> Result, + _disambiguated_data: &DisambiguatedDefPathData, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + self.pretty_path_append_impl( + |mut cx| { + cx = print_prefix(cx)?; + + cx.path.push_str("::"); + + Ok(cx) + }, + self_ty, + trait_ref, + ) + } + + fn path_append( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + disambiguated_data: &DisambiguatedDefPathData, + ) -> Result { + self = print_prefix(self)?; + + // Skip `::{{constructor}}` on tuple/unit structs. + match disambiguated_data.data { + DefPathData::Ctor => return Ok(self), + _ => {} + } + + self.path.push_str("::"); + + self.path.push_str(&disambiguated_data.data.as_interned_str().as_str()); + Ok(self) + } + + fn path_generic_args( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + args: &[Kind<'tcx>], + ) -> Result { + self = print_prefix(self)?; + let args = args.iter().cloned().filter(|arg| { + match arg.unpack() { + UnpackedKind::Lifetime(_) => false, + _ => true, + } + }); + if args.clone().next().is_some() { + self.generic_delimiters(|cx| cx.comma_sep(args)) + } else { + Ok(self) + } + } +} +impl PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> { + fn region_should_not_be_omitted( + &self, + _region: ty::Region<'_>, + ) -> bool { + false + } + fn comma_sep(mut self, mut elems: impl Iterator) -> Result + where + T: Print<'tcx, Self, Output = Self, Error = Self::Error>, + { + if let Some(first) = elems.next() { + self = first.print(self)?; + for elem in elems { + self.path.push_str(", "); + self = elem.print(self)?; + } + } + Ok(self) + } + + fn generic_delimiters( + mut self, + f: impl FnOnce(Self) -> Result, + ) -> Result { + write!(self, "<")?; + + self = f(self)?; + + write!(self, ">")?; + + Ok(self) + } +} + +impl Write for AbsolutePathPrinter<'_> { + fn write_str(&mut self, s: &str) -> std::fmt::Result { + Ok(self.path.push_str(s)) + } +} + +/// Produces an absolute path representation of the given type. See also the documentation on +/// `std::any::type_name` +pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> { + let alloc = alloc_type_name(tcx, ty); + tcx.mk_const(ty::Const { + val: ConstValue::Slice { + data: alloc, + start: 0, + end: alloc.bytes.len(), + }, + ty: tcx.mk_static_str(), + }) +} + +/// Directly returns an `Allocation` containing an absolute path representation of the given type. +pub(super) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation { + let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path; + let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes()); + tcx.intern_const_alloc(alloc) +} diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 7fb4c47d92acb..91263932ccd98 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -5,13 +5,13 @@ use std::borrow::{Borrow, Cow}; use std::hash::Hash; -use rustc::hir::{self, def_id::DefId}; +use rustc::hir::def_id::DefId; use rustc::mir; use rustc::ty::{self, query::TyCtxtAt}; use super::{ - Allocation, AllocId, EvalResult, Scalar, AllocationExtra, - EvalContext, PlaceTy, MPlaceTy, OpTy, ImmTy, Pointer, MemoryKind, + Allocation, AllocId, InterpResult, Scalar, AllocationExtra, + InterpretCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory }; /// Whether this kind of memory is allowed to leak @@ -54,18 +54,23 @@ pub trait AllocMap { k: K, vacant: impl FnOnce() -> Result ) -> Result<&mut V, E>; + + /// Read-only lookup. + fn get(&self, k: K) -> Option<&V> { + self.get_or(k, || Err(())).ok() + } } /// Methods of this trait signifies a point where CTFE evaluation would fail /// and some use case dependent behaviour can instead be applied. -pub trait Machine<'a, 'mir, 'tcx>: Sized { +pub trait Machine<'mir, 'tcx>: Sized { /// Additional memory kinds a machine wishes to distinguish from the builtin ones type MemoryKinds: ::std::fmt::Debug + MayLeak + Eq + 'static; /// Tag tracked alongside every pointer. This is used to implement "Stacked Borrows" /// . /// The `default()` is used for pointers to consts, statics, vtables and functions. - type PointerTag: ::std::fmt::Debug + Default + Copy + Eq + Hash + 'static; + type PointerTag: ::std::fmt::Debug + Copy + Eq + Hash + 'static; /// Extra data stored in every call frame. type FrameExtra; @@ -76,7 +81,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { type MemoryExtra: Default; /// Extra data stored in every allocation. - type AllocExtra: AllocationExtra + 'static; + type AllocExtra: AllocationExtra + 'static; /// Memory's allocation map type MemoryMap: @@ -90,16 +95,16 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { /// The memory kind to use for copied statics -- or None if statics should not be mutated /// and thus any such attempt will cause a `ModifiedStatic` error to be raised. /// Statics are copied under two circumstances: When they are mutated, and when - /// `static_with_default_tag` or `find_foreign_static` (see below) returns an owned allocation + /// `tag_allocation` or `find_foreign_static` (see below) returns an owned allocation /// that is added to the memory so that the work is not done twice. const STATIC_KIND: Option; /// Whether to enforce the validity invariant - fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool; + fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool; /// Called before a basic block terminator is executed. /// You can use this to detect endlessly running programs. - fn before_terminator(ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>; + fn before_terminator(ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>; /// Entry point to all function calls. /// @@ -112,99 +117,118 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them /// was used. fn find_fn( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Self::PointerTag>], dest: Option>, ret: Option, - ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>; + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>; /// Directly process an intrinsic without pushing a stack frame. /// If this returns successfully, the engine will take care of jumping to the next block. fn call_intrinsic( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Self::PointerTag>], dest: PlaceTy<'tcx, Self::PointerTag>, - ) -> EvalResult<'tcx>; + ) -> InterpResult<'tcx>; /// Called for read access to a foreign static item. /// /// This will only be called once per static and machine; the result is cached in /// the machine memory. (This relies on `AllocMap::get_or` being able to add the /// owned allocation to the map even when the map is shared.) + /// + /// This allocation will then be fed to `tag_allocation` to initialize the "extra" state. fn find_foreign_static( def_id: DefId, - tcx: TyCtxtAt<'a, 'tcx, 'tcx>, - memory_extra: &Self::MemoryExtra, - ) -> EvalResult<'tcx, Cow<'tcx, Allocation>>; - - /// Called to turn an allocation obtained from the `tcx` into one that has - /// the right type for this machine. - /// - /// This should avoid copying if no work has to be done! If this returns an owned - /// allocation (because a copy had to be done to add tags or metadata), machine memory will - /// cache the result. (This relies on `AllocMap::get_or` being able to add the - /// owned allocation to the map even when the map is shared.) - fn adjust_static_allocation<'b>( - alloc: &'b Allocation, - memory_extra: &Self::MemoryExtra, - ) -> Cow<'b, Allocation>; + tcx: TyCtxtAt<'tcx>, + ) -> InterpResult<'tcx, Cow<'tcx, Allocation>>; /// Called for all binary operations on integer(-like) types when one operand is a pointer /// value, and for the `Offset` operation that is inherently about pointers. /// /// Returns a (value, overflowed) pair if the operation succeeded fn ptr_op( - ecx: &EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &InterpretCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, left: ImmTy<'tcx, Self::PointerTag>, right: ImmTy<'tcx, Self::PointerTag>, - ) -> EvalResult<'tcx, (Scalar, bool)>; + ) -> InterpResult<'tcx, (Scalar, bool)>; /// Heap allocations via the `box` keyword. fn box_alloc( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, dest: PlaceTy<'tcx, Self::PointerTag>, - ) -> EvalResult<'tcx>; - - /// Adds the tag for a newly allocated pointer. - fn tag_new_allocation( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ptr: Pointer, - kind: MemoryKind, - ) -> Pointer; - - /// Executed when evaluating the `*` operator: Following a reference. - /// This has the chance to adjust the tag. It should not change anything else! - /// `mutability` can be `None` in case a raw ptr is being dereferenced. - #[inline] - fn tag_dereference( - _ecx: &EvalContext<'a, 'mir, 'tcx, Self>, - place: MPlaceTy<'tcx, Self::PointerTag>, - _mutability: Option, - ) -> EvalResult<'tcx, Scalar> { - Ok(place.ptr) - } + ) -> InterpResult<'tcx>; + + /// Called to initialize the "extra" state of an allocation and make the pointers + /// it contains (in relocations) tagged. The way we construct allocations is + /// to always first construct it without extra and then add the extra. + /// This keeps uniform code paths for handling both allocations created by CTFE + /// for statics, and allocations ceated by Miri during evaluation. + /// + /// `kind` is the kind of the allocation being tagged; it can be `None` when + /// it's a static and `STATIC_KIND` is `None`. + /// + /// This should avoid copying if no work has to be done! If this returns an owned + /// allocation (because a copy had to be done to add tags or metadata), machine memory will + /// cache the result. (This relies on `AllocMap::get_or` being able to add the + /// owned allocation to the map even when the map is shared.) + /// + /// For static allocations, the tag returned must be the same as the one returned by + /// `tag_static_base_pointer`. + fn tag_allocation<'b>( + id: AllocId, + alloc: Cow<'b, Allocation>, + kind: Option>, + memory: &Memory<'mir, 'tcx, Self>, + ) -> (Cow<'b, Allocation>, Self::PointerTag); + + /// Return the "base" tag for the given static allocation: the one that is used for direct + /// accesses to this static/const/fn allocation. + /// + /// Be aware that requesting the `Allocation` for that `id` will lead to cycles + /// for cyclic statics! + fn tag_static_base_pointer( + id: AllocId, + memory: &Memory<'mir, 'tcx, Self>, + ) -> Self::PointerTag; /// Executes a retagging operation #[inline] fn retag( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _ecx: &mut InterpretCx<'mir, 'tcx, Self>, _kind: mir::RetagKind, _place: PlaceTy<'tcx, Self::PointerTag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { Ok(()) } /// Called immediately before a new stack frame got pushed - fn stack_push( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ) -> EvalResult<'tcx, Self::FrameExtra>; + fn stack_push(ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, Self::FrameExtra>; /// Called immediately after a stack frame gets popped fn stack_pop( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, extra: Self::FrameExtra, - ) -> EvalResult<'tcx>; + ) -> InterpResult<'tcx>; + + fn int_to_ptr( + int: u64, + _mem: &Memory<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, Pointer> { + if int == 0 { + err!(InvalidNullPointerUsage) + } else { + err!(ReadBytesAsPointer) + } + } + + fn ptr_to_int( + _ptr: Pointer, + _mem: &Memory<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, u64> { + err!(ReadPointerAsBytes) + } } diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 88b936afaa4c1..56a0e14535bfc 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -12,15 +12,14 @@ use std::borrow::Cow; use rustc::ty::{self, Instance, ParamEnv, query::TyCtxtAt}; use rustc::ty::layout::{Align, TargetDataLayout, Size, HasDataLayout}; -pub use rustc::mir::interpret::{truncate, write_target_uint, read_target_uint}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use syntax::ast::Mutability; use super::{ Pointer, AllocId, Allocation, GlobalId, AllocationExtra, - EvalResult, Scalar, EvalErrorKind, AllocKind, PointerArithmetic, - Machine, AllocMap, MayLeak, ErrorHandled, InboundsCheck, + InterpResult, Scalar, InterpError, GlobalAlloc, PointerArithmetic, + Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg, }; #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] @@ -44,9 +43,20 @@ impl MayLeak for MemoryKind { } } +/// Used by `get_size_and_align` to indicate whether the allocation needs to be live. +#[derive(Debug, Copy, Clone)] +pub enum AllocCheck { + /// Allocation must be live and not a function pointer. + Dereferencable, + /// Allocations needs to be live, but may be a function pointer. + Live, + /// Allocation may be dead. + MaybeDead, +} + // `Memory` has to depend on the `Machine` because some of its operations // (e.g., `get`) call a `Machine` hook. -pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> { +pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// Allocations local to this instance of the miri engine. The kind /// helps ensure that the same mechanism is used for allocation and /// deallocation. When an allocation is not found here, it is a @@ -56,23 +66,22 @@ pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> { /// the wrong type), so we let the machine override this type. /// Either way, if the machine allows writing to a static, doing so will /// create a copy of the static allocation here. - alloc_map: M::MemoryMap, + // FIXME: this should not be public, but interning currently needs access to it + pub(super) alloc_map: M::MemoryMap, /// To be able to compare pointers with NULL, and to check alignment for accesses /// to ZSTs (where pointers may dangle), we keep track of the size even for allocations /// that do not exist any more. - dead_alloc_map: FxHashMap, + pub(super) dead_alloc_map: FxHashMap, /// Extra data added by the machine. pub extra: M::MemoryExtra, /// Lets us implement `HasDataLayout`, which is awfully convenient. - pub(super) tcx: TyCtxtAt<'a, 'tcx, 'tcx>, + pub(super) tcx: TyCtxtAt<'tcx>, } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> HasDataLayout - for Memory<'a, 'mir, 'tcx, M> -{ +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M> { #[inline] fn data_layout(&self) -> &TargetDataLayout { &self.tcx.data_layout @@ -81,12 +90,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> HasDataLayout // FIXME: Really we shouldn't clone memory, ever. Snapshot machinery should instead // carefully copy only the reachable parts. -impl<'a, 'mir, 'tcx, M> - Clone -for - Memory<'a, 'mir, 'tcx, M> +impl<'mir, 'tcx, M> Clone for Memory<'mir, 'tcx, M> where - M: Machine<'a, 'mir, 'tcx, PointerTag=(), AllocExtra=(), MemoryExtra=()>, + M: Machine<'mir, 'tcx, PointerTag = (), AllocExtra = (), MemoryExtra = ()>, M::MemoryMap: AllocMap, Allocation)>, { fn clone(&self) -> Self { @@ -99,8 +105,8 @@ where } } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { - pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>) -> Self { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { + pub fn new(tcx: TyCtxtAt<'tcx>) -> Self { Memory { alloc_map: M::MemoryMap::default(), dead_alloc_map: FxHashMap::default(), @@ -109,32 +115,44 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } } - pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> Pointer { - Pointer::from(self.tcx.alloc_map.lock().create_fn_alloc(instance)) + #[inline] + pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer { + ptr.with_tag(M::tag_static_base_pointer(ptr.alloc_id, &self)) } - pub fn allocate_static_bytes(&mut self, bytes: &[u8]) -> Pointer { - Pointer::from(self.tcx.allocate_bytes(bytes)) + pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> Pointer { + let id = self.tcx.alloc_map.lock().create_fn_alloc(instance); + self.tag_static_base_pointer(Pointer::from(id)) } - pub fn allocate_with( + pub fn allocate( &mut self, - alloc: Allocation, + size: Size, + align: Align, kind: MemoryKind, - ) -> AllocId { - let id = self.tcx.alloc_map.lock().reserve(); - self.alloc_map.insert(id, (kind, alloc)); - id + ) -> Pointer { + let alloc = Allocation::undef(size, align); + self.allocate_with(alloc, kind) } - pub fn allocate( + pub fn allocate_static_bytes( &mut self, - size: Size, - align: Align, + bytes: &[u8], kind: MemoryKind, - ) -> Pointer { - let extra = AllocationExtra::memory_allocated(size, &self.extra); - Pointer::from(self.allocate_with(Allocation::undef(size, align, extra), kind)) + ) -> Pointer { + let alloc = Allocation::from_byte_aligned_bytes(bytes); + self.allocate_with(alloc, kind) + } + + pub fn allocate_with( + &mut self, + alloc: Allocation, + kind: MemoryKind, + ) -> Pointer { + let id = self.tcx.alloc_map.lock().reserve(); + let (alloc, tag) = M::tag_allocation(id, Cow::Owned(alloc), Some(kind), &self); + self.alloc_map.insert(id, (kind, alloc.into_owned())); + Pointer::from(id).with_tag(tag) } pub fn reallocate( @@ -145,7 +163,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { new_size: Size, new_align: Align, kind: MemoryKind, - ) -> EvalResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer> { if ptr.offset.bytes() != 0 { return err!(ReallocateNonBasePtr); } @@ -156,7 +174,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { self.copy( ptr.into(), old_align, - new_ptr.with_default_tag().into(), + new_ptr.into(), new_align, old_size.min(new_size), /*nonoverlapping*/ true, @@ -167,7 +185,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } /// Deallocate a local, or do nothing if that local has been made into a static - pub fn deallocate_local(&mut self, ptr: Pointer) -> EvalResult<'tcx> { + pub fn deallocate_local(&mut self, ptr: Pointer) -> InterpResult<'tcx> { // The allocation might be already removed by static interning. // This can only really happen in the CTFE instance, not in miri. if self.alloc_map.contains_key(&ptr.alloc_id) { @@ -182,7 +200,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { ptr: Pointer, size_and_align: Option<(Size, Align)>, kind: MemoryKind, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { trace!("deallocating: {}", ptr.alloc_id); if ptr.offset.bytes() != 0 { @@ -194,12 +212,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { None => { // Deallocating static memory -- always an error return match self.tcx.alloc_map.lock().get(ptr.alloc_id) { - Some(AllocKind::Function(..)) => err!(DeallocatedWrongMemoryKind( + Some(GlobalAlloc::Function(..)) => err!(DeallocatedWrongMemoryKind( "function".to_string(), format!("{:?}", kind), )), - Some(AllocKind::Static(..)) | - Some(AllocKind::Memory(..)) => err!(DeallocatedWrongMemoryKind( + Some(GlobalAlloc::Static(..)) | + Some(GlobalAlloc::Memory(..)) => err!(DeallocatedWrongMemoryKind( "static".to_string(), format!("{:?}", kind), )), @@ -240,128 +258,176 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { Ok(()) } - /// Checks that the pointer is aligned AND non-NULL. This supports ZSTs in two ways: - /// You can pass a scalar, and a `Pointer` does not have to actually still be allocated. - pub fn check_align( + /// Check if the given scalar is allowed to do a memory access of given `size` + /// and `align`. On success, returns `None` for zero-sized accesses (where + /// nothing else is left to do) and a `Pointer` to use for the actual access otherwise. + /// Crucially, if the input is a `Pointer`, we will test it for liveness + /// *even of* the size is 0. + /// + /// Everyone accessing memory based on a `Scalar` should use this method to get the + /// `Pointer` they need. And even if you already have a `Pointer`, call this method + /// to make sure it is sufficiently aligned and not dangling. Not doing that may + /// cause ICEs. + pub fn check_ptr_access( &self, - ptr: Scalar, - required_align: Align - ) -> EvalResult<'tcx> { - // Check non-NULL/Undef, extract offset - let (offset, alloc_align) = match ptr { - Scalar::Ptr(ptr) => { - // check this is not NULL -- which we can ensure only if this is in-bounds - // of some (potentially dead) allocation. - let align = self.check_bounds_ptr(ptr, InboundsCheck::MaybeDead)?; - (ptr.offset.bytes(), align) + sptr: Scalar, + size: Size, + align: Align, + ) -> InterpResult<'tcx, Option>> { + fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> { + if offset % align.bytes() == 0 { + Ok(()) + } else { + // The biggest power of two through which `offset` is divisible. + let offset_pow2 = 1 << offset.trailing_zeros(); + err!(AlignmentCheckFailed { + has: Align::from_bytes(offset_pow2).unwrap(), + required: align, + }) } - Scalar::Bits { bits, size } => { - assert_eq!(size as u64, self.pointer_size().bytes()); - assert!(bits < (1u128 << self.pointer_size().bits())); - // check this is not NULL + } + + // Normalize to a `Pointer` if we definitely need one. + let normalized = if size.bytes() == 0 { + // Can be an integer, just take what we got. We do NOT `force_bits` here; + // if this is already a `Pointer` we want to do the bounds checks! + sptr + } else { + // A "real" access, we must get a pointer. + Scalar::Ptr(self.force_ptr(sptr)?) + }; + Ok(match normalized.to_bits_or_ptr(self.pointer_size(), self) { + Ok(bits) => { + let bits = bits as u64; // it's ptr-sized + assert!(size.bytes() == 0); + // Must be non-NULL and aligned. if bits == 0 { return err!(InvalidNullPointerUsage); } - // the "base address" is 0 and hence always aligned - (bits as u64, required_align) + check_offset_align(bits, align)?; + None } - }; - // Check alignment - if alloc_align.bytes() < required_align.bytes() { - return err!(AlignmentCheckFailed { - has: alloc_align, - required: required_align, - }); - } - if offset % required_align.bytes() == 0 { - Ok(()) - } else { - let has = offset % required_align.bytes(); - err!(AlignmentCheckFailed { - has: Align::from_bytes(has).unwrap(), - required: required_align, - }) - } + Err(ptr) => { + let (allocation_size, alloc_align) = + self.get_size_and_align(ptr.alloc_id, AllocCheck::Dereferencable)?; + // Test bounds. This also ensures non-NULL. + // It is sufficient to check this for the end pointer. The addition + // checks for overflow. + let end_ptr = ptr.offset(size, self)?; + end_ptr.check_in_alloc(allocation_size, CheckInAllocMsg::MemoryAccessTest)?; + // Test align. Check this last; if both bounds and alignment are violated + // we want the error to be about the bounds. + if alloc_align.bytes() < align.bytes() { + // The allocation itself is not aligned enough. + // FIXME: Alignment check is too strict, depending on the base address that + // got picked we might be aligned even if this check fails. + // We instead have to fall back to converting to an integer and checking + // the "real" alignment. + return err!(AlignmentCheckFailed { + has: alloc_align, + required: align, + }); + } + check_offset_align(ptr.offset.bytes(), align)?; + + // We can still be zero-sized in this branch, in which case we have to + // return `None`. + if size.bytes() == 0 { None } else { Some(ptr) } + } + }) } - /// Checks if the pointer is "in-bounds". Notice that a pointer pointing at the end - /// of an allocation (i.e., at the first *inaccessible* location) *is* considered - /// in-bounds! This follows C's/LLVM's rules. - /// If you want to check bounds before doing a memory access, better first obtain - /// an `Allocation` and call `check_bounds`. - pub fn check_bounds_ptr( + /// Test if the pointer might be NULL. + pub fn ptr_may_be_null( &self, ptr: Pointer, - liveness: InboundsCheck, - ) -> EvalResult<'tcx, Align> { - let (allocation_size, align) = self.get_size_and_align(ptr.alloc_id, liveness)?; - ptr.check_in_alloc(allocation_size, liveness)?; - Ok(align) + ) -> bool { + let (size, _align) = self.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead) + .expect("alloc info with MaybeDead cannot fail"); + ptr.check_in_alloc(size, CheckInAllocMsg::NullPointerTest).is_err() } } /// Allocation accessors -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { /// Helper function to obtain the global (tcx) allocation for a static. /// This attempts to return a reference to an existing allocation if /// one can be found in `tcx`. That, however, is only possible if `tcx` and /// this machine use the same pointer tag, so it is indirected through - /// `M::static_with_default_tag`. + /// `M::tag_allocation`. + /// + /// Notice that every static has two `AllocId` that will resolve to the same + /// thing here: one maps to `GlobalAlloc::Static`, this is the "lazy" ID, + /// and the other one is maps to `GlobalAlloc::Memory`, this is returned by + /// `const_eval_raw` and it is the "resolved" ID. + /// The resolved ID is never used by the interpreted progrma, it is hidden. + /// The `GlobalAlloc::Memory` branch here is still reachable though; when a static + /// contains a reference to memory that was created during its evaluation (i.e., not to + /// another static), those inner references only exist in "resolved" form. fn get_static_alloc( id: AllocId, - tcx: TyCtxtAt<'a, 'tcx, 'tcx>, - memory_extra: &M::MemoryExtra, - ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { + tcx: TyCtxtAt<'tcx>, + memory: &Memory<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { let alloc = tcx.alloc_map.lock().get(id); - let def_id = match alloc { - Some(AllocKind::Memory(mem)) => { - // We got tcx memory. Let the machine figure out whether and how to - // turn that into memory with the right pointer tag. - return Ok(M::adjust_static_allocation(mem, memory_extra)) - } - Some(AllocKind::Function(..)) => { - return err!(DerefFunctionPointer) - } - Some(AllocKind::Static(did)) => { - did - } + let alloc = match alloc { + Some(GlobalAlloc::Memory(mem)) => + Cow::Borrowed(mem), + Some(GlobalAlloc::Function(..)) => + return err!(DerefFunctionPointer), None => return err!(DanglingPointerDeref), - }; - // We got a "lazy" static that has not been computed yet, do some work - trace!("static_alloc: Need to compute {:?}", def_id); - if tcx.is_foreign_item(def_id) { - return M::find_foreign_static(def_id, tcx, memory_extra); - } - let instance = Instance::mono(tcx.tcx, def_id); - let gid = GlobalId { - instance, - promoted: None, - }; - // use the raw query here to break validation cycles. Later uses of the static will call the - // full query anyway - tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| { - // no need to report anything, the const_eval call takes care of that for statics - assert!(tcx.is_static(def_id).is_some()); - match err { - ErrorHandled::Reported => EvalErrorKind::ReferencedConstant.into(), - ErrorHandled::TooGeneric => EvalErrorKind::TooGeneric.into(), + Some(GlobalAlloc::Static(def_id)) => { + // We got a "lazy" static that has not been computed yet. + if tcx.is_foreign_item(def_id) { + trace!("static_alloc: foreign item {:?}", def_id); + M::find_foreign_static(def_id, tcx)? + } else { + trace!("static_alloc: Need to compute {:?}", def_id); + let instance = Instance::mono(tcx.tcx, def_id); + let gid = GlobalId { + instance, + promoted: None, + }; + // use the raw query here to break validation cycles. Later uses of the static + // will call the full query anyway + let raw_const = tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)) + .map_err(|err| { + // no need to report anything, the const_eval call takes care of that + // for statics + assert!(tcx.is_static(def_id)); + match err { + ErrorHandled::Reported => InterpError::ReferencedConstant, + ErrorHandled::TooGeneric => InterpError::TooGeneric, + } + })?; + // Make sure we use the ID of the resolved memory, not the lazy one! + let id = raw_const.alloc_id; + let allocation = tcx.alloc_map.lock().unwrap_memory(id); + Cow::Borrowed(allocation) + } } - }).map(|raw_const| { - let allocation = tcx.alloc_map.lock().unwrap_memory(raw_const.alloc_id); - // We got tcx memory. Let the machine figure out whether and how to - // turn that into memory with the right pointer tag. - M::adjust_static_allocation(allocation, memory_extra) - }) + }; + // We got tcx memory. Let the machine figure out whether and how to + // turn that into memory with the right pointer tag. + Ok(M::tag_allocation( + id, // always use the ID we got as input, not the "hidden" one. + alloc, + M::STATIC_KIND.map(MemoryKind::Machine), + memory + ).0) } - pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> { + pub fn get( + &self, + id: AllocId, + ) -> InterpResult<'tcx, &Allocation> { // The error type of the inner closure here is somewhat funny. We have two // ways of "erroring": An actual error, or because we got a reference from // `get_static_alloc` that we can actually use directly without inserting anything anywhere. - // So the error type is `EvalResult<'tcx, &Allocation>`. + // So the error type is `InterpResult<'tcx, &Allocation>`. let a = self.alloc_map.get_or(id, || { - let alloc = Self::get_static_alloc(id, self.tcx, &self.extra).map_err(Err)?; + let alloc = Self::get_static_alloc(id, self.tcx, &self).map_err(Err)?; match alloc { Cow::Borrowed(alloc) => { // We got a ref, cheaply return that as an "error" so that the @@ -388,13 +454,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { pub fn get_mut( &mut self, id: AllocId, - ) -> EvalResult<'tcx, &mut Allocation> { + ) -> InterpResult<'tcx, &mut Allocation> { let tcx = self.tcx; - let memory_extra = &self.extra; + let alloc = Self::get_static_alloc(id, tcx, &self); let a = self.alloc_map.get_mut_or(id, || { // Need to make a copy, even if `get_static_alloc` is able // to give us a cheap reference. - let alloc = Self::get_static_alloc(id, tcx, memory_extra)?; + let alloc = alloc?; if alloc.mutability == Mutability::Immutable { return err!(ModifiedConstantMemory); } @@ -417,52 +483,71 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } } - /// Obtain the size and alignment of an allocation, even if that allocation has been deallocated + /// Obtain the size and alignment of an allocation, even if that allocation has + /// been deallocated. /// - /// If `liveness` is `InboundsCheck::Dead`, this function always returns `Ok` + /// If `liveness` is `AllocCheck::MaybeDead`, this function always returns `Ok`. pub fn get_size_and_align( &self, id: AllocId, - liveness: InboundsCheck, - ) -> EvalResult<'static, (Size, Align)> { - if let Ok(alloc) = self.get(id) { + liveness: AllocCheck, + ) -> InterpResult<'static, (Size, Align)> { + // # Regular allocations + // Don't use `self.get` here as that will + // a) cause cycles in case `id` refers to a static + // b) duplicate a static's allocation in miri + if let Some((_, alloc)) = self.alloc_map.get(id) { return Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)); } - // Could also be a fn ptr or extern static - match self.tcx.alloc_map.lock().get(id) { - Some(AllocKind::Function(..)) => Ok((Size::ZERO, Align::from_bytes(1).unwrap())), - Some(AllocKind::Static(did)) => { - // The only way `get` couldn't have worked here is if this is an extern static - assert!(self.tcx.is_foreign_item(did)); - // Use size and align of the type + + // # Statics and function pointers + // Can't do this in the match argument, we may get cycle errors since the lock would + // be held throughout the match. + let alloc = self.tcx.alloc_map.lock().get(id); + match alloc { + Some(GlobalAlloc::Function(..)) => { + if let AllocCheck::Dereferencable = liveness { + // The caller requested no function pointers. + err!(DerefFunctionPointer) + } else { + Ok((Size::ZERO, Align::from_bytes(1).unwrap())) + } + }, + Some(GlobalAlloc::Static(did)) => { + // Use size and align of the type. let ty = self.tcx.type_of(did); let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); Ok((layout.size, layout.align.abi)) - } - _ => match liveness { - InboundsCheck::MaybeDead => { - // Must be a deallocated pointer - Ok(*self.dead_alloc_map.get(&id).expect( - "allocation missing in dead_alloc_map" - )) - }, - InboundsCheck::Live => err!(DanglingPointerDeref), + }, + Some(GlobalAlloc::Memory(alloc)) => + // Need to duplicate the logic here, because the global allocations have + // different associated types than the interpreter-local ones. + Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)), + // The rest must be dead. + None => if let AllocCheck::MaybeDead = liveness { + // Deallocated pointers are allowed, we should be able to find + // them in the map. + Ok(*self.dead_alloc_map.get(&id) + .expect("deallocated pointers should all be recorded in \ + `dead_alloc_map`")) + } else { + err!(DanglingPointerDeref) }, } } - pub fn get_fn(&self, ptr: Pointer) -> EvalResult<'tcx, Instance<'tcx>> { + pub fn get_fn(&self, ptr: Pointer) -> InterpResult<'tcx, Instance<'tcx>> { if ptr.offset.bytes() != 0 { return err!(InvalidFunctionPointer); } trace!("reading fn ptr: {}", ptr.alloc_id); match self.tcx.alloc_map.lock().get(ptr.alloc_id) { - Some(AllocKind::Function(instance)) => Ok(instance), - _ => Err(EvalErrorKind::ExecuteMemory.into()), + Some(GlobalAlloc::Function(instance)) => Ok(instance), + _ => Err(InterpError::ExecuteMemory.into()), } } - pub fn mark_immutable(&mut self, id: AllocId) -> EvalResult<'tcx> { + pub fn mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { self.get_mut(id)?.mutability = Mutability::Immutable; Ok(()) } @@ -555,16 +640,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { Err(()) => { // static alloc? match self.tcx.alloc_map.lock().get(id) { - Some(AllocKind::Memory(alloc)) => { + Some(GlobalAlloc::Memory(alloc)) => { self.dump_alloc_helper( &mut allocs_seen, &mut allocs_to_print, msg, alloc, " (immutable)".to_owned() ); } - Some(AllocKind::Function(func)) => { + Some(GlobalAlloc::Function(func)) => { trace!("{} {}", msg, func); } - Some(AllocKind::Static(did)) => { + Some(GlobalAlloc::Static(did)) => { trace!("{} {:?}", msg, did); } None => { @@ -593,74 +678,22 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } } -/// Byte Accessors -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { +/// Reading and writing. +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { + /// Performs appropriate bounds checks. pub fn read_bytes( &self, ptr: Scalar, size: Size, - ) -> EvalResult<'tcx, &[u8]> { - if size.bytes() == 0 { - Ok(&[]) - } else { - let ptr = ptr.to_ptr()?; - self.get(ptr.alloc_id)?.get_bytes(self, ptr, size) - } - } -} - -/// Interning (for CTFE) -impl<'a, 'mir, 'tcx, M> Memory<'a, 'mir, 'tcx, M> -where - M: Machine<'a, 'mir, 'tcx, PointerTag=(), AllocExtra=(), MemoryExtra=()>, - // FIXME: Working around https://github.com/rust-lang/rust/issues/24159 - M::MemoryMap: AllocMap, Allocation)>, -{ - /// mark an allocation as static and initialized, either mutable or not - pub fn intern_static( - &mut self, - alloc_id: AllocId, - mutability: Mutability, - ) -> EvalResult<'tcx> { - trace!( - "mark_static_initialized {:?}, mutability: {:?}", - alloc_id, - mutability - ); - // remove allocation - let (kind, mut alloc) = self.alloc_map.remove(&alloc_id).unwrap(); - match kind { - MemoryKind::Machine(_) => bug!("Static cannot refer to machine memory"), - MemoryKind::Stack | MemoryKind::Vtable => {}, - } - // ensure llvm knows not to put this into immutable memory - alloc.mutability = mutability; - let alloc = self.tcx.intern_const_alloc(alloc); - self.tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc); - // recurse into inner allocations - for &(_, alloc) in alloc.relocations.values() { - // FIXME: Reusing the mutability here is likely incorrect. It is originally - // determined via `is_freeze`, and data is considered frozen if there is no - // `UnsafeCell` *immediately* in that data -- however, this search stops - // at references. So whenever we follow a reference, we should likely - // assume immutability -- and we should make sure that the compiler - // does not permit code that would break this! - if self.alloc_map.contains_key(&alloc) { - // Not yet interned, so proceed recursively - self.intern_static(alloc, mutability)?; - } else if self.dead_alloc_map.contains_key(&alloc) { - // dangling pointer - return err!(ValidationFailure( - "encountered dangling pointer in final constant".into(), - )) - } - } - Ok(()) + ) -> InterpResult<'tcx, &[u8]> { + let ptr = match self.check_ptr_access(ptr, size, Align::from_bytes(1).unwrap())? { + Some(ptr) => ptr, + None => return Ok(&[]), // zero-sized access + }; + self.get(ptr.alloc_id)?.get_bytes(self, ptr, size) } -} -/// Reading and writing. -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { + /// Performs appropriate bounds checks. pub fn copy( &mut self, src: Scalar, @@ -669,10 +702,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { dest_align: Align, size: Size, nonoverlapping: bool, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { self.copy_repeatedly(src, src_align, dest, dest_align, size, 1, nonoverlapping) } + /// Performs appropriate bounds checks. pub fn copy_repeatedly( &mut self, src: Scalar, @@ -682,16 +716,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { size: Size, length: u64, nonoverlapping: bool, - ) -> EvalResult<'tcx> { - self.check_align(src, src_align)?; - self.check_align(dest, dest_align)?; - if size.bytes() == 0 { - // Nothing to do for ZST, other than checking alignment and - // non-NULLness which already happened. - return Ok(()); - } - let src = src.to_ptr()?; - let dest = dest.to_ptr()?; + ) -> InterpResult<'tcx> { + // We need to check *both* before early-aborting due to the size being 0. + let (src, dest) = match (self.check_ptr_access(src, size, src_align)?, + self.check_ptr_access(dest, size * length, dest_align)?) + { + (Some(src), Some(dest)) => (src, dest), + // One of the two sizes is 0. + _ => return Ok(()), + }; // first copy the relocations to a temporary buffer, because // `get_bytes_mut` will clear the relocations, which is correct, @@ -700,24 +733,29 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // relocations overlapping the edges; those would not be handled correctly). let relocations = { let relocations = self.get(src.alloc_id)?.relocations(self, src, size); - let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize)); - for i in 0..length { - new_relocations.extend( - relocations - .iter() - .map(|&(offset, reloc)| { - // compute offset for current repetition - let dest_offset = dest.offset + (i * size); - ( - // shift offsets from source allocation to destination allocation - offset + dest_offset - src.offset, - reloc, - ) - }) - ); - } + if relocations.is_empty() { + // nothing to copy, ignore even the `length` loop + Vec::new() + } else { + let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize)); + for i in 0..length { + new_relocations.extend( + relocations + .iter() + .map(|&(offset, reloc)| { + // compute offset for current repetition + let dest_offset = dest.offset + (i * size); + ( + // shift offsets from source allocation to destination allocation + offset + dest_offset - src.offset, + reloc, + ) + }) + ); + } - new_relocations + new_relocations + } }; let tcx = self.tcx.tcx; @@ -772,7 +810,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } /// Undefined bytes -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // FIXME: Add a fast version for the common, nonoverlapping case fn copy_undef_mask( &mut self, @@ -780,24 +818,90 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { dest: Pointer, size: Size, repeat: u64, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { // The bits have to be saved locally before writing to dest in case src and dest overlap. assert_eq!(size.bytes() as usize as u64, size.bytes()); - let undef_mask = self.get(src.alloc_id)?.undef_mask.clone(); - let dest_allocation = self.get_mut(dest.alloc_id)?; + let undef_mask = &self.get(src.alloc_id)?.undef_mask; + + // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`), + // a naive undef mask copying algorithm would repeatedly have to read the undef mask from + // the source and write it to the destination. Even if we optimized the memory accesses, + // we'd be doing all of this `repeat` times. + // Therefor we precompute a compressed version of the undef mask of the source value and + // then write it back `repeat` times without computing any more information from the source. + + // a precomputed cache for ranges of defined/undefined bits + // 0000010010001110 will become + // [5, 1, 2, 1, 3, 3, 1] + // where each element toggles the state + let mut ranges = smallvec::SmallVec::<[u64; 1]>::new(); + let first = undef_mask.get(src.offset); + let mut cur_len = 1; + let mut cur = first; + for i in 1..size.bytes() { + // FIXME: optimize to bitshift the current undef block's bits and read the top bit + if undef_mask.get(src.offset + Size::from_bytes(i)) == cur { + cur_len += 1; + } else { + ranges.push(cur_len); + cur_len = 1; + cur = !cur; + } + } - for i in 0..size.bytes() { - let defined = undef_mask.get(src.offset + Size::from_bytes(i)); + // now fill in all the data + let dest_allocation = self.get_mut(dest.alloc_id)?; + // an optimization where we can just overwrite an entire range of definedness bits if + // they are going to be uniformly `1` or `0`. + if ranges.is_empty() { + dest_allocation.undef_mask.set_range_inbounds( + dest.offset, + dest.offset + size * repeat, + first, + ); + return Ok(()) + } - for j in 0..repeat { - dest_allocation.undef_mask.set( - dest.offset + Size::from_bytes(i + (size.bytes() * j)), - defined + // remember to fill in the trailing bits + ranges.push(cur_len); + + for mut j in 0..repeat { + j *= size.bytes(); + j += dest.offset.bytes(); + let mut cur = first; + for range in &ranges { + let old_j = j; + j += range; + dest_allocation.undef_mask.set_range_inbounds( + Size::from_bytes(old_j), + Size::from_bytes(j), + cur, ); + cur = !cur; } } - Ok(()) } + + pub fn force_ptr( + &self, + scalar: Scalar, + ) -> InterpResult<'tcx, Pointer> { + match scalar { + Scalar::Ptr(ptr) => Ok(ptr), + _ => M::int_to_ptr(scalar.to_usize(self)?, self) + } + } + + pub fn force_bits( + &self, + scalar: Scalar, + size: Size + ) -> InterpResult<'tcx, u128> { + match scalar.to_bits_or_ptr(size, self) { + Ok(bits) => Ok(bits), + Err(ptr) => Ok(M::ptr_to_int(ptr, self)? as u128) + } + } } diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index d2ab3fcb7a30a..259bd6af0d5d4 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -14,16 +14,17 @@ mod traits; mod validity; mod intrinsics; mod visitor; +mod intern; pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one place: here pub use self::eval_context::{ - EvalContext, Frame, StackPopCleanup, LocalState, LocalValue, + InterpretCx, Frame, StackPopCleanup, LocalState, LocalValue, }; pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy}; -pub use self::memory::{Memory, MemoryKind}; +pub use self::memory::{Memory, MemoryKind, AllocCheck}; pub use self::machine::{Machine, AllocMap, MayLeak}; @@ -32,3 +33,7 @@ pub use self::operand::{ScalarMaybeUndef, Immediate, ImmTy, Operand, OpTy}; pub use self::visitor::{ValueVisitor, MutValueVisitor}; pub use self::validity::RefTracking; + +pub(super) use self::intrinsics::type_name; + +pub use self::intern::intern_const_alloc_recursive; diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 979595d6c0009..c72078fa89cd2 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -4,17 +4,19 @@ use std::convert::TryInto; use rustc::{mir, ty}; -use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx}; +use rustc::ty::layout::{ + self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx, +}; use rustc::mir::interpret::{ - GlobalId, AllocId, InboundsCheck, + GlobalId, AllocId, ConstValue, Pointer, Scalar, - EvalResult, EvalErrorKind, + InterpResult, InterpError, sign_extend, truncate, }; use super::{ - EvalContext, Machine, - MemPlace, MPlaceTy, PlaceTy, Place, MemoryKind, + InterpretCx, Machine, + MemPlace, MPlaceTy, PlaceTy, Place, }; pub use rustc::mir::interpret::ScalarMaybeUndef; @@ -31,35 +33,12 @@ pub enum Immediate { ScalarPair(ScalarMaybeUndef, ScalarMaybeUndef), } -impl Immediate { - #[inline] - pub fn with_default_tag(self) -> Immediate - where Tag: Default - { - match self { - Immediate::Scalar(x) => Immediate::Scalar(x.with_default_tag()), - Immediate::ScalarPair(x, y) => - Immediate::ScalarPair(x.with_default_tag(), y.with_default_tag()), - } - } -} - impl<'tcx, Tag> Immediate { #[inline] pub fn from_scalar(val: Scalar) -> Self { Immediate::Scalar(ScalarMaybeUndef::Scalar(val)) } - #[inline] - pub fn erase_tag(self) -> Immediate - { - match self { - Immediate::Scalar(x) => Immediate::Scalar(x.erase_tag()), - Immediate::ScalarPair(x, y) => - Immediate::ScalarPair(x.erase_tag(), y.erase_tag()), - } - } - pub fn new_slice( val: Scalar, len: u64, @@ -84,12 +63,12 @@ impl<'tcx, Tag> Immediate { } #[inline] - pub fn to_scalar(self) -> EvalResult<'tcx, Scalar> { + pub fn to_scalar(self) -> InterpResult<'tcx, Scalar> { self.to_scalar_or_undef().not_undef() } #[inline] - pub fn to_scalar_pair(self) -> EvalResult<'tcx, (Scalar, Scalar)> { + pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar, Scalar)> { match self { Immediate::Scalar(..) => bug!("Got a thin pointer where a scalar pair was expected"), Immediate::ScalarPair(a, b) => Ok((a.not_undef()?, b.not_undef()?)) @@ -99,7 +78,7 @@ impl<'tcx, Tag> Immediate { /// Converts the immediate into a pointer (or a pointer-sized integer). /// Throws away the second half of a ScalarPair! #[inline] - pub fn to_scalar_ptr(self) -> EvalResult<'tcx, Scalar> { + pub fn to_scalar_ptr(self) -> InterpResult<'tcx, Scalar> { match self { Immediate::Scalar(ptr) | Immediate::ScalarPair(ptr, _) => ptr.not_undef(), @@ -109,7 +88,7 @@ impl<'tcx, Tag> Immediate { /// Converts the value into its metadata. /// Throws away the first half of a ScalarPair! #[inline] - pub fn to_meta(self) -> EvalResult<'tcx, Option>> { + pub fn to_meta(self) -> InterpResult<'tcx, Option>> { Ok(match self { Immediate::Scalar(_) => None, Immediate::ScalarPair(_, meta) => Some(meta.not_undef()?), @@ -142,28 +121,7 @@ pub enum Operand { Indirect(MemPlace), } -impl Operand { - #[inline] - pub fn with_default_tag(self) -> Operand - where Tag: Default - { - match self { - Operand::Immediate(x) => Operand::Immediate(x.with_default_tag()), - Operand::Indirect(x) => Operand::Indirect(x.with_default_tag()), - } - } -} - impl Operand { - #[inline] - pub fn erase_tag(self) -> Operand - { - match self { - Operand::Immediate(x) => Operand::Immediate(x.erase_tag()), - Operand::Indirect(x) => Operand::Indirect(x.erase_tag()), - } - } - #[inline] pub fn to_mem_place(self) -> MemPlace where Tag: ::std::fmt::Debug @@ -229,30 +187,18 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> } #[inline] - pub fn to_bits(self) -> EvalResult<'tcx, u128> { + pub fn to_bits(self) -> InterpResult<'tcx, u128> { self.to_scalar()?.to_bits(self.layout.size) } } -impl<'tcx, Tag> OpTy<'tcx, Tag> -{ - #[inline] - pub fn erase_tag(self) -> OpTy<'tcx> - { - OpTy { - op: self.op.erase_tag(), - layout: self.layout, - } - } -} - // Use the existing layout if given (but sanity check in debug mode), // or compute the layout. #[inline(always)] pub(super) fn from_known_layout<'tcx>( layout: Option>, - compute: impl FnOnce() -> EvalResult<'tcx, TyLayout<'tcx>> -) -> EvalResult<'tcx, TyLayout<'tcx>> { + compute: impl FnOnce() -> InterpResult<'tcx, TyLayout<'tcx>> +) -> InterpResult<'tcx, TyLayout<'tcx>> { match layout { None => compute(), Some(layout) => { @@ -267,52 +213,57 @@ pub(super) fn from_known_layout<'tcx>( } } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { - /// Try reading an immediate in memory; this is interesting particularly for ScalarPair. +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> { + /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`. /// Returns `None` if the layout does not permit loading this as a value. fn try_read_immediate_from_mplace( &self, mplace: MPlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> { if mplace.layout.is_unsized() { // Don't touch unsized return Ok(None); } let (ptr, ptr_align) = mplace.to_scalar_ptr_align(); - if mplace.layout.is_zst() { - // Not all ZSTs have a layout we would handle below, so just short-circuit them - // all here. - self.memory.check_align(ptr, ptr_align)?; - return Ok(Some(Immediate::Scalar(Scalar::zst().into()))); - } + let ptr = match self.memory.check_ptr_access(ptr, mplace.layout.size, ptr_align)? { + Some(ptr) => ptr, + None => return Ok(Some(ImmTy { // zero-sized type + imm: Immediate::Scalar(Scalar::zst().into()), + layout: mplace.layout, + })), + }; - // check for integer pointers before alignment to report better errors - let ptr = ptr.to_ptr()?; - self.memory.check_align(ptr.into(), ptr_align)?; match mplace.layout.abi { layout::Abi::Scalar(..) => { let scalar = self.memory .get(ptr.alloc_id)? .read_scalar(self, ptr, mplace.layout.size)?; - Ok(Some(Immediate::Scalar(scalar))) + Ok(Some(ImmTy { + imm: Immediate::Scalar(scalar), + layout: mplace.layout, + })) } layout::Abi::ScalarPair(ref a, ref b) => { + // We checked `ptr_align` above, so all fields will have the alignment they need. + // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, + // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. let (a, b) = (&a.value, &b.value); let (a_size, b_size) = (a.size(self), b.size(self)); let a_ptr = ptr; let b_offset = a_size.align_to(b.align(self).abi); - assert!(b_offset.bytes() > 0); // we later use the offset to test which field to use + assert!(b_offset.bytes() > 0); // we later use the offset to tell apart the fields let b_ptr = ptr.offset(b_offset, self)?; let a_val = self.memory .get(ptr.alloc_id)? .read_scalar(self, a_ptr, a_size)?; - let b_align = ptr_align.restrict_for_offset(b_offset); - self.memory.check_align(b_ptr.into(), b_align)?; let b_val = self.memory .get(ptr.alloc_id)? .read_scalar(self, b_ptr, b_size)?; - Ok(Some(Immediate::ScalarPair(a_val, b_val))) + Ok(Some(ImmTy { + imm: Immediate::ScalarPair(a_val, b_val), + layout: mplace.layout, + })) } _ => Ok(None), } @@ -324,16 +275,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> /// Note that for a given layout, this operation will either always fail or always /// succeed! Whether it succeeds depends on whether the layout can be represented /// in a `Immediate`, not on which data is stored there currently. - pub(super) fn try_read_immediate( + pub(crate) fn try_read_immediate( &self, src: OpTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, Result, MemPlace>> { + ) -> InterpResult<'tcx, Result, MPlaceTy<'tcx, M::PointerTag>>> { Ok(match src.try_as_mplace() { Ok(mplace) => { if let Some(val) = self.try_read_immediate_from_mplace(mplace)? { Ok(val) } else { - Err(*mplace) + Err(mplace) } }, Err(val) => Ok(val), @@ -345,9 +296,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> pub fn read_immediate( &self, op: OpTy<'tcx, M::PointerTag> - ) -> EvalResult<'tcx, ImmTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { if let Ok(imm) = self.try_read_immediate(op)? { - Ok(ImmTy { imm, layout: op.layout }) + Ok(imm) } else { bug!("primitive read failed for type: {:?}", op.layout.ty); } @@ -357,7 +308,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> pub fn read_scalar( &self, op: OpTy<'tcx, M::PointerTag> - ) -> EvalResult<'tcx, ScalarMaybeUndef> { + ) -> InterpResult<'tcx, ScalarMaybeUndef> { Ok(self.read_immediate(op)?.to_scalar_or_undef()) } @@ -365,47 +316,20 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> pub fn read_str( &self, mplace: MPlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, &str> { + ) -> InterpResult<'tcx, &str> { let len = mplace.len(self)?; let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len as u64))?; let str = ::std::str::from_utf8(bytes) - .map_err(|err| EvalErrorKind::ValidationFailure(err.to_string()))?; + .map_err(|err| InterpError::ValidationFailure(err.to_string()))?; Ok(str) } - pub fn uninit_operand( - &mut self, - layout: TyLayout<'tcx> - ) -> EvalResult<'tcx, Operand> { - // This decides which types we will use the Immediate optimization for, and hence should - // match what `try_read_immediate` and `eval_place_to_op` support. - if layout.is_zst() { - return Ok(Operand::Immediate(Immediate::Scalar(Scalar::zst().into()))); - } - - Ok(match layout.abi { - layout::Abi::Scalar(..) => - Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef)), - layout::Abi::ScalarPair(..) => - Operand::Immediate(Immediate::ScalarPair( - ScalarMaybeUndef::Undef, - ScalarMaybeUndef::Undef, - )), - _ => { - trace!("Forcing allocation for local of type {:?}", layout.ty); - Operand::Indirect( - *self.allocate(layout, MemoryKind::Stack) - ) - } - }) - } - /// Projection functions pub fn operand_field( &self, op: OpTy<'tcx, M::PointerTag>, field: u64, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let base = match op.try_as_mplace() { Ok(mplace) => { // The easy case @@ -422,9 +346,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> return Ok(OpTy { op: Operand::Immediate(immediate), layout: field_layout }); } let offset = op.layout.fields.offset(field); - let immediate = match base { + let immediate = match *base { // the field covers the entire type - _ if offset.bytes() == 0 && field_layout.size == op.layout.size => base, + _ if offset.bytes() == 0 && field_layout.size == op.layout.size => *base, // extract fields from types with `ScalarPair` ABI Immediate::ScalarPair(a, b) => { let val = if offset.bytes() == 0 { a } else { b }; @@ -440,7 +364,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> &self, op: OpTy<'tcx, M::PointerTag>, variant: VariantIdx, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { // Downcasts only change the layout Ok(match op.try_as_mplace() { Ok(mplace) => { @@ -457,7 +381,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> &self, base: OpTy<'tcx, M::PointerTag>, proj_elem: &mir::PlaceElem<'tcx>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { use rustc::mir::ProjectionElem::*; Ok(match *proj_elem { Field(field, _) => self.operand_field(base, field.index() as u64)?, @@ -484,25 +408,30 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, local: mir::Local, layout: Option>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { assert_ne!(local, mir::RETURN_PLACE); - let op = *frame.locals[local].access()?; let layout = self.layout_of_local(frame, local, layout)?; + let op = if layout.is_zst() { + // Do not read from ZST, they might not be initialized + Operand::Immediate(Immediate::Scalar(Scalar::zst().into())) + } else { + frame.locals[local].access()? + }; Ok(OpTy { op, layout }) } - /// Every place can be read from, so we can turm them into an operand + /// Every place can be read from, so we can turn them into an operand #[inline(always)] pub fn place_to_op( &self, place: PlaceTy<'tcx, M::PointerTag> - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let op = match *place { Place::Ptr(mplace) => { Operand::Indirect(mplace) } Place::Local { frame, local } => - *self.stack[frame].locals[local].access()? + *self.access_local(&self.stack[frame], local, None)? }; Ok(OpTy { op, layout: place.layout }) } @@ -513,33 +442,47 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> &self, mir_place: &mir::Place<'tcx>, layout: Option>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { - use rustc::mir::Place::*; + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + use rustc::mir::Place; use rustc::mir::PlaceBase; - let op = match *mir_place { - Base(PlaceBase::Local(mir::RETURN_PLACE)) => return err!(ReadFromReturnPointer), - Base(PlaceBase::Local(local)) => self.access_local(self.frame(), local, layout)?, - Projection(ref proj) => { - let op = self.eval_place_to_op(&proj.base, None)?; - self.operand_projection(op, &proj.elem)? - } + mir_place.iterate(|place_base, place_projection| { + let mut op = match place_base { + PlaceBase::Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer), + PlaceBase::Local(local) => { + // FIXME use place_projection.is_empty() when is available + // Do not use the layout passed in as argument if the base we are looking at + // here is not the entire place. + let layout = if let Place::Base(_) = mir_place { + layout + } else { + None + }; + + self.access_local(self.frame(), *local, layout)? + } + PlaceBase::Static(place_static) => { + self.eval_static_to_mplace(place_static)?.into() + } + }; - _ => self.eval_place_to_mplace(mir_place)?.into(), - }; + for proj in place_projection { + op = self.operand_projection(op, &proj.elem)? + } - trace!("eval_place_to_op: got {:?}", *op); - Ok(op) + trace!("eval_place_to_op: got {:?}", *op); + Ok(op) + }) } /// Evaluate the operand, returning a place where you can then find the data. - /// if you already know the layout, you can save two some table lookups + /// If you already know the layout, you can save two table lookups /// by passing it in here. pub fn eval_operand( &self, mir_op: &mir::Operand<'tcx>, layout: Option>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { use rustc::mir::Operand::*; let op = match *mir_op { // FIXME: do some more logic on `move` to invalidate the old location @@ -547,7 +490,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> Move(ref place) => self.eval_place_to_op(place, layout)?, - Constant(ref constant) => self.eval_lazy_const_to_op(*constant.literal, layout)?, + Constant(ref constant) => self.eval_const_to_op(constant.literal, layout)?, }; trace!("{:?}: {:?}", mir_op, *op); Ok(op) @@ -557,90 +500,97 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> pub(super) fn eval_operands( &self, ops: &[mir::Operand<'tcx>], - ) -> EvalResult<'tcx, Vec>> { + ) -> InterpResult<'tcx, Vec>> { ops.into_iter() .map(|op| self.eval_operand(op, None)) .collect() } - // Used when Miri runs into a constant, and by const propagation. - crate fn eval_lazy_const_to_op( + // Used when the miri-engine runs into a constant and for extracting information from constants + // in patterns via the `const_eval` module + crate fn eval_const_to_op( &self, - val: ty::LazyConst<'tcx>, + val: &'tcx ty::Const<'tcx>, layout: Option>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { - trace!("const_to_op: {:?}", val); - match val { - ty::LazyConst::Unevaluated(def_id, substs) => { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + let tag_scalar = |scalar| match scalar { + Scalar::Ptr(ptr) => Scalar::Ptr(self.tag_static_base_pointer(ptr)), + Scalar::Raw { data, size } => Scalar::Raw { data, size }, + }; + // Early-return cases. + match val.val { + ConstValue::Param(_) => return err!(TooGeneric), // FIXME(oli-obk): try to monomorphize + ConstValue::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; return Ok(OpTy::from(self.const_eval_raw(GlobalId { instance, promoted: None, })?)); - }, - ty::LazyConst::Evaluated(c) => self.const_to_op(c, layout), + } + _ => {} } - } - - // Used when the miri-engine runs into a constant and for extracting information from constants - // in patterns via the `const_eval` module - crate fn const_to_op( - &self, - val: ty::Const<'tcx>, - layout: Option>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + // Other cases need layout. let layout = from_known_layout(layout, || { - let ty = self.monomorphize(val.ty)?; - self.layout_of(ty) + self.layout_of(self.monomorphize(val.ty)?) })?; let op = match val.val { - ConstValue::ByRef(ptr, alloc) => { + ConstValue::ByRef { offset, align, alloc } => { + let id = self.tcx.alloc_map.lock().create_memory_alloc(alloc); // We rely on mutability being set correctly in that allocation to prevent writes - // where none should happen -- and for `static mut`, we copy on demand anyway. - Operand::Indirect( - MemPlace::from_ptr(ptr, alloc.align) - ).with_default_tag() + // where none should happen. + let ptr = self.tag_static_base_pointer(Pointer::new(id, offset)); + Operand::Indirect(MemPlace::from_ptr(ptr, align)) }, - ConstValue::Slice(a, b) => - Operand::Immediate(Immediate::ScalarPair( - a.into(), - Scalar::from_uint(b, self.tcx.data_layout.pointer_size).into(), - )).with_default_tag(), ConstValue::Scalar(x) => - Operand::Immediate(Immediate::Scalar(x.into())).with_default_tag(), + Operand::Immediate(Immediate::Scalar(tag_scalar(x).into())), + ConstValue::Slice { data, start, end } => { + // We rely on mutability being set correctly in `data` to prevent writes + // where none should happen. + let ptr = Pointer::new( + self.tcx.alloc_map.lock().create_memory_alloc(data), + Size::from_bytes(start as u64), // offset: `start` + ); + Operand::Immediate(Immediate::new_slice( + self.tag_static_base_pointer(ptr).into(), + (end - start) as u64, // len: `end - start` + self, + )) + } + ConstValue::Param(..) | + ConstValue::Infer(..) | + ConstValue::Placeholder(..) | + ConstValue::Unevaluated(..) => + bug!("eval_const_to_op: Unexpected ConstValue {:?}", val), }; - Ok(OpTy { - op, - layout, - }) + Ok(OpTy { op, layout }) } /// Read discriminant, return the runtime value as well as the variant index. pub fn read_discriminant( &self, rval: OpTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, (u128, VariantIdx)> { + ) -> InterpResult<'tcx, (u128, VariantIdx)> { trace!("read_discriminant_value {:#?}", rval.layout); - match rval.layout.variants { + let (discr_kind, discr_index) = match rval.layout.variants { layout::Variants::Single { index } => { - let discr_val = rval.layout.ty.ty_adt_def().map_or( + let discr_val = rval.layout.ty.discriminant_for_variant(*self.tcx, index).map_or( index.as_u32() as u128, - |def| def.discriminant_for_variant(*self.tcx, index).val); + |discr| discr.val); return Ok((discr_val, index)); } - layout::Variants::Tagged { .. } | - layout::Variants::NicheFilling { .. } => {}, - } + layout::Variants::Multiple { ref discr_kind, discr_index, .. } => + (discr_kind, discr_index), + }; + // read raw discriminant value - let discr_op = self.operand_field(rval, 0)?; + let discr_op = self.operand_field(rval, discr_index as u64)?; let discr_val = self.read_immediate(discr_op)?; let raw_discr = discr_val.to_scalar_or_undef(); trace!("discr value: {:?}", raw_discr); // post-process - Ok(match rval.layout.variants { - layout::Variants::Single { .. } => bug!(), - layout::Variants::Tagged { .. } => { + Ok(match *discr_kind { + layout::DiscriminantKind::Tag => { let bits_discr = match raw_discr.to_bits(discr_val.layout.size) { Ok(raw_discr) => raw_discr, Err(_) => return err!(InvalidDiscriminant(raw_discr.erase_tag())), @@ -661,34 +611,37 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> bits_discr }; // Make sure we catch invalid discriminants - let index = rval.layout.ty - .ty_adt_def() - .expect("tagged layout for non adt") - .discriminants(self.tcx.tcx) - .find(|(_, var)| var.val == real_discr) - .ok_or_else(|| EvalErrorKind::InvalidDiscriminant(raw_discr.erase_tag()))?; + let index = match &rval.layout.ty.sty { + ty::Adt(adt, _) => adt + .discriminants(self.tcx.tcx) + .find(|(_, var)| var.val == real_discr), + ty::Generator(def_id, substs, _) => substs + .discriminants(*def_id, self.tcx.tcx) + .find(|(_, var)| var.val == real_discr), + _ => bug!("tagged layout for non-adt non-generator"), + }.ok_or_else(|| InterpError::InvalidDiscriminant(raw_discr.erase_tag()))?; (real_discr, index.0) }, - layout::Variants::NicheFilling { + layout::DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start, - .. } => { let variants_start = niche_variants.start().as_u32() as u128; let variants_end = niche_variants.end().as_u32() as u128; - match raw_discr { - ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) => { + let raw_discr = raw_discr.not_undef() + .map_err(|_| InterpError::InvalidDiscriminant(ScalarMaybeUndef::Undef))?; + match raw_discr.to_bits_or_ptr(discr_val.layout.size, self) { + Err(ptr) => { // The niche must be just 0 (which an inbounds pointer value never is) let ptr_valid = niche_start == 0 && variants_start == variants_end && - self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok(); + !self.memory.ptr_may_be_null(ptr); if !ptr_valid { - return err!(InvalidDiscriminant(raw_discr.erase_tag())); + return err!(InvalidDiscriminant(raw_discr.erase_tag().into())); } (dataful_variant.as_u32() as u128, dataful_variant) }, - ScalarMaybeUndef::Scalar(Scalar::Bits { bits: raw_discr, size }) => { - assert_eq!(size as u64, discr_val.layout.size.bytes()); + Ok(raw_discr) => { let adjusted_discr = raw_discr.wrapping_sub(niche_start) .wrapping_add(variants_start); if variants_start <= adjusted_discr && adjusted_discr <= variants_end { @@ -703,8 +656,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> (dataful_variant.as_u32() as u128, dataful_variant) } }, - ScalarMaybeUndef::Undef => - return err!(InvalidDiscriminant(ScalarMaybeUndef::Undef)), } } }) diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index b3b9c742d6c28..029a440f34e72 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -1,14 +1,13 @@ use rustc::mir; -use rustc::ty::{self, layout::{Size, TyLayout}}; +use rustc::ty::{self, layout::TyLayout}; use syntax::ast::FloatTy; -use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; -use rustc::mir::interpret::{EvalResult, Scalar}; +use rustc::mir::interpret::{InterpResult, Scalar}; -use super::{EvalContext, PlaceTy, Immediate, Machine, ImmTy}; +use super::{InterpretCx, PlaceTy, Immediate, Machine, ImmTy}; -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> { /// Applies the binary operation `op` to the two operands and writes a tuple of the result /// and a boolean signifying the potential overflow to the destination. pub fn binop_with_overflow( @@ -17,7 +16,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> left: ImmTy<'tcx, M::PointerTag>, right: ImmTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let (val, overflowed) = self.binary_op(op, left, right)?; let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into()); self.write_immediate(val, dest) @@ -31,19 +30,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> left: ImmTy<'tcx, M::PointerTag>, right: ImmTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let (val, _overflowed) = self.binary_op(op, left, right)?; self.write_scalar(val, dest) } } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> { fn binary_char_op( &self, bin_op: mir::BinOp, l: char, r: char, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> (Scalar, bool) { use rustc::mir::BinOp::*; let res = match bin_op { @@ -55,7 +54,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> Ge => l >= r, _ => bug!("Invalid operation on char: {:?}", bin_op), }; - return Ok((Scalar::from_bool(res), false)); + return (Scalar::from_bool(res), false); } fn binary_bool_op( @@ -63,7 +62,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> bin_op: mir::BinOp, l: bool, r: bool, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> (Scalar, bool) { use rustc::mir::BinOp::*; let res = match bin_op { @@ -78,46 +77,32 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> BitXor => l ^ r, _ => bug!("Invalid operation on bool: {:?}", bin_op), }; - return Ok((Scalar::from_bool(res), false)); + return (Scalar::from_bool(res), false); } - fn binary_float_op( + fn binary_float_op>>( &self, bin_op: mir::BinOp, - fty: FloatTy, - // passing in raw bits - l: u128, - r: u128, - ) -> EvalResult<'tcx, (Scalar, bool)> { + l: F, + r: F, + ) -> (Scalar, bool) { use rustc::mir::BinOp::*; - macro_rules! float_math { - ($ty:path, $size:expr) => {{ - let l = <$ty>::from_bits(l); - let r = <$ty>::from_bits(r); - let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| - Scalar::from_uint(res.value.to_bits(), Size::from_bytes($size)); - let val = match bin_op { - Eq => Scalar::from_bool(l == r), - Ne => Scalar::from_bool(l != r), - Lt => Scalar::from_bool(l < r), - Le => Scalar::from_bool(l <= r), - Gt => Scalar::from_bool(l > r), - Ge => Scalar::from_bool(l >= r), - Add => bitify(l + r), - Sub => bitify(l - r), - Mul => bitify(l * r), - Div => bitify(l / r), - Rem => bitify(l % r), - _ => bug!("invalid float op: `{:?}`", bin_op), - }; - return Ok((val, false)); - }}; - } - match fty { - FloatTy::F32 => float_math!(Single, 4), - FloatTy::F64 => float_math!(Double, 8), - } + let val = match bin_op { + Eq => Scalar::from_bool(l == r), + Ne => Scalar::from_bool(l != r), + Lt => Scalar::from_bool(l < r), + Le => Scalar::from_bool(l <= r), + Gt => Scalar::from_bool(l > r), + Ge => Scalar::from_bool(l >= r), + Add => (l + r).value.into(), + Sub => (l - r).value.into(), + Mul => (l * r).value.into(), + Div => (l / r).value.into(), + Rem => (l % r).value.into(), + _ => bug!("invalid float op: `{:?}`", bin_op), + }; + return (val, false); } fn binary_int_op( @@ -128,7 +113,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> left_layout: TyLayout<'tcx>, r: u128, right_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; // Shift ops can have an RHS with a different numeric type. @@ -279,35 +264,42 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> bin_op: mir::BinOp, left: ImmTy<'tcx, M::PointerTag>, right: ImmTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool)> { trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, *left, left.layout.ty, *right, right.layout.ty); match left.layout.ty.sty { ty::Char => { assert_eq!(left.layout.ty, right.layout.ty); - let left = left.to_scalar()?.to_char()?; - let right = right.to_scalar()?.to_char()?; - self.binary_char_op(bin_op, left, right) + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?)) } ty::Bool => { assert_eq!(left.layout.ty, right.layout.ty); - let left = left.to_scalar()?.to_bool()?; - let right = right.to_scalar()?.to_bool()?; - self.binary_bool_op(bin_op, left, right) + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?)) } ty::Float(fty) => { assert_eq!(left.layout.ty, right.layout.ty); - let left = left.to_bits()?; - let right = right.to_bits()?; - self.binary_float_op(bin_op, fty, left, right) + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(match fty { + FloatTy::F32 => self.binary_float_op(bin_op, left.to_f32()?, right.to_f32()?), + FloatTy::F64 => self.binary_float_op(bin_op, left.to_f64()?, right.to_f64()?), + }) } _ => { // Must be integer(-like) types. Don't forget about == on fn pointers. - assert!(left.layout.ty.is_integral() || left.layout.ty.is_unsafe_ptr() || - left.layout.ty.is_fn()); - assert!(right.layout.ty.is_integral() || right.layout.ty.is_unsafe_ptr() || - right.layout.ty.is_fn()); + assert!( + left.layout.ty.is_integral() || + left.layout.ty.is_unsafe_ptr() || left.layout.ty.is_fn_ptr(), + "Unexpected LHS type {:?} for BinOp {:?}", left.layout.ty, bin_op); + assert!( + right.layout.ty.is_integral() || + right.layout.ty.is_unsafe_ptr() || right.layout.ty.is_fn_ptr(), + "Unexpected RHS type {:?} for BinOp {:?}", right.layout.ty, bin_op); // Handle operations that support pointer values if left.to_scalar_ptr()?.is_ptr() || @@ -329,14 +321,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> &self, un_op: mir::UnOp, val: ImmTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { use rustc::mir::UnOp::*; - use rustc_apfloat::ieee::{Single, Double}; - use rustc_apfloat::Float; let layout = val.layout; let val = val.to_scalar()?; - trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty.sty); + trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty); match layout.ty.sty { ty::Bool => { @@ -348,17 +338,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> Ok(Scalar::from_bool(res)) } ty::Float(fty) => { - let val = val.to_bits(layout.size)?; let res = match (un_op, fty) { - (Neg, FloatTy::F32) => Single::to_bits(-Single::from_bits(val)), - (Neg, FloatTy::F64) => Double::to_bits(-Double::from_bits(val)), + (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?), + (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), _ => bug!("Invalid float op {:?}", un_op) }; - Ok(Scalar::from_uint(res, layout.size)) + Ok(res) } _ => { assert!(layout.ty.is_integral()); - let val = val.to_bits(layout.size)?; + let val = self.force_bits(val, layout.size)?; let res = match un_op { Not => !val, Neg => { diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 4df274bc9df97..1351b5bb8bd88 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -5,7 +5,6 @@ use std::convert::TryFrom; use std::hash::Hash; -use rustc::hir; use rustc::mir; use rustc::mir::interpret::truncate; use rustc::ty::{self, Ty}; @@ -13,9 +12,9 @@ use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, Va use rustc::ty::TypeFoldable; use super::{ - GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic, - EvalContext, Machine, AllocMap, AllocationExtra, - RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind + GlobalId, AllocId, Allocation, Scalar, InterpResult, Pointer, PointerArithmetic, + InterpretCx, Machine, AllocMap, AllocationExtra, + RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind, LocalValue }; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -83,23 +82,19 @@ impl<'tcx, Tag> From> for PlaceTy<'tcx, Tag> { } } -impl MemPlace { +impl MemPlace { + /// Replace ptr tag, maintain vtable tag (if any) #[inline] - pub fn with_default_tag(self) -> MemPlace - where Tag: Default - { + pub fn replace_tag(self, new_tag: Tag) -> Self { MemPlace { - ptr: self.ptr.with_default_tag(), + ptr: self.ptr.erase_tag().with_tag(new_tag), align: self.align, - meta: self.meta.map(Scalar::with_default_tag), + meta: self.meta, } } -} -impl MemPlace { #[inline] - pub fn erase_tag(self) -> MemPlace - { + pub fn erase_tag(self) -> MemPlace { MemPlace { ptr: self.ptr.erase_tag(), align: self.align, @@ -107,16 +102,6 @@ impl MemPlace { } } - #[inline] - pub fn with_tag(self, new_tag: Tag) -> Self - { - MemPlace { - ptr: self.ptr.with_tag(new_tag), - align: self.align, - meta: self.meta, - } - } - #[inline(always)] pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self { MemPlace { @@ -145,7 +130,7 @@ impl MemPlace { /// metact the ptr part of the mplace #[inline(always)] - pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> { + pub fn to_ptr(self) -> InterpResult<'tcx, Pointer> { // At this point, we forget about the alignment information -- // the place has been turned into a reference, and no matter where it came from, // it now must be aligned. @@ -167,7 +152,7 @@ impl MemPlace { offset: Size, meta: Option>, cx: &impl HasDataLayout, - ) -> EvalResult<'tcx, Self> { + ) -> InterpResult<'tcx, Self> { Ok(MemPlace { ptr: self.ptr.ptr_offset(offset, cx)?, align: self.align.restrict_for_offset(offset), @@ -189,11 +174,11 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { } } + /// Replace ptr tag, maintain vtable tag (if any) #[inline] - pub fn with_tag(self, new_tag: Tag) -> Self - { + pub fn replace_tag(self, new_tag: Tag) -> Self { MPlaceTy { - mplace: self.mplace.with_tag(new_tag), + mplace: self.mplace.replace_tag(new_tag), layout: self.layout, } } @@ -205,7 +190,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { meta: Option>, layout: TyLayout<'tcx>, cx: &impl HasDataLayout, - ) -> EvalResult<'tcx, Self> { + ) -> InterpResult<'tcx, Self> { Ok(MPlaceTy { mplace: self.mplace.offset(offset, meta, cx)?, layout, @@ -218,7 +203,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { } #[inline] - pub(super) fn len(self, cx: &impl HasDataLayout) -> EvalResult<'tcx, u64> { + pub(super) fn len(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { if self.layout.is_unsized() { // We need to consult `meta` metadata match self.layout.ty.sty { @@ -237,9 +222,9 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { } #[inline] - pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer> { + pub(super) fn vtable(self) -> Scalar { match self.layout.ty.sty { - ty::Dynamic(..) => self.mplace.meta.unwrap().to_ptr(), + ty::Dynamic(..) => self.mplace.meta.unwrap(), _ => bug!("vtable not supported on type {:?}", self.layout.ty), } } @@ -247,10 +232,10 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { #[inline(always)] - pub fn try_as_mplace(self) -> Result, Immediate> { + pub fn try_as_mplace(self) -> Result, ImmTy<'tcx, Tag>> { match *self { Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }), - Operand::Immediate(imm) => Err(imm), + Operand::Immediate(imm) => Err(ImmTy { imm, layout: self.layout }), } } @@ -292,7 +277,7 @@ impl<'tcx, Tag: ::std::fmt::Debug> Place { } #[inline] - pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> { + pub fn to_ptr(self) -> InterpResult<'tcx, Pointer> { self.to_mem_place().to_ptr() } } @@ -305,14 +290,14 @@ impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> { } // separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385 -impl<'a, 'mir, 'tcx, Tag, M> EvalContext<'a, 'mir, 'tcx, M> +impl<'mir, 'tcx, Tag, M> InterpretCx<'mir, 'tcx, M> where // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 - Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static, - M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>, + Tag: ::std::fmt::Debug + Copy + Eq + Hash + 'static, + M: Machine<'mir, 'tcx, PointerTag = Tag>, // FIXME: Working around https://github.com/rust-lang/rust/issues/24159 M::MemoryMap: AllocMap, Allocation)>, - M::AllocExtra: AllocationExtra, + M::AllocExtra: AllocationExtra, { /// Take a value, which represents a (thin or fat) reference, and make it a place. /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. @@ -321,7 +306,7 @@ where pub fn ref_to_mplace( &self, val: ImmTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty; let layout = self.layout_of(pointee_type)?; @@ -339,44 +324,36 @@ where // Take an operand, representing a pointer, and dereference it to a place -- that // will always be a MemPlace. Lives in `place.rs` because it creates a place. - // This calls the "deref" machine hook, and counts as a deref as far as - // Stacked Borrows is concerned. pub fn deref_operand( &self, src: OpTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { let val = self.read_immediate(src)?; trace!("deref to {} on {:?}", val.layout.ty, *val); - let mut place = self.ref_to_mplace(val)?; - // Pointer tag tracking might want to adjust the tag. - let mutbl = match val.layout.ty.sty { - // `builtin_deref` considers boxes immutable, that's useless for our purposes - ty::Ref(_, _, mutbl) => Some(mutbl), - ty::Adt(def, _) if def.is_box() => Some(hir::MutMutable), - ty::RawPtr(_) => None, - _ => bug!("Unexpected pointer type {}", val.layout.ty.sty), - }; - place.mplace.ptr = M::tag_dereference(self, place, mutbl)?; - Ok(place) + self.ref_to_mplace(val) } - /// Offset a pointer to project to a field. Unlike place_field, this is always - /// possible without allocating, so it can take &self. Also return the field's layout. + /// Offset a pointer to project to a field. Unlike `place_field`, this is always + /// possible without allocating, so it can take `&self`. Also return the field's layout. /// This supports both struct and array fields. #[inline(always)] pub fn mplace_field( &self, base: MPlaceTy<'tcx, M::PointerTag>, field: u64, - ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // Not using the layout method because we want to compute on u64 let offset = match base.layout.fields { layout::FieldPlacement::Arbitrary { ref offsets, .. } => offsets[usize::try_from(field).unwrap()], layout::FieldPlacement::Array { stride, .. } => { let len = base.len(self)?; - assert!(field < len, "Tried to access element {} of array/slice with length {}", - field, len); + if field >= len { + // This can be violated because this runs during promotion on code where the + // type system has not yet ensured that such things don't happen. + debug!("Tried to access element {} of array/slice with length {}", field, len); + return err!(BoundsCheck { len, index: field }); + } stride * field } layout::FieldPlacement::Union(count) => { @@ -423,8 +400,7 @@ where pub fn mplace_array_fields( &self, base: MPlaceTy<'tcx, Tag>, - ) -> - EvalResult<'tcx, impl Iterator>> + 'a> + ) -> InterpResult<'tcx, impl Iterator>> + 'tcx> { let len = base.len(self)?; // also asserts that we have a type where this makes sense let stride = match base.layout.fields { @@ -441,7 +417,7 @@ where base: MPlaceTy<'tcx, M::PointerTag>, from: u64, to: u64, - ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { let len = base.len(self)?; // also asserts that we have a type where this makes sense assert!(from <= len - to); @@ -475,7 +451,7 @@ where &self, base: MPlaceTy<'tcx, M::PointerTag>, variant: VariantIdx, - ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // Downcasts only change the layout assert!(base.meta.is_none()); Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base }) @@ -486,7 +462,7 @@ where &self, base: MPlaceTy<'tcx, M::PointerTag>, proj_elem: &mir::PlaceElem<'tcx>, - ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { use rustc::mir::ProjectionElem::*; Ok(match *proj_elem { Field(field, _) => self.mplace_field(base, field.index() as u64)?, @@ -497,7 +473,7 @@ where let layout = self.layout_of(self.tcx.types.usize)?; let n = self.access_local(self.frame(), local, Some(layout))?; let n = self.read_scalar(n)?; - let n = n.to_bits(self.tcx.data_layout.pointer_size)?; + let n = self.force_bits(n.not_undef()?, self.tcx.data_layout.pointer_size)?; self.mplace_field(base, u64::try_from(n).unwrap())? } @@ -531,7 +507,7 @@ where &mut self, base: PlaceTy<'tcx, M::PointerTag>, field: u64, - ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { // FIXME: We could try to be smarter and avoid allocation for fields that span the // entire place. let mplace = self.force_allocation(base)?; @@ -542,7 +518,7 @@ where &self, base: PlaceTy<'tcx, M::PointerTag>, variant: VariantIdx, - ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { // Downcast just changes the layout Ok(match base.place { Place::Ptr(mplace) => @@ -558,8 +534,8 @@ where pub fn place_projection( &mut self, base: PlaceTy<'tcx, M::PointerTag>, - proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>, - ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + proj_elem: &mir::ProjectionElem>, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { use rustc::mir::ProjectionElem::*; Ok(match *proj_elem { Field(field, _) => self.place_field(base, field.index() as u64)?, @@ -576,45 +552,49 @@ where /// Evaluate statics and promoteds to an `MPlace`. Used to share some code between /// `eval_place` and `eval_place_to_op`. - pub(super) fn eval_place_to_mplace( + pub(super) fn eval_static_to_mplace( &self, - mir_place: &mir::Place<'tcx> - ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - use rustc::mir::Place::*; - use rustc::mir::PlaceBase; - Ok(match *mir_place { - Base(PlaceBase::Promoted(ref promoted)) => { + place_static: &mir::Static<'tcx> + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + use rustc::mir::StaticKind; + + Ok(match place_static.kind { + StaticKind::Promoted(promoted) => { let instance = self.frame().instance; self.const_eval_raw(GlobalId { instance, - promoted: Some(promoted.0), + promoted: Some(promoted), })? } - Base(PlaceBase::Static(ref static_)) => { - assert!(!static_.ty.needs_subst()); - let layout = self.layout_of(static_.ty)?; - let instance = ty::Instance::mono(*self.tcx, static_.def_id); + StaticKind::Static(def_id) => { + let ty = place_static.ty; + assert!(!ty.needs_subst()); + let layout = self.layout_of(ty)?; + let instance = ty::Instance::mono(*self.tcx, def_id); let cid = GlobalId { instance, promoted: None }; // Just create a lazy reference, so we can support recursive statics. - // tcx takes are of assigning every static one and only one unique AllocId. + // tcx takes care of assigning every static one and only one unique AllocId. // When the data here is ever actually used, memory will notice, // and it knows how to deal with alloc_id that are present in the // global table but not in its local memory: It calls back into tcx through // a query, triggering the CTFE machinery to actually turn this lazy reference // into a bunch of bytes. IOW, statics are evaluated with CTFE even when - // this EvalContext uses another Machine (e.g., in miri). This is what we - // want! This way, computing statics works concistently between codegen + // this InterpretCx uses another Machine (e.g., in miri). This is what we + // want! This way, computing statics works consistently between codegen // and miri: They use the same query to eventually obtain a `ty::Const` // and use that for further computation. - let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id()); - MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout) + // + // Notice that statics have *two* AllocIds: the lazy one, and the resolved + // one. Here we make sure that the interpreted program never sees the + // resolved ID. Also see the doc comment of `Memory::get_static_alloc`. + let alloc_id = self.tcx.alloc_map.lock().create_static_alloc(cid.instance.def_id()); + let ptr = self.tag_static_base_pointer(Pointer::from(alloc_id)); + MPlaceTy::from_aligned_ptr(ptr, layout) } - - _ => bug!("eval_place_to_mplace called on {:?}", mir_place), }) } @@ -622,39 +602,42 @@ where /// place; for reading, a more efficient alternative is `eval_place_for_read`. pub fn eval_place( &mut self, - mir_place: &mir::Place<'tcx> - ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { - use rustc::mir::Place::*; + mir_place: &mir::Place<'tcx>, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { use rustc::mir::PlaceBase; - let place = match *mir_place { - Base(PlaceBase::Local(mir::RETURN_PLACE)) => match self.frame().return_place { - Some(return_place) => - // We use our layout to verify our assumption; caller will validate - // their layout on return. - PlaceTy { - place: *return_place, - layout: self.layout_of(self.monomorphize(self.frame().mir.return_ty())?)?, + + mir_place.iterate(|place_base, place_projection| { + let mut place = match place_base { + PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place { + Some(return_place) => { + // We use our layout to verify our assumption; caller will validate + // their layout on return. + PlaceTy { + place: *return_place, + layout: self + .layout_of(self.monomorphize(self.frame().body.return_ty())?)?, + } + } + None => return err!(InvalidNullPointerUsage), + }, + PlaceBase::Local(local) => PlaceTy { + // This works even for dead/uninitialized locals; we check further when writing + place: Place::Local { + frame: self.cur_frame(), + local: *local, }, - None => return err!(InvalidNullPointerUsage), - }, - Base(PlaceBase::Local(local)) => PlaceTy { - place: Place::Local { - frame: self.cur_frame(), - local, + layout: self.layout_of_local(self.frame(), *local, None)?, }, - layout: self.layout_of_local(self.frame(), local, None)?, - }, + PlaceBase::Static(place_static) => self.eval_static_to_mplace(place_static)?.into(), + }; - Projection(ref proj) => { - let place = self.eval_place(&proj.base)?; - self.place_projection(place, &proj.elem)? + for proj in place_projection { + place = self.place_projection(place, &proj.elem)? } - _ => self.eval_place_to_mplace(mir_place)?.into(), - }; - - self.dump_place(place.place); - Ok(place) + self.dump_place(place.place); + Ok(place) + }) } /// Write a scalar to a place @@ -662,7 +645,7 @@ where &mut self, val: impl Into>, dest: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { self.write_immediate(Immediate::Scalar(val.into()), dest) } @@ -672,12 +655,29 @@ where &mut self, src: Immediate, dest: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { self.write_immediate_no_validate(src, dest)?; if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(self.place_to_op(dest)?, vec![], None, /*const_mode*/false)?; + self.validate_operand(self.place_to_op(dest)?, vec![], None)?; + } + + Ok(()) + } + + /// Write an `Immediate` to memory. + #[inline(always)] + pub fn write_immediate_to_mplace( + &mut self, + src: Immediate, + dest: MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + self.write_immediate_to_mplace_no_validate(src, dest)?; + + if M::enforce_validity(self) { + // Data got changed, better make sure it matches the type! + self.validate_operand(dest.into(), vec![], None)?; } Ok(()) @@ -690,7 +690,7 @@ where &mut self, src: Immediate, dest: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { if cfg!(debug_assertions) { // This is a very common path, avoid some checks in release mode assert!(!dest.layout.is_unsized(), "Cannot write unsized data"); @@ -698,7 +698,7 @@ where Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Ptr(_))) => assert_eq!(self.pointer_size(), dest.layout.size, "Size mismatch when writing pointer"), - Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { size, .. })) => + Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Raw { size, .. })) => assert_eq!(Size::from_bytes(size.into()), dest.layout.size, "Size mismatch when writing bits"), Immediate::Scalar(ScalarMaybeUndef::Undef) => {}, // undef can have any size @@ -713,16 +713,19 @@ where // but not factored as a separate function. let mplace = match dest.place { Place::Local { frame, local } => { - match *self.stack[frame].locals[local].access_mut()? { - Operand::Immediate(ref mut dest_val) => { - // Yay, we can just change the local directly. - *dest_val = src; + match self.stack[frame].locals[local].access_mut()? { + Ok(local) => { + // Local can be updated in-place. + *local = LocalValue::Live(Operand::Immediate(src)); return Ok(()); - }, - Operand::Indirect(mplace) => mplace, // already in memory + } + Err(mplace) => { + // The local is in memory, go on below. + mplace + } } }, - Place::Ptr(mplace) => mplace, // already in memory + Place::Ptr(mplace) => mplace, // already referring to memory }; let dest = MPlaceTy { mplace, layout: dest.layout }; @@ -731,27 +734,25 @@ where } /// Write an immediate to memory. - /// If you use this you are responsible for validating that things git copied at the + /// If you use this you are responsible for validating that things got copied at the /// right type. fn write_immediate_to_mplace_no_validate( &mut self, value: Immediate, dest: MPlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let (ptr, ptr_align) = dest.to_scalar_ptr_align(); // Note that it is really important that the type here is the right one, and matches the // type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here // to handle padding properly, which is only correct if we never look at this data with the // wrong type. + assert!(!dest.layout.is_unsized()); - // Nothing to do for ZSTs, other than checking alignment - if dest.layout.is_zst() { - return self.memory.check_align(ptr, ptr_align); - } + let ptr = match self.memory.check_ptr_access(ptr, dest.layout.size, ptr_align)? { + Some(ptr) => ptr, + None => return Ok(()), // zero-sized access + }; - // check for integer pointers before alignment to report better errors - let ptr = ptr.to_ptr()?; - self.memory.check_align(ptr.into(), ptr_align)?; let tcx = &*self.tcx; // FIXME: We should check that there are dest.layout.size many bytes available in // memory. The code below is not sufficient, with enough padding it might not @@ -768,6 +769,9 @@ where ) } Immediate::ScalarPair(a_val, b_val) => { + // We checked `ptr_align` above, so all fields will have the alignment they need. + // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, + // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. let (a, b) = match dest.layout.abi { layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value), _ => bug!("write_immediate_to_mplace: invalid ScalarPair layout: {:#?}", @@ -775,11 +779,8 @@ where }; let (a_size, b_size) = (a.size(self), b.size(self)); let b_offset = a_size.align_to(b.align(self).abi); - let b_align = ptr_align.restrict_for_offset(b_offset); let b_ptr = ptr.offset(b_offset, self)?; - self.memory.check_align(b_ptr.into(), b_align)?; - // It is tempting to verify `b_offset` against `layout.fields.offset(1)`, // but that does not work: We could be a newtype around a pair, then the // fields do not match the `ScalarPair` components. @@ -801,12 +802,12 @@ where &mut self, src: OpTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { self.copy_op_no_validate(src, dest)?; if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(self.place_to_op(dest)?, vec![], None, /*const_mode*/false)?; + self.validate_operand(self.place_to_op(dest)?, vec![], None)?; } Ok(()) @@ -814,15 +815,13 @@ where /// Copies the data from an operand to a place. This does not support transmuting! /// Use `copy_op_transmute` if the layouts could disagree. - /// Also, if you use this you are responsible for validating that things git copied at the + /// Also, if you use this you are responsible for validating that things get copied at the /// right type. fn copy_op_no_validate( &mut self, src: OpTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx> { - debug_assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(), - "Cannot copy unsized data"); + ) -> InterpResult<'tcx> { // We do NOT compare the types for equality, because well-typed code can // actually "transmute" `&mut T` to `&T` in an assignment without a cast. assert!(src.layout.details == dest.layout.details, @@ -831,23 +830,30 @@ where // Let us see if the layout is simple so we take a shortcut, avoid force_allocation. let src = match self.try_read_immediate(src)? { Ok(src_val) => { + assert!(!src.layout.is_unsized(), "cannot have unsized immediates"); // Yay, we got a value that we can write directly. // FIXME: Add a check to make sure that if `src` is indirect, // it does not overlap with `dest`. - return self.write_immediate_no_validate(src_val, dest); + return self.write_immediate_no_validate(*src_val, dest); } Err(mplace) => mplace, }; // Slow path, this does not fit into an immediate. Just memcpy. trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty); - let dest = self.force_allocation(dest)?; - let (src_ptr, src_align) = src.to_scalar_ptr_align(); - let (dest_ptr, dest_align) = dest.to_scalar_ptr_align(); + // This interprets `src.meta` with the `dest` local's layout, if an unsized local + // is being initialized! + let (dest, size) = self.force_allocation_maybe_sized(dest, src.meta)?; + let size = size.unwrap_or_else(|| { + assert!(!dest.layout.is_unsized(), + "Cannot copy into already initialized unsized place"); + dest.layout.size + }); + assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances"); self.memory.copy( - src_ptr, src_align, - dest_ptr, dest_align, - dest.layout.size, + src.ptr, src.align, + dest.ptr, dest.align, + size, /*nonoverlapping*/ true, )?; @@ -860,16 +866,18 @@ where &mut self, src: OpTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { if src.layout.details == dest.layout.details { // Fast path: Just use normal `copy_op` return self.copy_op(src, dest); } - // We still require the sizes to match - debug_assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(), - "Cannot copy unsized data"); + // We still require the sizes to match. assert!(src.layout.size == dest.layout.size, "Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); + // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want + // to avoid that here. + assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(), + "Cannot transmute unsized data"); // The hard case is `ScalarPair`. `src` is already read from memory in this case, // using `src.layout` to figure out which bytes to use for the 1st and 2nd field. @@ -887,7 +895,7 @@ where if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(dest.into(), vec![], None, /*const_mode*/false)?; + self.validate_operand(dest.into(), vec![], None)?; } Ok(()) @@ -897,39 +905,69 @@ where /// If the place currently refers to a local that doesn't yet have a matching allocation, /// create such an allocation. /// This is essentially `force_to_memplace`. - pub fn force_allocation( + /// + /// This supports unsized types and returns the computed size to avoid some + /// redundant computation when copying; use `force_allocation` for a simpler, sized-only + /// version. + pub fn force_allocation_maybe_sized( &mut self, place: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - let mplace = match place.place { + meta: Option>, + ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option)> { + let (mplace, size) = match place.place { Place::Local { frame, local } => { - match *self.stack[frame].locals[local].access()? { - Operand::Indirect(mplace) => mplace, - Operand::Immediate(value) => { + match self.stack[frame].locals[local].access_mut()? { + Ok(local_val) => { // We need to make an allocation. // FIXME: Consider not doing anything for a ZST, and just returning // a fake pointer? Are we even called for ZST? + // We cannot hold on to the reference `local_val` while allocating, + // but we can hold on to the value in there. + let old_val = + if let LocalValue::Live(Operand::Immediate(value)) = *local_val { + Some(value) + } else { + None + }; + // We need the layout of the local. We can NOT use the layout we got, // that might e.g., be an inner field of a struct with `Scalar` layout, // that has different alignment than the outer field. + // We also need to support unsized types, and hence cannot use `allocate`. let local_layout = self.layout_of_local(&self.stack[frame], local, None)?; - let ptr = self.allocate(local_layout, MemoryKind::Stack); - // We don't have to validate as we can assume the local - // was already valid for its type. - self.write_immediate_to_mplace_no_validate(value, ptr)?; - let mplace = ptr.mplace; - // Update the local - *self.stack[frame].locals[local].access_mut()? = - Operand::Indirect(mplace); - mplace + let (size, align) = self.size_and_align_of(meta, local_layout)? + .expect("Cannot allocate for non-dyn-sized type"); + let ptr = self.memory.allocate(size, align, MemoryKind::Stack); + let mplace = MemPlace { ptr: ptr.into(), align, meta }; + if let Some(value) = old_val { + // Preserve old value. + // We don't have to validate as we can assume the local + // was already valid for its type. + let mplace = MPlaceTy { mplace, layout: local_layout }; + self.write_immediate_to_mplace_no_validate(value, mplace)?; + } + // Now we can call `access_mut` again, asserting it goes well, + // and actually overwrite things. + *self.stack[frame].locals[local].access_mut().unwrap().unwrap() = + LocalValue::Live(Operand::Indirect(mplace)); + (mplace, Some(size)) } + Err(mplace) => (mplace, None), // this already was an indirect local } } - Place::Ptr(mplace) => mplace + Place::Ptr(mplace) => (mplace, None) }; // Return with the original layout, so that the caller can go on - Ok(MPlaceTy { mplace, layout: place.layout }) + Ok((MPlaceTy { mplace, layout: place.layout }, size)) + } + + #[inline(always)] + pub fn force_allocation( + &mut self, + place: PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + Ok(self.force_allocation_maybe_sized(place, None)?.0) } pub fn allocate( @@ -937,46 +975,45 @@ where layout: TyLayout<'tcx>, kind: MemoryKind, ) -> MPlaceTy<'tcx, M::PointerTag> { - if layout.is_unsized() { - assert!(self.tcx.features().unsized_locals, "cannot alloc memory for unsized type"); - // FIXME: What should we do here? We should definitely also tag! - MPlaceTy::dangling(layout, self) - } else { - let ptr = self.memory.allocate(layout.size, layout.align.abi, kind); - let ptr = M::tag_new_allocation(self, ptr, kind); - MPlaceTy::from_aligned_ptr(ptr, layout) - } + let ptr = self.memory.allocate(layout.size, layout.align.abi, kind); + MPlaceTy::from_aligned_ptr(ptr, layout) } pub fn write_discriminant_index( &mut self, variant_index: VariantIdx, dest: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { match dest.layout.variants { layout::Variants::Single { index } => { assert_eq!(index, variant_index); } - layout::Variants::Tagged { ref tag, .. } => { - let adt_def = dest.layout.ty.ty_adt_def().unwrap(); - assert!(variant_index.as_usize() < adt_def.variants.len()); - let discr_val = adt_def - .discriminant_for_variant(*self.tcx, variant_index) - .val; + layout::Variants::Multiple { + discr_kind: layout::DiscriminantKind::Tag, + ref discr, + discr_index, + .. + } => { + assert!(dest.layout.ty.variant_range(*self.tcx).unwrap().contains(&variant_index)); + let discr_val = + dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val; // raw discriminants for enums are isize or bigger during // their computation, but the in-memory tag is the smallest possible // representation - let size = tag.value.size(self); + let size = discr.value.size(self); let discr_val = truncate(discr_val, size); - let discr_dest = self.place_field(dest, 0)?; + let discr_dest = self.place_field(dest, discr_index as u64)?; self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?; } - layout::Variants::NicheFilling { - dataful_variant, - ref niche_variants, - niche_start, + layout::Variants::Multiple { + discr_kind: layout::DiscriminantKind::Niche { + dataful_variant, + ref niche_variants, + niche_start, + }, + discr_index, .. } => { assert!( @@ -984,7 +1021,7 @@ where ); if variant_index != dataful_variant { let niche_dest = - self.place_field(dest, 0)?; + self.place_field(dest, discr_index as u64)?; let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); let niche_value = (niche_value as u128) .wrapping_add(niche_start); @@ -1002,21 +1039,19 @@ where pub fn raw_const_to_mplace( &self, raw: RawConst<'tcx>, - ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // This must be an allocation in `tcx` assert!(self.tcx.alloc_map.lock().get(raw.alloc_id).is_some()); + let ptr = self.tag_static_base_pointer(Pointer::from(raw.alloc_id)); let layout = self.layout_of(raw.ty)?; - Ok(MPlaceTy::from_aligned_ptr( - Pointer::new(raw.alloc_id, Size::ZERO).with_default_tag(), - layout, - )) + Ok(MPlaceTy::from_aligned_ptr(ptr, layout)) } /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. /// Also return some more information so drop doesn't have to run the same code twice. pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx, M::PointerTag>) - -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> { - let vtable = mplace.vtable()?; // also sanity checks the type + -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> { + let vtable = mplace.vtable(); // also sanity checks the type let (instance, ty) = self.read_drop_type_from_vtable(vtable)?; let layout = self.layout_of(ty)?; diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 0168e1301fa7a..ad631793a0827 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -12,7 +12,7 @@ use rustc::mir; use rustc::mir::interpret::{ AllocId, Pointer, Scalar, Relocations, Allocation, UndefMask, - EvalResult, EvalErrorKind, + InterpResult, InterpError, }; use rustc::ty::{self, TyCtxt}; @@ -28,30 +28,29 @@ use super::{Frame, Memory, Operand, MemPlace, Place, Immediate, ScalarMaybeUndef use crate::const_eval::CompileTimeInterpreter; #[derive(Default)] -pub(crate) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir> { - /// The set of all `EvalSnapshot` *hashes* observed by this detector. +pub(crate) struct InfiniteLoopDetector<'mir, 'tcx> { + /// The set of all `InterpSnapshot` *hashes* observed by this detector. /// /// When a collision occurs in this table, we store the full snapshot in /// `snapshots`. hashes: FxHashSet, - /// The set of all `EvalSnapshot`s observed by this detector. + /// The set of all `InterpSnapshot`s observed by this detector. /// - /// An `EvalSnapshot` will only be fully cloned once it has caused a + /// An `InterpSnapshot` will only be fully cloned once it has caused a /// collision in `hashes`. As a result, the detector must observe at least /// *two* full cycles of an infinite loop before it triggers. - snapshots: FxHashSet>, + snapshots: FxHashSet>, } -impl<'a, 'mir, 'tcx> InfiniteLoopDetector<'a, 'mir, 'tcx> -{ - pub fn observe_and_analyze<'b>( +impl<'mir, 'tcx> InfiniteLoopDetector<'mir, 'tcx> { + pub fn observe_and_analyze( &mut self, - tcx: &TyCtxt<'b, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, span: Span, - memory: &Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>, + memory: &Memory<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, stack: &[Frame<'mir, 'tcx>], - ) -> EvalResult<'tcx, ()> { + ) -> InterpResult<'tcx, ()> { // Compute stack's hash before copying anything let mut hcx = tcx.get_stable_hashing_context(); let mut hasher = StableHasher::::new(); @@ -72,13 +71,13 @@ impl<'a, 'mir, 'tcx> InfiniteLoopDetector<'a, 'mir, 'tcx> // We need to make a full copy. NOW things that to get really expensive. info!("snapshotting the state of the interpreter"); - if self.snapshots.insert(EvalSnapshot::new(memory, stack)) { + if self.snapshots.insert(InterpSnapshot::new(memory, stack)) { // Spurious collision or first cycle return Ok(()) } // Second cycle - Err(EvalErrorKind::InfiniteLoop.into()) + Err(InterpError::InfiniteLoop.into()) } } @@ -114,10 +113,11 @@ macro_rules! impl_snapshot_for { fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item { match *self { $( - $enum_name::$variant $( ( $(ref $field),* ) )? => + $enum_name::$variant $( ( $(ref $field),* ) )? => { $enum_name::$variant $( - ( $( __impl_snapshot_field!($field, __ctx $(, $delegate)?) ),* ), + ( $( __impl_snapshot_field!($field, __ctx $(, $delegate)?) ),* ) )? + } )* } } @@ -185,9 +185,9 @@ impl<'a, Ctx> Snapshot<'a, Ctx> for Scalar fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { match self { Scalar::Ptr(p) => Scalar::Ptr(p.snapshot(ctx)), - Scalar::Bits{ size, bits } => Scalar::Bits { + Scalar::Raw{ size, data } => Scalar::Raw { + data: *data, size: *size, - bits: *bits, }, } } @@ -250,11 +250,13 @@ impl_snapshot_for!(enum Operand { impl_stable_hash_for!(enum crate::interpret::LocalValue { Dead, + Uninitialized, Live(x), }); impl_snapshot_for!(enum LocalValue { - Live(v), Dead, + Uninitialized, + Live(v), }); impl<'a, Ctx> Snapshot<'a, Ctx> for Relocations @@ -302,7 +304,7 @@ impl_stable_hash_for!(enum crate::interpret::eval_context::StackPopCleanup { }); #[derive(Eq, PartialEq)] -struct FrameSnapshot<'a, 'tcx: 'a> { +struct FrameSnapshot<'a, 'tcx> { instance: &'a ty::Instance<'tcx>, span: &'a Span, return_to_block: &'a StackPopCleanup, @@ -312,8 +314,8 @@ struct FrameSnapshot<'a, 'tcx: 'a> { stmt: usize, } -impl_stable_hash_for!(impl<'mir, 'tcx: 'mir> for struct Frame<'mir, 'tcx> { - mir, +impl_stable_hash_for!(impl<> for struct Frame<'mir, 'tcx> { + body, instance, span, return_to_block, @@ -331,7 +333,7 @@ impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx> fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { let Frame { - mir: _, + body: _, instance, span, return_to_block, @@ -360,18 +362,18 @@ impl<'a, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a LocalState<'tcx> type Item = LocalValue<(), AllocIdSnapshot<'a>>; fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { - let LocalState { state, layout: _ } = self; - state.snapshot(ctx) + let LocalState { value, layout: _ } = self; + value.snapshot(ctx) } } impl_stable_hash_for!(struct LocalState<'tcx> { - state, + value, layout -> _, }); -impl<'a, 'b, 'mir, 'tcx: 'a+'mir> SnapshotContext<'b> - for Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>> +impl<'b, 'mir, 'tcx> SnapshotContext<'b> + for Memory<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { fn resolve(&'b self, id: &AllocId) -> Option<&'b Allocation> { self.get(*id).ok() @@ -381,18 +383,17 @@ impl<'a, 'b, 'mir, 'tcx: 'a+'mir> SnapshotContext<'b> /// The virtual machine state during const-evaluation at a given point in time. /// We assume the `CompileTimeInterpreter` has no interesting extra state that /// is worth considering here. -struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir> { - memory: Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>, +struct InterpSnapshot<'mir, 'tcx> { + memory: Memory<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, stack: Vec>, } -impl<'a, 'mir, 'tcx: 'a + 'mir> EvalSnapshot<'a, 'mir, 'tcx> -{ +impl InterpSnapshot<'mir, 'tcx> { fn new( - memory: &Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>, - stack: &[Frame<'mir, 'tcx>] + memory: &Memory<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, + stack: &[Frame<'mir, 'tcx>], ) -> Self { - EvalSnapshot { + InterpSnapshot { memory: memory.clone(), stack: stack.into(), } @@ -405,11 +406,9 @@ impl<'a, 'mir, 'tcx: 'a + 'mir> EvalSnapshot<'a, 'mir, 'tcx> // Start with the stack, iterate and recursively snapshot self.stack.iter().map(|frame| frame.snapshot(&self.memory)).collect() } - } -impl<'a, 'mir, 'tcx> Hash for EvalSnapshot<'a, 'mir, 'tcx> -{ +impl<'mir, 'tcx> Hash for InterpSnapshot<'mir, 'tcx> { fn hash(&self, state: &mut H) { // Implement in terms of hash stable, so that k1 == k2 -> hash(k1) == hash(k2) let mut hcx = self.memory.tcx.get_stable_hashing_context(); @@ -419,19 +418,17 @@ impl<'a, 'mir, 'tcx> Hash for EvalSnapshot<'a, 'mir, 'tcx> } } -impl_stable_hash_for!(impl<'tcx, 'b, 'mir> for struct EvalSnapshot<'b, 'mir, 'tcx> { +impl_stable_hash_for!(impl<> for struct InterpSnapshot<'mir, 'tcx> { // Not hashing memory: Avoid hashing memory all the time during execution memory -> _, stack, }); -impl<'a, 'mir, 'tcx> Eq for EvalSnapshot<'a, 'mir, 'tcx> -{} +impl<'mir, 'tcx> Eq for InterpSnapshot<'mir, 'tcx> {} -impl<'a, 'mir, 'tcx> PartialEq for EvalSnapshot<'a, 'mir, 'tcx> -{ +impl<'mir, 'tcx> PartialEq for InterpSnapshot<'mir, 'tcx> { fn eq(&self, other: &Self) -> bool { - // FIXME: This looks to be a *ridicolously expensive* comparison operation. + // FIXME: This looks to be a *ridiculously expensive* comparison operation. // Doesn't this make tons of copies? Either `snapshot` is very badly named, // or it does! self.snapshot() == other.snapshot() diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 656c13c16d9ed..2f99973b90d4a 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -1,12 +1,12 @@ -//! This module contains the `EvalContext` methods for executing a single step of the interpreter. +//! This module contains the `InterpretCx` methods for executing a single step of the interpreter. //! //! The main entry point is the `step` method. use rustc::mir; use rustc::ty::layout::LayoutOf; -use rustc::mir::interpret::{EvalResult, Scalar, PointerArithmetic}; +use rustc::mir::interpret::{InterpResult, Scalar, PointerArithmetic}; -use super::{EvalContext, Machine}; +use super::{InterpretCx, Machine}; /// Classify whether an operator is "left-homogeneous", i.e., the LHS has the /// same type as the result. @@ -35,8 +35,8 @@ fn binop_right_homogeneous(op: mir::BinOp) -> bool { } } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { - pub fn run(&mut self) -> EvalResult<'tcx> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> { + pub fn run(&mut self) -> InterpResult<'tcx> { while self.step()? {} Ok(()) } @@ -44,15 +44,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> /// Returns `true` as long as there are more things to do. /// /// This is used by [priroda](https://github.com/oli-obk/priroda) - pub fn step(&mut self) -> EvalResult<'tcx, bool> { + pub fn step(&mut self) -> InterpResult<'tcx, bool> { if self.stack.is_empty() { return Ok(false); } let block = self.frame().block; let stmt_id = self.frame().stmt; - let mir = self.mir(); - let basic_block = &mir.basic_blocks()[block]; + let body = self.body(); + let basic_block = &body.basic_blocks()[block]; let old_frames = self.cur_frame(); @@ -70,7 +70,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> Ok(true) } - fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> { + fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> { info!("{:?}", stmt); use rustc::mir::StatementKind::*; @@ -136,7 +136,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> &mut self, rvalue: &mir::Rvalue<'tcx>, place: &mir::Place<'tcx>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let dest = self.eval_place(place)?; use rustc::mir::Rvalue::*; @@ -259,8 +259,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> )?; } - Cast(kind, ref operand, cast_ty) => { - debug_assert_eq!(self.monomorphize(cast_ty)?, dest.layout.ty); + Cast(kind, ref operand, _) => { let src = self.eval_operand(operand, None)?; self.cast(src, kind, dest)?; } @@ -278,7 +277,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> Ok(()) } - fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx> { + fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { info!("{:?}", terminator.kind); self.tcx.span = terminator.source_info.span; self.memory.tcx.span = terminator.source_info.span; diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 83469d749870f..13baf245d10fb 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -1,18 +1,19 @@ use std::borrow::Cow; use rustc::{mir, ty}; +use rustc::ty::Instance; use rustc::ty::layout::{self, TyLayout, LayoutOf}; use syntax::source_map::Span; use rustc_target::spec::abi::Abi; -use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar}; +use rustc::mir::interpret::{InterpResult, PointerArithmetic, InterpError, Scalar}; use super::{ - EvalContext, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup + InterpretCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup }; -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> { #[inline] - pub fn goto_block(&mut self, target: Option) -> EvalResult<'tcx> { + pub fn goto_block(&mut self, target: Option) -> InterpResult<'tcx> { if let Some(target) = target { self.frame_mut().block = target; self.frame_mut().stmt = 0; @@ -25,7 +26,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> pub(super) fn eval_terminator( &mut self, terminator: &mir::Terminator<'tcx>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { use rustc::mir::TerminatorKind::*; match terminator.kind { Return => { @@ -78,7 +79,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let (fn_def, abi) = match func.layout.ty.sty { ty::FnPtr(sig) => { let caller_abi = sig.abi(); - let fn_ptr = self.read_scalar(func)?.to_ptr()?; + let fn_ptr = self.force_ptr(self.read_scalar(func)?.not_undef()?)?; let instance = self.memory.get_fn(fn_ptr)?; (instance, caller_abi) } @@ -112,7 +113,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let ty = place.layout.ty; trace!("TerminatorKind::drop: {:?}, type {}", location, ty); - let instance = crate::monomorphize::resolve_drop_in_place(*self.tcx, ty); + let instance = Instance::resolve_drop_in_place(*self.tcx, ty); self.drop_in_place( place, instance, @@ -134,7 +135,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> self.goto_block(Some(target))?; } else { // Compute error message - use rustc::mir::interpret::EvalErrorKind::*; + use rustc::mir::interpret::InterpError::*; return match *msg { BoundsCheck { ref len, ref index } => { let len = self.read_immediate(self.eval_operand(len, None)?) @@ -205,14 +206,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> rust_abi: bool, caller_arg: &mut impl Iterator>, callee_arg: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { if rust_abi && callee_arg.layout.is_zst() { // Nothing to do. trace!("Skipping callee ZST"); return Ok(()); } let caller_arg = caller_arg.next() - .ok_or_else(|| EvalErrorKind::FunctionArgCountMismatch)?; + .ok_or_else(|| InterpError::FunctionArgCountMismatch)?; if rust_abi { debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out"); } @@ -233,7 +234,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> args: &[OpTy<'tcx, M::PointerTag>], dest: Option>, ret: Option, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { trace!("eval_fn_call: {:#?}", instance); match instance.def { @@ -280,15 +281,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } // We need MIR for this fn - let mir = match M::find_fn(self, instance, args, dest, ret)? { - Some(mir) => mir, + let body = match M::find_fn(self, instance, args, dest, ret)? { + Some(body) => body, None => return Ok(()), }; self.push_stack_frame( instance, span, - mir, + body, dest, StackPopCleanup::Goto(ret), )?; @@ -306,8 +307,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> ); trace!( "spread_arg: {:?}, locals: {:#?}", - mir.spread_arg, - mir.args_iter() + body.spread_arg, + body.args_iter() .map(|local| (local, self.layout_of_local(self.frame(), local, None).unwrap().ty) ) @@ -315,12 +316,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> ); // Figure out how to pass which arguments. - // We have two iterators: Where the arguments come from, - // and where they go to. + // The Rust ABI is special: ZST get skipped. let rust_abi = match caller_abi { Abi::Rust | Abi::RustCall => true, _ => false }; + // We have two iterators: Where the arguments come from, + // and where they go to. // For where they come from: If the ABI is RustCall, we untuple the // last incoming argument. These two iterators do not have the same type, @@ -335,7 +337,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> .chain((0..untuple_arg.layout.fields.count()).into_iter() .map(|i| self.operand_field(untuple_arg, i as u64)) ) - .collect::>>>()?) + .collect::>>>()?) } else { // Plain arg passing Cow::from(args) @@ -350,12 +352,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // this is a single iterator (that handles `spread_arg`), then // `pass_argument` would be the loop body. It takes care to // not advance `caller_iter` for ZSTs. - let mut locals_iter = mir.args_iter(); + let mut locals_iter = body.args_iter(); while let Some(local) = locals_iter.next() { let dest = self.eval_place( - &mir::Place::Base(mir::PlaceBase::Local(local)) + &mir::Place::from(local) )?; - if Some(local) == mir.spread_arg { + if Some(local) == body.spread_arg { // Must be a tuple for i in 0..dest.layout.fields.count() { let dest = self.place_field(dest, i as u64)?; @@ -368,7 +370,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } // Now we should have no more caller args if caller_iter.next().is_some() { - trace!("Caller has too many args over"); + trace!("Caller has passed too many args"); return err!(FunctionArgCountMismatch); } // Don't forget to check the return type! @@ -386,12 +388,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> )); } } else { - let callee_layout = - self.layout_of_local(self.frame(), mir::RETURN_PLACE, None)?; - if !callee_layout.abi.is_uninhabited() { - return err!(FunctionRetMismatch( - self.tcx.types.never, callee_layout.ty - )); + let local = mir::RETURN_PLACE; + let ty = self.frame().body.local_decls[local].ty; + if !self.tcx.is_ty_uninhabited_from_any_module(ty) { + return err!(FunctionRetMismatch(self.tcx.types.never, ty)); } } Ok(()) @@ -406,25 +406,44 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } // cannot use the shim here, because that will only result in infinite recursion ty::InstanceDef::Virtual(_, idx) => { + let mut args = args.to_vec(); let ptr_size = self.pointer_size(); - let ptr = self.deref_operand(args[0])?; - let vtable = ptr.vtable()?; - self.memory.check_align(vtable.into(), self.tcx.data_layout.pointer_align.abi)?; - let fn_ptr = self.memory.get(vtable.alloc_id)?.read_ptr_sized( - self, - vtable.offset(ptr_size * (idx as u64 + 3), self)?, - )?.to_ptr()?; + // We have to implement all "object safe receivers". Currently we + // support built-in pointers (&, &mut, Box) as well as unsized-self. We do + // not yet support custom self types. + // Also see librustc_codegen_llvm/abi.rs and librustc_codegen_llvm/mir/block.rs. + let receiver_place = match args[0].layout.ty.builtin_deref(true) { + Some(_) => { + // Built-in pointer. + self.deref_operand(args[0])? + } + None => { + // Unsized self. + args[0].to_mem_place() + } + }; + // Find and consult vtable + let vtable = receiver_place.vtable(); + let vtable_slot = vtable.ptr_offset(ptr_size * (idx as u64 + 3), self)?; + let vtable_slot = self.memory.check_ptr_access( + vtable_slot, + ptr_size, + self.tcx.data_layout.pointer_align.abi, + )?.expect("cannot be a ZST"); + let fn_ptr = self.memory.get(vtable_slot.alloc_id)? + .read_ptr_sized(self, vtable_slot)?.to_ptr()?; let instance = self.memory.get_fn(fn_ptr)?; - // We have to patch the self argument, in particular get the layout - // expected by the actual function. Cannot just use "field 0" due to - // Box. - let mut args = args.to_vec(); - let pointee = args[0].layout.ty.builtin_deref(true).unwrap().ty; - let fake_fat_ptr_ty = self.tcx.mk_mut_ptr(pointee); - args[0] = OpTy::from(ImmTy { // strip vtable - layout: self.layout_of(fake_fat_ptr_ty)?.field(self, 0)?, - imm: Immediate::Scalar(ptr.ptr.into()) + // `*mut receiver_place.layout.ty` is almost the layout that we + // want for args[0]: We have to project to field 0 because we want + // a thin pointer. + assert!(receiver_place.layout.is_unsized()); + let receiver_ptr_ty = self.tcx.mk_mut_ptr(receiver_place.layout.ty); + let this_receiver_ptr = self.layout_of(receiver_ptr_ty)?.field(self, 0)?; + // Adjust receiver argument. + args[0] = OpTy::from(ImmTy { + layout: this_receiver_ptr, + imm: Immediate::Scalar(receiver_place.ptr.into()) }); trace!("Patched self operand to {:#?}", args[0]); // recurse with concrete function @@ -439,7 +458,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> instance: ty::Instance<'tcx>, span: Span, target: mir::BasicBlock, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance); // We take the address of the object. This may well be unaligned, which is fine // for us here. However, unaligned accesses will probably make the actual drop diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 1b0a9b17d3686..5d2f268d26639 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -1,11 +1,10 @@ -use rustc_data_structures::sync::Lrc; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, Instance}; use rustc::ty::layout::{Size, Align, LayoutOf}; -use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic}; +use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic}; -use super::{EvalContext, Machine, MemoryKind}; +use super::{InterpretCx, InterpError, Machine, MemoryKind}; -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for /// objects. /// @@ -16,7 +15,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> &mut self, ty: Ty<'tcx>, poly_trait_ref: Option>, - ) -> EvalResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer> { trace!("get_vtable(trait_ref={:?})", poly_trait_ref); let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref)); @@ -26,7 +25,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // always use the same vtable for the same (Type, Trait) combination. // That's not what happens in rustc, but emulating per-crate deduplication // does not sound like it actually makes anything any better. - return Ok(Pointer::from(vtable).with_default_tag()); + return Ok(vtable); } let methods = if let Some(poly_trait_ref) = poly_trait_ref { @@ -35,7 +34,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> self.tcx.vtable_methods(trait_ref) } else { - Lrc::new(Vec::new()) + &[] }; let layout = self.layout_of(ty)?; @@ -53,11 +52,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> ptr_size * (3 + methods.len() as u64), ptr_align, MemoryKind::Vtable, - ).with_default_tag(); + ); let tcx = &*self.tcx; - let drop = crate::monomorphize::resolve_drop_in_place(*tcx, ty); - let drop = self.memory.create_fn_alloc(drop).with_default_tag(); + let drop = Instance::resolve_drop_in_place(*tcx, ty); + let drop = self.memory.create_fn_alloc(drop); + // no need to do any alignment checks on the memory accesses below, because we know the // allocation is correctly aligned as we created it above. Also we're only offsetting by // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`. @@ -76,8 +76,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> for (i, method) in methods.iter().enumerate() { if let Some((def_id, substs)) = *method { - let instance = self.resolve(def_id, substs)?; - let fn_ptr = self.memory.create_fn_alloc(instance).with_default_tag(); + // resolve for vtable: insert shims where needed + let substs = self.subst_and_normalize_erasing_regions(substs)?; + let instance = ty::Instance::resolve_for_vtable( + *self.tcx, + self.param_env, + def_id, + substs, + ).ok_or_else(|| InterpError::TooGeneric)?; + let fn_ptr = self.memory.create_fn_alloc(instance); let method_ptr = vtable.offset(ptr_size * (3 + i as u64), self)?; self.memory .get_mut(method_ptr.alloc_id)? @@ -86,7 +93,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } self.memory.mark_immutable(vtable.alloc_id)?; - assert!(self.vtables.insert((ty, poly_trait_ref), vtable.alloc_id).is_none()); + assert!(self.vtables.insert((ty, poly_trait_ref), vtable).is_none()); Ok(vtable) } @@ -94,10 +101,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> /// Returns the drop fn instance as well as the actual dynamic type pub fn read_drop_type_from_vtable( &self, - vtable: Pointer, - ) -> EvalResult<'tcx, (ty::Instance<'tcx>, ty::Ty<'tcx>)> { + vtable: Scalar, + ) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> { // we don't care about the pointee type, we just want a pointer - self.memory.check_align(vtable.into(), self.tcx.data_layout.pointer_align.abi)?; + let vtable = self.memory.check_ptr_access( + vtable, + self.tcx.data_layout.pointer_size, + self.tcx.data_layout.pointer_align.abi, + )?.expect("cannot be a ZST"); let drop_fn = self.memory .get(vtable.alloc_id)? .read_ptr_sized(self, vtable)? @@ -106,20 +117,28 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> trace!("Found drop fn: {:?}", drop_instance); let fn_sig = drop_instance.ty(*self.tcx).fn_sig(*self.tcx); let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig); - // the drop function takes *mut T where T is the type being dropped, so get that + // The drop function takes `*mut T` where `T` is the type being dropped, so get that. let ty = fn_sig.inputs()[0].builtin_deref(true).unwrap().ty; Ok((drop_instance, ty)) } pub fn read_size_and_align_from_vtable( &self, - vtable: Pointer, - ) -> EvalResult<'tcx, (Size, Align)> { + vtable: Scalar, + ) -> InterpResult<'tcx, (Size, Align)> { let pointer_size = self.pointer_size(); - self.memory.check_align(vtable.into(), self.tcx.data_layout.pointer_align.abi)?; + // We check for size = 3*ptr_size, that covers the drop fn (unused here), + // the size, and the align (which we read below). + let vtable = self.memory.check_ptr_access( + vtable, + 3*pointer_size, + self.tcx.data_layout.pointer_align.abi, + )?.expect("cannot be a ZST"); let alloc = self.memory.get(vtable.alloc_id)?; - let size = alloc.read_ptr_sized(self, vtable.offset(pointer_size, self)?)? - .to_bits(pointer_size)? as u64; + let size = alloc.read_ptr_sized( + self, + vtable.offset(pointer_size, self)? + )?.to_bits(pointer_size)? as u64; let align = alloc.read_ptr_sized( self, vtable.offset(pointer_size * 2, self)?, diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 252e8bac2a3f8..b2a159fef59c6 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -1,17 +1,19 @@ use std::fmt::Write; -use std::hash::Hash; use std::ops::RangeInclusive; -use syntax_pos::symbol::Symbol; -use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf, VariantIdx}; +use syntax_pos::symbol::{sym, Symbol}; +use rustc::hir; +use rustc::ty::layout::{self, TyLayout, LayoutOf, VariantIdx}; use rustc::ty; use rustc_data_structures::fx::FxHashSet; use rustc::mir::interpret::{ - Scalar, AllocKind, EvalResult, EvalErrorKind, + GlobalAlloc, InterpResult, InterpError, }; +use std::hash::Hash; + use super::{ - OpTy, Machine, EvalContext, ValueVisitor, MPlaceTy, + OpTy, Machine, InterpretCx, ValueVisitor, MPlaceTy, }; macro_rules! validation_failure { @@ -65,6 +67,7 @@ macro_rules! try_validation { pub enum PathElem { Field(Symbol), Variant(Symbol), + GeneratorState(VariantIdx), ClosureVar(Symbol), ArrayElem(usize), TupleElem(usize), @@ -74,19 +77,34 @@ pub enum PathElem { } /// State for tracking recursive validation of references -pub struct RefTracking { +pub struct RefTracking { pub seen: FxHashSet, - pub todo: Vec<(T, Vec)>, + pub todo: Vec<(T, PATH)>, } -impl<'tcx, T: Copy + Eq + Hash> RefTracking { +impl RefTracking { + pub fn empty() -> Self { + RefTracking { + seen: FxHashSet::default(), + todo: vec![], + } + } pub fn new(op: T) -> Self { - let mut ref_tracking = RefTracking { + let mut ref_tracking_for_consts = RefTracking { seen: FxHashSet::default(), - todo: vec![(op, Vec::new())], + todo: vec![(op, PATH::default())], }; - ref_tracking.seen.insert(op); - ref_tracking + ref_tracking_for_consts.seen.insert(op); + ref_tracking_for_consts + } + + pub fn track(&mut self, op: T, path: impl FnOnce() -> PATH) { + if self.seen.insert(op) { + trace!("Recursing below ptr {:#?}", op); + let path = path(); + // Remember to come back to this later. + self.todo.push((op, path)); + } } } @@ -99,6 +117,7 @@ fn path_format(path: &Vec) -> String { match elem { Field(name) => write!(out, ".{}", name), Variant(name) => write!(out, ".", name), + GeneratorState(idx) => write!(out, ".", idx.index()), ClosureVar(name) => write!(out, ".", name), TupleElem(idx) => write!(out, ".{}", idx), ArrayElem(idx) => write!(out, "[{}]", idx), @@ -146,17 +165,19 @@ fn wrapping_range_format(r: &RangeInclusive, max_hi: u128) -> String { } } -struct ValidityVisitor<'rt, 'a: 'rt, 'mir: 'rt, 'tcx: 'a+'rt+'mir, M: Machine<'a, 'mir, 'tcx>+'rt> { +struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// The `path` may be pushed to, but the part that is present when a function /// starts must not be changed! `visit_fields` and `visit_array` rely on /// this stack discipline. path: Vec, - ref_tracking: Option<&'rt mut RefTracking>>, - const_mode: bool, - ecx: &'rt EvalContext<'a, 'mir, 'tcx, M>, + ref_tracking_for_consts: Option<&'rt mut RefTracking< + MPlaceTy<'tcx, M::PointerTag>, + Vec, + >>, + ecx: &'rt InterpretCx<'mir, 'tcx, M>, } -impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ValidityVisitor<'rt, 'a, 'mir, 'tcx, M> { +impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M> { fn aggregate_field_path_elem( &mut self, layout: TyLayout<'tcx>, @@ -165,13 +186,27 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ValidityVisitor<'rt, 'a, ' match layout.ty.sty { // generators and closures. ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { - if let Some(upvar) = self.ecx.tcx.optimized_mir(def_id).upvar_decls.get(field) { - PathElem::ClosureVar(upvar.debug_name) - } else { - // Sometimes the index is beyond the number of freevars (seen - // for a generator). - PathElem::ClosureVar(Symbol::intern(&field.to_string())) + let mut name = None; + if def_id.is_local() { + let tables = self.ecx.tcx.typeck_tables_of(def_id); + if let Some(upvars) = tables.upvar_list.get(&def_id) { + // Sometimes the index is beyond the number of upvars (seen + // for a generator). + if let Some((&var_hir_id, _)) = upvars.get_index(field) { + let node = self.ecx.tcx.hir().get(var_hir_id); + if let hir::Node::Binding(pat) = node { + if let hir::PatKind::Binding(_, _, ident, _) = pat.node { + name = Some(ident.name); + } + } + } + } } + + PathElem::ClosureVar(name.unwrap_or_else(|| { + // Fall back to showing the field index. + sym::integer(field) + })) } // tuples @@ -206,7 +241,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ValidityVisitor<'rt, 'a, ' &mut self, new_op: OpTy<'tcx, M::PointerTag>, elem: PathElem, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { // Remember the old state let path_len = self.path.len(); // Perform operation @@ -218,13 +253,13 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ValidityVisitor<'rt, 'a, ' } } -impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> - ValueVisitor<'a, 'mir, 'tcx, M> for ValidityVisitor<'rt, 'a, 'mir, 'tcx, M> +impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> + for ValidityVisitor<'rt, 'mir, 'tcx, M> { type V = OpTy<'tcx, M::PointerTag>; #[inline(always)] - fn ecx(&self) -> &EvalContext<'a, 'mir, 'tcx, M> { + fn ecx(&self) -> &InterpretCx<'mir, 'tcx, M> { &self.ecx } @@ -234,7 +269,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> old_op: OpTy<'tcx, M::PointerTag>, field: usize, new_op: OpTy<'tcx, M::PointerTag> - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let elem = self.aggregate_field_path_elem(old_op.layout, field); self.visit_elem(new_op, elem) } @@ -245,24 +280,29 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> old_op: OpTy<'tcx, M::PointerTag>, variant_id: VariantIdx, new_op: OpTy<'tcx, M::PointerTag> - ) -> EvalResult<'tcx> { - let name = old_op.layout.ty.ty_adt_def().unwrap().variants[variant_id].ident.name; - self.visit_elem(new_op, PathElem::Variant(name)) + ) -> InterpResult<'tcx> { + let name = match old_op.layout.ty.sty { + ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name), + // Generators also have variants + ty::Generator(..) => PathElem::GeneratorState(variant_id), + _ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty), + }; + self.visit_elem(new_op, name) } #[inline] - fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> + fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { trace!("visit_value: {:?}, {:?}", *op, op.layout); // Translate some possible errors to something nicer. match self.walk_value(op) { Ok(()) => Ok(()), Err(err) => match err.kind { - EvalErrorKind::InvalidDiscriminant(val) => + InterpError::InvalidDiscriminant(val) => validation_failure!( val, self.path, "a valid enum discriminant" ), - EvalErrorKind::ReadPointerAsBytes => + InterpError::ReadPointerAsBytes => validation_failure!( "a pointer", self.path, "plain (non-pointer) bytes" ), @@ -271,7 +311,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> } } - fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { let value = self.ecx.read_immediate(value)?; // Go over all the primitive types @@ -292,7 +332,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> // types below! let size = value.layout.size; let value = value.to_scalar_or_undef(); - if self.const_mode { + if self.ref_tracking_for_consts.is_some() { // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous try_validation!(value.to_bits(size), value, self.path, "initialized plain (non-pointer) bytes"); @@ -302,7 +342,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> } } ty::RawPtr(..) => { - if self.const_mode { + if self.ref_tracking_for_consts.is_some() { // Integers/floats in CTFE: For consistency with integers, we do not // accept undef. let _ptr = try_validation!(value.to_scalar_ptr(), @@ -325,8 +365,16 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> let tail = self.ecx.tcx.struct_tail(layout.ty); match tail.sty { ty::Dynamic(..) => { - let vtable = try_validation!(meta.unwrap().to_ptr(), - "non-pointer vtable in fat pointer", self.path); + let vtable = meta.unwrap(); + try_validation!( + self.ecx.memory.check_ptr_access( + vtable, + 3*self.ecx.tcx.data_layout.pointer_size, // drop, size, align + self.ecx.tcx.data_layout.pointer_align.abi, + ), + "dangling or unaligned vtable pointer or too small vtable", + self.path + ); try_validation!(self.ecx.read_drop_type_from_vtable(vtable), "invalid drop fn in vtable", self.path); try_validation!(self.ecx.read_size_and_align_from_vtable(vtable), @@ -344,43 +392,46 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> bug!("Unexpected unsized type tail: {:?}", tail), } } - // Make sure this is non-NULL and aligned + // Make sure this is dereferencable and all. let (size, align) = self.ecx.size_and_align_of(meta, layout)? // for the purpose of validity, consider foreign types to have // alignment and size determined by the layout (size will be 0, // alignment should take attributes into account). .unwrap_or_else(|| (layout.size, layout.align.abi)); - match self.ecx.memory.check_align(ptr, align) { - Ok(_) => {}, + let ptr: Option<_> = match self.ecx.memory.check_ptr_access(ptr, size, align) { + Ok(ptr) => ptr, Err(err) => { - error!("{:?} is not aligned to {:?}", ptr, align); + info!( + "{:?} did not pass access check for size {:?}, align {:?}", + ptr, size, align + ); match err.kind { - EvalErrorKind::InvalidNullPointerUsage => + InterpError::InvalidNullPointerUsage => return validation_failure!("NULL reference", self.path), - EvalErrorKind::AlignmentCheckFailed { required, has } => + InterpError::AlignmentCheckFailed { required, has } => return validation_failure!(format!("unaligned reference \ (required {} byte alignment but found {})", required.bytes(), has.bytes()), self.path), + InterpError::ReadBytesAsPointer => + return validation_failure!( + "integer pointer in non-ZST reference", + self.path + ), _ => return validation_failure!( - "dangling (out-of-bounds) reference (might be NULL at \ - run-time)", + "dangling (not entirely in bounds) reference", self.path ), } } - } + }; // Recursive checking - if let Some(ref mut ref_tracking) = self.ref_tracking { - assert!(self.const_mode, "We should only do recursie checking in const mode"); + if let Some(ref mut ref_tracking) = self.ref_tracking_for_consts { let place = self.ecx.ref_to_mplace(value)?; - if size != Size::ZERO { - // Non-ZST also have to be dereferencable - let ptr = try_validation!(place.ptr.to_ptr(), - "integer pointer in non-ZST reference", self.path); + if let Some(ptr) = ptr { // not a ZST // Skip validation entirely for some external statics let alloc_kind = self.ecx.tcx.alloc_map.lock().get(ptr.alloc_id); - if let Some(AllocKind::Static(did)) = alloc_kind { + if let Some(GlobalAlloc::Static(did)) = alloc_kind { // `extern static` cannot be validated as they have no body. // FIXME: Statics from other crates are also skipped. // They might be checked at a different type, but for now we @@ -389,28 +440,19 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> return Ok(()); } } - // Maintain the invariant that the place we are checking is - // already verified to be in-bounds. - try_validation!( - self.ecx.memory - .get(ptr.alloc_id)? - .check_bounds(self.ecx, ptr, size), - "dangling (not entirely in bounds) reference", self.path); } // Check if we have encountered this pointer+layout combination - // before. Proceed recursively even for integer pointers, no - // reason to skip them! They are (recursively) valid for some ZST, - // but not for others (e.g., `!` is a ZST). - if ref_tracking.seen.insert(place) { - trace!("Recursing below ptr {:#?}", *place); + // before. Proceed recursively even for ZST, no + // reason to skip them! E.g., `!` is a ZST and we want to validate it. + let path = &self.path; + ref_tracking.track(place, || { // We need to clone the path anyway, make sure it gets created // with enough space for the additional `Deref`. - let mut new_path = Vec::with_capacity(self.path.len()+1); - new_path.clone_from(&self.path); + let mut new_path = Vec::with_capacity(path.len() + 1); + new_path.clone_from(path); new_path.push(PathElem::Deref); - // Remember to come back to this later. - ref_tracking.todo.push((place, new_path)); - } + new_path + }); } } ty::FnPtr(_sig) => { @@ -427,7 +469,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Ok(()) } - fn visit_uninhabited(&mut self) -> EvalResult<'tcx> + fn visit_uninhabited(&mut self) -> InterpResult<'tcx> { validation_failure!("a value of an uninhabited type", self.path) } @@ -436,7 +478,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> &mut self, op: OpTy<'tcx, M::PointerTag>, layout: &layout::Scalar, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let value = self.ecx.read_scalar(op)?; // Determine the allowed range let (lo, hi) = layout.valid_range.clone().into_inner(); @@ -457,19 +499,20 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> wrapping_range_format(&layout.valid_range, max_hi), ) ); - let bits = match value { - Scalar::Ptr(ptr) => { + let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) { + Err(ptr) => { if lo == 1 && hi == max_hi { - // only NULL is not allowed. - // We can call `check_align` to check non-NULL-ness, but have to also look - // for function pointers. - let non_null = - self.ecx.memory.check_align( - Scalar::Ptr(ptr), Align::from_bytes(1).unwrap() - ).is_ok() || - self.ecx.memory.get_fn(ptr).is_ok(); - if !non_null { - // could be NULL + // Only NULL is the niche. So make sure the ptr is NOT NULL. + if self.ecx.memory.ptr_may_be_null(ptr) { + // These conditions are just here to improve the diagnostics so we can + // differentiate between null pointers and dangling pointers + if self.ref_tracking_for_consts.is_some() && + self.ecx.memory.get(ptr.alloc_id).is_err() && + self.ecx.memory.get_fn(ptr).is_err() { + return validation_failure!( + "encountered dangling pointer", self.path + ); + } return validation_failure!("a potentially NULL pointer", self.path); } return Ok(()); @@ -486,10 +529,8 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ); } } - Scalar::Bits { bits, size } => { - assert_eq!(size as u64, op.layout.size.bytes()); - bits - } + Ok(data) => + data }; // Now compare. This is slightly subtle because this is a special "wrap-around" range. if wrapping_range_contains(&layout.valid_range, bits) { @@ -506,8 +547,8 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> fn visit_aggregate( &mut self, op: OpTy<'tcx, M::PointerTag>, - fields: impl Iterator>, - ) -> EvalResult<'tcx> { + fields: impl Iterator>, + ) -> InterpResult<'tcx> { match op.layout.ty.sty { ty::Str => { let mplace = op.to_mem_place(); // strings are never immediate @@ -539,7 +580,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> // This is the size in bytes of the whole array. let size = ty_size * len; - let ptr = mplace.ptr.to_ptr()?; + let ptr = self.ecx.force_ptr(mplace.ptr)?; // NOTE: Keep this in sync with the handling of integer and float // types above, in `visit_primitive`. @@ -554,7 +595,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> self.ecx, ptr, size, - /*allow_ptr_and_undef*/!self.const_mode, + /*allow_ptr_and_undef*/ self.ref_tracking_for_consts.is_none(), ) { // In the happy case, we needn't check anything else. Ok(()) => {}, @@ -562,7 +603,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Err(err) => { // For some errors we might be able to provide extra information match err.kind { - EvalErrorKind::ReadUndefBytes(offset) => { + InterpError::ReadUndefBytes(offset) => { // Some byte was undefined, determine which // element that byte belongs to so we can // provide an index. @@ -587,28 +628,30 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> } } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> { /// This function checks the data at `op`. `op` is assumed to cover valid memory if it /// is an indirect operand. /// It will error if the bits at the destination do not match the ones described by the layout. /// - /// `ref_tracking` can be None to avoid recursive checking below references. + /// `ref_tracking_for_consts` can be `None` to avoid recursive checking below references. /// This also toggles between "run-time" (no recursion) and "compile-time" (with recursion) - /// validation (e.g., pointer values are fine in integers at runtime). + /// validation (e.g., pointer values are fine in integers at runtime) and various other const + /// specific validation checks pub fn validate_operand( &self, op: OpTy<'tcx, M::PointerTag>, path: Vec, - ref_tracking: Option<&mut RefTracking>>, - const_mode: bool, - ) -> EvalResult<'tcx> { + ref_tracking_for_consts: Option<&mut RefTracking< + MPlaceTy<'tcx, M::PointerTag>, + Vec, + >>, + ) -> InterpResult<'tcx> { trace!("validate_operand: {:?}, {:?}", *op, op.layout.ty); // Construct a visitor let mut visitor = ValidityVisitor { path, - ref_tracking, - const_mode, + ref_tracking_for_consts, ecx: self, }; diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index e2abf2ffc849c..d04dc3ab37ed3 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -4,26 +4,25 @@ use rustc::ty::layout::{self, TyLayout, VariantIdx}; use rustc::ty; use rustc::mir::interpret::{ - EvalResult, + InterpResult, }; use super::{ - Machine, EvalContext, MPlaceTy, OpTy, + Machine, InterpretCx, MPlaceTy, OpTy, }; // A thing that we can project into, and that has a layout. // This wouldn't have to depend on `Machine` but with the current type inference, // that's just more convenient to work with (avoids repeating all the `Machine` bounds). -pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy -{ +pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { /// Gets this value's layout. fn layout(&self) -> TyLayout<'tcx>; /// Makes this into an `OpTy`. fn to_op( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>>; + ecx: &InterpretCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; /// Creates this from an `MPlaceTy`. fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self; @@ -31,23 +30,21 @@ pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy /// Projects to the given enum variant. fn project_downcast( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, + ecx: &InterpretCx<'mir, 'tcx, M>, variant: VariantIdx, - ) -> EvalResult<'tcx, Self>; + ) -> InterpResult<'tcx, Self>; /// Projects to the n-th field. fn project_field( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, + ecx: &InterpretCx<'mir, 'tcx, M>, field: u64, - ) -> EvalResult<'tcx, Self>; + ) -> InterpResult<'tcx, Self>; } // Operands and memory-places are both values. // Places in general are not due to `place_field` having to do `force_allocation`. -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> - for OpTy<'tcx, M::PointerTag> -{ +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M::PointerTag> { #[inline(always)] fn layout(&self) -> TyLayout<'tcx> { self.layout @@ -56,8 +53,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> #[inline(always)] fn to_op( self, - _ecx: &EvalContext<'a, 'mir, 'tcx, M>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + _ecx: &InterpretCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { Ok(self) } @@ -69,24 +66,23 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> #[inline(always)] fn project_downcast( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, + ecx: &InterpretCx<'mir, 'tcx, M>, variant: VariantIdx, - ) -> EvalResult<'tcx, Self> { + ) -> InterpResult<'tcx, Self> { ecx.operand_downcast(self, variant) } #[inline(always)] fn project_field( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, + ecx: &InterpretCx<'mir, 'tcx, M>, field: u64, - ) -> EvalResult<'tcx, Self> { + ) -> InterpResult<'tcx, Self> { ecx.operand_field(self, field) } } -impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> - for MPlaceTy<'tcx, M::PointerTag> -{ + +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for MPlaceTy<'tcx, M::PointerTag> { #[inline(always)] fn layout(&self) -> TyLayout<'tcx> { self.layout @@ -95,8 +91,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> #[inline(always)] fn to_op( self, - _ecx: &EvalContext<'a, 'mir, 'tcx, M>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + _ecx: &InterpretCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { Ok(self.into()) } @@ -108,18 +104,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> #[inline(always)] fn project_downcast( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, + ecx: &InterpretCx<'mir, 'tcx, M>, variant: VariantIdx, - ) -> EvalResult<'tcx, Self> { + ) -> InterpResult<'tcx, Self> { ecx.mplace_downcast(self, variant) } #[inline(always)] fn project_field( self, - ecx: &EvalContext<'a, 'mir, 'tcx, M>, + ecx: &InterpretCx<'mir, 'tcx, M>, field: u64, - ) -> EvalResult<'tcx, Self> { + ) -> InterpResult<'tcx, Self> { ecx.mplace_field(self, field) } } @@ -127,40 +123,41 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M> macro_rules! make_value_visitor { ($visitor_trait_name:ident, $($mutability:ident)?) => { // How to traverse a value and what to do when we are at the leaves. - pub trait $visitor_trait_name<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Sized { - type V: Value<'a, 'mir, 'tcx, M>; + pub trait $visitor_trait_name<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { + type V: Value<'mir, 'tcx, M>; - /// The visitor must have an `EvalContext` in it. + /// The visitor must have an `InterpretCx` in it. fn ecx(&$($mutability)? self) - -> &$($mutability)? EvalContext<'a, 'mir, 'tcx, M>; + -> &$($mutability)? InterpretCx<'mir, 'tcx, M>; // Recursive actions, ready to be overloaded. /// Visits the given value, dispatching as appropriate to more specialized visitors. #[inline(always)] - fn visit_value(&mut self, v: Self::V) -> EvalResult<'tcx> + fn visit_value(&mut self, v: Self::V) -> InterpResult<'tcx> { self.walk_value(v) } /// Visits the given value as a union. No automatic recursion can happen here. #[inline(always)] - fn visit_union(&mut self, _v: Self::V) -> EvalResult<'tcx> + fn visit_union(&mut self, _v: Self::V) -> InterpResult<'tcx> { Ok(()) } - /// Visits this vale as an aggregate, you are even getting an iterator yielding - /// all the fields (still in an `EvalResult`, you have to do error handling yourself). + /// Visits this value as an aggregate, you are getting an iterator yielding + /// all the fields (still in an `InterpResult`, you have to do error handling yourself). /// Recurses into the fields. #[inline(always)] fn visit_aggregate( &mut self, v: Self::V, - fields: impl Iterator>, - ) -> EvalResult<'tcx> { + fields: impl Iterator>, + ) -> InterpResult<'tcx> { self.walk_aggregate(v, fields) } /// Called each time we recurse down to a field of a "product-like" aggregate - /// (structs, tuples, arrays and the like, but not enums), passing in old and new value. + /// (structs, tuples, arrays and the like, but not enums), passing in old (outer) + /// and new (inner) value. /// This gives the visitor the chance to track the stack of nested fields that /// we are descending through. #[inline(always)] @@ -169,22 +166,10 @@ macro_rules! make_value_visitor { _old_val: Self::V, _field: usize, new_val: Self::V, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { self.visit_value(new_val) } - /// Called for recursing into the field of a generator. These are not known to be - /// initialized, so we treat them like unions. - #[inline(always)] - fn visit_generator_field( - &mut self, - _old_val: Self::V, - _field: usize, - new_val: Self::V, - ) -> EvalResult<'tcx> { - self.visit_union(new_val) - } - /// Called when recursing into an enum variant. #[inline(always)] fn visit_variant( @@ -192,7 +177,7 @@ macro_rules! make_value_visitor { _old_val: Self::V, _variant: VariantIdx, new_val: Self::V, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { self.visit_value(new_val) } @@ -202,7 +187,7 @@ macro_rules! make_value_visitor { /// it is meant to provide the chance for additional checks when a value of uninhabited /// layout is detected. #[inline(always)] - fn visit_uninhabited(&mut self) -> EvalResult<'tcx> + fn visit_uninhabited(&mut self) -> InterpResult<'tcx> { Ok(()) } /// Called whenever we reach a value with scalar layout. /// We do NOT provide a `ScalarMaybeUndef` here to avoid accessing memory if the @@ -212,7 +197,7 @@ macro_rules! make_value_visitor { /// it is meant to provide the chance for additional checks when a value of scalar /// layout is detected. #[inline(always)] - fn visit_scalar(&mut self, _v: Self::V, _layout: &layout::Scalar) -> EvalResult<'tcx> + fn visit_scalar(&mut self, _v: Self::V, _layout: &layout::Scalar) -> InterpResult<'tcx> { Ok(()) } /// Called whenever we reach a value of primitive type. There can be no recursion @@ -220,29 +205,28 @@ macro_rules! make_value_visitor { /// We do *not* provide an `ImmTy` here because some implementations might want /// to write to the place this primitive lives in. #[inline(always)] - fn visit_primitive(&mut self, _v: Self::V) -> EvalResult<'tcx> + fn visit_primitive(&mut self, _v: Self::V) -> InterpResult<'tcx> { Ok(()) } // Default recursors. Not meant to be overloaded. fn walk_aggregate( &mut self, v: Self::V, - fields: impl Iterator>, - ) -> EvalResult<'tcx> { + fields: impl Iterator>, + ) -> InterpResult<'tcx> { // Now iterate over it. for (idx, field_val) in fields.enumerate() { self.visit_field(v, idx, field_val?)?; } Ok(()) } - fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx> + fn walk_value(&mut self, v: Self::V) -> InterpResult<'tcx> { trace!("walk_value: type: {}", v.layout().ty); - // If this is a multi-variant layout, we have find the right one and proceed with + // If this is a multi-variant layout, we have to find the right one and proceed with // that. match v.layout().variants { - layout::Variants::NicheFilling { .. } | - layout::Variants::Tagged { .. } => { + layout::Variants::Multiple { .. } => { let op = v.to_op(self.ecx())?; let idx = self.ecx().read_discriminant(op)?.1; let inner = v.project_downcast(self.ecx(), idx)?; @@ -264,6 +248,13 @@ macro_rules! make_value_visitor { // recurse with the inner type return self.visit_field(v, 0, Value::from_mem_place(inner)); }, + ty::Generator(..) => { + // FIXME: Generator layout is lying: it claims a whole bunch of fields exist + // when really many of them can be uninitialized. + // Just treat them as a union for now, until hopefully the layout + // computation is fixed. + return self.visit_union(v); + } _ => {}, }; @@ -305,34 +296,18 @@ macro_rules! make_value_visitor { // Empty unions are not accepted by rustc. That's great, it means we can // use that as an unambiguous signal for detecting primitives. Make sure // we did not miss any primitive. - debug_assert!(fields > 0); + assert!(fields > 0); self.visit_union(v) }, layout::FieldPlacement::Arbitrary { ref offsets, .. } => { - // Special handling needed for generators: All but the first field - // (which is the state) are actually implicitly `MaybeUninit`, i.e., - // they may or may not be initialized, so we cannot visit them. - match v.layout().ty.sty { - ty::Generator(..) => { - let field = v.project_field(self.ecx(), 0)?; - self.visit_aggregate(v, std::iter::once(Ok(field)))?; - for i in 1..offsets.len() { - let field = v.project_field(self.ecx(), i as u64)?; - self.visit_generator_field(v, i, field)?; - } - Ok(()) - } - _ => { - // FIXME: We collect in a vec because otherwise there are lifetime - // errors: Projecting to a field needs access to `ecx`. - let fields: Vec> = - (0..offsets.len()).map(|i| { - v.project_field(self.ecx(), i as u64) - }) - .collect(); - self.visit_aggregate(v, fields.into_iter()) - } - } + // FIXME: We collect in a vec because otherwise there are lifetime + // errors: Projecting to a field needs access to `ecx`. + let fields: Vec> = + (0..offsets.len()).map(|i| { + v.project_field(self.ecx(), i as u64) + }) + .collect(); + self.visit_aggregate(v, fields.into_iter()) }, layout::FieldPlacement::Array { .. } => { // Let's get an mplace first. diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 06e79dc4e7097..cb02e1a778c93 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -14,7 +14,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(const_fn)] #![feature(decl_macro)] #![feature(exhaustive_patterns)] -#![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_attrs)] #![feature(never_type)] @@ -23,13 +22,14 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(unicode_internals)] #![feature(step_trait)] #![feature(slice_concat_ext)] -#![feature(reverse_bits)] +#![feature(trusted_len)] #![feature(try_blocks)] #![recursion_limit="256"] #![deny(rust_2018_idioms)] -#![allow(explicit_outlives_requirements)] +#![deny(internal)] +#![deny(unused_lifetimes)] #[macro_use] extern crate log; #[macro_use] @@ -40,7 +40,7 @@ extern crate serialize as rustc_serialize; // used by deriving #[macro_use] extern crate syntax; -mod diagnostics; +mod error_codes; mod borrow_check; mod build; @@ -54,7 +54,6 @@ pub mod interpret; pub mod monomorphize; pub mod const_eval; -pub use hair::pattern::check_crate as matchck_crate; use rustc::ty::query::Providers; pub fn provide(providers: &mut Providers<'_>) { @@ -65,6 +64,11 @@ pub fn provide(providers: &mut Providers<'_>) { providers.const_eval = const_eval::const_eval_provider; providers.const_eval_raw = const_eval::const_eval_raw_provider; providers.check_match = hair::pattern::check_match; + providers.const_field = |tcx, param_env_and_value| { + let (param_env, (value, field)) = param_env_and_value.into_parts(); + const_eval::const_field(tcx, param_env, None, field, value) + }; + providers.type_name = interpret::type_name; } __build_diagnostic_array! { librustc_mir, DIAGNOSTICS } diff --git a/src/librustc_mir/lints.rs b/src/librustc_mir/lints.rs index bfc977c28cd39..8c815a51b5d65 100644 --- a/src/librustc_mir/lints.rs +++ b/src/librustc_mir/lints.rs @@ -3,24 +3,24 @@ use rustc::hir::def_id::DefId; use rustc::hir::intravisit::FnKind; use rustc::hir::map::blocks::FnLikeNode; use rustc::lint::builtin::UNCONDITIONAL_RECURSION; -use rustc::mir::{self, Mir, TerminatorKind}; -use rustc::ty::{AssociatedItem, AssociatedItemContainer, Instance, TyCtxt, TyKind}; +use rustc::mir::{self, Body, TerminatorKind}; +use rustc::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt}; use rustc::ty::subst::InternalSubsts; -pub fn check(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &Mir<'tcx>, - def_id: DefId) { - let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); +pub fn check(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId) { + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir().get(node_id)) { - check_fn_for_unconditional_recursion(tcx, fn_like_node.kind(), mir, def_id); + if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir().get(hir_id)) { + check_fn_for_unconditional_recursion(tcx, fn_like_node.kind(), body, def_id); } } -fn check_fn_for_unconditional_recursion(tcx: TyCtxt<'a, 'tcx, 'tcx>, - fn_kind: FnKind<'_>, - mir: &Mir<'tcx>, - def_id: DefId) { +fn check_fn_for_unconditional_recursion( + tcx: TyCtxt<'tcx>, + fn_kind: FnKind<'_>, + body: &Body<'tcx>, + def_id: DefId, +) { if let FnKind::Closure(_) = fn_kind { // closures can't recur, so they don't matter. return; @@ -54,7 +54,7 @@ fn check_fn_for_unconditional_recursion(tcx: TyCtxt<'a, 'tcx, 'tcx>, // to have behaviour like the above, rather than // e.g., accidentally recursing after an assert. - let basic_blocks = mir.basic_blocks(); + let basic_blocks = body.basic_blocks(); let mut reachable_without_self_call_queue = vec![mir::START_BLOCK]; let mut reached_exit_without_self_call = false; let mut self_call_locations = vec![]; @@ -63,8 +63,8 @@ fn check_fn_for_unconditional_recursion(tcx: TyCtxt<'a, 'tcx, 'tcx>, let param_env = tcx.param_env(def_id); let trait_substs_count = match tcx.opt_associated_item(def_id) { - Some(AssociatedItem { - container: AssociatedItemContainer::TraitContainer(trait_def_id), + Some(AssocItem { + container: AssocItemContainer::TraitContainer(trait_def_id), .. }) => tcx.generics_of(trait_def_id).count(), _ => 0 @@ -84,9 +84,9 @@ fn check_fn_for_unconditional_recursion(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Some(ref terminator) = block.terminator { match terminator.kind { TerminatorKind::Call { ref func, .. } => { - let func_ty = func.ty(mir, tcx); + let func_ty = func.ty(body, tcx); - if let TyKind::FnDef(fn_def_id, substs) = func_ty.sty { + if let ty::FnDef(fn_def_id, substs) = func_ty.sty { let (call_fn_id, call_substs) = if let Some(instance) = Instance::resolve(tcx, param_env, @@ -130,7 +130,7 @@ fn check_fn_for_unconditional_recursion(tcx: TyCtxt<'a, 'tcx, 'tcx>, // recurs. if !reached_exit_without_self_call && !self_call_locations.is_empty() { let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let sp = tcx.sess.source_map().def_span(tcx.hir().span_by_hir_id(hir_id)); + let sp = tcx.sess.source_map().def_span(tcx.hir().span(hir_id)); let mut db = tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index a58c69f636d41..bb2738d5aa4a3 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -181,23 +181,24 @@ use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::mir::interpret::{AllocId, ConstValue}; use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem}; use rustc::ty::subst::{InternalSubsts, SubstsRef}; -use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind}; -use rustc::ty::adjustment::CustomCoerceUnsized; +use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind, Instance}; +use rustc::ty::print::obsolete::DefPathBasedNames; +use rustc::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc::session::config::EntryFnType; -use rustc::mir::{self, Location, Promoted}; +use rustc::mir::{self, Location, PlaceBase, Promoted, Static, StaticKind}; use rustc::mir::visit::Visitor as MirVisitor; -use rustc::mir::mono::MonoItem; -use rustc::mir::interpret::{Scalar, GlobalId, AllocKind, ErrorHandled}; +use rustc::mir::mono::{MonoItem, InstantiationMode}; +use rustc::mir::interpret::{Scalar, GlobalId, GlobalAlloc, ErrorHandled}; -use crate::monomorphize::{self, Instance}; +use crate::monomorphize; use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; use rustc::util::common::time; -use crate::monomorphize::item::{MonoItemExt, DefPathBasedNames, InstantiationMode}; - use rustc_data_structures::bit_set::GrowableBitSet; use rustc_data_structures::sync::{MTRef, MTLock, ParallelIterator, par_iter}; +use std::iter; + #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] pub enum MonoItemCollectionMode { Eager, @@ -280,10 +281,10 @@ impl<'tcx> InliningMap<'tcx> { } } -pub fn collect_crate_mono_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mode: MonoItemCollectionMode) - -> (FxHashSet>, - InliningMap<'tcx>) { +pub fn collect_crate_mono_items<'tcx>( + tcx: TyCtxt<'tcx>, + mode: MonoItemCollectionMode, +) -> (FxHashSet>, InliningMap<'tcx>) { let roots = time(tcx.sess, "collecting roots", || { collect_roots(tcx, mode) }); @@ -314,9 +315,7 @@ pub fn collect_crate_mono_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Find all non-generic items by walking the HIR. These items serve as roots to // start monomorphizing from. -fn collect_roots<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mode: MonoItemCollectionMode) - -> Vec> { +fn collect_roots<'tcx>(tcx: TyCtxt<'tcx>, mode: MonoItemCollectionMode) -> Vec> { debug!("Collecting roots"); let mut roots = Vec::new(); @@ -346,11 +345,13 @@ fn collect_roots<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // Collect all monomorphized items reachable from `starting_point` -fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - starting_point: MonoItem<'tcx>, - visited: MTRef<'_, MTLock>>>, - recursion_depths: &mut DefIdMap, - inlining_map: MTRef<'_, MTLock>>) { +fn collect_items_rec<'tcx>( + tcx: TyCtxt<'tcx>, + starting_point: MonoItem<'tcx>, + visited: MTRef<'_, MTLock>>>, + recursion_depths: &mut DefIdMap, + inlining_map: MTRef<'_, MTLock>>, +) { if !visited.lock_mut().insert(starting_point.clone()) { // We've been here already, no need to search again. return; @@ -379,7 +380,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let param_env = ty::ParamEnv::reveal_all(); if let Ok(val) = tcx.const_eval(param_env.and(cid)) { - collect_const(tcx, val, &mut neighbors); + collect_const(tcx, val, InternalSubsts::empty(), &mut neighbors); } } MonoItem::Fn(instance) => { @@ -412,10 +413,12 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("END collect_items_rec({})", starting_point.to_string(tcx, true)); } -fn record_accesses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - caller: MonoItem<'tcx>, - callees: &[MonoItem<'tcx>], - inlining_map: MTRef<'_, MTLock>>) { +fn record_accesses<'tcx>( + tcx: TyCtxt<'tcx>, + caller: MonoItem<'tcx>, + callees: &[MonoItem<'tcx>], + inlining_map: MTRef<'_, MTLock>>, +) { let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| { mono_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy }; @@ -428,10 +431,11 @@ fn record_accesses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, inlining_map.lock_mut().record_accesses(caller, accesses); } -fn check_recursion_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, - recursion_depths: &mut DefIdMap) - -> (DefId, usize) { +fn check_recursion_limit<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + recursion_depths: &mut DefIdMap, +) -> (DefId, usize) { let def_id = instance.def_id(); let recursion_depth = recursion_depths.get(&def_id).cloned().unwrap_or(0); debug!(" => recursion depth={}", recursion_depth); @@ -451,7 +455,7 @@ fn check_recursion_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let error = format!("reached the recursion limit while instantiating `{}`", instance); if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { - tcx.sess.span_fatal(tcx.hir().span_by_hir_id(hir_id), &error); + tcx.sess.span_fatal(tcx.hir().span(hir_id), &error); } else { tcx.sess.fatal(&error); } @@ -462,11 +466,10 @@ fn check_recursion_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (def_id, recursion_depth) } -fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>) -{ +fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { let type_length = instance.substs.types().flat_map(|ty| ty.walk()).count(); - debug!(" => type length={}", type_length); + let const_length = instance.substs.consts().flat_map(|ct| ct.ty.walk()).count(); + debug!(" => type length={}, const length={}", type_length, const_length); // Rust code can easily create exponentially-long types using only a // polynomial recursion depth. Even with the default recursion @@ -475,30 +478,46 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // // Bail out in these cases to avoid that bad user experience. let type_length_limit = *tcx.sess.type_length_limit.get(); - if type_length > type_length_limit { - // The instance name is already known to be too long for rustc. Use - // `{:.64}` to avoid blasting the user's terminal with thousands of - // lines of type-name. - let instance_name = instance.to_string(); - let msg = format!("reached the type-length limit while instantiating `{:.64}...`", - instance_name); - let mut diag = if let Some(hir_id) = tcx.hir().as_local_hir_id(instance.def_id()) { - tcx.sess.struct_span_fatal(tcx.hir().span_by_hir_id(hir_id), &msg) - } else { - tcx.sess.struct_fatal(&msg) + // We include the const length in the type length, as it's better + // to be overly conservative. + // FIXME(const_generics): we should instead uniformly walk through `substs`, + // ignoring lifetimes. + if type_length + const_length > type_length_limit { + // The instance name is already known to be too long for rustc. + // Show only the first and last 32 characters to avoid blasting + // the user's terminal with thousands of lines of type-name. + let shrink = |s: String, before: usize, after: usize| { + // An iterator of all byte positions including the end of the string. + let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len())); + + let shrunk = format!( + "{before}...{after}", + before = &s[..positions().nth(before).unwrap_or(s.len())], + after = &s[positions().rev().nth(after).unwrap_or(0)..], + ); + + // Only use the shrunk version if it's really shorter. + // This also avoids the case where before and after slices overlap. + if shrunk.len() < s.len() { + shrunk + } else { + s + } }; - + let msg = format!("reached the type-length limit while instantiating `{}`", + shrink(instance.to_string(), 32, 32)); + let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg); diag.note(&format!( "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate", - type_length_limit*2)); + type_length)); diag.emit(); tcx.sess.abort_if_errors(); } } -struct MirNeighborCollector<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &'a mir::Mir<'tcx>, +struct MirNeighborCollector<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, output: &'a mut Vec>, param_substs: SubstsRef<'tcx>, } @@ -512,13 +531,15 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // When doing an cast from a regular pointer to a fat pointer, we // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. - mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => { + mir::Rvalue::Cast( + mir::CastKind::Pointer(PointerCast::Unsize), ref operand, target_ty + ) => { let target_ty = self.tcx.subst_and_normalize_erasing_regions( self.param_substs, ty::ParamEnv::reveal_all(), &target_ty, ); - let source_ty = operand.ty(self.mir, self.tcx); + let source_ty = operand.ty(self.body, self.tcx); let source_ty = self.tcx.subst_and_normalize_erasing_regions( self.param_substs, ty::ParamEnv::reveal_all(), @@ -537,8 +558,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output); } } - mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => { - let fn_ty = operand.ty(self.mir, self.tcx); + mir::Rvalue::Cast( + mir::CastKind::Pointer(PointerCast::ReifyFnPointer), ref operand, _ + ) => { + let fn_ty = operand.ty(self.body, self.tcx); let fn_ty = self.tcx.subst_and_normalize_erasing_regions( self.param_substs, ty::ParamEnv::reveal_all(), @@ -546,8 +569,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { ); visit_fn_use(self.tcx, fn_ty, false, &mut self.output); } - mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => { - let source_ty = operand.ty(self.mir, self.tcx); + mir::Rvalue::Cast( + mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)), ref operand, _ + ) => { + let source_ty = operand.ty(self.body, self.tcx); let source_ty = self.tcx.subst_and_normalize_erasing_regions( self.param_substs, ty::ParamEnv::reveal_all(), @@ -555,7 +580,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { ); match source_ty.sty { ty::Closure(def_id, substs) => { - let instance = monomorphize::resolve_closure( + let instance = Instance::resolve_closure( self.tcx, def_id, substs, ty::ClosureKind::FnOnce); if should_monomorphize_locally(self.tcx, &instance) { self.output.push(create_fn_mono_item(instance)); @@ -581,16 +606,15 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.super_rvalue(rvalue, location); } - fn visit_const(&mut self, constant: &&'tcx ty::LazyConst<'tcx>, location: Location) { + fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { debug!("visiting const {:?} @ {:?}", *constant, location); - collect_lazy_const(self.tcx, constant, self.param_substs, self.output); + collect_const(self.tcx, *constant, self.param_substs, self.output); self.super_const(constant); } fn visit_terminator_kind(&mut self, - block: mir::BasicBlock, kind: &mir::TerminatorKind<'tcx>, location: Location) { debug!("visiting terminator {:?} @ {:?}", kind, location); @@ -598,7 +622,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let tcx = self.tcx; match *kind { mir::TerminatorKind::Call { ref func, .. } => { - let callee_ty = func.ty(self.mir, tcx); + let callee_ty = func.ty(self.body, tcx); let callee_ty = tcx.subst_and_normalize_erasing_regions( self.param_substs, ty::ParamEnv::reveal_all(), @@ -608,8 +632,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } mir::TerminatorKind::Drop { ref location, .. } | mir::TerminatorKind::DropAndReplace { ref location, .. } => { - let ty = location.ty(self.mir, self.tcx) - .to_ty(self.tcx); + let ty = location.ty(self.body, self.tcx).ty; let ty = tcx.subst_and_normalize_erasing_regions( self.param_substs, ty::ParamEnv::reveal_all(), @@ -630,39 +653,49 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { mir::TerminatorKind::FalseUnwind { .. } => bug!(), } - self.super_terminator_kind(block, kind, location); + self.super_terminator_kind(kind, location); } - fn visit_static(&mut self, - static_: &mir::Static<'tcx>, - context: mir::visit::PlaceContext<'tcx>, - location: Location) { - debug!("visiting static {:?} @ {:?}", static_.def_id, location); + fn visit_place_base(&mut self, + place_base: &mir::PlaceBase<'tcx>, + _context: mir::visit::PlaceContext, + location: Location) { + match place_base { + PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. }) => { + debug!("visiting static {:?} @ {:?}", def_id, location); - let tcx = self.tcx; - let instance = Instance::mono(tcx, static_.def_id); - if should_monomorphize_locally(tcx, &instance) { - self.output.push(MonoItem::Static(static_.def_id)); + let tcx = self.tcx; + let instance = Instance::mono(tcx, *def_id); + if should_monomorphize_locally(tcx, &instance) { + self.output.push(MonoItem::Static(*def_id)); + } + } + PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => { + // FIXME: should we handle promoteds here instead of eagerly in collect_neighbours? + } + PlaceBase::Local(_) => { + // Locals have no relevance for collector + } } - - self.super_static(static_, context, location); } } -fn visit_drop_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, - is_direct_call: bool, - output: &mut Vec>) -{ - let instance = monomorphize::resolve_drop_in_place(tcx, ty); +fn visit_drop_use<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + is_direct_call: bool, + output: &mut Vec>, +) { + let instance = Instance::resolve_drop_in_place(tcx, ty); visit_instance_use(tcx, instance, is_direct_call, output); } -fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, - is_direct_call: bool, - output: &mut Vec>) -{ +fn visit_fn_use<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + is_direct_call: bool, + output: &mut Vec>, +) { if let ty::FnDef(def_id, substs) = ty.sty { let instance = ty::Instance::resolve(tcx, ty::ParamEnv::reveal_all(), @@ -672,11 +705,12 @@ fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn visit_instance_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: ty::Instance<'tcx>, - is_direct_call: bool, - output: &mut Vec>) -{ +fn visit_instance_use<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::Instance<'tcx>, + is_direct_call: bool, + output: &mut Vec>, +) { debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); if !should_monomorphize_locally(tcx, &instance) { return @@ -711,8 +745,7 @@ fn visit_instance_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Returns true if we should codegen an instance in the local crate. // Returns false if we can just link to the upstream crate and therefore don't // need a mono item. -fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instance<'tcx>) - -> bool { +fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool { let def_id = match instance.def { ty::InstanceDef::Item(def_id) => def_id, ty::InstanceDef::VtableShim(..) | @@ -746,10 +779,11 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: } return true; - fn is_available_upstream_generic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>) - -> bool { + fn is_available_upstream_generic<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> bool { debug_assert!(!def_id.is_local()); // If we are not in share generics mode, we don't link to upstream @@ -759,10 +793,10 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: return false } - // If this instance has no type parameters, it cannot be a shared + // If this instance has non-erasable parameters, it cannot be a shared // monomorphization. Non-generic instances are already handled above // by `is_reachable_non_generic()` - if substs.types().next().is_none() { + if substs.non_erasable_generics().next().is_none() { return false } @@ -811,10 +845,11 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: /// /// Finally, there is also the case of custom unsizing coercions, e.g., for /// smart pointers such as `Rc` and `Arc`. -fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - source_ty: Ty<'tcx>, - target_ty: Ty<'tcx>) - -> (Ty<'tcx>, Ty<'tcx>) { +fn find_vtable_types_for_unsizing<'tcx>( + tcx: TyCtxt<'tcx>, + source_ty: Ty<'tcx>, + target_ty: Ty<'tcx>, +) -> (Ty<'tcx>, Ty<'tcx>) { let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { let type_has_metadata = |ty: Ty<'tcx>| -> bool { use syntax_pos::DUMMY_SP; @@ -825,7 +860,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match tail.sty { ty::Foreign(..) => false, ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, - _ => bug!("unexpected unsized tail: {:?}", tail.sty), + _ => bug!("unexpected unsized tail: {:?}", tail), } }; if type_has_metadata(inner_source) { @@ -877,17 +912,19 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn create_fn_mono_item<'a, 'tcx>(instance: Instance<'tcx>) -> MonoItem<'tcx> { +fn create_fn_mono_item<'tcx>(instance: Instance<'tcx>) -> MonoItem<'tcx> { debug!("create_fn_mono_item(instance={})", instance); MonoItem::Fn(instance) } /// Creates a `MonoItem` for each method that is referenced by the vtable for /// the given trait/impl pair. -fn create_mono_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_ty: Ty<'tcx>, - impl_ty: Ty<'tcx>, - output: &mut Vec>) { +fn create_mono_items_for_vtable_methods<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ty: Ty<'tcx>, + impl_ty: Ty<'tcx>, + output: &mut Vec>, +) { assert!(!trait_ty.needs_subst() && !trait_ty.has_escaping_bound_vars() && !impl_ty.needs_subst() && !impl_ty.has_escaping_bound_vars()); @@ -918,14 +955,14 @@ fn create_mono_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Root Collection //=----------------------------------------------------------------------------- -struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct RootCollector<'a, 'tcx> { + tcx: TyCtxt<'tcx>, mode: MonoItemCollectionMode, - output: &'b mut Vec>, + output: &'a mut Vec>, entry_fn: Option<(DefId, EntryFnType)>, } -impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { +impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { hir::ItemKind::ExternCrate(..) | @@ -952,7 +989,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemKind::Union(_, ref generics) => { if generics.params.is_empty() { if self.mode == MonoItemCollectionMode::Eager { - let def_id = self.tcx.hir().local_def_id(item.id); + let def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); debug!("RootCollector: ADT drop-glue for {}", def_id_to_string(self.tcx, def_id)); @@ -964,11 +1001,11 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemKind::GlobalAsm(..) => { debug!("RootCollector: ItemKind::GlobalAsm({})", def_id_to_string(self.tcx, - self.tcx.hir().local_def_id(item.id))); - self.output.push(MonoItem::GlobalAsm(item.id)); + self.tcx.hir().local_def_id_from_hir_id(item.hir_id))); + self.output.push(MonoItem::GlobalAsm(item.hir_id)); } hir::ItemKind::Static(..) => { - let def_id = self.tcx.hir().local_def_id(item.id); + let def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); debug!("RootCollector: ItemKind::Static({})", def_id_to_string(self.tcx, def_id)); self.output.push(MonoItem::Static(def_id)); @@ -978,7 +1015,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { // actually used somewhere. Just declaring them is insufficient. // but even just declaring them must collect the items they refer to - let def_id = self.tcx.hir().local_def_id(item.id); + let def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); let instance = Instance::mono(self.tcx, def_id); let cid = GlobalId { @@ -988,11 +1025,11 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { let param_env = ty::ParamEnv::reveal_all(); if let Ok(val) = self.tcx.const_eval(param_env.and(cid)) { - collect_const(self.tcx, val, &mut self.output); + collect_const(self.tcx, val, InternalSubsts::empty(), &mut self.output); } } hir::ItemKind::Fn(..) => { - let def_id = self.tcx.hir().local_def_id(item.id); + let def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); self.push_if_root(def_id); } } @@ -1014,9 +1051,9 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { } } -impl<'b, 'a, 'v> RootCollector<'b, 'a, 'v> { +impl RootCollector<'_, 'v> { fn is_root(&self, def_id: DefId) -> bool { - !item_has_type_parameters(self.tcx, def_id) && match self.mode { + !item_requires_monomorphization(self.tcx, def_id) && match self.mode { MonoItemCollectionMode::Eager => { true } @@ -1077,14 +1114,16 @@ impl<'b, 'a, 'v> RootCollector<'b, 'a, 'v> { } } -fn item_has_type_parameters<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { +fn item_requires_monomorphization<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { let generics = tcx.generics_of(def_id); generics.requires_monomorphization(tcx) } -fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - item: &'tcx hir::Item, - output: &mut Vec>) { +fn create_mono_items_for_default_impls<'tcx>( + tcx: TyCtxt<'tcx>, + item: &'tcx hir::Item, + output: &mut Vec>, +) { match item.node { hir::ItemKind::Impl(_, _, _, ref generics, .., ref impl_item_refs) => { for param in &generics.params { @@ -1097,7 +1136,7 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - let impl_def_id = tcx.hir().local_def_id(item.id); + let impl_def_id = tcx.hir().local_def_id_from_hir_id(item.hir_id); debug!("create_mono_items_for_default_impls(item={})", def_id_to_string(tcx, impl_def_id)); @@ -1112,14 +1151,15 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, continue; } - if tcx.generics_of(method.def_id).own_counts().types != 0 { + if tcx.generics_of(method.def_id).own_requires_monomorphization() { continue; } let substs = InternalSubsts::for_item(tcx, method.def_id, |param, _| { match param.kind { - GenericParamDefKind::Lifetime => tcx.types.re_erased.into(), - GenericParamDefKind::Type {..} => { + GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), + GenericParamDefKind::Type { .. } | + GenericParamDefKind::Const => { trait_ref.substs[param.index as usize] } } @@ -1145,27 +1185,23 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } /// Scan the miri alloc in order to find function calls, closures, and drop-glue -fn collect_miri<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - alloc_id: AllocId, - output: &mut Vec>, -) { +fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec>) { let alloc_kind = tcx.alloc_map.lock().get(alloc_id); match alloc_kind { - Some(AllocKind::Static(did)) => { - let instance = Instance::mono(tcx, did); + Some(GlobalAlloc::Static(def_id)) => { + let instance = Instance::mono(tcx, def_id); if should_monomorphize_locally(tcx, &instance) { - trace!("collecting static {:?}", did); - output.push(MonoItem::Static(did)); + trace!("collecting static {:?}", def_id); + output.push(MonoItem::Static(def_id)); } } - Some(AllocKind::Memory(alloc)) => { + Some(GlobalAlloc::Memory(alloc)) => { trace!("collecting {:?} with {:#?}", alloc_id, alloc); for &((), inner) in alloc.relocations.values() { collect_miri(tcx, inner, output); } }, - Some(AllocKind::Function(fn_instance)) => { + Some(GlobalAlloc::Function(fn_instance)) => { if should_monomorphize_locally(tcx, &fn_instance) { trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); output.push(create_fn_mono_item(fn_instance)); @@ -1176,20 +1212,21 @@ fn collect_miri<'a, 'tcx>( } /// Scan the MIR in order to find function calls, closures, and drop-glue -fn collect_neighbours<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, - output: &mut Vec>) -{ - let mir = tcx.instance_mir(instance.def); +fn collect_neighbours<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + output: &mut Vec>, +) { + let body = tcx.instance_mir(instance.def); MirNeighborCollector { tcx, - mir: &mir, + body: &body, output, param_substs: instance.substs, - }.visit_mir(&mir); + }.visit_body(&body); let param_env = ty::ParamEnv::reveal_all(); - for i in 0..mir.promoted.len() { + for i in 0..body.promoted.len() { use rustc_data_structures::indexed_vec::Idx; let i = Promoted::new(i); let cid = GlobalId { @@ -1197,74 +1234,63 @@ fn collect_neighbours<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, promoted: Some(i), }; match tcx.const_eval(param_env.and(cid)) { - Ok(val) => collect_const(tcx, val, output), + Ok(val) => collect_const(tcx, val, instance.substs, output), Err(ErrorHandled::Reported) => {}, Err(ErrorHandled::TooGeneric) => span_bug!( - mir.promoted[i].span, "collection encountered polymorphic constant", + body.promoted[i].span, "collection encountered polymorphic constant", ), } } } -fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> String { +fn def_id_to_string<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> String { let mut output = String::new(); let printer = DefPathBasedNames::new(tcx, false, false); printer.push_def_path(def_id, &mut output); output } -fn collect_lazy_const<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - constant: &ty::LazyConst<'tcx>, +fn collect_const<'tcx>( + tcx: TyCtxt<'tcx>, + constant: &'tcx ty::Const<'tcx>, param_substs: SubstsRef<'tcx>, output: &mut Vec>, -) { - let (def_id, substs) = match *constant { - ty::LazyConst::Evaluated(c) => return collect_const(tcx, c, output), - ty::LazyConst::Unevaluated(did, substs) => (did, substs), - }; - let param_env = ty::ParamEnv::reveal_all(); - let substs = tcx.subst_and_normalize_erasing_regions( - param_substs, - param_env, - &substs, - ); - let instance = ty::Instance::resolve(tcx, - param_env, - def_id, - substs).unwrap(); - - let cid = GlobalId { - instance, - promoted: None, - }; - match tcx.const_eval(param_env.and(cid)) { - Ok(val) => collect_const(tcx, val, output), - Err(ErrorHandled::Reported) => {}, - Err(ErrorHandled::TooGeneric) => span_bug!( - tcx.def_span(def_id), "collection encountered polymorphic constant", - ), - } -} - -fn collect_const<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - constant: ty::Const<'tcx>, - output: &mut Vec>, ) { debug!("visiting const {:?}", constant); match constant.val { - ConstValue::Slice(Scalar::Ptr(ptr), _) | ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output), - ConstValue::ByRef(_ptr, alloc) => { + ConstValue::Slice { data: alloc, start: _, end: _ } | + ConstValue::ByRef { alloc, .. } => { for &((), id) in alloc.relocations.values() { collect_miri(tcx, id, output); } } + ConstValue::Unevaluated(def_id, substs) => { + let param_env = ty::ParamEnv::reveal_all(); + let substs = tcx.subst_and_normalize_erasing_regions( + param_substs, + param_env, + &substs, + ); + let instance = ty::Instance::resolve(tcx, + param_env, + def_id, + substs).unwrap(); + + let cid = GlobalId { + instance, + promoted: None, + }; + match tcx.const_eval(param_env.and(cid)) { + Ok(val) => collect_const(tcx, val, param_substs, output), + Err(ErrorHandled::Reported) => {}, + Err(ErrorHandled::TooGeneric) => span_bug!( + tcx.def_span(def_id), "collection encountered polymorphic constant", + ), + } + } _ => {}, } } diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 059af2dbba944..2bcf058ad7c35 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -1,17 +1,14 @@ -use crate::monomorphize::Instance; -use rustc::hir; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::def_id::LOCAL_CRATE; +use rustc::mir::mono::MonoItem; use rustc::session::config::OptLevel; -use rustc::ty::{self, Ty, TyCtxt, ClosureSubsts, GeneratorSubsts}; -use rustc::ty::subst::{SubstsRef, InternalSubsts}; -use syntax::ast; +use rustc::ty::{self, TyCtxt, Instance}; +use rustc::ty::subst::InternalSubsts; +use rustc::ty::print::obsolete::DefPathBasedNames; use syntax::attr::InlineAttr; -use std::fmt::{self, Write}; -use std::iter; +use std::fmt; use rustc::mir::mono::Linkage; -use syntax_pos::symbol::Symbol; +use syntax_pos::symbol::InternedString; use syntax::source_map::Span; -pub use rustc::mir::mono::MonoItem; /// Describes how a monomorphization will be instantiated in object files. #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] @@ -38,36 +35,34 @@ pub enum InstantiationMode { LocalCopy, } -pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { +pub trait MonoItemExt<'tcx>: fmt::Debug { fn as_mono_item(&self) -> &MonoItem<'tcx>; fn is_generic_fn(&self) -> bool { match *self.as_mono_item() { MonoItem::Fn(ref instance) => { - instance.substs.types().next().is_some() + instance.substs.non_erasable_generics().next().is_some() } MonoItem::Static(..) | MonoItem::GlobalAsm(..) => false, } } - fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::SymbolName { + fn symbol_name(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolName { match *self.as_mono_item() { MonoItem::Fn(instance) => tcx.symbol_name(instance), MonoItem::Static(def_id) => { tcx.symbol_name(Instance::mono(tcx, def_id)) } - MonoItem::GlobalAsm(node_id) => { - let def_id = tcx.hir().local_def_id(node_id); + MonoItem::GlobalAsm(hir_id) => { + let def_id = tcx.hir().local_def_id_from_hir_id(hir_id); ty::SymbolName { - name: Symbol::intern(&format!("global_asm_{:?}", def_id)).as_interned_str() + name: InternedString::intern(&format!("global_asm_{:?}", def_id)) } } } } - fn instantiation_mode(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> InstantiationMode { + fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode { let inline_in_all_cgus = tcx.sess.opts.debugging_opts.inline_in_all_cgus.unwrap_or_else(|| { tcx.sess.opts.optimize != OptLevel::No @@ -111,7 +106,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { } } - fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { + fn explicit_linkage(&self, tcx: TyCtxt<'tcx>) -> Option { let def_id = match *self.as_mono_item() { MonoItem::Fn(ref instance) => instance.def_id(), MonoItem::Static(def_id) => def_id, @@ -147,7 +142,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { /// Similarly, if a vtable method has such a signature, and therefore can't /// be used, we can just not emit it and have a placeholder (a null pointer, /// which will never be accessed) in its place. - fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { + fn is_instantiable(&self, tcx: TyCtxt<'tcx>) -> bool { debug!("is_instantiable({:?})", self); let (def_id, substs) = match *self.as_mono_item() { MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs), @@ -159,7 +154,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { tcx.substitute_normalize_and_test_predicates((def_id, &substs)) } - fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, debug: bool) -> String { + fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String { return match *self.as_mono_item() { MonoItem::Fn(instance) => { to_string_internal(tcx, "fn ", instance, debug) @@ -173,11 +168,12 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { } }; - fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - prefix: &str, - instance: Instance<'tcx>, - debug: bool) - -> String { + fn to_string_internal<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + prefix: &str, + instance: Instance<'tcx>, + debug: bool, + ) -> String { let mut result = String::with_capacity(32); result.push_str(prefix); let printer = DefPathBasedNames::new(tcx, false, false); @@ -186,280 +182,23 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { } } - fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { + fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option { match *self.as_mono_item() { MonoItem::Fn(Instance { def, .. }) => { - tcx.hir().as_local_node_id(def.def_id()) + tcx.hir().as_local_hir_id(def.def_id()) } MonoItem::Static(def_id) => { - tcx.hir().as_local_node_id(def_id) + tcx.hir().as_local_hir_id(def_id) } - MonoItem::GlobalAsm(node_id) => { - Some(node_id) + MonoItem::GlobalAsm(hir_id) => { + Some(hir_id) } - }.map(|node_id| tcx.hir().span(node_id)) + }.map(|hir_id| tcx.hir().span(hir_id)) } } -impl<'a, 'tcx> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { +impl MonoItemExt<'tcx> for MonoItem<'tcx> { fn as_mono_item(&self) -> &MonoItem<'tcx> { self } } - -//=----------------------------------------------------------------------------- -// MonoItem String Keys -//=----------------------------------------------------------------------------- - -// The code below allows for producing a unique string key for a mono item. -// These keys are used by the handwritten auto-tests, so they need to be -// predictable and human-readable. -// -// Note: A lot of this could looks very similar to what's already in the -// ppaux module. It would be good to refactor things so we only have one -// parameterizable implementation for printing types. - -/// Same as `unique_type_name()` but with the result pushed onto the given -/// `output` parameter. -pub struct DefPathBasedNames<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - omit_disambiguators: bool, - omit_local_crate_name: bool, -} - -impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, - omit_disambiguators: bool, - omit_local_crate_name: bool) - -> Self { - DefPathBasedNames { - tcx, - omit_disambiguators, - omit_local_crate_name, - } - } - - // Pushes the type name of the specified type to the provided string. - // If 'debug' is true, printing normally unprintable types is allowed - // (e.g. ty::GeneratorWitness). This parameter should only be set when - // this method is being used for logging purposes (e.g. with debug! or info!) - // When being used for codegen purposes, 'debug' should be set to 'false' - // in order to catch unexpected types that should never end up in a type name - pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) { - match t.sty { - ty::Bool => output.push_str("bool"), - ty::Char => output.push_str("char"), - ty::Str => output.push_str("str"), - ty::Never => output.push_str("!"), - ty::Int(ast::IntTy::Isize) => output.push_str("isize"), - ty::Int(ast::IntTy::I8) => output.push_str("i8"), - ty::Int(ast::IntTy::I16) => output.push_str("i16"), - ty::Int(ast::IntTy::I32) => output.push_str("i32"), - ty::Int(ast::IntTy::I64) => output.push_str("i64"), - ty::Int(ast::IntTy::I128) => output.push_str("i128"), - ty::Uint(ast::UintTy::Usize) => output.push_str("usize"), - ty::Uint(ast::UintTy::U8) => output.push_str("u8"), - ty::Uint(ast::UintTy::U16) => output.push_str("u16"), - ty::Uint(ast::UintTy::U32) => output.push_str("u32"), - ty::Uint(ast::UintTy::U64) => output.push_str("u64"), - ty::Uint(ast::UintTy::U128) => output.push_str("u128"), - ty::Float(ast::FloatTy::F32) => output.push_str("f32"), - ty::Float(ast::FloatTy::F64) => output.push_str("f64"), - ty::Adt(adt_def, substs) => { - self.push_def_path(adt_def.did, output); - self.push_type_params(substs, iter::empty(), output, debug); - }, - ty::Tuple(component_types) => { - output.push('('); - for &component_type in component_types { - self.push_type_name(component_type, output, debug); - output.push_str(", "); - } - if !component_types.is_empty() { - output.pop(); - output.pop(); - } - output.push(')'); - }, - ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { - output.push('*'); - match mutbl { - hir::MutImmutable => output.push_str("const "), - hir::MutMutable => output.push_str("mut "), - } - - self.push_type_name(inner_type, output, debug); - }, - ty::Ref(_, inner_type, mutbl) => { - output.push('&'); - if mutbl == hir::MutMutable { - output.push_str("mut "); - } - - self.push_type_name(inner_type, output, debug); - }, - ty::Array(inner_type, len) => { - output.push('['); - self.push_type_name(inner_type, output, debug); - write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap(); - output.push(']'); - }, - ty::Slice(inner_type) => { - output.push('['); - self.push_type_name(inner_type, output, debug); - output.push(']'); - }, - ty::Dynamic(ref trait_data, ..) => { - if let Some(principal) = trait_data.principal() { - self.push_def_path(principal.def_id(), output); - self.push_type_params( - principal.skip_binder().substs, - trait_data.projection_bounds(), - output, - debug - ); - } else { - output.push_str("dyn '_"); - } - }, - ty::Foreign(did) => self.push_def_path(did, output), - ty::FnDef(..) | - ty::FnPtr(_) => { - let sig = t.fn_sig(self.tcx); - if sig.unsafety() == hir::Unsafety::Unsafe { - output.push_str("unsafe "); - } - - let abi = sig.abi(); - if abi != ::rustc_target::spec::abi::Abi::Rust { - output.push_str("extern \""); - output.push_str(abi.name()); - output.push_str("\" "); - } - - output.push_str("fn("); - - let sig = self.tcx.normalize_erasing_late_bound_regions( - ty::ParamEnv::reveal_all(), - &sig, - ); - - if !sig.inputs().is_empty() { - for ¶meter_type in sig.inputs() { - self.push_type_name(parameter_type, output, debug); - output.push_str(", "); - } - output.pop(); - output.pop(); - } - - if sig.c_variadic { - if !sig.inputs().is_empty() { - output.push_str(", ..."); - } else { - output.push_str("..."); - } - } - - output.push(')'); - - if !sig.output().is_unit() { - output.push_str(" -> "); - self.push_type_name(sig.output(), output, debug); - } - }, - ty::Generator(def_id, GeneratorSubsts { ref substs }, _) | - ty::Closure(def_id, ClosureSubsts { ref substs }) => { - self.push_def_path(def_id, output); - let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id)); - let substs = substs.truncate_to(self.tcx, generics); - self.push_type_params(substs, iter::empty(), output, debug); - } - ty::Error | - ty::Bound(..) | - ty::Infer(_) | - ty::Placeholder(..) | - ty::UnnormalizedProjection(..) | - ty::Projection(..) | - ty::Param(_) | - ty::GeneratorWitness(_) | - ty::Opaque(..) => { - if debug { - output.push_str(&format!("`{:?}`", t)); - } else { - bug!("DefPathBasedNames: Trying to create type name for \ - unexpected type: {:?}", t); - } - } - } - } - - pub fn push_def_path(&self, - def_id: DefId, - output: &mut String) { - let def_path = self.tcx.def_path(def_id); - - // some_crate:: - if !(self.omit_local_crate_name && def_id.is_local()) { - output.push_str(&self.tcx.crate_name(def_path.krate).as_str()); - output.push_str("::"); - } - - // foo::bar::ItemName:: - for part in self.tcx.def_path(def_id).data { - if self.omit_disambiguators { - write!(output, "{}::", part.data.as_interned_str()).unwrap(); - } else { - write!(output, "{}[{}]::", - part.data.as_interned_str(), - part.disambiguator).unwrap(); - } - } - - // remove final "::" - output.pop(); - output.pop(); - } - - fn push_type_params(&self, - substs: SubstsRef<'tcx>, - projections: I, - output: &mut String, - debug: bool) - where I: Iterator> - { - let mut projections = projections.peekable(); - if substs.types().next().is_none() && projections.peek().is_none() { - return; - } - - output.push('<'); - - for type_parameter in substs.types() { - self.push_type_name(type_parameter, output, debug); - output.push_str(", "); - } - - for projection in projections { - let projection = projection.skip_binder(); - let name = &self.tcx.associated_item(projection.item_def_id).ident.as_str(); - output.push_str(name); - output.push_str("="); - self.push_type_name(projection.ty, output, debug); - output.push_str(", "); - } - - output.pop(); - output.pop(); - - output.push('>'); - } - - pub fn push_instance_as_string(&self, - instance: Instance<'tcx>, - output: &mut String, - debug: bool) { - self.push_def_path(instance.def_id(), output); - self.push_type_params(instance.substs, iter::empty(), output, debug); - } -} diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs index 7fa904d32cbb4..b36cf49ef1e45 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/src/librustc_mir/monomorphize/mod.rs @@ -1,147 +1,15 @@ -use rustc::hir::def_id::DefId; -use rustc::middle::lang_items::DropInPlaceFnLangItem; use rustc::traits; use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::ty::{self, Ty, TyCtxt}; -pub use rustc::ty::Instance; -pub use self::item::{MonoItem, MonoItemExt}; - pub mod collector; -pub mod item; pub mod partitioning; -#[inline(never)] // give this a place in the profiler -pub fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mono_items: I) - where I: Iterator> -{ - let mut symbols: Vec<_> = mono_items.map(|mono_item| { - (mono_item, mono_item.symbol_name(tcx)) - }).collect(); - - symbols.sort_by_key(|sym| sym.1); - - for pair in symbols.windows(2) { - let sym1 = &pair[0].1; - let sym2 = &pair[1].1; - - if sym1 == sym2 { - let mono_item1 = pair[0].0; - let mono_item2 = pair[1].0; - - let span1 = mono_item1.local_span(tcx); - let span2 = mono_item2.local_span(tcx); - - // Deterministically select one of the spans for error reporting - let span = match (span1, span2) { - (Some(span1), Some(span2)) => { - Some(if span1.lo().0 > span2.lo().0 { - span1 - } else { - span2 - }) - } - (span1, span2) => span1.or(span2), - }; - - let error_message = format!("symbol `{}` is already defined", sym1); - - if let Some(span) = span { - tcx.sess.span_fatal(span, &error_message) - } else { - tcx.sess.fatal(&error_message) - } - } - } -} - -fn fn_once_adapter_instance<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - closure_did: DefId, - substs: ty::ClosureSubsts<'tcx>, - ) -> Instance<'tcx> { - debug!("fn_once_adapter_shim({:?}, {:?})", - closure_did, - substs); - let fn_once = tcx.lang_items().fn_once_trait().unwrap(); - let call_once = tcx.associated_items(fn_once) - .find(|it| it.kind == ty::AssociatedKind::Method) - .unwrap().def_id; - let def = ty::InstanceDef::ClosureOnceShim { call_once }; - - let self_ty = tcx.mk_closure(closure_did, substs); - - let sig = substs.closure_sig(closure_did, tcx); - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - assert_eq!(sig.inputs().len(), 1); - let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]); - - debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); - Instance { def, substs } -} - -fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind, - trait_closure_kind: ty::ClosureKind) - -> Result -{ - match (actual_closure_kind, trait_closure_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { - // No adapter needed. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { - // The closure fn `llfn` is a `fn(&self, ...)`. We want a - // `fn(&mut self, ...)`. In fact, at codegen time, these are - // basically the same thing, so we can just return llfn. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut - // self, ...)`. We want a `fn(self, ...)`. We can produce - // this by doing something like: - // - // fn call_once(self, ...) { call_mut(&self, ...) } - // fn call_once(mut self, ...) { call_mut(&mut self, ...) } - // - // These are both the same at codegen time. - Ok(true) - } - _ => Err(()), - } -} - -pub fn resolve_closure<'a, 'tcx> ( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - requested_kind: ty::ClosureKind) - -> Instance<'tcx> -{ - let actual_kind = substs.closure_kind(def_id, tcx); - - match needs_fn_once_adapter_shim(actual_kind, requested_kind) { - Ok(true) => fn_once_adapter_instance(tcx, def_id, substs), - _ => Instance::new(def_id, substs.substs) - } -} - -pub fn resolve_drop_in_place<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>) - -> ty::Instance<'tcx> -{ - let def_id = tcx.require_lang_item(DropInPlaceFnLangItem); - let substs = tcx.intern_substs(&[ty.into()]); - Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap() -} - -pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - source_ty: Ty<'tcx>, - target_ty: Ty<'tcx>) - -> CustomCoerceUnsized { +pub fn custom_coerce_unsize_info<'tcx>( + tcx: TyCtxt<'tcx>, + source_ty: Ty<'tcx>, + target_ty: Ty<'tcx>, +) -> CustomCoerceUnsized { let def_id = tcx.lang_items().coerce_unsized_trait().unwrap(); let trait_ref = ty::Binder::bind(ty::TraitRef { diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index f342017603ed6..32e4d4f437a78 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -90,32 +90,27 @@ //! //! Note though that as a side-effect of creating a codegen units per //! source-level module, functions from the same module will be available for -//! inlining, even when they are not marked #[inline]. +//! inlining, even when they are not marked `#[inline]`. use std::collections::hash_map::Entry; use std::cmp; use std::sync::Arc; -use syntax::ast::NodeId; use syntax::symbol::InternedString; -use rustc::dep_graph::{WorkProductId, WorkProduct, DepNode, DepConstructor}; use rustc::hir::CodegenFnAttrFlags; +use rustc::hir::def::DefKind; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; -use rustc::hir::map::DefPathData; -use rustc::mir::mono::{Linkage, Visibility, CodegenUnitNameBuilder}; +use rustc::mir::mono::{Linkage, Visibility, CodegenUnitNameBuilder, CodegenUnit}; use rustc::middle::exported_symbols::SymbolExportLevel; -use rustc::ty::{self, TyCtxt, InstanceDef}; -use rustc::ty::item_path::characteristic_def_id_of_type; +use rustc::ty::{self, DefIdTree, TyCtxt, InstanceDef}; +use rustc::ty::print::characteristic_def_id_of_type; use rustc::ty::query::Providers; use rustc::util::common::time; use rustc::util::nodemap::{DefIdSet, FxHashMap, FxHashSet}; -use rustc::mir::mono::MonoItem; +use rustc::mir::mono::{MonoItem, InstantiationMode}; use crate::monomorphize::collector::InliningMap; use crate::monomorphize::collector::{self, MonoItemCollectionMode}; -use crate::monomorphize::item::{MonoItemExt, InstantiationMode}; - -pub use rustc::mir::mono::CodegenUnit; pub enum PartitioningStrategy { /// Generates one codegen unit per source-level module. @@ -125,111 +120,26 @@ pub enum PartitioningStrategy { FixedUnitCount(usize) } -pub trait CodegenUnitExt<'tcx> { - fn as_codegen_unit(&self) -> &CodegenUnit<'tcx>; - - fn contains_item(&self, item: &MonoItem<'tcx>) -> bool { - self.items().contains_key(item) - } - - fn name<'a>(&'a self) -> &'a InternedString - where 'tcx: 'a, - { - &self.as_codegen_unit().name() - } - - fn items(&self) -> &FxHashMap, (Linkage, Visibility)> { - &self.as_codegen_unit().items() - } - - fn work_product_id(&self) -> WorkProductId { - WorkProductId::from_cgu_name(&self.name().as_str()) - } - - fn work_product(&self, tcx: TyCtxt<'_, '_, '_>) -> WorkProduct { - let work_product_id = self.work_product_id(); - tcx.dep_graph - .previous_work_product(&work_product_id) - .unwrap_or_else(|| { - panic!("Could not find work-product for CGU `{}`", self.name()) - }) - } - - fn items_in_deterministic_order<'a>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Vec<(MonoItem<'tcx>, - (Linkage, Visibility))> { - // The codegen tests rely on items being process in the same order as - // they appear in the file, so for local items, we sort by node_id first - #[derive(PartialEq, Eq, PartialOrd, Ord)] - pub struct ItemSortKey(Option, ty::SymbolName); - - fn item_sort_key<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - item: MonoItem<'tcx>) -> ItemSortKey { - ItemSortKey(match item { - MonoItem::Fn(ref instance) => { - match instance.def { - // We only want to take NodeIds of user-defined - // instances into account. The others don't matter for - // the codegen tests and can even make item order - // unstable. - InstanceDef::Item(def_id) => { - tcx.hir().as_local_node_id(def_id) - } - InstanceDef::VtableShim(..) | - InstanceDef::Intrinsic(..) | - InstanceDef::FnPtrShim(..) | - InstanceDef::Virtual(..) | - InstanceDef::ClosureOnceShim { .. } | - InstanceDef::DropGlue(..) | - InstanceDef::CloneShim(..) => { - None - } - } - } - MonoItem::Static(def_id) => { - tcx.hir().as_local_node_id(def_id) - } - MonoItem::GlobalAsm(node_id) => { - Some(node_id) - } - }, item.symbol_name(tcx)) - } - - let mut items: Vec<_> = self.items().iter().map(|(&i, &l)| (i, l)).collect(); - items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i)); - items - } - - fn codegen_dep_node(&self, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> DepNode { - DepNode::new(tcx, DepConstructor::CompileCodegenUnit(self.name().clone())) - } -} - -impl<'tcx> CodegenUnitExt<'tcx> for CodegenUnit<'tcx> { - fn as_codegen_unit(&self) -> &CodegenUnit<'tcx> { - self - } -} - // Anything we can't find a proper codegen unit for goes into this. -fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder<'_, '_, '_>) -> InternedString { +fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder<'_>) -> InternedString { name_builder.build_cgu_name(LOCAL_CRATE, &["fallback"], Some("cgu")) } -pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mono_items: I, - strategy: PartitioningStrategy, - inlining_map: &InliningMap<'tcx>) - -> Vec> - where I: Iterator> +pub fn partition<'tcx, I>( + tcx: TyCtxt<'tcx>, + mono_items: I, + strategy: PartitioningStrategy, + inlining_map: &InliningMap<'tcx>, +) -> Vec> +where + I: Iterator>, { // In the first step, we place all regular monomorphizations into their // respective 'home' codegen unit. Regular monomorphizations are all // functions and statics defined in the local crate. let mut initial_partitioning = place_root_mono_items(tcx, mono_items); - initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(&tcx)); + initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); @@ -244,11 +154,11 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // In the next step, we use the inlining map to determine which additional // monomorphizations have to go into each codegen unit. These additional // monomorphizations can be drop-glue, functions from external crates, and - // local functions the definition of which is marked with #[inline]. + // local functions the definition of which is marked with `#[inline]`. let mut post_inlining = place_inlined_mono_items(initial_partitioning, inlining_map); - post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(&tcx)); + post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter()); @@ -258,7 +168,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, internalize_symbols(tcx, &mut post_inlining, inlining_map); } - // Finally, sort by codegen unit name, so that we get deterministic results + // Finally, sort by codegen unit name, so that we get deterministic results. let PostInliningPartitioning { codegen_units: mut result, mono_item_placements: _, @@ -293,10 +203,9 @@ struct PostInliningPartitioning<'tcx> { internalization_candidates: FxHashSet>, } -fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mono_items: I) - -> PreInliningPartitioning<'tcx> - where I: Iterator> +fn place_root_mono_items<'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) -> PreInliningPartitioning<'tcx> +where + I: Iterator>, { let mut roots = FxHashSet::default(); let mut codegen_units = FxHashMap::default(); @@ -350,8 +259,8 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, roots.insert(mono_item); } - // always ensure we have at least one CGU; otherwise, if we have a - // crate with just types (for example), we could wind up with no CGU + // Always ensure we have at least one CGU; otherwise, if we have a + // crate with just types (for example), we could wind up with no CGU. if codegen_units.is_empty() { let codegen_unit_name = fallback_cgu_name(cgu_name_builder); codegen_units.insert(codegen_unit_name.clone(), @@ -368,7 +277,7 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn mono_item_linkage_and_visibility( - tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, mono_item: &MonoItem<'tcx>, can_be_internalized: &mut bool, export_generics: bool, @@ -386,16 +295,16 @@ fn mono_item_linkage_and_visibility( } fn mono_item_visibility( - tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, mono_item: &MonoItem<'tcx>, can_be_internalized: &mut bool, export_generics: bool, ) -> Visibility { let instance = match mono_item { - // This is pretty complicated, go below + // This is pretty complicated; see below. MonoItem::Fn(instance) => instance, - // Misc handling for generics and such, but otherwise + // Misc handling for generics and such, but otherwise: MonoItem::Static(def_id) => { return if tcx.is_reachable_non_generic(*def_id) { *can_be_internalized = false; @@ -404,8 +313,8 @@ fn mono_item_visibility( Visibility::Hidden }; } - MonoItem::GlobalAsm(node_id) => { - let def_id = tcx.hir().local_def_id(*node_id); + MonoItem::GlobalAsm(hir_id) => { + let def_id = tcx.hir().local_def_id_from_hir_id(*hir_id); return if tcx.is_reachable_non_generic(def_id) { *can_be_internalized = false; default_visibility(tcx, def_id, false) @@ -448,13 +357,12 @@ fn mono_item_visibility( return Visibility::Hidden } - let is_generic = instance.substs.types().next().is_some(); + let is_generic = instance.substs.non_erasable_generics().next().is_some(); - // Upstream `DefId` instances get different handling than local ones + // Upstream `DefId` instances get different handling than local ones. if !def_id.is_local() { return if export_generics && is_generic { - // If it is a upstream monomorphization - // and we export generics, we must make + // If it is a upstream monomorphization and we export generics, we must make // it available to downstream crates. *can_be_internalized = false; default_visibility(tcx, def_id, true) @@ -466,20 +374,16 @@ fn mono_item_visibility( if is_generic { if export_generics { if tcx.is_unreachable_local_definition(def_id) { - // This instance cannot be used - // from another crate. + // This instance cannot be used from another crate. Visibility::Hidden } else { - // This instance might be useful in - // a downstream crate. + // This instance might be useful in a downstream crate. *can_be_internalized = false; default_visibility(tcx, def_id, true) } } else { - // We are not exporting generics or - // the definition is not reachable - // for downstream crates, we can - // internalize its instantiations. + // We are not exporting generics or the definition is not reachable + // for downstream crates, we can internalize its instantiations. Visibility::Hidden } } else { @@ -536,33 +440,35 @@ fn mono_item_visibility( } } -fn default_visibility(tcx: TyCtxt<'_, '_, '_>, id: DefId, is_generic: bool) -> Visibility { +fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { if !tcx.sess.target.target.options.default_hidden_visibility { return Visibility::Default } - // Generic functions never have export level C + // Generic functions never have export-level C. if is_generic { return Visibility::Hidden } // Things with export level C don't get instantiated in - // downstream crates + // downstream crates. if !id.is_local() { return Visibility::Hidden } // C-export level items remain at `Default`, all other internal - // items become `Hidden` + // items become `Hidden`. match tcx.reachable_non_generics(id.krate).get(&id) { Some(SymbolExportLevel::C) => Visibility::Default, _ => Visibility::Hidden, } } -fn merge_codegen_units<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, - initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize) { +fn merge_codegen_units<'tcx>( + tcx: TyCtxt<'tcx>, + initial_partitioning: &mut PreInliningPartitioning<'tcx>, + target_cgu_count: usize, +) { assert!(target_cgu_count >= 1); let codegen_units = &mut initial_partitioning.codegen_units; @@ -611,7 +517,7 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning< let single_codegen_unit = initial_cgus.len() == 1; for old_codegen_unit in initial_cgus { - // Collect all items that need to be available in this codegen unit + // Collect all items that need to be available in this codegen unit. let mut reachable = FxHashSet::default(); for root in old_codegen_unit.items().keys() { follow_inlining(*root, inlining_map, &mut reachable); @@ -619,10 +525,10 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning< let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name().clone()); - // Add all monomorphizations that are not already there + // Add all monomorphizations that are not already there. for mono_item in reachable { if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { - // This is a root, just copy it over + // This is a root, just copy it over. new_codegen_unit.items_mut().insert(mono_item, *linkage); } else { if roots.contains(&mono_item) { @@ -630,7 +536,7 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning< {:?}", mono_item); } - // This is a cgu-private copy + // This is a CGU-private copy. new_codegen_unit.items_mut().insert( mono_item, (Linkage::Internal, Visibility::Default), @@ -639,7 +545,7 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning< if !single_codegen_unit { // If there is more than one codegen unit, we need to keep track - // in which codegen units each monomorphization is placed: + // in which codegen units each monomorphization is placed. match mono_item_placements.entry(mono_item) { Entry::Occupied(e) => { let placement = e.into_mut(); @@ -682,9 +588,11 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning< } } -fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, - partitioning: &mut PostInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>) { +fn internalize_symbols<'tcx>( + _tcx: TyCtxt<'tcx>, + partitioning: &mut PostInliningPartitioning<'tcx>, + inlining_map: &InliningMap<'tcx>, +) { if partitioning.codegen_units.len() == 1 { // Fast path for when there is only one codegen unit. In this case we // can internalize all candidates, since there is nowhere else they @@ -747,9 +655,10 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn characteristic_def_id_of_mono_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mono_item: MonoItem<'tcx>) - -> Option { +fn characteristic_def_id_of_mono_item<'tcx>( + tcx: TyCtxt<'tcx>, + mono_item: MonoItem<'tcx>, +) -> Option { match mono_item { MonoItem::Fn(instance) => { let def_id = match instance.def { @@ -789,50 +698,45 @@ fn characteristic_def_id_of_mono_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Some(def_id) } MonoItem::Static(def_id) => Some(def_id), - MonoItem::GlobalAsm(node_id) => Some(tcx.hir().local_def_id(node_id)), + MonoItem::GlobalAsm(hir_id) => Some(tcx.hir().local_def_id_from_hir_id(hir_id)), } } type CguNameCache = FxHashMap<(DefId, bool), InternedString>; -fn compute_codegen_unit_name(tcx: TyCtxt<'_, '_, '_>, - name_builder: &mut CodegenUnitNameBuilder<'_, '_, '_>, - def_id: DefId, - volatile: bool, - cache: &mut CguNameCache) - -> InternedString { - // Find the innermost module that is not nested within a function +fn compute_codegen_unit_name( + tcx: TyCtxt<'_>, + name_builder: &mut CodegenUnitNameBuilder<'_>, + def_id: DefId, + volatile: bool, + cache: &mut CguNameCache, +) -> InternedString { + // Find the innermost module that is not nested within a function. let mut current_def_id = def_id; let mut cgu_def_id = None; - // Walk backwards from the item we want to find the module for: + // Walk backwards from the item we want to find the module for. loop { - let def_key = tcx.def_key(current_def_id); - - match def_key.disambiguated_data.data { - DefPathData::Module(..) => { - if cgu_def_id.is_none() { - cgu_def_id = Some(current_def_id); - } + if current_def_id.index == CRATE_DEF_INDEX { + if cgu_def_id.is_none() { + // If we have not found a module yet, take the crate root. + cgu_def_id = Some(DefId { + krate: def_id.krate, + index: CRATE_DEF_INDEX, + }); } - DefPathData::CrateRoot { .. } => { - if cgu_def_id.is_none() { - // If we have not found a module yet, take the crate root. - cgu_def_id = Some(DefId { - krate: def_id.krate, - index: CRATE_DEF_INDEX, - }); - } - break - } - _ => { - // If we encounter something that is not a module, throw away - // any module that we've found so far because we now know that - // it is nested within something else. - cgu_def_id = None; + break + } else if tcx.def_kind(current_def_id) == Some(DefKind::Mod) { + if cgu_def_id.is_none() { + cgu_def_id = Some(current_def_id); } + } else { + // If we encounter something that is not a module, throw away + // any module that we've found so far because we now know that + // it is nested within something else. + cgu_def_id = None; } - current_def_id.index = def_key.parent.unwrap(); + current_def_id = tcx.parent(current_def_id).unwrap(); } let cgu_def_id = cgu_def_id.unwrap(); @@ -855,17 +759,17 @@ fn compute_codegen_unit_name(tcx: TyCtxt<'_, '_, '_>, }).clone() } -fn numbered_codegen_unit_name(name_builder: &mut CodegenUnitNameBuilder<'_, '_, '_>, - index: usize) - -> InternedString { +fn numbered_codegen_unit_name( + name_builder: &mut CodegenUnitNameBuilder<'_>, + index: usize, +) -> InternedString { name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index)) } -fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - label: &str, - cgus: I) - where I: Iterator>, - 'tcx: 'a + 'b +fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I) +where + I: Iterator>, + 'tcx: 'a, { if cfg!(debug_assertions) { debug!("{}", label); @@ -889,11 +793,56 @@ fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn collect_and_partition_mono_items<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cnum: CrateNum, -) -> (Arc, Arc>>>) +#[inline(never)] // give this a place in the profiler +fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) +where + I: Iterator>, + 'tcx: 'a, { + let mut symbols: Vec<_> = mono_items.map(|mono_item| { + (mono_item, mono_item.symbol_name(tcx)) + }).collect(); + + symbols.sort_by_key(|sym| sym.1); + + for pair in symbols.windows(2) { + let sym1 = &pair[0].1; + let sym2 = &pair[1].1; + + if sym1 == sym2 { + let mono_item1 = pair[0].0; + let mono_item2 = pair[1].0; + + let span1 = mono_item1.local_span(tcx); + let span2 = mono_item2.local_span(tcx); + + // Deterministically select one of the spans for error reporting + let span = match (span1, span2) { + (Some(span1), Some(span2)) => { + Some(if span1.lo().0 > span2.lo().0 { + span1 + } else { + span2 + }) + } + (span1, span2) => span1.or(span2), + }; + + let error_message = format!("symbol `{}` is already defined", sym1); + + if let Some(span) = span { + tcx.sess.span_fatal(span, &error_message) + } else { + tcx.sess.fatal(&error_message) + } + } + } +} + +fn collect_and_partition_mono_items<'tcx>( + tcx: TyCtxt<'tcx>, + cnum: CrateNum, +) -> (Arc, Arc>>>) { assert_eq!(cnum, LOCAL_CRATE); let collection_mode = match tcx.sess.opts.debugging_opts.print_mono_items { @@ -929,7 +878,7 @@ fn collect_and_partition_mono_items<'a, 'tcx>( tcx.sess.abort_if_errors(); - crate::monomorphize::assert_symbols_are_distinct(tcx, items.iter()); + assert_symbols_are_distinct(tcx, items.iter()); let strategy = if tcx.sess.opts.incremental.is_some() { PartitioningStrategy::PerModule diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index adc328f1033ec..7987095a33401 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -1,8 +1,7 @@ use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::infer; use rustc::mir::*; -use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::VariantIdx; use rustc::ty::subst::{Subst, InternalSubsts}; use rustc::ty::query::Providers; @@ -10,8 +9,7 @@ use rustc::ty::query::Providers; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_target::spec::abi::Abi; -use syntax::ast; -use syntax_pos::Span; +use syntax_pos::{Span, sym}; use std::fmt; use std::iter; @@ -22,15 +20,13 @@ use crate::transform::{ }; use crate::util::elaborate_drops::{self, DropElaborator, DropStyle, DropFlagMode}; use crate::util::patch::MirPatch; +use crate::util::expand_aggregate; pub fn provide(providers: &mut Providers<'_>) { providers.mir_shims = make_shim; } -fn make_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: ty::InstanceDef<'tcx>) - -> &'tcx Mir<'tcx> -{ +fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> { debug!("make_shim({:?})", instance); let mut result = match instance { @@ -85,7 +81,7 @@ fn make_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let fn_mut = tcx.lang_items().fn_mut_trait().unwrap(); let call_mut = tcx.global_tcx() .associated_items(fn_mut) - .find(|it| it.kind == ty::AssociatedKind::Method) + .find(|it| it.kind == ty::AssocKind::Method) .unwrap().def_id; build_call_shim( @@ -101,9 +97,9 @@ fn make_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } ty::InstanceDef::CloneShim(def_id, ty) => { let name = tcx.item_name(def_id); - if name == "clone" { + if name == sym::clone { build_clone_shim(tcx, def_id, ty) - } else if name == "clone_from" { + } else if name == sym::clone_from { debug!("make_shim({:?}: using default trait implementation", instance); return tcx.optimized_mir(def_id); } else { @@ -126,7 +122,7 @@ fn make_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("make_shim({:?}) = {:?}", instance, result); - tcx.alloc_mir(result) + tcx.arena.alloc(result) } #[derive(Copy, Clone, Debug, PartialEq)] @@ -167,17 +163,13 @@ fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>, span: Span) .collect() } -fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - ty: Option>) - -> Mir<'tcx> -{ +fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) -> Body<'tcx> { debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty); // Check if this is a generator, if so, return the drop glue for it if let Some(&ty::TyS { sty: ty::Generator(gen_def_id, substs, _), .. }) = ty { - let mir = &**tcx.optimized_mir(gen_def_id).generator_drop.as_ref().unwrap(); - return mir.subst(tcx, substs.substs); + let body = &**tcx.optimized_mir(gen_def_id).generator_drop.as_ref().unwrap(); + return body.subst(tcx, substs.substs); } let substs = if let Some(ty) = ty { @@ -203,7 +195,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, block(&mut blocks, TerminatorKind::Goto { target: return_block }); block(&mut blocks, TerminatorKind::Return); - let mut mir = Mir::new( + let mut body = Body::new( blocks, IndexVec::from_elem_n( SourceScopeData { span: span, parent_scope: None }, 1 @@ -221,10 +213,10 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Some(..) = ty { // The first argument (index 0), but add 1 for the return value. - let dropee_ptr = Place::Base(PlaceBase::Local(Local::new(1+0))); + let dropee_ptr = Place::from(Local::new(1+0)); if tcx.sess.opts.debugging_opts.mir_emit_retag { // Function arguments should be retagged, and we make this one raw. - mir.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement { + body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement { source_info, kind: StatementKind::Retag(RetagKind::Raw, dropee_ptr.clone()), }); @@ -232,8 +224,8 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let patch = { let param_env = tcx.param_env(def_id).with_reveal_all(); let mut elaborator = DropShimElaborator { - mir: &mir, - patch: MirPatch::new(&mir), + body: &body, + patch: MirPatch::new(&body), tcx, param_env }; @@ -250,16 +242,16 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ); elaborator.patch }; - patch.apply(&mut mir); + patch.apply(&mut body); } - mir + body } -pub struct DropShimElaborator<'a, 'tcx: 'a> { - pub mir: &'a Mir<'tcx>, +pub struct DropShimElaborator<'a, 'tcx> { + pub body: &'a Body<'tcx>, pub patch: MirPatch<'tcx>, - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + pub tcx: TyCtxt<'tcx>, pub param_env: ty::ParamEnv<'tcx>, } @@ -273,8 +265,10 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { type Path = (); fn patch(&mut self) -> &mut MirPatch<'tcx> { &mut self.patch } - fn mir(&self) -> &'a Mir<'tcx> { self.mir } - fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx } + fn body(&self) -> &'a Body<'tcx> { self.body } + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle { @@ -307,18 +301,14 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { } /// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`. -fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - self_ty: Ty<'tcx>) - -> Mir<'tcx> -{ +fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> { debug!("build_clone_shim(def_id={:?})", def_id); let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty); let is_copy = self_ty.is_copy_modulo_regions(tcx, tcx.param_env(def_id), builder.span); let dest = Place::RETURN_PLACE; - let src = Place::Base(PlaceBase::Local(Local::new(1+0))).deref(); + let src = Place::from(Local::new(1+0)).deref(); match self_ty.sty { _ if is_copy => builder.copy_shim(), @@ -332,7 +322,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, substs.upvar_tys(def_id, tcx) ) } - ty::Tuple(tys) => builder.tuple_like_shim(dest, src, tys.iter().cloned()), + ty::Tuple(tys) => builder.tuple_like_shim(dest, src, tys.iter().map(|k| k.expect_ty())), _ => { bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty) } @@ -341,8 +331,8 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, builder.into_mir() } -struct CloneShimBuilder<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct CloneShimBuilder<'tcx> { + tcx: TyCtxt<'tcx>, def_id: DefId, local_decls: IndexVec>, blocks: IndexVec>, @@ -350,10 +340,8 @@ struct CloneShimBuilder<'a, 'tcx: 'a> { sig: ty::FnSig<'tcx>, } -impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { - fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - self_ty: Ty<'tcx>) -> Self { +impl CloneShimBuilder<'tcx> { + fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self { // we must subst the self_ty because it's // otherwise going to be TySelf and we can't index // or access fields of a Place of type TySelf. @@ -372,8 +360,8 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { } } - fn into_mir(self) -> Mir<'tcx> { - Mir::new( + fn into_mir(self) -> Body<'tcx> { + Body::new( self.blocks, IndexVec::from_elem_n( SourceScopeData { span: self.span, parent_scope: None }, 1 @@ -424,7 +412,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { } fn copy_shim(&mut self) { - let rcvr = Place::Base(PlaceBase::Local(Local::new(1+0))).deref(); + let rcvr = Place::from(Local::new(1+0)).deref(); let ret_statement = self.make_statement( StatementKind::Assign( Place::RETURN_PLACE, @@ -436,9 +424,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { fn make_place(&mut self, mutability: Mutability, ty: Ty<'tcx>) -> Place<'tcx> { let span = self.span; - Place::Base(PlaceBase::Local( - self.local_decls.push(temp_decl(mutability, ty, span)) - )) + Place::from(self.local_decls.push(temp_decl(mutability, ty, span))) } fn make_clone_call( @@ -451,12 +437,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { ) { let tcx = self.tcx; - let substs = InternalSubsts::for_item(tcx, self.def_id, |param, _| { - match param.kind { - GenericParamDefKind::Lifetime => tcx.types.re_erased.into(), - GenericParamDefKind::Type {..} => ty.into(), - } - }); + let substs = tcx.mk_substs_trait(ty, &[]); // `func == Clone::clone(&ty) -> ty` let func_ty = tcx.mk_fn_def(self.def_id, substs); @@ -464,14 +445,12 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { span: self.span, ty: func_ty, user_ty: None, - literal: tcx.mk_lazy_const(ty::LazyConst::Evaluated( - ty::Const::zero_sized(func_ty), - )), + literal: ty::Const::zero_sized(tcx, func_ty), }); let ref_loc = self.make_place( Mutability::Not, - tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut { + tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::MutImmutable, }) @@ -481,7 +460,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { let statement = self.make_statement( StatementKind::Assign( ref_loc.clone(), - box Rvalue::Ref(tcx.types.re_erased, BorrowKind::Shared, src) + box Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src) ) ); @@ -526,9 +505,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { span: self.span, ty: self.tcx.types.usize, user_ty: None, - literal: self.tcx.mk_lazy_const(ty::LazyConst::Evaluated( - ty::Const::from_usize(self.tcx, value), - )), + literal: ty::Const::from_usize(self.tcx, value), } } @@ -546,7 +523,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { let inits = vec![ self.make_statement( StatementKind::Assign( - Place::Base(PlaceBase::Local(beg)), + Place::from(beg), box Rvalue::Use(Operand::Constant(self.make_usize(0))) ) ), @@ -564,7 +541,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { // BB #3; // } // BB #4; - self.loop_header(Place::Base(PlaceBase::Local(beg)), + self.loop_header(Place::from(beg), end, BasicBlock::new(2), BasicBlock::new(4), @@ -584,10 +561,10 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { let statements = vec![ self.make_statement( StatementKind::Assign( - Place::Base(PlaceBase::Local(beg)), + Place::from(beg), box Rvalue::BinaryOp( BinOp::Add, - Operand::Copy(Place::Base(PlaceBase::Local(beg))), + Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)) ) ) @@ -607,7 +584,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span)); let init = self.make_statement( StatementKind::Assign( - Place::Base(PlaceBase::Local(beg)), + Place::from(beg), box Rvalue::Use(Operand::Constant(self.make_usize(0))) ) ); @@ -618,7 +595,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { // BB #8; // } // BB #9; - self.loop_header(Place::Base(PlaceBase::Local(beg)), Place::Base(PlaceBase::Local(end)), + self.loop_header(Place::from(beg), Place::from(end), BasicBlock::new(7), BasicBlock::new(9), true); // BB #7 (cleanup) @@ -634,10 +611,10 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { // `goto #6;` let statement = self.make_statement( StatementKind::Assign( - Place::Base(PlaceBase::Local(beg)), + Place::from(beg), box Rvalue::BinaryOp( BinOp::Add, - Operand::Copy(Place::Base(PlaceBase::Local(beg))), + Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)) ) ) @@ -650,7 +627,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { fn tuple_like_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I) - where I: Iterator> { + where I: Iterator> { let mut previous_field = None; for (i, ity) in tys.enumerate() { let field = Field::new(i); @@ -701,13 +678,13 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { /// /// If `untuple_args` is a vec of types, the second argument of the /// function will be untupled as these types. -fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - rcvr_adjustment: Adjustment, - call_kind: CallKind, - untuple_args: Option<&[Ty<'tcx>]>) - -> Mir<'tcx> -{ +fn build_call_shim<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + rcvr_adjustment: Adjustment, + call_kind: CallKind, + untuple_args: Option<&[Ty<'tcx>]>, +) -> Body<'tcx> { debug!("build_call_shim(def_id={:?}, rcvr_adjustment={:?}, \ call_kind={:?}, untuple_args={:?})", def_id, rcvr_adjustment, call_kind, untuple_args); @@ -722,7 +699,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }; let rcvr_arg = Local::new(1+0); - let rcvr_l = Place::Base(PlaceBase::Local(rcvr_arg)); + let rcvr_l = Place::from(rcvr_arg); let mut statements = vec![]; let rcvr = match rcvr_adjustment { @@ -740,7 +717,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // let rcvr = &mut rcvr; let ref_rcvr = local_decls.push(temp_decl( Mutability::Not, - tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut { + tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::MutMutable }), @@ -752,11 +729,11 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, statements.push(Statement { source_info, kind: StatementKind::Assign( - Place::Base(PlaceBase::Local(ref_rcvr)), - box Rvalue::Ref(tcx.types.re_erased, borrow_kind, rcvr_l) + Place::from(ref_rcvr), + box Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l) ) }); - Operand::Move(Place::Base(PlaceBase::Local(ref_rcvr))) + Operand::Move(Place::from(ref_rcvr)) } }; @@ -768,9 +745,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span, ty, user_ty: None, - literal: tcx.mk_lazy_const(ty::LazyConst::Evaluated( - ty::Const::zero_sized(ty) - )), + literal: ty::Const::zero_sized(tcx, ty), }), vec![rcvr]) } @@ -778,12 +753,12 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Some(untuple_args) = untuple_args { args.extend(untuple_args.iter().enumerate().map(|(i, ity)| { - let arg_place = Place::Base(PlaceBase::Local(Local::new(1+1))); + let arg_place = Place::from(Local::new(1+1)); Operand::Move(arg_place.field(Field::new(i), *ity)) })); } else { args.extend((1..sig.inputs().len()).map(|i| { - Operand::Move(Place::Base(PlaceBase::Local(Local::new(1+i)))) + Operand::Move(Place::from(Local::new(1+i))) })); } @@ -814,7 +789,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Adjustment::RefMut = rcvr_adjustment { // BB #1 - drop for Self block(&mut blocks, vec![], TerminatorKind::Drop { - location: Place::Base(PlaceBase::Local(rcvr_arg)), + location: Place::from(rcvr_arg), target: BasicBlock::new(2), unwind: None }, false); @@ -824,7 +799,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Adjustment::RefMut = rcvr_adjustment { // BB #3 - drop if closure panics block(&mut blocks, vec![], TerminatorKind::Drop { - location: Place::Base(PlaceBase::Local(rcvr_arg)), + location: Place::from(rcvr_arg), target: BasicBlock::new(4), unwind: None }, true); @@ -833,7 +808,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, block(&mut blocks, vec![], TerminatorKind::Resume, true); } - let mut mir = Mir::new( + let mut body = Body::new( blocks, IndexVec::from_elem_n( SourceScopeData { span: span, parent_scope: None }, 1 @@ -849,34 +824,31 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, vec![], ); if let Abi::RustCall = sig.abi { - mir.spread_arg = Some(Local::new(sig.inputs().len())); + body.spread_arg = Some(Local::new(sig.inputs().len())); } - mir + body } -pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, - ctor_id: ast::NodeId, - fields: &[hir::StructField], - span: Span) - -> Mir<'tcx> -{ - let tcx = infcx.tcx; - let gcx = tcx.global_tcx(); - let def_id = tcx.hir().local_def_id(ctor_id); - let param_env = gcx.param_env(def_id); +pub fn build_adt_ctor<'tcx>(tcx: TyCtxt<'tcx>, ctor_id: DefId) -> &'tcx Body<'tcx> { + debug_assert!(tcx.is_constructor(ctor_id)); + + let span = tcx.hir().span_if_local(ctor_id) + .unwrap_or_else(|| bug!("no span for ctor {:?}", ctor_id)); + + let param_env = tcx.param_env(ctor_id); // Normalize the sig. - let sig = gcx.fn_sig(def_id) + let sig = tcx.fn_sig(ctor_id) .no_bound_vars() .expect("LBR in ADT constructor signature"); - let sig = gcx.normalize_erasing_regions(param_env, sig); + let sig = tcx.normalize_erasing_regions(param_env, sig); let (adt_def, substs) = match sig.output().sty { ty::Adt(adt_def, substs) => (adt_def, substs), _ => bug!("unexpected type for ADT ctor {:?}", sig.output()) }; - debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields); + debug!("build_ctor: ctor_id={:?} sig={:?}", ctor_id, sig); let local_decls = local_decls_for_sig(&sig, span); @@ -885,26 +857,37 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, scope: OUTERMOST_SOURCE_SCOPE }; - let variant_no = if adt_def.is_enum() { - adt_def.variant_index_with_id(def_id) + let variant_index = if adt_def.is_enum() { + adt_def.variant_index_with_ctor_id(ctor_id) } else { VariantIdx::new(0) }; - // return = ADT(arg0, arg1, ...); return + // Generate the following MIR: + // + // (return as Variant).field0 = arg0; + // (return as Variant).field1 = arg1; + // + // return; + debug!("build_ctor: variant_index={:?}", variant_index); + + let statements = expand_aggregate( + Place::RETURN_PLACE, + adt_def + .variants[variant_index] + .fields + .iter() + .enumerate() + .map(|(idx, field_def)| ( + Operand::Move(Place::from(Local::new(idx + 1))), + field_def.ty(tcx, substs), + )), + AggregateKind::Adt(adt_def, variant_index, substs, None, None), + source_info, + ).collect(); + let start_block = BasicBlockData { - statements: vec![Statement { - source_info, - kind: StatementKind::Assign( - Place::RETURN_PLACE, - box Rvalue::Aggregate( - box AggregateKind::Adt(adt_def, variant_no, substs, None, None), - (1..sig.inputs().len()+1).map(|i| { - Operand::Move(Place::Base(PlaceBase::Local(Local::new(i)))) - }).collect() - ) - ) - }], + statements, terminator: Some(Terminator { source_info, kind: TerminatorKind::Return, @@ -912,7 +895,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, is_cleanup: false }; - Mir::new( + let body = Body::new( IndexVec::from_elem_n(start_block, 1), IndexVec::from_elem_n( SourceScopeData { span: span, parent_scope: None }, 1 @@ -926,5 +909,17 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, vec![], span, vec![], - ) + ); + + crate::util::dump_mir( + tcx, + None, + "mir_map", + &0, + crate::transform::MirSource::item(ctor_id), + &body, + |_, _| Ok(()), + ); + + tcx.arena.alloc(body) } diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs index 88042d64e96b7..c08c33bc6ff8b 100644 --- a/src/librustc_mir/transform/add_call_guards.rs +++ b/src/librustc_mir/transform/add_call_guards.rs @@ -31,25 +31,22 @@ pub use self::AddCallGuards::*; */ impl MirPass for AddCallGuards { - fn run_pass<'a, 'tcx>(&self, - _tcx: TyCtxt<'a, 'tcx, 'tcx>, - _src: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { - self.add_call_guards(mir); + fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + self.add_call_guards(body); } } impl AddCallGuards { - pub fn add_call_guards(&self, mir: &mut Mir<'_>) { + pub fn add_call_guards(&self, body: &mut Body<'_>) { let pred_count: IndexVec<_, _> = - mir.predecessors().iter().map(|ps| ps.len()).collect(); + body.predecessors().iter().map(|ps| ps.len()).collect(); // We need a place to store the new blocks generated let mut new_blocks = Vec::new(); - let cur_len = mir.basic_blocks().len(); + let cur_len = body.basic_blocks().len(); - for block in mir.basic_blocks_mut() { + for block in body.basic_blocks_mut() { match block.terminator { Some(Terminator { kind: TerminatorKind::Call { @@ -81,6 +78,6 @@ impl AddCallGuards { debug!("Broke {} N edges", new_blocks.len()); - mir.basic_blocks_mut().extend(new_blocks); + body.basic_blocks_mut().extend(new_blocks); } } diff --git a/src/librustc_mir/transform/add_moves_for_packed_drops.rs b/src/librustc_mir/transform/add_moves_for_packed_drops.rs index e8528eee0bcab..426e16698d74d 100644 --- a/src/librustc_mir/transform/add_moves_for_packed_drops.rs +++ b/src/librustc_mir/transform/add_moves_for_packed_drops.rs @@ -40,43 +40,34 @@ use crate::util; pub struct AddMovesForPackedDrops; impl MirPass for AddMovesForPackedDrops { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource<'tcx>, - mir: &mut Mir<'tcx>) - { - debug!("add_moves_for_packed_drops({:?} @ {:?})", src, mir.span); - add_moves_for_packed_drops(tcx, mir, src.def_id()); + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + debug!("add_moves_for_packed_drops({:?} @ {:?})", src, body.span); + add_moves_for_packed_drops(tcx, body, src.def_id()); } } -pub fn add_moves_for_packed_drops<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &mut Mir<'tcx>, - def_id: DefId) -{ - let patch = add_moves_for_packed_drops_patch(tcx, mir, def_id); - patch.apply(mir); +pub fn add_moves_for_packed_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, def_id: DefId) { + let patch = add_moves_for_packed_drops_patch(tcx, body, def_id); + patch.apply(body); } -fn add_moves_for_packed_drops_patch<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &Mir<'tcx>, - def_id: DefId) - -> MirPatch<'tcx> -{ - let mut patch = MirPatch::new(mir); +fn add_moves_for_packed_drops_patch<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + def_id: DefId, +) -> MirPatch<'tcx> { + let mut patch = MirPatch::new(body); let param_env = tcx.param_env(def_id); - for (bb, data) in mir.basic_blocks().iter_enumerated() { + for (bb, data) in body.basic_blocks().iter_enumerated() { let loc = Location { block: bb, statement_index: data.statements.len() }; let terminator = data.terminator(); match terminator.kind { TerminatorKind::Drop { ref location, .. } - if util::is_disaligned(tcx, mir, param_env, location) => + if util::is_disaligned(tcx, body, param_env, location) => { - add_move_for_packed_drop(tcx, mir, &mut patch, terminator, + add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup); } TerminatorKind::DropAndReplace { .. } => { @@ -90,14 +81,14 @@ fn add_moves_for_packed_drops_patch<'a, 'tcx>( patch } -fn add_move_for_packed_drop<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &Mir<'tcx>, +fn add_move_for_packed_drop<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, patch: &mut MirPatch<'tcx>, terminator: &Terminator<'tcx>, loc: Location, - is_cleanup: bool) -{ + is_cleanup: bool, +) { debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc); let (location, target, unwind) = match terminator.kind { TerminatorKind::Drop { ref location, target, unwind } => @@ -106,7 +97,7 @@ fn add_move_for_packed_drop<'a, 'tcx>( }; let source_info = terminator.source_info; - let ty = location.ty(mir, tcx).to_ty(tcx); + let ty = location.ty(body, tcx).ty; let temp = patch.new_temp(ty, terminator.source_info.span); let storage_dead_block = patch.new_block(BasicBlockData { @@ -121,10 +112,10 @@ fn add_move_for_packed_drop<'a, 'tcx>( patch.add_statement( loc, StatementKind::StorageLive(temp)); - patch.add_assign(loc, Place::Base(PlaceBase::Local(temp)), + patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(location.clone()))); patch.patch_terminator(loc.block, TerminatorKind::Drop { - location: Place::Base(PlaceBase::Local(temp)), + location: Place::from(temp), target: storage_dead_block, unwind }); diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index 20b75c5586794..e01017d7c9bdb 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -22,7 +22,6 @@ fn is_stable<'tcx>( match *place { // Locals and statics have stable addresses, for sure Base(PlaceBase::Local { .. }) | - Base(PlaceBase::Promoted { .. }) | Base(PlaceBase::Static { .. }) => true, // Recurse for projections @@ -49,7 +48,7 @@ fn is_stable<'tcx>( /// Determine whether this type may have a reference in it, recursing below compound types but /// not below references. -fn may_have_reference<'a, 'gcx, 'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { +fn may_have_reference<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> bool { match ty.sty { // Primitive types that are not references ty::Bool | ty::Char | @@ -64,7 +63,7 @@ fn may_have_reference<'a, 'gcx, 'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) ty::Array(ty, ..) | ty::Slice(ty) => may_have_reference(ty, tcx), ty::Tuple(tys) => - tys.iter().any(|ty| may_have_reference(ty, tcx)), + tys.iter().any(|ty| may_have_reference(ty.expect_ty(), tcx)), ty::Adt(adt, substs) => adt.variants.iter().any(|v| v.fields.iter().any(|f| may_have_reference(f.ty(tcx, substs), tcx) @@ -75,20 +74,16 @@ fn may_have_reference<'a, 'gcx, 'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) } impl MirPass for AddRetag { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _src: MirSource<'tcx>, - mir: &mut Mir<'tcx>) - { + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { if !tcx.sess.opts.debugging_opts.mir_emit_retag { return; } - let (span, arg_count) = (mir.span, mir.arg_count); - let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut(); + let (span, arg_count) = (body.span, body.arg_count); + let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); let needs_retag = |place: &Place<'tcx>| { // FIXME: Instead of giving up for unstable places, we should introduce // a temporary and retag on that. - is_stable(place) && may_have_reference(place.ty(&*local_decls, tcx).to_ty(tcx), tcx) + is_stable(place) && may_have_reference(place.ty(&*local_decls, tcx).ty, tcx) }; // PART 1 @@ -101,7 +96,7 @@ impl MirPass for AddRetag { }; // Gather all arguments, skip return value. let places = local_decls.iter_enumerated().skip(1).take(arg_count) - .map(|(local, _)| Place::Base(PlaceBase::Local(local))) + .map(|(local, _)| Place::from(local)) .filter(needs_retag) .collect::>(); // Emit their retags. @@ -165,7 +160,7 @@ impl MirPass for AddRetag { if src_ty.is_region_ptr() { // The only `Misc` casts on references are those creating raw pointers. assert!(dest_ty.is_unsafe_ptr()); - (RetagKind::Raw, place) + (RetagKind::Raw, place.clone()) } else { // Some other cast, no retag continue @@ -183,7 +178,7 @@ impl MirPass for AddRetag { _ => RetagKind::Default, }; - (kind, place) + (kind, place.clone()) } // Do nothing for the rest _ => continue, @@ -192,7 +187,7 @@ impl MirPass for AddRetag { let source_info = block_data.statements[i].source_info; block_data.statements.insert(i+1, Statement { source_info, - kind: StatementKind::Retag(retag_kind, place.clone()), + kind: StatementKind::Retag(retag_kind, place), }); } } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index a8816720b28bd..24df3549be481 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -12,33 +12,33 @@ use rustc::lint::builtin::{SAFE_EXTERN_STATICS, SAFE_PACKED_BORROWS, UNUSED_UNSA use rustc::mir::*; use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext}; -use syntax::symbol::Symbol; +use syntax::symbol::{InternedString, sym}; use std::ops::Bound; use crate::util; -pub struct UnsafetyChecker<'a, 'tcx: 'a> { - mir: &'a Mir<'tcx>, +pub struct UnsafetyChecker<'a, 'tcx> { + body: &'a Body<'tcx>, const_context: bool, min_const_fn: bool, source_scope_local_data: &'a IndexVec, violations: Vec, source_info: SourceInfo, - tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, /// Mark an `unsafe` block as used, so we don't lint it. used_unsafe: FxHashSet, inherited_blocks: Vec<(hir::HirId, bool)>, } -impl<'a, 'gcx, 'tcx> UnsafetyChecker<'a, 'tcx> { +impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { fn new( const_context: bool, min_const_fn: bool, - mir: &'a Mir<'tcx>, + body: &'a Body<'tcx>, source_scope_local_data: &'a IndexVec, - tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Self { // sanity check @@ -46,13 +46,13 @@ impl<'a, 'gcx, 'tcx> UnsafetyChecker<'a, 'tcx> { assert!(const_context); } Self { - mir, + body, const_context, min_const_fn, source_scope_local_data, violations: vec![], source_info: SourceInfo { - span: mir.span, + span: body.span, scope: OUTERMOST_SOURCE_SCOPE }, tcx, @@ -65,7 +65,6 @@ impl<'a, 'gcx, 'tcx> UnsafetyChecker<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { fn visit_terminator(&mut self, - block: BasicBlock, terminator: &Terminator<'tcx>, location: Location) { @@ -88,7 +87,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } TerminatorKind::Call { ref func, .. } => { - let func_ty = func.ty(self.mir, self.tcx); + let func_ty = func.ty(self.body, self.tcx); let sig = func_ty.fn_sig(self.tcx); if let hir::Unsafety::Unsafe = sig.unsafety() { self.require_unsafe("call to unsafe function", @@ -97,11 +96,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } } } - self.super_terminator(block, terminator, location); + self.super_terminator(terminator, location); } fn visit_statement(&mut self, - block: BasicBlock, statement: &Statement<'tcx>, location: Location) { @@ -124,7 +122,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { UnsafetyViolationKind::General) }, } - self.super_statement(block, statement, location); + self.super_statement(statement, location); } fn visit_rvalue(&mut self, @@ -161,7 +159,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { // pointers during const evaluation have no integral address, only an abstract one Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.const_context && self.tcx.features().const_raw_ptr_to_usize_cast => { - let operand_ty = operand.ty(self.mir, self.tcx); + let operand_ty = operand.ty(self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); match (cast_in, cast_out) { @@ -169,9 +167,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { (CastTy::FnPtr, CastTy::Int(_)) => { self.register_violations(&[UnsafetyViolation { source_info: self.source_info, - description: Symbol::intern("cast of pointer to int").as_interned_str(), - details: Symbol::intern("casting pointers to integers in constants") - .as_interned_str(), + description: InternedString::intern("cast of pointer to int"), + details: InternedString::intern( + "casting pointers to integers in constants"), kind: UnsafetyViolationKind::General, }], &[]); }, @@ -184,12 +182,11 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { // result of a comparison of addresses would differ between runtime and compile-time. Rvalue::BinaryOp(_, ref lhs, _) if self.const_context && self.tcx.features().const_compare_raw_pointers => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.mir, self.tcx).sty { + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).sty { self.register_violations(&[UnsafetyViolation { source_info: self.source_info, - description: Symbol::intern("pointer operation").as_interned_str(), - details: Symbol::intern("operations on pointers in constants") - .as_interned_str(), + description: InternedString::intern("pointer operation"), + details: InternedString::intern("operations on pointers in constants"), kind: UnsafetyViolationKind::General, }], &[]); } @@ -201,33 +198,59 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { fn visit_place(&mut self, place: &Place<'tcx>, - context: PlaceContext<'tcx>, - location: Location) { - match place { - &Place::Projection(box Projection { - ref base, ref elem - }) => { + context: PlaceContext, + _location: Location) { + place.iterate(|place_base, place_projections| { + match place_base { + PlaceBase::Local(..) => { + // Locals are safe. + } + PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => { + bug!("unsafety checking should happen before promotion") + } + PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. }) => { + if self.tcx.is_mutable_static(*def_id) { + self.require_unsafe("use of mutable static", + "mutable statics can be mutated by multiple threads: aliasing \ + violations or data races will cause undefined behavior", + UnsafetyViolationKind::General); + } else if self.tcx.is_foreign_item(*def_id) { + let source_info = self.source_info; + let lint_root = + self.source_scope_local_data[source_info.scope].lint_root; + self.register_violations(&[UnsafetyViolation { + source_info, + description: InternedString::intern("use of extern static"), + details: InternedString::intern( + "extern statics are not controlled by the Rust type system: \ + invalid data, aliasing violations or data races will cause \ + undefined behavior"), + kind: UnsafetyViolationKind::ExternStatic(lint_root) + }], &[]); + } + } + } + + for proj in place_projections { if context.is_borrow() { - if util::is_disaligned(self.tcx, self.mir, self.param_env, place) { + if util::is_disaligned(self.tcx, self.body, self.param_env, place) { let source_info = self.source_info; let lint_root = self.source_scope_local_data[source_info.scope].lint_root; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern("borrow of packed field").as_interned_str(), - details: - Symbol::intern("fields of packed structs might be misaligned: \ - dereferencing a misaligned pointer or even just \ - creating a misaligned reference is undefined \ - behavior") - .as_interned_str(), + description: InternedString::intern("borrow of packed field"), + details: InternedString::intern( + "fields of packed structs might be misaligned: dereferencing a \ + misaligned pointer or even just creating a misaligned reference \ + is undefined behavior"), kind: UnsafetyViolationKind::BorrowPacked(lint_root) }], &[]); } } - let is_borrow_of_interior_mut = context.is_borrow() && !base - .ty(self.mir, self.tcx) - .to_ty(self.tcx) + let is_borrow_of_interior_mut = context.is_borrow() && !proj.base + .ty(self.body, self.tcx) + .ty .is_freeze(self.tcx, self.param_env, self.source_info.span); // prevent // * `&mut x.field` @@ -241,15 +264,15 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { ); } let old_source_info = self.source_info; - if let &Place::Base(PlaceBase::Local(local)) = base { - if self.mir.local_decls[local].internal { + if let Place::Base(PlaceBase::Local(local)) = proj.base { + if self.body.local_decls[local].internal { // Internal locals are used in the `move_val_init` desugaring. // We want to check unsafety against the source info of the // desugaring, rather than the source info of the RHS. - self.source_info = self.mir.local_decls[local].source_info; + self.source_info = self.body.local_decls[local].source_info; } } - let base_ty = base.ty(self.mir, self.tcx).to_ty(self.tcx); + let base_ty = proj.base.ty(self.body, self.tcx).ty; match base_ty.sty { ty::RawPtr(..) => { self.require_unsafe("dereference of raw pointer", @@ -265,8 +288,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { MutatingUseContext::AsmOutput ) { - let elem_ty = match elem { - &ProjectionElem::Field(_, ty) => ty, + let elem_ty = match proj.elem { + ProjectionElem::Field(_, ty) => ty, _ => span_bug!( self.source_info.span, "non-field projection {:?} from union?", @@ -297,36 +320,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } self.source_info = old_source_info; } - &Place::Base(PlaceBase::Local(..)) => { - // locals are safe - } - &Place::Base(PlaceBase::Promoted(_)) => { - bug!("unsafety checking should happen before promotion") - } - &Place::Base(PlaceBase::Static(box Static { def_id, ty: _ })) => { - if self.tcx.is_static(def_id) == Some(hir::Mutability::MutMutable) { - self.require_unsafe("use of mutable static", - "mutable statics can be mutated by multiple threads: aliasing violations \ - or data races will cause undefined behavior", - UnsafetyViolationKind::General); - } else if self.tcx.is_foreign_item(def_id) { - let source_info = self.source_info; - let lint_root = - self.source_scope_local_data[source_info.scope].lint_root; - self.register_violations(&[UnsafetyViolation { - source_info, - description: Symbol::intern("use of extern static").as_interned_str(), - details: - Symbol::intern("extern statics are not controlled by the Rust type \ - system: invalid data, aliasing violations or data \ - races will cause undefined behavior") - .as_interned_str(), - kind: UnsafetyViolationKind::ExternStatic(lint_root) - }], &[]); - } - } - }; - self.super_place(place, context, location); + }); } } @@ -340,8 +334,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { let source_info = self.source_info; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern(description).as_interned_str(), - details: Symbol::intern(details).as_interned_str(), + description: InternedString::intern(description), + details: InternedString::intern(details), kind, }], &[]); } @@ -418,7 +412,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { }) = place { match *elem { ProjectionElem::Field(..) => { - let ty = base.ty(&self.mir.local_decls, self.tcx).to_ty(self.tcx); + let ty = base.ty(&self.body.local_decls, self.tcx).ty; match ty.sty { ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) { (Bound::Unbounded, Bound::Unbounded) => {}, @@ -441,8 +435,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { let source_info = self.source_info; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern(description).as_interned_str(), - details: Symbol::intern(details).as_interned_str(), + description: InternedString::intern(description), + details: InternedString::intern(details), kind: UnsafetyViolationKind::GeneralAndConstFn, }], &[]); } @@ -486,14 +480,15 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'a> { } } -fn check_unused_unsafe<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - used_unsafe: &FxHashSet, - unsafe_blocks: &'a mut Vec<(hir::HirId, bool)>) -{ +fn check_unused_unsafe<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + used_unsafe: &FxHashSet, + unsafe_blocks: &'a mut Vec<(hir::HirId, bool)>, +) { let body_id = tcx.hir().as_local_hir_id(def_id).and_then(|hir_id| { - tcx.hir().maybe_body_owned_by_by_hir_id(hir_id) + tcx.hir().maybe_body_owned_by(hir_id) }); let body_id = match body_id { @@ -511,16 +506,14 @@ fn check_unused_unsafe<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir::intravisit::Visitor::visit_body(&mut visitor, body); } -fn unsafety_check_result<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> UnsafetyCheckResult -{ +fn unsafety_check_result<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> UnsafetyCheckResult { debug!("unsafety_violations({:?})", def_id); // N.B., this borrow is valid because all the consumers of // `mir_built` force this. - let mir = &tcx.mir_built(def_id).borrow(); + let body = &tcx.mir_built(def_id).borrow(); - let source_scope_local_data = match mir.source_scope_local_data { + let source_scope_local_data = match body.source_scope_local_data { ClearCrossCrate::Set(ref data) => data, ClearCrossCrate::Clear => { debug!("unsafety_violations: {:?} - remote, skipping", def_id); @@ -533,7 +526,7 @@ fn unsafety_check_result<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) let param_env = tcx.param_env(def_id); - let id = tcx.hir().as_local_node_id(def_id).unwrap(); + let id = tcx.hir().as_local_hir_id(def_id).unwrap(); let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) { hir::BodyOwnerKind::Closure => (false, false), hir::BodyOwnerKind::Fn => (tcx.is_const_fn(def_id), tcx.is_min_const_fn(def_id)), @@ -542,8 +535,8 @@ fn unsafety_check_result<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) }; let mut checker = UnsafetyChecker::new( const_context, min_const_fn, - mir, source_scope_local_data, tcx, param_env); - checker.visit_mir(mir); + body, source_scope_local_data, tcx, param_env); + checker.visit_body(body); check_unused_unsafe(tcx, def_id, &checker.used_unsafe, &mut checker.inherited_blocks); UnsafetyCheckResult { @@ -552,15 +545,15 @@ fn unsafety_check_result<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) } } -fn unsafe_derive_on_repr_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { +fn unsafe_derive_on_repr_packed<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) { let lint_hir_id = tcx.hir().as_local_hir_id(def_id).unwrap_or_else(|| bug!("checking unsafety for non-local def id {:?}", def_id)); // FIXME: when we make this a hard error, this should have its // own error code. - let message = if tcx.generics_of(def_id).own_counts().types != 0 { + let message = if tcx.generics_of(def_id).own_requires_monomorphization() { "#[derive] can't be used on a #[repr(packed)] struct with \ - type parameters (error E0133)".to_string() + type or const parameters (error E0133)".to_string() } else { "#[derive] can't be used on a #[repr(packed)] struct that \ does not derive Copy (error E0133)".to_string() @@ -572,17 +565,19 @@ fn unsafe_derive_on_repr_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: D } /// Returns the `HirId` for an enclosing scope that is also `unsafe`. -fn is_enclosed(tcx: TyCtxt<'_, '_, '_>, - used_unsafe: &FxHashSet, - id: hir::HirId) -> Option<(String, hir::HirId)> { - let parent_id = tcx.hir().get_parent_node_by_hir_id(id); +fn is_enclosed( + tcx: TyCtxt<'_>, + used_unsafe: &FxHashSet, + id: hir::HirId, +) -> Option<(String, hir::HirId)> { + let parent_id = tcx.hir().get_parent_node(id); if parent_id != id { if used_unsafe.contains(&parent_id) { Some(("block".to_string(), parent_id)) } else if let Some(Node::Item(&hir::Item { node: hir::ItemKind::Fn(_, header, _, _), .. - })) = tcx.hir().find_by_hir_id(parent_id) { + })) = tcx.hir().find(parent_id) { match header.unsafety { hir::Unsafety::Unsafe => Some(("fn".to_string(), parent_id)), hir::Unsafety::Normal => None, @@ -595,24 +590,22 @@ fn is_enclosed(tcx: TyCtxt<'_, '_, '_>, } } -fn report_unused_unsafe(tcx: TyCtxt<'_, '_, '_>, - used_unsafe: &FxHashSet, - id: hir::HirId) { - let span = tcx.sess.source_map().def_span(tcx.hir().span_by_hir_id(id)); +fn report_unused_unsafe(tcx: TyCtxt<'_>, used_unsafe: &FxHashSet, id: hir::HirId) { + let span = tcx.sess.source_map().def_span(tcx.hir().span(id)); let msg = "unnecessary `unsafe` block"; let mut db = tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, msg); db.span_label(span, msg); if let Some((kind, id)) = is_enclosed(tcx, used_unsafe, id) { - db.span_label(tcx.sess.source_map().def_span(tcx.hir().span_by_hir_id(id)), + db.span_label(tcx.sess.source_map().def_span(tcx.hir().span(id)), format!("because it's nested under this `unsafe` {}", kind)); } db.emit(); } -fn builtin_derive_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option { +fn builtin_derive_def_id<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option { debug!("builtin_derive_def_id({:?})", def_id); if let Some(impl_def_id) = tcx.impl_of_method(def_id) { - if tcx.has_attr(impl_def_id, "automatically_derived") { + if tcx.has_attr(impl_def_id, sym::automatically_derived) { debug!("builtin_derive_def_id({:?}) - is {:?}", def_id, impl_def_id); Some(impl_def_id) } else { @@ -625,7 +618,7 @@ fn builtin_derive_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - } } -pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { +pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) { debug!("check_unsafety({:?})", def_id); // closures are handled by their parent fn. diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index 349b27523a0a1..6ee14160bbd1b 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -16,7 +16,7 @@ //! [`FakeRead`]: rustc::mir::StatementKind::FakeRead //! [`Nop`]: rustc::mir::StatementKind::Nop -use rustc::mir::{BasicBlock, BorrowKind, Rvalue, Location, Mir}; +use rustc::mir::{BorrowKind, Rvalue, Location, Body}; use rustc::mir::{Statement, StatementKind}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; @@ -27,18 +27,14 @@ pub struct CleanupNonCodegenStatements; pub struct DeleteNonCodegenStatements; impl MirPass for CleanupNonCodegenStatements { - fn run_pass<'a, 'tcx>(&self, - _tcx: TyCtxt<'a, 'tcx, 'tcx>, - _source: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { + fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { let mut delete = DeleteNonCodegenStatements; - delete.visit_mir(mir); + delete.visit_body(body); } } impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements { fn visit_statement(&mut self, - block: BasicBlock, statement: &mut Statement<'tcx>, location: Location) { match statement.kind { @@ -47,6 +43,6 @@ impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements { | StatementKind::FakeRead(..) => statement.make_nop(), _ => (), } - self.super_statement(block, statement, location); + self.super_statement(statement, location); } } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 9febe6af5b1fc..c7a2fdd93830f 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -1,24 +1,31 @@ //! Propagates constants for early reporting of statically known //! assertion failures - -use rustc::hir::def::Def; -use rustc::mir::{Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Local}; -use rustc::mir::{NullOp, UnOp, StatementKind, Statement, BasicBlock, LocalKind}; -use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem}; -use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext}; -use rustc::mir::interpret::{EvalErrorKind, Scalar, GlobalId, EvalResult}; -use rustc::ty::{TyCtxt, self, Instance}; -use syntax::source_map::{Span, DUMMY_SP}; +use std::cell::Cell; + +use rustc::hir::def::DefKind; +use rustc::mir::{ + AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, + Local, NullOp, UnOp, StatementKind, Statement, LocalKind, Static, StaticKind, + TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem, + SourceScope, SourceScopeLocalData, LocalDecl, Promoted, +}; +use rustc::mir::visit::{ + Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext, +}; +use rustc::mir::interpret::{InterpError, Scalar, GlobalId, InterpResult}; +use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; +use syntax_pos::{Span, DUMMY_SP}; use rustc::ty::subst::InternalSubsts; use rustc_data_structures::indexed_vec::IndexVec; -use rustc::ty::ParamEnv; use rustc::ty::layout::{ - LayoutOf, TyLayout, LayoutError, - HasTyCtxt, TargetDataLayout, HasDataLayout, + LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, Size, }; -use crate::interpret::{EvalContext, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind}; +use crate::interpret::{ + self, InterpretCx, ScalarMaybeUndef, Immediate, OpTy, + ImmTy, MemoryKind, StackPopCleanup, LocalValue, LocalState, +}; use crate::const_eval::{ CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx, }; @@ -27,22 +34,19 @@ use crate::transform::{MirPass, MirSource}; pub struct ConstProp; impl MirPass for ConstProp { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { // will be evaluated by miri and produce its errors there if source.promoted.is_some() { return; } use rustc::hir::map::blocks::FnLikeNode; - let node_id = tcx.hir().as_local_node_id(source.def_id()) - .expect("Non-local call to local provider is_const_fn"); + let hir_id = tcx.hir().as_local_hir_id(source.def_id()) + .expect("Non-local call to local provider is_const_fn"); - let is_fn_like = FnLikeNode::from_node(tcx.hir().get(node_id)).is_some(); - let is_assoc_const = match tcx.describe_def(source.def_id()) { - Some(Def::AssociatedConst(_)) => true, + let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); + let is_assoc_const = match tcx.def_kind(source.def_id()) { + Some(DefKind::AssocConst) => true, _ => false, }; @@ -55,82 +59,190 @@ impl MirPass for ConstProp { trace!("ConstProp starting for {:?}", source.def_id()); + // Steal some data we need from `body`. + let source_scope_local_data = std::mem::replace( + &mut body.source_scope_local_data, + ClearCrossCrate::Clear + ); + let promoted = std::mem::replace( + &mut body.promoted, + IndexVec::new() + ); + + let dummy_body = + &Body::new( + body.basic_blocks().clone(), + Default::default(), + ClearCrossCrate::Clear, + Default::default(), + None, + body.local_decls.clone(), + Default::default(), + body.arg_count, + Default::default(), + tcx.def_span(source.def_id()), + Default::default(), + ); + // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold // constants, instead of just checking for const-folding succeeding. // That would require an uniform one-def no-mutation analysis // and RPO (or recursing when needing the value of a local). - let mut optimization_finder = ConstPropagator::new(mir, tcx, source); - optimization_finder.visit_mir(mir); + let mut optimization_finder = ConstPropagator::new( + body, + dummy_body, + source_scope_local_data, + promoted, + tcx, + source + ); + optimization_finder.visit_body(body); + + // put back the data we stole from `mir` + let (source_scope_local_data, promoted) = optimization_finder.release_stolen_data(); + std::mem::replace( + &mut body.source_scope_local_data, + source_scope_local_data + ); + std::mem::replace( + &mut body.promoted, + promoted + ); trace!("ConstProp done for {:?}", source.def_id()); } } -type Const<'tcx> = (OpTy<'tcx>, Span); +type Const<'tcx> = OpTy<'tcx>; /// Finds optimization opportunities on the MIR. -struct ConstPropagator<'a, 'mir, 'tcx:'a+'mir> { - ecx: EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>, - mir: &'mir Mir<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct ConstPropagator<'mir, 'tcx> { + ecx: InterpretCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, + tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, - places: IndexVec>>, can_const_prop: IndexVec, param_env: ParamEnv<'tcx>, + source_scope_local_data: ClearCrossCrate>, + local_decls: IndexVec>, + promoted: IndexVec>, } -impl<'a, 'b, 'tcx> LayoutOf for ConstPropagator<'a, 'b, 'tcx> { - type Ty = ty::Ty<'tcx>; +impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> { + type Ty = Ty<'tcx>; type TyLayout = Result, LayoutError<'tcx>>; - fn layout_of(&self, ty: ty::Ty<'tcx>) -> Self::TyLayout { + fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout { self.tcx.layout_of(self.param_env.and(ty)) } } -impl<'a, 'b, 'tcx> HasDataLayout for ConstPropagator<'a, 'b, 'tcx> { +impl<'mir, 'tcx> HasDataLayout for ConstPropagator<'mir, 'tcx> { #[inline] fn data_layout(&self) -> &TargetDataLayout { &self.tcx.data_layout } } -impl<'a, 'b, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'a, 'b, 'tcx> { +impl<'mir, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'mir, 'tcx> { #[inline] - fn tcx<'c>(&'c self) -> TyCtxt<'c, 'tcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } } -impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn new( - mir: &'mir Mir<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, + body: &Body<'tcx>, + dummy_body: &'mir Body<'tcx>, + source_scope_local_data: ClearCrossCrate>, + promoted: IndexVec>, + tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, - ) -> ConstPropagator<'a, 'mir, 'tcx> { - let param_env = tcx.param_env(source.def_id()); - let ecx = mk_eval_cx(tcx, tcx.def_span(source.def_id()), param_env); + ) -> ConstPropagator<'mir, 'tcx> { + let def_id = source.def_id(); + let param_env = tcx.param_env(def_id); + let span = tcx.def_span(def_id); + let mut ecx = mk_eval_cx(tcx, span, param_env); + let can_const_prop = CanConstProp::check(body); + + ecx.push_stack_frame( + Instance::new(def_id, &InternalSubsts::identity_for_item(tcx, def_id)), + span, + dummy_body, + None, + StackPopCleanup::None { + cleanup: false, + }, + ).expect("failed to push initial stack frame"); + ConstPropagator { ecx, - mir, tcx, source, param_env, - can_const_prop: CanConstProp::check(mir), - places: IndexVec::from_elem(None, &mir.local_decls), + can_const_prop, + source_scope_local_data, + //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it + local_decls: body.local_decls.clone(), + promoted, } } + fn release_stolen_data( + self, + ) -> ( + ClearCrossCrate>, + IndexVec>, + ) { + (self.source_scope_local_data, self.promoted) + } + + fn get_const(&self, local: Local) -> Option> { + let l = &self.ecx.frame().locals[local]; + + // If the local is `Unitialized` or `Dead` then we haven't propagated a value into it. + // + // `InterpretCx::access_local()` mostly takes care of this for us however, for ZSTs, + // it will synthesize a value for us. In doing so, that will cause the + // `get_const(l).is_empty()` assert right before we call `set_const()` in `visit_statement` + // to fail. + if let LocalValue::Uninitialized | LocalValue::Dead = l.value { + return None; + } + + self.ecx.access_local(self.ecx.frame(), local, None).ok() + } + + fn set_const(&mut self, local: Local, c: Const<'tcx>) { + let frame = self.ecx.frame_mut(); + + if let Some(layout) = frame.locals[local].layout.get() { + debug_assert_eq!(c.layout, layout); + } + + frame.locals[local] = LocalState { + value: LocalValue::Live(*c), + layout: Cell::new(Some(c.layout)), + }; + } + + fn remove_const(&mut self, local: Local) { + self.ecx.frame_mut().locals[local] = LocalState { + value: LocalValue::Uninitialized, + layout: Cell::new(None), + }; + } + fn use_ecx( &mut self, source_info: SourceInfo, f: F ) -> Option where - F: FnOnce(&mut Self) -> EvalResult<'tcx, T>, + F: FnOnce(&mut Self) -> InterpResult<'tcx, T>, { self.ecx.tcx.span = source_info.span; - let lint_root = match self.mir.source_scope_local_data { + let lint_root = match self.source_scope_local_data { ClearCrossCrate::Set(ref ivs) => { //FIXME(#51314): remove this check if source_info.scope.index() >= ivs.len() { @@ -144,10 +256,11 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { Ok(val) => Some(val), Err(error) => { let diagnostic = error_to_const_error(&self.ecx, error); - use rustc::mir::interpret::EvalErrorKind::*; + use rustc::mir::interpret::InterpError::*; match diagnostic.error { // don't report these, they make no sense in a const prop context | MachineError(_) + | Exit(_) // at runtime these transformations might make sense // FIXME: figure out the rules and start linting | FunctionAbiMismatch(..) @@ -237,6 +350,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { self.ecx.tcx, "this expression will panic at runtime", lint_root, + None, ); } } @@ -250,12 +364,11 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { fn eval_constant( &mut self, c: &Constant<'tcx>, - source_info: SourceInfo, ) -> Option> { - self.ecx.tcx.span = source_info.span; - match self.ecx.eval_lazy_const_to_op(*c.literal, None) { + self.ecx.tcx.span = c.span; + match self.ecx.eval_const_to_op(c.literal, None) { Ok(op) => { - Some((op, c.span)) + Some(op) }, Err(error) => { let err = error_to_const_error(&self.ecx, error); @@ -266,49 +379,62 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { } fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option> { - match *place { - Place::Base(PlaceBase::Local(loc)) => self.places[loc].clone(), - Place::Projection(ref proj) => match proj.elem { - ProjectionElem::Field(field, _) => { - trace!("field proj on {:?}", proj.base); - let (base, span) = self.eval_place(&proj.base, source_info)?; + trace!("eval_place(place={:?})", place); + place.iterate(|place_base, place_projection| { + let mut eval = match place_base { + PlaceBase::Local(loc) => self.get_const(*loc).clone()?, + PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted), ..}) => { + let generics = self.tcx.generics_of(self.source.def_id()); + if generics.requires_monomorphization(self.tcx) { + // FIXME: can't handle code with generics + return None; + } + let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id()); + let instance = Instance::new(self.source.def_id(), substs); + let cid = GlobalId { + instance, + promoted: Some(*promoted), + }; + // cannot use `const_eval` here, because that would require having the MIR + // for the current function available, but we're producing said MIR right now let res = self.use_ecx(source_info, |this| { - this.ecx.operand_field(base, field.index() as u64) + let body = &this.promoted[*promoted]; + eval_promoted(this.tcx, cid, body, this.param_env) })?; - Some((res, span)) - }, - // We could get more projections by using e.g., `operand_projection`, - // but we do not even have the stack frame set up properly so - // an `Index` projection would throw us off-track. - _ => None, - }, - Place::Base(PlaceBase::Promoted(ref promoted)) => { - let generics = self.tcx.generics_of(self.source.def_id()); - if generics.requires_monomorphization(self.tcx) { - // FIXME: can't handle code with generics - return None; + trace!("evaluated promoted {:?} to {:?}", promoted, res); + res.into() } - let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id()); - let instance = Instance::new(self.source.def_id(), substs); - let cid = GlobalId { - instance, - promoted: Some(promoted.0), - }; - // cannot use `const_eval` here, because that would require having the MIR - // for the current function available, but we're producing said MIR right now - let res = self.use_ecx(source_info, |this| { - eval_promoted(this.tcx, cid, this.mir, this.param_env) - })?; - trace!("evaluated promoted {:?} to {:?}", promoted, res); - Some((res.into(), source_info.span)) - }, - _ => None, - } + _ => return None, + }; + + for proj in place_projection { + match proj.elem { + ProjectionElem::Field(field, _) => { + trace!("field proj on {:?}", proj.base); + eval = self.use_ecx(source_info, |this| { + this.ecx.operand_field(eval, field.index() as u64) + })?; + }, + ProjectionElem::Deref => { + trace!("processing deref"); + eval = self.use_ecx(source_info, |this| { + this.ecx.deref_operand(eval) + })?.into(); + } + // We could get more projections by using e.g., `operand_projection`, + // but we do not even have the stack frame set up properly so + // an `Index` projection would throw us off-track. + _ => return None, + } + } + + Some(eval) + }) } fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option> { match *op { - Operand::Constant(ref c) => self.eval_constant(c, source_info), + Operand::Constant(ref c) => self.eval_constant(c), | Operand::Move(ref place) | Operand::Copy(ref place) => self.eval_place(place, source_info), } @@ -325,36 +451,56 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { Rvalue::Use(ref op) => { self.eval_operand(op, source_info) }, + Rvalue::Ref(_, _, ref place) => { + let src = self.eval_place(place, source_info)?; + let mplace = src.try_as_mplace().ok()?; + Some(ImmTy::from_scalar(mplace.ptr.into(), place_layout).into()) + }, Rvalue::Repeat(..) | - Rvalue::Ref(..) | Rvalue::Aggregate(..) | Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::Discriminant(..) => None, Rvalue::Cast(kind, ref operand, _) => { - let (op, span) = self.eval_operand(operand, source_info)?; + let op = self.eval_operand(operand, source_info)?; self.use_ecx(source_info, |this| { let dest = this.ecx.allocate(place_layout, MemoryKind::Stack); this.ecx.cast(op, kind, dest.into())?; - Ok((dest.into(), span)) + Ok(dest.into()) }) - } + }, + Rvalue::Len(ref place) => { + let place = self.eval_place(&place, source_info)?; + let mplace = place.try_as_mplace().ok()?; - // FIXME(oli-obk): evaluate static/constant slice lengths - Rvalue::Len(_) => None, + if let ty::Slice(_) = mplace.layout.ty.sty { + let len = mplace.meta.unwrap().to_usize(&self.ecx).unwrap(); + + Some(ImmTy { + imm: Immediate::Scalar( + Scalar::from_uint( + len, + Size::from_bits( + self.tcx.sess.target.usize_ty.bit_width().unwrap() as u64 + ) + ).into(), + ), + layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?, + }.into()) + } else { + trace!("not slice: {:?}", mplace.layout.ty.sty); + None + } + }, Rvalue::NullaryOp(NullOp::SizeOf, ty) => { - type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some(( + type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some( ImmTy { imm: Immediate::Scalar( - Scalar::Bits { - bits: n as u128, - size: self.tcx.data_layout.pointer_size.bytes() as u8, - }.into() + Scalar::from_uint(n, self.tcx.data_layout.pointer_size).into() ), layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?, - }.into(), - span, - ))) + }.into() + )) } Rvalue::UnaryOp(op, ref arg) => { let def_id = if self.tcx.is_closure(self.source.def_id()) { @@ -368,7 +514,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { return None; } - let (arg, _) = self.eval_operand(arg, source_info)?; + let arg = self.eval_operand(arg, source_info)?; let val = self.use_ecx(source_info, |this| { let prim = this.ecx.read_immediate(arg)?; match op { @@ -390,7 +536,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { imm: Immediate::Scalar(val.into()), layout: place_layout, }; - Some((res.into(), span)) + Some(res.into()) } Rvalue::CheckedBinaryOp(op, ref left, ref right) | Rvalue::BinaryOp(op, ref left, ref right) => { @@ -408,20 +554,20 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { } let r = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(right.0) + this.ecx.read_immediate(right) })?; if op == BinOp::Shr || op == BinOp::Shl { - let left_ty = left.ty(self.mir, self.tcx); + let left_ty = left.ty(&self.local_decls, self.tcx); let left_bits = self .tcx .layout_of(self.param_env.and(left_ty)) .unwrap() .size .bits(); - let right_size = right.0.layout.size; + let right_size = right.layout.size; let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); if r_bits.ok().map_or(false, |b| b >= left_bits as u128) { - let source_scope_local_data = match self.mir.source_scope_local_data { + let source_scope_local_data = match self.source_scope_local_data { ClearCrossCrate::Set(ref data) => data, ClearCrossCrate::Clear => return None, }; @@ -441,7 +587,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { } let left = self.eval_operand(left, source_info)?; let l = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(left.0) + this.ecx.read_immediate(left) })?; trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); let (val, overflow) = self.use_ecx(source_info, |this| { @@ -454,7 +600,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { ) } else { if overflow { - let err = EvalErrorKind::Overflow(op).into(); + let err = InterpError::Overflow(op).into(); let _: Option<()> = self.use_ecx(source_info, |_| Err(err)); return None; } @@ -464,15 +610,88 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { imm: val, layout: place_layout, }; - Some((res.into(), span)) + Some(res.into()) }, } } + + fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>, span: Span) -> Operand<'tcx> { + Operand::Constant(Box::new( + Constant { + span, + ty, + user_ty: None, + literal: self.tcx.mk_const(*ty::Const::from_scalar( + self.tcx, + scalar, + ty, + )) + } + )) + } + + fn replace_with_const( + &mut self, + rval: &mut Rvalue<'tcx>, + value: Const<'tcx>, + source_info: SourceInfo, + ) { + trace!("attepting to replace {:?} with {:?}", rval, value); + if let Err(e) = self.ecx.validate_operand( + value, + vec![], + // FIXME: is ref tracking too expensive? + Some(&mut interpret::RefTracking::empty()), + ) { + trace!("validation error, attempt failed: {:?}", e); + return; + } + + // FIXME> figure out what tho do when try_read_immediate fails + let imm = self.use_ecx(source_info, |this| { + this.ecx.try_read_immediate(value) + }); + + if let Some(Ok(imm)) = imm { + match *imm { + interpret::Immediate::Scalar(ScalarMaybeUndef::Scalar(scalar)) => { + *rval = Rvalue::Use( + self.operand_from_scalar(scalar, value.layout.ty, source_info.span)); + }, + Immediate::ScalarPair( + ScalarMaybeUndef::Scalar(one), + ScalarMaybeUndef::Scalar(two) + ) => { + let ty = &value.layout.ty.sty; + if let ty::Tuple(substs) = ty { + *rval = Rvalue::Aggregate( + Box::new(AggregateKind::Tuple), + vec![ + self.operand_from_scalar( + one, substs[0].expect_ty(), source_info.span + ), + self.operand_from_scalar( + two, substs[1].expect_ty(), source_info.span + ), + ], + ); + } + }, + _ => { } + } + } + } + + fn should_const_prop(&self) -> bool { + self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2 + } } -fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: ty::Ty<'tcx>) -> Option { +fn type_size_of<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> Option { tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes()) } @@ -484,10 +703,10 @@ struct CanConstProp { impl CanConstProp { /// returns true if `local` can be propagated - fn check(mir: &Mir<'_>) -> IndexVec { + fn check(body: &Body<'_>) -> IndexVec { let mut cpv = CanConstProp { - can_const_prop: IndexVec::from_elem(true, &mir.local_decls), - found_assignment: IndexVec::from_elem(false, &mir.local_decls), + can_const_prop: IndexVec::from_elem(true, &body.local_decls), + found_assignment: IndexVec::from_elem(false, &body.local_decls), }; for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { // cannot use args at all @@ -495,9 +714,13 @@ impl CanConstProp { // lint for x != y // FIXME(oli-obk): lint variables until they are used in a condition // FIXME(oli-obk): lint if return value is constant - *val = mir.local_kind(local) == LocalKind::Temp; + *val = body.local_kind(local) == LocalKind::Temp; + + if !*val { + trace!("local {:?} can't be propagated because it's not a temporary", local); + } } - cpv.visit_mir(mir); + cpv.visit_body(body); cpv.can_const_prop } } @@ -506,7 +729,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { fn visit_local( &mut self, &local: &Local, - context: PlaceContext<'tcx>, + context: PlaceContext, _: Location, ) { use rustc::mir::visit::PlaceContext::*; @@ -515,6 +738,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { // FIXME(oli-obk): we could be more powerful here, if the multiple writes // only occur in independent execution paths MutatingUse(MutatingUseContext::Store) => if self.found_assignment[local] { + trace!("local {:?} can't be propagated because of multiple assignments", local); self.can_const_prop[local] = false; } else { self.found_assignment[local] = true @@ -526,131 +750,171 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { NonMutatingUse(NonMutatingUseContext::Projection) | MutatingUse(MutatingUseContext::Projection) | NonUse(_) => {}, - _ => self.can_const_prop[local] = false, + _ => { + trace!("local {:?} can't be propagaged because it's used: {:?}", local, context); + self.can_const_prop[local] = false; + }, } } } -impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { +impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { fn visit_constant( &mut self, - constant: &Constant<'tcx>, + constant: &mut Constant<'tcx>, location: Location, ) { trace!("visit_constant: {:?}", constant); self.super_constant(constant, location); - let source_info = *self.mir.source_info(location); - self.eval_constant(constant, source_info); + self.eval_constant(constant); } fn visit_statement( &mut self, - block: BasicBlock, - statement: &Statement<'tcx>, + statement: &mut Statement<'tcx>, location: Location, ) { trace!("visit_statement: {:?}", statement); - if let StatementKind::Assign(ref place, ref rval) = statement.kind { - let place_ty: ty::Ty<'tcx> = place - .ty(&self.mir.local_decls, self.tcx) - .to_ty(self.tcx); + if let StatementKind::Assign(ref place, ref mut rval) = statement.kind { + let place_ty: Ty<'tcx> = place + .ty(&self.local_decls, self.tcx) + .ty; if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) { if let Place::Base(PlaceBase::Local(local)) = *place { trace!("checking whether {:?} can be stored to {:?}", value, local); if self.can_const_prop[local] { trace!("storing {:?} to {:?}", value, local); - assert!(self.places[local].is_none()); - self.places[local] = Some(value); + assert!(self.get_const(local).is_none()); + self.set_const(local, value); + + if self.should_const_prop() { + self.replace_with_const( + rval, + value, + statement.source_info, + ); + } } } } } } - self.super_statement(block, statement, location); + self.super_statement(statement, location); } - fn visit_terminator_kind( + fn visit_terminator( &mut self, - block: BasicBlock, - kind: &TerminatorKind<'tcx>, + terminator: &mut Terminator<'tcx>, location: Location, ) { - self.super_terminator_kind(block, kind, location); - let source_info = *self.mir.source_info(location); - if let TerminatorKind::Assert { expected, msg, cond, .. } = kind { - if let Some(value) = self.eval_operand(cond, source_info) { - trace!("assertion on {:?} should be {:?}", value, expected); - let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected)); - if expected != self.ecx.read_scalar(value.0).unwrap() { - // poison all places this operand references so that further code - // doesn't use the invalid value - match cond { - Operand::Move(ref place) | Operand::Copy(ref place) => { - let mut place = place; - while let Place::Projection(ref proj) = *place { - place = &proj.base; - } - if let Place::Base(PlaceBase::Local(local)) = *place { - self.places[local] = None; + self.super_terminator(terminator, location); + let source_info = terminator.source_info; + match &mut terminator.kind { + TerminatorKind::Assert { expected, msg, ref mut cond, .. } => { + if let Some(value) = self.eval_operand(&cond, source_info) { + trace!("assertion on {:?} should be {:?}", value, expected); + let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected)); + let value_const = self.ecx.read_scalar(value).unwrap(); + if expected != value_const { + // poison all places this operand references so that further code + // doesn't use the invalid value + match cond { + Operand::Move(ref place) | Operand::Copy(ref place) => { + let mut place = place; + while let Place::Projection(ref proj) = *place { + place = &proj.base; + } + if let Place::Base(PlaceBase::Local(local)) = *place { + self.remove_const(local); + } + }, + Operand::Constant(_) => {} + } + let span = terminator.source_info.span; + let hir_id = self + .tcx + .hir() + .as_local_hir_id(self.source.def_id()) + .expect("some part of a failing const eval must be local"); + use rustc::mir::interpret::InterpError::*; + let msg = match msg { + Overflow(_) | + OverflowNeg | + DivisionByZero | + RemainderByZero => msg.description().to_owned(), + BoundsCheck { ref len, ref index } => { + let len = self + .eval_operand(len, source_info) + .expect("len must be const"); + let len = match self.ecx.read_scalar(len) { + Ok(ScalarMaybeUndef::Scalar(Scalar::Raw { + data, .. + })) => data, + other => bug!("const len not primitive: {:?}", other), + }; + let index = self + .eval_operand(index, source_info) + .expect("index must be const"); + let index = match self.ecx.read_scalar(index) { + Ok(ScalarMaybeUndef::Scalar(Scalar::Raw { + data, .. + })) => data, + other => bug!("const index not primitive: {:?}", other), + }; + format!( + "index out of bounds: \ + the len is {} but the index is {}", + len, + index, + ) + }, + // Need proper const propagator for these + _ => return, + }; + self.tcx.lint_hir( + ::rustc::lint::builtin::CONST_ERR, + hir_id, + span, + &msg, + ); + } else { + if self.should_const_prop() { + if let ScalarMaybeUndef::Scalar(scalar) = value_const { + *cond = self.operand_from_scalar( + scalar, + self.tcx.types.bool, + source_info.span, + ); } - }, - Operand::Constant(_) => {} + } } - let span = self.mir[block] - .terminator - .as_ref() - .unwrap() - .source_info - .span; - let hir_id = self - .tcx - .hir() - .as_local_hir_id(self.source.def_id()) - .expect("some part of a failing const eval must be local"); - use rustc::mir::interpret::EvalErrorKind::*; - let msg = match msg { - Overflow(_) | - OverflowNeg | - DivisionByZero | - RemainderByZero => msg.description().to_owned(), - BoundsCheck { ref len, ref index } => { - let len = self - .eval_operand(len, source_info) - .expect("len must be const"); - let len = match self.ecx.read_scalar(len.0) { - Ok(ScalarMaybeUndef::Scalar(Scalar::Bits { - bits, .. - })) => bits, - other => bug!("const len not primitive: {:?}", other), - }; - let index = self - .eval_operand(index, source_info) - .expect("index must be const"); - let index = match self.ecx.read_scalar(index.0) { - Ok(ScalarMaybeUndef::Scalar(Scalar::Bits { - bits, .. - })) => bits, - other => bug!("const index not primitive: {:?}", other), - }; - format!( - "index out of bounds: \ - the len is {} but the index is {}", - len, - index, - ) - }, - // Need proper const propagator for these - _ => return, - }; - self.tcx.lint_hir( - ::rustc::lint::builtin::CONST_ERR, - hir_id, - span, - &msg, - ); } - } + }, + TerminatorKind::SwitchInt { ref mut discr, switch_ty, .. } => { + if self.should_const_prop() { + if let Some(value) = self.eval_operand(&discr, source_info) { + if let ScalarMaybeUndef::Scalar(scalar) = + self.ecx.read_scalar(value).unwrap() { + *discr = self.operand_from_scalar(scalar, switch_ty, source_info.span); + } + } + } + }, + //none of these have Operands to const-propagate + TerminatorKind::Goto { .. } | + TerminatorKind::Resume | + TerminatorKind::Abort | + TerminatorKind::Return | + TerminatorKind::Unreachable | + TerminatorKind::Drop { .. } | + TerminatorKind::DropAndReplace { .. } | + TerminatorKind::Yield { .. } | + TerminatorKind::GeneratorDrop | + TerminatorKind::FalseEdges { .. } | + TerminatorKind::FalseUnwind { .. } => { } + //FIXME(wesleywiser) Call does have Operands that could be const-propagated + TerminatorKind::Call { .. } => { } } } } diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 817a2f31c0736..c850b48e074ab 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -20,7 +20,7 @@ //! future. use rustc::mir::{ - Constant, Local, LocalKind, Location, Place, PlaceBase, Mir, Operand, Rvalue, StatementKind + Constant, Local, LocalKind, Location, Place, PlaceBase, Body, Operand, Rvalue, StatementKind }; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; @@ -30,26 +30,23 @@ use crate::util::def_use::DefUseAnalysis; pub struct CopyPropagation; impl MirPass for CopyPropagation { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _source: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { // We only run when the MIR optimization level is > 1. // This avoids a slow pass, and messing up debug info. if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { return; } - let mut def_use_analysis = DefUseAnalysis::new(mir); + let mut def_use_analysis = DefUseAnalysis::new(body); loop { - def_use_analysis.analyze(mir); + def_use_analysis.analyze(body); - if eliminate_self_assignments(mir, &def_use_analysis) { - def_use_analysis.analyze(mir); + if eliminate_self_assignments(body, &def_use_analysis) { + def_use_analysis.analyze(body); } let mut changed = false; - for dest_local in mir.local_decls.indices() { + for dest_local in body.local_decls.indices() { debug!("Considering destination local: {:?}", dest_local); let action; @@ -76,7 +73,7 @@ impl MirPass for CopyPropagation { } // Conservatively gives up if the dest is an argument, // because there may be uses of the original argument value. - if mir.local_kind(dest_local) == LocalKind::Arg { + if body.local_kind(dest_local) == LocalKind::Arg { debug!(" Can't copy-propagate local: dest {:?} (argument)", dest_local); continue; @@ -84,7 +81,7 @@ impl MirPass for CopyPropagation { let dest_place_def = dest_use_info.defs_not_including_drop().next().unwrap(); location = dest_place_def.location; - let basic_block = &mir[location.block]; + let basic_block = &body[location.block]; let statement_index = location.statement_index; let statement = match basic_block.statements.get(statement_index) { Some(statement) => statement, @@ -103,7 +100,7 @@ impl MirPass for CopyPropagation { let maybe_action = match *operand { Operand::Copy(ref src_place) | Operand::Move(ref src_place) => { - Action::local_copy(&mir, &def_use_analysis, src_place) + Action::local_copy(&body, &def_use_analysis, src_place) } Operand::Constant(ref src_constant) => { Action::constant(src_constant) @@ -122,7 +119,7 @@ impl MirPass for CopyPropagation { } } - changed = action.perform(mir, &def_use_analysis, dest_local, location) || changed; + changed = action.perform(body, &def_use_analysis, dest_local, location) || changed; // FIXME(pcwalton): Update the use-def chains to delete the instructions instead of // regenerating the chains. break @@ -134,18 +131,18 @@ impl MirPass for CopyPropagation { } } -fn eliminate_self_assignments<'tcx>( - mir: &mut Mir<'tcx>, - def_use_analysis: &DefUseAnalysis<'tcx>, +fn eliminate_self_assignments( + body: &mut Body<'_>, + def_use_analysis: &DefUseAnalysis, ) -> bool { let mut changed = false; - for dest_local in mir.local_decls.indices() { + for dest_local in body.local_decls.indices() { let dest_use_info = def_use_analysis.local_info(dest_local); for def in dest_use_info.defs_not_including_drop() { let location = def.location; - if let Some(stmt) = mir[location.block].statements.get(location.statement_index) { + if let Some(stmt) = body[location.block].statements.get(location.statement_index) { match stmt.kind { StatementKind::Assign( Place::Base(PlaceBase::Local(local)), @@ -163,7 +160,7 @@ fn eliminate_self_assignments<'tcx>( continue; } debug!("Deleting a self-assignment for {:?}", dest_local); - mir.make_statement_nop(location); + body.make_statement_nop(location); changed = true; } } @@ -177,7 +174,7 @@ enum Action<'tcx> { } impl<'tcx> Action<'tcx> { - fn local_copy(mir: &Mir<'tcx>, def_use_analysis: &DefUseAnalysis<'_>, src_place: &Place<'tcx>) + fn local_copy(body: &Body<'tcx>, def_use_analysis: &DefUseAnalysis, src_place: &Place<'tcx>) -> Option> { // The source must be a local. let src_local = if let Place::Base(PlaceBase::Local(local)) = *src_place { @@ -214,7 +211,7 @@ impl<'tcx> Action<'tcx> { // USE(SRC); let src_def_count = src_use_info.def_count_not_including_drop(); // allow function arguments to be propagated - let is_arg = mir.local_kind(src_local) == LocalKind::Arg; + let is_arg = body.local_kind(src_local) == LocalKind::Arg; if (is_arg && src_def_count != 0) || (!is_arg && src_def_count != 1) { debug!( " Can't copy-propagate local: {} defs of src{}", @@ -232,8 +229,8 @@ impl<'tcx> Action<'tcx> { } fn perform(self, - mir: &mut Mir<'tcx>, - def_use_analysis: &DefUseAnalysis<'tcx>, + body: &mut Body<'tcx>, + def_use_analysis: &DefUseAnalysis, dest_local: Local, location: Location) -> bool { @@ -249,21 +246,21 @@ impl<'tcx> Action<'tcx> { src_local); for place_use in &def_use_analysis.local_info(dest_local).defs_and_uses { if place_use.context.is_storage_marker() { - mir.make_statement_nop(place_use.location) + body.make_statement_nop(place_use.location) } } for place_use in &def_use_analysis.local_info(src_local).defs_and_uses { if place_use.context.is_storage_marker() { - mir.make_statement_nop(place_use.location) + body.make_statement_nop(place_use.location) } } // Replace all uses of the destination local with the source local. - def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_local); + def_use_analysis.replace_all_defs_and_uses_with(dest_local, body, src_local); // Finally, zap the now-useless assignment instruction. debug!(" Deleting assignment"); - mir.make_statement_nop(location); + body.make_statement_nop(location); true } @@ -277,7 +274,7 @@ impl<'tcx> Action<'tcx> { let dest_local_info = def_use_analysis.local_info(dest_local); for place_use in &dest_local_info.defs_and_uses { if place_use.context.is_storage_marker() { - mir.make_statement_nop(place_use.location) + body.make_statement_nop(place_use.location) } } @@ -285,7 +282,7 @@ impl<'tcx> Action<'tcx> { let mut visitor = ConstantPropagationVisitor::new(dest_local, src_constant); for dest_place_use in &dest_local_info.defs_and_uses { - visitor.visit_location(mir, dest_place_use.location) + visitor.visit_location(body, dest_place_use.location) } // Zap the assignment instruction if we eliminated all the uses. We won't have been @@ -296,7 +293,7 @@ impl<'tcx> Action<'tcx> { debug!(" {} of {} use(s) replaced; deleting assignment", visitor.uses_replaced, use_count); - mir.make_statement_nop(location); + body.make_statement_nop(location); true } else if visitor.uses_replaced == 0 { debug!(" No uses replaced; not deleting assignment"); diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index 9061dfff76fe8..1b42a0dffb894 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -1,16 +1,13 @@ -use rustc::ty::TyCtxt; use rustc::mir::*; -use rustc_data_structures::indexed_vec::Idx; +use rustc::ty::TyCtxt; use crate::transform::{MirPass, MirSource}; +use crate::util::expand_aggregate; pub struct Deaggregator; impl MirPass for Deaggregator { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _source: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { - let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut(); + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { + let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); let local_decls = &*local_decls; for bb in basic_blocks { bb.expand_statements(|stmt| { @@ -30,7 +27,7 @@ impl MirPass for Deaggregator { let stmt = stmt.replace_nop(); let source_info = stmt.source_info; - let (mut lhs, kind, operands) = match stmt.kind { + let (lhs, kind, operands) = match stmt.kind { StatementKind::Assign(lhs, box rvalue) => { match rvalue { Rvalue::Aggregate(kind, operands) => (lhs, kind, operands), @@ -40,45 +37,15 @@ impl MirPass for Deaggregator { _ => bug!() }; - let mut set_discriminant = None; - let active_field_index = match *kind { - AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { - if adt_def.is_enum() { - set_discriminant = Some(Statement { - kind: StatementKind::SetDiscriminant { - place: lhs.clone(), - variant_index, - }, - source_info, - }); - lhs = lhs.downcast(adt_def, variant_index); - } - active_field_index - } - _ => None - }; - - Some(operands.into_iter().enumerate().map(move |(i, op)| { - let lhs_field = if let AggregateKind::Array(_) = *kind { - // FIXME(eddyb) `offset` should be u64. - let offset = i as u32; - assert_eq!(offset as usize, i); - lhs.clone().elem(ProjectionElem::ConstantIndex { - offset, - // FIXME(eddyb) `min_length` doesn't appear to be used. - min_length: offset + 1, - from_end: false - }) - } else { + Some(expand_aggregate( + lhs, + operands.into_iter().map(|op| { let ty = op.ty(local_decls, tcx); - let field = Field::new(active_field_index.unwrap_or(i)); - lhs.clone().field(field, ty) - }; - Statement { - source_info, - kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)), - } - }).chain(set_discriminant)) + (op, ty) + }), + *kind, + source_info, + )) }); } } diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 81e48fe2dbe3b..243820ba7d027 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -5,7 +5,7 @@ use std::fmt; use std::fs::File; use std::io; -use rustc::mir::Mir; +use rustc::mir::Body; use rustc::session::config::{OutputFilenames, OutputType}; use rustc::ty::TyCtxt; use crate::transform::{MirPass, MirSource}; @@ -18,11 +18,7 @@ impl MirPass for Marker { Cow::Borrowed(self.0) } - fn run_pass<'a, 'tcx>(&self, - _tcx: TyCtxt<'a, 'tcx, 'tcx>, - _source: MirSource<'tcx>, - _mir: &mut Mir<'tcx>) - { + fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, _body: &mut Body<'tcx>) { } } @@ -37,29 +33,26 @@ impl fmt::Display for Disambiguator { } } - -pub fn on_mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_num: &dyn fmt::Display, - pass_name: &str, - source: MirSource<'tcx>, - mir: &Mir<'tcx>, - is_after: bool) { +pub fn on_mir_pass<'tcx>( + tcx: TyCtxt<'tcx>, + pass_num: &dyn fmt::Display, + pass_name: &str, + source: MirSource<'tcx>, + body: &Body<'tcx>, + is_after: bool, +) { if mir_util::dump_enabled(tcx, pass_name, source) { mir_util::dump_mir(tcx, Some(pass_num), pass_name, &Disambiguator { is_after }, source, - mir, + body, |_, _| Ok(()) ); } } -pub fn emit_mir<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - outputs: &OutputFilenames) - -> io::Result<()> -{ +pub fn emit_mir<'tcx>(tcx: TyCtxt<'tcx>, outputs: &OutputFilenames) -> io::Result<()> { let path = outputs.path(OutputType::Mir); let mut f = File::create(&path)?; mir_util::write_mir_pretty(tcx, None, &mut f)?; diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 74175d0149ff4..ad19b974d7d61 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -11,26 +11,22 @@ use crate::util::elaborate_drops::{DropFlagState, Unwind, elaborate_drop}; use crate::util::elaborate_drops::{DropElaborator, DropStyle, DropFlagMode}; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::VariantIdx; +use rustc::hir; use rustc::mir::*; use rustc::util::nodemap::FxHashMap; use rustc_data_structures::bit_set::BitSet; use std::fmt; -use syntax::ast; use syntax_pos::Span; pub struct ElaborateDrops; impl MirPass for ElaborateDrops { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource<'tcx>, - mir: &mut Mir<'tcx>) - { - debug!("elaborate_drops({:?} @ {:?})", src, mir.span); + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + debug!("elaborate_drops({:?} @ {:?})", src, body.span); - let id = tcx.hir().as_local_node_id(src.def_id()).unwrap(); + let def_id = src.def_id(); let param_env = tcx.param_env(src.def_id()).with_reveal_all(); - let move_data = match MoveData::gather_moves(mir, tcx) { + let move_data = match MoveData::gather_moves(body, tcx) { Ok(move_data) => move_data, Err((move_data, _move_errors)) => { // The only way we should be allowing any move_errors @@ -45,54 +41,53 @@ impl MirPass for ElaborateDrops { } }; let elaborate_patch = { - let mir = &*mir; + let body = &*body; let env = MoveDataParamEnv { move_data, param_env, }; - let dead_unwinds = find_dead_unwinds(tcx, mir, id, &env); + let dead_unwinds = find_dead_unwinds(tcx, body, def_id, &env); let flow_inits = - do_dataflow(tcx, mir, id, &[], &dead_unwinds, - MaybeInitializedPlaces::new(tcx, mir, &env), + do_dataflow(tcx, body, def_id, &[], &dead_unwinds, + MaybeInitializedPlaces::new(tcx, body, &env), |bd, p| DebugFormatted::new(&bd.move_data().move_paths[p])); let flow_uninits = - do_dataflow(tcx, mir, id, &[], &dead_unwinds, - MaybeUninitializedPlaces::new(tcx, mir, &env), + do_dataflow(tcx, body, def_id, &[], &dead_unwinds, + MaybeUninitializedPlaces::new(tcx, body, &env), |bd, p| DebugFormatted::new(&bd.move_data().move_paths[p])); ElaborateDropsCtxt { tcx, - mir, + body, env: &env, flow_inits, flow_uninits, drop_flags: Default::default(), - patch: MirPatch::new(mir), + patch: MirPatch::new(body), }.elaborate() }; - elaborate_patch.apply(mir); + elaborate_patch.apply(body); } } /// Returns the set of basic blocks whose unwind edges are known /// to not be reachable, because they are `drop` terminators /// that can't drop anything. -fn find_dead_unwinds<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &Mir<'tcx>, - id: ast::NodeId, - env: &MoveDataParamEnv<'tcx, 'tcx>) - -> BitSet -{ - debug!("find_dead_unwinds({:?})", mir.span); +fn find_dead_unwinds<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + def_id: hir::def_id::DefId, + env: &MoveDataParamEnv<'tcx>, +) -> BitSet { + debug!("find_dead_unwinds({:?})", body.span); // We only need to do this pass once, because unwind edges can only // reach cleanup blocks, which can't have unwind edges themselves. - let mut dead_unwinds = BitSet::new_empty(mir.basic_blocks().len()); + let mut dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); let flow_inits = - do_dataflow(tcx, mir, id, &[], &dead_unwinds, - MaybeInitializedPlaces::new(tcx, mir, &env), + do_dataflow(tcx, body, def_id, &[], &dead_unwinds, + MaybeInitializedPlaces::new(tcx, body, &env), |bd, p| DebugFormatted::new(&bd.move_data().move_paths[p])); - for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { + for (bb, bb_data) in body.basic_blocks().iter_enumerated() { let location = match bb_data.terminator().kind { TerminatorKind::Drop { ref location, unwind: Some(_), .. } | TerminatorKind::DropAndReplace { ref location, unwind: Some(_), .. } => location, @@ -100,14 +95,14 @@ fn find_dead_unwinds<'a, 'tcx>( }; let mut init_data = InitializationData { - live: flow_inits.sets().on_entry_set_for(bb.index()).to_owned(), + live: flow_inits.sets().entry_set_for(bb.index()).to_owned(), dead: BitSet::new_empty(env.move_data.move_paths.len()), }; debug!("find_dead_unwinds @ {:?}: {:?}; init_data={:?}", bb, bb_data, init_data.live); for stmt in 0..bb_data.statements.len() { let loc = Location { block: bb, statement_index: stmt }; - init_data.apply_location(tcx, mir, env, loc); + init_data.apply_location(tcx, body, env, loc); } let path = match env.move_data.rev_lookup.find(location) { @@ -121,7 +116,7 @@ fn find_dead_unwinds<'a, 'tcx>( debug!("find_dead_unwinds @ {:?}: path({:?})={:?}", bb, location, path); let mut maybe_live = false; - on_all_drop_children_bits(tcx, mir, &env, path, |child| { + on_all_drop_children_bits(tcx, body, &env, path, |child| { let (child_maybe_live, _) = init_data.state(child); maybe_live |= child_maybe_live; }); @@ -141,13 +136,14 @@ struct InitializationData { } impl InitializationData { - fn apply_location<'a,'tcx>(&mut self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &Mir<'tcx>, - env: &MoveDataParamEnv<'tcx, 'tcx>, - loc: Location) - { - drop_flag_effects_for_location(tcx, mir, env, loc, |path, df| { + fn apply_location<'tcx>( + &mut self, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + env: &MoveDataParamEnv<'tcx>, + loc: Location, + ) { + drop_flag_effects_for_location(tcx, body, env, loc, |path, df| { debug!("at location {:?}: setting {:?} to {:?}", loc, path, df); match df { @@ -168,7 +164,7 @@ impl InitializationData { } } -struct Elaborator<'a, 'b: 'a, 'tcx: 'b> { +struct Elaborator<'a, 'b, 'tcx> { init_data: &'a InitializationData, ctxt: &'a mut ElaborateDropsCtxt<'b, 'tcx>, } @@ -186,11 +182,11 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { &mut self.ctxt.patch } - fn mir(&self) -> &'a Mir<'tcx> { - self.ctxt.mir + fn body(&self) -> &'a Body<'tcx> { + self.ctxt.body } - fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.ctxt.tcx } @@ -206,7 +202,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { let mut some_dead = false; let mut children_count = 0; on_all_drop_children_bits( - self.tcx(), self.mir(), self.ctxt.env, path, |child| { + self.tcx(), self.body(), self.ctxt.env, path, |child| { let (live, dead) = self.init_data.state(child); debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead)); @@ -232,7 +228,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { } DropFlagMode::Deep => { on_all_children_bits( - self.tcx(), self.mir(), self.ctxt.move_data(), path, + self.tcx(), self.body(), self.ctxt.move_data(), path, |child| self.ctxt.set_drop_flag(loc, child, DropFlagState::Absent) ); } @@ -289,12 +285,12 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { } } -struct ElaborateDropsCtxt<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &'a Mir<'tcx>, - env: &'a MoveDataParamEnv<'tcx, 'tcx>, - flow_inits: DataflowResults<'tcx, MaybeInitializedPlaces<'a, 'tcx, 'tcx>>, - flow_uninits: DataflowResults<'tcx, MaybeUninitializedPlaces<'a, 'tcx, 'tcx>>, +struct ElaborateDropsCtxt<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + env: &'a MoveDataParamEnv<'tcx>, + flow_inits: DataflowResults<'tcx, MaybeInitializedPlaces<'a, 'tcx>>, + flow_uninits: DataflowResults<'tcx, MaybeUninitializedPlaces<'a, 'tcx>>, drop_flags: FxHashMap, patch: MirPatch<'tcx>, } @@ -308,13 +304,13 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn initialization_data_at(&self, loc: Location) -> InitializationData { let mut data = InitializationData { - live: self.flow_inits.sets().on_entry_set_for(loc.block.index()) + live: self.flow_inits.sets().entry_set_for(loc.block.index()) .to_owned(), - dead: self.flow_uninits.sets().on_entry_set_for(loc.block.index()) + dead: self.flow_uninits.sets().entry_set_for(loc.block.index()) .to_owned(), }; for stmt in 0..loc.statement_index { - data.apply_location(self.tcx, self.mir, self.env, + data.apply_location(self.tcx, self.body, self.env, Location { block: loc.block, statement_index: stmt }); } data @@ -323,14 +319,14 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) { let tcx = self.tcx; let patch = &mut self.patch; - debug!("create_drop_flag({:?})", self.mir.span); + debug!("create_drop_flag({:?})", self.body.span); self.drop_flags.entry(index).or_insert_with(|| { patch.new_internal(tcx.types.bool, span) }); } fn drop_flag(&mut self, index: MovePathIndex) -> Option> { - self.drop_flags.get(&index).map(|t| Place::Base(PlaceBase::Local(*t))) + self.drop_flags.get(&index).map(|t| Place::from(*t)) } /// create a patch that elaborates all drops in the input @@ -351,7 +347,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn collect_drop_flags(&mut self) { - for (bb, data) in self.mir.basic_blocks().iter_enumerated() { + for (bb, data) in self.body.basic_blocks().iter_enumerated() { let terminator = data.terminator(); let location = match terminator.kind { TerminatorKind::Drop { ref location, .. } | @@ -382,7 +378,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } }; - on_all_drop_children_bits(self.tcx, self.mir, self.env, path, |child| { + on_all_drop_children_bits(self.tcx, self.body, self.env, path, |child| { let (maybe_live, maybe_dead) = init_data.state(child); debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", child, location, path, (maybe_live, maybe_dead)); @@ -395,7 +391,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn elaborate_drops(&mut self) { - for (bb, data) in self.mir.basic_blocks().iter_enumerated() { + for (bb, data) in self.body.basic_blocks().iter_enumerated() { let loc = Location { block: bb, statement_index: data.statements.len() }; let terminator = data.terminator(); @@ -464,7 +460,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { unwind: Option) { let bb = loc.block; - let data = &self.mir[bb]; + let data = &self.body[bb]; let terminator = data.terminator(); assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported"); @@ -508,7 +504,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { target, Unwind::To(unwind), bb); - on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| { + on_all_children_bits(self.tcx, self.body, self.move_data(), path, |child| { self.set_drop_flag(Location { block: target, statement_index: 0 }, child, DropFlagState::Present); self.set_drop_flag(Location { block: unwind, statement_index: 0 }, @@ -533,31 +529,29 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { span, ty: self.tcx.types.bool, user_ty: None, - literal: self.tcx.mk_lazy_const(ty::LazyConst::Evaluated( - ty::Const::from_bool(self.tcx, val), - )), + literal: ty::Const::from_bool(self.tcx, val), }))) } fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) { if let Some(&flag) = self.drop_flags.get(&path) { - let span = self.patch.source_info_for_location(self.mir, loc).span; + let span = self.patch.source_info_for_location(self.body, loc).span; let val = self.constant_bool(span, val.value()); - self.patch.add_assign(loc, Place::Base(PlaceBase::Local(flag)), val); + self.patch.add_assign(loc, Place::from(flag), val); } } fn drop_flags_on_init(&mut self) { let loc = Location::START; - let span = self.patch.source_info_for_location(self.mir, loc).span; + let span = self.patch.source_info_for_location(self.body, loc).span; let false_ = self.constant_bool(span, false); for flag in self.drop_flags.values() { - self.patch.add_assign(loc, Place::Base(PlaceBase::Local(*flag)), false_.clone()); + self.patch.add_assign(loc, Place::from(*flag), false_.clone()); } } fn drop_flags_for_fn_rets(&mut self) { - for (bb, data) in self.mir.basic_blocks().iter_enumerated() { + for (bb, data) in self.body.basic_blocks().iter_enumerated() { if let TerminatorKind::Call { destination: Some((ref place, tgt)), cleanup: Some(_), .. } = data.terminator().kind { @@ -566,7 +560,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let loc = Location { block: tgt, statement_index: 0 }; let path = self.move_data().rev_lookup.find(place); on_lookup_result_bits( - self.tcx, self.mir, self.move_data(), path, + self.tcx, self.body, self.move_data(), path, |child| self.set_drop_flag(loc, child, DropFlagState::Present) ); } @@ -576,7 +570,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn drop_flags_for_args(&mut self) { let loc = Location::START; dataflow::drop_flag_effects_for_function_entry( - self.tcx, self.mir, self.env, |path, ds| { + self.tcx, self.body, self.env, |path, ds| { self.set_drop_flag(loc, path, ds); } ) @@ -589,7 +583,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { // drop flags by themselves, to avoid the drop flags being // clobbered before they are read. - for (bb, data) in self.mir.basic_blocks().iter_enumerated() { + for (bb, data) in self.body.basic_blocks().iter_enumerated() { debug!("drop_flags_for_locs({:?})", data); for i in 0..(data.statements.len()+1) { debug!("drop_flag_for_locs: stmt {}", i); @@ -621,7 +615,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } let loc = Location { block: bb, statement_index: i }; dataflow::drop_flag_effects_for_location( - self.tcx, self.mir, self.env, loc, |path, ds| { + self.tcx, self.body, self.env, loc, |path, ds| { if ds == DropFlagState::Absent || allow_initializations { self.set_drop_flag(loc, path, ds) } @@ -640,7 +634,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let loc = Location { block: bb, statement_index: data.statements.len() }; let path = self.move_data().rev_lookup.find(place); on_lookup_result_bits( - self.tcx, self.mir, self.move_data(), path, + self.tcx, self.body, self.move_data(), path, |child| self.set_drop_flag(loc, child, DropFlagState::Present) ); } diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 9494d4b1f6c39..5a29ea21a7a04 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -10,29 +10,29 @@ use rustc::mir::*; use rustc::mir::visit::{MutVisitor, TyContext}; use crate::transform::{MirPass, MirSource}; -struct EraseRegionsVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct EraseRegionsVisitor<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx> EraseRegionsVisitor<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { +impl EraseRegionsVisitor<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> Self { EraseRegionsVisitor { tcx, } } } -impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { +impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> { fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) { *ty = self.tcx.erase_regions(ty); self.super_ty(ty); } fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) { - *region = self.tcx.types.re_erased; + *region = self.tcx.lifetimes.re_erased; } - fn visit_const(&mut self, constant: &mut &'tcx ty::LazyConst<'tcx>, _: Location) { + fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) { *constant = self.tcx.erase_regions(constant); } @@ -41,20 +41,16 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { } fn visit_statement(&mut self, - block: BasicBlock, statement: &mut Statement<'tcx>, location: Location) { - self.super_statement(block, statement, location); + self.super_statement(statement, location); } } pub struct EraseRegions; impl MirPass for EraseRegions { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { - EraseRegionsVisitor::new(tcx).visit_mir(mir); + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { + EraseRegionsVisitor::new(tcx).visit_body(body); } } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index c455d38cebce8..1acebede2e41b 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -26,7 +26,7 @@ //! } //! //! This pass computes the meaning of the state field and the MIR locals which are live -//! across a suspension point. There are however two hardcoded generator states: +//! across a suspension point. There are however three hardcoded generator states: //! 0 - Generator have not been resumed yet //! 1 - Generator has returned / is completed //! 2 - Generator has been poisoned @@ -54,21 +54,23 @@ use rustc::hir::def_id::DefId; use rustc::mir::*; use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor}; use rustc::ty::{self, TyCtxt, AdtDef, Ty}; +use rustc::ty::GeneratorSubsts; use rustc::ty::layout::VariantIdx; use rustc::ty::subst::SubstsRef; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::Idx; -use rustc_data_structures::bit_set::BitSet; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::bit_set::{BitSet, BitMatrix}; use std::borrow::Cow; -use std::iter::once; +use std::iter; use std::mem; use crate::transform::{MirPass, MirSource}; use crate::transform::simplify; use crate::transform::no_landing_pads::no_landing_pads; +use crate::dataflow::{DataflowResults, DataflowResultsConsumer, FlowAtLocation}; use crate::dataflow::{do_dataflow, DebugFormatted, state_for_location}; -use crate::dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals}; +use crate::dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals, RequiresStorage}; use crate::util::dump_mir; -use crate::util::liveness::{self, IdentityMap}; +use crate::util::liveness; pub struct StateTransform; @@ -80,7 +82,7 @@ struct RenameLocalVisitor { impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor { fn visit_local(&mut self, local: &mut Local, - _: PlaceContext<'tcx>, + _: PlaceContext, _: Location) { if *local == self.from { *local = self.to; @@ -93,20 +95,20 @@ struct DerefArgVisitor; impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { fn visit_local(&mut self, local: &mut Local, - _: PlaceContext<'tcx>, + _: PlaceContext, _: Location) { assert_ne!(*local, self_arg()); } fn visit_place(&mut self, place: &mut Place<'tcx>, - context: PlaceContext<'tcx>, + context: PlaceContext, location: Location) { - if *place == Place::Base(PlaceBase::Local(self_arg())) { - *place = Place::Projection(Box::new(Projection { - base: place.clone(), + if place.base_local() == Some(self_arg()) { + replace_base(place, Place::Projection(Box::new(Projection { + base: Place::Base(PlaceBase::Local(self_arg())), elem: ProjectionElem::Deref, - })); + }))); } else { self.super_place(place, context, location); } @@ -120,52 +122,67 @@ struct PinArgVisitor<'tcx> { impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { fn visit_local(&mut self, local: &mut Local, - _: PlaceContext<'tcx>, + _: PlaceContext, _: Location) { assert_ne!(*local, self_arg()); } fn visit_place(&mut self, place: &mut Place<'tcx>, - context: PlaceContext<'tcx>, + context: PlaceContext, location: Location) { - if *place == Place::Base(PlaceBase::Local(self_arg())) { - *place = Place::Projection(Box::new(Projection { - base: place.clone(), + if place.base_local() == Some(self_arg()) { + replace_base(place, Place::Projection(Box::new(Projection { + base: Place::Base(PlaceBase::Local(self_arg())), elem: ProjectionElem::Field(Field::new(0), self.ref_gen_ty), - })); + }))); } else { self.super_place(place, context, location); } } } +fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) { + if let Place::Projection(proj) = place { + replace_base(&mut proj.base, new_base); + } else { + *place = new_base; + } +} + fn self_arg() -> Local { Local::new(1) } +/// Generator have not been resumed yet +const UNRESUMED: usize = GeneratorSubsts::UNRESUMED; +/// Generator has returned / is completed +const RETURNED: usize = GeneratorSubsts::RETURNED; +/// Generator has been poisoned +const POISONED: usize = GeneratorSubsts::POISONED; + struct SuspensionPoint { - state: u32, + state: usize, resume: BasicBlock, drop: Option, - storage_liveness: liveness::LiveVarSet, + storage_liveness: liveness::LiveVarSet, } -struct TransformVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct TransformVisitor<'tcx> { + tcx: TyCtxt<'tcx>, state_adt_ref: &'tcx AdtDef, state_substs: SubstsRef<'tcx>, - // The index of the generator state in the generator struct - state_field: usize, + // The type of the discriminant in the generator struct + discr_ty: Ty<'tcx>, // Mapping from Local to (type of local, generator struct index) // FIXME(eddyb) This should use `IndexVec>`. - remap: FxHashMap, usize)>, + remap: FxHashMap, VariantIdx, usize)>, // A map from a suspension point in a block to the locals which have live storage at that point // FIXME(eddyb) This should use `IndexVec>`. - storage_liveness: FxHashMap>, + storage_liveness: FxHashMap, // A list of suspension points, generated during the transform suspension_points: Vec, @@ -174,7 +191,7 @@ struct TransformVisitor<'a, 'tcx: 'a> { new_ret_local: Local, } -impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { +impl TransformVisitor<'tcx> { // Make a GeneratorState rvalue fn make_state(&self, idx: VariantIdx, val: Operand<'tcx>) -> Rvalue<'tcx> { let adt = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None, None); @@ -182,8 +199,9 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { } // Create a Place referencing a generator struct field - fn make_field(&self, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> { - let base = Place::Base(PlaceBase::Local(self_arg())); + fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> { + let self_place = Place::from(self_arg()); + let base = self_place.downcast_unnamed(variant_index); let field = Projection { base: base, elem: ProjectionElem::Field(Field::new(idx), ty), @@ -191,42 +209,46 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { Place::Projection(Box::new(field)) } - // Create a statement which changes the generator state - fn set_state(&self, state_disc: u32, source_info: SourceInfo) -> Statement<'tcx> { - let state = self.make_field(self.state_field, self.tcx.types.u32); - let val = Operand::Constant(box Constant { - span: source_info.span, - ty: self.tcx.types.u32, - user_ty: None, - literal: self.tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bits( - self.tcx, - state_disc.into(), - ty::ParamEnv::empty().and(self.tcx.types.u32) - ))), - }); + // Create a statement which changes the discriminant + fn set_discr(&self, state_disc: VariantIdx, source_info: SourceInfo) -> Statement<'tcx> { + let self_place = Place::from(self_arg()); Statement { source_info, - kind: StatementKind::Assign(state, box Rvalue::Use(val)), + kind: StatementKind::SetDiscriminant { place: self_place, variant_index: state_disc }, } } + + // Create a statement which reads the discriminant into a temporary + fn get_discr(&self, body: &mut Body<'tcx>) -> (Statement<'tcx>, Place<'tcx>) { + let temp_decl = LocalDecl::new_internal(self.tcx.types.isize, body.span); + let local_decls_len = body.local_decls.push(temp_decl); + let temp = Place::from(local_decls_len); + + let self_place = Place::from(self_arg()); + let assign = Statement { + source_info: source_info(body), + kind: StatementKind::Assign(temp.clone(), box Rvalue::Discriminant(self_place)), + }; + (assign, temp) + } } -impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { +impl MutVisitor<'tcx> for TransformVisitor<'tcx> { fn visit_local(&mut self, local: &mut Local, - _: PlaceContext<'tcx>, + _: PlaceContext, _: Location) { assert_eq!(self.remap.get(local), None); } fn visit_place(&mut self, place: &mut Place<'tcx>, - context: PlaceContext<'tcx>, + context: PlaceContext, location: Location) { - if let Place::Base(PlaceBase::Local(l)) = *place { + if let Some(l) = place.base_local() { // Replace an Local in the remap with a generator struct access - if let Some(&(ty, idx)) = self.remap.get(&l) { - *place = self.make_field(idx, ty); + if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) { + replace_base(place, self.make_field(variant_index, idx, ty)); } } else { self.super_place(place, context, location); @@ -249,7 +271,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { let ret_val = match data.terminator().kind { TerminatorKind::Return => Some((VariantIdx::new(1), None, - Operand::Move(Place::Base(PlaceBase::Local(self.new_ret_local))), + Operand::Move(Place::from(self.new_ret_local)), None)), TerminatorKind::Yield { ref value, resume, drop } => Some((VariantIdx::new(0), Some(resume), @@ -267,7 +289,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { box self.make_state(state_idx, v)), }); let state = if let Some(resume) = resume { // Yield - let state = 3 + self.suspension_points.len() as u32; + let state = 3 + self.suspension_points.len(); self.suspension_points.push(SuspensionPoint { state, @@ -276,11 +298,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { storage_liveness: self.storage_liveness.get(&block).unwrap().clone(), }); - state + VariantIdx::new(state) } else { // Return - 1 // state for returned + VariantIdx::new(RETURNED) // state for returned }; - data.statements.push(self.set_state(state, source_info)); + data.statements.push(self.set_discr(state, source_info)); data.terminator.as_mut().unwrap().kind = TerminatorKind::Return; } @@ -288,11 +310,12 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { } } -fn make_generator_state_argument_indirect<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - mir: &mut Mir<'tcx>) { - let gen_ty = mir.local_decls.raw[1].ty; +fn make_generator_state_argument_indirect<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + body: &mut Body<'tcx>, +) { + let gen_ty = body.local_decls.raw[1].ty; let region = ty::ReFree(ty::FreeRegion { scope: def_id, @@ -307,16 +330,14 @@ fn make_generator_state_argument_indirect<'a, 'tcx>( }); // Replace the by value generator argument - mir.local_decls.raw[1].ty = ref_gen_ty; + body.local_decls.raw[1].ty = ref_gen_ty; // Add a deref to accesses of the generator state - DerefArgVisitor.visit_mir(mir); + DerefArgVisitor.visit_body(body); } -fn make_generator_state_argument_pinned<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &mut Mir<'tcx>) { - let ref_gen_ty = mir.local_decls.raw[1].ty; +fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let ref_gen_ty = body.local_decls.raw[1].ty; let pin_did = tcx.lang_items().pin_type().unwrap(); let pin_adt_ref = tcx.adt_def(pin_did); @@ -324,17 +345,17 @@ fn make_generator_state_argument_pinned<'a, 'tcx>( let pin_ref_gen_ty = tcx.mk_adt(pin_adt_ref, substs); // Replace the by ref generator argument - mir.local_decls.raw[1].ty = pin_ref_gen_ty; + body.local_decls.raw[1].ty = pin_ref_gen_ty; // Add the Pin field access to accesses of the generator state - PinArgVisitor { ref_gen_ty }.visit_mir(mir); + PinArgVisitor { ref_gen_ty }.visit_body(body); } fn replace_result_variable<'tcx>( ret_ty: Ty<'tcx>, - mir: &mut Mir<'tcx>, + body: &mut Body<'tcx>, ) -> Local { - let source_info = source_info(mir); + let source_info = source_info(body); let new_ret = LocalDecl { mutability: Mutability::Mut, ty: ret_ty, @@ -346,23 +367,22 @@ fn replace_result_variable<'tcx>( is_block_tail: None, is_user_variable: None, }; - let new_ret_local = Local::new(mir.local_decls.len()); - mir.local_decls.push(new_ret); - mir.local_decls.swap(RETURN_PLACE, new_ret_local); + let new_ret_local = Local::new(body.local_decls.len()); + body.local_decls.push(new_ret); + body.local_decls.swap(RETURN_PLACE, new_ret_local); RenameLocalVisitor { from: RETURN_PLACE, to: new_ret_local, - }.visit_mir(mir); + }.visit_body(body); new_ret_local } -struct StorageIgnored(liveness::LiveVarSet); +struct StorageIgnored(liveness::LiveVarSet); impl<'tcx> Visitor<'tcx> for StorageIgnored { fn visit_statement(&mut self, - _block: BasicBlock, statement: &Statement<'tcx>, _location: Location) { match statement.kind { @@ -373,72 +393,91 @@ impl<'tcx> Visitor<'tcx> for StorageIgnored { } } +struct LivenessInfo { + /// Which locals are live across any suspension point. + /// + /// GeneratorSavedLocal is indexed in terms of the elements in this set; + /// i.e. GeneratorSavedLocal::new(1) corresponds to the second local + /// included in this set. + live_locals: liveness::LiveVarSet, + + /// The set of saved locals live at each suspension point. + live_locals_at_suspension_points: Vec>, + + /// For every saved local, the set of other saved locals that are + /// storage-live at the same time as this local. We cannot overlap locals in + /// the layout which have conflicting storage. + storage_conflicts: BitMatrix, + + /// For every suspending block, the locals which are storage-live across + /// that suspension point. + storage_liveness: FxHashMap, +} + fn locals_live_across_suspend_points( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &Mir<'tcx>, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, source: MirSource<'tcx>, movable: bool, -) -> ( - liveness::LiveVarSet, - FxHashMap>, -) { - let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len()); - let node_id = tcx.hir().as_local_node_id(source.def_id()).unwrap(); +) -> LivenessInfo { + let dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); + let def_id = source.def_id(); // Calculate when MIR locals have live storage. This gives us an upper bound of their // lifetimes. - let storage_live_analysis = MaybeStorageLive::new(mir); + let storage_live_analysis = MaybeStorageLive::new(body); let storage_live = - do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, storage_live_analysis, - |bd, p| DebugFormatted::new(&bd.mir().local_decls[p])); + do_dataflow(tcx, body, def_id, &[], &dead_unwinds, storage_live_analysis, + |bd, p| DebugFormatted::new(&bd.body().local_decls[p])); // Find the MIR locals which do not use StorageLive/StorageDead statements. // The storage of these locals are always live. - let mut ignored = StorageIgnored(BitSet::new_filled(mir.local_decls.len())); - ignored.visit_mir(mir); + let mut ignored = StorageIgnored(BitSet::new_filled(body.local_decls.len())); + ignored.visit_body(body); // Calculate the MIR locals which have been previously // borrowed (even if they are still active). - // This is only used for immovable generators. - let borrowed_locals = if !movable { - let analysis = HaveBeenBorrowedLocals::new(mir); - let result = - do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis, - |bd, p| DebugFormatted::new(&bd.mir().local_decls[p])); - Some((analysis, result)) - } else { - None - }; + let borrowed_locals_analysis = HaveBeenBorrowedLocals::new(body); + let borrowed_locals_result = + do_dataflow(tcx, body, def_id, &[], &dead_unwinds, borrowed_locals_analysis, + |bd, p| DebugFormatted::new(&bd.body().local_decls[p])); + + // Calculate the MIR locals that we actually need to keep storage around + // for. + let requires_storage_analysis = RequiresStorage::new(body, &borrowed_locals_result); + let requires_storage = + do_dataflow(tcx, body, def_id, &[], &dead_unwinds, requires_storage_analysis, + |bd, p| DebugFormatted::new(&bd.body().local_decls[p])); + let requires_storage_analysis = RequiresStorage::new(body, &borrowed_locals_result); // Calculate the liveness of MIR locals ignoring borrows. - let mut set = liveness::LiveVarSet::new_empty(mir.local_decls.len()); + let mut live_locals = liveness::LiveVarSet::new_empty(body.local_decls.len()); let mut liveness = liveness::liveness_of_locals( - mir, - &IdentityMap::new(mir), + body, ); liveness::dump_mir( tcx, "generator_liveness", source, - mir, - &IdentityMap::new(mir), + body, &liveness, ); let mut storage_liveness_map = FxHashMap::default(); + let mut live_locals_at_suspension_points = Vec::new(); - for (block, data) in mir.basic_blocks().iter_enumerated() { + for (block, data) in body.basic_blocks().iter_enumerated() { if let TerminatorKind::Yield { .. } = data.terminator().kind { let loc = Location { block: block, statement_index: data.statements.len(), }; - if let Some((ref analysis, ref result)) = borrowed_locals { + if !movable { let borrowed_locals = state_for_location(loc, - analysis, - result, - mir); + &borrowed_locals_analysis, + &borrowed_locals_result, + body); // The `liveness` variable contains the liveness of MIR locals ignoring borrows. // This is correct for movable generators since borrows cannot live across // suspension points. However for immovable generators we need to account for @@ -452,61 +491,229 @@ fn locals_live_across_suspend_points( liveness.outs[block].union(&borrowed_locals); } - let mut storage_liveness = state_for_location(loc, - &storage_live_analysis, - &storage_live, - mir); + let storage_liveness = state_for_location(loc, + &storage_live_analysis, + &storage_live, + body); // Store the storage liveness for later use so we can restore the state // after a suspension point storage_liveness_map.insert(block, storage_liveness.clone()); - // Mark locals without storage statements as always having live storage - storage_liveness.union(&ignored.0); + let mut storage_required = state_for_location(loc, + &requires_storage_analysis, + &requires_storage, + body); + + // Mark locals without storage statements as always requiring storage + storage_required.union(&ignored.0); // Locals live are live at this point only if they are used across // suspension points (the `liveness` variable) - // and their storage is live (the `storage_liveness` variable) - storage_liveness.intersect(&liveness.outs[block]); + // and their storage is required (the `storage_required` variable) + let mut live_locals_here = storage_required; + live_locals_here.intersect(&liveness.outs[block]); + + // The generator argument is ignored + live_locals_here.remove(self_arg()); - let live_locals = storage_liveness; + debug!("loc = {:?}, live_locals_here = {:?}", loc, live_locals_here); - // Add the locals life at this suspension point to the set of locals which live across + // Add the locals live at this suspension point to the set of locals which live across // any suspension points - set.union(&live_locals); + live_locals.union(&live_locals_here); + + live_locals_at_suspension_points.push(live_locals_here); + } + } + debug!("live_locals = {:?}", live_locals); + + // Renumber our liveness_map bitsets to include only the locals we are + // saving. + let live_locals_at_suspension_points = live_locals_at_suspension_points + .iter() + .map(|live_here| renumber_bitset(&live_here, &live_locals)) + .collect(); + + let storage_conflicts = compute_storage_conflicts( + body, + &live_locals, + &ignored, + requires_storage, + requires_storage_analysis); + + LivenessInfo { + live_locals, + live_locals_at_suspension_points, + storage_conflicts, + storage_liveness: storage_liveness_map, + } +} + +/// Renumbers the items present in `stored_locals` and applies the renumbering +/// to 'input`. +/// +/// For example, if `stored_locals = [1, 3, 5]`, this would be renumbered to +/// `[0, 1, 2]`. Thus, if `input = [3, 5]` we would return `[1, 2]`. +fn renumber_bitset(input: &BitSet, stored_locals: &liveness::LiveVarSet) +-> BitSet { + assert!(stored_locals.superset(&input), "{:?} not a superset of {:?}", stored_locals, input); + let mut out = BitSet::new_empty(stored_locals.count()); + for (idx, local) in stored_locals.iter().enumerate() { + let saved_local = GeneratorSavedLocal::from(idx); + if input.contains(local) { + out.insert(saved_local); } } + debug!("renumber_bitset({:?}, {:?}) => {:?}", input, stored_locals, out); + out +} - // The generator argument is ignored - set.remove(self_arg()); +/// For every saved local, looks for which locals are StorageLive at the same +/// time. Generates a bitset for every local of all the other locals that may be +/// StorageLive simultaneously with that local. This is used in the layout +/// computation; see `GeneratorLayout` for more. +fn compute_storage_conflicts( + body: &'mir Body<'tcx>, + stored_locals: &liveness::LiveVarSet, + ignored: &StorageIgnored, + requires_storage: DataflowResults<'tcx, RequiresStorage<'mir, 'tcx>>, + _requires_storage_analysis: RequiresStorage<'mir, 'tcx>, +) -> BitMatrix { + assert_eq!(body.local_decls.len(), ignored.0.domain_size()); + assert_eq!(body.local_decls.len(), stored_locals.domain_size()); + debug!("compute_storage_conflicts({:?})", body.span); + debug!("ignored = {:?}", ignored.0); + + // Storage ignored locals are not eligible for overlap, since their storage + // is always live. + let mut ineligible_locals = ignored.0.clone(); + ineligible_locals.intersect(&stored_locals); + + // Compute the storage conflicts for all eligible locals. + let mut visitor = StorageConflictVisitor { + body, + stored_locals: &stored_locals, + local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()), + }; + let mut state = FlowAtLocation::new(requires_storage); + visitor.analyze_results(&mut state); + let local_conflicts = visitor.local_conflicts; + + // Compress the matrix using only stored locals (Local -> GeneratorSavedLocal). + // + // NOTE: Today we store a full conflict bitset for every local. Technically + // this is twice as many bits as we need, since the relation is symmetric. + // However, in practice these bitsets are not usually large. The layout code + // also needs to keep track of how many conflicts each local has, so it's + // simpler to keep it this way for now. + let mut storage_conflicts = BitMatrix::new(stored_locals.count(), stored_locals.count()); + for (idx_a, local_a) in stored_locals.iter().enumerate() { + let saved_local_a = GeneratorSavedLocal::new(idx_a); + if ineligible_locals.contains(local_a) { + // Conflicts with everything. + storage_conflicts.insert_all_into_row(saved_local_a); + } else { + // Keep overlap information only for stored locals. + for (idx_b, local_b) in stored_locals.iter().enumerate() { + let saved_local_b = GeneratorSavedLocal::new(idx_b); + if local_conflicts.contains(local_a, local_b) { + storage_conflicts.insert(saved_local_a, saved_local_b); + } + } + } + } + storage_conflicts +} - (set, storage_liveness_map) +struct StorageConflictVisitor<'body, 'tcx, 's> { + body: &'body Body<'tcx>, + stored_locals: &'s liveness::LiveVarSet, + // FIXME(tmandry): Consider using sparse bitsets here once we have good + // benchmarks for generators. + local_conflicts: BitMatrix, } -fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: MirSource<'tcx>, - upvars: Vec>, - interior: Ty<'tcx>, - movable: bool, - mir: &mut Mir<'tcx>) - -> (FxHashMap, usize)>, - GeneratorLayout<'tcx>, - FxHashMap>) +impl<'body, 'tcx, 's> DataflowResultsConsumer<'body, 'tcx> + for StorageConflictVisitor<'body, 'tcx, 's> { + type FlowState = FlowAtLocation<'tcx, RequiresStorage<'body, 'tcx>>; + + fn body(&self) -> &'body Body<'tcx> { + self.body + } + + fn visit_block_entry(&mut self, + block: BasicBlock, + flow_state: &Self::FlowState) { + // statement_index is only used for logging, so this is fine. + self.apply_state(flow_state, Location { block, statement_index: 0 }); + } + + fn visit_statement_entry(&mut self, + loc: Location, + _stmt: &Statement<'tcx>, + flow_state: &Self::FlowState) { + self.apply_state(flow_state, loc); + } + + fn visit_terminator_entry(&mut self, + loc: Location, + _term: &Terminator<'tcx>, + flow_state: &Self::FlowState) { + self.apply_state(flow_state, loc); + } +} + +impl<'body, 'tcx, 's> StorageConflictVisitor<'body, 'tcx, 's> { + fn apply_state(&mut self, + flow_state: &FlowAtLocation<'tcx, RequiresStorage<'body, 'tcx>>, + loc: Location) { + // Ignore unreachable blocks. + match self.body.basic_blocks()[loc.block].terminator().kind { + TerminatorKind::Unreachable => return, + _ => (), + }; + + let mut eligible_storage_live = flow_state.as_dense().clone(); + eligible_storage_live.intersect(&self.stored_locals); + + for local in eligible_storage_live.iter() { + self.local_conflicts.union_row_with(&eligible_storage_live, local); + } + + if eligible_storage_live.count() > 1 { + trace!("at {:?}, eligible_storage_live={:?}", loc, eligible_storage_live); + } + } +} + +fn compute_layout<'tcx>( + tcx: TyCtxt<'tcx>, + source: MirSource<'tcx>, + upvars: &Vec>, + interior: Ty<'tcx>, + movable: bool, + body: &mut Body<'tcx>, +) -> ( + FxHashMap, VariantIdx, usize)>, + GeneratorLayout<'tcx>, + FxHashMap, +) { // Use a liveness analysis to compute locals which are live across a suspension point - let (live_locals, storage_liveness) = locals_live_across_suspend_points(tcx, - mir, - source, - movable); + let LivenessInfo { + live_locals, live_locals_at_suspension_points, storage_conflicts, storage_liveness + } = locals_live_across_suspend_points(tcx, body, source, movable); + // Erase regions from the types passed in from typeck so we can compare them with // MIR types - let allowed_upvars = tcx.erase_regions(&upvars); + let allowed_upvars = tcx.erase_regions(upvars); let allowed = match interior.sty { ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(&s), _ => bug!(), }; - for (local, decl) in mir.local_decls.iter_enumerated() { + for (local, decl) in body.local_decls.iter_enumerated() { // Ignore locals which are internal or not live if !live_locals.contains(local) || decl.internal { continue; @@ -515,7 +722,7 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Sanity check that typeck knows about the type of locals which are // live across a suspension point if !allowed.contains(&decl.ty) && !allowed_upvars.contains(&decl.ty) { - span_bug!(mir.span, + span_bug!(body.span, "Broken MIR: generator contains type {} in MIR, \ but typeck only knows about {}", decl.ty, @@ -523,47 +730,73 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - let upvar_len = mir.upvar_decls.len(); - let dummy_local = LocalDecl::new_internal(tcx.mk_unit(), mir.span); + let dummy_local = LocalDecl::new_internal(tcx.mk_unit(), body.span); + + // Gather live locals and their indices replacing values in body.local_decls + // with a dummy to avoid changing local indices. + let mut locals = IndexVec::::new(); + let mut tys = IndexVec::::new(); + let mut decls = IndexVec::::new(); + for (idx, local) in live_locals.iter().enumerate() { + let var = mem::replace(&mut body.local_decls[local], dummy_local.clone()); + locals.push(local); + tys.push(var.ty); + decls.push(var); + debug!("generator saved local {:?} => {:?}", GeneratorSavedLocal::from(idx), local); + } - // Gather live locals and their indices replacing values in mir.local_decls with a dummy - // to avoid changing local indices - let live_decls = live_locals.iter().map(|local| { - let var = mem::replace(&mut mir.local_decls[local], dummy_local.clone()); - (local, var) - }); + // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states. + const RESERVED_VARIANTS: usize = 3; + // Build the generator variant field list. // Create a map from local indices to generator struct indices. - // These are offset by (upvar_len + 1) because of fields which comes before locals. - // We also create a vector of the LocalDecls of these locals. - let (remap, vars) = live_decls.enumerate().map(|(idx, (local, var))| { - ((local, (var.ty, upvar_len + 1 + idx)), var) - }).unzip(); + let mut variant_fields: IndexVec> = + iter::repeat(IndexVec::new()).take(RESERVED_VARIANTS).collect(); + let mut remap = FxHashMap::default(); + for (suspension_point_idx, live_locals) in live_locals_at_suspension_points.iter().enumerate() { + let variant_index = VariantIdx::from(RESERVED_VARIANTS + suspension_point_idx); + let mut fields = IndexVec::new(); + for (idx, saved_local) in live_locals.iter().enumerate() { + fields.push(saved_local); + // Note that if a field is included in multiple variants, we will + // just use the first one here. That's fine; fields do not move + // around inside generators, so it doesn't matter which variant + // index we access them by. + remap.entry(locals[saved_local]).or_insert((tys[saved_local], variant_index, idx)); + } + variant_fields.push(fields); + } + debug!("generator variant_fields = {:?}", variant_fields); + debug!("generator storage_conflicts = {:#?}", storage_conflicts); let layout = GeneratorLayout { - fields: vars + field_tys: tys, + variant_fields, + storage_conflicts, + __local_debuginfo_codegen_only_do_not_use: decls, }; (remap, layout, storage_liveness) } -fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &mut Mir<'tcx>, - cases: Vec<(u32, BasicBlock)>, - transform: &TransformVisitor<'a, 'tcx>, - default: TerminatorKind<'tcx>) { - let default_block = insert_term_block(mir, default); - +fn insert_switch<'tcx>( + body: &mut Body<'tcx>, + cases: Vec<(usize, BasicBlock)>, + transform: &TransformVisitor<'tcx>, + default: TerminatorKind<'tcx>, +) { + let default_block = insert_term_block(body, default); + let (assign, discr) = transform.get_discr(body); let switch = TerminatorKind::SwitchInt { - discr: Operand::Copy(transform.make_field(transform.state_field, tcx.types.u32)), - switch_ty: tcx.types.u32, - values: Cow::from(cases.iter().map(|&(i, _)| i.into()).collect::>()), - targets: cases.iter().map(|&(_, d)| d).chain(once(default_block)).collect(), + discr: Operand::Move(discr), + switch_ty: transform.discr_ty, + values: Cow::from(cases.iter().map(|&(i, _)| i as u128).collect::>()), + targets: cases.iter().map(|&(_, d)| d).chain(iter::once(default_block)).collect(), }; - let source_info = source_info(mir); - mir.basic_blocks_mut().raw.insert(0, BasicBlockData { - statements: Vec::new(), + let source_info = source_info(body); + body.basic_blocks_mut().raw.insert(0, BasicBlockData { + statements: vec![assign], terminator: Some(Terminator { source_info, kind: switch, @@ -571,16 +804,14 @@ fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, is_cleanup: false, }); - let blocks = mir.basic_blocks_mut().iter_mut(); + let blocks = body.basic_blocks_mut().iter_mut(); for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) { *target = BasicBlock::new(target.index() + 1); } } -fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - mir: &mut Mir<'tcx>) { +fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut Body<'tcx>) { use crate::util::elaborate_drops::{elaborate_drop, Unwind}; use crate::util::patch::MirPatch; use crate::shim::DropShimElaborator; @@ -592,8 +823,15 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let param_env = tcx.param_env(def_id); let gen = self_arg(); - for block in mir.basic_blocks().indices() { - let (target, unwind, source_info) = match mir.basic_blocks()[block].terminator() { + let mut elaborator = DropShimElaborator { + body: body, + patch: MirPatch::new(body), + tcx, + param_env + }; + + for (block, block_data) in body.basic_blocks().iter_enumerated() { + let (target, unwind, source_info) = match block_data.terminator() { &Terminator { source_info, kind: TerminatorKind::Drop { @@ -604,55 +842,47 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } if local == gen => (target, unwind, source_info), _ => continue, }; - let unwind = if let Some(unwind) = unwind { - Unwind::To(unwind) - } else { + let unwind = if block_data.is_cleanup { Unwind::InCleanup + } else { + Unwind::To(unwind.unwrap_or_else(|| elaborator.patch.resume_block())) }; - let patch = { - let mut elaborator = DropShimElaborator { - mir: &mir, - patch: MirPatch::new(mir), - tcx, - param_env - }; - elaborate_drop( - &mut elaborator, - source_info, - &Place::Base(PlaceBase::Local(gen)), - (), - target, - unwind, - block - ); - elaborator.patch - }; - patch.apply(mir); + elaborate_drop( + &mut elaborator, + source_info, + &Place::from(gen), + (), + target, + unwind, + block, + ); } + elaborator.patch.apply(body); } -fn create_generator_drop_shim<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - transform: &TransformVisitor<'a, 'tcx>, - def_id: DefId, - source: MirSource<'tcx>, - gen_ty: Ty<'tcx>, - mir: &Mir<'tcx>, - drop_clean: BasicBlock) -> Mir<'tcx> { - let mut mir = mir.clone(); +fn create_generator_drop_shim<'tcx>( + tcx: TyCtxt<'tcx>, + transform: &TransformVisitor<'tcx>, + def_id: DefId, + source: MirSource<'tcx>, + gen_ty: Ty<'tcx>, + body: &Body<'tcx>, + drop_clean: BasicBlock, +) -> Body<'tcx> { + let mut body = body.clone(); - let source_info = source_info(&mir); + let source_info = source_info(&body); - let mut cases = create_cases(&mut mir, transform, |point| point.drop); + let mut cases = create_cases(&mut body, transform, |point| point.drop); - cases.insert(0, (0, drop_clean)); + cases.insert(0, (UNRESUMED, drop_clean)); - // The returned state (1) and the poisoned state (2) falls through to - // the default case which is just to return + // The returned state and the poisoned state fall through to the default + // case which is just to return - insert_switch(tcx, &mut mir, cases, &transform, TerminatorKind::Return); + insert_switch(&mut body, cases, &transform, TerminatorKind::Return); - for block in mir.basic_blocks_mut() { + for block in body.basic_blocks_mut() { let kind = &mut block.terminator_mut().kind; if let TerminatorKind::GeneratorDrop = *kind { *kind = TerminatorKind::Return; @@ -660,7 +890,7 @@ fn create_generator_drop_shim<'a, 'tcx>( } // Replace the return variable - mir.local_decls[RETURN_PLACE] = LocalDecl { + body.local_decls[RETURN_PLACE] = LocalDecl { mutability: Mutability::Mut, ty: tcx.mk_unit(), user_ty: UserTypeProjections::none(), @@ -672,10 +902,10 @@ fn create_generator_drop_shim<'a, 'tcx>( is_user_variable: None, }; - make_generator_state_argument_indirect(tcx, def_id, &mut mir); + make_generator_state_argument_indirect(tcx, def_id, &mut body); // Change the generator argument from &mut to *mut - mir.local_decls[self_arg()] = LocalDecl { + body.local_decls[self_arg()] = LocalDecl { mutability: Mutability::Mut, ty: tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, @@ -691,27 +921,27 @@ fn create_generator_drop_shim<'a, 'tcx>( }; if tcx.sess.opts.debugging_opts.mir_emit_retag { // Alias tracking must know we changed the type - mir.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement { + body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement { source_info, - kind: StatementKind::Retag(RetagKind::Raw, Place::Base(PlaceBase::Local(self_arg()))), + kind: StatementKind::Retag(RetagKind::Raw, Place::from(self_arg())), }) } - no_landing_pads(tcx, &mut mir); + no_landing_pads(tcx, &mut body); // Make sure we remove dead blocks to remove // unrelated code from the resume part of the function - simplify::remove_dead_blocks(&mut mir); + simplify::remove_dead_blocks(&mut body); - dump_mir(tcx, None, "generator_drop", &0, source, &mut mir, |_, _| Ok(()) ); + dump_mir(tcx, None, "generator_drop", &0, source, &mut body, |_, _| Ok(()) ); - mir + body } -fn insert_term_block<'tcx>(mir: &mut Mir<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock { - let term_block = BasicBlock::new(mir.basic_blocks().len()); - let source_info = source_info(mir); - mir.basic_blocks_mut().push(BasicBlockData { +fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock { + let term_block = BasicBlock::new(body.basic_blocks().len()); + let source_info = source_info(body); + body.basic_blocks_mut().push(BasicBlockData { statements: Vec::new(), terminator: Some(Terminator { source_info, @@ -722,18 +952,18 @@ fn insert_term_block<'tcx>(mir: &mut Mir<'tcx>, kind: TerminatorKind<'tcx>) -> B term_block } -fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &mut Mir<'tcx>, - message: AssertMessage<'tcx>) -> BasicBlock { - let assert_block = BasicBlock::new(mir.basic_blocks().len()); +fn insert_panic_block<'tcx>( + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + message: AssertMessage<'tcx>, +) -> BasicBlock { + let assert_block = BasicBlock::new(body.basic_blocks().len()); let term = TerminatorKind::Assert { cond: Operand::Constant(box Constant { - span: mir.span, + span: body.span, ty: tcx.types.bool, user_ty: None, - literal: tcx.mk_lazy_const(ty::LazyConst::Evaluated( - ty::Const::from_bool(tcx, false), - )), + literal: ty::Const::from_bool(tcx, false), }), expected: true, msg: message, @@ -741,8 +971,8 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cleanup: None, }; - let source_info = source_info(mir); - mir.basic_blocks_mut().push(BasicBlockData { + let source_info = source_info(body); + body.basic_blocks_mut().push(BasicBlockData { statements: Vec::new(), terminator: Some(Terminator { source_info, @@ -754,67 +984,69 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert_block } -fn create_generator_resume_function<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - transform: TransformVisitor<'a, 'tcx>, - def_id: DefId, - source: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { +fn create_generator_resume_function<'tcx>( + tcx: TyCtxt<'tcx>, + transform: TransformVisitor<'tcx>, + def_id: DefId, + source: MirSource<'tcx>, + body: &mut Body<'tcx>, +) { // Poison the generator when it unwinds - for block in mir.basic_blocks_mut() { + for block in body.basic_blocks_mut() { let source_info = block.terminator().source_info; if let &TerminatorKind::Resume = &block.terminator().kind { - block.statements.push(transform.set_state(1, source_info)); + block.statements.push( + transform.set_discr(VariantIdx::new(POISONED), source_info)); } } - let mut cases = create_cases(mir, &transform, |point| Some(point.resume)); + let mut cases = create_cases(body, &transform, |point| Some(point.resume)); - use rustc::mir::interpret::EvalErrorKind::{ + use rustc::mir::interpret::InterpError::{ GeneratorResumedAfterPanic, GeneratorResumedAfterReturn, }; - // Jump to the entry point on the 0 state - cases.insert(0, (0, BasicBlock::new(0))); - // Panic when resumed on the returned (1) state - cases.insert(1, (1, insert_panic_block(tcx, mir, GeneratorResumedAfterReturn))); - // Panic when resumed on the poisoned (2) state - cases.insert(2, (2, insert_panic_block(tcx, mir, GeneratorResumedAfterPanic))); + // Jump to the entry point on the unresumed + cases.insert(0, (UNRESUMED, BasicBlock::new(0))); + // Panic when resumed on the returned state + cases.insert(1, (RETURNED, insert_panic_block(tcx, body, GeneratorResumedAfterReturn))); + // Panic when resumed on the poisoned state + cases.insert(2, (POISONED, insert_panic_block(tcx, body, GeneratorResumedAfterPanic))); - insert_switch(tcx, mir, cases, &transform, TerminatorKind::Unreachable); + insert_switch(body, cases, &transform, TerminatorKind::Unreachable); - make_generator_state_argument_indirect(tcx, def_id, mir); - make_generator_state_argument_pinned(tcx, mir); + make_generator_state_argument_indirect(tcx, def_id, body); + make_generator_state_argument_pinned(tcx, body); - no_landing_pads(tcx, mir); + no_landing_pads(tcx, body); // Make sure we remove dead blocks to remove // unrelated code from the drop part of the function - simplify::remove_dead_blocks(mir); + simplify::remove_dead_blocks(body); - dump_mir(tcx, None, "generator_resume", &0, source, mir, |_, _| Ok(()) ); + dump_mir(tcx, None, "generator_resume", &0, source, body, |_, _| Ok(()) ); } -fn source_info<'a, 'tcx>(mir: &Mir<'tcx>) -> SourceInfo { +fn source_info<'tcx>(body: &Body<'tcx>) -> SourceInfo { SourceInfo { - span: mir.span, + span: body.span, scope: OUTERMOST_SOURCE_SCOPE, } } -fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock { - let return_block = insert_term_block(mir, TerminatorKind::Return); +fn insert_clean_drop<'tcx>(body: &mut Body<'tcx>) -> BasicBlock { + let return_block = insert_term_block(body, TerminatorKind::Return); // Create a block to destroy an unresumed generators. This can only destroy upvars. - let drop_clean = BasicBlock::new(mir.basic_blocks().len()); + let drop_clean = BasicBlock::new(body.basic_blocks().len()); let term = TerminatorKind::Drop { - location: Place::Base(PlaceBase::Local(self_arg())), + location: Place::from(self_arg()), target: return_block, unwind: None, }; - let source_info = source_info(mir); - mir.basic_blocks_mut().push(BasicBlockData { + let source_info = source_info(body); + body.basic_blocks_mut().push(BasicBlockData { statements: Vec::new(), terminator: Some(Terminator { source_info, @@ -826,20 +1058,24 @@ fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock { drop_clean } -fn create_cases<'a, 'tcx, F>(mir: &mut Mir<'tcx>, - transform: &TransformVisitor<'a, 'tcx>, - target: F) -> Vec<(u32, BasicBlock)> - where F: Fn(&SuspensionPoint) -> Option { - let source_info = source_info(mir); +fn create_cases<'tcx, F>( + body: &mut Body<'tcx>, + transform: &TransformVisitor<'tcx>, + target: F, +) -> Vec<(usize, BasicBlock)> +where + F: Fn(&SuspensionPoint) -> Option, +{ + let source_info = source_info(body); transform.suspension_points.iter().filter_map(|point| { // Find the target for this suspension point, if applicable target(point).map(|target| { - let block = BasicBlock::new(mir.basic_blocks().len()); + let block = BasicBlock::new(body.basic_blocks().len()); let mut statements = Vec::new(); // Create StorageLive instructions for locals with live storage - for i in 0..(mir.local_decls.len()) { + for i in 0..(body.local_decls.len()) { let l = Local::new(i); if point.storage_liveness.contains(l) && !transform.remap.contains_key(&l) { statements.push(Statement { @@ -850,7 +1086,7 @@ fn create_cases<'a, 'tcx, F>(mir: &mut Mir<'tcx>, } // Then jump to the real target - mir.basic_blocks_mut().push(BasicBlockData { + body.basic_blocks_mut().push(BasicBlockData { statements, terminator: Some(Terminator { source_info, @@ -867,29 +1103,27 @@ fn create_cases<'a, 'tcx, F>(mir: &mut Mir<'tcx>, } impl MirPass for StateTransform { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { - let yield_ty = if let Some(yield_ty) = mir.yield_ty { + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + let yield_ty = if let Some(yield_ty) = body.yield_ty { yield_ty } else { // This only applies to generators return }; - assert!(mir.generator_drop.is_none()); + assert!(body.generator_drop.is_none()); let def_id = source.def_id(); // The first argument is the generator type passed by value - let gen_ty = mir.local_decls.raw[1].ty; + let gen_ty = body.local_decls.raw[1].ty; // Get the interior types and substs which typeck computed - let (upvars, interior, movable) = match gen_ty.sty { + let (upvars, interior, discr_ty, movable) = match gen_ty.sty { ty::Generator(_, substs, movability) => { (substs.upvar_tys(def_id, tcx).collect(), substs.witness(def_id, tcx), + substs.discr_ty(tcx), movability == hir::GeneratorMovability::Movable) } _ => bug!(), @@ -900,13 +1134,13 @@ impl MirPass for StateTransform { let state_adt_ref = tcx.adt_def(state_did); let state_substs = tcx.intern_substs(&[ yield_ty.into(), - mir.return_ty().into(), + body.return_ty().into(), ]); let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local // RETURN_PLACE then is a fresh unused local with type ret_ty. - let new_ret_local = replace_result_variable(ret_ty, mir); + let new_ret_local = replace_result_variable(ret_ty, body); // Extract locals which are live across suspension point into `layout` // `remap` gives a mapping from local indices onto generator struct indices @@ -914,12 +1148,10 @@ impl MirPass for StateTransform { let (remap, layout, storage_liveness) = compute_layout( tcx, source, - upvars, + &upvars, interior, movable, - mir); - - let state_field = mir.upvar_decls.len(); + body); // Run the transformation which converts Places from Local to generator struct // accesses for locals in `remap`. @@ -933,29 +1165,29 @@ impl MirPass for StateTransform { storage_liveness, suspension_points: Vec::new(), new_ret_local, - state_field, + discr_ty, }; - transform.visit_mir(mir); + transform.visit_body(body); // Update our MIR struct to reflect the changed we've made - mir.yield_ty = None; - mir.arg_count = 1; - mir.spread_arg = None; - mir.generator_layout = Some(layout); + body.yield_ty = None; + body.arg_count = 1; + body.spread_arg = None; + body.generator_layout = Some(layout); // Insert `drop(generator_struct)` which is used to drop upvars for generators in - // the unresumed (0) state. + // the unresumed state. // This is expanded to a drop ladder in `elaborate_generator_drops`. - let drop_clean = insert_clean_drop(mir); + let drop_clean = insert_clean_drop(body); - dump_mir(tcx, None, "generator_pre-elab", &0, source, mir, |_, _| Ok(()) ); + dump_mir(tcx, None, "generator_pre-elab", &0, source, body, |_, _| Ok(()) ); // Expand `drop(generator_struct)` to a drop ladder which destroys upvars. // If any upvars are moved out of, drop elaboration will handle upvar destruction. // However we need to also elaborate the code generated by `insert_clean_drop`. - elaborate_generator_drops(tcx, def_id, mir); + elaborate_generator_drops(tcx, def_id, body); - dump_mir(tcx, None, "generator_post-transform", &0, source, mir, |_, _| Ok(()) ); + dump_mir(tcx, None, "generator_post-transform", &0, source, body, |_, _| Ok(()) ); // Create a copy of our MIR and use it to create the drop shim for the generator let drop_shim = create_generator_drop_shim(tcx, @@ -963,12 +1195,12 @@ impl MirPass for StateTransform { def_id, source, gen_ty, - &mir, + &body, drop_clean); - mir.generator_drop = Some(box drop_shim); + body.generator_drop = Some(box drop_shim); // Create the Generator::resume function - create_generator_resume_function(tcx, transform, def_id, source, mir); + create_generator_resume_function(tcx, transform, def_id, source, body); } } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 4cdef015b53ff..dc73e58d15c3d 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -38,23 +38,20 @@ struct CallSite<'tcx> { } impl MirPass for Inline { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { - Inliner { tcx, source }.run_pass(mir); + Inliner { tcx, source }.run_pass(body); } } } -struct Inliner<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct Inliner<'tcx> { + tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, } -impl<'a, 'tcx> Inliner<'a, 'tcx> { - fn run_pass(&self, caller_mir: &mut Mir<'tcx>) { +impl Inliner<'tcx> { + fn run_pass(&self, caller_body: &mut Body<'tcx>) { // Keep a queue of callsites to try inlining on. We take // advantage of the fact that queries detect cycles here to // allow us to try and fetch the fully optimized MIR of a @@ -72,12 +69,14 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let param_env = self.tcx.param_env(self.source.def_id()); // Only do inlining into fn bodies. - let id = self.tcx.hir().as_local_node_id(self.source.def_id()).unwrap(); - if self.tcx.hir().body_owner_kind(id).is_fn_or_closure() && self.source.promoted.is_none() { - for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated() { + let id = self.tcx.hir().as_local_hir_id(self.source.def_id()).unwrap(); + if self.tcx.hir().body_owner_kind(id).is_fn_or_closure() + && self.source.promoted.is_none() + { + for (bb, bb_data) in caller_body.basic_blocks().iter_enumerated() { if let Some(callsite) = self.get_valid_function_call(bb, bb_data, - caller_mir, + caller_body, param_env) { callsites.push_back(callsite); } @@ -101,7 +100,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let self_node_id = self.tcx.hir().as_local_node_id(self.source.def_id()).unwrap(); let callee_node_id = self.tcx.hir().as_local_node_id(callsite.callee); - let callee_mir = if let Some(callee_node_id) = callee_node_id { + let callee_body = if let Some(callee_node_id) = callee_node_id { // Avoid a cycle here by only using `optimized_mir` only if we have // a lower node id than the callee. This ensures that the callee will // not inline us. This trick only works without incremental compilation. @@ -118,29 +117,29 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { self.tcx.optimized_mir(callsite.callee) }; - let callee_mir = if self.consider_optimizing(callsite, callee_mir) { + let callee_body = if self.consider_optimizing(callsite, callee_body) { self.tcx.subst_and_normalize_erasing_regions( &callsite.substs, param_env, - callee_mir, + callee_body, ) } else { continue; }; - let start = caller_mir.basic_blocks().len(); - debug!("attempting to inline callsite {:?} - mir={:?}", callsite, callee_mir); - if !self.inline_call(callsite, caller_mir, callee_mir) { + let start = caller_body.basic_blocks().len(); + debug!("attempting to inline callsite {:?} - body={:?}", callsite, callee_body); + if !self.inline_call(callsite, caller_body, callee_body) { debug!("attempting to inline callsite {:?} - failure", callsite); continue; } debug!("attempting to inline callsite {:?} - success", callsite); // Add callsites from inlined function - for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated().skip(start) { + for (bb, bb_data) in caller_body.basic_blocks().iter_enumerated().skip(start) { if let Some(new_callsite) = self.get_valid_function_call(bb, bb_data, - caller_mir, + caller_body, param_env) { // Don't inline the same function multiple times. if callsite.callee != new_callsite.callee { @@ -161,15 +160,15 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // Simplify if we inlined anything. if changed { debug!("Running simplify cfg on {:?}", self.source); - CfgSimplifier::new(caller_mir).simplify(); - remove_dead_blocks(caller_mir); + CfgSimplifier::new(caller_body).simplify(); + remove_dead_blocks(caller_body); } } fn get_valid_function_call(&self, bb: BasicBlock, bb_data: &BasicBlockData<'tcx>, - caller_mir: &Mir<'tcx>, + caller_body: &Body<'tcx>, param_env: ParamEnv<'tcx>, ) -> Option> { // Don't inline calls that are in cleanup blocks. @@ -178,7 +177,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // Only consider direct calls to functions let terminator = bb_data.terminator(); if let TerminatorKind::Call { func: ref op, .. } = terminator.kind { - if let ty::FnDef(callee_def_id, substs) = op.ty(caller_mir, self.tcx).sty { + if let ty::FnDef(callee_def_id, substs) = op.ty(caller_body, self.tcx).sty { let instance = Instance::resolve(self.tcx, param_env, callee_def_id, @@ -202,33 +201,33 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { fn consider_optimizing(&self, callsite: CallSite<'tcx>, - callee_mir: &Mir<'tcx>) + callee_body: &Body<'tcx>) -> bool { debug!("consider_optimizing({:?})", callsite); - self.should_inline(callsite, callee_mir) + self.should_inline(callsite, callee_body) && self.tcx.consider_optimizing(|| format!("Inline {:?} into {:?}", - callee_mir.span, + callee_body.span, callsite)) } fn should_inline(&self, callsite: CallSite<'tcx>, - callee_mir: &Mir<'tcx>) + callee_body: &Body<'tcx>) -> bool { debug!("should_inline({:?})", callsite); let tcx = self.tcx; - // Don't inline closures that have captures + // Don't inline closures that have capture debuginfo // FIXME: Handle closures better - if callee_mir.upvar_decls.len() > 0 { - debug!(" upvar decls present - not inlining"); + if callee_body.__upvar_debuginfo_codegen_only_do_not_use.len() > 0 { + debug!(" upvar debuginfo present - not inlining"); return false; } // Cannot inline generators which haven't been transformed yet - if callee_mir.yield_ty.is_some() { + if callee_body.yield_ty.is_some() { debug!(" yield ty present - not inlining"); return false; } @@ -259,7 +258,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // inlining. This is to ensure that the final crate doesn't have MIR that // reference unexported symbols if callsite.callee.is_local() { - if callsite.substs.types().count() == 0 && !hinted { + if callsite.substs.non_erasable_generics().count() == 0 && !hinted { debug!(" callee is an exported function - not inlining"); return false; } @@ -279,7 +278,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // Give a bonus functions with a small number of blocks, // We normally have two or three blocks for even // very small functions. - if callee_mir.basic_blocks().len() <= 3 { + if callee_body.basic_blocks().len() <= 3 { threshold += threshold / 4; } debug!(" final inline threshold = {}", threshold); @@ -294,10 +293,10 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // Traverse the MIR manually so we can account for the effects of // inlining on the CFG. let mut work_list = vec![START_BLOCK]; - let mut visited = BitSet::new_empty(callee_mir.basic_blocks().len()); + let mut visited = BitSet::new_empty(callee_body.basic_blocks().len()); while let Some(bb) = work_list.pop() { if !visited.insert(bb.index()) { continue; } - let blk = &callee_mir.basic_blocks()[bb]; + let blk = &callee_body.basic_blocks()[bb]; for stmt in &blk.statements { // Don't count StorageLive/StorageDead in the inlining cost. @@ -317,8 +316,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { work_list.push(target); // If the location doesn't actually need dropping, treat it like // a regular goto. - let ty = location.ty(callee_mir, tcx).subst(tcx, callsite.substs); - let ty = ty.to_ty(tcx); + let ty = location.ty(callee_body, tcx).subst(tcx, callsite.substs).ty; if ty.needs_drop(tcx, param_env) { cost += CALL_PENALTY; if let Some(unwind) = unwind { @@ -365,8 +363,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let ptr_size = tcx.data_layout.pointer_size.bytes(); - for v in callee_mir.vars_and_temps_iter() { - let v = &callee_mir.local_decls[v]; + for v in callee_body.vars_and_temps_iter() { + let v = &callee_body.local_decls[v]; let ty = v.ty.subst(tcx, callsite.substs); // Cost of the var is the size in machine-words, if we know // it. @@ -393,44 +391,44 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { fn inline_call(&self, callsite: CallSite<'tcx>, - caller_mir: &mut Mir<'tcx>, - mut callee_mir: Mir<'tcx>) -> bool { - let terminator = caller_mir[callsite.bb].terminator.take().unwrap(); + caller_body: &mut Body<'tcx>, + mut callee_body: Body<'tcx>) -> bool { + let terminator = caller_body[callsite.bb].terminator.take().unwrap(); match terminator.kind { // FIXME: Handle inlining of diverging calls TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => { debug!("Inlined {:?} into {:?}", callsite.callee, self.source); - let mut local_map = IndexVec::with_capacity(callee_mir.local_decls.len()); - let mut scope_map = IndexVec::with_capacity(callee_mir.source_scopes.len()); - let mut promoted_map = IndexVec::with_capacity(callee_mir.promoted.len()); + let mut local_map = IndexVec::with_capacity(callee_body.local_decls.len()); + let mut scope_map = IndexVec::with_capacity(callee_body.source_scopes.len()); + let mut promoted_map = IndexVec::with_capacity(callee_body.promoted.len()); - for mut scope in callee_mir.source_scopes.iter().cloned() { + for mut scope in callee_body.source_scopes.iter().cloned() { if scope.parent_scope.is_none() { scope.parent_scope = Some(callsite.location.scope); - scope.span = callee_mir.span; + scope.span = callee_body.span; } scope.span = callsite.location.span; - let idx = caller_mir.source_scopes.push(scope); + let idx = caller_body.source_scopes.push(scope); scope_map.push(idx); } - for loc in callee_mir.vars_and_temps_iter() { - let mut local = callee_mir.local_decls[loc].clone(); + for loc in callee_body.vars_and_temps_iter() { + let mut local = callee_body.local_decls[loc].clone(); local.source_info.scope = scope_map[local.source_info.scope]; local.source_info.span = callsite.location.span; local.visibility_scope = scope_map[local.visibility_scope]; - let idx = caller_mir.local_decls.push(local); + let idx = caller_body.local_decls.push(local); local_map.push(idx); } promoted_map.extend( - callee_mir.promoted.iter().cloned().map(|p| caller_mir.promoted.push(p)) + callee_body.promoted.iter().cloned().map(|p| caller_body.promoted.push(p)) ); // If the call is something like `a[*i] = f(i)`, where @@ -439,40 +437,43 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // writes to `i`. To prevent this we need to create a temporary // borrow of the place and pass the destination as `*temp` instead. fn dest_needs_borrow(place: &Place<'_>) -> bool { - match *place { - Place::Projection(ref p) => { - match p.elem { + place.iterate(|place_base, place_projection| { + for proj in place_projection { + match proj.elem { ProjectionElem::Deref | - ProjectionElem::Index(_) => true, - _ => dest_needs_borrow(&p.base) + ProjectionElem::Index(_) => return true, + _ => {} } } - // Static variables need a borrow because the callee - // might modify the same static. - Place::Base(PlaceBase::Static(_)) => true, - _ => false - } + + match place_base { + // Static variables need a borrow because the callee + // might modify the same static. + PlaceBase::Static(_) => true, + _ => false + } + }) } let dest = if dest_needs_borrow(&destination.0) { debug!("Creating temp for return destination"); let dest = Rvalue::Ref( - self.tcx.types.re_erased, + self.tcx.lifetimes.re_erased, BorrowKind::Mut { allow_two_phase_borrow: false }, destination.0); - let ty = dest.ty(caller_mir, self.tcx); + let ty = dest.ty(caller_body, self.tcx); let temp = LocalDecl::new_temp(ty, callsite.location.span); - let tmp = caller_mir.local_decls.push(temp); - let tmp = Place::Base(PlaceBase::Local(tmp)); + let tmp = caller_body.local_decls.push(temp); + let tmp = Place::from(tmp); let stmt = Statement { source_info: callsite.location, kind: StatementKind::Assign(tmp.clone(), box dest) }; - caller_mir[callsite.bb] + caller_body[callsite.bb] .statements.push(stmt); tmp.deref() } else { @@ -482,9 +483,9 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let return_block = destination.1; // Copy the arguments if needed. - let args: Vec<_> = self.make_call_args(args, &callsite, caller_mir); + let args: Vec<_> = self.make_call_args(args, &callsite, caller_body); - let bb_len = caller_mir.basic_blocks().len(); + let bb_len = caller_body.basic_blocks().len(); let mut integrator = Integrator { block_idx: bb_len, args: &args, @@ -499,9 +500,9 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { }; - for (bb, mut block) in callee_mir.basic_blocks_mut().drain_enumerated(..) { + for (bb, mut block) in callee_body.basic_blocks_mut().drain_enumerated(..) { integrator.visit_basic_block_data(bb, &mut block); - caller_mir.basic_blocks_mut().push(block); + caller_body.basic_blocks_mut().push(block); } let terminator = Terminator { @@ -509,12 +510,12 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { kind: TerminatorKind::Goto { target: BasicBlock::new(bb_len) } }; - caller_mir[callsite.bb].terminator = Some(terminator); + caller_body[callsite.bb].terminator = Some(terminator); true } kind => { - caller_mir[callsite.bb].terminator = Some(Terminator { + caller_body[callsite.bb].terminator = Some(Terminator { source_info: terminator.source_info, kind, }); @@ -527,7 +528,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { &self, args: Vec>, callsite: &CallSite<'tcx>, - caller_mir: &mut Mir<'tcx>, + caller_body: &mut Body<'tcx>, ) -> Vec { let tcx = self.tcx; @@ -556,12 +557,12 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`. if tcx.is_closure(callsite.callee) { let mut args = args.into_iter(); - let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_mir); - let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_mir); + let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); + let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); assert!(args.next().is_none()); - let tuple = Place::Base(PlaceBase::Local(tuple)); - let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_mir, tcx).to_ty(tcx).sty { + let tuple = Place::from(tuple); + let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.sty { s } else { bug!("Closure arguments are not passed as a tuple"); @@ -574,16 +575,19 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let tuple_tmp_args = tuple_tys.iter().enumerate().map(|(i, ty)| { // This is e.g., `tuple_tmp.0` in our example above. - let tuple_field = Operand::Move(tuple.clone().field(Field::new(i), ty)); + let tuple_field = Operand::Move(tuple.clone().field( + Field::new(i), + ty.expect_ty(), + )); // Spill to a local to make e.g., `tmp0`. - self.create_temp_if_necessary(tuple_field, callsite, caller_mir) + self.create_temp_if_necessary(tuple_field, callsite, caller_body) }); closure_ref_arg.chain(tuple_tmp_args).collect() } else { args.into_iter() - .map(|a| self.create_temp_if_necessary(a, callsite, caller_mir)) + .map(|a| self.create_temp_if_necessary(a, callsite, caller_body)) .collect() } } @@ -594,13 +598,13 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { &self, arg: Operand<'tcx>, callsite: &CallSite<'tcx>, - caller_mir: &mut Mir<'tcx>, + caller_body: &mut Body<'tcx>, ) -> Local { // FIXME: Analysis of the usage of the arguments to avoid // unnecessary temporaries. if let Operand::Move(Place::Base(PlaceBase::Local(local))) = arg { - if caller_mir.local_kind(local) == LocalKind::Temp { + if caller_body.local_kind(local) == LocalKind::Temp { // Reuse the operand if it's a temporary already return local; } @@ -610,23 +614,25 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // Otherwise, create a temporary for the arg let arg = Rvalue::Use(arg); - let ty = arg.ty(caller_mir, self.tcx); + let ty = arg.ty(caller_body, self.tcx); let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span); - let arg_tmp = caller_mir.local_decls.push(arg_tmp); + let arg_tmp = caller_body.local_decls.push(arg_tmp); let stmt = Statement { source_info: callsite.location, - kind: StatementKind::Assign(Place::Base(PlaceBase::Local(arg_tmp)), box arg), + kind: StatementKind::Assign(Place::from(arg_tmp), box arg), }; - caller_mir[callsite.bb].statements.push(stmt); + caller_body[callsite.bb].statements.push(stmt); arg_tmp } } -fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>) -> Option { +fn type_size_of<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> Option { tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes()) } @@ -636,8 +642,8 @@ fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, * Integrates blocks from the callee function into the calling function. * Updates block indices, references to locals and other control flow * stuff. - */ -struct Integrator<'a, 'tcx: 'a> { +*/ +struct Integrator<'a, 'tcx> { block_idx: usize, args: &'a [Local], local_map: IndexVec, @@ -661,7 +667,7 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> { impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { fn visit_local(&mut self, local: &mut Local, - _ctxt: PlaceContext<'tcx>, + _ctxt: PlaceContext, _location: Location) { if *local == RETURN_PLACE { match self.destination { @@ -682,7 +688,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { fn visit_place(&mut self, place: &mut Place<'tcx>, - _ctxt: PlaceContext<'tcx>, + _ctxt: PlaceContext, _location: Location) { match place { @@ -690,12 +696,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { // Return pointer; update the place itself *place = self.destination.clone(); }, - Place::Base(PlaceBase::Promoted(ref mut promoted)) => { - if let Some(p) = self.promoted_map.get(promoted.0).cloned() { - promoted.0 = p; + Place::Base( + PlaceBase::Static(box Static { kind: StaticKind::Promoted(promoted), .. }) + ) => { + if let Some(p) = self.promoted_map.get(*promoted).cloned() { + *promoted = p; } }, - _ => self.super_place(place, _ctxt, _location), + _ => self.super_place(place, _ctxt, _location) } } @@ -720,9 +728,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { } } - fn visit_terminator_kind(&mut self, block: BasicBlock, + fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, loc: Location) { - self.super_terminator_kind(block, kind, loc); + self.super_terminator_kind(kind, loc); match *kind { TerminatorKind::GeneratorDrop | @@ -778,11 +786,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { } TerminatorKind::Abort => { } TerminatorKind::Unreachable => { } - TerminatorKind::FalseEdges { ref mut real_target, ref mut imaginary_targets } => { + TerminatorKind::FalseEdges { ref mut real_target, ref mut imaginary_target } => { *real_target = self.update_target(*real_target); - for target in imaginary_targets { - *target = self.update_target(*target); - } + *imaginary_target = self.update_target(*imaginary_target); } TerminatorKind::FalseUnwind { real_target: _ , unwind: _ } => // see the ordering of passes in the optimized_mir query. diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index e0e64fd1f9b54..c338e1ebe936f 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -1,8 +1,9 @@ //! Performs various peephole optimizations. -use rustc::mir::{Constant, Location, Place, PlaceBase, Mir, Operand, ProjectionElem, Rvalue, Local}; +use rustc::mir::{Constant, Location, Place, PlaceBase, Body, Operand, ProjectionElem, Rvalue, + Local}; use rustc::mir::visit::{MutVisitor, Visitor}; -use rustc::ty::{TyCtxt, TyKind}; +use rustc::ty::{self, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::Idx; use std::mem; @@ -11,10 +12,7 @@ use crate::transform::{MirPass, MirSource}; pub struct InstCombine; impl MirPass for InstCombine { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { // We only run when optimizing MIR (at any level). if tcx.sess.opts.debugging_opts.mir_opt_level == 0 { return @@ -24,13 +22,13 @@ impl MirPass for InstCombine { // read-only so that we can do global analyses on the MIR in the process (e.g. // `Place::ty()`). let optimizations = { - let mut optimization_finder = OptimizationFinder::new(mir, tcx); - optimization_finder.visit_mir(mir); + let mut optimization_finder = OptimizationFinder::new(body, tcx); + optimization_finder.visit_body(body); optimization_finder.optimizations }; // Then carry out those optimizations. - MutVisitor::visit_mir(&mut InstCombineVisitor { optimizations }, mir); + MutVisitor::visit_body(&mut InstCombineVisitor { optimizations }, body); } } @@ -62,36 +60,36 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { } /// Finds optimization opportunities on the MIR. -struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { - mir: &'b Mir<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct OptimizationFinder<'b, 'tcx> { + body: &'b Body<'tcx>, + tcx: TyCtxt<'tcx>, optimizations: OptimizationList<'tcx>, } -impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { - fn new(mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> OptimizationFinder<'b, 'a, 'tcx> { +impl OptimizationFinder<'b, 'tcx> { + fn new(body: &'b Body<'tcx>, tcx: TyCtxt<'tcx>) -> OptimizationFinder<'b, 'tcx> { OptimizationFinder { - mir, + body, tcx, optimizations: OptimizationList::default(), } } } -impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { +impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Ref(_, _, Place::Projection(ref projection)) = *rvalue { if let ProjectionElem::Deref = projection.elem { - if projection.base.ty(self.mir, self.tcx).to_ty(self.tcx).is_region_ptr() { + if projection.base.ty(self.body, self.tcx).ty.is_region_ptr() { self.optimizations.and_stars.insert(location); } } } if let Rvalue::Len(ref place) = *rvalue { - let place_ty = place.ty(&self.mir.local_decls, self.tcx).to_ty(self.tcx); - if let TyKind::Array(_, len) = place_ty.sty { - let span = self.mir.source_info(location).span; + let place_ty = place.ty(&self.body.local_decls, self.tcx).ty; + if let ty::Array(_, len) = place_ty.sty { + let span = self.body.source_info(location).span; let ty = self.tcx.types.usize; let constant = Constant { span, ty, literal: len, user_ty: None }; self.optimizations.arrays_lengths.insert(location, constant); diff --git a/src/librustc_mir/transform/lower_128bit.rs b/src/librustc_mir/transform/lower_128bit.rs index ad108587247fb..f09a77d486c7e 100644 --- a/src/librustc_mir/transform/lower_128bit.rs +++ b/src/librustc_mir/transform/lower_128bit.rs @@ -3,33 +3,30 @@ use rustc::hir::def_id::DefId; use rustc::middle::lang_items::LangItem; use rustc::mir::*; -use rustc::ty::{List, Ty, TyCtxt, TyKind}; +use rustc::ty::{self, List, Ty, TyCtxt}; use rustc_data_structures::indexed_vec::{Idx}; use crate::transform::{MirPass, MirSource}; pub struct Lower128Bit; impl MirPass for Lower128Bit { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _src: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { let debugging_override = tcx.sess.opts.debugging_opts.lower_128bit_ops; let target_default = tcx.sess.host.options.i128_lowering; if !debugging_override.unwrap_or(target_default) { return } - self.lower_128bit_ops(tcx, mir); - } + self.lower_128bit_ops(tcx, body); +} } impl Lower128Bit { - fn lower_128bit_ops<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir<'tcx>) { + fn lower_128bit_ops<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let mut new_blocks = Vec::new(); - let cur_len = mir.basic_blocks().len(); + let cur_len = body.basic_blocks().len(); - let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut(); + let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); for block in basic_blocks.iter_mut() { for i in (0..block.statements.len()).rev() { let (lang_item, rhs_kind) = @@ -86,13 +83,13 @@ impl Lower128Bit { block.statements.push(Statement { source_info: source_info, kind: StatementKind::Assign( - Place::Base(PlaceBase::Local(local)), + Place::from(local), box Rvalue::Cast( CastKind::Misc, rhs, rhs_override_ty.unwrap())), }); - rhs = Operand::Move(Place::Base(PlaceBase::Local(local))); + rhs = Operand::Move(Place::from(local)); } let call_did = check_lang_item_type( @@ -120,31 +117,36 @@ impl Lower128Bit { } } -fn check_lang_item_type<'a, 'tcx, D>( +fn check_lang_item_type<'tcx, D>( lang_item: LangItem, place: &Place<'tcx>, lhs: &Operand<'tcx>, rhs: &Operand<'tcx>, local_decls: &D, - tcx: TyCtxt<'a, 'tcx, 'tcx>) --> DefId - where D: HasLocalDecls<'tcx> + tcx: TyCtxt<'tcx>, +) -> DefId +where + D: HasLocalDecls<'tcx>, { let did = tcx.require_lang_item(lang_item); let poly_sig = tcx.fn_sig(did); let sig = poly_sig.no_bound_vars().unwrap(); let lhs_ty = lhs.ty(local_decls, tcx); let rhs_ty = rhs.ty(local_decls, tcx); - let place_ty = place.ty(local_decls, tcx).to_ty(tcx); + let place_ty = place.ty(local_decls, tcx).ty; let expected = [lhs_ty, rhs_ty, place_ty]; assert_eq!(sig.inputs_and_output[..], expected, - "lang item {}", tcx.def_symbol_name(did)); + "lang item `{}`", tcx.def_path_str(did)); did } -fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Option<(LangItem, RhsKind)> - where D: HasLocalDecls<'tcx> +fn lower_to<'tcx, D>( + statement: &Statement<'tcx>, + local_decls: &D, + tcx: TyCtxt<'tcx>, +) -> Option<(LangItem, RhsKind)> +where + D: HasLocalDecls<'tcx>, { match statement.kind { StatementKind::Assign(_, box Rvalue::BinaryOp(bin_op, ref lhs, _)) => { @@ -172,7 +174,7 @@ enum RhsKind { } impl RhsKind { - fn ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option> { + fn ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option> { match *self { RhsKind::Unchanged => None, RhsKind::ForceU128 => Some(tcx.types.u128), @@ -183,8 +185,8 @@ impl RhsKind { fn sign_of_128bit(ty: Ty<'_>) -> Option { match ty.sty { - TyKind::Int(syntax::ast::IntTy::I128) => Some(true), - TyKind::Uint(syntax::ast::UintTy::U128) => Some(false), + ty::Int(syntax::ast::IntTy::I128) => Some(true), + ty::Uint(syntax::ast::UintTy::U128) => Some(false), _ => None, } } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index c1bb31a49a4b5..81d91dcd0a95f 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -1,14 +1,12 @@ -use crate::borrow_check::nll::type_check; -use crate::build; +use crate::{build, shim}; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc::mir::{Mir, MirPhase, Promoted}; +use rustc::mir::{Body, MirPhase, Promoted}; use rustc::ty::{TyCtxt, InstanceDef}; use rustc::ty::query::Providers; use rustc::ty::steal::Steal; use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::util::nodemap::DefIdSet; -use rustc_data_structures::sync::Lrc; use std::borrow::Cow; use syntax::ast; use syntax_pos::Span; @@ -52,14 +50,13 @@ pub(crate) fn provide(providers: &mut Providers<'_>) { }; } -fn is_mir_available<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { +fn is_mir_available<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { tcx.mir_keys(def_id.krate).contains(&def_id) } /// Finds the full set of `DefId`s within the current crate that have /// MIR associated with them. -fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum) - -> Lrc { +fn mir_keys<'tcx>(tcx: TyCtxt<'tcx>, krate: CrateNum) -> &'tcx DefIdSet { assert_eq!(krate, LOCAL_CRATE); let mut set = DefIdSet::default(); @@ -69,8 +66,8 @@ fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum) // Additionally, tuple struct/variant constructors have MIR, but // they don't have a BodyId, so we need to build them separately. - struct GatherCtors<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, + struct GatherCtors<'a, 'tcx> { + tcx: TyCtxt<'tcx>, set: &'a mut DefIdSet, } impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> { @@ -80,8 +77,8 @@ fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum) _: &'tcx hir::Generics, _: hir::HirId, _: Span) { - if let hir::VariantData::Tuple(_, node_id, _) = *v { - self.set.insert(self.tcx.hir().local_def_id(node_id)); + if let hir::VariantData::Tuple(_, hir_id) = *v { + self.set.insert(self.tcx.hir().local_def_id_from_hir_id(hir_id)); } intravisit::walk_struct_def(self, v) } @@ -94,15 +91,15 @@ fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum) set: &mut set, }.as_deep_visitor()); - Lrc::new(set) + tcx.arena.alloc(set) } -fn mir_built<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal> { +fn mir_built<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Steal> { let mir = build::mir_build(tcx, def_id); tcx.alloc_steal_mir(mir) } -/// Where a specific Mir comes from. +/// Where a specific `mir::Body` comes from. #[derive(Debug, Copy, Clone)] pub struct MirSource<'tcx> { pub instance: InstanceDef<'tcx>, @@ -144,23 +141,20 @@ pub trait MirPass { default_name::() } - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: MirSource<'tcx>, - mir: &mut Mir<'tcx>); + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>); } pub fn run_passes( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &mut Mir<'tcx>, + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, instance: InstanceDef<'tcx>, mir_phase: MirPhase, passes: &[&dyn MirPass], ) { let phase_index = mir_phase.phase_index(); - let run_passes = |mir: &mut Mir<'tcx>, promoted| { - if mir.phase >= mir_phase { + let run_passes = |body: &mut Body<'tcx>, promoted| { + if body.phase >= mir_phase { return; } @@ -170,13 +164,13 @@ pub fn run_passes( }; let mut index = 0; let mut run_pass = |pass: &dyn MirPass| { - let run_hooks = |mir: &_, index, is_after| { + let run_hooks = |body: &_, index, is_after| { dump_mir::on_mir_pass(tcx, &format_args!("{:03}-{:03}", phase_index, index), - &pass.name(), source, mir, is_after); + &pass.name(), source, body, is_after); }; - run_hooks(mir, index, false); - pass.run_pass(tcx, source, mir); - run_hooks(mir, index, true); + run_hooks(body, index, false); + pass.run_pass(tcx, source, body); + run_hooks(body, index, true); index += 1; }; @@ -185,52 +179,59 @@ pub fn run_passes( run_pass(*pass); } - mir.phase = mir_phase; + body.phase = mir_phase; }; - run_passes(mir, None); + run_passes(body, None); - for (index, promoted_mir) in mir.promoted.iter_enumerated_mut() { - run_passes(promoted_mir, Some(index)); + for (index, promoted_body) in body.promoted.iter_enumerated_mut() { + run_passes(promoted_body, Some(index)); //Let's make sure we don't miss any nested instances - assert!(promoted_mir.promoted.is_empty()) + assert!(promoted_body.promoted.is_empty()) } } -fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal> { +fn mir_const<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Steal> { // Unsafety check uses the raw mir, so make sure it is run let _ = tcx.unsafety_check_result(def_id); - let mut mir = tcx.mir_built(def_id).steal(); - run_passes(tcx, &mut mir, InstanceDef::Item(def_id), MirPhase::Const, &[ + let mut body = tcx.mir_built(def_id).steal(); + run_passes(tcx, &mut body, InstanceDef::Item(def_id), MirPhase::Const, &[ // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), - &type_check::TypeckMir, &rustc_peek::SanityCheck, &uniform_array_move_out::UniformArrayMoveOut, ]); - tcx.alloc_steal_mir(mir) + tcx.alloc_steal_mir(body) } -fn mir_validated<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal> { - let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); - if let hir::BodyOwnerKind::Const = tcx.hir().body_owner_kind(node_id) { +fn mir_validated(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Steal> { + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + if let hir::BodyOwnerKind::Const = tcx.hir().body_owner_kind(hir_id) { // Ensure that we compute the `mir_const_qualif` for constants at // this point, before we steal the mir-const result. let _ = tcx.mir_const_qualif(def_id); } - let mut mir = tcx.mir_const(def_id).steal(); - run_passes(tcx, &mut mir, InstanceDef::Item(def_id), MirPhase::Validated, &[ + let mut body = tcx.mir_const(def_id).steal(); + run_passes(tcx, &mut body, InstanceDef::Item(def_id), MirPhase::Validated, &[ // What we need to run borrowck etc. &qualify_consts::QualifyAndPromoteConstants, &simplify::SimplifyCfg::new("qualify-consts"), ]); - tcx.alloc_steal_mir(mir) + tcx.alloc_steal_mir(body) } -fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Mir<'tcx> { +fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Body<'tcx> { + if tcx.is_constructor(def_id) { + // There's no reason to run all of the MIR passes on constructors when + // we can just output the MIR we want directly. This also saves const + // qualification and borrow checking the trouble of special casing + // constructors. + return shim::build_adt_ctor(tcx, def_id); + } + // (Mir-)Borrowck uses `mir_validated`, so we have to force it to // execute before we can steal. tcx.ensure().mir_borrowck(def_id); @@ -239,8 +240,8 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx tcx.ensure().borrowck(def_id); } - let mut mir = tcx.mir_validated(def_id).steal(); - run_passes(tcx, &mut mir, InstanceDef::Item(def_id), MirPhase::Optimized, &[ + let mut body = tcx.mir_validated(def_id).steal(); + run_passes(tcx, &mut body, InstanceDef::Item(def_id), MirPhase::Optimized, &[ // Remove all things only needed by analysis &no_landing_pads::NoLandingPads, &simplify_branches::SimplifyBranches::new("initial"), @@ -285,6 +286,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx &simplify_branches::SimplifyBranches::new("after-const-prop"), &deaggregator::Deaggregator, ©_prop::CopyPropagation, + &simplify_branches::SimplifyBranches::new("after-copy-prop"), &remove_noop_landing_pads::RemoveNoopLandingPads, &simplify::SimplifyCfg::new("final"), &simplify::SimplifyLocals, @@ -292,5 +294,5 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx &add_call_guards::CriticalCallEdges, &dump_mir::Marker("PreCodegen"), ]); - tcx.alloc_mir(mir) + tcx.arena.alloc(body) } diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 089d9b9b54454..841db80fc7dbb 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -9,28 +9,24 @@ use crate::transform::{MirPass, MirSource}; pub struct NoLandingPads; impl MirPass for NoLandingPads { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { - no_landing_pads(tcx, mir) + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { + no_landing_pads(tcx, body) } } -pub fn no_landing_pads<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir<'tcx>) { +pub fn no_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { if tcx.sess.no_landing_pads() { - NoLandingPads.visit_mir(mir); + NoLandingPads.visit_body(body); } } impl<'tcx> MutVisitor<'tcx> for NoLandingPads { - fn visit_terminator(&mut self, - bb: BasicBlock, - terminator: &mut Terminator<'tcx>, + fn visit_terminator_kind(&mut self, + kind: &mut TerminatorKind<'tcx>, location: Location) { - if let Some(unwind) = terminator.kind.unwind_mut() { + if let Some(unwind) = kind.unwind_mut() { unwind.take(); } - self.super_terminator(bb, terminator, location); + self.super_terminator_kind(kind, location); } } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 831d8b46a65c3..b1804fb0ab331 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -44,8 +44,8 @@ pub enum TempState { impl TempState { pub fn is_promotable(&self) -> bool { debug!("is_promotable: self={:?}", self); - if let TempState::Defined { uses, .. } = *self { - uses > 0 + if let TempState::Defined { .. } = *self { + true } else { false } @@ -71,18 +71,23 @@ pub enum Candidate { struct TempCollector<'tcx> { temps: IndexVec, span: Span, - mir: &'tcx Mir<'tcx>, + body: &'tcx Body<'tcx>, } impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> { fn visit_local(&mut self, &index: &Local, - context: PlaceContext<'tcx>, + context: PlaceContext, location: Location) { debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location); - // We're only interested in temporaries - if self.mir.local_kind(index) != LocalKind::Temp { - return; + // We're only interested in temporaries and the return place + match self.body.local_kind(index) { + | LocalKind::Temp + | LocalKind::ReturnPointer + => {}, + | LocalKind::Arg + | LocalKind::Var + => return, } // Ignore drops, if the temp gets promoted, @@ -101,7 +106,6 @@ impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> { if *temp == TempState::Undefined { match context { PlaceContext::MutatingUse(MutatingUseContext::Store) | - PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) | PlaceContext::MutatingUse(MutatingUseContext::Call) => { *temp = TempState::Defined { location, @@ -130,12 +134,12 @@ impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> { } } -pub fn collect_temps(mir: &Mir<'_>, +pub fn collect_temps(body: &Body<'_>, rpo: &mut ReversePostorder<'_, '_>) -> IndexVec { let mut collector = TempCollector { - temps: IndexVec::from_elem(TempState::Undefined, &mir.local_decls), - span: mir.span, - mir, + temps: IndexVec::from_elem(TempState::Undefined, &body.local_decls), + span: body.span, + body, }; for (bb, data) in rpo { collector.visit_basic_block_data(bb, data); @@ -143,15 +147,15 @@ pub fn collect_temps(mir: &Mir<'_>, collector.temps } -struct Promoter<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: &'a mut Mir<'tcx>, - promoted: Mir<'tcx>, +struct Promoter<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + source: &'a mut Body<'tcx>, + promoted: Body<'tcx>, temps: &'a mut IndexVec, /// If true, all nested temps are also kept in the /// source MIR, not moved to the promoted MIR. - keep_original: bool + keep_original: bool, } impl<'a, 'tcx> Promoter<'a, 'tcx> { @@ -178,7 +182,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { span, scope: OUTERMOST_SOURCE_SCOPE }, - kind: StatementKind::Assign(Place::Base(PlaceBase::Local(dest)), box rvalue) + kind: StatementKind::Assign(Place::from(dest), box rvalue) }); } @@ -269,7 +273,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { args, cleanup: None, destination: Some( - (Place::Base(PlaceBase::Local(new_temp)), new_target) + (Place::from(new_temp), new_target) ), from_hir_call, }, @@ -292,9 +296,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let promoted_id = Promoted::new(self.source.promoted.len()); let mut promoted_place = |ty, span| { promoted.span = span; - promoted.local_decls[RETURN_PLACE] = - LocalDecl::new_return_place(ty, span); - Place::Base(PlaceBase::Promoted(box (promoted_id, ty))) + promoted.local_decls[RETURN_PLACE] = LocalDecl::new_return_place(ty, span); + Place::Base( + PlaceBase::Static(box Static{ kind: StaticKind::Promoted(promoted_id), ty }) + ) }; let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); match candidate { @@ -309,7 +314,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { place = &mut proj.base; }; - let ty = place.ty(local_decls, self.tcx).to_ty(self.tcx); + let ty = place.ty(local_decls, self.tcx).ty; let span = statement.source_info.span; Operand::Move(mem::replace(place, promoted_place(ty, span))) @@ -356,7 +361,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { fn visit_local(&mut self, local: &mut Local, - _: PlaceContext<'tcx>, + _: PlaceContext, _: Location) { if self.source.local_kind(*local) == LocalKind::Temp { *local = self.promote_temp(*local); @@ -364,17 +369,19 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { } } -pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mut temps: IndexVec, - candidates: Vec) { +pub fn promote_candidates<'tcx>( + body: &mut Body<'tcx>, + tcx: TyCtxt<'tcx>, + mut temps: IndexVec, + candidates: Vec, +) { // Visit candidates in reverse, in case they're nested. debug!("promote_candidates({:?})", candidates); for candidate in candidates.into_iter().rev() { match candidate { Candidate::Ref(Location { block, statement_index }) => { - match mir[block].statements[statement_index].kind { + match body[block].statements[statement_index].kind { StatementKind::Assign(Place::Base(PlaceBase::Local(local)), _) => { if temps[local] == TempState::PromotedOut { // Already promoted. @@ -388,29 +395,29 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, } - // Declare return place local so that `Mir::new` doesn't complain. + // Declare return place local so that `mir::Body::new` doesn't complain. let initial_locals = iter::once( - LocalDecl::new_return_place(tcx.types.never, mir.span) + LocalDecl::new_return_place(tcx.types.never, body.span) ).collect(); let promoter = Promoter { - promoted: Mir::new( + promoted: Body::new( IndexVec::new(), // FIXME: maybe try to filter this to avoid blowing up // memory usage? - mir.source_scopes.clone(), - mir.source_scope_local_data.clone(), + body.source_scopes.clone(), + body.source_scope_local_data.clone(), IndexVec::new(), None, initial_locals, IndexVec::new(), 0, vec![], - mir.span, + body.span, vec![], ), tcx, - source: mir, + source: body, temps: &mut temps, keep_original: false }; @@ -419,7 +426,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, // Eliminate assignments to, and drops of promoted temps. let promoted = |index: Local| temps[index] == TempState::PromotedOut; - for block in mir.basic_blocks_mut() { + for block in body.basic_blocks_mut() { block.statements.retain(|statement| { match statement.kind { StatementKind::Assign(Place::Base(PlaceBase::Local(index)), _) | diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index d41098e2881a6..f082b5e5a046c 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -7,7 +7,6 @@ use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sync::Lrc; use rustc_target::spec::abi::Abi; use rustc::hir; use rustc::hir::def_id::DefId; @@ -16,12 +15,14 @@ use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; use rustc::ty::cast::CastTy; use rustc::ty::query::Providers; use rustc::mir::*; +use rustc::mir::interpret::ConstValue; use rustc::mir::traversal::ReversePostorder; use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext}; use rustc::middle::lang_items; use rustc::session::config::nightly_options; use syntax::ast::LitKind; use syntax::feature_gate::{emit_feature_err, GateIssue}; +use syntax::symbol::sym; use syntax_pos::{Span, DUMMY_SP}; use std::fmt; @@ -34,11 +35,25 @@ use super::promote_consts::{self, Candidate, TempState}; /// What kind of item we are in. #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum Mode { - Const, + /// A `static` item. Static, + /// A `static mut` item. StaticMut, + /// A `const fn` item. ConstFn, - Fn + /// A `const` item or an anonymous constant (e.g. in array lengths). + Const, + /// Other type of `fn`. + NonConstFn, +} + +impl Mode { + /// Determine whether we have to do full const-checking because syntactically, we + /// are required to be "const". + #[inline] + fn requires_const_checking(self) -> bool { + self != Mode::NonConstFn + } } impl fmt::Display for Mode { @@ -47,7 +62,7 @@ impl fmt::Display for Mode { Mode::Const => write!(f, "constant"), Mode::Static | Mode::StaticMut => write!(f, "static"), Mode::ConstFn => write!(f, "constant function"), - Mode::Fn => write!(f, "function") + Mode::NonConstFn => write!(f, "function") } } } @@ -109,10 +124,10 @@ impl IndexMut for PerQualif { } struct ConstCx<'a, 'tcx> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, mode: Mode, - mir: &'a Mir<'tcx>, + body: &'a Body<'tcx>, per_local: PerQualif>, } @@ -134,6 +149,12 @@ enum ValueSource<'a, 'tcx> { }, } +/// A "qualif"(-ication) is a way to look for something "bad" in the MIR that would disqualify some +/// code for promotion or prevent it from evaluating at compile time. So `return true` means +/// "I found something bad, no reason to go on searching". `false` is only returned if we +/// definitely cannot find anything bad anywhere. +/// +/// The default implementations proceed structurally. trait Qualif { const IDX: usize; @@ -160,14 +181,14 @@ trait Qualif { fn in_projection_structurally( cx: &ConstCx<'_, 'tcx>, - proj: &PlaceProjection<'tcx>, + proj: &Projection<'tcx>, ) -> bool { let base_qualif = Self::in_place(cx, &proj.base); let qualif = base_qualif && Self::mask_for_ty( cx, - proj.base.ty(cx.mir, cx.tcx) + proj.base.ty(cx.body, cx.tcx) .projection_ty(cx.tcx, &proj.elem) - .to_ty(cx.tcx), + .ty, ); match proj.elem { ProjectionElem::Deref | @@ -180,15 +201,18 @@ trait Qualif { } } - fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &PlaceProjection<'tcx>) -> bool { + fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &Projection<'tcx>) -> bool { Self::in_projection_structurally(cx, proj) } fn in_place(cx: &ConstCx<'_, 'tcx>, place: &Place<'tcx>) -> bool { match *place { Place::Base(PlaceBase::Local(local)) => Self::in_local(cx, local), - Place::Base(PlaceBase::Promoted(_)) => bug!("qualifying already promoted MIR"), - Place::Base(PlaceBase::Static(ref static_)) => Self::in_static(cx, static_), + Place::Base(PlaceBase::Static(box Static {kind: StaticKind::Promoted(_), .. })) => + bug!("qualifying already promoted MIR"), + Place::Base(PlaceBase::Static(ref static_)) => { + Self::in_static(cx, static_) + }, Place::Projection(ref proj) => Self::in_projection(cx, proj), } } @@ -199,12 +223,12 @@ trait Qualif { Operand::Move(ref place) => Self::in_place(cx, place), Operand::Constant(ref constant) => { - if let ty::LazyConst::Unevaluated(def_id, _) = constant.literal { + if let ConstValue::Unevaluated(def_id, _) = constant.literal.val { // Don't peek inside trait associated constants. - if cx.tcx.trait_of_item(*def_id).is_some() { + if cx.tcx.trait_of_item(def_id).is_some() { Self::in_any_value_of_ty(cx, constant.ty).unwrap_or(false) } else { - let (bits, _) = cx.tcx.at(constant.span).mir_const_qualif(*def_id); + let (bits, _) = cx.tcx.at(constant.span).mir_const_qualif(def_id); let qualif = PerQualif::decode_from_bits(bits).0[Self::IDX]; @@ -241,7 +265,7 @@ trait Qualif { // Special-case reborrows to be more like a copy of the reference. if let Place::Projection(ref proj) = *place { if let ProjectionElem::Deref = proj.elem { - let base_ty = proj.base.ty(cx.mir, cx.tcx).to_ty(cx.tcx); + let base_ty = proj.base.ty(cx.body, cx.tcx).ty; if let ty::Ref(..) = base_ty.sty { return Self::in_place(cx, &proj.base); } @@ -281,7 +305,11 @@ trait Qualif { } } -// Constant containing interior mutability (UnsafeCell). +/// Constant containing interior mutability (`UnsafeCell`). +/// This must be ruled out to make sure that evaluating the constant at compile-time +/// and at *any point* during the run-time would produce the same result. In particular, +/// promotion of temporaries must not change program behavior; if the promoted could be +/// written to, that would be a problem. struct HasMutInterior; impl Qualif for HasMutInterior { @@ -297,7 +325,7 @@ impl Qualif for HasMutInterior { // allowed in constants (and the `Checker` will error), and/or it // won't be promoted, due to `&mut ...` or interior mutability. Rvalue::Ref(_, kind, ref place) => { - let ty = place.ty(cx.mir, cx.tcx).to_ty(cx.tcx); + let ty = place.ty(cx.body, cx.tcx).ty; if let BorrowKind::Mut { .. } = kind { // In theory, any zero-sized value could be borrowed @@ -310,10 +338,11 @@ impl Qualif for HasMutInterior { _ => return true, } } else if let ty::Array(_, len) = ty.sty { - // FIXME(eddyb) the `cx.mode == Mode::Fn` condition + // FIXME(eddyb) the `cx.mode == Mode::NonConstFn` condition // seems unnecessary, given that this is merely a ZST. - if !(len.unwrap_usize(cx.tcx) == 0 && cx.mode == Mode::Fn) { - return true; + match len.assert_usize(cx.tcx) { + Some(0) if cx.mode == Mode::NonConstFn => {}, + _ => return true, } } else { return true; @@ -324,7 +353,7 @@ impl Qualif for HasMutInterior { Rvalue::Aggregate(ref kind, _) => { if let AggregateKind::Adt(def, ..) = **kind { if Some(def.did) == cx.tcx.lang_items().unsafe_cell_type() { - let ty = rvalue.ty(cx.mir, cx.tcx); + let ty = rvalue.ty(cx.body, cx.tcx); assert_eq!(Self::in_any_value_of_ty(cx, ty), Some(true)); return true; } @@ -338,7 +367,10 @@ impl Qualif for HasMutInterior { } } -// Constant containing an ADT that implements Drop. +/// Constant containing an ADT that implements `Drop`. +/// This must be ruled out (a) because we cannot run `Drop` during compile-time +/// as that might not be a `const fn`, and (b) because implicit promotion would +/// remove side-effects that occur as part of dropping that value. struct NeedsDrop; impl Qualif for NeedsDrop { @@ -361,22 +393,33 @@ impl Qualif for NeedsDrop { } } -// Not constant at all - non-`const fn` calls, asm!, -// pointer comparisons, ptr-to-int casts, etc. -struct IsNotConst; +/// Not promotable at all - non-`const fn` calls, `asm!`, +/// pointer comparisons, ptr-to-int casts, etc. +/// Inside a const context all constness rules apply, so promotion simply has to follow the regular +/// constant rules (modulo interior mutability or `Drop` rules which are handled `HasMutInterior` +/// and `NeedsDrop` respectively). Basically this duplicates the checks that the const-checking +/// visitor enforces by emitting errors when working in const context. +struct IsNotPromotable; -impl Qualif for IsNotConst { +impl Qualif for IsNotPromotable { const IDX: usize = 2; fn in_static(cx: &ConstCx<'_, 'tcx>, static_: &Static<'tcx>) -> bool { - // Only allow statics (not consts) to refer to other statics. - let allowed = cx.mode == Mode::Static || cx.mode == Mode::StaticMut; + match static_.kind { + StaticKind::Promoted(_) => unreachable!(), + StaticKind::Static(def_id) => { + // Only allow statics (not consts) to refer to other statics. + let allowed = cx.mode == Mode::Static || cx.mode == Mode::StaticMut; - !allowed || - cx.tcx.get_attrs(static_.def_id).iter().any(|attr| attr.check_name("thread_local")) + !allowed || + cx.tcx.get_attrs(def_id).iter().any( + |attr| attr.check_name(sym::thread_local) + ) + } + } } - fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &PlaceProjection<'tcx>) -> bool { + fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &Projection<'tcx>) -> bool { match proj.elem { ProjectionElem::Deref | ProjectionElem::Downcast(..) => return true, @@ -386,9 +429,10 @@ impl Qualif for IsNotConst { ProjectionElem::Index(_) => {} ProjectionElem::Field(..) => { - if cx.mode == Mode::Fn { - let base_ty = proj.base.ty(cx.mir, cx.tcx).to_ty(cx.tcx); + if cx.mode == Mode::NonConstFn { + let base_ty = proj.base.ty(cx.body, cx.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { + // No promotion of union field accesses. if def.is_union() { return true; } @@ -402,8 +446,8 @@ impl Qualif for IsNotConst { fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool { match *rvalue { - Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if cx.mode == Mode::Fn => { - let operand_ty = operand.ty(cx.mir, cx.tcx); + Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if cx.mode == Mode::NonConstFn => { + let operand_ty = operand.ty(cx.body, cx.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); match (cast_in, cast_out) { @@ -416,8 +460,8 @@ impl Qualif for IsNotConst { } } - Rvalue::BinaryOp(op, ref lhs, _) if cx.mode == Mode::Fn => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(cx.mir, cx.tcx).sty { + Rvalue::BinaryOp(op, ref lhs, _) if cx.mode == Mode::NonConstFn => { + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(cx.body, cx.tcx).sty { assert!(op == BinOp::Eq || op == BinOp::Ne || op == BinOp::Le || op == BinOp::Lt || op == BinOp::Ge || op == BinOp::Gt || @@ -442,7 +486,7 @@ impl Qualif for IsNotConst { args: &[Operand<'tcx>], _return_ty: Ty<'tcx>, ) -> bool { - let fn_ty = callee.ty(cx.mir, cx.tcx); + let fn_ty = callee.ty(cx.body, cx.tcx); match fn_ty.sty { ty::FnDef(def_id, _) => { match cx.tcx.fn_sig(def_id).abi() { @@ -497,21 +541,24 @@ impl Qualif for IsNotConst { } } -// Refers to temporaries which cannot be promoted as -// promote_consts decided they weren't simple enough. -struct IsNotPromotable; +/// Refers to temporaries which cannot be promoted *implicitly*. +/// Explicit promotion happens e.g. for constant arguments declared via `rustc_args_required_const`. +/// Implicit promotion has almost the same rules, except that disallows `const fn` except for +/// those marked `#[rustc_promotable]`. This is to avoid changing a legitimate run-time operation +/// into a failing compile-time operation e.g. due to addresses being compared inside the function. +struct IsNotImplicitlyPromotable; -impl Qualif for IsNotPromotable { +impl Qualif for IsNotImplicitlyPromotable { const IDX: usize = 3; fn in_call( cx: &ConstCx<'_, 'tcx>, callee: &Operand<'tcx>, - _args: &[Operand<'tcx>], + args: &[Operand<'tcx>], _return_ty: Ty<'tcx>, ) -> bool { - if cx.mode == Mode::Fn { - if let ty::FnDef(def_id, _) = callee.ty(cx.mir, cx.tcx).sty { + if cx.mode == Mode::NonConstFn { + if let ty::FnDef(def_id, _) = callee.ty(cx.body, cx.tcx).sty { // Never promote runtime `const fn` calls of // functions without `#[rustc_promotable]`. if !cx.tcx.is_promotable_const_fn(def_id) { @@ -520,35 +567,35 @@ impl Qualif for IsNotPromotable { } } - // FIXME(eddyb) do we need "not promotable" in anything - // other than `Mode::Fn` by any chance? - - false + Self::in_operand(cx, callee) || args.iter().any(|arg| Self::in_operand(cx, arg)) } } // Ensure the `IDX` values are sequential (`0..QUALIF_COUNT`). macro_rules! static_assert_seq_qualifs { ($i:expr => $first:ident $(, $rest:ident)*) => { - static_assert!(SEQ_QUALIFS: { + static_assert!({ static_assert_seq_qualifs!($i + 1 => $($rest),*); $first::IDX == $i }); }; ($i:expr =>) => { - static_assert!(SEQ_QUALIFS: QUALIF_COUNT == $i); + static_assert!(QUALIF_COUNT == $i); }; } -static_assert_seq_qualifs!(0 => HasMutInterior, NeedsDrop, IsNotConst, IsNotPromotable); +static_assert_seq_qualifs!( + 0 => HasMutInterior, NeedsDrop, IsNotPromotable, IsNotImplicitlyPromotable +); impl ConstCx<'_, 'tcx> { fn qualifs_in_any_value_of_ty(&self, ty: Ty<'tcx>) -> PerQualif { let mut qualifs = PerQualif::default(); qualifs[HasMutInterior] = HasMutInterior::in_any_value_of_ty(self, ty).unwrap_or(false); qualifs[NeedsDrop] = NeedsDrop::in_any_value_of_ty(self, ty).unwrap_or(false); - qualifs[IsNotConst] = IsNotConst::in_any_value_of_ty(self, ty).unwrap_or(false); qualifs[IsNotPromotable] = IsNotPromotable::in_any_value_of_ty(self, ty).unwrap_or(false); + qualifs[IsNotImplicitlyPromotable] = + IsNotImplicitlyPromotable::in_any_value_of_ty(self, ty).unwrap_or(false); qualifs } @@ -556,8 +603,8 @@ impl ConstCx<'_, 'tcx> { let mut qualifs = PerQualif::default(); qualifs[HasMutInterior] = HasMutInterior::in_local(self, local); qualifs[NeedsDrop] = NeedsDrop::in_local(self, local); - qualifs[IsNotConst] = IsNotConst::in_local(self, local); qualifs[IsNotPromotable] = IsNotPromotable::in_local(self, local); + qualifs[IsNotImplicitlyPromotable] = IsNotImplicitlyPromotable::in_local(self, local); qualifs } @@ -565,12 +612,17 @@ impl ConstCx<'_, 'tcx> { let mut qualifs = PerQualif::default(); qualifs[HasMutInterior] = HasMutInterior::in_value(self, source); qualifs[NeedsDrop] = NeedsDrop::in_value(self, source); - qualifs[IsNotConst] = IsNotConst::in_value(self, source); qualifs[IsNotPromotable] = IsNotPromotable::in_value(self, source); + qualifs[IsNotImplicitlyPromotable] = IsNotImplicitlyPromotable::in_value(self, source); qualifs } } +/// Checks MIR for being admissible as a compile-time constant, using `ConstCx` +/// for value qualifications, and accumulates writes of +/// rvalue/call results to locals, in `local_qualif`. +/// It also records candidates for promotion in `promotion_candidates`, +/// both in functions and const/static items. struct Checker<'a, 'tcx> { cx: ConstCx<'a, 'tcx>, @@ -600,14 +652,10 @@ impl Deref for Checker<'a, 'tcx> { } impl<'a, 'tcx> Checker<'a, 'tcx> { - fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - mir: &'a Mir<'tcx>, - mode: Mode) - -> Self { + fn new(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>, mode: Mode) -> Self { assert!(def_id.is_local()); - let mut rpo = traversal::reverse_postorder(mir); - let temps = promote_consts::collect_temps(mir, &mut rpo); + let mut rpo = traversal::reverse_postorder(body); + let temps = promote_consts::collect_temps(body, &mut rpo); rpo.reset(); let param_env = tcx.param_env(def_id); @@ -616,37 +664,32 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { tcx, param_env, mode, - mir, - per_local: PerQualif::new(BitSet::new_empty(mir.local_decls.len())), + body, + per_local: PerQualif::new(BitSet::new_empty(body.local_decls.len())), }; - for (local, decl) in mir.local_decls.iter_enumerated() { - match mir.local_kind(local) { - LocalKind::Arg => { - let qualifs = cx.qualifs_in_any_value_of_ty(decl.ty); - for (per_local, qualif) in &mut cx.per_local.as_mut().zip(qualifs).0 { - if *qualif { - per_local.insert(local); - } + for (local, decl) in body.local_decls.iter_enumerated() { + if let LocalKind::Arg = body.local_kind(local) { + let qualifs = cx.qualifs_in_any_value_of_ty(decl.ty); + for (per_local, qualif) in &mut cx.per_local.as_mut().zip(qualifs).0 { + if *qualif { + per_local.insert(local); } - cx.per_local[IsNotPromotable].insert(local); - } - - LocalKind::Var if mode == Mode::Fn => { - cx.per_local[IsNotConst].insert(local); } - - LocalKind::Temp if !temps[local].is_promotable() => { - cx.per_local[IsNotPromotable].insert(local); - } - - _ => {} + } + if !temps[local].is_promotable() { + cx.per_local[IsNotPromotable].insert(local); + } + if let LocalKind::Var = body.local_kind(local) { + // Sanity check to prevent implicit and explicit promotion of + // named locals + assert!(cx.per_local[IsNotPromotable].contains(local)); } } Checker { cx, - span: mir.span, + span: body.span, def_id, rpo, temp_promotion_state: temps, @@ -659,7 +702,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // slightly pointless (even with feature-gating). fn not_const(&mut self) { unleash_miri!(self); - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { let mut err = struct_span_err!( self.tcx.sess, self.span, @@ -688,40 +731,45 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // the borrowed place is disallowed from being borrowed, // due to either a mutable borrow (with some exceptions), // or an shared borrow of a value with interior mutability. - // Then `HasMutInterior` is replaced with `IsNotConst`, + // Then `HasMutInterior` is replaced with `IsNotPromotable`, // to avoid duplicate errors (e.g. from reborrowing). if qualifs[HasMutInterior] { qualifs[HasMutInterior] = false; - qualifs[IsNotConst] = true; - - if self.mode != Mode::Fn { - if let BorrowKind::Mut { .. } = kind { - let mut err = struct_span_err!(self.tcx.sess, self.span, E0017, - "references in {}s may only refer \ - to immutable values", self.mode); - err.span_label(self.span, format!("{}s require immutable values", - self.mode)); - if self.tcx.sess.teach(&err.get_code().unwrap()) { - err.note("References in statics and constants may only refer to \ - immutable values.\n\n\ - Statics are shared everywhere, and if they refer to \ - mutable data one might violate memory safety since \ - holding multiple mutable references to shared data is \ - not allowed.\n\n\ - If you really want global mutable state, try using \ - static mut or a global UnsafeCell."); + qualifs[IsNotPromotable] = true; + + if self.mode.requires_const_checking() { + if !self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { + if let BorrowKind::Mut { .. } = kind { + let mut err = struct_span_err!(self.tcx.sess, self.span, E0017, + "references in {}s may only refer \ + to immutable values", self.mode); + err.span_label(self.span, format!("{}s require immutable values", + self.mode)); + if self.tcx.sess.teach(&err.get_code().unwrap()) { + err.note("References in statics and constants may only refer to \ + immutable values.\n\n\ + Statics are shared everywhere, and if they refer to \ + mutable data one might violate memory safety since \ + holding multiple mutable references to shared data is \ + not allowed.\n\n\ + If you really want global mutable state, try using \ + static mut or a global UnsafeCell."); + } + err.emit(); + } else { + span_err!(self.tcx.sess, self.span, E0492, + "cannot borrow a constant which may contain \ + interior mutability, create a static instead"); } - err.emit(); - } else { - span_err!(self.tcx.sess, self.span, E0492, - "cannot borrow a constant which may contain \ - interior mutability, create a static instead"); } } - } else { + } else if let BorrowKind::Mut { .. } | BorrowKind::Shared = kind { + // Don't promote BorrowKind::Shallow borrows, as they don't + // reach codegen. + // We might have a candidate for promotion. let candidate = Candidate::Ref(location); - // We can only promote interior borrows of promotable temps. + // Start by traversing to the "base", with non-deref projections removed. let mut place = place; while let Place::Projection(ref proj) = *place { if proj.elem == ProjectionElem::Deref { @@ -730,8 +778,12 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { place = &proj.base; } debug!("qualify_consts: promotion candidate: place={:?}", place); + // We can only promote interior borrows of promotable temps (non-temps + // don't get promoted anyway). + // (If we bailed out of the loop due to a `Deref` above, we will definitely + // not enter the conditional here.) if let Place::Base(PlaceBase::Local(local)) = *place { - if self.mir.local_kind(local) == LocalKind::Temp { + if self.body.local_kind(local) == LocalKind::Temp { debug!("qualify_consts: promotion candidate: local={:?}", local); // The borrowed place doesn't have `HasMutInterior` // (from `in_rvalue`), so we can safely ignore @@ -740,6 +792,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // `HasMutInterior`, from a type that does, e.g.: // `let _: &'static _ = &(Cell::new(1), 2).1;` let mut local_qualifs = self.qualifs_in_local(local); + // Any qualifications, except HasMutInterior (see above), disqualify + // from promotion. + // This is, in particular, the "implicit promotion" version of + // the check making sure that we don't run drop glue during const-eval. local_qualifs[HasMutInterior] = false; if !local_qualifs.0.iter().any(|&qualif| qualif) { debug!("qualify_consts: promotion candidate: {:?}", candidate); @@ -768,9 +824,9 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { ); dest = &proj.base; }, - Place::Base(PlaceBase::Promoted(..)) => + Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => bug!("promoteds don't exist yet during promotion"), - Place::Base(PlaceBase::Static(..)) => { + Place::Base(PlaceBase::Static(box Static{ kind: _, .. })) => { // Catch more errors in the destination. `visit_place` also checks that we // do not try to access statics from constants or try to mutate statics self.visit_place( @@ -783,11 +839,11 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { } }; - let kind = self.mir.local_kind(index); + let kind = self.body.local_kind(index); debug!("store to {:?} {:?}", kind, index); // Only handle promotable temps in non-const functions. - if self.mode == Mode::Fn { + if self.mode == Mode::NonConstFn { if kind != LocalKind::Temp || !self.temp_promotion_state[index].is_promotable() { return; @@ -818,19 +874,19 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { } /// Check a whole const, static initializer or const fn. - fn check_const(&mut self) -> (u8, Lrc>) { + fn check_const(&mut self) -> (u8, &'tcx BitSet) { debug!("const-checking {} {:?}", self.mode, self.def_id); - let mir = self.mir; + let body = self.body; - let mut seen_blocks = BitSet::new_empty(mir.basic_blocks().len()); + let mut seen_blocks = BitSet::new_empty(body.basic_blocks().len()); let mut bb = START_BLOCK; loop { seen_blocks.insert(bb.index()); - self.visit_basic_block_data(bb, &mir[bb]); + self.visit_basic_block_data(bb, &body[bb]); - let target = match mir[bb].terminator().kind { + let target = match body[bb].terminator().kind { TerminatorKind::Goto { target } | TerminatorKind::Drop { target, .. } | TerminatorKind::Assert { target, .. } | @@ -878,7 +934,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { for candidate in &self.promotion_candidates { match *candidate { Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => { - match self.mir[bb].statements[stmt_idx].kind { + match self.body[bb].statements[stmt_idx].kind { StatementKind::Assign( _, box Rvalue::Ref(_, _, Place::Base(PlaceBase::Local(index))) @@ -892,44 +948,40 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { } } - let promoted_temps = Lrc::new(promoted_temps); - let mut qualifs = self.qualifs_in_local(RETURN_PLACE); // Account for errors in consts by using the // conservative type qualification instead. - if qualifs[IsNotConst] { - qualifs = self.qualifs_in_any_value_of_ty(mir.return_ty()); + if qualifs[IsNotPromotable] { + qualifs = self.qualifs_in_any_value_of_ty(body.return_ty()); } - (qualifs.encode_to_bits(), promoted_temps) + (qualifs.encode_to_bits(), self.tcx.arena.alloc(promoted_temps)) } } -/// Checks MIR for const-correctness, using `ConstCx` -/// for value qualifications, and accumulates writes of -/// rvalue/call results to locals, in `local_qualif`. -/// For functions (constant or not), it also records -/// candidates for promotion in `promotion_candidates`. impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { - fn visit_place(&mut self, - place: &Place<'tcx>, - context: PlaceContext<'tcx>, - location: Location) { - debug!("visit_place: place={:?} context={:?} location={:?}", place, context, location); - self.super_place(place, context, location); - match *place { - Place::Base(PlaceBase::Local(_)) | - Place::Base(PlaceBase::Promoted(_)) => {} - Place::Base(PlaceBase::Static(ref global)) => { + fn visit_place_base( + &mut self, + place_base: &PlaceBase<'tcx>, + context: PlaceContext, + location: Location, + ) { + self.super_place_base(place_base, context, location); + match place_base { + PlaceBase::Local(_) => {} + PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => { + unreachable!() + } + PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => { if self.tcx - .get_attrs(global.def_id) - .iter() - .any(|attr| attr.check_name("thread_local")) { - if self.mode != Mode::Fn { + .get_attrs(*def_id) + .iter() + .any(|attr| attr.check_name(sym::thread_local)) { + if self.mode.requires_const_checking() { span_err!(self.tcx.sess, self.span, E0625, - "thread-local statics cannot be \ - accessed at compile-time"); + "thread-local statics cannot be \ + accessed at compile-time"); } return; } @@ -950,14 +1002,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } unleash_miri!(self); - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { let mut err = struct_span_err!(self.tcx.sess, self.span, E0013, - "{}s cannot refer to statics, use \ + "{}s cannot refer to statics, use \ a constant instead", self.mode); if self.tcx.sess.teach(&err.get_code().unwrap()) { err.note( - "Static and const variables can refer to other const variables. But a \ - const variable cannot refer to a static variable." + "Static and const variables can refer to other const variables. \ + But a const variable cannot refer to a static variable." ); err.help( "To fix this, the value can be extracted as a const and then used." @@ -966,66 +1018,77 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { err.emit() } } - Place::Projection(ref proj) => { - match proj.elem { - ProjectionElem::Deref => { - if context.is_mutating_use() { - // `not_const` errors out in const contexts - self.not_const() - } - let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); - match self.mode { - Mode::Fn => {}, - _ => { - if let ty::RawPtr(_) = base_ty.sty { - if !self.tcx.features().const_raw_ptr_deref { - emit_feature_err( - &self.tcx.sess.parse_sess, "const_raw_ptr_deref", - self.span, GateIssue::Language, - &format!( - "dereferencing raw pointers in {}s is unstable", - self.mode, - ), - ); - } - } + } + } + + fn visit_projection( + &mut self, + proj: &Projection<'tcx>, + context: PlaceContext, + location: Location, + ) { + debug!( + "visit_place_projection: proj={:?} context={:?} location={:?}", + proj, context, location, + ); + self.super_projection(proj, context, location); + match proj.elem { + ProjectionElem::Deref => { + if context.is_mutating_use() { + // `not_const` errors out in const contexts + self.not_const() + } + let base_ty = proj.base.ty(self.body, self.tcx).ty; + match self.mode { + Mode::NonConstFn => {}, + _ => { + if let ty::RawPtr(_) = base_ty.sty { + if !self.tcx.features().const_raw_ptr_deref { + emit_feature_err( + &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref, + self.span, GateIssue::Language, + &format!( + "dereferencing raw pointers in {}s is unstable", + self.mode, + ), + ); } } } + } + } - ProjectionElem::ConstantIndex {..} | - ProjectionElem::Subslice {..} | - ProjectionElem::Field(..) | - ProjectionElem::Index(_) => { - let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); - if let Some(def) = base_ty.ty_adt_def() { - if def.is_union() { - match self.mode { - Mode::ConstFn => { - if !self.tcx.features().const_fn_union { - emit_feature_err( - &self.tcx.sess.parse_sess, "const_fn_union", - self.span, GateIssue::Language, - "unions in const fn are unstable", - ); - } - }, - - | Mode::Fn - | Mode::Static - | Mode::StaticMut - | Mode::Const - => {}, + ProjectionElem::ConstantIndex {..} | + ProjectionElem::Subslice {..} | + ProjectionElem::Field(..) | + ProjectionElem::Index(_) => { + let base_ty = proj.base.ty(self.body, self.tcx).ty; + if let Some(def) = base_ty.ty_adt_def() { + if def.is_union() { + match self.mode { + Mode::ConstFn => { + if !self.tcx.features().const_fn_union { + emit_feature_err( + &self.tcx.sess.parse_sess, sym::const_fn_union, + self.span, GateIssue::Language, + "unions in const fn are unstable", + ); } - } - } - } + }, - ProjectionElem::Downcast(..) => { - self.not_const() + | Mode::NonConstFn + | Mode::Static + | Mode::StaticMut + | Mode::Const + => {}, + } } } } + + ProjectionElem::Downcast(..) => { + self.not_const() + } } } @@ -1049,34 +1112,34 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { debug!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location); // Check nested operands and places. - if let Rvalue::Ref(region, kind, ref place) = *rvalue { + if let Rvalue::Ref(_, kind, ref place) = *rvalue { // Special-case reborrows. - let mut is_reborrow = false; + let mut reborrow_place = None; if let Place::Projection(ref proj) = *place { if let ProjectionElem::Deref = proj.elem { - let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let base_ty = proj.base.ty(self.body, self.tcx).ty; if let ty::Ref(..) = base_ty.sty { - is_reborrow = true; + reborrow_place = Some(&proj.base); } } } - if is_reborrow { + if let Some(place) = reborrow_place { let ctx = match kind { BorrowKind::Shared => PlaceContext::NonMutatingUse( - NonMutatingUseContext::SharedBorrow(region), + NonMutatingUseContext::SharedBorrow, ), BorrowKind::Shallow => PlaceContext::NonMutatingUse( - NonMutatingUseContext::ShallowBorrow(region), + NonMutatingUseContext::ShallowBorrow, ), BorrowKind::Unique => PlaceContext::NonMutatingUse( - NonMutatingUseContext::UniqueBorrow(region), + NonMutatingUseContext::UniqueBorrow, ), BorrowKind::Mut { .. } => PlaceContext::MutatingUse( - MutatingUseContext::Borrow(region), + MutatingUseContext::Borrow, ), }; - self.super_place(place, ctx, location); + self.visit_place(place, ctx, location); } else { self.super_rvalue(rvalue, location); } @@ -1091,28 +1154,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { Rvalue::UnaryOp(UnOp::Not, _) | Rvalue::NullaryOp(NullOp::SizeOf, _) | Rvalue::CheckedBinaryOp(..) | - Rvalue::Cast(CastKind::ReifyFnPointer, ..) | - Rvalue::Cast(CastKind::UnsafeFnPointer, ..) | - Rvalue::Cast(CastKind::ClosureFnPointer, ..) | - Rvalue::Cast(CastKind::Unsize, ..) | + Rvalue::Cast(CastKind::Pointer(_), ..) | Rvalue::Discriminant(..) | Rvalue::Len(_) | Rvalue::Ref(..) | Rvalue::Aggregate(..) => {} Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { - let operand_ty = operand.ty(self.mir, self.tcx); + let operand_ty = operand.ty(self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); match (cast_in, cast_out) { (CastTy::Ptr(_), CastTy::Int(_)) | - (CastTy::FnPtr, CastTy::Int(_)) if self.mode != Mode::Fn => { + (CastTy::FnPtr, CastTy::Int(_)) if self.mode != Mode::NonConstFn => { unleash_miri!(self); if !self.tcx.features().const_raw_ptr_to_usize_cast { // in const fn and constants require the feature gate // FIXME: make it unsafe inside const fn and constants emit_feature_err( - &self.tcx.sess.parse_sess, "const_raw_ptr_to_usize_cast", + &self.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast, self.span, GateIssue::Language, &format!( "casting pointers to integers in {}s is unstable", @@ -1126,19 +1186,21 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } Rvalue::BinaryOp(op, ref lhs, _) => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.mir, self.tcx).sty { + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).sty { assert!(op == BinOp::Eq || op == BinOp::Ne || op == BinOp::Le || op == BinOp::Lt || op == BinOp::Ge || op == BinOp::Gt || op == BinOp::Offset); unleash_miri!(self); - if self.mode != Mode::Fn && !self.tcx.features().const_compare_raw_pointers { + if self.mode.requires_const_checking() && + !self.tcx.features().const_compare_raw_pointers + { // require the feature gate inside constants and const fn // FIXME: make it unsafe to use these operations emit_feature_err( &self.tcx.sess.parse_sess, - "const_compare_raw_pointers", + sym::const_compare_raw_pointers, self.span, GateIssue::Language, &format!("comparing raw pointers inside {}", self.mode), @@ -1149,7 +1211,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { Rvalue::NullaryOp(NullOp::Box, _) => { unleash_miri!(self); - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { let mut err = struct_span_err!(self.tcx.sess, self.span, E0010, "allocations are not allowed in {}s", self.mode); err.span_label(self.span, format!("allocation not allowed in {}s", self.mode)); @@ -1168,20 +1230,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } fn visit_terminator_kind(&mut self, - bb: BasicBlock, kind: &TerminatorKind<'tcx>, location: Location) { - debug!("visit_terminator_kind: bb={:?} kind={:?} location={:?}", bb, kind, location); + debug!("visit_terminator_kind: kind={:?} location={:?}", kind, location); if let TerminatorKind::Call { ref func, ref args, ref destination, .. } = *kind { if let Some((ref dest, _)) = *destination { self.assign(dest, ValueSource::Call { callee: func, args, - return_ty: dest.ty(self.mir, self.tcx).to_ty(self.tcx), + return_ty: dest.ty(self.body, self.tcx).ty, }, location); } - let fn_ty = func.ty(self.mir, self.tcx); + let fn_ty = func.ty(self.body, self.tcx); let mut callee_def_id = None; let mut is_shuffle = false; match fn_ty.sty { @@ -1195,12 +1256,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // special intrinsic that can be called diretly without an intrinsic // feature gate needs a language feature gate "transmute" => { - // never promote transmute calls - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { // const eval transmute calls only with the feature gate if !self.tcx.features().const_transmute { emit_feature_err( - &self.tcx.sess.parse_sess, "const_transmute", + &self.tcx.sess.parse_sess, sym::const_transmute, self.span, GateIssue::Language, &format!("The use of std::mem::transmute() \ is gated in {}s", self.mode)); @@ -1219,7 +1279,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } _ => { // In normal functions no calls are feature-gated. - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { let unleash_miri = self .tcx .sess @@ -1239,7 +1299,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // Don't allow panics in constants without the feature gate. emit_feature_err( &self.tcx.sess.parse_sess, - "const_panic", + sym::const_panic, self.span, GateIssue::Language, &format!("panicking in {}s is unstable", self.mode), @@ -1250,10 +1310,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // Check `#[unstable]` const fns or `#[rustc_const_unstable]` // functions without the feature gate active in this crate in // order to report a better error message than the one below. - if !self.span.allows_unstable(&feature.as_str()) { + if !self.span.allows_unstable(feature) { let mut err = self.tcx.sess.struct_span_err(self.span, &format!("`{}` is not yet stable as a const fn", - self.tcx.item_path_str(def_id))); + self.tcx.def_path_str(def_id))); if nightly_options::is_nightly_build() { help!(&mut err, "add `#![feature({})]` to the \ @@ -1278,7 +1338,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } } ty::FnPtr(_) => { - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { let mut err = self.tcx.sess.struct_span_err( self.span, &format!("function pointers are not allowed in const fn")); @@ -1290,7 +1350,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } } - if self.mode == Mode::Fn { + // No need to do anything in constants and statics, as everything is "constant" anyway + // so promotion would be useless. + if self.mode != Mode::Static && self.mode != Mode::Const { let constant_args = callee_def_id.and_then(|id| { args_required_const(self.tcx, id) }).unwrap_or_default(); @@ -1299,7 +1361,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { continue; } - let candidate = Candidate::Argument { bb, index: i }; + let candidate = Candidate::Argument { bb: location.block, index: i }; // Since the argument is required to be constant, // we care about constness, not promotability. // If we checked for promotability, we'd miss out on @@ -1310,7 +1372,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // which happens even without the user requesting it. // We can error out with a hard error if the argument is not // constant here. - if !IsNotConst::in_operand(self, arg) { + if !IsNotPromotable::in_operand(self, arg) { debug!("visit_terminator_kind: candidate={:?}", candidate); self.promotion_candidates.push(candidate); } else { @@ -1332,16 +1394,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { self.visit_operand(arg, location); } } else if let TerminatorKind::Drop { location: ref place, .. } = *kind { - self.super_terminator_kind(bb, kind, location); + self.super_terminator_kind(kind, location); // Deny *any* live drops anywhere other than functions. - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { unleash_miri!(self); // HACK(eddyb): emulate a bit of dataflow analysis, // conservatively, that drop elaboration will do. let needs_drop = if let Place::Base(PlaceBase::Local(local)) = *place { if NeedsDrop::in_local(self, local) { - Some(self.mir.local_decls[local].source_info.span) + Some(self.body.local_decls[local].source_info.span) } else { None } @@ -1351,7 +1413,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { if let Some(span) = needs_drop { // Double-check the type being dropped, to minimize false positives. - let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx); + let ty = place.ty(self.body, self.tcx).ty; if ty.needs_drop(self.tcx, self.param_env) { struct_span_err!(self.tcx.sess, span, E0493, "destructors cannot be evaluated at compile-time") @@ -1363,12 +1425,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } } else { // Qualify any operands inside other terminators. - self.super_terminator_kind(bb, kind, location); + self.super_terminator_kind(kind, location); } } fn visit_assign(&mut self, - _: BasicBlock, dest: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { @@ -1383,11 +1444,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { self.span = source_info.span; } - fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>, location: Location) { - debug!("visit_statement: bb={:?} statement={:?} location={:?}", bb, statement, location); + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + debug!("visit_statement: statement={:?} location={:?}", statement, location); match statement.kind { StatementKind::Assign(..) => { - self.super_statement(bb, statement, location); + self.super_statement(statement, location); + } + StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => { + self.not_const(); } // FIXME(eddyb) should these really do nothing? StatementKind::FakeRead(..) | @@ -1400,14 +1464,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { StatementKind::Nop => {} } } - - fn visit_terminator(&mut self, - bb: BasicBlock, - terminator: &Terminator<'tcx>, - location: Location) { - debug!("visit_terminator: bb={:?} terminator={:?} location={:?}", bb, terminator, location); - self.super_terminator(bb, terminator, location); - } } pub fn provide(providers: &mut Providers<'_>) { @@ -1417,33 +1473,28 @@ pub fn provide(providers: &mut Providers<'_>) { }; } -fn mir_const_qualif<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> (u8, Lrc>) { +fn mir_const_qualif<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> (u8, &'tcx BitSet) { // N.B., this `borrow()` is guaranteed to be valid (i.e., the value // cannot yet be stolen), because `mir_validated()`, which steals // from `mir_const(), forces this query to execute before // performing the steal. - let mir = &tcx.mir_const(def_id).borrow(); + let body = &tcx.mir_const(def_id).borrow(); - if mir.return_ty().references_error() { - tcx.sess.delay_span_bug(mir.span, "mir_const_qualif: Mir had errors"); - return (1 << IsNotConst::IDX, Lrc::new(BitSet::new_empty(0))); + if body.return_ty().references_error() { + tcx.sess.delay_span_bug(body.span, "mir_const_qualif: MIR had errors"); + return (1 << IsNotPromotable::IDX, tcx.arena.alloc(BitSet::new_empty(0))); } - Checker::new(tcx, def_id, mir, Mode::Const).check_const() + Checker::new(tcx, def_id, body, Mode::Const).check_const() } pub struct QualifyAndPromoteConstants; impl MirPass for QualifyAndPromoteConstants { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { // There's not really any point in promoting errorful MIR. - if mir.return_ty().references_error() { - tcx.sess.delay_span_bug(mir.span, "QualifyAndPromoteConstants: Mir had errors"); + if body.return_ty().references_error() { + tcx.sess.delay_span_bug(body.span, "QualifyAndPromoteConstants: MIR had errors"); return; } @@ -1454,13 +1505,13 @@ impl MirPass for QualifyAndPromoteConstants { let def_id = src.def_id(); let id = tcx.hir().as_local_hir_id(def_id).unwrap(); let mut const_promoted_temps = None; - let mode = match tcx.hir().body_owner_kind_by_hir_id(id) { - hir::BodyOwnerKind::Closure => Mode::Fn, + let mode = match tcx.hir().body_owner_kind(id) { + hir::BodyOwnerKind::Closure => Mode::NonConstFn, hir::BodyOwnerKind::Fn => { if tcx.is_const_fn(def_id) { Mode::ConstFn } else { - Mode::Fn + Mode::NonConstFn } } hir::BodyOwnerKind::Const => { @@ -1472,25 +1523,27 @@ impl MirPass for QualifyAndPromoteConstants { }; debug!("run_pass: mode={:?}", mode); - if mode == Mode::Fn || mode == Mode::ConstFn { + if mode == Mode::NonConstFn || mode == Mode::ConstFn { // This is ugly because Checker holds onto mir, // which can't be mutated until its scope ends. let (temps, candidates) = { - let mut checker = Checker::new(tcx, def_id, mir, mode); + let mut checker = Checker::new(tcx, def_id, body, mode); if mode == Mode::ConstFn { if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { checker.check_const(); } else if tcx.is_min_const_fn(def_id) { // enforce `min_const_fn` for stable const fns use super::qualify_min_const_fn::is_min_const_fn; - if let Err((span, err)) = is_min_const_fn(tcx, def_id, mir) { + if let Err((span, err)) = is_min_const_fn(tcx, def_id, body) { let mut diag = struct_span_err!( tcx.sess, span, E0723, - "{} (see issue #57563)", + "{}", err, ); + diag.note("for more information, see issue \ + https://github.com/rust-lang/rust/issues/57563"); diag.help( "add #![feature(const_fn)] to the crate attributes to enable", ); @@ -1514,12 +1567,12 @@ impl MirPass for QualifyAndPromoteConstants { }; // Do the actual promotion, now that we know what's viable. - promote_consts::promote_candidates(mir, tcx, temps, candidates); + promote_consts::promote_candidates(body, tcx, temps, candidates); } else { - if !mir.control_flow_destroyed.is_empty() { - let mut locals = mir.vars_iter(); + if !body.control_flow_destroyed.is_empty() { + let mut locals = body.vars_iter(); if let Some(local) = locals.next() { - let span = mir.local_decls[local].source_info.span; + let span = body.local_decls[local].source_info.span; let mut error = tcx.sess.struct_span_err( span, &format!( @@ -1528,7 +1581,7 @@ impl MirPass for QualifyAndPromoteConstants { mode, ), ); - for (span, kind) in mir.control_flow_destroyed.iter() { + for (span, kind) in body.control_flow_destroyed.iter() { error.span_note( *span, &format!("use of {} here does not actually short circuit due to \ @@ -1538,7 +1591,7 @@ impl MirPass for QualifyAndPromoteConstants { ); } for local in locals { - let span = mir.local_decls[local].source_info.span; + let span = body.local_decls[local].source_info.span; error.span_note( span, "more locals defined here", @@ -1551,14 +1604,14 @@ impl MirPass for QualifyAndPromoteConstants { // Already computed by `mir_const_qualif`. const_promoted_temps.unwrap() } else { - Checker::new(tcx, def_id, mir, mode).check_const().1 + Checker::new(tcx, def_id, body, mode).check_const().1 }; // In `const` and `static` everything without `StorageDead` // is `'static`, we don't have to create promoted MIR fragments, // just remove `Drop` and `StorageDead` on "promoted" locals. debug!("run_pass: promoted_temps={:?}", promoted_temps); - for block in mir.basic_blocks_mut() { + for block in body.basic_blocks_mut() { block.statements.retain(|statement| { match statement.kind { StatementKind::StorageDead(index) => { @@ -1589,14 +1642,14 @@ impl MirPass for QualifyAndPromoteConstants { if mode == Mode::Static { // `#[thread_local]` statics don't have to be `Sync`. for attr in &tcx.get_attrs(def_id)[..] { - if attr.check_name("thread_local") { + if attr.check_name(sym::thread_local) { return; } } - let ty = mir.return_ty(); + let ty = body.return_ty(); tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::empty(); - let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic); + let cause = traits::ObligationCause::new(body.span, id, traits::SharedStatic); let mut fulfillment_cx = traits::FulfillmentContext::new(); fulfillment_cx.register_bound(&infcx, param_env, @@ -1611,9 +1664,9 @@ impl MirPass for QualifyAndPromoteConstants { } } -fn args_required_const(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option> { +fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { let attrs = tcx.get_attrs(def_id); - let attr = attrs.iter().find(|a| a.check_name("rustc_args_required_const"))?; + let attr = attrs.iter().find(|a| a.check_name(sym::rustc_args_required_const))?; let mut ret = FxHashSet::default(); for meta in attr.meta_item_list()? { match meta.literal()?.node { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 6c44fac10f59d..b84bc31ec2ae2 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -1,18 +1,14 @@ use rustc::hir::def_id::DefId; use rustc::hir; use rustc::mir::*; -use rustc::ty::{self, Predicate, TyCtxt}; +use rustc::ty::{self, Predicate, Ty, TyCtxt, adjustment::{PointerCast}}; use rustc_target::spec::abi; use std::borrow::Cow; use syntax_pos::Span; type McfResult = Result<(), (Span, Cow<'static, str>)>; -pub fn is_min_const_fn( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - mir: &'a Mir<'tcx>, -) -> McfResult { +pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -> McfResult { let mut current = def_id; loop { let predicates = tcx.predicates_of(current); @@ -59,30 +55,27 @@ pub fn is_min_const_fn( } } - for local in &mir.local_decls { - check_ty(tcx, local.ty, local.source_info.span)?; + for local in &body.local_decls { + check_ty(tcx, local.ty, local.source_info.span, def_id)?; } // impl trait is gone in MIR, so check the return type manually check_ty( tcx, tcx.fn_sig(def_id).output().skip_binder(), - mir.local_decls.iter().next().unwrap().source_info.span, + body.local_decls.iter().next().unwrap().source_info.span, + def_id, )?; - for bb in mir.basic_blocks() { - check_terminator(tcx, mir, bb.terminator())?; + for bb in body.basic_blocks() { + check_terminator(tcx, body, bb.terminator())?; for stmt in &bb.statements { - check_statement(tcx, mir, stmt)?; + check_statement(tcx, body, stmt)?; } } Ok(()) } -fn check_ty( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: ty::Ty<'tcx>, - span: Span, -) -> McfResult { +fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult { for ty in ty.walk() { match ty.sty { ty::Ref(_, _, hir::Mutability::MutMutable) => return Err(( @@ -91,7 +84,9 @@ fn check_ty( )), ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), ty::FnPtr(..) => { - return Err((span, "function pointers in const fn are unstable".into())) + if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) { + return Err((span, "function pointers in const fn are unstable".into())) + } } ty::Dynamic(preds, _) => { for pred in preds.iter() { @@ -125,21 +120,21 @@ fn check_ty( } fn check_rvalue( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &'a Mir<'tcx>, + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, rvalue: &Rvalue<'tcx>, span: Span, ) -> McfResult { match rvalue { Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => { - check_operand(tcx, mir, operand, span) + check_operand(operand, span) } Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => { - check_place(tcx, mir, place, span) + check_place(place, span) } Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { use rustc::ty::cast::CastTy; - let cast_in = CastTy::from_ty(operand.ty(mir, tcx)).expect("bad input type for cast"); + let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); match (cast_in, cast_out) { (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => Err(( @@ -149,24 +144,27 @@ fn check_rvalue( (CastTy::RPtr(_), CastTy::Float) => bug!(), (CastTy::RPtr(_), CastTy::Int(_)) => bug!(), (CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(), - _ => check_operand(tcx, mir, operand, span), + _ => check_operand(operand, span), } } - Rvalue::Cast(CastKind::UnsafeFnPointer, _, _) | - Rvalue::Cast(CastKind::ClosureFnPointer, _, _) | - Rvalue::Cast(CastKind::ReifyFnPointer, _, _) => Err(( + Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _) => { + check_operand(operand, span) + } + Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), _, _) | + Rvalue::Cast(CastKind::Pointer(PointerCast::ClosureFnPointer(_)), _, _) | + Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), _, _) => Err(( span, "function pointer casts are not allowed in const fn".into(), )), - Rvalue::Cast(CastKind::Unsize, _, _) => Err(( + Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => Err(( span, "unsizing casts are not allowed in const fn".into(), )), // binops are fine on integers Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { - check_operand(tcx, mir, lhs, span)?; - check_operand(tcx, mir, rhs, span)?; - let ty = lhs.ty(mir, tcx); + check_operand(lhs, span)?; + check_operand(rhs, span)?; + let ty = lhs.ty(body, tcx); if ty.is_integral() || ty.is_bool() || ty.is_char() { Ok(()) } else { @@ -182,9 +180,9 @@ fn check_rvalue( "heap allocations are not allowed in const fn".into(), )), Rvalue::UnaryOp(_, operand) => { - let ty = operand.ty(mir, tcx); + let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { - check_operand(tcx, mir, operand, span) + check_operand(operand, span) } else { Err(( span, @@ -194,7 +192,7 @@ fn check_rvalue( } Rvalue::Aggregate(_, operands) => { for operand in operands { - check_operand(tcx, mir, operand, span)?; + check_operand(operand, span)?; } Ok(()) } @@ -202,18 +200,22 @@ fn check_rvalue( } fn check_statement( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &'a Mir<'tcx>, + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, statement: &Statement<'tcx>, ) -> McfResult { let span = statement.source_info.span; match &statement.kind { StatementKind::Assign(place, rval) => { - check_place(tcx, mir, place, span)?; - check_rvalue(tcx, mir, rval, span) + check_place(place, span)?; + check_rvalue(tcx, body, rval, span) + } + + StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => { + Err((span, "loops and conditional expressions are not stable in const fn".into())) } - StatementKind::FakeRead(_, place) => check_place(tcx, mir, place, span), + StatementKind::FakeRead(_, place) => check_place(place, span), // just an assignment StatementKind::SetDiscriminant { .. } => Ok(()), @@ -232,48 +234,48 @@ fn check_statement( } fn check_operand( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &'a Mir<'tcx>, operand: &Operand<'tcx>, span: Span, ) -> McfResult { match operand { Operand::Move(place) | Operand::Copy(place) => { - check_place(tcx, mir, place, span) + check_place(place, span) } Operand::Constant(_) => Ok(()), } } fn check_place( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &'a Mir<'tcx>, place: &Place<'tcx>, span: Span, ) -> McfResult { - match place { - Place::Base(PlaceBase::Local(_)) => Ok(()), - // promoteds are always fine, they are essentially constants - Place::Base(PlaceBase::Promoted(_)) => Ok(()), - Place::Base(PlaceBase::Static(_)) => - Err((span, "cannot access `static` items in const fn".into())), - Place::Projection(proj) => { + place.iterate(|place_base, place_projection| { + for proj in place_projection { match proj.elem { - | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } - | ProjectionElem::Deref | ProjectionElem::Field(..) | ProjectionElem::Index(_) => { - check_place(tcx, mir, &proj.base, span) - } - | ProjectionElem::Downcast(..) => { - Err((span, "`match` or `if let` in `const fn` is unstable".into())) + ProjectionElem::Downcast(..) => { + return Err((span, "`match` or `if let` in `const fn` is unstable".into())); } + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Deref + | ProjectionElem::Field(..) + | ProjectionElem::Index(_) => {} } } - } + + match place_base { + PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. }) => { + Err((span, "cannot access `static` items in const fn".into())) + } + PlaceBase::Local(_) + | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => Ok(()), + } + }) } fn check_terminator( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &'a Mir<'tcx>, + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, terminator: &Terminator<'tcx>, ) -> McfResult { let span = terminator.source_info.span; @@ -283,16 +285,16 @@ fn check_terminator( | TerminatorKind::Resume => Ok(()), TerminatorKind::Drop { location, .. } => { - check_place(tcx, mir, location, span) + check_place(location, span) } TerminatorKind::DropAndReplace { location, value, .. } => { - check_place(tcx, mir, location, span)?; - check_operand(tcx, mir, value, span) + check_place(location, span)?; + check_operand(value, span) }, TerminatorKind::FalseEdges { .. } | TerminatorKind::SwitchInt { .. } => Err(( span, - "`if`, `match`, `&&` and `||` are not stable in const fn".into(), + "loops and conditional expressions are not stable in const fn".into(), )), | TerminatorKind::Abort | TerminatorKind::Unreachable => { Err((span, "const fn with unreachable code is not stable".into())) @@ -308,7 +310,7 @@ fn check_terminator( destination: _, cleanup: _, } => { - let fn_ty = func.ty(mir, tcx); + let fn_ty = func.ty(body, tcx); if let ty::FnDef(def_id, _) = fn_ty.sty { // some intrinsics are waved through if called inside the @@ -323,7 +325,12 @@ fn check_terminator( abi::Abi::Rust if tcx.is_min_const_fn(def_id) => {}, abi::Abi::Rust => return Err(( span, - "can only call other `min_const_fn` within a `min_const_fn`".into(), + format!( + "can only call other `const fn` within a `const fn`, \ + but `{:?}` is not stable as `const fn`", + func, + ) + .into(), )), abi => return Err(( span, @@ -334,10 +341,10 @@ fn check_terminator( )), } - check_operand(tcx, mir, func, span)?; + check_operand(func, span)?; for arg in args { - check_operand(tcx, mir, arg, span)?; + check_operand(arg, span)?; } Ok(()) } else { @@ -351,7 +358,7 @@ fn check_terminator( msg: _, target: _, cleanup: _, - } => check_operand(tcx, mir, cond, span), + } => check_operand(cond, span), TerminatorKind::FalseUnwind { .. } => { Err((span, "loops are not allowed in const fn".into())) @@ -363,7 +370,7 @@ fn check_terminator( /// for being called from stable `const fn`s (`min_const_fn`). /// /// Adding more intrinsics requires sign-off from @rust-lang/lang. -fn is_intrinsic_whitelisted(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { +fn is_intrinsic_whitelisted(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { match &tcx.item_name(def_id).as_str()[..] { | "size_of" | "min_align_of" diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index b7493b25d4650..7b3cdc835ebb1 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -9,24 +9,18 @@ use crate::util::patch::MirPatch; /// code for these. pub struct RemoveNoopLandingPads; -pub fn remove_noop_landing_pads<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &mut Mir<'tcx>) -{ +pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { if tcx.sess.no_landing_pads() { return } - debug!("remove_noop_landing_pads({:?})", mir); + debug!("remove_noop_landing_pads({:?})", body); - RemoveNoopLandingPads.remove_nop_landing_pads(mir) + RemoveNoopLandingPads.remove_nop_landing_pads(body) } impl MirPass for RemoveNoopLandingPads { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _src: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { - remove_noop_landing_pads(tcx, mir); + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + remove_noop_landing_pads(tcx, body); } } @@ -34,10 +28,10 @@ impl RemoveNoopLandingPads { fn is_nop_landing_pad( &self, bb: BasicBlock, - mir: &Mir<'_>, + body: &Body<'_>, nop_landing_pads: &BitSet, ) -> bool { - for stmt in &mir[bb].statements { + for stmt in &body[bb].statements { match stmt.kind { StatementKind::FakeRead(..) | StatementKind::StorageLive(_) | @@ -61,7 +55,7 @@ impl RemoveNoopLandingPads { } } - let terminator = mir[bb].terminator(); + let terminator = body[bb].terminator(); match terminator.kind { TerminatorKind::Goto { .. } | TerminatorKind::Resume | @@ -86,26 +80,26 @@ impl RemoveNoopLandingPads { } } - fn remove_nop_landing_pads(&self, mir: &mut Mir<'_>) { + fn remove_nop_landing_pads(&self, body: &mut Body<'_>) { // make sure there's a single resume block let resume_block = { - let patch = MirPatch::new(mir); + let patch = MirPatch::new(body); let resume_block = patch.resume_block(); - patch.apply(mir); + patch.apply(body); resume_block }; debug!("remove_noop_landing_pads: resume block is {:?}", resume_block); let mut jumps_folded = 0; let mut landing_pads_removed = 0; - let mut nop_landing_pads = BitSet::new_empty(mir.basic_blocks().len()); + let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks().len()); // This is a post-order traversal, so that if A post-dominates B // then A will be visited before B. - let postorder: Vec<_> = traversal::postorder(mir).map(|(bb, _)| bb).collect(); + let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect(); for bb in postorder { debug!(" processing {:?}", bb); - for target in mir[bb].terminator_mut().successors_mut() { + for target in body[bb].terminator_mut().successors_mut() { if *target != resume_block && nop_landing_pads.contains(*target) { debug!(" folding noop jump to {:?} to resume block", target); *target = resume_block; @@ -113,7 +107,7 @@ impl RemoveNoopLandingPads { } } - match mir[bb].terminator_mut().unwind_mut() { + match body[bb].terminator_mut().unwind_mut() { Some(unwind) => { if *unwind == Some(resume_block) { debug!(" removing noop landing pad"); @@ -125,7 +119,7 @@ impl RemoveNoopLandingPads { _ => {} } - let is_nop_landing_pad = self.is_nop_landing_pad(bb, mir, &nop_landing_pads); + let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads); if is_nop_landing_pad { nop_landing_pads.insert(bb); } diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index a44ec526f9ddc..f12309c1d0a13 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -1,9 +1,11 @@ use rustc_target::spec::abi::{Abi}; use syntax::ast; +use syntax::symbol::sym; use syntax_pos::Span; use rustc::ty::{self, TyCtxt}; -use rustc::mir::{self, Mir, Location}; +use rustc::hir::def_id::DefId; +use rustc::mir::{self, Body, Location}; use rustc_data_structures::bit_set::BitSet; use crate::transform::{MirPass, MirSource}; @@ -16,52 +18,49 @@ use crate::dataflow::{ }; use crate::dataflow::move_paths::{MovePathIndex, LookupResult}; use crate::dataflow::move_paths::{HasMoveData, MoveData}; -use crate::dataflow; use crate::dataflow::has_rustc_mir_with; pub struct SanityCheck; impl MirPass for SanityCheck { - fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource<'tcx>, mir: &mut Mir<'tcx>) { + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { let def_id = src.def_id(); - let id = tcx.hir().as_local_node_id(def_id).unwrap(); - if !tcx.has_attr(def_id, "rustc_mir") { - debug!("skipping rustc_peek::SanityCheck on {}", tcx.item_path_str(def_id)); + if !tcx.has_attr(def_id, sym::rustc_mir) { + debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); return; } else { - debug!("running rustc_peek::SanityCheck on {}", tcx.item_path_str(def_id)); + debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); } let attributes = tcx.get_attrs(def_id); let param_env = tcx.param_env(def_id); - let move_data = MoveData::gather_moves(mir, tcx).unwrap(); + let move_data = MoveData::gather_moves(body, tcx).unwrap(); let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; - let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len()); + let dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); let flow_inits = - do_dataflow(tcx, mir, id, &attributes, &dead_unwinds, - MaybeInitializedPlaces::new(tcx, mir, &mdpe), + do_dataflow(tcx, body, def_id, &attributes, &dead_unwinds, + MaybeInitializedPlaces::new(tcx, body, &mdpe), |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i])); let flow_uninits = - do_dataflow(tcx, mir, id, &attributes, &dead_unwinds, - MaybeUninitializedPlaces::new(tcx, mir, &mdpe), + do_dataflow(tcx, body, def_id, &attributes, &dead_unwinds, + MaybeUninitializedPlaces::new(tcx, body, &mdpe), |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i])); let flow_def_inits = - do_dataflow(tcx, mir, id, &attributes, &dead_unwinds, - DefinitelyInitializedPlaces::new(tcx, mir, &mdpe), + do_dataflow(tcx, body, def_id, &attributes, &dead_unwinds, + DefinitelyInitializedPlaces::new(tcx, body, &mdpe), |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i])); - if has_rustc_mir_with(&attributes, "rustc_peek_maybe_init").is_some() { - sanity_check_via_rustc_peek(tcx, mir, id, &attributes, &flow_inits); + if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_init).is_some() { + sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_inits); } - if has_rustc_mir_with(&attributes, "rustc_peek_maybe_uninit").is_some() { - sanity_check_via_rustc_peek(tcx, mir, id, &attributes, &flow_uninits); + if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_uninit).is_some() { + sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_uninits); } - if has_rustc_mir_with(&attributes, "rustc_peek_definite_init").is_some() { - sanity_check_via_rustc_peek(tcx, mir, id, &attributes, &flow_def_inits); + if has_rustc_mir_with(&attributes, sym::rustc_peek_definite_init).is_some() { + sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_def_inits); } - if has_rustc_mir_with(&attributes, "stop_after_dataflow").is_some() { + if has_rustc_mir_with(&attributes, sym::stop_after_dataflow).is_some() { tcx.sess.fatal("stop_after_dataflow ended compilation"); } } @@ -83,31 +82,35 @@ impl MirPass for SanityCheck { /// (If there are any calls to `rustc_peek` that do not match the /// expression form above, then that emits an error as well, but those /// errors are not intended to be used for unit tests.) -pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &Mir<'tcx>, - id: ast::NodeId, - _attributes: &[ast::Attribute], - results: &DataflowResults<'tcx, O>) - where O: BitDenotation<'tcx, Idx=MovePathIndex> + HasMoveData<'tcx> +pub fn sanity_check_via_rustc_peek<'tcx, O>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + def_id: DefId, + _attributes: &[ast::Attribute], + results: &DataflowResults<'tcx, O>, +) where + O: BitDenotation<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>, { - debug!("sanity_check_via_rustc_peek id: {:?}", id); + debug!("sanity_check_via_rustc_peek def_id: {:?}", def_id); // FIXME: this is not DRY. Figure out way to abstract this and // `dataflow::build_sets`. (But note it is doing non-standard // stuff, so such generalization may not be realistic.) - for bb in mir.basic_blocks().indices() { - each_block(tcx, mir, results, bb); + for bb in body.basic_blocks().indices() { + each_block(tcx, body, results, bb); } } -fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &Mir<'tcx>, - results: &DataflowResults<'tcx, O>, - bb: mir::BasicBlock) where - O: BitDenotation<'tcx, Idx=MovePathIndex> + HasMoveData<'tcx> +fn each_block<'tcx, O>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + results: &DataflowResults<'tcx, O>, + bb: mir::BasicBlock, +) where + O: BitDenotation<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>, { let move_data = results.0.operator.move_data(); - let mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = mir[bb]; + let mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = body[bb]; let (args, span) = match is_rustc_peek(tcx, terminator) { Some(args_and_span) => args_and_span, @@ -129,9 +132,8 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }; - let mut on_entry = results.0.sets.on_entry_set_for(bb.index()).to_owned(); - let mut gen_set = results.0.sets.gen_set_for(bb.index()).clone(); - let mut kill_set = results.0.sets.kill_set_for(bb.index()).clone(); + let mut on_entry = results.0.sets.entry_set_for(bb.index()).to_owned(); + let mut trans = results.0.sets.trans_for(bb.index()).clone(); // Emulate effect of all statements in the block up to (but not // including) the borrow within `peek_arg_place`. Do *not* include @@ -139,10 +141,6 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // of the argument at time immediate preceding Call to // `rustc_peek`). - let mut sets = dataflow::BlockSets { on_entry: &mut on_entry, - gen_set: &mut gen_set, - kill_set: &mut kill_set }; - for (j, stmt) in statements.iter().enumerate() { debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt); let (place, rvalue) = match stmt.kind { @@ -166,7 +164,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Okay, our search is over. match move_data.rev_lookup.find(peeking_at_place) { LookupResult::Exact(peek_mpi) => { - let bit_state = sets.on_entry.contains(peek_mpi); + let bit_state = on_entry.contains(peek_mpi); debug!("rustc_peek({:?} = &{:?}) bit_state: {}", place, peeking_at_place, bit_state); if !bit_state { @@ -193,18 +191,18 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("rustc_peek: computing effect on place: {:?} ({:?}) in stmt: {:?}", place, lhs_mpi, stmt); // reset GEN and KILL sets before emulating their effect. - sets.gen_set.clear(); - sets.kill_set.clear(); + trans.clear(); results.0.operator.before_statement_effect( - &mut sets, Location { block: bb, statement_index: j }); + &mut trans, + Location { block: bb, statement_index: j }); results.0.operator.statement_effect( - &mut sets, Location { block: bb, statement_index: j }); - sets.on_entry.union(sets.gen_set); - sets.on_entry.subtract(sets.kill_set); + &mut trans, + Location { block: bb, statement_index: j }); + trans.apply(&mut on_entry); } results.0.operator.before_terminator_effect( - &mut sets, + &mut trans, Location { block: bb, statement_index: statements.len() }); tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \ @@ -213,16 +211,17 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, form `&expr`")); } -fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - terminator: &'a Option>) - -> Option<(&'a [mir::Operand<'tcx>], Span)> { +fn is_rustc_peek<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + terminator: &'a Option>, +) -> Option<(&'a [mir::Operand<'tcx>], Span)> { if let Some(mir::Terminator { ref kind, source_info, .. }) = *terminator { if let mir::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind { if let mir::Operand::Constant(ref func) = *oper { if let ty::FnDef(def_id, _) = func.ty.sty { let abi = tcx.fn_sig(def_id).abi(); let name = tcx.item_name(def_id); - if abi == Abi::RustIntrinsic && name == "rustc_peek" { + if abi == Abi::RustIntrinsic && name == sym::rustc_peek { return Some((args, source_info.span)); } } diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 14e7895af0419..f226f15c0096f 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -44,12 +44,12 @@ impl SimplifyCfg { } } -pub fn simplify_cfg(mir: &mut Mir<'_>) { - CfgSimplifier::new(mir).simplify(); - remove_dead_blocks(mir); +pub fn simplify_cfg(body: &mut Body<'_>) { + CfgSimplifier::new(body).simplify(); + remove_dead_blocks(body); // FIXME: Should probably be moved into some kind of pass manager - mir.basic_blocks_mut().raw.shrink_to_fit(); + body.basic_blocks_mut().raw.shrink_to_fit(); } impl MirPass for SimplifyCfg { @@ -57,29 +57,26 @@ impl MirPass for SimplifyCfg { Cow::Borrowed(&self.label) } - fn run_pass<'a, 'tcx>(&self, - _tcx: TyCtxt<'a, 'tcx, 'tcx>, - _src: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { - debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, mir); - simplify_cfg(mir); + fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body); + simplify_cfg(body); } } -pub struct CfgSimplifier<'a, 'tcx: 'a> { +pub struct CfgSimplifier<'a, 'tcx> { basic_blocks: &'a mut IndexVec>, pred_count: IndexVec } -impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { - pub fn new(mir: &'a mut Mir<'tcx>) -> Self { - let mut pred_count = IndexVec::from_elem(0u32, mir.basic_blocks()); +impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { + pub fn new(body: &'a mut Body<'tcx>) -> Self { + let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks()); // we can't use mir.predecessors() here because that counts // dead blocks, which we don't want to. pred_count[START_BLOCK] = 1; - for (_, data) in traversal::preorder(mir) { + for (_, data) in traversal::preorder(body) { if let Some(ref term) = data.terminator { for &tgt in term.successors() { pred_count[tgt] += 1; @@ -87,7 +84,7 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { } } - let basic_blocks = mir.basic_blocks_mut(); + let basic_blocks = body.basic_blocks_mut(); CfgSimplifier { basic_blocks, @@ -263,13 +260,13 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { } } -pub fn remove_dead_blocks(mir: &mut Mir<'_>) { - let mut seen = BitSet::new_empty(mir.basic_blocks().len()); - for (bb, _) in traversal::preorder(mir) { +pub fn remove_dead_blocks(body: &mut Body<'_>) { + let mut seen = BitSet::new_empty(body.basic_blocks().len()); + for (bb, _) in traversal::preorder(body) { seen.insert(bb.index()); } - let basic_blocks = mir.basic_blocks_mut(); + let basic_blocks = body.basic_blocks_mut(); let num_blocks = basic_blocks.len(); let mut replacements : Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); @@ -296,34 +293,31 @@ pub fn remove_dead_blocks(mir: &mut Mir<'_>) { pub struct SimplifyLocals; impl MirPass for SimplifyLocals { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { - let mut marker = DeclMarker { locals: BitSet::new_empty(mir.local_decls.len()) }; - marker.visit_mir(mir); + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { + let mut marker = DeclMarker { locals: BitSet::new_empty(body.local_decls.len()) }; + marker.visit_body(body); // Return pointer and arguments are always live marker.locals.insert(RETURN_PLACE); - for arg in mir.args_iter() { + for arg in body.args_iter() { marker.locals.insert(arg); } // We may need to keep dead user variables live for debuginfo. if tcx.sess.opts.debuginfo == DebugInfo::Full { - for local in mir.vars_iter() { + for local in body.vars_iter() { marker.locals.insert(local); } } - let map = make_local_map(&mut mir.local_decls, marker.locals); + let map = make_local_map(&mut body.local_decls, marker.locals); // Update references to all vars and tmps now - LocalUpdater { map }.visit_mir(mir); - mir.local_decls.shrink_to_fit(); + LocalUpdater { map }.visit_body(body); + body.local_decls.shrink_to_fit(); } } /// Construct the mapping while swapping out unused stuff out from the `vec`. -fn make_local_map<'tcx, V>( +fn make_local_map( vec: &mut IndexVec, mask: BitSet, ) -> IndexVec> { @@ -345,7 +339,7 @@ struct DeclMarker { } impl<'tcx> Visitor<'tcx> for DeclMarker { - fn visit_local(&mut self, local: &Local, ctx: PlaceContext<'tcx>, _: Location) { + fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) { // Ignore storage markers altogether, they get removed along with their otherwise unused // decls. // FIXME: Extend this to all non-uses. @@ -372,7 +366,7 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater { }); self.super_basic_block_data(block, data); } - fn visit_local(&mut self, l: &mut Local, _: PlaceContext<'tcx>, _: Location) { + fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { *l = self.map[*l].unwrap(); } } diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 3c4d1227a691c..0c63a8d9c96b1 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -19,18 +19,15 @@ impl MirPass for SimplifyBranches { Cow::Borrowed(&self.label) } - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _src: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { - for block in mir.basic_blocks_mut() { + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + for block in body.basic_blocks_mut() { let terminator = block.terminator_mut(); terminator.kind = match terminator.kind { TerminatorKind::SwitchInt { discr: Operand::Constant(ref c), switch_ty, ref values, ref targets, .. } => { let switch_ty = ParamEnv::empty().and(switch_ty); - let constant = c.literal.map_evaluated(|c| c.assert_bits(tcx, switch_ty)); + let constant = c.literal.assert_bits(tcx, switch_ty); if let Some(constant) = constant { let (otherwise, targets) = targets.split_last().unwrap(); let mut ret = TerminatorKind::Goto { target: *otherwise }; @@ -47,7 +44,7 @@ impl MirPass for SimplifyBranches { }, TerminatorKind::Assert { target, cond: Operand::Constant(ref c), expected, .. - } if (c.literal.map_evaluated(|e| e.assert_bool(tcx)) == Some(true)) == expected => + } if (c.literal.assert_bool(tcx) == Some(true)) == expected => TerminatorKind::Goto { target }, TerminatorKind::FalseEdges { real_target, .. } => { TerminatorKind::Goto { target: real_target } diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index b1d898bb5b026..6878eceb2a5db 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -37,28 +37,24 @@ use crate::util::patch::MirPatch; pub struct UniformArrayMoveOut; impl MirPass for UniformArrayMoveOut { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _src: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { - let mut patch = MirPatch::new(mir); + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + let mut patch = MirPatch::new(body); { - let mut visitor = UniformArrayMoveOutVisitor{mir, patch: &mut patch, tcx}; - visitor.visit_mir(mir); + let mut visitor = UniformArrayMoveOutVisitor{body, patch: &mut patch, tcx}; + visitor.visit_body(body); } - patch.apply(mir); + patch.apply(body); } } -struct UniformArrayMoveOutVisitor<'a, 'tcx: 'a> { - mir: &'a Mir<'tcx>, +struct UniformArrayMoveOutVisitor<'a, 'tcx> { + body: &'a Body<'tcx>, patch: &'a mut MirPatch<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, } impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { fn visit_assign(&mut self, - block: BasicBlock, dst_place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { @@ -69,7 +65,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { from_end: false} = proj.elem { // no need to transformation } else { - let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let place_ty = proj.base.ty(self.body, self.tcx).ty; if let ty::Array(item_ty, const_size) = place_ty.sty { if let Some(size) = const_size.assert_usize(self.tcx) { assert!(size <= u32::max_value() as u64, @@ -82,7 +78,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { } } } - self.super_assign(block, dst_place, rvalue, location) + self.super_assign(dst_place, rvalue, location) } } @@ -90,7 +86,7 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { fn uniform(&mut self, location: Location, dst_place: &Place<'tcx>, - proj: &PlaceProjection<'tcx>, + proj: &Projection<'tcx>, item_ty: &'tcx ty::TyS<'tcx>, size: u32) { match proj.elem { @@ -98,13 +94,13 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { ProjectionElem::Subslice{from, to} => { self.patch.make_nop(location); let temps : Vec<_> = (from..(size-to)).map(|i| { - let temp = self.patch.new_temp(item_ty, self.mir.source_info(location).span); + let temp = self.patch.new_temp(item_ty, self.body.source_info(location).span); self.patch.add_statement(location, StatementKind::StorageLive(temp)); self.patch.add_assign(location, - Place::Base(PlaceBase::Local(temp)), + Place::from(temp), Rvalue::Use( Operand::Move( - Place::Projection(box PlaceProjection{ + Place::Projection(box Projection{ base: proj.base.clone(), elem: ProjectionElem::ConstantIndex{ offset: i, @@ -119,7 +115,7 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { Rvalue::Aggregate( box AggregateKind::Array(item_ty), temps.iter().map( - |x| Operand::Move(Place::Base(PlaceBase::Local(*x))) + |x| Operand::Move(Place::from(*x)) ).collect() ) ); @@ -134,7 +130,7 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { dst_place.clone(), Rvalue::Use( Operand::Move( - Place::Projection(box PlaceProjection{ + Place::Projection(box Projection{ base: proj.base.clone(), elem: ProjectionElem::ConstantIndex{ offset: size - offset, @@ -163,26 +159,24 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { pub struct RestoreSubsliceArrayMoveOut; impl MirPass for RestoreSubsliceArrayMoveOut { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _src: MirSource<'tcx>, - mir: &mut Mir<'tcx>) { - let mut patch = MirPatch::new(mir); + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + let mut patch = MirPatch::new(body); { let mut visitor = RestoreDataCollector { - locals_use: IndexVec::from_elem(LocalUse::new(), &mir.local_decls), + locals_use: IndexVec::from_elem(LocalUse::new(), &body.local_decls), candidates: vec![], }; - visitor.visit_mir(mir); + visitor.visit_body(body); for candidate in &visitor.candidates { - let statement = &mir[candidate.block].statements[candidate.statement_index]; + let statement = &body[candidate.block].statements[candidate.statement_index]; if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind { if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = **rval { let items : Vec<_> = items.iter().map(|item| { if let Operand::Move(Place::Base(PlaceBase::Local(local))) = item { let local_use = &visitor.locals_use[*local]; - let opt_index_and_place = Self::try_get_item_source(local_use, mir); + let opt_index_and_place = + Self::try_get_item_source(local_use, body); // each local should be used twice: // in assign and in aggregate statements if local_use.use_count == 2 && opt_index_and_place.is_some() { @@ -195,7 +189,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut { let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2); let opt_size = opt_src_place.and_then(|src_place| { - let src_ty = src_place.ty(mir, tcx).to_ty(tcx); + let src_ty = src_place.ty(body, tcx).ty; if let ty::Array(_, ref size_o) = src_ty.sty { size_o.assert_usize(tcx) } else { @@ -207,7 +201,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut { } } } - patch.apply(mir); + patch.apply(body); } } @@ -247,7 +241,7 @@ impl RestoreSubsliceArrayMoveOut { dst_place.clone(), Rvalue::Use( Operand::Move( - Place::Projection(box PlaceProjection{ + Place::Projection(box Projection{ base: opt_src_place.unwrap().clone(), elem: ProjectionElem::Subslice{ from: min, to: size - max - 1}})))); @@ -255,14 +249,14 @@ impl RestoreSubsliceArrayMoveOut { } fn try_get_item_source<'a, 'tcx>(local_use: &LocalUse, - mir: &'a Mir<'tcx>) -> Option<(u32, &'a Place<'tcx>)> { + body: &'a Body<'tcx>) -> Option<(u32, &'a Place<'tcx>)> { if let Some(location) = local_use.first_use { - let block = &mir[location.block]; + let block = &body[location.block]; if block.statements.len() > location.statement_index { let statement = &block.statements[location.statement_index]; if let StatementKind::Assign( Place::Base(PlaceBase::Local(_)), - box Rvalue::Use(Operand::Move(Place::Projection(box PlaceProjection{ + box Rvalue::Use(Operand::Move(Place::Projection(box Projection{ ref base, elem: ProjectionElem::ConstantIndex{ offset, min_length: _, from_end: false}})))) = statement.kind { return Some((offset, base)) @@ -294,19 +288,18 @@ struct RestoreDataCollector { impl<'tcx> Visitor<'tcx> for RestoreDataCollector { fn visit_assign(&mut self, - block: BasicBlock, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Aggregate(box AggregateKind::Array(_), _) = *rvalue { self.candidates.push(location); } - self.super_assign(block, place, rvalue, location) + self.super_assign(place, rvalue, location) } fn visit_local(&mut self, local: &Local, - context: PlaceContext<'tcx>, + context: PlaceContext, location: Location) { let local_use = &mut self.locals_use[*local]; match context { diff --git a/src/librustc_mir/util/aggregate.rs b/src/librustc_mir/util/aggregate.rs new file mode 100644 index 0000000000000..98e70671ab715 --- /dev/null +++ b/src/librustc_mir/util/aggregate.rs @@ -0,0 +1,76 @@ +use rustc::mir::*; +use rustc::ty::Ty; +use rustc::ty::layout::VariantIdx; +use rustc_data_structures::indexed_vec::Idx; + +use std::iter::TrustedLen; + +/// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields. +/// +/// Produces something like +/// +/// (lhs as Variant).field0 = arg0; // We only have a downcast if this is an enum +/// (lhs as Variant).field1 = arg1; +/// discriminant(lhs) = variant_index; // If lhs is an enum or generator. +pub fn expand_aggregate<'tcx>( + mut lhs: Place<'tcx>, + operands: impl Iterator, Ty<'tcx>)> + TrustedLen, + kind: AggregateKind<'tcx>, + source_info: SourceInfo, +) -> impl Iterator> + TrustedLen { + let mut set_discriminant = None; + let active_field_index = match kind { + AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { + if adt_def.is_enum() { + set_discriminant = Some(Statement { + kind: StatementKind::SetDiscriminant { + place: lhs.clone(), + variant_index, + }, + source_info, + }); + lhs = lhs.downcast(adt_def, variant_index); + } + active_field_index + } + AggregateKind::Generator(..) => { + // Right now we only support initializing generators to + // variant 0 (Unresumed). + let variant_index = VariantIdx::new(0); + set_discriminant = Some(Statement { + kind: StatementKind::SetDiscriminant { + place: lhs.clone(), + variant_index, + }, + source_info, + }); + + // Operands are upvars stored on the base place, so no + // downcast is necessary. + + None + } + _ => None + }; + + operands.into_iter().enumerate().map(move |(i, (op, ty))| { + let lhs_field = if let AggregateKind::Array(_) = kind { + // FIXME(eddyb) `offset` should be u64. + let offset = i as u32; + assert_eq!(offset as usize, i); + lhs.clone().elem(ProjectionElem::ConstantIndex { + offset, + // FIXME(eddyb) `min_length` doesn't appear to be used. + min_length: offset + 1, + from_end: false + }) + } else { + let field = Field::new(active_field_index.unwrap_or(i)); + lhs.clone().field(field, ty) + }; + Statement { + source_info, + kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)), + } + }).chain(set_discriminant) +} diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs index 7be34d001df07..6245d9c208b69 100644 --- a/src/librustc_mir/util/alignment.rs +++ b/src/librustc_mir/util/alignment.rs @@ -4,12 +4,14 @@ use rustc::mir::*; /// Returns `true` if this place is allowed to be less aligned /// than its containing struct (because it is within a packed /// struct). -pub fn is_disaligned<'a, 'tcx, L>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - local_decls: &L, - param_env: ty::ParamEnv<'tcx>, - place: &Place<'tcx>) - -> bool - where L: HasLocalDecls<'tcx> +pub fn is_disaligned<'tcx, L>( + tcx: TyCtxt<'tcx>, + local_decls: &L, + param_env: ty::ParamEnv<'tcx>, + place: &Place<'tcx>, +) -> bool +where + L: HasLocalDecls<'tcx>, { debug!("is_disaligned({:?})", place); if !is_within_packed(tcx, local_decls, place) { @@ -17,7 +19,7 @@ pub fn is_disaligned<'a, 'tcx, L>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return false } - let ty = place.ty(local_decls, tcx).to_ty(tcx); + let ty = place.ty(local_decls, tcx).ty; match tcx.layout_raw(param_env.and(ty)) { Ok(layout) if layout.align.abi.bytes() == 1 => { // if the alignment is 1, the type can't be further @@ -32,11 +34,9 @@ pub fn is_disaligned<'a, 'tcx, L>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn is_within_packed<'a, 'tcx, L>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - local_decls: &L, - place: &Place<'tcx>) - -> bool - where L: HasLocalDecls<'tcx> +fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<'tcx>) -> bool +where + L: HasLocalDecls<'tcx>, { let mut place = place; while let &Place::Projection(box Projection { @@ -46,7 +46,7 @@ fn is_within_packed<'a, 'tcx, L>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // encountered a Deref, which is ABI-aligned ProjectionElem::Deref => break, ProjectionElem::Field(..) => { - let ty = base.ty(local_decls, tcx).to_ty(tcx); + let ty = base.ty(local_decls, tcx).ty; match ty.sty { ty::Adt(def, _) if def.repr.packed() => { return true diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index fd694ddbbd19f..f1aaa857dd3f3 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -1,5 +1,5 @@ use rustc::session::config::BorrowckMode; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; use syntax_pos::{MultiSpan, Span}; @@ -12,26 +12,10 @@ pub enum Origin { } impl fmt::Display for Origin { - fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { - // If the user passed `-Z borrowck=compare`, then include - // origin info as part of the error report, - // otherwise - let display_origin = ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - tcx.sess.opts.borrowck_mode == BorrowckMode::Compare - } else { - false - } - }); - if display_origin { - match *self { - Origin::Mir => write!(w, " (Mir)"), - Origin::Ast => write!(w, " (Ast)"), - } - } else { - // Print no origin info - Ok(()) - } + fn fmt(&self, _w: &mut fmt::Formatter<'_>) -> fmt::Result { + // FIXME(chrisvittal) remove Origin entirely + // Print no origin info + Ok(()) } } @@ -40,7 +24,7 @@ impl Origin { pub fn should_emit_errors(self, mode: BorrowckMode) -> bool { match self { Origin::Ast => mode.use_ast(), - Origin::Mir => mode.use_mir(), + Origin::Mir => true, } } } @@ -415,7 +399,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { move_from_desc: &str, o: Origin, ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( + let err = struct_span_err!( self, move_from_span, E0507, @@ -423,10 +407,6 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { move_from_desc, OGN = o ); - err.span_label( - move_from_span, - format!("cannot move out of {}", move_from_desc), - ); self.cancel_if_wrong_origin(err, o) } @@ -437,7 +417,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { fn cannot_move_out_of_interior_noncopy( self, move_from_span: Span, - ty: ty::Ty<'_>, + ty: Ty<'_>, is_index: Option, o: Origin, ) -> DiagnosticBuilder<'cx> { @@ -450,8 +430,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { self, move_from_span, E0508, - "cannot move out of type `{}`, \ - a non-copy {}{OGN}", + "cannot move out of type `{}`, a non-copy {}{OGN}", ty, type_name, OGN = o @@ -464,15 +443,14 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { fn cannot_move_out_of_interior_of_drop( self, move_from_span: Span, - container_ty: ty::Ty<'_>, + container_ty: Ty<'_>, o: Origin, ) -> DiagnosticBuilder<'cx> { let mut err = struct_span_err!( self, move_from_span, E0509, - "cannot move out of type `{}`, \ - which implements the `Drop` trait{OGN}", + "cannot move out of type `{}`, which implements the `Drop` trait{OGN}", container_ty, OGN = o ); @@ -650,6 +628,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { fn cannot_return_reference_to_local( self, span: Span, + return_kind: &str, reference_desc: &str, path_desc: &str, o: Origin, @@ -658,7 +637,8 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { self, span, E0515, - "cannot return {REFERENCE} {LOCAL}{OGN}", + "cannot {RETURN} {REFERENCE} {LOCAL}{OGN}", + RETURN=return_kind, REFERENCE=reference_desc, LOCAL=path_desc, OGN = o @@ -666,7 +646,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { err.span_label( span, - format!("returns a {} data owned by the current function", reference_desc), + format!("{}s a {} data owned by the current function", return_kind, reference_desc), ); self.cancel_if_wrong_origin(err, o) @@ -808,25 +788,25 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { } } -impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> { +impl BorrowckErrors<'tcx> for TyCtxt<'tcx> { fn struct_span_err_with_code>( self, sp: S, msg: &str, code: DiagnosticId, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { self.sess.struct_span_err_with_code(sp, msg, code) } - fn struct_span_err>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx> { + fn struct_span_err>(self, sp: S, msg: &str) -> DiagnosticBuilder<'tcx> { self.sess.struct_span_err(sp, msg) } fn cancel_if_wrong_origin( self, - mut diag: DiagnosticBuilder<'cx>, + mut diag: DiagnosticBuilder<'tcx>, o: Origin, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { if !o.should_emit_errors(self.borrowck_mode()) { self.sess.diagnostic().cancel(&mut diag); } diff --git a/src/librustc_mir/util/collect_writes.rs b/src/librustc_mir/util/collect_writes.rs index fd94c49dd1d4a..c8804dfbaf261 100644 --- a/src/librustc_mir/util/collect_writes.rs +++ b/src/librustc_mir/util/collect_writes.rs @@ -1,5 +1,5 @@ use rustc::mir::{Local, Location}; -use rustc::mir::Mir; +use rustc::mir::Body; use rustc::mir::visit::PlaceContext; use rustc::mir::visit::Visitor; @@ -9,10 +9,10 @@ crate trait FindAssignments { fn find_assignments(&self, local: Local) -> Vec; } -impl<'tcx> FindAssignments for Mir<'tcx>{ +impl<'tcx> FindAssignments for Body<'tcx>{ fn find_assignments(&self, local: Local) -> Vec{ let mut visitor = FindLocalAssignmentVisitor{ needle: local, locations: vec![]}; - visitor.visit_mir(self); + visitor.visit_body(self); visitor.locations } } @@ -27,7 +27,7 @@ struct FindLocalAssignmentVisitor { impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor { fn visit_local(&mut self, local: &Local, - place_context: PlaceContext<'tcx>, + place_context: PlaceContext, location: Location) { if self.needle != *local { return; diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs index 2e41c6e493bc3..fac752dbf023e 100644 --- a/src/librustc_mir/util/def_use.rs +++ b/src/librustc_mir/util/def_use.rs @@ -1,42 +1,39 @@ //! Def-use analysis. -use rustc::mir::{Local, Location, Mir}; +use rustc::mir::{Local, Location, Body}; use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor}; use rustc_data_structures::indexed_vec::IndexVec; -use std::marker::PhantomData; use std::mem; -use std::slice; -use std::iter; -pub struct DefUseAnalysis<'tcx> { - info: IndexVec>, +pub struct DefUseAnalysis { + info: IndexVec, } #[derive(Clone)] -pub struct Info<'tcx> { - pub defs_and_uses: Vec>, +pub struct Info { + pub defs_and_uses: Vec, } #[derive(Clone)] -pub struct Use<'tcx> { - pub context: PlaceContext<'tcx>, +pub struct Use { + pub context: PlaceContext, pub location: Location, } -impl<'tcx> DefUseAnalysis<'tcx> { - pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> { +impl DefUseAnalysis { + pub fn new(body: &Body<'_>) -> DefUseAnalysis { DefUseAnalysis { - info: IndexVec::from_elem_n(Info::new(), mir.local_decls.len()), + info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()), } } - pub fn analyze(&mut self, mir: &Mir<'tcx>) { + pub fn analyze(&mut self, body: &Body<'_>) { self.clear(); let mut finder = DefUseFinder { info: mem::replace(&mut self.info, IndexVec::new()), }; - finder.visit_mir(mir); + finder.visit_body(body); self.info = finder.info } @@ -46,38 +43,38 @@ impl<'tcx> DefUseAnalysis<'tcx> { } } - pub fn local_info(&self, local: Local) -> &Info<'tcx> { + pub fn local_info(&self, local: Local) -> &Info { &self.info[local] } - fn mutate_defs_and_uses(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F) + fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, mut callback: F) where F: for<'a> FnMut(&'a mut Local, - PlaceContext<'tcx>, + PlaceContext, Location) { for place_use in &self.info[local].defs_and_uses { MutateUseVisitor::new(local, &mut callback, - mir).visit_location(mir, place_use.location) + body).visit_location(body, place_use.location) } } // FIXME(pcwalton): this should update the def-use chains. pub fn replace_all_defs_and_uses_with(&self, local: Local, - mir: &mut Mir<'tcx>, + body: &mut Body<'_>, new_local: Local) { - self.mutate_defs_and_uses(local, mir, |local, _, _| *local = new_local) + self.mutate_defs_and_uses(local, body, |local, _, _| *local = new_local) } } -struct DefUseFinder<'tcx> { - info: IndexVec>, +struct DefUseFinder { + info: IndexVec, } -impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> { +impl Visitor<'_> for DefUseFinder { fn visit_local(&mut self, &local: &Local, - context: PlaceContext<'tcx>, + context: PlaceContext, location: Location) { self.info[local].defs_and_uses.push(Use { context, @@ -86,8 +83,8 @@ impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> { } } -impl<'tcx> Info<'tcx> { - fn new() -> Info<'tcx> { +impl Info { + fn new() -> Info { Info { defs_and_uses: vec![], } @@ -107,7 +104,7 @@ impl<'tcx> Info<'tcx> { pub fn defs_not_including_drop( &self, - ) -> iter::Filter>, fn(&&Use<'tcx>) -> bool> { + ) -> impl Iterator { self.defs_and_uses.iter().filter(|place_use| { place_use.context.is_mutating_use() && !place_use.context.is_drop() }) @@ -120,29 +117,27 @@ impl<'tcx> Info<'tcx> { } } -struct MutateUseVisitor<'tcx, F> { +struct MutateUseVisitor { query: Local, callback: F, - phantom: PhantomData<&'tcx ()>, } -impl<'tcx, F> MutateUseVisitor<'tcx, F> { - fn new(query: Local, callback: F, _: &Mir<'tcx>) - -> MutateUseVisitor<'tcx, F> - where F: for<'a> FnMut(&'a mut Local, PlaceContext<'tcx>, Location) { +impl MutateUseVisitor { + fn new(query: Local, callback: F, _: &Body<'_>) + -> MutateUseVisitor + where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) { MutateUseVisitor { query, callback, - phantom: PhantomData, } } } -impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F> - where F: for<'a> FnMut(&'a mut Local, PlaceContext<'tcx>, Location) { +impl MutVisitor<'_> for MutateUseVisitor + where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) { fn visit_local(&mut self, local: &mut Local, - context: PlaceContext<'tcx>, + context: PlaceContext, location: Location) { if *local == self.query { (self.callback)(local, context, location) diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 26fa8d6d1f0bf..dac90d37275b4 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -10,7 +10,7 @@ use rustc::ty::util::IntTypeExt; use rustc_data_structures::indexed_vec::Idx; use crate::util::patch::MirPatch; -use std::u32; +use std::convert::TryInto; #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum DropFlagState { @@ -70,12 +70,12 @@ impl Unwind { } } -pub trait DropElaborator<'a, 'tcx: 'a> : fmt::Debug { +pub trait DropElaborator<'a, 'tcx>: fmt::Debug { type Path : Copy + fmt::Debug; fn patch(&mut self) -> &mut MirPatch<'tcx>; - fn mir(&self) -> &'a Mir<'tcx>; - fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>; + fn body(&self) -> &'a Body<'tcx>; + fn tcx(&self) -> TyCtxt<'tcx>; fn param_env(&self) -> ty::ParamEnv<'tcx>; fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle; @@ -90,8 +90,9 @@ pub trait DropElaborator<'a, 'tcx: 'a> : fmt::Debug { } #[derive(Debug)] -struct DropCtxt<'l, 'b: 'l, 'tcx: 'b, D> - where D : DropElaborator<'b, 'tcx> + 'l +struct DropCtxt<'l, 'b, 'tcx, D> +where + D: DropElaborator<'b, 'tcx>, { elaborator: &'l mut D, @@ -110,8 +111,10 @@ pub fn elaborate_drop<'b, 'tcx, D>( path: D::Path, succ: BasicBlock, unwind: Unwind, - bb: BasicBlock) - where D: DropElaborator<'b, 'tcx> + bb: BasicBlock, +) where + D: DropElaborator<'b, 'tcx>, + 'tcx: 'b, { DropCtxt { elaborator, source_info, place, path, succ, unwind @@ -119,13 +122,15 @@ pub fn elaborate_drop<'b, 'tcx, D>( } impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> - where D: DropElaborator<'b, 'tcx> +where + D: DropElaborator<'b, 'tcx>, + 'tcx: 'b, { fn place_ty(&self, place: &Place<'tcx>) -> Ty<'tcx> { - place.ty(self.elaborator.mir(), self.tcx()).to_ty(self.tcx()) + place.ty(self.elaborator.body(), self.tcx()).ty } - fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.elaborator.tcx() } @@ -147,7 +152,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> // // FIXME: I think we should just control the flags externally, // and then we do not need this machinery. - pub fn elaborate_drop<'a>(&mut self, bb: BasicBlock) { + pub fn elaborate_drop(&mut self, bb: BasicBlock) { debug!("elaborate_drop({:?})", self); let style = self.elaborator.drop_style(self.path, DropFlagMode::Deep); debug!("elaborate_drop({:?}): live - {:?}", self, style); @@ -285,12 +290,12 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> /// /// NOTE: this does not clear the master drop flag, so you need /// to point succ/unwind on a `drop_ladder_bottom`. - fn drop_ladder<'a>(&mut self, - fields: Vec<(Place<'tcx>, Option)>, - succ: BasicBlock, - unwind: Unwind) - -> (BasicBlock, Unwind) - { + fn drop_ladder( + &mut self, + fields: Vec<(Place<'tcx>, Option)>, + succ: BasicBlock, + unwind: Unwind, + ) -> (BasicBlock, Unwind) { debug!("drop_ladder({:?}, {:?})", self, fields); let mut fields = fields; @@ -314,9 +319,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> (*normal_ladder.last().unwrap(), *unwind_ladder.last().unwrap()) } - fn open_drop_for_tuple<'a>(&mut self, tys: &[Ty<'tcx>]) - -> BasicBlock - { + fn open_drop_for_tuple(&mut self, tys: &[Ty<'tcx>]) -> BasicBlock { debug!("open_drop_for_tuple({:?}, {:?})", self, tys); let fields = tys.iter().enumerate().map(|(i, &ty)| { @@ -328,9 +331,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.drop_ladder(fields, succ, unwind).0 } - fn open_drop_for_box<'a>(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) - -> BasicBlock - { + fn open_drop_for_box(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock { debug!("open_drop_for_box({:?}, {:?}, {:?})", self, adt, substs); let interior = self.place.clone().deref(); @@ -346,8 +347,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.drop_subpath(&interior, interior_path, succ, unwind_succ) } - fn open_drop_for_adt<'a>(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) - -> BasicBlock { + fn open_drop_for_adt(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock { debug!("open_drop_for_adt({:?}, {:?}, {:?})", self, adt, substs); if adt.variants.len() == 0 { return self.elaborator.patch().new_block(BasicBlockData { @@ -412,8 +412,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.path, variant_index); if let Some(variant_path) = subpath { let base_place = self.place.clone().elem( - ProjectionElem::Downcast(adt, variant_index) - ); + ProjectionElem::Downcast(Some(adt.variants[variant_index].ident.name), + variant_index)); let fields = self.move_paths_for_fields( &base_place, variant_path, @@ -486,7 +486,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> // discriminant after it is free-ed, because that // way lies only trouble. let discr_ty = adt.repr.discr_type().to_ty(self.tcx()); - let discr = Place::Base(PlaceBase::Local(self.new_temp(discr_ty))); + let discr = Place::from(self.new_temp(discr_ty)); let discr_rv = Rvalue::Discriminant(self.place.clone()); let switch_block = BasicBlockData { statements: vec![self.assign(&discr, discr_rv)], @@ -505,9 +505,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.drop_flag_test_block(switch_block, succ, unwind) } - fn destructor_call_block<'a>(&mut self, (succ, unwind): (BasicBlock, Unwind)) - -> BasicBlock - { + fn destructor_call_block(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> BasicBlock { debug!("destructor_call_block({:?}, {:?})", self, succ); let tcx = self.tcx(); let drop_trait = tcx.lang_items().drop_trait().unwrap(); @@ -515,17 +513,17 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let ty = self.place_ty(self.place); let substs = tcx.mk_substs_trait(ty, &[]); - let ref_ty = tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut { + let ref_ty = tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::MutMutable }); let ref_place = self.new_temp(ref_ty); - let unit_temp = Place::Base(PlaceBase::Local(self.new_temp(tcx.mk_unit()))); + let unit_temp = Place::from(self.new_temp(tcx.mk_unit())); let result = BasicBlockData { statements: vec![self.assign( - &Place::Base(PlaceBase::Local(ref_place)), - Rvalue::Ref(tcx.types.re_erased, + &Place::from(ref_place), + Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Mut { allow_two_phase_borrow: false }, self.place.clone()) )], @@ -533,7 +531,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> kind: TerminatorKind::Call { func: Operand::function_handle(tcx, drop_fn.def_id, substs, self.source_info.span), - args: vec![Operand::Move(Place::Base(PlaceBase::Local(ref_place)))], + args: vec![Operand::Move(Place::from(ref_place))], destination: Some((unit_temp, succ)), cleanup: unwind.into_option(), from_hir_call: true, @@ -545,10 +543,9 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.elaborator.patch().new_block(result) } - /// create a loop that drops an array: - /// - + /// Create a loop that drops an array: /// + /// ```text /// loop-block: /// can_go = cur == length_or_end /// if can_go then succ else drop-block @@ -561,49 +558,50 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> /// cur = cur + 1 /// } /// drop(ptr) - fn drop_loop(&mut self, - succ: BasicBlock, - cur: Local, - length_or_end: &Place<'tcx>, - ety: Ty<'tcx>, - unwind: Unwind, - ptr_based: bool) - -> BasicBlock - { + /// ``` + fn drop_loop( + &mut self, + succ: BasicBlock, + cur: Local, + length_or_end: &Place<'tcx>, + ety: Ty<'tcx>, + unwind: Unwind, + ptr_based: bool, + ) -> BasicBlock { let copy = |place: &Place<'tcx>| Operand::Copy(place.clone()); let move_ = |place: &Place<'tcx>| Operand::Move(place.clone()); let tcx = self.tcx(); - let ref_ty = tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut { + let ref_ty = tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::MutMutable }); - let ptr = &Place::Base(PlaceBase::Local(self.new_temp(ref_ty))); - let can_go = &Place::Base(PlaceBase::Local(self.new_temp(tcx.types.bool))); + let ptr = &Place::from(self.new_temp(ref_ty)); + let can_go = &Place::from(self.new_temp(tcx.types.bool)); let one = self.constant_usize(1); let (ptr_next, cur_next) = if ptr_based { (Rvalue::Ref( - tcx.types.re_erased, + tcx.lifetimes.re_erased, BorrowKind::Mut { allow_two_phase_borrow: false }, Place::Projection(Box::new(Projection { base: Place::Base(PlaceBase::Local(cur)), elem: ProjectionElem::Deref, })) ), - Rvalue::BinaryOp(BinOp::Offset, copy(&Place::Base(PlaceBase::Local(cur))), one)) + Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one)) } else { (Rvalue::Ref( - tcx.types.re_erased, + tcx.lifetimes.re_erased, BorrowKind::Mut { allow_two_phase_borrow: false }, self.place.clone().index(cur)), - Rvalue::BinaryOp(BinOp::Add, copy(&Place::Base(PlaceBase::Local(cur))), one)) + Rvalue::BinaryOp(BinOp::Add, move_(&Place::from(cur)), one)) }; let drop_block = BasicBlockData { statements: vec![ self.assign(ptr, ptr_next), - self.assign(&Place::Base(PlaceBase::Local(cur)), cur_next) + self.assign(&Place::from(cur), cur_next) ], is_cleanup: unwind.is_cleanup(), terminator: Some(Terminator { @@ -617,7 +615,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let loop_block = BasicBlockData { statements: vec![ self.assign(can_go, Rvalue::BinaryOp(BinOp::Eq, - copy(&Place::Base(PlaceBase::Local(cur))), + copy(&Place::from(cur)), copy(length_or_end))) ], is_cleanup: unwind.is_cleanup(), @@ -647,9 +645,9 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> // } if let Some(size) = opt_size { - assert!(size <= (u32::MAX as u64), - "move out check doesn't implemented for array bigger then u32"); - let size = size as u32; + let size: u32 = size.try_into().unwrap_or_else(|_| { + bug!("move out check isn't implemented for array sizes bigger than u32::MAX"); + }); let fields: Vec<(Place<'tcx>, Option)> = (0..size).map(|i| { (self.place.clone().elem(ProjectionElem::ConstantIndex{ offset: i, @@ -667,33 +665,42 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let move_ = |place: &Place<'tcx>| Operand::Move(place.clone()); let tcx = self.tcx(); - let size = &Place::Base(PlaceBase::Local(self.new_temp(tcx.types.usize))); - let size_is_zero = &Place::Base(PlaceBase::Local(self.new_temp(tcx.types.bool))); + let elem_size = &Place::from(self.new_temp(tcx.types.usize)); + let len = &Place::from(self.new_temp(tcx.types.usize)); + + static USIZE_SWITCH_ZERO: &[u128] = &[0]; + let base_block = BasicBlockData { statements: vec![ - self.assign(size, Rvalue::NullaryOp(NullOp::SizeOf, ety)), - self.assign(size_is_zero, Rvalue::BinaryOp(BinOp::Eq, - move_(size), - self.constant_usize(0))) + self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)), + self.assign(len, Rvalue::Len(self.place.clone())), ], is_cleanup: self.unwind.is_cleanup(), terminator: Some(Terminator { source_info: self.source_info, - kind: TerminatorKind::if_( - tcx, - move_(size_is_zero), - self.drop_loop_pair(ety, false), - self.drop_loop_pair(ety, true) - ) + kind: TerminatorKind::SwitchInt { + discr: move_(elem_size), + switch_ty: tcx.types.usize, + values: From::from(USIZE_SWITCH_ZERO), + targets: vec![ + self.drop_loop_pair(ety, false, len.clone()), + self.drop_loop_pair(ety, true, len.clone()), + ], + }, }) }; self.elaborator.patch().new_block(base_block) } - // create a pair of drop-loops of `place`, which drops its contents - // even in the case of 1 panic. If `ptr_based`, create a pointer loop, - // otherwise create an index loop. - fn drop_loop_pair(&mut self, ety: Ty<'tcx>, ptr_based: bool) -> BasicBlock { + /// Ceates a pair of drop-loops of `place`, which drops its contents, even + /// in the case of 1 panic. If `ptr_based`, creates a pointer loop, + /// otherwise create an index loop. + fn drop_loop_pair( + &mut self, + ety: Ty<'tcx>, + ptr_based: bool, + length: Place<'tcx>, + ) -> BasicBlock { debug!("drop_loop_pair({:?}, {:?})", ety, ptr_based); let tcx = self.tcx(); let iter_ty = if ptr_based { @@ -703,12 +710,10 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> }; let cur = self.new_temp(iter_ty); - let length = Place::Base(PlaceBase::Local(self.new_temp(tcx.types.usize))); let length_or_end = if ptr_based { // FIXME check if we want to make it return a `Place` directly // if all use sites want a `Place::Base` anyway. - let temp = self.new_temp(iter_ty); - Place::Base(PlaceBase::Local(temp)) + Place::from(self.new_temp(iter_ty)) } else { length.clone() }; @@ -722,41 +727,41 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> ptr_based) }); - let succ = self.succ; // FIXME(#43234) let loop_block = self.drop_loop( - succ, + self.succ, cur, &length_or_end, ety, unwind, ptr_based); - let cur = Place::Base(PlaceBase::Local(cur)); - let zero = self.constant_usize(0); - let mut drop_block_stmts = vec![]; - drop_block_stmts.push(self.assign(&length, Rvalue::Len(self.place.clone()))); - if ptr_based { + let cur = Place::from(cur); + let drop_block_stmts = if ptr_based { let tmp_ty = tcx.mk_mut_ptr(self.place_ty(self.place)); - let tmp = Place::Base(PlaceBase::Local(self.new_temp(tmp_ty))); + let tmp = Place::from(self.new_temp(tmp_ty)); // tmp = &mut P; // cur = tmp as *mut T; // end = Offset(cur, len); - drop_block_stmts.push(self.assign(&tmp, Rvalue::Ref( - tcx.types.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, - self.place.clone() - ))); - drop_block_stmts.push(self.assign(&cur, Rvalue::Cast( - CastKind::Misc, Operand::Move(tmp), iter_ty - ))); - drop_block_stmts.push(self.assign(&length_or_end, - Rvalue::BinaryOp(BinOp::Offset, - Operand::Copy(cur), Operand::Move(length) - ))); + vec![ + self.assign(&tmp, Rvalue::Ref( + tcx.lifetimes.re_erased, + BorrowKind::Mut { allow_two_phase_borrow: false }, + self.place.clone() + )), + self.assign( + &cur, + Rvalue::Cast(CastKind::Misc, Operand::Move(tmp), iter_ty), + ), + self.assign( + &length_or_end, + Rvalue::BinaryOp(BinOp::Offset, Operand::Copy(cur), Operand::Move(length) + )), + ] } else { - // index = 0 (length already pushed) - drop_block_stmts.push(self.assign(&cur, Rvalue::Use(zero))); - } + // cur = 0 (length already pushed) + let zero = self.constant_usize(0); + vec![self.assign(&cur, Rvalue::Use(zero))] + }; let drop_block = self.elaborator.patch().new_block(BasicBlockData { statements: drop_block_stmts, is_cleanup: unwind.is_cleanup(), @@ -768,7 +773,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> // FIXME(#34708): handle partially-dropped array/slice elements. let reset_block = self.drop_flag_reset_block(DropFlagMode::Deep, drop_block, unwind); - self.drop_flag_test_block(reset_block, succ, unwind) + self.drop_flag_test_block(reset_block, self.succ, unwind) } /// The slow-path - create an "open", elaborated drop for a type @@ -779,7 +784,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> /// /// This creates a "drop ladder" that drops the needed fields of the /// ADT, both in the success case or if one of the destructors fail. - fn open_drop<'a>(&mut self) -> BasicBlock { + fn open_drop(&mut self) -> BasicBlock { let ty = self.place_ty(self.place); match ty.sty { ty::Closure(def_id, substs) => { @@ -791,13 +796,14 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> // within that own generator's resume function. // This should only happen for the self argument on the resume function. // It effetively only contains upvars until the generator transformation runs. - // See librustc_mir/transform/generator.rs for more details. + // See librustc_body/transform/generator.rs for more details. ty::Generator(def_id, substs, _) => { let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx()).collect(); self.open_drop_for_tuple(&tys) } ty::Tuple(tys) => { - self.open_drop_for_tuple(tys) + let tys: Vec<_> = tys.iter().map(|k| k.expect_ty()).collect(); + self.open_drop_for_tuple(&tys) } ty::Adt(def, substs) => { if def.is_box() { @@ -828,11 +834,12 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> /// if FLAG(self.path) /// if let Some(mode) = mode: FLAG(self.path)[mode] = false /// drop(self.place) - fn complete_drop<'a>(&mut self, - drop_mode: Option, - succ: BasicBlock, - unwind: Unwind) -> BasicBlock - { + fn complete_drop( + &mut self, + drop_mode: Option, + succ: BasicBlock, + unwind: Unwind, + ) -> BasicBlock { debug!("complete_drop({:?},{:?})", self, drop_mode); let drop_block = self.drop_block(succ, unwind); @@ -858,7 +865,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> block } - fn elaborated_drop_block<'a>(&mut self) -> BasicBlock { + fn elaborated_drop_block(&mut self) -> BasicBlock { debug!("elaborated_drop_block({:?})", self); let unwind = self.unwind; // FIXME(#43234) let succ = self.succ; @@ -867,7 +874,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> blk } - fn box_free_block<'a>( + fn box_free_block( &mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>, @@ -878,15 +885,15 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.drop_flag_test_block(block, target, unwind) } - fn unelaborated_free_block<'a>( + fn unelaborated_free_block( &mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>, target: BasicBlock, - unwind: Unwind + unwind: Unwind, ) -> BasicBlock { let tcx = self.tcx(); - let unit_temp = Place::Base(PlaceBase::Local(self.new_temp(tcx.mk_unit()))); + let unit_temp = Place::from(self.new_temp(tcx.mk_unit())); let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem); let args = adt.variants[VariantIdx::new(0)].fields.iter().enumerate().map(|(i, f)| { let field = Field::new(i); @@ -908,7 +915,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> free_block } - fn drop_block<'a>(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { + fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { let block = TerminatorKind::Drop { location: self.place.clone(), target, @@ -938,11 +945,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> } } - fn new_block<'a>(&mut self, - unwind: Unwind, - k: TerminatorKind<'tcx>) - -> BasicBlock - { + fn new_block(&mut self, unwind: Unwind, k: TerminatorKind<'tcx>) -> BasicBlock { self.elaborator.patch().new_block(BasicBlockData { statements: vec![], terminator: Some(Terminator { @@ -957,8 +960,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> } fn terminator_loc(&mut self, bb: BasicBlock) -> Location { - let mir = self.elaborator.mir(); - self.elaborator.patch().terminator_loc(mir, bb) + let body = self.elaborator.body(); + self.elaborator.patch().terminator_loc(body, bb) } fn constant_usize(&self, val: u16) -> Operand<'tcx> { @@ -966,9 +969,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> span: self.source_info.span, ty: self.tcx().types.usize, user_ty: None, - literal: self.tcx().mk_lazy_const(ty::LazyConst::Evaluated( - ty::Const::from_usize(self.tcx(), val.into()) - )), + literal: ty::Const::from_usize(self.tcx(), val.into()), }) } diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs index 5d495fc04588b..1d876d7bddb53 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/src/librustc_mir/util/graphviz.rs @@ -1,33 +1,49 @@ use rustc::hir::def_id::DefId; use rustc::mir::*; use rustc::ty::TyCtxt; +use rustc_data_structures::indexed_vec::Idx; use std::fmt::Debug; use std::io::{self, Write}; use super::pretty::dump_mir_def_ids; /// Write a graphviz DOT graph of a list of MIRs. -pub fn write_mir_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>, - single: Option, - w: &mut W) - -> io::Result<()> - where W: Write +pub fn write_mir_graphviz<'tcx, W>( + tcx: TyCtxt<'tcx>, + single: Option, + w: &mut W, +) -> io::Result<()> +where + W: Write, { for def_id in dump_mir_def_ids(tcx, single) { - let mir = &tcx.optimized_mir(def_id); - write_mir_fn_graphviz(tcx, def_id, mir, w)?; + let body = &tcx.optimized_mir(def_id); + write_mir_fn_graphviz(tcx, def_id, body, w)?; } Ok(()) } +// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so +// it does not have to be user friendly. +pub fn graphviz_safe_def_name(def_id: DefId) -> String { + format!( + "{}_{}", + def_id.krate.index(), + def_id.index.index(), + ) +} + /// Write a graphviz DOT graph of the MIR. -pub fn write_mir_fn_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>, - def_id: DefId, - mir: &Mir<'_>, - w: &mut W) -> io::Result<()> - where W: Write +pub fn write_mir_fn_graphviz<'tcx, W>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + body: &Body<'_>, + w: &mut W, +) -> io::Result<()> +where + W: Write, { - writeln!(w, "digraph Mir_{} {{", tcx.hir().as_local_node_id(def_id).unwrap())?; + writeln!(w, "digraph Mir_{} {{", graphviz_safe_def_name(def_id))?; // Global graph properties writeln!(w, r#" graph [fontname="monospace"];"#)?; @@ -35,16 +51,16 @@ pub fn write_mir_fn_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>, writeln!(w, r#" edge [fontname="monospace"];"#)?; // Graph label - write_graph_label(tcx, def_id, mir, w)?; + write_graph_label(tcx, def_id, body, w)?; // Nodes - for (block, _) in mir.basic_blocks().iter_enumerated() { - write_node(block, mir, w)?; + for (block, _) in body.basic_blocks().iter_enumerated() { + write_node(block, body, w)?; } // Edges - for (source, _) in mir.basic_blocks().iter_enumerated() { - write_edges(source, mir, w)?; + for (source, _) in body.basic_blocks().iter_enumerated() { + write_edges(source, body, w)?; } writeln!(w, "}}") } @@ -57,7 +73,7 @@ pub fn write_mir_fn_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>, /// `init` and `fini` are callbacks for emitting additional rows of /// data (using HTML enclosed with `` in the emitted text). pub fn write_node_label(block: BasicBlock, - mir: &Mir<'_>, + body: &Body<'_>, w: &mut W, num_cols: u32, init: INIT, @@ -65,7 +81,7 @@ pub fn write_node_label(block: BasicBlock, where INIT: Fn(&mut W) -> io::Result<()>, FINI: Fn(&mut W) -> io::Result<()> { - let data = &mir[block]; + let data = &body[block]; write!(w, r#""#)?; @@ -99,17 +115,17 @@ pub fn write_node_label(block: BasicBlock, } /// Write a graphviz DOT node for the given basic block. -fn write_node(block: BasicBlock, mir: &Mir<'_>, w: &mut W) -> io::Result<()> { +fn write_node(block: BasicBlock, body: &Body<'_>, w: &mut W) -> io::Result<()> { // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables. write!(w, r#" {} [shape="none", label=<"#, node(block))?; - write_node_label(block, mir, w, 1, |_| Ok(()), |_| Ok(()))?; + write_node_label(block, body, w, 1, |_| Ok(()), |_| Ok(()))?; // Close the node label and the node itself. writeln!(w, ">];") } /// Write graphviz DOT edges with labels between the given basic block and all of its successors. -fn write_edges(source: BasicBlock, mir: &Mir<'_>, w: &mut W) -> io::Result<()> { - let terminator = mir[source].terminator(); +fn write_edges(source: BasicBlock, body: &Body<'_>, w: &mut W) -> io::Result<()> { + let terminator = body[source].terminator(); let labels = terminator.kind.fmt_successor_labels(); for (&target, label) in terminator.successors().zip(labels) { @@ -122,30 +138,31 @@ fn write_edges(source: BasicBlock, mir: &Mir<'_>, w: &mut W) -> io::Re /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that /// will appear below the graph, showing the type of the `fn` this MIR represents and the types of /// all the variables and temporaries. -fn write_graph_label<'a, 'gcx, 'tcx, W: Write>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - def_id: DefId, - mir: &Mir<'_>, - w: &mut W) - -> io::Result<()> { - write!(w, " label=( + tcx: TyCtxt<'tcx>, + def_id: DefId, + body: &Body<'_>, + w: &mut W, +) -> io::Result<()> { + write!(w, " label= 0 { write!(w, ", ")?; } write!(w, "{:?}: {}", - Place::Base(PlaceBase::Local(arg)), - escape(&mir.local_decls[arg].ty) + Place::from(arg), + escape(&body.local_decls[arg].ty) )?; } - write!(w, ") -> {}", escape(mir.return_ty()))?; + write!(w, ") -> {}", escape(&body.return_ty()))?; write!(w, r#"
"#)?; - for local in mir.vars_and_temps_iter() { - let decl = &mir.local_decls[local]; + for local in body.vars_and_temps_iter() { + let decl = &body.local_decls[local]; write!(w, "let ")?; if decl.mutability == Mutability::Mut { @@ -154,10 +171,10 @@ fn write_graph_label<'a, 'gcx, 'tcx, W: Write>(tcx: TyCtxt<'a, 'gcx, 'tcx>, if let Some(name) = decl.name { write!(w, r#"{:?}: {}; // {}
"#, - Place::Base(PlaceBase::Local(local)), escape(&decl.ty), name)?; + Place::from(local), escape(&decl.ty), name)?; } else { - write!(w, r#"let mut {:?}: {};
"#, - Place::Base(PlaceBase::Local(local)), escape(&decl.ty))?; + write!(w, r#"{:?}: {};
"#, + Place::from(local), escape(&decl.ty))?; } } diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index dcbd9aa9af225..8ead571d9664d 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -29,7 +29,7 @@ use rustc::mir::visit::{ }; use rustc::mir::Local; use rustc::mir::*; -use rustc::ty::{item_path, TyCtxt}; +use rustc::ty::{self, TyCtxt}; use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::work_queue::WorkQueue; @@ -39,7 +39,7 @@ use std::path::{Path, PathBuf}; use crate::transform::MirSource; use crate::util::pretty::{dump_enabled, write_basic_block, write_mir_intro}; -pub type LiveVarSet = BitSet; +pub type LiveVarSet = BitSet; /// This gives the result of the liveness analysis at the boundary of /// basic blocks. @@ -48,66 +48,26 @@ pub type LiveVarSet = BitSet; /// liveness for. This is often `Local`, in which case we computed /// liveness for all variables -- but it can also be some other type, /// which indicates a subset of the variables within the graph. -pub struct LivenessResult { +pub struct LivenessResult { /// Live variables on exit to each basic block. This is equal to /// the union of the `ins` for each successor. - pub outs: IndexVec>, -} - -/// Defines the mapping to/from the MIR local variables (`Local`) to -/// the "live variable indices" we are using in a particular -/// computation. -pub trait LiveVariableMap { - type LiveVar; - - fn from_local(&self, local: Local) -> Option; - fn from_live_var(&self, local: Self::LiveVar) -> Local; - fn num_variables(&self) -> usize; -} - -#[derive(Debug)] -pub struct IdentityMap<'a, 'tcx: 'a> { - mir: &'a Mir<'tcx>, -} - -impl<'a, 'tcx> IdentityMap<'a, 'tcx> { - pub fn new(mir: &'a Mir<'tcx>) -> Self { - Self { mir } - } -} - -impl<'a, 'tcx> LiveVariableMap for IdentityMap<'a, 'tcx> { - type LiveVar = Local; - - fn from_local(&self, local: Local) -> Option { - Some(local) - } - - fn from_live_var(&self, local: Self::LiveVar) -> Local { - local - } - - fn num_variables(&self) -> usize { - self.mir.local_decls.len() - } + pub outs: IndexVec, } /// Computes which local variables are live within the given function -/// `mir`. The liveness mode `mode` determines what sorts of uses are -/// considered to make a variable live (e.g., do drops count?). -pub fn liveness_of_locals<'tcx, V: Idx>( - mir: &Mir<'tcx>, - map: &impl LiveVariableMap, -) -> LivenessResult { - let num_live_vars = map.num_variables(); - - let def_use: IndexVec<_, DefsUses> = mir +/// `mir`, including drops. +pub fn liveness_of_locals<'tcx>( + body: &Body<'tcx>, +) -> LivenessResult { + let num_live_vars = body.local_decls.len(); + + let def_use: IndexVec<_, DefsUses> = body .basic_blocks() .iter() - .map(|b| block(map, b, num_live_vars)) + .map(|b| block(b, num_live_vars)) .collect(); - let mut outs: IndexVec<_, LiveVarSet> = mir + let mut outs: IndexVec<_, LiveVarSet> = body .basic_blocks() .indices() .map(|_| LiveVarSet::new_empty(num_live_vars)) @@ -115,11 +75,26 @@ pub fn liveness_of_locals<'tcx, V: Idx>( let mut bits = LiveVarSet::new_empty(num_live_vars); - // queue of things that need to be re-processed, and a set containing - // the things currently in the queue - let mut dirty_queue: WorkQueue = WorkQueue::with_all(mir.basic_blocks().len()); + // The dirty queue contains the set of basic blocks whose entry sets have changed since they + // were last processed. At the start of the analysis, we initialize the queue in post-order to + // make it more likely that the entry set for a given basic block will have the effects of all + // its successors in the CFG applied before it is processed. + // + // FIXME(ecstaticmorse): Reverse post-order on the reverse CFG may generate a better iteration + // order when cycles are present, but the overhead of computing the reverse CFG may outweigh + // any benefits. Benchmark this and find out. + let mut dirty_queue: WorkQueue = WorkQueue::with_none(body.basic_blocks().len()); + for (bb, _) in traversal::postorder(body) { + dirty_queue.insert(bb); + } - let predecessors = mir.predecessors(); + // Add blocks which are not reachable from START_BLOCK to the work queue. These blocks will + // be processed after the ones added above. + for bb in body.basic_blocks().indices() { + dirty_queue.insert(bb); + } + + let predecessors = body.predecessors(); while let Some(bb) = dirty_queue.pop() { // bits = use ∪ (bits - def) @@ -149,7 +124,7 @@ pub enum DefUse { Drop, } -pub fn categorize<'tcx>(context: PlaceContext<'tcx>) -> Option { +pub fn categorize(context: PlaceContext) -> Option { match context { /////////////////////////////////////////////////////////////////////////// // DEFS @@ -186,10 +161,10 @@ pub fn categorize<'tcx>(context: PlaceContext<'tcx>) -> Option { // This won't affect the results since we use this analysis for generators // and we only care about the result at suspension points. Borrows cannot // cross suspension points so this behavior is unproblematic. - PlaceContext::MutatingUse(MutatingUseContext::Borrow(..)) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow(..)) | + PlaceContext::MutatingUse(MutatingUseContext::Borrow) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) | PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) | PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | @@ -211,27 +186,23 @@ pub fn categorize<'tcx>(context: PlaceContext<'tcx>) -> Option { } } -struct DefsUsesVisitor<'lv, V, M> -where - V: Idx, - M: LiveVariableMap + 'lv, +struct DefsUsesVisitor { - map: &'lv M, - defs_uses: DefsUses, + defs_uses: DefsUses, } #[derive(Eq, PartialEq, Clone)] -struct DefsUses { - defs: LiveVarSet, - uses: LiveVarSet, +struct DefsUses { + defs: LiveVarSet, + uses: LiveVarSet, } -impl DefsUses { - fn apply(&self, bits: &mut LiveVarSet) -> bool { +impl DefsUses { + fn apply(&self, bits: &mut LiveVarSet) -> bool { bits.subtract(&self.defs) | bits.union(&self.uses) } - fn add_def(&mut self, index: V) { + fn add_def(&mut self, index: Local) { // If it was used already in the block, remove that use // now that we found a definition. // @@ -245,7 +216,7 @@ impl DefsUses { self.defs.insert(index); } - fn add_use(&mut self, index: V) { + fn add_use(&mut self, index: Local) { // Inverse of above. // // Example: @@ -261,29 +232,22 @@ impl DefsUses { } } -impl<'tcx, 'lv, V, M> Visitor<'tcx> for DefsUsesVisitor<'lv, V, M> -where - V: Idx, - M: LiveVariableMap, +impl<'tcx> Visitor<'tcx> for DefsUsesVisitor { - fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, _: Location) { - if let Some(v_index) = self.map.from_local(local) { - match categorize(context) { - Some(DefUse::Def) => self.defs_uses.add_def(v_index), - Some(DefUse::Use) | Some(DefUse::Drop) => self.defs_uses.add_use(v_index), - _ => (), - } + fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + match categorize(context) { + Some(DefUse::Def) => self.defs_uses.add_def(local), + Some(DefUse::Use) | Some(DefUse::Drop) => self.defs_uses.add_use(local), + _ => (), } } } -fn block<'tcx, V: Idx>( - map: &impl LiveVariableMap, +fn block<'tcx>( b: &BasicBlockData<'tcx>, locals: usize, -) -> DefsUses { +) -> DefsUses { let mut visitor = DefsUsesVisitor { - map, defs_uses: DefsUses { defs: LiveVarSet::new_empty(locals), uses: LiveVarSet::new_empty(locals), @@ -297,44 +261,42 @@ fn block<'tcx, V: Idx>( // Visit the various parts of the basic block in reverse. If we go // forward, the logic in `add_def` and `add_use` would be wrong. - visitor.visit_terminator(BasicBlock::new(0), b.terminator(), dummy_location); + visitor.visit_terminator(b.terminator(), dummy_location); for statement in b.statements.iter().rev() { - visitor.visit_statement(BasicBlock::new(0), statement, dummy_location); + visitor.visit_statement(statement, dummy_location); } visitor.defs_uses } -pub fn dump_mir<'a, 'tcx, V: Idx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn dump_mir<'tcx>( + tcx: TyCtxt<'tcx>, pass_name: &str, source: MirSource<'tcx>, - mir: &Mir<'tcx>, - map: &impl LiveVariableMap, - result: &LivenessResult, + body: &Body<'tcx>, + result: &LivenessResult, ) { if !dump_enabled(tcx, pass_name, source) { return; } - let node_path = item_path::with_forced_impl_filename_line(|| { + let node_path = ty::print::with_forced_impl_filename_line(|| { // see notes on #41697 below - tcx.item_path_str(source.def_id()) + tcx.def_path_str(source.def_id()) }); - dump_matched_mir_node(tcx, pass_name, &node_path, source, mir, map, result); + dump_matched_mir_node(tcx, pass_name, &node_path, source, body, result); } -fn dump_matched_mir_node<'a, 'tcx, V: Idx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn dump_matched_mir_node<'tcx>( + tcx: TyCtxt<'tcx>, pass_name: &str, node_path: &str, source: MirSource<'tcx>, - mir: &Mir<'tcx>, - map: &dyn LiveVariableMap, - result: &LivenessResult, + body: &Body<'tcx>, + result: &LivenessResult, ) { let mut file_path = PathBuf::new(); file_path.push(Path::new(&tcx.sess.opts.debugging_opts.dump_mir_dir)); - let item_id = tcx.hir().as_local_node_id(source.def_id()).unwrap(); + let item_id = tcx.hir().as_local_hir_id(source.def_id()).unwrap(); let file_name = format!("rustc.node{}{}-liveness.mir", item_id, pass_name); file_path.push(&file_name); let _ = fs::File::create(&file_path).and_then(|mut file| { @@ -342,32 +304,30 @@ fn dump_matched_mir_node<'a, 'tcx, V: Idx>( writeln!(file, "// source = {:?}", source)?; writeln!(file, "// pass_name = {}", pass_name)?; writeln!(file, "")?; - write_mir_fn(tcx, source, mir, map, &mut file, result)?; + write_mir_fn(tcx, source, body, &mut file, result)?; Ok(()) }); } -pub fn write_mir_fn<'a, 'tcx, V: Idx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn write_mir_fn<'tcx>( + tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, - mir: &Mir<'tcx>, - map: &dyn LiveVariableMap, + body: &Body<'tcx>, w: &mut dyn Write, - result: &LivenessResult, + result: &LivenessResult, ) -> io::Result<()> { - write_mir_intro(tcx, src, mir, w)?; - for block in mir.basic_blocks().indices() { - let print = |w: &mut dyn Write, prefix, result: &IndexVec>| { + write_mir_intro(tcx, src, body, w)?; + for block in body.basic_blocks().indices() { + let print = |w: &mut dyn Write, prefix, result: &IndexVec| { let live: Vec = result[block] .iter() - .map(|v| map.from_live_var(v)) .map(|local| format!("{:?}", local)) .collect(); writeln!(w, "{} {{{}}}", prefix, live.join(", ")) }; - write_basic_block(tcx, block, mir, &mut |_, _| Ok(()), w)?; + write_basic_block(tcx, block, body, &mut |_, _| Ok(()), w)?; print(w, " ", &result.outs)?; - if block.index() + 1 != mir.basic_blocks().len() { + if block.index() + 1 != body.basic_blocks().len() { writeln!(w, "")?; } } diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs index 29614a33f8e27..719029dbaac77 100644 --- a/src/librustc_mir/util/mod.rs +++ b/src/librustc_mir/util/mod.rs @@ -1,7 +1,8 @@ use core::unicode::property::Pattern_White_Space; -use rustc::ty; +use rustc::ty::TyCtxt; use syntax_pos::Span; +pub mod aggregate; pub mod borrowck_errors; pub mod elaborate_drops; pub mod def_use; @@ -13,16 +14,14 @@ pub(crate) mod pretty; pub mod liveness; pub mod collect_writes; +pub use self::aggregate::expand_aggregate; pub use self::alignment::is_disaligned; pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere}; -pub use self::graphviz::{write_mir_graphviz}; +pub use self::graphviz::{graphviz_safe_def_name, write_mir_graphviz}; pub use self::graphviz::write_node_label as write_graphviz_node_label; /// If possible, suggest replacing `ref` with `ref mut`. -pub fn suggest_ref_mut<'cx, 'gcx, 'tcx>( - tcx: ty::TyCtxt<'cx, 'gcx, 'tcx>, - binding_span: Span, -) -> Option<(String)> { +pub fn suggest_ref_mut<'tcx>(tcx: TyCtxt<'tcx>, binding_span: Span) -> Option<(String)> { let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).unwrap(); if hi_src.starts_with("ref") && hi_src["ref".len()..].starts_with(Pattern_White_Space) diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index 366cd71f6d4e9..eb457dacf8467 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -17,13 +17,13 @@ pub struct MirPatch<'tcx> { } impl<'tcx> MirPatch<'tcx> { - pub fn new(mir: &Mir<'tcx>) -> Self { + pub fn new(body: &Body<'tcx>) -> Self { let mut result = MirPatch { - patch_map: IndexVec::from_elem(None, mir.basic_blocks()), + patch_map: IndexVec::from_elem(None, body.basic_blocks()), new_blocks: vec![], new_statements: vec![], new_locals: vec![], - next_local: mir.local_decls.len(), + next_local: body.local_decls.len(), resume_block: START_BLOCK, make_nop: vec![] }; @@ -35,7 +35,7 @@ impl<'tcx> MirPatch<'tcx> { let mut resume_block = None; let mut resume_stmt_block = None; - for (bb, block) in mir.basic_blocks().iter_enumerated() { + for (bb, block) in body.basic_blocks().iter_enumerated() { if let TerminatorKind::Resume = block.terminator().kind { if block.statements.len() > 0 { assert!(resume_stmt_block.is_none()); @@ -51,7 +51,7 @@ impl<'tcx> MirPatch<'tcx> { statements: vec![], terminator: Some(Terminator { source_info: SourceInfo { - span: mir.span, + span: body.span, scope: OUTERMOST_SOURCE_SCOPE }, kind: TerminatorKind::Resume @@ -75,10 +75,10 @@ impl<'tcx> MirPatch<'tcx> { self.patch_map[bb].is_some() } - pub fn terminator_loc(&self, mir: &Mir<'tcx>, bb: BasicBlock) -> Location { - let offset = match bb.index().checked_sub(mir.basic_blocks().len()) { + pub fn terminator_loc(&self, body: &Body<'tcx>, bb: BasicBlock) -> Location { + let offset = match bb.index().checked_sub(body.basic_blocks().len()) { Some(index) => self.new_blocks[index].statements.len(), - None => mir[bb].statements.len() + None => body[bb].statements.len() }; Location { block: bb, @@ -127,21 +127,21 @@ impl<'tcx> MirPatch<'tcx> { self.make_nop.push(loc); } - pub fn apply(self, mir: &mut Mir<'tcx>) { + pub fn apply(self, body: &mut Body<'tcx>) { debug!("MirPatch: make nops at: {:?}", self.make_nop); for loc in self.make_nop { - mir.make_statement_nop(loc); + body.make_statement_nop(loc); } debug!("MirPatch: {:?} new temps, starting from index {}: {:?}", - self.new_locals.len(), mir.local_decls.len(), self.new_locals); + self.new_locals.len(), body.local_decls.len(), self.new_locals); debug!("MirPatch: {} new blocks, starting from index {}", - self.new_blocks.len(), mir.basic_blocks().len()); - mir.basic_blocks_mut().extend(self.new_blocks); - mir.local_decls.extend(self.new_locals); + self.new_blocks.len(), body.basic_blocks().len()); + body.basic_blocks_mut().extend(self.new_blocks); + body.local_decls.extend(self.new_locals); for (src, patch) in self.patch_map.into_iter_enumerated() { if let Some(patch) = patch { debug!("MirPatch: patching block {:?}", src); - mir[src].terminator_mut().kind = patch; + body[src].terminator_mut().kind = patch; } } @@ -159,9 +159,9 @@ impl<'tcx> MirPatch<'tcx> { stmt, loc, delta); loc.statement_index += delta; let source_info = Self::source_info_for_index( - &mir[loc.block], loc + &body[loc.block], loc ); - mir[loc.block].statements.insert( + body[loc.block].statements.insert( loc.statement_index, Statement { source_info, kind: stmt @@ -177,10 +177,10 @@ impl<'tcx> MirPatch<'tcx> { } } - pub fn source_info_for_location(&self, mir: &Mir<'_>, loc: Location) -> SourceInfo { - let data = match loc.block.index().checked_sub(mir.basic_blocks().len()) { + pub fn source_info_for_location(&self, body: &Body<'_>, loc: Location) -> SourceInfo { + let data = match loc.block.index().checked_sub(body.basic_blocks().len()) { Some(new) => &self.new_blocks[new], - None => &mir[loc.block] + None => &body[loc.block] }; Self::source_info_for_index(data, loc) } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index c3fbee3a2a6e5..d66f35f82c662 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -2,7 +2,6 @@ use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::mir::*; use rustc::mir::visit::Visitor; use rustc::ty::{self, TyCtxt}; -use rustc::ty::item_path; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; use std::fmt::Display; @@ -63,13 +62,13 @@ pub enum PassWhere { /// or `typeck` appears in the name. /// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name /// or `typeck` and `bar` both appear in the name. -pub fn dump_mir<'a, 'gcx, 'tcx, F>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, +pub fn dump_mir<'tcx, F>( + tcx: TyCtxt<'tcx>, pass_num: Option<&dyn Display>, pass_name: &str, disambiguator: &dyn Display, source: MirSource<'tcx>, - mir: &Mir<'tcx>, + body: &Body<'tcx>, extra_data: F, ) where F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, @@ -78,9 +77,9 @@ pub fn dump_mir<'a, 'gcx, 'tcx, F>( return; } - let node_path = item_path::with_forced_impl_filename_line(|| { + let node_path = ty::print::with_forced_impl_filename_line(|| { // see notes on #41697 below - tcx.item_path_str(source.def_id()) + tcx.def_path_str(source.def_id()) }); dump_matched_mir_node( tcx, @@ -89,23 +88,19 @@ pub fn dump_mir<'a, 'gcx, 'tcx, F>( &node_path, disambiguator, source, - mir, + body, extra_data, ); } -pub fn dump_enabled<'a, 'gcx, 'tcx>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - pass_name: &str, - source: MirSource<'tcx>, -) -> bool { +pub fn dump_enabled<'tcx>(tcx: TyCtxt<'tcx>, pass_name: &str, source: MirSource<'tcx>) -> bool { let filters = match tcx.sess.opts.debugging_opts.dump_mir { None => return false, Some(ref filters) => filters, }; - let node_path = item_path::with_forced_impl_filename_line(|| { + let node_path = ty::print::with_forced_impl_filename_line(|| { // see notes on #41697 below - tcx.item_path_str(source.def_id()) + tcx.def_path_str(source.def_id()) }); filters.split('|').any(|or_filter| { or_filter.split('&').all(|and_filter| { @@ -115,17 +110,17 @@ pub fn dump_enabled<'a, 'gcx, 'tcx>( } // #41697 -- we use `with_forced_impl_filename_line()` because -// `item_path_str()` would otherwise trigger `type_of`, and this can +// `def_path_str()` would otherwise trigger `type_of`, and this can // run while we are already attempting to evaluate `type_of`. -fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, +fn dump_matched_mir_node<'tcx, F>( + tcx: TyCtxt<'tcx>, pass_num: Option<&dyn Display>, pass_name: &str, node_path: &str, disambiguator: &dyn Display, source: MirSource<'tcx>, - mir: &Mir<'tcx>, + body: &Body<'tcx>, mut extra_data: F, ) where F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, @@ -136,13 +131,13 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( writeln!(file, "// source = {:?}", source)?; writeln!(file, "// pass_name = {}", pass_name)?; writeln!(file, "// disambiguator = {}", disambiguator)?; - if let Some(ref layout) = mir.generator_layout { + if let Some(ref layout) = body.generator_layout { writeln!(file, "// generator_layout = {:?}", layout)?; } writeln!(file, "")?; extra_data(PassWhere::BeforeCFG, &mut file)?; - write_user_type_annotations(mir, &mut file)?; - write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?; + write_user_type_annotations(body, &mut file)?; + write_mir_fn(tcx, source, body, &mut extra_data, &mut file)?; extra_data(PassWhere::AfterCFG, &mut file)?; }; @@ -150,7 +145,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( let _: io::Result<()> = try { let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?; - write_mir_fn_graphviz(tcx, source.def_id(), mir, &mut file)?; + write_mir_fn_graphviz(tcx, source.def_id(), body, &mut file)?; }; } } @@ -159,7 +154,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( /// Also used by other bits of code (e.g., NLL inference) that dump /// graphviz data or other things. fn dump_path( - tcx: TyCtxt<'_, '_, '_>, + tcx: TyCtxt<'_>, extension: &str, pass_num: Option<&dyn Display>, pass_name: &str, @@ -226,7 +221,7 @@ fn dump_path( /// bits of code (e.g., NLL inference) that dump graphviz data or /// other things, and hence takes the extension as an argument. pub(crate) fn create_dump_file( - tcx: TyCtxt<'_, '_, '_>, + tcx: TyCtxt<'_>, extension: &str, pass_num: Option<&dyn Display>, pass_name: &str, @@ -241,8 +236,8 @@ pub(crate) fn create_dump_file( } /// Write out a human-readable textual representation for the given MIR. -pub fn write_mir_pretty<'a, 'gcx, 'tcx>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, +pub fn write_mir_pretty<'tcx>( + tcx: TyCtxt<'tcx>, single: Option, w: &mut dyn Write, ) -> io::Result<()> { @@ -257,7 +252,7 @@ pub fn write_mir_pretty<'a, 'gcx, 'tcx>( let mut first = true; for def_id in dump_mir_def_ids(tcx, single) { - let mir = &tcx.optimized_mir(def_id); + let body = &tcx.optimized_mir(def_id); if first { first = false; @@ -266,35 +261,35 @@ pub fn write_mir_pretty<'a, 'gcx, 'tcx>( writeln!(w, "")?; } - write_mir_fn(tcx, MirSource::item(def_id), mir, &mut |_, _| Ok(()), w)?; + write_mir_fn(tcx, MirSource::item(def_id), body, &mut |_, _| Ok(()), w)?; - for (i, mir) in mir.promoted.iter_enumerated() { + for (i, body) in body.promoted.iter_enumerated() { writeln!(w, "")?; let src = MirSource { instance: ty::InstanceDef::Item(def_id), promoted: Some(i), }; - write_mir_fn(tcx, src, mir, &mut |_, _| Ok(()), w)?; + write_mir_fn(tcx, src, body, &mut |_, _| Ok(()), w)?; } } Ok(()) } -pub fn write_mir_fn<'a, 'gcx, 'tcx, F>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, +pub fn write_mir_fn<'tcx, F>( + tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, - mir: &Mir<'tcx>, + body: &Body<'tcx>, extra_data: &mut F, w: &mut dyn Write, ) -> io::Result<()> where F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, { - write_mir_intro(tcx, src, mir, w)?; - for block in mir.basic_blocks().indices() { + write_mir_intro(tcx, src, body, w)?; + for block in body.basic_blocks().indices() { extra_data(PassWhere::BeforeBlock(block), w)?; - write_basic_block(tcx, block, mir, extra_data, w)?; - if block.index() + 1 != mir.basic_blocks().len() { + write_basic_block(tcx, block, body, extra_data, w)?; + if block.index() + 1 != body.basic_blocks().len() { writeln!(w, "")?; } } @@ -304,22 +299,21 @@ where } /// Write out a human-readable textual representation for the given basic block. -pub fn write_basic_block<'cx, 'gcx, 'tcx, F>( - tcx: TyCtxt<'cx, 'gcx, 'tcx>, +pub fn write_basic_block<'tcx, F>( + tcx: TyCtxt<'tcx>, block: BasicBlock, - mir: &Mir<'tcx>, + body: &Body<'tcx>, extra_data: &mut F, w: &mut dyn Write, ) -> io::Result<()> where F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, { - let data = &mir[block]; + let data = &body[block]; // Basic block label at the top. - let cleanup_text = if data.is_cleanup { " // cleanup" } else { "" }; - let lbl = format!("{}{:?}: {{", INDENT, block); - writeln!(w, "{0:1$}{2}", lbl, ALIGN, cleanup_text)?; + let cleanup_text = if data.is_cleanup { " (cleanup)" } else { "" }; + writeln!(w, "{}{:?}{}: {{", INDENT, block, cleanup_text)?; // List of statements in the middle. let mut current_location = Location { @@ -328,18 +322,18 @@ where }; for statement in &data.statements { extra_data(PassWhere::BeforeLocation(current_location), w)?; - let indented_mir = format!("{0}{0}{1:?};", INDENT, statement); + let indented_body = format!("{0}{0}{1:?};", INDENT, statement); writeln!( w, "{:A$} // {:?}: {}", - indented_mir, + indented_body, current_location, comment(tcx, statement.source_info), A = ALIGN, )?; write_extra(tcx, w, |visitor| { - visitor.visit_statement(current_location.block, statement, current_location); + visitor.visit_statement(statement, current_location); })?; extra_data(PassWhere::AfterLocation(current_location), w)?; @@ -360,7 +354,7 @@ where )?; write_extra(tcx, w, |visitor| { - visitor.visit_terminator(current_location.block, data.terminator(), current_location); + visitor.visit_terminator(data.terminator(), current_location); })?; extra_data(PassWhere::AfterLocation(current_location), w)?; @@ -372,13 +366,9 @@ where /// After we print the main statement, we sometimes dump extra /// information. There's often a lot of little things "nuzzled up" in /// a statement. -fn write_extra<'cx, 'gcx, 'tcx, F>( - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - write: &mut dyn Write, - mut visit_op: F, -) -> io::Result<()> +fn write_extra<'tcx, F>(tcx: TyCtxt<'tcx>, write: &mut dyn Write, mut visit_op: F) -> io::Result<()> where - F: FnMut(&mut ExtraComments<'cx, 'gcx, 'tcx>), + F: FnMut(&mut ExtraComments<'tcx>), { let mut extra_comments = ExtraComments { _tcx: tcx, @@ -391,12 +381,12 @@ where Ok(()) } -struct ExtraComments<'cx, 'gcx: 'tcx, 'tcx: 'cx> { - _tcx: TyCtxt<'cx, 'gcx, 'tcx>, // don't need it now, but bet we will soon +struct ExtraComments<'tcx> { + _tcx: TyCtxt<'tcx>, // don't need it now, but bet we will soon comments: Vec, } -impl<'cx, 'gcx, 'tcx> ExtraComments<'cx, 'gcx, 'tcx> { +impl ExtraComments<'tcx> { fn push(&mut self, lines: &str) { for line in lines.split('\n') { self.comments.push(line.to_string()); @@ -404,7 +394,7 @@ impl<'cx, 'gcx, 'tcx> ExtraComments<'cx, 'gcx, 'tcx> { } } -impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> { +impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); let Constant { span, ty, user_ty, literal } = constant; @@ -417,21 +407,12 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> { self.push(&format!("+ literal: {:?}", literal)); } - fn visit_const(&mut self, constant: &&'tcx ty::LazyConst<'tcx>, _: Location) { + fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { self.super_const(constant); - match constant { - ty::LazyConst::Evaluated(constant) => { - let ty::Const { ty, val, .. } = constant; - self.push("ty::Const"); - self.push(&format!("+ ty: {:?}", ty)); - self.push(&format!("+ val: {:?}", val)); - }, - ty::LazyConst::Unevaluated(did, substs) => { - self.push("ty::LazyConst::Unevaluated"); - self.push(&format!("+ did: {:?}", did)); - self.push(&format!("+ substs: {:?}", substs)); - }, - } + let ty::Const { ty, val, .. } = constant; + self.push("ty::Const"); + self.push(&format!("+ ty: {:?}", ty)); + self.push(&format!("+ val: {:?}", val)); } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { @@ -464,7 +445,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> { } } -fn comment(tcx: TyCtxt<'_, '_, '_>, SourceInfo { span, scope }: SourceInfo) -> String { +fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo) -> String { format!( "scope {} at {}", scope.index(), @@ -472,12 +453,10 @@ fn comment(tcx: TyCtxt<'_, '_, '_>, SourceInfo { span, scope }: SourceInfo) -> S ) } -/// Prints user-defined variables in a scope tree. -/// -/// Returns the total number of variables printed. +/// Prints local variables in a scope tree. fn write_scope_tree( - tcx: TyCtxt<'_, '_, '_>, - mir: &Mir<'_>, + tcx: TyCtxt<'_>, + body: &Body<'_>, scope_tree: &FxHashMap>, w: &mut dyn Write, parent: SourceScope, @@ -485,57 +464,64 @@ fn write_scope_tree( ) -> io::Result<()> { let indent = depth * INDENT.len(); - let children = match scope_tree.get(&parent) { - Some(children) => children, - None => return Ok(()), - }; - - for &child in children { - let data = &mir.source_scopes[child]; - assert_eq!(data.parent_scope, Some(parent)); - writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?; + // Local variable types (including the user's name in a comment). + for (local, local_decl) in body.local_decls.iter_enumerated() { + if (1..body.arg_count+1).contains(&local.index()) { + // Skip over argument locals, they're printed in the signature. + continue; + } - // User variable types (including the user's name in a comment). - for local in mir.vars_iter() { - let var = &mir.local_decls[local]; - let (name, source_info) = if var.source_info.scope == child { - (var.name.unwrap(), var.source_info) - } else { - // Not a variable or not declared in this scope. - continue; - }; + if local_decl.source_info.scope != parent { + // Not declared in this scope. + continue; + } - let mut_str = if var.mutability == Mutability::Mut { - "mut " - } else { - "" - }; + let mut_str = if local_decl.mutability == Mutability::Mut { + "mut " + } else { + "" + }; - let indent = indent + INDENT.len(); - let mut indented_var = format!( - "{0:1$}let {2}{3:?}: {4:?}", - INDENT, - indent, - mut_str, - local, - var.ty - ); - for user_ty in var.user_ty.projections() { - write!(indented_var, " as {:?}", user_ty).unwrap(); - } - indented_var.push_str(";"); - writeln!( - w, - "{0:1$} // \"{2}\" in {3}", - indented_var, - ALIGN, - name, - comment(tcx, source_info) - )?; + let mut indented_decl = format!( + "{0:1$}let {2}{3:?}: {4:?}", + INDENT, + indent, + mut_str, + local, + local_decl.ty + ); + for user_ty in local_decl.user_ty.projections() { + write!(indented_decl, " as {:?}", user_ty).unwrap(); } + indented_decl.push_str(";"); + + let local_name = if local == RETURN_PLACE { + format!(" return place") + } else if let Some(name) = local_decl.name { + format!(" \"{}\"", name) + } else { + String::new() + }; + + writeln!( + w, + "{0:1$} //{2} in {3}", + indented_decl, + ALIGN, + local_name, + comment(tcx, local_decl.source_info), + )?; + } - write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?; + let children = match scope_tree.get(&parent) { + Some(childs) => childs, + None => return Ok(()), + }; + for &child in children { + assert_eq!(body.source_scopes[child].parent_scope, Some(parent)); + writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?; + write_scope_tree(tcx, body, scope_tree, w, child, depth + 1)?; writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?; } @@ -544,18 +530,18 @@ fn write_scope_tree( /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its /// local variables (both user-defined bindings and compiler temporaries). -pub fn write_mir_intro<'a, 'gcx, 'tcx>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, +pub fn write_mir_intro<'tcx>( + tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, - mir: &Mir<'_>, + body: &Body<'_>, w: &mut dyn Write, ) -> io::Result<()> { - write_mir_sig(tcx, src, mir, w)?; + write_mir_sig(tcx, src, body, w)?; writeln!(w, "{{")?; // construct a scope tree and write it out let mut scope_tree: FxHashMap> = Default::default(); - for (index, scope_data) in mir.source_scopes.iter().enumerate() { + for (index, scope_data) in body.source_scopes.iter().enumerate() { if let Some(parent) = scope_data.parent_scope { scope_tree .entry(parent) @@ -567,18 +553,7 @@ pub fn write_mir_intro<'a, 'gcx, 'tcx>( } } - // Print return place - let indented_retptr = format!("{}let mut {:?}: {};", - INDENT, - RETURN_PLACE, - mir.local_decls[RETURN_PLACE].ty); - writeln!(w, "{0:1$} // return place", - indented_retptr, - ALIGN)?; - - write_scope_tree(tcx, mir, &scope_tree, w, OUTERMOST_SOURCE_SCOPE, 1)?; - - write_temp_decls(mir, w)?; + write_scope_tree(tcx, body, &scope_tree, w, OUTERMOST_SOURCE_SCOPE, 1)?; // Add an empty line before the first block is printed. writeln!(w, "")?; @@ -587,54 +562,55 @@ pub fn write_mir_intro<'a, 'gcx, 'tcx>( } fn write_mir_sig( - tcx: TyCtxt<'_, '_, '_>, + tcx: TyCtxt<'_>, src: MirSource<'tcx>, - mir: &Mir<'_>, + body: &Body<'_>, w: &mut dyn Write, ) -> io::Result<()> { - use rustc::hir::def::Def; + use rustc::hir::def::DefKind; trace!("write_mir_sig: {:?}", src.instance); - let descr = tcx.describe_def(src.def_id()); - let is_function = match descr { - Some(Def::Fn(_)) | Some(Def::Method(_)) | Some(Def::StructCtor(..)) => true, + let kind = tcx.def_kind(src.def_id()); + let is_function = match kind { + Some(DefKind::Fn) + | Some(DefKind::Method) + | Some(DefKind::Ctor(..)) => true, _ => tcx.is_closure(src.def_id()), }; - match (descr, src.promoted) { + match (kind, src.promoted) { (_, Some(i)) => write!(w, "{:?} in ", i)?, - (Some(Def::StructCtor(..)), _) => write!(w, "struct ")?, - (Some(Def::Const(_)), _) - | (Some(Def::AssociatedConst(_)), _) => write!(w, "const ")?, - (Some(Def::Static(_, /*is_mutbl*/false)), _) => write!(w, "static ")?, - (Some(Def::Static(_, /*is_mutbl*/true)), _) => write!(w, "static mut ")?, + (Some(DefKind::Const), _) + | (Some(DefKind::AssocConst), _) => write!(w, "const ")?, + (Some(DefKind::Static), _) => + write!(w, "static {}", if tcx.is_mutable_static(src.def_id()) { "mut " } else { "" })?, (_, _) if is_function => write!(w, "fn ")?, (None, _) => {}, // things like anon const, not an item - _ => bug!("Unexpected def description {:?}", descr), + _ => bug!("Unexpected def kind {:?}", kind), } - item_path::with_forced_impl_filename_line(|| { + ty::print::with_forced_impl_filename_line(|| { // see notes on #41697 elsewhere - write!(w, "{}", tcx.item_path_str(src.def_id())) + write!(w, " {}", tcx.def_path_str(src.def_id())) })?; if src.promoted.is_none() && is_function { write!(w, "(")?; // fn argument types. - for (i, arg) in mir.args_iter().enumerate() { + for (i, arg) in body.args_iter().enumerate() { if i != 0 { write!(w, ", ")?; } - write!(w, "{:?}: {}", Place::Base(PlaceBase::Local(arg)), mir.local_decls[arg].ty)?; + write!(w, "{:?}: {}", Place::from(arg), body.local_decls[arg].ty)?; } - write!(w, ") -> {}", mir.return_ty())?; + write!(w, ") -> {}", body.return_ty())?; } else { - assert_eq!(mir.arg_count, 0); - write!(w, ": {} =", mir.return_ty())?; + assert_eq!(body.arg_count, 0); + write!(w, ": {} =", body.return_ty())?; } - if let Some(yield_ty) = mir.yield_ty { + if let Some(yield_ty) = body.yield_ty { writeln!(w)?; writeln!(w, "yields {}", yield_ty)?; } @@ -645,36 +621,20 @@ fn write_mir_sig( Ok(()) } -fn write_temp_decls(mir: &Mir<'_>, w: &mut dyn Write) -> io::Result<()> { - // Compiler-introduced temporary types. - for temp in mir.temps_iter() { - writeln!( - w, - "{}let {}{:?}: {};", - INDENT, - if mir.local_decls[temp].mutability == Mutability::Mut {"mut "} else {""}, - temp, - mir.local_decls[temp].ty - )?; - } - - Ok(()) -} - -fn write_user_type_annotations(mir: &Mir<'_>, w: &mut dyn Write) -> io::Result<()> { - if !mir.user_type_annotations.is_empty() { +fn write_user_type_annotations(body: &Body<'_>, w: &mut dyn Write) -> io::Result<()> { + if !body.user_type_annotations.is_empty() { writeln!(w, "| User Type Annotations")?; } - for (index, annotation) in mir.user_type_annotations.iter_enumerated() { + for (index, annotation) in body.user_type_annotations.iter_enumerated() { writeln!(w, "| {:?}: {:?} at {:?}", index.index(), annotation.user_ty, annotation.span)?; } - if !mir.user_type_annotations.is_empty() { + if !body.user_type_annotations.is_empty() { writeln!(w, "|")?; } Ok(()) } -pub fn dump_mir_def_ids(tcx: TyCtxt<'_, '_, '_>, single: Option) -> Vec { +pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option) -> Vec { if let Some(i) = single { vec![i] } else { diff --git a/src/librustc_msan/Cargo.toml b/src/librustc_msan/Cargo.toml index 7d88aa59b3adb..bda4078572501 100644 --- a/src/librustc_msan/Cargo.toml +++ b/src/librustc_msan/Cargo.toml @@ -12,7 +12,7 @@ test = false [build-dependencies] build_helper = { path = "../build_helper" } -cmake = "0.1.18" +cmake = "0.1.38" [dependencies] alloc = { path = "../liballoc" } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index f96fc3b897f80..560635962995c 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -1,4 +1,4 @@ -// Validate AST before lowering it to HIR +// Validate AST before lowering it to HIR. // // This pass is supposed to catch things that fit into AST data structures, // but not permitted by the language. It runs after expansion when AST is frozen, @@ -9,53 +9,151 @@ use std::mem; use syntax::print::pprust; use rustc::lint; +use rustc::lint::builtin::{BuiltinLintDiagnostics, NESTED_IMPL_TRAIT}; use rustc::session::Session; use rustc_data_structures::fx::FxHashMap; use syntax::ast::*; use syntax::attr; +use syntax::feature_gate::is_builtin_attr; use syntax::source_map::Spanned; -use syntax::symbol::keywords; -use syntax::ptr::P; +use syntax::symbol::{kw, sym}; use syntax::visit::{self, Visitor}; use syntax::{span_err, struct_span_err, walk_list}; use syntax_ext::proc_macro_decls::is_proc_macro_attr; -use syntax_pos::Span; -use errors::Applicability; -use log::debug; +use syntax_pos::{Span, MultiSpan}; +use errors::{Applicability, FatalError}; + +#[derive(Copy, Clone, Debug)] +struct OuterImplTrait { + span: Span, + + /// rust-lang/rust#57979: a bug in original implementation caused + /// us to fail sometimes to record an outer `impl Trait`. + /// Therefore, in order to reliably issue a warning (rather than + /// an error) in the *precise* places where we are newly injecting + /// the diagnostic, we have to distinguish between the places + /// where the outer `impl Trait` has always been recorded, versus + /// the places where it has only recently started being recorded. + only_recorded_since_pull_request_57730: bool, +} + +impl OuterImplTrait { + /// This controls whether we should downgrade the nested impl + /// trait diagnostic to a warning rather than an error, based on + /// whether the outer impl trait had been improperly skipped in + /// earlier implementations of the analysis on the stable + /// compiler. + fn should_warn_instead_of_error(&self) -> bool { + self.only_recorded_since_pull_request_57730 + } +} struct AstValidator<'a> { session: &'a Session, has_proc_macro_decls: bool, has_global_allocator: bool, - // Used to ban nested `impl Trait`, e.g., `impl Into`. - // Nested `impl Trait` _is_ allowed in associated type position, - // e.g `impl Iterator` - outer_impl_trait: Option, + /// Used to ban nested `impl Trait`, e.g., `impl Into`. + /// Nested `impl Trait` _is_ allowed in associated type position, + /// e.g., `impl Iterator`. + outer_impl_trait: Option, - // Used to ban `impl Trait` in path projections like `::Item` - // or `Foo::Bar` + /// Used to ban `impl Trait` in path projections like `::Item` + /// or `Foo::Bar` is_impl_trait_banned: bool, + + /// Used to ban associated type bounds (i.e., `Type`) in + /// certain positions. + is_assoc_ty_bound_banned: bool, + + /// rust-lang/rust#57979: the ban of nested `impl Trait` was buggy + /// until PRs #57730 and #57981 landed: it would jump directly to + /// walk_ty rather than visit_ty (or skip recurring entirely for + /// impl trait in projections), and thus miss some cases. We track + /// whether we should downgrade to a warning for short-term via + /// these booleans. + warning_period_57979_didnt_record_next_impl_trait: bool, + warning_period_57979_impl_trait_in_proj: bool, } impl<'a> AstValidator<'a> { + fn with_impl_trait_in_proj_warning(&mut self, v: bool, f: impl FnOnce(&mut Self) -> T) -> T { + let old = mem::replace(&mut self.warning_period_57979_impl_trait_in_proj, v); + let ret = f(self); + self.warning_period_57979_impl_trait_in_proj = old; + ret + } + fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { let old = mem::replace(&mut self.is_impl_trait_banned, true); f(self); self.is_impl_trait_banned = old; } - fn with_impl_trait(&mut self, outer_impl_trait: Option, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.outer_impl_trait, outer_impl_trait); + fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) { + let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true); + f(self); + self.is_assoc_ty_bound_banned = old; + } + + fn with_impl_trait(&mut self, outer: Option, f: impl FnOnce(&mut Self)) { + let old = mem::replace(&mut self.outer_impl_trait, outer); f(self); self.outer_impl_trait = old; } - // Mirrors visit::walk_ty, but tracks relevant state + fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) { + match constraint.kind { + AssocTyConstraintKind::Equality { ref ty } => { + // rust-lang/rust#57979: bug in old `visit_generic_args` called + // `walk_ty` rather than `visit_ty`, skipping outer `impl Trait` + // if it happened to occur at `ty`. + if let TyKind::ImplTrait(..) = ty.node { + self.warning_period_57979_didnt_record_next_impl_trait = true; + } + } + AssocTyConstraintKind::Bound { .. } => { + if self.is_assoc_ty_bound_banned { + self.err_handler().span_err(constraint.span, + "associated type bounds are not allowed within structs, enums, or unions" + ); + } + } + } + self.visit_assoc_ty_constraint(constraint); + } + + fn visit_ty_from_generic_args(&mut self, ty: &'a Ty) { + // rust-lang/rust#57979: bug in old `visit_generic_args` called + // `walk_ty` rather than `visit_ty`, skippping outer `impl Trait` + // if it happened to occur at `ty`. + if let TyKind::ImplTrait(..) = ty.node { + self.warning_period_57979_didnt_record_next_impl_trait = true; + } + self.visit_ty(ty); + } + + fn outer_impl_trait(&mut self, span: Span) -> OuterImplTrait { + let only_recorded_since_pull_request_57730 = + self.warning_period_57979_didnt_record_next_impl_trait; + + // (This flag is designed to be set to `true`, and then only + // reach the construction point for the outer impl trait once, + // so its safe and easiest to unconditionally reset it to + // false.) + self.warning_period_57979_didnt_record_next_impl_trait = false; + + OuterImplTrait { + span, only_recorded_since_pull_request_57730, + } + } + + // Mirrors `visit::walk_ty`, but tracks relevant state. fn walk_ty(&mut self, t: &'a Ty) { match t.node { TyKind::ImplTrait(..) => { - self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) + let outer_impl_trait = self.outer_impl_trait(t.span); + self.with_impl_trait(Some(outer_impl_trait), |this| visit::walk_ty(this, t)) } TyKind::Path(ref qself, ref path) => { // We allow these: @@ -99,9 +197,9 @@ impl<'a> AstValidator<'a> { } fn check_lifetime(&self, ident: Ident) { - let valid_names = [keywords::UnderscoreLifetime.name(), - keywords::StaticLifetime.name(), - keywords::Invalid.name()]; + let valid_names = [kw::UnderscoreLifetime, + kw::StaticLifetime, + kw::Invalid]; if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names"); } @@ -114,14 +212,6 @@ impl<'a> AstValidator<'a> { } } - fn invalid_non_exhaustive_attribute(&self, variant: &Variant) { - let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive"); - if has_non_exhaustive { - self.err_handler().span_err(variant.span, - "#[non_exhaustive] is not yet supported on variants"); - } - } - fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) { if let VisibilityKind::Inherited = vis.node { return @@ -227,52 +317,27 @@ impl<'a> AstValidator<'a> { } } - /// With eRFC 2497, we need to check whether an expression is ambiguous and warn or error - /// depending on the edition, this function handles that. - fn while_if_let_ambiguity(&self, expr: &P) { - if let Some((span, op_kind)) = self.while_if_let_expr_ambiguity(&expr) { - let mut err = self.err_handler().struct_span_err( - span, &format!("ambiguous use of `{}`", op_kind.to_string()) - ); - - err.note( - "this will be a error until the `let_chains` feature is stabilized" - ); - err.note( - "see rust-lang/rust#53668 for more information" - ); - - if let Ok(snippet) = self.session.source_map().span_to_snippet(span) { - err.span_suggestion( - span, "consider adding parentheses", format!("({})", snippet), - Applicability::MachineApplicable, + fn check_fn_decl(&self, fn_decl: &FnDecl) { + fn_decl + .inputs + .iter() + .flat_map(|i| i.attrs.as_ref()) + .filter(|attr| { + let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn]; + !arr.contains(&attr.name_or_empty()) && is_builtin_attr(attr) + }) + .for_each(|attr| if attr.is_sugared_doc { + let mut err = self.err_handler().struct_span_err( + attr.span, + "documentation comments cannot be applied to function parameters" ); + err.span_label(attr.span, "doc comments are not allowed here"); + err.emit(); } - - err.emit(); - } - } - - /// With eRFC 2497 adding if-let chains, there is a requirement that the parsing of - /// `&&` and `||` in a if-let statement be unambiguous. This function returns a span and - /// a `BinOpKind` (either `&&` or `||` depending on what was ambiguous) if it is determined - /// that the current expression parsed is ambiguous and will break in future. - fn while_if_let_expr_ambiguity(&self, expr: &P) -> Option<(Span, BinOpKind)> { - debug!("while_if_let_expr_ambiguity: expr.node: {:?}", expr.node); - match &expr.node { - ExprKind::Binary(op, _, _) if op.node == BinOpKind::And || op.node == BinOpKind::Or => { - Some((expr.span, op.node)) - }, - ExprKind::Range(ref lhs, ref rhs, _) => { - let lhs_ambiguous = lhs.as_ref() - .and_then(|lhs| self.while_if_let_expr_ambiguity(lhs)); - let rhs_ambiguous = rhs.as_ref() - .and_then(|rhs| self.while_if_let_expr_ambiguity(rhs)); - - lhs_ambiguous.or(rhs_ambiguous) - } - _ => None, - } + else { + self.err_handler().span_err(attr.span, "allow, cfg, cfg_attr, deny, \ + forbid, and warn are the only allowed built-in attributes in function parameters") + }); } } @@ -282,18 +347,28 @@ enum GenericPosition { } fn validate_generics_order<'a>( + sess: &Session, handler: &errors::Handler, - generics: impl Iterator)>, + generics: impl Iterator< + Item = ( + ParamKindOrd, + Option<&'a [GenericBound]>, + Span, + Option + ), + >, pos: GenericPosition, span: Span, ) { let mut max_param: Option = None; let mut out_of_order = FxHashMap::default(); let mut param_idents = vec![]; + let mut found_type = false; + let mut found_const = false; - for (kind, span, ident) in generics { + for (kind, bounds, span, ident) in generics { if let Some(ident) = ident { - param_idents.push((kind, param_idents.len(), ident)); + param_idents.push((kind, bounds, param_idents.len(), ident)); } let max_param = &mut max_param; match max_param { @@ -303,17 +378,28 @@ fn validate_generics_order<'a>( } Some(_) | None => *max_param = Some(kind), }; + match kind { + ParamKindOrd::Type => found_type = true, + ParamKindOrd::Const => found_const = true, + _ => {} + } } let mut ordered_params = "<".to_string(); if !out_of_order.is_empty() { - param_idents.sort_by_key(|&(po, i, _)| (po, i)); + param_idents.sort_by_key(|&(po, _, i, _)| (po, i)); let mut first = true; - for (_, _, ident) in param_idents { + for (_, bounds, _, ident) in param_idents { if !first { ordered_params += ", "; } ordered_params += &ident; + if let Some(bounds) = bounds { + if !bounds.is_empty() { + ordered_params += ": "; + ordered_params += &pprust::bounds_to_string(&bounds); + } + } first = false; } } @@ -324,8 +410,8 @@ fn validate_generics_order<'a>( GenericPosition::Arg => "argument", }; - for (param_ord, (max_param, spans)) in out_of_order { - let mut err = handler.struct_span_err(spans, + for (param_ord, (max_param, spans)) in &out_of_order { + let mut err = handler.struct_span_err(spans.clone(), &format!( "{} {pos}s must be declared prior to {} {pos}s", param_ord, @@ -335,55 +421,45 @@ fn validate_generics_order<'a>( if let GenericPosition::Param = pos { err.span_suggestion( span, - &format!("reorder the {}s: lifetimes, then types, then consts", pos_str), + &format!( + "reorder the {}s: lifetimes, then types{}", + pos_str, + if sess.features_untracked().const_generics { ", then consts" } else { "" }, + ), ordered_params.clone(), Applicability::MachineApplicable, ); } err.emit(); } + + // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs + // if we don't. Const parameters and type parameters can currently conflict if they + // are out-of-order. + if !out_of_order.is_empty() && found_type && found_const { + FatalError.raise(); + } } impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_expr(&mut self, expr: &'a Expr) { - match expr.node { - ExprKind::IfLet(_, ref expr, _, _) | ExprKind::WhileLet(_, ref expr, _, _) => - self.while_if_let_ambiguity(&expr), + match &expr.node { + ExprKind::Closure(_, _, _, fn_decl, _, _) => { + self.check_fn_decl(fn_decl); + } ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => { span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target"); } - ExprKind::ObsoleteInPlace(ref place, ref val) => { - let mut err = self.err_handler().struct_span_err( - expr.span, - "emplacement syntax is obsolete (for now, anyway)", - ); - err.note( - "for more information, see \ - " - ); - match val.node { - ExprKind::Lit(ref v) if v.node.is_numeric() => { - err.span_suggestion( - place.span.between(val.span), - "if you meant to write a comparison against a negative value, add a \ - space in between `<` and `-`", - "< -".to_string(), - Applicability::MaybeIncorrect - ); - } - _ => {} - } - err.emit(); - } _ => {} } - visit::walk_expr(self, expr) + visit::walk_expr(self, expr); } fn visit_ty(&mut self, ty: &'a Ty) { match ty.node { TyKind::BareFn(ref bfty) => { + self.check_fn_decl(&bfty.decl); self.check_decl_no_pat(&bfty.decl, |span, _| { struct_span_err!(self.session, span, E0561, "patterns aren't allowed in function pointer types").emit(); @@ -406,22 +482,41 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } TyKind::ImplTrait(_, ref bounds) => { if self.is_impl_trait_banned { - struct_span_err!(self.session, ty.span, E0667, - "`impl Trait` is not allowed in path parameters").emit(); + if self.warning_period_57979_impl_trait_in_proj { + self.session.buffer_lint( + NESTED_IMPL_TRAIT, ty.id, ty.span, + "`impl Trait` is not allowed in path parameters"); + } else { + struct_span_err!(self.session, ty.span, E0667, + "`impl Trait` is not allowed in path parameters").emit(); + } } if let Some(outer_impl_trait) = self.outer_impl_trait { - struct_span_err!(self.session, ty.span, E0666, - "nested `impl Trait` is not allowed") - .span_label(outer_impl_trait, "outer `impl Trait`") - .span_label(ty.span, "nested `impl Trait` here") - .emit(); - + if outer_impl_trait.should_warn_instead_of_error() { + self.session.buffer_lint_with_diagnostic( + NESTED_IMPL_TRAIT, ty.id, ty.span, + "nested `impl Trait` is not allowed", + BuiltinLintDiagnostics::NestedImplTrait { + outer_impl_trait_span: outer_impl_trait.span, + inner_impl_trait_span: ty.span, + }); + } else { + struct_span_err!(self.session, ty.span, E0666, + "nested `impl Trait` is not allowed") + .span_label(outer_impl_trait.span, "outer `impl Trait`") + .span_label(ty.span, "nested `impl Trait` here") + .emit(); + } } + if !bounds.iter() .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) { self.err_handler().span_err(ty.span, "at least one trait must be specified"); } + + self.with_impl_trait_in_proj_warning(true, |this| this.walk_ty(ty)); + return; } _ => {} } @@ -444,7 +539,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.has_proc_macro_decls = true; } - if attr::contains_name(&item.attrs, "global_allocator") { + if attr::contains_name(&item.attrs, sym::global_allocator) { self.has_global_allocator = true; } @@ -482,10 +577,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .note("only trait implementations may be annotated with default").emit(); } } - ItemKind::Fn(_, ref header, ref generics, _) => { + ItemKind::Fn(ref decl, ref header, ref generics, _) => { + self.visit_fn_header(header); + self.check_fn_decl(decl); // We currently do not permit const generics in `const fn`, as // this is tantamount to allowing compile-time dependent typing. - self.visit_fn_header(header); if header.constness.node == Constness::Const { // Look for const generics and error if we find any. for param in &generics.params { @@ -511,7 +607,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Enum(ref def, _) => { for variant in &def.variants { - self.invalid_non_exhaustive_attribute(variant); for field in variant.node.data.fields() { self.invalid_visibility(&field.vis, None); } @@ -522,20 +617,24 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // Auto traits cannot have generics, super traits nor contain items. if !generics.params.is_empty() { struct_span_err!(self.session, item.span, E0567, - "auto traits cannot have generic parameters").emit(); + "auto traits cannot have generic parameters" + ).emit(); } if !bounds.is_empty() { struct_span_err!(self.session, item.span, E0568, - "auto traits cannot have super traits").emit(); + "auto traits cannot have super traits" + ).emit(); } if !trait_items.is_empty() { struct_span_err!(self.session, item.span, E0380, - "auto traits cannot have methods or associated items").emit(); + "auto traits cannot have methods or associated items" + ).emit(); } } self.no_questions_in_bounds(bounds, "supertraits", true); for trait_item in trait_items { if let TraitItemKind::Method(ref sig, ref block) = trait_item.node { + self.check_fn_decl(&sig.decl); self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness.node); self.check_trait_fn_not_const(sig.header.constness); if block.is_none() { @@ -556,15 +655,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Mod(_) => { // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). - attr::first_attr_value_str_by_name(&item.attrs, "path"); - if attr::contains_name(&item.attrs, "warn_directory_ownership") { + attr::first_attr_value_str_by_name(&item.attrs, sym::path); + if attr::contains_name(&item.attrs, sym::warn_directory_ownership) { let lint = lint::builtin::LEGACY_DIRECTORY_OWNERSHIP; let msg = "cannot declare a new module at this location"; self.session.buffer_lint(lint, item.id, item.span, msg); } } ItemKind::Union(ref vdata, _) => { - if !vdata.is_struct() { + if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata { self.err_handler().span_err(item.span, "tuple and unit unions are not permitted"); } @@ -573,6 +672,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { "unions cannot have zero fields"); } } + ItemKind::Existential(ref bounds, _) => { + if !bounds.iter() + .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) { + let msp = MultiSpan::from_spans(bounds.iter() + .map(|bound| bound.span()).collect()); + self.err_handler().span_err(msp, "at least one trait must be specified"); + } + } _ => {} } @@ -582,6 +689,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { match fi.node { ForeignItemKind::Fn(ref decl, _) => { + self.check_fn_decl(decl); self.check_decl_no_pat(decl, |span, _| { struct_span_err!(self.session, span, E0130, "patterns aren't allowed in foreign function declarations") @@ -594,22 +702,30 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_foreign_item(self, fi) } - // Mirrors visit::walk_generic_args, but tracks relevant state + // Mirrors `visit::walk_generic_args`, but tracks relevant state. fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) { match *generic_args { GenericArgs::AngleBracketed(ref data) => { walk_list!(self, visit_generic_arg, &data.args); - validate_generics_order(self.err_handler(), data.args.iter().map(|arg| { - (match arg { - GenericArg::Lifetime(..) => ParamKindOrd::Lifetime, - GenericArg::Type(..) => ParamKindOrd::Type, - GenericArg::Const(..) => ParamKindOrd::Const, - }, arg.span(), None) - }), GenericPosition::Arg, generic_args.span()); - // Type bindings such as `Item=impl Debug` in `Iterator` + validate_generics_order( + self.session, + self.err_handler(), + data.args.iter().map(|arg| { + (match arg { + GenericArg::Lifetime(..) => ParamKindOrd::Lifetime, + GenericArg::Type(..) => ParamKindOrd::Type, + GenericArg::Const(..) => ParamKindOrd::Const, + }, None, arg.span(), None) + }), + GenericPosition::Arg, + generic_args.span(), + ); + + // Type bindings such as `Item = impl Debug` in `Iterator` // are allowed to contain nested `impl Trait`. self.with_impl_trait(None, |this| { - walk_list!(this, visit_assoc_type_binding, &data.bindings); + walk_list!(this, visit_assoc_ty_constraint_from_generic_args, + &data.constraints); }); } GenericArgs::Parenthesized(ref data) => { @@ -617,7 +733,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let Some(ref type_) = data.output { // `-> Foo` syntax is essentially an associated type binding, // so it is also allowed to contain nested `impl Trait`. - self.with_impl_trait(None, |this| this.visit_ty(type_)); + self.with_impl_trait(None, |this| this.visit_ty_from_generic_args(type_)); } } } @@ -637,18 +753,24 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } - validate_generics_order(self.err_handler(), generics.params.iter().map(|param| { - let span = param.ident.span; - let ident = Some(param.ident.to_string()); - match ¶m.kind { - GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, span, ident), - GenericParamKind::Type { .. } => (ParamKindOrd::Type, span, ident), - GenericParamKind::Const { ref ty } => { - let ty = pprust::ty_to_string(ty); - (ParamKindOrd::Const, span, Some(format!("const {}: {}", param.ident, ty))) - } - } - }), GenericPosition::Param, generics.span); + validate_generics_order( + self.session, + self.err_handler(), + generics.params.iter().map(|param| { + let ident = Some(param.ident.to_string()); + let (kind, ident) = match ¶m.kind { + GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident), + GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident), + GenericParamKind::Const { ref ty } => { + let ty = pprust::ty_to_string(ty); + (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty))) + } + }; + (kind, Some(&*param.bounds), param.ident.span, ident) + }), + GenericPosition::Param, + generics.span, + ); for predicate in &generics.where_clause.predicates { if let WherePredicate::EqPredicate(ref predicate) = *predicate { @@ -696,6 +818,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_poly_trait_ref(self, t, m); } + fn visit_variant_data(&mut self, s: &'a VariantData, _: Ident, + _: &'a Generics, _: NodeId, _: Span) { + self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s)) + } + + fn visit_enum_def(&mut self, enum_definition: &'a EnumDef, + generics: &'a Generics, item_id: NodeId, _: Span) { + self.with_banned_assoc_ty_bound( + |this| visit::walk_enum_def(this, enum_definition, generics, item_id)) + } + fn visit_mac(&mut self, mac: &Spanned) { // when a new macro kind is added but the author forgets to set it up for expansion // because that's the only part that won't cause a compiler error @@ -704,11 +837,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { the relevant `fold_*()` method in `PlaceholderExpander`?"); } - fn visit_fn_header(&mut self, header: &'a FnHeader) { - if header.asyncness.node.is_async() && self.session.rust_2015() { - struct_span_err!(self.session, header.asyncness.span, E0670, - "`async fn` is not permitted in the 2015 edition").emit(); + fn visit_impl_item(&mut self, ii: &'a ImplItem) { + match ii.node { + ImplItemKind::Method(ref sig, _) => { + self.check_fn_decl(&sig.decl); + } + _ => {} } + visit::walk_impl_item(self, ii); } } @@ -719,6 +855,9 @@ pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) { has_global_allocator: false, outer_impl_trait: None, is_impl_trait_banned: false, + is_assoc_ty_bound_banned: false, + warning_period_57979_didnt_record_next_impl_trait: false, + warning_period_57979_impl_trait_in_proj: false, }; visit::walk_crate(&mut validator, krate); diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/error_codes.rs similarity index 100% rename from src/librustc_passes/diagnostics.rs rename to src/librustc_passes/error_codes.rs diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index c74314ce0c4b5..6936aedb9de80 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -149,7 +149,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } fn visit_arm(&mut self, a: &'v hir::Arm) { - self.record("Arm", Id::None, a); + self.record("Arm", Id::Node(a.hir_id), a); hir_visit::walk_arm(self, a) } @@ -353,9 +353,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { ast_visit::walk_path_segment(self, path_span, path_segment) } - fn visit_assoc_type_binding(&mut self, type_binding: &'v ast::TypeBinding) { - self.record("TypeBinding", Id::None, type_binding); - ast_visit::walk_assoc_type_binding(self, type_binding) + fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) { + self.record("AssocTyConstraint", Id::None, constraint); + ast_visit::walk_assoc_ty_constraint(self, constraint) } fn visit_attribute(&mut self, attr: &'v ast::Attribute) { diff --git a/src/librustc_passes/layout_test.rs b/src/librustc_passes/layout_test.rs index d21707c578b2a..8f790d1328572 100644 --- a/src/librustc_passes/layout_test.rs +++ b/src/librustc_passes/layout_test.rs @@ -7,12 +7,14 @@ use rustc::ty::layout::HasTyCtxt; use rustc::ty::layout::LayoutOf; use rustc::ty::layout::TargetDataLayout; use rustc::ty::layout::TyLayout; +use rustc::ty::layout::HasParamEnv; use rustc::ty::ParamEnv; use rustc::ty::Ty; use rustc::ty::TyCtxt; use syntax::ast::Attribute; +use syntax::symbol::sym; -pub fn test_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn test_layout<'tcx>(tcx: TyCtxt<'tcx>) { if tcx.features().rustc_attrs { // if the `rustc_attrs` feature is not enabled, don't bother testing layout tcx.hir() @@ -21,17 +23,17 @@ pub fn test_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { } } -struct VarianceTest<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct VarianceTest<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx> ItemLikeVisitor<'tcx> for VarianceTest<'a, 'tcx> { +impl ItemLikeVisitor<'tcx> for VarianceTest<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { - let item_def_id = self.tcx.hir().local_def_id(item.id); + let item_def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); if let ItemKind::Ty(..) = item.node { for attr in self.tcx.get_attrs(item_def_id).iter() { - if attr.check_name("rustc_layout") { + if attr.check_name(sym::rustc_layout) { self.dump_layout_of(item_def_id, item, attr); } } @@ -42,7 +44,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for VarianceTest<'a, 'tcx> { fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {} } -impl<'a, 'tcx> VarianceTest<'a, 'tcx> { +impl VarianceTest<'tcx> { fn dump_layout_of(&self, item_def_id: DefId, item: &hir::Item, attr: &Attribute) { let tcx = self.tcx; let param_env = self.tcx.param_env(item_def_id); @@ -53,29 +55,26 @@ impl<'a, 'tcx> VarianceTest<'a, 'tcx> { // The `..` are the names of fields to dump. let meta_items = attr.meta_item_list().unwrap_or_default(); for meta_item in meta_items { - let name = meta_item.word().map(|mi| mi.name().as_str()); - let name = name.as_ref().map(|s| &s[..]).unwrap_or(""); - - match name { - "abi" => { + match meta_item.name_or_empty() { + sym::abi => { self.tcx .sess .span_err(item.span, &format!("abi: {:?}", ty_layout.abi)); } - "align" => { + sym::align => { self.tcx .sess .span_err(item.span, &format!("align: {:?}", ty_layout.align)); } - "size" => { + sym::size => { self.tcx .sess .span_err(item.span, &format!("size: {:?}", ty_layout.size)); } - "homogeneous_aggregate" => { + sym::homogeneous_aggregate => { self.tcx.sess.span_err( item.span, &format!( @@ -86,9 +85,9 @@ impl<'a, 'tcx> VarianceTest<'a, 'tcx> { ); } - _ => { + name => { self.tcx.sess.span_err( - meta_item.span, + meta_item.span(), &format!("unrecognized field name `{}`", name), ); } @@ -105,12 +104,12 @@ impl<'a, 'tcx> VarianceTest<'a, 'tcx> { } } -struct UnwrapLayoutCx<'me, 'tcx> { - tcx: TyCtxt<'me, 'tcx, 'tcx>, +struct UnwrapLayoutCx<'tcx> { + tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, } -impl<'me, 'tcx> LayoutOf for UnwrapLayoutCx<'me, 'tcx> { +impl LayoutOf for UnwrapLayoutCx<'tcx> { type Ty = Ty<'tcx>; type TyLayout = TyLayout<'tcx>; @@ -119,13 +118,19 @@ impl<'me, 'tcx> LayoutOf for UnwrapLayoutCx<'me, 'tcx> { } } -impl<'me, 'tcx> HasTyCtxt<'tcx> for UnwrapLayoutCx<'me, 'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { +impl HasTyCtxt<'tcx> for UnwrapLayoutCx<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } } -impl<'me, 'tcx> HasDataLayout for UnwrapLayoutCx<'me, 'tcx> { +impl HasParamEnv<'tcx> for UnwrapLayoutCx<'tcx> { + fn param_env(&self) -> ParamEnv<'tcx> { + self.param_env + } +} + +impl HasDataLayout for UnwrapLayoutCx<'tcx> { fn data_layout(&self) -> &TargetDataLayout { self.tcx.data_layout() } diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index ff2e345d08401..5f3d7159be6ce 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -6,19 +6,23 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(in_band_lifetimes)] #![feature(nll)] +#![feature(bind_by_move_pattern_guards)] #![feature(rustc_diagnostic_macros)] #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] #[macro_use] extern crate rustc; use rustc::ty::query::Providers; -mod diagnostics; +mod error_codes; pub mod ast_validation; pub mod rvalue_promotion; diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index 533e043efa9d2..ed0a78b465276 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -8,7 +8,6 @@ use rustc::hir::def_id::DefId; use rustc::hir::map::Map; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::{self, Node, Destination}; -use syntax::ast; use syntax::struct_span_err; use syntax_pos::Span; use errors::Applicability; @@ -40,19 +39,13 @@ enum Context { } #[derive(Copy, Clone)] -struct CheckLoopVisitor<'a, 'hir: 'a> { +struct CheckLoopVisitor<'a, 'hir> { sess: &'a Session, hir_map: &'a Map<'hir>, cx: Context, } -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - for &module in tcx.hir().krate().modules.keys() { - tcx.ensure().check_mod_loops(tcx.hir().local_def_id(module)); - } -} - -fn check_mod_loops<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) { +fn check_mod_loops<'tcx>(tcx: TyCtxt<'tcx>, module_def_id: DefId) { tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: &tcx.hir(), @@ -105,22 +98,22 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { let loop_id = match label.target_id.into() { Ok(loop_id) => loop_id, - Err(hir::LoopIdError::OutsideLoopScope) => ast::DUMMY_NODE_ID, + Err(hir::LoopIdError::OutsideLoopScope) => hir::DUMMY_HIR_ID, Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { self.emit_unlabled_cf_in_while_condition(e.span, "break"); - ast::DUMMY_NODE_ID + hir::DUMMY_HIR_ID }, - Err(hir::LoopIdError::UnresolvedLabel) => ast::DUMMY_NODE_ID, + Err(hir::LoopIdError::UnresolvedLabel) => hir::DUMMY_HIR_ID, }; - if loop_id != ast::DUMMY_NODE_ID { + if loop_id != hir::DUMMY_HIR_ID { if let Node::Block(_) = self.hir_map.find(loop_id).unwrap() { return } } if opt_expr.is_some() { - let loop_kind = if loop_id == ast::DUMMY_NODE_ID { + let loop_kind = if loop_id == hir::DUMMY_HIR_ID { None } else { Some(match self.hir_map.expect_expr(loop_id).node { diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index 6b8e37b3b3133..bc1151974bb70 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -14,8 +14,8 @@ // - It's not possible to take the address of a static item with unsafe interior. This is enforced // by borrowck::gather_loans -use rustc::ty::cast::CastKind; -use rustc::hir::def::{Def, CtorKind}; +use rustc::ty::cast::CastTy; +use rustc::hir::def::{Res, DefKind, CtorKind}; use rustc::hir::def_id::DefId; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; @@ -25,8 +25,7 @@ use rustc::ty::query::Providers; use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::util::nodemap::{ItemLocalSet, HirIdSet}; use rustc::hir; -use rustc_data_structures::sync::Lrc; -use syntax::ast; +use syntax::symbol::sym; use syntax_pos::{Span, DUMMY_SP}; use log::debug; use Promotability::*; @@ -40,29 +39,16 @@ pub fn provide(providers: &mut Providers<'_>) { }; } -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - for &body_id in &tcx.hir().krate().body_ids { - let def_id = tcx.hir().body_owner_def_id(body_id); - tcx.const_is_rvalue_promotable_to_static(def_id); - } -} - -fn const_is_rvalue_promotable_to_static<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> bool -{ +fn const_is_rvalue_promotable_to_static<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { assert!(def_id.is_local()); - let node_id = tcx.hir().as_local_node_id(def_id) + let hir_id = tcx.hir().as_local_hir_id(def_id) .expect("rvalue_promotable_map invoked with non-local def-id"); - let body_id = tcx.hir().body_owned_by(node_id); + let body_id = tcx.hir().body_owned_by(hir_id); tcx.rvalue_promotable_map(def_id).contains(&body_id.hir_id.local_id) } -fn rvalue_promotable_map<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> Lrc -{ +fn rvalue_promotable_map<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx ItemLocalSet { let outer_def_id = tcx.closure_base_def_id(def_id); if outer_def_id != def_id { return tcx.rvalue_promotable_map(outer_def_id); @@ -80,16 +66,16 @@ fn rvalue_promotable_map<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; // `def_id` should be a `Body` owner - let node_id = tcx.hir().as_local_node_id(def_id) + let hir_id = tcx.hir().as_local_hir_id(def_id) .expect("rvalue_promotable_map invoked with non-local def-id"); - let body_id = tcx.hir().body_owned_by(node_id); + let body_id = tcx.hir().body_owned_by(hir_id); let _ = visitor.check_nested_body(body_id); - Lrc::new(visitor.result) + tcx.arena.alloc(visitor.result) } -struct CheckCrateVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct CheckCrateVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, in_fn: bool, in_static: bool, mut_rvalue_borrows: HirIdSet, @@ -134,9 +120,9 @@ impl BitOr for Promotability { } } -impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { +impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { // Returns true iff all the values of the type are promotable. - fn type_promotability(&mut self, ty: Ty<'gcx>) -> Promotability { + fn type_promotability(&mut self, ty: Ty<'tcx>) -> Promotability { debug!("type_promotability({})", ty); if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) && @@ -179,7 +165,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { fn check_nested_body(&mut self, body_id: hir::BodyId) -> Promotability { let item_id = self.tcx.hir().body_owner(body_id); - let item_def_id = self.tcx.hir().local_def_id(item_id); + let item_def_id = self.tcx.hir().local_def_id_from_hir_id(item_id); let outer_in_fn = self.in_fn; let outer_tables = self.tables; @@ -207,8 +193,15 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { let param_env = self.param_env; let region_scope_tree = self.tcx.region_scope_tree(item_def_id); let tables = self.tables; - euv::ExprUseVisitor::new(self, tcx, param_env, ®ion_scope_tree, tables, None) - .consume_body(body); + euv::ExprUseVisitor::new( + self, + tcx, + item_def_id, + param_env, + ®ion_scope_tree, + tables, + None, + ).consume_body(body); let body_promotable = self.check_expr(&body.value); self.in_fn = outer_in_fn; @@ -319,32 +312,32 @@ fn check_expr_kind<'a, 'tcx>( hir::ExprKind::Cast(ref from, _) => { let expr_promotability = v.check_expr(from); debug!("Checking const cast(id={})", from.hir_id); - match v.tables.cast_kinds().get(from.hir_id) { - None => { - v.tcx.sess.delay_span_bug(e.span, "no kind for cast"); - NotPromotable - }, - Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => { - NotPromotable - } - _ => expr_promotability + let cast_in = CastTy::from_ty(v.tables.expr_ty(from)); + let cast_out = CastTy::from_ty(v.tables.expr_ty(e)); + match (cast_in, cast_out) { + (Some(CastTy::FnPtr), Some(CastTy::Int(_))) | + (Some(CastTy::Ptr(_)), Some(CastTy::Int(_))) => NotPromotable, + (_, _) => expr_promotability } } hir::ExprKind::Path(ref qpath) => { - let def = v.tables.qpath_def(qpath, e.hir_id); - match def { - Def::VariantCtor(..) | Def::StructCtor(..) | - Def::Fn(..) | Def::Method(..) | Def::SelfCtor(..) => Promotable, + let res = v.tables.qpath_res(qpath, e.hir_id); + match res { + Res::Def(DefKind::Ctor(..), _) + | Res::Def(DefKind::Fn, _) + | Res::Def(DefKind::Method, _) + | Res::SelfCtor(..) => + Promotable, // References to a static that are themselves within a static // are inherently promotable with the exception // of "#[thread_local]" statics, which may not // outlive the current function - Def::Static(did, _) => { + Res::Def(DefKind::Static, did) => { if v.in_static { for attr in &v.tcx.get_attrs(did)[..] { - if attr.check_name("thread_local") { + if attr.check_name(sym::thread_local) { debug!("Reference to Static(id={:?}) is unpromotable \ due to a #[thread_local] attribute", did); return NotPromotable; @@ -358,8 +351,8 @@ fn check_expr_kind<'a, 'tcx>( } } - Def::Const(did) | - Def::AssociatedConst(did) => { + Res::Def(DefKind::Const, did) | + Res::Def(DefKind::AssocConst, did) => { let promotable = if v.tcx.trait_of_item(did).is_some() { // Don't peek inside trait associated constants. NotPromotable @@ -393,16 +386,15 @@ fn check_expr_kind<'a, 'tcx>( } // The callee is an arbitrary expression, it doesn't necessarily have a definition. let def = if let hir::ExprKind::Path(ref qpath) = callee.node { - v.tables.qpath_def(qpath, callee.hir_id) + v.tables.qpath_res(qpath, callee.hir_id) } else { - Def::Err + Res::Err }; let def_result = match def { - Def::StructCtor(_, CtorKind::Fn) | - Def::VariantCtor(_, CtorKind::Fn) | - Def::SelfCtor(..) => Promotable, - Def::Fn(did) => v.handle_const_fn_call(did), - Def::Method(did) => { + Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | + Res::SelfCtor(..) => Promotable, + Res::Def(DefKind::Fn, did) => v.handle_const_fn_call(did), + Res::Def(DefKind::Method, did) => { match v.tcx.associated_item(did).container { ty::ImplContainer(_) => v.handle_const_fn_call(did), ty::TraitContainer(_) => NotPromotable, @@ -417,8 +409,7 @@ fn check_expr_kind<'a, 'tcx>( for index in hirvec.iter() { method_call_result &= v.check_expr(index); } - if let Some(def) = v.tables.type_dependent_defs().get(e.hir_id) { - let def_id = def.def_id(); + if let Some(def_id) = v.tables.type_dependent_def_id(e.hir_id) { match v.tcx.associated_item(def_id).container { ty::ImplContainer(_) => method_call_result & v.handle_const_fn_call(def_id), ty::TraitContainer(_) => NotPromotable, @@ -449,17 +440,19 @@ fn check_expr_kind<'a, 'tcx>( hir::ExprKind::Err => Promotable, hir::ExprKind::AddrOf(_, ref expr) | - hir::ExprKind::Repeat(ref expr, _) => { + hir::ExprKind::Repeat(ref expr, _) | + hir::ExprKind::Type(ref expr, _) | + hir::ExprKind::DropTemps(ref expr) => { v.check_expr(&expr) } hir::ExprKind::Closure(_capture_clause, ref _box_fn_decl, body_id, _span, _option_generator_movability) => { let nested_body_promotable = v.check_nested_body(body_id); - let node_id = v.tcx.hir().hir_to_node_id(e.hir_id); // Paths in constant contexts cannot refer to local variables, // as there are none, and thus closures can't have upvars there. - if v.tcx.with_freevars(node_id, |fv| !fv.is_empty()) { + let closure_def_id = v.tcx.hir().local_def_id_from_hir_id(e.hir_id); + if !v.tcx.upvars(closure_def_id).map_or(true, |v| v.is_empty()) { NotPromotable } else { nested_body_promotable @@ -497,10 +490,6 @@ fn check_expr_kind<'a, 'tcx>( array_result } - hir::ExprKind::Type(ref expr, ref _ty) => { - v.check_expr(&expr) - } - hir::ExprKind::Tup(ref hirvec) => { let mut tup_result = Promotable; for index in hirvec.iter() { @@ -509,7 +498,6 @@ fn check_expr_kind<'a, 'tcx>( tup_result } - // Conditional control flow (possible to implement). hir::ExprKind::Match(ref expr, ref hirvec_arm, ref _match_source) => { // Compute the most demanding borrow from all the arms' @@ -532,15 +520,6 @@ fn check_expr_kind<'a, 'tcx>( NotPromotable } - hir::ExprKind::If(ref lhs, ref rhs, ref option_expr) => { - let _ = v.check_expr(lhs); - let _ = v.check_expr(rhs); - if let Some(ref expr) = option_expr { - let _ = v.check_expr(&expr); - } - NotPromotable - } - // Loops (not very meaningful in constants). hir::ExprKind::While(ref expr, ref box_block, ref _option_label) => { let _ = v.check_expr(expr); @@ -566,7 +545,7 @@ fn check_expr_kind<'a, 'tcx>( } // Generator expressions - hir::ExprKind::Yield(ref expr) => { + hir::ExprKind::Yield(ref expr, _) => { let _ = v.check_expr(&expr); NotPromotable } @@ -598,12 +577,8 @@ fn check_adjustments<'a, 'tcx>( while let Some(adjustment) = adjustments.next() { match adjustment.kind { Adjust::NeverToAny | - Adjust::ReifyFnPointer | - Adjust::UnsafeFnPointer | - Adjust::ClosureFnPointer | - Adjust::MutToConstPointer | - Adjust::Borrow(_) | - Adjust::Unsize => {} + Adjust::Pointer(_) | + Adjust::Borrow(_) => {} Adjust::Deref(_) => { if let Some(next_adjustment) = adjustments.peek() { @@ -618,7 +593,7 @@ fn check_adjustments<'a, 'tcx>( Promotable } -impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> { +impl<'a, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'tcx> { fn consume(&mut self, _consume_id: hir::HirId, _consume_span: Span, @@ -677,7 +652,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> { } } - fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) {} + fn decl_without_init(&mut self, _id: hir::HirId, _span: Span) {} fn mutate(&mut self, _assignment_id: hir::HirId, _assignment_span: Span, diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs index c1ba4d7b3d867..d3ac597160fd6 100644 --- a/src/librustc_plugin/build.rs +++ b/src/librustc_plugin/build.rs @@ -1,7 +1,7 @@ //! Used by `rustc` when compiling a plugin crate. -use syntax::ast; use syntax::attr; +use syntax::symbol::sym; use syntax_pos::Span; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; @@ -10,15 +10,14 @@ use rustc::ty::TyCtxt; use rustc::ty::query::Providers; struct RegistrarFinder { - registrars: Vec<(ast::NodeId, Span)> , + registrars: Vec<(hir::HirId, Span)> , } impl<'v> ItemLikeVisitor<'v> for RegistrarFinder { fn visit_item(&mut self, item: &hir::Item) { if let hir::ItemKind::Fn(..) = item.node { - if attr::contains_name(&item.attrs, - "plugin_registrar") { - self.registrars.push((item.id, item.span)); + if attr::contains_name(&item.attrs, sym::plugin_registrar) { + self.registrars.push((item.hir_id, item.span)); } } } @@ -31,14 +30,11 @@ impl<'v> ItemLikeVisitor<'v> for RegistrarFinder { } /// Finds the function marked with `#[plugin_registrar]`, if any. -pub fn find_plugin_registrar<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> Option { +pub fn find_plugin_registrar<'tcx>(tcx: TyCtxt<'tcx>) -> Option { tcx.plugin_registrar_fn(LOCAL_CRATE) } -fn plugin_registrar_fn<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, - cnum: CrateNum, -) -> Option { +fn plugin_registrar_fn<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> Option { assert_eq!(cnum, LOCAL_CRATE); let mut finder = RegistrarFinder { registrars: Vec::new() }; @@ -47,8 +43,8 @@ fn plugin_registrar_fn<'tcx>( match finder.registrars.len() { 0 => None, 1 => { - let (node_id, _) = finder.registrars.pop().unwrap(); - Some(tcx.hir().local_def_id(node_id)) + let (hir_id, _) = finder.registrars.pop().unwrap(); + Some(tcx.hir().local_def_id_from_hir_id(hir_id)) }, _ => { let diagnostic = tcx.sess.diagnostic(); diff --git a/src/librustc_plugin/diagnostics.rs b/src/librustc_plugin/error_codes.rs similarity index 100% rename from src/librustc_plugin/diagnostics.rs rename to src/librustc_plugin/error_codes.rs diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index 351ba7f04d3b1..cb6f8ebd82e4e 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -47,8 +47,9 @@ //! #![plugin(myplugin)] //! ``` //! -//! See the [`plugin` feature](../unstable-book/language-features/plugin.html) of -//! the Unstable Book for more examples. +//! See the [`plugin` +//! feature](https://doc.rust-lang.org/nightly/unstable-book/language-features/plugin.html) +//! of the Unstable Book for more examples. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] @@ -61,7 +62,7 @@ pub use registry::Registry; -mod diagnostics; +mod error_codes; pub mod registry; pub mod load; pub mod build; diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 1b88cf05f40d5..4481892bcf244 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -10,7 +10,8 @@ use std::env; use std::mem; use std::path::PathBuf; use syntax::ast; -use syntax::span_err; +use syntax::struct_span_err; +use syntax::symbol::{Symbol, kw, sym}; use syntax_pos::{Span, DUMMY_SP}; /// Pointer to a registrar function. @@ -28,8 +29,10 @@ struct PluginLoader<'a> { plugins: Vec, } -fn call_malformed_plugin_attribute(a: &Session, b: Span) { - span_err!(a, b, E0498, "malformed plugin attribute"); +fn call_malformed_plugin_attribute(sess: &Session, span: Span) { + struct_span_err!(sess, span, E0498, "malformed `plugin` attribute") + .span_label(span, "malformed attribute") + .emit(); } /// Read plugin metadata and dynamically load registrar functions. @@ -45,7 +48,7 @@ pub fn load_plugins(sess: &Session, // the feature enabled will result in an error later... if sess.features_untracked().plugin { for attr in &krate.attrs { - if !attr.check_name("plugin") { + if !attr.check_name(sym::plugin) { continue; } @@ -56,12 +59,12 @@ pub fn load_plugins(sess: &Session, for plugin in plugins { // plugins must have a name and can't be key = value - match plugin.name() { - Some(name) if !plugin.is_value_str() => { - let args = plugin.meta_item_list().map(ToOwned::to_owned); - loader.load_plugin(plugin.span, &name.as_str(), args.unwrap_or_default()); - }, - _ => call_malformed_plugin_attribute(sess, attr.span), + let name = plugin.name_or_empty(); + if name != kw::Invalid && !plugin.is_value_str() { + let args = plugin.meta_item_list().map(ToOwned::to_owned); + loader.load_plugin(plugin.span(), name, args.unwrap_or_default()); + } else { + call_malformed_plugin_attribute(sess, attr.span); } } } @@ -69,7 +72,7 @@ pub fn load_plugins(sess: &Session, if let Some(plugins) = addl_plugins { for plugin in plugins { - loader.load_plugin(DUMMY_SP, &plugin, vec![]); + loader.load_plugin(DUMMY_SP, Symbol::intern(&plugin), vec![]); } } @@ -85,7 +88,7 @@ impl<'a> PluginLoader<'a> { } } - fn load_plugin(&mut self, span: Span, name: &str, args: Vec) { + fn load_plugin(&mut self, span: Span, name: Symbol, args: Vec) { let registrar = self.reader.find_plugin_registrar(span, name); if let Some((lib, disambiguator)) = registrar { diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 5c5b6f232b271..16d484e2a98f2 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -4,10 +4,9 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint}; use rustc::session::Session; use rustc::util::nodemap::FxHashMap; -use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT}; +use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, NamedSyntaxExtension}; use syntax::ext::base::MacroExpanderFn; -use syntax::ext::hygiene; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax::ast; use syntax::feature_gate::AttributeType; use syntax_pos::Span; @@ -49,7 +48,7 @@ pub struct Registry<'a> { pub llvm_passes: Vec, #[doc(hidden)] - pub attributes: Vec<(String, AttributeType)>, + pub attributes: Vec<(Symbol, AttributeType)>, } impl<'a> Registry<'a> { @@ -85,53 +84,25 @@ impl<'a> Registry<'a> { /// Register a syntax extension of any kind. /// /// This is the most general hook into `libsyntax`'s expansion behavior. - pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) { - if name == "macro_rules" { + pub fn register_syntax_extension(&mut self, name: ast::Name, mut extension: SyntaxExtension) { + if name == sym::macro_rules { panic!("user-defined macros may not be named `macro_rules`"); } - self.syntax_exts.push((name, match extension { - NormalTT { - expander, - def_info: _, - allow_internal_unstable, - allow_internal_unsafe, - local_inner_macros, - unstable_feature, - edition, - } => { - let nid = ast::CRATE_NODE_ID; - NormalTT { - expander, - def_info: Some((nid, self.krate_span)), - allow_internal_unstable, - allow_internal_unsafe, - local_inner_macros, - unstable_feature, - edition, - } - } - IdentTT { expander, span: _, allow_internal_unstable } => { - IdentTT { expander, span: Some(self.krate_span), allow_internal_unstable } - } - _ => extension, - })); + if extension.def_info.is_none() { + extension.def_info = Some((ast::CRATE_NODE_ID, self.krate_span)); + } + self.syntax_exts.push((name, extension)); } /// Register a macro of the usual kind. /// /// This is a convenience wrapper for `register_syntax_extension`. - /// It builds for you a `NormalTT` that calls `expander`, + /// It builds for you a `SyntaxExtensionKind::LegacyBang` that calls `expander`, /// and also takes care of interning the macro's name. pub fn register_macro(&mut self, name: &str, expander: MacroExpanderFn) { - self.register_syntax_extension(Symbol::intern(name), NormalTT { - expander: Box::new(expander), - def_info: None, - allow_internal_unstable: None, - allow_internal_unsafe: false, - local_inner_macros: false, - unstable_feature: None, - edition: hygiene::default_edition(), - }); + let kind = SyntaxExtensionKind::LegacyBang(Box::new(expander)); + let ext = SyntaxExtension::default(kind, self.sess.edition()); + self.register_syntax_extension(Symbol::intern(name), ext); } /// Register a compiler lint pass. @@ -169,7 +140,7 @@ impl<'a> Registry<'a> { /// Registered attributes will bypass the `custom_attribute` feature gate. /// `Whitelisted` attributes will additionally not trigger the `unused_attribute` /// lint. `CrateLevel` attributes will not be allowed on anything other than a crate. - pub fn register_attribute(&mut self, name: String, ty: AttributeType) { + pub fn register_attribute(&mut self, name: Symbol, ty: AttributeType) { self.attributes.push((name, ty)); } } diff --git a/src/librustc_privacy/diagnostics.rs b/src/librustc_privacy/error_codes.rs similarity index 100% rename from src/librustc_privacy/diagnostics.rs rename to src/librustc_privacy/error_codes.rs diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 4a73f86ef6fe9..3e98200e53274 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1,7 +1,10 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] +#![feature(in_band_lifetimes)] #![feature(nll)] #![feature(rustc_diagnostic_macros)] @@ -10,8 +13,8 @@ #[macro_use] extern crate syntax; use rustc::bug; -use rustc::hir::{self, Node, PatKind, AssociatedItemKind}; -use rustc::hir::def::Def; +use rustc::hir::{self, Node, PatKind, AssocItemKind}; +use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::DeepVisitor; @@ -23,16 +26,15 @@ use rustc::ty::query::Providers; use rustc::ty::subst::InternalSubsts; use rustc::util::nodemap::HirIdSet; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sync::Lrc; -use syntax::ast::{self, DUMMY_NODE_ID, Ident}; +use syntax::ast::Ident; use syntax::attr; -use syntax::symbol::keywords; +use syntax::symbol::{kw, sym}; use syntax_pos::Span; use std::{cmp, fmt, mem}; use std::marker::PhantomData; -mod diagnostics; +mod error_codes; //////////////////////////////////////////////////////////////////////////////// /// Generic infrastructure used to implement specific visitors below. @@ -46,14 +48,14 @@ mod diagnostics; /// First, it doesn't have overridable `fn visit_trait_ref`, so we have to catch trait `DefId`s /// manually. Second, it doesn't visit some type components like signatures of fn types, or traits /// in `impl Trait`, see individual comments in `DefIdVisitorSkeleton::visit_ty`. -trait DefIdVisitor<'a, 'tcx: 'a> { - fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>; +trait DefIdVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx>; fn shallow(&self) -> bool { false } fn skip_assoc_tys(&self) -> bool { false } fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool; /// Not overridden, but used to actually visit types and traits. - fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'a, 'tcx, Self> { + fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> { DefIdVisitorSkeleton { def_id_visitor: self, visited_opaque_tys: Default::default(), @@ -66,21 +68,23 @@ trait DefIdVisitor<'a, 'tcx: 'a> { fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool { self.skeleton().visit_trait(trait_ref) } - fn visit_predicates(&mut self, predicates: Lrc>) -> bool { + fn visit_predicates(&mut self, predicates: &ty::GenericPredicates<'tcx>) -> bool { self.skeleton().visit_predicates(predicates) } } -struct DefIdVisitorSkeleton<'v, 'a, 'tcx, V> - where V: DefIdVisitor<'a, 'tcx> + ?Sized +struct DefIdVisitorSkeleton<'v, 'tcx, V> +where + V: DefIdVisitor<'tcx> + ?Sized, { def_id_visitor: &'v mut V, visited_opaque_tys: FxHashSet, - dummy: PhantomData>, + dummy: PhantomData>, } -impl<'a, 'tcx, V> DefIdVisitorSkeleton<'_, 'a, 'tcx, V> - where V: DefIdVisitor<'a, 'tcx> + ?Sized +impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V> +where + V: DefIdVisitor<'tcx> + ?Sized, { fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool { let TraitRef { def_id, substs } = trait_ref; @@ -88,8 +92,8 @@ impl<'a, 'tcx, V> DefIdVisitorSkeleton<'_, 'a, 'tcx, V> (!self.def_id_visitor.shallow() && substs.visit_with(self)) } - fn visit_predicates(&mut self, predicates: Lrc>) -> bool { - let ty::GenericPredicates { parent: _, predicates } = &*predicates; + fn visit_predicates(&mut self, predicates: &ty::GenericPredicates<'tcx>) -> bool { + let ty::GenericPredicates { parent: _, predicates } = predicates; for (predicate, _span) in predicates { match predicate { ty::Predicate::Trait(poly_predicate) => { @@ -122,8 +126,9 @@ impl<'a, 'tcx, V> DefIdVisitorSkeleton<'_, 'a, 'tcx, V> } } -impl<'a, 'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'a, 'tcx, V> - where V: DefIdVisitor<'a, 'tcx> + ?Sized +impl<'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'tcx, V> +where + V: DefIdVisitor<'tcx> + ?Sized, { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { let tcx = self.def_id_visitor.tcx(); @@ -134,7 +139,7 @@ impl<'a, 'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'a, 'tcx, V> ty::FnDef(def_id, ..) | ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => { - if self.def_id_visitor.visit_def_id(def_id, "type", ty) { + if self.def_id_visitor.visit_def_id(def_id, "type", &ty) { return true; } if self.def_id_visitor.shallow() { @@ -218,66 +223,100 @@ impl<'a, 'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'a, 'tcx, V> } } -fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> (ty::Visibility, Span, &'static str) { - match tcx.hir().as_local_node_id(def_id) { - Some(node_id) => { - let vis = match tcx.hir().get(node_id) { +fn def_id_visibility<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> (ty::Visibility, Span, &'static str) { + match tcx.hir().as_local_hir_id(def_id) { + Some(hir_id) => { + let vis = match tcx.hir().get(hir_id) { Node::Item(item) => &item.vis, Node::ForeignItem(foreign_item) => &foreign_item.vis, Node::TraitItem(..) | Node::Variant(..) => { - return def_id_visibility(tcx, tcx.hir().get_parent_did(node_id)); + return def_id_visibility(tcx, tcx.hir().get_parent_did(hir_id)); } Node::ImplItem(impl_item) => { - match tcx.hir().get(tcx.hir().get_parent(node_id)) { + match tcx.hir().get(tcx.hir().get_parent_item(hir_id)) { Node::Item(item) => match &item.node { hir::ItemKind::Impl(.., None, _, _) => &impl_item.vis, hir::ItemKind::Impl(.., Some(trait_ref), _, _) - => return def_id_visibility(tcx, trait_ref.path.def.def_id()), + => return def_id_visibility(tcx, trait_ref.path.res.def_id()), kind => bug!("unexpected item kind: {:?}", kind), } node => bug!("unexpected node kind: {:?}", node), } } - Node::StructCtor(vdata) => { - let struct_node_id = tcx.hir().get_parent(node_id); - let item = match tcx.hir().get(struct_node_id) { - Node::Item(item) => item, - node => bug!("unexpected node kind: {:?}", node), - }; - let (mut ctor_vis, mut span, mut descr) = - (ty::Visibility::from_hir(&item.vis, struct_node_id, tcx), - item.vis.span, item.vis.node.descr()); - for field in vdata.fields() { - let field_vis = ty::Visibility::from_hir(&field.vis, node_id, tcx); - if ctor_vis.is_at_least(field_vis, tcx) { - ctor_vis = field_vis; - span = field.vis.span; - descr = field.vis.node.descr(); + Node::Ctor(vdata) => { + let parent_hir_id = tcx.hir().get_parent_node(hir_id); + match tcx.hir().get(parent_hir_id) { + Node::Variant(..) => { + let parent_did = tcx.hir().local_def_id_from_hir_id(parent_hir_id); + let (mut ctor_vis, mut span, mut descr) = def_id_visibility( + tcx, parent_did, + ); + + let adt_def = tcx.adt_def(tcx.hir().get_parent_did(hir_id)); + let ctor_did = tcx.hir().local_def_id_from_hir_id( + vdata.ctor_hir_id().unwrap()); + let variant = adt_def.variant_with_ctor_id(ctor_did); + + if variant.is_field_list_non_exhaustive() && + ctor_vis == ty::Visibility::Public + { + ctor_vis = ty::Visibility::Restricted( + DefId::local(CRATE_DEF_INDEX)); + let attrs = tcx.get_attrs(variant.def_id); + span = attr::find_by_name(&attrs, sym::non_exhaustive) + .unwrap().span; + descr = "crate-visible"; + } + + return (ctor_vis, span, descr); } - } + Node::Item(..) => { + let item = match tcx.hir().get(parent_hir_id) { + Node::Item(item) => item, + node => bug!("unexpected node kind: {:?}", node), + }; + let (mut ctor_vis, mut span, mut descr) = + (ty::Visibility::from_hir(&item.vis, parent_hir_id, tcx), + item.vis.span, item.vis.node.descr()); + for field in vdata.fields() { + let field_vis = ty::Visibility::from_hir(&field.vis, hir_id, tcx); + if ctor_vis.is_at_least(field_vis, tcx) { + ctor_vis = field_vis; + span = field.vis.span; + descr = field.vis.node.descr(); + } + } - // If the structure is marked as non_exhaustive then lower the - // visibility to within the crate. - if ctor_vis == ty::Visibility::Public { - let adt_def = tcx.adt_def(tcx.hir().get_parent_did(node_id)); - if adt_def.non_enum_variant().is_field_list_non_exhaustive() { - ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); - span = attr::find_by_name(&item.attrs, "non_exhaustive").unwrap().span; - descr = "crate-visible"; + // If the structure is marked as non_exhaustive then lower the + // visibility to within the crate. + if ctor_vis == ty::Visibility::Public { + let adt_def = + tcx.adt_def(tcx.hir().get_parent_did(hir_id)); + if adt_def.non_enum_variant().is_field_list_non_exhaustive() { + ctor_vis = + ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); + span = attr::find_by_name(&item.attrs, sym::non_exhaustive) + .unwrap().span; + descr = "crate-visible"; + } + } + + return (ctor_vis, span, descr); } + node => bug!("unexpected node kind: {:?}", node), } - - return (ctor_vis, span, descr); } Node::Expr(expr) => { return (ty::Visibility::Restricted( - tcx.hir().get_module_parent_by_hir_id(expr.hir_id)), + tcx.hir().get_module_parent(expr.hir_id)), expr.span, "private") } node => bug!("unexpected node kind: {:?}", node) }; - (ty::Visibility::from_hir(vis, node_id, tcx), vis.span, vis.node.descr()) + (ty::Visibility::from_hir(vis, hir_id, tcx), vis.span, vis.node.descr()) } None => { let vis = tcx.visibility(def_id); @@ -289,16 +328,16 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) // Set the correct `TypeckTables` for the given `item_id` (or an empty table if // there is no `TypeckTables` for the item). -fn item_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - hir_id: hir::HirId, - empty_tables: &'a ty::TypeckTables<'tcx>) - -> &'a ty::TypeckTables<'tcx> { +fn item_tables<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + hir_id: hir::HirId, + empty_tables: &'a ty::TypeckTables<'tcx>, +) -> &'a ty::TypeckTables<'tcx> { let def_id = tcx.hir().local_def_id_from_hir_id(hir_id); if tcx.has_typeck_tables(def_id) { tcx.typeck_tables_of(def_id) } else { empty_tables } } -fn min<'a, 'tcx>(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::Visibility { +fn min<'tcx>(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'tcx>) -> ty::Visibility { if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 } } @@ -308,12 +347,12 @@ fn min<'a, 'tcx>(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'a, 'tc /// This is done so that `private_in_public` warnings can be turned into hard errors /// in crates that have been updated to use pub(restricted). //////////////////////////////////////////////////////////////////////////////// -struct PubRestrictedVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct PubRestrictedVisitor<'tcx> { + tcx: TyCtxt<'tcx>, has_pub_restricted: bool, } -impl<'a, 'tcx> Visitor<'tcx> for PubRestrictedVisitor<'a, 'tcx> { +impl Visitor<'tcx> for PubRestrictedVisitor<'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::All(&self.tcx.hir()) } @@ -327,13 +366,13 @@ impl<'a, 'tcx> Visitor<'tcx> for PubRestrictedVisitor<'a, 'tcx> { //////////////////////////////////////////////////////////////////////////////// struct FindMin<'a, 'tcx, VL: VisibilityLike> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, access_levels: &'a AccessLevels, min: VL, } -impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'a, 'tcx> for FindMin<'a, 'tcx, VL> { - fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx } +impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } fn shallow(&self) -> bool { VL::SHALLOW } fn skip_assoc_tys(&self) -> bool { true } fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool { @@ -349,10 +388,13 @@ trait VisibilityLike: Sized { // Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to // associated types for which we can't determine visibility precisely. - fn of_impl<'a, 'tcx>(node_id: ast::NodeId, tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &'a AccessLevels) -> Self { + fn of_impl<'a, 'tcx>( + hir_id: hir::HirId, + tcx: TyCtxt<'tcx>, + access_levels: &'a AccessLevels, + ) -> Self { let mut find = FindMin { tcx, access_levels, min: Self::MAX }; - let def_id = tcx.hir().local_def_id(node_id); + let def_id = tcx.hir().local_def_id_from_hir_id(hir_id); find.visit(tcx.type_of(def_id)); if let Some(trait_ref) = tcx.impl_trait_ref(def_id) { find.visit_trait(trait_ref); @@ -379,8 +421,8 @@ impl VisibilityLike for Option { // (which require reaching the `DefId`s in them). const SHALLOW: bool = true; fn new_min<'a, 'tcx>(find: &FindMin<'a, 'tcx, Self>, def_id: DefId) -> Self { - cmp::min(if let Some(node_id) = find.tcx.hir().as_local_node_id(def_id) { - find.access_levels.map.get(&node_id).cloned() + cmp::min(if let Some(hir_id) = find.tcx.hir().as_local_hir_id(def_id) { + find.access_levels.map.get(&hir_id).cloned() } else { Self::MAX }, find.min) @@ -391,8 +433,8 @@ impl VisibilityLike for Option { /// The embargo visitor, used to determine the exports of the AST. //////////////////////////////////////////////////////////////////////////////// -struct EmbargoVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct EmbargoVisitor<'tcx> { + tcx: TyCtxt<'tcx>, // Accessibility levels for reachable nodes. access_levels: AccessLevels, @@ -402,19 +444,19 @@ struct EmbargoVisitor<'a, 'tcx: 'a> { changed: bool, } -struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> { +struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> { access_level: Option, item_def_id: DefId, - ev: &'b mut EmbargoVisitor<'a, 'tcx>, + ev: &'a mut EmbargoVisitor<'tcx>, } -impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { - fn get(&self, id: ast::NodeId) -> Option { +impl EmbargoVisitor<'tcx> { + fn get(&self, id: hir::HirId) -> Option { self.access_levels.map.get(&id).cloned() } // Updates node level and returns the updated level. - fn update(&mut self, id: ast::NodeId, level: Option) -> Option { + fn update(&mut self, id: hir::HirId, level: Option) -> Option { let old_level = self.get(id); // Accessibility levels can only grow. if level > old_level { @@ -426,11 +468,14 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { } } - fn reach(&mut self, item_id: ast::NodeId, access_level: Option) - -> ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> { + fn reach( + &mut self, + item_id: hir::HirId, + access_level: Option, + ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { ReachEverythingInTheInterfaceVisitor { access_level: cmp::min(access_level, Some(AccessLevel::Reachable)), - item_def_id: self.tcx.hir().local_def_id(item_id), + item_def_id: self.tcx.hir().local_def_id_from_hir_id(item_id), ev: self, } } @@ -440,7 +485,7 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { /// to update the visibility of the intermediate use so that it isn't linted /// by `unreachable_pub`. /// - /// This isn't trivial as `path.def` has the `DefId` of the eventual target + /// This isn't trivial as `path.res` has the `DefId` of the eventual target /// of the use statement not of the next intermediate use statement. /// /// To do this, consider the last two segments of the path to our intermediate @@ -453,18 +498,18 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { /// namespaces. See . fn update_visibility_of_intermediate_use_statements(&mut self, segments: &[hir::PathSegment]) { if let Some([module, segment]) = segments.rchunks_exact(2).next() { - if let Some(item) = module.def - .and_then(|def| def.mod_def_id()) + if let Some(item) = module.res + .and_then(|res| res.mod_def_id()) .and_then(|def_id| self.tcx.hir().as_local_hir_id(def_id)) - .map(|module_hir_id| self.tcx.hir().expect_item_by_hir_id(module_hir_id)) + .map(|module_hir_id| self.tcx.hir().expect_item(module_hir_id)) { if let hir::ItemKind::Mod(m) = &item.node { for item_id in m.item_ids.as_ref() { let item = self.tcx.hir().expect_item(item_id.id); - let def_id = self.tcx.hir().local_def_id(item_id.id); + let def_id = self.tcx.hir().local_def_id_from_hir_id(item_id.id); if !self.tcx.hygienic_eq(segment.ident, item.ident, def_id) { continue; } if let hir::ItemKind::Use(..) = item.node { - self.update(item.id, Some(AccessLevel::Exported)); + self.update(item.hir_id, Some(AccessLevel::Exported)); } } } @@ -473,7 +518,7 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { +impl Visitor<'tcx> for EmbargoVisitor<'tcx> { /// We want to visit items in the context of their containing /// module and so forth, so supply a crate for doing a deep walk. fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { @@ -483,7 +528,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { let inherited_item_level = match item.node { hir::ItemKind::Impl(..) => - Option::::of_impl(item.id, self.tcx, &self.access_levels), + Option::::of_impl(item.hir_id, self.tcx, &self.access_levels), // Foreign modules inherit level from parents. hir::ItemKind::ForeignMod(..) => self.prev_level, // Other `pub` items inherit levels from parents. @@ -498,44 +543,47 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { }; // Update level of the item itself. - let item_level = self.update(item.id, inherited_item_level); + let item_level = self.update(item.hir_id, inherited_item_level); // Update levels of nested things. match item.node { hir::ItemKind::Enum(ref def, _) => { for variant in &def.variants { - let variant_level = self.update(variant.node.data.id(), item_level); + let variant_level = self.update(variant.node.id, item_level); + if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() { + self.update(ctor_hir_id, item_level); + } for field in variant.node.data.fields() { - self.update(field.id, variant_level); + self.update(field.hir_id, variant_level); } } } hir::ItemKind::Impl(.., ref trait_ref, _, ref impl_item_refs) => { for impl_item_ref in impl_item_refs { if trait_ref.is_some() || impl_item_ref.vis.node.is_pub() { - self.update(impl_item_ref.id.node_id, item_level); + self.update(impl_item_ref.id.hir_id, item_level); } } } hir::ItemKind::Trait(.., ref trait_item_refs) => { for trait_item_ref in trait_item_refs { - self.update(trait_item_ref.id.node_id, item_level); + self.update(trait_item_ref.id.hir_id, item_level); } } hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => { - if !def.is_struct() { - self.update(def.id(), item_level); + if let Some(ctor_hir_id) = def.ctor_hir_id() { + self.update(ctor_hir_id, item_level); } for field in def.fields() { if field.vis.node.is_pub() { - self.update(field.id, item_level); + self.update(field.hir_id, item_level); } } } hir::ItemKind::ForeignMod(ref foreign_mod) => { for foreign_item in &foreign_mod.items { if foreign_item.vis.node.is_pub() { - self.update(foreign_item.id, item_level); + self.update(foreign_item.hir_id, item_level); } } } @@ -572,24 +620,24 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time // reachable if they are returned via `impl Trait`, even from private functions. let exist_level = cmp::max(item_level, Some(AccessLevel::ReachableFromImplTrait)); - self.reach(item.id, exist_level).generics().predicates().ty(); + self.reach(item.hir_id, exist_level).generics().predicates().ty(); } // Visit everything. hir::ItemKind::Const(..) | hir::ItemKind::Static(..) | hir::ItemKind::Fn(..) | hir::ItemKind::Ty(..) => { if item_level.is_some() { - self.reach(item.id, item_level).generics().predicates().ty(); + self.reach(item.hir_id, item_level).generics().predicates().ty(); } } hir::ItemKind::Trait(.., ref trait_item_refs) => { if item_level.is_some() { - self.reach(item.id, item_level).generics().predicates(); + self.reach(item.hir_id, item_level).generics().predicates(); for trait_item_ref in trait_item_refs { - let mut reach = self.reach(trait_item_ref.id.node_id, item_level); + let mut reach = self.reach(trait_item_ref.id.hir_id, item_level); reach.generics().predicates(); - if trait_item_ref.kind == AssociatedItemKind::Type && + if trait_item_ref.kind == AssocItemKind::Type && !trait_item_ref.defaultness.has_value() { // No type to visit. } else { @@ -600,18 +648,18 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } hir::ItemKind::TraitAlias(..) => { if item_level.is_some() { - self.reach(item.id, item_level).generics().predicates(); + self.reach(item.hir_id, item_level).generics().predicates(); } } // Visit everything except for private impl items. hir::ItemKind::Impl(.., ref impl_item_refs) => { if item_level.is_some() { - self.reach(item.id, item_level).generics().predicates().ty().trait_ref(); + self.reach(item.hir_id, item_level).generics().predicates().ty().trait_ref(); for impl_item_ref in impl_item_refs { - let impl_item_level = self.get(impl_item_ref.id.node_id); + let impl_item_level = self.get(impl_item_ref.id.hir_id); if impl_item_level.is_some() { - self.reach(impl_item_ref.id.node_id, impl_item_level) + self.reach(impl_item_ref.id.hir_id, impl_item_level) .generics().predicates().ty(); } } @@ -621,26 +669,26 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { // Visit everything, but enum variants have their own levels. hir::ItemKind::Enum(ref def, _) => { if item_level.is_some() { - self.reach(item.id, item_level).generics().predicates(); + self.reach(item.hir_id, item_level).generics().predicates(); } for variant in &def.variants { - let variant_level = self.get(variant.node.data.id()); + let variant_level = self.get(variant.node.id); if variant_level.is_some() { for field in variant.node.data.fields() { - self.reach(field.id, variant_level).ty(); + self.reach(field.hir_id, variant_level).ty(); } // Corner case: if the variant is reachable, but its // enum is not, make the enum reachable as well. - self.update(item.id, variant_level); + self.update(item.hir_id, variant_level); } } } // Visit everything, but foreign items have their own levels. hir::ItemKind::ForeignMod(ref foreign_mod) => { for foreign_item in &foreign_mod.items { - let foreign_item_level = self.get(foreign_item.id); + let foreign_item_level = self.get(foreign_item.hir_id); if foreign_item_level.is_some() { - self.reach(foreign_item.id, foreign_item_level) + self.reach(foreign_item.hir_id, foreign_item_level) .generics().predicates().ty(); } } @@ -649,11 +697,11 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { if item_level.is_some() { - self.reach(item.id, item_level).generics().predicates(); + self.reach(item.hir_id, item_level).generics().predicates(); for field in struct_def.fields() { - let field_level = self.get(field.id); + let field_level = self.get(field.hir_id); if field_level.is_some() { - self.reach(field.id, field_level).ty(); + self.reach(field.hir_id, field_level).ty(); } } } @@ -682,9 +730,9 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { if let Some(exports) = self.tcx.module_exports(def_id) { for export in exports.iter() { if export.vis == ty::Visibility::Public { - if let Some(def_id) = export.def.opt_def_id() { - if let Some(node_id) = self.tcx.hir().as_local_node_id(def_id) { - self.update(node_id, Some(AccessLevel::Exported)); + if let Some(def_id) = export.res.opt_def_id() { + if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) { + self.update(hir_id, Some(AccessLevel::Exported)); } } } @@ -696,10 +744,8 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) { - let node_id = self.tcx.hir().hir_to_node_id(md.hir_id); - if md.legacy { - self.update(node_id, Some(AccessLevel::Public)); + self.update(md.hir_id, Some(AccessLevel::Public)); return } @@ -707,15 +753,15 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { self.tcx, self.tcx.hir().local_def_id_from_hir_id(md.hir_id) ).unwrap(); - let mut module_id = self.tcx.hir().as_local_node_id(module_did).unwrap(); + let mut module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap(); let level = if md.vis.node.is_pub() { self.get(module_id) } else { None }; - let level = self.update(node_id, level); + let level = self.update(md.hir_id, level); if level.is_none() { return } loop { - let module = if module_id == ast::CRATE_NODE_ID { + let module = if module_id == hir::CRATE_HIR_ID { &self.tcx.hir().krate().module } else if let hir::ItemKind::Mod(ref module) = self.tcx.hir().expect_item(module_id).node { @@ -726,16 +772,16 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { for id in &module.item_ids { self.update(id.id, level); } - let def_id = self.tcx.hir().local_def_id(module_id); + let def_id = self.tcx.hir().local_def_id_from_hir_id(module_id); if let Some(exports) = self.tcx.module_exports(def_id) { for export in exports.iter() { - if let Some(node_id) = self.tcx.hir().as_local_node_id(export.def.def_id()) { - self.update(node_id, level); + if let Some(hir_id) = self.tcx.hir().as_local_hir_id(export.res.def_id()) { + self.update(hir_id, level); } } } - if module_id == ast::CRATE_NODE_ID { + if module_id == hir::CRATE_HIR_ID { break } module_id = self.tcx.hir().get_parent_node(module_id); @@ -743,16 +789,19 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> { +impl ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { fn generics(&mut self) -> &mut Self { for param in &self.ev.tcx.generics_of(self.item_def_id).params { match param.kind { + GenericParamDefKind::Lifetime => {} GenericParamDefKind::Type { has_default, .. } => { if has_default { self.visit(self.ev.tcx.type_of(param.def_id)); } } - GenericParamDefKind::Lifetime => {} + GenericParamDefKind::Const => { + self.visit(self.ev.tcx.type_of(param.def_id)); + } } } self @@ -776,11 +825,11 @@ impl<'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> { } } -impl<'a, 'tcx> DefIdVisitor<'a, 'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> { - fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.ev.tcx } +impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.ev.tcx } fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool { - if let Some(node_id) = self.ev.tcx.hir().as_local_node_id(def_id) { - self.ev.update(node_id, self.access_level); + if let Some(hir_id) = self.ev.tcx.hir().as_local_hir_id(def_id) { + self.ev.update(hir_id, self.access_level); } false } @@ -793,10 +842,10 @@ impl<'a, 'tcx> DefIdVisitor<'a, 'tcx> for ReachEverythingInTheInterfaceVisitor<' /// This pass performs remaining checks for fields in struct expressions and patterns. ////////////////////////////////////////////////////////////////////////////////////// -struct NamePrivacyVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct NamePrivacyVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, tables: &'a ty::TypeckTables<'tcx>, - current_item: ast::NodeId, + current_item: hir::HirId, empty_tables: &'a ty::TypeckTables<'tcx>, } @@ -807,12 +856,12 @@ impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> { span: Span, // span of the field pattern, e.g., `x: 0` def: &'tcx ty::AdtDef, // definition of the struct or enum field: &'tcx ty::FieldDef) { // definition of the field - let ident = Ident::new(keywords::Invalid.name(), use_ctxt); - let current_hir = self.tcx.hir().node_to_hir_id(self.current_item); - let def_id = self.tcx.adjust_ident(ident, def.did, current_hir).1; + let ident = Ident::new(kw::Invalid, use_ctxt); + let current_hir = self.current_item; + let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did, current_hir).1; if !def.is_enum() && !field.vis.is_accessible_from(def_id, self.tcx) { struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private", - field.ident, def.variant_descr(), self.tcx.item_path_str(def.did)) + field.ident, def.variant_descr(), self.tcx.def_path_str(def.did)) .span_label(span, format!("field `{}` is private", field.ident)) .emit(); } @@ -839,7 +888,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item) { - let orig_current_item = mem::replace(&mut self.current_item, item.id); + let orig_current_item = mem::replace(&mut self.current_item, item.hir_id); let orig_tables = mem::replace(&mut self.tables, item_tables(self.tcx, item.hir_id, self.empty_tables)); intravisit::walk_item(self, item); @@ -864,9 +913,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprKind::Struct(ref qpath, ref fields, ref base) => { - let def = self.tables.qpath_def(qpath, expr.hir_id); + let res = self.tables.qpath_res(qpath, expr.hir_id); let adt = self.tables.expr_ty(expr).ty_adt_def().unwrap(); - let variant = adt.variant_of_def(def); + let variant = adt.variant_of_res(res); if let Some(ref base) = *base { // If the expression uses FRU we need to make sure all the unmentioned fields // are checked for privacy (RFC 736). Rather than computing the set of @@ -898,9 +947,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { fn visit_pat(&mut self, pat: &'tcx hir::Pat) { match pat.node { PatKind::Struct(ref qpath, ref fields, _) => { - let def = self.tables.qpath_def(qpath, pat.hir_id); + let res = self.tables.qpath_res(qpath, pat.hir_id); let adt = self.tables.pat_ty(pat).ty_adt_def().unwrap(); - let variant = adt.variant_of_def(def); + let variant = adt.variant_of_res(res); for field in fields { let use_ctxt = field.node.ident.span; let index = self.tcx.field_index(field.node.hir_id, self.tables); @@ -920,8 +969,8 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { /// Checks are performed on "semantic" types regardless of names and their hygiene. //////////////////////////////////////////////////////////////////////////////////////////// -struct TypePrivacyVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct TypePrivacyVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, tables: &'a ty::TypeckTables<'tcx>, current_item: DefId, in_body: bool, @@ -1004,12 +1053,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { if !self.in_body { // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE. // The traits' privacy in bodies is already checked as a part of trait object types. - let (principal, projections) = - rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref); + let (principal, bounds) = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref); if self.visit_trait(*principal.skip_binder()) { return; } - for (poly_predicate, _) in projections { + for (poly_predicate, _) in bounds.projection_bounds { let tcx = self.tcx; if self.visit(poly_predicate.skip_binder().ty) || self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) { @@ -1037,8 +1085,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { hir::ExprKind::MethodCall(_, span, _) => { // Method calls have to be checked specially. self.span = span; - if let Some(def) = self.tables.type_dependent_defs().get(expr.hir_id) { - if self.visit(self.tcx.type_of(def.def_id())) { + if let Some(def_id) = self.tables.type_dependent_def_id(expr.hir_id) { + if self.visit(self.tcx.type_of(def_id)) { return; } } else { @@ -1059,26 +1107,30 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { // more code internal visibility at link time. (Access to private functions // is already prohibited by type privacy for function types.) fn visit_qpath(&mut self, qpath: &'tcx hir::QPath, id: hir::HirId, span: Span) { - let def = match *qpath { - hir::QPath::Resolved(_, ref path) => match path.def { - Def::Method(..) | Def::AssociatedConst(..) | - Def::AssociatedTy(..) | Def::AssociatedExistential(..) | - Def::Static(..) => Some(path.def), - _ => None, - } - hir::QPath::TypeRelative(..) => { - self.tables.type_dependent_defs().get(id).cloned() - } + let def = match self.tables.qpath_res(qpath, id) { + Res::Def(kind, def_id) => Some((kind, def_id)), + _ => None, }; - if let Some(def) = def { - let def_id = def.def_id(); - let is_local_static = if let Def::Static(..) = def { def_id.is_local() } else { false }; + let def = def.filter(|(kind, _)| { + match kind { + DefKind::Method + | DefKind::AssocConst + | DefKind::AssocTy + | DefKind::AssocExistential + | DefKind::Static => true, + _ => false, + } + }); + if let Some((kind, def_id)) = def { + let is_local_static = if let DefKind::Static = kind { + def_id.is_local() + } else { false }; if !self.item_is_accessible(def_id) && !is_local_static { let name = match *qpath { hir::QPath::Resolved(_, ref path) => path.to_string(), hir::QPath::TypeRelative(_, ref segment) => segment.ident.to_string(), }; - let msg = format!("{} `{}` is private", def.kind_name(), name); + let msg = format!("{} `{}` is private", kind.descr(), name); self.tcx.sess.span_err(span, &msg); return; } @@ -1110,8 +1162,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { // Check types in item interfaces. fn visit_item(&mut self, item: &'tcx hir::Item) { - let orig_current_item = - mem::replace(&mut self.current_item, self.tcx.hir().local_def_id(item.id)); + let orig_current_item = mem::replace(&mut self.current_item, + self.tcx.hir().local_def_id_from_hir_id(item.hir_id)); let orig_in_body = mem::replace(&mut self.in_body, false); let orig_tables = mem::replace(&mut self.tables, item_tables(self.tcx, item.hir_id, self.empty_tables)); @@ -1136,8 +1188,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> DefIdVisitor<'a, 'tcx> for TypePrivacyVisitor<'a, 'tcx> { - fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx } +impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { self.check_def_id(def_id, kind, descr) } @@ -1150,15 +1202,15 @@ impl<'a, 'tcx> DefIdVisitor<'a, 'tcx> for TypePrivacyVisitor<'a, 'tcx> { /// warnings instead of hard errors when the erroneous node is not in this old set. /////////////////////////////////////////////////////////////////////////////// -struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, access_levels: &'a AccessLevels, in_variant: bool, // Set of errors produced by this obsolete visitor. old_error_set: HirIdSet, } -struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> { +struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> { inner: &'a ObsoleteVisiblePrivateTypesVisitor<'b, 'tcx>, /// Whether the type refers to private types. contains_private: bool, @@ -1171,17 +1223,17 @@ struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> { impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { fn path_is_private_type(&self, path: &hir::Path) -> bool { - let did = match path.def { - Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => return false, - def => def.def_id(), + let did = match path.res { + Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => return false, + res => res.def_id(), }; // A path can only be private if: // it's in this crate... - if let Some(node_id) = self.tcx.hir().as_local_node_id(did) { + if let Some(hir_id) = self.tcx.hir().as_local_hir_id(did) { // .. and it corresponds to a private type in the AST (this returns // `None` for type parameters). - match self.tcx.hir().find(node_id) { + match self.tcx.hir().find(hir_id) { Some(Node::Item(ref item)) => !item.vis.node.is_pub(), Some(_) | None => false, } @@ -1190,7 +1242,7 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } } - fn trait_is_public(&self, trait_id: ast::NodeId) -> bool { + fn trait_is_public(&self, trait_id: hir::HirId) -> bool { // FIXME: this would preferably be using `exported_items`, but all // traits are exported currently (see `EmbargoVisitor.exported_trait`). self.access_levels.is_public(trait_id) @@ -1204,7 +1256,7 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } } - fn item_is_public(&self, id: &ast::NodeId, vis: &hir::Visibility) -> bool { + fn item_is_public(&self, id: &hir::HirId, vis: &hir::Visibility) -> bool { self.access_levels.is_reachable(*id) || vis.node.is_pub() } } @@ -1253,7 +1305,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { hir::ItemKind::ForeignMod(_) => {} hir::ItemKind::Trait(.., ref bounds, _) => { - if !self.trait_is_public(item.id) { + if !self.trait_is_public(item.hir_id) { return } @@ -1293,10 +1345,10 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { let not_private_trait = trait_ref.as_ref().map_or(true, // no trait counts as public trait |tr| { - let did = tr.path.def.def_id(); + let did = tr.path.res.def_id(); - if let Some(node_id) = self.tcx.hir().as_local_node_id(did) { - self.trait_is_public(node_id) + if let Some(hir_id) = self.tcx.hir().as_local_hir_id(did) { + self.trait_is_public(hir_id) } else { true // external traits must be public } @@ -1318,9 +1370,8 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { match impl_item.node { hir::ImplItemKind::Const(..) | hir::ImplItemKind::Method(..) => { - let node_id = self.tcx.hir().hir_to_node_id( - impl_item.hir_id); - self.access_levels.is_reachable(node_id) + self.access_levels.is_reachable( + impl_item_ref.id.hir_id) } hir::ImplItemKind::Existential(..) | hir::ImplItemKind::Type(_) => false, @@ -1342,11 +1393,10 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // don't erroneously report errors for private // types in private items. let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); - let node_id = self.tcx.hir().hir_to_node_id(impl_item.hir_id); match impl_item.node { hir::ImplItemKind::Const(..) | hir::ImplItemKind::Method(..) - if self.item_is_public(&node_id, &impl_item.vis) => + if self.item_is_public(&impl_item.hir_id, &impl_item.vis) => { intravisit::walk_impl_item(self, impl_item) } @@ -1387,14 +1437,14 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // methods will be visible as `Public::foo`. let mut found_pub_static = false; for impl_item_ref in impl_item_refs { - if self.item_is_public(&impl_item_ref.id.node_id, &impl_item_ref.vis) { + if self.item_is_public(&impl_item_ref.id.hir_id, &impl_item_ref.vis) { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); match impl_item_ref.kind { - AssociatedItemKind::Const => { + AssocItemKind::Const => { found_pub_static = true; intravisit::walk_impl_item(self, impl_item); } - AssociatedItemKind::Method { has_self: false } => { + AssocItemKind::Method { has_self: false } => { found_pub_static = true; intravisit::walk_impl_item(self, impl_item); } @@ -1414,7 +1464,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { hir::ItemKind::Ty(..) => return, // Not at all public, so we don't care. - _ if !self.item_is_public(&item.id, &item.vis) => { + _ if !self.item_is_public(&item.hir_id, &item.vis) => { return; } @@ -1450,7 +1500,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { - if self.access_levels.is_reachable(item.id) { + if self.access_levels.is_reachable(item.hir_id) { intravisit::walk_foreign_item(self, item) } } @@ -1468,7 +1518,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { v: &'tcx hir::Variant, g: &'tcx hir::Generics, item_id: hir::HirId) { - if self.access_levels.is_reachable(v.node.data.id()) { + if self.access_levels.is_reachable(v.node.id) { self.in_variant = true; intravisit::walk_variant(self, v, g, item_id); self.in_variant = false; @@ -1496,8 +1546,8 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { /// and traits in public interfaces. /////////////////////////////////////////////////////////////////////////////// -struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct SearchInterfaceForPrivateItemsVisitor<'tcx> { + tcx: TyCtxt<'tcx>, item_id: hir::HirId, item_def_id: DefId, span: Span, @@ -1506,19 +1556,21 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> { has_pub_restricted: bool, has_old_errors: bool, in_assoc_ty: bool, - private_crates: FxHashSet } -impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { +impl SearchInterfaceForPrivateItemsVisitor<'tcx> { fn generics(&mut self) -> &mut Self { for param in &self.tcx.generics_of(self.item_def_id).params { match param.kind { + GenericParamDefKind::Lifetime => {} GenericParamDefKind::Type { has_default, .. } => { if has_default { self.visit(self.tcx.type_of(param.def_id)); } } - GenericParamDefKind::Lifetime => {} + GenericParamDefKind::Const => { + self.visit(self.tcx.type_of(param.def_id)); + } } } self @@ -1585,30 +1637,32 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { /// 2. It comes from a private crate fn leaks_private_dep(&self, item_id: DefId) -> bool { let ret = self.required_visibility == ty::Visibility::Public && - self.private_crates.contains(&item_id.krate); + self.tcx.is_private_dep(item_id.krate); log::debug!("leaks_private_dep(item_id={:?})={}", item_id, ret); return ret; } } -impl<'a, 'tcx> DefIdVisitor<'a, 'tcx> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { - fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx } +impl DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { self.check_def_id(def_id, kind, descr) } } -struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, has_pub_restricted: bool, old_error_set: &'a HirIdSet, - private_crates: FxHashSet } impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { - fn check(&self, item_id: hir::HirId, required_visibility: ty::Visibility) - -> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { + fn check( + &self, + item_id: hir::HirId, + required_visibility: ty::Visibility, + ) -> SearchInterfaceForPrivateItemsVisitor<'tcx> { let mut has_old_errors = false; // Slow path taken only if there any errors in the crate. @@ -1620,7 +1674,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { has_old_errors = true; break; } - let parent = self.tcx.hir().get_parent_node_by_hir_id(id); + let parent = self.tcx.hir().get_parent_node(id); if parent == id { break; } @@ -1636,25 +1690,29 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { tcx: self.tcx, item_id, item_def_id: self.tcx.hir().local_def_id_from_hir_id(item_id), - span: self.tcx.hir().span_by_hir_id(item_id), + span: self.tcx.hir().span(item_id), required_visibility, has_pub_restricted: self.has_pub_restricted, has_old_errors, in_assoc_ty: false, - private_crates: self.private_crates.clone() } } - fn check_trait_or_impl_item(&self, hir_id: hir::HirId, assoc_item_kind: AssociatedItemKind, - defaultness: hir::Defaultness, vis: ty::Visibility) { + fn check_assoc_item( + &self, + hir_id: hir::HirId, + assoc_item_kind: AssocItemKind, + defaultness: hir::Defaultness, + vis: ty::Visibility, + ) { let mut check = self.check(hir_id, vis); let (check_ty, is_assoc_ty) = match assoc_item_kind { - AssociatedItemKind::Const | AssociatedItemKind::Method { .. } => (true, false), - AssociatedItemKind::Type => (defaultness.has_value(), true), + AssocItemKind::Const | AssocItemKind::Method { .. } => (true, false), + AssocItemKind::Type => (defaultness.has_value(), true), // `ty()` for existential types is the underlying type, // it's not a part of interface, so we skip it. - AssociatedItemKind::Existential => (false, true), + AssocItemKind::Existential => (false, true), }; check.in_assoc_ty = is_assoc_ty; check.generics().predicates(); @@ -1671,7 +1729,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> fn visit_item(&mut self, item: &'tcx hir::Item) { let tcx = self.tcx; - let item_visibility = ty::Visibility::from_hir(&item.vis, item.id, tcx); + let item_visibility = ty::Visibility::from_hir(&item.vis, item.hir_id, tcx); match item.node { // Crates are always public. @@ -1696,9 +1754,12 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> self.check(item.hir_id, item_visibility).generics().predicates(); for trait_item_ref in trait_item_refs { - let hir_id = tcx.hir().node_to_hir_id(trait_item_ref.id.node_id); - self.check_trait_or_impl_item(hir_id, trait_item_ref.kind, - trait_item_ref.defaultness, item_visibility); + self.check_assoc_item( + trait_item_ref.id.hir_id, + trait_item_ref.kind, + trait_item_ref.defaultness, + item_visibility, + ); } } hir::ItemKind::TraitAlias(..) => { @@ -1716,7 +1777,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> // Subitems of foreign modules have their own publicity. hir::ItemKind::ForeignMod(ref foreign_mod) => { for foreign_item in &foreign_mod.items { - let vis = ty::Visibility::from_hir(&foreign_item.vis, item.id, tcx); + let vis = ty::Visibility::from_hir(&foreign_item.vis, item.hir_id, tcx); self.check(foreign_item.hir_id, vis).generics().predicates().ty(); } } @@ -1726,7 +1787,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> self.check(item.hir_id, item_visibility).generics().predicates(); for field in struct_def.fields() { - let field_visibility = ty::Visibility::from_hir(&field.vis, item.id, tcx); + let field_visibility = ty::Visibility::from_hir(&field.vis, item.hir_id, tcx); self.check(field.hir_id, min(item_visibility, field_visibility, tcx)).ty(); } } @@ -1735,18 +1796,23 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> // A trait impl is public when both its type and its trait are public // Subitems of trait impls have inherited publicity. hir::ItemKind::Impl(.., ref trait_ref, _, ref impl_item_refs) => { - let impl_vis = ty::Visibility::of_impl(item.id, tcx, &Default::default()); + let impl_vis = ty::Visibility::of_impl(item.hir_id, tcx, &Default::default()); self.check(item.hir_id, impl_vis).generics().predicates(); for impl_item_ref in impl_item_refs { let impl_item = tcx.hir().impl_item(impl_item_ref.id); let impl_item_vis = if trait_ref.is_none() { - min(ty::Visibility::from_hir(&impl_item.vis, item.id, tcx), impl_vis, tcx) + min(ty::Visibility::from_hir(&impl_item.vis, item.hir_id, tcx), + impl_vis, + tcx) } else { impl_vis }; - let hir_id = tcx.hir().node_to_hir_id(impl_item_ref.id.node_id); - self.check_trait_or_impl_item(hir_id, impl_item_ref.kind, - impl_item_ref.defaultness, impl_item_vis); + self.check_assoc_item( + impl_item_ref.id.hir_id, + impl_item_ref.kind, + impl_item_ref.defaultness, + impl_item_vis, + ); } } } @@ -1756,28 +1822,24 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> pub fn provide(providers: &mut Providers<'_>) { *providers = Providers { privacy_access_levels, + check_private_in_public, check_mod_privacy, ..*providers }; } -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Lrc { - tcx.privacy_access_levels(LOCAL_CRATE) -} - -fn check_mod_privacy<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) { +fn check_mod_privacy<'tcx>(tcx: TyCtxt<'tcx>, module_def_id: DefId) { let empty_tables = ty::TypeckTables::empty(None); - // Check privacy of names not checked in previous compilation stages. let mut visitor = NamePrivacyVisitor { tcx, tables: &empty_tables, - current_item: DUMMY_NODE_ID, + current_item: hir::DUMMY_HIR_ID, empty_tables: &empty_tables, }; - let (module, span, node_id) = tcx.hir().get_module(module_def_id); - let hir_id = tcx.hir().node_to_hir_id(node_id); + let (module, span, hir_id) = tcx.hir().get_module(module_def_id); + intravisit::walk_mod(&mut visitor, module, hir_id); // Check privacy of explicitly written types and traits as well as @@ -1793,24 +1855,9 @@ fn check_mod_privacy<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) { intravisit::walk_mod(&mut visitor, module, hir_id); } -fn privacy_access_levels<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, - krate: CrateNum, -) -> Lrc { +fn privacy_access_levels<'tcx>(tcx: TyCtxt<'tcx>, krate: CrateNum) -> &'tcx AccessLevels { assert_eq!(krate, LOCAL_CRATE); - let krate = tcx.hir().krate(); - - for &module in krate.modules.keys() { - tcx.ensure().check_mod_privacy(tcx.hir().local_def_id(module)); - } - - let private_crates: FxHashSet = tcx.sess.opts.extern_private.iter() - .flat_map(|c| { - tcx.crates().iter().find(|&&krate| &tcx.crate_name(krate) == c).cloned() - }).collect(); - - // Build up a set of all exported items in the AST. This is a set of all // items which are reachable from external crates based on visibility. let mut visitor = EmbargoVisitor { @@ -1820,45 +1867,49 @@ fn privacy_access_levels<'tcx>( changed: false, }; loop { - intravisit::walk_crate(&mut visitor, krate); + intravisit::walk_crate(&mut visitor, tcx.hir().krate()); if visitor.changed { visitor.changed = false; } else { break } } - visitor.update(ast::CRATE_NODE_ID, Some(AccessLevel::Public)); + visitor.update(hir::CRATE_HIR_ID, Some(AccessLevel::Public)); - { - let mut visitor = ObsoleteVisiblePrivateTypesVisitor { - tcx, - access_levels: &visitor.access_levels, - in_variant: false, - old_error_set: Default::default(), - }; - intravisit::walk_crate(&mut visitor, krate); + tcx.arena.alloc(visitor.access_levels) +} +fn check_private_in_public<'tcx>(tcx: TyCtxt<'tcx>, krate: CrateNum) { + assert_eq!(krate, LOCAL_CRATE); - let has_pub_restricted = { - let mut pub_restricted_visitor = PubRestrictedVisitor { - tcx, - has_pub_restricted: false - }; - intravisit::walk_crate(&mut pub_restricted_visitor, krate); - pub_restricted_visitor.has_pub_restricted - }; + let access_levels = tcx.privacy_access_levels(LOCAL_CRATE); + + let krate = tcx.hir().krate(); + + let mut visitor = ObsoleteVisiblePrivateTypesVisitor { + tcx, + access_levels: &access_levels, + in_variant: false, + old_error_set: Default::default(), + }; + intravisit::walk_crate(&mut visitor, krate); - // Check for private types and traits in public interfaces. - let mut visitor = PrivateItemsInPublicInterfacesVisitor { + let has_pub_restricted = { + let mut pub_restricted_visitor = PubRestrictedVisitor { tcx, - has_pub_restricted, - old_error_set: &visitor.old_error_set, - private_crates + has_pub_restricted: false }; - krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor)); - } + intravisit::walk_crate(&mut pub_restricted_visitor, krate); + pub_restricted_visitor.has_pub_restricted + }; - Lrc::new(visitor.access_levels) + // Check for private types and traits in public interfaces. + let mut visitor = PrivateItemsInPublicInterfacesVisitor { + tcx, + has_pub_restricted, + old_error_set: &visitor.old_error_set, + }; + krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor)); } __build_diagnostic_array! { librustc_privacy, DIAGNOSTICS } diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 836b4ad38ca88..8e3359c775288 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -12,6 +12,7 @@ test = false [dependencies] bitflags = "1.0" +indexmap = "1" log = "0.4" syntax = { path = "../libsyntax" } rustc = { path = "../librustc" } @@ -20,3 +21,4 @@ errors = { path = "../librustc_errors", package = "rustc_errors" } syntax_pos = { path = "../libsyntax_pos" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_metadata = { path = "../librustc_metadata" } +smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 29de5308a3cdb..616728d541848 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -12,7 +12,7 @@ use crate::Namespace::{self, TypeNS, ValueNS, MacroNS}; use crate::{resolve_error, resolve_struct_error, ResolutionError}; use rustc::bug; -use rustc::hir::def::*; +use rustc::hir::def::{self, *}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; use rustc::ty; use rustc::middle::cstore::CrateStore; @@ -28,7 +28,7 @@ use syntax::ast::{Name, Ident}; use syntax::attr; use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId}; -use syntax::ast::{MetaItemKind, Mutability, StmtKind, TraitItem, TraitItemKind, Variant}; +use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind, Variant}; use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::base::Determinacy::Undetermined; use syntax::ext::hygiene::Mark; @@ -37,13 +37,15 @@ use syntax::feature_gate::is_builtin_attr; use syntax::parse::token::{self, Token}; use syntax::span_err; use syntax::std_inject::injected_crate_name; -use syntax::symbol::keywords; +use syntax::symbol::{kw, sym}; use syntax::visit::{self, Visitor}; use syntax_pos::{Span, DUMMY_SP}; use log::debug; +type Res = def::Res; + impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { @@ -56,10 +58,10 @@ impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) { } } -impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark) { +impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, Mark) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Def(self.0, false), + kind: NameBindingKind::Res(self.0, false), ambiguity: None, vis: self.1, span: self.2, @@ -70,10 +72,10 @@ impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark) { pub(crate) struct IsMacroExport; -impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark, IsMacroExport) { +impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, Mark, IsMacroExport) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Def(self.0, true), + kind: NameBindingKind::Res(self.0, true), ambiguity: None, vis: self.1, span: self.2, @@ -131,12 +133,9 @@ impl<'a> Resolver<'a> { // so prefixes are prepended with crate root segment if necessary. // The root is prepended lazily, when the first non-empty prefix or terminating glob // appears, so imports in braced groups can have roots prepended independently. - // 2015 identifiers used on global 2018 edition enter special "virtual 2015 mode", don't - // get crate root prepended, but get special treatment during in-scope resolution instead. let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false }; let crate_root = match prefix_iter.peek() { - Some(seg) if !seg.ident.is_path_segment_keyword() && - seg.ident.span.rust_2015() && self.session.rust_2015() => { + Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => { Some(seg.ident.span.ctxt()) } None if is_glob && use_tree.span.rust_2015() => { @@ -144,7 +143,7 @@ impl<'a> Resolver<'a> { } _ => None, }.map(|ctxt| Segment::from_ident(Ident::new( - keywords::PathRoot.name(), use_tree.prefix.span.shrink_to_lo().with_ctxt(ctxt) + kw::PathRoot, use_tree.prefix.span.shrink_to_lo().with_ctxt(ctxt) ))); let prefix = crate_root.into_iter().chain(prefix_iter).collect::>(); @@ -152,7 +151,7 @@ impl<'a> Resolver<'a> { let empty_for_self = |prefix: &[Segment]| { prefix.is_empty() || - prefix.len() == 1 && prefix[0].ident.name == keywords::PathRoot.name() + prefix.len() == 1 && prefix[0].ident.name == kw::PathRoot }; match use_tree.kind { ast::UseTreeKind::Simple(rename, ..) => { @@ -163,7 +162,7 @@ impl<'a> Resolver<'a> { if nested { // Correctly handle `self` - if source.ident.name == keywords::SelfLower.name() { + if source.ident.name == kw::SelfLower { type_ns_only = true; if empty_for_self(&module_path) { @@ -184,27 +183,27 @@ impl<'a> Resolver<'a> { } } else { // Disallow `self` - if source.ident.name == keywords::SelfLower.name() { + if source.ident.name == kw::SelfLower { resolve_error(self, use_tree.span, ResolutionError::SelfImportsOnlyAllowedWithin); } // Disallow `use $crate;` - if source.ident.name == keywords::DollarCrate.name() && module_path.is_empty() { + if source.ident.name == kw::DollarCrate && module_path.is_empty() { let crate_root = self.resolve_crate_root(source.ident); let crate_name = match crate_root.kind { - ModuleKind::Def(_, name) => name, + ModuleKind::Def(.., name) => name, ModuleKind::Block(..) => unreachable!(), }; // HACK(eddyb) unclear how good this is, but keeping `$crate` // in `source` breaks `src/test/compile-fail/import-crate-var.rs`, // while the current crate doesn't have a valid `crate_name`. - if crate_name != keywords::Invalid.name() { + if crate_name != kw::Invalid { // `crate_name` should not be interpreted as relative. module_path.push(Segment { ident: Ident { - name: keywords::PathRoot.name(), + name: kw::PathRoot, span: source.ident.span, }, id: Some(self.session.next_node_id()), @@ -222,7 +221,7 @@ impl<'a> Resolver<'a> { } } - if ident.name == keywords::Crate.name() { + if ident.name == kw::Crate { self.session.span_err(ident.span, "crate root imports need to be explicitly named: \ `use crate as name;`"); @@ -258,7 +257,7 @@ impl<'a> Resolver<'a> { } ast::UseTreeKind::Glob => { let subclass = GlobImport { - is_prelude: attr::contains_name(&item.attrs, "prelude_import"), + is_prelude: attr::contains_name(&item.attrs, sym::prelude_import), max_vis: Cell::new(ty::Visibility::Invisible), }; self.add_import_directive( @@ -277,7 +276,7 @@ impl<'a> Resolver<'a> { // Ensure there is at most one `self` in the list let self_spans = items.iter().filter_map(|&(ref use_tree, _)| { if let ast::UseTreeKind::Simple(..) = use_tree.kind { - if use_tree.ident().name == keywords::SelfLower.name() { + if use_tree.ident().name == kw::SelfLower { return Some(use_tree.span); } } @@ -312,10 +311,10 @@ impl<'a> Resolver<'a> { let new_span = prefix[prefix.len() - 1].ident.span; let tree = ast::UseTree { prefix: ast::Path::from_ident( - Ident::new(keywords::SelfLower.name(), new_span) + Ident::new(kw::SelfLower, new_span) ), kind: ast::UseTreeKind::Simple( - Some(Ident::new(keywords::Underscore.name().gensymed(), new_span)), + Some(Ident::new(kw::Underscore, new_span)), ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID, ), @@ -351,7 +350,7 @@ impl<'a> Resolver<'a> { } ItemKind::ExternCrate(orig_name) => { - let module = if orig_name.is_none() && ident.name == keywords::SelfLower.name() { + let module = if orig_name.is_none() && ident.name == kw::SelfLower { self.session .struct_span_err(item.span, "`extern crate self;` requires renaming") .span_suggestion( @@ -362,7 +361,7 @@ impl<'a> Resolver<'a> { ) .emit(); return; - } else if orig_name == Some(keywords::SelfLower.name()) { + } else if orig_name == Some(kw::SelfLower) { self.graph_root } else { let crate_id = self.crate_loader.process_extern_crate(item, &self.definitions); @@ -370,7 +369,7 @@ impl<'a> Resolver<'a> { }; self.populate_module_if_necessary(module); - if injected_crate_name().map_or(false, |name| ident.name == name) { + if injected_crate_name().map_or(false, |name| ident.name.as_str() == name) { self.injected_crate = Some(module); } @@ -421,14 +420,14 @@ impl<'a> Resolver<'a> { ItemKind::GlobalAsm(..) => {} - ItemKind::Mod(..) if ident == keywords::Invalid.ident() => {} // Crate root + ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root ItemKind::Mod(..) => { let def_id = self.definitions.local_def_id(item.id); - let module_kind = ModuleKind::Def(Def::Mod(def_id), ident.name); + let module_kind = ModuleKind::Def(DefKind::Mod, def_id, ident.name); let module = self.arenas.alloc_module(ModuleData { no_implicit_prelude: parent.no_implicit_prelude || { - attr::contains_name(&item.attrs, "no_implicit_prelude") + attr::contains_name(&item.attrs, sym::no_implicit_prelude) }, ..ModuleData::new(Some(parent), module_kind, def_id, expansion, item.span) }); @@ -443,33 +442,34 @@ impl<'a> Resolver<'a> { ItemKind::ForeignMod(..) => {} // These items live in the value namespace. - ItemKind::Static(_, m, _) => { - let mutbl = m == Mutability::Mutable; - let def = Def::Static(self.definitions.local_def_id(item.id), mutbl); - self.define(parent, ident, ValueNS, (def, vis, sp, expansion)); + ItemKind::Static(..) => { + let res = Res::Def(DefKind::Static, self.definitions.local_def_id(item.id)); + self.define(parent, ident, ValueNS, (res, vis, sp, expansion)); } ItemKind::Const(..) => { - let def = Def::Const(self.definitions.local_def_id(item.id)); - self.define(parent, ident, ValueNS, (def, vis, sp, expansion)); + let res = Res::Def(DefKind::Const, self.definitions.local_def_id(item.id)); + self.define(parent, ident, ValueNS, (res, vis, sp, expansion)); } ItemKind::Fn(..) => { - let def = Def::Fn(self.definitions.local_def_id(item.id)); - self.define(parent, ident, ValueNS, (def, vis, sp, expansion)); + let res = Res::Def(DefKind::Fn, self.definitions.local_def_id(item.id)); + self.define(parent, ident, ValueNS, (res, vis, sp, expansion)); // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). - if attr::contains_name(&item.attrs, "proc_macro") || - attr::contains_name(&item.attrs, "proc_macro_attribute") { - let def = Def::Macro(def.def_id(), MacroKind::ProcMacroStub); - self.define(parent, ident, MacroNS, (def, vis, sp, expansion)); + if attr::contains_name(&item.attrs, sym::proc_macro) || + attr::contains_name(&item.attrs, sym::proc_macro_attribute) { + let res = Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), res.def_id()); + self.define(parent, ident, MacroNS, (res, vis, sp, expansion)); } - if let Some(attr) = attr::find_by_name(&item.attrs, "proc_macro_derive") { + if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { if let Some(trait_attr) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { - if let Some(ident) = trait_attr.name().map(Ident::with_empty_ctxt) { - let sp = trait_attr.span; - let def = Def::Macro(def.def_id(), MacroKind::ProcMacroStub); - self.define(parent, ident, MacroNS, (def, vis, sp, expansion)); + if let Some(ident) = trait_attr.ident() { + let res = Res::Def( + DefKind::Macro(MacroKind::ProcMacroStub), + res.def_id(), + ); + self.define(parent, ident, MacroNS, (res, vis, ident.span, expansion)); } } } @@ -477,18 +477,21 @@ impl<'a> Resolver<'a> { // These items live in the type namespace. ItemKind::Ty(..) => { - let def = Def::TyAlias(self.definitions.local_def_id(item.id)); - self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); + let res = Res::Def(DefKind::TyAlias, self.definitions.local_def_id(item.id)); + self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } ItemKind::Existential(_, _) => { - let def = Def::Existential(self.definitions.local_def_id(item.id)); - self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); + let res = Res::Def(DefKind::Existential, self.definitions.local_def_id(item.id)); + self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } ItemKind::Enum(ref enum_definition, _) => { - let def = Def::Enum(self.definitions.local_def_id(item.id)); - let module_kind = ModuleKind::Def(def, ident.name); + let module_kind = ModuleKind::Def( + DefKind::Enum, + self.definitions.local_def_id(item.id), + ident.name, + ); let module = self.new_module(parent, module_kind, parent.normal_ancestor_id, @@ -502,20 +505,20 @@ impl<'a> Resolver<'a> { } ItemKind::TraitAlias(..) => { - let def = Def::TraitAlias(self.definitions.local_def_id(item.id)); - self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); + let res = Res::Def(DefKind::TraitAlias, self.definitions.local_def_id(item.id)); + self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } // These items live in both the type and value namespaces. ItemKind::Struct(ref struct_def, _) => { // Define a name in the type namespace. let def_id = self.definitions.local_def_id(item.id); - let def = Def::Struct(def_id); - self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); + let res = Res::Def(DefKind::Struct, def_id); + self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); let mut ctor_vis = vis; - let has_non_exhaustive = attr::contains_name(&item.attrs, "non_exhaustive"); + let has_non_exhaustive = attr::contains_name(&item.attrs, sym::non_exhaustive); // If the structure is marked as non_exhaustive then lower the visibility // to within the crate. @@ -536,17 +539,19 @@ impl<'a> Resolver<'a> { // If this is a tuple or unit struct, define a name // in the value namespace as well. - if !struct_def.is_struct() { - let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()), - CtorKind::from_ast(struct_def)); - self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, sp, expansion)); - self.struct_constructors.insert(def.def_id(), (ctor_def, ctor_vis)); + if let Some(ctor_node_id) = struct_def.ctor_id() { + let ctor_res = Res::Def( + DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(struct_def)), + self.definitions.local_def_id(ctor_node_id), + ); + self.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); + self.struct_constructors.insert(res.def_id(), (ctor_res, ctor_vis)); } } ItemKind::Union(ref vdata, _) => { - let def = Def::Union(self.definitions.local_def_id(item.id)); - self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); + let res = Res::Def(DefKind::Union, self.definitions.local_def_id(item.id)); + self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); // Record field names for error reporting. let field_names = vdata.fields().iter().filter_map(|field| { @@ -563,7 +568,7 @@ impl<'a> Resolver<'a> { let def_id = self.definitions.local_def_id(item.id); // Add all the items within to a new module. - let module_kind = ModuleKind::Def(Def::Trait(def_id), ident.name); + let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name); let module = self.new_module(parent, module_kind, parent.normal_ancestor_id, @@ -585,38 +590,49 @@ impl<'a> Resolver<'a> { vis: ty::Visibility, expansion: Mark) { let ident = variant.node.ident; - let def_id = self.definitions.local_def_id(variant.node.data.id()); // Define a name in the type namespace. - let def = Def::Variant(def_id); - self.define(parent, ident, TypeNS, (def, vis, variant.span, expansion)); + let def_id = self.definitions.local_def_id(variant.node.id); + let res = Res::Def(DefKind::Variant, def_id); + self.define(parent, ident, TypeNS, (res, vis, variant.span, expansion)); + + // If the variant is marked as non_exhaustive then lower the visibility to within the + // crate. + let mut ctor_vis = vis; + let has_non_exhaustive = attr::contains_name(&variant.node.attrs, sym::non_exhaustive); + if has_non_exhaustive && vis == ty::Visibility::Public { + ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); + } // Define a constructor name in the value namespace. // Braced variants, unlike structs, generate unusable names in // value namespace, they are reserved for possible future use. + // It's ok to use the variant's id as a ctor id since an + // error will be reported on any use of such resolution anyway. + let ctor_node_id = variant.node.data.ctor_id().unwrap_or(variant.node.id); + let ctor_def_id = self.definitions.local_def_id(ctor_node_id); let ctor_kind = CtorKind::from_ast(&variant.node.data); - let ctor_def = Def::VariantCtor(def_id, ctor_kind); - - self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion)); + let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id); + self.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expansion)); } /// Constructs the reduced graph for one foreign item. fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expansion: Mark) { - let (def, ns) = match item.node { + let (res, ns) = match item.node { ForeignItemKind::Fn(..) => { - (Def::Fn(self.definitions.local_def_id(item.id)), ValueNS) + (Res::Def(DefKind::Fn, self.definitions.local_def_id(item.id)), ValueNS) } - ForeignItemKind::Static(_, m) => { - (Def::Static(self.definitions.local_def_id(item.id), m), ValueNS) + ForeignItemKind::Static(..) => { + (Res::Def(DefKind::Static, self.definitions.local_def_id(item.id)), ValueNS) } ForeignItemKind::Ty => { - (Def::ForeignTy(self.definitions.local_def_id(item.id)), TypeNS) + (Res::Def(DefKind::ForeignTy, self.definitions.local_def_id(item.id)), TypeNS) } ForeignItemKind::Macro(_) => unreachable!(), }; let parent = self.current_module; let vis = self.resolve_visibility(&item.vis); - self.define(parent, item.ident, ns, (def, vis, item.span, expansion)); + self.define(parent, item.ident, ns, (res, vis, item.span, expansion)); } fn build_reduced_graph_for_block(&mut self, block: &Block, expansion: Mark) { @@ -633,40 +649,53 @@ impl<'a> Resolver<'a> { } /// Builds the reduced graph for a single item in an external crate. - fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, child: Export) { - let Export { ident, def, vis, span } = child; + fn build_reduced_graph_for_external_crate_res( + &mut self, + parent: Module<'a>, + child: Export, + ) { + let Export { ident, res, vis, span } = child; // FIXME: We shouldn't create the gensym here, it should come from metadata, // but metadata cannot encode gensyms currently, so we create it here. // This is only a guess, two equivalent idents may incorrectly get different gensyms here. let ident = ident.gensym_if_underscore(); - let def_id = def.def_id(); let expansion = Mark::root(); // FIXME(jseyfried) intercrate hygiene - match def { - Def::Mod(..) | Def::Enum(..) => { + match res { + Res::Def(kind @ DefKind::Mod, def_id) + | Res::Def(kind @ DefKind::Enum, def_id) => { let module = self.new_module(parent, - ModuleKind::Def(def, ident.name), + ModuleKind::Def(kind, def_id, ident.name), def_id, expansion, span); self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); } - Def::Variant(..) | Def::TyAlias(..) | Def::ForeignTy(..) => { - self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion)); + Res::Def(DefKind::Variant, _) + | Res::Def(DefKind::TyAlias, _) + | Res::Def(DefKind::ForeignTy, _) + | Res::Def(DefKind::Existential, _) + | Res::Def(DefKind::TraitAlias, _) + | Res::PrimTy(..) + | Res::ToolMod => { + self.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)); } - Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::VariantCtor(..) => { - self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, expansion)); + Res::Def(DefKind::Fn, _) + | Res::Def(DefKind::Static, _) + | Res::Def(DefKind::Const, _) + | Res::Def(DefKind::Ctor(CtorOf::Variant, ..), _) => { + self.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)); } - Def::StructCtor(..) => { - self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, expansion)); + Res::Def(DefKind::Ctor(CtorOf::Struct, ..), def_id) => { + self.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)); if let Some(struct_def_id) = self.cstore.def_key(def_id).parent .map(|index| DefId { krate: def_id.krate, index: index }) { - self.struct_constructors.insert(struct_def_id, (def, vis)); + self.struct_constructors.insert(struct_def_id, (res, vis)); } } - Def::Trait(..) => { - let module_kind = ModuleKind::Def(def, ident.name); + Res::Def(DefKind::Trait, def_id) => { + let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name); let module = self.new_module(parent, module_kind, parent.normal_ancestor_id, @@ -675,32 +704,31 @@ impl<'a> Resolver<'a> { self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); for child in self.cstore.item_children_untracked(def_id, self.session) { - let ns = if let Def::AssociatedTy(..) = child.def { TypeNS } else { ValueNS }; + let res = child.res.map_id(|_| panic!("unexpected id")); + let ns = if let Res::Def(DefKind::AssocTy, _) = res { + TypeNS + } else { ValueNS }; self.define(module, child.ident, ns, - (child.def, ty::Visibility::Public, DUMMY_SP, expansion)); + (res, ty::Visibility::Public, DUMMY_SP, expansion)); - if self.cstore.associated_item_cloned_untracked(child.def.def_id()) + if self.cstore.associated_item_cloned_untracked(child.res.def_id()) .method_has_self_argument { - self.has_self.insert(child.def.def_id()); + self.has_self.insert(res.def_id()); } } module.populated.set(true); } - Def::Existential(..) | - Def::TraitAlias(..) => { - self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion)); - } - Def::Struct(..) | Def::Union(..) => { - self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion)); + Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) => { + self.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)); // Record field names for error reporting. let field_names = self.cstore.struct_field_names_untracked(def_id); self.insert_field_names(def_id, field_names); } - Def::Macro(..) => { - self.define(parent, ident, MacroNS, (def, vis, DUMMY_SP, expansion)); + Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => { + self.define(parent, ident, MacroNS, (res, vis, DUMMY_SP, expansion)); } - _ => bug!("unexpected definition: {:?}", def) + _ => bug!("unexpected resolution: {:?}", res) } } @@ -722,7 +750,7 @@ impl<'a> Resolver<'a> { Some(self.get_module(DefId { index: def_key.parent.unwrap(), ..def_id }))) }; - let kind = ModuleKind::Def(Def::Mod(def_id), name.as_symbol()); + let kind = ModuleKind::Def(DefKind::Mod, def_id, name.as_symbol()); let module = self.arenas.alloc_module(ModuleData::new(parent, kind, def_id, Mark::root(), DUMMY_SP)); self.extern_module_map.insert((def_id, macros_only), module); @@ -741,13 +769,12 @@ impl<'a> Resolver<'a> { } } - pub fn get_macro(&mut self, def: Def) -> Lrc { - let def_id = match def { - Def::Macro(def_id, ..) => def_id, - Def::NonMacroAttr(attr_kind) => return Lrc::new(SyntaxExtension::NonMacroAttr { - mark_used: attr_kind == NonMacroAttrKind::Tool, - }), - _ => panic!("expected `Def::Macro` or `Def::NonMacroAttr`"), + pub fn get_macro(&mut self, res: Res) -> Lrc { + let def_id = match res { + Res::Def(DefKind::Macro(..), def_id) => def_id, + Res::NonMacroAttr(attr_kind) => + return self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool), + _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"), }; if let Some(ext) = self.macro_map.get(&def_id) { return ext.clone(); @@ -772,7 +799,8 @@ impl<'a> Resolver<'a> { if module.populated.get() { return } let def_id = module.def_id().unwrap(); for child in self.cstore.item_children_untracked(def_id, self.session) { - self.build_reduced_graph_for_external_crate_def(module, child); + let child = child.map_id(|_| panic!("unexpected id")); + self.build_reduced_graph_for_external_crate_res(module, child); } module.populated.set(true) } @@ -796,13 +824,13 @@ impl<'a> Resolver<'a> { let mut import_all = None; let mut single_imports = Vec::new(); for attr in &item.attrs { - if attr.check_name("macro_use") { + if attr.check_name(sym::macro_use) { if self.current_module.parent.is_some() { span_err!(self.session, item.span, E0468, "an `extern crate` loading macros must be at the crate root"); } if let ItemKind::ExternCrate(Some(orig_name)) = item.node { - if orig_name == keywords::SelfLower.name() { + if orig_name == kw::SelfLower { self.session.span_err(attr.span, "`macro_use` is not supported on `extern crate self`"); } @@ -815,14 +843,14 @@ impl<'a> Resolver<'a> { break; } MetaItemKind::List(nested_metas) => for nested_meta in nested_metas { - match nested_meta.word() { - Some(word) => single_imports.push((word.name(), word.span)), - None => ill_formed(nested_meta.span), + match nested_meta.ident() { + Some(ident) if nested_meta.is_word() => single_imports.push(ident), + _ => ill_formed(nested_meta.span()), } } MetaItemKind::NameValue(..) => ill_formed(meta.span), } - None => ill_formed(attr.span()), + None => ill_formed(attr.span), } } } @@ -853,23 +881,23 @@ impl<'a> Resolver<'a> { self.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing); }); } else { - for (name, span) in single_imports.iter().cloned() { - let ident = Ident::with_empty_ctxt(name); + for ident in single_imports.iter().cloned() { let result = self.resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, MacroNS, None, false, - span, + ident.span, ); if let Ok(binding) = result { - let directive = macro_use_directive(span); + let directive = macro_use_directive(ident.span); self.potentially_unused_imports.push(directive); let imported_binding = self.import(binding, directive); - self.legacy_import_macro(name, imported_binding, span, allow_shadowing); + self.legacy_import_macro(ident.name, imported_binding, + ident.span, allow_shadowing); } else { - span_err!(self.session, span, E0469, "imported macro not found"); + span_err!(self.session, ident.span, E0469, "imported macro not found"); } } } @@ -879,7 +907,7 @@ impl<'a> Resolver<'a> { /// Returns `true` if this attribute list contains `macro_use`. fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { for attr in attrs { - if attr.check_name("macro_escape") { + if attr.check_name(sym::macro_escape) { let msg = "macro_escape is a deprecated synonym for macro_use"; let mut err = self.session.struct_span_warn(attr.span, msg); if let ast::AttrStyle::Inner = attr.style { @@ -887,7 +915,7 @@ impl<'a> Resolver<'a> { } else { err.emit(); } - } else if !attr.check_name("macro_use") { + } else if !attr.check_name(sym::macro_use) { continue; } @@ -901,7 +929,7 @@ impl<'a> Resolver<'a> { } } -pub struct BuildReducedGraphVisitor<'a, 'b: 'a> { +pub struct BuildReducedGraphVisitor<'a, 'b> { pub resolver: &'a mut Resolver<'b>, pub current_legacy_scope: LegacyScope<'b>, pub expansion: Mark, @@ -1003,20 +1031,20 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { // Add the item to the trait info. let item_def_id = self.resolver.definitions.local_def_id(item.id); - let (def, ns) = match item.node { - TraitItemKind::Const(..) => (Def::AssociatedConst(item_def_id), ValueNS), + let (res, ns) = match item.node { + TraitItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS), TraitItemKind::Method(ref sig, _) => { if sig.decl.has_self() { self.resolver.has_self.insert(item_def_id); } - (Def::Method(item_def_id), ValueNS) + (Res::Def(DefKind::Method, item_def_id), ValueNS) } - TraitItemKind::Type(..) => (Def::AssociatedTy(item_def_id), TypeNS), + TraitItemKind::Type(..) => (Res::Def(DefKind::AssocTy, item_def_id), TypeNS), TraitItemKind::Macro(_) => bug!(), // handled above }; let vis = ty::Visibility::Public; - self.resolver.define(parent, item.ident, ns, (def, vis, item.span, self.expansion)); + self.resolver.define(parent, item.ident, ns, (res, vis, item.span, self.expansion)); self.resolver.current_module = parent.parent.unwrap(); // nearest normal ancestor visit::walk_trait_item(self, item); @@ -1024,7 +1052,7 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { } fn visit_token(&mut self, t: Token) { - if let Token::Interpolated(nt) = t { + if let token::Interpolated(nt) = t.kind { if let token::NtExpr(ref expr) = *nt { if let ast::ExprKind::Mac(..) = expr.node { self.visit_invoc(expr.id); diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 3b6179f78558b..4fee15c59b33d 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -48,7 +48,7 @@ impl<'a> UnusedImport<'a> { } } -struct UnusedImportCheckVisitor<'a, 'b: 'a> { +struct UnusedImportCheckVisitor<'a, 'b> { resolver: &'a mut Resolver<'b>, /// All the (so far) unused imports, grouped path list unused_imports: NodeMap>, diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 5c095994a1bbd..e93a2315ca321 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1,1672 +1,873 @@ -#![allow(non_snake_case)] - -use syntax::{register_diagnostic, register_diagnostics, register_long_diagnostics}; - -// Error messages for EXXXX errors. Each message should start and end with a -// new line, and be wrapped to 80 characters. In vim you can `:set tw=80` and -// use `gq` to wrap paragraphs. Use `:set tw=0` to disable. -register_long_diagnostics! { - -E0128: r##" -Type parameter defaults can only use parameters that occur before them. -Erroneous code example: - -```compile_fail,E0128 -struct Foo { - field1: T, - filed2: U, -} -// error: type parameters with a default cannot use forward declared -// identifiers -``` - -Since type parameters are evaluated in-order, you may be able to fix this issue -by doing: - -``` -struct Foo { - field1: T, - filed2: U, -} -``` - -Please also verify that this wasn't because of a name-clash and rename the type -parameter if so. -"##, - -E0154: r##" -#### Note: this error code is no longer emitted by the compiler. - -Imports (`use` statements) are not allowed after non-item statements, such as -variable declarations and expression statements. - -Here is an example that demonstrates the error: - -``` -fn f() { - // Variable declaration before import - let x = 0; - use std::io::Read; - // ... -} -``` - -The solution is to declare the imports at the top of the block, function, or -file. - -Here is the previous example again, with the correct order: - -``` -fn f() { - use std::io::Read; - let x = 0; - // ... -} -``` - -See the Declaration Statements section of the reference for more information -about what constitutes an Item declaration and what does not: - -https://doc.rust-lang.org/reference.html#statements -"##, - -E0251: r##" -#### Note: this error code is no longer emitted by the compiler. - -Two items of the same name cannot be imported without rebinding one of the -items under a new local name. - -An example of this error: - -``` -use foo::baz; -use bar::*; // error, do `use foo::baz as quux` instead on the previous line - -fn main() {} - -mod foo { - pub struct baz; -} - -mod bar { - pub mod baz {} -} -``` -"##, - -E0252: r##" -Two items of the same name cannot be imported without rebinding one of the -items under a new local name. - -Erroneous code example: - -```compile_fail,E0252 -use foo::baz; -use bar::baz; // error, do `use bar::baz as quux` instead - -fn main() {} - -mod foo { - pub struct baz; -} - -mod bar { - pub mod baz {} -} -``` - -You can use aliases in order to fix this error. Example: - -``` -use foo::baz as foo_baz; -use bar::baz; // ok! - -fn main() {} - -mod foo { - pub struct baz; -} - -mod bar { - pub mod baz {} -} -``` - -Or you can reference the item with its parent: - -``` -use bar::baz; - -fn main() { - let x = foo::baz; // ok! -} +use std::cmp::Reverse; + +use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use log::debug; +use rustc::hir::def::{self, DefKind, CtorKind, Namespace::*}; +use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::session::{Session, config::nightly_options}; +use syntax::ast::{self, Expr, ExprKind, Ident}; +use syntax::ext::base::MacroKind; +use syntax::symbol::{Symbol, kw}; +use syntax_pos::{BytePos, Span}; + +type Res = def::Res; + +use crate::macros::ParentScope; +use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; +use crate::{import_candidate_to_enum_paths, is_self_type, is_self_value, path_names_to_string}; +use crate::{AssocSuggestion, CrateLint, ImportSuggestion, ModuleOrUniformRoot, PathResult, + PathSource, Resolver, Segment, Suggestion}; + +impl<'a> Resolver<'a> { + /// Handles error reporting for `smart_resolve_path_fragment` function. + /// Creates base error and amends it with one short label and possibly some longer helps/notes. + pub(crate) fn smart_resolve_report_errors( + &mut self, + path: &[Segment], + span: Span, + source: PathSource<'_>, + res: Option, + ) -> (DiagnosticBuilder<'a>, Vec) { + let ident_span = path.last().map_or(span, |ident| ident.ident.span); + let ns = source.namespace(); + let is_expected = &|res| source.is_expected(res); + let is_enum_variant = &|res| { + if let Res::Def(DefKind::Variant, _) = res { true } else { false } + }; + + // Make the base error. + let expected = source.descr_expected(); + let path_str = Segment::names_to_string(path); + let item_str = path.last().unwrap().ident; + let code = source.error_code(res.is_some()); + let (base_msg, fallback_label, base_span) = if let Some(res) = res { + (format!("expected {}, found {} `{}`", expected, res.descr(), path_str), + format!("not a {}", expected), + span) + } else { + let item_span = path.last().unwrap().ident.span; + let (mod_prefix, mod_str) = if path.len() == 1 { + (String::new(), "this scope".to_string()) + } else if path.len() == 2 && path[0].ident.name == kw::PathRoot { + (String::new(), "the crate root".to_string()) + } else { + let mod_path = &path[..path.len() - 1]; + let mod_prefix = match self.resolve_path_without_parent_scope( + mod_path, Some(TypeNS), false, span, CrateLint::No + ) { + PathResult::Module(ModuleOrUniformRoot::Module(module)) => + module.def_kind(), + _ => None, + }.map_or(String::new(), |kind| format!("{} ", kind.descr())); + (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path))) + }; + (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), + format!("not found in {}", mod_str), + item_span) + }; + + let code = DiagnosticId::Error(code.into()); + let mut err = self.session.struct_span_err_with_code(base_span, &base_msg, code); + + // Emit help message for fake-self from other languages (e.g., `this` in Javascript). + if ["this", "my"].contains(&&*item_str.as_str()) + && self.self_value_is_available(path[0].ident.span, span) { + err.span_suggestion( + span, + "did you mean", + "self".to_string(), + Applicability::MaybeIncorrect, + ); + } -mod foo { - pub struct baz; -} + // Emit special messages for unresolved `Self` and `self`. + if is_self_type(path, ns) { + __diagnostic_used!(E0411); + err.code(DiagnosticId::Error("E0411".into())); + err.span_label(span, format!("`Self` is only available in impls, traits, \ + and type definitions")); + return (err, Vec::new()); + } + if is_self_value(path, ns) { + debug!("smart_resolve_path_fragment: E0424, source={:?}", source); + + __diagnostic_used!(E0424); + err.code(DiagnosticId::Error("E0424".into())); + err.span_label(span, match source { + PathSource::Pat => { + format!("`self` value is a keyword \ + and may not be bound to \ + variables or shadowed") + } + _ => { + format!("`self` value is a keyword \ + only available in methods \ + with `self` parameter") + } + }); + return (err, Vec::new()); + } -mod bar { - pub mod baz {} -} -``` -"##, + // Try to lookup name in more relaxed fashion for better error reporting. + let ident = path.last().unwrap().ident; + let candidates = self.lookup_import_candidates(ident, ns, is_expected) + .drain(..) + .filter(|ImportSuggestion { did, .. }| { + match (did, res.and_then(|res| res.opt_def_id())) { + (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did, + _ => true, + } + }) + .collect::>(); + let crate_def_id = DefId::local(CRATE_DEF_INDEX); + if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) { + let enum_candidates = + self.lookup_import_candidates(ident, ns, is_enum_variant); + let mut enum_candidates = enum_candidates.iter() + .map(|suggestion| { + import_candidate_to_enum_paths(&suggestion) + }).collect::>(); + enum_candidates.sort(); + + if !enum_candidates.is_empty() { + // Contextualize for E0412 "cannot find type", but don't belabor the point + // (that it's a variant) for E0573 "expected type, found variant". + let preamble = if res.is_none() { + let others = match enum_candidates.len() { + 1 => String::new(), + 2 => " and 1 other".to_owned(), + n => format!(" and {} others", n) + }; + format!("there is an enum variant `{}`{}; ", + enum_candidates[0].0, others) + } else { + String::new() + }; + let msg = format!("{}try using the variant's enum", preamble); + + err.span_suggestions( + span, + &msg, + enum_candidates.into_iter() + .map(|(_variant_path, enum_ty_path)| enum_ty_path) + // Variants re-exported in prelude doesn't mean `prelude::v1` is the + // type name! + // FIXME: is there a more principled way to do this that + // would work for other re-exports? + .filter(|enum_ty_path| enum_ty_path != "std::prelude::v1") + // Also write `Option` rather than `std::prelude::v1::Option`. + .map(|enum_ty_path| { + // FIXME #56861: DRY-er prelude filtering. + enum_ty_path.trim_start_matches("std::prelude::v1::").to_owned() + }), + Applicability::MachineApplicable, + ); + } + } + if path.len() == 1 && self.self_type_is_available(span) { + if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) { + let self_is_available = self.self_value_is_available(path[0].ident.span, span); + match candidate { + AssocSuggestion::Field => { + if self_is_available { + err.span_suggestion( + span, + "you might have meant to use the available field", + format!("self.{}", path_str), + Applicability::MachineApplicable, + ); + } else { + err.span_label( + span, + "a field by this name exists in `Self`", + ); + } + } + AssocSuggestion::MethodWithSelf if self_is_available => { + err.span_suggestion( + span, + "try", + format!("self.{}", path_str), + Applicability::MachineApplicable, + ); + } + AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => { + err.span_suggestion( + span, + "try", + format!("Self::{}", path_str), + Applicability::MachineApplicable, + ); + } + } + return (err, candidates); + } + } -E0253: r##" -Attempt was made to import an unimportable value. This can happen when trying -to import a method from a trait. + let mut levenshtein_worked = false; + + // Try Levenshtein algorithm. + let suggestion = self.lookup_typo_candidate(path, ns, is_expected, span); + if let Some(suggestion) = suggestion { + let msg = format!( + "{} {} with a similar name exists", + suggestion.article, suggestion.kind + ); + err.span_suggestion( + ident_span, + &msg, + suggestion.candidate.to_string(), + Applicability::MaybeIncorrect, + ); + + levenshtein_worked = true; + } -Erroneous code example: + // Try context-dependent help if relaxed lookup didn't work. + if let Some(res) = res { + if self.smart_resolve_context_dependent_help(&mut err, + span, + source, + res, + &path_str, + &fallback_label) { + return (err, candidates); + } + } -```compile_fail,E0253 -mod foo { - pub trait MyTrait { - fn do_something(); + // Fallback label. + if !levenshtein_worked { + err.span_label(base_span, fallback_label); + self.type_ascription_suggestion(&mut err, base_span); + } + (err, candidates) } -} - -use foo::MyTrait::do_something; -// error: `do_something` is not directly importable - -fn main() {} -``` - -It's invalid to directly import methods belonging to a trait or concrete type. -"##, - -E0254: r##" -Attempt was made to import an item whereas an extern crate with this name has -already been imported. - -Erroneous code example: -```compile_fail,E0254 -extern crate core; - -mod foo { - pub trait core { - fn do_something(); + fn followed_by_brace(&self, span: Span) -> (bool, Option<(Span, String)>) { + // HACK(estebank): find a better way to figure out that this was a + // parser issue where a struct literal is being used on an expression + // where a brace being opened means a block is being started. Look + // ahead for the next text to see if `span` is followed by a `{`. + let sm = self.session.source_map(); + let mut sp = span; + loop { + sp = sm.next_point(sp); + match sm.span_to_snippet(sp) { + Ok(ref snippet) => { + if snippet.chars().any(|c| { !c.is_whitespace() }) { + break; + } + } + _ => break, + } + } + let followed_by_brace = match sm.span_to_snippet(sp) { + Ok(ref snippet) if snippet == "{" => true, + _ => false, + }; + // In case this could be a struct literal that needs to be surrounded + // by parenthesis, find the appropriate span. + let mut i = 0; + let mut closing_brace = None; + loop { + sp = sm.next_point(sp); + match sm.span_to_snippet(sp) { + Ok(ref snippet) => { + if snippet == "}" { + let sp = span.to(sp); + if let Ok(snippet) = sm.span_to_snippet(sp) { + closing_brace = Some((sp, snippet)); + } + break; + } + } + _ => break, + } + i += 1; + // The bigger the span, the more likely we're incorrect -- + // bound it to 100 chars long. + if i > 100 { + break; + } + } + return (followed_by_brace, closing_brace) } -} - -use foo::core; // error: an extern crate named `core` has already - // been imported in this module - -fn main() {} -``` - -To fix this issue, you have to rename at least one of the two imports. -Example: - -``` -extern crate core as libcore; // ok! -mod foo { - pub trait core { - fn do_something(); + /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment` + /// function. + /// Returns `true` if able to provide context-dependent help. + fn smart_resolve_context_dependent_help( + &mut self, + err: &mut DiagnosticBuilder<'a>, + span: Span, + source: PathSource<'_>, + res: Res, + path_str: &str, + fallback_label: &str, + ) -> bool { + let ns = source.namespace(); + let is_expected = &|res| source.is_expected(res); + + let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.node { + ExprKind::Field(_, ident) => { + err.span_suggestion( + expr.span, + "use the path separator to refer to an item", + format!("{}::{}", path_str, ident), + Applicability::MaybeIncorrect, + ); + true + } + ExprKind::MethodCall(ref segment, ..) => { + let span = expr.span.with_hi(segment.ident.span.hi()); + err.span_suggestion( + span, + "use the path separator to refer to an item", + format!("{}::{}", path_str, segment.ident), + Applicability::MaybeIncorrect, + ); + true + } + _ => false, + }; + + let mut bad_struct_syntax_suggestion = || { + let (followed_by_brace, closing_brace) = self.followed_by_brace(span); + let mut suggested = false; + match source { + PathSource::Expr(Some(parent)) => { + suggested = path_sep(err, &parent); + } + PathSource::Expr(None) if followed_by_brace == true => { + if let Some((sp, snippet)) = closing_brace { + err.span_suggestion( + sp, + "surround the struct literal with parenthesis", + format!("({})", snippet), + Applicability::MaybeIncorrect, + ); + } else { + err.span_label( + span, // Note the parenthesis surrounding the suggestion below + format!("did you mean `({} {{ /* fields */ }})`?", path_str), + ); + } + suggested = true; + }, + _ => {} + } + if !suggested { + err.span_label( + span, + format!("did you mean `{} {{ /* fields */ }}`?", path_str), + ); + } + }; + + match (res, source) { + (Res::Def(DefKind::Macro(..), _), _) => { + err.span_suggestion( + span, + "use `!` to invoke the macro", + format!("{}!", path_str), + Applicability::MaybeIncorrect, + ); + if path_str == "try" && span.rust_2015() { + err.note("if you want the `try` keyword, you need to be in the 2018 edition"); + } + } + (Res::Def(DefKind::TyAlias, _), PathSource::Trait(_)) => { + err.span_label(span, "type aliases cannot be used as traits"); + if nightly_options::is_nightly_build() { + err.note("did you mean to use a trait alias?"); + } + } + (Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => { + if !path_sep(err, &parent) { + return false; + } + } + (Res::Def(DefKind::Enum, def_id), PathSource::TupleStruct) + | (Res::Def(DefKind::Enum, def_id), PathSource::Expr(..)) => { + if let Some(variants) = self.collect_enum_variants(def_id) { + if !variants.is_empty() { + let msg = if variants.len() == 1 { + "try using the enum's variant" + } else { + "try using one of the enum's variants" + }; + + err.span_suggestions( + span, + msg, + variants.iter().map(path_names_to_string), + Applicability::MaybeIncorrect, + ); + } + } else { + err.note("did you mean to use one of the enum's variants?"); + } + }, + (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { + if let Some((ctor_def, ctor_vis)) + = self.struct_constructors.get(&def_id).cloned() { + let accessible_ctor = self.is_accessible(ctor_vis); + if is_expected(ctor_def) && !accessible_ctor { + err.span_label( + span, + format!("constructor is not visible here due to private fields"), + ); + } + } else { + bad_struct_syntax_suggestion(); + } + } + (Res::Def(DefKind::Union, _), _) | + (Res::Def(DefKind::Variant, _), _) | + (Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _), _) if ns == ValueNS => { + bad_struct_syntax_suggestion(); + } + (Res::SelfTy(..), _) if ns == ValueNS => { + err.span_label(span, fallback_label); + err.note("can't use `Self` as a constructor, you must use the implemented struct"); + } + (Res::Def(DefKind::TyAlias, _), _) + | (Res::Def(DefKind::AssocTy, _), _) if ns == ValueNS => { + err.note("can't use a type alias as a constructor"); + } + _ => return false, + } + true } } -use foo::core; - -fn main() {} -``` -"##, - -E0255: r##" -You can't import a value whose name is the same as another value defined in the -module. - -Erroneous code example: - -```compile_fail,E0255 -use bar::foo; // error: an item named `foo` is already in scope - -fn foo() {} - -mod bar { - pub fn foo() {} -} - -fn main() {} -``` - -You can use aliases in order to fix this error. Example: - -``` -use bar::foo as bar_foo; // ok! - -fn foo() {} - -mod bar { - pub fn foo() {} -} - -fn main() {} -``` - -Or you can reference the item with its parent: - -``` -fn foo() {} - -mod bar { - pub fn foo() {} -} - -fn main() { - bar::foo(); // we get the item by referring to its parent -} -``` -"##, - -E0256: r##" -#### Note: this error code is no longer emitted by the compiler. - -You can't import a type or module when the name of the item being imported is -the same as another type or submodule defined in the module. - -An example of this error: - -```compile_fail -use foo::Bar; // error - -type Bar = u32; - -mod foo { - pub mod Bar { } -} - -fn main() {} -``` -"##, - -E0259: r##" -The name chosen for an external crate conflicts with another external crate -that has been imported into the current module. - -Erroneous code example: - -```compile_fail,E0259 -extern crate core; -extern crate std as core; - -fn main() {} -``` - -The solution is to choose a different name that doesn't conflict with any -external crate imported into the current module. - -Correct example: - -``` -extern crate core; -extern crate std as other_name; - -fn main() {} -``` -"##, - -E0260: r##" -The name for an item declaration conflicts with an external crate's name. - -Erroneous code example: - -```compile_fail,E0260 -extern crate core; - -struct core; - -fn main() {} -``` - -There are two possible solutions: - -Solution #1: Rename the item. - -``` -extern crate core; - -struct xyz; -``` - -Solution #2: Import the crate with a different name. - -``` -extern crate core as xyz; - -struct abc; -``` - -See the Declaration Statements section of the reference for more information -about what constitutes an Item declaration and what does not: - -https://doc.rust-lang.org/reference.html#statements -"##, - -E0364: r##" -Private items cannot be publicly re-exported. This error indicates that you -attempted to `pub use` a type or value that was not itself public. - -Erroneous code example: - -```compile_fail -mod foo { - const X: u32 = 1; -} - -pub use foo::X; - -fn main() {} -``` - -The solution to this problem is to ensure that the items that you are -re-exporting are themselves marked with `pub`: - -``` -mod foo { - pub const X: u32 = 1; -} - -pub use foo::X; - -fn main() {} -``` - -See the 'Use Declarations' section of the reference for more information on -this topic: - -https://doc.rust-lang.org/reference.html#use-declarations -"##, - -E0365: r##" -Private modules cannot be publicly re-exported. This error indicates that you -attempted to `pub use` a module that was not itself public. - -Erroneous code example: - -```compile_fail,E0365 -mod foo { - pub const X: u32 = 1; -} - -pub use foo as foo2; - -fn main() {} -``` - -The solution to this problem is to ensure that the module that you are -re-exporting is itself marked with `pub`: - -``` -pub mod foo { - pub const X: u32 = 1; -} - -pub use foo as foo2; - -fn main() {} -``` - -See the 'Use Declarations' section of the reference for more information -on this topic: - -https://doc.rust-lang.org/reference.html#use-declarations -"##, - -E0401: r##" -Inner items do not inherit type or const parameters from the functions -they are embedded in. - -Erroneous code example: +impl<'a, 'b> ImportResolver<'a, 'b> { + /// Adds suggestions for a path that cannot be resolved. + pub(crate) fn make_path_suggestion( + &mut self, + span: Span, + mut path: Vec, + parent_scope: &ParentScope<'b>, + ) -> Option<(Vec, Vec)> { + debug!("make_path_suggestion: span={:?} path={:?}", span, path); + + match (path.get(0), path.get(1)) { + // `{{root}}::ident::...` on both editions. + // On 2015 `{{root}}` is usually added implicitly. + (Some(fst), Some(snd)) if fst.ident.name == kw::PathRoot && + !snd.ident.is_path_segment_keyword() => {} + // `ident::...` on 2018. + (Some(fst), _) if fst.ident.span.rust_2018() && + !fst.ident.is_path_segment_keyword() => { + // Insert a placeholder that's later replaced by `self`/`super`/etc. + path.insert(0, Segment::from_ident(Ident::invalid())); + } + _ => return None, + } -```compile_fail,E0401 -fn foo(x: T) { - fn bar(y: T) { // T is defined in the "outer" function - // .. + self.make_missing_self_suggestion(span, path.clone(), parent_scope) + .or_else(|| self.make_missing_crate_suggestion(span, path.clone(), parent_scope)) + .or_else(|| self.make_missing_super_suggestion(span, path.clone(), parent_scope)) + .or_else(|| self.make_external_crate_suggestion(span, path, parent_scope)) } - bar(x); -} -``` - -Nor will this: - -```compile_fail,E0401 -fn foo(x: T) { - type MaybeT = Option; - // ... -} -``` -Or this: - -```compile_fail,E0401 -fn foo(x: T) { - struct Foo { - x: T, + /// Suggest a missing `self::` if that resolves to an correct module. + /// + /// ``` + /// | + /// LL | use foo::Bar; + /// | ^^^ did you mean `self::foo`? + /// ``` + fn make_missing_self_suggestion( + &mut self, + span: Span, + mut path: Vec, + parent_scope: &ParentScope<'b>, + ) -> Option<(Vec, Vec)> { + // Replace first ident with `self` and check if that is valid. + path[0].ident.name = kw::SelfLower; + let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); + debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result); + if let PathResult::Module(..) = result { + Some((path, Vec::new())) + } else { + None + } } - // ... -} -``` - -Items inside functions are basically just like top-level items, except -that they can only be used from the function they are in. -There are a couple of solutions for this. + /// Suggests a missing `crate::` if that resolves to an correct module. + /// + /// ``` + /// | + /// LL | use foo::Bar; + /// | ^^^ did you mean `crate::foo`? + /// ``` + fn make_missing_crate_suggestion( + &mut self, + span: Span, + mut path: Vec, + parent_scope: &ParentScope<'b>, + ) -> Option<(Vec, Vec)> { + // Replace first ident with `crate` and check if that is valid. + path[0].ident.name = kw::Crate; + let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); + debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result); + if let PathResult::Module(..) = result { + Some(( + path, + vec![ + "`use` statements changed in Rust 2018; read more at \ + ".to_string() + ], + )) + } else { + None + } + } -If the item is a function, you may use a closure: + /// Suggests a missing `super::` if that resolves to an correct module. + /// + /// ``` + /// | + /// LL | use foo::Bar; + /// | ^^^ did you mean `super::foo`? + /// ``` + fn make_missing_super_suggestion( + &mut self, + span: Span, + mut path: Vec, + parent_scope: &ParentScope<'b>, + ) -> Option<(Vec, Vec)> { + // Replace first ident with `crate` and check if that is valid. + path[0].ident.name = kw::Super; + let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); + debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result); + if let PathResult::Module(..) = result { + Some((path, Vec::new())) + } else { + None + } + } -``` -fn foo(x: T) { - let bar = |y: T| { // explicit type annotation may not be necessary - // .. - }; - bar(x); -} -``` + /// Suggests a missing external crate name if that resolves to an correct module. + /// + /// ``` + /// | + /// LL | use foobar::Baz; + /// | ^^^^^^ did you mean `baz::foobar`? + /// ``` + /// + /// Used when importing a submodule of an external crate but missing that crate's + /// name as the first part of path. + fn make_external_crate_suggestion( + &mut self, + span: Span, + mut path: Vec, + parent_scope: &ParentScope<'b>, + ) -> Option<(Vec, Vec)> { + if path[1].ident.span.rust_2015() { + return None; + } -For a generic item, you can copy over the parameters: + // Sort extern crate names in reverse order to get + // 1) some consistent ordering for emitted dignostics, and + // 2) `std` suggestions before `core` suggestions. + let mut extern_crate_names = + self.resolver.extern_prelude.iter().map(|(ident, _)| ident.name).collect::>(); + extern_crate_names.sort_by_key(|name| Reverse(name.as_str())); + + for name in extern_crate_names.into_iter() { + // Replace first ident with a crate name and check if that is valid. + path[0].ident.name = name; + let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); + debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}", + name, path, result); + if let PathResult::Module(..) = result { + return Some((path, Vec::new())); + } + } -``` -fn foo(x: T) { - fn bar(y: T) { - // .. + None } - bar(x); -} -``` -``` -fn foo(x: T) { - type MaybeT = Option; -} -``` + /// Suggests importing a macro from the root of the crate rather than a module within + /// the crate. + /// + /// ``` + /// help: a macro with this name exists at the root of the crate + /// | + /// LL | use issue_59764::makro; + /// | ^^^^^^^^^^^^^^^^^^ + /// | + /// = note: this could be because a macro annotated with `#[macro_export]` will be exported + /// at the root of the crate instead of the module where it is defined + /// ``` + pub(crate) fn check_for_module_export_macro( + &self, + directive: &'b ImportDirective<'b>, + module: ModuleOrUniformRoot<'b>, + ident: Ident, + ) -> Option<(Option, Vec)> { + let mut crate_module = if let ModuleOrUniformRoot::Module(module) = module { + module + } else { + return None; + }; + + while let Some(parent) = crate_module.parent { + crate_module = parent; + } -Be sure to copy over any bounds as well: + if ModuleOrUniformRoot::same_def(ModuleOrUniformRoot::Module(crate_module), module) { + // Don't make a suggestion if the import was already from the root of the + // crate. + return None; + } -``` -fn foo(x: T) { - fn bar(y: T) { - // .. + let resolutions = crate_module.resolutions.borrow(); + let resolution = resolutions.get(&(ident, MacroNS))?; + let binding = resolution.borrow().binding()?; + if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() { + let module_name = crate_module.kind.name().unwrap(); + let import = match directive.subclass { + ImportDirectiveSubclass::SingleImport { source, target, .. } if source != target => + format!("{} as {}", source, target), + _ => format!("{}", ident), + }; + + let mut corrections: Vec<(Span, String)> = Vec::new(); + if !directive.is_nested() { + // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove + // intermediate segments. + corrections.push((directive.span, format!("{}::{}", module_name, import))); + } else { + // Find the binding span (and any trailing commas and spaces). + // ie. `use a::b::{c, d, e};` + // ^^^ + let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding( + self.resolver.session, directive.span, directive.use_span, + ); + debug!("check_for_module_export_macro: found_closing_brace={:?} binding_span={:?}", + found_closing_brace, binding_span); + + let mut removal_span = binding_span; + if found_closing_brace { + // If the binding span ended with a closing brace, as in the below example: + // ie. `use a::b::{c, d};` + // ^ + // Then expand the span of characters to remove to include the previous + // binding's trailing comma. + // ie. `use a::b::{c, d};` + // ^^^ + if let Some(previous_span) = extend_span_to_previous_binding( + self.resolver.session, binding_span, + ) { + debug!("check_for_module_export_macro: previous_span={:?}", previous_span); + removal_span = removal_span.with_lo(previous_span.lo()); + } + } + debug!("check_for_module_export_macro: removal_span={:?}", removal_span); + + // Remove the `removal_span`. + corrections.push((removal_span, "".to_string())); + + // Find the span after the crate name and if it has nested imports immediatately + // after the crate name already. + // ie. `use a::b::{c, d};` + // ^^^^^^^^^ + // or `use a::{b, c, d}};` + // ^^^^^^^^^^^ + let (has_nested, after_crate_name) = find_span_immediately_after_crate_name( + self.resolver.session, module_name, directive.use_span, + ); + debug!("check_for_module_export_macro: has_nested={:?} after_crate_name={:?}", + has_nested, after_crate_name); + + let source_map = self.resolver.session.source_map(); + + // Add the import to the start, with a `{` if required. + let start_point = source_map.start_point(after_crate_name); + if let Ok(start_snippet) = source_map.span_to_snippet(start_point) { + corrections.push(( + start_point, + if has_nested { + // In this case, `start_snippet` must equal '{'. + format!("{}{}, ", start_snippet, import) + } else { + // In this case, add a `{`, then the moved import, then whatever + // was there before. + format!("{{{}, {}", import, start_snippet) + } + )); + } + + // Add a `};` to the end if nested, matching the `{` added at the start. + if !has_nested { + corrections.push((source_map.end_point(after_crate_name), + "};".to_string())); + } + } + + let suggestion = Some(( + corrections, + String::from("a macro with this name exists at the root of the crate"), + Applicability::MaybeIncorrect, + )); + let note = vec![ + "this could be because a macro annotated with `#[macro_export]` will be exported \ + at the root of the crate instead of the module where it is defined".to_string(), + ]; + Some((suggestion, note)) + } else { + None + } } - bar(x); } -``` -``` -fn foo(x: T) { - struct Foo { - x: T, +/// Given a `binding_span` of a binding within a use statement: +/// +/// ``` +/// use foo::{a, b, c}; +/// ^ +/// ``` +/// +/// then return the span until the next binding or the end of the statement: +/// +/// ``` +/// use foo::{a, b, c}; +/// ^^^ +/// ``` +pub(crate) fn find_span_of_binding_until_next_binding( + sess: &Session, + binding_span: Span, + use_span: Span, +) -> (bool, Span) { + let source_map = sess.source_map(); + + // Find the span of everything after the binding. + // ie. `a, e};` or `a};` + let binding_until_end = binding_span.with_hi(use_span.hi()); + + // Find everything after the binding but not including the binding. + // ie. `, e};` or `};` + let after_binding_until_end = binding_until_end.with_lo(binding_span.hi()); + + // Keep characters in the span until we encounter something that isn't a comma or + // whitespace. + // ie. `, ` or ``. + // + // Also note whether a closing brace character was encountered. If there + // was, then later go backwards to remove any trailing commas that are left. + let mut found_closing_brace = false; + let after_binding_until_next_binding = source_map.span_take_while( + after_binding_until_end, + |&ch| { + if ch == '}' { found_closing_brace = true; } + ch == ' ' || ch == ',' + } + ); + + // Combine the two spans. + // ie. `a, ` or `a`. + // + // Removing these would leave `issue_52891::{d, e};` or `issue_52891::{d, e, };` + let span = binding_span.with_hi(after_binding_until_next_binding.hi()); + + (found_closing_brace, span) +} + +/// Given a `binding_span`, return the span through to the comma or opening brace of the previous +/// binding. +/// +/// ``` +/// use foo::a::{a, b, c}; +/// ^^--- binding span +/// | +/// returned span +/// +/// use foo::{a, b, c}; +/// --- binding span +/// ``` +pub(crate) fn extend_span_to_previous_binding( + sess: &Session, + binding_span: Span, +) -> Option { + let source_map = sess.source_map(); + + // `prev_source` will contain all of the source that came before the span. + // Then split based on a command and take the first (ie. closest to our span) + // snippet. In the example, this is a space. + let prev_source = source_map.span_to_prev_source(binding_span).ok()?; + + let prev_comma = prev_source.rsplit(',').collect::>(); + let prev_starting_brace = prev_source.rsplit('{').collect::>(); + if prev_comma.len() <= 1 || prev_starting_brace.len() <= 1 { + return None; } -} -``` - -This may require additional type hints in the function body. - -In case the item is a function inside an `impl`, defining a private helper -function might be easier: -``` -# struct Foo(T); -impl Foo { - pub fn foo(&self, x: T) { - self.bar(x); - } + let prev_comma = prev_comma.first().unwrap(); + let prev_starting_brace = prev_starting_brace.first().unwrap(); - fn bar(&self, y: T) { - // .. + // If the amount of source code before the comma is greater than + // the amount of source code before the starting brace then we've only + // got one item in the nested item (eg. `issue_52891::{self}`). + if prev_comma.len() > prev_starting_brace.len() { + return None; } -} -``` - -For default impls in traits, the private helper solution won't work, however -closures or copying the parameters should still work. -"##, - -E0403: r##" -Some type parameters have the same name. - -Erroneous code example: - -```compile_fail,E0403 -fn foo(s: T, u: T) {} // error: the name `T` is already used for a type - // parameter in this type parameter list -``` - -Please verify that none of the type parameters are misspelled, and rename any -clashing parameters. Example: - -``` -fn foo(s: T, u: Y) {} // ok! -``` -"##, - -E0404: r##" -You tried to use something which is not a trait in a trait position, such as -a bound or `impl`. - -Erroneous code example: - -```compile_fail,E0404 -struct Foo; -struct Bar; - -impl Foo for Bar {} // error: `Foo` is not a trait -``` - -Another erroneous code example: - -```compile_fail,E0404 -struct Foo; - -fn bar(t: T) {} // error: `Foo` is not a trait -``` - -Please verify that you didn't misspell the trait's name or otherwise use the -wrong identifier. Example: - -``` -trait Foo { - // some functions -} -struct Bar; - -impl Foo for Bar { // ok! - // functions implementation -} -``` - -or - -``` -trait Foo { - // some functions -} - -fn bar(t: T) {} // ok! -``` - -"##, - -E0405: r##" -The code refers to a trait that is not in scope. - -Erroneous code example: - -```compile_fail,E0405 -struct Foo; - -impl SomeTrait for Foo {} // error: trait `SomeTrait` is not in scope -``` - -Please verify that the name of the trait wasn't misspelled and ensure that it -was imported. Example: - -``` -# #[cfg(for_demonstration_only)] -// solution 1: -use some_file::SomeTrait; - -// solution 2: -trait SomeTrait { - // some functions -} - -struct Foo; - -impl SomeTrait for Foo { // ok! - // implements functions -} -``` -"##, - -E0407: r##" -A definition of a method not in the implemented trait was given in a trait -implementation. - -Erroneous code example: - -```compile_fail,E0407 -trait Foo { - fn a(); -} - -struct Bar; - -impl Foo for Bar { - fn a() {} - fn b() {} // error: method `b` is not a member of trait `Foo` -} -``` - -Please verify you didn't misspell the method name and you used the correct -trait. First example: - -``` -trait Foo { - fn a(); - fn b(); -} - -struct Bar; - -impl Foo for Bar { - fn a() {} - fn b() {} // ok! -} -``` - -Second example: - -``` -trait Foo { - fn a(); -} - -struct Bar; - -impl Foo for Bar { - fn a() {} -} - -impl Bar { - fn b() {} -} -``` -"##, - -E0408: r##" -An "or" pattern was used where the variable bindings are not consistently bound -across patterns. - -Erroneous code example: - -```compile_fail,E0408 -match x { - Some(y) | None => { /* use y */ } // error: variable `y` from pattern #1 is - // not bound in pattern #2 - _ => () -} -``` - -Here, `y` is bound to the contents of the `Some` and can be used within the -block corresponding to the match arm. However, in case `x` is `None`, we have -not specified what `y` is, and the block will use a nonexistent variable. - -To fix this error, either split into multiple match arms: - -``` -let x = Some(1); -match x { - Some(y) => { /* use y */ } - None => { /* ... */ } -} -``` - -or, bind the variable to a field of the same type in all sub-patterns of the -or pattern: - -``` -let x = (0, 2); -match x { - (0, y) | (y, 0) => { /* use y */} - _ => {} -} -``` - -In this example, if `x` matches the pattern `(0, _)`, the second field is set -to `y`. If it matches `(_, 0)`, the first field is set to `y`; so in all -cases `y` is set to some value. -"##, - -E0409: r##" -An "or" pattern was used where the variable bindings are not consistently bound -across patterns. - -Erroneous code example: - -```compile_fail,E0409 -let x = (0, 2); -match x { - (0, ref y) | (y, 0) => { /* use y */} // error: variable `y` is bound with - // different mode in pattern #2 - // than in pattern #1 - _ => () -} -``` - -Here, `y` is bound by-value in one case and by-reference in the other. - -To fix this error, just use the same mode in both cases. -Generally using `ref` or `ref mut` where not already used will fix this: - -``` -let x = (0, 2); -match x { - (0, ref y) | (ref y, 0) => { /* use y */} - _ => () -} -``` - -Alternatively, split the pattern: - -``` -let x = (0, 2); -match x { - (y, 0) => { /* use y */ } - (0, ref y) => { /* use y */} - _ => () -} -``` -"##, -E0411: r##" -The `Self` keyword was used outside an impl, trait, or type definition. - -Erroneous code example: - -```compile_fail,E0411 -::foo; // error: use of `Self` outside of an impl, trait, or type - // definition -``` - -The `Self` keyword represents the current type, which explains why it can only -be used inside an impl, trait, or type definition. It gives access to the -associated items of a type: - -``` -trait Foo { - type Bar; -} - -trait Baz : Foo { - fn bar() -> Self::Bar; // like this -} -``` - -However, be careful when two types have a common associated type: - -```compile_fail -trait Foo { - type Bar; -} - -trait Foo2 { - type Bar; -} - -trait Baz : Foo + Foo2 { - fn bar() -> Self::Bar; - // error: ambiguous associated type `Bar` in bounds of `Self` -} -``` - -This problem can be solved by specifying from which trait we want to use the -`Bar` type: - -``` -trait Foo { - type Bar; -} - -trait Foo2 { - type Bar; -} - -trait Baz : Foo + Foo2 { - fn bar() -> ::Bar; // ok! -} -``` -"##, - -E0412: r##" -The type name used is not in scope. - -Erroneous code examples: - -```compile_fail,E0412 -impl Something {} // error: type name `Something` is not in scope - -// or: - -trait Foo { - fn bar(N); // error: type name `N` is not in scope -} - -// or: - -fn foo(x: T) {} // type name `T` is not in scope -``` - -To fix this error, please verify you didn't misspell the type name, you did -declare it or imported it into the scope. Examples: - -``` -struct Something; - -impl Something {} // ok! - -// or: - -trait Foo { - type N; - - fn bar(_: Self::N); // ok! -} - -// or: - -fn foo(x: T) {} // ok! -``` - -Another case that causes this error is when a type is imported into a parent -module. To fix this, you can follow the suggestion and use File directly or -`use super::File;` which will import the types from the parent namespace. An -example that causes this error is below: - -```compile_fail,E0412 -use std::fs::File; - -mod foo { - fn some_function(f: File) {} -} -``` - -``` -use std::fs::File; - -mod foo { - // either - use super::File; - // or - // use std::fs::File; - fn foo(f: File) {} -} -# fn main() {} // don't insert it for us; that'll break imports -``` -"##, - -E0415: r##" -More than one function parameter have the same name. - -Erroneous code example: - -```compile_fail,E0415 -fn foo(f: i32, f: i32) {} // error: identifier `f` is bound more than - // once in this parameter list -``` - -Please verify you didn't misspell parameters' name. Example: - -``` -fn foo(f: i32, g: i32) {} // ok! -``` -"##, - -E0416: r##" -An identifier is bound more than once in a pattern. - -Erroneous code example: - -```compile_fail,E0416 -match (1, 2) { - (x, x) => {} // error: identifier `x` is bound more than once in the - // same pattern -} -``` - -Please verify you didn't misspell identifiers' name. Example: - -``` -match (1, 2) { - (x, y) => {} // ok! -} -``` - -Or maybe did you mean to unify? Consider using a guard: - -``` -# let (A, B, C) = (1, 2, 3); -match (A, B, C) { - (x, x2, see) if x == x2 => { /* A and B are equal, do one thing */ } - (y, z, see) => { /* A and B unequal; do another thing */ } -} -``` -"##, - -E0422: r##" -You are trying to use an identifier that is either undefined or not a struct. -Erroneous code example: - -```compile_fail,E0422 -fn main () { - let x = Foo { x: 1, y: 2 }; -} -``` - -In this case, `Foo` is undefined, so it inherently isn't anything, and -definitely not a struct. - -```compile_fail -fn main () { - let foo = 1; - let x = foo { x: 1, y: 2 }; -} -``` - -In this case, `foo` is defined, but is not a struct, so Rust can't use it as -one. -"##, - -E0423: r##" -An identifier was used like a function name or a value was expected and the -identifier exists but it belongs to a different namespace. - -For (an erroneous) example, here a `struct` variant name were used as a -function: - -```compile_fail,E0423 -struct Foo { a: bool }; - -let f = Foo(); -// error: expected function, found `Foo` -// `Foo` is a struct name, but this expression uses it like a function name -``` - -Please verify you didn't misspell the name of what you actually wanted to use -here. Example: - -``` -fn Foo() -> u32 { 0 } - -let f = Foo(); // ok! -``` - -It is common to forget the trailing `!` on macro invocations, which would also -yield this error: - -```compile_fail,E0423 -println(""); -// error: expected function, found macro `println` -// did you mean `println!(...)`? (notice the trailing `!`) -``` - -Another case where this error is emitted is when a value is expected, but -something else is found: - -```compile_fail,E0423 -pub mod a { - pub const I: i32 = 1; -} - -fn h1() -> i32 { - a.I - //~^ ERROR expected value, found module `a` - // did you mean `a::I`? -} -``` -"##, - -E0424: r##" -The `self` keyword was used in a static method. - -Erroneous code example: - -```compile_fail,E0424 -struct Foo; - -impl Foo { - fn bar(self) {} - - fn foo() { - self.bar(); // error: `self` is not available in a static method. - } -} -``` - -Please check if the method's argument list should have contained `self`, -`&self`, or `&mut self` (in case you didn't want to create a static -method), and add it if so. Example: - -``` -struct Foo; - -impl Foo { - fn bar(self) {} - - fn foo(self) { - self.bar(); // ok! - } -} -``` -"##, - -E0425: r##" -An unresolved name was used. - -Erroneous code examples: - -```compile_fail,E0425 -something_that_doesnt_exist::foo; -// error: unresolved name `something_that_doesnt_exist::foo` - -// or: - -trait Foo { - fn bar() { - Self; // error: unresolved name `Self` - } -} - -// or: - -let x = unknown_variable; // error: unresolved name `unknown_variable` -``` - -Please verify that the name wasn't misspelled and ensure that the -identifier being referred to is valid for the given situation. Example: - -``` -enum something_that_does_exist { - Foo, -} -``` - -Or: - -``` -mod something_that_does_exist { - pub static foo : i32 = 0i32; -} - -something_that_does_exist::foo; // ok! -``` - -Or: - -``` -let unknown_variable = 12u32; -let x = unknown_variable; // ok! -``` - -If the item is not defined in the current module, it must be imported using a -`use` statement, like so: - -``` -# mod foo { pub fn bar() {} } -# fn main() { -use foo::bar; -bar(); -# } -``` - -If the item you are importing is not defined in some super-module of the -current module, then it must also be declared as public (e.g., `pub fn`). -"##, - -E0426: r##" -An undeclared label was used. - -Erroneous code example: - -```compile_fail,E0426 -loop { - break 'a; // error: use of undeclared label `'a` -} -``` - -Please verify you spelt or declare the label correctly. Example: - -``` -'a: loop { - break 'a; // ok! -} -``` -"##, - -E0428: r##" -A type or module has been defined more than once. - -Erroneous code example: - -```compile_fail,E0428 -struct Bar; -struct Bar; // error: duplicate definition of value `Bar` -``` - -Please verify you didn't misspell the type/module's name or remove/rename the -duplicated one. Example: - -``` -struct Bar; -struct Bar2; // ok! -``` -"##, - -E0429: r##" -The `self` keyword cannot appear alone as the last segment in a `use` -declaration. - -Erroneous code example: - -```compile_fail,E0429 -use std::fmt::self; // error: `self` imports are only allowed within a { } list -``` - -To use a namespace itself in addition to some of its members, `self` may appear -as part of a brace-enclosed list of imports: - -``` -use std::fmt::{self, Debug}; -``` - -If you only want to import the namespace, do so directly: - -``` -use std::fmt; -``` -"##, - -E0430: r##" -The `self` import appears more than once in the list. - -Erroneous code example: - -```compile_fail,E0430 -use something::{self, self}; // error: `self` import can only appear once in - // the list -``` - -Please verify you didn't misspell the import name or remove the duplicated -`self` import. Example: - -``` -# mod something {} -# fn main() { -use something::{self}; // ok! -# } -``` -"##, - -E0431: r##" -An invalid `self` import was made. - -Erroneous code example: - -```compile_fail,E0431 -use {self}; // error: `self` import can only appear in an import list with a - // non-empty prefix -``` - -You cannot import the current module into itself, please remove this import -or verify you didn't misspell it. -"##, - -E0432: r##" -An import was unresolved. - -Erroneous code example: - -```compile_fail,E0432 -use something::Foo; // error: unresolved import `something::Foo`. -``` - -Paths in `use` statements are relative to the crate root. To import items -relative to the current and parent modules, use the `self::` and `super::` -prefixes, respectively. Also verify that you didn't misspell the import -name and that the import exists in the module from where you tried to -import it. Example: - -``` -use self::something::Foo; // ok! - -mod something { - pub struct Foo; -} -# fn main() {} -``` - -Or, if you tried to use a module from an external crate, you may have missed -the `extern crate` declaration (which is usually placed in the crate root): - -``` -extern crate core; // Required to use the `core` crate - -use core::any; -# fn main() {} -``` -"##, - -E0433: r##" -An undeclared type or module was used. - -Erroneous code example: - -```compile_fail,E0433 -let map = HashMap::new(); -// error: failed to resolve: use of undeclared type or module `HashMap` -``` - -Please verify you didn't misspell the type/module's name or that you didn't -forget to import it: - - -``` -use std::collections::HashMap; // HashMap has been imported. -let map: HashMap = HashMap::new(); // So it can be used! -``` -"##, - -E0434: r##" -This error indicates that a variable usage inside an inner function is invalid -because the variable comes from a dynamic environment. Inner functions do not -have access to their containing environment. - -Erroneous code example: - -```compile_fail,E0434 -fn foo() { - let y = 5; - fn bar() -> u32 { - y // error: can't capture dynamic environment in a fn item; use the - // || { ... } closure form instead. - } -} -``` - -Functions do not capture local variables. To fix this error, you can replace the -function with a closure: - -``` -fn foo() { - let y = 5; - let bar = || { - y - }; -} -``` - -or replace the captured variable with a constant or a static item: - -``` -fn foo() { - static mut X: u32 = 4; - const Y: u32 = 5; - fn bar() -> u32 { - unsafe { - X = 3; + Some(binding_span.with_lo(BytePos( + // Take away the number of bytes for the characters we've found and an + // extra for the comma. + binding_span.lo().0 - (prev_comma.as_bytes().len() as u32) - 1 + ))) +} + +/// Given a `use_span` of a binding within a use statement, returns the highlighted span and if +/// it is a nested use tree. +/// +/// ``` +/// use foo::a::{b, c}; +/// ^^^^^^^^^^ // false +/// +/// use foo::{a, b, c}; +/// ^^^^^^^^^^ // true +/// +/// use foo::{a, b::{c, d}}; +/// ^^^^^^^^^^^^^^^ // true +/// ``` +fn find_span_immediately_after_crate_name( + sess: &Session, + module_name: Symbol, + use_span: Span, +) -> (bool, Span) { + debug!("find_span_immediately_after_crate_name: module_name={:?} use_span={:?}", + module_name, use_span); + let source_map = sess.source_map(); + + // Using `use issue_59764::foo::{baz, makro};` as an example throughout.. + let mut num_colons = 0; + // Find second colon.. `use issue_59764:` + let until_second_colon = source_map.span_take_while(use_span, |c| { + if *c == ':' { num_colons += 1; } + match c { + ':' if num_colons == 2 => false, + _ => true, } - Y - } -} -``` -"##, - -E0435: r##" -A non-constant value was used in a constant expression. - -Erroneous code example: - -```compile_fail,E0435 -let foo = 42; -let a: [u8; foo]; // error: attempt to use a non-constant value in a constant -``` - -To fix this error, please replace the value with a constant. Example: - -``` -let a: [u8; 42]; // ok! -``` - -Or: - -``` -const FOO: usize = 42; -let a: [u8; FOO]; // ok! -``` -"##, - -E0437: r##" -Trait implementations can only implement associated types that are members of -the trait in question. This error indicates that you attempted to implement -an associated type whose name does not match the name of any associated type -in the trait. - -Erroneous code example: - -```compile_fail,E0437 -trait Foo {} - -impl Foo for i32 { - type Bar = bool; -} -``` - -The solution to this problem is to remove the extraneous associated type: - -``` -trait Foo {} - -impl Foo for i32 {} -``` -"##, - -E0438: r##" -Trait implementations can only implement associated constants that are -members of the trait in question. This error indicates that you -attempted to implement an associated constant whose name does not -match the name of any associated constant in the trait. - -Erroneous code example: - -```compile_fail,E0438 -trait Foo {} - -impl Foo for i32 { - const BAR: bool = true; -} -``` - -The solution to this problem is to remove the extraneous associated constant: - -``` -trait Foo {} - -impl Foo for i32 {} -``` -"##, - -E0466: r##" -Macro import declarations were malformed. - -Erroneous code examples: - -```compile_fail,E0466 -#[macro_use(a_macro(another_macro))] // error: invalid import declaration -extern crate core as some_crate; - -#[macro_use(i_want = "some_macros")] // error: invalid import declaration -extern crate core as another_crate; -``` - -This is a syntax error at the level of attribute declarations. The proper -syntax for macro imports is the following: - -```ignore (cannot-doctest-multicrate-project) -// In some_crate: -#[macro_export] -macro_rules! get_tacos { - ... -} - -#[macro_export] -macro_rules! get_pimientos { - ... -} - -// In your crate: -#[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and -extern crate some_crate; // `get_pimientos` macros from some_crate -``` - -If you would like to import all exported macros, write `macro_use` with no -arguments. -"##, - -E0468: r##" -A non-root module attempts to import macros from another crate. - -Example of erroneous code: - -```compile_fail,E0468 -mod foo { - #[macro_use(debug_assert)] // error: must be at crate root to import - extern crate core; // macros from another crate - fn run_macro() { debug_assert!(true); } -} -``` - -Only `extern crate` imports at the crate root level are allowed to import -macros. - -Either move the macro import to crate root or do without the foreign macros. -This will work: - -``` -#[macro_use(debug_assert)] -extern crate core; - -mod foo { - fn run_macro() { debug_assert!(true); } -} -# fn main() {} -``` -"##, - -E0469: r##" -A macro listed for import was not found. - -Erroneous code example: - -```compile_fail,E0469 -#[macro_use(drink, be_merry)] // error: imported macro not found -extern crate alloc; - -fn main() { - // ... -} -``` - -Either the listed macro is not contained in the imported crate, or it is not -exported from the given crate. - -This could be caused by a typo. Did you misspell the macro's name? - -Double-check the names of the macros listed for import, and that the crate -in question exports them. - -A working version would be: - -```ignore (cannot-doctest-multicrate-project) -// In some_crate crate: -#[macro_export] -macro_rules! eat { - ... -} - -#[macro_export] -macro_rules! drink { - ... -} - -// In your crate: -#[macro_use(eat, drink)] -extern crate some_crate; //ok! -``` -"##, - -E0530: r##" -A binding shadowed something it shouldn't. - -Erroneous code example: - -```compile_fail,E0530 -static TEST: i32 = 0; - -let r: (i32, i32) = (0, 0); -match r { - TEST => {} // error: match bindings cannot shadow statics -} -``` - -To fix this error, just change the binding's name in order to avoid shadowing -one of the following: - -* struct name -* struct/enum variant -* static -* const -* associated const - -Fixed example: - -``` -static TEST: i32 = 0; - -let r: (i32, i32) = (0, 0); -match r { - something => {} // ok! -} -``` -"##, - -E0532: r##" -Pattern arm did not match expected kind. - -Erroneous code example: - -```compile_fail,E0532 -enum State { - Succeeded, - Failed(String), -} - -fn print_on_failure(state: &State) { - match *state { - // error: expected unit struct/variant or constant, found tuple - // variant `State::Failed` - State::Failed => println!("Failed"), - _ => () - } -} -``` - -To fix this error, ensure the match arm kind is the same as the expression -matched. - -Fixed example: - -``` -enum State { - Succeeded, - Failed(String), -} - -fn print_on_failure(state: &State) { - match *state { - State::Failed(ref msg) => println!("Failed with {}", msg), - _ => () - } -} -``` -"##, - -E0603: r##" -A private item was used outside its scope. - -Erroneous code example: - -```compile_fail,E0603 -mod SomeModule { - const PRIVATE: u32 = 0x_a_bad_1dea_u32; // This const is private, so we - // can't use it outside of the - // `SomeModule` module. -} - -println!("const value: {}", SomeModule::PRIVATE); // error: constant `PRIVATE` - // is private -``` - -In order to fix this error, you need to make the item public by using the `pub` -keyword. Example: - -``` -mod SomeModule { - pub const PRIVATE: u32 = 0x_a_bad_1dea_u32; // We set it public by using the - // `pub` keyword. -} - -println!("const value: {}", SomeModule::PRIVATE); // ok! -``` -"##, - -E0659: r##" -An item usage is ambiguous. - -Erroneous code example: - -```compile_fail,E0659 -pub mod moon { - pub fn foo() {} -} - -pub mod earth { - pub fn foo() {} -} - -mod collider { - pub use moon::*; - pub use earth::*; -} - -fn main() { - collider::foo(); // ERROR: `foo` is ambiguous -} -``` - -This error generally appears when two items with the same name are imported into -a module. Here, the `foo` functions are imported and reexported from the -`collider` module and therefore, when we're using `collider::foo()`, both -functions collide. - -To solve this error, the best solution is generally to keep the path before the -item when using it. Example: - -``` -pub mod moon { - pub fn foo() {} -} - -pub mod earth { - pub fn foo() {} -} - -mod collider { - pub use moon; - pub use earth; -} - -fn main() { - collider::moon::foo(); // ok! - collider::earth::foo(); // ok! -} -``` -"##, - -} - -register_diagnostics! { -// E0153, unused error code -// E0157, unused error code -// E0257, -// E0258, -// E0402, // cannot use an outer type parameter in this context -// E0406, merged into 420 -// E0410, merged into 408 -// E0413, merged into 530 -// E0414, merged into 530 -// E0417, merged into 532 -// E0418, merged into 532 -// E0419, merged into 531 -// E0420, merged into 532 -// E0421, merged into 531 - E0531, // unresolved pattern path kind `name` -// E0427, merged into 530 -// E0467, removed -// E0470, removed - E0573, - E0574, - E0575, - E0576, - E0577, - E0578, + }); + // Find everything after the second colon.. `foo::{baz, makro};` + let from_second_colon = use_span.with_lo(until_second_colon.hi() + BytePos(1)); + + let mut found_a_non_whitespace_character = false; + // Find the first non-whitespace character in `from_second_colon`.. `f` + let after_second_colon = source_map.span_take_while(from_second_colon, |c| { + if found_a_non_whitespace_character { return false; } + if !c.is_whitespace() { found_a_non_whitespace_character = true; } + true + }); + + // Find the first `{` in from_second_colon.. `foo::{` + let next_left_bracket = source_map.span_through_char(from_second_colon, '{'); + + (next_left_bracket == after_second_colon, from_second_colon) } diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs new file mode 100644 index 0000000000000..7cd26dce1447c --- /dev/null +++ b/src/librustc_resolve/error_codes.rs @@ -0,0 +1,1685 @@ +#![allow(non_snake_case)] + +use syntax::{register_diagnostic, register_diagnostics, register_long_diagnostics}; + +// Error messages for EXXXX errors. Each message should start and end with a +// new line, and be wrapped to 80 characters. In vim you can `:set tw=80` and +// use `gq` to wrap paragraphs. Use `:set tw=0` to disable. +register_long_diagnostics! { + +E0128: r##" +Type parameter defaults can only use parameters that occur before them. +Erroneous code example: + +```compile_fail,E0128 +struct Foo { + field1: T, + filed2: U, +} +// error: type parameters with a default cannot use forward declared +// identifiers +``` + +Since type parameters are evaluated in-order, you may be able to fix this issue +by doing: + +``` +struct Foo { + field1: T, + filed2: U, +} +``` + +Please also verify that this wasn't because of a name-clash and rename the type +parameter if so. +"##, + +E0154: r##" +#### Note: this error code is no longer emitted by the compiler. + +Imports (`use` statements) are not allowed after non-item statements, such as +variable declarations and expression statements. + +Here is an example that demonstrates the error: + +``` +fn f() { + // Variable declaration before import + let x = 0; + use std::io::Read; + // ... +} +``` + +The solution is to declare the imports at the top of the block, function, or +file. + +Here is the previous example again, with the correct order: + +``` +fn f() { + use std::io::Read; + let x = 0; + // ... +} +``` + +See the Declaration Statements section of the reference for more information +about what constitutes an Item declaration and what does not: + +https://doc.rust-lang.org/reference.html#statements +"##, + +E0251: r##" +#### Note: this error code is no longer emitted by the compiler. + +Two items of the same name cannot be imported without rebinding one of the +items under a new local name. + +An example of this error: + +``` +use foo::baz; +use bar::*; // error, do `use foo::baz as quux` instead on the previous line + +fn main() {} + +mod foo { + pub struct baz; +} + +mod bar { + pub mod baz {} +} +``` +"##, + +E0252: r##" +Two items of the same name cannot be imported without rebinding one of the +items under a new local name. + +Erroneous code example: + +```compile_fail,E0252 +use foo::baz; +use bar::baz; // error, do `use bar::baz as quux` instead + +fn main() {} + +mod foo { + pub struct baz; +} + +mod bar { + pub mod baz {} +} +``` + +You can use aliases in order to fix this error. Example: + +``` +use foo::baz as foo_baz; +use bar::baz; // ok! + +fn main() {} + +mod foo { + pub struct baz; +} + +mod bar { + pub mod baz {} +} +``` + +Or you can reference the item with its parent: + +``` +use bar::baz; + +fn main() { + let x = foo::baz; // ok! +} + +mod foo { + pub struct baz; +} + +mod bar { + pub mod baz {} +} +``` +"##, + +E0253: r##" +Attempt was made to import an unimportable value. This can happen when trying +to import a method from a trait. + +Erroneous code example: + +```compile_fail,E0253 +mod foo { + pub trait MyTrait { + fn do_something(); + } +} + +use foo::MyTrait::do_something; +// error: `do_something` is not directly importable + +fn main() {} +``` + +It's invalid to directly import methods belonging to a trait or concrete type. +"##, + +E0254: r##" +Attempt was made to import an item whereas an extern crate with this name has +already been imported. + +Erroneous code example: + +```compile_fail,E0254 +extern crate core; + +mod foo { + pub trait core { + fn do_something(); + } +} + +use foo::core; // error: an extern crate named `core` has already + // been imported in this module + +fn main() {} +``` + +To fix this issue, you have to rename at least one of the two imports. +Example: + +``` +extern crate core as libcore; // ok! + +mod foo { + pub trait core { + fn do_something(); + } +} + +use foo::core; + +fn main() {} +``` +"##, + +E0255: r##" +You can't import a value whose name is the same as another value defined in the +module. + +Erroneous code example: + +```compile_fail,E0255 +use bar::foo; // error: an item named `foo` is already in scope + +fn foo() {} + +mod bar { + pub fn foo() {} +} + +fn main() {} +``` + +You can use aliases in order to fix this error. Example: + +``` +use bar::foo as bar_foo; // ok! + +fn foo() {} + +mod bar { + pub fn foo() {} +} + +fn main() {} +``` + +Or you can reference the item with its parent: + +``` +fn foo() {} + +mod bar { + pub fn foo() {} +} + +fn main() { + bar::foo(); // we get the item by referring to its parent +} +``` +"##, + +E0256: r##" +#### Note: this error code is no longer emitted by the compiler. + +You can't import a type or module when the name of the item being imported is +the same as another type or submodule defined in the module. + +An example of this error: + +```compile_fail +use foo::Bar; // error + +type Bar = u32; + +mod foo { + pub mod Bar { } +} + +fn main() {} +``` +"##, + +E0259: r##" +The name chosen for an external crate conflicts with another external crate +that has been imported into the current module. + +Erroneous code example: + +```compile_fail,E0259 +extern crate core; +extern crate std as core; + +fn main() {} +``` + +The solution is to choose a different name that doesn't conflict with any +external crate imported into the current module. + +Correct example: + +``` +extern crate core; +extern crate std as other_name; + +fn main() {} +``` +"##, + +E0260: r##" +The name for an item declaration conflicts with an external crate's name. + +Erroneous code example: + +```compile_fail,E0260 +extern crate core; + +struct core; + +fn main() {} +``` + +There are two possible solutions: + +Solution #1: Rename the item. + +``` +extern crate core; + +struct xyz; +``` + +Solution #2: Import the crate with a different name. + +``` +extern crate core as xyz; + +struct abc; +``` + +See the Declaration Statements section of the reference for more information +about what constitutes an Item declaration and what does not: + +https://doc.rust-lang.org/reference.html#statements +"##, + +E0364: r##" +Private items cannot be publicly re-exported. This error indicates that you +attempted to `pub use` a type or value that was not itself public. + +Erroneous code example: + +```compile_fail +mod foo { + const X: u32 = 1; +} + +pub use foo::X; + +fn main() {} +``` + +The solution to this problem is to ensure that the items that you are +re-exporting are themselves marked with `pub`: + +``` +mod foo { + pub const X: u32 = 1; +} + +pub use foo::X; + +fn main() {} +``` + +See the 'Use Declarations' section of the reference for more information on +this topic: + +https://doc.rust-lang.org/reference.html#use-declarations +"##, + +E0365: r##" +Private modules cannot be publicly re-exported. This error indicates that you +attempted to `pub use` a module that was not itself public. + +Erroneous code example: + +```compile_fail,E0365 +mod foo { + pub const X: u32 = 1; +} + +pub use foo as foo2; + +fn main() {} +``` + +The solution to this problem is to ensure that the module that you are +re-exporting is itself marked with `pub`: + +``` +pub mod foo { + pub const X: u32 = 1; +} + +pub use foo as foo2; + +fn main() {} +``` + +See the 'Use Declarations' section of the reference for more information +on this topic: + +https://doc.rust-lang.org/reference.html#use-declarations +"##, + +E0401: r##" +Inner items do not inherit type or const parameters from the functions +they are embedded in. + +Erroneous code example: + +```compile_fail,E0401 +fn foo(x: T) { + fn bar(y: T) { // T is defined in the "outer" function + // .. + } + bar(x); +} +``` + +Nor will this: + +```compile_fail,E0401 +fn foo(x: T) { + type MaybeT = Option; + // ... +} +``` + +Or this: + +```compile_fail,E0401 +fn foo(x: T) { + struct Foo { + x: T, + } + // ... +} +``` + +Items inside functions are basically just like top-level items, except +that they can only be used from the function they are in. + +There are a couple of solutions for this. + +If the item is a function, you may use a closure: + +``` +fn foo(x: T) { + let bar = |y: T| { // explicit type annotation may not be necessary + // .. + }; + bar(x); +} +``` + +For a generic item, you can copy over the parameters: + +``` +fn foo(x: T) { + fn bar(y: T) { + // .. + } + bar(x); +} +``` + +``` +fn foo(x: T) { + type MaybeT = Option; +} +``` + +Be sure to copy over any bounds as well: + +``` +fn foo(x: T) { + fn bar(y: T) { + // .. + } + bar(x); +} +``` + +``` +fn foo(x: T) { + struct Foo { + x: T, + } +} +``` + +This may require additional type hints in the function body. + +In case the item is a function inside an `impl`, defining a private helper +function might be easier: + +``` +# struct Foo(T); +impl Foo { + pub fn foo(&self, x: T) { + self.bar(x); + } + + fn bar(&self, y: T) { + // .. + } +} +``` + +For default impls in traits, the private helper solution won't work, however +closures or copying the parameters should still work. +"##, + +E0403: r##" +Some type parameters have the same name. + +Erroneous code example: + +```compile_fail,E0403 +fn foo(s: T, u: T) {} // error: the name `T` is already used for a type + // parameter in this type parameter list +``` + +Please verify that none of the type parameters are misspelled, and rename any +clashing parameters. Example: + +``` +fn foo(s: T, u: Y) {} // ok! +``` +"##, + +E0404: r##" +You tried to use something which is not a trait in a trait position, such as +a bound or `impl`. + +Erroneous code example: + +```compile_fail,E0404 +struct Foo; +struct Bar; + +impl Foo for Bar {} // error: `Foo` is not a trait +``` + +Another erroneous code example: + +```compile_fail,E0404 +struct Foo; + +fn bar(t: T) {} // error: `Foo` is not a trait +``` + +Please verify that you didn't misspell the trait's name or otherwise use the +wrong identifier. Example: + +``` +trait Foo { + // some functions +} +struct Bar; + +impl Foo for Bar { // ok! + // functions implementation +} +``` + +or + +``` +trait Foo { + // some functions +} + +fn bar(t: T) {} // ok! +``` + +"##, + +E0405: r##" +The code refers to a trait that is not in scope. + +Erroneous code example: + +```compile_fail,E0405 +struct Foo; + +impl SomeTrait for Foo {} // error: trait `SomeTrait` is not in scope +``` + +Please verify that the name of the trait wasn't misspelled and ensure that it +was imported. Example: + +``` +# #[cfg(for_demonstration_only)] +// solution 1: +use some_file::SomeTrait; + +// solution 2: +trait SomeTrait { + // some functions +} + +struct Foo; + +impl SomeTrait for Foo { // ok! + // implements functions +} +``` +"##, + +E0407: r##" +A definition of a method not in the implemented trait was given in a trait +implementation. + +Erroneous code example: + +```compile_fail,E0407 +trait Foo { + fn a(); +} + +struct Bar; + +impl Foo for Bar { + fn a() {} + fn b() {} // error: method `b` is not a member of trait `Foo` +} +``` + +Please verify you didn't misspell the method name and you used the correct +trait. First example: + +``` +trait Foo { + fn a(); + fn b(); +} + +struct Bar; + +impl Foo for Bar { + fn a() {} + fn b() {} // ok! +} +``` + +Second example: + +``` +trait Foo { + fn a(); +} + +struct Bar; + +impl Foo for Bar { + fn a() {} +} + +impl Bar { + fn b() {} +} +``` +"##, + +E0408: r##" +An "or" pattern was used where the variable bindings are not consistently bound +across patterns. + +Erroneous code example: + +```compile_fail,E0408 +match x { + Some(y) | None => { /* use y */ } // error: variable `y` from pattern #1 is + // not bound in pattern #2 + _ => () +} +``` + +Here, `y` is bound to the contents of the `Some` and can be used within the +block corresponding to the match arm. However, in case `x` is `None`, we have +not specified what `y` is, and the block will use a nonexistent variable. + +To fix this error, either split into multiple match arms: + +``` +let x = Some(1); +match x { + Some(y) => { /* use y */ } + None => { /* ... */ } +} +``` + +or, bind the variable to a field of the same type in all sub-patterns of the +or pattern: + +``` +let x = (0, 2); +match x { + (0, y) | (y, 0) => { /* use y */} + _ => {} +} +``` + +In this example, if `x` matches the pattern `(0, _)`, the second field is set +to `y`. If it matches `(_, 0)`, the first field is set to `y`; so in all +cases `y` is set to some value. +"##, + +E0409: r##" +An "or" pattern was used where the variable bindings are not consistently bound +across patterns. + +Erroneous code example: + +```compile_fail,E0409 +let x = (0, 2); +match x { + (0, ref y) | (y, 0) => { /* use y */} // error: variable `y` is bound with + // different mode in pattern #2 + // than in pattern #1 + _ => () +} +``` + +Here, `y` is bound by-value in one case and by-reference in the other. + +To fix this error, just use the same mode in both cases. +Generally using `ref` or `ref mut` where not already used will fix this: + +``` +let x = (0, 2); +match x { + (0, ref y) | (ref y, 0) => { /* use y */} + _ => () +} +``` + +Alternatively, split the pattern: + +``` +let x = (0, 2); +match x { + (y, 0) => { /* use y */ } + (0, ref y) => { /* use y */} + _ => () +} +``` +"##, + +E0411: r##" +The `Self` keyword was used outside an impl, trait, or type definition. + +Erroneous code example: + +```compile_fail,E0411 +::foo; // error: use of `Self` outside of an impl, trait, or type + // definition +``` + +The `Self` keyword represents the current type, which explains why it can only +be used inside an impl, trait, or type definition. It gives access to the +associated items of a type: + +``` +trait Foo { + type Bar; +} + +trait Baz : Foo { + fn bar() -> Self::Bar; // like this +} +``` + +However, be careful when two types have a common associated type: + +```compile_fail +trait Foo { + type Bar; +} + +trait Foo2 { + type Bar; +} + +trait Baz : Foo + Foo2 { + fn bar() -> Self::Bar; + // error: ambiguous associated type `Bar` in bounds of `Self` +} +``` + +This problem can be solved by specifying from which trait we want to use the +`Bar` type: + +``` +trait Foo { + type Bar; +} + +trait Foo2 { + type Bar; +} + +trait Baz : Foo + Foo2 { + fn bar() -> ::Bar; // ok! +} +``` +"##, + +E0412: r##" +The type name used is not in scope. + +Erroneous code examples: + +```compile_fail,E0412 +impl Something {} // error: type name `Something` is not in scope + +// or: + +trait Foo { + fn bar(N); // error: type name `N` is not in scope +} + +// or: + +fn foo(x: T) {} // type name `T` is not in scope +``` + +To fix this error, please verify you didn't misspell the type name, you did +declare it or imported it into the scope. Examples: + +``` +struct Something; + +impl Something {} // ok! + +// or: + +trait Foo { + type N; + + fn bar(_: Self::N); // ok! +} + +// or: + +fn foo(x: T) {} // ok! +``` + +Another case that causes this error is when a type is imported into a parent +module. To fix this, you can follow the suggestion and use File directly or +`use super::File;` which will import the types from the parent namespace. An +example that causes this error is below: + +```compile_fail,E0412 +use std::fs::File; + +mod foo { + fn some_function(f: File) {} +} +``` + +``` +use std::fs::File; + +mod foo { + // either + use super::File; + // or + // use std::fs::File; + fn foo(f: File) {} +} +# fn main() {} // don't insert it for us; that'll break imports +``` +"##, + +E0415: r##" +More than one function parameter have the same name. + +Erroneous code example: + +```compile_fail,E0415 +fn foo(f: i32, f: i32) {} // error: identifier `f` is bound more than + // once in this parameter list +``` + +Please verify you didn't misspell parameters' name. Example: + +``` +fn foo(f: i32, g: i32) {} // ok! +``` +"##, + +E0416: r##" +An identifier is bound more than once in a pattern. + +Erroneous code example: + +```compile_fail,E0416 +match (1, 2) { + (x, x) => {} // error: identifier `x` is bound more than once in the + // same pattern +} +``` + +Please verify you didn't misspell identifiers' name. Example: + +``` +match (1, 2) { + (x, y) => {} // ok! +} +``` + +Or maybe did you mean to unify? Consider using a guard: + +``` +# let (A, B, C) = (1, 2, 3); +match (A, B, C) { + (x, x2, see) if x == x2 => { /* A and B are equal, do one thing */ } + (y, z, see) => { /* A and B unequal; do another thing */ } +} +``` +"##, + +E0422: r##" +You are trying to use an identifier that is either undefined or not a struct. +Erroneous code example: + +```compile_fail,E0422 +fn main () { + let x = Foo { x: 1, y: 2 }; +} +``` + +In this case, `Foo` is undefined, so it inherently isn't anything, and +definitely not a struct. + +```compile_fail +fn main () { + let foo = 1; + let x = foo { x: 1, y: 2 }; +} +``` + +In this case, `foo` is defined, but is not a struct, so Rust can't use it as +one. +"##, + +E0423: r##" +An identifier was used like a function name or a value was expected and the +identifier exists but it belongs to a different namespace. + +For (an erroneous) example, here a `struct` variant name were used as a +function: + +```compile_fail,E0423 +struct Foo { a: bool }; + +let f = Foo(); +// error: expected function, found `Foo` +// `Foo` is a struct name, but this expression uses it like a function name +``` + +Please verify you didn't misspell the name of what you actually wanted to use +here. Example: + +``` +fn Foo() -> u32 { 0 } + +let f = Foo(); // ok! +``` + +It is common to forget the trailing `!` on macro invocations, which would also +yield this error: + +```compile_fail,E0423 +println(""); +// error: expected function, found macro `println` +// did you mean `println!(...)`? (notice the trailing `!`) +``` + +Another case where this error is emitted is when a value is expected, but +something else is found: + +```compile_fail,E0423 +pub mod a { + pub const I: i32 = 1; +} + +fn h1() -> i32 { + a.I + //~^ ERROR expected value, found module `a` + // did you mean `a::I`? +} +``` +"##, + +E0424: r##" +The `self` keyword was used in a static method. + +Erroneous code example: + +```compile_fail,E0424 +struct Foo; + +impl Foo { + fn bar(self) {} + + fn foo() { + self.bar(); // error: `self` is not available in a static method. + } +} +``` + +Please check if the method's argument list should have contained `self`, +`&self`, or `&mut self` (in case you didn't want to create a static +method), and add it if so. Example: + +``` +struct Foo; + +impl Foo { + fn bar(self) {} + + fn foo(self) { + self.bar(); // ok! + } +} +``` +"##, + +E0425: r##" +An unresolved name was used. + +Erroneous code examples: + +```compile_fail,E0425 +something_that_doesnt_exist::foo; +// error: unresolved name `something_that_doesnt_exist::foo` + +// or: + +trait Foo { + fn bar() { + Self; // error: unresolved name `Self` + } +} + +// or: + +let x = unknown_variable; // error: unresolved name `unknown_variable` +``` + +Please verify that the name wasn't misspelled and ensure that the +identifier being referred to is valid for the given situation. Example: + +``` +enum something_that_does_exist { + Foo, +} +``` + +Or: + +``` +mod something_that_does_exist { + pub static foo : i32 = 0i32; +} + +something_that_does_exist::foo; // ok! +``` + +Or: + +``` +let unknown_variable = 12u32; +let x = unknown_variable; // ok! +``` + +If the item is not defined in the current module, it must be imported using a +`use` statement, like so: + +``` +# mod foo { pub fn bar() {} } +# fn main() { +use foo::bar; +bar(); +# } +``` + +If the item you are importing is not defined in some super-module of the +current module, then it must also be declared as public (e.g., `pub fn`). +"##, + +E0426: r##" +An undeclared label was used. + +Erroneous code example: + +```compile_fail,E0426 +loop { + break 'a; // error: use of undeclared label `'a` +} +``` + +Please verify you spelt or declare the label correctly. Example: + +``` +'a: loop { + break 'a; // ok! +} +``` +"##, + +E0428: r##" +A type or module has been defined more than once. + +Erroneous code example: + +```compile_fail,E0428 +struct Bar; +struct Bar; // error: duplicate definition of value `Bar` +``` + +Please verify you didn't misspell the type/module's name or remove/rename the +duplicated one. Example: + +``` +struct Bar; +struct Bar2; // ok! +``` +"##, + +E0429: r##" +The `self` keyword cannot appear alone as the last segment in a `use` +declaration. + +Erroneous code example: + +```compile_fail,E0429 +use std::fmt::self; // error: `self` imports are only allowed within a { } list +``` + +To use a namespace itself in addition to some of its members, `self` may appear +as part of a brace-enclosed list of imports: + +``` +use std::fmt::{self, Debug}; +``` + +If you only want to import the namespace, do so directly: + +``` +use std::fmt; +``` +"##, + +E0430: r##" +The `self` import appears more than once in the list. + +Erroneous code example: + +```compile_fail,E0430 +use something::{self, self}; // error: `self` import can only appear once in + // the list +``` + +Please verify you didn't misspell the import name or remove the duplicated +`self` import. Example: + +``` +# mod something {} +# fn main() { +use something::{self}; // ok! +# } +``` +"##, + +E0431: r##" +An invalid `self` import was made. + +Erroneous code example: + +```compile_fail,E0431 +use {self}; // error: `self` import can only appear in an import list with a + // non-empty prefix +``` + +You cannot import the current module into itself, please remove this import +or verify you didn't misspell it. +"##, + +E0432: r##" +An import was unresolved. + +Erroneous code example: + +```compile_fail,E0432 +use something::Foo; // error: unresolved import `something::Foo`. +``` + +Paths in `use` statements are relative to the crate root. To import items +relative to the current and parent modules, use the `self::` and `super::` +prefixes, respectively. Also verify that you didn't misspell the import +name and that the import exists in the module from where you tried to +import it. Example: + +``` +use self::something::Foo; // ok! + +mod something { + pub struct Foo; +} +# fn main() {} +``` + +Or, if you tried to use a module from an external crate, you may have missed +the `extern crate` declaration (which is usually placed in the crate root): + +``` +extern crate core; // Required to use the `core` crate + +use core::any; +# fn main() {} +``` +"##, + +E0433: r##" +An undeclared type or module was used. + +Erroneous code example: + +```compile_fail,E0433 +let map = HashMap::new(); +// error: failed to resolve: use of undeclared type or module `HashMap` +``` + +Please verify you didn't misspell the type/module's name or that you didn't +forget to import it: + + +``` +use std::collections::HashMap; // HashMap has been imported. +let map: HashMap = HashMap::new(); // So it can be used! +``` +"##, + +E0434: r##" +This error indicates that a variable usage inside an inner function is invalid +because the variable comes from a dynamic environment. Inner functions do not +have access to their containing environment. + +Erroneous code example: + +```compile_fail,E0434 +fn foo() { + let y = 5; + fn bar() -> u32 { + y // error: can't capture dynamic environment in a fn item; use the + // || { ... } closure form instead. + } +} +``` + +Functions do not capture local variables. To fix this error, you can replace the +function with a closure: + +``` +fn foo() { + let y = 5; + let bar = || { + y + }; +} +``` + +or replace the captured variable with a constant or a static item: + +``` +fn foo() { + static mut X: u32 = 4; + const Y: u32 = 5; + fn bar() -> u32 { + unsafe { + X = 3; + } + Y + } +} +``` +"##, + +E0435: r##" +A non-constant value was used in a constant expression. + +Erroneous code example: + +```compile_fail,E0435 +let foo = 42; +let a: [u8; foo]; // error: attempt to use a non-constant value in a constant +``` + +To fix this error, please replace the value with a constant. Example: + +``` +let a: [u8; 42]; // ok! +``` + +Or: + +``` +const FOO: usize = 42; +let a: [u8; FOO]; // ok! +``` +"##, + +E0437: r##" +Trait implementations can only implement associated types that are members of +the trait in question. This error indicates that you attempted to implement +an associated type whose name does not match the name of any associated type +in the trait. + +Erroneous code example: + +```compile_fail,E0437 +trait Foo {} + +impl Foo for i32 { + type Bar = bool; +} +``` + +The solution to this problem is to remove the extraneous associated type: + +``` +trait Foo {} + +impl Foo for i32 {} +``` +"##, + +E0438: r##" +Trait implementations can only implement associated constants that are +members of the trait in question. This error indicates that you +attempted to implement an associated constant whose name does not +match the name of any associated constant in the trait. + +Erroneous code example: + +```compile_fail,E0438 +trait Foo {} + +impl Foo for i32 { + const BAR: bool = true; +} +``` + +The solution to this problem is to remove the extraneous associated constant: + +``` +trait Foo {} + +impl Foo for i32 {} +``` +"##, + +E0466: r##" +Macro import declarations were malformed. + +Erroneous code examples: + +```compile_fail,E0466 +#[macro_use(a_macro(another_macro))] // error: invalid import declaration +extern crate core as some_crate; + +#[macro_use(i_want = "some_macros")] // error: invalid import declaration +extern crate core as another_crate; +``` + +This is a syntax error at the level of attribute declarations. The proper +syntax for macro imports is the following: + +```ignore (cannot-doctest-multicrate-project) +// In some_crate: +#[macro_export] +macro_rules! get_tacos { + ... +} + +#[macro_export] +macro_rules! get_pimientos { + ... +} + +// In your crate: +#[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and +extern crate some_crate; // `get_pimientos` macros from some_crate +``` + +If you would like to import all exported macros, write `macro_use` with no +arguments. +"##, + +E0468: r##" +A non-root module attempts to import macros from another crate. + +Example of erroneous code: + +```compile_fail,E0468 +mod foo { + #[macro_use(debug_assert)] // error: must be at crate root to import + extern crate core; // macros from another crate + fn run_macro() { debug_assert!(true); } +} +``` + +Only `extern crate` imports at the crate root level are allowed to import +macros. + +Either move the macro import to crate root or do without the foreign macros. +This will work: + +``` +#[macro_use(debug_assert)] +extern crate core; + +mod foo { + fn run_macro() { debug_assert!(true); } +} +# fn main() {} +``` +"##, + +E0469: r##" +A macro listed for import was not found. + +Erroneous code example: + +```compile_fail,E0469 +#[macro_use(drink, be_merry)] // error: imported macro not found +extern crate alloc; + +fn main() { + // ... +} +``` + +Either the listed macro is not contained in the imported crate, or it is not +exported from the given crate. + +This could be caused by a typo. Did you misspell the macro's name? + +Double-check the names of the macros listed for import, and that the crate +in question exports them. + +A working version would be: + +```ignore (cannot-doctest-multicrate-project) +// In some_crate crate: +#[macro_export] +macro_rules! eat { + ... +} + +#[macro_export] +macro_rules! drink { + ... +} + +// In your crate: +#[macro_use(eat, drink)] +extern crate some_crate; //ok! +``` +"##, + +E0530: r##" +A binding shadowed something it shouldn't. + +Erroneous code example: + +```compile_fail,E0530 +static TEST: i32 = 0; + +let r: (i32, i32) = (0, 0); +match r { + TEST => {} // error: match bindings cannot shadow statics +} +``` + +To fix this error, just change the binding's name in order to avoid shadowing +one of the following: + +* struct name +* struct/enum variant +* static +* const +* associated const + +Fixed example: + +``` +static TEST: i32 = 0; + +let r: (i32, i32) = (0, 0); +match r { + something => {} // ok! +} +``` +"##, + +E0532: r##" +Pattern arm did not match expected kind. + +Erroneous code example: + +```compile_fail,E0532 +enum State { + Succeeded, + Failed(String), +} + +fn print_on_failure(state: &State) { + match *state { + // error: expected unit struct/variant or constant, found tuple + // variant `State::Failed` + State::Failed => println!("Failed"), + _ => () + } +} +``` + +To fix this error, ensure the match arm kind is the same as the expression +matched. + +Fixed example: + +``` +enum State { + Succeeded, + Failed(String), +} + +fn print_on_failure(state: &State) { + match *state { + State::Failed(ref msg) => println!("Failed with {}", msg), + _ => () + } +} +``` +"##, + +E0603: r##" +A private item was used outside its scope. + +Erroneous code example: + +```compile_fail,E0603 +mod SomeModule { + const PRIVATE: u32 = 0x_a_bad_1dea_u32; // This const is private, so we + // can't use it outside of the + // `SomeModule` module. +} + +println!("const value: {}", SomeModule::PRIVATE); // error: constant `PRIVATE` + // is private +``` + +In order to fix this error, you need to make the item public by using the `pub` +keyword. Example: + +``` +mod SomeModule { + pub const PRIVATE: u32 = 0x_a_bad_1dea_u32; // We set it public by using the + // `pub` keyword. +} + +println!("const value: {}", SomeModule::PRIVATE); // ok! +``` +"##, + +E0659: r##" +An item usage is ambiguous. + +Erroneous code example: + +```compile_fail,E0659 +pub mod moon { + pub fn foo() {} +} + +pub mod earth { + pub fn foo() {} +} + +mod collider { + pub use moon::*; + pub use earth::*; +} + +fn main() { + collider::foo(); // ERROR: `foo` is ambiguous +} +``` + +This error generally appears when two items with the same name are imported into +a module. Here, the `foo` functions are imported and reexported from the +`collider` module and therefore, when we're using `collider::foo()`, both +functions collide. + +To solve this error, the best solution is generally to keep the path before the +item when using it. Example: + +``` +pub mod moon { + pub fn foo() {} +} + +pub mod earth { + pub fn foo() {} +} + +mod collider { + pub use moon; + pub use earth; +} + +fn main() { + collider::moon::foo(); // ok! + collider::earth::foo(); // ok! +} +``` +"##, + +E0671: r##" +Const parameters cannot depend on type parameters. +The following is therefore invalid: +```compile_fail,E0671 +#![feature(const_generics)] + +fn const_id() -> T { // error: const parameter + // depends on type parameter + N +} +``` +"##, + +} + +register_diagnostics! { +// E0153, unused error code +// E0157, unused error code +// E0257, +// E0258, +// E0402, // cannot use an outer type parameter in this context +// E0406, merged into 420 +// E0410, merged into 408 +// E0413, merged into 530 +// E0414, merged into 530 +// E0417, merged into 532 +// E0418, merged into 532 +// E0419, merged into 531 +// E0420, merged into 532 +// E0421, merged into 531 + E0531, // unresolved pattern path kind `name` +// E0427, merged into 530 +// E0467, removed +// E0470, removed + E0573, + E0574, + E0575, + E0576, + E0577, + E0578, +} diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs deleted file mode 100644 index cd771d93e00f6..0000000000000 --- a/src/librustc_resolve/error_reporting.rs +++ /dev/null @@ -1,580 +0,0 @@ -use std::cmp::Reverse; - -use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; -use log::debug; -use rustc::hir::def::*; -use rustc::hir::def::Namespace::*; -use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; -use rustc::session::config::nightly_options; -use syntax::ast::{ExprKind}; -use syntax::symbol::keywords; -use syntax_pos::Span; - -use crate::macros::ParentScope; -use crate::resolve_imports::ImportResolver; -use crate::{import_candidate_to_enum_paths, is_self_type, is_self_value, path_names_to_string}; -use crate::{AssocSuggestion, CrateLint, ImportSuggestion, ModuleOrUniformRoot, PathResult, - PathSource, Resolver, Segment}; - -impl<'a> Resolver<'a> { - /// Handles error reporting for `smart_resolve_path_fragment` function. - /// Creates base error and amends it with one short label and possibly some longer helps/notes. - pub(crate) fn smart_resolve_report_errors( - &mut self, - path: &[Segment], - span: Span, - source: PathSource<'_>, - def: Option, - ) -> (DiagnosticBuilder<'a>, Vec) { - let ident_span = path.last().map_or(span, |ident| ident.ident.span); - let ns = source.namespace(); - let is_expected = &|def| source.is_expected(def); - let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false }; - - // Make the base error. - let expected = source.descr_expected(); - let path_str = Segment::names_to_string(path); - let item_str = path.last().unwrap().ident; - let code = source.error_code(def.is_some()); - let (base_msg, fallback_label, base_span) = if let Some(def) = def { - (format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str), - format!("not a {}", expected), - span) - } else { - let item_span = path.last().unwrap().ident.span; - let (mod_prefix, mod_str) = if path.len() == 1 { - (String::new(), "this scope".to_string()) - } else if path.len() == 2 && path[0].ident.name == keywords::PathRoot.name() { - (String::new(), "the crate root".to_string()) - } else { - let mod_path = &path[..path.len() - 1]; - let mod_prefix = match self.resolve_path_without_parent_scope( - mod_path, Some(TypeNS), false, span, CrateLint::No - ) { - PathResult::Module(ModuleOrUniformRoot::Module(module)) => - module.def(), - _ => None, - }.map_or(String::new(), |def| format!("{} ", def.kind_name())); - (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path))) - }; - (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), - format!("not found in {}", mod_str), - item_span) - }; - - let code = DiagnosticId::Error(code.into()); - let mut err = self.session.struct_span_err_with_code(base_span, &base_msg, code); - - // Emit help message for fake-self from other languages (e.g., `this` in Javascript). - if ["this", "my"].contains(&&*item_str.as_str()) - && self.self_value_is_available(path[0].ident.span, span) { - err.span_suggestion( - span, - "did you mean", - "self".to_string(), - Applicability::MaybeIncorrect, - ); - } - - // Emit special messages for unresolved `Self` and `self`. - if is_self_type(path, ns) { - __diagnostic_used!(E0411); - err.code(DiagnosticId::Error("E0411".into())); - err.span_label(span, format!("`Self` is only available in impls, traits, \ - and type definitions")); - return (err, Vec::new()); - } - if is_self_value(path, ns) { - debug!("smart_resolve_path_fragment: E0424, source={:?}", source); - - __diagnostic_used!(E0424); - err.code(DiagnosticId::Error("E0424".into())); - err.span_label(span, match source { - PathSource::Pat => { - format!("`self` value is a keyword \ - and may not be bound to \ - variables or shadowed") - } - _ => { - format!("`self` value is a keyword \ - only available in methods \ - with `self` parameter") - } - }); - return (err, Vec::new()); - } - - // Try to lookup name in more relaxed fashion for better error reporting. - let ident = path.last().unwrap().ident; - let candidates = self.lookup_import_candidates(ident, ns, is_expected) - .drain(..) - .filter(|ImportSuggestion { did, .. }| { - match (did, def.and_then(|def| def.opt_def_id())) { - (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did, - _ => true, - } - }) - .collect::>(); - if candidates.is_empty() && is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { - let enum_candidates = - self.lookup_import_candidates(ident, ns, is_enum_variant); - let mut enum_candidates = enum_candidates.iter() - .map(|suggestion| { - import_candidate_to_enum_paths(&suggestion) - }).collect::>(); - enum_candidates.sort(); - - if !enum_candidates.is_empty() { - // Contextualize for E0412 "cannot find type", but don't belabor the point - // (that it's a variant) for E0573 "expected type, found variant". - let preamble = if def.is_none() { - let others = match enum_candidates.len() { - 1 => String::new(), - 2 => " and 1 other".to_owned(), - n => format!(" and {} others", n) - }; - format!("there is an enum variant `{}`{}; ", - enum_candidates[0].0, others) - } else { - String::new() - }; - let msg = format!("{}try using the variant's enum", preamble); - - err.span_suggestions( - span, - &msg, - enum_candidates.into_iter() - .map(|(_variant_path, enum_ty_path)| enum_ty_path) - // Variants re-exported in prelude doesn't mean `prelude::v1` is the - // type name! - // FIXME: is there a more principled way to do this that - // would work for other re-exports? - .filter(|enum_ty_path| enum_ty_path != "std::prelude::v1") - // Also write `Option` rather than `std::prelude::v1::Option`. - .map(|enum_ty_path| { - // FIXME #56861: DRY-er prelude filtering. - enum_ty_path.trim_start_matches("std::prelude::v1::").to_owned() - }), - Applicability::MachineApplicable, - ); - } - } - if path.len() == 1 && self.self_type_is_available(span) { - if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) { - let self_is_available = self.self_value_is_available(path[0].ident.span, span); - match candidate { - AssocSuggestion::Field => { - err.span_suggestion( - span, - "try", - format!("self.{}", path_str), - Applicability::MachineApplicable, - ); - if !self_is_available { - err.span_label(span, format!("`self` value is a keyword \ - only available in \ - methods with `self` parameter")); - } - } - AssocSuggestion::MethodWithSelf if self_is_available => { - err.span_suggestion( - span, - "try", - format!("self.{}", path_str), - Applicability::MachineApplicable, - ); - } - AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => { - err.span_suggestion( - span, - "try", - format!("Self::{}", path_str), - Applicability::MachineApplicable, - ); - } - } - return (err, candidates); - } - } - - let mut levenshtein_worked = false; - - // Try Levenshtein algorithm. - let suggestion = self.lookup_typo_candidate(path, ns, is_expected, span); - if let Some(suggestion) = suggestion { - let msg = format!( - "{} {} with a similar name exists", - suggestion.article, suggestion.kind - ); - err.span_suggestion( - ident_span, - &msg, - suggestion.candidate.to_string(), - Applicability::MaybeIncorrect, - ); - - levenshtein_worked = true; - } - - // Try context-dependent help if relaxed lookup didn't work. - if let Some(def) = def { - if self.smart_resolve_context_dependent_help(&mut err, - span, - source, - def, - &path_str, - &fallback_label) { - return (err, candidates); - } - } - - // Fallback label. - if !levenshtein_worked { - err.span_label(base_span, fallback_label); - self.type_ascription_suggestion(&mut err, base_span); - } - (err, candidates) - } - - /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment` - /// function. - /// Returns `true` if able to provide context-dependent help. - fn smart_resolve_context_dependent_help( - &mut self, - err: &mut DiagnosticBuilder<'a>, - span: Span, - source: PathSource<'_>, - def: Def, - path_str: &str, - fallback_label: &str, - ) -> bool { - let ns = source.namespace(); - let is_expected = &|def| source.is_expected(def); - - match (def, source) { - (Def::Macro(..), _) => { - err.span_suggestion( - span, - "use `!` to invoke the macro", - format!("{}!", path_str), - Applicability::MaybeIncorrect, - ); - if path_str == "try" && span.rust_2015() { - err.note("if you want the `try` keyword, \ - you need to be in the 2018 edition"); - } - } - (Def::TyAlias(..), PathSource::Trait(_)) => { - err.span_label(span, "type aliases cannot be used as traits"); - if nightly_options::is_nightly_build() { - err.note("did you mean to use a trait alias?"); - } - } - (Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node { - ExprKind::Field(_, ident) => { - err.span_suggestion( - parent.span, - "use the path separator to refer to an item", - format!("{}::{}", path_str, ident), - Applicability::MaybeIncorrect, - ); - } - ExprKind::MethodCall(ref segment, ..) => { - let span = parent.span.with_hi(segment.ident.span.hi()); - err.span_suggestion( - span, - "use the path separator to refer to an item", - format!("{}::{}", path_str, segment.ident), - Applicability::MaybeIncorrect, - ); - } - _ => return false, - }, - (Def::Enum(..), PathSource::TupleStruct) - | (Def::Enum(..), PathSource::Expr(..)) => { - if let Some(variants) = self.collect_enum_variants(def) { - err.note(&format!("did you mean to use one \ - of the following variants?\n{}", - variants.iter() - .map(|suggestion| path_names_to_string(suggestion)) - .map(|suggestion| format!("- `{}`", suggestion)) - .collect::>() - .join("\n"))); - } else { - err.note("did you mean to use one of the enum's variants?"); - } - }, - (Def::Struct(def_id), _) if ns == ValueNS => { - if let Some((ctor_def, ctor_vis)) - = self.struct_constructors.get(&def_id).cloned() { - let accessible_ctor = self.is_accessible(ctor_vis); - if is_expected(ctor_def) && !accessible_ctor { - err.span_label(span, format!("constructor is not visible \ - here due to private fields")); - } - } else { - // HACK(estebank): find a better way to figure out that this was a - // parser issue where a struct literal is being used on an expression - // where a brace being opened means a block is being started. Look - // ahead for the next text to see if `span` is followed by a `{`. - let sm = self.session.source_map(); - let mut sp = span; - loop { - sp = sm.next_point(sp); - match sm.span_to_snippet(sp) { - Ok(ref snippet) => { - if snippet.chars().any(|c| { !c.is_whitespace() }) { - break; - } - } - _ => break, - } - } - let followed_by_brace = match sm.span_to_snippet(sp) { - Ok(ref snippet) if snippet == "{" => true, - _ => false, - }; - // In case this could be a struct literal that needs to be surrounded - // by parenthesis, find the appropriate span. - let mut i = 0; - let mut closing_brace = None; - loop { - sp = sm.next_point(sp); - match sm.span_to_snippet(sp) { - Ok(ref snippet) => { - if snippet == "}" { - let sp = span.to(sp); - if let Ok(snippet) = sm.span_to_snippet(sp) { - closing_brace = Some((sp, snippet)); - } - break; - } - } - _ => break, - } - i += 1; - // The bigger the span, the more likely we're incorrect -- - // bound it to 100 chars long. - if i > 100 { - break; - } - } - match source { - PathSource::Expr(Some(parent)) => { - match parent.node { - ExprKind::MethodCall(ref path_assignment, _) => { - err.span_suggestion( - sm.start_point(parent.span) - .to(path_assignment.ident.span), - "use `::` to access an associated function", - format!("{}::{}", - path_str, - path_assignment.ident), - Applicability::MaybeIncorrect - ); - }, - _ => { - err.span_label( - span, - format!("did you mean `{} {{ /* fields */ }}`?", - path_str), - ); - }, - } - }, - PathSource::Expr(None) if followed_by_brace == true => { - if let Some((sp, snippet)) = closing_brace { - err.span_suggestion( - sp, - "surround the struct literal with parenthesis", - format!("({})", snippet), - Applicability::MaybeIncorrect, - ); - } else { - err.span_label( - span, - format!("did you mean `({} {{ /* fields */ }})`?", - path_str), - ); - } - }, - _ => { - err.span_label( - span, - format!("did you mean `{} {{ /* fields */ }}`?", - path_str), - ); - }, - } - } - } - (Def::Union(..), _) | - (Def::Variant(..), _) | - (Def::VariantCtor(_, CtorKind::Fictive), _) if ns == ValueNS => { - err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", - path_str)); - } - (Def::SelfTy(..), _) if ns == ValueNS => { - err.span_label(span, fallback_label); - err.note("can't use `Self` as a constructor, you must use the \ - implemented struct"); - } - (Def::TyAlias(_), _) | (Def::AssociatedTy(..), _) if ns == ValueNS => { - err.note("can't use a type alias as a constructor"); - } - _ => return false, - } - true - } -} - -impl<'a, 'b:'a> ImportResolver<'a, 'b> { - /// Adds suggestions for a path that cannot be resolved. - pub(crate) fn make_path_suggestion( - &mut self, - span: Span, - mut path: Vec, - parent_scope: &ParentScope<'b>, - ) -> Option<(Vec, Option)> { - debug!("make_path_suggestion: span={:?} path={:?}", span, path); - - match (path.get(0), path.get(1)) { - // `{{root}}::ident::...` on both editions. - // On 2015 `{{root}}` is usually added implicitly. - (Some(fst), Some(snd)) if fst.ident.name == keywords::PathRoot.name() && - !snd.ident.is_path_segment_keyword() => {} - // `ident::...` on 2018. - (Some(fst), _) if fst.ident.span.rust_2018() && - !fst.ident.is_path_segment_keyword() => { - // Insert a placeholder that's later replaced by `self`/`super`/etc. - path.insert(0, Segment::from_ident(keywords::Invalid.ident())); - } - _ => return None, - } - - self.make_missing_self_suggestion(span, path.clone(), parent_scope) - .or_else(|| self.make_missing_crate_suggestion(span, path.clone(), parent_scope)) - .or_else(|| self.make_missing_super_suggestion(span, path.clone(), parent_scope)) - .or_else(|| self.make_external_crate_suggestion(span, path, parent_scope)) - } - - /// Suggest a missing `self::` if that resolves to an correct module. - /// - /// ``` - /// | - /// LL | use foo::Bar; - /// | ^^^ did you mean `self::foo`? - /// ``` - fn make_missing_self_suggestion( - &mut self, - span: Span, - mut path: Vec, - parent_scope: &ParentScope<'b>, - ) -> Option<(Vec, Option)> { - // Replace first ident with `self` and check if that is valid. - path[0].ident.name = keywords::SelfLower.name(); - let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); - debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result); - if let PathResult::Module(..) = result { - Some((path, None)) - } else { - None - } - } - - /// Suggests a missing `crate::` if that resolves to an correct module. - /// - /// ``` - /// | - /// LL | use foo::Bar; - /// | ^^^ did you mean `crate::foo`? - /// ``` - fn make_missing_crate_suggestion( - &mut self, - span: Span, - mut path: Vec, - parent_scope: &ParentScope<'b>, - ) -> Option<(Vec, Option)> { - // Replace first ident with `crate` and check if that is valid. - path[0].ident.name = keywords::Crate.name(); - let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); - debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result); - if let PathResult::Module(..) = result { - Some(( - path, - Some( - "`use` statements changed in Rust 2018; read more at \ - ".to_string() - ), - )) - } else { - None - } - } - - /// Suggests a missing `super::` if that resolves to an correct module. - /// - /// ``` - /// | - /// LL | use foo::Bar; - /// | ^^^ did you mean `super::foo`? - /// ``` - fn make_missing_super_suggestion( - &mut self, - span: Span, - mut path: Vec, - parent_scope: &ParentScope<'b>, - ) -> Option<(Vec, Option)> { - // Replace first ident with `crate` and check if that is valid. - path[0].ident.name = keywords::Super.name(); - let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); - debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result); - if let PathResult::Module(..) = result { - Some((path, None)) - } else { - None - } - } - - /// Suggests a missing external crate name if that resolves to an correct module. - /// - /// ``` - /// | - /// LL | use foobar::Baz; - /// | ^^^^^^ did you mean `baz::foobar`? - /// ``` - /// - /// Used when importing a submodule of an external crate but missing that crate's - /// name as the first part of path. - fn make_external_crate_suggestion( - &mut self, - span: Span, - mut path: Vec, - parent_scope: &ParentScope<'b>, - ) -> Option<(Vec, Option)> { - if path[1].ident.span.rust_2015() { - return None; - } - - // Sort extern crate names in reverse order to get - // 1) some consistent ordering for emitted dignostics, and - // 2) `std` suggestions before `core` suggestions. - let mut extern_crate_names = - self.resolver.extern_prelude.iter().map(|(ident, _)| ident.name).collect::>(); - extern_crate_names.sort_by_key(|name| Reverse(name.as_str())); - - for name in extern_crate_names.into_iter() { - // Replace first ident with a crate name and check if that is valid. - path[0].ident.name = name; - let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); - debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}", - name, path, result); - if let PathResult::Module(..) = result { - return Some((path, None)); - } - } - - None - } -} diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e9331fcd8bad1..79e168ed64453 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1,28 +1,36 @@ +// ignore-tidy-filelength + #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] #![feature(nll)] #![feature(rustc_diagnostic_macros)] +#![cfg_attr(bootstrap, feature(type_alias_enum_variants))] #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] pub use rustc::hir::def::{Namespace, PerNS}; use GenericParameters::*; use RibKind::*; +use smallvec::smallvec; use rustc::hir::map::{Definitions, DefCollector}; use rustc::hir::{self, PrimTy, Bool, Char, Float, Int, Uint, Str}; use rustc::middle::cstore::CrateStore; use rustc::session::Session; use rustc::lint; -use rustc::hir::def::*; +use rustc::hir::def::{ + self, DefKind, PartialRes, CtorKind, CtorOf, NonMacroAttrKind, ExportMap +}; use rustc::hir::def::Namespace::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; -use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; +use rustc::hir::{TraitCandidate, TraitMap, GlobMap}; use rustc::ty::{self, DefIdTree}; use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap}; use rustc::{bug, span_bug}; @@ -33,10 +41,10 @@ use rustc_metadata::cstore::CStore; use syntax::source_map::SourceMap; use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext}; use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy}; -use syntax::ext::base::SyntaxExtension; +use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::base::MacroKind; -use syntax::symbol::{Symbol, keywords}; +use syntax::symbol::{Symbol, kw, sym}; use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit::{self, FnKind, Visitor}; @@ -49,7 +57,7 @@ use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind}; use syntax::ptr::P; use syntax::{span_err, struct_span_err, unwrap_or, walk_list}; -use syntax_pos::{BytePos, Span, DUMMY_SP, MultiSpan}; +use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use log::debug; @@ -60,14 +68,18 @@ use std::collections::BTreeSet; use std::mem::replace; use rustc_data_structures::ptr_key::PtrKey; use rustc_data_structures::sync::Lrc; +use smallvec::SmallVec; +use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding}; use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver}; use macros::{InvocationData, LegacyBinding, ParentScope}; +type Res = def::Res; + // N.B., this module needs to be declared first so diagnostics are // registered before they are used. +mod error_codes; mod diagnostics; -mod error_reporting; mod macros; mod check_unused; mod build_reduced_graph; @@ -137,9 +149,12 @@ impl Ord for BindingError { } } +/// A vector of spans and replacements, a message and applicability. +type Suggestion = (Vec<(Span, String)>, String, Applicability); + enum ResolutionError<'a> { /// Error E0401: can't use type or const parameters from outer function. - GenericParamsFromOuterFunction(Def), + GenericParamsFromOuterFunction(Res), /// Error E0403: the name is already used for a type or const parameter in this generic /// parameter list. NameAlreadyUsedInParameterList(Name, &'a Span), @@ -166,7 +181,7 @@ enum ResolutionError<'a> { /// Error E0431: `self` import can only appear in an import list with a non-empty prefix. SelfImportOnlyInImportListWithNonEmptyPrefix, /// Error E0433: failed to resolve. - FailedToResolve(&'a str), + FailedToResolve { label: String, suggestion: Option }, /// Error E0434: can't capture dynamic environment in a fn item. CannotCaptureDynamicEnvironmentInFnItem, /// Error E0435: attempt to use a non-constant value in a constant. @@ -175,6 +190,8 @@ enum ResolutionError<'a> { BindingShadowsSomethingUnacceptable(&'a str, Name, &'a NameBinding<'a>), /// Error E0128: type parameters with a default cannot use forward-declared identifiers. ForwardDeclaredTyParam, // FIXME(const_generics:defaults) + /// Error E0671: const parameter cannot depend on type parameter. + ConstParamDependentOnTypeParam, } /// Combines an error with provided span and emits it. @@ -192,7 +209,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>, resolution_error: ResolutionError<'a>) -> DiagnosticBuilder<'sess> { match resolution_error { - ResolutionError::GenericParamsFromOuterFunction(outer_def) => { + ResolutionError::GenericParamsFromOuterFunction(outer_res) => { let mut err = struct_span_err!(resolver.session, span, E0401, @@ -201,8 +218,8 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>, err.span_label(span, format!("use of generic parameter from outer function")); let cm = resolver.session.source_map(); - match outer_def { - Def::SelfTy(maybe_trait_defid, maybe_impl_defid) => { + match outer_res { + Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => { if let Some(impl_span) = maybe_impl_defid.and_then(|def_id| { resolver.definitions.opt_span(def_id) }) { @@ -222,19 +239,19 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>, } return err; }, - Def::TyParam(def_id) => { + Res::Def(DefKind::TyParam, def_id) => { if let Some(span) = resolver.definitions.opt_span(def_id) { - err.span_label(span, "type variable from outer function"); + err.span_label(span, "type parameter from outer function"); } } - Def::ConstParam(def_id) => { + Res::Def(DefKind::ConstParam, def_id) => { if let Some(span) = resolver.definitions.opt_span(def_id) { - err.span_label(span, "const variable from outer function"); + err.span_label(span, "const parameter from outer function"); } } _ => { - bug!("GenericParamsFromOuterFunction should only be used with Def::SelfTy, \ - Def::TyParam"); + bug!("GenericParamsFromOuterFunction should only be used with Res::SelfTy, \ + DefKind::TyParam"); } } @@ -354,7 +371,12 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>, "use of undeclared label `{}`", name); if let Some(lev_candidate) = lev_candidate { - err.span_label(span, format!("did you mean `{}`?", lev_candidate)); + err.span_suggestion( + span, + "a label with a similar name exists in this scope", + lev_candidate.to_string(), + Applicability::MaybeIncorrect, + ); } else { err.span_label(span, format!("undeclared label `{}`", name)); } @@ -380,10 +402,15 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>, err.span_label(span, "can only appear in an import list with a non-empty prefix"); err } - ResolutionError::FailedToResolve(msg) => { + ResolutionError::FailedToResolve { label, suggestion } => { let mut err = struct_span_err!(resolver.session, span, E0433, - "failed to resolve: {}", msg); - err.span_label(span, msg); + "failed to resolve: {}", &label); + err.span_label(span, label); + + if let Some((suggestions, msg, applicability)) = suggestion { + err.multipart_suggestion(&msg, suggestions, applicability); + } + err } ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => { @@ -420,6 +447,16 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>, span, "defaulted type parameters cannot be forward declared".to_string()); err } + ResolutionError::ConstParamDependentOnTypeParam => { + let mut err = struct_span_err!( + resolver.session, + span, + E0671, + "const parameters cannot depend on type parameters" + ); + err.span_label(span, format!("const parameter depends on type parameter")); + err + } } } @@ -448,8 +485,6 @@ type BindingMap = FxHashMap; #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum PatternSource { Match, - IfLet, - WhileLet, Let, For, FnParam, @@ -459,8 +494,6 @@ impl PatternSource { fn descr(self) -> &'static str { match self { PatternSource::Match => "match binding", - PatternSource::IfLet => "if let binding", - PatternSource::WhileLet => "while let binding", PatternSource::Let => "let binding", PatternSource::For => "for binding", PatternSource::FnParam => "function parameter", @@ -536,7 +569,7 @@ impl<'a> PathSource<'a> { MacroNS => bug!("associated macro"), }, PathSource::Expr(parent) => match parent.map(|p| &p.node) { - // "function" here means "anything callable" rather than `Def::Fn`, + // "function" here means "anything callable" rather than `DefKind::Fn`, // this is not precise but usually more helpful than just "value". Some(&ExprKind::Call(..)) => "function", _ => "value", @@ -544,57 +577,72 @@ impl<'a> PathSource<'a> { } } - fn is_expected(self, def: Def) -> bool { + fn is_expected(self, res: Res) -> bool { match self { - PathSource::Type => match def { - Def::Struct(..) | Def::Union(..) | Def::Enum(..) | - Def::Trait(..) | Def::TraitAlias(..) | Def::TyAlias(..) | - Def::AssociatedTy(..) | Def::PrimTy(..) | Def::TyParam(..) | - Def::SelfTy(..) | Def::Existential(..) | Def::ForeignTy(..) => true, + PathSource::Type => match res { + Res::Def(DefKind::Struct, _) + | Res::Def(DefKind::Union, _) + | Res::Def(DefKind::Enum, _) + | Res::Def(DefKind::Trait, _) + | Res::Def(DefKind::TraitAlias, _) + | Res::Def(DefKind::TyAlias, _) + | Res::Def(DefKind::AssocTy, _) + | Res::PrimTy(..) + | Res::Def(DefKind::TyParam, _) + | Res::SelfTy(..) + | Res::Def(DefKind::Existential, _) + | Res::Def(DefKind::ForeignTy, _) => true, _ => false, }, - PathSource::Trait(AliasPossibility::No) => match def { - Def::Trait(..) => true, + PathSource::Trait(AliasPossibility::No) => match res { + Res::Def(DefKind::Trait, _) => true, _ => false, }, - PathSource::Trait(AliasPossibility::Maybe) => match def { - Def::Trait(..) => true, - Def::TraitAlias(..) => true, + PathSource::Trait(AliasPossibility::Maybe) => match res { + Res::Def(DefKind::Trait, _) => true, + Res::Def(DefKind::TraitAlias, _) => true, _ => false, }, - PathSource::Expr(..) => match def { - Def::StructCtor(_, CtorKind::Const) | Def::StructCtor(_, CtorKind::Fn) | - Def::VariantCtor(_, CtorKind::Const) | Def::VariantCtor(_, CtorKind::Fn) | - Def::Const(..) | Def::Static(..) | Def::Local(..) | Def::Upvar(..) | - Def::Fn(..) | Def::Method(..) | Def::AssociatedConst(..) | - Def::SelfCtor(..) | Def::ConstParam(..) => true, + PathSource::Expr(..) => match res { + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) + | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) + | Res::Def(DefKind::Const, _) + | Res::Def(DefKind::Static, _) + | Res::Local(..) + | Res::Def(DefKind::Fn, _) + | Res::Def(DefKind::Method, _) + | Res::Def(DefKind::AssocConst, _) + | Res::SelfCtor(..) + | Res::Def(DefKind::ConstParam, _) => true, _ => false, }, - PathSource::Pat => match def { - Def::StructCtor(_, CtorKind::Const) | - Def::VariantCtor(_, CtorKind::Const) | - Def::Const(..) | Def::AssociatedConst(..) | - Def::SelfCtor(..) => true, + PathSource::Pat => match res { + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | + Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) | + Res::SelfCtor(..) => true, _ => false, }, - PathSource::TupleStruct => match def { - Def::StructCtor(_, CtorKind::Fn) | - Def::VariantCtor(_, CtorKind::Fn) | - Def::SelfCtor(..) => true, + PathSource::TupleStruct => match res { + Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true, _ => false, }, - PathSource::Struct => match def { - Def::Struct(..) | Def::Union(..) | Def::Variant(..) | - Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => true, + PathSource::Struct => match res { + Res::Def(DefKind::Struct, _) + | Res::Def(DefKind::Union, _) + | Res::Def(DefKind::Variant, _) + | Res::Def(DefKind::TyAlias, _) + | Res::Def(DefKind::AssocTy, _) + | Res::SelfTy(..) => true, _ => false, }, - PathSource::TraitItem(ns) => match def { - Def::AssociatedConst(..) | Def::Method(..) if ns == ValueNS => true, - Def::AssociatedTy(..) if ns == TypeNS => true, + PathSource::TraitItem(ns) => match res { + Res::Def(DefKind::AssocConst, _) + | Res::Def(DefKind::Method, _) if ns == ValueNS => true, + Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true, _ => false, }, - PathSource::Visibility => match def { - Def::Mod(..) => true, + PathSource::Visibility => match res { + Res::Def(DefKind::Mod, _) => true, _ => false, }, } @@ -710,7 +758,7 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder { ItemKind::Use(..) => { // don't suggest placing a use before the prelude // import or other generated ones - if item.span.ctxt().outer().expn_info().is_none() { + if item.span.ctxt().outer_expn_info().is_none() { self.span = Some(item.span.shrink_to_lo()); self.found_use = true; return; @@ -720,7 +768,7 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder { ItemKind::ExternCrate(_) => {} // but place them before the first other item _ => if self.span.map_or(true, |span| item.span < span ) { - if item.span.ctxt().outer().expn_info().is_none() { + if item.span.ctxt().outer_expn_info().is_none() { // don't insert between attributes and an item if item.attrs.is_empty() { self.span = Some(item.span.shrink_to_lo()); @@ -768,10 +816,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type); } TyKind::ImplicitSelf => { - let self_ty = keywords::SelfUpper.ident(); - let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.id), ty.span) - .map_or(Def::Err, |d| d.def()); - self.record_def(ty.id, PathResolution::new(def)); + let self_ty = Ident::with_empty_ctxt(kw::SelfUpper); + let res = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.id), ty.span) + .map_or(Res::Err, |d| d.res()); + self.record_partial_res(ty.id, PartialRes::new(res)); } _ => (), } @@ -801,18 +849,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { function_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, _: Span, - node_id: NodeId) + _: NodeId) { debug!("(resolving function) entering function"); - let (rib_kind, asyncness) = match function_kind { - FnKind::ItemFn(_, ref header, ..) => - (ItemRibKind, header.asyncness.node), - FnKind::Method(_, ref sig, _, _) => - (TraitOrImplItemRibKind, sig.header.asyncness.node), - FnKind::Closure(_) => - // Async closures aren't resolved through `visit_fn`-- they're - // processed separately - (ClosureRibKind(node_id), IsAsync::NotAsync), + let rib_kind = match function_kind { + FnKind::ItemFn(..) => FnItemRibKind, + FnKind::Method(..) => AssocItemRibKind, + FnKind::Closure(_) => NormalRibKind, }; // Create a value rib for the function. @@ -833,12 +876,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { visit::walk_fn_ret_ty(self, &declaration.output); // Resolve the function body, potentially inside the body of an async closure - if let IsAsync::Async { closure_id, .. } = asyncness { - let rib_kind = ClosureRibKind(closure_id); - self.ribs[ValueNS].push(Rib::new(rib_kind)); - self.label_ribs.push(Rib::new(rib_kind)); - } - match function_kind { FnKind::ItemFn(.., body) | FnKind::Method(.., body) => { @@ -849,12 +886,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { } }; - // Leave the body of the async closure - if asyncness.is_async() { - self.label_ribs.pop(); - self.ribs[ValueNS].pop(); - } - debug!("(resolving function) leaving function"); self.label_ribs.pop(); @@ -876,13 +907,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { GenericParamKind::Type { ref default, .. } => { found_default |= default.is_some(); if found_default { - Some((Ident::with_empty_ctxt(param.ident.name), Def::Err)) + Some((Ident::with_empty_ctxt(param.ident.name), Res::Err)) } else { None } } })); + // We also ban access to type parameters for use as the types of const parameters. + let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy); + const_ty_param_ban_rib.bindings.extend(generics.params.iter() + .filter(|param| { + if let GenericParamKind::Type { .. } = param.kind { + true + } else { + false + } + }) + .map(|param| (Ident::with_empty_ctxt(param.ident.name), Res::Err))); + for param in &generics.params { match param.kind { GenericParamKind::Lifetime { .. } => self.visit_generic_param(param), @@ -901,11 +944,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name)); } GenericParamKind::Const { ref ty } => { + self.ribs[TypeNS].push(const_ty_param_ban_rib); + for bound in ¶m.bounds { self.visit_param_bound(bound); } self.visit_ty(ty); + + const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap(); } } } @@ -925,22 +972,22 @@ enum GenericParameters<'a, 'b> { RibKind<'a>), } -/// The rib kind controls the translation of local -/// definitions (`Def::Local`) to upvars (`Def::Upvar`). +/// The rib kind restricts certain accesses, +/// e.g. to a `Res::Local` of an outer item. #[derive(Copy, Clone, Debug)] enum RibKind<'a> { - /// No translation needs to be applied. + /// No restriction needs to be applied. NormalRibKind, - /// We passed through a closure scope at the given `NodeId`. - /// Translate upvars as appropriate. - ClosureRibKind(NodeId /* func id */), - /// We passed through an impl or trait and are now in one of its /// methods or associated types. Allow references to ty params that impl or trait /// binds. Disallow any other upvars (including other ty params that are /// upvars). - TraitOrImplItemRibKind, + AssocItemRibKind, + + /// We passed through a function definition. Disallow upvars. + /// Permit only those const parameters that are specified in the function's generics. + FnItemRibKind, /// We passed through an item scope. Disallow upvars. ItemRibKind, @@ -958,6 +1005,9 @@ enum RibKind<'a> { /// from the default of a type parameter because they're not declared /// before said type parameter. Also see the `visit_generics` override. ForwardTyParamBanRibKind, + + /// We forbid the use of type parameters as the types of const parameters. + TyParamAsConstParamTy, } /// A single local scope. @@ -973,13 +1023,13 @@ enum RibKind<'a> { /// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When /// resolving, the name is looked up from inside out. #[derive(Debug)] -struct Rib<'a> { - bindings: FxHashMap, +struct Rib<'a, R = Res> { + bindings: FxHashMap, kind: RibKind<'a>, } -impl<'a> Rib<'a> { - fn new(kind: RibKind<'a>) -> Rib<'a> { +impl<'a, R> Rib<'a, R> { + fn new(kind: RibKind<'a>) -> Rib<'a, R> { Rib { bindings: Default::default(), kind, @@ -989,12 +1039,12 @@ impl<'a> Rib<'a> { /// An intermediate resolution result. /// -/// This refers to the thing referred by a name. The difference between `Def` and `Item` is that -/// items are visible in their whole block, while defs only from the place they are defined +/// This refers to the thing referred by a name. The difference between `Res` and `Item` is that +/// items are visible in their whole block, while `Res`es only from the place they are defined /// forward. enum LexicalScopeBinding<'a> { Item(&'a NameBinding<'a>), - Def(Def), + Res(Res), } impl<'a> LexicalScopeBinding<'a> { @@ -1005,10 +1055,10 @@ impl<'a> LexicalScopeBinding<'a> { } } - fn def(self) -> Def { + fn res(self) -> Res { match self { - LexicalScopeBinding::Item(binding) => binding.def(), - LexicalScopeBinding::Def(def) => def, + LexicalScopeBinding::Item(binding) => binding.res(), + LexicalScopeBinding::Res(res) => res, } } } @@ -1035,7 +1085,7 @@ impl ModuleOrUniformRoot<'_> { fn same_def(lhs: Self, rhs: Self) -> bool { match (lhs, rhs) { (ModuleOrUniformRoot::Module(lhs), - ModuleOrUniformRoot::Module(rhs)) => lhs.def() == rhs.def(), + ModuleOrUniformRoot::Module(rhs)) => lhs.def_id() == rhs.def_id(), (ModuleOrUniformRoot::CrateRootAndExternPrelude, ModuleOrUniformRoot::CrateRootAndExternPrelude) | (ModuleOrUniformRoot::ExternPrelude, ModuleOrUniformRoot::ExternPrelude) | @@ -1048,9 +1098,14 @@ impl ModuleOrUniformRoot<'_> { #[derive(Clone, Debug)] enum PathResult<'a> { Module(ModuleOrUniformRoot<'a>), - NonModule(PathResolution), + NonModule(PartialRes), Indeterminate, - Failed(Span, String, bool /* is the error from the last segment? */), + Failed { + span: Span, + label: String, + suggestion: Option, + is_error_from_last_segment: bool, + }, } enum ModuleKind { @@ -1074,7 +1129,17 @@ enum ModuleKind { /// * A normal module ‒ either `mod from_file;` or `mod from_block { }`. /// * A trait or an enum (it implicitly contains associated types, methods and variant /// constructors). - Def(Def, Name), + Def(DefKind, DefId, Name), +} + +impl ModuleKind { + /// Get name of the module. + pub fn name(&self) -> Option { + match self { + ModuleKind::Block(..) => None, + ModuleKind::Def(.., name) => Some(*name), + } + } } /// One node in the tree of modules. @@ -1089,7 +1154,7 @@ pub struct ModuleData<'a> { single_segment_macro_resolutions: RefCell, Option<&'a NameBinding<'a>>)>>, multi_segment_macro_resolutions: RefCell, Span, MacroKind, ParentScope<'a>, - Option)>>, + Option)>>, builtin_attrs: RefCell)>>, // Macro invocations that can expand into items in this module. @@ -1156,28 +1221,38 @@ impl<'a> ModuleData<'a> { } } - fn def(&self) -> Option { + fn res(&self) -> Option { match self.kind { - ModuleKind::Def(def, _) => Some(def), + ModuleKind::Def(kind, def_id, _) => Some(Res::Def(kind, def_id)), + _ => None, + } + } + + fn def_kind(&self) -> Option { + match self.kind { + ModuleKind::Def(kind, ..) => Some(kind), _ => None, } } fn def_id(&self) -> Option { - self.def().as_ref().map(Def::def_id) + match self.kind { + ModuleKind::Def(_, def_id, _) => Some(def_id), + _ => None, + } } // `self` resolves to the first module ancestor that `is_normal`. fn is_normal(&self) -> bool { match self.kind { - ModuleKind::Def(Def::Mod(_), _) => true, + ModuleKind::Def(DefKind::Mod, _, _) => true, _ => false, } } fn is_trait(&self) -> bool { match self.kind { - ModuleKind::Def(Def::Trait(_), _) => true, + ModuleKind::Def(DefKind::Trait, _, _) => true, _ => false, } } @@ -1200,7 +1275,7 @@ impl<'a> ModuleData<'a> { impl<'a> fmt::Debug for ModuleData<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.def()) + write!(f, "{:?}", self.res()) } } @@ -1226,7 +1301,7 @@ impl<'a> ToNameBinding<'a> for &'a NameBinding<'a> { #[derive(Clone, Debug)] enum NameBindingKind<'a> { - Def(Def, /* is_macro_export */ bool), + Res(Res, /* is_macro_export */ bool), Module(Module<'a>), Import { binding: &'a NameBinding<'a>, @@ -1260,7 +1335,6 @@ struct UseError<'a> { #[derive(Clone, Copy, PartialEq, Debug)] enum AmbiguityKind { Import, - AbsolutePath, BuiltinAttr, DeriveHelper, LegacyHelperVsPrelude, @@ -1276,8 +1350,6 @@ impl AmbiguityKind { match self { AmbiguityKind::Import => "name vs any other name during import resolution", - AmbiguityKind::AbsolutePath => - "name in the crate root vs extern crate during absolute path resolution", AmbiguityKind::BuiltinAttr => "built-in attribute vs any other name", AmbiguityKind::DeriveHelper => @@ -1327,11 +1399,11 @@ impl<'a> NameBinding<'a> { } } - fn def(&self) -> Def { + fn res(&self) -> Res { match self.kind { - NameBindingKind::Def(def, _) => def, - NameBindingKind::Module(module) => module.def().unwrap(), - NameBindingKind::Import { binding, .. } => binding.def(), + NameBindingKind::Res(res, _) => res, + NameBindingKind::Module(module) => module.res().unwrap(), + NameBindingKind::Import { binding, .. } => binding.res(), } } @@ -1342,9 +1414,9 @@ impl<'a> NameBinding<'a> { } } - // We sometimes need to treat variants as `pub` for backwards compatibility + // We sometimes need to treat variants as `pub` for backwards compatibility. fn pseudo_vis(&self) -> ty::Visibility { - if self.is_variant() && self.def().def_id().is_local() { + if self.is_variant() && self.res().def_id().is_local() { ty::Visibility::Public } else { self.vis @@ -1353,8 +1425,8 @@ impl<'a> NameBinding<'a> { fn is_variant(&self) -> bool { match self.kind { - NameBindingKind::Def(Def::Variant(..), _) | - NameBindingKind::Def(Def::VariantCtor(..), _) => true, + NameBindingKind::Res(Res::Def(DefKind::Variant, _), _) | + NameBindingKind::Res(Res::Def(DefKind::Ctor(CtorOf::Variant, ..), _), _) => true, _ => false, } } @@ -1367,7 +1439,7 @@ impl<'a> NameBinding<'a> { }, .. } => true, NameBindingKind::Module( - &ModuleData { kind: ModuleKind::Def(Def::Mod(def_id), _), .. } + &ModuleData { kind: ModuleKind::Def(DefKind::Mod, def_id, _), .. } ) => def_id.index == CRATE_DEF_INDEX, _ => false, } @@ -1388,33 +1460,35 @@ impl<'a> NameBinding<'a> { } fn is_importable(&self) -> bool { - match self.def() { - Def::AssociatedConst(..) | Def::Method(..) | Def::AssociatedTy(..) => false, + match self.res() { + Res::Def(DefKind::AssocConst, _) + | Res::Def(DefKind::Method, _) + | Res::Def(DefKind::AssocTy, _) => false, _ => true, } } fn is_macro_def(&self) -> bool { match self.kind { - NameBindingKind::Def(Def::Macro(..), _) => true, + NameBindingKind::Res(Res::Def(DefKind::Macro(..), _), _) => true, _ => false, } } fn macro_kind(&self) -> Option { - match self.def() { - Def::Macro(_, kind) => Some(kind), - Def::NonMacroAttr(..) => Some(MacroKind::Attr), + match self.res() { + Res::Def(DefKind::Macro(kind), _) => Some(kind), + Res::NonMacroAttr(..) => Some(MacroKind::Attr), _ => None, } } fn descr(&self) -> &'static str { - if self.is_extern_crate() { "extern crate" } else { self.def().kind_name() } + if self.is_extern_crate() { "extern crate" } else { self.res().descr() } } fn article(&self) -> &'static str { - if self.is_extern_crate() { "an" } else { self.def().article() } + if self.is_extern_crate() { "an" } else { self.res().article() } } // Suppose that we resolved macro invocation with `invoc_parent_expansion` to binding `binding` @@ -1441,37 +1515,32 @@ impl<'a> NameBinding<'a> { /// /// All other types are defined somewhere and possibly imported, but the primitive ones need /// special handling, since they have no place of origin. -#[derive(Default)] struct PrimitiveTypeTable { primitive_types: FxHashMap, } impl PrimitiveTypeTable { fn new() -> PrimitiveTypeTable { - let mut table = PrimitiveTypeTable::default(); - - table.intern("bool", Bool); - table.intern("char", Char); - table.intern("f32", Float(FloatTy::F32)); - table.intern("f64", Float(FloatTy::F64)); - table.intern("isize", Int(IntTy::Isize)); - table.intern("i8", Int(IntTy::I8)); - table.intern("i16", Int(IntTy::I16)); - table.intern("i32", Int(IntTy::I32)); - table.intern("i64", Int(IntTy::I64)); - table.intern("i128", Int(IntTy::I128)); - table.intern("str", Str); - table.intern("usize", Uint(UintTy::Usize)); - table.intern("u8", Uint(UintTy::U8)); - table.intern("u16", Uint(UintTy::U16)); - table.intern("u32", Uint(UintTy::U32)); - table.intern("u64", Uint(UintTy::U64)); - table.intern("u128", Uint(UintTy::U128)); - table - } - - fn intern(&mut self, string: &str, primitive_type: PrimTy) { - self.primitive_types.insert(Symbol::intern(string), primitive_type); + let mut table = FxHashMap::default(); + + table.insert(sym::bool, Bool); + table.insert(sym::char, Char); + table.insert(sym::f32, Float(FloatTy::F32)); + table.insert(sym::f64, Float(FloatTy::F64)); + table.insert(sym::isize, Int(IntTy::Isize)); + table.insert(sym::i8, Int(IntTy::I8)); + table.insert(sym::i16, Int(IntTy::I16)); + table.insert(sym::i32, Int(IntTy::I32)); + table.insert(sym::i64, Int(IntTy::I64)); + table.insert(sym::i128, Int(IntTy::I128)); + table.insert(sym::str, Str); + table.insert(sym::usize, Uint(UintTy::Usize)); + table.insert(sym::u8, Uint(UintTy::U8)); + table.insert(sym::u16, Uint(UintTy::U16)); + table.insert(sym::u32, Uint(UintTy::U32)); + table.insert(sym::u64, Uint(UintTy::U64)); + table.insert(sym::u128, Uint(UintTy::U128)); + Self { primitive_types: table } } } @@ -1516,7 +1585,7 @@ pub struct Resolver<'a> { ribs: PerNS>>, /// The current set of local scopes, for labels. - label_ribs: Vec>, + label_ribs: Vec>, /// The trait that the current context can refer to. current_trait_ref: Option<(Module<'a>, TraitRef)>, @@ -1537,11 +1606,14 @@ pub struct Resolver<'a> { /// The idents for the primitive types. primitive_type_table: PrimitiveTypeTable, - def_map: DefMap, - import_map: ImportMap, - pub freevars: FreevarMap, - freevars_seen: NodeMap>, - pub export_map: ExportMap, + /// Resolutions for nodes that have a single resolution. + partial_res_map: NodeMap, + /// Resolutions for import nodes, which have multiple resolutions in different namespaces. + import_res_map: NodeMap>>, + /// Resolutions for labels (node IDs of their corresponding blocks or loops). + label_res_map: NodeMap, + + pub export_map: ExportMap, pub trait_map: TraitMap, /// A map from nodes to anonymous modules. @@ -1590,8 +1662,9 @@ pub struct Resolver<'a> { macro_names: FxHashSet, builtin_macros: FxHashMap>, macro_use_prelude: FxHashMap>, - pub all_macros: FxHashMap, + pub all_macros: FxHashMap, macro_map: FxHashMap>, + non_macro_attrs: [Lrc; 2], macro_defs: FxHashMap, local_macro_def_scopes: FxHashMap>, @@ -1609,7 +1682,7 @@ pub struct Resolver<'a> { /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. - struct_constructors: DefIdMap<(Def, ty::Visibility)>, + struct_constructors: DefIdMap<(Res, ty::Visibility)>, /// Only used for better errors on `fn(): fn()`. current_type_ascription: Vec, @@ -1659,7 +1732,7 @@ impl<'a> ResolverArenas<'a> { } } -impl<'a, 'b: 'a> ty::DefIdTree for &'a Resolver<'b> { +impl<'a, 'b> ty::DefIdTree for &'a Resolver<'b> { fn parent(self, id: DefId) -> Option { match id.krate { LOCAL_CRATE => self.definitions.def_key(id.index).parent, @@ -1671,44 +1744,53 @@ impl<'a, 'b: 'a> ty::DefIdTree for &'a Resolver<'b> { /// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that /// the resolver is no longer needed as all the relevant information is inline. impl<'a> hir::lowering::Resolver for Resolver<'a> { - fn resolve_hir_path( + fn resolve_ast_path( &mut self, path: &ast::Path, is_value: bool, - ) -> hir::Path { - self.resolve_hir_path_cb(path, is_value, + ) -> Res { + self.resolve_ast_path_cb(path, is_value, |resolver, span, error| resolve_error(resolver, span, error)) } fn resolve_str_path( &mut self, span: Span, - crate_root: Option<&str>, - components: &[&str], + crate_root: Option, + components: &[Symbol], is_value: bool - ) -> hir::Path { - let segments = iter::once(keywords::PathRoot.ident()) + ) -> (ast::Path, Res) { + let root = if crate_root.is_some() { + kw::PathRoot + } else { + kw::Crate + }; + let segments = iter::once(Ident::with_empty_ctxt(root)) .chain( crate_root.into_iter() .chain(components.iter().cloned()) - .map(Ident::from_str) + .map(Ident::with_empty_ctxt) ).map(|i| self.new_ast_path_segment(i)).collect::>(); - let path = ast::Path { span, segments, }; - self.resolve_hir_path(&path, is_value) + let res = self.resolve_ast_path(&path, is_value); + (path, res) } - fn get_resolution(&mut self, id: NodeId) -> Option { - self.def_map.get(&id).cloned() + fn get_partial_res(&mut self, id: NodeId) -> Option { + self.partial_res_map.get(&id).cloned() } - fn get_import(&mut self, id: NodeId) -> PerNS> { - self.import_map.get(&id).cloned().unwrap_or_default() + fn get_import_res(&mut self, id: NodeId) -> PerNS> { + self.import_res_map.get(&id).cloned().unwrap_or_default() + } + + fn get_label_res(&mut self, id: NodeId) -> Option { + self.label_res_map.get(&id).cloned() } fn definitions(&mut self) -> &mut Definitions { @@ -1722,14 +1804,13 @@ impl<'a> Resolver<'a> { /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, /// just that an error occurred. pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool) - -> Result { - use std::iter; + -> Result<(ast::Path, Res), ()> { let mut errored = false; let path = if path_str.starts_with("::") { ast::Path { span, - segments: iter::once(keywords::PathRoot.ident()) + segments: iter::once(Ident::with_empty_ctxt(kw::PathRoot)) .chain({ path_str.split("::").skip(1).map(Ident::from_str) }) @@ -1746,55 +1827,49 @@ impl<'a> Resolver<'a> { .collect(), } }; - let path = self.resolve_hir_path_cb(&path, is_value, |_, _, _| errored = true); - if errored || path.def == Def::Err { + let res = self.resolve_ast_path_cb(&path, is_value, |_, _, _| errored = true); + if errored || res == def::Res::Err { Err(()) } else { - Ok(path) + Ok((path, res)) } } - /// Like `resolve_hir_path`, but takes a callback in case there was an error. - fn resolve_hir_path_cb( + /// Like `resolve_ast_path`, but takes a callback in case there was an error. + // FIXME(eddyb) use `Result` or something instead of callbacks. + fn resolve_ast_path_cb( &mut self, path: &ast::Path, is_value: bool, error_callback: F, - ) -> hir::Path + ) -> Res where F: for<'c, 'b> FnOnce(&'c mut Resolver<'_>, Span, ResolutionError<'b>) { let namespace = if is_value { ValueNS } else { TypeNS }; let span = path.span; - let segments = &path.segments; let path = Segment::from_path(&path); // FIXME(Manishearth): intra-doc links won't get warned of epoch changes. - let def = match self.resolve_path_without_parent_scope(&path, Some(namespace), true, + match self.resolve_path_without_parent_scope(&path, Some(namespace), true, span, CrateLint::No) { PathResult::Module(ModuleOrUniformRoot::Module(module)) => - module.def().unwrap(), + module.res().unwrap(), PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => - path_res.base_def(), + path_res.base_res(), PathResult::NonModule(..) => { - let msg = "type-relative paths are not supported in this context"; - error_callback(self, span, ResolutionError::FailedToResolve(msg)); - Def::Err + error_callback(self, span, ResolutionError::FailedToResolve { + label: String::from("type-relative paths are not supported in this context"), + suggestion: None, + }); + Res::Err } PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), - PathResult::Failed(span, msg, _) => { - error_callback(self, span, ResolutionError::FailedToResolve(&msg)); - Def::Err + PathResult::Failed { span, label, suggestion, .. } => { + error_callback(self, span, ResolutionError::FailedToResolve { + label, + suggestion, + }); + Res::Err } - }; - - let segments: Vec<_> = segments.iter().map(|seg| { - let mut hir_seg = hir::PathSegment::from_ident(seg.ident); - hir_seg.def = Some(self.def_map.get(&seg.id).map_or(Def::Err, |p| p.base_def())); - hir_seg - }).collect(); - hir::Path { - span, - def, - segments: segments.into(), } } @@ -1814,15 +1889,19 @@ impl<'a> Resolver<'a> { arenas: &'a ResolverArenas<'a>) -> Resolver<'a> { let root_def_id = DefId::local(CRATE_DEF_INDEX); - let root_module_kind = ModuleKind::Def(Def::Mod(root_def_id), keywords::Invalid.name()); + let root_module_kind = ModuleKind::Def( + DefKind::Mod, + root_def_id, + kw::Invalid, + ); let graph_root = arenas.alloc_module(ModuleData { - no_implicit_prelude: attr::contains_name(&krate.attrs, "no_implicit_prelude"), + no_implicit_prelude: attr::contains_name(&krate.attrs, sym::no_implicit_prelude), ..ModuleData::new(None, root_module_kind, root_def_id, Mark::root(), krate.span) }); let mut module_map = FxHashMap::default(); module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root); - let mut definitions = Definitions::new(); + let mut definitions = Definitions::default(); DefCollector::new(&mut definitions, Mark::root()) .collect_root(crate_name, session.local_crate_disambiguator()); @@ -1830,12 +1909,12 @@ impl<'a> Resolver<'a> { session.opts.externs.iter().map(|kv| (Ident::from_str(kv.0), Default::default())) .collect(); - if !attr::contains_name(&krate.attrs, "no_core") { - extern_prelude.insert(Ident::from_str("core"), Default::default()); - if !attr::contains_name(&krate.attrs, "no_std") { - extern_prelude.insert(Ident::from_str("std"), Default::default()); + if !attr::contains_name(&krate.attrs, sym::no_core) { + extern_prelude.insert(Ident::with_empty_ctxt(sym::core), Default::default()); + if !attr::contains_name(&krate.attrs, sym::no_std) { + extern_prelude.insert(Ident::with_empty_ctxt(sym::std), Default::default()); if session.rust_2018() { - extern_prelude.insert(Ident::from_str("meta"), Default::default()); + extern_prelude.insert(Ident::with_empty_ctxt(sym::meta), Default::default()); } } } @@ -1847,6 +1926,10 @@ impl<'a> Resolver<'a> { let mut macro_defs = FxHashMap::default(); macro_defs.insert(Mark::root(), root_def_id); + let non_macro_attr = |mark_used| Lrc::new(SyntaxExtension::default( + SyntaxExtensionKind::NonMacroAttr { mark_used }, session.edition() + )); + Resolver { session, @@ -1882,10 +1965,9 @@ impl<'a> Resolver<'a> { primitive_type_table: PrimitiveTypeTable::new(), - def_map: Default::default(), - import_map: Default::default(), - freevars: Default::default(), - freevars_seen: Default::default(), + partial_res_map: Default::default(), + import_res_map: Default::default(), + label_res_map: Default::default(), export_map: FxHashMap::default(), trait_map: Default::default(), module_map, @@ -1908,7 +1990,7 @@ impl<'a> Resolver<'a> { arenas, dummy_binding: arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Def(Def::Err, false), + kind: NameBindingKind::Res(Res::Err, false), ambiguity: None, expansion: Mark::root(), span: DUMMY_SP, @@ -1921,6 +2003,7 @@ impl<'a> Resolver<'a> { macro_use_prelude: FxHashMap::default(), all_macros: FxHashMap::default(), macro_map: FxHashMap::default(), + non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)], invocations, macro_defs, local_macro_def_scopes: FxHashMap::default(), @@ -1937,6 +2020,10 @@ impl<'a> Resolver<'a> { Default::default() } + fn non_macro_attr(&self, mark_used: bool) -> Lrc { + self.non_macro_attrs[mark_used as usize].clone() + } + /// Runs the function on each namespace. fn per_ns(&mut self, mut f: F) { f(self, TypeNS); @@ -2037,11 +2124,11 @@ impl<'a> Resolver<'a> { record_used_id: Option, path_span: Span) -> Option> { - assert!(ns == TypeNS || ns == ValueNS); - if ident.name == keywords::Invalid.name() { - return Some(LexicalScopeBinding::Def(Def::Err)); + assert!(ns == TypeNS || ns == ValueNS); + if ident.name == kw::Invalid { + return Some(LexicalScopeBinding::Res(Res::Err)); } - ident.span = if ident.name == keywords::SelfUpper.name() { + ident.span = if ident.name == kw::SelfUpper { // FIXME(jseyfried) improve `Self` hygiene ident.span.with_ctxt(SyntaxContext::empty()) } else if ns == TypeNS { @@ -2055,10 +2142,10 @@ impl<'a> Resolver<'a> { let mut module = self.graph_root; for i in (0 .. self.ribs[ns].len()).rev() { debug!("walk rib\n{:?}", self.ribs[ns][i].bindings); - if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() { + if let Some(res) = self.ribs[ns][i].bindings.get(&ident).cloned() { // The ident resolves to a type parameter or local variable. - return Some(LexicalScopeBinding::Def( - self.adjust_local_def(ns, i, def, record_used, path_span) + return Some(LexicalScopeBinding::Res( + self.validate_res_from_ribs(ns, i, res, record_used, path_span), )); } @@ -2138,7 +2225,7 @@ impl<'a> Resolver<'a> { } } if ns == TypeNS && is_known_tool(ident.name) { - let binding = (Def::ToolMod, ty::Visibility::Public, + let binding = (Res::ToolMod, ty::Visibility::Public, DUMMY_SP, Mark::root()).to_name_binding(self.arenas); return Some(LexicalScopeBinding::Item(binding)); } @@ -2160,7 +2247,7 @@ impl<'a> Resolver<'a> { fn hygienic_lexical_parent(&mut self, module: Module<'a>, span: &mut Span) -> Option> { - if !module.expansion.is_descendant_of(span.ctxt().outer()) { + if !module.expansion.outer_is_descendant_of(span.ctxt()) { return Some(self.macro_def_scope(span.remove_mark())); } @@ -2196,7 +2283,7 @@ impl<'a> Resolver<'a> { module.expansion.is_descendant_of(parent.expansion) { // The macro is a proc macro derive if module.expansion.looks_like_proc_macro_derive() { - if parent.expansion.is_descendant_of(span.ctxt().outer()) { + if parent.expansion.outer_is_descendant_of(span.ctxt()) { *poisoned = Some(node_id); return module.parent; } @@ -2233,14 +2320,12 @@ impl<'a> Resolver<'a> { let orig_current_module = self.current_module; match module { ModuleOrUniformRoot::Module(module) => { - ident.span = ident.span.modern(); - if let Some(def) = ident.span.adjust(module.expansion) { + if let Some(def) = ident.span.modernize_and_adjust(module.expansion) { self.current_module = self.macro_def_scope(def); } } ModuleOrUniformRoot::ExternPrelude => { - ident.span = ident.span.modern(); - ident.span.adjust(Mark::root()); + ident.span.modernize_and_adjust(Mark::root()); } ModuleOrUniformRoot::CrateRootAndExternPrelude | ModuleOrUniformRoot::CurrentScope => { @@ -2256,7 +2341,7 @@ impl<'a> Resolver<'a> { fn resolve_crate_root(&mut self, ident: Ident) -> Module<'a> { let mut ctxt = ident.span.ctxt(); - let mark = if ident.name == keywords::DollarCrate.name() { + let mark = if ident.name == kw::DollarCrate { // When resolving `$crate` from a `macro_rules!` invoked in a `macro`, // we don't want to pretend that the `macro_rules!` definition is in the `macro` // as described in `SyntaxContext::apply_mark`, so we ignore prepended modern marks. @@ -2350,7 +2435,7 @@ impl<'a> Resolver<'a> { /// /// Stops after meeting a closure. fn search_label(&self, mut ident: Ident, pred: P) -> Option - where P: Fn(&Rib<'_>, Ident) -> Option + where P: Fn(&Rib<'_, NodeId>, Ident) -> Option { for rib in self.label_ribs.iter().rev() { match rib.kind { @@ -2380,7 +2465,7 @@ impl<'a> Resolver<'a> { self.with_current_self_item(item, |this| { this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| { let item_def_id = this.definitions.local_def_id(item.id); - this.with_self_rib(Def::SelfTy(None, Some(item_def_id)), |this| { + this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| { visit::walk_item(this, item); }); }); @@ -2406,13 +2491,13 @@ impl<'a> Resolver<'a> { for &ns in nss { match self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) { - Some(LexicalScopeBinding::Def(..)) => { + Some(LexicalScopeBinding::Res(..)) => { report_error(self, ns); } Some(LexicalScopeBinding::Item(binding)) => { let orig_blacklisted_binding = mem::replace(&mut self.blacklisted_binding, Some(binding)); - if let Some(LexicalScopeBinding::Def(..)) = + if let Some(LexicalScopeBinding::Res(..)) = self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) { report_error(self, ns); @@ -2435,10 +2520,12 @@ impl<'a> Resolver<'a> { match item.node { ItemKind::Ty(_, ref generics) | - ItemKind::Fn(_, _, ref generics, _) | - ItemKind::Existential(_, ref generics) => { - self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), - |this| visit::walk_item(this, item)); + ItemKind::Existential(_, ref generics) | + ItemKind::Fn(_, _, ref generics, _) => { + self.with_generic_param_rib( + HasGenericParams(generics, ItemRibKind), + |this| visit::walk_item(this, item) + ); } ItemKind::Enum(_, ref generics) | @@ -2458,13 +2545,13 @@ impl<'a> Resolver<'a> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| { let local_def_id = this.definitions.local_def_id(item.id); - this.with_self_rib(Def::SelfTy(Some(local_def_id), None), |this| { + this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds); for trait_item in trait_items { let generic_params = HasGenericParams(&trait_item.generics, - TraitOrImplItemRibKind); + AssocItemRibKind); this.with_generic_param_rib(generic_params, |this| { match trait_item.node { TraitItemKind::Const(ref ty, ref default) => { @@ -2499,7 +2586,7 @@ impl<'a> Resolver<'a> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| { let local_def_id = this.definitions.local_def_id(item.id); - this.with_self_rib(Def::SelfTy(Some(local_def_id), None), |this| { + this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds); }); @@ -2562,10 +2649,13 @@ impl<'a> Resolver<'a> { } seen_bindings.entry(ident).or_insert(param.ident.span); - // Plain insert (no renaming). - let def = Def::TyParam(self.definitions.local_def_id(param.id)); - function_type_rib.bindings.insert(ident, def); - self.record_def(param.id, PathResolution::new(def)); + // Plain insert (no renaming). + let res = Res::Def( + DefKind::TyParam, + self.definitions.local_def_id(param.id), + ); + function_type_rib.bindings.insert(ident, res); + self.record_partial_res(param.id, PartialRes::new(res)); } GenericParamKind::Const { .. } => { let ident = param.ident.modern(); @@ -2581,9 +2671,12 @@ impl<'a> Resolver<'a> { } seen_bindings.entry(ident).or_insert(param.ident.span); - let def = Def::ConstParam(self.definitions.local_def_id(param.id)); - function_value_rib.bindings.insert(ident, def); - self.record_def(param.id, PathResolution::new(def)); + let res = Res::Def( + DefKind::ConstParam, + self.definitions.local_def_id(param.id), + ); + function_value_rib.bindings.insert(ident, res); + self.record_partial_res(param.id, PartialRes::new(res)); } } } @@ -2660,16 +2753,16 @@ impl<'a> Resolver<'a> { let mut new_id = None; if let Some(trait_ref) = opt_trait_ref { let path: Vec<_> = Segment::from_path(&trait_ref.path); - let def = self.smart_resolve_path_fragment( + let res = self.smart_resolve_path_fragment( trait_ref.ref_id, None, &path, trait_ref.path.span, PathSource::Trait(AliasPossibility::No), CrateLint::SimplePath(trait_ref.ref_id), - ).base_def(); - if def != Def::Err { - new_id = Some(def.def_id()); + ).base_res(); + if res != Res::Err { + new_id = Some(res.def_id()); let span = trait_ref.path.span; if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path_without_parent_scope( @@ -2690,13 +2783,13 @@ impl<'a> Resolver<'a> { result } - fn with_self_rib(&mut self, self_def: Def, f: F) + fn with_self_rib(&mut self, self_res: Res, f: F) where F: FnOnce(&mut Resolver<'_>) { let mut self_type_rib = Rib::new(NormalRibKind); - // plain insert (no renaming, types are not currently hygienic....) - self_type_rib.bindings.insert(keywords::SelfUpper.ident(), self_def); + // Plain insert (no renaming, since types are not currently hygienic) + self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res); self.ribs[TypeNS].push(self_type_rib); f(self); self.ribs[TypeNS].pop(); @@ -2705,9 +2798,9 @@ impl<'a> Resolver<'a> { fn with_self_struct_ctor_rib(&mut self, impl_id: DefId, f: F) where F: FnOnce(&mut Resolver<'_>) { - let self_def = Def::SelfCtor(impl_id); + let self_res = Res::SelfCtor(impl_id); let mut self_type_rib = Rib::new(NormalRibKind); - self_type_rib.bindings.insert(keywords::SelfUpper.ident(), self_def); + self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res); self.ribs[ValueNS].push(self_type_rib); f(self); self.ribs[ValueNS].pop(); @@ -2723,11 +2816,11 @@ impl<'a> Resolver<'a> { // If applicable, create a rib for the type parameters. self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| { // Dummy self type for better errors if `Self` is used in the trait path. - this.with_self_rib(Def::SelfTy(None, None), |this| { + this.with_self_rib(Res::SelfTy(None, None), |this| { // Resolve the trait reference, if necessary. this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { let item_def_id = this.definitions.local_def_id(item_id); - this.with_self_rib(Def::SelfTy(trait_id, Some(item_def_id)), |this| { + this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| { if let Some(trait_ref) = opt_trait_reference.as_ref() { // Resolve type arguments in the trait path. visit::walk_trait_ref(this, trait_ref); @@ -2745,7 +2838,7 @@ impl<'a> Resolver<'a> { // We also need a new scope for the impl item type parameters. let generic_params = HasGenericParams(&impl_item.generics, - TraitOrImplItemRibKind); + AssocItemRibKind); this.with_generic_param_rib(generic_params, |this| { use self::ResolutionError::*; match impl_item.node { @@ -2851,8 +2944,9 @@ impl<'a> Resolver<'a> { pat.walk(&mut |pat| { if let PatKind::Ident(binding_mode, ident, ref sub_pat) = pat.node { - if sub_pat.is_some() || match self.def_map.get(&pat.id).map(|res| res.base_def()) { - Some(Def::Local(..)) => true, + if sub_pat.is_some() || match self.partial_res_map.get(&pat.id) + .map(|res| res.base_res()) { + Some(Res::Local(..)) => true, _ => false, } { let binding_info = BindingInfo { span: ident.span, binding_mode: binding_mode }; @@ -2865,7 +2959,7 @@ impl<'a> Resolver<'a> { binding_map } - // check that all of the arms in an or-pattern have exactly the + // Checks that all of the arms in an or-pattern have exactly the // same set of bindings, with the same binding modes for each. fn check_consistent_bindings(&mut self, pats: &[P]) { if pats.is_empty() { @@ -2885,7 +2979,7 @@ impl<'a> Resolver<'a> { let map_j = self.binding_mode_map(&q); for (&key, &binding_i) in &map_i { if map_j.is_empty() { // Account for missing bindings when - let binding_error = missing_vars // map_j has none. + let binding_error = missing_vars // `map_j` has none. .entry(key.name) .or_insert(BindingError { name: key.name, @@ -2937,15 +3031,9 @@ impl<'a> Resolver<'a> { fn resolve_arm(&mut self, arm: &Arm) { self.ribs[ValueNS].push(Rib::new(NormalRibKind)); - let mut bindings_list = FxHashMap::default(); - for pattern in &arm.pats { - self.resolve_pattern(&pattern, PatternSource::Match, &mut bindings_list); - } - - // This has to happen *after* we determine which pat_idents are variants. - self.check_consistent_bindings(&arm.pats); + self.resolve_pats(&arm.pats, PatternSource::Match); - if let Some(ast::Guard::If(ref expr)) = arm.guard { + if let Some(ref expr) = arm.guard { self.visit_expr(expr) } self.visit_expr(&arm.body); @@ -2953,6 +3041,16 @@ impl<'a> Resolver<'a> { self.ribs[ValueNS].pop(); } + /// Arising from `source`, resolve a sequence of patterns (top level or-patterns). + fn resolve_pats(&mut self, pats: &[P], source: PatternSource) { + let mut bindings_list = FxHashMap::default(); + for pat in pats { + self.resolve_pattern(pat, source, &mut bindings_list); + } + // This has to happen *after* we determine which pat_idents are variants + self.check_consistent_bindings(pats); + } + fn resolve_block(&mut self, block: &Block) { debug!("(resolving block) entering block"); // Move down in the graph, if there's an anonymous module rooted here. @@ -2975,9 +3073,9 @@ impl<'a> Resolver<'a> { if let ast::StmtKind::Item(ref item) = stmt.node { if let ast::ItemKind::MacroDef(..) = item.node { num_macro_definition_ribs += 1; - let def = self.definitions.local_def_id(item.id); - self.ribs[ValueNS].push(Rib::new(MacroDefinition(def))); - self.label_ribs.push(Rib::new(MacroDefinition(def))); + let res = self.definitions.local_def_id(item.id); + self.ribs[ValueNS].push(Rib::new(MacroDefinition(res))); + self.label_ribs.push(Rib::new(MacroDefinition(res))); } } @@ -3003,14 +3101,14 @@ impl<'a> Resolver<'a> { outer_pat_id: NodeId, pat_src: PatternSource, bindings: &mut FxHashMap) - -> PathResolution { + -> Res { // Add the binding to the local ribs, if it // doesn't already exist in the bindings map. (We // must not add it if it's in the bindings map // because that breaks the assumptions later // passes make about or-patterns.) let ident = ident.modern_and_legacy(); - let mut def = Def::Local(pat_id); + let mut res = Res::Local(pat_id); match bindings.get(&ident).cloned() { Some(id) if id == outer_pat_id => { // `Variant(a, a)`, error @@ -3031,11 +3129,10 @@ impl<'a> Resolver<'a> { ); } Some(..) if pat_src == PatternSource::Match || - pat_src == PatternSource::IfLet || - pat_src == PatternSource::WhileLet => { + pat_src == PatternSource::Let => { // `Variant1(a) | Variant2(a)`, ok // Reuse definition from the first `a`. - def = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident]; + res = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident]; } Some(..) => { span_bug!(ident.span, "two bindings with the same name from \ @@ -3043,14 +3140,14 @@ impl<'a> Resolver<'a> { } None => { // A completely fresh binding, add to the lists if it's valid. - if ident.name != keywords::Invalid.name() { + if ident.name != kw::Invalid { bindings.insert(ident, outer_pat_id); - self.ribs[ValueNS].last_mut().unwrap().bindings.insert(ident, def); + self.ribs[ValueNS].last_mut().unwrap().bindings.insert(ident, res); } } } - PathResolution::new(def) + res } fn resolve_pattern(&mut self, @@ -3070,20 +3167,20 @@ impl<'a> Resolver<'a> { let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span) .and_then(LexicalScopeBinding::item); - let resolution = binding.map(NameBinding::def).and_then(|def| { + let res = binding.map(NameBinding::res).and_then(|res| { let is_syntactic_ambiguity = opt_pat.is_none() && bmode == BindingMode::ByValue(Mutability::Immutable); - match def { - Def::StructCtor(_, CtorKind::Const) | - Def::VariantCtor(_, CtorKind::Const) | - Def::Const(..) if is_syntactic_ambiguity => { + match res { + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | + Res::Def(DefKind::Const, _) if is_syntactic_ambiguity => { // Disambiguate in favor of a unit struct/variant // or constant pattern. self.record_use(ident, ValueNS, binding.unwrap(), false); - Some(PathResolution::new(def)) + Some(res) } - Def::StructCtor(..) | Def::VariantCtor(..) | - Def::Const(..) | Def::Static(..) => { + Res::Def(DefKind::Ctor(..), _) + | Res::Def(DefKind::Const, _) + | Res::Def(DefKind::Static, _) => { // This is unambiguously a fresh binding, either syntactically // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves // to something unusable as a pattern (e.g., constructor function), @@ -3097,21 +3194,21 @@ impl<'a> Resolver<'a> { ); None } - Def::Fn(..) | Def::Err => { + Res::Def(DefKind::Fn, _) | Res::Err => { // These entities are explicitly allowed // to be shadowed by fresh bindings. None } - def => { - span_bug!(ident.span, "unexpected definition for an \ - identifier in pattern: {:?}", def); + res => { + span_bug!(ident.span, "unexpected resolution for an \ + identifier in pattern: {:?}", res); } } }).unwrap_or_else(|| { self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings) }); - self.record_def(pat.id, resolution); + self.record_partial_res(pat.id, PartialRes::new(res)); } PatKind::TupleStruct(ref path, ..) => { @@ -3143,35 +3240,15 @@ impl<'a> Resolver<'a> { id: NodeId, qself: Option<&QSelf>, path: &Path, - source: PathSource<'_>) - -> PathResolution { - self.smart_resolve_path_with_crate_lint(id, qself, path, source, CrateLint::SimplePath(id)) - } - - /// A variant of `smart_resolve_path` where you also specify extra - /// information about where the path came from; this extra info is - /// sometimes needed for the lint that recommends rewriting - /// absolute paths to `crate`, so that it knows how to frame the - /// suggestion. If you are just resolving a path like `foo::bar` - /// that appears in an arbitrary location, then you just want - /// `CrateLint::SimplePath`, which is what `smart_resolve_path` - /// already provides. - fn smart_resolve_path_with_crate_lint( - &mut self, - id: NodeId, - qself: Option<&QSelf>, - path: &Path, - source: PathSource<'_>, - crate_lint: CrateLint - ) -> PathResolution { + source: PathSource<'_>) { self.smart_resolve_path_fragment( id, qself, &Segment::from_path(path), path.span, source, - crate_lint, - ) + CrateLint::SimplePath(id), + ); } fn smart_resolve_path_fragment(&mut self, @@ -3181,20 +3258,20 @@ impl<'a> Resolver<'a> { span: Span, source: PathSource<'_>, crate_lint: CrateLint) - -> PathResolution { + -> PartialRes { let ns = source.namespace(); - let is_expected = &|def| source.is_expected(def); + let is_expected = &|res| source.is_expected(res); - let report_errors = |this: &mut Self, def: Option| { - let (err, candidates) = this.smart_resolve_report_errors(path, span, source, def); + let report_errors = |this: &mut Self, res: Option| { + let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); let def_id = this.current_module.normal_ancestor_id; let node_id = this.definitions.as_local_node_id(def_id).unwrap(); - let better = def.is_some(); + let better = res.is_some(); this.use_injections.push(UseError { err, candidates, node_id, better }); - err_path_resolution() + PartialRes::new(Res::Err) }; - let resolution = match self.resolve_qpath_anywhere( + let partial_res = match self.resolve_qpath_anywhere( id, qself, path, @@ -3204,31 +3281,31 @@ impl<'a> Resolver<'a> { source.global_by_default(), crate_lint, ) { - Some(resolution) if resolution.unresolved_segments() == 0 => { - if is_expected(resolution.base_def()) || resolution.base_def() == Def::Err { - resolution + Some(partial_res) if partial_res.unresolved_segments() == 0 => { + if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err { + partial_res } else { // Add a temporary hack to smooth the transition to new struct ctor // visibility rules. See #38932 for more details. let mut res = None; - if let Def::Struct(def_id) = resolution.base_def() { - if let Some((ctor_def, ctor_vis)) + if let Res::Def(DefKind::Struct, def_id) = partial_res.base_res() { + if let Some((ctor_res, ctor_vis)) = self.struct_constructors.get(&def_id).cloned() { - if is_expected(ctor_def) && self.is_accessible(ctor_vis) { + if is_expected(ctor_res) && self.is_accessible(ctor_vis) { let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY; self.session.buffer_lint(lint, id, span, "private struct constructors are not usable through \ re-exports in outer modules", ); - res = Some(PathResolution::new(ctor_def)); + res = Some(PartialRes::new(ctor_res)); } } } - res.unwrap_or_else(|| report_errors(self, Some(resolution.base_def()))) + res.unwrap_or_else(|| report_errors(self, Some(partial_res.base_res()))) } } - Some(resolution) if source.defer_to_typeck() => { + Some(partial_res) if source.defer_to_typeck() => { // Not fully resolved associated item `T::A::B` or `::A::B` // or `::A::B`. If `B` should be resolved in value namespace then // it needs to be added to the trait map. @@ -3237,23 +3314,52 @@ impl<'a> Resolver<'a> { let traits = self.get_traits_containing_item(item_name, ns); self.trait_map.insert(id, traits); } - resolution + + let mut std_path = vec![Segment::from_ident(Ident::with_empty_ctxt(sym::std))]; + std_path.extend(path); + if self.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) { + let cl = CrateLint::No; + let ns = Some(ns); + if let PathResult::Module(_) | PathResult::NonModule(_) = + self.resolve_path_without_parent_scope(&std_path, ns, false, span, cl) + { + // check if we wrote `str::from_utf8` instead of `std::str::from_utf8` + let item_span = path.iter().last().map(|segment| segment.ident.span) + .unwrap_or(span); + debug!("accessed item from `std` submodule as a bare type {:?}", std_path); + let mut hm = self.session.confused_type_with_std_module.borrow_mut(); + hm.insert(item_span, span); + // In some places (E0223) we only have access to the full path + hm.insert(span, span); + } + } + partial_res } _ => report_errors(self, None) }; if let PathSource::TraitItem(..) = source {} else { // Avoid recording definition of `A::B` in `::B::C`. - self.record_def(id, resolution); + self.record_partial_res(id, partial_res); } - resolution + partial_res } - fn type_ascription_suggestion(&self, - err: &mut DiagnosticBuilder<'_>, - base_span: Span) { + /// Only used in a specific case of type ascription suggestions + #[doc(hidden)] + fn get_colon_suggestion_span(&self, start: Span) -> Span { + let cm = self.session.source_map(); + start.to(cm.next_point(start)) + } + + fn type_ascription_suggestion( + &self, + err: &mut DiagnosticBuilder<'_>, + base_span: Span, + ) { debug!("type_ascription_suggetion {:?}", base_span); let cm = self.session.source_map(); + let base_snippet = cm.span_to_snippet(base_span); debug!("self.current_type_ascription {:?}", self.current_type_ascription); if let Some(sp) = self.current_type_ascription.last() { let mut sp = *sp; @@ -3261,13 +3367,10 @@ impl<'a> Resolver<'a> { // Try to find the `:`; bail on first non-':' / non-whitespace. sp = cm.next_point(sp); if let Ok(snippet) = cm.span_to_snippet(sp.to(cm.next_point(sp))) { - debug!("snippet {:?}", snippet); let line_sp = cm.lookup_char_pos(sp.hi()).line; let line_base_sp = cm.lookup_char_pos(base_span.lo()).line; - debug!("{:?} {:?}", line_sp, line_base_sp); if snippet == ":" { - err.span_label(base_span, - "expecting a type here because of type ascription"); + let mut show_label = true; if line_sp != line_base_sp { err.span_suggestion_short( sp, @@ -3275,6 +3378,49 @@ impl<'a> Resolver<'a> { ";".to_string(), Applicability::MaybeIncorrect, ); + } else { + let colon_sp = self.get_colon_suggestion_span(sp); + let after_colon_sp = self.get_colon_suggestion_span( + colon_sp.shrink_to_hi(), + ); + if !cm.span_to_snippet(after_colon_sp).map(|s| s == " ") + .unwrap_or(false) + { + err.span_suggestion( + colon_sp, + "maybe you meant to write a path separator here", + "::".to_string(), + Applicability::MaybeIncorrect, + ); + show_label = false; + } + if let Ok(base_snippet) = base_snippet { + let mut sp = after_colon_sp; + for _ in 0..100 { + // Try to find an assignment + sp = cm.next_point(sp); + let snippet = cm.span_to_snippet(sp.to(cm.next_point(sp))); + match snippet { + Ok(ref x) if x.as_str() == "=" => { + err.span_suggestion( + base_span, + "maybe you meant to write an assignment here", + format!("let {}", base_snippet), + Applicability::MaybeIncorrect, + ); + show_label = false; + break; + } + Ok(ref x) if x.as_str() == "\n" => break, + Err(_) => break, + Ok(_) => {} + } + } + } + } + if show_label { + err.span_label(base_span, + "expecting a type here because of type ascription"); } break; } else if !snippet.trim().is_empty() { @@ -3289,28 +3435,29 @@ impl<'a> Resolver<'a> { } fn self_type_is_available(&mut self, span: Span) -> bool { - let binding = self.resolve_ident_in_lexical_scope(keywords::SelfUpper.ident(), + let binding = self.resolve_ident_in_lexical_scope(Ident::with_empty_ctxt(kw::SelfUpper), TypeNS, None, span); - if let Some(LexicalScopeBinding::Def(def)) = binding { def != Def::Err } else { false } + if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } } fn self_value_is_available(&mut self, self_span: Span, path_span: Span) -> bool { - let ident = Ident::new(keywords::SelfLower.name(), self_span); + let ident = Ident::new(kw::SelfLower, self_span); let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, path_span); - if let Some(LexicalScopeBinding::Def(def)) = binding { def != Def::Err } else { false } + if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } } // Resolve in alternative namespaces if resolution in the primary namespace fails. - fn resolve_qpath_anywhere(&mut self, - id: NodeId, - qself: Option<&QSelf>, - path: &[Segment], - primary_ns: Namespace, - span: Span, - defer_to_typeck: bool, - global_by_default: bool, - crate_lint: CrateLint) - -> Option { + fn resolve_qpath_anywhere( + &mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &[Segment], + primary_ns: Namespace, + span: Span, + defer_to_typeck: bool, + global_by_default: bool, + crate_lint: CrateLint, + ) -> Option { let mut fin_res = None; // FIXME: can't resolve paths in macro namespace yet, macros are // processed by the little special hack below. @@ -3319,9 +3466,10 @@ impl<'a> Resolver<'a> { match self.resolve_qpath(id, qself, path, ns, span, global_by_default, crate_lint) { // If defer_to_typeck, then resolution > no resolution, // otherwise full resolution > partial resolution > no resolution. - Some(res) if res.unresolved_segments() == 0 || defer_to_typeck => - return Some(res), - res => if fin_res.is_none() { fin_res = res }, + Some(partial_res) if partial_res.unresolved_segments() == 0 || + defer_to_typeck => + return Some(partial_res), + partial_res => if fin_res.is_none() { fin_res = partial_res }, }; } } @@ -3332,23 +3480,25 @@ impl<'a> Resolver<'a> { self.macro_use_prelude.get(&path[0].ident.name).cloned() .and_then(NameBinding::macro_kind) == Some(MacroKind::Bang)) { // Return some dummy definition, it's enough for error reporting. - return Some( - PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang)) - ); + return Some(PartialRes::new(Res::Def( + DefKind::Macro(MacroKind::Bang), + DefId::local(CRATE_DEF_INDEX), + ))); } fin_res } /// Handles paths that may refer to associated items. - fn resolve_qpath(&mut self, - id: NodeId, - qself: Option<&QSelf>, - path: &[Segment], - ns: Namespace, - span: Span, - global_by_default: bool, - crate_lint: CrateLint) - -> Option { + fn resolve_qpath( + &mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &[Segment], + ns: Namespace, + span: Span, + global_by_default: bool, + crate_lint: CrateLint, + ) -> Option { debug!( "resolve_qpath(id={:?}, qself={:?}, path={:?}, \ ns={:?}, span={:?}, global_by_default={:?})", @@ -3365,8 +3515,8 @@ impl<'a> Resolver<'a> { // This is a case like `::B`, where there is no // trait to resolve. In that case, we leave the `B` // segment to be resolved by type-check. - return Some(PathResolution::with_unresolved_segments( - Def::Mod(DefId::local(CRATE_DEF_INDEX)), path.len() + return Some(PartialRes::with_unresolved_segments( + Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)), path.len() )); } @@ -3385,7 +3535,7 @@ impl<'a> Resolver<'a> { // name from a fully qualified path, and this also // contains the full span (the `CrateLint::QPathTrait`). let ns = if qself.position + 1 == path.len() { ns } else { TypeNS }; - let res = self.smart_resolve_path_fragment( + let partial_res = self.smart_resolve_path_fragment( id, None, &path[..=qself.position], @@ -3400,8 +3550,9 @@ impl<'a> Resolver<'a> { // The remaining segments (the `C` in our example) will // have to be resolved by type-check, since that requires doing // trait resolution. - return Some(PathResolution::with_unresolved_segments( - res.base_def(), res.unresolved_segments() + path.len() - qself.position - 1 + return Some(PartialRes::with_unresolved_segments( + partial_res.base_res(), + partial_res.unresolved_segments() + path.len() - qself.position - 1, )); } @@ -3414,7 +3565,7 @@ impl<'a> Resolver<'a> { ) { PathResult::NonModule(path_res) => path_res, PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => { - PathResolution::new(module.def().unwrap()) + PartialRes::new(module.res().unwrap()) } // In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we // don't report an error right away, but try to fallback to a primitive type. @@ -3429,26 +3580,26 @@ impl<'a> Resolver<'a> { // Such behavior is required for backward compatibility. // The same fallback is used when `a` resolves to nothing. PathResult::Module(ModuleOrUniformRoot::Module(_)) | - PathResult::Failed(..) + PathResult::Failed { .. } if (ns == TypeNS || path.len() > 1) && self.primitive_type_table.primitive_types .contains_key(&path[0].ident.name) => { let prim = self.primitive_type_table.primitive_types[&path[0].ident.name]; - PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1) + PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1) } PathResult::Module(ModuleOrUniformRoot::Module(module)) => - PathResolution::new(module.def().unwrap()), - PathResult::Failed(span, msg, false) => { - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); - err_path_resolution() + PartialRes::new(module.res().unwrap()), + PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => { + resolve_error(self, span, ResolutionError::FailedToResolve { label, suggestion }); + PartialRes::new(Res::Err) } - PathResult::Module(..) | PathResult::Failed(..) => return None, + PathResult::Module(..) | PathResult::Failed { .. } => return None, PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"), }; - if path.len() > 1 && !global_by_default && result.base_def() != Def::Err && - path[0].ident.name != keywords::PathRoot.name() && - path[0].ident.name != keywords::DollarCrate.name() { + if path.len() > 1 && !global_by_default && result.base_res() != Res::Err && + path[0].ident.name != kw::PathRoot && + path[0].ident.name != kw::DollarCrate { let unqualified_result = { match self.resolve_path_without_parent_scope( &[*path.last().unwrap()], @@ -3457,13 +3608,13 @@ impl<'a> Resolver<'a> { span, CrateLint::No, ) { - PathResult::NonModule(path_res) => path_res.base_def(), + PathResult::NonModule(path_res) => path_res.base_res(), PathResult::Module(ModuleOrUniformRoot::Module(module)) => - module.def().unwrap(), + module.res().unwrap(), _ => return Some(result), } }; - if result.base_def() == unqualified_result { + if result.base_res() == unqualified_result { let lint = lint::builtin::UNUSED_QUALIFICATIONS; self.session.buffer_lint(lint, id, span, "unnecessary qualification") } @@ -3513,12 +3664,12 @@ impl<'a> Resolver<'a> { for (i, &Segment { ident, id }) in path.iter().enumerate() { debug!("resolve_path ident {} {:?} {:?}", i, ident, id); - let record_segment_def = |this: &mut Self, def| { + let record_segment_res = |this: &mut Self, res| { if record_used { if let Some(id) = id { - if !this.def_map.contains_key(&id) { + if !this.partial_res_map.contains_key(&id) { assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); - this.record_def(id, PathResolution::new(def)); + this.record_partial_res(id, PartialRes::new(res)); } } } @@ -3529,11 +3680,11 @@ impl<'a> Resolver<'a> { let name = ident.name; allow_super &= ns == TypeNS && - (name == keywords::SelfLower.name() || - name == keywords::Super.name()); + (name == kw::SelfLower || + name == kw::Super); if ns == TypeNS { - if allow_super && name == keywords::Super.name() { + if allow_super && name == kw::Super { let mut ctxt = ident.span.ctxt().modern(); let self_module = match i { 0 => Some(self.resolve_self(&mut ctxt, self.current_module)), @@ -3550,28 +3701,33 @@ impl<'a> Resolver<'a> { } } let msg = "there are too many initial `super`s.".to_string(); - return PathResult::Failed(ident.span, msg, false); + return PathResult::Failed { + span: ident.span, + label: msg, + suggestion: None, + is_error_from_last_segment: false, + }; } if i == 0 { - if name == keywords::SelfLower.name() { + if name == kw::SelfLower { let mut ctxt = ident.span.ctxt().modern(); module = Some(ModuleOrUniformRoot::Module( self.resolve_self(&mut ctxt, self.current_module))); continue; } - if name == keywords::PathRoot.name() && ident.span.rust_2018() { + if name == kw::PathRoot && ident.span.rust_2018() { module = Some(ModuleOrUniformRoot::ExternPrelude); continue; } - if name == keywords::PathRoot.name() && + if name == kw::PathRoot && ident.span.rust_2015() && self.session.rust_2018() { // `::a::b` from 2015 macro on 2018 global edition module = Some(ModuleOrUniformRoot::CrateRootAndExternPrelude); continue; } - if name == keywords::PathRoot.name() || - name == keywords::Crate.name() || - name == keywords::DollarCrate.name() { + if name == kw::PathRoot || + name == kw::Crate || + name == kw::DollarCrate { // `::a::b`, `crate::a::b` or `$crate::a::b` module = Some(ModuleOrUniformRoot::Module( self.resolve_crate_root(ident))); @@ -3582,17 +3738,22 @@ impl<'a> Resolver<'a> { // Report special messages for path segment keywords in wrong positions. if ident.is_path_segment_keyword() && i != 0 { - let name_str = if name == keywords::PathRoot.name() { + let name_str = if name == kw::PathRoot { "crate root".to_string() } else { format!("`{}`", name) }; - let msg = if i == 1 && path[0].ident.name == keywords::PathRoot.name() { + let label = if i == 1 && path[0].ident.name == kw::PathRoot { format!("global paths cannot start with {}", name_str) } else { format!("{} in paths can only be used in start position", name_str) }; - return PathResult::Failed(ident.span, msg, false); + return PathResult::Failed { + span: ident.span, + label, + suggestion: None, + is_error_from_last_segment: false, + }; } let binding = if let Some(module) = module { @@ -3609,11 +3770,11 @@ impl<'a> Resolver<'a> { // we found a locally-imported or available item/module Some(LexicalScopeBinding::Item(binding)) => Ok(binding), // we found a local variable or type param - Some(LexicalScopeBinding::Def(def)) + Some(LexicalScopeBinding::Res(res)) if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) => { - record_segment_def(self, def); - return PathResult::NonModule(PathResolution::with_unresolved_segments( - def, path.len() - 1 + record_segment_res(self, res); + return PathResult::NonModule(PartialRes::with_unresolved_segments( + res, path.len() - 1 )); } _ => Err(Determinacy::determined(record_used)), @@ -3625,12 +3786,12 @@ impl<'a> Resolver<'a> { if i == 1 { second_binding = Some(binding); } - let def = binding.def(); - let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def); + let res = binding.res(); + let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); if let Some(next_module) = binding.module() { module = Some(ModuleOrUniformRoot::Module(next_module)); - record_segment_def(self, def); - } else if def == Def::ToolMod && i + 1 != path.len() { + record_segment_res(self, res); + } else if res == Res::ToolMod && i + 1 != path.len() { if binding.is_import() { self.session.struct_span_err( ident.span, "cannot use a tool module through an import" @@ -3638,10 +3799,10 @@ impl<'a> Resolver<'a> { binding.span, "the tool module imported here" ).emit(); } - let def = Def::NonMacroAttr(NonMacroAttrKind::Tool); - return PathResult::NonModule(PathResolution::new(def)); - } else if def == Def::Err { - return PathResult::NonModule(err_path_resolution()); + let res = Res::NonMacroAttr(NonMacroAttrKind::Tool); + return PathResult::NonModule(PartialRes::new(res)); + } else if res == Res::Err { + return PathResult::NonModule(PartialRes::new(Res::Err)); } else if opt_ns.is_some() && (is_last || maybe_assoc) { self.lint_if_path_starts_with_module( crate_lint, @@ -3649,49 +3810,73 @@ impl<'a> Resolver<'a> { path_span, second_binding, ); - return PathResult::NonModule(PathResolution::with_unresolved_segments( - def, path.len() - i - 1 + return PathResult::NonModule(PartialRes::with_unresolved_segments( + res, path.len() - i - 1 )); } else { - return PathResult::Failed(ident.span, - format!("not a module `{}`", ident), - is_last); + let label = format!( + "`{}` is {} {}, not a module", + ident, + res.article(), + res.descr(), + ); + + return PathResult::Failed { + span: ident.span, + label, + suggestion: None, + is_error_from_last_segment: is_last, + }; } } Err(Undetermined) => return PathResult::Indeterminate, Err(Determined) => { if let Some(ModuleOrUniformRoot::Module(module)) = module { if opt_ns.is_some() && !module.is_normal() { - return PathResult::NonModule(PathResolution::with_unresolved_segments( - module.def().unwrap(), path.len() - i + return PathResult::NonModule(PartialRes::with_unresolved_segments( + module.res().unwrap(), path.len() - i )); } } - let module_def = match module { - Some(ModuleOrUniformRoot::Module(module)) => module.def(), + let module_res = match module { + Some(ModuleOrUniformRoot::Module(module)) => module.res(), _ => None, }; - let msg = if module_def == self.graph_root.def() { - let is_mod = |def| match def { Def::Mod(..) => true, _ => false }; + let (label, suggestion) = if module_res == self.graph_root.res() { + let is_mod = |res| { + match res { Res::Def(DefKind::Mod, _) => true, _ => false } + }; let mut candidates = self.lookup_import_candidates(ident, TypeNS, is_mod); candidates.sort_by_cached_key(|c| { (c.path.segments.len(), c.path.to_string()) }); if let Some(candidate) = candidates.get(0) { - format!("did you mean `{}`?", candidate.path) + ( + String::from("unresolved import"), + Some(( + vec![(ident.span, candidate.path.to_string())], + String::from("a similar path exists"), + Applicability::MaybeIncorrect, + )), + ) } else if !ident.is_reserved() { - format!("maybe a missing `extern crate {};`?", ident) + (format!("maybe a missing `extern crate {};`?", ident), None) } else { // the parser will already have complained about the keyword being used - return PathResult::NonModule(err_path_resolution()); + return PathResult::NonModule(PartialRes::new(Res::Err)); } } else if i == 0 { - format!("use of undeclared type or module `{}`", ident) + (format!("use of undeclared type or module `{}`", ident), None) } else { - format!("could not find `{}` in `{}`", ident, path[i - 1].ident) + (format!("could not find `{}` in `{}`", ident, path[i - 1].ident), None) + }; + return PathResult::Failed { + span: ident.span, + label, + suggestion, + is_error_from_last_segment: is_last, }; - return PathResult::Failed(ident.span, msg, is_last); } } } @@ -3727,13 +3912,13 @@ impl<'a> Resolver<'a> { // We're only interested in `use` paths which should start with // `{{root}}` currently. - if first_name != keywords::PathRoot.name() { + if first_name != kw::PathRoot { return } match path.get(1) { // If this import looks like `crate::...` it's already good - Some(Segment { ident, .. }) if ident.name == keywords::Crate.name() => return, + Some(Segment { ident, .. }) if ident.name == kw::Crate => return, // Otherwise go below to see if it's an extern crate Some(_) => {} // If the path has length one (and it's `PathRoot` most likely) @@ -3765,14 +3950,16 @@ impl<'a> Resolver<'a> { diag); } - // Resolve a local definition, potentially adjusting for closures. - fn adjust_local_def(&mut self, - ns: Namespace, - rib_index: usize, - mut def: Def, - record_used: bool, - span: Span) -> Def { - debug!("adjust_local_def"); + // Validate a local resolution (from ribs). + fn validate_res_from_ribs( + &mut self, + ns: Namespace, + rib_index: usize, + res: Res, + record_used: bool, + span: Span, + ) -> Res { + debug!("validate_res_from_ribs({:?})", res); let ribs = &self.ribs[ns][rib_index + 1..]; // An invalid forward use of a type parameter from a previous default. @@ -3780,49 +3967,31 @@ impl<'a> Resolver<'a> { if record_used { resolve_error(self, span, ResolutionError::ForwardDeclaredTyParam); } - assert_eq!(def, Def::Err); - return Def::Err; + assert_eq!(res, Res::Err); + return Res::Err; } - match def { - Def::Upvar(..) => { - span_bug!(span, "unexpected {:?} in bindings", def) + // An invalid use of a type parameter as the type of a const parameter. + if let TyParamAsConstParamTy = self.ribs[ns][rib_index].kind { + if record_used { + resolve_error(self, span, ResolutionError::ConstParamDependentOnTypeParam); } - Def::Local(node_id) => { + assert_eq!(res, Res::Err); + return Res::Err; + } + + match res { + Res::Local(_) => { use ResolutionError::*; let mut res_err = None; for rib in ribs { match rib.kind { NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) | - ForwardTyParamBanRibKind => { + ForwardTyParamBanRibKind | TyParamAsConstParamTy => { // Nothing to do. Continue. } - ClosureRibKind(function_id) => { - let prev_def = def; - - let seen = self.freevars_seen - .entry(function_id) - .or_default(); - if let Some(&index) = seen.get(&node_id) { - def = Def::Upvar(node_id, index, function_id); - continue; - } - let vec = self.freevars - .entry(function_id) - .or_default(); - let depth = vec.len(); - def = Def::Upvar(node_id, depth, function_id); - - if record_used { - vec.push(Freevar { - def: prev_def, - span, - }); - seen.insert(node_id, depth); - } - } - ItemRibKind | TraitOrImplItemRibKind => { + ItemRibKind | FnItemRibKind | AssocItemRibKind => { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we // report an error. @@ -3839,59 +4008,62 @@ impl<'a> Resolver<'a> { if record_used { resolve_error(self, span, AttemptToUseNonConstantValueInConstant); } - return Def::Err; + return Res::Err; } } } if let Some(res_err) = res_err { resolve_error(self, span, res_err); - return Def::Err; + return Res::Err; } } - Def::TyParam(..) | Def::SelfTy(..) => { + Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => { for rib in ribs { match rib.kind { - NormalRibKind | TraitOrImplItemRibKind | ClosureRibKind(..) | + NormalRibKind | AssocItemRibKind | ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind | - ConstantItemRibKind => { + ConstantItemRibKind | TyParamAsConstParamTy => { // Nothing to do. Continue. } - ItemRibKind => { + ItemRibKind | FnItemRibKind => { // This was an attempt to use a type parameter outside its scope. if record_used { resolve_error( self, span, - ResolutionError::GenericParamsFromOuterFunction(def), + ResolutionError::GenericParamsFromOuterFunction(res), ); } - return Def::Err; + return Res::Err; } } } } - Def::ConstParam(..) => { - // A const param is always declared in a signature, which is always followed by - // some kind of function rib kind (specifically, ItemRibKind in the case of a - // normal function), so we can skip the first rib as it will be guaranteed to - // (spuriously) conflict with the const param. - for rib in &ribs[1..] { - if let ItemRibKind = rib.kind { + Res::Def(DefKind::ConstParam, _) => { + let mut ribs = ribs.iter().peekable(); + if let Some(Rib { kind: FnItemRibKind, .. }) = ribs.peek() { + // When declaring const parameters inside function signatures, the first rib + // is always a `FnItemRibKind`. In this case, we can skip it, to avoid it + // (spuriously) conflicting with the const param. + ribs.next(); + } + for rib in ribs { + if let ItemRibKind | FnItemRibKind = rib.kind { // This was an attempt to use a const parameter outside its scope. if record_used { resolve_error( self, span, - ResolutionError::GenericParamsFromOuterFunction(def), + ResolutionError::GenericParamsFromOuterFunction(res), ); } - return Def::Err; + return Res::Err; } } } _ => {} } - def + res } fn lookup_assoc_candidate(&mut self, @@ -3899,7 +4071,7 @@ impl<'a> Resolver<'a> { ns: Namespace, filter_fn: FilterFn) -> Option - where FilterFn: Fn(Def) -> bool + where FilterFn: Fn(Res) -> bool { fn extract_node_id(t: &Ty) -> Option { match t.node { @@ -3913,12 +4085,12 @@ impl<'a> Resolver<'a> { } // Fields are generally expected in the same contexts as locals. - if filter_fn(Def::Local(ast::DUMMY_NODE_ID)) { + if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) { if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) { // Look for a field with the same name in the current self_type. - if let Some(resolution) = self.def_map.get(&node_id) { - match resolution.base_def() { - Def::Struct(did) | Def::Union(did) + if let Some(resolution) = self.partial_res_map.get(&node_id) { + match resolution.base_res() { + Res::Def(DefKind::Struct, did) | Res::Def(DefKind::Union, did) if resolution.unresolved_segments() == 0 => { if let Some(field_names) = self.field_names.get(&did) { if field_names.iter().any(|&field_name| ident.name == field_name) { @@ -3942,9 +4114,9 @@ impl<'a> Resolver<'a> { false, module.span, ) { - let def = binding.def(); - if filter_fn(def) { - return Some(if self.has_self.contains(&def.def_id()) { + let res = binding.res(); + if filter_fn(res) { + return Some(if self.has_self.contains(&res.def_id()) { AssocSuggestion::MethodWithSelf } else { AssocSuggestion::AssocItem @@ -3964,16 +4136,16 @@ impl<'a> Resolver<'a> { span: Span, ) -> Option where - FilterFn: Fn(Def) -> bool, + FilterFn: Fn(Res) -> bool, { let add_module_candidates = |module: Module<'_>, names: &mut Vec| { for (&(ident, _), resolution) in module.resolutions.borrow().iter() { if let Some(binding) = resolution.borrow().binding { - if filter_fn(binding.def()) { + if filter_fn(binding.res()) { names.push(TypoSuggestion { candidate: ident.name, - article: binding.def().article(), - kind: binding.def().kind_name(), + article: binding.res().article(), + kind: binding.res().descr(), }); } } @@ -3986,12 +4158,12 @@ impl<'a> Resolver<'a> { // Walk backwards up the ribs in scope and collect candidates. for rib in self.ribs[ns].iter().rev() { // Locals and type parameters - for (ident, def) in &rib.bindings { - if filter_fn(*def) { + for (ident, &res) in &rib.bindings { + if filter_fn(res) { names.push(TypoSuggestion { candidate: ident.name, - article: def.article(), - kind: def.kind_name(), + article: res.article(), + kind: res.descr(), }); } } @@ -4005,13 +4177,30 @@ impl<'a> Resolver<'a> { } else { // Items from the prelude if !module.no_implicit_prelude { - names.extend(self.extern_prelude.iter().map(|(ident, _)| { - TypoSuggestion { - candidate: ident.name, - article: "a", - kind: "crate", - } + names.extend(self.extern_prelude.clone().iter().flat_map(|(ident, _)| { + self.crate_loader + .maybe_process_path_extern(ident.name, ident.span) + .and_then(|crate_id| { + let crate_mod = Res::Def( + DefKind::Mod, + DefId { + krate: crate_id, + index: CRATE_DEF_INDEX, + }, + ); + + if filter_fn(crate_mod) { + Some(TypoSuggestion { + candidate: ident.name, + article: "a", + kind: "crate", + }) + } else { + None + } + }) })); + if let Some(prelude) = self.prelude { add_module_candidates(prelude, &mut names); } @@ -4021,7 +4210,7 @@ impl<'a> Resolver<'a> { } } // Add primitive types to the mix - if filter_fn(Def::PrimTy(Bool)) { + if filter_fn(Res::PrimTy(Bool)) { names.extend( self.primitive_type_table.primitive_types.iter().map(|(name, _)| { TypoSuggestion { @@ -4065,10 +4254,9 @@ impl<'a> Resolver<'a> { { if let Some(label) = label { self.unused_labels.insert(id, label.ident.span); - let def = Def::Label(id); self.with_label_rib(|this| { let ident = label.ident.modern_and_legacy(); - this.label_ribs.last_mut().unwrap().bindings.insert(ident, def); + this.label_ribs.last_mut().unwrap().bindings.insert(ident, id); f(this); }); } else { @@ -4099,31 +4287,34 @@ impl<'a> Resolver<'a> { } ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => { - let def = self.search_label(label.ident, |rib, ident| { + let node_id = self.search_label(label.ident, |rib, ident| { rib.bindings.get(&ident.modern_and_legacy()).cloned() }); - match def { + match node_id { None => { // Search again for close matches... // Picks the first label that is "close enough", which is not necessarily // the closest match let close_match = self.search_label(label.ident, |rib, ident| { - let names = rib.bindings.iter().map(|(id, _)| &id.name); + let names = rib.bindings.iter().filter_map(|(id, _)| { + if id.span.ctxt() == label.ident.span.ctxt() { + Some(&id.name) + } else { + None + } + }); find_best_match_for_name(names, &*ident.as_str(), None) }); - self.record_def(expr.id, err_path_resolution()); + self.record_partial_res(expr.id, PartialRes::new(Res::Err)); resolve_error(self, label.ident.span, ResolutionError::UndeclaredLabel(&label.ident.as_str(), close_match)); } - Some(Def::Label(id)) => { - // Since this def is a label, it is never read. - self.record_def(expr.id, PathResolution::new(Def::Label(id))); - self.unused_labels.remove(&id); - } - Some(_) => { - span_bug!(expr.span, "label wasn't mapped to a label def!"); + Some(node_id) => { + // Since this res is a label, it is never read. + self.label_res_map.insert(expr.id, node_id); + self.unused_labels.remove(&node_id); } } @@ -4131,41 +4322,26 @@ impl<'a> Resolver<'a> { visit::walk_expr(self, expr); } - ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => { - self.visit_expr(subexpression); + ExprKind::Let(ref pats, ref scrutinee) => { + self.visit_expr(scrutinee); + self.resolve_pats(pats, PatternSource::Let); + } + ExprKind::If(ref cond, ref then, ref opt_else) => { self.ribs[ValueNS].push(Rib::new(NormalRibKind)); - let mut bindings_list = FxHashMap::default(); - for pat in pats { - self.resolve_pattern(pat, PatternSource::IfLet, &mut bindings_list); - } - // This has to happen *after* we determine which pat_idents are variants - self.check_consistent_bindings(pats); - self.visit_block(if_block); + self.visit_expr(cond); + self.visit_block(then); self.ribs[ValueNS].pop(); - optional_else.as_ref().map(|expr| self.visit_expr(expr)); + opt_else.as_ref().map(|expr| self.visit_expr(expr)); } ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block), ExprKind::While(ref subexpression, ref block, label) => { self.with_resolved_label(label, expr.id, |this| { - this.visit_expr(subexpression); - this.visit_block(block); - }); - } - - ExprKind::WhileLet(ref pats, ref subexpression, ref block, label) => { - self.with_resolved_label(label, expr.id, |this| { - this.visit_expr(subexpression); this.ribs[ValueNS].push(Rib::new(NormalRibKind)); - let mut bindings_list = FxHashMap::default(); - for pat in pats { - this.resolve_pattern(pat, PatternSource::WhileLet, &mut bindings_list); - } - // This has to happen *after* we determine which pat_idents are variants. - this.check_consistent_bindings(pats); + this.visit_expr(subexpression); this.visit_block(block); this.ribs[ValueNS].pop(); }); @@ -4207,25 +4383,15 @@ impl<'a> Resolver<'a> { visit::walk_expr(self, expr); self.current_type_ascription.pop(); } - // Resolve the body of async exprs inside the async closure to which they desugar - ExprKind::Async(_, async_closure_id, ref block) => { - let rib_kind = ClosureRibKind(async_closure_id); - self.ribs[ValueNS].push(Rib::new(rib_kind)); - self.label_ribs.push(Rib::new(rib_kind)); - self.visit_block(&block); - self.label_ribs.pop(); - self.ribs[ValueNS].pop(); - } // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to // resolve the arguments within the proper scopes so that usages of them inside the // closure are detected as upvars rather than normal closure arg usages. ExprKind::Closure( - _, IsAsync::Async { closure_id: inner_closure_id, .. }, _, + _, IsAsync::Async { .. }, _, ref fn_decl, ref body, _span, ) => { - let rib_kind = ClosureRibKind(expr.id); + let rib_kind = NormalRibKind; self.ribs[ValueNS].push(Rib::new(rib_kind)); - self.label_ribs.push(Rib::new(rib_kind)); // Resolve arguments: let mut bindings_list = FxHashMap::default(); for argument in &fn_decl.inputs { @@ -4237,18 +4403,12 @@ impl<'a> Resolver<'a> { // Now resolve the inner closure { - let rib_kind = ClosureRibKind(inner_closure_id); - self.ribs[ValueNS].push(Rib::new(rib_kind)); - self.label_ribs.push(Rib::new(rib_kind)); // No need to resolve arguments: the inner closure has none. // Resolve the return type: visit::walk_fn_ret_ty(self, &fn_decl.output); // Resolve the body self.visit_expr(body); - self.label_ribs.pop(); - self.ribs[ValueNS].pop(); } - self.label_ribs.pop(); self.ribs[ValueNS].pop(); } _ => { @@ -4295,7 +4455,7 @@ impl<'a> Resolver<'a> { module.span, ).is_ok() { let def_id = module.def_id().unwrap(); - found_traits.push(TraitCandidate { def_id: def_id, import_id: None }); + found_traits.push(TraitCandidate { def_id: def_id, import_ids: smallvec![] }); } } @@ -4328,40 +4488,60 @@ impl<'a> Resolver<'a> { let mut collected_traits = Vec::new(); module.for_each_child(|name, ns, binding| { if ns != TypeNS { return } - if let Def::Trait(_) = binding.def() { - collected_traits.push((name, binding)); + match binding.res() { + Res::Def(DefKind::Trait, _) | + Res::Def(DefKind::TraitAlias, _) => collected_traits.push((name, binding)), + _ => (), } }); *traits = Some(collected_traits.into_boxed_slice()); } for &(trait_name, binding) in traits.as_ref().unwrap().iter() { - let module = binding.module().unwrap(); - let mut ident = ident; - if ident.span.glob_adjust(module.expansion, binding.span.ctxt().modern()).is_none() { - continue - } - if self.resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(module), - ident, - ns, - false, - module.span, - ).is_ok() { - let import_id = match binding.kind { - NameBindingKind::Import { directive, .. } => { - self.maybe_unused_trait_imports.insert(directive.id); - self.add_to_glob_map(&directive, trait_name); - Some(directive.id) - } - _ => None, - }; - let trait_def_id = module.def_id().unwrap(); - found_traits.push(TraitCandidate { def_id: trait_def_id, import_id: import_id }); + // Traits have pseudo-modules that can be used to search for the given ident. + if let Some(module) = binding.module() { + let mut ident = ident; + if ident.span.glob_adjust( + module.expansion, + binding.span, + ).is_none() { + continue + } + if self.resolve_ident_in_module_unadjusted( + ModuleOrUniformRoot::Module(module), + ident, + ns, + false, + module.span, + ).is_ok() { + let import_ids = self.find_transitive_imports(&binding.kind, trait_name); + let trait_def_id = module.def_id().unwrap(); + found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); + } + } else if let Res::Def(DefKind::TraitAlias, _) = binding.res() { + // For now, just treat all trait aliases as possible candidates, since we don't + // know if the ident is somewhere in the transitive bounds. + let import_ids = self.find_transitive_imports(&binding.kind, trait_name); + let trait_def_id = binding.res().def_id(); + found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); + } else { + bug!("candidate is not trait or trait alias?") } } } + fn find_transitive_imports(&mut self, mut kind: &NameBindingKind<'_>, + trait_name: Ident) -> SmallVec<[NodeId; 1]> { + let mut import_ids = smallvec![]; + while let NameBindingKind::Import { directive, binding, .. } = kind { + self.maybe_unused_trait_imports.insert(directive.id); + self.add_to_glob_map(&directive, trait_name); + import_ids.push(directive.id); + kind = &binding.kind; + }; + import_ids + } + fn lookup_import_candidates_from_module(&mut self, lookup_ident: Ident, namespace: Namespace, @@ -4369,11 +4549,11 @@ impl<'a> Resolver<'a> { crate_name: Ident, filter_fn: FilterFn) -> Vec - where FilterFn: Fn(Def) -> bool + where FilterFn: Fn(Res) -> bool { let mut candidates = Vec::new(); let mut seen_modules = FxHashSet::default(); - let not_local_module = crate_name != keywords::Crate.ident(); + let not_local_module = crate_name.name != kw::Crate; let mut worklist = vec![(start_module, Vec::::new(), not_local_module)]; while let Some((in_module, @@ -4391,8 +4571,8 @@ impl<'a> Resolver<'a> { // collect results based on the filter function if ident.name == lookup_ident.name && ns == namespace { - let def = name_binding.def(); - if filter_fn(def) { + let res = name_binding.res(); + if filter_fn(res) { // create the path let mut segms = path_segments.clone(); if lookup_ident.span.rust_2018() { @@ -4416,10 +4596,9 @@ impl<'a> Resolver<'a> { // declared as public (due to pruning, we don't explore // outside crate private modules => no need to check this) if !in_module_is_extern || name_binding.vis == ty::Visibility::Public { - let did = match def { - Def::StructCtor(did, _) | Def::VariantCtor(did, _) => - self.parent(did), - _ => def.opt_def_id(), + let did = match res { + Res::Def(DefKind::Ctor(..), did) => self.parent(did), + _ => res.opt_def_id(), }; candidates.push(ImportSuggestion { did, path }); } @@ -4465,10 +4644,11 @@ impl<'a> Resolver<'a> { namespace: Namespace, filter_fn: FilterFn) -> Vec - where FilterFn: Fn(Def) -> bool + where FilterFn: Fn(Res) -> bool { let mut suggestions = self.lookup_import_candidates_from_module( - lookup_ident, namespace, self.graph_root, keywords::Crate.ident(), &filter_fn); + lookup_ident, namespace, self.graph_root, Ident::with_empty_ctxt(kw::Crate), &filter_fn + ); if lookup_ident.span.rust_2018() { let extern_prelude_names = self.extern_prelude.clone(); @@ -4490,10 +4670,7 @@ impl<'a> Resolver<'a> { suggestions } - fn find_module(&mut self, - module_def: Def) - -> Option<(Module<'a>, ImportSuggestion)> - { + fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> { let mut result = None; let mut seen_modules = FxHashSet::default(); let mut worklist = vec![(self.graph_root, Vec::new())]; @@ -4513,16 +4690,16 @@ impl<'a> Resolver<'a> { // form the path let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); - if module.def() == Some(module_def) { + let module_def_id = module.def_id().unwrap(); + if module_def_id == def_id { let path = Path { span: name_binding.span, segments: path_segments, }; - let did = module.def().and_then(|def| def.opt_def_id()); - result = Some((module, ImportSuggestion { did, path })); + result = Some((module, ImportSuggestion { did: Some(def_id), path })); } else { // add the module to the lookup - if seen_modules.insert(module.def_id().unwrap()) { + if seen_modules.insert(module_def_id) { worklist.push((module, path_segments)); } } @@ -4533,17 +4710,13 @@ impl<'a> Resolver<'a> { result } - fn collect_enum_variants(&mut self, enum_def: Def) -> Option> { - if let Def::Enum(..) = enum_def {} else { - panic!("Non-enum def passed to collect_enum_variants: {:?}", enum_def) - } - - self.find_module(enum_def).map(|(enum_module, enum_import_suggestion)| { + fn collect_enum_variants(&mut self, def_id: DefId) -> Option> { + self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| { self.populate_module_if_necessary(enum_module); let mut variants = Vec::new(); enum_module.for_each_child_stable(|ident, _, name_binding| { - if let Def::Variant(..) = name_binding.def() { + if let Res::Def(DefKind::Variant, _) = name_binding.res() { let mut segms = enum_import_suggestion.path.segments.clone(); segms.push(ast::PathSegment::from_ident(ident)); variants.push(Path { @@ -4556,9 +4729,9 @@ impl<'a> Resolver<'a> { }) } - fn record_def(&mut self, node_id: NodeId, resolution: PathResolution) { - debug!("(recording def) recording {:?} for {}", resolution, node_id); - if let Some(prev_res) = self.def_map.insert(node_id, resolution) { + fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) { + debug!("(recording res) recording {:?} for {}", resolution, node_id); + if let Some(prev_res) = self.partial_res_map.insert(node_id, resolution) { panic!("path resolved multiple times ({:?} before, {:?} now)", prev_res, resolution); } } @@ -4594,24 +4767,24 @@ impl<'a> Resolver<'a> { } else { let ctxt = ident.span.ctxt(); Some(Segment::from_ident(Ident::new( - keywords::PathRoot.name(), path.span.shrink_to_lo().with_ctxt(ctxt) + kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ctxt) ))) }; let segments = crate_root.into_iter() .chain(path.segments.iter().map(|seg| seg.into())).collect::>(); - let def = self.smart_resolve_path_fragment( + let res = self.smart_resolve_path_fragment( id, None, &segments, path.span, PathSource::Visibility, CrateLint::SimplePath(id), - ).base_def(); - if def == Def::Err { + ).base_res(); + if res == Res::Err { ty::Visibility::Public } else { - let vis = ty::Visibility::Restricted(def.def_id()); + let vis = ty::Visibility::Restricted(res.def_id()); if self.is_accessible(vis) { vis } else { @@ -4659,9 +4832,9 @@ impl<'a> Resolver<'a> { fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String { if b.span.is_dummy() { - let add_built_in = match b.def() { + let add_built_in = match b.res() { // These already contain the "built-in" prefix or look bad with it. - Def::NonMacroAttr(..) | Def::PrimTy(..) | Def::ToolMod => false, + Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod => false, _ => true, }; let (built_in, from) = if from_prelude { @@ -4791,8 +4964,8 @@ impl<'a> Resolver<'a> { } let container = match parent.kind { - ModuleKind::Def(Def::Mod(_), _) => "module", - ModuleKind::Def(Def::Trait(_), _) => "trait", + ModuleKind::Def(DefKind::Mod, _, _) => "module", + ModuleKind::Def(DefKind::Trait, _, _) => "trait", ModuleKind::Block(..) => "block", _ => "enum", }; @@ -4874,7 +5047,7 @@ impl<'a> Resolver<'a> { }; // Check if the target of the use for both bindings is the same. - let duplicate = new_binding.def().opt_def_id() == old_binding.def().opt_def_id(); + let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id(); let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy(); let from_item = self.extern_prelude.get(&ident) .map(|entry| entry.introduced_by_item) @@ -4891,7 +5064,7 @@ impl<'a> Resolver<'a> { Some((directive, _, true)) if should_remove_import && !directive.is_glob() => { // Simple case - remove the entire import. Due to the above match arm, this can // only be a single use so just remove it entirely. - err.span_suggestion( + err.tool_only_span_suggestion( directive.use_span_with_attributes, "remove unnecessary import", String::new(), @@ -5001,7 +5174,6 @@ impl<'a> Resolver<'a> { ) { assert!(directive.is_nested()); let message = "remove unnecessary import"; - let source_map = self.session.source_map(); // Two examples will be used to illustrate the span manipulations we're doing: // @@ -5010,73 +5182,24 @@ impl<'a> Resolver<'a> { // - Given `use issue_52891::{d, e, a};` where `a` is a duplicate then `binding_span` is // `a` and `directive.use_span` is `issue_52891::{d, e, a};`. - // Find the span of everything after the binding. - // ie. `a, e};` or `a};` - let binding_until_end = binding_span.with_hi(directive.use_span.hi()); - - // Find everything after the binding but not including the binding. - // ie. `, e};` or `};` - let after_binding_until_end = binding_until_end.with_lo(binding_span.hi()); - - // Keep characters in the span until we encounter something that isn't a comma or - // whitespace. - // ie. `, ` or ``. - // - // Also note whether a closing brace character was encountered. If there - // was, then later go backwards to remove any trailing commas that are left. - let mut found_closing_brace = false; - let after_binding_until_next_binding = source_map.span_take_while( - after_binding_until_end, - |&ch| { - if ch == '}' { found_closing_brace = true; } - ch == ' ' || ch == ',' - } + let (found_closing_brace, span) = find_span_of_binding_until_next_binding( + self.session, binding_span, directive.use_span, ); - // Combine the two spans. - // ie. `a, ` or `a`. - // - // Removing these would leave `issue_52891::{d, e};` or `issue_52891::{d, e, };` - let span = binding_span.with_hi(after_binding_until_next_binding.hi()); - // If there was a closing brace then identify the span to remove any trailing commas from // previous imports. if found_closing_brace { - if let Ok(prev_source) = source_map.span_to_prev_source(span) { - // `prev_source` will contain all of the source that came before the span. - // Then split based on a command and take the first (ie. closest to our span) - // snippet. In the example, this is a space. - let prev_comma = prev_source.rsplit(',').collect::>(); - let prev_starting_brace = prev_source.rsplit('{').collect::>(); - if prev_comma.len() > 1 && prev_starting_brace.len() > 1 { - let prev_comma = prev_comma.first().unwrap(); - let prev_starting_brace = prev_starting_brace.first().unwrap(); - - // If the amount of source code before the comma is greater than - // the amount of source code before the starting brace then we've only - // got one item in the nested item (eg. `issue_52891::{self}`). - if prev_comma.len() > prev_starting_brace.len() { - // So just remove the entire line... - err.span_suggestion( - directive.use_span_with_attributes, - message, - String::new(), - Applicability::MaybeIncorrect, - ); - return; - } - - let span = span.with_lo(BytePos( - // Take away the number of bytes for the characters we've found and an - // extra for the comma. - span.lo().0 - (prev_comma.as_bytes().len() as u32) - 1 - )); - err.span_suggestion( - span, message, String::new(), Applicability::MaybeIncorrect, - ); - return; - } + if let Some(span) = extend_span_to_previous_binding(self.session, span) { + err.tool_only_span_suggestion(span, message, String::new(), + Applicability::MaybeIncorrect); + } else { + // Remove the entire line if we cannot extend the span back, this indicates a + // `issue_52891::{self}` case. + err.span_suggestion(directive.use_span_with_attributes, message, String::new(), + Applicability::MaybeIncorrect); } + + return; } err.span_suggestion(span, message, String::new(), Applicability::MachineApplicable); @@ -5113,17 +5236,17 @@ impl<'a> Resolver<'a> { } fn is_self_type(path: &[Segment], namespace: Namespace) -> bool { - namespace == TypeNS && path.len() == 1 && path[0].ident.name == keywords::SelfUpper.name() + namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper } fn is_self_value(path: &[Segment], namespace: Namespace) -> bool { - namespace == ValueNS && path.len() == 1 && path[0].ident.name == keywords::SelfLower.name() + namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower } fn names_to_string(idents: &[Ident]) -> String { let mut result = String::new(); for (i, ident) in idents.iter() - .filter(|ident| ident.name != keywords::PathRoot.name()) + .filter(|ident| ident.name != kw::PathRoot) .enumerate() { if i > 0 { result.push_str("::"); @@ -5210,7 +5333,7 @@ fn module_to_string(module: Module<'_>) -> Option { let mut names = Vec::new(); fn collect_mod(names: &mut Vec, module: Module<'_>) { - if let ModuleKind::Def(_, name) = module.kind { + if let ModuleKind::Def(.., name) = module.kind { if let Some(parent) = module.parent { names.push(Ident::with_empty_ctxt(name)); collect_mod(names, parent); @@ -5231,10 +5354,6 @@ fn module_to_string(module: Module<'_>) -> Option { .collect::>())) } -fn err_path_resolution() -> PathResolution { - PathResolution::new(Def::Err) -} - #[derive(Copy, Clone, Debug)] enum CrateLint { /// Do not issue the lint. diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 63f752ac9c942..392a46a262f50 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -6,9 +6,8 @@ use crate::ModuleOrUniformRoot; use crate::Namespace::*; use crate::build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport}; use crate::resolve_imports::ImportResolver; -use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX, DefIndex, - CrateNum, DefIndexAddressSpace}; -use rustc::hir::def::{Def, NonMacroAttrKind}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; +use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; use rustc::hir::map::{self, DefCollector}; use rustc::{ty, lint}; use rustc::{bug, span_bug}; @@ -18,12 +17,12 @@ use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Determinacy}; use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; -use syntax::ext::hygiene::{self, Mark}; +use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{ feature_err, is_builtin_attr_name, AttributeGate, GateIssue, Stability, BUILTIN_ATTRIBUTES, }; -use syntax::symbol::{Symbol, keywords}; +use syntax::symbol::{Symbol, kw, sym}; use syntax::visit::Visitor; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{Span, DUMMY_SP}; @@ -33,6 +32,8 @@ use std::cell::Cell; use std::{mem, ptr}; use rustc_data_structures::sync::Lrc; +type Res = def::Res; + #[derive(Clone, Debug)] pub struct InvocationData<'a> { def_index: DefIndex, @@ -113,6 +114,22 @@ fn sub_namespace_match(candidate: Option, requirement: Option String { + let mut path_str = String::with_capacity(64); + for (i, segment) in path.segments.iter().enumerate() { + if i != 0 { + path_str.push_str("::"); + } + if segment.ident.name != kw::PathRoot { + path_str.push_str(&segment.ident.as_str()) + } + } + path_str +} + impl<'a> base::Resolver for Resolver<'a> { fn next_node_id(&mut self) -> ast::NodeId { self.session.next_node_id() @@ -131,15 +148,15 @@ impl<'a> base::Resolver for Resolver<'a> { } fn resolve_dollar_crates(&mut self, fragment: &AstFragment) { - struct ResolveDollarCrates<'a, 'b: 'a> { + struct ResolveDollarCrates<'a, 'b> { resolver: &'a mut Resolver<'b> } impl<'a> Visitor<'a> for ResolveDollarCrates<'a, '_> { fn visit_ident(&mut self, ident: Ident) { - if ident.name == keywords::DollarCrate.name() { + if ident.name == kw::DollarCrate { let name = match self.resolver.resolve_crate_root(ident).kind { - ModuleKind::Def(_, name) if name != keywords::Invalid.name() => name, - _ => keywords::Crate.name(), + ModuleKind::Def(.., name) if name != kw::Invalid => name, + _ => kw::Crate, }; ident.span.ctxt().set_dollar_crate_name(name); } @@ -171,13 +188,12 @@ impl<'a> base::Resolver for Resolver<'a> { fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc) { let def_id = DefId { krate: CrateNum::BuiltinMacros, - index: DefIndex::from_array_index(self.macro_map.len(), - DefIndexAddressSpace::Low), + index: DefIndex::from(self.macro_map.len()), }; - let kind = ext.kind(); + let kind = ext.macro_kind(); self.macro_map.insert(def_id, ext); let binding = self.arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Def(Def::Macro(def_id, kind), false), + kind: NameBindingKind::Res(Res::Def(DefKind::Macro(kind), def_id), false), ambiguity: None, span: DUMMY_SP, vis: ty::Visibility::Public, @@ -207,16 +223,21 @@ impl<'a> base::Resolver for Resolver<'a> { }; let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); - let (def, ext) = match self.resolve_macro_to_def(path, kind, &parent_scope, true, force) { - Ok((def, ext)) => (def, ext), - Err(Determinacy::Determined) if kind == MacroKind::Attr => { - // Replace unresolved attributes with used inert attributes for better recovery. - return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr { mark_used: true }))); - } + let (res, ext) = match self.resolve_macro_to_res(path, kind, &parent_scope, true, force) { + Ok((res, ext)) => (res, ext), + // Replace unresolved attributes with used inert attributes for better recovery. + Err(Determinacy::Determined) if kind == MacroKind::Attr => + (Res::Err, self.non_macro_attr(true)), Err(determinacy) => return Err(determinacy), }; - if let Def::Macro(def_id, _) = def { + let format = match kind { + MacroKind::Derive => format!("derive({})", fast_print_path(path)), + _ => fast_print_path(path), + }; + invoc.expansion_data.mark.set_expn_info(ext.expn_info(invoc.span(), &format)); + + if let Res::Def(_, def_id) = res { if after_derive { self.session.span_err(invoc.span(), "macro attributes must be placed before `#[derive]`"); @@ -226,7 +247,6 @@ impl<'a> base::Resolver for Resolver<'a> { self.macro_def_scope(invoc.expansion_data.mark).normal_ancestor_id; self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.mark, normal_module_def_id); - invoc.expansion_data.mark.set_default_transparency(ext.default_transparency()); } Ok(Some(ext)) @@ -236,17 +256,12 @@ impl<'a> base::Resolver for Resolver<'a> { derives_in_scope: Vec, force: bool) -> Result, Determinacy> { let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); - Ok(self.resolve_macro_to_def(path, kind, &parent_scope, false, force)?.1) + Ok(self.resolve_macro_to_res(path, kind, &parent_scope, false, force)?.1) } fn check_unused_macros(&self) { for did in self.unused_macros.iter() { - let id_span = match *self.macro_map[did] { - SyntaxExtension::NormalTT { def_info, .. } | - SyntaxExtension::DeclMacro { def_info, .. } => def_info, - _ => None, - }; - if let Some((id, span)) = id_span { + if let Some((id, span)) = self.macro_map[did].def_info { let lint = lint::builtin::UNUSED_MACROS; let msg = "unused macro definition"; self.session.buffer_lint(lint, id, span, msg); @@ -272,18 +287,18 @@ impl<'a> Resolver<'a> { } } - fn resolve_macro_to_def( + fn resolve_macro_to_res( &mut self, path: &ast::Path, kind: MacroKind, parent_scope: &ParentScope<'a>, trace: bool, force: bool, - ) -> Result<(Def, Lrc), Determinacy> { - let def = self.resolve_macro_to_def_inner(path, kind, parent_scope, trace, force); + ) -> Result<(Res, Lrc), Determinacy> { + let res = self.resolve_macro_to_res_inner(path, kind, parent_scope, trace, force); // Report errors and enforce feature gates for the resolved macro. - if def != Err(Determinacy::Undetermined) { + if res != Err(Determinacy::Undetermined) { // Do not report duplicated errors on every undetermined resolution. for segment in &path.segments { if let Some(args) = &segment.args { @@ -292,10 +307,10 @@ impl<'a> Resolver<'a> { } } - let def = def?; + let res = res?; - match def { - Def::Macro(def_id, macro_kind) => { + match res { + Res::Def(DefKind::Macro(macro_kind), def_id) => { self.unused_macros.remove(&def_id); if macro_kind == MacroKind::ProcMacroStub { let msg = "can't use a procedural macro from the same crate that defines it"; @@ -303,7 +318,7 @@ impl<'a> Resolver<'a> { return Err(Determinacy::Determined); } } - Def::NonMacroAttr(attr_kind) => { + Res::NonMacroAttr(attr_kind) => { if kind == MacroKind::Attr { let features = self.session.features_untracked(); if attr_kind == NonMacroAttrKind::Custom { @@ -313,7 +328,8 @@ impl<'a> Resolver<'a> { if !features.rustc_attrs { let msg = "unless otherwise specified, attributes with the prefix \ `rustc_` are reserved for internal compiler diagnostics"; - self.report_unknown_attribute(path.span, &name, msg, "rustc_attrs"); + self.report_unknown_attribute(path.span, &name, msg, + sym::rustc_attrs); } } else if !features.custom_attribute { let msg = format!("The attribute `{}` is currently unknown to the \ @@ -323,29 +339,29 @@ impl<'a> Resolver<'a> { path.span, &name, &msg, - "custom_attribute", + sym::custom_attribute, ); } } } else { // Not only attributes, but anything in macro namespace can result in - // `Def::NonMacroAttr` definition (e.g., `inline!()`), so we must report + // `Res::NonMacroAttr` definition (e.g., `inline!()`), so we must report // an error for those cases. - let msg = format!("expected a macro, found {}", def.kind_name()); + let msg = format!("expected a macro, found {}", res.descr()); self.session.span_err(path.span, &msg); return Err(Determinacy::Determined); } } - Def::Err => { + Res::Err => { return Err(Determinacy::Determined); } - _ => panic!("expected `Def::Macro` or `Def::NonMacroAttr`"), + _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"), } - Ok((def, self.get_macro(def))) + Ok((res, self.get_macro(res))) } - fn report_unknown_attribute(&self, span: Span, name: &str, msg: &str, feature: &str) { + fn report_unknown_attribute(&self, span: Span, name: &str, msg: &str, feature: Symbol) { let mut err = feature_err( &self.session.parse_sess, feature, @@ -358,8 +374,8 @@ impl<'a> Resolver<'a> { let attr_candidates = BUILTIN_ATTRIBUTES .iter() - .filter_map(|(name, _, _, gate)| { - if name.starts_with("rustc_") && !features.rustc_attrs { + .filter_map(|&(name, _, _, ref gate)| { + if name.as_str().starts_with("rustc_") && !features.rustc_attrs { return None; } @@ -374,7 +390,6 @@ impl<'a> Resolver<'a> { _ => None, } }) - .map(|name| Symbol::intern(name)) .chain( // Add built-in macro attributes as well. self.builtin_macros.iter().filter_map(|(name, binding)| { @@ -400,45 +415,45 @@ impl<'a> Resolver<'a> { err.emit(); } - pub fn resolve_macro_to_def_inner( + pub fn resolve_macro_to_res_inner( &mut self, path: &ast::Path, kind: MacroKind, parent_scope: &ParentScope<'a>, trace: bool, force: bool, - ) -> Result { + ) -> Result { let path_span = path.span; let mut path = Segment::from_path(path); // Possibly apply the macro helper hack if kind == MacroKind::Bang && path.len() == 1 && - path[0].ident.span.ctxt().outer().expn_info() + path[0].ident.span.ctxt().outer_expn_info() .map_or(false, |info| info.local_inner_macros) { - let root = Ident::new(keywords::DollarCrate.name(), path[0].ident.span); + let root = Ident::new(kw::DollarCrate, path[0].ident.span); path.insert(0, Segment::from_ident(root)); } if path.len() > 1 { - let def = match self.resolve_path(&path, Some(MacroNS), parent_scope, + let res = match self.resolve_path(&path, Some(MacroNS), parent_scope, false, path_span, CrateLint::No) { PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { - Ok(path_res.base_def()) + Ok(path_res.base_res()) } PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), - PathResult::NonModule(..) | PathResult::Indeterminate | PathResult::Failed(..) => { - Err(Determinacy::Determined) - } + PathResult::NonModule(..) + | PathResult::Indeterminate + | PathResult::Failed { .. } => Err(Determinacy::Determined), PathResult::Module(..) => unreachable!(), }; if trace { parent_scope.module.multi_segment_macro_resolutions.borrow_mut() - .push((path, path_span, kind, parent_scope.clone(), def.ok())); + .push((path, path_span, kind, parent_scope.clone(), res.ok())); } - self.prohibit_imported_non_macro_attrs(None, def.ok(), path_span); - def + self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span); + res } else { let binding = self.early_resolve_ident_in_lexical_scope( path[0].ident, ScopeSet::Macro(kind), parent_scope, false, force, path_span @@ -452,9 +467,9 @@ impl<'a> Resolver<'a> { .push((path[0].ident, kind, parent_scope.clone(), binding.ok())); } - let def = binding.map(|binding| binding.def()); - self.prohibit_imported_non_macro_attrs(binding.ok(), def.ok(), path_span); - def + let res = binding.map(|binding| binding.res()); + self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span); + res } } @@ -572,7 +587,7 @@ impl<'a> Resolver<'a> { ScopeSet::Module => (TypeNS, None, false, false), }; let mut where_to_resolve = match ns { - _ if is_absolute_path || is_import && rust_2015 => WhereToResolve::CrateRoot, + _ if is_absolute_path => WhereToResolve::CrateRoot, TypeNS | ValueNS => WhereToResolve::Module(parent_scope.module), MacroNS => WhereToResolve::DeriveHelpers, }; @@ -584,19 +599,14 @@ impl<'a> Resolver<'a> { let mut result = Err(Determinacy::Determined); for derive in &parent_scope.derives { let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope }; - match self.resolve_macro_to_def(derive, MacroKind::Derive, + match self.resolve_macro_to_res(derive, MacroKind::Derive, &parent_scope, true, force) { - Ok((_, ext)) => { - if let SyntaxExtension::ProcMacroDerive(_, helpers, _) = &*ext { - if helpers.contains(&ident.name) { - let binding = - (Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper), - ty::Visibility::Public, derive.span, Mark::root()) - .to_name_binding(self.arenas); - result = Ok((binding, Flags::empty())); - break; - } - } + Ok((_, ext)) => if ext.helper_attrs.contains(&ident.name) { + let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper), + ty::Visibility::Public, derive.span, Mark::root()) + .to_name_binding(self.arenas); + result = Ok((binding, Flags::empty())); + break; } Err(Determinacy::Determined) => {} Err(Determinacy::Undetermined) => @@ -613,7 +623,7 @@ impl<'a> Resolver<'a> { _ => Err(Determinacy::Determined), } WhereToResolve::CrateRoot => { - let root_ident = Ident::new(keywords::PathRoot.name(), orig_ident.span); + let root_ident = Ident::new(kw::PathRoot, orig_ident.span); let root_module = self.resolve_crate_root(root_ident); let binding = self.resolve_ident_in_module_ext( ModuleOrUniformRoot::Module(root_module), @@ -683,7 +693,7 @@ impl<'a> Resolver<'a> { } WhereToResolve::BuiltinAttrs => { if is_builtin_attr_name(ident.name) { - let binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin), + let binding = (Res::NonMacroAttr(NonMacroAttrKind::Builtin), ty::Visibility::Public, DUMMY_SP, Mark::root()) .to_name_binding(self.arenas); Ok((binding, Flags::PRELUDE)) @@ -694,8 +704,8 @@ impl<'a> Resolver<'a> { WhereToResolve::LegacyPluginHelpers => { if (use_prelude || rust_2015) && self.session.plugin_attributes.borrow().iter() - .any(|(name, _)| ident.name == &**name) { - let binding = (Def::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper), + .any(|(name, _)| ident.name == *name) { + let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper), ty::Visibility::Public, DUMMY_SP, Mark::root()) .to_name_binding(self.arenas); Ok((binding, Flags::PRELUDE)) @@ -717,7 +727,7 @@ impl<'a> Resolver<'a> { } WhereToResolve::ToolPrelude => { if use_prelude && is_known_tool(ident.name) { - let binding = (Def::ToolMod, ty::Visibility::Public, + let binding = (Res::ToolMod, ty::Visibility::Public, DUMMY_SP, Mark::root()).to_name_binding(self.arenas); Ok((binding, Flags::PRELUDE)) } else { @@ -744,7 +754,7 @@ impl<'a> Resolver<'a> { WhereToResolve::BuiltinTypes => { match self.primitive_type_table.primitive_types.get(&ident.name).cloned() { Some(prim_ty) => { - let binding = (Def::PrimTy(prim_ty), ty::Visibility::Public, + let binding = (Res::PrimTy(prim_ty), ty::Visibility::Public, DUMMY_SP, Mark::root()).to_name_binding(self.arenas); Ok((binding, Flags::PRELUDE)) } @@ -761,24 +771,22 @@ impl<'a> Resolver<'a> { if let Some((innermost_binding, innermost_flags)) = innermost_result { // Found another solution, if the first one was "weak", report an error. - let (def, innermost_def) = (binding.def(), innermost_binding.def()); - if def != innermost_def { - let builtin = Def::NonMacroAttr(NonMacroAttrKind::Builtin); - let derive_helper = Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper); + let (res, innermost_res) = (binding.res(), innermost_binding.res()); + if res != innermost_res { + let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin); + let derive_helper = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); let legacy_helper = - Def::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper); + Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper); let ambiguity_error_kind = if is_import { Some(AmbiguityKind::Import) - } else if is_absolute_path { - Some(AmbiguityKind::AbsolutePath) - } else if innermost_def == builtin || def == builtin { + } else if innermost_res == builtin || res == builtin { Some(AmbiguityKind::BuiltinAttr) - } else if innermost_def == derive_helper || def == derive_helper { + } else if innermost_res == derive_helper || res == derive_helper { Some(AmbiguityKind::DeriveHelper) - } else if innermost_def == legacy_helper && + } else if innermost_res == legacy_helper && flags.contains(Flags::PRELUDE) || - def == legacy_helper && + res == legacy_helper && innermost_flags.contains(Flags::PRELUDE) { Some(AmbiguityKind::LegacyHelperVsPrelude) } else if innermost_flags.contains(Flags::MACRO_RULES) && @@ -841,18 +849,13 @@ impl<'a> Resolver<'a> { LegacyScope::Empty => WhereToResolve::Module(parent_scope.module), LegacyScope::Uninitialized => unreachable!(), } - WhereToResolve::CrateRoot if is_import => match ns { - TypeNS | ValueNS => WhereToResolve::Module(parent_scope.module), - MacroNS => WhereToResolve::DeriveHelpers, - } - WhereToResolve::CrateRoot if is_absolute_path => match ns { + WhereToResolve::CrateRoot => match ns { TypeNS => { ident.span.adjust(Mark::root()); WhereToResolve::ExternPrelude } ValueNS | MacroNS => break, } - WhereToResolve::CrateRoot => unreachable!(), WhereToResolve::Module(module) => { match self.hygienic_lexical_parent(module, &mut ident.span) { Some(parent_module) => WhereToResolve::Module(parent_module), @@ -885,44 +888,7 @@ impl<'a> Resolver<'a> { } // The first found solution was the only one, return it. - if let Some((binding, flags)) = innermost_result { - // We get to here only if there's no ambiguity, in ambiguous cases an error will - // be reported anyway, so there's no reason to report an additional feature error. - // The `binding` can actually be introduced by something other than `--extern`, - // but its `Def` should coincide with a crate passed with `--extern` - // (otherwise there would be ambiguity) and we can skip feature error in this case. - 'ok: { - if !is_import || !rust_2015 { - break 'ok; - } - if ns == TypeNS && use_prelude && self.extern_prelude_get(ident, true).is_some() { - break 'ok; - } - let root_ident = Ident::new(keywords::PathRoot.name(), orig_ident.span); - let root_module = self.resolve_crate_root(root_ident); - if self.resolve_ident_in_module_ext(ModuleOrUniformRoot::Module(root_module), - orig_ident, ns, None, false, path_span) - .is_ok() { - break 'ok; - } - - let msg = "imports can only refer to extern crate names passed with \ - `--extern` in macros originating from 2015 edition"; - let mut err = self.session.struct_span_err(ident.span, msg); - let what = self.binding_description(binding, ident, - flags.contains(Flags::MISC_FROM_PRELUDE)); - let note_msg = format!("this import refers to {what}", what = what); - let label_span = if binding.span.is_dummy() { - err.note(¬e_msg); - ident.span - } else { - err.span_note(binding.span, ¬e_msg); - binding.span - }; - err.span_label(label_span, "not an extern crate passed with `--extern`"); - err.emit(); - } - + if let Some((binding, _)) = innermost_result { return Ok(binding); } @@ -932,7 +898,7 @@ impl<'a> Resolver<'a> { // attribute. (Lexical resolution implies the first segment and attr kind should imply // the last segment, so we are certainly working with a single-segment attribute here.) assert!(ns == MacroNS); - let binding = (Def::NonMacroAttr(NonMacroAttrKind::Custom), + let binding = (Res::NonMacroAttr(NonMacroAttrKind::Custom), ty::Visibility::Public, ident.span, Mark::root()) .to_name_binding(self.arenas); Ok(binding) @@ -945,18 +911,18 @@ impl<'a> Resolver<'a> { let module = self.current_module; let check_consistency = |this: &mut Self, path: &[Segment], span, kind: MacroKind, - initial_def: Option, def: Def| { - if let Some(initial_def) = initial_def { - if def != initial_def && def != Def::Err && this.ambiguity_errors.is_empty() { + initial_res: Option, res: Res| { + if let Some(initial_res) = initial_res { + if res != initial_res && res != Res::Err && this.ambiguity_errors.is_empty() { // Make sure compilation does not succeed if preferred macro resolution // has changed after the macro had been expanded. In theory all such // situations should be reported as ambiguity errors, so this is a bug. - if initial_def == Def::NonMacroAttr(NonMacroAttrKind::Custom) { + if initial_res == Res::NonMacroAttr(NonMacroAttrKind::Custom) { // Yeah, legacy custom attributes are implemented using forced resolution // (which is a best effort error recovery tool, basically), so we can't // promise their resolution won't change later. let msg = format!("inconsistent resolution for a macro: first {}, then {}", - initial_def.kind_name(), def.kind_name()); + initial_res.descr(), res.descr()); this.session.span_err(span, &msg); } else { span_bug!(span, "inconsistent resolution for a macro"); @@ -981,23 +947,26 @@ impl<'a> Resolver<'a> { let macro_resolutions = mem::replace(&mut *module.multi_segment_macro_resolutions.borrow_mut(), Vec::new()); - for (mut path, path_span, kind, parent_scope, initial_def) in macro_resolutions { + for (mut path, path_span, kind, parent_scope, initial_res) in macro_resolutions { // FIXME: Path resolution will ICE if segment IDs present. for seg in &mut path { seg.id = None; } match self.resolve_path(&path, Some(MacroNS), &parent_scope, true, path_span, CrateLint::No) { PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { - let def = path_res.base_def(); - check_consistency(self, &path, path_span, kind, initial_def, def); + let res = path_res.base_res(); + check_consistency(self, &path, path_span, kind, initial_res, res); } - path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed(..) => { - let (span, msg) = if let PathResult::Failed(span, msg, ..) = path_res { - (span, msg) + path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => { + let (span, label) = if let PathResult::Failed { span, label, .. } = path_res { + (span, label) } else { (path_span, format!("partially resolved path in {} {}", kind.article(), kind.descr())) }; - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + resolve_error(self, span, ResolutionError::FailedToResolve { + label, + suggestion: None + }); } PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), } @@ -1009,13 +978,13 @@ impl<'a> Resolver<'a> { match self.early_resolve_ident_in_lexical_scope(ident, ScopeSet::Macro(kind), &parent_scope, true, true, ident.span) { Ok(binding) => { - let initial_def = initial_binding.map(|initial_binding| { + let initial_res = initial_binding.map(|initial_binding| { self.record_use(ident, MacroNS, initial_binding, false); - initial_binding.def() + initial_binding.res() }); - let def = binding.def(); + let res = binding.res(); let seg = Segment::from_ident(ident); - check_consistency(self, &[seg], ident.span, kind, initial_def, def); + check_consistency(self, &[seg], ident.span, kind, initial_res, res); } Err(..) => { assert!(initial_binding.is_none()); @@ -1023,7 +992,7 @@ impl<'a> Resolver<'a> { let msg = format!("cannot find {} `{}{}` in this scope", kind.descr(), ident, bang); let mut err = self.session.struct_span_err(ident.span, &msg); - self.suggest_macro_name(&ident.as_str(), kind, &mut err, ident.span); + self.suggest_macro_name(ident.name, kind, &mut err, ident.span); err.emit(); } } @@ -1038,8 +1007,8 @@ impl<'a> Resolver<'a> { } fn prohibit_imported_non_macro_attrs(&self, binding: Option<&'a NameBinding<'a>>, - def: Option, span: Span) { - if let Some(Def::NonMacroAttr(kind)) = def { + res: Option, span: Span) { + if let Some(Res::NonMacroAttr(kind)) = res { if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) { let msg = format!("cannot use a {} through an import", kind.descr()); let mut err = self.session.struct_span_err(span, &msg); @@ -1051,11 +1020,18 @@ impl<'a> Resolver<'a> { } } - fn suggest_macro_name(&mut self, name: &str, kind: MacroKind, + fn suggest_macro_name(&mut self, name: Symbol, kind: MacroKind, err: &mut DiagnosticBuilder<'a>, span: Span) { + if kind == MacroKind::Derive && (name.as_str() == "Send" || name.as_str() == "Sync") { + let msg = format!("unsafe traits like `{}` should be implemented explicitly", name); + err.span_note(span, &msg); + return; + } + // First check if this is a locally-defined bang macro. let suggestion = if let MacroKind::Bang = kind { - find_best_match_for_name(self.macro_names.iter().map(|ident| &ident.name), name, None) + find_best_match_for_name( + self.macro_names.iter().map(|ident| &ident.name), &name.as_str(), None) } else { None // Then check global macros. @@ -1064,17 +1040,17 @@ impl<'a> Resolver<'a> { .filter_map(|(name, binding)| { if binding.macro_kind() == Some(kind) { Some(name) } else { None } }); - find_best_match_for_name(names, name, None) + find_best_match_for_name(names, &name.as_str(), None) // Then check modules. }).or_else(|| { - let is_macro = |def| { - if let Def::Macro(_, def_kind) = def { + let is_macro = |res| { + if let Res::Def(DefKind::Macro(def_kind), _) = res { def_kind == kind } else { false } }; - let ident = Ident::new(Symbol::intern(name), span); + let ident = Ident::new(name, span); self.lookup_typo_candidate(&[Segment::from_ident(ident)], MacroNS, is_macro, span) .map(|suggestion| suggestion.candidate) }); @@ -1133,52 +1109,52 @@ impl<'a> Resolver<'a> { current_legacy_scope: &mut LegacyScope<'a>) { self.local_macro_def_scopes.insert(item.id, self.current_module); let ident = item.ident; - if ident.name == "macro_rules" { + if ident.name == sym::macro_rules { self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`"); } let def_id = self.definitions.local_def_id(item.id); let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess, &self.session.features_untracked(), - item, hygiene::default_edition())); + item, self.session.edition())); self.macro_map.insert(def_id, ext); let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() }; if def.legacy { let ident = ident.modern(); self.macro_names.insert(ident); - let def = Def::Macro(def_id, MacroKind::Bang); - let is_macro_export = attr::contains_name(&item.attrs, "macro_export"); + let res = Res::Def(DefKind::Macro(MacroKind::Bang), def_id); + let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { ty::Visibility::Public } else { ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)) }; - let binding = (def, vis, item.span, expansion).to_name_binding(self.arenas); + let binding = (res, vis, item.span, expansion).to_name_binding(self.arenas); self.set_binding_parent_module(binding, self.current_module); let legacy_binding = self.arenas.alloc_legacy_binding(LegacyBinding { parent_legacy_scope: *current_legacy_scope, binding, ident }); *current_legacy_scope = LegacyScope::Binding(legacy_binding); - self.all_macros.insert(ident.name, def); + self.all_macros.insert(ident.name, res); if is_macro_export { let module = self.graph_root; self.define(module, ident, MacroNS, - (def, vis, item.span, expansion, IsMacroExport)); + (res, vis, item.span, expansion, IsMacroExport)); } else { - if !attr::contains_name(&item.attrs, "rustc_doc_only_macro") { + if !attr::contains_name(&item.attrs, sym::rustc_doc_only_macro) { self.check_reserved_macro_name(ident, MacroNS); } self.unused_macros.insert(def_id); } } else { let module = self.current_module; - let def = Def::Macro(def_id, MacroKind::Bang); + let res = Res::Def(DefKind::Macro(MacroKind::Bang), def_id); let vis = self.resolve_visibility(&item.vis); if vis != ty::Visibility::Public { self.unused_macros.insert(def_id); } - self.define(module, ident, MacroNS, (def, vis, item.span, expansion)); + self.define(module, ident, MacroNS, (res, vis, item.span, expansion)); } } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index b930c30c51192..f69849bb4a9ee 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -6,15 +6,22 @@ use crate::Namespace::{self, TypeNS, MacroNS}; use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; use crate::{Resolver, Segment}; use crate::{names_to_string, module_to_string}; -use crate::{resolve_error, ResolutionError}; +use crate::{resolve_error, ResolutionError, Suggestion}; +use crate::ModuleKind; use crate::macros::ParentScope; +use errors::Applicability; + use rustc_data_structures::ptr_key::PtrKey; use rustc::ty; use rustc::lint::builtin::BuiltinLintDiagnostics; -use rustc::lint::builtin::{DUPLICATE_MACRO_EXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE}; +use rustc::lint::builtin::{ + DUPLICATE_MACRO_EXPORTS, + PUB_USE_OF_PRIVATE_EXTERN_CRATE, + UNUSED_IMPORTS, +}; use rustc::hir::def_id::{CrateNum, DefId}; -use rustc::hir::def::*; +use rustc::hir::def::{self, DefKind, PartialRes, Export}; use rustc::session::DiagnosticMessageId; use rustc::util::nodemap::FxHashSet; use rustc::{bug, span_bug}; @@ -22,16 +29,18 @@ use rustc::{bug, span_bug}; use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::hygiene::Mark; -use syntax::symbol::keywords; +use syntax::symbol::{kw, sym}; use syntax::util::lev_distance::find_best_match_for_name; use syntax::{struct_span_err, unwrap_or}; use syntax_pos::{MultiSpan, Span}; -use log::debug; +use log::*; use std::cell::{Cell, RefCell}; use std::{mem, ptr}; +type Res = def::Res; + /// Contains data for specific types of import directives. #[derive(Clone, Debug)] pub enum ImportDirectiveSubclass<'a> { @@ -138,7 +147,7 @@ pub struct NameResolution<'a> { impl<'a> NameResolution<'a> { // Returns the binding for the name if it is known or None if it not known. - fn binding(&self) -> Option<&'a NameBinding<'a>> { + pub(crate) fn binding(&self) -> Option<&'a NameBinding<'a>> { self.binding.and_then(|binding| { if !binding.is_glob_import() || self.single_imports.is_empty() { Some(binding) } else { None } @@ -208,15 +217,15 @@ impl<'a> Resolver<'a> { parent_scope.expect("no parent scope for a single-segment import"); if ns == TypeNS { - if ident.name == keywords::Crate.name() || - ident.name == keywords::DollarCrate.name() { + if ident.name == kw::Crate || + ident.name == kw::DollarCrate { let module = self.resolve_crate_root(ident); let binding = (module, ty::Visibility::Public, module.span, Mark::root()) .to_name_binding(self.arenas); return Ok(binding); - } else if ident.name == keywords::Super.name() || - ident.name == keywords::SelfLower.name() { + } else if ident.name == kw::Super || + ident.name == kw::SelfLower { // FIXME: Implement these with renaming requirements so that e.g. // `use super;` doesn't work, but `use super as name;` does. // Fall through here to get an error from `early_resolve_...`. @@ -238,7 +247,7 @@ impl<'a> Resolver<'a> { if let Some(binding) = resolution.binding { if !restricted_shadowing && binding.expansion != Mark::root() { - if let NameBindingKind::Def(_, true) = binding.kind { + if let NameBindingKind::Res(_, true) = binding.kind { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); } } @@ -278,7 +287,7 @@ impl<'a> Resolver<'a> { // Forbid expanded shadowing to avoid time travel. if restricted_shadowing && binding.expansion != Mark::root() && - binding.def() != shadowed_glob.def() { + binding.res() != shadowed_glob.res() { self.ambiguity_errors.push(AmbiguityError { kind: AmbiguityKind::GlobVsExpanded, ident, @@ -379,7 +388,7 @@ impl<'a> Resolver<'a> { None => return Err((Undetermined, Weak::Yes)), }; let (orig_current_module, mut ident) = (self.current_module, ident.modern()); - match ident.span.glob_adjust(module.expansion, glob_import.span.ctxt().modern()) { + match ident.span.glob_adjust(module.expansion, glob_import.span) { Some(Some(def)) => self.current_module = self.macro_def_scope(def), Some(None) => {} None => continue, @@ -487,7 +496,8 @@ impl<'a> Resolver<'a> { // Reserve some names that are not quite covered by the general check // performed on `Resolver::builtin_attrs`. if ns == MacroNS && - (ident.name == "cfg" || ident.name == "cfg_attr" || ident.name == "derive") { + (ident.name == sym::cfg || ident.name == sym::cfg_attr || + ident.name == sym::derive) { self.session.span_err(ident.span, &format!("name `{}` is reserved in macro namespace", ident)); } @@ -504,13 +514,13 @@ impl<'a> Resolver<'a> { self.set_binding_parent_module(binding, module); self.update_resolution(module, ident, ns, |this, resolution| { if let Some(old_binding) = resolution.binding { - if binding.def() == Def::Err { - // Do not override real bindings with `Def::Err`s from error recovery. + if binding.res() == Res::Err { + // Do not override real bindings with `Res::Err`s from error recovery. return Ok(()); } match (old_binding.is_glob_import(), binding.is_glob_import()) { (true, true) => { - if binding.def() != old_binding.def() { + if binding.res() != old_binding.res() { resolution.binding = Some(this.ambiguity(AmbiguityKind::GlobVsGlob, old_binding, binding)); } else if !old_binding.vis.is_at_least(binding.vis, &*this) { @@ -524,7 +534,7 @@ impl<'a> Resolver<'a> { } else { (binding, old_binding) }; - if glob_binding.def() != nonglob_binding.def() && + if glob_binding.res() != nonglob_binding.res() && ns == MacroNS && nonglob_binding.expansion != Mark::root() { resolution.binding = Some(this.ambiguity(AmbiguityKind::GlobVsExpanded, nonglob_binding, glob_binding)); @@ -534,7 +544,7 @@ impl<'a> Resolver<'a> { resolution.shadowed_glob = Some(glob_binding); } (false, false) => { - if let (&NameBindingKind::Def(_, true), &NameBindingKind::Def(_, true)) = + if let (&NameBindingKind::Res(_, true), &NameBindingKind::Res(_, true)) = (&old_binding.kind, &binding.kind) { this.session.buffer_lint_with_diagnostic( @@ -595,8 +605,7 @@ impl<'a> Resolver<'a> { // Define `binding` in `module`s glob importers. for directive in module.glob_importers.borrow_mut().iter() { let mut ident = ident.modern(); - let scope = match ident.span.reverse_glob_adjust(module.expansion, - directive.span.ctxt().modern()) { + let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) { Some(Some(def)) => self.macro_def_scope(def), Some(None) => directive.parent_scope.module, None => continue, @@ -610,7 +619,7 @@ impl<'a> Resolver<'a> { t } - // Define a "dummy" resolution containing a Def::Err as a placeholder for a + // Define a "dummy" resolution containing a Res::Err as a placeholder for a // failed resolution fn import_dummy_binding(&mut self, directive: &'a ImportDirective<'a>) { if let SingleImport { target, .. } = directive.subclass { @@ -618,35 +627,47 @@ impl<'a> Resolver<'a> { let dummy_binding = self.import(dummy_binding, directive); self.per_ns(|this, ns| { let _ = this.try_define(directive.parent_scope.module, target, ns, dummy_binding); + // Consider erroneous imports used to avoid duplicate diagnostics. + this.record_use(target, ns, dummy_binding, false); }); } } } -pub struct ImportResolver<'a, 'b: 'a> { +/// An error that may be transformed into a diagnostic later. Used to combine multiple unresolved +/// import errors within the same use tree into a single diagnostic. +#[derive(Debug, Clone)] +struct UnresolvedImportError { + span: Span, + label: Option, + note: Vec, + suggestion: Option, +} + +pub struct ImportResolver<'a, 'b> { pub resolver: &'a mut Resolver<'b>, } -impl<'a, 'b: 'a> std::ops::Deref for ImportResolver<'a, 'b> { +impl<'a, 'b> std::ops::Deref for ImportResolver<'a, 'b> { type Target = Resolver<'b>; fn deref(&self) -> &Resolver<'b> { self.resolver } } -impl<'a, 'b: 'a> std::ops::DerefMut for ImportResolver<'a, 'b> { +impl<'a, 'b> std::ops::DerefMut for ImportResolver<'a, 'b> { fn deref_mut(&mut self) -> &mut Resolver<'b> { self.resolver } } -impl<'a, 'b: 'a> ty::DefIdTree for &'a ImportResolver<'a, 'b> { +impl<'a, 'b> ty::DefIdTree for &'a ImportResolver<'a, 'b> { fn parent(self, id: DefId) -> Option { self.resolver.parent(id) } } -impl<'a, 'b:'a> ImportResolver<'a, 'b> { +impl<'a, 'b> ImportResolver<'a, 'b> { // Import resolution // // This is a fixed-point algorithm. We resolve imports until our efforts @@ -675,17 +696,17 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.finalize_resolutions_in(module); } - let mut errors = false; + let mut has_errors = false; let mut seen_spans = FxHashSet::default(); - let mut error_vec = Vec::new(); + let mut errors = vec![]; let mut prev_root_id: NodeId = NodeId::from_u32(0); for i in 0 .. self.determined_imports.len() { let import = self.determined_imports[i]; - if let Some((span, err, note)) = self.finalize_import(import) { - errors = true; + if let Some(err) = self.finalize_import(import) { + has_errors = true; if let SingleImport { source, ref source_bindings, .. } = import.subclass { - if source.name == "self" { + if source.name == kw::SelfLower { // Silence `unresolved import` error if E0429 is already emitted if let Err(Determined) = source_bindings.value_ns.get() { continue; @@ -696,37 +717,36 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // If the error is a single failed import then create a "fake" import // resolution for it so that later resolve stages won't complain. self.import_dummy_binding(import); - if prev_root_id.as_u32() != 0 && - prev_root_id.as_u32() != import.root_id.as_u32() && - !error_vec.is_empty(){ - // in case of new import line, throw diagnostic message - // for previous line. - let mut empty_vec = vec![]; - mem::swap(&mut empty_vec, &mut error_vec); - self.throw_unresolved_import_error(empty_vec, None); + if prev_root_id.as_u32() != 0 + && prev_root_id.as_u32() != import.root_id.as_u32() + && !errors.is_empty() { + // In the case of a new import line, throw a diagnostic message + // for the previous line. + self.throw_unresolved_import_error(errors, None); + errors = vec![]; } - if !seen_spans.contains(&span) { + if !seen_spans.contains(&err.span) { let path = import_path_to_string( &import.module_path.iter().map(|seg| seg.ident).collect::>(), &import.subclass, - span, + err.span, ); - error_vec.push((span, path, err, note)); - seen_spans.insert(span); + seen_spans.insert(err.span); + errors.push((path, err)); prev_root_id = import.root_id; } } } - if !error_vec.is_empty() { - self.throw_unresolved_import_error(error_vec.clone(), None); + if !errors.is_empty() { + self.throw_unresolved_import_error(errors.clone(), None); } // Report unresolved imports only if no hard error was already reported // to avoid generating multiple errors on the same import. - if !errors { + if !has_errors { for import in &self.indeterminate_imports { - self.throw_unresolved_import_error(error_vec, Some(MultiSpan::from(import.span))); + self.throw_unresolved_import_error(errors, Some(MultiSpan::from(import.span))); break; } } @@ -734,44 +754,55 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { fn throw_unresolved_import_error( &self, - error_vec: Vec<(Span, String, String, Option)>, + errors: Vec<(String, UnresolvedImportError)>, span: Option, ) { - let max_span_label_msg_count = 10; // upper limit on number of span_label message. - let (span, msg, note) = if error_vec.is_empty() { - (span.unwrap(), "unresolved import".to_string(), None) + /// Upper limit on the number of `span_label` messages. + const MAX_LABEL_COUNT: usize = 10; + + let (span, msg) = if errors.is_empty() { + (span.unwrap(), "unresolved import".to_string()) } else { let span = MultiSpan::from_spans( - error_vec.clone().into_iter() - .map(|elem: (Span, String, String, Option)| elem.0) - .collect() + errors + .iter() + .map(|(_, err)| err.span) + .collect(), ); - let note: Option = error_vec.clone().into_iter() - .filter_map(|elem: (Span, String, String, Option)| elem.3) - .last(); + let paths = errors + .iter() + .map(|(path, _)| format!("`{}`", path)) + .collect::>(); - let path_vec: Vec = error_vec.clone().into_iter() - .map(|elem: (Span, String, String, Option)| format!("`{}`", elem.1)) - .collect(); - let path = path_vec.join(", "); let msg = format!( "unresolved import{} {}", - if path_vec.len() > 1 { "s" } else { "" }, - path + if paths.len() > 1 { "s" } else { "" }, + paths.join(", "), ); - (span, msg, note) + (span, msg) }; - let mut err = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg); - for span_error in error_vec.into_iter().take(max_span_label_msg_count) { - err.span_label(span_error.0, span_error.2); + let mut diag = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg); + + if let Some((_, UnresolvedImportError { note, .. })) = errors.iter().last() { + for message in note { + diag.note(&message); + } } - if let Some(note) = note { - err.note(¬e); + + for (_, err) in errors.into_iter().take(MAX_LABEL_COUNT) { + if let Some(label) = err.label { + diag.span_label(err.span, label); + } + + if let Some((suggestions, msg, applicability)) = err.suggestion { + diag.multipart_suggestion(&msg, suggestions, applicability); + } } - err.emit(); + + diag.emit(); } /// Attempts to resolve the given import, returning true if its resolution is determined. @@ -802,7 +833,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { match path_res { PathResult::Module(module) => module, PathResult::Indeterminate => return false, - PathResult::NonModule(..) | PathResult::Failed(..) => return true, + PathResult::NonModule(..) | PathResult::Failed { .. } => return true, } }; @@ -855,10 +886,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { Ok(binding) => { let imported_binding = this.import(binding, directive); target_bindings[ns].set(Some(imported_binding)); - let conflict = this.try_define(parent, target, ns, imported_binding); - if let Err(old_binding) = conflict { - this.report_conflict(parent, target, ns, imported_binding, old_binding); - } + this.define(parent, target, ns, imported_binding); } } }); @@ -866,11 +894,14 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { !indeterminate } - // If appropriate, returns an error to report. + /// Performs final import resolution, consistency checks and error reporting. + /// + /// Optionally returns an unresolved import error. This error is buffered and used to + /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import( &mut self, directive: &'b ImportDirective<'b> - ) -> Option<(Span, String, Option)> { + ) -> Option { self.current_module = directive.parent_scope.module; let orig_vis = directive.vis.replace(ty::Visibility::Invisible); @@ -896,29 +927,51 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { module } - PathResult::Failed(span, msg, false) => { + PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => { if no_ambiguity { assert!(directive.imported_module.get().is_none()); - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + resolve_error(self, span, ResolutionError::FailedToResolve { + label, + suggestion, + }); } return None; } - PathResult::Failed(span, msg, true) => { + PathResult::Failed { is_error_from_last_segment: true, span, label, suggestion } => { if no_ambiguity { assert!(directive.imported_module.get().is_none()); - return Some(match self.make_path_suggestion(span, directive.module_path.clone(), - &directive.parent_scope) { - Some((suggestion, note)) => ( - span, - format!("did you mean `{}`?", Segment::names_to_string(&suggestion)), - note, - ), - None => (span, msg, None), - }); + let err = match self.make_path_suggestion( + span, + directive.module_path.clone(), + &directive.parent_scope, + ) { + Some((suggestion, note)) => { + UnresolvedImportError { + span, + label: None, + note, + suggestion: Some(( + vec![(span, Segment::names_to_string(&suggestion))], + String::from("a similar path exists"), + Applicability::MaybeIncorrect, + )), + } + } + None => { + UnresolvedImportError { + span, + label: Some(label), + note: Vec::new(), + suggestion, + } + } + }; + + return Some(err); } return None; } - PathResult::NonModule(path_res) if path_res.base_def() == Def::Err => { + PathResult::NonModule(path_res) if path_res.base_res() == Res::Err => { if no_ambiguity { assert!(directive.imported_module.get().is_none()); } @@ -938,7 +991,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = directive.module_path.clone(); - full_path.push(Segment::from_ident(keywords::Invalid.ident())); + full_path.push(Segment::from_ident(Ident::invalid())); self.lint_if_path_starts_with_module( directive.crate_lint(), &full_path, @@ -950,11 +1003,12 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if let ModuleOrUniformRoot::Module(module) = module { if module.def_id() == directive.parent_scope.module.def_id() { // Importing a module into itself is not allowed. - return Some(( - directive.span, - "Cannot glob-import a module into itself.".to_string(), - None, - )); + return Some(UnresolvedImportError { + span: directive.span, + label: Some(String::from("cannot glob-import a module into itself")), + note: Vec::new(), + suggestion: None, + }); } } if !is_prelude && @@ -984,24 +1038,25 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { match binding { Ok(binding) => { // Consistency checks, analogous to `finalize_current_module_macro_resolutions`. - let initial_def = source_bindings[ns].get().map(|initial_binding| { + let initial_res = source_bindings[ns].get().map(|initial_binding| { all_ns_err = false; if let Some(target_binding) = target_bindings[ns].get() { - if target.name == "_" && + // Note that as_str() de-gensyms the Symbol + if target.name.as_str() == "_" && initial_binding.is_extern_crate() && !initial_binding.is_import() { this.record_use(ident, ns, target_binding, directive.module_path.is_empty()); } } - initial_binding.def() + initial_binding.res() }); - let def = binding.def(); - if let Ok(initial_def) = initial_def { - if def != initial_def && this.ambiguity_errors.is_empty() { + let res = binding.res(); + if let Ok(initial_res) = initial_res { + if res != initial_res && this.ambiguity_errors.is_empty() { span_bug!(directive.span, "inconsistent resolution for an import"); } } else { - if def != Def::Err && + if res != Res::Err && this.ambiguity_errors.is_empty() && this.privacy_errors.is_empty() { let msg = "cannot determine resolution for the import"; let msg_note = @@ -1047,7 +1102,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { match binding.kind { // Never suggest the name that has binding error // i.e., the name that cannot be previously resolved - NameBindingKind::Def(Def::Err, _) => return None, + NameBindingKind::Res(Res::Err, _) => return None, _ => Some(&i.name), } }, @@ -1059,31 +1114,47 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { _ => Some(&i.name), } }); - let lev_suggestion = - match find_best_match_for_name(names, &ident.as_str(), None) { - Some(name) => format!(". Did you mean to use `{}`?", name), - None => String::new(), - }; - let msg = match module { + + let lev_suggestion = find_best_match_for_name(names, &ident.as_str(), None) + .map(|suggestion| + (vec![(ident.span, suggestion.to_string())], + String::from("a similar name exists in the module"), + Applicability::MaybeIncorrect) + ); + + let (suggestion, note) = match self.check_for_module_export_macro( + directive, module, ident, + ) { + Some((suggestion, note)) => (suggestion.or(lev_suggestion), note), + _ => (lev_suggestion, Vec::new()), + }; + + let label = match module { ModuleOrUniformRoot::Module(module) => { let module_str = module_to_string(module); if let Some(module_str) = module_str { - format!("no `{}` in `{}`{}", ident, module_str, lev_suggestion) + format!("no `{}` in `{}`", ident, module_str) } else { - format!("no `{}` in the root{}", ident, lev_suggestion) + format!("no `{}` in the root", ident) } } _ => { if !ident.is_path_segment_keyword() { - format!("no `{}` external crate{}", ident, lev_suggestion) + format!("no `{}` external crate", ident) } else { // HACK(eddyb) this shows up for `self` & `super`, which // should work instead - for now keep the same error message. - format!("no `{}` in the root{}", ident, lev_suggestion) + format!("no `{}` in the root", ident) } } }; - Some((directive.span, msg, None)) + + Some(UnresolvedImportError { + span: directive.span, + label: Some(label), + note, + suggestion, + }) } else { // `resolve_ident_in_module` reported a privacy error. self.import_dummy_binding(directive); @@ -1153,24 +1224,110 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. self.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() { - let mut def = binding.def(); - if let Def::Macro(def_id, _) = def { + let mut res = binding.res(); + if let Res::Def(DefKind::Macro(_), def_id) = res { // `DefId`s from the "built-in macro crate" should not leak from resolve because // later stages are not ready to deal with them and produce lots of ICEs. Replace - // them with `Def::Err` until some saner scheme is implemented for built-in macros. + // them with `Res::Err` until some saner scheme is implemented for built-in macros. if def_id.krate == CrateNum::BuiltinMacros { this.session.span_err(directive.span, "cannot import a built-in macro"); - def = Def::Err; + res = Res::Err; } } - let import = this.import_map.entry(directive.id).or_default(); - import[ns] = Some(PathResolution::new(def)); + this.import_res_map.entry(directive.id).or_default()[ns] = Some(res); }); + self.check_for_redundant_imports( + ident, + directive, + source_bindings, + target_bindings, + target, + ); + debug!("(resolving single import) successfully resolved import"); None } + fn check_for_redundant_imports( + &mut self, + ident: Ident, + directive: &'b ImportDirective<'b>, + source_bindings: &PerNS, Determinacy>>>, + target_bindings: &PerNS>>>, + target: Ident, + ) { + // Skip if the import was produced by a macro. + if directive.parent_scope.expansion != Mark::root() { + return; + } + + // Skip if we are inside a named module (in contrast to an anonymous + // module defined by a block). + if let ModuleKind::Def(..) = directive.parent_scope.module.kind { + return; + } + + let mut is_redundant = PerNS { + value_ns: None, + type_ns: None, + macro_ns: None, + }; + + let mut redundant_span = PerNS { + value_ns: None, + type_ns: None, + macro_ns: None, + }; + + self.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() { + if binding.res() == Res::Err { + return; + } + + let orig_blacklisted_binding = mem::replace( + &mut this.blacklisted_binding, + target_bindings[ns].get() + ); + + match this.early_resolve_ident_in_lexical_scope( + target, + ScopeSet::Import(ns), + &directive.parent_scope, + false, + false, + directive.span, + ) { + Ok(other_binding) => { + is_redundant[ns] = Some( + binding.res() == other_binding.res() + && !other_binding.is_ambiguity() + ); + redundant_span[ns] = + Some((other_binding.span, other_binding.is_import())); + } + Err(_) => is_redundant[ns] = Some(false) + } + + this.blacklisted_binding = orig_blacklisted_binding; + }); + + if !is_redundant.is_empty() && + is_redundant.present_items().all(|is_redundant| is_redundant) + { + let mut redundant_spans: Vec<_> = redundant_span.present_items().collect(); + redundant_spans.sort(); + redundant_spans.dedup(); + self.session.buffer_lint_with_diagnostic( + UNUSED_IMPORTS, + directive.id, + directive.span, + &format!("the item `{}` is imported redundantly", ident), + BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident), + ); + } + } + fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) { let module = match directive.imported_module.get().unwrap() { ModuleOrUniformRoot::Module(module) => module, @@ -1182,7 +1339,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.populate_module_if_necessary(module); - if let Some(Def::Trait(_)) = module.def() { + if module.is_trait() { self.session.span_err(directive.span, "items in traits are not importable."); return; } else if module.def_id() == directive.parent_scope.module.def_id() { @@ -1201,8 +1358,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { resolution.borrow().binding().map(|binding| (ident, binding)) }).collect::>(); for ((mut ident, ns), binding) in bindings { - let scope = match ident.span.reverse_glob_adjust(module.expansion, - directive.span.ctxt().modern()) { + let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) { Some(Some(def)) => self.macro_def_scope(def), Some(None) => self.current_module, None => continue, @@ -1214,7 +1370,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } // Record the destination of this import - self.record_def(directive.id, PathResolution::new(module.def().unwrap())); + self.record_partial_res(directive.id, PartialRes::new(module.res().unwrap())); } // Miscellaneous post-processing, including recording re-exports, @@ -1232,20 +1388,23 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { None => continue, }; - // Filter away "empty import canaries" and ambiguous imports. + // Filter away ambiguous and gensymed imports. Gensymed imports + // (e.g. implicitly injected `std`) cannot be properly encoded in metadata, + // so they can cause name conflict errors downstream. let is_good_import = binding.is_import() && !binding.is_ambiguity() && - binding.vis != ty::Visibility::Invisible; + // Note that as_str() de-gensyms the Symbol + !(ident.is_gensymed() && ident.name.as_str() != "_"); if is_good_import || binding.is_macro_def() { - let def = binding.def(); - if def != Def::Err { - if let Some(def_id) = def.opt_def_id() { + let res = binding.res(); + if res != Res::Err { + if let Some(def_id) = res.opt_def_id() { if !def_id.is_local() && def_id.krate != CrateNum::BuiltinMacros { self.cstore.export_macros_untracked(def_id.krate); } } reexports.push(Export { ident: ident.modern(), - def: def, + res: res, span: binding.span, vis: binding.vis, }); @@ -1323,8 +1482,8 @@ fn import_path_to_string(names: &[Ident], subclass: &ImportDirectiveSubclass<'_>, span: Span) -> String { let pos = names.iter() - .position(|p| span == p.span && p.name != keywords::PathRoot.name()); - let global = !names.is_empty() && names[0].name == keywords::PathRoot.name(); + .position(|p| span == p.span && p.name != kw::PathRoot); + let global = !names.is_empty() && names[0].name == kw::PathRoot; if let Some(pos) = pos { let names = if global { &names[1..pos + 1] } else { &names[..pos + 1] }; names_to_string(names) diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 8bb2e722b5794..767c726b761f2 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -16,9 +16,8 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_target = { path = "../librustc_target" } rustc_typeck = { path = "../librustc_typeck" } +serde_json = "1" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rls-data = "0.18.1" -rls-span = "0.4" -# FIXME(#40527) should move rustc serialize out of tree -rustc-serialize = "0.3" +rls-data = "0.19" +rls-span = "0.5" diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index b82aee7c96ad2..beef9f151cf00 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -13,11 +13,11 @@ //! DumpVisitor walks the AST and processes it, and JsonDumper is used for //! recording the output. -use rustc::hir::def::Def as HirDef; +use rustc::hir::def::{Res, DefKind as HirDefKind}; use rustc::hir::def_id::DefId; use rustc::session::config::Input; use rustc::span_bug; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, DefIdTree, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use std::path::Path; @@ -58,24 +58,26 @@ macro_rules! down_cast_data { } macro_rules! access_from { - ($save_ctxt:expr, $vis:expr, $id:expr) => { + ($save_ctxt:expr, $item:expr, $id:expr) => { Access { - public: $vis.node.is_pub(), + public: $item.vis.node.is_pub(), reachable: $save_ctxt.access_levels.is_reachable($id), } }; +} - ($save_ctxt:expr, $item:expr) => { +macro_rules! access_from_vis { + ($save_ctxt:expr, $vis:expr, $id:expr) => { Access { - public: $item.vis.node.is_pub(), - reachable: $save_ctxt.access_levels.is_reachable($item.id), + public: $vis.node.is_pub(), + reachable: $save_ctxt.access_levels.is_reachable($id), } }; } -pub struct DumpVisitor<'l, 'tcx: 'l, 'll, O: DumpOutput> { +pub struct DumpVisitor<'l, 'tcx, 'll, O: DumpOutput> { save_ctxt: SaveContext<'l, 'tcx>, - tcx: TyCtxt<'l, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, dumper: &'ll mut JsonDumper, span: SpanUtils<'l>, @@ -90,7 +92,7 @@ pub struct DumpVisitor<'l, 'tcx: 'l, 'll, O: DumpOutput> { // macro_calls: FxHashSet, } -impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { +impl<'l, 'tcx, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { pub fn new( save_ctxt: SaveContext<'l, 'tcx>, dumper: &'ll mut JsonDumper, @@ -231,8 +233,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { } fn lookup_def_id(&self, ref_id: NodeId) -> Option { - match self.save_ctxt.get_path_def(ref_id) { - HirDef::PrimTy(..) | HirDef::SelfTy(..) | HirDef::Err => None, + match self.save_ctxt.get_path_res(ref_id) { + Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => None, def => Some(def.def_id()), } } @@ -303,7 +305,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { method_data.value = sig_str; method_data.sig = sig::method_signature(id, ident, generics, sig, &self.save_ctxt); - self.dumper.dump_def(&access_from!(self.save_ctxt, vis, id), method_data); + let hir_id = self.tcx.hir().node_to_hir_id(id); + self.dumper.dump_def(&access_from_vis!(self.save_ctxt, vis, hir_id), method_data); } // walk arg and return types @@ -324,7 +327,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) { let field_data = self.save_ctxt.get_field_data(field, parent_id); if let Some(field_data) = field_data { - self.dumper.dump_def(&access_from!(self.save_ctxt, field), field_data); + let hir_id = self.tcx.hir().node_to_hir_id(field.id); + self.dumper.dump_def(&access_from!(self.save_ctxt, field, hir_id), field_data); } } @@ -389,7 +393,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { |v| v.process_formals(&decl.inputs, &fn_data.qualname), ); self.process_generic_params(ty_params, &fn_data.qualname, item.id); - self.dumper.dump_def(&access_from!(self.save_ctxt, item), fn_data); + let hir_id = self.tcx.hir().node_to_hir_id(item.id); + self.dumper.dump_def(&access_from!(self.save_ctxt, item, hir_id), fn_data); } for arg in &decl.inputs { @@ -409,10 +414,11 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { typ: &'l ast::Ty, expr: &'l ast::Expr, ) { + let hir_id = self.tcx.hir().node_to_hir_id(item.id); self.nest_tables(item.id, |v| { if let Some(var_data) = v.save_ctxt.get_item_data(item) { down_cast_data!(var_data, DefData, item.span); - v.dumper.dump_def(&access_from!(v.save_ctxt, item), var_data); + v.dumper.dump_def(&access_from!(v.save_ctxt, item, hir_id), var_data); } v.visit_ty(&typ); v.visit_expr(expr); @@ -429,14 +435,16 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { vis: ast::Visibility, attrs: &'l [Attribute], ) { - let qualname = format!("::{}", self.tcx.node_path_str(id)); + let qualname = format!("::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(id))); if !self.span.filter_generated(ident.span) { let sig = sig::assoc_const_signature(id, ident.name, typ, expr, &self.save_ctxt); let span = self.span_from_span(ident.span); + let hir_id = self.tcx.hir().node_to_hir_id(id); self.dumper.dump_def( - &access_from!(self.save_ctxt, vis, id), + &access_from_vis!(self.save_ctxt, vis, hir_id), Def { kind: DefKind::Const, id: id_from_node_id(id, &self.save_ctxt), @@ -455,10 +463,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { } // walk type and init value - self.visit_ty(typ); - if let Some(expr) = expr { - self.visit_expr(expr); - } + self.nest_tables(id, |v| { + v.visit_ty(typ); + if let Some(expr) = expr { + v.visit_expr(expr); + } + }); } // FIXME tuple structs should generate tuple-specific data. @@ -470,7 +480,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { ) { debug!("process_struct {:?} {:?}", item, item.span); let name = item.ident.to_string(); - let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + let qualname = format!("::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id))); let kind = match item.node { ast::ItemKind::Struct(_, _) => DefKind::Struct, @@ -479,8 +490,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { }; let (value, fields) = match item.node { - ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) | - ast::ItemKind::Union(ast::VariantData::Struct(ref fields, _), _) => { + ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, ..), ..) | + ast::ItemKind::Union(ast::VariantData::Struct(ref fields, ..), ..) => { let include_priv_fields = !self.save_ctxt.config.pub_only; let fields_str = fields .iter() @@ -510,8 +521,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { if !self.span.filter_generated(item.ident.span) { let span = self.span_from_span(item.ident.span); + let hir_id = self.tcx.hir().node_to_hir_id(item.id); self.dumper.dump_def( - &access_from!(self.save_ctxt, item), + &access_from!(self.save_ctxt, item, hir_id), Def { kind, id: id_from_node_id(item.id, &self.save_ctxt), @@ -550,7 +562,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { }; down_cast_data!(enum_data, DefData, item.span); - let access = access_from!(self.save_ctxt, item); + let hir_id = self.tcx.hir().node_to_hir_id(item.id); + let access = access_from!(self.save_ctxt, item, hir_id); for variant in &enum_definition.variants { let name = variant.node.ident.name.to_string(); @@ -558,7 +571,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { let name_span = variant.node.ident.span; match variant.node.data { - ast::VariantData::Struct(ref fields, _) => { + ast::VariantData::Struct(ref fields, ..) => { let fields_str = fields .iter() .enumerate() @@ -570,7 +583,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str); if !self.span.filter_generated(name_span) { let span = self.span_from_span(name_span); - let id = id_from_node_id(variant.node.data.id(), &self.save_ctxt); + let id = id_from_node_id(variant.node.id, &self.save_ctxt); let parent = Some(id_from_node_id(item.id, &self.save_ctxt)); self.dumper.dump_def( @@ -608,7 +621,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { } if !self.span.filter_generated(name_span) { let span = self.span_from_span(name_span); - let id = id_from_node_id(variant.node.data.id(), &self.save_ctxt); + let id = id_from_node_id(variant.node.id, &self.save_ctxt); let parent = Some(id_from_node_id(item.id, &self.save_ctxt)); self.dumper.dump_def( @@ -637,7 +650,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { for field in variant.node.data.fields() { - self.process_struct_field_def(field, variant.node.data.id()); + self.process_struct_field_def(field, variant.node.id); self.visit_ty(&field.ty); } } @@ -648,7 +661,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { fn process_impl( &mut self, item: &'l ast::Item, - type_parameters: &'l ast::Generics, + generics: &'l ast::Generics, trait_ref: &'l Option, typ: &'l ast::Ty, impl_items: &'l [ast::ImplItem], @@ -667,7 +680,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { if let &Some(ref trait_ref) = trait_ref { self.process_path(trait_ref.ref_id, &trait_ref.path); } - self.process_generic_params(type_parameters, "", item.id); + self.process_generic_params(generics, "", item.id); for impl_item in impl_items { let map = &self.tcx.hir(); self.process_impl_item(impl_item, map.local_def_id(item.id)); @@ -682,7 +695,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { methods: &'l [ast::TraitItem], ) { let name = item.ident.to_string(); - let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + let qualname = format!("::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id))); let mut val = name.clone(); if !generics.params.is_empty() { val.push_str(&generic_params_to_string(&generics.params)); @@ -698,8 +712,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { .iter() .map(|i| id_from_node_id(i.id, &self.save_ctxt)) .collect(); + let hir_id = self.tcx.hir().node_to_hir_id(item.id); self.dumper.dump_def( - &access_from!(self.save_ctxt, item), + &access_from!(self.save_ctxt, item, hir_id), Def { kind: DefKind::Trait, id, @@ -757,7 +772,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { fn process_mod(&mut self, item: &ast::Item) { if let Some(mod_data) = self.save_ctxt.get_item_data(item) { down_cast_data!(mod_data, DefData, item.span); - self.dumper.dump_def(&access_from!(self.save_ctxt, item), mod_data); + let hir_id = self.tcx.hir().node_to_hir_id(item.id); + self.dumper.dump_def(&access_from!(self.save_ctxt, item, hir_id), mod_data); } } @@ -870,7 +886,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { return; } }; - let variant = adt.variant_of_def(self.save_ctxt.get_path_def(p.id)); + let variant = adt.variant_of_res(self.save_ctxt.get_path_res(p.id)); for &Spanned { node: ref field, .. } in fields { if let Some(index) = self.tcx.find_field_index(field.ident, variant) { @@ -900,14 +916,14 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { // process collected paths for (id, ident, immut) in collector.collected_idents { - match self.save_ctxt.get_path_def(id) { - HirDef::Local(id) => { + match self.save_ctxt.get_path_res(id) { + Res::Local(hir_id) => { let mut value = if immut == ast::Mutability::Immutable { self.span.snippet(ident.span) } else { "".to_owned() }; - let hir_id = self.tcx.hir().node_to_hir_id(id); + let id = self.tcx.hir().hir_to_node_id(hir_id); let typ = self.save_ctxt .tables .node_type_opt(hir_id) @@ -943,15 +959,14 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { ); } } - HirDef::StructCtor(..) | - HirDef::VariantCtor(..) | - HirDef::Const(..) | - HirDef::AssociatedConst(..) | - HirDef::Struct(..) | - HirDef::Variant(..) | - HirDef::TyAlias(..) | - HirDef::AssociatedTy(..) | - HirDef::SelfTy(..) => { + Res::Def(HirDefKind::Ctor(..), _) | + Res::Def(HirDefKind::Const, _) | + Res::Def(HirDefKind::AssocConst, _) | + Res::Def(HirDefKind::Struct, _) | + Res::Def(HirDefKind::Variant, _) | + Res::Def(HirDefKind::TyAlias, _) | + Res::Def(HirDefKind::AssocTy, _) | + Res::SelfTy(..) => { self.dump_path_ref(id, &ast::Path::from_ident(ident)); } def => error!( @@ -1093,7 +1108,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { ast::TraitItemKind::Type(ref bounds, ref default_ty) => { // FIXME do something with _bounds (for type refs) let name = trait_item.ident.name.to_string(); - let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id)); + let qualname = format!("::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(trait_item.id))); if !self.span.filter_generated(trait_item.ident.span) { let span = self.span_from_span(trait_item.ident.span); @@ -1161,13 +1177,13 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { ); } ast::ImplItemKind::Type(ref ty) => { - // FIXME uses of the assoc type should ideally point to this + // FIXME: uses of the assoc type should ideally point to this // 'def' and the name here should be a ref to the def in the // trait. self.visit_ty(ty) } ast::ImplItemKind::Existential(ref bounds) => { - // FIXME uses of the assoc type should ideally point to this + // FIXME: uses of the assoc type should ideally point to this // 'def' and the name here should be a ref to the def in the // trait. for bound in bounds.iter() { @@ -1197,11 +1213,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { // The access is calculated using the current tree ID, but with the root tree's visibility // (since nested trees don't have their own visibility). - let access = access_from!(self.save_ctxt, root_item.vis, id); + let hir_id = self.tcx.hir().node_to_hir_id(id); + let access = access_from!(self.save_ctxt, root_item, hir_id); - // The parent def id of a given use tree is always the enclosing item. + // The parent `DefId` of a given use tree is always the enclosing item. let parent = self.save_ctxt.tcx.hir().opt_local_def_id(id) - .and_then(|id| self.save_ctxt.tcx.parent_def_id(id)) + .and_then(|id| self.save_ctxt.tcx.parent(id)) .map(id_from_def_id); match use_tree.kind { @@ -1294,13 +1311,14 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { } } -impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, O> { +impl<'l, 'tcx, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, O> { fn visit_mod(&mut self, m: &'l ast::Mod, span: Span, attrs: &[ast::Attribute], id: NodeId) { // Since we handle explicit modules ourselves in visit_item, this should // only get called for the root module of a crate. assert_eq!(id, ast::CRATE_NODE_ID); - let qualname = format!("::{}", self.tcx.node_path_str(id)); + let qualname = format!("::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(id))); let cm = self.tcx.sess.source_map(); let filename = cm.span_to_filename(span); @@ -1350,7 +1368,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc if !self.span.filter_generated(name_span) { let span = self.span_from_span(name_span); let parent = self.save_ctxt.tcx.hir().opt_local_def_id(item.id) - .and_then(|id| self.save_ctxt.tcx.parent_def_id(id)) + .and_then(|id| self.save_ctxt.tcx.parent(id)) .map(id_from_def_id); self.dumper.import( &Access { @@ -1389,14 +1407,16 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc self.nest_scope(item.id, |v| visit::walk_mod(v, m)); } Ty(ref ty, ref ty_params) => { - let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + let qualname = format!("::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id))); let value = ty_to_string(&ty); if !self.span.filter_generated(item.ident.span) { let span = self.span_from_span(item.ident.span); let id = id_from_node_id(item.id, &self.save_ctxt); + let hir_id = self.tcx.hir().node_to_hir_id(item.id); self.dumper.dump_def( - &access_from!(self.save_ctxt, item), + &access_from!(self.save_ctxt, item, hir_id), Def { kind: DefKind::Type, id, @@ -1418,15 +1438,17 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc self.process_generic_params(ty_params, &qualname, item.id); } Existential(ref _bounds, ref ty_params) => { - let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + let qualname = format!("::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id))); // FIXME do something with _bounds let value = String::new(); if !self.span.filter_generated(item.ident.span) { let span = self.span_from_span(item.ident.span); let id = id_from_node_id(item.id, &self.save_ctxt); + let hir_id = self.tcx.hir().node_to_hir_id(item.id); self.dumper.dump_def( - &access_from!(self.save_ctxt, item), + &access_from!(self.save_ctxt, item, hir_id), Def { kind: DefKind::Type, id, @@ -1509,7 +1531,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc self.process_macro_use(ex.span); match ex.node { ast::ExprKind::Struct(ref path, ref fields, ref base) => { - let hir_expr = self.save_ctxt.tcx.hir().expect_expr(ex.id); + let expr_hir_id = self.save_ctxt.tcx.hir().node_to_hir_id(ex.id); + let hir_expr = self.save_ctxt.tcx.hir().expect_expr(expr_hir_id); let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) { Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(), _ => { @@ -1518,8 +1541,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc } }; let node_id = self.save_ctxt.tcx.hir().hir_to_node_id(hir_expr.hir_id); - let def = self.save_ctxt.get_path_def(node_id); - self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base) + let res = self.save_ctxt.get_path_res(node_id); + self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), base) } ast::ExprKind::MethodCall(ref seg, ref args) => self.process_method_call(ex, seg, args), ast::ExprKind::Field(ref sub_ex, _) => { @@ -1557,17 +1580,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc self.visit_expr(subexpression); visit::walk_block(self, block); } - ast::ExprKind::WhileLet(ref pats, ref subexpression, ref block, _) => { + ast::ExprKind::Let(ref pats, ref scrutinee) => { self.process_var_decl_multi(pats); - debug!("for loop, walk sub-expr: {:?}", subexpression.node); - self.visit_expr(subexpression); - visit::walk_block(self, block); - } - ast::ExprKind::IfLet(ref pats, ref subexpression, ref block, ref opt_else) => { - self.process_var_decl_multi(pats); - self.visit_expr(subexpression); - visit::walk_block(self, block); - opt_else.as_ref().map(|el| self.visit_expr(el)); + self.visit_expr(scrutinee); } ast::ExprKind::Repeat(ref element, ref count) => { self.visit_expr(element); @@ -1594,9 +1609,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc fn visit_arm(&mut self, arm: &'l ast::Arm) { self.process_var_decl_multi(&arm.pats); - match arm.guard { - Some(ast::Guard::If(ref expr)) => self.visit_expr(expr), - _ => {} + if let Some(expr) = &arm.guard { + self.visit_expr(expr); } self.visit_expr(&arm.body); } @@ -1624,7 +1638,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc } fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) { - let access = access_from!(self.save_ctxt, item); + let hir_id = self.tcx.hir().node_to_hir_id(item.id); + let access = access_from!(self.save_ctxt, item, hir_id); match item.node { ast::ForeignItemKind::Fn(ref decl, ref generics) => { diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 1840cf652e1d5..82b78369e1339 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -1,7 +1,5 @@ use std::io::Write; -use rustc_serialize::json::as_json; - use rls_data::config::Config; use rls_data::{self, Analysis, CompilationOptions, CratePreludeData, Def, DefKind, Impl, Import, MacroRef, Ref, RefKind, Relation}; @@ -31,8 +29,8 @@ pub struct WriteOutput<'b, W: Write> { impl<'b, W: Write> DumpOutput for WriteOutput<'b, W> { fn dump(&mut self, result: &Analysis) { - if write!(self.output, "{}", as_json(&result)).is_err() { - error!("Error writing output"); + if let Err(e) = serde_json::to_writer(self.output.by_ref(), result) { + error!("Can't serialize save-analysis: {:?}", e); } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index af3f54187b0c3..ab82f75f74f4b 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -1,7 +1,8 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(custom_attribute)] #![feature(nll)] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] #![allow(unused_attributes)] #![recursion_limit="256"] @@ -14,22 +15,21 @@ mod span_utils; mod sig; use rustc::hir; -use rustc::hir::def::Def as HirDef; +use rustc::hir::def::{CtorOf, Res, DefKind as HirDefKind}; use rustc::hir::Node; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::middle::privacy::AccessLevels; use rustc::middle::cstore::ExternCrate; use rustc::session::config::{CrateType, Input, OutputType}; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, DefIdTree, TyCtxt}; use rustc::{bug, span_bug}; -use rustc_typeck::hir_ty_to_ty; use rustc_codegen_utils::link::{filename_for_metadata, out_filename}; -use rustc_data_structures::sync::Lrc; use std::cell::Cell; use std::default::Default; use std::env; use std::fs::File; +use std::io::BufWriter; use std::path::{Path, PathBuf}; use syntax::ast::{self, Attribute, DUMMY_NODE_ID, NodeId, PatKind}; @@ -52,8 +52,8 @@ use rls_data::config::Config; use log::{debug, error, info}; -pub struct SaveContext<'l, 'tcx: 'l> { - tcx: TyCtxt<'l, 'tcx, 'tcx>, +pub struct SaveContext<'l, 'tcx> { + tcx: TyCtxt<'tcx>, tables: &'l ty::TypeckTables<'tcx>, access_levels: &'l AccessLevels, span_utils: SpanUtils<'tcx>, @@ -68,7 +68,7 @@ pub enum Data { RelationData(Relation, Impl), } -impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { +impl<'l, 'tcx> SaveContext<'l, 'tcx> { fn span_from_span(&self, span: Span) -> SpanData { use rls_span::{Column, Row}; @@ -110,8 +110,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let mut result = Vec::with_capacity(self.tcx.crates().len()); for &n in self.tcx.crates().iter() { - let span = match *self.tcx.extern_crate(n.as_def_id()) { - Some(ExternCrate { span, .. }) => span, + let span = match self.tcx.extern_crate(n.as_def_id()) { + Some(&ExternCrate { span, .. }) => span, None => { debug!("Skipping crate {}, no data", n); continue; @@ -134,7 +134,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } pub fn get_extern_item_data(&self, item: &ast::ForeignItem) -> Option { - let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + let qualname = format!("::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id))); match item.node { ast::ForeignItemKind::Fn(ref decl, ref generics) => { filter!(self.span_utils, item.ident.span); @@ -184,7 +185,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_item_data(&self, item: &ast::Item) -> Option { match item.node { ast::ItemKind::Fn(ref decl, .., ref generics, _) => { - let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + let qualname = format!("::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id))); filter!(self.span_utils, item.ident.span); Some(Data::DefData(Def { kind: DefKind::Function, @@ -202,7 +204,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { })) } ast::ItemKind::Static(ref typ, ..) => { - let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + let qualname = format!("::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id))); filter!(self.span_utils, item.ident.span); @@ -225,7 +228,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { })) } ast::ItemKind::Const(ref typ, _) => { - let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + let qualname = format!("::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id))); filter!(self.span_utils, item.ident.span); let id = id_from_node_id(item.id, self); @@ -247,7 +251,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { })) } ast::ItemKind::Mod(ref m) => { - let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + let qualname = format!("::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id))); let cm = self.tcx.sess.source_map(); let filename = cm.span_to_filename(m.inner); @@ -274,7 +279,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } ast::ItemKind::Enum(ref def, _) => { let name = item.ident.to_string(); - let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + let qualname = format!("::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(item.id))); filter!(self.span_utils, item.ident.span); let variants_str = def.variants .iter() @@ -292,7 +298,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { parent: None, children: def.variants .iter() - .map(|v| id_from_node_id(v.node.data.id(), self)) + .map(|v| id_from_node_id(v.node.id, self)) .collect(), decl_id: None, docs: self.docs_for_attrs(&item.attrs), @@ -358,7 +364,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_field_data(&self, field: &ast::StructField, scope: NodeId) -> Option { if let Some(ident) = field.ident { let name = ident.to_string(); - let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident); + let qualname = format!("::{}::{}", + self.tcx.def_path_str(self.tcx.hir().local_def_id(scope)), + ident); filter!(self.span_utils, ident.span); let def_id = self.tcx.hir().local_def_id(field.id); let typ = self.tcx.type_of(def_id).to_string(); @@ -403,7 +411,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let mut decl_id = None; let mut docs = String::new(); let mut attrs = vec![]; - if let Some(Node::ImplItem(item)) = self.tcx.hir().find(id) { + let hir_id = self.tcx.hir().node_to_hir_id(id); + if let Some(Node::ImplItem(item)) = + self.tcx.hir().find(hir_id) + { docs = self.docs_for_attrs(&item.attrs); attrs = item.attrs.to_vec(); } @@ -411,7 +422,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { if let Some(def_id) = trait_id { // A method in a trait impl. qualname.push_str(" as "); - qualname.push_str(&self.tcx.item_path_str(def_id)); + qualname.push_str(&self.tcx.def_path_str(def_id)); self.tcx .associated_items(def_id) .find(|item| item.ident.name == ident.name) @@ -444,14 +455,15 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Some(def_id) => { let mut docs = String::new(); let mut attrs = vec![]; + let hir_id = self.tcx.hir().node_to_hir_id(id); - if let Some(Node::TraitItem(item)) = self.tcx.hir().find(id) { + if let Some(Node::TraitItem(item)) = self.tcx.hir().find(hir_id) { docs = self.docs_for_attrs(&item.attrs); attrs = item.attrs.to_vec(); } ( - format!("::{}", self.tcx.item_path_str(def_id)), + format!("::{}", self.tcx.def_path_str(def_id)), Some(def_id), None, docs, @@ -506,14 +518,16 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } pub fn get_expr_data(&self, expr: &ast::Expr) -> Option { - let hir_node = self.tcx.hir().expect_expr(expr.id); + let expr_hir_id = self.tcx.hir().node_to_hir_id(expr.id); + let hir_node = self.tcx.hir().expect_expr(expr_hir_id); let ty = self.tables.expr_ty_adjusted_opt(&hir_node); if ty.is_none() || ty.unwrap().sty == ty::Error { return None; } match expr.node { ast::ExprKind::Field(ref sub_ex, ident) => { - let hir_node = match self.tcx.hir().find(sub_ex.id) { + let sub_ex_hir_id = self.tcx.hir().node_to_hir_id(sub_ex.id); + let hir_node = match self.tcx.hir().find(sub_ex_hir_id) { Some(Node::Expr(expr)) => expr, _ => { debug!( @@ -565,8 +579,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } ast::ExprKind::MethodCall(ref seg, ..) => { let expr_hir_id = self.tcx.hir().definitions().node_to_hir_id(expr.id); - let method_id = match self.tables.type_dependent_defs().get(expr_hir_id) { - Some(id) => id.def_id(), + let method_id = match self.tables.type_dependent_def_id(expr_hir_id) { + Some(id) => id, None => { debug!("Could not resolve method id for {:?}", expr); return None; @@ -598,21 +612,25 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } - pub fn get_path_def(&self, id: NodeId) -> HirDef { - match self.tcx.hir().get(id) { - Node::TraitRef(tr) => tr.path.def, + pub fn get_path_res(&self, id: NodeId) -> Res { + let hir_id = self.tcx.hir().node_to_hir_id(id); + match self.tcx.hir().get(hir_id) { + Node::TraitRef(tr) => tr.path.res, Node::Item(&hir::Item { node: hir::ItemKind::Use(ref path, _), .. }) | Node::Visibility(&Spanned { - node: hir::VisibilityKind::Restricted { ref path, .. }, .. }) => path.def, + node: hir::VisibilityKind::Restricted { ref path, .. }, .. }) => path.res, Node::PathSegment(seg) => { - match seg.def { - Some(def) if def != HirDef::Err => def, - _ => self.get_path_def(self.tcx.hir().get_parent_node(id)), + match seg.res { + Some(res) if res != Res::Err => res, + _ => { + let parent_node = self.tcx.hir().get_parent_node(hir_id); + self.get_path_res(self.tcx.hir().hir_to_node_id(parent_node)) + }, } } @@ -620,8 +638,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { node: hir::ExprKind::Struct(ref qpath, ..), .. }) => { - let hir_id = self.tcx.hir().node_to_hir_id(id); - self.tables.qpath_def(qpath, hir_id) + self.tables.qpath_res(qpath, hir_id) } Node::Expr(&hir::Expr { @@ -639,36 +656,20 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Node::Pat(&hir::Pat { node: hir::PatKind::TupleStruct(ref qpath, ..), .. + }) | + Node::Ty(&hir::Ty { + node: hir::TyKind::Path(ref qpath), + .. }) => { - let hir_id = self.tcx.hir().node_to_hir_id(id); - self.tables.qpath_def(qpath, hir_id) + self.tables.qpath_res(qpath, hir_id) } Node::Binding(&hir::Pat { node: hir::PatKind::Binding(_, canonical_id, ..), .. - }) => HirDef::Local(canonical_id), + }) => Res::Local(canonical_id), - Node::Ty(ty) => if let hir::Ty { - node: hir::TyKind::Path(ref qpath), - .. - } = *ty - { - match *qpath { - hir::QPath::Resolved(_, ref path) => path.def, - hir::QPath::TypeRelative(..) => { - let ty = hir_ty_to_ty(self.tcx, ty); - if let ty::Projection(proj) = ty.sty { - return HirDef::AssociatedTy(proj.item_def_id); - } - HirDef::Err - } - } - } else { - HirDef::Err - }, - - _ => HirDef::Err, + _ => Res::Err, } } @@ -704,73 +705,73 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { return None; } - let def = self.get_path_def(id); + let res = self.get_path_res(id); let span = path_seg.ident.span; filter!(self.span_utils, span); let span = self.span_from_span(span); - match def { - HirDef::Upvar(id, ..) | HirDef::Local(id) => { - Some(Ref { - kind: RefKind::Variable, - span, - ref_id: id_from_node_id(id, self), - }) - } - HirDef::Static(..) | - HirDef::Const(..) | - HirDef::AssociatedConst(..) | - HirDef::VariantCtor(..) => { + match res { + Res::Local(id) => { Some(Ref { kind: RefKind::Variable, span, - ref_id: id_from_def_id(def.def_id()), + ref_id: id_from_node_id(self.tcx.hir().hir_to_node_id(id), self), }) } - HirDef::Trait(def_id) if fn_type(path_seg) => { + Res::Def(HirDefKind::Trait, def_id) if fn_type(path_seg) => { Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(def_id), }) } - HirDef::Struct(def_id) | - HirDef::Variant(def_id, ..) | - HirDef::Union(def_id) | - HirDef::Enum(def_id) | - HirDef::TyAlias(def_id) | - HirDef::ForeignTy(def_id) | - HirDef::TraitAlias(def_id) | - HirDef::AssociatedExistential(def_id) | - HirDef::AssociatedTy(def_id) | - HirDef::Trait(def_id) | - HirDef::Existential(def_id) | - HirDef::TyParam(def_id) => { + Res::Def(HirDefKind::Struct, def_id) | + Res::Def(HirDefKind::Variant, def_id) | + Res::Def(HirDefKind::Union, def_id) | + Res::Def(HirDefKind::Enum, def_id) | + Res::Def(HirDefKind::TyAlias, def_id) | + Res::Def(HirDefKind::ForeignTy, def_id) | + Res::Def(HirDefKind::TraitAlias, def_id) | + Res::Def(HirDefKind::AssocExistential, def_id) | + Res::Def(HirDefKind::AssocTy, def_id) | + Res::Def(HirDefKind::Trait, def_id) | + Res::Def(HirDefKind::Existential, def_id) | + Res::Def(HirDefKind::TyParam, def_id) => { Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(def_id), }) } - HirDef::ConstParam(def_id) => { + Res::Def(HirDefKind::ConstParam, def_id) => { Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_def_id(def_id), }) } - HirDef::StructCtor(def_id, _) => { + Res::Def(HirDefKind::Ctor(CtorOf::Struct, ..), def_id) => { // This is a reference to a tuple struct where the def_id points // to an invisible constructor function. That is not a very useful // def, so adjust to point to the tuple struct itself. - let parent_def_id = self.tcx.parent_def_id(def_id).unwrap(); + let parent_def_id = self.tcx.parent(def_id).unwrap(); Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(parent_def_id), }) } - HirDef::Method(decl_id) => { + Res::Def(HirDefKind::Static, _) | + Res::Def(HirDefKind::Const, _) | + Res::Def(HirDefKind::AssocConst, _) | + Res::Def(HirDefKind::Ctor(..), _) => { + Some(Ref { + kind: RefKind::Variable, + span, + ref_id: id_from_def_id(res.def_id()), + }) + } + Res::Def(HirDefKind::Method, decl_id) => { let def_id = if decl_id.is_local() { let ti = self.tcx.associated_item(decl_id); self.tcx @@ -787,28 +788,27 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ref_id: id_from_def_id(def_id.unwrap_or(decl_id)), }) } - HirDef::Fn(def_id) => { + Res::Def(HirDefKind::Fn, def_id) => { Some(Ref { kind: RefKind::Function, span, ref_id: id_from_def_id(def_id), }) } - HirDef::Mod(def_id) => { + Res::Def(HirDefKind::Mod, def_id) => { Some(Ref { kind: RefKind::Mod, span, ref_id: id_from_def_id(def_id), }) } - HirDef::PrimTy(..) | - HirDef::SelfTy(..) | - HirDef::Label(..) | - HirDef::Macro(..) | - HirDef::ToolMod | - HirDef::NonMacroAttr(..) | - HirDef::SelfCtor(..) | - HirDef::Err => None, + Res::PrimTy(..) | + Res::SelfTy(..) | + Res::Def(HirDefKind::Macro(..), _) | + Res::ToolMod | + Res::NonMacroAttr(..) | + Res::SelfCtor(..) | + Res::Err => None, } } @@ -877,8 +877,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } fn lookup_ref_id(&self, ref_id: NodeId) -> Option { - match self.get_path_def(ref_id) { - HirDef::PrimTy(_) | HirDef::SelfTy(..) | HirDef::Err => None, + match self.get_path_res(ref_id) { + Res::PrimTy(_) | Res::SelfTy(..) | Res::Err => None, def => Some(def.def_id()), } } @@ -887,7 +887,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let mut result = String::new(); for attr in attrs { - if attr.check_name("doc") { + if attr.check_name(sym::doc) { if let Some(val) = attr.value_str() { if attr.is_sugared_doc { result.push_str(&strip_doc_comment_decoration(&val.as_str())); @@ -897,10 +897,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result.push('\n'); } else if let Some(meta_list) = attr.meta_item_list() { meta_list.into_iter() - .filter(|it| it.check_name("include")) + .filter(|it| it.check_name(sym::include)) .filter_map(|it| it.meta_item_list().map(|l| l.to_owned())) .flat_map(|it| it) - .filter(|meta| meta.check_name("contents")) + .filter(|meta| meta.check_name(sym::contents)) .filter_map(|meta| meta.value_str()) .for_each(|val| { result.push_str(&val.as_str()); @@ -969,8 +969,8 @@ impl<'l> PathCollector<'l> { } } -impl<'l, 'a: 'l> Visitor<'a> for PathCollector<'l> { - fn visit_pat(&mut self, p: &'a ast::Pat) { +impl<'l> Visitor<'l> for PathCollector<'l> { + fn visit_pat(&mut self, p: &'l ast::Pat) { match p.node { PatKind::Struct(ref path, ..) => { self.collected_paths.push((p.id, path)); @@ -1026,7 +1026,7 @@ impl<'a> DumpHandler<'a> { } } - fn output_file(&self, ctx: &SaveContext<'_, '_>) -> File { + fn output_file(&self, ctx: &SaveContext<'_, '_>) -> (BufWriter, PathBuf) { let sess = &ctx.tcx.sess; let file_name = match ctx.config.output_file { Some(ref s) => PathBuf::from(s), @@ -1060,11 +1060,11 @@ impl<'a> DumpHandler<'a> { info!("Writing output to {}", file_name.display()); - let output_file = File::create(&file_name).unwrap_or_else( + let output_file = BufWriter::new(File::create(&file_name).unwrap_or_else( |e| sess.fatal(&format!("Could not open {}: {}", file_name.display(), e)), - ); + )); - output_file + (output_file, file_name) } } @@ -1076,13 +1076,23 @@ impl<'a> SaveHandler for DumpHandler<'a> { cratename: &str, input: &'l Input, ) { - let output = &mut self.output_file(&save_ctxt); - let mut dumper = JsonDumper::new(output, save_ctxt.config.clone()); - let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper); + let sess = &save_ctxt.tcx.sess; + let file_name = { + let (mut output, file_name) = self.output_file(&save_ctxt); + let mut dumper = JsonDumper::new(&mut output, save_ctxt.config.clone()); + let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper); - visitor.dump_crate_info(cratename, krate); - visitor.dump_compilation_options(input, cratename); - visit::walk_crate(&mut visitor, krate); + visitor.dump_crate_info(cratename, krate); + visitor.dump_compilation_options(input, cratename); + visit::walk_crate(&mut visitor, krate); + + file_name + }; + + if sess.opts.debugging_opts.emit_artifact_notifications { + sess.parse_sess.span_diagnostic + .emit_artifact_notification(&file_name, "save-analysis"); + } } } @@ -1114,7 +1124,7 @@ impl<'b> SaveHandler for CallbackHandler<'b> { } pub fn process_crate<'l, 'tcx, H: SaveHandler>( - tcx: TyCtxt<'l, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, krate: &ast::Crate, cratename: &str, input: &'l Input, @@ -1128,7 +1138,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>( // fallback in case the access levels couldn't have been correctly computed. let access_levels = match tcx.sess.compile_status() { Ok(..) => tcx.privacy_access_levels(LOCAL_CRATE), - Err(..) => Lrc::new(AccessLevels::default()), + Err(..) => tcx.arena.alloc(AccessLevels::default()), }; let save_ctxt = SaveContext { @@ -1148,10 +1158,15 @@ fn find_config(supplied: Option) -> Config { if let Some(config) = supplied { return config; } + match env::var_os("RUST_SAVE_ANALYSIS_CONFIG") { - Some(config_string) => rustc_serialize::json::decode(config_string.to_str().unwrap()) - .expect("Could not deserialize save-analysis config"), None => Config::default(), + Some(config) => config.to_str() + .ok_or(()) + .map_err(|_| error!("`RUST_SAVE_ANALYSIS_CONFIG` isn't UTF-8")) + .and_then(|cfg| serde_json::from_str(cfg) + .map_err(|_| error!("Could not deserialize save-analysis config")) + ).unwrap_or_default() } } @@ -1173,7 +1188,7 @@ fn generated_code(span: Span) -> bool { fn id_from_def_id(id: DefId) -> rls_data::Id { rls_data::Id { krate: id.krate.as_u32(), - index: id.index.as_raw_u32(), + index: id.index.as_u32(), } } @@ -1200,7 +1215,7 @@ fn null_id() -> rls_data::Id { fn lower_attributes(attrs: Vec, scx: &SaveContext<'_, '_>) -> Vec { attrs.into_iter() // Only retain real attributes. Doc comments are lowered separately. - .filter(|attr| attr.path != "doc") + .filter(|attr| attr.path != sym::doc) .map(|mut attr| { // Remove the surrounding '#[..]' or '#![..]' of the pretty printed // attribute. First normalize all inner attribute (#![..]) to outer diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 64a2c92d04dbd..db8b5eacd94d9 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -29,7 +29,7 @@ use crate::{id_from_def_id, id_from_node_id, SaveContext}; use rls_data::{SigElement, Signature}; -use rustc::hir::def::Def; +use rustc::hir::def::{Res, DefKind}; use syntax::ast::{self, NodeId}; use syntax::print::pprust; @@ -273,8 +273,8 @@ impl Sig for ast::Ty { }; let name = pprust::path_segment_to_string(path.segments.last().ok_or("Bad path")?); - let def = scx.get_path_def(id.ok_or("Missing id for Path")?); - let id = id_from_def_id(def.def_id()); + let res = scx.get_path_res(id.ok_or("Missing id for Path")?); + let id = id_from_def_id(res.def_id()); if path.segments.len() - qself.position == 1 { let start = offset + prefix.len(); let end = start + name.len(); @@ -576,17 +576,19 @@ impl Sig for ast::Item { impl Sig for ast::Path { fn make(&self, offset: usize, id: Option, scx: &SaveContext<'_, '_>) -> Result { - let def = scx.get_path_def(id.ok_or("Missing id for Path")?); + let res = scx.get_path_res(id.ok_or("Missing id for Path")?); - let (name, start, end) = match def { - Def::Label(..) | Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => { + let (name, start, end) = match res { + Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => { return Ok(Signature { text: pprust::path_to_string(self), defs: vec![], refs: vec![], }) } - Def::AssociatedConst(..) | Def::Variant(..) | Def::VariantCtor(..) => { + Res::Def(DefKind::AssocConst, _) + | Res::Def(DefKind::Variant, _) + | Res::Def(DefKind::Ctor(..), _) => { let len = self.segments.len(); if len < 2 { return Err("Bad path"); @@ -606,7 +608,7 @@ impl Sig for ast::Path { } }; - let id = id_from_def_id(def.def_id()); + let id = id_from_def_id(res.def_id()); Ok(Signature { text: name, defs: vec![], @@ -700,10 +702,11 @@ impl Sig for ast::StructField { impl Sig for ast::Variant_ { - fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext<'_, '_>) -> Result { + fn make(&self, offset: usize, parent_id: Option, scx: &SaveContext<'_, '_>) -> Result { let mut text = self.ident.to_string(); match self.data { - ast::VariantData::Struct(ref fields, id) => { + ast::VariantData::Struct(ref fields, r) => { + let id = parent_id.unwrap(); let name_def = SigElement { id: id_from_node_id(id, scx), start: offset, @@ -712,12 +715,16 @@ impl Sig for ast::Variant_ { text.push_str(" { "); let mut defs = vec![name_def]; let mut refs = vec![]; - for f in fields { - let field_sig = f.make(offset + text.len(), Some(id), scx)?; - text.push_str(&field_sig.text); - text.push_str(", "); - defs.extend(field_sig.defs.into_iter()); - refs.extend(field_sig.refs.into_iter()); + if r { + text.push_str("/* parse error */ "); + } else { + for f in fields { + let field_sig = f.make(offset + text.len(), Some(id), scx)?; + text.push_str(&field_sig.text); + text.push_str(", "); + defs.extend(field_sig.defs.into_iter()); + refs.extend(field_sig.refs.into_iter()); + } } text.push('}'); Ok(Signature { text, defs, refs }) @@ -793,7 +800,7 @@ impl Sig for ast::ForeignItem { } ast::ForeignItemKind::Static(ref ty, m) => { let mut text = "static ".to_owned(); - if m { + if m == ast::Mutability::Mutable { text.push_str("mut "); } let name = self.ident.to_string(); diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index e2c93b6d33158..8905f475647ba 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -2,25 +2,19 @@ use rustc::session::Session; use crate::generated_code; -use std::cell::Cell; - use syntax::parse::lexer::{self, StringReader}; -use syntax::parse::token::{self, Token}; +use syntax::parse::token::{self, TokenKind}; use syntax_pos::*; #[derive(Clone)] pub struct SpanUtils<'a> { pub sess: &'a Session, - // FIXME given that we clone SpanUtils all over the place, this err_count is - // probably useless and any logic relying on it is bogus. - pub err_count: Cell, } impl<'a> SpanUtils<'a> { pub fn new(sess: &'a Session) -> SpanUtils<'a> { SpanUtils { sess, - err_count: Cell::new(0), } } @@ -56,15 +50,15 @@ impl<'a> SpanUtils<'a> { lexer::StringReader::retokenize(&self.sess.parse_sess, span) } - pub fn sub_span_of_token(&self, span: Span, tok: Token) -> Option { + pub fn sub_span_of_token(&self, span: Span, tok: TokenKind) -> Option { let mut toks = self.retokenise_span(span); loop { let next = toks.real_token(); - if next.tok == token::Eof { + if next == token::Eof { return None; } - if next.tok == tok { - return Some(next.sp); + if next == tok { + return Some(next.span); } } } @@ -74,12 +68,12 @@ impl<'a> SpanUtils<'a> { // let mut toks = self.retokenise_span(span); // loop { // let ts = toks.real_token(); - // if ts.tok == token::Eof { + // if ts == token::Eof { // return None; // } - // if ts.tok == token::Not { + // if ts == token::Not { // let ts = toks.real_token(); - // if ts.tok.is_ident() { + // if ts.kind.is_ident() { // return Some(ts.sp); // } else { // return None; @@ -93,12 +87,12 @@ impl<'a> SpanUtils<'a> { // let mut toks = self.retokenise_span(span); // let mut prev = toks.real_token(); // loop { - // if prev.tok == token::Eof { + // if prev == token::Eof { // return None; // } // let ts = toks.real_token(); - // if ts.tok == token::Not { - // if prev.tok.is_ident() { + // if ts == token::Not { + // if prev.kind.is_ident() { // return Some(prev.sp); // } else { // return None; diff --git a/src/librustc_target/Cargo.toml b/src/librustc_target/Cargo.toml index ecea15a992250..3ab25146331c1 100644 --- a/src/librustc_target/Cargo.toml +++ b/src/librustc_target/Cargo.toml @@ -15,3 +15,4 @@ log = "0.4" rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } rustc_data_structures = { path = "../librustc_data_structures" } serialize = { path = "../libserialize" } +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_target/abi/call/x86_64.rs b/src/librustc_target/abi/call/x86_64.rs index 680e529b108e0..cdec65e5d40df 100644 --- a/src/librustc_target/abi/call/x86_64.rs +++ b/src/librustc_target/abi/call/x86_64.rs @@ -61,8 +61,7 @@ fn classify_arg<'a, Ty, C>(cx: &C, arg: &ArgType<'a, Ty>) } return Ok(()); } - abi::Variants::Tagged { .. } | - abi::Variants::NicheFilling { .. } => return Err(Memory), + abi::Variants::Multiple { .. } => return Err(Memory), } } @@ -168,20 +167,23 @@ fn cast_target(cls: &[Option], size: Size) -> CastTarget { target } +const MAX_INT_REGS: usize = 6; // RDI, RSI, RDX, RCX, R8, R9 +const MAX_SSE_REGS: usize = 8; // XMM0-7 + pub fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnType<'a, Ty>) where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf> + HasDataLayout { - let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9 - let mut sse_regs = 8; // XMM0-7 + let mut int_regs = MAX_INT_REGS; + let mut sse_regs = MAX_SSE_REGS; let mut x86_64_ty = |arg: &mut ArgType<'a, Ty>, is_arg: bool| { let mut cls_or_mem = classify_arg(cx, arg); - let mut needed_int = 0; - let mut needed_sse = 0; if is_arg { if let Ok(cls) = cls_or_mem { + let mut needed_int = 0; + let mut needed_sse = 0; for &c in &cls { match c { Some(Class::Int) => needed_int += 1, @@ -189,8 +191,20 @@ pub fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnType<'a, Ty>) _ => {} } } - if arg.layout.is_aggregate() && (int_regs < needed_int || sse_regs < needed_sse) { - cls_or_mem = Err(Memory); + match (int_regs.checked_sub(needed_int), sse_regs.checked_sub(needed_sse)) { + (Some(left_int), Some(left_sse)) => { + int_regs = left_int; + sse_regs = left_sse; + } + _ => { + // Not enough registers for this argument, so it will be + // passed on the stack, but we only mark aggregates + // explicitly as indirect `byval` arguments, as LLVM will + // automatically put immediates on the stack itself. + if arg.layout.is_aggregate() { + cls_or_mem = Err(Memory); + } + } } } } @@ -202,14 +216,14 @@ pub fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnType<'a, Ty>) } else { // `sret` parameter thus one less integer register available arg.make_indirect(); + // NOTE(eddyb) return is handled first, so no registers + // should've been used yet. + assert_eq!(int_regs, MAX_INT_REGS); int_regs -= 1; } } Ok(ref cls) => { // split into sized chunks passed individually - int_regs -= needed_int; - sse_regs -= needed_sse; - if arg.layout.is_aggregate() { let size = arg.layout.size; arg.cast_to(cast_target(cls, size)) diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 8b96a8c1658b2..55cb179144309 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -7,6 +7,7 @@ use std::fmt; use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use syntax_pos::symbol::{sym, Symbol}; pub mod call; @@ -135,7 +136,7 @@ impl TargetDataLayout { } if bits >= i128_align_src && bits <= 128 { // Default alignment for i128 is decided by taking the alignment of - // largest-sized i{64...128}. + // largest-sized i{64..=128}. i128_align_src = bits; dl.i128_align = a; } @@ -552,6 +553,13 @@ impl FloatTy { } } + pub fn to_symbol(self) -> Symbol { + match self { + FloatTy::F32 => sym::f32, + FloatTy::F64 => sym::f64, + } + } + pub fn bit_width(self) -> usize { match self { FloatTy::F32 => 32, @@ -575,7 +583,7 @@ pub enum Primitive { Pointer } -impl<'a, 'tcx> Primitive { +impl Primitive { pub fn size(self, cx: &C) -> Size { let dl = cx.data_layout(); @@ -691,7 +699,16 @@ pub enum FieldPlacement { offsets: Vec, /// Maps source order field indices to memory order indices, - /// depending how fields were permuted. + /// depending on how the fields were reordered (if at all). + /// This is a permutation, with both the source order and the + /// memory order using the same (0..n) index ranges. + /// + /// Note that during computation of `memory_index`, sometimes + /// it is easier to operate on the inverse mapping (that is, + /// from memory order to source order), and that is usually + /// named `inverse_memory_index`. + /// + // FIXME(eddyb) build a better abstraction for permutations, if possible. // FIXME(camlorn) also consider small vector optimization here. memory_index: Vec } @@ -828,29 +845,36 @@ pub enum Variants { index: VariantIdx, }, - /// General-case enums: for each case there is a struct, and they all have - /// all space reserved for the tag, and their first field starts - /// at a non-0 offset, after where the tag would go. - Tagged { - tag: Scalar, + /// Enum-likes with more than one inhabited variant: for each case there is + /// a struct, and they all have space reserved for the discriminant. + /// For enums this is the sole field of the layout. + Multiple { + discr: Scalar, + discr_kind: DiscriminantKind, + discr_index: usize, variants: IndexVec, }, +} - /// Multiple cases distinguished by a niche (values invalid for a type): +#[derive(PartialEq, Eq, Hash, Debug)] +pub enum DiscriminantKind { + /// Integer tag holding the discriminant value itself. + Tag, + + /// Niche (values invalid for a type) encoding the discriminant: /// the variant `dataful_variant` contains a niche at an arbitrary - /// offset (field 0 of the enum), which for a variant with discriminant - /// `d` is set to `(d - niche_variants.start).wrapping_add(niche_start)`. + /// offset (field `discr_index` of the enum), which for a variant with + /// discriminant `d` is set to + /// `(d - niche_variants.start).wrapping_add(niche_start)`. /// /// For example, `Option<(usize, &T)>` is represented such that /// `None` has a null pointer for the second tuple field, and /// `Some` is the identity function (with a non-null reference). - NicheFilling { + Niche { dataful_variant: VariantIdx, niche_variants: RangeInclusive, - niche: Scalar, niche_start: u128, - variants: IndexVec, - } + }, } #[derive(PartialEq, Eq, Hash, Debug)] @@ -903,6 +927,28 @@ pub trait LayoutOf { fn layout_of(&self, ty: Self::Ty) -> Self::TyLayout; } +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum PointerKind { + /// Most general case, we know no restrictions to tell LLVM. + Shared, + + /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`. + Frozen, + + /// `&mut T`, when we know `noalias` is safe for LLVM. + UniqueBorrowed, + + /// `Box`, unlike `UniqueBorrowed`, it also has `noalias` on returns. + UniqueOwned +} + +#[derive(Copy, Clone)] +pub struct PointeeInfo { + pub size: Size, + pub align: Align, + pub safe: Option, +} + pub trait TyLayoutMethods<'a, C: LayoutOf>: Sized { fn for_variant( this: TyLayout<'a, Self>, @@ -910,6 +956,11 @@ pub trait TyLayoutMethods<'a, C: LayoutOf>: Sized { variant_index: VariantIdx, ) -> TyLayout<'a, Self>; fn field(this: TyLayout<'a, Self>, cx: &C, i: usize) -> C::TyLayout; + fn pointee_info_at( + this: TyLayout<'a, Self>, + cx: &C, + offset: Size, + ) -> Option; } impl<'a, Ty> TyLayout<'a, Ty> { @@ -921,6 +972,10 @@ impl<'a, Ty> TyLayout<'a, Ty> { where Ty: TyLayoutMethods<'a, C>, C: LayoutOf { Ty::field(self, cx, i) } + pub fn pointee_info_at(self, cx: &C, offset: Size) -> Option + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf { + Ty::pointee_info_at(self, cx, offset) + } } impl<'a, Ty> TyLayout<'a, Ty> { diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index efffb1985728d..1bebe420251fd 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -16,6 +16,8 @@ #![feature(step_trait)] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] #[macro_use] extern crate log; diff --git a/src/librustc_target/spec/aarch64_unknown_linux_gnu.rs b/src/librustc_target/spec/aarch64_unknown_linux_gnu.rs index e772d8b532cb0..b9d36c09f1636 100644 --- a/src/librustc_target/spec/aarch64_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/aarch64_unknown_linux_gnu.rs @@ -17,6 +17,7 @@ pub fn target() -> TargetResult { linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "\u{1}_mcount".to_string(), .. base }, }) diff --git a/src/librustc_target/spec/aarch64_unknown_linux_musl.rs b/src/librustc_target/spec/aarch64_unknown_linux_musl.rs index 8123ee82ed524..968e82ca39fbe 100644 --- a/src/librustc_target/spec/aarch64_unknown_linux_musl.rs +++ b/src/librustc_target/spec/aarch64_unknown_linux_musl.rs @@ -17,6 +17,7 @@ pub fn target() -> TargetResult { linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "\u{1}_mcount".to_string(), .. base }, }) diff --git a/src/librustc_target/spec/aarch64_unknown_netbsd.rs b/src/librustc_target/spec/aarch64_unknown_netbsd.rs index 47ae08ade9a6b..455cbebb91e28 100644 --- a/src/librustc_target/spec/aarch64_unknown_netbsd.rs +++ b/src/librustc_target/spec/aarch64_unknown_netbsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); @@ -16,6 +16,9 @@ pub fn target() -> TargetResult { target_env: String::new(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "__mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/apple_base.rs b/src/librustc_target/spec/apple_base.rs index c21f7f38ca5a3..53364e72bfe3a 100644 --- a/src/librustc_target/spec/apple_base.rs +++ b/src/librustc_target/spec/apple_base.rs @@ -14,13 +14,7 @@ pub fn opts() -> TargetOptions { // // Here we detect what version is being requested, defaulting to 10.7. ELF // TLS is flagged as enabled if it looks to be supported. - let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok(); - let version = deployment_target.as_ref().and_then(|s| { - let mut i = s.splitn(2, '.'); - i.next().and_then(|a| i.next().map(|b| (a, b))) - }).and_then(|(a, b)| { - a.parse::().and_then(|a| b.parse::().map(|b| (a, b))).ok() - }).unwrap_or((10, 7)); + let version = macos_deployment_target(); TargetOptions { // macOS has -dead_strip, which doesn't rely on function_sections @@ -40,3 +34,20 @@ pub fn opts() -> TargetOptions { .. Default::default() } } + +fn macos_deployment_target() -> (u32, u32) { + let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok(); + let version = deployment_target.as_ref().and_then(|s| { + let mut i = s.splitn(2, '.'); + i.next().and_then(|a| i.next().map(|b| (a, b))) + }).and_then(|(a, b)| { + a.parse::().and_then(|a| b.parse::().map(|b| (a, b))).ok() + }); + + version.unwrap_or((10, 7)) +} + +pub fn macos_llvm_target(arch: &str) -> String { + let (major, minor) = macos_deployment_target(); + format!("{}-apple-macosx{}.{}.0", arch, major, minor) +} diff --git a/src/librustc_target/spec/arm_unknown_linux_gnueabi.rs b/src/librustc_target/spec/arm_unknown_linux_gnueabi.rs index f291818ba80f5..2f835420148fe 100644 --- a/src/librustc_target/spec/arm_unknown_linux_gnueabi.rs +++ b/src/librustc_target/spec/arm_unknown_linux_gnueabi.rs @@ -18,6 +18,7 @@ pub fn target() -> TargetResult { options: TargetOptions { features: "+strict-align,+v6".to_string(), abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "\u{1}__gnu_mcount_nc".to_string(), .. base }, }) diff --git a/src/librustc_target/spec/arm_unknown_linux_gnueabihf.rs b/src/librustc_target/spec/arm_unknown_linux_gnueabihf.rs index 32b509d9721ef..cd4b2e1c92252 100644 --- a/src/librustc_target/spec/arm_unknown_linux_gnueabihf.rs +++ b/src/librustc_target/spec/arm_unknown_linux_gnueabihf.rs @@ -18,6 +18,7 @@ pub fn target() -> TargetResult { options: TargetOptions { features: "+strict-align,+v6,+vfp2".to_string(), abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "\u{1}__gnu_mcount_nc".to_string(), .. base } }) diff --git a/src/librustc_target/spec/arm_unknown_linux_musleabi.rs b/src/librustc_target/spec/arm_unknown_linux_musleabi.rs index 7637577e7e848..606c3f1906031 100644 --- a/src/librustc_target/spec/arm_unknown_linux_musleabi.rs +++ b/src/librustc_target/spec/arm_unknown_linux_musleabi.rs @@ -23,6 +23,7 @@ pub fn target() -> TargetResult { linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "\u{1}mcount".to_string(), .. base }, }) diff --git a/src/librustc_target/spec/arm_unknown_linux_musleabihf.rs b/src/librustc_target/spec/arm_unknown_linux_musleabihf.rs index 9def151b3ef29..d22156bc328e0 100644 --- a/src/librustc_target/spec/arm_unknown_linux_musleabihf.rs +++ b/src/librustc_target/spec/arm_unknown_linux_musleabihf.rs @@ -23,6 +23,7 @@ pub fn target() -> TargetResult { linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "\u{1}mcount".to_string(), .. base }, }) diff --git a/src/librustc_target/spec/armv4t_unknown_linux_gnueabi.rs b/src/librustc_target/spec/armv4t_unknown_linux_gnueabi.rs index 7cd4b14cdebc8..e7da24843cc05 100644 --- a/src/librustc_target/spec/armv4t_unknown_linux_gnueabi.rs +++ b/src/librustc_target/spec/armv4t_unknown_linux_gnueabi.rs @@ -19,6 +19,7 @@ pub fn target() -> TargetResult { // Atomic operations provided by compiler-builtins max_atomic_width: Some(32), abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "\u{1}__gnu_mcount_nc".to_string(), .. base } }) diff --git a/src/librustc_target/spec/armv5te_unknown_linux_gnueabi.rs b/src/librustc_target/spec/armv5te_unknown_linux_gnueabi.rs index 15f614827718b..ea586f42c269e 100644 --- a/src/librustc_target/spec/armv5te_unknown_linux_gnueabi.rs +++ b/src/librustc_target/spec/armv5te_unknown_linux_gnueabi.rs @@ -19,6 +19,7 @@ pub fn target() -> TargetResult { // Atomic operations provided by compiler-builtins max_atomic_width: Some(32), abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "\u{1}__gnu_mcount_nc".to_string(), .. base } }) diff --git a/src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs b/src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs index 74915b942ea4f..dae5c8c3d7504 100644 --- a/src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs +++ b/src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs @@ -22,6 +22,7 @@ pub fn target() -> TargetResult { // Atomic operations provided by compiler-builtins max_atomic_width: Some(32), abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "\u{1}mcount".to_string(), .. base } }) diff --git a/src/librustc_target/spec/armv6_unknown_freebsd.rs b/src/librustc_target/spec/armv6_unknown_freebsd.rs new file mode 100644 index 0000000000000..a90590a39e75e --- /dev/null +++ b/src/librustc_target/spec/armv6_unknown_freebsd.rs @@ -0,0 +1,25 @@ +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + let base = super::freebsd_base::opts(); + Ok(Target { + llvm_target: "armv6-unknown-freebsd-gnueabihf".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "freebsd".to_string(), + target_env: "gnueabihf".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + + options: TargetOptions { + features: "+v6,+vfp2".to_string(), + max_atomic_width: Some(64), + abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "\u{1}__gnu_mcount_nc".to_string(), + .. base + } + }) +} diff --git a/src/librustc_target/spec/armv6_unknown_netbsd_eabihf.rs b/src/librustc_target/spec/armv6_unknown_netbsd_eabihf.rs index e460b6c574a26..b056776bdfb8b 100644 --- a/src/librustc_target/spec/armv6_unknown_netbsd_eabihf.rs +++ b/src/librustc_target/spec/armv6_unknown_netbsd_eabihf.rs @@ -18,6 +18,7 @@ pub fn target() -> TargetResult { options: TargetOptions { features: "+v6,+vfp2".to_string(), abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "__mcount".to_string(), .. base } }) diff --git a/src/librustc_target/spec/armv7_unknown_cloudabi_eabihf.rs b/src/librustc_target/spec/armv7_unknown_cloudabi_eabihf.rs index a6c7fb537c785..c03f4b544ed0b 100644 --- a/src/librustc_target/spec/armv7_unknown_cloudabi_eabihf.rs +++ b/src/librustc_target/spec/armv7_unknown_cloudabi_eabihf.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::cloudabi_base::opts(); @@ -19,6 +19,9 @@ pub fn target() -> TargetResult { target_env: String::new(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "\u{1}mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/armv7_unknown_freebsd.rs b/src/librustc_target/spec/armv7_unknown_freebsd.rs new file mode 100644 index 0000000000000..ca7ab474bef88 --- /dev/null +++ b/src/librustc_target/spec/armv7_unknown_freebsd.rs @@ -0,0 +1,25 @@ +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + let base = super::freebsd_base::opts(); + Ok(Target { + llvm_target: "armv7-unknown-freebsd-gnueabihf".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "freebsd".to_string(), + target_env: "gnueabihf".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + + options: TargetOptions { + features: "+v7,+vfp3,+d16,+thumb2,-neon".to_string(), + max_atomic_width: Some(64), + abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "\u{1}__gnu_mcount_nc".to_string(), + .. base + } + }) +} diff --git a/src/librustc_target/spec/armv7_unknown_linux_gnueabihf.rs b/src/librustc_target/spec/armv7_unknown_linux_gnueabihf.rs index f16215433c766..f0952cccb2087 100644 --- a/src/librustc_target/spec/armv7_unknown_linux_gnueabihf.rs +++ b/src/librustc_target/spec/armv7_unknown_linux_gnueabihf.rs @@ -23,6 +23,7 @@ pub fn target() -> TargetResult { cpu: "generic".to_string(), max_atomic_width: Some(64), abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "\u{1}__gnu_mcount_nc".to_string(), .. base } }) diff --git a/src/librustc_target/spec/armv7_unknown_linux_musleabihf.rs b/src/librustc_target/spec/armv7_unknown_linux_musleabihf.rs index 45a26966b716b..a9974f6b80c93 100644 --- a/src/librustc_target/spec/armv7_unknown_linux_musleabihf.rs +++ b/src/librustc_target/spec/armv7_unknown_linux_musleabihf.rs @@ -26,6 +26,7 @@ pub fn target() -> TargetResult { cpu: "generic".to_string(), max_atomic_width: Some(64), abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "\u{1}mcount".to_string(), .. base } }) diff --git a/src/librustc_target/spec/armv7_unknown_netbsd_eabihf.rs b/src/librustc_target/spec/armv7_unknown_netbsd_eabihf.rs index 44e2636e9188e..e2d55e9317b76 100644 --- a/src/librustc_target/spec/armv7_unknown_netbsd_eabihf.rs +++ b/src/librustc_target/spec/armv7_unknown_netbsd_eabihf.rs @@ -19,6 +19,7 @@ pub fn target() -> TargetResult { cpu: "generic".to_string(), max_atomic_width: Some(64), abi_blacklist: super::arm_base::abi_blacklist(), + target_mcount: "__mcount".to_string(), .. base } }) diff --git a/src/librustc_target/spec/bitrig_base.rs b/src/librustc_target/spec/bitrig_base.rs deleted file mode 100644 index 9b34119fc00c9..0000000000000 --- a/src/librustc_target/spec/bitrig_base.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::spec::{TargetOptions, RelroLevel}; -use std::default::Default; - -pub fn opts() -> TargetOptions { - TargetOptions { - dynamic_linking: true, - executables: true, - target_family: Some("unix".to_string()), - linker_is_gnu: true, - has_rpath: true, - position_independent_executables: true, - relro_level: RelroLevel::Full, - - .. Default::default() - } -} diff --git a/src/librustc_target/spec/fuchsia_base.rs b/src/librustc_target/spec/fuchsia_base.rs index 4e4f2fa0cf34c..48749dff941ac 100644 --- a/src/librustc_target/spec/fuchsia_base.rs +++ b/src/librustc_target/spec/fuchsia_base.rs @@ -19,7 +19,7 @@ pub fn opts() -> TargetOptions { is_like_fuchsia: true, linker_is_gnu: true, has_rpath: false, - pre_link_args: pre_link_args, + pre_link_args, pre_link_objects_exe: vec![ "Scrt1.o".to_string() ], diff --git a/src/librustc_target/spec/i686_apple_darwin.rs b/src/librustc_target/spec/i686_apple_darwin.rs index c8a61296d33d2..7d804ea53fb31 100644 --- a/src/librustc_target/spec/i686_apple_darwin.rs +++ b/src/librustc_target/spec/i686_apple_darwin.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::apple_base::opts(); @@ -8,8 +8,14 @@ pub fn target() -> TargetResult { base.stack_probes = true; base.eliminate_frame_pointer = false; + // Clang automatically chooses a more specific target based on + // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work + // correctly, we do too. + let arch = "i686"; + let llvm_target = super::apple_base::macos_llvm_target(&arch); + Ok(Target { - llvm_target: "i686-apple-darwin".to_string(), + llvm_target: llvm_target, target_endian: "little".to_string(), target_pointer_width: "32".to_string(), target_c_int_width: "32".to_string(), @@ -19,6 +25,9 @@ pub fn target() -> TargetResult { target_env: String::new(), target_vendor: "apple".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "\u{1}mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/i686_unknown_netbsd.rs b/src/librustc_target/spec/i686_unknown_netbsd.rs index e8a9f29ea5f4c..99130e93dad61 100644 --- a/src/librustc_target/spec/i686_unknown_netbsd.rs +++ b/src/librustc_target/spec/i686_unknown_netbsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); @@ -18,6 +18,9 @@ pub fn target() -> TargetResult { target_env: String::new(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "__mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/mips64_unknown_linux_gnuabi64.rs b/src/librustc_target/spec/mips64_unknown_linux_gnuabi64.rs index 3b38e64050f3b..b2ea8a6f38814 100644 --- a/src/librustc_target/spec/mips64_unknown_linux_gnuabi64.rs +++ b/src/librustc_target/spec/mips64_unknown_linux_gnuabi64.rs @@ -17,6 +17,7 @@ pub fn target() -> TargetResult { cpu: "mips64r2".to_string(), features: "+mips64r2".to_string(), max_atomic_width: Some(64), + target_mcount: "_mcount".to_string(), ..super::linux_base::opts() }, diff --git a/src/librustc_target/spec/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_target/spec/mips64el_unknown_linux_gnuabi64.rs index 0f6cd86d616d8..48aea4a39b0a4 100644 --- a/src/librustc_target/spec/mips64el_unknown_linux_gnuabi64.rs +++ b/src/librustc_target/spec/mips64el_unknown_linux_gnuabi64.rs @@ -17,6 +17,7 @@ pub fn target() -> TargetResult { cpu: "mips64r2".to_string(), features: "+mips64r2".to_string(), max_atomic_width: Some(64), + target_mcount: "_mcount".to_string(), ..super::linux_base::opts() }, diff --git a/src/librustc_target/spec/mips_unknown_linux_gnu.rs b/src/librustc_target/spec/mips_unknown_linux_gnu.rs index b4d29c5fbeaf4..e360abdb38d3f 100644 --- a/src/librustc_target/spec/mips_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/mips_unknown_linux_gnu.rs @@ -16,6 +16,7 @@ pub fn target() -> TargetResult { cpu: "mips32r2".to_string(), features: "+mips32r2,+fpxx,+nooddspreg".to_string(), max_atomic_width: Some(32), + target_mcount: "_mcount".to_string(), ..super::linux_base::opts() }, diff --git a/src/librustc_target/spec/mips_unknown_linux_musl.rs b/src/librustc_target/spec/mips_unknown_linux_musl.rs index c56c6e3822959..3f5428de95074 100644 --- a/src/librustc_target/spec/mips_unknown_linux_musl.rs +++ b/src/librustc_target/spec/mips_unknown_linux_musl.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); @@ -17,6 +17,9 @@ pub fn target() -> TargetResult { target_env: "musl".to_string(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "_mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/mips_unknown_linux_uclibc.rs b/src/librustc_target/spec/mips_unknown_linux_uclibc.rs index cb02769c7dfe4..8116b8c9cc840 100644 --- a/src/librustc_target/spec/mips_unknown_linux_uclibc.rs +++ b/src/librustc_target/spec/mips_unknown_linux_uclibc.rs @@ -16,6 +16,7 @@ pub fn target() -> TargetResult { cpu: "mips32r2".to_string(), features: "+mips32r2,+soft-float".to_string(), max_atomic_width: Some(32), + target_mcount: "_mcount".to_string(), ..super::linux_base::opts() }, diff --git a/src/librustc_target/spec/mipsel_unknown_linux_gnu.rs b/src/librustc_target/spec/mipsel_unknown_linux_gnu.rs index ed49ddd49937f..7e9d8cd942a23 100644 --- a/src/librustc_target/spec/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/mipsel_unknown_linux_gnu.rs @@ -17,6 +17,7 @@ pub fn target() -> TargetResult { cpu: "mips32r2".to_string(), features: "+mips32r2,+fpxx,+nooddspreg".to_string(), max_atomic_width: Some(32), + target_mcount: "_mcount".to_string(), ..super::linux_base::opts() }, diff --git a/src/librustc_target/spec/mipsel_unknown_linux_musl.rs b/src/librustc_target/spec/mipsel_unknown_linux_musl.rs index bcc49cf5ffe4f..56ad2940feba8 100644 --- a/src/librustc_target/spec/mipsel_unknown_linux_musl.rs +++ b/src/librustc_target/spec/mipsel_unknown_linux_musl.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); @@ -17,6 +17,9 @@ pub fn target() -> TargetResult { target_env: "musl".to_string(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "_mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/mipsel_unknown_linux_uclibc.rs b/src/librustc_target/spec/mipsel_unknown_linux_uclibc.rs index 205f328a24cec..a8152011efa79 100644 --- a/src/librustc_target/spec/mipsel_unknown_linux_uclibc.rs +++ b/src/librustc_target/spec/mipsel_unknown_linux_uclibc.rs @@ -17,6 +17,7 @@ pub fn target() -> TargetResult { cpu: "mips32r2".to_string(), features: "+mips32r2,+soft-float".to_string(), max_atomic_width: Some(32), + target_mcount: "_mcount".to_string(), ..super::linux_base::opts() }, diff --git a/src/librustc_target/spec/mipsisa32r6_unknown_linux_gnu.rs b/src/librustc_target/spec/mipsisa32r6_unknown_linux_gnu.rs new file mode 100644 index 0000000000000..36b83c63fca28 --- /dev/null +++ b/src/librustc_target/spec/mipsisa32r6_unknown_linux_gnu.rs @@ -0,0 +1,24 @@ +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mipsisa32r6-unknown-linux-gnu".to_string(), + target_endian: "big".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), + arch: "mips".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: TargetOptions { + cpu: "mips32r6".to_string(), + features: "+mips32r6".to_string(), + max_atomic_width: Some(32), + target_mcount: "_mcount".to_string(), + + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_target/spec/mipsisa32r6el_unknown_linux_gnu.rs b/src/librustc_target/spec/mipsisa32r6el_unknown_linux_gnu.rs new file mode 100644 index 0000000000000..717ae3f1d20e1 --- /dev/null +++ b/src/librustc_target/spec/mipsisa32r6el_unknown_linux_gnu.rs @@ -0,0 +1,25 @@ +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mipsisa32r6el-unknown-linux-gnu".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), + arch: "mips".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + + options: TargetOptions { + cpu: "mips32r6".to_string(), + features: "+mips32r6".to_string(), + max_atomic_width: Some(32), + target_mcount: "_mcount".to_string(), + + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_target/spec/mipsisa64r6_unknown_linux_gnuabi64.rs b/src/librustc_target/spec/mipsisa64r6_unknown_linux_gnuabi64.rs new file mode 100644 index 0000000000000..3f7d233e55fbc --- /dev/null +++ b/src/librustc_target/spec/mipsisa64r6_unknown_linux_gnuabi64.rs @@ -0,0 +1,25 @@ +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mipsisa64r6-unknown-linux-gnuabi64".to_string(), + target_endian: "big".to_string(), + target_pointer_width: "64".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), + arch: "mips64".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: TargetOptions { + // NOTE(mips64r6) matches C toolchain + cpu: "mips64r6".to_string(), + features: "+mips64r6".to_string(), + max_atomic_width: Some(64), + target_mcount: "_mcount".to_string(), + + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_target/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs b/src/librustc_target/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs new file mode 100644 index 0000000000000..4f41b8323a99a --- /dev/null +++ b/src/librustc_target/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs @@ -0,0 +1,25 @@ +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mipsisa64r6el-unknown-linux-gnuabi64".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), + arch: "mips64".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: TargetOptions { + // NOTE(mips64r6) matches C toolchain + cpu: "mips64r6".to_string(), + features: "+mips64r6".to_string(), + max_atomic_width: Some(64), + target_mcount: "_mcount".to_string(), + + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index a7edb4403d1bd..e978cfbc8914e 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -47,7 +47,6 @@ mod android_base; mod apple_base; mod apple_ios_base; mod arm_base; -mod bitrig_base; mod cloudabi_base; mod dragonfly_base; mod freebsd_base; @@ -66,6 +65,7 @@ mod l4re_base; mod fuchsia_base; mod redox_base; mod riscv_base; +mod wasm32_base; #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, RustcEncodable, RustcDecodable)] @@ -119,19 +119,19 @@ macro_rules! flavor_mappings { ($((($($flavor:tt)*), $string:expr),)*) => ( impl LinkerFlavor { pub const fn one_of() -> &'static str { - concat!("one of: ", $($string, " ",)+) + concat!("one of: ", $($string, " ",)*) } pub fn from_str(s: &str) -> Option { Some(match s { - $($string => $($flavor)*,)+ + $($string => $($flavor)*,)* _ => return None, }) } pub fn desc(&self) -> &str { match *self { - $($($flavor)* => $string,)+ + $($($flavor)* => $string,)* } } } @@ -268,16 +268,16 @@ pub type LinkArgs = BTreeMap>; pub type TargetResult = Result; macro_rules! supported_targets { - ( $(($triple:expr, $module:ident),)+ ) => ( - $(mod $module;)* + ( $(($( $triple:literal, )+ $module:ident ),)+ ) => { + $(mod $module;)+ /// List of supported targets - const TARGETS: &[&str] = &[$($triple),*]; + const TARGETS: &[&str] = &[$($($triple),+),+]; fn load_specific(target: &str) -> Result { match target { $( - $triple => { + $($triple)|+ => { let mut t = $module::target() .map_err(LoadTargetError::Other)?; t.options.is_builtin = true; @@ -307,7 +307,7 @@ macro_rules! supported_targets { mod test_json_encode_decode { use serialize::json::ToJson; use super::Target; - $(use super::$module;)* + $(use super::$module;)+ $( #[test] @@ -322,9 +322,9 @@ macro_rules! supported_targets { assert_eq!(original, parsed); }); } - )* + )+ } - ) + }; } supported_targets! { @@ -335,6 +335,10 @@ supported_targets! { ("mips-unknown-linux-gnu", mips_unknown_linux_gnu), ("mips64-unknown-linux-gnuabi64", mips64_unknown_linux_gnuabi64), ("mips64el-unknown-linux-gnuabi64", mips64el_unknown_linux_gnuabi64), + ("mipsisa32r6-unknown-linux-gnu", mipsisa32r6_unknown_linux_gnu), + ("mipsisa32r6el-unknown-linux-gnu", mipsisa32r6el_unknown_linux_gnu), + ("mipsisa64r6-unknown-linux-gnuabi64", mipsisa64r6_unknown_linux_gnuabi64), + ("mipsisa64r6el-unknown-linux-gnuabi64", mipsisa64r6el_unknown_linux_gnuabi64), ("mipsel-unknown-linux-gnu", mipsel_unknown_linux_gnu), ("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu), ("powerpc-unknown-linux-gnuspe", powerpc_unknown_linux_gnuspe), @@ -376,6 +380,8 @@ supported_targets! { ("aarch64-linux-android", aarch64_linux_android), ("aarch64-unknown-freebsd", aarch64_unknown_freebsd), + ("armv6-unknown-freebsd", armv6_unknown_freebsd), + ("armv7-unknown-freebsd", armv7_unknown_freebsd), ("i686-unknown-freebsd", i686_unknown_freebsd), ("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd), ("x86_64-unknown-freebsd", x86_64_unknown_freebsd), @@ -383,8 +389,6 @@ supported_targets! { ("i686-unknown-dragonfly", i686_unknown_dragonfly), ("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly), - ("x86_64-unknown-bitrig", x86_64_unknown_bitrig), - ("aarch64-unknown-openbsd", aarch64_unknown_openbsd), ("i686-unknown-openbsd", i686_unknown_openbsd), ("x86_64-unknown-openbsd", x86_64_unknown_openbsd), @@ -422,7 +426,9 @@ supported_targets! { ("armv7r-none-eabi", armv7r_none_eabi), ("armv7r-none-eabihf", armv7r_none_eabihf), - ("x86_64-sun-solaris", x86_64_sun_solaris), + // `x86_64-pc-solaris` is an alias for `x86_64_sun_solaris` for backwards compatibility reasons. + // (See .) + ("x86_64-sun-solaris", "x86_64-pc-solaris", x86_64_sun_solaris), ("sparcv9-sun-solaris", sparcv9_sun_solaris), ("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu), @@ -437,6 +443,7 @@ supported_targets! { ("asmjs-unknown-emscripten", asmjs_unknown_emscripten), ("wasm32-unknown-emscripten", wasm32_unknown_emscripten), ("wasm32-unknown-unknown", wasm32_unknown_unknown), + ("wasm32-wasi", wasm32_wasi), ("wasm32-experimental-emscripten", wasm32_experimental_emscripten), ("thumbv6m-none-eabi", thumbv6m_none_eabi), @@ -745,6 +752,9 @@ pub struct TargetOptions { /// wasm32 where the whole program either has simd or not. pub simd_types_indirect: bool, + /// Pass a list of symbol which should be exported in the dylib to the linker. + pub limit_rdylib_exports: bool, + /// If set, have the linker export exactly these symbols, instead of using /// the usual logic to figure this out from the crate itself. pub override_export_symbols: Option>, @@ -755,7 +765,10 @@ pub struct TargetOptions { /// to opt out. The default is "aliases". /// /// Workaround for: https://github.com/rust-lang/rust/issues/57356 - pub merge_functions: MergeFunctions + pub merge_functions: MergeFunctions, + + /// Use platform dependent mcount function + pub target_mcount: String } impl Default for TargetOptions { @@ -837,8 +850,10 @@ impl Default for TargetOptions { emit_debug_gdb_scripts: true, requires_uwtable: false, simd_types_indirect: true, + limit_rdylib_exports: true, override_export_symbols: None, merge_functions: MergeFunctions::Aliases, + target_mcount: "mcount".to_string(), } } } @@ -1142,8 +1157,10 @@ impl Target { key!(emit_debug_gdb_scripts, bool); key!(requires_uwtable, bool); key!(simd_types_indirect, bool); + key!(limit_rdylib_exports, bool); key!(override_export_symbols, opt_list); key!(merge_functions, MergeFunctions)?; + key!(target_mcount); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -1356,8 +1373,10 @@ impl ToJson for Target { target_option_val!(emit_debug_gdb_scripts); target_option_val!(requires_uwtable); target_option_val!(simd_types_indirect); + target_option_val!(limit_rdylib_exports); target_option_val!(override_export_symbols); target_option_val!(merge_functions); + target_option_val!(target_mcount); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/librustc_target/spec/netbsd_base.rs b/src/librustc_target/spec/netbsd_base.rs index e9cd98c0e7151..72e2fd59cf8d6 100644 --- a/src/librustc_target/spec/netbsd_base.rs +++ b/src/librustc_target/spec/netbsd_base.rs @@ -9,9 +9,6 @@ pub fn opts() -> TargetOptions { // libraries which follow this flag. Thus, use it before // specifying libraries to link to. "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), ]); TargetOptions { diff --git a/src/librustc_target/spec/powerpc64_unknown_freebsd.rs b/src/librustc_target/spec/powerpc64_unknown_freebsd.rs index 360876b9ff557..fc881db6b0906 100644 --- a/src/librustc_target/spec/powerpc64_unknown_freebsd.rs +++ b/src/librustc_target/spec/powerpc64_unknown_freebsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); @@ -17,6 +17,9 @@ pub fn target() -> TargetResult { target_env: String::new(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "_mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/powerpc64_unknown_linux_gnu.rs b/src/librustc_target/spec/powerpc64_unknown_linux_gnu.rs index c16db7583f32b..89e68ab306200 100644 --- a/src/librustc_target/spec/powerpc64_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/powerpc64_unknown_linux_gnu.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult, RelroLevel}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult, RelroLevel}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); @@ -21,6 +21,9 @@ pub fn target() -> TargetResult { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "_mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/powerpc64_unknown_linux_musl.rs b/src/librustc_target/spec/powerpc64_unknown_linux_musl.rs index ac0b7431f91a4..be91dc44b9357 100644 --- a/src/librustc_target/spec/powerpc64_unknown_linux_musl.rs +++ b/src/librustc_target/spec/powerpc64_unknown_linux_musl.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); @@ -17,6 +17,9 @@ pub fn target() -> TargetResult { target_env: "musl".to_string(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "_mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/powerpc64le_unknown_linux_gnu.rs b/src/librustc_target/spec/powerpc64le_unknown_linux_gnu.rs index 038b925a28692..784e3b090943c 100644 --- a/src/librustc_target/spec/powerpc64le_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/powerpc64le_unknown_linux_gnu.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); @@ -17,6 +17,9 @@ pub fn target() -> TargetResult { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "_mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/powerpc64le_unknown_linux_musl.rs b/src/librustc_target/spec/powerpc64le_unknown_linux_musl.rs index 57103345f0a0c..a3cf47fc5e082 100644 --- a/src/librustc_target/spec/powerpc64le_unknown_linux_musl.rs +++ b/src/librustc_target/spec/powerpc64le_unknown_linux_musl.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); @@ -17,6 +17,9 @@ pub fn target() -> TargetResult { target_env: "musl".to_string(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "_mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/powerpc_unknown_linux_gnu.rs b/src/librustc_target/spec/powerpc_unknown_linux_gnu.rs index 38a801d5ab507..ff52fbc179b16 100644 --- a/src/librustc_target/spec/powerpc_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/powerpc_unknown_linux_gnu.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); @@ -16,6 +16,9 @@ pub fn target() -> TargetResult { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "_mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/powerpc_unknown_linux_gnuspe.rs b/src/librustc_target/spec/powerpc_unknown_linux_gnuspe.rs index 675b2c749d648..1868c42be39d2 100644 --- a/src/librustc_target/spec/powerpc_unknown_linux_gnuspe.rs +++ b/src/librustc_target/spec/powerpc_unknown_linux_gnuspe.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); @@ -16,6 +16,9 @@ pub fn target() -> TargetResult { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "_mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/powerpc_unknown_linux_musl.rs b/src/librustc_target/spec/powerpc_unknown_linux_musl.rs index 240443aa98db4..1ad2201092c3f 100644 --- a/src/librustc_target/spec/powerpc_unknown_linux_musl.rs +++ b/src/librustc_target/spec/powerpc_unknown_linux_musl.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); @@ -16,6 +16,9 @@ pub fn target() -> TargetResult { target_env: "musl".to_string(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "_mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/powerpc_unknown_netbsd.rs b/src/librustc_target/spec/powerpc_unknown_netbsd.rs index 10e7089cf1c4c..6cc3a6c2ef3f2 100644 --- a/src/librustc_target/spec/powerpc_unknown_netbsd.rs +++ b/src/librustc_target/spec/powerpc_unknown_netbsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); @@ -16,6 +16,9 @@ pub fn target() -> TargetResult { target_env: String::new(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "__mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs b/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs index 5064393d31135..8a97a09bb60aa 100644 --- a/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs @@ -25,6 +25,7 @@ pub fn target() -> TargetResult { relocation_model: "static".to_string(), emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), + eliminate_frame_pointer: false, .. Default::default() }, }) diff --git a/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs b/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs index 31e74c5920cf9..647d33e3ffeee 100644 --- a/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs @@ -26,6 +26,7 @@ pub fn target() -> TargetResult { relocation_model: "static".to_string(), emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), + eliminate_frame_pointer: false, .. Default::default() }, }) diff --git a/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs b/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs index 2d4070c786fed..a5c13fa28e2ce 100644 --- a/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs @@ -25,6 +25,7 @@ pub fn target() -> TargetResult { relocation_model: "static".to_string(), emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), + eliminate_frame_pointer: false, .. Default::default() }, }) diff --git a/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs b/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs index f2e152c741e02..237d615ffcc4b 100644 --- a/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs @@ -25,6 +25,7 @@ pub fn target() -> TargetResult { relocation_model: "static".to_string(), emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), + eliminate_frame_pointer: false, .. Default::default() }, }) diff --git a/src/librustc_target/spec/solaris_base.rs b/src/librustc_target/spec/solaris_base.rs index 0dfbb13b77317..9e7eda037732b 100644 --- a/src/librustc_target/spec/solaris_base.rs +++ b/src/librustc_target/spec/solaris_base.rs @@ -8,6 +8,7 @@ pub fn opts() -> TargetOptions { has_rpath: true, target_family: Some("unix".to_string()), is_like_solaris: true, + limit_rdylib_exports: false, // Linker doesn't support this .. Default::default() } diff --git a/src/librustc_target/spec/sparc64_unknown_netbsd.rs b/src/librustc_target/spec/sparc64_unknown_netbsd.rs index 78d53e69e8b52..09d1debef41e9 100644 --- a/src/librustc_target/spec/sparc64_unknown_netbsd.rs +++ b/src/librustc_target/spec/sparc64_unknown_netbsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); @@ -17,6 +17,9 @@ pub fn target() -> TargetResult { target_env: String::new(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "__mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/uefi_base.rs b/src/librustc_target/spec/uefi_base.rs index 631966c09a498..956767a22a0e1 100644 --- a/src/librustc_target/spec/uefi_base.rs +++ b/src/librustc_target/spec/uefi_base.rs @@ -59,7 +59,7 @@ pub fn opts() -> TargetOptions { singlethread: true, emit_debug_gdb_scripts: false, - linker: Some("lld-link".to_string()), + linker: Some("rust-lld".to_string()), lld_flavor: LldFlavor::Link, pre_link_args, diff --git a/src/librustc_target/spec/wasm32_base.rs b/src/librustc_target/spec/wasm32_base.rs new file mode 100644 index 0000000000000..39a8ce9282573 --- /dev/null +++ b/src/librustc_target/spec/wasm32_base.rs @@ -0,0 +1,137 @@ +use std::collections::BTreeMap; +use super::{LldFlavor, TargetOptions, PanicStrategy, LinkerFlavor}; + +pub fn options() -> TargetOptions { + let mut lld_args = Vec::new(); + let mut clang_args = Vec::new(); + let mut arg = |arg: &str| { + lld_args.push(arg.to_string()); + clang_args.push(format!("-Wl,{}", arg)); + }; + + // There have been reports in the wild (rustwasm/wasm-bindgen#119) of + // using threads causing weird hangs and bugs. Disable it entirely as + // this isn't yet the bottleneck of compilation at all anyway. + // + // FIXME: we should file an upstream issue with LLD about this + arg("--no-threads"); + + // By default LLD only gives us one page of stack (64k) which is a + // little small. Default to a larger stack closer to other PC platforms + // (1MB) and users can always inject their own link-args to override this. + arg("-z"); + arg("stack-size=1048576"); + + // By default LLD's memory layout is: + // + // 1. First, a blank page + // 2. Next, all static data + // 3. Finally, the main stack (which grows down) + // + // This has the unfortunate consequence that on stack overflows you + // corrupt static data and can cause some exceedingly weird bugs. To + // help detect this a little sooner we instead request that the stack is + // placed before static data. + // + // This means that we'll generate slightly larger binaries as references + // to static data will take more bytes in the ULEB128 encoding, but + // stack overflow will be guaranteed to trap as it underflows instead of + // corrupting static data. + arg("--stack-first"); + + // FIXME we probably shouldn't pass this but instead pass an explicit + // whitelist of symbols we'll allow to be undefined. We don't currently have + // a mechanism of knowing, however, which symbols are intended to be + // imported from the environment and which are intended to be imported from + // other objects linked elsewhere. This is a coarse approximation but is + // sure to hide some bugs and frustrate someone at some point, so we should + // ideally work towards a world where we can explicitly list symbols that + // are supposed to be imported and have all other symbols generate errors if + // they remain undefined. + arg("--allow-undefined"); + + // Rust code should never have warnings, and warnings are often + // indicative of bugs, let's prevent them. + arg("--fatal-warnings"); + + // LLD only implements C++-like demangling, which doesn't match our own + // mangling scheme. Tell LLD to not demangle anything and leave it up to + // us to demangle these symbols later. Currently rustc does not perform + // further demangling, but tools like twiggy and wasm-bindgen are intended + // to do so. + arg("--no-demangle"); + + // The symbol visibility story is a bit in flux right now with LLD. + // It's... not entirely clear to me what's going on, but this looks to + // make everything work when `export_symbols` isn't otherwise called for + // things like executables. + // + // This is really only here to get things working. If it can be removed and + // basic tests still work, then sounds like it should be removed! + arg("--export-dynamic"); + + let mut pre_link_args = BTreeMap::new(); + pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args); + pre_link_args.insert(LinkerFlavor::Gcc, clang_args); + + TargetOptions { + // we allow dynamic linking, but only cdylibs. Basically we allow a + // final library artifact that exports some symbols (a wasm module) but + // we don't allow intermediate `dylib` crate types + dynamic_linking: true, + only_cdylib: true, + + // This means we'll just embed a `start` function in the wasm module + executables: true, + + // relatively self-explanatory! + exe_suffix: ".wasm".to_string(), + dll_prefix: String::new(), + dll_suffix: ".wasm".to_string(), + linker_is_gnu: false, + + max_atomic_width: Some(64), + + // Unwinding doesn't work right now, so the whole target unconditionally + // defaults to panic=abort. Note that this is guaranteed to change in + // the future once unwinding is implemented. Don't rely on this as we're + // basically guaranteed to change it once WebAssembly supports + // exceptions. + panic_strategy: PanicStrategy::Abort, + + // Wasm doesn't have atomics yet, so tell LLVM that we're in a single + // threaded model which will legalize atomics to normal operations. + singlethread: true, + + // no dynamic linking, no need for default visibility! + default_hidden_visibility: true, + + // Symbol visibility takes care of this for the WebAssembly. + // Additionally the only known linker, LLD, doesn't support the script + // arguments just yet + limit_rdylib_exports: false, + + // we use the LLD shipped with the Rust toolchain by default + linker: Some("rust-lld".to_owned()), + lld_flavor: LldFlavor::Wasm, + + // No need for indirection here, simd types can always be passed by + // value as the whole module either has simd or not, which is different + // from x86 (for example) where programs can have functions that don't + // enable simd features. + simd_types_indirect: false, + + pre_link_args, + + // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when + // PIC code is implemented this has quite a drastric effect if it stays + // at the default, `pic`. In an effort to keep wasm binaries as minimal + // as possible we're defaulting to `static` for now, but the hope is + // that eventually we can ship a `pic`-compatible standard library which + // works with `static` as well (or works with some method of generating + // non-relative calls and such later on). + relocation_model: "static".to_string(), + + .. Default::default() + } +} diff --git a/src/librustc_target/spec/wasm32_experimental_emscripten.rs b/src/librustc_target/spec/wasm32_experimental_emscripten.rs index 5ecd66306d055..b802bee25ae7a 100644 --- a/src/librustc_target/spec/wasm32_experimental_emscripten.rs +++ b/src/librustc_target/spec/wasm32_experimental_emscripten.rs @@ -24,6 +24,7 @@ pub fn target() -> Result { is_like_emscripten: true, max_atomic_width: Some(32), post_link_args, + limit_rdylib_exports: false, target_family: Some("unix".to_string()), .. Default::default() }; diff --git a/src/librustc_target/spec/wasm32_unknown_emscripten.rs b/src/librustc_target/spec/wasm32_unknown_emscripten.rs index a6e9340ce28ef..e0df36884bf56 100644 --- a/src/librustc_target/spec/wasm32_unknown_emscripten.rs +++ b/src/librustc_target/spec/wasm32_unknown_emscripten.rs @@ -26,6 +26,7 @@ pub fn target() -> Result { is_like_emscripten: true, max_atomic_width: Some(32), post_link_args, + limit_rdylib_exports: false, target_family: Some("unix".to_string()), codegen_backend: "emscripten".to_string(), .. Default::default() diff --git a/src/librustc_target/spec/wasm32_unknown_unknown.rs b/src/librustc_target/spec/wasm32_unknown_unknown.rs index ee2160c472080..909527d2b6120 100644 --- a/src/librustc_target/spec/wasm32_unknown_unknown.rs +++ b/src/librustc_target/spec/wasm32_unknown_unknown.rs @@ -1,70 +1,48 @@ -// The wasm32-unknown-unknown target is currently an experimental version of a -// wasm-based target which does *not* use the Emscripten toolchain. Instead -// this toolchain is based purely on LLVM's own toolchain, using LLVM's native -// WebAssembly backend as well as LLD for a native linker. -// -// There's some trickery below on crate types supported and various defaults -// (aka panic=abort by default), but otherwise this is in general a relatively -// standard target. - -use super::{LldFlavor, LinkerFlavor, Target, TargetOptions, PanicStrategy}; +//! A "bare wasm" target representing a WebAssembly output that makes zero +//! assumptions about its environment. +//! +//! The `wasm32-unknown-unknown` target is intended to encapsulate use cases +//! that do not rely on any imported functionality. The binaries generated are +//! entirely self-contained by default when using the standard library. Although +//! the standard library is available, most of it returns an error immediately +//! (e.g. trying to create a TCP stream or something like that). +//! +//! This target is more or less managed by the Rust and WebAssembly Working +//! Group nowadays at https://github.com/rustwasm. + +use super::{LldFlavor, LinkerFlavor, Target}; +use super::wasm32_base; pub fn target() -> Result { - let opts = TargetOptions { - // we allow dynamic linking, but only cdylibs. Basically we allow a - // final library artifact that exports some symbols (a wasm module) but - // we don't allow intermediate `dylib` crate types - dynamic_linking: true, - only_cdylib: true, - - // This means we'll just embed a `start` function in the wasm module - executables: true, - - // relatively self-explanatory! - exe_suffix: ".wasm".to_string(), - dll_prefix: String::new(), - dll_suffix: ".wasm".to_string(), - linker_is_gnu: false, - - max_atomic_width: Some(64), - - // Unwinding doesn't work right now, so the whole target unconditionally - // defaults to panic=abort. Note that this is guaranteed to change in - // the future once unwinding is implemented. Don't rely on this. - panic_strategy: PanicStrategy::Abort, - - // Wasm doesn't have atomics yet, so tell LLVM that we're in a single - // threaded model which will legalize atomics to normal operations. - singlethread: true, + let mut options = wasm32_base::options(); + let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); - // no dynamic linking, no need for default visibility! - default_hidden_visibility: true, + // Make sure clang uses LLD as its linker and is configured appropriately + // otherwise + clang_args.push("--target=wasm32-unknown-unknown".to_string()); - // we use the LLD shipped with the Rust toolchain by default - linker: Some("rust-lld".to_owned()), - lld_flavor: LldFlavor::Wasm, + // Disable attempting to link crt1.o since it typically isn't present and + // isn't needed currently. + clang_args.push("-nostdlib".to_string()); - // No need for indirection here, simd types can always be passed by - // value as the whole module either has simd or not, which is different - // from x86 (for example) where programs can have functions that don't - // enable simd features. - simd_types_indirect: false, + // For now this target just never has an entry symbol no matter the output + // type, so unconditionally pass this. + clang_args.push("-Wl,--no-entry".to_string()); + options.pre_link_args.get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm)) + .unwrap() + .push("--no-entry".to_string()); - .. Default::default() - }; Ok(Target { llvm_target: "wasm32-unknown-unknown".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), target_c_int_width: "32".to_string(), - // This is basically guaranteed to change in the future, don't rely on - // this. Use `not(target_os = "emscripten")` for now. target_os: "unknown".to_string(), target_env: String::new(), target_vendor: "unknown".to_string(), data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(), arch: "wasm32".to_string(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Wasm), - options: opts, + options, }) } diff --git a/src/librustc_target/spec/wasm32_wasi.rs b/src/librustc_target/spec/wasm32_wasi.rs new file mode 100644 index 0000000000000..bb33493a77333 --- /dev/null +++ b/src/librustc_target/spec/wasm32_wasi.rs @@ -0,0 +1,113 @@ +//! The `wasm32-wasi` target is a new and still (as of April 2019) an +//! experimental target. The definition in this file is likely to be tweaked +//! over time and shouldn't be relied on too much. +//! +//! The `wasi` target is a proposal to define a standardized set of syscalls +//! that WebAssembly files can interoperate with. This set of syscalls is +//! intended to empower WebAssembly binaries with native capabilities such as +//! filesystem access, network access, etc. +//! +//! You can see more about the proposal at https://wasi.dev +//! +//! The Rust target definition here is interesting in a few ways. We want to +//! serve two use cases here with this target: +//! +//! * First, we want Rust usage of the target to be as hassle-free as possible, +//! ideally avoiding the need to configure and install a local wasm32-wasi +//! toolchain. +//! +//! * Second, one of the primary use cases of LLVM's new wasm backend and the +//! wasm support in LLD is that any compiled language can interoperate with +//! any other. To that the `wasm32-wasi` target is the first with a viable C +//! standard library and sysroot common definition, so we want Rust and C/C++ +//! code to interoperate when compiled to `wasm32-unknown-unknown`. +//! +//! You'll note, however, that the two goals above are somewhat at odds with one +//! another. To attempt to solve both use cases in one go we define a target +//! that (ab)uses the `crt-static` target feature to indicate which one you're +//! in. +//! +//! ## No interop with C required +//! +//! By default the `crt-static` target feature is enabled, and when enabled +//! this means that the the bundled version of `libc.a` found in `liblibc.rlib` +//! is used. This isn't intended really for interoperation with a C because it +//! may be the case that Rust's bundled C library is incompatible with a +//! foreign-compiled C library. In this use case, though, we use `rust-lld` and +//! some copied crt startup object files to ensure that you can download the +//! wasi target for Rust and you're off to the races, no further configuration +//! necessary. +//! +//! All in all, by default, no external dependencies are required. You can +//! compile `wasm32-wasi` binaries straight out of the box. You can't, however, +//! reliably interoperate with C code in this mode (yet). +//! +//! ## Interop with C required +//! +//! For the second goal we repurpose the `target-feature` flag, meaning that +//! you'll need to do a few things to have C/Rust code interoperate. +//! +//! 1. All Rust code needs to be compiled with `-C target-feature=-crt-static`, +//! indicating that the bundled C standard library in the Rust sysroot will +//! not be used. +//! +//! 2. If you're using rustc to build a linked artifact then you'll need to +//! specify `-C linker` to a `clang` binary that supports +//! `wasm32-wasi` and is configured with the `wasm32-wasi` sysroot. This +//! will cause Rust code to be linked against the libc.a that the specified +//! `clang` provides. +//! +//! 3. If you're building a staticlib and integrating Rust code elsewhere, then +//! compiling with `-C target-feature=-crt-static` is all you need to do. +//! +//! You can configure the linker via Cargo using the +//! `CARGO_TARGET_WASM32_WASI_LINKER` env var. Be sure to also set +//! `CC_wasm32-wasi` if any crates in the dependency graph are using the `cc` +//! crate. +//! +//! ## Remember, this is all in flux +//! +//! The wasi target is **very** new in its specification. It's likely going to +//! be a long effort to get it standardized and stable. We'll be following it as +//! best we can with this target. Don't start relying on too much here unless +//! you know what you're getting in to! + +use super::wasm32_base; +use super::{LinkerFlavor, LldFlavor, Target}; + +pub fn target() -> Result { + let mut options = wasm32_base::options(); + + options + .pre_link_args + .entry(LinkerFlavor::Gcc) + .or_insert(Vec::new()) + .push("--target=wasm32-wasi".to_string()); + + // When generating an executable be sure to put the startup object at the + // front so the main function is correctly hooked up. + options.pre_link_objects_exe_crt.push("crt1.o".to_string()); + + // Right now this is a bit of a workaround but we're currently saying that + // the target by default has a static crt which we're taking as a signal + // for "use the bundled crt". If that's turned off then the system's crt + // will be used, but this means that default usage of this target doesn't + // need an external compiler but it's still interoperable with an external + // compiler if configured correctly. + options.crt_static_default = true; + options.crt_static_respected = true; + + Ok(Target { + llvm_target: "wasm32-wasi".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + target_os: "wasi".to_string(), + target_env: String::new(), + target_vendor: String::new(), + data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(), + arch: "wasm32".to_string(), + linker_flavor: LinkerFlavor::Lld(LldFlavor::Wasm), + options, + }) +} diff --git a/src/librustc_target/spec/x86_64_apple_darwin.rs b/src/librustc_target/spec/x86_64_apple_darwin.rs index 0911ce06c13d7..182103440f035 100644 --- a/src/librustc_target/spec/x86_64_apple_darwin.rs +++ b/src/librustc_target/spec/x86_64_apple_darwin.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::apple_base::opts(); @@ -8,17 +8,26 @@ pub fn target() -> TargetResult { base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); base.stack_probes = true; + // Clang automatically chooses a more specific target based on + // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work + // correctly, we do too. + let arch = "x86_64"; + let llvm_target = super::apple_base::macos_llvm_target(&arch); + Ok(Target { - llvm_target: "x86_64-apple-darwin".to_string(), + llvm_target: llvm_target, target_endian: "little".to_string(), target_pointer_width: "64".to_string(), target_c_int_width: "32".to_string(), data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(), - arch: "x86_64".to_string(), + arch: arch.to_string(), target_os: "macos".to_string(), target_env: String::new(), target_vendor: "apple".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "\u{1}mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs index 7c369daa2a8f6..46cf4cd8ae353 100644 --- a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs +++ b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs @@ -21,6 +21,15 @@ pub fn target() -> Result { "-Wl,--no-undefined-version", "-Wl,-Bsymbolic", "-Wl,--export-dynamic", + // The following symbols are needed by libunwind, which is linked after + // libstd. Make sure they're included in the link. + "-Wl,-u,__rust_abort", + "-Wl,-u,__rust_c_alloc", + "-Wl,-u,__rust_c_dealloc", + "-Wl,-u,__rust_print_err", + "-Wl,-u,__rust_rwlock_rdlock", + "-Wl,-u,__rust_rwlock_unlock", + "-Wl,-u,__rust_rwlock_wrlock", ]; const EXPORT_SYMBOLS: &[&str] = &[ diff --git a/src/librustc_target/spec/x86_64_rumprun_netbsd.rs b/src/librustc_target/spec/x86_64_rumprun_netbsd.rs index a2c706c4c7232..f6861f2a68727 100644 --- a/src/librustc_target/spec/x86_64_rumprun_netbsd.rs +++ b/src/librustc_target/spec/x86_64_rumprun_netbsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); @@ -24,6 +24,9 @@ pub fn target() -> TargetResult { target_env: String::new(), target_vendor: "rumprun".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "__mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_target/spec/x86_64_unknown_bitrig.rs b/src/librustc_target/spec/x86_64_unknown_bitrig.rs deleted file mode 100644 index 999d93a7e6090..0000000000000 --- a/src/librustc_target/spec/x86_64_unknown_bitrig.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; - -pub fn target() -> TargetResult { - let mut base = super::bitrig_base::opts(); - base.cpu = "x86-64".to_string(); - base.max_atomic_width = Some(64); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); - base.stack_probes = true; - - Ok(Target { - llvm_target: "x86_64-unknown-bitrig".to_string(), - target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), - target_c_int_width: "32".to_string(), - data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(), - arch: "x86_64".to_string(), - target_os: "bitrig".to_string(), - target_env: String::new(), - target_vendor: "unknown".to_string(), - linker_flavor: LinkerFlavor::Gcc, - options: base, - }) -} diff --git a/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs b/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs index 0b2d7aacc4ddf..73151b194de42 100644 --- a/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs +++ b/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs @@ -5,7 +5,8 @@ pub fn target() -> TargetResult { base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string()); - base.stack_probes = true; + // BUG: temporarily workaround #59674 + base.stack_probes = false; base.has_elf_tls = false; // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI // breaks code gen. See LLVM bug 36743 diff --git a/src/librustc_target/spec/x86_64_unknown_netbsd.rs b/src/librustc_target/spec/x86_64_unknown_netbsd.rs index ffc4f1d5c49b7..6f4ab4995b5dc 100644 --- a/src/librustc_target/spec/x86_64_unknown_netbsd.rs +++ b/src/librustc_target/spec/x86_64_unknown_netbsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); @@ -18,6 +18,9 @@ pub fn target() -> TargetResult { target_env: String::new(), target_vendor: "unknown".to_string(), linker_flavor: LinkerFlavor::Gcc, - options: base, + options: TargetOptions { + target_mcount: "__mcount".to_string(), + .. base + }, }) } diff --git a/src/librustc_traits/chalk_context/mod.rs b/src/librustc_traits/chalk_context/mod.rs index a326d84725ab4..5c23ad4a4edfb 100644 --- a/src/librustc_traits/chalk_context/mod.rs +++ b/src/librustc_traits/chalk_context/mod.rs @@ -17,6 +17,7 @@ use rustc::infer::canonical::{ CanonicalVarValues, OriginalQueryValues, QueryResponse, + QueryRegionConstraints, Certainty, }; use rustc::traits::{ @@ -32,11 +33,11 @@ use rustc::traits::{ InEnvironment, ChalkCanonicalGoal, }; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt, InferConst}; use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc::ty::query::Providers; use rustc::ty::subst::{Kind, UnpackedKind}; -use rustc_data_structures::sync::Lrc; +use rustc::mir::interpret::ConstValue; use syntax_pos::DUMMY_SP; use std::fmt::{self, Debug}; @@ -45,19 +46,19 @@ use std::marker::PhantomData; use self::unify::*; #[derive(Copy, Clone, Debug)] -crate struct ChalkArenas<'gcx> { - _phantom: PhantomData<&'gcx ()>, +crate struct ChalkArenas<'tcx> { + _phantom: PhantomData<&'tcx ()>, } #[derive(Copy, Clone)] -crate struct ChalkContext<'cx, 'gcx: 'cx> { - _arenas: ChalkArenas<'gcx>, - tcx: TyCtxt<'cx, 'gcx, 'gcx>, +crate struct ChalkContext<'tcx> { + _arenas: ChalkArenas<'tcx>, + tcx: TyCtxt<'tcx>, } #[derive(Copy, Clone)] -crate struct ChalkInferenceContext<'cx, 'gcx: 'tcx, 'tcx: 'cx> { - infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, +crate struct ChalkInferenceContext<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, } #[derive(Copy, Clone, Debug)] @@ -126,12 +127,12 @@ impl context::Context for ChalkArenas<'tcx> { } } -impl context::AggregateOps> for ChalkContext<'cx, 'gcx> { +impl context::AggregateOps> for ChalkContext<'tcx> { fn make_solution( &self, - root_goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - mut simplified_answers: impl context::AnswerStream>, - ) -> Option>> { + root_goal: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, + mut simplified_answers: impl context::AnswerStream>, + ) -> Option>> { use chalk_engine::SimplifiedAnswer; debug!("make_solution(root_goal = {:?})", root_goal); @@ -151,14 +152,14 @@ impl context::AggregateOps> for ChalkContext<'cx, 'gcx> { let solution = constrained_subst.unchecked_map(|cs| match ambiguous { true => QueryResponse { var_values: cs.subst.make_identity(self.tcx), - region_constraints: Vec::new(), + region_constraints: QueryRegionConstraints::default(), certainty: Certainty::Ambiguous, value: (), }, false => QueryResponse { var_values: cs.subst, - region_constraints: Vec::new(), + region_constraints: QueryRegionConstraints::default(), // FIXME: restore this later once we get better at handling regions // region_constraints: cs.constraints @@ -176,13 +177,10 @@ impl context::AggregateOps> for ChalkContext<'cx, 'gcx> { } } -impl context::ContextOps> for ChalkContext<'cx, 'gcx> { +impl context::ContextOps> for ChalkContext<'tcx> { /// Returns `true` if this is a coinductive goal: basically proving that an auto trait /// is implemented or proving that a trait reference is well-formed. - fn is_coinductive( - &self, - goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>> - ) -> bool { + fn is_coinductive(&self, goal: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>) -> bool { use rustc::traits::{WellFormed, WhereClause}; let mut goal = goal.value.goal; @@ -216,8 +214,8 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { /// - the environment and goal found by substitution `S` into `arg`. fn instantiate_ucanonical_goal( &self, - arg: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - op: impl context::WithInstantiatedUCanonicalGoal, Output = R>, + arg: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, + op: impl context::WithInstantiatedUCanonicalGoal, Output = R>, ) -> R { self.tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, arg, |ref infcx, arg, subst| { let chalk_infcx = &mut ChalkInferenceContext { @@ -230,8 +228,8 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { fn instantiate_ex_clause( &self, _num_universes: usize, - arg: &Canonical<'gcx, ChalkExClause<'gcx>>, - op: impl context::WithInstantiatedExClause, Output = R>, + arg: &Canonical<'tcx, ChalkExClause<'tcx>>, + op: impl context::WithInstantiatedExClause, Output = R>, ) -> R { self.tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &arg.upcast(), |ref infcx, arg, _| { let chalk_infcx = &mut ChalkInferenceContext { @@ -242,31 +240,31 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { } /// Returns `true` if this solution has no region constraints. - fn empty_constraints(ccs: &Canonical<'gcx, ConstrainedSubst<'gcx>>) -> bool { + fn empty_constraints(ccs: &Canonical<'tcx, ConstrainedSubst<'tcx>>) -> bool { ccs.value.constraints.is_empty() } fn inference_normalized_subst_from_ex_clause( - canon_ex_clause: &'a Canonical<'gcx, ChalkExClause<'gcx>>, - ) -> &'a CanonicalVarValues<'gcx> { + canon_ex_clause: &'a Canonical<'tcx, ChalkExClause<'tcx>>, + ) -> &'a CanonicalVarValues<'tcx> { &canon_ex_clause.value.subst } fn inference_normalized_subst_from_subst( - canon_subst: &'a Canonical<'gcx, ConstrainedSubst<'gcx>>, - ) -> &'a CanonicalVarValues<'gcx> { + canon_subst: &'a Canonical<'tcx, ConstrainedSubst<'tcx>>, + ) -> &'a CanonicalVarValues<'tcx> { &canon_subst.value.subst } fn canonical( - u_canon: &'a Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - ) -> &'a Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>> { + u_canon: &'a Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, + ) -> &'a Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>> { u_canon } fn is_trivial_substitution( - u_canon: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - canonical_subst: &Canonical<'gcx, ConstrainedSubst<'gcx>>, + u_canon: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, + canonical_subst: &Canonical<'tcx, ConstrainedSubst<'tcx>>, ) -> bool { let subst = &canonical_subst.value.subst; assert_eq!(u_canon.variables.len(), subst.var_values.len()); @@ -287,10 +285,17 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { } _ => false, }, + UnpackedKind::Const(ct) => match ct.val { + ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)) => { + debug_assert_eq!(debruijn, ty::INNERMOST); + cvar == bound_ct + } + _ => false, + } }) } - fn num_universes(canon: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>) -> usize { + fn num_universes(canon: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>) -> usize { canon.max_universe.index() + 1 } @@ -299,21 +304,21 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { /// but for the universes of universally quantified names. fn map_goal_from_canonical( _map: &UniverseMap, - value: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - ) -> Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>> { + value: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, + ) -> Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>> { *value // FIXME universe maps not implemented yet } fn map_subst_from_canonical( _map: &UniverseMap, - value: &Canonical<'gcx, ConstrainedSubst<'gcx>>, - ) -> Canonical<'gcx, ConstrainedSubst<'gcx>> { + value: &Canonical<'tcx, ConstrainedSubst<'tcx>>, + ) -> Canonical<'tcx, ConstrainedSubst<'tcx>> { value.clone() // FIXME universe maps not implemented yet } } -impl context::InferenceTable, ChalkArenas<'tcx>> - for ChalkInferenceContext<'cx, 'gcx, 'tcx> +impl context::InferenceTable, ChalkArenas<'tcx>> + for ChalkInferenceContext<'cx, 'tcx> { fn into_goal(&self, domain_goal: DomainGoal<'tcx>) -> Goal<'tcx> { self.infcx.tcx.mk_goal(GoalKind::DomainGoal(domain_goal)) @@ -356,8 +361,8 @@ impl context::InferenceTable, ChalkArenas<'tcx>> } } -impl context::TruncateOps, ChalkArenas<'tcx>> - for ChalkInferenceContext<'cx, 'gcx, 'tcx> +impl context::TruncateOps, ChalkArenas<'tcx>> + for ChalkInferenceContext<'cx, 'tcx> { fn truncate_goal( &mut self, @@ -374,8 +379,8 @@ impl context::TruncateOps, ChalkArenas<'tcx>> } } -impl context::UnificationOps, ChalkArenas<'tcx>> - for ChalkInferenceContext<'cx, 'gcx, 'tcx> +impl context::UnificationOps, ChalkArenas<'tcx>> + for ChalkInferenceContext<'cx, 'tcx> { fn program_clauses( &self, @@ -404,14 +409,14 @@ impl context::UnificationOps, ChalkArenas<'tcx>> } fn debug_ex_clause(&mut self, value: &'v ChalkExClause<'tcx>) -> Box { - let string = format!("{:?}", self.infcx.resolve_type_vars_if_possible(value)); + let string = format!("{:?}", self.infcx.resolve_vars_if_possible(value)); Box::new(string) } fn canonicalize_goal( &mut self, value: &InEnvironment<'tcx, Goal<'tcx>>, - ) -> Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>> { + ) -> Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>> { let mut _orig_values = OriginalQueryValues::default(); self.infcx.canonicalize_query(value, &mut _orig_values) } @@ -419,7 +424,7 @@ impl context::UnificationOps, ChalkArenas<'tcx>> fn canonicalize_ex_clause( &mut self, value: &ChalkExClause<'tcx>, - ) -> Canonical<'gcx, ChalkExClause<'gcx>> { + ) -> Canonical<'tcx, ChalkExClause<'tcx>> { self.infcx.canonicalize_response(value) } @@ -427,19 +432,16 @@ impl context::UnificationOps, ChalkArenas<'tcx>> &mut self, subst: CanonicalVarValues<'tcx>, constraints: Vec>, - ) -> Canonical<'gcx, ConstrainedSubst<'gcx>> { + ) -> Canonical<'tcx, ConstrainedSubst<'tcx>> { self.infcx.canonicalize_response(&ConstrainedSubst { subst, constraints }) } fn u_canonicalize_goal( &mut self, - value: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - ) -> ( - Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - UniverseMap, - ) { + value: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, + ) -> (Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, UniverseMap) { (value.clone(), UniverseMap) - } +} fn invert_goal( &mut self, @@ -463,7 +465,7 @@ impl context::UnificationOps, ChalkArenas<'tcx>> fn sink_answer_subset( &self, - value: &Canonical<'gcx, ConstrainedSubst<'gcx>>, + value: &Canonical<'tcx, ConstrainedSubst<'tcx>>, ) -> Canonical<'tcx, ConstrainedSubst<'tcx>> { value.clone() } @@ -471,7 +473,7 @@ impl context::UnificationOps, ChalkArenas<'tcx>> fn lift_delayed_literal( &self, value: DelayedLiteral>, - ) -> DelayedLiteral> { + ) -> DelayedLiteral> { match self.infcx.tcx.lift_to_global(&value) { Some(literal) => literal, None => bug!("cannot lift {:?}", value), @@ -501,13 +503,13 @@ type ChalkHhGoal<'tcx> = HhGoal>; type ChalkExClause<'tcx> = ExClause>; -impl Debug for ChalkContext<'cx, 'gcx> { +impl Debug for ChalkContext<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ChalkContext") } } -impl Debug for ChalkInferenceContext<'cx, 'gcx, 'tcx> { +impl Debug for ChalkInferenceContext<'cx, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ChalkInferenceContext") } @@ -520,7 +522,7 @@ impl ChalkContextLift<'tcx> for ChalkArenas<'a> { fn lift_ex_clause_to_tcx( ex_clause: &ChalkExClause<'a>, - tcx: TyCtxt<'_, 'gcx, 'tcx> + tcx: TyCtxt<'tcx>, ) -> Option { Some(ChalkExClause { subst: tcx.lift(&ex_clause.subst)?, @@ -532,7 +534,7 @@ impl ChalkContextLift<'tcx> for ChalkArenas<'a> { fn lift_delayed_literal_to_tcx( literal: &DelayedLiteral>, - tcx: TyCtxt<'_, 'gcx, 'tcx> + tcx: TyCtxt<'tcx>, ) -> Option { Some(match literal { DelayedLiteral::CannotProve(()) => DelayedLiteral::CannotProve(()), @@ -546,7 +548,7 @@ impl ChalkContextLift<'tcx> for ChalkArenas<'a> { fn lift_literal_to_tcx( literal: &Literal>, - tcx: TyCtxt<'_, 'gcx, 'tcx>, + tcx: TyCtxt<'tcx>, ) -> Option { Some(match literal { Literal::Negative(goal) => Literal::Negative(tcx.lift(goal)?), @@ -556,7 +558,7 @@ impl ChalkContextLift<'tcx> for ChalkArenas<'a> { } impl ExClauseFold<'tcx> for ChalkArenas<'tcx> { - fn fold_ex_clause_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>( + fn fold_ex_clause_with>( ex_clause: &ChalkExClause<'tcx>, folder: &mut F, ) -> ChalkExClause<'tcx> { @@ -568,7 +570,7 @@ impl ExClauseFold<'tcx> for ChalkArenas<'tcx> { } } - fn visit_ex_clause_with<'gcx: 'tcx, V: TypeVisitor<'tcx>>( + fn visit_ex_clause_with>( ex_clause: &ExClause, visitor: &mut V, ) -> bool { @@ -593,13 +595,13 @@ BraceStructLiftImpl! { } } -trait Upcast<'tcx, 'gcx: 'tcx>: 'gcx { +trait Upcast<'tcx>: 'tcx { type Upcasted: 'tcx; fn upcast(&self) -> Self::Upcasted; } -impl<'tcx, 'gcx: 'tcx> Upcast<'tcx, 'gcx> for DelayedLiteral> { +impl<'tcx> Upcast<'tcx> for DelayedLiteral> { type Upcasted = DelayedLiteral>; fn upcast(&self) -> Self::Upcasted { @@ -614,7 +616,7 @@ impl<'tcx, 'gcx: 'tcx> Upcast<'tcx, 'gcx> for DelayedLiteral> } } -impl<'tcx, 'gcx: 'tcx> Upcast<'tcx, 'gcx> for Literal> { +impl<'tcx> Upcast<'tcx> for Literal> { type Upcasted = Literal>; fn upcast(&self) -> Self::Upcasted { @@ -625,7 +627,7 @@ impl<'tcx, 'gcx: 'tcx> Upcast<'tcx, 'gcx> for Literal> { } } -impl<'tcx, 'gcx: 'tcx> Upcast<'tcx, 'gcx> for ExClause> { +impl<'tcx> Upcast<'tcx> for ExClause> { type Upcasted = ExClause>; fn upcast(&self) -> Self::Upcasted { @@ -644,8 +646,9 @@ impl<'tcx, 'gcx: 'tcx> Upcast<'tcx, 'gcx> for ExClause> { } } -impl<'tcx, 'gcx: 'tcx, T> Upcast<'tcx, 'gcx> for Canonical<'gcx, T> - where T: Upcast<'tcx, 'gcx> +impl<'tcx, T> Upcast<'tcx> for Canonical<'tcx, T> +where + T: Upcast<'tcx>, { type Upcasted = Canonical<'tcx, T::Upcasted>; @@ -665,13 +668,10 @@ crate fn provide(p: &mut Providers<'_>) { }; } -crate fn evaluate_goal<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - goal: ChalkCanonicalGoal<'tcx> -) -> Result< - Lrc>>, - traits::query::NoSolution -> { +crate fn evaluate_goal<'tcx>( + tcx: TyCtxt<'tcx>, + goal: ChalkCanonicalGoal<'tcx>, +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> { use crate::lowering::Lower; use rustc::traits::WellFormed; @@ -710,6 +710,6 @@ crate fn evaluate_goal<'a, 'tcx>( debug!("evaluate_goal: solution = {:?}", solution); - solution.map(|ok| Ok(Lrc::new(ok))) - .unwrap_or(Err(traits::query::NoSolution)) + solution.map(|ok| Ok(&*tcx.arena.alloc(ok))) + .unwrap_or(Err(traits::query::NoSolution)) } diff --git a/src/librustc_traits/chalk_context/program_clauses.rs b/src/librustc_traits/chalk_context/program_clauses.rs deleted file mode 100644 index 3f88d0e08b46a..0000000000000 --- a/src/librustc_traits/chalk_context/program_clauses.rs +++ /dev/null @@ -1,621 +0,0 @@ -use rustc::traits::{ - WellFormed, - FromEnv, - DomainGoal, - GoalKind, - Clause, - Clauses, - ProgramClause, - ProgramClauseCategory, - Environment, -}; -use rustc::ty; -use rustc::ty::subst::{InternalSubsts, Subst}; -use rustc::hir; -use rustc::hir::def_id::DefId; -use rustc_target::spec::abi; -use super::ChalkInferenceContext; -use crate::lowering::Lower; -use crate::generic_types; -use std::iter; - -fn assemble_clauses_from_impls<'tcx>( - tcx: ty::TyCtxt<'_, '_, 'tcx>, - trait_def_id: DefId, - clauses: &mut Vec> -) { - tcx.for_each_impl(trait_def_id, |impl_def_id| { - clauses.extend( - tcx.program_clauses_for(impl_def_id) - .into_iter() - .cloned() - ); - }); -} - -fn assemble_clauses_from_assoc_ty_values<'tcx>( - tcx: ty::TyCtxt<'_, '_, 'tcx>, - trait_def_id: DefId, - clauses: &mut Vec> -) { - tcx.for_each_impl(trait_def_id, |impl_def_id| { - for def_id in tcx.associated_item_def_ids(impl_def_id).iter() { - clauses.extend( - tcx.program_clauses_for(*def_id) - .into_iter() - .cloned() - ); - } - }); -} - -fn assemble_builtin_sized_impls<'tcx>( - tcx: ty::TyCtxt<'_, '_, 'tcx>, - sized_def_id: DefId, - ty: ty::Ty<'tcx>, - clauses: &mut Vec> -) { - let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| { - let clause = ProgramClause { - goal: ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id: sized_def_id, - substs: tcx.mk_substs_trait(ty, &[]), - }, - }.lower(), - hypotheses: tcx.mk_goals( - nested.iter() - .cloned() - .map(|nested_ty| ty::TraitRef { - def_id: sized_def_id, - substs: tcx.mk_substs_trait(nested_ty, &[]), - }) - .map(|trait_ref| ty::TraitPredicate { trait_ref }) - .map(|pred| GoalKind::DomainGoal(pred.lower())) - .map(|goal_kind| tcx.mk_goal(goal_kind)) - ), - category: ProgramClauseCategory::Other, - }; - // Bind innermost bound vars that may exist in `ty` and `nested`. - clauses.push(Clause::ForAll(ty::Binder::bind(clause))); - }; - - match &ty.sty { - // Non parametric primitive types. - ty::Bool | - ty::Char | - ty::Int(..) | - ty::Uint(..) | - ty::Float(..) | - ty::Error | - ty::Never => push_builtin_impl(ty, &[]), - - // These ones are always `Sized`. - &ty::Array(_, length) => { - push_builtin_impl(tcx.mk_ty(ty::Array(generic_types::bound(tcx, 0), length)), &[]); - } - ty::RawPtr(ptr) => { - push_builtin_impl(generic_types::raw_ptr(tcx, ptr.mutbl), &[]); - } - &ty::Ref(_, _, mutbl) => { - push_builtin_impl(generic_types::ref_ty(tcx, mutbl), &[]); - } - ty::FnPtr(fn_ptr) => { - let fn_ptr = fn_ptr.skip_binder(); - let fn_ptr = generic_types::fn_ptr( - tcx, - fn_ptr.inputs_and_output.len(), - fn_ptr.c_variadic, - fn_ptr.unsafety, - fn_ptr.abi - ); - push_builtin_impl(fn_ptr, &[]); - } - &ty::FnDef(def_id, ..) => { - push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]); - } - &ty::Closure(def_id, ..) => { - push_builtin_impl(generic_types::closure(tcx, def_id), &[]); - } - &ty::Generator(def_id, ..) => { - push_builtin_impl(generic_types::generator(tcx, def_id), &[]); - } - - // `Sized` if the last type is `Sized` (because else we will get a WF error anyway). - &ty::Tuple(type_list) => { - let type_list = generic_types::type_list(tcx, type_list.len()); - push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &**type_list); - } - - // Struct def - ty::Adt(adt_def, _) => { - let substs = InternalSubsts::bound_vars_for_item(tcx, adt_def.did); - let adt = tcx.mk_ty(ty::Adt(adt_def, substs)); - let sized_constraint = adt_def.sized_constraint(tcx) - .iter() - .map(|ty| ty.subst(tcx, substs)) - .collect::>(); - push_builtin_impl(adt, &sized_constraint); - } - - // Artificially trigger an ambiguity. - ty::Infer(..) => { - // Everybody can find at least two types to unify against: - // general ty vars, int vars and float vars. - push_builtin_impl(tcx.types.i32, &[]); - push_builtin_impl(tcx.types.u32, &[]); - push_builtin_impl(tcx.types.f32, &[]); - push_builtin_impl(tcx.types.f64, &[]); - } - - ty::Projection(_projection_ty) => { - // FIXME: add builtin impls from the associated type values found in - // trait impls of `projection_ty.trait_ref(tcx)`. - } - - // The `Sized` bound can only come from the environment. - ty::Param(..) | - ty::Placeholder(..) | - ty::UnnormalizedProjection(..) => (), - - // Definitely not `Sized`. - ty::Foreign(..) | - ty::Str | - ty::Slice(..) | - ty::Dynamic(..) | - ty::Opaque(..) => (), - - ty::Bound(..) | - ty::GeneratorWitness(..) => bug!("unexpected type {:?}", ty), - } -} - -fn wf_clause_for_raw_ptr<'tcx>( - tcx: ty::TyCtxt<'_, '_, 'tcx>, - mutbl: hir::Mutability -) -> Clauses<'tcx> { - let ptr_ty = generic_types::raw_ptr(tcx, mutbl); - - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(ptr_ty)), - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::Implies(wf_clause); - - // `forall { WellFormed(*const T). }` - tcx.mk_clauses(iter::once(wf_clause)) -} - -fn wf_clause_for_fn_ptr<'tcx>( - tcx: ty::TyCtxt<'_, '_, 'tcx>, - arity_and_output: usize, - c_variadic: bool, - unsafety: hir::Unsafety, - abi: abi::Abi -) -> Clauses<'tcx> { - let fn_ptr = generic_types::fn_ptr(tcx, arity_and_output, c_variadic, unsafety, abi); - - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(fn_ptr)), - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); - - // `forall { WellFormed(for<> fn(T1, ..., Tn) -> Tn+1). }` - // where `n + 1` == `arity_and_output` - tcx.mk_clauses(iter::once(wf_clause)) -} - -fn wf_clause_for_slice<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> { - let ty = generic_types::bound(tcx, 0); - let slice_ty = tcx.mk_slice(ty); - - let sized_trait = match tcx.lang_items().sized_trait() { - Some(def_id) => def_id, - None => return ty::List::empty(), - }; - let sized_implemented = ty::TraitRef { - def_id: sized_trait, - substs: tcx.mk_substs_trait(ty, ty::List::empty()), - }; - let sized_implemented: DomainGoal<'_> = ty::TraitPredicate { - trait_ref: sized_implemented - }.lower(); - - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(slice_ty)), - hypotheses: tcx.mk_goals( - iter::once(tcx.mk_goal(GoalKind::DomainGoal(sized_implemented))) - ), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); - - // `forall { WellFormed([T]) :- Implemented(T: Sized). }` - tcx.mk_clauses(iter::once(wf_clause)) -} - -fn wf_clause_for_array<'tcx>( - tcx: ty::TyCtxt<'_, '_, 'tcx>, - length: &'tcx ty::LazyConst<'tcx> -) -> Clauses<'tcx> { - let ty = generic_types::bound(tcx, 0); - let array_ty = tcx.mk_ty(ty::Array(ty, length)); - - let sized_trait = match tcx.lang_items().sized_trait() { - Some(def_id) => def_id, - None => return ty::List::empty(), - }; - let sized_implemented = ty::TraitRef { - def_id: sized_trait, - substs: tcx.mk_substs_trait(ty, ty::List::empty()), - }; - let sized_implemented: DomainGoal<'_> = ty::TraitPredicate { - trait_ref: sized_implemented - }.lower(); - - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(array_ty)), - hypotheses: tcx.mk_goals( - iter::once(tcx.mk_goal(GoalKind::DomainGoal(sized_implemented))) - ), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); - - // `forall { WellFormed([T; length]) :- Implemented(T: Sized). }` - tcx.mk_clauses(iter::once(wf_clause)) -} - -fn wf_clause_for_tuple<'tcx>( - tcx: ty::TyCtxt<'_, '_, 'tcx>, - arity: usize -) -> Clauses<'tcx> { - let type_list = generic_types::type_list(tcx, arity); - let tuple_ty = tcx.mk_ty(ty::Tuple(type_list)); - - let sized_trait = match tcx.lang_items().sized_trait() { - Some(def_id) => def_id, - None => return ty::List::empty(), - }; - - // If `arity == 0` (i.e. the unit type) or `arity == 1`, this list of - // hypotheses is actually empty. - let sized_implemented = type_list[0 .. std::cmp::max(arity, 1) - 1].iter() - .map(|ty| ty::TraitRef { - def_id: sized_trait, - substs: tcx.mk_substs_trait(*ty, ty::List::empty()), - }) - .map(|trait_ref| ty::TraitPredicate { trait_ref }) - .map(|predicate| predicate.lower()); - - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(tuple_ty)), - hypotheses: tcx.mk_goals( - sized_implemented.map(|domain_goal| { - tcx.mk_goal(GoalKind::DomainGoal(domain_goal)) - }) - ), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); - - // ``` - // forall { - // WellFormed((T1, ..., Tn)) :- - // Implemented(T1: Sized), - // ... - // Implemented(Tn-1: Sized). - // } - // ``` - tcx.mk_clauses(iter::once(wf_clause)) -} - -fn wf_clause_for_ref<'tcx>( - tcx: ty::TyCtxt<'_, '_, 'tcx>, - mutbl: hir::Mutability -) -> Clauses<'tcx> { - let region = tcx.mk_region( - ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0)) - ); - let ty = generic_types::bound(tcx, 1); - let ref_ty = tcx.mk_ref(region, ty::TypeAndMut { - ty, - mutbl, - }); - - let _outlives: DomainGoal<'_> = ty::OutlivesPredicate(ty, region).lower(); - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(ref_ty)), - hypotheses: ty::List::empty(), - - // FIXME: restore this later once we get better at handling regions - // hypotheses: tcx.mk_goals( - // iter::once(tcx.mk_goal(outlives.into_goal())) - // ), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); - - // `forall<'a, T> { WellFormed(&'a T) :- Outlives(T: 'a). }` - tcx.mk_clauses(iter::once(wf_clause)) -} - -fn wf_clause_for_fn_def<'tcx>( - tcx: ty::TyCtxt<'_, '_, 'tcx>, - def_id: DefId -) -> Clauses<'tcx> { - let fn_def = generic_types::fn_def(tcx, def_id); - - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(fn_def)), - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); - - // `forall { WellFormed(fn some_fn(T1, ..., Tn) -> Tn+1). }` - // where `def_id` maps to the `some_fn` function definition - tcx.mk_clauses(iter::once(wf_clause)) -} - -impl ChalkInferenceContext<'cx, 'gcx, 'tcx> { - pub(super) fn program_clauses_impl( - &self, - environment: &Environment<'tcx>, - goal: &DomainGoal<'tcx>, - ) -> Vec> { - use rustc::traits::WhereClause::*; - use rustc::infer::canonical::OriginalQueryValues; - - let goal = self.infcx.resolve_type_vars_if_possible(goal); - - debug!("program_clauses(goal = {:?})", goal); - - let mut clauses = match goal { - DomainGoal::Holds(Implemented(trait_predicate)) => { - // These come from: - // * implementations of the trait itself (rule `Implemented-From-Impl`) - // * the trait decl (rule `Implemented-From-Env`) - - let mut clauses = vec![]; - - assemble_clauses_from_impls( - self.infcx.tcx, - trait_predicate.def_id(), - &mut clauses - ); - - if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().sized_trait() { - assemble_builtin_sized_impls( - self.infcx.tcx, - trait_predicate.def_id(), - trait_predicate.self_ty(), - &mut clauses - ); - } - - // FIXME: we need to add special rules for builtin impls: - // * `Copy` / `Clone` - // * `Sized` - // * `Unsize` - // * `Generator` - // * `FnOnce` / `FnMut` / `Fn` - // * trait objects - // * auto traits - - // Rule `Implemented-From-Env` will be computed from the environment. - clauses - } - - DomainGoal::Holds(ProjectionEq(projection_predicate)) => { - // These come from: - // * the assoc type definition (rule `ProjectionEq-Placeholder`) - // * normalization of the assoc ty values (rule `ProjectionEq-Normalize`) - // * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`) - // * implied bounds from type definitions (rule `Implied-Bound-From-Type`) - - let clauses = self.infcx.tcx.program_clauses_for( - projection_predicate.projection_ty.item_def_id - ).into_iter() - - // only select `ProjectionEq-Placeholder` and `ProjectionEq-Normalize` - .filter(|clause| clause.category() == ProgramClauseCategory::Other) - - .cloned() - .collect::>(); - - // Rules `Implied-Bound-From-Trait` and `Implied-Bound-From-Type` will be computed - // from the environment. - clauses - } - - DomainGoal::Holds(RegionOutlives(..)) => { - // These come from: - // * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`) - // * implied bounds from type definitions (rule `Implied-Bound-From-Type`) - - // All of these rules are computed in the environment. - vec![] - } - - DomainGoal::Holds(TypeOutlives(..)) => { - // These come from: - // * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`) - // * implied bounds from type definitions (rule `Implied-Bound-From-Type`) - - // All of these rules are computed in the environment. - vec![] - } - - DomainGoal::WellFormed(WellFormed::Trait(trait_predicate)) => { - // These come from -- the trait decl (rule `WellFormed-TraitRef`). - self.infcx.tcx.program_clauses_for(trait_predicate.def_id()) - .into_iter() - - // only select `WellFormed-TraitRef` - .filter(|clause| clause.category() == ProgramClauseCategory::WellFormed) - - .cloned() - .collect() - } - - DomainGoal::WellFormed(WellFormed::Ty(ty)) => { - // These come from: - // * the associated type definition if `ty` refers to an unnormalized - // associated type (rule `WellFormed-AssocTy`) - // * custom rules for built-in types - // * the type definition otherwise (rule `WellFormed-Type`) - let clauses = match ty.sty { - ty::Projection(data) => { - self.infcx.tcx.program_clauses_for(data.item_def_id) - } - - // These types are always WF. - ty::Bool | - ty::Char | - ty::Int(..) | - ty::Uint(..) | - ty::Float(..) | - ty::Str | - ty::Param(..) | - ty::Placeholder(..) | - ty::Error | - ty::Never => { - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(ty)), - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::Implies(wf_clause); - - self.infcx.tcx.mk_clauses(iter::once(wf_clause)) - } - - // Always WF (recall that we do not check for parameters to be WF). - ty::RawPtr(ptr) => wf_clause_for_raw_ptr(self.infcx.tcx, ptr.mutbl), - - // Always WF (recall that we do not check for parameters to be WF). - ty::FnPtr(fn_ptr) => { - let fn_ptr = fn_ptr.skip_binder(); - wf_clause_for_fn_ptr( - self.infcx.tcx, - fn_ptr.inputs_and_output.len(), - fn_ptr.c_variadic, - fn_ptr.unsafety, - fn_ptr.abi - ) - } - - // WF if inner type is `Sized`. - ty::Slice(..) => wf_clause_for_slice(self.infcx.tcx), - - // WF if inner type is `Sized`. - ty::Array(_, length) => wf_clause_for_array(self.infcx.tcx, length), - - // WF if all types but the last one are `Sized`. - ty::Tuple(types) => wf_clause_for_tuple( - self.infcx.tcx, - types.len() - ), - - // WF if `sub_ty` outlives `region`. - ty::Ref(_, _, mutbl) => wf_clause_for_ref(self.infcx.tcx, mutbl), - - ty::FnDef(def_id, ..) => wf_clause_for_fn_def(self.infcx.tcx, def_id), - - ty::Dynamic(..) => { - // FIXME: no rules yet for trait objects - ty::List::empty() - } - - ty::Adt(def, ..) => { - self.infcx.tcx.program_clauses_for(def.did) - } - - // FIXME: these are probably wrong - ty::Foreign(def_id) | - ty::Closure(def_id, ..) | - ty::Generator(def_id, ..) | - ty::Opaque(def_id, ..) => { - self.infcx.tcx.program_clauses_for(def_id) - } - - // Artificially trigger an ambiguity. - ty::Infer(..) => { - let tcx = self.infcx.tcx; - let types = [tcx.types.i32, tcx.types.u32, tcx.types.f32, tcx.types.f64]; - let clauses = types.iter() - .cloned() - .map(|ty| ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(ty)), - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::WellFormed, - }) - .map(|clause| Clause::Implies(clause)); - tcx.mk_clauses(clauses) - } - - ty::GeneratorWitness(..) | - ty::UnnormalizedProjection(..) | - ty::Bound(..) => { - bug!("unexpected type {:?}", ty) - } - }; - - clauses.into_iter() - .filter(|clause| clause.category() == ProgramClauseCategory::WellFormed) - .cloned() - .collect() - } - - DomainGoal::FromEnv(FromEnv::Trait(..)) => { - // These come from: - // * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`) - // * implied bounds from type definitions (rule `Implied-Bound-From-Type`) - // * implied bounds from assoc type defs (rules `Implied-Trait-From-AssocTy`, - // `Implied-Bound-From-AssocTy` and `Implied-WC-From-AssocTy`) - - // All of these rules are computed in the environment. - vec![] - } - - DomainGoal::FromEnv(FromEnv::Ty(..)) => { - // There are no `FromEnv::Ty(..) :- ...` rules (this predicate only - // comes from the environment). - vec![] - } - - DomainGoal::Normalize(projection_predicate) => { - // These come from -- assoc ty values (rule `Normalize-From-Impl`). - let mut clauses = vec![]; - - assemble_clauses_from_assoc_ty_values( - self.infcx.tcx, - projection_predicate.projection_ty.trait_ref(self.infcx.tcx).def_id, - &mut clauses - ); - - clauses - } - }; - - debug!("program_clauses: clauses = {:?}", clauses); - debug!("program_clauses: adding clauses from environment = {:?}", environment); - - let mut _orig_query_values = OriginalQueryValues::default(); - let canonical_environment = self.infcx.canonicalize_query( - environment, - &mut _orig_query_values - ).value; - let env_clauses = self.infcx.tcx.program_clauses_for_env(canonical_environment); - - debug!("program_clauses: env_clauses = {:?}", env_clauses); - - clauses.extend(env_clauses.into_iter().cloned()); - clauses.extend(environment.clauses.iter().cloned()); - clauses - } -} diff --git a/src/librustc_traits/chalk_context/program_clauses/builtin.rs b/src/librustc_traits/chalk_context/program_clauses/builtin.rs new file mode 100644 index 0000000000000..71e18d2b6f949 --- /dev/null +++ b/src/librustc_traits/chalk_context/program_clauses/builtin.rs @@ -0,0 +1,327 @@ +use rustc::traits::{ + GoalKind, + Clause, + ProgramClause, + ProgramClauseCategory, +}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst::{Kind, InternalSubsts, Subst}; +use rustc::hir; +use rustc::hir::def_id::DefId; +use crate::lowering::Lower; +use crate::generic_types; + +/// Returns a predicate of the form +/// `Implemented(ty: Trait) :- Implemented(nested: Trait)...` +/// where `Trait` is specified by `trait_def_id`. +fn builtin_impl_clause( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + nested: &[Kind<'tcx>], + trait_def_id: DefId, +) -> ProgramClause<'tcx> { + ProgramClause { + goal: ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: trait_def_id, + substs: tcx.mk_substs_trait(ty, &[]), + }, + }.lower(), + hypotheses: tcx.mk_goals( + nested.iter() + .cloned() + .map(|nested_ty| ty::TraitRef { + def_id: trait_def_id, + substs: tcx.mk_substs_trait(nested_ty.expect_ty(), &[]), + }) + .map(|trait_ref| ty::TraitPredicate { trait_ref }) + .map(|pred| GoalKind::DomainGoal(pred.lower())) + .map(|goal_kind| tcx.mk_goal(goal_kind)) + ), + category: ProgramClauseCategory::Other, + } +} + +crate fn assemble_builtin_unsize_impls<'tcx>( + tcx: TyCtxt<'tcx>, + unsize_def_id: DefId, + source: Ty<'tcx>, + target: Ty<'tcx>, + clauses: &mut Vec>, +) { + match (&source.sty, &target.sty) { + (ty::Dynamic(data_a, ..), ty::Dynamic(data_b, ..)) => { + if data_a.principal_def_id() != data_b.principal_def_id() + || data_b.auto_traits().any(|b| data_a.auto_traits().all(|a| a != b)) + { + return; + } + + // FIXME: rules for trait upcast + } + + (_, &ty::Dynamic(..)) => { + // FIXME: basically, we should have something like: + // ``` + // forall { + // Implemented(T: Unsize< for<...> dyn Trait<...> >) :- + // for<...> Implemented(T: Trait<...>). + // } + // ``` + // The question is: how to correctly handle the higher-ranked + // `for<...>` binder in order to have a generic rule? + // (Having generic rules is useful for caching, as we may be able + // to turn this function and others into tcx queries later on). + } + + (ty::Array(_, length), ty::Slice(_)) => { + let ty_param = generic_types::bound(tcx, 0); + let array_ty = tcx.mk_ty(ty::Array(ty_param, length)); + let slice_ty = tcx.mk_ty(ty::Slice(ty_param)); + + // `forall { Implemented([T; N]: Unsize<[T]>). }` + let clause = ProgramClause { + goal: ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: unsize_def_id, + substs: tcx.mk_substs_trait(array_ty, &[slice_ty.into()]) + }, + }.lower(), + hypotheses: ty::List::empty(), + category: ProgramClauseCategory::Other, + }; + + clauses.push(Clause::ForAll(ty::Binder::bind(clause))); + } + + (ty::Infer(ty::TyVar(_)), _) | (_, ty::Infer(ty::TyVar(_))) => { + // FIXME: ambiguous + } + + (ty::Adt(def_id_a, ..), ty::Adt(def_id_b, ..)) => { + if def_id_a != def_id_b { + return; + } + + // FIXME: rules for struct unsizing + } + + (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => { + if tys_a.len() != tys_b.len() { + return; + } + + // FIXME: rules for tuple unsizing + } + + _ => (), + } +} + +crate fn assemble_builtin_sized_impls<'tcx>( + tcx: TyCtxt<'tcx>, + sized_def_id: DefId, + ty: Ty<'tcx>, + clauses: &mut Vec>, +) { + let mut push_builtin_impl = |ty: Ty<'tcx>, nested: &[Kind<'tcx>]| { + let clause = builtin_impl_clause(tcx, ty, nested, sized_def_id); + // Bind innermost bound vars that may exist in `ty` and `nested`. + clauses.push(Clause::ForAll(ty::Binder::bind(clause))); + }; + + match &ty.sty { + // Non parametric primitive types. + ty::Bool | + ty::Char | + ty::Int(..) | + ty::Uint(..) | + ty::Float(..) | + ty::Infer(ty::IntVar(_)) | + ty::Infer(ty::FloatVar(_)) | + ty::Error | + ty::Never => push_builtin_impl(ty, &[]), + + // These ones are always `Sized`. + &ty::Array(_, length) => { + push_builtin_impl(tcx.mk_ty(ty::Array(generic_types::bound(tcx, 0), length)), &[]); + } + ty::RawPtr(ptr) => { + push_builtin_impl(generic_types::raw_ptr(tcx, ptr.mutbl), &[]); + } + &ty::Ref(_, _, mutbl) => { + push_builtin_impl(generic_types::ref_ty(tcx, mutbl), &[]); + } + ty::FnPtr(fn_ptr) => { + let fn_ptr = fn_ptr.skip_binder(); + let fn_ptr = generic_types::fn_ptr( + tcx, + fn_ptr.inputs_and_output.len(), + fn_ptr.c_variadic, + fn_ptr.unsafety, + fn_ptr.abi + ); + push_builtin_impl(fn_ptr, &[]); + } + &ty::FnDef(def_id, ..) => { + push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]); + } + &ty::Closure(def_id, ..) => { + push_builtin_impl(generic_types::closure(tcx, def_id), &[]); + } + &ty::Generator(def_id, ..) => { + push_builtin_impl(generic_types::generator(tcx, def_id), &[]); + } + + // `Sized` if the last type is `Sized` (because else we will get a WF error anyway). + &ty::Tuple(type_list) => { + let type_list = generic_types::type_list(tcx, type_list.len()); + push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &type_list); + } + + // Struct def + ty::Adt(adt_def, _) => { + let substs = InternalSubsts::bound_vars_for_item(tcx, adt_def.did); + let adt = tcx.mk_ty(ty::Adt(adt_def, substs)); + let sized_constraint = adt_def.sized_constraint(tcx) + .iter() + .map(|ty| Kind::from(ty.subst(tcx, substs))) + .collect::>(); + push_builtin_impl(adt, &sized_constraint); + } + + // Artificially trigger an ambiguity by adding two possible types to + // unify against. + ty::Infer(ty::TyVar(_)) => { + push_builtin_impl(tcx.types.i32, &[]); + push_builtin_impl(tcx.types.f32, &[]); + } + + ty::Projection(_projection_ty) => { + // FIXME: add builtin impls from the associated type values found in + // trait impls of `projection_ty.trait_ref(tcx)`. + } + + // The `Sized` bound can only come from the environment. + ty::Param(..) | + ty::Placeholder(..) | + ty::UnnormalizedProjection(..) => (), + + // Definitely not `Sized`. + ty::Foreign(..) | + ty::Str | + ty::Slice(..) | + ty::Dynamic(..) | + ty::Opaque(..) => (), + + ty::Bound(..) | + ty::GeneratorWitness(..) | + ty::Infer(ty::FreshTy(_)) | + ty::Infer(ty::FreshIntTy(_)) | + ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty), + } +} + +crate fn assemble_builtin_copy_clone_impls<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + ty: Ty<'tcx>, + clauses: &mut Vec>, +) { + let mut push_builtin_impl = |ty: Ty<'tcx>, nested: &[Kind<'tcx>]| { + let clause = builtin_impl_clause(tcx, ty, nested, trait_def_id); + // Bind innermost bound vars that may exist in `ty` and `nested`. + clauses.push(Clause::ForAll(ty::Binder::bind(clause))); + }; + + match &ty.sty { + // Implementations provided in libcore. + ty::Bool | + ty::Char | + ty::Int(..) | + ty::Uint(..) | + ty::Float(..) | + ty::RawPtr(..) | + ty::Never | + ty::Ref(_, _, hir::MutImmutable) => (), + + // Non parametric primitive types. + ty::Infer(ty::IntVar(_)) | + ty::Infer(ty::FloatVar(_)) | + ty::Error => push_builtin_impl(ty, &[]), + + // These implement `Copy`/`Clone` if their element types do. + &ty::Array(_, length) => { + let element_ty = generic_types::bound(tcx, 0); + push_builtin_impl( + tcx.mk_ty(ty::Array(element_ty, length)), + &[Kind::from(element_ty)], + ); + } + &ty::Tuple(type_list) => { + let type_list = generic_types::type_list(tcx, type_list.len()); + push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &**type_list); + } + &ty::Closure(def_id, ..) => { + let closure_ty = generic_types::closure(tcx, def_id); + let upvar_tys: Vec<_> = match &closure_ty.sty { + ty::Closure(_, substs) => { + substs.upvar_tys(def_id, tcx).map(|ty| Kind::from(ty)).collect() + }, + _ => bug!(), + }; + push_builtin_impl(closure_ty, &upvar_tys); + } + + // These ones are always `Clone`. + ty::FnPtr(fn_ptr) => { + let fn_ptr = fn_ptr.skip_binder(); + let fn_ptr = generic_types::fn_ptr( + tcx, + fn_ptr.inputs_and_output.len(), + fn_ptr.c_variadic, + fn_ptr.unsafety, + fn_ptr.abi + ); + push_builtin_impl(fn_ptr, &[]); + } + &ty::FnDef(def_id, ..) => { + push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]); + } + + // These depend on whatever user-defined impls might exist. + ty::Adt(_, _) => (), + + // Artificially trigger an ambiguity by adding two possible types to + // unify against. + ty::Infer(ty::TyVar(_)) => { + push_builtin_impl(tcx.types.i32, &[]); + push_builtin_impl(tcx.types.f32, &[]); + } + + ty::Projection(_projection_ty) => { + // FIXME: add builtin impls from the associated type values found in + // trait impls of `projection_ty.trait_ref(tcx)`. + } + + // The `Copy`/`Clone` bound can only come from the environment. + ty::Param(..) | + ty::Placeholder(..) | + ty::UnnormalizedProjection(..) | + ty::Opaque(..) => (), + + // Definitely not `Copy`/`Clone`. + ty::Dynamic(..) | + ty::Foreign(..) | + ty::Generator(..) | + ty::Str | + ty::Slice(..) | + ty::Ref(_, _, hir::MutMutable) => (), + + ty::Bound(..) | + ty::GeneratorWitness(..) | + ty::Infer(ty::FreshTy(_)) | + ty::Infer(ty::FreshIntTy(_)) | + ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty), + } +} diff --git a/src/librustc_traits/chalk_context/program_clauses/mod.rs b/src/librustc_traits/chalk_context/program_clauses/mod.rs new file mode 100644 index 0000000000000..a49ca400f5a21 --- /dev/null +++ b/src/librustc_traits/chalk_context/program_clauses/mod.rs @@ -0,0 +1,329 @@ +mod builtin; +mod primitive; + +use rustc::traits::{ + WellFormed, + FromEnv, + DomainGoal, + Clause, + ProgramClause, + ProgramClauseCategory, + Environment, +}; +use rustc::ty::{self, TyCtxt}; +use rustc::hir::def_id::DefId; +use super::ChalkInferenceContext; +use std::iter; + +use self::primitive::*; +use self::builtin::*; + +fn assemble_clauses_from_impls<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + clauses: &mut Vec>, +) { + tcx.for_each_impl(trait_def_id, |impl_def_id| { + clauses.extend( + tcx.program_clauses_for(impl_def_id) + .into_iter() + .cloned() + ); + }); +} + +fn assemble_clauses_from_assoc_ty_values<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + clauses: &mut Vec>, +) { + tcx.for_each_impl(trait_def_id, |impl_def_id| { + for def_id in tcx.associated_item_def_ids(impl_def_id).iter() { + clauses.extend( + tcx.program_clauses_for(*def_id) + .into_iter() + .cloned() + ); + } + }); +} + +impl ChalkInferenceContext<'cx, 'tcx> { + pub(super) fn program_clauses_impl( + &self, + environment: &Environment<'tcx>, + goal: &DomainGoal<'tcx>, + ) -> Vec> { + use rustc::traits::WhereClause::*; + use rustc::infer::canonical::OriginalQueryValues; + + let goal = self.infcx.resolve_vars_if_possible(goal); + + debug!("program_clauses(goal = {:?})", goal); + + let mut clauses = match goal { + DomainGoal::Holds(Implemented(trait_predicate)) => { + // These come from: + // * implementations of the trait itself (rule `Implemented-From-Impl`) + // * the trait decl (rule `Implemented-From-Env`) + + let mut clauses = vec![]; + + assemble_clauses_from_impls( + self.infcx.tcx, + trait_predicate.def_id(), + &mut clauses + ); + + if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().sized_trait() { + assemble_builtin_sized_impls( + self.infcx.tcx, + trait_predicate.def_id(), + trait_predicate.self_ty(), + &mut clauses + ); + } + + if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().unsize_trait() { + let source = trait_predicate.self_ty(); + let target = trait_predicate.trait_ref.substs.type_at(1); + assemble_builtin_unsize_impls( + self.infcx.tcx, + trait_predicate.def_id(), + source, + target, + &mut clauses + ); + } + + if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().copy_trait() { + assemble_builtin_copy_clone_impls( + self.infcx.tcx, + trait_predicate.def_id(), + trait_predicate.self_ty(), + &mut clauses + ); + } + + if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().clone_trait() { + // For all builtin impls, the conditions for `Copy` and + // `Clone` are the same. + assemble_builtin_copy_clone_impls( + self.infcx.tcx, + trait_predicate.def_id(), + trait_predicate.self_ty(), + &mut clauses + ); + } + + // FIXME: we need to add special rules for other builtin impls: + // * `Generator` + // * `FnOnce` / `FnMut` / `Fn` + // * trait objects + // * auto traits + + // Rule `Implemented-From-Env` will be computed from the environment. + clauses + } + + DomainGoal::Holds(ProjectionEq(projection_predicate)) => { + // These come from: + // * the assoc type definition (rule `ProjectionEq-Placeholder`) + // * normalization of the assoc ty values (rule `ProjectionEq-Normalize`) + // * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`) + // * implied bounds from type definitions (rule `Implied-Bound-From-Type`) + + let clauses = self.infcx.tcx.program_clauses_for( + projection_predicate.projection_ty.item_def_id + ).into_iter() + + // only select `ProjectionEq-Placeholder` and `ProjectionEq-Normalize` + .filter(|clause| clause.category() == ProgramClauseCategory::Other) + + .cloned() + .collect::>(); + + // Rules `Implied-Bound-From-Trait` and `Implied-Bound-From-Type` will be computed + // from the environment. + clauses + } + + // For outlive requirements, just assume they hold. `ResolventOps::resolvent_clause` + // will register them as actual region constraints later. + DomainGoal::Holds(RegionOutlives(..)) | DomainGoal::Holds(TypeOutlives(..)) => { + vec![Clause::Implies(ProgramClause { + goal, + hypotheses: ty::List::empty(), + category: ProgramClauseCategory::Other, + })] + } + + DomainGoal::WellFormed(WellFormed::Trait(trait_predicate)) => { + // These come from -- the trait decl (rule `WellFormed-TraitRef`). + self.infcx.tcx.program_clauses_for(trait_predicate.def_id()) + .into_iter() + + // only select `WellFormed-TraitRef` + .filter(|clause| clause.category() == ProgramClauseCategory::WellFormed) + + .cloned() + .collect() + } + + DomainGoal::WellFormed(WellFormed::Ty(ty)) => { + // These come from: + // * the associated type definition if `ty` refers to an unnormalized + // associated type (rule `WellFormed-AssocTy`) + // * custom rules for built-in types + // * the type definition otherwise (rule `WellFormed-Type`) + let clauses = match ty.sty { + ty::Projection(data) => { + self.infcx.tcx.program_clauses_for(data.item_def_id) + } + + // These types are always WF. + ty::Bool | + ty::Char | + ty::Int(..) | + ty::Uint(..) | + ty::Float(..) | + ty::Str | + ty::Param(..) | + ty::Placeholder(..) | + ty::Error | + ty::Never => { + let wf_clause = ProgramClause { + goal, + hypotheses: ty::List::empty(), + category: ProgramClauseCategory::WellFormed, + }; + let wf_clause = Clause::Implies(wf_clause); + + self.infcx.tcx.mk_clauses(iter::once(wf_clause)) + } + + // Always WF (recall that we do not check for parameters to be WF). + ty::RawPtr(ptr) => wf_clause_for_raw_ptr(self.infcx.tcx, ptr.mutbl), + + // Always WF (recall that we do not check for parameters to be WF). + ty::FnPtr(fn_ptr) => { + let fn_ptr = fn_ptr.skip_binder(); + wf_clause_for_fn_ptr( + self.infcx.tcx, + fn_ptr.inputs_and_output.len(), + fn_ptr.c_variadic, + fn_ptr.unsafety, + fn_ptr.abi + ) + } + + // WF if inner type is `Sized`. + ty::Slice(..) => wf_clause_for_slice(self.infcx.tcx), + + // WF if inner type is `Sized`. + ty::Array(_, length) => wf_clause_for_array(self.infcx.tcx, length), + + // WF if all types but the last one are `Sized`. + ty::Tuple(types) => wf_clause_for_tuple( + self.infcx.tcx, + types.len() + ), + + // WF if `sub_ty` outlives `region`. + ty::Ref(_, _, mutbl) => wf_clause_for_ref(self.infcx.tcx, mutbl), + + ty::FnDef(def_id, ..) => wf_clause_for_fn_def(self.infcx.tcx, def_id), + + ty::Dynamic(..) => { + // FIXME: no rules yet for trait objects + ty::List::empty() + } + + ty::Adt(def, ..) => { + self.infcx.tcx.program_clauses_for(def.did) + } + + // FIXME: these are probably wrong + ty::Foreign(def_id) | + ty::Closure(def_id, ..) | + ty::Generator(def_id, ..) | + ty::Opaque(def_id, ..) => { + self.infcx.tcx.program_clauses_for(def_id) + } + + // Artificially trigger an ambiguity. + ty::Infer(..) => { + let tcx = self.infcx.tcx; + let types = [tcx.types.i32, tcx.types.u32, tcx.types.f32, tcx.types.f64]; + let clauses = types.iter() + .cloned() + .map(|ty| ProgramClause { + goal: DomainGoal::WellFormed(WellFormed::Ty(ty)), + hypotheses: ty::List::empty(), + category: ProgramClauseCategory::WellFormed, + }) + .map(|clause| Clause::Implies(clause)); + tcx.mk_clauses(clauses) + } + + ty::GeneratorWitness(..) | + ty::UnnormalizedProjection(..) | + ty::Bound(..) => { + bug!("unexpected type {:?}", ty) + } + }; + + clauses.into_iter() + .filter(|clause| clause.category() == ProgramClauseCategory::WellFormed) + .cloned() + .collect() + } + + DomainGoal::FromEnv(FromEnv::Trait(..)) => { + // These come from: + // * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`) + // * implied bounds from type definitions (rule `Implied-Bound-From-Type`) + // * implied bounds from assoc type defs (rules `Implied-Trait-From-AssocTy`, + // `Implied-Bound-From-AssocTy` and `Implied-WC-From-AssocTy`) + + // All of these rules are computed in the environment. + vec![] + } + + DomainGoal::FromEnv(FromEnv::Ty(..)) => { + // There are no `FromEnv::Ty(..) :- ...` rules (this predicate only + // comes from the environment). + vec![] + } + + DomainGoal::Normalize(projection_predicate) => { + // These come from -- assoc ty values (rule `Normalize-From-Impl`). + let mut clauses = vec![]; + + assemble_clauses_from_assoc_ty_values( + self.infcx.tcx, + projection_predicate.projection_ty.trait_ref(self.infcx.tcx).def_id, + &mut clauses + ); + + clauses + } + }; + + debug!("program_clauses: clauses = {:?}", clauses); + debug!("program_clauses: adding clauses from environment = {:?}", environment); + + let mut _orig_query_values = OriginalQueryValues::default(); + let canonical_environment = self.infcx.canonicalize_query( + environment, + &mut _orig_query_values + ).value; + let env_clauses = self.infcx.tcx.program_clauses_for_env(canonical_environment); + + debug!("program_clauses: env_clauses = {:?}", env_clauses); + + clauses.extend(env_clauses.into_iter().cloned()); + clauses.extend(environment.clauses.iter().cloned()); + clauses + } +} diff --git a/src/librustc_traits/chalk_context/program_clauses/primitive.rs b/src/librustc_traits/chalk_context/program_clauses/primitive.rs new file mode 100644 index 0000000000000..8e4b9da6de268 --- /dev/null +++ b/src/librustc_traits/chalk_context/program_clauses/primitive.rs @@ -0,0 +1,192 @@ +use rustc::traits::{ + WellFormed, + DomainGoal, + GoalKind, + Clause, + Clauses, + ProgramClause, + ProgramClauseCategory, +}; +use rustc::ty::{self, TyCtxt}; +use rustc::hir; +use rustc::hir::def_id::DefId; +use rustc_target::spec::abi; +use crate::lowering::Lower; +use crate::generic_types; +use std::iter; + +crate fn wf_clause_for_raw_ptr<'tcx>(tcx: TyCtxt<'tcx>, mutbl: hir::Mutability) -> Clauses<'tcx> { + let ptr_ty = generic_types::raw_ptr(tcx, mutbl); + + let wf_clause = ProgramClause { + goal: DomainGoal::WellFormed(WellFormed::Ty(ptr_ty)), + hypotheses: ty::List::empty(), + category: ProgramClauseCategory::WellFormed, + }; + let wf_clause = Clause::Implies(wf_clause); + + // `forall { WellFormed(*const T). }` + tcx.mk_clauses(iter::once(wf_clause)) +} + +crate fn wf_clause_for_fn_ptr<'tcx>( + tcx: TyCtxt<'tcx>, + arity_and_output: usize, + variadic: bool, + unsafety: hir::Unsafety, + abi: abi::Abi, +) -> Clauses<'tcx> { + let fn_ptr = generic_types::fn_ptr(tcx, arity_and_output, variadic, unsafety, abi); + + let wf_clause = ProgramClause { + goal: DomainGoal::WellFormed(WellFormed::Ty(fn_ptr)), + hypotheses: ty::List::empty(), + category: ProgramClauseCategory::WellFormed, + }; + let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); + + // `forall { WellFormed(for<> fn(T1, ..., Tn) -> Tn+1). }` + // where `n + 1` == `arity_and_output` + tcx.mk_clauses(iter::once(wf_clause)) +} + +crate fn wf_clause_for_slice<'tcx>(tcx: TyCtxt<'tcx>) -> Clauses<'tcx> { + let ty = generic_types::bound(tcx, 0); + let slice_ty = tcx.mk_slice(ty); + + let sized_trait = match tcx.lang_items().sized_trait() { + Some(def_id) => def_id, + None => return ty::List::empty(), + }; + let sized_implemented = ty::TraitRef { + def_id: sized_trait, + substs: tcx.mk_substs_trait(ty, ty::List::empty()), + }; + let sized_implemented: DomainGoal<'_> = ty::TraitPredicate { + trait_ref: sized_implemented + }.lower(); + + let wf_clause = ProgramClause { + goal: DomainGoal::WellFormed(WellFormed::Ty(slice_ty)), + hypotheses: tcx.mk_goals( + iter::once(tcx.mk_goal(GoalKind::DomainGoal(sized_implemented))) + ), + category: ProgramClauseCategory::WellFormed, + }; + let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); + + // `forall { WellFormed([T]) :- Implemented(T: Sized). }` + tcx.mk_clauses(iter::once(wf_clause)) +} + +crate fn wf_clause_for_array<'tcx>( + tcx: TyCtxt<'tcx>, + length: &'tcx ty::Const<'tcx>, +) -> Clauses<'tcx> { + let ty = generic_types::bound(tcx, 0); + let array_ty = tcx.mk_ty(ty::Array(ty, length)); + + let sized_trait = match tcx.lang_items().sized_trait() { + Some(def_id) => def_id, + None => return ty::List::empty(), + }; + let sized_implemented = ty::TraitRef { + def_id: sized_trait, + substs: tcx.mk_substs_trait(ty, ty::List::empty()), + }; + let sized_implemented: DomainGoal<'_> = ty::TraitPredicate { + trait_ref: sized_implemented + }.lower(); + + let wf_clause = ProgramClause { + goal: DomainGoal::WellFormed(WellFormed::Ty(array_ty)), + hypotheses: tcx.mk_goals( + iter::once(tcx.mk_goal(GoalKind::DomainGoal(sized_implemented))) + ), + category: ProgramClauseCategory::WellFormed, + }; + let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); + + // `forall { WellFormed([T; length]) :- Implemented(T: Sized). }` + tcx.mk_clauses(iter::once(wf_clause)) +} + +crate fn wf_clause_for_tuple<'tcx>(tcx: TyCtxt<'tcx>, arity: usize) -> Clauses<'tcx> { + let type_list = generic_types::type_list(tcx, arity); + let tuple_ty = tcx.mk_ty(ty::Tuple(type_list)); + + let sized_trait = match tcx.lang_items().sized_trait() { + Some(def_id) => def_id, + None => return ty::List::empty(), + }; + + // If `arity == 0` (i.e. the unit type) or `arity == 1`, this list of + // hypotheses is actually empty. + let sized_implemented = type_list[0 .. std::cmp::max(arity, 1) - 1].iter() + .map(|ty| ty::TraitRef { + def_id: sized_trait, + substs: tcx.mk_substs_trait(ty.expect_ty(), ty::List::empty()), + }) + .map(|trait_ref| ty::TraitPredicate { trait_ref }) + .map(|predicate| predicate.lower()); + + let wf_clause = ProgramClause { + goal: DomainGoal::WellFormed(WellFormed::Ty(tuple_ty)), + hypotheses: tcx.mk_goals( + sized_implemented.map(|domain_goal| { + tcx.mk_goal(GoalKind::DomainGoal(domain_goal)) + }) + ), + category: ProgramClauseCategory::WellFormed, + }; + let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); + + // ``` + // forall { + // WellFormed((T1, ..., Tn)) :- + // Implemented(T1: Sized), + // ... + // Implemented(Tn-1: Sized). + // } + // ``` + tcx.mk_clauses(iter::once(wf_clause)) +} + +crate fn wf_clause_for_ref<'tcx>(tcx: TyCtxt<'tcx>, mutbl: hir::Mutability) -> Clauses<'tcx> { + let region = tcx.mk_region( + ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0)) + ); + let ty = generic_types::bound(tcx, 1); + let ref_ty = tcx.mk_ref(region, ty::TypeAndMut { + ty, + mutbl, + }); + + let outlives: DomainGoal<'_> = ty::OutlivesPredicate(ty, region).lower(); + let wf_clause = ProgramClause { + goal: DomainGoal::WellFormed(WellFormed::Ty(ref_ty)), + hypotheses: tcx.mk_goals( + iter::once(tcx.mk_goal(outlives.into_goal())) + ), + category: ProgramClauseCategory::WellFormed, + }; + let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); + + // `forall<'a, T> { WellFormed(&'a T) :- Outlives(T: 'a). }` + tcx.mk_clauses(iter::once(wf_clause)) +} + +crate fn wf_clause_for_fn_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Clauses<'tcx> { + let fn_def = generic_types::fn_def(tcx, def_id); + + let wf_clause = ProgramClause { + goal: DomainGoal::WellFormed(WellFormed::Ty(fn_def)), + hypotheses: ty::List::empty(), + category: ProgramClauseCategory::WellFormed, + }; + let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); + + // `forall { WellFormed(fn some_fn(T1, ..., Tn) -> Tn+1). }` + // where `def_id` maps to the `some_fn` function definition + tcx.mk_clauses(iter::once(wf_clause)) +} diff --git a/src/librustc_traits/chalk_context/resolvent_ops.rs b/src/librustc_traits/chalk_context/resolvent_ops.rs index 932501cc04fe0..59c01b8b1b7b1 100644 --- a/src/librustc_traits/chalk_context/resolvent_ops.rs +++ b/src/librustc_traits/chalk_context/resolvent_ops.rs @@ -8,6 +8,7 @@ use rustc::infer::{InferCtxt, LateBoundRegionConversionTime}; use rustc::infer::canonical::{Canonical, CanonicalVarValues}; use rustc::traits::{ DomainGoal, + WhereClause, Goal, GoalKind, Clause, @@ -15,16 +16,17 @@ use rustc::traits::{ Environment, InEnvironment, }; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, TyCtxt, InferConst}; use rustc::ty::subst::Kind; use rustc::ty::relate::{Relate, RelateResult, TypeRelation}; +use rustc::mir::interpret::ConstValue; use syntax_pos::DUMMY_SP; use super::{ChalkInferenceContext, ChalkArenas, ChalkExClause, ConstrainedSubst}; use super::unify::*; -impl context::ResolventOps, ChalkArenas<'tcx>> - for ChalkInferenceContext<'cx, 'gcx, 'tcx> +impl context::ResolventOps, ChalkArenas<'tcx>> + for ChalkInferenceContext<'cx, 'tcx> { fn resolvent_clause( &mut self, @@ -32,7 +34,7 @@ impl context::ResolventOps, ChalkArenas<'tcx>> goal: &DomainGoal<'tcx>, subst: &CanonicalVarValues<'tcx>, clause: &Clause<'tcx>, - ) -> Fallible>> { + ) -> Fallible>> { use chalk_engine::context::UnificationOps; debug!("resolvent_clause(goal = {:?}, clause = {:?})", goal, clause); @@ -75,6 +77,23 @@ impl context::ResolventOps, ChalkArenas<'tcx>> }) ); + // If we have a goal of the form `T: 'a` or `'a: 'b`, then just + // assume it is true (no subgoals) and register it as a constraint + // instead. + match goal { + DomainGoal::Holds(WhereClause::RegionOutlives(pred)) => { + assert_eq!(ex_clause.subgoals.len(), 0); + ex_clause.constraints.push(ty::OutlivesPredicate(pred.0.into(), pred.1)); + } + + DomainGoal::Holds(WhereClause::TypeOutlives(pred)) => { + assert_eq!(ex_clause.subgoals.len(), 0); + ex_clause.constraints.push(ty::OutlivesPredicate(pred.0.into(), pred.1)); + } + + _ => (), + }; + let canonical_ex_clause = self.canonicalize_ex_clause(&ex_clause); Ok(canonical_ex_clause) }); @@ -87,13 +106,13 @@ impl context::ResolventOps, ChalkArenas<'tcx>> &mut self, ex_clause: ChalkExClause<'tcx>, selected_goal: &InEnvironment<'tcx, Goal<'tcx>>, - answer_table_goal: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - canonical_answer_subst: &Canonical<'gcx, ConstrainedSubst<'gcx>>, + answer_table_goal: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, + canonical_answer_subst: &Canonical<'tcx, ConstrainedSubst<'tcx>>, ) -> Fallible> { debug!( "apply_answer_subst(ex_clause = {:?}, selected_goal = {:?})", - self.infcx.resolve_type_vars_if_possible(&ex_clause), - self.infcx.resolve_type_vars_if_possible(selected_goal) + self.infcx.resolve_vars_if_possible(&ex_clause), + self.infcx.resolve_vars_if_possible(selected_goal) ); let (answer_subst, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars( @@ -112,25 +131,23 @@ impl context::ResolventOps, ChalkArenas<'tcx>> substitutor.relate(&answer_table_goal.value, &selected_goal) .map_err(|_| NoSolution)?; - let ex_clause = substitutor.ex_clause; - - // FIXME: restore this later once we get better at handling regions - // ex_clause.constraints.extend(answer_subst.constraints); + let mut ex_clause = substitutor.ex_clause; + ex_clause.constraints.extend(answer_subst.constraints); debug!("apply_answer_subst: ex_clause = {:?}", ex_clause); Ok(ex_clause) } } -struct AnswerSubstitutor<'cx, 'gcx: 'tcx, 'tcx: 'cx> { - infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, +struct AnswerSubstitutor<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, environment: Environment<'tcx>, answer_subst: CanonicalVarValues<'tcx>, binder_index: ty::DebruijnIndex, ex_clause: ChalkExClause<'tcx>, } -impl AnswerSubstitutor<'cx, 'gcx, 'tcx> { +impl AnswerSubstitutor<'cx, 'tcx> { fn unify_free_answer_var( &mut self, answer_var: ty::BoundVar, @@ -152,8 +169,8 @@ impl AnswerSubstitutor<'cx, 'gcx, 'tcx> { } } -impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> { - fn tcx(&self) -> ty::TyCtxt<'cx, 'gcx, 'tcx> { +impl TypeRelation<'tcx> for AnswerSubstitutor<'cx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -259,4 +276,44 @@ impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> { Ok(a) } + + fn consts( + &mut self, + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + if let ty::Const { + val: ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)), + .. + } = a { + if *debruijn == self.binder_index { + self.unify_free_answer_var(*bound_ct, b.into())?; + return Ok(b); + } + } + + match (a, b) { + ( + ty::Const { + val: ConstValue::Infer(InferConst::Canonical(a_debruijn, a_bound)), + .. + }, + ty::Const { + val: ConstValue::Infer(InferConst::Canonical(b_debruijn, b_bound)), + .. + }, + ) => { + assert_eq!(a_debruijn, b_debruijn); + assert_eq!(a_bound, b_bound); + Ok(a) + } + + // Everything else should just be a perfect match as well, + // and we forbid inference variables. + _ => match ty::relate::super_relate_consts(self, a, b) { + Ok(ct) => Ok(ct), + Err(err) => bug!("const mismatch in `AnswerSubstitutor`: {}", err), + } + } + } } diff --git a/src/librustc_traits/chalk_context/unify.rs b/src/librustc_traits/chalk_context/unify.rs index abb4812734123..1f9090324414b 100644 --- a/src/librustc_traits/chalk_context/unify.rs +++ b/src/librustc_traits/chalk_context/unify.rs @@ -10,12 +10,12 @@ crate struct UnificationResult<'tcx> { crate constraints: Vec>, } -crate fn unify<'me, 'gcx, 'tcx, T: Relate<'tcx>>( - infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, +crate fn unify<'me, 'tcx, T: Relate<'tcx>>( + infcx: &'me InferCtxt<'me, 'tcx>, environment: Environment<'tcx>, variance: ty::Variance, a: &T, - b: &T + b: &T, ) -> RelateResult<'tcx, UnificationResult<'tcx>> { debug!("unify( a = {:?}, @@ -42,18 +42,15 @@ crate fn unify<'me, 'gcx, 'tcx, T: Relate<'tcx>>( }) } -struct ChalkTypeRelatingDelegate<'me, 'gcx: 'tcx, 'tcx: 'me> { - infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, +struct ChalkTypeRelatingDelegate<'me, 'tcx> { + infcx: &'me InferCtxt<'me, 'tcx>, environment: Environment<'tcx>, goals: Vec>>, constraints: Vec>, } -impl ChalkTypeRelatingDelegate<'me, 'gcx, 'tcx> { - fn new( - infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, - environment: Environment<'tcx>, - ) -> Self { +impl ChalkTypeRelatingDelegate<'me, 'tcx> { + fn new(infcx: &'me InferCtxt<'me, 'tcx>, environment: Environment<'tcx>) -> Self { Self { infcx, environment, @@ -63,7 +60,7 @@ impl ChalkTypeRelatingDelegate<'me, 'gcx, 'tcx> { } } -impl TypeRelatingDelegate<'tcx> for &mut ChalkTypeRelatingDelegate<'_, '_, 'tcx> { +impl TypeRelatingDelegate<'tcx> for &mut ChalkTypeRelatingDelegate<'_, 'tcx> { fn create_next_universe(&mut self) -> ty::UniverseIndex { self.infcx.create_next_universe() } diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 49fcb7cd83355..3abd7e90cf10f 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -7,7 +7,6 @@ use rustc::ty::query::Providers; use rustc::ty::subst::{Subst, InternalSubsts}; use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt}; use rustc::util::nodemap::FxHashSet; -use rustc_data_structures::sync::Lrc; use syntax::source_map::{Span, DUMMY_SP}; crate fn provide(p: &mut Providers<'_>) { @@ -19,9 +18,9 @@ crate fn provide(p: &mut Providers<'_>) { } fn dropck_outlives<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, canonical_goal: CanonicalTyGoal<'tcx>, -) -> Result>>>, NoSolution> { +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, NoSolution> { debug!("dropck_outlives(goal={:#?})", canonical_goal); tcx.infer_ctxt().enter_with_canonical( @@ -147,8 +146,8 @@ fn dropck_outlives<'tcx>( /// Returns a set of constraints that needs to be satisfied in /// order for `ty` to be valid for destruction. -fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, +fn dtorck_constraint_for_ty<'tcx>( + tcx: TyCtxt<'tcx>, span: Span, for_ty: Ty<'tcx>, depth: usize, @@ -191,7 +190,7 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>( } ty::Tuple(tys) => tys.iter() - .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty)) + .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty.expect_ty())) .collect(), ty::Closure(def_id, substs) => substs @@ -280,8 +279,8 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>( } /// Calculates the dtorck constraint for a type. -crate fn adt_dtorck_constraint<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +crate fn adt_dtorck_constraint<'tcx>( + tcx: TyCtxt<'tcx>, def_id: DefId, ) -> Result, NoSolution> { let def = tcx.adt_def(def_id); diff --git a/src/librustc_traits/evaluate_obligation.rs b/src/librustc_traits/evaluate_obligation.rs index 83aebd16e2400..30a1814d0f83e 100644 --- a/src/librustc_traits/evaluate_obligation.rs +++ b/src/librustc_traits/evaluate_obligation.rs @@ -14,7 +14,7 @@ crate fn provide(p: &mut Providers<'_>) { } fn evaluate_obligation<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, canonical_goal: CanonicalPredicateGoal<'tcx>, ) -> Result { tcx.infer_ctxt().enter_with_canonical( @@ -29,7 +29,7 @@ fn evaluate_obligation<'tcx>( let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical); let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); - selcx.evaluate_obligation_recursively(&obligation) + selcx.evaluate_root_obligation(&obligation) }, ) } diff --git a/src/librustc_traits/generic_types.rs b/src/librustc_traits/generic_types.rs index f2ce9631f35ab..bd2ed94b18d59 100644 --- a/src/librustc_traits/generic_types.rs +++ b/src/librustc_traits/generic_types.rs @@ -1,12 +1,12 @@ //! Utilities for creating generic types with bound vars in place of parameter values. use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::subst::InternalSubsts; +use rustc::ty::subst::{Kind, SubstsRef, InternalSubsts}; use rustc::hir; use rustc::hir::def_id::DefId; use rustc_target::spec::abi; -crate fn bound(tcx: ty::TyCtxt<'_, '_, 'tcx>, index: u32) -> Ty<'tcx> { +crate fn bound(tcx: TyCtxt<'tcx>, index: u32) -> Ty<'tcx> { let ty = ty::Bound( ty::INNERMOST, ty::BoundVar::from_u32(index).into() @@ -14,7 +14,7 @@ crate fn bound(tcx: ty::TyCtxt<'_, '_, 'tcx>, index: u32) -> Ty<'tcx> { tcx.mk_ty(ty) } -crate fn raw_ptr(tcx: TyCtxt<'_, '_, 'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> { +crate fn raw_ptr(tcx: TyCtxt<'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> { tcx.mk_ptr(ty::TypeAndMut { ty: bound(tcx, 0), mutbl, @@ -22,11 +22,11 @@ crate fn raw_ptr(tcx: TyCtxt<'_, '_, 'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> } crate fn fn_ptr( - tcx: ty::TyCtxt<'_, '_, 'tcx>, + tcx: TyCtxt<'tcx>, arity_and_output: usize, c_variadic: bool, unsafety: hir::Unsafety, - abi: abi::Abi + abi: abi::Abi, ) -> Ty<'tcx> { let inputs_and_output = tcx.mk_type_list( (0..arity_and_output).into_iter() @@ -44,15 +44,16 @@ crate fn fn_ptr( tcx.mk_fn_ptr(fn_sig) } -crate fn type_list(tcx: ty::TyCtxt<'_, '_, 'tcx>, arity: usize) -> &'tcx ty::List> { - tcx.mk_type_list( +crate fn type_list(tcx: TyCtxt<'tcx>, arity: usize) -> SubstsRef<'tcx> { + tcx.mk_substs( (0..arity).into_iter() .map(|i| ty::BoundVar::from(i)) .map(|var| tcx.mk_ty(ty::Bound(ty::INNERMOST, var.into()))) + .map(|ty| Kind::from(ty)) ) } -crate fn ref_ty(tcx: ty::TyCtxt<'_, '_, 'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> { +crate fn ref_ty(tcx: TyCtxt<'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> { let region = tcx.mk_region( ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0)) ); @@ -63,17 +64,17 @@ crate fn ref_ty(tcx: ty::TyCtxt<'_, '_, 'tcx>, mutbl: hir::Mutability) -> Ty<'tc }) } -crate fn fn_def(tcx: ty::TyCtxt<'_, '_, 'tcx>, def_id: DefId) -> Ty<'tcx> { +crate fn fn_def(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> { tcx.mk_ty(ty::FnDef(def_id, InternalSubsts::bound_vars_for_item(tcx, def_id))) } -crate fn closure(tcx: ty::TyCtxt<'_, '_, 'tcx>, def_id: DefId) -> Ty<'tcx> { +crate fn closure(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> { tcx.mk_closure(def_id, ty::ClosureSubsts { substs: InternalSubsts::bound_vars_for_item(tcx, def_id), }) } -crate fn generator(tcx: ty::TyCtxt<'_, '_, 'tcx>, def_id: DefId) -> Ty<'tcx> { +crate fn generator(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> { tcx.mk_generator(def_id, ty::GeneratorSubsts { substs: InternalSubsts::bound_vars_for_item(tcx, def_id), }, hir::GeneratorMovability::Movable) diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index dad45130062a4..7f9ebdc79c276 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -15,8 +15,6 @@ use smallvec::{SmallVec, smallvec}; use syntax::source_map::DUMMY_SP; use rustc::traits::FulfillmentContext; -use rustc_data_structures::sync::Lrc; - crate fn provide(p: &mut Providers<'_>) { *p = Providers { implied_outlives_bounds, @@ -25,11 +23,11 @@ crate fn provide(p: &mut Providers<'_>) { } fn implied_outlives_bounds<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, goal: CanonicalTyGoal<'tcx>, ) -> Result< - Lrc>>>>, - NoSolution, + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec>>>, + NoSolution, > { tcx.infer_ctxt() .enter_canonical_trait_query(&goal, |infcx, _fulfill_cx, key| { @@ -39,9 +37,9 @@ fn implied_outlives_bounds<'tcx>( } fn compute_implied_outlives_bounds<'tcx>( - infcx: &InferCtxt<'_, '_, 'tcx>, + infcx: &InferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx> + ty: Ty<'tcx>, ) -> Fallible>> { let tcx = infcx.tcx; @@ -123,7 +121,7 @@ fn compute_implied_outlives_bounds<'tcx>( ty::Predicate::TypeOutlives(ref data) => match data.no_bound_vars() { None => vec![], Some(ty::OutlivesPredicate(ty_a, r_b)) => { - let ty_a = infcx.resolve_type_vars_if_possible(&ty_a); + let ty_a = infcx.resolve_vars_if_possible(&ty_a); let mut components = smallvec![]; tcx.push_outlives_components(ty_a, &mut components); implied_bounds_from_components(r_b, components) diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index d52a976981db0..7311fd96dadc7 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -2,6 +2,8 @@ //! the guts are broken up into modules; see the comments in those modules. #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index 962a145814c8b..0173685583148 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -10,17 +10,14 @@ use rustc::traits::{ use rustc::ty::{self, TyCtxt, Ty}; use rustc::hir::def_id::DefId; use rustc_data_structures::fx::FxHashSet; -use super::Lower; -use crate::generic_types; -use std::iter; -struct ClauseVisitor<'set, 'a, 'tcx: 'a + 'set> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - round: &'set mut FxHashSet>, +struct ClauseVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + round: &'a mut FxHashSet>, } -impl ClauseVisitor<'set, 'a, 'tcx> { - fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, round: &'set mut FxHashSet>) -> Self { +impl ClauseVisitor<'a, 'tcx> { + fn new(tcx: TyCtxt<'tcx>, round: &'a mut FxHashSet>) -> Self { ClauseVisitor { tcx, round, @@ -38,30 +35,6 @@ impl ClauseVisitor<'set, 'a, 'tcx> { ); } - // forall<'a, T> { `Outlives(T: 'a) :- FromEnv(&'a T)` } - ty::Ref(_, _, mutbl) => { - let region = self.tcx.mk_region( - ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0)) - ); - let ty = generic_types::bound(self.tcx, 1); - let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut { - ty, - mutbl, - }); - - let from_env = DomainGoal::FromEnv(FromEnv::Ty(ref_ty)); - - let clause = ProgramClause { - goal: ty::OutlivesPredicate(ty, region).lower(), - hypotheses: self.tcx.mk_goals( - iter::once(self.tcx.mk_goal(from_env.into_goal())) - ), - category: ProgramClauseCategory::ImpliedBound, - }; - let clause = Clause::ForAll(ty::Binder::bind(clause)); - self.round.insert(clause); - } - ty::Dynamic(..) => { // FIXME: trait object rules are not yet implemented } @@ -99,6 +72,7 @@ impl ClauseVisitor<'set, 'a, 'tcx> { ty::RawPtr(..) | ty::FnPtr(..) | ty::Tuple(..) | + ty::Ref(..) | ty::Never | ty::Infer(..) | ty::Placeholder(..) | @@ -153,8 +127,8 @@ impl ClauseVisitor<'set, 'a, 'tcx> { } } -crate fn program_clauses_for_env<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +crate fn program_clauses_for_env<'tcx>( + tcx: TyCtxt<'tcx>, environment: Environment<'tcx>, ) -> Clauses<'tcx> { debug!("program_clauses_for_env(environment={:?})", environment); @@ -186,10 +160,7 @@ crate fn program_clauses_for_env<'a, 'tcx>( ); } -crate fn environment<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId -) -> Environment<'tcx> { +crate fn environment<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Environment<'tcx> { use super::{Lower, IntoFromEnvGoal}; use rustc::hir::{Node, TraitItemKind, ImplItemKind, ItemKind, ForeignItemKind}; @@ -213,8 +184,8 @@ crate fn environment<'a, 'tcx>( // could bound lifetimes. .map(Clause::ForAll); - let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); - let node = tcx.hir().get(node_id); + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let node = tcx.hir().get(hir_id); enum NodeKind { TraitImpl, diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index 44883d438a1e5..2a6613101614d 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -1,5 +1,6 @@ mod environment; +use rustc::hir::def::DefKind; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::hir::map::definitions::DefPathData; @@ -20,6 +21,7 @@ use rustc::ty::query::Providers; use rustc::ty::{self, List, TyCtxt}; use rustc::ty::subst::{Subst, InternalSubsts}; use syntax::ast; +use syntax::symbol::sym; use std::iter; @@ -153,25 +155,33 @@ impl<'tcx> IntoWellFormedGoal for DomainGoal<'tcx> { } } -crate fn program_clauses_for<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, -) -> Clauses<'tcx> { +crate fn program_clauses_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Clauses<'tcx> { + // FIXME(eddyb) this should only be using `def_kind`. match tcx.def_key(def_id).disambiguated_data.data { - DefPathData::Trait(_) | - DefPathData::TraitAlias(_) => program_clauses_for_trait(tcx, def_id), + DefPathData::TypeNs(..) => match tcx.def_kind(def_id) { + Some(DefKind::Trait) + | Some(DefKind::TraitAlias) => program_clauses_for_trait(tcx, def_id), + // FIXME(eddyb) deduplicate this `associated_item` call with + // `program_clauses_for_associated_type_{value,def}`. + Some(DefKind::AssocTy) => match tcx.associated_item(def_id).container { + ty::AssocItemContainer::ImplContainer(_) => + program_clauses_for_associated_type_value(tcx, def_id), + ty::AssocItemContainer::TraitContainer(_) => + program_clauses_for_associated_type_def(tcx, def_id) + }, + Some(DefKind::Struct) + | Some(DefKind::Enum) + | Some(DefKind::TyAlias) + | Some(DefKind::Union) + | Some(DefKind::Existential) => program_clauses_for_type_def(tcx, def_id), + _ => List::empty(), + }, DefPathData::Impl => program_clauses_for_impl(tcx, def_id), - DefPathData::AssocTypeInImpl(..) => program_clauses_for_associated_type_value(tcx, def_id), - DefPathData::AssocTypeInTrait(..) => program_clauses_for_associated_type_def(tcx, def_id), - DefPathData::TypeNs(..) => program_clauses_for_type_def(tcx, def_id), _ => List::empty(), } } -fn program_clauses_for_trait<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, -) -> Clauses<'tcx> { +fn program_clauses_for_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Clauses<'tcx> { // `trait Trait where WC { .. } // P0 == Self` // Rule Implemented-From-Env (see rustc guide) @@ -209,6 +219,10 @@ fn program_clauses_for_trait<'a, 'tcx>( let implemented_from_env = Clause::ForAll(ty::Binder::bind(implemented_from_env)); let predicates = &tcx.predicates_defined_on(def_id).predicates; + + // Warning: these where clauses are not substituted for bound vars yet, + // so that we don't need to adjust binders in the `FromEnv` rules below + // (see the FIXME). let where_clauses = &predicates .iter() .map(|(wc, _)| wc.lower()) @@ -258,6 +272,7 @@ fn program_clauses_for_trait<'a, 'tcx>( // `WellFormed(WC)` let wf_conditions = where_clauses .into_iter() + .map(|wc| wc.subst(tcx, bound_vars)) .map(|wc| wc.map_bound(|goal| goal.into_well_formed_goal())); // `WellFormed(Self: Trait) :- Implemented(Self: Trait) && WellFormed(WC)` @@ -279,7 +294,7 @@ fn program_clauses_for_trait<'a, 'tcx>( ) } -fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Clauses<'tcx> { +fn program_clauses_for_impl(tcx: TyCtxt<'tcx>, def_id: DefId) -> Clauses<'tcx> { if let ImplPolarity::Negative = tcx.impl_polarity(def_id) { return List::empty(); } @@ -322,17 +337,14 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::bind(clause)))) } -pub fn program_clauses_for_type_def<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, -) -> Clauses<'tcx> { +pub fn program_clauses_for_type_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Clauses<'tcx> { // Rule WellFormed-Type // // `struct Ty where WC1, ..., WCm` // // ``` // forall { - // WellFormed(Ty<...>) :- WC1, ..., WCm` + // WellFormed(Ty<...>) :- WellFormed(WC1), ..., WellFormed(WCm)` // } // ``` @@ -341,19 +353,22 @@ pub fn program_clauses_for_type_def<'a, 'tcx>( // `Ty<...>` let ty = tcx.type_of(def_id).subst(tcx, bound_vars); - // `WC` + // Warning: these where clauses are not substituted for bound vars yet, + // so that we don't need to adjust binders in the `FromEnv` rules below + // (see the FIXME). let where_clauses = tcx.predicates_of(def_id).predicates .iter() .map(|(wc, _)| wc.lower()) .collect::>(); - // `WellFormed(Ty<...>) :- WC1, ..., WCm` + // `WellFormed(Ty<...>) :- WellFormed(WC1), ..., WellFormed(WCm)` let well_formed_clause = ProgramClause { goal: DomainGoal::WellFormed(WellFormed::Ty(ty)), hypotheses: tcx.mk_goals( where_clauses .iter() .map(|wc| wc.subst(tcx, bound_vars)) + .map(|wc| wc.map_bound(|bound| bound.into_well_formed_goal())) .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))), ), category: ProgramClauseCategory::WellFormed, @@ -396,8 +411,8 @@ pub fn program_clauses_for_type_def<'a, 'tcx>( tcx.mk_clauses(iter::once(well_formed_clause).chain(from_env_clauses)) } -pub fn program_clauses_for_associated_type_def<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn program_clauses_for_associated_type_def<'tcx>( + tcx: TyCtxt<'tcx>, item_id: DefId, ) -> Clauses<'tcx> { // Rule ProjectionEq-Placeholder @@ -420,9 +435,9 @@ pub fn program_clauses_for_associated_type_def<'a, 'tcx>( // ``` let item = tcx.associated_item(item_id); - debug_assert_eq!(item.kind, ty::AssociatedKind::Type); + debug_assert_eq!(item.kind, ty::AssocKind::Type); let trait_id = match item.container { - ty::AssociatedItemContainer::TraitContainer(trait_id) => trait_id, + ty::AssocItemContainer::TraitContainer(trait_id) => trait_id, _ => bug!("not an trait container"), }; @@ -450,13 +465,13 @@ pub fn program_clauses_for_associated_type_def<'a, 'tcx>( // ``` // forall { // WellFormed((Trait::AssocType)) - // :- Implemented(Self: Trait) + // :- WellFormed(Self: Trait) // } // ``` let trait_predicate = ty::TraitPredicate { trait_ref }; let hypothesis = tcx.mk_goal( - DomainGoal::Holds(WhereClause::Implemented(trait_predicate)).into_goal() + DomainGoal::WellFormed(WellFormed::Trait(trait_predicate)).into_goal() ); let wf_clause = ProgramClause { @@ -534,8 +549,8 @@ pub fn program_clauses_for_associated_type_def<'a, 'tcx>( tcx.mk_clauses(clauses) } -pub fn program_clauses_for_associated_type_value<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn program_clauses_for_associated_type_value<'tcx>( + tcx: TyCtxt<'tcx>, item_id: DefId, ) -> Clauses<'tcx> { // Rule Normalize-From-Impl (see rustc guide) @@ -558,9 +573,9 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>( // ``` let item = tcx.associated_item(item_id); - debug_assert_eq!(item.kind, ty::AssociatedKind::Type); + debug_assert_eq!(item.kind, ty::AssocKind::Type); let impl_id = match item.container { - ty::AssociatedItemContainer::ImplContainer(impl_id) => impl_id, + ty::AssocItemContainer::ImplContainer(impl_id) => impl_id, _ => bug!("not an impl container"), }; @@ -596,7 +611,7 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>( tcx.mk_clauses(iter::once(normalize_clause)) } -pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn dump_program_clauses<'tcx>(tcx: TyCtxt<'tcx>) { if !tcx.features().rustc_attrs { return; } @@ -607,21 +622,21 @@ pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { .visit_all_item_likes(&mut visitor.as_deep_visitor()); } -struct ClauseDumper<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct ClauseDumper<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx> ClauseDumper<'a, 'tcx> { +impl ClauseDumper<'tcx> { fn process_attrs(&mut self, hir_id: hir::HirId, attrs: &[ast::Attribute]) { let def_id = self.tcx.hir().local_def_id_from_hir_id(hir_id); for attr in attrs { let mut clauses = None; - if attr.check_name("rustc_dump_program_clauses") { + if attr.check_name(sym::rustc_dump_program_clauses) { clauses = Some(self.tcx.program_clauses_for(def_id)); } - if attr.check_name("rustc_dump_env_program_clauses") { + if attr.check_name(sym::rustc_dump_env_program_clauses) { let environment = self.tcx.environment(def_id); clauses = Some(self.tcx.program_clauses_for_env(environment)); } @@ -649,7 +664,7 @@ impl<'a, 'tcx> ClauseDumper<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for ClauseDumper<'a, 'tcx> { +impl Visitor<'tcx> for ClauseDumper<'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::OnlyBodies(&self.tcx.hir()) } diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index 412d2ca6dfcff..d138ce753b07e 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -12,7 +12,7 @@ crate fn provide(p: &mut Providers<'_>) { } fn normalize_ty_after_erasing_regions<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, goal: ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Ty<'tcx> { debug!("normalize_ty_after_erasing_regions(goal={:#?})", goal); @@ -36,9 +36,8 @@ fn normalize_ty_after_erasing_regions<'tcx>( None, ); - let normalized_value = infcx.resolve_type_vars_if_possible(&normalized_value); - let normalized_value = infcx.tcx.erase_regions(&normalized_value); - tcx.lift_to_global(&normalized_value).unwrap() + let normalized_value = infcx.resolve_vars_if_possible(&normalized_value); + infcx.tcx.erase_regions(&normalized_value) } Err(NoSolution) => bug!("could not fully normalize `{:?}`", value), } diff --git a/src/librustc_traits/normalize_projection_ty.rs b/src/librustc_traits/normalize_projection_ty.rs index 38f7a21e66c55..7e0ca5b00183d 100644 --- a/src/librustc_traits/normalize_projection_ty.rs +++ b/src/librustc_traits/normalize_projection_ty.rs @@ -4,7 +4,6 @@ use rustc::traits::query::{normalize::NormalizationResult, CanonicalProjectionGo use rustc::traits::{self, ObligationCause, SelectionContext, TraitEngineExt}; use rustc::ty::query::Providers; use rustc::ty::{ParamEnvAnd, TyCtxt}; -use rustc_data_structures::sync::Lrc; use std::sync::atomic::Ordering; use syntax_pos::DUMMY_SP; @@ -16,9 +15,9 @@ crate fn provide(p: &mut Providers<'_>) { } fn normalize_projection_ty<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, goal: CanonicalProjectionGoal<'tcx>, -) -> Result>>>, NoSolution> { +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { debug!("normalize_provider(goal={:#?})", goal); tcx.sess diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index 30fbdbdeb4433..cb30eba5b0505 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -17,7 +17,6 @@ use rustc::ty::subst::{Kind, Subst, UserSubsts, UserSelfTy}; use rustc::ty::{ FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance, }; -use rustc_data_structures::sync::Lrc; use std::fmt; use syntax_pos::DUMMY_SP; @@ -36,9 +35,9 @@ crate fn provide(p: &mut Providers<'_>) { } fn type_op_ascribe_user_type<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>, -) -> Result>>, NoSolution> { +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { let ( @@ -57,13 +56,13 @@ fn type_op_ascribe_user_type<'tcx>( }) } -struct AscribeUserTypeCx<'me, 'gcx: 'tcx, 'tcx: 'me> { - infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, +struct AscribeUserTypeCx<'me, 'tcx> { + infcx: &'me InferCtxt<'me, 'tcx>, param_env: ParamEnv<'tcx>, fulfill_cx: &'me mut dyn TraitEngine<'tcx>, } -impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { +impl AscribeUserTypeCx<'me, 'tcx> { fn normalize(&mut self, value: T) -> T where T: TypeFoldable<'tcx>, @@ -95,7 +94,7 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { ); } - fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -168,9 +167,9 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { } fn type_op_eq<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>, -) -> Result>>, NoSolution> { +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { let (param_env, Eq { a, b }) = key.into_parts(); @@ -182,12 +181,12 @@ fn type_op_eq<'tcx>( } fn type_op_normalize( - infcx: &InferCtxt<'_, 'gcx, 'tcx>, + infcx: &InferCtxt<'_, 'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx>, key: ParamEnvAnd<'tcx, Normalize>, ) -> Fallible where - T: fmt::Debug + TypeFoldable<'tcx> + Lift<'gcx>, + T: fmt::Debug + TypeFoldable<'tcx> + Lift<'tcx>, { let (param_env, Normalize { value }) = key.into_parts(); let Normalized { value, obligations } = infcx @@ -198,41 +197,41 @@ where } fn type_op_normalize_ty( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize>>>, -) -> Result>>>, NoSolution> { +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, type_op_normalize) } fn type_op_normalize_predicate( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize>>>, -) -> Result>>>, NoSolution> { +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, Predicate<'tcx>>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, type_op_normalize) } fn type_op_normalize_fn_sig( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize>>>, -) -> Result>>>, NoSolution> { +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, FnSig<'tcx>>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, type_op_normalize) } fn type_op_normalize_poly_fn_sig( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize>>>, -) -> Result>>>, NoSolution> { +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, PolyFnSig<'tcx>>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, type_op_normalize) } fn type_op_subtype<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Subtype<'tcx>>>, -) -> Result>>, NoSolution> { +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { let (param_env, Subtype { sub, sup }) = key.into_parts(); @@ -244,9 +243,9 @@ fn type_op_subtype<'tcx>( } fn type_op_prove_predicate<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>, -) -> Result>>, NoSolution> { +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { let (param_env, ProvePredicate { predicate }) = key.into_parts(); diff --git a/src/librustc_tsan/Cargo.toml b/src/librustc_tsan/Cargo.toml index d805833a7efc1..82045dd0cddc7 100644 --- a/src/librustc_tsan/Cargo.toml +++ b/src/librustc_tsan/Cargo.toml @@ -12,7 +12,7 @@ test = false [build-dependencies] build_helper = { path = "../build_helper" } -cmake = "0.1.18" +cmake = "0.1.38" [dependencies] alloc = { path = "../liballoc" } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5dbcf908020b0..9b8f6a556bf88 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -3,20 +3,21 @@ //! instance of `AstConv`. use errors::{Applicability, DiagnosticId}; -use crate::hir::{self, GenericArg, GenericArgs}; -use crate::hir::def::Def; +use crate::hir::{self, GenericArg, GenericArgs, ExprKind}; +use crate::hir::def::{CtorOf, Res, DefKind}; use crate::hir::def_id::DefId; use crate::hir::HirVec; use crate::lint; +use crate::middle::lang_items::SizedTraitLangItem; use crate::middle::resolve_lifetime as rl; use crate::namespace::Namespace; use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc::traits; -use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; +use rustc::ty::{self, DefIdTree, Ty, TyCtxt, Const, ToPredicate, TypeFoldable}; use rustc::ty::{GenericParamDef, GenericParamDefKind}; use rustc::ty::subst::{Kind, Subst, InternalSubsts, SubstsRef}; use rustc::ty::wf::object_region_bounds; -use rustc_data_structures::sync::Lrc; +use rustc::mir::interpret::ConstValue; use rustc_target::spec::abi; use crate::require_c_abi_if_c_variadic; use smallvec::SmallVec; @@ -24,6 +25,7 @@ use syntax::ast; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; +use syntax::symbol::sym; use syntax_pos::{DUMMY_SP, Span, MultiSpan}; use crate::util::common::ErrorReported; use crate::util::nodemap::FxHashMap; @@ -32,33 +34,37 @@ use std::collections::BTreeSet; use std::iter; use std::slice; -use super::{check_type_alias_enum_variants_enabled}; use rustc_data_structures::fx::FxHashSet; #[derive(Debug)] pub struct PathSeg(pub DefId, pub usize); -pub trait AstConv<'gcx, 'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>; +pub trait AstConv<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; /// Returns the set of bounds in scope for the type parameter with /// the given id. fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) - -> Lrc>; + -> &'tcx ty::GenericPredicates<'tcx>; - /// What lifetime should we use when a lifetime is omitted (and not elided)? - fn re_infer(&self, span: Span, _def: Option<&ty::GenericParamDef>) + /// Returns the lifetime to use when a lifetime is omitted (and not elided). + fn re_infer( + &self, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> Option>; - /// What type should we use when a type is omitted? - fn ty_infer(&self, span: Span) -> Ty<'tcx>; + /// Returns the type to use when a type is omitted. + fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>; - /// Same as ty_infer, but with a known type parameter definition. - fn ty_infer_for_def(&self, - _def: &ty::GenericParamDef, - span: Span) -> Ty<'tcx> { - self.ty_infer(span) - } + /// Returns the const to use when a const is omitted. + fn ct_infer( + &self, + ty: Ty<'tcx>, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> &'tcx Const<'tcx>; /// Projecting an associated type from a (potentially) /// higher-ranked trait reference is more complicated, because of @@ -85,12 +91,22 @@ pub trait AstConv<'gcx, 'tcx> { fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span); } -struct ConvertedBinding<'tcx> { +pub enum SizedByDefault { + Yes, + No, +} + +struct ConvertedBinding<'a, 'tcx> { item_name: ast::Ident, - ty: Ty<'tcx>, + kind: ConvertedBindingKind<'a, 'tcx>, span: Span, } +enum ConvertedBindingKind<'a, 'tcx> { + Equality(Ty<'tcx>), + Constraint(&'a [hir::GenericBound]), +} + #[derive(PartialEq)] enum GenericArgPosition { Type, @@ -98,12 +114,7 @@ enum GenericArgPosition { MethodCall, } -/// Dummy type used for the `Self` of a `TraitRef` created for converting -/// a trait object, and which gets removed in `ExistentialTraitRef`. -/// This type must not appear anywhere in other converted types. -const TRAIT_OBJECT_DUMMY_SELF: ty::TyKind<'static> = ty::Infer(ty::FreshTy(0)); - -impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { +impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn ast_region_to_region(&self, lifetime: &hir::Lifetime, def: Option<&ty::GenericParamDef>) @@ -111,12 +122,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { { let tcx = self.tcx(); let lifetime_name = |def_id| { - tcx.hir().name_by_hir_id(tcx.hir().as_local_hir_id(def_id).unwrap()).as_interned_str() + tcx.hir().name(tcx.hir().as_local_hir_id(def_id).unwrap()).as_interned_str() }; let r = match tcx.named_region(lifetime.hir_id) { Some(rl::Region::Static) => { - tcx.types.re_static + tcx.lifetimes.re_static } Some(rl::Region::LateBound(debruijn, id, _)) => { @@ -149,7 +160,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } None => { - self.re_infer(lifetime.span, def) + self.re_infer(def, lifetime.span) .unwrap_or_else(|| { // This indicates an illegal lifetime // elision. `resolve_lifetime` should have @@ -159,7 +170,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { // Supply some dummy value. We don't have an // `re_error`, annoyingly, so use `'static`. - tcx.types.re_static + tcx.lifetimes.re_static }) } }; @@ -179,15 +190,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { item_segment: &hir::PathSegment) -> SubstsRef<'tcx> { - let (substs, assoc_bindings, _) = item_segment.with_generic_args(|generic_args| { - self.create_substs_for_ast_path( - span, - def_id, - generic_args, - item_segment.infer_types, - None, - ) - }); + let (substs, assoc_bindings, _) = self.create_substs_for_ast_path( + span, + def_id, + item_segment.generic_args(), + item_segment.infer_args, + None, + ); assoc_bindings.first().map(|b| Self::prohibit_assoc_ty_binding(self.tcx(), b.span)); @@ -196,12 +205,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { /// Report error if there is an explicit type parameter when using `impl Trait`. fn check_impl_trait( - tcx: TyCtxt<'_, '_, '_>, + tcx: TyCtxt<'_>, span: Span, seg: &hir::PathSegment, generics: &ty::Generics, ) -> bool { - let explicit = !seg.infer_types; + let explicit = !seg.infer_args; let impl_trait = generics.params.iter().any(|param| match param.kind { ty::GenericParamDefKind::Type { synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), .. @@ -227,7 +236,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { /// Checks that the correct number of generic arguments have been provided. /// Used specifically for function calls. pub fn check_generic_arg_count_for_call( - tcx: TyCtxt<'_, '_, '_>, + tcx: TyCtxt<'_>, span: Span, def: &ty::Generics, seg: &hir::PathSegment, @@ -252,20 +261,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { GenericArgPosition::Value }, def.parent.is_none() && def.has_self, // `has_self` - seg.infer_types || suppress_mismatch, // `infer_types` + seg.infer_args || suppress_mismatch, // `infer_args` ).0 } /// Checks that the correct number of generic arguments have been provided. /// This is used both for datatypes and function calls. fn check_generic_arg_count( - tcx: TyCtxt<'_, '_, '_>, + tcx: TyCtxt<'_>, span: Span, def: &ty::Generics, args: &hir::GenericArgs, position: GenericArgPosition, has_self: bool, - infer_types: bool, + infer_args: bool, ) -> (bool, Option>) { // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. // that lifetimes will proceed types. So it suffices to check the number of each generic @@ -281,6 +290,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { GenericParamDefKind::Type { has_default, .. } => { defaults.types += has_default as usize } + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + } }; } @@ -289,6 +301,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } // Prohibit explicit lifetime arguments if late-bound lifetime parameters are present. + let mut reported_late_bound_region_err = None; if !infer_lifetimes { if let Some(span_late) = def.has_late_bound_regions { let msg = "cannot specify lifetime arguments explicitly \ @@ -300,27 +313,31 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let mut err = tcx.sess.struct_span_err(span, msg); err.span_note(span_late, note); err.emit(); - return (true, None); + reported_late_bound_region_err = Some(true); } else { let mut multispan = MultiSpan::from_span(span); multispan.push_span_label(span_late, note.to_string()); tcx.lint_hir(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, args.args[0].id(), multispan, msg); - return (false, None); + reported_late_bound_region_err = Some(false); } } } - let check_kind_count = |kind, - required, - permitted, - provided, - offset| { + let check_kind_count = |kind, required, permitted, provided, offset| { + debug!( + "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}", + kind, + required, + permitted, + provided, + offset + ); // We enforce the following: `required` <= `provided` <= `permitted`. - // For kinds without defaults (i.e., lifetimes), `required == permitted`. + // For kinds without defaults (e.g.., lifetimes), `required == permitted`. // For other kinds (i.e., types), `permitted` may be greater than `required`. if required <= provided && provided <= permitted { - return (false, None); + return (reported_late_bound_region_err.unwrap_or(false), None); } // Unfortunately lifetime and type parameter mismatches are typically styled @@ -371,11 +388,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } err.emit(); - (provided > required, // `suppress_error` - potential_assoc_types) + ( + provided > required, // `suppress_error` + potential_assoc_types, + ) }; - if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { + if reported_late_bound_region_err.is_none() + && (!infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes) { check_kind_count( "lifetime", param_counts.lifetimes, @@ -384,7 +404,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { 0, ); } - if !infer_types + // FIXME(const_generics:defaults) + if !infer_args || arg_counts.consts > param_counts.consts { + check_kind_count( + "const", + param_counts.consts, + param_counts.consts, + arg_counts.consts, + arg_counts.lifetimes + arg_counts.types, + ); + } + // Note that type errors are currently be emitted *after* const errors. + if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize { check_kind_count( "type", @@ -394,7 +425,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { arg_counts.lifetimes, ) } else { - (false, None) + (reported_late_bound_region_err.unwrap_or(false), None) } } @@ -427,8 +458,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { /// instantiate a `Kind`. /// - `inferred_kind`: if no parameter was provided, and inference is enabled, then /// creates a suitable inference variable. - pub fn create_substs_for_generic_args<'a, 'b>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, + pub fn create_substs_for_generic_args<'b>( + tcx: TyCtxt<'tcx>, def_id: DefId, parent_substs: &[Kind<'tcx>], has_self: bool, @@ -481,7 +512,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } // Check whether this segment takes generic arguments and the user has provided any. - let (generic_args, infer_types) = args_for_def_id(def_id); + let (generic_args, infer_args) = args_for_def_id(def_id); let mut args = generic_args.iter().flat_map(|generic_args| generic_args.args.iter()) .peekable(); @@ -495,7 +526,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { (Some(&arg), Some(¶m)) => { match (arg, ¶m.kind) { (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime) - | (GenericArg::Type(_), GenericParamDefKind::Type { .. }) => { + | (GenericArg::Type(_), GenericParamDefKind::Type { .. }) + | (GenericArg::Const(_), GenericParamDefKind::Const) => { substs.push(provided_kind(param, arg)); args.next(); params.next(); @@ -504,7 +536,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { | (GenericArg::Const(_), GenericParamDefKind::Lifetime) => { // We expected a lifetime argument, but got a type or const // argument. That means we're inferring the lifetimes. - substs.push(inferred_kind(None, param, infer_types)); + substs.push(inferred_kind(None, param, infer_args)); params.next(); } (_, _) => { @@ -525,7 +557,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { (None, Some(¶m)) => { // If there are fewer arguments than parameters, it means // we're inferring the remaining arguments. - substs.push(inferred_kind(Some(&substs), param, infer_types)); + substs.push(inferred_kind(Some(&substs), param, infer_args)); args.next(); params.next(); } @@ -537,18 +569,33 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { tcx.intern_substs(&substs) } - /// Given the type/region arguments provided to some path (along with - /// an implicit `Self`, if this is a trait reference) returns the complete + /// Given the type/lifetime/const arguments provided to some path (along with + /// an implicit `Self`, if this is a trait reference), returns the complete /// set of substitutions. This may involve applying defaulted type parameters. + /// Also returns back constriants on associated types. + /// + /// Example: + /// + /// ``` + /// T: std::ops::Index + /// ^1 ^^^^^^^^^^^^^^2 ^^^^3 ^^^^^^^^^^^4 + /// ``` + /// + /// 1. The `self_ty` here would refer to the type `T`. + /// 2. The path in question is the path to the trait `std::ops::Index`, + /// which will have been resolved to a `def_id` + /// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type + /// parameters are returned in the `SubstsRef`, the associated type bindings like + /// `Output = u32` are returned in the `Vec` result. /// /// Note that the type listing given here is *exactly* what the user provided. - fn create_substs_for_ast_path(&self, + fn create_substs_for_ast_path<'a>(&self, span: Span, def_id: DefId, - generic_args: &hir::GenericArgs, - infer_types: bool, + generic_args: &'a hir::GenericArgs, + infer_args: bool, self_ty: Option>) - -> (SubstsRef<'tcx>, Vec>, Option>) + -> (SubstsRef<'tcx>, Vec>, Option>) { // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, @@ -571,10 +618,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { &generic_args, GenericArgPosition::Type, has_self, - infer_types, + infer_args, ); - let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); + let is_object = self_ty.map_or(false, |ty| { + ty == self.tcx().types.trait_object_dummy_self + }); let default_needs_object_self = |param: &ty::GenericParamDef| { if let GenericParamDefKind::Type { has_default, .. } = param.kind { if is_object && has_default { @@ -596,7 +645,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { self_ty.is_some(), self_ty, // Provide the generic args, and whether types should be inferred. - |_| (Some(generic_args), infer_types), + |_| (Some(generic_args), infer_args), // Provide substitutions for parameters for which (valid) arguments have been provided. |param, arg| { match (¶m.kind, arg) { @@ -606,15 +655,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { self.ast_ty_to_ty(&ty).into() } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + self.ast_const_to_const(&ct.value, tcx.type_of(param.def_id)).into() + } _ => unreachable!(), } }, // Provide substitutions for parameters for which arguments are inferred. - |substs, param, infer_types| { + |substs, param, infer_args| { match param.kind { - GenericParamDefKind::Lifetime => tcx.types.re_static.into(), + GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), GenericParamDefKind::Type { has_default, .. } => { - if !infer_types && has_default { + if !infer_args && has_default { // No type parameter provided, but a default exists. // If we are converting an object type, then the @@ -624,14 +676,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { // careful! if default_needs_object_self(param) { struct_span_err!(tcx.sess, span, E0393, - "the type parameter `{}` must be explicitly \ - specified", - param.name) - .span_label(span, - format!("missing reference to `{}`", param.name)) - .note(&format!("because of the default `Self` reference, \ - type parameters must be specified on object \ - types")) + "the type parameter `{}` must be explicitly specified", + param.name + ) + .span_label(span, format!( + "missing reference to `{}`", param.name)) + .note(&format!( + "because of the default `Self` reference, type parameters \ + must be specified on object types")) .emit(); tcx.types.err.into() } else { @@ -642,29 +694,58 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { .subst_spanned(tcx, substs.unwrap(), Some(span)) ).into() } - } else if infer_types { + } else if infer_args { // No type parameters were provided, we can infer all. - if !default_needs_object_self(param) { - self.ty_infer_for_def(param, span).into() + let param = if !default_needs_object_self(param) { + Some(param) } else { - self.ty_infer(span).into() - } + None + }; + self.ty_infer(param, span).into() } else { // We've already errored above about the mismatch. tcx.types.err.into() } } + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + if infer_args { + // No const parameters were provided, we can infer all. + let ty = tcx.at(span).type_of(param.def_id); + self.ct_infer(ty, Some(param), span).into() + } else { + // We've already errored above about the mismatch. + tcx.consts.err.into() + } + } } }, ); - let assoc_bindings = generic_args.bindings.iter().map(|binding| { - ConvertedBinding { - item_name: binding.ident, - ty: self.ast_ty_to_ty(&binding.ty), - span: binding.span, - } - }).collect(); + // Convert associated-type bindings or constraints into a separate vector. + // Example: Given this: + // + // T: Iterator + // + // The `T` is passed in as a self-type; the `Item = u32` is + // not a "type parameter" of the `Iterator` trait, but rather + // a restriction on `::Item`, so it is passed + // back separately. + let assoc_bindings = generic_args.bindings.iter() + .map(|binding| { + let kind = match binding.kind { + hir::TypeBindingKind::Equality { ref ty } => + ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty)), + hir::TypeBindingKind::Constraint { ref bounds } => + ConvertedBindingKind::Constraint(bounds), + }; + ConvertedBinding { + item_name: binding.ident, + kind, + span: binding.span, + } + }) + .collect(); debug!("create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", generic_params, self_ty, substs); @@ -673,15 +754,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } /// Instantiates the path for the given trait reference, assuming that it's - /// bound to a valid trait type. Returns the def_id for the defining trait. + /// bound to a valid trait type. Returns the `DefId` of the defining trait. /// The type _cannot_ be a type other than a trait type. /// /// If the `projections` argument is `None`, then assoc type bindings like `Foo` /// are disallowed. Otherwise, they are pushed onto the vector given. pub fn instantiate_mono_trait_ref(&self, trait_ref: &hir::TraitRef, - self_ty: Ty<'tcx>) - -> ty::TraitRef<'tcx> + self_ty: Ty<'tcx> + ) -> ty::TraitRef<'tcx> { self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); @@ -695,9 +776,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { pub(super) fn instantiate_poly_trait_ref_inner(&self, trait_ref: &hir::TraitRef, self_ty: Ty<'tcx>, - poly_projections: &mut Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>, - speculative: bool) - -> (ty::PolyTraitRef<'tcx>, Option>) + bounds: &mut Bounds<'tcx>, + speculative: bool, + ) -> (ty::PolyTraitRef<'tcx>, Option>) { let trait_def_id = trait_ref.trait_def_id(); @@ -714,36 +795,59 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); let mut dup_bindings = FxHashMap::default(); - poly_projections.extend(assoc_bindings.iter().filter_map(|binding| { - // specify type to assert that error was already reported in Err case: - let predicate: Result<_, ErrorReported> = - self.ast_type_binding_to_poly_projection_predicate( - trait_ref.hir_ref_id, poly_trait_ref, binding, speculative, &mut dup_bindings); - // okay to ignore Err because of ErrorReported (see above) - Some((predicate.ok()?, binding.span)) - })); - - debug!("instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}", - trait_ref, poly_projections, poly_trait_ref); + for binding in &assoc_bindings { + // Specify type to assert that error was already reported in `Err` case. + let _: Result<_, ErrorReported> = + self.add_predicates_for_ast_type_binding( + trait_ref.hir_ref_id, + poly_trait_ref, + binding, + bounds, + speculative, + &mut dup_bindings + ); + // Okay to ignore `Err` because of `ErrorReported` (see above). + } + + debug!("instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}", + trait_ref, bounds, poly_trait_ref); (poly_trait_ref, potential_assoc_types) } + /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct + /// a full trait reference. The resulting trait reference is returned. This may also generate + /// auxiliary bounds, which are added to `bounds`. + /// + /// Example: + /// + /// ``` + /// poly_trait_ref = Iterator + /// self_ty = Foo + /// ``` + /// + /// this would return `Foo: Iterator` and add `::Item = u32` into `bounds`. + /// + /// **A note on binders:** against our usual convention, there is an implied bounder around + /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions. + /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>` + /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be + /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, + /// however. pub fn instantiate_poly_trait_ref(&self, poly_trait_ref: &hir::PolyTraitRef, self_ty: Ty<'tcx>, - poly_projections: &mut Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>) - -> (ty::PolyTraitRef<'tcx>, Option>) + bounds: &mut Bounds<'tcx> + ) -> (ty::PolyTraitRef<'tcx>, Option>) { - self.instantiate_poly_trait_ref_inner(&poly_trait_ref.trait_ref, self_ty, - poly_projections, false) + self.instantiate_poly_trait_ref_inner(&poly_trait_ref.trait_ref, self_ty, bounds, false) } fn ast_path_to_mono_trait_ref(&self, - span: Span, - trait_def_id: DefId, - self_ty: Ty<'tcx>, - trait_segment: &hir::PathSegment) - -> ty::TraitRef<'tcx> + span: Span, + trait_def_id: DefId, + self_ty: Ty<'tcx>, + trait_segment: &hir::PathSegment + ) -> ty::TraitRef<'tcx> { let (substs, assoc_bindings, _) = self.create_substs_for_ast_trait_ref(span, @@ -754,21 +858,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { ty::TraitRef::new(trait_def_id, substs) } - fn create_substs_for_ast_trait_ref( + fn create_substs_for_ast_trait_ref<'a>( &self, span: Span, trait_def_id: DefId, self_ty: Ty<'tcx>, - trait_segment: &hir::PathSegment, - ) -> (SubstsRef<'tcx>, Vec>, Option>) { + trait_segment: &'a hir::PathSegment, + ) -> (SubstsRef<'tcx>, Vec>, Option>) { debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); let trait_def = self.tcx().trait_def(trait_def_id); if !self.tcx().features().unboxed_closures && - trait_segment.with_generic_args(|generic_args| generic_args.parenthesized) - != trait_def.paren_sugar { + trait_segment.generic_args().parenthesized != trait_def.paren_sugar + { // For now, require that parenthetical notation be used only with `Fn()` etc. let msg = if trait_def.paren_sugar { "the precise format of `Fn`-family traits' type parameters is subject to change. \ @@ -776,17 +880,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } else { "parenthetical notation is only stable when used with `Fn`-family traits" }; - emit_feature_err(&self.tcx().sess.parse_sess, "unboxed_closures", + emit_feature_err(&self.tcx().sess.parse_sess, sym::unboxed_closures, span, GateIssue::Language, msg); } - trait_segment.with_generic_args(|generic_args| { - self.create_substs_for_ast_path(span, - trait_def_id, - generic_args, - trait_segment.infer_types, - Some(self_ty)) - }) + self.create_substs_for_ast_path(span, + trait_def_id, + trait_segment.generic_args(), + trait_segment.infer_args, + Some(self_ty)) } fn trait_defines_associated_type_named(&self, @@ -795,20 +897,161 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { -> bool { self.tcx().associated_items(trait_def_id).any(|item| { - item.kind == ty::AssociatedKind::Type && + item.kind == ty::AssocKind::Type && self.tcx().hygienic_eq(assoc_name, item.ident, trait_def_id) }) } - fn ast_type_binding_to_poly_projection_predicate( + // Returns `true` if a bounds list includes `?Sized`. + pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound], span: Span) -> bool { + let tcx = self.tcx(); + + // Try to find an unbound in bounds. + let mut unbound = None; + for ab in ast_bounds { + if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab { + if unbound.is_none() { + unbound = Some(&ptr.trait_ref); + } else { + span_err!( + tcx.sess, + span, + E0203, + "type parameter has more than one relaxed default \ + bound, only one is supported" + ); + } + } + } + + let kind_id = tcx.lang_items().require(SizedTraitLangItem); + match unbound { + Some(tpb) => { + // FIXME(#8559) currently requires the unbound to be built-in. + if let Ok(kind_id) = kind_id { + if tpb.path.res != Res::Def(DefKind::Trait, kind_id) { + tcx.sess.span_warn( + span, + "default bound relaxed for a type parameter, but \ + this does nothing because the given bound is not \ + a default. Only `?Sized` is supported", + ); + } + } + } + _ if kind_id.is_ok() => { + return false; + } + // No lang item for `Sized`, so we can't add it as a bound. + None => {} + } + + true + } + + /// This helper takes a *converted* parameter type (`param_ty`) + /// and an *unconverted* list of bounds: + /// + /// ``` + /// fn foo + /// ^ ^^^^^ `ast_bounds` parameter, in HIR form + /// | + /// `param_ty`, in ty form + /// ``` + /// + /// It adds these `ast_bounds` into the `bounds` structure. + /// + /// **A note on binders:** there is an implied binder around + /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` + /// for more details. + fn add_bounds(&self, + param_ty: Ty<'tcx>, + ast_bounds: &[hir::GenericBound], + bounds: &mut Bounds<'tcx>, + ) { + let mut trait_bounds = Vec::new(); + let mut region_bounds = Vec::new(); + + for ast_bound in ast_bounds { + match *ast_bound { + hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => + trait_bounds.push(b), + hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} + hir::GenericBound::Outlives(ref l) => + region_bounds.push(l), + } + } + + for bound in trait_bounds { + let (poly_trait_ref, _) = self.instantiate_poly_trait_ref( + bound, + param_ty, + bounds, + ); + bounds.trait_bounds.push((poly_trait_ref, bound.span)) + } + + bounds.region_bounds.extend(region_bounds + .into_iter() + .map(|r| (self.ast_region_to_region(r, None), r.span)) + ); + } + + /// Translates a list of bounds from the HIR into the `Bounds` data structure. + /// The self-type for the bounds is given by `param_ty`. + /// + /// Example: + /// + /// ``` + /// fn foo() { } + /// ^ ^^^^^^^^^ ast_bounds + /// param_ty + /// ``` + /// + /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be + /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the + /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`. + /// + /// `span` should be the declaration size of the parameter. + pub fn compute_bounds(&self, + param_ty: Ty<'tcx>, + ast_bounds: &[hir::GenericBound], + sized_by_default: SizedByDefault, + span: Span, + ) -> Bounds<'tcx> { + let mut bounds = Bounds::default(); + + self.add_bounds(param_ty, ast_bounds, &mut bounds); + bounds.trait_bounds.sort_by_key(|(t, _)| t.def_id()); + + bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default { + if !self.is_unsized(ast_bounds, span) { + Some(span) + } else { + None + } + } else { + None + }; + + bounds + } + + /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates + /// onto `bounds`. + /// + /// **A note on binders:** given something like `T: for<'a> Iterator`, the + /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside* + /// the binder (e.g., `&'a u32`) and hence may reference bound regions. + fn add_predicates_for_ast_type_binding( &self, hir_ref_id: hir::HirId, trait_ref: ty::PolyTraitRef<'tcx>, - binding: &ConvertedBinding<'tcx>, + binding: &ConvertedBinding<'_, 'tcx>, + bounds: &mut Bounds<'tcx>, speculative: bool, - dup_bindings: &mut FxHashMap) - -> Result, ErrorReported> - { + dup_bindings: &mut FxHashMap, + ) -> Result<(), ErrorReported> { let tcx = self.tcx(); if !speculative { @@ -823,40 +1066,43 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { // trait SubTrait: SuperTrait { } // trait SuperTrait { type T; } // - // ... B : SubTrait ... + // ... B: SubTrait ... // ``` // // We want to produce `>::T == foo`. // Find any late-bound regions declared in `ty` that are not - // declared in the trait-ref. These are not wellformed. + // declared in the trait-ref. These are not well-formed. // // Example: // // for<'a> ::Item = &'a str // <-- 'a is bad // for<'a> >::Output = &'a str // <-- 'a is ok - let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref); - let late_bound_in_ty = - tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(binding.ty)); - debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); - debug!("late_bound_in_ty = {:?}", late_bound_in_ty); - for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) { - let br_name = match *br { - ty::BrNamed(_, name) => name, - _ => { - span_bug!( - binding.span, - "anonymous bound region {:?} in binding but not trait ref", - br); - } - }; - struct_span_err!(tcx.sess, + if let ConvertedBindingKind::Equality(ty) = binding.kind { + let late_bound_in_trait_ref = + tcx.collect_constrained_late_bound_regions(&trait_ref); + let late_bound_in_ty = + tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty)); + debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); + debug!("late_bound_in_ty = {:?}", late_bound_in_ty); + for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) { + let br_name = match *br { + ty::BrNamed(_, name) => name, + _ => { + span_bug!( binding.span, - E0582, - "binding for associated type `{}` references lifetime `{}`, \ - which does not appear in the trait input types", - binding.item_name, br_name) - .emit(); + "anonymous bound region {:?} in binding but not trait ref", + br); + } + }; + struct_span_err!(tcx.sess, + binding.span, + E0582, + "binding for associated type `{}` references lifetime `{}`, \ + which does not appear in the trait input types", + binding.item_name, br_name) + .emit(); + } } } @@ -875,9 +1121,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { }?; let (assoc_ident, def_scope) = - tcx.adjust_ident(binding.item_name, candidate.def_id(), hir_ref_id); + tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id); let assoc_ty = tcx.associated_items(candidate.def_id()).find(|i| { - i.kind == ty::AssociatedKind::Type && i.ident.modern() == assoc_ident + i.kind == ty::AssocKind::Type && i.ident.modern() == assoc_ident }).expect("missing associated type"); if !assoc_ty.vis.is_accessible_from(def_scope, tcx) { @@ -893,7 +1139,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { "the value of the associated type `{}` (from the trait `{}`) \ is already specified", binding.item_name, - tcx.item_path_str(assoc_ty.container.id())) + tcx.def_path_str(assoc_ty.container.id())) .span_label(binding.span, "re-bound here") .span_label(*prev_span, format!("`{}` bound here first", binding.item_name)) .emit(); @@ -901,16 +1147,39 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { .or_insert(binding.span); } - Ok(candidate.map_bound(|trait_ref| { - ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy::from_ref_and_name( - tcx, - trait_ref, - binding.item_name, - ), - ty: binding.ty, + match binding.kind { + ConvertedBindingKind::Equality(ref ty) => { + // "Desugar" a constraint like `T: Iterator` this to + // the "projection predicate" for: + // + // `::Item = u32` + bounds.projection_bounds.push((candidate.map_bound(|trait_ref| { + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy::from_ref_and_name( + tcx, + trait_ref, + binding.item_name, + ), + ty, + } + }), binding.span)); } - })) + ConvertedBindingKind::Constraint(ast_bounds) => { + // "Desugar" a constraint like `T: Iterator` to + // + // `::Item: Debug` + // + // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` + // parameter to have a skipped binder. + let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs); + self.add_bounds( + param_ty, + ast_bounds, + bounds, + ); + } + } + Ok(()) } fn ast_path_to_ty(&self, @@ -927,10 +1196,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } /// Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by - /// removing the dummy `Self` type (`TRAIT_OBJECT_DUMMY_SELF`). + /// removing the dummy `Self` type (`trait_object_dummy_self`). fn trait_ref_to_existential(&self, trait_ref: ty::TraitRef<'tcx>) -> ty::ExistentialTraitRef<'tcx> { - assert_eq!(trait_ref.self_ty().sty, TRAIT_OBJECT_DUMMY_SELF); + if trait_ref.self_ty() != self.tcx().types.trait_object_dummy_self { + bug!("trait_ref_to_existential called on {:?} with non-dummy Self", trait_ref); + } ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref) } @@ -942,70 +1213,90 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { { let tcx = self.tcx(); - if trait_bounds.is_empty() { - span_err!(tcx.sess, span, E0224, - "at least one non-builtin trait is required for an object type"); - return tcx.types.err; - } - - let mut projection_bounds = Vec::new(); - let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF); - let (principal, potential_assoc_types) = self.instantiate_poly_trait_ref( - &trait_bounds[0], - dummy_self, - &mut projection_bounds, - ); - debug!("principal: {:?}", principal); - - for trait_bound in trait_bounds[1..].iter() { - // sanity check for non-principal trait bounds - self.instantiate_poly_trait_ref(trait_bound, - dummy_self, - &mut vec![]); + let mut bounds = Bounds::default(); + let mut potential_assoc_types = Vec::new(); + let dummy_self = self.tcx().types.trait_object_dummy_self; + // FIXME: we want to avoid collecting into a `Vec` here, but simply cloning the iterator is + // not straightforward due to the borrow checker. + let bound_trait_refs: Vec<_> = trait_bounds + .iter() + .rev() + .map(|trait_bound| { + let (trait_ref, cur_potential_assoc_types) = self.instantiate_poly_trait_ref( + trait_bound, + dummy_self, + &mut bounds, + ); + potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten()); + (trait_ref, trait_bound.span) + }) + .collect(); + + // Expand trait aliases recursively and check that only one regular (non-auto) trait + // is used and no 'maybe' bounds are used. + let expanded_traits = traits::expand_trait_aliases(tcx, bound_trait_refs.iter().cloned()); + let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = + expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); + if regular_traits.len() > 1 { + let first_trait = ®ular_traits[0]; + let additional_trait = ®ular_traits[1]; + let mut err = struct_span_err!(tcx.sess, additional_trait.bottom().1, E0225, + "only auto traits can be used as additional traits in a trait object" + ); + additional_trait.label_with_exp_info(&mut err, + "additional non-auto trait", "additional use"); + first_trait.label_with_exp_info(&mut err, + "first non-auto trait", "first use"); + err.emit(); } - let (mut auto_traits, trait_bounds) = split_auto_traits(tcx, &trait_bounds[1..]); - - if !trait_bounds.is_empty() { - let b = &trait_bounds[0]; - let span = b.trait_ref.path.span; - struct_span_err!(self.tcx().sess, span, E0225, - "only auto traits can be used as additional traits in a trait object") - .span_label(span, "non-auto additional trait") - .emit(); + if regular_traits.is_empty() && auto_traits.is_empty() { + span_err!(tcx.sess, span, E0224, + "at least one trait is required for an object type"); + return tcx.types.err; } // Check that there are no gross object safety violations; // most importantly, that the supertraits don't contain `Self`, // to avoid ICEs. - let object_safety_violations = - tcx.global_tcx().astconv_object_safety_violations(principal.def_id()); - if !object_safety_violations.is_empty() { - tcx.report_object_safety_error( - span, principal.def_id(), object_safety_violations) - .emit(); - return tcx.types.err; + for item in ®ular_traits { + let object_safety_violations = + tcx.global_tcx().astconv_object_safety_violations(item.trait_ref().def_id()); + if !object_safety_violations.is_empty() { + tcx.report_object_safety_error( + span, + item.trait_ref().def_id(), + object_safety_violations + ) + .map(|mut err| err.emit()); + return tcx.types.err; + } } // Use a `BTreeSet` to keep output in a more consistent order. let mut associated_types = BTreeSet::default(); - for tr in traits::elaborate_trait_ref(tcx, principal) { - debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", tr); - match tr { + let regular_traits_refs = bound_trait_refs + .into_iter() + .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())) + .map(|(trait_ref, _)| trait_ref); + for trait_ref in traits::elaborate_trait_refs(tcx, regular_traits_refs) { + debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", trait_ref); + match trait_ref { ty::Predicate::Trait(pred) => { - associated_types.extend(tcx.associated_items(pred.def_id()) - .filter(|item| item.kind == ty::AssociatedKind::Type) - .map(|item| item.def_id)); + associated_types + .extend(tcx.associated_items(pred.def_id()) + .filter(|item| item.kind == ty::AssocKind::Type) + .map(|item| item.def_id)); } ty::Predicate::Projection(pred) => { // A `Self` within the original bound will be substituted with a - // `TRAIT_OBJECT_DUMMY_SELF`, so check for that. + // `trait_object_dummy_self`, so check for that. let references_self = pred.skip_binder().ty.walk().any(|t| t == dummy_self); // If the projection output contains `Self`, force the user to - // elaborate it explicitly to avoid a bunch of complexity. + // elaborate it explicitly to avoid a lot of complexity. // // The "classicaly useful" case is the following: // ``` @@ -1014,22 +1305,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { // } // ``` // - // Here, the user could theoretically write `dyn MyTrait`, + // Here, the user could theoretically write `dyn MyTrait`, // but actually supporting that would "expand" to an infinitely-long type - // `fix $ τ → dyn MyTrait::MyOutput`. + // `fix $ τ → dyn MyTrait::MyOutput`. // - // Instead, we force the user to write `dyn MyTrait`, + // Instead, we force the user to write `dyn MyTrait`, // which is uglier but works. See the discussion in #56288 for alternatives. if !references_self { - // Include projections defined on supertraits, - projection_bounds.push((pred, DUMMY_SP)) + // Include projections defined on supertraits. + bounds.projection_bounds.push((pred, DUMMY_SP)) } } _ => () } } - for (projection_bound, _) in &projection_bounds { + for (projection_bound, _) in &bounds.projection_bounds { associated_types.remove(&projection_bound.projection_def_id()); } @@ -1040,7 +1331,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { format!( "`{}` (from the trait `{}`)", assoc_item.ident, - tcx.item_path_str(trait_def_id), + tcx.def_path_str(trait_def_id), ) }).collect::>().join(", "); let mut err = struct_span_err!( @@ -1051,20 +1342,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { if associated_types.len() == 1 { "" } else { "s" }, names, ); - let mut suggest = false; - let mut potential_assoc_types_spans = vec![]; - if let Some(potential_assoc_types) = potential_assoc_types { + let (suggest, potential_assoc_types_spans) = if potential_assoc_types.len() == associated_types.len() { - // Only suggest when the amount of missing associated types is equals to the + // Only suggest when the amount of missing associated types equals the number of // extra type arguments present, as that gives us a relatively high confidence // that the user forgot to give the associtated type's name. The canonical // example would be trying to use `Iterator` instead of - // `Iterator`. - suggest = true; - potential_assoc_types_spans = potential_assoc_types; - } - } - let mut suggestions = vec![]; + // `Iterator`. + (true, potential_assoc_types) + } else { + (false, Vec::new()) + }; + let mut suggestions = Vec::new(); for (i, item_def_id) in associated_types.iter().enumerate() { let assoc_item = tcx.associated_item(*item_def_id); err.span_label( @@ -1100,11 +1389,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { err.emit(); } - // Erase the `dummy_self` (`TRAIT_OBJECT_DUMMY_SELF`) used above. - let existential_principal = principal.map_bound(|trait_ref| { - self.trait_ref_to_existential(trait_ref) + // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as + // `dyn Trait + Send`. + auto_traits.sort_by_key(|i| i.trait_ref().def_id()); + auto_traits.dedup_by_key(|i| i.trait_ref().def_id()); + debug!("regular_traits: {:?}", regular_traits); + debug!("auto_traits: {:?}", auto_traits); + + // Erase the `dummy_self` (`trait_object_dummy_self`) used above. + let existential_trait_refs = regular_traits.iter().map(|i| { + i.trait_ref().map_bound(|trait_ref| self.trait_ref_to_existential(trait_ref)) }); - let existential_projections = projection_bounds.iter().map(|(bound, _)| { + let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { bound.map_bound(|b| { let trait_ref = self.trait_ref_to_existential(b.projection_ty.trait_ref(tcx)); ty::ExistentialProjection { @@ -1115,19 +1411,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { }) }); - // Dedup auto traits so that `dyn Trait + Send + Send` is the same as `dyn Trait + Send`. - auto_traits.sort(); - auto_traits.dedup(); - - // Calling `skip_binder` is okay, because the predicates are re-bound. - let principal = if tcx.trait_is_auto(existential_principal.def_id()) { - ty::ExistentialPredicate::AutoTrait(existential_principal.def_id()) - } else { - ty::ExistentialPredicate::Trait(*existential_principal.skip_binder()) - }; + // Calling `skip_binder` is okay because the predicates are re-bound. + let regular_trait_predicates = existential_trait_refs.map( + |trait_ref| ty::ExistentialPredicate::Trait(*trait_ref.skip_binder())); + let auto_trait_predicates = auto_traits.into_iter().map( + |trait_ref| ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())); let mut v = - iter::once(principal) - .chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait)) + regular_trait_predicates + .chain(auto_trait_predicates) .chain(existential_projections .map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder()))) .collect::>(); @@ -1143,16 +1434,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { if tcx.named_region(lifetime.hir_id).is_some() { self.ast_region_to_region(lifetime, None) } else { - self.re_infer(span, None).unwrap_or_else(|| { + self.re_infer(None, span).unwrap_or_else(|| { span_err!(tcx.sess, span, E0228, - "the lifetime bound for this object type cannot be deduced \ - from context; please supply an explicit bound"); - tcx.types.re_static + "the lifetime bound for this object type cannot be deduced \ + from context; please supply an explicit bound"); + tcx.lifetimes.re_static }) } }) }; - debug!("region_bound: {:?}", region_bound); let ty = tcx.mk_dynamic(existential_predicates, region_bound); @@ -1160,22 +1450,37 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { ty } - fn report_ambiguous_associated_type(&self, - span: Span, - type_str: &str, - trait_str: &str, - name: &str) { - struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type") - .span_suggestion( + fn report_ambiguous_associated_type( + &self, + span: Span, + type_str: &str, + trait_str: &str, + name: &str, + ) { + let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type"); + if let (Some(_), Ok(snippet)) = ( + self.tcx().sess.confused_type_with_std_module.borrow().get(&span), + self.tcx().sess.source_map().span_to_snippet(span), + ) { + err.span_suggestion( span, - "use fully-qualified syntax", - format!("<{} as {}>::{}", type_str, trait_str, name), - Applicability::HasPlaceholders - ).emit(); + "you are looking for the module in `std`, not the primitive type", + format!("std::{}", snippet), + Applicability::MachineApplicable, + ); + } else { + err.span_suggestion( + span, + "use fully-qualified syntax", + format!("<{} as {}>::{}", type_str, trait_str, name), + Applicability::HasPlaceholders + ); + } + err.emit(); } // Search for a bound on a type parameter which includes the associated item - // given by `assoc_name`. `ty_param_def_id` is the `DefId` for the type parameter + // given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter // This function will fail if there are no suitable bounds or there is // any ambiguity. fn find_bound_for_assoc_item(&self, @@ -1194,8 +1499,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let suitable_bounds = traits::transitive_bounds(tcx, bounds) .filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name)); - let param_node_id = tcx.hir().as_local_node_id(ty_param_def_id).unwrap(); - let param_name = tcx.hir().ty_param_name(param_node_id); + let param_hir_id = tcx.hir().as_local_hir_id(ty_param_def_id).unwrap(); + let param_name = tcx.hir().ty_param_name(param_hir_id); self.one_bound_for_assoc_type(suitable_bounds, ¶m_name.as_str(), assoc_name, @@ -1236,7 +1541,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { for bound in bounds { let bound_span = self.tcx().associated_items(bound.def_id()).find(|item| { - item.kind == ty::AssociatedKind::Type && + item.kind == ty::AssocKind::Type && self.tcx().hygienic_eq(assoc_name, item.ident, bound.def_id()) }) .and_then(|item| self.tcx().hir().span_if_local(item.def_id)); @@ -1269,10 +1574,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { hir_ref_id: hir::HirId, span: Span, qself_ty: Ty<'tcx>, - qself_def: Def, + qself_res: Res, assoc_segment: &hir::PathSegment, permit_variants: bool, - ) -> (Ty<'tcx>, Def) { + ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorReported> { let tcx = self.tcx(); let assoc_ident = assoc_segment.ident; @@ -1288,13 +1593,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { tcx.hygienic_eq(assoc_ident, vd.ident, adt_def.did) }); if let Some(variant_def) = variant_def { - let def = Def::Variant(variant_def.did); if permit_variants { - check_type_alias_enum_variants_enabled(tcx, span); - tcx.check_stability(variant_def.did, Some(hir_ref_id), span); - return (qself_ty, def); + tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span); + return Ok((qself_ty, DefKind::Variant, variant_def.def_id)); } else { - variant_resolution = Some(def); + variant_resolution = Some(variant_def.def_id); } } } @@ -1302,32 +1605,26 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { // Find the type of the associated item, and the trait where the associated // item is declared. - let bound = match (&qself_ty.sty, qself_def) { - (_, Def::SelfTy(Some(_), Some(impl_def_id))) => { + let bound = match (&qself_ty.sty, qself_res) { + (_, Res::SelfTy(Some(_), Some(impl_def_id))) => { // `Self` in an impl of a trait -- we have a concrete self type and a // trait reference. let trait_ref = match tcx.impl_trait_ref(impl_def_id) { Some(trait_ref) => trait_ref, None => { // A cycle error occurred, most likely. - return (tcx.types.err, Def::Err); + return Err(ErrorReported); } }; let candidates = traits::supertraits(tcx, ty::Binder::bind(trait_ref)) .filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_ident)); - match self.one_bound_for_assoc_type(candidates, "Self", assoc_ident, span) { - Ok(bound) => bound, - Err(ErrorReported) => return (tcx.types.err, Def::Err), - } + self.one_bound_for_assoc_type(candidates, "Self", assoc_ident, span)? } - (&ty::Param(_), Def::SelfTy(Some(param_did), None)) | - (&ty::Param(_), Def::TyParam(param_did)) => { - match self.find_bound_for_assoc_item(param_did, assoc_ident, span) { - Ok(bound) => bound, - Err(ErrorReported) => return (tcx.types.err, Def::Err), - } + (&ty::Param(_), Res::SelfTy(Some(param_did), None)) | + (&ty::Param(_), Res::Def(DefKind::TyParam, param_did)) => { + self.find_bound_for_assoc_item(param_did, assoc_ident, span)? } _ => { if variant_resolution.is_some() { @@ -1335,12 +1632,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let msg = format!("expected type, found variant `{}`", assoc_ident); tcx.sess.span_err(span, &msg); } else if qself_ty.is_enum() { - // Report as incorrect enum variant rather than ambiguous type. let mut err = tcx.sess.struct_span_err( - span, - &format!("no variant `{}` on enum `{}`", &assoc_ident.as_str(), qself_ty), + assoc_ident.span, + &format!("no variant `{}` in enum `{}`", assoc_ident, qself_ty), ); - // Check if it was a typo. + let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT"); if let Some(suggested_name) = find_best_match_for_name( adt_def.variants.iter().map(|variant| &variant.ident.name), @@ -1348,28 +1644,37 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { None, ) { err.span_suggestion( - span, - "did you mean", - format!("{}::{}", qself_ty, suggested_name), + assoc_ident.span, + "there is a variant with a similar name", + suggested_name.to_string(), Applicability::MaybeIncorrect, ); } else { - err.span_label(span, "unknown variant"); + err.span_label(span, format!("variant not found in `{}`", qself_ty)); } + + if let Some(sp) = tcx.hir().span_if_local(adt_def.did) { + let sp = tcx.sess.source_map().def_span(sp); + err.span_label(sp, format!("variant `{}` not found here", assoc_ident)); + } + err.emit(); } else if !qself_ty.references_error() { // Don't print `TyErr` to the user. - self.report_ambiguous_associated_type(span, - &qself_ty.to_string(), - "Trait", - &assoc_ident.as_str()); + self.report_ambiguous_associated_type( + span, + &qself_ty.to_string(), + "Trait", + &assoc_ident.as_str(), + ); } - return (tcx.types.err, Def::Err); + return Err(ErrorReported); } }; let trait_did = bound.def_id(); - let (assoc_ident, def_scope) = tcx.adjust_ident(assoc_ident, trait_did, hir_ref_id); + let (assoc_ident, def_scope) = + tcx.adjust_ident_and_get_scope(assoc_ident, trait_did, hir_ref_id); let item = tcx.associated_items(trait_did).find(|i| { Namespace::from(i.kind) == Namespace::Type && i.ident.modern() == assoc_ident @@ -1378,14 +1683,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, bound); let ty = self.normalize_ty(span, ty); - let def = Def::AssociatedTy(item.def_id); + let kind = DefKind::AssocTy; if !item.vis.is_accessible_from(def_scope, tcx) { - let msg = format!("{} `{}` is private", def.kind_name(), assoc_ident); + let msg = format!("{} `{}` is private", kind.descr(), assoc_ident); tcx.sess.span_err(span, &msg); } tcx.check_stability(item.def_id, Some(hir_ref_id), span); - if let Some(variant_def) = variant_resolution { + if let Some(variant_def_id) = variant_resolution { let mut err = tcx.struct_span_lint_hir( AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, @@ -1393,13 +1698,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { "ambiguous associated item", ); - let mut could_refer_to = |def: Def, also| { + let mut could_refer_to = |kind: DefKind, def_id, also| { let note_msg = format!("`{}` could{} refer to {} defined here", - assoc_ident, also, def.kind_name()); - err.span_note(tcx.def_span(def.def_id()), ¬e_msg); + assoc_ident, also, kind.descr()); + err.span_note(tcx.def_span(def_id), ¬e_msg); }; - could_refer_to(variant_def, ""); - could_refer_to(def, " also"); + could_refer_to(DefKind::Variant, variant_def_id, ""); + could_refer_to(kind, item.def_id, " also"); err.span_suggestion( span, @@ -1409,7 +1714,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { ).emit(); } - (ty, def) + Ok((ty, kind, item.def_id)) } fn qpath_to_ty(&self, @@ -1421,18 +1726,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { -> Ty<'tcx> { let tcx = self.tcx(); - let trait_def_id = tcx.parent_def_id(item_def_id).unwrap(); + let trait_def_id = tcx.parent(item_def_id).unwrap(); self.prohibit_generics(slice::from_ref(item_segment)); let self_ty = if let Some(ty) = opt_self_ty { ty } else { - let path_str = tcx.item_path_str(trait_def_id); - self.report_ambiguous_associated_type(span, - "Type", - &path_str, - &item_segment.ident.as_str()); + let path_str = tcx.def_path_str(trait_def_id); + self.report_ambiguous_associated_type( + span, + "Type", + &path_str, + &item_segment.ident.as_str(), + ); return tcx.types.err; }; @@ -1452,65 +1759,63 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { &self, segments: T) -> bool { let mut has_err = false; for segment in segments { - segment.with_generic_args(|generic_args| { - let (mut err_for_lt, mut err_for_ty, mut err_for_ct) = (false, false, false); - for arg in &generic_args.args { - let (mut span_err, span, kind) = match arg { - // FIXME(varkor): unify E0109, E0110 and E0111. - hir::GenericArg::Lifetime(lt) => { - if err_for_lt { continue } - err_for_lt = true; - has_err = true; - (struct_span_err!(self.tcx().sess, lt.span, E0110, - "lifetime arguments are not allowed on this entity"), - lt.span, - "lifetime") - } - hir::GenericArg::Type(ty) => { - if err_for_ty { continue } - err_for_ty = true; - has_err = true; - (struct_span_err!(self.tcx().sess, ty.span, E0109, - "type arguments are not allowed on this entity"), - ty.span, - "type") - } - hir::GenericArg::Const(ct) => { - if err_for_ct { continue } - err_for_ct = true; - (struct_span_err!(self.tcx().sess, ct.span, E0111, - "const parameters are not allowed on this type"), - ct.span, - "const") - } - }; - span_err.span_label(span, format!("{} argument not allowed", kind)) - .emit(); - if err_for_lt && err_for_ty && err_for_ct { - break; + let (mut err_for_lt, mut err_for_ty, mut err_for_ct) = (false, false, false); + for arg in &segment.generic_args().args { + let (span, kind) = match arg { + hir::GenericArg::Lifetime(lt) => { + if err_for_lt { continue } + err_for_lt = true; + has_err = true; + (lt.span, "lifetime") } - } - for binding in &generic_args.bindings { - has_err = true; - Self::prohibit_assoc_ty_binding(self.tcx(), binding.span); + hir::GenericArg::Type(ty) => { + if err_for_ty { continue } + err_for_ty = true; + has_err = true; + (ty.span, "type") + } + hir::GenericArg::Const(ct) => { + if err_for_ct { continue } + err_for_ct = true; + (ct.span, "const") + } + }; + let mut err = struct_span_err!( + self.tcx().sess, + span, + E0109, + "{} arguments are not allowed for this type", + kind, + ); + err.span_label(span, format!("{} argument not allowed", kind)); + err.emit(); + if err_for_lt && err_for_ty && err_for_ct { break; } - }) + } + for binding in &segment.generic_args().bindings { + has_err = true; + Self::prohibit_assoc_ty_binding(self.tcx(), binding.span); + break; + } } has_err } - pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_, '_, '_>, span: Span) { + pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) { let mut err = struct_span_err!(tcx.sess, span, E0229, "associated type bindings are not allowed here"); err.span_label(span, "associated type not allowed here").emit(); } - pub fn def_ids_for_path_segments(&self, - segments: &[hir::PathSegment], - self_ty: Option>, - def: Def) - -> Vec { + // FIXME(eddyb, varkor) handle type paths here too, not just value ones. + pub fn def_ids_for_value_path_segments( + &self, + segments: &[hir::PathSegment], + self_ty: Option>, + kind: DefKind, + def_id: DefId, + ) -> Vec { // We need to extract the type parameters supplied by the user in // the path `path`. Due to the current setup, this is a bit of a // tricky-process; the problem is that resolve only tells us the @@ -1554,10 +1859,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { // `SomeStruct::`, contains parameters in TypeSpace, and the // final segment, `foo::` contains parameters in fn space. // - // 5. Reference to a local variable - // - // Local variables can't have any type parameters. - // // The first step then is to categorize the segments appropriately. let tcx = self.tcx(); @@ -1567,10 +1868,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let mut path_segs = vec![]; - match def { + match kind { // Case 1. Reference to a struct constructor. - Def::StructCtor(def_id, ..) | - Def::SelfCtor(.., def_id) => { + DefKind::Ctor(CtorOf::Struct, ..) => { // Everything but the final segment should have no // parameters at all. let generics = tcx.generics_of(def_id); @@ -1581,8 +1881,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } // Case 2. Reference to a variant constructor. - Def::Variant(def_id) | - Def::VariantCtor(def_id, ..) => { + DefKind::Ctor(CtorOf::Variant, ..) + | DefKind::Variant => { let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap()); let (generics_def_id, index) = if let Some(adt_def) = adt_def { debug_assert!(adt_def.is_enum()); @@ -1590,7 +1890,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } else if last >= 1 && segments[last - 1].args.is_some() { // Everything but the penultimate segment should have no // parameters at all. - let enum_def_id = tcx.parent_def_id(def_id).unwrap(); + let mut def_id = def_id; + + // `DefKind::Ctor` -> `DefKind::Variant` + if let DefKind::Ctor(..) = kind { + def_id = tcx.parent(def_id).unwrap() + } + + // `DefKind::Variant` -> `DefKind::Enum` + let enum_def_id = tcx.parent(def_id).unwrap(); (enum_def_id, last - 1) } else { // FIXME: lint here recommending `Enum::<...>::Variant` form @@ -1607,15 +1915,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } // Case 3. Reference to a top-level value. - Def::Fn(def_id) | - Def::Const(def_id) | - Def::Static(def_id, _) => { + DefKind::Fn + | DefKind::Const + | DefKind::ConstParam + | DefKind::Static => { path_segs.push(PathSeg(def_id, last)); } // Case 4. Reference to a method or associated const. - Def::Method(def_id) | - Def::AssociatedConst(def_id) => { + DefKind::Method + | DefKind::AssocConst => { if segments.len() >= 2 { let generics = tcx.generics_of(def_id); path_segs.push(PathSeg(generics.parent.unwrap(), last - 1)); @@ -1623,10 +1932,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { path_segs.push(PathSeg(def_id, last)); } - // Case 5. Local variable, no generics. - Def::Local(..) | Def::Upvar(..) => {} - - _ => bug!("unexpected definition: {:?}", def), + kind => bug!("unexpected definition kind {:?} for {:?}", kind, def_id), } debug!("path_segs = {:?}", path_segs); @@ -1635,20 +1941,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } // Check a type `Path` and convert it to a `Ty`. - pub fn def_to_ty(&self, + pub fn res_to_ty(&self, opt_self_ty: Option>, path: &hir::Path, permit_variants: bool) -> Ty<'tcx> { let tcx = self.tcx(); - debug!("def_to_ty(def={:?}, opt_self_ty={:?}, path_segments={:?})", - path.def, opt_self_ty, path.segments); + debug!("res_to_ty(res={:?}, opt_self_ty={:?}, path_segments={:?})", + path.res, opt_self_ty, path.segments); let span = path.span; - match path.def { - Def::Existential(did) => { - // Check for desugared impl trait. + match path.res { + Res::Def(DefKind::Existential, did) => { + // Check for desugared `impl Trait`. assert!(ty::is_impl_trait_defn(tcx, did).is_none()); let item_segment = path.segments.split_last().unwrap(); self.prohibit_generics(item_segment.1); @@ -1658,18 +1964,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { tcx.mk_opaque(did, substs), ) } - Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | - Def::Union(did) | Def::ForeignTy(did) => { + Res::Def(DefKind::Enum, did) + | Res::Def(DefKind::TyAlias, did) + | Res::Def(DefKind::Struct, did) + | Res::Def(DefKind::Union, did) + | Res::Def(DefKind::ForeignTy, did) => { assert_eq!(opt_self_ty, None); self.prohibit_generics(path.segments.split_last().unwrap().1); self.ast_path_to_ty(span, did, path.segments.last().unwrap()) } - Def::Variant(_) if permit_variants => { + Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => { // Convert "variant type" as if it were a real type. // The resulting `Ty` is type of the variant's enum for now. assert_eq!(opt_self_ty, None); - let path_segs = self.def_ids_for_path_segments(&path.segments, None, path.def); + let path_segs = + self.def_ids_for_value_path_segments(&path.segments, None, kind, def_id); let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect(); self.prohibit_generics(path.segments.iter().enumerate().filter_map(|(index, seg)| { @@ -1683,32 +1993,31 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let PathSeg(def_id, index) = path_segs.last().unwrap(); self.ast_path_to_ty(span, *def_id, &path.segments[*index]) } - Def::TyParam(did) => { + Res::Def(DefKind::TyParam, def_id) => { assert_eq!(opt_self_ty, None); self.prohibit_generics(&path.segments); - let hir_id = tcx.hir().as_local_hir_id(did).unwrap(); - let item_id = tcx.hir().get_parent_node_by_hir_id(hir_id); + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let item_id = tcx.hir().get_parent_node(hir_id); let item_def_id = tcx.hir().local_def_id_from_hir_id(item_id); let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[ - &tcx.hir().local_def_id_from_hir_id(hir_id)]; - tcx.mk_ty_param(index, tcx.hir().name_by_hir_id(hir_id).as_interned_str()) + let index = generics.param_def_id_to_index[&def_id]; + tcx.mk_ty_param(index, tcx.hir().name(hir_id).as_interned_str()) } - Def::SelfTy(_, Some(def_id)) => { - // `Self` in impl (we know the concrete type). + Res::SelfTy(Some(_), None) => { + // `Self` in trait or type alias. assert_eq!(opt_self_ty, None); self.prohibit_generics(&path.segments); - // Try to evaluate any array length constants - self.normalize_ty(span, tcx.at(span).type_of(def_id)) + tcx.mk_self_type() } - Def::SelfTy(Some(_), None) => { - // `Self` in trait. + Res::SelfTy(_, Some(def_id)) => { + // `Self` in impl (we know the concrete type). assert_eq!(opt_self_ty, None); self.prohibit_generics(&path.segments); - tcx.mk_self_type() + // Try to evaluate any array length constants. + self.normalize_ty(span, tcx.at(span).type_of(def_id)) } - Def::AssociatedTy(def_id) => { + Res::Def(DefKind::AssocTy, def_id) => { debug_assert!(path.segments.len() >= 2); self.prohibit_generics(&path.segments[..path.segments.len() - 2]); self.qpath_to_ty(span, @@ -1717,7 +2026,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { &path.segments[path.segments.len() - 2], path.segments.last().unwrap()) } - Def::PrimTy(prim_ty) => { + Res::PrimTy(prim_ty) => { assert_eq!(opt_self_ty, None); self.prohibit_generics(&path.segments); match prim_ty { @@ -1729,11 +2038,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { hir::Str => tcx.mk_str() } } - Def::Err => { + Res::Err => { self.set_tainted_by_errors(); return self.tcx().types.err; } - _ => span_bug!(span, "unexpected definition: {:?}", path.def) + _ => span_bug!(span, "unexpected resolution: {:?}", path.res) } } @@ -1757,7 +2066,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } hir::TyKind::Rptr(ref region, ref mt) => { let r = self.ast_region_to_region(region, None); - debug!("Ref r={:?}", r); + debug!("ast_ty_to_ty: r={:?}", r); let t = self.ast_ty_to_ty(&mt.ty); tcx.mk_ref(r, ty::TypeAndMut {ty: t, mutbl: mt.mutbl}) } @@ -1779,28 +2088,26 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let opt_self_ty = maybe_qself.as_ref().map(|qself| { self.ast_ty_to_ty(qself) }); - self.def_to_ty(opt_self_ty, path, false) + self.res_to_ty(opt_self_ty, path, false) } hir::TyKind::Def(item_id, ref lifetimes) => { - let did = tcx.hir().local_def_id(item_id.id); + let did = tcx.hir().local_def_id_from_hir_id(item_id.id); self.impl_trait_ty_to_ty(did, lifetimes) - }, + } hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => { debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment); let ty = self.ast_ty_to_ty(qself); - let def = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.node { - path.def + let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.node { + path.res } else { - Def::Err + Res::Err }; - self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, def, segment, false).0 + self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false) + .map(|(ty, _, _)| ty).unwrap_or(tcx.types.err) } hir::TyKind::Array(ref ty, ref length) => { - let length_def_id = tcx.hir().local_def_id_from_hir_id(length.hir_id); - let substs = InternalSubsts::identity_for_item(tcx, length_def_id); - let length = ty::LazyConst::Unevaluated(length_def_id, substs); - let length = tcx.mk_lazy_const(length); + let length = self.ast_const_to_const(length, tcx.types.usize); let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length)); self.normalize_ty(ast_ty.span, array_ty) } @@ -1817,10 +2124,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { // values in a ExprKind::Closure, or as // the type of local variables. Both of these cases are // handled specially and will not descend into this routine. - self.ty_infer(ast_ty.span) - } - hir::TyKind::Err => { - tcx.types.err + self.ty_infer(None, ast_ty.span) } hir::TyKind::CVarArgs(lt) => { let va_list_did = match tcx.lang_items().va_list() { @@ -1831,12 +2135,70 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let region = self.ast_region_to_region(<, None); tcx.type_of(va_list_did).subst(tcx, &[region.into()]) } + hir::TyKind::Err => { + tcx.types.err + } }; + debug!("ast_ty_to_ty: result_ty={:?}", result_ty); + self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span); result_ty } + /// Returns the `DefId` of the constant parameter that the provided expression is a path to. + pub fn const_param_def_id(&self, expr: &hir::Expr) -> Option { + // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments + // currently have to be wrapped in curly brackets, so it's necessary to special-case. + let expr = match &expr.node { + ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => + block.expr.as_ref().unwrap(), + _ => expr, + }; + + match &expr.node { + ExprKind::Path(hir::QPath::Resolved(_, path)) => match path.res { + Res::Def(DefKind::ConstParam, did) => Some(did), + _ => None, + }, + _ => None, + } + } + + pub fn ast_const_to_const( + &self, + ast_const: &hir::AnonConst, + ty: Ty<'tcx> + ) -> &'tcx ty::Const<'tcx> { + debug!("ast_const_to_const(id={:?}, ast_const={:?})", ast_const.hir_id, ast_const); + + let tcx = self.tcx(); + let def_id = tcx.hir().local_def_id_from_hir_id(ast_const.hir_id); + + let mut const_ = ty::Const { + val: ConstValue::Unevaluated( + def_id, + InternalSubsts::identity_for_item(tcx, def_id), + ), + ty, + }; + + let expr = &tcx.hir().body(ast_const.body).value; + if let Some(def_id) = self.const_param_def_id(expr) { + // Find the name and index of the const parameter by indexing the generics of the + // parent item and construct a `ParamConst`. + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let item_id = tcx.hir().get_parent_node(hir_id); + let item_def_id = tcx.hir().local_def_id_from_hir_id(item_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&tcx.hir().local_def_id_from_hir_id(hir_id)]; + let name = tcx.hir().name(hir_id).as_interned_str(); + const_.val = ConstValue::Param(ty::ParamConst::new(index, name)); + } + + tcx.mk_const(const_) + } + pub fn impl_trait_ty_to_ty( &self, def_id: DefId, @@ -1862,16 +2224,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { _ => bug!() } } else { - // Replace all parent lifetimes with 'static. + // Replace all parent lifetimes with `'static`. match param.kind { GenericParamDefKind::Lifetime => { - tcx.types.re_static.into() + tcx.lifetimes.re_static.into() } _ => tcx.mk_param_from_def(param) } } }); - debug!("impl_trait_ty_to_ty: final substs = {:?}", substs); + debug!("impl_trait_ty_to_ty: substs={:?}", substs); let ty = tcx.mk_opaque(def_id, substs); debug!("impl_trait_ty_to_ty: {}", ty); @@ -1932,7 +2294,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { for br in late_bound_in_ret.difference(&late_bound_in_args) { let lifetime_name = match *br { ty::BrNamed(_, name) => format!("lifetime `{}`,", name), - ty::BrAnon(_) | ty::BrFresh(_) | ty::BrEnv => "an anonymous lifetime".to_string(), + ty::BrAnon(_) | ty::BrEnv => "an anonymous lifetime".to_string(), }; let mut err = struct_span_err!(tcx.sess, decl.output.span(), @@ -1985,7 +2347,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { // If any of the derived region bounds are 'static, that is always // the best choice. if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) { - return Some(tcx.types.re_static); + return Some(tcx.lifetimes.re_static); } // Determine whether there is exactly one unique region in the set @@ -2000,48 +2362,58 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } } -/// Divides a list of general trait bounds into two groups: auto traits (e.g., Sync and Send) and -/// the remaining general trait bounds. -fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - trait_bounds: &'b [hir::PolyTraitRef]) - -> (Vec, Vec<&'b hir::PolyTraitRef>) -{ - let (auto_traits, trait_bounds): (Vec<_>, _) = trait_bounds.iter().partition(|bound| { - // Checks whether `trait_did` is an auto trait and adds it to `auto_traits` if so. - match bound.trait_ref.path.def { - Def::Trait(trait_did) if tcx.trait_is_auto(trait_did) => { - true - } - _ => false - } - }); - - let auto_traits = auto_traits.into_iter().map(|tr| { - if let Def::Trait(trait_did) = tr.trait_ref.path.def { - trait_did - } else { - unreachable!() - } - }).collect::>(); - - (auto_traits, trait_bounds) -} - -// A helper struct for conveniently grouping a set of bounds which we pass to -// and return from functions in multiple places. -#[derive(PartialEq, Eq, Clone, Debug)] +/// Collects together a list of bounds that are applied to some type, +/// after they've been converted into `ty` form (from the HIR +/// representations). These lists of bounds occur in many places in +/// Rust's syntax: +/// +/// ``` +/// trait Foo: Bar + Baz { } +/// ^^^^^^^^^ supertrait list bounding the `Self` type parameter +/// +/// fn foo() { } +/// ^^^^^^^^^ bounding the type parameter `T` +/// +/// impl dyn Bar + Baz +/// ^^^^^^^^^ bounding the forgotten dynamic type +/// ``` +/// +/// Our representation is a bit mixed here -- in some cases, we +/// include the self type (e.g., `trait_bounds`) but in others we do +#[derive(Default, PartialEq, Eq, Clone, Debug)] pub struct Bounds<'tcx> { + /// A list of region bounds on the (implicit) self type. So if you + /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but + /// the `T` is not explicitly included). pub region_bounds: Vec<(ty::Region<'tcx>, Span)>, - pub implicitly_sized: Option, + + /// A list of trait bounds. So if you had `T: Debug` this would be + /// `T: Debug`. Note that the self-type is explicit here. pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span)>, + + /// A list of projection equality bounds. So if you had `T: + /// Iterator` this would include `::Item => u32`. Note that the self-type is explicit + /// here. pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>, + + /// `Some` if there is *no* `?Sized` predicate. The `span` + /// is the location in the source of the `T` declaration which can + /// be cited as the source of the `T: Sized` requirement. + pub implicitly_sized: Option, } -impl<'a, 'gcx, 'tcx> Bounds<'tcx> { - pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'tcx>) - -> Vec<(ty::Predicate<'tcx>, Span)> - { - // If it could be sized, and is, add the sized predicate. +impl<'tcx> Bounds<'tcx> { + /// Converts a bounds list into a flat set of predicates (like + /// where-clauses). Because some of our bounds listings (e.g., + /// regions) don't include the self-type, you must supply the + /// self-type here (the `param_ty` parameter). + pub fn predicates( + &self, + tcx: TyCtxt<'tcx>, + param_ty: Ty<'tcx>, + ) -> Vec<(ty::Predicate<'tcx>, Span)> { + // If it could be sized, and is, add the `Sized` predicate. let sized_predicate = self.implicitly_sized.and_then(|span| { tcx.lang_items().sized_trait().map(|sized| { let trait_ref = ty::TraitRef { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index e27672842dbc1..b435c99ad01f5 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -1,30 +1,31 @@ use crate::check::{FnCtxt, Expectation, Diverges, Needs}; use crate::check::coercion::CoerceMany; use crate::util::nodemap::FxHashMap; -use errors::Applicability; -use rustc::hir::{self, PatKind}; -use rustc::hir::def::{Def, CtorKind}; +use errors::{Applicability, DiagnosticBuilder}; +use rustc::hir::{self, PatKind, Pat, ExprKind}; +use rustc::hir::def::{Res, DefKind, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::infer; -use rustc::infer::type_variable::TypeVariableOrigin; -use rustc::traits::ObligationCauseCode; +use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc::traits::{ObligationCause, ObligationCauseCode}; use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::subst::Kind; use syntax::ast; use syntax::source_map::Spanned; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; +use syntax_pos::hygiene::CompilerDesugaringKind; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::cmp; -use super::report_unexpected_variant_def; +use super::report_unexpected_variant_res; -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - /// `match_discrim_span` argument having a `Span` indicates that this pattern is part of - /// a match expression arm guard, and it points to the match discriminant to add context - /// in type errors. In the folloowing example, `match_discrim_span` corresponds to the - /// `a + b` expression: +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + /// `discrim_span` argument having a `Span` indicates that this pattern is part of a match + /// expression arm guard, and it points to the match discriminant to add context in type errors. + /// In the following example, `discrim_span` corresponds to the `a + b` expression: /// /// ```text /// error[E0308]: mismatched types @@ -40,15 +41,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// ``` pub fn check_pat_walk( &self, - pat: &'gcx hir::Pat, + pat: &'tcx hir::Pat, mut expected: Ty<'tcx>, mut def_bm: ty::BindingMode, - match_discrim_span: Option, + discrim_span: Option, ) { let tcx = self.tcx; debug!("check_pat_walk(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm); + let mut path_resolution = None; let is_non_ref_pat = match pat.node { PatKind::Struct(..) | PatKind::TupleStruct(..) | @@ -64,9 +66,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } PatKind::Path(ref qpath) => { - let (def, _, _) = self.resolve_ty_and_def_ufcs(qpath, pat.hir_id, pat.span); - match def { - Def::Const(..) | Def::AssociatedConst(..) => false, + let resolution = self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span); + path_resolution = Some(resolution); + match resolution.0 { + Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => false, _ => true, } } @@ -88,7 +91,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // See the examples in `run-pass/match-defbm*.rs`. let mut pat_adjustments = vec![]; while let ty::Ref(_, inner_ty, inner_mutability) = exp_ty.sty { - debug!("inspecting {:?} with type {:?}", exp_ty, exp_ty.sty); + debug!("inspecting {:?}", exp_ty); debug!("current discriminant is Ref, inserting implicit deref"); // Preserve the reference type. We'll need it later during HAIR lowering. @@ -131,7 +134,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // } // ``` // - // cc #46688 + // See issue #46688. def_bm = ty::BindByValue(hir::MutImmutable); } @@ -149,21 +152,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty = self.node_ty(lt.hir_id); // Byte string patterns behave the same way as array patterns - // They can denote both statically and dynamically sized byte arrays + // They can denote both statically and dynamically-sized byte arrays. let mut pat_ty = ty; if let hir::ExprKind::Lit(ref lt) = lt.node { if let ast::LitKind::ByteStr(_) = lt.node { let expected_ty = self.structurally_resolved_type(pat.span, expected); if let ty::Ref(_, r_ty, _) = expected_ty.sty { if let ty::Slice(_) = r_ty.sty { - pat_ty = tcx.mk_imm_ref(tcx.types.re_static, + pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8)) } } } } - // somewhat surprising: in this case, the subtyping + // Somewhat surprising: in this case, the subtyping // relation goes the opposite way as the other // cases. Actually what we really want is not a subtyping // relation at all but rather that there exists a LUB (so @@ -174,8 +177,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // &'static str <: expected // - // that's equivalent to there existing a LUB. - self.demand_suptype(pat.span, expected, pat_ty); + // then that's equivalent to there existing a LUB. + if let Some(mut err) = self.demand_suptype_diag(pat.span, expected, pat_ty) { + err.emit_unless(discrim_span + .filter(|&s| s.is_compiler_desugaring(CompilerDesugaringKind::IfTemporary)) + .is_some()); + } + pat_ty } PatKind::Range(ref begin, ref end, _) => { @@ -220,14 +228,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Now that we know the types can be unified we find the unified type and use // it to type the entire expression. - let common_type = self.resolve_type_vars_if_possible(&lhs_ty); + let common_type = self.resolve_vars_if_possible(&lhs_ty); - // subtyping doesn't matter here, as the value is some kind of scalar - self.demand_eqtype_pat(pat.span, expected, lhs_ty, match_discrim_span); - self.demand_eqtype_pat(pat.span, expected, rhs_ty, match_discrim_span); + // Subtyping doesn't matter here, as the value is some kind of scalar. + self.demand_eqtype_pat(pat.span, expected, lhs_ty, discrim_span); + self.demand_eqtype_pat(pat.span, expected, rhs_ty, discrim_span); common_type } - PatKind::Binding(ba, _, var_id, _, ref sub) => { + PatKind::Binding(ba, var_id, _, ref sub) => { let bm = if ba == hir::BindingAnnotation::Unannotated { def_bm } else { @@ -242,8 +250,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let local_ty = self.local_ty(pat.span, pat.hir_id).decl_ty; match bm { ty::BindByReference(mutbl) => { - // if the binding is like - // ref x | ref const x | ref mut x + // If the binding is like + // ref x | ref const x | ref mut x // then `x` is assigned a value of type `&M T` where M is the mutability // and T is the expected type. let region_var = self.next_region_var(infer::PatternRegion(pat.span)); @@ -253,25 +261,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is // required. However, we use equality, which is stronger. See (*) for // an explanation. - self.demand_eqtype_pat(pat.span, region_ty, local_ty, match_discrim_span); + self.demand_eqtype_pat(pat.span, region_ty, local_ty, discrim_span); } - // otherwise the type of x is the expected type T + // Otherwise, the type of x is the expected type `T`. ty::BindByValue(_) => { - // As above, `T <: typeof(x)` is required but we + // As above, `T <: typeof(x)` is required, but we // use equality, see (*) below. - self.demand_eqtype_pat(pat.span, expected, local_ty, match_discrim_span); + self.demand_eqtype_pat(pat.span, expected, local_ty, discrim_span); } } - // if there are multiple arms, make sure they all agree on - // what the type of the binding `x` ought to be + // If there are multiple arms, make sure they all agree on + // what the type of the binding `x` ought to be. if var_id != pat.hir_id { let vt = self.local_ty(pat.span, var_id).decl_ty; - self.demand_eqtype_pat(pat.span, vt, local_ty, match_discrim_span); + self.demand_eqtype_pat(pat.span, vt, local_ty, discrim_span); } if let Some(ref p) = *sub { - self.check_pat_walk(&p, expected, def_bm, match_discrim_span); + self.check_pat_walk(&p, expected, def_bm, discrim_span); } local_ty @@ -284,14 +292,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ddpos, expected, def_bm, - match_discrim_span, + discrim_span, ) } PatKind::Path(ref qpath) => { - self.check_pat_path(pat, qpath, expected) + self.check_pat_path(pat, path_resolution.unwrap(), qpath, expected) } PatKind::Struct(ref qpath, ref fields, etc) => { - self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, match_discrim_span) + self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, discrim_span) } PatKind::Tuple(ref elements, ddpos) => { let mut expected_len = elements.len(); @@ -304,11 +312,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } let max_len = cmp::max(expected_len, elements.len()); - let element_tys_iter = (0..max_len).map(|_| self.next_ty_var( - // FIXME: `MiscVariable` for now -- obtaining the span and name information - // from all tuple elements isn't trivial. - TypeVariableOrigin::TypeInference(pat.span))); - let element_tys = tcx.mk_type_list(element_tys_iter); + let element_tys_iter = (0..max_len).map(|_| { + Kind::from(self.next_ty_var( + // FIXME: `MiscVariable` for now -- obtaining the span and name information + // from all tuple elements isn't trivial. + TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: pat.span, + }, + )) + }); + let element_tys = tcx.mk_substs(element_tys_iter); let pat_ty = tcx.mk_ty(ty::Tuple(element_tys)); if let Some(mut err) = self.demand_eqtype_diag(pat.span, expected, pat_ty) { err.emit(); @@ -316,29 +330,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // further errors being emitted when using the bindings. #50333 let element_tys_iter = (0..max_len).map(|_| tcx.types.err); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat_walk(elem, &tcx.types.err, def_bm, match_discrim_span); + self.check_pat_walk(elem, &tcx.types.err, def_bm, discrim_span); } tcx.mk_tup(element_tys_iter) } else { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat_walk(elem, &element_tys[i], def_bm, match_discrim_span); + self.check_pat_walk( + elem, + &element_tys[i].expect_ty(), + def_bm, + discrim_span, + ); } pat_ty } } PatKind::Box(ref inner) => { - let inner_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(inner.span)); + let inner_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: inner.span, + }); let uniq_ty = tcx.mk_box(inner_ty); if self.check_dereferencable(pat.span, expected, &inner) { // Here, `demand::subtype` is good enough, but I don't // think any errors can be introduced by using // `demand::eqtype`. - self.demand_eqtype_pat(pat.span, expected, uniq_ty, match_discrim_span); - self.check_pat_walk(&inner, inner_ty, def_bm, match_discrim_span); + self.demand_eqtype_pat(pat.span, expected, uniq_ty, discrim_span); + self.check_pat_walk(&inner, inner_ty, def_bm, discrim_span); uniq_ty } else { - self.check_pat_walk(&inner, tcx.types.err, def_bm, match_discrim_span); + self.check_pat_walk(&inner, tcx.types.err, def_bm, discrim_span); tcx.types.err } } @@ -360,7 +382,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } _ => { let inner_ty = self.next_ty_var( - TypeVariableOrigin::TypeInference(inner.span)); + TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: inner.span, + } + ); let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; let region = self.next_region_var(infer::PatternRegion(pat.span)); let rptr_ty = tcx.mk_ref(region, mt); @@ -370,25 +396,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Look for a case like `fn foo(&foo: u32)` and suggest // `fn foo(foo: &u32)` if let Some(mut err) = err { - if let PatKind::Binding(..) = inner.node { - if let Ok(snippet) = tcx.sess.source_map() - .span_to_snippet(pat.span) - { - err.help(&format!("did you mean `{}: &{}`?", - &snippet[1..], - expected)); - } - } + self.borrow_pat_suggestion(&mut err, &pat, &inner, &expected); err.emit(); } (rptr_ty, inner_ty) } }; - self.check_pat_walk(&inner, inner_ty, def_bm, match_discrim_span); + self.check_pat_walk(&inner, inner_ty, def_bm, discrim_span); rptr_ty } else { - self.check_pat_walk(&inner, tcx.types.err, def_bm, match_discrim_span); + self.check_pat_walk(&inner, tcx.types.err, def_bm, discrim_span); tcx.types.err } } @@ -396,27 +414,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_ty = self.structurally_resolved_type(pat.span, expected); let (inner_ty, slice_ty) = match expected_ty.sty { ty::Array(inner_ty, size) => { - let size = size.unwrap_usize(tcx); - let min_len = before.len() as u64 + after.len() as u64; - if slice.is_none() { - if min_len != size { - struct_span_err!( - tcx.sess, pat.span, E0527, - "pattern requires {} elements but array has {}", - min_len, size) - .span_label(pat.span, format!("expected {} elements", size)) + if let Some(size) = size.assert_usize(tcx) { + let min_len = before.len() as u64 + after.len() as u64; + if slice.is_none() { + if min_len != size { + struct_span_err!( + tcx.sess, pat.span, E0527, + "pattern requires {} elements but array has {}", + min_len, size) + .span_label(pat.span, format!("expected {} elements", size)) + .emit(); + } + (inner_ty, tcx.types.err) + } else if let Some(rest) = size.checked_sub(min_len) { + (inner_ty, tcx.mk_array(inner_ty, rest)) + } else { + struct_span_err!(tcx.sess, pat.span, E0528, + "pattern requires at least {} elements but array has {}", + min_len, size) + .span_label(pat.span, + format!("pattern cannot match array of {} elements", size)) .emit(); + (inner_ty, tcx.types.err) } - (inner_ty, tcx.types.err) - } else if let Some(rest) = size.checked_sub(min_len) { - (inner_ty, tcx.mk_array(inner_ty, rest)) } else { - struct_span_err!(tcx.sess, pat.span, E0528, - "pattern requires at least {} elements but array has {}", - min_len, size) - .span_label(pat.span, - format!("pattern cannot match array of {} elements", size)) - .emit(); + struct_span_err!( + tcx.sess, + pat.span, + E0730, + "cannot pattern-match on an array without a fixed length", + ).emit(); (inner_ty, tcx.types.err) } } @@ -446,13 +473,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; for elt in before { - self.check_pat_walk(&elt, inner_ty, def_bm, match_discrim_span); + self.check_pat_walk(&elt, inner_ty, def_bm, discrim_span); } if let Some(ref slice) = *slice { - self.check_pat_walk(&slice, slice_ty, def_bm, match_discrim_span); + self.check_pat_walk(&slice, slice_ty, def_bm, discrim_span); } for elt in after { - self.check_pat_walk(&elt, inner_ty, def_bm, match_discrim_span); + self.check_pat_walk(&elt, inner_ty, def_bm, discrim_span); } expected_ty } @@ -510,6 +537,49 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // subtyping. } + fn borrow_pat_suggestion( + &self, + err: &mut DiagnosticBuilder<'_>, + pat: &Pat, + inner: &Pat, + expected: Ty<'tcx>, + ) { + let tcx = self.tcx; + if let PatKind::Binding(..) = inner.node { + let parent_id = tcx.hir().get_parent_node(pat.hir_id); + let parent = tcx.hir().get(parent_id); + debug!("inner {:?} pat {:?} parent {:?}", inner, pat, parent); + match parent { + hir::Node::Item(hir::Item { node: hir::ItemKind::Fn(..), .. }) | + hir::Node::ForeignItem(hir::ForeignItem { + node: hir::ForeignItemKind::Fn(..), .. + }) | + hir::Node::TraitItem(hir::TraitItem { node: hir::TraitItemKind::Method(..), .. }) | + hir::Node::ImplItem(hir::ImplItem { node: hir::ImplItemKind::Method(..), .. }) => { + // this pat is likely an argument + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { + // FIXME: turn into structured suggestion, will need a span that also + // includes the the arg's type. + err.help(&format!("did you mean `{}: &{}`?", snippet, expected)); + } + } + hir::Node::Arm(_) | + hir::Node::Pat(_) => { + // rely on match ergonomics or it might be nested `&&pat` + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { + err.span_suggestion( + pat.span, + "you can probably remove the explicit borrow", + snippet, + Applicability::MaybeIncorrect, + ); + } + } + _ => {} // don't provide suggestions in other cases #55175 + } + } + } + pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool { if let PatKind::Binding(..) = inner.node { if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) { @@ -545,81 +615,34 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); pub fn check_match( &self, - expr: &'gcx hir::Expr, - discrim: &'gcx hir::Expr, - arms: &'gcx [hir::Arm], + expr: &'tcx hir::Expr, + discrim: &'tcx hir::Expr, + arms: &'tcx [hir::Arm], expected: Expectation<'tcx>, match_src: hir::MatchSource, ) -> Ty<'tcx> { let tcx = self.tcx; - // Not entirely obvious: if matches may create ref bindings, we want to - // use the *precise* type of the discriminant, *not* some supertype, as - // the "discriminant type" (issue #23116). - // - // arielb1 [writes here in this comment thread][c] that there - // is certainly *some* potential danger, e.g., for an example - // like: - // - // [c]: https://github.com/rust-lang/rust/pull/43399#discussion_r130223956 - // - // ``` - // let Foo(x) = f()[0]; - // ``` - // - // Then if the pattern matches by reference, we want to match - // `f()[0]` as a lexpr, so we can't allow it to be - // coerced. But if the pattern matches by value, `f()[0]` is - // still syntactically a lexpr, but we *do* want to allow - // coercions. - // - // However, *likely* we are ok with allowing coercions to - // happen if there are no explicit ref mut patterns - all - // implicit ref mut patterns must occur behind a reference, so - // they will have the "correct" variance and lifetime. - // - // This does mean that the following pattern would be legal: - // - // ``` - // struct Foo(Bar); - // struct Bar(u32); - // impl Deref for Foo { - // type Target = Bar; - // fn deref(&self) -> &Bar { &self.0 } - // } - // impl DerefMut for Foo { - // fn deref_mut(&mut self) -> &mut Bar { &mut self.0 } - // } - // fn foo(x: &mut Foo) { - // { - // let Bar(z): &mut Bar = x; - // *z = 42; - // } - // assert_eq!(foo.0.0, 42); - // } - // ``` - // - // FIXME(tschottdorf): don't call contains_explicit_ref_binding, which - // is problematic as the HIR is being scraped, but ref bindings may be - // implicit after #42640. We need to make sure that pat_adjustments - // (once introduced) is populated by the time we get here. - // - // See #44848. - let contains_ref_bindings = arms.iter() - .filter_map(|a| a.contains_explicit_ref_binding()) - .max_by_key(|m| match *m { - hir::MutMutable => 1, - hir::MutImmutable => 0, - }); - let discrim_ty; - if let Some(m) = contains_ref_bindings { - discrim_ty = self.check_expr_with_needs(discrim, Needs::maybe_mut_place(m)); + use hir::MatchSource::*; + let (source_if, if_no_else, if_desugar) = match match_src { + IfDesugar { contains_else_clause } => (true, !contains_else_clause, true), + IfLetDesugar { contains_else_clause } => (true, !contains_else_clause, false), + _ => (false, false, false), + }; + + // Type check the descriminant and get its type. + let discrim_ty = if if_desugar { + // Here we want to ensure: + // + // 1. That default match bindings are *not* accepted in the condition of an + // `if` expression. E.g. given `fn foo() -> &bool;` we reject `if foo() { .. }`. + // + // 2. By expecting `bool` for `expr` we get nice diagnostics for e.g. `if x = y { .. }`. + // + // FIXME(60707): Consider removing hack with principled solution. + self.check_expr_has_type_or_error(discrim, self.tcx.types.bool) } else { - // ...but otherwise we want to use any supertype of the - // discriminant. This is sort of a workaround, see note (*) in - // `check_pat` for some details. - discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span)); - self.check_expr_has_type_or_error(discrim, discrim_ty); + self.demand_discriminant_type(arms, discrim) }; // If there are no arms, that is a diverging match; a special case. @@ -628,11 +651,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); return tcx.types.never; } - if self.diverges.get().always() { - for arm in arms { - self.warn_if_unreachable(arm.body.hir_id, arm.body.span, "arm"); - } - } + self.warn_arms_when_scrutinee_diverges(arms, source_if); // Otherwise, we have to union together the types that the // arms produce and so forth. @@ -645,12 +664,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let mut all_pats_diverge = Diverges::WarnedAlways; for p in &arm.pats { self.diverges.set(Diverges::Maybe); - self.check_pat_walk( - &p, - discrim_ty, - ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), - Some(discrim.span), - ); + let binding_mode = ty::BindingMode::BindByValue(hir::Mutability::MutImmutable); + self.check_pat_walk(&p, discrim_ty, binding_mode, Some(discrim.span)); all_pats_diverge &= self.diverges.get(); } @@ -684,7 +699,10 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); // arm for inconsistent arms or to the whole match when a `()` type // is required). Expectation::ExpectHasType(ety) if ety != self.tcx.mk_unit() => ety, - _ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)), + _ => self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: expr.span, + }), }; CoerceMany::with_coercion_sites(coerce_first, arms) }; @@ -692,7 +710,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let mut other_arms = vec![]; // used only for diagnostics let mut prior_arm_ty = None; for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { - if let Some(ref g) = arm.guard { + if let Some(g) = &arm.guard { self.diverges.set(pats_diverge); match g { hir::Guard::If(e) => self.check_expr_has_type_or_error(e, tcx.types.bool), @@ -703,42 +721,44 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let arm_ty = self.check_expr_with_expectation(&arm.body, expected); all_arms_diverge &= self.diverges.get(); - // Handle the fallback arm of a desugared if-let like a missing else. - let is_if_let_fallback = match match_src { - hir::MatchSource::IfLetDesugar { contains_else_clause: false } => { - i == arms.len() - 1 && arm_ty.is_unit() + let span = expr.span; + + if source_if { + let then_expr = &arms[0].body; + match (i, if_no_else) { + (0, _) => coercion.coerce(self, &self.misc(span), then_expr, arm_ty), + (_, true) => self.if_fallback_coercion(span, then_expr, &mut coercion), + (_, _) => { + let then_ty = prior_arm_ty.unwrap(); + let cause = self.if_cause(span, then_expr, &arm.body, then_ty, arm_ty); + coercion.coerce(self, &cause, &arm.body, arm_ty); + } } - _ => false - }; - - let arm_span = if let hir::ExprKind::Block(ref blk, _) = arm.body.node { - // Point at the block expr instead of the entire block - blk.expr.as_ref().map(|e| e.span).unwrap_or(arm.body.span) - } else { - arm.body.span - }; - if is_if_let_fallback { - let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse); - assert!(arm_ty.is_unit()); - coercion.coerce_forced_unit(self, &cause, &mut |_| (), true); } else { - let cause = if i == 0 { + let arm_span = if let hir::ExprKind::Block(blk, _) = &arm.body.node { + // Point at the block expr instead of the entire block + blk.expr.as_ref().map(|e| e.span).unwrap_or(arm.body.span) + } else { + arm.body.span + }; + let (span, code) = match i { // The reason for the first arm to fail is not that the match arms diverge, // but rather that there's a prior obligation that doesn't hold. - self.cause(arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)) - } else { - self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { + 0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)), + _ => (span, ObligationCauseCode::MatchExpressionArm { arm_span, source: match_src, prior_arms: other_arms.clone(), last_ty: prior_arm_ty.unwrap(), - }) + discrim_hir_id: discrim.hir_id, + }), }; + let cause = self.cause(span, code); coercion.coerce(self, &cause, &arm.body, arm_ty); - } - other_arms.push(arm_span); - if other_arms.len() > 5 { - other_arms.remove(0); + other_arms.push(arm_span); + if other_arms.len() > 5 { + other_arms.remove(0); + } } prior_arm_ty = Some(arm_ty); } @@ -749,35 +769,280 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); coercion.complete(self) } + /// When the previously checked expression (the scrutinee) diverges, + /// warn the user about the match arms being unreachable. + fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm], source_if: bool) { + if self.diverges.get().always() { + let msg = if source_if { "block in `if` expression" } else { "arm" }; + for arm in arms { + self.warn_if_unreachable(arm.body.hir_id, arm.body.span, msg); + } + } + } + + /// Handle the fallback arm of a desugared if(-let) like a missing else. + fn if_fallback_coercion( + &self, + span: Span, + then_expr: &'tcx hir::Expr, + coercion: &mut CoerceMany<'tcx, '_, rustc::hir::Arm>, + ) { + // If this `if` expr is the parent's function return expr, + // the cause of the type coercion is the return type, point at it. (#25228) + let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, span); + let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse); + coercion.coerce_forced_unit(self, &cause, &mut |err| { + if let Some((span, msg)) = &ret_reason { + err.span_label(*span, msg.as_str()); + } else if let ExprKind::Block(block, _) = &then_expr.node { + if let Some(expr) = &block.expr { + err.span_label(expr.span, "found here".to_string()); + } + } + err.note("`if` expressions without `else` evaluate to `()`"); + err.help("consider adding an `else` block that evaluates to the expected type"); + }, ret_reason.is_none()); + } + + fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, span: Span) -> Option<(Span, String)> { + use hir::Node::{Block, Item, Local}; + + let hir = self.tcx.hir(); + let arm_id = hir.get_parent_node(hir_id); + let match_id = hir.get_parent_node(arm_id); + let containing_id = hir.get_parent_node(match_id); + + let node = hir.get(containing_id); + if let Block(block) = node { + // check that the body's parent is an fn + let parent = hir.get( + hir.get_parent_node( + hir.get_parent_node(block.hir_id), + ), + ); + if let (Some(expr), Item(hir::Item { + node: hir::ItemKind::Fn(..), .. + })) = (&block.expr, parent) { + // check that the `if` expr without `else` is the fn body's expr + if expr.span == span { + return self.get_fn_decl(hir_id).map(|(fn_decl, _)| ( + fn_decl.output.span(), + format!("expected `{}` because of this return type", fn_decl.output), + )); + } + } + } + if let Local(hir::Local { ty: Some(_), pat, .. }) = node { + return Some((pat.span, "expected because of this assignment".to_string())); + } + None + } + + fn if_cause( + &self, + span: Span, + then_expr: &'tcx hir::Expr, + else_expr: &'tcx hir::Expr, + then_ty: Ty<'tcx>, + else_ty: Ty<'tcx>, + ) -> ObligationCause<'tcx> { + let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) { + // The `if`/`else` isn't in one line in the output, include some context to make it + // clear it is an if/else expression: + // ``` + // LL | let x = if true { + // | _____________- + // LL || 10i32 + // || ----- expected because of this + // LL || } else { + // LL || 10u32 + // || ^^^^^ expected i32, found u32 + // LL || }; + // ||_____- if and else have incompatible types + // ``` + Some(span) + } else { + // The entire expression is in one line, only point at the arms + // ``` + // LL | let x = if true { 10i32 } else { 10u32 }; + // | ----- ^^^^^ expected i32, found u32 + // | | + // | expected because of this + // ``` + None + }; + + let mut remove_semicolon = None; + let error_sp = if let ExprKind::Block(block, _) = &else_expr.node { + if let Some(expr) = &block.expr { + expr.span + } else if let Some(stmt) = block.stmts.last() { + // possibly incorrect trailing `;` in the else arm + remove_semicolon = self.could_remove_semicolon(block, then_ty); + stmt.span + } else { // empty block; point at its entirety + // Avoid overlapping spans that aren't as readable: + // ``` + // 2 | let x = if true { + // | _____________- + // 3 | | 3 + // | | - expected because of this + // 4 | | } else { + // | |____________^ + // 5 | || + // 6 | || }; + // | || ^ + // | ||_____| + // | |______if and else have incompatible types + // | expected integer, found () + // ``` + // by not pointing at the entire expression: + // ``` + // 2 | let x = if true { + // | ------- if and else have incompatible types + // 3 | 3 + // | - expected because of this + // 4 | } else { + // | ____________^ + // 5 | | + // 6 | | }; + // | |_____^ expected integer, found () + // ``` + if outer_sp.is_some() { + outer_sp = Some(self.tcx.sess.source_map().def_span(span)); + } + else_expr.span + } + } else { // shouldn't happen unless the parser has done something weird + else_expr.span + }; + + // Compute `Span` of `then` part of `if`-expression. + let then_sp = if let ExprKind::Block(block, _) = &then_expr.node { + if let Some(expr) = &block.expr { + expr.span + } else if let Some(stmt) = block.stmts.last() { + // possibly incorrect trailing `;` in the else arm + remove_semicolon = remove_semicolon.or(self.could_remove_semicolon(block, else_ty)); + stmt.span + } else { // empty block; point at its entirety + outer_sp = None; // same as in `error_sp`; cleanup output + then_expr.span + } + } else { // shouldn't happen unless the parser has done something weird + then_expr.span + }; + + // Finally construct the cause: + self.cause(error_sp, ObligationCauseCode::IfExpression { + then: then_sp, + outer: outer_sp, + semicolon: remove_semicolon, + }) + } + + fn demand_discriminant_type( + &self, + arms: &'tcx [hir::Arm], + discrim: &'tcx hir::Expr, + ) -> Ty<'tcx> { + // Not entirely obvious: if matches may create ref bindings, we want to + // use the *precise* type of the discriminant, *not* some supertype, as + // the "discriminant type" (issue #23116). + // + // arielb1 [writes here in this comment thread][c] that there + // is certainly *some* potential danger, e.g., for an example + // like: + // + // [c]: https://github.com/rust-lang/rust/pull/43399#discussion_r130223956 + // + // ``` + // let Foo(x) = f()[0]; + // ``` + // + // Then if the pattern matches by reference, we want to match + // `f()[0]` as a lexpr, so we can't allow it to be + // coerced. But if the pattern matches by value, `f()[0]` is + // still syntactically a lexpr, but we *do* want to allow + // coercions. + // + // However, *likely* we are ok with allowing coercions to + // happen if there are no explicit ref mut patterns - all + // implicit ref mut patterns must occur behind a reference, so + // they will have the "correct" variance and lifetime. + // + // This does mean that the following pattern would be legal: + // + // ``` + // struct Foo(Bar); + // struct Bar(u32); + // impl Deref for Foo { + // type Target = Bar; + // fn deref(&self) -> &Bar { &self.0 } + // } + // impl DerefMut for Foo { + // fn deref_mut(&mut self) -> &mut Bar { &mut self.0 } + // } + // fn foo(x: &mut Foo) { + // { + // let Bar(z): &mut Bar = x; + // *z = 42; + // } + // assert_eq!(foo.0.0, 42); + // } + // ``` + // + // FIXME(tschottdorf): don't call contains_explicit_ref_binding, which + // is problematic as the HIR is being scraped, but ref bindings may be + // implicit after #42640. We need to make sure that pat_adjustments + // (once introduced) is populated by the time we get here. + // + // See #44848. + let contains_ref_bindings = arms.iter() + .filter_map(|a| a.contains_explicit_ref_binding()) + .max_by_key(|m| match *m { + hir::MutMutable => 1, + hir::MutImmutable => 0, + }); + + if let Some(m) = contains_ref_bindings { + self.check_expr_with_needs(discrim, Needs::maybe_mut_place(m)) + } else { + // ...but otherwise we want to use any supertype of the + // discriminant. This is sort of a workaround, see note (*) in + // `check_pat` for some details. + let discrim_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: discrim.span, + }); + self.check_expr_has_type_or_error(discrim, discrim_ty); + discrim_ty + } + } + fn check_pat_struct( &self, - pat: &'gcx hir::Pat, + pat: &'tcx hir::Pat, qpath: &hir::QPath, - fields: &'gcx [Spanned], + fields: &'tcx [Spanned], etc: bool, expected: Ty<'tcx>, def_bm: ty::BindingMode, - match_discrim_span: Option, - ) -> Ty<'tcx> - { + discrim_span: Option, + ) -> Ty<'tcx> { // Resolve the path and check the definition for errors. let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.hir_id) { variant_ty } else { for field in fields { - self.check_pat_walk( - &field.node.pat, - self.tcx.types.err, - def_bm, - match_discrim_span, - ); + self.check_pat_walk(&field.node.pat, self.tcx.types.err, def_bm, discrim_span); } return self.tcx.types.err; }; // Type-check the path. - self.demand_eqtype_pat(pat.span, expected, pat_ty, match_discrim_span); + self.demand_eqtype_pat(pat.span, expected, pat_ty, discrim_span); // Type-check subpatterns. if self.check_struct_pat_fields(pat_ty, pat.hir_id, pat.span, variant, fields, etc, def_bm) @@ -791,36 +1056,32 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); fn check_pat_path( &self, pat: &hir::Pat, + path_resolution: (Res, Option>, &'b [hir::PathSegment]), qpath: &hir::QPath, expected: Ty<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - // Resolve the path and check the definition for errors. - let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(qpath, pat.hir_id, pat.span); - match def { - Def::Err => { + // We have already resolved the path. + let (res, opt_ty, segments) = path_resolution; + match res { + Res::Err => { self.set_tainted_by_errors(); return tcx.types.err; } - Def::Method(..) => { - report_unexpected_variant_def(tcx, &def, pat.span, qpath); - return tcx.types.err; - } - Def::VariantCtor(_, CtorKind::Fictive) | - Def::VariantCtor(_, CtorKind::Fn) => { - report_unexpected_variant_def(tcx, &def, pat.span, qpath); + Res::Def(DefKind::Method, _) | + Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) | + Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => { + report_unexpected_variant_res(tcx, res, pat.span, qpath); return tcx.types.err; } - Def::VariantCtor(_, CtorKind::Const) | - Def::StructCtor(_, CtorKind::Const) | - Def::SelfCtor(..) | - Def::Const(..) | Def::AssociatedConst(..) => {} // OK - _ => bug!("unexpected pattern definition: {:?}", def) + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::SelfCtor(..) | + Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {} // OK + _ => bug!("unexpected pattern resolution: {:?}", res) } // Type-check the path. - let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.hir_id).0; + let pat_ty = self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id).0; self.demand_suptype(pat.span, expected, pat_ty); pat_ty } @@ -829,7 +1090,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); &self, pat: &hir::Pat, qpath: &hir::QPath, - subpats: &'gcx [P], + subpats: &'tcx [P], ddpos: Option, expected: Ty<'tcx>, def_bm: ty::BindingMode, @@ -841,46 +1102,55 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); self.check_pat_walk(&pat, tcx.types.err, def_bm, match_arm_pat_span); } }; - let report_unexpected_def = |def: Def| { + let report_unexpected_res = |res: Res| { let msg = format!("expected tuple struct/variant, found {} `{}`", - def.kind_name(), + res.descr(), hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false))); - struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg) - .span_label(pat.span, "not a tuple variant or struct").emit(); + let mut err = struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg); + match (res, &pat.node) { + (Res::Def(DefKind::Fn, _), _) | (Res::Def(DefKind::Method, _), _) => { + err.span_label(pat.span, "`fn` calls are not allowed in patterns"); + err.help("for more information, visit \ + https://doc.rust-lang.org/book/ch18-00-patterns.html"); + } + _ => { + err.span_label(pat.span, "not a tuple variant or struct"); + } + } + err.emit(); on_error(); }; // Resolve the path and check the definition for errors. - let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(qpath, pat.hir_id, pat.span); - if def == Def::Err { + let (res, opt_ty, segments) = self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span); + if res == Res::Err { self.set_tainted_by_errors(); on_error(); return self.tcx.types.err; } // Type-check the path. - let (pat_ty, def) = self.instantiate_value_path(segments, opt_ty, def, pat.span, + let (pat_ty, res) = self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id); if !pat_ty.is_fn() { - report_unexpected_def(def); + report_unexpected_res(res); return self.tcx.types.err; } - let variant = match def { - Def::Err => { + let variant = match res { + Res::Err => { self.set_tainted_by_errors(); on_error(); return tcx.types.err; } - Def::AssociatedConst(..) | Def::Method(..) => { - report_unexpected_def(def); + Res::Def(DefKind::AssocConst, _) | Res::Def(DefKind::Method, _) => { + report_unexpected_res(res); return tcx.types.err; } - Def::VariantCtor(_, CtorKind::Fn) | - Def::StructCtor(_, CtorKind::Fn) => { - tcx.expect_variant_def(def) + Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => { + tcx.expect_variant_res(res) } - _ => bug!("unexpected pattern definition: {:?}", def) + _ => bug!("unexpected pattern resolution: {:?}", res) }; // Replace constructor type with constructed type for tuple struct patterns. @@ -894,7 +1164,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); subpats.len() < variant.fields.len() && ddpos.is_some() { let substs = match pat_ty.sty { ty::Adt(_, substs) => substs, - ref ty => bug!("unexpected pattern type {:?}", ty), + _ => bug!("unexpected pattern type {:?}", pat_ty), }; for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs); @@ -907,7 +1177,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let fields_ending = if variant.fields.len() == 1 { "" } else { "s" }; struct_span_err!(tcx.sess, pat.span, E0023, "this pattern has {} field{}, but the corresponding {} has {} field{}", - subpats.len(), subpats_ending, def.kind_name(), + subpats.len(), subpats_ending, res.descr(), variant.fields.len(), fields_ending) .span_label(pat.span, format!("expected {} field{}, found {}", variant.fields.len(), fields_ending, subpats.len())) @@ -918,14 +1188,16 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); pat_ty } - fn check_struct_pat_fields(&self, - adt_ty: Ty<'tcx>, - pat_id: hir::HirId, - span: Span, - variant: &'tcx ty::VariantDef, - fields: &'gcx [Spanned], - etc: bool, - def_bm: ty::BindingMode) -> bool { + fn check_struct_pat_fields( + &self, + adt_ty: Ty<'tcx>, + pat_id: hir::HirId, + span: Span, + variant: &'tcx ty::VariantDef, + fields: &'tcx [Spanned], + etc: bool, + def_bm: ty::BindingMode, + ) -> bool { let tcx = self.tcx; let (substs, adt) = match adt_ty.sty { @@ -948,7 +1220,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let mut inexistent_fields = vec![]; // Typecheck each field. for &Spanned { node: ref field, span } in fields { - let ident = tcx.adjust_ident(field.ident, variant.did, self.body_id).0; + let ident = tcx.adjust_ident(field.ident, variant.def_id); let field_ty = match used_fields.entry(ident) { Occupied(occupied) => { struct_span_err!(tcx.sess, span, E0025, @@ -971,7 +1243,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); self.field_ty(span, f, substs) }) .unwrap_or_else(|| { - inexistent_fields.push((span, field.ident)); + inexistent_fields.push(field.ident); no_field_errors = false; tcx.types.err }) @@ -985,29 +1257,29 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); .map(|field| field.ident.modern()) .filter(|ident| !used_fields.contains_key(&ident)) .collect::>(); - if inexistent_fields.len() > 0 { + if inexistent_fields.len() > 0 && !variant.recovered { let (field_names, t, plural) = if inexistent_fields.len() == 1 { - (format!("a field named `{}`", inexistent_fields[0].1), "this", "") + (format!("a field named `{}`", inexistent_fields[0]), "this", "") } else { (format!("fields named {}", inexistent_fields.iter() - .map(|(_, name)| format!("`{}`", name)) + .map(|ident| format!("`{}`", ident)) .collect::>() .join(", ")), "these", "s") }; - let spans = inexistent_fields.iter().map(|(span, _)| *span).collect::>(); + let spans = inexistent_fields.iter().map(|ident| ident.span).collect::>(); let mut err = struct_span_err!(tcx.sess, spans, E0026, "{} `{}` does not have {}", kind_name, - tcx.item_path_str(variant.did), + tcx.def_path_str(variant.def_id), field_names); - if let Some((span, ident)) = inexistent_fields.last() { - err.span_label(*span, + if let Some(ident) = inexistent_fields.last() { + err.span_label(ident.span, format!("{} `{}` does not have {} field{}", kind_name, - tcx.item_path_str(variant.did), + tcx.def_path_str(variant.def_id), t, plural)); if plural == "" { @@ -1016,8 +1288,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); find_best_match_for_name(input, &ident.as_str(), None); if let Some(suggested_name) = suggested_name { err.span_suggestion( - *span, - "did you mean", + ident.span, + "a field with a similar name exists", suggested_name.to_string(), Applicability::MaybeIncorrect, ); diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index f863cfe1887db..ecdf28e5d7f0b 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -20,8 +20,8 @@ enum AutoderefKind { Overloaded, } -pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> { - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, +pub struct Autoderef<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, steps: Vec<(Ty<'tcx>, AutoderefKind)>, @@ -31,10 +31,10 @@ pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> { include_raw_pointers: bool, span: Span, silence_errors: bool, - reached_recursion_limit: bool + reached_recursion_limit: bool, } -impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { type Item = (Ty<'tcx>, usize); fn next(&mut self) -> Option { @@ -85,20 +85,20 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - span: Span, - base_ty: Ty<'tcx>) - -> Autoderef<'a, 'gcx, 'tcx> - { +impl<'a, 'tcx> Autoderef<'a, 'tcx> { + pub fn new( + infcx: &'a InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + span: Span, + base_ty: Ty<'tcx>, + ) -> Autoderef<'a, 'tcx> { Autoderef { infcx, body_id, param_env, steps: vec![], - cur_ty: infcx.resolve_type_vars_if_possible(&base_ty), + cur_ty: infcx.resolve_vars_if_possible(&base_ty), obligations: vec![], at_start: true, include_raw_pointers: false, @@ -152,19 +152,19 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { ty, normalized_ty, obligations); self.obligations.extend(obligations); - Some(self.infcx.resolve_type_vars_if_possible(&normalized_ty)) + Some(self.infcx.resolve_vars_if_possible(&normalized_ty)) } /// Returns the final type, generating an error if it is an /// unresolved inference variable. - pub fn unambiguous_final_ty(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { + pub fn unambiguous_final_ty(&self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> { fcx.structurally_resolved_type(self.span, self.cur_ty) } /// Returns the final type we ended up with, which may well be an /// inference variable (we will resolve it first, if possible). pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> { - self.infcx.resolve_type_vars_if_possible(&self.cur_ty) + self.infcx.resolve_vars_if_possible(&self.cur_ty) } pub fn step_count(&self) -> usize { @@ -172,13 +172,15 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { } /// Returns the adjustment steps. - pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, needs: Needs) - -> Vec> { + pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>, needs: Needs) -> Vec> { fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx, needs)) } - pub fn adjust_steps_as_infer_ok(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, needs: Needs) - -> InferOk<'tcx, Vec>> { + pub fn adjust_steps_as_infer_ok( + &self, + fcx: &FnCtxt<'a, 'tcx>, + needs: Needs, + ) -> InferOk<'tcx, Vec>> { let mut obligations = vec![]; let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty) .chain(iter::once(self.cur_ty)); @@ -230,7 +232,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self.reached_recursion_limit } - pub fn finalize(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { + pub fn finalize(self, fcx: &FnCtxt<'a, 'tcx>) { fcx.register_predicates(self.into_obligations()); } @@ -239,9 +241,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { } } -pub fn report_autoderef_recursion_limit_error<'a, 'gcx, 'tcx>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, span: Span, ty: Ty<'tcx>) -{ +pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { // We've reached the recursion limit, error gracefully. let suggested_limit = *tcx.sess.recursion_limit.get() * 2; let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", @@ -262,8 +262,8 @@ pub fn report_autoderef_recursion_limit_error<'a, 'gcx, 'tcx>( } } -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> { Autoderef::new(self, self.param_env, self.body_id, span, base_ty) } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 0a4c0eb3aff72..e6999f9e3ac8a 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -2,13 +2,13 @@ use super::autoderef::Autoderef; use super::method::MethodCallee; use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag}; -use errors::Applicability; -use hir::def::Def; +use errors::{Applicability, DiagnosticBuilder}; +use hir::def::Res; use hir::def_id::{DefId, LOCAL_CRATE}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::{infer, traits}; -use rustc::infer::type_variable::TypeVariableOrigin; +use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_target::spec::abi; use syntax::ast::Ident; use syntax_pos::Span; @@ -18,7 +18,7 @@ use rustc::hir; /// Checks that it is legal to call methods of the trait corresponding /// to `trait_id` (this only cares about the trait, not the specific /// method that is called). -pub fn check_legal_trait_for_method_call(tcx: TyCtxt<'_, '_, '_>, span: Span, trait_id: DefId) { +pub fn check_legal_trait_for_method_call(tcx: TyCtxt<'_>, span: Span, trait_id: DefId) { if tcx.lang_items().drop_trait() == Some(trait_id) { struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method") .span_label(span, "explicit destructor calls not allowed") @@ -33,12 +33,12 @@ enum CallStep<'tcx> { Overloaded(MethodCallee<'tcx>), } -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_call( &self, - call_expr: &'gcx hir::Expr, - callee_expr: &'gcx hir::Expr, - arg_exprs: &'gcx [hir::Expr], + call_expr: &'tcx hir::Expr, + callee_expr: &'tcx hir::Expr, + arg_exprs: &'tcx [hir::Expr], expected: Expectation<'tcx>, ) -> Ty<'tcx> { let original_callee_ty = self.check_expr(callee_expr); @@ -78,10 +78,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn try_overloaded_call_step( &self, - call_expr: &'gcx hir::Expr, - callee_expr: &'gcx hir::Expr, - arg_exprs: &'gcx [hir::Expr], - autoderef: &Autoderef<'a, 'gcx, 'tcx>, + call_expr: &'tcx hir::Expr, + callee_expr: &'tcx hir::Expr, + arg_exprs: &'tcx [hir::Expr], + autoderef: &Autoderef<'a, 'tcx>, ) -> Option> { let adjusted_ty = autoderef.unambiguous_final_ty(self); debug!( @@ -165,7 +165,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &self, call_expr: &hir::Expr, adjusted_ty: Ty<'tcx>, - opt_arg_exprs: Option<&'gcx [hir::Expr]>, + opt_arg_exprs: Option<&'tcx [hir::Expr]>, ) -> Option<(Option>, MethodCallee<'tcx>)> { // Try the options that are least restrictive on the caller first. for &(opt_trait_def_id, method_name, borrow) in &[ @@ -193,9 +193,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let opt_input_types = opt_arg_exprs.map(|arg_exprs| [self.tcx.mk_tup( arg_exprs .iter() - .map(|e| self.next_ty_var( - TypeVariableOrigin::TypeInference(e.span) - )) + .map(|e| { + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: e.span, + }) + }) )]); let opt_input_types = opt_input_types.as_ref().map(AsRef::as_ref); @@ -232,11 +235,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None } + /// Give appropriate suggestion when encountering `||{/* not callable */}()`, where the + /// likely intention is to call the closure, suggest `(||{})()`. (#55851) + fn identify_bad_closure_def_and_call( + &self, + err: &mut DiagnosticBuilder<'a>, + hir_id: hir::HirId, + callee_node: &hir::ExprKind, + callee_span: Span, + ) { + let hir_id = self.tcx.hir().get_parent_node(hir_id); + let parent_node = self.tcx.hir().get(hir_id); + if let ( + hir::Node::Expr(hir::Expr { node: hir::ExprKind::Closure(_, _, _, sp, ..), .. }), + hir::ExprKind::Block(..), + ) = (parent_node, callee_node) { + let start = sp.shrink_to_lo(); + let end = self.tcx.sess.source_map().next_point(callee_span); + err.multipart_suggestion( + "if you meant to create this closure and immediately call it, surround the \ + closure with parenthesis", + vec![(start, "(".to_string()), (end, ")".to_string())], + Applicability::MaybeIncorrect, + ); + } + } + fn confirm_builtin_call( &self, call_expr: &hir::Expr, callee_ty: Ty<'tcx>, - arg_exprs: &'gcx [hir::Expr], + arg_exprs: &'tcx [hir::Expr], expected: Expectation<'tcx>, ) -> Ty<'tcx> { let (fn_sig, def_span) = match callee_ty.sty { @@ -268,6 +297,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } ); + self.identify_bad_closure_def_and_call( + &mut err, + call_expr.hir_id, + &callee.node, + callee.span, + ); + if let Some(ref path) = unit_variant { err.span_suggestion( call_expr.span, @@ -284,7 +320,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut inner_callee_path = None; let def = match callee.node { hir::ExprKind::Path(ref qpath) => { - self.tables.borrow().qpath_def(qpath, callee.hir_id) + self.tables.borrow().qpath_res(qpath, callee.hir_id) } hir::ExprKind::Call(ref inner_callee, _) => { // If the call spans more than one line and the callee kind is @@ -305,19 +341,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { inner_callee_path = Some(inner_qpath); self.tables .borrow() - .qpath_def(inner_qpath, inner_callee.hir_id) + .qpath_res(inner_qpath, inner_callee.hir_id) } else { - Def::Err + Res::Err } } - _ => Def::Err, + _ => Res::Err, }; err.span_label(call_expr.span, "call expression requires function"); let def_span = match def { - Def::Err => None, - Def::Local(id) | Def::Upvar(id, ..) => Some(self.tcx.hir().span(id)), + Res::Err => None, + Res::Local(id) => { + Some(self.tcx.hir().span(id)) + }, _ => def .opt_def_id() .and_then(|did| self.tcx.hir().span_if_local(did)), @@ -402,7 +440,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn confirm_deferred_closure_call( &self, call_expr: &hir::Expr, - arg_exprs: &'gcx [hir::Expr], + arg_exprs: &'tcx [hir::Expr], expected: Expectation<'tcx>, fn_sig: ty::FnSig<'tcx>, ) -> Ty<'tcx> { @@ -435,7 +473,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn confirm_overloaded_call( &self, call_expr: &hir::Expr, - arg_exprs: &'gcx [hir::Expr], + arg_exprs: &'tcx [hir::Expr], expected: Expectation<'tcx>, method_callee: MethodCallee<'tcx>, ) -> Ty<'tcx> { @@ -454,9 +492,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } #[derive(Debug)] -pub struct DeferredCallResolution<'gcx: 'tcx, 'tcx> { - call_expr: &'gcx hir::Expr, - callee_expr: &'gcx hir::Expr, +pub struct DeferredCallResolution<'tcx> { + call_expr: &'tcx hir::Expr, + callee_expr: &'tcx hir::Expr, adjusted_ty: Ty<'tcx>, adjustments: Vec>, fn_sig: ty::FnSig<'tcx>, @@ -464,8 +502,8 @@ pub struct DeferredCallResolution<'gcx: 'tcx, 'tcx> { closure_substs: ty::ClosureSubsts<'tcx>, } -impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> { - pub fn resolve(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { +impl<'a, 'tcx> DeferredCallResolution<'tcx> { + pub fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) { debug!("DeferredCallResolution::resolve() {:?}", self); // we should not be invoked until the closure kind has been diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 87276b8c66ca4..53101499af1dc 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -74,7 +74,7 @@ enum PointerKind<'tcx> { OfParam(&'tcx ty::ParamTy), } -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Returns the kind of unsize information of t, or None /// if t is unknown. fn pointer_kind(&self, t: Ty<'tcx>, span: Span) -> @@ -82,7 +82,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { debug!("pointer_kind({:?}, {:?})", t, span); - let t = self.resolve_type_vars_if_possible(&t); + let t = self.resolve_vars_if_possible(&t); if t.references_error() { return Err(ErrorReported); @@ -107,7 +107,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } ty::Tuple(fields) => match fields.last() { None => Some(PointerKind::Thin), - Some(f) => self.pointer_kind(f, span)? + Some(f) => self.pointer_kind(f.expect_ty(), span)? }, // Pointers to foreign types are thin, despite being unsized @@ -158,26 +158,28 @@ impl From for CastError { } } -fn make_invalid_casting_error<'a, 'gcx, 'tcx>(sess: &'a Session, - span: Span, - expr_ty: Ty<'tcx>, - cast_ty: Ty<'tcx>, - fcx: &FnCtxt<'a, 'gcx, 'tcx>) - -> DiagnosticBuilder<'a> { +fn make_invalid_casting_error<'a, 'tcx>( + sess: &'a Session, + span: Span, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, +) -> DiagnosticBuilder<'a> { type_error_struct!(sess, span, expr_ty, E0606, "casting `{}` as `{}` is invalid", fcx.ty_to_string(expr_ty), fcx.ty_to_string(cast_ty)) } -impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { - pub fn new(fcx: &FnCtxt<'a, 'gcx, 'tcx>, - expr: &'tcx hir::Expr, - expr_ty: Ty<'tcx>, - cast_ty: Ty<'tcx>, - cast_span: Span, - span: Span) - -> Result, ErrorReported> { +impl<'a, 'tcx> CastCheck<'tcx> { + pub fn new( + fcx: &FnCtxt<'a, 'tcx>, + expr: &'tcx hir::Expr, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, + cast_span: Span, + span: Span, + ) -> Result, ErrorReported> { let check = CastCheck { expr, expr_ty, @@ -198,7 +200,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } } - fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) { + fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) { match e { CastError::ErrorReported => { // an error has already been reported @@ -326,7 +328,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } } - fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { + fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'tcx>) { if self.cast_ty.references_error() || self.expr_ty.references_error() { return; } @@ -334,7 +336,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { let tstr = fcx.ty_to_string(self.cast_ty); let mut err = type_error_struct!(fcx.tcx.sess, self.span, self.expr_ty, E0620, "cast to unsized type: `{}` as `{}`", - fcx.resolve_type_vars_if_possible(&self.expr_ty), + fcx.resolve_vars_if_possible(&self.expr_ty), tstr); match self.expr_ty.sty { ty::Ref(_, _, mt) => { @@ -386,7 +388,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { err.emit(); } - fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { + fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { let t_cast = self.cast_ty; let t_expr = self.expr_ty; let type_asc_or = if fcx.tcx.features().type_ascription { @@ -412,7 +414,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { err.emit(); } - pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { + pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); @@ -428,13 +430,12 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } else if self.try_coercion_cast(fcx) { self.trivial_cast_lint(fcx); debug!(" -> CoercionCast"); - fcx.tables.borrow_mut().cast_kinds_mut().insert(self.expr.hir_id, - CastKind::CoercionCast); + fcx.tables.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id); + } else { match self.do_check(fcx) { Ok(k) => { debug!(" -> {:?}", k); - fcx.tables.borrow_mut().cast_kinds_mut().insert(self.expr.hir_id, k); } Err(e) => self.report_cast_error(fcx, e), }; @@ -444,7 +445,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { /// Checks a cast, and report an error if one exists. In some cases, this /// can return Ok and create type errors in the fcx rather than returning /// directly. coercion-cast is handled in check instead of here. - fn do_check(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Result { + fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result { use rustc::ty::cast::IntTy::*; use rustc::ty::cast::CastTy::*; @@ -532,11 +533,12 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } } - fn check_ptr_ptr_cast(&self, - fcx: &FnCtxt<'a, 'gcx, 'tcx>, - m_expr: ty::TypeAndMut<'tcx>, - m_cast: ty::TypeAndMut<'tcx>) - -> Result { + fn check_ptr_ptr_cast( + &self, + fcx: &FnCtxt<'a, 'tcx>, + m_expr: ty::TypeAndMut<'tcx>, + m_cast: ty::TypeAndMut<'tcx>, + ) -> Result { debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast); // ptr-ptr cast. vtables must match. @@ -573,10 +575,11 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } } - fn check_fptr_ptr_cast(&self, - fcx: &FnCtxt<'a, 'gcx, 'tcx>, - m_cast: ty::TypeAndMut<'tcx>) - -> Result { + fn check_fptr_ptr_cast( + &self, + fcx: &FnCtxt<'a, 'tcx>, + m_cast: ty::TypeAndMut<'tcx>, + ) -> Result { // fptr-ptr cast. must be to thin ptr match fcx.pointer_kind(m_cast.ty, self.span)? { @@ -586,10 +589,11 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } } - fn check_ptr_addr_cast(&self, - fcx: &FnCtxt<'a, 'gcx, 'tcx>, - m_expr: ty::TypeAndMut<'tcx>) - -> Result { + fn check_ptr_addr_cast( + &self, + fcx: &FnCtxt<'a, 'tcx>, + m_expr: ty::TypeAndMut<'tcx>, + ) -> Result { // ptr-addr cast. must be from thin ptr match fcx.pointer_kind(m_expr.ty, self.span)? { @@ -599,11 +603,12 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } } - fn check_ref_cast(&self, - fcx: &FnCtxt<'a, 'gcx, 'tcx>, - m_expr: ty::TypeAndMut<'tcx>, - m_cast: ty::TypeAndMut<'tcx>) - -> Result { + fn check_ref_cast( + &self, + fcx: &FnCtxt<'a, 'tcx>, + m_expr: ty::TypeAndMut<'tcx>, + m_cast: ty::TypeAndMut<'tcx>, + ) -> Result { // array-ptr-cast. if m_expr.mutbl == hir::MutImmutable && m_cast.mutbl == hir::MutImmutable { @@ -624,10 +629,11 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { Err(CastError::IllegalCast) } - fn check_addr_ptr_cast(&self, - fcx: &FnCtxt<'a, 'gcx, 'tcx>, - m_cast: TypeAndMut<'tcx>) - -> Result { + fn check_addr_ptr_cast( + &self, + fcx: &FnCtxt<'a, 'tcx>, + m_cast: TypeAndMut<'tcx>, + ) -> Result { // ptr-addr cast. pointer must be thin. match fcx.pointer_kind(m_cast.ty, self.span)? { None => Err(CastError::UnknownCastPtrKind), @@ -636,12 +642,12 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } } - fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool { + fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool { fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No).is_ok() } } -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool { let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem); traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index db89b32be7b68..6c0deededdc73 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -7,7 +7,7 @@ use crate::middle::region; use rustc::hir::def_id::DefId; use rustc::infer::{InferOk, InferResult}; use rustc::infer::LateBoundRegionConversionTime; -use rustc::infer::type_variable::TypeVariableOrigin; +use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::traits::Obligation; use rustc::traits::error_reporting::ArgKind; use rustc::ty::{self, Ty, GenericParamDefKind}; @@ -32,12 +32,12 @@ struct ClosureSignatures<'tcx> { liberated_sig: ty::FnSig<'tcx>, } -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_expr_closure( &self, expr: &hir::Expr, _capture: hir::CaptureClause, - decl: &'gcx hir::FnDecl, + decl: &'tcx hir::FnDecl, body_id: hir::BodyId, gen: Option, expected: Expectation<'tcx>, @@ -62,8 +62,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &self, expr: &hir::Expr, opt_kind: Option, - decl: &'gcx hir::FnDecl, - body: &'gcx hir::Body, + decl: &'tcx hir::FnDecl, + body: &'tcx hir::Body, gen: Option, expected_sig: Option>, ) -> Ty<'tcx> { @@ -99,11 +99,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let substs = base_substs.extend_to(self.tcx,expr_def_id, |param, _| { match param.kind { GenericParamDefKind::Lifetime => { - span_bug!(expr.span, "closure has region param") + span_bug!(expr.span, "closure has lifetime param") } - GenericParamDefKind::Type {..} => { - self.infcx - .next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span)).into() + GenericParamDefKind::Type { .. } => { + self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr.span, + }).into() + } + GenericParamDefKind::Const => { + span_bug!(expr.span, "closure has const param") } } }); @@ -244,7 +249,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } /// Given a projection like "::Result == Y", we can deduce - /// everything we need to know about a closure. + /// everything we need to know about a closure or generator. /// /// The `cause_span` should be the span that caused us to /// have this expected signature, or `None` if we can't readily @@ -260,37 +265,50 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let trait_ref = projection.to_poly_trait_ref(tcx); - if tcx.lang_items().fn_trait_kind(trait_ref.def_id()).is_none() { + let is_fn = tcx.lang_items().fn_trait_kind(trait_ref.def_id()).is_some(); + let gen_trait = tcx.lang_items().gen_trait().unwrap(); + let is_gen = gen_trait == trait_ref.def_id(); + if !is_fn && !is_gen { + debug!("deduce_sig_from_projection: not fn or generator"); return None; } - let arg_param_ty = trait_ref.skip_binder().substs.type_at(1); - let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty); - debug!( - "deduce_sig_from_projection: arg_param_ty {:?}", - arg_param_ty - ); + if is_gen { + // Check that we deduce the signature from the `<_ as std::ops::Generator>::Return` + // associated item and not yield. + let return_assoc_item = self.tcx.associated_items(gen_trait).nth(1).unwrap().def_id; + if return_assoc_item != projection.projection_def_id() { + debug!("deduce_sig_from_projection: not return assoc item of generator"); + return None; + } + } - let input_tys = match arg_param_ty.sty { - ty::Tuple(tys) => tys.into_iter(), - _ => return None + let input_tys = if is_fn { + let arg_param_ty = trait_ref.skip_binder().substs.type_at(1); + let arg_param_ty = self.resolve_vars_if_possible(&arg_param_ty); + debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty); + + match arg_param_ty.sty { + ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()).collect::>(), + _ => return None, + } + } else { + // Generators cannot have explicit arguments. + vec![] }; let ret_param_ty = projection.skip_binder().ty; - let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty); - debug!( - "deduce_sig_from_projection: ret_param_ty {:?}", - ret_param_ty - ); + let ret_param_ty = self.resolve_vars_if_possible(&ret_param_ty); + debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty); let sig = self.tcx.mk_fn_sig( - input_tys.cloned(), - ret_param_ty, + input_tys.iter(), + &ret_param_ty, false, hir::Unsafety::Normal, Abi::Rust, ); - debug!("deduce_sig_from_projection: sig {:?}", sig); + debug!("deduce_sig_from_projection: sig={:?}", sig); Some(ExpectedSig { cause_span, sig }) } @@ -574,13 +592,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr_def_id: DefId, decl: &hir::FnDecl, ) -> ty::PolyFnSig<'tcx> { - let astconv: &dyn AstConv<'_, '_> = self; + let astconv: &dyn AstConv<'_> = self; // First, convert the types that the user supplied (if any). let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a)); let supplied_return = match decl.output { hir::Return(ref output) => astconv.ast_ty_to_ty(&output), - hir::DefaultReturn(_) => astconv.ty_infer(decl.output.span()), + hir::DefaultReturn(_) => astconv.ty_infer(None, decl.output.span()), }; let result = ty::Binder::bind(self.tcx.mk_fn_sig( @@ -606,7 +624,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// so should yield an error, but returns back a signature where /// all parameters are of type `TyErr`. fn error_sig_of_closure(&self, decl: &hir::FnDecl) -> ty::PolyFnSig<'tcx> { - let astconv: &dyn AstConv<'_, '_> = self; + let astconv: &dyn AstConv<'_> = self; let supplied_arguments = decl.inputs.iter().map(|a| { // Convert the types that the user supplied (if any), but ignore them. diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 64f61d5e5232e..4bd2f216224a5 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -55,9 +55,11 @@ use errors::DiagnosticBuilder; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::infer::{Coercion, InferResult, InferOk}; -use rustc::infer::type_variable::TypeVariableOrigin; +use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::traits::{self, ObligationCause, ObligationCauseCode}; -use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; +use rustc::ty::adjustment::{ + Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast +}; use rustc::ty::{self, TypeAndMut, Ty, ClosureSubsts}; use rustc::ty::fold::TypeFoldable; use rustc::ty::error::TypeError; @@ -66,10 +68,11 @@ use smallvec::{smallvec, SmallVec}; use std::ops::Deref; use syntax::feature_gate; use syntax::ptr::P; +use syntax::symbol::sym; use syntax_pos; -struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, +struct Coerce<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, cause: ObligationCause<'tcx>, use_lub: bool, /// Determines whether or not allow_two_phase_borrow is set on any @@ -81,8 +84,8 @@ struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { allow_two_phase: AllowTwoPhase, } -impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { - type Target = FnCtxt<'a, 'gcx, 'tcx>; +impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { + type Target = FnCtxt<'a, 'tcx>; fn deref(&self) -> &Self::Target { &self.fcx } @@ -117,10 +120,12 @@ fn success<'tcx>(adj: Vec>, }) } -impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { - fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, - cause: ObligationCause<'tcx>, - allow_two_phase: AllowTwoPhase) -> Self { +impl<'f, 'tcx> Coerce<'f, 'tcx> { + fn new( + fcx: &'f FnCtxt<'f, 'tcx>, + cause: ObligationCause<'tcx>, + allow_two_phase: AllowTwoPhase, + ) -> Self { Coerce { fcx, cause, @@ -170,10 +175,14 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // here, we would coerce from `!` to `?T`. let b = self.shallow_resolve(b); return if self.shallow_resolve(b).is_ty_var() { - // micro-optimization: no need for this if `b` is + // Micro-optimization: no need for this if `b` is // already resolved in some way. let diverging_ty = self.next_diverging_ty_var( - TypeVariableOrigin::AdjustmentType(self.cause.span)); + TypeVariableOrigin { + kind: TypeVariableOriginKind::AdjustmentType, + span: self.cause.span, + }, + ); self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny)) } else { success(simple(Adjust::NeverToAny)(b), b, vec![]) @@ -225,7 +234,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } ty::Closure(def_id_a, substs_a) => { // Non-capturing closures are coercible to - // function pointers + // function pointers or unsafe function pointers. + // It cannot convert closures that require unsafe. self.coerce_closure_to_fn(a, def_id_a, substs_a, b) } _ => { @@ -507,11 +517,14 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // the `CoerceUnsized` target type and the expected type. // We only have the latter, so we use an inference variable // for the former and let type inference do the rest. - let origin = TypeVariableOrigin::MiscVariable(self.cause.span); + let origin = TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: self.cause.span, + }; let coerce_target = self.next_ty_var(origin); let mut coercion = self.unify_and(coerce_target, target, |target| { let unsize = Adjustment { - kind: Adjust::Unsize, + kind: Adjust::Pointer(PointerCast::Unsize), target }; match reborrow { @@ -571,7 +584,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Uncertain or unimplemented. Ok(None) => { if trait_ref.def_id() == unsize_did { - let trait_ref = self.resolve_type_vars_if_possible(&trait_ref); + let trait_ref = self.resolve_vars_if_possible(&trait_ref); let self_ty = trait_ref.skip_binder().self_ty(); let unsize_ty = trait_ref.skip_binder().input_types().nth(1).unwrap(); debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_ref); @@ -617,7 +630,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, - "unsized_tuple_coercion", + sym::unsized_tuple_coercion, self.cause.span, feature_gate::GateIssue::Language, feature_gate::EXPLAIN_UNSIZED_TUPLE_COERCION); @@ -660,7 +673,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); self.coerce_from_safe_fn(a, fn_ty_a, b, - simple(Adjust::UnsafeFnPointer), identity) + simple(Adjust::Pointer(PointerCast::UnsafeFnPointer)), identity) } fn coerce_from_fn_item(&self, @@ -686,11 +699,17 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { b, |unsafe_ty| { vec![ - Adjustment { kind: Adjust::ReifyFnPointer, target: a_fn_pointer }, - Adjustment { kind: Adjust::UnsafeFnPointer, target: unsafe_ty }, + Adjustment { + kind: Adjust::Pointer(PointerCast::ReifyFnPointer), + target: a_fn_pointer + }, + Adjustment { + kind: Adjust::Pointer(PointerCast::UnsafeFnPointer), + target: unsafe_ty + }, ] }, - simple(Adjust::ReifyFnPointer) + simple(Adjust::Pointer(PointerCast::ReifyFnPointer)) )?; obligations.extend(o2); @@ -712,18 +731,22 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let b = self.shallow_resolve(b); - let node_id_a = self.tcx.hir().as_local_node_id(def_id_a).unwrap(); match b.sty { - ty::FnPtr(_) if self.tcx.with_freevars(node_id_a, |v| v.is_empty()) => { + ty::FnPtr(fn_ty) if self.tcx.upvars(def_id_a).map_or(true, |v| v.is_empty()) => { // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` // to // `fn(arg0,arg1,...) -> _` + // or + // `unsafe fn(arg0,arg1,...) -> _` let sig = self.closure_sig(def_id_a, substs_a); - let pointer_ty = self.tcx.coerce_closure_fn_ty(sig); + let unsafety = fn_ty.unsafety(); + let pointer_ty = self.tcx.coerce_closure_fn_ty(sig, unsafety); debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); - self.unify_and(pointer_ty, b, simple(Adjust::ClosureFnPointer)) + self.unify_and(pointer_ty, b, simple( + Adjust::Pointer(PointerCast::ClosureFnPointer(unsafety)) + )) } _ => self.unify_and(a, b, identity), } @@ -762,14 +785,16 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }] }) } else if mt_a.mutbl != mutbl_b { - self.unify_and(a_unsafe, b, simple(Adjust::MutToConstPointer)) + self.unify_and( + a_unsafe, b, simple(Adjust::Pointer(PointerCast::MutToConstPointer)) + ) } else { self.unify_and(a_unsafe, b, identity) } } } -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Attempt to coerce an expression to a type, and return the /// adjusted type of the expression, if successful. /// Adjustments are only recorded if the coercion succeeded. @@ -853,7 +878,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // The only adjustment that can produce an fn item is // `NeverToAny`, so this should always be valid. self.apply_adjustments(expr, vec![Adjustment { - kind: Adjust::ReifyFnPointer, + kind: Adjust::Pointer(PointerCast::ReifyFnPointer), target: fn_ptr }]); } @@ -981,29 +1006,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// } /// let final_ty = coerce.complete(fcx); /// ``` -pub struct CoerceMany<'gcx, 'tcx, 'exprs, E> - where 'gcx: 'tcx, E: 'exprs + AsCoercionSite, -{ +pub struct CoerceMany<'tcx, 'exprs, E: AsCoercionSite> { expected_ty: Ty<'tcx>, final_ty: Option>, - expressions: Expressions<'gcx, 'exprs, E>, + expressions: Expressions<'tcx, 'exprs, E>, pushed: usize, } /// The type of a `CoerceMany` that is storing up the expressions into /// a buffer. We use this in `check/mod.rs` for things like `break`. -pub type DynamicCoerceMany<'gcx, 'tcx> = CoerceMany<'gcx, 'tcx, 'gcx, P>; +pub type DynamicCoerceMany<'tcx> = CoerceMany<'tcx, 'tcx, P>; -enum Expressions<'gcx, 'exprs, E> - where E: 'exprs + AsCoercionSite, -{ - Dynamic(Vec<&'gcx hir::Expr>), +enum Expressions<'tcx, 'exprs, E: AsCoercionSite> { + Dynamic(Vec<&'tcx hir::Expr>), UpFront(&'exprs [E]), } -impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> - where 'gcx: 'tcx, E: 'exprs + AsCoercionSite, -{ +impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { /// The usual case; collect the set of expressions dynamically. /// If the full set of coercion sites is known before hand, /// consider `with_coercion_sites()` instead to avoid allocation. @@ -1022,7 +1041,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> Self::make(expected_ty, Expressions::UpFront(coercion_sites)) } - fn make(expected_ty: Ty<'tcx>, expressions: Expressions<'gcx, 'exprs, E>) -> Self { + fn make(expected_ty: Ty<'tcx>, expressions: Expressions<'tcx, 'exprs, E>) -> Self { CoerceMany { expected_ty, final_ty: None, @@ -1056,12 +1075,13 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> /// could coerce from. This will record `expression`, and later /// calls to `coerce` may come back and add adjustments and things /// if necessary. - pub fn coerce<'a>(&mut self, - fcx: &FnCtxt<'a, 'gcx, 'tcx>, - cause: &ObligationCause<'tcx>, - expression: &'gcx hir::Expr, - expression_ty: Ty<'tcx>) - { + pub fn coerce<'a>( + &mut self, + fcx: &FnCtxt<'a, 'tcx>, + cause: &ObligationCause<'tcx>, + expression: &'tcx hir::Expr, + expression_ty: Ty<'tcx>, + ) { self.coerce_inner(fcx, cause, Some(expression), @@ -1081,12 +1101,13 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> /// The `augment_error` gives you a chance to extend the error /// message, in case any results (e.g., we use this to suggest /// removing a `;`). - pub fn coerce_forced_unit<'a>(&mut self, - fcx: &FnCtxt<'a, 'gcx, 'tcx>, - cause: &ObligationCause<'tcx>, - augment_error: &mut dyn FnMut(&mut DiagnosticBuilder<'_>), - label_unit_as_expected: bool) - { + pub fn coerce_forced_unit<'a>( + &mut self, + fcx: &FnCtxt<'a, 'tcx>, + cause: &ObligationCause<'tcx>, + augment_error: &mut dyn FnMut(&mut DiagnosticBuilder<'_>), + label_unit_as_expected: bool, + ) { self.coerce_inner(fcx, cause, None, @@ -1098,14 +1119,15 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> /// The inner coercion "engine". If `expression` is `None`, this /// is a forced-unit case, and hence `expression_ty` must be /// `Nil`. - fn coerce_inner<'a>(&mut self, - fcx: &FnCtxt<'a, 'gcx, 'tcx>, - cause: &ObligationCause<'tcx>, - expression: Option<&'gcx hir::Expr>, - mut expression_ty: Ty<'tcx>, - augment_error: Option<&mut dyn FnMut(&mut DiagnosticBuilder<'_>)>, - label_expression_as_expected: bool) - { + fn coerce_inner<'a>( + &mut self, + fcx: &FnCtxt<'a, 'tcx>, + cause: &ObligationCause<'tcx>, + expression: Option<&'tcx hir::Expr>, + mut expression_ty: Ty<'tcx>, + augment_error: Option<&mut dyn FnMut(&mut DiagnosticBuilder<'_>)>, + label_expression_as_expected: bool, + ) { // Incorporate whatever type inference information we have // until now; in principle we might also want to process // pending obligations, but doing so should only improve @@ -1209,7 +1231,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> db.span_label(cause.span, "return type is not `()`"); } ObligationCauseCode::BlockTailExpression(blk_id) => { - let parent_id = fcx.tcx.hir().get_parent_node_by_hir_id(blk_id); + let parent_id = fcx.tcx.hir().get_parent_node(blk_id); db = self.report_return_mismatched_types( cause, expected, @@ -1233,7 +1255,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> augment_error(&mut db); } - db.emit(); + // Error possibly reported in `check_assign` so avoid emitting error again. + db.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected)).is_some()); self.final_ty = Some(fcx.tcx.types.err); } @@ -1246,9 +1269,9 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> expected: Ty<'tcx>, found: Ty<'tcx>, err: TypeError<'tcx>, - fcx: &FnCtxt<'a, 'gcx, 'tcx>, + fcx: &FnCtxt<'a, 'tcx>, id: hir::HirId, - expression: Option<(&'gcx hir::Expr, hir::HirId)>, + expression: Option<(&'tcx hir::Expr, hir::HirId)>, ) -> DiagnosticBuilder<'a> { let mut db = fcx.report_mismatched_types(cause, expected, found, err); @@ -1258,7 +1281,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> // Verify that this is a tail expression of a function, otherwise the // label pointing out the cause for the type coercion will be wrong // as prior return coercions would not be relevant (#57664). - let parent_id = fcx.tcx.hir().get_parent_node_by_hir_id(id); + let parent_id = fcx.tcx.hir().get_parent_node(id); let fn_decl = if let Some((expr, blk_id)) = expression { pointing_at_return_type = fcx.suggest_mismatched_types_on_tail( &mut db, @@ -1268,7 +1291,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> cause.span, blk_id, ); - let parent = fcx.tcx.hir().get_by_hir_id(parent_id); + let parent = fcx.tcx.hir().get(parent_id); fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main)) } else { fcx.get_fn_decl(parent_id) @@ -1293,7 +1316,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> db } - pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { + pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> { if let Some(final_ty) = self.final_ty { final_ty } else { diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index e061a5304eb28..946082746f46f 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -1,4 +1,5 @@ use rustc::hir::{self, GenericParamKind, ImplItemKind, TraitItemKind}; +use rustc::hir::def::{Res, DefKind}; use rustc::infer::{self, InferOk}; use rustc::ty::{self, TyCtxt, GenericParamDefKind}; use rustc::ty::util::ExplicitSelf; @@ -6,7 +7,7 @@ use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::error::{ExpectedFound, TypeError}; use rustc::ty::subst::{Subst, InternalSubsts, SubstsRef}; use rustc::util::common::ErrorReported; -use errors::Applicability; +use errors::{Applicability, DiagnosticId}; use syntax_pos::Span; @@ -22,12 +23,14 @@ use super::{Inherited, FnCtxt, potentially_plural_count}; /// - `trait_m`: the method in the trait /// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation -pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_m: &ty::AssociatedItem, - impl_m_span: Span, - trait_m: &ty::AssociatedItem, - impl_trait_ref: ty::TraitRef<'tcx>, - trait_item_span: Option) { +pub fn compare_impl_method<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: &ty::AssocItem, + impl_m_span: Span, + trait_m: &ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, + trait_item_span: Option, +) { debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); @@ -72,19 +75,19 @@ pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_m: &ty::AssociatedItem, - impl_m_span: Span, - trait_m: &ty::AssociatedItem, - impl_trait_ref: ty::TraitRef<'tcx>) - -> Result<(), ErrorReported> { +fn compare_predicate_entailment<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: &ty::AssocItem, + impl_m_span: Span, + trait_m: &ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> Result<(), ErrorReported> { let trait_to_impl_substs = impl_trait_ref.substs; // This node-id should be used for the `body_id` field on each // `ObligationCause` (and the `FnCtxt`). This is what // `regionck_item` expects. - let impl_m_node_id = tcx.hir().as_local_node_id(impl_m.def_id).unwrap(); - let impl_m_hir_id = tcx.hir().node_to_hir_id(impl_m_node_id); + let impl_m_hir_id = tcx.hir().as_local_hir_id(impl_m.def_id).unwrap(); let cause = ObligationCause { span: impl_m_span, @@ -309,7 +312,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let mut diag = struct_span_err!(tcx.sess, - cause.span(&tcx), + cause.span(tcx), E0053, "method `{}` has an incompatible type for trait", trait_m.ident); @@ -355,14 +358,15 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } -fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - span: Span, - impl_m: &ty::AssociatedItem, - trait_m: &ty::AssociatedItem, - trait_generics: &ty::Generics, - impl_generics: &ty::Generics, - trait_to_skol_substs: SubstsRef<'tcx>) - -> Result<(), ErrorReported> { +fn check_region_bounds_on_impl_method<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + impl_m: &ty::AssocItem, + trait_m: &ty::AssocItem, + trait_generics: &ty::Generics, + impl_generics: &ty::Generics, + trait_to_skol_substs: SubstsRef<'tcx>, +) -> Result<(), ErrorReported> { let trait_params = trait_generics.own_counts().lifetimes; let impl_params = impl_generics.own_counts().lifetimes; @@ -385,7 +389,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // the moment, give a kind of vague error message. if trait_params != impl_params { let def_span = tcx.sess.source_map().def_span(span); - let span = tcx.hir().get_generics_span(impl_m.def_id).unwrap_or(def_span); + let span = tcx.hir().get_generics(impl_m.def_id).map(|g| g.span).unwrap_or(def_span); let mut err = struct_span_err!( tcx.sess, span, @@ -396,7 +400,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, err.span_label(span, "lifetimes do not match method in trait"); if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) { let def_sp = tcx.sess.source_map().def_span(sp); - let sp = tcx.hir().get_generics_span(trait_m.def_id).unwrap_or(def_sp); + let sp = tcx.hir().get_generics(trait_m.def_id).map(|g| g.span).unwrap_or(def_sp); err.span_label(sp, "lifetimes in impl do not match this method in trait"); } err.emit(); @@ -406,18 +410,21 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(()) } -fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - terr: &TypeError<'_>, - cause: &ObligationCause<'tcx>, - impl_m: &ty::AssociatedItem, - impl_sig: ty::FnSig<'tcx>, - trait_m: &ty::AssociatedItem, - trait_sig: ty::FnSig<'tcx>) - -> (Span, Option) { +fn extract_spans_for_error_reporting<'a, 'tcx>( + infcx: &infer::InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + terr: &TypeError<'_>, + cause: &ObligationCause<'tcx>, + impl_m: &ty::AssocItem, + impl_sig: ty::FnSig<'tcx>, + trait_m: &ty::AssocItem, + trait_sig: ty::FnSig<'tcx>, +) -> (Span, Option) { let tcx = infcx.tcx; - let impl_m_node_id = tcx.hir().as_local_node_id(impl_m.def_id).unwrap(); - let (impl_m_output, impl_m_iter) = match tcx.hir().expect_impl_item(impl_m_node_id).node { + let impl_m_hir_id = tcx.hir().as_local_hir_id(impl_m.def_id).unwrap(); + let (impl_m_output, impl_m_iter) = match tcx.hir() + .expect_impl_item(impl_m_hir_id) + .node { ImplItemKind::Method(ref impl_m_sig, _) => { (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter()) } @@ -426,8 +433,10 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a match *terr { TypeError::Mutability => { - if let Some(trait_m_node_id) = tcx.hir().as_local_node_id(trait_m.def_id) { - let trait_m_iter = match tcx.hir().expect_trait_item(trait_m_node_id).node { + if let Some(trait_m_hir_id) = tcx.hir().as_local_hir_id(trait_m.def_id) { + let trait_m_iter = match tcx.hir() + .expect_trait_item(trait_m_hir_id) + .node { TraitItemKind::Method(ref trait_m_sig, _) => { trait_m_sig.decl.inputs.iter() } @@ -445,15 +454,15 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a }).map(|(ref impl_arg, ref trait_arg)| { (impl_arg.span, Some(trait_arg.span)) }) - .unwrap_or_else(|| (cause.span(&tcx), tcx.hir().span_if_local(trait_m.def_id))) + .unwrap_or_else(|| (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))) } else { - (cause.span(&tcx), tcx.hir().span_if_local(trait_m.def_id)) + (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)) } } TypeError::Sorts(ExpectedFound { .. }) => { - if let Some(trait_m_node_id) = tcx.hir().as_local_node_id(trait_m.def_id) { + if let Some(trait_m_hir_id) = tcx.hir().as_local_hir_id(trait_m.def_id) { let (trait_m_output, trait_m_iter) = - match tcx.hir().expect_trait_item(trait_m_node_id).node { + match tcx.hir().expect_trait_item(trait_m_hir_id).node { TraitItemKind::Method(ref trait_m_sig, _) => { (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter()) } @@ -480,24 +489,24 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a { (impl_m_output.span(), Some(trait_m_output.span())) } else { - (cause.span(&tcx), tcx.hir().span_if_local(trait_m.def_id)) + (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)) } ) } else { - (cause.span(&tcx), tcx.hir().span_if_local(trait_m.def_id)) + (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)) } } - _ => (cause.span(&tcx), tcx.hir().span_if_local(trait_m.def_id)), + _ => (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)), } } -fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_m: &ty::AssociatedItem, - impl_m_span: Span, - trait_m: &ty::AssociatedItem, - impl_trait_ref: ty::TraitRef<'tcx>) - -> Result<(), ErrorReported> -{ +fn compare_self_type<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: &ty::AssocItem, + impl_m_span: Span, + trait_m: &ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> Result<(), ErrorReported> { // Try to give more informative error messages about self typing // mismatches. Note that any mismatch will also be detected // below, where we construct a canonical function type that @@ -506,7 +515,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // inscrutable, particularly for cases where one method has no // self. - let self_string = |method: &ty::AssociatedItem| { + let self_string = |method: &ty::AssocItem| { let untransformed_self_ty = match method.container { ty::ImplContainer(_) => impl_trait_ref.self_ty(), ty::TraitContainer(_) => tcx.mk_self_type() @@ -546,7 +555,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, err.span_label(span, format!("trait method declared without `{}`", self_descr)); } else { err.note_trait_signature(trait_m.ident.to_string(), - trait_m.signature(&tcx)); + trait_m.signature(tcx)); } err.emit(); return Err(ErrorReported); @@ -566,7 +575,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, err.span_label(span, format!("`{}` used in trait", self_descr)); } else { err.note_trait_signature(trait_m.ident.to_string(), - trait_m.signature(&tcx)); + trait_m.signature(tcx)); } err.emit(); return Err(ErrorReported); @@ -576,70 +585,135 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(()) } -fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_m: &ty::AssociatedItem, - impl_m_span: Span, - trait_m: &ty::AssociatedItem, - trait_item_span: Option) - -> Result<(), ErrorReported> { - let impl_m_generics = tcx.generics_of(impl_m.def_id); - let trait_m_generics = tcx.generics_of(trait_m.def_id); - let num_impl_m_type_params = impl_m_generics.own_counts().types; - let num_trait_m_type_params = trait_m_generics.own_counts().types; - - if num_impl_m_type_params != num_trait_m_type_params { - let impl_m_node_id = tcx.hir().as_local_node_id(impl_m.def_id).unwrap(); - let impl_m_item = tcx.hir().expect_impl_item(impl_m_node_id); - let span = if impl_m_item.generics.params.is_empty() - || impl_m_item.generics.span.is_dummy() // impl Trait in argument position (#55374) - { - impl_m_span - } else { - impl_m_item.generics.span - }; - - let mut err = struct_span_err!(tcx.sess, span, E0049, - "method `{}` has {} but its trait declaration has {}", - trait_m.ident, - potentially_plural_count(num_impl_m_type_params, "type parameter"), - potentially_plural_count(num_trait_m_type_params, "type parameter") - ); +fn compare_number_of_generics<'tcx>( + tcx: TyCtxt<'tcx>, + impl_: &ty::AssocItem, + _impl_span: Span, + trait_: &ty::AssocItem, + trait_span: Option, +) -> Result<(), ErrorReported> { + let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts(); + let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts(); + + let matchings = [ + ("type", trait_own_counts.types, impl_own_counts.types), + ("const", trait_own_counts.consts, impl_own_counts.consts), + ]; + + let mut err_occurred = false; + for &(kind, trait_count, impl_count) in &matchings { + if impl_count != trait_count { + err_occurred = true; + + let ( + trait_spans, + impl_trait_spans, + ) = if let Some(trait_hir_id) = tcx.hir().as_local_hir_id(trait_.def_id) { + let trait_item = tcx.hir().expect_trait_item(trait_hir_id); + if trait_item.generics.params.is_empty() { + (Some(vec![trait_item.generics.span]), vec![]) + } else { + let arg_spans: Vec = trait_item.generics.params.iter() + .map(|p| p.span) + .collect(); + let impl_trait_spans: Vec = trait_item.generics.params.iter() + .filter_map(|p| match p.kind { + GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), .. + } => Some(p.span), + _ => None, + }).collect(); + (Some(arg_spans), impl_trait_spans) + } + } else { + (trait_span.map(|s| vec![s]), vec![]) + }; - let mut suffix = None; + let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap(); + let impl_item = tcx.hir().expect_impl_item(impl_hir_id); + let impl_item_impl_trait_spans: Vec = impl_item.generics.params.iter() + .filter_map(|p| match p.kind { + GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), .. + } => Some(p.span), + _ => None, + }).collect(); + let spans = impl_item.generics.spans(); + let span = spans.primary_span(); + + let mut err = tcx.sess.struct_span_err_with_code( + spans, + &format!( + "method `{}` has {} {kind} parameter{} but its trait \ + declaration has {} {kind} parameter{}", + trait_.ident, + impl_count, + if impl_count != 1 { "s" } else { "" }, + trait_count, + if trait_count != 1 { "s" } else { "" }, + kind = kind, + ), + DiagnosticId::Error("E0049".into()), + ); - if let Some(span) = trait_item_span { - err.span_label(span, format!("expected {}", - potentially_plural_count(num_trait_m_type_params, "type parameter"))); - } else { - suffix = Some(format!(", expected {}", num_trait_m_type_params)); - } + let mut suffix = None; + + if let Some(spans) = trait_spans { + let mut spans = spans.iter(); + if let Some(span) = spans.next() { + err.span_label(*span, format!( + "expected {} {} parameter{}", + trait_count, + kind, + if trait_count != 1 { "s" } else { "" }, + )); + } + for span in spans { + err.span_label(*span, ""); + } + } else { + suffix = Some(format!(", expected {}", trait_count)); + } - err.span_label(span, - format!("found {}{}", - potentially_plural_count(num_impl_m_type_params, "type parameter"), - suffix.as_ref().map(|s| &s[..]).unwrap_or(""))); + if let Some(span) = span { + err.span_label(span, format!( + "found {} {} parameter{}{}", + impl_count, + kind, + if impl_count != 1 { "s" } else { "" }, + suffix.unwrap_or_else(|| String::new()), + )); + } - err.emit(); + for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) { + err.span_label(*span, "`impl Trait` introduces an implicit type parameter"); + } - return Err(ErrorReported); + err.emit(); + } } - Ok(()) + if err_occurred { + Err(ErrorReported) + } else { + Ok(()) + } } -fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_m: &ty::AssociatedItem, - impl_m_span: Span, - trait_m: &ty::AssociatedItem, - trait_item_span: Option) - -> Result<(), ErrorReported> { +fn compare_number_of_method_arguments<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: &ty::AssocItem, + impl_m_span: Span, + trait_m: &ty::AssocItem, + trait_item_span: Option, +) -> Result<(), ErrorReported> { let impl_m_fty = tcx.fn_sig(impl_m.def_id); let trait_m_fty = tcx.fn_sig(trait_m.def_id); let trait_number_args = trait_m_fty.inputs().skip_binder().len(); let impl_number_args = impl_m_fty.inputs().skip_binder().len(); if trait_number_args != impl_number_args { - let trait_m_node_id = tcx.hir().as_local_node_id(trait_m.def_id); - let trait_span = if let Some(trait_id) = trait_m_node_id { + let trait_m_hir_id = tcx.hir().as_local_hir_id(trait_m.def_id); + let trait_span = if let Some(trait_id) = trait_m_hir_id { match tcx.hir().expect_trait_item(trait_id).node { TraitItemKind::Method(ref trait_m_sig, _) => { let pos = if trait_number_args > 0 { @@ -664,8 +738,8 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } else { trait_item_span }; - let impl_m_node_id = tcx.hir().as_local_node_id(impl_m.def_id).unwrap(); - let impl_span = match tcx.hir().expect_impl_item(impl_m_node_id).node { + let impl_m_hir_id = tcx.hir().as_local_hir_id(impl_m.def_id).unwrap(); + let impl_span = match tcx.hir().expect_impl_item(impl_m_hir_id).node { ImplItemKind::Method(ref impl_m_sig, _) => { let pos = if impl_number_args > 0 { impl_number_args - 1 @@ -693,14 +767,14 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait `{}` has {}", trait_m.ident, potentially_plural_count(impl_number_args, "parameter"), - tcx.item_path_str(trait_m.def_id), + tcx.def_path_str(trait_m.def_id), trait_number_args); if let Some(trait_span) = trait_span { err.span_label(trait_span, format!("trait requires {}", potentially_plural_count(trait_number_args, "parameter"))); } else { err.note_trait_signature(trait_m.ident.to_string(), - trait_m.signature(&tcx)); + trait_m.signature(tcx)); } err.span_label(impl_span, format!("expected {}, found {}", potentially_plural_count(trait_number_args, "parameter"), impl_number_args)); @@ -711,10 +785,11 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(()) } -fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_m: &ty::AssociatedItem, - trait_m: &ty::AssociatedItem) - -> Result<(), ErrorReported> { +fn compare_synthetic_generics<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: &ty::AssocItem, + trait_m: &ty::AssocItem, +) -> Result<(), ErrorReported> { // FIXME(chrisvittal) Clean up this function, list of FIXME items: // 1. Better messages for the span labels // 2. Explanation as to what is going on @@ -725,12 +800,12 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_m_generics = tcx.generics_of(trait_m.def_id); let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind { GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), - GenericParamDefKind::Lifetime => None, + GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None, }); let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| { match param.kind { GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), - GenericParamDefKind::Lifetime => None, + GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None, } }); for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) @@ -738,7 +813,7 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { if impl_synthetic != trait_synthetic { let impl_hir_id = tcx.hir().as_local_hir_id(impl_def_id).unwrap(); - let impl_span = tcx.hir().span_by_hir_id(impl_hir_id); + let impl_span = tcx.hir().span(impl_hir_id); let trait_span = tcx.def_span(trait_def_id); let mut err = struct_span_err!(tcx.sess, impl_span, @@ -760,11 +835,11 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .source_map() .span_to_snippet(trait_span) .ok()?; - let trait_m = tcx.hir().as_local_node_id(trait_m.def_id)?; - let trait_m = tcx.hir().trait_item(hir::TraitItemId { node_id: trait_m }); + let trait_m = tcx.hir().as_local_hir_id(trait_m.def_id)?; + let trait_m = tcx.hir().trait_item(hir::TraitItemId { hir_id: trait_m }); - let impl_m = tcx.hir().as_local_node_id(impl_m.def_id)?; - let impl_m = tcx.hir().impl_item(hir::ImplItemId { node_id: impl_m }); + let impl_m = tcx.hir().as_local_hir_id(impl_m.def_id)?; + let impl_m = tcx.hir().impl_item(hir::ImplItemId { hir_id: impl_m }); // in case there are no generics, take the spot between the function name // and the opening paren of the argument list @@ -805,8 +880,8 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (None, Some(hir::SyntheticTyParamKind::ImplTrait)) => { err.span_label(impl_span, "expected `impl Trait`, found generic parameter"); (|| { - let impl_m = tcx.hir().as_local_node_id(impl_m.def_id)?; - let impl_m = tcx.hir().impl_item(hir::ImplItemId { node_id: impl_m }); + let impl_m = tcx.hir().as_local_hir_id(impl_m.def_id)?; + let impl_m = tcx.hir().impl_item(hir::ImplItemId { hir_id: impl_m }); let input_tys = match impl_m.node { hir::ImplItemKind::Method(ref sig, _) => &sig.decl.inputs, _ => unreachable!(), @@ -818,7 +893,7 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let hir::TyKind::Path( hir::QPath::Resolved(None, ref path)) = ty.node { - if let hir::def::Def::TyParam(def_id) = path.def { + if let Res::Def(DefKind::TyParam, def_id) = path.res { if def_id == self.1 { self.0 = Some(ty.span); } @@ -883,15 +958,17 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_c: &ty::AssociatedItem, - impl_c_span: Span, - trait_c: &ty::AssociatedItem, - impl_trait_ref: ty::TraitRef<'tcx>) { +pub fn compare_const_impl<'tcx>( + tcx: TyCtxt<'tcx>, + impl_c: &ty::AssocItem, + impl_c_span: Span, + trait_c: &ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) { debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); tcx.infer_ctxt().enter(|infcx| { - let param_env = ty::ParamEnv::empty(); + let param_env = tcx.param_env(impl_c.def_id); let inh = Inherited::new(infcx, impl_c.def_id); let infcx = &inh.infcx; @@ -904,8 +981,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Create a parameter environment that represents the implementation's // method. - let impl_c_node_id = tcx.hir().as_local_node_id(impl_c.def_id).unwrap(); - let impl_c_hir_id = tcx.hir().node_to_hir_id(impl_c_node_id); + let impl_c_hir_id = tcx.hir().as_local_hir_id(impl_c.def_id).unwrap(); // Compute placeholder form of impl and trait const tys. let impl_ty = tcx.type_of(impl_c.def_id); @@ -937,7 +1013,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_ty); // Locate the Span containing just the type of the offending impl - match tcx.hir().expect_impl_item(impl_c_node_id).node { + match tcx.hir().expect_impl_item(impl_c_hir_id).node { ImplItemKind::Const(ref ty, _) => cause.span = ty.span, _ => bug!("{:?} is not a impl const", impl_c), } @@ -949,10 +1025,10 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait", trait_c.ident); - let trait_c_node_id = tcx.hir().as_local_node_id(trait_c.def_id); - let trait_c_span = trait_c_node_id.map(|trait_c_node_id| { + let trait_c_hir_id = tcx.hir().as_local_hir_id(trait_c.def_id); + let trait_c_span = trait_c_hir_id.map(|trait_c_hir_id| { // Add a label to the Span containing just the type of the const - match tcx.hir().expect_trait_item(trait_c_node_id).node { + match tcx.hir().expect_trait_item(trait_c_hir_id).node { TraitItemKind::Const(ref ty, _) => ty.span, _ => bug!("{:?} is not a trait const", trait_c), } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index f736e7ac29d08..14c38ae053d23 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -1,20 +1,20 @@ use crate::check::FnCtxt; use rustc::infer::InferOk; -use rustc::traits::{ObligationCause, ObligationCauseCode}; +use rustc::traits::{self, ObligationCause, ObligationCauseCode}; +use syntax::symbol::sym; use syntax::util::parser::PREC_POSTFIX; use syntax_pos::Span; use rustc::hir; -use rustc::hir::def::Def; use rustc::hir::Node; -use rustc::hir::{Item, ItemKind, print}; -use rustc::ty::{self, Ty, AssociatedItem}; +use rustc::hir::{print, lowering::is_range_literal}; +use rustc::ty::{self, Ty, AssocItem}; use rustc::ty::adjustment::AllowTwoPhase; -use errors::{Applicability, DiagnosticBuilder, SourceMapper}; +use errors::{Applicability, DiagnosticBuilder}; use super::method::probe; -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Requires that the two types unify, and prints an error message if // they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { @@ -119,46 +119,68 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e); - // If the expected type is an enum (Issue #55250) with any variants whose - // sole field is of the found type, suggest such variants. (Issue #42764) - if let ty::Adt(expected_adt, substs) = expected.sty { - if expected_adt.is_enum() { - let mut compatible_variants = expected_adt.variants - .iter() - .filter(|variant| variant.fields.len() == 1) - .filter_map(|variant| { - let sole_field = &variant.fields[0]; - let sole_field_ty = sole_field.ty(self.tcx, substs); - if self.can_coerce(expr_ty, sole_field_ty) { - let variant_path = self.tcx.item_path_str(variant.did); - // FIXME #56861: DRYer prelude filtering - Some(variant_path.trim_start_matches("std::prelude::v1::").to_string()) - } else { - None - } - }).peekable(); - - if compatible_variants.peek().is_some() { - let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr)); - let suggestions = compatible_variants - .map(|v| format!("{}({})", v, expr_text)); - err.span_suggestions( - expr.span, - "try using a variant of the expected type", - suggestions, - Applicability::MaybeIncorrect, - ); - } - } + if self.is_assign_to_bool(expr, expected) { + // Error reported in `check_assign` so avoid emitting error again. + err.delay_as_bug(); + return (expected, None) } + self.suggest_compatible_variants(&mut err, expr, expected, expr_ty); self.suggest_ref_or_into(&mut err, expr, expected, expr_ty); + self.suggest_missing_await(&mut err, expr, expected, expr_ty); (expected, Some(err)) } + /// Returns whether the expected type is `bool` and the expression is `x = y`. + pub fn is_assign_to_bool(&self, expr: &hir::Expr, expected: Ty<'tcx>) -> bool { + if let hir::ExprKind::Assign(..) = expr.node { + return expected == self.tcx.types.bool; + } + false + } + + /// If the expected type is an enum (Issue #55250) with any variants whose + /// sole field is of the found type, suggest such variants. (Issue #42764) + fn suggest_compatible_variants( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr, + expected: Ty<'tcx>, + expr_ty: Ty<'tcx>, + ) { + if let ty::Adt(expected_adt, substs) = expected.sty { + if !expected_adt.is_enum() { + return; + } + + let mut compatible_variants = expected_adt.variants + .iter() + .filter(|variant| variant.fields.len() == 1) + .filter_map(|variant| { + let sole_field = &variant.fields[0]; + let sole_field_ty = sole_field.ty(self.tcx, substs); + if self.can_coerce(expr_ty, sole_field_ty) { + let variant_path = self.tcx.def_path_str(variant.def_id); + // FIXME #56861: DRYer prelude filtering + Some(variant_path.trim_start_matches("std::prelude::v1::").to_string()) + } else { + None + } + }).peekable(); + + if compatible_variants.peek().is_some() { + let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr)); + let suggestions = compatible_variants + .map(|v| format!("{}({})", v, expr_text)); + let msg = "try using a variant of the expected type"; + err.span_suggestions(expr.span, msg, suggestions, Applicability::MaybeIncorrect); + } + } + } + pub fn get_conversion_methods(&self, span: Span, expected: Ty<'tcx>, checked_ty: Ty<'tcx>) - -> Vec { + -> Vec { let mut methods = self.probe_for_return_type(span, probe::Mode::MethodCall, expected, @@ -177,17 +199,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // FIXME? Other potential candidate methods: `as_ref` and // `as_mut`? - .find(|a| a.check_name("rustc_conversion_suggestion")).is_some() + .find(|a| a.check_name(sym::rustc_conversion_suggestion)).is_some() }); methods } // This function checks if the method isn't static and takes other arguments than `self`. - fn has_no_input_arg(&self, method: &AssociatedItem) -> bool { - match method.def() { - Def::Method(def_id) => { - self.tcx.fn_sig(def_id).inputs().skip_binder().len() == 1 + fn has_no_input_arg(&self, method: &AssocItem) -> bool { + match method.kind { + ty::AssocKind::Method => { + self.tcx.fn_sig(method.def_id).inputs().skip_binder().len() == 1 } _ => false, } @@ -214,18 +236,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &hir::Expr, ) -> Option<(Span, &'static str, String)> { if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.node { - if let hir::def::Def::Local(id) = path.def { + if let hir::def::Res::Local(id) = path.res { let parent = self.tcx.hir().get_parent_node(id); if let Some(Node::Expr(hir::Expr { hir_id, node: hir::ExprKind::Closure(_, decl, ..), .. })) = self.tcx.hir().find(parent) { - let parent = self.tcx.hir().get_parent_node_by_hir_id(*hir_id); + let parent = self.tcx.hir().get_parent_node(*hir_id); if let (Some(Node::Expr(hir::Expr { node: hir::ExprKind::MethodCall(path, span, expr), .. - })), 1) = (self.tcx.hir().find_by_hir_id(parent), decl.inputs.len()) { + })), 1) = (self.tcx.hir().find(parent), decl.inputs.len()) { let self_ty = self.tables.borrow().node_type(expr[0].hir_id); let self_ty = format!("{:?}", self_ty); let name = path.ident.as_str(); @@ -249,6 +271,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None } + crate fn is_hir_id_from_struct_pattern_shorthand_field( + &self, + hir_id: hir::HirId, + sp: Span, + ) -> bool { + let cm = self.sess().source_map(); + let parent_id = self.tcx.hir().get_parent_node(hir_id); + if let Some(parent) = self.tcx.hir().find(parent_id) { + // Account for fields + if let Node::Expr(hir::Expr { + node: hir::ExprKind::Struct(_, fields, ..), .. + }) = parent { + if let Ok(src) = cm.span_to_snippet(sp) { + for field in fields { + if field.ident.as_str() == src.as_str() && field.is_shorthand { + return true; + } + } + } + } + } + false + } + /// This function is used to determine potential "simple" improvements or users' errors and /// provide them useful help. For example: /// @@ -265,20 +311,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// In addition of this check, it also checks between references mutability state. If the /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with /// `&mut`!". - pub fn check_ref(&self, - expr: &hir::Expr, - checked_ty: Ty<'tcx>, - expected: Ty<'tcx>) - -> Option<(Span, &'static str, String)> { + pub fn check_ref( + &self, + expr: &hir::Expr, + checked_ty: Ty<'tcx>, + expected: Ty<'tcx>, + ) -> Option<(Span, &'static str, String)> { let cm = self.sess().source_map(); - // Use the callsite's span if this is a macro call. #41858 - let sp = cm.call_span_if_macro(expr.span); + let sp = expr.span; if !cm.span_to_filename(sp).is_real() { + // Ignore if span is from within a macro #41858, #58298. We previously used the macro + // call span, but that breaks down when the type error comes from multiple calls down. return None; } - match (&expected.sty, &checked_ty.sty) { - (&ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.sty, &check.sty) { + let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field( + expr.hir_id, + sp, + ); + + // Check the `expn_info()` to see if this is a macro; if so, it's hard to + // extract the text and make a good suggestion, so don't bother. + let is_macro = sp.ctxt().outer_expn_info().is_some(); + + match (&expr.node, &expected.sty, &checked_ty.sty) { + (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.sty, &check.sty) { (&ty::Str, &ty::Array(arr, _)) | (&ty::Str, &ty::Slice(arr)) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.node { @@ -305,7 +362,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } _ => {} }, - (&ty::Ref(_, _, mutability), _) => { + (_, &ty::Ref(_, _, mutability), _) => { // Check if it can work when put into a ref. For example: // // ``` @@ -315,21 +372,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // bar(&x); // error, expected &mut // ``` let ref_ty = match mutability { - hir::Mutability::MutMutable => self.tcx.mk_mut_ref( - self.tcx.mk_region(ty::ReStatic), - checked_ty), - hir::Mutability::MutImmutable => self.tcx.mk_imm_ref( - self.tcx.mk_region(ty::ReStatic), - checked_ty), + hir::Mutability::MutMutable => { + self.tcx.mk_mut_ref(self.tcx.mk_region(ty::ReStatic), checked_ty) + } + hir::Mutability::MutImmutable => { + self.tcx.mk_imm_ref(self.tcx.mk_region(ty::ReStatic), checked_ty) + } }; if self.can_coerce(ref_ty, expected) { - if let Ok(src) = cm.span_to_snippet(sp) { + let mut sugg_sp = sp; + if let hir::ExprKind::MethodCall(segment, _sp, args) = &expr.node { + let clone_trait = self.tcx.lang_items().clone_trait().unwrap(); + if let ([arg], Some(true), "clone") = ( + &args[..], + self.tables.borrow().type_dependent_def_id(expr.hir_id).map(|did| { + let ai = self.tcx.associated_item(did); + ai.container == ty::TraitContainer(clone_trait) + }), + &segment.ident.as_str()[..], + ) { + // If this expression had a clone call when suggesting borrowing + // we want to suggest removing it because it'd now be unecessary. + sugg_sp = arg.span; + } + } + if let Ok(src) = cm.span_to_snippet(sugg_sp) { let needs_parens = match expr.node { // parenthesize if needed (Issue #46756) hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, // parenthesize borrows of range literals (Issue #54505) - _ if self.is_range_literal(expr) => true, + _ if is_range_literal(self.tcx.sess, expr) => true, _ => false, }; let sugg_expr = if needs_parens { @@ -341,125 +414,115 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(sugg) = self.can_use_as_ref(expr) { return Some(sugg); } - return Some(match mutability { - hir::Mutability::MutMutable => { - (sp, "consider mutably borrowing here", format!("&mut {}", - sugg_expr)) - } - hir::Mutability::MutImmutable => { - (sp, "consider borrowing here", format!("&{}", sugg_expr)) + let field_name = if is_struct_pat_shorthand_field { + format!("{}: ", sugg_expr) + } else { + String::new() + }; + if let Some(hir::Node::Expr(hir::Expr { + node: hir::ExprKind::Assign(left_expr, _), + .. + })) = self.tcx.hir().find( + self.tcx.hir().get_parent_node(expr.hir_id), + ) { + if mutability == hir::Mutability::MutMutable { + // Found the following case: + // fn foo(opt: &mut Option){ opt = None } + // --- ^^^^ + // | | + // consider dereferencing here: `*opt` | + // expected mutable reference, found enum `Option` + if let Ok(src) = cm.span_to_snippet(left_expr.span) { + return Some(( + left_expr.span, + "consider dereferencing here to assign to the mutable \ + borrowed piece of memory", + format!("*{}", src), + )); + } } + } + + return Some(match mutability { + hir::Mutability::MutMutable => ( + sp, + "consider mutably borrowing here", + format!("{}&mut {}", field_name, sugg_expr), + ), + hir::Mutability::MutImmutable => ( + sp, + "consider borrowing here", + format!("{}&{}", field_name, sugg_expr), + ), }); } } - } - (_, &ty::Ref(_, checked, _)) => { + }, + (hir::ExprKind::AddrOf(_, ref expr), _, &ty::Ref(_, checked, _)) if { + self.infcx.can_sub(self.param_env, checked, &expected).is_ok() && !is_macro + } => { // We have `&T`, check if what was expected was `T`. If so, - // we may want to suggest adding a `*`, or removing - // a `&`. - // - // (But, also check the `expn_info()` to see if this is - // a macro; if so, it's hard to extract the text and make a good - // suggestion, so don't bother.) - if self.infcx.can_sub(self.param_env, checked, &expected).is_ok() && - sp.ctxt().outer().expn_info().is_none() { - match expr.node { - // Maybe remove `&`? - hir::ExprKind::AddrOf(_, ref expr) => { - if !cm.span_to_filename(expr.span).is_real() { - return None; - } - if let Ok(code) = cm.span_to_snippet(expr.span) { - return Some((sp, "consider removing the borrow", code)); - } - } - - // Maybe add `*`? Only if `T: Copy`. - _ => { - if self.infcx.type_is_copy_modulo_regions(self.param_env, - checked, - sp) { - // do not suggest if the span comes from a macro (#52783) - if let (Ok(code), - true) = (cm.span_to_snippet(sp), sp == expr.span) { - return Some(( - sp, - "consider dereferencing the borrow", - format!("*{}", code), - )); - } - } + // we may want to suggest removing a `&`. + if !cm.span_to_filename(expr.span).is_real() { + if let Ok(code) = cm.span_to_snippet(sp) { + if code.chars().next() == Some('&') { + return Some(( + sp, + "consider removing the borrow", + code[1..].to_string(), + )); } } + return None; } - } - _ => {} - } - None - } - - /// This function checks if the specified expression is a built-in range literal. - /// (See: `LoweringContext::lower_expr()` in `src/librustc/hir/lowering.rs`). - fn is_range_literal(&self, expr: &hir::Expr) -> bool { - use hir::{Path, QPath, ExprKind, TyKind}; - - // We support `::std::ops::Range` and `::core::ops::Range` prefixes - let is_range_path = |path: &Path| { - let mut segs = path.segments.iter() - .map(|seg| seg.ident.as_str()); - - if let (Some(root), Some(std_core), Some(ops), Some(range), None) = - (segs.next(), segs.next(), segs.next(), segs.next(), segs.next()) - { - // "{{root}}" is the equivalent of `::` prefix in Path - root == "{{root}}" && (std_core == "std" || std_core == "core") - && ops == "ops" && range.starts_with("Range") - } else { - false - } - }; - - let span_is_range_literal = |span: &Span| { - // Check whether a span corresponding to a range expression - // is a range literal, rather than an explicit struct or `new()` call. - let source_map = self.tcx.sess.source_map(); - let end_point = source_map.end_point(*span); - - if let Ok(end_string) = source_map.span_to_snippet(end_point) { - !(end_string.ends_with("}") || end_string.ends_with(")")) - } else { - false - } - }; - - match expr.node { - // All built-in range literals but `..=` and `..` desugar to Structs - ExprKind::Struct(ref qpath, _, _) => { - if let QPath::Resolved(None, ref path) = **qpath { - return is_range_path(&path) && span_is_range_literal(&expr.span); + if let Ok(code) = cm.span_to_snippet(expr.span) { + return Some((sp, "consider removing the borrow", code)); } - } - // `..` desugars to its struct path - ExprKind::Path(QPath::Resolved(None, ref path)) => { - return is_range_path(&path) && span_is_range_literal(&expr.span); - } - - // `..=` desugars into `::std::ops::RangeInclusive::new(...)` - ExprKind::Call(ref func, _) => { - if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node { - if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node { - let call_to_new = segment.ident.as_str() == "new"; - - return is_range_path(&path) && span_is_range_literal(&expr.span) - && call_to_new; + }, + _ if sp == expr.span && !is_macro => { + // Check for `Deref` implementations by constructing a predicate to + // prove: `::Output == U` + let deref_trait = self.tcx.lang_items().deref_trait().unwrap(); + let item_def_id = self.tcx.associated_items(deref_trait).next().unwrap().def_id; + let predicate = ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate { + // `::Output` + projection_ty: ty::ProjectionTy { + // `T` + substs: self.tcx.mk_substs_trait( + checked_ty, + self.fresh_substs_for_item(sp, item_def_id), + ), + // `Deref::Output` + item_def_id, + }, + // `U` + ty: expected, + })); + let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); + let impls_deref = self.infcx.predicate_may_hold(&obligation); + + // For a suggestion to make sense, the type would need to be `Copy`. + let is_copy = self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp); + + if is_copy && impls_deref { + if let Ok(code) = cm.span_to_snippet(sp) { + let message = if checked_ty.is_region_ptr() { + "consider dereferencing the borrow" + } else { + "consider dereferencing the type" + }; + let suggestion = if is_struct_pat_shorthand_field { + format!("{}: *{}", code, code) + } else { + format!("*{}", code) + }; + return Some((sp, message, suggestion)); } } } - _ => {} } - - false + None } pub fn check_for_cast( @@ -469,22 +532,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, ) -> bool { - let parent_id = self.tcx.hir().get_parent_node_by_hir_id(expr.hir_id); - if let Some(parent) = self.tcx.hir().find_by_hir_id(parent_id) { + if self.tcx.hir().is_const_scope(expr.hir_id) { // Shouldn't suggest `.into()` on `const`s. - if let Node::Item(Item { node: ItemKind::Const(_, _), .. }) = parent { - // FIXME(estebank): modify once we decide to suggest `as` casts - return false; - } - }; - - let will_truncate = "will truncate the source value"; - let depending_on_isize = "will truncate or zero-extend depending on the bit width of \ - `isize`"; - let depending_on_usize = "will truncate or zero-extend depending on the bit width of \ - `usize`"; - let will_sign_extend = "will sign-extend the source value"; - let will_zero_extend = "will zero-extend the source value"; + // FIXME(estebank): modify once we decide to suggest `as` casts + return false; + } // If casting this expression to a given numeric type would be appropriate in case of a type // mismatch. @@ -500,7 +552,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(hir::Node::Expr(hir::Expr { node: hir::ExprKind::Struct(_, fields, _), .. - })) = self.tcx.hir().find_by_hir_id(self.tcx.hir().get_parent_node_by_hir_id(expr.hir_id)) { + })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id)) { // `expr` is a literal field for a struct, only suggest if appropriate for field in fields { if field.expr.hir_id == expr.hir_id && field.is_shorthand { @@ -515,10 +567,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + let msg = format!("you can convert an `{}` to `{}`", checked_ty, expected_ty); + let cast_msg = format!("you can cast an `{} to `{}`", checked_ty, expected_ty); + let try_msg = format!("{} and panic if the converted value wouldn't fit", msg); + let lit_msg = format!( + "change the type of the numeric literal from `{}` to `{}`", + checked_ty, + expected_ty, + ); + let needs_paren = expr.precedence().order() < (PREC_POSTFIX as i8); if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) { - let msg = format!("you can cast an `{}` to `{}`", checked_ty, expected_ty); let cast_suggestion = format!( "{}{}{}{} as {}", prefix, @@ -527,6 +587,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if needs_paren { ")" } else { "" }, expected_ty, ); + let try_into_suggestion = format!( + "{}{}{}{}.try_into().unwrap()", + prefix, + if needs_paren { "(" } else { "" }, + src, + if needs_paren { ")" } else { "" }, + ); let into_suggestion = format!( "{}{}{}{}.into()", prefix, @@ -534,6 +601,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { src, if needs_paren { ")" } else { "" }, ); + let suffix_suggestion = format!( + "{}{}{}{}", + if needs_paren { "(" } else { "" }, + if let (ty::Int(_), ty::Float(_)) | (ty::Uint(_), ty::Float(_)) = ( + &expected_ty.sty, + &checked_ty.sty, + ) { + // Remove fractional part from literal, for example `42.0f32` into `42` + let src = src.trim_end_matches(&checked_ty.to_string()); + src.split(".").next().unwrap() + } else { + src.trim_end_matches(&checked_ty.to_string()) + }, + expected_ty, + if needs_paren { ")" } else { "" }, + ); let literal_is_ty_suffixed = |expr: &hir::Expr| { if let hir::ExprKind::Lit(lit) = &expr.node { lit.node.is_suffixed() @@ -542,35 +625,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - let into_sugg = into_suggestion.clone(); - let suggest_to_change_suffix_or_into = |err: &mut DiagnosticBuilder<'_>, - note: Option<&str>| { - let suggest_msg = if literal_is_ty_suffixed(expr) { - format!( - "change the type of the numeric literal from `{}` to `{}`", - checked_ty, - expected_ty, - ) - } else { - match note { - Some(note) => format!("{}, which {}", msg, note), - _ => format!("{} in a lossless way", msg), - } - }; - - let suffix_suggestion = format!( - "{}{}{}{}", - if needs_paren { "(" } else { "" }, - src.trim_end_matches(&checked_ty.to_string()), - expected_ty, - if needs_paren { ")" } else { "" }, - ); - + let suggest_to_change_suffix_or_into = | + err: &mut DiagnosticBuilder<'_>, + is_fallible: bool, + | { + let into_sugg = into_suggestion.clone(); err.span_suggestion( expr.span, - &suggest_msg, if literal_is_ty_suffixed(expr) { - suffix_suggestion + &lit_msg + } else if is_fallible { + &try_msg + } else { + &msg + }, + if literal_is_ty_suffixed(expr) { + suffix_suggestion.clone() + } else if is_fallible { + try_into_suggestion } else { into_sugg }, @@ -580,188 +652,67 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match (&expected_ty.sty, &checked_ty.sty) { (&ty::Int(ref exp), &ty::Int(ref found)) => { - match (found.bit_width(), exp.bit_width()) { - (Some(found), Some(exp)) if found > exp => { - if can_cast { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, will_truncate), - cast_suggestion, - Applicability::MaybeIncorrect // lossy conversion - ); - } - } - (None, _) | (_, None) => { - if can_cast { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, depending_on_isize), - cast_suggestion, - Applicability::MaybeIncorrect // lossy conversion - ); - } - } - _ => { - suggest_to_change_suffix_or_into( - err, - Some(will_sign_extend), - ); - } - } + let is_fallible = match (found.bit_width(), exp.bit_width()) { + (Some(found), Some(exp)) if found > exp => true, + (None, _) | (_, None) => true, + _ => false, + }; + suggest_to_change_suffix_or_into(err, is_fallible); true } (&ty::Uint(ref exp), &ty::Uint(ref found)) => { - match (found.bit_width(), exp.bit_width()) { - (Some(found), Some(exp)) if found > exp => { - if can_cast { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, will_truncate), - cast_suggestion, - Applicability::MaybeIncorrect // lossy conversion - ); - } - } - (None, _) | (_, None) => { - if can_cast { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, depending_on_usize), - cast_suggestion, - Applicability::MaybeIncorrect // lossy conversion - ); - } - } - _ => { - suggest_to_change_suffix_or_into( - err, - Some(will_zero_extend), - ); - } - } + let is_fallible = match (found.bit_width(), exp.bit_width()) { + (Some(found), Some(exp)) if found > exp => true, + (None, _) | (_, None) => true, + _ => false, + }; + suggest_to_change_suffix_or_into(err, is_fallible); true } - (&ty::Int(ref exp), &ty::Uint(ref found)) => { - if can_cast { - match (found.bit_width(), exp.bit_width()) { - (Some(found), Some(exp)) if found > exp - 1 => { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, will_truncate), - cast_suggestion, - Applicability::MaybeIncorrect // lossy conversion - ); - } - (None, None) => { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, will_truncate), - cast_suggestion, - Applicability::MaybeIncorrect // lossy conversion - ); - } - (None, _) => { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, depending_on_isize), - cast_suggestion, - Applicability::MaybeIncorrect // lossy conversion - ); - } - (_, None) => { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, depending_on_usize), - cast_suggestion, - Applicability::MaybeIncorrect // lossy conversion - ); - } - _ => { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, will_zero_extend), - cast_suggestion, - Applicability::MachineApplicable - ); - } - } - } - true - } - (&ty::Uint(ref exp), &ty::Int(ref found)) => { - if can_cast { - match (found.bit_width(), exp.bit_width()) { - (Some(found), Some(exp)) if found - 1 > exp => { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, will_truncate), - cast_suggestion, - Applicability::MaybeIncorrect // lossy conversion - ); - } - (None, None) => { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, will_sign_extend), - cast_suggestion, - Applicability::MachineApplicable // lossy conversion - ); - } - (None, _) => { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, depending_on_usize), - cast_suggestion, - Applicability::MaybeIncorrect // lossy conversion - ); - } - (_, None) => { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, depending_on_isize), - cast_suggestion, - Applicability::MaybeIncorrect // lossy conversion - ); - } - _ => { - err.span_suggestion( - expr.span, - &format!("{}, which {}", msg, will_sign_extend), - cast_suggestion, - Applicability::MachineApplicable - ); - } - } - } + (&ty::Int(_), &ty::Uint(_)) | (&ty::Uint(_), &ty::Int(_)) => { + suggest_to_change_suffix_or_into(err, true); true } (&ty::Float(ref exp), &ty::Float(ref found)) => { if found.bit_width() < exp.bit_width() { - suggest_to_change_suffix_or_into( - err, - None, - ); - } else if can_cast { + suggest_to_change_suffix_or_into(err, false); + } else if literal_is_ty_suffixed(expr) { err.span_suggestion( expr.span, - &format!("{}, producing the closest possible value", msg), + &lit_msg, + suffix_suggestion, + Applicability::MachineApplicable, + ); + } else if can_cast { // Missing try_into implementation for `f64` to `f32` + err.span_suggestion( + expr.span, + &format!("{}, producing the closest possible value", cast_msg), cast_suggestion, - Applicability::MaybeIncorrect // lossy conversion + Applicability::MaybeIncorrect, // lossy conversion ); } true } (&ty::Uint(_), &ty::Float(_)) | (&ty::Int(_), &ty::Float(_)) => { - if can_cast { + if literal_is_ty_suffixed(expr) { + err.span_suggestion( + expr.span, + &lit_msg, + suffix_suggestion, + Applicability::MachineApplicable, + ); + } else if can_cast { + // Missing try_into implementation for `{float}` to `{integer}` err.span_suggestion( expr.span, &format!("{}, rounding the float towards zero", msg), cast_suggestion, Applicability::MaybeIncorrect // lossy conversion ); - err.warn("casting here will cause undefined behavior if the rounded value \ - cannot be represented by the target integer type, including \ - `Inf` and `NaN` (this is a bug and will be fixed)"); + err.warn("if the rounded value cannot be represented by the target \ + integer type, including `Inf` and `NaN`, casting will cause \ + undefined behavior \ + (https://github.com/rust-lang/rust/issues/10184)"); } true } @@ -770,18 +721,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if exp.bit_width() > found.bit_width().unwrap_or(256) { err.span_suggestion( expr.span, - &format!("{}, producing the floating point representation of the \ - integer", - msg), + &format!( + "{}, producing the floating point representation of the integer", + msg, + ), into_suggestion, Applicability::MachineApplicable ); - } else if can_cast { + } else if literal_is_ty_suffixed(expr) { + err.span_suggestion( + expr.span, + &lit_msg, + suffix_suggestion, + Applicability::MachineApplicable, + ); + } else { + // Missing try_into implementation for `{integer}` to `{float}` err.span_suggestion( expr.span, - &format!("{}, producing the floating point representation of the \ - integer, rounded if necessary", - msg), + &format!( + "{}, producing the floating point representation of the integer, + rounded if necessary", + cast_msg, + ), cast_suggestion, Applicability::MaybeIncorrect // lossy conversion ); @@ -793,18 +755,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if exp.bit_width() > found.bit_width().unwrap_or(256) { err.span_suggestion( expr.span, - &format!("{}, producing the floating point representation of the \ - integer", - msg), + &format!( + "{}, producing the floating point representation of the integer", + &msg, + ), into_suggestion, Applicability::MachineApplicable ); - } else if can_cast { + } else if literal_is_ty_suffixed(expr) { + err.span_suggestion( + expr.span, + &lit_msg, + suffix_suggestion, + Applicability::MachineApplicable, + ); + } else { + // Missing try_into implementation for `{integer}` to `{float}` err.span_suggestion( expr.span, - &format!("{}, producing the floating point representation of the \ - integer, rounded if necessary", - msg), + &format!( + "{}, producing the floating point representation of the integer, \ + rounded if necessary", + &msg, + ), cast_suggestion, Applicability::MaybeIncorrect // lossy conversion ); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 12c7484f0f921..a2621abf44d8d 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -29,10 +29,7 @@ use syntax_pos::Span; /// struct/enum definition for the nominal type itself (i.e. /// cannot do `struct S; impl Drop for S { ... }`). /// -pub fn check_drop_impl<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - drop_impl_did: DefId, -) -> Result<(), ErrorReported> { +pub fn check_drop_impl<'tcx>(tcx: TyCtxt<'tcx>, drop_impl_did: DefId) -> Result<(), ErrorReported> { let dtor_self_type = tcx.type_of(drop_impl_did); let dtor_predicates = tcx.predicates_of(drop_impl_did); match dtor_self_type.sty { @@ -64,8 +61,8 @@ pub fn check_drop_impl<'a, 'tcx>( } } -fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn ensure_drop_params_and_item_params_correspond<'tcx>( + tcx: TyCtxt<'tcx>, drop_impl_did: DefId, drop_impl_ty: Ty<'tcx>, self_type_did: DefId, @@ -140,8 +137,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( /// Confirms that every predicate imposed by dtor_predicates is /// implied by assuming the predicates attached to self_type_did. -fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( + tcx: TyCtxt<'tcx>, drop_impl_did: DefId, dtor_predicates: &ty::GenericPredicates<'tcx>, self_type_did: DefId, @@ -216,7 +213,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( // repeated `contains` calls. if !assumptions_in_impl_context.contains(&predicate) { - let item_span = tcx.hir().span_by_hir_id(self_type_hir_id); + let item_span = tcx.hir().span(self_type_hir_id); struct_span_err!( tcx.sess, drop_impl_span, @@ -287,8 +284,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( /// this conservative assumption (and thus assume the obligation of /// ensuring that they do not access data nor invoke methods of /// values that have been previously dropped). -pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( - rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>, +pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>( + rcx: &mut RegionCtxt<'a, 'tcx>, ty: Ty<'tcx>, span: Span, body_id: hir::HirId, @@ -313,6 +310,9 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( match kind.unpack() { UnpackedKind::Lifetime(r) => rcx.sub_regions(origin(), parent_scope, r), UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope), + UnpackedKind::Const(_) => { + // Generic consts don't add constraints. + } } } Ok(()) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs new file mode 100644 index 0000000000000..21fa219a1cab2 --- /dev/null +++ b/src/librustc_typeck/check/expr.rs @@ -0,0 +1,1568 @@ +//! Type checking expressions. +//! +//! See `mod.rs` for more context on type checking in general. + +use crate::check::BreakableCtxt; +use crate::check::cast; +use crate::check::coercion::CoerceMany; +use crate::check::Diverges; +use crate::check::FnCtxt; +use crate::check::Expectation::{self, NoExpectation, ExpectHasType, ExpectCastableToType}; +use crate::check::fatally_break_rust; +use crate::check::report_unexpected_variant_res; +use crate::check::Needs; +use crate::check::TupleArgumentsFlag::DontTupleArguments; +use crate::check::method::SelfSource; +use crate::middle::lang_items; +use crate::util::common::ErrorReported; +use crate::util::nodemap::FxHashMap; +use crate::astconv::AstConv as _; + +use errors::{Applicability, DiagnosticBuilder}; +use syntax::ast; +use syntax::ptr::P; +use syntax::symbol::{Symbol, LocalInternedString, kw, sym}; +use syntax::source_map::Span; +use syntax::util::lev_distance::find_best_match_for_name; +use rustc::hir; +use rustc::hir::{ExprKind, QPath}; +use rustc::hir::def::{CtorKind, Res, DefKind}; +use rustc::infer; +use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc::mir::interpret::GlobalId; +use rustc::ty; +use rustc::ty::adjustment::{ + Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, +}; +use rustc::ty::{AdtKind, Visibility}; +use rustc::ty::Ty; +use rustc::ty::TypeFoldable; +use rustc::ty::subst::InternalSubsts; +use rustc::traits::{self, ObligationCauseCode}; + +use std::fmt::Display; + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + fn check_expr_eq_type(&self, expr: &'tcx hir::Expr, expected: Ty<'tcx>) { + let ty = self.check_expr_with_hint(expr, expected); + self.demand_eqtype(expr.span, expected, ty); + } + + pub fn check_expr_has_type_or_error( + &self, + expr: &'tcx hir::Expr, + expected: Ty<'tcx>, + ) -> Ty<'tcx> { + self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected)) + } + + fn check_expr_meets_expectation_or_error( + &self, + expr: &'tcx hir::Expr, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + let expected_ty = expected.to_option(&self).unwrap_or(self.tcx.types.bool); + let mut ty = self.check_expr_with_expectation(expr, expected); + + // While we don't allow *arbitrary* coercions here, we *do* allow + // coercions from ! to `expected`. + if ty.is_never() { + assert!(!self.tables.borrow().adjustments().contains_key(expr.hir_id), + "expression with never type wound up being adjusted"); + let adj_ty = self.next_diverging_ty_var( + TypeVariableOrigin { + kind: TypeVariableOriginKind::AdjustmentType, + span: expr.span, + }, + ); + self.apply_adjustments(expr, vec![Adjustment { + kind: Adjust::NeverToAny, + target: adj_ty + }]); + ty = adj_ty; + } + + if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { + let expr = match &expr.node { + ExprKind::DropTemps(expr) => expr, + _ => expr, + }; + // Error possibly reported in `check_assign` so avoid emitting error again. + err.emit_unless(self.is_assign_to_bool(expr, expected_ty)); + } + ty + } + + pub(super) fn check_expr_coercable_to_type( + &self, + expr: &'tcx hir::Expr, + expected: Ty<'tcx> + ) -> Ty<'tcx> { + let ty = self.check_expr_with_hint(expr, expected); + // checks don't need two phase + self.demand_coerce(expr, ty, expected, AllowTwoPhase::No) + } + + pub(super) fn check_expr_with_hint( + &self, + expr: &'tcx hir::Expr, + expected: Ty<'tcx> + ) -> Ty<'tcx> { + self.check_expr_with_expectation(expr, ExpectHasType(expected)) + } + + pub(super) fn check_expr_with_expectation( + &self, + expr: &'tcx hir::Expr, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + self.check_expr_with_expectation_and_needs(expr, expected, Needs::None) + } + + pub(super) fn check_expr(&self, expr: &'tcx hir::Expr) -> Ty<'tcx> { + self.check_expr_with_expectation(expr, NoExpectation) + } + + pub(super) fn check_expr_with_needs(&self, expr: &'tcx hir::Expr, needs: Needs) -> Ty<'tcx> { + self.check_expr_with_expectation_and_needs(expr, NoExpectation, needs) + } + + /// Invariant: + /// If an expression has any sub-expressions that result in a type error, + /// inspecting that expression's type with `ty.references_error()` will return + /// true. Likewise, if an expression is known to diverge, inspecting its + /// type with `ty::type_is_bot` will return true (n.b.: since Rust is + /// strict, _|_ can appear in the type of an expression that does not, + /// itself, diverge: for example, fn() -> _|_.) + /// Note that inspecting a type's structure *directly* may expose the fact + /// that there are actually multiple representations for `Error`, so avoid + /// that when err needs to be handled differently. + fn check_expr_with_expectation_and_needs( + &self, + expr: &'tcx hir::Expr, + expected: Expectation<'tcx>, + needs: Needs, + ) -> Ty<'tcx> { + debug!(">> type-checking: expr={:?} expected={:?}", + expr, expected); + + // Warn for expressions after diverging siblings. + self.warn_if_unreachable(expr.hir_id, expr.span, "expression"); + + // Hide the outer diverging and has_errors flags. + let old_diverges = self.diverges.get(); + let old_has_errors = self.has_errors.get(); + self.diverges.set(Diverges::Maybe); + self.has_errors.set(false); + + let ty = self.check_expr_kind(expr, expected, needs); + + // Warn for non-block expressions with diverging children. + match expr.node { + ExprKind::Block(..) | + ExprKind::Loop(..) | ExprKind::While(..) | + ExprKind::Match(..) => {} + + _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression") + } + + // Any expression that produces a value of type `!` must have diverged + if ty.is_never() { + self.diverges.set(self.diverges.get() | Diverges::Always); + } + + // Record the type, which applies it effects. + // We need to do this after the warning above, so that + // we don't warn for the diverging expression itself. + self.write_ty(expr.hir_id, ty); + + // Combine the diverging and has_error flags. + self.diverges.set(self.diverges.get() | old_diverges); + self.has_errors.set(self.has_errors.get() | old_has_errors); + + debug!("type of {} is...", self.tcx.hir().node_to_string(expr.hir_id)); + debug!("... {:?}, expected is {:?}", ty, expected); + + ty + } + + fn check_expr_kind( + &self, + expr: &'tcx hir::Expr, + expected: Expectation<'tcx>, + needs: Needs, + ) -> Ty<'tcx> { + debug!( + "check_expr_kind(expr={:?}, expected={:?}, needs={:?})", + expr, + expected, + needs, + ); + + let tcx = self.tcx; + match expr.node { + ExprKind::Box(ref subexpr) => { + self.check_expr_box(subexpr, expected) + } + ExprKind::Lit(ref lit) => { + self.check_lit(&lit, expected) + } + ExprKind::Binary(op, ref lhs, ref rhs) => { + self.check_binop(expr, op, lhs, rhs) + } + ExprKind::AssignOp(op, ref lhs, ref rhs) => { + self.check_binop_assign(expr, op, lhs, rhs) + } + ExprKind::Unary(unop, ref oprnd) => { + self.check_expr_unary(unop, oprnd, expected, needs, expr) + } + ExprKind::AddrOf(mutbl, ref oprnd) => { + self.check_expr_addr_of(mutbl, oprnd, expected, expr) + } + ExprKind::Path(ref qpath) => { + self.check_expr_path(qpath, expr) + } + ExprKind::InlineAsm(_, ref outputs, ref inputs) => { + for expr in outputs.iter().chain(inputs.iter()) { + self.check_expr(expr); + } + tcx.mk_unit() + } + ExprKind::Break(destination, ref expr_opt) => { + self.check_expr_break(destination, expr_opt.deref(), expr) + } + ExprKind::Continue(destination) => { + if destination.target_id.is_ok() { + tcx.types.never + } else { + // There was an error; make type-check fail. + tcx.types.err + } + } + ExprKind::Ret(ref expr_opt) => { + self.check_expr_return(expr_opt.deref(), expr) + } + ExprKind::Assign(ref lhs, ref rhs) => { + self.check_expr_assign(expr, expected, lhs, rhs) + } + ExprKind::While(ref cond, ref body, _) => { + self.check_expr_while(cond, body, expr) + } + ExprKind::Loop(ref body, _, source) => { + self.check_expr_loop(body, source, expected, expr) + } + ExprKind::Match(ref discrim, ref arms, match_src) => { + self.check_match(expr, &discrim, arms, expected, match_src) + } + ExprKind::Closure(capture, ref decl, body_id, _, gen) => { + self.check_expr_closure(expr, capture, &decl, body_id, gen, expected) + } + ExprKind::Block(ref body, _) => { + self.check_block_with_expected(&body, expected) + } + ExprKind::Call(ref callee, ref args) => { + self.check_call(expr, &callee, args, expected) + } + ExprKind::MethodCall(ref segment, span, ref args) => { + self.check_method_call(expr, segment, span, args, expected, needs) + } + ExprKind::Cast(ref e, ref t) => { + self.check_expr_cast(e, t, expr) + } + ExprKind::Type(ref e, ref t) => { + let ty = self.to_ty_saving_user_provided_ty(&t); + self.check_expr_eq_type(&e, ty); + ty + } + ExprKind::DropTemps(ref e) => { + self.check_expr_with_expectation(e, expected) + } + ExprKind::Array(ref args) => { + self.check_expr_array(args, expected, expr) + } + ExprKind::Repeat(ref element, ref count) => { + self.check_expr_repeat(element, count, expected, expr) + } + ExprKind::Tup(ref elts) => { + self.check_expr_tuple(elts, expected, expr) + } + ExprKind::Struct(ref qpath, ref fields, ref base_expr) => { + self.check_expr_struct(expr, expected, qpath, fields, base_expr) + } + ExprKind::Field(ref base, field) => { + self.check_field(expr, needs, &base, field) + } + ExprKind::Index(ref base, ref idx) => { + self.check_expr_index(base, idx, needs, expr) + } + ExprKind::Yield(ref value, ref src) => { + self.check_expr_yield(value, expr, src) + } + hir::ExprKind::Err => { + tcx.types.err + } + } + } + + fn check_expr_box(&self, expr: &'tcx hir::Expr, expected: Expectation<'tcx>) -> Ty<'tcx> { + let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| { + match ty.sty { + ty::Adt(def, _) if def.is_box() + => Expectation::rvalue_hint(self, ty.boxed_ty()), + _ => NoExpectation + } + }); + let referent_ty = self.check_expr_with_expectation(expr, expected_inner); + self.tcx.mk_box(referent_ty) + } + + fn check_expr_unary( + &self, + unop: hir::UnOp, + oprnd: &'tcx hir::Expr, + expected: Expectation<'tcx>, + needs: Needs, + expr: &'tcx hir::Expr, + ) -> Ty<'tcx> { + let tcx = self.tcx; + let expected_inner = match unop { + hir::UnNot | hir::UnNeg => expected, + hir::UnDeref => NoExpectation, + }; + let needs = match unop { + hir::UnDeref => needs, + _ => Needs::None + }; + let mut oprnd_t = self.check_expr_with_expectation_and_needs(&oprnd, expected_inner, needs); + + if !oprnd_t.references_error() { + oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); + match unop { + hir::UnDeref => { + if let Some(mt) = oprnd_t.builtin_deref(true) { + oprnd_t = mt.ty; + } else if let Some(ok) = self.try_overloaded_deref( + expr.span, oprnd_t, needs) { + let method = self.register_infer_ok_obligations(ok); + if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].sty { + let mutbl = match mutbl { + hir::MutImmutable => AutoBorrowMutability::Immutable, + hir::MutMutable => AutoBorrowMutability::Mutable { + // (It shouldn't actually matter for unary ops whether + // we enable two-phase borrows or not, since a unary + // op has no additional operands.) + allow_two_phase_borrow: AllowTwoPhase::No, + } + }; + self.apply_adjustments(oprnd, vec![Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), + target: method.sig.inputs()[0] + }]); + } + oprnd_t = self.make_overloaded_place_return_type(method).ty; + self.write_method_call(expr.hir_id, method); + } else { + let mut err = type_error_struct!( + tcx.sess, + expr.span, + oprnd_t, + E0614, + "type `{}` cannot be dereferenced", + oprnd_t, + ); + let sp = tcx.sess.source_map().start_point(expr.span); + if let Some(sp) = tcx.sess.parse_sess.ambiguous_block_expr_parse + .borrow().get(&sp) + { + tcx.sess.parse_sess.expr_parentheses_needed( + &mut err, + *sp, + None, + ); + } + err.emit(); + oprnd_t = tcx.types.err; + } + } + hir::UnNot => { + let result = self.check_user_unop(expr, oprnd_t, unop); + // If it's builtin, we can reuse the type, this helps inference. + if !(oprnd_t.is_integral() || oprnd_t.sty == ty::Bool) { + oprnd_t = result; + } + } + hir::UnNeg => { + let result = self.check_user_unop(expr, oprnd_t, unop); + // If it's builtin, we can reuse the type, this helps inference. + if !oprnd_t.is_numeric() { + oprnd_t = result; + } + } + } + } + oprnd_t + } + + fn check_expr_addr_of( + &self, + mutbl: hir::Mutability, + oprnd: &'tcx hir::Expr, + expected: Expectation<'tcx>, + expr: &'tcx hir::Expr, + ) -> Ty<'tcx> { + let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| { + match ty.sty { + ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { + if oprnd.is_place_expr() { + // Places may legitimately have unsized types. + // For example, dereferences of a fat pointer and + // the last field of a struct can be unsized. + ExpectHasType(ty) + } else { + Expectation::rvalue_hint(self, ty) + } + } + _ => NoExpectation + } + }); + let needs = Needs::maybe_mut_place(mutbl); + let ty = self.check_expr_with_expectation_and_needs(&oprnd, hint, needs); + + let tm = ty::TypeAndMut { ty: ty, mutbl: mutbl }; + if tm.ty.references_error() { + self.tcx.types.err + } else { + // Note: at this point, we cannot say what the best lifetime + // is to use for resulting pointer. We want to use the + // shortest lifetime possible so as to avoid spurious borrowck + // errors. Moreover, the longest lifetime will depend on the + // precise details of the value whose address is being taken + // (and how long it is valid), which we don't know yet until type + // inference is complete. + // + // Therefore, here we simply generate a region variable. The + // region inferencer will then select the ultimate value. + // Finally, borrowck is charged with guaranteeing that the + // value whose address was taken can actually be made to live + // as long as it needs to live. + let region = self.next_region_var(infer::AddrOfRegion(expr.span)); + self.tcx.mk_ref(region, tm) + } + } + + fn check_expr_path(&self, qpath: &hir::QPath, expr: &'tcx hir::Expr) -> Ty<'tcx> { + let tcx = self.tcx; + let (res, opt_ty, segs) = self.resolve_ty_and_res_ufcs(qpath, expr.hir_id, expr.span); + let ty = match res { + Res::Err => { + self.set_tainted_by_errors(); + tcx.types.err + } + Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) => { + report_unexpected_variant_res(tcx, res, expr.span, qpath); + tcx.types.err + } + _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, + }; + + if let ty::FnDef(..) = ty.sty { + let fn_sig = ty.fn_sig(tcx); + if !tcx.features().unsized_locals { + // We want to remove some Sized bounds from std functions, + // but don't want to expose the removal to stable Rust. + // i.e., we don't want to allow + // + // ```rust + // drop as fn(str); + // ``` + // + // to work in stable even if the Sized bound on `drop` is relaxed. + for i in 0..fn_sig.inputs().skip_binder().len() { + // We just want to check sizedness, so instead of introducing + // placeholder lifetimes with probing, we just replace higher lifetimes + // with fresh vars. + let input = self.replace_bound_vars_with_fresh_vars( + expr.span, + infer::LateBoundRegionConversionTime::FnCall, + &fn_sig.input(i)).0; + self.require_type_is_sized_deferred(input, expr.span, + traits::SizedArgumentType); + } + } + // Here we want to prevent struct constructors from returning unsized types. + // There were two cases this happened: fn pointer coercion in stable + // and usual function call in presense of unsized_locals. + // Also, as we just want to check sizedness, instead of introducing + // placeholder lifetimes with probing, we just replace higher lifetimes + // with fresh vars. + let output = self.replace_bound_vars_with_fresh_vars( + expr.span, + infer::LateBoundRegionConversionTime::FnCall, + &fn_sig.output()).0; + self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); + } + + // We always require that the type provided as the value for + // a type parameter outlives the moment of instantiation. + let substs = self.tables.borrow().node_substs(expr.hir_id); + self.add_wf_bounds(substs, expr); + + ty + } + + fn check_expr_break( + &self, + destination: hir::Destination, + expr_opt: Option<&'tcx hir::Expr>, + expr: &'tcx hir::Expr, + ) -> Ty<'tcx> { + let tcx = self.tcx; + if let Ok(target_id) = destination.target_id { + let (e_ty, cause); + if let Some(ref e) = expr_opt { + // If this is a break with a value, we need to type-check + // the expression. Get an expected type from the loop context. + let opt_coerce_to = { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + enclosing_breakables.find_breakable(target_id) + .coerce + .as_ref() + .map(|coerce| coerce.expected_ty()) + }; + + // If the loop context is not a `loop { }`, then break with + // a value is illegal, and `opt_coerce_to` will be `None`. + // Just set expectation to error in that case. + let coerce_to = opt_coerce_to.unwrap_or(tcx.types.err); + + // Recurse without `enclosing_breakables` borrowed. + e_ty = self.check_expr_with_hint(e, coerce_to); + cause = self.misc(e.span); + } else { + // Otherwise, this is a break *without* a value. That's + // always legal, and is equivalent to `break ()`. + e_ty = tcx.mk_unit(); + cause = self.misc(expr.span); + } + + // Now that we have type-checked `expr_opt`, borrow + // the `enclosing_loops` field and let's coerce the + // type of `expr_opt` into what is expected. + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + let ctxt = enclosing_breakables.find_breakable(target_id); + if let Some(ref mut coerce) = ctxt.coerce { + if let Some(ref e) = expr_opt { + coerce.coerce(self, &cause, e, e_ty); + } else { + assert!(e_ty.is_unit()); + coerce.coerce_forced_unit(self, &cause, &mut |_| (), true); + } + } else { + // If `ctxt.coerce` is `None`, we can just ignore + // the type of the expresison. This is because + // either this was a break *without* a value, in + // which case it is always a legal type (`()`), or + // else an error would have been flagged by the + // `loops` pass for using break with an expression + // where you are not supposed to. + assert!(expr_opt.is_none() || self.tcx.sess.has_errors()); + } + + ctxt.may_break = true; + + // the type of a `break` is always `!`, since it diverges + tcx.types.never + } else { + // Otherwise, we failed to find the enclosing loop; + // this can only happen if the `break` was not + // inside a loop at all, which is caught by the + // loop-checking pass. + self.tcx.sess.delay_span_bug(expr.span, + "break was outside loop, but no error was emitted"); + + // We still need to assign a type to the inner expression to + // prevent the ICE in #43162. + if let Some(ref e) = expr_opt { + self.check_expr_with_hint(e, tcx.types.err); + + // ... except when we try to 'break rust;'. + // ICE this expression in particular (see #43162). + if let ExprKind::Path(QPath::Resolved(_, ref path)) = e.node { + if path.segments.len() == 1 && + path.segments[0].ident.name == sym::rust { + fatally_break_rust(self.tcx.sess); + } + } + } + // There was an error; make type-check fail. + tcx.types.err + } + } + + fn check_expr_return( + &self, + expr_opt: Option<&'tcx hir::Expr>, + expr: &'tcx hir::Expr + ) -> Ty<'tcx> { + if self.ret_coercion.is_none() { + struct_span_err!(self.tcx.sess, expr.span, E0572, + "return statement outside of function body").emit(); + } else if let Some(ref e) = expr_opt { + if self.ret_coercion_span.borrow().is_none() { + *self.ret_coercion_span.borrow_mut() = Some(e.span); + } + self.check_return_expr(e); + } else { + let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); + if self.ret_coercion_span.borrow().is_none() { + *self.ret_coercion_span.borrow_mut() = Some(expr.span); + } + let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); + if let Some((fn_decl, _)) = self.get_fn_decl(expr.hir_id) { + coercion.coerce_forced_unit( + self, + &cause, + &mut |db| { + db.span_label( + fn_decl.output.span(), + format!( + "expected `{}` because of this return type", + fn_decl.output, + ), + ); + }, + true, + ); + } else { + coercion.coerce_forced_unit(self, &cause, &mut |_| (), true); + } + } + self.tcx.types.never + } + + pub(super) fn check_return_expr(&self, return_expr: &'tcx hir::Expr) { + let ret_coercion = + self.ret_coercion + .as_ref() + .unwrap_or_else(|| span_bug!(return_expr.span, + "check_return_expr called outside fn body")); + + let ret_ty = ret_coercion.borrow().expected_ty(); + let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty.clone()); + ret_coercion.borrow_mut() + .coerce(self, + &self.cause(return_expr.span, + ObligationCauseCode::ReturnType(return_expr.hir_id)), + return_expr, + return_expr_ty); + } + + /// Type check assignment expression `expr` of form `lhs = rhs`. + /// The expected type is `()` and is passsed to the function for the purposes of diagnostics. + fn check_expr_assign( + &self, + expr: &'tcx hir::Expr, + expected: Expectation<'tcx>, + lhs: &'tcx hir::Expr, + rhs: &'tcx hir::Expr, + ) -> Ty<'tcx> { + let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); + let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty); + + let expected_ty = expected.coercion_target_type(self, expr.span); + if expected_ty == self.tcx.types.bool { + // The expected type is `bool` but this will result in `()` so we can reasonably + // say that the user intended to write `lhs == rhs` instead of `lhs = rhs`. + // The likely cause of this is `if foo = bar { .. }`. + let actual_ty = self.tcx.mk_unit(); + let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap(); + let msg = "try comparing for equality"; + let left = self.tcx.sess.source_map().span_to_snippet(lhs.span); + let right = self.tcx.sess.source_map().span_to_snippet(rhs.span); + if let (Ok(left), Ok(right)) = (left, right) { + let help = format!("{} == {}", left, right); + err.span_suggestion(expr.span, msg, help, Applicability::MaybeIncorrect); + } else { + err.help(msg); + } + err.emit(); + } else if !lhs.is_place_expr() { + struct_span_err!(self.tcx.sess, expr.span, E0070, + "invalid left-hand side expression") + .span_label(expr.span, "left-hand of expression not valid") + .emit(); + } + + self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); + + if lhs_ty.references_error() || rhs_ty.references_error() { + self.tcx.types.err + } else { + self.tcx.mk_unit() + } + } + + fn check_expr_while( + &self, + cond: &'tcx hir::Expr, + body: &'tcx hir::Block, + expr: &'tcx hir::Expr + ) -> Ty<'tcx> { + let ctxt = BreakableCtxt { + // Cannot use break with a value from a while loop. + coerce: None, + may_break: false, // Will get updated if/when we find a `break`. + }; + + let (ctxt, ()) = self.with_breakable_ctxt(expr.hir_id, ctxt, || { + self.check_expr_has_type_or_error(&cond, self.tcx.types.bool); + let cond_diverging = self.diverges.get(); + self.check_block_no_value(&body); + + // We may never reach the body so it diverging means nothing. + self.diverges.set(cond_diverging); + }); + + if ctxt.may_break { + // No way to know whether it's diverging because + // of a `break` or an outer `break` or `return`. + self.diverges.set(Diverges::Maybe); + } + + self.tcx.mk_unit() + } + + fn check_expr_loop( + &self, + body: &'tcx hir::Block, + source: hir::LoopSource, + expected: Expectation<'tcx>, + expr: &'tcx hir::Expr, + ) -> Ty<'tcx> { + let coerce = match source { + // you can only use break with a value from a normal `loop { }` + hir::LoopSource::Loop => { + let coerce_to = expected.coercion_target_type(self, body.span); + Some(CoerceMany::new(coerce_to)) + } + + hir::LoopSource::WhileLet | + hir::LoopSource::ForLoop => { + None + } + }; + + let ctxt = BreakableCtxt { + coerce, + may_break: false, // Will get updated if/when we find a `break`. + }; + + let (ctxt, ()) = self.with_breakable_ctxt(expr.hir_id, ctxt, || { + self.check_block_no_value(&body); + }); + + if ctxt.may_break { + // No way to know whether it's diverging because + // of a `break` or an outer `break` or `return`. + self.diverges.set(Diverges::Maybe); + } + + // If we permit break with a value, then result type is + // the LUB of the breaks (possibly ! if none); else, it + // is nil. This makes sense because infinite loops + // (which would have type !) are only possible iff we + // permit break with a value [1]. + if ctxt.coerce.is_none() && !ctxt.may_break { + // [1] + self.tcx.sess.delay_span_bug(body.span, "no coercion, but loop may not break"); + } + ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| self.tcx.mk_unit()) + } + + /// Checks a method call. + fn check_method_call( + &self, + expr: &'tcx hir::Expr, + segment: &hir::PathSegment, + span: Span, + args: &'tcx [hir::Expr], + expected: Expectation<'tcx>, + needs: Needs, + ) -> Ty<'tcx> { + let rcvr = &args[0]; + let rcvr_t = self.check_expr_with_needs(&rcvr, needs); + // no need to check for bot/err -- callee does that + let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t); + + let method = match self.lookup_method(rcvr_t, + segment, + span, + expr, + rcvr) { + Ok(method) => { + self.write_method_call(expr.hir_id, method); + Ok(method) + } + Err(error) => { + if segment.ident.name != kw::Invalid { + self.report_method_error(span, + rcvr_t, + segment.ident, + SelfSource::MethodCall(rcvr), + error, + Some(args)); + } + Err(()) + } + }; + + // Call the generic checker. + self.check_method_argument_types(span, + expr.span, + method, + &args[1..], + DontTupleArguments, + expected) + } + + fn check_expr_cast( + &self, + e: &'tcx hir::Expr, + t: &'tcx hir::Ty, + expr: &'tcx hir::Expr, + ) -> Ty<'tcx> { + // Find the type of `e`. Supply hints based on the type we are casting to, + // if appropriate. + let t_cast = self.to_ty_saving_user_provided_ty(t); + let t_cast = self.resolve_vars_if_possible(&t_cast); + let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); + let t_cast = self.resolve_vars_if_possible(&t_cast); + + // Eagerly check for some obvious errors. + if t_expr.references_error() || t_cast.references_error() { + self.tcx.types.err + } else { + // Defer other checks until we're done type checking. + let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); + match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { + Ok(cast_check) => { + deferred_cast_checks.push(cast_check); + t_cast + } + Err(ErrorReported) => { + self.tcx.types.err + } + } + } + } + + fn check_expr_array( + &self, + args: &'tcx [hir::Expr], + expected: Expectation<'tcx>, + expr: &'tcx hir::Expr + ) -> Ty<'tcx> { + let uty = expected.to_option(self).and_then(|uty| { + match uty.sty { + ty::Array(ty, _) | ty::Slice(ty) => Some(ty), + _ => None + } + }); + + let element_ty = if !args.is_empty() { + let coerce_to = uty.unwrap_or_else(|| { + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: expr.span, + }) + }); + let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args); + assert_eq!(self.diverges.get(), Diverges::Maybe); + for e in args { + let e_ty = self.check_expr_with_hint(e, coerce_to); + let cause = self.misc(e.span); + coerce.coerce(self, &cause, e, e_ty); + } + coerce.complete(self) + } else { + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: expr.span, + }) + }; + self.tcx.mk_array(element_ty, args.len() as u64) + } + + fn check_expr_repeat( + &self, + element: &'tcx hir::Expr, + count: &'tcx hir::AnonConst, + expected: Expectation<'tcx>, + expr: &'tcx hir::Expr, + ) -> Ty<'tcx> { + let tcx = self.tcx; + let count_def_id = tcx.hir().local_def_id_from_hir_id(count.hir_id); + let count = if self.const_param_def_id(count).is_some() { + Ok(self.to_const(count, tcx.type_of(count_def_id))) + } else { + let param_env = ty::ParamEnv::empty(); + let substs = InternalSubsts::identity_for_item(tcx.global_tcx(), count_def_id); + let instance = ty::Instance::resolve( + tcx.global_tcx(), + param_env, + count_def_id, + substs, + ).unwrap(); + let global_id = GlobalId { + instance, + promoted: None + }; + + tcx.const_eval(param_env.and(global_id)) + }; + + let uty = match expected { + ExpectHasType(uty) => { + match uty.sty { + ty::Array(ty, _) | ty::Slice(ty) => Some(ty), + _ => None + } + } + _ => None + }; + + let (element_ty, t) = match uty { + Some(uty) => { + self.check_expr_coercable_to_type(&element, uty); + (uty, uty) + } + None => { + let ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: element.span, + }); + let element_ty = self.check_expr_has_type_or_error(&element, ty); + (element_ty, ty) + } + }; + + if let Ok(count) = count { + let zero_or_one = count.assert_usize(tcx).map_or(false, |count| count <= 1); + if !zero_or_one { + // For [foo, ..n] where n > 1, `foo` must have + // Copy type: + let lang_item = tcx.require_lang_item(lang_items::CopyTraitLangItem); + self.require_type_meets(t, expr.span, traits::RepeatVec, lang_item); + } + } + + if element_ty.references_error() { + tcx.types.err + } else if let Ok(count) = count { + tcx.mk_ty(ty::Array(t, count)) + } else { + tcx.types.err + } + } + + fn check_expr_tuple( + &self, + elts: &'tcx [hir::Expr], + expected: Expectation<'tcx>, + expr: &'tcx hir::Expr, + ) -> Ty<'tcx> { + let flds = expected.only_has_type(self).and_then(|ty| { + let ty = self.resolve_type_vars_with_obligations(ty); + match ty.sty { + ty::Tuple(ref flds) => Some(&flds[..]), + _ => None + } + }); + + let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| { + let t = match flds { + Some(ref fs) if i < fs.len() => { + let ety = fs[i].expect_ty(); + self.check_expr_coercable_to_type(&e, ety); + ety + } + _ => { + self.check_expr_with_expectation(&e, NoExpectation) + } + }; + t + }); + let tuple = self.tcx.mk_tup(elt_ts_iter); + if tuple.references_error() { + self.tcx.types.err + } else { + self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized); + tuple + } + } + + fn check_expr_struct( + &self, + expr: &hir::Expr, + expected: Expectation<'tcx>, + qpath: &QPath, + fields: &'tcx [hir::Field], + base_expr: &'tcx Option>, + ) -> Ty<'tcx> { + // Find the relevant variant + let (variant, adt_ty) = + if let Some(variant_ty) = self.check_struct_path(qpath, expr.hir_id) { + variant_ty + } else { + self.check_struct_fields_on_error(fields, base_expr); + return self.tcx.types.err; + }; + + let path_span = match *qpath { + QPath::Resolved(_, ref path) => path.span, + QPath::TypeRelative(ref qself, _) => qself.span + }; + + // Prohibit struct expressions when non-exhaustive flag is set. + let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type"); + if !adt.did.is_local() && variant.is_field_list_non_exhaustive() { + span_err!(self.tcx.sess, expr.span, E0639, + "cannot create non-exhaustive {} using struct expression", + adt.variant_descr()); + } + + let error_happened = self.check_expr_struct_fields(adt_ty, expected, expr.hir_id, path_span, + variant, fields, base_expr.is_none()); + if let &Some(ref base_expr) = base_expr { + // If check_expr_struct_fields hit an error, do not attempt to populate + // the fields with the base_expr. This could cause us to hit errors later + // when certain fields are assumed to exist that in fact do not. + if !error_happened { + self.check_expr_has_type_or_error(base_expr, adt_ty); + match adt_ty.sty { + ty::Adt(adt, substs) if adt.is_struct() => { + let fru_field_types = adt.non_enum_variant().fields.iter().map(|f| { + self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs)) + }).collect(); + + self.tables + .borrow_mut() + .fru_field_types_mut() + .insert(expr.hir_id, fru_field_types); + } + _ => { + span_err!(self.tcx.sess, base_expr.span, E0436, + "functional record update syntax requires a struct"); + } + } + } + } + self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized); + adt_ty + } + + fn check_expr_struct_fields( + &self, + adt_ty: Ty<'tcx>, + expected: Expectation<'tcx>, + expr_id: hir::HirId, + span: Span, + variant: &'tcx ty::VariantDef, + ast_fields: &'tcx [hir::Field], + check_completeness: bool, + ) -> bool { + let tcx = self.tcx; + + let adt_ty_hint = + self.expected_inputs_for_expected_output(span, expected, adt_ty, &[adt_ty]) + .get(0).cloned().unwrap_or(adt_ty); + // re-link the regions that EIfEO can erase. + self.demand_eqtype(span, adt_ty_hint, adt_ty); + + let (substs, adt_kind, kind_name) = match &adt_ty.sty { + &ty::Adt(adt, substs) => { + (substs, adt.adt_kind(), adt.variant_descr()) + } + _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields") + }; + + let mut remaining_fields = variant.fields.iter().enumerate().map(|(i, field)| + (field.ident.modern(), (i, field)) + ).collect::>(); + + let mut seen_fields = FxHashMap::default(); + + let mut error_happened = false; + + // Type-check each field. + for field in ast_fields { + let ident = tcx.adjust_ident(field.ident, variant.def_id); + let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) { + seen_fields.insert(ident, field.span); + self.write_field_index(field.hir_id, i); + + // We don't look at stability attributes on + // struct-like enums (yet...), but it's definitely not + // a bug to have constructed one. + if adt_kind != AdtKind::Enum { + tcx.check_stability(v_field.did, Some(expr_id), field.span); + } + + self.field_ty(field.span, v_field, substs) + } else { + error_happened = true; + if let Some(prev_span) = seen_fields.get(&ident) { + let mut err = struct_span_err!(self.tcx.sess, + field.ident.span, + E0062, + "field `{}` specified more than once", + ident); + + err.span_label(field.ident.span, "used more than once"); + err.span_label(*prev_span, format!("first use of `{}`", ident)); + + err.emit(); + } else { + self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name, span); + } + + tcx.types.err + }; + + // Make sure to give a type to the field even if there's + // an error, so we can continue type-checking. + self.check_expr_coercable_to_type(&field.expr, field_type); + } + + // Make sure the programmer specified correct number of fields. + if kind_name == "union" { + if ast_fields.len() != 1 { + tcx.sess.span_err(span, "union expressions should have exactly one field"); + } + } else if check_completeness && !error_happened && !remaining_fields.is_empty() { + let len = remaining_fields.len(); + + let mut displayable_field_names = remaining_fields + .keys() + .map(|ident| ident.as_str()) + .collect::>(); + + displayable_field_names.sort(); + + let truncated_fields_error = if len <= 3 { + String::new() + } else { + format!(" and {} other field{}", (len - 3), if len - 3 == 1 {""} else {"s"}) + }; + + let remaining_fields_names = displayable_field_names.iter().take(3) + .map(|n| format!("`{}`", n)) + .collect::>() + .join(", "); + + struct_span_err!(tcx.sess, span, E0063, + "missing field{} {}{} in initializer of `{}`", + if remaining_fields.len() == 1 { "" } else { "s" }, + remaining_fields_names, + truncated_fields_error, + adt_ty) + .span_label(span, format!("missing {}{}", + remaining_fields_names, + truncated_fields_error)) + .emit(); + } + error_happened + } + + fn check_struct_fields_on_error( + &self, + fields: &'tcx [hir::Field], + base_expr: &'tcx Option>, + ) { + for field in fields { + self.check_expr(&field.expr); + } + if let Some(ref base) = *base_expr { + self.check_expr(&base); + } + } + + fn report_unknown_field( + &self, + ty: Ty<'tcx>, + variant: &'tcx ty::VariantDef, + field: &hir::Field, + skip_fields: &[hir::Field], + kind_name: &str, + ty_span: Span + ) { + if variant.recovered { + return; + } + let mut err = self.type_error_struct_with_diag( + field.ident.span, + |actual| match ty.sty { + ty::Adt(adt, ..) if adt.is_enum() => { + struct_span_err!(self.tcx.sess, field.ident.span, E0559, + "{} `{}::{}` has no field named `{}`", + kind_name, actual, variant.ident, field.ident) + } + _ => { + struct_span_err!(self.tcx.sess, field.ident.span, E0560, + "{} `{}` has no field named `{}`", + kind_name, actual, field.ident) + } + }, + ty); + match variant.ctor_kind { + CtorKind::Fn => { + err.span_label(variant.ident.span, format!("`{adt}` defined here", adt=ty)); + err.span_label(field.ident.span, "field does not exist"); + err.span_label(ty_span, format!( + "`{adt}` is a tuple {kind_name}, \ + use the appropriate syntax: `{adt}(/* fields */)`", + adt=ty, + kind_name=kind_name + )); + } + _ => { + // prevent all specified fields from being suggested + let skip_fields = skip_fields.iter().map(|ref x| x.ident.as_str()); + if let Some(field_name) = Self::suggest_field_name( + variant, + &field.ident.as_str(), + skip_fields.collect() + ) { + err.span_suggestion( + field.ident.span, + "a field with a similar name exists", + field_name.to_string(), + Applicability::MaybeIncorrect, + ); + } else { + match ty.sty { + ty::Adt(adt, ..) => { + if adt.is_enum() { + err.span_label(field.ident.span, format!( + "`{}::{}` does not have this field", + ty, + variant.ident + )); + } else { + err.span_label(field.ident.span, format!( + "`{}` does not have this field", + ty + )); + } + let available_field_names = self.available_field_names(variant); + if !available_field_names.is_empty() { + err.note(&format!("available fields are: {}", + self.name_series_display(available_field_names))); + } + } + _ => bug!("non-ADT passed to report_unknown_field") + } + }; + } + } + err.emit(); + } + + // Return an hint about the closest match in field names + fn suggest_field_name(variant: &'tcx ty::VariantDef, + field: &str, + skip: Vec) + -> Option { + let names = variant.fields.iter().filter_map(|field| { + // ignore already set fields and private fields from non-local crates + if skip.iter().any(|x| *x == field.ident.as_str()) || + (!variant.def_id.is_local() && field.vis != Visibility::Public) + { + None + } else { + Some(&field.ident.name) + } + }); + + find_best_match_for_name(names, field, None) + } + + fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec { + variant.fields.iter().filter(|field| { + let def_scope = + self.tcx.adjust_ident_and_get_scope(field.ident, variant.def_id, self.body_id).1; + field.vis.is_accessible_from(def_scope, self.tcx) + }) + .map(|field| field.ident.name) + .collect() + } + + fn name_series_display(&self, names: Vec) -> String { + // dynamic limit, to never omit just one field + let limit = if names.len() == 6 { 6 } else { 5 }; + let mut display = names.iter().take(limit) + .map(|n| format!("`{}`", n)).collect::>().join(", "); + if names.len() > limit { + display = format!("{} ... and {} others", display, names.len() - limit); + } + display + } + + // Check field access expressions + fn check_field( + &self, + expr: &'tcx hir::Expr, + needs: Needs, + base: &'tcx hir::Expr, + field: ast::Ident, + ) -> Ty<'tcx> { + let expr_t = self.check_expr_with_needs(base, needs); + let expr_t = self.structurally_resolved_type(base.span, + expr_t); + let mut private_candidate = None; + let mut autoderef = self.autoderef(expr.span, expr_t); + while let Some((base_t, _)) = autoderef.next() { + match base_t.sty { + ty::Adt(base_def, substs) if !base_def.is_enum() => { + debug!("struct named {:?}", base_t); + let (ident, def_scope) = + self.tcx.adjust_ident_and_get_scope(field, base_def.did, self.body_id); + let fields = &base_def.non_enum_variant().fields; + if let Some(index) = fields.iter().position(|f| f.ident.modern() == ident) { + let field = &fields[index]; + let field_ty = self.field_ty(expr.span, field, substs); + // Save the index of all fields regardless of their visibility in case + // of error recovery. + self.write_field_index(expr.hir_id, index); + if field.vis.is_accessible_from(def_scope, self.tcx) { + let adjustments = autoderef.adjust_steps(self, needs); + self.apply_adjustments(base, adjustments); + autoderef.finalize(self); + + self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span); + return field_ty; + } + private_candidate = Some((base_def.did, field_ty)); + } + } + ty::Tuple(ref tys) => { + let fstr = field.as_str(); + if let Ok(index) = fstr.parse::() { + if fstr == index.to_string() { + if let Some(field_ty) = tys.get(index) { + let adjustments = autoderef.adjust_steps(self, needs); + self.apply_adjustments(base, adjustments); + autoderef.finalize(self); + + self.write_field_index(expr.hir_id, index); + return field_ty.expect_ty(); + } + } + } + } + _ => {} + } + } + autoderef.unambiguous_final_ty(self); + + if let Some((did, field_ty)) = private_candidate { + let struct_path = self.tcx().def_path_str(did); + let mut err = struct_span_err!(self.tcx().sess, expr.span, E0616, + "field `{}` of struct `{}` is private", + field, struct_path); + // Also check if an accessible method exists, which is often what is meant. + if self.method_exists(field, expr_t, expr.hir_id, false) + && !self.expr_in_place(expr.hir_id) + { + self.suggest_method_call( + &mut err, + &format!("a method `{}` also exists, call it with parentheses", field), + field, + expr_t, + expr.hir_id, + ); + } + err.emit(); + field_ty + } else if field.name == kw::Invalid { + self.tcx().types.err + } else if self.method_exists(field, expr_t, expr.hir_id, true) { + let mut err = type_error_struct!(self.tcx().sess, field.span, expr_t, E0615, + "attempted to take value of method `{}` on type `{}`", + field, expr_t); + + if !self.expr_in_place(expr.hir_id) { + self.suggest_method_call( + &mut err, + "use parentheses to call the method", + field, + expr_t, + expr.hir_id + ); + } else { + err.help("methods are immutable and cannot be assigned to"); + } + + err.emit(); + self.tcx().types.err + } else { + if !expr_t.is_primitive_ty() { + let mut err = self.no_such_field_err(field.span, field, expr_t); + + match expr_t.sty { + ty::Adt(def, _) if !def.is_enum() => { + if let Some(suggested_field_name) = + Self::suggest_field_name(def.non_enum_variant(), + &field.as_str(), vec![]) { + err.span_suggestion( + field.span, + "a field with a similar name exists", + suggested_field_name.to_string(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_label(field.span, "unknown field"); + let struct_variant_def = def.non_enum_variant(); + let field_names = self.available_field_names(struct_variant_def); + if !field_names.is_empty() { + err.note(&format!("available fields are: {}", + self.name_series_display(field_names))); + } + }; + } + ty::Array(_, len) => { + if let (Some(len), Ok(user_index)) = ( + len.assert_usize(self.tcx), + field.as_str().parse::() + ) { + let base = self.tcx.sess.source_map() + .span_to_snippet(base.span) + .unwrap_or_else(|_| + self.tcx.hir().hir_to_pretty_string(base.hir_id)); + let help = "instead of using tuple indexing, use array indexing"; + let suggestion = format!("{}[{}]", base, field); + let applicability = if len < user_index { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }; + err.span_suggestion( + expr.span, help, suggestion, applicability + ); + } + } + ty::RawPtr(..) => { + let base = self.tcx.sess.source_map() + .span_to_snippet(base.span) + .unwrap_or_else(|_| self.tcx.hir().hir_to_pretty_string(base.hir_id)); + let msg = format!("`{}` is a raw pointer; try dereferencing it", base); + let suggestion = format!("(*{}).{}", base, field); + err.span_suggestion( + expr.span, + &msg, + suggestion, + Applicability::MaybeIncorrect, + ); + } + _ => {} + } + err + } else { + type_error_struct!(self.tcx().sess, field.span, expr_t, E0610, + "`{}` is a primitive type and therefore doesn't have fields", + expr_t) + }.emit(); + self.tcx().types.err + } + } + + fn no_such_field_err(&self, span: Span, field: T, expr_t: &ty::TyS<'_>) + -> DiagnosticBuilder<'_> { + type_error_struct!(self.tcx().sess, span, expr_t, E0609, + "no field `{}` on type `{}`", + field, expr_t) + } + + fn check_expr_index( + &self, + base: &'tcx hir::Expr, + idx: &'tcx hir::Expr, + needs: Needs, + expr: &'tcx hir::Expr, + ) -> Ty<'tcx> { + let base_t = self.check_expr_with_needs(&base, needs); + let idx_t = self.check_expr(&idx); + + if base_t.references_error() { + base_t + } else if idx_t.references_error() { + idx_t + } else { + let base_t = self.structurally_resolved_type(base.span, base_t); + match self.lookup_indexing(expr, base, base_t, idx_t, needs) { + Some((index_ty, element_ty)) => { + // two-phase not needed because index_ty is never mutable + self.demand_coerce(idx, idx_t, index_ty, AllowTwoPhase::No); + element_ty + } + None => { + let mut err = + type_error_struct!(self.tcx.sess, expr.span, base_t, E0608, + "cannot index into a value of type `{}`", + base_t); + // Try to give some advice about indexing tuples. + if let ty::Tuple(..) = base_t.sty { + let mut needs_note = true; + // If the index is an integer, we can show the actual + // fixed expression: + if let ExprKind::Lit(ref lit) = idx.node { + if let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node { + let snip = self.tcx.sess.source_map().span_to_snippet(base.span); + if let Ok(snip) = snip { + err.span_suggestion( + expr.span, + "to access tuple elements, use", + format!("{}.{}", snip, i), + Applicability::MachineApplicable, + ); + needs_note = false; + } + } + } + if needs_note { + err.help("to access tuple elements, use tuple indexing \ + syntax (e.g., `tuple.0`)"); + } + } + err.emit(); + self.tcx.types.err + } + } + } + } + + fn check_expr_yield( + &self, + value: &'tcx hir::Expr, + expr: &'tcx hir::Expr, + src: &'tcx hir::YieldSource + ) -> Ty<'tcx> { + match self.yield_ty { + Some(ty) => { + self.check_expr_coercable_to_type(&value, ty); + } + // Given that this `yield` expression was generated as a result of lowering a `.await`, + // we know that the yield type must be `()`; however, the context won't contain this + // information. Hence, we check the source of the yield expression here and check its + // value's type against `()` (this check should always hold). + None if src == &hir::YieldSource::Await => { + self.check_expr_coercable_to_type(&value, self.tcx.mk_unit()); + } + _ => { + struct_span_err!(self.tcx.sess, expr.span, E0627, + "yield statement outside of generator literal").emit(); + } + } + self.tcx.mk_unit() + } +} diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 7f4b0a96a15ab..0bd078dace410 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -6,21 +6,21 @@ use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::{self, Pat, PatKind, Expr}; -use rustc::middle::region; +use rustc::middle::region::{self, YieldData}; use rustc::ty::{self, Ty}; -use rustc_data_structures::sync::Lrc; use syntax_pos::Span; use super::FnCtxt; use crate::util::nodemap::FxHashMap; -struct InteriorVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, +struct InteriorVisitor<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, types: FxHashMap, usize>, - region_scope_tree: Lrc, + region_scope_tree: &'tcx region::ScopeTree, expr_count: usize, + kind: hir::GeneratorKind, } -impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { fn record(&mut self, ty: Ty<'tcx>, scope: Option, @@ -28,8 +28,12 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { source_span: Span) { use syntax_pos::DUMMY_SP; - let live_across_yield = scope.map_or(Some(DUMMY_SP), |s| { - self.region_scope_tree.yield_in_scope(s).and_then(|(yield_span, expr_count)| { + debug!("generator_interior: attempting to record type {:?} {:?} {:?} {:?}", + ty, scope, expr, source_span); + + + let live_across_yield = scope.map(|s| { + self.region_scope_tree.yield_in_scope(s).and_then(|yield_data| { // If we are recording an expression that is the last yield // in the scope, or that has a postorder CFG index larger // than the one of all of the yields, then its value can't @@ -38,28 +42,44 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { // See the mega-comment at `yield_in_scope` for a proof. debug!("comparing counts yield: {} self: {}, source_span = {:?}", - expr_count, self.expr_count, source_span); + yield_data.expr_and_pat_count, self.expr_count, source_span); - if expr_count >= self.expr_count { - Some(yield_span) + if yield_data.expr_and_pat_count >= self.expr_count { + Some(yield_data) } else { None } }) - }); - - if let Some(yield_span) = live_across_yield { - let ty = self.fcx.resolve_type_vars_if_possible(&ty); + }).unwrap_or_else(|| Some(YieldData { + span: DUMMY_SP, + expr_and_pat_count: 0, + source: match self.kind { // Guess based on the kind of the current generator. + hir::GeneratorKind::Gen => hir::YieldSource::Yield, + hir::GeneratorKind::Async => hir::YieldSource::Await, + }, + })); + + if let Some(yield_data) = live_across_yield { + let ty = self.fcx.resolve_vars_if_possible(&ty); debug!("type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}", - expr, scope, ty, self.expr_count, yield_span); - - if self.fcx.any_unresolved_type_vars(&ty) { - let mut err = struct_span_err!(self.fcx.tcx.sess, source_span, E0698, - "type inside generator must be known in this context"); - err.span_note(yield_span, - "the type is part of the generator because of this `yield`"); - err.emit(); + expr, scope, ty, self.expr_count, yield_data.span); + + if let Some((unresolved_type, unresolved_type_span)) = + self.fcx.unresolved_type_vars(&ty) + { + let note = format!("the type is part of the {} because of this {}", + self.kind, + yield_data.source); + + // If unresolved type isn't a ty_var then unresolved_type_span is None + self.fcx.need_type_info_err_in_generator( + self.kind, + unresolved_type_span.unwrap_or(yield_data.span), + unresolved_type, + ) + .span_note(yield_data.span, &*note) + .emit(); } else { // Map the type to the number of types added before it let entries = self.types.len(); @@ -72,16 +92,20 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { } } -pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - def_id: DefId, - body_id: hir::BodyId, - interior: Ty<'tcx>) { +pub fn resolve_interior<'a, 'tcx>( + fcx: &'a FnCtxt<'a, 'tcx>, + def_id: DefId, + body_id: hir::BodyId, + interior: Ty<'tcx>, + kind: hir::GeneratorKind, +) { let body = fcx.tcx.hir().body(body_id); let mut visitor = InteriorVisitor { fcx, types: FxHashMap::default(), region_scope_tree: fcx.tcx.region_scope_tree(def_id), expr_count: 0, + kind, }; intravisit::walk_body(&mut visitor, body); @@ -133,7 +157,7 @@ pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, // This visitor has to have the same visit_expr calls as RegionResolutionVisitor in // librustc/middle/region.rs since `expr_count` is compared against the results // there. -impl<'a, 'gcx, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 924ced2e2a3c7..8c2b8d1565f2f 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -7,14 +7,14 @@ use rustc::ty::subst::Subst; use crate::require_same_types; use rustc_target::spec::abi::Abi; -use syntax::symbol::Symbol; +use syntax::symbol::InternedString; use rustc::hir; use std::iter; -fn equate_intrinsic_type<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn equate_intrinsic_type<'tcx>( + tcx: TyCtxt<'tcx>, it: &hir::ForeignItem, n_tps: usize, abi: Abi, @@ -22,7 +22,7 @@ fn equate_intrinsic_type<'a, 'tcx>( inputs: Vec>, output: Ty<'tcx>, ) { - let def_id = tcx.hir().local_def_id(it.id); + let def_id = tcx.hir().local_def_id_from_hir_id(it.hir_id); match it.node { hir::ForeignItemKind::Fn(..) => {} @@ -70,7 +70,8 @@ pub fn intrisic_operation_unsafety(intrinsic: &str) -> hir::Unsafety { "overflowing_add" | "overflowing_sub" | "overflowing_mul" | "saturating_add" | "saturating_sub" | "rotate_left" | "rotate_right" | - "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" + "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" | + "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" => hir::Unsafety::Normal, _ => hir::Unsafety::Unsafe, } @@ -78,17 +79,19 @@ pub fn intrisic_operation_unsafety(intrinsic: &str) -> hir::Unsafety { /// Remember to add all intrinsics here, in librustc_codegen_llvm/intrinsic.rs, /// and in libcore/intrinsics.rs -pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - it: &hir::ForeignItem) { - let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)).as_interned_str()); +pub fn check_intrinsic_type<'tcx>(tcx: TyCtxt<'tcx>, it: &hir::ForeignItem) { + let param = |n| tcx.mk_ty_param(n, InternedString::intern(&format!("P{}", n))); let name = it.ident.as_str(); - let mk_va_list_ty = || { + let mk_va_list_ty = |mutbl| { tcx.lang_items().va_list().map(|did| { let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0))); let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]); - tcx.mk_mut_ref(tcx.mk_region(env_region), va_list_ty) + (tcx.mk_ref(tcx.mk_region(env_region), ty::TypeAndMut { + ty: va_list_ty, + mutbl + }), va_list_ty) }) }; @@ -272,6 +275,10 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } "fabsf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), "fabsf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), + "minnumf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32), + "minnumf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64), + "maxnumf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32), + "maxnumf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64), "copysignf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32), "copysignf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64), "floorf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), @@ -305,7 +312,8 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "unchecked_shl" | "unchecked_shr" | "rotate_left" | "rotate_right" => (1, vec![param(0), param(0)], param(0)), - + "unchecked_add" | "unchecked_sub" | "unchecked_mul" => + (1, vec![param(0), param(0)], param(0)), "overflowing_add" | "overflowing_sub" | "overflowing_mul" => (1, vec![param(0), param(0)], param(0)), "saturating_add" | "saturating_sub" => @@ -335,42 +343,25 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } "va_start" | "va_end" => { - match mk_va_list_ty() { - Some(va_list_ty) => (0, vec![va_list_ty], tcx.mk_unit()), + match mk_va_list_ty(hir::MutMutable) { + Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], tcx.mk_unit()), None => bug!("`va_list` language item needed for C-variadic intrinsics") } } "va_copy" => { - match tcx.lang_items().va_list() { - Some(did) => { - let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0))); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); - let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]); - let ret_ty = match va_list_ty.sty { - ty::Adt(def, _) if def.is_struct() => { - let fields = &def.non_enum_variant().fields; - match tcx.type_of(fields[0].did).subst(tcx, &[region.into()]).sty { - ty::Ref(_, element_ty, _) => match element_ty.sty { - ty::Adt(..) => element_ty, - _ => va_list_ty - } - _ => bug!("va_list structure is invalid") - } - } - _ => { - bug!("va_list structure is invalid") - } - }; - (0, vec![tcx.mk_imm_ref(tcx.mk_region(env_region), va_list_ty)], ret_ty) + match mk_va_list_ty(hir::MutImmutable) { + Some((va_list_ref_ty, va_list_ty)) => { + let va_list_ptr_ty = tcx.mk_mut_ptr(va_list_ty); + (0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.mk_unit()) } None => bug!("`va_list` language item needed for C-variadic intrinsics") } } "va_arg" => { - match mk_va_list_ty() { - Some(va_list_ty) => (1, vec![va_list_ty], param(0)), + match mk_va_list_ty(hir::MutMutable) { + Some((va_list_ref_ty, _)) => (1, vec![va_list_ref_ty], param(0)), None => bug!("`va_list` language item needed for C-variadic intrinsics") } } @@ -394,10 +385,9 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } /// Type-check `extern "platform-intrinsic" { ... }` functions. -pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - it: &hir::ForeignItem) { +pub fn check_platform_intrinsic_type<'tcx>(tcx: TyCtxt<'tcx>, it: &hir::ForeignItem) { let param = |n| { - let name = Symbol::intern(&format!("P{}", n)).as_interned_str(); + let name = InternedString::intern(&format!("P{}", n)); tcx.mk_ty_param(n, name) }; diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 996d6cfd56830..5df0010b63eb2 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -7,7 +7,7 @@ use crate::hir::def_id::DefId; use rustc::ty::subst::{Subst, SubstsRef}; use rustc::traits; use rustc::ty::{self, Ty, GenericParamDefKind}; -use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref}; +use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref, PointerCast}; use rustc::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::fold::TypeFoldable; use rustc::infer::{self, InferOk}; @@ -16,15 +16,15 @@ use syntax_pos::Span; use std::ops::Deref; -struct ConfirmContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, +struct ConfirmContext<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, span: Span, - self_expr: &'gcx hir::Expr, - call_expr: &'gcx hir::Expr, + self_expr: &'tcx hir::Expr, + call_expr: &'tcx hir::Expr, } -impl<'a, 'gcx, 'tcx> Deref for ConfirmContext<'a, 'gcx, 'tcx> { - type Target = FnCtxt<'a, 'gcx, 'tcx>; +impl<'a, 'tcx> Deref for ConfirmContext<'a, 'tcx> { + type Target = FnCtxt<'a, 'tcx>; fn deref(&self) -> &Self::Target { &self.fcx } @@ -35,12 +35,12 @@ pub struct ConfirmResult<'tcx> { pub illegal_sized_bound: bool, } -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn confirm_method( &self, span: Span, - self_expr: &'gcx hir::Expr, - call_expr: &'gcx hir::Expr, + self_expr: &'tcx hir::Expr, + call_expr: &'tcx hir::Expr, unadjusted_self_ty: Ty<'tcx>, pick: probe::Pick<'tcx>, segment: &hir::PathSegment, @@ -57,12 +57,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { - fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - span: Span, - self_expr: &'gcx hir::Expr, - call_expr: &'gcx hir::Expr) - -> ConfirmContext<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { + fn new( + fcx: &'a FnCtxt<'a, 'tcx>, + span: Span, + self_expr: &'tcx hir::Expr, + call_expr: &'tcx hir::Expr, + ) -> ConfirmContext<'a, 'tcx> { ConfirmContext { fcx, span, @@ -179,7 +180,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { ty: unsize_target }); adjustments.push(Adjustment { - kind: Adjust::Unsize, + kind: Adjust::Pointer(PointerCast::Unsize), target }); } @@ -263,10 +264,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } fn extract_existential_trait_ref(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R - where F: FnMut(&mut ConfirmContext<'a, 'gcx, 'tcx>, - Ty<'tcx>, - ty::PolyExistentialTraitRef<'tcx>) - -> R + where + F: FnMut(&mut ConfirmContext<'a, 'tcx>, Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>) -> R, { // If we specified that this is an object method, then the // self-type ought to be something that can be dereferenced to @@ -341,6 +340,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { self.to_ty(ty).into() } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + self.to_const(&ct.value, self.tcx.type_of(param.def_id)).into() + } _ => unreachable!(), } }, @@ -508,7 +510,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let base_ty = self.tables.borrow().expr_adjustments(base_expr).last() .map_or_else(|| self.node_ty(expr.hir_id), |adj| adj.target); - let base_ty = self.resolve_type_vars_if_possible(&base_ty); + let base_ty = self.resolve_vars_if_possible(&base_ty); // Need to deref because overloaded place ops take self by-reference. let base_ty = base_ty.builtin_deref(false) @@ -562,7 +564,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // If we have an autoref followed by unsizing at the end, fix the unsize target. match adjustments[..] { [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, - Adjustment { kind: Adjust::Unsize, ref mut target }] => { + Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }] => { *target = method.sig.inputs()[0]; } _ => {} diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index d81d24e6d2b03..b8b65279fe767 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -15,7 +15,7 @@ use crate::namespace::Namespace; use errors::{Applicability, DiagnosticBuilder}; use rustc_data_structures::sync::Lrc; use rustc::hir; -use rustc::hir::def::Def; +use rustc::hir::def::{CtorOf, DefKind}; use rustc::hir::def_id::DefId; use rustc::traits; use rustc::ty::subst::{InternalSubsts, SubstsRef}; @@ -26,7 +26,6 @@ use rustc::infer::{self, InferOk}; use syntax::ast; use syntax_pos::Span; -use crate::{check_type_alias_enum_variants_enabled}; use self::probe::{IsSuggestion, ProbeScope}; pub fn provide(providers: &mut ty::query::Providers<'_>) { @@ -53,9 +52,9 @@ pub enum MethodError<'tcx> { // Multiple methods might apply. Ambiguity(Vec), - // Found an applicable method, but it is not visible. The second argument contains a list of + // Found an applicable method, but it is not visible. The third argument contains a list of // not-in-scope traits which may work. - PrivateMatch(Def, Vec), + PrivateMatch(DefKind, DefId, Vec), // Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have // forgotten to import a trait. @@ -71,7 +70,7 @@ pub struct NoMatchData<'tcx> { pub static_candidates: Vec, pub unsatisfied_predicates: Vec>, pub out_of_scope_traits: Vec, - pub lev_candidate: Option, + pub lev_candidate: Option, pub mode: probe::Mode, } @@ -79,7 +78,7 @@ impl<'tcx> NoMatchData<'tcx> { pub fn new(static_candidates: Vec, unsatisfied_predicates: Vec>, out_of_scope_traits: Vec, - lev_candidate: Option, + lev_candidate: Option, mode: probe::Mode) -> Self { NoMatchData { @@ -100,7 +99,7 @@ pub enum CandidateSource { TraitSource(DefId /* trait id */), } -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Determines whether the type `self_ty` supports a method name `method_name` or not. pub fn method_exists(&self, method_name: ast::Ident, @@ -174,13 +173,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// * `self_ty`: the (unadjusted) type of the self expression (`foo`) /// * `supplied_method_types`: the explicit method type parameters, if any (`T1..Tn`) /// * `self_expr`: the self expression (`foo`) - pub fn lookup_method(&self, - self_ty: Ty<'tcx>, - segment: &hir::PathSegment, - span: Span, - call_expr: &'gcx hir::Expr, - self_expr: &'gcx hir::Expr) - -> Result, MethodError<'tcx>> { + pub fn lookup_method( + &self, + self_ty: Ty<'tcx>, + segment: &hir::PathSegment, + span: Span, + call_expr: &'tcx hir::Expr, + self_expr: &'tcx hir::Expr, + ) -> Result, MethodError<'tcx>> { debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})", segment.ident, self_ty, @@ -195,8 +195,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ProbeScope::TraitsInScope )?; - if let Some(import_id) = pick.import_id { - let import_def_id = self.tcx.hir().local_def_id(import_id); + for import_id in &pick.import_ids { + let import_def_id = self.tcx.hir().local_def_id_from_hir_id(*import_id); debug!("used_trait_import: {:?}", import_def_id); Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports) .unwrap().insert(import_def_id); @@ -245,15 +245,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Ok(result.callee) } - fn lookup_probe(&self, - span: Span, - method_name: ast::Ident, - self_ty: Ty<'tcx>, - call_expr: &'gcx hir::Expr, - scope: ProbeScope) - -> probe::PickResult<'tcx> { + fn lookup_probe( + &self, + span: Span, + method_name: ast::Ident, + self_ty: Ty<'tcx>, + call_expr: &'tcx hir::Expr, + scope: ProbeScope, + ) -> probe::PickResult<'tcx> { let mode = probe::Mode::MethodCall; - let self_ty = self.resolve_type_vars_if_possible(&self_ty); + let self_ty = self.resolve_vars_if_possible(&self_ty); self.probe_for_name(span, mode, method_name, IsSuggestion(false), self_ty, call_expr.hir_id, scope) } @@ -283,8 +284,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Construct a trait-reference `self_ty : Trait` let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| { match param.kind { - GenericParamDefKind::Lifetime => {} - GenericParamDefKind::Type {..} => { + GenericParamDefKind::Lifetime | GenericParamDefKind::Const => {} + GenericParamDefKind::Type { .. } => { if param.index == 0 { return self_ty.into(); } else if let Some(ref input_types) = opt_input_types { @@ -400,7 +401,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { method_name: ast::Ident, self_ty: Ty<'tcx>, expr_id: hir::HirId - ) -> Result> { + ) -> Result<(DefKind, DefId), MethodError<'tcx>> { debug!( "resolve_ufcs: method_name={:?} self_ty={:?} expr_id={:?}", method_name, self_ty, expr_id, @@ -415,11 +416,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.hygienic_eq(method_name, vd.ident, adt_def.did) }); if let Some(variant_def) = variant_def { - check_type_alias_enum_variants_enabled(tcx, span); - - let def = Def::VariantCtor(variant_def.did, variant_def.ctor_kind); - tcx.check_stability(def.def_id(), Some(expr_id), span); - return Ok(def); + // Braced variants generate unusable names in value namespace (reserved for + // possible future use), so variants resolved as associated items may refer to + // them as well. It's ok to use the variant's id as a ctor id since an + // error will be reported on any use of such resolution anyway. + let ctor_def_id = variant_def.ctor_def_id.unwrap_or(variant_def.def_id); + tcx.check_stability(ctor_def_id, Some(expr_id), span); + return Ok(( + DefKind::Ctor(CtorOf::Variant, variant_def.ctor_kind), + ctor_def_id, + )); } } } @@ -427,23 +433,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let pick = self.probe_for_name(span, probe::Mode::Path, method_name, IsSuggestion(false), self_ty, expr_id, ProbeScope::TraitsInScope)?; debug!("resolve_ufcs: pick={:?}", pick); - if let Some(import_id) = pick.import_id { - let import_def_id = tcx.hir().local_def_id(import_id); + for import_id in pick.import_ids { + let import_def_id = tcx.hir().local_def_id_from_hir_id(import_id); debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id); Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports) .unwrap().insert(import_def_id); } - let def = pick.item.def(); - debug!("resolve_ufcs: def={:?}", def); - tcx.check_stability(def.def_id(), Some(expr_id), span); - Ok(def) + let def_kind = pick.item.def_kind(); + debug!("resolve_ufcs: def_kind={:?}, def_id={:?}", def_kind, pick.item.def_id); + tcx.check_stability(pick.item.def_id, Some(expr_id), span); + Ok((def_kind, pick.item.def_id)) } /// Finds item with name `item_name` defined in impl/trait `def_id` /// and return it, or `None`, if no such item was defined there. pub fn associated_item(&self, def_id: DefId, item_name: ast::Ident, ns: Namespace) - -> Option { + -> Option { self.tcx.associated_items(def_id).find(|item| { Namespace::from(item.kind) == ns && self.tcx.hygienic_eq(item_name, item.ident, def_id) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index a4624eebcba83..661883f2ac11d 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -6,7 +6,7 @@ use super::suggest; use crate::check::autoderef::{self, Autoderef}; use crate::check::FnCtxt; use crate::hir::def_id::DefId; -use crate::hir::def::Def; +use crate::hir::def::DefKind; use crate::namespace::Namespace; use rustc_data_structures::sync::Lrc; @@ -20,7 +20,8 @@ use rustc::traits::query::method_autoderef::{CandidateStep, MethodAutoderefSteps use rustc::traits::query::method_autoderef::{MethodAutoderefBadTy}; use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable}; use rustc::ty::GenericParamDefKind; -use rustc::infer::type_variable::TypeVariableOrigin; +use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc::util::nodemap::FxHashSet; use rustc::infer::{self, InferOk}; use rustc::infer::canonical::{Canonical, QueryResponse}; @@ -34,6 +35,8 @@ use std::mem; use std::ops::Deref; use std::cmp::max; +use smallvec::{smallvec, SmallVec}; + use self::CandidateKind::*; pub use self::PickKind::*; @@ -42,8 +45,8 @@ pub use self::PickKind::*; #[derive(Clone, Copy)] pub struct IsSuggestion(pub bool); -struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, +struct ProbeContext<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, span: Span, mode: Mode, method_name: Option, @@ -52,7 +55,7 @@ struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { /// This is the OriginalQueryValues for the steps queries /// that are answered in steps. orig_steps_var_values: OriginalQueryValues<'tcx>, - steps: Lrc>>, + steps: Lrc>>, inherent_candidates: Vec>, extension_candidates: Vec>, @@ -67,7 +70,7 @@ struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { allow_similar_names: bool, /// Some(candidate) if there is a private candidate - private_candidate: Option, + private_candidate: Option<(DefKind, DefId)>, /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used /// for error reporting @@ -76,8 +79,8 @@ struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { is_suggestion: IsSuggestion, } -impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> { - type Target = FnCtxt<'a, 'gcx, 'tcx>; +impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> { + type Target = FnCtxt<'a, 'tcx>; fn deref(&self) -> &Self::Target { &self.fcx } @@ -86,7 +89,7 @@ impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> { #[derive(Debug)] struct Candidate<'tcx> { // Candidates are (I'm not quite sure, but they are mostly) basically - // some metadata on top of a `ty::AssociatedItem` (without substs). + // some metadata on top of a `ty::AssocItem` (without substs). // // However, method probing wants to be able to evaluate the predicates // for a function with the substs applied - for example, if a function @@ -118,9 +121,9 @@ struct Candidate<'tcx> { // if `T: Sized`. xform_self_ty: Ty<'tcx>, xform_ret_ty: Option>, - item: ty::AssociatedItem, + item: ty::AssocItem, kind: CandidateKind<'tcx>, - import_id: Option, + import_ids: SmallVec<[hir::HirId; 1]>, } #[derive(Debug)] @@ -143,9 +146,9 @@ enum ProbeResult { #[derive(Debug, PartialEq, Clone)] pub struct Pick<'tcx> { - pub item: ty::AssociatedItem, + pub item: ty::AssocItem, pub kind: PickKind<'tcx>, - pub import_id: Option, + pub import_ids: SmallVec<[hir::HirId; 1]>, // Indicates that the source expression should be autoderef'd N times // @@ -197,7 +200,7 @@ pub enum ProbeScope { AllTraits, } -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This is used to offer suggestions to users. It returns methods /// that could have been called which have the desired return /// type. Some effort is made to rule out methods that, if called, @@ -210,7 +213,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return_type: Ty<'tcx>, self_ty: Ty<'tcx>, scope_expr_id: hir::HirId) - -> Vec { + -> Vec { debug!("probe(self_ty={:?}, return_type={}, scope_expr_id={})", self_ty, return_type, @@ -256,18 +259,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { |probe_cx| probe_cx.pick()) } - fn probe_op(&'a self, - span: Span, - mode: Mode, - method_name: Option, - return_type: Option>, - is_suggestion: IsSuggestion, - self_ty: Ty<'tcx>, - scope_expr_id: hir::HirId, - scope: ProbeScope, - op: OP) - -> Result> - where OP: FnOnce(ProbeContext<'a, 'gcx, 'tcx>) -> Result> + fn probe_op( + &'a self, + span: Span, + mode: Mode, + method_name: Option, + return_type: Option>, + is_suggestion: IsSuggestion, + self_ty: Ty<'tcx>, + scope_expr_id: hir::HirId, + scope: ProbeScope, + op: OP, + ) -> Result> + where + OP: FnOnce(ProbeContext<'a, 'tcx>) -> Result>, { let mut orig_values = OriginalQueryValues::default(); let param_env_and_self_ty = @@ -392,10 +397,10 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { providers.method_autoderef_steps = method_autoderef_steps; } -fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, - goal: CanonicalTyGoal<'tcx>) - -> MethodAutoderefStepsResult<'gcx> -{ +fn method_autoderef_steps<'tcx>( + tcx: TyCtxt<'tcx>, + goal: CanonicalTyGoal<'tcx>, +) -> MethodAutoderefStepsResult<'tcx> { debug!("method_autoderef_steps({:?})", goal); tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| { @@ -460,17 +465,17 @@ fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, }) } - -impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { - fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - span: Span, - mode: Mode, - method_name: Option, - return_type: Option>, - orig_steps_var_values: OriginalQueryValues<'tcx>, - steps: Lrc>>, - is_suggestion: IsSuggestion) - -> ProbeContext<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> ProbeContext<'a, 'tcx> { + fn new( + fcx: &'a FnCtxt<'a, 'tcx>, + span: Span, + mode: Mode, + method_name: Option, + return_type: Option>, + orig_steps_var_values: OriginalQueryValues<'tcx>, + steps: Lrc>>, + is_suggestion: IsSuggestion, + ) -> ProbeContext<'a, 'tcx> { ProbeContext { fcx, span, @@ -507,7 +512,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { { let is_accessible = if let Some(name) = self.method_name { let item = candidate.item; - let def_scope = self.tcx.adjust_ident(name, item.container.id(), self.body_id).1; + let def_scope = + self.tcx.adjust_ident_and_get_scope(name, item.container.id(), self.body_id).1; item.vis.is_accessible_from(def_scope, self.tcx) } else { true @@ -519,7 +525,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.extension_candidates.push(candidate); } } else if self.private_candidate.is_none() { - self.private_candidate = Some(candidate.item.def()); + self.private_candidate = + Some((candidate.item.def_kind(), candidate.item.def_id)); } } @@ -530,7 +537,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } } - fn assemble_probe(&mut self, self_ty: &Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>) { + fn assemble_probe(&mut self, self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>) { debug!("assemble_probe: self_ty={:?}", self_ty); let lang_items = self.tcx.lang_items(); @@ -714,7 +721,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.push_candidate(Candidate { xform_self_ty, xform_ret_ty, item, kind: InherentImplCandidate(impl_substs, obligations), - import_id: None + import_ids: smallvec![] }, true); } } @@ -748,14 +755,13 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { this.push_candidate(Candidate { xform_self_ty, xform_ret_ty, item, kind: ObjectCandidate, - import_id: None + import_ids: smallvec![] }, true); }); } - fn assemble_inherent_candidates_from_param(&mut self, - param_ty: ty::ParamTy) { - // FIXME -- Do we want to commit to this behavior for param bounds? + fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) { + // FIXME: do we want to commit to this behavior for param bounds? let bounds = self.param_env .caller_bounds @@ -797,19 +803,19 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { this.push_candidate(Candidate { xform_self_ty, xform_ret_ty, item, kind: WhereClauseCandidate(poly_trait_ref), - import_id: None + import_ids: smallvec![] }, true); }); } // Do a search through a list of bounds, using a callback to actually // create the candidates. - fn elaborate_bounds(&mut self, - bounds: impl Iterator>, - mut mk_cand: F) - where F: for<'b> FnMut(&mut ProbeContext<'b, 'gcx, 'tcx>, - ty::PolyTraitRef<'tcx>, - ty::AssociatedItem) + fn elaborate_bounds( + &mut self, + bounds: impl Iterator>, + mut mk_cand: F, + ) where + F: for<'b> FnMut(&mut ProbeContext<'b, 'tcx>, ty::PolyTraitRef<'tcx>, ty::AssocItem), { let tcx = self.tcx; for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { @@ -836,8 +842,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { for trait_candidate in applicable_traits.iter() { let trait_did = trait_candidate.def_id; if duplicates.insert(trait_did) { - let import_id = trait_candidate.import_id; - let result = self.assemble_extension_candidates_for_trait(import_id, trait_did); + let import_ids = trait_candidate.import_ids.iter().map(|node_id| + self.fcx.tcx.hir().node_to_hir_id(*node_id)).collect(); + let result = self.assemble_extension_candidates_for_trait(import_ids, + trait_did); result?; } } @@ -849,19 +857,19 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let mut duplicates = FxHashSet::default(); for trait_info in suggest::all_traits(self.tcx) { if duplicates.insert(trait_info.def_id) { - self.assemble_extension_candidates_for_trait(None, trait_info.def_id)?; + self.assemble_extension_candidates_for_trait(smallvec![], trait_info.def_id)?; } } Ok(()) } pub fn matches_return_type(&self, - method: &ty::AssociatedItem, + method: &ty::AssocItem, self_ty: Option>, expected: Ty<'tcx>) -> bool { - match method.def() { - Def::Method(def_id) => { - let fty = self.tcx.fn_sig(def_id); + match method.kind { + ty::AssocKind::Method => { + let fty = self.tcx.fn_sig(method.def_id); self.probe(|_| { let substs = self.fresh_substs_for_item(self.span, method.def_id); let fty = fty.subst(self.tcx, substs); @@ -887,7 +895,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn assemble_extension_candidates_for_trait(&mut self, - import_id: Option, + import_ids: SmallVec<[hir::HirId; 1]>, trait_def_id: DefId) -> Result<(), MethodError<'tcx>> { debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", @@ -895,20 +903,36 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let trait_substs = self.fresh_item_substs(trait_def_id); let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs); - for item in self.impl_or_trait_item(trait_def_id) { - // Check whether `trait_def_id` defines a method with suitable name: - if !self.has_applicable_self(&item) { - debug!("method has inapplicable self"); - self.record_static_candidate(TraitSource(trait_def_id)); - continue; - } + if self.tcx.is_trait_alias(trait_def_id) { + // For trait aliases, assume all super-traits are relevant. + let bounds = iter::once(trait_ref.to_poly_trait_ref()); + self.elaborate_bounds(bounds, |this, new_trait_ref, item| { + let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref); + + let (xform_self_ty, xform_ret_ty) = + this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs); + this.push_candidate(Candidate { + xform_self_ty, xform_ret_ty, item, import_ids: import_ids.clone(), + kind: TraitCandidate(new_trait_ref), + }, true); + }); + } else { + debug_assert!(self.tcx.is_trait(trait_def_id)); + for item in self.impl_or_trait_item(trait_def_id) { + // Check whether `trait_def_id` defines a method with suitable name. + if !self.has_applicable_self(&item) { + debug!("method has inapplicable self"); + self.record_static_candidate(TraitSource(trait_def_id)); + continue; + } - let (xform_self_ty, xform_ret_ty) = - self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs); - self.push_candidate(Candidate { - xform_self_ty, xform_ret_ty, item, import_id, - kind: TraitCandidate(trait_ref), - }, false); + let (xform_self_ty, xform_ret_ty) = + self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs); + self.push_candidate(Candidate { + xform_self_ty, xform_ret_ty, item, import_ids: import_ids.clone(), + kind: TraitCandidate(trait_ref), + }, false); + } } Ok(()) } @@ -929,7 +953,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { .filter(|&name| set.insert(name)) .collect(); - // sort them by the name so we have a stable result + // Sort them by the name so we have a stable result. names.sort_by_cached_key(|n| n.as_str()); names } @@ -944,6 +968,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { return r; } + debug!("pick: actual search failed, assemble diagnotics"); + let static_candidates = mem::replace(&mut self.static_candidates, vec![]); let private_candidate = self.private_candidate.take(); let unsatisfied_predicates = mem::replace(&mut self.unsatisfied_predicates, vec![]); @@ -984,8 +1010,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { _ => vec![], }; - if let Some(def) = private_candidate { - return Err(MethodError::PrivateMatch(def, out_of_scope_traits)); + if let Some((kind, def_id)) = private_candidate { + return Err(MethodError::PrivateMatch(kind, def_id, out_of_scope_traits)); } let lev_candidate = self.probe_for_lev_candidate()?; @@ -1021,9 +1047,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { .next() } - fn pick_by_value_method(&mut self, step: &CandidateStep<'gcx>, self_ty: Ty<'tcx>) - -> Option> - { + fn pick_by_value_method( + &mut self, + step: &CandidateStep<'tcx>, + self_ty: Ty<'tcx>, + ) -> Option> { //! For each type `T` in the step list, this attempts to find a //! method where the (transformed) self type is exactly `T`. We //! do however do one transformation on the adjustment: if we @@ -1051,16 +1079,17 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { }) } - fn pick_autorefd_method(&mut self, - step: &CandidateStep<'gcx>, - self_ty: Ty<'tcx>, - mutbl: hir::Mutability) - -> Option> { + fn pick_autorefd_method( + &mut self, + step: &CandidateStep<'tcx>, + self_ty: Ty<'tcx>, + mutbl: hir::Mutability, + ) -> Option> { let tcx = self.tcx; // In general, during probing we erase regions. See // `impl_self_ty()` for an explanation. - let region = tcx.types.re_erased; + let region = tcx.lifetimes.re_erased; let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { @@ -1195,7 +1224,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // `report_method_error()`. diag.help(&format!( "call with fully qualified syntax `{}(...)` to keep using the current method", - self.tcx.item_path_str(stable_pick.item.def_id), + self.tcx.def_path_str(stable_pick.item.def_id), )); if nightly_options::is_nightly_build() { @@ -1203,7 +1232,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { diag.help(&format!( "add #![feature({})] to the crate attributes to enable `{}`", feature, - self.tcx.item_path_str(candidate.item.def_id), + self.tcx.def_path_str(candidate.item.def_id), )); } } @@ -1315,7 +1344,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // and point at it rather than reporting the entire // trait-ref? result = ProbeResult::NoMatch; - let trait_ref = self.resolve_type_vars_if_possible(&trait_ref); + let trait_ref = self.resolve_vars_if_possible(&trait_ref); possibly_unsatisfied_predicates.push(trait_ref); } } @@ -1328,7 +1357,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // Evaluate those obligations to see if they might possibly hold. for o in candidate_obligations.into_iter().chain(sub_obligations) { - let o = self.resolve_type_vars_if_possible(&o); + let o = self.resolve_vars_if_possible(&o); if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; if let &ty::Predicate::Trait(ref pred) = &o.predicate { @@ -1341,7 +1370,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { if let (Some(return_ty), Some(xform_ret_ty)) = (self.return_type, probe.xform_ret_ty) { - let xform_ret_ty = self.resolve_type_vars_if_possible(&xform_ret_ty); + let xform_ret_ty = self.resolve_vars_if_possible(&xform_ret_ty); debug!("comparing return_ty {:?} with xform ret ty {:?}", return_ty, probe.xform_ret_ty); @@ -1392,7 +1421,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { Some(Pick { item: probes[0].0.item.clone(), kind: TraitPick, - import_id: probes[0].0.import_id, + import_ids: probes[0].0.import_ids.clone(), autoderefs: 0, autoref: None, unsize: None, @@ -1402,7 +1431,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// Similarly to `probe_for_return_type`, this method attempts to find the best matching /// candidate method where the method name may have been misspelt. Similarly to other /// Levenshtein based suggestions, we provide at most one such suggestion. - fn probe_for_lev_candidate(&mut self) -> Result, MethodError<'tcx>> { + fn probe_for_lev_candidate(&mut self) -> Result, MethodError<'tcx>> { debug!("Probing for method names similar to {:?}", self.method_name); @@ -1418,7 +1447,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let method_names = pcx.candidate_method_names(); pcx.allow_similar_names = false; - let applicable_close_candidates: Vec = method_names + let applicable_close_candidates: Vec = method_names .iter() .filter_map(|&method_name| { pcx.reset(); @@ -1451,7 +1480,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /////////////////////////////////////////////////////////////////////////// // MISCELLANY - fn has_applicable_self(&self, item: &ty::AssociatedItem) -> bool { + fn has_applicable_self(&self, item: &ty::AssocItem) -> bool { // "Fast track" -- check for usage of sugar when in method call // mode. // @@ -1460,9 +1489,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { match self.mode { Mode::MethodCall => item.method_has_self_argument, Mode::Path => match item.kind { - ty::AssociatedKind::Existential | - ty::AssociatedKind::Type => false, - ty::AssociatedKind::Method | ty::AssociatedKind::Const => true + ty::AssocKind::Existential | + ty::AssocKind::Type => false, + ty::AssocKind::Method | ty::AssocKind::Const => true }, } // FIXME -- check for types that deref to `Self`, @@ -1478,11 +1507,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn xform_self_ty(&self, - item: &ty::AssociatedItem, + item: &ty::AssocItem, impl_ty: Ty<'tcx>, substs: SubstsRef<'tcx>) -> (Ty<'tcx>, Option>) { - if item.kind == ty::AssociatedKind::Method && self.mode == Mode::MethodCall { + if item.kind == ty::AssocKind::Method && self.mode == Mode::MethodCall { let sig = self.xform_method_sig(item.def_id, substs); (sig.inputs()[0], Some(sig.output())) } else { @@ -1526,9 +1555,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { GenericParamDefKind::Lifetime => { // In general, during probe we erase regions. See // `impl_self_ty()` for an explanation. - self.tcx.types.re_erased.into() + self.tcx.lifetimes.re_erased.into() + } + GenericParamDefKind::Type { .. } + | GenericParamDefKind::Const => { + self.var_for_def(self.span, param) } - GenericParamDefKind::Type {..} => self.var_for_def(self.span, param), } } }); @@ -1544,10 +1576,20 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx> { InternalSubsts::for_item(self.tcx, def_id, |param, _| { match param.kind { - GenericParamDefKind::Lifetime => self.tcx.types.re_erased.into(), - GenericParamDefKind::Type {..} => { - self.next_ty_var(TypeVariableOrigin::SubstitutionPlaceholder( - self.tcx.def_span(def_id))).into() + GenericParamDefKind::Lifetime => self.tcx.lifetimes.re_erased.into(), + GenericParamDefKind::Type { .. } => { + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::SubstitutionPlaceholder, + span: self.tcx.def_span(def_id), + }).into() + } + GenericParamDefKind::Const { .. } => { + let span = self.tcx.def_span(def_id); + let origin = ConstVariableOrigin { + kind: ConstVariableOriginKind::SubstitutionPlaceholder, + span, + }; + self.next_const_var(self.tcx.type_of(param.def_id), origin).into() } } }) @@ -1579,7 +1621,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// Finds the method with the appropriate name (or return type, as the case may be). If /// `allow_similar_names` is set, find methods with close-matching names. - fn impl_or_trait_item(&self, def_id: DefId) -> Vec { + fn impl_or_trait_item(&self, def_id: DefId) -> Vec { if let Some(name) = self.method_name { if self.allow_similar_names { let max_dist = max(name.as_str().len(), 3) / 3; @@ -1623,7 +1665,7 @@ impl<'tcx> Candidate<'tcx> { WhereClausePick(trait_ref.clone()) } }, - import_id: self.import_id, + import_ids: self.import_ids.clone(), autoderefs: 0, autoref: None, unsize: None, diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index c15cb1e5bb151..fa1b07d2dcfcd 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -6,27 +6,26 @@ use crate::middle::lang_items::FnOnceTraitLangItem; use crate::namespace::Namespace; use crate::util::nodemap::FxHashSet; use errors::{Applicability, DiagnosticBuilder}; -use rustc_data_structures::sync::Lrc; use rustc::hir::{self, ExprKind, Node, QPath}; -use rustc::hir::def::Def; +use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; use rustc::hir::map as hir_map; use rustc::hir::print; -use rustc::infer::type_variable::TypeVariableOrigin; +use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::traits::Obligation; -use rustc::ty::{self, Adt, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable}; -use rustc::ty::item_path::with_crate_prefix; +use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable}; +use rustc::ty::print::with_crate_prefix; use syntax_pos::{Span, FileName}; use syntax::ast; -use syntax::util::lev_distance::find_best_match_for_name; +use syntax::util::lev_distance; use std::cmp::Ordering; use super::{MethodError, NoMatchData, CandidateSource}; use super::probe::Mode; -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - fn is_fn_ty(&self, ty: &Ty<'tcx>, span: Span) -> bool { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { let tcx = self.tcx; match ty.sty { // Not all of these (e.g., unsafe fns) implement `FnOnce`, @@ -44,7 +43,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.autoderef(span, ty).any(|(ty, _)| { self.probe(|_| { let fn_once_substs = tcx.mk_substs_trait(ty, &[ - self.next_ty_var(TypeVariableOrigin::MiscVariable(span)).into() + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span, + }).into() ]); let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs); let poly_trait_ref = trait_ref.to_poly_trait_ref(); @@ -60,20 +62,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn report_method_error<'b>(&self, - span: Span, - rcvr_ty: Ty<'tcx>, - item_name: ast::Ident, - source: SelfSource<'b>, - error: MethodError<'tcx>, - args: Option<&'gcx [hir::Expr]>) { + pub fn report_method_error<'b>( + &self, + span: Span, + rcvr_ty: Ty<'tcx>, + item_name: ast::Ident, + source: SelfSource<'b>, + error: MethodError<'tcx>, + args: Option<&'tcx [hir::Expr]>, + ) { + let orig_span = span; + let mut span = span; // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { return; } - let report_candidates = |err: &mut DiagnosticBuilder<'_>, - mut sources: Vec| { + let report_candidates = | + span: Span, + err: &mut DiagnosticBuilder<'_>, + mut sources: Vec, + | { sources.sort(); sources.dedup(); // Dynamic limit to avoid hiding just one candidate, which is silly. @@ -84,14 +93,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { CandidateSource::ImplSource(impl_did) => { // Provide the best span we can. Use the item, if local to crate, else // the impl, if local to crate (item may be defaulted), else nothing. - let item = self.associated_item(impl_did, item_name, Namespace::Value) - .or_else(|| { - self.associated_item( - self.tcx.impl_trait_ref(impl_did).unwrap().def_id, - item_name, - Namespace::Value, - ) - }).unwrap(); + let item = match self.associated_item( + impl_did, + item_name, + Namespace::Value, + ).or_else(|| { + let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?; + self.associated_item( + impl_trait_ref.def_id, + item_name, + Namespace::Value, + ) + }) { + Some(item) => item, + None => continue, + }; let note_span = self.tcx.hir().span_if_local(item.def_id).or_else(|| { self.tcx.hir().span_if_local(impl_did) }); @@ -102,7 +118,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None => String::new(), Some(trait_ref) => { format!(" of the trait `{}`", - self.tcx.item_path_str(trait_ref.def_id)) + self.tcx.def_path_str(trait_ref.def_id)) } }; @@ -125,9 +141,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } CandidateSource::TraitSource(trait_did) => { - let item = self - .associated_item(trait_did, item_name, Namespace::Value) - .unwrap(); + let item = match self.associated_item( + trait_did, + item_name, + Namespace::Value) + { + Some(item) => item, + None => continue, + }; let item_span = self.tcx.sess.source_map() .def_span(self.tcx.def_span(item.def_id)); if sources.len() > 1 { @@ -135,16 +156,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { item_span, "candidate #{} is defined in the trait `{}`", idx + 1, - self.tcx.item_path_str(trait_did)); + self.tcx.def_path_str(trait_did)); } else { span_note!(err, item_span, "the candidate is defined in the trait `{}`", - self.tcx.item_path_str(trait_did)); + self.tcx.def_path_str(trait_did)); } err.help(&format!("to disambiguate the method call, write `{}::{}({}{})` \ instead", - self.tcx.item_path_str(trait_did), + self.tcx.def_path_str(trait_did), item_name, if rcvr_ty.is_region_ptr() && args.is_some() { if rcvr_ty.is_mutable_pointer() { @@ -178,20 +199,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) => { let tcx = self.tcx; - let actual = self.resolve_type_vars_if_possible(&rcvr_ty); + let actual = self.resolve_vars_if_possible(&rcvr_ty); let ty_str = self.ty_to_string(actual); let is_method = mode == Mode::MethodCall; - let mut suggestion = None; let item_kind = if is_method { "method" } else if actual.is_enum() { - if let Adt(ref adt_def, _) = actual.sty { - let names = adt_def.variants.iter().map(|s| &s.ident.name); - suggestion = find_best_match_for_name(names, - &item_name.as_str(), - None); - } - "variant" + "variant or associated item" } else { match (item_name.as_str().chars().next(), actual.is_fresh_ty()) { (Some(name), false) if name.is_lowercase() => { @@ -249,26 +263,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ExprKind::Path(ref qpath) => { // local binding if let &QPath::Resolved(_, ref path) = &qpath { - if let hir::def::Def::Local(node_id) = path.def { - let span = tcx.hir().span(node_id); - let snippet = tcx.sess.source_map().span_to_snippet(span) - .unwrap(); + if let hir::def::Res::Local(hir_id) = path.res { + let span = tcx.hir().span(hir_id); + let snippet = tcx.sess.source_map().span_to_snippet(span); let filename = tcx.sess.source_map().span_to_filename(span); let parent_node = self.tcx.hir().get( - self.tcx.hir().get_parent_node(node_id), + self.tcx.hir().get_parent_node(hir_id), ); let msg = format!( "you must specify a type for this binding, like `{}`", concrete_type, ); - match (filename, parent_node) { + match (filename, parent_node, snippet) { (FileName::Real(_), Node::Local(hir::Local { source: hir::LocalSource::Normal, ty, .. - })) => { + }), Ok(ref snippet)) => { err.span_suggestion( // account for `let x: _ = 42;` // ^^^^ @@ -291,23 +304,33 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.emit(); return; } else { + span = item_name.span; let mut err = struct_span_err!( tcx.sess, - item_name.span, + span, E0599, "no {} named `{}` found for type `{}` in the current scope", item_kind, item_name, ty_str ); - if let Some(suggestion) = suggestion { - // enum variant - err.span_suggestion( - item_name.span, - "did you mean", - suggestion.to_string(), - Applicability::MaybeIncorrect, - ); + if let Some(span) = tcx.sess.confused_type_with_std_module.borrow() + .get(&span) + { + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) { + err.span_suggestion( + *span, + "you are looking for the module in `std`, \ + not the primitive type", + format!("std::{}", snippet), + Applicability::MachineApplicable, + ); + } + } + if let ty::RawPtr(_) = &actual.sty { + err.note("try using `<*const T>::as_ref()` to get a reference to the \ + type behind the pointer: https://doc.rust-lang.org/std/\ + primitive.pointer.html#method.as_ref"); } err } @@ -332,47 +355,65 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If the method name is the name of a field with a function or closure type, // give a helping note that it has to be called as `(x.f)(...)`. if let SelfSource::MethodCall(expr) = source { - for (ty, _) in self.autoderef(span, rcvr_ty) { - if let ty::Adt(def, substs) = ty.sty { - if !def.is_enum() { + let field_receiver = self + .autoderef(span, rcvr_ty) + .find_map(|(ty, _)| match ty.sty { + ty::Adt(def, substs) if !def.is_enum() => { let variant = &def.non_enum_variant(); - if let Some(index) = self.tcx.find_field_index(item_name, variant) { + self.tcx.find_field_index(item_name, variant).map(|index| { let field = &variant.fields[index]; - let snippet = tcx.sess.source_map().span_to_snippet(expr.span); - let expr_string = match snippet { - Ok(expr_string) => expr_string, - _ => "s".into(), // Default to a generic placeholder for the - // expression when we can't generate a - // string snippet. - }; - let field_ty = field.ty(tcx, substs); - let scope = self.tcx.hir().get_module_parent_by_hir_id( - self.body_id); - if field.vis.is_accessible_from(scope, self.tcx) { - if self.is_fn_ty(&field_ty, span) { - err.help(&format!("use `({0}.{1})(...)` if you \ - meant to call the function \ - stored in the `{1}` field", - expr_string, - item_name)); - } else { - err.help(&format!("did you mean to write `{0}.{1}` \ - instead of `{0}.{1}(...)`?", - expr_string, - item_name)); - } - err.span_label(span, "field, not a method"); - } else { - err.span_label(span, "private field, not a method"); - } - break; + (field, field_ty) + }) + } + _ => None, + }); + + if let Some((field, field_ty)) = field_receiver { + let scope = self.tcx.hir().get_module_parent(self.body_id); + let is_accessible = field.vis.is_accessible_from(scope, self.tcx); + + if is_accessible { + if self.is_fn_ty(&field_ty, span) { + let expr_span = expr.span.to(item_name.span); + err.multipart_suggestion( + &format!( + "to call the function stored in `{}`, \ + surround the field access with parentheses", + item_name, + ), + vec![ + (expr_span.shrink_to_lo(), '('.to_string()), + (expr_span.shrink_to_hi(), ')'.to_string()), + ], + Applicability::MachineApplicable, + ); + } else { + let call_expr = self.tcx.hir().expect_expr( + self.tcx.hir().get_parent_node(expr.hir_id), + ); + + if let Some(span) = call_expr.span.trim_start(item_name.span) { + err.span_suggestion( + span, + "remove the arguments", + String::new(), + Applicability::MaybeIncorrect, + ); } } } + + let field_kind = if is_accessible { + "field" + } else { + "private field" + }; + err.span_label(item_name.span, format!("{}, not a method", field_kind)); } } else { err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str)); + self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span); } if self.is_fn_ty(&rcvr_ty, span) { @@ -414,9 +455,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.ty_to_string(actual), item_name)); } - report_candidates(&mut err, static_sources); + report_candidates(span, &mut err, static_sources); } else if static_sources.len() > 1 { - report_candidates(&mut err, static_sources); + report_candidates(span, &mut err, static_sources); } if !unsatisfied_predicates.is_empty() { @@ -443,14 +484,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { out_of_scope_traits); } + if actual.is_enum() { + let adt_def = actual.ty_adt_def().expect("enum is not an ADT"); + if let Some(suggestion) = lev_distance::find_best_match_for_name( + adt_def.variants.iter().map(|s| &s.ident.name), + &item_name.as_str(), + None, + ) { + err.span_suggestion( + span, + "there is a variant with a similar name", + suggestion.to_string(), + Applicability::MaybeIncorrect, + ); + } + } + if let Some(lev_candidate) = lev_candidate { + let def_kind = lev_candidate.def_kind(); err.span_suggestion( span, - "did you mean", + &format!( + "there is {} {} with a similar name", + def_kind.article(), + def_kind.descr(), + ), lev_candidate.ident.to_string(), Applicability::MaybeIncorrect, ); } + err.emit(); } @@ -461,13 +524,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { "multiple applicable items in scope"); err.span_label(span, format!("multiple `{}` found", item_name)); - report_candidates(&mut err, sources); + report_candidates(span, &mut err, sources); err.emit(); } - MethodError::PrivateMatch(def, out_of_scope_traits) => { + MethodError::PrivateMatch(kind, _, out_of_scope_traits) => { let mut err = struct_span_err!(self.tcx.sess, span, E0624, - "{} `{}` is private", def.kind_name(), item_name); + "{} `{}` is private", kind.descr(), item_name); self.suggest_valid_traits(&mut err, out_of_scope_traits); err.emit(); } @@ -501,7 +564,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err: &mut DiagnosticBuilder<'_>, mut msg: String, candidates: Vec) { - let module_did = self.tcx.hir().get_module_parent_by_hir_id(self.body_id); + let module_did = self.tcx.hir().get_module_parent(self.body_id); let module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap(); let krate = self.tcx.hir().krate(); let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id); @@ -516,7 +579,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; format!( "use {};\n{}", - with_crate_prefix(|| self.tcx.item_path_str(*did)), + with_crate_prefix(|| self.tcx.def_path_str(*did)), additional_newline ) }); @@ -530,14 +593,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &format!( "\ncandidate #{}: `use {};`", i + 1, - with_crate_prefix(|| self.tcx.item_path_str(*trait_did)) + with_crate_prefix(|| self.tcx.def_path_str(*trait_did)) ) ); } else { msg.push_str( &format!( "\n`use {};`", - with_crate_prefix(|| self.tcx.item_path_str(*trait_did)) + with_crate_prefix(|| self.tcx.def_path_str(*trait_did)) ) ); } @@ -638,7 +701,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for (i, trait_info) in candidates.iter().enumerate() { msg.push_str(&format!("\ncandidate #{}: `{}`", i + 1, - self.tcx.item_path_str(trait_info.def_id))); + self.tcx.def_path_str(trait_info.def_id))); } err.note(&msg[..]); } @@ -712,28 +775,32 @@ impl Ord for TraitInfo { } /// Retrieves all traits in this crate and any dependent crates. -pub fn all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec { +pub fn all_traits<'tcx>(tcx: TyCtxt<'tcx>) -> Vec { tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect() } /// Computes all traits in this crate and any dependent crates. -fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec { +fn compute_all_traits<'tcx>(tcx: TyCtxt<'tcx>) -> Vec { use hir::itemlikevisit; let mut traits = vec![]; // Crate-local: - struct Visitor<'a, 'tcx: 'a> { + struct Visitor<'a, 'tcx> { map: &'a hir_map::Map<'tcx>, traits: &'a mut Vec, } impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'v hir::Item) { - if let hir::ItemKind::Trait(..) = i.node { - let def_id = self.map.local_def_id(i.id); - self.traits.push(def_id); + match i.node { + hir::ItemKind::Trait(..) | + hir::ItemKind::TraitAlias(..) => { + let def_id = self.map.local_def_id_from_hir_id(i.hir_id); + self.traits.push(def_id); + } + _ => () } } @@ -750,20 +817,23 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec // Cross-crate: let mut external_mods = FxHashSet::default(); - fn handle_external_def(tcx: TyCtxt<'_, '_, '_>, - traits: &mut Vec, - external_mods: &mut FxHashSet, - def: Def) { - match def { - Def::Trait(def_id) => { + fn handle_external_res( + tcx: TyCtxt<'_>, + traits: &mut Vec, + external_mods: &mut FxHashSet, + res: Res, + ) { + match res { + Res::Def(DefKind::Trait, def_id) | + Res::Def(DefKind::TraitAlias, def_id) => { traits.push(def_id); } - Def::Mod(def_id) => { + Res::Def(DefKind::Mod, def_id) => { if !external_mods.insert(def_id) { return; } for child in tcx.item_children(def_id).iter() { - handle_external_def(tcx, traits, external_mods, child.def) + handle_external_res(tcx, traits, external_mods, child.res) } } _ => {} @@ -774,7 +844,7 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec krate: cnum, index: CRATE_DEF_INDEX, }; - handle_external_def(tcx, &mut traits, &mut external_mods, Def::Mod(def_id)); + handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id)); } traits @@ -783,20 +853,20 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec pub fn provide(providers: &mut ty::query::Providers<'_>) { providers.all_traits = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - Lrc::new(compute_all_traits(tcx)) + &tcx.arena.alloc(compute_all_traits(tcx))[..] } } -struct UsePlacementFinder<'a, 'tcx: 'a, 'gcx: 'tcx> { +struct UsePlacementFinder<'tcx> { target_module: hir::HirId, span: Option, found_use: bool, - tcx: TyCtxt<'a, 'gcx, 'tcx> + tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx, 'gcx> UsePlacementFinder<'a, 'tcx, 'gcx> { +impl UsePlacementFinder<'tcx> { fn check( - tcx: TyCtxt<'a, 'gcx, 'tcx>, + tcx: TyCtxt<'tcx>, krate: &'tcx hir::Crate, target_module: hir::HirId, ) -> (Option, bool) { @@ -811,7 +881,7 @@ impl<'a, 'tcx, 'gcx> UsePlacementFinder<'a, 'tcx, 'gcx> { } } -impl<'a, 'tcx, 'gcx> hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'a, 'tcx, 'gcx> { +impl hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> { fn visit_mod( &mut self, module: &'tcx hir::Mod, @@ -832,7 +902,7 @@ impl<'a, 'tcx, 'gcx> hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'a, ' hir::ItemKind::Use(..) => { // Don't suggest placing a `use` before the prelude // import or other generated ones. - if item.span.ctxt().outer().expn_info().is_none() { + if item.span.ctxt().outer_expn_info().is_none() { self.span = Some(item.span.shrink_to_lo()); self.found_use = true; return; @@ -842,7 +912,7 @@ impl<'a, 'tcx, 'gcx> hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'a, ' hir::ItemKind::ExternCrate(_) => {} // ...but do place them before the first other item. _ => if self.span.map_or(true, |span| item.span < span ) { - if item.span.ctxt().outer().expn_info().is_none() { + if item.span.ctxt().outer_expn_info().is_none() { // Don't insert between attributes and an item. if item.attrs.is_empty() { self.span = Some(item.span.shrink_to_lo()); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 80ffe44156101..17513c8608a81 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + /*! # typeck: check phase @@ -72,6 +74,7 @@ pub mod writeback; mod regionck; pub mod coercion; pub mod demand; +mod expr; pub mod method; mod upvar; mod wfcheck; @@ -86,45 +89,46 @@ mod op; use crate::astconv::{AstConv, PathSeg}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use rustc::hir::{self, ExprKind, GenericArg, ItemKind, Node, PatKind, QPath}; -use rustc::hir::def::{CtorKind, Def}; +use rustc::hir::def::{CtorOf, Res, DefKind}; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::ItemLikeVisitor; use crate::middle::lang_items; use crate::namespace::Namespace; -use rustc::infer::{self, InferCtxt, InferOk, InferResult, RegionVariableOrigin}; +use rustc::infer::{self, InferCtxt, InferOk, InferResult}; use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_data_structures::indexed_vec::Idx; -use rustc_data_structures::sync::Lrc; use rustc_target::spec::abi::Abi; use rustc::infer::opaque_types::OpaqueTypeDecl; -use rustc::infer::type_variable::{TypeVariableOrigin}; +use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc::middle::region; use rustc::mir::interpret::{ConstValue, GlobalId}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; use rustc::ty::{ - self, AdtKind, CanonicalUserType, Ty, TyCtxt, GenericParamDefKind, Visibility, + self, AdtKind, CanonicalUserType, Ty, TyCtxt, Const, GenericParamDefKind, ToPolyTraitRef, ToPredicate, RegionKind, UserType }; -use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; +use rustc::ty::adjustment::{ + Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast +}; use rustc::ty::fold::TypeFoldable; use rustc::ty::query::Providers; use rustc::ty::subst::{UnpackedKind, Subst, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts}; use rustc::ty::util::{Representability, IntTypeExt, Discr}; use rustc::ty::layout::VariantIdx; use syntax_pos::{self, BytePos, Span, MultiSpan}; +use syntax_pos::hygiene::CompilerDesugaringKind; use syntax::ast; use syntax::attr; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::ptr::P; use syntax::source_map::{DUMMY_SP, original_sp}; -use syntax::symbol::{Symbol, LocalInternedString, keywords}; -use syntax::util::lev_distance::find_best_match_for_name; +use syntax::symbol::{kw, sym}; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::collections::hash_map::Entry; use std::cmp; -use std::fmt::Display; use std::iter; use std::mem::replace; use std::ops::{self, Deref}; @@ -137,7 +141,7 @@ use crate::TypeAndSubsts; use crate::lint; use crate::util::captures::Captures; use crate::util::common::{ErrorReported, indenter}; -use crate::util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, HirIdMap}; +use crate::util::nodemap::{DefIdMap, DefIdSet, FxHashSet, HirIdMap}; pub use self::Expectation::*; use self::autoderef::Autoderef; @@ -156,7 +160,7 @@ pub struct LocalTy<'tcx> { /// A wrapper for `InferCtxt`'s `in_progress_tables` field. #[derive(Copy, Clone)] -struct MaybeInProgressTables<'a, 'tcx: 'a> { +struct MaybeInProgressTables<'a, 'tcx> { maybe_tables: Option<&'a RefCell>>, } @@ -189,8 +193,8 @@ impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { /// Here, the function `foo()` and the closure passed to /// `bar()` will each have their own `FnCtxt`, but they will /// share the inherited fields. -pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - infcx: InferCtxt<'a, 'gcx, 'tcx>, +pub struct Inherited<'a, 'tcx> { + infcx: InferCtxt<'a, 'tcx>, tables: MaybeInProgressTables<'a, 'tcx>, @@ -209,11 +213,11 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // decision. We keep these deferred resolutions grouped by the // def-id of the closure, so that once we decide, we can easily go // back and process them. - deferred_call_resolutions: RefCell>>>, + deferred_call_resolutions: RefCell>>>, deferred_cast_checks: RefCell>>, - deferred_generator_interiors: RefCell)>>, + deferred_generator_interiors: RefCell, hir::GeneratorKind)>>, // Opaque types found in explicit return types and their // associated fresh inference variable. Writeback resolves these @@ -232,8 +236,8 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { body_id: Option, } -impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> { - type Target = InferCtxt<'a, 'gcx, 'tcx>; +impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { + type Target = InferCtxt<'a, 'tcx>; fn deref(&self) -> &Self::Target { &self.infcx } @@ -246,9 +250,6 @@ pub enum Expectation<'tcx> { /// We know nothing about what type this expression should have. NoExpectation, - /// This expression is an `if` condition, it must resolve to `bool`. - ExpectIfCondition, - /// This expression should have the type given (or some subtype). ExpectHasType(Ty<'tcx>), @@ -260,7 +261,7 @@ pub enum Expectation<'tcx> { ExpectRvalueLikeUnsized(Ty<'tcx>), } -impl<'a, 'gcx, 'tcx> Expectation<'tcx> { +impl<'a, 'tcx> Expectation<'tcx> { // Disregard "castable to" expectations because they // can lead us astray. Consider for example `if cond // {22} else {c} as u8` -- if we propagate the @@ -277,7 +278,7 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { // an expected type. Otherwise, we might write parts of the type // when checking the 'then' block which are incompatible with the // 'else' branch. - fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Expectation<'tcx> { + fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { match *self { ExpectHasType(ety) => { let ety = fcx.shallow_resolve(ety); @@ -313,7 +314,7 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { /// which still is useful, because it informs integer literals and the like. /// See the test case `test/run-pass/coerce-expect-unsized.rs` and #20169 /// for examples of where this comes up,. - fn rvalue_hint(fcx: &FnCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> { + fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> { match fcx.tcx.struct_tail(ty).sty { ty::Slice(_) | ty::Str | ty::Dynamic(..) => { ExpectRvalueLikeUnsized(ty) @@ -325,26 +326,24 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { // Resolves `expected` by a single level if it is a variable. If // there is no expected type or resolution is not possible (e.g., // no constraints yet present), just returns `None`. - fn resolve(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Expectation<'tcx> { + fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { match self { NoExpectation => NoExpectation, - ExpectIfCondition => ExpectIfCondition, ExpectCastableToType(t) => { - ExpectCastableToType(fcx.resolve_type_vars_if_possible(&t)) + ExpectCastableToType(fcx.resolve_vars_if_possible(&t)) } ExpectHasType(t) => { - ExpectHasType(fcx.resolve_type_vars_if_possible(&t)) + ExpectHasType(fcx.resolve_vars_if_possible(&t)) } ExpectRvalueLikeUnsized(t) => { - ExpectRvalueLikeUnsized(fcx.resolve_type_vars_if_possible(&t)) + ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)) } } } - fn to_option(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Option> { + fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { match self.resolve(fcx) { NoExpectation => None, - ExpectIfCondition => Some(fcx.tcx.types.bool), ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty), @@ -355,19 +354,23 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { /// a **hard constraint** (i.e., something that must be satisfied /// for the program to type-check). `only_has_type` will return /// such a constraint, if it exists. - fn only_has_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Option> { + fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { match self.resolve(fcx) { ExpectHasType(ty) => Some(ty), - ExpectIfCondition => Some(fcx.tcx.types.bool), NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None, } } /// Like `only_has_type`, but instead of returning `None` if no /// hard constraint exists, creates a fresh type variable. - fn coercion_target_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, span: Span) -> Ty<'tcx> { + fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> { self.only_has_type(fcx) - .unwrap_or_else(|| fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span))) + .unwrap_or_else(|| { + fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span, + }) + }) } } @@ -487,21 +490,21 @@ impl Diverges { } } -pub struct BreakableCtxt<'gcx: 'tcx, 'tcx> { +pub struct BreakableCtxt<'tcx> { may_break: bool, // this is `null` for loops where break with a value is illegal, // such as `while`, `for`, and `while let` - coerce: Option>, + coerce: Option>, } -pub struct EnclosingBreakables<'gcx: 'tcx, 'tcx> { - stack: Vec>, +pub struct EnclosingBreakables<'tcx> { + stack: Vec>, by_id: HirIdMap, } -impl<'gcx, 'tcx> EnclosingBreakables<'gcx, 'tcx> { - fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'gcx, 'tcx> { +impl<'tcx> EnclosingBreakables<'tcx> { + fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> { let ix = *self.by_id.get(&target_id).unwrap_or_else(|| { bug!("could not find enclosing breakable with id {}", target_id); }); @@ -509,7 +512,7 @@ impl<'gcx, 'tcx> EnclosingBreakables<'gcx, 'tcx> { } } -pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +pub struct FnCtxt<'a, 'tcx> { body_id: hir::HirId, /// The parameter environment used for proving trait obligations @@ -520,13 +523,15 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// eventually). param_env: ty::ParamEnv<'tcx>, - // Number of errors that had been reported when we started - // checking this function. On exit, if we find that *more* errors - // have been reported, we will skip regionck and other work that - // expects the types within the function to be consistent. + /// Number of errors that had been reported when we started + /// checking this function. On exit, if we find that *more* errors + /// have been reported, we will skip regionck and other work that + /// expects the types within the function to be consistent. + // FIXME(matthewjasper) This should not exist, and it's not correct + // if type checking is run in parallel. err_count_on_creation: usize, - ret_coercion: Option>>, + ret_coercion: Option>>, ret_coercion_span: RefCell>, yield_ty: Option>, @@ -569,13 +574,13 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// Whether any child nodes have any type errors. has_errors: Cell, - enclosing_breakables: RefCell>, + enclosing_breakables: RefCell>, - inh: &'a Inherited<'a, 'gcx, 'tcx>, + inh: &'a Inherited<'a, 'tcx>, } -impl<'a, 'gcx, 'tcx> Deref for FnCtxt<'a, 'gcx, 'tcx> { - type Target = Inherited<'a, 'gcx, 'tcx>; +impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { + type Target = Inherited<'a, 'tcx>; fn deref(&self) -> &Self::Target { &self.inh } @@ -583,18 +588,16 @@ impl<'a, 'gcx, 'tcx> Deref for FnCtxt<'a, 'gcx, 'tcx> { /// Helper type of a temporary returned by `Inherited::build(...)`. /// Necessary because we can't write the following bound: -/// `F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Inherited<'b, 'gcx, 'tcx>)`. -pub struct InheritedBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - infcx: infer::InferCtxtBuilder<'a, 'gcx, 'tcx>, +/// `F: for<'b, 'tcx> where 'tcx FnOnce(Inherited<'b, 'tcx>)`. +pub struct InheritedBuilder<'tcx> { + infcx: infer::InferCtxtBuilder<'tcx>, def_id: DefId, } -impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { - pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, def_id: DefId) - -> InheritedBuilder<'a, 'gcx, 'tcx> { +impl Inherited<'_, 'tcx> { + pub fn build(tcx: TyCtxt<'tcx>, def_id: DefId) -> InheritedBuilder<'tcx> { let hir_id_root = if def_id.is_local() { - let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); - let hir_id = tcx.hir().definitions().node_to_hir_id(node_id); + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); DefId::local(hir_id.owner) } else { def_id @@ -607,19 +610,20 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> { - fn enter(&'tcx mut self, f: F) -> R - where F: for<'b> FnOnce(Inherited<'b, 'gcx, 'tcx>) -> R +impl<'tcx> InheritedBuilder<'tcx> { + fn enter(&mut self, f: F) -> R + where + F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R, { let def_id = self.def_id; self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id))) } } -impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { - fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>, def_id: DefId) -> Self { +impl Inherited<'a, 'tcx> { + fn new(infcx: InferCtxt<'a, 'tcx>, def_id: DefId) -> Self { let tcx = infcx.tcx; - let item_id = tcx.hir().as_local_node_id(def_id); + let item_id = tcx.hir().as_local_hir_id(def_id); let body_id = item_id.and_then(|id| tcx.hir().maybe_body_owned_by(id)); let implicit_region_bound = body_id.map(|body_id| { let body = tcx.hir().body(body_id); @@ -682,9 +686,11 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { } } -struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } +struct CheckItemTypesVisitor<'tcx> { + tcx: TyCtxt<'tcx>, +} -impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> { +impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { fn visit_item(&mut self, i: &'tcx hir::Item) { check_item_type(self.tcx, i); } @@ -692,49 +698,31 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> { fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) { } } -pub fn check_wf_new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Result<(), ErrorReported> { - tcx.sess.track_errors(|| { - let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); - tcx.hir().krate().visit_all_item_likes(&mut visit); - }) -} - -pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Result<(), ErrorReported> { - tcx.sess.track_errors(|| { - for &module in tcx.hir().krate().modules.keys() { - tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module)); - } - }) +pub fn check_wf_new<'tcx>(tcx: TyCtxt<'tcx>) { + let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); + tcx.hir().krate().par_visit_all_item_likes(&mut visit); } -fn check_mod_item_types<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) { +fn check_mod_item_types<'tcx>(tcx: TyCtxt<'tcx>, module_def_id: DefId) { tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); } -pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Result<(), ErrorReported> { - tcx.typeck_item_bodies(LOCAL_CRATE) -} - -fn typeck_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) - -> Result<(), ErrorReported> -{ +fn typeck_item_bodies<'tcx>(tcx: TyCtxt<'tcx>, crate_num: CrateNum) { debug_assert!(crate_num == LOCAL_CRATE); - Ok(tcx.sess.track_errors(|| { - tcx.par_body_owners(|body_owner_def_id| { - tcx.ensure().typeck_tables_of(body_owner_def_id); - }); - })?) + tcx.par_body_owners(|body_owner_def_id| { + tcx.ensure().typeck_tables_of(body_owner_def_id); + }); } -fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { +fn check_item_well_formed<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) { wfcheck::check_item_well_formed(tcx, def_id); } -fn check_trait_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { +fn check_trait_item_well_formed<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) { wfcheck::check_trait_item(tcx, def_id); } -fn check_impl_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { +fn check_impl_item_well_formed<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) { wfcheck::check_impl_item(tcx, def_id); } @@ -754,9 +742,7 @@ pub fn provide(providers: &mut Providers<'_>) { }; } -fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> Option { +fn adt_destructor<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option { tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl) } @@ -769,11 +755,11 @@ fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// may not succeed. In some cases where this function returns `None` /// (notably closures), `typeck_tables(def_id)` would wind up /// redirecting to the owning function. -fn primary_body_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: hir::HirId) - -> Option<(hir::BodyId, Option<&'tcx hir::FnDecl>)> -{ - match tcx.hir().get_by_hir_id(id) { +fn primary_body_of<'tcx>( + tcx: TyCtxt<'tcx>, + id: hir::HirId, +) -> Option<(hir::BodyId, Option<&'tcx hir::FnDecl>)> { + match tcx.hir().get(id) { Node::Item(item) => { match item.node { hir::ItemKind::Const(_, body) | @@ -810,9 +796,7 @@ fn primary_body_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn has_typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> bool { +fn has_typeck_tables<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { // Closures' tables come from their outermost function, // as they are part of the same "inference environment". let outer_def_id = tcx.closure_base_def_id(def_id); @@ -824,15 +808,11 @@ fn has_typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, primary_body_of(tcx, id).is_some() } -fn used_trait_imports<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> Lrc { - tcx.typeck_tables_of(def_id).used_trait_imports.clone() +fn used_trait_imports<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx DefIdSet { + &*tcx.typeck_tables_of(def_id).used_trait_imports } -fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> &'tcx ty::TypeckTables<'tcx> { +fn typeck_tables_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx ty::TypeckTables<'tcx> { // Closures' tables come from their outermost function, // as they are part of the same "inference environment". let outer_def_id = tcx.closure_base_def_id(def_id); @@ -841,7 +821,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let span = tcx.hir().span_by_hir_id(id); + let span = tcx.hir().span(id); // Figure out what primary body this item has. let (body_id, fn_decl) = primary_body_of(tcx, id).unwrap_or_else(|| { @@ -876,7 +856,8 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let revealed_ty = if tcx.features().impl_trait_in_bindings { fcx.instantiate_opaque_types_from_value( id, - &expected_type + &expected_type, + body.value.span, ) } else { expected_type @@ -887,6 +868,8 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx.check_expr_coercable_to_type(&body.value, revealed_ty); + fcx.write_ty(id, revealed_ty); + fcx }; @@ -930,24 +913,27 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables } -fn check_abi<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, abi: Abi) { +fn check_abi<'tcx>(tcx: TyCtxt<'tcx>, span: Span, abi: Abi) { if !tcx.sess.target.target.is_abi_supported(abi) { struct_span_err!(tcx.sess, span, E0570, "The ABI `{}` is not supported for the current target", abi).emit() } } -struct GatherLocalsVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, +struct GatherLocalsVisitor<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId, } -impl<'a, 'gcx, 'tcx> GatherLocalsVisitor<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option>) -> Ty<'tcx> { match ty_opt { None => { // infer the variable's type - let var_ty = self.fcx.next_ty_var(TypeVariableOrigin::TypeInference(span)); + let var_ty = self.fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }); self.fcx.locals.borrow_mut().insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty @@ -963,13 +949,13 @@ impl<'a, 'gcx, 'tcx> GatherLocalsVisitor<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { +impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } // Add explicitly-declared locals. - fn visit_local(&mut self, local: &'gcx hir::Local) { + fn visit_local(&mut self, local: &'tcx hir::Local) { let local_ty = match local.ty { Some(ref ty) => { let o_ty = self.fcx.to_ty(&ty); @@ -977,7 +963,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { self.fcx.instantiate_opaque_types_from_value( self.parent_id, - &o_ty + &o_ty, + ty.span, ) } else { o_ty @@ -1004,13 +991,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { } // Add pattern bindings. - fn visit_pat(&mut self, p: &'gcx hir::Pat) { - if let PatKind::Binding(_, _, _, ident, _) = p.node { + fn visit_pat(&mut self, p: &'tcx hir::Pat) { + if let PatKind::Binding(_, _, ident, _) = p.node { let var_ty = self.assign(p.span, p.hir_id, None); if !self.fcx.tcx.features().unsized_locals { self.fcx.require_type_is_sized(var_ty, p.span, - traits::VariableType(p.id)); + traits::VariableType(p.hir_id)); } debug!("Pattern binding {} is assigned to {} with type {:?}", @@ -1023,8 +1010,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { } // Don't descend into the bodies of nested closures - fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl, - _: hir::BodyId, _: Span, _: hir::HirId) { } + fn visit_fn( + &mut self, + _: intravisit::FnKind<'tcx>, + _: &'tcx hir::FnDecl, + _: hir::BodyId, + _: Span, + _: hir::HirId, + ) { } } /// When `check_fn` is invoked on a generator (i.e., a body that @@ -1032,10 +1025,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { /// points. struct GeneratorTypes<'tcx> { /// Type of value that is yielded. - yield_ty: ty::Ty<'tcx>, + yield_ty: Ty<'tcx>, /// Types that are captured (see `GeneratorInterior` for more). - interior: ty::Ty<'tcx>, + interior: Ty<'tcx>, /// Indicates if the generator is movable or static (immovable). movability: hir::GeneratorMovability, @@ -1047,15 +1040,15 @@ struct GeneratorTypes<'tcx> { /// /// * ... /// * inherited: other fields inherited from the enclosing fn (if any) -fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - fn_sig: ty::FnSig<'tcx>, - decl: &'gcx hir::FnDecl, - fn_id: hir::HirId, - body: &'gcx hir::Body, - can_be_generator: Option) - -> (FnCtxt<'a, 'gcx, 'tcx>, Option>) -{ +fn check_fn<'a, 'tcx>( + inherited: &'a Inherited<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + fn_sig: ty::FnSig<'tcx>, + decl: &'tcx hir::FnDecl, + fn_id: hir::HirId, + body: &'tcx hir::Body, + can_be_generator: Option, +) -> (FnCtxt<'a, 'tcx>, Option>) { let mut fn_sig = fn_sig.clone(); debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env); @@ -1067,7 +1060,11 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, let declared_ret_ty = fn_sig.output(); fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - let revealed_ret_ty = fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty); + let revealed_ret_ty = fcx.instantiate_opaque_types_from_value( + fn_id, + &declared_ret_ty, + decl.output.span(), + ); fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); fn_sig = fcx.tcx.mk_fn_sig( fn_sig.inputs().iter().cloned(), @@ -1079,8 +1076,11 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, let span = body.value.span; - if body.is_generator && can_be_generator.is_some() { - let yield_ty = fcx.next_ty_var(TypeVariableOrigin::TypeInference(span)); + if body.generator_kind.is_some() && can_be_generator.is_some() { + let yield_ty = fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }); fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); fcx.yield_ty = Some(yield_ty); } @@ -1092,12 +1092,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Add formal parameters. for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) { // Check the pattern. - fcx.check_pat_walk( - &arg.pat, - arg_ty, - ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), - None, - ); + let binding_mode = ty::BindingMode::BindByValue(hir::Mutability::MutImmutable); + fcx.check_pat_walk(&arg.pat, arg_ty, binding_mode, None); // Check that argument is Sized. // The check for a non-trivial pattern is a hack to avoid duplicate warnings @@ -1117,9 +1113,12 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // We insert the deferred_generator_interiors entry after visiting the body. // This ensures that all nested generators appear before the entry of this generator. // resolve_generator_interiors relies on this property. - let gen_ty = if can_be_generator.is_some() && body.is_generator { - let interior = fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span)); - fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior)); + let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) { + let interior = fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span, + }); + fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind)); Some(GeneratorTypes { yield_ty: fcx.yield_ty.unwrap(), interior, @@ -1156,7 +1155,11 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, let mut actual_return_ty = coercion.complete(&fcx); if actual_return_ty.is_never() { actual_return_ty = fcx.next_diverging_ty_var( - TypeVariableOrigin::DivergingFn(span)); + TypeVariableOrigin { + kind: TypeVariableOriginKind::DivergingFn, + span, + }, + ); } fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); @@ -1195,7 +1198,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, } let inputs = fn_sig.inputs(); - let span = fcx.tcx.hir().span_by_hir_id(fn_id); + let span = fcx.tcx.hir().span(fn_id); if inputs.len() == 1 { let arg_is_panic_info = match inputs[0].sty { ty::Ref(region, ty, mutbl) => match ty.sty { @@ -1216,7 +1219,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, ); } - if let Node::Item(item) = fcx.tcx.hir().get_by_hir_id(fn_id) { + if let Node::Item(item) = fcx.tcx.hir().get(fn_id) { if let ItemKind::Fn(_, _, ref generics, _) = item.node { if !generics.params.is_empty() { fcx.tcx.sess.span_err( @@ -1248,7 +1251,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, } let inputs = fn_sig.inputs(); - let span = fcx.tcx.hir().span_by_hir_id(fn_id); + let span = fcx.tcx.hir().span(fn_id); if inputs.len() == 1 { let arg_is_alloc_layout = match inputs[0].sty { ty::Adt(ref adt, _) => { @@ -1264,7 +1267,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, ); } - if let Node::Item(item) = fcx.tcx.hir().get_by_hir_id(fn_id) { + if let Node::Item(item) = fcx.tcx.hir().get(fn_id) { if let ItemKind::Fn(_, _, ref generics, _) = item.node { if !generics.params.is_empty() { fcx.tcx.sess.span_err( @@ -1288,10 +1291,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, (fcx, gen_ty) } -fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: ast::NodeId, - span: Span) { - let def_id = tcx.hir().local_def_id(id); +fn check_struct<'tcx>(tcx: TyCtxt<'tcx>, id: hir::HirId, span: Span) { + let def_id = tcx.hir().local_def_id_from_hir_id(id); let def = tcx.adt_def(def_id); def.destructor(tcx); // force the destructor to be evaluated check_representable(tcx, span, def_id); @@ -1304,23 +1305,16 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_packed(tcx, span, def_id); } -fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: ast::NodeId, - span: Span) { - let def_id = tcx.hir().local_def_id(id); +fn check_union<'tcx>(tcx: TyCtxt<'tcx>, id: hir::HirId, span: Span) { + let def_id = tcx.hir().local_def_id_from_hir_id(id); let def = tcx.adt_def(def_id); def.destructor(tcx); // force the destructor to be evaluated check_representable(tcx, span, def_id); - + check_transparent(tcx, span, def_id); check_packed(tcx, span, def_id); } -fn check_opaque<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, - span: Span, -) { +fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, span: Span) { if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id, substs) { let mut err = struct_span_err!( tcx.sess, span, E0720, @@ -1336,30 +1330,30 @@ fn check_opaque<'a, 'tcx>( } } -pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) { +pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item) { debug!( - "check_item_type(it.id={}, it.name={})", - it.id, - tcx.item_path_str(tcx.hir().local_def_id(it.id)) + "check_item_type(it.hir_id={}, it.name={})", + it.hir_id, + tcx.def_path_str(tcx.hir().local_def_id_from_hir_id(it.hir_id)) ); let _indenter = indenter(); match it.node { // Consts can play a role in type-checking, so they are included here. hir::ItemKind::Static(..) => { - let def_id = tcx.hir().local_def_id(it.id); + let def_id = tcx.hir().local_def_id_from_hir_id(it.hir_id); tcx.typeck_tables_of(def_id); maybe_check_static_with_link_section(tcx, def_id, it.span); } hir::ItemKind::Const(..) => { - tcx.typeck_tables_of(tcx.hir().local_def_id(it.id)); + tcx.typeck_tables_of(tcx.hir().local_def_id_from_hir_id(it.hir_id)); } hir::ItemKind::Enum(ref enum_definition, _) => { - check_enum(tcx, it.span, &enum_definition.variants, it.id); + check_enum(tcx, it.span, &enum_definition.variants, it.hir_id); } hir::ItemKind::Fn(..) => {} // entirely within check_item_body hir::ItemKind::Impl(.., ref impl_item_refs) => { - debug!("ItemKind::Impl {} with id {}", it.ident, it.id); - let impl_def_id = tcx.hir().local_def_id(it.id); + debug!("ItemKind::Impl {} with id {}", it.ident, it.hir_id); + let impl_def_id = tcx.hir().local_def_id_from_hir_id(it.hir_id); if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) { check_impl_items_against_trait( tcx, @@ -1373,23 +1367,23 @@ pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Ite } } hir::ItemKind::Trait(..) => { - let def_id = tcx.hir().local_def_id(it.id); + let def_id = tcx.hir().local_def_id_from_hir_id(it.hir_id); check_on_unimplemented(tcx, def_id, it); } hir::ItemKind::Struct(..) => { - check_struct(tcx, it.id, it.span); + check_struct(tcx, it.hir_id, it.span); } hir::ItemKind::Union(..) => { - check_union(tcx, it.id, it.span); + check_union(tcx, it.hir_id, it.span); } hir::ItemKind::Existential(..) => { - let def_id = tcx.hir().local_def_id(it.id); + let def_id = tcx.hir().local_def_id_from_hir_id(it.hir_id); let substs = InternalSubsts::identity_for_item(tcx, def_id); check_opaque(tcx, def_id, substs, it.span); } hir::ItemKind::Ty(..) => { - let def_id = tcx.hir().local_def_id(it.id); + let def_id = tcx.hir().local_def_id_from_hir_id(it.hir_id); let pty_ty = tcx.type_of(def_id); let generics = tcx.generics_of(def_id); check_bounds_are_used(tcx, &generics, pty_ty); @@ -1407,7 +1401,7 @@ pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Ite } } else { for item in &m.items { - let generics = tcx.generics_of(tcx.hir().local_def_id(item.id)); + let generics = tcx.generics_of(tcx.hir().local_def_id_from_hir_id(item.hir_id)); if generics.params.len() - generics.own_counts().lifetimes != 0 { let mut err = struct_span_err!( tcx.sess, @@ -1435,7 +1429,7 @@ pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Ite } } -fn maybe_check_static_with_link_section(tcx: TyCtxt<'_, '_, '_>, id: DefId, span: Span) { +fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: DefId, span: Span) { // Only restricted on wasm32 target for now if !tcx.sess.opts.target_triple.triple().starts_with("wasm32") { return @@ -1459,8 +1453,8 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_, '_, '_>, id: DefId, span }; let param_env = ty::ParamEnv::reveal_all(); if let Ok(static_) = tcx.const_eval(param_env.and(cid)) { - let alloc = if let ConstValue::ByRef(_, allocation) = static_.val { - allocation + let alloc = if let ConstValue::ByRef { alloc, .. } = static_.val { + alloc } else { bug!("Matching on non-ByRef static") }; @@ -1473,18 +1467,17 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_, '_, '_>, id: DefId, span } } -fn check_on_unimplemented<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_def_id: DefId, - item: &hir::Item) { - let item_def_id = tcx.hir().local_def_id(item.id); +fn check_on_unimplemented<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, item: &hir::Item) { + let item_def_id = tcx.hir().local_def_id_from_hir_id(item.hir_id); // an error would be reported if this fails. let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id); } -fn report_forbidden_specialization<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_item: &hir::ImplItem, - parent_impl: DefId) -{ +fn report_forbidden_specialization<'tcx>( + tcx: TyCtxt<'tcx>, + impl_item: &hir::ImplItem, + parent_impl: DefId, +) { let mut err = struct_span_err!( tcx.sess, impl_item.span, E0520, "`{}` specializes an item from a parent `impl`, but \ @@ -1507,19 +1500,20 @@ fn report_forbidden_specialization<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, err.emit(); } -fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_def: &ty::TraitDef, - trait_item: &ty::AssociatedItem, - impl_id: DefId, - impl_item: &hir::ImplItem) -{ +fn check_specialization_validity<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def: &ty::TraitDef, + trait_item: &ty::AssocItem, + impl_id: DefId, + impl_item: &hir::ImplItem, +) { let ancestors = trait_def.ancestors(tcx, impl_id); let kind = match impl_item.node { - hir::ImplItemKind::Const(..) => ty::AssociatedKind::Const, - hir::ImplItemKind::Method(..) => ty::AssociatedKind::Method, - hir::ImplItemKind::Existential(..) => ty::AssociatedKind::Existential, - hir::ImplItemKind::Type(_) => ty::AssociatedKind::Type + hir::ImplItemKind::Const(..) => ty::AssocKind::Const, + hir::ImplItemKind::Method(..) => ty::AssocKind::Method, + hir::ImplItemKind::Existential(..) => ty::AssocKind::Existential, + hir::ImplItemKind::Type(_) => ty::AssocKind::Type }; let parent = ancestors.defs(tcx, trait_item.ident, kind, trait_def.def_id).nth(1) @@ -1533,11 +1527,13 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } -fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_span: Span, - impl_id: DefId, - impl_trait_ref: ty::TraitRef<'tcx>, - impl_item_refs: &[hir::ImplItemRef]) { +fn check_impl_items_against_trait<'tcx>( + tcx: TyCtxt<'tcx>, + impl_span: Span, + impl_id: DefId, + impl_trait_ref: ty::TraitRef<'tcx>, + impl_item_refs: &[hir::ImplItemRef], +) { let impl_span = tcx.sess.source_map().def_span(impl_span); // If the trait reference itself is erroneous (so the compilation is going @@ -1570,7 +1566,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match impl_item.node { hir::ImplItemKind::Const(..) => { // Find associated const definition. - if ty_trait_item.kind == ty::AssociatedKind::Const { + if ty_trait_item.kind == ty::AssocKind::Const { compare_const_impl(tcx, &ty_impl_item, impl_item.span, @@ -1593,7 +1589,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } hir::ImplItemKind::Method(..) => { let trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); - if ty_trait_item.kind == ty::AssociatedKind::Method { + if ty_trait_item.kind == ty::AssocKind::Method { compare_impl_method(tcx, &ty_impl_item, impl_item.span, @@ -1615,7 +1611,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } hir::ImplItemKind::Existential(..) | hir::ImplItemKind::Type(_) => { - if ty_trait_item.kind == ty::AssociatedKind::Type { + if ty_trait_item.kind == ty::AssocKind::Type { if ty_trait_item.defaultness.has_value() { overridden_associated_type = Some(impl_item); } @@ -1673,7 +1669,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, err.span_label(span, format!("`{}` from trait", trait_item.ident)); } else { err.note_trait_signature(trait_item.ident.to_string(), - trait_item.signature(&tcx)); + trait_item.signature(tcx)); } } err.emit(); @@ -1694,10 +1690,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// Checks whether a type can be represented in memory. In particular, it /// identifies types that contain themselves without indirection through a /// pointer, which would mean their size is unbounded. -fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - sp: Span, - item_def_id: DefId) - -> bool { +fn check_representable<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, item_def_id: DefId) -> bool { let rty = tcx.type_of(item_def_id); // Check that it is possible to represent this type. This call identifies @@ -1716,10 +1709,10 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } Representability::Representable | Representability::ContainsRecursive => (), } - return true + return true; } -pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) { +pub fn check_simd<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, def_id: DefId) { let t = tcx.type_of(def_id); if let ty::Adt(def, substs) = t.sty { if def.is_struct() { @@ -1748,7 +1741,7 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId } } -fn check_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) { +fn check_packed<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, def_id: DefId) { let repr = tcx.adt_def(def_id).repr; if repr.packed() { for attr in tcx.get_attrs(def_id).iter() { @@ -1772,9 +1765,7 @@ fn check_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) } } -fn check_packed_inner<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - stack: &mut Vec) -> bool { +fn check_packed_inner<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, stack: &mut Vec) -> bool { let t = tcx.type_of(def_id); if stack.contains(&def_id) { debug!("check_packed_inner: {:?} is recursive", t); @@ -1802,14 +1793,88 @@ fn check_packed_inner<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, false } -fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) { +/// Emit an error when encountering more or less than one variant in a transparent enum. +fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, did: DefId) { + let variant_spans: Vec<_> = adt.variants.iter().map(|variant| { + tcx.hir().span_if_local(variant.def_id).unwrap() + }).collect(); + let msg = format!( + "needs exactly one variant, but has {}", + adt.variants.len(), + ); + let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {}", msg); + err.span_label(sp, &msg); + if let &[ref start.., ref end] = &variant_spans[..] { + for variant_span in start { + err.span_label(*variant_span, ""); + } + err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did))); + } + err.emit(); +} + +/// Emit an error when encountering more or less than one non-zero-sized field in a transparent +/// enum. +fn bad_non_zero_sized_fields<'tcx>( + tcx: TyCtxt<'tcx>, + adt: &'tcx ty::AdtDef, + field_count: usize, + field_spans: impl Iterator, + sp: Span, +) { + let msg = format!("needs exactly one non-zero-sized field, but has {}", field_count); + let mut err = struct_span_err!( + tcx.sess, + sp, + E0690, + "{}transparent {} {}", + if adt.is_enum() { "the variant of a " } else { "" }, + adt.descr(), + msg, + ); + err.span_label(sp, &msg); + for sp in field_spans { + err.span_label(sp, "this field is non-zero-sized"); + } + err.emit(); +} + +fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, def_id: DefId) { let adt = tcx.adt_def(def_id); if !adt.repr.transparent() { return; } + let sp = tcx.sess.source_map().def_span(sp); + + if adt.is_enum() { + if !tcx.features().transparent_enums { + emit_feature_err( + &tcx.sess.parse_sess, + sym::transparent_enums, + sp, + GateIssue::Language, + "transparent enums are unstable", + ); + } + if adt.variants.len() != 1 { + bad_variant_count(tcx, adt, sp, def_id); + if adt.variants.is_empty() { + // Don't bother checking the fields. No variants (and thus no fields) exist. + return; + } + } + } + + if adt.is_union() && !tcx.features().transparent_unions { + emit_feature_err(&tcx.sess.parse_sess, + sym::transparent_unions, + sp, + GateIssue::Language, + "transparent unions are unstable"); + } // For each field, figure out if it's known to be a ZST and align(1) - let field_infos = adt.non_enum_variant().fields.iter().map(|field| { + let field_infos = adt.all_fields().map(|field| { let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did)); let param_env = tcx.param_env(field.did); let layout = tcx.layout_of(param_env.and(ty)); @@ -1820,36 +1885,37 @@ fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: De (span, zst, align1) }); - let non_zst_fields = field_infos.clone().filter(|(_span, zst, _align1)| !*zst); + let non_zst_fields = field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { + Some(span) + } else { + None + }); let non_zst_count = non_zst_fields.clone().count(); if non_zst_count != 1 { - let field_spans: Vec<_> = non_zst_fields.map(|(span, _zst, _align1)| span).collect(); - struct_span_err!(tcx.sess, sp, E0690, - "transparent struct needs exactly one non-zero-sized field, but has {}", - non_zst_count) - .span_note(field_spans, "non-zero-sized field") - .emit(); + bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp); } for (span, zst, align1) in field_infos { if zst && !align1 { - span_err!(tcx.sess, span, E0691, - "zero-sized field in transparent struct has alignment larger than 1"); + struct_span_err!( + tcx.sess, + span, + E0691, + "zero-sized field in transparent {} has alignment larger than 1", + adt.descr(), + ).span_label(span, "has alignment larger than 1").emit(); } } } #[allow(trivial_numeric_casts)] -pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - sp: Span, - vs: &'tcx [hir::Variant], - id: ast::NodeId) { - let def_id = tcx.hir().local_def_id(id); +pub fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, vs: &'tcx [hir::Variant], id: hir::HirId) { + let def_id = tcx.hir().local_def_id_from_hir_id(id); let def = tcx.adt_def(def_id); def.destructor(tcx); // force the destructor to be evaluated if vs.is_empty() { let attributes = tcx.get_attrs(def_id); - if let Some(attr) = attr::find_by_name(&attributes, "repr") { + if let Some(attr) = attr::find_by_name(&attributes, sym::repr) { struct_span_err!( tcx.sess, attr.span, E0084, "unsupported representation for zero-variant enum") @@ -1862,7 +1928,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { if !tcx.features().repr128 { emit_feature_err(&tcx.sess.parse_sess, - "repr128", + sym::repr128, sp, GateIssue::Language, "repr with 128-bit type is unstable"); @@ -1875,19 +1941,38 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } + if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant { + let is_unit = + |var: &hir::Variant| match var.node.data { + hir::VariantData::Unit(..) => true, + _ => false + }; + + let has_disr = |var: &hir::Variant| var.node.disr_expr.is_some(); + let has_non_units = vs.iter().any(|var| !is_unit(var)); + let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var)); + let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var)); + + if disr_non_unit || (disr_units && has_non_units) { + let mut err = struct_span_err!(tcx.sess, sp, E0732, + "`#[repr(inttype)]` must be specified"); + err.emit(); + } + } + let mut disr_vals: Vec> = Vec::with_capacity(vs.len()); for ((_, discr), v) in def.discriminants(tcx).zip(vs) { // Check for duplicate discriminant values if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) { - let variant_did = def.variants[VariantIdx::new(i)].did; + let variant_did = def.variants[VariantIdx::new(i)].def_id; let variant_i_hir_id = tcx.hir().as_local_hir_id(variant_did).unwrap(); let variant_i = tcx.hir().expect_variant(variant_i_hir_id); let i_span = match variant_i.node.disr_expr { - Some(ref expr) => tcx.hir().span_by_hir_id(expr.hir_id), - None => tcx.hir().span_by_hir_id(variant_i_hir_id) + Some(ref expr) => tcx.hir().span(expr.hir_id), + None => tcx.hir().span(variant_i_hir_id) }; let span = match v.node.disr_expr { - Some(ref expr) => tcx.hir().span_by_hir_id(expr.hir_id), + Some(ref expr) => tcx.hir().span(expr.hir_id), None => v.span }; struct_span_err!(tcx.sess, span, E0081, @@ -1900,31 +1985,31 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } check_representable(tcx, sp, def_id); + check_transparent(tcx, sp, def_id); } -fn report_unexpected_variant_def<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - def: &Def, - span: Span, - qpath: &QPath) { +fn report_unexpected_variant_res<'tcx>(tcx: TyCtxt<'tcx>, res: Res, span: Span, qpath: &QPath) { span_err!(tcx.sess, span, E0533, "expected unit struct/variant or constant, found {} `{}`", - def.kind_name(), + res.descr(), hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false))); } -impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } +impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) - -> Lrc> + -> &'tcx ty::GenericPredicates<'tcx> { let tcx = self.tcx; - let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); - let item_id = tcx.hir().ty_param_owner(node_id); - let item_def_id = tcx.hir().local_def_id(item_id); + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let item_id = tcx.hir().ty_param_owner(hir_id); + let item_def_id = tcx.hir().local_def_id_from_hir_id(item_id); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; - Lrc::new(ty::GenericPredicates { + tcx.arena.alloc(ty::GenericPredicates { parent: None, predicates: self.param_env.caller_bounds.iter().filter_map(|&predicate| { match predicate { @@ -1940,8 +2025,11 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { }) } - fn re_infer(&self, span: Span, def: Option<&ty::GenericParamDef>) - -> Option> { + fn re_infer( + &self, + def: Option<&ty::GenericParamDef>, + span: Span, + ) -> Option> { let v = match def { Some(def) => infer::EarlyBoundRegion(span, def.name), None => infer::MiscVariable(span) @@ -1949,17 +2037,37 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { Some(self.next_region_var(v)) } - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.next_ty_var(TypeVariableOrigin::TypeInference(span)) + fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { + if let Some(param) = param { + if let UnpackedKind::Type(ty) = self.var_for_def(span, param).unpack() { + return ty; + } + unreachable!() + } else { + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }) + } } - fn ty_infer_for_def(&self, - ty_param_def: &ty::GenericParamDef, - span: Span) -> Ty<'tcx> { - if let UnpackedKind::Type(ty) = self.var_for_def(span, ty_param_def).unpack() { - return ty; + fn ct_infer( + &self, + ty: Ty<'tcx>, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> &'tcx Const<'tcx> { + if let Some(param) = param { + if let UnpackedKind::Const(ct) = self.var_for_def(span, param).unpack() { + return ct; + } + unreachable!() + } else { + self.next_const_var(ty, ConstVariableOrigin { + kind: ConstVariableOriginKind::ConstInference, + span, + }) } - unreachable!() } fn projected_ty_from_poly_trait_ref(&self, @@ -2016,11 +2124,12 @@ enum TupleArgumentsFlag { TupleArguments, } -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId) - -> FnCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn new( + inh: &'a Inherited<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ) -> FnCtxt<'a, 'tcx> { FnCtxt { body_id, param_env, @@ -2044,22 +2153,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &self.tcx.sess } - pub fn err_count_since_creation(&self) -> usize { - self.tcx.sess.err_count() - self.err_count_on_creation + pub fn errors_reported_since_creation(&self) -> bool { + self.tcx.sess.err_count() > self.err_count_on_creation } /// Produces warning on the given node, if the current point in the /// function is unreachable, and there hasn't been another warning. fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { - if self.diverges.get() == Diverges::Always { + if self.diverges.get() == Diverges::Always && + // If span arose from a desugaring of `if` then it is the condition itself, + // which diverges, that we are about to lint on. This gives suboptimal diagnostics + // and so we stop here and allow the block of the `if`-expression to be linted instead. + !span.is_compiler_desugaring(CompilerDesugaringKind::IfTemporary) { self.diverges.set(Diverges::WarnedAlways); debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); - self.tcx().lint_hir( - lint::builtin::UNREACHABLE_CODE, - id, span, - &format!("unreachable {}", kind)); + let msg = format!("unreachable {}", kind); + self.tcx().lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, &msg); } } @@ -2075,7 +2186,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } /// Resolves type variables in `ty` if possible. Unlike the infcx - /// version (resolve_type_vars_if_possible), this version will + /// version (resolve_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort /// to get more type information. fn resolve_type_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { @@ -2088,7 +2199,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // If `ty` is a type variable, see whether we already know what it is. - ty = self.resolve_type_vars_if_possible(&ty); + ty = self.resolve_vars_if_possible(&ty); if !ty.has_infer_types() { debug!("resolve_type_vars_with_obligations: ty={:?}", ty); return ty; @@ -2099,43 +2210,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // indirect dependencies that don't seem worth tracking // precisely. self.select_obligations_where_possible(false); - ty = self.resolve_type_vars_if_possible(&ty); + ty = self.resolve_vars_if_possible(&ty); debug!("resolve_type_vars_with_obligations: ty={:?}", ty); ty } - fn record_deferred_call_resolution(&self, - closure_def_id: DefId, - r: DeferredCallResolution<'gcx, 'tcx>) { + fn record_deferred_call_resolution( + &self, + closure_def_id: DefId, + r: DeferredCallResolution<'tcx>, + ) { let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); deferred_call_resolutions.entry(closure_def_id).or_default().push(r); } - fn remove_deferred_call_resolutions(&self, - closure_def_id: DefId) - -> Vec> - { + fn remove_deferred_call_resolutions( + &self, + closure_def_id: DefId, + ) -> Vec> { let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![]) } pub fn tag(&self) -> String { - let self_ptr: *const FnCtxt<'_, '_, '_> = self; - format!("{:?}", self_ptr) + format!("{:p}", self) } pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> { self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| span_bug!(span, "no type for local variable {}", - self.tcx.hir().hir_to_string(nid)) + self.tcx.hir().node_to_string(nid)) ) } #[inline] pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) { debug!("write_ty({:?}, {:?}) in fcx {}", - id, self.resolve_type_vars_if_possible(&ty), self.tag()); + id, self.resolve_vars_if_possible(&ty), self.tag()); self.tables.borrow_mut().node_types_mut().insert(id, ty); if ty.references_error() { @@ -2148,15 +2260,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tables.borrow_mut().field_indices_mut().insert(hir_id, index); } + fn write_resolution(&self, hir_id: hir::HirId, r: Result<(DefKind, DefId), ErrorReported>) { + self.tables.borrow_mut().type_dependent_defs_mut().insert(hir_id, r); + } + pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method); - self.tables - .borrow_mut() - .type_dependent_defs_mut() - .insert(hir_id, Def::Method(method.def_id)); - + self.write_resolution(hir_id, Ok((DefKind::Method, method.def_id))); self.write_substs(hir_id, method.substs); // When the method is confirmed, the `method.substs` includes @@ -2339,6 +2451,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &self, parent_id: hir::HirId, value: &T, + value_span: Span, ) -> T { let parent_def_id = self.tcx.hir().local_def_id_from_hir_id(parent_id); debug!("instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})", @@ -2351,6 +2464,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.body_id, self.param_env, value, + value_span, ) ); @@ -2436,6 +2550,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } + /// Returns the `DefId` of the constant parameter that the provided expression is a path to. + pub fn const_param_def_id(&self, hir_c: &hir::AnonConst) -> Option { + AstConv::const_param_def_id(self, &self.tcx.hir().body(hir_c.body).value) + } + + pub fn to_const(&self, ast_c: &hir::AnonConst, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> { + AstConv::ast_const_to_const(self, ast_c, ty) + } + // If the type given by the user has free regions, save it for later, since // NLL would like to enforce those. Also pass in types that involve // projections, since those can resolve to `'static` bounds (modulo #54940, @@ -2455,9 +2578,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some(&t) => t, None if self.is_tainted_by_errors() => self.tcx.types.err, None => { - let node_id = self.tcx.hir().hir_to_node_id(id); bug!("no type for node {}: {} in fcx {}", - node_id, self.tcx.hir().node_to_string(node_id), + id, self.tcx.hir().node_to_string(id), self.tag()); } } @@ -2537,9 +2659,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn resolve_generator_interiors(&self, def_id: DefId) { let mut generators = self.deferred_generator_interiors.borrow_mut(); - for (body_id, interior) in generators.drain(..) { + for (body_id, interior, kind) in generators.drain(..) { self.select_obligations_where_possible(false); - generator_interior::resolve_interior(self, def_id, body_id, interior); + generator_interior::resolve_interior(self, def_id, body_id, interior, kind); } } @@ -2562,7 +2684,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), Neither => return false, }; - debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); + debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback); self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback); true } @@ -2596,14 +2718,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ret_ty.builtin_deref(true).unwrap() } - fn lookup_indexing(&self, - expr: &hir::Expr, - base_expr: &'gcx hir::Expr, - base_ty: Ty<'tcx>, - idx_ty: Ty<'tcx>, - needs: Needs) - -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> - { + fn lookup_indexing( + &self, + expr: &hir::Expr, + base_expr: &'tcx hir::Expr, + base_ty: Ty<'tcx>, + idx_ty: Ty<'tcx>, + needs: Needs, + ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { // FIXME(#18741) -- this is almost but not quite the same as the // autoderef that normal method probing does. They could likely be // consolidated. @@ -2622,14 +2744,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// supports builtin indexing or overloaded indexing. /// This loop implements one step in that search; the autoderef loop /// is implemented by `lookup_indexing`. - fn try_index_step(&self, - expr: &hir::Expr, - base_expr: &hir::Expr, - autoderef: &Autoderef<'a, 'gcx, 'tcx>, - needs: Needs, - index_ty: Ty<'tcx>) - -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> - { + fn try_index_step( + &self, + expr: &hir::Expr, + base_expr: &hir::Expr, + autoderef: &Autoderef<'a, 'tcx>, + needs: Needs, + index_ty: Ty<'tcx>, + ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { let adjusted_ty = autoderef.unambiguous_final_ty(self); debug!("try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ index_ty={:?})", @@ -2652,7 +2774,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If some lookup succeeds, write callee into table and extract index/element // type from the method signature. // If some lookup succeeded, install method in table - let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span)); + let input_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::AutoDeref, + span: base_expr.span, + }); let method = self.try_overloaded_place_op( expr.span, self_ty, &[input_ty], needs, PlaceOp::Index); @@ -2682,7 +2807,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if unsize { adjustments.push(Adjustment { - kind: Adjust::Unsize, + kind: Adjust::Pointer(PointerCast::Unsize), target: method.sig.inputs()[0] }); } @@ -2701,16 +2826,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn resolve_place_op(&self, op: PlaceOp, is_mut: bool) -> (Option, ast::Ident) { let (tr, name) = match (op, is_mut) { - (PlaceOp::Deref, false) => - (self.tcx.lang_items().deref_trait(), "deref"), - (PlaceOp::Deref, true) => - (self.tcx.lang_items().deref_mut_trait(), "deref_mut"), - (PlaceOp::Index, false) => - (self.tcx.lang_items().index_trait(), "index"), - (PlaceOp::Index, true) => - (self.tcx.lang_items().index_mut_trait(), "index_mut"), + (PlaceOp::Deref, false) => (self.tcx.lang_items().deref_trait(), sym::deref), + (PlaceOp::Deref, true) => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut), + (PlaceOp::Index, false) => (self.tcx.lang_items().index_trait(), sym::index), + (PlaceOp::Index, true) => (self.tcx.lang_items().index_mut_trait(), sym::index_mut), }; - (tr, ast::Ident::from_str(name)) + (tr, ast::Ident::with_empty_ctxt(name)) } fn try_overloaded_place_op(&self, @@ -2748,14 +2869,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { method } - fn check_method_argument_types(&self, - sp: Span, - expr_sp: Span, - method: Result, ()>, - args_no_rcvr: &'gcx [hir::Expr], - tuple_arguments: TupleArgumentsFlag, - expected: Expectation<'tcx>) - -> Ty<'tcx> { + fn check_method_argument_types( + &self, + sp: Span, + expr_sp: Span, + method: Result, ()>, + args_no_rcvr: &'tcx [hir::Expr], + tuple_arguments: TupleArgumentsFlag, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { let has_error = match method { Ok(method) => { method.substs.references_error() || method.sig.references_error() @@ -2811,10 +2933,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn obligations_for_self_ty<'b>(&'b self, self_ty: ty::TyVid) - -> impl Iterator, traits::PredicateObligation<'tcx>)> - + Captures<'gcx> + 'b - { + fn obligations_for_self_ty<'b>( + &'b self, + self_ty: ty::TyVid, + ) -> impl Iterator, traits::PredicateObligation<'tcx>)> + + Captures<'tcx> + + 'b { // FIXME: consider using `sub_root_var` here so we // can see through subtyping. let ty_var_root = self.root_var(self_ty); @@ -2857,15 +2981,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Generic function that factors out common logic from function calls, /// method calls and overloaded operators. - fn check_argument_types(&self, - sp: Span, - expr_sp: Span, - fn_inputs: &[Ty<'tcx>], - mut expected_arg_tys: &[Ty<'tcx>], - args: &'gcx [hir::Expr], - c_variadic: bool, - tuple_arguments: TupleArgumentsFlag, - def_span: Option) { + fn check_argument_types( + &self, + sp: Span, + expr_sp: Span, + fn_inputs: &[Ty<'tcx>], + expected_arg_tys: &[Ty<'tcx>], + args: &'tcx [hir::Expr], + c_variadic: bool, + tuple_arguments: TupleArgumentsFlag, + def_span: Option, + ) { let tcx = self.tcx; // Grab the argument types, supplying fresh type variables @@ -2917,29 +3043,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.emit(); }; + let mut expected_arg_tys = expected_arg_tys.to_vec(); + let formal_tys = if tuple_arguments == TupleArguments { let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); match tuple_type.sty { ty::Tuple(arg_types) if arg_types.len() != args.len() => { param_count_error(arg_types.len(), args.len(), "E0057", false, false); - expected_arg_tys = &[]; + expected_arg_tys = vec![]; self.err_args(args.len()) } ty::Tuple(arg_types) => { expected_arg_tys = match expected_arg_tys.get(0) { Some(&ty) => match ty.sty { - ty::Tuple(ref tys) => &tys, - _ => &[] + ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(), + _ => vec![], }, - None => &[] + None => vec![], }; - arg_types.to_vec() + arg_types.iter().map(|k| k.expect_ty()).collect() } _ => { span_err!(tcx.sess, sp, E0059, "cannot use call notation; the first type parameter \ for the function trait is neither a tuple nor unit"); - expected_arg_tys = &[]; + expected_arg_tys = vec![]; self.err_args(args.len()) } } @@ -2950,33 +3078,34 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_inputs.to_vec() } else { param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false); - expected_arg_tys = &[]; + expected_arg_tys = vec![]; self.err_args(supplied_arg_count) } } else { // is the missing argument of type `()`? let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 { - self.resolve_type_vars_if_possible(&expected_arg_tys[0]).is_unit() + self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit() } else if fn_inputs.len() == 1 && supplied_arg_count == 0 { - self.resolve_type_vars_if_possible(&fn_inputs[0]).is_unit() + self.resolve_vars_if_possible(&fn_inputs[0]).is_unit() } else { false }; param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit); - expected_arg_tys = &[]; + expected_arg_tys = vec![]; self.err_args(supplied_arg_count) }; + + debug!("check_argument_types: formal_tys={:?}", + formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::>()); + // If there is no expectation, expect formal_tys. let expected_arg_tys = if !expected_arg_tys.is_empty() { expected_arg_tys } else { - &formal_tys + formal_tys.clone() }; - debug!("check_argument_types: formal_tys={:?}", - formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::>()); - // Check the arguments. // We do this in a pretty awful way: first we type-check any arguments // that are not closures, then we type-check the closures. This is so @@ -3068,7 +3197,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } ty::FnDef(..) => { let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); - let ptr_ty = self.resolve_type_vars_if_possible(&ptr_ty); + let ptr_ty = self.resolve_vars_if_possible(&ptr_ty); variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); } _ => {} @@ -3083,7 +3212,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // AST fragment checking fn check_lit(&self, - lit: &ast::Lit, + lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> { @@ -3092,7 +3221,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match lit.node { ast::LitKind::Str(..) => tcx.mk_static_str(), ast::LitKind::ByteStr(ref v) => { - tcx.mk_imm_ref(tcx.types.re_static, + tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64)) } ast::LitKind::Byte(_) => tcx.types.u8, @@ -3109,8 +3238,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => None } }); - opt_ty.unwrap_or_else( - || tcx.mk_int_var(self.next_int_var_id())) + opt_ty.unwrap_or_else(|| self.next_int_var()) } ast::LitKind::Float(_, t) => tcx.mk_mach_float(t), ast::LitKind::FloatUnsuffixed(_) => { @@ -3120,99 +3248,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => None } }); - opt_ty.unwrap_or_else( - || tcx.mk_float_var(self.next_float_var_id())) + opt_ty.unwrap_or_else(|| self.next_float_var()) } ast::LitKind::Bool(_) => tcx.types.bool, ast::LitKind::Err(_) => tcx.types.err, } } - fn check_expr_eq_type(&self, - expr: &'gcx hir::Expr, - expected: Ty<'tcx>) { - let ty = self.check_expr_with_hint(expr, expected); - self.demand_eqtype(expr.span, expected, ty); - } - - pub fn check_expr_has_type_or_error(&self, - expr: &'gcx hir::Expr, - expected: Ty<'tcx>) -> Ty<'tcx> { - self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected)) - } - - fn check_expr_meets_expectation_or_error(&self, - expr: &'gcx hir::Expr, - expected: Expectation<'tcx>) -> Ty<'tcx> { - let expected_ty = expected.to_option(&self).unwrap_or(self.tcx.types.bool); - let mut ty = self.check_expr_with_expectation(expr, expected); - - // While we don't allow *arbitrary* coercions here, we *do* allow - // coercions from ! to `expected`. - if ty.is_never() { - assert!(!self.tables.borrow().adjustments().contains_key(expr.hir_id), - "expression with never type wound up being adjusted"); - let adj_ty = self.next_diverging_ty_var( - TypeVariableOrigin::AdjustmentType(expr.span)); - self.apply_adjustments(expr, vec![Adjustment { - kind: Adjust::NeverToAny, - target: adj_ty - }]); - ty = adj_ty; - } - - if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { - // Add help to type error if this is an `if` condition with an assignment. - if let (ExpectIfCondition, &ExprKind::Assign(ref lhs, ref rhs)) - = (expected, &expr.node) - { - let msg = "try comparing for equality"; - if let (Ok(left), Ok(right)) = ( - self.tcx.sess.source_map().span_to_snippet(lhs.span), - self.tcx.sess.source_map().span_to_snippet(rhs.span)) - { - err.span_suggestion( - expr.span, - msg, - format!("{} == {}", left, right), - Applicability::MaybeIncorrect); - } else { - err.help(msg); - } - } - err.emit(); - } - ty - } - - fn check_expr_coercable_to_type(&self, - expr: &'gcx hir::Expr, - expected: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.check_expr_with_hint(expr, expected); - // checks don't need two phase - self.demand_coerce(expr, ty, expected, AllowTwoPhase::No) - } - - fn check_expr_with_hint(&self, - expr: &'gcx hir::Expr, - expected: Ty<'tcx>) -> Ty<'tcx> { - self.check_expr_with_expectation(expr, ExpectHasType(expected)) - } - - fn check_expr_with_expectation(&self, - expr: &'gcx hir::Expr, - expected: Expectation<'tcx>) -> Ty<'tcx> { - self.check_expr_with_expectation_and_needs(expr, expected, Needs::None) - } - - fn check_expr(&self, expr: &'gcx hir::Expr) -> Ty<'tcx> { - self.check_expr_with_expectation(expr, NoExpectation) - } - - fn check_expr_with_needs(&self, expr: &'gcx hir::Expr, needs: Needs) -> Ty<'tcx> { - self.check_expr_with_expectation_and_needs(expr, NoExpectation, needs) - } - // Determine the `Self` type, using fresh variables for all variables // declared on the impl declaration e.g., `impl for Vec<(A,B)>` // would return `($0, $1)` where `$0` and `$1` are freshly instantiated type @@ -3243,7 +3285,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some(ret) => ret, None => return Vec::new() }; - let expect_args = self.fudge_regions_if_ok(&RegionVariableOrigin::Coercion(call_span), || { + let expect_args = self.fudge_inference_if_ok(|| { // Attempt to apply a subtyping relationship between the formal // return type (likely containing type variables if the function // is polymorphic) and the expected return type. @@ -3273,7 +3315,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Record all the argument types, with the substitutions // produced from the above subtyping unification. Ok(formal_args.iter().map(|ty| { - self.resolve_type_vars_if_possible(ty) + self.resolve_vars_if_possible(ty) }).collect()) }).unwrap_or_default(); debug!("expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})", @@ -3282,1483 +3324,118 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expect_args } - // Checks a method call. - fn check_method_call(&self, - expr: &'gcx hir::Expr, - segment: &hir::PathSegment, - span: Span, - args: &'gcx [hir::Expr], - expected: Expectation<'tcx>, - needs: Needs) -> Ty<'tcx> { - let rcvr = &args[0]; - let rcvr_t = self.check_expr_with_needs(&rcvr, needs); - // no need to check for bot/err -- callee does that - let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t); - - let method = match self.lookup_method(rcvr_t, - segment, - span, - expr, - rcvr) { - Ok(method) => { - self.write_method_call(expr.hir_id, method); - Ok(method) + pub fn check_struct_path(&self, + qpath: &QPath, + hir_id: hir::HirId) + -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> { + let path_span = match *qpath { + QPath::Resolved(_, ref path) => path.span, + QPath::TypeRelative(ref qself, _) => qself.span + }; + let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); + let variant = match def { + Res::Err => { + self.set_tainted_by_errors(); + return None; } - Err(error) => { - if segment.ident.name != keywords::Invalid.name() { - self.report_method_error(span, - rcvr_t, - segment.ident, - SelfSource::MethodCall(rcvr), - error, - Some(args)); + Res::Def(DefKind::Variant, _) => { + match ty.sty { + ty::Adt(adt, substs) => { + Some((adt.variant_of_res(def), adt.did, substs)) + } + _ => bug!("unexpected type: {:?}", ty) } - Err(()) } - }; - - // Call the generic checker. - self.check_method_argument_types(span, - expr.span, - method, - &args[1..], - DontTupleArguments, - expected) - } - - fn check_return_expr(&self, return_expr: &'gcx hir::Expr) { - let ret_coercion = - self.ret_coercion - .as_ref() - .unwrap_or_else(|| span_bug!(return_expr.span, - "check_return_expr called outside fn body")); - - let ret_ty = ret_coercion.borrow().expected_ty(); - let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty.clone()); - ret_coercion.borrow_mut() - .coerce(self, - &self.cause(return_expr.span, - ObligationCauseCode::ReturnType(return_expr.hir_id)), - return_expr, - return_expr_ty); - } - - // A generic function for checking the 'then' and 'else' clauses in an 'if' - // or 'if-else' expression. - fn check_then_else(&self, - cond_expr: &'gcx hir::Expr, - then_expr: &'gcx hir::Expr, - opt_else_expr: Option<&'gcx hir::Expr>, - sp: Span, - expected: Expectation<'tcx>) -> Ty<'tcx> { - let cond_ty = self.check_expr_meets_expectation_or_error(cond_expr, ExpectIfCondition); - let cond_diverges = self.diverges.get(); - self.diverges.set(Diverges::Maybe); - - let expected = expected.adjust_for_branches(self); - let then_ty = self.check_expr_with_expectation(then_expr, expected); - let then_diverges = self.diverges.get(); - self.diverges.set(Diverges::Maybe); - - // We've already taken the expected type's preferences - // into account when typing the `then` branch. To figure - // out the initial shot at a LUB, we thus only consider - // `expected` if it represents a *hard* constraint - // (`only_has_type`); otherwise, we just go with a - // fresh type variable. - let coerce_to_ty = expected.coercion_target_type(self, sp); - let mut coerce: DynamicCoerceMany<'_, '_> = CoerceMany::new(coerce_to_ty); - - coerce.coerce(self, &self.misc(sp), then_expr, then_ty); - - if let Some(else_expr) = opt_else_expr { - let else_ty = self.check_expr_with_expectation(else_expr, expected); - let else_diverges = self.diverges.get(); - - let mut outer_sp = if self.tcx.sess.source_map().is_multiline(sp) { - // The `if`/`else` isn't in one line in the output, include some context to make it - // clear it is an if/else expression: - // ``` - // LL | let x = if true { - // | _____________- - // LL || 10i32 - // || ----- expected because of this - // LL || } else { - // LL || 10u32 - // || ^^^^^ expected i32, found u32 - // LL || }; - // ||_____- if and else have incompatible types - // ``` - Some(sp) - } else { - // The entire expression is in one line, only point at the arms - // ``` - // LL | let x = if true { 10i32 } else { 10u32 }; - // | ----- ^^^^^ expected i32, found u32 - // | | - // | expected because of this - // ``` - None - }; - let mut remove_semicolon = None; - let error_sp = if let ExprKind::Block(block, _) = &else_expr.node { - if let Some(expr) = &block.expr { - expr.span - } else if let Some(stmt) = block.stmts.last() { - // possibly incorrect trailing `;` in the else arm - remove_semicolon = self.could_remove_semicolon(block, then_ty); - stmt.span - } else { // empty block, point at its entirety - // Avoid overlapping spans that aren't as readable: - // ``` - // 2 | let x = if true { - // | _____________- - // 3 | | 3 - // | | - expected because of this - // 4 | | } else { - // | |____________^ - // 5 | || - // 6 | || }; - // | || ^ - // | ||_____| - // | |______if and else have incompatible types - // | expected integer, found () - // ``` - // by not pointing at the entire expression: - // ``` - // 2 | let x = if true { - // | ------- if and else have incompatible types - // 3 | 3 - // | - expected because of this - // 4 | } else { - // | ____________^ - // 5 | | - // 6 | | }; - // | |_____^ expected integer, found () - // ``` - if outer_sp.is_some() { - outer_sp = Some(self.tcx.sess.source_map().def_span(sp)); + Res::Def(DefKind::Struct, _) + | Res::Def(DefKind::Union, _) + | Res::Def(DefKind::TyAlias, _) + | Res::Def(DefKind::AssocTy, _) + | Res::SelfTy(..) => { + match ty.sty { + ty::Adt(adt, substs) if !adt.is_enum() => { + Some((adt.non_enum_variant(), adt.did, substs)) } - else_expr.span - } - } else { // shouldn't happen unless the parser has done something weird - else_expr.span - }; - let then_sp = if let ExprKind::Block(block, _) = &then_expr.node { - if let Some(expr) = &block.expr { - expr.span - } else if let Some(stmt) = block.stmts.last() { - // possibly incorrect trailing `;` in the else arm - remove_semicolon = remove_semicolon.or( - self.could_remove_semicolon(block, else_ty)); - stmt.span - } else { // empty block, point at its entirety - outer_sp = None; // same as in `error_sp`, cleanup output - then_expr.span + _ => None, } - } else { // shouldn't happen unless the parser has done something weird - then_expr.span - }; - - let if_cause = self.cause(error_sp, ObligationCauseCode::IfExpression { - then: then_sp, - outer: outer_sp, - semicolon: remove_semicolon, - }); - - coerce.coerce(self, &if_cause, else_expr, else_ty); + } + _ => bug!("unexpected definition: {:?}", def) + }; - // We won't diverge unless both branches do (or the condition does). - self.diverges.set(cond_diverges | then_diverges & else_diverges); - } else { - let else_cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse); - coerce.coerce_forced_unit(self, &else_cause, &mut |_| (), true); + if let Some((variant, did, substs)) = variant { + debug!("check_struct_path: did={:?} substs={:?}", did, substs); + self.write_user_type_annotation_from_substs(hir_id, did, substs, None); - // If the condition is false we can't diverge. - self.diverges.set(cond_diverges); - } + // Check bounds on type arguments used in the path. + let bounds = self.instantiate_bounds(path_span, did, substs); + let cause = traits::ObligationCause::new(path_span, self.body_id, + traits::ItemObligation(did)); + self.add_obligations_for_parameters(cause, &bounds); - let result_ty = coerce.complete(self); - if cond_ty.references_error() { - self.tcx.types.err + Some((variant, ty)) } else { - result_ty + struct_span_err!(self.tcx.sess, path_span, E0071, + "expected struct, variant or union type, found {}", + ty.sort_string(self.tcx)) + .span_label(path_span, "not a struct") + .emit(); + None } } - // Check field access expressions - fn check_field(&self, - expr: &'gcx hir::Expr, - needs: Needs, - base: &'gcx hir::Expr, - field: ast::Ident) -> Ty<'tcx> { - let expr_t = self.check_expr_with_needs(base, needs); - let expr_t = self.structurally_resolved_type(base.span, - expr_t); - let mut private_candidate = None; - let mut autoderef = self.autoderef(expr.span, expr_t); - while let Some((base_t, _)) = autoderef.next() { - match base_t.sty { - ty::Adt(base_def, substs) if !base_def.is_enum() => { - debug!("struct named {:?}", base_t); - let (ident, def_scope) = - self.tcx.adjust_ident(field, base_def.did, self.body_id); - let fields = &base_def.non_enum_variant().fields; - if let Some(index) = fields.iter().position(|f| f.ident.modern() == ident) { - let field = &fields[index]; - let field_ty = self.field_ty(expr.span, field, substs); - // Save the index of all fields regardless of their visibility in case - // of error recovery. - self.write_field_index(expr.hir_id, index); - if field.vis.is_accessible_from(def_scope, self.tcx) { - let adjustments = autoderef.adjust_steps(self, needs); - self.apply_adjustments(base, adjustments); - autoderef.finalize(self); - - self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span); - return field_ty; - } - private_candidate = Some((base_def.did, field_ty)); - } - } - ty::Tuple(ref tys) => { - let fstr = field.as_str(); - if let Ok(index) = fstr.parse::() { - if fstr == index.to_string() { - if let Some(field_ty) = tys.get(index) { - let adjustments = autoderef.adjust_steps(self, needs); - self.apply_adjustments(base, adjustments); - autoderef.finalize(self); - - self.write_field_index(expr.hir_id, index); - return field_ty; - } - } - } - } - _ => {} - } - } - autoderef.unambiguous_final_ty(self); - - if let Some((did, field_ty)) = private_candidate { - let struct_path = self.tcx().item_path_str(did); - let mut err = struct_span_err!(self.tcx().sess, expr.span, E0616, - "field `{}` of struct `{}` is private", - field, struct_path); - // Also check if an accessible method exists, which is often what is meant. - if self.method_exists(field, expr_t, expr.hir_id, false) - && !self.expr_in_place(expr.hir_id) - { - self.suggest_method_call( - &mut err, - &format!("a method `{}` also exists, call it with parentheses", field), - field, - expr_t, - expr.hir_id, - ); + // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. + // The newly resolved definition is written into `type_dependent_defs`. + fn finish_resolving_struct_path(&self, + qpath: &QPath, + path_span: Span, + hir_id: hir::HirId) + -> (Res, Ty<'tcx>) + { + match *qpath { + QPath::Resolved(ref maybe_qself, ref path) => { + let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); + let ty = AstConv::res_to_ty(self, self_ty, path, true); + (path.res, ty) } - err.emit(); - field_ty - } else if field.name == keywords::Invalid.name() { - self.tcx().types.err - } else if self.method_exists(field, expr_t, expr.hir_id, true) { - let mut err = type_error_struct!(self.tcx().sess, field.span, expr_t, E0615, - "attempted to take value of method `{}` on type `{}`", - field, expr_t); - - if !self.expr_in_place(expr.hir_id) { - self.suggest_method_call( - &mut err, - "use parentheses to call the method", - field, - expr_t, - expr.hir_id + QPath::TypeRelative(ref qself, ref segment) => { + let ty = self.to_ty(qself); + + let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.node { + path.res + } else { + Res::Err + }; + let result = AstConv::associated_path_to_ty( + self, + hir_id, + path_span, + ty, + res, + segment, + true, ); - } else { - err.help("methods are immutable and cannot be assigned to"); - } + let ty = result.map(|(ty, _, _)| ty).unwrap_or(self.tcx().types.err); + let result = result.map(|(_, kind, def_id)| (kind, def_id)); - err.emit(); - self.tcx().types.err - } else { - if !expr_t.is_primitive_ty() { - let mut err = self.no_such_field_err(field.span, field, expr_t); - - match expr_t.sty { - ty::Adt(def, _) if !def.is_enum() => { - if let Some(suggested_field_name) = - Self::suggest_field_name(def.non_enum_variant(), - &field.as_str(), vec![]) { - err.span_suggestion( - field.span, - "a field with a similar name exists", - suggested_field_name.to_string(), - Applicability::MaybeIncorrect, - ); - } else { - err.span_label(field.span, "unknown field"); - let struct_variant_def = def.non_enum_variant(); - let field_names = self.available_field_names(struct_variant_def); - if !field_names.is_empty() { - err.note(&format!("available fields are: {}", - self.name_series_display(field_names))); - } - }; - } - ty::Array(_, len) => { - if let (Some(len), Ok(user_index)) = ( - len.assert_usize(self.tcx), - field.as_str().parse::() - ) { - let base = self.tcx.sess.source_map() - .span_to_snippet(base.span) - .unwrap_or_else(|_| - self.tcx.hir().hir_to_pretty_string(base.hir_id)); - let help = "instead of using tuple indexing, use array indexing"; - let suggestion = format!("{}[{}]", base, field); - let applicability = if len < user_index { - Applicability::MachineApplicable - } else { - Applicability::MaybeIncorrect - }; - err.span_suggestion( - expr.span, help, suggestion, applicability - ); - } - } - ty::RawPtr(..) => { - let base = self.tcx.sess.source_map() - .span_to_snippet(base.span) - .unwrap_or_else(|_| self.tcx.hir().hir_to_pretty_string(base.hir_id)); - let msg = format!("`{}` is a raw pointer; try dereferencing it", base); - let suggestion = format!("(*{}).{}", base, field); - err.span_suggestion( - expr.span, - &msg, - suggestion, - Applicability::MaybeIncorrect, - ); - } - _ => {} - } - err - } else { - type_error_struct!(self.tcx().sess, field.span, expr_t, E0610, - "`{}` is a primitive type and therefore doesn't have fields", - expr_t) - }.emit(); - self.tcx().types.err - } - } + // Write back the new resolution. + self.write_resolution(hir_id, result); - // Return an hint about the closest match in field names - fn suggest_field_name(variant: &'tcx ty::VariantDef, - field: &str, - skip: Vec) - -> Option { - let names = variant.fields.iter().filter_map(|field| { - // ignore already set fields and private fields from non-local crates - if skip.iter().any(|x| *x == field.ident.as_str()) || - (variant.did.krate != LOCAL_CRATE && field.vis != Visibility::Public) { - None - } else { - Some(&field.ident.name) + (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty) } - }); - - find_best_match_for_name(names, field, None) - } - - fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec { - variant.fields.iter().filter(|field| { - let def_scope = self.tcx.adjust_ident(field.ident, variant.did, self.body_id).1; - field.vis.is_accessible_from(def_scope, self.tcx) - }) - .map(|field| field.ident.name) - .collect() + } } - fn name_series_display(&self, names: Vec) -> String { - // dynamic limit, to never omit just one field - let limit = if names.len() == 6 { 6 } else { 5 }; - let mut display = names.iter().take(limit) - .map(|n| format!("`{}`", n)).collect::>().join(", "); - if names.len() > limit { - display = format!("{} ... and {} others", display, names.len() - limit); - } - display - } - - fn no_such_field_err(&self, span: Span, field: T, expr_t: &ty::TyS<'_>) - -> DiagnosticBuilder<'_> { - type_error_struct!(self.tcx().sess, span, expr_t, E0609, - "no field `{}` on type `{}`", - field, expr_t) - } - - fn report_unknown_field(&self, - ty: Ty<'tcx>, - variant: &'tcx ty::VariantDef, - field: &hir::Field, - skip_fields: &[hir::Field], - kind_name: &str) { - let mut err = self.type_error_struct_with_diag( - field.ident.span, - |actual| match ty.sty { - ty::Adt(adt, ..) if adt.is_enum() => { - struct_span_err!(self.tcx.sess, field.ident.span, E0559, - "{} `{}::{}` has no field named `{}`", - kind_name, actual, variant.ident, field.ident) - } - _ => { - struct_span_err!(self.tcx.sess, field.ident.span, E0560, - "{} `{}` has no field named `{}`", - kind_name, actual, field.ident) - } - }, - ty); - // prevent all specified fields from being suggested - let skip_fields = skip_fields.iter().map(|ref x| x.ident.as_str()); - if let Some(field_name) = Self::suggest_field_name(variant, - &field.ident.as_str(), - skip_fields.collect()) { - err.span_suggestion( - field.ident.span, - "a field with a similar name exists", - field_name.to_string(), - Applicability::MaybeIncorrect, - ); - } else { - match ty.sty { - ty::Adt(adt, ..) => { - if adt.is_enum() { - err.span_label(field.ident.span, - format!("`{}::{}` does not have this field", - ty, variant.ident)); - } else { - err.span_label(field.ident.span, - format!("`{}` does not have this field", ty)); - } - let available_field_names = self.available_field_names(variant); - if !available_field_names.is_empty() { - err.note(&format!("available fields are: {}", - self.name_series_display(available_field_names))); - } - } - _ => bug!("non-ADT passed to report_unknown_field") - } - }; - err.emit(); - } - - fn check_expr_struct_fields(&self, - adt_ty: Ty<'tcx>, - expected: Expectation<'tcx>, - expr_id: hir::HirId, - span: Span, - variant: &'tcx ty::VariantDef, - ast_fields: &'gcx [hir::Field], - check_completeness: bool) -> bool { - let tcx = self.tcx; - - let adt_ty_hint = - self.expected_inputs_for_expected_output(span, expected, adt_ty, &[adt_ty]) - .get(0).cloned().unwrap_or(adt_ty); - // re-link the regions that EIfEO can erase. - self.demand_eqtype(span, adt_ty_hint, adt_ty); - - let (substs, adt_kind, kind_name) = match &adt_ty.sty { - &ty::Adt(adt, substs) => { - (substs, adt.adt_kind(), adt.variant_descr()) - } - _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields") - }; - - let mut remaining_fields = variant.fields.iter().enumerate().map(|(i, field)| - (field.ident.modern(), (i, field)) - ).collect::>(); - - let mut seen_fields = FxHashMap::default(); - - let mut error_happened = false; - - // Type-check each field. - for field in ast_fields { - let ident = tcx.adjust_ident(field.ident, variant.did, self.body_id).0; - let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) { - seen_fields.insert(ident, field.span); - self.write_field_index(field.hir_id, i); - - // We don't look at stability attributes on - // struct-like enums (yet...), but it's definitely not - // a bug to have constructed one. - if adt_kind != AdtKind::Enum { - tcx.check_stability(v_field.did, Some(expr_id), field.span); - } - - self.field_ty(field.span, v_field, substs) - } else { - error_happened = true; - if let Some(prev_span) = seen_fields.get(&ident) { - let mut err = struct_span_err!(self.tcx.sess, - field.ident.span, - E0062, - "field `{}` specified more than once", - ident); - - err.span_label(field.ident.span, "used more than once"); - err.span_label(*prev_span, format!("first use of `{}`", ident)); - - err.emit(); - } else { - self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name); - } - - tcx.types.err - }; - - // Make sure to give a type to the field even if there's - // an error, so we can continue type-checking. - self.check_expr_coercable_to_type(&field.expr, field_type); - } - - // Make sure the programmer specified correct number of fields. - if kind_name == "union" { - if ast_fields.len() != 1 { - tcx.sess.span_err(span, "union expressions should have exactly one field"); - } - } else if check_completeness && !error_happened && !remaining_fields.is_empty() { - let len = remaining_fields.len(); - - let mut displayable_field_names = remaining_fields - .keys() - .map(|ident| ident.as_str()) - .collect::>(); - - displayable_field_names.sort(); - - let truncated_fields_error = if len <= 3 { - String::new() - } else { - format!(" and {} other field{}", (len - 3), if len - 3 == 1 {""} else {"s"}) - }; - - let remaining_fields_names = displayable_field_names.iter().take(3) - .map(|n| format!("`{}`", n)) - .collect::>() - .join(", "); - - struct_span_err!(tcx.sess, span, E0063, - "missing field{} {}{} in initializer of `{}`", - if remaining_fields.len() == 1 { "" } else { "s" }, - remaining_fields_names, - truncated_fields_error, - adt_ty) - .span_label(span, format!("missing {}{}", - remaining_fields_names, - truncated_fields_error)) - .emit(); - } - error_happened - } - - fn check_struct_fields_on_error(&self, - fields: &'gcx [hir::Field], - base_expr: &'gcx Option>) { - for field in fields { - self.check_expr(&field.expr); - } - if let Some(ref base) = *base_expr { - self.check_expr(&base); - } - } - - pub fn check_struct_path(&self, - qpath: &QPath, - hir_id: hir::HirId) - -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> { - let path_span = match *qpath { - QPath::Resolved(_, ref path) => path.span, - QPath::TypeRelative(ref qself, _) => qself.span - }; - let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); - let variant = match def { - Def::Err => { - self.set_tainted_by_errors(); - return None; - } - Def::Variant(..) => { - match ty.sty { - ty::Adt(adt, substs) => { - Some((adt.variant_of_def(def), adt.did, substs)) - } - _ => bug!("unexpected type: {:?}", ty.sty) - } - } - Def::Struct(..) | Def::Union(..) | Def::TyAlias(..) | - Def::AssociatedTy(..) | Def::SelfTy(..) => { - match ty.sty { - ty::Adt(adt, substs) if !adt.is_enum() => { - Some((adt.non_enum_variant(), adt.did, substs)) - } - _ => None, - } - } - _ => bug!("unexpected definition: {:?}", def) - }; - - if let Some((variant, did, substs)) = variant { - debug!("check_struct_path: did={:?} substs={:?}", did, substs); - self.write_user_type_annotation_from_substs(hir_id, did, substs, None); - - // Check bounds on type arguments used in the path. - let bounds = self.instantiate_bounds(path_span, did, substs); - let cause = traits::ObligationCause::new(path_span, self.body_id, - traits::ItemObligation(did)); - self.add_obligations_for_parameters(cause, &bounds); - - Some((variant, ty)) - } else { - struct_span_err!(self.tcx.sess, path_span, E0071, - "expected struct, variant or union type, found {}", - ty.sort_string(self.tcx)) - .span_label(path_span, "not a struct") - .emit(); - None - } - } - - fn check_expr_struct(&self, - expr: &hir::Expr, - expected: Expectation<'tcx>, - qpath: &QPath, - fields: &'gcx [hir::Field], - base_expr: &'gcx Option>) -> Ty<'tcx> - { - // Find the relevant variant - let (variant, adt_ty) = - if let Some(variant_ty) = self.check_struct_path(qpath, expr.hir_id) { - variant_ty - } else { - self.check_struct_fields_on_error(fields, base_expr); - return self.tcx.types.err; - }; - - let path_span = match *qpath { - QPath::Resolved(_, ref path) => path.span, - QPath::TypeRelative(ref qself, _) => qself.span - }; - - // Prohibit struct expressions when non-exhaustive flag is set. - let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type"); - if !adt.did.is_local() && variant.is_field_list_non_exhaustive() { - span_err!(self.tcx.sess, expr.span, E0639, - "cannot create non-exhaustive {} using struct expression", - adt.variant_descr()); - } - - let error_happened = self.check_expr_struct_fields(adt_ty, expected, expr.hir_id, path_span, - variant, fields, base_expr.is_none()); - if let &Some(ref base_expr) = base_expr { - // If check_expr_struct_fields hit an error, do not attempt to populate - // the fields with the base_expr. This could cause us to hit errors later - // when certain fields are assumed to exist that in fact do not. - if !error_happened { - self.check_expr_has_type_or_error(base_expr, adt_ty); - match adt_ty.sty { - ty::Adt(adt, substs) if adt.is_struct() => { - let fru_field_types = adt.non_enum_variant().fields.iter().map(|f| { - self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs)) - }).collect(); - - self.tables - .borrow_mut() - .fru_field_types_mut() - .insert(expr.hir_id, fru_field_types); - } - _ => { - span_err!(self.tcx.sess, base_expr.span, E0436, - "functional record update syntax requires a struct"); - } - } - } - } - self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized); - adt_ty - } - - - /// Invariant: - /// If an expression has any sub-expressions that result in a type error, - /// inspecting that expression's type with `ty.references_error()` will return - /// true. Likewise, if an expression is known to diverge, inspecting its - /// type with `ty::type_is_bot` will return true (n.b.: since Rust is - /// strict, _|_ can appear in the type of an expression that does not, - /// itself, diverge: for example, fn() -> _|_.) - /// Note that inspecting a type's structure *directly* may expose the fact - /// that there are actually multiple representations for `Error`, so avoid - /// that when err needs to be handled differently. - fn check_expr_with_expectation_and_needs(&self, - expr: &'gcx hir::Expr, - expected: Expectation<'tcx>, - needs: Needs) -> Ty<'tcx> { - debug!(">> type-checking: expr={:?} expected={:?}", - expr, expected); - - // Warn for expressions after diverging siblings. - self.warn_if_unreachable(expr.hir_id, expr.span, "expression"); - - // Hide the outer diverging and has_errors flags. - let old_diverges = self.diverges.get(); - let old_has_errors = self.has_errors.get(); - self.diverges.set(Diverges::Maybe); - self.has_errors.set(false); - - let ty = self.check_expr_kind(expr, expected, needs); - - // Warn for non-block expressions with diverging children. - match expr.node { - ExprKind::Block(..) | - ExprKind::Loop(..) | ExprKind::While(..) | - ExprKind::If(..) | ExprKind::Match(..) => {} - - _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression") - } - - // Any expression that produces a value of type `!` must have diverged - if ty.is_never() { - self.diverges.set(self.diverges.get() | Diverges::Always); - } - - // Record the type, which applies it effects. - // We need to do this after the warning above, so that - // we don't warn for the diverging expression itself. - self.write_ty(expr.hir_id, ty); - - // Combine the diverging and has_error flags. - self.diverges.set(self.diverges.get() | old_diverges); - self.has_errors.set(self.has_errors.get() | old_has_errors); - - debug!("type of {} is...", self.tcx.hir().hir_to_string(expr.hir_id)); - debug!("... {:?}, expected is {:?}", ty, expected); - - ty - } - - fn check_expr_kind( - &self, - expr: &'gcx hir::Expr, - expected: Expectation<'tcx>, - needs: Needs - ) -> Ty<'tcx> { - debug!( - "check_expr_kind(expr={:?}, expected={:?}, needs={:?})", - expr, - expected, - needs, - ); - - let tcx = self.tcx; - let id = expr.hir_id; - match expr.node { - ExprKind::Box(ref subexpr) => { - let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| { - match ty.sty { - ty::Adt(def, _) if def.is_box() - => Expectation::rvalue_hint(self, ty.boxed_ty()), - _ => NoExpectation - } - }); - let referent_ty = self.check_expr_with_expectation(subexpr, expected_inner); - tcx.mk_box(referent_ty) - } - - ExprKind::Lit(ref lit) => { - self.check_lit(&lit, expected) - } - ExprKind::Binary(op, ref lhs, ref rhs) => { - self.check_binop(expr, op, lhs, rhs) - } - ExprKind::AssignOp(op, ref lhs, ref rhs) => { - self.check_binop_assign(expr, op, lhs, rhs) - } - ExprKind::Unary(unop, ref oprnd) => { - let expected_inner = match unop { - hir::UnNot | hir::UnNeg => { - expected - } - hir::UnDeref => { - NoExpectation - } - }; - let needs = match unop { - hir::UnDeref => needs, - _ => Needs::None - }; - let mut oprnd_t = self.check_expr_with_expectation_and_needs(&oprnd, - expected_inner, - needs); - - if !oprnd_t.references_error() { - oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); - match unop { - hir::UnDeref => { - if let Some(mt) = oprnd_t.builtin_deref(true) { - oprnd_t = mt.ty; - } else if let Some(ok) = self.try_overloaded_deref( - expr.span, oprnd_t, needs) { - let method = self.register_infer_ok_obligations(ok); - if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].sty { - let mutbl = match mutbl { - hir::MutImmutable => AutoBorrowMutability::Immutable, - hir::MutMutable => AutoBorrowMutability::Mutable { - // (It shouldn't actually matter for unary ops whether - // we enable two-phase borrows or not, since a unary - // op has no additional operands.) - allow_two_phase_borrow: AllowTwoPhase::No, - } - }; - self.apply_adjustments(oprnd, vec![Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), - target: method.sig.inputs()[0] - }]); - } - oprnd_t = self.make_overloaded_place_return_type(method).ty; - self.write_method_call(expr.hir_id, method); - } else { - type_error_struct!(tcx.sess, expr.span, oprnd_t, E0614, - "type `{}` cannot be dereferenced", - oprnd_t).emit(); - oprnd_t = tcx.types.err; - } - } - hir::UnNot => { - let result = self.check_user_unop(expr, oprnd_t, unop); - // If it's builtin, we can reuse the type, this helps inference. - if !(oprnd_t.is_integral() || oprnd_t.sty == ty::Bool) { - oprnd_t = result; - } - } - hir::UnNeg => { - let result = self.check_user_unop(expr, oprnd_t, unop); - // If it's builtin, we can reuse the type, this helps inference. - if !(oprnd_t.is_integral() || oprnd_t.is_fp()) { - oprnd_t = result; - } - } - } - } - oprnd_t - } - ExprKind::AddrOf(mutbl, ref oprnd) => { - let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| { - match ty.sty { - ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { - if oprnd.is_place_expr() { - // Places may legitimately have unsized types. - // For example, dereferences of a fat pointer and - // the last field of a struct can be unsized. - ExpectHasType(ty) - } else { - Expectation::rvalue_hint(self, ty) - } - } - _ => NoExpectation - } - }); - let needs = Needs::maybe_mut_place(mutbl); - let ty = self.check_expr_with_expectation_and_needs(&oprnd, hint, needs); - - let tm = ty::TypeAndMut { ty: ty, mutbl: mutbl }; - if tm.ty.references_error() { - tcx.types.err - } else { - // Note: at this point, we cannot say what the best lifetime - // is to use for resulting pointer. We want to use the - // shortest lifetime possible so as to avoid spurious borrowck - // errors. Moreover, the longest lifetime will depend on the - // precise details of the value whose address is being taken - // (and how long it is valid), which we don't know yet until type - // inference is complete. - // - // Therefore, here we simply generate a region variable. The - // region inferencer will then select the ultimate value. - // Finally, borrowck is charged with guaranteeing that the - // value whose address was taken can actually be made to live - // as long as it needs to live. - let region = self.next_region_var(infer::AddrOfRegion(expr.span)); - tcx.mk_ref(region, tm) - } - } - ExprKind::Path(ref qpath) => { - let (def, opt_ty, segs) = self.resolve_ty_and_def_ufcs(qpath, expr.hir_id, - expr.span); - let ty = match def { - Def::Err => { - self.set_tainted_by_errors(); - tcx.types.err - } - Def::VariantCtor(_, CtorKind::Fictive) => { - report_unexpected_variant_def(tcx, &def, expr.span, qpath); - tcx.types.err - } - _ => self.instantiate_value_path(segs, opt_ty, def, expr.span, id).0, - }; - - if let ty::FnDef(..) = ty.sty { - let fn_sig = ty.fn_sig(tcx); - if !tcx.features().unsized_locals { - // We want to remove some Sized bounds from std functions, - // but don't want to expose the removal to stable Rust. - // i.e., we don't want to allow - // - // ```rust - // drop as fn(str); - // ``` - // - // to work in stable even if the Sized bound on `drop` is relaxed. - for i in 0..fn_sig.inputs().skip_binder().len() { - // We just want to check sizedness, so instead of introducing - // placeholder lifetimes with probing, we just replace higher lifetimes - // with fresh vars. - let input = self.replace_bound_vars_with_fresh_vars( - expr.span, - infer::LateBoundRegionConversionTime::FnCall, - &fn_sig.input(i)).0; - self.require_type_is_sized_deferred(input, expr.span, - traits::SizedArgumentType); - } - } - // Here we want to prevent struct constructors from returning unsized types. - // There were two cases this happened: fn pointer coercion in stable - // and usual function call in presense of unsized_locals. - // Also, as we just want to check sizedness, instead of introducing - // placeholder lifetimes with probing, we just replace higher lifetimes - // with fresh vars. - let output = self.replace_bound_vars_with_fresh_vars( - expr.span, - infer::LateBoundRegionConversionTime::FnCall, - &fn_sig.output()).0; - self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); - } - - // We always require that the type provided as the value for - // a type parameter outlives the moment of instantiation. - let substs = self.tables.borrow().node_substs(expr.hir_id); - self.add_wf_bounds(substs, expr); - - ty - } - ExprKind::InlineAsm(_, ref outputs, ref inputs) => { - for expr in outputs.iter().chain(inputs.iter()) { - self.check_expr(expr); - } - tcx.mk_unit() - } - ExprKind::Break(destination, ref expr_opt) => { - if let Ok(target_id) = destination.target_id { - let target_id = tcx.hir().node_to_hir_id(target_id); - let (e_ty, cause); - if let Some(ref e) = *expr_opt { - // If this is a break with a value, we need to type-check - // the expression. Get an expected type from the loop context. - let opt_coerce_to = { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - enclosing_breakables.find_breakable(target_id) - .coerce - .as_ref() - .map(|coerce| coerce.expected_ty()) - }; - - // If the loop context is not a `loop { }`, then break with - // a value is illegal, and `opt_coerce_to` will be `None`. - // Just set expectation to error in that case. - let coerce_to = opt_coerce_to.unwrap_or(tcx.types.err); - - // Recurse without `enclosing_breakables` borrowed. - e_ty = self.check_expr_with_hint(e, coerce_to); - cause = self.misc(e.span); - } else { - // Otherwise, this is a break *without* a value. That's - // always legal, and is equivalent to `break ()`. - e_ty = tcx.mk_unit(); - cause = self.misc(expr.span); - } - - // Now that we have type-checked `expr_opt`, borrow - // the `enclosing_loops` field and let's coerce the - // type of `expr_opt` into what is expected. - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - let ctxt = enclosing_breakables.find_breakable(target_id); - if let Some(ref mut coerce) = ctxt.coerce { - if let Some(ref e) = *expr_opt { - coerce.coerce(self, &cause, e, e_ty); - } else { - assert!(e_ty.is_unit()); - coerce.coerce_forced_unit(self, &cause, &mut |_| (), true); - } - } else { - // If `ctxt.coerce` is `None`, we can just ignore - // the type of the expresison. This is because - // either this was a break *without* a value, in - // which case it is always a legal type (`()`), or - // else an error would have been flagged by the - // `loops` pass for using break with an expression - // where you are not supposed to. - assert!(expr_opt.is_none() || self.tcx.sess.err_count() > 0); - } - - ctxt.may_break = true; - - // the type of a `break` is always `!`, since it diverges - tcx.types.never - } else { - // Otherwise, we failed to find the enclosing loop; - // this can only happen if the `break` was not - // inside a loop at all, which is caught by the - // loop-checking pass. - if self.tcx.sess.err_count() == 0 { - self.tcx.sess.delay_span_bug(expr.span, - "break was outside loop, but no error was emitted"); - } - - // We still need to assign a type to the inner expression to - // prevent the ICE in #43162. - if let Some(ref e) = *expr_opt { - self.check_expr_with_hint(e, tcx.types.err); - - // ... except when we try to 'break rust;'. - // ICE this expression in particular (see #43162). - if let ExprKind::Path(QPath::Resolved(_, ref path)) = e.node { - if path.segments.len() == 1 && path.segments[0].ident.name == "rust" { - fatally_break_rust(self.tcx.sess); - } - } - } - // There was an error; make type-check fail. - tcx.types.err - } - - } - ExprKind::Continue(destination) => { - if destination.target_id.is_ok() { - tcx.types.never - } else { - // There was an error; make type-check fail. - tcx.types.err - } - } - ExprKind::Ret(ref expr_opt) => { - if self.ret_coercion.is_none() { - struct_span_err!(self.tcx.sess, expr.span, E0572, - "return statement outside of function body").emit(); - } else if let Some(ref e) = *expr_opt { - if self.ret_coercion_span.borrow().is_none() { - *self.ret_coercion_span.borrow_mut() = Some(e.span); - } - self.check_return_expr(e); - } else { - let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); - if self.ret_coercion_span.borrow().is_none() { - *self.ret_coercion_span.borrow_mut() = Some(expr.span); - } - let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); - if let Some((fn_decl, _)) = self.get_fn_decl(expr.hir_id) { - coercion.coerce_forced_unit( - self, - &cause, - &mut |db| { - db.span_label( - fn_decl.output.span(), - format!( - "expected `{}` because of this return type", - fn_decl.output, - ), - ); - }, - true, - ); - } else { - coercion.coerce_forced_unit(self, &cause, &mut |_| (), true); - } - } - tcx.types.never - } - ExprKind::Assign(ref lhs, ref rhs) => { - let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); - - let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty); - - match expected { - ExpectIfCondition => { - self.tcx.sess.delay_span_bug(lhs.span, "invalid lhs expression in if;\ - expected error elsehwere"); - } - _ => { - // Only check this if not in an `if` condition, as the - // mistyped comparison help is more appropriate. - if !lhs.is_place_expr() { - struct_span_err!(self.tcx.sess, expr.span, E0070, - "invalid left-hand side expression") - .span_label(expr.span, "left-hand of expression not valid") - .emit(); - } - } - } - - self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); - - if lhs_ty.references_error() || rhs_ty.references_error() { - tcx.types.err - } else { - tcx.mk_unit() - } - } - ExprKind::If(ref cond, ref then_expr, ref opt_else_expr) => { - self.check_then_else(&cond, then_expr, opt_else_expr.as_ref().map(|e| &**e), - expr.span, expected) - } - ExprKind::While(ref cond, ref body, _) => { - let ctxt = BreakableCtxt { - // cannot use break with a value from a while loop - coerce: None, - may_break: false, // Will get updated if/when we find a `break`. - }; - - let (ctxt, ()) = self.with_breakable_ctxt(expr.hir_id, ctxt, || { - self.check_expr_has_type_or_error(&cond, tcx.types.bool); - let cond_diverging = self.diverges.get(); - self.check_block_no_value(&body); - - // We may never reach the body so it diverging means nothing. - self.diverges.set(cond_diverging); - }); - - if ctxt.may_break { - // No way to know whether it's diverging because - // of a `break` or an outer `break` or `return`. - self.diverges.set(Diverges::Maybe); - } - - self.tcx.mk_unit() - } - ExprKind::Loop(ref body, _, source) => { - let coerce = match source { - // you can only use break with a value from a normal `loop { }` - hir::LoopSource::Loop => { - let coerce_to = expected.coercion_target_type(self, body.span); - Some(CoerceMany::new(coerce_to)) - } - - hir::LoopSource::WhileLet | - hir::LoopSource::ForLoop => { - None - } - }; - - let ctxt = BreakableCtxt { - coerce, - may_break: false, // Will get updated if/when we find a `break`. - }; - - let (ctxt, ()) = self.with_breakable_ctxt(expr.hir_id, ctxt, || { - self.check_block_no_value(&body); - }); - - if ctxt.may_break { - // No way to know whether it's diverging because - // of a `break` or an outer `break` or `return`. - self.diverges.set(Diverges::Maybe); - } - - // If we permit break with a value, then result type is - // the LUB of the breaks (possibly ! if none); else, it - // is nil. This makes sense because infinite loops - // (which would have type !) are only possible iff we - // permit break with a value [1]. - if ctxt.coerce.is_none() && !ctxt.may_break { - // [1] - self.tcx.sess.delay_span_bug(body.span, "no coercion, but loop may not break"); - } - ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| self.tcx.mk_unit()) - } - ExprKind::Match(ref discrim, ref arms, match_src) => { - self.check_match(expr, &discrim, arms, expected, match_src) - } - ExprKind::Closure(capture, ref decl, body_id, _, gen) => { - self.check_expr_closure(expr, capture, &decl, body_id, gen, expected) - } - ExprKind::Block(ref body, _) => { - self.check_block_with_expected(&body, expected) - } - ExprKind::Call(ref callee, ref args) => { - self.check_call(expr, &callee, args, expected) - } - ExprKind::MethodCall(ref segment, span, ref args) => { - self.check_method_call(expr, segment, span, args, expected, needs) - } - ExprKind::Cast(ref e, ref t) => { - // Find the type of `e`. Supply hints based on the type we are casting to, - // if appropriate. - let t_cast = self.to_ty_saving_user_provided_ty(t); - let t_cast = self.resolve_type_vars_if_possible(&t_cast); - let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); - let t_cast = self.resolve_type_vars_if_possible(&t_cast); - - // Eagerly check for some obvious errors. - if t_expr.references_error() || t_cast.references_error() { - tcx.types.err - } else { - // Defer other checks until we're done type checking. - let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { - Ok(cast_check) => { - deferred_cast_checks.push(cast_check); - t_cast - } - Err(ErrorReported) => { - tcx.types.err - } - } - } - } - ExprKind::Type(ref e, ref t) => { - let ty = self.to_ty_saving_user_provided_ty(&t); - self.check_expr_eq_type(&e, ty); - ty - } - ExprKind::Array(ref args) => { - let uty = expected.to_option(self).and_then(|uty| { - match uty.sty { - ty::Array(ty, _) | ty::Slice(ty) => Some(ty), - _ => None - } - }); - - let element_ty = if !args.is_empty() { - let coerce_to = uty.unwrap_or_else( - || self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span))); - let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args); - assert_eq!(self.diverges.get(), Diverges::Maybe); - for e in args { - let e_ty = self.check_expr_with_hint(e, coerce_to); - let cause = self.misc(e.span); - coerce.coerce(self, &cause, e, e_ty); - } - coerce.complete(self) - } else { - self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span)) - }; - tcx.mk_array(element_ty, args.len() as u64) - } - ExprKind::Repeat(ref element, ref count) => { - let count_def_id = tcx.hir().local_def_id_from_hir_id(count.hir_id); - let param_env = ty::ParamEnv::empty(); - let substs = InternalSubsts::identity_for_item(tcx.global_tcx(), count_def_id); - let instance = ty::Instance::resolve( - tcx.global_tcx(), - param_env, - count_def_id, - substs, - ).unwrap(); - let global_id = GlobalId { - instance, - promoted: None - }; - let count = tcx.const_eval(param_env.and(global_id)); - - let uty = match expected { - ExpectHasType(uty) => { - match uty.sty { - ty::Array(ty, _) | ty::Slice(ty) => Some(ty), - _ => None - } - } - _ => None - }; - - let (element_ty, t) = match uty { - Some(uty) => { - self.check_expr_coercable_to_type(&element, uty); - (uty, uty) - } - None => { - let ty = self.next_ty_var(TypeVariableOrigin::MiscVariable(element.span)); - let element_ty = self.check_expr_has_type_or_error(&element, ty); - (element_ty, ty) - } - }; - - if let Ok(count) = count { - let zero_or_one = count.assert_usize(tcx).map_or(false, |count| count <= 1); - if !zero_or_one { - // For [foo, ..n] where n > 1, `foo` must have - // Copy type: - let lang_item = self.tcx.require_lang_item(lang_items::CopyTraitLangItem); - self.require_type_meets(t, expr.span, traits::RepeatVec, lang_item); - } - } - - if element_ty.references_error() { - tcx.types.err - } else if let Ok(count) = count { - tcx.mk_ty(ty::Array(t, tcx.mk_lazy_const(ty::LazyConst::Evaluated(count)))) - } else { - tcx.types.err - } - } - ExprKind::Tup(ref elts) => { - let flds = expected.only_has_type(self).and_then(|ty| { - let ty = self.resolve_type_vars_with_obligations(ty); - match ty.sty { - ty::Tuple(ref flds) => Some(&flds[..]), - _ => None - } - }); - - let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| { - let t = match flds { - Some(ref fs) if i < fs.len() => { - let ety = fs[i]; - self.check_expr_coercable_to_type(&e, ety); - ety - } - _ => { - self.check_expr_with_expectation(&e, NoExpectation) - } - }; - t - }); - let tuple = tcx.mk_tup(elt_ts_iter); - if tuple.references_error() { - tcx.types.err - } else { - self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized); - tuple - } - } - ExprKind::Struct(ref qpath, ref fields, ref base_expr) => { - self.check_expr_struct(expr, expected, qpath, fields, base_expr) - } - ExprKind::Field(ref base, field) => { - self.check_field(expr, needs, &base, field) - } - ExprKind::Index(ref base, ref idx) => { - let base_t = self.check_expr_with_needs(&base, needs); - let idx_t = self.check_expr(&idx); - - if base_t.references_error() { - base_t - } else if idx_t.references_error() { - idx_t - } else { - let base_t = self.structurally_resolved_type(base.span, base_t); - match self.lookup_indexing(expr, base, base_t, idx_t, needs) { - Some((index_ty, element_ty)) => { - // two-phase not needed because index_ty is never mutable - self.demand_coerce(idx, idx_t, index_ty, AllowTwoPhase::No); - element_ty - } - None => { - let mut err = - type_error_struct!(tcx.sess, expr.span, base_t, E0608, - "cannot index into a value of type `{}`", - base_t); - // Try to give some advice about indexing tuples. - if let ty::Tuple(..) = base_t.sty { - let mut needs_note = true; - // If the index is an integer, we can show the actual - // fixed expression: - if let ExprKind::Lit(ref lit) = idx.node { - if let ast::LitKind::Int(i, - ast::LitIntType::Unsuffixed) = lit.node { - let snip = tcx.sess.source_map().span_to_snippet(base.span); - if let Ok(snip) = snip { - err.span_suggestion( - expr.span, - "to access tuple elements, use", - format!("{}.{}", snip, i), - Applicability::MachineApplicable, - ); - needs_note = false; - } - } - } - if needs_note { - err.help("to access tuple elements, use tuple indexing \ - syntax (e.g., `tuple.0`)"); - } - } - err.emit(); - self.tcx.types.err - } - } - } - } - ExprKind::Yield(ref value) => { - match self.yield_ty { - Some(ty) => { - self.check_expr_coercable_to_type(&value, ty); - } - None => { - struct_span_err!(self.tcx.sess, expr.span, E0627, - "yield statement outside of generator literal").emit(); - } - } - tcx.mk_unit() - } - hir::ExprKind::Err => { - tcx.types.err - } - } - } - - // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. - // The newly resolved definition is written into `type_dependent_defs`. - fn finish_resolving_struct_path(&self, - qpath: &QPath, - path_span: Span, - hir_id: hir::HirId) - -> (Def, Ty<'tcx>) - { - match *qpath { - QPath::Resolved(ref maybe_qself, ref path) => { - let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); - let ty = AstConv::def_to_ty(self, self_ty, path, true); - (path.def, ty) - } - QPath::TypeRelative(ref qself, ref segment) => { - let ty = self.to_ty(qself); - - let def = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.node { - path.def - } else { - Def::Err - }; - let (ty, def) = AstConv::associated_path_to_ty(self, hir_id, path_span, - ty, def, segment, true); - - // Write back the new resolution. - self.tables.borrow_mut().type_dependent_defs_mut().insert(hir_id, def); - - (def, ty) - } - } - } - - /// Resolves associated value path into a base type and associated constant or method - /// definition. The newly resolved definition is written into `type_dependent_defs`. - pub fn resolve_ty_and_def_ufcs<'b>(&self, + /// Resolves an associated value path into a base type and associated constant, or method + /// resolution. The newly resolved definition is written into `type_dependent_defs`. + pub fn resolve_ty_and_res_ufcs<'b>(&self, qpath: &'b QPath, hir_id: hir::HirId, span: Span) - -> (Def, Option>, &'b [hir::PathSegment]) + -> (Res, Option>, &'b [hir::PathSegment]) { - debug!("resolve_ty_and_def_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span); + debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span); let (ty, qself, item_segment) = match *qpath { QPath::Resolved(ref opt_qself, ref path) => { - return (path.def, + return (path.res, opt_qself.as_ref().map(|qself| self.to_ty(qself)), &path.segments[..]); } @@ -4766,40 +3443,46 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (self.to_ty(qself), qself, segment) } }; - if let Some(cached_def) = self.tables.borrow().type_dependent_defs().get(hir_id) { + if let Some(&cached_result) = self.tables.borrow().type_dependent_defs().get(hir_id) { // Return directly on cache hit. This is useful to avoid doubly reporting // errors with default match binding modes. See #44614. - return (*cached_def, Some(ty), slice::from_ref(&**item_segment)) + let def = cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)) + .unwrap_or(Res::Err); + return (def, Some(ty), slice::from_ref(&**item_segment)); } let item_name = item_segment.ident; - let def = match self.resolve_ufcs(span, item_name, ty, hir_id) { - Ok(def) => def, - Err(error) => { - let def = match error { - method::MethodError::PrivateMatch(def, _) => def, - _ => Def::Err, - }; - if item_name.name != keywords::Invalid.name() { - self.report_method_error(span, - ty, - item_name, - SelfSource::QPath(qself), - error, - None); - } - def + let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| { + let result = match error { + method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), + _ => Err(ErrorReported), + }; + if item_name.name != kw::Invalid { + self.report_method_error( + span, + ty, + item_name, + SelfSource::QPath(qself), + error, + None, + ); } - }; + result + }); // Write back the new resolution. - self.tables.borrow_mut().type_dependent_defs_mut().insert(hir_id, def); - (def, Some(ty), slice::from_ref(&**item_segment)) + self.write_resolution(hir_id, result); + ( + result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), + Some(ty), + slice::from_ref(&**item_segment), + ) } - pub fn check_decl_initializer(&self, - local: &'gcx hir::Local, - init: &'gcx hir::Expr) -> Ty<'tcx> - { + pub fn check_decl_initializer( + &self, + local: &'tcx hir::Local, + init: &'tcx hir::Expr, + ) -> Ty<'tcx> { // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed // for #42640 (default match binding modes). // @@ -4824,7 +3507,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn check_decl_local(&self, local: &'gcx hir::Local) { + pub fn check_decl_local(&self, local: &'tcx hir::Local) { let t = self.local_ty(local.span, local.hir_id).decl_ty; self.write_ty(local.hir_id, t); @@ -4847,7 +3530,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) { + pub fn check_stmt(&self, stmt: &'tcx hir::Stmt) { // Don't do all the complex logic below for `DeclItem`. match stmt.node { hir::StmtKind::Item(..) => return, @@ -4882,7 +3565,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.has_errors.set(self.has_errors.get() | old_has_errors); } - pub fn check_block_no_value(&self, blk: &'gcx hir::Block) { + pub fn check_block_no_value(&self, blk: &'tcx hir::Block) { let unit = self.tcx.mk_unit(); let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); @@ -4893,9 +3576,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn check_block_with_expected(&self, - blk: &'gcx hir::Block, - expected: Expectation<'tcx>) -> Ty<'tcx> { + fn check_block_with_expected( + &self, + blk: &'tcx hir::Block, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { let prev = { let mut fcx_ps = self.ps.borrow_mut(); let unsafety_state = fcx_ps.recurse(blk); @@ -4975,10 +3660,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // that highlight errors inline. let mut sp = blk.span; let mut fn_span = None; - let blk_node_id = self.tcx.hir().hir_to_node_id(blk.hir_id); - if let Some((decl, ident)) = self.get_parent_fn_decl(blk_node_id) { + if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { let ret_sp = decl.output.span(); - if let Some(block_sp) = self.parent_item_span(blk_node_id) { + if let Some(block_sp) = self.parent_item_span(blk.hir_id) { // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the // output would otherwise be incorrect and even misleading. Make sure // the span we're aiming at correspond to a `fn` body. @@ -5018,8 +3702,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } - fn parent_item_span(&self, id: ast::NodeId) -> Option { - let node = self.tcx.hir().get(self.tcx.hir().get_parent(id)); + fn parent_item_span(&self, id: hir::HirId) -> Option { + let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id)); match node { Node::Item(&hir::Item { node: hir::ItemKind::Fn(_, _, _, body_id), .. @@ -5037,44 +3721,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None } - /// Given a function block's `NodeId`, returns its `FnDecl` if it exists, or `None` otherwise. - fn get_parent_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, ast::Ident)> { - let parent = self.tcx.hir().get(self.tcx.hir().get_parent(blk_id)); + /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise. + fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl, ast::Ident)> { + let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id)); self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident)) } /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise. - fn get_node_fn_decl(&self, node: Node<'_>) -> Option<(hir::FnDecl, ast::Ident, bool)> { + fn get_node_fn_decl(&self, node: Node<'tcx>) -> Option<(&'tcx hir::FnDecl, ast::Ident, bool)> { match node { Node::Item(&hir::Item { ident, node: hir::ItemKind::Fn(ref decl, ..), .. - }) => decl.clone().and_then(|decl| { + }) => { // This is less than ideal, it will not suggest a return type span on any // method called `main`, regardless of whether it is actually the entry point, // but it will still present it as the reason for the expected type. - Some((decl, ident, ident.name != Symbol::intern("main"))) - }), + Some((decl, ident, ident.name != sym::main)) + } Node::TraitItem(&hir::TraitItem { ident, node: hir::TraitItemKind::Method(hir::MethodSig { ref decl, .. }, ..), .. - }) => decl.clone().and_then(|decl| Some((decl, ident, true))), + }) => Some((decl, ident, true)), Node::ImplItem(&hir::ImplItem { ident, node: hir::ImplItemKind::Method(hir::MethodSig { ref decl, .. }, ..), .. - }) => decl.clone().and_then(|decl| Some((decl, ident, false))), + }) => Some((decl, ident, false)), _ => None, } } /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a /// suggestion can be made, `None` otherwise. - pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(hir::FnDecl, bool)> { + pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl, bool)> { // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or // `while` before reaching it, as block tail returns are not available in them. self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| { - let parent = self.tcx.hir().get_by_hir_id(blk_id); + let parent = self.tcx.hir().get(blk_id); self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main)) }) } @@ -5087,7 +3771,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn suggest_mismatched_types_on_tail( &self, err: &mut DiagnosticBuilder<'tcx>, - expression: &'gcx hir::Expr, + expression: &'tcx hir::Expr, expected: Ty<'tcx>, found: Ty<'tcx>, cause_span: Span, @@ -5118,6 +3802,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Applicability::MachineApplicable, ); } else if !self.check_for_cast(err, expr, found, expected) { + let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field( + expr.hir_id, + expr.span, + ); let methods = self.get_conversion_methods(expr.span, expected, found); if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { let mut suggestions = iter::repeat(&expr_text).zip(methods.iter()) @@ -5127,14 +3815,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None // do not suggest code that is already there (#53348) } else { let method_call_list = [".to_vec()", ".to_string()"]; - if receiver.ends_with(".clone()") + let sugg = if receiver.ends_with(".clone()") && method_call_list.contains(&method_call.as_str()) { let max_len = receiver.rfind(".").unwrap(); - Some(format!("{}{}", &receiver[..max_len], method_call)) - } - else { - Some(format!("{}{}", receiver, method_call)) - } + format!("{}{}", &receiver[..max_len], method_call) + } else { + format!("{}{}", receiver, method_call) + }; + Some(if is_struct_pat_shorthand_field { + format!("{}: {}", receiver, sugg) + } else { + sugg + }) } }).peekable(); if suggestions.peek().is_some() { @@ -5160,18 +3852,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// This routine checks if the return expression in a block would make sense on its own as a /// statement and the return type has been left as default or has been specified as `()`. If so, /// it suggests adding a semicolon. - fn suggest_missing_semicolon(&self, - err: &mut DiagnosticBuilder<'tcx>, - expression: &'gcx hir::Expr, - expected: Ty<'tcx>, - cause_span: Span) { + fn suggest_missing_semicolon( + &self, + err: &mut DiagnosticBuilder<'tcx>, + expression: &'tcx hir::Expr, + expected: Ty<'tcx>, + cause_span: Span, + ) { if expected.is_unit() { // `BlockTailExpression` only relevant if the tail expr would be // useful on its own. match expression.node { ExprKind::Call(..) | ExprKind::MethodCall(..) | - ExprKind::If(..) | ExprKind::While(..) | ExprKind::Loop(..) | ExprKind::Match(..) | @@ -5235,8 +3928,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.node); let sp = ty.span; let ty = AstConv::ast_ty_to_ty(self, ty); - debug!("suggest_missing_return_type: return type sty {:?}", ty.sty); - debug!("suggest_missing_return_type: expected type sty {:?}", ty.sty); + debug!("suggest_missing_return_type: return type {:?}", ty); + debug!("suggest_missing_return_type: expected type {:?}", ty); if ty.sty == expected.sty { err.span_label(sp, format!("expected `{}` because of return type", expected)); @@ -5247,6 +3940,72 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + /// A possible error is to forget to add `.await` when using futures: + /// + /// ``` + /// #![feature(async_await)] + /// + /// async fn make_u32() -> u32 { + /// 22 + /// } + /// + /// fn take_u32(x: u32) {} + /// + /// async fn foo() { + /// let x = make_u32(); + /// take_u32(x); + /// } + /// ``` + /// + /// This routine checks if the found type `T` implements `Future` where `U` is the + /// expected type. If this is the case, and we are inside of an async body, it suggests adding + /// `.await` to the tail of the expression. + fn suggest_missing_await( + &self, + err: &mut DiagnosticBuilder<'tcx>, + expr: &hir::Expr, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the + // body isn't `async`. + let item_id = self.tcx().hir().get_parent_node(self.body_id); + if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) { + let body = self.tcx().hir().body(body_id); + if let Some(hir::GeneratorKind::Async) = body.generator_kind { + let sp = expr.span; + // Check for `Future` implementations by constructing a predicate to + // prove: `::Output == U` + let future_trait = self.tcx.lang_items().future_trait().unwrap(); + let item_def_id = self.tcx.associated_items(future_trait).next().unwrap().def_id; + let predicate = ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate { + // `::Output` + projection_ty: ty::ProjectionTy { + // `T` + substs: self.tcx.mk_substs_trait( + found, + self.fresh_substs_for_item(sp, item_def_id) + ), + // `Future::Output` + item_def_id, + }, + ty: expected, + })); + let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); + if self.infcx.predicate_may_hold(&obligation) { + if let Ok(code) = self.sess().source_map().span_to_snippet(sp) { + err.span_suggestion( + sp, + "consider using `.await` here", + format!("{}.await", code), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + /// A common error is to add an extra semicolon: /// /// ``` @@ -5260,7 +4019,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// with `expected_ty`. If so, it suggests removing the semicolon. fn consider_hint_about_removing_semicolon( &self, - blk: &'gcx hir::Block, + blk: &'tcx hir::Block, expected_ty: Ty<'tcx>, err: &mut DiagnosticBuilder<'_>, ) { @@ -5274,17 +4033,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn could_remove_semicolon( - &self, - blk: &'gcx hir::Block, - expected_ty: Ty<'tcx>, - ) -> Option { + fn could_remove_semicolon(&self, blk: &'tcx hir::Block, expected_ty: Ty<'tcx>) -> Option { // Be helpful when the user wrote `{... expr;}` and // taking the `;` off is enough to fix the error. - let last_stmt = match blk.stmts.last() { - Some(s) => s, - None => return None, - }; + let last_stmt = blk.stmts.last()?; let last_expr = match last_stmt.node { hir::StmtKind::Semi(ref e) => e, _ => return None, @@ -5302,26 +4054,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn instantiate_value_path(&self, segments: &[hir::PathSegment], self_ty: Option>, - def: Def, + res: Res, span: Span, hir_id: hir::HirId) - -> (Ty<'tcx>, Def) { + -> (Ty<'tcx>, Res) { debug!( - "instantiate_value_path(segments={:?}, self_ty={:?}, def={:?}, hir_id={})", + "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})", segments, self_ty, - def, + res, hir_id, ); let tcx = self.tcx; - let path_segs = AstConv::def_ids_for_path_segments(self, segments, self_ty, def); + let path_segs = match res { + Res::Local(_) | Res::SelfCtor(_) => vec![], + Res::Def(kind, def_id) => + AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id), + _ => bug!("instantiate_value_path on {:?}", res), + }; let mut user_self_ty = None; let mut is_alias_variant_ctor = false; - match def { - Def::VariantCtor(_, _) => { + match res { + Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => { if let Some(self_ty) = self_ty { let adt_def = self_ty.ty_adt_def().unwrap(); user_self_ty = Some(UserSelfTy { @@ -5331,10 +4088,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { is_alias_variant_ctor = true; } } - Def::Method(def_id) | - Def::AssociatedConst(def_id) => { + Res::Def(DefKind::Method, def_id) + | Res::Def(DefKind::AssocConst, def_id) => { let container = tcx.associated_item(def_id).container; - debug!("instantiate_value_path: def={:?} container={:?}", def, container); + debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container); match container { ty::TraitContainer(trait_did) => { callee::check_legal_trait_for_method_call(tcx, span, trait_did) @@ -5372,22 +4129,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None } })); + + if let Res::Local(hid) = res { + let ty = self.local_ty(span, hid).decl_ty; + let ty = self.normalize_associated_types_in(span, &ty); + self.write_ty(hir_id, ty); + return (ty, res); + } + if generics_has_err { // Don't try to infer type parameters when prohibited generic arguments were given. user_self_ty = None; } - match def { - Def::Local(nid) | Def::Upvar(nid, ..) => { - let hid = self.tcx.hir().node_to_hir_id(nid); - let ty = self.local_ty(span, hid).decl_ty; - let ty = self.normalize_associated_types_in(span, &ty); - self.write_ty(hir_id, ty); - return (ty, def); - } - _ => {} - } - // Now we have to compare the types that the user *actually* // provided against the types that were *expected*. If the user // did not provide any types, then we want to substitute inference @@ -5420,54 +4174,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.generics_of(*def_id).has_self }).unwrap_or(false); - let mut new_def = def; - let (def_id, ty) = match def { - Def::SelfCtor(impl_def_id) => { - let ty = self.impl_self_ty(span, impl_def_id).ty; - let adt_def = ty.ty_adt_def(); - - match adt_def { - Some(adt_def) if adt_def.has_ctor() => { - let variant = adt_def.non_enum_variant(); - new_def = Def::StructCtor(variant.did, variant.ctor_kind); - (variant.did, tcx.type_of(variant.did)) - } - _ => { - let mut err = tcx.sess.struct_span_err(span, - "the `Self` constructor can only be used with tuple or unit structs"); - if let Some(adt_def) = adt_def { - match adt_def.adt_kind() { - AdtKind::Enum => { - err.help("did you mean to use one of the enum's variants?"); - }, - AdtKind::Struct | - AdtKind::Union => { - err.span_suggestion( - span, - "use curly brackets", - String::from("Self { /* fields */ }"), - Applicability::HasPlaceholders, - ); - } + let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { + let ty = self.impl_self_ty(span, impl_def_id).ty; + let adt_def = ty.ty_adt_def(); + + match ty.sty { + ty::Adt(adt_def, substs) if adt_def.has_ctor() => { + let variant = adt_def.non_enum_variant(); + let ctor_def_id = variant.ctor_def_id.unwrap(); + ( + Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id), + Some(substs), + ) + } + _ => { + let mut err = tcx.sess.struct_span_err(span, + "the `Self` constructor can only be used with tuple or unit structs"); + if let Some(adt_def) = adt_def { + match adt_def.adt_kind() { + AdtKind::Enum => { + err.help("did you mean to use one of the enum's variants?"); + }, + AdtKind::Struct | + AdtKind::Union => { + err.span_suggestion( + span, + "use curly brackets", + String::from("Self { /* fields */ }"), + Applicability::HasPlaceholders, + ); } } - err.emit(); - - (impl_def_id, tcx.types.err) } - } - } - _ => { - let def_id = def.def_id(); + err.emit(); - // The things we are substituting into the type should not contain - // escaping late-bound regions, and nor should the base type scheme. - let ty = tcx.type_of(def_id); - (def_id, ty) + return (tcx.types.err, res) + } } + } else { + (res, None) }; + let def_id = res.def_id(); - let substs = AstConv::create_substs_for_generic_args( + // The things we are substituting into the type should not contain + // escaping late-bound regions, and nor should the base type scheme. + let ty = tcx.type_of(def_id); + + let substs = self_ctor_substs.unwrap_or_else(|| AstConv::create_substs_for_generic_args( tcx, def_id, &[][..], @@ -5483,10 +4236,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !infer_args_for_err.contains(&index) { // Check whether the user has provided generic arguments. if let Some(ref data) = segments[index].args { - return (Some(data), segments[index].infer_types); + return (Some(data), segments[index].infer_args); } } - return (None, segments[index].infer_types); + return (None, segments[index].infer_args); } (None, true) @@ -5500,17 +4253,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { self.to_ty(ty).into() } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + self.to_const(&ct.value, self.tcx.type_of(param.def_id)).into() + } _ => unreachable!(), } }, // Provide substitutions for parameters for which arguments are inferred. - |substs, param, infer_types| { + |substs, param, infer_args| { match param.kind { GenericParamDefKind::Lifetime => { - self.re_infer(span, Some(param)).unwrap().into() + self.re_infer(Some(param), span).unwrap().into() } GenericParamDefKind::Type { has_default, .. } => { - if !infer_types && has_default { + if !infer_args && has_default { // If we have a default, then we it doesn't matter that we're not // inferring the type arguments: we provide the default where any // is missing. @@ -5527,9 +4283,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.var_for_def(span, param) } } + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + // No const parameters were provided, we have to infer them. + self.var_for_def(span, param) + } } }, - ); + )); assert!(!substs.has_escaping_bound_vars()); assert!(!ty.has_escaping_bound_vars()); @@ -5559,10 +4320,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { - span_bug!(span, + self.tcx.sess.delay_span_bug(span, &format!( "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", self_ty, - impl_ty); + impl_ty, + )); } } } @@ -5574,7 +4336,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty_substituted); self.write_substs(hir_id, substs); - (ty_substituted, new_def) + (ty_substituted, res) } fn check_rustc_args_require_const(&self, @@ -5583,14 +4345,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span) { // We're only interested in functions tagged with // #[rustc_args_required_const], so ignore anything that's not. - if !self.tcx.has_attr(def_id, "rustc_args_required_const") { + if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) { return } // If our calling expression is indeed the function itself, we're good! // If not, generate an error that this can only be called directly. - if let Node::Expr(expr) = self.tcx.hir().get_by_hir_id( - self.tcx.hir().get_parent_node_by_hir_id(hir_id)) + if let Node::Expr(expr) = self.tcx.hir().get( + self.tcx.hir().get_parent_node(hir_id)) { if let ExprKind::Call(ref callee, ..) = expr.node { if callee.hir_id == hir_id { @@ -5621,9 +4383,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn with_breakable_ctxt R, R>(&self, id: hir::HirId, - ctxt: BreakableCtxt<'gcx, 'tcx>, f: F) - -> (BreakableCtxt<'gcx, 'tcx>, R) { + fn with_breakable_ctxt R, R>( + &self, + id: hir::HirId, + ctxt: BreakableCtxt<'tcx>, + f: F, + ) -> (BreakableCtxt<'tcx>, R) { let index; { let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); @@ -5662,7 +4427,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut contained_in_place = false; while let hir::Node::Expr(parent_expr) = - self.tcx.hir().get_by_hir_id(self.tcx.hir().get_parent_node_by_hir_id(expr_id)) + self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id)) { match &parent_expr.node { hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => { @@ -5680,26 +4445,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } -pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - generics: &ty::Generics, - ty: Ty<'tcx>) { +pub fn check_bounds_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) { let own_counts = generics.own_counts(); - debug!("check_bounds_are_used(n_tps={}, ty={:?})", own_counts.types, ty); + debug!( + "check_bounds_are_used(n_tys={}, n_cts={}, ty={:?})", + own_counts.types, + own_counts.consts, + ty + ); if own_counts.types == 0 { return; } - // Make a vector of booleans initially false, set to true when used. + + // Make a vector of booleans initially `false`; set to `true` when used. let mut types_used = vec![false; own_counts.types]; for leaf_ty in ty.walk() { - if let ty::Param(ty::ParamTy { idx, .. }) = leaf_ty.sty { - debug!("Found use of ty param num {}", idx); - types_used[idx as usize - own_counts.lifetimes] = true; + if let ty::Param(ty::ParamTy { index, .. }) = leaf_ty.sty { + debug!("Found use of ty param num {}", index); + types_used[index as usize - own_counts.lifetimes] = true; } else if let ty::Error = leaf_ty.sty { // If there is already another error, do not emit - // an error for not using a type Parameter. - assert!(tcx.sess.err_count() > 0); + // an error for not using a type parameter. + assert!(tcx.sess.has_errors()); return; } } @@ -5711,7 +4480,7 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for (&used, param) in types_used.iter().zip(types) { if !used { let id = tcx.hir().as_local_hir_id(param.def_id).unwrap(); - let span = tcx.hir().span_by_hir_id(id); + let span = tcx.hir().span(id); struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name) .span_label(span, "unused type parameter") .emit(); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 9d883b22214f7..93855a3b68a7f 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -3,22 +3,23 @@ use super::{FnCtxt, Needs}; use super::method::MethodCallee; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::TyKind::{Ref, Adt, Str, Uint, Never, Tuple, Char, Array}; +use rustc::ty::TyKind::{Ref, Adt, FnDef, Str, Uint, Never, Tuple, Char, Array}; use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; -use rustc::infer::type_variable::TypeVariableOrigin; +use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use errors::{self,Applicability}; use syntax_pos::Span; use syntax::ast::Ident; use rustc::hir; -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Checks a `a = b` - pub fn check_binop_assign(&self, - expr: &'gcx hir::Expr, - op: hir::BinOp, - lhs_expr: &'gcx hir::Expr, - rhs_expr: &'gcx hir::Expr) -> Ty<'tcx> - { + pub fn check_binop_assign( + &self, + expr: &'tcx hir::Expr, + op: hir::BinOp, + lhs_expr: &'tcx hir::Expr, + rhs_expr: &'tcx hir::Expr, + ) -> Ty<'tcx> { let (lhs_ty, rhs_ty, return_ty) = self.check_overloaded_binop(expr, lhs_expr, rhs_expr, op, IsAssign::Yes); @@ -43,12 +44,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } /// Checks a potentially overloaded binary operator. - pub fn check_binop(&self, - expr: &'gcx hir::Expr, - op: hir::BinOp, - lhs_expr: &'gcx hir::Expr, - rhs_expr: &'gcx hir::Expr) -> Ty<'tcx> - { + pub fn check_binop( + &self, + expr: &'tcx hir::Expr, + op: hir::BinOp, + lhs_expr: &'tcx hir::Expr, + rhs_expr: &'tcx hir::Expr, + ) -> Ty<'tcx> { let tcx = self.tcx; debug!("check_binop(expr.hir_id={}, expr={:?}, op={:?}, lhs_expr={:?}, rhs_expr={:?})", @@ -104,14 +106,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn enforce_builtin_binop_types(&self, - lhs_expr: &'gcx hir::Expr, - lhs_ty: Ty<'tcx>, - rhs_expr: &'gcx hir::Expr, - rhs_ty: Ty<'tcx>, - op: hir::BinOp) - -> Ty<'tcx> - { + fn enforce_builtin_binop_types( + &self, + lhs_expr: &'tcx hir::Expr, + lhs_ty: Ty<'tcx>, + rhs_expr: &'tcx hir::Expr, + rhs_ty: Ty<'tcx>, + op: hir::BinOp, + ) -> Ty<'tcx> { debug_assert!(is_builtin_binop(lhs_ty, rhs_ty, op)); let tcx = self.tcx; @@ -142,14 +144,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn check_overloaded_binop(&self, - expr: &'gcx hir::Expr, - lhs_expr: &'gcx hir::Expr, - rhs_expr: &'gcx hir::Expr, - op: hir::BinOp, - is_assign: IsAssign) - -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>) - { + fn check_overloaded_binop( + &self, + expr: &'tcx hir::Expr, + lhs_expr: &'tcx hir::Expr, + rhs_expr: &'tcx hir::Expr, + op: hir::BinOp, + is_assign: IsAssign, + ) -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>) { debug!("check_overloaded_binop(expr.hir_id={}, op={:?}, is_assign={:?})", expr.hir_id, op, @@ -163,7 +165,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // e.g., adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`. let lhs_ty = self.check_expr_with_needs(lhs_expr, Needs::None); - let fresh_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(lhs_expr.span)); + let fresh_var = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: lhs_expr.span, + }); self.demand_coerce(lhs_expr, lhs_ty, fresh_var, AllowTwoPhase::No) } IsAssign::Yes => { @@ -182,7 +187,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // using this variable as the expected type, which sometimes lets // us do better coercions than we would be able to do otherwise, // particularly for things like `String + &String`. - let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span)); + let rhs_ty_var = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: rhs_expr.span, + }); let result = self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign)); @@ -305,8 +313,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(missing_trait) = missing_trait { if op.node == hir::BinOpKind::Add && - self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, - rhs_ty, &mut err, true) { + self.check_str_addition( + lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, true, op) { // This has nothing here because it means we did string // concatenation (e.g., "Hello " += "World!"). This means // we don't want the note in the else clause to be emitted @@ -327,10 +335,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.emit(); } IsAssign::No => { - let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369, + let mut err = struct_span_err!(self.tcx.sess, op.span, E0369, "binary operation `{}` cannot be applied to type `{}`", op.node.as_str(), lhs_ty); + + let mut involves_fn = false; + if !lhs_expr.span.eq(&rhs_expr.span) { + involves_fn |= self.add_type_neq_err_label( + &mut err, + lhs_expr.span, + lhs_ty, + rhs_ty, + op, + is_assign + ); + involves_fn |= self.add_type_neq_err_label( + &mut err, + rhs_expr.span, + rhs_ty, + lhs_ty, + op, + is_assign + ); + } + let mut suggested_deref = false; if let Ref(_, mut rty, _) = lhs_ty.sty { if { @@ -379,8 +408,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(missing_trait) = missing_trait { if op.node == hir::BinOpKind::Add && - self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, - rhs_ty, &mut err, false) { + self.check_str_addition( + lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, false, op) { // This has nothing here because it means we did string // concatenation (e.g., "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted @@ -390,7 +419,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { "`{}` might need a bound for `{}`", lhs_ty, missing_trait )); - } else if !suggested_deref { + } else if !suggested_deref && !involves_fn { err.note(&format!( "an implementation of `{}` might \ be missing for `{}`", @@ -409,56 +438,166 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (lhs_ty, rhs_ty, return_ty) } + /// If one of the types is an uncalled function and calling it would yield the other type, + /// suggest calling the function. Returns wether a suggestion was given. + fn add_type_neq_err_label( + &self, + err: &mut errors::DiagnosticBuilder<'_>, + span: Span, + ty: Ty<'tcx>, + other_ty: Ty<'tcx>, + op: hir::BinOp, + is_assign: IsAssign, + ) -> bool /* did we suggest to call a function because of missing parenthesis? */ { + err.span_label(span, ty.to_string()); + if let FnDef(def_id, _) = ty.sty { + let source_map = self.tcx.sess.source_map(); + let hir_id = match self.tcx.hir().as_local_hir_id(def_id) { + Some(hir_id) => hir_id, + None => return false, + }; + if self.tcx.has_typeck_tables(def_id) == false { + return false; + } + let fn_sig = { + match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(hir_id) { + Some(f) => f.clone(), + None => { + bug!("No fn-sig entry for def_id={:?}", def_id); + } + } + }; + + let other_ty = if let FnDef(def_id, _) = other_ty.sty { + let hir_id = match self.tcx.hir().as_local_hir_id(def_id) { + Some(hir_id) => hir_id, + None => return false, + }; + if self.tcx.has_typeck_tables(def_id) == false { + return false; + } + match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(hir_id) { + Some(f) => f.clone().output(), + None => { + bug!("No fn-sig entry for def_id={:?}", def_id); + } + } + } else { + other_ty + }; + + if self.lookup_op_method(fn_sig.output(), + &[other_ty], + Op::Binary(op, is_assign)) + .is_ok() { + let (variable_snippet, applicability) = if fn_sig.inputs().len() > 0 { + (format!("{}( /* arguments */ )", source_map.span_to_snippet(span).unwrap()), + Applicability::HasPlaceholders) + } else { + (format!("{}()", source_map.span_to_snippet(span).unwrap()), + Applicability::MaybeIncorrect) + }; + + err.span_suggestion( + span, + "you might have forgotten to call this function", + variable_snippet, + applicability, + ); + return true; + } + } + false + } + + /// Provide actionable suggestions when trying to add two strings with incorrect types, + /// like `&str + &str`, `String + String` and `&str + &String`. + /// + /// If this function returns `true` it means a note was printed, so we don't need + /// to print the normal "implementation of `std::ops::Add` might be missing" note fn check_str_addition( &self, - expr: &'gcx hir::Expr, - lhs_expr: &'gcx hir::Expr, - rhs_expr: &'gcx hir::Expr, + lhs_expr: &'tcx hir::Expr, + rhs_expr: &'tcx hir::Expr, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>, err: &mut errors::DiagnosticBuilder<'_>, is_assign: bool, + op: hir::BinOp, ) -> bool { let source_map = self.tcx.sess.source_map(); + let remove_borrow_msg = "String concatenation appends the string on the right to the \ + string on the left and may require reallocation. This \ + requires ownership of the string on the left"; + let msg = "`to_owned()` can be used to create an owned `String` \ from a string reference. String concatenation \ appends the string on the right to the string \ on the left and may require reallocation. This \ requires ownership of the string on the left"; - // If this function returns true it means a note was printed, so we don't need - // to print the normal "implementation of `std::ops::Add` might be missing" note + + let is_std_string = |ty| &format!("{:?}", ty) == "std::string::String"; + match (&lhs_ty.sty, &rhs_ty.sty) { - (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) - if l_ty.sty == Str && r_ty.sty == Str => { - if !is_assign { - err.span_label(expr.span, - "`+` can't be used to concatenate two `&str` strings"); + (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str + if (l_ty.sty == Str || is_std_string(l_ty)) && ( + r_ty.sty == Str || is_std_string(r_ty) || + &format!("{:?}", rhs_ty) == "&&str" + ) => + { + if !is_assign { // Do not supply this message if `&str += &str` + err.span_label( + op.span, + "`+` cannot be used to concatenate two `&str` strings", + ); match source_map.span_to_snippet(lhs_expr.span) { - Ok(lstring) => err.span_suggestion( - lhs_expr.span, - msg, - format!("{}.to_owned()", lstring), - Applicability::MachineApplicable, - ), + Ok(lstring) => { + err.span_suggestion( + lhs_expr.span, + if lstring.starts_with("&") { + remove_borrow_msg + } else { + msg + }, + if lstring.starts_with("&") { + // let a = String::new(); + // let _ = &a + "bar"; + format!("{}", &lstring[1..]) + } else { + format!("{}.to_owned()", lstring) + }, + Applicability::MachineApplicable, + ) + } _ => err.help(msg), }; } true } - (&Ref(_, l_ty, _), &Adt(..)) - if l_ty.sty == Str && &format!("{:?}", rhs_ty) == "std::string::String" => { - err.span_label(expr.span, - "`+` can't be used to concatenate a `&str` with a `String`"); + (&Ref(_, l_ty, _), &Adt(..)) // Handle `&str` & `&String` + `String` + if (l_ty.sty == Str || is_std_string(l_ty)) && is_std_string(rhs_ty) => + { + err.span_label( + op.span, + "`+` cannot be used to concatenate a `&str` with a `String`", + ); match ( source_map.span_to_snippet(lhs_expr.span), source_map.span_to_snippet(rhs_expr.span), is_assign, ) { (Ok(l), Ok(r), false) => { + let to_string = if l.starts_with("&") { + // let a = String::new(); let b = String::new(); + // let _ = &a + b; + format!("{}", &l[1..]) + } else { + format!("{}.to_owned()", l) + }; err.multipart_suggestion( msg, vec![ - (lhs_expr.span, format!("{}.to_owned()", l)), + (lhs_expr.span, to_string), (rhs_expr.span, format!("&{}", r)), ], Applicability::MachineApplicable, @@ -474,12 +613,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn check_user_unop(&self, - ex: &'gcx hir::Expr, - operand_ty: Ty<'tcx>, - op: hir::UnOp) - -> Ty<'tcx> - { + pub fn check_user_unop( + &self, + ex: &'tcx hir::Expr, + operand_ty: Ty<'tcx>, + op: hir::UnOp, + ) -> Ty<'tcx> { assert!(op.is_by_value()); match self.lookup_op_method(operand_ty, &[], Op::Unary(op, ex.span)) { Ok(method) => { @@ -487,7 +626,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { method.sig.output() } Err(()) => { - let actual = self.resolve_type_vars_if_possible(&operand_ty); + let actual = self.resolve_vars_if_possible(&operand_ty); if !actual.references_error() { let mut err = struct_span_err!(self.tcx.sess, ex.span, E0600, "cannot apply unary operator `{}` to type `{}`", diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index b549986777c84..5313e1d0f73a3 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -81,12 +81,11 @@ use rustc::hir::def_id::DefId; use rustc::infer::outlives::env::OutlivesEnvironment; use rustc::infer::{self, RegionObligation, SuppressRegionErrors}; use rustc::ty::adjustment; -use rustc::ty::subst::SubstsRef; +use rustc::ty::subst::{SubstsRef, UnpackedKind}; use rustc::ty::{self, Ty}; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::hir::{self, PatKind}; -use rustc_data_structures::sync::Lrc; use std::mem; use std::ops::Deref; use std::rc::Rc; @@ -108,8 +107,8 @@ macro_rules! ignore_err { /////////////////////////////////////////////////////////////////////////// // PUBLIC ENTRY POINTS -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn regionck_expr(&self, body: &'gcx hir::Body) { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn regionck_expr(&self, body: &'tcx hir::Body) { let subject = self.tcx.hir().body_owner_def_id(body.id()); let id = body.value.hir_id; let mut rcx = RegionCtxt::new( @@ -124,7 +123,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // standalone expr (e.g., the `E` in a type like `[u32; E]`). rcx.outlives_environment.save_implied_bounds(id); - if self.err_count_since_creation() == 0 { + if !self.errors_reported_since_creation() { // regionck assumes typeck succeeded rcx.visit_body(body); rcx.visit_region_obligations(id); @@ -162,7 +161,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// rest of type check and because sometimes we need type /// inference to have completed before we can determine which /// constraints to add. - pub fn regionck_fn(&self, fn_id: hir::HirId, body: &'gcx hir::Body) { + pub fn regionck_fn(&self, fn_id: hir::HirId, body: &'tcx hir::Body) { debug!("regionck_fn(id={})", fn_id); let subject = self.tcx.hir().body_owner_def_id(body.id()); let hir_id = body.value.hir_id; @@ -174,9 +173,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.param_env, ); - if self.err_count_since_creation() == 0 { + if !self.errors_reported_since_creation() { // regionck assumes typeck succeeded - rcx.visit_fn_body(fn_id, body, self.tcx.hir().span_by_hir_id(fn_id)); + rcx.visit_fn_body(fn_id, body, self.tcx.hir().span(fn_id)); } rcx.resolve_regions_and_report_errors(SuppressRegionErrors::when_nll_is_enabled(self.tcx)); @@ -192,15 +191,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /////////////////////////////////////////////////////////////////////////// // INTERNALS -pub struct RegionCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - pub fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, +pub struct RegionCtxt<'a, 'tcx> { + pub fcx: &'a FnCtxt<'a, 'tcx>, - pub region_scope_tree: Lrc, + pub region_scope_tree: &'tcx region::ScopeTree, outlives_environment: OutlivesEnvironment<'tcx>, // id of innermost fn body id body_id: hir::HirId, + body_owner: DefId, // call_site scope of innermost fn call_site_scope: Option, @@ -212,8 +212,8 @@ pub struct RegionCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { subject_def_id: DefId, } -impl<'a, 'gcx, 'tcx> Deref for RegionCtxt<'a, 'gcx, 'tcx> { - type Target = FnCtxt<'a, 'gcx, 'tcx>; +impl<'a, 'tcx> Deref for RegionCtxt<'a, 'tcx> { + type Target = FnCtxt<'a, 'tcx>; fn deref(&self) -> &Self::Target { &self.fcx } @@ -222,14 +222,14 @@ impl<'a, 'gcx, 'tcx> Deref for RegionCtxt<'a, 'gcx, 'tcx> { pub struct RepeatingScope(hir::HirId); pub struct Subject(DefId); -impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { pub fn new( - fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, + fcx: &'a FnCtxt<'a, 'tcx>, RepeatingScope(initial_repeating_scope): RepeatingScope, initial_body_id: hir::HirId, Subject(subject): Subject, param_env: ty::ParamEnv<'tcx>, - ) -> RegionCtxt<'a, 'gcx, 'tcx> { + ) -> RegionCtxt<'a, 'tcx> { let region_scope_tree = fcx.tcx.region_scope_tree(subject); let outlives_environment = OutlivesEnvironment::new(param_env); RegionCtxt { @@ -237,6 +237,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { region_scope_tree, repeating_scope: initial_repeating_scope, body_id: initial_body_id, + body_owner: subject, call_site_scope: None, subject_def_id: subject, outlives_environment, @@ -271,7 +272,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// of b will be `&.i32` and then `*b` will require that `` be bigger than the let and /// the `*b` expression, so we will effectively resolve `` to be the block B. pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> { - self.resolve_type_vars_if_possible(&unresolved_ty) + self.resolve_vars_if_possible(&unresolved_ty) } /// Try to resolve the type for the given node. @@ -301,7 +302,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn visit_fn_body( &mut self, id: hir::HirId, // the id of the fn itself - body: &'gcx hir::Body, + body: &'tcx hir::Body, span: Span, ) { // When we enter a function, we can derive @@ -309,6 +310,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let body_id = body.id(); self.body_id = body_id.hir_id; + self.body_owner = self.tcx.hir().body_owner_def_id(body_id); let call_site = region::Scope { id: body.value.hir_id.local_id, @@ -435,7 +437,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { // (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local, // However, right now we run into an issue whereby some free // regions are not properly related if they appear within the @@ -444,14 +446,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { // hierarchy, and in particular the relationships between free // regions, until regionck, as described in #3238. - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } fn visit_fn( &mut self, - fk: intravisit::FnKind<'gcx>, - _: &'gcx hir::FnDecl, + fk: intravisit::FnKind<'tcx>, + _: &'tcx hir::FnDecl, body_id: hir::BodyId, span: Span, hir_id: hir::HirId, @@ -467,6 +469,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { // Save state of current function before invoking // `visit_fn_body`. We will restore afterwards. let old_body_id = self.body_id; + let old_body_owner = self.body_owner; let old_call_site_scope = self.call_site_scope; let env_snapshot = self.outlives_environment.push_snapshot_pre_closure(); @@ -478,11 +481,12 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { .pop_snapshot_post_closure(env_snapshot); self.call_site_scope = old_call_site_scope; self.body_id = old_body_id; + self.body_owner = old_body_owner; } //visit_pat: visit_pat, // (..) see above - fn visit_arm(&mut self, arm: &'gcx hir::Arm) { + fn visit_arm(&mut self, arm: &'tcx hir::Arm) { // see above for p in &arm.pats { self.constrain_bindings_in_pat(p); @@ -490,14 +494,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { intravisit::walk_arm(self, arm); } - fn visit_local(&mut self, l: &'gcx hir::Local) { + fn visit_local(&mut self, l: &'tcx hir::Local) { // see above self.constrain_bindings_in_pat(&l.pat); self.link_local(l); intravisit::walk_local(self, l); } - fn visit_expr(&mut self, expr: &'gcx hir::Expr) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { debug!( "regionck::visit_expr(e={:?}, repeating_scope={:?})", expr, self.repeating_scope @@ -713,7 +717,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { fn constrain_cast(&mut self, cast_expr: &hir::Expr, source_expr: &hir::Expr) { debug!( "constrain_cast(cast_expr={:?}, source_expr={:?})", @@ -754,7 +758,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } } - fn check_expr_fn_block(&mut self, expr: &'gcx hir::Expr, body_id: hir::BodyId) { + fn check_expr_fn_block(&mut self, expr: &'tcx hir::Expr, body_id: hir::BodyId) { let repeating_scope = self.set_repeating_scope(body_id.hir_id); intravisit::walk_expr(self, expr); self.set_repeating_scope(repeating_scope); @@ -826,10 +830,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// Creates a temporary `MemCategorizationContext` and pass it to the closure. fn with_mc(&self, f: F) -> R where - F: for<'b> FnOnce(mc::MemCategorizationContext<'b, 'gcx, 'tcx>) -> R, + F: for<'b> FnOnce(mc::MemCategorizationContext<'b, 'tcx>) -> R, { f(mc::MemCategorizationContext::with_infer( &self.infcx, + self.body_owner, &self.region_scope_tree, &self.tables.borrow(), )) @@ -986,8 +991,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } } - /// Guarantees that any lifetimes which appear in the type of the node `id` (after applying - /// adjustments) are valid for at least `minimum_lifetime` + /// Guarantees that any lifetimes that appear in the type of the node `id` (after applying + /// adjustments) are valid for at least `minimum_lifetime`. fn type_of_node_must_outlive( &mut self, origin: infer::SubregionOrigin<'tcx>, @@ -1407,13 +1412,19 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let origin = infer::ParameterInScope(origin, expr_span); - for region in substs.regions() { - self.sub_regions(origin.clone(), expr_region, region); - } - - for ty in substs.types() { - let ty = self.resolve_type(ty); - self.type_must_outlive(origin.clone(), ty, expr_region); + for kind in substs { + match kind.unpack() { + UnpackedKind::Lifetime(lt) => { + self.sub_regions(origin.clone(), expr_region, lt); + } + UnpackedKind::Type(ty) => { + let ty = self.resolve_type(ty); + self.type_must_outlive(origin.clone(), ty, expr_region); + } + UnpackedKind::Const(_) => { + // Const parameters don't impose constraints. + } + } } } } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index bf6f4482e746d..ac39757df74dc 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -41,11 +41,12 @@ use rustc::hir::def_id::LocalDefId; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::infer::UpvarRegion; use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts}; +use rustc_data_structures::fx::FxIndexMap; use syntax::ast; use syntax_pos::Span; -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn closure_analyze(&self, body: &'gcx hir::Body) { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn closure_analyze(&self, body: &'tcx hir::Body) { InferBorrowKindVisitor { fcx: self }.visit_body(body); // it's our job to process these. @@ -53,16 +54,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } -struct InferBorrowKindVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, +struct InferBorrowKindVisitor<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, } -impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { +impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } - fn visit_expr(&mut self, expr: &'gcx hir::Expr) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.node { let body = self.fcx.tcx.hir().body(body_id); self.visit_body(body); @@ -74,7 +75,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn analyze_closure( &self, closure_hir_id: hir::HirId, @@ -93,19 +94,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ); // Extract the type of the closure. - let (closure_def_id, substs) = match self.node_ty(closure_hir_id).sty { + let ty = self.node_ty(closure_hir_id); + let (closure_def_id, substs) = match ty.sty { ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), ty::Error => { // #51714: skip analysis when we have already encountered type errors return; } - ref t => { + _ => { span_bug!( span, "type of closure expr {:?} is not a closure {:?}", closure_hir_id, - t + ty ); } }; @@ -120,30 +122,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None }; - let closure_node_id = self.tcx.hir().hir_to_node_id(closure_hir_id); - - self.tcx.with_freevars(closure_node_id, |freevars| { - let mut freevar_list: Vec = Vec::with_capacity(freevars.len()); - for freevar in freevars { + if let Some(upvars) = self.tcx.upvars(closure_def_id) { + let mut upvar_list: FxIndexMap = + FxIndexMap::with_capacity_and_hasher(upvars.len(), Default::default()); + for (&var_hir_id, _) in upvars.iter() { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { - hir_id: self.tcx.hir().node_to_hir_id(freevar.var_id()), + hir_id: var_hir_id, }, closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; debug!("seed upvar_id {:?}", upvar_id); // Adding the upvar Id to the list of Upvars, which will be added // to the map for the closure at the end of the for loop. - freevar_list.push(upvar_id); + upvar_list.insert(var_hir_id, upvar_id); let capture_kind = match capture_clause { hir::CaptureByValue => ty::UpvarCapture::ByValue, hir::CaptureByRef => { let origin = UpvarRegion(upvar_id, span); - let freevar_region = self.next_region_var(origin); + let upvar_region = self.next_region_var(origin); let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, - region: freevar_region, + region: upvar_region, }; ty::UpvarCapture::ByRef(upvar_borrow) } @@ -154,18 +155,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .upvar_capture_map .insert(upvar_id, capture_kind); } - // Add the vector of freevars to the map keyed with the closure id. + // Add the vector of upvars to the map keyed with the closure id. // This gives us an easier access to them without having to call - // with_freevars again.. - if !freevar_list.is_empty() { + // tcx.upvars again.. + if !upvar_list.is_empty() { self.tables .borrow_mut() .upvar_list - .insert(closure_def_id, freevar_list); + .insert(closure_def_id, upvar_list); } - }); + } let body_owner_def_id = self.tcx.hir().body_owner_def_id(body.id()); + assert_eq!(body_owner_def_id, closure_def_id); let region_scope_tree = &self.tcx.region_scope_tree(body_owner_def_id); let mut delegate = InferBorrowKind { fcx: self, @@ -177,6 +179,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { euv::ExprUseVisitor::with_infer( &mut delegate, &self.infcx, + body_owner_def_id, self.param_env, region_scope_tree, &self.tables.borrow(), @@ -217,10 +220,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // inference algorithm will reject it). // Equate the type variables for the upvars with the actual types. - let final_upvar_tys = self.final_upvar_tys(closure_node_id); + let final_upvar_tys = self.final_upvar_tys(closure_hir_id); debug!( "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}", - closure_node_id, substs, final_upvar_tys + closure_hir_id, substs, final_upvar_tys ); for (upvar_ty, final_upvar_ty) in substs .upvar_tys(closure_def_id, self.tcx) @@ -238,51 +241,49 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Returns a list of `ClosureUpvar`s for each upvar. - fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec> { + fn final_upvar_tys(&self, closure_id: hir::HirId) -> Vec> { // Presently an unboxed closure type cannot "escape" out of a // function, so we will only encounter ones that originated in the // local crate or were inlined into it along with some function. // This may change if abstract return types of some sort are // implemented. let tcx = self.tcx; - let closure_def_index = tcx.hir().local_def_id(closure_id); + let closure_def_id = tcx.hir().local_def_id_from_hir_id(closure_id); - tcx.with_freevars(closure_id, |freevars| { - freevars + tcx.upvars(closure_def_id).iter().flat_map(|upvars| { + upvars .iter() - .map(|freevar| { - let var_node_id = freevar.var_id(); - let var_hir_id = tcx.hir().node_to_hir_id(var_node_id); - let freevar_ty = self.node_ty(var_hir_id); + .map(|(&var_hir_id, _)| { + let upvar_ty = self.node_ty(var_hir_id); let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: LocalDefId::from_def_id(closure_def_index), + closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; let capture = self.tables.borrow().upvar_capture(upvar_id); debug!( - "var_id={:?} freevar_ty={:?} capture={:?}", - var_node_id, freevar_ty, capture + "var_id={:?} upvar_ty={:?} capture={:?}", + var_hir_id, upvar_ty, capture ); match capture { - ty::UpvarCapture::ByValue => freevar_ty, + ty::UpvarCapture::ByValue => upvar_ty, ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref( borrow.region, ty::TypeAndMut { - ty: freevar_ty, + ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy(), }, ), } }) - .collect() }) + .collect() } } -struct InferBorrowKind<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, +struct InferBorrowKind<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, // The def-id of the closure whose kind and upvar accesses are being inferred. closure_def_id: DefId, @@ -304,7 +305,7 @@ struct InferBorrowKind<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>, } -impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { fn adjust_upvar_borrow_kind_for_consume( &mut self, cmt: &mc::cmt_<'tcx>, @@ -580,7 +581,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { fn consume( &mut self, _consume_id: hir::HirId, @@ -635,7 +636,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { } } - fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) {} + fn decl_without_init(&mut self, _id: hir::HirId, _span: Span) {} fn mutate( &mut self, @@ -650,6 +651,6 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { } } -fn var_name(tcx: TyCtxt<'_, '_, '_>, var_hir_id: hir::HirId) -> ast::Name { - tcx.hir().name_by_hir_id(var_hir_id) +fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> ast::Name { + tcx.hir().name(var_hir_id) } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index b7c862a89a1b4..d612d042f7f23 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -1,36 +1,41 @@ use crate::check::{Inherited, FnCtxt}; -use crate::constrained_type_params::{identify_constrained_type_params, Parameter}; +use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; use crate::hir::def_id::DefId; use rustc::traits::{self, ObligationCauseCode}; -use rustc::ty::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable, ToPredicate}; +use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable, ToPredicate}; use rustc::ty::subst::{Subst, InternalSubsts}; use rustc::util::nodemap::{FxHashSet, FxHashMap}; +use rustc::mir::interpret::ConstValue; use rustc::middle::lang_items; use rustc::infer::opaque_types::may_define_existential_type; use syntax::ast; use syntax::feature_gate::{self, GateIssue}; use syntax_pos::Span; +use syntax::symbol::sym; use errors::{DiagnosticBuilder, DiagnosticId}; -use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::hir::itemlikevisit::ParItemLikeVisitor; use rustc::hir; /// Helper type of a temporary returned by `.for_item(...)`. -/// Necessary because we can't write the following bound: -/// `F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>)`. -struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>, +/// This is necessary because we can't write the following bound: +/// +/// ```rust +/// F: for<'b, 'tcx> where 'tcx FnOnce(FnCtxt<'b, 'tcx>) +/// ``` +struct CheckWfFcxBuilder<'tcx> { + inherited: super::InheritedBuilder<'tcx>, id: hir::HirId, span: Span, param_env: ty::ParamEnv<'tcx>, } -impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { - fn with_fcx(&'tcx mut self, f: F) where - F: for<'b> FnOnce(&FnCtxt<'b, 'gcx, 'tcx>, - TyCtxt<'b, 'gcx, 'gcx>) -> Vec> +impl<'tcx> CheckWfFcxBuilder<'tcx> { + fn with_fcx(&mut self, f: F) + where + F: for<'b> FnOnce(&FnCtxt<'b, 'tcx>, TyCtxt<'tcx>) -> Vec>, { let id = self.id; let span = self.span; @@ -40,7 +45,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { if !inh.tcx.features().trivial_bounds { // As predicates are cached rather than obligations, this // needsto be called first so that they are checked with an - // empty param_env. + // empty `param_env`. check_false_global_bounds(&fcx, span, id); } let wf_tys = f(&fcx, fcx.tcx.global_tcx()); @@ -54,26 +59,28 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { /// well-formed, meaning that they do not require any constraints not declared in the struct /// definition itself. For example, this definition would be illegal: /// -/// struct Ref<'a, T> { x: &'a T } +/// ```rust +/// struct Ref<'a, T> { x: &'a T } +/// ``` /// /// because the type did not declare that `T:'a`. /// /// We do this check as a pre-pass before checking fn bodies because if these constraints are /// not included it frequently leads to confusing errors in fn bodies. So it's better to check /// the types first. -pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { +pub fn check_item_well_formed<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) { let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let item = tcx.hir().expect_item_by_hir_id(hir_id); + let item = tcx.hir().expect_item(hir_id); debug!("check_item_well_formed(it.hir_id={:?}, it.name={})", item.hir_id, - tcx.item_path_str(def_id)); + tcx.def_path_str(def_id)); match item.node { // Right now we check that every default trait implementation // has an implementation of itself. Basically, a case like: // - // `impl Trait for T {}` + // impl Trait for T {} // // has a requirement of `T: Trait` which was required for default // method implementations. Although this could be improved now that @@ -83,7 +90,7 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def // Since there's such a requirement, we need to check *just* positive // implementations, otherwise things like: // - // impl !Send for T {} + // impl !Send for T {} // // won't be allowed unless there's an *explicit* implementation of `Send` // for `T` @@ -96,7 +103,7 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def if polarity == hir::ImplPolarity::Positive { check_impl(tcx, item, self_ty, trait_ref); } else { - // FIXME(#27579) what amount of WF checking do we need for neg impls? + // FIXME(#27579): what amount of WF checking do we need for neg impls? if trait_ref.is_some() && !is_auto { span_err!(tcx.sess, item.span, E0192, "negative impls are only allowed for \ @@ -149,9 +156,9 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def } } -pub fn check_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { - let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); - let trait_item = tcx.hir().expect_trait_item(node_id); +pub fn check_trait_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) { + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let trait_item = tcx.hir().expect_trait_item(hir_id); let method_sig = match trait_item.node { hir::TraitItemKind::Method(ref sig, _) => Some(sig), @@ -160,9 +167,9 @@ pub fn check_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { check_associated_item(tcx, trait_item.hir_id, trait_item.span, method_sig); } -pub fn check_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { - let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); - let impl_item = tcx.hir().expect_impl_item(node_id); +pub fn check_impl_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) { + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let impl_item = tcx.hir().expect_impl_item(hir_id); let method_sig = match impl_item.node { hir::ImplItemKind::Method(ref sig, _) => Some(sig), @@ -171,10 +178,12 @@ pub fn check_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { check_associated_item(tcx, impl_item.hir_id, impl_item.span, method_sig); } -fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - item_id: hir::HirId, - span: Span, - sig_if_method: Option<&hir::MethodSig>) { +fn check_associated_item<'tcx>( + tcx: TyCtxt<'tcx>, + item_id: hir::HirId, + span: Span, + sig_if_method: Option<&hir::MethodSig>, +) { debug!("check_associated_item: {:?}", item_id); let code = ObligationCauseCode::MiscObligation; @@ -188,12 +197,12 @@ fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; match item.kind { - ty::AssociatedKind::Const => { + ty::AssocKind::Const => { let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.normalize_associated_types_in(span, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } - ty::AssociatedKind::Method => { + ty::AssocKind::Method => { reject_shadowing_parameters(fcx.tcx, item.def_id); let sig = fcx.tcx.fn_sig(item.def_id); let sig = fcx.normalize_associated_types_in(span, &sig); @@ -202,14 +211,14 @@ fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let sig_if_method = sig_if_method.expect("bad signature for method"); check_method_receiver(fcx, sig_if_method, &item, self_ty); } - ty::AssociatedKind::Type => { + ty::AssocKind::Type => { if item.defaultness.has_value() { let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.normalize_associated_types_in(span, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } } - ty::AssociatedKind::Existential => { + ty::AssocKind::Existential => { // do nothing, existential types check themselves } } @@ -218,13 +227,11 @@ fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } -fn for_item<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, item: &hir::Item) - -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { +fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item) -> CheckWfFcxBuilder<'tcx> { for_id(tcx, item.hir_id, item.span) } -fn for_id<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, id: hir::HirId, span: Span) - -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { +fn for_id<'tcx>(tcx: TyCtxt<'tcx>, id: hir::HirId, span: Span) -> CheckWfFcxBuilder<'tcx> { let def_id = tcx.hir().local_def_id_from_hir_id(id); CheckWfFcxBuilder { inherited: Inherited::build(tcx, def_id), @@ -235,13 +242,17 @@ fn for_id<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, id: hir::HirId, span: Spa } /// In a type definition, we check that to ensure that the types of the fields are well-formed. -fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - item: &hir::Item, all_sized: bool, mut lookup_fields: F) - where F: for<'fcx, 'gcx, 'tcx2> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx2>) -> Vec> +fn check_type_defn<'tcx, F>( + tcx: TyCtxt<'tcx>, + item: &hir::Item, + all_sized: bool, + mut lookup_fields: F, +) where + F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec>, { for_item(tcx, item).with_fcx(|fcx, fcx_tcx| { let variants = lookup_fields(fcx); - let def_id = fcx.tcx.hir().local_def_id(item.id); + let def_id = fcx.tcx.hir().local_def_id_from_hir_id(item.hir_id); let packed = fcx.tcx.adt_def(def_id).repr.packed(); for variant in &variants { @@ -250,11 +261,15 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let needs_drop_copy = || { packed && { let ty = variant.fields.last().unwrap().ty; - let ty = fcx.tcx.erase_regions(&ty).lift_to_tcx(fcx_tcx) - .unwrap_or_else(|| { - span_bug!(item.span, "inference variables in {:?}", ty) - }); - ty.needs_drop(fcx_tcx, fcx_tcx.param_env(def_id)) + let ty = fcx.tcx.erase_regions(&ty); + if ty.has_local_value() { + fcx_tcx.sess.delay_span_bug( + item.span, &format!("inference variables in {:?}", ty)); + // Just treat unresolved type expression as if it needs drop. + true + } else { + ty.needs_drop(fcx_tcx, fcx_tcx.param_env(def_id)) + } } }; let all_sized = @@ -297,14 +312,15 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_where_clauses(tcx, fcx, item.span, def_id, None); - vec![] // no implied bounds in a struct def'n + // No implied bounds in a struct definition. + vec![] }); } -fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { - debug!("check_trait: {:?}", item.id); +fn check_trait<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item) { + debug!("check_trait: {:?}", item.hir_id); - let trait_def_id = tcx.hir().local_def_id(item.id); + let trait_def_id = tcx.hir().local_def_id_from_hir_id(item.hir_id); let trait_def = tcx.trait_def(trait_def_id); if trait_def.is_marker { @@ -324,9 +340,9 @@ fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { }); } -fn check_item_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { +fn check_item_fn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item) { for_item(tcx, item).with_fcx(|fcx, tcx| { - let def_id = fcx.tcx.hir().local_def_id(item.id); + let def_id = fcx.tcx.hir().local_def_id_from_hir_id(item.hir_id); let sig = fcx.tcx.fn_sig(def_id); let sig = fcx.normalize_associated_types_in(item.span, &sig); let mut implied_bounds = vec![]; @@ -336,8 +352,8 @@ fn check_item_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { }) } -fn check_item_type<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn check_item_type<'tcx>( + tcx: TyCtxt<'tcx>, item_id: hir::HirId, ty_span: Span, allow_foreign_ty: bool, @@ -350,7 +366,7 @@ fn check_item_type<'a, 'tcx>( let mut forbid_unsized = true; if allow_foreign_ty { - if let TyKind::Foreign(_) = fcx.tcx.struct_tail(item_ty).sty { + if let ty::Foreign(_) = fcx.tcx.struct_tail(item_ty).sty { forbid_unsized = false; } } @@ -364,19 +380,21 @@ fn check_item_type<'a, 'tcx>( ); } - vec![] // no implied bounds in a const etc + // No implied bounds in a const, etc. + vec![] }); } -fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - item: &hir::Item, - ast_self_ty: &hir::Ty, - ast_trait_ref: &Option) -{ +fn check_impl<'tcx>( + tcx: TyCtxt<'tcx>, + item: &hir::Item, + ast_self_ty: &hir::Ty, + ast_trait_ref: &Option, +) { debug!("check_impl: {:?}", item); for_item(tcx, item).with_fcx(|fcx, tcx| { - let item_def_id = fcx.tcx.hir().local_def_id(item.id); + let item_def_id = fcx.tcx.hir().local_def_id_from_hir_id(item.hir_id); match *ast_trait_ref { Some(ref ast_trait_ref) => { @@ -409,19 +427,18 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } /// Checks where-clauses and inline bounds that are declared on `def_id`. -fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( - tcx: TyCtxt<'a, 'gcx, 'gcx>, - fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, +fn check_where_clauses<'tcx, 'fcx>( + tcx: TyCtxt<'tcx>, + fcx: &FnCtxt<'fcx, 'tcx>, span: Span, def_id: DefId, return_ty: Option>, ) { - use ty::subst::Subst; - use rustc::ty::TypeFoldable; + debug!("check_where_clauses(def_id={:?}, return_ty={:?})", def_id, return_ty); let predicates = fcx.tcx.predicates_of(def_id); - let generics = tcx.generics_of(def_id); + let is_our_default = |def: &ty::GenericParamDef| { match def.kind { GenericParamDefKind::Type { has_default, .. } => { @@ -432,15 +449,17 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( }; // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`. - // For example this forbids the declaration: - // struct Foo> { .. } - // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. + // For example, this forbids the declaration: + // + // struct Foo> { .. } + // + // Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. for param in &generics.params { - if let GenericParamDefKind::Type {..} = param.kind { + if let GenericParamDefKind::Type { .. } = param.kind { if is_our_default(¶m) { let ty = fcx.tcx.type_of(param.def_id); - // ignore dependent defaults -- that is, where the default of one type - // parameter includes another (e.g., ). In those cases, we can't + // Ignore dependent defaults -- that is, where the default of one type + // parameter includes another (e.g., ``). In those cases, we can't // be sure if it will error or not as user might always specify the other. if !ty.needs_subst() { fcx.register_wf_obligation(ty, fcx.tcx.def_span(param.def_id), @@ -464,39 +483,50 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( // All regions are identity. fcx.tcx.mk_param_from_def(param) } - GenericParamDefKind::Type {..} => { - // If the param has a default, + + GenericParamDefKind::Type { .. } => { + // If the param has a default, ... if is_our_default(param) { let default_ty = fcx.tcx.type_of(param.def_id); - // and it's not a dependent default + // ... and it's not a dependent default, ... if !default_ty.needs_subst() { - // then substitute with the default. + // ... then substitute it with the default. return default_ty.into(); } } - // Mark unwanted params as err. + // Mark unwanted params as error. fcx.tcx.types.err.into() } + + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + fcx.tcx.consts.err.into() + } } }); + // Now we build the substituted predicates. let default_obligations = predicates.predicates.iter().flat_map(|&(pred, _)| { #[derive(Default)] struct CountParams { params: FxHashSet } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.sty { - ty::Param(p) => { - self.params.insert(p.idx); - t.super_visit_with(self) - } - _ => t.super_visit_with(self) + if let ty::Param(param) = t.sty { + self.params.insert(param.index); } + t.super_visit_with(self) } fn visit_region(&mut self, _: ty::Region<'tcx>) -> bool { true } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + if let ConstValue::Param(param) = c.val { + self.params.insert(param.index); + } + c.super_visit_with(self) + } } let mut param_count = CountParams::default(); let has_region = pred.visit_with(&mut param_count); @@ -512,7 +542,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( Some(substituted_pred) } }).map(|pred| { - // convert each of those into an obligation. So if you have + // Convert each of those into an obligation. So if you have // something like `struct Foo`, we would // take that predicate `T: Copy`, substitute to `String: Copy` // (actually that happens in the previous `flat_map` call), @@ -550,13 +580,14 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( } } -fn check_fn_or_method<'a, 'fcx, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, - fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, - span: Span, - sig: ty::PolyFnSig<'tcx>, - def_id: DefId, - implied_bounds: &mut Vec>) -{ +fn check_fn_or_method<'fcx, 'tcx>( + tcx: TyCtxt<'tcx>, + fcx: &FnCtxt<'fcx, 'tcx>, + span: Span, + sig: ty::PolyFnSig<'tcx>, + def_id: DefId, + implied_bounds: &mut Vec>, +) { let sig = fcx.normalize_associated_types_in(span, &sig); let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig); @@ -582,46 +613,44 @@ fn check_fn_or_method<'a, 'fcx, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, /// ```rust /// existential type Foo; /// -/// // ok -- `Foo` is applied to two distinct, generic types. +/// // Okay -- `Foo` is applied to two distinct, generic types. /// fn a() -> Foo { .. } /// -/// // not ok -- `Foo` is applied to `T` twice. +/// // Not okay -- `Foo` is applied to `T` twice. /// fn b() -> Foo { .. } /// -/// -/// // not ok -- `Foo` is applied to a non-generic type. +/// // Not okay -- `Foo` is applied to a non-generic type. /// fn b() -> Foo { .. } /// ``` /// -fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( - tcx: TyCtxt<'a, 'gcx, 'gcx>, - fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, +fn check_existential_types<'fcx, 'tcx>( + tcx: TyCtxt<'tcx>, + fcx: &FnCtxt<'fcx, 'tcx>, fn_def_id: DefId, span: Span, ty: Ty<'tcx>, ) -> Vec> { - trace!("check_existential_types: {:?}, {:?}", ty, ty.sty); + trace!("check_existential_types(ty={:?})", ty); let mut substituted_predicates = Vec::new(); ty.fold_with(&mut ty::fold::BottomUpFolder { tcx: fcx.tcx, - fldop: |ty| { + ty_op: |ty| { if let ty::Opaque(def_id, substs) = ty.sty { trace!("check_existential_types: opaque_ty, {:?}, {:?}", def_id, substs); let generics = tcx.generics_of(def_id); - // only check named existential types defined in this crate + // Only check named existential types defined in this crate. if generics.parent.is_none() && def_id.is_local() { - let opaque_node_id = tcx.hir().as_local_node_id(def_id).unwrap(); - if may_define_existential_type(tcx, fn_def_id, opaque_node_id) { - trace!("check_existential_types may define. Generics: {:#?}", generics); + let opaque_hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + if may_define_existential_type(tcx, fn_def_id, opaque_hir_id) { + trace!("check_existential_types: may define, generics={:#?}", generics); let mut seen: FxHashMap<_, Vec<_>> = FxHashMap::default(); for (subst, param) in substs.iter().zip(&generics.params) { match subst.unpack() { ty::subst::UnpackedKind::Type(ty) => match ty.sty { - ty::Param(..) => {}, - // prevent `fn foo() -> Foo` from being defining + ty::Param(..) => {} + // Prevent `fn foo() -> Foo` from being defining. _ => { - tcx - .sess + tcx.sess .struct_span_err( span, "non-defining existential type use \ @@ -636,8 +665,9 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( ), ) .emit(); - }, - }, // match ty + } + } + ty::subst::UnpackedKind::Lifetime(region) => { let param_span = tcx.def_span(param.def_id); if let ty::ReStatic = region { @@ -658,7 +688,28 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( } else { seen.entry(region).or_default().push(param_span); } - }, + } + + ty::subst::UnpackedKind::Const(ct) => match ct.val { + ConstValue::Param(_) => {} + _ => { + tcx.sess + .struct_span_err( + span, + "non-defining existential type use \ + in defining scope", + ) + .span_note( + tcx.def_span(param.def_id), + &format!( + "used non-generic const {} for \ + generic parameter", + ty, + ), + ) + .emit(); + } + } } // match subst } // for (subst, param) for (_, spans) in seen { @@ -679,20 +730,19 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( } } // if may_define_existential_type - // now register the bounds on the parameters of the existential type - // so the parameters given by the function need to fulfill them - // ```rust - // existential type Foo: 'static; - // fn foo() -> Foo { .. *} - // ``` + // Now register the bounds on the parameters of the existential type + // so the parameters given by the function need to fulfill them. + // + // existential type Foo: 'static; + // fn foo() -> Foo { .. *} + // // becomes - // ```rust - // existential type Foo: 'static; - // fn foo() -> Foo { .. *} - // ``` + // + // existential type Foo: 'static; + // fn foo() -> Foo { .. *} let predicates = tcx.predicates_of(def_id); trace!( - "check_existential_types may define. adding predicates: {:#?}", + "check_existential_types: may define, predicates={:#?}", predicates, ); for &(pred, _) in predicates.predicates.iter() { @@ -706,17 +756,19 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( } // if let Opaque ty }, - reg_op: |reg| reg, + lt_op: |lt| lt, + ct_op: |ct| ct, }); substituted_predicates } -fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, - method_sig: &hir::MethodSig, - method: &ty::AssociatedItem, - self_ty: Ty<'tcx>) -{ - // check that the method has a valid receiver type, given the type `Self` +fn check_method_receiver<'fcx, 'tcx>( + fcx: &FnCtxt<'fcx, 'tcx>, + method_sig: &hir::MethodSig, + method: &ty::AssocItem, + self_ty: Ty<'tcx>, +) { + // Check that the method has a valid receiver type, given the type `Self`. debug!("check_method_receiver({:?}, self_ty={:?})", method, self_ty); @@ -748,7 +800,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, if fcx.tcx.features().arbitrary_self_types { if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { - // report error, arbitrary_self_types was enabled + // Report error; `arbitrary_self_types` was enabled. fcx.tcx.sess.diagnostic().mut_span_err( span, &format!("invalid method receiver type: {:?}", receiver_ty) ).note("type of `self` must be `Self` or a type that dereferences to it") @@ -759,10 +811,10 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, } else { if !receiver_is_valid(fcx, span, receiver_ty, self_ty, false) { if receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { - // report error, would have worked with arbitrary_self_types + // Report error; would have worked with `arbitrary_self_types`. feature_gate::feature_err( &fcx.tcx.sess.parse_sess, - "arbitrary_self_types", + sym::arbitrary_self_types, span, GateIssue::Language, &format!( @@ -773,7 +825,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, ).help("consider changing to `self`, `&self`, `&mut self`, or `self: Box`") .emit(); } else { - // report error, would not have worked with arbitrary_self_types + // Report error; would not have worked with `arbitrary_self_types`. fcx.tcx.sess.diagnostic().mut_span_err( span, &format!("invalid method receiver type: {:?}", receiver_ty) ).note("type must be `Self` or a type that dereferences to it") @@ -785,16 +837,17 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, } } -/// returns true if `receiver_ty` would be considered a valid receiver type for `self_ty`. If +/// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If /// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly /// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more -/// strict: `receiver_ty` must implement `Receiver` and directly implement `Deref`. +/// strict: `receiver_ty` must implement `Receiver` and directly implement +/// `Deref`. /// /// N.B., there are cases this function returns `true` but causes an error to be emitted, /// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the /// wrong lifetime. Be careful of this if you are calling this function speculatively. -fn receiver_is_valid<'fcx, 'tcx, 'gcx>( - fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, +fn receiver_is_valid<'fcx, 'tcx>( + fcx: &FnCtxt<'fcx, 'tcx>, span: Span, receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, @@ -804,7 +857,7 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>( let can_eq_self = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok(); - // `self: Self` is always valid + // `self: Self` is always valid. if can_eq_self(receiver_ty) { if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, receiver_ty) { err.emit(); @@ -814,15 +867,15 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>( let mut autoderef = fcx.autoderef(span, receiver_ty); - // the `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self` + // The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`. if arbitrary_self_types_enabled { autoderef = autoderef.include_raw_pointers(); } - // the first type is `receiver_ty`, which we know its not equal to `self_ty`. skip it. + // The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it. autoderef.next(); - // keep dereferencing `receiver_ty` until we get to `self_ty` + // Keep dereferencing `receiver_ty` until we get to `self_ty`. loop { if let Some((potential_self_ty, _)) = autoderef.next() { debug!("receiver_is_valid: potential self type `{:?}` to match `{:?}`", @@ -842,17 +895,19 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>( } else { debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); - return false + // If he receiver already has errors reported due to it, consider it valid to avoid + // unecessary errors (#58712). + return receiver_ty.references_error(); } - // without the `arbitrary_self_types` feature, `receiver_ty` must directly deref to - // `self_ty`. Enforce this by only doing one iteration of the loop + // Without the `arbitrary_self_types` feature, `receiver_ty` must directly deref to + // `self_ty`. Enforce this by only doing one iteration of the loop. if !arbitrary_self_types_enabled { return false } } - // without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver` + // Without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`. if !arbitrary_self_types_enabled { let trait_def_id = match fcx.tcx.lang_items().receiver_trait() { Some(did) => did, @@ -868,7 +923,7 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>( }; let obligation = traits::Obligation::new( - cause.clone(), + cause, fcx.param_env, trait_ref.to_predicate() ); @@ -883,11 +938,12 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>( true } -fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - item: &hir::Item, - hir_generics: &hir::Generics) -{ - let item_def_id = tcx.hir().local_def_id(item.id); +fn check_variances_for_type_defn<'tcx>( + tcx: TyCtxt<'tcx>, + item: &hir::Item, + hir_generics: &hir::Generics, +) { + let item_def_id = tcx.hir().local_def_id_from_hir_id(item.hir_id); let ty = tcx.type_of(item_def_id); if tcx.has_error_field(ty) { return; @@ -903,10 +959,12 @@ fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .map(|(index, _)| Parameter(index as u32)) .collect(); - identify_constrained_type_params(tcx, - &ty_predicates, - None, - &mut constrained_parameters); + identify_constrained_generic_params( + tcx, + &ty_predicates, + None, + &mut constrained_parameters, + ); for (index, _) in variances.iter().enumerate() { if constrained_parameters.contains(&Parameter(index as u32)) { @@ -914,6 +972,7 @@ fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let param = &hir_generics.params[index]; + match param.name { hir::ParamName::Error => { } _ => report_bivariance(tcx, param.span, param.name.ident().name), @@ -921,37 +980,36 @@ fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn report_bivariance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - span: Span, - param_name: ast::Name) -{ +fn report_bivariance<'tcx>(tcx: TyCtxt<'tcx>, span: Span, param_name: ast::Name) { let mut err = error_392(tcx, span, param_name); let suggested_marker_id = tcx.lang_items().phantom_data(); - // help is available only in presence of lang items + // Help is available only in presence of lang items. if let Some(def_id) = suggested_marker_id { err.help(&format!("consider removing `{}` or using a marker such as `{}`", param_name, - tcx.item_path_str(def_id))); + tcx.def_path_str(def_id))); } err.emit(); } -fn reject_shadowing_parameters(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) { +fn reject_shadowing_parameters(tcx: TyCtxt<'_>, def_id: DefId) { let generics = tcx.generics_of(def_id); let parent = tcx.generics_of(generics.parent.unwrap()); let impl_params: FxHashMap<_, _> = parent.params.iter().flat_map(|param| match param.kind { GenericParamDefKind::Lifetime => None, - GenericParamDefKind::Type {..} => Some((param.name, param.def_id)), + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { + Some((param.name, param.def_id)) + } }).collect(); for method_param in &generics.params { - // Shadowing is checked in resolve_lifetime. + // Shadowing is checked in `resolve_lifetime`. if let GenericParamDefKind::Lifetime = method_param.kind { continue } if impl_params.contains_key(&method_param.name) { - // Tighten up the span to focus on only the shadowing type + // Tighten up the span to focus on only the shadowing type. let type_span = tcx.def_span(method_param.def_id); // The expectation here is that the original trait declaration is @@ -965,13 +1023,7 @@ fn reject_shadowing_parameters(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) { /// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that /// aren't true. -fn check_false_global_bounds<'a, 'gcx, 'tcx>( - fcx: &FnCtxt<'a, 'gcx, 'tcx>, - span: Span, - id: hir::HirId) -{ - use rustc::ty::TypeFoldable; - +fn check_false_global_bounds<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, id: hir::HirId) { let empty_env = ty::ParamEnv::empty(); let def_id = fcx.tcx.hir().local_def_id_from_hir_id(id); @@ -979,7 +1031,7 @@ fn check_false_global_bounds<'a, 'gcx, 'tcx>( .iter() .map(|(p, _)| *p) .collect(); - // Check elaborated bounds + // Check elaborated bounds. let implied_obligations = traits::elaborate_predicates(fcx.tcx, predicates); for pred in implied_obligations { @@ -1002,33 +1054,32 @@ fn check_false_global_bounds<'a, 'gcx, 'tcx>( fcx.select_all_obligations_or_error(); } -pub struct CheckTypeWellFormedVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub struct CheckTypeWellFormedVisitor<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { - pub fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) - -> CheckTypeWellFormedVisitor<'a, 'gcx> { +impl CheckTypeWellFormedVisitor<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> CheckTypeWellFormedVisitor<'tcx> { CheckTypeWellFormedVisitor { tcx, } } } -impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'a, 'tcx> { - fn visit_item(&mut self, i: &'tcx hir::Item) { +impl ParItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> { + fn visit_item(&self, i: &'tcx hir::Item) { debug!("visit_item: {:?}", i); - let def_id = self.tcx.hir().local_def_id(i.id); + let def_id = self.tcx.hir().local_def_id_from_hir_id(i.hir_id); self.tcx.ensure().check_item_well_formed(def_id); } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { + fn visit_trait_item(&self, trait_item: &'tcx hir::TraitItem) { debug!("visit_trait_item: {:?}", trait_item); let def_id = self.tcx.hir().local_def_id_from_hir_id(trait_item.hir_id); self.tcx.ensure().check_trait_item_well_formed(def_id); } - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { + fn visit_impl_item(&self, impl_item: &'tcx hir::ImplItem) { debug!("visit_impl_item: {:?}", impl_item); let def_id = self.tcx.hir().local_def_id_from_hir_id(impl_item.hir_id); self.tcx.ensure().check_impl_item_well_formed(def_id); @@ -1047,10 +1098,10 @@ struct AdtField<'tcx> { span: Span, } -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn non_enum_variant(&self, struct_def: &hir::VariantData) -> AdtVariant<'tcx> { let fields = struct_def.fields().iter().map(|field| { - let field_ty = self.tcx.type_of(self.tcx.hir().local_def_id(field.id)); + let field_ty = self.tcx.type_of(self.tcx.hir().local_def_id_from_hir_id(field.hir_id)); let field_ty = self.normalize_associated_types_in(field.span, &field_ty); AdtField { ty: field_ty, span: field.span } @@ -1084,15 +1135,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } -fn error_392<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, param_name: ast::Name) - -> DiagnosticBuilder<'tcx> { +fn error_392<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + param_name: ast::Name, +) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!(tcx.sess, span, E0392, "parameter `{}` is never used", param_name); - err.span_label(span, "unused type parameter"); + err.span_label(span, "unused parameter"); err } -fn error_194(tcx: TyCtxt<'_, '_, '_>, span: Span, trait_decl_span: Span, name: &str) { +fn error_194(tcx: TyCtxt<'_>, span: Span, trait_decl_span: Span, name: &str) { struct_span_err!(tcx.sess, span, E0194, "type parameter `{}` shadows another type parameter of the same name", name) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 5981d9bb66bfc..28711e32a4c51 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -8,14 +8,15 @@ use rustc::hir; use rustc::hir::def_id::{DefId, DefIndex}; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::infer::InferCtxt; -use rustc::ty::adjustment::{Adjust, Adjustment}; +use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder}; use rustc::ty::subst::UnpackedKind; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::mir::interpret::ConstValue; use rustc::util::nodemap::DefIdSet; use rustc_data_structures::sync::Lrc; use std::mem; -use syntax::ast; +use syntax::symbol::sym; use syntax_pos::Span; /////////////////////////////////////////////////////////////////////////// @@ -30,27 +31,33 @@ use syntax_pos::Span; // so instead all of the replacement happens at the end in // resolve_type_vars_in_body, which creates a new TypeTables which // doesn't contain any inference types. -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) -> &'gcx ty::TypeckTables<'gcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn resolve_type_vars_in_body(&self, body: &'tcx hir::Body) -> &'tcx ty::TypeckTables<'tcx> { let item_id = self.tcx.hir().body_owner(body.id()); - let item_def_id = self.tcx.hir().local_def_id(item_id); + let item_def_id = self.tcx.hir().local_def_id_from_hir_id(item_id); // This attribute causes us to dump some writeback information - // in the form of errors, which is used for unit tests. - let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, "rustc_dump_user_substs"); + // in the form of errors, which is uSymbolfor unit tests. + let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_substs); let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs); for arg in &body.arguments { wbcx.visit_node_id(arg.pat.span, arg.hir_id); } + // Type only exists for constants and statics, not functions. + match self.tcx.hir().body_owner_kind(item_id) { + hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => { + wbcx.visit_node_id(body.value.span, item_id); + } + hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (), + } wbcx.visit_body(body); wbcx.visit_upvar_capture_map(); - wbcx.visit_upvar_list_map(); wbcx.visit_closures(); wbcx.visit_liberated_fn_sigs(); wbcx.visit_fru_field_types(); wbcx.visit_opaque_types(body.value.span); - wbcx.visit_cast_types(); + wbcx.visit_coercion_casts(); wbcx.visit_free_region_map(); wbcx.visit_user_provided_tys(); wbcx.visit_user_provided_sigs(); @@ -65,6 +72,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ); wbcx.tables.used_trait_imports = used_trait_imports; + wbcx.tables.upvar_list = mem::replace( + &mut self.tables.borrow_mut().upvar_list, + Default::default(), + ); + wbcx.tables.tainted_by_errors = self.is_tainted_by_errors(); debug!( @@ -72,7 +84,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { item_def_id, wbcx.tables ); - self.tcx.alloc_tables(wbcx.tables) + self.tcx.arena.alloc(wbcx.tables) } } @@ -84,22 +96,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // there, it applies a few ad-hoc checks that were not convenient to // do elsewhere. -struct WritebackCx<'cx, 'gcx: 'cx + 'tcx, 'tcx: 'cx> { - fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, +struct WritebackCx<'cx, 'tcx> { + fcx: &'cx FnCtxt<'cx, 'tcx>, - tables: ty::TypeckTables<'gcx>, + tables: ty::TypeckTables<'tcx>, - body: &'gcx hir::Body, + body: &'tcx hir::Body, rustc_dump_user_substs: bool, } -impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { +impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn new( - fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, - body: &'gcx hir::Body, + fcx: &'cx FnCtxt<'cx, 'tcx>, + body: &'tcx hir::Body, rustc_dump_user_substs: bool, - ) -> WritebackCx<'cx, 'gcx, 'tcx> { + ) -> WritebackCx<'cx, 'tcx> { let owner = body.id().hir_id; WritebackCx { @@ -110,11 +122,11 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.fcx.tcx } - fn write_ty_to_tables(&mut self, hir_id: hir::HirId, ty: Ty<'gcx>) { + fn write_ty_to_tables(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) { debug!("write_ty_to_tables({:?}, {:?})", hir_id, ty); assert!(!ty.needs_infer() && !ty.has_placeholders()); self.tables.node_types_mut().insert(hir_id, ty); @@ -129,7 +141,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { hir::ExprKind::Unary(hir::UnNeg, ref inner) | hir::ExprKind::Unary(hir::UnNot, ref inner) => { let inner_ty = self.fcx.node_ty(inner.hir_id); - let inner_ty = self.fcx.resolve_type_vars_if_possible(&inner_ty); + let inner_ty = self.fcx.resolve_vars_if_possible(&inner_ty); if inner_ty.is_scalar() { let mut tables = self.fcx.tables.borrow_mut(); @@ -140,10 +152,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { hir::ExprKind::Binary(ref op, ref lhs, ref rhs) | hir::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => { let lhs_ty = self.fcx.node_ty(lhs.hir_id); - let lhs_ty = self.fcx.resolve_type_vars_if_possible(&lhs_ty); + let lhs_ty = self.fcx.resolve_vars_if_possible(&lhs_ty); let rhs_ty = self.fcx.node_ty(rhs.hir_id); - let rhs_ty = self.fcx.resolve_type_vars_if_possible(&rhs_ty); + let rhs_ty = self.fcx.resolve_vars_if_possible(&rhs_ty); if lhs_ty.is_scalar() && rhs_ty.is_scalar() { let mut tables = self.fcx.tables.borrow_mut(); @@ -183,7 +195,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { // All valid indexing looks like this; might encounter non-valid indexes at this point if let ty::Ref(_, base_ty, _) = tables.expr_ty_adjusted(&base).sty { let index_ty = tables.expr_ty_adjusted(&index); - let index_ty = self.fcx.resolve_type_vars_if_possible(&index_ty); + let index_ty = self.fcx.resolve_vars_if_possible(&index_ty); if base_ty.builtin_index().is_some() && index_ty == self.fcx.tcx.types.usize { // Remove the method call record @@ -198,7 +210,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { // Since this is "after" the other adjustment to be // discarded, we do an extra `pop()` Some(Adjustment { - kind: Adjust::Unsize, + kind: Adjust::Pointer(PointerCast::Unsize), .. }) => { // So the borrow discard actually happens here @@ -221,12 +233,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { // below. In general, a function is made into a `visitor` if it must // traffic in node-ids or update tables in the type context etc. -impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { +impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } - fn visit_expr(&mut self, e: &'gcx hir::Expr) { + fn visit_expr(&mut self, e: &'tcx hir::Expr) { self.fix_scalar_builtin_expr(e); self.fix_index_builtin_expr(e); @@ -255,12 +267,12 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { intravisit::walk_expr(self, e); } - fn visit_block(&mut self, b: &'gcx hir::Block) { + fn visit_block(&mut self, b: &'tcx hir::Block) { self.visit_node_id(b.span, b.hir_id); intravisit::walk_block(self, b); } - fn visit_pat(&mut self, p: &'gcx hir::Pat) { + fn visit_pat(&mut self, p: &'tcx hir::Pat) { match p.node { hir::PatKind::Binding(..) => { if let Some(&bm) = self.fcx.tables.borrow().pat_binding_modes().get(p.hir_id) { @@ -285,14 +297,14 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { intravisit::walk_pat(self, p); } - fn visit_local(&mut self, l: &'gcx hir::Local) { + fn visit_local(&mut self, l: &'tcx hir::Local) { intravisit::walk_local(self, l); let var_ty = self.fcx.local_ty(l.span, l.hir_id).decl_ty; let var_ty = self.resolve(&var_ty, &l.span); self.write_ty_to_tables(l.hir_id, var_ty); } - fn visit_ty(&mut self, hir_ty: &'gcx hir::Ty) { + fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty) { intravisit::walk_ty(self, hir_ty); let ty = self.fcx.node_ty(hir_ty.hir_id); let ty = self.resolve(&ty, &hir_ty.span); @@ -300,7 +312,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { } } -impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { +impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn visit_upvar_capture_map(&mut self) { for (upvar_id, upvar_capture) in self.fcx.tables.borrow().upvar_capture_map.iter() { let new_upvar_capture = match *upvar_capture { @@ -324,21 +336,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - /// Runs through the function context's upvar list map and adds the same to - /// the TypeckTables. upvarlist is a hashmap of the list of upvars referred - /// to in a closure.. - fn visit_upvar_list_map(&mut self) { - for (closure_def_id, upvar_list) in self.fcx.tables.borrow().upvar_list.iter() { - debug!( - "UpvarIDs captured by closure {:?} are: {:?}", - closure_def_id, upvar_list - ); - self.tables - .upvar_list - .insert(*closure_def_id, upvar_list.to_vec()); - } - } - fn visit_closures(&mut self) { let fcx_tables = self.fcx.tables.borrow(); debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); @@ -355,27 +352,19 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - fn visit_cast_types(&mut self) { + fn visit_coercion_casts(&mut self) { let fcx_tables = self.fcx.tables.borrow(); - let fcx_cast_kinds = fcx_tables.cast_kinds(); + let fcx_coercion_casts = fcx_tables.coercion_casts(); debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); - let mut self_cast_kinds = self.tables.cast_kinds_mut(); - let common_local_id_root = fcx_tables.local_id_root.unwrap(); - for (&local_id, &cast_kind) in fcx_cast_kinds.iter() { - let hir_id = hir::HirId { - owner: common_local_id_root.index, - local_id, - }; - self_cast_kinds.insert(hir_id, cast_kind); + for local_id in fcx_coercion_casts { + self.tables.set_coercion_cast(*local_id); } } fn visit_free_region_map(&mut self) { - let free_region_map = self.tcx() - .lift_to_global(&self.fcx.tables.borrow().free_region_map); - let free_region_map = free_region_map.expect("all regions in free-region-map are global"); - self.tables.free_region_map = free_region_map; + self.tables.free_region_map = self.fcx.tables.borrow().free_region_map.clone(); + debug_assert!(!self.tables.free_region_map.elements().any(|r| r.has_local_value())); } fn visit_user_provided_tys(&mut self) { @@ -390,12 +379,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { local_id, }; - let c_ty = if let Some(c_ty) = self.tcx().lift_to_global(c_ty) { - c_ty - } else { + if cfg!(debug_assertions) && c_ty.has_local_value() { span_bug!( - hir_id.to_span(&self.fcx.tcx), - "writeback: `{:?}` missing from the global type context", + hir_id.to_span(self.fcx.tcx), + "writeback: `{:?}` is a local value", c_ty ); }; @@ -407,7 +394,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { if let ty::UserType::TypeOf(_, user_substs) = c_ty.value { if self.rustc_dump_user_substs { // This is a unit-testing mechanism. - let span = self.tcx().hir().span_by_hir_id(hir_id); + let span = self.tcx().hir().span(hir_id); // We need to buffer the errors in order to guarantee a consistent // order when emitting them. let err = self.tcx().sess.struct_span_err( @@ -432,12 +419,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); for (&def_id, c_sig) in fcx_tables.user_provided_sigs.iter() { - let c_sig = if let Some(c_sig) = self.tcx().lift_to_global(c_sig) { - c_sig - } else { + if cfg!(debug_assertions) && c_sig.has_local_value() { span_bug!( self.fcx.tcx.hir().span_if_local(def_id).unwrap(), - "writeback: `{:?}` missing from the global type context", + "writeback: `{:?}` is a local value", c_sig ); }; @@ -450,44 +435,46 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_opaque_types(&mut self, span: Span) { for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() { - let node_id = self.tcx().hir().as_local_node_id(def_id).unwrap(); - let instantiated_ty = self.resolve(&opaque_defn.concrete_ty, &node_id); + let hir_id = self.tcx().hir().as_local_hir_id(def_id).unwrap(); + let instantiated_ty = self.resolve(&opaque_defn.concrete_ty, &hir_id); + + debug_assert!(!instantiated_ty.has_escaping_bound_vars()); let generics = self.tcx().generics_of(def_id); let definition_ty = if generics.parent.is_some() { - // impl trait + // `impl Trait` self.fcx.infer_opaque_definition_from_instantiation( def_id, opaque_defn, instantiated_ty, ) } else { - // prevent + // Prevent: // * `fn foo() -> Foo` // * `fn foo() -> Foo` - // from being defining + // from being defining. // Also replace all generic params with the ones from the existential type - // definition so + // definition so that // ```rust // existential type Foo: 'static; // fn foo() -> Foo { .. } // ``` - // figures out the concrete type with `U`, but the stored type is with `T` + // figures out the concrete type with `U`, but the stored type is with `T`. instantiated_ty.fold_with(&mut BottomUpFolder { tcx: self.tcx().global_tcx(), - fldop: |ty| { - trace!("checking type {:?}: {:#?}", ty, ty.sty); - // find a type parameter + ty_op: |ty| { + trace!("checking type {:?}", ty); + // Find a type parameter. if let ty::Param(..) = ty.sty { - // look it up in the substitution list + // Look it up in the substitution list. assert_eq!(opaque_defn.substs.len(), generics.params.len()); for (subst, param) in opaque_defn.substs.iter().zip(&generics.params) { if let UnpackedKind::Type(subst) = subst.unpack() { if subst == ty { - // found it in the substitution list, replace with the - // parameter from the existential type + // Found it in the substitution list; replace with the + // parameter from the existential type. return self.tcx() .global_tcx() .mk_ty_param(param.index, param.name); @@ -509,17 +496,17 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } ty }, - reg_op: |region| { + lt_op: |region| { match region { - // ignore static regions - ty::ReStatic => region, + // Skip static and bound regions: they don't require substitution. + ty::ReStatic | ty::ReLateBound(..) => region, _ => { trace!("checking {:?}", region); for (subst, p) in opaque_defn.substs.iter().zip(&generics.params) { if let UnpackedKind::Lifetime(subst) = subst.unpack() { if subst == region { - // found it in the substitution list, replace with the - // parameter from the existential type + // Found it in the substitution list; replace with the + // parameter from the existential type. let reg = ty::EarlyBoundRegion { def_id: p.def_id, index: p.index, @@ -553,39 +540,79 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } }, + ct_op: |ct| { + trace!("checking const {:?}", ct); + // Find a const parameter + if let ConstValue::Param(..) = ct.val { + // look it up in the substitution list + assert_eq!(opaque_defn.substs.len(), generics.params.len()); + for (subst, param) in opaque_defn.substs.iter() + .zip(&generics.params) { + if let UnpackedKind::Const(subst) = subst.unpack() { + if subst == ct { + // found it in the substitution list, replace with the + // parameter from the existential type + return self.tcx() + .global_tcx() + .mk_const_param(param.index, param.name, ct.ty); + } + } + } + self.tcx() + .sess + .struct_span_err( + span, + &format!( + "const parameter `{}` is part of concrete type but not \ + used in parameter list for existential type", + ct, + ), + ) + .emit(); + return self.tcx().consts.err; + } + ct + } }) }; if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.sty { if def_id == defin_ty_def_id { - // Concrete type resolved to the existential type itself - // Force a cycle error + // Concrete type resolved to the existential type itself. + // Force a cycle error. // FIXME(oli-obk): we could just not insert it into `concrete_existential_types` // which simply would make this use not a defining use. self.tcx().at(span).type_of(defin_ty_def_id); } } - let new = ty::ResolvedOpaqueTy { - concrete_type: definition_ty, - substs: self.tcx().lift_to_global(&opaque_defn.substs).unwrap(), - }; - - let old = self.tables - .concrete_existential_types - .insert(def_id, new); - if let Some(old) = old { - if old.concrete_type != definition_ty || old.substs != opaque_defn.substs { - span_bug!( - span, - "visit_opaque_types tried to write \ - different types for the same existential type: {:?}, {:?}, {:?}, {:?}", - def_id, - definition_ty, - opaque_defn, - old, - ); + if !opaque_defn.substs.has_local_value() { + let new = ty::ResolvedOpaqueTy { + concrete_type: definition_ty, + substs: opaque_defn.substs, + }; + + let old = self.tables + .concrete_existential_types + .insert(def_id, new); + if let Some(old) = old { + if old.concrete_type != definition_ty || old.substs != opaque_defn.substs { + span_bug!( + span, + "visit_opaque_types tried to write \ + different types for the same existential type: {:?}, {:?}, {:?}, {:?}", + def_id, + definition_ty, + opaque_defn, + old, + ); + } } + } else { + self.tcx().sess.delay_span_bug( + span, + "`opaque_defn` is a local value", + ); } } } @@ -710,49 +737,42 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - fn resolve(&self, x: &T, span: &dyn Locatable) -> T::Lifted + fn resolve(&self, x: &T, span: &dyn Locatable) -> T where - T: TypeFoldable<'tcx> + ty::Lift<'gcx>, + T: TypeFoldable<'tcx>, { let x = x.fold_with(&mut Resolver::new(self.fcx, span, self.body)); - if let Some(lifted) = self.tcx().lift_to_global(&x) { - lifted - } else { + if cfg!(debug_assertions) && x.has_local_value() { span_bug!( - span.to_span(&self.fcx.tcx), - "writeback: `{:?}` missing from the global type context", + span.to_span(self.fcx.tcx), + "writeback: `{:?}` is a local value", x ); } + x } } trait Locatable { - fn to_span(&self, tcx: &TyCtxt<'_, '_, '_>) -> Span; + fn to_span(&self, tcx: TyCtxt<'_>) -> Span; } impl Locatable for Span { - fn to_span(&self, _: &TyCtxt<'_, '_, '_>) -> Span { + fn to_span(&self, _: TyCtxt<'_>) -> Span { *self } } -impl Locatable for ast::NodeId { - fn to_span(&self, tcx: &TyCtxt<'_, '_, '_>) -> Span { - tcx.hir().span(*self) - } -} - impl Locatable for DefIndex { - fn to_span(&self, tcx: &TyCtxt<'_, '_, '_>) -> Span { + fn to_span(&self, tcx: TyCtxt<'_>) -> Span { let hir_id = tcx.hir().def_index_to_hir_id(*self); - tcx.hir().span_by_hir_id(hir_id) + tcx.hir().span(hir_id) } } impl Locatable for hir::HirId { - fn to_span(&self, tcx: &TyCtxt<'_, '_, '_>) -> Span { - tcx.hir().span_by_hir_id(*self) + fn to_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.hir().span(*self) } } @@ -760,19 +780,19 @@ impl Locatable for hir::HirId { // The Resolver. This is the type folding engine that detects // unresolved types and so forth. -struct Resolver<'cx, 'gcx: 'cx + 'tcx, 'tcx: 'cx> { - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, +struct Resolver<'cx, 'tcx> { + tcx: TyCtxt<'tcx>, + infcx: &'cx InferCtxt<'cx, 'tcx>, span: &'cx dyn Locatable, - body: &'gcx hir::Body, + body: &'tcx hir::Body, } -impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> { +impl<'cx, 'tcx> Resolver<'cx, 'tcx> { fn new( - fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, + fcx: &'cx FnCtxt<'cx, 'tcx>, span: &'cx dyn Locatable, - body: &'gcx hir::Body, - ) -> Resolver<'cx, 'gcx, 'tcx> { + body: &'tcx hir::Body, + ) -> Resolver<'cx, 'tcx> { Resolver { tcx: fcx.tcx, infcx: fcx, @@ -784,14 +804,14 @@ impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> { fn report_error(&self, t: Ty<'tcx>) { if !self.tcx.sess.has_errors() { self.infcx - .need_type_info_err(Some(self.body.id()), self.span.to_span(&self.tcx), t) + .need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t) .emit(); } } } -impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx> { +impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { self.tcx } @@ -812,7 +832,22 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> { // FIXME This should be carefully checked // We could use `self.report_error` but it doesn't accept a ty::Region, right now. fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - self.infcx.fully_resolve(&r).unwrap_or(self.tcx.types.re_static) + self.infcx.fully_resolve(&r).unwrap_or(self.tcx.lifetimes.re_static) + } + + fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + match self.infcx.fully_resolve(&ct) { + Ok(ct) => ct, + Err(_) => { + debug!( + "Resolver::fold_const: input const `{:?}` not fully resolvable", + ct + ); + // FIXME: we'd like to use `self.report_error`, but it doesn't yet + // accept a &'tcx ty::Const. + self.tcx().consts.err + } + } } } diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 4c6d7710009bf..7e781eeec56a9 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -13,7 +13,7 @@ use rustc::util::nodemap::DefIdSet; use rustc_data_structures::fx::FxHashMap; -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) { let mut used_trait_imports = DefIdSet::default(); for &body_id in tcx.hir().krate().bodies.keys() { let item_def_id = tcx.hir().body_owner_def_id(body_id); @@ -28,7 +28,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { unused_crates_lint(tcx); } -impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CheckVisitor<'a, 'tcx> { +impl ItemLikeVisitor<'v> for CheckVisitor<'tcx> { fn visit_item(&mut self, item: &hir::Item) { if item.vis.node.is_pub() || item.span.is_dummy() { return; @@ -45,12 +45,12 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CheckVisitor<'a, 'tcx> { } } -struct CheckVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct CheckVisitor<'tcx> { + tcx: TyCtxt<'tcx>, used_trait_imports: DefIdSet, } -impl<'a, 'tcx> CheckVisitor<'a, 'tcx> { +impl CheckVisitor<'tcx> { fn check_import(&self, id: hir::HirId, span: Span) { let def_id = self.tcx.hir().local_def_id_from_hir_id(id); if !self.tcx.maybe_unused_trait_import(def_id) { @@ -70,7 +70,7 @@ impl<'a, 'tcx> CheckVisitor<'a, 'tcx> { } } -fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) { +fn unused_crates_lint<'tcx>(tcx: TyCtxt<'tcx>) { let lint = lint::builtin::UNUSED_EXTERN_CRATES; // Collect first the crates that are completely unused. These we @@ -94,7 +94,7 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) { // Note that if we carry through to the `extern_mod_stmt_cnum` query // below it'll cause a panic because `def_id` is actually bogus at this // point in time otherwise. - if let Some(id) = tcx.hir().as_local_node_id(def_id) { + if let Some(id) = tcx.hir().as_local_hir_id(def_id) { if tcx.hir().find(id).is_none() { return false; } @@ -121,7 +121,7 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) { for extern_crate in &crates_to_lint { let id = tcx.hir().as_local_hir_id(extern_crate.def_id).unwrap(); - let item = tcx.hir().expect_item_by_hir_id(id); + let item = tcx.hir().expect_item(id); // If the crate is fully unused, we suggest removing it altogether. // We do this in any edition. @@ -158,6 +158,13 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) { continue; } + // If the extern crate is renamed, then we cannot suggest replacing it with a use as this + // would not insert the new name into the prelude, where other imports in the crate may be + // expecting it. + if extern_crate.orig_name.is_some() { + continue; + } + // If the extern crate has any attributes, they may have funky // semantics we can't faithfully represent using `use` (most // notably `#[macro_use]`). Ignore it. @@ -187,8 +194,8 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) { } } -struct CollectExternCrateVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct CollectExternCrateVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, crates_to_lint: &'a mut Vec, } @@ -212,7 +219,7 @@ struct ExternCrateToLint { impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CollectExternCrateVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { if let hir::ItemKind::ExternCrate(orig_name) = item.node { - let extern_crate_def_id = self.tcx.hir().local_def_id(item.id); + let extern_crate_def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); self.crates_to_lint.push( ExternCrateToLint { def_id: extern_crate_def_id, diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 0996d1ff3b998..42deeaf31f427 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -17,7 +17,7 @@ use rustc::hir::def_id::DefId; use hir::Node; use rustc::hir::{self, ItemKind}; -pub fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId) { +pub fn check_trait<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId) { Checker { tcx, trait_def_id } .check(tcx.lang_items().drop_trait(), visit_implementation_of_drop) .check(tcx.lang_items().copy_trait(), visit_implementation_of_copy) @@ -26,18 +26,19 @@ pub fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId) { visit_implementation_of_dispatch_from_dyn); } -struct Checker<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_def_id: DefId +struct Checker<'tcx> { + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, } -impl<'a, 'tcx> Checker<'a, 'tcx> { +impl<'tcx> Checker<'tcx> { fn check(&self, trait_def_id: Option, mut f: F) -> &Self - where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId) + where + F: FnMut(TyCtxt<'tcx>, DefId), { if Some(self.trait_def_id) == trait_def_id { for &impl_id in self.tcx.hir().trait_impls(self.trait_def_id) { - let impl_def_id = self.tcx.hir().local_def_id(impl_id); + let impl_def_id = self.tcx.hir().local_def_id_from_hir_id(impl_id); f(self.tcx, impl_def_id); } } @@ -45,13 +46,13 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { } } -fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did: DefId) { +fn visit_implementation_of_drop<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) { if let ty::Adt(..) = tcx.type_of(impl_did).sty { /* do nothing */ } else { // Destructors only work on nominal types. - if let Some(impl_node_id) = tcx.hir().as_local_node_id(impl_did) { - if let Some(Node::Item(item)) = tcx.hir().find(impl_node_id) { + if let Some(impl_hir_id) = tcx.hir().as_local_hir_id(impl_did) { + if let Some(Node::Item(item)) = tcx.hir().find(impl_hir_id) { let span = match item.node { ItemKind::Impl(.., ref ty, _) => ty.span, _ => item.span, @@ -73,7 +74,7 @@ fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did: } } -fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did: DefId) { +fn visit_implementation_of_copy<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) { debug!("visit_implementation_of_copy: impl_did={:?}", impl_did); let impl_hir_id = if let Some(n) = tcx.hir().as_local_hir_id(impl_did) { @@ -87,7 +88,7 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did: debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type); - let span = tcx.hir().span_by_hir_id(impl_hir_id); + let span = tcx.hir().span(impl_hir_id); let param_env = tcx.param_env(impl_did); assert!(!self_type.has_escaping_bound_vars()); @@ -97,7 +98,7 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did: match param_env.can_type_implement_copy(tcx, self_type) { Ok(()) => {} Err(CopyImplementationError::InfrigingFields(fields)) => { - let item = tcx.hir().expect_item_by_hir_id(impl_hir_id); + let item = tcx.hir().expect_item(impl_hir_id); let span = if let ItemKind::Impl(.., Some(ref tr), _, _) = item.node { tr.path.span } else { @@ -114,7 +115,7 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did: err.emit() } Err(CopyImplementationError::NotAnAdt) => { - let item = tcx.hir().expect_item_by_hir_id(impl_hir_id); + let item = tcx.hir().expect_item(impl_hir_id); let span = if let ItemKind::Impl(.., ref ty, _) = item.node { ty.span } else { @@ -140,7 +141,7 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did: } } -fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did: DefId) { +fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'tcx>, impl_did: DefId) { debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did); @@ -153,17 +154,14 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn visit_implementation_of_dispatch_from_dyn<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_did: DefId, -) { +fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) { debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did); if impl_did.is_local() { let dispatch_from_dyn_trait = tcx.lang_items().dispatch_from_dyn_trait().unwrap(); let impl_hir_id = tcx.hir().as_local_hir_id(impl_did).unwrap(); - let span = tcx.hir().span_by_hir_id(impl_hir_id); + let span = tcx.hir().span(impl_hir_id); let source = tcx.type_of(impl_did); assert!(!source.has_escaping_bound_vars()); @@ -198,8 +196,8 @@ fn visit_implementation_of_dispatch_from_dyn<'a, 'tcx>( if def_a.is_struct() && def_b.is_struct() => { if def_a != def_b { - let source_path = tcx.item_path_str(def_a.did); - let target_path = tcx.item_path_str(def_b.did); + let source_path = tcx.def_path_str(def_a.did); + let target_path = tcx.def_path_str(def_b.did); create_err( &format!( @@ -223,19 +221,22 @@ fn visit_implementation_of_dispatch_from_dyn<'a, 'tcx>( let fields = &def_a.non_enum_variant().fields; let coerced_fields = fields.iter().filter_map(|field| { - if tcx.type_of(field.did).is_phantom_data() { - // ignore PhantomData fields - return None - } - let ty_a = field.ty(tcx, substs_a); let ty_b = field.ty(tcx, substs_b); + + if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) { + if layout.is_zst() && layout.details.align.abi.bytes() == 1 { + // ignore ZST fields with alignment of 1 byte + return None; + } + } + if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) { if ok.obligations.is_empty() { create_err( "the trait `DispatchFromDyn` may only be implemented \ for structs containing the field being coerced, \ - `PhantomData` fields, and nothing else" + ZST fields with 1 byte alignment, and nothing else" ).note( &format!( "extra field `{}` of type `{}` is not allowed", @@ -321,9 +322,7 @@ fn visit_implementation_of_dispatch_from_dyn<'a, 'tcx>( } } -pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>, - impl_did: DefId) - -> CoerceUnsizedInfo { +pub fn coerce_unsized_info<'tcx>(gcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo { debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did); let coerce_unsized_trait = gcx.lang_items().coerce_unsized_trait().unwrap(); @@ -344,7 +343,7 @@ pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>, source, target); - let span = gcx.hir().span_by_hir_id(impl_hir_id); + let span = gcx.hir().span(impl_hir_id); let param_env = gcx.param_env(impl_did); assert!(!source.has_escaping_bound_vars()); @@ -356,9 +355,9 @@ pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>, gcx.infer_ctxt().enter(|infcx| { let cause = ObligationCause::misc(span, impl_hir_id); - let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>, - mt_b: ty::TypeAndMut<'gcx>, - mk_ptr: &dyn Fn(Ty<'gcx>) -> Ty<'gcx>| { + let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, + mt_b: ty::TypeAndMut<'tcx>, + mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| { if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) { infcx.report_mismatched_types(&cause, mk_ptr(mt_b.ty), @@ -388,8 +387,8 @@ pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>, (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) if def_a.is_struct() && def_b.is_struct() => { if def_a != def_b { - let source_path = gcx.item_path_str(def_a.did); - let target_path = gcx.item_path_str(def_b.did); + let source_path = gcx.def_path_str(def_a.did); + let target_path = gcx.def_path_str(def_b.did); span_err!(gcx.sess, span, E0377, @@ -481,11 +480,11 @@ pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>, being coerced, none found"); return err_info; } else if diff_fields.len() > 1 { - let item = gcx.hir().expect_item_by_hir_id(impl_hir_id); + let item = gcx.hir().expect_item(impl_hir_id); let span = if let ItemKind::Impl(.., Some(ref t), _, _) = item.node { t.path.span } else { - gcx.hir().span_by_hir_id(impl_hir_id) + gcx.hir().span(impl_hir_id) }; let mut err = struct_span_err!(gcx.sess, diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index 93cc86423ace3..6088c03fc0681 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -13,14 +13,14 @@ use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::ty::{self, CrateInherentImpls, TyCtxt}; -use rustc_data_structures::sync::Lrc; use syntax::ast; use syntax_pos::Span; /// On-demand query: yields a map containing all types mapped to their inherent impls. -pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - crate_num: CrateNum) - -> Lrc { +pub fn crate_inherent_impls<'tcx>( + tcx: TyCtxt<'tcx>, + crate_num: CrateNum, +) -> &'tcx CrateInherentImpls { assert_eq!(crate_num, LOCAL_CRATE); let krate = tcx.hir().krate(); @@ -29,13 +29,11 @@ pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impls_map: Default::default(), }; krate.visit_all_item_likes(&mut collect); - Lrc::new(collect.impls_map) + tcx.arena.alloc(collect.impls_map) } /// On-demand query: yields a vector of the inherent impls for a specific type. -pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty_def_id: DefId) - -> Lrc> { +pub fn inherent_impls<'tcx>(tcx: TyCtxt<'tcx>, ty_def_id: DefId) -> &'tcx [DefId] { assert!(ty_def_id.is_local()); // NB. Until we adopt the red-green dep-tracking algorithm (see @@ -53,15 +51,11 @@ pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // // [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4 - thread_local! { - static EMPTY_DEF_ID_VEC: Lrc> = Lrc::new(vec![]) - } - let result = tcx.dep_graph.with_ignore(|| { let crate_map = tcx.crate_inherent_impls(ty_def_id.krate); match crate_map.inherent_impls.get(&ty_def_id) { - Some(v) => v.clone(), - None => EMPTY_DEF_ID_VEC.with(|v| v.clone()) + Some(v) => &v[..], + None => &[], } }); @@ -73,19 +67,19 @@ pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result } -struct InherentCollect<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct InherentCollect<'tcx> { + tcx: TyCtxt<'tcx>, impls_map: CrateInherentImpls, } -impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { +impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { fn visit_item(&mut self, item: &hir::Item) { let ty = match item.node { hir::ItemKind::Impl(.., None, ref ty, _) => ty, _ => return }; - let def_id = self.tcx.hir().local_def_id(item.id); + let def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); let self_ty = self.tcx.type_of(def_id); let lang_items = self.tcx.lang_items(); match self_ty.sty { @@ -282,20 +276,15 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { } } -impl<'a, 'tcx> InherentCollect<'a, 'tcx> { +impl InherentCollect<'tcx> { fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) { if def_id.is_local() { // Add the implementation to the mapping from implementation to base // type def ID, if there is a base type for this implementation and // the implementation does not have any associated traits. - let impl_def_id = self.tcx.hir().local_def_id(item.id); - let mut rc_vec = self.impls_map.inherent_impls - .entry(def_id) - .or_default(); - - // At this point, there should not be any clones of the - // `Lrc`, so we can still safely push into it in place: - Lrc::get_mut(&mut rc_vec).unwrap().push(impl_def_id); + let impl_def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); + let vec = self.impls_map.inherent_impls.entry(def_id).or_default(); + vec.push(impl_def_id); } else { struct_span_err!(self.tcx.sess, item.span, diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index a51f45a6ff8f3..aae1b1777a30f 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -5,27 +5,23 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::traits::{self, IntercrateMode}; use rustc::ty::TyCtxt; -use crate::lint; - -pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - crate_num: CrateNum) { +pub fn crate_inherent_impls_overlap_check<'tcx>(tcx: TyCtxt<'tcx>, crate_num: CrateNum) { assert_eq!(crate_num, LOCAL_CRATE); let krate = tcx.hir().krate(); krate.visit_all_item_likes(&mut InherentOverlapChecker { tcx }); } -struct InherentOverlapChecker<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx> +struct InherentOverlapChecker<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { +impl InherentOverlapChecker<'tcx> { fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId, - overlap: traits::OverlapResult<'_>, - used_to_be_allowed: bool) { + overlap: traits::OverlapResult<'_>) { let name_and_namespace = |def_id| { let item = self.tcx.associated_item(def_id); - (item.ident, Namespace::from(item.kind)) + (item.ident.modern(), Namespace::from(item.kind)) }; let impl_items1 = self.tcx.associated_item_def_ids(impl1); @@ -36,22 +32,12 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { for &item2 in &impl_items2[..] { if (name, namespace) == name_and_namespace(item2) { - let hir_id = self.tcx.hir().as_local_hir_id(impl1); - let mut err = if used_to_be_allowed && hir_id.is_some() { - self.tcx.struct_span_lint_hir( - lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS, - hir_id.unwrap(), - self.tcx.span_of_impl(item1).unwrap(), - &format!("duplicate definitions with name `{}` (E0592)", name) - ) - } else { + let mut err = struct_span_err!(self.tcx.sess, self.tcx.span_of_impl(item1).unwrap(), E0592, "duplicate definitions with name `{}`", - name) - }; - + name); err.span_label(self.tcx.span_of_impl(item1).unwrap(), format!("duplicate definitions for `{}`", name)); err.span_label(self.tcx.span_of_impl(item2).unwrap(), @@ -76,7 +62,7 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { for (i, &impl1_def_id) in impls.iter().enumerate() { for &impl2_def_id in &impls[(i + 1)..] { - let used_to_be_allowed = traits::overlapping_impls( + traits::overlapping_impls( self.tcx, impl1_def_id, impl2_def_id, @@ -86,41 +72,24 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { impl1_def_id, impl2_def_id, overlap, - false, ); false }, || true, ); - - if used_to_be_allowed { - traits::overlapping_impls( - self.tcx, - impl1_def_id, - impl2_def_id, - IntercrateMode::Fixed, - |overlap| self.check_for_common_items_in_impls( - impl1_def_id, - impl2_def_id, - overlap, - true, - ), - || (), - ); - } } } } } -impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> { +impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Trait(..) | hir::ItemKind::Union(..) => { - let type_def_id = self.tcx.hir().local_def_id(item.id); + let type_def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); self.check_for_overlapping_inherent_impls(type_def_id); } _ => {} diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 01aba658850bf..4336e861ce216 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -5,22 +5,21 @@ // done by the orphan and overlap modules. Then we build up various // mappings. That mapping code resides here. +use crate::hir::HirId; use crate::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::traits; use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc::ty::query::Providers; use rustc::util::common::time; -use syntax::ast; - mod builtin; mod inherent_impls; mod inherent_impls_overlap; mod orphan; mod unsafety; -fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) { - let impl_def_id = tcx.hir().local_def_id(node_id); +fn check_impl<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId) { + let impl_def_id = tcx.hir().local_def_id_from_hir_id(hir_id); // If there are no traits, then this implementation must have a // base type. @@ -28,7 +27,7 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) { if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { debug!("(checking implementation) adding impl for trait '{:?}', item '{}'", trait_ref, - tcx.item_path_str(impl_def_id)); + tcx.def_path_str(impl_def_id)); // Skip impls where one of the self type is an error type. // This occurs with e.g., resolve failures (#30589). @@ -41,11 +40,7 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) { } } -fn enforce_trait_manually_implementable( - tcx: TyCtxt<'_, '_, '_>, - impl_def_id: DefId, - trait_def_id: DefId -) { +fn enforce_trait_manually_implementable(tcx: TyCtxt<'_>, impl_def_id: DefId, trait_def_id: DefId) { let did = Some(trait_def_id); let li = tcx.lang_items(); let span = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap()); @@ -97,11 +92,7 @@ fn enforce_trait_manually_implementable( /// We allow impls of marker traits to overlap, so they can't override impls /// as that could make it ambiguous which associated item to use. -fn enforce_empty_impls_for_marker_traits( - tcx: TyCtxt<'_, '_, '_>, - impl_def_id: DefId, - trait_def_id: DefId -) { +fn enforce_empty_impls_for_marker_traits(tcx: TyCtxt<'_>, impl_def_id: DefId, trait_def_id: DefId) { if !tcx.trait_def(trait_def_id).is_marker { return; } @@ -133,7 +124,7 @@ pub fn provide(providers: &mut Providers<'_>) { }; } -fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { +fn coherent_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) { let impls = tcx.hir().trait_impls(def_id); for &impl_id in impls { check_impl(tcx, impl_id); @@ -141,12 +132,10 @@ fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { for &impl_id in impls { check_impl_overlap(tcx, impl_id); } - use rustc::util::common::time; - time(tcx.sess, "builtin::check_trait checking", || - builtin::check_trait(tcx, def_id)); + builtin::check_trait(tcx, def_id); } -pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn check_coherence<'tcx>(tcx: TyCtxt<'tcx>) { for &trait_def_id in tcx.hir().krate().trait_impls.keys() { tcx.ensure().coherent_trait(trait_def_id); } @@ -162,8 +151,8 @@ pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { /// Overlap: no two impls for the same trait are implemented for the /// same type. Likewise, no two inherent impls for a given type /// constructor provide a method with the same name. -fn check_impl_overlap<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) { - let impl_def_id = tcx.hir().local_def_id(node_id); +fn check_impl_overlap<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId) { + let impl_def_id = tcx.hir().local_def_id_from_hir_id(hir_id); let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); let trait_def_id = trait_ref.def_id; @@ -206,10 +195,10 @@ fn check_impl_overlap<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeI E0371, "the object type `{}` automatically implements the trait `{}`", trait_ref.self_ty(), - tcx.item_path_str(trait_def_id)) + tcx.def_path_str(trait_def_id)) .span_label(sp, format!("`{}` automatically implements trait `{}`", trait_ref.self_ty(), - tcx.item_path_str(trait_def_id))) + tcx.def_path_str(trait_def_id))) .emit(); } } diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index b776a980b7c97..4e6fcfe0593e2 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -6,27 +6,27 @@ use rustc::ty::{self, TyCtxt}; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; -pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn check<'tcx>(tcx: TyCtxt<'tcx>) { let mut orphan = OrphanChecker { tcx }; tcx.hir().krate().visit_all_item_likes(&mut orphan); } -struct OrphanChecker<'cx, 'tcx: 'cx> { - tcx: TyCtxt<'cx, 'tcx, 'tcx>, +struct OrphanChecker<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { +impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { /// Checks exactly one impl for orphan rules and other such /// restrictions. In this fn, it can happen that multiple errors /// apply to a specific impl, so just return after reporting one /// to prevent inundating the user with a bunch of similar error /// reports. fn visit_item(&mut self, item: &hir::Item) { - let def_id = self.tcx.hir().local_def_id(item.id); + let def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); // "Trait" impl if let hir::ItemKind::Impl(.., Some(_), _, _) = item.node { debug!("coherence2::orphan check: trait impl {}", - self.tcx.hir().node_to_string(item.id)); + self.tcx.hir().node_to_string(item.hir_id)); let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap(); let trait_def_id = trait_ref.def_id; let cm = self.tcx.sess.source_map(); @@ -121,7 +121,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { format!("cross-crate traits with a default impl, like `{}`, \ can only be implemented for a struct/enum type \ defined in the current crate", - self.tcx.item_path_str(trait_def_id)), + self.tcx.def_path_str(trait_def_id)), "can't implement cross-crate trait for type in another crate" )) } @@ -129,7 +129,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { _ => { Some((format!("cross-crate traits with a default impl, like `{}`, can \ only be implemented for a struct/enum type, not `{}`", - self.tcx.item_path_str(trait_def_id), + self.tcx.def_path_str(trait_def_id), self_ty), "can't implement cross-crate trait with a default impl for \ non-struct/enum type")) diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 81ef4de3d80e5..c41a0e1514e68 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -5,23 +5,24 @@ use rustc::ty::TyCtxt; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::{self, Unsafety}; -pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn check<'tcx>(tcx: TyCtxt<'tcx>) { let mut unsafety = UnsafetyChecker { tcx }; tcx.hir().krate().visit_all_item_likes(&mut unsafety); } -struct UnsafetyChecker<'cx, 'tcx: 'cx> { - tcx: TyCtxt<'cx, 'tcx, 'tcx>, +struct UnsafetyChecker<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { +impl UnsafetyChecker<'tcx> { fn check_unsafety_coherence(&mut self, item: &'v hir::Item, impl_generics: Option<&hir::Generics>, unsafety: hir::Unsafety, polarity: hir::ImplPolarity) { - if let Some(trait_ref) = self.tcx.impl_trait_ref(self.tcx.hir().local_def_id(item.id)) { + let local_did = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); + if let Some(trait_ref) = self.tcx.impl_trait_ref(local_did) { let trait_def = self.tcx.trait_def(trait_ref.def_id); let unsafe_attr = impl_generics.and_then(|generics| { generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle") @@ -68,7 +69,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { } } -impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> { +impl ItemLikeVisitor<'v> for UnsafetyChecker<'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { if let hir::ItemKind::Impl(unsafety, polarity, _, ref generics, ..) = item.node { self.check_unsafety_coherence(item, Some(generics), unsafety, polarity); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 16102ad4cde30..87e1166b7c041 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1,6 +1,6 @@ //! "Collection" is the process of determining the type and other external //! details of each item in Rust. Collection is specifically concerned -//! with *interprocedural* things -- for example, for a function +//! with *inter-procedural* things -- for example, for a function //! definition, collection will figure out the type and signature of the //! function, but it will not visit the *body* of the function in any way, //! nor examine type annotations on local variables (that's the job of @@ -14,11 +14,10 @@ //! At present, however, we do run collection across all items in the //! crate as a kind of pass. This should eventually be factored away. -use crate::astconv::{AstConv, Bounds}; -use crate::constrained_type_params as ctp; +use crate::astconv::{AstConv, Bounds, SizedByDefault}; +use crate::constrained_generic_params as cgp; use crate::check::intrinsic::intrisic_operation_unsafety; use crate::lint; -use crate::middle::lang_items::SizedTraitLangItem; use crate::middle::resolve_lifetime as rl; use crate::middle::weak_lang_items; use rustc::mir::mono::Linkage; @@ -27,11 +26,10 @@ use rustc::ty::subst::{Subst, InternalSubsts}; use rustc::ty::util::Discr; use rustc::ty::util::IntTypeExt; use rustc::ty::subst::UnpackedKind; -use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, Const}; use rustc::ty::{ReprOptions, ToPredicate}; use rustc::util::captures::Captures; use rustc::util::nodemap::FxHashMap; -use rustc_data_structures::sync::Lrc; use rustc_target::spec::abi; use syntax::ast; @@ -39,16 +37,18 @@ use syntax::ast::{Ident, MetaItemKind}; use syntax::attr::{InlineAttr, OptimizeAttr, list_contains_name, mark_used}; use syntax::source_map::Spanned; use syntax::feature_gate; -use syntax::symbol::{keywords, Symbol}; +use syntax::symbol::{InternedString, kw, Symbol, sym}; use syntax_pos::{Span, DUMMY_SP}; -use rustc::hir::def::{CtorKind, Def}; +use rustc::hir::def::{CtorKind, Res, DefKind}; use rustc::hir::Node; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::hir::GenericParamKind; use rustc::hir::{self, CodegenFnAttrFlags, CodegenFnAttrs, Unsafety}; +use errors::{Applicability, DiagnosticId}; + use std::iter; struct OnlySelfBounds(bool); @@ -56,13 +56,7 @@ struct OnlySelfBounds(bool); /////////////////////////////////////////////////////////////////////////// // Main entry point -pub fn collect_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - for &module in tcx.hir().krate().modules.keys() { - tcx.ensure().collect_mod_item_types(tcx.hir().local_def_id(module)); - } -} - -fn collect_mod_item_types<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) { +fn collect_mod_item_types<'tcx>(tcx: TyCtxt<'tcx>, module_def_id: DefId) { tcx.hir().visit_item_likes_in_module( module_def_id, &mut CollectItemTypesVisitor { tcx }.as_deep_visitor() @@ -84,6 +78,7 @@ pub fn provide(providers: &mut Providers<'_>) { impl_trait_ref, impl_polarity, is_foreign_item, + static_mutability, codegen_fn_attrs, collect_mod_item_types, ..*providers @@ -101,24 +96,24 @@ pub fn provide(providers: &mut Providers<'_>) { /// `ItemCtxt` is parameterized by a `DefId` that it uses to satisfy /// `get_type_parameter_bounds` requests, drawing the information from /// the AST (`hir::Generics`), recursively. -pub struct ItemCtxt<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub struct ItemCtxt<'tcx> { + tcx: TyCtxt<'tcx>, item_def_id: DefId, } /////////////////////////////////////////////////////////////////////////// -struct CollectItemTypesVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct CollectItemTypesVisitor<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { +impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::OnlyBodies(&self.tcx.hir()) } fn visit_item(&mut self, item: &'tcx hir::Item) { - convert_item(self.tcx, item.id); + convert_item(self.tcx, item.hir_id); intravisit::walk_item(self, item); } @@ -165,25 +160,23 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { /////////////////////////////////////////////////////////////////////////// // Utility types and common code for the above passes. -impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId) -> ItemCtxt<'a, 'tcx> { +impl ItemCtxt<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> ItemCtxt<'tcx> { ItemCtxt { tcx, item_def_id } } -} -impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { - pub fn to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> { + pub fn to_ty(&self, ast_ty: &'tcx hir::Ty) -> Ty<'tcx> { AstConv::ast_ty_to_ty(self, ast_ty) } } -impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { +impl AstConv<'tcx> for ItemCtxt<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) - -> Lrc> { + -> &'tcx ty::GenericPredicates<'tcx> { self.tcx .at(span) .type_param_predicates((self.item_def_id, def_id)) @@ -191,24 +184,39 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { fn re_infer( &self, - _span: Span, - _def: Option<&ty::GenericParamDef>, + _: Option<&ty::GenericParamDef>, + _: Span, ) -> Option> { None } - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - struct_span_err!( - self.tcx().sess, + fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { + self.tcx().sess.struct_span_err_with_code( span, - E0121, - "the type placeholder `_` is not allowed within types on item signatures" + "the type placeholder `_` is not allowed within types on item signatures", + DiagnosticId::Error("E0121".into()), ).span_label(span, "not allowed in type signatures") .emit(); self.tcx().types.err } + fn ct_infer( + &self, + _: Ty<'tcx>, + _: Option<&ty::GenericParamDef>, + span: Span, + ) -> &'tcx Const<'tcx> { + self.tcx().sess.struct_span_err_with_code( + span, + "the const placeholder `_` is not allowed within types on item signatures", + DiagnosticId::Error("E0121".into()), + ).span_label(span, "not allowed in type signatures") + .emit(); + + self.tcx().consts.err + } + fn projected_ty_from_poly_trait_ref( &self, span: Span, @@ -237,7 +245,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { } fn set_tainted_by_errors(&self) { - // no obvious place to track this, just let it go + // no obvious place to track this, so just let it go } fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) { @@ -245,19 +253,19 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { } } -fn type_param_predicates<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn type_param_predicates<'tcx>( + tcx: TyCtxt<'tcx>, (item_def_id, def_id): (DefId, DefId), -) -> Lrc> { +) -> &'tcx ty::GenericPredicates<'tcx> { use rustc::hir::*; // In the AST, bounds can derive from two places. Either // written inline like `` or in a where clause like // `where T : Foo`. - let param_id = tcx.hir().as_local_node_id(def_id).unwrap(); + let param_id = tcx.hir().as_local_hir_id(def_id).unwrap(); let param_owner = tcx.hir().ty_param_owner(param_id); - let param_owner_def_id = tcx.hir().local_def_id(param_owner); + let param_owner_def_id = tcx.hir().local_def_id_from_hir_id(param_owner); let generics = tcx.generics_of(param_owner_def_id); let index = generics.param_def_id_to_index[&def_id]; let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(param_id).as_interned_str()); @@ -269,19 +277,14 @@ fn type_param_predicates<'a, 'tcx>( tcx.generics_of(item_def_id).parent }; - let mut result = parent.map_or_else( - || Lrc::new(ty::GenericPredicates { - parent: None, - predicates: vec![], - }), - |parent| { - let icx = ItemCtxt::new(tcx, parent); - icx.get_type_parameter_bounds(DUMMY_SP, def_id) - }, - ); + let result = parent.map_or(&tcx.common.empty_predicates, |parent| { + let icx = ItemCtxt::new(tcx, parent); + icx.get_type_parameter_bounds(DUMMY_SP, def_id) + }); + let mut extend = None; - let item_node_id = tcx.hir().as_local_node_id(item_def_id).unwrap(); - let ast_generics = match tcx.hir().get(item_node_id) { + let item_hir_id = tcx.hir().as_local_hir_id(item_def_id).unwrap(); + let ast_generics = match tcx.hir().get(item_hir_id) { Node::TraitItem(item) => &item.generics, Node::ImplItem(item) => &item.generics, @@ -301,11 +304,9 @@ fn type_param_predicates<'a, 'tcx>( | ItemKind::Union(_, ref generics) => generics, ItemKind::Trait(_, _, ref generics, ..) => { // Implied `Self: Trait` and supertrait bounds. - if param_id == item_node_id { + if param_id == item_hir_id { let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id); - Lrc::make_mut(&mut result) - .predicates - .push((identity_trait_ref.to_predicate(), item.span)); + extend = Some((identity_trait_ref.to_predicate(), item.span)); } generics } @@ -322,22 +323,22 @@ fn type_param_predicates<'a, 'tcx>( }; let icx = ItemCtxt::new(tcx, item_def_id); - let param_hir_id = tcx.hir().node_to_hir_id(param_id); - Lrc::make_mut(&mut result) - .predicates - .extend(icx.type_parameter_bounds_in_generics(ast_generics, param_hir_id, ty, - OnlySelfBounds(true))); - result + let mut result = (*result).clone(); + result.predicates.extend(extend.into_iter()); + result.predicates + .extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, + OnlySelfBounds(true))); + tcx.arena.alloc(result) } -impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { +impl ItemCtxt<'tcx> { /// Finds bounds from `hir::Generics`. This requires scanning through the /// AST. We do this to avoid having to convert *all* the bounds, which /// would create artificial cycles. Instead we can only convert the /// bounds for a type parameter `X` if `X::Foo` is used. fn type_parameter_bounds_in_generics( &self, - ast_generics: &hir::Generics, + ast_generics: &'tcx hir::Generics, param_id: hir::HirId, ty: Ty<'tcx>, only_self_bounds: OnlySelfBounds, @@ -380,14 +381,10 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { /// parameter with ID `param_id`. We use this so as to avoid running /// `ast_ty_to_ty`, because we want to avoid triggering an all-out /// conversion of the type to avoid inducing unnecessary cycles. -fn is_param<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ast_ty: &hir::Ty, - param_id: hir::HirId, -) -> bool { +fn is_param<'tcx>(tcx: TyCtxt<'tcx>, ast_ty: &hir::Ty, param_id: hir::HirId) -> bool { if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = ast_ty.node { - match path.def { - Def::SelfTy(Some(def_id), None) | Def::TyParam(def_id) => { + match path.res { + Res::SelfTy(Some(def_id), None) | Res::Def(DefKind::TyParam, def_id) => { def_id == tcx.hir().local_def_id_from_hir_id(param_id) } _ => false, @@ -397,10 +394,10 @@ fn is_param<'a, 'tcx>( } } -fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { +fn convert_item<'tcx>(tcx: TyCtxt<'tcx>, item_id: hir::HirId) { let it = tcx.hir().expect_item(item_id); - debug!("convert: item {} with id {}", it.ident, it.id); - let def_id = tcx.hir().local_def_id(item_id); + debug!("convert: item {} with id {}", it.ident, it.hir_id); + let def_id = tcx.hir().local_def_id_from_hir_id(item_id); match it.node { // These don't define types. hir::ItemKind::ExternCrate(_) @@ -409,7 +406,7 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { | hir::ItemKind::GlobalAsm(_) => {} hir::ItemKind::ForeignMod(ref foreign_mod) => { for item in &foreign_mod.items { - let def_id = tcx.hir().local_def_id(item.id); + let def_id = tcx.hir().local_def_id_from_hir_id(item.hir_id); tcx.generics_of(def_id); tcx.type_of(def_id); tcx.predicates_of(def_id); @@ -447,18 +444,18 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { tcx.predicates_of(def_id); for f in struct_def.fields() { - let def_id = tcx.hir().local_def_id(f.id); + let def_id = tcx.hir().local_def_id_from_hir_id(f.hir_id); tcx.generics_of(def_id); tcx.type_of(def_id); tcx.predicates_of(def_id); } - if !struct_def.is_struct() { - convert_variant_ctor(tcx, struct_def.id()); + if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { + convert_variant_ctor(tcx, ctor_hir_id); } } - // Desugared from `impl Trait` -> visited by the function's return type + // Desugared from `impl Trait`, so visited by the function's return type. hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(_), .. @@ -479,8 +476,8 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { } } -fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item_id: hir::HirId) { - let trait_item = tcx.hir().expect_trait_item_by_hir_id(trait_item_id); +fn convert_trait_item<'tcx>(tcx: TyCtxt<'tcx>, trait_item_id: hir::HirId) { + let trait_item = tcx.hir().expect_trait_item(trait_item_id); let def_id = tcx.hir().local_def_id_from_hir_id(trait_item.hir_id); tcx.generics_of(def_id); @@ -500,28 +497,24 @@ fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item_id: hir: tcx.predicates_of(def_id); } -fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item_id: hir::HirId) { +fn convert_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item_id: hir::HirId) { let def_id = tcx.hir().local_def_id_from_hir_id(impl_item_id); tcx.generics_of(def_id); tcx.type_of(def_id); tcx.predicates_of(def_id); - if let hir::ImplItemKind::Method(..) = tcx.hir().expect_impl_item_by_hir_id(impl_item_id).node { + if let hir::ImplItemKind::Method(..) = tcx.hir().expect_impl_item(impl_item_id).node { tcx.fn_sig(def_id); } } -fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ctor_id: ast::NodeId) { - let def_id = tcx.hir().local_def_id(ctor_id); +fn convert_variant_ctor<'tcx>(tcx: TyCtxt<'tcx>, ctor_id: hir::HirId) { + let def_id = tcx.hir().local_def_id_from_hir_id(ctor_id); tcx.generics_of(def_id); tcx.type_of(def_id); tcx.predicates_of(def_id); } -fn convert_enum_variant_types<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - variants: &[hir::Variant], -) { +fn convert_enum_variant_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, variants: &[hir::Variant]) { let def = tcx.adt_def(def_id); let repr_type = def.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx); @@ -555,7 +548,7 @@ fn convert_enum_variant_types<'a, 'tcx>( ); for f in variant.node.data.fields() { - let def_id = tcx.hir().local_def_id(f.id); + let def_id = tcx.hir().local_def_id_from_hir_id(f.hir_id); tcx.generics_of(def_id); tcx.type_of(def_id); tcx.predicates_of(def_id); @@ -563,26 +556,29 @@ fn convert_enum_variant_types<'a, 'tcx>( // Convert the ctor, if any. This also registers the variant as // an item. - convert_variant_ctor(tcx, variant.node.data.id()); + if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() { + convert_variant_ctor(tcx, ctor_hir_id); + } } } -fn convert_variant<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId, +fn convert_variant<'tcx>( + tcx: TyCtxt<'tcx>, + variant_did: Option, + ctor_did: Option, ident: Ident, discr: ty::VariantDiscr, def: &hir::VariantData, adt_kind: ty::AdtKind, - attribute_def_id: DefId + parent_did: DefId, ) -> ty::VariantDef { let mut seen_fields: FxHashMap = Default::default(); - let node_id = tcx.hir().as_local_node_id(did).unwrap(); + let hir_id = tcx.hir().as_local_hir_id(variant_did.unwrap_or(parent_did)).unwrap(); let fields = def .fields() .iter() .map(|f| { - let fid = tcx.hir().local_def_id(f.id); + let fid = tcx.hir().local_def_id_from_hir_id(f.hir_id); let dup_span = seen_fields.get(&f.ident.modern()).cloned(); if let Some(prev_span) = dup_span { struct_span_err!( @@ -601,26 +597,33 @@ fn convert_variant<'a, 'tcx>( ty::FieldDef { did: fid, ident: f.ident, - vis: ty::Visibility::from_hir(&f.vis, node_id, tcx), + vis: ty::Visibility::from_hir(&f.vis, hir_id, tcx), } }) .collect(); - ty::VariantDef::new(tcx, - did, + let recovered = match def { + hir::VariantData::Struct(_, r) => *r, + _ => false, + }; + ty::VariantDef::new( + tcx, ident, + variant_did, + ctor_did, discr, fields, - adt_kind, CtorKind::from_hir(def), - attribute_def_id + adt_kind, + parent_did, + recovered, ) } -fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::AdtDef { +fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx ty::AdtDef { use rustc::hir::*; - let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); - let item = match tcx.hir().get(node_id) { + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let item = match tcx.hir().get(hir_id) { Node::Item(item) => item, _ => bug!(), }; @@ -629,76 +632,70 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Ad let (kind, variants) = match item.node { ItemKind::Enum(ref def, _) => { let mut distance_from_explicit = 0; - ( - AdtKind::Enum, - def.variants - .iter() - .map(|v| { - let did = tcx.hir().local_def_id(v.node.data.id()); - let discr = if let Some(ref e) = v.node.disr_expr { - distance_from_explicit = 0; - ty::VariantDiscr::Explicit(tcx.hir().local_def_id_from_hir_id(e.hir_id)) - } else { - ty::VariantDiscr::Relative(distance_from_explicit) - }; - distance_from_explicit += 1; + let variants = def.variants + .iter() + .map(|v| { + let variant_did = Some(tcx.hir().local_def_id_from_hir_id(v.node.id)); + let ctor_did = v.node.data.ctor_hir_id() + .map(|hir_id| tcx.hir().local_def_id_from_hir_id(hir_id)); + + let discr = if let Some(ref e) = v.node.disr_expr { + distance_from_explicit = 0; + ty::VariantDiscr::Explicit(tcx.hir().local_def_id_from_hir_id(e.hir_id)) + } else { + ty::VariantDiscr::Relative(distance_from_explicit) + }; + distance_from_explicit += 1; - convert_variant(tcx, did, v.node.ident, discr, &v.node.data, AdtKind::Enum, - did) - }) - .collect(), - ) + convert_variant(tcx, variant_did, ctor_did, v.node.ident, discr, + &v.node.data, AdtKind::Enum, def_id) + }) + .collect(); + + (AdtKind::Enum, variants) } ItemKind::Struct(ref def, _) => { - // Use separate constructor id for unit/tuple structs and reuse did for braced structs. - let ctor_id = if !def.is_struct() { - Some(tcx.hir().local_def_id(def.id())) - } else { - None - }; - ( - AdtKind::Struct, - std::iter::once(convert_variant( - tcx, - ctor_id.unwrap_or(def_id), - item.ident, - ty::VariantDiscr::Relative(0), - def, - AdtKind::Struct, - def_id - )).collect(), - ) + let variant_did = None; + let ctor_did = def.ctor_hir_id() + .map(|hir_id| tcx.hir().local_def_id_from_hir_id(hir_id)); + + let variants = std::iter::once(convert_variant( + tcx, variant_did, ctor_did, item.ident, ty::VariantDiscr::Relative(0), def, + AdtKind::Struct, def_id, + )).collect(); + + (AdtKind::Struct, variants) } - ItemKind::Union(ref def, _) => ( - AdtKind::Union, - std::iter::once(convert_variant( - tcx, - def_id, - item.ident, - ty::VariantDiscr::Relative(0), - def, - AdtKind::Union, - def_id - )).collect(), - ), + ItemKind::Union(ref def, _) => { + let variant_did = None; + let ctor_did = def.ctor_hir_id() + .map(|hir_id| tcx.hir().local_def_id_from_hir_id(hir_id)); + + let variants = std::iter::once(convert_variant( + tcx, variant_did, ctor_did, item.ident, ty::VariantDiscr::Relative(0), def, + AdtKind::Union, def_id, + )).collect(); + + (AdtKind::Union, variants) + }, _ => bug!(), }; tcx.alloc_adt_def(def_id, kind, variants, repr) } -/// Ensures that the super-predicates of the trait with `DefId` -/// trait_def_id are converted and stored. This also ensures that -/// the transitive super-predicates are converted; -fn super_predicates_of<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +/// Ensures that the super-predicates of the trait with a `DefId` +/// of `trait_def_id` are converted and stored. This also ensures that +/// the transitive super-predicates are converted. +fn super_predicates_of<'tcx>( + tcx: TyCtxt<'tcx>, trait_def_id: DefId, -) -> Lrc> { +) -> &'tcx ty::GenericPredicates<'tcx> { debug!("super_predicates(trait_def_id={:?})", trait_def_id); - let trait_node_id = tcx.hir().as_local_node_id(trait_def_id).unwrap(); + let trait_hir_id = tcx.hir().as_local_hir_id(trait_def_id).unwrap(); - let item = match tcx.hir().get(trait_node_id) { + let item = match tcx.hir().get(trait_hir_id) { Node::Item(item) => item, - _ => bug!("trait_node_id {} is not an item", trait_node_id), + _ => bug!("trait_node_id {} is not an item", trait_hir_id), }; let (generics, bounds) = match item.node { @@ -709,15 +706,16 @@ fn super_predicates_of<'a, 'tcx>( let icx = ItemCtxt::new(tcx, trait_def_id); - // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo : Bar + Zed`. + // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. let self_param_ty = tcx.mk_self_type(); - let superbounds1 = compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span); + let superbounds1 = AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, + item.span); let superbounds1 = superbounds1.predicates(tcx, self_param_ty); - // Convert any explicit superbounds in the where clause, - // e.g., `trait Foo where Self : Bar`. - // In the case of trait aliases, however, we include all bounds in the where clause, + // Convert any explicit superbounds in the where-clause, + // e.g., `trait Foo where Self: Bar`. + // In the case of trait aliases, however, we include all bounds in the where-clause, // so e.g., `trait Foo = where u32: PartialEq` would include `u32: PartialEq` // as one of its "superpredicates". let is_trait_alias = tcx.is_trait_alias(trait_def_id); @@ -736,15 +734,15 @@ fn super_predicates_of<'a, 'tcx>( } } - Lrc::new(ty::GenericPredicates { + tcx.arena.alloc(ty::GenericPredicates { parent: None, predicates: superbounds, }) } -fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::TraitDef { +fn trait_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx ty::TraitDef { let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let item = tcx.hir().expect_item_by_hir_id(hir_id); + let item = tcx.hir().expect_item(hir_id); let (is_auto, unsafety) = match item.node { hir::ItemKind::Trait(is_auto, unsafety, ..) => (is_auto == hir::IsAuto::Yes, unsafety), @@ -752,7 +750,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty:: _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"), }; - let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar"); + let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar); if paren_sugar && !tcx.features().unboxed_closures { let mut err = tcx.sess.struct_span_err( item.span, @@ -767,23 +765,20 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty:: err.emit(); } - let is_marker = tcx.has_attr(def_id, "marker"); + let is_marker = tcx.has_attr(def_id, sym::marker); let def_path_hash = tcx.def_path_hash(def_id); let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, is_auto, is_marker, def_path_hash); - tcx.alloc_trait_def(def) + tcx.arena.alloc(def) } -fn has_late_bound_regions<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - node: Node<'tcx>, -) -> Option { - struct LateBoundRegionsDetector<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option { + struct LateBoundRegionsDetector<'tcx> { + tcx: TyCtxt<'tcx>, outer_index: ty::DebruijnIndex, has_late_bound_regions: Option, } - impl<'a, 'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'a, 'tcx> { + impl Visitor<'tcx> for LateBoundRegionsDetector<'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } @@ -834,8 +829,8 @@ fn has_late_bound_regions<'a, 'tcx>( } } - fn has_late_bound_regions<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn has_late_bound_regions<'tcx>( + tcx: TyCtxt<'tcx>, generics: &'tcx hir::Generics, decl: &'tcx hir::FnDecl, ) -> Option { @@ -884,17 +879,17 @@ fn has_late_bound_regions<'a, 'tcx>( } } -fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Generics { +fn generics_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx ty::Generics { use rustc::hir::*; - let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let node = tcx.hir().get(node_id); + let node = tcx.hir().get(hir_id); let parent_def_id = match node { - Node::ImplItem(_) | Node::TraitItem(_) | Node::Variant(_) - | Node::StructCtor(_) | Node::Field(_) => { - let parent_id = tcx.hir().get_parent(node_id); - Some(tcx.hir().local_def_id(parent_id)) + Node::ImplItem(_) | Node::TraitItem(_) | Node::Variant(_) | + Node::Ctor(..) | Node::Field(_) => { + let parent_id = tcx.hir().get_parent_item(hir_id); + Some(tcx.hir().local_def_id_from_hir_id(parent_id)) } Node::Expr(&hir::Expr { node: hir::ExprKind::Closure(..), @@ -937,12 +932,12 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty // // Something of a hack: use the node id for the trait, also as // the node id for the Self type parameter. - let param_id = item.id; + let param_id = item.hir_id; opt_self = Some(ty::GenericParamDef { index: 0, - name: keywords::SelfUpper.name().as_interned_str(), - def_id: tcx.hir().local_def_id(param_id), + name: kw::SelfUpper.as_interned_str(), + def_id: tcx.hir().local_def_id_from_hir_id(param_id), pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { has_default: false, @@ -994,7 +989,6 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty }), ); - let hir_id = tcx.hir().node_to_hir_id(node_id); let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id); // Now create the real type parameters. @@ -1004,67 +998,65 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty ast_generics .params .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Type { - ref default, - synthetic, - .. - } => { - if param.name.ident().name == keywords::SelfUpper.name() { - span_bug!( - param.span, - "`Self` should not be the name of a regular parameter" - ); - } - - if !allow_defaults && default.is_some() { - if !tcx.features().default_type_parameter_fallback { - tcx.lint_hir( - lint::builtin::INVALID_TYPE_PARAM_DEFAULT, - param.hir_id, + .filter_map(|param| { + let kind = match param.kind { + GenericParamKind::Type { + ref default, + synthetic, + .. + } => { + if param.name.ident().name == kw::SelfUpper { + span_bug!( param.span, - &format!( - "defaults for type parameters are only allowed in \ - `struct`, `enum`, `type`, or `trait` definitions." - ), + "`Self` should not be the name of a regular parameter" ); } - } - let ty_param = ty::GenericParamDef { - index: type_start + i as u32, - name: param.name.ident().as_interned_str(), - def_id: tcx.hir().local_def_id_from_hir_id(param.hir_id), - pure_wrt_drop: param.pure_wrt_drop, - kind: ty::GenericParamDefKind::Type { + if !allow_defaults && default.is_some() { + if !tcx.features().default_type_parameter_fallback { + tcx.lint_hir( + lint::builtin::INVALID_TYPE_PARAM_DEFAULT, + param.hir_id, + param.span, + &format!( + "defaults for type parameters are only allowed in \ + `struct`, `enum`, `type`, or `trait` definitions." + ), + ); + } + } + + ty::GenericParamDefKind::Type { has_default: default.is_some(), object_lifetime_default: object_lifetime_defaults .as_ref() .map_or(rl::Set1::Empty, |o| o[i]), synthetic, - }, - }; - i += 1; - Some(ty_param) - } - GenericParamKind::Const { .. } => { - if param.name.ident().name == keywords::SelfUpper.name() { - span_bug!( - param.span, - "`Self` should not be the name of a regular parameter", - ); + } } + GenericParamKind::Const { .. } => { + if param.name.ident().name == kw::SelfUpper { + span_bug!( + param.span, + "`Self` should not be the name of a regular parameter", + ); + } - // Emit an error, but skip the parameter rather than aborting to - // continue to get other errors. - tcx.sess.struct_span_err( - param.span, - "const generics in any position are currently unsupported", - ).emit(); - None - } - _ => None, - }), + ty::GenericParamDefKind::Const + } + _ => return None, + }; + + let param_def = ty::GenericParamDef { + index: type_start + i as u32, + name: param.name.ident().as_interned_str(), + def_id: tcx.hir().local_def_id_from_hir_id(param.hir_id), + pure_wrt_drop: param.pure_wrt_drop, + kind, + }; + i += 1; + Some(param_def) + }) ); // provide junk type parameter defs - the only place that @@ -1087,7 +1079,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty .enumerate() .map(|(i, &arg)| ty::GenericParamDef { index: type_start + i as u32, - name: Symbol::intern(arg).as_interned_str(), + name: InternedString::intern(arg), def_id, pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { @@ -1098,11 +1090,11 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty }), ); - tcx.with_freevars(node_id, |fv| { - params.extend(fv.iter().zip((dummy_args.len() as u32)..).map(|(_, i)| { + if let Some(upvars) = tcx.upvars(def_id) { + params.extend(upvars.iter().zip((dummy_args.len() as u32)..).map(|(_, i)| { ty::GenericParamDef { index: type_start + i, - name: Symbol::intern("").as_interned_str(), + name: InternedString::intern(""), def_id, pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { @@ -1112,7 +1104,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty }, } })); - }); + } } let param_def_id_to_index = params @@ -1120,7 +1112,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty .map(|param| (param.def_id, param.index)) .collect(); - tcx.alloc_generics(ty::Generics { + tcx.arena.alloc(ty::Generics { parent: parent_def_id, parent_count, params, @@ -1130,7 +1122,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty }) } -fn report_assoc_ty_on_inherent_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span) { +fn report_assoc_ty_on_inherent_impl<'tcx>(tcx: TyCtxt<'tcx>, span: Span) { span_err!( tcx.sess, span, @@ -1139,14 +1131,30 @@ fn report_assoc_ty_on_inherent_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: ); } -fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { +fn type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> { + checked_type_of(tcx, def_id, true).unwrap() +} + +/// Same as [`type_of`] but returns [`Option`] instead of failing. +/// +/// If you want to fail anyway, you can set the `fail` parameter to true, but in this case, +/// you'd better just call [`type_of`] directly. +pub fn checked_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fail: bool) -> Option> { use rustc::hir::*; - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let hir_id = match tcx.hir().as_local_hir_id(def_id) { + Some(hir_id) => hir_id, + None => { + if !fail { + return None; + } + bug!("invalid node"); + } + }; let icx = ItemCtxt::new(tcx, def_id); - match tcx.hir().get_by_hir_id(hir_id) { + Some(match tcx.hir().get(hir_id) { Node::TraitItem(item) => match item.node { TraitItemKind::Method(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); @@ -1154,6 +1162,9 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { } TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty), TraitItemKind::Type(_, None) => { + if !fail { + return None; + } span_bug!(item.span, "associated type missing default"); } }, @@ -1166,7 +1177,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { ImplItemKind::Const(ref ty, _) => icx.to_ty(ty), ImplItemKind::Existential(_) => { if tcx - .impl_trait_ref(tcx.hir().get_parent_did_by_hir_id(hir_id)) + .impl_trait_ref(tcx.hir().get_parent_did(hir_id)) .is_none() { report_assoc_ty_on_inherent_impl(tcx, item.span); @@ -1176,7 +1187,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { } ImplItemKind::Type(ref ty) => { if tcx - .impl_trait_ref(tcx.hir().get_parent_did_by_hir_id(hir_id)) + .impl_trait_ref(tcx.hir().get_parent_did(hir_id)) .is_none() { report_assoc_ty_on_inherent_impl(tcx, item.span); @@ -1205,7 +1216,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { impl_trait_fn: None, .. }) => find_existential_constraints(tcx, def_id), - // existential types desugared from impl Trait + // Existential types desugared from `impl Trait`. ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(owner), .. @@ -1235,6 +1246,9 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { | ItemKind::GlobalAsm(..) | ItemKind::ExternCrate(..) | ItemKind::Use(..) => { + if !fail { + return None; + } span_bug!( item.span, "compute_type_of_item: unexpected item type: {:?}", @@ -1253,13 +1267,12 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { ForeignItemKind::Type => tcx.mk_foreign(def_id), }, - Node::StructCtor(&ref def) - | Node::Variant(&Spanned { + Node::Ctor(&ref def) | Node::Variant(&Spanned { node: hir::VariantKind { data: ref def, .. }, .. }) => match *def { VariantData::Unit(..) | VariantData::Struct(..) => { - tcx.type_of(tcx.hir().get_parent_did_by_hir_id(hir_id)) + tcx.type_of(tcx.hir().get_parent_did(hir_id)) } VariantData::Tuple(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); @@ -1274,7 +1287,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { .. }) => { if gen.is_some() { - return tcx.typeck_tables_of(def_id).node_type(hir_id); + return Some(tcx.typeck_tables_of(def_id).node_type(hir_id)); } let substs = ty::ClosureSubsts { @@ -1284,83 +1297,199 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { tcx.mk_closure(def_id, substs) } - Node::AnonConst(_) => match tcx.hir().get_by_hir_id( - tcx.hir().get_parent_node_by_hir_id(hir_id)) - { - Node::Ty(&hir::Ty { - node: hir::TyKind::Array(_, ref constant), - .. - }) - | Node::Ty(&hir::Ty { - node: hir::TyKind::Typeof(ref constant), - .. - }) - | Node::Expr(&hir::Expr { - node: ExprKind::Repeat(_, ref constant), - .. - }) if constant.hir_id == hir_id => - { - tcx.types.usize - } + Node::AnonConst(_) => { + let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id)); + match parent_node { + Node::Ty(&hir::Ty { + node: hir::TyKind::Array(_, ref constant), + .. + }) + | Node::Ty(&hir::Ty { + node: hir::TyKind::Typeof(ref constant), + .. + }) + | Node::Expr(&hir::Expr { + node: ExprKind::Repeat(_, ref constant), + .. + }) if constant.hir_id == hir_id => + { + tcx.types.usize + } - Node::Variant(&Spanned { - node: - VariantKind { - disr_expr: Some(ref e), - .. - }, - .. - }) if e.hir_id == hir_id => - { - tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id)) - .repr - .discr_type() - .to_ty(tcx) - } + Node::Variant(&Spanned { + node: + VariantKind { + disr_expr: Some(ref e), + .. + }, + .. + }) if e.hir_id == hir_id => + { + tcx.adt_def(tcx.hir().get_parent_did(hir_id)) + .repr + .discr_type() + .to_ty(tcx) + } - x => { - bug!("unexpected const parent in type_of_def_id(): {:?}", x); + Node::Ty(&hir::Ty { node: hir::TyKind::Path(_), .. }) | + Node::Expr(&hir::Expr { node: ExprKind::Struct(..), .. }) | + Node::Expr(&hir::Expr { node: ExprKind::Path(_), .. }) | + Node::TraitRef(..) => { + let path = match parent_node { + Node::Ty(&hir::Ty { + node: hir::TyKind::Path(QPath::Resolved(_, ref path)), + .. + }) + | Node::Expr(&hir::Expr { + node: ExprKind::Path(QPath::Resolved(_, ref path)), + .. + }) => { + Some(&**path) + } + Node::Expr(&hir::Expr { node: ExprKind::Struct(ref path, ..), .. }) => { + if let QPath::Resolved(_, ref path) = **path { + Some(&**path) + } else { + None + } + } + Node::TraitRef(&hir::TraitRef { ref path, .. }) => Some(path), + _ => None, + }; + + if let Some(path) = path { + let arg_index = path.segments.iter() + .filter_map(|seg| seg.args.as_ref()) + .map(|generic_args| generic_args.args.as_ref()) + .find_map(|args| { + args.iter() + .filter(|arg| arg.is_const()) + .enumerate() + .filter(|(_, arg)| arg.id() == hir_id) + .map(|(index, _)| index) + .next() + }) + .or_else(|| { + if !fail { + None + } else { + bug!("no arg matching AnonConst in path") + } + })?; + + // We've encountered an `AnonConst` in some path, so we need to + // figure out which generic parameter it corresponds to and return + // the relevant type. + let generics = match path.res { + Res::Def(DefKind::Ctor(..), def_id) => { + tcx.generics_of(tcx.parent(def_id).unwrap()) + } + Res::Def(_, def_id) => tcx.generics_of(def_id), + Res::Err => return Some(tcx.types.err), + _ if !fail => return None, + res => { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "unexpected const parent path def {:?}", + res, + ), + ); + return Some(tcx.types.err); + } + }; + + generics.params.iter() + .filter(|param| { + if let ty::GenericParamDefKind::Const = param.kind { + true + } else { + false + } + }) + .nth(arg_index) + .map(|param| tcx.type_of(param.def_id)) + // This is no generic parameter associated with the arg. This is + // probably from an extra arg where one is not needed. + .unwrap_or(tcx.types.err) + } else { + if !fail { + return None; + } + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "unexpected const parent path {:?}", + parent_node, + ), + ); + return Some(tcx.types.err); + } + } + + x => { + if !fail { + return None; + } + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "unexpected const parent in type_of_def_id(): {:?}", x + ), + ); + tcx.types.err + } } - }, + } Node::GenericParam(param) => match ¶m.kind { hir::GenericParamKind::Type { default: Some(ref ty), .. } | hir::GenericParamKind::Const { ref ty, .. } => { icx.to_ty(ty) } - x => bug!("unexpected non-type Node::GenericParam: {:?}", x), + x => { + if !fail { + return None; + } + bug!("unexpected non-type Node::GenericParam: {:?}", x) + }, }, x => { + if !fail { + return None; + } bug!("unexpected sort of node in type_of_def_id(): {:?}", x); } - } + }) } -fn find_existential_constraints<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, -) -> ty::Ty<'tcx> { - use rustc::hir::*; +fn find_existential_constraints<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> { + use rustc::hir::{ImplItem, Item, TraitItem}; + + debug!("find_existential_constraints({:?})", def_id); - struct ConstraintLocator<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, + struct ConstraintLocator<'tcx> { + tcx: TyCtxt<'tcx>, def_id: DefId, - // First found type span, actual type, mapping from the existential type's generic - // parameters to the concrete type's generic parameters + // (first found type span, actual type, mapping from the existential type's generic + // parameters to the concrete type's generic parameters) // // The mapping is an index for each use site of a generic parameter in the concrete type // // The indices index into the generic parameters on the existential type. - found: Option<(Span, ty::Ty<'tcx>, Vec)>, + found: Option<(Span, Ty<'tcx>, Vec)>, } - impl<'a, 'tcx> ConstraintLocator<'a, 'tcx> { + impl ConstraintLocator<'tcx> { fn check(&mut self, def_id: DefId) { - trace!("checking {:?}", def_id); - // don't try to check items that cannot possibly constrain the type + // Don't try to check items that cannot possibly constrain the type. if !self.tcx.has_typeck_tables(def_id) { - trace!("no typeck tables for {:?}", def_id); + debug!( + "find_existential_constraints: no constraint for `{:?}` at `{:?}`: no tables", + self.def_id, + def_id, + ); return; } let ty = self @@ -1369,22 +1498,32 @@ fn find_existential_constraints<'a, 'tcx>( .concrete_existential_types .get(&self.def_id); if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty { - // FIXME(oli-obk): trace the actual span from inference to improve errors + debug!( + "find_existential_constraints: found constraint for `{:?}` at `{:?}`: {:?}", + self.def_id, + def_id, + ty, + ); + + // FIXME(oli-obk): trace the actual span from inference to improve errors. let span = self.tcx.def_span(def_id); // used to quickly look up the position of a generic parameter let mut index_map: FxHashMap = FxHashMap::default(); - // skip binder is ok, since we only use this to find generic parameters and their - // positions. + // Skipping binder is ok, since we only use this to find generic parameters and + // their positions. for (idx, subst) in substs.iter().enumerate() { if let UnpackedKind::Type(ty) = subst.unpack() { if let ty::Param(p) = ty.sty { if index_map.insert(p, idx).is_some() { - // there was already an entry for `p`, meaning a generic parameter - // was used twice + // There was already an entry for `p`, meaning a generic parameter + // was used twice. self.tcx.sess.span_err( span, - &format!("defining existential type use restricts existential \ - type by using the generic parameter `{}` twice", p.name), + &format!( + "defining existential type use restricts existential \ + type by using the generic parameter `{}` twice", + p.name + ), ); return; } @@ -1399,8 +1538,8 @@ fn find_existential_constraints<'a, 'tcx>( } } } - // compute the index within the existential type for each generic parameter used in - // the concrete type + // Compute the index within the existential type for each generic parameter used in + // the concrete type. let indices = concrete_type .subst(self.tcx, substs) .walk() @@ -1408,7 +1547,7 @@ fn find_existential_constraints<'a, 'tcx>( ty::Param(p) => Some(*index_map.get(p).unwrap()), _ => None, }).collect(); - let is_param = |ty: ty::Ty<'_>| match ty.sty { + let is_param = |ty: Ty<'_>| match ty.sty { ty::Param(_) => true, _ => false, }; @@ -1421,14 +1560,15 @@ fn find_existential_constraints<'a, 'tcx>( let mut ty = concrete_type.walk().fuse(); let mut p_ty = prev_ty.walk().fuse(); let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.sty, &p.sty) { - // type parameters are equal to any other type parameter for the purpose of + // Type parameters are equal to any other type parameter for the purpose of // concrete type equality, as it is possible to obtain the same type just // by passing matching parameters to a function. (ty::Param(_), ty::Param(_)) => true, _ => t == p, }); if !iter_eq || ty.next().is_some() || p_ty.next().is_some() { - // found different concrete types for the existential type + debug!("find_existential_constraints: span={:?}", span); + // Found different concrete types for the existential type. let mut err = self.tcx.sess.struct_span_err( span, "concrete type differs from previous defining existential type use", @@ -1440,7 +1580,7 @@ fn find_existential_constraints<'a, 'tcx>( err.span_note(prev_span, "previous use here"); err.emit(); } else if indices != *prev_indices { - // found "same" concrete types, but the generic parameter order differs + // Found "same" concrete types, but the generic parameter order differs. let mut err = self.tcx.sess.struct_span_err( span, "concrete type's generic parameters differ from previous defining use", @@ -1468,17 +1608,23 @@ fn find_existential_constraints<'a, 'tcx>( } else { self.found = Some((span, concrete_type, indices)); } + } else { + debug!( + "find_existential_constraints: no constraint for `{:?}` at `{:?}`", + self.def_id, + def_id, + ); } } } - impl<'a, 'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'a, 'tcx> { + impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> { fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { intravisit::NestedVisitorMap::All(&self.tcx.hir()) } fn visit_item(&mut self, it: &'tcx Item) { - let def_id = self.tcx.hir().local_def_id(it.id); - // the existential type itself or its children are not within its reveal scope + let def_id = self.tcx.hir().local_def_id_from_hir_id(it.hir_id); + // The existential type itself or its children are not within its reveal scope. if def_id != self.def_id { self.check(def_id); intravisit::walk_item(self, it); @@ -1486,7 +1632,7 @@ fn find_existential_constraints<'a, 'tcx>( } fn visit_impl_item(&mut self, it: &'tcx ImplItem) { let def_id = self.tcx.hir().local_def_id_from_hir_id(it.hir_id); - // the existential type itself or its children are not within its reveal scope + // The existential type itself or its children are not within its reveal scope. if def_id != self.def_id { self.check(def_id); intravisit::walk_impl_item(self, it); @@ -1499,26 +1645,28 @@ fn find_existential_constraints<'a, 'tcx>( } } + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let scope = tcx.hir() + .get_defining_scope(hir_id) + .expect("could not get defining scope"); let mut locator = ConstraintLocator { def_id, tcx, found: None, }; - let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); - let parent = tcx.hir().get_parent(node_id); - trace!("parent_id: {:?}", parent); + debug!("find_existential_constraints: scope={:?}", scope); - if parent == ast::CRATE_NODE_ID { + if scope == hir::CRATE_HIR_ID { intravisit::walk_crate(&mut locator, tcx.hir().krate()); } else { - trace!("parent: {:?}", tcx.hir().get(parent)); - match tcx.hir().get(parent) { + debug!("find_existential_constraints: scope={:?}", tcx.hir().get(scope)); + match tcx.hir().get(scope) { Node::Item(ref it) => intravisit::walk_item(&mut locator, it), Node::ImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it), Node::TraitItem(ref it) => intravisit::walk_trait_item(&mut locator, it), other => bug!( - "{:?} is not a valid parent of an existential type item", + "{:?} is not a valid scope for an existential type item", other ), } @@ -1534,15 +1682,15 @@ fn find_existential_constraints<'a, 'tcx>( } } -fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::PolyFnSig<'tcx> { +fn fn_sig<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::PolyFnSig<'tcx> { use rustc::hir::*; use rustc::hir::Node::*; - let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); let icx = ItemCtxt::new(tcx, def_id); - match tcx.hir().get(node_id) { + match tcx.hir().get(hir_id) { TraitItem(hir::TraitItem { node: TraitItemKind::Method(sig, _), .. @@ -1561,23 +1709,18 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::PolyFnSig node: ForeignItemKind::Fn(ref fn_decl, _, _), .. }) => { - let abi = tcx.hir().get_foreign_abi(node_id); + let abi = tcx.hir().get_foreign_abi(hir_id); compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi) } - StructCtor(&VariantData::Tuple(ref fields, ..)) - | Variant(&Spanned { - node: - hir::VariantKind { - data: VariantData::Tuple(ref fields, ..), - .. - }, + Ctor(data) | Variant(Spanned { + node: hir::VariantKind { data, .. }, .. - }) => { - let ty = tcx.type_of(tcx.hir().get_parent_did(node_id)); - let inputs = fields + }) if data.ctor_hir_id().is_some() => { + let ty = tcx.type_of(tcx.hir().get_parent_did(hir_id)); + let inputs = data.fields() .iter() - .map(|f| tcx.type_of(tcx.hir().local_def_id(f.id))); + .map(|f| tcx.type_of(tcx.hir().local_def_id_from_hir_id(f.hir_id))); ty::Binder::bind(tcx.mk_fn_sig( inputs, ty, @@ -1615,14 +1758,11 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::PolyFnSig } } -fn impl_trait_ref<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, -) -> Option> { +fn impl_trait_ref<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option> { let icx = ItemCtxt::new(tcx, def_id); let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - match tcx.hir().expect_item_by_hir_id(hir_id).node { + match tcx.hir().expect_item(hir_id).node { hir::ItemKind::Impl(.., ref opt_trait_ref, _, _) => { opt_trait_ref.as_ref().map(|ast_trait_ref| { let selfty = tcx.type_of(def_id); @@ -1633,72 +1773,21 @@ fn impl_trait_ref<'a, 'tcx>( } } -fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> hir::ImplPolarity { +fn impl_polarity<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> hir::ImplPolarity { let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - match tcx.hir().expect_item_by_hir_id(hir_id).node { + match tcx.hir().expect_item(hir_id).node { hir::ItemKind::Impl(_, polarity, ..) => polarity, ref item => bug!("impl_polarity: {:?} not an impl", item), } } -// Is it marked with ?Sized -fn is_unsized<'gcx: 'tcx, 'tcx>( - astconv: &dyn AstConv<'gcx, 'tcx>, - ast_bounds: &[hir::GenericBound], - span: Span, -) -> bool { - let tcx = astconv.tcx(); - - // Try to find an unbound in bounds. - let mut unbound = None; - for ab in ast_bounds { - if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab { - if unbound.is_none() { - unbound = Some(ptr.trait_ref.clone()); - } else { - span_err!( - tcx.sess, - span, - E0203, - "type parameter has more than one relaxed default \ - bound, only one is supported" - ); - } - } - } - - let kind_id = tcx.lang_items().require(SizedTraitLangItem); - match unbound { - Some(ref tpb) => { - // FIXME(#8559) currently requires the unbound to be built-in. - if let Ok(kind_id) = kind_id { - if tpb.path.def != Def::Trait(kind_id) { - tcx.sess.span_warn( - span, - "default bound relaxed for a type parameter, but \ - this does nothing because the given bound is not \ - a default. Only `?Sized` is supported", - ); - } - } - } - _ if kind_id.is_ok() => { - return false; - } - // No lang item for Sized, so we can't add it as a bound. - None => {} - } - - true -} - /// Returns the early-bound lifetimes declared in this generics /// listing. For anything other than fns/methods, this is just all /// the lifetimes that are declared. For fns or methods, we have to /// screen out those that do not appear in any where-clauses etc using /// `resolve_lifetime::early_bound_lifetimes`. -fn early_bound_lifetimes_from_generics<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>( + tcx: TyCtxt<'tcx>, generics: &'a hir::Generics, ) -> impl Iterator + Captures<'tcx> { generics @@ -1715,10 +1804,10 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx>( /// Returns a list of type predicates for the definition with ID `def_id`, including inferred /// lifetime constraints. This includes all predicates returned by `explicit_predicates_of`, plus /// inferred constraints concerning which regions outlive other regions. -fn predicates_defined_on<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn predicates_defined_on<'tcx>( + tcx: TyCtxt<'tcx>, def_id: DefId, -) -> Lrc> { +) -> &'tcx ty::GenericPredicates<'tcx> { debug!("predicates_defined_on({:?})", def_id); let mut result = tcx.explicit_predicates_of(def_id); debug!( @@ -1734,9 +1823,9 @@ fn predicates_defined_on<'a, 'tcx>( def_id, inferred_outlives, ); - Lrc::make_mut(&mut result) - .predicates - .extend(inferred_outlives.iter().map(|&p| (p, span))); + let mut predicates = (*result).clone(); + predicates.predicates.extend(inferred_outlives.iter().map(|&p| (p, span))); + result = tcx.arena.alloc(predicates); } debug!("predicates_defined_on({:?}) = {:?}", def_id, result); result @@ -1745,10 +1834,7 @@ fn predicates_defined_on<'a, 'tcx>( /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus /// `Self: Trait` predicates for traits. -fn predicates_of<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, -) -> Lrc> { +fn predicates_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx ty::GenericPredicates<'tcx> { let mut result = tcx.predicates_defined_on(def_id); if tcx.is_trait(def_id) { @@ -1765,9 +1851,9 @@ fn predicates_of<'a, 'tcx>( // used, and adding the predicate into this list ensures // that this is done. let span = tcx.def_span(def_id); - Lrc::make_mut(&mut result) - .predicates - .push((ty::TraitRef::identity(tcx, def_id).to_predicate(), span)); + let mut predicates = (*result).clone(); + predicates.predicates.push((ty::TraitRef::identity(tcx, def_id).to_predicate(), span)); + result = tcx.arena.alloc(predicates); } debug!("predicates_of(def_id={:?}) = {:?}", def_id, result); result @@ -1775,10 +1861,10 @@ fn predicates_of<'a, 'tcx>( /// Returns a list of user-specified type predicates for the definition with ID `def_id`. /// N.B., this does not include any implied/inferred constraints. -fn explicit_predicates_of<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn explicit_predicates_of<'tcx>( + tcx: TyCtxt<'tcx>, def_id: DefId, -) -> Lrc> { +) -> &'tcx ty::GenericPredicates<'tcx> { use rustc::hir::*; use rustc_data_structures::fx::FxHashSet; @@ -1813,14 +1899,19 @@ fn explicit_predicates_of<'a, 'tcx>( } } - let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); - let node = tcx.hir().get(node_id); + let hir_id = match tcx.hir().as_local_hir_id(def_id) { + Some(hir_id) => hir_id, + None => return tcx.predicates_of(def_id), + }; + let node = tcx.hir().get(hir_id); let mut is_trait = None; let mut is_default_impl_trait = None; let icx = ItemCtxt::new(tcx, def_id); - let no_generics = hir::Generics::empty(); + + const NO_GENERICS: &hir::Generics = &hir::Generics::empty(); + let empty_trait_items = HirVec::new(); let mut predicates = UniquePredicates::new(); @@ -1833,8 +1924,8 @@ fn explicit_predicates_of<'a, 'tcx>( let substs = InternalSubsts::identity_for_item(tcx, def_id); let opaque_ty = tcx.mk_opaque(def_id, substs); - // Collect the bounds, i.e., the `A+B+'c` in `impl A+B+'c`. - let bounds = compute_bounds( + // Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`. + let bounds = AstConv::compute_bounds( &icx, opaque_ty, bounds, @@ -1874,12 +1965,13 @@ fn explicit_predicates_of<'a, 'tcx>( ref bounds, impl_trait_fn, ref generics, + origin: _, }) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); let opaque_ty = tcx.mk_opaque(def_id, substs); - // Collect the bounds, i.e., the `A+B+'c` in `impl A+B+'c`. - let bounds = compute_bounds( + // Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`. + let bounds = AstConv::compute_bounds( &icx, opaque_ty, bounds, @@ -1887,30 +1979,31 @@ fn explicit_predicates_of<'a, 'tcx>( tcx.def_span(def_id), ); + let bounds_predicates = bounds.predicates(tcx, opaque_ty); if impl_trait_fn.is_some() { - // impl Trait - return Lrc::new(ty::GenericPredicates { + // opaque types + return tcx.arena.alloc(ty::GenericPredicates { parent: None, - predicates: bounds.predicates(tcx, opaque_ty), + predicates: bounds_predicates, }); } else { // named existential types - predicates.extend(bounds.predicates(tcx, opaque_ty)); + predicates.extend(bounds_predicates); generics } } - _ => &no_generics, + _ => NO_GENERICS, } } Node::ForeignItem(item) => match item.node { - ForeignItemKind::Static(..) => &no_generics, + ForeignItemKind::Static(..) => NO_GENERICS, ForeignItemKind::Fn(_, _, ref generics) => generics, - ForeignItemKind::Type => &no_generics, + ForeignItemKind::Type => NO_GENERICS, }, - _ => &no_generics, + _ => NO_GENERICS, }; let generics = tcx.generics_of(def_id); @@ -1965,7 +2058,7 @@ fn explicit_predicates_of<'a, 'tcx>( } // Collect the predicates that were written inline by the user on each - // type parameter (e.g., ``). + // type parameter (e.g., ``). for param in &ast_generics.params { if let GenericParamKind::Type { .. } = param.kind { let name = param.name.ident().as_interned_str(); @@ -1973,12 +2066,12 @@ fn explicit_predicates_of<'a, 'tcx>( index += 1; let sized = SizedByDefault::Yes; - let bounds = compute_bounds(&icx, param_ty, ¶m.bounds, sized, param.span); + let bounds = AstConv::compute_bounds(&icx, param_ty, ¶m.bounds, sized, param.span); predicates.extend(bounds.predicates(tcx, param_ty)); } } - // Add in the bounds that appear in the where-clause + // Add in the bounds that appear in the where-clause. let where_clause = &ast_generics.where_clause; for predicate in &where_clause.predicates { match predicate { @@ -2008,19 +2101,17 @@ fn explicit_predicates_of<'a, 'tcx>( for bound in bound_pred.bounds.iter() { match bound { &hir::GenericBound::Trait(ref poly_trait_ref, _) => { - let mut projections = Vec::new(); + let mut bounds = Bounds::default(); let (trait_ref, _) = AstConv::instantiate_poly_trait_ref( &icx, poly_trait_ref, ty, - &mut projections, + &mut bounds, ); - predicates.extend( - iter::once((trait_ref.to_predicate(), poly_trait_ref.span)).chain( - projections.iter().map(|&(p, span)| (p.to_predicate(), span) - ))); + predicates.push((trait_ref.to_predicate(), poly_trait_ref.span)); + predicates.extend(bounds.predicates(tcx, ty)); } &hir::GenericBound::Outlives(ref lifetime) => { @@ -2059,14 +2150,14 @@ fn explicit_predicates_of<'a, 'tcx>( let trait_item = tcx.hir().trait_item(trait_item_ref.id); let bounds = match trait_item.node { hir::TraitItemKind::Type(ref bounds, _) => bounds, - _ => return vec![].into_iter() + _ => return Vec::new().into_iter() }; let assoc_ty = tcx.mk_projection(tcx.hir().local_def_id_from_hir_id(trait_item.hir_id), self_trait_ref.substs); - let bounds = compute_bounds( + let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, def_id), assoc_ty, bounds, @@ -2092,15 +2183,15 @@ fn explicit_predicates_of<'a, 'tcx>( { let self_ty = tcx.type_of(def_id); let trait_ref = tcx.impl_trait_ref(def_id); - ctp::setup_constraining_predicates( + cgp::setup_constraining_predicates( tcx, &mut predicates, trait_ref, - &mut ctp::parameters_for_impl(self_ty, trait_ref), + &mut cgp::parameters_for_impl(self_ty, trait_ref), ); } - let result = Lrc::new(ty::GenericPredicates { + let result = tcx.arena.alloc(ty::GenericPredicates { parent: generics.parent, predicates, }); @@ -2108,87 +2199,23 @@ fn explicit_predicates_of<'a, 'tcx>( result } -pub enum SizedByDefault { - Yes, - No, -} - -/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped `Ty` -/// or a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the -/// built-in trait `Send`. -pub fn compute_bounds<'gcx: 'tcx, 'tcx>( - astconv: &dyn AstConv<'gcx, 'tcx>, - param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound], - sized_by_default: SizedByDefault, - span: Span, -) -> Bounds<'tcx> { - let mut region_bounds = Vec::new(); - let mut trait_bounds = Vec::new(); - - for ast_bound in ast_bounds { - match *ast_bound { - hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => trait_bounds.push(b), - hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} - hir::GenericBound::Outlives(ref l) => region_bounds.push(l), - } - } - - let mut projection_bounds = Vec::new(); - - let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| { - let (poly_trait_ref, _) = astconv.instantiate_poly_trait_ref( - bound, - param_ty, - &mut projection_bounds, - ); - (poly_trait_ref, bound.span) - }).collect(); - - let region_bounds = region_bounds - .into_iter() - .map(|r| (astconv.ast_region_to_region(r, None), r.span)) - .collect(); - - trait_bounds.sort_by_key(|(t, _)| t.def_id()); - - let implicitly_sized = if let SizedByDefault::Yes = sized_by_default { - if !is_unsized(astconv, ast_bounds, span) { - Some(span) - } else { - None - } - } else { - None - }; - - Bounds { - region_bounds, - implicitly_sized, - trait_bounds, - projection_bounds, - } -} - /// Converts a specific `GenericBound` from the AST into a set of /// predicates that apply to the self type. A vector is returned /// because this can be anywhere from zero predicates (`T: ?Sized` adds no /// predicates) to one (`T: Foo`) to many (`T: Bar` adds `T: Bar` /// and `::X == i32`). fn predicates_from_bound<'tcx>( - astconv: &dyn AstConv<'tcx, 'tcx>, + astconv: &dyn AstConv<'tcx>, param_ty: Ty<'tcx>, - bound: &hir::GenericBound, + bound: &'tcx hir::GenericBound, ) -> Vec<(ty::Predicate<'tcx>, Span)> { match *bound { hir::GenericBound::Trait(ref tr, hir::TraitBoundModifier::None) => { - let mut projections = Vec::new(); - let (pred, _) = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut projections); - iter::once((pred.to_predicate(), tr.span)).chain( - projections - .into_iter() - .map(|(p, span)| (p.to_predicate(), span)) - ).collect() + let mut bounds = Bounds::default(); + let (pred, _) = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut bounds); + iter::once((pred.to_predicate(), tr.span)) + .chain(bounds.predicates(astconv.tcx(), param_ty)) + .collect() } hir::GenericBound::Outlives(ref lifetime) => { let region = astconv.ast_region_to_region(lifetime, None); @@ -2199,10 +2226,10 @@ fn predicates_from_bound<'tcx>( } } -fn compute_sig_of_foreign_fn_decl<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn compute_sig_of_foreign_fn_decl<'tcx>( + tcx: TyCtxt<'tcx>, def_id: DefId, - decl: &hir::FnDecl, + decl: &'tcx hir::FnDecl, abi: abi::Abi, ) -> ty::PolyFnSig<'tcx> { let unsafety = if abi == abi::Abi::RustIntrinsic { @@ -2212,8 +2239,8 @@ fn compute_sig_of_foreign_fn_decl<'a, 'tcx>( }; let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), unsafety, abi, decl); - // feature gate SIMD types in FFI, since I (huonw) am not sure the - // ABIs are handled at all correctly. + // Feature gate SIMD types in FFI, since I am not sure that the + // ABIs are handled at all correctly. -huonw if abi != abi::Abi::RustIntrinsic && abi != abi::Abi::PlatformIntrinsic && !tcx.features().simd_ffi @@ -2244,7 +2271,7 @@ fn compute_sig_of_foreign_fn_decl<'a, 'tcx>( fty } -fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { +fn is_foreign_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { match tcx.hir().get_if_local(def_id) { Some(Node::ForeignItem(..)) => true, Some(_) => false, @@ -2252,51 +2279,69 @@ fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool } } +fn static_mutability<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option { + match tcx.hir().get_if_local(def_id) { + Some(Node::Item(&hir::Item { + node: hir::ItemKind::Static(_, mutbl, _), .. + })) | + Some(Node::ForeignItem( &hir::ForeignItem { + node: hir::ForeignItemKind::Static(_, mutbl), .. + })) => Some(mutbl), + Some(_) => None, + _ => bug!("static_mutability applied to non-local def-id {:?}", def_id), + } +} + fn from_target_feature( - tcx: TyCtxt<'_, '_, '_>, + tcx: TyCtxt<'_>, id: DefId, attr: &ast::Attribute, - whitelist: &FxHashMap>, + whitelist: &FxHashMap>, target_features: &mut Vec, ) { let list = match attr.meta_item_list() { Some(list) => list, None => return, }; + let bad_item = |span| { + let msg = "malformed `target_feature` attribute input"; + let code = "enable = \"..\"".to_owned(); + tcx.sess.struct_span_err(span, &msg) + .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders) + .emit(); + }; let rust_features = tcx.features(); for item in list { - // Only `enable = ...` is accepted in the meta item list - if !item.check_name("enable") { - let msg = "#[target_feature(..)] only accepts sub-keys of `enable` \ - currently"; - tcx.sess.span_err(item.span, &msg); + // Only `enable = ...` is accepted in the meta-item list. + if !item.check_name(sym::enable) { + bad_item(item.span()); continue; } - // Must be of the form `enable = "..."` ( a string) + // Must be of the form `enable = "..."` (a string). let value = match item.value_str() { Some(value) => value, None => { - let msg = "#[target_feature] attribute must be of the form \ - #[target_feature(enable = \"..\")]"; - tcx.sess.span_err(item.span, &msg); + bad_item(item.span()); continue; } }; - // We allow comma separation to enable multiple features + // We allow comma separation to enable multiple features. target_features.extend(value.as_str().split(',').filter_map(|feature| { - // Only allow whitelisted features per platform + // Only allow whitelisted features per platform. let feature_gate = match whitelist.get(feature) { Some(g) => g, None => { let msg = format!( - "the feature named `{}` is not valid for \ - this target", + "the feature named `{}` is not valid for this target", feature ); - let mut err = tcx.sess.struct_span_err(item.span, &msg); - + let mut err = tcx.sess.struct_span_err(item.span(), &msg); + err.span_label( + item.span(), + format!("`{}` is not valid for this target", feature), + ); if feature.starts_with("+") { let valid = whitelist.contains_key(&feature[1..]); if valid { @@ -2308,29 +2353,31 @@ fn from_target_feature( } }; - // Only allow features whose feature gates have been enabled - let allowed = match feature_gate.as_ref().map(|s| &**s) { - Some("arm_target_feature") => rust_features.arm_target_feature, - Some("aarch64_target_feature") => rust_features.aarch64_target_feature, - Some("hexagon_target_feature") => rust_features.hexagon_target_feature, - Some("powerpc_target_feature") => rust_features.powerpc_target_feature, - Some("mips_target_feature") => rust_features.mips_target_feature, - Some("avx512_target_feature") => rust_features.avx512_target_feature, - Some("mmx_target_feature") => rust_features.mmx_target_feature, - Some("sse4a_target_feature") => rust_features.sse4a_target_feature, - Some("tbm_target_feature") => rust_features.tbm_target_feature, - Some("wasm_target_feature") => rust_features.wasm_target_feature, - Some("cmpxchg16b_target_feature") => rust_features.cmpxchg16b_target_feature, - Some("adx_target_feature") => rust_features.adx_target_feature, - Some("movbe_target_feature") => rust_features.movbe_target_feature, + // Only allow features whose feature gates have been enabled. + let allowed = match feature_gate.as_ref().map(|s| *s) { + Some(sym::arm_target_feature) => rust_features.arm_target_feature, + Some(sym::aarch64_target_feature) => rust_features.aarch64_target_feature, + Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature, + Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature, + Some(sym::mips_target_feature) => rust_features.mips_target_feature, + Some(sym::avx512_target_feature) => rust_features.avx512_target_feature, + Some(sym::mmx_target_feature) => rust_features.mmx_target_feature, + Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature, + Some(sym::tbm_target_feature) => rust_features.tbm_target_feature, + Some(sym::wasm_target_feature) => rust_features.wasm_target_feature, + Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature, + Some(sym::adx_target_feature) => rust_features.adx_target_feature, + Some(sym::movbe_target_feature) => rust_features.movbe_target_feature, + Some(sym::rtm_target_feature) => rust_features.rtm_target_feature, + Some(sym::f16c_target_feature) => rust_features.f16c_target_feature, Some(name) => bug!("unknown target feature gate {}", name), None => true, }; if !allowed && id.is_local() { feature_gate::emit_feature_err( &tcx.sess.parse_sess, - feature_gate.as_ref().unwrap(), - item.span, + feature_gate.unwrap(), + item.span(), feature_gate::GateIssue::Language, &format!("the target feature `{}` is currently unstable", feature), ); @@ -2340,7 +2387,7 @@ fn from_target_feature( } } -fn linkage_by_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, name: &str) -> Linkage { +fn linkage_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Linkage { use rustc::mir::mono::Linkage::*; // Use the names from src/llvm/docs/LangRef.rst here. Most types are only @@ -2375,7 +2422,7 @@ fn linkage_by_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, name: & } } -fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> CodegenFnAttrs { +fn codegen_fn_attrs<'tcx>(tcx: TyCtxt<'tcx>, id: DefId) -> CodegenFnAttrs { let attrs = tcx.get_attrs(id); let mut codegen_fn_attrs = CodegenFnAttrs::new(); @@ -2384,17 +2431,17 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen let mut inline_span = None; for attr in attrs.iter() { - if attr.check_name("cold") { + if attr.check_name(sym::cold) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD; - } else if attr.check_name("allocator") { + } else if attr.check_name(sym::rustc_allocator) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR; - } else if attr.check_name("unwind") { + } else if attr.check_name(sym::unwind) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::UNWIND; - } else if attr.check_name("ffi_returns_twice") { + } else if attr.check_name(sym::ffi_returns_twice) { if tcx.is_foreign_item(id) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE; } else { - // `#[ffi_returns_twice]` is only allowed `extern fn`s + // `#[ffi_returns_twice]` is only allowed `extern fn`s. struct_span_err!( tcx.sess, attr.span, @@ -2402,21 +2449,21 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen "`#[ffi_returns_twice]` may only be used on foreign functions" ).emit(); } - } else if attr.check_name("rustc_allocator_nounwind") { + } else if attr.check_name(sym::rustc_allocator_nounwind) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND; - } else if attr.check_name("naked") { + } else if attr.check_name(sym::naked) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED; - } else if attr.check_name("no_mangle") { + } else if attr.check_name(sym::no_mangle) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; - } else if attr.check_name("rustc_std_internal_symbol") { + } else if attr.check_name(sym::rustc_std_internal_symbol) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; - } else if attr.check_name("no_debug") { + } else if attr.check_name(sym::no_debug) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_DEBUG; - } else if attr.check_name("used") { + } else if attr.check_name(sym::used) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; - } else if attr.check_name("thread_local") { + } else if attr.check_name(sym::thread_local) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; - } else if attr.check_name("export_name") { + } else if attr.check_name(sym::export_name) { if let Some(s) = attr.value_str() { if s.as_str().contains("\0") { // `#[export_name = ...]` will be converted to a null-terminated string, @@ -2430,11 +2477,13 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen } codegen_fn_attrs.export_name = Some(s); } - } else if attr.check_name("target_feature") { + } else if attr.check_name(sym::target_feature) { if tcx.fn_sig(id).unsafety() == Unsafety::Normal { - let msg = "#[target_feature(..)] can only be applied to \ - `unsafe` function"; - tcx.sess.span_err(attr.span, msg); + let msg = "#[target_feature(..)] can only be applied to `unsafe` functions"; + tcx.sess.struct_span_err(attr.span, msg) + .span_label(attr.span, "can only be applied to `unsafe` functions") + .span_label(tcx.def_span(id), "not an `unsafe` function") + .emit(); } from_target_feature( tcx, @@ -2443,11 +2492,11 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen &whitelist, &mut codegen_fn_attrs.target_features, ); - } else if attr.check_name("linkage") { + } else if attr.check_name(sym::linkage) { if let Some(val) = attr.value_str() { codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str())); } - } else if attr.check_name("link_section") { + } else if attr.check_name(sym::link_section) { if let Some(val) = attr.value_str() { if val.as_str().bytes().any(|b| b == 0) { let msg = format!( @@ -2460,13 +2509,13 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen codegen_fn_attrs.link_section = Some(val); } } - } else if attr.check_name("link_name") { + } else if attr.check_name(sym::link_name) { codegen_fn_attrs.link_name = attr.value_str(); } } codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { - if attr.path != "inline" { + if attr.path != sym::inline { return ia; } match attr.meta().map(|i| i.node) { @@ -2485,14 +2534,14 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen "expected one argument" ); InlineAttr::None - } else if list_contains_name(&items[..], "always") { + } else if list_contains_name(&items[..], sym::always) { InlineAttr::Always - } else if list_contains_name(&items[..], "never") { + } else if list_contains_name(&items[..], sym::never) { InlineAttr::Never } else { span_err!( tcx.sess.diagnostic(), - items[0].span, + items[0].span(), E0535, "invalid argument" ); @@ -2506,7 +2555,7 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen }); codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| { - if attr.path != "optimize" { + if attr.path != sym::optimize { return ia; } let err = |sp, s| span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s); @@ -2521,12 +2570,12 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen if items.len() != 1 { err(attr.span, "expected one argument"); OptimizeAttr::None - } else if list_contains_name(&items[..], "size") { + } else if list_contains_name(&items[..], sym::size) { OptimizeAttr::Size - } else if list_contains_name(&items[..], "speed") { + } else if list_contains_name(&items[..], sym::speed) { OptimizeAttr::Speed } else { - err(items[0].span, "invalid argument"); + err(items[0].span(), "invalid argument"); OptimizeAttr::None } } diff --git a/src/librustc_typeck/constrained_generic_params.rs b/src/librustc_typeck/constrained_generic_params.rs new file mode 100644 index 0000000000000..79a04b9423a8e --- /dev/null +++ b/src/librustc_typeck/constrained_generic_params.rs @@ -0,0 +1,210 @@ +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::fold::{TypeFoldable, TypeVisitor}; +use rustc::util::nodemap::FxHashSet; +use rustc::mir::interpret::ConstValue; +use syntax::source_map::Span; + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct Parameter(pub u32); + +impl From for Parameter { + fn from(param: ty::ParamTy) -> Self { Parameter(param.index) } +} + +impl From for Parameter { + fn from(param: ty::EarlyBoundRegion) -> Self { Parameter(param.index) } +} + +impl From for Parameter { + fn from(param: ty::ParamConst) -> Self { Parameter(param.index) } +} + +/// Returns the set of parameters constrained by the impl header. +pub fn parameters_for_impl<'tcx>(impl_self_ty: Ty<'tcx>, + impl_trait_ref: Option>) + -> FxHashSet +{ + let vec = match impl_trait_ref { + Some(tr) => parameters_for(&tr, false), + None => parameters_for(&impl_self_ty, false), + }; + vec.into_iter().collect() +} + +/// If `include_projections` is false, returns the list of parameters that are +/// constrained by `t` - i.e., the value of each parameter in the list is +/// uniquely determined by `t` (see RFC 447). If it is true, return the list +/// of parameters whose values are needed in order to constrain `ty` - these +/// differ, with the latter being a superset, in the presence of projections. +pub fn parameters_for<'tcx, T>(t: &T, + include_nonconstraining: bool) + -> Vec + where T: TypeFoldable<'tcx> +{ + + let mut collector = ParameterCollector { + parameters: vec![], + include_nonconstraining, + }; + t.visit_with(&mut collector); + collector.parameters +} + +struct ParameterCollector { + parameters: Vec, + include_nonconstraining: bool +} + +impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.sty { + ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { + // projections are not injective + return false; + } + ty::Param(data) => { + self.parameters.push(Parameter::from(data)); + } + _ => {} + } + + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + if let ty::ReEarlyBound(data) = *r { + self.parameters.push(Parameter::from(data)); + } + false + } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + if let ConstValue::Param(data) = c.val { + self.parameters.push(Parameter::from(data)); + } + false + } +} + +pub fn identify_constrained_generic_params<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: &ty::GenericPredicates<'tcx>, + impl_trait_ref: Option>, + input_parameters: &mut FxHashSet, +) { + let mut predicates = predicates.predicates.clone(); + setup_constraining_predicates(tcx, &mut predicates, impl_trait_ref, input_parameters); +} + + +/// Order the predicates in `predicates` such that each parameter is +/// constrained before it is used, if that is possible, and add the +/// parameters so constrained to `input_parameters`. For example, +/// imagine the following impl: +/// +/// impl> Trait for U +/// +/// The impl's predicates are collected from left to right. Ignoring +/// the implicit `Sized` bounds, these are +/// * T: Debug +/// * U: Iterator +/// * ::Item = T -- a desugared ProjectionPredicate +/// +/// When we, for example, try to go over the trait-reference +/// `IntoIter as Trait`, we substitute the impl parameters with fresh +/// variables and match them with the impl trait-ref, so we know that +/// `$U = IntoIter`. +/// +/// However, in order to process the `$T: Debug` predicate, we must first +/// know the value of `$T` - which is only given by processing the +/// projection. As we occasionally want to process predicates in a single +/// pass, we want the projection to come first. In fact, as projections +/// can (acyclically) depend on one another - see RFC447 for details - we +/// need to topologically sort them. +/// +/// We *do* have to be somewhat careful when projection targets contain +/// projections themselves, for example in +/// impl Trait for U where +/// /* 0 */ S: Iterator, +/// /* - */ U: Iterator, +/// /* 1 */ ::Item: ToOwned::Item)> +/// /* 2 */ W: Iterator +/// /* 3 */ V: Debug +/// we have to evaluate the projections in the order I wrote them: +/// `V: Debug` requires `V` to be evaluated. The only projection that +/// *determines* `V` is 2 (1 contains it, but *does not determine it*, +/// as it is only contained within a projection), but that requires `W` +/// which is determined by 1, which requires `U`, that is determined +/// by 0. I should probably pick a less tangled example, but I can't +/// think of any. +pub fn setup_constraining_predicates<'tcx>( + tcx: TyCtxt<'_>, + predicates: &mut [(ty::Predicate<'tcx>, Span)], + impl_trait_ref: Option>, + input_parameters: &mut FxHashSet, +) { + // The canonical way of doing the needed topological sort + // would be a DFS, but getting the graph and its ownership + // right is annoying, so I am using an in-place fixed-point iteration, + // which is `O(nt)` where `t` is the depth of type-parameter constraints, + // remembering that `t` should be less than 7 in practice. + // + // Basically, I iterate over all projections and swap every + // "ready" projection to the start of the list, such that + // all of the projections before `i` are topologically sorted + // and constrain all the parameters in `input_parameters`. + // + // In the example, `input_parameters` starts by containing `U` - which + // is constrained by the trait-ref - and so on the first pass we + // observe that `::Item = T` is a "ready" projection that + // constrains `T` and swap it to front. As it is the sole projection, + // no more swaps can take place afterwards, with the result being + // * ::Item = T + // * T: Debug + // * U: Iterator + debug!("setup_constraining_predicates: predicates={:?} \ + impl_trait_ref={:?} input_parameters={:?}", + predicates, impl_trait_ref, input_parameters); + let mut i = 0; + let mut changed = true; + while changed { + changed = false; + + for j in i..predicates.len() { + if let ty::Predicate::Projection(ref poly_projection) = predicates[j].0 { + // Note that we can skip binder here because the impl + // trait ref never contains any late-bound regions. + let projection = poly_projection.skip_binder(); + + // Special case: watch out for some kind of sneaky attempt + // to project out an associated type defined by this very + // trait. + let unbound_trait_ref = projection.projection_ty.trait_ref(tcx); + if Some(unbound_trait_ref.clone()) == impl_trait_ref { + continue; + } + + // A projection depends on its input types and determines its output + // type. For example, if we have + // `<::Baz as Iterator>::Output = ::Output` + // Then the projection only applies if `T` is known, but it still + // does not determine `U`. + let inputs = parameters_for(&projection.projection_ty.trait_ref(tcx), true); + let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p)); + if !relies_only_on_inputs { + continue; + } + input_parameters.extend(parameters_for(&projection.ty, false)); + } else { + continue; + } + // fancy control flow to bypass borrow checker + predicates.swap(i, j); + i += 1; + changed = true; + } + debug!("setup_constraining_predicates: predicates={:?} \ + i={} impl_trait_ref={:?} input_parameters={:?}", + predicates, i, impl_trait_ref, input_parameters); + } +} diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs deleted file mode 100644 index 6a530f454d2b3..0000000000000 --- a/src/librustc_typeck/constrained_type_params.rs +++ /dev/null @@ -1,196 +0,0 @@ -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::fold::{TypeFoldable, TypeVisitor}; -use rustc::util::nodemap::FxHashSet; -use syntax::source_map::Span; - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct Parameter(pub u32); - -impl From for Parameter { - fn from(param: ty::ParamTy) -> Self { Parameter(param.idx) } -} - -impl From for Parameter { - fn from(param: ty::EarlyBoundRegion) -> Self { Parameter(param.index) } -} - -/// Returns the set of parameters constrained by the impl header. -pub fn parameters_for_impl<'tcx>(impl_self_ty: Ty<'tcx>, - impl_trait_ref: Option>) - -> FxHashSet -{ - let vec = match impl_trait_ref { - Some(tr) => parameters_for(&tr, false), - None => parameters_for(&impl_self_ty, false), - }; - vec.into_iter().collect() -} - -/// If `include_projections` is false, returns the list of parameters that are -/// constrained by `t` - i.e., the value of each parameter in the list is -/// uniquely determined by `t` (see RFC 447). If it is true, return the list -/// of parameters whose values are needed in order to constrain `ty` - these -/// differ, with the latter being a superset, in the presence of projections. -pub fn parameters_for<'tcx, T>(t: &T, - include_nonconstraining: bool) - -> Vec - where T: TypeFoldable<'tcx> -{ - - let mut collector = ParameterCollector { - parameters: vec![], - include_nonconstraining, - }; - t.visit_with(&mut collector); - collector.parameters -} - -struct ParameterCollector { - parameters: Vec, - include_nonconstraining: bool -} - -impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.sty { - ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { - // projections are not injective - return false; - } - ty::Param(data) => { - self.parameters.push(Parameter::from(data)); - } - _ => {} - } - - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - if let ty::ReEarlyBound(data) = *r { - self.parameters.push(Parameter::from(data)); - } - false - } -} - -pub fn identify_constrained_type_params<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, - predicates: &ty::GenericPredicates<'tcx>, - impl_trait_ref: Option>, - input_parameters: &mut FxHashSet) -{ - let mut predicates = predicates.predicates.clone(); - setup_constraining_predicates(tcx, &mut predicates, impl_trait_ref, input_parameters); -} - - -/// Order the predicates in `predicates` such that each parameter is -/// constrained before it is used, if that is possible, and add the -/// parameters so constrained to `input_parameters`. For example, -/// imagine the following impl: -/// -/// impl> Trait for U -/// -/// The impl's predicates are collected from left to right. Ignoring -/// the implicit `Sized` bounds, these are -/// * T: Debug -/// * U: Iterator -/// * ::Item = T -- a desugared ProjectionPredicate -/// -/// When we, for example, try to go over the trait-reference -/// `IntoIter as Trait`, we substitute the impl parameters with fresh -/// variables and match them with the impl trait-ref, so we know that -/// `$U = IntoIter`. -/// -/// However, in order to process the `$T: Debug` predicate, we must first -/// know the value of `$T` - which is only given by processing the -/// projection. As we occasionally want to process predicates in a single -/// pass, we want the projection to come first. In fact, as projections -/// can (acyclically) depend on one another - see RFC447 for details - we -/// need to topologically sort them. -/// -/// We *do* have to be somewhat careful when projection targets contain -/// projections themselves, for example in -/// impl Trait for U where -/// /* 0 */ S: Iterator, -/// /* - */ U: Iterator, -/// /* 1 */ ::Item: ToOwned::Item)> -/// /* 2 */ W: Iterator -/// /* 3 */ V: Debug -/// we have to evaluate the projections in the order I wrote them: -/// `V: Debug` requires `V` to be evaluated. The only projection that -/// *determines* `V` is 2 (1 contains it, but *does not determine it*, -/// as it is only contained within a projection), but that requires `W` -/// which is determined by 1, which requires `U`, that is determined -/// by 0. I should probably pick a less tangled example, but I can't -/// think of any. -pub fn setup_constraining_predicates<'tcx>(tcx: TyCtxt<'_, '_, '_>, - predicates: &mut [(ty::Predicate<'tcx>, Span)], - impl_trait_ref: Option>, - input_parameters: &mut FxHashSet) -{ - // The canonical way of doing the needed topological sort - // would be a DFS, but getting the graph and its ownership - // right is annoying, so I am using an in-place fixed-point iteration, - // which is `O(nt)` where `t` is the depth of type-parameter constraints, - // remembering that `t` should be less than 7 in practice. - // - // Basically, I iterate over all projections and swap every - // "ready" projection to the start of the list, such that - // all of the projections before `i` are topologically sorted - // and constrain all the parameters in `input_parameters`. - // - // In the example, `input_parameters` starts by containing `U` - which - // is constrained by the trait-ref - and so on the first pass we - // observe that `::Item = T` is a "ready" projection that - // constrains `T` and swap it to front. As it is the sole projection, - // no more swaps can take place afterwards, with the result being - // * ::Item = T - // * T: Debug - // * U: Iterator - debug!("setup_constraining_predicates: predicates={:?} \ - impl_trait_ref={:?} input_parameters={:?}", - predicates, impl_trait_ref, input_parameters); - let mut i = 0; - let mut changed = true; - while changed { - changed = false; - - for j in i..predicates.len() { - if let ty::Predicate::Projection(ref poly_projection) = predicates[j].0 { - // Note that we can skip binder here because the impl - // trait ref never contains any late-bound regions. - let projection = poly_projection.skip_binder(); - - // Special case: watch out for some kind of sneaky attempt - // to project out an associated type defined by this very - // trait. - let unbound_trait_ref = projection.projection_ty.trait_ref(tcx); - if Some(unbound_trait_ref.clone()) == impl_trait_ref { - continue; - } - - // A projection depends on its input types and determines its output - // type. For example, if we have - // `<::Baz as Iterator>::Output = ::Output` - // Then the projection only applies if `T` is known, but it still - // does not determine `U`. - let inputs = parameters_for(&projection.projection_ty.trait_ref(tcx), true); - let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p)); - if !relies_only_on_inputs { - continue; - } - input_parameters.extend(parameters_for(&projection.ty, false)); - } else { - continue; - } - // fancy control flow to bypass borrow checker - predicates.swap(i, j); - i += 1; - changed = true; - } - debug!("setup_constraining_predicates: predicates={:?} \ - i={} impl_trait_ref={:?} input_parameters={:?}", - predicates, i, impl_trait_ref, input_parameters); - } -} diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs deleted file mode 100644 index feff79dc3f508..0000000000000 --- a/src/librustc_typeck/diagnostics.rs +++ /dev/null @@ -1,4744 +0,0 @@ -// ignore-tidy-linelength -#![allow(non_snake_case)] - -register_long_diagnostics! { - -E0023: r##" -A pattern used to match against an enum variant must provide a sub-pattern for -each field of the enum variant. This error indicates that a pattern attempted to -extract an incorrect number of fields from a variant. - -``` -enum Fruit { - Apple(String, String), - Pear(u32), -} -``` - -Here the `Apple` variant has two fields, and should be matched against like so: - -``` -enum Fruit { - Apple(String, String), - Pear(u32), -} - -let x = Fruit::Apple(String::new(), String::new()); - -// Correct. -match x { - Fruit::Apple(a, b) => {}, - _ => {} -} -``` - -Matching with the wrong number of fields has no sensible interpretation: - -```compile_fail,E0023 -enum Fruit { - Apple(String, String), - Pear(u32), -} - -let x = Fruit::Apple(String::new(), String::new()); - -// Incorrect. -match x { - Fruit::Apple(a) => {}, - Fruit::Apple(a, b, c) => {}, -} -``` - -Check how many fields the enum was declared with and ensure that your pattern -uses the same number. -"##, - -E0025: r##" -Each field of a struct can only be bound once in a pattern. Erroneous code -example: - -```compile_fail,E0025 -struct Foo { - a: u8, - b: u8, -} - -fn main(){ - let x = Foo { a:1, b:2 }; - - let Foo { a: x, a: y } = x; - // error: field `a` bound multiple times in the pattern -} -``` - -Each occurrence of a field name binds the value of that field, so to fix this -error you will have to remove or alter the duplicate uses of the field name. -Perhaps you misspelled another field name? Example: - -``` -struct Foo { - a: u8, - b: u8, -} - -fn main(){ - let x = Foo { a:1, b:2 }; - - let Foo { a: x, b: y } = x; // ok! -} -``` -"##, - -E0026: r##" -This error indicates that a struct pattern attempted to extract a non-existent -field from a struct. Struct fields are identified by the name used before the -colon `:` so struct patterns should resemble the declaration of the struct type -being matched. - -``` -// Correct matching. -struct Thing { - x: u32, - y: u32 -} - -let thing = Thing { x: 1, y: 2 }; - -match thing { - Thing { x: xfield, y: yfield } => {} -} -``` - -If you are using shorthand field patterns but want to refer to the struct field -by a different name, you should rename it explicitly. - -Change this: - -```compile_fail,E0026 -struct Thing { - x: u32, - y: u32 -} - -let thing = Thing { x: 0, y: 0 }; - -match thing { - Thing { x, z } => {} -} -``` - -To this: - -``` -struct Thing { - x: u32, - y: u32 -} - -let thing = Thing { x: 0, y: 0 }; - -match thing { - Thing { x, y: z } => {} -} -``` -"##, - -E0027: r##" -This error indicates that a pattern for a struct fails to specify a sub-pattern -for every one of the struct's fields. Ensure that each field from the struct's -definition is mentioned in the pattern, or use `..` to ignore unwanted fields. - -For example: - -```compile_fail,E0027 -struct Dog { - name: String, - age: u32, -} - -let d = Dog { name: "Rusty".to_string(), age: 8 }; - -// This is incorrect. -match d { - Dog { age: x } => {} -} -``` - -This is correct (explicit): - -``` -struct Dog { - name: String, - age: u32, -} - -let d = Dog { name: "Rusty".to_string(), age: 8 }; - -match d { - Dog { name: ref n, age: x } => {} -} - -// This is also correct (ignore unused fields). -match d { - Dog { age: x, .. } => {} -} -``` -"##, - -E0029: r##" -In a match expression, only numbers and characters can be matched against a -range. This is because the compiler checks that the range is non-empty at -compile-time, and is unable to evaluate arbitrary comparison functions. If you -want to capture values of an orderable type between two end-points, you can use -a guard. - -```compile_fail,E0029 -let string = "salutations !"; - -// The ordering relation for strings can't be evaluated at compile time, -// so this doesn't work: -match string { - "hello" ..= "world" => {} - _ => {} -} - -// This is a more general version, using a guard: -match string { - s if s >= "hello" && s <= "world" => {} - _ => {} -} -``` -"##, - -E0033: r##" -This error indicates that a pointer to a trait type cannot be implicitly -dereferenced by a pattern. Every trait defines a type, but because the -size of trait implementors isn't fixed, this type has no compile-time size. -Therefore, all accesses to trait types must be through pointers. If you -encounter this error you should try to avoid dereferencing the pointer. - -```compile_fail,E0033 -# trait SomeTrait { fn method_one(&self){} fn method_two(&self){} } -# impl SomeTrait for T {} -let trait_obj: &SomeTrait = &"some_value"; - -// This tries to implicitly dereference to create an unsized local variable. -let &invalid = trait_obj; - -// You can call methods without binding to the value being pointed at. -trait_obj.method_one(); -trait_obj.method_two(); -``` - -You can read more about trait objects in the [Trait Objects] section of the -Reference. - -[Trait Objects]: https://doc.rust-lang.org/reference/types.html#trait-objects -"##, - -E0034: r##" -The compiler doesn't know what method to call because more than one method -has the same prototype. Erroneous code example: - -```compile_fail,E0034 -struct Test; - -trait Trait1 { - fn foo(); -} - -trait Trait2 { - fn foo(); -} - -impl Trait1 for Test { fn foo() {} } -impl Trait2 for Test { fn foo() {} } - -fn main() { - Test::foo() // error, which foo() to call? -} -``` - -To avoid this error, you have to keep only one of them and remove the others. -So let's take our example and fix it: - -``` -struct Test; - -trait Trait1 { - fn foo(); -} - -impl Trait1 for Test { fn foo() {} } - -fn main() { - Test::foo() // and now that's good! -} -``` - -However, a better solution would be using fully explicit naming of type and -trait: - -``` -struct Test; - -trait Trait1 { - fn foo(); -} - -trait Trait2 { - fn foo(); -} - -impl Trait1 for Test { fn foo() {} } -impl Trait2 for Test { fn foo() {} } - -fn main() { - ::foo() -} -``` - -One last example: - -``` -trait F { - fn m(&self); -} - -trait G { - fn m(&self); -} - -struct X; - -impl F for X { fn m(&self) { println!("I am F"); } } -impl G for X { fn m(&self) { println!("I am G"); } } - -fn main() { - let f = X; - - F::m(&f); // it displays "I am F" - G::m(&f); // it displays "I am G" -} -``` -"##, - -E0040: r##" -It is not allowed to manually call destructors in Rust. It is also not -necessary to do this since `drop` is called automatically whenever a value goes -out of scope. - -Here's an example of this error: - -```compile_fail,E0040 -struct Foo { - x: i32, -} - -impl Drop for Foo { - fn drop(&mut self) { - println!("kaboom"); - } -} - -fn main() { - let mut x = Foo { x: -7 }; - x.drop(); // error: explicit use of destructor method -} -``` -"##, - -E0044: r##" -You can't use type or const parameters on foreign items. -Example of erroneous code: - -```compile_fail,E0044 -extern { fn some_func(x: T); } -``` - -To fix this, replace the generic parameter with the specializations that you -need: - -``` -extern { fn some_func_i32(x: i32); } -extern { fn some_func_i64(x: i64); } -``` -"##, - -E0045: r##" -Rust only supports variadic parameters for interoperability with C code in its -FFI. As such, variadic parameters can only be used with functions which are -using the C ABI. Examples of erroneous code: - -```compile_fail -#![feature(unboxed_closures)] - -extern "rust-call" { fn foo(x: u8, ...); } - -// or - -fn foo(x: u8, ...) {} -``` - -To fix such code, put them in an extern "C" block: - -``` -extern "C" { - fn foo (x: u8, ...); -} -``` -"##, - -E0046: r##" -Items are missing in a trait implementation. Erroneous code example: - -```compile_fail,E0046 -trait Foo { - fn foo(); -} - -struct Bar; - -impl Foo for Bar {} -// error: not all trait items implemented, missing: `foo` -``` - -When trying to make some type implement a trait `Foo`, you must, at minimum, -provide implementations for all of `Foo`'s required methods (meaning the -methods that do not have default implementations), as well as any required -trait items like associated types or constants. Example: - -``` -trait Foo { - fn foo(); -} - -struct Bar; - -impl Foo for Bar { - fn foo() {} // ok! -} -``` -"##, - -E0049: r##" -This error indicates that an attempted implementation of a trait method -has the wrong number of type parameters. - -For example, the trait below has a method `foo` with a type parameter `T`, -but the implementation of `foo` for the type `Bar` is missing this parameter: - -```compile_fail,E0049 -trait Foo { - fn foo(x: T) -> Self; -} - -struct Bar; - -// error: method `foo` has 0 type parameters but its trait declaration has 1 -// type parameter -impl Foo for Bar { - fn foo(x: bool) -> Self { Bar } -} -``` -"##, - -E0050: r##" -This error indicates that an attempted implementation of a trait method -has the wrong number of function parameters. - -For example, the trait below has a method `foo` with two function parameters -(`&self` and `u8`), but the implementation of `foo` for the type `Bar` omits -the `u8` parameter: - -```compile_fail,E0050 -trait Foo { - fn foo(&self, x: u8) -> bool; -} - -struct Bar; - -// error: method `foo` has 1 parameter but the declaration in trait `Foo::foo` -// has 2 -impl Foo for Bar { - fn foo(&self) -> bool { true } -} -``` -"##, - -E0053: r##" -The parameters of any trait method must match between a trait implementation -and the trait definition. - -Here are a couple examples of this error: - -```compile_fail,E0053 -trait Foo { - fn foo(x: u16); - fn bar(&self); -} - -struct Bar; - -impl Foo for Bar { - // error, expected u16, found i16 - fn foo(x: i16) { } - - // error, types differ in mutability - fn bar(&mut self) { } -} -``` -"##, - -E0054: r##" -It is not allowed to cast to a bool. If you are trying to cast a numeric type -to a bool, you can compare it with zero instead: - -```compile_fail,E0054 -let x = 5; - -// Not allowed, won't compile -let x_is_nonzero = x as bool; -``` - -``` -let x = 5; - -// Ok -let x_is_nonzero = x != 0; -``` -"##, - -E0055: r##" -During a method call, a value is automatically dereferenced as many times as -needed to make the value's type match the method's receiver. The catch is that -the compiler will only attempt to dereference a number of times up to the -recursion limit (which can be set via the `recursion_limit` attribute). - -For a somewhat artificial example: - -```compile_fail,E0055 -#![recursion_limit="5"] - -struct Foo; - -impl Foo { - fn foo(&self) {} -} - -fn main() { - let foo = Foo; - let ref_foo = &&&&&Foo; - - // error, reached the recursion limit while auto-dereferencing `&&&&&Foo` - ref_foo.foo(); -} -``` - -One fix may be to increase the recursion limit. Note that it is possible to -create an infinite recursion of dereferencing, in which case the only fix is to -somehow break the recursion. -"##, - -E0057: r##" -When invoking closures or other implementations of the function traits `Fn`, -`FnMut` or `FnOnce` using call notation, the number of parameters passed to the -function must match its definition. - -An example using a closure: - -```compile_fail,E0057 -let f = |x| x * 3; -let a = f(); // invalid, too few parameters -let b = f(4); // this works! -let c = f(2, 3); // invalid, too many parameters -``` - -A generic function must be treated similarly: - -``` -fn foo(f: F) { - f(); // this is valid, but f(3) would not work -} -``` -"##, - -E0059: r##" -The built-in function traits are generic over a tuple of the function arguments. -If one uses angle-bracket notation (`Fn<(T,), Output=U>`) instead of parentheses -(`Fn(T) -> U`) to denote the function trait, the type parameter should be a -tuple. Otherwise function call notation cannot be used and the trait will not be -implemented by closures. - -The most likely source of this error is using angle-bracket notation without -wrapping the function argument type into a tuple, for example: - -```compile_fail,E0059 -#![feature(unboxed_closures)] - -fn foo>(f: F) -> F::Output { f(3) } -``` - -It can be fixed by adjusting the trait bound like this: - -``` -#![feature(unboxed_closures)] - -fn foo>(f: F) -> F::Output { f(3) } -``` - -Note that `(T,)` always denotes the type of a 1-tuple containing an element of -type `T`. The comma is necessary for syntactic disambiguation. -"##, - -E0060: r##" -External C functions are allowed to be variadic. However, a variadic function -takes a minimum number of arguments. For example, consider C's variadic `printf` -function: - -``` -use std::os::raw::{c_char, c_int}; - -extern "C" { - fn printf(_: *const c_char, ...) -> c_int; -} -``` - -Using this declaration, it must be called with at least one argument, so -simply calling `printf()` is invalid. But the following uses are allowed: - -``` -# #![feature(static_nobundle)] -# use std::os::raw::{c_char, c_int}; -# #[cfg_attr(all(windows, target_env = "msvc"), -# link(name = "legacy_stdio_definitions", kind = "static-nobundle"))] -# extern "C" { fn printf(_: *const c_char, ...) -> c_int; } -# fn main() { -unsafe { - use std::ffi::CString; - - let fmt = CString::new("test\n").unwrap(); - printf(fmt.as_ptr()); - - let fmt = CString::new("number = %d\n").unwrap(); - printf(fmt.as_ptr(), 3); - - let fmt = CString::new("%d, %d\n").unwrap(); - printf(fmt.as_ptr(), 10, 5); -} -# } -``` -"##, -// ^ Note: On MSVC 2015, the `printf` function is "inlined" in the C code, and -// the C runtime does not contain the `printf` definition. This leads to linker -// error from the doc test (issue #42830). -// This can be fixed by linking to the static library -// `legacy_stdio_definitions.lib` (see https://stackoverflow.com/a/36504365/). -// If this compatibility library is removed in the future, consider changing -// `printf` in this example to another well-known variadic function. - -E0061: r##" -The number of arguments passed to a function must match the number of arguments -specified in the function signature. - -For example, a function like: - -``` -fn f(a: u16, b: &str) {} -``` - -Must always be called with exactly two arguments, e.g., `f(2, "test")`. - -Note that Rust does not have a notion of optional function arguments or -variadic functions (except for its C-FFI). -"##, - -E0062: r##" -This error indicates that during an attempt to build a struct or struct-like -enum variant, one of the fields was specified more than once. Erroneous code -example: - -```compile_fail,E0062 -struct Foo { - x: i32, -} - -fn main() { - let x = Foo { - x: 0, - x: 0, // error: field `x` specified more than once - }; -} -``` - -Each field should be specified exactly one time. Example: - -``` -struct Foo { - x: i32, -} - -fn main() { - let x = Foo { x: 0 }; // ok! -} -``` -"##, - -E0063: r##" -This error indicates that during an attempt to build a struct or struct-like -enum variant, one of the fields was not provided. Erroneous code example: - -```compile_fail,E0063 -struct Foo { - x: i32, - y: i32, -} - -fn main() { - let x = Foo { x: 0 }; // error: missing field: `y` -} -``` - -Each field should be specified exactly once. Example: - -``` -struct Foo { - x: i32, - y: i32, -} - -fn main() { - let x = Foo { x: 0, y: 0 }; // ok! -} -``` -"##, - -E0067: r##" -The left-hand side of a compound assignment expression must be a place -expression. A place expression represents a memory location and includes -item paths (ie, namespaced variables), dereferences, indexing expressions, -and field references. - -Let's start with some erroneous code examples: - -```compile_fail,E0067 -use std::collections::LinkedList; - -// Bad: assignment to non-place expression -LinkedList::new() += 1; - -// ... - -fn some_func(i: &mut i32) { - i += 12; // Error : '+=' operation cannot be applied on a reference ! -} -``` - -And now some working examples: - -``` -let mut i : i32 = 0; - -i += 12; // Good ! - -// ... - -fn some_func(i: &mut i32) { - *i += 12; // Good ! -} -``` -"##, - -E0069: r##" -The compiler found a function whose body contains a `return;` statement but -whose return type is not `()`. An example of this is: - -```compile_fail,E0069 -// error -fn foo() -> u8 { - return; -} -``` - -Since `return;` is just like `return ();`, there is a mismatch between the -function's return type and the value being returned. -"##, - -E0070: r##" -The left-hand side of an assignment operator must be a place expression. A -place expression represents a memory location and can be a variable (with -optional namespacing), a dereference, an indexing expression or a field -reference. - -More details can be found in the [Expressions] section of the Reference. - -[Expressions]: https://doc.rust-lang.org/reference/expressions.html#places-rvalues-and-temporaries - -Now, we can go further. Here are some erroneous code examples: - -```compile_fail,E0070 -struct SomeStruct { - x: i32, - y: i32 -} - -const SOME_CONST : i32 = 12; - -fn some_other_func() {} - -fn some_function() { - SOME_CONST = 14; // error : a constant value cannot be changed! - 1 = 3; // error : 1 isn't a valid place! - some_other_func() = 4; // error : we can't assign value to a function! - SomeStruct.x = 12; // error : SomeStruct a structure name but it is used - // like a variable! -} -``` - -And now let's give working examples: - -``` -struct SomeStruct { - x: i32, - y: i32 -} -let mut s = SomeStruct {x: 0, y: 0}; - -s.x = 3; // that's good ! - -// ... - -fn some_func(x: &mut i32) { - *x = 12; // that's good ! -} -``` -"##, - -E0071: r##" -You tried to use structure-literal syntax to create an item that is -not a structure or enum variant. - -Example of erroneous code: - -```compile_fail,E0071 -type U32 = u32; -let t = U32 { value: 4 }; // error: expected struct, variant or union type, - // found builtin type `u32` -``` - -To fix this, ensure that the name was correctly spelled, and that -the correct form of initializer was used. - -For example, the code above can be fixed to: - -``` -enum Foo { - FirstValue(i32) -} - -fn main() { - let u = Foo::FirstValue(0i32); - - let t = 4; -} -``` -"##, - -E0073: r##" -#### Note: this error code is no longer emitted by the compiler. - -You cannot define a struct (or enum) `Foo` that requires an instance of `Foo` -in order to make a new `Foo` value. This is because there would be no way a -first instance of `Foo` could be made to initialize another instance! - -Here's an example of a struct that has this problem: - -``` -struct Foo { x: Box } // error -``` - -One fix is to use `Option`, like so: - -``` -struct Foo { x: Option> } -``` - -Now it's possible to create at least one instance of `Foo`: `Foo { x: None }`. -"##, - -E0074: r##" -#### Note: this error code is no longer emitted by the compiler. - -When using the `#[simd]` attribute on a tuple struct, the components of the -tuple struct must all be of a concrete, nongeneric type so the compiler can -reason about how to use SIMD with them. This error will occur if the types -are generic. - -This will cause an error: - -``` -#![feature(repr_simd)] - -#[repr(simd)] -struct Bad(T, T, T); -``` - -This will not: - -``` -#![feature(repr_simd)] - -#[repr(simd)] -struct Good(u32, u32, u32); -``` -"##, - -E0075: r##" -The `#[simd]` attribute can only be applied to non empty tuple structs, because -it doesn't make sense to try to use SIMD operations when there are no values to -operate on. - -This will cause an error: - -```compile_fail,E0075 -#![feature(repr_simd)] - -#[repr(simd)] -struct Bad; -``` - -This will not: - -``` -#![feature(repr_simd)] - -#[repr(simd)] -struct Good(u32); -``` -"##, - -E0076: r##" -When using the `#[simd]` attribute to automatically use SIMD operations in tuple -struct, the types in the struct must all be of the same type, or the compiler -will trigger this error. - -This will cause an error: - -```compile_fail,E0076 -#![feature(repr_simd)] - -#[repr(simd)] -struct Bad(u16, u32, u32); -``` - -This will not: - -``` -#![feature(repr_simd)] - -#[repr(simd)] -struct Good(u32, u32, u32); -``` -"##, - -E0077: r##" -When using the `#[simd]` attribute on a tuple struct, the elements in the tuple -must be machine types so SIMD operations can be applied to them. - -This will cause an error: - -```compile_fail,E0077 -#![feature(repr_simd)] - -#[repr(simd)] -struct Bad(String); -``` - -This will not: - -``` -#![feature(repr_simd)] - -#[repr(simd)] -struct Good(u32, u32, u32); -``` -"##, - -E0081: r##" -Enum discriminants are used to differentiate enum variants stored in memory. -This error indicates that the same value was used for two or more variants, -making them impossible to tell apart. - -```compile_fail,E0081 -// Bad. -enum Enum { - P = 3, - X = 3, - Y = 5, -} -``` - -``` -// Good. -enum Enum { - P, - X = 3, - Y = 5, -} -``` - -Note that variants without a manually specified discriminant are numbered from -top to bottom starting from 0, so clashes can occur with seemingly unrelated -variants. - -```compile_fail,E0081 -enum Bad { - X, - Y = 0 -} -``` - -Here `X` will have already been specified the discriminant 0 by the time `Y` is -encountered, so a conflict occurs. -"##, - -E0084: r##" -An unsupported representation was attempted on a zero-variant enum. - -Erroneous code example: - -```compile_fail,E0084 -#[repr(i32)] -enum NightsWatch {} // error: unsupported representation for zero-variant enum -``` - -It is impossible to define an integer type to be used to represent zero-variant -enum values because there are no zero-variant enum values. There is no way to -construct an instance of the following type using only safe code. So you have -two solutions. Either you add variants in your enum: - -``` -#[repr(i32)] -enum NightsWatch { - JonSnow, - Commander, -} -``` - -or you remove the integer represention of your enum: - -``` -enum NightsWatch {} -``` -"##, - -E0087: r##" -#### Note: this error code is no longer emitted by the compiler. - -Too many type arguments were supplied for a function. For example: - -```compile_fail,E0107 -fn foo() {} - -fn main() { - foo::(); // error: wrong number of type arguments: - // expected 1, found 2 -} -``` - -The number of supplied arguments must exactly match the number of defined type -parameters. -"##, - -E0088: r##" -#### Note: this error code is no longer emitted by the compiler. - -You gave too many lifetime arguments. Erroneous code example: - -```compile_fail,E0107 -fn f() {} - -fn main() { - f::<'static>() // error: wrong number of lifetime arguments: - // expected 0, found 1 -} -``` - -Please check you give the right number of lifetime arguments. Example: - -``` -fn f() {} - -fn main() { - f() // ok! -} -``` - -It's also important to note that the Rust compiler can generally -determine the lifetime by itself. Example: - -``` -struct Foo { - value: String -} - -impl Foo { - // it can be written like this - fn get_value<'a>(&'a self) -> &'a str { &self.value } - // but the compiler works fine with this too: - fn without_lifetime(&self) -> &str { &self.value } -} - -fn main() { - let f = Foo { value: "hello".to_owned() }; - - println!("{}", f.get_value()); - println!("{}", f.without_lifetime()); -} -``` -"##, - -E0089: r##" -#### Note: this error code is no longer emitted by the compiler. - -Too few type arguments were supplied for a function. For example: - -```compile_fail,E0107 -fn foo() {} - -fn main() { - foo::(); // error: wrong number of type arguments: expected 2, found 1 -} -``` - -Note that if a function takes multiple type arguments but you want the compiler -to infer some of them, you can use type placeholders: - -```compile_fail,E0107 -fn foo(x: T) {} - -fn main() { - let x: bool = true; - foo::(x); // error: wrong number of type arguments: - // expected 2, found 1 - foo::<_, f64>(x); // same as `foo::(x)` -} -``` -"##, - -E0090: r##" -#### Note: this error code is no longer emitted by the compiler. - -You gave too few lifetime arguments. Example: - -```compile_fail,E0107 -fn foo<'a: 'b, 'b: 'a>() {} - -fn main() { - foo::<'static>(); // error: wrong number of lifetime arguments: - // expected 2, found 1 -} -``` - -Please check you give the right number of lifetime arguments. Example: - -``` -fn foo<'a: 'b, 'b: 'a>() {} - -fn main() { - foo::<'static, 'static>(); -} -``` -"##, - -E0091: r##" -You gave an unnecessary type parameter in a type alias. Erroneous code -example: - -```compile_fail,E0091 -type Foo = u32; // error: type parameter `T` is unused -// or: -type Foo = Box; // error: type parameter `B` is unused -``` - -Please check you didn't write too many type parameters. Example: - -``` -type Foo = u32; // ok! -type Foo2 = Box; // ok! -``` -"##, - -E0092: r##" -You tried to declare an undefined atomic operation function. -Erroneous code example: - -```compile_fail,E0092 -#![feature(intrinsics)] - -extern "rust-intrinsic" { - fn atomic_foo(); // error: unrecognized atomic operation - // function -} -``` - -Please check you didn't make a mistake in the function's name. All intrinsic -functions are defined in librustc_codegen_llvm/intrinsic.rs and in -libcore/intrinsics.rs in the Rust source code. Example: - -``` -#![feature(intrinsics)] - -extern "rust-intrinsic" { - fn atomic_fence(); // ok! -} -``` -"##, - -E0093: r##" -You declared an unknown intrinsic function. Erroneous code example: - -```compile_fail,E0093 -#![feature(intrinsics)] - -extern "rust-intrinsic" { - fn foo(); // error: unrecognized intrinsic function: `foo` -} - -fn main() { - unsafe { - foo(); - } -} -``` - -Please check you didn't make a mistake in the function's name. All intrinsic -functions are defined in librustc_codegen_llvm/intrinsic.rs and in -libcore/intrinsics.rs in the Rust source code. Example: - -``` -#![feature(intrinsics)] - -extern "rust-intrinsic" { - fn atomic_fence(); // ok! -} - -fn main() { - unsafe { - atomic_fence(); - } -} -``` -"##, - -E0094: r##" -You gave an invalid number of type parameters to an intrinsic function. -Erroneous code example: - -```compile_fail,E0094 -#![feature(intrinsics)] - -extern "rust-intrinsic" { - fn size_of() -> usize; // error: intrinsic has wrong number - // of type parameters -} -``` - -Please check that you provided the right number of type parameters -and verify with the function declaration in the Rust source code. -Example: - -``` -#![feature(intrinsics)] - -extern "rust-intrinsic" { - fn size_of() -> usize; // ok! -} -``` -"##, - -E0107: r##" -This error means that an incorrect number of generic arguments were provided: - -```compile_fail,E0107 -struct Foo { x: T } - -struct Bar { x: Foo } // error: wrong number of type arguments: - // expected 1, found 0 -struct Baz { x: Foo } // error: wrong number of type arguments: - // expected 1, found 2 - -fn foo(x: T, y: U) {} - -fn main() { - let x: bool = true; - foo::(x); // error: wrong number of type arguments: - // expected 2, found 1 - foo::(x, 2, 4); // error: wrong number of type arguments: - // expected 2, found 3 -} - -fn f() {} - -fn main() { - f::<'static>(); // error: wrong number of lifetime arguments: - // expected 0, found 1 -} -``` - -"##, - -E0109: r##" -You tried to give a type parameter to a type which doesn't need it. Erroneous -code example: - -```compile_fail,E0109 -type X = u32; // error: type arguments are not allowed on this entity -``` - -Please check that you used the correct type and recheck its definition. Perhaps -it doesn't need the type parameter. - -Example: - -``` -type X = u32; // this compiles -``` - -Note that type parameters for enum-variant constructors go after the variant, -not after the enum (`Option::None::`, not `Option::::None`). -"##, - -E0110: r##" -You tried to give a lifetime parameter to a type which doesn't need it. -Erroneous code example: - -```compile_fail,E0110 -type X = u32<'static>; // error: lifetime parameters are not allowed on - // this type -``` - -Please check that the correct type was used and recheck its definition; perhaps -it doesn't need the lifetime parameter. Example: - -``` -type X = u32; // ok! -``` -"##, - -E0111: r##" -You tried to give a const parameter to a type which doesn't need it. -"##, - -E0116: r##" -You can only define an inherent implementation for a type in the same crate -where the type was defined. For example, an `impl` block as below is not allowed -since `Vec` is defined in the standard library: - -```compile_fail,E0116 -impl Vec { } // error -``` - -To fix this problem, you can do either of these things: - - - define a trait that has the desired associated functions/types/constants and - implement the trait for the type in question - - define a new type wrapping the type and define an implementation on the new - type - -Note that using the `type` keyword does not work here because `type` only -introduces a type alias: - -```compile_fail,E0116 -type Bytes = Vec; - -impl Bytes { } // error, same as above -``` -"##, - -E0117: r##" -This error indicates a violation of one of Rust's orphan rules for trait -implementations. The rule prohibits any implementation of a foreign trait (a -trait defined in another crate) where - - - the type that is implementing the trait is foreign - - all of the parameters being passed to the trait (if there are any) are also - foreign. - -Here's one example of this error: - -```compile_fail,E0117 -impl Drop for u32 {} -``` - -To avoid this kind of error, ensure that at least one local type is referenced -by the `impl`: - -``` -pub struct Foo; // you define your type in your crate - -impl Drop for Foo { // and you can implement the trait on it! - // code of trait implementation here -# fn drop(&mut self) { } -} - -impl From for i32 { // or you use a type from your crate as - // a type parameter - fn from(i: Foo) -> i32 { - 0 - } -} -``` - -Alternatively, define a trait locally and implement that instead: - -``` -trait Bar { - fn get(&self) -> usize; -} - -impl Bar for u32 { - fn get(&self) -> usize { 0 } -} -``` - -For information on the design of the orphan rules, see [RFC 1023]. - -[RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md -"##, - -E0118: r##" -You're trying to write an inherent implementation for something which isn't a -struct nor an enum. Erroneous code example: - -```compile_fail,E0118 -impl (u8, u8) { // error: no base type found for inherent implementation - fn get_state(&self) -> String { - // ... - } -} -``` - -To fix this error, please implement a trait on the type or wrap it in a struct. -Example: - -``` -// we create a trait here -trait LiveLongAndProsper { - fn get_state(&self) -> String; -} - -// and now you can implement it on (u8, u8) -impl LiveLongAndProsper for (u8, u8) { - fn get_state(&self) -> String { - "He's dead, Jim!".to_owned() - } -} -``` - -Alternatively, you can create a newtype. A newtype is a wrapping tuple-struct. -For example, `NewType` is a newtype over `Foo` in `struct NewType(Foo)`. -Example: - -``` -struct TypeWrapper((u8, u8)); - -impl TypeWrapper { - fn get_state(&self) -> String { - "Fascinating!".to_owned() - } -} -``` -"##, - -E0120: r##" -An attempt was made to implement Drop on a trait, which is not allowed: only -structs and enums can implement Drop. An example causing this error: - -```compile_fail,E0120 -trait MyTrait {} - -impl Drop for MyTrait { - fn drop(&mut self) {} -} -``` - -A workaround for this problem is to wrap the trait up in a struct, and implement -Drop on that. An example is shown below: - -``` -trait MyTrait {} -struct MyWrapper { foo: T } - -impl Drop for MyWrapper { - fn drop(&mut self) {} -} - -``` - -Alternatively, wrapping trait objects requires something like the following: - -``` -trait MyTrait {} - -//or Box, if you wanted an owned trait object -struct MyWrapper<'a> { foo: &'a MyTrait } - -impl <'a> Drop for MyWrapper<'a> { - fn drop(&mut self) {} -} -``` -"##, - -E0121: r##" -In order to be consistent with Rust's lack of global type inference, type -placeholders are disallowed by design in item signatures. - -Examples of this error include: - -```compile_fail,E0121 -fn foo() -> _ { 5 } // error, explicitly write out the return type instead - -static BAR: _ = "test"; // error, explicitly write out the type instead -``` -"##, - -E0124: r##" -You declared two fields of a struct with the same name. Erroneous code -example: - -```compile_fail,E0124 -struct Foo { - field1: i32, - field1: i32, // error: field is already declared -} -``` - -Please verify that the field names have been correctly spelled. Example: - -``` -struct Foo { - field1: i32, - field2: i32, // ok! -} -``` -"##, - -E0131: r##" -It is not possible to define `main` with generic parameters. -When `main` is present, it must take no arguments and return `()`. -Erroneous code example: - -```compile_fail,E0131 -fn main() { // error: main function is not allowed to have generic parameters -} -``` -"##, - -E0132: r##" -A function with the `start` attribute was declared with type parameters. - -Erroneous code example: - -```compile_fail,E0132 -#![feature(start)] - -#[start] -fn f() {} -``` - -It is not possible to declare type parameters on a function that has the `start` -attribute. Such a function must have the following type signature (for more -information, view [the unstable book][1]): - -[1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#writing-an-executable-without-stdlib - -``` -# let _: -fn(isize, *const *const u8) -> isize; -``` - -Example: - -``` -#![feature(start)] - -#[start] -fn my_start(argc: isize, argv: *const *const u8) -> isize { - 0 -} -``` -"##, - -E0164: r##" -This error means that an attempt was made to match a struct type enum -variant as a non-struct type: - -```compile_fail,E0164 -enum Foo { B { i: u32 } } - -fn bar(foo: Foo) -> u32 { - match foo { - Foo::B(i) => i, // error E0164 - } -} -``` - -Try using `{}` instead: - -``` -enum Foo { B { i: u32 } } - -fn bar(foo: Foo) -> u32 { - match foo { - Foo::B{i} => i, - } -} -``` -"##, - -E0184: r##" -Explicitly implementing both Drop and Copy for a type is currently disallowed. -This feature can make some sense in theory, but the current implementation is -incorrect and can lead to memory unsafety (see [issue #20126][iss20126]), so -it has been disabled for now. - -[iss20126]: https://github.com/rust-lang/rust/issues/20126 -"##, - -E0185: r##" -An associated function for a trait was defined to be static, but an -implementation of the trait declared the same function to be a method (i.e., to -take a `self` parameter). - -Here's an example of this error: - -```compile_fail,E0185 -trait Foo { - fn foo(); -} - -struct Bar; - -impl Foo for Bar { - // error, method `foo` has a `&self` declaration in the impl, but not in - // the trait - fn foo(&self) {} -} -``` -"##, - -E0186: r##" -An associated function for a trait was defined to be a method (i.e., to take a -`self` parameter), but an implementation of the trait declared the same function -to be static. - -Here's an example of this error: - -```compile_fail,E0186 -trait Foo { - fn foo(&self); -} - -struct Bar; - -impl Foo for Bar { - // error, method `foo` has a `&self` declaration in the trait, but not in - // the impl - fn foo() {} -} -``` -"##, - -E0191: r##" -Trait objects need to have all associated types specified. Erroneous code -example: - -```compile_fail,E0191 -trait Trait { - type Bar; -} - -type Foo = Trait; // error: the value of the associated type `Bar` (from - // the trait `Trait`) must be specified -``` - -Please verify you specified all associated types of the trait and that you -used the right trait. Example: - -``` -trait Trait { - type Bar; -} - -type Foo = Trait; // ok! -``` -"##, - -E0192: r##" -Negative impls are only allowed for auto traits. For more -information see the [opt-in builtin traits RFC][RFC 19]. - -[RFC 19]: https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md -"##, - -E0193: r##" -#### Note: this error code is no longer emitted by the compiler. - -`where` clauses must use generic type parameters: it does not make sense to use -them otherwise. An example causing this error: - -``` -trait Foo { - fn bar(&self); -} - -#[derive(Copy,Clone)] -struct Wrapper { - Wrapped: T -} - -impl Foo for Wrapper where Wrapper: Clone { - fn bar(&self) { } -} -``` - -This use of a `where` clause is strange - a more common usage would look -something like the following: - -``` -trait Foo { - fn bar(&self); -} - -#[derive(Copy,Clone)] -struct Wrapper { - Wrapped: T -} -impl Foo for Wrapper where Wrapper: Clone { - fn bar(&self) { } -} -``` - -Here, we're saying that the implementation exists on Wrapper only when the -wrapped type `T` implements `Clone`. The `where` clause is important because -some types will not implement `Clone`, and thus will not get this method. - -In our erroneous example, however, we're referencing a single concrete type. -Since we know for certain that `Wrapper` implements `Clone`, there's no -reason to also specify it in a `where` clause. -"##, - -E0194: r##" -A type parameter was declared which shadows an existing one. An example of this -error: - -```compile_fail,E0194 -trait Foo { - fn do_something(&self) -> T; - fn do_something_else(&self, bar: T); -} -``` - -In this example, the trait `Foo` and the trait method `do_something_else` both -define a type parameter `T`. This is not allowed: if the method wishes to -define a type parameter, it must use a different name for it. -"##, - -E0195: r##" -Your method's lifetime parameters do not match the trait declaration. -Erroneous code example: - -```compile_fail,E0195 -trait Trait { - fn bar<'a,'b:'a>(x: &'a str, y: &'b str); -} - -struct Foo; - -impl Trait for Foo { - fn bar<'a,'b>(x: &'a str, y: &'b str) { - // error: lifetime parameters or bounds on method `bar` - // do not match the trait declaration - } -} -``` - -The lifetime constraint `'b` for bar() implementation does not match the -trait declaration. Ensure lifetime declarations match exactly in both trait -declaration and implementation. Example: - -``` -trait Trait { - fn t<'a,'b:'a>(x: &'a str, y: &'b str); -} - -struct Foo; - -impl Trait for Foo { - fn t<'a,'b:'a>(x: &'a str, y: &'b str) { // ok! - } -} -``` -"##, - -E0199: r##" -Safe traits should not have unsafe implementations, therefore marking an -implementation for a safe trait unsafe will cause a compiler error. Removing -the unsafe marker on the trait noted in the error will resolve this problem. - -```compile_fail,E0199 -struct Foo; - -trait Bar { } - -// this won't compile because Bar is safe -unsafe impl Bar for Foo { } -// this will compile -impl Bar for Foo { } -``` -"##, - -E0200: r##" -Unsafe traits must have unsafe implementations. This error occurs when an -implementation for an unsafe trait isn't marked as unsafe. This may be resolved -by marking the unsafe implementation as unsafe. - -```compile_fail,E0200 -struct Foo; - -unsafe trait Bar { } - -// this won't compile because Bar is unsafe and impl isn't unsafe -impl Bar for Foo { } -// this will compile -unsafe impl Bar for Foo { } -``` -"##, - -E0201: r##" -It is an error to define two associated items (like methods, associated types, -associated functions, etc.) with the same identifier. - -For example: - -```compile_fail,E0201 -struct Foo(u8); - -impl Foo { - fn bar(&self) -> bool { self.0 > 5 } - fn bar() {} // error: duplicate associated function -} - -trait Baz { - type Quux; - fn baz(&self) -> bool; -} - -impl Baz for Foo { - type Quux = u32; - - fn baz(&self) -> bool { true } - - // error: duplicate method - fn baz(&self) -> bool { self.0 > 5 } - - // error: duplicate associated type - type Quux = u32; -} -``` - -Note, however, that items with the same name are allowed for inherent `impl` -blocks that don't overlap: - -``` -struct Foo(T); - -impl Foo { - fn bar(&self) -> bool { self.0 > 5 } -} - -impl Foo { - fn bar(&self) -> bool { self.0 } -} -``` -"##, - -E0202: r##" -Inherent associated types were part of [RFC 195] but are not yet implemented. -See [the tracking issue][iss8995] for the status of this implementation. - -[RFC 195]: https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md -[iss8995]: https://github.com/rust-lang/rust/issues/8995 -"##, - -E0204: r##" -An attempt to implement the `Copy` trait for a struct failed because one of the -fields does not implement `Copy`. To fix this, you must implement `Copy` for the -mentioned field. Note that this may not be possible, as in the example of - -```compile_fail,E0204 -struct Foo { - foo : Vec, -} - -impl Copy for Foo { } -``` - -This fails because `Vec` does not implement `Copy` for any `T`. - -Here's another example that will fail: - -```compile_fail,E0204 -#[derive(Copy)] -struct Foo<'a> { - ty: &'a mut bool, -} -``` - -This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this -differs from the behavior for `&T`, which is always `Copy`). -"##, - -/* -E0205: r##" -An attempt to implement the `Copy` trait for an enum failed because one of the -variants does not implement `Copy`. To fix this, you must implement `Copy` for -the mentioned variant. Note that this may not be possible, as in the example of - -```compile_fail,E0205 -enum Foo { - Bar(Vec), - Baz, -} - -impl Copy for Foo { } -``` - -This fails because `Vec` does not implement `Copy` for any `T`. - -Here's another example that will fail: - -```compile_fail,E0205 -#[derive(Copy)] -enum Foo<'a> { - Bar(&'a mut bool), - Baz, -} -``` - -This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this -differs from the behavior for `&T`, which is always `Copy`). -"##, -*/ - -E0206: r##" -You can only implement `Copy` for a struct or enum. Both of the following -examples will fail, because neither `[u8; 256]` nor `&'static mut Bar` -(mutable reference to `Bar`) is a struct or enum: - -```compile_fail,E0206 -type Foo = [u8; 256]; -impl Copy for Foo { } // error - -#[derive(Copy, Clone)] -struct Bar; -impl Copy for &'static mut Bar { } // error -``` -"##, - -E0207: r##" -Any type parameter or lifetime parameter of an `impl` must meet at least one of -the following criteria: - - - it appears in the self type of the impl - - for a trait impl, it appears in the trait reference - - it is bound as an associated type - -### Error example 1 - -Suppose we have a struct `Foo` and we would like to define some methods for it. -The following definition leads to a compiler error: - -```compile_fail,E0207 -struct Foo; - -impl Foo { -// error: the type parameter `T` is not constrained by the impl trait, self -// type, or predicates [E0207] - fn get(&self) -> T { - ::default() - } -} -``` - -The problem is that the parameter `T` does not appear in the self type (`Foo`) -of the impl. In this case, we can fix the error by moving the type parameter -from the `impl` to the method `get`: - - -``` -struct Foo; - -// Move the type parameter from the impl to the method -impl Foo { - fn get(&self) -> T { - ::default() - } -} -``` - -### Error example 2 - -As another example, suppose we have a `Maker` trait and want to establish a -type `FooMaker` that makes `Foo`s: - -```compile_fail,E0207 -trait Maker { - type Item; - fn make(&mut self) -> Self::Item; -} - -struct Foo { - foo: T -} - -struct FooMaker; - -impl Maker for FooMaker { -// error: the type parameter `T` is not constrained by the impl trait, self -// type, or predicates [E0207] - type Item = Foo; - - fn make(&mut self) -> Foo { - Foo { foo: ::default() } - } -} -``` - -This fails to compile because `T` does not appear in the trait or in the -implementing type. - -One way to work around this is to introduce a phantom type parameter into -`FooMaker`, like so: - -``` -use std::marker::PhantomData; - -trait Maker { - type Item; - fn make(&mut self) -> Self::Item; -} - -struct Foo { - foo: T -} - -// Add a type parameter to `FooMaker` -struct FooMaker { - phantom: PhantomData, -} - -impl Maker for FooMaker { - type Item = Foo; - - fn make(&mut self) -> Foo { - Foo { - foo: ::default(), - } - } -} -``` - -Another way is to do away with the associated type in `Maker` and use an input -type parameter instead: - -``` -// Use a type parameter instead of an associated type here -trait Maker { - fn make(&mut self) -> Item; -} - -struct Foo { - foo: T -} - -struct FooMaker; - -impl Maker> for FooMaker { - fn make(&mut self) -> Foo { - Foo { foo: ::default() } - } -} -``` - -### Additional information - -For more information, please see [RFC 447]. - -[RFC 447]: https://github.com/rust-lang/rfcs/blob/master/text/0447-no-unused-impl-parameters.md -"##, - -E0210: r##" -This error indicates a violation of one of Rust's orphan rules for trait -implementations. The rule concerns the use of type parameters in an -implementation of a foreign trait (a trait defined in another crate), and -states that type parameters must be "covered" by a local type. To understand -what this means, it is perhaps easiest to consider a few examples. - -If `ForeignTrait` is a trait defined in some external crate `foo`, then the -following trait `impl` is an error: - -```compile_fail,E0210 -# #[cfg(for_demonstration_only)] -extern crate foo; -# #[cfg(for_demonstration_only)] -use foo::ForeignTrait; -# use std::panic::UnwindSafe as ForeignTrait; - -impl ForeignTrait for T { } // error -# fn main() {} -``` - -To work around this, it can be covered with a local type, `MyType`: - -``` -# use std::panic::UnwindSafe as ForeignTrait; -struct MyType(T); -impl ForeignTrait for MyType { } // Ok -``` - -Please note that a type alias is not sufficient. - -For another example of an error, suppose there's another trait defined in `foo` -named `ForeignTrait2` that takes two type parameters. Then this `impl` results -in the same rule violation: - -```ignore (cannot-doctest-multicrate-project) -struct MyType2; -impl ForeignTrait2> for MyType2 { } // error -``` - -The reason for this is that there are two appearances of type parameter `T` in -the `impl` header, both as parameters for `ForeignTrait2`. The first appearance -is uncovered, and so runs afoul of the orphan rule. - -Consider one more example: - -```ignore (cannot-doctest-multicrate-project) -impl ForeignTrait2, T> for MyType2 { } // Ok -``` - -This only differs from the previous `impl` in that the parameters `T` and -`MyType` for `ForeignTrait2` have been swapped. This example does *not* -violate the orphan rule; it is permitted. - -To see why that last example was allowed, you need to understand the general -rule. Unfortunately this rule is a bit tricky to state. Consider an `impl`: - -```ignore (only-for-syntax-highlight) -impl ForeignTrait for T0 { ... } -``` - -where `P1, ..., Pm` are the type parameters of the `impl` and `T0, ..., Tn` -are types. One of the types `T0, ..., Tn` must be a local type (this is another -orphan rule, see the explanation for E0117). Let `i` be the smallest integer -such that `Ti` is a local type. Then no type parameter can appear in any of the -`Tj` for `j < i`. - -For information on the design of the orphan rules, see [RFC 1023]. - -[RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md -"##, - -/* -E0211: r##" -You used a function or type which doesn't fit the requirements for where it was -used. Erroneous code examples: - -```compile_fail -#![feature(intrinsics)] - -extern "rust-intrinsic" { - fn size_of(); // error: intrinsic has wrong type -} - -// or: - -fn main() -> i32 { 0 } -// error: main function expects type: `fn() {main}`: expected (), found i32 - -// or: - -let x = 1u8; -match x { - 0u8..=3i8 => (), - // error: mismatched types in range: expected u8, found i8 - _ => () -} - -// or: - -use std::rc::Rc; -struct Foo; - -impl Foo { - fn x(self: Rc) {} - // error: mismatched self type: expected `Foo`: expected struct - // `Foo`, found struct `alloc::rc::Rc` -} -``` - -For the first code example, please check the function definition. Example: - -``` -#![feature(intrinsics)] - -extern "rust-intrinsic" { - fn size_of() -> usize; // ok! -} -``` - -The second case example is a bit particular : the main function must always -have this definition: - -```compile_fail -fn main(); -``` - -They never take parameters and never return types. - -For the third example, when you match, all patterns must have the same type -as the type you're matching on. Example: - -``` -let x = 1u8; - -match x { - 0u8..=3u8 => (), // ok! - _ => () -} -``` - -And finally, for the last example, only `Box`, `&Self`, `Self`, -or `&mut Self` work as explicit self parameters. Example: - -``` -struct Foo; - -impl Foo { - fn x(self: Box) {} // ok! -} -``` -"##, - */ - -E0220: r##" -You used an associated type which isn't defined in the trait. -Erroneous code example: - -```compile_fail,E0220 -trait T1 { - type Bar; -} - -type Foo = T1; // error: associated type `F` not found for `T1` - -// or: - -trait T2 { - type Bar; - - // error: Baz is used but not declared - fn return_bool(&self, _: &Self::Bar, _: &Self::Baz) -> bool; -} -``` - -Make sure that you have defined the associated type in the trait body. -Also, verify that you used the right trait or you didn't misspell the -associated type name. Example: - -``` -trait T1 { - type Bar; -} - -type Foo = T1; // ok! - -// or: - -trait T2 { - type Bar; - type Baz; // we declare `Baz` in our trait. - - // and now we can use it here: - fn return_bool(&self, _: &Self::Bar, _: &Self::Baz) -> bool; -} -``` -"##, - -E0221: r##" -An attempt was made to retrieve an associated type, but the type was ambiguous. -For example: - -```compile_fail,E0221 -trait T1 {} -trait T2 {} - -trait Foo { - type A: T1; -} - -trait Bar : Foo { - type A: T2; - fn do_something() { - let _: Self::A; - } -} -``` - -In this example, `Foo` defines an associated type `A`. `Bar` inherits that type -from `Foo`, and defines another associated type of the same name. As a result, -when we attempt to use `Self::A`, it's ambiguous whether we mean the `A` defined -by `Foo` or the one defined by `Bar`. - -There are two options to work around this issue. The first is simply to rename -one of the types. Alternatively, one can specify the intended type using the -following syntax: - -``` -trait T1 {} -trait T2 {} - -trait Foo { - type A: T1; -} - -trait Bar : Foo { - type A: T2; - fn do_something() { - let _: ::A; - } -} -``` -"##, - -E0223: r##" -An attempt was made to retrieve an associated type, but the type was ambiguous. -For example: - -```compile_fail,E0223 -trait MyTrait {type X; } - -fn main() { - let foo: MyTrait::X; -} -``` - -The problem here is that we're attempting to take the type of X from MyTrait. -Unfortunately, the type of X is not defined, because it's only made concrete in -implementations of the trait. A working version of this code might look like: - -``` -trait MyTrait {type X; } -struct MyStruct; - -impl MyTrait for MyStruct { - type X = u32; -} - -fn main() { - let foo: ::X; -} -``` - -This syntax specifies that we want the X type from MyTrait, as made concrete in -MyStruct. The reason that we cannot simply use `MyStruct::X` is that MyStruct -might implement two different traits with identically-named associated types. -This syntax allows disambiguation between the two. -"##, - -E0225: r##" -You attempted to use multiple types as bounds for a closure or trait object. -Rust does not currently support this. A simple example that causes this error: - -```compile_fail,E0225 -fn main() { - let _: Box; -} -``` - -Auto traits such as Send and Sync are an exception to this rule: -It's possible to have bounds of one non-builtin trait, plus any number of -auto traits. For example, the following compiles correctly: - -``` -fn main() { - let _: Box; -} -``` -"##, - -E0229: r##" -An associated type binding was done outside of the type parameter declaration -and `where` clause. Erroneous code example: - -```compile_fail,E0229 -pub trait Foo { - type A; - fn boo(&self) -> ::A; -} - -struct Bar; - -impl Foo for isize { - type A = usize; - fn boo(&self) -> usize { 42 } -} - -fn baz(x: &>::A) {} -// error: associated type bindings are not allowed here -``` - -To solve this error, please move the type bindings in the type parameter -declaration: - -``` -# struct Bar; -# trait Foo { type A; } -fn baz>(x: &::A) {} // ok! -``` - -Or in the `where` clause: - -``` -# struct Bar; -# trait Foo { type A; } -fn baz(x: &::A) where I: Foo {} -``` -"##, - -E0243: r##" -#### Note: this error code is no longer emitted by the compiler. - -This error indicates that not enough type parameters were found in a type or -trait. - -For example, the `Foo` struct below is defined to be generic in `T`, but the -type parameter is missing in the definition of `Bar`: - -```compile_fail,E0107 -struct Foo { x: T } - -struct Bar { x: Foo } -``` -"##, - -E0244: r##" -#### Note: this error code is no longer emitted by the compiler. - -This error indicates that too many type parameters were found in a type or -trait. - -For example, the `Foo` struct below has no type parameters, but is supplied -with two in the definition of `Bar`: - -```compile_fail,E0107 -struct Foo { x: bool } - -struct Bar { x: Foo } -``` -"##, - -E0321: r##" -A cross-crate opt-out trait was implemented on something which wasn't a struct -or enum type. Erroneous code example: - -```compile_fail,E0321 -#![feature(optin_builtin_traits)] - -struct Foo; - -impl !Sync for Foo {} - -unsafe impl Send for &'static Foo {} -// error: cross-crate traits with a default impl, like `core::marker::Send`, -// can only be implemented for a struct/enum type, not -// `&'static Foo` -``` - -Only structs and enums are permitted to impl Send, Sync, and other opt-out -trait, and the struct or enum must be local to the current crate. So, for -example, `unsafe impl Send for Rc` is not allowed. -"##, - -E0322: r##" -The `Sized` trait is a special trait built-in to the compiler for types with a -constant size known at compile-time. This trait is automatically implemented -for types as needed by the compiler, and it is currently disallowed to -explicitly implement it for a type. -"##, - -E0323: r##" -An associated const was implemented when another trait item was expected. -Erroneous code example: - -```compile_fail,E0323 -trait Foo { - type N; -} - -struct Bar; - -impl Foo for Bar { - const N : u32 = 0; - // error: item `N` is an associated const, which doesn't match its - // trait `` -} -``` - -Please verify that the associated const wasn't misspelled and the correct trait -was implemented. Example: - -``` -struct Bar; - -trait Foo { - type N; -} - -impl Foo for Bar { - type N = u32; // ok! -} -``` - -Or: - -``` -struct Bar; - -trait Foo { - const N : u32; -} - -impl Foo for Bar { - const N : u32 = 0; // ok! -} -``` -"##, - -E0324: r##" -A method was implemented when another trait item was expected. Erroneous -code example: - -```compile_fail,E0324 -struct Bar; - -trait Foo { - const N : u32; - - fn M(); -} - -impl Foo for Bar { - fn N() {} - // error: item `N` is an associated method, which doesn't match its - // trait `` -} -``` - -To fix this error, please verify that the method name wasn't misspelled and -verify that you are indeed implementing the correct trait items. Example: - -``` -struct Bar; - -trait Foo { - const N : u32; - - fn M(); -} - -impl Foo for Bar { - const N : u32 = 0; - - fn M() {} // ok! -} -``` -"##, - -E0325: r##" -An associated type was implemented when another trait item was expected. -Erroneous code example: - -```compile_fail,E0325 -struct Bar; - -trait Foo { - const N : u32; -} - -impl Foo for Bar { - type N = u32; - // error: item `N` is an associated type, which doesn't match its - // trait `` -} -``` - -Please verify that the associated type name wasn't misspelled and your -implementation corresponds to the trait definition. Example: - -``` -struct Bar; - -trait Foo { - type N; -} - -impl Foo for Bar { - type N = u32; // ok! -} -``` - -Or: - -``` -struct Bar; - -trait Foo { - const N : u32; -} - -impl Foo for Bar { - const N : u32 = 0; // ok! -} -``` -"##, - -E0326: r##" -The types of any associated constants in a trait implementation must match the -types in the trait definition. This error indicates that there was a mismatch. - -Here's an example of this error: - -```compile_fail,E0326 -trait Foo { - const BAR: bool; -} - -struct Bar; - -impl Foo for Bar { - const BAR: u32 = 5; // error, expected bool, found u32 -} -``` -"##, - -E0328: r##" -The Unsize trait should not be implemented directly. All implementations of -Unsize are provided automatically by the compiler. - -Erroneous code example: - -```compile_fail,E0328 -#![feature(unsize)] - -use std::marker::Unsize; - -pub struct MyType; - -impl Unsize for MyType {} -``` - -If you are defining your own smart pointer type and would like to enable -conversion from a sized to an unsized type with the -[DST coercion system][RFC 982], use [`CoerceUnsized`] instead. - -``` -#![feature(coerce_unsized)] - -use std::ops::CoerceUnsized; - -pub struct MyType { - field_with_unsized_type: T, -} - -impl CoerceUnsized> for MyType - where T: CoerceUnsized {} -``` - -[RFC 982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md -[`CoerceUnsized`]: https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html -"##, - -/* -// Associated consts can now be accessed through generic type parameters, and -// this error is no longer emitted. -// -// FIXME: consider whether to leave it in the error index, or remove it entirely -// as associated consts is not stabilized yet. - -E0329: r##" -An attempt was made to access an associated constant through either a generic -type parameter or `Self`. This is not supported yet. An example causing this -error is shown below: - -``` -trait Foo { - const BAR: f64; -} - -struct MyStruct; - -impl Foo for MyStruct { - const BAR: f64 = 0f64; -} - -fn get_bar_bad(t: F) -> f64 { - F::BAR -} -``` - -Currently, the value of `BAR` for a particular type can only be accessed -through a concrete type, as shown below: - -``` -trait Foo { - const BAR: f64; -} - -struct MyStruct; - -fn get_bar_good() -> f64 { - ::BAR -} -``` -"##, -*/ - -E0366: r##" -An attempt was made to implement `Drop` on a concrete specialization of a -generic type. An example is shown below: - -```compile_fail,E0366 -struct Foo { - t: T -} - -impl Drop for Foo { - fn drop(&mut self) {} -} -``` - -This code is not legal: it is not possible to specialize `Drop` to a subset of -implementations of a generic type. One workaround for this is to wrap the -generic type, as shown below: - -``` -struct Foo { - t: T -} - -struct Bar { - t: Foo -} - -impl Drop for Bar { - fn drop(&mut self) {} -} -``` -"##, - -E0367: r##" -An attempt was made to implement `Drop` on a specialization of a generic type. -An example is shown below: - -```compile_fail,E0367 -trait Foo{} - -struct MyStruct { - t: T -} - -impl Drop for MyStruct { - fn drop(&mut self) {} -} -``` - -This code is not legal: it is not possible to specialize `Drop` to a subset of -implementations of a generic type. In order for this code to work, `MyStruct` -must also require that `T` implements `Foo`. Alternatively, another option is -to wrap the generic type in another that specializes appropriately: - -``` -trait Foo{} - -struct MyStruct { - t: T -} - -struct MyStructWrapper { - t: MyStruct -} - -impl Drop for MyStructWrapper { - fn drop(&mut self) {} -} -``` -"##, - -E0368: r##" -This error indicates that a binary assignment operator like `+=` or `^=` was -applied to a type that doesn't support it. For example: - -```compile_fail,E0368 -let mut x = 12f32; // error: binary operation `<<` cannot be applied to - // type `f32` - -x <<= 2; -``` - -To fix this error, please check that this type implements this binary -operation. Example: - -``` -let mut x = 12u32; // the `u32` type does implement the `ShlAssign` trait - -x <<= 2; // ok! -``` - -It is also possible to overload most operators for your own type by -implementing the `[OP]Assign` traits from `std::ops`. - -Another problem you might be facing is this: suppose you've overloaded the `+` -operator for some type `Foo` by implementing the `std::ops::Add` trait for -`Foo`, but you find that using `+=` does not work, as in this example: - -```compile_fail,E0368 -use std::ops::Add; - -struct Foo(u32); - -impl Add for Foo { - type Output = Foo; - - fn add(self, rhs: Foo) -> Foo { - Foo(self.0 + rhs.0) - } -} - -fn main() { - let mut x: Foo = Foo(5); - x += Foo(7); // error, `+= cannot be applied to the type `Foo` -} -``` - -This is because `AddAssign` is not automatically implemented, so you need to -manually implement it for your type. -"##, - -E0369: r##" -A binary operation was attempted on a type which doesn't support it. -Erroneous code example: - -```compile_fail,E0369 -let x = 12f32; // error: binary operation `<<` cannot be applied to - // type `f32` - -x << 2; -``` - -To fix this error, please check that this type implements this binary -operation. Example: - -``` -let x = 12u32; // the `u32` type does implement it: - // https://doc.rust-lang.org/stable/std/ops/trait.Shl.html - -x << 2; // ok! -``` - -It is also possible to overload most operators for your own type by -implementing traits from `std::ops`. - -String concatenation appends the string on the right to the string on the -left and may require reallocation. This requires ownership of the string -on the left. If something should be added to a string literal, move the -literal to the heap by allocating it with `to_owned()` like in -`"Your text".to_owned()`. - -"##, - -E0370: r##" -The maximum value of an enum was reached, so it cannot be automatically -set in the next enum value. Erroneous code example: - -```compile_fail,E0370 -#[repr(i64)] -enum Foo { - X = 0x7fffffffffffffff, - Y, // error: enum discriminant overflowed on value after - // 9223372036854775807: i64; set explicitly via - // Y = -9223372036854775808 if that is desired outcome -} -``` - -To fix this, please set manually the next enum value or put the enum variant -with the maximum value at the end of the enum. Examples: - -``` -#[repr(i64)] -enum Foo { - X = 0x7fffffffffffffff, - Y = 0, // ok! -} -``` - -Or: - -``` -#[repr(i64)] -enum Foo { - Y = 0, // ok! - X = 0x7fffffffffffffff, -} -``` -"##, - -E0371: r##" -When `Trait2` is a subtrait of `Trait1` (for example, when `Trait2` has a -definition like `trait Trait2: Trait1 { ... }`), it is not allowed to implement -`Trait1` for `Trait2`. This is because `Trait2` already implements `Trait1` by -definition, so it is not useful to do this. - -Example: - -```compile_fail,E0371 -trait Foo { fn foo(&self) { } } -trait Bar: Foo { } -trait Baz: Bar { } - -impl Bar for Baz { } // error, `Baz` implements `Bar` by definition -impl Foo for Baz { } // error, `Baz` implements `Bar` which implements `Foo` -impl Baz for Baz { } // error, `Baz` (trivially) implements `Baz` -impl Baz for Bar { } // Note: This is OK -``` -"##, - -E0374: r##" -A struct without a field containing an unsized type cannot implement -`CoerceUnsized`. An [unsized type][1] is any type that the compiler -doesn't know the length or alignment of at compile time. Any struct -containing an unsized type is also unsized. - -[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait - -Example of erroneous code: - -```compile_fail,E0374 -#![feature(coerce_unsized)] -use std::ops::CoerceUnsized; - -struct Foo { - a: i32, -} - -// error: Struct `Foo` has no unsized fields that need `CoerceUnsized`. -impl CoerceUnsized> for Foo - where T: CoerceUnsized {} -``` - -`CoerceUnsized` is used to coerce one struct containing an unsized type -into another struct containing a different unsized type. If the struct -doesn't have any fields of unsized types then you don't need explicit -coercion to get the types you want. To fix this you can either -not try to implement `CoerceUnsized` or you can add a field that is -unsized to the struct. - -Example: - -``` -#![feature(coerce_unsized)] -use std::ops::CoerceUnsized; - -// We don't need to impl `CoerceUnsized` here. -struct Foo { - a: i32, -} - -// We add the unsized type field to the struct. -struct Bar { - a: i32, - b: T, -} - -// The struct has an unsized field so we can implement -// `CoerceUnsized` for it. -impl CoerceUnsized> for Bar - where T: CoerceUnsized {} -``` - -Note that `CoerceUnsized` is mainly used by smart pointers like `Box`, `Rc` -and `Arc` to be able to mark that they can coerce unsized types that they -are pointing at. -"##, - -E0375: r##" -A struct with more than one field containing an unsized type cannot implement -`CoerceUnsized`. This only occurs when you are trying to coerce one of the -types in your struct to another type in the struct. In this case we try to -impl `CoerceUnsized` from `T` to `U` which are both types that the struct -takes. An [unsized type][1] is any type that the compiler doesn't know the -length or alignment of at compile time. Any struct containing an unsized type -is also unsized. - -Example of erroneous code: - -```compile_fail,E0375 -#![feature(coerce_unsized)] -use std::ops::CoerceUnsized; - -struct Foo { - a: i32, - b: T, - c: U, -} - -// error: Struct `Foo` has more than one unsized field. -impl CoerceUnsized> for Foo {} -``` - -`CoerceUnsized` only allows for coercion from a structure with a single -unsized type field to another struct with a single unsized type field. -In fact Rust only allows for a struct to have one unsized type in a struct -and that unsized type must be the last field in the struct. So having two -unsized types in a single struct is not allowed by the compiler. To fix this -use only one field containing an unsized type in the struct and then use -multiple structs to manage each unsized type field you need. - -Example: - -``` -#![feature(coerce_unsized)] -use std::ops::CoerceUnsized; - -struct Foo { - a: i32, - b: T, -} - -impl CoerceUnsized> for Foo - where T: CoerceUnsized {} - -fn coerce_foo, U>(t: T) -> Foo { - Foo { a: 12i32, b: t } // we use coercion to get the `Foo` type we need -} -``` - -[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait -"##, - -E0376: r##" -The type you are trying to impl `CoerceUnsized` for is not a struct. -`CoerceUnsized` can only be implemented for a struct. Unsized types are -already able to be coerced without an implementation of `CoerceUnsized` -whereas a struct containing an unsized type needs to know the unsized type -field it's containing is able to be coerced. An [unsized type][1] -is any type that the compiler doesn't know the length or alignment of at -compile time. Any struct containing an unsized type is also unsized. - -[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait - -Example of erroneous code: - -```compile_fail,E0376 -#![feature(coerce_unsized)] -use std::ops::CoerceUnsized; - -struct Foo { - a: T, -} - -// error: The type `U` is not a struct -impl CoerceUnsized for Foo {} -``` - -The `CoerceUnsized` trait takes a struct type. Make sure the type you are -providing to `CoerceUnsized` is a struct with only the last field containing an -unsized type. - -Example: - -``` -#![feature(coerce_unsized)] -use std::ops::CoerceUnsized; - -struct Foo { - a: T, -} - -// The `Foo` is a struct so `CoerceUnsized` can be implemented -impl CoerceUnsized> for Foo where T: CoerceUnsized {} -``` - -Note that in Rust, structs can only contain an unsized type if the field -containing the unsized type is the last and only unsized type field in the -struct. -"##, - -E0378: r##" -The `DispatchFromDyn` trait currently can only be implemented for -builtin pointer types and structs that are newtype wrappers around them -— that is, the struct must have only one field (except for`PhantomData`), -and that field must itself implement `DispatchFromDyn`. - -Examples: - -``` -#![feature(dispatch_from_dyn, unsize)] -use std::{ - marker::Unsize, - ops::DispatchFromDyn, -}; - -struct Ptr(*const T); - -impl DispatchFromDyn> for Ptr -where - T: Unsize, -{} -``` - -``` -#![feature(dispatch_from_dyn)] -use std::{ - ops::DispatchFromDyn, - marker::PhantomData, -}; - -struct Wrapper { - ptr: T, - _phantom: PhantomData<()>, -} - -impl DispatchFromDyn> for Wrapper -where - T: DispatchFromDyn, -{} -``` - -Example of illegal `DispatchFromDyn` implementation -(illegal because of extra field) - -```compile-fail,E0378 -#![feature(dispatch_from_dyn)] -use std::ops::DispatchFromDyn; - -struct WrapperExtraField { - ptr: T, - extra_stuff: i32, -} - -impl DispatchFromDyn> for WrapperExtraField -where - T: DispatchFromDyn, -{} -``` -"##, - -E0390: r##" -You tried to implement methods for a primitive type. Erroneous code example: - -```compile_fail,E0390 -struct Foo { - x: i32 -} - -impl *mut Foo {} -// error: only a single inherent implementation marked with -// `#[lang = "mut_ptr"]` is allowed for the `*mut T` primitive -``` - -This isn't allowed, but using a trait to implement a method is a good solution. -Example: - -``` -struct Foo { - x: i32 -} - -trait Bar { - fn bar(); -} - -impl Bar for *mut Foo { - fn bar() {} // ok! -} -``` -"##, - -E0392: r##" -This error indicates that a type or lifetime parameter has been declared -but not actually used. Here is an example that demonstrates the error: - -```compile_fail,E0392 -enum Foo { - Bar, -} -``` - -If the type parameter was included by mistake, this error can be fixed -by simply removing the type parameter, as shown below: - -``` -enum Foo { - Bar, -} -``` - -Alternatively, if the type parameter was intentionally inserted, it must be -used. A simple fix is shown below: - -``` -enum Foo { - Bar(T), -} -``` - -This error may also commonly be found when working with unsafe code. For -example, when using raw pointers one may wish to specify the lifetime for -which the pointed-at data is valid. An initial attempt (below) causes this -error: - -```compile_fail,E0392 -struct Foo<'a, T> { - x: *const T, -} -``` - -We want to express the constraint that Foo should not outlive `'a`, because -the data pointed to by `T` is only valid for that lifetime. The problem is -that there are no actual uses of `'a`. It's possible to work around this -by adding a PhantomData type to the struct, using it to tell the compiler -to act as if the struct contained a borrowed reference `&'a T`: - -``` -use std::marker::PhantomData; - -struct Foo<'a, T: 'a> { - x: *const T, - phantom: PhantomData<&'a T> -} -``` - -[PhantomData] can also be used to express information about unused type -parameters. - -[PhantomData]: https://doc.rust-lang.org/std/marker/struct.PhantomData.html -"##, - -E0393: r##" -A type parameter which references `Self` in its default value was not specified. -Example of erroneous code: - -```compile_fail,E0393 -trait A {} - -fn together_we_will_rule_the_galaxy(son: &A) {} -// error: the type parameter `T` must be explicitly specified in an -// object type because its default value `Self` references the -// type `Self` -``` - -A trait object is defined over a single, fully-defined trait. With a regular -default parameter, this parameter can just be substituted in. However, if the -default parameter is `Self`, the trait changes for each concrete type; i.e. -`i32` will be expected to implement `A`, `bool` will be expected to -implement `A`, etc... These types will not share an implementation of a -fully-defined trait; instead they share implementations of a trait with -different parameters substituted in for each implementation. This is -irreconcilable with what we need to make a trait object work, and is thus -disallowed. Making the trait concrete by explicitly specifying the value of the -defaulted parameter will fix this issue. Fixed example: - -``` -trait A {} - -fn together_we_will_rule_the_galaxy(son: &A) {} // Ok! -``` -"##, - -E0399: r##" -You implemented a trait, overriding one or more of its associated types but did -not reimplement its default methods. - -Example of erroneous code: - -```compile_fail,E0399 -#![feature(associated_type_defaults)] - -pub trait Foo { - type Assoc = u8; - fn bar(&self) {} -} - -impl Foo for i32 { - // error - the following trait items need to be reimplemented as - // `Assoc` was overridden: `bar` - type Assoc = i32; -} -``` - -To fix this, add an implementation for each default method from the trait: - -``` -#![feature(associated_type_defaults)] - -pub trait Foo { - type Assoc = u8; - fn bar(&self) {} -} - -impl Foo for i32 { - type Assoc = i32; - fn bar(&self) {} // ok! -} -``` -"##, - -E0436: r##" -The functional record update syntax is only allowed for structs. (Struct-like -enum variants don't qualify, for example.) - -Erroneous code example: - -```compile_fail,E0436 -enum PublicationFrequency { - Weekly, - SemiMonthly { days: (u8, u8), annual_special: bool }, -} - -fn one_up_competitor(competitor_frequency: PublicationFrequency) - -> PublicationFrequency { - match competitor_frequency { - PublicationFrequency::Weekly => PublicationFrequency::SemiMonthly { - days: (1, 15), annual_special: false - }, - c @ PublicationFrequency::SemiMonthly{ .. } => - PublicationFrequency::SemiMonthly { - annual_special: true, ..c // error: functional record update - // syntax requires a struct - } - } -} -``` - -Rewrite the expression without functional record update syntax: - -``` -enum PublicationFrequency { - Weekly, - SemiMonthly { days: (u8, u8), annual_special: bool }, -} - -fn one_up_competitor(competitor_frequency: PublicationFrequency) - -> PublicationFrequency { - match competitor_frequency { - PublicationFrequency::Weekly => PublicationFrequency::SemiMonthly { - days: (1, 15), annual_special: false - }, - PublicationFrequency::SemiMonthly{ days, .. } => - PublicationFrequency::SemiMonthly { - days, annual_special: true // ok! - } - } -} -``` -"##, - -E0439: r##" -The length of the platform-intrinsic function `simd_shuffle` -wasn't specified. Erroneous code example: - -```compile_fail,E0439 -#![feature(platform_intrinsics)] - -extern "platform-intrinsic" { - fn simd_shuffle(a: A, b: A, c: [u32; 8]) -> B; - // error: invalid `simd_shuffle`, needs length: `simd_shuffle` -} -``` - -The `simd_shuffle` function needs the length of the array passed as -last parameter in its name. Example: - -``` -#![feature(platform_intrinsics)] - -extern "platform-intrinsic" { - fn simd_shuffle8(a: A, b: A, c: [u32; 8]) -> B; -} -``` -"##, - -E0516: r##" -The `typeof` keyword is currently reserved but unimplemented. -Erroneous code example: - -```compile_fail,E0516 -fn main() { - let x: typeof(92) = 92; -} -``` - -Try using type inference instead. Example: - -``` -fn main() { - let x = 92; -} -``` -"##, - -E0520: r##" -A non-default implementation was already made on this type so it cannot be -specialized further. Erroneous code example: - -```compile_fail,E0520 -#![feature(specialization)] - -trait SpaceLlama { - fn fly(&self); -} - -// applies to all T -impl SpaceLlama for T { - default fn fly(&self) {} -} - -// non-default impl -// applies to all `Clone` T and overrides the previous impl -impl SpaceLlama for T { - fn fly(&self) {} -} - -// since `i32` is clone, this conflicts with the previous implementation -impl SpaceLlama for i32 { - default fn fly(&self) {} - // error: item `fly` is provided by an `impl` that specializes - // another, but the item in the parent `impl` is not marked - // `default` and so it cannot be specialized. -} -``` - -Specialization only allows you to override `default` functions in -implementations. - -To fix this error, you need to mark all the parent implementations as default. -Example: - -``` -#![feature(specialization)] - -trait SpaceLlama { - fn fly(&self); -} - -// applies to all T -impl SpaceLlama for T { - default fn fly(&self) {} // This is a parent implementation. -} - -// applies to all `Clone` T; overrides the previous impl -impl SpaceLlama for T { - default fn fly(&self) {} // This is a parent implementation but was - // previously not a default one, causing the error -} - -// applies to i32, overrides the previous two impls -impl SpaceLlama for i32 { - fn fly(&self) {} // And now that's ok! -} -``` -"##, - -E0527: r##" -The number of elements in an array or slice pattern differed from the number of -elements in the array being matched. - -Example of erroneous code: - -```compile_fail,E0527 -let r = &[1, 2, 3, 4]; -match r { - &[a, b] => { // error: pattern requires 2 elements but array - // has 4 - println!("a={}, b={}", a, b); - } -} -``` - -Ensure that the pattern is consistent with the size of the matched -array. Additional elements can be matched with `..`: - -``` -#![feature(slice_patterns)] - -let r = &[1, 2, 3, 4]; -match r { - &[a, b, ..] => { // ok! - println!("a={}, b={}", a, b); - } -} -``` -"##, - -E0528: r##" -An array or slice pattern required more elements than were present in the -matched array. - -Example of erroneous code: - -```compile_fail,E0528 -#![feature(slice_patterns)] - -let r = &[1, 2]; -match r { - &[a, b, c, rest..] => { // error: pattern requires at least 3 - // elements but array has 2 - println!("a={}, b={}, c={} rest={:?}", a, b, c, rest); - } -} -``` - -Ensure that the matched array has at least as many elements as the pattern -requires. You can match an arbitrary number of remaining elements with `..`: - -``` -#![feature(slice_patterns)] - -let r = &[1, 2, 3, 4, 5]; -match r { - &[a, b, c, rest..] => { // ok! - // prints `a=1, b=2, c=3 rest=[4, 5]` - println!("a={}, b={}, c={} rest={:?}", a, b, c, rest); - } -} -``` -"##, - -E0529: r##" -An array or slice pattern was matched against some other type. - -Example of erroneous code: - -```compile_fail,E0529 -let r: f32 = 1.0; -match r { - [a, b] => { // error: expected an array or slice, found `f32` - println!("a={}, b={}", a, b); - } -} -``` - -Ensure that the pattern and the expression being matched on are of consistent -types: - -``` -let r = [1.0, 2.0]; -match r { - [a, b] => { // ok! - println!("a={}, b={}", a, b); - } -} -``` -"##, - -E0534: r##" -The `inline` attribute was malformed. - -Erroneous code example: - -```ignore (compile_fail not working here; see Issue #43707) -#[inline()] // error: expected one argument -pub fn something() {} - -fn main() {} -``` - -The parenthesized `inline` attribute requires the parameter to be specified: - -``` -#[inline(always)] -fn something() {} -``` - -or: - -``` -#[inline(never)] -fn something() {} -``` - -Alternatively, a paren-less version of the attribute may be used to hint the -compiler about inlining opportunity: - -``` -#[inline] -fn something() {} -``` - -For more information about the inline attribute, read: -https://doc.rust-lang.org/reference.html#inline-attributes -"##, - -E0535: r##" -An unknown argument was given to the `inline` attribute. - -Erroneous code example: - -```ignore (compile_fail not working here; see Issue #43707) -#[inline(unknown)] // error: invalid argument -pub fn something() {} - -fn main() {} -``` - -The `inline` attribute only supports two arguments: - - * always - * never - -All other arguments given to the `inline` attribute will return this error. -Example: - -``` -#[inline(never)] // ok! -pub fn something() {} - -fn main() {} -``` - -For more information about the inline attribute, https: -read://doc.rust-lang.org/reference.html#inline-attributes -"##, - -E0559: r##" -An unknown field was specified into an enum's structure variant. - -Erroneous code example: - -```compile_fail,E0559 -enum Field { - Fool { x: u32 }, -} - -let s = Field::Fool { joke: 0 }; -// error: struct variant `Field::Fool` has no field named `joke` -``` - -Verify you didn't misspell the field's name or that the field exists. Example: - -``` -enum Field { - Fool { joke: u32 }, -} - -let s = Field::Fool { joke: 0 }; // ok! -``` -"##, - -E0560: r##" -An unknown field was specified into a structure. - -Erroneous code example: - -```compile_fail,E0560 -struct Simba { - mother: u32, -} - -let s = Simba { mother: 1, father: 0 }; -// error: structure `Simba` has no field named `father` -``` - -Verify you didn't misspell the field's name or that the field exists. Example: - -``` -struct Simba { - mother: u32, - father: u32, -} - -let s = Simba { mother: 1, father: 0 }; // ok! -``` -"##, - -E0569: r##" -If an impl has a generic parameter with the `#[may_dangle]` attribute, then -that impl must be declared as an `unsafe impl. - -Erroneous code example: - -```compile_fail,E0569 -#![feature(dropck_eyepatch)] - -struct Foo(X); -impl<#[may_dangle] X> Drop for Foo { - fn drop(&mut self) { } -} -``` - -In this example, we are asserting that the destructor for `Foo` will not -access any data of type `X`, and require this assertion to be true for -overall safety in our program. The compiler does not currently attempt to -verify this assertion; therefore we must tag this `impl` as unsafe. -"##, - -E0570: r##" -The requested ABI is unsupported by the current target. - -The rust compiler maintains for each target a blacklist of ABIs unsupported on -that target. If an ABI is present in such a list this usually means that the -target / ABI combination is currently unsupported by llvm. - -If necessary, you can circumvent this check using custom target specifications. -"##, - -E0572: r##" -A return statement was found outside of a function body. - -Erroneous code example: - -```compile_fail,E0572 -const FOO: u32 = return 0; // error: return statement outside of function body - -fn main() {} -``` - -To fix this issue, just remove the return keyword or move the expression into a -function. Example: - -``` -const FOO: u32 = 0; - -fn some_fn() -> u32 { - return FOO; -} - -fn main() { - some_fn(); -} -``` -"##, - -E0581: r##" -In a `fn` type, a lifetime appears only in the return type, -and not in the arguments types. - -Erroneous code example: - -```compile_fail,E0581 -fn main() { - // Here, `'a` appears only in the return type: - let x: for<'a> fn() -> &'a i32; -} -``` - -To fix this issue, either use the lifetime in the arguments, or use -`'static`. Example: - -``` -fn main() { - // Here, `'a` appears only in the return type: - let x: for<'a> fn(&'a i32) -> &'a i32; - let y: fn() -> &'static i32; -} -``` - -Note: The examples above used to be (erroneously) accepted by the -compiler, but this was since corrected. See [issue #33685] for more -details. - -[issue #33685]: https://github.com/rust-lang/rust/issues/33685 -"##, - -E0582: r##" -A lifetime appears only in an associated-type binding, -and not in the input types to the trait. - -Erroneous code example: - -```compile_fail,E0582 -fn bar(t: F) - // No type can satisfy this requirement, since `'a` does not - // appear in any of the input types (here, `i32`): - where F: for<'a> Fn(i32) -> Option<&'a i32> -{ -} - -fn main() { } -``` - -To fix this issue, either use the lifetime in the inputs, or use -`'static`. Example: - -``` -fn bar(t: F, u: G) - where F: for<'a> Fn(&'a i32) -> Option<&'a i32>, - G: Fn(i32) -> Option<&'static i32>, -{ -} - -fn main() { } -``` - -Note: The examples above used to be (erroneously) accepted by the -compiler, but this was since corrected. See [issue #33685] for more -details. - -[issue #33685]: https://github.com/rust-lang/rust/issues/33685 -"##, - -E0599: r##" -This error occurs when a method is used on a type which doesn't implement it: - -Erroneous code example: - -```compile_fail,E0599 -struct Mouth; - -let x = Mouth; -x.chocolate(); // error: no method named `chocolate` found for type `Mouth` - // in the current scope -``` -"##, - -E0600: r##" -An unary operator was used on a type which doesn't implement it. - -Example of erroneous code: - -```compile_fail,E0600 -enum Question { - Yes, - No, -} - -!Question::Yes; // error: cannot apply unary operator `!` to type `Question` -``` - -In this case, `Question` would need to implement the `std::ops::Not` trait in -order to be able to use `!` on it. Let's implement it: - -``` -use std::ops::Not; - -enum Question { - Yes, - No, -} - -// We implement the `Not` trait on the enum. -impl Not for Question { - type Output = bool; - - fn not(self) -> bool { - match self { - Question::Yes => false, // If the `Answer` is `Yes`, then it - // returns false. - Question::No => true, // And here we do the opposite. - } - } -} - -assert_eq!(!Question::Yes, false); -assert_eq!(!Question::No, true); -``` -"##, - -E0608: r##" -An attempt to index into a type which doesn't implement the `std::ops::Index` -trait was performed. - -Erroneous code example: - -```compile_fail,E0608 -0u8[2]; // error: cannot index into a value of type `u8` -``` - -To be able to index into a type it needs to implement the `std::ops::Index` -trait. Example: - -``` -let v: Vec = vec![0, 1, 2, 3]; - -// The `Vec` type implements the `Index` trait so you can do: -println!("{}", v[2]); -``` -"##, - -E0604: r##" -A cast to `char` was attempted on a type other than `u8`. - -Erroneous code example: - -```compile_fail,E0604 -0u32 as char; // error: only `u8` can be cast as `char`, not `u32` -``` - -As the error message indicates, only `u8` can be cast into `char`. Example: - -``` -let c = 86u8 as char; // ok! -assert_eq!(c, 'V'); -``` - -For more information about casts, take a look at the Type cast section in -[The Reference Book][1]. - -[1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions -"##, - -E0605: r##" -An invalid cast was attempted. - -Erroneous code examples: - -```compile_fail,E0605 -let x = 0u8; -x as Vec; // error: non-primitive cast: `u8` as `std::vec::Vec` - -// Another example - -let v = 0 as *const u8; // So here, `v` is a `*const u8`. -v as &u8; // error: non-primitive cast: `*const u8` as `&u8` -``` - -Only primitive types can be cast into each other. Examples: - -``` -let x = 0u8; -x as u32; // ok! - -let v = 0 as *const u8; -v as *const i8; // ok! -``` - -For more information about casts, take a look at the Type cast section in -[The Reference Book][1]. - -[1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions -"##, - -E0606: r##" -An incompatible cast was attempted. - -Erroneous code example: - -```compile_fail,E0606 -let x = &0u8; // Here, `x` is a `&u8`. -let y: u32 = x as u32; // error: casting `&u8` as `u32` is invalid -``` - -When casting, keep in mind that only primitive types can be cast into each -other. Example: - -``` -let x = &0u8; -let y: u32 = *x as u32; // We dereference it first and then cast it. -``` - -For more information about casts, take a look at the Type cast section in -[The Reference Book][1]. - -[1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions -"##, - -E0607: r##" -A cast between a thin and a fat pointer was attempted. - -Erroneous code example: - -```compile_fail,E0607 -let v = 0 as *const u8; -v as *const [u8]; -``` - -First: what are thin and fat pointers? - -Thin pointers are "simple" pointers: they are purely a reference to a memory -address. - -Fat pointers are pointers referencing Dynamically Sized Types (also called DST). -DST don't have a statically known size, therefore they can only exist behind -some kind of pointers that contain additional information. Slices and trait -objects are DSTs. In the case of slices, the additional information the fat -pointer holds is their size. - -To fix this error, don't try to cast directly between thin and fat pointers. - -For more information about casts, take a look at the Type cast section in -[The Reference Book][1]. - -[1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions -"##, - -E0609: r##" -Attempted to access a non-existent field in a struct. - -Erroneous code example: - -```compile_fail,E0609 -struct StructWithFields { - x: u32, -} - -let s = StructWithFields { x: 0 }; -println!("{}", s.foo); // error: no field `foo` on type `StructWithFields` -``` - -To fix this error, check that you didn't misspell the field's name or that the -field actually exists. Example: - -``` -struct StructWithFields { - x: u32, -} - -let s = StructWithFields { x: 0 }; -println!("{}", s.x); // ok! -``` -"##, - -E0610: r##" -Attempted to access a field on a primitive type. - -Erroneous code example: - -```compile_fail,E0610 -let x: u32 = 0; -println!("{}", x.foo); // error: `{integer}` is a primitive type, therefore - // doesn't have fields -``` - -Primitive types are the most basic types available in Rust and don't have -fields. To access data via named fields, struct types are used. Example: - -``` -// We declare struct called `Foo` containing two fields: -struct Foo { - x: u32, - y: i64, -} - -// We create an instance of this struct: -let variable = Foo { x: 0, y: -12 }; -// And we can now access its fields: -println!("x: {}, y: {}", variable.x, variable.y); -``` - -For more information about primitives and structs, take a look at The Book: -https://doc.rust-lang.org/book/ch03-02-data-types.html -https://doc.rust-lang.org/book/ch05-00-structs.html -"##, - -E0614: r##" -Attempted to dereference a variable which cannot be dereferenced. - -Erroneous code example: - -```compile_fail,E0614 -let y = 0u32; -*y; // error: type `u32` cannot be dereferenced -``` - -Only types implementing `std::ops::Deref` can be dereferenced (such as `&T`). -Example: - -``` -let y = 0u32; -let x = &y; -// So here, `x` is a `&u32`, so we can dereference it: -*x; // ok! -``` -"##, - -E0615: r##" -Attempted to access a method like a field. - -Erroneous code example: - -```compile_fail,E0615 -struct Foo { - x: u32, -} - -impl Foo { - fn method(&self) {} -} - -let f = Foo { x: 0 }; -f.method; // error: attempted to take value of method `method` on type `Foo` -``` - -If you want to use a method, add `()` after it: - -``` -# struct Foo { x: u32 } -# impl Foo { fn method(&self) {} } -# let f = Foo { x: 0 }; -f.method(); -``` - -However, if you wanted to access a field of a struct check that the field name -is spelled correctly. Example: - -``` -# struct Foo { x: u32 } -# impl Foo { fn method(&self) {} } -# let f = Foo { x: 0 }; -println!("{}", f.x); -``` -"##, - -E0616: r##" -Attempted to access a private field on a struct. - -Erroneous code example: - -```compile_fail,E0616 -mod some_module { - pub struct Foo { - x: u32, // So `x` is private in here. - } - - impl Foo { - pub fn new() -> Foo { Foo { x: 0 } } - } -} - -let f = some_module::Foo::new(); -println!("{}", f.x); // error: field `x` of struct `some_module::Foo` is private -``` - -If you want to access this field, you have two options: - -1) Set the field public: - -``` -mod some_module { - pub struct Foo { - pub x: u32, // `x` is now public. - } - - impl Foo { - pub fn new() -> Foo { Foo { x: 0 } } - } -} - -let f = some_module::Foo::new(); -println!("{}", f.x); // ok! -``` - -2) Add a getter function: - -``` -mod some_module { - pub struct Foo { - x: u32, // So `x` is still private in here. - } - - impl Foo { - pub fn new() -> Foo { Foo { x: 0 } } - - // We create the getter function here: - pub fn get_x(&self) -> &u32 { &self.x } - } -} - -let f = some_module::Foo::new(); -println!("{}", f.get_x()); // ok! -``` -"##, - -E0617: r##" -Attempted to pass an invalid type of variable into a variadic function. - -Erroneous code example: - -```compile_fail,E0617 -extern { - fn printf(c: *const i8, ...); -} - -unsafe { - printf(::std::ptr::null(), 0f32); - // error: can't pass an `f32` to variadic function, cast to `c_double` -} -``` - -Certain Rust types must be cast before passing them to a variadic function, -because of arcane ABI rules dictated by the C standard. To fix the error, -cast the value to the type specified by the error message (which you may need -to import from `std::os::raw`). -"##, - -E0618: r##" -Attempted to call something which isn't a function nor a method. - -Erroneous code examples: - -```compile_fail,E0618 -enum X { - Entry, -} - -X::Entry(); // error: expected function, found `X::Entry` - -// Or even simpler: -let x = 0i32; -x(); // error: expected function, found `i32` -``` - -Only functions and methods can be called using `()`. Example: - -``` -// We declare a function: -fn i_am_a_function() {} - -// And we call it: -i_am_a_function(); -``` -"##, - -E0619: r##" -#### Note: this error code is no longer emitted by the compiler. -The type-checker needed to know the type of an expression, but that type had not -yet been inferred. - -Erroneous code example: - -```compile_fail -let mut x = vec![]; -match x.pop() { - Some(v) => { - // Here, the type of `v` is not (yet) known, so we - // cannot resolve this method call: - v.to_uppercase(); // error: the type of this value must be known in - // this context - } - None => {} -} -``` - -Type inference typically proceeds from the top of the function to the bottom, -figuring out types as it goes. In some cases -- notably method calls and -overloadable operators like `*` -- the type checker may not have enough -information *yet* to make progress. This can be true even if the rest of the -function provides enough context (because the type-checker hasn't looked that -far ahead yet). In this case, type annotations can be used to help it along. - -To fix this error, just specify the type of the variable. Example: - -``` -let mut x: Vec = vec![]; // We precise the type of the vec elements. -match x.pop() { - Some(v) => { - v.to_uppercase(); // Since rustc now knows the type of the vec elements, - // we can use `v`'s methods. - } - None => {} -} -``` -"##, - -E0620: r##" -A cast to an unsized type was attempted. - -Erroneous code example: - -```compile_fail,E0620 -let x = &[1_usize, 2] as [usize]; // error: cast to unsized type: `&[usize; 2]` - // as `[usize]` -``` - -In Rust, some types don't have a known size at compile-time. For example, in a -slice type like `[u32]`, the number of elements is not known at compile-time and -hence the overall size cannot be computed. As a result, such types can only be -manipulated through a reference (e.g., `&T` or `&mut T`) or other pointer-type -(e.g., `Box` or `Rc`). Try casting to a reference instead: - -``` -let x = &[1_usize, 2] as &[usize]; // ok! -``` -"##, - -E0622: r##" -An intrinsic was declared without being a function. - -Erroneous code example: - -```compile_fail,E0622 -#![feature(intrinsics)] -extern "rust-intrinsic" { - pub static breakpoint : unsafe extern "rust-intrinsic" fn(); - // error: intrinsic must be a function -} - -fn main() { unsafe { breakpoint(); } } -``` - -An intrinsic is a function available for use in a given programming language -whose implementation is handled specially by the compiler. In order to fix this -error, just declare a function. -"##, - -E0624: r##" -A private item was used outside of its scope. - -Erroneous code example: - -```compile_fail,E0624 -mod inner { - pub struct Foo; - - impl Foo { - fn method(&self) {} - } -} - -let foo = inner::Foo; -foo.method(); // error: method `method` is private -``` - -Two possibilities are available to solve this issue: - -1. Only use the item in the scope it has been defined: - -``` -mod inner { - pub struct Foo; - - impl Foo { - fn method(&self) {} - } - - pub fn call_method(foo: &Foo) { // We create a public function. - foo.method(); // Which calls the item. - } -} - -let foo = inner::Foo; -inner::call_method(&foo); // And since the function is public, we can call the - // method through it. -``` - -2. Make the item public: - -``` -mod inner { - pub struct Foo; - - impl Foo { - pub fn method(&self) {} // It's now public. - } -} - -let foo = inner::Foo; -foo.method(); // Ok! -``` -"##, - -E0638: r##" -This error indicates that the struct or enum must be matched non-exhaustively -as it has been marked as `non_exhaustive`. - -When applied within a crate, downstream users of the crate will need to use the -`_` pattern when matching enums and use the `..` pattern when matching structs. - -For example, in the below example, since the enum is marked as -`non_exhaustive`, it is required that downstream crates match non-exhaustively -on it. - -```rust,ignore (pseudo-Rust) -use std::error::Error as StdError; - -#[non_exhaustive] pub enum Error { - Message(String), - Other, -} - -impl StdError for Error { - fn description(&self) -> &str { - // This will not error, despite being marked as non_exhaustive, as this - // enum is defined within the current crate, it can be matched - // exhaustively. - match *self { - Message(ref s) => s, - Other => "other or unknown error", - } - } -} -``` - -An example of matching non-exhaustively on the above enum is provided below: - -```rust,ignore (pseudo-Rust) -use mycrate::Error; - -// This will not error as the non_exhaustive Error enum has been matched with a -// wildcard. -match error { - Message(ref s) => ..., - Other => ..., - _ => ..., -} -``` - -Similarly, for structs, match with `..` to avoid this error. -"##, - -E0639: r##" -This error indicates that the struct or enum cannot be instantiated from -outside of the defining crate as it has been marked as `non_exhaustive` and as -such more fields/variants may be added in future that could cause adverse side -effects for this code. - -It is recommended that you look for a `new` function or equivalent in the -crate's documentation. -"##, - -E0643: r##" -This error indicates that there is a mismatch between generic parameters and -impl Trait parameters in a trait declaration versus its impl. - -```compile_fail,E0643 -trait Foo { - fn foo(&self, _: &impl Iterator); -} -impl Foo for () { - fn foo(&self, _: &U) { } // error method `foo` has incompatible - // signature for trait -} -``` -"##, - -E0646: r##" -It is not possible to define `main` with a where clause. -Erroneous code example: - -```compile_fail,E0646 -fn main() where i32: Copy { // error: main function is not allowed to have - // a where clause -} -``` -"##, - -E0647: r##" -It is not possible to define `start` with a where clause. -Erroneous code example: - -```compile_fail,E0647 -#![feature(start)] - -#[start] -fn start(_: isize, _: *const *const u8) -> isize where (): Copy { - //^ error: start function is not allowed to have a where clause - 0 -} -``` -"##, - -E0648: r##" -`export_name` attributes may not contain null characters (`\0`). - -```compile_fail,E0648 -#[export_name="\0foo"] // error: `export_name` may not contain null characters -pub fn bar() {} -``` -"##, - -E0689: r##" -This error indicates that the numeric value for the method being passed exists -but the type of the numeric value or binding could not be identified. - -The error happens on numeric literals: - -```compile_fail,E0689 -2.0.neg(); -``` - -and on numeric bindings without an identified concrete type: - -```compile_fail,E0689 -let x = 2.0; -x.neg(); // same error as above -``` - -Because of this, you must give the numeric literal or binding a type: - -``` -use std::ops::Neg; - -let _ = 2.0_f32.neg(); -let x: f32 = 2.0; -let _ = x.neg(); -let _ = (2.0 as f32).neg(); -``` -"##, - -E0690: r##" -A struct with the representation hint `repr(transparent)` had zero or more than -on fields that were not guaranteed to be zero-sized. - -Erroneous code example: - -```compile_fail,E0690 -#[repr(transparent)] -struct LengthWithUnit { // error: transparent struct needs exactly one - value: f32, // non-zero-sized field, but has 2 - unit: U, -} -``` - -Because transparent structs are represented exactly like one of their fields at -run time, said field must be uniquely determined. If there is no field, or if -there are multiple fields, it is not clear how the struct should be represented. -Note that fields of zero-typed types (e.g., `PhantomData`) can also exist -alongside the field that contains the actual data, they do not count for this -error. When generic types are involved (as in the above example), an error is -reported because the type parameter could be non-zero-sized. - -To combine `repr(transparent)` with type parameters, `PhantomData` may be -useful: - -``` -use std::marker::PhantomData; - -#[repr(transparent)] -struct LengthWithUnit { - value: f32, - unit: PhantomData, -} -``` -"##, - -E0691: r##" -A struct with the `repr(transparent)` representation hint contains a zero-sized -field that requires non-trivial alignment. - -Erroneous code example: - -```compile_fail,E0691 -#![feature(repr_align)] - -#[repr(align(32))] -struct ForceAlign32; - -#[repr(transparent)] -struct Wrapper(f32, ForceAlign32); // error: zero-sized field in transparent - // struct has alignment larger than 1 -``` - -A transparent struct is supposed to be represented exactly like the piece of -data it contains. Zero-sized fields with different alignment requirements -potentially conflict with this property. In the example above, `Wrapper` would -have to be aligned to 32 bytes even though `f32` has a smaller alignment -requirement. - -Consider removing the over-aligned zero-sized field: - -``` -#[repr(transparent)] -struct Wrapper(f32); -``` - -Alternatively, `PhantomData` has alignment 1 for all `T`, so you can use it -if you need to keep the field for some reason: - -``` -#![feature(repr_align)] - -use std::marker::PhantomData; - -#[repr(align(32))] -struct ForceAlign32; - -#[repr(transparent)] -struct Wrapper(f32, PhantomData); -``` - -Note that empty arrays `[T; 0]` have the same alignment requirement as the -element type `T`. Also note that the error is conservatively reported even when -the alignment of the zero-sized type is less than or equal to the data field's -alignment. -"##, - - -E0699: r##" -A method was called on a raw pointer whose inner type wasn't completely known. - -For example, you may have done something like: - -```compile_fail -# #![deny(warnings)] -let foo = &1; -let bar = foo as *const _; -if bar.is_null() { - // ... -} -``` - -Here, the type of `bar` isn't known; it could be a pointer to anything. Instead, -specify a type for the pointer (preferably something that makes sense for the -thing you're pointing to): - -``` -let foo = &1; -let bar = foo as *const i32; -if bar.is_null() { - // ... -} -``` - -Even though `is_null()` exists as a method on any raw pointer, Rust shows this -error because Rust allows for `self` to have arbitrary types (behind the -arbitrary_self_types feature flag). - -This means that someone can specify such a function: - -```ignore (cannot-doctest-feature-doesnt-exist-yet) -impl Foo { - fn is_null(self: *const Self) -> bool { - // do something else - } -} -``` - -and now when you call `.is_null()` on a raw pointer to `Foo`, there's ambiguity. - -Given that we don't know what type the pointer is, and there's potential -ambiguity for some types, we disallow calling methods on raw pointers when -the type is unknown. -"##, - -E0714: r##" -A `#[marker]` trait contained an associated item. - -The items of marker traits cannot be overridden, so there's no need to have them -when they cannot be changed per-type anyway. If you wanted them for ergonomic -reasons, consider making an extension trait instead. -"##, - -E0715: r##" -An `impl` for a `#[marker]` trait tried to override an associated item. - -Because marker traits are allowed to have multiple implementations for the same -type, it's not allowed to override anything in those implementations, as it -would be ambiguous which override should actually be used. -"##, - - -E0720: r##" -An `impl Trait` type expands to a recursive type. - -An `impl Trait` type must be expandable to a concrete type that contains no -`impl Trait` types. For example the following example tries to create an -`impl Trait` type `T` that is equal to `[T, T]`: - -```compile_fail,E0720 -fn make_recursive_type() -> impl Sized { - [make_recursive_type(), make_recursive_type()] -} -``` -"##, - -} - -register_diagnostics! { -// E0035, merged into E0087/E0089 -// E0036, merged into E0087/E0089 -// E0068, -// E0085, -// E0086, -// E0103, -// E0104, -// E0122, // bounds in type aliases are ignored, turned into proper lint -// E0123, -// E0127, -// E0129, -// E0141, -// E0159, // use of trait `{}` as struct constructor -// E0163, // merged into E0071 -// E0167, -// E0168, -// E0172, // non-trait found in a type sum, moved to resolve -// E0173, // manual implementations of unboxed closure traits are experimental -// E0174, -// E0182, // merged into E0229 - E0183, -// E0187, // can't infer the kind of the closure -// E0188, // can not cast an immutable reference to a mutable pointer -// E0189, // deprecated: can only cast a boxed pointer to a boxed object -// E0190, // deprecated: can only cast a &-pointer to an &-object -// E0196, // cannot determine a type for this closure - E0203, // type parameter has more than one relaxed default bound, - // and only one is supported - E0208, -// E0209, // builtin traits can only be implemented on structs or enums - E0212, // cannot extract an associated type from a higher-ranked trait bound -// E0213, // associated types are not accepted in this context -// E0215, // angle-bracket notation is not stable with `Fn` -// E0216, // parenthetical notation is only stable with `Fn` -// E0217, // ambiguous associated type, defined in multiple supertraits -// E0218, // no associated type defined -// E0219, // associated type defined in higher-ranked supertrait -// E0222, // Error code E0045 (variadic function must have C or cdecl calling - // convention) duplicate - E0224, // at least one non-builtin train is required for an object type - E0227, // ambiguous lifetime bound, explicit lifetime bound required - E0228, // explicit lifetime bound required -// E0233, -// E0234, -// E0235, // structure constructor specifies a structure of type but -// E0236, // no lang item for range syntax -// E0237, // no lang item for range syntax -// E0238, // parenthesized parameters may only be used with a trait -// E0239, // `next` method of `Iterator` trait has unexpected type -// E0240, -// E0241, -// E0242, -// E0245, // not a trait -// E0246, // invalid recursive type -// E0247, -// E0248, // value used as a type, now reported earlier during resolution as E0412 -// E0249, - E0307, // invalid method `self` type -// E0319, // trait impls for defaulted traits allowed just for structs/enums -// E0372, // coherence not object safe - E0377, // the trait `CoerceUnsized` may only be implemented for a coercion - // between structures with the same definition -// E0558, // replaced with a generic attribute input check - E0533, // `{}` does not name a unit variant, unit struct or a constant -// E0563, // cannot determine a type for this `impl Trait`: {} // removed in 6383de15 - E0564, // only named lifetimes are allowed in `impl Trait`, - // but `{}` was found in the type `{}` - E0587, // type has conflicting packed and align representation hints - E0588, // packed type cannot transitively contain a `[repr(align)]` type - E0592, // duplicate definitions with name `{}` -// E0611, // merged into E0616 -// E0612, // merged into E0609 -// E0613, // Removed (merged with E0609) - E0627, // yield statement outside of generator literal - E0632, // cannot provide explicit type parameters when `impl Trait` is used in - // argument position. - E0634, // type has conflicting packed representaton hints - E0640, // infer outlives requirements - E0641, // cannot cast to/from a pointer with an unknown kind - E0645, // trait aliases not finished - E0698, // type inside generator must be known in this context - E0719, // duplicate values for associated type binding - E0722, // Malformed #[optimize] attribute - E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions -} diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs new file mode 100644 index 0000000000000..d61cef7f858d6 --- /dev/null +++ b/src/librustc_typeck/error_codes.rs @@ -0,0 +1,4853 @@ +// ignore-tidy-filelength + +#![allow(non_snake_case)] + +register_long_diagnostics! { + +E0023: r##" +A pattern used to match against an enum variant must provide a sub-pattern for +each field of the enum variant. This error indicates that a pattern attempted to +extract an incorrect number of fields from a variant. + +``` +enum Fruit { + Apple(String, String), + Pear(u32), +} +``` + +Here the `Apple` variant has two fields, and should be matched against like so: + +``` +enum Fruit { + Apple(String, String), + Pear(u32), +} + +let x = Fruit::Apple(String::new(), String::new()); + +// Correct. +match x { + Fruit::Apple(a, b) => {}, + _ => {} +} +``` + +Matching with the wrong number of fields has no sensible interpretation: + +```compile_fail,E0023 +enum Fruit { + Apple(String, String), + Pear(u32), +} + +let x = Fruit::Apple(String::new(), String::new()); + +// Incorrect. +match x { + Fruit::Apple(a) => {}, + Fruit::Apple(a, b, c) => {}, +} +``` + +Check how many fields the enum was declared with and ensure that your pattern +uses the same number. +"##, + +E0025: r##" +Each field of a struct can only be bound once in a pattern. Erroneous code +example: + +```compile_fail,E0025 +struct Foo { + a: u8, + b: u8, +} + +fn main(){ + let x = Foo { a:1, b:2 }; + + let Foo { a: x, a: y } = x; + // error: field `a` bound multiple times in the pattern +} +``` + +Each occurrence of a field name binds the value of that field, so to fix this +error you will have to remove or alter the duplicate uses of the field name. +Perhaps you misspelled another field name? Example: + +``` +struct Foo { + a: u8, + b: u8, +} + +fn main(){ + let x = Foo { a:1, b:2 }; + + let Foo { a: x, b: y } = x; // ok! +} +``` +"##, + +E0026: r##" +This error indicates that a struct pattern attempted to extract a non-existent +field from a struct. Struct fields are identified by the name used before the +colon `:` so struct patterns should resemble the declaration of the struct type +being matched. + +``` +// Correct matching. +struct Thing { + x: u32, + y: u32 +} + +let thing = Thing { x: 1, y: 2 }; + +match thing { + Thing { x: xfield, y: yfield } => {} +} +``` + +If you are using shorthand field patterns but want to refer to the struct field +by a different name, you should rename it explicitly. + +Change this: + +```compile_fail,E0026 +struct Thing { + x: u32, + y: u32 +} + +let thing = Thing { x: 0, y: 0 }; + +match thing { + Thing { x, z } => {} +} +``` + +To this: + +``` +struct Thing { + x: u32, + y: u32 +} + +let thing = Thing { x: 0, y: 0 }; + +match thing { + Thing { x, y: z } => {} +} +``` +"##, + +E0027: r##" +This error indicates that a pattern for a struct fails to specify a sub-pattern +for every one of the struct's fields. Ensure that each field from the struct's +definition is mentioned in the pattern, or use `..` to ignore unwanted fields. + +For example: + +```compile_fail,E0027 +struct Dog { + name: String, + age: u32, +} + +let d = Dog { name: "Rusty".to_string(), age: 8 }; + +// This is incorrect. +match d { + Dog { age: x } => {} +} +``` + +This is correct (explicit): + +``` +struct Dog { + name: String, + age: u32, +} + +let d = Dog { name: "Rusty".to_string(), age: 8 }; + +match d { + Dog { name: ref n, age: x } => {} +} + +// This is also correct (ignore unused fields). +match d { + Dog { age: x, .. } => {} +} +``` +"##, + +E0029: r##" +In a match expression, only numbers and characters can be matched against a +range. This is because the compiler checks that the range is non-empty at +compile-time, and is unable to evaluate arbitrary comparison functions. If you +want to capture values of an orderable type between two end-points, you can use +a guard. + +```compile_fail,E0029 +let string = "salutations !"; + +// The ordering relation for strings can't be evaluated at compile time, +// so this doesn't work: +match string { + "hello" ..= "world" => {} + _ => {} +} + +// This is a more general version, using a guard: +match string { + s if s >= "hello" && s <= "world" => {} + _ => {} +} +``` +"##, + +E0033: r##" +This error indicates that a pointer to a trait type cannot be implicitly +dereferenced by a pattern. Every trait defines a type, but because the +size of trait implementors isn't fixed, this type has no compile-time size. +Therefore, all accesses to trait types must be through pointers. If you +encounter this error you should try to avoid dereferencing the pointer. + +```compile_fail,E0033 +# trait SomeTrait { fn method_one(&self){} fn method_two(&self){} } +# impl SomeTrait for T {} +let trait_obj: &SomeTrait = &"some_value"; + +// This tries to implicitly dereference to create an unsized local variable. +let &invalid = trait_obj; + +// You can call methods without binding to the value being pointed at. +trait_obj.method_one(); +trait_obj.method_two(); +``` + +You can read more about trait objects in the [Trait Objects] section of the +Reference. + +[Trait Objects]: https://doc.rust-lang.org/reference/types.html#trait-objects +"##, + +E0034: r##" +The compiler doesn't know what method to call because more than one method +has the same prototype. Erroneous code example: + +```compile_fail,E0034 +struct Test; + +trait Trait1 { + fn foo(); +} + +trait Trait2 { + fn foo(); +} + +impl Trait1 for Test { fn foo() {} } +impl Trait2 for Test { fn foo() {} } + +fn main() { + Test::foo() // error, which foo() to call? +} +``` + +To avoid this error, you have to keep only one of them and remove the others. +So let's take our example and fix it: + +``` +struct Test; + +trait Trait1 { + fn foo(); +} + +impl Trait1 for Test { fn foo() {} } + +fn main() { + Test::foo() // and now that's good! +} +``` + +However, a better solution would be using fully explicit naming of type and +trait: + +``` +struct Test; + +trait Trait1 { + fn foo(); +} + +trait Trait2 { + fn foo(); +} + +impl Trait1 for Test { fn foo() {} } +impl Trait2 for Test { fn foo() {} } + +fn main() { + ::foo() +} +``` + +One last example: + +``` +trait F { + fn m(&self); +} + +trait G { + fn m(&self); +} + +struct X; + +impl F for X { fn m(&self) { println!("I am F"); } } +impl G for X { fn m(&self) { println!("I am G"); } } + +fn main() { + let f = X; + + F::m(&f); // it displays "I am F" + G::m(&f); // it displays "I am G" +} +``` +"##, + +E0040: r##" +It is not allowed to manually call destructors in Rust. It is also not +necessary to do this since `drop` is called automatically whenever a value goes +out of scope. + +Here's an example of this error: + +```compile_fail,E0040 +struct Foo { + x: i32, +} + +impl Drop for Foo { + fn drop(&mut self) { + println!("kaboom"); + } +} + +fn main() { + let mut x = Foo { x: -7 }; + x.drop(); // error: explicit use of destructor method +} +``` +"##, + +E0044: r##" +You can't use type or const parameters on foreign items. +Example of erroneous code: + +```compile_fail,E0044 +extern { fn some_func(x: T); } +``` + +To fix this, replace the generic parameter with the specializations that you +need: + +``` +extern { fn some_func_i32(x: i32); } +extern { fn some_func_i64(x: i64); } +``` +"##, + +E0045: r##" +Rust only supports variadic parameters for interoperability with C code in its +FFI. As such, variadic parameters can only be used with functions which are +using the C ABI. Examples of erroneous code: + +```compile_fail +#![feature(unboxed_closures)] + +extern "rust-call" { fn foo(x: u8, ...); } + +// or + +fn foo(x: u8, ...) {} +``` + +To fix such code, put them in an extern "C" block: + +``` +extern "C" { + fn foo (x: u8, ...); +} +``` +"##, + +E0046: r##" +Items are missing in a trait implementation. Erroneous code example: + +```compile_fail,E0046 +trait Foo { + fn foo(); +} + +struct Bar; + +impl Foo for Bar {} +// error: not all trait items implemented, missing: `foo` +``` + +When trying to make some type implement a trait `Foo`, you must, at minimum, +provide implementations for all of `Foo`'s required methods (meaning the +methods that do not have default implementations), as well as any required +trait items like associated types or constants. Example: + +``` +trait Foo { + fn foo(); +} + +struct Bar; + +impl Foo for Bar { + fn foo() {} // ok! +} +``` +"##, + +E0049: r##" +This error indicates that an attempted implementation of a trait method +has the wrong number of type or const parameters. + +For example, the trait below has a method `foo` with a type parameter `T`, +but the implementation of `foo` for the type `Bar` is missing this parameter: + +```compile_fail,E0049 +trait Foo { + fn foo(x: T) -> Self; +} + +struct Bar; + +// error: method `foo` has 0 type parameters but its trait declaration has 1 +// type parameter +impl Foo for Bar { + fn foo(x: bool) -> Self { Bar } +} +``` +"##, + +E0050: r##" +This error indicates that an attempted implementation of a trait method +has the wrong number of function parameters. + +For example, the trait below has a method `foo` with two function parameters +(`&self` and `u8`), but the implementation of `foo` for the type `Bar` omits +the `u8` parameter: + +```compile_fail,E0050 +trait Foo { + fn foo(&self, x: u8) -> bool; +} + +struct Bar; + +// error: method `foo` has 1 parameter but the declaration in trait `Foo::foo` +// has 2 +impl Foo for Bar { + fn foo(&self) -> bool { true } +} +``` +"##, + +E0053: r##" +The parameters of any trait method must match between a trait implementation +and the trait definition. + +Here are a couple examples of this error: + +```compile_fail,E0053 +trait Foo { + fn foo(x: u16); + fn bar(&self); +} + +struct Bar; + +impl Foo for Bar { + // error, expected u16, found i16 + fn foo(x: i16) { } + + // error, types differ in mutability + fn bar(&mut self) { } +} +``` +"##, + +E0054: r##" +It is not allowed to cast to a bool. If you are trying to cast a numeric type +to a bool, you can compare it with zero instead: + +```compile_fail,E0054 +let x = 5; + +// Not allowed, won't compile +let x_is_nonzero = x as bool; +``` + +``` +let x = 5; + +// Ok +let x_is_nonzero = x != 0; +``` +"##, + +E0055: r##" +During a method call, a value is automatically dereferenced as many times as +needed to make the value's type match the method's receiver. The catch is that +the compiler will only attempt to dereference a number of times up to the +recursion limit (which can be set via the `recursion_limit` attribute). + +For a somewhat artificial example: + +```compile_fail,E0055 +#![recursion_limit="5"] + +struct Foo; + +impl Foo { + fn foo(&self) {} +} + +fn main() { + let foo = Foo; + let ref_foo = &&&&&Foo; + + // error, reached the recursion limit while auto-dereferencing `&&&&&Foo` + ref_foo.foo(); +} +``` + +One fix may be to increase the recursion limit. Note that it is possible to +create an infinite recursion of dereferencing, in which case the only fix is to +somehow break the recursion. +"##, + +E0057: r##" +When invoking closures or other implementations of the function traits `Fn`, +`FnMut` or `FnOnce` using call notation, the number of parameters passed to the +function must match its definition. + +An example using a closure: + +```compile_fail,E0057 +let f = |x| x * 3; +let a = f(); // invalid, too few parameters +let b = f(4); // this works! +let c = f(2, 3); // invalid, too many parameters +``` + +A generic function must be treated similarly: + +``` +fn foo(f: F) { + f(); // this is valid, but f(3) would not work +} +``` +"##, + +E0059: r##" +The built-in function traits are generic over a tuple of the function arguments. +If one uses angle-bracket notation (`Fn<(T,), Output=U>`) instead of parentheses +(`Fn(T) -> U`) to denote the function trait, the type parameter should be a +tuple. Otherwise function call notation cannot be used and the trait will not be +implemented by closures. + +The most likely source of this error is using angle-bracket notation without +wrapping the function argument type into a tuple, for example: + +```compile_fail,E0059 +#![feature(unboxed_closures)] + +fn foo>(f: F) -> F::Output { f(3) } +``` + +It can be fixed by adjusting the trait bound like this: + +``` +#![feature(unboxed_closures)] + +fn foo>(f: F) -> F::Output { f(3) } +``` + +Note that `(T,)` always denotes the type of a 1-tuple containing an element of +type `T`. The comma is necessary for syntactic disambiguation. +"##, + +E0060: r##" +External C functions are allowed to be variadic. However, a variadic function +takes a minimum number of arguments. For example, consider C's variadic `printf` +function: + +``` +use std::os::raw::{c_char, c_int}; + +extern "C" { + fn printf(_: *const c_char, ...) -> c_int; +} +``` + +Using this declaration, it must be called with at least one argument, so +simply calling `printf()` is invalid. But the following uses are allowed: + +``` +# #![feature(static_nobundle)] +# use std::os::raw::{c_char, c_int}; +# #[cfg_attr(all(windows, target_env = "msvc"), +# link(name = "legacy_stdio_definitions", kind = "static-nobundle"))] +# extern "C" { fn printf(_: *const c_char, ...) -> c_int; } +# fn main() { +unsafe { + use std::ffi::CString; + + let fmt = CString::new("test\n").unwrap(); + printf(fmt.as_ptr()); + + let fmt = CString::new("number = %d\n").unwrap(); + printf(fmt.as_ptr(), 3); + + let fmt = CString::new("%d, %d\n").unwrap(); + printf(fmt.as_ptr(), 10, 5); +} +# } +``` +"##, +// ^ Note: On MSVC 2015, the `printf` function is "inlined" in the C code, and +// the C runtime does not contain the `printf` definition. This leads to linker +// error from the doc test (issue #42830). +// This can be fixed by linking to the static library +// `legacy_stdio_definitions.lib` (see https://stackoverflow.com/a/36504365/). +// If this compatibility library is removed in the future, consider changing +// `printf` in this example to another well-known variadic function. + +E0061: r##" +The number of arguments passed to a function must match the number of arguments +specified in the function signature. + +For example, a function like: + +``` +fn f(a: u16, b: &str) {} +``` + +Must always be called with exactly two arguments, e.g., `f(2, "test")`. + +Note that Rust does not have a notion of optional function arguments or +variadic functions (except for its C-FFI). +"##, + +E0062: r##" +This error indicates that during an attempt to build a struct or struct-like +enum variant, one of the fields was specified more than once. Erroneous code +example: + +```compile_fail,E0062 +struct Foo { + x: i32, +} + +fn main() { + let x = Foo { + x: 0, + x: 0, // error: field `x` specified more than once + }; +} +``` + +Each field should be specified exactly one time. Example: + +``` +struct Foo { + x: i32, +} + +fn main() { + let x = Foo { x: 0 }; // ok! +} +``` +"##, + +E0063: r##" +This error indicates that during an attempt to build a struct or struct-like +enum variant, one of the fields was not provided. Erroneous code example: + +```compile_fail,E0063 +struct Foo { + x: i32, + y: i32, +} + +fn main() { + let x = Foo { x: 0 }; // error: missing field: `y` +} +``` + +Each field should be specified exactly once. Example: + +``` +struct Foo { + x: i32, + y: i32, +} + +fn main() { + let x = Foo { x: 0, y: 0 }; // ok! +} +``` +"##, + +E0067: r##" +The left-hand side of a compound assignment expression must be a place +expression. A place expression represents a memory location and includes +item paths (ie, namespaced variables), dereferences, indexing expressions, +and field references. + +Let's start with some erroneous code examples: + +```compile_fail,E0067 +use std::collections::LinkedList; + +// Bad: assignment to non-place expression +LinkedList::new() += 1; + +// ... + +fn some_func(i: &mut i32) { + i += 12; // Error : '+=' operation cannot be applied on a reference ! +} +``` + +And now some working examples: + +``` +let mut i : i32 = 0; + +i += 12; // Good ! + +// ... + +fn some_func(i: &mut i32) { + *i += 12; // Good ! +} +``` +"##, + +E0069: r##" +The compiler found a function whose body contains a `return;` statement but +whose return type is not `()`. An example of this is: + +```compile_fail,E0069 +// error +fn foo() -> u8 { + return; +} +``` + +Since `return;` is just like `return ();`, there is a mismatch between the +function's return type and the value being returned. +"##, + +E0070: r##" +The left-hand side of an assignment operator must be a place expression. A +place expression represents a memory location and can be a variable (with +optional namespacing), a dereference, an indexing expression or a field +reference. + +More details can be found in the [Expressions] section of the Reference. + +[Expressions]: https://doc.rust-lang.org/reference/expressions.html#places-rvalues-and-temporaries + +Now, we can go further. Here are some erroneous code examples: + +```compile_fail,E0070 +struct SomeStruct { + x: i32, + y: i32 +} + +const SOME_CONST : i32 = 12; + +fn some_other_func() {} + +fn some_function() { + SOME_CONST = 14; // error : a constant value cannot be changed! + 1 = 3; // error : 1 isn't a valid place! + some_other_func() = 4; // error : we can't assign value to a function! + SomeStruct.x = 12; // error : SomeStruct a structure name but it is used + // like a variable! +} +``` + +And now let's give working examples: + +``` +struct SomeStruct { + x: i32, + y: i32 +} +let mut s = SomeStruct {x: 0, y: 0}; + +s.x = 3; // that's good ! + +// ... + +fn some_func(x: &mut i32) { + *x = 12; // that's good ! +} +``` +"##, + +E0071: r##" +You tried to use structure-literal syntax to create an item that is +not a structure or enum variant. + +Example of erroneous code: + +```compile_fail,E0071 +type U32 = u32; +let t = U32 { value: 4 }; // error: expected struct, variant or union type, + // found builtin type `u32` +``` + +To fix this, ensure that the name was correctly spelled, and that +the correct form of initializer was used. + +For example, the code above can be fixed to: + +``` +enum Foo { + FirstValue(i32) +} + +fn main() { + let u = Foo::FirstValue(0i32); + + let t = 4; +} +``` +"##, + +E0073: r##" +#### Note: this error code is no longer emitted by the compiler. + +You cannot define a struct (or enum) `Foo` that requires an instance of `Foo` +in order to make a new `Foo` value. This is because there would be no way a +first instance of `Foo` could be made to initialize another instance! + +Here's an example of a struct that has this problem: + +``` +struct Foo { x: Box } // error +``` + +One fix is to use `Option`, like so: + +``` +struct Foo { x: Option> } +``` + +Now it's possible to create at least one instance of `Foo`: `Foo { x: None }`. +"##, + +E0074: r##" +#### Note: this error code is no longer emitted by the compiler. + +When using the `#[simd]` attribute on a tuple struct, the components of the +tuple struct must all be of a concrete, nongeneric type so the compiler can +reason about how to use SIMD with them. This error will occur if the types +are generic. + +This will cause an error: + +``` +#![feature(repr_simd)] + +#[repr(simd)] +struct Bad(T, T, T); +``` + +This will not: + +``` +#![feature(repr_simd)] + +#[repr(simd)] +struct Good(u32, u32, u32); +``` +"##, + +E0075: r##" +The `#[simd]` attribute can only be applied to non empty tuple structs, because +it doesn't make sense to try to use SIMD operations when there are no values to +operate on. + +This will cause an error: + +```compile_fail,E0075 +#![feature(repr_simd)] + +#[repr(simd)] +struct Bad; +``` + +This will not: + +``` +#![feature(repr_simd)] + +#[repr(simd)] +struct Good(u32); +``` +"##, + +E0076: r##" +When using the `#[simd]` attribute to automatically use SIMD operations in tuple +struct, the types in the struct must all be of the same type, or the compiler +will trigger this error. + +This will cause an error: + +```compile_fail,E0076 +#![feature(repr_simd)] + +#[repr(simd)] +struct Bad(u16, u32, u32); +``` + +This will not: + +``` +#![feature(repr_simd)] + +#[repr(simd)] +struct Good(u32, u32, u32); +``` +"##, + +E0077: r##" +When using the `#[simd]` attribute on a tuple struct, the elements in the tuple +must be machine types so SIMD operations can be applied to them. + +This will cause an error: + +```compile_fail,E0077 +#![feature(repr_simd)] + +#[repr(simd)] +struct Bad(String); +``` + +This will not: + +``` +#![feature(repr_simd)] + +#[repr(simd)] +struct Good(u32, u32, u32); +``` +"##, + +E0081: r##" +Enum discriminants are used to differentiate enum variants stored in memory. +This error indicates that the same value was used for two or more variants, +making them impossible to tell apart. + +```compile_fail,E0081 +// Bad. +enum Enum { + P = 3, + X = 3, + Y = 5, +} +``` + +``` +// Good. +enum Enum { + P, + X = 3, + Y = 5, +} +``` + +Note that variants without a manually specified discriminant are numbered from +top to bottom starting from 0, so clashes can occur with seemingly unrelated +variants. + +```compile_fail,E0081 +enum Bad { + X, + Y = 0 +} +``` + +Here `X` will have already been specified the discriminant 0 by the time `Y` is +encountered, so a conflict occurs. +"##, + +E0084: r##" +An unsupported representation was attempted on a zero-variant enum. + +Erroneous code example: + +```compile_fail,E0084 +#[repr(i32)] +enum NightsWatch {} // error: unsupported representation for zero-variant enum +``` + +It is impossible to define an integer type to be used to represent zero-variant +enum values because there are no zero-variant enum values. There is no way to +construct an instance of the following type using only safe code. So you have +two solutions. Either you add variants in your enum: + +``` +#[repr(i32)] +enum NightsWatch { + JonSnow, + Commander, +} +``` + +or you remove the integer represention of your enum: + +``` +enum NightsWatch {} +``` +"##, + +// FIXME(const_generics:docs): example of inferring const parameter. +E0087: r##" +#### Note: this error code is no longer emitted by the compiler. + +Too many type arguments were supplied for a function. For example: + +```compile_fail,E0107 +fn foo() {} + +fn main() { + foo::(); // error: wrong number of type arguments: + // expected 1, found 2 +} +``` + +The number of supplied arguments must exactly match the number of defined type +parameters. +"##, + +E0088: r##" +#### Note: this error code is no longer emitted by the compiler. + +You gave too many lifetime arguments. Erroneous code example: + +```compile_fail,E0107 +fn f() {} + +fn main() { + f::<'static>() // error: wrong number of lifetime arguments: + // expected 0, found 1 +} +``` + +Please check you give the right number of lifetime arguments. Example: + +``` +fn f() {} + +fn main() { + f() // ok! +} +``` + +It's also important to note that the Rust compiler can generally +determine the lifetime by itself. Example: + +``` +struct Foo { + value: String +} + +impl Foo { + // it can be written like this + fn get_value<'a>(&'a self) -> &'a str { &self.value } + // but the compiler works fine with this too: + fn without_lifetime(&self) -> &str { &self.value } +} + +fn main() { + let f = Foo { value: "hello".to_owned() }; + + println!("{}", f.get_value()); + println!("{}", f.without_lifetime()); +} +``` +"##, + +E0089: r##" +#### Note: this error code is no longer emitted by the compiler. + +Too few type arguments were supplied for a function. For example: + +```compile_fail,E0107 +fn foo() {} + +fn main() { + foo::(); // error: wrong number of type arguments: expected 2, found 1 +} +``` + +Note that if a function takes multiple type arguments but you want the compiler +to infer some of them, you can use type placeholders: + +```compile_fail,E0107 +fn foo(x: T) {} + +fn main() { + let x: bool = true; + foo::(x); // error: wrong number of type arguments: + // expected 2, found 1 + foo::<_, f64>(x); // same as `foo::(x)` +} +``` +"##, + +E0090: r##" +#### Note: this error code is no longer emitted by the compiler. + +You gave too few lifetime arguments. Example: + +```compile_fail,E0107 +fn foo<'a: 'b, 'b: 'a>() {} + +fn main() { + foo::<'static>(); // error: wrong number of lifetime arguments: + // expected 2, found 1 +} +``` + +Please check you give the right number of lifetime arguments. Example: + +``` +fn foo<'a: 'b, 'b: 'a>() {} + +fn main() { + foo::<'static, 'static>(); +} +``` +"##, + +E0091: r##" +You gave an unnecessary type or const parameter in a type alias. Erroneous +code example: + +```compile_fail,E0091 +type Foo = u32; // error: type parameter `T` is unused +// or: +type Foo = Box; // error: type parameter `B` is unused +``` + +Please check you didn't write too many parameters. Example: + +``` +type Foo = u32; // ok! +type Foo2 = Box; // ok! +``` +"##, + +E0092: r##" +You tried to declare an undefined atomic operation function. +Erroneous code example: + +```compile_fail,E0092 +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn atomic_foo(); // error: unrecognized atomic operation + // function +} +``` + +Please check you didn't make a mistake in the function's name. All intrinsic +functions are defined in librustc_codegen_llvm/intrinsic.rs and in +libcore/intrinsics.rs in the Rust source code. Example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn atomic_fence(); // ok! +} +``` +"##, + +E0093: r##" +You declared an unknown intrinsic function. Erroneous code example: + +```compile_fail,E0093 +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn foo(); // error: unrecognized intrinsic function: `foo` +} + +fn main() { + unsafe { + foo(); + } +} +``` + +Please check you didn't make a mistake in the function's name. All intrinsic +functions are defined in librustc_codegen_llvm/intrinsic.rs and in +libcore/intrinsics.rs in the Rust source code. Example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn atomic_fence(); // ok! +} + +fn main() { + unsafe { + atomic_fence(); + } +} +``` +"##, + +E0094: r##" +You gave an invalid number of type parameters to an intrinsic function. +Erroneous code example: + +```compile_fail,E0094 +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn size_of() -> usize; // error: intrinsic has wrong number + // of type parameters +} +``` + +Please check that you provided the right number of type parameters +and verify with the function declaration in the Rust source code. +Example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn size_of() -> usize; // ok! +} +``` +"##, + +E0107: r##" +This error means that an incorrect number of generic arguments were provided: + +```compile_fail,E0107 +struct Foo { x: T } + +struct Bar { x: Foo } // error: wrong number of type arguments: + // expected 1, found 0 +struct Baz { x: Foo } // error: wrong number of type arguments: + // expected 1, found 2 + +fn foo(x: T, y: U) {} + +fn main() { + let x: bool = true; + foo::(x); // error: wrong number of type arguments: + // expected 2, found 1 + foo::(x, 2, 4); // error: wrong number of type arguments: + // expected 2, found 3 +} + +fn f() {} + +fn main() { + f::<'static>(); // error: wrong number of lifetime arguments: + // expected 0, found 1 +} +``` + +"##, + +E0109: r##" +You tried to provide a generic argument to a type which doesn't need it. +Erroneous code example: + +```compile_fail,E0109 +type X = u32; // error: type arguments are not allowed for this type +type Y = bool<'static>; // error: lifetime parameters are not allowed on + // this type +``` + +Check that you used the correct argument and that the definition is correct. + +Example: + +``` +type X = u32; // ok! +type Y = bool; // ok! +``` + +Note that generic arguments for enum variant constructors go after the variant, +not after the enum. For example, you would write `Option::None::`, +rather than `Option::::None`. +"##, + +E0110: r##" +#### Note: this error code is no longer emitted by the compiler. + +You tried to provide a lifetime to a type which doesn't need it. +See `E0109` for more details. +"##, + +E0116: r##" +You can only define an inherent implementation for a type in the same crate +where the type was defined. For example, an `impl` block as below is not allowed +since `Vec` is defined in the standard library: + +```compile_fail,E0116 +impl Vec { } // error +``` + +To fix this problem, you can do either of these things: + + - define a trait that has the desired associated functions/types/constants and + implement the trait for the type in question + - define a new type wrapping the type and define an implementation on the new + type + +Note that using the `type` keyword does not work here because `type` only +introduces a type alias: + +```compile_fail,E0116 +type Bytes = Vec; + +impl Bytes { } // error, same as above +``` +"##, + +E0117: r##" +This error indicates a violation of one of Rust's orphan rules for trait +implementations. The rule prohibits any implementation of a foreign trait (a +trait defined in another crate) where + + - the type that is implementing the trait is foreign + - all of the parameters being passed to the trait (if there are any) are also + foreign. + +Here's one example of this error: + +```compile_fail,E0117 +impl Drop for u32 {} +``` + +To avoid this kind of error, ensure that at least one local type is referenced +by the `impl`: + +``` +pub struct Foo; // you define your type in your crate + +impl Drop for Foo { // and you can implement the trait on it! + // code of trait implementation here +# fn drop(&mut self) { } +} + +impl From for i32 { // or you use a type from your crate as + // a type parameter + fn from(i: Foo) -> i32 { + 0 + } +} +``` + +Alternatively, define a trait locally and implement that instead: + +``` +trait Bar { + fn get(&self) -> usize; +} + +impl Bar for u32 { + fn get(&self) -> usize { 0 } +} +``` + +For information on the design of the orphan rules, see [RFC 1023]. + +[RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md +"##, + +E0118: r##" +You're trying to write an inherent implementation for something which isn't a +struct nor an enum. Erroneous code example: + +```compile_fail,E0118 +impl (u8, u8) { // error: no base type found for inherent implementation + fn get_state(&self) -> String { + // ... + } +} +``` + +To fix this error, please implement a trait on the type or wrap it in a struct. +Example: + +``` +// we create a trait here +trait LiveLongAndProsper { + fn get_state(&self) -> String; +} + +// and now you can implement it on (u8, u8) +impl LiveLongAndProsper for (u8, u8) { + fn get_state(&self) -> String { + "He's dead, Jim!".to_owned() + } +} +``` + +Alternatively, you can create a newtype. A newtype is a wrapping tuple-struct. +For example, `NewType` is a newtype over `Foo` in `struct NewType(Foo)`. +Example: + +``` +struct TypeWrapper((u8, u8)); + +impl TypeWrapper { + fn get_state(&self) -> String { + "Fascinating!".to_owned() + } +} +``` +"##, + +E0120: r##" +An attempt was made to implement Drop on a trait, which is not allowed: only +structs and enums can implement Drop. An example causing this error: + +```compile_fail,E0120 +trait MyTrait {} + +impl Drop for MyTrait { + fn drop(&mut self) {} +} +``` + +A workaround for this problem is to wrap the trait up in a struct, and implement +Drop on that. An example is shown below: + +``` +trait MyTrait {} +struct MyWrapper { foo: T } + +impl Drop for MyWrapper { + fn drop(&mut self) {} +} + +``` + +Alternatively, wrapping trait objects requires something like the following: + +``` +trait MyTrait {} + +//or Box, if you wanted an owned trait object +struct MyWrapper<'a> { foo: &'a MyTrait } + +impl <'a> Drop for MyWrapper<'a> { + fn drop(&mut self) {} +} +``` +"##, + +E0121: r##" +In order to be consistent with Rust's lack of global type inference, +type and const placeholders are disallowed by design in item signatures. + +Examples of this error include: + +```compile_fail,E0121 +fn foo() -> _ { 5 } // error, explicitly write out the return type instead + +static BAR: _ = "test"; // error, explicitly write out the type instead +``` +"##, + +E0124: r##" +You declared two fields of a struct with the same name. Erroneous code +example: + +```compile_fail,E0124 +struct Foo { + field1: i32, + field1: i32, // error: field is already declared +} +``` + +Please verify that the field names have been correctly spelled. Example: + +``` +struct Foo { + field1: i32, + field2: i32, // ok! +} +``` +"##, + +E0131: r##" +It is not possible to define `main` with generic parameters. +When `main` is present, it must take no arguments and return `()`. +Erroneous code example: + +```compile_fail,E0131 +fn main() { // error: main function is not allowed to have generic parameters +} +``` +"##, + +E0132: r##" +A function with the `start` attribute was declared with type parameters. + +Erroneous code example: + +```compile_fail,E0132 +#![feature(start)] + +#[start] +fn f() {} +``` + +It is not possible to declare type parameters on a function that has the `start` +attribute. Such a function must have the following type signature (for more +information, view [the unstable book][1]): + +[1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#writing-an-executable-without-stdlib + +``` +# let _: +fn(isize, *const *const u8) -> isize; +``` + +Example: + +``` +#![feature(start)] + +#[start] +fn my_start(argc: isize, argv: *const *const u8) -> isize { + 0 +} +``` +"##, + +E0164: r##" +This error means that an attempt was made to match a struct type enum +variant as a non-struct type: + +```compile_fail,E0164 +enum Foo { B { i: u32 } } + +fn bar(foo: Foo) -> u32 { + match foo { + Foo::B(i) => i, // error E0164 + } +} +``` + +Try using `{}` instead: + +``` +enum Foo { B { i: u32 } } + +fn bar(foo: Foo) -> u32 { + match foo { + Foo::B{i} => i, + } +} +``` +"##, + +E0184: r##" +Explicitly implementing both Drop and Copy for a type is currently disallowed. +This feature can make some sense in theory, but the current implementation is +incorrect and can lead to memory unsafety (see [issue #20126][iss20126]), so +it has been disabled for now. + +[iss20126]: https://github.com/rust-lang/rust/issues/20126 +"##, + +E0185: r##" +An associated function for a trait was defined to be static, but an +implementation of the trait declared the same function to be a method (i.e., to +take a `self` parameter). + +Here's an example of this error: + +```compile_fail,E0185 +trait Foo { + fn foo(); +} + +struct Bar; + +impl Foo for Bar { + // error, method `foo` has a `&self` declaration in the impl, but not in + // the trait + fn foo(&self) {} +} +``` +"##, + +E0186: r##" +An associated function for a trait was defined to be a method (i.e., to take a +`self` parameter), but an implementation of the trait declared the same function +to be static. + +Here's an example of this error: + +```compile_fail,E0186 +trait Foo { + fn foo(&self); +} + +struct Bar; + +impl Foo for Bar { + // error, method `foo` has a `&self` declaration in the trait, but not in + // the impl + fn foo() {} +} +``` +"##, + +E0191: r##" +Trait objects need to have all associated types specified. Erroneous code +example: + +```compile_fail,E0191 +trait Trait { + type Bar; +} + +type Foo = Trait; // error: the value of the associated type `Bar` (from + // the trait `Trait`) must be specified +``` + +Please verify you specified all associated types of the trait and that you +used the right trait. Example: + +``` +trait Trait { + type Bar; +} + +type Foo = Trait; // ok! +``` +"##, + +E0192: r##" +Negative impls are only allowed for auto traits. For more +information see the [opt-in builtin traits RFC][RFC 19]. + +[RFC 19]: https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md +"##, + +E0193: r##" +#### Note: this error code is no longer emitted by the compiler. + +`where` clauses must use generic type parameters: it does not make sense to use +them otherwise. An example causing this error: + +``` +trait Foo { + fn bar(&self); +} + +#[derive(Copy,Clone)] +struct Wrapper { + Wrapped: T +} + +impl Foo for Wrapper where Wrapper: Clone { + fn bar(&self) { } +} +``` + +This use of a `where` clause is strange - a more common usage would look +something like the following: + +``` +trait Foo { + fn bar(&self); +} + +#[derive(Copy,Clone)] +struct Wrapper { + Wrapped: T +} +impl Foo for Wrapper where Wrapper: Clone { + fn bar(&self) { } +} +``` + +Here, we're saying that the implementation exists on Wrapper only when the +wrapped type `T` implements `Clone`. The `where` clause is important because +some types will not implement `Clone`, and thus will not get this method. + +In our erroneous example, however, we're referencing a single concrete type. +Since we know for certain that `Wrapper` implements `Clone`, there's no +reason to also specify it in a `where` clause. +"##, + +E0194: r##" +A type parameter was declared which shadows an existing one. An example of this +error: + +```compile_fail,E0194 +trait Foo { + fn do_something(&self) -> T; + fn do_something_else(&self, bar: T); +} +``` + +In this example, the trait `Foo` and the trait method `do_something_else` both +define a type parameter `T`. This is not allowed: if the method wishes to +define a type parameter, it must use a different name for it. +"##, + +E0195: r##" +Your method's lifetime parameters do not match the trait declaration. +Erroneous code example: + +```compile_fail,E0195 +trait Trait { + fn bar<'a,'b:'a>(x: &'a str, y: &'b str); +} + +struct Foo; + +impl Trait for Foo { + fn bar<'a,'b>(x: &'a str, y: &'b str) { + // error: lifetime parameters or bounds on method `bar` + // do not match the trait declaration + } +} +``` + +The lifetime constraint `'b` for bar() implementation does not match the +trait declaration. Ensure lifetime declarations match exactly in both trait +declaration and implementation. Example: + +``` +trait Trait { + fn t<'a,'b:'a>(x: &'a str, y: &'b str); +} + +struct Foo; + +impl Trait for Foo { + fn t<'a,'b:'a>(x: &'a str, y: &'b str) { // ok! + } +} +``` +"##, + +E0199: r##" +Safe traits should not have unsafe implementations, therefore marking an +implementation for a safe trait unsafe will cause a compiler error. Removing +the unsafe marker on the trait noted in the error will resolve this problem. + +```compile_fail,E0199 +struct Foo; + +trait Bar { } + +// this won't compile because Bar is safe +unsafe impl Bar for Foo { } +// this will compile +impl Bar for Foo { } +``` +"##, + +E0200: r##" +Unsafe traits must have unsafe implementations. This error occurs when an +implementation for an unsafe trait isn't marked as unsafe. This may be resolved +by marking the unsafe implementation as unsafe. + +```compile_fail,E0200 +struct Foo; + +unsafe trait Bar { } + +// this won't compile because Bar is unsafe and impl isn't unsafe +impl Bar for Foo { } +// this will compile +unsafe impl Bar for Foo { } +``` +"##, + +E0201: r##" +It is an error to define two associated items (like methods, associated types, +associated functions, etc.) with the same identifier. + +For example: + +```compile_fail,E0201 +struct Foo(u8); + +impl Foo { + fn bar(&self) -> bool { self.0 > 5 } + fn bar() {} // error: duplicate associated function +} + +trait Baz { + type Quux; + fn baz(&self) -> bool; +} + +impl Baz for Foo { + type Quux = u32; + + fn baz(&self) -> bool { true } + + // error: duplicate method + fn baz(&self) -> bool { self.0 > 5 } + + // error: duplicate associated type + type Quux = u32; +} +``` + +Note, however, that items with the same name are allowed for inherent `impl` +blocks that don't overlap: + +``` +struct Foo(T); + +impl Foo { + fn bar(&self) -> bool { self.0 > 5 } +} + +impl Foo { + fn bar(&self) -> bool { self.0 } +} +``` +"##, + +E0202: r##" +Inherent associated types were part of [RFC 195] but are not yet implemented. +See [the tracking issue][iss8995] for the status of this implementation. + +[RFC 195]: https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md +[iss8995]: https://github.com/rust-lang/rust/issues/8995 +"##, + +E0204: r##" +An attempt to implement the `Copy` trait for a struct failed because one of the +fields does not implement `Copy`. To fix this, you must implement `Copy` for the +mentioned field. Note that this may not be possible, as in the example of + +```compile_fail,E0204 +struct Foo { + foo : Vec, +} + +impl Copy for Foo { } +``` + +This fails because `Vec` does not implement `Copy` for any `T`. + +Here's another example that will fail: + +```compile_fail,E0204 +#[derive(Copy)] +struct Foo<'a> { + ty: &'a mut bool, +} +``` + +This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this +differs from the behavior for `&T`, which is always `Copy`). +"##, + +/* +E0205: r##" +An attempt to implement the `Copy` trait for an enum failed because one of the +variants does not implement `Copy`. To fix this, you must implement `Copy` for +the mentioned variant. Note that this may not be possible, as in the example of + +```compile_fail,E0205 +enum Foo { + Bar(Vec), + Baz, +} + +impl Copy for Foo { } +``` + +This fails because `Vec` does not implement `Copy` for any `T`. + +Here's another example that will fail: + +```compile_fail,E0205 +#[derive(Copy)] +enum Foo<'a> { + Bar(&'a mut bool), + Baz, +} +``` + +This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this +differs from the behavior for `&T`, which is always `Copy`). +"##, +*/ + +E0206: r##" +You can only implement `Copy` for a struct or enum. Both of the following +examples will fail, because neither `[u8; 256]` nor `&'static mut Bar` +(mutable reference to `Bar`) is a struct or enum: + +```compile_fail,E0206 +type Foo = [u8; 256]; +impl Copy for Foo { } // error + +#[derive(Copy, Clone)] +struct Bar; +impl Copy for &'static mut Bar { } // error +``` +"##, + +E0207: r##" +Any type parameter or lifetime parameter of an `impl` must meet at least one of +the following criteria: + + - it appears in the _implementing type_ of the impl, e.g. `impl Foo` + - for a trait impl, it appears in the _implemented trait_, e.g. + `impl SomeTrait for Foo` + - it is bound as an associated type, e.g. `impl SomeTrait for T + where T: AnotherTrait` + +### Error example 1 + +Suppose we have a struct `Foo` and we would like to define some methods for it. +The following definition leads to a compiler error: + +```compile_fail,E0207 +struct Foo; + +impl Foo { +// error: the type parameter `T` is not constrained by the impl trait, self +// type, or predicates [E0207] + fn get(&self) -> T { + ::default() + } +} +``` + +The problem is that the parameter `T` does not appear in the implementing type +(`Foo`) of the impl. In this case, we can fix the error by moving the type +parameter from the `impl` to the method `get`: + + +``` +struct Foo; + +// Move the type parameter from the impl to the method +impl Foo { + fn get(&self) -> T { + ::default() + } +} +``` + +### Error example 2 + +As another example, suppose we have a `Maker` trait and want to establish a +type `FooMaker` that makes `Foo`s: + +```compile_fail,E0207 +trait Maker { + type Item; + fn make(&mut self) -> Self::Item; +} + +struct Foo { + foo: T +} + +struct FooMaker; + +impl Maker for FooMaker { +// error: the type parameter `T` is not constrained by the impl trait, self +// type, or predicates [E0207] + type Item = Foo; + + fn make(&mut self) -> Foo { + Foo { foo: ::default() } + } +} +``` + +This fails to compile because `T` does not appear in the trait or in the +implementing type. + +One way to work around this is to introduce a phantom type parameter into +`FooMaker`, like so: + +``` +use std::marker::PhantomData; + +trait Maker { + type Item; + fn make(&mut self) -> Self::Item; +} + +struct Foo { + foo: T +} + +// Add a type parameter to `FooMaker` +struct FooMaker { + phantom: PhantomData, +} + +impl Maker for FooMaker { + type Item = Foo; + + fn make(&mut self) -> Foo { + Foo { + foo: ::default(), + } + } +} +``` + +Another way is to do away with the associated type in `Maker` and use an input +type parameter instead: + +``` +// Use a type parameter instead of an associated type here +trait Maker { + fn make(&mut self) -> Item; +} + +struct Foo { + foo: T +} + +struct FooMaker; + +impl Maker> for FooMaker { + fn make(&mut self) -> Foo { + Foo { foo: ::default() } + } +} +``` + +### Additional information + +For more information, please see [RFC 447]. + +[RFC 447]: https://github.com/rust-lang/rfcs/blob/master/text/0447-no-unused-impl-parameters.md +"##, + +E0210: r##" +This error indicates a violation of one of Rust's orphan rules for trait +implementations. The rule concerns the use of type parameters in an +implementation of a foreign trait (a trait defined in another crate), and +states that type parameters must be "covered" by a local type. To understand +what this means, it is perhaps easiest to consider a few examples. + +If `ForeignTrait` is a trait defined in some external crate `foo`, then the +following trait `impl` is an error: + +```compile_fail,E0210 +# #[cfg(for_demonstration_only)] +extern crate foo; +# #[cfg(for_demonstration_only)] +use foo::ForeignTrait; +# use std::panic::UnwindSafe as ForeignTrait; + +impl ForeignTrait for T { } // error +# fn main() {} +``` + +To work around this, it can be covered with a local type, `MyType`: + +``` +# use std::panic::UnwindSafe as ForeignTrait; +struct MyType(T); +impl ForeignTrait for MyType { } // Ok +``` + +Please note that a type alias is not sufficient. + +For another example of an error, suppose there's another trait defined in `foo` +named `ForeignTrait2` that takes two type parameters. Then this `impl` results +in the same rule violation: + +```ignore (cannot-doctest-multicrate-project) +struct MyType2; +impl ForeignTrait2> for MyType2 { } // error +``` + +The reason for this is that there are two appearances of type parameter `T` in +the `impl` header, both as parameters for `ForeignTrait2`. The first appearance +is uncovered, and so runs afoul of the orphan rule. + +Consider one more example: + +```ignore (cannot-doctest-multicrate-project) +impl ForeignTrait2, T> for MyType2 { } // Ok +``` + +This only differs from the previous `impl` in that the parameters `T` and +`MyType` for `ForeignTrait2` have been swapped. This example does *not* +violate the orphan rule; it is permitted. + +To see why that last example was allowed, you need to understand the general +rule. Unfortunately this rule is a bit tricky to state. Consider an `impl`: + +```ignore (only-for-syntax-highlight) +impl ForeignTrait for T0 { ... } +``` + +where `P1, ..., Pm` are the type parameters of the `impl` and `T0, ..., Tn` +are types. One of the types `T0, ..., Tn` must be a local type (this is another +orphan rule, see the explanation for E0117). Let `i` be the smallest integer +such that `Ti` is a local type. Then no type parameter can appear in any of the +`Tj` for `j < i`. + +For information on the design of the orphan rules, see [RFC 1023]. + +[RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md +"##, + +/* +E0211: r##" +You used a function or type which doesn't fit the requirements for where it was +used. Erroneous code examples: + +```compile_fail +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn size_of(); // error: intrinsic has wrong type +} + +// or: + +fn main() -> i32 { 0 } +// error: main function expects type: `fn() {main}`: expected (), found i32 + +// or: + +let x = 1u8; +match x { + 0u8..=3i8 => (), + // error: mismatched types in range: expected u8, found i8 + _ => () +} + +// or: + +use std::rc::Rc; +struct Foo; + +impl Foo { + fn x(self: Rc) {} + // error: mismatched self type: expected `Foo`: expected struct + // `Foo`, found struct `alloc::rc::Rc` +} +``` + +For the first code example, please check the function definition. Example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn size_of() -> usize; // ok! +} +``` + +The second case example is a bit particular : the main function must always +have this definition: + +```compile_fail +fn main(); +``` + +They never take parameters and never return types. + +For the third example, when you match, all patterns must have the same type +as the type you're matching on. Example: + +``` +let x = 1u8; + +match x { + 0u8..=3u8 => (), // ok! + _ => () +} +``` + +And finally, for the last example, only `Box`, `&Self`, `Self`, +or `&mut Self` work as explicit self parameters. Example: + +``` +struct Foo; + +impl Foo { + fn x(self: Box) {} // ok! +} +``` +"##, + */ + +E0220: r##" +You used an associated type which isn't defined in the trait. +Erroneous code example: + +```compile_fail,E0220 +trait T1 { + type Bar; +} + +type Foo = T1; // error: associated type `F` not found for `T1` + +// or: + +trait T2 { + type Bar; + + // error: Baz is used but not declared + fn return_bool(&self, _: &Self::Bar, _: &Self::Baz) -> bool; +} +``` + +Make sure that you have defined the associated type in the trait body. +Also, verify that you used the right trait or you didn't misspell the +associated type name. Example: + +``` +trait T1 { + type Bar; +} + +type Foo = T1; // ok! + +// or: + +trait T2 { + type Bar; + type Baz; // we declare `Baz` in our trait. + + // and now we can use it here: + fn return_bool(&self, _: &Self::Bar, _: &Self::Baz) -> bool; +} +``` +"##, + +E0221: r##" +An attempt was made to retrieve an associated type, but the type was ambiguous. +For example: + +```compile_fail,E0221 +trait T1 {} +trait T2 {} + +trait Foo { + type A: T1; +} + +trait Bar : Foo { + type A: T2; + fn do_something() { + let _: Self::A; + } +} +``` + +In this example, `Foo` defines an associated type `A`. `Bar` inherits that type +from `Foo`, and defines another associated type of the same name. As a result, +when we attempt to use `Self::A`, it's ambiguous whether we mean the `A` defined +by `Foo` or the one defined by `Bar`. + +There are two options to work around this issue. The first is simply to rename +one of the types. Alternatively, one can specify the intended type using the +following syntax: + +``` +trait T1 {} +trait T2 {} + +trait Foo { + type A: T1; +} + +trait Bar : Foo { + type A: T2; + fn do_something() { + let _: ::A; + } +} +``` +"##, + +E0223: r##" +An attempt was made to retrieve an associated type, but the type was ambiguous. +For example: + +```compile_fail,E0223 +trait MyTrait {type X; } + +fn main() { + let foo: MyTrait::X; +} +``` + +The problem here is that we're attempting to take the type of X from MyTrait. +Unfortunately, the type of X is not defined, because it's only made concrete in +implementations of the trait. A working version of this code might look like: + +``` +trait MyTrait {type X; } +struct MyStruct; + +impl MyTrait for MyStruct { + type X = u32; +} + +fn main() { + let foo: ::X; +} +``` + +This syntax specifies that we want the X type from MyTrait, as made concrete in +MyStruct. The reason that we cannot simply use `MyStruct::X` is that MyStruct +might implement two different traits with identically-named associated types. +This syntax allows disambiguation between the two. +"##, + +E0225: r##" +You attempted to use multiple types as bounds for a closure or trait object. +Rust does not currently support this. A simple example that causes this error: + +```compile_fail,E0225 +fn main() { + let _: Box; +} +``` + +Auto traits such as Send and Sync are an exception to this rule: +It's possible to have bounds of one non-builtin trait, plus any number of +auto traits. For example, the following compiles correctly: + +``` +fn main() { + let _: Box; +} +``` +"##, + +E0229: r##" +An associated type binding was done outside of the type parameter declaration +and `where` clause. Erroneous code example: + +```compile_fail,E0229 +pub trait Foo { + type A; + fn boo(&self) -> ::A; +} + +struct Bar; + +impl Foo for isize { + type A = usize; + fn boo(&self) -> usize { 42 } +} + +fn baz(x: &>::A) {} +// error: associated type bindings are not allowed here +``` + +To solve this error, please move the type bindings in the type parameter +declaration: + +``` +# struct Bar; +# trait Foo { type A; } +fn baz>(x: &::A) {} // ok! +``` + +Or in the `where` clause: + +``` +# struct Bar; +# trait Foo { type A; } +fn baz(x: &::A) where I: Foo {} +``` +"##, + +E0243: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error indicates that not enough type parameters were found in a type or +trait. + +For example, the `Foo` struct below is defined to be generic in `T`, but the +type parameter is missing in the definition of `Bar`: + +```compile_fail,E0107 +struct Foo { x: T } + +struct Bar { x: Foo } +``` +"##, + +E0244: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error indicates that too many type parameters were found in a type or +trait. + +For example, the `Foo` struct below has no type parameters, but is supplied +with two in the definition of `Bar`: + +```compile_fail,E0107 +struct Foo { x: bool } + +struct Bar { x: Foo } +``` +"##, + +E0321: r##" +A cross-crate opt-out trait was implemented on something which wasn't a struct +or enum type. Erroneous code example: + +```compile_fail,E0321 +#![feature(optin_builtin_traits)] + +struct Foo; + +impl !Sync for Foo {} + +unsafe impl Send for &'static Foo {} +// error: cross-crate traits with a default impl, like `core::marker::Send`, +// can only be implemented for a struct/enum type, not +// `&'static Foo` +``` + +Only structs and enums are permitted to impl Send, Sync, and other opt-out +trait, and the struct or enum must be local to the current crate. So, for +example, `unsafe impl Send for Rc` is not allowed. +"##, + +E0322: r##" +The `Sized` trait is a special trait built-in to the compiler for types with a +constant size known at compile-time. This trait is automatically implemented +for types as needed by the compiler, and it is currently disallowed to +explicitly implement it for a type. +"##, + +E0323: r##" +An associated const was implemented when another trait item was expected. +Erroneous code example: + +```compile_fail,E0323 +trait Foo { + type N; +} + +struct Bar; + +impl Foo for Bar { + const N : u32 = 0; + // error: item `N` is an associated const, which doesn't match its + // trait `` +} +``` + +Please verify that the associated const wasn't misspelled and the correct trait +was implemented. Example: + +``` +struct Bar; + +trait Foo { + type N; +} + +impl Foo for Bar { + type N = u32; // ok! +} +``` + +Or: + +``` +struct Bar; + +trait Foo { + const N : u32; +} + +impl Foo for Bar { + const N : u32 = 0; // ok! +} +``` +"##, + +E0324: r##" +A method was implemented when another trait item was expected. Erroneous +code example: + +```compile_fail,E0324 +struct Bar; + +trait Foo { + const N : u32; + + fn M(); +} + +impl Foo for Bar { + fn N() {} + // error: item `N` is an associated method, which doesn't match its + // trait `` +} +``` + +To fix this error, please verify that the method name wasn't misspelled and +verify that you are indeed implementing the correct trait items. Example: + +``` +struct Bar; + +trait Foo { + const N : u32; + + fn M(); +} + +impl Foo for Bar { + const N : u32 = 0; + + fn M() {} // ok! +} +``` +"##, + +E0325: r##" +An associated type was implemented when another trait item was expected. +Erroneous code example: + +```compile_fail,E0325 +struct Bar; + +trait Foo { + const N : u32; +} + +impl Foo for Bar { + type N = u32; + // error: item `N` is an associated type, which doesn't match its + // trait `` +} +``` + +Please verify that the associated type name wasn't misspelled and your +implementation corresponds to the trait definition. Example: + +``` +struct Bar; + +trait Foo { + type N; +} + +impl Foo for Bar { + type N = u32; // ok! +} +``` + +Or: + +``` +struct Bar; + +trait Foo { + const N : u32; +} + +impl Foo for Bar { + const N : u32 = 0; // ok! +} +``` +"##, + +E0326: r##" +The types of any associated constants in a trait implementation must match the +types in the trait definition. This error indicates that there was a mismatch. + +Here's an example of this error: + +```compile_fail,E0326 +trait Foo { + const BAR: bool; +} + +struct Bar; + +impl Foo for Bar { + const BAR: u32 = 5; // error, expected bool, found u32 +} +``` +"##, + +E0328: r##" +The Unsize trait should not be implemented directly. All implementations of +Unsize are provided automatically by the compiler. + +Erroneous code example: + +```compile_fail,E0328 +#![feature(unsize)] + +use std::marker::Unsize; + +pub struct MyType; + +impl Unsize for MyType {} +``` + +If you are defining your own smart pointer type and would like to enable +conversion from a sized to an unsized type with the +[DST coercion system][RFC 982], use [`CoerceUnsized`] instead. + +``` +#![feature(coerce_unsized)] + +use std::ops::CoerceUnsized; + +pub struct MyType { + field_with_unsized_type: T, +} + +impl CoerceUnsized> for MyType + where T: CoerceUnsized {} +``` + +[RFC 982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md +[`CoerceUnsized`]: https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html +"##, + +/* +// Associated consts can now be accessed through generic type parameters, and +// this error is no longer emitted. +// +// FIXME: consider whether to leave it in the error index, or remove it entirely +// as associated consts is not stabilized yet. + +E0329: r##" +An attempt was made to access an associated constant through either a generic +type parameter or `Self`. This is not supported yet. An example causing this +error is shown below: + +``` +trait Foo { + const BAR: f64; +} + +struct MyStruct; + +impl Foo for MyStruct { + const BAR: f64 = 0f64; +} + +fn get_bar_bad(t: F) -> f64 { + F::BAR +} +``` + +Currently, the value of `BAR` for a particular type can only be accessed +through a concrete type, as shown below: + +``` +trait Foo { + const BAR: f64; +} + +struct MyStruct; + +fn get_bar_good() -> f64 { + ::BAR +} +``` +"##, +*/ + +E0366: r##" +An attempt was made to implement `Drop` on a concrete specialization of a +generic type. An example is shown below: + +```compile_fail,E0366 +struct Foo { + t: T +} + +impl Drop for Foo { + fn drop(&mut self) {} +} +``` + +This code is not legal: it is not possible to specialize `Drop` to a subset of +implementations of a generic type. One workaround for this is to wrap the +generic type, as shown below: + +``` +struct Foo { + t: T +} + +struct Bar { + t: Foo +} + +impl Drop for Bar { + fn drop(&mut self) {} +} +``` +"##, + +E0367: r##" +An attempt was made to implement `Drop` on a specialization of a generic type. +An example is shown below: + +```compile_fail,E0367 +trait Foo{} + +struct MyStruct { + t: T +} + +impl Drop for MyStruct { + fn drop(&mut self) {} +} +``` + +This code is not legal: it is not possible to specialize `Drop` to a subset of +implementations of a generic type. In order for this code to work, `MyStruct` +must also require that `T` implements `Foo`. Alternatively, another option is +to wrap the generic type in another that specializes appropriately: + +``` +trait Foo{} + +struct MyStruct { + t: T +} + +struct MyStructWrapper { + t: MyStruct +} + +impl Drop for MyStructWrapper { + fn drop(&mut self) {} +} +``` +"##, + +E0368: r##" +This error indicates that a binary assignment operator like `+=` or `^=` was +applied to a type that doesn't support it. For example: + +```compile_fail,E0368 +let mut x = 12f32; // error: binary operation `<<` cannot be applied to + // type `f32` + +x <<= 2; +``` + +To fix this error, please check that this type implements this binary +operation. Example: + +``` +let mut x = 12u32; // the `u32` type does implement the `ShlAssign` trait + +x <<= 2; // ok! +``` + +It is also possible to overload most operators for your own type by +implementing the `[OP]Assign` traits from `std::ops`. + +Another problem you might be facing is this: suppose you've overloaded the `+` +operator for some type `Foo` by implementing the `std::ops::Add` trait for +`Foo`, but you find that using `+=` does not work, as in this example: + +```compile_fail,E0368 +use std::ops::Add; + +struct Foo(u32); + +impl Add for Foo { + type Output = Foo; + + fn add(self, rhs: Foo) -> Foo { + Foo(self.0 + rhs.0) + } +} + +fn main() { + let mut x: Foo = Foo(5); + x += Foo(7); // error, `+= cannot be applied to the type `Foo` +} +``` + +This is because `AddAssign` is not automatically implemented, so you need to +manually implement it for your type. +"##, + +E0369: r##" +A binary operation was attempted on a type which doesn't support it. +Erroneous code example: + +```compile_fail,E0369 +let x = 12f32; // error: binary operation `<<` cannot be applied to + // type `f32` + +x << 2; +``` + +To fix this error, please check that this type implements this binary +operation. Example: + +``` +let x = 12u32; // the `u32` type does implement it: + // https://doc.rust-lang.org/stable/std/ops/trait.Shl.html + +x << 2; // ok! +``` + +It is also possible to overload most operators for your own type by +implementing traits from `std::ops`. + +String concatenation appends the string on the right to the string on the +left and may require reallocation. This requires ownership of the string +on the left. If something should be added to a string literal, move the +literal to the heap by allocating it with `to_owned()` like in +`"Your text".to_owned()`. + +"##, + +E0370: r##" +The maximum value of an enum was reached, so it cannot be automatically +set in the next enum value. Erroneous code example: + +```compile_fail,E0370 +#[repr(i64)] +enum Foo { + X = 0x7fffffffffffffff, + Y, // error: enum discriminant overflowed on value after + // 9223372036854775807: i64; set explicitly via + // Y = -9223372036854775808 if that is desired outcome +} +``` + +To fix this, please set manually the next enum value or put the enum variant +with the maximum value at the end of the enum. Examples: + +``` +#[repr(i64)] +enum Foo { + X = 0x7fffffffffffffff, + Y = 0, // ok! +} +``` + +Or: + +``` +#[repr(i64)] +enum Foo { + Y = 0, // ok! + X = 0x7fffffffffffffff, +} +``` +"##, + +E0371: r##" +When `Trait2` is a subtrait of `Trait1` (for example, when `Trait2` has a +definition like `trait Trait2: Trait1 { ... }`), it is not allowed to implement +`Trait1` for `Trait2`. This is because `Trait2` already implements `Trait1` by +definition, so it is not useful to do this. + +Example: + +```compile_fail,E0371 +trait Foo { fn foo(&self) { } } +trait Bar: Foo { } +trait Baz: Bar { } + +impl Bar for Baz { } // error, `Baz` implements `Bar` by definition +impl Foo for Baz { } // error, `Baz` implements `Bar` which implements `Foo` +impl Baz for Baz { } // error, `Baz` (trivially) implements `Baz` +impl Baz for Bar { } // Note: This is OK +``` +"##, + +E0374: r##" +A struct without a field containing an unsized type cannot implement +`CoerceUnsized`. An [unsized type][1] is any type that the compiler +doesn't know the length or alignment of at compile time. Any struct +containing an unsized type is also unsized. + +[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait + +Example of erroneous code: + +```compile_fail,E0374 +#![feature(coerce_unsized)] +use std::ops::CoerceUnsized; + +struct Foo { + a: i32, +} + +// error: Struct `Foo` has no unsized fields that need `CoerceUnsized`. +impl CoerceUnsized> for Foo + where T: CoerceUnsized {} +``` + +`CoerceUnsized` is used to coerce one struct containing an unsized type +into another struct containing a different unsized type. If the struct +doesn't have any fields of unsized types then you don't need explicit +coercion to get the types you want. To fix this you can either +not try to implement `CoerceUnsized` or you can add a field that is +unsized to the struct. + +Example: + +``` +#![feature(coerce_unsized)] +use std::ops::CoerceUnsized; + +// We don't need to impl `CoerceUnsized` here. +struct Foo { + a: i32, +} + +// We add the unsized type field to the struct. +struct Bar { + a: i32, + b: T, +} + +// The struct has an unsized field so we can implement +// `CoerceUnsized` for it. +impl CoerceUnsized> for Bar + where T: CoerceUnsized {} +``` + +Note that `CoerceUnsized` is mainly used by smart pointers like `Box`, `Rc` +and `Arc` to be able to mark that they can coerce unsized types that they +are pointing at. +"##, + +E0375: r##" +A struct with more than one field containing an unsized type cannot implement +`CoerceUnsized`. This only occurs when you are trying to coerce one of the +types in your struct to another type in the struct. In this case we try to +impl `CoerceUnsized` from `T` to `U` which are both types that the struct +takes. An [unsized type][1] is any type that the compiler doesn't know the +length or alignment of at compile time. Any struct containing an unsized type +is also unsized. + +Example of erroneous code: + +```compile_fail,E0375 +#![feature(coerce_unsized)] +use std::ops::CoerceUnsized; + +struct Foo { + a: i32, + b: T, + c: U, +} + +// error: Struct `Foo` has more than one unsized field. +impl CoerceUnsized> for Foo {} +``` + +`CoerceUnsized` only allows for coercion from a structure with a single +unsized type field to another struct with a single unsized type field. +In fact Rust only allows for a struct to have one unsized type in a struct +and that unsized type must be the last field in the struct. So having two +unsized types in a single struct is not allowed by the compiler. To fix this +use only one field containing an unsized type in the struct and then use +multiple structs to manage each unsized type field you need. + +Example: + +``` +#![feature(coerce_unsized)] +use std::ops::CoerceUnsized; + +struct Foo { + a: i32, + b: T, +} + +impl CoerceUnsized> for Foo + where T: CoerceUnsized {} + +fn coerce_foo, U>(t: T) -> Foo { + Foo { a: 12i32, b: t } // we use coercion to get the `Foo` type we need +} +``` + +[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait +"##, + +E0376: r##" +The type you are trying to impl `CoerceUnsized` for is not a struct. +`CoerceUnsized` can only be implemented for a struct. Unsized types are +already able to be coerced without an implementation of `CoerceUnsized` +whereas a struct containing an unsized type needs to know the unsized type +field it's containing is able to be coerced. An [unsized type][1] +is any type that the compiler doesn't know the length or alignment of at +compile time. Any struct containing an unsized type is also unsized. + +[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait + +Example of erroneous code: + +```compile_fail,E0376 +#![feature(coerce_unsized)] +use std::ops::CoerceUnsized; + +struct Foo { + a: T, +} + +// error: The type `U` is not a struct +impl CoerceUnsized for Foo {} +``` + +The `CoerceUnsized` trait takes a struct type. Make sure the type you are +providing to `CoerceUnsized` is a struct with only the last field containing an +unsized type. + +Example: + +``` +#![feature(coerce_unsized)] +use std::ops::CoerceUnsized; + +struct Foo { + a: T, +} + +// The `Foo` is a struct so `CoerceUnsized` can be implemented +impl CoerceUnsized> for Foo where T: CoerceUnsized {} +``` + +Note that in Rust, structs can only contain an unsized type if the field +containing the unsized type is the last and only unsized type field in the +struct. +"##, + +E0378: r##" +The `DispatchFromDyn` trait currently can only be implemented for +builtin pointer types and structs that are newtype wrappers around them +— that is, the struct must have only one field (except for`PhantomData`), +and that field must itself implement `DispatchFromDyn`. + +Examples: + +``` +#![feature(dispatch_from_dyn, unsize)] +use std::{ + marker::Unsize, + ops::DispatchFromDyn, +}; + +struct Ptr(*const T); + +impl DispatchFromDyn> for Ptr +where + T: Unsize, +{} +``` + +``` +#![feature(dispatch_from_dyn)] +use std::{ + ops::DispatchFromDyn, + marker::PhantomData, +}; + +struct Wrapper { + ptr: T, + _phantom: PhantomData<()>, +} + +impl DispatchFromDyn> for Wrapper +where + T: DispatchFromDyn, +{} +``` + +Example of illegal `DispatchFromDyn` implementation +(illegal because of extra field) + +```compile-fail,E0378 +#![feature(dispatch_from_dyn)] +use std::ops::DispatchFromDyn; + +struct WrapperExtraField { + ptr: T, + extra_stuff: i32, +} + +impl DispatchFromDyn> for WrapperExtraField +where + T: DispatchFromDyn, +{} +``` +"##, + +E0390: r##" +You tried to implement methods for a primitive type. Erroneous code example: + +```compile_fail,E0390 +struct Foo { + x: i32 +} + +impl *mut Foo {} +// error: only a single inherent implementation marked with +// `#[lang = "mut_ptr"]` is allowed for the `*mut T` primitive +``` + +This isn't allowed, but using a trait to implement a method is a good solution. +Example: + +``` +struct Foo { + x: i32 +} + +trait Bar { + fn bar(); +} + +impl Bar for *mut Foo { + fn bar() {} // ok! +} +``` +"##, + +E0392: r##" +This error indicates that a type or lifetime parameter has been declared +but not actually used. Here is an example that demonstrates the error: + +```compile_fail,E0392 +enum Foo { + Bar, +} +``` + +If the type parameter was included by mistake, this error can be fixed +by simply removing the type parameter, as shown below: + +``` +enum Foo { + Bar, +} +``` + +Alternatively, if the type parameter was intentionally inserted, it must be +used. A simple fix is shown below: + +``` +enum Foo { + Bar(T), +} +``` + +This error may also commonly be found when working with unsafe code. For +example, when using raw pointers one may wish to specify the lifetime for +which the pointed-at data is valid. An initial attempt (below) causes this +error: + +```compile_fail,E0392 +struct Foo<'a, T> { + x: *const T, +} +``` + +We want to express the constraint that Foo should not outlive `'a`, because +the data pointed to by `T` is only valid for that lifetime. The problem is +that there are no actual uses of `'a`. It's possible to work around this +by adding a PhantomData type to the struct, using it to tell the compiler +to act as if the struct contained a borrowed reference `&'a T`: + +``` +use std::marker::PhantomData; + +struct Foo<'a, T: 'a> { + x: *const T, + phantom: PhantomData<&'a T> +} +``` + +[PhantomData] can also be used to express information about unused type +parameters. + +[PhantomData]: https://doc.rust-lang.org/std/marker/struct.PhantomData.html +"##, + +E0393: r##" +A type parameter which references `Self` in its default value was not specified. +Example of erroneous code: + +```compile_fail,E0393 +trait A {} + +fn together_we_will_rule_the_galaxy(son: &A) {} +// error: the type parameter `T` must be explicitly specified in an +// object type because its default value `Self` references the +// type `Self` +``` + +A trait object is defined over a single, fully-defined trait. With a regular +default parameter, this parameter can just be substituted in. However, if the +default parameter is `Self`, the trait changes for each concrete type; i.e. +`i32` will be expected to implement `A`, `bool` will be expected to +implement `A`, etc... These types will not share an implementation of a +fully-defined trait; instead they share implementations of a trait with +different parameters substituted in for each implementation. This is +irreconcilable with what we need to make a trait object work, and is thus +disallowed. Making the trait concrete by explicitly specifying the value of the +defaulted parameter will fix this issue. Fixed example: + +``` +trait A {} + +fn together_we_will_rule_the_galaxy(son: &A) {} // Ok! +``` +"##, + +E0399: r##" +You implemented a trait, overriding one or more of its associated types but did +not reimplement its default methods. + +Example of erroneous code: + +```compile_fail,E0399 +#![feature(associated_type_defaults)] + +pub trait Foo { + type Assoc = u8; + fn bar(&self) {} +} + +impl Foo for i32 { + // error - the following trait items need to be reimplemented as + // `Assoc` was overridden: `bar` + type Assoc = i32; +} +``` + +To fix this, add an implementation for each default method from the trait: + +``` +#![feature(associated_type_defaults)] + +pub trait Foo { + type Assoc = u8; + fn bar(&self) {} +} + +impl Foo for i32 { + type Assoc = i32; + fn bar(&self) {} // ok! +} +``` +"##, + +E0436: r##" +The functional record update syntax is only allowed for structs. (Struct-like +enum variants don't qualify, for example.) + +Erroneous code example: + +```compile_fail,E0436 +enum PublicationFrequency { + Weekly, + SemiMonthly { days: (u8, u8), annual_special: bool }, +} + +fn one_up_competitor(competitor_frequency: PublicationFrequency) + -> PublicationFrequency { + match competitor_frequency { + PublicationFrequency::Weekly => PublicationFrequency::SemiMonthly { + days: (1, 15), annual_special: false + }, + c @ PublicationFrequency::SemiMonthly{ .. } => + PublicationFrequency::SemiMonthly { + annual_special: true, ..c // error: functional record update + // syntax requires a struct + } + } +} +``` + +Rewrite the expression without functional record update syntax: + +``` +enum PublicationFrequency { + Weekly, + SemiMonthly { days: (u8, u8), annual_special: bool }, +} + +fn one_up_competitor(competitor_frequency: PublicationFrequency) + -> PublicationFrequency { + match competitor_frequency { + PublicationFrequency::Weekly => PublicationFrequency::SemiMonthly { + days: (1, 15), annual_special: false + }, + PublicationFrequency::SemiMonthly{ days, .. } => + PublicationFrequency::SemiMonthly { + days, annual_special: true // ok! + } + } +} +``` +"##, + +E0439: r##" +The length of the platform-intrinsic function `simd_shuffle` +wasn't specified. Erroneous code example: + +```compile_fail,E0439 +#![feature(platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_shuffle(a: A, b: A, c: [u32; 8]) -> B; + // error: invalid `simd_shuffle`, needs length: `simd_shuffle` +} +``` + +The `simd_shuffle` function needs the length of the array passed as +last parameter in its name. Example: + +``` +#![feature(platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_shuffle8(a: A, b: A, c: [u32; 8]) -> B; +} +``` +"##, + +E0516: r##" +The `typeof` keyword is currently reserved but unimplemented. +Erroneous code example: + +```compile_fail,E0516 +fn main() { + let x: typeof(92) = 92; +} +``` + +Try using type inference instead. Example: + +``` +fn main() { + let x = 92; +} +``` +"##, + +E0520: r##" +A non-default implementation was already made on this type so it cannot be +specialized further. Erroneous code example: + +```compile_fail,E0520 +#![feature(specialization)] + +trait SpaceLlama { + fn fly(&self); +} + +// applies to all T +impl SpaceLlama for T { + default fn fly(&self) {} +} + +// non-default impl +// applies to all `Clone` T and overrides the previous impl +impl SpaceLlama for T { + fn fly(&self) {} +} + +// since `i32` is clone, this conflicts with the previous implementation +impl SpaceLlama for i32 { + default fn fly(&self) {} + // error: item `fly` is provided by an `impl` that specializes + // another, but the item in the parent `impl` is not marked + // `default` and so it cannot be specialized. +} +``` + +Specialization only allows you to override `default` functions in +implementations. + +To fix this error, you need to mark all the parent implementations as default. +Example: + +``` +#![feature(specialization)] + +trait SpaceLlama { + fn fly(&self); +} + +// applies to all T +impl SpaceLlama for T { + default fn fly(&self) {} // This is a parent implementation. +} + +// applies to all `Clone` T; overrides the previous impl +impl SpaceLlama for T { + default fn fly(&self) {} // This is a parent implementation but was + // previously not a default one, causing the error +} + +// applies to i32, overrides the previous two impls +impl SpaceLlama for i32 { + fn fly(&self) {} // And now that's ok! +} +``` +"##, + +E0527: r##" +The number of elements in an array or slice pattern differed from the number of +elements in the array being matched. + +Example of erroneous code: + +```compile_fail,E0527 +let r = &[1, 2, 3, 4]; +match r { + &[a, b] => { // error: pattern requires 2 elements but array + // has 4 + println!("a={}, b={}", a, b); + } +} +``` + +Ensure that the pattern is consistent with the size of the matched +array. Additional elements can be matched with `..`: + +``` +#![feature(slice_patterns)] + +let r = &[1, 2, 3, 4]; +match r { + &[a, b, ..] => { // ok! + println!("a={}, b={}", a, b); + } +} +``` +"##, + +E0528: r##" +An array or slice pattern required more elements than were present in the +matched array. + +Example of erroneous code: + +```compile_fail,E0528 +#![feature(slice_patterns)] + +let r = &[1, 2]; +match r { + &[a, b, c, rest..] => { // error: pattern requires at least 3 + // elements but array has 2 + println!("a={}, b={}, c={} rest={:?}", a, b, c, rest); + } +} +``` + +Ensure that the matched array has at least as many elements as the pattern +requires. You can match an arbitrary number of remaining elements with `..`: + +``` +#![feature(slice_patterns)] + +let r = &[1, 2, 3, 4, 5]; +match r { + &[a, b, c, rest..] => { // ok! + // prints `a=1, b=2, c=3 rest=[4, 5]` + println!("a={}, b={}, c={} rest={:?}", a, b, c, rest); + } +} +``` +"##, + +E0529: r##" +An array or slice pattern was matched against some other type. + +Example of erroneous code: + +```compile_fail,E0529 +let r: f32 = 1.0; +match r { + [a, b] => { // error: expected an array or slice, found `f32` + println!("a={}, b={}", a, b); + } +} +``` + +Ensure that the pattern and the expression being matched on are of consistent +types: + +``` +let r = [1.0, 2.0]; +match r { + [a, b] => { // ok! + println!("a={}, b={}", a, b); + } +} +``` +"##, + +E0534: r##" +The `inline` attribute was malformed. + +Erroneous code example: + +```ignore (compile_fail not working here; see Issue #43707) +#[inline()] // error: expected one argument +pub fn something() {} + +fn main() {} +``` + +The parenthesized `inline` attribute requires the parameter to be specified: + +``` +#[inline(always)] +fn something() {} +``` + +or: + +``` +#[inline(never)] +fn something() {} +``` + +Alternatively, a paren-less version of the attribute may be used to hint the +compiler about inlining opportunity: + +``` +#[inline] +fn something() {} +``` + +For more information about the inline attribute, read: +https://doc.rust-lang.org/reference.html#inline-attributes +"##, + +E0535: r##" +An unknown argument was given to the `inline` attribute. + +Erroneous code example: + +```ignore (compile_fail not working here; see Issue #43707) +#[inline(unknown)] // error: invalid argument +pub fn something() {} + +fn main() {} +``` + +The `inline` attribute only supports two arguments: + + * always + * never + +All other arguments given to the `inline` attribute will return this error. +Example: + +``` +#[inline(never)] // ok! +pub fn something() {} + +fn main() {} +``` + +For more information about the inline attribute, https: +read://doc.rust-lang.org/reference.html#inline-attributes +"##, + +E0559: r##" +An unknown field was specified into an enum's structure variant. + +Erroneous code example: + +```compile_fail,E0559 +enum Field { + Fool { x: u32 }, +} + +let s = Field::Fool { joke: 0 }; +// error: struct variant `Field::Fool` has no field named `joke` +``` + +Verify you didn't misspell the field's name or that the field exists. Example: + +``` +enum Field { + Fool { joke: u32 }, +} + +let s = Field::Fool { joke: 0 }; // ok! +``` +"##, + +E0560: r##" +An unknown field was specified into a structure. + +Erroneous code example: + +```compile_fail,E0560 +struct Simba { + mother: u32, +} + +let s = Simba { mother: 1, father: 0 }; +// error: structure `Simba` has no field named `father` +``` + +Verify you didn't misspell the field's name or that the field exists. Example: + +``` +struct Simba { + mother: u32, + father: u32, +} + +let s = Simba { mother: 1, father: 0 }; // ok! +``` +"##, + +E0569: r##" +If an impl has a generic parameter with the `#[may_dangle]` attribute, then +that impl must be declared as an `unsafe impl. + +Erroneous code example: + +```compile_fail,E0569 +#![feature(dropck_eyepatch)] + +struct Foo(X); +impl<#[may_dangle] X> Drop for Foo { + fn drop(&mut self) { } +} +``` + +In this example, we are asserting that the destructor for `Foo` will not +access any data of type `X`, and require this assertion to be true for +overall safety in our program. The compiler does not currently attempt to +verify this assertion; therefore we must tag this `impl` as unsafe. +"##, + +E0570: r##" +The requested ABI is unsupported by the current target. + +The rust compiler maintains for each target a blacklist of ABIs unsupported on +that target. If an ABI is present in such a list this usually means that the +target / ABI combination is currently unsupported by llvm. + +If necessary, you can circumvent this check using custom target specifications. +"##, + +E0572: r##" +A return statement was found outside of a function body. + +Erroneous code example: + +```compile_fail,E0572 +const FOO: u32 = return 0; // error: return statement outside of function body + +fn main() {} +``` + +To fix this issue, just remove the return keyword or move the expression into a +function. Example: + +``` +const FOO: u32 = 0; + +fn some_fn() -> u32 { + return FOO; +} + +fn main() { + some_fn(); +} +``` +"##, + +E0581: r##" +In a `fn` type, a lifetime appears only in the return type, +and not in the arguments types. + +Erroneous code example: + +```compile_fail,E0581 +fn main() { + // Here, `'a` appears only in the return type: + let x: for<'a> fn() -> &'a i32; +} +``` + +To fix this issue, either use the lifetime in the arguments, or use +`'static`. Example: + +``` +fn main() { + // Here, `'a` appears only in the return type: + let x: for<'a> fn(&'a i32) -> &'a i32; + let y: fn() -> &'static i32; +} +``` + +Note: The examples above used to be (erroneously) accepted by the +compiler, but this was since corrected. See [issue #33685] for more +details. + +[issue #33685]: https://github.com/rust-lang/rust/issues/33685 +"##, + +E0582: r##" +A lifetime appears only in an associated-type binding, +and not in the input types to the trait. + +Erroneous code example: + +```compile_fail,E0582 +fn bar(t: F) + // No type can satisfy this requirement, since `'a` does not + // appear in any of the input types (here, `i32`): + where F: for<'a> Fn(i32) -> Option<&'a i32> +{ +} + +fn main() { } +``` + +To fix this issue, either use the lifetime in the inputs, or use +`'static`. Example: + +``` +fn bar(t: F, u: G) + where F: for<'a> Fn(&'a i32) -> Option<&'a i32>, + G: Fn(i32) -> Option<&'static i32>, +{ +} + +fn main() { } +``` + +Note: The examples above used to be (erroneously) accepted by the +compiler, but this was since corrected. See [issue #33685] for more +details. + +[issue #33685]: https://github.com/rust-lang/rust/issues/33685 +"##, + +E0592: r##" +This error occurs when you defined methods or associated functions with same +name. + +Erroneous code example: + +```compile_fail,E0592 +struct Foo; + +impl Foo { + fn bar() {} // previous definition here +} + +impl Foo { + fn bar() {} // duplicate definition here +} +``` + +A similar error is E0201. The difference is whether there is one declaration +block or not. To avoid this error, you must give each `fn` a unique name. + +``` +struct Foo; + +impl Foo { + fn bar() {} +} + +impl Foo { + fn baz() {} // define with different name +} +``` +"##, + +E0599: r##" +This error occurs when a method is used on a type which doesn't implement it: + +Erroneous code example: + +```compile_fail,E0599 +struct Mouth; + +let x = Mouth; +x.chocolate(); // error: no method named `chocolate` found for type `Mouth` + // in the current scope +``` +"##, + +E0600: r##" +An unary operator was used on a type which doesn't implement it. + +Example of erroneous code: + +```compile_fail,E0600 +enum Question { + Yes, + No, +} + +!Question::Yes; // error: cannot apply unary operator `!` to type `Question` +``` + +In this case, `Question` would need to implement the `std::ops::Not` trait in +order to be able to use `!` on it. Let's implement it: + +``` +use std::ops::Not; + +enum Question { + Yes, + No, +} + +// We implement the `Not` trait on the enum. +impl Not for Question { + type Output = bool; + + fn not(self) -> bool { + match self { + Question::Yes => false, // If the `Answer` is `Yes`, then it + // returns false. + Question::No => true, // And here we do the opposite. + } + } +} + +assert_eq!(!Question::Yes, false); +assert_eq!(!Question::No, true); +``` +"##, + +E0608: r##" +An attempt to index into a type which doesn't implement the `std::ops::Index` +trait was performed. + +Erroneous code example: + +```compile_fail,E0608 +0u8[2]; // error: cannot index into a value of type `u8` +``` + +To be able to index into a type it needs to implement the `std::ops::Index` +trait. Example: + +``` +let v: Vec = vec![0, 1, 2, 3]; + +// The `Vec` type implements the `Index` trait so you can do: +println!("{}", v[2]); +``` +"##, + +E0604: r##" +A cast to `char` was attempted on a type other than `u8`. + +Erroneous code example: + +```compile_fail,E0604 +0u32 as char; // error: only `u8` can be cast as `char`, not `u32` +``` + +As the error message indicates, only `u8` can be cast into `char`. Example: + +``` +let c = 86u8 as char; // ok! +assert_eq!(c, 'V'); +``` + +For more information about casts, take a look at the Type cast section in +[The Reference Book][1]. + +[1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions +"##, + +E0605: r##" +An invalid cast was attempted. + +Erroneous code examples: + +```compile_fail,E0605 +let x = 0u8; +x as Vec; // error: non-primitive cast: `u8` as `std::vec::Vec` + +// Another example + +let v = core::ptr::null::(); // So here, `v` is a `*const u8`. +v as &u8; // error: non-primitive cast: `*const u8` as `&u8` +``` + +Only primitive types can be cast into each other. Examples: + +``` +let x = 0u8; +x as u32; // ok! + +let v = core::ptr::null::(); +v as *const i8; // ok! +``` + +For more information about casts, take a look at the Type cast section in +[The Reference Book][1]. + +[1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions +"##, + +E0606: r##" +An incompatible cast was attempted. + +Erroneous code example: + +```compile_fail,E0606 +let x = &0u8; // Here, `x` is a `&u8`. +let y: u32 = x as u32; // error: casting `&u8` as `u32` is invalid +``` + +When casting, keep in mind that only primitive types can be cast into each +other. Example: + +``` +let x = &0u8; +let y: u32 = *x as u32; // We dereference it first and then cast it. +``` + +For more information about casts, take a look at the Type cast section in +[The Reference Book][1]. + +[1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions +"##, + +E0607: r##" +A cast between a thin and a fat pointer was attempted. + +Erroneous code example: + +```compile_fail,E0607 +let v = core::ptr::null::(); +v as *const [u8]; +``` + +First: what are thin and fat pointers? + +Thin pointers are "simple" pointers: they are purely a reference to a memory +address. + +Fat pointers are pointers referencing Dynamically Sized Types (also called DST). +DST don't have a statically known size, therefore they can only exist behind +some kind of pointers that contain additional information. Slices and trait +objects are DSTs. In the case of slices, the additional information the fat +pointer holds is their size. + +To fix this error, don't try to cast directly between thin and fat pointers. + +For more information about casts, take a look at the Type cast section in +[The Reference Book][1]. + +[1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions +"##, + +E0609: r##" +Attempted to access a non-existent field in a struct. + +Erroneous code example: + +```compile_fail,E0609 +struct StructWithFields { + x: u32, +} + +let s = StructWithFields { x: 0 }; +println!("{}", s.foo); // error: no field `foo` on type `StructWithFields` +``` + +To fix this error, check that you didn't misspell the field's name or that the +field actually exists. Example: + +``` +struct StructWithFields { + x: u32, +} + +let s = StructWithFields { x: 0 }; +println!("{}", s.x); // ok! +``` +"##, + +E0610: r##" +Attempted to access a field on a primitive type. + +Erroneous code example: + +```compile_fail,E0610 +let x: u32 = 0; +println!("{}", x.foo); // error: `{integer}` is a primitive type, therefore + // doesn't have fields +``` + +Primitive types are the most basic types available in Rust and don't have +fields. To access data via named fields, struct types are used. Example: + +``` +// We declare struct called `Foo` containing two fields: +struct Foo { + x: u32, + y: i64, +} + +// We create an instance of this struct: +let variable = Foo { x: 0, y: -12 }; +// And we can now access its fields: +println!("x: {}, y: {}", variable.x, variable.y); +``` + +For more information about primitives and structs, take a look at The Book: +https://doc.rust-lang.org/book/ch03-02-data-types.html +https://doc.rust-lang.org/book/ch05-00-structs.html +"##, + +E0614: r##" +Attempted to dereference a variable which cannot be dereferenced. + +Erroneous code example: + +```compile_fail,E0614 +let y = 0u32; +*y; // error: type `u32` cannot be dereferenced +``` + +Only types implementing `std::ops::Deref` can be dereferenced (such as `&T`). +Example: + +``` +let y = 0u32; +let x = &y; +// So here, `x` is a `&u32`, so we can dereference it: +*x; // ok! +``` +"##, + +E0615: r##" +Attempted to access a method like a field. + +Erroneous code example: + +```compile_fail,E0615 +struct Foo { + x: u32, +} + +impl Foo { + fn method(&self) {} +} + +let f = Foo { x: 0 }; +f.method; // error: attempted to take value of method `method` on type `Foo` +``` + +If you want to use a method, add `()` after it: + +``` +# struct Foo { x: u32 } +# impl Foo { fn method(&self) {} } +# let f = Foo { x: 0 }; +f.method(); +``` + +However, if you wanted to access a field of a struct check that the field name +is spelled correctly. Example: + +``` +# struct Foo { x: u32 } +# impl Foo { fn method(&self) {} } +# let f = Foo { x: 0 }; +println!("{}", f.x); +``` +"##, + +E0616: r##" +Attempted to access a private field on a struct. + +Erroneous code example: + +```compile_fail,E0616 +mod some_module { + pub struct Foo { + x: u32, // So `x` is private in here. + } + + impl Foo { + pub fn new() -> Foo { Foo { x: 0 } } + } +} + +let f = some_module::Foo::new(); +println!("{}", f.x); // error: field `x` of struct `some_module::Foo` is private +``` + +If you want to access this field, you have two options: + +1) Set the field public: + +``` +mod some_module { + pub struct Foo { + pub x: u32, // `x` is now public. + } + + impl Foo { + pub fn new() -> Foo { Foo { x: 0 } } + } +} + +let f = some_module::Foo::new(); +println!("{}", f.x); // ok! +``` + +2) Add a getter function: + +``` +mod some_module { + pub struct Foo { + x: u32, // So `x` is still private in here. + } + + impl Foo { + pub fn new() -> Foo { Foo { x: 0 } } + + // We create the getter function here: + pub fn get_x(&self) -> &u32 { &self.x } + } +} + +let f = some_module::Foo::new(); +println!("{}", f.get_x()); // ok! +``` +"##, + +E0617: r##" +Attempted to pass an invalid type of variable into a variadic function. + +Erroneous code example: + +```compile_fail,E0617 +extern { + fn printf(c: *const i8, ...); +} + +unsafe { + printf(::std::ptr::null(), 0f32); + // error: can't pass an `f32` to variadic function, cast to `c_double` +} +``` + +Certain Rust types must be cast before passing them to a variadic function, +because of arcane ABI rules dictated by the C standard. To fix the error, +cast the value to the type specified by the error message (which you may need +to import from `std::os::raw`). +"##, + +E0618: r##" +Attempted to call something which isn't a function nor a method. + +Erroneous code examples: + +```compile_fail,E0618 +enum X { + Entry, +} + +X::Entry(); // error: expected function, found `X::Entry` + +// Or even simpler: +let x = 0i32; +x(); // error: expected function, found `i32` +``` + +Only functions and methods can be called using `()`. Example: + +``` +// We declare a function: +fn i_am_a_function() {} + +// And we call it: +i_am_a_function(); +``` +"##, + +E0619: r##" +#### Note: this error code is no longer emitted by the compiler. +The type-checker needed to know the type of an expression, but that type had not +yet been inferred. + +Erroneous code example: + +```compile_fail +let mut x = vec![]; +match x.pop() { + Some(v) => { + // Here, the type of `v` is not (yet) known, so we + // cannot resolve this method call: + v.to_uppercase(); // error: the type of this value must be known in + // this context + } + None => {} +} +``` + +Type inference typically proceeds from the top of the function to the bottom, +figuring out types as it goes. In some cases -- notably method calls and +overloadable operators like `*` -- the type checker may not have enough +information *yet* to make progress. This can be true even if the rest of the +function provides enough context (because the type-checker hasn't looked that +far ahead yet). In this case, type annotations can be used to help it along. + +To fix this error, just specify the type of the variable. Example: + +``` +let mut x: Vec = vec![]; // We precise the type of the vec elements. +match x.pop() { + Some(v) => { + v.to_uppercase(); // Since rustc now knows the type of the vec elements, + // we can use `v`'s methods. + } + None => {} +} +``` +"##, + +E0620: r##" +A cast to an unsized type was attempted. + +Erroneous code example: + +```compile_fail,E0620 +let x = &[1_usize, 2] as [usize]; // error: cast to unsized type: `&[usize; 2]` + // as `[usize]` +``` + +In Rust, some types don't have a known size at compile-time. For example, in a +slice type like `[u32]`, the number of elements is not known at compile-time and +hence the overall size cannot be computed. As a result, such types can only be +manipulated through a reference (e.g., `&T` or `&mut T`) or other pointer-type +(e.g., `Box` or `Rc`). Try casting to a reference instead: + +``` +let x = &[1_usize, 2] as &[usize]; // ok! +``` +"##, + +E0622: r##" +An intrinsic was declared without being a function. + +Erroneous code example: + +```compile_fail,E0622 +#![feature(intrinsics)] +extern "rust-intrinsic" { + pub static breakpoint : unsafe extern "rust-intrinsic" fn(); + // error: intrinsic must be a function +} + +fn main() { unsafe { breakpoint(); } } +``` + +An intrinsic is a function available for use in a given programming language +whose implementation is handled specially by the compiler. In order to fix this +error, just declare a function. +"##, + +E0624: r##" +A private item was used outside of its scope. + +Erroneous code example: + +```compile_fail,E0624 +mod inner { + pub struct Foo; + + impl Foo { + fn method(&self) {} + } +} + +let foo = inner::Foo; +foo.method(); // error: method `method` is private +``` + +Two possibilities are available to solve this issue: + +1. Only use the item in the scope it has been defined: + +``` +mod inner { + pub struct Foo; + + impl Foo { + fn method(&self) {} + } + + pub fn call_method(foo: &Foo) { // We create a public function. + foo.method(); // Which calls the item. + } +} + +let foo = inner::Foo; +inner::call_method(&foo); // And since the function is public, we can call the + // method through it. +``` + +2. Make the item public: + +``` +mod inner { + pub struct Foo; + + impl Foo { + pub fn method(&self) {} // It's now public. + } +} + +let foo = inner::Foo; +foo.method(); // Ok! +``` +"##, + +E0638: r##" +This error indicates that the struct, enum or enum variant must be matched +non-exhaustively as it has been marked as `non_exhaustive`. + +When applied within a crate, downstream users of the crate will need to use the +`_` pattern when matching enums and use the `..` pattern when matching structs. +Downstream crates cannot match against non-exhaustive enum variants. + +For example, in the below example, since the enum is marked as +`non_exhaustive`, it is required that downstream crates match non-exhaustively +on it. + +```rust,ignore (pseudo-Rust) +use std::error::Error as StdError; + +#[non_exhaustive] pub enum Error { + Message(String), + Other, +} + +impl StdError for Error { + fn description(&self) -> &str { + // This will not error, despite being marked as non_exhaustive, as this + // enum is defined within the current crate, it can be matched + // exhaustively. + match *self { + Message(ref s) => s, + Other => "other or unknown error", + } + } +} +``` + +An example of matching non-exhaustively on the above enum is provided below: + +```rust,ignore (pseudo-Rust) +use mycrate::Error; + +// This will not error as the non_exhaustive Error enum has been matched with a +// wildcard. +match error { + Message(ref s) => ..., + Other => ..., + _ => ..., +} +``` + +Similarly, for structs, match with `..` to avoid this error. +"##, + +E0639: r##" +This error indicates that the struct, enum or enum variant cannot be +instantiated from outside of the defining crate as it has been marked +as `non_exhaustive` and as such more fields/variants may be added in +future that could cause adverse side effects for this code. + +It is recommended that you look for a `new` function or equivalent in the +crate's documentation. +"##, + +E0643: r##" +This error indicates that there is a mismatch between generic parameters and +impl Trait parameters in a trait declaration versus its impl. + +```compile_fail,E0643 +trait Foo { + fn foo(&self, _: &impl Iterator); +} +impl Foo for () { + fn foo(&self, _: &U) { } // error method `foo` has incompatible + // signature for trait +} +``` +"##, + +E0646: r##" +It is not possible to define `main` with a where clause. +Erroneous code example: + +```compile_fail,E0646 +fn main() where i32: Copy { // error: main function is not allowed to have + // a where clause +} +``` +"##, + +E0647: r##" +It is not possible to define `start` with a where clause. +Erroneous code example: + +```compile_fail,E0647 +#![feature(start)] + +#[start] +fn start(_: isize, _: *const *const u8) -> isize where (): Copy { + //^ error: start function is not allowed to have a where clause + 0 +} +``` +"##, + +E0648: r##" +`export_name` attributes may not contain null characters (`\0`). + +```compile_fail,E0648 +#[export_name="\0foo"] // error: `export_name` may not contain null characters +pub fn bar() {} +``` +"##, + +E0689: r##" +This error indicates that the numeric value for the method being passed exists +but the type of the numeric value or binding could not be identified. + +The error happens on numeric literals: + +```compile_fail,E0689 +2.0.neg(); +``` + +and on numeric bindings without an identified concrete type: + +```compile_fail,E0689 +let x = 2.0; +x.neg(); // same error as above +``` + +Because of this, you must give the numeric literal or binding a type: + +``` +use std::ops::Neg; + +let _ = 2.0_f32.neg(); +let x: f32 = 2.0; +let _ = x.neg(); +let _ = (2.0 as f32).neg(); +``` +"##, + +E0690: r##" +A struct with the representation hint `repr(transparent)` had zero or more than +one fields that were not guaranteed to be zero-sized. + +Erroneous code example: + +```compile_fail,E0690 +#[repr(transparent)] +struct LengthWithUnit { // error: transparent struct needs exactly one + value: f32, // non-zero-sized field, but has 2 + unit: U, +} +``` + +Because transparent structs are represented exactly like one of their fields at +run time, said field must be uniquely determined. If there is no field, or if +there are multiple fields, it is not clear how the struct should be represented. +Note that fields of zero-typed types (e.g., `PhantomData`) can also exist +alongside the field that contains the actual data, they do not count for this +error. When generic types are involved (as in the above example), an error is +reported because the type parameter could be non-zero-sized. + +To combine `repr(transparent)` with type parameters, `PhantomData` may be +useful: + +``` +use std::marker::PhantomData; + +#[repr(transparent)] +struct LengthWithUnit { + value: f32, + unit: PhantomData, +} +``` +"##, + +E0691: r##" +A struct, enum, or union with the `repr(transparent)` representation hint +contains a zero-sized field that requires non-trivial alignment. + +Erroneous code example: + +```compile_fail,E0691 +#![feature(repr_align)] + +#[repr(align(32))] +struct ForceAlign32; + +#[repr(transparent)] +struct Wrapper(f32, ForceAlign32); // error: zero-sized field in transparent + // struct has alignment larger than 1 +``` + +A transparent struct, enum, or union is supposed to be represented exactly like +the piece of data it contains. Zero-sized fields with different alignment +requirements potentially conflict with this property. In the example above, +`Wrapper` would have to be aligned to 32 bytes even though `f32` has a smaller +alignment requirement. + +Consider removing the over-aligned zero-sized field: + +``` +#[repr(transparent)] +struct Wrapper(f32); +``` + +Alternatively, `PhantomData` has alignment 1 for all `T`, so you can use it +if you need to keep the field for some reason: + +``` +#![feature(repr_align)] + +use std::marker::PhantomData; + +#[repr(align(32))] +struct ForceAlign32; + +#[repr(transparent)] +struct Wrapper(f32, PhantomData); +``` + +Note that empty arrays `[T; 0]` have the same alignment requirement as the +element type `T`. Also note that the error is conservatively reported even when +the alignment of the zero-sized type is less than or equal to the data field's +alignment. +"##, + +E0699: r##" +A method was called on a raw pointer whose inner type wasn't completely known. + +For example, you may have done something like: + +```compile_fail +# #![deny(warnings)] +let foo = &1; +let bar = foo as *const _; +if bar.is_null() { + // ... +} +``` + +Here, the type of `bar` isn't known; it could be a pointer to anything. Instead, +specify a type for the pointer (preferably something that makes sense for the +thing you're pointing to): + +``` +let foo = &1; +let bar = foo as *const i32; +if bar.is_null() { + // ... +} +``` + +Even though `is_null()` exists as a method on any raw pointer, Rust shows this +error because Rust allows for `self` to have arbitrary types (behind the +arbitrary_self_types feature flag). + +This means that someone can specify such a function: + +```ignore (cannot-doctest-feature-doesnt-exist-yet) +impl Foo { + fn is_null(self: *const Self) -> bool { + // do something else + } +} +``` + +and now when you call `.is_null()` on a raw pointer to `Foo`, there's ambiguity. + +Given that we don't know what type the pointer is, and there's potential +ambiguity for some types, we disallow calling methods on raw pointers when +the type is unknown. +"##, + +E0714: r##" +A `#[marker]` trait contained an associated item. + +The items of marker traits cannot be overridden, so there's no need to have them +when they cannot be changed per-type anyway. If you wanted them for ergonomic +reasons, consider making an extension trait instead. +"##, + +E0715: r##" +An `impl` for a `#[marker]` trait tried to override an associated item. + +Because marker traits are allowed to have multiple implementations for the same +type, it's not allowed to override anything in those implementations, as it +would be ambiguous which override should actually be used. +"##, + + +E0720: r##" +An `impl Trait` type expands to a recursive type. + +An `impl Trait` type must be expandable to a concrete type that contains no +`impl Trait` types. For example the following example tries to create an +`impl Trait` type `T` that is equal to `[T, T]`: + +```compile_fail,E0720 +fn make_recursive_type() -> impl Sized { + [make_recursive_type(), make_recursive_type()] +} +``` +"##, + +E0730: r##" +An array without a fixed length was pattern-matched. + +Example of erroneous code: + +```compile_fail,E0730 +#![feature(const_generics)] + +fn is_123(x: [u32; N]) -> bool { + match x { + [1, 2, 3] => true, // error: cannot pattern-match on an + // array without a fixed length + _ => false + } +} +``` + +Ensure that the pattern is consistent with the size of the matched +array. Additional elements can be matched with `..`: + +``` +#![feature(slice_patterns)] + +let r = &[1, 2, 3, 4]; +match r { + &[a, b, ..] => { // ok! + println!("a={}, b={}", a, b); + } +} +``` +"##, + +E0731: r##" +An enum with the representation hint `repr(transparent)` had zero or more than +one variants. + +Erroneous code example: + +```compile_fail,E0731 +#[repr(transparent)] +enum Status { // error: transparent enum needs exactly one variant, but has 2 + Errno(u32), + Ok, +} +``` + +Because transparent enums are represented exactly like one of their variants at +run time, said variant must be uniquely determined. If there is no variant, or +if there are multiple variants, it is not clear how the enum should be +represented. +"##, + +E0732: r##" +An `enum` with a discriminant must specify a `#[repr(inttype)]`. + +A `#[repr(inttype)]` must be provided on an `enum` if it has a non-unit +variant with a discriminant, or where there are both unit variants with +discriminants and non-unit variants. This restriction ensures that there +is a well-defined way to extract a variant's discriminant from a value; +for instance: + +``` +#![feature(arbitrary_enum_discriminant)] + +#[repr(u8)] +enum Enum { + Unit = 3, + Tuple(u16) = 2, + Struct { + a: u8, + b: u16, + } = 1, +} + +fn discriminant(v : &Enum) -> u8 { + unsafe { *(v as *const Enum as *const u8) } +} + +assert_eq!(3, discriminant(&Enum::Unit)); +assert_eq!(2, discriminant(&Enum::Tuple(5))); +assert_eq!(1, discriminant(&Enum::Struct{a: 7, b: 11})); +``` +"##, + +} + +register_diagnostics! { +// E0035, merged into E0087/E0089 +// E0036, merged into E0087/E0089 +// E0068, +// E0085, +// E0086, +// E0103, +// E0104, +// E0122, // bounds in type aliases are ignored, turned into proper lint +// E0123, +// E0127, +// E0129, +// E0141, +// E0159, // use of trait `{}` as struct constructor +// E0163, // merged into E0071 +// E0167, +// E0168, +// E0172, // non-trait found in a type sum, moved to resolve +// E0173, // manual implementations of unboxed closure traits are experimental +// E0174, +// E0182, // merged into E0229 + E0183, +// E0187, // can't infer the kind of the closure +// E0188, // can not cast an immutable reference to a mutable pointer +// E0189, // deprecated: can only cast a boxed pointer to a boxed object +// E0190, // deprecated: can only cast a &-pointer to an &-object +// E0196, // cannot determine a type for this closure + E0203, // type parameter has more than one relaxed default bound, + // and only one is supported + E0208, +// E0209, // builtin traits can only be implemented on structs or enums + E0212, // cannot extract an associated type from a higher-ranked trait bound +// E0213, // associated types are not accepted in this context +// E0215, // angle-bracket notation is not stable with `Fn` +// E0216, // parenthetical notation is only stable with `Fn` +// E0217, // ambiguous associated type, defined in multiple supertraits +// E0218, // no associated type defined +// E0219, // associated type defined in higher-ranked supertrait +// E0222, // Error code E0045 (variadic function must have C or cdecl calling + // convention) duplicate + E0224, // at least one non-builtin train is required for an object type + E0227, // ambiguous lifetime bound, explicit lifetime bound required + E0228, // explicit lifetime bound required +// E0233, +// E0234, +// E0235, // structure constructor specifies a structure of type but +// E0236, // no lang item for range syntax +// E0237, // no lang item for range syntax +// E0238, // parenthesized parameters may only be used with a trait +// E0239, // `next` method of `Iterator` trait has unexpected type +// E0240, +// E0241, +// E0242, +// E0245, // not a trait +// E0246, // invalid recursive type +// E0247, +// E0248, // value used as a type, now reported earlier during resolution as E0412 +// E0249, + E0307, // invalid method `self` type +// E0319, // trait impls for defaulted traits allowed just for structs/enums +// E0372, // coherence not object safe + E0377, // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures with the same definition +// E0558, // replaced with a generic attribute input check + E0533, // `{}` does not name a unit variant, unit struct or a constant +// E0563, // cannot determine a type for this `impl Trait`: {} // removed in 6383de15 + E0564, // only named lifetimes are allowed in `impl Trait`, + // but `{}` was found in the type `{}` + E0587, // type has conflicting packed and align representation hints + E0588, // packed type cannot transitively contain a `[repr(align)]` type +// E0611, // merged into E0616 +// E0612, // merged into E0609 +// E0613, // Removed (merged with E0609) + E0627, // yield statement outside of generator literal + E0632, // cannot provide explicit type parameters when `impl Trait` is used in + // argument position. + E0634, // type has conflicting packed representaton hints + E0640, // infer outlives requirements + E0641, // cannot cast to/from a pointer with an unknown kind + E0645, // trait aliases not finished + E0719, // duplicate values for associated type binding + E0722, // Malformed #[optimize] attribute + E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions +} diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index ed39874eeaada..b833d8555ee0a 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -8,7 +8,7 @@ //! specialization errors. These things can (and probably should) be //! fixed, but for the moment it's easier to do these checks early. -use crate::constrained_type_params as ctp; +use crate::constrained_generic_params as cgp; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::def_id::DefId; @@ -49,7 +49,7 @@ use syntax_pos::Span; /// impl<'a> Trait for Bar { type X = &'a i32; } /// // ^ 'a is unused and appears in assoc type, error /// ``` -pub fn impl_wf_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn impl_wf_check<'tcx>(tcx: TyCtxt<'tcx>) { // We will tag this as part of the WF check -- logically, it is, // but it's one that we must perform earlier than the rest of // WfCheck. @@ -58,7 +58,7 @@ pub fn impl_wf_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { } } -fn check_mod_impl_wf<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) { +fn check_mod_impl_wf<'tcx>(tcx: TyCtxt<'tcx>, module_def_id: DefId) { tcx.hir().visit_item_likes_in_module( module_def_id, &mut ImplWfCheck { tcx } @@ -72,14 +72,14 @@ pub fn provide(providers: &mut Providers<'_>) { }; } -struct ImplWfCheck<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct ImplWfCheck<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> { +impl ItemLikeVisitor<'tcx> for ImplWfCheck<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { if let hir::ItemKind::Impl(.., ref impl_item_refs) = item.node { - let impl_def_id = self.tcx.hir().local_def_id(item.id); + let impl_def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); enforce_impl_params_are_constrained(self.tcx, impl_def_id, impl_item_refs); @@ -92,37 +92,38 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> { fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { } } -fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_def_id: DefId, - impl_item_refs: &[hir::ImplItemRef]) -{ +fn enforce_impl_params_are_constrained<'tcx>( + tcx: TyCtxt<'tcx>, + impl_def_id: DefId, + impl_item_refs: &[hir::ImplItemRef], +) { // Every lifetime used in an associated type must be constrained. let impl_self_ty = tcx.type_of(impl_def_id); let impl_generics = tcx.generics_of(impl_def_id); let impl_predicates = tcx.predicates_of(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); - let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref); - ctp::identify_constrained_type_params( + let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref); + cgp::identify_constrained_generic_params( tcx, &impl_predicates, impl_trait_ref, &mut input_parameters); // Disallow unconstrained lifetimes, but only if they appear in assoc types. let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs.iter() - .map(|item_ref| tcx.hir().local_def_id(item_ref.id.node_id)) + .map(|item_ref| tcx.hir().local_def_id_from_hir_id(item_ref.id.hir_id)) .filter(|&def_id| { let item = tcx.associated_item(def_id); - item.kind == ty::AssociatedKind::Type && item.defaultness.has_value() + item.kind == ty::AssocKind::Type && item.defaultness.has_value() }) .flat_map(|def_id| { - ctp::parameters_for(&tcx.type_of(def_id), true) + cgp::parameters_for(&tcx.type_of(def_id), true) }).collect(); for param in &impl_generics.params { match param.kind { // Disallow ANY unconstrained type parameters. - ty::GenericParamDefKind::Type {..} => { + ty::GenericParamDefKind::Type { .. } => { let param_ty = ty::ParamTy::for_def(param); - if !input_parameters.contains(&ctp::Parameter::from(param_ty)) { + if !input_parameters.contains(&cgp::Parameter::from(param_ty)) { report_unused_parameter(tcx, tcx.def_span(param.def_id), "type", @@ -130,7 +131,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } ty::GenericParamDefKind::Lifetime => { - let param_lt = ctp::Parameter::from(param.to_early_bound_region_data()); + let param_lt = cgp::Parameter::from(param.to_early_bound_region_data()); if lifetimes_in_associated_types.contains(¶m_lt) && // (*) !input_parameters.contains(¶m_lt) { report_unused_parameter(tcx, @@ -139,6 +140,15 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ¶m.name.to_string()); } } + ty::GenericParamDefKind::Const => { + let param_ct = ty::ParamConst::for_def(param); + if !input_parameters.contains(&cgp::Parameter::from(param_ct)) { + report_unused_parameter(tcx, + tcx.def_span(param.def_id), + "const", + ¶m_ct.to_string()); + } + } } } @@ -162,11 +172,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // used elsewhere are not projected back out. } -fn report_unused_parameter(tcx: TyCtxt<'_, '_, '_>, - span: Span, - kind: &str, - name: &str) -{ +fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: &str) { struct_span_err!( tcx.sess, span, E0207, "the {} parameter `{}` is not constrained by the \ @@ -177,9 +183,7 @@ fn report_unused_parameter(tcx: TyCtxt<'_, '_, '_>, } /// Enforce that we do not have two items in an impl with the same name. -fn enforce_impl_items_are_distinct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_item_refs: &[hir::ImplItemRef]) -{ +fn enforce_impl_items_are_distinct<'tcx>(tcx: TyCtxt<'tcx>, impl_item_refs: &[hir::ImplItemRef]) { let mut seen_type_items = FxHashMap::default(); let mut seen_value_items = FxHashMap::default(); for impl_item_ref in impl_item_refs { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index a918113b1fc0b..85ae55b2dd946 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -63,16 +63,18 @@ This API is completely unstable and subject to change. #![feature(box_syntax)] #![feature(crate_visibility_modifier)] #![feature(exhaustive_patterns)] +#![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] #![feature(never_type)] +#![feature(inner_deref)] #![recursion_limit="256"] #![deny(rust_2018_idioms)] -#![allow(explicit_outlives_requirements)] +#![deny(internal)] +#![deny(unused_lifetimes)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; @@ -81,14 +83,14 @@ This API is completely unstable and subject to change. // N.B., this module needs to be declared first so diagnostics are // registered before they are used. -mod diagnostics; +mod error_codes; mod astconv; mod check; mod check_unused; mod coherence; mod collect; -mod constrained_type_params; +mod constrained_generic_params; mod structured_errors; mod impl_wf_check; mod namespace; @@ -103,43 +105,26 @@ use rustc::lint; use rustc::middle; use rustc::session; use rustc::util::common::ErrorReported; -use rustc::session::config::{EntryFnType, nightly_options}; +use rustc::session::config::EntryFnType; use rustc::traits::{ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt}; use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::query::Providers; use rustc::util; -use rustc::util::profiling::ProfileCategory; use syntax_pos::Span; use util::common::time; use std::iter; +use astconv::{AstConv, Bounds}; +pub use collect::checked_type_of; + pub struct TypeAndSubsts<'tcx> { substs: SubstsRef<'tcx>, ty: Ty<'tcx>, } -fn check_type_alias_enum_variants_enabled<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - span: Span) { - if !tcx.features().type_alias_enum_variants { - let mut err = tcx.sess.struct_span_err( - span, - "enum variants on type aliases are experimental" - ); - if nightly_options::is_nightly_build() { - help!(&mut err, - "add `#![feature(type_alias_enum_variants)]` to the \ - crate attributes to enable"); - } - err.emit(); - } -} - -fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_, '_, '_>, - decl: &hir::FnDecl, - abi: Abi, - span: Span) { +fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl, abi: Abi, span: Span) { if decl.c_variadic && !(abi == Abi::C || abi == Abi::Cdecl) { let mut err = struct_span_err!(tcx.sess, span, E0045, "C-variadic function must have C or cdecl calling convention"); @@ -147,11 +132,12 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_, '_, '_>, } } -fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - cause: &ObligationCause<'tcx>, - expected: Ty<'tcx>, - actual: Ty<'tcx>) - -> bool { +fn require_same_types<'tcx>( + tcx: TyCtxt<'tcx>, + cause: &ObligationCause<'tcx>, + expected: Ty<'tcx>, + actual: Ty<'tcx>, +) -> bool { tcx.infer_ctxt().enter(|ref infcx| { let param_env = ty::ParamEnv::empty(); let mut fulfill_cx = TraitEngine::new(infcx.tcx); @@ -175,13 +161,13 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } -fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, main_def_id: DefId) { +fn check_main_fn_ty<'tcx>(tcx: TyCtxt<'tcx>, main_def_id: DefId) { let main_id = tcx.hir().as_local_hir_id(main_def_id).unwrap(); let main_span = tcx.def_span(main_def_id); let main_t = tcx.type_of(main_def_id); match main_t.sty { ty::FnDef(..) => { - if let Some(Node::Item(it)) = tcx.hir().find_by_hir_id(main_id) { + if let Some(Node::Item(it)) = tcx.hir().find(main_id) { if let hir::ItemKind::Fn(.., ref generics, _) = it.node { let mut error = false; if !generics.params.is_empty() { @@ -240,13 +226,13 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, main_def_id: DefId) { } } -fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, start_def_id: DefId) { +fn check_start_fn_ty<'tcx>(tcx: TyCtxt<'tcx>, start_def_id: DefId) { let start_id = tcx.hir().as_local_hir_id(start_def_id).unwrap(); let start_span = tcx.def_span(start_def_id); let start_t = tcx.type_of(start_def_id); match start_t.sty { ty::FnDef(..) => { - if let Some(Node::Item(it)) = tcx.hir().find_by_hir_id(start_id) { + if let Some(Node::Item(it)) = tcx.hir().find(start_id) { if let hir::ItemKind::Fn(.., ref generics, _) = it.node { let mut error = false; if !generics.params.is_empty() { @@ -297,7 +283,7 @@ fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, start_def_id: DefId) } } -fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +fn check_for_entry_fn<'tcx>(tcx: TyCtxt<'tcx>) { match tcx.entry_fn(LOCAL_CRATE) { Some((def_id, EntryFnType::Main)) => check_main_fn_ty(tcx, def_id), Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id), @@ -314,16 +300,18 @@ pub fn provide(providers: &mut Providers<'_>) { impl_wf_check::provide(providers); } -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Result<(), ErrorReported> -{ - tcx.sess.profiler(|p| p.start_activity(ProfileCategory::TypeChecking)); +pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) -> Result<(), ErrorReported> { + tcx.sess.profiler(|p| p.start_activity("type-check crate")); // this ensures that later parts of type checking can assume that items // have valid types and not error + // FIXME(matthewjasper) We shouldn't need to do this. tcx.sess.track_errors(|| { - time(tcx.sess, "type collecting", || - collect::collect_item_types(tcx)); + time(tcx.sess, "type collecting", || { + for &module in tcx.hir().krate().modules.keys() { + tcx.ensure().collect_mod_item_types(tcx.hir().local_def_id(module)); + } + }); })?; if tcx.features().rustc_attrs { @@ -350,16 +338,22 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) })?; } - time(tcx.sess, "wf checking", || check::check_wf_new(tcx))?; + tcx.sess.track_errors(|| { + time(tcx.sess, "wf checking", || check::check_wf_new(tcx)); + })?; - time(tcx.sess, "item-types checking", || check::check_item_types(tcx))?; + time(tcx.sess, "item-types checking", || { + for &module in tcx.hir().krate().modules.keys() { + tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module)); + } + }); - time(tcx.sess, "item-bodies checking", || check::check_item_bodies(tcx))?; + time(tcx.sess, "item-bodies checking", || tcx.typeck_item_bodies(LOCAL_CRATE)); check_unused::check_crate(tcx); check_for_entry_fn(tcx); - tcx.sess.profiler(|p| p.end_activity(ProfileCategory::TypeChecking)); + tcx.sess.profiler(|p| p.end_activity("type-check crate")); if tcx.sess.err_count() == 0 { Ok(()) @@ -368,11 +362,11 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) } } -/// A quasi-deprecated helper used in rustdoc and save-analysis to get +/// A quasi-deprecated helper used in rustdoc and clippy to get /// the type from a HIR node. -pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) -> Ty<'tcx> { - // In case there are any projections etc, find the "environment" - // def-id that will be used to determine the traits/predicates in +pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty) -> Ty<'tcx> { + // In case there are any projections, etc., find the "environment" + // def-ID that will be used to determine the traits/predicates in // scope. This is derived from the enclosing item-like thing. let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id); let env_def_id = tcx.hir().local_def_id_from_hir_id(env_node_id); @@ -381,20 +375,22 @@ pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) -> astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty) } -pub fn hir_trait_to_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_trait: &hir::TraitRef) - -> (ty::PolyTraitRef<'tcx>, Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>) { - // In case there are any projections etc, find the "environment" - // def-id that will be used to determine the traits/predicates in +pub fn hir_trait_to_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + hir_trait: &hir::TraitRef, +) -> (ty::PolyTraitRef<'tcx>, Bounds<'tcx>) { + // In case there are any projections, etc., find the "environment" + // def-ID that will be used to determine the traits/predicates in // scope. This is derived from the enclosing item-like thing. let env_hir_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id); let env_def_id = tcx.hir().local_def_id_from_hir_id(env_hir_id); let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id); - let mut projections = Vec::new(); - let (principal, _) = astconv::AstConv::instantiate_poly_trait_ref_inner( - &item_cx, hir_trait, tcx.types.err, &mut projections, true + let mut bounds = Bounds::default(); + let (principal, _) = AstConv::instantiate_poly_trait_ref_inner( + &item_cx, hir_trait, tcx.types.err, &mut bounds, true ); - (principal, projections) + (principal, bounds) } __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS } diff --git a/src/librustc_typeck/namespace.rs b/src/librustc_typeck/namespace.rs index e8f6272810a37..9b6c5bd9f429f 100644 --- a/src/librustc_typeck/namespace.rs +++ b/src/librustc_typeck/namespace.rs @@ -8,13 +8,13 @@ pub enum Namespace { Value, } -impl From for Namespace { - fn from(a_kind: ty::AssociatedKind) -> Self { +impl From for Namespace { + fn from(a_kind: ty::AssocKind) -> Self { match a_kind { - ty::AssociatedKind::Existential | - ty::AssociatedKind::Type => Namespace::Type, - ty::AssociatedKind::Const | - ty::AssociatedKind::Method => Namespace::Value, + ty::AssocKind::Existential | + ty::AssocKind::Type => Namespace::Type, + ty::AssocKind::Const | + ty::AssocKind::Method => Namespace::Value, } } } diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index 574086f780a9d..40a57788c0710 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -18,7 +18,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { pub fn explicit_predicates_of( &mut self, - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, def_id: DefId, ) -> &RequiredPredicates<'tcx> { self.map.entry(def_id).or_insert_with(|| { diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs index 6c56e9991c8a8..f2661b46b8b0c 100644 --- a/src/librustc_typeck/outlives/implicit_infer.rs +++ b/src/librustc_typeck/outlives/implicit_infer.rs @@ -15,7 +15,7 @@ use super::utils::*; /// was generated by walking the items in the crate. This will /// now be filled with inferred predicates. pub fn infer_predicates<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) -> FxHashMap> { debug!("infer_predicates"); @@ -43,8 +43,8 @@ pub fn infer_predicates<'tcx>( global_inferred_outlives } -pub struct InferVisitor<'cx, 'tcx: 'cx> { - tcx: TyCtxt<'cx, 'tcx, 'tcx>, +pub struct InferVisitor<'cx, 'tcx> { + tcx: TyCtxt<'tcx>, global_inferred_outlives: &'cx mut FxHashMap>, predicates_added: &'cx mut bool, explicit_map: &'cx mut ExplicitPredicatesMap<'tcx>, @@ -52,16 +52,16 @@ pub struct InferVisitor<'cx, 'tcx: 'cx> { impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { - let item_did = self.tcx.hir().local_def_id(item.id); + let item_did = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); debug!("InferVisitor::visit_item(item={:?})", item_did); - let node_id = self + let hir_id = self .tcx .hir() - .as_local_node_id(item_did) + .as_local_hir_id(item_did) .expect("expected local def-id"); - let item = match self.tcx.hir().get(node_id) { + let item = match self.tcx.hir().get(hir_id) { Node::Item(item) => item, _ => bug!(), }; @@ -117,7 +117,7 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { } fn insert_required_predicates_to_be_wf<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, field_ty: Ty<'tcx>, global_inferred_outlives: &FxHashMap>, required_predicates: &mut RequiredPredicates<'tcx>, @@ -255,7 +255,7 @@ pub struct IgnoreSelfTy(bool); /// can ignore, but we will want to process `U: 'static`, /// applying the substitution as above. pub fn check_explicit_predicates<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, def_id: &DefId, substs: &[Kind<'tcx>], required_predicates: &mut RequiredPredicates<'tcx>, diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index b3634d37cc2b8..63e41e01fbff5 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -4,7 +4,7 @@ use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::ty::query::Providers; use rustc::ty::subst::UnpackedKind; use rustc::ty::{self, CratePredicatesMap, TyCtxt}; -use rustc_data_structures::sync::Lrc; +use syntax::symbol::sym; mod explicit; mod implicit_infer; @@ -20,13 +20,13 @@ pub fn provide(providers: &mut Providers<'_>) { }; } -fn inferred_outlives_of<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn inferred_outlives_of<'tcx>( + tcx: TyCtxt<'tcx>, item_def_id: DefId, -) -> Lrc>> { +) -> &'tcx [ty::Predicate<'tcx>] { let id = tcx .hir() - .as_local_node_id(item_def_id) + .as_local_hir_id(item_def_id) .expect("expected local def-id"); match tcx.hir().get(id) { @@ -37,10 +37,10 @@ fn inferred_outlives_of<'a, 'tcx>( let predicates = crate_map .predicates .get(&item_def_id) - .unwrap_or(&crate_map.empty_predicate) - .clone(); + .map(|p| *p) + .unwrap_or(&[]); - if tcx.has_attr(item_def_id, "rustc_outlives") { + if tcx.has_attr(item_def_id, sym::rustc_outlives) { let mut pred: Vec = predicates .iter() .map(|out_pred| match out_pred { @@ -63,17 +63,17 @@ fn inferred_outlives_of<'a, 'tcx>( predicates } - _ => Lrc::new(Vec::new()), + _ => &[], }, - _ => Lrc::new(Vec::new()), + _ => &[], } } fn inferred_outlives_crate<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, crate_num: CrateNum, -) -> Lrc> { +) -> &'tcx CratePredicatesMap<'tcx> { assert_eq!(crate_num, LOCAL_CRATE); // Compute a map from each struct/enum/union S to the **explicit** @@ -96,25 +96,30 @@ fn inferred_outlives_crate<'tcx>( let predicates = global_inferred_outlives .iter() .map(|(&def_id, set)| { - let vec: Vec> = set + let predicates = tcx.arena.alloc_from_iter(set .iter() - .map( + .filter_map( |ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() { - UnpackedKind::Type(ty1) => ty::Predicate::TypeOutlives(ty::Binder::bind( - ty::OutlivesPredicate(ty1, region2), - )), - UnpackedKind::Lifetime(region1) => ty::Predicate::RegionOutlives( - ty::Binder::bind(ty::OutlivesPredicate(region1, region2)), - ), + UnpackedKind::Type(ty1) => { + Some(ty::Predicate::TypeOutlives(ty::Binder::bind( + ty::OutlivesPredicate(ty1, region2) + ))) + } + UnpackedKind::Lifetime(region1) => { + Some(ty::Predicate::RegionOutlives( + ty::Binder::bind(ty::OutlivesPredicate(region1, region2)) + )) + } + UnpackedKind::Const(_) => { + // Generic consts don't impose any constraints. + None + } }, - ).collect(); - (def_id, Lrc::new(vec)) + )); + (def_id, &*predicates) }).collect(); - let empty_predicate = Lrc::new(Vec::new()); - - Lrc::new(ty::CratePredicatesMap { + tcx.arena.alloc(ty::CratePredicatesMap { predicates, - empty_predicate, }) } diff --git a/src/librustc_typeck/outlives/test.rs b/src/librustc_typeck/outlives/test.rs index cbeb7f7b69194..4690cb9eada2e 100644 --- a/src/librustc_typeck/outlives/test.rs +++ b/src/librustc_typeck/outlives/test.rs @@ -1,24 +1,25 @@ use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::ty::TyCtxt; +use syntax::symbol::sym; -pub fn test_inferred_outlives<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn test_inferred_outlives<'tcx>(tcx: TyCtxt<'tcx>) { tcx.hir() .krate() .visit_all_item_likes(&mut OutlivesTest { tcx }); } -struct OutlivesTest<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct OutlivesTest<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx> ItemLikeVisitor<'tcx> for OutlivesTest<'a, 'tcx> { +impl ItemLikeVisitor<'tcx> for OutlivesTest<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { - let item_def_id = self.tcx.hir().local_def_id(item.id); + let item_def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); // For unit testing: check for a special "rustc_outlives" // attribute and report an error with various results if found. - if self.tcx.has_attr(item_def_id, "rustc_outlives") { + if self.tcx.has_attr(item_def_id, sym::rustc_outlives) { let inferred_outlives_of = self.tcx.inferred_outlives_of(item_def_id); span_err!( self.tcx.sess, diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs index c886c7a4ffce5..c6b0da3fe474c 100644 --- a/src/librustc_typeck/outlives/utils.rs +++ b/src/librustc_typeck/outlives/utils.rs @@ -11,7 +11,7 @@ pub type RequiredPredicates<'tcx> = BTreeSet, t /// Given a requirement `T: 'a` or `'b: 'a`, deduce the /// outlives_component and add it to `required_predicates` pub fn insert_outlives_predicate<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, kind: Kind<'tcx>, outlived_region: Region<'tcx>, required_predicates: &mut RequiredPredicates<'tcx>, @@ -118,10 +118,14 @@ pub fn insert_outlives_predicate<'tcx>( } required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region)); } + + UnpackedKind::Const(_) => { + // Generic consts don't impose any constraints. + } } } -fn is_free_region<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, region: Region<'_>) -> bool { +fn is_free_region<'tcx>(tcx: TyCtxt<'tcx>, region: Region<'_>) -> bool { // First, screen for regions that might appear in a type header. match region { // These correspond to `T: 'a` relationships: diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index d8d93b462a900..36f0dbcd2fcbd 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -4,7 +4,7 @@ //! We walk the set of items and, for each member, generate new constraints. use hir::def_id::DefId; -use rustc::ty::subst::{UnpackedKind, SubstsRef}; +use rustc::ty::subst::{SubstsRef, UnpackedKind}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -12,7 +12,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use super::terms::*; use super::terms::VarianceTerm::*; -pub struct ConstraintContext<'a, 'tcx: 'a> { +pub struct ConstraintContext<'a, 'tcx> { pub terms_cx: TermsContext<'a, 'tcx>, // These are pointers to common `ConstantTerm` instances @@ -74,7 +74,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { self.visit_node_helper(item.hir_id); if let hir::VariantData::Tuple(..) = *struct_def { - self.visit_node_helper(struct_def.hir_id()); + self.visit_node_helper(struct_def.ctor_hir_id().unwrap()); } } @@ -83,7 +83,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { for variant in &enum_def.variants { if let hir::VariantData::Tuple(..) = variant.node.data { - self.visit_node_helper(variant.node.data.hir_id()); + self.visit_node_helper(variant.node.data.ctor_hir_id().unwrap()); } } } @@ -124,13 +124,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.build_constraints_for_item(def_id); } - fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.terms_cx.tcx } fn build_constraints_for_item(&mut self, def_id: DefId) { let tcx = self.tcx(); - debug!("build_constraints_for_item({})", tcx.item_path_str(def_id)); + debug!("build_constraints_for_item({})", tcx.def_path_str(def_id)); // Skip items with no generics - there's nothing to infer in them. if tcx.generics_of(def_id).count() == 0 { @@ -229,12 +229,19 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // Trait are always invariant so we can take advantage of that. let variance_i = self.invariant(variance); - for ty in substs.types() { - self.add_constraints_from_ty(current, ty, variance_i); - } - for region in substs.regions() { - self.add_constraints_from_region(current, region, variance_i); + for k in substs { + match k.unpack() { + UnpackedKind::Lifetime(lt) => { + self.add_constraints_from_region(current, lt, variance_i) + } + UnpackedKind::Type(ty) => { + self.add_constraints_from_ty(current, ty, variance_i) + } + UnpackedKind::Const(_) => { + // Consts impose no constraints. + } + } } } @@ -267,7 +274,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance); } - ty::Array(typ, _) | + ty::Array(typ, _) => { + self.add_constraints_from_ty(current, typ, variance); + } + ty::Slice(typ) => { self.add_constraints_from_ty(current, typ, variance); } @@ -278,7 +288,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::Tuple(subtys) => { for &subty in subtys { - self.add_constraints_from_ty(current, subty, variance); + self.add_constraints_from_ty(current, subty.expect_ty(), variance); } } @@ -314,7 +324,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::Param(ref data) => { - self.add_constraint(current, data.idx, variance); + self.add_constraint(current, data.index, variance); } ty::FnPtr(sig) => { @@ -383,6 +393,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { UnpackedKind::Type(ty) => { self.add_constraints_from_ty(current, ty, variance_i) } + UnpackedKind::Const(_) => { + // Consts impose no constraints. + } } } } diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index c2f79207a5624..1a8871a3da9da 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -9,7 +9,6 @@ use hir::Node; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::ty::{self, CrateVariancesMap, TyCtxt}; use rustc::ty::query::Providers; -use rustc_data_structures::sync::Lrc; /// Defines the `TermsContext` basically houses an arena where we can /// allocate terms. @@ -35,23 +34,21 @@ pub fn provide(providers: &mut Providers<'_>) { }; } -fn crate_variances<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) - -> Lrc { +fn crate_variances<'tcx>(tcx: TyCtxt<'tcx>, crate_num: CrateNum) -> &'tcx CrateVariancesMap<'tcx> { assert_eq!(crate_num, LOCAL_CRATE); let mut arena = arena::TypedArena::default(); let terms_cx = terms::determine_parameters_to_be_inferred(tcx, &mut arena); let constraints_cx = constraints::add_constraints_from_crate(terms_cx); - Lrc::new(solve::solve_constraints(constraints_cx)) + tcx.arena.alloc(solve::solve_constraints(constraints_cx)) } -fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId) - -> Lrc> { +fn variances_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> &'tcx [ty::Variance] { let id = tcx.hir().as_local_hir_id(item_def_id).expect("expected local def-id"); let unsupported = || { // Variance not relevant. - span_bug!(tcx.hir().span_by_hir_id(id), "asked to compute variance for wrong kind of item") + span_bug!(tcx.hir().span(id), "asked to compute variance for wrong kind of item") }; - match tcx.hir().get_by_hir_id(id) { + match tcx.hir().get(id) { Node::Item(item) => match item.node { hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | @@ -79,7 +76,7 @@ fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId) _ => unsupported() }, - Node::Variant(_) | Node::StructCtor(_) => {} + Node::Variant(_) | Node::Ctor(..) => {} _ => unsupported() } @@ -88,6 +85,6 @@ fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId) let crate_map = tcx.crate_variances(LOCAL_CRATE); crate_map.variances.get(&item_def_id) - .unwrap_or(&crate_map.empty_variance) - .clone() + .map(|p| *p) + .unwrap_or(&[]) } diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index cec33ba87dea4..3851b918c4855 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -8,14 +8,13 @@ use rustc::hir::def_id::DefId; use rustc::ty; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::Lrc; use super::constraints::*; use super::terms::*; use super::terms::VarianceTerm::*; use super::xform::*; -struct SolveContext<'a, 'tcx: 'a> { +struct SolveContext<'a, 'tcx> { terms_cx: TermsContext<'a, 'tcx>, constraints: Vec>, @@ -23,7 +22,9 @@ struct SolveContext<'a, 'tcx: 'a> { solutions: Vec, } -pub fn solve_constraints(constraints_cx: ConstraintContext<'_, '_>) -> ty::CrateVariancesMap { +pub fn solve_constraints<'tcx>( + constraints_cx: ConstraintContext<'_, 'tcx> +) -> ty::CrateVariancesMap<'tcx> { let ConstraintContext { terms_cx, constraints, .. } = constraints_cx; let mut solutions = vec![ty::Bivariant; terms_cx.inferred_terms.len()]; @@ -41,9 +42,8 @@ pub fn solve_constraints(constraints_cx: ConstraintContext<'_, '_>) -> ty::Crate }; solutions_cx.solve(); let variances = solutions_cx.create_map(); - let empty_variance = Lrc::new(Vec::new()); - ty::CrateVariancesMap { variances, empty_variance } + ty::CrateVariancesMap { variances } } impl<'a, 'tcx> SolveContext<'a, 'tcx> { @@ -78,28 +78,46 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { } } - fn create_map(&self) -> FxHashMap>> { + fn enforce_const_invariance(&self, generics: &ty::Generics, variances: &mut [ty::Variance]) { + let tcx = self.terms_cx.tcx; + + // Make all const parameters invariant. + for param in generics.params.iter() { + if let ty::GenericParamDefKind::Const = param.kind { + variances[param.index as usize] = ty::Invariant; + } + } + + // Make all the const parameters in the parent invariant (recursively). + if let Some(def_id) = generics.parent { + self.enforce_const_invariance(tcx.generics_of(def_id), variances); + } + } + + fn create_map(&self) -> FxHashMap { let tcx = self.terms_cx.tcx; let solutions = &self.solutions; self.terms_cx.inferred_starts.iter().map(|(&id, &InferredIndex(start))| { let def_id = tcx.hir().local_def_id_from_hir_id(id); let generics = tcx.generics_of(def_id); + let count = generics.count(); - let mut variances = solutions[start..start+generics.count()].to_vec(); + let variances = tcx.arena.alloc_slice(&solutions[start..(start + count)]); - debug!("id={} variances={:?}", id, variances); + // Const parameters are always invariant. + self.enforce_const_invariance(generics, variances); - // Functions can have unused type parameters: make those invariant. + // Functions are permitted to have unused generic parameters: make those invariant. if let ty::FnDef(..) = tcx.type_of(def_id).sty { - for variance in &mut variances { + for variance in variances.iter_mut() { if *variance == ty::Bivariant { *variance = ty::Invariant; } } } - (def_id, Lrc::new(variances)) + (def_id, &*variances) }).collect() } diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index e564a8658fcab..3f6eadeac3334 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -47,8 +47,8 @@ impl<'a> fmt::Debug for VarianceTerm<'a> { // The first pass over the crate simply builds up the set of inferreds. -pub struct TermsContext<'a, 'tcx: 'a> { - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub struct TermsContext<'a, 'tcx> { + pub tcx: TyCtxt<'tcx>, pub arena: &'a TypedArena>, // For marker types, UnsafeCell, and other lang items where @@ -64,9 +64,10 @@ pub struct TermsContext<'a, 'tcx: 'a> { pub inferred_terms: Vec>, } -pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - arena: &'a mut TypedArena>) - -> TermsContext<'a, 'tcx> { +pub fn determine_parameters_to_be_inferred<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + arena: &'a mut TypedArena>, +) -> TermsContext<'a, 'tcx> { let mut terms_cx = TermsContext { tcx, arena, @@ -85,7 +86,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx> terms_cx } -fn lang_items(tcx: TyCtxt<'_, '_, '_>) -> Vec<(hir::HirId, Vec)> { +fn lang_items(tcx: TyCtxt<'_>) -> Vec<(hir::HirId, Vec)> { let lang_items = tcx.lang_items(); let all = vec![ (lang_items.phantom_data(), vec![ty::Covariant]), @@ -119,7 +120,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { // for a particular item are assigned continuous indices. let arena = self.arena; - self.inferred_terms.extend((start..start+count).map(|i| { + self.inferred_terms.extend((start..(start + count)).map(|i| { &*arena.alloc(InferredTerm(InferredIndex(i))) })); } @@ -128,7 +129,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { debug!("add_inferreds for item {}", - self.tcx.hir().node_to_string(item.id)); + self.tcx.hir().node_to_string(item.hir_id)); match item.node { hir::ItemKind::Struct(ref struct_def, _) | @@ -136,7 +137,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { self.add_inferreds_for_item(item.hir_id); if let hir::VariantData::Tuple(..) = *struct_def { - self.add_inferreds_for_item(struct_def.hir_id()); + self.add_inferreds_for_item(struct_def.ctor_hir_id().unwrap()); } } @@ -145,7 +146,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { for variant in &enum_def.variants { if let hir::VariantData::Tuple(..) = variant.node.data { - self.add_inferreds_for_item(variant.node.data.hir_id()); + self.add_inferreds_for_item(variant.node.data.ctor_hir_id().unwrap()); } } } diff --git a/src/librustc_typeck/variance/test.rs b/src/librustc_typeck/variance/test.rs index 0f566e6ded973..cefc200f5cba8 100644 --- a/src/librustc_typeck/variance/test.rs +++ b/src/librustc_typeck/variance/test.rs @@ -1,22 +1,23 @@ use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::ty::TyCtxt; +use syntax::symbol::sym; -pub fn test_variance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn test_variance<'tcx>(tcx: TyCtxt<'tcx>) { tcx.hir().krate().visit_all_item_likes(&mut VarianceTest { tcx }); } -struct VarianceTest<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx> +struct VarianceTest<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx> ItemLikeVisitor<'tcx> for VarianceTest<'a, 'tcx> { +impl ItemLikeVisitor<'tcx> for VarianceTest<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { - let item_def_id = self.tcx.hir().local_def_id(item.id); + let item_def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id); // For unit testing: check for a special "rustc_variance" // attribute and report an error with various results if found. - if self.tcx.has_attr(item_def_id, "rustc_variance") { + if self.tcx.has_attr(item_def_id, sym::rustc_variance) { let variances_of = self.tcx.variances_of(item_def_id); span_err!(self.tcx.sess, item.span, diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index a8c9166591d85..3158ec3832aed 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -9,7 +9,8 @@ name = "rustdoc" path = "lib.rs" [dependencies] -pulldown-cmark = { version = "0.1.2", default-features = false } -minifier = "0.0.28" +pulldown-cmark = { version = "0.5.2", default-features = false } +minifier = "0.0.30" +rayon = { version = "0.2.0", package = "rustc-rayon" } tempfile = "3" parking_lot = "0.7" diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index d07a4579ad5c3..5a4dc7be326d2 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -1,125 +1,87 @@ use rustc::hir; -use rustc::traits::auto_trait as auto; +use rustc::traits::auto_trait::{self, AutoTraitResult}; use rustc::ty::{self, TypeFoldable}; use std::fmt::Debug; -use self::def_ctor::{get_def_from_def_id, get_def_from_node_id}; - use super::*; -pub struct AutoTraitFinder<'a, 'tcx: 'a, 'rcx: 'a> { - pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>, - pub f: auto::AutoTraitFinder<'a, 'tcx>, +pub struct AutoTraitFinder<'a, 'tcx> { + pub cx: &'a core::DocContext<'tcx>, + pub f: auto_trait::AutoTraitFinder<'tcx>, } -impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { - pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx>) -> Self { - let f = auto::AutoTraitFinder::new(&cx.tcx); +impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { + pub fn new(cx: &'a core::DocContext<'tcx>) -> Self { + let f = auto_trait::AutoTraitFinder::new(cx.tcx); AutoTraitFinder { cx, f } } - pub fn get_with_def_id(&self, def_id: DefId) -> Vec { - get_def_from_def_id(&self.cx, def_id, &|def_ctor| { - self.get_auto_trait_impls(def_id, &def_ctor, None) - }) - } - - pub fn get_with_node_id(&self, id: ast::NodeId, name: String) -> Vec { - get_def_from_node_id(&self.cx, id, name, &|def_ctor, name| { - let did = self.cx.tcx.hir().local_def_id(id); - self.get_auto_trait_impls(did, &def_ctor, Some(name)) - }) - } - - pub fn get_auto_trait_impls( + // FIXME(eddyb) figure out a better way to pass information about + // parametrization of `ty` than `param_env_def_id`. + pub fn get_auto_trait_impls( &self, - def_id: DefId, - def_ctor: &F, - name: Option, - ) -> Vec - where F: Fn(DefId) -> Def { - if self.cx - .tcx - .get_attrs(def_id) - .lists("doc") - .has_word("hidden") - { - debug!( - "get_auto_trait_impls(def_id={:?}, def_ctor=...): item has doc('hidden'), \ - aborting", - def_id - ); - return Vec::new(); - } + ty: Ty<'tcx>, + param_env_def_id: DefId, + ) -> Vec { + let param_env = self.cx.tcx.param_env(param_env_def_id); + + debug!("get_auto_trait_impls({:?})", ty); + let auto_traits = self.cx.auto_traits.iter().cloned(); + auto_traits.filter_map(|trait_def_id| { + let trait_ref = ty::TraitRef { + def_id: trait_def_id, + substs: self.cx.tcx.mk_substs_trait(ty, &[]), + }; + if !self.cx + .generated_synthetics + .borrow_mut() + .insert((ty, trait_def_id)) + { + debug!( + "get_auto_trait_impl_for({:?}): already generated, aborting", + trait_ref + ); + return None; + } - let tcx = self.cx.tcx; - let generics = self.cx.tcx.generics_of(def_id); + let result = self.f.find_auto_trait_generics( + ty, + param_env, + trait_def_id, + |infcx, info| { + let region_data = info.region_data; - debug!( - "get_auto_trait_impls(def_id={:?}, def_ctor=..., generics={:?}", - def_id, generics - ); - let auto_traits: Vec<_> = self.cx - .send_trait - .and_then(|send_trait| { - self.get_auto_trait_impl_for( - def_id, - name.clone(), - generics.clone(), - def_ctor, - send_trait, - ) - }) - .into_iter() - .chain(self.get_auto_trait_impl_for( - def_id, - name, - generics.clone(), - def_ctor, - tcx.require_lang_item(lang_items::SyncTraitLangItem), - ).into_iter()) - .collect(); + let names_map = self.cx.tcx.generics_of(param_env_def_id) + .params + .iter() + .filter_map(|param| match param.kind { + ty::GenericParamDefKind::Lifetime => Some(param.name.to_string()), + _ => None, + }) + .map(|name| (name.clone(), Lifetime(name))) + .collect(); + let lifetime_predicates = + self.handle_lifetimes(®ion_data, &names_map); + let new_generics = self.param_env_to_generics( + infcx.tcx, + param_env_def_id, + info.full_user_env, + lifetime_predicates, + info.vid_to_region, + ); - debug!( - "get_auto_traits: type {:?} auto_traits {:?}", - def_id, auto_traits - ); - auto_traits - } + debug!( + "find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \ + finished with {:?}", + param_env_def_id, trait_def_id, new_generics + ); - fn get_auto_trait_impl_for( - &self, - def_id: DefId, - name: Option, - generics: ty::Generics, - def_ctor: &F, - trait_def_id: DefId, - ) -> Option - where F: Fn(DefId) -> Def { - if !self.cx - .generated_synthetics - .borrow_mut() - .insert((def_id, trait_def_id)) - { - debug!( - "get_auto_trait_impl_for(def_id={:?}, generics={:?}, def_ctor=..., \ - trait_def_id={:?}): already generated, aborting", - def_id, generics, trait_def_id + new_generics + }, ); - return None; - } - - let result = self.find_auto_trait_generics(def_id, trait_def_id, &generics); - - if result.is_auto() { - let trait_ = hir::TraitRef { - path: get_path_for_type(self.cx.tcx, trait_def_id, hir::def::Def::Trait), - hir_ref_id: hir::DUMMY_HIR_ID, - }; let polarity; - let new_generics = match result { AutoTraitResult::PositiveImpl(new_generics) => { polarity = None; @@ -140,83 +102,40 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { // Instead, we generate `impl !Send for Foo`, which better // expresses the fact that `Foo` never implements `Send`, // regardless of the choice of `T`. - let real_generics = (&generics, &Default::default()); - - // Clean the generics, but ignore the '?Sized' bounds generated - // by the `Clean` impl - let clean_generics = real_generics.clean(self.cx); + let params = ( + self.cx.tcx.generics_of(param_env_def_id), + &&self.cx.tcx.common.empty_predicates, + ).clean(self.cx).params; Generics { - params: clean_generics.params, + params, where_predicates: Vec::new(), } } - _ => unreachable!(), + AutoTraitResult::ExplicitImpl => return None, }; - let real_name = name.map(|name| Ident::from_str(&name)); - let ty = self.cx.get_real_ty(def_id, def_ctor, &real_name, &generics); - return Some(Item { + Some(Item { source: Span::empty(), name: None, attrs: Default::default(), visibility: None, - def_id: self.cx.next_def_id(def_id.krate), + def_id: self.cx.next_def_id(param_env_def_id.krate), stability: None, deprecation: None, inner: ImplItem(Impl { unsafety: hir::Unsafety::Normal, generics: new_generics, provided_trait_methods: Default::default(), - trait_: Some(trait_.clean(self.cx)), + trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()), for_: ty.clean(self.cx), items: Vec::new(), polarity, synthetic: true, blanket_impl: None, }), - }); - } - None - } - - fn find_auto_trait_generics( - &self, - did: DefId, - trait_did: DefId, - generics: &ty::Generics, - ) -> AutoTraitResult { - match self.f.find_auto_trait_generics(did, trait_did, generics, - |infcx, mut info| { - let region_data = info.region_data; - let names_map = - info.names_map - .drain() - .map(|name| (name.clone(), Lifetime(name))) - .collect(); - let lifetime_predicates = - self.handle_lifetimes(®ion_data, &names_map); - let new_generics = self.param_env_to_generics( - infcx.tcx, - did, - info.full_user_env, - generics.clone(), - lifetime_predicates, - info.vid_to_region, - ); - - debug!( - "find_auto_trait_generics(did={:?}, trait_did={:?}, generics={:?}): \ - finished with {:?}", - did, trait_did, generics, new_generics - ); - - new_generics - }) { - auto::AutoTraitResult::ExplicitImpl => AutoTraitResult::ExplicitImpl, - auto::AutoTraitResult::NegativeImpl => AutoTraitResult::NegativeImpl, - auto::AutoTraitResult::PositiveImpl(res) => AutoTraitResult::PositiveImpl(res), - } + }) + }).collect() } fn get_lifetime( @@ -392,10 +311,10 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { lifetime_predicates } - fn extract_for_generics<'b, 'c, 'd>( + fn extract_for_generics( &self, - tcx: TyCtxt<'b, 'c, 'd>, - pred: ty::Predicate<'d>, + tcx: TyCtxt<'tcx>, + pred: ty::Predicate<'tcx>, ) -> FxHashSet { pred.walk_tys() .flat_map(|t| { @@ -420,7 +339,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { .collect() } - fn make_final_bounds<'b, 'c, 'cx>( + fn make_final_bounds( &self, ty_to_bounds: FxHashMap>, ty_to_fn: FxHashMap, Option)>, @@ -435,7 +354,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { let new_ty = match &poly_trait.trait_ { &Type::ResolvedPath { ref path, - ref typarams, + ref param_names, ref did, ref is_generic, } => { @@ -444,7 +363,13 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { .expect("segments were empty"); let (old_input, old_output) = match last_segment.args { - GenericArgs::AngleBracketed { types, .. } => (types, None), + GenericArgs::AngleBracketed { args, .. } => { + let types = args.iter().filter_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty.clone()), + _ => None, + }).collect(); + (types, None) + } GenericArgs::Parenthesized { inputs, output, .. } => { (inputs, output) } @@ -469,7 +394,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { Type::ResolvedPath { path: new_path, - typarams: typarams.clone(), + param_names: param_names.clone(), did: did.clone(), is_generic: *is_generic, } @@ -521,19 +446,18 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { // * Fn bounds are handled specially - instead of leaving it as 'T: Fn(), = // K', we use the dedicated syntax 'T: Fn() -> K' // * We explcitly add a '?Sized' bound if we didn't find any 'Sized' predicates for a type - fn param_env_to_generics<'b, 'c, 'cx>( + fn param_env_to_generics( &self, - tcx: TyCtxt<'b, 'c, 'cx>, - did: DefId, - param_env: ty::ParamEnv<'cx>, - type_generics: ty::Generics, + tcx: TyCtxt<'tcx>, + param_env_def_id: DefId, + param_env: ty::ParamEnv<'tcx>, mut existing_predicates: Vec, - vid_to_region: FxHashMap>, + vid_to_region: FxHashMap>, ) -> Generics { debug!( - "param_env_to_generics(did={:?}, param_env={:?}, type_generics={:?}, \ + "param_env_to_generics(param_env_def_id={:?}, param_env={:?}, \ existing_predicates={:?})", - did, param_env, type_generics, existing_predicates + param_env_def_id, param_env, existing_predicates ); // The `Sized` trait must be handled specially, since we only display it when @@ -547,7 +471,8 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { tcx, }; - let orig_bounds: FxHashSet<_> = self.cx.tcx.param_env(did).caller_bounds.iter().collect(); + let orig_bounds: FxHashSet<_> = + self.cx.tcx.param_env(param_env_def_id).caller_bounds.iter().collect(); let clean_where_predicates = param_env .caller_bounds .iter() @@ -562,11 +487,10 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { (replaced.clone(), replaced.clean(self.cx)) }); - let full_generics = (&type_generics, &tcx.predicates_of(did)); - let Generics { - params: mut generic_params, - .. - } = full_generics.clean(self.cx); + let mut generic_params = ( + tcx.generics_of(param_env_def_id), + &tcx.explicit_predicates_of(param_env_def_id), + ).clean(self.cx).params; let mut has_sized = FxHashSet::default(); let mut ty_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); @@ -628,7 +552,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { // that we don't end up with duplicate bounds (e.g., for<'b, 'b>) for_generics.extend(p.generic_params.clone()); p.generic_params = for_generics.into_iter().collect(); - self.is_fn_ty(&tcx, &p.trait_) + self.is_fn_ty(tcx, &p.trait_) } _ => false, }; @@ -669,13 +593,13 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { match **trait_ { Type::ResolvedPath { path: ref trait_path, - ref typarams, + ref param_names, ref did, ref is_generic, } => { let mut new_trait_path = trait_path.clone(); - if self.is_fn_ty(&tcx, trait_) && left_name == FN_OUTPUT_NAME { + if self.is_fn_ty(tcx, trait_) && left_name == FN_OUTPUT_NAME { ty_to_fn .entry(*ty.clone()) .and_modify(|e| *e = (e.0.clone(), Some(rhs.clone()))) @@ -700,7 +624,9 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { } => { bindings.push(TypeBinding { name: left_name.clone(), - ty: rhs, + kind: TypeBindingKind::Equality { + ty: rhs, + }, }); } &mut GenericArgs::Parenthesized { .. } => { @@ -724,7 +650,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { PolyTrait { trait_: Type::ResolvedPath { path: new_trait_path, - typarams: typarams.clone(), + param_names: param_names.clone(), did: did.clone(), is_generic: *is_generic, }, @@ -751,10 +677,14 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { .or_default() .insert(*trait_.clone()); } - _ => panic!("Unexpected trait {:?} for {:?}", trait_, did), + _ => panic!( + "Unexpected trait {:?} for {:?}", + trait_, + param_env_def_id, + ), } } - _ => panic!("Unexpected LHS {:?} for {:?}", lhs, did), + _ => panic!("Unexpected LHS {:?} for {:?}", lhs, param_env_def_id), } } }; @@ -844,7 +774,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { vec.sort_by_cached_key(|x| format!("{:?}", x)) } - fn is_fn_ty(&self, tcx: &TyCtxt<'_, '_, '_>, ty: &Type) -> bool { + fn is_fn_ty(&self, tcx: TyCtxt<'_>, ty: &Type) -> bool { match &ty { &&Type::ResolvedPath { ref did, .. } => { *did == tcx.require_lang_item(lang_items::FnTraitLangItem) @@ -857,13 +787,13 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { } // Replaces all ReVars in a type with ty::Region's, using the provided map -struct RegionReplacer<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { +struct RegionReplacer<'a, 'tcx> { vid_to_region: &'a FxHashMap>, - tcx: TyCtxt<'a, 'gcx, 'tcx>, + tcx: TyCtxt<'tcx>, } -impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { +impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { self.tcx } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 5a13490eeccf2..5c42d705bd579 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -9,78 +9,45 @@ use crate::core::DocAccessLevels; use super::*; -use self::def_ctor::{get_def_from_def_id, get_def_from_node_id}; - -pub struct BlanketImplFinder<'a, 'tcx: 'a, 'rcx: 'a> { - pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>, +pub struct BlanketImplFinder<'a, 'tcx> { + pub cx: &'a core::DocContext<'tcx>, } -impl<'a, 'tcx, 'rcx> BlanketImplFinder <'a, 'tcx, 'rcx> { - pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx>) -> Self { +impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { + pub fn new(cx: &'a core::DocContext<'tcx>) -> Self { BlanketImplFinder { cx } } - pub fn get_with_def_id(&self, def_id: DefId) -> Vec { - get_def_from_def_id(&self.cx, def_id, &|def_ctor| { - self.get_blanket_impls(def_id, &def_ctor, None) - }) - } - - pub fn get_with_node_id(&self, id: ast::NodeId, name: String) -> Vec { - get_def_from_node_id(&self.cx, id, name, &|def_ctor, name| { - let did = self.cx.tcx.hir().local_def_id(id); - self.get_blanket_impls(did, &def_ctor, Some(name)) - }) - } - - pub fn get_blanket_impls( + // FIXME(eddyb) figure out a better way to pass information about + // parametrization of `ty` than `param_env_def_id`. + pub fn get_blanket_impls( &self, - def_id: DefId, - def_ctor: &F, - name: Option, - ) -> Vec - where F: Fn(DefId) -> Def { - debug!("get_blanket_impls(def_id={:?}, ...)", def_id); + ty: Ty<'tcx>, + param_env_def_id: DefId, + ) -> Vec { + let param_env = self.cx.tcx.param_env(param_env_def_id); + + debug!("get_blanket_impls({:?})", ty); let mut impls = Vec::new(); - if self.cx - .tcx - .get_attrs(def_id) - .lists("doc") - .has_word("hidden") - { - debug!( - "get_blanket_impls(def_id={:?}, def_ctor=...): item has doc('hidden'), \ - aborting", - def_id - ); - return impls; - } - let ty = self.cx.tcx.type_of(def_id); - let generics = self.cx.tcx.generics_of(def_id); - let real_name = name.map(|name| Ident::from_str(&name)); - let param_env = self.cx.tcx.param_env(def_id); for &trait_def_id in self.cx.all_traits.iter() { if !self.cx.renderinfo.borrow().access_levels.is_doc_reachable(trait_def_id) || self.cx.generated_synthetics .borrow_mut() - .get(&(def_id, trait_def_id)) + .get(&(ty, trait_def_id)) .is_some() { continue } self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| { - self.cx.tcx.infer_ctxt().enter(|infcx| { - debug!("get_blanet_impls: Considering impl for trait '{:?}' {:?}", - trait_def_id, impl_def_id); - let t_generics = infcx.tcx.generics_of(impl_def_id); - let trait_ref = infcx.tcx.impl_trait_ref(impl_def_id) - .expect("Cannot get impl trait"); - + debug!("get_blanket_impls: Considering impl for trait '{:?}' {:?}", + trait_def_id, impl_def_id); + let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap(); + let may_apply = self.cx.tcx.infer_ctxt().enter(|infcx| { match trait_ref.self_ty().sty { ty::Param(_) => {}, - _ => return, + _ => return false, } - let substs = infcx.fresh_substs_for_item(DUMMY_SP, def_id); + let substs = infcx.fresh_substs_for_item(DUMMY_SP, param_env_def_id); let ty = ty.subst(infcx.tcx, substs); let param_env = param_env.subst(infcx.tcx, substs); @@ -100,7 +67,7 @@ impl<'a, 'tcx, 'rcx> BlanketImplFinder <'a, 'tcx, 'rcx> { "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}", param_env, trait_ref, ty ); - let may_apply = match infcx.evaluate_obligation( + match infcx.evaluate_obligation( &traits::Obligation::new( cause, param_env, @@ -109,56 +76,53 @@ impl<'a, 'tcx, 'rcx> BlanketImplFinder <'a, 'tcx, 'rcx> { ) { Ok(eval_result) => eval_result.may_apply(), Err(traits::OverflowError) => true, // overflow doesn't mean yes *or* no - }; - debug!("get_blanket_impls: found applicable impl: {}\ - for trait_ref={:?}, ty={:?}", - may_apply, trait_ref, ty); - - if !may_apply { - return } - self.cx.generated_synthetics.borrow_mut() - .insert((def_id, trait_def_id)); - let trait_ = hir::TraitRef { - path: get_path_for_type(infcx.tcx, - trait_def_id, - hir::def::Def::Trait), - hir_ref_id: hir::DUMMY_HIR_ID, - }; - let provided_trait_methods = - infcx.tcx.provided_trait_methods(trait_def_id) - .into_iter() - .map(|meth| meth.ident.to_string()) - .collect(); - - let ty = self.cx.get_real_ty(def_id, def_ctor, &real_name, generics); - let predicates = infcx.tcx.predicates_of(impl_def_id); - - impls.push(Item { - source: infcx.tcx.def_span(impl_def_id).clean(self.cx), - name: None, - attrs: Default::default(), - visibility: None, - def_id: self.cx.next_def_id(impl_def_id.krate), - stability: None, - deprecation: None, - inner: ImplItem(Impl { - unsafety: hir::Unsafety::Normal, - generics: (t_generics, &predicates).clean(self.cx), - provided_trait_methods, - trait_: Some(trait_.clean(self.cx)), - for_: ty.clean(self.cx), - items: infcx.tcx.associated_items(impl_def_id) - .collect::>() - .clean(self.cx), - polarity: None, - synthetic: false, - blanket_impl: Some(infcx.tcx.type_of(impl_def_id) - .clean(self.cx)), - }), - }); + } else { + false } }); + debug!("get_blanket_impls: found applicable impl: {}\ + for trait_ref={:?}, ty={:?}", + may_apply, trait_ref, ty); + if !may_apply { + return; + } + + self.cx.generated_synthetics.borrow_mut() + .insert((ty, trait_def_id)); + let provided_trait_methods = + self.cx.tcx.provided_trait_methods(trait_def_id) + .into_iter() + .map(|meth| meth.ident.to_string()) + .collect(); + + impls.push(Item { + source: self.cx.tcx.def_span(impl_def_id).clean(self.cx), + name: None, + attrs: Default::default(), + visibility: None, + def_id: self.cx.next_def_id(impl_def_id.krate), + stability: None, + deprecation: None, + inner: ImplItem(Impl { + unsafety: hir::Unsafety::Normal, + generics: ( + self.cx.tcx.generics_of(impl_def_id), + &self.cx.tcx.explicit_predicates_of(impl_def_id), + ).clean(self.cx), + provided_trait_methods, + // FIXME(eddyb) compute both `trait_` and `for_` from + // the post-inference `trait_ref`, as it's more accurate. + trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()), + for_: ty.clean(self.cx), + items: self.cx.tcx.associated_items(impl_def_id) + .collect::>() + .clean(self.cx), + polarity: None, + synthetic: false, + blanket_impl: Some(trait_ref.self_ty().clean(self.cx)), + }), + }); }); } impls diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 45e1ea2d3a39d..ad211763a6c46 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -7,8 +7,8 @@ use std::mem; use std::fmt::{self, Write}; use std::ops; -use syntax::symbol::Symbol; -use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind, LitKind}; +use syntax::symbol::{Symbol, sym}; +use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, LitKind}; use syntax::parse::ParseSess; use syntax::feature_gate::Features; @@ -16,7 +16,7 @@ use syntax_pos::Span; use crate::html::escape::Escape; -#[derive(Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Cfg { /// Accepts all configurations. True, @@ -41,9 +41,9 @@ pub struct InvalidCfgError { impl Cfg { /// Parses a `NestedMetaItem` into a `Cfg`. fn parse_nested(nested_cfg: &NestedMetaItem) -> Result { - match nested_cfg.node { - NestedMetaItemKind::MetaItem(ref cfg) => Cfg::parse(cfg), - NestedMetaItemKind::Literal(ref lit) => Err(InvalidCfgError { + match nested_cfg { + NestedMetaItem::MetaItem(ref cfg) => Cfg::parse(cfg), + NestedMetaItem::Literal(ref lit) => Err(InvalidCfgError { msg: "unexpected literal", span: lit.span, }), @@ -58,7 +58,13 @@ impl Cfg { /// If the content is not properly formatted, it will return an error indicating what and where /// the error is. pub fn parse(cfg: &MetaItem) -> Result { - let name = cfg.name(); + let name = match cfg.ident() { + Some(ident) => ident.name, + None => return Err(InvalidCfgError { + msg: "expected a single identifier", + span: cfg.span + }), + }; match cfg.node { MetaItemKind::Word => Ok(Cfg::Cfg(name, None)), MetaItemKind::NameValue(ref lit) => match lit.node { @@ -180,7 +186,7 @@ impl Cfg { fn should_use_with_in_description(&self) -> bool { match *self { - Cfg::Cfg(ref name, _) if name == &"target_feature" => true, + Cfg::Cfg(name, _) if name == sym::target_feature => true, _ => false, } } @@ -332,7 +338,6 @@ impl<'a> fmt::Display for Html<'a> { ("debug_assertions", None) => "debug-assertions enabled", ("target_os", Some(os)) => match &*os.as_str() { "android" => "Android", - "bitrig" => "Bitrig", "dragonfly" => "DragonFly BSD", "emscripten" => "Emscripten", "freebsd" => "FreeBSD", @@ -408,11 +413,12 @@ impl<'a> fmt::Display for Html<'a> { mod test { use super::Cfg; - use syntax::symbol::Symbol; + use syntax_pos::DUMMY_SP; use syntax::ast::*; + use syntax::attr; use syntax::source_map::dummy_spanned; - use syntax_pos::DUMMY_SP; - use syntax::with_globals; + use syntax::symbol::Symbol; + use syntax::with_default_globals; fn word_cfg(s: &str) -> Cfg { Cfg::Cfg(Symbol::intern(s), None) @@ -424,7 +430,7 @@ mod test { fn dummy_meta_item_word(name: &str) -> MetaItem { MetaItem { - ident: Path::from_ident(Ident::from_str(name)), + path: Path::from_ident(Ident::from_str(name)), node: MetaItemKind::Word, span: DUMMY_SP, } @@ -433,12 +439,12 @@ mod test { macro_rules! dummy_meta_item_list { ($name:ident, [$($list:ident),* $(,)?]) => { MetaItem { - ident: Path::from_ident(Ident::from_str(stringify!($name))), + path: Path::from_ident(Ident::from_str(stringify!($name))), node: MetaItemKind::List(vec![ $( - dummy_spanned(NestedMetaItemKind::MetaItem( + NestedMetaItem::MetaItem( dummy_meta_item_word(stringify!($list)), - )), + ), )* ]), span: DUMMY_SP, @@ -447,10 +453,10 @@ mod test { ($name:ident, [$($list:expr),* $(,)?]) => { MetaItem { - ident: Path::from_ident(Ident::from_str(stringify!($name))), + path: Path::from_ident(Ident::from_str(stringify!($name))), node: MetaItemKind::List(vec![ $( - dummy_spanned(NestedMetaItemKind::MetaItem($list)), + NestedMetaItem::MetaItem($list), )* ]), span: DUMMY_SP, @@ -460,7 +466,7 @@ mod test { #[test] fn test_cfg_not() { - with_globals(|| { + with_default_globals(|| { assert_eq!(!Cfg::False, Cfg::True); assert_eq!(!Cfg::True, Cfg::False); assert_eq!(!word_cfg("test"), Cfg::Not(Box::new(word_cfg("test")))); @@ -478,7 +484,7 @@ mod test { #[test] fn test_cfg_and() { - with_globals(|| { + with_default_globals(|| { let mut x = Cfg::False; x &= Cfg::True; assert_eq!(x, Cfg::False); @@ -530,7 +536,7 @@ mod test { #[test] fn test_cfg_or() { - with_globals(|| { + with_default_globals(|| { let mut x = Cfg::True; x |= Cfg::False; assert_eq!(x, Cfg::True); @@ -582,18 +588,14 @@ mod test { #[test] fn test_parse_ok() { - with_globals(|| { + with_default_globals(|| { let mi = dummy_meta_item_word("all"); assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all"))); - let mi = MetaItem { - ident: Path::from_ident(Ident::from_str("all")), - node: MetaItemKind::NameValue(dummy_spanned(LitKind::Str( - Symbol::intern("done"), - StrStyle::Cooked, - ))), - span: DUMMY_SP, - }; + let mi = attr::mk_name_value_item_str( + Ident::from_str("all"), + dummy_spanned(Symbol::intern("done")) + ); assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done"))); let mi = dummy_meta_item_list!(all, [a, b]); @@ -620,12 +622,13 @@ mod test { #[test] fn test_parse_err() { - with_globals(|| { - let mi = MetaItem { - ident: Path::from_ident(Ident::from_str("foo")), - node: MetaItemKind::NameValue(dummy_spanned(LitKind::Bool(false))), - span: DUMMY_SP, - }; + with_default_globals(|| { + let mi = attr::mk_name_value_item( + DUMMY_SP, + Ident::from_str("foo"), + LitKind::Bool(false), + DUMMY_SP, + ); assert!(Cfg::parse(&mi).is_err()); let mi = dummy_meta_item_list!(not, [a, b]); @@ -658,7 +661,7 @@ mod test { #[test] fn test_render_short_html() { - with_globals(|| { + with_default_globals(|| { assert_eq!( word_cfg("unix").render_short_html(), "Unix" @@ -738,7 +741,7 @@ mod test { #[test] fn test_render_long_html() { - with_globals(|| { + with_default_globals(|| { assert_eq!( word_cfg("unix").render_long_html(), "This is supported on Unix only." diff --git a/src/librustdoc/clean/def_ctor.rs b/src/librustdoc/clean/def_ctor.rs deleted file mode 100644 index fce86d590159b..0000000000000 --- a/src/librustdoc/clean/def_ctor.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::core::DocContext; - -use super::*; - -pub fn get_def_from_def_id(cx: &DocContext<'_, '_, '_>, - def_id: DefId, - callback: &F, -) -> Vec -where F: Fn(& dyn Fn(DefId) -> Def) -> Vec { - let ty = cx.tcx.type_of(def_id); - - match ty.sty { - ty::Adt(adt, _) => callback(&match adt.adt_kind() { - AdtKind::Struct => Def::Struct, - AdtKind::Enum => Def::Enum, - AdtKind::Union => Def::Union, - }), - ty::Int(_) | - ty::Uint(_) | - ty::Float(_) | - ty::Str | - ty::Bool | - ty::Char => callback(&move |_: DefId| { - match ty.sty { - ty::Int(x) => Def::PrimTy(hir::Int(x)), - ty::Uint(x) => Def::PrimTy(hir::Uint(x)), - ty::Float(x) => Def::PrimTy(hir::Float(x)), - ty::Str => Def::PrimTy(hir::Str), - ty::Bool => Def::PrimTy(hir::Bool), - ty::Char => Def::PrimTy(hir::Char), - _ => unreachable!(), - } - }), - _ => { - debug!("Unexpected type {:?}", def_id); - Vec::new() - } - } -} - -pub fn get_def_from_node_id(cx: &DocContext<'_, '_, '_>, - id: ast::NodeId, - name: String, - callback: &F, -) -> Vec -where F: Fn(& dyn Fn(DefId) -> Def, String) -> Vec { - let item = &cx.tcx.hir().expect_item(id).node; - - callback(&match *item { - hir::ItemKind::Struct(_, _) => Def::Struct, - hir::ItemKind::Union(_, _) => Def::Union, - hir::ItemKind::Enum(_, _) => Def::Enum, - _ => panic!("Unexpected type {:?} {:?}", item, id), - }, name) -} diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cdffbdd540f8c..9259b3b5d3abb 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -3,11 +3,12 @@ use std::iter::once; use syntax::ast; -use syntax::ext::base::{MacroKind, SyntaxExtension}; +use syntax::ext::base::MacroKind; +use syntax::symbol::sym; use syntax_pos::Span; use rustc::hir; -use rustc::hir::def::{Def, CtorKind}; +use rustc::hir::def::{Res, DefKind, CtorKind}; use rustc::hir::def_id::DefId; use rustc_metadata::cstore::LoadedMacro; use rustc::ty; @@ -36,75 +37,72 @@ use super::Clean; /// The returned value is `None` if the definition could not be inlined, /// and `Some` of a vector of items if it was successfully expanded. pub fn try_inline( - cx: &DocContext<'_, '_, '_>, - def: Def, + cx: &DocContext<'_>, + res: Res, name: ast::Name, visited: &mut FxHashSet -) - -> Option> { - let did = if let Some(did) = def.opt_def_id() { +) -> Option> { + let did = if let Some(did) = res.opt_def_id() { did } else { return None; }; if did.is_local() { return None } let mut ret = Vec::new(); - let inner = match def { - Def::Trait(did) => { + let inner = match res { + Res::Def(DefKind::Trait, did) => { record_extern_fqn(cx, did, clean::TypeKind::Trait); ret.extend(build_impls(cx, did)); clean::TraitItem(build_external_trait(cx, did)) } - Def::Fn(did) => { + Res::Def(DefKind::Fn, did) => { record_extern_fqn(cx, did, clean::TypeKind::Function); clean::FunctionItem(build_external_function(cx, did)) } - Def::Struct(did) => { + Res::Def(DefKind::Struct, did) => { record_extern_fqn(cx, did, clean::TypeKind::Struct); ret.extend(build_impls(cx, did)); clean::StructItem(build_struct(cx, did)) } - Def::Union(did) => { + Res::Def(DefKind::Union, did) => { record_extern_fqn(cx, did, clean::TypeKind::Union); ret.extend(build_impls(cx, did)); clean::UnionItem(build_union(cx, did)) } - Def::TyAlias(did) => { + Res::Def(DefKind::TyAlias, did) => { record_extern_fqn(cx, did, clean::TypeKind::Typedef); ret.extend(build_impls(cx, did)); clean::TypedefItem(build_type_alias(cx, did), false) } - Def::Enum(did) => { + Res::Def(DefKind::Enum, did) => { record_extern_fqn(cx, did, clean::TypeKind::Enum); ret.extend(build_impls(cx, did)); clean::EnumItem(build_enum(cx, did)) } - Def::ForeignTy(did) => { + Res::Def(DefKind::ForeignTy, did) => { record_extern_fqn(cx, did, clean::TypeKind::Foreign); ret.extend(build_impls(cx, did)); clean::ForeignTypeItem } // Never inline enum variants but leave them shown as re-exports. - Def::Variant(..) => return None, + Res::Def(DefKind::Variant, _) => return None, // Assume that enum variants and struct types are re-exported next to // their constructors. - Def::VariantCtor(..) | - Def::StructCtor(..) | - Def::SelfCtor(..) => return Some(Vec::new()), - Def::Mod(did) => { + Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => return Some(Vec::new()), + Res::Def(DefKind::Mod, did) => { record_extern_fqn(cx, did, clean::TypeKind::Module); clean::ModuleItem(build_module(cx, did, visited)) } - Def::Static(did, mtbl) => { + Res::Def(DefKind::Static, did) => { record_extern_fqn(cx, did, clean::TypeKind::Static); - clean::StaticItem(build_static(cx, did, mtbl)) + clean::StaticItem(build_static(cx, did, cx.tcx.is_mutable_static(did))) } - Def::Const(did) => { + Res::Def(DefKind::Const, did) => { record_extern_fqn(cx, did, clean::TypeKind::Const); clean::ConstantItem(build_const(cx, did)) } // FIXME: proc-macros don't propagate attributes or spans across crates, so they look empty - Def::Macro(did, MacroKind::Bang) => { + Res::Def(DefKind::Macro(MacroKind::Bang), did) => { let mac = build_macro(cx, did, name); if let clean::MacroItem(..) = mac { record_extern_fqn(cx, did, clean::TypeKind::Macro); @@ -129,15 +127,15 @@ pub fn try_inline( Some(ret) } -pub fn try_inline_glob(cx: &DocContext<'_, '_, '_>, def: Def, visited: &mut FxHashSet) +pub fn try_inline_glob(cx: &DocContext<'_>, res: Res, visited: &mut FxHashSet) -> Option> { - if def == Def::Err { return None } - let did = def.def_id(); + if res == Res::Err { return None } + let did = res.def_id(); if did.is_local() { return None } - match def { - Def::Mod(did) => { + match res { + Res::Def(DefKind::Mod, did) => { let m = build_module(cx, did, visited); Some(m.items) } @@ -146,7 +144,7 @@ pub fn try_inline_glob(cx: &DocContext<'_, '_, '_>, def: Def, visited: &mut FxHa } } -pub fn load_attrs(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Attributes { +pub fn load_attrs(cx: &DocContext<'_>, did: DefId) -> clean::Attributes { cx.tcx.get_attrs(did).clean(cx) } @@ -154,7 +152,7 @@ pub fn load_attrs(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Attributes /// /// These names are used later on by HTML rendering to generate things like /// source links back to the original item. -pub fn record_extern_fqn(cx: &DocContext<'_, '_, '_>, did: DefId, kind: clean::TypeKind) { +pub fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKind) { let mut crate_name = cx.tcx.crate_name(did.krate).to_string(); if did.is_local() { crate_name = cx.crate_name.clone().unwrap_or(crate_name); @@ -182,14 +180,14 @@ pub fn record_extern_fqn(cx: &DocContext<'_, '_, '_>, did: DefId, kind: clean::T } } -pub fn build_external_trait(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Trait { +pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { let auto_trait = cx.tcx.trait_def(did).has_auto_impl; let trait_items = cx.tcx.associated_items(did).map(|item| item.clean(cx)).collect(); let predicates = cx.tcx.predicates_of(did); let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); - let is_spotlight = load_attrs(cx, did).has_doc_flag("spotlight"); + let is_spotlight = load_attrs(cx, did).has_doc_flag(sym::spotlight); let is_auto = cx.tcx.trait_is_auto(did); clean::Trait { auto: auto_trait, @@ -202,7 +200,7 @@ pub fn build_external_trait(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::T } } -fn build_external_function(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Function { +fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { let sig = cx.tcx.fn_sig(did); let constness = if cx.tcx.is_min_const_fn(did) { @@ -212,20 +210,25 @@ fn build_external_function(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Fu }; let predicates = cx.tcx.predicates_of(did); + let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); + let decl = (did, sig).clean(cx); + let (all_types, ret_types) = clean::get_all_types(&generics, &decl, cx); clean::Function { - decl: (did, sig).clean(cx), - generics: (cx.tcx.generics_of(did), &predicates).clean(cx), + decl, + generics, header: hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness: hir::IsAsync::NotAsync, - } + }, + all_types, + ret_types, } } -fn build_enum(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Enum { - let predicates = cx.tcx.predicates_of(did); +fn build_enum(cx: &DocContext<'_>, did: DefId) -> clean::Enum { + let predicates = cx.tcx.explicit_predicates_of(did); clean::Enum { generics: (cx.tcx.generics_of(did), &predicates).clean(cx), @@ -234,8 +237,8 @@ fn build_enum(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Enum { } } -fn build_struct(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Struct { - let predicates = cx.tcx.predicates_of(did); +fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct { + let predicates = cx.tcx.explicit_predicates_of(did); let variant = cx.tcx.adt_def(did).non_enum_variant(); clean::Struct { @@ -250,8 +253,8 @@ fn build_struct(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Struct { } } -fn build_union(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Union { - let predicates = cx.tcx.predicates_of(did); +fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union { + let predicates = cx.tcx.explicit_predicates_of(did); let variant = cx.tcx.adt_def(did).non_enum_variant(); clean::Union { @@ -262,8 +265,8 @@ fn build_union(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Union { } } -fn build_type_alias(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Typedef { - let predicates = cx.tcx.predicates_of(did); +fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef { + let predicates = cx.tcx.explicit_predicates_of(did); clean::Typedef { type_: cx.tcx.type_of(did).clean(cx), @@ -271,7 +274,7 @@ fn build_type_alias(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Typedef { } } -pub fn build_impls(cx: &DocContext<'_, '_, '_>, did: DefId) -> Vec { +pub fn build_impls(cx: &DocContext<'_>, did: DefId) -> Vec { let tcx = cx.tcx; let mut impls = Vec::new(); @@ -282,7 +285,7 @@ pub fn build_impls(cx: &DocContext<'_, '_, '_>, did: DefId) -> Vec impls } -pub fn build_impl(cx: &DocContext<'_, '_, '_>, did: DefId, ret: &mut Vec) { +pub fn build_impl(cx: &DocContext<'_>, did: DefId, ret: &mut Vec) { if !cx.renderinfo.borrow_mut().inlined.insert(did) { return } @@ -302,7 +305,7 @@ pub fn build_impl(cx: &DocContext<'_, '_, '_>, did: DefId, ret: &mut Vec { t.clean(cx) } @@ -322,9 +325,9 @@ pub fn build_impl(cx: &DocContext<'_, '_, '_>, did: DefId, ret: &mut Vec { ( item_ids.iter() @@ -393,7 +396,7 @@ pub fn build_impl(cx: &DocContext<'_, '_, '_>, did: DefId, ret: &mut Vec, + cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet ) -> clean::Module { @@ -404,16 +407,16 @@ fn build_module( is_crate: false, }; - fn fill_in(cx: &DocContext<'_, '_, '_>, did: DefId, items: &mut Vec, + fn fill_in(cx: &DocContext<'_>, did: DefId, items: &mut Vec, visited: &mut FxHashSet) { // If we're re-exporting a re-export it may actually re-export something in // two namespaces, so the target may be listed twice. Make sure we only // visit each node at most once. for &item in cx.tcx.item_children(did).iter() { - let def_id = item.def.def_id(); + let def_id = item.res.def_id(); if item.vis == ty::Visibility::Public { if did == def_id || !visited.insert(def_id) { continue } - if let Some(i) = try_inline(cx, item.def, item.ident.name, visited) { + if let Some(i) = try_inline(cx, item.res, item.ident.name, visited) { items.extend(i) } } @@ -421,22 +424,22 @@ fn build_module( } } -pub fn print_inlined_const(cx: &DocContext<'_, '_, '_>, did: DefId) -> String { - if let Some(node_id) = cx.tcx.hir().as_local_node_id(did) { - cx.tcx.hir().node_to_pretty_string(node_id) +pub fn print_inlined_const(cx: &DocContext<'_>, did: DefId) -> String { + if let Some(node_id) = cx.tcx.hir().as_local_hir_id(did) { + cx.tcx.hir().hir_to_pretty_string(node_id) } else { cx.tcx.rendered_const(did) } } -fn build_const(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Constant { +fn build_const(cx: &DocContext<'_>, did: DefId) -> clean::Constant { clean::Constant { type_: cx.tcx.type_of(did).clean(cx), expr: print_inlined_const(cx, did) } } -fn build_static(cx: &DocContext<'_, '_, '_>, did: DefId, mutable: bool) -> clean::Static { +fn build_static(cx: &DocContext<'_>, did: DefId, mutable: bool) -> clean::Static { clean::Static { type_: cx.tcx.type_of(did).clean(cx), mutability: if mutable {clean::Mutable} else {clean::Immutable}, @@ -444,7 +447,7 @@ fn build_static(cx: &DocContext<'_, '_, '_>, did: DefId, mutable: bool) -> clean } } -fn build_macro(cx: &DocContext<'_, '_, '_>, did: DefId, name: ast::Name) -> clean::ItemEnum { +fn build_macro(cx: &DocContext<'_>, did: DefId, name: ast::Name) -> clean::ItemEnum { let imported_from = cx.tcx.original_crate_name(did.krate); match cx.cstore.load_macro_untracked(did, cx.sess()) { LoadedMacro::MacroDef(def) => { @@ -467,18 +470,12 @@ fn build_macro(cx: &DocContext<'_, '_, '_>, did: DefId, name: ast::Name) -> clea }) } LoadedMacro::ProcMacro(ext) => { - let helpers = match &*ext { - &SyntaxExtension::ProcMacroDerive(_, ref syms, ..) => { syms.clean(cx) } - _ => Vec::new(), - }; - clean::ProcMacroItem(clean::ProcMacro { - kind: ext.kind(), - helpers, + kind: ext.macro_kind(), + helpers: ext.helper_attrs.clean(cx), }) } } - } /// A trait's generics clause actually contains all of the predicates for all of @@ -546,7 +543,7 @@ fn separate_supertrait_bounds(mut g: clean::Generics) (g, ty_bounds) } -pub fn record_extern_trait(cx: &DocContext<'_, '_, '_>, did: DefId) { +pub fn record_extern_trait(cx: &DocContext<'_>, did: DefId) { if did.is_local() { return; } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d88d0dab4f0eb..3fe048a6986bb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + //! This module contains the "cleaned" pieces of the AST, and the functions //! that clean them. @@ -6,22 +8,20 @@ pub mod cfg; mod simplify; mod auto_trait; mod blanket_impl; -pub mod def_ctor; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -use rustc_data_structures::sync::Lrc; use rustc_target::spec::abi::Abi; use rustc_typeck::hir_ty_to_ty; use rustc::infer::region_constraints::{RegionConstraintData, Constraint}; use rustc::middle::resolve_lifetime as rl; use rustc::middle::lang_items; use rustc::middle::stability; -use rustc::mir::interpret::GlobalId; -use rustc::hir::{self, GenericArg, HirVec}; -use rustc::hir::def::{self, Def, CtorKind}; +use rustc::mir::interpret::{GlobalId, ConstValue}; +use rustc::hir; +use rustc::hir::def::{CtorKind, DefKind, Res}; use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc::ty::subst::{InternalSubsts, SubstsRef}; -use rustc::ty::{self, TyCtxt, Region, RegionVid, Ty, AdtKind}; +use rustc::ty::subst::{InternalSubsts, SubstsRef, UnpackedKind}; +use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind}; use rustc::ty::fold::TypeFolder; use rustc::ty::layout::VariantIdx; use rustc::util::nodemap::{FxHashMap, FxHashSet}; @@ -30,9 +30,9 @@ use syntax::attr; use syntax::ext::base::MacroKind; use syntax::source_map::{dummy_spanned, Spanned}; use syntax::ptr::P; -use syntax::symbol::keywords::{self, Keyword}; +use syntax::symbol::{Symbol, kw, sym}; use syntax::symbol::InternedString; -use syntax_pos::{self, DUMMY_SP, Pos, FileName}; +use syntax_pos::{self, Pos, FileName}; use std::collections::hash_map::Entry; use std::fmt; @@ -41,7 +41,6 @@ use std::default::Default; use std::{mem, slice, vec}; use std::iter::{FromIterator, once}; use std::rc::Rc; -use std::str::FromStr; use std::cell::RefCell; use std::sync::Arc; use std::u32; @@ -71,56 +70,56 @@ thread_local!(pub static MAX_DEF_ID: RefCell> = Defau const FN_OUTPUT_NAME: &'static str = "Output"; // extract the stability index for a node from tcx, if possible -fn get_stability(cx: &DocContext<'_, '_, '_>, def_id: DefId) -> Option { +fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option { cx.tcx.lookup_stability(def_id).clean(cx) } -fn get_deprecation(cx: &DocContext<'_, '_, '_>, def_id: DefId) -> Option { +fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option { cx.tcx.lookup_deprecation(def_id).clean(cx) } pub trait Clean { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> T; + fn clean(&self, cx: &DocContext<'_>) -> T; } impl, U> Clean> for [T] { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec { + fn clean(&self, cx: &DocContext<'_>) -> Vec { self.iter().map(|x| x.clean(cx)).collect() } } impl, U, V: Idx> Clean> for IndexVec { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> IndexVec { + fn clean(&self, cx: &DocContext<'_>) -> IndexVec { self.iter().map(|x| x.clean(cx)).collect() } } impl, U> Clean for P { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> U { + fn clean(&self, cx: &DocContext<'_>) -> U { (**self).clean(cx) } } impl, U> Clean for Rc { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> U { + fn clean(&self, cx: &DocContext<'_>) -> U { (**self).clean(cx) } } impl, U> Clean> for Option { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, cx: &DocContext<'_>) -> Option { self.as_ref().map(|v| v.clean(cx)) } } impl Clean for ty::Binder where T: Clean { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> U { + fn clean(&self, cx: &DocContext<'_>) -> U { self.skip_binder().clean(cx) } } impl, U> Clean> for P<[T]> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec { + fn clean(&self, cx: &DocContext<'_>) -> Vec { self.iter().map(|x| x.clean(cx)).collect() } } @@ -139,8 +138,8 @@ pub struct Crate { pub masked_crates: FxHashSet, } -impl<'a, 'tcx, 'rcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Crate { +impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { + fn clean(&self, cx: &DocContext<'_>) -> Crate { use crate::visit_lib::LibEmbargoVisitor; { @@ -160,7 +159,7 @@ impl<'a, 'tcx, 'rcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> // Clean the crate, translating the entire libsyntax AST to one that is // understood by rustdoc. - let mut module = self.module.clean(cx); + let mut module = self.module.as_ref().unwrap().clean(cx); let mut masked_crates = FxHashSet::default(); match module.inner { @@ -169,7 +168,7 @@ impl<'a, 'tcx, 'rcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> // `compiler_builtins` should be masked too, but we can't apply // `#[doc(masked)]` to the injected `extern crate` because it's unstable. if it.is_extern_crate() - && (it.attrs.has_doc_flag("masked") + && (it.attrs.has_doc_flag(sym::masked) || self.cx.tcx.is_compiler_builtins(it.def_id.krate)) { masked_crates.insert(it.def_id.krate); @@ -224,7 +223,7 @@ impl<'a, 'tcx, 'rcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct ExternalCrate { pub name: String, pub src: FileName, @@ -234,7 +233,7 @@ pub struct ExternalCrate { } impl Clean for CrateNum { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> ExternalCrate { + fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate { let root = DefId { krate: *self, index: CRATE_DEF_INDEX }; let krate_span = cx.tcx.def_span(root); let krate_src = cx.sess().source_map().span_to_filename(krate_span); @@ -256,13 +255,13 @@ impl Clean for CrateNum { // Also note that this does not attempt to deal with modules tagged // duplicately for the same primitive. This is handled later on when // rendering by delegating everything to a hash map. - let as_primitive = |def: Def| { - if let Def::Mod(def_id) = def { + let as_primitive = |res: Res| { + if let Res::Def(DefKind::Mod, def_id) = res { let attrs = cx.tcx.get_attrs(def_id).clean(cx); let mut prim = None; - for attr in attrs.lists("doc") { + for attr in attrs.lists(sym::doc) { if let Some(v) = attr.value_str() { - if attr.check_name("primitive") { + if attr.check_name(sym::primitive) { prim = PrimitiveType::from_str(&v.as_str()); if prim.is_some() { break; @@ -280,34 +279,36 @@ impl Clean for CrateNum { let item = cx.tcx.hir().expect_item(id.id); match item.node { hir::ItemKind::Mod(_) => { - as_primitive(Def::Mod(cx.tcx.hir().local_def_id(id.id))) + as_primitive(Res::Def( + DefKind::Mod, + cx.tcx.hir().local_def_id_from_hir_id(id.id), + )) } hir::ItemKind::Use(ref path, hir::UseKind::Single) if item.vis.node.is_pub() => { - as_primitive(path.def).map(|(_, prim, attrs)| { + as_primitive(path.res).map(|(_, prim, attrs)| { // Pretend the primitive is local. - (cx.tcx.hir().local_def_id(id.id), prim, attrs) + (cx.tcx.hir().local_def_id_from_hir_id(id.id), prim, attrs) }) } _ => None } }).collect() } else { - cx.tcx.item_children(root).iter().map(|item| item.def) + cx.tcx.item_children(root).iter().map(|item| item.res) .filter_map(as_primitive).collect() }; - let as_keyword = |def: Def| { - if let Def::Mod(def_id) = def { + let as_keyword = |res: Res| { + if let Res::Def(DefKind::Mod, def_id) = res { let attrs = cx.tcx.get_attrs(def_id).clean(cx); let mut keyword = None; - for attr in attrs.lists("doc") { + for attr in attrs.lists(sym::doc) { if let Some(v) = attr.value_str() { - if attr.check_name("keyword") { - keyword = Keyword::from_str(&v.as_str()).ok() - .map(|x| x.name().to_string()); - if keyword.is_some() { - break + if attr.check_name(sym::keyword) { + if v.is_doc_keyword() { + keyword = Some(v.to_string()); + break; } // FIXME: should warn on unknown keywords? } @@ -322,19 +323,22 @@ impl Clean for CrateNum { let item = cx.tcx.hir().expect_item(id.id); match item.node { hir::ItemKind::Mod(_) => { - as_keyword(Def::Mod(cx.tcx.hir().local_def_id(id.id))) + as_keyword(Res::Def( + DefKind::Mod, + cx.tcx.hir().local_def_id_from_hir_id(id.id), + )) } hir::ItemKind::Use(ref path, hir::UseKind::Single) if item.vis.node.is_pub() => { - as_keyword(path.def).map(|(_, prim, attrs)| { - (cx.tcx.hir().local_def_id(id.id), prim, attrs) + as_keyword(path.res).map(|(_, prim, attrs)| { + (cx.tcx.hir().local_def_id_from_hir_id(id.id), prim, attrs) }) } _ => None } }).collect() } else { - cx.tcx.item_children(root).iter().map(|item| item.def) + cx.tcx.item_children(root).iter().map(|item| item.res) .filter_map(as_keyword).collect() }; @@ -351,7 +355,7 @@ impl Clean for CrateNum { /// Anything with a source location and set of attributes and, optionally, a /// name. That is, anything that can be documented. This doesn't correspond /// directly to the AST's concept of an item; it's a strict superset. -#[derive(Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone)] pub struct Item { /// Stringified span pub source: Span, @@ -420,11 +424,14 @@ impl Item { pub fn is_enum(&self) -> bool { self.type_() == ItemType::Enum } + pub fn is_variant(&self) -> bool { + self.type_() == ItemType::Variant + } pub fn is_associated_type(&self) -> bool { - self.type_() == ItemType::AssociatedType + self.type_() == ItemType::AssocType } pub fn is_associated_const(&self) -> bool { - self.type_() == ItemType::AssociatedConst + self.type_() == ItemType::AssocConst } pub fn is_method(&self) -> bool { self.type_() == ItemType::Method @@ -491,7 +498,7 @@ impl Item { pub fn is_non_exhaustive(&self) -> bool { self.attrs.other_attrs.iter() - .any(|a| a.name().as_str() == "non_exhaustive") + .any(|a| a.check_name(sym::non_exhaustive)) } /// Returns a documentation-level item type from the item. @@ -507,9 +514,21 @@ impl Item { .as_ref() .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref())) } + pub fn is_default(&self) -> bool { + match self.inner { + ItemEnum::MethodItem(ref meth) => { + if let Some(defaultness) = meth.defaultness { + defaultness.has_value() && !defaultness.is_final() + } else { + false + } + } + _ => false, + } + } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub enum ItemEnum { ExternCrateItem(String, Option), ImportItem(Import), @@ -541,8 +560,8 @@ pub enum ItemEnum { MacroItem(Macro), ProcMacroItem(ProcMacro), PrimitiveItem(PrimitiveType), - AssociatedConstItem(Type, Option), - AssociatedTypeItem(Vec, Option), + AssocConstItem(Type, Option), + AssocTypeItem(Vec, Option), /// An item that has been stripped by a rustdoc pass StrippedItem(Box), KeywordItem(String), @@ -569,20 +588,20 @@ impl ItemEnum { pub fn is_associated(&self) -> bool { match *self { ItemEnum::TypedefItem(_, _) | - ItemEnum::AssociatedTypeItem(_, _) => true, + ItemEnum::AssocTypeItem(_, _) => true, _ => false, } } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Module { pub items: Vec, pub is_crate: bool, } -impl Clean for doctree::Module { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::Module<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { let name = if self.name.is_some() { self.name.expect("No name provided").clean(cx) } else { @@ -601,7 +620,7 @@ impl Clean for doctree::Module { items.extend(self.unions.iter().map(|x| x.clean(cx))); items.extend(self.enums.iter().map(|x| x.clean(cx))); items.extend(self.fns.iter().map(|x| x.clean(cx))); - items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx))); + items.extend(self.foreigns.iter().map(|x| x.clean(cx))); items.extend(self.mods.iter().map(|x| x.clean(cx))); items.extend(self.typedefs.iter().map(|x| x.clean(cx))); items.extend(self.existentials.iter().map(|x| x.clean(cx))); @@ -647,7 +666,7 @@ impl Clean for doctree::Module { pub struct ListAttributesIter<'a> { attrs: slice::Iter<'a, ast::Attribute>, current_list: vec::IntoIter, - name: &'a str + name: Symbol, } impl<'a> Iterator for ListAttributesIter<'a> { @@ -680,11 +699,11 @@ impl<'a> Iterator for ListAttributesIter<'a> { pub trait AttributesExt { /// Finds an attribute as List and returns the list of attributes nested inside. - fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a>; + fn lists<'a>(&'a self, name: Symbol) -> ListAttributesIter<'a>; } impl AttributesExt for [ast::Attribute] { - fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> { + fn lists<'a>(&'a self, name: Symbol) -> ListAttributesIter<'a> { ListAttributesIter { attrs: self.iter(), current_list: Vec::new().into_iter(), @@ -695,11 +714,11 @@ impl AttributesExt for [ast::Attribute] { pub trait NestedAttributesExt { /// Returns `true` if the attribute list contains a specific `Word` - fn has_word(self, word: &str) -> bool; + fn has_word(self, word: Symbol) -> bool; } impl> NestedAttributesExt for I { - fn has_word(self, word: &str) -> bool { + fn has_word(self, word: Symbol) -> bool { self.into_iter().any(|attr| attr.is_word() && attr.check_name(word)) } } @@ -712,7 +731,7 @@ impl> NestedAttributesExt for I { /// Included files are kept separate from inline doc comments so that proper line-number /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are /// kept separate because of issue #42760. -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum DocFragment { /// A doc fragment created from a `///` or `//!` doc comment. SugaredDoc(usize, syntax_pos::Span, String), @@ -762,7 +781,7 @@ impl<'a> FromIterator<&'a DocFragment> for String { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct Attributes { pub doc_strings: Vec, pub other_attrs: Vec, @@ -776,15 +795,15 @@ pub struct Attributes { impl Attributes { /// Extracts the content from an attribute `#[doc(cfg(content))]`. fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { - use syntax::ast::NestedMetaItemKind::MetaItem; + use syntax::ast::NestedMetaItem::MetaItem; if let ast::MetaItemKind::List(ref nmis) = mi.node { if nmis.len() == 1 { - if let MetaItem(ref cfg_mi) = nmis[0].node { - if cfg_mi.check_name("cfg") { + if let MetaItem(ref cfg_mi) = nmis[0] { + if cfg_mi.check_name(sym::cfg) { if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.node { if cfg_nmis.len() == 1 { - if let MetaItem(ref content_mi) = cfg_nmis[0].node { + if let MetaItem(ref content_mi) = cfg_nmis[0] { return Some(content_mi); } } @@ -805,7 +824,7 @@ impl Attributes { { mi.meta_item_list().and_then(|list| { for meta in list { - if meta.check_name("include") { + if meta.check_name(sym::include) { // the actual compiled `#[doc(include="filename")]` gets expanded to // `#[doc(include(file="filename", contents="file contents")]` so we need to // look for that instead @@ -814,11 +833,11 @@ impl Attributes { let mut contents: Option = None; for it in list { - if it.check_name("file") { + if it.check_name(sym::file) { if let Some(name) = it.value_str() { filename = Some(name.to_string()); } - } else if it.check_name("contents") { + } else if it.check_name(sym::contents) { if let Some(docs) = it.value_str() { contents = Some(docs.to_string()); } @@ -838,9 +857,9 @@ impl Attributes { }) } - pub fn has_doc_flag(&self, flag: &str) -> bool { + pub fn has_doc_flag(&self, flag: Symbol) -> bool { for attr in &self.other_attrs { - if !attr.check_name("doc") { continue; } + if !attr.check_name(sym::doc) { continue; } if let Some(items) = attr.meta_item_list() { if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) { @@ -861,7 +880,7 @@ impl Attributes { let other_attrs = attrs.iter().filter_map(|attr| { attr.with_desugared_doc(|attr| { - if attr.check_name("doc") { + if attr.check_name(sym::doc) { if let Some(mi) = attr.meta() { if let Some(value) = mi.value_str() { // Extracted #[doc = "..."] @@ -903,11 +922,12 @@ impl Attributes { // treat #[target_feature(enable = "feat")] attributes as if they were // #[doc(cfg(target_feature = "feat"))] attributes as well - for attr in attrs.lists("target_feature") { - if attr.check_name("enable") { + for attr in attrs.lists(sym::target_feature) { + if attr.check_name(sym::enable) { if let Some(feat) = attr.value_str() { - let meta = attr::mk_name_value_item_str(Ident::from_str("target_feature"), - dummy_spanned(feat)); + let meta = attr::mk_name_value_item_str( + Ident::with_empty_ctxt(sym::target_feature), + dummy_spanned(feat)); if let Ok(feat_cfg) = Cfg::parse(&meta) { cfg &= feat_cfg; } @@ -916,7 +936,7 @@ impl Attributes { } let inner_docs = attrs.iter() - .filter(|a| a.check_name("doc")) + .filter(|a| a.check_name(sym::doc)) .next() .map_or(true, |a| a.style == AttrStyle::Inner); @@ -1017,25 +1037,25 @@ impl Hash for Attributes { } impl AttributesExt for Attributes { - fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> { + fn lists<'a>(&'a self, name: Symbol) -> ListAttributesIter<'a> { self.other_attrs.lists(name) } } impl Clean for [ast::Attribute] { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Attributes { + fn clean(&self, cx: &DocContext<'_>) -> Attributes { Attributes::from_ast(cx.sess().diagnostic(), self) } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum GenericBound { TraitBound(PolyTrait, hir::TraitBoundModifier), Outlives(Lifetime), } impl GenericBound { - fn maybe_sized(cx: &DocContext<'_, '_, '_>) -> GenericBound { + fn maybe_sized(cx: &DocContext<'_>) -> GenericBound { let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem); let empty = cx.tcx.intern_substs(&[]); let path = external_path(cx, &cx.tcx.item_name(did).as_str(), @@ -1044,7 +1064,7 @@ impl GenericBound { GenericBound::TraitBound(PolyTrait { trait_: ResolvedPath { path, - typarams: None, + param_names: None, did, is_generic: false, }, @@ -1052,7 +1072,7 @@ impl GenericBound { }, hir::TraitBoundModifier::Maybe) } - fn is_sized_bound(&self, cx: &DocContext<'_, '_, '_>) -> bool { + fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { use rustc::hir::TraitBoundModifier as TBM; if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self { if trait_.def_id() == cx.tcx.lang_items().sized_trait() { @@ -1071,14 +1091,15 @@ impl GenericBound { fn get_trait_type(&self) -> Option { if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self { - return Some(trait_.clone()); + Some(trait_.clone()) + } else { + None } - None } } impl Clean for hir::GenericBound { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericBound { + fn clean(&self, cx: &DocContext<'_>) -> GenericBound { match *self { hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)), hir::GenericBound::Trait(ref t, modifier) => { @@ -1088,24 +1109,37 @@ impl Clean for hir::GenericBound { } } -fn external_generic_args(cx: &DocContext<'_, '_, '_>, trait_did: Option, has_self: bool, - bindings: Vec, substs: SubstsRef<'_>) -> GenericArgs { - let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect(); - let types = substs.types().skip(has_self as usize).collect::>(); +fn external_generic_args( + cx: &DocContext<'_>, + trait_did: Option, + has_self: bool, + bindings: Vec, + substs: SubstsRef<'_>, +) -> GenericArgs { + let mut skip_self = has_self; + let mut ty_sty = None; + let args: Vec<_> = substs.iter().filter_map(|kind| match kind.unpack() { + UnpackedKind::Lifetime(lt) => { + lt.clean(cx).and_then(|lt| Some(GenericArg::Lifetime(lt))) + } + UnpackedKind::Type(_) if skip_self => { + skip_self = false; + None + } + UnpackedKind::Type(ty) => { + ty_sty = Some(&ty.sty); + Some(GenericArg::Type(ty.clean(cx))) + } + UnpackedKind::Const(ct) => Some(GenericArg::Const(ct.clean(cx))), + }).collect(); match trait_did { // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C Some(did) if cx.tcx.lang_items().fn_trait_kind(did).is_some() => { - assert_eq!(types.len(), 1); - let inputs = match types[0].sty { - ty::Tuple(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(), - _ => { - return GenericArgs::AngleBracketed { - lifetimes, - types: types.clean(cx), - bindings, - } - } + assert!(ty_sty.is_some()); + let inputs = match ty_sty { + Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(), + _ => return GenericArgs::AngleBracketed { args, bindings }, }; let output = None; // FIXME(#20299) return type comes from a projection now @@ -1113,28 +1147,21 @@ fn external_generic_args(cx: &DocContext<'_, '_, '_>, trait_did: Option, // ty::Tuple(ref v) if v.is_empty() => None, // -> () // _ => Some(types[1].clean(cx)) // }; - GenericArgs::Parenthesized { - inputs, - output, - } + GenericArgs::Parenthesized { inputs, output } }, _ => { - GenericArgs::AngleBracketed { - lifetimes, - types: types.clean(cx), - bindings, - } + GenericArgs::AngleBracketed { args, bindings } } } } // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar // from Fn<(A, B,), C> to Fn(A, B) -> C -fn external_path(cx: &DocContext<'_, '_, '_>, name: &str, trait_did: Option, has_self: bool, +fn external_path(cx: &DocContext<'_>, name: &str, trait_did: Option, has_self: bool, bindings: Vec, substs: SubstsRef<'_>) -> Path { Path { global: false, - def: Def::Err, + res: Res::Err, segments: vec![PathSegment { name: name.to_string(), args: external_generic_args(cx, trait_did, has_self, bindings, substs) @@ -1143,7 +1170,7 @@ fn external_path(cx: &DocContext<'_, '_, '_>, name: &str, trait_did: Option Clean for (&'a ty::TraitRef<'tcx>, Vec) { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericBound { + fn clean(&self, cx: &DocContext<'_>) -> GenericBound { let (trait_ref, ref bounds) = *self; inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait); let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id).as_str(), @@ -1156,7 +1183,7 @@ impl<'a, 'tcx> Clean for (&'a ty::TraitRef<'tcx>, Vec for ty_s in trait_ref.input_types().skip(1) { if let ty::Tuple(ts) = ty_s.sty { for &ty_s in ts { - if let ty::Ref(ref reg, _, _) = ty_s.sty { + if let ty::Ref(ref reg, _, _) = ty_s.expect_ty().sty { if let &ty::RegionKind::ReLateBound(..) = *reg { debug!(" hit an ReLateBound {:?}", reg); if let Some(Lifetime(name)) = reg.clean(cx) { @@ -1175,7 +1202,7 @@ impl<'a, 'tcx> Clean for (&'a ty::TraitRef<'tcx>, Vec PolyTrait { trait_: ResolvedPath { path, - typarams: None, + param_names: None, did: trait_ref.def_id, is_generic: false, }, @@ -1187,13 +1214,13 @@ impl<'a, 'tcx> Clean for (&'a ty::TraitRef<'tcx>, Vec } impl<'tcx> Clean for ty::TraitRef<'tcx> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericBound { + fn clean(&self, cx: &DocContext<'_>) -> GenericBound { (self, vec![]).clean(cx) } } impl<'tcx> Clean>> for InternalSubsts<'tcx> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option> { + fn clean(&self, cx: &DocContext<'_>) -> Option> { let mut v = Vec::new(); v.extend(self.regions().filter_map(|r| r.clean(cx)).map(GenericBound::Outlives)); v.extend(self.types().map(|t| GenericBound::TraitBound(PolyTrait { @@ -1204,7 +1231,7 @@ impl<'tcx> Clean>> for InternalSubsts<'tcx> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Lifetime(String); impl Lifetime { @@ -1220,7 +1247,7 @@ impl Lifetime { } impl Clean for hir::Lifetime { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Lifetime { + fn clean(&self, cx: &DocContext<'_>) -> Lifetime { if self.hir_id != hir::DUMMY_HIR_ID { let def = cx.tcx.named_region(self.hir_id); match def { @@ -1239,7 +1266,7 @@ impl Clean for hir::Lifetime { } impl Clean for hir::GenericParam { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> Lifetime { + fn clean(&self, _: &DocContext<'_>) -> Lifetime { match self.kind { hir::GenericParamKind::Lifetime { .. } => { if self.bounds.len() > 0 { @@ -1263,7 +1290,7 @@ impl Clean for hir::GenericParam { } impl Clean for hir::ConstArg { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Constant { + fn clean(&self, cx: &DocContext<'_>) -> Constant { Constant { type_: cx.tcx.type_of(cx.tcx.hir().body_owner_def_id(self.value.body)).clean(cx), expr: print_const_expr(cx, self.value.body), @@ -1271,14 +1298,14 @@ impl Clean for hir::ConstArg { } } -impl<'tcx> Clean for ty::GenericParamDef { - fn clean(&self, _cx: &DocContext<'_, '_, '_>) -> Lifetime { +impl Clean for ty::GenericParamDef { + fn clean(&self, _cx: &DocContext<'_>) -> Lifetime { Lifetime(self.name.to_string()) } } impl Clean> for ty::RegionKind { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, cx: &DocContext<'_>) -> Option { match *self { ty::ReStatic => Some(Lifetime::statik()), ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())), @@ -1299,15 +1326,25 @@ impl Clean> for ty::RegionKind { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec }, RegionPredicate { lifetime: Lifetime, bounds: Vec }, EqPredicate { lhs: Type, rhs: Type }, } +impl WherePredicate { + pub fn get_bounds(&self) -> Option<&[GenericBound]> { + match *self { + WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds), + WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds), + _ => None, + } + } +} + impl Clean for hir::WherePredicate { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> WherePredicate { + fn clean(&self, cx: &DocContext<'_>) -> WherePredicate { match *self { hir::WherePredicate::BoundPredicate(ref wbp) => { WherePredicate::BoundPredicate { @@ -1334,7 +1371,7 @@ impl Clean for hir::WherePredicate { } impl<'a> Clean> for ty::Predicate<'a> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, cx: &DocContext<'_>) -> Option { use rustc::ty::Predicate; match *self { @@ -1353,7 +1390,7 @@ impl<'a> Clean> for ty::Predicate<'a> { } impl<'a> Clean for ty::TraitPredicate<'a> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> WherePredicate { + fn clean(&self, cx: &DocContext<'_>) -> WherePredicate { WherePredicate::BoundPredicate { ty: self.trait_ref.self_ty().clean(cx), bounds: vec![self.trait_ref.clean(cx)] @@ -1362,7 +1399,7 @@ impl<'a> Clean for ty::TraitPredicate<'a> { } impl<'tcx> Clean for ty::SubtypePredicate<'tcx> { - fn clean(&self, _cx: &DocContext<'_, '_, '_>) -> WherePredicate { + fn clean(&self, _cx: &DocContext<'_>) -> WherePredicate { panic!("subtype predicates are an internal rustc artifact \ and should not be seen by rustdoc") } @@ -1371,7 +1408,7 @@ impl<'tcx> Clean for ty::SubtypePredicate<'tcx> { impl<'tcx> Clean> for ty::OutlivesPredicate,ty::Region<'tcx>> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, cx: &DocContext<'_>) -> Option { let ty::OutlivesPredicate(ref a, ref b) = *self; match (a, b) { @@ -1389,7 +1426,7 @@ impl<'tcx> Clean> for } impl<'tcx> Clean> for ty::OutlivesPredicate, ty::Region<'tcx>> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, cx: &DocContext<'_>) -> Option { let ty::OutlivesPredicate(ref ty, ref lt) = *self; match lt { @@ -1405,7 +1442,7 @@ impl<'tcx> Clean> for ty::OutlivesPredicate, ty: } impl<'tcx> Clean for ty::ProjectionPredicate<'tcx> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> WherePredicate { + fn clean(&self, cx: &DocContext<'_>) -> WherePredicate { WherePredicate::EqPredicate { lhs: self.projection_ty.clean(cx), rhs: self.ty.clean(cx) @@ -1414,7 +1451,7 @@ impl<'tcx> Clean for ty::ProjectionPredicate<'tcx> { } impl<'tcx> Clean for ty::ProjectionTy<'tcx> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Type { + fn clean(&self, cx: &DocContext<'_>) -> Type { let trait_ = match self.trait_ref(cx.tcx).clean(cx) { GenericBound::TraitBound(t, _) => t.trait_, GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"), @@ -1427,7 +1464,7 @@ impl<'tcx> Clean for ty::ProjectionTy<'tcx> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum GenericParamDefKind { Lifetime, Type { @@ -1442,7 +1479,26 @@ pub enum GenericParamDefKind { }, } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +impl GenericParamDefKind { + pub fn is_type(&self) -> bool { + match *self { + GenericParamDefKind::Type { .. } => true, + _ => false, + } + } + + pub fn get_type(&self, cx: &DocContext<'_>) -> Option { + match *self { + GenericParamDefKind::Type { did, .. } => { + rustc_typeck::checked_type_of(cx.tcx, did, false).map(|t| t.clean(cx)) + } + GenericParamDefKind::Const { ref ty, .. } => Some(ty.clone()), + GenericParamDefKind::Lifetime => None, + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct GenericParamDef { pub name: String, @@ -1453,22 +1509,35 @@ impl GenericParamDef { pub fn is_synthetic_type_param(&self) -> bool { match self.kind { GenericParamDefKind::Lifetime | - GenericParamDefKind::Const { .. } => { - false - } + GenericParamDefKind::Const { .. } => false, GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(), } } + + pub fn is_type(&self) -> bool { + self.kind.is_type() + } + + pub fn get_type(&self, cx: &DocContext<'_>) -> Option { + self.kind.get_type(cx) + } + + pub fn get_bounds(&self) -> Option<&[GenericBound]> { + match self.kind { + GenericParamDefKind::Type { ref bounds, .. } => Some(bounds), + _ => None, + } + } } -impl<'tcx> Clean for ty::GenericParamDef { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericParamDef { +impl Clean for ty::GenericParamDef { + fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef { let (name, kind) = match self.kind { ty::GenericParamDefKind::Lifetime => { (self.name.to_string(), GenericParamDefKind::Lifetime) } ty::GenericParamDefKind::Type { has_default, .. } => { - cx.renderinfo.borrow_mut().external_typarams + cx.renderinfo.borrow_mut().external_param_names .insert(self.def_id, self.name.clean(cx)); let default = if has_default { Some(cx.tcx.type_of(self.def_id).clean(cx)) @@ -1482,6 +1551,12 @@ impl<'tcx> Clean for ty::GenericParamDef { synthetic: None, }) } + ty::GenericParamDefKind::Const { .. } => { + (self.name.clean(cx), GenericParamDefKind::Const { + did: self.def_id, + ty: cx.tcx.type_of(self.def_id).clean(cx), + }) + } }; GenericParamDef { @@ -1492,7 +1567,7 @@ impl<'tcx> Clean for ty::GenericParamDef { } impl Clean for hir::GenericParam { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericParamDef { + fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef { let (name, kind) = match self.kind { hir::GenericParamKind::Lifetime { .. } => { let name = if self.bounds.len() > 0 { @@ -1535,14 +1610,14 @@ impl Clean for hir::GenericParam { } // maybe use a Generic enum and use Vec? -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Default, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)] pub struct Generics { pub params: Vec, pub where_predicates: Vec, } impl Clean for hir::Generics { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Generics { + fn clean(&self, cx: &DocContext<'_>) -> Generics { // Synthetic type-parameters are inserted after normal ones. // In order for normal parameters to be able to refer to synthetic ones, // scans them first. @@ -1611,8 +1686,8 @@ impl Clean for hir::Generics { } impl<'a, 'tcx> Clean for (&'a ty::Generics, - &'a Lrc>) { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Generics { + &'a &'tcx ty::GenericPredicates<'tcx>) { + fn clean(&self, cx: &DocContext<'_>) -> Generics { use self::WherePredicate as WP; let (gens, preds) = *self; @@ -1623,12 +1698,13 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, let stripped_typarams = gens.params.iter().filter_map(|param| match param.kind { ty::GenericParamDefKind::Lifetime => None, ty::GenericParamDefKind::Type { .. } => { - if param.name == keywords::SelfUpper.name().as_str() { + if param.name.as_symbol() == kw::SelfUpper { assert_eq!(param.index, 0); return None; } Some(param.clean(cx)) } + ty::GenericParamDefKind::Const { .. } => None, }).collect::>(); let mut where_predicates = preds.predicates.iter() @@ -1678,6 +1754,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, .flat_map(|param| match param.kind { ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)), ty::GenericParamDefKind::Type { .. } => None, + ty::GenericParamDefKind::Const { .. } => Some(param.clean(cx)), }).chain(simplify::ty_params(stripped_typarams).into_iter()) .collect(), where_predicates: simplify::where_clauses(cx, where_predicates), @@ -1685,52 +1762,177 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +/// The point of this function is to replace bounds with types. +/// +/// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option` will return +/// `[Display, Option]` (we just returns the list of the types, we don't care about the +/// wrapped types in here). +fn get_real_types( + generics: &Generics, + arg: &Type, + cx: &DocContext<'_>, + recurse: i32, +) -> FxHashSet { + let arg_s = arg.to_string(); + let mut res = FxHashSet::default(); + if recurse >= 10 { // FIXME: remove this whole recurse thing when the recursion bug is fixed + return res; + } + if arg.is_full_generic() { + if let Some(where_pred) = generics.where_predicates.iter().find(|g| { + match g { + &WherePredicate::BoundPredicate { ref ty, .. } => ty.def_id() == arg.def_id(), + _ => false, + } + }) { + let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]); + for bound in bounds.iter() { + match *bound { + GenericBound::TraitBound(ref poly_trait, _) => { + for x in poly_trait.generic_params.iter() { + if !x.is_type() { + continue + } + if let Some(ty) = x.get_type(cx) { + let adds = get_real_types(generics, &ty, cx, recurse + 1); + if !adds.is_empty() { + res.extend(adds); + } else if !ty.is_full_generic() { + res.insert(ty); + } + } + } + } + _ => {} + } + } + } + if let Some(bound) = generics.params.iter().find(|g| { + g.is_type() && g.name == arg_s + }) { + for bound in bound.get_bounds().unwrap_or_else(|| &[]) { + if let Some(ty) = bound.get_trait_type() { + let adds = get_real_types(generics, &ty, cx, recurse + 1); + if !adds.is_empty() { + res.extend(adds); + } else if !ty.is_full_generic() { + res.insert(ty.clone()); + } + } + } + } + } else { + res.insert(arg.clone()); + if let Some(gens) = arg.generics() { + for gen in gens.iter() { + if gen.is_full_generic() { + let adds = get_real_types(generics, gen, cx, recurse + 1); + if !adds.is_empty() { + res.extend(adds); + } + } else { + res.insert(gen.clone()); + } + } + } + } + res +} + +/// Return the full list of types when bounds have been resolved. +/// +/// i.e. `fn foo>(x: u32, y: B)` will return +/// `[u32, Display, Option]`. +pub fn get_all_types( + generics: &Generics, + decl: &FnDecl, + cx: &DocContext<'_>, +) -> (Vec, Vec) { + let mut all_types = FxHashSet::default(); + for arg in decl.inputs.values.iter() { + if arg.type_.is_self_type() { + continue; + } + let args = get_real_types(generics, &arg.type_, cx, 0); + if !args.is_empty() { + all_types.extend(args); + } else { + all_types.insert(arg.type_.clone()); + } + } + + let ret_types = match decl.output { + FunctionRetTy::Return(ref return_type) => { + let mut ret = get_real_types(generics, &return_type, cx, 0); + if ret.is_empty() { + ret.insert(return_type.clone()); + } + ret.into_iter().collect() + } + _ => Vec::new(), + }; + (all_types.into_iter().collect(), ret_types) +} + +#[derive(Clone, Debug)] pub struct Method { pub generics: Generics, pub decl: FnDecl, pub header: hir::FnHeader, + pub defaultness: Option, + pub all_types: Vec, + pub ret_types: Vec, } -impl<'a> Clean for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Method { +impl<'a> Clean for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId, + Option) { + fn clean(&self, cx: &DocContext<'_>) -> Method { let (generics, decl) = enter_impl_trait(cx, || { (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx)) }); + let (all_types, ret_types) = get_all_types(&generics, &decl, cx); Method { decl, generics, header: self.0.header, + defaultness: self.3, + all_types, + ret_types, } } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct TyMethod { pub header: hir::FnHeader, pub decl: FnDecl, pub generics: Generics, + pub all_types: Vec, + pub ret_types: Vec, } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Function { pub decl: FnDecl, pub generics: Generics, pub header: hir::FnHeader, + pub all_types: Vec, + pub ret_types: Vec, } -impl Clean for doctree::Function { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::Function<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { let (generics, decl) = enter_impl_trait(cx, || { - (self.generics.clean(cx), (&self.decl, self.body).clean(cx)) + (self.generics.clean(cx), (self.decl, self.body).clean(cx)) }); - let did = cx.tcx.hir().local_def_id(self.id); + let did = cx.tcx.hir().local_def_id_from_hir_id(self.id); let constness = if cx.tcx.is_min_const_fn(did) { hir::Constness::Const } else { hir::Constness::NotConst }; + let (all_types, ret_types) = get_all_types(&generics, &decl, cx); Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -1743,12 +1945,14 @@ impl Clean for doctree::Function { decl, generics, header: hir::FnHeader { constness, ..self.header }, + all_types, + ret_types, }), } } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct FnDecl { pub inputs: Arguments, pub output: FunctionRetTy, @@ -1775,7 +1979,7 @@ impl FnDecl { match &bounds[0] { GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => { let bindings = trait_.bindings().unwrap(); - FunctionRetTy::Return(bindings[0].ty.clone()) + FunctionRetTy::Return(bindings[0].ty().clone()) } _ => panic!("unexpected desugaring of async function"), } @@ -1785,13 +1989,13 @@ impl FnDecl { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Arguments { pub values: Vec, } impl<'a> Clean for (&'a [hir::Ty], &'a [ast::Ident]) { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Arguments { + fn clean(&self, cx: &DocContext<'_>) -> Arguments { Arguments { values: self.0.iter().enumerate().map(|(i, ty)| { let mut name = self.1.get(i).map(|ident| ident.to_string()) @@ -1809,7 +2013,7 @@ impl<'a> Clean for (&'a [hir::Ty], &'a [ast::Ident]) { } impl<'a> Clean for (&'a [hir::Ty], hir::BodyId) { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Arguments { + fn clean(&self, cx: &DocContext<'_>) -> Arguments { let body = cx.tcx.hir().body(self.1); Arguments { @@ -1826,19 +2030,19 @@ impl<'a> Clean for (&'a [hir::Ty], hir::BodyId) { impl<'a, A: Copy> Clean for (&'a hir::FnDecl, A) where (&'a [hir::Ty], A): Clean { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> FnDecl { + fn clean(&self, cx: &DocContext<'_>) -> FnDecl { FnDecl { inputs: (&self.0.inputs[..], self.1).clean(cx), output: self.0.output.clean(cx), - attrs: Attributes::default() + attrs: Attributes::default(), } } } -impl<'a, 'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> FnDecl { +impl<'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { + fn clean(&self, cx: &DocContext<'_>) -> FnDecl { let (did, sig) = *self; - let mut names = if cx.tcx.hir().as_local_node_id(did).is_some() { + let mut names = if cx.tcx.hir().as_local_hir_id(did).is_some() { vec![].into_iter() } else { cx.tcx.fn_arg_names(did).into_iter() @@ -1859,13 +2063,13 @@ impl<'a, 'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Argument { pub type_: Type, pub name: String, } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, PartialEq, Debug)] pub enum SelfTy { SelfValue, SelfBorrowed(Option, Mutability), @@ -1889,14 +2093,14 @@ impl Argument { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum FunctionRetTy { Return(Type), DefaultReturn, } impl Clean for hir::FunctionRetTy { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> FunctionRetTy { + fn clean(&self, cx: &DocContext<'_>) -> FunctionRetTy { match *self { hir::Return(ref typ) => Return(typ.clean(cx)), hir::DefaultReturn(..) => DefaultReturn, @@ -1913,7 +2117,7 @@ impl GetDefId for FunctionRetTy { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Trait { pub auto: bool, pub unsafety: hir::Unsafety, @@ -1924,22 +2128,22 @@ pub struct Trait { pub is_auto: bool, } -impl Clean for doctree::Trait { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::Trait<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { let attrs = self.attrs.clean(cx); - let is_spotlight = attrs.has_doc_flag("spotlight"); + let is_spotlight = attrs.has_doc_flag(sym::spotlight); Item { name: Some(self.name.clean(cx)), attrs: attrs, source: self.whence.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), inner: TraitItem(Trait { auto: self.is_auto.clean(cx), unsafety: self.unsafety, - items: self.items.clean(cx), + items: self.items.iter().map(|ti| ti.clean(cx)).collect(), generics: self.generics.clean(cx), bounds: self.bounds.clean(cx), is_spotlight, @@ -1949,20 +2153,20 @@ impl Clean for doctree::Trait { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct TraitAlias { pub generics: Generics, pub bounds: Vec, } -impl Clean for doctree::TraitAlias { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::TraitAlias<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { let attrs = self.attrs.clean(cx); Item { name: Some(self.name.clean(cx)), attrs, source: self.whence.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -1975,7 +2179,7 @@ impl Clean for doctree::TraitAlias { } impl Clean for hir::IsAuto { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> bool { + fn clean(&self, _: &DocContext<'_>) -> bool { match *self { hir::IsAuto::Yes => true, hir::IsAuto::No => false, @@ -1984,13 +2188,13 @@ impl Clean for hir::IsAuto { } impl Clean for hir::TraitRef { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Type { + fn clean(&self, cx: &DocContext<'_>) -> Type { resolve_type(cx, self.path.clean(cx), self.hir_ref_id) } } impl Clean for hir::PolyTraitRef { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> PolyTrait { + fn clean(&self, cx: &DocContext<'_>) -> PolyTrait { PolyTrait { trait_: self.trait_ref.clean(cx), generic_params: self.bound_generic_params.clean(cx) @@ -1999,27 +2203,30 @@ impl Clean for hir::PolyTraitRef { } impl Clean for hir::TraitItem { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { let inner = match self.node { hir::TraitItemKind::Const(ref ty, default) => { - AssociatedConstItem(ty.clean(cx), + AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx, e))) } hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => { - MethodItem((sig, &self.generics, body).clean(cx)) + MethodItem((sig, &self.generics, body, None).clean(cx)) } hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => { let (generics, decl) = enter_impl_trait(cx, || { (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx)) }); + let (all_types, ret_types) = get_all_types(&generics, &decl, cx); TyMethodItem(TyMethod { header: sig.header, decl, generics, + all_types, + ret_types, }) } hir::TraitItemKind::Type(ref bounds, ref default) => { - AssociatedTypeItem(bounds.clean(cx), default.clean(cx)) + AssocTypeItem(bounds.clean(cx), default.clean(cx)) } }; let local_did = cx.tcx.hir().local_def_id_from_hir_id(self.hir_id); @@ -2037,14 +2244,14 @@ impl Clean for hir::TraitItem { } impl Clean for hir::ImplItem { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { let inner = match self.node { hir::ImplItemKind::Const(ref ty, expr) => { - AssociatedConstItem(ty.clean(cx), + AssocConstItem(ty.clean(cx), Some(print_const_expr(cx, expr))) } hir::ImplItemKind::Method(ref sig, body) => { - MethodItem((sig, &self.generics, body).clean(cx)) + MethodItem((sig, &self.generics, body, Some(self.defaultness)).clean(cx)) } hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef { type_: ty.clean(cx), @@ -2069,21 +2276,21 @@ impl Clean for hir::ImplItem { } } -impl<'tcx> Clean for ty::AssociatedItem { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for ty::AssocItem { + fn clean(&self, cx: &DocContext<'_>) -> Item { let inner = match self.kind { - ty::AssociatedKind::Const => { + ty::AssocKind::Const => { let ty = cx.tcx.type_of(self.def_id); let default = if self.defaultness.has_value() { Some(inline::print_inlined_const(cx, self.def_id)) } else { None }; - AssociatedConstItem(ty.clean(cx), default) + AssocConstItem(ty.clean(cx), default) } - ty::AssociatedKind::Method => { + ty::AssocKind::Method => { let generics = (cx.tcx.generics_of(self.def_id), - &cx.tcx.predicates_of(self.def_id)).clean(cx); + &cx.tcx.explicit_predicates_of(self.def_id)).clean(cx); let sig = cx.tcx.fn_sig(self.def_id); let mut decl = (self.def_id, sig).clean(cx); @@ -2113,12 +2320,17 @@ impl<'tcx> Clean for ty::AssociatedItem { ty::ImplContainer(_) => true, ty::TraitContainer(_) => self.defaultness.has_value() }; + let (all_types, ret_types) = get_all_types(&generics, &decl, cx); if provided { let constness = if cx.tcx.is_min_const_fn(self.def_id) { hir::Constness::Const } else { hir::Constness::NotConst }; + let defaultness = match self.container { + ty::ImplContainer(_) => Some(self.defaultness), + ty::TraitContainer(_) => None, + }; MethodItem(Method { generics, decl, @@ -2127,7 +2339,10 @@ impl<'tcx> Clean for ty::AssociatedItem { abi: sig.abi(), constness, asyncness: hir::IsAsync::NotAsync, - } + }, + defaultness, + all_types, + ret_types, }) } else { TyMethodItem(TyMethod { @@ -2138,11 +2353,13 @@ impl<'tcx> Clean for ty::AssociatedItem { abi: sig.abi(), constness: hir::Constness::NotConst, asyncness: hir::IsAsync::NotAsync, - } + }, + all_types, + ret_types, }) } } - ty::AssociatedKind::Type => { + ty::AssocKind::Type => { let my_name = self.ident.name.clean(cx); if let ty::TraitContainer(did) = self.container { @@ -2150,7 +2367,7 @@ impl<'tcx> Clean for ty::AssociatedItem { // are actually located on the trait/impl itself, so we need to load // all of the generics from there and then look for bounds that are // applied to this associated type in question. - let predicates = cx.tcx.predicates_of(did); + let predicates = cx.tcx.explicit_predicates_of(did); let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); let mut bounds = generics.where_predicates.iter().filter_map(|pred| { let (name, self_type, trait_, bounds) = match *pred { @@ -2187,7 +2404,7 @@ impl<'tcx> Clean for ty::AssociatedItem { None }; - AssociatedTypeItem(bounds, ty.clean(cx)) + AssocTypeItem(bounds, ty.clean(cx)) } else { TypedefItem(Typedef { type_: cx.tcx.type_of(self.def_id).clean(cx), @@ -2198,7 +2415,7 @@ impl<'tcx> Clean for ty::AssociatedItem { }, true) } } - ty::AssociatedKind::Existential => unimplemented!(), + ty::AssocKind::Existential => unimplemented!(), }; let visibility = match self.container { @@ -2220,21 +2437,21 @@ impl<'tcx> Clean for ty::AssociatedItem { } /// A trait reference, which may have higher ranked lifetimes. -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct PolyTrait { pub trait_: Type, pub generic_params: Vec, } -/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original -/// type out of the AST/TyCtxt given one of these, if more information is needed. Most importantly -/// it does not preserve mutability or boxes. -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +/// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original +/// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most +/// importantly, it does not preserve mutability or boxes. +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum Type { - /// Structs/enums/traits (most that'd be an `hir::TyKind::Path`). + /// Structs/enums/traits (most that would be an `hir::TyKind::Path`). ResolvedPath { path: Path, - typarams: Option>, + param_names: Option>, did: DefId, /// `true` if is a `T::Name` path for associated types. is_generic: bool, @@ -2245,14 +2462,13 @@ pub enum Type { /// Primitives are the fixed-size numeric types (plus int/usize/float), char, /// arrays, slices, and tuples. Primitive(PrimitiveType), - /// extern "ABI" fn + /// `extern "ABI" fn` BareFunction(Box), Tuple(Vec), Slice(Box), Array(Box, String), Never, CVarArgs, - Unique(Box), RawPointer(Mutability, Box), BorrowedRef { lifetime: Option, @@ -2260,21 +2476,21 @@ pub enum Type { type_: Box, }, - // ::Name + // `::Name` QPath { name: String, self_type: Box, trait_: Box }, - // _ + // `_` Infer, - // impl TraitA+TraitB + // `impl TraitA + TraitB + ...` ImplTrait(Vec), } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] pub enum PrimitiveType { Isize, I8, I16, I32, I64, I128, Usize, U8, U16, U32, U64, U128, @@ -2293,7 +2509,7 @@ pub enum PrimitiveType { CVarArgs, } -#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)] +#[derive(Clone, Copy, Debug)] pub enum TypeKind { Enum, Function, @@ -2303,7 +2519,6 @@ pub enum TypeKind { Struct, Union, Trait, - Variant, Typedef, Foreign, Macro, @@ -2355,12 +2570,15 @@ impl Type { } } - pub fn generics(&self) -> Option<&[Type]> { + pub fn generics(&self) -> Option> { match *self { ResolvedPath { ref path, .. } => { path.segments.last().and_then(|seg| { - if let GenericArgs::AngleBracketed { ref types, .. } = seg.args { - Some(&**types) + if let GenericArgs::AngleBracketed { ref args, .. } = seg.args { + Some(args.iter().filter_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty.clone()), + _ => None, + }).collect()) } else { None } @@ -2384,6 +2602,13 @@ impl Type { _ => None } } + + pub fn is_full_generic(&self) -> bool { + match *self { + Type::Generic(_) => true, + _ => false, + } + } } impl GetDefId for Type { @@ -2515,12 +2740,11 @@ impl From for PrimitiveType { } impl Clean for hir::Ty { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Type { + fn clean(&self, cx: &DocContext<'_>) -> Type { use rustc::hir::*; match self.node { TyKind::Never => Never, - TyKind::CVarArgs(_) => CVarArgs, TyKind::Ptr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)), TyKind::Rptr(ref l, ref m) => { let lifetime = if l.is_elided() { @@ -2541,8 +2765,11 @@ impl Clean for hir::Ty { promoted: None }; let length = match cx.tcx.const_eval(param_env.and(cid)) { - Ok(length) => print_const(cx, ty::LazyConst::Evaluated(length)), - Err(_) => "_".to_string(), + Ok(length) => print_const(cx, length), + Err(_) => cx.sess() + .source_map() + .span_to_snippet(cx.tcx.def_span(def_id)) + .unwrap_or_else(|_| "_".to_string()), }; Array(box ty.clean(cx), length) }, @@ -2556,22 +2783,21 @@ impl Clean for hir::Ty { } } TyKind::Path(hir::QPath::Resolved(None, ref path)) => { - if let Some(new_ty) = cx.ty_substs.borrow().get(&path.def).cloned() { - return new_ty; - } - - if let Def::TyParam(did) = path.def { + if let Res::Def(DefKind::TyParam, did) = path.res { + if let Some(new_ty) = cx.ty_substs.borrow().get(&did).cloned() { + return new_ty; + } if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) { return ImplTrait(bounds); } } let mut alias = None; - if let Def::TyAlias(def_id) = path.def { + if let Res::Def(DefKind::TyAlias, def_id) = path.res { // Substitute private type aliases if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) { if !cx.renderinfo.borrow().access_levels.is_exported(def_id) { - alias = Some(&cx.tcx.hir().expect_item_by_hir_id(hir_id).node); + alias = Some(&cx.tcx.hir().expect_item(hir_id).node); } } }; @@ -2580,8 +2806,9 @@ impl Clean for hir::Ty { let provided_params = &path.segments.last().expect("segments were empty"); let mut ty_substs = FxHashMap::default(); let mut lt_substs = FxHashMap::default(); - let mut const_substs = FxHashMap::default(); - provided_params.with_generic_args(|generic_args| { + let mut ct_substs = FxHashMap::default(); + let generic_args = provided_params.generic_args(); + { let mut indices: GenericParamCount = Default::default(); for param in generics.params.iter() { match param.kind { @@ -2609,9 +2836,8 @@ impl Clean for hir::Ty { indices.lifetimes += 1; } hir::GenericParamKind::Type { ref default, .. } => { - let ty_param_def = - Def::TyParam( - cx.tcx.hir().local_def_id_from_hir_id(param.hir_id)); + let ty_param_def_id = + cx.tcx.hir().local_def_id_from_hir_id(param.hir_id); let mut j = 0; let type_ = generic_args.args.iter().find_map(|arg| { match arg { @@ -2625,18 +2851,17 @@ impl Clean for hir::Ty { _ => None, } }); - if let Some(ty) = type_.cloned() { - ty_substs.insert(ty_param_def, ty.clean(cx)); + if let Some(ty) = type_ { + ty_substs.insert(ty_param_def_id, ty.clean(cx)); } else if let Some(default) = default.clone() { - ty_substs.insert(ty_param_def, - default.into_inner().clean(cx)); + ty_substs.insert(ty_param_def_id, + default.clean(cx)); } indices.types += 1; } hir::GenericParamKind::Const { .. } => { - let const_param_def = - Def::ConstParam( - cx.tcx.hir().local_def_id_from_hir_id(param.hir_id)); + let const_param_def_id = + cx.tcx.hir().local_def_id_from_hir_id(param.hir_id); let mut j = 0; let const_ = generic_args.args.iter().find_map(|arg| { match arg { @@ -2650,42 +2875,45 @@ impl Clean for hir::Ty { _ => None, } }); - if let Some(ct) = const_.cloned() { - const_substs.insert(const_param_def, ct.clean(cx)); + if let Some(ct) = const_ { + ct_substs.insert(const_param_def_id, ct.clean(cx)); } // FIXME(const_generics:defaults) indices.consts += 1; } } } - }); - return cx.enter_alias(ty_substs, lt_substs, const_substs, || ty.clean(cx)); + } + return cx.enter_alias(ty_substs, lt_substs, ct_substs, || ty.clean(cx)); } resolve_type(cx, path.clean(cx), self.hir_id) } TyKind::Path(hir::QPath::Resolved(Some(ref qself), ref p)) => { - let mut segments: Vec<_> = p.segments.clone().into(); - segments.pop(); - let trait_path = hir::Path { - span: p.span, - def: Def::Trait(cx.tcx.associated_item(p.def.def_id()).container.id()), - segments: segments.into(), + let segments = if p.is_global() { &p.segments[1..] } else { &p.segments }; + let trait_segments = &segments[..segments.len() - 1]; + let trait_path = self::Path { + global: p.is_global(), + res: Res::Def( + DefKind::Trait, + cx.tcx.associated_item(p.res.def_id()).container.id(), + ), + segments: trait_segments.clean(cx), }; Type::QPath { name: p.segments.last().expect("segments were empty").ident.name.clean(cx), self_type: box qself.clean(cx), - trait_: box resolve_type(cx, trait_path.clean(cx), self.hir_id) + trait_: box resolve_type(cx, trait_path, self.hir_id) } } TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => { - let mut def = Def::Err; + let mut res = Res::Err; let ty = hir_ty_to_ty(cx.tcx, self); if let ty::Projection(proj) = ty.sty { - def = Def::Trait(proj.trait_ref(cx.tcx).def_id); + res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id); } let trait_path = hir::Path { span: self.span, - def, + res, segments: vec![].into(), }; Type::QPath { @@ -2696,7 +2924,7 @@ impl Clean for hir::Ty { } TyKind::TraitObject(ref bounds, ref lifetime) => { match bounds[0].clean(cx).trait_ { - ResolvedPath { path, typarams: None, did, is_generic } => { + ResolvedPath { path, param_names: None, did, is_generic } => { let mut bounds: Vec = bounds[1..].iter().map(|bound| { self::GenericBound::TraitBound(bound.clean(cx), hir::TraitBoundModifier::None) @@ -2704,20 +2932,22 @@ impl Clean for hir::Ty { if !lifetime.is_elided() { bounds.push(self::GenericBound::Outlives(lifetime.clean(cx))); } - ResolvedPath { path, typarams: Some(bounds), did, is_generic, } + ResolvedPath { path, param_names: Some(bounds), did, is_generic, } } - _ => Infer // shouldn't happen + _ => Infer, // shouldn't happen } } TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)), TyKind::Infer | TyKind::Err => Infer, - TyKind::Typeof(..) => panic!("Unimplemented type {:?}", self.node), + TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.node), + TyKind::CVarArgs(_) => CVarArgs, } } } impl<'tcx> Clean for Ty<'tcx> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Type { + fn clean(&self, cx: &DocContext<'_>) -> Type { + debug!("cleaning type: {:?}", self); match self.sty { ty::Never => Never, ty::Bool => Primitive(PrimitiveType::Bool), @@ -2728,15 +2958,15 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Str => Primitive(PrimitiveType::Str), ty::Slice(ty) => Slice(box ty.clean(cx)), ty::Array(ty, n) => { - let mut n = *cx.tcx.lift(&n).expect("array lift failed"); - if let ty::LazyConst::Unevaluated(def_id, substs) = n { + let mut n = cx.tcx.lift(&n).expect("array lift failed"); + if let ConstValue::Unevaluated(def_id, substs) = n.val { let param_env = cx.tcx.param_env(def_id); let cid = GlobalId { instance: ty::Instance::new(def_id, substs), promoted: None }; if let Ok(new_n) = cx.tcx.const_eval(param_env.and(cid)) { - n = ty::LazyConst::Evaluated(new_n); + n = new_n; } }; let n = print_const(cx, n); @@ -2771,7 +3001,7 @@ impl<'tcx> Clean for Ty<'tcx> { None, false, vec![], substs); ResolvedPath { path, - typarams: None, + param_names: None, did, is_generic: false, } @@ -2782,7 +3012,7 @@ impl<'tcx> Clean for Ty<'tcx> { None, false, vec![], InternalSubsts::empty()); ResolvedPath { path: path, - typarams: None, + param_names: None, did: did, is_generic: false, } @@ -2803,8 +3033,8 @@ impl<'tcx> Clean for Ty<'tcx> { inline::record_extern_fqn(cx, did, TypeKind::Trait); - let mut typarams = vec![]; - reg.clean(cx).map(|b| typarams.push(GenericBound::Outlives(b))); + let mut param_names = vec![]; + reg.clean(cx).map(|b| param_names.push(GenericBound::Outlives(b))); for did in dids { let empty = cx.tcx.intern_substs(&[]); let path = external_path(cx, &cx.tcx.item_name(did).as_str(), @@ -2813,20 +3043,22 @@ impl<'tcx> Clean for Ty<'tcx> { let bound = GenericBound::TraitBound(PolyTrait { trait_: ResolvedPath { path, - typarams: None, + param_names: None, did, is_generic: false, }, generic_params: Vec::new(), }, hir::TraitBoundModifier::None); - typarams.push(bound); + param_names.push(bound); } let mut bindings = vec![]; for pb in obj.projection_bounds() { bindings.push(TypeBinding { name: cx.tcx.associated_item(pb.item_def_id()).ident.name.clean(cx), - ty: pb.skip_binder().ty.clean(cx) + kind: TypeBindingKind::Equality { + ty: pb.skip_binder().ty.clean(cx) + }, }); } @@ -2834,12 +3066,14 @@ impl<'tcx> Clean for Ty<'tcx> { false, bindings, substs); ResolvedPath { path, - typarams: Some(typarams), + param_names: Some(param_names), did, is_generic: false, } } - ty::Tuple(ref t) => Tuple(t.clean(cx)), + ty::Tuple(ref t) => { + Tuple(t.iter().map(|t| t.expect_ty()).collect::>().clean(cx)) + } ty::Projection(ref data) => data.clean(cx), @@ -2848,7 +3082,7 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Opaque(def_id, substs) => { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let predicates_of = cx.tcx.predicates_of(def_id); + let predicates_of = cx.tcx.explicit_predicates_of(def_id); let substs = cx.tcx.lift(&substs).expect("Opaque lift failed"); let bounds = predicates_of.instantiate(cx.tcx, substs); let mut regions = vec![]; @@ -2880,7 +3114,9 @@ impl<'tcx> Clean for Ty<'tcx> { Some(TypeBinding { name: cx.tcx.associated_item(proj.projection_ty.item_def_id) .ident.name.clean(cx), - ty: proj.ty.clean(cx), + kind: TypeBindingKind::Equality { + ty: proj.ty.clean(cx), + }, }) } else { None @@ -2911,23 +3147,34 @@ impl<'tcx> Clean for Ty<'tcx> { } } +impl<'tcx> Clean for ty::Const<'tcx> { + fn clean(&self, cx: &DocContext<'_>) -> Constant { + Constant { + type_: self.ty.clean(cx), + expr: format!("{}", self), + } + } +} + impl Clean for hir::StructField { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { + let local_did = cx.tcx.hir().local_def_id_from_hir_id(self.hir_id); + Item { name: Some(self.ident.name).clean(cx), attrs: self.attrs.clean(cx), source: self.span.clean(cx), visibility: self.vis.clean(cx), - stability: get_stability(cx, cx.tcx.hir().local_def_id(self.id)), - deprecation: get_deprecation(cx, cx.tcx.hir().local_def_id(self.id)), - def_id: cx.tcx.hir().local_def_id(self.id), + stability: get_stability(cx, local_did), + deprecation: get_deprecation(cx, local_did), + def_id: local_did, inner: StructFieldItem(self.ty.clean(cx)), } } } -impl<'tcx> Clean for ty::FieldDef { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for ty::FieldDef { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.ident.name).clean(cx), attrs: cx.tcx.get_attrs(self.did).clean(cx), @@ -2941,7 +3188,7 @@ impl<'tcx> Clean for ty::FieldDef { } } -#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum Visibility { Public, Inherited, @@ -2950,14 +3197,14 @@ pub enum Visibility { } impl Clean> for hir::Visibility { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, cx: &DocContext<'_>) -> Option { Some(match self.node { hir::VisibilityKind::Public => Visibility::Public, hir::VisibilityKind::Inherited => Visibility::Inherited, hir::VisibilityKind::Crate(_) => Visibility::Crate, hir::VisibilityKind::Restricted { ref path, .. } => { let path = path.clean(cx); - let did = register_def(cx, path.def); + let did = register_res(cx, path.res); Visibility::Restricted(did, path) } }) @@ -2965,12 +3212,12 @@ impl Clean> for hir::Visibility { } impl Clean> for ty::Visibility { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, _: &DocContext<'_>) -> Option { Some(if *self == ty::Visibility::Public { Public } else { Inherited }) } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Struct { pub struct_type: doctree::StructType, pub generics: Generics, @@ -2978,7 +3225,7 @@ pub struct Struct { pub fields_stripped: bool, } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Union { pub struct_type: doctree::StructType, pub generics: Generics, @@ -2986,13 +3233,13 @@ pub struct Union { pub fields_stripped: bool, } -impl Clean for doctree::Struct { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::Struct<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -3006,13 +3253,13 @@ impl Clean for doctree::Struct { } } -impl Clean for doctree::Union { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::Union<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -3029,7 +3276,7 @@ impl Clean for doctree::Union { /// This is a more limited form of the standard Struct, different in that /// it lacks the things most items have (name, id, parameterization). Found /// only as a variant in an enum. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct VariantStruct { pub struct_type: doctree::StructType, pub fields: Vec, @@ -3037,7 +3284,7 @@ pub struct VariantStruct { } impl Clean for ::rustc::hir::VariantData { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> VariantStruct { + fn clean(&self, cx: &DocContext<'_>) -> VariantStruct { VariantStruct { struct_type: doctree::struct_type_from_def(self), fields: self.fields().iter().map(|x| x.clean(cx)).collect(), @@ -3046,20 +3293,20 @@ impl Clean for ::rustc::hir::VariantData { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Enum { pub variants: IndexVec, pub generics: Generics, pub variants_stripped: bool, } -impl Clean for doctree::Enum { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::Enum<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -3072,13 +3319,13 @@ impl Clean for doctree::Enum { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Variant { pub kind: VariantKind, } -impl Clean for doctree::Variant { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::Variant<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -3086,7 +3333,7 @@ impl Clean for doctree::Variant { visibility: None, stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.def.id()), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), inner: VariantItem(Variant { kind: self.def.clean(cx), }), @@ -3094,8 +3341,8 @@ impl Clean for doctree::Variant { } } -impl<'tcx> Clean for ty::VariantDef { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for ty::VariantDef { + fn clean(&self, cx: &DocContext<'_>) -> Item { let kind = match self.ctor_kind { CtorKind::Const => VariantKind::CLike, CtorKind::Fn => { @@ -3124,18 +3371,18 @@ impl<'tcx> Clean for ty::VariantDef { }; Item { name: Some(self.ident.clean(cx)), - attrs: inline::load_attrs(cx, self.did), - source: cx.tcx.def_span(self.did).clean(cx), + attrs: inline::load_attrs(cx, self.def_id), + source: cx.tcx.def_span(self.def_id).clean(cx), visibility: Some(Inherited), - def_id: self.did, + def_id: self.def_id, inner: VariantItem(Variant { kind }), - stability: get_stability(cx, self.did), - deprecation: get_deprecation(cx, self.did), + stability: get_stability(cx, self.def_id), + deprecation: get_deprecation(cx, self.def_id), } } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub enum VariantKind { CLike, Tuple(Vec), @@ -3143,24 +3390,24 @@ pub enum VariantKind { } impl Clean for hir::VariantData { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> VariantKind { - if self.is_struct() { - VariantKind::Struct(self.clean(cx)) - } else if self.is_unit() { - VariantKind::CLike - } else { - VariantKind::Tuple(self.fields().iter().map(|x| x.ty.clean(cx)).collect()) + fn clean(&self, cx: &DocContext<'_>) -> VariantKind { + match self { + hir::VariantData::Struct(..) => VariantKind::Struct(self.clean(cx)), + hir::VariantData::Tuple(..) => + VariantKind::Tuple(self.fields().iter().map(|x| x.ty.clean(cx)).collect()), + hir::VariantData::Unit(..) => VariantKind::CLike, } } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Span { pub filename: FileName, pub loline: usize, pub locol: usize, pub hiline: usize, pub hicol: usize, + pub original: syntax_pos::Span, } impl Span { @@ -3169,12 +3416,17 @@ impl Span { filename: FileName::Anon(0), loline: 0, locol: 0, hiline: 0, hicol: 0, + original: syntax_pos::DUMMY_SP, } } + + pub fn span(&self) -> syntax_pos::Span { + self.original + } } impl Clean for syntax_pos::Span { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Span { + fn clean(&self, cx: &DocContext<'_>) -> Span { if self.is_dummy() { return Span::empty(); } @@ -3189,14 +3441,15 @@ impl Clean for syntax_pos::Span { locol: lo.col.to_usize(), hiline: hi.line, hicol: hi.col.to_usize(), + original: *self, } } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Path { pub global: bool, - pub def: Def, + pub res: Res, pub segments: Vec, } @@ -3207,20 +3460,36 @@ impl Path { } impl Clean for hir::Path { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Path { + fn clean(&self, cx: &DocContext<'_>) -> Path { Path { global: self.is_global(), - def: self.def, + res: self.res, segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx), } } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum GenericArg { + Lifetime(Lifetime), + Type(Type), + Const(Constant), +} + +impl fmt::Display for GenericArg { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + GenericArg::Lifetime(lt) => lt.fmt(f), + GenericArg::Type(ty) => ty.fmt(f), + GenericArg::Const(ct) => ct.fmt(f), + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum GenericArgs { AngleBracketed { - lifetimes: Vec, - types: Vec, + args: Vec, bindings: Vec, }, Parenthesized { @@ -3230,67 +3499,58 @@ pub enum GenericArgs { } impl Clean for hir::GenericArgs { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericArgs { + fn clean(&self, cx: &DocContext<'_>) -> GenericArgs { if self.parenthesized { - let output = self.bindings[0].ty.clean(cx); + let output = self.bindings[0].ty().clean(cx); GenericArgs::Parenthesized { inputs: self.inputs().clean(cx), output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None } } } else { - let (mut lifetimes, mut types) = (vec![], vec![]); - let mut elided_lifetimes = true; - for arg in &self.args { - match arg { - GenericArg::Lifetime(lt) => { - if !lt.is_elided() { - elided_lifetimes = false; - } - lifetimes.push(lt.clean(cx)); - } - GenericArg::Type(ty) => { - types.push(ty.clean(cx)); - } - GenericArg::Const(..) => { - unimplemented!() // FIXME(const_generics) - } - } - } + let elide_lifetimes = self.args.iter().all(|arg| match arg { + hir::GenericArg::Lifetime(lt) => lt.is_elided(), + _ => true, + }); GenericArgs::AngleBracketed { - lifetimes: if elided_lifetimes { vec![] } else { lifetimes }, - types, + args: self.args.iter().filter_map(|arg| match arg { + hir::GenericArg::Lifetime(lt) if !elide_lifetimes => { + Some(GenericArg::Lifetime(lt.clean(cx))) + } + hir::GenericArg::Lifetime(_) => None, + hir::GenericArg::Type(ty) => Some(GenericArg::Type(ty.clean(cx))), + hir::GenericArg::Const(ct) => Some(GenericArg::Const(ct.clean(cx))), + }).collect(), bindings: self.bindings.clean(cx), } } } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct PathSegment { pub name: String, pub args: GenericArgs, } impl Clean for hir::PathSegment { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> PathSegment { + fn clean(&self, cx: &DocContext<'_>) -> PathSegment { PathSegment { name: self.ident.name.clean(cx), - args: self.with_generic_args(|generic_args| generic_args.clean(cx)) + args: self.generic_args().clean(cx), } } } fn strip_type(ty: Type) -> Type { match ty { - Type::ResolvedPath { path, typarams, did, is_generic } => { - Type::ResolvedPath { path: strip_path(&path), typarams, did, is_generic } + Type::ResolvedPath { path, param_names, did, is_generic } => { + Type::ResolvedPath { path: strip_path(&path), param_names, did, is_generic } } Type::Tuple(inner_tys) => { Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect()) } Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))), Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s), - Type::Unique(inner_ty) => Type::Unique(Box::new(strip_type(*inner_ty))), Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))), Type::BorrowedRef { lifetime, mutability, type_ } => { Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) } @@ -3310,16 +3570,15 @@ fn strip_path(path: &Path) -> Path { PathSegment { name: s.name.clone(), args: GenericArgs::AngleBracketed { - lifetimes: Vec::new(), - types: Vec::new(), - bindings: Vec::new(), + args: vec![], + bindings: vec![], } } }).collect(); Path { global: path.global, - def: path.def.clone(), + res: path.res.clone(), segments, } } @@ -3335,7 +3594,7 @@ fn qpath_to_string(p: &hir::QPath) -> String { if i > 0 { s.push_str("::"); } - if seg.ident.name != keywords::PathRoot.name() { + if seg.ident.name != kw::PathRoot { s.push_str(&*seg.ident.as_str()); } } @@ -3344,38 +3603,38 @@ fn qpath_to_string(p: &hir::QPath) -> String { impl Clean for Ident { #[inline] - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> String { + fn clean(&self, cx: &DocContext<'_>) -> String { self.name.clean(cx) } } impl Clean for ast::Name { #[inline] - fn clean(&self, _: &DocContext<'_, '_, '_>) -> String { + fn clean(&self, _: &DocContext<'_>) -> String { self.to_string() } } impl Clean for InternedString { #[inline] - fn clean(&self, _: &DocContext<'_, '_, '_>) -> String { + fn clean(&self, _: &DocContext<'_>) -> String { self.to_string() } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Typedef { pub type_: Type, pub generics: Generics, } -impl Clean for doctree::Typedef { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::Typedef<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id.clone()), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -3387,19 +3646,19 @@ impl Clean for doctree::Typedef { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Existential { pub bounds: Vec, pub generics: Generics, } -impl Clean for doctree::Existential { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::Existential<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id.clone()), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -3411,7 +3670,7 @@ impl Clean for doctree::Existential { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct BareFunctionDecl { pub unsafety: hir::Unsafety, pub generic_params: Vec, @@ -3420,7 +3679,7 @@ pub struct BareFunctionDecl { } impl Clean for hir::BareFnTy { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> BareFunctionDecl { + fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl { let (generic_params, decl) = enter_impl_trait(cx, || { (self.generic_params.clean(cx), (&*self.decl, &self.arg_names[..]).clean(cx)) }); @@ -3433,7 +3692,7 @@ impl Clean for hir::BareFnTy { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Static { pub type_: Type, pub mutability: Mutability, @@ -3443,14 +3702,14 @@ pub struct Static { pub expr: String, } -impl Clean for doctree::Static { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::Static<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { debug!("cleaning static {}: {:?}", self.name.clean(cx), self); Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -3463,19 +3722,19 @@ impl Clean for doctree::Static { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct Constant { pub type_: Type, pub expr: String, } -impl Clean for doctree::Constant { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::Constant<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -3487,14 +3746,14 @@ impl Clean for doctree::Constant { } } -#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)] pub enum Mutability { Mutable, Immutable, } impl Clean for hir::Mutability { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> Mutability { + fn clean(&self, _: &DocContext<'_>) -> Mutability { match self { &hir::MutMutable => Mutable, &hir::MutImmutable => Immutable, @@ -3502,14 +3761,14 @@ impl Clean for hir::Mutability { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Copy, Debug, Hash)] pub enum ImplPolarity { Positive, Negative, } impl Clean for hir::ImplPolarity { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> ImplPolarity { + fn clean(&self, _: &DocContext<'_>) -> ImplPolarity { match self { &hir::ImplPolarity::Positive => ImplPolarity::Positive, &hir::ImplPolarity::Negative => ImplPolarity::Negative, @@ -3517,7 +3776,7 @@ impl Clean for hir::ImplPolarity { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Impl { pub unsafety: hir::Unsafety, pub generics: Generics, @@ -3530,47 +3789,20 @@ pub struct Impl { pub blanket_impl: Option, } -pub fn get_auto_traits_with_node_id( - cx: &DocContext<'_, '_, '_>, - id: ast::NodeId, - name: String -) -> Vec { - let finder = AutoTraitFinder::new(cx); - finder.get_with_node_id(id, name) -} - -pub fn get_auto_traits_with_def_id( - cx: &DocContext<'_, '_, '_>, - id: DefId -) -> Vec { - let finder = AutoTraitFinder::new(cx); - - finder.get_with_def_id(id) -} - -pub fn get_blanket_impls_with_node_id( - cx: &DocContext<'_, '_, '_>, - id: ast::NodeId, - name: String -) -> Vec { - let finder = BlanketImplFinder::new(cx); - finder.get_with_node_id(id, name) -} - -pub fn get_blanket_impls_with_def_id( - cx: &DocContext<'_, '_, '_>, - id: DefId -) -> Vec { - let finder = BlanketImplFinder::new(cx); - - finder.get_with_def_id(id) +pub fn get_auto_trait_and_blanket_impls( + cx: &DocContext<'tcx>, + ty: Ty<'tcx>, + param_env_def_id: DefId, +) -> impl Iterator { + AutoTraitFinder::new(cx).get_auto_trait_impls(ty, param_env_def_id).into_iter() + .chain(BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id)) } -impl Clean> for doctree::Impl { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec { +impl Clean> for doctree::Impl<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Vec { let mut ret = Vec::new(); let trait_ = self.trait_.clean(cx); - let items = self.items.clean(cx); + let items = self.items.iter().map(|ii| ii.clean(cx)).collect::>(); // If this impl block is an implementation of the Deref trait, then we // need to try inlining the target's inherent impl blocks as well. @@ -3589,7 +3821,7 @@ impl Clean> for doctree::Impl { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -3609,7 +3841,7 @@ impl Clean> for doctree::Impl { } } -fn build_deref_target_impls(cx: &DocContext<'_, '_, '_>, +fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut Vec) { use self::PrimitiveType::*; @@ -3667,12 +3899,12 @@ fn build_deref_target_impls(cx: &DocContext<'_, '_, '_>, } } -impl Clean> for doctree::ExternCrate { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec { +impl Clean> for doctree::ExternCrate<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Vec { let please_inline = self.vis.node.is_pub() && self.attrs.iter().any(|a| { - a.name() == "doc" && match a.meta_item_list() { - Some(l) => attr::list_contains_name(&l, "inline"), + a.check_name(sym::doc) && match a.meta_item_list() { + Some(l) => attr::list_contains_name(&l, sym::inline), None => false, } }); @@ -3680,12 +3912,15 @@ impl Clean> for doctree::ExternCrate { if please_inline { let mut visited = FxHashSet::default(); - let def = Def::Mod(DefId { - krate: self.cnum, - index: CRATE_DEF_INDEX, - }); + let res = Res::Def( + DefKind::Mod, + DefId { + krate: self.cnum, + index: CRATE_DEF_INDEX, + }, + ); - if let Some(items) = inline::try_inline(cx, def, self.name, &mut visited) { + if let Some(items) = inline::try_inline(cx, res, self.name, &mut visited) { return items; } } @@ -3703,27 +3938,27 @@ impl Clean> for doctree::ExternCrate { } } -impl Clean> for doctree::Import { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec { +impl Clean> for doctree::Import<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Vec { // We consider inlining the documentation of `pub use` statements, but we // forcefully don't inline if this is not public or if the // #[doc(no_inline)] attribute is present. // Don't inline doc(hidden) imports so they can be stripped at a later stage. let mut denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| { - a.name() == "doc" && match a.meta_item_list() { - Some(l) => attr::list_contains_name(&l, "no_inline") || - attr::list_contains_name(&l, "hidden"), + a.check_name(sym::doc) && match a.meta_item_list() { + Some(l) => attr::list_contains_name(&l, sym::no_inline) || + attr::list_contains_name(&l, sym::hidden), None => false, } }); // Also check whether imports were asked to be inlined, in case we're trying to re-export a // crate in Rust 2018+ - let please_inline = self.attrs.lists("doc").has_word("inline"); + let please_inline = self.attrs.lists(sym::doc).has_word(sym::inline); let path = self.path.clean(cx); let inner = if self.glob { if !denied { let mut visited = FxHashSet::default(); - if let Some(items) = inline::try_inline_glob(cx, path.def, &mut visited) { + if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) { return items; } } @@ -3732,18 +3967,20 @@ impl Clean> for doctree::Import { } else { let name = self.name; if !please_inline { - match path.def { - Def::Mod(did) => if !did.is_local() && did.index == CRATE_DEF_INDEX { - // if we're `pub use`ing an extern crate root, don't inline it unless we - // were specifically asked for it - denied = true; + match path.res { + Res::Def(DefKind::Mod, did) => { + if !did.is_local() && did.index == CRATE_DEF_INDEX { + // if we're `pub use`ing an extern crate root, don't inline it unless we + // were specifically asked for it + denied = true; + } } _ => {} } } if !denied { let mut visited = FxHashSet::default(); - if let Some(items) = inline::try_inline(cx, path.def, name, &mut visited) { + if let Some(items) = inline::try_inline(cx, path.res, name, &mut visited) { return items; } } @@ -3763,7 +4000,7 @@ impl Clean> for doctree::Import { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub enum Import { // use source as str; Simple(String, ImportSource), @@ -3771,46 +4008,38 @@ pub enum Import { Glob(ImportSource) } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct ImportSource { pub path: Path, pub did: Option, } -impl Clean> for hir::ForeignMod { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec { - let mut items = self.items.clean(cx); - for item in &mut items { - if let ForeignFunctionItem(ref mut f) = item.inner { - f.header.abi = self.abi; - } - } - items - } -} - -impl Clean for hir::ForeignItem { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { - let inner = match self.node { +impl Clean for doctree::ForeignItem<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { + let inner = match self.kind { hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => { + let abi = cx.tcx.hir().get_foreign_abi(self.id); let (generics, decl) = enter_impl_trait(cx, || { (generics.clean(cx), (&**decl, &names[..]).clean(cx)) }); + let (all_types, ret_types) = get_all_types(&generics, &decl, cx); ForeignFunctionItem(Function { decl, generics, header: hir::FnHeader { unsafety: hir::Unsafety::Unsafe, - abi: Abi::Rust, + abi, constness: hir::Constness::NotConst, asyncness: hir::IsAsync::NotAsync, }, + all_types, + ret_types, }) } hir::ForeignItemKind::Static(ref ty, mutbl) => { ForeignStaticItem(Static { type_: ty.clean(cx), - mutability: if mutbl {Mutable} else {Immutable}, + mutability: mutbl.clean(cx), expr: String::new(), }) } @@ -3820,13 +4049,13 @@ impl Clean for hir::ForeignItem { }; Item { - name: Some(self.ident.clean(cx)), + name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.span.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id), + source: self.whence.clean(cx), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), visibility: self.vis.clean(cx), - stability: get_stability(cx, cx.tcx.hir().local_def_id(self.id)), - deprecation: get_deprecation(cx, cx.tcx.hir().local_def_id(self.id)), + stability: self.stab.clean(cx), + deprecation: self.depr.clean(cx), inner, } } @@ -3835,11 +4064,11 @@ impl Clean for hir::ForeignItem { // Utilities pub trait ToSource { - fn to_src(&self, cx: &DocContext<'_, '_, '_>) -> String; + fn to_src(&self, cx: &DocContext<'_>) -> String; } impl ToSource for syntax_pos::Span { - fn to_src(&self, cx: &DocContext<'_, '_, '_>) -> String { + fn to_src(&self, cx: &DocContext<'_>) -> String { debug!("converting span {:?} to snippet", self.clean(cx)); let sn = match cx.sess().source_map().span_to_snippet(*self) { Ok(x) => x, @@ -3856,7 +4085,7 @@ fn name_from_pat(p: &hir::Pat) -> String { match p.node { PatKind::Wild => "_".to_string(), - PatKind::Binding(_, _, _, ident, _) => ident.to_string(), + PatKind::Binding(_, _, ident, _) => ident.to_string(), PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p), PatKind::Struct(ref name, ref fields, etc) => { format!("{} {{ {}{} }}", qpath_to_string(name), @@ -3886,34 +4115,37 @@ fn name_from_pat(p: &hir::Pat) -> String { } } -fn print_const(cx: &DocContext<'_, '_, '_>, n: ty::LazyConst<'_>) -> String { - match n { - ty::LazyConst::Unevaluated(def_id, _) => { - if let Some(node_id) = cx.tcx.hir().as_local_node_id(def_id) { - print_const_expr(cx, cx.tcx.hir().body_owned_by(node_id)) +fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String { + match n.val { + ConstValue::Unevaluated(def_id, _) => { + if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) { + print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id)) } else { inline::print_inlined_const(cx, def_id) } }, - ty::LazyConst::Evaluated(n) => { - let mut s = String::new(); - ::rustc::mir::fmt_const_val(&mut s, n).expect("fmt_const_val failed"); + _ => { + let mut s = n.to_string(); // array lengths are obviously usize if s.ends_with("usize") { let n = s.len() - "usize".len(); s.truncate(n); + if s.ends_with(": ") { + let n = s.len() - ": ".len(); + s.truncate(n); + } } s }, } } -fn print_const_expr(cx: &DocContext<'_, '_, '_>, body: hir::BodyId) -> String { +fn print_const_expr(cx: &DocContext<'_>, body: hir::BodyId) -> String { cx.tcx.hir().hir_to_pretty_string(body.hir_id) } /// Given a type Path, resolve it to a Type using the TyCtxt -fn resolve_type(cx: &DocContext<'_, '_, '_>, +fn resolve_type(cx: &DocContext<'_>, path: Path, id: hir::HirId) -> Type { if id == hir::DUMMY_HIR_ID { @@ -3922,8 +4154,8 @@ fn resolve_type(cx: &DocContext<'_, '_, '_>, debug!("resolve_type({:?},{:?})", path, id); } - let is_generic = match path.def { - Def::PrimTy(p) => match p { + let is_generic = match path.res { + Res::PrimTy(p) => match p { hir::Str => return Primitive(PrimitiveType::Str), hir::Bool => return Primitive(PrimitiveType::Bool), hir::Char => return Primitive(PrimitiveType::Char), @@ -3931,45 +4163,47 @@ fn resolve_type(cx: &DocContext<'_, '_, '_>, hir::Uint(uint_ty) => return Primitive(uint_ty.into()), hir::Float(float_ty) => return Primitive(float_ty.into()), }, - Def::SelfTy(..) if path.segments.len() == 1 => { - return Generic(keywords::SelfUpper.name().to_string()); + Res::SelfTy(..) if path.segments.len() == 1 => { + return Generic(kw::SelfUpper.to_string()); } - Def::TyParam(..) if path.segments.len() == 1 => { + Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => { return Generic(format!("{:#}", path)); } - Def::SelfTy(..) | Def::TyParam(..) | Def::AssociatedTy(..) => true, + Res::SelfTy(..) + | Res::Def(DefKind::TyParam, _) + | Res::Def(DefKind::AssocTy, _) => true, _ => false, }; - let did = register_def(&*cx, path.def); - ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic } -} - -pub fn register_def(cx: &DocContext<'_, '_, '_>, def: Def) -> DefId { - debug!("register_def({:?})", def); - - let (did, kind) = match def { - Def::Fn(i) => (i, TypeKind::Function), - Def::TyAlias(i) => (i, TypeKind::Typedef), - Def::Enum(i) => (i, TypeKind::Enum), - Def::Trait(i) => (i, TypeKind::Trait), - Def::Struct(i) => (i, TypeKind::Struct), - Def::Union(i) => (i, TypeKind::Union), - Def::Mod(i) => (i, TypeKind::Module), - Def::ForeignTy(i) => (i, TypeKind::Foreign), - Def::Const(i) => (i, TypeKind::Const), - Def::Static(i, _) => (i, TypeKind::Static), - Def::Variant(i) => (cx.tcx.parent_def_id(i).expect("cannot get parent def id"), + let did = register_res(&*cx, path.res); + ResolvedPath { path: path, param_names: None, did: did, is_generic: is_generic } +} + +pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId { + debug!("register_res({:?})", res); + + let (did, kind) = match res { + Res::Def(DefKind::Fn, i) => (i, TypeKind::Function), + Res::Def(DefKind::TyAlias, i) => (i, TypeKind::Typedef), + Res::Def(DefKind::Enum, i) => (i, TypeKind::Enum), + Res::Def(DefKind::Trait, i) => (i, TypeKind::Trait), + Res::Def(DefKind::Struct, i) => (i, TypeKind::Struct), + Res::Def(DefKind::Union, i) => (i, TypeKind::Union), + Res::Def(DefKind::Mod, i) => (i, TypeKind::Module), + Res::Def(DefKind::ForeignTy, i) => (i, TypeKind::Foreign), + Res::Def(DefKind::Const, i) => (i, TypeKind::Const), + Res::Def(DefKind::Static, i) => (i, TypeKind::Static), + Res::Def(DefKind::Variant, i) => (cx.tcx.parent(i).expect("cannot get parent def id"), TypeKind::Enum), - Def::Macro(i, mac_kind) => match mac_kind { + Res::Def(DefKind::Macro(mac_kind), i) => match mac_kind { MacroKind::Bang => (i, TypeKind::Macro), MacroKind::Attr => (i, TypeKind::Attr), MacroKind::Derive => (i, TypeKind::Derive), MacroKind::ProcMacroStub => unreachable!(), }, - Def::TraitAlias(i) => (i, TypeKind::TraitAlias), - Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait), - Def::SelfTy(_, Some(impl_def_id)) => return impl_def_id, - _ => return def.def_id() + Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias), + Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait), + Res::SelfTy(_, Some(impl_def_id)) => return impl_def_id, + _ => return res.def_id() }; if did.is_local() { return did } inline::record_extern_fqn(cx, did, kind); @@ -3979,25 +4213,25 @@ pub fn register_def(cx: &DocContext<'_, '_, '_>, def: Def) -> DefId { did } -fn resolve_use_source(cx: &DocContext<'_, '_, '_>, path: Path) -> ImportSource { +fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource { ImportSource { - did: if path.def.opt_def_id().is_none() { + did: if path.res.opt_def_id().is_none() { None } else { - Some(register_def(cx, path.def)) + Some(register_res(cx, path.res)) }, path, } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Macro { pub source: String, pub imported_from: Option, } -impl Clean for doctree::Macro { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::Macro<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { let name = self.name.clean(cx); Item { name: Some(name.clone()), @@ -4019,14 +4253,14 @@ impl Clean for doctree::Macro { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct ProcMacro { pub kind: MacroKind, pub helpers: Vec, } -impl Clean for doctree::ProcMacro { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { +impl Clean for doctree::ProcMacro<'_> { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -4034,7 +4268,7 @@ impl Clean for doctree::ProcMacro { visibility: Some(Public), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), inner: ProcMacroItem(ProcMacro { kind: self.kind, helpers: self.helpers.clean(cx), @@ -4043,7 +4277,7 @@ impl Clean for doctree::ProcMacro { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Stability { pub level: stability::StabilityLevel, pub feature: Option, @@ -4053,14 +4287,14 @@ pub struct Stability { pub issue: Option, } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Deprecation { pub since: Option, pub note: Option, } impl Clean for attr::Stability { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> Stability { + fn clean(&self, _: &DocContext<'_>) -> Stability { Stability { level: stability::StabilityLevel::from_attr_level(&self.level), feature: Some(self.feature.to_string()).filter(|f| !f.is_empty()), @@ -4087,13 +4321,13 @@ impl Clean for attr::Stability { } impl<'a> Clean for &'a attr::Stability { - fn clean(&self, dc: &DocContext<'_, '_, '_>) -> Stability { + fn clean(&self, dc: &DocContext<'_>) -> Stability { (**self).clean(dc) } } impl Clean for attr::Deprecation { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> Deprecation { + fn clean(&self, _: &DocContext<'_>) -> Deprecation { Deprecation { since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()), note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()), @@ -4101,24 +4335,59 @@ impl Clean for attr::Deprecation { } } -/// An equality constraint on an associated type, e.g., `A = Bar` in `Foo` -#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)] +/// An type binding on an associated type (e.g., `A = Bar` in `Foo` or +/// `A: Send + Sync` in `Foo`). +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeBinding { pub name: String, - pub ty: Type + pub kind: TypeBindingKind, +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum TypeBindingKind { + Equality { + ty: Type, + }, + Constraint { + bounds: Vec, + }, +} + +impl TypeBinding { + pub fn ty(&self) -> &Type { + match self.kind { + TypeBindingKind::Equality { ref ty } => ty, + _ => panic!("expected equality type binding for parenthesized generic args"), + } + } } impl Clean for hir::TypeBinding { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> TypeBinding { + fn clean(&self, cx: &DocContext<'_>) -> TypeBinding { TypeBinding { name: self.ident.name.clean(cx), - ty: self.ty.clean(cx) + kind: self.kind.clean(cx), + } + } +} + +impl Clean for hir::TypeBindingKind { + fn clean(&self, cx: &DocContext<'_>) -> TypeBindingKind { + match *self { + hir::TypeBindingKind::Equality { ref ty } => + TypeBindingKind::Equality { + ty: ty.clean(cx), + }, + hir::TypeBindingKind::Constraint { ref bounds } => + TypeBindingKind::Constraint { + bounds: bounds.into_iter().map(|b| b.clean(cx)).collect(), + }, } } } pub fn def_id_to_path( - cx: &DocContext<'_, '_, '_>, + cx: &DocContext<'_>, did: DefId, name: Option ) -> Vec { @@ -4135,7 +4404,7 @@ pub fn def_id_to_path( once(crate_name).chain(relative).collect() } -pub fn enter_impl_trait(cx: &DocContext<'_, '_, '_>, f: F) -> R +pub fn enter_impl_trait(cx: &DocContext<'_>, f: F) -> R where F: FnOnce() -> R, { @@ -4146,109 +4415,6 @@ where r } -// Start of code copied from rust-clippy - -pub fn path_to_def_local(tcx: &TyCtxt<'_, '_, '_>, path: &[&str]) -> Option { - let krate = tcx.hir().krate(); - let mut items = krate.module.item_ids.clone(); - let mut path_it = path.iter().peekable(); - - loop { - let segment = path_it.next()?; - - for item_id in mem::replace(&mut items, HirVec::new()).iter() { - let item = tcx.hir().expect_item(item_id.id); - if item.ident.name == *segment { - if path_it.peek().is_none() { - return Some(tcx.hir().local_def_id(item_id.id)) - } - - items = match &item.node { - &hir::ItemKind::Mod(ref m) => m.item_ids.clone(), - _ => panic!("Unexpected item {:?} in path {:?} path") - }; - break; - } - } - } -} - -pub fn path_to_def(tcx: &TyCtxt<'_, '_, '_>, path: &[&str]) -> Option { - let crates = tcx.crates(); - - let krate = crates - .iter() - .find(|&&krate| tcx.crate_name(krate) == path[0]); - - if let Some(krate) = krate { - let krate = DefId { - krate: *krate, - index: CRATE_DEF_INDEX, - }; - let mut items = tcx.item_children(krate); - let mut path_it = path.iter().skip(1).peekable(); - - loop { - let segment = path_it.next()?; - - for item in mem::replace(&mut items, Lrc::new(vec![])).iter() { - if item.ident.name == *segment { - if path_it.peek().is_none() { - return match item.def { - def::Def::Trait(did) => Some(did), - _ => None, - } - } - - items = tcx.item_children(item.def.def_id()); - break; - } - } - } - } else { - None - } -} - -pub fn get_path_for_type(tcx: TyCtxt<'_, '_, '_>, def_id: DefId, def_ctor: F) -> hir::Path -where F: Fn(DefId) -> Def { - #[derive(Debug)] - struct AbsolutePathBuffer { - names: Vec, - } - - impl ty::item_path::ItemPathBuffer for AbsolutePathBuffer { - fn root_mode(&self) -> &ty::item_path::RootMode { - const ABSOLUTE: &'static ty::item_path::RootMode = &ty::item_path::RootMode::Absolute; - ABSOLUTE - } - - fn push(&mut self, text: &str) { - self.names.push(text.to_owned()); - } - } - - let mut apb = AbsolutePathBuffer { names: vec![] }; - - tcx.push_item_path(&mut apb, def_id, false); - - hir::Path { - span: DUMMY_SP, - def: def_ctor(def_id), - segments: hir::HirVec::from_vec(apb.names.iter().map(|s| hir::PathSegment { - ident: ast::Ident::from_str(&s), - id: None, - hir_id: None, - def: None, - args: None, - infer_types: false, - }).collect()) - } -} - -// End of code copied from rust-clippy - - #[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)] enum RegionTarget<'tcx> { Region(Region<'tcx>), @@ -4267,29 +4433,14 @@ enum SimpleBound { Outlives(Lifetime), } -enum AutoTraitResult { - ExplicitImpl, - PositiveImpl(Generics), - NegativeImpl, -} - -impl AutoTraitResult { - fn is_auto(&self) -> bool { - match *self { - AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true, - _ => false, - } - } -} - impl From for SimpleBound { fn from(bound: GenericBound) -> Self { match bound.clone() { GenericBound::Outlives(l) => SimpleBound::Outlives(l), GenericBound::TraitBound(t, mod_) => match t.trait_ { - Type::ResolvedPath { path, typarams, .. } => { + Type::ResolvedPath { path, param_names, .. } => { SimpleBound::TraitBound(path.segments, - typarams + param_names .map_or_else(|| Vec::new(), |v| v.iter() .map(|p| SimpleBound::from(p.clone())) .collect()), diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 8614b72dffba7..36e6a6003df09 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -22,7 +22,7 @@ use crate::clean::WherePredicate as WP; use crate::clean; use crate::core::DocContext; -pub fn where_clauses(cx: &DocContext<'_, '_, '_>, clauses: Vec) -> Vec { +pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { // First, partition the where clause into its separate components let mut params: BTreeMap<_, Vec<_>> = BTreeMap::new(); let mut lifetimes = Vec::new(); @@ -91,7 +91,9 @@ pub fn where_clauses(cx: &DocContext<'_, '_, '_>, clauses: Vec) -> Vec { PP::AngleBracketed { ref mut bindings, .. } => { bindings.push(clean::TypeBinding { name: name.clone(), - ty: rhs.clone(), + kind: clean::TypeBindingKind::Equality { + ty: rhs.clone(), + }, }); } PP::Parenthesized { ref mut output, .. } => { @@ -141,7 +143,7 @@ fn ty_bounds(bounds: Vec) -> Vec { bounds } -fn trait_is_same_or_supertrait(cx: &DocContext<'_, '_, '_>, child: DefId, +fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) -> bool { if child == trait_ { return true diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index b1c53ea92b300..67ca7f407d801 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -1,19 +1,19 @@ -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeMap; use std::fmt; use std::path::PathBuf; use errors; -use errors::emitter::ColorConfig; +use errors::emitter::{ColorConfig, HumanReadableErrorType}; use getopts; use rustc::lint::Level; use rustc::session::early_error; use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options, - get_cmd_lint_options}; + get_cmd_lint_options, ExternEntry}; use rustc::session::search_paths::SearchPath; use rustc_driver; use rustc_target::spec::TargetTriple; -use syntax::edition::Edition; +use syntax::edition::{Edition, DEFAULT_EDITION}; use crate::core::new_handler; use crate::externalfiles::ExternalHtml; @@ -85,6 +85,9 @@ pub struct Options { /// Whether to display warnings during doc generation or while gathering doctests. By default, /// all non-rustdoc-specific lints are allowed when generating docs. pub display_warnings: bool, + /// Whether to run the `calculate-doc-coverage` pass, which counts the number of public items + /// with and without documentation. + pub show_coverage: bool, // Options that alter generated documentation pages @@ -128,6 +131,7 @@ impl fmt::Debug for Options { .field("default_passes", &self.default_passes) .field("manual_passes", &self.manual_passes) .field("display_warnings", &self.display_warnings) + .field("show_coverage", &self.show_coverage) .field("crate_version", &self.crate_version) .field("render_options", &self.render_options) .finish() @@ -199,7 +203,7 @@ pub struct RenderOptions { impl Options { /// Parses the given command-line for options. If an error message or other early-return has /// been printed, returns `Err` with the exit code. - pub fn from_matches(matches: &getopts::Matches) -> Result { + pub fn from_matches(matches: &getopts::Matches) -> Result { // Check for unstable options. nightly_options::check_nightly_options(&matches, &opts()); @@ -224,6 +228,18 @@ impl Options { for &name in passes::DEFAULT_PRIVATE_PASSES { println!("{:>20}", name); } + + if nightly_options::is_nightly_build() { + println!("\nPasses run with `--show-coverage`:"); + for &name in passes::DEFAULT_COVERAGE_PASSES { + println!("{:>20}", name); + } + println!("\nPasses run with `--show-coverage --document-private-items`:"); + for &name in passes::PRIVATE_COVERAGE_PASSES { + println!("{:>20}", name); + } + } + return Err(0); } @@ -238,12 +254,19 @@ impl Options { (instead was `{}`)", arg)); } }; + // FIXME: deduplicate this code from the identical code in librustc/session/config.rs let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) { - Some("human") => ErrorOutputType::HumanReadable(color), - Some("json") => ErrorOutputType::Json(false), - Some("pretty-json") => ErrorOutputType::Json(true), - Some("short") => ErrorOutputType::Short(color), - None => ErrorOutputType::HumanReadable(color), + None | + Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)), + Some("json") => ErrorOutputType::Json { + pretty: false, + json_rendered: HumanReadableErrorType::Default(ColorConfig::Never), + }, + Some("pretty-json") => ErrorOutputType::Json { + pretty: true, + json_rendered: HumanReadableErrorType::Default(ColorConfig::Never), + }, + Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)), Some(arg) => { early_error(ErrorOutputType::default(), &format!("argument for --error-format must be `human`, `json` or \ @@ -360,6 +383,18 @@ impl Options { } } + let edition = if let Some(e) = matches.opt_str("edition") { + match e.parse() { + Ok(e) => e, + Err(_) => { + diag.struct_err("could not parse edition").emit(); + return Err(1); + } + } + } else { + DEFAULT_EDITION + }; + let mut id_map = html::markdown::IdMap::new(); id_map.populate(html::render::initial_ids()); let external_html = match ExternalHtml::load( @@ -367,20 +402,12 @@ impl Options { &matches.opt_strs("html-before-content"), &matches.opt_strs("html-after-content"), &matches.opt_strs("markdown-before-content"), - &matches.opt_strs("markdown-after-content"), &diag, &mut id_map) { + &matches.opt_strs("markdown-after-content"), + &diag, &mut id_map, edition) { Some(eh) => eh, None => return Err(3), }; - let edition = matches.opt_str("edition").unwrap_or("2015".to_string()); - let edition = match edition.parse() { - Ok(e) => e, - Err(_) => { - diag.struct_err("could not parse edition").emit(); - return Err(1); - } - }; - match matches.opt_str("r").as_ref().map(|s| &**s) { Some("rust") | None => {} Some(s) => { @@ -413,9 +440,16 @@ impl Options { } }); + let show_coverage = matches.opt_present("show-coverage"); + let document_private = matches.opt_present("document-private-items"); + let default_passes = if matches.opt_present("no-defaults") { passes::DefaultPassOption::None - } else if matches.opt_present("document-private-items") { + } else if show_coverage && document_private { + passes::DefaultPassOption::PrivateCoverage + } else if show_coverage { + passes::DefaultPassOption::Coverage + } else if document_private { passes::DefaultPassOption::Private } else { passes::DefaultPassOption::Default @@ -463,6 +497,7 @@ impl Options { default_passes, manual_passes, display_warnings, + show_coverage, crate_version, persist_doctests, render_options: RenderOptions { @@ -504,7 +539,7 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) "passes", ]; - for flag in deprecated_flags.into_iter() { + for flag in deprecated_flags.iter() { if matches.opt_present(flag) { let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated", flag)); @@ -554,7 +589,7 @@ fn parse_extern_html_roots( /// error message. // FIXME(eddyb) This shouldn't be duplicated with `rustc::session`. fn parse_externs(matches: &getopts::Matches) -> Result { - let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new(); + let mut externs: BTreeMap<_, ExternEntry> = BTreeMap::new(); for arg in &matches.opt_strs("extern") { let mut parts = arg.splitn(2, '='); let name = parts.next().ok_or("--extern value must not be empty".to_string())?; @@ -564,7 +599,10 @@ fn parse_externs(matches: &getopts::Matches) -> Result { enable `--extern crate_name` without `=path`".to_string()); } let name = name.to_string(); - externs.entry(name).or_default().insert(location); + // For Rustdoc purposes, we can treat all externs as public + externs.entry(name) + .or_default() + .locations.insert(location.clone()); } Ok(Externs::new(externs)) } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index fdb071638b799..29ee59d124274 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,43 +1,38 @@ use rustc_lint; -use rustc_driver::{driver, abort_on_err}; use rustc::session::{self, config}; -use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CrateNum, LOCAL_CRATE}; -use rustc::hir::def::Def; -use rustc::hir::{self, HirVec}; +use rustc::hir::def_id::{DefId, DefIndex, CrateNum, LOCAL_CRATE}; +use rustc::hir::HirId; use rustc::middle::cstore::CrateStore; use rustc::middle::privacy::AccessLevels; -use rustc::ty::{self, TyCtxt, AllArenas}; -use rustc::hir::map as hir_map; +use rustc::ty::{Ty, TyCtxt}; use rustc::lint::{self, LintPass}; use rustc::session::config::ErrorOutputType; +use rustc::session::DiagnosticOutput; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use rustc_interface::util; +use rustc_interface::interface; +use rustc_driver::abort_on_err; use rustc_resolve as resolve; -use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::CStore; use rustc_target::spec::TargetTriple; -use syntax::ast::{self, Ident, NodeId}; use syntax::source_map; use syntax::feature_gate::UnstableFeatures; use syntax::json::JsonEmitter; -use syntax::ptr::P; -use syntax::symbol::keywords; -use syntax_pos::DUMMY_SP; -use errors::{self, FatalError}; +use syntax::symbol::sym; +use errors; use errors::emitter::{Emitter, EmitterWriter}; use parking_lot::ReentrantMutex; use std::cell::RefCell; use std::mem; use rustc_data_structures::sync::{self, Lrc}; -use std::rc::Rc; use std::sync::Arc; +use std::rc::Rc; use crate::visit_ast::RustdocVisitor; use crate::config::{Options as RustdocOptions, RenderOptions}; use crate::clean; -use crate::clean::{get_path_for_type, Clean, MAX_DEF_ID, AttributesExt}; +use crate::clean::{Clean, MAX_DEF_ID, AttributesExt}; use crate::html::render::RenderInfo; use crate::passes; @@ -47,12 +42,13 @@ pub use rustc::session::search_paths::SearchPath; pub type ExternalPaths = FxHashMap, clean::TypeKind)>; -pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - pub resolver: &'a RefCell>, +pub struct DocContext<'tcx> { + + pub tcx: TyCtxt<'tcx>, + pub resolver: Rc>>, /// The stack of module NodeIds up till this point pub crate_name: Option, - pub cstore: Rc, + pub cstore: Lrc, /// Later on moved into `html::render::CACHE_KEY` pub renderinfo: RefCell, /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY` @@ -63,33 +59,41 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { // The current set of type and lifetime substitutions, // for expanding type aliases at the HIR level: - /// Table type parameter definition -> substituted type - pub ty_substs: RefCell>, - /// Table `NodeId` of lifetime parameter definition -> substituted lifetime + /// Table `DefId` of type parameter -> substituted type + pub ty_substs: RefCell>, + /// Table `DefId` of lifetime parameter -> substituted lifetime pub lt_substs: RefCell>, - /// Table node id of const parameter definition -> substituted const - pub ct_substs: RefCell>, + /// Table `DefId` of const parameter -> substituted const + pub ct_substs: RefCell>, /// Table DefId of `impl Trait` in argument position -> bounds pub impl_trait_bounds: RefCell>>, - pub send_trait: Option, pub fake_def_ids: RefCell>, pub all_fake_def_ids: RefCell>, - /// Maps (type_id, trait_id) -> auto trait impl - pub generated_synthetics: RefCell>, + /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`. + // FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set. + pub generated_synthetics: RefCell, DefId)>>, pub all_traits: Vec, + pub auto_traits: Vec, } -impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> { +impl<'tcx> DocContext<'tcx> { pub fn sess(&self) -> &session::Session { &self.tcx.sess } + pub fn enter_resolver(&self, f: F) -> R + where F: FnOnce(&mut resolve::Resolver<'_>) -> R { + let resolver = &*self.resolver; + let resolver = resolver.as_ref().unwrap(); + resolver.borrow_mut().access(f) + } + /// Call the closure with the given parameters set as /// the substitutions for a type alias' RHS. pub fn enter_alias(&self, - ty_substs: FxHashMap, + ty_substs: FxHashMap, lt_substs: FxHashMap, - ct_substs: FxHashMap, + ct_substs: FxHashMap, f: F) -> R where F: FnOnce() -> R { let (old_tys, old_lts, old_cts) = ( @@ -109,8 +113,8 @@ impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> { // registered after the AST is constructed would require storing the defid mapping in a // RefCell, decreasing the performance for normal compilation for very little gain. // - // Instead, we construct 'fake' def ids, which start immediately after the last DefId in - // DefIndexAddressSpace::Low. In the Debug impl for clean::Item, we explicitly check for fake + // Instead, we construct 'fake' def ids, which start immediately after the last DefId. + // In the Debug impl for clean::Item, we explicitly check for fake // def ids, as we'll end up with a panic if we use the DefId Debug impl for fake DefIds pub fn next_def_id(&self, crate_num: CrateNum) -> DefId { let start_def_id = { @@ -119,11 +123,11 @@ impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> { .hir() .definitions() .def_path_table() - .next_id(DefIndexAddressSpace::Low) + .next_id() } else { self.cstore .def_path_table(crate_num) - .next_id(DefIndexAddressSpace::Low) + .next_id() }; DefId { @@ -139,10 +143,7 @@ impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> { crate_num, DefId { krate: crate_num, - index: DefIndex::from_array_index( - def_id.index.as_array_index() + 1, - def_id.index.address_space(), - ), + index: DefIndex::from(def_id.index.index() + 1), }, ); @@ -159,93 +160,11 @@ impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> { /// Like the function of the same name on the HIR map, but skips calling it on fake DefIds. /// (This avoids a slice-index-out-of-bounds panic.) - pub fn as_local_node_id(&self, def_id: DefId) -> Option { + pub fn as_local_hir_id(&self, def_id: DefId) -> Option { if self.all_fake_def_ids.borrow().contains(&def_id) { None } else { - self.tcx.hir().as_local_node_id(def_id) - } - } - - pub fn get_real_ty(&self, - def_id: DefId, - def_ctor: &F, - real_name: &Option, - generics: &ty::Generics, - ) -> hir::Ty - where F: Fn(DefId) -> Def { - let path = get_path_for_type(self.tcx, def_id, def_ctor); - let mut segments = path.segments.into_vec(); - let last = segments.pop().expect("segments were empty"); - - segments.push(hir::PathSegment::new( - real_name.unwrap_or(last.ident), - None, - None, - None, - self.generics_to_path_params(generics.clone()), - false, - )); - - let new_path = hir::Path { - span: path.span, - def: path.def, - segments: HirVec::from_vec(segments), - }; - - hir::Ty { - node: hir::TyKind::Path(hir::QPath::Resolved(None, P(new_path))), - span: DUMMY_SP, - hir_id: hir::DUMMY_HIR_ID, - } - } - - pub fn generics_to_path_params(&self, generics: ty::Generics) -> hir::GenericArgs { - let mut args = vec![]; - - for param in generics.params.iter() { - match param.kind { - ty::GenericParamDefKind::Lifetime => { - let name = if param.name == "" { - hir::ParamName::Plain(keywords::StaticLifetime.ident()) - } else { - hir::ParamName::Plain(ast::Ident::from_interned_str(param.name)) - }; - - args.push(hir::GenericArg::Lifetime(hir::Lifetime { - hir_id: hir::DUMMY_HIR_ID, - span: DUMMY_SP, - name: hir::LifetimeName::Param(name), - })); - } - ty::GenericParamDefKind::Type { .. } => { - args.push(hir::GenericArg::Type(self.ty_param_to_ty(param.clone()))); - } - } - } - - hir::GenericArgs { - args: HirVec::from_vec(args), - bindings: HirVec::new(), - parenthesized: false, - } - } - - pub fn ty_param_to_ty(&self, param: ty::GenericParamDef) -> hir::Ty { - debug!("ty_param_to_ty({:?}) {:?}", param, param.def_id); - hir::Ty { - node: hir::TyKind::Path(hir::QPath::Resolved( - None, - P(hir::Path { - span: DUMMY_SP, - def: Def::TyParam(param.def_id), - segments: HirVec::from_vec(vec![ - hir::PathSegment::from_ident(Ident::from_interned_str(param.name)) - ]), - }), - )), - span: DUMMY_SP, - hir_id: hir::DUMMY_HIR_ID, + self.tcx.hir().as_local_hir_id(def_id) } } } @@ -266,22 +185,25 @@ impl DocAccessLevels for AccessLevels { /// will be created for the handler. pub fn new_handler(error_format: ErrorOutputType, source_map: Option>, - treat_err_as_bug: bool, + treat_err_as_bug: Option, ui_testing: bool, ) -> errors::Handler { // rustdoc doesn't override (or allow to override) anything from this that is relevant here, so // stick to the defaults let sessopts = Options::default(); let emitter: Box = match error_format { - ErrorOutputType::HumanReadable(color_config) => Box::new( - EmitterWriter::stderr( - color_config, - source_map.map(|cm| cm as _), - false, - sessopts.debugging_opts.teach, - ).ui_testing(ui_testing) - ), - ErrorOutputType::Json(pretty) => { + ErrorOutputType::HumanReadable(kind) => { + let (short, color_config) = kind.unzip(); + Box::new( + EmitterWriter::stderr( + color_config, + source_map.map(|cm| cm as _), + short, + sessopts.debugging_opts.teach, + ).ui_testing(ui_testing) + ) + }, + ErrorOutputType::Json { pretty, json_rendered } => { let source_map = source_map.unwrap_or_else( || Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping()))); Box::new( @@ -289,16 +211,10 @@ pub fn new_handler(error_format: ErrorOutputType, None, source_map, pretty, + json_rendered, ).ui_testing(ui_testing) ) }, - ErrorOutputType::Short(color_config) => Box::new( - EmitterWriter::stderr( - color_config, - source_map.map(|cm| cm as _), - true, - false) - ), }; errors::Handler::with_emitter_and_flags( @@ -357,19 +273,31 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); - let lints = lint::builtin::HardwiredLints.get_lints() - .into_iter() - .chain(rustc_lint::SoftLints.get_lints().into_iter()) - .filter_map(|lint| { - if lint.name == warnings_lint_name || - lint.name == intra_link_resolution_failure_name { - None - } else { - Some((lint.name_lower(), lint::Allow)) - } - }) - .chain(lint_opts.into_iter()) - .collect::>(); + let lints = || { + lint::builtin::HardwiredLints + .get_lints() + .into_iter() + .chain(rustc_lint::SoftLints.get_lints().into_iter()) + }; + + let lint_opts = lints().filter_map(|lint| { + if lint.name == warnings_lint_name || + lint.name == intra_link_resolution_failure_name { + None + } else { + Some((lint.name_lower(), lint::Allow)) + } + }).chain(lint_opts.into_iter()).collect::>(); + + let lint_caps = lints().filter_map(|lint| { + // We don't want to whitelist *all* lints so let's + // ignore those ones. + if whitelisted_lints.iter().any(|l| &lint.name == l) { + None + } else { + Some((lint::LintId::of(lint), lint::Allow)) + } + }).collect(); let host_triple = TargetTriple::from_triple(config::host_triple()); // plays with error output here! @@ -378,7 +306,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt search_paths: libs, crate_types: vec![config::CrateType::Rlib], lint_opts: if !display_warnings { - lints + lint_opts } else { vec![] }, @@ -389,144 +317,65 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt // Ensure that rustdoc works even if rustc is feature-staged unstable_features: UnstableFeatures::Allow, actually_rustdoc: true, - debugging_opts: debugging_options.clone(), + debugging_opts: debugging_options, error_format, edition, describe_lints, ..Options::default() }; - driver::spawn_thread_pool(sessopts, move |sessopts| { - let source_map = Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping())); - let diagnostic_handler = new_handler(error_format, - Some(source_map.clone()), - debugging_options.treat_err_as_bug, - debugging_options.ui_testing); - - let mut sess = session::build_session_( - sessopts, cpath, diagnostic_handler, source_map, Default::default(), - ); - lint::builtin::HardwiredLints.get_lints() - .into_iter() - .chain(rustc_lint::SoftLints.get_lints().into_iter()) - .filter_map(|lint| { - // We don't want to whitelist *all* lints so let's - // ignore those ones. - if whitelisted_lints.iter().any(|l| &lint.name == l) { - None - } else { - Some(lint) - } - }) - .for_each(|l| { - sess.driver_lint_caps.insert(lint::LintId::of(l), - lint::Allow); - }); - - let codegen_backend = util::get_codegen_backend(&sess); - let cstore = Rc::new(CStore::new(codegen_backend.metadata_loader())); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - - let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs)); - util::add_configuration(&mut cfg, &sess, &*codegen_backend); - sess.parse_sess.config = cfg; - - let control = &driver::CompileController::basic(); - - let krate = match driver::phase_1_parse_input(control, &sess, &input) { - Ok(krate) => krate, - Err(mut e) => { - e.emit(); - FatalError.raise(); - } - }; + let config = interface::Config { + opts: sessopts, + crate_cfg: config::parse_cfgspecs(cfgs), + input, + input_path: cpath, + output_file: None, + output_dir: None, + file_loader: None, + diagnostic_output: DiagnosticOutput::Default, + stderr: None, + crate_name: crate_name.clone(), + lint_caps, + }; - let name = match crate_name { - Some(ref crate_name) => crate_name.clone(), - None => ::rustc_codegen_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input), - }; + interface::run_compiler_in_existing_thread_pool(config, |compiler| { + let sess = compiler.session(); - let mut crate_loader = CrateLoader::new(&sess, &cstore, &name); - - let resolver_arenas = resolve::Resolver::arenas(); - let result = driver::phase_2_configure_and_expand_inner(&sess, - &cstore, - krate, - None, - &name, - None, - &resolver_arenas, - &mut crate_loader, - |_| Ok(())); - let driver::InnerExpansionResult { - mut hir_forest, - resolver, - .. - } = abort_on_err(result, &sess); - - // We need to hold on to the complete resolver, so we clone everything - // for the analysis passes to use. Suboptimal, but necessary in the + // We need to hold on to the complete resolver, so we cause everything to be + // cloned for the analysis passes to use. Suboptimal, but necessary in the // current architecture. - let defs = resolver.definitions.clone(); - let resolutions = ty::Resolutions { - freevars: resolver.freevars.clone(), - export_map: resolver.export_map.clone(), - trait_map: resolver.trait_map.clone(), - glob_map: resolver.glob_map.clone(), - maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(), - maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(), - extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { - (ident.name, entry.introduced_by_item) - }).collect(), - }; + let resolver = abort_on_err(compiler.expansion(), sess).peek().1.clone(); - let mut arenas = AllArenas::new(); - let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs); - let output_filenames = util::build_output_filenames(&input, - &None, - &None, - &[], - &sess); - - let resolver = RefCell::new(resolver); - driver::phase_3_run_analysis_passes(&*codegen_backend, - control, - &sess, - &*cstore, - hir_map, - resolutions, - &mut arenas, - &name, - &output_filenames, - |tcx, _, result| { - if result.is_err() { - sess.fatal("Compilation failed, aborting rustdoc"); - } + if sess.has_errors() { + sess.fatal("Compilation failed, aborting rustdoc"); + } - let access_levels = tcx.privacy_access_levels(LOCAL_CRATE); + let mut global_ctxt = abort_on_err(compiler.global_ctxt(), sess).take(); + + global_ctxt.enter(|tcx| { + tcx.analysis(LOCAL_CRATE).ok(); - // Convert from a NodeId set to a DefId set since we don't always have easy access - // to the map from defid -> nodeid + // Abort if there were any errors so far + sess.abort_if_errors(); + + let access_levels = tcx.privacy_access_levels(LOCAL_CRATE); + // Convert from a HirId set to a DefId set since we don't always have easy access + // to the map from defid -> hirid let access_levels = AccessLevels { map: access_levels.map.iter() - .map(|(&k, &v)| (tcx.hir().local_def_id(k), v)) + .map(|(&k, &v)| (tcx.hir().local_def_id_from_hir_id(k), v)) .collect() }; - let send_trait = if crate_name == Some("core".to_string()) { - clean::path_to_def_local(&tcx, &["marker", "Send"]) - } else { - clean::path_to_def(&tcx, &["core", "marker", "Send"]) - }; - let mut renderinfo = RenderInfo::default(); renderinfo.access_levels = access_levels; + let all_traits = tcx.all_traits(LOCAL_CRATE).to_vec(); let ctxt = DocContext { tcx, - resolver: &resolver, + resolver, crate_name, - cstore: cstore.clone(), + cstore: compiler.cstore().clone(), external_traits: Default::default(), active_extern_traits: Default::default(), renderinfo: RefCell::new(renderinfo), @@ -534,11 +383,13 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt lt_substs: Default::default(), ct_substs: Default::default(), impl_trait_bounds: Default::default(), - send_trait: send_trait, fake_def_ids: Default::default(), all_fake_def_ids: Default::default(), generated_synthetics: Default::default(), - all_traits: tcx.all_traits(LOCAL_CRATE).to_vec(), + auto_traits: all_traits.iter().cloned().filter(|trait_def_id| { + tcx.trait_is_auto(*trait_def_id) + }).collect(), + all_traits, }; debug!("crate: {:?}", tcx.hir().krate()); @@ -562,13 +413,12 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt // Process all of the crate attributes, extracting plugin metadata along // with the passes which we are supposed to run. - for attr in krate.module.as_ref().unwrap().attrs.lists("doc") { + for attr in krate.module.as_ref().unwrap().attrs.lists(sym::doc) { let diag = ctxt.sess().diagnostic(); - let name = attr.name().map(|s| s.as_str()); - let name = name.as_ref().map(|s| &s[..]); + let name = attr.name_or_empty(); if attr.is_word() { - if name == Some("no_default_passes") { + if name == sym::no_default_passes { report_deprecated_attr("no_default_passes", diag); if default_passes == passes::DefaultPassOption::Default { default_passes = passes::DefaultPassOption::None; @@ -576,11 +426,11 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt } } else if let Some(value) = attr.value_str() { let sink = match name { - Some("passes") => { + sym::passes => { report_deprecated_attr("passes = \"...\"", diag); &mut manual_passes }, - Some("plugins") => { + sym::plugins => { report_deprecated_attr("plugins = \"...\"", diag); eprintln!("WARNING: #![doc(plugins = \"...\")] no longer functions; \ see CVE-2018-1000622"); @@ -593,7 +443,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt } } - if attr.is_word() && name == Some("document_private_items") { + if attr.is_word() && name == sym::document_private_items { if default_passes == passes::DefaultPassOption::Default { default_passes = passes::DefaultPassOption::Private; } @@ -606,10 +456,13 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt info!("Executing passes"); - for pass in &passes { - match passes::find_pass(pass).map(|p| p.pass) { - Some(pass) => krate = pass(krate, &ctxt), - None => error!("unknown pass {}, skipping", *pass), + for pass_name in &passes { + match passes::find_pass(pass_name).map(|p| p.pass) { + Some(pass) => { + debug!("running pass {}", pass_name); + krate = pass(krate, &ctxt); + } + None => error!("unknown pass {}, skipping", *pass_name), } } diff --git a/src/librustdoc/docfs.rs b/src/librustdoc/docfs.rs new file mode 100644 index 0000000000000..740947fc3e37e --- /dev/null +++ b/src/librustdoc/docfs.rs @@ -0,0 +1,116 @@ +//! Rustdoc's FileSystem abstraction module. +//! +//! On Windows this indirects IO into threads to work around performance issues +//! with Defender (and other similar virus scanners that do blocking operations). +//! On other platforms this is a thin shim to fs. +//! +//! Only calls needed to permit this workaround have been abstracted: thus +//! fs::read is still done directly via the fs module; if in future rustdoc +//! needs to read-after-write from a file, then it would be added to this +//! abstraction. + +use errors; + +use std::fs; +use std::io; +use std::path::Path; +use std::sync::Arc; +use std::sync::mpsc::{channel, Receiver, Sender}; + +macro_rules! try_err { + ($e:expr, $file:expr) => {{ + match $e { + Ok(e) => e, + Err(e) => return Err(E::new(e, $file)), + } + }}; +} + +pub trait PathError { + fn new>(e: io::Error, path: P) -> Self; +} + +pub struct ErrorStorage { + sender: Option>>, + receiver: Receiver>, +} + +impl ErrorStorage { + pub fn new() -> ErrorStorage { + let (sender, receiver) = channel(); + ErrorStorage { + sender: Some(sender), + receiver, + } + } + + /// Prints all stored errors. Returns the number of printed errors. + pub fn write_errors(&mut self, diag: &errors::Handler) -> usize { + let mut printed = 0; + // In order to drop the sender part of the channel. + self.sender = None; + + for msg in self.receiver.iter() { + if let Some(ref error) = msg { + diag.struct_err(&error).emit(); + printed += 1; + } + } + printed + } +} + +pub struct DocFS { + sync_only: bool, + errors: Arc, +} + +impl DocFS { + pub fn new(errors: &Arc) -> DocFS { + DocFS { + sync_only: false, + errors: Arc::clone(errors), + } + } + + pub fn set_sync_only(&mut self, sync_only: bool) { + self.sync_only = sync_only; + } + + pub fn create_dir_all>(&self, path: P) -> io::Result<()> { + // For now, dir creation isn't a huge time consideration, do it + // synchronously, which avoids needing ordering between write() actions + // and directory creation. + fs::create_dir_all(path) + } + + pub fn write(&self, path: P, contents: C) -> Result<(), E> + where + P: AsRef, + C: AsRef<[u8]>, + E: PathError, + { + if !self.sync_only && cfg!(windows) { + // A possible future enhancement after more detailed profiling would + // be to create the file sync so errors are reported eagerly. + let contents = contents.as_ref().to_vec(); + let path = path.as_ref().to_path_buf(); + let sender = self.errors.sender.clone().unwrap(); + rayon::spawn(move || { + match fs::write(&path, &contents) { + Ok(_) => { + sender.send(None) + .expect(&format!("failed to send error on \"{}\"", path.display())); + } + Err(e) => { + sender.send(Some(format!("\"{}\": {}", path.display(), e))) + .expect(&format!("failed to send non-error on \"{}\"", path.display())); + } + } + }); + Ok(()) + } else { + Ok(try_err!(fs::write(&path, contents), path)) + } + } +} diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index e8458385739df..2557b8d1627c0 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -7,52 +7,55 @@ use syntax::ast::{Name, NodeId}; use syntax::attr; use syntax::ext::base::MacroKind; use syntax::ptr::P; -use syntax::source_map::Spanned; use syntax_pos::{self, Span}; use rustc::hir; use rustc::hir::def_id::CrateNum; -pub struct Module { +pub struct Module<'hir> { pub name: Option, - pub attrs: hir::HirVec, + pub attrs: &'hir hir::HirVec, pub where_outer: Span, pub where_inner: Span, - pub extern_crates: Vec, - pub imports: Vec, - pub structs: Vec, - pub unions: Vec, - pub enums: Vec, - pub fns: Vec, - pub mods: Vec, + pub extern_crates: Vec>, + pub imports: Vec>, + pub structs: Vec>, + pub unions: Vec>, + pub enums: Vec>, + pub fns: Vec>, + pub mods: Vec>, pub id: NodeId, - pub typedefs: Vec, - pub existentials: Vec, - pub statics: Vec, - pub constants: Vec, - pub traits: Vec, - pub vis: hir::Visibility, + pub typedefs: Vec>, + pub existentials: Vec>, + pub statics: Vec>, + pub constants: Vec>, + pub traits: Vec>, + pub vis: &'hir hir::Visibility, pub stab: Option, pub depr: Option, - pub impls: Vec, - pub foreigns: Vec, - pub macros: Vec, - pub proc_macros: Vec, - pub trait_aliases: Vec, + pub impls: Vec>, + pub foreigns: Vec>, + pub macros: Vec>, + pub proc_macros: Vec>, + pub trait_aliases: Vec>, pub is_crate: bool, } -impl Module { - pub fn new(name: Option) -> Module { +impl Module<'hir> { + pub fn new( + name: Option, + attrs: &'hir hir::HirVec, + vis: &'hir hir::Visibility, + ) -> Module<'hir> { Module { name : name, id: ast::CRATE_NODE_ID, - vis: Spanned { span: syntax_pos::DUMMY_SP, node: hir::VisibilityKind::Inherited }, + vis, stab: None, depr: None, where_outer: syntax_pos::DUMMY_SP, where_inner: syntax_pos::DUMMY_SP, - attrs : hir::HirVec::new(), + attrs, extern_crates: Vec::new(), imports : Vec::new(), structs : Vec::new(), @@ -75,7 +78,7 @@ impl Module { } } -#[derive(Debug, Clone, RustcEncodable, RustcDecodable, Copy)] +#[derive(Debug, Clone, Copy)] pub enum StructType { /// A braced struct Plain, @@ -85,166 +88,178 @@ pub enum StructType { Unit, } -pub struct Struct { - pub vis: hir::Visibility, +pub struct Struct<'hir> { + pub vis: &'hir hir::Visibility, pub stab: Option, pub depr: Option, - pub id: NodeId, + pub id: hir::HirId, pub struct_type: StructType, pub name: Name, - pub generics: hir::Generics, - pub attrs: hir::HirVec, - pub fields: hir::HirVec, + pub generics: &'hir hir::Generics, + pub attrs: &'hir hir::HirVec, + pub fields: &'hir [hir::StructField], pub whence: Span, } -pub struct Union { - pub vis: hir::Visibility, +pub struct Union<'hir> { + pub vis: &'hir hir::Visibility, pub stab: Option, pub depr: Option, - pub id: NodeId, + pub id: hir::HirId, pub struct_type: StructType, pub name: Name, - pub generics: hir::Generics, - pub attrs: hir::HirVec, - pub fields: hir::HirVec, + pub generics: &'hir hir::Generics, + pub attrs: &'hir hir::HirVec, + pub fields: &'hir [hir::StructField], pub whence: Span, } -pub struct Enum { - pub vis: hir::Visibility, +pub struct Enum<'hir> { + pub vis: &'hir hir::Visibility, pub stab: Option, pub depr: Option, - pub variants: hir::HirVec, - pub generics: hir::Generics, - pub attrs: hir::HirVec, - pub id: NodeId, + pub variants: Vec>, + pub generics: &'hir hir::Generics, + pub attrs: &'hir hir::HirVec, + pub id: hir::HirId, pub whence: Span, pub name: Name, } -pub struct Variant { +pub struct Variant<'hir> { pub name: Name, - pub attrs: hir::HirVec, - pub def: hir::VariantData, + pub id: hir::HirId, + pub attrs: &'hir hir::HirVec, + pub def: &'hir hir::VariantData, pub stab: Option, pub depr: Option, pub whence: Span, } -pub struct Function { - pub decl: hir::FnDecl, - pub attrs: hir::HirVec, - pub id: NodeId, +pub struct Function<'hir> { + pub decl: &'hir hir::FnDecl, + pub attrs: &'hir hir::HirVec, + pub id: hir::HirId, pub name: Name, - pub vis: hir::Visibility, + pub vis: &'hir hir::Visibility, pub stab: Option, pub depr: Option, pub header: hir::FnHeader, pub whence: Span, - pub generics: hir::Generics, + pub generics: &'hir hir::Generics, pub body: hir::BodyId, } -pub struct Typedef { - pub ty: P, - pub gen: hir::Generics, +pub struct Typedef<'hir> { + pub ty: &'hir P, + pub gen: &'hir hir::Generics, pub name: Name, - pub id: ast::NodeId, - pub attrs: hir::HirVec, + pub id: hir::HirId, + pub attrs: &'hir hir::HirVec, pub whence: Span, - pub vis: hir::Visibility, + pub vis: &'hir hir::Visibility, pub stab: Option, pub depr: Option, } -pub struct Existential { - pub exist_ty: hir::ExistTy, +pub struct Existential<'hir> { + pub exist_ty: &'hir hir::ExistTy, pub name: Name, - pub id: ast::NodeId, - pub attrs: hir::HirVec, + pub id: hir::HirId, + pub attrs: &'hir hir::HirVec, pub whence: Span, - pub vis: hir::Visibility, + pub vis: &'hir hir::Visibility, pub stab: Option, pub depr: Option, } #[derive(Debug)] -pub struct Static { - pub type_: P, +pub struct Static<'hir> { + pub type_: &'hir P, pub mutability: hir::Mutability, pub expr: hir::BodyId, pub name: Name, - pub attrs: hir::HirVec, - pub vis: hir::Visibility, + pub attrs: &'hir hir::HirVec, + pub vis: &'hir hir::Visibility, pub stab: Option, pub depr: Option, - pub id: ast::NodeId, + pub id: hir::HirId, pub whence: Span, } -pub struct Constant { - pub type_: P, +pub struct Constant<'hir> { + pub type_: &'hir P, pub expr: hir::BodyId, pub name: Name, - pub attrs: hir::HirVec, - pub vis: hir::Visibility, + pub attrs: &'hir hir::HirVec, + pub vis: &'hir hir::Visibility, pub stab: Option, pub depr: Option, - pub id: ast::NodeId, + pub id: hir::HirId, pub whence: Span, } -pub struct Trait { +pub struct Trait<'hir> { pub is_auto: hir::IsAuto, pub unsafety: hir::Unsafety, pub name: Name, - pub items: hir::HirVec, - pub generics: hir::Generics, - pub bounds: hir::HirVec, - pub attrs: hir::HirVec, - pub id: ast::NodeId, + pub items: Vec<&'hir hir::TraitItem>, + pub generics: &'hir hir::Generics, + pub bounds: &'hir hir::HirVec, + pub attrs: &'hir hir::HirVec, + pub id: hir::HirId, pub whence: Span, - pub vis: hir::Visibility, + pub vis: &'hir hir::Visibility, pub stab: Option, pub depr: Option, } -pub struct TraitAlias { +pub struct TraitAlias<'hir> { pub name: Name, - pub generics: hir::Generics, - pub bounds: hir::HirVec, - pub attrs: hir::HirVec, - pub id: ast::NodeId, + pub generics: &'hir hir::Generics, + pub bounds: &'hir hir::HirVec, + pub attrs: &'hir hir::HirVec, + pub id: hir::HirId, pub whence: Span, - pub vis: hir::Visibility, + pub vis: &'hir hir::Visibility, pub stab: Option, pub depr: Option, } #[derive(Debug)] -pub struct Impl { +pub struct Impl<'hir> { pub unsafety: hir::Unsafety, pub polarity: hir::ImplPolarity, pub defaultness: hir::Defaultness, - pub generics: hir::Generics, - pub trait_: Option, - pub for_: P, - pub items: hir::HirVec, - pub attrs: hir::HirVec, + pub generics: &'hir hir::Generics, + pub trait_: &'hir Option, + pub for_: &'hir P, + pub items: Vec<&'hir hir::ImplItem>, + pub attrs: &'hir hir::HirVec, pub whence: Span, - pub vis: hir::Visibility, + pub vis: &'hir hir::Visibility, + pub stab: Option, + pub depr: Option, + pub id: hir::HirId, +} + +pub struct ForeignItem<'hir> { + pub vis: &'hir hir::Visibility, pub stab: Option, pub depr: Option, - pub id: ast::NodeId, + pub id: hir::HirId, + pub name: Name, + pub kind: &'hir hir::ForeignItemKind, + pub attrs: &'hir hir::HirVec, + pub whence: Span, } // For Macro we store the DefId instead of the NodeId, since we also create // these imported macro_rules (which only have a DUMMY_NODE_ID). -pub struct Macro { +pub struct Macro<'hir> { pub name: Name, pub def_id: hir::def_id::DefId, - pub attrs: hir::HirVec, + pub attrs: &'hir hir::HirVec, pub whence: Span, pub matchers: hir::HirVec, pub stab: Option, @@ -252,31 +267,31 @@ pub struct Macro { pub imported_from: Option, } -pub struct ExternCrate { +pub struct ExternCrate<'hir> { pub name: Name, pub cnum: CrateNum, pub path: Option, - pub vis: hir::Visibility, - pub attrs: hir::HirVec, + pub vis: &'hir hir::Visibility, + pub attrs: &'hir hir::HirVec, pub whence: Span, } -pub struct Import { +pub struct Import<'hir> { pub name: Name, - pub id: NodeId, - pub vis: hir::Visibility, - pub attrs: hir::HirVec, - pub path: hir::Path, + pub id: hir::HirId, + pub vis: &'hir hir::Visibility, + pub attrs: &'hir hir::HirVec, + pub path: &'hir hir::Path, pub glob: bool, pub whence: Span, } -pub struct ProcMacro { +pub struct ProcMacro<'hir> { pub name: Name, - pub id: NodeId, + pub id: hir::HirId, pub kind: MacroKind, pub helpers: Vec, - pub attrs: hir::HirVec, + pub attrs: &'hir hir::HirVec, pub whence: Span, pub stab: Option, pub depr: Option, diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 0378b12662da2..d604ba11d4186 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -3,6 +3,7 @@ use std::path::Path; use std::str; use errors; use crate::syntax::feature_gate::UnstableFeatures; +use crate::syntax::edition::Edition; use crate::html::markdown::{IdMap, ErrorCodes, Markdown}; use std::cell::RefCell; @@ -23,7 +24,7 @@ pub struct ExternalHtml { impl ExternalHtml { pub fn load(in_header: &[String], before_content: &[String], after_content: &[String], md_before_content: &[String], md_after_content: &[String], diag: &errors::Handler, - id_map: &mut IdMap) + id_map: &mut IdMap, edition: Edition) -> Option { let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); load_external_files(in_header, diag) @@ -34,7 +35,8 @@ impl ExternalHtml { .and_then(|(ih, bc)| load_external_files(md_before_content, diag) .map(|m_bc| (ih, - format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map), codes)))) + format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map), + codes, edition)))) ) .and_then(|(ih, bc)| load_external_files(after_content, diag) @@ -43,7 +45,8 @@ impl ExternalHtml { .and_then(|(ih, bc, ac)| load_external_files(md_after_content, diag) .map(|m_ac| (ih, bc, - format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map), codes)))) + format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map), + codes, edition)))) ) .map(|(ih, bc, ac)| ExternalHtml { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index d204a179ca62c..9e5cc03b83123 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -9,6 +9,7 @@ use std::borrow::Cow; use std::fmt; use rustc::hir::def_id::DefId; +use rustc::util::nodemap::FxHashSet; use rustc_target::spec::abi::Abi; use rustc::hir; @@ -17,7 +18,6 @@ use crate::core::DocAccessLevels; use crate::html::item_type::ItemType; use crate::html::render::{self, cache, CURRENT_LOCATION_KEY}; - /// Helper to render an optional visibility with a space after it (if the /// visibility is preset) #[derive(Copy, Clone)] @@ -45,6 +45,7 @@ pub struct GenericBounds<'a>(pub &'a [clean::GenericBound]); /// Wrapper struct for emitting a comma-separated list of items pub struct CommaSep<'a, T>(pub &'a [T]); pub struct AbiSpace(pub Abi); +pub struct DefaultSpace(pub bool); /// Wrapper struct for properly emitting a function or method declaration. pub struct Function<'a> { @@ -106,8 +107,10 @@ impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> { impl<'a> fmt::Display for GenericBounds<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut bounds_dup = FxHashSet::default(); let &GenericBounds(bounds) = self; - for (i, bound) in bounds.iter().enumerate() { + + for (i, bound) in bounds.iter().filter(|b| bounds_dup.insert(b.to_string())).enumerate() { if i > 0 { f.write_str(" + ")?; } @@ -205,16 +208,13 @@ impl<'a> fmt::Display for WhereClause<'a> { clause.push_str(&format!("{}: {}", ty, GenericBounds(bounds))); } } - &clean::WherePredicate::RegionPredicate { ref lifetime, - ref bounds } => { - clause.push_str(&format!("{}: ", lifetime)); - for (i, lifetime) in bounds.iter().enumerate() { - if i > 0 { - clause.push_str(" + "); - } - - clause.push_str(&lifetime.to_string()); - } + &clean::WherePredicate::RegionPredicate { ref lifetime, ref bounds } => { + clause.push_str(&format!("{}: {}", + lifetime, + bounds.iter() + .map(|b| b.to_string()) + .collect::>() + .join(" + "))); } &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => { if f.alternate() { @@ -259,6 +259,12 @@ impl fmt::Display for clean::Lifetime { } } +impl fmt::Display for clean::Constant { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.expr, f) + } +} + impl fmt::Display for clean::PolyTrait { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if !self.generic_params.is_empty() { @@ -300,32 +306,23 @@ impl fmt::Display for clean::GenericBound { impl fmt::Display for clean::GenericArgs { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - clean::GenericArgs::AngleBracketed { - ref lifetimes, ref types, ref bindings - } => { - if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() { + clean::GenericArgs::AngleBracketed { ref args, ref bindings } => { + if !args.is_empty() || !bindings.is_empty() { if f.alternate() { f.write_str("<")?; } else { f.write_str("<")?; } let mut comma = false; - for lifetime in lifetimes { - if comma { - f.write_str(", ")?; - } - comma = true; - write!(f, "{}", *lifetime)?; - } - for ty in types { + for arg in args { if comma { f.write_str(", ")?; } comma = true; if f.alternate() { - write!(f, "{:#}", *ty)?; + write!(f, "{:#}", *arg)?; } else { - write!(f, "{}", *ty)?; + write!(f, "{}", *arg)?; } } for binding in bindings { @@ -521,8 +518,8 @@ fn primitive_link(f: &mut fmt::Formatter<'_>, /// Helper to render type parameters fn tybounds(w: &mut fmt::Formatter<'_>, - typarams: &Option>) -> fmt::Result { - match *typarams { + param_names: &Option>) -> fmt::Result { + match *param_names { Some(ref params) => { for param in params { write!(w, " + ")?; @@ -559,13 +556,13 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> clean::Generic(ref name) => { f.write_str(name) } - clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => { - if typarams.is_some() { + clean::ResolvedPath{ did, ref param_names, ref path, is_generic } => { + if param_names.is_some() { f.write_str("dyn ")?; } - // Paths like T::Output and Self::Output should be rendered with all segments + // Paths like `T::Output` and `Self::Output` should be rendered with all segments. resolved_path(f, did, path, is_generic, use_absolute)?; - tybounds(f, typarams) + tybounds(f, param_names) } clean::Infer => write!(f, "_"), clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()), @@ -587,7 +584,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> &[] => primitive_link(f, PrimitiveType::Unit, "()"), &[ref one] => { primitive_link(f, PrimitiveType::Tuple, "(")?; - //carry f.alternate() into this display w/o branching manually + // Carry `f.alternate()` into this display w/o branching manually. fmt::Display::fmt(one, f)?; primitive_link(f, PrimitiveType::Tuple, ",)") } @@ -640,7 +637,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> "&".to_string() }; match **ty { - clean::Slice(ref bt) => { // BorrowedRef{ ... Slice(T) } is &[T] + clean::Slice(ref bt) => { // `BorrowedRef{ ... Slice(T) }` is `&[T]` match **bt { clean::Generic(_) => { if f.alternate() { @@ -663,7 +660,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } } } - clean::ResolvedPath { typarams: Some(ref v), .. } if !v.is_empty() => { + clean::ResolvedPath { param_names: Some(ref v), .. } if !v.is_empty() => { write!(f, "{}{}{}(", amp, lt, m)?; fmt_type(&ty, f, use_absolute)?; write!(f, ")") @@ -717,22 +714,22 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> // the ugliness comes from inlining across crates where // everything comes in as a fully resolved QPath (hard to // look at). - box clean::ResolvedPath { did, ref typarams, .. } => { + box clean::ResolvedPath { did, ref param_names, .. } => { match href(did) { Some((ref url, _, ref path)) if !f.alternate() => { write!(f, "{name}", url = url, - shortty = ItemType::AssociatedType, + shortty = ItemType::AssocType, name = name, path = path.join("::"))?; } _ => write!(f, "{}", name)?, } - // FIXME: `typarams` are not rendered, and this seems bad? - drop(typarams); + // FIXME: `param_names` are not rendered, and this seems bad? + drop(param_names); Ok(()) } _ => { @@ -740,9 +737,6 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } } } - clean::Unique(..) => { - panic!("should have been cleaned") - } } } @@ -771,7 +765,7 @@ fn fmt_impl(i: &clean::Impl, fmt::Display::fmt(ty, f)?; } else { match *ty { - clean::ResolvedPath { typarams: None, ref path, is_generic: false, .. } => { + clean::ResolvedPath { param_names: None, ref path, is_generic: false, .. } => { let last = path.segments.last().unwrap(); fmt::Display::fmt(&last.name, f)?; fmt::Display::fmt(&last.args, f)?; @@ -1022,11 +1016,26 @@ impl fmt::Display for clean::ImportSource { impl fmt::Display for clean::TypeBinding { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if f.alternate() { - write!(f, "{} = {:#}", self.name, self.ty) - } else { - write!(f, "{} = {}", self.name, self.ty) + f.write_str(&self.name)?; + match self.kind { + clean::TypeBindingKind::Equality { ref ty } => { + if f.alternate() { + write!(f, " = {:#}", ty)?; + } else { + write!(f, " = {}", ty)?; + } + } + clean::TypeBindingKind::Constraint { ref bounds } => { + if !bounds.is_empty() { + if f.alternate() { + write!(f, ": {:#}", GenericBounds(bounds))?; + } else { + write!(f, ": {}", GenericBounds(bounds))?; + } + } + } } + Ok(()) } } @@ -1057,3 +1066,13 @@ impl fmt::Display for AbiSpace { } } } + +impl fmt::Display for DefaultSpace { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.0 { + write!(f, "default ") + } else { + Ok(()) + } + } +} diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index d66455f91ba1a..99ca8c43cfbe2 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -12,9 +12,10 @@ use std::io; use std::io::prelude::*; use syntax::source_map::{SourceMap, FilePathMapping}; -use syntax::parse::lexer::{self, TokenAndSpan}; -use syntax::parse::token; +use syntax::parse::lexer; +use syntax::parse::token::{self, Token}; use syntax::parse; +use syntax::symbol::{kw, sym}; use syntax_pos::{Span, FileName}; /// Highlights `src`, returning the HTML output. @@ -185,9 +186,9 @@ impl<'a> Classifier<'a> { } /// Gets the next token out of the lexer. - fn try_next_token(&mut self) -> Result { + fn try_next_token(&mut self) -> Result { match self.lexer.try_next_token() { - Ok(tas) => Ok(tas), + Ok(token) => Ok(token), Err(_) => Err(HighlightError::LexError), } } @@ -204,7 +205,7 @@ impl<'a> Classifier<'a> { -> Result<(), HighlightError> { loop { let next = self.try_next_token()?; - if next.tok == token::Eof { + if next == token::Eof { break; } @@ -217,9 +218,9 @@ impl<'a> Classifier<'a> { // Handles an individual token from the lexer. fn write_token(&mut self, out: &mut W, - tas: TokenAndSpan) + token: Token) -> Result<(), HighlightError> { - let klass = match tas.tok { + let klass = match token.kind { token::Shebang(s) => { out.string(Escape(&s.as_str()), Class::None)?; return Ok(()); @@ -233,7 +234,7 @@ impl<'a> Classifier<'a> { // reference or dereference operator or a reference or pointer type, instead of the // bit-and or multiplication operator. token::BinOp(token::And) | token::BinOp(token::Star) - if self.lexer.peek().tok != token::Whitespace => Class::RefKeyWord, + if self.lexer.peek() != &token::Whitespace => Class::RefKeyWord, // Consider this as part of a macro invocation if there was a // leading identifier. @@ -256,7 +257,7 @@ impl<'a> Classifier<'a> { token::Question => Class::QuestionMark, token::Dollar => { - if self.lexer.peek().tok.is_ident() { + if self.lexer.peek().is_ident() { self.in_macro_nonterminal = true; Class::MacroNonTerminal } else { @@ -279,9 +280,9 @@ impl<'a> Classifier<'a> { // as an attribute. // Case 1: #![inner_attribute] - if self.lexer.peek().tok == token::Not { + if self.lexer.peek() == &token::Not { self.try_next_token()?; // NOTE: consumes `!` token! - if self.lexer.peek().tok == token::OpenDelim(token::Bracket) { + if self.lexer.peek() == &token::OpenDelim(token::Bracket) { self.in_attribute = true; out.enter_span(Class::Attribute)?; } @@ -291,7 +292,7 @@ impl<'a> Classifier<'a> { } // Case 2: #[outer_attribute] - if self.lexer.peek().tok == token::OpenDelim(token::Bracket) { + if self.lexer.peek() == &token::OpenDelim(token::Bracket) { self.in_attribute = true; out.enter_span(Class::Attribute)?; } @@ -309,37 +310,38 @@ impl<'a> Classifier<'a> { } } - token::Literal(lit, _suf) => { - match lit { + token::Literal(lit) => { + match lit.kind { // Text literals. - token::Byte(..) | token::Char(..) | token::Err(..) | - token::ByteStr(..) | token::ByteStrRaw(..) | - token::Str_(..) | token::StrRaw(..) => Class::String, + token::Byte | token::Char | token::Err | + token::ByteStr | token::ByteStrRaw(..) | + token::Str | token::StrRaw(..) => Class::String, // Number literals. - token::Integer(..) | token::Float(..) => Class::Number, + token::Integer | token::Float => Class::Number, + + token::Bool => panic!("literal token contains `Lit::Bool`"), } } // Keywords are also included in the identifier set. - token::Ident(ident, is_raw) => { - match &*ident.as_str() { - "ref" | "mut" if !is_raw => Class::RefKeyWord, + token::Ident(name, is_raw) => { + match name { + kw::Ref | kw::Mut if !is_raw => Class::RefKeyWord, - "self" | "Self" => Class::Self_, - "false" | "true" if !is_raw => Class::Bool, + kw::SelfLower | kw::SelfUpper => Class::Self_, + kw::False | kw::True if !is_raw => Class::Bool, - "Option" | "Result" => Class::PreludeTy, - "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, + sym::Option | sym::Result => Class::PreludeTy, + sym::Some | sym::None | sym::Ok | sym::Err => Class::PreludeVal, - "$crate" => Class::KeyWord, - _ if tas.tok.is_reserved_ident() => Class::KeyWord, + _ if token.is_reserved_ident() => Class::KeyWord, _ => { if self.in_macro_nonterminal { self.in_macro_nonterminal = false; Class::MacroNonTerminal - } else if self.lexer.peek().tok == token::Not { + } else if self.lexer.peek() == &token::Not { self.in_macro = true; Class::Macro } else { @@ -357,7 +359,7 @@ impl<'a> Classifier<'a> { // Anything that didn't return above is the simple case where we the // class just spans a single token, so we can use the `string` method. - out.string(Escape(&self.snip(tas.sp)), klass)?; + out.string(Escape(&self.snip(token.span)), klass)?; Ok(()) } diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 353fa4ae8c999..5f1a1b31616c1 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -15,7 +15,7 @@ use crate::clean; /// module headings. If you are adding to this enum and want to ensure that the sidebar also prints /// a heading, edit the listing in `html/render.rs`, function `sidebar_module`. This uses an /// ordering based on a helper function inside `item_module`, in the same file. -#[derive(Copy, PartialEq, Clone, Debug)] +#[derive(Copy, PartialEq, Eq, Clone, Debug, PartialOrd, Ord)] pub enum ItemType { Module = 0, ExternCrate = 1, @@ -33,9 +33,9 @@ pub enum ItemType { Variant = 13, Macro = 14, Primitive = 15, - AssociatedType = 16, + AssocType = 16, Constant = 17, - AssociatedConst = 18, + AssocConst = 18, Union = 19, ForeignType = 20, Keyword = 21, @@ -83,8 +83,8 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::ForeignStaticItem(..) => ItemType::Static, // no ForeignStatic clean::MacroItem(..) => ItemType::Macro, clean::PrimitiveItem(..) => ItemType::Primitive, - clean::AssociatedConstItem(..) => ItemType::AssociatedConst, - clean::AssociatedTypeItem(..) => ItemType::AssociatedType, + clean::AssocConstItem(..) => ItemType::AssocConst, + clean::AssocTypeItem(..) => ItemType::AssocType, clean::ForeignTypeItem => ItemType::ForeignType, clean::KeywordItem(..) => ItemType::Keyword, clean::TraitAliasItem(..) => ItemType::TraitAlias, @@ -110,7 +110,6 @@ impl From for ItemType { clean::TypeKind::Module => ItemType::Module, clean::TypeKind::Static => ItemType::Static, clean::TypeKind::Const => ItemType::Constant, - clean::TypeKind::Variant => ItemType::Variant, clean::TypeKind::Typedef => ItemType::Typedef, clean::TypeKind::Foreign => ItemType::ForeignType, clean::TypeKind::Macro => ItemType::Macro, @@ -141,9 +140,9 @@ impl ItemType { ItemType::Variant => "variant", ItemType::Macro => "macro", ItemType::Primitive => "primitive", - ItemType::AssociatedType => "associatedtype", + ItemType::AssocType => "associatedtype", ItemType::Constant => "constant", - ItemType::AssociatedConst => "associatedconstant", + ItemType::AssocConst => "associatedconstant", ItemType::ForeignType => "foreigntype", ItemType::Keyword => "keyword", ItemType::Existential => "existential", @@ -162,7 +161,7 @@ impl ItemType { ItemType::Typedef | ItemType::Trait | ItemType::Primitive | - ItemType::AssociatedType | + ItemType::AssocType | ItemType::Existential | ItemType::TraitAlias | ItemType::ForeignType => NameSpace::Type, @@ -177,7 +176,7 @@ impl ItemType { ItemType::StructField | ItemType::Variant | ItemType::Constant | - ItemType::AssociatedConst => NameSpace::Value, + ItemType::AssocConst => NameSpace::Value, ItemType::Macro | ItemType::ProcAttribute | diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 6ff3917a265ed..ae0bd1aafa8f1 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -157,11 +157,11 @@ pub fn render( window.rootPath = \"{root_path}\";\ window.currentCrate = \"{krate}\";\ \ - \ + \ \ {static_extra_scripts}\ {extra_scripts}\ - \ + \ \ ", css_extension = if css_file_extension { @@ -182,14 +182,14 @@ pub fn render( let p = SlashChecker(&p); if layout.logo.is_empty() { format!("\ - logo", +
\ + logo
", path=p, static_root_path=static_root_path, suffix=page.resource_suffix) } else { format!("\ - logo", +
logo
", p, layout.logo) } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a70fe363ca69a..c698200039623 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -8,12 +8,16 @@ //! ``` //! #![feature(rustc_private)] //! +//! extern crate syntax; +//! +//! use syntax::edition::Edition; //! use rustdoc::html::markdown::{IdMap, Markdown, ErrorCodes}; //! use std::cell::RefCell; //! //! let s = "My *markdown* _text_"; //! let mut id_map = IdMap::new(); -//! let html = format!("{}", Markdown(s, &[], RefCell::new(&mut id_map), ErrorCodes::Yes)); +//! let html = format!("{}", Markdown(s, &[], RefCell::new(&mut id_map), +//! ErrorCodes::Yes, Edition::Edition2015)); //! // ... something using html //! ``` @@ -33,21 +37,36 @@ use crate::html::toc::TocBuilder; use crate::html::highlight; use crate::test; -use pulldown_cmark::{html, Event, Tag, Parser}; -use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES}; +use pulldown_cmark::{html, CowStr, Event, Options, Parser, Tag}; + +fn opts() -> Options { + Options::ENABLE_TABLES | Options::ENABLE_FOOTNOTES +} -/// A unit struct which has the `fmt::Display` trait implemented. When -/// formatted, this struct will emit the HTML corresponding to the rendered +/// A tuple struct that has the `fmt::Display` trait implemented. +/// When formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. -/// The second parameter is a list of link replacements pub struct Markdown<'a>( - pub &'a str, pub &'a [(String, String)], pub RefCell<&'a mut IdMap>, pub ErrorCodes); -/// A unit struct like `Markdown`, that renders the markdown with a -/// table of contents. -pub struct MarkdownWithToc<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes); -/// A unit struct like `Markdown`, that renders the markdown escaping HTML tags. -pub struct MarkdownHtml<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes); -/// A unit struct like `Markdown`, that renders only the first paragraph. + pub &'a str, + /// A list of link replacements. + pub &'a [(String, String)], + /// The current list of used header IDs. + pub RefCell<&'a mut IdMap>, + /// Whether to allow the use of explicit error codes in doctest lang strings. + pub ErrorCodes, + /// Default edition to use when parsing doctests (to add a `fn main`). + pub Edition, +); +/// A tuple struct like `Markdown` that renders the markdown with a table of contents. +pub struct MarkdownWithToc<'a>( + pub &'a str, + pub RefCell<&'a mut IdMap>, + pub ErrorCodes, + pub Edition, +); +/// A tuple struct like `Markdown` that renders the markdown escaping HTML tags. +pub struct MarkdownHtml<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition); +/// A tuple struct like `Markdown` that renders only the first paragraph. pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [(String, String)]); #[derive(Copy, Clone, PartialEq, Debug)] @@ -143,13 +162,15 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = struct CodeBlocks<'a, I: Iterator>> { inner: I, check_error_codes: ErrorCodes, + edition: Edition, } impl<'a, I: Iterator>> CodeBlocks<'a, I> { - fn new(iter: I, error_codes: ErrorCodes) -> Self { + fn new(iter: I, error_codes: ErrorCodes, edition: Edition) -> Self { CodeBlocks { inner: iter, check_error_codes: error_codes, + edition, } } } @@ -174,6 +195,9 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { return event; } + let explicit_edition = edition.is_some(); + let edition = edition.unwrap_or(self.edition); + let mut origtext = String::new(); for event in &mut self.inner { match event { @@ -199,22 +223,14 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { .collect::>>().join("\n"); let krate = krate.as_ref().map(|s| &**s); let (test, _) = test::make_test(&test, krate, false, - &Default::default()); + &Default::default(), edition); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; - let edition_string = if let Some(e @ Edition::Edition2018) = edition { - format!("&edition={}{}", e, - if channel == "&version=nightly" { "" } - else { "&version=nightly" }) - } else if let Some(e) = edition { - format!("&edition={}", e) - } else { - "".to_owned() - }; + let edition_string = format!("&edition={}", edition); // These characters don't need to be escaped in a URI. // FIXME: use a library function for percent encoding. @@ -244,8 +260,8 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { Some(("This example is not tested".to_owned(), "ignore")) } else if compile_fail { Some(("This example deliberately fails to compile".to_owned(), "compile_fail")) - } else if let Some(e) = edition { - Some((format!("This code runs with edition {}", e), "edition")) + } else if explicit_edition { + Some((format!("This code runs with edition {}", edition), "edition")) } else { None }; @@ -256,7 +272,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { Some(&format!("rust-example-rendered{}", if ignore { " ignore" } else if compile_fail { " compile_fail" } - else if edition.is_some() { " edition " } + else if explicit_edition { " edition " } else { "" })), playground_button.as_ref().map(String::as_str), Some((s1.as_str(), s2)))); @@ -267,7 +283,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { Some(&format!("rust-example-rendered{}", if ignore { " ignore" } else if compile_fail { " compile_fail" } - else if edition.is_some() { " edition " } + else if explicit_edition { " edition " } else { "" })), playground_button.as_ref().map(String::as_str), None)); @@ -297,12 +313,11 @@ impl<'a, 'b, I: Iterator>> Iterator for LinkReplacer<'a, 'b, I> fn next(&mut self) -> Option { let event = self.inner.next(); - if let Some(Event::Start(Tag::Link(dest, text))) = event { - if let Some(&(_, ref replace)) = self.links.into_iter().find(|link| &*link.0 == &*dest) - { - Some(Event::Start(Tag::Link(replace.to_owned().into(), text))) + if let Some(Event::Start(Tag::Link(kind, dest, text))) = event { + if let Some(&(_, ref replace)) = self.links.iter().find(|link| link.0 == *dest) { + Some(Event::Start(Tag::Link(kind, replace.to_owned().into(), text))) } else { - Some(Event::Start(Tag::Link(dest, text))) + Some(Event::Start(Tag::Link(kind, dest, text))) } } else { event @@ -341,9 +356,11 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator for HeadingLinks<'a, if let Some(Event::Start(Tag::Header(level))) = event { let mut id = String::new(); for event in &mut self.inner { - match event { + match &event { Event::End(Tag::Header(..)) => break, - Event::Text(ref text) => id.extend(text.chars().filter_map(slugify)), + Event::Text(text) | Event::Code(text) => { + id.extend(text.chars().filter_map(slugify)); + } _ => {}, } self.buf.push_back(event); @@ -392,8 +409,7 @@ fn check_if_allowed_tag(t: &Tag<'_>) -> bool { | Tag::Item | Tag::Emphasis | Tag::Strong - | Tag::Code - | Tag::Link(_, _) + | Tag::Link(..) | Tag::BlockQuote => true, _ => false, } @@ -520,63 +536,39 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { } } -pub struct TestableCodeError(()); - -impl fmt::Display for TestableCodeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "invalid start of a new code block") - } -} - -pub fn find_testable_code( - doc: &str, - tests: &mut T, - error_codes: ErrorCodes, -) -> Result<(), TestableCodeError> { +pub fn find_testable_code(doc: &str, tests: &mut T, error_codes: ErrorCodes) { let mut parser = Parser::new(doc); let mut prev_offset = 0; let mut nb_lines = 0; let mut register_header = None; - 'main: while let Some(event) = parser.next() { + while let Some(event) = parser.next() { match event { Event::Start(Tag::CodeBlock(s)) => { + let offset = parser.get_offset(); + let block_info = if s.is_empty() { LangString::all_false() } else { LangString::parse(&*s, error_codes) }; if !block_info.rust { - continue + continue; } let mut test_s = String::new(); - let mut offset = None; - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::CodeBlock(_)) => break, - Event::Text(ref s) => { - test_s.push_str(s); - if offset.is_none() { - offset = Some(parser.get_offset()); - } - } - _ => {} - } - } else { - break 'main; - } - } - if let Some(offset) = offset { - let lines = test_s.lines().map(|l| map_line(l).for_code()); - let text = lines.collect::>>().join("\n"); - nb_lines += doc[prev_offset..offset].lines().count(); - let line = tests.get_line() + (nb_lines - 1); - tests.add_test(text, block_info, line); - prev_offset = offset; - } else { - return Err(TestableCodeError(())); + + while let Some(Event::Text(s)) = parser.next() { + test_s.push_str(&s); } + + let text = test_s + .lines() + .map(|l| map_line(l).for_code()) + .collect::>>() + .join("\n"); + nb_lines += doc[prev_offset..offset].lines().count(); + let line = tests.get_line() + nb_lines; + tests.add_test(text, block_info, line); + prev_offset = offset; } Event::Start(Tag::Header(level)) => { register_header = Some(level as u32); @@ -593,7 +585,6 @@ pub fn find_testable_code( _ => {} } } - Ok(()) } #[derive(Eq, PartialEq, Clone, Debug)] @@ -682,15 +673,11 @@ impl LangString { impl<'a> fmt::Display for Markdown<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let Markdown(md, links, ref ids, codes) = *self; + let Markdown(md, links, ref ids, codes, edition) = *self; let mut ids = ids.borrow_mut(); // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); - let replacer = |_: &str, s: &str| { if let Some(&(_, ref replace)) = links.into_iter().find(|link| &*link.0 == s) { Some((replace.clone(), s.to_owned())) @@ -699,13 +686,13 @@ impl<'a> fmt::Display for Markdown<'a> { } }; - let p = Parser::new_with_broken_link_callback(md, opts, Some(&replacer)); + let p = Parser::new_with_broken_link_callback(md, opts(), Some(&replacer)); let mut s = String::with_capacity(md.len() * 3 / 2); let p = HeadingLinks::new(p, None, &mut ids); let p = LinkReplacer::new(p, links); - let p = CodeBlocks::new(p, codes); + let p = CodeBlocks::new(p, codes, edition); let p = Footnotes::new(p); html::push_html(&mut s, p); @@ -715,14 +702,10 @@ impl<'a> fmt::Display for Markdown<'a> { impl<'a> fmt::Display for MarkdownWithToc<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let MarkdownWithToc(md, ref ids, codes) = *self; + let MarkdownWithToc(md, ref ids, codes, edition) = *self; let mut ids = ids.borrow_mut(); - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); - - let p = Parser::new_ext(md, opts); + let p = Parser::new_ext(md, opts()); let mut s = String::with_capacity(md.len() * 3 / 2); @@ -730,7 +713,7 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> { { let p = HeadingLinks::new(p, Some(&mut toc), &mut ids); - let p = CodeBlocks::new(p, codes); + let p = CodeBlocks::new(p, codes, edition); let p = Footnotes::new(p); html::push_html(&mut s, p); } @@ -743,16 +726,12 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> { impl<'a> fmt::Display for MarkdownHtml<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let MarkdownHtml(md, ref ids, codes) = *self; + let MarkdownHtml(md, ref ids, codes, edition) = *self; let mut ids = ids.borrow_mut(); // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); - - let p = Parser::new_ext(md, opts); + let p = Parser::new_ext(md, opts()); // Treat inline HTML as plain text. let p = p.map(|event| match event { @@ -763,7 +742,7 @@ impl<'a> fmt::Display for MarkdownHtml<'a> { let mut s = String::with_capacity(md.len() * 3 / 2); let p = HeadingLinks::new(p, None, &mut ids); - let p = CodeBlocks::new(p, codes); + let p = CodeBlocks::new(p, codes, edition); let p = Footnotes::new(p); html::push_html(&mut s, p); @@ -817,9 +796,8 @@ pub fn plain_summary_line_full(md: &str, limit_length: bool) -> String { let next_event = next_event.unwrap(); let (ret, is_in) = match next_event { Event::Start(Tag::Paragraph) => (None, 1), - Event::Start(Tag::Code) => (Some("`".to_owned()), 1), - Event::End(Tag::Code) => (Some("`".to_owned()), -1), Event::Start(Tag::Header(_)) => (None, 1), + Event::Code(code) => (Some(format!("`{}`", code)), 0), Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), Event::End(Tag::Paragraph) | Event::End(Tag::Header(_)) => (None, -1), _ => (None, 0), @@ -868,10 +846,6 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { return vec![]; } - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); - let mut links = vec![]; let shortcut_links = RefCell::new(vec![]); @@ -894,8 +868,7 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { shortcut_links.borrow_mut().push((s.to_owned(), locate(s))); None }; - let p = Parser::new_with_broken_link_callback(md, opts, - Some(&push)); + let p = Parser::new_with_broken_link_callback(md, opts(), Some(&push)); // There's no need to thread an IdMap through to here because // the IDs generated aren't going to be emitted anywhere. @@ -903,11 +876,11 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids)); for ev in iter { - if let Event::Start(Tag::Link(dest, _)) = ev { + if let Event::Start(Tag::Link(_, dest, _)) = ev { debug!("found link: {}", dest); links.push(match dest { - Cow::Borrowed(s) => (s.to_owned(), locate(s)), - Cow::Owned(s) => (s, None), + CowStr::Borrowed(s) => (s.to_owned(), locate(s)), + s @ CowStr::Boxed(..) | s @ CowStr::Inlined(..) => (s.into_string(), None), }); } } @@ -939,10 +912,7 @@ crate fn rust_code_blocks(md: &str) -> Vec { return code_blocks; } - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); - let mut p = Parser::new_ext(md, opts); + let mut p = Parser::new_ext(md, opts()); let mut code_block_start = 0; let mut code_start = 0; @@ -1013,7 +983,7 @@ crate fn rust_code_blocks(md: &str) -> Vec { end: code_end, }, syntax: if !syntax.is_empty() { - Some(syntax.into_owned()) + Some(syntax.into_string()) } else { None }, @@ -1085,127 +1055,4 @@ fn test_unique_id() { } #[cfg(test)] -mod tests { - use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap}; - use super::plain_summary_line; - use std::cell::RefCell; - use syntax::edition::Edition; - - #[test] - fn test_lang_string_parse() { - fn t(s: &str, - should_panic: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool, - compile_fail: bool, allow_fail: bool, error_codes: Vec, - edition: Option) { - assert_eq!(LangString::parse(s, ErrorCodes::Yes), LangString { - should_panic, - no_run, - ignore, - rust, - test_harness, - compile_fail, - error_codes, - original: s.to_owned(), - allow_fail, - edition, - }) - } - - fn v() -> Vec { - Vec::new() - } - - // ignore-tidy-linelength - // marker | should_panic | no_run | ignore | rust | test_harness - // | compile_fail | allow_fail | error_codes | edition - t("", false, false, false, true, false, false, false, v(), None); - t("rust", false, false, false, true, false, false, false, v(), None); - t("sh", false, false, false, false, false, false, false, v(), None); - t("ignore", false, false, true, true, false, false, false, v(), None); - t("should_panic", true, false, false, true, false, false, false, v(), None); - t("no_run", false, true, false, true, false, false, false, v(), None); - t("test_harness", false, false, false, true, true, false, false, v(), None); - t("compile_fail", false, true, false, true, false, true, false, v(), None); - t("allow_fail", false, false, false, true, false, false, true, v(), None); - t("{.no_run .example}", false, true, false, true, false, false, false, v(), None); - t("{.sh .should_panic}", true, false, false, false, false, false, false, v(), None); - t("{.example .rust}", false, false, false, true, false, false, false, v(), None); - t("{.test_harness .rust}", false, false, false, true, true, false, false, v(), None); - t("text, no_run", false, true, false, false, false, false, false, v(), None); - t("text,no_run", false, true, false, false, false, false, false, v(), None); - t("edition2015", false, false, false, true, false, false, false, v(), Some(Edition::Edition2015)); - t("edition2018", false, false, false, true, false, false, false, v(), Some(Edition::Edition2018)); - } - - #[test] - fn test_header() { - fn t(input: &str, expect: &str) { - let mut map = IdMap::new(); - let output = Markdown(input, &[], RefCell::new(&mut map), ErrorCodes::Yes).to_string(); - assert_eq!(output, expect, "original: {}", input); - } - - t("# Foo bar", "

\ - Foo bar

"); - t("## Foo-bar_baz qux", "

Foo-bar_baz qux

"); - t("### **Foo** *bar* baz!?!& -_qux_-%", - "

\ - Foo \ - bar baz!?!& -qux-%

"); - t("#### **Foo?** & \\*bar?!* _`baz`_ ❤ #qux", - "

\ - Foo? & *bar?!* \ - baz ❤ #qux

"); - } - - #[test] - fn test_header_ids_multiple_blocks() { - let mut map = IdMap::new(); - fn t(map: &mut IdMap, input: &str, expect: &str) { - let output = Markdown(input, &[], RefCell::new(map), ErrorCodes::Yes).to_string(); - assert_eq!(output, expect, "original: {}", input); - } - - t(&mut map, "# Example", "

\ - Example

"); - t(&mut map, "# Panics", "

\ - Panics

"); - t(&mut map, "# Example", "

\ - Example

"); - t(&mut map, "# Main", "

\ - Main

"); - t(&mut map, "# Example", "

\ - Example

"); - t(&mut map, "# Panics", "

\ - Panics

"); - } - - #[test] - fn test_plain_summary_line() { - fn t(input: &str, expect: &str) { - let output = plain_summary_line(input); - assert_eq!(output, expect, "original: {}", input); - } - - t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)"); - t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); - t("code `let x = i32;` ...", "code `let x = i32;` ..."); - t("type `Type<'static>` ...", "type `Type<'static>` ..."); - t("# top header", "top header"); - t("## header", "header"); - } - - #[test] - fn test_markdown_html_escape() { - fn t(input: &str, expect: &str) { - let mut idmap = IdMap::new(); - let output = MarkdownHtml(input, RefCell::new(&mut idmap), ErrorCodes::Yes).to_string(); - assert_eq!(output, expect, "original: {}", input); - } - - t("`Struct<'a, T>`", "

Struct<'a, T>

\n"); - t("Struct<'a, T>", "

Struct<'a, T>

\n"); - t("Struct
", "

Struct<br>

\n"); - } -} +mod tests; diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs new file mode 100644 index 0000000000000..f470e649d8265 --- /dev/null +++ b/src/librustdoc/html/markdown/tests.rs @@ -0,0 +1,125 @@ +use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap}; +use super::plain_summary_line; +use std::cell::RefCell; +use syntax::edition::{Edition, DEFAULT_EDITION}; + +#[test] +fn test_lang_string_parse() { + fn t(s: &str, + should_panic: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool, + compile_fail: bool, allow_fail: bool, error_codes: Vec, + edition: Option) { + assert_eq!(LangString::parse(s, ErrorCodes::Yes), LangString { + should_panic, + no_run, + ignore, + rust, + test_harness, + compile_fail, + error_codes, + original: s.to_owned(), + allow_fail, + edition, + }) + } + + fn v() -> Vec { + Vec::new() + } + + // ignore-tidy-linelength + // marker | should_panic | no_run | ignore | rust | test_harness + // | compile_fail | allow_fail | error_codes | edition + t("", false, false, false, true, false, false, false, v(), None); + t("rust", false, false, false, true, false, false, false, v(), None); + t("sh", false, false, false, false, false, false, false, v(), None); + t("ignore", false, false, true, true, false, false, false, v(), None); + t("should_panic", true, false, false, true, false, false, false, v(), None); + t("no_run", false, true, false, true, false, false, false, v(), None); + t("test_harness", false, false, false, true, true, false, false, v(), None); + t("compile_fail", false, true, false, true, false, true, false, v(), None); + t("allow_fail", false, false, false, true, false, false, true, v(), None); + t("{.no_run .example}", false, true, false, true, false, false, false, v(), None); + t("{.sh .should_panic}", true, false, false, false, false, false, false, v(), None); + t("{.example .rust}", false, false, false, true, false, false, false, v(), None); + t("{.test_harness .rust}", false, false, false, true, true, false, false, v(), None); + t("text, no_run", false, true, false, false, false, false, false, v(), None); + t("text,no_run", false, true, false, false, false, false, false, v(), None); + t("edition2015", false, false, false, true, false, false, false, v(), Some(Edition::Edition2015)); + t("edition2018", false, false, false, true, false, false, false, v(), Some(Edition::Edition2018)); +} + +#[test] +fn test_header() { + fn t(input: &str, expect: &str) { + let mut map = IdMap::new(); + let output = Markdown(input, &[], RefCell::new(&mut map), + ErrorCodes::Yes, DEFAULT_EDITION).to_string(); + assert_eq!(output, expect, "original: {}", input); + } + + t("# Foo bar", "

\ + Foo bar

"); + t("## Foo-bar_baz qux", "

Foo-bar_baz qux

"); + t("### **Foo** *bar* baz!?!& -_qux_-%", + "

\ + Foo \ + bar baz!?!& -qux-%

"); + t("#### **Foo?** & \\*bar?!* _`baz`_ ❤ #qux", + "

\ + Foo? & *bar?!* \ + baz ❤ #qux

"); +} + +#[test] +fn test_header_ids_multiple_blocks() { + let mut map = IdMap::new(); + fn t(map: &mut IdMap, input: &str, expect: &str) { + let output = Markdown(input, &[], RefCell::new(map), + ErrorCodes::Yes, DEFAULT_EDITION).to_string(); + assert_eq!(output, expect, "original: {}", input); + } + + t(&mut map, "# Example", "

\ + Example

"); + t(&mut map, "# Panics", "

\ + Panics

"); + t(&mut map, "# Example", "

\ + Example

"); + t(&mut map, "# Main", "

\ + Main

"); + t(&mut map, "# Example", "

\ + Example

"); + t(&mut map, "# Panics", "

\ + Panics

"); +} + +#[test] +fn test_plain_summary_line() { + fn t(input: &str, expect: &str) { + let output = plain_summary_line(input); + assert_eq!(output, expect, "original: {}", input); + } + + t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)"); + t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); + t("code `let x = i32;` ...", "code `let x = i32;` ..."); + t("type `Type<'static>` ...", "type `Type<'static>` ..."); + t("# top header", "top header"); + t("## header", "header"); +} + +#[test] +fn test_markdown_html_escape() { + fn t(input: &str, expect: &str) { + let mut idmap = IdMap::new(); + let output = MarkdownHtml(input, RefCell::new(&mut idmap), + ErrorCodes::Yes, DEFAULT_EDITION).to_string(); + assert_eq!(output, expect, "original: {}", input); + } + + t("`Struct<'a, T>`", "

Struct<'a, T>

\n"); + t("Struct<'a, T>", "

Struct<'a, T>

\n"); + t("Struct
", "

Struct<br>

\n"); +} diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d711e4514a049..2080637ecb402 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + //! Rustdoc's HTML rendering module. //! //! This modules contains the bulk of the logic necessary for rendering a @@ -33,9 +35,9 @@ use std::default::Default; use std::error; use std::fmt::{self, Display, Formatter, Write as FmtWrite}; use std::ffi::OsStr; -use std::fs::{self, File, OpenOptions}; +use std::fs::{self, File}; use std::io::prelude::*; -use std::io::{self, BufWriter, BufReader}; +use std::io::{self, BufReader}; use std::mem; use std::path::{PathBuf, Path, Component}; use std::str; @@ -45,9 +47,11 @@ use std::rc::Rc; use errors; use serialize::json::{ToJson, Json, as_json}; use syntax::ast; +use syntax::edition::Edition; use syntax::ext::base::MacroKind; use syntax::source_map::FileName; use syntax::feature_gate::UnstableFeatures; +use syntax::symbol::{Symbol, sym}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::middle::privacy::AccessLevels; use rustc::middle::stability; @@ -57,11 +61,12 @@ use rustc_data_structures::flock; use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, Mutability}; use crate::config::RenderOptions; +use crate::docfs::{DocFS, ErrorStorage, PathError}; use crate::doctree; use crate::fold::DocFolder; use crate::html::escape::Escape; use crate::html::format::{AsyncSpace, ConstnessSpace}; -use crate::html::format::{GenericBounds, WhereClause, href, AbiSpace}; +use crate::html::format::{GenericBounds, WhereClause, href, AbiSpace, DefaultSpace}; use crate::html::format::{VisSpace, Function, UnsafetySpace, MutableSpace}; use crate::html::format::fmt_impl_for_trait_page; use crate::html::item_type::ItemType; @@ -85,6 +90,58 @@ impl<'a> Display for SlashChecker<'a> { } } +#[derive(Debug)] +pub struct Error { + pub file: PathBuf, + pub error: io::Error, +} + +impl error::Error for Error { + fn description(&self) -> &str { + self.error.description() + } +} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let file = self.file.display().to_string(); + if file.is_empty() { + write!(f, "{}", self.error) + } else { + write!(f, "\"{}\": {}", self.file.display(), self.error) + } + } +} + +impl PathError for Error { + fn new>(e: io::Error, path: P) -> Error { + Error { + file: path.as_ref().to_path_buf(), + error: e, + } + } +} + +macro_rules! try_none { + ($e:expr, $file:expr) => ({ + use std::io; + match $e { + Some(e) => e, + None => return Err(Error::new(io::Error::new(io::ErrorKind::Other, "not found"), + $file)) + } + }) +} + +macro_rules! try_err { + ($e:expr, $file:expr) => ({ + match $e { + Ok(e) => e, + Err(e) => return Err(Error::new(e, $file)), + } + }) +} + /// Major driving force in all rustdoc rendering. This contains information /// about where in the tree-like hierarchy rendering is occurring and controls /// how the current page is being rendered. @@ -105,6 +162,8 @@ struct Context { /// publicly reused items to redirect to the right location. pub render_redirect_pages: bool, pub codes: ErrorCodes, + /// The default edition used to parse doctests. + pub edition: Edition, /// The map used to ensure all generated 'id=' attributes are unique. id_map: Rc>, pub shared: Arc, @@ -150,13 +209,15 @@ struct SharedContext { pub generate_search_filter: bool, /// Option disabled by default to generate files used by RLS and some other tools. pub generate_redirect_pages: bool, + /// The fs handle we are working with. + pub fs: DocFS, } impl SharedContext { - fn ensure_dir(&self, dst: &Path) -> io::Result<()> { + fn ensure_dir(&self, dst: &Path) -> Result<(), Error> { let mut dirs = self.created_dirs.borrow_mut(); if !dirs.contains(dst) { - fs::create_dir_all(dst)?; + try_err!(self.fs.create_dir_all(dst), dst); dirs.insert(dst.to_path_buf()); } @@ -210,53 +271,6 @@ impl Impl { } } -#[derive(Debug)] -pub struct Error { - pub file: PathBuf, - pub error: io::Error, -} - -impl error::Error for Error { - fn description(&self) -> &str { - self.error.description() - } -} - -impl Display for Error { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "\"{}\": {}", self.file.display(), self.error) - } -} - -impl Error { - pub fn new(e: io::Error, file: &Path) -> Error { - Error { - file: file.to_path_buf(), - error: e, - } - } -} - -macro_rules! try_none { - ($e:expr, $file:expr) => ({ - use std::io; - match $e { - Some(e) => e, - None => return Err(Error::new(io::Error::new(io::ErrorKind::Other, "not found"), - $file)) - } - }) -} - -macro_rules! try_err { - ($e:expr, $file:expr) => ({ - match $e { - Ok(e) => e, - Err(e) => return Err(Error::new(e, $file)), - } - }) -} - /// This cache is used to store information about the `clean::Crate` being /// rendered in order to provide more useful documentation. This contains /// information like all implementors of a trait, all traits a type implements, @@ -271,7 +285,7 @@ pub struct Cache { /// Mapping of typaram ids to the name of the type parameter. This is used /// when pretty-printing a type (so pretty-printing doesn't have to /// painfully maintain a context like this) - pub typarams: FxHashMap, + pub param_names: FxHashMap, /// Maps a type ID to all known implementations for that type. This is only /// recognized for intra-crate `ResolvedPath` types, and is used to print @@ -368,7 +382,7 @@ pub struct Cache { pub struct RenderInfo { pub inlined: FxHashSet, pub external_paths: crate::core::ExternalPaths, - pub external_typarams: FxHashMap, + pub external_param_names: FxHashMap, pub exact_paths: FxHashMap>, pub access_levels: AccessLevels, pub deref_trait_did: Option, @@ -446,7 +460,7 @@ impl ToJson for Type { } Json::Array(data) } - None => Json::Null + None => Json::Null, } } } @@ -455,19 +469,27 @@ impl ToJson for Type { #[derive(Debug)] struct IndexItemFunctionType { inputs: Vec, - output: Option, + output: Option>, } impl ToJson for IndexItemFunctionType { fn to_json(&self) -> Json { // If we couldn't figure out a type, just write `null`. - if self.inputs.iter().chain(self.output.iter()).any(|ref i| i.name.is_none()) { + let mut iter = self.inputs.iter(); + if match self.output { + Some(ref output) => iter.chain(output.iter()).any(|ref i| i.name.is_none()), + None => iter.any(|ref i| i.name.is_none()), + } { Json::Null } else { let mut data = Vec::with_capacity(2); data.push(self.inputs.to_json()); if let Some(ref output) = self.output { - data.push(output.to_json()); + if output.len() > 1 { + data.push(output.to_json()); + } else { + data.push(output[0].to_json()); + } } Json::Array(data) } @@ -495,7 +517,7 @@ pub fn initial_ids() -> Vec { "methods", "deref-methods", "implementations", - ].into_iter().map(|id| (String::from(*id))).collect() + ].iter().map(|id| (String::from(*id))).collect() } /// Generates the documentation for `crate` into the directory `dst` @@ -503,7 +525,8 @@ pub fn run(mut krate: clean::Crate, options: RenderOptions, passes: FxHashSet, renderinfo: RenderInfo, - diag: &errors::Handler) -> Result<(), Error> { + diag: &errors::Handler, + edition: Edition) -> Result<(), Error> { // need to save a copy of the options for rendering the index page let md_opts = options.clone(); let RenderOptions { @@ -529,6 +552,7 @@ pub fn run(mut krate: clean::Crate, }, _ => PathBuf::new(), }; + let mut errors = Arc::new(ErrorStorage::new()); let mut scx = SharedContext { src_root, passes, @@ -549,6 +573,7 @@ pub fn run(mut krate: clean::Crate, static_root_path, generate_search_filter, generate_redirect_pages, + fs: DocFS::new(&errors), }; // If user passed in `--playground-url` arg, we fill in crate name here @@ -561,25 +586,24 @@ pub fn run(mut krate: clean::Crate, // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML if let Some(attrs) = krate.module.as_ref().map(|m| &m.attrs) { - for attr in attrs.lists("doc") { - let name = attr.name().map(|s| s.as_str()); - match (name.as_ref().map(|s| &s[..]), attr.value_str()) { - (Some("html_favicon_url"), Some(s)) => { + for attr in attrs.lists(sym::doc) { + match (attr.name_or_empty(), attr.value_str()) { + (sym::html_favicon_url, Some(s)) => { scx.layout.favicon = s.to_string(); } - (Some("html_logo_url"), Some(s)) => { + (sym::html_logo_url, Some(s)) => { scx.layout.logo = s.to_string(); } - (Some("html_playground_url"), Some(s)) => { + (sym::html_playground_url, Some(s)) => { markdown::PLAYGROUND.with(|slot| { let name = krate.name.clone(); *slot.borrow_mut() = Some((Some(name), s.to_string())); }); } - (Some("issue_tracker_base_url"), Some(s)) => { + (sym::issue_tracker_base_url, Some(s)) => { scx.issue_tracker_base_url = Some(s.to_string()); } - (Some("html_no_source"), None) if attr.is_word() => { + (sym::html_no_source, None) if attr.is_word() => { scx.include_sources = false; } _ => {} @@ -587,13 +611,14 @@ pub fn run(mut krate: clean::Crate, } } let dst = output; - try_err!(fs::create_dir_all(&dst), &dst); + scx.ensure_dir(&dst)?; krate = render_sources(&dst, &mut scx, krate)?; - let cx = Context { + let mut cx = Context { current: Vec::new(), dst, render_redirect_pages: false, codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()), + edition, id_map: Rc::new(RefCell::new(id_map)), shared: Arc::new(scx), }; @@ -602,7 +627,7 @@ pub fn run(mut krate: clean::Crate, let RenderInfo { inlined: _, external_paths, - external_typarams, + external_param_names, exact_paths, access_levels, deref_trait_did, @@ -636,7 +661,7 @@ pub fn run(mut krate: clean::Crate, deref_mut_trait_did, owned_box_did, masked_crates: mem::replace(&mut krate.masked_crates, Default::default()), - typarams: external_typarams, + param_names: external_param_names, aliases: Default::default(), }; @@ -690,10 +715,21 @@ pub fn run(mut krate: clean::Crate, CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone()); CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear()); + // Write shared runs within a flock; disable thread dispatching of IO temporarily. + Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true); write_shared(&cx, &krate, &*cache, index, &md_opts, diag)?; + Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false); // And finally render the whole crate's documentation - cx.krate(krate) + let ret = cx.krate(krate); + let nb_errors = Arc::get_mut(&mut errors).map_or_else(|| 0, |errors| errors.write_errors(diag)); + if ret.is_err() { + ret + } else if nb_errors > 0 { + Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), "")) + } else { + Ok(()) + } } /// Builds the search index from the collected metadata @@ -782,13 +818,13 @@ fn write_shared( // Add all the static files. These may already exist, but we just // overwrite them anyway to make sure that they're fresh and up-to-date. - write_minify(cx.dst.join(&format!("rustdoc{}.css", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.dst.join(&format!("rustdoc{}.css", cx.shared.resource_suffix)), static_files::RUSTDOC_CSS, options.enable_minification)?; - write_minify(cx.dst.join(&format!("settings{}.css", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.dst.join(&format!("settings{}.css", cx.shared.resource_suffix)), static_files::SETTINGS_CSS, options.enable_minification)?; - write_minify(cx.dst.join(&format!("noscript{}.css", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.dst.join(&format!("noscript{}.css", cx.shared.resource_suffix)), static_files::NOSCRIPT_CSS, options.enable_minification)?; @@ -800,11 +836,13 @@ fn write_shared( let content = try_err!(fs::read(&entry), &entry); let theme = try_none!(try_none!(entry.file_stem(), &entry).to_str(), &entry); let extension = try_none!(try_none!(entry.extension(), &entry).to_str(), &entry); - write(cx.dst.join(format!("{}{}.{}", theme, cx.shared.resource_suffix, extension)), - content.as_slice())?; + cx.shared.fs.write( + cx.dst.join(format!("{}{}.{}", theme, cx.shared.resource_suffix, extension)), + content.as_slice())?; themes.insert(theme.to_owned()); } + let write = |p, c| { cx.shared.fs.write(p, c) }; if (*cx.shared).layout.logo.is_empty() { write(cx.dst.join(&format!("rust-logo{}.png", cx.shared.resource_suffix)), static_files::RUST_LOGO)?; @@ -819,11 +857,11 @@ fn write_shared( static_files::WHEEL_SVG)?; write(cx.dst.join(&format!("down-arrow{}.svg", cx.shared.resource_suffix)), static_files::DOWN_ARROW_SVG)?; - write_minify(cx.dst.join(&format!("light{}.css", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.dst.join(&format!("light{}.css", cx.shared.resource_suffix)), static_files::themes::LIGHT, options.enable_minification)?; themes.insert("light".to_owned()); - write_minify(cx.dst.join(&format!("dark{}.css", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.dst.join(&format!("dark{}.css", cx.shared.resource_suffix)), static_files::themes::DARK, options.enable_minification)?; themes.insert("dark".to_owned()); @@ -832,8 +870,7 @@ fn write_shared( themes.sort(); // To avoid theme switch latencies as much as possible, we put everything theme related // at the beginning of the html files into another js file. - write(cx.dst.join(&format!("theme{}.js", cx.shared.resource_suffix)), - format!( + let theme_js = format!( r#"var themes = document.getElementById("theme-choices"); var themePicker = document.getElementById("theme-picker"); @@ -876,39 +913,45 @@ themePicker.onblur = handleThemeButtonsBlur; themes.iter() .map(|s| format!("\"{}\"", s)) .collect::>() - .join(",")).as_bytes(), + .join(",")); + write(cx.dst.join(&format!("theme{}.js", cx.shared.resource_suffix)), + theme_js.as_bytes() )?; - write_minify(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)), static_files::MAIN_JS, options.enable_minification)?; - write_minify(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)), static_files::SETTINGS_JS, options.enable_minification)?; if cx.shared.include_sources { - write_minify(cx.dst.join(&format!("source-script{}.js", cx.shared.resource_suffix)), - static_files::sidebar::SOURCE_SCRIPT, - options.enable_minification)?; + write_minify( + &cx.shared.fs, + cx.dst.join(&format!("source-script{}.js", cx.shared.resource_suffix)), + static_files::sidebar::SOURCE_SCRIPT, + options.enable_minification)?; } { - write_minify(cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)), - &format!("var resourcesSuffix = \"{}\";{}", - cx.shared.resource_suffix, - static_files::STORAGE_JS), - options.enable_minification)?; + write_minify( + &cx.shared.fs, + cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)), + &format!("var resourcesSuffix = \"{}\";{}", + cx.shared.resource_suffix, + static_files::STORAGE_JS), + options.enable_minification)?; } if let Some(ref css) = cx.shared.css_file_extension { let out = cx.dst.join(&format!("theme{}.css", cx.shared.resource_suffix)); + let buffer = try_err!(fs::read_to_string(css), css); if !options.enable_minification { - try_err!(fs::copy(css, out), css); + cx.shared.fs.write(&out, &buffer)?; } else { - let buffer = try_err!(fs::read_to_string(css), css); - write_minify(out, &buffer, options.enable_minification)?; + write_minify(&cx.shared.fs, out, &buffer, options.enable_minification)?; } } - write_minify(cx.dst.join(&format!("normalize{}.css", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.dst.join(&format!("normalize{}.css", cx.shared.resource_suffix)), static_files::NORMALIZE_CSS, options.enable_minification)?; write(cx.dst.join("FiraSans-Regular.woff"), @@ -923,7 +966,7 @@ themePicker.onblur = handleThemeButtonsBlur; static_files::source_serif_pro::BOLD)?; write(cx.dst.join("SourceSerifPro-It.ttf.woff"), static_files::source_serif_pro::ITALIC)?; - write(cx.dst.join("SourceSerifPro-LICENSE.txt"), + write(cx.dst.join("SourceSerifPro-LICENSE.md"), static_files::source_serif_pro::LICENSE)?; write(cx.dst.join("SourceCodePro-Regular.woff"), static_files::source_code_pro::REGULAR)?; @@ -944,36 +987,15 @@ themePicker.onblur = handleThemeButtonsBlur; key: &str, for_search_index: bool, ) -> io::Result<(Vec, Vec, Vec)> { - use minifier::js; - let mut ret = Vec::new(); let mut krates = Vec::new(); let mut variables = Vec::new(); - let mut krate = krate.to_owned(); - if path.exists() { for line in BufReader::new(File::open(path)?).lines() { let line = line?; if for_search_index && line.starts_with("var R") { variables.push(line.clone()); - // We need to check if the crate name has been put into a variable as well. - let tokens = js::simple_minify(&line).apply(js::clean_tokens); - let mut pos = 0; - while pos < tokens.len() { - if let Some((var_pos, Some(value_pos))) = - js::get_variable_name_and_value_positions(&tokens, pos) { - if let Some(s) = tokens.0[value_pos].get_string() { - if &s[1..s.len() - 1] == krate { - if let Some(var) = tokens[var_pos].get_other() { - krate = var.to_owned(); - break - } - } - } - } - pos += 1; - } continue; } if !line.starts_with(key) { @@ -1002,10 +1024,9 @@ themePicker.onblur = handleThemeButtonsBlur; }) } - let dst = cx.dst.join("aliases.js"); + let dst = cx.dst.join(&format!("aliases{}.js", cx.shared.resource_suffix)); { let (mut all_aliases, _, _) = try_err!(collect(&dst, &krate.name, "ALIASES", false), &dst); - let mut w = try_err!(File::create(&dst), &dst); let mut output = String::with_capacity(100); for (alias, items) in &cache.aliases { if items.is_empty() { @@ -1020,10 +1041,12 @@ themePicker.onblur = handleThemeButtonsBlur; } all_aliases.push(format!("ALIASES[\"{}\"] = {{{}}};", krate.name, output)); all_aliases.sort(); - try_err!(writeln!(&mut w, "var ALIASES = {{}};"), &dst); + let mut v = Vec::new(); + try_err!(writeln!(&mut v, "var ALIASES = {{}};"), &dst); for aliases in &all_aliases { - try_err!(writeln!(&mut w, "{}", aliases), &dst); + try_err!(writeln!(&mut v, "{}", aliases), &dst); } + cx.shared.fs.write(&dst, &v)?; } use std::ffi::OsString; @@ -1053,17 +1076,26 @@ themePicker.onblur = handleThemeButtonsBlur; .expect("invalid osstring conversion"))) .collect::>(); files.sort_unstable_by(|a, b| a.cmp(b)); - // FIXME(imperio): we could avoid to generate "dirs" and "files" if they're empty. - format!("{{\"name\":\"{name}\",\"dirs\":[{subs}],\"files\":[{files}]}}", + let subs = subs.iter().map(|s| s.to_json_string()).collect::>().join(","); + let dirs = if subs.is_empty() { + String::new() + } else { + format!(",\"dirs\":[{}]", subs) + }; + let files = files.join(","); + let files = if files.is_empty() { + String::new() + } else { + format!(",\"files\":[{}]", files) + }; + format!("{{\"name\":\"{name}\"{dirs}{files}}}", name=self.elem.to_str().expect("invalid osstring conversion"), - subs=subs.iter().map(|s| s.to_json_string()).collect::>().join(","), - files=files.join(",")) + dirs=dirs, + files=files) } } if cx.shared.include_sources { - use std::path::Component; - let mut hierarchy = Hierarchy::new(OsString::new()); for source in cx.shared.local_sources.iter() .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root) @@ -1090,7 +1122,7 @@ themePicker.onblur = handleThemeButtonsBlur; } } - let dst = cx.dst.join("source-files.js"); + let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix)); let (mut all_sources, _krates, _) = try_err!(collect(&dst, &krate.name, "sourcesIndex", false), &dst); @@ -1098,15 +1130,16 @@ themePicker.onblur = handleThemeButtonsBlur; &krate.name, hierarchy.to_json_string())); all_sources.sort(); - let mut w = try_err!(File::create(&dst), &dst); - try_err!(writeln!(&mut w, + let mut v = Vec::new(); + try_err!(writeln!(&mut v, "var N = null;var sourcesIndex = {{}};\n{}\ncreateSourceSidebar();", all_sources.join("\n")), &dst); + cx.shared.fs.write(&dst, &v)?; } // Update the search index - let dst = cx.dst.join("search-index.js"); + let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix)); let (mut all_indexes, mut krates, variables) = try_err!(collect(&dst, &krate.name, "searchIndex", @@ -1116,28 +1149,26 @@ themePicker.onblur = handleThemeButtonsBlur; // Sort the indexes by crate so the file will be generated identically even // with rustdoc running in parallel. all_indexes.sort(); - let mut w = try_err!(File::create(&dst), &dst); - if options.enable_minification { - try_err!(writeln!(&mut w, "var N=null,E=\"\",T=\"t\",U=\"u\",searchIndex={{}};"), &dst); - } else { - try_err!(writeln!(&mut w, "var searchIndex={{}};"), &dst); + { + let mut v = Vec::new(); + try_err!(writeln!(&mut v, "var N=null,E=\"\",T=\"t\",U=\"u\",searchIndex={{}};"), &dst); + try_err!(write_minify_replacer( + &mut v, + &format!("{}\n{}", variables.join(""), all_indexes.join("\n")), + options.enable_minification), + &dst); + try_err!(write!(&mut v, "initSearch(searchIndex);addSearchOptions(searchIndex);"), &dst); + cx.shared.fs.write(&dst, &v)?; } - try_err!(write_minify_replacer(&mut w, - &format!("{}\n{}", variables.join(""), all_indexes.join("\n")), - options.enable_minification), - &dst); - try_err!(write!(&mut w, "initSearch(searchIndex);addSearchOptions(searchIndex);"), &dst); - if options.enable_index_page { if let Some(index_page) = options.index_page.clone() { let mut md_opts = options.clone(); md_opts.output = cx.dst.clone(); md_opts.external_html = (*cx.shared).layout.external_html.clone(); - crate::markdown::render(index_page, md_opts, diag); + crate::markdown::render(index_page, md_opts, diag, cx.edition); } else { let dst = cx.dst.join("index.html"); - let mut w = BufWriter::new(try_err!(File::create(&dst), &dst)); let page = layout::Page { title: "Index of crates", css_class: "mod", @@ -1164,12 +1195,13 @@ themePicker.onblur = handleThemeButtonsBlur; SlashChecker(s), s) }) .collect::()); - try_err!(layout::render(&mut w, &cx.shared.layout, + let mut v = Vec::new(); + try_err!(layout::render(&mut v, &cx.shared.layout, &page, &(""), &content, cx.shared.css_file_extension.is_some(), &cx.shared.themes, cx.shared.generate_search_filter), &dst); - try_err!(w.flush(), &dst); + cx.shared.fs.write(&dst, &v)?; } } @@ -1221,7 +1253,7 @@ themePicker.onblur = handleThemeButtonsBlur; for part in &remote_path[..remote_path.len() - 1] { mydst.push(part); } - try_err!(fs::create_dir_all(&mydst), &mydst); + cx.shared.ensure_dir(&mydst)?; mydst.push(&format!("{}.{}.js", remote_item_type.css_class(), remote_path[remote_path.len() - 1])); @@ -1234,19 +1266,20 @@ themePicker.onblur = handleThemeButtonsBlur; // identically even with rustdoc running in parallel. all_implementors.sort(); - let mut f = try_err!(File::create(&mydst), &mydst); - try_err!(writeln!(&mut f, "(function() {{var implementors = {{}};"), &mydst); + let mut v = Vec::new(); + try_err!(writeln!(&mut v, "(function() {{var implementors = {{}};"), &mydst); for implementor in &all_implementors { - try_err!(writeln!(&mut f, "{}", *implementor), &mydst); + try_err!(writeln!(&mut v, "{}", *implementor), &mydst); } - try_err!(writeln!(&mut f, "{}", r" + try_err!(writeln!(&mut v, "{}", r" if (window.register_implementors) { window.register_implementors(implementors); } else { window.pending_implementors = implementors; } "), &mydst); - try_err!(writeln!(&mut f, r"}})()"), &mydst); + try_err!(writeln!(&mut v, r"}})()"), &mydst); + cx.shared.fs.write(&mydst, &v)?; } Ok(()) } @@ -1255,7 +1288,7 @@ fn render_sources(dst: &Path, scx: &mut SharedContext, krate: clean::Crate) -> Result { info!("emitting source files"); let dst = dst.join("src").join(&krate.name); - try_err!(fs::create_dir_all(&dst), &dst); + scx.ensure_dir(&dst)?; let mut folder = SourceCollector { dst, scx, @@ -1263,22 +1296,17 @@ fn render_sources(dst: &Path, scx: &mut SharedContext, Ok(folder.fold_crate(krate)) } -/// Writes the entire contents of a string to a destination, not attempting to -/// catch any errors. -fn write(dst: PathBuf, contents: &[u8]) -> Result<(), Error> { - Ok(try_err!(fs::write(&dst, contents), &dst)) -} - -fn write_minify(dst: PathBuf, contents: &str, enable_minification: bool) -> Result<(), Error> { +fn write_minify(fs:&DocFS, dst: PathBuf, contents: &str, enable_minification: bool + ) -> Result<(), Error> { if enable_minification { if dst.extension() == Some(&OsStr::new("css")) { let res = try_none!(minifier::css::minify(contents).ok(), &dst); - write(dst, res.as_bytes()) + fs.write(dst, res.as_bytes()) } else { - write(dst, minifier::js::minify(contents).as_bytes()) + fs.write(dst, minifier::js::minify(contents).as_bytes()) } } else { - write(dst, contents.as_bytes()) + fs.write(dst, contents.as_bytes()) } } @@ -1287,46 +1315,61 @@ fn write_minify_replacer( contents: &str, enable_minification: bool, ) -> io::Result<()> { - use minifier::js::{Keyword, ReservedChar, Token}; + use minifier::js::{simple_minify, Keyword, ReservedChar, Token, Tokens}; if enable_minification { writeln!(dst, "{}", - minifier::js::simple_minify(contents) - .apply(|f| { - // We keep backlines. - minifier::js::clean_tokens_except(f, |c| { - c.get_char() != Some(ReservedChar::Backline) - }) - }) - .apply(|f| { - minifier::js::replace_token_with(f, |t| { - match *t { - Token::Keyword(Keyword::Null) => Some(Token::Other("N")), - Token::String(s) => { - let s = &s[1..s.len() -1]; // The quotes are included - if s.is_empty() { - Some(Token::Other("E")) - } else if s == "t" { - Some(Token::Other("T")) - } else if s == "u" { - Some(Token::Other("U")) - } else { - None - } - } - _ => None, - } - }) - }) - .apply(|f| { - // We add a backline after the newly created variables. - minifier::js::aggregate_strings_into_array_with_separation( - f, - "R", - Token::Char(ReservedChar::Backline), - ) - }) - .to_string()) + { + let tokens: Tokens<'_> = simple_minify(contents) + .into_iter() + .filter(|f| { + // We keep backlines. + minifier::js::clean_token_except(f, &|c: &Token<'_>| { + c.get_char() != Some(ReservedChar::Backline) + }) + }) + .map(|f| { + minifier::js::replace_token_with(f, &|t: &Token<'_>| { + match *t { + Token::Keyword(Keyword::Null) => Some(Token::Other("N")), + Token::String(s) => { + let s = &s[1..s.len() -1]; // The quotes are included + if s.is_empty() { + Some(Token::Other("E")) + } else if s == "t" { + Some(Token::Other("T")) + } else if s == "u" { + Some(Token::Other("U")) + } else { + None + } + } + _ => None, + } + }) + }) + .collect::>() + .into(); + tokens.apply(|f| { + // We add a backline after the newly created variables. + minifier::js::aggregate_strings_into_array_with_separation_filter( + f, + "R", + Token::Char(ReservedChar::Backline), + // This closure prevents crates' names from being aggregated. + // + // The point here is to check if the string is preceded by '[' and + // "searchIndex". If so, it means this is a crate name and that it + // shouldn't be aggregated. + |tokens, pos| { + pos < 2 || + !tokens[pos - 1].is_char(ReservedChar::OpenBracket) || + tokens[pos - 2].get_other() != Some("searchIndex") + } + ) + }) + .to_string() + }) } else { writeln!(dst, "{}", contents) } @@ -1337,7 +1380,8 @@ fn write_minify_replacer( /// static HTML tree. Each component in the cleaned path will be passed as an /// argument to `f`. The very last component of the path (ie the file name) will /// be passed to `f` if `keep_filename` is true, and ignored otherwise. -fn clean_srcpath(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) where +fn clean_srcpath(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) +where F: FnMut(&OsStr), { // make it relative, if possible @@ -1379,8 +1423,8 @@ fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Pat // Failing that, see if there's an attribute specifying where to find this // external crate - e.attrs.lists("doc") - .filter(|a| a.check_name("html_root_url")) + e.attrs.lists(sym::doc) + .filter(|a| a.check_name(sym::html_root_url)) .filter_map(|a| a.value_str()) .map(|url| { let mut url = url.to_string(); @@ -1424,7 +1468,7 @@ impl<'a> DocFolder for SourceCollector<'a> { impl<'a> SourceCollector<'a> { /// Renders the given filename into its corresponding HTML source file. - fn emit_source(&mut self, filename: &FileName) -> io::Result<()> { + fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> { let p = match *filename { FileName::Real(ref file) => file, _ => return Ok(()), @@ -1434,7 +1478,7 @@ impl<'a> SourceCollector<'a> { return Ok(()); } - let contents = fs::read_to_string(&p)?; + let contents = try_err!(fs::read_to_string(&p), &p); // Remove the utf-8 BOM if any let contents = if contents.starts_with("\u{feff}") { @@ -1449,11 +1493,11 @@ impl<'a> SourceCollector<'a> { let mut href = String::new(); clean_srcpath(&self.scx.src_root, &p, false, |component| { cur.push(component); - fs::create_dir_all(&cur).unwrap(); root_path.push_str("../"); href.push_str(&component.to_string_lossy()); href.push('/'); }); + self.scx.ensure_dir(&cur)?; let mut fname = p.file_name() .expect("source has no filename") .to_os_string(); @@ -1461,8 +1505,8 @@ impl<'a> SourceCollector<'a> { cur.push(&fname); href.push_str(&fname.to_string_lossy()); - let mut w = BufWriter::new(File::create(&cur)?); - let title = format!("{} -- source", cur.file_name().unwrap() + let mut v = Vec::new(); + let title = format!("{} -- source", cur.file_name().expect("failed to get file name") .to_string_lossy()); let desc = format!("Source to the Rust file `{}`.", filename); let page = layout::Page { @@ -1473,15 +1517,15 @@ impl<'a> SourceCollector<'a> { description: &desc, keywords: BASIC_KEYWORDS, resource_suffix: &self.scx.resource_suffix, - extra_scripts: &["source-files"], + extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)], static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)], }; - layout::render(&mut w, &self.scx.layout, + try_err!(layout::render(&mut v, &self.scx.layout, &page, &(""), &Source(contents), self.scx.css_file_extension.is_some(), &self.scx.themes, - self.scx.generate_search_filter)?; - w.flush()?; + self.scx.generate_search_filter), &cur); + self.scx.fs.write(&cur, &v)?; self.scx.local_sources.insert(p.clone(), href); Ok(()) } @@ -1539,12 +1583,12 @@ impl DocFolder for Cache { if let Some(ref s) = item.name { let (parent, is_inherent_impl_item) = match item.inner { clean::StrippedItem(..) => ((None, None), false), - clean::AssociatedConstItem(..) | + clean::AssocConstItem(..) | clean::TypedefItem(_, true) if self.parent_is_trait_impl => { // skip associated items in trait impls ((None, None), false) } - clean::AssociatedTypeItem(..) | + clean::AssocTypeItem(..) | clean::TyMethodItem(..) | clean::StructFieldItem(..) | clean::VariantItem(..) => { @@ -1552,7 +1596,7 @@ impl DocFolder for Cache { Some(&self.stack[..self.stack.len() - 1])), false) } - clean::MethodItem(..) | clean::AssociatedConstItem(..) => { + clean::MethodItem(..) | clean::AssocConstItem(..) => { if self.parent_stack.is_empty() { ((None, None), false) } else { @@ -1749,14 +1793,14 @@ impl DocFolder for Cache { } } -impl<'a> Cache { +impl Cache { fn generics(&mut self, generics: &clean::Generics) { for param in &generics.params { match param.kind { clean::GenericParamDefKind::Lifetime => {} clean::GenericParamDefKind::Type { did, .. } | clean::GenericParamDefKind::Const { did, .. } => { - self.typarams.insert(did, param.name.clone()); + self.param_names.insert(did, param.name.clone()); } } } @@ -1770,8 +1814,8 @@ impl<'a> Cache { let path = self.paths.get(&item.def_id) .map(|p| p.0[..p.0.len() - 1].join("::")) .unwrap_or("std".to_owned()); - for alias in item.attrs.lists("doc") - .filter(|a| a.check_name("alias")) + for alias in item.attrs.lists(sym::doc) + .filter(|a| a.check_name(sym::alias)) .filter_map(|a| a.value_str() .map(|s| s.to_string().replace("\"", ""))) .filter(|v| !v.is_empty()) @@ -2058,7 +2102,6 @@ impl Context { } } - let mut w = BufWriter::new(try_err!(File::create(&final_file), &final_file)); let mut root_path = self.dst.to_str().expect("invalid path").to_owned(); if !root_path.ends_with('/') { root_path.push('/'); @@ -2084,30 +2127,34 @@ impl Context { } else { String::new() }; - try_err!(layout::render(&mut w, &self.shared.layout, + let mut v = Vec::new(); + try_err!(layout::render(&mut v, &self.shared.layout, &page, &sidebar, &all, self.shared.css_file_extension.is_some(), &self.shared.themes, self.shared.generate_search_filter), &final_file); + self.shared.fs.write(&final_file, &v)?; // Generating settings page. - let settings = Settings::new("./", &self.shared.resource_suffix); + let settings = Settings::new(self.shared.static_root_path.deref().unwrap_or("./"), + &self.shared.resource_suffix); page.title = "Rustdoc settings"; page.description = "Settings of Rustdoc"; page.root_path = "./"; - let mut w = BufWriter::new(try_err!(File::create(&settings_file), &settings_file)); let mut themes = self.shared.themes.clone(); let sidebar = "

Settings

"; themes.push(PathBuf::from("settings.css")); let layout = self.shared.layout.clone(); - try_err!(layout::render(&mut w, &layout, + let mut v = Vec::new(); + try_err!(layout::render(&mut v, &layout, &page, &sidebar, &settings, self.shared.css_file_extension.is_some(), &themes, self.shared.generate_search_filter), &settings_file); + self.shared.fs.write(&settings_file, &v)?; Ok(()) } @@ -2207,6 +2254,7 @@ impl Context { // recurse into the items of the module as well. let name = item.name.as_ref().unwrap().to_string(); let mut item = Some(item); + let scx = self.shared.clone(); self.recurse(name, |this| { let item = item.take().unwrap(); @@ -2214,9 +2262,9 @@ impl Context { this.render_item(&mut buf, &item, false).unwrap(); // buf will be empty if the module is stripped and there is no redirect for it if !buf.is_empty() { - try_err!(this.shared.ensure_dir(&this.dst), &this.dst); + this.shared.ensure_dir(&this.dst)?; let joint_dst = this.dst.join("index.html"); - try_err!(fs::write(&joint_dst, buf), &joint_dst); + scx.fs.write(&joint_dst, buf)?; } let m = match item.inner { @@ -2229,9 +2277,10 @@ impl Context { if !this.render_redirect_pages { let items = this.build_sidebar_items(&m); let js_dst = this.dst.join("sidebar-items.js"); - let mut js_out = BufWriter::new(try_err!(File::create(&js_dst), &js_dst)); - try_err!(write!(&mut js_out, "initSidebarItems({});", + let mut v = Vec::new(); + try_err!(write!(&mut v, "initSidebarItems({});", as_json(&items)), &js_dst); + scx.fs.write(&js_dst, &v)?; } for item in m.items { @@ -2248,9 +2297,9 @@ impl Context { let name = item.name.as_ref().unwrap(); let item_type = item.type_(); let file_name = &item_path(item_type, name); - try_err!(self.shared.ensure_dir(&self.dst), &self.dst); + self.shared.ensure_dir(&self.dst)?; let joint_dst = self.dst.join(file_name); - try_err!(fs::write(&joint_dst, buf), &joint_dst); + self.shared.fs.write(&joint_dst, buf)?; if !self.render_redirect_pages { all.append(full_path(self, &item), &item_type); @@ -2260,21 +2309,18 @@ impl Context { // URL for the page. let redir_name = format!("{}.{}.html", name, item_type.name_space()); let redir_dst = self.dst.join(redir_name); - if let Ok(redirect_out) = OpenOptions::new().create_new(true) - .write(true) - .open(&redir_dst) { - let mut redirect_out = BufWriter::new(redirect_out); - try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst); - } + let mut v = Vec::new(); + try_err!(layout::redirect(&mut v, file_name), &redir_dst); + self.shared.fs.write(&redir_dst, &v)?; } // If the item is a macro, redirect from the old macro URL (with !) // to the new one (without). if item_type == ItemType::Macro { let redir_name = format!("{}.{}!.html", item_type, name); let redir_dst = self.dst.join(redir_name); - let redirect_out = try_err!(File::create(&redir_dst), &redir_dst); - let mut redirect_out = BufWriter::new(redirect_out); - try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst); + let mut v = Vec::new(); + try_err!(layout::redirect(&mut v, file_name), &redir_dst); + self.shared.fs.write(&redir_dst, &v)?; } } } @@ -2542,7 +2588,7 @@ fn render_markdown(w: &mut fmt::Formatter<'_>, if is_hidden { " hidden" } else { "" }, prefix, Markdown(md_text, &links, RefCell::new(&mut ids), - cx.codes)) + cx.codes, cx.edition)) } fn document_short( @@ -2601,7 +2647,15 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str { fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fmt::Result { if item.is_non_exhaustive() { write!(w, "
", { - if item.is_struct() { "struct" } else if item.is_enum() { "enum" } else { "type" } + if item.is_struct() { + "struct" + } else if item.is_enum() { + "enum" + } else if item.is_variant() { + "variant" + } else { + "type" + } })?; if item.is_struct() { @@ -2614,6 +2668,10 @@ fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fm write!(w, "Non-exhaustive enums could have additional variants added in future. \ Therefore, when matching against variants of non-exhaustive enums, an \ extra wildcard arm must be added to account for any future variants.")?; + } else if item.is_variant() { + write!(w, "Non-exhaustive enum variants could have additional fields added in future. \ + Therefore, non-exhaustive enum variants cannot be constructed in external \ + crates and cannot be matched against.")?; } else { write!(w, "This type will require a wildcard arm in any match statements or \ constructors.")?; @@ -2895,7 +2953,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { if let Some(note) = note { let mut ids = cx.id_map.borrow_mut(); - let html = MarkdownHtml(¬e, RefCell::new(&mut ids), error_codes); + let html = MarkdownHtml(¬e, RefCell::new(&mut ids), error_codes, cx.edition); message.push_str(&format!(": {}", html)); } stability.push(format!("
{}
", message)); @@ -2944,7 +3002,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { message = format!( "
{}{}
", message, - MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes) + MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes, cx.edition) ); } @@ -2969,7 +3027,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { fn item_constant(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, c: &clean::Constant) -> fmt::Result { write!(w, "
")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "{vis}const \
                {name}: {typ}
", vis = VisSpace(&it.visibility), @@ -2981,7 +3039,7 @@ fn item_constant(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, fn item_static(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, s: &clean::Static) -> fmt::Result { write!(w, "
")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "{vis}static {mutability}\
                {name}: {typ}
", vis = VisSpace(&it.visibility), @@ -3004,7 +3062,7 @@ fn item_function(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, f.generics ).len(); write!(w, "{}
", render_spotlight_traits(it)?)?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w,
            "{vis}{constness}{unsafety}{asyncness}{abi}fn \
            {name}{generics}{decl}{where_clause}
", @@ -3038,7 +3096,7 @@ fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter<' _ => false, }; render_impl(w, cx, implementor, AssocItemLink::Anchor(None), RenderMode::Normal, - implementor.impl_item.stable_since(), false, Some(use_absolute))?; + implementor.impl_item.stable_since(), false, Some(use_absolute), false, false)?; Ok(()) } @@ -3049,7 +3107,7 @@ fn render_impls(cx: &Context, w: &mut fmt::Formatter<'_>, let did = i.trait_did().unwrap(); let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods); render_impl(w, cx, i, assoc_link, - RenderMode::Normal, containing_item.stable_since(), true, None)?; + RenderMode::Normal, containing_item.stable_since(), true, None, false, true)?; } Ok(()) } @@ -3093,7 +3151,7 @@ fn item_trait( // Output the trait definition wrap_into_docblock(w, |w| { write!(w, "
")?;
-        render_attributes(w, it)?;
+        render_attributes(w, it, true)?;
         write!(w, "{}{}{}trait {}{}{}",
                VisSpace(&it.visibility),
                UnsafetySpace(t.unsafety),
@@ -3114,7 +3172,6 @@ fn item_trait(
             // FIXME: we should be using a derived_id for the Anchors here
             write!(w, "{{\n")?;
             for t in &types {
-                write!(w, "    ")?;
                 render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?;
                 write!(w, ";\n")?;
             }
@@ -3122,7 +3179,6 @@ fn item_trait(
                 w.write_str("\n")?;
             }
             for t in &consts {
-                write!(w, "    ")?;
                 render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?;
                 write!(w, ";\n")?;
             }
@@ -3130,7 +3186,6 @@ fn item_trait(
                 w.write_str("\n")?;
             }
             for (pos, m) in required.iter().enumerate() {
-                write!(w, "    ")?;
                 render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?;
                 write!(w, ";\n")?;
 
@@ -3142,7 +3197,6 @@ fn item_trait(
                 w.write_str("\n")?;
             }
             for (pos, m) in provided.iter().enumerate() {
-                write!(w, "    ")?;
                 render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?;
                 match m.inner {
                     clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => {
@@ -3283,7 +3337,7 @@ fn item_trait(
                 );
                 render_impl(w, cx, &implementor, assoc_link,
                             RenderMode::Normal, implementor.impl_item.stable_since(), false,
-                            None)?;
+                            None, true, false)?;
             }
             write_loading_content(w, "")?;
         }
@@ -3342,7 +3396,7 @@ fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>) -> String {
 
     let name = it.name.as_ref().unwrap();
     let ty = match it.type_() {
-        Typedef | AssociatedType => AssociatedType,
+        Typedef | AssocType => AssocType,
         s@_ => s,
     };
 
@@ -3360,8 +3414,10 @@ fn assoc_const(w: &mut fmt::Formatter<'_>,
                it: &clean::Item,
                ty: &clean::Type,
                _default: Option<&String>,
-               link: AssocItemLink<'_>) -> fmt::Result {
-    write!(w, "{}const {}: {}",
+               link: AssocItemLink<'_>,
+               extra: &str) -> fmt::Result {
+    write!(w, "{}{}const {}: {}",
+           extra,
            VisSpace(&it.visibility),
            naive_assoc_href(it, link),
            it.name.as_ref().unwrap(),
@@ -3372,8 +3428,10 @@ fn assoc_const(w: &mut fmt::Formatter<'_>,
 fn assoc_type(w: &mut W, it: &clean::Item,
                              bounds: &[clean::GenericBound],
                              default: Option<&clean::Type>,
-                             link: AssocItemLink<'_>) -> fmt::Result {
-    write!(w, "type {}",
+                             link: AssocItemLink<'_>,
+                             extra: &str) -> fmt::Result {
+    write!(w, "{}type {}",
+           extra,
            naive_assoc_href(it, link),
            it.name.as_ref().unwrap())?;
     if !bounds.is_empty() {
@@ -3392,7 +3450,7 @@ fn render_stability_since_raw<'a, T: fmt::Write>(
 ) -> fmt::Result {
     if let Some(v) = ver {
         if containing_ver != ver && v.len() > 0 {
-            write!(w, "
{0}
", v)? + write!(w, "{0}", v)? } } Ok(()) @@ -3434,11 +3492,12 @@ fn render_assoc_item(w: &mut fmt::Formatter<'_>, } }; let mut header_len = format!( - "{}{}{}{}{:#}fn {}{:#}", + "{}{}{}{}{}{:#}fn {}{:#}", VisSpace(&meth.visibility), ConstnessSpace(header.constness), UnsafetySpace(header.unsafety), AsyncSpace(header.asyncness), + DefaultSpace(meth.is_default()), AbiSpace(header.abi), name, *g @@ -3449,13 +3508,15 @@ fn render_assoc_item(w: &mut fmt::Formatter<'_>, } else { (0, true) }; - render_attributes(w, meth)?; - write!(w, "{}{}{}{}{}fn {name}\ + render_attributes(w, meth, false)?; + write!(w, "{}{}{}{}{}{}{}fn {name}\ {generics}{decl}{where_clause}", + if parent == ItemType::Trait { " " } else { "" }, VisSpace(&meth.visibility), ConstnessSpace(header.constness), UnsafetySpace(header.unsafety), AsyncSpace(header.asyncness), + DefaultSpace(meth.is_default()), AbiSpace(header.abi), href = href, name = name, @@ -3480,11 +3541,13 @@ fn render_assoc_item(w: &mut fmt::Formatter<'_>, clean::MethodItem(ref m) => { method(w, item, m.header, &m.generics, &m.decl, link, parent) } - clean::AssociatedConstItem(ref ty, ref default) => { - assoc_const(w, item, ty, default.as_ref(), link) + clean::AssocConstItem(ref ty, ref default) => { + assoc_const(w, item, ty, default.as_ref(), link, + if parent == ItemType::Trait { " " } else { "" }) } - clean::AssociatedTypeItem(ref bounds, ref default) => { - assoc_type(w, item, bounds, default.as_ref(), link) + clean::AssocTypeItem(ref bounds, ref default) => { + assoc_type(w, item, bounds, default.as_ref(), link, + if parent == ItemType::Trait { " " } else { "" }) } _ => panic!("render_assoc_item called on non-associated-item") } @@ -3494,7 +3557,7 @@ fn item_struct(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, s: &clean::Struct) -> fmt::Result { wrap_into_docblock(w, |w| { write!(w, "
")?;
-        render_attributes(w, it)?;
+        render_attributes(w, it, true)?;
         render_struct(w,
                       it,
                       Some(&s.generics),
@@ -3545,7 +3608,7 @@ fn item_union(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
                s: &clean::Union) -> fmt::Result {
     wrap_into_docblock(w, |w| {
         write!(w, "
")?;
-        render_attributes(w, it)?;
+        render_attributes(w, it, true)?;
         render_union(w,
                      it,
                      Some(&s.generics),
@@ -3590,7 +3653,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
              e: &clean::Enum) -> fmt::Result {
     wrap_into_docblock(w, |w| {
         write!(w, "
")?;
-        render_attributes(w, it)?;
+        render_attributes(w, it, true)?;
         write!(w, "{}enum {}{}{}",
                VisSpace(&it.visibility),
                it.name.as_ref().unwrap(),
@@ -3674,6 +3737,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
             }
             write!(w, "")?;
             document(w, cx, variant)?;
+            document_non_exhaustive(w, variant)?;
 
             use crate::clean::{Variant, VariantKind};
             if let clean::VariantItem(Variant {
@@ -3718,19 +3782,19 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
 }
 
 fn render_attribute(attr: &ast::MetaItem) -> Option {
-    let name = attr.name();
+    let path = attr.path.to_string();
 
     if attr.is_word() {
-        Some(name.to_string())
+        Some(path)
     } else if let Some(v) = attr.value_str() {
-        Some(format!("{} = {:?}", name, v.as_str()))
+        Some(format!("{} = {:?}", path, v.as_str()))
     } else if let Some(values) = attr.meta_item_list() {
         let display: Vec<_> = values.iter().filter_map(|attr| {
             attr.meta_item().and_then(|mi| render_attribute(mi))
         }).collect();
 
         if display.len() > 0 {
-            Some(format!("{}({})", name, display.join(", ")))
+            Some(format!("{}({})", path, display.join(", ")))
         } else {
             None
         }
@@ -3739,23 +3803,30 @@ fn render_attribute(attr: &ast::MetaItem) -> Option {
     }
 }
 
-const ATTRIBUTE_WHITELIST: &'static [&'static str] = &[
-    "export_name",
-    "lang",
-    "link_section",
-    "must_use",
-    "no_mangle",
-    "repr",
-    "unsafe_destructor_blind_to_params",
-    "non_exhaustive"
+const ATTRIBUTE_WHITELIST: &'static [Symbol] = &[
+    sym::export_name,
+    sym::lang,
+    sym::link_section,
+    sym::must_use,
+    sym::no_mangle,
+    sym::repr,
+    sym::unsafe_destructor_blind_to_params,
+    sym::non_exhaustive
 ];
 
-fn render_attributes(w: &mut fmt::Formatter<'_>, it: &clean::Item) -> fmt::Result {
+// The `top` parameter is used when generating the item declaration to ensure it doesn't have a
+// left padding. For example:
+//
+// #[foo] <----- "top" attribute
+// struct Foo {
+//     #[bar] <---- not "top" attribute
+//     bar: usize,
+// }
+fn render_attributes(w: &mut dyn fmt::Write, it: &clean::Item, top: bool) -> fmt::Result {
     let mut attrs = String::new();
 
     for attr in &it.attrs.other_attrs {
-        let name = attr.name();
-        if !ATTRIBUTE_WHITELIST.contains(&&*name.as_str()) {
+        if !ATTRIBUTE_WHITELIST.contains(&attr.name_or_empty()) {
             continue;
         }
         if let Some(s) = render_attribute(&attr.meta().unwrap()) {
@@ -3763,7 +3834,8 @@ fn render_attributes(w: &mut fmt::Formatter<'_>, it: &clean::Item) -> fmt::Resul
         }
     }
     if attrs.len() > 0 {
-        write!(w, "
{}
", &attrs)?; + write!(w, "{}", + if top { " top-attr" } else { "" }, &attrs)?; } Ok(()) } @@ -3937,7 +4009,7 @@ fn render_assoc_items(w: &mut fmt::Formatter<'_>, }; for i in &non_trait { render_impl(w, cx, i, AssocItemLink::Anchor(None), render_mode, - containing_item.stable_since(), true, None)?; + containing_item.stable_since(), true, None, false, true)?; } } if let AssocItemRender::DerefFor { .. } = what { @@ -4096,7 +4168,8 @@ fn spotlight_decl(decl: &clean::FnDecl) -> Result { out.push_str(" "); assoc_type(&mut out, it, &[], Some(&tydef.type_), - AssocItemLink::GotoSource(t_did, &FxHashSet::default()))?; + AssocItemLink::GotoSource(t_did, &FxHashSet::default()), + "")?; out.push_str(";"); } } @@ -4117,11 +4190,16 @@ fn spotlight_decl(decl: &clean::FnDecl) -> Result { } fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocItemLink<'_>, - render_mode: RenderMode, outer_version: Option<&str>, - show_def_docs: bool, use_absolute: Option) -> fmt::Result { + render_mode: RenderMode, outer_version: Option<&str>, show_def_docs: bool, + use_absolute: Option, is_on_foreign_type: bool, + show_default_items: bool) -> fmt::Result { if render_mode == RenderMode::Normal { let id = cx.derive_id(match i.inner_impl().trait_ { - Some(ref t) => format!("impl-{}", small_url_encode(&format!("{:#}", t))), + Some(ref t) => if is_on_foreign_type { + get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t) + } else { + format!("impl-{}", small_url_encode(&format!("{:#}", t))) + }, None => "impl".to_string(), }); if let Some(use_absolute) = use_absolute { @@ -4132,7 +4210,8 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt if let clean::TypedefItem(ref tydef, _) = it.inner { write!(w, " ")?; assoc_type(w, it, &vec![], Some(&tydef.type_), - AssocItemLink::Anchor(None))?; + AssocItemLink::Anchor(None), + "")?; write!(w, ";")?; } } @@ -4154,7 +4233,8 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) { let mut ids = cx.id_map.borrow_mut(); write!(w, "
{}
", - Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids), cx.codes))?; + Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids), + cx.codes, cx.edition))?; } } @@ -4198,19 +4278,19 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt } } clean::TypedefItem(ref tydef, _) => { - let id = cx.derive_id(format!("{}.{}", ItemType::AssociatedType, name)); + let id = cx.derive_id(format!("{}.{}", ItemType::AssocType, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type, extra_class)?; write!(w, "", ns_id)?; - assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id))?; + assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id), "")?; write!(w, "

")?; } - clean::AssociatedConstItem(ref ty, ref default) => { + clean::AssocConstItem(ref ty, ref default) => { let id = cx.derive_id(format!("{}.{}", item_type, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type, extra_class)?; write!(w, "", ns_id)?; - assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?; + assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "")?; write!(w, "")?; render_stability_since_raw(w, item.stable_since(), outer_version)?; if let Some(l) = (Item { cx, item }).src_href() { @@ -4219,12 +4299,12 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt } write!(w, "

")?; } - clean::AssociatedTypeItem(ref bounds, ref default) => { + clean::AssocTypeItem(ref bounds, ref default) => { let id = cx.derive_id(format!("{}.{}", item_type, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type, extra_class)?; write!(w, "", ns_id)?; - assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id))?; + assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id), "")?; write!(w, "

")?; } clean::StrippedItem(..) => return Ok(()), @@ -4296,9 +4376,13 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt // If we've implemented a trait, then also emit documentation for all // default items which weren't overridden in the implementation block. - if let Some(t) = trait_ { - render_default_items(w, cx, t, &i.inner_impl(), - render_mode, outer_version, show_def_docs)?; + // We don't emit documentation for default items if they appear in the + // Implementations on Foreign Types or Implementors sections. + if show_default_items { + if let Some(t) = trait_ { + render_default_items(w, cx, t, &i.inner_impl(), + render_mode, outer_version, show_def_docs)?; + } } write!(w, "
")?; @@ -4312,7 +4396,7 @@ fn item_existential( t: &clean::Existential, ) -> fmt::Result { write!(w, "
")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "existential type {}{}{where_clause}: {bounds};
", it.name.as_ref().unwrap(), t.generics, @@ -4331,7 +4415,7 @@ fn item_existential( fn item_trait_alias(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, t: &clean::TraitAlias) -> fmt::Result { write!(w, "
")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "trait {}{}{} = {};
", it.name.as_ref().unwrap(), t.generics, @@ -4350,7 +4434,7 @@ fn item_trait_alias(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, fn item_typedef(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, t: &clean::Typedef) -> fmt::Result { write!(w, "
")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "type {}{}{where_clause} = {type_};
", it.name.as_ref().unwrap(), t.generics, @@ -4368,7 +4452,7 @@ fn item_typedef(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, fn item_foreign_type(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item) -> fmt::Result { writeln!(w, "
extern {{")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(
         w,
         "    {}type {};\n}}
", @@ -4667,11 +4751,15 @@ fn sidebar_struct(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, Ok(()) } +fn get_id_for_impl_on_foreign_type(for_: &clean::Type, trait_: &clean::Type) -> String { + small_url_encode(&format!("impl-{:#}-for-{:#}", trait_, for_)) +} + fn extract_for_impl_name(item: &clean::Item) -> Option<(String, String)> { match item.inner { clean::ItemEnum::ImplItem(ref i) => { if let Some(ref trait_) = i.trait_ { - Some((format!("{:#}", i.for_), format!("{:#}", trait_))) + Some((format!("{:#}", i.for_), get_id_for_impl_on_foreign_type(&i.for_, trait_))) } else { None } @@ -4767,9 +4855,9 @@ fn sidebar_trait(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, .map_or(false, |d| !c.paths.contains_key(&d))) .filter_map(|i| { match extract_for_impl_name(&i.impl_item) { - Some((ref name, ref url)) => { - Some(format!("{}", - small_url_encode(url), + Some((ref name, ref id)) => { + Some(format!("{}", + id, Escape(name))) } _ => None, @@ -4893,8 +4981,8 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) { ItemType::Variant => ("variants", "Variants"), ItemType::Macro => ("macros", "Macros"), ItemType::Primitive => ("primitives", "Primitive Types"), - ItemType::AssociatedType => ("associated-types", "Associated Types"), - ItemType::AssociatedConst => ("associated-consts", "Associated Constants"), + ItemType::AssocType => ("associated-types", "Associated Types"), + ItemType::AssocConst => ("associated-consts", "Associated Constants"), ItemType::ForeignType => ("foreign-types", "Foreign Types"), ItemType::Keyword => ("keywords", "Keywords"), ItemType::Existential => ("existentials", "Existentials"), @@ -4921,7 +5009,7 @@ fn sidebar_module(fmt: &mut fmt::Formatter<'_>, _it: &clean::Item, ItemType::Enum, ItemType::Constant, ItemType::Static, ItemType::Trait, ItemType::Function, ItemType::Typedef, ItemType::Union, ItemType::Impl, ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant, - ItemType::AssociatedType, ItemType::AssociatedConst, ItemType::ForeignType] { + ItemType::AssocType, ItemType::AssocConst, ItemType::ForeignType] { if items.iter().any(|it| !it.is_stripped() && it.type_() == myty) { let (short, name) = item_ty_to_strs(&myty); sidebar.push_str(&format!("
  • {name}
  • ", @@ -5029,20 +5117,26 @@ fn make_item_keywords(it: &clean::Item) -> String { } fn get_index_search_type(item: &clean::Item) -> Option { - let decl = match item.inner { - clean::FunctionItem(ref f) => &f.decl, - clean::MethodItem(ref m) => &m.decl, - clean::TyMethodItem(ref m) => &m.decl, - _ => return None + let (all_types, ret_types) = match item.inner { + clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types), + clean::MethodItem(ref m) => (&m.all_types, &m.ret_types), + clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types), + _ => return None, }; - let inputs = decl.inputs.values.iter().map(|arg| get_index_type(&arg.type_)).collect(); - let output = match decl.output { - clean::FunctionRetTy::Return(ref return_type) => Some(get_index_type(return_type)), - _ => None + let inputs = all_types.iter().map(|arg| { + get_index_type(&arg) + }).filter(|a| a.name.is_some()).collect(); + let output = ret_types.iter().map(|arg| { + get_index_type(&arg) + }).filter(|a| a.name.is_some()).collect::>(); + let output = if output.is_empty() { + None + } else { + Some(output) }; - Some(IndexItemFunctionType { inputs: inputs, output: output }) + Some(IndexItemFunctionType { inputs, output }) } fn get_index_type(clean_type: &clean::Type) -> Type { @@ -5094,9 +5188,6 @@ fn collect_paths_for_type(first_ty: clean::Type) -> Vec { clean::Type::Array(ty, _) => { work.push_back(*ty); }, - clean::Type::Unique(ty) => { - work.push_back(*ty); - }, clean::Type::RawPointer(_, ty) => { work.push_back(*ty); }, diff --git a/src/librustdoc/html/static/FiraSans-LICENSE.txt b/src/librustdoc/html/static/FiraSans-LICENSE.txt index b4a39671ee94d..d444ea92b6f12 100644 --- a/src/librustdoc/html/static/FiraSans-LICENSE.txt +++ b/src/librustdoc/html/static/FiraSans-LICENSE.txt @@ -1,10 +1,5 @@ -Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ -with Reserved Font Name Fira Sans. - -Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ -with Reserved Font Name Fira Mono. - -Copyright (c) 2014, Telefonica S.A. +Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A. +with Reserved Font Name < Fira >, This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is copied below, and is also available with a FAQ at: @@ -24,7 +19,7 @@ with others. The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, +fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The diff --git a/src/librustdoc/html/static/FiraSans-Medium.woff b/src/librustdoc/html/static/FiraSans-Medium.woff index 5627227744ae5..7d742c5fb7d45 100644 Binary files a/src/librustdoc/html/static/FiraSans-Medium.woff and b/src/librustdoc/html/static/FiraSans-Medium.woff differ diff --git a/src/librustdoc/html/static/FiraSans-Regular.woff b/src/librustdoc/html/static/FiraSans-Regular.woff index 9ff40445bf4a6..d8e0363f4e1a0 100644 Binary files a/src/librustdoc/html/static/FiraSans-Regular.woff and b/src/librustdoc/html/static/FiraSans-Regular.woff differ diff --git a/src/librustdoc/html/static/SourceSerifPro-Bold.ttf.woff b/src/librustdoc/html/static/SourceSerifPro-Bold.ttf.woff index e283dae58de6b..ca254318fe9ea 100644 Binary files a/src/librustdoc/html/static/SourceSerifPro-Bold.ttf.woff and b/src/librustdoc/html/static/SourceSerifPro-Bold.ttf.woff differ diff --git a/src/librustdoc/html/static/SourceSerifPro-It.ttf.woff b/src/librustdoc/html/static/SourceSerifPro-It.ttf.woff index 4bd621c9bd0ba..a287bbe6ed3f8 100644 Binary files a/src/librustdoc/html/static/SourceSerifPro-It.ttf.woff and b/src/librustdoc/html/static/SourceSerifPro-It.ttf.woff differ diff --git a/src/librustdoc/html/static/SourceSerifPro-LICENSE.md b/src/librustdoc/html/static/SourceSerifPro-LICENSE.md new file mode 100644 index 0000000000000..22cb755f2f1db --- /dev/null +++ b/src/librustdoc/html/static/SourceSerifPro-LICENSE.md @@ -0,0 +1,93 @@ +Copyright 2014-2018 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/librustdoc/html/static/SourceSerifPro-LICENSE.txt b/src/librustdoc/html/static/SourceSerifPro-LICENSE.txt deleted file mode 100644 index b77d653ad4f0d..0000000000000 --- a/src/librustdoc/html/static/SourceSerifPro-LICENSE.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. - -This Font Software is licensed under the SIL Open Font License, Version 1.1. - -This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/librustdoc/html/static/SourceSerifPro-Regular.ttf.woff b/src/librustdoc/html/static/SourceSerifPro-Regular.ttf.woff index 96b36a0ed2366..a3d55cfdf2555 100644 Binary files a/src/librustdoc/html/static/SourceSerifPro-Regular.ttf.woff and b/src/librustdoc/html/static/SourceSerifPro-Regular.ttf.woff differ diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 1849e53d937ad..82d2c11b2497b 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -162,8 +162,15 @@ if (!DOMTokenList.prototype.remove) { var i, from, to, match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/); if (match) { from = parseInt(match[1], 10); - to = Math.min(50000, parseInt(match[2] || match[1], 10)); - from = Math.min(from, to); + to = from; + if (typeof match[2] !== "undefined") { + to = parseInt(match[2], 10); + } + if (to < from) { + var tmp = to; + to = from; + from = tmp; + } elem = document.getElementById(from); if (!elem) { return; @@ -180,7 +187,11 @@ if (!DOMTokenList.prototype.remove) { }); }); for (i = from; i <= to; ++i) { - addClass(document.getElementById(i), "line-highlighted"); + elem = document.getElementById(i); + if (!elem) { + break; + } + addClass(elem, "line-highlighted"); } } else if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) { addClass(search, "hidden"); @@ -714,7 +725,10 @@ if (!DOMTokenList.prototype.remove) { } lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance); if (lev_distance <= MAX_LEV_DISTANCE) { - lev_distance = Math.min(checkGenerics(obj, val), lev_distance); + // The generics didn't match but the name kinda did so we give it + // a levenshtein distance value that isn't *this* good so it goes + // into the search results but not too high. + lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2); } else if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) { // We can check if the type we're looking for is inside the generics! var olength = obj[GENERICS_DATA].length; @@ -752,13 +766,26 @@ if (!DOMTokenList.prototype.remove) { var lev_distance = MAX_LEV_DISTANCE + 1; if (obj && obj.type && obj.type.length > OUTPUT_DATA) { - var tmp = checkType(obj.type[OUTPUT_DATA], val, literalSearch); - if (literalSearch === true && tmp === true) { - return true; + var ret = obj.type[OUTPUT_DATA]; + if (!obj.type[OUTPUT_DATA].length) { + ret = [ret]; } - lev_distance = Math.min(tmp, lev_distance); - if (lev_distance === 0) { - return 0; + for (var x = 0; x < ret.length; ++x) { + var r = ret[x]; + if (typeof r === "string") { + r = [r]; + } + var tmp = checkType(r, val, literalSearch); + if (literalSearch === true) { + if (tmp === true) { + return true; + } + continue; + } + lev_distance = Math.min(tmp, lev_distance); + if (lev_distance === 0) { + return 0; + } } } return literalSearch === true ? false : lev_distance; @@ -914,10 +941,10 @@ if (!DOMTokenList.prototype.remove) { returned = checkReturned(ty, output, true); if (output.name === "*" || returned === true) { in_args = false; - var module = false; + var is_module = false; if (input === "*") { - module = true; + is_module = true; } else { var allFound = true; for (var it = 0; allFound === true && it < inputs.length; it++) { @@ -939,7 +966,7 @@ if (!DOMTokenList.prototype.remove) { dontValidate: true, }; } - if (module === true) { + if (is_module === true) { results[fullId] = { id: i, index: -1, @@ -1057,6 +1084,10 @@ if (!DOMTokenList.prototype.remove) { if (index !== -1 || lev <= MAX_LEV_DISTANCE) { if (index !== -1 && paths.length < 2) { lev = 0; + } else if (searchWords[j] === val) { + // Small trick to fix when you're looking for a one letter type + // and there are other short named types. + lev = -1; } if (results[fullId] === undefined) { results[fullId] = { @@ -2055,6 +2086,14 @@ if (!DOMTokenList.prototype.remove) { collapser(e, collapse); }); } + + var blanket_list = document.getElementById("blanket-implementations-list"); + + if (blanket_list !== null) { + onEachLazy(blanket_list.getElementsByClassName("collapse-toggle"), function(e) { + collapser(e, collapse); + }); + } } } @@ -2077,16 +2116,22 @@ if (!DOMTokenList.prototype.remove) { } var toggle = createSimpleToggle(false); + var hideMethodDocs = getCurrentValue("rustdoc-method-docs") === "true"; + var pageId = getPageId(); var func = function(e) { var next = e.nextElementSibling; if (!next) { return; } - if (hasClass(next, "docblock") || - (hasClass(next, "stability") && - hasClass(next.nextElementSibling, "docblock"))) { - insertAfter(toggle.cloneNode(true), e.childNodes[e.childNodes.length - 1]); + if (hasClass(next, "docblock") === true || + (hasClass(next, "stability") === true && + hasClass(next.nextElementSibling, "docblock") === true)) { + var newToggle = toggle.cloneNode(true); + insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]); + if (hideMethodDocs === true && hasClass(e, "method") === true) { + collapseDocs(newToggle, "hide", pageId); + } } }; @@ -2107,17 +2152,16 @@ if (!DOMTokenList.prototype.remove) { onEachLazy(document.getElementsByClassName("associatedconstant"), func); onEachLazy(document.getElementsByClassName("impl"), funcImpl); var impl_call = function() {}; - if (getCurrentValue("rustdoc-method-docs") !== "false") { + if (hideMethodDocs === true) { impl_call = function(e, newToggle, pageId) { if (e.id.match(/^impl(?:-\d+)?$/) === null) { // Automatically minimize all non-inherent impls - if (hasClass(e, "impl")) { + if (hasClass(e, "impl") === true) { collapseDocs(newToggle, "hide", pageId); } } }; } - var pageId = getPageId(); var newToggle = document.createElement("a"); newToggle.href = "javascript:void(0)"; newToggle.className = "collapse-toggle hidden-default collapsed"; @@ -2163,7 +2207,7 @@ if (!DOMTokenList.prototype.remove) { var inner_toggle = newToggle.cloneNode(true); inner_toggle.onclick = toggleClicked; e.insertBefore(inner_toggle, e.firstChild); - impl_call(e, inner_toggle, pageId); + impl_call(e.previousSibling, inner_toggle, pageId); } }); @@ -2242,6 +2286,8 @@ if (!DOMTokenList.prototype.remove) { otherMessage += "struct"; } else if (hasClass(e, "non-exhaustive-enum")) { otherMessage += "enum"; + } else if (hasClass(e, "non-exhaustive-variant")) { + otherMessage += "enum variant"; } else if (hasClass(e, "non-exhaustive-type")) { otherMessage += "type"; } @@ -2259,36 +2305,15 @@ if (!DOMTokenList.prototype.remove) { if (hasClass(e, "type-decl") === true && showItemDeclarations === true) { collapseDocs(e.previousSibling.childNodes[0], "toggle"); } + if (hasClass(e, "non-exhaustive") === true) { + collapseDocs(e.previousSibling.childNodes[0], "toggle"); + } } } onEachLazy(document.getElementsByClassName("docblock"), buildToggleWrapper); onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper); - // In the search display, allows to switch between tabs. - function printTab(nb) { - if (nb === 0 || nb === 1 || nb === 2) { - currentTab = nb; - } - var nb_copy = nb; - onEachLazy(document.getElementById("titles").childNodes, function(elem) { - if (nb_copy === 0) { - addClass(elem, "selected"); - } else { - removeClass(elem, "selected"); - } - nb_copy -= 1; - }); - onEachLazy(document.getElementById("results").childNodes, function(elem) { - if (nb === 0) { - elem.style.display = ""; - } else { - elem.style.display = "none"; - } - nb -= 1; - }); - } - function createToggleWrapper(tog) { var span = document.createElement("span"); span.className = "toggle-label"; @@ -2311,7 +2336,11 @@ if (!DOMTokenList.prototype.remove) { } var attributesToggle = createToggleWrapper(createSimpleToggle(false)); onEachLazy(main.getElementsByClassName("attributes"), function(i_e) { - i_e.parentNode.insertBefore(attributesToggle.cloneNode(true), i_e); + var attr_tog = attributesToggle.cloneNode(true); + if (hasClass(i_e, "top-attr") === true) { + addClass(attr_tog, "top-attr"); + } + i_e.parentNode.insertBefore(attr_tog, i_e); itemAttributesFunc(i_e); }); @@ -2374,6 +2403,30 @@ if (!DOMTokenList.prototype.remove) { }; }); + // In the search display, allows to switch between tabs. + function printTab(nb) { + if (nb === 0 || nb === 1 || nb === 2) { + currentTab = nb; + } + var nb_copy = nb; + onEachLazy(document.getElementById("titles").childNodes, function(elem) { + if (nb_copy === 0) { + addClass(elem, "selected"); + } else { + removeClass(elem, "selected"); + } + nb_copy -= 1; + }); + onEachLazy(document.getElementById("results").childNodes, function(elem) { + if (nb === 0) { + elem.style.display = ""; + } else { + elem.style.display = "none"; + } + nb -= 1; + }); + } + function putBackSearch(search_input) { if (search_input.value !== "") { addClass(main, "hidden"); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 787f3c7f48004..0493bf7c5c0f5 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -182,12 +182,25 @@ nav.sub { display: none !important; } -.sidebar img { +.logo-container { + height: 100px; + width: 100px; + position: relative; margin: 20px auto; display: block; margin-top: 10px; } +.logo-container > img { + max-width: 100px; + max-height: 100px; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + display: block; +} + .sidebar .location { border: 1px solid; font-size: 17px; @@ -345,7 +358,7 @@ nav.sub { margin: 0; } .docblock-short code { - white-space: nowrap; + white-space: pre-wrap; } .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { @@ -658,18 +671,18 @@ a { transition: border-color 300ms ease; transition: border-radius 300ms ease-in-out; transition: box-shadow 300ms ease-in-out; - width: calc(100% - 32px); + width: 100%; } #crate-search + .search-input { border-radius: 0 1px 1px 0; + width: calc(100% - 32px); } .search-input:focus { border-radius: 2px; border: 0; outline: 0; - box-shadow: 0 0 8px #078dd8; } .search-results .desc { @@ -914,7 +927,7 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { height: 12px; } -span.since { +.out-of-band > span.since { position: initial; font-size: 20px; margin-right: 5px; @@ -998,6 +1011,195 @@ span.since { opacity: 1; } +.information { + position: absolute; + left: -20px; + margin-top: 7px; + z-index: 1; +} + +.tooltip { + position: relative; + display: inline-block; + cursor: pointer; +} + +.tooltip .tooltiptext { + width: 120px; + display: none; + text-align: center; + padding: 5px 3px; + border-radius: 6px; + margin-left: 5px; + top: -5px; + left: 105%; + z-index: 10; +} + +.tooltip:hover .tooltiptext { + display: inline; +} + +.tooltip .tooltiptext::after { + content: " "; + position: absolute; + top: 50%; + left: 11px; + margin-top: -5px; + border-width: 5px; + border-style: solid; +} + +.important-traits .tooltip .tooltiptext { + border: 1px solid; +} + +pre.rust { + position: relative; + tab-width: 4; + -moz-tab-width: 4; +} + +.search-failed { + text-align: center; + margin-top: 20px; +} + +.search-failed > ul { + text-align: left; + max-width: 570px; + margin-left: auto; + margin-right: auto; +} + +#titles { + height: 35px; +} + +#titles > div { + float: left; + width: 33.3%; + text-align: center; + font-size: 18px; + cursor: pointer; + border-top: 2px solid; +} + +#titles > div:not(:last-child) { + margin-right: 1px; + width: calc(33.3% - 1px); +} + +#titles > div > div.count { + display: inline-block; + font-size: 16px; +} + +.important-traits { + cursor: pointer; + z-index: 2; +} + +h4 > .important-traits { + position: absolute; + left: -44px; + top: 2px; +} + +#all-types { + text-align: center; + border: 1px solid; + margin: 0 10px; + margin-bottom: 10px; + display: block; + border-radius: 7px; +} +#all-types > p { + margin: 5px 0; +} + +#sidebar-toggle { + position: fixed; + top: 30px; + left: 300px; + z-index: 10; + padding: 3px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + cursor: pointer; + font-weight: bold; + transition: left .5s; + font-size: 1.2em; + border: 1px solid; + border-left: 0; +} +#source-sidebar { + position: fixed; + top: 0; + bottom: 0; + left: 0; + width: 300px; + z-index: 1; + overflow: auto; + transition: left .5s; + border-right: 1px solid; +} +#source-sidebar > .title { + font-size: 1.5em; + text-align: center; + border-bottom: 1px solid; + margin-bottom: 6px; +} + +.theme-picker { + position: absolute; + left: 211px; + top: 19px; +} + +.theme-picker button { + outline: none; +} + +#settings-menu { + position: absolute; + right: 0; + top: 10px; + outline: none; +} + +#theme-picker, #settings-menu { + padding: 4px; + width: 27px; + height: 29px; + border: 1px solid; + border-radius: 3px; + cursor: pointer; +} + +#theme-choices { + display: none; + position: absolute; + left: 0; + top: 28px; + border: 1px solid; + border-radius: 3px; + z-index: 1; + cursor: pointer; +} + +#theme-choices > button { + border: none; + width: 100%; + padding: 4px; + text-align: center; + background: rgba(0,0,0,0); +} + +#theme-choices > button:not(:first-child) { + border-top: 1px solid; +} + /* Media Queries */ @media (max-width: 700px) { @@ -1030,14 +1232,20 @@ span.since { padding: 0; } - .sidebar img { + .sidebar .logo-container { width: 35px; + height: 35px; margin-top: 5px; margin-bottom: 5px; float: left; margin-left: 50px; } + .sidebar .logo-container > img { + max-width: 35px; + max-height: 35px; + } + .sidebar-menu { position: fixed; z-index: 10; @@ -1052,6 +1260,10 @@ span.since { height: 45px; } + .rustdoc.source > .sidebar > .sidebar-menu { + display: none; + } + .sidebar-elems { position: fixed; z-index: 1; @@ -1113,122 +1325,13 @@ span.since { h1.fqn { overflow: initial; } -} -@media print { - nav.sub, .content .out-of-band, .collapse-toggle { - display: none; + .theme-picker { + left: 10px; + top: 54px; + z-index: 1; } -} -.information { - position: absolute; - left: -20px; - margin-top: 7px; - z-index: 1; -} - -.tooltip { - position: relative; - display: inline-block; - cursor: pointer; -} - -.tooltip .tooltiptext { - width: 120px; - display: none; - text-align: center; - padding: 5px 3px; - border-radius: 6px; - margin-left: 5px; - top: -5px; - left: 105%; - z-index: 10; -} - -.tooltip:hover .tooltiptext { - display: inline; -} - -.tooltip .tooltiptext::after { - content: " "; - position: absolute; - top: 50%; - left: 11px; - margin-top: -5px; - border-width: 5px; - border-style: solid; -} - -.important-traits .tooltip .tooltiptext { - border: 1px solid; -} - -pre.rust { - position: relative; - tab-width: 4; - -moz-tab-width: 4; -} - -.search-failed { - text-align: center; - margin-top: 20px; -} - -.search-failed > ul { - text-align: left; - max-width: 570px; - margin-left: auto; - margin-right: auto; -} - -#titles { - height: 35px; -} - -#titles > div { - float: left; - width: 33.3%; - text-align: center; - font-size: 18px; - cursor: pointer; - border-top: 2px solid; -} - -#titles > div:not(:last-child):not(.selected) { - margin-right: 1px; - width: calc(33.3% - 1px); -} - -#titles > div > div.count { - display: inline-block; - font-size: 16px; -} - -.important-traits { - cursor: pointer; - z-index: 2; -} - -h4 > .important-traits { - position: absolute; - left: -44px; - top: 2px; -} - -#all-types { - text-align: center; - border: 1px solid; - margin: 0 10px; - margin-bottom: 10px; - display: block; - border-radius: 7px; -} -#all-types > p { - margin: 5px 0; -} - -@media (max-width: 700px) { h4 > .important-traits { position: absolute; left: -22px; @@ -1303,8 +1406,29 @@ h4 > .important-traits { #all-types { margin: 10px; } + + #sidebar-toggle { + top: 100px; + width: 30px; + font-size: 1.5rem; + text-align: center; + padding: 0; + } + + #source-sidebar { + z-index: 11; + } + + #main > .line-numbers { + margin-top: 0; + } } +@media print { + nav.sub, .content .out-of-band, .collapse-toggle { + display: none; + } +} @media (max-width: 416px) { #titles { @@ -1404,63 +1528,6 @@ kbd { cursor: default; } -.theme-picker { - position: absolute; - left: 211px; - top: 19px; -} - -.theme-picker button { - outline: none; -} - -#settings-menu { - position: absolute; - right: 0; - top: 10px; - outline: none; -} - -#theme-picker, #settings-menu { - padding: 4px; - width: 27px; - height: 29px; - border: 1px solid; - border-radius: 3px; - cursor: pointer; -} - -#theme-choices { - display: none; - position: absolute; - left: 0; - top: 28px; - border: 1px solid; - border-radius: 3px; - z-index: 1; - cursor: pointer; -} - -#theme-choices > button { - border: none; - width: 100%; - padding: 4px; - text-align: center; - background: rgba(0,0,0,0); -} - -#theme-choices > button:not(:first-child) { - border-top: 1px solid; -} - -@media (max-width: 700px) { - .theme-picker { - left: 10px; - top: 54px; - z-index: 1; - } -} - .hidden-by-impl-hider, .hidden-by-usual-hider { /* important because of conflicting rule for small screens */ @@ -1512,39 +1579,6 @@ kbd { margin-bottom: 1em; } -#sidebar-toggle { - position: fixed; - top: 30px; - left: 300px; - z-index: 10; - padding: 3px; - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - cursor: pointer; - font-weight: bold; - transition: left .5s; - font-size: 1.2em; - border: 1px solid; - border-left: 0; -} -#source-sidebar { - position: fixed; - top: 0; - bottom: 0; - left: 0; - width: 300px; - z-index: 1; - overflow: auto; - transition: left .5s; - border-right: 1px solid; -} -#source-sidebar > .title { - font-size: 1.5em; - text-align: center; - border-bottom: 1px solid; - margin-bottom: 6px; -} - div.children { padding-left: 27px; display: none; @@ -1577,3 +1611,17 @@ div.name.expand::before { left: -15px; top: 2px; } + +/* This part is to fix the "Expand attributes" part in the type declaration. */ +.type-decl > pre > .toggle-wrapper.toggle-attributes.top-attr { + margin-left: 0 !important; +} +.type-decl > pre > .docblock.attributes.top-attr { + margin-left: 1.8em !important; +} +.type-decl > pre > .toggle-attributes { + margin-left: 2.2em; +} +.type-decl > pre > .docblock.attributes { + margin-left: 4em; +} diff --git a/src/librustdoc/html/static/source-script.js b/src/librustdoc/html/static/source-script.js index 509c628ce5a46..567022b4139ad 100644 --- a/src/librustdoc/html/static/source-script.js +++ b/src/librustdoc/html/static/source-script.js @@ -39,28 +39,32 @@ function createDirEntry(elem, parent, fullPath, currentFile, hasFoundFile) { children.className = "children"; var folders = document.createElement("div"); folders.className = "folders"; - for (var i = 0; i < elem.dirs.length; ++i) { - if (createDirEntry(elem.dirs[i], folders, fullPath, currentFile, - hasFoundFile) === true) { - addClass(name, "expand"); - hasFoundFile = true; + if (elem.dirs) { + for (var i = 0; i < elem.dirs.length; ++i) { + if (createDirEntry(elem.dirs[i], folders, fullPath, currentFile, + hasFoundFile) === true) { + addClass(name, "expand"); + hasFoundFile = true; + } } } children.appendChild(folders); var files = document.createElement("div"); files.className = "files"; - for (i = 0; i < elem.files.length; ++i) { - var file = document.createElement("a"); - file.innerText = elem.files[i]; - file.href = window.rootPath + "src/" + fullPath + elem.files[i] + ".html"; - if (hasFoundFile === false && - currentFile === fullPath + elem.files[i]) { - file.className = "selected"; - addClass(name, "expand"); - hasFoundFile = true; + if (elem.files) { + for (i = 0; i < elem.files.length; ++i) { + var file = document.createElement("a"); + file.innerText = elem.files[i]; + file.href = window.rootPath + "src/" + fullPath + elem.files[i] + ".html"; + if (hasFoundFile === false && + currentFile === fullPath + elem.files[i]) { + file.className = "selected"; + addClass(name, "expand"); + hasFoundFile = true; + } + files.appendChild(file); } - files.appendChild(file); } search.fullPath = fullPath; children.appendChild(files); diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index e756ab60ccc6d..e44ae2ad10cee 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -164,31 +164,36 @@ a.test-arrow { color: #111; background-color: #f0f0f0; border-color: #000; + box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent; } .search-input { color: #111; - box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent; background-color: #f0f0f0; + box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent; } .search-input:focus { border-color: #008dfd; } -#crate-search + .search-input { - box-shadow: 1px 0 0 1px #000, 0 0 0 2px transparent; +#crate-search + .search-input:focus { + box-shadow: 0 0 8px 4px #078dd8; } .module-item .stab { color: #ddd; } -.stab.unstable {background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } +.stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } .stab.internal { background: #FFB9B3; border-color: #B71C1C; color: #2f2f2f; } .stab.deprecated { background: #F3DFFF; border-color: #7F0087; color: #2f2f2f; } .stab.portability { background: #C4ECFF; border-color: #7BA5DB; color: #2f2f2f; } +.stab.portability > code { + color: #ddd; +} + #help > div { background: #4d4d4d; border-color: #bfbfbf; diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index a294f6f2ff123..4c37000dde2c5 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -164,21 +164,21 @@ a.test-arrow { color: #555; background-color: white; border-color: #e0e0e0; - box-shadow: 0px 0 0 1px #e0e0e0, 0 0 0 2px transparent; + box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; } .search-input { color: #555; - box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; background-color: white; + box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; } .search-input:focus { border-color: #66afe9; } -#crate-search + .search-input { - box-shadow: 1px 0 0 1px #e0e0e0, 0 0 0 2px transparent; +#crate-search + .search-input:focus { + box-shadow: 0 0 8px #078dd8; } .module-item .stab { @@ -190,6 +190,10 @@ a.test-arrow { .stab.deprecated { background: #F3DFFF; border-color: #7F0087; } .stab.portability { background: #C4ECFF; border-color: #7BA5DB; } +.stab.portability > code { + color: #000; +} + #help > div { background: #e9e9e9; border-color: #bfbfbf; diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index a1d8cfacc54ad..3a2c24b1a967f 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -91,7 +91,7 @@ pub mod source_serif_pro { pub static ITALIC: &'static [u8] = include_bytes!("static/SourceSerifPro-It.ttf.woff"); /// The file `SourceSerifPro-LICENSE.txt`, the license text for the Source Serif Pro font. - pub static LICENSE: &'static [u8] = include_bytes!("static/SourceSerifPro-LICENSE.txt"); + pub static LICENSE: &'static [u8] = include_bytes!("static/SourceSerifPro-LICENSE.md"); } /// Files related to the Source Code Pro font. diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs index 409f2479ccc7c..2564c611e54e5 100644 --- a/src/librustdoc/html/toc.rs +++ b/src/librustdoc/html/toc.rs @@ -188,85 +188,4 @@ impl fmt::Display for Toc { } #[cfg(test)] -mod tests { - use super::{TocBuilder, Toc, TocEntry}; - - #[test] - fn builder_smoke() { - let mut builder = TocBuilder::new(); - - // this is purposely not using a fancy macro like below so - // that we're sure that this is doing the correct thing, and - // there's been no macro mistake. - macro_rules! push { - ($level: expr, $name: expr) => { - assert_eq!(builder.push($level, - $name.to_string(), - "".to_string()), - $name); - } - } - push!(2, "0.1"); - push!(1, "1"); - { - push!(2, "1.1"); - { - push!(3, "1.1.1"); - push!(3, "1.1.2"); - } - push!(2, "1.2"); - { - push!(3, "1.2.1"); - push!(3, "1.2.2"); - } - } - push!(1, "2"); - push!(1, "3"); - { - push!(4, "3.0.0.1"); - { - push!(6, "3.0.0.1.0.1"); - } - push!(4, "3.0.0.2"); - push!(2, "3.1"); - { - push!(4, "3.1.0.1"); - } - } - - macro_rules! toc { - ($(($level: expr, $name: expr, $(($sub: tt))* )),*) => { - Toc { - entries: vec![ - $( - TocEntry { - level: $level, - name: $name.to_string(), - sec_number: $name.to_string(), - id: "".to_string(), - children: toc!($($sub),*) - } - ),* - ] - } - } - } - let expected = toc!( - (2, "0.1", ), - - (1, "1", - ((2, "1.1", ((3, "1.1.1", )) ((3, "1.1.2", )))) - ((2, "1.2", ((3, "1.2.1", )) ((3, "1.2.2", )))) - ), - - (1, "2", ), - - (1, "3", - ((4, "3.0.0.1", ((6, "3.0.0.1.0.1", )))) - ((4, "3.0.0.2", )) - ((2, "3.1", ((4, "3.1.0.1", )))) - ) - ); - assert_eq!(expected, builder.into_toc()); - } -} +mod tests; diff --git a/src/librustdoc/html/toc/tests.rs b/src/librustdoc/html/toc/tests.rs new file mode 100644 index 0000000000000..ef69ada466496 --- /dev/null +++ b/src/librustdoc/html/toc/tests.rs @@ -0,0 +1,80 @@ +use super::{TocBuilder, Toc, TocEntry}; + +#[test] +fn builder_smoke() { + let mut builder = TocBuilder::new(); + + // this is purposely not using a fancy macro like below so + // that we're sure that this is doing the correct thing, and + // there's been no macro mistake. + macro_rules! push { + ($level: expr, $name: expr) => { + assert_eq!(builder.push($level, + $name.to_string(), + "".to_string()), + $name); + } + } + push!(2, "0.1"); + push!(1, "1"); + { + push!(2, "1.1"); + { + push!(3, "1.1.1"); + push!(3, "1.1.2"); + } + push!(2, "1.2"); + { + push!(3, "1.2.1"); + push!(3, "1.2.2"); + } + } + push!(1, "2"); + push!(1, "3"); + { + push!(4, "3.0.0.1"); + { + push!(6, "3.0.0.1.0.1"); + } + push!(4, "3.0.0.2"); + push!(2, "3.1"); + { + push!(4, "3.1.0.1"); + } + } + + macro_rules! toc { + ($(($level: expr, $name: expr, $(($sub: tt))* )),*) => { + Toc { + entries: vec![ + $( + TocEntry { + level: $level, + name: $name.to_string(), + sec_number: $name.to_string(), + id: "".to_string(), + children: toc!($($sub),*) + } + ),* + ] + } + } + } + let expected = toc!( + (2, "0.1", ), + + (1, "1", + ((2, "1.1", ((3, "1.1.1", )) ((3, "1.1.2", )))) + ((2, "1.2", ((3, "1.2.1", )) ((3, "1.2.2", )))) + ), + + (1, "2", ), + + (1, "3", + ((4, "3.0.0.1", ((6, "3.0.0.1.0.1", )))) + ((4, "3.0.0.2", )) + ((2, "3.1", ((4, "3.1.0.1", )))) + ) + ); + assert_eq!(expected, builder.into_toc()); +} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index b3807d750b6ea..ba423300e0277 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -1,12 +1,16 @@ #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/")] #![feature(bind_by_move_pattern_guards)] #![feature(rustc_private)] +#![feature(arbitrary_self_types)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(in_band_lifetimes)] #![feature(nll)] #![feature(set_stdio)] #![feature(test)] @@ -16,6 +20,7 @@ #![feature(const_fn)] #![feature(drain_filter)] #![feature(inner_deref)] +#![feature(never_type)] #![recursion_limit="256"] @@ -23,14 +28,13 @@ extern crate getopts; extern crate env_logger; extern crate rustc; extern crate rustc_data_structures; -extern crate rustc_codegen_utils; extern crate rustc_driver; extern crate rustc_resolve; extern crate rustc_lint; +extern crate rustc_interface; extern crate rustc_metadata; extern crate rustc_target; extern crate rustc_typeck; -extern crate rustc_interface; extern crate serialize; extern crate syntax; extern crate syntax_pos; @@ -38,8 +42,6 @@ extern crate test as testing; #[macro_use] extern crate log; extern crate rustc_errors as errors; -extern crate serialize as rustc_serialize; // used by deriving - use std::default::Default; use std::env; use std::panic; @@ -55,6 +57,7 @@ mod externalfiles; mod clean; mod config; mod core; +mod docfs; mod doctree; mod fold; pub mod html { @@ -91,11 +94,9 @@ pub fn main() { rustc_driver::set_sigpipe_handler(); env_logger::init(); let res = std::thread::Builder::new().stack_size(thread_stack_size).spawn(move || { - syntax::with_globals(move || { - get_args().map(|args| main_args(&args)).unwrap_or(1) - }) + get_args().map(|args| main_args(&args)).unwrap_or(1) }).unwrap().join().unwrap_or(rustc_driver::EXIT_FAILURE); - process::exit(res as i32); + process::exit(res); } fn get_args() -> Option> { @@ -348,6 +349,11 @@ fn opts() -> Vec { "generate-redirect-pages", "Generate extra pages to support legacy URLs and tool links") }), + unstable("show-coverage", |o| { + o.optflag("", + "show-coverage", + "calculate percentage of public items with documentation") + }), ] } @@ -359,7 +365,7 @@ fn usage(argv0: &str) { println!("{}", options.usage(&format!("{} [options] ", argv0))); } -fn main_args(args: &[String]) -> isize { +fn main_args(args: &[String]) -> i32 { let mut options = getopts::Options::new(); for option in opts() { (option.apply)(&mut options); @@ -374,7 +380,12 @@ fn main_args(args: &[String]) -> isize { Ok(opts) => opts, Err(code) => return code, }; + rustc_interface::interface::default_thread_pool(options.edition, move || { + main_options(options) + }) +} +fn main_options(options: config::Options) -> i32 { let diag = core::new_handler(options.error_format, None, options.debugging_options.treat_err_as_bug, @@ -383,7 +394,10 @@ fn main_args(args: &[String]) -> isize { match (options.should_test, options.markdown_input()) { (true, true) => return markdown::test(options, &diag), (true, false) => return test::run(options), - (false, true) => return markdown::render(options.input, options.render_options, &diag), + (false, true) => return markdown::render(options.input, + options.render_options, + &diag, + options.edition), (false, false) => {} } @@ -391,11 +405,19 @@ fn main_args(args: &[String]) -> isize { // but we can't crates the Handler ahead of time because it's not Send let diag_opts = (options.error_format, options.debugging_options.treat_err_as_bug, - options.debugging_options.ui_testing); + options.debugging_options.ui_testing, + options.edition); + let show_coverage = options.show_coverage; rust_input(options, move |out| { + if show_coverage { + // if we ran coverage, bail early, we don't need to also generate docs at this point + // (also we didn't load in any of the useful passes) + return rustc_driver::EXIT_SUCCESS; + } + let Output { krate, passes, renderinfo, renderopts } = out; info!("going to format"); - let (error_format, treat_err_as_bug, ui_testing) = diag_opts; + let (error_format, treat_err_as_bug, ui_testing, edition) = diag_opts; let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing); match html::render::run( krate, @@ -403,6 +425,7 @@ fn main_args(args: &[String]) -> isize { passes.into_iter().collect(), renderinfo, &diag, + edition, ) { Ok(_) => rustc_driver::EXIT_SUCCESS, Err(e) => { @@ -429,7 +452,7 @@ where R: 'static + Send, let (tx, rx) = channel(); - let result = rustc_driver::monitor(move || syntax::with_globals(move || { + let result = rustc_driver::report_ices_to_stderr_if_any(move || { let crate_name = options.crate_name.clone(); let crate_version = options.crate_version.clone(); let (mut krate, renderinfo, renderopts, passes) = core::run_core(options); @@ -448,7 +471,7 @@ where R: 'static + Send, renderopts, passes: passes })).unwrap(); - })); + }); match result { Ok(()) => rx.recv().unwrap(), diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 0014d9ceb5ba2..b0a37ea9c8081 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -5,6 +5,7 @@ use std::cell::RefCell; use errors; use testing; +use syntax::edition::Edition; use syntax::source_map::DUMMY_SP; use syntax::feature_gate::UnstableFeatures; @@ -36,7 +37,12 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) { /// Render `input` (e.g., "foo.md") into an HTML file in `output` /// (e.g., output = "bar" => "bar/foo.html"). -pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> isize { +pub fn render( + input: PathBuf, + options: RenderOptions, + diag: &errors::Handler, + edition: Edition +) -> i32 { let mut output = options.output; output.push(input.file_stem().unwrap()); output.set_extension("html"); @@ -76,9 +82,9 @@ pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> let mut ids = IdMap::new(); let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); let text = if !options.markdown_no_toc { - MarkdownWithToc(text, RefCell::new(&mut ids), error_codes).to_string() + MarkdownWithToc(text, RefCell::new(&mut ids), error_codes, edition).to_string() } else { - Markdown(text, &[], RefCell::new(&mut ids), error_codes).to_string() + Markdown(text, &[], RefCell::new(&mut ids), error_codes, edition).to_string() }; let err = write!( @@ -126,7 +132,7 @@ pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> } /// Runs any tests/code examples in the markdown file `input`. -pub fn test(mut options: Options, diag: &errors::Handler) -> isize { +pub fn test(mut options: Options, diag: &errors::Handler) -> i32 { let input_str = match load_string(&options.input, diag) { Ok(s) => s, Err(LoadStringError::ReadFail) => return 1, @@ -143,10 +149,9 @@ pub fn test(mut options: Options, diag: &errors::Handler) -> isize { options.linker, options.edition, options.persist_doctests); collector.set_position(DUMMY_SP); let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); - let res = find_testable_code(&input_str, &mut collector, codes); - if let Err(err) = res { - diag.span_warn(DUMMY_SP, &err.to_string()); - } + + find_testable_code(&input_str, &mut collector, codes); + options.test_args.insert(0, "rustdoctest".to_string()); testing::test_main(&options.test_args, collector.tests, testing::Options::new().display_output(options.display_warnings)); diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs new file mode 100644 index 0000000000000..4ee09f7096b61 --- /dev/null +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -0,0 +1,167 @@ +use crate::clean; +use crate::core::DocContext; +use crate::fold::{self, DocFolder}; +use crate::passes::Pass; + +use syntax::attr; +use syntax_pos::FileName; +use syntax::symbol::sym; + +use std::collections::BTreeMap; +use std::ops; + +pub const CALCULATE_DOC_COVERAGE: Pass = Pass { + name: "calculate-doc-coverage", + pass: calculate_doc_coverage, + description: "counts the number of items with and without documentation", +}; + +fn calculate_doc_coverage(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { + let mut calc = CoverageCalculator::default(); + let krate = calc.fold_crate(krate); + + calc.print_results(); + + krate +} + +#[derive(Default, Copy, Clone)] +struct ItemCount { + total: u64, + with_docs: u64, +} + +impl ItemCount { + fn count_item(&mut self, has_docs: bool) { + self.total += 1; + + if has_docs { + self.with_docs += 1; + } + } + + fn percentage(&self) -> Option { + if self.total > 0 { + Some((self.with_docs as f64 * 100.0) / self.total as f64) + } else { + None + } + } +} + +impl ops::Sub for ItemCount { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + ItemCount { + total: self.total - rhs.total, + with_docs: self.with_docs - rhs.with_docs, + } + } +} + +impl ops::AddAssign for ItemCount { + fn add_assign(&mut self, rhs: Self) { + self.total += rhs.total; + self.with_docs += rhs.with_docs; + } +} + +#[derive(Default)] +struct CoverageCalculator { + items: BTreeMap, +} + +impl CoverageCalculator { + fn print_results(&self) { + let mut total = ItemCount::default(); + + fn print_table_line() { + println!("+-{0:->35}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+", ""); + } + + fn print_table_record(name: &str, count: ItemCount, percentage: f64) { + println!("| {:<35} | {:>10} | {:>10} | {:>9.1}% |", + name, count.with_docs, count.total, percentage); + } + + print_table_line(); + println!("| {:<35} | {:>10} | {:>10} | {:>10} |", + "File", "Documented", "Total", "Percentage"); + print_table_line(); + + for (file, &count) in &self.items { + if let Some(percentage) = count.percentage() { + let mut name = file.to_string(); + // if a filename is too long, shorten it so we don't blow out the table + // FIXME(misdreavus): this needs to count graphemes, and probably also track + // double-wide characters... + if name.len() > 35 { + name = "...".to_string() + &name[name.len()-32..]; + } + + print_table_record(&name, count, percentage); + + total += count; + } + } + + print_table_line(); + print_table_record("Total", total, total.percentage().unwrap_or(0.0)); + print_table_line(); + } +} + +impl fold::DocFolder for CoverageCalculator { + fn fold_item(&mut self, i: clean::Item) -> Option { + let has_docs = !i.attrs.doc_strings.is_empty(); + + match i.inner { + _ if !i.def_id.is_local() => { + // non-local items are skipped because they can be out of the users control, + // especially in the case of trait impls, which rustdoc eagerly inlines + return Some(i); + } + clean::StrippedItem(..) => { + // don't count items in stripped modules + return Some(i); + } + clean::ImportItem(..) | clean::ExternCrateItem(..) => { + // docs on `use` and `extern crate` statements are not displayed, so they're not + // worth counting + return Some(i); + } + clean::ImplItem(ref impl_) + if attr::contains_name(&i.attrs.other_attrs, sym::automatically_derived) + || impl_.synthetic || impl_.blanket_impl.is_some() => + { + // built-in derives get the `#[automatically_derived]` attribute, and + // synthetic/blanket impls are made up by rustdoc and can't be documented + // FIXME(misdreavus): need to also find items that came out of a derive macro + return Some(i); + } + clean::ImplItem(ref impl_) => { + if let Some(ref tr) = impl_.trait_ { + debug!("impl {:#} for {:#} in {}", tr, impl_.for_, i.source.filename); + + // don't count trait impls, the missing-docs lint doesn't so we shouldn't + // either + return Some(i); + } else { + // inherent impls *can* be documented, and those docs show up, but in most + // cases it doesn't make sense, as all methods on a type are in one single + // impl block + debug!("impl {:#} in {}", impl_.for_, i.source.filename); + } + } + _ => { + debug!("counting {} {:?} in {}", i.type_(), i.name, i.source.filename); + self.items.entry(i.source.filename.clone()) + .or_default() + .count_item(has_docs); + } + } + + self.fold_item_recur(i) + } +} diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 88d9c87c52898..f6ab1290da37c 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -1,8 +1,8 @@ use errors::Applicability; -use syntax::parse::lexer::{TokenAndSpan, StringReader as Lexer}; +use syntax::parse::lexer::{StringReader as Lexer}; use syntax::parse::{ParseSess, token}; use syntax::source_map::FilePathMapping; -use syntax_pos::FileName; +use syntax_pos::{InnerSpan, FileName}; use crate::clean; use crate::core::DocContext; @@ -16,15 +16,15 @@ pub const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass { description: "validates syntax inside Rust code blocks", }; -pub fn check_code_block_syntax(krate: clean::Crate, cx: &DocContext<'_, '_, '_>) -> clean::Crate { +pub fn check_code_block_syntax(krate: clean::Crate, cx: &DocContext<'_>) -> clean::Crate { SyntaxChecker { cx }.fold_crate(krate) } -struct SyntaxChecker<'a, 'tcx: 'a, 'rcx: 'a> { - cx: &'a DocContext<'a, 'tcx, 'rcx>, +struct SyntaxChecker<'a, 'tcx> { + cx: &'a DocContext<'tcx>, } -impl<'a, 'tcx, 'rcx> SyntaxChecker<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) { let sess = ParseSess::new(FilePathMapping::empty()); let source_file = sess.source_map().new_source_file( @@ -33,8 +33,8 @@ impl<'a, 'tcx, 'rcx> SyntaxChecker<'a, 'tcx, 'rcx> { ); let errors = Lexer::new_or_buffered_errs(&sess, source_file, None).and_then(|mut lexer| { - while let Ok(TokenAndSpan { tok, .. }) = lexer.try_next_token() { - if tok == token::Eof { + while let Ok(token::Token { kind, .. }) = lexer.try_next_token() { + if kind == token::Eof { break; } } @@ -63,7 +63,7 @@ impl<'a, 'tcx, 'rcx> SyntaxChecker<'a, 'tcx, 'rcx> { } if code_block.syntax.is_none() && code_block.is_fenced { - let sp = sp.from_inner_byte_pos(0, 3); + let sp = sp.from_inner(InnerSpan::new(0, 3)); diag.span_suggestion( sp, "mark blocks that do not contain Rust code as text", @@ -98,7 +98,7 @@ impl<'a, 'tcx, 'rcx> SyntaxChecker<'a, 'tcx, 'rcx> { } } -impl<'a, 'tcx, 'rcx> DocFolder for SyntaxChecker<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> { fn fold_item(&mut self, item: clean::Item) -> Option { if let Some(dox) = &item.attrs.collapsed_doc_value() { for code_block in markdown::rust_code_blocks(&dox) { diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index 088a6ea77c73f..8666ba357b832 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -29,7 +29,7 @@ impl DocFragment { } } -pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate { +pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { Collapser.fold_crate(krate) } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 25c86b24c187b..bb85fe898dabd 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1,10 +1,11 @@ -use rustc::lint as lint; -use rustc::hir; -use rustc::hir::def::Def; +use errors::Applicability; +use rustc::hir::def::{Res, DefKind, Namespace::{self, *}, PerNS}; use rustc::hir::def_id::DefId; +use rustc::hir; +use rustc::lint as lint; use rustc::ty; use syntax; -use syntax::ast::{self, Ident, NodeId}; +use syntax::ast::{self, Ident}; use syntax::feature_gate::UnstableFeatures; use syntax::symbol::Symbol; use syntax_pos::DUMMY_SP; @@ -25,7 +26,7 @@ pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass { description: "reads a crate's documentation to resolve intra-doc-links", }; -pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate { +pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate { if !UnstableFeatures::from_environment().is_nightly_build() { krate } else { @@ -35,42 +36,27 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Cra } } -#[derive(Debug)] -enum PathKind { - /// Either a value or type, but not a macro - Unknown, - /// Macro - Macro, - /// Values, functions, consts, statics (everything in the value namespace) - Value, - /// Types, traits (everything in the type namespace) - Type, -} - -struct LinkCollector<'a, 'tcx: 'a, 'rcx: 'a> { - cx: &'a DocContext<'a, 'tcx, 'rcx>, - mod_ids: Vec, - is_nightly_build: bool, +struct LinkCollector<'a, 'tcx> { + cx: &'a DocContext<'tcx>, + mod_ids: Vec, } -impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { - fn new(cx: &'a DocContext<'a, 'tcx, 'rcx>) -> Self { +impl<'a, 'tcx> LinkCollector<'a, 'tcx> { + fn new(cx: &'a DocContext<'tcx>) -> Self { LinkCollector { cx, mod_ids: Vec::new(), - is_nightly_build: UnstableFeatures::from_environment().is_nightly_build(), } } - /// Resolves a given string as a path, along with whether or not it is - /// in the value namespace. Also returns an optional URL fragment in the case - /// of variants and methods. + /// Resolves a string as a path within a particular namespace. Also returns an optional + /// URL fragment in the case of variants and methods. fn resolve(&self, path_str: &str, - is_val: bool, + ns: Namespace, current_item: &Option, - parent_id: Option) - -> Result<(Def, Option), ()> + parent_id: Option) + -> Result<(Res, Option), ()> { let cx = self.cx; @@ -78,34 +64,35 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { // path. if let Some(id) = parent_id.or(self.mod_ids.last().cloned()) { // FIXME: `with_scope` requires the `NodeId` of a module. - let result = cx.resolver.borrow_mut() - .with_scope(id, - |resolver| { - resolver.resolve_str_path_error(DUMMY_SP, - &path_str, is_val) + let node_id = cx.tcx.hir().hir_to_node_id(id); + let result = cx.enter_resolver(|resolver| { + resolver.with_scope(node_id, |resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns == ValueNS) + }) }); - if let Ok(result) = result { + if let Ok((_, res)) = result { + let res = res.map_id(|_| panic!("unexpected node_id")); // In case this is a trait item, skip the // early return and try looking for the trait. - let value = match result.def { - Def::Method(_) | Def::AssociatedConst(_) => true, - Def::AssociatedTy(_) => false, - Def::Variant(_) => return handle_variant(cx, result.def), + let value = match res { + Res::Def(DefKind::Method, _) | Res::Def(DefKind::AssocConst, _) => true, + Res::Def(DefKind::AssocTy, _) => false, + Res::Def(DefKind::Variant, _) => return handle_variant(cx, res), // Not a trait item; just return what we found. - _ => return Ok((result.def, None)) + _ => return Ok((res, None)) }; - if value != is_val { + if value != (ns == ValueNS) { return Err(()) } - } else if let Some(prim) = is_primitive(path_str, is_val) { + } else if let Some(prim) = is_primitive(path_str, ns) { return Ok((prim, Some(path_str.to_owned()))) } else { // If resolution failed, it may still be a method // because methods are not handled by the resolver // If so, bail when we're not looking for a value. - if !is_val { + if ns != ValueNS { return Err(()) } } @@ -113,7 +100,7 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { // Try looking for methods and associated items. let mut split = path_str.rsplitn(2, "::"); let item_name = if let Some(first) = split.next() { - first + Symbol::intern(first) } else { return Err(()) }; @@ -129,12 +116,12 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { path = name.clone(); } } - if let Some(prim) = is_primitive(&path, false) { + if let Some(prim) = is_primitive(&path, TypeNS) { let did = primitive_impl(cx, &path).ok_or(())?; return cx.tcx.associated_items(did) .find(|item| item.ident.name == item_name) .and_then(|item| match item.kind { - ty::AssociatedKind::Method => Some("method"), + ty::AssocKind::Method => Some("method"), _ => None, }) .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name)))) @@ -142,24 +129,27 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { } // FIXME: `with_scope` requires the `NodeId` of a module. - let ty = cx.resolver.borrow_mut() - .with_scope(id, - |resolver| { + let node_id = cx.tcx.hir().hir_to_node_id(id); + let (_, ty_res) = cx.enter_resolver(|resolver| resolver.with_scope(node_id, |resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, false) - })?; - match ty.def { - Def::Struct(did) | Def::Union(did) | Def::Enum(did) | Def::TyAlias(did) => { + }))?; + let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); + match ty_res { + Res::Def(DefKind::Struct, did) + | Res::Def(DefKind::Union, did) + | Res::Def(DefKind::Enum, did) + | Res::Def(DefKind::TyAlias, did) => { let item = cx.tcx.inherent_impls(did) .iter() .flat_map(|imp| cx.tcx.associated_items(*imp)) .find(|item| item.ident.name == item_name); if let Some(item) = item { let out = match item.kind { - ty::AssociatedKind::Method if is_val => "method", - ty::AssociatedKind::Const if is_val => "associatedconstant", + ty::AssocKind::Method if ns == ValueNS => "method", + ty::AssocKind::Const if ns == ValueNS => "associatedconstant", _ => return Err(()) }; - Ok((ty.def, Some(format!("{}.{}", out, item_name)))) + Ok((ty_res, Some(format!("{}.{}", out, item_name)))) } else { match cx.tcx.type_of(did).sty { ty::Adt(def, _) => { @@ -171,7 +161,7 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { .iter() .find(|item| item.ident.name == item_name) } { - Ok((ty.def, + Ok((ty_res, Some(format!("{}.{}", if def.is_enum() { "variant" @@ -187,15 +177,15 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { } } } - Def::Trait(did) => { + Res::Def(DefKind::Trait, did) => { let item = cx.tcx.associated_item_def_ids(did).iter() .map(|item| cx.tcx.associated_item(*item)) .find(|item| item.ident.name == item_name); if let Some(item) = item { let kind = match item.kind { - ty::AssociatedKind::Const if is_val => "associatedconstant", - ty::AssociatedKind::Type if !is_val => "associatedtype", - ty::AssociatedKind::Method if is_val => { + ty::AssocKind::Const if ns == ValueNS => "associatedconstant", + ty::AssocKind::Type if ns == TypeNS => "associatedtype", + ty::AssocKind::Method if ns == ValueNS => { if item.defaultness.has_value() { "method" } else { @@ -205,7 +195,7 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { _ => return Err(()) }; - Ok((ty.def, Some(format!("{}.{}", kind, item_name)))) + Ok((ty_res, Some(format!("{}.{}", kind, item_name)))) } else { Err(()) } @@ -213,15 +203,16 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { _ => Err(()) } } else { + debug!("attempting to resolve item without parent module: {}", path_str); Err(()) } } } -impl<'a, 'tcx, 'rcx> DocFolder for LinkCollector<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { fn fold_item(&mut self, mut item: Item) -> Option { - let item_node_id = if item.is_mod() { - if let Some(id) = self.cx.tcx.hir().as_local_node_id(item.def_id) { + let item_hir_id = if item.is_mod() { + if let Some(id) = self.cx.tcx.hir().as_local_hir_id(item.def_id) { Some(id) } else { debug!("attempting to fold on a non-local item: {:?}", item); @@ -232,11 +223,11 @@ impl<'a, 'tcx, 'rcx> DocFolder for LinkCollector<'a, 'tcx, 'rcx> { }; // FIXME: get the resolver to work with non-local resolve scopes. - let parent_node = self.cx.as_local_node_id(item.def_id).and_then(|node_id| { + let parent_node = self.cx.as_local_hir_id(item.def_id).and_then(|hir_id| { // FIXME: this fails hard for impls in non-module scope, but is necessary for the // current `resolve()` implementation. - match self.cx.tcx.hir().get_module_parent_node(node_id) { - id if id != node_id => Some(id), + match self.cx.tcx.hir().get_module_parent_node(hir_id) { + id if id != hir_id => Some(id), _ => None, } }); @@ -248,14 +239,14 @@ impl<'a, 'tcx, 'rcx> DocFolder for LinkCollector<'a, 'tcx, 'rcx> { let current_item = match item.inner { ModuleItem(..) => { if item.attrs.inner_docs { - if item_node_id.unwrap() != NodeId::from_u32(0) { + if item_hir_id.unwrap() != hir::CRATE_HIR_ID { item.name.clone() } else { None } } else { match parent_node.or(self.mod_ids.last().cloned()) { - Some(parent) if parent != NodeId::from_u32(0) => { + Some(parent) if parent != hir::CRATE_HIR_ID => { // FIXME: can we pull the parent module's name from elsewhere? Some(self.cx.tcx.hir().name(parent).to_string()) } @@ -274,7 +265,7 @@ impl<'a, 'tcx, 'rcx> DocFolder for LinkCollector<'a, 'tcx, 'rcx> { }; if item.is_mod() && item.attrs.inner_docs { - self.mod_ids.push(item_node_id.unwrap()); + self.mod_ids.push(item_hir_id.unwrap()); } let cx = self.cx; @@ -282,39 +273,41 @@ impl<'a, 'tcx, 'rcx> DocFolder for LinkCollector<'a, 'tcx, 'rcx> { look_for_tests(&cx, &dox, &item, true); - if !self.is_nightly_build { - return None; - } - for (ori_link, link_range) in markdown_links(&dox) { // Bail early for real links. if ori_link.contains('/') { continue; } + + // [] is mostly likely not supposed to be a link + if ori_link.is_empty() { + continue; + } + let link = ori_link.replace("`", ""); - let (def, fragment) = { - let mut kind = PathKind::Unknown; + let (res, fragment) = { + let mut kind = None; let path_str = if let Some(prefix) = ["struct@", "enum@", "type@", "trait@", "union@"].iter() .find(|p| link.starts_with(**p)) { - kind = PathKind::Type; + kind = Some(TypeNS); link.trim_start_matches(prefix) } else if let Some(prefix) = ["const@", "static@", "value@", "function@", "mod@", "fn@", "module@", "method@"] .iter().find(|p| link.starts_with(**p)) { - kind = PathKind::Value; + kind = Some(ValueNS); link.trim_start_matches(prefix) } else if link.ends_with("()") { - kind = PathKind::Value; + kind = Some(ValueNS); link.trim_end_matches("()") } else if link.starts_with("macro@") { - kind = PathKind::Macro; + kind = Some(MacroNS); link.trim_start_matches("macro@") } else if link.ends_with('!') { - kind = PathKind::Macro; + kind = Some(MacroNS); link.trim_end_matches('!') } else { &link[..] @@ -326,102 +319,87 @@ impl<'a, 'tcx, 'rcx> DocFolder for LinkCollector<'a, 'tcx, 'rcx> { } match kind { - PathKind::Value => { - if let Ok(def) = self.resolve(path_str, true, ¤t_item, parent_node) { - def + Some(ns @ ValueNS) => { + if let Ok(res) = self.resolve(path_str, ns, ¤t_item, parent_node) { + res } else { - resolution_failure(cx, &item.attrs, path_str, &dox, link_range); + resolution_failure(cx, &item, path_str, &dox, link_range); // This could just be a normal link or a broken link // we could potentially check if something is // "intra-doc-link-like" and warn in that case. continue; } } - PathKind::Type => { - if let Ok(def) = self.resolve(path_str, false, ¤t_item, parent_node) { - def + Some(ns @ TypeNS) => { + if let Ok(res) = self.resolve(path_str, ns, ¤t_item, parent_node) { + res } else { - resolution_failure(cx, &item.attrs, path_str, &dox, link_range); + resolution_failure(cx, &item, path_str, &dox, link_range); // This could just be a normal link. continue; } } - PathKind::Unknown => { + None => { // Try everything! - if let Some(macro_def) = macro_resolve(cx, path_str) { - if let Ok(type_def) = - self.resolve(path_str, false, ¤t_item, parent_node) - { - let (type_kind, article, type_disambig) - = type_ns_kind(type_def.0, path_str); - ambiguity_error(cx, &item.attrs, path_str, - article, type_kind, &type_disambig, - "a", "macro", &format!("macro@{}", path_str)); - continue; - } else if let Ok(value_def) = - self.resolve(path_str, true, ¤t_item, parent_node) - { - let (value_kind, value_disambig) - = value_ns_kind(value_def.0, path_str) - .expect("struct and mod cases should have been \ - caught in previous branch"); - ambiguity_error(cx, &item.attrs, path_str, - "a", value_kind, &value_disambig, - "a", "macro", &format!("macro@{}", path_str)); - } - (macro_def, None) - } else if let Ok(type_def) = - self.resolve(path_str, false, ¤t_item, parent_node) - { - // It is imperative we search for not-a-value first - // Otherwise we will find struct ctors for when we are looking - // for structs, and the link won't work if there is something in - // both namespaces. - if let Ok(value_def) = - self.resolve(path_str, true, ¤t_item, parent_node) - { - let kind = value_ns_kind(value_def.0, path_str); - if let Some((value_kind, value_disambig)) = kind { - let (type_kind, article, type_disambig) - = type_ns_kind(type_def.0, path_str); - ambiguity_error(cx, &item.attrs, path_str, - article, type_kind, &type_disambig, - "a", value_kind, &value_disambig); - continue; - } - } - type_def - } else if let Ok(value_def) = - self.resolve(path_str, true, ¤t_item, parent_node) - { - value_def - } else { - resolution_failure(cx, &item.attrs, path_str, &dox, link_range); + let candidates = PerNS { + macro_ns: macro_resolve(cx, path_str).map(|res| (res, None)), + type_ns: self + .resolve(path_str, TypeNS, ¤t_item, parent_node) + .ok(), + value_ns: self + .resolve(path_str, ValueNS, ¤t_item, parent_node) + .ok() + .and_then(|(res, fragment)| { + // Constructors are picked up in the type namespace. + match res { + Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => None, + _ => Some((res, fragment)) + } + }), + }; + + if candidates.is_empty() { + resolution_failure(cx, &item, path_str, &dox, link_range); // this could just be a normal link continue; } + + let is_unambiguous = candidates.clone().present_items().count() == 1; + if is_unambiguous { + candidates.present_items().next().unwrap() + } else { + ambiguity_error( + cx, + &item, + path_str, + &dox, + link_range, + candidates.map(|candidate| candidate.map(|(res, _)| res)), + ); + continue; + } } - PathKind::Macro => { - if let Some(def) = macro_resolve(cx, path_str) { - (def, None) + Some(MacroNS) => { + if let Some(res) = macro_resolve(cx, path_str) { + (res, None) } else { - resolution_failure(cx, &item.attrs, path_str, &dox, link_range); + resolution_failure(cx, &item, path_str, &dox, link_range); continue } } } }; - if let Def::PrimTy(_) = def { + if let Res::PrimTy(_) = res { item.attrs.links.push((ori_link, None, fragment)); } else { - let id = register_def(cx, def); + let id = register_res(cx, res); item.attrs.links.push((ori_link, Some(id), fragment)); } } if item.is_mod() && !item.attrs.inner_docs { - self.mod_ids.push(item_node_id.unwrap()); + self.mod_ids.push(item_hir_id.unwrap()); } if item.is_mod() { @@ -434,29 +412,39 @@ impl<'a, 'tcx, 'rcx> DocFolder for LinkCollector<'a, 'tcx, 'rcx> { self.fold_item_recur(item) } } + + // FIXME: if we can resolve intra-doc links from other crates, we can use the stock + // `fold_crate`, but until then we should avoid scanning `krate.external_traits` since those + // will never resolve properly + fn fold_crate(&mut self, mut c: Crate) -> Crate { + c.module = c.module.take().and_then(|module| self.fold_item(module)); + + c + } } /// Resolves a string as a macro. -fn macro_resolve(cx: &DocContext<'_, '_, '_>, path_str: &str) -> Option { - use syntax::ext::base::{MacroKind, SyntaxExtension}; +fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option { + use syntax::ext::base::{MacroKind, SyntaxExtensionKind}; let segment = ast::PathSegment::from_ident(Ident::from_str(path_str)); let path = ast::Path { segments: vec![segment], span: DUMMY_SP }; - let mut resolver = cx.resolver.borrow_mut(); - let parent_scope = resolver.dummy_parent_scope(); - if let Ok(def) = resolver.resolve_macro_to_def_inner(&path, MacroKind::Bang, - &parent_scope, false, false) { - if let Def::Macro(_, MacroKind::ProcMacroStub) = def { - // skip proc-macro stubs, they'll cause `get_macro` to crash - } else { - if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) { - return Some(def); + cx.enter_resolver(|resolver| { + let parent_scope = resolver.dummy_parent_scope(); + if let Ok(res) = resolver.resolve_macro_to_res_inner(&path, MacroKind::Bang, + &parent_scope, false, false) { + if let Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) = res { + // skip proc-macro stubs, they'll cause `get_macro` to crash + } else { + if let SyntaxExtensionKind::LegacyBang(..) = resolver.get_macro(res).kind { + return Some(res.map_id(|_| panic!("unexpected id"))); + } } } - } - if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) { - return Some(*def); - } - None + if let Some(res) = resolver.all_macros.get(&Symbol::intern(path_str)) { + return Some(res.map_id(|_| panic!("unexpected id"))); + } + None + }) } /// Reports a resolution failure diagnostic. @@ -465,17 +453,25 @@ fn macro_resolve(cx: &DocContext<'_, '_, '_>, path_str: &str) -> Option { /// documentation attributes themselves. This is a little heavy-handed, so we display the markdown /// line containing the failure as a note as well. fn resolution_failure( - cx: &DocContext<'_, '_, '_>, - attrs: &Attributes, + cx: &DocContext<'_>, + item: &Item, path_str: &str, dox: &str, link_range: Option>, ) { + let hir_id = match cx.as_local_hir_id(item.def_id) { + Some(hir_id) => hir_id, + None => { + // If non-local, no need to check anything. + return; + } + }; + let attrs = &item.attrs; let sp = span_of_attrs(attrs); let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - hir::CRATE_HIR_ID, + hir_id, sp, &format!("`[{}]` cannot be resolved, ignoring it...", path_str), ); @@ -507,104 +503,167 @@ fn resolution_failure( diag.emit(); } -fn ambiguity_error(cx: &DocContext<'_, '_, '_>, attrs: &Attributes, - path_str: &str, - article1: &str, kind1: &str, disambig1: &str, - article2: &str, kind2: &str, disambig2: &str) { +fn ambiguity_error( + cx: &DocContext<'_>, + item: &Item, + path_str: &str, + dox: &str, + link_range: Option>, + candidates: PerNS>, +) { + let hir_id = match cx.as_local_hir_id(item.def_id) { + Some(hir_id) => hir_id, + None => { + // If non-local, no need to check anything. + return; + } + }; + let attrs = &item.attrs; let sp = span_of_attrs(attrs); - cx.sess() - .struct_span_warn(sp, - &format!("`{}` is both {} {} and {} {}", - path_str, article1, kind1, - article2, kind2)) - .help(&format!("try `{}` if you want to select the {}, \ - or `{}` if you want to \ - select the {}", - disambig1, kind1, disambig2, - kind2)) - .emit(); -} -/// Given a def, returns its name and disambiguator -/// for a value namespace. -/// -/// Returns `None` for things which cannot be ambiguous since -/// they exist in both namespaces (structs and modules). -fn value_ns_kind(def: Def, path_str: &str) -> Option<(&'static str, String)> { - match def { - // Structs, variants, and mods exist in both namespaces; skip them. - Def::StructCtor(..) | Def::Mod(..) | Def::Variant(..) | - Def::VariantCtor(..) | Def::SelfCtor(..) - => None, - Def::Fn(..) - => Some(("function", format!("{}()", path_str))), - Def::Method(..) - => Some(("method", format!("{}()", path_str))), - Def::Const(..) - => Some(("const", format!("const@{}", path_str))), - Def::Static(..) - => Some(("static", format!("static@{}", path_str))), - _ => Some(("value", format!("value@{}", path_str))), + let mut msg = format!("`{}` is ", path_str); + + let candidates = [TypeNS, ValueNS, MacroNS].iter().filter_map(|&ns| { + candidates[ns].map(|res| (res, ns)) + }).collect::>(); + match candidates.as_slice() { + [(first_def, _), (second_def, _)] => { + msg += &format!( + "both {} {} and {} {}", + first_def.article(), + first_def.descr(), + second_def.article(), + second_def.descr(), + ); + } + _ => { + let mut candidates = candidates.iter().peekable(); + while let Some((res, _)) = candidates.next() { + if candidates.peek().is_some() { + msg += &format!("{} {}, ", res.article(), res.descr()); + } else { + msg += &format!("and {} {}", res.article(), res.descr()); + } + } + } } -} -/// Given a def, returns its name, the article to be used, and a disambiguator -/// for the type namespace. -fn type_ns_kind(def: Def, path_str: &str) -> (&'static str, &'static str, String) { - let (kind, article) = match def { - // We can still have non-tuple structs. - Def::Struct(..) => ("struct", "a"), - Def::Enum(..) => ("enum", "an"), - Def::Trait(..) => ("trait", "a"), - Def::Union(..) => ("union", "a"), - _ => ("type", "a"), - }; - (kind, article, format!("{}@{}", kind, path_str)) + let mut diag = cx.tcx.struct_span_lint_hir( + lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, + hir_id, + sp, + &msg, + ); + + if let Some(link_range) = link_range { + if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) { + diag.set_span(sp); + diag.span_label(sp, "ambiguous link"); + + for (res, ns) in candidates { + let (action, mut suggestion) = match res { + Res::Def(DefKind::Method, _) | Res::Def(DefKind::Fn, _) => { + ("add parentheses", format!("{}()", path_str)) + } + Res::Def(DefKind::Macro(..), _) => { + ("add an exclamation mark", format!("{}!", path_str)) + } + _ => { + let type_ = match (res, ns) { + (Res::Def(DefKind::Const, _), _) => "const", + (Res::Def(DefKind::Static, _), _) => "static", + (Res::Def(DefKind::Struct, _), _) => "struct", + (Res::Def(DefKind::Enum, _), _) => "enum", + (Res::Def(DefKind::Union, _), _) => "union", + (Res::Def(DefKind::Trait, _), _) => "trait", + (Res::Def(DefKind::Mod, _), _) => "module", + (_, TypeNS) => "type", + (_, ValueNS) => "value", + (_, MacroNS) => "macro", + }; + + // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` + ("prefix with the item type", format!("{}@{}", type_, path_str)) + } + }; + + if dox.bytes().nth(link_range.start) == Some(b'`') { + suggestion = format!("`{}`", suggestion); + } + + diag.span_suggestion( + sp, + &format!("to link to the {}, {}", res.descr(), action), + suggestion, + Applicability::MaybeIncorrect, + ); + } + } else { + // blah blah blah\nblah\nblah [blah] blah blah\nblah blah + // ^ ~~~~ + // | link_range + // last_new_line_offset + let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1); + let line = dox[last_new_line_offset..].lines().next().unwrap_or(""); + + // Print the line containing the `link_range` and manually mark it with '^'s. + diag.note(&format!( + "the link appears in this line:\n\n{line}\n\ + {indicator: , def: Def) -> Result<(Def, Option), ()> { +/// Given an enum variant's res, return the res of its enum and the associated fragment. +fn handle_variant(cx: &DocContext<'_>, res: Res) -> Result<(Res, Option), ()> { use rustc::ty::DefIdTree; - let parent = if let Some(parent) = cx.tcx.parent(def.def_id()) { + let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) { parent } else { return Err(()) }; - let parent_def = Def::Enum(parent); - let variant = cx.tcx.expect_variant_def(def); + let parent_def = Res::Def(DefKind::Enum, parent); + let variant = cx.tcx.expect_variant_res(res); Ok((parent_def, Some(format!("{}.v", variant.ident.name)))) } -const PRIMITIVES: &[(&str, Def)] = &[ - ("u8", Def::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U8))), - ("u16", Def::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U16))), - ("u32", Def::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U32))), - ("u64", Def::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U64))), - ("u128", Def::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U128))), - ("usize", Def::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::Usize))), - ("i8", Def::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I8))), - ("i16", Def::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I16))), - ("i32", Def::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I32))), - ("i64", Def::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I64))), - ("i128", Def::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I128))), - ("isize", Def::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::Isize))), - ("f32", Def::PrimTy(hir::PrimTy::Float(syntax::ast::FloatTy::F32))), - ("f64", Def::PrimTy(hir::PrimTy::Float(syntax::ast::FloatTy::F64))), - ("str", Def::PrimTy(hir::PrimTy::Str)), - ("bool", Def::PrimTy(hir::PrimTy::Bool)), - ("char", Def::PrimTy(hir::PrimTy::Char)), +const PRIMITIVES: &[(&str, Res)] = &[ + ("u8", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U8))), + ("u16", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U16))), + ("u32", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U32))), + ("u64", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U64))), + ("u128", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U128))), + ("usize", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::Usize))), + ("i8", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I8))), + ("i16", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I16))), + ("i32", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I32))), + ("i64", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I64))), + ("i128", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I128))), + ("isize", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::Isize))), + ("f32", Res::PrimTy(hir::PrimTy::Float(syntax::ast::FloatTy::F32))), + ("f64", Res::PrimTy(hir::PrimTy::Float(syntax::ast::FloatTy::F64))), + ("str", Res::PrimTy(hir::PrimTy::Str)), + ("bool", Res::PrimTy(hir::PrimTy::Bool)), + ("char", Res::PrimTy(hir::PrimTy::Char)), ]; -fn is_primitive(path_str: &str, is_val: bool) -> Option { - if is_val { - None - } else { +fn is_primitive(path_str: &str, ns: Namespace) -> Option { + if ns == TypeNS { PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1) + } else { + None } } -fn primitive_impl(cx: &DocContext<'_, '_, '_>, path_str: &str) -> Option { +fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option { let tcx = cx.tcx; match path_str { "u8" => tcx.lang_items().u8_impl(), diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 4c90540871d2e..70cd4b72199bc 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -5,6 +5,7 @@ use super::Pass; use rustc::util::nodemap::FxHashSet; use rustc::hir::def_id::DefId; +use syntax::symbol::sym; pub const COLLECT_TRAIT_IMPLS: Pass = Pass { name: "collect-trait-impls", @@ -12,7 +13,7 @@ pub const COLLECT_TRAIT_IMPLS: Pass = Pass { description: "retrieves trait impls for items in the crate", }; -pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate { +pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { let mut synth = SyntheticImplCollector::new(cx); let mut krate = synth.fold_crate(krate); @@ -67,16 +68,14 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate { if !def_id.is_local() { inline::build_impl(cx, def_id, &mut new_items); - let auto_impls = get_auto_traits_with_def_id(cx, def_id); - let blanket_impls = get_blanket_impls_with_def_id(cx, def_id); - let mut renderinfo = cx.renderinfo.borrow_mut(); + // FIXME(eddyb) is this `doc(hidden)` check needed? + if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) { + let self_ty = cx.tcx.type_of(def_id); + let impls = get_auto_trait_and_blanket_impls(cx, self_ty, def_id); + let mut renderinfo = cx.renderinfo.borrow_mut(); - let new_impls: Vec = auto_impls.into_iter() - .chain(blanket_impls.into_iter()) - .filter(|i| renderinfo.inlined.insert(i.def_id)) - .collect(); - - new_items.extend(new_impls); + new_items.extend(impls.filter(|i| renderinfo.inlined.insert(i.def_id))); + } } } @@ -119,7 +118,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate { // doesn't work with it anyway, so pull them from the HIR map instead for &trait_did in cx.all_traits.iter() { for &impl_node in cx.tcx.hir().trait_impls(trait_did) { - let impl_did = cx.tcx.hir().local_def_id(impl_node); + let impl_did = cx.tcx.hir().local_def_id_from_hir_id(impl_node); inline::build_impl(cx, impl_did, &mut new_items); } } @@ -138,13 +137,13 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate { krate } -struct SyntheticImplCollector<'a, 'tcx: 'a, 'rcx: 'a> { - cx: &'a DocContext<'a, 'tcx, 'rcx>, +struct SyntheticImplCollector<'a, 'tcx> { + cx: &'a DocContext<'tcx>, impls: Vec, } -impl<'a, 'tcx, 'rcx> SyntheticImplCollector<'a, 'tcx, 'rcx> { - fn new(cx: &'a DocContext<'a, 'tcx, 'rcx>) -> Self { +impl<'a, 'tcx> SyntheticImplCollector<'a, 'tcx> { + fn new(cx: &'a DocContext<'tcx>) -> Self { SyntheticImplCollector { cx, impls: Vec::new(), @@ -152,17 +151,16 @@ impl<'a, 'tcx, 'rcx> SyntheticImplCollector<'a, 'tcx, 'rcx> { } } -impl<'a, 'tcx, 'rcx> DocFolder for SyntheticImplCollector<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> { fn fold_item(&mut self, i: Item) -> Option { if i.is_struct() || i.is_enum() || i.is_union() { - if let (Some(node_id), Some(name)) = - (self.cx.tcx.hir().as_local_node_id(i.def_id), i.name.clone()) - { - self.impls.extend(get_auto_traits_with_node_id(self.cx, node_id, name.clone())); - self.impls.extend(get_blanket_impls_with_node_id(self.cx, node_id, name)); - } else { - self.impls.extend(get_auto_traits_with_def_id(self.cx, i.def_id)); - self.impls.extend(get_blanket_impls_with_def_id(self.cx, i.def_id)); + // FIXME(eddyb) is this `doc(hidden)` check needed? + if !self.cx.tcx.get_attrs(i.def_id).lists(sym::doc).has_word(sym::hidden) { + self.impls.extend(get_auto_trait_and_blanket_impls( + self.cx, + self.cx.tcx.type_of(i.def_id), + i.def_id, + )); } } diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index d6f3585a04f33..8fc6b9fdbe6b9 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -1,13 +1,12 @@ //! Contains information about "passes", used to modify crate information during the documentation //! process. -use rustc::hir; use rustc::hir::def_id::DefId; use rustc::lint as lint; use rustc::middle::privacy::AccessLevels; use rustc::util::nodemap::DefIdSet; use std::mem; -use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::{DUMMY_SP, InnerSpan, Span}; use std::ops::Range; use crate::clean::{self, GetDefId, Item}; @@ -45,13 +44,16 @@ pub use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; mod check_code_block_syntax; pub use self::check_code_block_syntax::CHECK_CODE_BLOCK_SYNTAX; +mod calculate_doc_coverage; +pub use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE; + /// A single pass over the cleaned documentation. /// /// Runs in the compiler context, so it has access to types and traits and the like. #[derive(Copy, Clone)] pub struct Pass { pub name: &'static str, - pub pass: fn(clean::Crate, &DocContext<'_, '_, '_>) -> clean::Crate, + pub pass: fn(clean::Crate, &DocContext<'_>) -> clean::Crate, pub description: &'static str, } @@ -67,6 +69,7 @@ pub const PASSES: &'static [Pass] = &[ COLLECT_INTRA_DOC_LINKS, CHECK_CODE_BLOCK_SYNTAX, COLLECT_TRAIT_IMPLS, + CALCULATE_DOC_COVERAGE, ]; /// The list of passes run by default. @@ -94,12 +97,29 @@ pub const DEFAULT_PRIVATE_PASSES: &[&str] = &[ "propagate-doc-cfg", ]; +/// The list of default passes run when `--doc-coverage` is passed to rustdoc. +pub const DEFAULT_COVERAGE_PASSES: &'static [&'static str] = &[ + "collect-trait-impls", + "strip-hidden", + "strip-private", + "calculate-doc-coverage", +]; + +/// The list of default passes run when `--doc-coverage --document-private-items` is passed to +/// rustdoc. +pub const PRIVATE_COVERAGE_PASSES: &'static [&'static str] = &[ + "collect-trait-impls", + "calculate-doc-coverage", +]; + /// A shorthand way to refer to which set of passes to use, based on the presence of /// `--no-defaults` or `--document-private-items`. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum DefaultPassOption { Default, Private, + Coverage, + PrivateCoverage, None, } @@ -108,6 +128,8 @@ pub fn defaults(default_set: DefaultPassOption) -> &'static [&'static str] { match default_set { DefaultPassOption::Default => DEFAULT_PASSES, DefaultPassOption::Private => DEFAULT_PRIVATE_PASSES, + DefaultPassOption::Coverage => DEFAULT_COVERAGE_PASSES, + DefaultPassOption::PrivateCoverage => PRIVATE_COVERAGE_PASSES, DefaultPassOption::None => &[], } } @@ -150,7 +172,7 @@ impl<'a> DocFolder for Stripper<'a> { | clean::ForeignStaticItem(..) | clean::ConstantItem(..) | clean::UnionItem(..) - | clean::AssociatedConstItem(..) + | clean::AssocConstItem(..) | clean::TraitAliasItem(..) | clean::ForeignTypeItem => { if i.def_id.is_local() { @@ -192,7 +214,7 @@ impl<'a> DocFolder for Stripper<'a> { clean::PrimitiveItem(..) => {} // Associated types are never stripped - clean::AssociatedTypeItem(..) => {} + clean::AssocTypeItem(..) => {} // Keywords are never stripped clean::KeywordItem(..) => {} @@ -285,16 +307,19 @@ impl DocFolder for ImportStripper { } } -pub fn look_for_tests<'a, 'tcx: 'a, 'rcx: 'a>( - cx: &'a DocContext<'a, 'tcx, 'rcx>, +pub fn look_for_tests<'tcx>( + cx: &DocContext<'tcx>, dox: &str, item: &Item, check_missing_code: bool, ) { - if cx.as_local_node_id(item.def_id).is_none() { - // If non-local, no need to check anything. - return; - } + let hir_id = match cx.as_local_hir_id(item.def_id) { + Some(hir_id) => hir_id, + None => { + // If non-local, no need to check anything. + return; + } + }; struct Tests { found_tests: usize, @@ -310,24 +335,25 @@ pub fn look_for_tests<'a, 'tcx: 'a, 'rcx: 'a>( found_tests: 0, }; - if find_testable_code(&dox, &mut tests, ErrorCodes::No).is_ok() { - if check_missing_code == true && tests.found_tests == 0 { - let mut diag = cx.tcx.struct_span_lint_hir( - lint::builtin::MISSING_DOC_CODE_EXAMPLES, - hir::CRATE_HIR_ID, - span_of_attrs(&item.attrs), - "Missing code example in this documentation"); - diag.emit(); - } else if check_missing_code == false && - tests.found_tests > 0 && - !cx.renderinfo.borrow().access_levels.is_doc_reachable(item.def_id) { - let mut diag = cx.tcx.struct_span_lint_hir( - lint::builtin::PRIVATE_DOC_TESTS, - hir::CRATE_HIR_ID, - span_of_attrs(&item.attrs), - "Documentation test in private item"); - diag.emit(); - } + find_testable_code(&dox, &mut tests, ErrorCodes::No); + + if check_missing_code == true && tests.found_tests == 0 { + let sp = span_of_attrs(&item.attrs).substitute_dummy(item.source.span()); + let mut diag = cx.tcx.struct_span_lint_hir( + lint::builtin::MISSING_DOC_CODE_EXAMPLES, + hir_id, + sp, + "Missing code example in this documentation"); + diag.emit(); + } else if check_missing_code == false && + tests.found_tests > 0 && + !cx.renderinfo.borrow().access_levels.is_doc_reachable(item.def_id) { + let mut diag = cx.tcx.struct_span_lint_hir( + lint::builtin::PRIVATE_DOC_TESTS, + hir_id, + span_of_attrs(&item.attrs), + "Documentation test in private item"); + diag.emit(); } } @@ -347,7 +373,7 @@ crate fn span_of_attrs(attrs: &clean::Attributes) -> Span { /// attributes are not all sugared doc comments. It's difficult to calculate the correct span in /// that case due to escaping and other source features. crate fn source_span_for_markdown_range( - cx: &DocContext<'_, '_, '_>, + cx: &DocContext<'_>, markdown: &str, md_range: &Range, attrs: &clean::Attributes, @@ -414,10 +440,10 @@ crate fn source_span_for_markdown_range( } } - let sp = span_of_attrs(attrs).from_inner_byte_pos( + let sp = span_of_attrs(attrs).from_inner(InnerSpan::new( md_range.start + start_bytes, md_range.end + start_bytes + end_bytes, - ); + )); Some(sp) } diff --git a/src/librustdoc/passes/private_items_doc_tests.rs b/src/librustdoc/passes/private_items_doc_tests.rs index 1c3977c4f85cd..5560ebed9ae69 100644 --- a/src/librustdoc/passes/private_items_doc_tests.rs +++ b/src/librustdoc/passes/private_items_doc_tests.rs @@ -9,25 +9,25 @@ pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { description: "check private items doc tests", }; -struct PrivateItemDocTestLinter<'a, 'tcx: 'a, 'rcx: 'a> { - cx: &'a DocContext<'a, 'tcx, 'rcx>, +struct PrivateItemDocTestLinter<'a, 'tcx> { + cx: &'a DocContext<'tcx>, } -impl<'a, 'tcx, 'rcx> PrivateItemDocTestLinter<'a, 'tcx, 'rcx> { - fn new(cx: &'a DocContext<'a, 'tcx, 'rcx>) -> Self { +impl<'a, 'tcx> PrivateItemDocTestLinter<'a, 'tcx> { + fn new(cx: &'a DocContext<'tcx>) -> Self { PrivateItemDocTestLinter { cx, } } } -pub fn check_private_items_doc_tests(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate { +pub fn check_private_items_doc_tests(krate: Crate, cx: &DocContext<'_>) -> Crate { let mut coll = PrivateItemDocTestLinter::new(cx); coll.fold_crate(krate) } -impl<'a, 'tcx, 'rcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> { fn fold_item(&mut self, item: Item) -> Option { let cx = self.cx; let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new); diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index aed80b5ba86fd..a71a1e001fc69 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -12,7 +12,7 @@ pub const PROPAGATE_DOC_CFG: Pass = Pass { description: "propagates `#[doc(cfg(...))]` to child items", }; -pub fn propagate_doc_cfg(cr: Crate, _: &DocContext<'_, '_, '_>) -> Crate { +pub fn propagate_doc_cfg(cr: Crate, _: &DocContext<'_>) -> Crate { CfgPropagator { parent_cfg: None }.fold_crate(cr) } diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 330057e53843b..da8977544f64b 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -1,5 +1,6 @@ use rustc::util::nodemap::DefIdSet; use std::mem; +use syntax::symbol::sym; use crate::clean::{self, AttributesExt, NestedAttributesExt}; use crate::clean::Item; @@ -14,7 +15,7 @@ pub const STRIP_HIDDEN: Pass = Pass { }; /// Strip items marked `#[doc(hidden)]` -pub fn strip_hidden(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate { +pub fn strip_hidden(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { let mut retained = DefIdSet::default(); // strip all #[doc(hidden)] items @@ -37,7 +38,7 @@ struct Stripper<'a> { impl<'a> DocFolder for Stripper<'a> { fn fold_item(&mut self, i: Item) -> Option { - if i.attrs.lists("doc").has_word("hidden") { + if i.attrs.lists(sym::doc).has_word(sym::hidden) { debug!("strip_hidden: stripping {} {:?}", i.type_(), i.name); // use a dedicated hidden item for given item type if any match i.inner { diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs index 479f0877bd7d2..516760ade6667 100644 --- a/src/librustdoc/passes/strip_priv_imports.rs +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -9,6 +9,6 @@ pub const STRIP_PRIV_IMPORTS: Pass = Pass { description: "strips all private import statements (`use`, `extern crate`) from a crate", }; -pub fn strip_priv_imports(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate { +pub fn strip_priv_imports(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { ImportStripper.fold_crate(krate) } diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 1ac3a90f38d35..fc742bf74d006 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -14,7 +14,7 @@ pub const STRIP_PRIVATE: Pass = Pass { /// Strip private items from the point of view of a crate or externally from a /// crate, specified by the `xcrate` flag. -pub fn strip_private(mut krate: clean::Crate, cx: &DocContext<'_, '_, '_>) -> clean::Crate { +pub fn strip_private(mut krate: clean::Crate, cx: &DocContext<'_>) -> clean::Crate { // This stripper collects all *retained* nodes. let mut retained = DefIdSet::default(); let access_levels = cx.renderinfo.borrow().access_levels.clone(); diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index b77cf68d7c63f..95e322f70b2ea 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -13,7 +13,7 @@ pub const UNINDENT_COMMENTS: Pass = Pass { description: "removes excess indentation on comments in order for markdown to like it", }; -pub fn unindent_comments(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate { +pub fn unindent_comments(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { CommentCleaner.fold_crate(krate) } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index c3c0875bc7d24..63545ab45bf64 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -1,33 +1,29 @@ -use errors::{self, FatalError}; -use errors::emitter::ColorConfig; use rustc_data_structures::sync::Lrc; -use rustc_lint; -use rustc_driver::{self, driver, Compilation}; -use rustc_driver::driver::phase_2_configure_and_expand; -use rustc_metadata::cstore::CStore; -use rustc_interface::util; +use rustc_interface::interface; use rustc::hir; use rustc::hir::intravisit; -use rustc::session::{self, CompileIncomplete, config}; +use rustc::hir::def_id::LOCAL_CRATE; +use rustc::session::{self, config, DiagnosticOutput}; use rustc::session::config::{OutputType, OutputTypes, Externs, CodegenOptions}; use rustc::session::search_paths::SearchPath; +use rustc::util::common::ErrorReported; use syntax::ast; +use syntax::with_globals; use syntax::source_map::SourceMap; use syntax::edition::Edition; use syntax::feature_gate::UnstableFeatures; -use syntax::with_globals; -use syntax_pos::{BytePos, DUMMY_SP, Pos, Span, FileName}; -use tempfile::Builder as TempFileBuilder; -use testing; - use std::env; use std::io::prelude::*; use std::io; -use std::path::PathBuf; use std::panic::{self, AssertUnwindSafe}; -use std::process::Command; +use std::path::PathBuf; +use std::process::{self, Command}; use std::str; use std::sync::{Arc, Mutex}; +use syntax::symbol::sym; +use syntax_pos::{BytePos, DUMMY_SP, Pos, Span, FileName}; +use tempfile::Builder as TempFileBuilder; +use testing; use crate::clean::Attributes; use crate::config::Options; @@ -44,12 +40,11 @@ pub struct TestOptions { pub attrs: Vec, } -pub fn run(mut options: Options) -> isize { +pub fn run(options: Options) -> i32 { let input = config::Input::File(options.input.clone()); let sessopts = config::Options { - maybe_sysroot: options.maybe_sysroot.clone().or_else( - || Some(env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_path_buf())), + maybe_sysroot: options.maybe_sysroot.clone(), search_paths: options.libs.clone(), crate_types: vec![config::CrateType::Dylib], cg: options.codegen_options.clone(), @@ -63,52 +58,31 @@ pub fn run(mut options: Options) -> isize { edition: options.edition, ..config::Options::default() }; - driver::spawn_thread_pool(sessopts, |sessopts| { - let source_map = Lrc::new(SourceMap::new(sessopts.file_path_mapping())); - let handler = - errors::Handler::with_tty_emitter(ColorConfig::Auto, - true, false, - Some(source_map.clone())); - - let mut sess = session::build_session_( - sessopts, Some(options.input), handler, source_map.clone(), Default::default(), - ); - let codegen_backend = util::get_codegen_backend(&sess); - let cstore = CStore::new(codegen_backend.metadata_loader()); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - - let mut cfg = config::build_configuration(&sess, - config::parse_cfgspecs(options.cfgs.clone())); - util::add_configuration(&mut cfg, &sess, &*codegen_backend); - sess.parse_sess.config = cfg; - - let krate = - match driver::phase_1_parse_input(&driver::CompileController::basic(), &sess, &input) { - Ok(krate) => krate, - Err(mut e) => { - e.emit(); - FatalError.raise(); - } - }; - let driver::ExpansionResult { defs, mut hir_forest, .. } = { - phase_2_configure_and_expand( - &sess, - &cstore, - krate, - None, - "rustdoc-test", - None, - |_| Ok(()), - ).expect("phase_2_configure_and_expand aborted in rustdoc!") - }; - let crate_name = options.crate_name.unwrap_or_else(|| { - ::rustc_codegen_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input) - }); - let mut opts = scrape_test_config(hir_forest.krate()); + let config = interface::Config { + opts: sessopts, + crate_cfg: config::parse_cfgspecs(options.cfgs.clone()), + input, + input_path: None, + output_file: None, + output_dir: None, + file_loader: None, + diagnostic_output: DiagnosticOutput::Default, + stderr: None, + crate_name: options.crate_name.clone(), + lint_caps: Default::default(), + }; + + let mut test_args = options.test_args.clone(); + let display_warnings = options.display_warnings; + + let tests = interface::run_compiler(config, |compiler| -> Result<_, ErrorReported> { + let lower_to_hir = compiler.lower_to_hir()?; + + let mut opts = scrape_test_config(lower_to_hir.peek().0.borrow().krate()); opts.display_warnings |= options.display_warnings; let mut collector = Collector::new( - crate_name, + compiler.crate_name()?.peek().to_string(), options.cfgs, options.libs, options.codegen_options, @@ -116,34 +90,40 @@ pub fn run(mut options: Options) -> isize { false, opts, options.maybe_sysroot, - Some(source_map), + Some(compiler.source_map().clone()), None, options.linker, options.edition, options.persist_doctests, ); - { - let map = hir::map::map_crate(&sess, &cstore, &mut hir_forest, &defs); - let krate = map.krate(); + let mut global_ctxt = compiler.global_ctxt()?.take(); + global_ctxt.enter(|tcx| { + let krate = tcx.hir().krate(); let mut hir_collector = HirCollector { - sess: &sess, + sess: compiler.session(), collector: &mut collector, - map: &map, - codes: ErrorCodes::from(sess.opts.unstable_features.is_nightly_build()), + map: tcx.hir(), + codes: ErrorCodes::from(compiler.session().opts + .unstable_features.is_nightly_build()), }; hir_collector.visit_testable("".to_string(), &krate.attrs, |this| { intravisit::walk_crate(this, krate); }); - } + }); - options.test_args.insert(0, "rustdoctest".to_string()); + Ok(collector.tests) + }).expect("compiler aborted in rustdoc!"); - testing::test_main(&options.test_args, - collector.tests.into_iter().collect(), - testing::Options::new().display_output(options.display_warnings)); - 0 - }) + test_args.insert(0, "rustdoctest".to_string()); + + testing::test_main( + &test_args, + tests, + testing::Options::new().display_output(display_warnings) + ); + + 0 } // Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade. @@ -157,17 +137,17 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { }; let test_attrs: Vec<_> = krate.attrs.iter() - .filter(|a| a.check_name("doc")) + .filter(|a| a.check_name(sym::doc)) .flat_map(|a| a.meta_item_list().unwrap_or_else(Vec::new)) - .filter(|a| a.check_name("test")) + .filter(|a| a.check_name(sym::test)) .collect(); let attrs = test_attrs.iter().flat_map(|a| a.meta_item_list().unwrap_or(&[])); for attr in attrs { - if attr.check_name("no_crate_inject") { + if attr.check_name(sym::no_crate_inject) { opts.no_crate_inject = true; } - if attr.check_name("attr") { + if attr.check_name(sym::attr) { if let Some(l) = attr.meta_item_list() { for item in l { opts.attrs.push(pprust::meta_list_item_to_string(item)); @@ -179,16 +159,57 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { opts } -fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, - cfgs: Vec, libs: Vec, - cg: CodegenOptions, externs: Externs, - should_panic: bool, no_run: bool, as_test_harness: bool, - compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, - maybe_sysroot: Option, linker: Option, edition: Edition, - persist_doctests: Option) { - // The test harness wants its own `main` and top-level functions, so - // never wrap the test in `fn main() { ... }`. - let (test, line_offset) = make_test(test, Some(cratename), as_test_harness, opts); +/// Documentation test failure modes. +enum TestFailure { + /// The test failed to compile. + CompileError, + /// The test is marked `compile_fail` but compiled successfully. + UnexpectedCompilePass, + /// The test failed to compile (as expected) but the compiler output did not contain all + /// expected error codes. + MissingErrorCodes(Vec), + /// The test binary was unable to be executed. + ExecutionError(io::Error), + /// The test binary exited with a non-zero exit code. + /// + /// This typically means an assertion in the test failed or another form of panic occurred. + ExecutionFailure(process::Output), + /// The test is marked `should_panic` but the test binary executed successfully. + UnexpectedRunPass, +} + +fn run_test( + test: &str, + cratename: &str, + filename: &FileName, + line: usize, + cfgs: Vec, + libs: Vec, + cg: CodegenOptions, + externs: Externs, + should_panic: bool, + no_run: bool, + as_test_harness: bool, + compile_fail: bool, + mut error_codes: Vec, + opts: &TestOptions, + maybe_sysroot: Option, + linker: Option, + edition: Edition, + persist_doctests: Option, +) -> Result<(), TestFailure> { + let (test, line_offset) = match panic::catch_unwind(|| { + make_test(test, Some(cratename), as_test_harness, opts, edition) + }) { + Ok((test, line_offset)) => (test, line_offset), + Err(cause) if cause.is::() => { + // If the parser used by `make_test` panicked due to a fatal error, pass the test code + // through unchanged. The error will be reported during compilation. + (test.to_owned(), 0) + }, + Err(cause) => panic::resume_unwind(cause), + }; + // FIXME(#44940): if doctests ever support path remapping, then this filename // needs to be the result of `SourceMap::span_to_unmapped_path`. let path = match filename { @@ -203,8 +224,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, let outputs = OutputTypes::new(&[(OutputType::Exe, None)]); let sessopts = config::Options { - maybe_sysroot: maybe_sysroot.or_else( - || Some(env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_path_buf())), + maybe_sysroot, search_paths: libs, crate_types: vec![config::CrateType::Executable], output_types: outputs, @@ -239,16 +259,18 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, } fn flush(&mut self) -> io::Result<()> { Ok(()) } } - struct Bomb(Arc>>, Box); + struct Bomb(Arc>>, Option>); impl Drop for Bomb { fn drop(&mut self) { - let _ = self.1.write_all(&self.0.lock().unwrap()); + let mut old = self.1.take().unwrap(); + let _ = old.write_all(&self.0.lock().unwrap()); + io::set_panic(Some(old)); } } let data = Arc::new(Mutex::new(Vec::new())); let old = io::set_panic(Some(box Sink(data.clone()))); - let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout())); + let _bomb = Bomb(data.clone(), Some(old.unwrap_or(box io::stdout()))); enum DirState { Temp(tempfile::TempDir), @@ -264,125 +286,108 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, } } - let (outdir, compile_result) = driver::spawn_thread_pool(sessopts, |sessopts| { - let source_map = Lrc::new(SourceMap::new(sessopts.file_path_mapping())); - let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()), - Some(source_map.clone()), - false, - false); - - // Compile the code - let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter); - - let mut sess = session::build_session_( - sessopts, None, diagnostic_handler, source_map, Default::default(), - ); - let codegen_backend = util::get_codegen_backend(&sess); - let cstore = CStore::new(codegen_backend.metadata_loader()); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - - let outdir = Mutex::new( - if let Some(mut path) = persist_doctests { - path.push(format!("{}_{}", - filename - .to_string() - .rsplit('/') - .next() - .unwrap() - .replace(".", "_"), - line) - ); - std::fs::create_dir_all(&path) - .expect("Couldn't create directory for doctest executables"); - - DirState::Perm(path) - } else { - DirState::Temp(TempFileBuilder::new() - .prefix("rustdoctest") - .tempdir() - .expect("rustdoc needs a tempdir")) - } + let outdir = if let Some(mut path) = persist_doctests { + path.push(format!("{}_{}", + filename + .to_string() + .rsplit('/') + .next() + .unwrap() + .replace(".", "_"), + line) ); - let mut control = driver::CompileController::basic(); - - let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); - util::add_configuration(&mut cfg, &sess, &*codegen_backend); - sess.parse_sess.config = cfg; + std::fs::create_dir_all(&path) + .expect("Couldn't create directory for doctest executables"); - let out = Some(outdir.lock().unwrap().path().join("rust_out")); - - if no_run { - control.after_analysis.stop = Compilation::Stop; - } - - let res = panic::catch_unwind(AssertUnwindSafe(|| { - driver::compile_input( - codegen_backend, - &sess, - &cstore, - &None, - &input, - &None, - &out, - None, - &control - ) - })); - - let compile_result = match res { - Ok(Ok(())) | Ok(Err(CompileIncomplete::Stopped)) => Ok(()), - Err(_) | Ok(Err(CompileIncomplete::Errored(_))) => Err(()) - }; + DirState::Perm(path) + } else { + DirState::Temp(TempFileBuilder::new() + .prefix("rustdoctest") + .tempdir() + .expect("rustdoc needs a tempdir")) + }; + let output_file = outdir.path().join("rust_out"); + + let config = interface::Config { + opts: sessopts, + crate_cfg: config::parse_cfgspecs(cfgs), + input, + input_path: None, + output_file: Some(output_file.clone()), + output_dir: None, + file_loader: None, + diagnostic_output: DiagnosticOutput::Raw(box Sink(data.clone())), + stderr: Some(data.clone()), + crate_name: None, + lint_caps: Default::default(), + }; - (outdir, compile_result) - }); + let compile_result = panic::catch_unwind(AssertUnwindSafe(|| { + interface::run_compiler(config, |compiler| { + if no_run { + compiler.global_ctxt().and_then(|global_ctxt| global_ctxt.take().enter(|tcx| { + tcx.analysis(LOCAL_CRATE) + })).ok(); + } else { + compiler.compile().ok(); + }; + compiler.session().compile_status() + }) + })).map_err(|_| ()).and_then(|s| s.map_err(|_| ())); match (compile_result, compile_fail) { (Ok(()), true) => { - panic!("test compiled while it wasn't supposed to") + return Err(TestFailure::UnexpectedCompilePass); } (Ok(()), false) => {} - (Err(()), true) => { - if error_codes.len() > 0 { + (Err(_), true) => { + if !error_codes.is_empty() { let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap(); error_codes.retain(|err| !out.contains(err)); + + if !error_codes.is_empty() { + return Err(TestFailure::MissingErrorCodes(error_codes)); + } } } - (Err(()), false) => { - panic!("couldn't compile the test") + (Err(_), false) => { + return Err(TestFailure::CompileError); } } - if error_codes.len() > 0 { - panic!("Some expected error codes were not found: {:?}", error_codes); + if no_run { + return Ok(()); } - if no_run { return } - // Run the code! - let mut cmd = Command::new(&outdir.lock().unwrap().path().join("rust_out")); + let mut cmd = Command::new(output_file); + match cmd.output() { - Err(e) => panic!("couldn't run the test: {}{}", e, - if e.kind() == io::ErrorKind::PermissionDenied { - " - maybe your tempdir is mounted with noexec?" - } else { "" }), + Err(e) => return Err(TestFailure::ExecutionError(e)), Ok(out) => { if should_panic && out.status.success() { - panic!("test executable succeeded when it should have failed"); + return Err(TestFailure::UnexpectedRunPass); } else if !should_panic && !out.status.success() { - panic!("test executable failed:\n{}\n{}\n", - str::from_utf8(&out.stdout).unwrap_or(""), - str::from_utf8(&out.stderr).unwrap_or("")); + return Err(TestFailure::ExecutionFailure(out)); } } } + + Ok(()) } -/// Makes the test file. Also returns the number of lines before the code begins +/// Transforms a test into code that can be compiled into a Rust binary, and returns the number of +/// lines before the test code begins. +/// +/// # Panics +/// +/// This function uses the compiler's parser internally. The parser will panic if it encounters a +/// fatal error while parsing the test. pub fn make_test(s: &str, cratename: Option<&str>, dont_insert_main: bool, - opts: &TestOptions) + opts: &TestOptions, + edition: Edition) -> (String, usize) { let (crate_attrs, everything_else, crates) = partition_source(s); let everything_else = everything_else.trim(); @@ -411,9 +416,8 @@ pub fn make_test(s: &str, // Uses libsyntax to parse the doctest and find if there's a main fn and the extern // crate already is included. - let (already_has_main, already_has_extern_crate, found_macro) = crate::syntax::with_globals(|| { - use crate::syntax::{ast, parse::{self, ParseSess}, source_map::FilePathMapping}; - use crate::syntax_pos::FileName; + let (already_has_main, already_has_extern_crate, found_macro) = with_globals(edition, || { + use crate::syntax::{parse::{self, ParseSess}, source_map::FilePathMapping}; use errors::emitter::EmitterWriter; use errors::Handler; @@ -423,8 +427,9 @@ pub fn make_test(s: &str, // Any errors in parsing should also appear when the doctest is compiled for real, so just // send all the errors that libsyntax emits directly into a `Sink` instead of stderr. let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let emitter = EmitterWriter::new(box io::sink(), None, false, false); - let handler = Handler::with_emitter(false, false, box emitter); + let emitter = EmitterWriter::new(box io::sink(), None, false, false, false); + // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser + let handler = Handler::with_emitter(false, None, box emitter); let sess = ParseSess::with_span_handler(handler, cm); let mut found_main = false; @@ -728,41 +733,90 @@ impl Tester for Collector { debug!("Creating test {}: {}", name, test); self.tests.push(testing::TestDescAndFn { desc: testing::TestDesc { - name: testing::DynTestName(name.clone()), + name: testing::DynTestName(name), ignore: config.ignore, // compiler failures are test failures should_panic: testing::ShouldPanic::No, allow_fail: config.allow_fail, }, testfn: testing::DynTestFn(box move || { - let panic = io::set_panic(None); - let print = io::set_print(None); - match { - rustc_driver::in_named_rustc_thread(name, move || with_globals(move || { - io::set_panic(panic); - io::set_print(print); - run_test(&test, - &cratename, - &filename, - line, - cfgs, - libs, - cg, - externs, - config.should_panic, - config.no_run, - config.test_harness, - config.compile_fail, - config.error_codes, - &opts, - maybe_sysroot, - linker, - edition, - persist_doctests) - })) - } { - Ok(()) => (), - Err(err) => panic::resume_unwind(err), + let res = run_test( + &test, + &cratename, + &filename, + line, + cfgs, + libs, + cg, + externs, + config.should_panic, + config.no_run, + config.test_harness, + config.compile_fail, + config.error_codes, + &opts, + maybe_sysroot, + linker, + edition, + persist_doctests + ); + + if let Err(err) = res { + match err { + TestFailure::CompileError => { + eprint!("Couldn't compile the test."); + } + TestFailure::UnexpectedCompilePass => { + eprint!("Test compiled successfully, but it's marked `compile_fail`."); + } + TestFailure::UnexpectedRunPass => { + eprint!("Test executable succeeded, but it's marked `should_panic`."); + } + TestFailure::MissingErrorCodes(codes) => { + eprint!("Some expected error codes were not found: {:?}", codes); + } + TestFailure::ExecutionError(err) => { + eprint!("Couldn't run the test: {}", err); + if err.kind() == io::ErrorKind::PermissionDenied { + eprint!(" - maybe your tempdir is mounted with noexec?"); + } + } + TestFailure::ExecutionFailure(out) => { + let reason = if let Some(code) = out.status.code() { + format!("exit code {}", code) + } else { + String::from("terminated by signal") + }; + + eprintln!("Test executable failed ({}).", reason); + + // FIXME(#12309): An unfortunate side-effect of capturing the test + // executable's output is that the relative ordering between the test's + // stdout and stderr is lost. However, this is better than the + // alternative: if the test executable inherited the parent's I/O + // handles the output wouldn't be captured at all, even on success. + // + // The ordering could be preserved if the test process' stderr was + // redirected to stdout, but that functionality does not exist in the + // standard library, so it may not be portable enough. + let stdout = str::from_utf8(&out.stdout).unwrap_or_default(); + let stderr = str::from_utf8(&out.stderr).unwrap_or_default(); + + if !stdout.is_empty() || !stderr.is_empty() { + eprintln!(); + + if !stdout.is_empty() { + eprintln!("stdout:\n{}", stdout); + } + + if !stderr.is_empty() { + eprintln!("stderr:\n{}", stderr); + } + } + } + } + + panic::resume_unwind(box ()); } }), }); @@ -817,7 +871,7 @@ impl Tester for Collector { } } -struct HirCollector<'a, 'hir: 'a> { +struct HirCollector<'a, 'hir> { sess: &'a session::Session, collector: &'a mut Collector, map: &'a hir::map::Map<'hir>, @@ -847,11 +901,7 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { // anything else, this will combine them for us. if let Some(doc) = attrs.collapsed_doc_value() { self.collector.set_position(attrs.span.unwrap_or(DUMMY_SP)); - let res = markdown::find_testable_code(&doc, self.collector, self.codes); - if let Err(err) = res { - self.sess.diagnostic().span_warn(attrs.span.unwrap_or(DUMMY_SP), - &err.to_string()); - } + markdown::find_testable_code(&doc, self.collector, self.codes); } nested(self); @@ -918,303 +968,4 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> { } #[cfg(test)] -mod tests { - use super::{TestOptions, make_test}; - - #[test] - fn make_test_basic() { - //basic use: wraps with `fn main`, adds `#![allow(unused)]` - let opts = TestOptions::default(); - let input = -"assert_eq!(2+2, 4);"; - let expected = -"#![allow(unused)] -fn main() { -assert_eq!(2+2, 4); -}".to_string(); - let output = make_test(input, None, false, &opts); - assert_eq!(output, (expected, 2)); - } - - #[test] - fn make_test_crate_name_no_use() { - // If you give a crate name but *don't* use it within the test, it won't bother inserting - // the `extern crate` statement. - let opts = TestOptions::default(); - let input = -"assert_eq!(2+2, 4);"; - let expected = -"#![allow(unused)] -fn main() { -assert_eq!(2+2, 4); -}".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); - assert_eq!(output, (expected, 2)); - } - - #[test] - fn make_test_crate_name() { - // If you give a crate name and use it within the test, it will insert an `extern crate` - // statement before `fn main`. - let opts = TestOptions::default(); - let input = -"use asdf::qwop; -assert_eq!(2+2, 4);"; - let expected = -"#![allow(unused)] -extern crate asdf; -fn main() { -use asdf::qwop; -assert_eq!(2+2, 4); -}".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); - assert_eq!(output, (expected, 3)); - } - - #[test] - fn make_test_no_crate_inject() { - // Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip - // adding it anyway. - let opts = TestOptions { - no_crate_inject: true, - display_warnings: false, - attrs: vec![], - }; - let input = -"use asdf::qwop; -assert_eq!(2+2, 4);"; - let expected = -"#![allow(unused)] -fn main() { -use asdf::qwop; -assert_eq!(2+2, 4); -}".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); - assert_eq!(output, (expected, 2)); - } - - #[test] - fn make_test_ignore_std() { - // Even if you include a crate name, and use it in the doctest, we still won't include an - // `extern crate` statement if the crate is "std" -- that's included already by the - // compiler! - let opts = TestOptions::default(); - let input = -"use std::*; -assert_eq!(2+2, 4);"; - let expected = -"#![allow(unused)] -fn main() { -use std::*; -assert_eq!(2+2, 4); -}".to_string(); - let output = make_test(input, Some("std"), false, &opts); - assert_eq!(output, (expected, 2)); - } - - #[test] - fn make_test_manual_extern_crate() { - // When you manually include an `extern crate` statement in your doctest, `make_test` - // assumes you've included one for your own crate too. - let opts = TestOptions::default(); - let input = -"extern crate asdf; -use asdf::qwop; -assert_eq!(2+2, 4);"; - let expected = -"#![allow(unused)] -extern crate asdf; -fn main() { -use asdf::qwop; -assert_eq!(2+2, 4); -}".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); - assert_eq!(output, (expected, 2)); - } - - #[test] - fn make_test_manual_extern_crate_with_macro_use() { - let opts = TestOptions::default(); - let input = -"#[macro_use] extern crate asdf; -use asdf::qwop; -assert_eq!(2+2, 4);"; - let expected = -"#![allow(unused)] -#[macro_use] extern crate asdf; -fn main() { -use asdf::qwop; -assert_eq!(2+2, 4); -}".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); - assert_eq!(output, (expected, 2)); - } - - #[test] - fn make_test_opts_attrs() { - // If you supplied some doctest attributes with `#![doc(test(attr(...)))]`, it will use - // those instead of the stock `#![allow(unused)]`. - let mut opts = TestOptions::default(); - opts.attrs.push("feature(sick_rad)".to_string()); - let input = -"use asdf::qwop; -assert_eq!(2+2, 4);"; - let expected = -"#![feature(sick_rad)] -extern crate asdf; -fn main() { -use asdf::qwop; -assert_eq!(2+2, 4); -}".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); - assert_eq!(output, (expected, 3)); - - // Adding more will also bump the returned line offset. - opts.attrs.push("feature(hella_dope)".to_string()); - let expected = -"#![feature(sick_rad)] -#![feature(hella_dope)] -extern crate asdf; -fn main() { -use asdf::qwop; -assert_eq!(2+2, 4); -}".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); - assert_eq!(output, (expected, 4)); - } - - #[test] - fn make_test_crate_attrs() { - // Including inner attributes in your doctest will apply them to the whole "crate", pasting - // them outside the generated main function. - let opts = TestOptions::default(); - let input = -"#![feature(sick_rad)] -assert_eq!(2+2, 4);"; - let expected = -"#![allow(unused)] -#![feature(sick_rad)] -fn main() { -assert_eq!(2+2, 4); -}".to_string(); - let output = make_test(input, None, false, &opts); - assert_eq!(output, (expected, 2)); - } - - #[test] - fn make_test_with_main() { - // Including your own `fn main` wrapper lets the test use it verbatim. - let opts = TestOptions::default(); - let input = -"fn main() { - assert_eq!(2+2, 4); -}"; - let expected = -"#![allow(unused)] -fn main() { - assert_eq!(2+2, 4); -}".to_string(); - let output = make_test(input, None, false, &opts); - assert_eq!(output, (expected, 1)); - } - - #[test] - fn make_test_fake_main() { - // ... but putting it in a comment will still provide a wrapper. - let opts = TestOptions::default(); - let input = -"//Ceci n'est pas une `fn main` -assert_eq!(2+2, 4);"; - let expected = -"#![allow(unused)] -//Ceci n'est pas une `fn main` -fn main() { -assert_eq!(2+2, 4); -}".to_string(); - let output = make_test(input, None, false, &opts); - assert_eq!(output, (expected, 2)); - } - - #[test] - fn make_test_dont_insert_main() { - // Even with that, if you set `dont_insert_main`, it won't create the `fn main` wrapper. - let opts = TestOptions::default(); - let input = -"//Ceci n'est pas une `fn main` -assert_eq!(2+2, 4);"; - let expected = -"#![allow(unused)] -//Ceci n'est pas une `fn main` -assert_eq!(2+2, 4);".to_string(); - let output = make_test(input, None, true, &opts); - assert_eq!(output, (expected, 1)); - } - - #[test] - fn make_test_display_warnings() { - // If the user is asking to display doctest warnings, suppress the default `allow(unused)`. - let mut opts = TestOptions::default(); - opts.display_warnings = true; - let input = -"assert_eq!(2+2, 4);"; - let expected = -"fn main() { -assert_eq!(2+2, 4); -}".to_string(); - let output = make_test(input, None, false, &opts); - assert_eq!(output, (expected, 1)); - } - - #[test] - fn make_test_issues_21299_33731() { - let opts = TestOptions::default(); - - let input = -"// fn main -assert_eq!(2+2, 4);"; - - let expected = -"#![allow(unused)] -// fn main -fn main() { -assert_eq!(2+2, 4); -}".to_string(); - - let output = make_test(input, None, false, &opts); - assert_eq!(output, (expected, 2)); - - let input = -"extern crate hella_qwop; -assert_eq!(asdf::foo, 4);"; - - let expected = -"#![allow(unused)] -extern crate hella_qwop; -extern crate asdf; -fn main() { -assert_eq!(asdf::foo, 4); -}".to_string(); - - let output = make_test(input, Some("asdf"), false, &opts); - assert_eq!(output, (expected, 3)); - } - - #[test] - fn make_test_main_in_macro() { - let opts = TestOptions::default(); - let input = -"#[macro_use] extern crate my_crate; -test_wrapper! { - fn main() {} -}"; - let expected = -"#![allow(unused)] -#[macro_use] extern crate my_crate; -test_wrapper! { - fn main() {} -}".to_string(); - - let output = make_test(input, Some("my_crate"), false, &opts); - assert_eq!(output, (expected, 1)); - } -} +mod tests; diff --git a/src/librustdoc/test/tests.rs b/src/librustdoc/test/tests.rs new file mode 100644 index 0000000000000..d4d558b7cd78c --- /dev/null +++ b/src/librustdoc/test/tests.rs @@ -0,0 +1,299 @@ +use super::{TestOptions, make_test}; +use syntax::edition::DEFAULT_EDITION; + +#[test] +fn make_test_basic() { + //basic use: wraps with `fn main`, adds `#![allow(unused)]` + let opts = TestOptions::default(); + let input = +"assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +fn main() { +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 2)); +} + +#[test] +fn make_test_crate_name_no_use() { + // If you give a crate name but *don't* use it within the test, it won't bother inserting + // the `extern crate` statement. + let opts = TestOptions::default(); + let input = +"assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +fn main() { +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 2)); +} + +#[test] +fn make_test_crate_name() { + // If you give a crate name and use it within the test, it will insert an `extern crate` + // statement before `fn main`. + let opts = TestOptions::default(); + let input = +"use asdf::qwop; +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +extern crate asdf; +fn main() { +use asdf::qwop; +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 3)); +} + +#[test] +fn make_test_no_crate_inject() { + // Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip + // adding it anyway. + let opts = TestOptions { + no_crate_inject: true, + display_warnings: false, + attrs: vec![], + }; + let input = +"use asdf::qwop; +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +fn main() { +use asdf::qwop; +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 2)); +} + +#[test] +fn make_test_ignore_std() { + // Even if you include a crate name, and use it in the doctest, we still won't include an + // `extern crate` statement if the crate is "std" -- that's included already by the + // compiler! + let opts = TestOptions::default(); + let input = +"use std::*; +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +fn main() { +use std::*; +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 2)); +} + +#[test] +fn make_test_manual_extern_crate() { + // When you manually include an `extern crate` statement in your doctest, `make_test` + // assumes you've included one for your own crate too. + let opts = TestOptions::default(); + let input = +"extern crate asdf; +use asdf::qwop; +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +extern crate asdf; +fn main() { +use asdf::qwop; +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 2)); +} + +#[test] +fn make_test_manual_extern_crate_with_macro_use() { + let opts = TestOptions::default(); + let input = +"#[macro_use] extern crate asdf; +use asdf::qwop; +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +#[macro_use] extern crate asdf; +fn main() { +use asdf::qwop; +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 2)); +} + +#[test] +fn make_test_opts_attrs() { + // If you supplied some doctest attributes with `#![doc(test(attr(...)))]`, it will use + // those instead of the stock `#![allow(unused)]`. + let mut opts = TestOptions::default(); + opts.attrs.push("feature(sick_rad)".to_string()); + let input = +"use asdf::qwop; +assert_eq!(2+2, 4);"; + let expected = +"#![feature(sick_rad)] +extern crate asdf; +fn main() { +use asdf::qwop; +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 3)); + + // Adding more will also bump the returned line offset. + opts.attrs.push("feature(hella_dope)".to_string()); + let expected = +"#![feature(sick_rad)] +#![feature(hella_dope)] +extern crate asdf; +fn main() { +use asdf::qwop; +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 4)); +} + +#[test] +fn make_test_crate_attrs() { + // Including inner attributes in your doctest will apply them to the whole "crate", pasting + // them outside the generated main function. + let opts = TestOptions::default(); + let input = +"#![feature(sick_rad)] +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +#![feature(sick_rad)] +fn main() { +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 2)); +} + +#[test] +fn make_test_with_main() { + // Including your own `fn main` wrapper lets the test use it verbatim. + let opts = TestOptions::default(); + let input = +"fn main() { + assert_eq!(2+2, 4); +}"; + let expected = +"#![allow(unused)] +fn main() { + assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 1)); +} + +#[test] +fn make_test_fake_main() { + // ... but putting it in a comment will still provide a wrapper. + let opts = TestOptions::default(); + let input = +"//Ceci n'est pas une `fn main` +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +//Ceci n'est pas une `fn main` +fn main() { +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 2)); +} + +#[test] +fn make_test_dont_insert_main() { + // Even with that, if you set `dont_insert_main`, it won't create the `fn main` wrapper. + let opts = TestOptions::default(); + let input = +"//Ceci n'est pas une `fn main` +assert_eq!(2+2, 4);"; + let expected = +"#![allow(unused)] +//Ceci n'est pas une `fn main` +assert_eq!(2+2, 4);".to_string(); + let output = make_test(input, None, true, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 1)); +} + +#[test] +fn make_test_display_warnings() { + // If the user is asking to display doctest warnings, suppress the default `allow(unused)`. + let mut opts = TestOptions::default(); + opts.display_warnings = true; + let input = +"assert_eq!(2+2, 4);"; + let expected = +"fn main() { +assert_eq!(2+2, 4); +}".to_string(); + let output = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 1)); +} + +#[test] +fn make_test_issues_21299_33731() { + let opts = TestOptions::default(); + + let input = +"// fn main +assert_eq!(2+2, 4);"; + + let expected = +"#![allow(unused)] +// fn main +fn main() { +assert_eq!(2+2, 4); +}".to_string(); + + let output = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 2)); + + let input = +"extern crate hella_qwop; +assert_eq!(asdf::foo, 4);"; + + let expected = +"#![allow(unused)] +extern crate hella_qwop; +extern crate asdf; +fn main() { +assert_eq!(asdf::foo, 4); +}".to_string(); + + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 3)); +} + +#[test] +fn make_test_main_in_macro() { + let opts = TestOptions::default(); + let input = +"#[macro_use] extern crate my_crate; +test_wrapper! { + fn main() {} +}"; + let expected = +"#![allow(unused)] +#[macro_use] extern crate my_crate; +test_wrapper! { + fn main() {} +}".to_string(); + + let output = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION); + assert_eq!(output, (expected, 1)); +} diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs index 7a0ccf6975f8c..7220a05df47e6 100644 --- a/src/librustdoc/theme.rs +++ b/src/librustdoc/theme.rs @@ -103,16 +103,16 @@ fn is_line_comment(pos: usize, v: &[u8], events: &[Events]) -> bool { if let Some(&Events::StartComment(_)) = events.last() { return false; } - pos + 1 < v.len() && v[pos + 1] == b'/' + v[pos + 1] == b'/' } fn load_css_events(v: &[u8]) -> Vec { let mut pos = 0; let mut events = Vec::with_capacity(100); - while pos < v.len() - 1 { + while pos + 1 < v.len() { match v[pos] { - b'/' if pos + 1 < v.len() && v[pos + 1] == b'*' => { + b'/' if v[pos + 1] == b'*' => { events.push(Events::StartComment(pos)); pos += 1; } @@ -123,7 +123,7 @@ fn load_css_events(v: &[u8]) -> Vec { b'\n' if previous_is_line_comment(&events) => { events.push(Events::EndComment(pos)); } - b'*' if pos + 1 < v.len() && v[pos + 1] == b'/' => { + b'*' if v[pos + 1] == b'/' => { events.push(Events::EndComment(pos + 2)); pos += 1; } @@ -264,9 +264,11 @@ pub fn get_differences(against: &CssPath, other: &CssPath, v: &mut Vec) } } -pub fn test_theme_against>(f: &P, against: &CssPath, diag: &Handler) - -> (bool, Vec) -{ +pub fn test_theme_against>( + f: &P, + against: &CssPath, + diag: &Handler, +) -> (bool, Vec) { let data = try_something!(fs::read(f), diag, (false, vec![])); let paths = load_css_paths(&data); let mut ret = vec![]; @@ -366,4 +368,16 @@ a { get_differences(&other, &against, &mut ret); assert_eq!(ret, vec![" Missing \"c\" rule".to_owned()]); } + + #[test] + fn check_empty_css() { + let events = load_css_events(&[]); + assert_eq!(events.len(), 0); + } + + #[test] + fn check_invalid_css() { + let events = load_css_events(b"*"); + assert_eq!(events.len(), 0); + } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index b791bfc11e01a..781e62c3b274c 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -2,7 +2,7 @@ //! usable for `clean`. use rustc::hir::{self, Node}; -use rustc::hir::def::Def; +use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::middle::privacy::AccessLevel; use rustc::util::nodemap::{FxHashSet, FxHashMap}; @@ -10,6 +10,7 @@ use syntax::ast; use syntax::attr; use syntax::ext::base::MacroKind; use syntax::source_map::Spanned; +use syntax::symbol::sym; use syntax_pos::{self, Span}; use std::mem; @@ -27,27 +28,25 @@ use crate::doctree::*; // Also, is there some reason that this doesn't use the 'visit' // framework from syntax?. -pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a> { - pub module: Module, - pub attrs: hir::HirVec, - pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>, - view_item_stack: FxHashSet, +pub struct RustdocVisitor<'a, 'tcx> { + pub module: Option>, + pub cx: &'a core::DocContext<'tcx>, + view_item_stack: FxHashSet, inlining: bool, /// Are the current module and all of its parents public? inside_public_path: bool, exact_paths: Option>>, } -impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { pub fn new( - cx: &'a core::DocContext<'a, 'tcx, 'rcx> - ) -> RustdocVisitor<'a, 'tcx, 'rcx> { + cx: &'a core::DocContext<'tcx> + ) -> RustdocVisitor<'a, 'tcx> { // If the root is re-exported, terminate all recursion. let mut stack = FxHashSet::default(); - stack.insert(ast::CRATE_NODE_ID); + stack.insert(hir::CRATE_HIR_ID); RustdocVisitor { - module: Module::new(None), - attrs: hir::HirVec::new(), + module: None, cx, view_item_stack: stack, inlining: false, @@ -76,99 +75,99 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { .and_then(|def_id| self.cx.tcx.lookup_deprecation(def_id)) } - pub fn visit(&mut self, krate: &hir::Crate) { - self.attrs = krate.attrs.clone(); - - self.module = self.visit_mod_contents(krate.span, - krate.attrs.clone(), - Spanned { span: syntax_pos::DUMMY_SP, + pub fn visit(&mut self, krate: &'tcx hir::Crate) { + let mut module = self.visit_mod_contents(krate.span, + &krate.attrs, + &Spanned { span: syntax_pos::DUMMY_SP, node: hir::VisibilityKind::Public }, hir::CRATE_HIR_ID, &krate.module, None); // Attach the crate's exported macros to the top-level module: - let macro_exports: Vec<_> = - krate.exported_macros.iter().map(|def| self.visit_local_macro(def, None)).collect(); - self.module.macros.extend(macro_exports); - self.module.is_crate = true; + module.macros.extend( + krate.exported_macros.iter().map(|def| self.visit_local_macro(def, None)), + ); + module.is_crate = true; + self.module = Some(module); self.cx.renderinfo.borrow_mut().exact_paths = self.exact_paths.take().unwrap(); } - pub fn visit_variant_data(&mut self, item: &hir::Item, - name: ast::Name, sd: &hir::VariantData, - generics: &hir::Generics) -> Struct { + pub fn visit_variant_data(&mut self, item: &'tcx hir::Item, + name: ast::Name, sd: &'tcx hir::VariantData, + generics: &'tcx hir::Generics) -> Struct<'tcx> { debug!("Visiting struct"); let struct_type = struct_type_from_def(&*sd); Struct { - id: item.id, + id: item.hir_id, struct_type, name, - vis: item.vis.clone(), + vis: &item.vis, stab: self.stability(item.hir_id), depr: self.deprecation(item.hir_id), - attrs: item.attrs.clone(), - generics: generics.clone(), - fields: sd.fields().iter().cloned().collect(), + attrs: &item.attrs, + generics, + fields: sd.fields(), whence: item.span } } - pub fn visit_union_data(&mut self, item: &hir::Item, - name: ast::Name, sd: &hir::VariantData, - generics: &hir::Generics) -> Union { + pub fn visit_union_data(&mut self, item: &'tcx hir::Item, + name: ast::Name, sd: &'tcx hir::VariantData, + generics: &'tcx hir::Generics) -> Union<'tcx> { debug!("Visiting union"); let struct_type = struct_type_from_def(&*sd); Union { - id: item.id, + id: item.hir_id, struct_type, name, - vis: item.vis.clone(), + vis: &item.vis, stab: self.stability(item.hir_id), depr: self.deprecation(item.hir_id), - attrs: item.attrs.clone(), - generics: generics.clone(), - fields: sd.fields().iter().cloned().collect(), + attrs: &item.attrs, + generics, + fields: sd.fields(), whence: item.span } } - pub fn visit_enum_def(&mut self, it: &hir::Item, - name: ast::Name, def: &hir::EnumDef, - params: &hir::Generics) -> Enum { + pub fn visit_enum_def(&mut self, it: &'tcx hir::Item, + name: ast::Name, def: &'tcx hir::EnumDef, + generics: &'tcx hir::Generics) -> Enum<'tcx> { debug!("Visiting enum"); Enum { name, variants: def.variants.iter().map(|v| Variant { name: v.node.ident.name, - attrs: v.node.attrs.clone(), - stab: self.stability(v.node.data.hir_id()), - depr: self.deprecation(v.node.data.hir_id()), - def: v.node.data.clone(), + id: v.node.id, + attrs: &v.node.attrs, + stab: self.stability(v.node.id), + depr: self.deprecation(v.node.id), + def: &v.node.data, whence: v.span, }).collect(), - vis: it.vis.clone(), + vis: &it.vis, stab: self.stability(it.hir_id), depr: self.deprecation(it.hir_id), - generics: params.clone(), - attrs: it.attrs.clone(), - id: it.id, + generics, + attrs: &it.attrs, + id: it.hir_id, whence: it.span, } } - pub fn visit_fn(&mut self, om: &mut Module, item: &hir::Item, - name: ast::Name, fd: &hir::FnDecl, + pub fn visit_fn(&mut self, om: &mut Module<'tcx>, item: &'tcx hir::Item, + name: ast::Name, decl: &'tcx hir::FnDecl, header: hir::FnHeader, - gen: &hir::Generics, + generics: &'tcx hir::Generics, body: hir::BodyId) { debug!("Visiting fn"); let macro_kind = item.attrs.iter().filter_map(|a| { - if a.check_name("proc_macro") { + if a.check_name(sym::proc_macro) { Some(MacroKind::Bang) - } else if a.check_name("proc_macro_derive") { + } else if a.check_name(sym::proc_macro_derive) { Some(MacroKind::Derive) - } else if a.check_name("proc_macro_attribute") { + } else if a.check_name(sym::proc_macro_attribute) { Some(MacroKind::Attr) } else { None @@ -177,24 +176,25 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { match macro_kind { Some(kind) => { let name = if kind == MacroKind::Derive { - item.attrs.lists("proc_macro_derive") - .filter_map(|mi| mi.name()) + item.attrs.lists(sym::proc_macro_derive) + .filter_map(|mi| mi.ident()) .next() .expect("proc-macro derives require a name") + .name } else { name }; let mut helpers = Vec::new(); - for mi in item.attrs.lists("proc_macro_derive") { - if !mi.check_name("attributes") { + for mi in item.attrs.lists(sym::proc_macro_derive) { + if !mi.check_name(sym::attributes) { continue; } if let Some(list) = mi.meta_item_list() { for inner_mi in list { - if let Some(name) = inner_mi.name() { - helpers.push(name); + if let Some(ident) = inner_mi.ident() { + helpers.push(ident.name); } } } @@ -202,10 +202,10 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { om.proc_macros.push(ProcMacro { name, - id: item.id, + id: item.hir_id, kind, helpers, - attrs: item.attrs.clone(), + attrs: &item.attrs, whence: item.span, stab: self.stability(item.hir_id), depr: self.deprecation(item.hir_id), @@ -213,15 +213,15 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { } None => { om.fns.push(Function { - id: item.id, - vis: item.vis.clone(), + id: item.hir_id, + vis: &item.vis, stab: self.stability(item.hir_id), depr: self.deprecation(item.hir_id), - attrs: item.attrs.clone(), - decl: fd.clone(), + attrs: &item.attrs, + decl, name, whence: item.span, - generics: gen.clone(), + generics, header, body, }); @@ -229,15 +229,13 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { } } - pub fn visit_mod_contents(&mut self, span: Span, attrs: hir::HirVec, - vis: hir::Visibility, id: hir::HirId, - m: &hir::Mod, - name: Option) -> Module { - let mut om = Module::new(name); + pub fn visit_mod_contents(&mut self, span: Span, attrs: &'tcx hir::HirVec, + vis: &'tcx hir::Visibility, id: hir::HirId, + m: &'tcx hir::Mod, + name: Option) -> Module<'tcx> { + let mut om = Module::new(name, attrs, vis); om.where_outer = span; om.where_inner = m.inner; - om.attrs = attrs; - om.vis = vis.clone(); om.stab = self.stability(id); om.depr = self.deprecation(id); om.id = self.cx.tcx.hir().hir_to_node_id(id); @@ -262,30 +260,31 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { /// /// Returns `true` if the target has been inlined. fn maybe_inline_local(&mut self, - id: ast::NodeId, - def: Def, + id: hir::HirId, + res: Res, renamed: Option, glob: bool, - om: &mut Module, + om: &mut Module<'tcx>, please_inline: bool) -> bool { - fn inherits_doc_hidden(cx: &core::DocContext<'_, '_, '_>, mut node: ast::NodeId) -> bool { + fn inherits_doc_hidden(cx: &core::DocContext<'_>, mut node: hir::HirId) -> bool { while let Some(id) = cx.tcx.hir().get_enclosing_scope(node) { node = id; - if cx.tcx.hir().attrs(node).lists("doc").has_word("hidden") { + if cx.tcx.hir().attrs(node) + .lists(sym::doc).has_word(sym::hidden) { return true; } - if node == ast::CRATE_NODE_ID { + if node == hir::CRATE_HIR_ID { break; } } false } - debug!("maybe_inline_local def: {:?}", def); + debug!("maybe_inline_local res: {:?}", res); let tcx = self.cx.tcx; - let def_did = if let Some(did) = def.opt_def_id() { + let res_did = if let Some(did) = res.opt_def_id() { did } else { return false; @@ -293,29 +292,29 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { let use_attrs = tcx.hir().attrs(id); // Don't inline `doc(hidden)` imports so they can be stripped at a later stage. - let is_no_inline = use_attrs.lists("doc").has_word("no_inline") || - use_attrs.lists("doc").has_word("hidden"); + let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline) || + use_attrs.lists(sym::doc).has_word(sym::hidden); // For cross-crate impl inlining we need to know whether items are // reachable in documentation -- a previously nonreachable item can be // made reachable by cross-crate inlining which we're checking here. // (this is done here because we need to know this upfront). - if !def_did.is_local() && !is_no_inline { - let attrs = clean::inline::load_attrs(self.cx, def_did); - let self_is_hidden = attrs.lists("doc").has_word("hidden"); - match def { - Def::Trait(did) | - Def::Struct(did) | - Def::Union(did) | - Def::Enum(did) | - Def::ForeignTy(did) | - Def::TyAlias(did) if !self_is_hidden => { + if !res_did.is_local() && !is_no_inline { + let attrs = clean::inline::load_attrs(self.cx, res_did); + let self_is_hidden = attrs.lists(sym::doc).has_word(sym::hidden); + match res { + Res::Def(DefKind::Trait, did) | + Res::Def(DefKind::Struct, did) | + Res::Def(DefKind::Union, did) | + Res::Def(DefKind::Enum, did) | + Res::Def(DefKind::ForeignTy, did) | + Res::Def(DefKind::TyAlias, did) if !self_is_hidden => { self.cx.renderinfo .borrow_mut() .access_levels.map .insert(did, AccessLevel::Public); }, - Def::Mod(did) => if !self_is_hidden { + Res::Def(DefKind::Mod, did) => if !self_is_hidden { crate::visit_lib::LibEmbargoVisitor::new(self.cx).visit_mod(did); }, _ => {}, @@ -324,21 +323,21 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { return false } - let def_node_id = match tcx.hir().as_local_node_id(def_did) { + let res_hir_id = match tcx.hir().as_local_hir_id(res_did) { Some(n) => n, None => return false }; - let is_private = !self.cx.renderinfo.borrow().access_levels.is_public(def_did); - let is_hidden = inherits_doc_hidden(self.cx, def_node_id); + let is_private = !self.cx.renderinfo.borrow().access_levels.is_public(res_did); + let is_hidden = inherits_doc_hidden(self.cx, res_hir_id); // Only inline if requested or if the item would otherwise be stripped. if (!please_inline && !is_private && !is_hidden) || is_no_inline { return false } - if !self.view_item_stack.insert(def_node_id) { return false } + if !self.view_item_stack.insert(res_hir_id) { return false } - let ret = match tcx.hir().get(def_node_id) { + let ret = match tcx.hir().get(res_hir_id) { Node::Item(&hir::Item { node: hir::ItemKind::Mod(ref m), .. }) if glob => { let prev = mem::replace(&mut self.inlining, true); for i in &m.item_ids { @@ -355,14 +354,9 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { true } Node::ForeignItem(it) if !glob => { - // Generate a fresh `extern {}` block if we want to inline a foreign item. - om.foreigns.push(hir::ForeignMod { - abi: tcx.hir().get_foreign_abi(it.id), - items: vec![hir::ForeignItem { - ident: renamed.unwrap_or(it.ident), - .. it.clone() - }].into(), - }); + let prev = mem::replace(&mut self.inlining, true); + self.visit_foreign_item(it, renamed, om); + self.inlining = prev; true } Node::MacroDef(def) if !glob => { @@ -371,44 +365,38 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { } _ => false, }; - self.view_item_stack.remove(&def_node_id); + self.view_item_stack.remove(&res_hir_id); ret } - pub fn visit_item(&mut self, item: &hir::Item, - renamed: Option, om: &mut Module) { + pub fn visit_item(&mut self, item: &'tcx hir::Item, + renamed: Option, om: &mut Module<'tcx>) { debug!("Visiting item {:?}", item); let ident = renamed.unwrap_or(item.ident); if item.vis.node.is_pub() { - let def_id = self.cx.tcx.hir().local_def_id(item.id); + let def_id = self.cx.tcx.hir().local_def_id_from_hir_id(item.hir_id); self.store_path(def_id); } match item.node { hir::ItemKind::ForeignMod(ref fm) => { - // If inlining we only want to include public functions. - om.foreigns.push(if self.inlining { - hir::ForeignMod { - abi: fm.abi, - items: fm.items.iter().filter(|i| i.vis.node.is_pub()).cloned().collect(), - } - } else { - fm.clone() - }); + for item in &fm.items { + self.visit_foreign_item(item, None, om); + } } // If we're inlining, skip private items. _ if self.inlining && !item.vis.node.is_pub() => {} hir::ItemKind::GlobalAsm(..) => {} hir::ItemKind::ExternCrate(orig_name) => { - let def_id = self.cx.tcx.hir().local_def_id(item.id); + let def_id = self.cx.tcx.hir().local_def_id_from_hir_id(item.hir_id); om.extern_crates.push(ExternCrate { cnum: self.cx.tcx.extern_mod_stmt_cnum(def_id) .unwrap_or(LOCAL_CRATE), name: ident.name, path: orig_name.map(|x|x.to_string()), - vis: item.vis.clone(), - attrs: item.attrs.clone(), + vis: &item.vis, + attrs: &item.attrs, whence: item.span, }) } @@ -418,9 +406,10 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { // Struct and variant constructors and proc macro stubs always show up alongside // their definitions, we've already processed them so just discard these. - match path.def { - Def::StructCtor(..) | Def::VariantCtor(..) | Def::SelfCtor(..) | - Def::Macro(_, MacroKind::ProcMacroStub) => return, + match path.res { + Res::Def(DefKind::Ctor(..), _) + | Res::SelfCtor(..) + | Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) => return, _ => {} } @@ -429,15 +418,15 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { if item.vis.node.is_pub() && self.inside_public_path { let please_inline = item.attrs.iter().any(|item| { match item.meta_item_list() { - Some(ref list) if item.check_name("doc") => { - list.iter().any(|i| i.check_name("inline")) + Some(ref list) if item.check_name(sym::doc) => { + list.iter().any(|i| i.check_name(sym::inline)) } _ => false, } }); let ident = if is_glob { None } else { Some(ident) }; - if self.maybe_inline_local(item.id, - path.def, + if self.maybe_inline_local(item.hir_id, + path.res, ident, is_glob, om, @@ -448,18 +437,18 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { om.imports.push(Import { name: ident.name, - id: item.id, - vis: item.vis.clone(), - attrs: item.attrs.clone(), - path: (**path).clone(), + id: item.hir_id, + vis: &item.vis, + attrs: &item.attrs, + path, glob: is_glob, whence: item.span, }); } hir::ItemKind::Mod(ref m) => { om.mods.push(self.visit_mod_contents(item.span, - item.attrs.clone(), - item.vis.clone(), + &item.attrs, + &item.vis, item.hir_id, m, Some(ident.name))); @@ -474,13 +463,13 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { self.visit_fn(om, item, ident.name, &**fd, header, gen, body), hir::ItemKind::Ty(ref ty, ref gen) => { let t = Typedef { - ty: ty.clone(), - gen: gen.clone(), + ty, + gen, name: ident.name, - id: item.id, - attrs: item.attrs.clone(), + id: item.hir_id, + attrs: &item.attrs, whence: item.span, - vis: item.vis.clone(), + vis: &item.vis, stab: self.stability(item.hir_id), depr: self.deprecation(item.hir_id), }; @@ -488,75 +477,75 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { }, hir::ItemKind::Existential(ref exist_ty) => { let t = Existential { - exist_ty: exist_ty.clone(), + exist_ty, name: ident.name, - id: item.id, - attrs: item.attrs.clone(), + id: item.hir_id, + attrs: &item.attrs, whence: item.span, - vis: item.vis.clone(), + vis: &item.vis, stab: self.stability(item.hir_id), depr: self.deprecation(item.hir_id), }; om.existentials.push(t); }, - hir::ItemKind::Static(ref ty, ref mut_, ref exp) => { + hir::ItemKind::Static(ref type_, mutability, expr) => { let s = Static { - type_: ty.clone(), - mutability: mut_.clone(), - expr: exp.clone(), - id: item.id, + type_, + mutability, + expr, + id: item.hir_id, name: ident.name, - attrs: item.attrs.clone(), + attrs: &item.attrs, whence: item.span, - vis: item.vis.clone(), + vis: &item.vis, stab: self.stability(item.hir_id), depr: self.deprecation(item.hir_id), }; om.statics.push(s); }, - hir::ItemKind::Const(ref ty, ref exp) => { + hir::ItemKind::Const(ref type_, expr) => { let s = Constant { - type_: ty.clone(), - expr: exp.clone(), - id: item.id, + type_, + expr, + id: item.hir_id, name: ident.name, - attrs: item.attrs.clone(), + attrs: &item.attrs, whence: item.span, - vis: item.vis.clone(), + vis: &item.vis, stab: self.stability(item.hir_id), depr: self.deprecation(item.hir_id), }; om.constants.push(s); }, - hir::ItemKind::Trait(is_auto, unsafety, ref gen, ref b, ref item_ids) => { + hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => { let items = item_ids.iter() - .map(|ti| self.cx.tcx.hir().trait_item(ti.id).clone()) + .map(|ti| self.cx.tcx.hir().trait_item(ti.id)) .collect(); let t = Trait { is_auto, unsafety, name: ident.name, items, - generics: gen.clone(), - bounds: b.iter().cloned().collect(), - id: item.id, - attrs: item.attrs.clone(), + generics, + bounds, + id: item.hir_id, + attrs: &item.attrs, whence: item.span, - vis: item.vis.clone(), + vis: &item.vis, stab: self.stability(item.hir_id), depr: self.deprecation(item.hir_id), }; om.traits.push(t); }, - hir::ItemKind::TraitAlias(ref gen, ref b) => { + hir::ItemKind::TraitAlias(ref generics, ref bounds) => { let t = TraitAlias { name: ident.name, - generics: gen.clone(), - bounds: b.iter().cloned().collect(), - id: item.id, - attrs: item.attrs.clone(), + generics, + bounds, + id: item.hir_id, + attrs: &item.attrs, whence: item.span, - vis: item.vis.clone(), + vis: &item.vis, stab: self.stability(item.hir_id), depr: self.deprecation(item.hir_id), }; @@ -566,28 +555,28 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { hir::ItemKind::Impl(unsafety, polarity, defaultness, - ref gen, - ref tr, - ref ty, + ref generics, + ref trait_, + ref for_, ref item_ids) => { // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick // them up regardless of where they're located. - if !self.inlining && tr.is_none() { + if !self.inlining && trait_.is_none() { let items = item_ids.iter() - .map(|ii| self.cx.tcx.hir().impl_item(ii.id).clone()) + .map(|ii| self.cx.tcx.hir().impl_item(ii.id)) .collect(); let i = Impl { unsafety, polarity, defaultness, - generics: gen.clone(), - trait_: tr.clone(), - for_: ty.clone(), + generics, + trait_, + for_, items, - attrs: item.attrs.clone(), - id: item.id, + attrs: &item.attrs, + id: item.hir_id, whence: item.span, - vis: item.vis.clone(), + vis: &item.vis, stab: self.stability(item.hir_id), depr: self.deprecation(item.hir_id), }; @@ -597,12 +586,31 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { } } + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem, + renamed: Option, om: &mut Module<'tcx>) { + // If inlining we only want to include public functions. + if self.inlining && !item.vis.node.is_pub() { + return; + } + + om.foreigns.push(ForeignItem { + id: item.hir_id, + name: renamed.unwrap_or(item.ident).name, + kind: &item.node, + vis: &item.vis, + stab: self.stability(item.hir_id), + depr: self.deprecation(item.hir_id), + attrs: &item.attrs, + whence: item.span + }); + } + // Convert each `exported_macro` into a doc item. fn visit_local_macro( &self, - def: &hir::MacroDef, + def: &'tcx hir::MacroDef, renamed: Option - ) -> Macro { + ) -> Macro<'tcx> { debug!("visit_local_macro: {}", def.name); let tts = def.body.trees().collect::>(); // Extract the spans of all matchers. They represent the "interface" of the macro. @@ -611,7 +619,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { Macro { def_id: self.cx.tcx.hir().local_def_id_from_hir_id(def.hir_id), - attrs: def.attrs.clone(), + attrs: &def.attrs, name: renamed.unwrap_or(def.name), whence: def.span, matchers, diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index f538c58c213ee..2547e3a06e9ef 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -1,8 +1,9 @@ use rustc::middle::privacy::{AccessLevels, AccessLevel}; -use rustc::hir::def::Def; +use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::ty::Visibility; use rustc::util::nodemap::FxHashSet; +use syntax::symbol::sym; use std::cell::RefMut; @@ -12,8 +13,8 @@ use crate::clean::{AttributesExt, NestedAttributesExt}; /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes /// specific rustdoc annotations into account (i.e., `doc(hidden)`) -pub struct LibEmbargoVisitor<'a, 'tcx: 'a, 'rcx: 'a> { - cx: &'a crate::core::DocContext<'a, 'tcx, 'rcx>, +pub struct LibEmbargoVisitor<'a, 'tcx> { + cx: &'a crate::core::DocContext<'tcx>, // Accessibility levels for reachable nodes access_levels: RefMut<'a, AccessLevels>, // Previous accessibility level, None means unreachable @@ -22,10 +23,10 @@ pub struct LibEmbargoVisitor<'a, 'tcx: 'a, 'rcx: 'a> { visited_mods: FxHashSet, } -impl<'a, 'tcx, 'rcx> LibEmbargoVisitor<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { pub fn new( - cx: &'a crate::core::DocContext<'a, 'tcx, 'rcx> - ) -> LibEmbargoVisitor<'a, 'tcx, 'rcx> { + cx: &'a crate::core::DocContext<'tcx> + ) -> LibEmbargoVisitor<'a, 'tcx> { LibEmbargoVisitor { cx, access_levels: RefMut::map(cx.renderinfo.borrow_mut(), |ri| &mut ri.access_levels), @@ -42,7 +43,7 @@ impl<'a, 'tcx, 'rcx> LibEmbargoVisitor<'a, 'tcx, 'rcx> { // Updates node level and returns the updated level fn update(&mut self, did: DefId, level: Option) -> Option { - let is_hidden = self.cx.tcx.get_attrs(did).lists("doc").has_word("hidden"); + let is_hidden = self.cx.tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden); let old_level = self.access_levels.map.get(&did).cloned(); // Accessibility levels can only grow @@ -60,17 +61,17 @@ impl<'a, 'tcx, 'rcx> LibEmbargoVisitor<'a, 'tcx, 'rcx> { } for item in self.cx.tcx.item_children(def_id).iter() { - if let Some(def_id) = item.def.opt_def_id() { + if let Some(def_id) = item.res.opt_def_id() { if self.cx.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index) || item.vis == Visibility::Public { - self.visit_item(item.def); + self.visit_item(item.res); } } } } - fn visit_item(&mut self, def: Def) { - let def_id = def.def_id(); + fn visit_item(&mut self, res: Res) { + let def_id = res.def_id(); let vis = self.cx.tcx.visibility(def_id); let inherited_item_level = if vis == Visibility::Public { self.prev_level @@ -80,7 +81,7 @@ impl<'a, 'tcx, 'rcx> LibEmbargoVisitor<'a, 'tcx, 'rcx> { let item_level = self.update(def_id, inherited_item_level); - if let Def::Mod(..) = def { + if let Res::Def(DefKind::Mod, _) = res { let orig_level = self.prev_level; self.prev_level = item_level; diff --git a/src/libserialize/Cargo.toml b/src/libserialize/Cargo.toml index 949af0e2b9746..fa31a68a75b72 100644 --- a/src/libserialize/Cargo.toml +++ b/src/libserialize/Cargo.toml @@ -10,4 +10,5 @@ path = "lib.rs" crate-type = ["dylib", "rlib"] [dependencies] +indexmap = "1" smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index c0a8fa9d0016d..80aeecb84d72b 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -217,6 +217,75 @@ impl Decodable for HashSet } } +impl Encodable for indexmap::IndexMap + where K: Encodable + Hash + Eq, + V: Encodable, + S: BuildHasher, +{ + fn encode(&self, e: &mut E) -> Result<(), E::Error> { + e.emit_map(self.len(), |e| { + let mut i = 0; + for (key, val) in self { + e.emit_map_elt_key(i, |e| key.encode(e))?; + e.emit_map_elt_val(i, |e| val.encode(e))?; + i += 1; + } + Ok(()) + }) + } +} + +impl Decodable for indexmap::IndexMap + where K: Decodable + Hash + Eq, + V: Decodable, + S: BuildHasher + Default, +{ + fn decode(d: &mut D) -> Result, D::Error> { + d.read_map(|d, len| { + let state = Default::default(); + let mut map = indexmap::IndexMap::with_capacity_and_hasher(len, state); + for i in 0..len { + let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?; + let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?; + map.insert(key, val); + } + Ok(map) + }) + } +} + +impl Encodable for indexmap::IndexSet + where T: Encodable + Hash + Eq, + S: BuildHasher, +{ + fn encode(&self, s: &mut E) -> Result<(), E::Error> { + s.emit_seq(self.len(), |s| { + let mut i = 0; + for e in self { + s.emit_seq_elt(i, |s| e.encode(s))?; + i += 1; + } + Ok(()) + }) + } +} + +impl Decodable for indexmap::IndexSet + where T: Decodable + Hash + Eq, + S: BuildHasher + Default, +{ + fn decode(d: &mut D) -> Result, D::Error> { + d.read_seq(|d, len| { + let state = Default::default(); + let mut set = indexmap::IndexSet::with_capacity_and_hasher(len, state); + for i in 0..len { + set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?); + } + Ok(set) + }) + } +} + impl Encodable for Rc<[T]> { fn encode(&self, s: &mut E) -> Result<(), E::Error> { s.emit_seq(self.len(), |s| { diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs index 8a7927e42c9c3..95d92f311ed3c 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -143,79 +143,4 @@ impl FromHex for str { } #[cfg(test)] -mod tests { - extern crate test; - use test::Bencher; - use crate::hex::{FromHex, ToHex}; - - #[test] - pub fn test_to_hex() { - assert_eq!("foobar".as_bytes().to_hex(), "666f6f626172"); - } - - #[test] - pub fn test_from_hex_okay() { - assert_eq!("666f6f626172".from_hex().unwrap(), - b"foobar"); - assert_eq!("666F6F626172".from_hex().unwrap(), - b"foobar"); - } - - #[test] - pub fn test_from_hex_odd_len() { - assert!("666".from_hex().is_err()); - assert!("66 6".from_hex().is_err()); - } - - #[test] - pub fn test_from_hex_invalid_char() { - assert!("66y6".from_hex().is_err()); - } - - #[test] - pub fn test_from_hex_ignores_whitespace() { - assert_eq!("666f 6f6\r\n26172 ".from_hex().unwrap(), - b"foobar"); - } - - #[test] - pub fn test_to_hex_all_bytes() { - for i in 0..256 { - assert_eq!([i as u8].to_hex(), format!("{:02x}", i as usize)); - } - } - - #[test] - pub fn test_from_hex_all_bytes() { - for i in 0..256 { - let ii: &[u8] = &[i as u8]; - assert_eq!(format!("{:02x}", i as usize).from_hex() - .unwrap(), - ii); - assert_eq!(format!("{:02X}", i as usize).from_hex() - .unwrap(), - ii); - } - } - - #[bench] - pub fn bench_to_hex(b: &mut Bencher) { - let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ - ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; - b.iter(|| { - s.as_bytes().to_hex(); - }); - b.bytes = s.len() as u64; - } - - #[bench] - pub fn bench_from_hex(b: &mut Bencher) { - let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ - ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; - let sb = s.as_bytes().to_hex(); - b.iter(|| { - sb.from_hex().unwrap(); - }); - b.bytes = sb.len() as u64; - } -} +mod tests; diff --git a/src/libserialize/hex/tests.rs b/src/libserialize/hex/tests.rs new file mode 100644 index 0000000000000..471912c11d06f --- /dev/null +++ b/src/libserialize/hex/tests.rs @@ -0,0 +1,74 @@ +extern crate test; +use test::Bencher; +use crate::hex::{FromHex, ToHex}; + +#[test] +pub fn test_to_hex() { + assert_eq!("foobar".as_bytes().to_hex(), "666f6f626172"); +} + +#[test] +pub fn test_from_hex_okay() { + assert_eq!("666f6f626172".from_hex().unwrap(), + b"foobar"); + assert_eq!("666F6F626172".from_hex().unwrap(), + b"foobar"); +} + +#[test] +pub fn test_from_hex_odd_len() { + assert!("666".from_hex().is_err()); + assert!("66 6".from_hex().is_err()); +} + +#[test] +pub fn test_from_hex_invalid_char() { + assert!("66y6".from_hex().is_err()); +} + +#[test] +pub fn test_from_hex_ignores_whitespace() { + assert_eq!("666f 6f6\r\n26172 ".from_hex().unwrap(), + b"foobar"); +} + +#[test] +pub fn test_to_hex_all_bytes() { + for i in 0..256 { + assert_eq!([i as u8].to_hex(), format!("{:02x}", i as usize)); + } +} + +#[test] +pub fn test_from_hex_all_bytes() { + for i in 0..256 { + let ii: &[u8] = &[i as u8]; + assert_eq!(format!("{:02x}", i as usize).from_hex() + .unwrap(), + ii); + assert_eq!(format!("{:02X}", i as usize).from_hex() + .unwrap(), + ii); + } +} + +#[bench] +pub fn bench_to_hex(b: &mut Bencher) { + let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ + ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; + b.iter(|| { + s.as_bytes().to_hex(); + }); + b.bytes = s.len() as u64; +} + +#[bench] +pub fn bench_from_hex(b: &mut Bencher) { + let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ + ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; + let sb = s.as_bytes().to_hex(); + b.iter(|| { + sb.from_hex().unwrap(); + }); + b.bytes = sb.len() as u64; +} diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index a4fd288451205..a7e7c09f9ae44 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -461,7 +461,7 @@ impl<'a> Encoder<'a> { /// Creates a new JSON encoder whose output will be written to the writer /// specified. pub fn new(writer: &'a mut dyn fmt::Write) -> Encoder<'a> { - Encoder { writer: writer, is_emitting_map_key: false, } + Encoder { writer, is_emitting_map_key: false, } } } @@ -513,7 +513,7 @@ impl<'a> crate::Encoder for Encoder<'a> { emit_enquoted_if_mapkey!(self, fmt_number_or_null(v)) } fn emit_f32(&mut self, v: f32) -> EncodeResult { - self.emit_f64(v as f64) + self.emit_f64(f64::from(v)) } fn emit_char(&mut self, v: char) -> EncodeResult { @@ -763,7 +763,7 @@ impl<'a> crate::Encoder for PrettyEncoder<'a> { emit_enquoted_if_mapkey!(self, fmt_number_or_null(v)) } fn emit_f32(&mut self, v: f32) -> EncodeResult { - self.emit_f64(v as f64) + self.emit_f64(f64::from(v)) } fn emit_char(&mut self, v: char) -> EncodeResult { @@ -1698,12 +1698,12 @@ impl> Parser { if n2 < 0xDC00 || n2 > 0xDFFF { return self.error(LoneLeadingSurrogateInHexEscape) } - let c = (((n1 - 0xD800) as u32) << 10 | - (n2 - 0xDC00) as u32) + 0x1_0000; + let c = (u32::from(n1 - 0xD800) << 10 | + u32::from(n2 - 0xDC00)) + 0x1_0000; res.push(char::from_u32(c).unwrap()); } - n => match char::from_u32(n as u32) { + n => match char::from_u32(u32::from(n)) { Some(c) => res.push(c), None => return self.error(InvalidUnicodeCodePoint), }, @@ -2405,7 +2405,7 @@ impl ToJson for Json { } impl ToJson for f32 { - fn to_json(&self) -> Json { (*self as f64).to_json() } + fn to_json(&self) -> Json { f64::from(*self).to_json() } } impl ToJson for f64 { @@ -2502,7 +2502,7 @@ impl ToJson for Option { } } -struct FormatShim<'a, 'b: 'a> { +struct FormatShim<'a, 'b> { inner: &'a mut fmt::Formatter<'b>, } @@ -2582,139 +2582,4 @@ impl FromStr for Json { } #[cfg(test)] -mod tests { - // Benchmarks and tests that require private items - - extern crate test; - use test::Bencher; - use super::{from_str, Parser, StackElement, Stack}; - use std::string; - - #[test] - fn test_stack() { - let mut stack = Stack::new(); - - assert!(stack.is_empty()); - assert!(stack.is_empty()); - assert!(!stack.last_is_index()); - - stack.push_index(0); - stack.bump_index(); - - assert!(stack.len() == 1); - assert!(stack.is_equal_to(&[StackElement::Index(1)])); - assert!(stack.starts_with(&[StackElement::Index(1)])); - assert!(stack.ends_with(&[StackElement::Index(1)])); - assert!(stack.last_is_index()); - assert!(stack.get(0) == StackElement::Index(1)); - - stack.push_key("foo".to_string()); - - assert!(stack.len() == 2); - assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.starts_with(&[StackElement::Index(1)])); - assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.ends_with(&[StackElement::Key("foo")])); - assert!(!stack.last_is_index()); - assert!(stack.get(0) == StackElement::Index(1)); - assert!(stack.get(1) == StackElement::Key("foo")); - - stack.push_key("bar".to_string()); - - assert!(stack.len() == 3); - assert!(stack.is_equal_to(&[StackElement::Index(1), - StackElement::Key("foo"), - StackElement::Key("bar")])); - assert!(stack.starts_with(&[StackElement::Index(1)])); - assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.starts_with(&[StackElement::Index(1), - StackElement::Key("foo"), - StackElement::Key("bar")])); - assert!(stack.ends_with(&[StackElement::Key("bar")])); - assert!(stack.ends_with(&[StackElement::Key("foo"), StackElement::Key("bar")])); - assert!(stack.ends_with(&[StackElement::Index(1), - StackElement::Key("foo"), - StackElement::Key("bar")])); - assert!(!stack.last_is_index()); - assert!(stack.get(0) == StackElement::Index(1)); - assert!(stack.get(1) == StackElement::Key("foo")); - assert!(stack.get(2) == StackElement::Key("bar")); - - stack.pop(); - - assert!(stack.len() == 2); - assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.starts_with(&[StackElement::Index(1)])); - assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.ends_with(&[StackElement::Key("foo")])); - assert!(!stack.last_is_index()); - assert!(stack.get(0) == StackElement::Index(1)); - assert!(stack.get(1) == StackElement::Key("foo")); - } - - #[bench] - fn bench_streaming_small(b: &mut Bencher) { - b.iter( || { - let mut parser = Parser::new( - r#"{ - "a": 1.0, - "b": [ - true, - "foo\nbar", - { "c": {"d": null} } - ] - }"#.chars() - ); - loop { - match parser.next() { - None => return, - _ => {} - } - } - }); - } - #[bench] - fn bench_small(b: &mut Bencher) { - b.iter( || { - let _ = from_str(r#"{ - "a": 1.0, - "b": [ - true, - "foo\nbar", - { "c": {"d": null} } - ] - }"#); - }); - } - - fn big_json() -> string::String { - let mut src = "[\n".to_string(); - for _ in 0..500 { - src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \ - [1,2,3]},"#); - } - src.push_str("{}]"); - return src; - } - - #[bench] - fn bench_streaming_large(b: &mut Bencher) { - let src = big_json(); - b.iter( || { - let mut parser = Parser::new(src.chars()); - loop { - match parser.next() { - None => return, - _ => {} - } - } - }); - } - #[bench] - fn bench_large(b: &mut Bencher) { - let src = big_json(); - b.iter( || { let _ = from_str(&src); }); - } -} +mod tests; diff --git a/src/libserialize/json/tests.rs b/src/libserialize/json/tests.rs new file mode 100644 index 0000000000000..a16b8bdd78704 --- /dev/null +++ b/src/libserialize/json/tests.rs @@ -0,0 +1,134 @@ +// Benchmarks and tests that require private items + +extern crate test; +use test::Bencher; +use super::{from_str, Parser, StackElement, Stack}; +use std::string; + +#[test] +fn test_stack() { + let mut stack = Stack::new(); + + assert!(stack.is_empty()); + assert!(stack.is_empty()); + assert!(!stack.last_is_index()); + + stack.push_index(0); + stack.bump_index(); + + assert!(stack.len() == 1); + assert!(stack.is_equal_to(&[StackElement::Index(1)])); + assert!(stack.starts_with(&[StackElement::Index(1)])); + assert!(stack.ends_with(&[StackElement::Index(1)])); + assert!(stack.last_is_index()); + assert!(stack.get(0) == StackElement::Index(1)); + + stack.push_key("foo".to_string()); + + assert!(stack.len() == 2); + assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")])); + assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")])); + assert!(stack.starts_with(&[StackElement::Index(1)])); + assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")])); + assert!(stack.ends_with(&[StackElement::Key("foo")])); + assert!(!stack.last_is_index()); + assert!(stack.get(0) == StackElement::Index(1)); + assert!(stack.get(1) == StackElement::Key("foo")); + + stack.push_key("bar".to_string()); + + assert!(stack.len() == 3); + assert!(stack.is_equal_to(&[StackElement::Index(1), + StackElement::Key("foo"), + StackElement::Key("bar")])); + assert!(stack.starts_with(&[StackElement::Index(1)])); + assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")])); + assert!(stack.starts_with(&[StackElement::Index(1), + StackElement::Key("foo"), + StackElement::Key("bar")])); + assert!(stack.ends_with(&[StackElement::Key("bar")])); + assert!(stack.ends_with(&[StackElement::Key("foo"), StackElement::Key("bar")])); + assert!(stack.ends_with(&[StackElement::Index(1), + StackElement::Key("foo"), + StackElement::Key("bar")])); + assert!(!stack.last_is_index()); + assert!(stack.get(0) == StackElement::Index(1)); + assert!(stack.get(1) == StackElement::Key("foo")); + assert!(stack.get(2) == StackElement::Key("bar")); + + stack.pop(); + + assert!(stack.len() == 2); + assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")])); + assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")])); + assert!(stack.starts_with(&[StackElement::Index(1)])); + assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")])); + assert!(stack.ends_with(&[StackElement::Key("foo")])); + assert!(!stack.last_is_index()); + assert!(stack.get(0) == StackElement::Index(1)); + assert!(stack.get(1) == StackElement::Key("foo")); +} + +#[bench] +fn bench_streaming_small(b: &mut Bencher) { + b.iter( || { + let mut parser = Parser::new( + r#"{ + "a": 1.0, + "b": [ + true, + "foo\nbar", + { "c": {"d": null} } + ] + }"#.chars() + ); + loop { + match parser.next() { + None => return, + _ => {} + } + } + }); +} +#[bench] +fn bench_small(b: &mut Bencher) { + b.iter( || { + let _ = from_str(r#"{ + "a": 1.0, + "b": [ + true, + "foo\nbar", + { "c": {"d": null} } + ] + }"#); + }); +} + +fn big_json() -> string::String { + let mut src = "[\n".to_string(); + for _ in 0..500 { + src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \ + [1,2,3]},"#); + } + src.push_str("{}]"); + return src; +} + +#[bench] +fn bench_streaming_large(b: &mut Bencher) { + let src = big_json(); + b.iter( || { + let mut parser = Parser::new(src.chars()); + loop { + match parser.next() { + None => return, + _ => {} + } + } + }); +} +#[bench] +fn bench_large(b: &mut Bencher) { + let src = big_json(); + b.iter( || { let _ = from_str(&src); }); +} diff --git a/src/libserialize/leb128.rs b/src/libserialize/leb128.rs index 16ff59489e718..f9d80842d7558 100644 --- a/src/libserialize/leb128.rs +++ b/src/libserialize/leb128.rs @@ -123,7 +123,7 @@ pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i128, usize) { loop { byte = data[position]; position += 1; - result |= ((byte & 0x7F) as i128) << shift; + result |= i128::from(byte & 0x7F) << shift; shift += 7; if (byte & 0x80) == 0 { diff --git a/src/libserialize/opaque.rs b/src/libserialize/opaque.rs index a6a5c318079f1..75988198eb9b5 100644 --- a/src/libserialize/opaque.rs +++ b/src/libserialize/opaque.rs @@ -296,13 +296,13 @@ impl<'a> serialize::Decoder for Decoder<'a> { #[inline] fn read_f64(&mut self) -> Result { let bits = self.read_u64()?; - Ok(unsafe { ::std::mem::transmute(bits) }) + Ok(f64::from_bits(bits)) } #[inline] fn read_f32(&mut self) -> Result { let bits = self.read_u32()?; - Ok(unsafe { ::std::mem::transmute(bits) }) + Ok(f32::from_bits(bits)) } #[inline] diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index cf948078b08c5..2def2a455fb64 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -723,53 +723,66 @@ macro_rules! peel { ($name:ident, $($other:ident,)*) => (tuple! { $($other,)* }) } -/// Evaluates to the number of identifiers passed to it, for example: `count_idents!(a, b, c) == 3 -macro_rules! count_idents { - () => { 0 }; - ($_i:ident, $($rest:ident,)*) => { 1 + count_idents!($($rest,)*) } +/// Evaluates to the number of tokens passed to it. +/// +/// Logarithmic counting: every one or two recursive expansions, the number of +/// tokens to count is divided by two, instead of being reduced by one. +/// Therefore, the recursion depth is the binary logarithm of the number of +/// tokens to count, and the expanded tree is likewise very small. +macro_rules! count { + () => (0usize); + ($one:tt) => (1usize); + ($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize); + ($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize); } macro_rules! tuple { () => (); ( $($name:ident,)+ ) => ( - impl<$($name:Decodable),*> Decodable for ($($name,)*) { + impl<$($name:Decodable),+> Decodable for ($($name,)+) { #[allow(non_snake_case)] - fn decode(d: &mut D) -> Result<($($name,)*), D::Error> { - let len: usize = count_idents!($($name,)*); + fn decode(d: &mut D) -> Result<($($name,)+), D::Error> { + let len: usize = count!($($name)+); d.read_tuple(len, |d| { let mut i = 0; let ret = ($(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name, D::Error> { Decodable::decode(d) - })?,)*); + })?,)+); Ok(ret) }) } } - impl<$($name:Encodable),*> Encodable for ($($name,)*) { + impl<$($name:Encodable),+> Encodable for ($($name,)+) { #[allow(non_snake_case)] fn encode(&self, s: &mut S) -> Result<(), S::Error> { - let ($(ref $name,)*) = *self; + let ($(ref $name,)+) = *self; let mut n = 0; - $(let $name = $name; n += 1;)* + $(let $name = $name; n += 1;)+ s.emit_tuple(n, |s| { let mut i = 0; - $(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s))?;)* + $(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s))?;)+ Ok(()) }) } } - peel! { $($name,)* } + peel! { $($name,)+ } ) } tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } -impl Encodable for path::PathBuf { +impl Encodable for path::Path { fn encode(&self, e: &mut S) -> Result<(), S::Error> { self.to_str().unwrap().encode(e) } } +impl Encodable for path::PathBuf { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { + path::Path::encode(self, e) + } +} + impl Decodable for path::PathBuf { fn decode(d: &mut D) -> Result { let bytes: String = Decodable::decode(d)?; @@ -911,4 +924,5 @@ impl Decodable for T { impl<'a, T: ?Sized + Encodable> UseSpecializedEncodable for &'a T {} impl UseSpecializedEncodable for Box {} impl UseSpecializedDecodable for Box {} - +impl<'a, T: Decodable> UseSpecializedDecodable for &'a T {} +impl<'a, T: Decodable> UseSpecializedDecodable for &'a [T] {} diff --git a/src/libserialize/tests/json.rs b/src/libserialize/tests/json.rs index 3fb6bda679bc1..0fe3d4cfd6297 100644 --- a/src/libserialize/tests/json.rs +++ b/src/libserialize/tests/json.rs @@ -1,3 +1,4 @@ +#[allow(unused_extern_crates)] extern crate serialize as rustc_serialize; use rustc_serialize::{Encodable, Decodable}; diff --git a/src/libserialize/tests/opaque.rs b/src/libserialize/tests/opaque.rs index fff6fc69e7842..62a8f25124439 100644 --- a/src/libserialize/tests/opaque.rs +++ b/src/libserialize/tests/opaque.rs @@ -1,3 +1,4 @@ +#[allow(unused_extern_crates)] extern crate serialize as rustc_serialize; use rustc_serialize::{Encodable, Decodable}; diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 1a6b58f35b398..38df1f26d95fd 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -3,7 +3,7 @@ authors = ["The Rust Project Developers"] name = "std" version = "0.0.0" build = "build.rs" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust.git" description = "The Rust Standard Library" edition = "2018" @@ -15,15 +15,27 @@ crate-type = ["dylib", "rlib"] [dependencies] alloc = { path = "../liballoc" } +cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../libpanic_unwind", optional = true } panic_abort = { path = "../libpanic_abort" } core = { path = "../libcore" } -libc = { version = "0.2.44", default-features = false, features = ['rustc-dep-of-std'] } -compiler_builtins = { version = "0.1.1" } +libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.16" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } -rustc-demangle = { version = "0.1.10", features = ['rustc-dep-of-std'] } -backtrace-sys = { version = "0.1.24", features = ["rustc-dep-of-std"], optional = true } +hashbrown = { version = "0.4.0", features = ['rustc-dep-of-std'] } + +[dependencies.backtrace] +version = "0.3.29" +default-features = false # don't use coresymbolication on OSX +features = [ + "rustc-dep-of-std", # enable build support for integrating into libstd + "dbghelp", # backtrace/symbolize on MSVC + "libbacktrace", # symbolize on most platforms + "libunwind", # backtrace on most platforms + "dladdr", # symbolize on platforms w/o libbacktrace +] +optional = true [dev-dependencies] rand = "0.6.1" @@ -48,12 +60,12 @@ fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } cc = "1.0" [features] -default = ["compiler_builtins_c", "std_detect_file_io", "std_detect_dlsym_getauxval"] +default = ["std_detect_file_io", "std_detect_dlsym_getauxval"] -backtrace = ["backtrace-sys"] panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] -compiler_builtins_c = ["compiler_builtins/c"] +compiler-builtins-c = ["alloc/compiler-builtins-c"] +llvm-libunwind = ["unwind/llvm-libunwind"] # Make panics and failed asserts immediately abort without formatting any message panic_immediate_abort = ["core/panic_immediate_abort"] @@ -72,3 +84,9 @@ wasm-bindgen-threads = [] # https://github.com/rust-lang-nursery/stdsimd/blob/master/crates/std_detect/Cargo.toml std_detect_file_io = [] std_detect_dlsym_getauxval = [] + +[package.metadata.fortanix-sgx] +# Maximum possible number of threads when testing +threads = 125 +# Maximum heap size +heap_size = 0x8000000 diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index a13da2901df94..ff52974775b05 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -130,7 +130,7 @@ pub use alloc_crate::alloc::*; /// program opts in to using jemalloc as the global allocator, `System` will /// still allocate memory using `malloc` and `HeapAlloc`. #[stable(feature = "alloc_system_type", since = "1.28.0")] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone)] pub struct System; // The Alloc impl just forwards to the GlobalAlloc impl, which is in `std::sys::*::alloc`. @@ -173,6 +173,9 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); /// about the allocation that failed. /// /// The allocation error hook is a global resource. +/// +/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html +/// [`take_alloc_error_hook`]: fn.take_alloc_error_hook.html #[unstable(feature = "alloc_error_hook", issue = "51245")] pub fn set_alloc_error_hook(hook: fn(Layout)) { HOOK.store(hook as *mut (), Ordering::SeqCst); @@ -183,6 +186,8 @@ pub fn set_alloc_error_hook(hook: fn(Layout)) { /// *See also the function [`set_alloc_error_hook`].* /// /// If no custom hook is registered, the default hook will be returned. +/// +/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html #[unstable(feature = "alloc_error_hook", issue = "51245")] pub fn take_alloc_error_hook() -> fn(Layout) { let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 726c27321538d..7a6c97ebaa226 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -20,8 +20,7 @@ fn main() { } else if target.contains("netbsd") { println!("cargo:rustc-link-lib=pthread"); println!("cargo:rustc-link-lib=rt"); - } else if target.contains("dragonfly") || target.contains("bitrig") || - target.contains("openbsd") { + } else if target.contains("dragonfly") || target.contains("openbsd") { println!("cargo:rustc-link-lib=pthread"); } else if target.contains("solaris") { println!("cargo:rustc-link-lib=socket"); diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a51847c92b51e..2925d8362c8d9 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1,222 +1,20 @@ +// ignore-tidy-filelength + use self::Entry::*; -use self::VacantEntryState::*; -use crate::intrinsics::unlikely; -use crate::collections::CollectionAllocErr; -use crate::cell::Cell; +use hashbrown::hash_map as base; + use crate::borrow::Borrow; -use crate::cmp::max; +use crate::cell::Cell; +use crate::collections::CollectionAllocErr; use crate::fmt::{self, Debug}; #[allow(deprecated)] -use crate::hash::{Hash, Hasher, BuildHasher, SipHasher13}; +use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13}; use crate::iter::{FromIterator, FusedIterator}; -use crate::mem::{self, replace}; -use crate::ops::{Deref, DerefMut, Index}; +use crate::ops::Index; use crate::sys; -use super::table::{self, Bucket, EmptyBucket, Fallibility, FullBucket, FullBucketMut, RawTable, - SafeHash}; -use super::table::BucketState::{Empty, Full}; -use super::table::Fallibility::{Fallible, Infallible}; - -const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two - -/// The default behavior of HashMap implements a maximum load factor of 90.9%. -#[derive(Clone)] -struct DefaultResizePolicy; - -impl DefaultResizePolicy { - #[inline] - fn new() -> DefaultResizePolicy { - DefaultResizePolicy - } - - /// A hash map's "capacity" is the number of elements it can hold without - /// being resized. Its "raw capacity" is the number of slots required to - /// provide that capacity, accounting for maximum loading. The raw capacity - /// is always zero or a power of two. - #[inline] - fn try_raw_capacity(&self, len: usize) -> Result { - if len == 0 { - Ok(0) - } else { - // 1. Account for loading: `raw_capacity >= len * 1.1`. - // 2. Ensure it is a power of two. - // 3. Ensure it is at least the minimum size. - let mut raw_cap = len.checked_mul(11) - .map(|l| l / 10) - .and_then(|l| l.checked_next_power_of_two()) - .ok_or(CollectionAllocErr::CapacityOverflow)?; - - raw_cap = max(MIN_NONZERO_RAW_CAPACITY, raw_cap); - Ok(raw_cap) - } - } - - #[inline] - fn raw_capacity(&self, len: usize) -> usize { - self.try_raw_capacity(len).expect("raw_capacity overflow") - } - - /// The capacity of the given raw capacity. - #[inline] - fn capacity(&self, raw_cap: usize) -> usize { - // This doesn't have to be checked for overflow since allocation size - // in bytes will overflow earlier than multiplication by 10. - // - // As per https://github.com/rust-lang/rust/pull/30991 this is updated - // to be: (raw_cap * den + den - 1) / num - (raw_cap * 10 + 10 - 1) / 11 - } -} - -// The main performance trick in this hashmap is called Robin Hood Hashing. -// It gains its excellent performance from one essential operation: -// -// If an insertion collides with an existing element, and that element's -// "probe distance" (how far away the element is from its ideal location) -// is higher than how far we've already probed, swap the elements. -// -// This massively lowers variance in probe distance, and allows us to get very -// high load factors with good performance. The 90% load factor I use is rather -// conservative. -// -// > Why a load factor of approximately 90%? -// -// In general, all the distances to initial buckets will converge on the mean. -// At a load factor of α, the odds of finding the target bucket after k -// probes is approximately 1-α^k. If we set this equal to 50% (since we converge -// on the mean) and set k=8 (64-byte cache line / 8-byte hash), α=0.92. I round -// this down to make the math easier on the CPU and avoid its FPU. -// Since on average we start the probing in the middle of a cache line, this -// strategy pulls in two cache lines of hashes on every lookup. I think that's -// pretty good, but if you want to trade off some space, it could go down to one -// cache line on average with an α of 0.84. -// -// > Wait, what? Where did you get 1-α^k from? -// -// On the first probe, your odds of a collision with an existing element is α. -// The odds of doing this twice in a row is approximately α^2. For three times, -// α^3, etc. Therefore, the odds of colliding k times is α^k. The odds of NOT -// colliding after k tries is 1-α^k. -// -// The paper from 1986 cited below mentions an implementation which keeps track -// of the distance-to-initial-bucket histogram. This approach is not suitable -// for modern architectures because it requires maintaining an internal data -// structure. This allows very good first guesses, but we are most concerned -// with guessing entire cache lines, not individual indexes. Furthermore, array -// accesses are no longer linear and in one direction, as we have now. There -// is also memory and cache pressure that this would entail that would be very -// difficult to properly see in a microbenchmark. -// -// ## Future Improvements (FIXME!) -// -// Allow the load factor to be changed dynamically and/or at initialization. -// -// Also, would it be possible for us to reuse storage when growing the -// underlying table? This is exactly the use case for 'realloc', and may -// be worth exploring. -// -// ## Future Optimizations (FIXME!) -// -// Another possible design choice that I made without any real reason is -// parameterizing the raw table over keys and values. Technically, all we need -// is the size and alignment of keys and values, and the code should be just as -// efficient (well, we might need one for power-of-two size and one for not...). -// This has the potential to reduce code bloat in rust executables, without -// really losing anything except 4 words (key size, key alignment, val size, -// val alignment) which can be passed in to every call of a `RawTable` function. -// This would definitely be an avenue worth exploring if people start complaining -// about the size of rust executables. -// -// Annotate exceedingly likely branches in `table::make_hash` -// and `search_hashed` to reduce instruction cache pressure -// and mispredictions once it becomes possible (blocked on issue #11092). -// -// Shrinking the table could simply reallocate in place after moving buckets -// to the first half. -// -// The growth algorithm (fragment of the Proof of Correctness) -// -------------------- -// -// The growth algorithm is basically a fast path of the naive reinsertion- -// during-resize algorithm. Other paths should never be taken. -// -// Consider growing a robin hood hashtable of capacity n. Normally, we do this -// by allocating a new table of capacity `2n`, and then individually reinsert -// each element in the old table into the new one. This guarantees that the -// new table is a valid robin hood hashtable with all the desired statistical -// properties. Remark that the order we reinsert the elements in should not -// matter. For simplicity and efficiency, we will consider only linear -// reinsertions, which consist of reinserting all elements in the old table -// into the new one by increasing order of index. However we will not be -// starting our reinsertions from index 0 in general. If we start from index -// i, for the purpose of reinsertion we will consider all elements with real -// index j < i to have virtual index n + j. -// -// Our hash generation scheme consists of generating a 64-bit hash and -// truncating the most significant bits. When moving to the new table, we -// simply introduce a new bit to the front of the hash. Therefore, if an -// element has ideal index i in the old table, it can have one of two ideal -// locations in the new table. If the new bit is 0, then the new ideal index -// is i. If the new bit is 1, then the new ideal index is n + i. Intuitively, -// we are producing two independent tables of size n, and for each element we -// independently choose which table to insert it into with equal probability. -// However, rather than wrapping around themselves on overflowing their -// indexes, the first table overflows into the second, and the second into the -// first. Visually, our new table will look something like: -// -// [yy_xxx_xxxx_xxx|xx_yyy_yyyy_yyy] -// -// Where x's are elements inserted into the first table, y's are elements -// inserted into the second, and _'s are empty sections. We now define a few -// key concepts that we will use later. Note that this is a very abstract -// perspective of the table. A real resized table would be at least half -// empty. -// -// Theorem: A linear robin hood reinsertion from the first ideal element -// produces identical results to a linear naive reinsertion from the same -// element. -// -// FIXME(Gankro, pczarn): review the proof and put it all in a separate README.md -// -// Adaptive early resizing -// ---------------------- -// To protect against degenerate performance scenarios (including DOS attacks), -// the implementation includes an adaptive behavior that can resize the map -// early (before its capacity is exceeded) when suspiciously long probe sequences -// are encountered. -// -// With this algorithm in place it would be possible to turn a CPU attack into -// a memory attack due to the aggressive resizing. To prevent that the -// adaptive behavior only triggers when the map is at least half full. -// This reduces the effectiveness of the algorithm but also makes it completely safe. -// -// The previous safety measure also prevents degenerate interactions with -// really bad quality hash algorithms that can make normal inputs look like a -// DOS attack. -// -const DISPLACEMENT_THRESHOLD: usize = 128; -// -// The threshold of 128 is chosen to minimize the chance of exceeding it. -// In particular, we want that chance to be less than 10^-8 with a load of 90%. -// For displacement, the smallest constant that fits our needs is 90, -// so we round that up to 128. -// -// At a load factor of α, the odds of finding the target bucket after exactly n -// unsuccessful probes[1] are -// -// Pr_α{displacement = n} = -// (1 - α) / α * ∑_{k≥1} e^(-kα) * (kα)^(k+n) / (k + n)! * (1 - kα / (k + n + 1)) -// -// We use this formula to find the probability of triggering the adaptive behavior -// -// Pr_0.909{displacement > 128} = 1.601 * 10^-11 -// -// 1. Alfredo Viola (2005). Distributional analysis of Robin Hood linear probing -// hashing with buckets. - -/// A hash map implemented with linear probing and Robin Hood bucket stealing. +/// A hash map implemented with quadratic probing and SIMD lookup. /// /// By default, `HashMap` uses a hashing algorithm selected to provide /// resistance against HashDoS attacks. The algorithm is randomly seeded, and a @@ -254,13 +52,13 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// the [`Eq`] trait, changes while it is in the map. This is normally only /// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. /// -/// Relevant papers/articles: +/// The hash table implementation is a Rust port of Google's [SwissTable]. +/// The original C++ version of SwissTable can be found [here], and this +/// [CppCon talk] gives an overview of how the algorithm works. /// -/// 1. Pedro Celis. ["Robin Hood Hashing"](https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf) -/// 2. Emmanuel Goossaert. ["Robin Hood -/// hashing"](http://codecapsule.com/2013/11/11/robin-hood-hashing/) -/// 3. Emmanuel Goossaert. ["Robin Hood hashing: backward shift -/// deletion"](http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/) +/// [SwissTable]: https://abseil.io/blog/20180927-swisstables +/// [here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h +/// [CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4 /// /// # Examples /// @@ -407,277 +205,7 @@ const DISPLACEMENT_THRESHOLD: usize = 128; #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct HashMap { - // All hashes are keyed on these values, to prevent hash collision attacks. - hash_builder: S, - - table: RawTable, - - resize_policy: DefaultResizePolicy, -} - -/// Search for a pre-hashed key. -/// If you don't already know the hash, use search or search_mut instead -#[inline] -fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalEntry - where M: Deref>, - F: FnMut(&K) -> bool -{ - // This is the only function where capacity can be zero. To avoid - // undefined behavior when Bucket::new gets the raw bucket in this - // case, immediately return the appropriate search result. - if table.capacity() == 0 { - return InternalEntry::TableIsEmpty; - } - - search_hashed_nonempty(table, hash, is_match, true) -} - -/// Search for a pre-hashed key when the hash map is known to be non-empty. -#[inline] -fn search_hashed_nonempty(table: M, hash: SafeHash, mut is_match: F, - compare_hashes: bool) - -> InternalEntry - where M: Deref>, - F: FnMut(&K) -> bool -{ - // Do not check the capacity as an extra branch could slow the lookup. - - let size = table.size(); - let mut probe = Bucket::new(table, hash); - let mut displacement = 0; - - loop { - let full = match probe.peek() { - Empty(bucket) => { - // Found a hole! - return InternalEntry::Vacant { - hash, - elem: NoElem(bucket, displacement), - }; - } - Full(bucket) => bucket, - }; - - let probe_displacement = full.displacement(); - - if probe_displacement < displacement { - // Found a luckier bucket than me. - // We can finish the search early if we hit any bucket - // with a lower distance to initial bucket than we've probed. - return InternalEntry::Vacant { - hash, - elem: NeqElem(full, probe_displacement), - }; - } - - // If the hash doesn't match, it can't be this one.. - if !compare_hashes || hash == full.hash() { - // If the key doesn't match, it can't be this one.. - if is_match(full.read().0) { - return InternalEntry::Occupied { elem: full }; - } - } - displacement += 1; - probe = full.next(); - debug_assert!(displacement <= size); - } -} - -/// Same as `search_hashed_nonempty` but for mutable access. -#[inline] -fn search_hashed_nonempty_mut(table: M, hash: SafeHash, mut is_match: F, - compare_hashes: bool) - -> InternalEntry - where M: DerefMut>, - F: FnMut(&K) -> bool -{ - // Do not check the capacity as an extra branch could slow the lookup. - - let size = table.size(); - let mut probe = Bucket::new(table, hash); - let mut displacement = 0; - - loop { - let mut full = match probe.peek() { - Empty(bucket) => { - // Found a hole! - return InternalEntry::Vacant { - hash, - elem: NoElem(bucket, displacement), - }; - } - Full(bucket) => bucket, - }; - - let probe_displacement = full.displacement(); - - if probe_displacement < displacement { - // Found a luckier bucket than me. - // We can finish the search early if we hit any bucket - // with a lower distance to initial bucket than we've probed. - return InternalEntry::Vacant { - hash, - elem: NeqElem(full, probe_displacement), - }; - } - - // If the hash doesn't match, it can't be this one.. - if hash == full.hash() || !compare_hashes { - // If the key doesn't match, it can't be this one.. - if is_match(full.read_mut().0) { - return InternalEntry::Occupied { elem: full }; - } - } - displacement += 1; - probe = full.next(); - debug_assert!(displacement <= size); - } -} - -fn pop_internal(starting_bucket: FullBucketMut) - -> (K, V, &mut RawTable) -{ - let (empty, retkey, retval) = starting_bucket.take(); - let mut gap = match empty.gap_peek() { - Ok(b) => b, - Err(b) => return (retkey, retval, b.into_table()), - }; - - while gap.full().displacement() != 0 { - gap = match gap.shift() { - Ok(b) => b, - Err(b) => { - return (retkey, retval, b.into_table()); - }, - }; - } - - // Now we've done all our shifting. Return the value we grabbed earlier. - (retkey, retval, gap.into_table()) -} - -/// Performs robin hood bucket stealing at the given `bucket`. You must -/// also pass that bucket's displacement so we don't have to recalculate it. -/// -/// `hash`, `key`, and `val` are the elements to "robin hood" into the hashtable. -fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, - mut displacement: usize, - mut hash: SafeHash, - mut key: K, - mut val: V) - -> FullBucketMut<'a, K, V> { - let size = bucket.table().size(); - let raw_capacity = bucket.table().capacity(); - // There can be at most `size - dib` buckets to displace, because - // in the worst case, there are `size` elements and we already are - // `displacement` buckets away from the initial one. - let idx_end = (bucket.index() + size - bucket.displacement()) % raw_capacity; - // Save the *starting point*. - let mut bucket = bucket.stash(); - - loop { - let (old_hash, old_key, old_val) = bucket.replace(hash, key, val); - hash = old_hash; - key = old_key; - val = old_val; - - loop { - displacement += 1; - let probe = bucket.next(); - debug_assert!(probe.index() != idx_end); - - let full_bucket = match probe.peek() { - Empty(bucket) => { - // Found a hole! - let bucket = bucket.put(hash, key, val); - // Now that it's stolen, just read the value's pointer - // right out of the table! Go back to the *starting point*. - // - // This use of `into_table` is misleading. It turns the - // bucket, which is a FullBucket on top of a - // FullBucketMut, into just one FullBucketMut. The "table" - // refers to the inner FullBucketMut in this context. - return bucket.into_table(); - } - Full(bucket) => bucket, - }; - - let probe_displacement = full_bucket.displacement(); - - bucket = full_bucket; - - // Robin hood! Steal the spot. - if probe_displacement < displacement { - displacement = probe_displacement; - break; - } - } - } -} - -impl HashMap - where K: Eq + Hash, - S: BuildHasher -{ - fn make_hash(&self, x: &X) -> SafeHash - where X: Hash - { - table::make_hash(&self.hash_builder, x) - } - - /// Search for a key, yielding the index if it's found in the hashtable. - /// If you already have the hash for the key lying around, or if you need an - /// InternalEntry, use search_hashed or search_hashed_nonempty. - #[inline] - fn search<'a, Q: ?Sized>(&'a self, q: &Q) - -> Option>> - where K: Borrow, - Q: Eq + Hash - { - if self.is_empty() { - return None; - } - - let hash = self.make_hash(q); - search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow()), true) - .into_occupied_bucket() - } - - #[inline] - fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) - -> Option>> - where K: Borrow, - Q: Eq + Hash - { - if self.is_empty() { - return None; - } - - let hash = self.make_hash(q); - search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow()), true) - .into_occupied_bucket() - } - - // The caller should ensure that invariants by Robin Hood Hashing hold - // and that there's space in the underlying table. - fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { - let mut buckets = Bucket::new(&mut self.table, hash); - let start_index = buckets.index(); - - loop { - // We don't need to compare hashes for value swap. - // Not even DIBs for Robin Hood. - buckets = match buckets.peek() { - Empty(empty) => { - empty.put(hash, k, v); - return; - } - Full(b) => b.into_bucket(), - }; - buckets.next(); - debug_assert!(buckets.index() != start_index); - } - } + base: base::HashMap, } impl HashMap { @@ -732,13 +260,7 @@ impl HashMap { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn capacity(&self) -> usize { - self.resize_policy.capacity(self.raw_capacity()) - } - - /// Returns the hash map's raw capacity. - #[inline] - fn raw_capacity(&self) -> usize { - self.table.capacity() + self.base.capacity() } /// An iterator visiting all keys in arbitrary order. @@ -759,7 +281,7 @@ impl HashMap { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn keys(&self) -> Keys { + pub fn keys(&self) -> Keys<'_, K, V> { Keys { inner: self.iter() } } @@ -781,7 +303,7 @@ impl HashMap { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn values(&self) -> Values { + pub fn values(&self) -> Values<'_, K, V> { Values { inner: self.iter() } } @@ -808,7 +330,7 @@ impl HashMap { /// } /// ``` #[stable(feature = "map_values_mut", since = "1.10.0")] - pub fn values_mut(&mut self) -> ValuesMut { + pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { ValuesMut { inner: self.iter_mut() } } @@ -830,8 +352,8 @@ impl HashMap { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { - Iter { inner: self.table.iter() } + pub fn iter(&self) -> Iter<'_, K, V> { + Iter { base: self.base.iter() } } /// An iterator visiting all key-value pairs in arbitrary order, @@ -858,8 +380,8 @@ impl HashMap { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter_mut(&mut self) -> IterMut { - IterMut { inner: self.table.iter_mut() } + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + IterMut { base: self.base.iter_mut() } } /// Returns the number of elements in the map. @@ -876,7 +398,7 @@ impl HashMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { - self.table.size() + self.base.len() } /// Returns `true` if the map contains no elements. @@ -894,7 +416,7 @@ impl HashMap { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_empty(&self) -> bool { - self.len() == 0 + self.base.is_empty() } /// Clears the map, returning all key-value pairs as an iterator. Keeps the @@ -918,8 +440,8 @@ impl HashMap { /// ``` #[inline] #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self) -> Drain { - Drain { inner: self.table.drain() } + pub fn drain(&mut self) -> Drain<'_, K, V> { + Drain { base: self.base.drain() } } /// Clears the map, removing all key-value pairs. Keeps the allocated memory @@ -938,13 +460,14 @@ impl HashMap { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn clear(&mut self) { - self.drain(); + self.base.clear(); } } impl HashMap - where K: Eq + Hash, - S: BuildHasher +where + K: Eq + Hash, + S: BuildHasher, { /// Creates an empty `HashMap` which will use the given hash builder to hash /// keys. @@ -970,9 +493,7 @@ impl HashMap #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_hasher(hash_builder: S) -> HashMap { HashMap { - hash_builder, - resize_policy: DefaultResizePolicy::new(), - table: RawTable::new(0), + base: base::HashMap::with_hasher(hash_builder), } } @@ -1000,12 +521,8 @@ impl HashMap #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap { - let resize_policy = DefaultResizePolicy::new(); - let raw_cap = resize_policy.raw_capacity(capacity); HashMap { - hash_builder, - resize_policy, - table: RawTable::new(raw_cap), + base: base::HashMap::with_capacity_and_hasher(capacity, hash_builder), } } @@ -1023,9 +540,10 @@ impl HashMap /// let map: HashMap = HashMap::with_hasher(hasher); /// let hasher: &RandomState = map.hasher(); /// ``` + #[inline] #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] pub fn hasher(&self) -> &S { - &self.hash_builder + self.base.hasher() } /// Reserves capacity for at least `additional` more elements to be inserted @@ -1048,11 +566,7 @@ impl HashMap #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { - match self.reserve_internal(additional, Infallible) { - Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => unreachable!(), - Ok(()) => { /* yay */ } - } + self.base.reserve(additional) } /// Tries to reserve capacity for at least `additional` more elements to be inserted @@ -1072,92 +586,12 @@ impl HashMap /// let mut map: HashMap<&str, isize> = HashMap::new(); /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { - self.reserve_internal(additional, Fallible) - } - #[inline] - fn reserve_internal(&mut self, additional: usize, fallibility: Fallibility) - -> Result<(), CollectionAllocErr> { - - let remaining = self.capacity() - self.len(); // this can't overflow - if remaining < additional { - let min_cap = self.len() - .checked_add(additional) - .ok_or(CollectionAllocErr::CapacityOverflow)?; - let raw_cap = self.resize_policy.try_raw_capacity(min_cap)?; - self.try_resize(raw_cap, fallibility)?; - } else if self.table.tag() && remaining <= self.len() { - // Probe sequence is too long and table is half full, - // resize early to reduce probing length. - let new_capacity = self.table.capacity() * 2; - self.try_resize(new_capacity, fallibility)?; - } - Ok(()) - } - - /// Resizes the internal vectors to a new capacity. It's your - /// responsibility to: - /// 1) Ensure `new_raw_cap` is enough for all the elements, accounting - /// for the load factor. - /// 2) Ensure `new_raw_cap` is a power of two or zero. - #[inline(never)] - #[cold] - fn try_resize( - &mut self, - new_raw_cap: usize, - fallibility: Fallibility, - ) -> Result<(), CollectionAllocErr> { - assert!(self.table.size() <= new_raw_cap); - assert!(new_raw_cap.is_power_of_two() || new_raw_cap == 0); - - let mut old_table = replace( - &mut self.table, - match fallibility { - Infallible => RawTable::new(new_raw_cap), - Fallible => RawTable::try_new(new_raw_cap)?, - } - ); - let old_size = old_table.size(); - - if old_table.size() == 0 { - return Ok(()); - } - - let mut bucket = Bucket::head_bucket(&mut old_table); - - // This is how the buckets might be laid out in memory: - // ($ marks an initialized bucket) - // ________________ - // |$$$_$$$$$$_$$$$$| - // - // But we've skipped the entire initial cluster of buckets - // and will continue iteration in this order: - // ________________ - // |$$$$$$_$$$$$ - // ^ wrap around once end is reached - // ________________ - // $$$_____________| - // ^ exit once table.size == 0 - loop { - bucket = match bucket.peek() { - Full(bucket) => { - let h = bucket.hash(); - let (b, k, v) = bucket.take(); - self.insert_hashed_ordered(h, k, v); - if b.table().size() == 0 { - break; - } - b.into_bucket() - } - Empty(b) => b.into_bucket(), - }; - bucket.next(); - } - - assert_eq!(self.table.size(), old_size); - Ok(()) + #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + self.base + .try_reserve(additional) + .map_err(map_collection_alloc_err) } /// Shrinks the capacity of the map as much as possible. It will drop @@ -1176,20 +610,10 @@ impl HashMap /// map.shrink_to_fit(); /// assert!(map.capacity() >= 2); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { - let new_raw_cap = self.resize_policy.raw_capacity(self.len()); - if self.raw_capacity() != new_raw_cap { - let old_table = replace(&mut self.table, RawTable::new(new_raw_cap)); - let old_size = old_table.size(); - - // Shrink the table. Naive algorithm for resizing: - for (h, k, v) in old_table.into_iter() { - self.insert_hashed_nocheck(h, k, v); - } - - debug_assert_eq!(self.table.size(), old_size); - } + self.base.shrink_to_fit(); } /// Shrinks the capacity of the map with a lower limit. It will drop @@ -1214,40 +638,14 @@ impl HashMap /// map.shrink_to(0); /// assert!(map.capacity() >= 2); /// ``` - #[unstable(feature = "shrink_to", reason = "new API", issue="56431")] + #[inline] + #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] pub fn shrink_to(&mut self, min_capacity: usize) { - assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity"); - - let new_raw_cap = self.resize_policy.raw_capacity(max(self.len(), min_capacity)); - if self.raw_capacity() != new_raw_cap { - let old_table = replace(&mut self.table, RawTable::new(new_raw_cap)); - let old_size = old_table.size(); - - // Shrink the table. Naive algorithm for resizing: - for (h, k, v) in old_table.into_iter() { - self.insert_hashed_nocheck(h, k, v); - } - - debug_assert_eq!(self.table.size(), old_size); - } - } - - /// Insert a pre-hashed key-value pair, without first checking - /// that there's enough room in the buckets. Returns a reference to the - /// newly insert value. - /// - /// If the key already exists, the hashtable will be returned untouched - /// and a reference to the existing element will be returned. - fn insert_hashed_nocheck(&mut self, hash: SafeHash, k: K, v: V) -> Option { - let entry = search_hashed(&mut self.table, hash, |key| *key == k).into_entry(k); - match entry { - Some(Occupied(mut elem)) => Some(elem.insert(v)), - Some(Vacant(elem)) => { - elem.insert(v); - None - } - None => unreachable!(), - } + assert!( + self.capacity() >= min_capacity, + "Tried to shrink to a larger capacity" + ); + self.base.shrink_to(min_capacity); } /// Gets the given key's corresponding entry in the map for in-place manipulation. @@ -1269,13 +667,10 @@ impl HashMap /// assert_eq!(letters[&'u'], 1); /// assert_eq!(letters.get(&'y'), None); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn entry(&mut self, key: K) -> Entry { - // Gotta resize now. - self.reserve(1); - let hash = self.make_hash(&key); - search_hashed(&mut self.table, hash, |q| q.eq(&key)) - .into_entry(key).expect("unreachable") + pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { + map_entry(self.base.rustc_entry(key)) } /// Returns a reference to the value corresponding to the key. @@ -1300,10 +695,11 @@ impl HashMap #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn get(&self, k: &Q) -> Option<&V> - where K: Borrow, - Q: Hash + Eq + where + K: Borrow, + Q: Hash + Eq, { - self.search(k).map(|bucket| bucket.into_refs().1) + self.base.get(k) } /// Returns the key-value pair corresponding to the supplied key. @@ -1327,11 +723,13 @@ impl HashMap /// assert_eq!(map.get_key_value(&2), None); /// ``` #[unstable(feature = "map_get_key_value", issue = "49347")] + #[inline] pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> - where K: Borrow, - Q: Hash + Eq + where + K: Borrow, + Q: Hash + Eq, { - self.search(k).map(|bucket| bucket.into_refs()) + self.base.get_key_value(k) } /// Returns `true` if the map contains a value for the specified key. @@ -1354,11 +752,13 @@ impl HashMap /// assert_eq!(map.contains_key(&2), false); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn contains_key(&self, k: &Q) -> bool - where K: Borrow, - Q: Hash + Eq + where + K: Borrow, + Q: Hash + Eq, { - self.search(k).is_some() + self.base.contains_key(k) } /// Returns a mutable reference to the value corresponding to the key. @@ -1383,11 +783,13 @@ impl HashMap /// assert_eq!(map[&1], "b"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> - where K: Borrow, - Q: Hash + Eq + where + K: Borrow, + Q: Hash + Eq, { - self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) + self.base.get_mut(k) } /// Inserts a key-value pair into the map. @@ -1416,10 +818,9 @@ impl HashMap /// assert_eq!(map[&37], "c"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn insert(&mut self, k: K, v: V) -> Option { - let hash = self.make_hash(&k); - self.reserve(1); - self.insert_hashed_nocheck(hash, k, v) + self.base.insert(k, v) } /// Removes a key from the map, returning the value at the key if the key @@ -1443,11 +844,13 @@ impl HashMap /// assert_eq!(map.remove(&1), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn remove(&mut self, k: &Q) -> Option - where K: Borrow, - Q: Hash + Eq + where + K: Borrow, + Q: Hash + Eq, { - self.search_mut(k).map(|bucket| pop_internal(bucket).1) + self.base.remove(k) } /// Removes a key from the map, returning the stored key and value if the @@ -1473,15 +876,13 @@ impl HashMap /// # } /// ``` #[stable(feature = "hash_map_remove_entry", since = "1.27.0")] + #[inline] pub fn remove_entry(&mut self, k: &Q) -> Option<(K, V)> - where K: Borrow, - Q: Hash + Eq + where + K: Borrow, + Q: Hash + Eq, { - self.search_mut(k) - .map(|bucket| { - let (k, v, _) = pop_internal(bucket); - (k, v) - }) + self.base.remove_entry(k) } /// Retains only the elements specified by the predicate. @@ -1498,45 +899,18 @@ impl HashMap /// assert_eq!(map.len(), 4); /// ``` #[stable(feature = "retain_hash_collection", since = "1.18.0")] - pub fn retain(&mut self, mut f: F) - where F: FnMut(&K, &mut V) -> bool + #[inline] + pub fn retain(&mut self, f: F) + where + F: FnMut(&K, &mut V) -> bool, { - if self.table.size() == 0 { - return; - } - let mut elems_left = self.table.size(); - let mut bucket = Bucket::head_bucket(&mut self.table); - bucket.prev(); - let start_index = bucket.index(); - while elems_left != 0 { - bucket = match bucket.peek() { - Full(mut full) => { - elems_left -= 1; - let should_remove = { - let (k, v) = full.read_mut(); - !f(k, v) - }; - if should_remove { - let prev_raw = full.raw(); - let (_, _, t) = pop_internal(full); - Bucket::new_from(prev_raw, t) - } else { - full.into_bucket() - } - }, - Empty(b) => { - b.into_bucket() - } - }; - bucket.prev(); // reverse iteration - debug_assert!(elems_left == 0 || bucket.index() != start_index); - } + self.base.retain(f) } } impl HashMap - where K: Eq + Hash, - S: BuildHasher +where + S: BuildHasher, { /// Creates a raw entry builder for the HashMap. /// @@ -1569,10 +943,9 @@ impl HashMap /// so that the map now contains keys which compare equal, search may start /// acting erratically, with two keys randomly masking each other. Implementations /// are free to assume this doesn't happen (within the limits of memory-safety). - #[inline(always)] + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut { - self.reserve(1); + pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S> { RawEntryBuilderMut { map: self } } @@ -1591,52 +964,59 @@ impl HashMap /// `get` should be preferred. /// /// Immutable raw entries have very limited use; you might instead want `raw_entry_mut`. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn raw_entry(&self) -> RawEntryBuilder { + pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S> { RawEntryBuilder { map: self } } } #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for HashMap - where K: Eq + Hash, - V: PartialEq, - S: BuildHasher +where + K: Eq + Hash, + V: PartialEq, + S: BuildHasher, { fn eq(&self, other: &HashMap) -> bool { if self.len() != other.len() { return false; } - self.iter().all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + self.iter() + .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) } } #[stable(feature = "rust1", since = "1.0.0")] impl Eq for HashMap - where K: Eq + Hash, - V: Eq, - S: BuildHasher +where + K: Eq + Hash, + V: Eq, + S: BuildHasher, { } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for HashMap - where K: Eq + Hash + Debug, - V: Debug, - S: BuildHasher +where + K: Eq + Hash + Debug, + V: Debug, + S: BuildHasher, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_map().entries(self.iter()).finish() } } #[stable(feature = "rust1", since = "1.0.0")] impl Default for HashMap - where K: Eq + Hash, - S: BuildHasher + Default +where + K: Eq + Hash, + S: BuildHasher + Default, { /// Creates an empty `HashMap`, with the `Default` value for the hasher. + #[inline] fn default() -> HashMap { HashMap::with_hasher(Default::default()) } @@ -1644,9 +1024,10 @@ impl Default for HashMap #[stable(feature = "rust1", since = "1.0.0")] impl Index<&Q> for HashMap - where K: Eq + Hash + Borrow, - Q: Eq + Hash, - S: BuildHasher +where + K: Eq + Hash + Borrow, + Q: Eq + Hash, + S: BuildHasher, { type Output = V; @@ -1670,23 +1051,24 @@ impl Index<&Q> for HashMap /// [`HashMap`]: struct.HashMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { - inner: table::Iter<'a, K, V>, + base: base::Iter<'a, K, V>, } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Iter<'_, K, V> { + #[inline] fn clone(&self) -> Self { - Iter { inner: self.inner.clone() } + Iter { + base: self.base.clone(), + } } } #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Iter<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.clone()) - .finish() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() } } @@ -1699,7 +1081,17 @@ impl fmt::Debug for Iter<'_, K, V> { /// [`HashMap`]: struct.HashMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, K: 'a, V: 'a> { - inner: table::IterMut<'a, K, V>, + base: base::IterMut<'a, K, V>, +} + +impl<'a, K, V> IterMut<'a, K, V> { + /// Returns a iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + base: self.base.rustc_iter(), + } + } } /// An owning iterator over the entries of a `HashMap`. @@ -1711,7 +1103,17 @@ pub struct IterMut<'a, K: 'a, V: 'a> { /// [`HashMap`]: struct.HashMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { - pub(super) inner: table::IntoIter, + base: base::IntoIter, +} + +impl IntoIter { + /// Returns a iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + base: self.base.rustc_iter(), + } + } } /// An iterator over the keys of a `HashMap`. @@ -1729,17 +1131,18 @@ pub struct Keys<'a, K: 'a, V: 'a> { // FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Keys<'_, K, V> { + #[inline] fn clone(&self) -> Self { - Keys { inner: self.inner.clone() } + Keys { + inner: self.inner.clone(), + } } } #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Keys<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.clone()) - .finish() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() } } @@ -1758,17 +1161,18 @@ pub struct Values<'a, K: 'a, V: 'a> { // FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Values<'_, K, V> { + #[inline] fn clone(&self) -> Self { - Values { inner: self.inner.clone() } + Values { + inner: self.inner.clone(), + } } } #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Values<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.clone()) - .finish() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() } } @@ -1781,7 +1185,17 @@ impl fmt::Debug for Values<'_, K, V> { /// [`HashMap`]: struct.HashMap.html #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, K: 'a, V: 'a> { - pub(super) inner: table::Drain<'a, K, V>, + base: base::Drain<'a, K, V>, +} + +impl<'a, K, V> Drain<'a, K, V> { + /// Returns a iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + base: self.base.rustc_iter(), + } + } } /// A mutable iterator over the values of a `HashMap`. @@ -1796,47 +1210,6 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, } -enum InternalEntry { - Occupied { elem: FullBucket }, - Vacant { - hash: SafeHash, - elem: VacantEntryState, - }, - TableIsEmpty, -} - -impl InternalEntry { - #[inline] - fn into_occupied_bucket(self) -> Option> { - match self { - InternalEntry::Occupied { elem } => Some(elem), - _ => None, - } - } -} - -impl<'a, K, V> InternalEntry> { - #[inline] - fn into_entry(self, key: K) -> Option> { - match self { - InternalEntry::Occupied { elem } => { - Some(Occupied(OccupiedEntry { - key: Some(key), - elem, - })) - } - InternalEntry::Vacant { hash, elem } => { - Some(Vacant(VacantEntry { - hash, - key, - elem, - })) - } - InternalEntry::TableIsEmpty => None, - } - } -} - /// A builder for computing where in a HashMap a key-value pair would be stored. /// /// See the [`HashMap::raw_entry_mut`] docs for usage examples. @@ -1852,11 +1225,13 @@ pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> { /// /// This is a lower-level version of [`Entry`]. /// -/// This `enum` is constructed from the [`raw_entry`] method on [`HashMap`]. +/// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`], +/// then calling one of the methods of that [`RawEntryBuilderMut`]. /// /// [`HashMap`]: struct.HashMap.html /// [`Entry`]: enum.Entry.html -/// [`raw_entry`]: struct.HashMap.html#method.raw_entry +/// [`raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut +/// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html #[unstable(feature = "hash_raw_entry", issue = "56167")] pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> { /// An occupied entry. @@ -1871,7 +1246,7 @@ pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> { /// [`RawEntryMut`]: enum.RawEntryMut.html #[unstable(feature = "hash_raw_entry", issue = "56167")] pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a> { - elem: FullBucket>, + base: base::RawOccupiedEntryMut<'a, K, V>, } /// A view into a vacant entry in a `HashMap`. @@ -1880,8 +1255,7 @@ pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a> { /// [`RawEntryMut`]: enum.RawEntryMut.html #[unstable(feature = "hash_raw_entry", issue = "56167")] pub struct RawVacantEntryMut<'a, K: 'a, V: 'a, S: 'a> { - elem: VacantEntryState>, - hash_builder: &'a S, + base: base::RawVacantEntryMut<'a, K, V, S>, } /// A builder for computing where in a HashMap a key-value pair would be stored. @@ -1895,128 +1269,81 @@ pub struct RawEntryBuilder<'a, K: 'a, V: 'a, S: 'a> { } impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> - where S: BuildHasher, - K: Eq + Hash, +where + S: BuildHasher, { /// Creates a `RawEntryMut` from the given key. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn from_key(self, k: &Q) -> RawEntryMut<'a, K, V, S> - where K: Borrow, - Q: Hash + Eq + where + K: Borrow, + Q: Hash + Eq, { - let mut hasher = self.map.hash_builder.build_hasher(); - k.hash(&mut hasher); - self.from_key_hashed_nocheck(hasher.finish(), k) + map_raw_entry(self.map.base.raw_entry_mut().from_key(k)) } /// Creates a `RawEntryMut` from the given key and its hash. #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S> - where K: Borrow, - Q: Eq + where + K: Borrow, + Q: Eq, { - self.from_hash(hash, |q| q.borrow().eq(k)) + map_raw_entry( + self.map + .base + .raw_entry_mut() + .from_key_hashed_nocheck(hash, k), + ) } - #[inline] - fn search(self, hash: u64, is_match: F, compare_hashes: bool) -> RawEntryMut<'a, K, V, S> - where for<'b> F: FnMut(&'b K) -> bool, - { - match search_hashed_nonempty_mut(&mut self.map.table, - SafeHash::new(hash), - is_match, - compare_hashes) { - InternalEntry::Occupied { elem } => { - RawEntryMut::Occupied(RawOccupiedEntryMut { elem }) - } - InternalEntry::Vacant { elem, .. } => { - RawEntryMut::Vacant(RawVacantEntryMut { - elem, - hash_builder: &self.map.hash_builder, - }) - } - InternalEntry::TableIsEmpty => { - unreachable!() - } - } - } /// Creates a `RawEntryMut` from the given hash. #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn from_hash(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S> - where for<'b> F: FnMut(&'b K) -> bool, + where + for<'b> F: FnMut(&'b K) -> bool, { - self.search(hash, is_match, true) - } - - /// Search possible locations for an element with hash `hash` until `is_match` returns true for - /// one of them. There is no guarantee that all keys passed to `is_match` will have the provided - /// hash. - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn search_bucket(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S> - where for<'b> F: FnMut(&'b K) -> bool, - { - self.search(hash, is_match, false) + map_raw_entry(self.map.base.raw_entry_mut().from_hash(hash, is_match)) } } impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S> - where S: BuildHasher, +where + S: BuildHasher, { /// Access an entry by key. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn from_key(self, k: &Q) -> Option<(&'a K, &'a V)> - where K: Borrow, - Q: Hash + Eq + where + K: Borrow, + Q: Hash + Eq, { - let mut hasher = self.map.hash_builder.build_hasher(); - k.hash(&mut hasher); - self.from_key_hashed_nocheck(hasher.finish(), k) + self.map.base.raw_entry().from_key(k) } /// Access an entry by a key and its hash. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> Option<(&'a K, &'a V)> - where K: Borrow, - Q: Hash + Eq - - { - self.from_hash(hash, |q| q.borrow().eq(k)) - } - - fn search(self, hash: u64, is_match: F, compare_hashes: bool) -> Option<(&'a K, &'a V)> - where F: FnMut(&K) -> bool + where + K: Borrow, + Q: Hash + Eq, { - if unsafe { unlikely(self.map.table.size() == 0) } { - return None; - } - match search_hashed_nonempty(&self.map.table, - SafeHash::new(hash), - is_match, - compare_hashes) { - InternalEntry::Occupied { elem } => Some(elem.into_refs()), - InternalEntry::Vacant { .. } => None, - InternalEntry::TableIsEmpty => unreachable!(), - } + self.map.base.raw_entry().from_key_hashed_nocheck(hash, k) } /// Access an entry by hash. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn from_hash(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)> - where F: FnMut(&K) -> bool - { - self.search(hash, is_match, true) - } - - /// Search possible locations for an element with hash `hash` until `is_match` returns true for - /// one of them. There is no guarantee that all keys passed to `is_match` will have the provided - /// hash. - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn search_bucket(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)> - where F: FnMut(&K) -> bool + where + F: FnMut(&K) -> bool, { - self.search(hash, is_match, false) + self.map.base.raw_entry().from_hash(hash, is_match) } } @@ -2038,10 +1365,12 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { /// *map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 10).1 *= 2; /// assert_eq!(map["poneyland"], 6); /// ``` + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn or_insert(self, default_key: K, default_val: V) -> (&'a mut K, &'a mut V) - where K: Hash, - S: BuildHasher, + where + K: Hash, + S: BuildHasher, { match self { RawEntryMut::Occupied(entry) => entry.into_key_value(), @@ -2066,11 +1395,13 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { /// /// assert_eq!(map["poneyland"], "hoho".to_string()); /// ``` + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn or_insert_with(self, default: F) -> (&'a mut K, &'a mut V) - where F: FnOnce() -> (K, V), - K: Hash, - S: BuildHasher, + where + F: FnOnce() -> (K, V), + K: Hash, + S: BuildHasher, { match self { RawEntryMut::Occupied(entry) => entry.into_key_value(), @@ -2104,9 +1435,11 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { /// .or_insert("poneyland", 0); /// assert_eq!(map["poneyland"], 43); /// ``` + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn and_modify(self, f: F) -> Self - where F: FnOnce(&mut K, &mut V) + where + F: FnOnce(&mut K, &mut V), { match self { RawEntryMut::Occupied(mut entry) => { @@ -2115,7 +1448,7 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { f(k, v); } RawEntryMut::Occupied(entry) - }, + } RawEntryMut::Vacant(entry) => RawEntryMut::Vacant(entry), } } @@ -2123,174 +1456,164 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { impl<'a, K, V> RawOccupiedEntryMut<'a, K, V> { /// Gets a reference to the key in the entry. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn key(&self) -> &K { - self.elem.read().0 + self.base.key() } /// Gets a mutable reference to the key in the entry. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn key_mut(&mut self) -> &mut K { - self.elem.read_mut().0 + self.base.key_mut() } /// Converts the entry into a mutable reference to the key in the entry /// with a lifetime bound to the map itself. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn into_key(self) -> &'a mut K { - self.elem.into_mut_refs().0 + self.base.into_key() } /// Gets a reference to the value in the entry. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn get(&self) -> &V { - self.elem.read().1 + self.base.get() } /// Converts the OccupiedEntry into a mutable reference to the value in the entry /// with a lifetime bound to the map itself. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn into_mut(self) -> &'a mut V { - self.elem.into_mut_refs().1 + self.base.into_mut() } /// Gets a mutable reference to the value in the entry. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn get_mut(&mut self) -> &mut V { - self.elem.read_mut().1 + self.base.get_mut() } /// Gets a reference to the key and value in the entry. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn get_key_value(&mut self) -> (&K, &V) { - self.elem.read() + self.base.get_key_value() } /// Gets a mutable reference to the key and value in the entry. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) { - self.elem.read_mut() + self.base.get_key_value_mut() } /// Converts the OccupiedEntry into a mutable reference to the key and value in the entry /// with a lifetime bound to the map itself. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn into_key_value(self) -> (&'a mut K, &'a mut V) { - self.elem.into_mut_refs() + self.base.into_key_value() } /// Sets the value of the entry, and returns the entry's old value. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn insert(&mut self, value: V) -> V { - mem::replace(self.get_mut(), value) + self.base.insert(value) } /// Sets the value of the entry, and returns the entry's old value. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn insert_key(&mut self, key: K) -> K { - mem::replace(self.key_mut(), key) + self.base.insert_key(key) } /// Takes the value out of the entry, and returns it. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn remove(self) -> V { - pop_internal(self.elem).1 + self.base.remove() } /// Take the ownership of the key and value from the map. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn remove_entry(self) -> (K, V) { - let (k, v, _) = pop_internal(self.elem); - (k, v) + self.base.remove_entry() } } impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it. + #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V) - where K: Hash, - S: BuildHasher, + where + K: Hash, + S: BuildHasher, { - let mut hasher = self.hash_builder.build_hasher(); - key.hash(&mut hasher); - self.insert_hashed_nocheck(hasher.finish(), key, value) + self.base.insert(key, value) } /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it. #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) { - let hash = SafeHash::new(hash); - let b = match self.elem { - NeqElem(mut bucket, disp) => { - if disp >= DISPLACEMENT_THRESHOLD { - bucket.table_mut().set_tag(true); - } - robin_hood(bucket, disp, hash, key, value) - }, - NoElem(mut bucket, disp) => { - if disp >= DISPLACEMENT_THRESHOLD { - bucket.table_mut().set_tag(true); - } - bucket.put(hash, key, value) - }, - }; - b.into_mut_refs() + pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + self.base.insert_hashed_nocheck(hash, key, value) } } #[unstable(feature = "hash_raw_entry", issue = "56167")] impl Debug for RawEntryBuilderMut<'_, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("RawEntryBuilder") - .finish() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish() } } #[unstable(feature = "hash_raw_entry", issue = "56167")] impl Debug for RawEntryMut<'_, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - RawEntryMut::Vacant(ref v) => { - f.debug_tuple("RawEntry") - .field(v) - .finish() - } - RawEntryMut::Occupied(ref o) => { - f.debug_tuple("RawEntry") - .field(o) - .finish() - } + RawEntryMut::Vacant(ref v) => f.debug_tuple("RawEntry").field(v).finish(), + RawEntryMut::Occupied(ref o) => f.debug_tuple("RawEntry").field(o).finish(), } } } #[unstable(feature = "hash_raw_entry", issue = "56167")] impl Debug for RawOccupiedEntryMut<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawOccupiedEntryMut") - .field("key", self.key()) - .field("value", self.get()) - .finish() + .field("key", self.key()) + .field("value", self.get()) + .finish() } } #[unstable(feature = "hash_raw_entry", issue = "56167")] impl Debug for RawVacantEntryMut<'_, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("RawVacantEntryMut") - .finish() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawVacantEntryMut").finish() } } #[unstable(feature = "hash_raw_entry", issue = "56167")] impl Debug for RawEntryBuilder<'_, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("RawEntryBuilder") - .finish() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish() } } @@ -2304,29 +1627,19 @@ impl Debug for RawEntryBuilder<'_, K, V, S> { pub enum Entry<'a, K: 'a, V: 'a> { /// An occupied entry. #[stable(feature = "rust1", since = "1.0.0")] - Occupied(#[stable(feature = "rust1", since = "1.0.0")] - OccupiedEntry<'a, K, V>), + Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>), /// A vacant entry. #[stable(feature = "rust1", since = "1.0.0")] - Vacant(#[stable(feature = "rust1", since = "1.0.0")] - VacantEntry<'a, K, V>), + Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>), } -#[stable(feature= "debug_hash_map", since = "1.12.0")] +#[stable(feature = "debug_hash_map", since = "1.12.0")] impl Debug for Entry<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - Vacant(ref v) => { - f.debug_tuple("Entry") - .field(v) - .finish() - } - Occupied(ref o) => { - f.debug_tuple("Entry") - .field(o) - .finish() - } + Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), } } } @@ -2337,13 +1650,12 @@ impl Debug for Entry<'_, K, V> { /// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { - key: Option, - elem: FullBucket>, + base: base::RustcOccupiedEntry<'a, K, V>, } -#[stable(feature= "debug_hash_map", since = "1.12.0")] +#[stable(feature = "debug_hash_map", since = "1.12.0")] impl Debug for OccupiedEntry<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry") .field("key", self.key()) .field("value", self.get()) @@ -2357,34 +1669,22 @@ impl Debug for OccupiedEntry<'_, K, V> { /// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { - hash: SafeHash, - key: K, - elem: VacantEntryState>, + base: base::RustcVacantEntry<'a, K, V>, } -#[stable(feature= "debug_hash_map", since = "1.12.0")] +#[stable(feature = "debug_hash_map", since = "1.12.0")] impl Debug for VacantEntry<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("VacantEntry") - .field(self.key()) - .finish() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() } } -/// Possible states of a VacantEntry. -enum VacantEntryState { - /// The index is occupied, but the key to insert has precedence, - /// and will kick the current one out on insertion. - NeqElem(FullBucket, usize), - /// The index is genuinely vacant. - NoElem(EmptyBucket, usize), -} - #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S> IntoIterator for &'a HashMap { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; + #[inline] fn into_iter(self) -> Iter<'a, K, V> { self.iter() } @@ -2395,6 +1695,7 @@ impl<'a, K, V, S> IntoIterator for &'a mut HashMap { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; + #[inline] fn into_iter(self) -> IterMut<'a, K, V> { self.iter_mut() } @@ -2422,8 +1723,11 @@ impl IntoIterator for HashMap { /// // Not possible with .iter() /// let vec: Vec<(&str, i32)> = map.into_iter().collect(); /// ``` + #[inline] fn into_iter(self) -> IntoIter { - IntoIter { inner: self.table.into_iter() } + IntoIter { + base: self.base.into_iter(), + } } } @@ -2433,18 +1737,18 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { #[inline] fn next(&mut self) -> Option<(&'a K, &'a V)> { - self.inner.next() + self.base.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() + self.base.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Iter<'_, K, V> { #[inline] fn len(&self) -> usize { - self.inner.len() + self.base.len() } } @@ -2457,18 +1761,18 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { #[inline] fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - self.inner.next() + self.base.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() + self.base.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IterMut<'_, K, V> { #[inline] fn len(&self) -> usize { - self.inner.len() + self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] @@ -2476,13 +1780,12 @@ impl FusedIterator for IterMut<'_, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for IterMut<'_, K, V> - where K: fmt::Debug, - V: fmt::Debug, +where + K: fmt::Debug, + V: fmt::Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.inner.iter()) - .finish() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() } } @@ -2492,18 +1795,18 @@ impl Iterator for IntoIter { #[inline] fn next(&mut self) -> Option<(K, V)> { - self.inner.next().map(|(_, k, v)| (k, v)) + self.base.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() + self.base.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter { #[inline] fn len(&self) -> usize { - self.inner.len() + self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] @@ -2511,10 +1814,8 @@ impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.inner.iter()) - .finish() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() } } @@ -2589,13 +1890,12 @@ impl FusedIterator for ValuesMut<'_, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for ValuesMut<'_, K, V> - where K: fmt::Debug, - V: fmt::Debug, +where + K: fmt::Debug, + V: fmt::Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.inner.inner.iter()) - .finish() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter()).finish() } } @@ -2605,18 +1905,18 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { #[inline] fn next(&mut self) -> Option<(K, V)> { - self.inner.next().map(|(_, k, v)| (k, v)) + self.base.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() + self.base.size_hint() } } #[stable(feature = "drain", since = "1.6.0")] impl ExactSizeIterator for Drain<'_, K, V> { #[inline] fn len(&self) -> usize { - self.inner.len() + self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] @@ -2624,13 +1924,12 @@ impl FusedIterator for Drain<'_, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Drain<'_, K, V> - where K: fmt::Debug, - V: fmt::Debug, +where + K: fmt::Debug, + V: fmt::Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.inner.iter()) - .finish() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() } } @@ -2652,6 +1951,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// *map.entry("poneyland").or_insert(10) *= 2; /// assert_eq!(map["poneyland"], 6); /// ``` + #[inline] pub fn or_insert(self, default: V) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), @@ -2675,6 +1975,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// /// assert_eq!(map["poneyland"], "hoho".to_string()); /// ``` + #[inline] pub fn or_insert_with V>(self, default: F) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), @@ -2692,6 +1993,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// let mut map: HashMap<&str, u32> = HashMap::new(); /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); /// ``` + #[inline] #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { match *self { @@ -2720,19 +2022,20 @@ impl<'a, K, V> Entry<'a, K, V> { /// .or_insert(42); /// assert_eq!(map["poneyland"], 43); /// ``` + #[inline] #[stable(feature = "entry_and_modify", since = "1.26.0")] pub fn and_modify(self, f: F) -> Self - where F: FnOnce(&mut V) + where + F: FnOnce(&mut V), { match self { Occupied(mut entry) => { f(entry.get_mut()); Occupied(entry) - }, + } Vacant(entry) => Vacant(entry), } } - } impl<'a, K, V: Default> Entry<'a, K, V> { @@ -2752,6 +2055,7 @@ impl<'a, K, V: Default> Entry<'a, K, V> { /// assert_eq!(map["poneyland"], None); /// # } /// ``` + #[inline] pub fn or_default(self) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), @@ -2772,9 +2076,10 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// map.entry("poneyland").or_insert(12); /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); /// ``` + #[inline] #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { - self.elem.read().0 + self.base.key() } /// Take the ownership of the key and value from the map. @@ -2795,10 +2100,10 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// assert_eq!(map.contains_key("poneyland"), false); /// ``` + #[inline] #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] pub fn remove_entry(self) -> (K, V) { - let (k, v, _) = pop_internal(self.elem); - (k, v) + self.base.remove_entry() } /// Gets a reference to the value in the entry. @@ -2816,9 +2121,10 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// assert_eq!(o.get(), &12); /// } /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn get(&self) -> &V { - self.elem.read().1 + self.base.get() } /// Gets a mutable reference to the value in the entry. @@ -2848,9 +2154,10 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// assert_eq!(map["poneyland"], 24); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut V { - self.elem.read_mut().1 + self.base.get_mut() } /// Converts the OccupiedEntry into a mutable reference to the value in the entry @@ -2876,9 +2183,10 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// assert_eq!(map["poneyland"], 22); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn into_mut(self) -> &'a mut V { - self.elem.into_mut_refs().1 + self.base.into_mut() } /// Sets the value of the entry, and returns the entry's old value. @@ -2898,11 +2206,10 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// assert_eq!(map["poneyland"], 15); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(&mut self, mut value: V) -> V { - let old_value = self.get_mut(); - mem::swap(&mut value, old_value); - value + pub fn insert(&mut self, value: V) -> V { + self.base.insert(value) } /// Takes the value out of the entry, and returns it. @@ -2922,16 +2229,10 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// assert_eq!(map.contains_key("poneyland"), false); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(self) -> V { - pop_internal(self.elem).1 - } - - /// Returns a key that was used for search. - /// - /// The key was retained for further use. - fn take_key(&mut self) -> Option { - self.key.take() + self.base.remove() } /// Replaces the entry, returning the old key and value. The new key in the hash map will be @@ -2955,14 +2256,10 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// } /// /// ``` + #[inline] #[unstable(feature = "map_entry_replace", issue = "44286")] - pub fn replace_entry(mut self, value: V) -> (K, V) { - let (old_key, old_value) = self.elem.read_mut(); - - let old_key = mem::replace(old_key, self.key.unwrap()); - let old_value = mem::replace(old_value, value); - - (old_key, old_value) + pub fn replace_entry(self, value: V) -> (K, V) { + self.base.replace_entry(value) } /// Replaces the key in the hash map with the key used to create this entry. @@ -2990,10 +2287,10 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// } /// } /// ``` + #[inline] #[unstable(feature = "map_entry_replace", issue = "44286")] - pub fn replace_key(mut self) -> K { - let (old_key, _) = self.elem.read_mut(); - mem::replace(old_key, self.key.unwrap()) + pub fn replace_key(self) -> K { + self.base.replace_key() } } @@ -3009,9 +2306,10 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// let mut map: HashMap<&str, u32> = HashMap::new(); /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); /// ``` + #[inline] #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { - &self.key + self.base.key() } /// Take ownership of the key. @@ -3028,9 +2326,10 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// v.into_key(); /// } /// ``` + #[inline] #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] pub fn into_key(self) -> K { - self.key + self.base.into_key() } /// Sets the value of the entry with the VacantEntry's key, @@ -3049,30 +2348,18 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// } /// assert_eq!(map["poneyland"], 37); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { - let b = match self.elem { - NeqElem(mut bucket, disp) => { - if disp >= DISPLACEMENT_THRESHOLD { - bucket.table_mut().set_tag(true); - } - robin_hood(bucket, disp, self.hash, self.key, value) - }, - NoElem(mut bucket, disp) => { - if disp >= DISPLACEMENT_THRESHOLD { - bucket.table_mut().set_tag(true); - } - bucket.put(self.hash, self.key, value) - }, - }; - b.into_mut_refs().1 + self.base.insert(value) } } #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator<(K, V)> for HashMap - where K: Eq + Hash, - S: BuildHasher + Default +where + K: Eq + Hash, + S: BuildHasher + Default, { fn from_iter>(iter: T) -> HashMap { let mut map = HashMap::with_hasher(Default::default()); @@ -3083,35 +2370,26 @@ impl FromIterator<(K, V)> for HashMap #[stable(feature = "rust1", since = "1.0.0")] impl Extend<(K, V)> for HashMap - where K: Eq + Hash, - S: BuildHasher +where + K: Eq + Hash, + S: BuildHasher, { + #[inline] fn extend>(&mut self, iter: T) { - // Keys may be already present or show multiple times in the iterator. - // Reserve the entire hint lower bound if the map is empty. - // Otherwise reserve half the hint (rounded up), so the map - // will only resize twice in the worst case. - let iter = iter.into_iter(); - let reserve = if self.is_empty() { - iter.size_hint().0 - } else { - (iter.size_hint().0 + 1) / 2 - }; - self.reserve(reserve); - for (k, v) in iter { - self.insert(k, v); - } + self.base.extend(iter) } } #[stable(feature = "hash_extend_copy", since = "1.4.0")] impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap - where K: Eq + Hash + Copy, - V: Copy, - S: BuildHasher +where + K: Eq + Hash + Copy, + V: Copy, + S: BuildHasher, { + #[inline] fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); + self.base.extend(iter) } } @@ -3216,7 +2494,10 @@ impl DefaultHasher { #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] impl Default for DefaultHasher { - /// Creates a new `DefaultHasher` using [`new`][DefaultHasher::new]. + // FIXME: here should link `new` to [DefaultHasher::new], but it occurs intra-doc link + // resolution failure when re-exporting libstd items. When #56922 fixed, + // link `new` to [DefaultHasher::new] again. + /// Creates a new `DefaultHasher` using `new`. /// See its documentation for more. fn default() -> DefaultHasher { DefaultHasher::new() @@ -3247,41 +2528,34 @@ impl Default for RandomState { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for RandomState { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("RandomState { .. }") } } -impl super::Recover for HashMap - where K: Eq + Hash + Borrow, - S: BuildHasher, - Q: Eq + Hash -{ - type Key = K; - - #[inline] - fn get(&self, key: &Q) -> Option<&K> { - self.search(key).map(|bucket| bucket.into_refs().0) +#[inline] +fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, V> { + match raw { + base::RustcEntry::Occupied(base) => Entry::Occupied(OccupiedEntry { base }), + base::RustcEntry::Vacant(base) => Entry::Vacant(VacantEntry { base }), } +} - fn take(&mut self, key: &Q) -> Option { - self.search_mut(key).map(|bucket| pop_internal(bucket).0) +#[inline] +fn map_collection_alloc_err(err: hashbrown::CollectionAllocErr) -> CollectionAllocErr { + match err { + hashbrown::CollectionAllocErr::CapacityOverflow => CollectionAllocErr::CapacityOverflow, + hashbrown::CollectionAllocErr::AllocErr => CollectionAllocErr::AllocErr, } +} - #[inline] - fn replace(&mut self, key: K) -> Option { - self.reserve(1); - - match self.entry(key) { - Occupied(mut occupied) => { - let key = occupied.take_key().unwrap(); - Some(mem::replace(occupied.elem.read_mut().0, key)) - } - Vacant(vacant) => { - vacant.insert(()); - None - } - } +#[inline] +fn map_raw_entry<'a, K: 'a, V: 'a, S: 'a>( + raw: base::RawEntryMut<'a, K, V, S>, +) -> RawEntryMut<'a, K, V, S> { + match raw { + base::RawEntryMut::Occupied(base) => RawEntryMut::Occupied(RawOccupiedEntryMut { base }), + base::RawEntryMut::Vacant(base) => RawEntryMut::Vacant(RawVacantEntryMut { base }), } } @@ -3317,23 +2591,29 @@ fn assert_covariance() { fn values_val<'a, 'new>(v: Values<'a, u8, &'static str>) -> Values<'a, u8, &'new str> { v } - fn drain<'new>(d: Drain<'static, &'static str, &'static str>) - -> Drain<'new, &'new str, &'new str> { + fn drain<'new>( + d: Drain<'static, &'static str, &'static str>, + ) -> Drain<'new, &'new str, &'new str> { d } } #[cfg(test)] mod test_map { - use super::HashMap; use super::Entry::{Occupied, Vacant}; + use super::HashMap; use super::RandomState; use crate::cell::RefCell; use rand::{thread_rng, Rng}; use realstd::collections::CollectionAllocErr::*; - use realstd::mem::size_of; use realstd::usize; + // https://github.com/rust-lang/rust/issues/62301 + fn _assert_hashmap_is_unwind_safe() { + fn assert_unwind_safe() {} + assert_unwind_safe::>>(); + } + #[test] fn test_zero_capacities() { type HM = HashMap; @@ -3468,19 +2748,19 @@ mod test_map { DROP_VECTOR.with(|v| { assert_eq!(v.borrow()[i], 1); - assert_eq!(v.borrow()[i+100], 1); + assert_eq!(v.borrow()[i + 100], 1); }); } DROP_VECTOR.with(|v| { for i in 0..50 { assert_eq!(v.borrow()[i], 0); - assert_eq!(v.borrow()[i+100], 0); + assert_eq!(v.borrow()[i + 100], 0); } for i in 50..100 { assert_eq!(v.borrow()[i], 1); - assert_eq!(v.borrow()[i+100], 1); + assert_eq!(v.borrow()[i + 100], 1); } }); } @@ -3537,13 +2817,9 @@ mod test_map { for _ in half.by_ref() {} DROP_VECTOR.with(|v| { - let nk = (0..100) - .filter(|&i| v.borrow()[i] == 1) - .count(); + let nk = (0..100).filter(|&i| v.borrow()[i] == 1).count(); - let nv = (0..100) - .filter(|&i| v.borrow()[i + 100] == 1) - .count(); + let nv = (0..100).filter(|&i| v.borrow()[i + 100] == 1).count(); assert_eq!(nk, 50); assert_eq!(nv, 50); @@ -3731,7 +3007,7 @@ mod test_map { fn test_iterate() { let mut m = HashMap::with_capacity(4); for i in 0..32 { - assert!(m.insert(i, i*2).is_none()); + assert!(m.insert(i, i * 2).is_none()); } assert_eq!(m.len(), 32); @@ -3819,85 +3095,10 @@ mod test_map { let map_str = format!("{:?}", map); - assert!(map_str == "{1: 2, 3: 4}" || - map_str == "{3: 4, 1: 2}"); + assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); assert_eq!(format!("{:?}", empty), "{}"); } - #[test] - fn test_expand() { - let mut m = HashMap::new(); - - assert_eq!(m.len(), 0); - assert!(m.is_empty()); - - let mut i = 0; - let old_raw_cap = m.raw_capacity(); - while old_raw_cap == m.raw_capacity() { - m.insert(i, i); - i += 1; - } - - assert_eq!(m.len(), i); - assert!(!m.is_empty()); - } - - #[test] - fn test_behavior_resize_policy() { - let mut m = HashMap::new(); - - assert_eq!(m.len(), 0); - assert_eq!(m.raw_capacity(), 0); - assert!(m.is_empty()); - - m.insert(0, 0); - m.remove(&0); - assert!(m.is_empty()); - let initial_raw_cap = m.raw_capacity(); - m.reserve(initial_raw_cap); - let raw_cap = m.raw_capacity(); - - assert_eq!(raw_cap, initial_raw_cap * 2); - - let mut i = 0; - for _ in 0..raw_cap * 3 / 4 { - m.insert(i, i); - i += 1; - } - // three quarters full - - assert_eq!(m.len(), i); - assert_eq!(m.raw_capacity(), raw_cap); - - for _ in 0..raw_cap / 4 { - m.insert(i, i); - i += 1; - } - // half full - - let new_raw_cap = m.raw_capacity(); - assert_eq!(new_raw_cap, raw_cap * 2); - - for _ in 0..raw_cap / 2 - 1 { - i -= 1; - m.remove(&i); - assert_eq!(m.raw_capacity(), new_raw_cap); - } - // A little more than one quarter full. - m.shrink_to_fit(); - assert_eq!(m.raw_capacity(), raw_cap); - // again, a little more than half full - for _ in 0..raw_cap / 2 - 1 { - i -= 1; - m.remove(&i); - } - m.shrink_to_fit(); - - assert_eq!(m.len(), i); - assert!(!m.is_empty()); - assert_eq!(m.raw_capacity(), initial_raw_cap); - } - #[test] fn test_reserve_shrink_to_fit() { let mut m = HashMap::new(); @@ -4038,7 +3239,6 @@ mod test_map { assert_eq!(map.get(&1).unwrap(), &100); assert_eq!(map.len(), 6); - // Existing key (update) match map.entry(2) { Vacant(_) => unreachable!(), @@ -4061,7 +3261,6 @@ mod test_map { assert_eq!(map.get(&3), None); assert_eq!(map.len(), 5); - // Inexistent key (insert) match map.entry(10) { Occupied(_) => unreachable!(), @@ -4076,11 +3275,10 @@ mod test_map { #[test] fn test_entry_take_doesnt_corrupt() { #![allow(deprecated)] //rand - // Test for #19292 + // Test for #19292 fn check(m: &HashMap) { for k in m.keys() { - assert!(m.contains_key(k), - "{} is in keys() but not in the map?", k); + assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); } } @@ -4185,7 +3383,7 @@ mod test_map { #[test] fn test_retain() { - let mut map: HashMap = (0..100).map(|x|(x, x*10)).collect(); + let mut map: HashMap = (0..100).map(|x| (x, x * 10)).collect(); map.retain(|&k, _| k % 2 == 0); assert_eq!(map.len(), 50); @@ -4194,51 +3392,20 @@ mod test_map { assert_eq!(map[&6], 60); } - #[test] - fn test_adaptive() { - const TEST_LEN: usize = 5000; - // by cloning we get maps with the same hasher seed - let mut first = HashMap::new(); - let mut second = first.clone(); - first.extend((0..TEST_LEN).map(|i| (i, i))); - second.extend((TEST_LEN..TEST_LEN * 2).map(|i| (i, i))); - - for (&k, &v) in &second { - let prev_cap = first.capacity(); - let expect_grow = first.len() == prev_cap; - first.insert(k, v); - if !expect_grow && first.capacity() != prev_cap { - return; - } - } - panic!("Adaptive early resize failed"); - } - #[test] fn test_try_reserve() { - - let mut empty_bytes: HashMap = HashMap::new(); + let mut empty_bytes: HashMap = HashMap::new(); const MAX_USIZE: usize = usize::MAX; - // HashMap and RawTables use complicated size calculations - // hashes_size is sizeof(HashUint) * capacity; - // pairs_size is sizeof((K. V)) * capacity; - // alignment_hashes_size is 8 - // alignment_pairs size is 4 - let size_of_multiplier = (size_of::() + size_of::<(u8, u8)>()).next_power_of_two(); - // The following formula is used to calculate the new capacity - let max_no_ovf = ((MAX_USIZE / 11) * 10) / size_of_multiplier - 1; - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { - } else { panic!("usize::MAX should trigger an overflow!"); } + } else { + panic!("usize::MAX should trigger an overflow!"); + } - if size_of::() < 8 { - if let Err(CapacityOverflow) = empty_bytes.try_reserve(max_no_ovf) { - } else { panic!("isize::MAX + 1 should trigger a CapacityOverflow!") } + if let Err(AllocErr) = empty_bytes.try_reserve(MAX_USIZE / 8) { } else { - if let Err(AllocErr) = empty_bytes.try_reserve(max_no_ovf) { - } else { panic!("isize::MAX + 1 should trigger an OOM!") } + panic!("usize::MAX / 8 should trigger an OOM!") } } @@ -4268,9 +3435,14 @@ mod test_map { } let hash1 = compute_hash(&map, 1); assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100)); - assert_eq!(map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), (&1, &100)); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), (&1, &100)); - assert_eq!(map.raw_entry().search_bucket(hash1, |k| *k == 1).unwrap(), (&1, &100)); + assert_eq!( + map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), + (&1, &100) + ); + assert_eq!( + map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), + (&1, &100) + ); assert_eq!(map.len(), 6); // Existing key (update) @@ -4284,9 +3456,14 @@ mod test_map { } let hash2 = compute_hash(&map, 2); assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200)); - assert_eq!(map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), (&2, &200)); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), (&2, &200)); - assert_eq!(map.raw_entry().search_bucket(hash2, |k| *k == 2).unwrap(), (&2, &200)); + assert_eq!( + map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), + (&2, &200) + ); + assert_eq!( + map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), + (&2, &200) + ); assert_eq!(map.len(), 6); // Existing key (take) @@ -4300,10 +3477,8 @@ mod test_map { assert_eq!(map.raw_entry().from_key(&3), None); assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None); assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None); - assert_eq!(map.raw_entry().search_bucket(hash3, |k| *k == 3), None); assert_eq!(map.len(), 5); - // Nonexistent key (insert) match map.raw_entry_mut().from_key(&10) { Occupied(_) => unreachable!(), @@ -4323,7 +3498,6 @@ mod test_map { assert_eq!(map.raw_entry().from_key(&k), kv); assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); - assert_eq!(map.raw_entry().search_bucket(hash, |q| *q == k), kv); match map.raw_entry_mut().from_key(&k) { Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), @@ -4337,10 +3511,6 @@ mod test_map { Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), Vacant(_) => assert_eq!(v, None), } - match map.raw_entry_mut().search_bucket(hash, |q| *q == k) { - Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), - Vacant(_) => assert_eq!(v, None), - } } } diff --git a/src/libstd/collections/hash/mod.rs b/src/libstd/collections/hash/mod.rs index 0d1bbb590db9e..a6d89a4d32abf 100644 --- a/src/libstd/collections/hash/mod.rs +++ b/src/libstd/collections/hash/mod.rs @@ -1,14 +1,5 @@ //! Unordered containers, implemented as hash-tables mod bench; -mod table; pub mod map; pub mod set; - -trait Recover { - type Key; - - fn get(&self, key: &Q) -> Option<&Self::Key>; - fn take(&mut self, key: &Q) -> Option; - fn replace(&mut self, key: Self::Key) -> Option; -} diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 8a599c11b2095..403914c070780 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -1,14 +1,14 @@ use crate::borrow::Borrow; +use crate::collections::CollectionAllocErr; use crate::fmt; use crate::hash::{Hash, BuildHasher}; use crate::iter::{Chain, FromIterator, FusedIterator}; use crate::ops::{BitOr, BitAnd, BitXor, Sub}; -use super::Recover; use super::map::{self, HashMap, Keys, RandomState}; // Future Optimization (FIXME!) -// ============================= +// ============================ // // Iteration over zero sized values is a noop. There is no need // for `bucket.val` in the case of HashSet. I suppose we would need HKT @@ -181,8 +181,9 @@ impl HashSet { /// println!("{}", x); /// } /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, T> { Iter { iter: self.map.keys() } } @@ -198,6 +199,7 @@ impl HashSet { /// v.insert(1); /// assert_eq!(v.len(), 1); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { self.map.len() @@ -215,6 +217,7 @@ impl HashSet { /// v.insert(1); /// assert!(!v.is_empty()); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_empty(&self) -> bool { self.map.is_empty() @@ -239,7 +242,7 @@ impl HashSet { /// ``` #[inline] #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self) -> Drain { + pub fn drain(&mut self) -> Drain<'_, T> { Drain { iter: self.map.drain() } } @@ -255,6 +258,7 @@ impl HashSet { /// v.clear(); /// assert!(v.is_empty()); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn clear(&mut self) { self.map.clear() @@ -332,6 +336,7 @@ impl HashSet /// let set: HashSet = HashSet::with_hasher(hasher); /// let hasher: &RandomState = set.hasher(); /// ``` + #[inline] #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] pub fn hasher(&self) -> &S { self.map.hasher() @@ -353,11 +358,35 @@ impl HashSet /// set.reserve(10); /// assert!(set.capacity() >= 10); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { self.map.reserve(additional) } + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashSet`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_reserve)] + /// use std::collections::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// ``` + #[inline] + #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + self.map.try_reserve(additional) + } + /// Shrinks the capacity of the set as much as possible. It will drop /// down as much as possible while maintaining the internal rules /// and possibly leaving some space in accordance with the resize policy. @@ -374,6 +403,7 @@ impl HashSet /// set.shrink_to_fit(); /// assert!(set.capacity() >= 2); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { self.map.shrink_to_fit() @@ -430,6 +460,7 @@ impl HashSet /// let diff: HashSet<_> = b.difference(&a).collect(); /// assert_eq!(diff, [4].iter().collect()); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn difference<'a>(&'a self, other: &'a HashSet) -> Difference<'a, T, S> { Difference { @@ -459,6 +490,7 @@ impl HashSet /// assert_eq!(diff1, diff2); /// assert_eq!(diff1, [1, 4].iter().collect()); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet) @@ -484,6 +516,7 @@ impl HashSet /// let intersection: HashSet<_> = a.intersection(&b).collect(); /// assert_eq!(intersection, [2, 3].iter().collect()); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn intersection<'a>(&'a self, other: &'a HashSet) -> Intersection<'a, T, S> { if self.len() <= other.len() { @@ -517,6 +550,7 @@ impl HashSet /// let union: HashSet<_> = a.union(&b).collect(); /// assert_eq!(union, [1, 2, 3, 4].iter().collect()); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn union<'a>(&'a self, other: &'a HashSet) -> Union<'a, T, S> { if self.len() <= other.len() { @@ -548,6 +582,7 @@ impl HashSet /// /// [`Eq`]: ../../std/cmp/trait.Eq.html /// [`Hash`]: ../../std/hash/trait.Hash.html + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn contains(&self, value: &Q) -> bool where T: Borrow, @@ -574,12 +609,69 @@ impl HashSet /// /// [`Eq`]: ../../std/cmp/trait.Eq.html /// [`Hash`]: ../../std/hash/trait.Hash.html + #[inline] #[stable(feature = "set_recovery", since = "1.9.0")] pub fn get(&self, value: &Q) -> Option<&T> where T: Borrow, Q: Hash + Eq { - Recover::get(&self.map, value) + self.map.get_key_value(value).map(|(k, _)| k) + } + + /// Inserts the given `value` into the set if it is not present, then + /// returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// assert_eq!(set.len(), 3); + /// assert_eq!(set.get_or_insert(2), &2); + /// assert_eq!(set.get_or_insert(100), &100); + /// assert_eq!(set.len(), 4); // 100 was inserted + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get_or_insert(&mut self, value: T) -> &T { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.map.raw_entry_mut().from_key(&value).or_insert(value, ()).0 + } + + /// Inserts a value computed from `f` into the set if the given `value` is + /// not present, then returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set: HashSet = ["cat", "dog", "horse"] + /// .iter().map(|&pet| pet.to_owned()).collect(); + /// + /// assert_eq!(set.len(), 3); + /// for &pet in &["cat", "dog", "fish"] { + /// let value = set.get_or_insert_with(pet, str::to_owned); + /// assert_eq!(value, pet); + /// } + /// assert_eq!(set.len(), 4); // a new "fish" was inserted + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T + where T: Borrow, + Q: Hash + Eq, + F: FnOnce(&Q) -> T + { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.map.raw_entry_mut().from_key(value).or_insert_with(|| (f(value), ())).0 } /// Returns `true` if `self` has no elements in common with `other`. @@ -627,7 +719,11 @@ impl HashSet /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_subset(&self, other: &HashSet) -> bool { - self.iter().all(|v| other.contains(v)) + if self.len() <= other.len() { + self.iter().all(|v| other.contains(v)) + } else { + false + } } /// Returns `true` if the set is a superset of another, @@ -673,6 +769,7 @@ impl HashSet /// assert_eq!(set.insert(2), false); /// assert_eq!(set.len(), 1); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()).is_none() @@ -693,9 +790,16 @@ impl HashSet /// set.replace(Vec::with_capacity(10)); /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10); /// ``` + #[inline] #[stable(feature = "set_recovery", since = "1.9.0")] pub fn replace(&mut self, value: T) -> Option { - Recover::replace(&mut self.map, value) + match self.map.entry(value) { + map::Entry::Occupied(occupied) => Some(occupied.replace_key()), + map::Entry::Vacant(vacant) => { + vacant.insert(()); + None + } + } } /// Removes a value from the set. Returns whether the value was @@ -719,6 +823,7 @@ impl HashSet /// /// [`Eq`]: ../../std/cmp/trait.Eq.html /// [`Hash`]: ../../std/hash/trait.Hash.html + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(&mut self, value: &Q) -> bool where T: Borrow, @@ -745,12 +850,13 @@ impl HashSet /// /// [`Eq`]: ../../std/cmp/trait.Eq.html /// [`Hash`]: ../../std/hash/trait.Hash.html + #[inline] #[stable(feature = "set_recovery", since = "1.9.0")] pub fn take(&mut self, value: &Q) -> Option where T: Borrow, Q: Hash + Eq { - Recover::take(&mut self.map, value) + self.map.remove_entry(value).map(|(k, _)| k) } /// Retains only the elements specified by the predicate. @@ -801,7 +907,7 @@ impl fmt::Debug for HashSet where T: Eq + Hash + fmt::Debug, S: BuildHasher { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_set().entries(self.iter()).finish() } } @@ -811,6 +917,7 @@ impl FromIterator for HashSet where T: Eq + Hash, S: BuildHasher + Default { + #[inline] fn from_iter>(iter: I) -> HashSet { let mut set = HashSet::with_hasher(Default::default()); set.extend(iter); @@ -823,6 +930,7 @@ impl Extend for HashSet where T: Eq + Hash, S: BuildHasher { + #[inline] fn extend>(&mut self, iter: I) { self.map.extend(iter.into_iter().map(|k| (k, ()))); } @@ -833,6 +941,7 @@ impl<'a, T, S> Extend<&'a T> for HashSet where T: 'a + Eq + Hash + Copy, S: BuildHasher { + #[inline] fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } @@ -844,13 +953,14 @@ impl Default for HashSet S: BuildHasher + Default { /// Creates an empty `HashSet` with the `Default` value for the hasher. + #[inline] fn default() -> HashSet { HashSet { map: HashMap::default() } } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T, S> BitOr<&'b HashSet> for &'a HashSet +impl BitOr<&HashSet> for &HashSet where T: Eq + Hash + Clone, S: BuildHasher + Default { @@ -882,7 +992,7 @@ impl<'a, 'b, T, S> BitOr<&'b HashSet> for &'a HashSet } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T, S> BitAnd<&'b HashSet> for &'a HashSet +impl BitAnd<&HashSet> for &HashSet where T: Eq + Hash + Clone, S: BuildHasher + Default { @@ -914,7 +1024,7 @@ impl<'a, 'b, T, S> BitAnd<&'b HashSet> for &'a HashSet } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T, S> BitXor<&'b HashSet> for &'a HashSet +impl BitXor<&HashSet> for &HashSet where T: Eq + Hash + Clone, S: BuildHasher + Default { @@ -946,7 +1056,7 @@ impl<'a, 'b, T, S> BitXor<&'b HashSet> for &'a HashSet } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T, S> Sub<&'b HashSet> for &'a HashSet +impl Sub<&HashSet> for &HashSet where T: Eq + Hash + Clone, S: BuildHasher + Default { @@ -1072,6 +1182,7 @@ impl<'a, T, S> IntoIterator for &'a HashSet { type Item = &'a T; type IntoIter = Iter<'a, T>; + #[inline] fn into_iter(self) -> Iter<'a, T> { self.iter() } @@ -1102,6 +1213,7 @@ impl IntoIterator for HashSet { /// println!("{}", x); /// } /// ``` + #[inline] fn into_iter(self) -> IntoIter { IntoIter { iter: self.map.into_iter() } } @@ -1109,6 +1221,7 @@ impl IntoIterator for HashSet { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Iter<'_, K> { + #[inline] fn clone(&self) -> Self { Iter { iter: self.iter.clone() } } @@ -1117,15 +1230,18 @@ impl Clone for Iter<'_, K> { impl<'a, K> Iterator for Iter<'a, K> { type Item = &'a K; + #[inline] fn next(&mut self) -> Option<&'a K> { self.iter.next() } + #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Iter<'_, K> { + #[inline] fn len(&self) -> usize { self.iter.len() } @@ -1135,7 +1251,7 @@ impl FusedIterator for Iter<'_, K> {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Iter<'_, K> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } @@ -1144,15 +1260,18 @@ impl fmt::Debug for Iter<'_, K> { impl Iterator for IntoIter { type Item = K; + #[inline] fn next(&mut self) -> Option { self.iter.next().map(|(k, _)| k) } + #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter { + #[inline] fn len(&self) -> usize { self.iter.len() } @@ -1162,9 +1281,8 @@ impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let entries_iter = self.iter - .inner .iter() .map(|(k, _)| k); f.debug_list().entries(entries_iter).finish() @@ -1175,15 +1293,18 @@ impl fmt::Debug for IntoIter { impl<'a, K> Iterator for Drain<'a, K> { type Item = K; + #[inline] fn next(&mut self) -> Option { self.iter.next().map(|(k, _)| k) } + #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Drain<'_, K> { + #[inline] fn len(&self) -> usize { self.iter.len() } @@ -1193,9 +1314,8 @@ impl FusedIterator for Drain<'_, K> {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Drain<'_, K> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let entries_iter = self.iter - .inner .iter() .map(|(k, _)| k); f.debug_list().entries(entries_iter).finish() @@ -1204,6 +1324,7 @@ impl fmt::Debug for Drain<'_, K> { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Intersection<'_, T, S> { + #[inline] fn clone(&self) -> Self { Intersection { iter: self.iter.clone(), ..*self } } @@ -1216,6 +1337,7 @@ impl<'a, T, S> Iterator for Intersection<'a, T, S> { type Item = &'a T; + #[inline] fn next(&mut self) -> Option<&'a T> { loop { let elt = self.iter.next()?; @@ -1225,6 +1347,7 @@ impl<'a, T, S> Iterator for Intersection<'a, T, S> } } + #[inline] fn size_hint(&self) -> (usize, Option) { let (_, upper) = self.iter.size_hint(); (0, upper) @@ -1236,7 +1359,7 @@ impl fmt::Debug for Intersection<'_, T, S> where T: fmt::Debug + Eq + Hash, S: BuildHasher { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } @@ -1250,6 +1373,7 @@ impl FusedIterator for Intersection<'_, T, S> #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Difference<'_, T, S> { + #[inline] fn clone(&self) -> Self { Difference { iter: self.iter.clone(), ..*self } } @@ -1262,6 +1386,7 @@ impl<'a, T, S> Iterator for Difference<'a, T, S> { type Item = &'a T; + #[inline] fn next(&mut self) -> Option<&'a T> { loop { let elt = self.iter.next()?; @@ -1271,6 +1396,7 @@ impl<'a, T, S> Iterator for Difference<'a, T, S> } } + #[inline] fn size_hint(&self) -> (usize, Option) { let (_, upper) = self.iter.size_hint(); (0, upper) @@ -1289,13 +1415,14 @@ impl fmt::Debug for Difference<'_, T, S> where T: fmt::Debug + Eq + Hash, S: BuildHasher { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } #[stable(feature = "rust1", since = "1.0.0")] impl Clone for SymmetricDifference<'_, T, S> { + #[inline] fn clone(&self) -> Self { SymmetricDifference { iter: self.iter.clone() } } @@ -1308,9 +1435,11 @@ impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> { type Item = &'a T; + #[inline] fn next(&mut self) -> Option<&'a T> { self.iter.next() } + #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } @@ -1328,13 +1457,14 @@ impl fmt::Debug for SymmetricDifference<'_, T, S> where T: fmt::Debug + Eq + Hash, S: BuildHasher { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Union<'_, T, S> { + #[inline] fn clone(&self) -> Self { Union { iter: self.iter.clone() } } @@ -1352,7 +1482,7 @@ impl fmt::Debug for Union<'_, T, S> where T: fmt::Debug + Eq + Hash, S: BuildHasher { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } @@ -1364,9 +1494,11 @@ impl<'a, T, S> Iterator for Union<'a, T, S> { type Item = &'a T; + #[inline] fn next(&mut self) -> Option<&'a T> { self.iter.next() } + #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs deleted file mode 100644 index 31e7a6931356c..0000000000000 --- a/src/libstd/collections/hash/table.rs +++ /dev/null @@ -1,1131 +0,0 @@ -use crate::alloc::{Global, Alloc, Layout, LayoutErr, handle_alloc_error}; -use crate::collections::CollectionAllocErr; -use crate::hash::{BuildHasher, Hash, Hasher}; -use crate::marker; -use crate::mem::{self, size_of, needs_drop}; -use crate::ops::{Deref, DerefMut}; -use crate::ptr::{self, Unique, NonNull}; -use crate::hint; - -use self::BucketState::*; - -/// Integer type used for stored hash values. -/// -/// No more than bit_width(usize) bits are needed to select a bucket. -/// -/// The most significant bit is ours to use for tagging `SafeHash`. -/// -/// (Even if we could have usize::MAX bytes allocated for buckets, -/// each bucket stores at least a `HashUint`, so there can be no more than -/// usize::MAX / size_of(usize) buckets.) -type HashUint = usize; - -const EMPTY_BUCKET: HashUint = 0; -const EMPTY: usize = 1; - -/// Special `Unique` that uses the lower bit of the pointer -/// to expose a boolean tag. -/// Note: when the pointer is initialized to EMPTY `.ptr()` will return -/// null and the tag functions shouldn't be used. -struct TaggedHashUintPtr(Unique); - -impl TaggedHashUintPtr { - #[inline] - unsafe fn new(ptr: *mut HashUint) -> Self { - debug_assert!(ptr as usize & 1 == 0 || ptr as usize == EMPTY as usize); - TaggedHashUintPtr(Unique::new_unchecked(ptr)) - } - - #[inline] - fn set_tag(&mut self, value: bool) { - let mut usize_ptr = self.0.as_ptr() as usize; - unsafe { - if value { - usize_ptr |= 1; - } else { - usize_ptr &= !1; - } - self.0 = Unique::new_unchecked(usize_ptr as *mut HashUint) - } - } - - #[inline] - fn tag(&self) -> bool { - (self.0.as_ptr() as usize) & 1 == 1 - } - - #[inline] - fn ptr(&self) -> *mut HashUint { - (self.0.as_ptr() as usize & !1) as *mut HashUint - } -} - -/// The raw hashtable, providing safe-ish access to the unzipped and highly -/// optimized arrays of hashes, and key-value pairs. -/// -/// This design is a lot faster than the naive -/// `Vec>`, because we don't pay for the overhead of an -/// option on every element, and we get a generally more cache-aware design. -/// -/// Essential invariants of this structure: -/// -/// - if `t.hashes[i] == EMPTY_BUCKET`, then `Bucket::at_index(&t, i).raw` -/// points to 'undefined' contents. Don't read from it. This invariant is -/// enforced outside this module with the `EmptyBucket`, `FullBucket`, -/// and `SafeHash` types. -/// -/// - An `EmptyBucket` is only constructed at an index with -/// a hash of EMPTY_BUCKET. -/// -/// - A `FullBucket` is only constructed at an index with a -/// non-EMPTY_BUCKET hash. -/// -/// - A `SafeHash` is only constructed for non-`EMPTY_BUCKET` hash. We get -/// around hashes of zero by changing them to 0x8000_0000_0000_0000, -/// which will likely map to the same bucket, while not being confused -/// with "empty". -/// -/// - Both "arrays represented by pointers" are the same length: -/// `capacity`. This is set at creation and never changes. The arrays -/// are unzipped and are more cache aware (scanning through 8 hashes -/// brings in at most 2 cache lines, since they're all right beside each -/// other). This layout may waste space in padding such as in a map from -/// u64 to u8, but is a more cache conscious layout as the key-value pairs -/// are only very shortly probed and the desired value will be in the same -/// or next cache line. -/// -/// You can kind of think of this module/data structure as a safe wrapper -/// around just the "table" part of the hashtable. It enforces some -/// invariants at the type level and employs some performance trickery, -/// but in general is just a tricked out `Vec>`. -/// -/// The hashtable also exposes a special boolean tag. The tag defaults to false -/// when the RawTable is created and is accessible with the `tag` and `set_tag` -/// functions. -pub struct RawTable { - capacity_mask: usize, - size: usize, - hashes: TaggedHashUintPtr, - - // Because K/V do not appear directly in any of the types in the struct, - // inform rustc that in fact instances of K and V are reachable from here. - marker: marker::PhantomData<(K, V)>, -} - -// An unsafe view of a RawTable bucket -// Valid indexes are within [0..table_capacity) -pub struct RawBucket { - hash_start: *mut HashUint, - // We use *const to ensure covariance with respect to K and V - pair_start: *const (K, V), - idx: usize, - _marker: marker::PhantomData<(K, V)>, -} - -impl Copy for RawBucket {} -impl Clone for RawBucket { - fn clone(&self) -> RawBucket { - *self - } -} - -pub struct Bucket { - raw: RawBucket, - table: M, -} - -impl Copy for Bucket {} -impl Clone for Bucket { - fn clone(&self) -> Bucket { - *self - } -} - -pub struct EmptyBucket { - raw: RawBucket, - table: M, -} - -pub struct FullBucket { - raw: RawBucket, - table: M, -} - -pub type FullBucketMut<'table, K, V> = FullBucket>; - -pub enum BucketState { - Empty(EmptyBucket), - Full(FullBucket), -} - -// A GapThenFull encapsulates the state of two consecutive buckets at once. -// The first bucket, called the gap, is known to be empty. -// The second bucket is full. -pub struct GapThenFull { - gap: EmptyBucket, - full: FullBucket, -} - -/// A hash that is not zero, since we use a hash of zero to represent empty -/// buckets. -#[derive(PartialEq, Copy, Clone)] -pub struct SafeHash { - hash: HashUint, -} - -impl SafeHash { - /// Peek at the hash value, which is guaranteed to be non-zero. - #[inline(always)] - pub fn inspect(&self) -> HashUint { - self.hash - } - - #[inline(always)] - pub fn new(hash: u64) -> Self { - // We need to avoid 0 in order to prevent collisions with - // EMPTY_HASH. We can maintain our precious uniform distribution - // of initial indexes by unconditionally setting the MSB, - // effectively reducing the hashes by one bit. - // - // Truncate hash to fit in `HashUint`. - let hash_bits = size_of::() * 8; - SafeHash { hash: (1 << (hash_bits - 1)) | (hash as HashUint) } - } -} - -/// We need to remove hashes of 0. That's reserved for empty buckets. -/// This function wraps up `hash_keyed` to be the only way outside this -/// module to generate a SafeHash. -pub fn make_hash(hash_state: &S, t: &T) -> SafeHash - where T: Hash, - S: BuildHasher -{ - let mut state = hash_state.build_hasher(); - t.hash(&mut state); - SafeHash::new(state.finish()) -} - -// `replace` casts a `*HashUint` to a `*SafeHash`. Since we statically -// ensure that a `FullBucket` points to an index with a non-zero hash, -// and a `SafeHash` is just a `HashUint` with a different name, this is -// safe. -// -// This test ensures that a `SafeHash` really IS the same size as a -// `HashUint`. If you need to change the size of `SafeHash` (and -// consequently made this test fail), `replace` needs to be -// modified to no longer assume this. -#[test] -fn can_alias_safehash_as_hash() { - assert_eq!(size_of::(), size_of::()) -} - -// RawBucket methods are unsafe as it's possible to -// make a RawBucket point to invalid memory using safe code. -impl RawBucket { - unsafe fn hash(&self) -> *mut HashUint { - self.hash_start.add(self.idx) - } - unsafe fn pair(&self) -> *mut (K, V) { - self.pair_start.add(self.idx) as *mut (K, V) - } - unsafe fn hash_pair(&self) -> (*mut HashUint, *mut (K, V)) { - (self.hash(), self.pair()) - } -} - -// Buckets hold references to the table. -impl FullBucket { - /// Borrow a reference to the table. - pub fn table(&self) -> &M { - &self.table - } - /// Borrow a mutable reference to the table. - pub fn table_mut(&mut self) -> &mut M { - &mut self.table - } - /// Move out the reference to the table. - pub fn into_table(self) -> M { - self.table - } - /// Gets the raw index. - pub fn index(&self) -> usize { - self.raw.idx - } - /// Gets the raw bucket. - pub fn raw(&self) -> RawBucket { - self.raw - } -} - -impl EmptyBucket { - /// Borrow a reference to the table. - pub fn table(&self) -> &M { - &self.table - } - /// Borrow a mutable reference to the table. - pub fn table_mut(&mut self) -> &mut M { - &mut self.table - } -} - -impl Bucket { - /// Gets the raw index. - pub fn index(&self) -> usize { - self.raw.idx - } - /// get the table. - pub fn into_table(self) -> M { - self.table - } -} - -impl Deref for FullBucket - where M: Deref> -{ - type Target = RawTable; - fn deref(&self) -> &RawTable { - &self.table - } -} - -/// `Put` is implemented for types which provide access to a table and cannot be invalidated -/// by filling a bucket. A similar implementation for `Take` is possible. -pub trait Put { - unsafe fn borrow_table_mut(&mut self) -> &mut RawTable; -} - - -impl Put for &mut RawTable { - unsafe fn borrow_table_mut(&mut self) -> &mut RawTable { - *self - } -} - -impl Put for Bucket - where M: Put -{ - unsafe fn borrow_table_mut(&mut self) -> &mut RawTable { - self.table.borrow_table_mut() - } -} - -impl Put for FullBucket - where M: Put -{ - unsafe fn borrow_table_mut(&mut self) -> &mut RawTable { - self.table.borrow_table_mut() - } -} - -impl>> Bucket { - #[inline] - pub fn new(table: M, hash: SafeHash) -> Bucket { - Bucket::at_index(table, hash.inspect() as usize) - } - - pub fn new_from(r: RawBucket, t: M) - -> Bucket - { - Bucket { - raw: r, - table: t, - } - } - - #[inline] - pub fn at_index(table: M, ib_index: usize) -> Bucket { - // if capacity is 0, then the RawBucket will be populated with bogus pointers. - // This is an uncommon case though, so avoid it in release builds. - debug_assert!(table.capacity() > 0, - "Table should have capacity at this point"); - let ib_index = ib_index & table.capacity_mask; - Bucket { - raw: table.raw_bucket_at(ib_index), - table, - } - } - - pub fn first(table: M) -> Bucket { - Bucket { - raw: table.raw_bucket_at(0), - table, - } - } - - // "So a few of the first shall be last: for many be called, - // but few chosen." - // - // We'll most likely encounter a few buckets at the beginning that - // have their initial buckets near the end of the table. They were - // placed at the beginning as the probe wrapped around the table - // during insertion. We must skip forward to a bucket that won't - // get reinserted too early and won't unfairly steal others spot. - // This eliminates the need for robin hood. - pub fn head_bucket(table: M) -> Bucket { - let mut bucket = Bucket::first(table); - - loop { - bucket = match bucket.peek() { - Full(full) => { - if full.displacement() == 0 { - // This bucket occupies its ideal spot. - // It indicates the start of another "cluster". - bucket = full.into_bucket(); - break; - } - // Leaving this bucket in the last cluster for later. - full.into_bucket() - } - Empty(b) => { - // Encountered a hole between clusters. - b.into_bucket() - } - }; - bucket.next(); - } - bucket - } - - /// Reads a bucket at a given index, returning an enum indicating whether - /// it's initialized or not. You need to match on this enum to get - /// the appropriate types to call most of the other functions in - /// this module. - pub fn peek(self) -> BucketState { - match unsafe { *self.raw.hash() } { - EMPTY_BUCKET => { - Empty(EmptyBucket { - raw: self.raw, - table: self.table, - }) - } - _ => { - Full(FullBucket { - raw: self.raw, - table: self.table, - }) - } - } - } - - /// Modifies the bucket in place to make it point to the next slot. - pub fn next(&mut self) { - self.raw.idx = self.raw.idx.wrapping_add(1) & self.table.capacity_mask; - } - - /// Modifies the bucket in place to make it point to the previous slot. - pub fn prev(&mut self) { - self.raw.idx = self.raw.idx.wrapping_sub(1) & self.table.capacity_mask; - } -} - -impl>> EmptyBucket { - #[inline] - pub fn next(self) -> Bucket { - let mut bucket = self.into_bucket(); - bucket.next(); - bucket - } - - #[inline] - pub fn into_bucket(self) -> Bucket { - Bucket { - raw: self.raw, - table: self.table, - } - } - - pub fn gap_peek(self) -> Result, Bucket> { - let gap = EmptyBucket { - raw: self.raw, - table: (), - }; - - match self.next().peek() { - Full(bucket) => { - Ok(GapThenFull { - gap, - full: bucket, - }) - } - Empty(e) => Err(e.into_bucket()), - } - } -} - -impl EmptyBucket - where M: Put -{ - /// Puts given key and value pair, along with the key's hash, - /// into this bucket in the hashtable. Note how `self` is 'moved' into - /// this function, because this slot will no longer be empty when - /// we return! A `FullBucket` is returned for later use, pointing to - /// the newly-filled slot in the hashtable. - /// - /// Use `make_hash` to construct a `SafeHash` to pass to this function. - pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket { - unsafe { - *self.raw.hash() = hash.inspect(); - ptr::write(self.raw.pair(), (key, value)); - - self.table.borrow_table_mut().size += 1; - } - - FullBucket { - raw: self.raw, - table: self.table, - } - } -} - -impl>> FullBucket { - #[inline] - pub fn next(self) -> Bucket { - let mut bucket = self.into_bucket(); - bucket.next(); - bucket - } - - #[inline] - pub fn into_bucket(self) -> Bucket { - Bucket { - raw: self.raw, - table: self.table, - } - } - - /// Duplicates the current position. This can be useful for operations - /// on two or more buckets. - pub fn stash(self) -> FullBucket { - FullBucket { - raw: self.raw, - table: self, - } - } - - /// Gets the distance between this bucket and the 'ideal' location - /// as determined by the key's hash stored in it. - /// - /// In the cited blog posts above, this is called the "distance to - /// initial bucket", or DIB. Also known as "probe count". - pub fn displacement(&self) -> usize { - // Calculates the distance one has to travel when going from - // `hash mod capacity` onwards to `idx mod capacity`, wrapping around - // if the destination is not reached before the end of the table. - (self.raw.idx.wrapping_sub(self.hash().inspect() as usize)) & self.table.capacity_mask - } - - #[inline] - pub fn hash(&self) -> SafeHash { - unsafe { SafeHash { hash: *self.raw.hash() } } - } - - /// Gets references to the key and value at a given index. - pub fn read(&self) -> (&K, &V) { - unsafe { - let pair_ptr = self.raw.pair(); - (&(*pair_ptr).0, &(*pair_ptr).1) - } - } -} - -// We take a mutable reference to the table instead of accepting anything that -// implements `DerefMut` to prevent fn `take` from being called on `stash`ed -// buckets. -impl<'t, K, V> FullBucket> { - /// Removes this bucket's key and value from the hashtable. - /// - /// This works similarly to `put`, building an `EmptyBucket` out of the - /// taken bucket. - pub fn take(self) -> (EmptyBucket>, K, V) { - self.table.size -= 1; - - unsafe { - *self.raw.hash() = EMPTY_BUCKET; - let (k, v) = ptr::read(self.raw.pair()); - (EmptyBucket { - raw: self.raw, - table: self.table, - }, - k, - v) - } - } -} - -// This use of `Put` is misleading and restrictive, but safe and sufficient for our use cases -// where `M` is a full bucket or table reference type with mutable access to the table. -impl FullBucket - where M: Put -{ - pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) { - unsafe { - let old_hash = ptr::replace(self.raw.hash() as *mut SafeHash, h); - let (old_key, old_val) = ptr::replace(self.raw.pair(), (k, v)); - - (old_hash, old_key, old_val) - } - } -} - -impl FullBucket - where M: Deref> + DerefMut -{ - /// Gets mutable references to the key and value at a given index. - pub fn read_mut(&mut self) -> (&mut K, &mut V) { - unsafe { - let pair_ptr = self.raw.pair(); - (&mut (*pair_ptr).0, &mut (*pair_ptr).1) - } - } -} - -impl<'t, K, V, M> FullBucket - where M: Deref> + 't -{ - /// Exchange a bucket state for immutable references into the table. - /// Because the underlying reference to the table is also consumed, - /// no further changes to the structure of the table are possible; - /// in exchange for this, the returned references have a longer lifetime - /// than the references returned by `read()`. - pub fn into_refs(self) -> (&'t K, &'t V) { - unsafe { - let pair_ptr = self.raw.pair(); - (&(*pair_ptr).0, &(*pair_ptr).1) - } - } -} - -impl<'t, K, V, M> FullBucket - where M: Deref> + DerefMut + 't -{ - /// This works similarly to `into_refs`, exchanging a bucket state - /// for mutable references into the table. - pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) { - unsafe { - let pair_ptr = self.raw.pair(); - (&mut (*pair_ptr).0, &mut (*pair_ptr).1) - } - } -} - -impl GapThenFull - where M: Deref> -{ - #[inline] - pub fn full(&self) -> &FullBucket { - &self.full - } - - pub fn into_table(self) -> M { - self.full.into_table() - } - - pub fn shift(mut self) -> Result, Bucket> { - unsafe { - let (gap_hash, gap_pair) = self.gap.raw.hash_pair(); - let (full_hash, full_pair) = self.full.raw.hash_pair(); - *gap_hash = mem::replace(&mut *full_hash, EMPTY_BUCKET); - ptr::copy_nonoverlapping(full_pair, gap_pair, 1); - } - - let FullBucket { raw: prev_raw, .. } = self.full; - - match self.full.next().peek() { - Full(bucket) => { - self.gap.raw = prev_raw; - - self.full = bucket; - - Ok(self) - } - Empty(b) => Err(b.into_bucket()), - } - } -} - -// Returns a Layout which describes the allocation required for a hash table, -// and the offset of the array of (key, value) pairs in the allocation. -#[inline(always)] -fn calculate_layout(capacity: usize) -> Result<(Layout, usize), LayoutErr> { - let hashes = Layout::array::(capacity)?; - let pairs = Layout::array::<(K, V)>(capacity)?; - hashes.extend(pairs).map(|(layout, _)| { - // LLVM seems to have trouble properly const-propagating pairs.align(), - // possibly due to the use of NonZeroUsize. This little hack allows it - // to generate optimal code. - // - // See https://github.com/rust-lang/rust/issues/51346 for more details. - ( - layout, - hashes.size() + hashes.padding_needed_for(mem::align_of::<(K, V)>()), - ) - }) -} - -pub(crate) enum Fallibility { - Fallible, - Infallible, -} - -use self::Fallibility::*; - -impl RawTable { - /// Does not initialize the buckets. The caller should ensure they, - /// at the very least, set every hash to EMPTY_BUCKET. - /// Returns an error if it cannot allocate or capacity overflows. - unsafe fn new_uninitialized_internal( - capacity: usize, - fallibility: Fallibility, - ) -> Result, CollectionAllocErr> { - if capacity == 0 { - return Ok(RawTable { - size: 0, - capacity_mask: capacity.wrapping_sub(1), - hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint), - marker: marker::PhantomData, - }); - } - - // Allocating hashmaps is a little tricky. We need to allocate two - // arrays, but since we know their sizes and alignments up front, - // we just allocate a single array, and then have the subarrays - // point into it. - let (layout, _) = calculate_layout::(capacity)?; - let buffer = Global.alloc(layout).map_err(|e| match fallibility { - Infallible => handle_alloc_error(layout), - Fallible => e, - })?; - - Ok(RawTable { - capacity_mask: capacity.wrapping_sub(1), - size: 0, - hashes: TaggedHashUintPtr::new(buffer.cast().as_ptr()), - marker: marker::PhantomData, - }) - } - - /// Does not initialize the buckets. The caller should ensure they, - /// at the very least, set every hash to EMPTY_BUCKET. - unsafe fn new_uninitialized(capacity: usize) -> RawTable { - match Self::new_uninitialized_internal(capacity, Infallible) { - Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => unreachable!(), - Ok(table) => { table } - } - } - - #[inline(always)] - fn raw_bucket_at(&self, index: usize) -> RawBucket { - let (_, pairs_offset) = calculate_layout::(self.capacity()) - .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); - let buffer = self.hashes.ptr() as *mut u8; - unsafe { - RawBucket { - hash_start: buffer as *mut HashUint, - pair_start: buffer.add(pairs_offset) as *const (K, V), - idx: index, - _marker: marker::PhantomData, - } - } - } - - #[inline] - fn new_internal( - capacity: usize, - fallibility: Fallibility, - ) -> Result, CollectionAllocErr> { - unsafe { - let ret = RawTable::new_uninitialized_internal(capacity, fallibility)?; - if capacity > 0 { - ptr::write_bytes(ret.hashes.ptr(), 0, capacity); - } - Ok(ret) - } - } - - /// Tries to create a new raw table from a given capacity. If it cannot allocate, - /// it returns with AllocErr. - #[inline] - pub fn try_new(capacity: usize) -> Result, CollectionAllocErr> { - Self::new_internal(capacity, Fallible) - } - - /// Creates a new raw table from a given capacity. All buckets are - /// initially empty. - #[inline] - pub fn new(capacity: usize) -> RawTable { - match Self::new_internal(capacity, Infallible) { - Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => unreachable!(), - Ok(table) => { table } - } - } - - /// The hashtable's capacity, similar to a vector's. - pub fn capacity(&self) -> usize { - self.capacity_mask.wrapping_add(1) - } - - /// The number of elements ever `put` in the hashtable, minus the number - /// of elements ever `take`n. - pub fn size(&self) -> usize { - self.size - } - - fn raw_buckets(&self) -> RawBuckets { - RawBuckets { - raw: self.raw_bucket_at(0), - elems_left: self.size, - marker: marker::PhantomData, - } - } - - pub fn iter(&self) -> Iter { - Iter { - iter: self.raw_buckets(), - } - } - - pub fn iter_mut(&mut self) -> IterMut { - IterMut { - iter: self.raw_buckets(), - _marker: marker::PhantomData, - } - } - - pub fn into_iter(self) -> IntoIter { - let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); - // Replace the marker regardless of lifetime bounds on parameters. - IntoIter { - iter: RawBuckets { - raw, - elems_left, - marker: marker::PhantomData, - }, - table: self, - } - } - - pub fn drain(&mut self) -> Drain { - let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); - // Replace the marker regardless of lifetime bounds on parameters. - Drain { - iter: RawBuckets { - raw, - elems_left, - marker: marker::PhantomData, - }, - table: NonNull::from(self), - marker: marker::PhantomData, - } - } - - /// Drops buckets in reverse order. It leaves the table in an inconsistent - /// state and should only be used for dropping the table's remaining - /// entries. It's used in the implementation of Drop. - unsafe fn rev_drop_buckets(&mut self) { - // initialize the raw bucket past the end of the table - let mut raw = self.raw_bucket_at(self.capacity()); - let mut elems_left = self.size; - - while elems_left != 0 { - raw.idx -= 1; - - if *raw.hash() != EMPTY_BUCKET { - elems_left -= 1; - ptr::drop_in_place(raw.pair()); - } - } - } - - /// Sets the table tag. - pub fn set_tag(&mut self, value: bool) { - self.hashes.set_tag(value) - } - - /// Gets the table tag. - pub fn tag(&self) -> bool { - self.hashes.tag() - } -} - -/// A raw iterator. The basis for some other iterators in this module. Although -/// this interface is safe, it's not used outside this module. -struct RawBuckets<'a, K, V> { - raw: RawBucket, - elems_left: usize, - - // Strictly speaking, this should be &'a (K,V), but that would - // require that K:'a, and we often use RawBuckets<'static...> for - // move iterations, so that messes up a lot of other things. So - // just use `&'a (K,V)` as this is not a publicly exposed type - // anyway. - marker: marker::PhantomData<&'a ()>, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -impl Clone for RawBuckets<'_, K, V> { - fn clone(&self) -> Self { - RawBuckets { - raw: self.raw, - elems_left: self.elems_left, - marker: marker::PhantomData, - } - } -} - - -impl<'a, K, V> Iterator for RawBuckets<'a, K, V> { - type Item = RawBucket; - - fn next(&mut self) -> Option> { - if self.elems_left == 0 { - return None; - } - - loop { - unsafe { - let item = self.raw; - self.raw.idx += 1; - if *item.hash() != EMPTY_BUCKET { - self.elems_left -= 1; - return Some(item); - } - } - } - } - - fn size_hint(&self) -> (usize, Option) { - (self.elems_left, Some(self.elems_left)) - } -} - -impl ExactSizeIterator for RawBuckets<'_, K, V> { - fn len(&self) -> usize { - self.elems_left - } -} - -/// Iterator over shared references to entries in a table. -pub struct Iter<'a, K: 'a, V: 'a> { - iter: RawBuckets<'a, K, V>, -} - -unsafe impl Sync for Iter<'_, K, V> {} -unsafe impl Send for Iter<'_, K, V> {} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -impl Clone for Iter<'_, K, V> { - fn clone(&self) -> Self { - Iter { - iter: self.iter.clone(), - } - } -} - -/// Iterator over mutable references to entries in a table. -pub struct IterMut<'a, K: 'a, V: 'a> { - iter: RawBuckets<'a, K, V>, - // To ensure invariance with respect to V - _marker: marker::PhantomData<&'a mut V>, -} - -unsafe impl Sync for IterMut<'_, K, V> {} -// Both K: Sync and K: Send are correct for IterMut's Send impl, -// but Send is the more useful bound -unsafe impl Send for IterMut<'_, K, V> {} - -impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> { - pub fn iter(&self) -> Iter { - Iter { - iter: self.iter.clone(), - } - } -} - -/// Iterator over the entries in a table, consuming the table. -pub struct IntoIter { - table: RawTable, - iter: RawBuckets<'static, K, V>, -} - -unsafe impl Sync for IntoIter {} -unsafe impl Send for IntoIter {} - -impl IntoIter { - pub fn iter(&self) -> Iter { - Iter { - iter: self.iter.clone(), - } - } -} - -/// Iterator over the entries in a table, clearing the table. -pub struct Drain<'a, K: 'a, V: 'a> { - table: NonNull>, - iter: RawBuckets<'static, K, V>, - marker: marker::PhantomData<&'a RawTable>, -} - -unsafe impl Sync for Drain<'_, K, V> {} -unsafe impl Send for Drain<'_, K, V> {} - -impl<'a, K, V> Drain<'a, K, V> { - pub fn iter(&self) -> Iter { - Iter { - iter: self.iter.clone(), - } - } -} - -impl<'a, K, V> Iterator for Iter<'a, K, V> { - type Item = (&'a K, &'a V); - - fn next(&mut self) -> Option<(&'a K, &'a V)> { - self.iter.next().map(|raw| unsafe { - let pair_ptr = raw.pair(); - (&(*pair_ptr).0, &(*pair_ptr).1) - }) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Iter<'_, K, V> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl<'a, K, V> Iterator for IterMut<'a, K, V> { - type Item = (&'a K, &'a mut V); - - fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - self.iter.next().map(|raw| unsafe { - let pair_ptr = raw.pair(); - (&(*pair_ptr).0, &mut (*pair_ptr).1) - }) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for IterMut<'_, K, V> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl Iterator for IntoIter { - type Item = (SafeHash, K, V); - - fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|raw| { - self.table.size -= 1; - unsafe { - let (k, v) = ptr::read(raw.pair()); - (SafeHash { hash: *raw.hash() }, k, v) - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for IntoIter { - fn len(&self) -> usize { - self.iter().len() - } -} - -impl<'a, K, V> Iterator for Drain<'a, K, V> { - type Item = (SafeHash, K, V); - - #[inline] - fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|raw| { - unsafe { - self.table.as_mut().size -= 1; - let (k, v) = ptr::read(raw.pair()); - (SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v) - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Drain<'_, K, V> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl Drop for Drain<'_, K, V> { - fn drop(&mut self) { - self.for_each(drop); - } -} - -impl Clone for RawTable { - fn clone(&self) -> RawTable { - unsafe { - let cap = self.capacity(); - let mut new_ht = RawTable::new_uninitialized(cap); - - let mut new_buckets = new_ht.raw_bucket_at(0); - let mut buckets = self.raw_bucket_at(0); - while buckets.idx < cap { - *new_buckets.hash() = *buckets.hash(); - if *new_buckets.hash() != EMPTY_BUCKET { - let pair_ptr = buckets.pair(); - let kv = ((*pair_ptr).0.clone(), (*pair_ptr).1.clone()); - ptr::write(new_buckets.pair(), kv); - } - buckets.idx += 1; - new_buckets.idx += 1; - } - - new_ht.size = self.size(); - new_ht.set_tag(self.tag()); - - new_ht - } - } -} - -unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { - fn drop(&mut self) { - if self.capacity() == 0 { - return; - } - - // This is done in reverse because we've likely partially taken - // some elements out with `.into_iter()` from the front. - // Check if the size is 0, so we don't do a useless scan when - // dropping empty tables such as on resize. - // Also avoid double drop of elements that have been already moved out. - unsafe { - if needs_drop::<(K, V)>() { - // avoid linear runtime for types that don't need drop - self.rev_drop_buckets(); - } - } - - let (layout, _) = calculate_layout::(self.capacity()) - .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); - unsafe { - Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).cast(), layout); - // Remember how everything was allocated out of one buffer - // during initialization? We only need one call to free here. - } - } -} diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 286ce2d389b8c..15c2532f8b4e0 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -150,10 +150,9 @@ //! Any `with_capacity` constructor will instruct the collection to allocate //! enough space for the specified number of elements. Ideally this will be for //! exactly that many elements, but some implementation details may prevent -//! this. [`Vec`] and [`VecDeque`] can be relied on to allocate exactly the -//! requested amount, though. Use `with_capacity` when you know exactly how many -//! elements will be inserted, or at least have a reasonable upper-bound on that -//! number. +//! this. See collection-specific documentation for details. In general, use +//! `with_capacity` when you know exactly how many elements will be inserted, or +//! at least have a reasonable upper-bound on that number. //! //! When anticipating a large influx of elements, the `reserve` family of //! methods can be used to hint to the collection how much room it should make diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 97c67f562a7df..00e840a53e9c0 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -156,7 +156,7 @@ impl Iterator for Vars { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Vars { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Vars { .. }") } } @@ -170,7 +170,7 @@ impl Iterator for VarsOs { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for VarsOs { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("VarsOs { .. }") } } @@ -253,7 +253,7 @@ pub enum VarError { #[stable(feature = "env", since = "1.0.0")] impl fmt::Display for VarError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { VarError::NotPresent => write!(f, "environment variable not found"), VarError::NotUnicode(ref s) => { @@ -359,9 +359,12 @@ fn _remove_var(k: &OsStr) { /// An iterator that splits an environment variable into paths according to /// platform-specific conventions. /// +/// The iterator element type is [`PathBuf`]. +/// /// This structure is created by the [`std::env::split_paths`] function. See its /// documentation for more. /// +/// [`PathBuf`]: ../../std/path/struct.PathBuf.html /// [`std::env::split_paths`]: fn.split_paths.html #[stable(feature = "env", since = "1.0.0")] pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> } @@ -369,7 +372,8 @@ pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> } /// Parses input according to platform conventions for the `PATH` /// environment variable. /// -/// Returns an iterator over the paths contained in `unparsed`. +/// Returns an iterator over the paths contained in `unparsed`. The iterator +/// element type is [`PathBuf`]. /// /// # Examples /// @@ -386,8 +390,10 @@ pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> } /// None => println!("{} is not defined in the environment.", key) /// } /// ``` +/// +/// [`PathBuf`]: ../../std/path/struct.PathBuf.html #[stable(feature = "env", since = "1.0.0")] -pub fn split_paths + ?Sized>(unparsed: &T) -> SplitPaths { +pub fn split_paths + ?Sized>(unparsed: &T) -> SplitPaths<'_> { SplitPaths { inner: os_imp::split_paths(unparsed.as_ref()) } } @@ -400,7 +406,7 @@ impl<'a> Iterator for SplitPaths<'a> { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for SplitPaths<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("SplitPaths { .. }") } } @@ -459,7 +465,7 @@ pub struct JoinPathsError { /// # } /// ``` /// -/// Using `env::join_paths` with `env::spit_paths` to append an item to the `PATH` environment +/// Using `env::join_paths` with [`env::split_paths`] to append an item to the `PATH` environment /// variable: /// /// ``` @@ -477,6 +483,8 @@ pub struct JoinPathsError { /// Ok(()) /// } /// ``` +/// +/// [`env::split_paths`]: fn.split_paths.html #[stable(feature = "env", since = "1.0.0")] pub fn join_paths(paths: I) -> Result where I: IntoIterator, T: AsRef @@ -488,7 +496,7 @@ pub fn join_paths(paths: I) -> Result #[stable(feature = "env", since = "1.0.0")] impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } @@ -757,7 +765,7 @@ impl DoubleEndedIterator for Args { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Args") .field("inner", &self.inner.inner.inner_debug()) .finish() @@ -790,7 +798,7 @@ impl DoubleEndedIterator for ArgsOs { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for ArgsOs { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ArgsOs") .field("inner", &self.inner.inner_debug()) .finish() @@ -839,7 +847,6 @@ pub mod consts { /// - ios /// - freebsd /// - dragonfly - /// - bitrig /// - netbsd /// - openbsd /// - solaris @@ -975,7 +982,7 @@ mod tests { use crate::path::Path; #[test] - #[cfg_attr(target_os = "emscripten", ignore)] + #[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)] fn test_self_exe_path() { let path = current_exe(); assert!(path.is_ok()); @@ -989,6 +996,7 @@ mod tests { fn test() { assert!((!Path::new("test-path").is_absolute())); + #[cfg(not(target_env = "sgx"))] current_dir().unwrap(); } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 2858308e8f8d5..5b1e78a113917 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -84,7 +84,7 @@ pub trait Error: Debug + Display { /// } /// /// impl fmt::Display for SuperError { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "SuperError is here!") /// } /// } @@ -94,7 +94,7 @@ pub trait Error: Debug + Display { /// "I'm the superhero of errors" /// } /// - /// fn cause(&self) -> Option<&Error> { + /// fn cause(&self) -> Option<&dyn Error> { /// Some(&self.side) /// } /// } @@ -103,7 +103,7 @@ pub trait Error: Debug + Display { /// struct SuperErrorSideKick; /// /// impl fmt::Display for SuperErrorSideKick { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "SuperErrorSideKick is here!") /// } /// } @@ -149,7 +149,7 @@ pub trait Error: Debug + Display { /// } /// /// impl fmt::Display for SuperError { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "SuperError is here!") /// } /// } @@ -168,7 +168,7 @@ pub trait Error: Debug + Display { /// struct SuperErrorSideKick; /// /// impl fmt::Display for SuperErrorSideKick { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "SuperErrorSideKick is here!") /// } /// } @@ -198,16 +198,28 @@ pub trait Error: Debug + Display { /// Gets the `TypeId` of `self` #[doc(hidden)] - #[stable(feature = "error_type_id", since = "1.34.0")] - fn type_id(&self) -> TypeId where Self: 'static { + #[unstable(feature = "error_type_id", + reason = "this is memory unsafe to override in user code", + issue = "60784")] + fn type_id(&self, _: private::Internal) -> TypeId where Self: 'static { TypeId::of::() } } +mod private { + // This is a hack to prevent `type_id` from being overridden by `Error` + // implementations, since that can enable unsound downcasting. + #[unstable(feature = "error_type_id", issue = "60784")] + #[derive(Debug)] + pub struct Internal; +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + 'a> From for Box { /// Converts a type of [`Error`] into a box of dyn [`Error`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -219,7 +231,7 @@ impl<'a, E: Error + 'a> From for Box { /// struct AnError; /// /// impl fmt::Display for AnError { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f , "An error") /// } /// } @@ -232,7 +244,7 @@ impl<'a, E: Error + 'a> From for Box { /// /// let an_error = AnError; /// assert!(0 == mem::size_of_val(&an_error)); - /// let a_boxed_error = Box::::from(an_error); + /// let a_boxed_error = Box::::from(an_error); /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` fn from(err: E) -> Box { @@ -245,6 +257,8 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box From for Box fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f , "An error") /// } /// } @@ -273,7 +287,7 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box::from(an_error); + /// let a_boxed_error = Box::::from(an_error); /// assert!( /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` @@ -286,6 +300,8 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box for Box { /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -293,12 +309,11 @@ impl From for Box { /// use std::mem; /// /// let a_string_error = "a string error".to_string(); - /// let a_boxed_error = Box::::from(a_string_error); + /// let a_boxed_error = Box::::from(a_string_error); /// assert!( /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` fn from(err: String) -> Box { - #[derive(Debug)] struct StringError(String); impl Error for StringError { @@ -306,11 +321,18 @@ impl From for Box { } impl Display for StringError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(&self.0, f) } } + // Purposefully skip printing "StringError(..)" + impl Debug for StringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Debug::fmt(&self.0, f) + } + } + Box::new(StringError(err)) } } @@ -319,6 +341,8 @@ impl From for Box { impl From for Box { /// Converts a [`String`] into a box of dyn [`Error`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -326,7 +350,7 @@ impl From for Box { /// use std::mem; /// /// let a_string_error = "a string error".to_string(); - /// let a_boxed_error = Box::::from(a_string_error); + /// let a_boxed_error = Box::::from(a_string_error); /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` fn from(str_err: String) -> Box { @@ -337,9 +361,11 @@ impl From for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b> From<&'b str> for Box { +impl<'a> From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -347,19 +373,21 @@ impl<'a, 'b> From<&'b str> for Box { /// use std::mem; /// /// let a_str_error = "a str error"; - /// let a_boxed_error = Box::::from(a_str_error); + /// let a_boxed_error = Box::::from(a_str_error); /// assert!( /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` - fn from(err: &'b str) -> Box { + fn from(err: &str) -> Box { From::from(String::from(err)) } } #[stable(feature = "string_box_error", since = "1.6.0")] -impl<'a> From<&'a str> for Box { +impl From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -367,10 +395,10 @@ impl<'a> From<&'a str> for Box { /// use std::mem; /// /// let a_str_error = "a str error"; - /// let a_boxed_error = Box::::from(a_str_error); + /// let a_boxed_error = Box::::from(a_str_error); /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` - fn from(err: &'a str) -> Box { + fn from(err: &str) -> Box { From::from(String::from(err)) } } @@ -379,6 +407,9 @@ impl<'a> From<&'a str> for Box { impl<'a, 'b> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// + /// [`Cow`]: ../borrow/enum.Cow.html + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -387,7 +418,7 @@ impl<'a, 'b> From> for Box { /// use std::borrow::Cow; /// /// let a_cow_str_error = Cow::from("a str error"); - /// let a_boxed_error = Box::::from(a_cow_str_error); + /// let a_boxed_error = Box::::from(a_cow_str_error); /// assert!( /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` @@ -400,6 +431,9 @@ impl<'a, 'b> From> for Box { impl<'a> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`]. /// + /// [`Cow`]: ../borrow/enum.Cow.html + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -408,7 +442,7 @@ impl<'a> From> for Box { /// use std::borrow::Cow; /// /// let a_cow_str_error = Cow::from("a str error"); - /// let a_boxed_error = Box::::from(a_cow_str_error); + /// let a_boxed_error = Box::::from(a_cow_str_error); /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) /// ``` fn from(err: Cow<'a, str>) -> Box { @@ -526,6 +560,10 @@ impl Error for Box { fn cause(&self) -> Option<&dyn Error> { Error::cause(&**self) } + + fn source(&self) -> Option<&(dyn Error + 'static)> { + Error::source(&**self) + } } #[stable(feature = "fmt_error", since = "1.11.0")] @@ -573,7 +611,7 @@ impl dyn Error + 'static { let t = TypeId::of::(); // Get TypeId of the type in the trait object - let boxed = self.type_id(); + let boxed = self.type_id(private::Internal); // Compare both TypeIds on equality t == boxed @@ -686,13 +724,13 @@ impl dyn Error { /// struct B(Option>); /// /// impl fmt::Display for A { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "A") /// } /// } /// /// impl fmt::Display for B { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "B") /// } /// } @@ -721,7 +759,7 @@ impl dyn Error { /// [`source`]: trait.Error.html#method.source #[unstable(feature = "error_iter", issue = "58520")] #[inline] - pub fn iter_chain(&self) -> ErrorIter { + pub fn iter_chain(&self) -> ErrorIter<'_> { ErrorIter { current: Some(self), } @@ -747,19 +785,19 @@ impl dyn Error { /// struct C(Option>); /// /// impl fmt::Display for A { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "A") /// } /// } /// /// impl fmt::Display for B { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "B") /// } /// } /// /// impl fmt::Display for C { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "C") /// } /// } @@ -795,7 +833,7 @@ impl dyn Error { /// [`source`]: trait.Error.html#method.source #[inline] #[unstable(feature = "error_iter", issue = "58520")] - pub fn iter_sources(&self) -> ErrorIter { + pub fn iter_sources(&self) -> ErrorIter<'_> { ErrorIter { current: self.source(), } @@ -861,12 +899,12 @@ mod tests { struct B; impl fmt::Display for A { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "A") } } impl fmt::Display for B { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "B") } } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index f6cd9e82abd40..7254c62161161 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -32,11 +32,13 @@ impl f32 { /// # Examples /// /// ``` - /// let f = 3.99_f32; + /// let f = 3.7_f32; /// let g = 3.0_f32; + /// let h = -3.7_f32; /// /// assert_eq!(f.floor(), 3.0); /// assert_eq!(g.floor(), 3.0); + /// assert_eq!(h.floor(), -4.0); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -104,11 +106,13 @@ impl f32 { /// # Examples /// /// ``` - /// let f = 3.3_f32; - /// let g = -3.7_f32; + /// let f = 3.7_f32; + /// let g = 3.0_f32; + /// let h = -3.7_f32; /// /// assert_eq!(f.trunc(), 3.0); - /// assert_eq!(g.trunc(), -3.0); + /// assert_eq!(g.trunc(), 3.0); + /// assert_eq!(h.trunc(), -3.0); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -184,21 +188,20 @@ impl f32 { if self.is_nan() { NAN } else { - unsafe { intrinsics::copysignf32(1.0, self) } + 1.0_f32.copysign(self) } } /// Returns a number composed of the magnitude of `self` and the sign of - /// `y`. + /// `sign`. /// - /// Equal to `self` if the sign of `self` and `y` are the same, otherwise + /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of - /// `y` is returned. + /// `sign` is returned. /// /// # Examples /// /// ``` - /// #![feature(copysign)] /// use std::f32; /// /// let f = 3.5_f32; @@ -212,9 +215,9 @@ impl f32 { /// ``` #[inline] #[must_use] - #[unstable(feature="copysign", issue="55169")] - pub fn copysign(self, y: f32) -> f32 { - unsafe { intrinsics::copysignf32(self, y) } + #[stable(feature = "copysign", since = "1.35.0")] + pub fn copysign(self, sign: f32) -> f32 { + unsafe { intrinsics::copysignf32(self, sign) } } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding @@ -956,6 +959,38 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + + /// Restrict a value to a certain interval unless it is NaN. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// Not that this function returns NaN if the initial value was NaN as + /// well. + /// + /// # Panics + /// + /// Panics if `min > max`, `min` is NaN, or `max` is NaN. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// assert!((-3.0f32).clamp(-2.0, 1.0) == -2.0); + /// assert!((0.0f32).clamp(-2.0, 1.0) == 0.0); + /// assert!((2.0f32).clamp(-2.0, 1.0) == 1.0); + /// assert!((std::f32::NAN).clamp(-2.0, 1.0).is_nan()); + /// ``` + #[unstable(feature = "clamp", issue = "44095")] + #[inline] + pub fn clamp(self, min: f32, max: f32) -> f32 { + assert!(min <= max); + let mut x = self; + if x < min { x = min; } + if x > max { x = max; } + x + } + } #[cfg(test)] @@ -1556,4 +1591,22 @@ mod tests { assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1); assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2); } + + #[test] + #[should_panic] + fn test_clamp_min_greater_than_max() { + 1.0f32.clamp(3.0, 1.0); + } + + #[test] + #[should_panic] + fn test_clamp_min_is_nan() { + 1.0f32.clamp(NAN, 1.0); + } + + #[test] + #[should_panic] + fn test_clamp_max_is_nan() { + 1.0f32.clamp(3.0, NAN); + } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 8ff97ab828a73..f8bb36ad0a89e 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -32,11 +32,13 @@ impl f64 { /// # Examples /// /// ``` - /// let f = 3.99_f64; + /// let f = 3.7_f64; /// let g = 3.0_f64; + /// let h = -3.7_f64; /// /// assert_eq!(f.floor(), 3.0); /// assert_eq!(g.floor(), 3.0); + /// assert_eq!(h.floor(), -4.0); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -84,11 +86,13 @@ impl f64 { /// # Examples /// /// ``` - /// let f = 3.3_f64; - /// let g = -3.7_f64; + /// let f = 3.7_f64; + /// let g = 3.0_f64; + /// let h = -3.7_f64; /// /// assert_eq!(f.trunc(), 3.0); - /// assert_eq!(g.trunc(), -3.0); + /// assert_eq!(g.trunc(), 3.0); + /// assert_eq!(h.trunc(), -3.0); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -162,21 +166,20 @@ impl f64 { if self.is_nan() { NAN } else { - unsafe { intrinsics::copysignf64(1.0, self) } + 1.0_f64.copysign(self) } } /// Returns a number composed of the magnitude of `self` and the sign of - /// `y`. + /// `sign`. /// - /// Equal to `self` if the sign of `self` and `y` are the same, otherwise + /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of - /// `y` is returned. + /// `sign` is returned. /// /// # Examples /// /// ``` - /// #![feature(copysign)] /// use std::f64; /// /// let f = 3.5_f64; @@ -190,9 +193,9 @@ impl f64 { /// ``` #[inline] #[must_use] - #[unstable(feature="copysign", issue="55169")] - pub fn copysign(self, y: f64) -> f64 { - unsafe { intrinsics::copysignf64(self, y) } + #[stable(feature = "copysign", since = "1.35.0")] + pub fn copysign(self, sign: f64) -> f64 { + unsafe { intrinsics::copysignf64(self, sign) } } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding @@ -878,6 +881,37 @@ impl f64 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + /// Restrict a value to a certain interval unless it is NaN. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// Not that this function returns NaN if the initial value was NaN as + /// well. + /// + /// # Panics + /// + /// Panics if `min > max`, `min` is NaN, or `max` is NaN. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// assert!((-3.0f64).clamp(-2.0, 1.0) == -2.0); + /// assert!((0.0f64).clamp(-2.0, 1.0) == 0.0); + /// assert!((2.0f64).clamp(-2.0, 1.0) == 1.0); + /// assert!((std::f64::NAN).clamp(-2.0, 1.0).is_nan()); + /// ``` + #[unstable(feature = "clamp", issue = "44095")] + #[inline] + pub fn clamp(self, min: f64, max: f64) -> f64 { + assert!(min <= max); + let mut x = self; + if x < min { x = min; } + if x > max { x = max; } + x + } + // Solaris/Illumos requires a wrapper around log, log2, and log10 functions // because of their non-standard behavior (e.g., log(-n) returns -Inf instead // of expected NaN). @@ -1497,4 +1531,22 @@ mod tests { assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1); assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2); } + + #[test] + #[should_panic] + fn test_clamp_min_greater_than_max() { + 1.0f64.clamp(3.0, 1.0); + } + + #[test] + #[should_panic] + fn test_clamp_min_is_nan() { + 1.0f64.clamp(NAN, 1.0); + } + + #[test] + #[should_panic] + fn test_clamp_max_is_nan() { + 1.0f64.clamp(3.0, NAN); + } } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 139680e526fd6..5c6c43017cf64 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -43,7 +43,9 @@ use crate::sys; /// `CString` implements a [`as_ptr`] method through the [`Deref`] /// trait. This method will give you a `*const c_char` which you can /// feed directly to extern functions that expect a nul-terminated -/// string, like C's `strdup()`. +/// string, like C's `strdup()`. Notice that [`as_ptr`] returns a +/// read-only pointer; if the C code writes to it, that causes +/// undefined behavior. /// /// # Extracting a slice of the whole C string /// @@ -61,7 +63,7 @@ use crate::sys; /// /// Once you have the kind of slice you need (with or without a nul /// terminator), you can call the slice's own -/// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to +/// [`as_ptr`][slice.as_ptr] method to get a read-only raw pointer to pass to /// extern functions. See the documentation for that function for a /// discussion on ensuring the lifetime of the raw pointer. /// @@ -628,7 +630,7 @@ impl ops::Deref for CString { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for CString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } @@ -649,7 +651,7 @@ impl From for Vec { #[stable(feature = "cstr_debug", since = "1.3.0")] impl fmt::Debug for CStr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\"")?; for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) { f.write_char(byte as char)?; @@ -690,8 +692,8 @@ impl<'a> From> for CString { } #[stable(feature = "box_from_c_str", since = "1.17.0")] -impl<'a> From<&'a CStr> for Box { - fn from(s: &'a CStr) -> Box { +impl From<&CStr> for Box { + fn from(s: &CStr) -> Box { let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul()); unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) } } @@ -767,7 +769,7 @@ impl From for Arc { } #[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl<'a> From<&'a CStr> for Arc { +impl From<&CStr> for Arc { #[inline] fn from(s: &CStr) -> Arc { let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul()); @@ -789,7 +791,7 @@ impl From for Rc { } #[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl<'a> From<&'a CStr> for Rc { +impl From<&CStr> for Rc { #[inline] fn from(s: &CStr) -> Rc { let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul()); @@ -847,7 +849,7 @@ impl Error for NulError { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for NulError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "nul byte found in provided data at position: {}", self.0) } } @@ -878,7 +880,7 @@ impl Error for FromBytesWithNulError { #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] impl fmt::Display for FromBytesWithNulError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.description())?; if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind { write!(f, " at byte pos {}", pos)?; @@ -917,7 +919,7 @@ impl Error for IntoStringError { #[stable(feature = "cstring_into", since = "1.7.0")] impl fmt::Display for IntoStringError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.description().fmt(f) } } @@ -1043,6 +1045,9 @@ impl CStr { /// /// **WARNING** /// + /// The returned pointer is read-only; writing to it (including passing it + /// to C code that writes to it) causes undefined behavior. + /// /// It is your responsibility to make sure that the underlying memory is not /// freed too early. For example, the following code will cause undefined /// behavior when `ptr` is used inside the `unsafe` block: @@ -1208,11 +1213,11 @@ impl CStr { /// .expect("CStr::from_bytes_with_nul failed"); /// assert_eq!( /// c_str.to_string_lossy(), - /// Cow::Owned(String::from("Hello �World")) as Cow + /// Cow::Owned(String::from("Hello �World")) as Cow<'_, str> /// ); /// ``` #[stable(feature = "cstr_to_str", since = "1.4.0")] - pub fn to_string_lossy(&self) -> Cow { + pub fn to_string_lossy(&self) -> Cow<'_, str> { String::from_utf8_lossy(self.to_bytes()) } @@ -1268,8 +1273,8 @@ impl ToOwned for CStr { } #[stable(feature = "cstring_asref", since = "1.7.0")] -impl<'a> From<&'a CStr> for CString { - fn from(s: &'a CStr) -> CString { +impl From<&CStr> for CString { + fn from(s: &CStr) -> CString { s.to_owned() } } diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index 7a38f0ebd5a57..69fcfa8b39ca5 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -170,7 +170,7 @@ pub use core::ffi::c_void; reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930")] -pub use core::ffi::VaList; +pub use core::ffi::{VaList, VaListImpl}; mod c_str; mod os_str; diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index f68eaeb9c7e1f..c7c5849a00fa0 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -351,14 +351,16 @@ impl From for OsString { /// Converts a [`String`] into a [`OsString`]. /// /// The conversion copies the data, and includes an allocation on the heap. + /// + /// [`OsString`]: ../../std/ffi/struct.OsString.html fn from(s: String) -> OsString { OsString { inner: Buf::from_string(s) } } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized + AsRef> From<&'a T> for OsString { - fn from(s: &'a T) -> OsString { +impl> From<&T> for OsString { + fn from(s: &T) -> OsString { s.as_ref().to_os_string() } } @@ -394,7 +396,7 @@ impl Default for OsString { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for OsString { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, formatter) } } @@ -421,8 +423,8 @@ impl PartialEq for str { } #[stable(feature = "os_str_str_ref_eq", since = "1.29.0")] -impl<'a> PartialEq<&'a str> for OsString { - fn eq(&self, other: &&'a str) -> bool { +impl PartialEq<&str> for OsString { + fn eq(&self, other: &&str) -> bool { **self == **other } } @@ -563,7 +565,7 @@ impl OsStr { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_string_lossy(&self) -> Cow { + pub fn to_string_lossy(&self) -> Cow<'_, str> { self.inner.to_string_lossy() } @@ -656,8 +658,8 @@ impl OsStr { } #[stable(feature = "box_from_os_str", since = "1.17.0")] -impl<'a> From<&'a OsStr> for Box { - fn from(s: &'a OsStr) -> Box { +impl From<&OsStr> for Box { + fn from(s: &OsStr) -> Box { let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr; unsafe { Box::from_raw(rw) } } @@ -707,7 +709,7 @@ impl From for Arc { } #[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl<'a> From<&'a OsStr> for Arc { +impl From<&OsStr> for Arc { #[inline] fn from(s: &OsStr) -> Arc { let arc = s.inner.into_arc(); @@ -729,7 +731,7 @@ impl From for Rc { } #[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl<'a> From<&'a OsStr> for Rc { +impl From<&OsStr> for Rc { #[inline] fn from(s: &OsStr) -> Rc { let rc = s.inner.into_rc(); @@ -891,13 +893,13 @@ impl Hash for OsStr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for OsStr { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.inner, formatter) } } impl OsStr { - pub(crate) fn display(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + pub(crate) fn display(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.inner, formatter) } } @@ -960,6 +962,7 @@ impl IntoInner for OsString { } impl AsInner for OsStr { + #[inline] fn as_inner(&self) -> &Slice { &self.inner } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 25f2dd73504ae..d41b3a3a1233f 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + //! Filesystem manipulation operations. //! //! This module contains basic methods to manipulate the contents of the local @@ -9,7 +11,7 @@ use crate::fmt; use crate::ffi::OsString; -use crate::io::{self, SeekFrom, Seek, Read, Initializer, Write}; +use crate::io::{self, SeekFrom, Seek, Read, Initializer, Write, IoSlice, IoSliceMut}; use crate::path::{Path, PathBuf}; use crate::sys::fs as fs_imp; use crate::sys_common::{AsInnerMut, FromInner, AsInner, IntoInner}; @@ -21,7 +23,9 @@ use crate::time::SystemTime; /// it was opened with. Files also implement [`Seek`] to alter the logical cursor /// that the file contains internally. /// -/// Files are automatically closed when they go out of scope. +/// Files are automatically closed when they go out of scope. Errors detected +/// on closing are ignored by the implementation of `Drop`. Use the method +/// [`sync_all`] if these errors must be manually handled. /// /// # Examples /// @@ -84,6 +88,7 @@ use crate::time::SystemTime; /// [`Read`]: ../io/trait.Read.html /// [`Write`]: ../io/trait.Write.html /// [`BufReader`]: ../io/struct.BufReader.html +/// [`sync_all`]: struct.File.html#method.sync_all #[stable(feature = "rust1", since = "1.0.0")] pub struct File { inner: fs_imp::File, @@ -211,7 +216,7 @@ pub struct DirBuilder { recursive: bool, } -/// How large a buffer to pre-allocate before reading the entire file. +/// Indicates how large a buffer to pre-allocate before reading the entire file. fn initial_buffer_size(file: &File) -> usize { // Allocate one extra byte so the buffer doesn't need to grow before the // final `read` call at the end of the file. Don't worry about `usize` @@ -391,9 +396,13 @@ impl File { /// Attempts to sync all OS-internal metadata to disk. /// - /// This function will attempt to ensure that all in-core data reaches the + /// This function will attempt to ensure that all in-memory data reaches the /// filesystem before returning. /// + /// This can be used to handle errors that would otherwise only be caught + /// when the `File` is closed. Dropping a file will ignore errors in + /// synchronizing this in-memory data. + /// /// # Examples /// /// ```no_run @@ -597,7 +606,7 @@ impl IntoInner for File { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } @@ -608,6 +617,10 @@ impl Read for File { self.inner.read(buf) } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.inner.read_vectored(bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -618,6 +631,11 @@ impl Write for File { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(buf) } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.inner.write_vectored(bufs) + } + fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } #[stable(feature = "rust1", since = "1.0.0")] @@ -632,6 +650,10 @@ impl Read for &File { self.inner.read(buf) } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.inner.read_vectored(bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -642,6 +664,11 @@ impl Write for &File { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(buf) } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.inner.write_vectored(bufs) + } + fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } #[stable(feature = "rust1", since = "1.0.0")] @@ -876,11 +903,14 @@ impl OpenOptions { } fn _open(&self, path: &Path) -> io::Result { - let inner = fs_imp::File::open(path, &self.0)?; - Ok(File { inner }) + fs_imp::File::open(path, &self.0).map(|inner| File { inner }) } } +impl AsInner for OpenOptions { + fn as_inner(&self) -> &fs_imp::OpenOptions { &self.0 } +} + impl AsInnerMut for OpenOptions { fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 } } @@ -1087,7 +1117,7 @@ impl Metadata { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Metadata { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Metadata") .field("file_type", &self.file_type()) .field("is_dir", &self.is_dir()) @@ -1104,6 +1134,10 @@ impl AsInner for Metadata { fn as_inner(&self) -> &fs_imp::FileAttr { &self.0 } } +impl FromInner for Metadata { + fn from_inner(attr: fs_imp::FileAttr) -> Metadata { Metadata(attr) } +} + impl Permissions { /// Returns `true` if these permissions describe a readonly (unwritable) file. /// @@ -1394,7 +1428,7 @@ impl DirEntry { #[stable(feature = "dir_entry_debug", since = "1.13.0")] impl fmt::Debug for DirEntry { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("DirEntry") .field(&self.path()) .finish() @@ -1581,7 +1615,8 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> /// `O_CLOEXEC` is set for returned file descriptors. /// On Windows, this function currently corresponds to `CopyFileEx`. Alternate /// NTFS streams are copied but only the size of the main stream is returned by -/// this function. +/// this function. On MacOS, this function corresponds to `fclonefileat` and +/// `fcopyfile`. /// Note that, this [may change in the future][changes]. /// /// [changes]: ../io/index.html#platform-specific-behavior @@ -1777,6 +1812,8 @@ pub fn canonicalize>(path: P) -> io::Result { /// function.) /// * `path` already exists. /// +/// [`create_dir_all`]: fn.create_dir_all.html +/// /// # Examples /// /// ```no_run @@ -1939,7 +1976,7 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// use std::path::Path; /// /// // one possible implementation of walking a directory only visiting files -/// fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> { +/// fn visit_dirs(dir: &Path, cb: &dyn Fn(&DirEntry)) -> io::Result<()> { /// if dir.is_dir() { /// for entry in fs::read_dir(dir)? { /// let entry = entry?; @@ -2094,7 +2131,7 @@ impl AsInnerMut for DirBuilder { } } -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] mod tests { use crate::io::prelude::*; @@ -2836,6 +2873,26 @@ mod tests { assert_eq!(check!(out_path.metadata()).len(), copied_len); } + #[test] + fn copy_file_follows_dst_symlink() { + let tmp = tmpdir(); + if !got_symlink_permission(&tmp) { return }; + + let in_path = tmp.join("in.txt"); + let out_path = tmp.join("out.txt"); + let out_path_symlink = tmp.join("out_symlink.txt"); + + check!(fs::write(&in_path, "foo")); + check!(fs::write(&out_path, "bar")); + check!(symlink_file(&out_path, &out_path_symlink)); + + check!(fs::copy(&in_path, &out_path_symlink)); + + assert!(check!(out_path_symlink.symlink_metadata()).file_type().is_symlink()); + assert_eq!(check!(fs::read(&out_path_symlink)), b"foo".to_vec()); + assert_eq!(check!(fs::read(&out_path)), b"foo".to_vec()); + } + #[test] fn symlinks_work() { let tmpdir = tmpdir(); diff --git a/src/libstd/future.rs b/src/libstd/future.rs index aa784746122db..0406549ff0791 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -5,22 +5,25 @@ use core::marker::Unpin; use core::pin::Pin; use core::option::Option; use core::ptr::NonNull; -use core::task::{Waker, Poll}; +use core::task::{Context, Poll}; use core::ops::{Drop, Generator, GeneratorState}; #[doc(inline)] +#[stable(feature = "futures_api", since = "1.36.0")] pub use core::future::*; /// Wrap a generator in a future. /// /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). +#[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] pub fn from_generator>(x: T) -> impl Future { GenFuture(x) } /// A wrapper around generators used to implement `Future` for `async`/`await` code. +#[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] struct GenFuture>(T); @@ -29,13 +32,14 @@ struct GenFuture>(T); // self-referential borrows in the underlying generator. impl> !Unpin for GenFuture {} +#[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] impl> Future for GenFuture { type Output = T::Return; - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // Safe because we're !Unpin + !Drop mapping to a ?Unpin value let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; - set_task_waker(waker, || match gen.resume() { + set_task_context(cx, || match gen.resume() { GeneratorState::Yielded(()) => Poll::Pending, GeneratorState::Complete(x) => Poll::Ready(x), }) @@ -43,61 +47,75 @@ impl> Future for GenFuture { } thread_local! { - static TLS_WAKER: Cell>> = Cell::new(None); + static TLS_CX: Cell>>> = Cell::new(None); } -struct SetOnDrop(Option>); +struct SetOnDrop(Option>>); impl Drop for SetOnDrop { fn drop(&mut self) { - TLS_WAKER.with(|tls_waker| { - tls_waker.set(self.0.take()); + TLS_CX.with(|tls_cx| { + tls_cx.set(self.0.take()); }); } } +#[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] /// Sets the thread-local task context used by async/await futures. -pub fn set_task_waker(waker: &Waker, f: F) -> R +pub fn set_task_context(cx: &mut Context<'_>, f: F) -> R where F: FnOnce() -> R { - let old_waker = TLS_WAKER.with(|tls_waker| { - tls_waker.replace(Some(NonNull::from(waker))) + // transmute the context's lifetime to 'static so we can store it. + let cx = unsafe { + core::mem::transmute::<&mut Context<'_>, &mut Context<'static>>(cx) + }; + let old_cx = TLS_CX.with(|tls_cx| { + tls_cx.replace(Some(NonNull::from(cx))) }); - let _reset_waker = SetOnDrop(old_waker); + let _reset = SetOnDrop(old_cx); f() } +#[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] -/// Retrieves the thread-local task waker used by async/await futures. +/// Retrieves the thread-local task context used by async/await futures. /// -/// This function acquires exclusive access to the task waker. +/// This function acquires exclusive access to the task context. /// -/// Panics if no waker has been set or if the waker has already been -/// retrieved by a surrounding call to get_task_waker. -pub fn get_task_waker(f: F) -> R +/// Panics if no context has been set or if the context has already been +/// retrieved by a surrounding call to get_task_context. +pub fn get_task_context(f: F) -> R where - F: FnOnce(&Waker) -> R + F: FnOnce(&mut Context<'_>) -> R { - let waker_ptr = TLS_WAKER.with(|tls_waker| { + let cx_ptr = TLS_CX.with(|tls_cx| { // Clear the entry so that nested `get_task_waker` calls // will fail or set their own value. - tls_waker.replace(None) + tls_cx.replace(None) }); - let _reset_waker = SetOnDrop(waker_ptr); + let _reset = SetOnDrop(cx_ptr); - let waker_ptr = waker_ptr.expect( - "TLS Waker not set. This is a rustc bug. \ + let mut cx_ptr = cx_ptr.expect( + "TLS Context not set. This is a rustc bug. \ Please file an issue on https://github.com/rust-lang/rust."); - unsafe { f(waker_ptr.as_ref()) } + + // Safety: we've ensured exclusive access to the context by + // removing the pointer from TLS, only to be replaced once + // we're done with it. + // + // The pointer that was inserted came from an `&mut Context<'_>`, + // so it is safe to treat as mutable. + unsafe { f(cx_ptr.as_mut()) } } +#[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] /// Polls a future in the current thread-local task waker. -pub fn poll_with_tls_waker(f: Pin<&mut F>) -> Poll +pub fn poll_with_tls_context(f: Pin<&mut F>) -> Poll where F: Future { - get_task_waker(|waker| F::poll(f, waker)) + get_task_context(|cx| F::poll(f, cx)) } diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 559a54d3c8aca..aaf628e6c260f 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -5,7 +5,8 @@ use crate::io::prelude::*; use crate::cmp; use crate::error; use crate::fmt; -use crate::io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom, IoVec, IoVecMut}; +use crate::io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom, IoSlice, + IoSliceMut}; use crate::memchr; /// The `BufReader` struct adds buffering to any reader. @@ -21,6 +22,10 @@ use crate::memchr; /// times. It also provides no advantage when reading from a source that is /// already in memory, like a `Vec`. /// +/// When the `BufReader` is dropped, the contents of its buffer will be +/// discarded. Creating multiple instances of a `BufReader` on the same +/// stream can cause data loss. +/// /// [`Read`]: ../../std/io/trait.Read.html /// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read /// [`TcpStream`]: ../../std/net/struct.TcpStream.html @@ -88,10 +93,10 @@ impl BufReader { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(cap: usize, inner: R) -> BufReader { + pub fn with_capacity(capacity: usize, inner: R) -> BufReader { unsafe { - let mut buffer = Vec::with_capacity(cap); - buffer.set_len(cap); + let mut buffer = Vec::with_capacity(capacity); + buffer.set_len(capacity); inner.initializer().initialize(&mut buffer); BufReader { inner, @@ -101,7 +106,9 @@ impl BufReader { } } } +} +impl BufReader { /// Gets a reference to the underlying reader. /// /// It is inadvisable to directly read from the underlying reader. @@ -151,7 +158,6 @@ impl BufReader { /// # Examples /// /// ```no_run - /// # #![feature(bufreader_buffer)] /// use std::io::{BufReader, BufRead}; /// use std::fs::File; /// @@ -166,7 +172,7 @@ impl BufReader { /// Ok(()) /// } /// ``` - #[unstable(feature = "bufreader_buffer", issue = "45323")] + #[stable(feature = "bufreader_buffer", since = "1.37.0")] pub fn buffer(&self) -> &[u8] { &self.buf[self.pos..self.cap] } @@ -191,6 +197,13 @@ impl BufReader { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> R { self.inner } + + /// Invalidates all data in the internal buffer. + #[inline] + fn discard_buffer(&mut self) { + self.pos = 0; + self.cap = 0; + } } impl BufReader { @@ -225,6 +238,7 @@ impl Read for BufReader { // (larger than our internal buffer), bypass our internal buffer // entirely. if self.pos == self.cap && buf.len() >= self.buf.len() { + self.discard_buffer(); return self.inner.read(buf); } let nread = { @@ -235,9 +249,10 @@ impl Read for BufReader { Ok(nread) } - fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let total_len = bufs.iter().map(|b| b.len()).sum::(); if self.pos == self.cap && total_len >= self.buf.len() { + self.discard_buffer(); return self.inner.read_vectored(bufs); } let nread = { @@ -276,7 +291,7 @@ impl BufRead for BufReader { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for BufReader where R: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("BufReader") .field("reader", &self.inner) .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len())) @@ -323,14 +338,14 @@ impl Seek for BufReader { } else { // seek backwards by our remainder, and then by the offset self.inner.seek(SeekFrom::Current(-remainder))?; - self.pos = self.cap; // empty the buffer + self.discard_buffer(); result = self.inner.seek(SeekFrom::Current(n))?; } } else { // Seeking with Start/End doesn't care about our buffer length. result = self.inner.seek(pos)?; } - self.pos = self.cap; // empty the buffer + self.discard_buffer(); Ok(result) } } @@ -339,7 +354,7 @@ impl Seek for BufReader { /// /// It can be excessively inefficient to work directly with something that /// implements [`Write`]. For example, every call to -/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A +/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A /// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying /// writer in large, infrequent batches. /// @@ -390,7 +405,7 @@ impl Seek for BufReader { /// the `stream` is dropped. /// /// [`Write`]: ../../std/io/trait.Write.html -/// [`Tcpstream::write`]: ../../std/net/struct.TcpStream.html#method.write +/// [`TcpStream::write`]: ../../std/net/struct.TcpStream.html#method.write /// [`TcpStream`]: ../../std/net/struct.TcpStream.html /// [`flush`]: #method.flush #[stable(feature = "rust1", since = "1.0.0")] @@ -462,10 +477,10 @@ impl BufWriter { /// let mut buffer = BufWriter::with_capacity(100, stream); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(cap: usize, inner: W) -> BufWriter { + pub fn with_capacity(capacity: usize, inner: W) -> BufWriter { BufWriter { inner: Some(inner), - buf: Vec::with_capacity(cap), + buf: Vec::with_capacity(capacity), panicked: false, } } @@ -536,7 +551,6 @@ impl BufWriter { /// # Examples /// /// ```no_run - /// # #![feature(bufreader_buffer)] /// use std::io::BufWriter; /// use std::net::TcpStream; /// @@ -545,7 +559,7 @@ impl BufWriter { /// // See how many bytes are currently buffered /// let bytes_buffered = buf_writer.buffer().len(); /// ``` - #[unstable(feature = "bufreader_buffer", issue = "45323")] + #[stable(feature = "bufreader_buffer", since = "1.37.0")] pub fn buffer(&self) -> &[u8] { &self.buf } @@ -586,7 +600,7 @@ impl Write for BufWriter { } if buf.len() >= self.buf.capacity() { self.panicked = true; - let r = self.inner.as_mut().unwrap().write(buf); + let r = self.get_mut().write(buf); self.panicked = false; r } else { @@ -594,14 +608,14 @@ impl Write for BufWriter { } } - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { let total_len = bufs.iter().map(|b| b.len()).sum::(); if self.buf.len() + total_len > self.buf.capacity() { self.flush_buf()?; } if total_len >= self.buf.capacity() { self.panicked = true; - let r = self.inner.as_mut().unwrap().write_vectored(bufs); + let r = self.get_mut().write_vectored(bufs); self.panicked = false; r } else { @@ -616,7 +630,7 @@ impl Write for BufWriter { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for BufWriter where W: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("BufWriter") .field("writer", &self.inner.as_ref().unwrap()) .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) @@ -724,7 +738,7 @@ impl error::Error for IntoInnerError { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for IntoInnerError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.error().fmt(f) } } @@ -738,7 +752,7 @@ impl fmt::Display for IntoInnerError { /// completed, rather than the entire buffer at once. Enter `LineWriter`. It /// does exactly that. /// -/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the +/// Like [`BufWriter`][bufwriter], a `LineWriter`’s buffer will also be flushed when the /// `LineWriter` goes out of scope or when its internal buffer is full. /// /// [bufwriter]: struct.BufWriter.html @@ -836,9 +850,9 @@ impl LineWriter { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(cap: usize, inner: W) -> LineWriter { + pub fn with_capacity(capacity: usize, inner: W) -> LineWriter { LineWriter { - inner: BufWriter::with_capacity(cap, inner), + inner: BufWriter::with_capacity(capacity, inner), need_flush: false, } } @@ -966,7 +980,7 @@ impl Write for LineWriter { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for LineWriter where W: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("LineWriter") .field("writer", &self.inner.inner) .field("buffer", @@ -1066,6 +1080,40 @@ mod tests { assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..])); } + #[test] + fn test_buffered_reader_invalidated_after_read() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); + + assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); + reader.consume(3); + + let mut buffer = [0, 0, 0, 0, 0]; + assert_eq!(reader.read(&mut buffer).ok(), Some(5)); + assert_eq!(buffer, [0, 1, 2, 3, 4]); + + assert!(reader.seek_relative(-2).is_ok()); + let mut buffer = [0, 0]; + assert_eq!(reader.read(&mut buffer).ok(), Some(2)); + assert_eq!(buffer, [3, 4]); + } + + #[test] + fn test_buffered_reader_invalidated_after_seek() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); + + assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); + reader.consume(3); + + assert!(reader.seek(SeekFrom::Current(5)).is_ok()); + + assert!(reader.seek_relative(-2).is_ok()); + let mut buffer = [0, 0]; + assert_eq!(reader.read(&mut buffer).ok(), Some(2)); + assert_eq!(buffer, [3, 4]); + } + #[test] fn test_buffered_reader_seek_underflow() { // gimmick reader that yields its position modulo 256 for each byte @@ -1112,6 +1160,41 @@ mod tests { assert_eq!(reader.get_ref().pos, expected); } + #[test] + fn test_buffered_reader_seek_underflow_discard_buffer_between_seeks() { + // gimmick reader that returns Err after first seek + struct ErrAfterFirstSeekReader { + first_seek: bool, + } + impl Read for ErrAfterFirstSeekReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + for x in &mut *buf { + *x = 0; + } + Ok(buf.len()) + } + } + impl Seek for ErrAfterFirstSeekReader { + fn seek(&mut self, _: SeekFrom) -> io::Result { + if self.first_seek { + self.first_seek = false; + Ok(0) + } else { + Err(io::Error::new(io::ErrorKind::Other, "oh no!")) + } + } + } + + let mut reader = BufReader::with_capacity(5, ErrAfterFirstSeekReader { first_seek: true }); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 0, 0, 0, 0][..])); + + // The following seek will require two underlying seeks. The first will + // succeed but the second will fail. This should still invalidate the + // buffer. + assert!(reader.seek(SeekFrom::Current(i64::min_value())).is_err()); + assert_eq!(reader.buffer().len(), 0); + } + #[test] fn test_buffered_writer() { let inner = Vec::new(); diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 873da0898c7fe..a94176e710005 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -1,7 +1,7 @@ use crate::io::prelude::*; use crate::cmp; -use crate::io::{self, Initializer, SeekFrom, Error, ErrorKind, IoVec, IoVecMut}; +use crate::io::{self, Initializer, SeekFrom, Error, ErrorKind, IoSlice, IoSliceMut}; use core::convert::TryInto; @@ -72,7 +72,7 @@ use core::convert::TryInto; /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct Cursor { inner: T, pos: u64, @@ -212,6 +212,14 @@ impl io::Seek for Cursor where T: AsRef<[u8]> { "invalid seek to a negative or overflowing position")) } } + + fn stream_len(&mut self) -> io::Result { + Ok(self.inner.as_ref().len() as u64) + } + + fn stream_position(&mut self) -> io::Result { + Ok(self.pos) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -222,7 +230,7 @@ impl Read for Cursor where T: AsRef<[u8]> { Ok(n) } - fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let mut nread = 0; for buf in bufs { let n = self.read(buf)?; @@ -257,6 +265,7 @@ impl BufRead for Cursor where T: AsRef<[u8]> { } // Non-resizing write implementation +#[inline] fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result { let pos = cmp::min(*pos_mut, slice.len() as u64); let amt = (&mut slice[(pos as usize)..]).write(buf)?; @@ -264,10 +273,11 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result], + bufs: &[IoSlice<'_>], ) -> io::Result { let mut nwritten = 0; @@ -311,7 +321,7 @@ fn vec_write(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result, - bufs: &[IoVec<'_>], + bufs: &[IoSlice<'_>], ) -> io::Result { let mut nwritten = 0; @@ -329,10 +339,11 @@ impl Write for Cursor<&mut [u8]> { } #[inline] - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { slice_write_vectored(&mut self.pos, self.inner, bufs) } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } @@ -342,10 +353,11 @@ impl Write for Cursor<&mut Vec> { vec_write(&mut self.pos, self.inner, buf) } - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { vec_write_vectored(&mut self.pos, self.inner, bufs) } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } @@ -355,10 +367,11 @@ impl Write for Cursor> { vec_write(&mut self.pos, &mut self.inner, buf) } - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { vec_write_vectored(&mut self.pos, &mut self.inner, bufs) } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } @@ -370,17 +383,18 @@ impl Write for Cursor> { } #[inline] - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { slice_write_vectored(&mut self.pos, &mut self.inner, bufs) } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } #[cfg(test)] mod tests { use crate::io::prelude::*; - use crate::io::{Cursor, SeekFrom, IoVec, IoVecMut}; + use crate::io::{Cursor, SeekFrom, IoSlice, IoSliceMut}; #[test] fn test_vec_writer() { @@ -389,7 +403,7 @@ mod tests { assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); assert_eq!(writer.write_vectored( - &[IoVec::new(&[]), IoVec::new(&[8, 9]), IoVec::new(&[10])], + &[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])], ).unwrap(), 3); let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; assert_eq!(writer, b); @@ -402,7 +416,7 @@ mod tests { assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); assert_eq!(writer.write_vectored( - &[IoVec::new(&[]), IoVec::new(&[8, 9]), IoVec::new(&[10])], + &[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])], ).unwrap(), 3); let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; assert_eq!(&writer.get_ref()[..], b); @@ -416,7 +430,7 @@ mod tests { assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); assert_eq!(writer.write_vectored( - &[IoVec::new(&[]), IoVec::new(&[8, 9]), IoVec::new(&[10])], + &[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])], ).unwrap(), 3); let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; assert_eq!(&writer.get_ref()[..], b); @@ -444,18 +458,21 @@ mod tests { fn test_box_slice_writer_vectored() { let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); assert_eq!(writer.position(), 0); - assert_eq!(writer.write_vectored(&[IoVec::new(&[0])]).unwrap(), 1); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1); assert_eq!(writer.position(), 1); assert_eq!( - writer.write_vectored(&[IoVec::new(&[1, 2, 3]), IoVec::new(&[4, 5, 6, 7])]).unwrap(), + writer.write_vectored(&[ + IoSlice::new(&[1, 2, 3]), + IoSlice::new(&[4, 5, 6, 7]), + ]).unwrap(), 7, ); assert_eq!(writer.position(), 8); assert_eq!(writer.write_vectored(&[]).unwrap(), 0); assert_eq!(writer.position(), 8); - assert_eq!(writer.write_vectored(&[IoVec::new(&[8, 9])]).unwrap(), 1); - assert_eq!(writer.write_vectored(&[IoVec::new(&[10])]).unwrap(), 0); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0); let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; assert_eq!(&**writer.get_ref(), b); } @@ -487,11 +504,11 @@ mod tests { { let mut writer = Cursor::new(&mut buf[..]); assert_eq!(writer.position(), 0); - assert_eq!(writer.write_vectored(&[IoVec::new(&[0])]).unwrap(), 1); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1); assert_eq!(writer.position(), 1); assert_eq!( writer.write_vectored( - &[IoVec::new(&[1, 2, 3]), IoVec::new(&[4, 5, 6, 7])], + &[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])], ).unwrap(), 7, ); @@ -499,8 +516,8 @@ mod tests { assert_eq!(writer.write_vectored(&[]).unwrap(), 0); assert_eq!(writer.position(), 8); - assert_eq!(writer.write_vectored(&[IoVec::new(&[8, 9])]).unwrap(), 1); - assert_eq!(writer.write_vectored(&[IoVec::new(&[10])]).unwrap(), 0); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0); } let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; assert_eq!(buf, b); @@ -570,11 +587,14 @@ mod tests { fn test_mem_reader_vectored() { let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); let mut buf = []; - assert_eq!(reader.read_vectored(&mut [IoVecMut::new(&mut buf)]).unwrap(), 0); + assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); assert_eq!(reader.position(), 0); let mut buf = [0]; assert_eq!( - reader.read_vectored(&mut [IoVecMut::new(&mut []), IoVecMut::new(&mut buf)]).unwrap(), + reader.read_vectored(&mut [ + IoSliceMut::new(&mut []), + IoSliceMut::new(&mut buf), + ]).unwrap(), 1, ); assert_eq!(reader.position(), 1); @@ -583,9 +603,10 @@ mod tests { let mut buf1 = [0; 4]; let mut buf2 = [0; 4]; assert_eq!( - reader.read_vectored( - &mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)], - ).unwrap(), + reader.read_vectored(&mut [ + IoSliceMut::new(&mut buf1), + IoSliceMut::new(&mut buf2), + ]).unwrap(), 7, ); let b1: &[_] = &[1, 2, 3, 4]; @@ -621,11 +642,14 @@ mod tests { fn test_boxed_slice_reader_vectored() { let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); let mut buf = []; - assert_eq!(reader.read_vectored(&mut [IoVecMut::new(&mut buf)]).unwrap(), 0); + assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); assert_eq!(reader.position(), 0); let mut buf = [0]; assert_eq!( - reader.read_vectored(&mut [IoVecMut::new(&mut []), IoVecMut::new(&mut buf)]).unwrap(), + reader.read_vectored(&mut [ + IoSliceMut::new(&mut []), + IoSliceMut::new(&mut buf), + ]).unwrap(), 1, ); assert_eq!(reader.position(), 1); @@ -635,7 +659,7 @@ mod tests { let mut buf2 = [0; 4]; assert_eq!( reader.read_vectored( - &mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)], + &mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)], ).unwrap(), 7, ); @@ -681,10 +705,13 @@ mod tests { let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; let reader = &mut &in_buf[..]; let mut buf = []; - assert_eq!(reader.read_vectored(&mut [IoVecMut::new(&mut buf)]).unwrap(), 0); + assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); let mut buf = [0]; assert_eq!( - reader.read_vectored(&mut [IoVecMut::new(&mut []), IoVecMut::new(&mut buf)]).unwrap(), + reader.read_vectored(&mut [ + IoSliceMut::new(&mut []), + IoSliceMut::new(&mut buf), + ]).unwrap(), 1, ); assert_eq!(reader.len(), 7); @@ -694,7 +721,7 @@ mod tests { let mut buf2 = [0; 4]; assert_eq!( reader.read_vectored( - &mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)], + &mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)], ).unwrap(), 7, ); diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index fdc5625ff1841..c29a68e6f02b8 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -59,7 +59,7 @@ pub struct Error { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.repr, f) } } @@ -413,7 +413,7 @@ impl Error { /// } /// /// impl Display for MyError { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "MyError: {}", &self.v) /// } /// } @@ -512,7 +512,7 @@ impl Error { } impl fmt::Debug for Repr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Repr::Os(code) => fmt.debug_struct("Os") @@ -527,7 +527,7 @@ impl fmt::Debug for Repr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Error { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self.repr { Repr::Os(code) => { let detail = sys::os::error_string(code); @@ -556,6 +556,14 @@ impl error::Error for Error { Repr::Custom(ref c) => c.error.cause(), } } + + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match self.repr { + Repr::Os(..) => None, + Repr::Simple(..) => None, + Repr::Custom(ref c) => c.error.source(), + } + } } fn _assert_error_is_sync_send() { @@ -604,7 +612,7 @@ mod test { struct TestError; impl fmt::Display for TestError { - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { Ok(()) } } diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs index bd3d0a4163869..c959f2d389b11 100644 --- a/src/libstd/io/impls.rs +++ b/src/libstd/io/impls.rs @@ -1,6 +1,6 @@ use crate::cmp; -use crate::io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind, IoVecMut, - IoVec}; +use crate::io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind, + IoSliceMut, IoSlice}; use crate::fmt; use crate::mem; @@ -15,7 +15,7 @@ impl Read for &mut R { } #[inline] - fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { (**self).read_vectored(bufs) } @@ -45,7 +45,7 @@ impl Write for &mut W { fn write(&mut self, buf: &[u8]) -> io::Result { (**self).write(buf) } #[inline] - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { (**self).write_vectored(bufs) } @@ -58,7 +58,7 @@ impl Write for &mut W { } #[inline] - fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { (**self).write_fmt(fmt) } } @@ -94,7 +94,7 @@ impl Read for Box { } #[inline] - fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { (**self).read_vectored(bufs) } @@ -124,7 +124,7 @@ impl Write for Box { fn write(&mut self, buf: &[u8]) -> io::Result { (**self).write(buf) } #[inline] - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { (**self).write_vectored(bufs) } @@ -137,7 +137,7 @@ impl Write for Box { } #[inline] - fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { (**self).write_fmt(fmt) } } @@ -165,6 +165,20 @@ impl BufRead for Box { } } +// Used by panicking::default_hook +#[cfg(test)] +/// This impl is only used by printing logic, so any error returned is always +/// of kind `Other`, and should be ignored. +impl Write for Box { + fn write(&mut self, buf: &[u8]) -> io::Result { + (**self).write(buf).map_err(|_| ErrorKind::Other.into()) + } + + fn flush(&mut self) -> io::Result<()> { + (**self).flush().map_err(|_| ErrorKind::Other.into()) + } +} + // ============================================================================= // In-memory buffer implementations @@ -193,7 +207,7 @@ impl Read for &[u8] { } #[inline] - fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let mut nread = 0; for buf in bufs { nread += self.read(buf)?; @@ -266,7 +280,7 @@ impl Write for &mut [u8] { } #[inline] - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { let mut nwritten = 0; for buf in bufs { nwritten += self.write(buf)?; @@ -302,7 +316,7 @@ impl Write for Vec { } #[inline] - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { let len = bufs.iter().map(|b| b.len()).sum(); self.reserve(len); for buf in bufs { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index e3e2754a7aa09..3d0568c16cdf6 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -24,9 +24,9 @@ //! let mut buffer = [0; 10]; //! //! // read up to 10 bytes -//! f.read(&mut buffer)?; +//! let n = f.read(&mut buffer)?; //! -//! println!("The bytes: {:?}", buffer); +//! println!("The bytes: {:?}", &buffer[..n]); //! Ok(()) //! } //! ``` @@ -56,9 +56,9 @@ //! f.seek(SeekFrom::End(-10))?; //! //! // read up to 10 bytes -//! f.read(&mut buffer)?; +//! let n = f.read(&mut buffer)?; //! -//! println!("The bytes: {:?}", buffer); +//! println!("The bytes: {:?}", &buffer[..n]); //! Ok(()) //! } //! ``` @@ -390,6 +390,28 @@ fn read_to_end_with_reservation(r: &mut R, ret } +pub(crate) fn default_read_vectored(read: F, bufs: &mut [IoSliceMut<'_>]) -> Result +where + F: FnOnce(&mut [u8]) -> Result +{ + let buf = bufs + .iter_mut() + .find(|b| !b.is_empty()) + .map_or(&mut [][..], |b| &mut **b); + read(buf) +} + +pub(crate) fn default_write_vectored(write: F, bufs: &[IoSlice<'_>]) -> Result +where + F: FnOnce(&[u8]) -> Result +{ + let buf = bufs + .iter() + .find(|b| !b.is_empty()) + .map_or(&[][..], |b| &**b); + write(buf) +} + /// The `Read` trait allows for reading bytes from a source. /// /// Implementors of the `Read` trait are called 'readers'. @@ -484,9 +506,18 @@ pub trait Read { /// /// No guarantees are provided about the contents of `buf` when this /// function is called, implementations cannot rely on any property of the - /// contents of `buf` being true. It is recommended that implementations + /// contents of `buf` being true. It is recommended that *implementations* /// only write data to `buf` instead of reading its contents. /// + /// Correspondingly, however, *callers* of this method may not assume any guarantees + /// about how the implementation uses `buf`. The trait is safe to implement, + // so it is possible that the code that's supposed to write to the buffer might also read + // from it. It is your responsibility to make sure that `buf` is initialized + /// before calling `read`. Calling `read` with an uninitialized `buf` (of the kind one + /// obtains via [`MaybeUninit`]) is not safe, and can lead to undefined behavior. + /// + /// [`MaybeUninit`]: ../mem/union.MaybeUninit.html + /// /// # Errors /// /// If this function encounters any form of I/O or other error, an error @@ -515,7 +546,9 @@ pub trait Read { /// let mut buffer = [0; 10]; /// /// // read up to 10 bytes - /// f.read(&mut buffer[..])?; + /// let n = f.read(&mut buffer[..])?; + /// + /// println!("The bytes: {:?}", &buffer[..n]); /// Ok(()) /// } /// ``` @@ -528,14 +561,11 @@ pub trait Read { /// written to possibly being only partially filled. This method must behave /// as a single call to `read` with the buffers concatenated would. /// - /// The default implementation simply passes the first nonempty buffer to - /// `read`. - #[unstable(feature = "iovec", issue = "58452")] - fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> Result { - match bufs.iter_mut().find(|b| !b.is_empty()) { - Some(buf) => self.read(buf), - None => Ok(0), - } + /// The default implementation calls `read` with either the first nonempty + /// buffer provided, or an empty one if none exists. + #[stable(feature = "iovec", since = "1.36.0")] + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { + default_read_vectored(|b| self.read(b), bufs) } /// Determines if this `Read`er can work with buffers of uninitialized @@ -890,32 +920,32 @@ pub trait Read { /// It is semantically a wrapper around an `&mut [u8]`, but is guaranteed to be /// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on /// Windows. -#[unstable(feature = "iovec", issue = "58452")] +#[stable(feature = "iovec", since = "1.36.0")] #[repr(transparent)] -pub struct IoVecMut<'a>(sys::io::IoVecMut<'a>); +pub struct IoSliceMut<'a>(sys::io::IoSliceMut<'a>); -#[unstable(feature = "iovec", issue = "58452")] -impl<'a> fmt::Debug for IoVecMut<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { +#[stable(feature = "iovec", since = "1.36.0")] +impl<'a> fmt::Debug for IoSliceMut<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self.0.as_slice(), fmt) } } -impl<'a> IoVecMut<'a> { - /// Creates a new `IoVecMut` wrapping a byte slice. +impl<'a> IoSliceMut<'a> { + /// Creates a new `IoSliceMut` wrapping a byte slice. /// /// # Panics /// /// Panics on Windows if the slice is larger than 4GB. - #[unstable(feature = "iovec", issue = "58452")] + #[stable(feature = "iovec", since = "1.36.0")] #[inline] - pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { - IoVecMut(sys::io::IoVecMut::new(buf)) + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut(sys::io::IoSliceMut::new(buf)) } } -#[unstable(feature = "iovec", issue = "58452")] -impl<'a> Deref for IoVecMut<'a> { +#[stable(feature = "iovec", since = "1.36.0")] +impl<'a> Deref for IoSliceMut<'a> { type Target = [u8]; #[inline] @@ -924,8 +954,8 @@ impl<'a> Deref for IoVecMut<'a> { } } -#[unstable(feature = "iovec", issue = "58452")] -impl<'a> DerefMut for IoVecMut<'a> { +#[stable(feature = "iovec", since = "1.36.0")] +impl<'a> DerefMut for IoSliceMut<'a> { #[inline] fn deref_mut(&mut self) -> &mut [u8] { self.0.as_mut_slice() @@ -937,32 +967,32 @@ impl<'a> DerefMut for IoVecMut<'a> { /// It is semantically a wrapper around an `&[u8]`, but is guaranteed to be /// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on /// Windows. -#[unstable(feature = "iovec", issue = "58452")] +#[stable(feature = "iovec", since = "1.36.0")] #[repr(transparent)] -pub struct IoVec<'a>(sys::io::IoVec<'a>); +pub struct IoSlice<'a>(sys::io::IoSlice<'a>); -#[unstable(feature = "iovec", issue = "58452")] -impl<'a> fmt::Debug for IoVec<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { +#[stable(feature = "iovec", since = "1.36.0")] +impl<'a> fmt::Debug for IoSlice<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self.0.as_slice(), fmt) } } -impl<'a> IoVec<'a> { - /// Creates a new `IoVec` wrapping a byte slice. +impl<'a> IoSlice<'a> { + /// Creates a new `IoSlice` wrapping a byte slice. /// /// # Panics /// /// Panics on Windows if the slice is larger than 4GB. - #[unstable(feature = "iovec", issue = "58452")] + #[stable(feature = "iovec", since = "1.36.0")] #[inline] - pub fn new(buf: &'a [u8]) -> IoVec<'a> { - IoVec(sys::io::IoVec::new(buf)) + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice(sys::io::IoSlice::new(buf)) } } -#[unstable(feature = "iovec", issue = "58452")] -impl<'a> Deref for IoVec<'a> { +#[stable(feature = "iovec", since = "1.36.0")] +impl<'a> Deref for IoSlice<'a> { type Target = [u8]; #[inline] @@ -1043,12 +1073,23 @@ impl Initializer { /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { +/// let data = b"some bytes"; +/// +/// let mut pos = 0; /// let mut buffer = File::create("foo.txt")?; /// -/// buffer.write(b"some bytes")?; +/// while pos < data.len() { +/// let bytes_written = buffer.write(&data[pos..])?; +/// pos += bytes_written; +/// } /// Ok(()) /// } /// ``` +/// +/// The trait also provides convenience methods like [`write_all`], which calls +/// `write` in a loop until its entire input has been written. +/// +/// [`write_all`]: #method.write_all #[stable(feature = "rust1", since = "1.0.0")] #[doc(spotlight)] pub trait Write { @@ -1107,14 +1148,11 @@ pub trait Write { /// read from possibly being only partially consumed. This method must /// behave as a call to `write` with the buffers concatenated would. /// - /// The default implementation simply passes the first nonempty buffer to - /// `write`. - #[unstable(feature = "iovec", issue = "58452")] - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> Result { - match bufs.iter().find(|b| !b.is_empty()) { - Some(buf) => self.write(buf), - None => Ok(0), - } + /// The default implementation calls `write` with either the first nonempty + /// buffer provided, or an empty one if none exists. + #[stable(feature = "iovec", since = "1.36.0")] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { + default_write_vectored(|b| self.write(b), bufs) } /// Flush this output stream, ensuring that all intermediately buffered @@ -1135,7 +1173,7 @@ pub trait Write { /// fn main() -> std::io::Result<()> { /// let mut buffer = BufWriter::new(File::create("foo.txt")?); /// - /// buffer.write(b"some bytes")?; + /// buffer.write_all(b"some bytes")?; /// buffer.flush()?; /// Ok(()) /// } @@ -1226,7 +1264,7 @@ pub trait Write { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> { + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> { // Create a shim which translates a Write to a fmt::Write and saves // off I/O errors. instead of discarding them struct Adaptor<'a, T: ?Sized + 'a> { @@ -1329,6 +1367,85 @@ pub trait Seek { /// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start #[stable(feature = "rust1", since = "1.0.0")] fn seek(&mut self, pos: SeekFrom) -> Result; + + /// Returns the length of this stream (in bytes). + /// + /// This method is implemented using up to three seek operations. If this + /// method returns successfully, the seek position is unchanged (i.e. the + /// position before calling this method is the same as afterwards). + /// However, if this method returns an error, the seek position is + /// unspecified. + /// + /// If you need to obtain the length of *many* streams and you don't care + /// about the seek position afterwards, you can reduce the number of seek + /// operations by simply calling `seek(SeekFrom::End(0))` and using its + /// return value (it is also the stream length). + /// + /// Note that length of a stream can change over time (for example, when + /// data is appended to a file). So calling this method multiple times does + /// not necessarily return the same length each time. + /// + /// + /// # Example + /// + /// ```no_run + /// #![feature(seek_convenience)] + /// use std::{ + /// io::{self, Seek}, + /// fs::File, + /// }; + /// + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// + /// let len = f.stream_len()?; + /// println!("The file is currently {} bytes long", len); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "seek_convenience", issue = "59359")] + fn stream_len(&mut self) -> Result { + let old_pos = self.stream_position()?; + let len = self.seek(SeekFrom::End(0))?; + + // Avoid seeking a third time when we were already at the end of the + // stream. The branch is usually way cheaper than a seek operation. + if old_pos != len { + self.seek(SeekFrom::Start(old_pos))?; + } + + Ok(len) + } + + /// Returns the current seek position from the start of the stream. + /// + /// This is equivalent to `self.seek(SeekFrom::Current(0))`. + /// + /// + /// # Example + /// + /// ```no_run + /// #![feature(seek_convenience)] + /// use std::{ + /// io::{self, BufRead, BufReader, Seek}, + /// fs::File, + /// }; + /// + /// fn main() -> io::Result<()> { + /// let mut f = BufReader::new(File::open("foo.txt")?); + /// + /// let before = f.stream_position()?; + /// f.read_line(&mut String::new())?; + /// let after = f.stream_position()?; + /// + /// println!("The first line was {} bytes long", after - before); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "seek_convenience", issue = "59359")] + fn stream_position(&mut self) -> Result { + self.seek(SeekFrom::Current(0)) + } } /// Enumeration of possible methods to seek within an I/O object. @@ -1471,18 +1588,13 @@ pub trait BufRead: Read { /// let stdin = io::stdin(); /// let mut stdin = stdin.lock(); /// - /// // we can't have two `&mut` references to `stdin`, so use a block - /// // to end the borrow early. - /// let length = { - /// let buffer = stdin.fill_buf().unwrap(); + /// let buffer = stdin.fill_buf().unwrap(); /// - /// // work with buffer - /// println!("{:?}", buffer); - /// - /// buffer.len() - /// }; + /// // work with buffer + /// println!("{:?}", buffer); /// /// // ensure the bytes we worked with aren't returned again later + /// let length = buffer.len(); /// stdin.consume(length); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1798,7 +1910,7 @@ impl Chain { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Chain { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Chain") .field("t", &self.first) .field("u", &self.second) @@ -1818,7 +1930,7 @@ impl Read for Chain { self.second.read(buf) } - fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> Result { + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { if !self.done_first { match self.first.read_vectored(bufs)? { 0 if bufs.iter().any(|b| !b.is_empty()) => self.done_first = true, @@ -2157,8 +2269,7 @@ impl Iterator for Lines { mod tests { use crate::io::prelude::*; use crate::io; - use super::Cursor; - use super::repeat; + use super::{Cursor, SeekFrom, repeat}; #[test] #[cfg_attr(target_os = "emscripten", ignore)] @@ -2380,4 +2491,50 @@ mod tests { super::read_to_end(&mut lr, &mut vec) }); } + + #[test] + fn seek_len() -> io::Result<()> { + let mut c = Cursor::new(vec![0; 15]); + assert_eq!(c.stream_len()?, 15); + + c.seek(SeekFrom::End(0))?; + let old_pos = c.stream_position()?; + assert_eq!(c.stream_len()?, 15); + assert_eq!(c.stream_position()?, old_pos); + + c.seek(SeekFrom::Start(7))?; + c.seek(SeekFrom::Current(2))?; + let old_pos = c.stream_position()?; + assert_eq!(c.stream_len()?, 15); + assert_eq!(c.stream_position()?, old_pos); + + Ok(()) + } + + #[test] + fn seek_position() -> io::Result<()> { + // All `asserts` are duplicated here to make sure the method does not + // change anything about the seek state. + let mut c = Cursor::new(vec![0; 15]); + assert_eq!(c.stream_position()?, 0); + assert_eq!(c.stream_position()?, 0); + + c.seek(SeekFrom::End(0))?; + assert_eq!(c.stream_position()?, 15); + assert_eq!(c.stream_position()?, 15); + + + c.seek(SeekFrom::Start(7))?; + c.seek(SeekFrom::Current(2))?; + assert_eq!(c.stream_position()?, 9); + assert_eq!(c.stream_position()?, 9); + + c.seek(SeekFrom::End(-3))?; + c.seek(SeekFrom::Current(1))?; + c.seek(SeekFrom::Current(-5))?; + assert_eq!(c.stream_position()?, 8); + assert_eq!(c.stream_position()?, 8); + + Ok(()) + } } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 13bf357e2eb8f..990c0eb8955e4 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -1,21 +1,30 @@ +#![cfg_attr(test, allow(unused))] + use crate::io::prelude::*; use crate::cell::RefCell; use crate::fmt; use crate::io::lazy::Lazy; -use crate::io::{self, Initializer, BufReader, LineWriter}; +use crate::io::{self, Initializer, BufReader, LineWriter, IoSlice, IoSliceMut}; use crate::sync::{Arc, Mutex, MutexGuard}; use crate::sys::stdio; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use crate::thread::LocalKey; -/// Stdout used by print! and println! macros thread_local! { + /// Stdout used by print! and println! macros static LOCAL_STDOUT: RefCell>> = { RefCell::new(None) } } +thread_local! { + /// Stderr used by eprint! and eprintln! macros, and panics + static LOCAL_STDERR: RefCell>> = { + RefCell::new(None) + } +} + /// A handle to a raw instance of the standard input stream of this process. /// /// This handle is not synchronized or buffered in any fashion. Constructed via @@ -66,6 +75,10 @@ fn stderr_raw() -> io::Result { stdio::Stderr::new().map(StderrRaw) } impl Read for StdinRaw { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -73,10 +86,20 @@ impl Read for StdinRaw { } impl Write for StdoutRaw { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + fn flush(&mut self) -> io::Result<()> { self.0.flush() } } impl Write for StderrRaw { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + fn flush(&mut self) -> io::Result<()> { self.0.flush() } } @@ -93,6 +116,14 @@ impl io::Write for Maybe { } } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let total = bufs.iter().map(|b| b.len()).sum(); + match self { + Maybe::Real(w) => handle_ebadf(w.write_vectored(bufs), total), + Maybe::Fake => Ok(total), + } + } + fn flush(&mut self) -> io::Result<()> { match *self { Maybe::Real(ref mut w) => handle_ebadf(w.flush(), ()), @@ -108,6 +139,13 @@ impl io::Read for Maybe { Maybe::Fake => Ok(0) } } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + match self { + Maybe::Real(r) => handle_ebadf(r.read_vectored(bufs), 0), + Maybe::Fake => Ok(0) + } + } } fn handle_ebadf(r: io::Result, default: T) -> io::Result { @@ -246,7 +284,7 @@ impl Stdin { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> StdinLock { + pub fn lock(&self) -> StdinLock<'_> { StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } } @@ -286,7 +324,7 @@ impl Stdin { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Stdin { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Stdin { .. }") } } @@ -296,6 +334,9 @@ impl Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.lock().read(buf) } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.lock().read_vectored(bufs) + } #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -316,6 +357,11 @@ impl Read for StdinLock<'_> { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.inner.read_vectored(bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -330,7 +376,7 @@ impl BufRead for StdinLock<'_> { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for StdinLock<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("StdinLock { .. }") } } @@ -396,7 +442,7 @@ pub struct StdoutLock<'a> { /// use std::io::{self, Write}; /// /// fn main() -> io::Result<()> { -/// io::stdout().write(b"hello world")?; +/// io::stdout().write_all(b"hello world")?; /// /// Ok(()) /// } @@ -411,7 +457,7 @@ pub struct StdoutLock<'a> { /// let stdout = io::stdout(); /// let mut handle = stdout.lock(); /// -/// handle.write(b"hello world")?; +/// handle.write_all(b"hello world")?; /// /// Ok(()) /// } @@ -451,20 +497,20 @@ impl Stdout { /// let stdout = io::stdout(); /// let mut handle = stdout.lock(); /// - /// handle.write(b"hello world")?; + /// handle.write_all(b"hello world")?; /// /// Ok(()) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> StdoutLock { + pub fn lock(&self) -> StdoutLock<'_> { StdoutLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } } } #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Stdout { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Stdout { .. }") } } @@ -474,13 +520,16 @@ impl Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.lock().write_vectored(bufs) + } fn flush(&mut self) -> io::Result<()> { self.lock().flush() } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.lock().write_all(buf) } - fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> { + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { self.lock().write_fmt(args) } } @@ -489,6 +538,9 @@ impl Write for StdoutLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.borrow_mut().write(buf) } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.inner.borrow_mut().write_vectored(bufs) + } fn flush(&mut self) -> io::Result<()> { self.inner.borrow_mut().flush() } @@ -496,7 +548,7 @@ impl Write for StdoutLock<'_> { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for StdoutLock<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("StdoutLock { .. }") } } @@ -549,7 +601,7 @@ pub struct StderrLock<'a> { /// use std::io::{self, Write}; /// /// fn main() -> io::Result<()> { -/// io::stderr().write(b"hello world")?; +/// io::stderr().write_all(b"hello world")?; /// /// Ok(()) /// } @@ -564,7 +616,7 @@ pub struct StderrLock<'a> { /// let stderr = io::stderr(); /// let mut handle = stderr.lock(); /// -/// handle.write(b"hello world")?; +/// handle.write_all(b"hello world")?; /// /// Ok(()) /// } @@ -604,20 +656,20 @@ impl Stderr { /// let stderr = io::stderr(); /// let mut handle = stderr.lock(); /// - /// handle.write(b"hello world")?; + /// handle.write_all(b"hello world")?; /// /// Ok(()) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> StderrLock { + pub fn lock(&self) -> StderrLock<'_> { StderrLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } } } #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Stderr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Stderr { .. }") } } @@ -627,13 +679,16 @@ impl Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.lock().write_vectored(bufs) + } fn flush(&mut self) -> io::Result<()> { self.lock().flush() } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.lock().write_all(buf) } - fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> { + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { self.lock().write_fmt(args) } } @@ -642,6 +697,9 @@ impl Write for StderrLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.borrow_mut().write(buf) } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.inner.borrow_mut().write_vectored(bufs) + } fn flush(&mut self) -> io::Result<()> { self.inner.borrow_mut().flush() } @@ -649,7 +707,7 @@ impl Write for StderrLock<'_> { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for StderrLock<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("StderrLock { .. }") } } @@ -668,7 +726,6 @@ impl fmt::Debug for StderrLock<'_> { issue = "0")] #[doc(hidden)] pub fn set_panic(sink: Option>) -> Option> { - use crate::panicking::LOCAL_STDERR; use crate::mem; LOCAL_STDERR.with(move |slot| { mem::replace(&mut *slot.borrow_mut(), sink) @@ -712,7 +769,7 @@ pub fn set_print(sink: Option>) -> Option( - args: fmt::Arguments, + args: fmt::Arguments<'_>, local_s: &'static LocalKey>>>, global_s: fn() -> T, label: &str, @@ -740,7 +797,8 @@ where reason = "implementation detail which may disappear or be replaced at any time", issue = "0")] #[doc(hidden)] -pub fn _print(args: fmt::Arguments) { +#[cfg(not(test))] +pub fn _print(args: fmt::Arguments<'_>) { print_to(args, &LOCAL_STDOUT, stdout, "stdout"); } @@ -748,11 +806,14 @@ pub fn _print(args: fmt::Arguments) { reason = "implementation detail which may disappear or be replaced at any time", issue = "0")] #[doc(hidden)] -pub fn _eprint(args: fmt::Arguments) { - use crate::panicking::LOCAL_STDERR; +#[cfg(not(test))] +pub fn _eprint(args: fmt::Arguments<'_>) { print_to(args, &LOCAL_STDERR, stderr, "stderr"); } +#[cfg(test)] +pub use realstd::io::{_eprint, _print}; + #[cfg(test)] mod tests { use crate::panic::{UnwindSafe, RefUnwindSafe}; @@ -765,7 +826,7 @@ mod tests { } #[test] fn stdoutlock_unwind_safe() { - assert_unwind_safe::(); + assert_unwind_safe::>(); assert_unwind_safe::>(); } #[test] @@ -774,7 +835,7 @@ mod tests { } #[test] fn stderrlock_unwind_safe() { - assert_unwind_safe::(); + assert_unwind_safe::>(); assert_unwind_safe::>(); } diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index 6aaf8f1889ac0..7c4eae6512df4 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -1,7 +1,7 @@ #![allow(missing_copy_implementations)] use crate::fmt; -use crate::io::{self, Read, Initializer, Write, ErrorKind, BufRead, IoVec, IoVecMut}; +use crate::io::{self, Read, Initializer, Write, ErrorKind, BufRead, IoSlice, IoSliceMut}; use crate::mem; /// Copies the entire contents of a reader into a writer. @@ -111,7 +111,7 @@ impl BufRead for Empty { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Empty { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Empty { .. }") } } @@ -153,7 +153,7 @@ impl Read for Repeat { } #[inline] - fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let mut nwritten = 0; for buf in bufs { nwritten += self.read(buf)?; @@ -169,7 +169,7 @@ impl Read for Repeat { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Repeat { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Repeat { .. }") } } @@ -206,7 +206,7 @@ impl Write for Sink { fn write(&mut self, buf: &[u8]) -> io::Result { Ok(buf.len()) } #[inline] - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { let total_len = bufs.iter().map(|b| b.len()).sum(); Ok(total_len) } @@ -217,7 +217,7 @@ impl Write for Sink { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Sink { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Sink { .. }") } } diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index bef6bc9266197..d133c2f5cb11c 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1,6 +1,6 @@ #[doc(keyword = "as")] // -/// The keyword for casting a value to a type. +/// Cast between types, or rename an import. /// /// `as` is most commonly used to turn primitive types into other primitive types, but it has other /// uses that include turning pointers into addresses, addresses into pointers, and pointers into @@ -25,14 +25,22 @@ /// /// For more information on what `as` is capable of, see the [Reference] /// -/// [Reference]: -/// https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions +/// [Reference]: ../reference/expressions/operator-expr.html#type-cast-expressions /// [`crate`]: keyword.crate.html mod as_keyword { } +#[doc(keyword = "break")] +// +/// Exit early from a loop. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod break_keyword { } + #[doc(keyword = "const")] // -/// The keyword for defining constants. +/// Compile-time constants and deterministic functions. /// /// Sometimes a certain value is used many times throughout a program, and it can become /// inconvenient to copy it over and over. What's more, it's not always possible or desirable to @@ -80,13 +88,22 @@ mod as_keyword { } /// /// [pointer]: primitive.pointer.html /// [Rust Book]: -/// https://doc.rust-lang.org/stable/book/2018-edition/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants -/// [Reference]: https://doc.rust-lang.org/reference/items/constant-items.html +/// ../book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants +/// [Reference]: ../reference/items/constant-items.html mod const_keyword { } +#[doc(keyword = "continue")] +// +/// Skip to the next iteration of a loop. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod continue_keyword { } + #[doc(keyword = "crate")] // -/// The `crate` keyword. +/// A Rust binary or library. /// /// The primary use of the `crate` keyword is as a part of `extern crate` declarations, which are /// used to specify a dependency on a crate external to the one it's declared in. Crates are the @@ -114,17 +131,27 @@ mod const_keyword { } /// } /// ``` /// -/// [Reference]: https://doc.rust-lang.org/reference/items/extern-crates.html +/// [Reference]: ../reference/items/extern-crates.html mod crate_keyword { } +#[doc(keyword = "else")] +// +/// What to do when an [`if`] condition does not hold. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`if`]: keyword.if.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod else_keyword { } + #[doc(keyword = "enum")] // -/// For defining enumerations. +/// A type that can be any one of several variants. /// /// Enums in Rust are similar to those of other compiled languages like C, but have important /// differences that make them considerably more powerful. What Rust calls enums are more commonly -/// known as [Algebraic Data Types] if you're coming from a functional programming background. The -/// important detail is that each enum variant can have data to go along with it. +/// known as [Algebraic Data Types][ADT] if you're coming from a functional programming background. +/// The important detail is that each enum variant can have data to go along with it. /// /// ```rust /// # struct Coord; @@ -167,15 +194,15 @@ mod crate_keyword { } /// /// For more information, take a look at the [Rust Book] or the [Reference] /// -/// [Algebraic Data Types]: https://en.wikipedia.org/wiki/Algebraic_data_type +/// [ADT]: https://en.wikipedia.org/wiki/Algebraic_data_type /// [`Option`]: option/enum.Option.html -/// [Rust Book]: https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html -/// [Reference]: https://doc.rust-lang.org/reference/items/enumerations.html +/// [Rust Book]: ../book/ch06-01-defining-an-enum.html +/// [Reference]: ../reference/items/enumerations.html mod enum_keyword { } #[doc(keyword = "extern")] // -/// For external connections in Rust code. +/// Link to or import external code. /// /// The `extern` keyword is used in two places in Rust. One is in conjunction with the [`crate`] /// keyword to make your Rust code aware of other Rust crates in your project, i.e., `extern crate @@ -211,13 +238,23 @@ mod enum_keyword { } /// For more information on FFI, check the [Rust book] or the [Reference]. /// /// [Rust book]: -/// https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code -/// [Reference]: https://doc.rust-lang.org/reference/items/external-blocks.html +/// ../book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code +/// [Reference]: ../reference/items/external-blocks.html mod extern_keyword { } +#[doc(keyword = "false")] +// +/// A value of type [`bool`] representing logical **false**. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`bool`]: primitive.bool.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod false_keyword { } + #[doc(keyword = "fn")] // -/// The keyword for defining functions. +/// A function or function pointer. /// /// Functions are the primary way code is executed within Rust. Function blocks, usually just /// called functions, can be defined in a variety of different places and be assigned many @@ -278,19 +315,25 @@ mod extern_keyword { } /// /// [`impl`]: keyword.impl.html /// [`extern`]: keyword.extern.html -/// [Rust book]: https://doc.rust-lang.org/book/ch03-03-how-functions-work.html -/// [Reference]: https://doc.rust-lang.org/reference/items/functions.html +/// [Rust book]: ../book/ch03-03-how-functions-work.html +/// [Reference]: ../reference/items/functions.html mod fn_keyword { } #[doc(keyword = "for")] // -/// The `for` keyword. +/// Iteration with [`in`], trait implementation with [`impl`], or [higher-ranked trait bounds] +/// (`for<'a>`). +/// +/// The `for` keyword is used in many syntactic locations: +/// +/// * `for` is used in for-in-loops (see below). +/// * `for` is used when implementing traits as in `impl Trait for Type` (see [`impl`] for more info +/// on that). +/// * `for` is also used for [higher-ranked trait bounds] as in `for<'a> &'a T: PartialEq`. /// -/// `for` is primarily used in for-in-loops, but it has a few other pieces of syntactic uses such as -/// `impl Trait for Type` (see [`impl`] for more info on that). for-in-loops, or to be more -/// precise, iterator loops, are a simple syntactic sugar over an exceedingly common practice -/// within Rust, which is to loop over an iterator until that iterator returns `None` (or `break` -/// is called). +/// for-in-loops, or to be more precise, iterator loops, are a simple syntactic sugar over a common +/// practice within Rust, which is to loop over an iterator until that iterator returns `None` (or +/// `break` is called). /// /// ```rust /// for i in 0..5 { @@ -346,16 +389,18 @@ mod fn_keyword { } /// /// For more information on for-loops, see the [Rust book] or the [Reference]. /// +/// [`in`]: keyword.in.html /// [`impl`]: keyword.impl.html +/// [higher-ranked trait bounds]: ../reference/trait-bounds.html#higher-ranked-trait-bounds /// [`IntoIterator`]: iter/trait.IntoIterator.html /// [Rust book]: -/// https://doc.rust-lang.org/book/2018-edition/ch03-05-control-flow.html#looping-through-a-collection-with-for -/// [Reference]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#iterator-loops +/// ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for +/// [Reference]: ../reference/expressions/loop-expr.html#iterator-loops mod for_keyword { } #[doc(keyword = "if")] // -/// If statements and expressions. +/// Evaluate a block if a condition holds. /// /// `if` is a familiar construct to most programmers, and is the main way you'll often do logic in /// your code. However, unlike in most languages, `if` blocks can also act as expressions. @@ -423,14 +468,13 @@ mod for_keyword { } /// /// For more information on `if` expressions, see the [Rust book] or the [Reference]. /// -/// [Rust book]: -/// https://doc.rust-lang.org/stable/book/2018-edition/ch03-05-control-flow.html#if-expressions -/// [Reference]: https://doc.rust-lang.org/reference/expressions/if-expr.html +/// [Rust book]: ../book/ch03-05-control-flow.html#if-expressions +/// [Reference]: ../reference/expressions/if-expr.html mod if_keyword { } #[doc(keyword = "impl")] // -/// The implementation-defining keyword. +/// Implement some functionality for a type. /// /// The `impl` keyword is primarily used to define implementations on types. Inherent /// implementations are standalone, while trait implementations are used to implement traits for @@ -486,15 +530,24 @@ mod if_keyword { } /// /// For more information on `impl Trait` syntax, see the [Rust book][book2]. /// -/// [book1]: https://doc.rust-lang.org/stable/book/2018-edition/ch05-03-method-syntax.html -/// [Reference]: https://doc.rust-lang.org/reference/items/implementations.html -/// [book2]: -/// https://doc.rust-lang.org/stable/book/2018-edition/ch10-02-traits.html#returning-traits +/// [book1]: ../book/ch05-03-method-syntax.html +/// [Reference]: ../reference/items/implementations.html +/// [book2]: ../book/ch10-02-traits.html#returning-types-that-implement-traits mod impl_keyword { } +#[doc(keyword = "in")] +// +/// Iterate over a series of values with [`for`]. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`for`]: keyword.for.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod in_keyword { } + #[doc(keyword = "let")] // -/// The variable binding keyword. +/// Bind a value to a variable. /// /// The primary use for the `let` keyword is in `let` statements, which are used to introduce a new /// set of variables into the current scope, as given by a pattern. @@ -547,18 +600,17 @@ mod impl_keyword { } /// enumerations. `while let` also exists, which runs a loop with a pattern matched value until /// that pattern can't be matched. /// -/// For more information on the `let` keyword, see the [Rust book] or the [Reference] +/// For more information on the `let` keyword, see the [Rust book][book2] or the [Reference] /// -/// [book1]: https://doc.rust-lang.org/stable/book/2018-edition/ch06-02-match.html +/// [book1]: ../book/ch06-02-match.html /// [`if`]: keyword.if.html -/// [book2]: -/// https://doc.rust-lang.org/stable/book/2018-edition/ch18-01-all-the-places-for-patterns.html#let-statements -/// [Reference]: https://doc.rust-lang.org/reference/statements.html#let-statements +/// [book2]: ../book/ch18-01-all-the-places-for-patterns.html#let-statements +/// [Reference]: ../reference/statements.html#let-statements mod let_keyword { } #[doc(keyword = "loop")] // -/// The loop-defining keyword. +/// Loop indefinitely. /// /// `loop` is used to define the simplest kind of loop supported in Rust. It runs the code inside /// it until the code uses `break` or the program exits. @@ -598,12 +650,107 @@ mod let_keyword { } /// /// For more information on `loop` and loops in general, see the [Reference]. /// -/// [Reference]: https://doc.rust-lang.org/reference/expressions/loop-expr.html +/// [Reference]: ../reference/expressions/loop-expr.html mod loop_keyword { } +#[doc(keyword = "match")] +// +/// Control flow based on pattern matching. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod match_keyword { } + +#[doc(keyword = "mod")] +// +/// Organize code into [modules]. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [modules]: ../reference/items/modules.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod mod_keyword { } + +#[doc(keyword = "move")] +// +/// Capture a [closure]'s environment by value. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [closure]: ../book/second-edition/ch13-01-closures.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod move_keyword { } + +#[doc(keyword = "mut")] +// +/// A mutable binding, reference, or pointer. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod mut_keyword { } + +#[doc(keyword = "pub")] +// +/// Make an item visible to others. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod pub_keyword { } + +#[doc(keyword = "ref")] +// +/// Bind by reference during pattern matching. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod ref_keyword { } + +#[doc(keyword = "return")] +// +/// Return a value from a function. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod return_keyword { } + +#[doc(keyword = "self")] +// +/// The receiver of a method, or the current module. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod self_keyword { } + +#[doc(keyword = "Self")] +// +/// The implementing type within a [`trait`] or [`impl`] block, or the current type within a type +/// definition. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`impl`]: keyword.impl.html +/// [`trait`]: keyword.trait.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod self_upper_keyword { } + +#[doc(keyword = "static")] +// +/// A place that is valid for the duration of a program. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod static_keyword { } + #[doc(keyword = "struct")] // -/// The keyword used to define structs. +/// A type that is composed of other types. /// /// Structs in Rust come in three flavors: Structs with named fields, tuple structs, and unit /// structs. @@ -705,6 +852,125 @@ mod loop_keyword { } /// [Reference][reference]. /// /// [`PhantomData`]: marker/struct.PhantomData.html -/// [book]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html -/// [reference]: https://doc.rust-lang.org/reference/items/structs.html +/// [book]: ../book/ch05-01-defining-structs.html +/// [reference]: ../reference/items/structs.html mod struct_keyword { } + +#[doc(keyword = "super")] +// +/// The parent of the current [module]. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [module]: ../reference/items/modules.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod super_keyword { } + +#[doc(keyword = "trait")] +// +/// A common interface for a class of types. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod trait_keyword { } + +#[doc(keyword = "true")] +// +/// A value of type [`bool`] representing logical **true**. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`bool`]: primitive.bool.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod true_keyword { } + +#[doc(keyword = "type")] +// +/// Define an alias for an existing type. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod type_keyword { } + +#[doc(keyword = "unsafe")] +// +/// Code or interfaces whose [memory safety] cannot be verified by the type system. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [memory safety]: ../book/ch19-01-unsafe-rust.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod unsafe_keyword { } + +#[doc(keyword = "use")] +// +/// Import or rename items from other crates or modules. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod use_keyword { } + +#[doc(keyword = "where")] +// +/// Add constraints that must be upheld to use an item. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod where_keyword { } + +#[doc(keyword = "while")] +// +/// Loop while a condition is upheld. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod while_keyword { } + +// 2018 Edition keywords + +#[unstable(feature = "async_await", issue = "50547")] +#[doc(keyword = "async")] +// +/// Return a [`Future`] instead of blocking the current thread. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`Future`]: ./future/trait.Future.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod async_keyword { } + +#[unstable(feature = "async_await", issue = "50547")] +#[doc(keyword = "await")] +// +/// Suspend execution until the result of a [`Future`] is ready. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`Future`]: ./future/trait.Future.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod await_keyword { } + +#[doc(keyword = "dyn")] +// +/// Name the type of a [trait object]. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [trait object]: ../book/ch17-02-trait-objects.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod dyn_keyword { } + +#[doc(keyword = "union")] +// +/// The [Rust equivalent of a C-style union][union]. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [union]: ../reference/items/unions.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod union_keyword { } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 32a168619dfb3..60e06139eba99 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -205,13 +205,13 @@ // Don't link to std. We are std. #![no_std] -#![deny(missing_docs)] -#![deny(intra_doc_link_resolution_failure)] -#![deny(missing_debug_implementations)] +//#![warn(deprecated_in_future)] // FIXME: std still has quite a few uses of `mem::uninitialized` +#![warn(missing_docs)] +#![warn(missing_debug_implementations)] +#![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings #![deny(rust_2018_idioms)] #![allow(explicit_outlives_requirements)] -#![allow(elided_lifetimes_in_paths)] // Tell the compiler to link to either panic_abort or panic_unwind #![needs_panic_runtime] @@ -219,18 +219,18 @@ // std may use features in a platform-specific way #![allow(unused_features)] -#![cfg_attr(test, feature(test, update_panic_count))] +#![cfg_attr(test, feature(print_internals, set_stdio, test, update_panic_count))] #![cfg_attr(all(target_vendor = "fortanix", target_env = "sgx"), - feature(global_asm, range_contains, slice_index_methods, + feature(global_asm, slice_index_methods, decl_macro, coerce_unsized, sgx_platform, ptr_wrapping_offset_from))] +#![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), + feature(fixed_size_array, maybe_uninit_extra))] // std is implemented with unstable features, many of which are internal // compiler details that will never be stable // NB: the following list is sorted to minimize merge conflicts. -#![feature(align_offset)] #![feature(alloc_error_handler)] #![feature(alloc_layout_extra)] -#![feature(alloc)] #![feature(allocator_api)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] @@ -245,6 +245,7 @@ #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] #![feature(checked_duration_since)] +#![feature(clamp)] #![feature(compiler_builtins_lib)] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] @@ -260,20 +261,17 @@ #![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] #![feature(external_doc)] -#![feature(fixed_size_array)] #![feature(fn_traits)] -#![feature(fnbox)] -#![feature(futures_api)] #![feature(generator_trait)] #![feature(hash_raw_entry)] #![feature(hashmap_internals)] #![feature(int_error_internals)] +#![feature(int_error_matching)] #![feature(integer_atomics)] #![feature(lang_items)] #![feature(libc)] #![feature(link_args)] #![feature(linkage)] -#![feature(maybe_uninit)] #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(nll)] @@ -300,6 +298,7 @@ #![feature(stmt_expr_attributes)] #![feature(str_internals)] #![feature(thread_local)] +#![feature(todo_macro)] #![feature(toowned_clone_into)] #![feature(try_reserve)] #![feature(unboxed_closures)] @@ -322,7 +321,7 @@ use prelude::v1::*; #[stable(feature = "rust1", since = "1.0.0")] pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::{unreachable, unimplemented, write, writeln, r#try}; +pub use core::{unreachable, unimplemented, write, writeln, r#try, todo}; #[allow(unused_imports)] // macros from `alloc` are not used on all platforms #[macro_use] @@ -336,6 +335,12 @@ extern crate libc; #[allow(unused_extern_crates)] extern crate unwind; +// Only needed for now for the `std_detect` module until that crate changes to +// use `cfg_if::cfg_if!` +#[macro_use] +#[cfg(not(test))] +extern crate cfg_if; + // During testing, this crate is not actually the "real" std library, but rather // it links to the real std library, which was compiled from this same source // code. So any lang items std defines are conditionally excluded (or else they @@ -435,6 +440,8 @@ pub use core::char; pub use core::u128; #[stable(feature = "core_hint", since = "1.27.0")] pub use core::hint; +#[stable(feature = "core_array", since = "1.36.0")] +pub use core::array; pub mod f32; pub mod f64; @@ -457,18 +464,15 @@ pub mod process; pub mod sync; pub mod time; -#[unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#[stable(feature = "futures_api", since = "1.36.0")] pub mod task { //! Types and Traits for working with asynchronous tasks. #[doc(inline)] + #[stable(feature = "futures_api", since = "1.36.0")] pub use core::task::*; } -#[unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#[stable(feature = "futures_api", since = "1.36.0")] pub mod future; // Platform-abstraction modules diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 281641c3c1232..d695141bef0b9 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -4,7 +4,7 @@ //! library. Each macro is available for use when linking against the standard //! library. -/// The entry point for panic of Rust threads. +/// Panics the current thread. /// /// This allows a program to terminate immediately and provide feedback /// to the caller of the program. `panic!` should be used when a program reaches @@ -53,17 +53,16 @@ /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(stage0, allow_internal_unstable)] -#[cfg_attr(not(stage0), allow_internal_unstable(__rust_unstable_column, libstd_sys_internals))] +#[allow_internal_unstable(__rust_unstable_column, libstd_sys_internals)] macro_rules! panic { () => ({ - panic!("explicit panic") + $crate::panic!("explicit panic") }); ($msg:expr) => ({ $crate::rt::begin_panic($msg, &(file!(), line!(), __rust_unstable_column!())) }); ($msg:expr,) => ({ - panic!($msg) + $crate::panic!($msg) }); ($fmt:expr, $($arg:tt)+) => ({ $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), @@ -71,7 +70,7 @@ macro_rules! panic { }); } -/// Macro for printing to the standard output. +/// Prints to the standard output. /// /// Equivalent to the [`println!`] macro except that a newline is not printed at /// the end of the message. @@ -112,13 +111,12 @@ macro_rules! panic { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(stage0, allow_internal_unstable)] -#[cfg_attr(not(stage0), allow_internal_unstable(print_internals))] +#[allow_internal_unstable(print_internals)] macro_rules! print { ($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*))); } -/// Macro for printing to the standard output, with a newline. +/// Prints to the standard output, with a newline. /// /// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone /// (no additional CARRIAGE RETURN (`\r`/`U+000D`). @@ -145,16 +143,15 @@ macro_rules! print { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(stage0, allow_internal_unstable)] -#[cfg_attr(not(stage0), allow_internal_unstable(print_internals, format_args_nl))] +#[allow_internal_unstable(print_internals, format_args_nl)] macro_rules! println { - () => (print!("\n")); + () => ($crate::print!("\n")); ($($arg:tt)*) => ({ $crate::io::_print(format_args_nl!($($arg)*)); }) } -/// Macro for printing to the standard error. +/// Prints to the standard error. /// /// Equivalent to the [`print!`] macro, except that output goes to /// [`io::stderr`] instead of `io::stdout`. See [`print!`] for @@ -177,13 +174,12 @@ macro_rules! println { /// ``` #[macro_export] #[stable(feature = "eprint", since = "1.19.0")] -#[cfg_attr(stage0, allow_internal_unstable)] -#[cfg_attr(not(stage0), allow_internal_unstable(print_internals))] +#[allow_internal_unstable(print_internals)] macro_rules! eprint { ($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*))); } -/// Macro for printing to the standard error, with a newline. +/// Prints to the standard error, with a newline. /// /// Equivalent to the [`println!`] macro, except that output goes to /// [`io::stderr`] instead of `io::stdout`. See [`println!`] for @@ -206,17 +202,18 @@ macro_rules! eprint { /// ``` #[macro_export] #[stable(feature = "eprint", since = "1.19.0")] -#[cfg_attr(stage0, allow_internal_unstable)] -#[cfg_attr(not(stage0), allow_internal_unstable(print_internals, format_args_nl))] +#[allow_internal_unstable(print_internals, format_args_nl)] macro_rules! eprintln { - () => (eprint!("\n")); + () => ($crate::eprint!("\n")); ($($arg:tt)*) => ({ $crate::io::_eprint(format_args_nl!($($arg)*)); }) } -/// A macro for quick and dirty debugging with which you can inspect -/// the value of a given expression. An example: +/// Prints and returns the value of a given expression for quick and dirty +/// debugging. +/// +/// An example: /// /// ```rust /// let a = 2; @@ -236,10 +233,14 @@ macro_rules! eprintln { /// to give up ownership, you can instead borrow with `dbg!(&expr)` /// for some expression `expr`. /// +/// The `dbg!` macro works exactly the same in release builds. +/// This is useful when debugging issues that only occur in release +/// builds or when debugging in release mode is significantly faster. +/// /// Note that the macro is intended as a debugging tool and therefore you /// should avoid having uses of it in version control for longer periods. /// Use cases involving debug output that should be added to version control -/// may be better served by macros such as `debug!` from the `log` crate. +/// are better served by macros such as [`debug!`] from the [`log`] crate. /// /// # Stability /// @@ -310,100 +311,50 @@ macro_rules! eprintln { /// let _ = dbg!(a); // <-- `a` is moved again; error! /// ``` /// +/// You can also use `dbg!()` without a value to just print the +/// file and line whenever it's reached. +/// +/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as +/// a tuple (and return it, too): +/// +/// ``` +/// assert_eq!(dbg!(1usize, 2u32), (1, 2)); +/// ``` +/// +/// However, a single argument with a trailing comma will still not be treated +/// as a tuple, following the convention of ignoring trailing commas in macro +/// invocations. You can use a 1-tuple directly if you need one: +/// +/// ``` +/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored +/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple +/// ``` +/// /// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr) +/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html +/// [`log`]: https://crates.io/crates/log #[macro_export] #[stable(feature = "dbg_macro", since = "1.32.0")] macro_rules! dbg { + () => { + $crate::eprintln!("[{}:{}]", file!(), line!()); + }; ($val:expr) => { // Use of `match` here is intentional because it affects the lifetimes // of temporaries - https://stackoverflow.com/a/48732525/1063961 match $val { tmp => { - eprintln!("[{}:{}] {} = {:#?}", + $crate::eprintln!("[{}:{}] {} = {:#?}", file!(), line!(), stringify!($val), &tmp); tmp } } - } -} - -/// A macro to await on an async call. -#[macro_export] -#[unstable(feature = "await_macro", issue = "50547")] -#[cfg_attr(stage0, allow_internal_unstable)] -#[cfg_attr(not(stage0), allow_internal_unstable(gen_future, generators))] -#[allow_internal_unsafe] -macro_rules! r#await { - ($e:expr) => { { - let mut pinned = $e; - loop { - if let $crate::task::Poll::Ready(x) = - $crate::future::poll_with_tls_waker(unsafe { - $crate::pin::Pin::new_unchecked(&mut pinned) - }) - { - break x; - } - // FIXME(cramertj) prior to stabilizing await, we have to ensure that this - // can't be used to create a generator on stable via `|| await!()`. - yield - } - } } -} - -/// A macro to select an event from a number of receivers. -/// -/// This macro is used to wait for the first event to occur on a number of -/// receivers. It places no restrictions on the types of receivers given to -/// this macro, this can be viewed as a heterogeneous select. -/// -/// # Examples -/// -/// ``` -/// #![feature(mpsc_select)] -/// -/// use std::thread; -/// use std::sync::mpsc; -/// -/// // two placeholder functions for now -/// fn long_running_thread() {} -/// fn calculate_the_answer() -> u32 { 42 } -/// -/// let (tx1, rx1) = mpsc::channel(); -/// let (tx2, rx2) = mpsc::channel(); -/// -/// thread::spawn(move|| { long_running_thread(); tx1.send(()).unwrap(); }); -/// thread::spawn(move|| { tx2.send(calculate_the_answer()).unwrap(); }); -/// -/// select! { -/// _ = rx1.recv() => println!("the long running thread finished first"), -/// answer = rx2.recv() => { -/// println!("the answer was: {}", answer.unwrap()); -/// } -/// } -/// # drop(rx1.recv()); -/// # drop(rx2.recv()); -/// ``` -/// -/// For more information about select, see the `std::sync::mpsc::Select` structure. -#[macro_export] -#[unstable(feature = "mpsc_select", issue = "27800")] -#[rustc_deprecated(since = "1.32.0", - reason = "channel selection will be removed in a future release")] -macro_rules! select { - ( - $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ - ) => ({ - use $crate::sync::mpsc::Select; - let sel = Select::new(); - $( let mut $rx = sel.handle(&$rx); )+ - unsafe { - $( $rx.add(); )+ - } - let ret = sel.wait(); - $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+ - { unreachable!() } - }) + }; + // Trailing comma with single argument is ignored + ($val:expr,) => { $crate::dbg!($val) }; + ($($val:expr),+ $(,)?) => { + ($($crate::dbg!($val)),+,) + }; } #[cfg(test)] @@ -423,7 +374,7 @@ macro_rules! assert_approx_eq { #[cfg(rustdoc)] mod builtin { - /// Unconditionally causes compilation to fail with the given error message when encountered. + /// Causes compilation to fail with the given error message when encountered. /// /// This macro should be used when a crate uses a conditional compilation strategy to provide /// better error messages for erroneous conditions. It's the compiler-level form of [`panic!`], @@ -454,7 +405,7 @@ mod builtin { /// /// ```compile_fail /// #[cfg(not(any(feature = "foo", feature = "bar")))] - /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate.") + /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate."); /// ``` /// /// [`panic!`]: ../std/macro.panic.html @@ -465,7 +416,7 @@ mod builtin { ($msg:expr,) => ({ /* compiler built-in */ }); } - /// The core macro for formatted string creation & output. + /// Constructs parameters for the other string-formatting macros. /// /// This macro functions by taking a formatting string literal containing /// `{}` for each additional argument passed. `format_args!` prepares the @@ -517,7 +468,7 @@ mod builtin { ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); } - /// Inspect an environment variable at compile time. + /// Inspects an environment variable at compile time. /// /// This macro will expand to the value of the named environment variable at /// compile time, yielding an expression of type `&'static str`. @@ -555,7 +506,7 @@ mod builtin { ($name:expr,) => ({ /* compiler built-in */ }); } - /// Optionally inspect an environment variable at compile time. + /// Optionally inspects an environment variable at compile time. /// /// If the named environment variable is present at compile time, this will /// expand into an expression of type `Option<&'static str>` whose value is @@ -581,7 +532,7 @@ mod builtin { ($name:expr,) => ({ /* compiler built-in */ }); } - /// Concatenate identifiers into one identifier. + /// Concatenates identifiers into one identifier. /// /// This macro takes any number of comma-separated identifiers, and /// concatenates them all into one, yielding an expression which is a new @@ -634,7 +585,7 @@ mod builtin { ($($e:expr,)*) => ({ /* compiler built-in */ }); } - /// A macro which expands to the line number on which it was invoked. + /// Expands to the line number on which it was invoked. /// /// With [`column!`] and [`file!`], these macros provide debugging information for /// developers about the location within the source. @@ -659,7 +610,7 @@ mod builtin { #[rustc_doc_only_macro] macro_rules! line { () => ({ /* compiler built-in */ }) } - /// A macro which expands to the column number on which it was invoked. + /// Expands to the column number at which it was invoked. /// /// With [`line!`] and [`file!`], these macros provide debugging information for /// developers about the location within the source. @@ -684,7 +635,7 @@ mod builtin { #[rustc_doc_only_macro] macro_rules! column { () => ({ /* compiler built-in */ }) } - /// A macro which expands to the file name from which it was invoked. + /// Expands to the file name in which it was invoked. /// /// With [`line!`] and [`column!`], these macros provide debugging information for /// developers about the location within the source. @@ -708,7 +659,7 @@ mod builtin { #[rustc_doc_only_macro] macro_rules! file { () => ({ /* compiler built-in */ }) } - /// A macro which stringifies its arguments. + /// Stringifies its arguments. /// /// This macro will yield an expression of type `&'static str` which is the /// stringification of all the tokens passed to the macro. No restrictions @@ -822,15 +773,17 @@ mod builtin { #[rustc_doc_only_macro] macro_rules! module_path { () => ({ /* compiler built-in */ }) } - /// Boolean evaluation of configuration flags, at compile-time. + /// Evaluates boolean combinations of configuration flags at compile-time. /// /// In addition to the `#[cfg]` attribute, this macro is provided to allow /// boolean expression evaluation of configuration flags. This frequently /// leads to less duplicated code. /// - /// The syntax given to this macro is the same syntax as the `cfg` + /// The syntax given to this macro is the same syntax as the [`cfg`] /// attribute. /// + /// [`cfg`]: ../reference/conditional-compilation.html#the-cfg-attribute + /// /// # Examples /// /// ``` @@ -844,7 +797,7 @@ mod builtin { #[rustc_doc_only_macro] macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } - /// Parse a file as an expression or an item according to the context. + /// Parses a file as an expression or an item according to the context. /// /// The file is located relative to the current file (similarly to how /// modules are found). @@ -890,7 +843,7 @@ mod builtin { ($file:expr,) => ({ /* compiler built-in */ }); } - /// Ensure that a boolean expression is `true` at runtime. + /// Asserts that a boolean expression is `true` at runtime. /// /// This will invoke the [`panic!`] macro if the provided expression cannot be /// evaluated to `true` at runtime. @@ -943,39 +896,3 @@ mod builtin { ($cond:expr, $($arg:tt)+) => ({ /* compiler built-in */ }); } } - -/// A macro for defining `#[cfg]` if-else statements. -/// -/// This is similar to the `if/elif` C preprocessor macro by allowing definition -/// of a cascade of `#[cfg]` cases, emitting the implementation which matches -/// first. -/// -/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code -/// without having to rewrite each clause multiple times. -macro_rules! cfg_if { - ($( - if #[cfg($($meta:meta),*)] { $($it:item)* } - ) else * else { - $($it2:item)* - }) => { - __cfg_if_items! { - () ; - $( ( ($($meta),*) ($($it)*) ), )* - ( () ($($it2)*) ), - } - } -} - -macro_rules! __cfg_if_items { - (($($not:meta,)*) ; ) => {}; - (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { - __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* } - __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* } - } -} - -macro_rules! __cfg_if_apply { - ($m:meta, $($it:item)*) => { - $(#[$m] $it)* - } -} diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index f5a87cc3ea67a..ca86a175058b5 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -546,6 +546,9 @@ impl FromInner for SocketAddrV6 { #[stable(feature = "ip_from_ip", since = "1.16.0")] impl From for SocketAddr { /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`]. + /// + /// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html + /// [`SocketAddr::V4`]: ../../std/net/enum.SocketAddr.html#variant.V4 fn from(sock4: SocketAddrV4) -> SocketAddr { SocketAddr::V4(sock4) } @@ -554,6 +557,9 @@ impl From for SocketAddr { #[stable(feature = "ip_from_ip", since = "1.16.0")] impl From for SocketAddr { /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`]. + /// + /// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html + /// [`SocketAddr::V6`]: ../../std/net/enum.SocketAddr.html#variant.V6 fn from(sock6: SocketAddrV6) -> SocketAddr { SocketAddr::V6(sock6) } @@ -567,6 +573,13 @@ impl> From<(I, u16)> for SocketAddr { /// and creates a [`SocketAddr::V6`] for a [`IpAddr::V6`]. /// /// `u16` is treated as port of the newly created [`SocketAddr`]. + /// + /// [`IpAddr`]: ../../std/net/enum.IpAddr.html + /// [`IpAddr::V4`]: ../../std/net/enum.IpAddr.html#variant.V4 + /// [`IpAddr::V6`]: ../../std/net/enum.IpAddr.html#variant.V6 + /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html + /// [`SocketAddr::V4`]: ../../std/net/enum.SocketAddr.html#variant.V4 + /// [`SocketAddr::V6`]: ../../std/net/enum.SocketAddr.html#variant.V6 fn from(pieces: (I, u16)) -> SocketAddr { SocketAddr::new(pieces.0.into(), pieces.1) } @@ -587,7 +600,7 @@ impl<'a> IntoInner<(*const c::sockaddr, c::socklen_t)> for &'a SocketAddr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for SocketAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { SocketAddr::V4(ref a) => a.fmt(f), SocketAddr::V6(ref a) => a.fmt(f), @@ -597,28 +610,28 @@ impl fmt::Display for SocketAddr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for SocketAddrV4 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", self.ip(), self.port()) } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for SocketAddrV4 { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, fmt) } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for SocketAddrV6 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "[{}]:{}", self.ip(), self.port()) } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for SocketAddrV6 { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, fmt) } } @@ -941,7 +954,10 @@ mod tests { assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53))); let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); + #[cfg(not(target_env = "sgx"))] assert!(tsa(("localhost", 23924)).unwrap().contains(&a)); + #[cfg(target_env = "sgx")] + let _ = a; } #[test] @@ -953,7 +969,10 @@ mod tests { assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53")); let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); + #[cfg(not(target_env = "sgx"))] assert!(tsa("localhost:23924").unwrap().contains(&a)); + #[cfg(target_env = "sgx")] + let _ = a; } #[test] @@ -968,9 +987,9 @@ mod tests { // s has been moved into the tsa call } - // FIXME: figure out why this fails on openbsd and bitrig and fix it + // FIXME: figure out why this fails on openbsd and fix it #[test] - #[cfg(not(any(windows, target_os = "openbsd", target_os = "bitrig")))] + #[cfg(not(any(windows, target_os = "openbsd")))] fn to_socket_addr_str_bad() { assert!(tsa("1200::AB00:1234::2552:7777:1313:34300").is_err()); } diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index fa256ce508655..6b504056e5f87 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -502,12 +502,19 @@ impl Ipv4Addr { /// /// The following return false: /// - /// - private address (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16) - /// - the loopback address (127.0.0.0/8) - /// - the link-local address (169.254.0.0/16) - /// - the broadcast address (255.255.255.255/32) - /// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24) - /// - the unspecified address (0.0.0.0) + /// - private addresses (see [`is_private()`](#method.is_private)) + /// - the loopback address (see [`is_loopback()`](#method.is_loopback)) + /// - the link-local address (see [`is_link_local()`](#method.is_link_local)) + /// - the broadcast address (see [`is_broadcast()`](#method.is_broadcast)) + /// - addresses used for documentation (see [`is_documentation()`](#method.is_documentation)) + /// - the unspecified address (see [`is_unspecified()`](#method.is_unspecified)), and the whole + /// 0.0.0.0/8 block + /// - addresses reserved for future protocols (see + /// [`is_ietf_protocol_assignment()`](#method.is_ietf_protocol_assignment), except + /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable + /// - addresses reserved for future use (see [`is_reserved()`](#method.is_reserved) + /// - addresses reserved for networking devices benchmarking (see + /// [`is_benchmarking`](#method.is_benchmarking)) /// /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml /// [`true`]: ../../std/primitive.bool.html @@ -520,16 +527,181 @@ impl Ipv4Addr { /// use std::net::Ipv4Addr; /// /// fn main() { + /// // private addresses are not global /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); + /// + /// // the 0.0.0.0/8 block is not global + /// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false); + /// // in particular, the unspecified address is not global /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); + /// + /// // the loopback address is not global + /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false); + /// + /// // link local addresses are not global + /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); + /// + /// // the broadcast address is not global + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false); + /// + /// // the broadcast address is not global + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); + /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); + /// + /// // shared addresses are not global + /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); + /// + /// // addresses reserved for protocol assignment are not global + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false); + /// + /// // addresses reserved for future use are not global + /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); + /// + /// // addresses reserved for network devices benchmarking are not global + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); + /// + /// // All the other addresses are global + /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); /// } /// ``` pub fn is_global(&self) -> bool { - !self.is_private() && !self.is_loopback() && !self.is_link_local() && - !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified() + // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two + // globally routable addresses in the 192.0.0.0/24 range. + if u32::from(*self) == 0xc0000009 || u32::from(*self) == 0xc000000a { + return true; + } + !self.is_private() + && !self.is_loopback() + && !self.is_link_local() + && !self.is_broadcast() + && !self.is_documentation() + && !self.is_shared() + && !self.is_ietf_protocol_assignment() + && !self.is_reserved() + && !self.is_benchmarking() + // Make sure the address is not in 0.0.0.0/8 + && self.octets()[0] != 0 + } + + /// Returns [`true`] if this address is part of the Shared Address Space defined in + /// [IETF RFC 6598] (`100.64.0.0/10`). + /// + /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv4Addr; + /// + /// fn main() { + /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); + /// } + /// ``` + pub fn is_shared(&self) -> bool { + self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) + } + + /// Returns [`true`] if this address is part of `192.0.0.0/24`, which is reserved to + /// IANA for IETF protocol assignments, as documented in [IETF RFC 6890]. + /// + /// Note that parts of this block are in use: + /// + /// - `192.0.0.8/32` is the "IPv4 dummy address" (see [IETF RFC 7600]) + /// - `192.0.0.9/32` is the "Port Control Protocol Anycast" (see [IETF RFC 7723]) + /// - `192.0.0.10/32` is used for NAT traversal (see [IETF RFC 8155]) + /// + /// [IETF RFC 6890]: https://tools.ietf.org/html/rfc6890 + /// [IETF RFC 7600]: https://tools.ietf.org/html/rfc7600 + /// [IETF RFC 7723]: https://tools.ietf.org/html/rfc7723 + /// [IETF RFC 8155]: https://tools.ietf.org/html/rfc8155 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv4Addr; + /// + /// fn main() { + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 8).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 9).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false); + /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); + /// } + /// ``` + pub fn is_ietf_protocol_assignment(&self) -> bool { + self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 + } + + /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for + /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` + /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. + /// + /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 + /// [errate 423]: https://www.rfc-editor.org/errata/eid423 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv4Addr; + /// + /// fn main() { + /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); + /// } + /// ``` + pub fn is_benchmarking(&self) -> bool { + self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 + } + + /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] + /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the + /// broadcast address `255.255.255.255`, but this implementation explicitely excludes it, since + /// it is obviously not reserved for future use. + /// + /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Warning + /// + /// As IANA assigns new addresses, this method will be + /// updated. This may result in non-reserved addresses being + /// treated as reserved in code that relies on an outdated version + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv4Addr; + /// + /// fn main() { + /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); + /// + /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); + /// // The broadcast address is not considered as reserved for future use by this + /// // implementation + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); + /// } + /// ``` + pub fn is_reserved(&self) -> bool { + self.octets()[0] & 240 == 240 && !self.is_broadcast() } /// Returns [`true`] if this is a multicast address (224.0.0.0/4). @@ -658,7 +830,7 @@ impl Ipv4Addr { #[stable(feature = "ip_addr", since = "1.7.0")] impl fmt::Display for IpAddr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self { IpAddr::V4(ip) => ip.fmt(fmt), IpAddr::V6(ip) => ip.fmt(fmt), @@ -682,7 +854,7 @@ impl From for IpAddr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Ipv4Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let octets = self.octets(); write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) } @@ -690,7 +862,7 @@ impl fmt::Display for Ipv4Addr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Ipv4Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, fmt) } } @@ -1003,7 +1175,7 @@ impl Ipv6Addr { } } - /// Returns [`true`] if this is a unique local address (fc00::/7). + /// Returns [`true`] if this is a unique local address (`fc00::/7`). /// /// This property is defined in [IETF RFC 4193]. /// @@ -1027,12 +1199,83 @@ impl Ipv6Addr { (self.segments()[0] & 0xfe00) == 0xfc00 } - /// Returns [`true`] if the address is unicast and link-local (fe80::/10). + /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`). /// - /// This property is defined in [IETF RFC 4291]. + /// A common mis-conception is to think that "unicast link-local addresses start with + /// `fe80::`", but the [IETF RFC 4291] actually defines a stricter format for these addresses: + /// + /// ```no_rust + /// | 10 | + /// | bits | 54 bits | 64 bits | + /// +----------+-------------------------+----------------------------+ + /// |1111111010| 0 | interface ID | + /// +----------+-------------------------+----------------------------+ + /// ``` + /// + /// This method validates the format defined in the RFC and won't recognize the following + /// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example. + /// If you need a less strict validation use [`is_unicast_link_local()`] instead. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// fn main() { + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local_strict()); + /// + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); + /// assert!(ip.is_unicast_link_local_strict()); + /// + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); + /// assert!(!ip.is_unicast_link_local_strict()); + /// assert!(ip.is_unicast_link_local()); + /// + /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); + /// assert!(!ip.is_unicast_link_local_strict()); + /// assert!(ip.is_unicast_link_local()); + /// } + /// ``` + /// + /// # See also + /// + /// - [IETF RFC 4291 section 2.5.6] + /// - [RFC 4291 errata 4406] + /// - [`is_unicast_link_local()`] /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 /// [`true`]: ../../std/primitive.bool.html + /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 + /// [`is_unicast_link_local()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local + /// + pub fn is_unicast_link_local_strict(&self) -> bool { + (self.segments()[0] & 0xffff) == 0xfe80 + && (self.segments()[1] & 0xffff) == 0 + && (self.segments()[2] & 0xffff) == 0 + && (self.segments()[3] & 0xffff) == 0 + } + + /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). + /// + /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4], + /// i.e. addresses with the following format: + /// + /// ```no_rust + /// | 10 | + /// | bits | 54 bits | 64 bits | + /// +----------+-------------------------+----------------------------+ + /// |1111111010| arbitratry value | interface ID | + /// +----------+-------------------------+----------------------------+ + /// ``` + /// + /// As a result, this method consider addresses such as `fe80:0:0:1::` or `fe81::` to be + /// unicast link-local addresses, whereas [`is_unicast_link_local_strict()`] does not. If you + /// need a strict validation fully compliant with the RFC, use + /// [`is_unicast_link_local_strict()`]. /// /// # Examples /// @@ -1042,19 +1285,49 @@ impl Ipv6Addr { /// use std::net::Ipv6Addr; /// /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_link_local(), - /// false); - /// assert_eq!(Ipv6Addr::new(0xfe8a, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local()); + /// + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); + /// assert!(ip.is_unicast_link_local()); + /// + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local()); + /// assert!(!ip.is_unicast_link_local_strict()); + /// + /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local()); + /// assert!(!ip.is_unicast_link_local_strict()); /// } /// ``` + /// + /// # See also + /// + /// - [IETF RFC 4291 section 2.4] + /// - [RFC 4291 errata 4406] + /// + /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 + /// [`true`]: ../../std/primitive.bool.html + /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 + /// [`is_unicast_link_local_strict()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local_strict + /// pub fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 } - /// Returns [`true`] if this is a deprecated unicast site-local address - /// (fec0::/10). + /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The + /// unicast site-local address format is defined in [RFC 4291 section 2.5.7] as: + /// + /// ```no_rust + /// | 10 | + /// | bits | 54 bits | 64 bits | + /// +----------+-------------------------+----------------------------+ + /// |1111111011| subnet ID | interface ID | + /// +----------+-------------------------+----------------------------+ + /// ``` /// /// [`true`]: ../../std/primitive.bool.html + /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 /// /// # Examples /// @@ -1069,6 +1342,14 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true); /// } /// ``` + /// + /// # Warning + /// + /// As per [RFC 3879], the whole `FEC0::/10` prefix is + /// deprecated. New software must not support site-local + /// addresses. + /// + /// [RFC 3879]: https://tools.ietf.org/html/rfc3879 pub fn is_unicast_site_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfec0 } @@ -1104,12 +1385,20 @@ impl Ipv6Addr { /// /// - the loopback address /// - the link-local addresses - /// - the (deprecated) site-local addresses /// - unique local addresses /// - the unspecified address /// - the address range reserved for documentation /// + /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7] + /// + /// ```no_rust + /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer + /// be supported in new implementations (i.e., new implementations must treat this prefix as + /// Global Unicast). + /// ``` + /// /// [`true`]: ../../std/primitive.bool.html + /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 /// /// # Examples /// @@ -1126,9 +1415,11 @@ impl Ipv6Addr { /// ``` pub fn is_unicast_global(&self) -> bool { !self.is_multicast() - && !self.is_loopback() && !self.is_unicast_link_local() - && !self.is_unicast_site_local() && !self.is_unique_local() - && !self.is_unspecified() && !self.is_documentation() + && !self.is_loopback() + && !self.is_unicast_link_local() + && !self.is_unique_local() + && !self.is_unspecified() + && !self.is_documentation() } /// Returns the address's multicast scope if the address is multicast. @@ -1229,7 +1520,7 @@ impl Ipv6Addr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Ipv6Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self.segments() { // We need special cases for :: and ::1, otherwise they're formatted // as ::0.0.0.[01] @@ -1276,7 +1567,7 @@ impl fmt::Display for Ipv6Addr { let (zeros_at, zeros_len) = find_zero_slice(&self.segments()); if zeros_len > 1 { - fn fmt_subslice(segments: &[u16], fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt_subslice(segments: &[u16], fmt: &mut fmt::Formatter<'_>) -> fmt::Result { if !segments.is_empty() { write!(fmt, "{:x}", segments[0])?; for &seg in &segments[1..] { @@ -1301,7 +1592,7 @@ impl fmt::Display for Ipv6Addr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Ipv6Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, fmt) } } @@ -1510,8 +1801,8 @@ impl From<[u16; 8]> for IpAddr { #[cfg(all(test, not(target_os = "emscripten")))] mod tests { use crate::net::*; - use crate::net::Ipv6MulticastScope::*; use crate::net::test::{tsa, sa6, sa4}; + use crate::str::FromStr; #[test] fn test_from_str_ipv4() { @@ -1675,164 +1966,491 @@ mod tests { #[test] fn ip_properties() { - fn check4(octets: &[u8; 4], unspec: bool, loopback: bool, - global: bool, multicast: bool, documentation: bool) { - let ip = IpAddr::V4(Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])); - assert_eq!(ip.is_unspecified(), unspec); - assert_eq!(ip.is_loopback(), loopback); - assert_eq!(ip.is_global(), global); - assert_eq!(ip.is_multicast(), multicast); - assert_eq!(ip.is_documentation(), documentation); + macro_rules! ip { + ($s:expr) => { + IpAddr::from_str($s).unwrap() + } } - fn check6(str_addr: &str, unspec: bool, loopback: bool, - global: bool, u_doc: bool, mcast: bool) { - let ip = IpAddr::V6(str_addr.parse().unwrap()); - assert_eq!(ip.is_unspecified(), unspec); - assert_eq!(ip.is_loopback(), loopback); - assert_eq!(ip.is_global(), global); - assert_eq!(ip.is_documentation(), u_doc); - assert_eq!(ip.is_multicast(), mcast); + macro_rules! check { + ($s:expr) => { + check!($s, 0); + }; + + ($s:expr, $mask:expr) => {{ + let unspec: u8 = 1 << 0; + let loopback: u8 = 1 << 1; + let global: u8 = 1 << 2; + let multicast: u8 = 1 << 3; + let doc: u8 = 1 << 4; + + if ($mask & unspec) == unspec { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + + if ($mask & multicast) == multicast { + assert!(ip!($s).is_multicast()); + } else { + assert!(!ip!($s).is_multicast()); + } + + if ($mask & doc) == doc { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + }} } - // address unspec loopbk global multicast doc - check4(&[0, 0, 0, 0], true, false, false, false, false); - check4(&[0, 0, 0, 1], false, false, true, false, false); - check4(&[0, 1, 0, 0], false, false, true, false, false); - check4(&[10, 9, 8, 7], false, false, false, false, false); - check4(&[127, 1, 2, 3], false, true, false, false, false); - check4(&[172, 31, 254, 253], false, false, false, false, false); - check4(&[169, 254, 253, 242], false, false, false, false, false); - check4(&[192, 0, 2, 183], false, false, false, false, true); - check4(&[192, 1, 2, 183], false, false, true, false, false); - check4(&[192, 168, 254, 253], false, false, false, false, false); - check4(&[198, 51, 100, 0], false, false, false, false, true); - check4(&[203, 0, 113, 0], false, false, false, false, true); - check4(&[203, 2, 113, 0], false, false, true, false, false); - check4(&[224, 0, 0, 0], false, false, true, true, false); - check4(&[239, 255, 255, 255], false, false, true, true, false); - check4(&[255, 255, 255, 255], false, false, false, false, false); - - // address unspec loopbk global doc mcast - check6("::", true, false, false, false, false); - check6("::1", false, true, false, false, false); - check6("::0.0.0.2", false, false, true, false, false); - check6("1::", false, false, true, false, false); - check6("fc00::", false, false, false, false, false); - check6("fdff:ffff::", false, false, false, false, false); - check6("fe80:ffff::", false, false, false, false, false); - check6("febf:ffff::", false, false, false, false, false); - check6("fec0::", false, false, false, false, false); - check6("ff01::", false, false, false, false, true); - check6("ff02::", false, false, false, false, true); - check6("ff03::", false, false, false, false, true); - check6("ff04::", false, false, false, false, true); - check6("ff05::", false, false, false, false, true); - check6("ff08::", false, false, false, false, true); - check6("ff0e::", false, false, true, false, true); - check6("2001:db8:85a3::8a2e:370:7334", false, false, false, true, false); - check6("102:304:506:708:90a:b0c:d0e:f10", false, false, true, false, false); + let unspec: u8 = 1 << 0; + let loopback: u8 = 1 << 1; + let global: u8 = 1 << 2; + let multicast: u8 = 1 << 3; + let doc: u8 = 1 << 4; + + check!("0.0.0.0", unspec); + check!("0.0.0.1"); + check!("0.1.0.0"); + check!("10.9.8.7"); + check!("127.1.2.3", loopback); + check!("172.31.254.253"); + check!("169.254.253.242"); + check!("192.0.2.183", doc); + check!("192.1.2.183", global); + check!("192.168.254.253"); + check!("198.51.100.0", doc); + check!("203.0.113.0", doc); + check!("203.2.113.0", global); + check!("224.0.0.0", global|multicast); + check!("239.255.255.255", global|multicast); + check!("255.255.255.255"); + // make sure benchmarking addresses are not global + check!("198.18.0.0"); + check!("198.18.54.2"); + check!("198.19.255.255"); + // make sure addresses reserved for protocol assignment are not global + check!("192.0.0.0"); + check!("192.0.0.255"); + check!("192.0.0.100"); + // make sure reserved addresses are not global + check!("240.0.0.0"); + check!("251.54.1.76"); + check!("254.255.255.255"); + // make sure shared addresses are not global + check!("100.64.0.0"); + check!("100.127.255.255"); + check!("100.100.100.0"); + + check!("::", unspec); + check!("::1", loopback); + check!("::0.0.0.2", global); + check!("1::", global); + check!("fc00::"); + check!("fdff:ffff::"); + check!("fe80:ffff::"); + check!("febf:ffff::"); + check!("fec0::", global); + check!("ff01::", multicast); + check!("ff02::", multicast); + check!("ff03::", multicast); + check!("ff04::", multicast); + check!("ff05::", multicast); + check!("ff08::", multicast); + check!("ff0e::", global|multicast); + check!("2001:db8:85a3::8a2e:370:7334", doc); + check!("102:304:506:708:90a:b0c:d0e:f10", global); } #[test] fn ipv4_properties() { - fn check(octets: &[u8; 4], unspec: bool, loopback: bool, - private: bool, link_local: bool, global: bool, - multicast: bool, broadcast: bool, documentation: bool) { - let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]); - assert_eq!(octets, &ip.octets()); - - assert_eq!(ip.is_unspecified(), unspec); - assert_eq!(ip.is_loopback(), loopback); - assert_eq!(ip.is_private(), private); - assert_eq!(ip.is_link_local(), link_local); - assert_eq!(ip.is_global(), global); - assert_eq!(ip.is_multicast(), multicast); - assert_eq!(ip.is_broadcast(), broadcast); - assert_eq!(ip.is_documentation(), documentation); + macro_rules! ip { + ($s:expr) => { + Ipv4Addr::from_str($s).unwrap() + } } - // address unspec loopbk privt linloc global multicast brdcast doc - check(&[0, 0, 0, 0], true, false, false, false, false, false, false, false); - check(&[0, 0, 0, 1], false, false, false, false, true, false, false, false); - check(&[0, 1, 0, 0], false, false, false, false, true, false, false, false); - check(&[10, 9, 8, 7], false, false, true, false, false, false, false, false); - check(&[127, 1, 2, 3], false, true, false, false, false, false, false, false); - check(&[172, 31, 254, 253], false, false, true, false, false, false, false, false); - check(&[169, 254, 253, 242], false, false, false, true, false, false, false, false); - check(&[192, 0, 2, 183], false, false, false, false, false, false, false, true); - check(&[192, 1, 2, 183], false, false, false, false, true, false, false, false); - check(&[192, 168, 254, 253], false, false, true, false, false, false, false, false); - check(&[198, 51, 100, 0], false, false, false, false, false, false, false, true); - check(&[203, 0, 113, 0], false, false, false, false, false, false, false, true); - check(&[203, 2, 113, 0], false, false, false, false, true, false, false, false); - check(&[224, 0, 0, 0], false, false, false, false, true, true, false, false); - check(&[239, 255, 255, 255], false, false, false, false, true, true, false, false); - check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false); + macro_rules! check { + ($s:expr) => { + check!($s, 0); + }; + + ($s:expr, $mask:expr) => {{ + let unspec: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let private: u16 = 1 << 2; + let link_local: u16 = 1 << 3; + let global: u16 = 1 << 4; + let multicast: u16 = 1 << 5; + let broadcast: u16 = 1 << 6; + let documentation: u16 = 1 << 7; + let benchmarking: u16 = 1 << 8; + let ietf_protocol_assignment: u16 = 1 << 9; + let reserved: u16 = 1 << 10; + let shared: u16 = 1 << 11; + + if ($mask & unspec) == unspec { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + + if ($mask & private) == private { + assert!(ip!($s).is_private()); + } else { + assert!(!ip!($s).is_private()); + } + + if ($mask & link_local) == link_local { + assert!(ip!($s).is_link_local()); + } else { + assert!(!ip!($s).is_link_local()); + } + + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + + if ($mask & multicast) == multicast { + assert!(ip!($s).is_multicast()); + } else { + assert!(!ip!($s).is_multicast()); + } + + if ($mask & broadcast) == broadcast { + assert!(ip!($s).is_broadcast()); + } else { + assert!(!ip!($s).is_broadcast()); + } + + if ($mask & documentation) == documentation { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } + + if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment { + assert!(ip!($s).is_ietf_protocol_assignment()); + } else { + assert!(!ip!($s).is_ietf_protocol_assignment()); + } + + if ($mask & reserved) == reserved { + assert!(ip!($s).is_reserved()); + } else { + assert!(!ip!($s).is_reserved()); + } + + if ($mask & shared) == shared { + assert!(ip!($s).is_shared()); + } else { + assert!(!ip!($s).is_shared()); + } + }} + } + + let unspec: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let private: u16 = 1 << 2; + let link_local: u16 = 1 << 3; + let global: u16 = 1 << 4; + let multicast: u16 = 1 << 5; + let broadcast: u16 = 1 << 6; + let documentation: u16 = 1 << 7; + let benchmarking: u16 = 1 << 8; + let ietf_protocol_assignment: u16 = 1 << 9; + let reserved: u16 = 1 << 10; + let shared: u16 = 1 << 11; + + check!("0.0.0.0", unspec); + check!("0.0.0.1"); + check!("0.1.0.0"); + check!("10.9.8.7", private); + check!("127.1.2.3", loopback); + check!("172.31.254.253", private); + check!("169.254.253.242", link_local); + check!("192.0.2.183", documentation); + check!("192.1.2.183", global); + check!("192.168.254.253", private); + check!("198.51.100.0", documentation); + check!("203.0.113.0", documentation); + check!("203.2.113.0", global); + check!("224.0.0.0", global|multicast); + check!("239.255.255.255", global|multicast); + check!("255.255.255.255", broadcast); + check!("198.18.0.0", benchmarking); + check!("198.18.54.2", benchmarking); + check!("198.19.255.255", benchmarking); + check!("192.0.0.0", ietf_protocol_assignment); + check!("192.0.0.255", ietf_protocol_assignment); + check!("192.0.0.100", ietf_protocol_assignment); + check!("240.0.0.0", reserved); + check!("251.54.1.76", reserved); + check!("254.255.255.255", reserved); + check!("100.64.0.0", shared); + check!("100.127.255.255", shared); + check!("100.100.100.0", shared); } #[test] fn ipv6_properties() { - fn check(str_addr: &str, octets: &[u8; 16], unspec: bool, loopback: bool, - unique_local: bool, global: bool, - u_link_local: bool, u_site_local: bool, u_global: bool, u_doc: bool, - m_scope: Option) { - let ip: Ipv6Addr = str_addr.parse().unwrap(); - assert_eq!(str_addr, ip.to_string()); - assert_eq!(&ip.octets(), octets); - assert_eq!(Ipv6Addr::from(*octets), ip); - - assert_eq!(ip.is_unspecified(), unspec); - assert_eq!(ip.is_loopback(), loopback); - assert_eq!(ip.is_unique_local(), unique_local); - assert_eq!(ip.is_global(), global); - assert_eq!(ip.is_unicast_link_local(), u_link_local); - assert_eq!(ip.is_unicast_site_local(), u_site_local); - assert_eq!(ip.is_unicast_global(), u_global); - assert_eq!(ip.is_documentation(), u_doc); - assert_eq!(ip.multicast_scope(), m_scope); - assert_eq!(ip.is_multicast(), m_scope.is_some()); + macro_rules! ip { + ($s:expr) => { + Ipv6Addr::from_str($s).unwrap() + } + } + + macro_rules! check { + ($s:expr, &[$($octet:expr),*], $mask:expr) => { + assert_eq!($s, ip!($s).to_string()); + let octets = &[$($octet),*]; + assert_eq!(&ip!($s).octets(), octets); + assert_eq!(Ipv6Addr::from(*octets), ip!($s)); + + let unspecified: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let unique_local: u16 = 1 << 2; + let global: u16 = 1 << 3; + let unicast_link_local: u16 = 1 << 4; + let unicast_link_local_strict: u16 = 1 << 5; + let unicast_site_local: u16 = 1 << 6; + let unicast_global: u16 = 1 << 7; + let documentation: u16 = 1 << 8; + let multicast_interface_local: u16 = 1 << 9; + let multicast_link_local: u16 = 1 << 10; + let multicast_realm_local: u16 = 1 << 11; + let multicast_admin_local: u16 = 1 << 12; + let multicast_site_local: u16 = 1 << 13; + let multicast_organization_local: u16 = 1 << 14; + let multicast_global: u16 = 1 << 15; + let multicast: u16 = multicast_interface_local + | multicast_admin_local + | multicast_global + | multicast_link_local + | multicast_realm_local + | multicast_site_local + | multicast_organization_local; + + if ($mask & unspecified) == unspecified { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + if ($mask & unique_local) == unique_local { + assert!(ip!($s).is_unique_local()); + } else { + assert!(!ip!($s).is_unique_local()); + } + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + if ($mask & unicast_link_local) == unicast_link_local { + assert!(ip!($s).is_unicast_link_local()); + } else { + assert!(!ip!($s).is_unicast_link_local()); + } + if ($mask & unicast_link_local_strict) == unicast_link_local_strict { + assert!(ip!($s).is_unicast_link_local_strict()); + } else { + assert!(!ip!($s).is_unicast_link_local_strict()); + } + if ($mask & unicast_site_local) == unicast_site_local { + assert!(ip!($s).is_unicast_site_local()); + } else { + assert!(!ip!($s).is_unicast_site_local()); + } + if ($mask & unicast_global) == unicast_global { + assert!(ip!($s).is_unicast_global()); + } else { + assert!(!ip!($s).is_unicast_global()); + } + if ($mask & documentation) == documentation { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + if ($mask & multicast) != 0 { + assert!(ip!($s).multicast_scope().is_some()); + assert!(ip!($s).is_multicast()); + } else { + assert!(ip!($s).multicast_scope().is_none()); + assert!(!ip!($s).is_multicast()); + } + if ($mask & multicast_interface_local) == multicast_interface_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::InterfaceLocal); + } + if ($mask & multicast_link_local) == multicast_link_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::LinkLocal); + } + if ($mask & multicast_realm_local) == multicast_realm_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::RealmLocal); + } + if ($mask & multicast_admin_local) == multicast_admin_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::AdminLocal); + } + if ($mask & multicast_site_local) == multicast_site_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::SiteLocal); + } + if ($mask & multicast_organization_local) == multicast_organization_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::OrganizationLocal); + } + if ($mask & multicast_global) == multicast_global { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::Global); + } + } } - // unspec loopbk uniqlo global unill unisl uniglo doc mscope - check("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - true, false, false, false, false, false, false, false, None); - check("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], - false, true, false, false, false, false, false, false, None); - check("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], - false, false, false, true, false, false, true, false, None); - check("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, true, false, false, true, false, None); - check("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, true, false, false, false, false, false, None); - check("fdff:ffff::", &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, true, false, false, false, false, false, None); - check("fe80:ffff::", &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, true, false, false, false, None); - check("febf:ffff::", &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, true, false, false, false, None); - check("fec0::", &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, true, false, false, None); - check("ff01::", &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, false, false, false, Some(InterfaceLocal)); - check("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, false, false, false, Some(LinkLocal)); - check("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, false, false, false, Some(RealmLocal)); - check("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, false, false, false, Some(AdminLocal)); - check("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, false, false, false, Some(SiteLocal)); - check("ff08::", &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, false, false, false, Some(OrganizationLocal)); - check("ff0e::", &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, true, false, false, false, false, Some(Global)); - check("2001:db8:85a3::8a2e:370:7334", - &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], - false, false, false, false, false, false, false, true, None); - check("102:304:506:708:90a:b0c:d0e:f10", - &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], - false, false, false, true, false, false, true, false, None); + let unspecified: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let unique_local: u16 = 1 << 2; + let global: u16 = 1 << 3; + let unicast_link_local: u16 = 1 << 4; + let unicast_link_local_strict: u16 = 1 << 5; + let unicast_site_local: u16 = 1 << 6; + let unicast_global: u16 = 1 << 7; + let documentation: u16 = 1 << 8; + let multicast_interface_local: u16 = 1 << 9; + let multicast_link_local: u16 = 1 << 10; + let multicast_realm_local: u16 = 1 << 11; + let multicast_admin_local: u16 = 1 << 12; + let multicast_site_local: u16 = 1 << 13; + let multicast_organization_local: u16 = 1 << 14; + let multicast_global: u16 = 1 << 15; + + check!("::", + &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unspecified); + + check!("::1", + &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + loopback); + + check!("::0.0.0.2", + &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], + global | unicast_global); + + check!("1::", + &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global); + + check!("fc00::", + &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unique_local); + + check!("fdff:ffff::", + &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unique_local); + + check!("fe80:ffff::", + &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local); + + check!("fe80::", + &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local|unicast_link_local_strict); + + check!("febf:ffff::", + &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local); + + check!("febf::", + &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local); + + check!("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + &[0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], + unicast_link_local); + + check!("fe80::ffff:ffff:ffff:ffff", + &[0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], + unicast_link_local|unicast_link_local_strict); + + check!("fe80:0:0:1::", + &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local); + + check!("fec0::", + &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_site_local|unicast_global|global); + + check!("ff01::", + &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_interface_local); + + check!("ff02::", + &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_link_local); + + check!("ff03::", + &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_realm_local); + + check!("ff04::", + &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_admin_local); + + check!("ff05::", + &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_site_local); + + check!("ff08::", + &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_organization_local); + + check!("ff0e::", + &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_global | global); + + check!("2001:db8:85a3::8a2e:370:7334", + &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], + documentation); + + check!("102:304:506:708:90a:b0c:d0e:f10", + &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + global| unicast_global); } #[test] diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index 7951cd6bcf28c..5a76139530a46 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -28,7 +28,7 @@ impl<'a> Parser<'a> { // Commit only if parser returns Some fn read_atomically(&mut self, cb: F) -> Option where - F: FnOnce(&mut Parser) -> Option, + F: FnOnce(&mut Parser<'_>) -> Option, { let pos = self.pos; let r = cb(self); @@ -40,7 +40,7 @@ impl<'a> Parser<'a> { // Commit only if parser read till EOF fn read_till_eof(&mut self, cb: F) -> Option where - F: FnOnce(&mut Parser) -> Option, + F: FnOnce(&mut Parser<'_>) -> Option, { self.read_atomically(move |p| { cb(p).filter(|_| p.is_eof()) @@ -48,10 +48,10 @@ impl<'a> Parser<'a> { } // Return result of first successful parser - fn read_or(&mut self, parsers: &mut [Box Option + 'static>]) + fn read_or(&mut self, parsers: &mut [Box) -> Option + 'static>]) -> Option { for pf in parsers { - if let Some(r) = self.read_atomically(|p: &mut Parser| pf(p)) { + if let Some(r) = self.read_atomically(|p: &mut Parser<'_>| pf(p)) { return Some(r); } } @@ -64,9 +64,9 @@ impl<'a> Parser<'a> { pb: PB, pc: PC) -> Option<(A, B, C)> where - PA: FnOnce(&mut Parser) -> Option, - PB: FnOnce(&mut Parser) -> Option, - PC: FnOnce(&mut Parser) -> Option, + PA: FnOnce(&mut Parser<'_>) -> Option, + PB: FnOnce(&mut Parser<'_>) -> Option, + PC: FnOnce(&mut Parser<'_>) -> Option, { self.read_atomically(move |p| { let a = pa(p); @@ -177,7 +177,7 @@ impl<'a> Parser<'a> { Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7]) } - fn read_groups(p: &mut Parser, groups: &mut [u16; 8], limit: usize) + fn read_groups(p: &mut Parser<'_>, groups: &mut [u16; 8], limit: usize) -> (usize, bool) { let mut i = 0; while i < limit { @@ -244,15 +244,15 @@ impl<'a> Parser<'a> { } fn read_ip_addr(&mut self) -> Option { - let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr().map(IpAddr::V4); - let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr().map(IpAddr::V6); + let ipv4_addr = |p: &mut Parser<'_>| p.read_ipv4_addr().map(IpAddr::V4); + let ipv6_addr = |p: &mut Parser<'_>| p.read_ipv6_addr().map(IpAddr::V6); self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)]) } fn read_socket_addr_v4(&mut self) -> Option { - let ip_addr = |p: &mut Parser| p.read_ipv4_addr(); - let colon = |p: &mut Parser| p.read_given_char(':'); - let port = |p: &mut Parser| { + let ip_addr = |p: &mut Parser<'_>| p.read_ipv4_addr(); + let colon = |p: &mut Parser<'_>| p.read_given_char(':'); + let port = |p: &mut Parser<'_>| { p.read_number(10, 5, 0x10000).map(|n| n as u16) }; @@ -263,14 +263,14 @@ impl<'a> Parser<'a> { } fn read_socket_addr_v6(&mut self) -> Option { - let ip_addr = |p: &mut Parser| { - let open_br = |p: &mut Parser| p.read_given_char('['); - let ip_addr = |p: &mut Parser| p.read_ipv6_addr(); - let clos_br = |p: &mut Parser| p.read_given_char(']'); + let ip_addr = |p: &mut Parser<'_>| { + let open_br = |p: &mut Parser<'_>| p.read_given_char('['); + let ip_addr = |p: &mut Parser<'_>| p.read_ipv6_addr(); + let clos_br = |p: &mut Parser<'_>| p.read_given_char(']'); p.read_seq_3(open_br, ip_addr, clos_br).map(|t| t.1) }; - let colon = |p: &mut Parser| p.read_given_char(':'); - let port = |p: &mut Parser| { + let colon = |p: &mut Parser<'_>| p.read_given_char(':'); + let port = |p: &mut Parser<'_>| { p.read_number(10, 5, 0x10000).map(|n| n as u16) }; @@ -281,8 +281,8 @@ impl<'a> Parser<'a> { } fn read_socket_addr(&mut self) -> Option { - let v4 = |p: &mut Parser| p.read_socket_addr_v4().map(SocketAddr::V4); - let v6 = |p: &mut Parser| p.read_socket_addr_v6().map(SocketAddr::V6); + let v4 = |p: &mut Parser<'_>| p.read_socket_addr_v4().map(SocketAddr::V4); + let v6 = |p: &mut Parser<'_>| p.read_socket_addr_v6().map(SocketAddr::V6); self.read_or(&mut [Box::new(v4), Box::new(v6)]) } } @@ -391,7 +391,7 @@ pub struct AddrParseError(()); #[stable(feature = "addr_parse_error_error", since = "1.4.0")] impl fmt::Display for AddrParseError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.write_str(self.description()) } } diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 275557da96f67..cdffa390223a2 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -1,7 +1,7 @@ use crate::io::prelude::*; use crate::fmt; -use crate::io::{self, Initializer, IoVec, IoVecMut}; +use crate::io::{self, Initializer, IoSlice, IoSliceMut}; use crate::net::{ToSocketAddrs, SocketAddr, Shutdown}; use crate::sys_common::net as net_imp; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -569,7 +569,7 @@ impl TcpStream { impl Read for TcpStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } @@ -582,7 +582,7 @@ impl Read for TcpStream { impl Write for TcpStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.0.write_vectored(bufs) } @@ -592,7 +592,7 @@ impl Write for TcpStream { impl Read for &TcpStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } @@ -605,7 +605,7 @@ impl Read for &TcpStream { impl Write for &TcpStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.0.write_vectored(bufs) } @@ -626,7 +626,7 @@ impl IntoInner for TcpStream { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for TcpStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } @@ -771,7 +771,7 @@ impl TcpListener { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn incoming(&self) -> Incoming { + pub fn incoming(&self) -> Incoming<'_> { Incoming { listener: self } } @@ -922,19 +922,19 @@ impl IntoInner for TcpListener { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for TcpListener { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } #[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] mod tests { - use crate::io::{ErrorKind, IoVec, IoVecMut}; + use crate::fmt; + use crate::io::{ErrorKind, IoSlice, IoSliceMut}; use crate::io::prelude::*; use crate::net::*; use crate::net::test::{next_test_ip4, next_test_ip6}; use crate::sync::mpsc::channel; - use crate::sys_common::AsInner; use crate::time::{Instant, Duration}; use crate::thread; @@ -1129,7 +1129,7 @@ mod tests { connect(i + 1, addr); t!(stream.write(&[i as u8])); }); - t.join().ok().unwrap(); + t.join().ok().expect("thread panicked"); } } @@ -1162,7 +1162,7 @@ mod tests { connect(i + 1, addr); t!(stream.write(&[99])); }); - t.join().ok().unwrap(); + t.join().ok().expect("thread panicked"); } } @@ -1216,7 +1216,7 @@ mod tests { let mut b = [0]; let mut c = [0; 3]; let len = t!(s2.read_vectored( - &mut [IoVecMut::new(&mut a), IoVecMut::new(&mut b), IoVecMut::new(&mut c)], + &mut [IoSliceMut::new(&mut a), IoSliceMut::new(&mut b), IoSliceMut::new(&mut c)], )); assert!(len > 0); assert_eq!(b, [10]); @@ -1235,7 +1235,7 @@ mod tests { let a = []; let b = [10]; let c = [11, 12]; - t!(s1.write_vectored(&[IoVec::new(&a), IoVec::new(&b), IoVec::new(&c)])); + t!(s1.write_vectored(&[IoSlice::new(&a), IoSlice::new(&b), IoSlice::new(&c)])); let mut buf = [0; 4]; let len = t!(s2.read(&mut buf)); @@ -1377,6 +1377,8 @@ mod tests { } #[test] + // FIXME: https://github.com/fortanix/rust-sgx/issues/110 + #[cfg_attr(target_env = "sgx", ignore)] fn shutdown_smoke() { each_ip(&mut |addr| { let a = t!(TcpListener::bind(&addr)); @@ -1397,6 +1399,8 @@ mod tests { } #[test] + // FIXME: https://github.com/fortanix/rust-sgx/issues/110 + #[cfg_attr(target_env = "sgx", ignore)] fn close_readwrite_smoke() { each_ip(&mut |addr| { let a = t!(TcpListener::bind(&addr)); @@ -1550,30 +1554,51 @@ mod tests { #[test] fn debug() { - let name = if cfg!(windows) {"socket"} else {"fd"}; + #[cfg(not(target_env = "sgx"))] + fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { + addr + } + #[cfg(target_env = "sgx")] + fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { + addr.to_string() + } + + #[cfg(unix)] + use crate::os::unix::io::AsRawFd; + #[cfg(target_env = "sgx")] + use crate::os::fortanix_sgx::io::AsRawFd; + #[cfg(not(windows))] + fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug { + addr.as_raw_fd() + } + #[cfg(windows)] + fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Debug { + addr.as_raw_socket() + } + + let inner_name = if cfg!(windows) {"socket"} else {"fd"}; let socket_addr = next_test_ip4(); let listener = t!(TcpListener::bind(&socket_addr)); - let listener_inner = listener.0.socket().as_inner(); let compare = format!("TcpListener {{ addr: {:?}, {}: {:?} }}", - socket_addr, name, listener_inner); + render_socket_addr(&socket_addr), + inner_name, + render_inner(&listener)); assert_eq!(format!("{:?}", listener), compare); - let stream = t!(TcpStream::connect(&("localhost", - socket_addr.port()))); - let stream_inner = stream.0.socket().as_inner(); - let compare = format!("TcpStream {{ addr: {:?}, \ - peer: {:?}, {}: {:?} }}", - stream.local_addr().unwrap(), - stream.peer_addr().unwrap(), - name, - stream_inner); + let stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); + let compare = format!("TcpStream {{ addr: {:?}, peer: {:?}, {}: {:?} }}", + render_socket_addr(&stream.local_addr().unwrap()), + render_socket_addr(&stream.peer_addr().unwrap()), + inner_name, + render_inner(&stream)); assert_eq!(format!("{:?}", stream), compare); } - // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code + // FIXME: re-enabled openbsd tests once their socket timeout code // no longer has rounding errors. - #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] + #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd"), ignore)] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 #[test] fn timeouts() { let addr = next_test_ip4(); @@ -1601,6 +1626,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn test_read_timeout() { let addr = next_test_ip4(); let listener = t!(TcpListener::bind(&addr)); @@ -1618,6 +1644,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn test_read_with_timeout() { let addr = next_test_ip4(); let listener = t!(TcpListener::bind(&addr)); @@ -1661,6 +1688,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] fn nodelay() { let addr = next_test_ip4(); let _listener = t!(TcpListener::bind(&addr)); @@ -1675,6 +1703,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] fn ttl() { let ttl = 100; @@ -1691,6 +1720,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] fn set_nonblocking() { let addr = next_test_ip4(); let listener = t!(TcpListener::bind(&addr)); @@ -1712,6 +1742,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn peek() { each_ip(&mut |addr| { let (txdone, rxdone) = channel(); @@ -1743,21 +1774,7 @@ mod tests { } #[test] - fn connect_timeout_unbound() { - // bind and drop a socket to track down a "probably unassigned" port - let socket = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = socket.local_addr().unwrap(); - drop(socket); - - let timeout = Duration::from_secs(1); - let e = TcpStream::connect_timeout(&addr, timeout).unwrap_err(); - assert!(e.kind() == io::ErrorKind::ConnectionRefused || - e.kind() == io::ErrorKind::TimedOut || - e.kind() == io::ErrorKind::Other, - "bad error: {} {:?}", e, e.kind()); - } - - #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn connect_timeout_valid() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap(); diff --git a/src/libstd/net/test.rs b/src/libstd/net/test.rs index 89fefd9d1d5e0..e2991cbdd8822 100644 --- a/src/libstd/net/test.rs +++ b/src/libstd/net/test.rs @@ -36,12 +36,16 @@ pub fn tsa(a: A) -> Result, String> { // all want to use ports. This function figures out which workspace // it is running in and assigns a port range based on it. fn base_port() -> u16 { - let cwd = env::current_dir().unwrap(); + let cwd = if cfg!(target_env = "sgx") { + String::from("sgx") + } else { + env::current_dir().unwrap().into_os_string().into_string().unwrap() + }; let dirs = ["32-opt", "32-nopt", "musl-64-opt", "cross-opt", "64-opt", "64-nopt", "64-opt-vg", "64-debug-opt", - "all-opt", "snap3", "dist"]; + "all-opt", "snap3", "dist", "sgx"]; dirs.iter().enumerate().find(|&(_, dir)| { - cwd.to_str().unwrap().contains(dir) + cwd.contains(dir) }).map(|p| p.0).unwrap_or(0) as u16 * 1000 + 19600 } diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index edc9d665444a0..61d9149952ee5 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -180,6 +180,37 @@ impl UdpSocket { } } + /// Returns the socket address of the remote peer this socket was connected to. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(udp_peer_addr)] + /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.connect("192.168.0.1:41203").expect("couldn't connect to address"); + /// assert_eq!(socket.peer_addr().unwrap(), + /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 41203))); + /// ``` + /// + /// If the socket isn't connected, it will return a [`NotConnected`] error. + /// + /// [`NotConnected`]: ../../std/io/enum.ErrorKind.html#variant.NotConnected + /// + /// ```no_run + /// #![feature(udp_peer_addr)] + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// assert_eq!(socket.peer_addr().unwrap_err().kind(), + /// ::std::io::ErrorKind::NotConnected); + /// ``` + #[unstable(feature = "udp_peer_addr", issue = "59127")] + pub fn peer_addr(&self) -> io::Result { + self.0.peer_addr() + } + /// Returns the socket address that this socket was created from. /// /// # Examples @@ -801,12 +832,12 @@ impl IntoInner for UdpSocket { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for UdpSocket { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] mod tests { use crate::io::ErrorKind; use crate::net::*; @@ -865,13 +896,23 @@ mod tests { } #[test] - fn socket_name_ip4() { + fn socket_name() { each_ip(&mut |addr, _| { let server = t!(UdpSocket::bind(&addr)); assert_eq!(addr, t!(server.local_addr())); }) } + #[test] + fn socket_peer() { + each_ip(&mut |addr1, addr2| { + let server = t!(UdpSocket::bind(&addr1)); + assert_eq!(server.peer_addr().unwrap_err().kind(), ErrorKind::NotConnected); + t!(server.connect(&addr2)); + assert_eq!(addr2, t!(server.peer_addr())); + }) + } + #[test] fn udp_clone_smoke() { each_ip(&mut |addr1, addr2| { @@ -983,9 +1024,9 @@ mod tests { assert_eq!(format!("{:?}", udpsock), compare); } - // FIXME: re-enabled bitrig/openbsd/netbsd tests once their socket timeout code + // FIXME: re-enabled openbsd/netbsd tests once their socket timeout code // no longer has rounding errors. - #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] + #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd"), ignore)] #[test] fn timeouts() { let addr = next_test_ip4(); diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 828d5720eec1e..2a2ca0b5237ee 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -13,6 +13,14 @@ pub use core::num::Wrapping; #[stable(feature = "nonzero", since = "1.28.0")] pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; +#[stable(feature = "signed_nonzero", since = "1.34.0")] +pub use core::num::{NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize}; + +#[unstable(feature = "int_error_matching", + reason = "it can be useful to match errors when making error messages \ + for integer parsing", + issue = "22639")] +pub use core::num::IntErrorKind; #[cfg(test)] use crate::fmt; #[cfg(test)] use crate::ops::{Add, Sub, Mul, Div, Rem}; diff --git a/src/libstd/os/android/fs.rs b/src/libstd/os/android/fs.rs index 9b24f86204bb6..90fdee567ae2c 100644 --- a/src/libstd/os/android/fs.rs +++ b/src/libstd/os/android/fs.rs @@ -116,4 +116,3 @@ impl MetadataExt for Metadata { self.as_inner().as_inner().st_blocks as u64 } } - diff --git a/src/libstd/os/android/raw.rs b/src/libstd/os/android/raw.rs index acf5ca1e4297b..946a77cbfd325 100644 --- a/src/libstd/os/android/raw.rs +++ b/src/libstd/os/android/raw.rs @@ -217,4 +217,3 @@ mod arch { __unused: [c_long; 3], } } - diff --git a/src/libstd/os/bitrig/fs.rs b/src/libstd/os/bitrig/fs.rs deleted file mode 100644 index 849d4aa67f204..0000000000000 --- a/src/libstd/os/bitrig/fs.rs +++ /dev/null @@ -1,139 +0,0 @@ -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use crate::fs::Metadata; -use crate::sys_common::AsInner; - -#[allow(deprecated)] -use crate::os::bitrig::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } -} - diff --git a/src/libstd/os/bitrig/mod.rs b/src/libstd/os/bitrig/mod.rs deleted file mode 100644 index 0bc105bb2b40a..0000000000000 --- a/src/libstd/os/bitrig/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Bitrig-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/src/libstd/os/bitrig/raw.rs b/src/libstd/os/bitrig/raw.rs deleted file mode 100644 index c966d5a8e5b49..0000000000000 --- a/src/libstd/os/bitrig/raw.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! Bitrig-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -use crate::os::raw::c_long; -use crate::os::unix::raw::{uid_t, gid_t}; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: i64, -} diff --git a/src/libstd/os/dragonfly/fs.rs b/src/libstd/os/dragonfly/fs.rs index ba38660224f24..ba3d8d7867def 100644 --- a/src/libstd/os/dragonfly/fs.rs +++ b/src/libstd/os/dragonfly/fs.rs @@ -131,4 +131,3 @@ impl MetadataExt for Metadata { self.as_inner().as_inner().st_lspare as u32 } } - diff --git a/src/libstd/os/fortanix_sgx/mod.rs b/src/libstd/os/fortanix_sgx/mod.rs index bca22e717d724..4e30b1edd15e8 100644 --- a/src/libstd/os/fortanix_sgx/mod.rs +++ b/src/libstd/os/fortanix_sgx/mod.rs @@ -43,3 +43,8 @@ pub mod mem { } pub use crate::sys::ext::{io, arch, ffi}; + +/// Functions for querying thread-related information. +pub mod thread { + pub use crate::sys::abi::thread::current; +} diff --git a/src/libstd/os/freebsd/fs.rs b/src/libstd/os/freebsd/fs.rs index 4cc3a4b91fbd8..cfe8d575c673e 100644 --- a/src/libstd/os/freebsd/fs.rs +++ b/src/libstd/os/freebsd/fs.rs @@ -141,4 +141,3 @@ impl MetadataExt for Metadata { self.as_inner().as_inner().st_lspare as u32 } } - diff --git a/src/libstd/os/ios/fs.rs b/src/libstd/os/ios/fs.rs index 7b625f5e3fe36..9bdfa8e690b09 100644 --- a/src/libstd/os/ios/fs.rs +++ b/src/libstd/os/ios/fs.rs @@ -141,4 +141,3 @@ impl MetadataExt for Metadata { self.as_inner().as_inner().st_lspare as u32 } } - diff --git a/src/libstd/os/macos/fs.rs b/src/libstd/os/macos/fs.rs index 1bd66ad4c764c..bf951ee18c9f9 100644 --- a/src/libstd/os/macos/fs.rs +++ b/src/libstd/os/macos/fs.rs @@ -147,4 +147,3 @@ impl MetadataExt for Metadata { [qspare[0] as u64, qspare[1] as u64] } } - diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs index 5cce3df71d6a9..94e8b7805cf93 100644 --- a/src/libstd/os/mod.rs +++ b/src/libstd/os/mod.rs @@ -3,7 +3,7 @@ #![stable(feature = "os", since = "1.0.0")] #![allow(missing_docs, nonstandard_style, missing_debug_implementations)] -cfg_if! { +cfg_if::cfg_if! { if #[cfg(rustdoc)] { // When documenting libstd we want to show unix/windows/linux modules as @@ -39,7 +39,6 @@ cfg_if! { } #[cfg(target_os = "android")] pub mod android; -#[cfg(target_os = "bitrig")] pub mod bitrig; #[cfg(target_os = "dragonfly")] pub mod dragonfly; #[cfg(target_os = "freebsd")] pub mod freebsd; #[cfg(target_os = "haiku")] pub mod haiku; @@ -51,6 +50,7 @@ cfg_if! { #[cfg(target_os = "emscripten")] pub mod emscripten; #[cfg(target_os = "fuchsia")] pub mod fuchsia; #[cfg(target_os = "hermit")] pub mod hermit; +#[cfg(target_os = "wasi")] pub mod wasi; #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] pub mod fortanix_sgx; pub mod raw; diff --git a/src/libstd/os/netbsd/fs.rs b/src/libstd/os/netbsd/fs.rs index 6dffb70b5dc7b..dedfc6390ce20 100644 --- a/src/libstd/os/netbsd/fs.rs +++ b/src/libstd/os/netbsd/fs.rs @@ -136,4 +136,3 @@ impl MetadataExt for Metadata { self.as_inner().as_inner().st_flags as u32 } } - diff --git a/src/libstd/os/openbsd/fs.rs b/src/libstd/os/openbsd/fs.rs index 73f9757f3b794..1c019159be026 100644 --- a/src/libstd/os/openbsd/fs.rs +++ b/src/libstd/os/openbsd/fs.rs @@ -136,4 +136,3 @@ impl MetadataExt for Metadata { self.as_inner().as_inner().st_flags as u32 } } - diff --git a/src/libstd/os/wasi.rs b/src/libstd/os/wasi.rs new file mode 100644 index 0000000000000..d25b8d39ed680 --- /dev/null +++ b/src/libstd/os/wasi.rs @@ -0,0 +1,6 @@ +//! WASI-specific definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::sys::ext::*; diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 6a16414c1417e..1d4fd98dd754f 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -4,6 +4,7 @@ use crate::any::Any; use crate::cell::UnsafeCell; +use crate::collections; use crate::fmt; use crate::future::Future; use crate::pin::Pin; @@ -12,7 +13,7 @@ use crate::panicking; use crate::ptr::{Unique, NonNull}; use crate::rc::Rc; use crate::sync::{Arc, Mutex, RwLock, atomic}; -use crate::task::{Waker, Poll}; +use crate::task::{Context, Poll}; use crate::thread::Result; #[stable(feature = "panic_hooks", since = "1.10.0")] @@ -285,6 +286,11 @@ impl RefUnwindSafe for atomic::AtomicBool {} #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] impl RefUnwindSafe for atomic::AtomicPtr {} +// https://github.com/rust-lang/rust/issues/62301 +#[stable(feature = "hashbrown", since = "1.36.0")] +impl UnwindSafe for collections::HashMap + where K: UnwindSafe, V: UnwindSafe, S: UnwindSafe {} + #[stable(feature = "catch_unwind", since = "1.9.0")] impl Deref for AssertUnwindSafe { type Target = T; @@ -312,20 +318,20 @@ impl R> FnOnce<()> for AssertUnwindSafe { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for AssertUnwindSafe { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("AssertUnwindSafe") .field(&self.0) .finish() } } -#[unstable(feature = "futures_api", issue = "50547")] +#[stable(feature = "futures_api", since = "1.36.0")] impl Future for AssertUnwindSafe { type Output = F::Output; - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) }; - F::poll(pinned_field, waker) + F::poll(pinned_field, cx) } } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 868b309686cf6..797d85e941d96 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -7,13 +7,9 @@ //! * Executing a panic up to doing the actual implementation //! * Shims around "try" -use core::panic::BoxMeUp; -use core::panic::{PanicInfo, Location}; - -use crate::io::prelude::*; +use core::panic::{BoxMeUp, PanicInfo, Location}; use crate::any::Any; -use crate::cell::RefCell; use crate::fmt; use crate::intrinsics; use crate::mem; @@ -25,11 +21,12 @@ use crate::sys_common::thread_info; use crate::sys_common::util; use crate::thread; -thread_local! { - pub static LOCAL_STDERR: RefCell>> = { - RefCell::new(None) - } -} +#[cfg(not(test))] +use crate::io::set_panic; +// make sure to use the stderr output configured +// by libtest in the real copy of std +#[cfg(test)] +use realstd::io::set_panic; // Binary interface to the panic runtime that the standard library depends on. // @@ -54,7 +51,7 @@ extern { #[derive(Copy, Clone)] enum Hook { Default, - Custom(*mut (dyn Fn(&PanicInfo) + 'static + Sync + Send)), + Custom(*mut (dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send)), } static HOOK_LOCK: RWLock = RWLock::new(); @@ -94,7 +91,7 @@ static mut HOOK: Hook = Hook::Default; /// panic!("Normal panic"); /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] -pub fn set_hook(hook: Box) { +pub fn set_hook(hook: Box) + 'static + Sync + Send>) { if thread::panicking() { panic!("cannot modify the panic hook from a panicking thread"); } @@ -106,7 +103,9 @@ pub fn set_hook(hook: Box) { HOOK_LOCK.write_unlock(); if let Hook::Custom(ptr) = old_hook { - Box::from_raw(ptr); + #[allow(unused_must_use)] { + Box::from_raw(ptr); + } } } } @@ -139,7 +138,7 @@ pub fn set_hook(hook: Box) { /// panic!("Normal panic"); /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] -pub fn take_hook() -> Box { +pub fn take_hook() -> Box) + 'static + Sync + Send> { if thread::panicking() { panic!("cannot modify the panic hook from a panicking thread"); } @@ -157,7 +156,7 @@ pub fn take_hook() -> Box { } } -fn default_hook(info: &PanicInfo) { +fn default_hook(info: &PanicInfo<'_>) { #[cfg(feature = "backtrace")] use crate::sys_common::backtrace; @@ -174,7 +173,8 @@ fn default_hook(info: &PanicInfo) { } }; - let location = info.location().unwrap(); // The current implementation always returns Some + // The current implementation always returns `Some`. + let location = info.location().unwrap(); let msg = match info.payload().downcast_ref::<&'static str>() { Some(s) => *s, @@ -199,18 +199,17 @@ fn default_hook(info: &PanicInfo) { if let Some(format) = log_backtrace { let _ = backtrace::print(err, format); } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) { - let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` \ + let _ = writeln!(err, "note: run with `RUST_BACKTRACE=1` \ environment variable to display a backtrace."); } } }; - if let Some(mut local) = LOCAL_STDERR.with(|s| s.borrow_mut().take()) { - write(&mut *local); - let mut s = Some(local); - LOCAL_STDERR.with(|slot| { - *slot.borrow_mut() = s.take(); - }); + if let Some(mut local) = set_panic(None) { + // NB. In `cfg(test)` this uses the forwarding impl + // for `Box`. + write(&mut local); + set_panic(Some(local)); } else if let Some(mut out) = panic_output() { write(&mut out); } @@ -308,7 +307,7 @@ pub fn panicking() -> bool { #[cfg(not(test))] #[panic_handler] #[unwind(allowed)] -pub fn rust_begin_panic(info: &PanicInfo) -> ! { +pub fn rust_begin_panic(info: &PanicInfo<'_>) -> ! { continue_panic_fmt(&info) } @@ -326,7 +325,7 @@ pub fn rust_begin_panic(info: &PanicInfo) -> ! { // otherwise avoid inlining because of it is cold path. #[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] #[cfg_attr( feature="panic_immediate_abort" ,inline)] -pub fn begin_panic_fmt(msg: &fmt::Arguments, +pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>, file_line_col: &(&'static str, u32, u32)) -> ! { if cfg!(feature = "panic_immediate_abort") { unsafe { intrinsics::abort() } @@ -340,7 +339,7 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, continue_panic_fmt(&info) } -fn continue_panic_fmt(info: &PanicInfo) -> ! { +fn continue_panic_fmt(info: &PanicInfo<'_>) -> ! { struct PanicPayload<'a> { inner: &'a fmt::Arguments<'a>, string: Option, @@ -445,7 +444,7 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 /// panics, panic hooks, and finally dispatching to the panic runtime to either /// abort or unwind. fn rust_panic_with_hook(payload: &mut dyn BoxMeUp, - message: Option<&fmt::Arguments>, + message: Option<&fmt::Arguments<'_>>, file_line_col: &(&str, u32, u32)) -> ! { let (file, line, col) = *file_line_col; diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 858a5778b8161..126bc3754dabc 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + //! Cross-platform path manipulation. //! //! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`] @@ -323,7 +325,7 @@ fn has_redox_scheme(s: &[u8]) -> bool { //////////////////////////////////////////////////////////////////////////////// /// Says whether the first byte after the prefix is a separator. -fn has_physical_root(s: &[u8], prefix: Option) -> bool { +fn has_physical_root(s: &[u8], prefix: Option>) -> bool { let path = if let Some(p) = prefix { &s[p.len()..] } else { @@ -630,11 +632,11 @@ pub struct Iter<'a> { #[stable(feature = "path_components_debug", since = "1.13.0")] impl fmt::Debug for Components<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { struct DebugHelper<'a>(&'a Path); impl fmt::Debug for DebugHelper<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list() .entries(self.0.components()) .finish() @@ -828,11 +830,11 @@ impl AsRef for Components<'_> { #[stable(feature = "path_iter_debug", since = "1.13.0")] impl fmt::Debug for Iter<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { struct DebugHelper<'a>(&'a Path); impl fmt::Debug for DebugHelper<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list() .entries(self.0.iter()) .finish() @@ -1456,8 +1458,8 @@ impl PathBuf { } #[stable(feature = "box_from_path", since = "1.17.0")] -impl<'a> From<&'a Path> for Box { - fn from(path: &'a Path) -> Box { +impl From<&Path> for Box { + fn from(path: &Path) -> Box { let boxed: Box = path.inner.into(); let rw = Box::into_raw(boxed) as *mut Path; unsafe { Box::from_raw(rw) } @@ -1494,8 +1496,8 @@ impl Clone for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized + AsRef> From<&'a T> for PathBuf { - fn from(s: &'a T) -> PathBuf { +impl> From<&T> for PathBuf { + fn from(s: &T) -> PathBuf { PathBuf::from(s.as_ref().to_os_string()) } } @@ -1551,15 +1553,13 @@ impl> iter::FromIterator

    for PathBuf { #[stable(feature = "rust1", since = "1.0.0")] impl> iter::Extend

    for PathBuf { fn extend>(&mut self, iter: I) { - for p in iter { - self.push(p.as_ref()) - } + iter.into_iter().for_each(move |p| self.push(p.as_ref())); } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for PathBuf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, formatter) } } @@ -1630,7 +1630,7 @@ impl From for Arc { } #[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl<'a> From<&'a Path> for Arc { +impl From<&Path> for Arc { /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. #[inline] fn from(s: &Path) -> Arc { @@ -1650,7 +1650,7 @@ impl From for Rc { } #[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl<'a> From<&'a Path> for Rc { +impl From<&Path> for Rc { /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. #[inline] fn from(s: &Path) -> Rc { @@ -1857,7 +1857,7 @@ impl Path { /// Had `path` contained invalid unicode, the `to_string_lossy` call might /// have returned `"fo�.txt"`. #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_string_lossy(&self) -> Cow { + pub fn to_string_lossy(&self) -> Cow<'_, str> { self.inner.to_string_lossy() } @@ -1926,7 +1926,7 @@ impl Path { !self.is_absolute() } - fn prefix(&self) -> Option { + fn prefix(&self) -> Option> { self.components().prefix } @@ -2007,7 +2007,7 @@ impl Path { /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`parent`]: struct.Path.html#method.parent #[stable(feature = "path_ancestors", since = "1.28.0")] - pub fn ancestors(&self) -> Ancestors { + pub fn ancestors(&self) -> Ancestors<'_> { Ancestors { next: Some(&self), } @@ -2305,7 +2305,7 @@ impl Path { /// [`Component`]: enum.Component.html /// [`CurDir`]: enum.Component.html#variant.CurDir #[stable(feature = "rust1", since = "1.0.0")] - pub fn components(&self) -> Components { + pub fn components(&self) -> Components<'_> { let prefix = parse_prefix(self.as_os_str()); Components { path: self.as_u8_slice(), @@ -2339,7 +2339,7 @@ impl Path { /// assert_eq!(it.next(), None) /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_> { Iter { inner: self.components() } } @@ -2358,7 +2358,7 @@ impl Path { /// println!("{}", path.display()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn display(&self) -> Display { + pub fn display(&self) -> Display<'_> { Display { path: self } } @@ -2578,7 +2578,7 @@ impl AsRef for Path { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Path { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.inner, formatter) } } @@ -2610,14 +2610,14 @@ pub struct Display<'a> { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Display<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.path, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Display<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.path.inner.display(f) } } @@ -2805,7 +2805,7 @@ impl_cmp_os_str!(Cow<'a, Path>, OsString); #[stable(since = "1.7.0", feature = "strip_prefix")] impl fmt::Display for StripPrefixError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.description().fmt(f) } } @@ -2915,7 +2915,7 @@ mod tests { { let path: &Path = &pathbuf; - let borrowed_cow_path: Cow = path.into(); + let borrowed_cow_path: Cow<'_, Path> = path.into(); assert_eq!(static_cow_path, borrowed_cow_path); } @@ -3801,7 +3801,7 @@ mod tests { }); ); - if cfg!(unix) { + if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { tp!("", "foo", "foo"); tp!("foo", "bar", "foo/bar"); tp!("foo/", "bar", "foo/bar"); @@ -3960,7 +3960,7 @@ mod tests { tfn!("foo", "bar", "bar"); tfn!("foo", "", ""); tfn!("", "foo", "foo"); - if cfg!(unix) { + if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { tfn!(".", "foo", "./foo"); tfn!("foo/", "bar", "bar"); tfn!("foo/.", "bar", "bar"); @@ -4013,8 +4013,8 @@ mod tests { let mut owned: PathBuf = PathBuf::new(); owned.push("foo"); owned.push("bar"); - let borrowed_cow: Cow = borrowed.into(); - let owned_cow: Cow = owned.clone().into(); + let borrowed_cow: Cow<'_, Path> = borrowed.into(); + let owned_cow: Cow<'_, Path> = owned.clone().into(); macro_rules! t { ($($current:expr),+) => { diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 6bb7f28efebcf..65fd8c83e1ce5 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -120,7 +120,7 @@ mod prim_bool { } /// When implementing this trait for [`String`] we need to pick a type for [`Err`]. And since /// converting a string into a string will never result in an error, the appropriate type is `!`. /// (Currently the type actually used is an enum with no variants, though this is only because `!` -/// was added to Rust at a later date and it may change in the future). With an [`Err`] type of +/// was added to Rust at a later date and it may change in the future.) With an [`Err`] type of /// `!`, if we have to call [`String::from_str`] for some reason the result will be a /// [`Result`] which we can unpack like this: /// @@ -204,10 +204,10 @@ mod prim_bool { } /// #![feature(never_type)] /// # use std::fmt; /// # trait Debug { -/// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result; +/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; /// # } /// impl Debug for ! { -/// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { /// *self /// } /// } @@ -279,7 +279,7 @@ mod prim_never { } /// /// As always, remember that a human intuition for 'character' may not map to /// Unicode's definitions. For example, despite looking similar, the 'é' -/// character is one Unicode code point while 'é' is two Unicode code points: +/// character is one Unicode code point while 'é' is two Unicode code points: /// /// ``` /// let mut chars = "é".chars(); @@ -482,8 +482,8 @@ mod prim_pointer { } /// an array. Indeed, this provides most of the API for working with arrays. /// Slices have a dynamic size and do not coerce to arrays. /// -/// There is no way to move elements out of an array. See [`mem::replace`][replace] -/// for an alternative. +/// You can move elements out of an array with a slice pattern. If you want +/// one element, see [`mem::replace`][replace]. /// /// # Examples /// @@ -525,6 +525,16 @@ mod prim_pointer { } /// for x in &array { } /// ``` /// +/// You can use a slice pattern to move elements out of an array: +/// +/// ``` +/// fn move_away(_: String) { /* Do interesting things. */ } +/// +/// let [john, roa] = ["John".to_string(), "Roa".to_string()]; +/// move_away(john); +/// move_away(roa); +/// ``` +/// /// [slice]: primitive.slice.html /// [copy]: marker/trait.Copy.html /// [clone]: clone/trait.Clone.html @@ -683,6 +693,10 @@ mod prim_str { } /// assert_eq!(tuple.2, 'c'); /// ``` /// +/// The sequential nature of the tuple applies to its implementations of various +/// traits. For example, in `PartialOrd` and `Ord`, the elements are compared +/// sequentially until the first non-equal set is found. +/// /// For more about tuples, see [the book](../book/ch03-02-data-types.html#the-tuple-type). /// /// # Trait implementations diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 568400093440c..a568f46663730 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -8,7 +8,7 @@ //! //! The [`Command`] struct is used to configure and spawn processes: //! -//! ``` +//! ```no_run //! use std::process::Command; //! //! let output = Command::new("echo") @@ -111,7 +111,7 @@ use crate::io::prelude::*; use crate::ffi::OsStr; use crate::fmt; use crate::fs; -use crate::io::{self, Initializer}; +use crate::io::{self, Initializer, IoSlice, IoSliceMut}; use crate::path::Path; use crate::str; use crate::sys::pipe::{read2, AnonPipe}; @@ -134,6 +134,18 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// the parent process wait until the child has actually exited before /// continuing. /// +/// # Warning +/// +/// On some system, calling [`wait`] or similar is necessary for the OS to +/// release resources. A process that terminated but has not been waited on is +/// still around as a "zombie". Leaving too many zombies around may exhaust +/// global resources (for example process IDs). +/// +/// The standard library does *not* automatically wait on child processes (not +/// even if the `Child` is dropped), it is up to the application developer to do +/// so. As a consequence, dropping `Child` handles without waiting on them first +/// is not recommended in long-running applications. +/// /// # Examples /// /// ```should_panic @@ -194,7 +206,7 @@ impl IntoInner for Child { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Child { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Child") .field("stdin", &self.stdin) .field("stdout", &self.stdout) @@ -225,6 +237,10 @@ impl Write for ChildStdin { self.inner.write(buf) } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.inner.write_vectored(bufs) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } @@ -246,7 +262,7 @@ impl FromInner for ChildStdin { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for ChildStdin { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("ChildStdin { .. }") } } @@ -271,6 +287,11 @@ impl Read for ChildStdout { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.inner.read_vectored(bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -293,7 +314,7 @@ impl FromInner for ChildStdout { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for ChildStdout { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("ChildStdout { .. }") } } @@ -318,6 +339,11 @@ impl Read for ChildStderr { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.inner.read_vectored(bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -340,7 +366,7 @@ impl FromInner for ChildStderr { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for ChildStderr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("ChildStderr { .. }") } } @@ -803,7 +829,7 @@ impl fmt::Debug for Command { /// Format the program and arguments of a Command for display. Any /// non-utf8 data is lossily converted using the utf8 replacement /// character. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } @@ -844,7 +870,7 @@ pub struct Output { // strings, otherwise it prints the byte sequence instead #[stable(feature = "process_output_debug", since = "1.7.0")] impl fmt::Debug for Output { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let stdout_utf8 = str::from_utf8(&self.stdout); let stdout_debug: &dyn fmt::Debug = match stdout_utf8 { @@ -1002,7 +1028,7 @@ impl FromInner for Stdio { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Stdio { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Stdio { .. }") } } @@ -1127,10 +1153,13 @@ impl From for Stdio { /// /// This `struct` is used to represent the exit status of a child process. /// Child processes are created via the [`Command`] struct and their exit -/// status is exposed through the [`status`] method. +/// status is exposed through the [`status`] method, or the [`wait`] method +/// of a [`Child`] process. /// /// [`Command`]: struct.Command.html +/// [`Child`]: struct.Child.html /// [`status`]: struct.Command.html#method.status +/// [`wait`]: struct.Child.html#method.wait #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "process", since = "1.0.0")] pub struct ExitStatus(imp::ExitStatus); @@ -1199,7 +1228,7 @@ impl FromInner for ExitStatus { #[stable(feature = "process", since = "1.0.0")] impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } @@ -1621,7 +1650,7 @@ impl Termination for ExitCode { } } -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] mod tests { use crate::io::prelude::*; diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index a4205daba8b6e..23ba63a61098d 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -59,7 +59,7 @@ pub struct BarrierWaitResult(bool); #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Barrier { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Barrier { .. }") } } @@ -151,7 +151,7 @@ impl Barrier { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for BarrierWaitResult { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("BarrierWaitResult") .field("is_leader", &self.is_leader()) .finish() diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 5ebb61754e1ff..ffb9ce1c81a53 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -190,7 +190,7 @@ impl Condvar { /// // Wait for the thread to start up. /// let &(ref lock, ref cvar) = &*pair; /// let mut started = lock.lock().unwrap(); - /// // As long as the value inside the `Mutex` is false, we wait. + /// // As long as the value inside the `Mutex` is `false`, we wait. /// while !*started { /// started = cvar.wait(started).unwrap(); /// } @@ -254,7 +254,7 @@ impl Condvar { /// /// // Wait for the thread to start up. /// let &(ref lock, ref cvar) = &*pair; - /// // As long as the value inside the `Mutex` is false, we wait. + /// // As long as the value inside the `Mutex` is `false`, we wait. /// let _guard = cvar.wait_until(lock.lock().unwrap(), |started| { *started }).unwrap(); /// ``` #[unstable(feature = "wait_until", issue = "47960")] @@ -311,7 +311,7 @@ impl Condvar { /// // Wait for the thread to start up. /// let &(ref lock, ref cvar) = &*pair; /// let mut started = lock.lock().unwrap(); - /// // As long as the value inside the `Mutex` is false, we wait. + /// // As long as the value inside the `Mutex` is `false`, we wait. /// loop { /// let result = cvar.wait_timeout_ms(started, 10).unwrap(); /// // 10 milliseconds have passed, or maybe the value changed! @@ -384,7 +384,7 @@ impl Condvar { /// // wait for the thread to start up /// let &(ref lock, ref cvar) = &*pair; /// let mut started = lock.lock().unwrap(); - /// // as long as the value inside the `Mutex` is false, we wait + /// // as long as the value inside the `Mutex` is `false`, we wait /// loop { /// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap(); /// // 10 milliseconds have passed, or maybe the value changed! @@ -518,7 +518,7 @@ impl Condvar { /// // Wait for the thread to start up. /// let &(ref lock, ref cvar) = &*pair; /// let mut started = lock.lock().unwrap(); - /// // As long as the value inside the `Mutex` is false, we wait. + /// // As long as the value inside the `Mutex` is `false`, we wait. /// while !*started { /// started = cvar.wait(started).unwrap(); /// } @@ -558,7 +558,7 @@ impl Condvar { /// // Wait for the thread to start up. /// let &(ref lock, ref cvar) = &*pair; /// let mut started = lock.lock().unwrap(); - /// // As long as the value inside the `Mutex` is false, we wait. + /// // As long as the value inside the `Mutex` is `false`, we wait. /// while !*started { /// started = cvar.wait(started).unwrap(); /// } @@ -589,7 +589,7 @@ impl Condvar { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Condvar { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Condvar { .. }") } } @@ -705,6 +705,7 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn wait_timeout_wait() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); @@ -724,6 +725,7 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn wait_timeout_until_wait() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); @@ -748,6 +750,7 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn wait_timeout_until_wake() { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair_copy = pair.clone(); @@ -771,6 +774,7 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn wait_timeout_wake() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 809ee8826981b..fd6e46fd61dc5 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -163,6 +163,7 @@ pub use self::condvar::{Condvar, WaitTimeoutResult}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::mutex::{Mutex, MutexGuard}; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] pub use self::once::{Once, OnceState, ONCE_INIT}; #[stable(feature = "rust1", since = "1.0.0")] pub use crate::sys_common::poison::{PoisonError, TryLockError, TryLockResult, LockResult}; diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 90c5c50c23b9c..69ecd201063b0 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + //! Multi-producer, single-consumer FIFO queue communication primitives. //! //! This module provides message-based communication over channels, concretely @@ -114,7 +116,6 @@ //! ``` #![stable(feature = "rust1", since = "1.0.0")] -#![allow(deprecated)] // for mpsc_select // A description of how Rust's channel implementation works // @@ -261,6 +262,8 @@ // believe that there is anything fundamental that needs to change about these // channels, however, in order to support a more efficient select(). // +// FIXME: Select is now removed, so these factors are ready to be cleaned up! +// // # Conclusion // // And now that you've seen all the races that I found and attempted to fix, @@ -273,18 +276,8 @@ use crate::mem; use crate::cell::UnsafeCell; use crate::time::{Duration, Instant}; -#[unstable(feature = "mpsc_select", issue = "27800")] -pub use self::select::{Select, Handle}; -use self::select::StartResult; -use self::select::StartResult::*; -use self::blocking::SignalToken; - -#[cfg(all(test, not(target_os = "emscripten")))] -mod select_tests; - mod blocking; mod oneshot; -mod select; mod shared; mod stream; mod sync; @@ -914,7 +907,7 @@ impl Drop for Sender { #[stable(feature = "mpsc_debug", since = "1.8.0")] impl fmt::Debug for Sender { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Sender").finish() } } @@ -1005,7 +998,7 @@ impl SyncSender { /// thread::spawn(move || { /// // This will return an error and send /// // no message if the buffer is full - /// sync_sender2.try_send(3).is_err(); + /// let _ = sync_sender2.try_send(3); /// }); /// /// let mut msg; @@ -1044,7 +1037,7 @@ impl Drop for SyncSender { #[stable(feature = "mpsc_debug", since = "1.8.0")] impl fmt::Debug for SyncSender { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SyncSender").finish() } } @@ -1463,7 +1456,7 @@ impl Receiver { /// assert_eq!(iter.next(), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, T> { Iter { rx: self } } @@ -1506,84 +1499,12 @@ impl Receiver { /// assert_eq!(iter.next(), None); /// ``` #[stable(feature = "receiver_try_iter", since = "1.15.0")] - pub fn try_iter(&self) -> TryIter { + pub fn try_iter(&self) -> TryIter<'_, T> { TryIter { rx: self } } } -impl select::Packet for Receiver { - fn can_recv(&self) -> bool { - loop { - let new_port = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => { - match p.can_recv() { - Ok(ret) => return ret, - Err(upgrade) => upgrade, - } - } - Flavor::Stream(ref p) => { - match p.can_recv() { - Ok(ret) => return ret, - Err(upgrade) => upgrade, - } - } - Flavor::Shared(ref p) => return p.can_recv(), - Flavor::Sync(ref p) => return p.can_recv(), - }; - unsafe { - mem::swap(self.inner_mut(), - new_port.inner_mut()); - } - } - } - - fn start_selection(&self, mut token: SignalToken) -> StartResult { - loop { - let (t, new_port) = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => { - match p.start_selection(token) { - oneshot::SelSuccess => return Installed, - oneshot::SelCanceled => return Abort, - oneshot::SelUpgraded(t, rx) => (t, rx), - } - } - Flavor::Stream(ref p) => { - match p.start_selection(token) { - stream::SelSuccess => return Installed, - stream::SelCanceled => return Abort, - stream::SelUpgraded(t, rx) => (t, rx), - } - } - Flavor::Shared(ref p) => return p.start_selection(token), - Flavor::Sync(ref p) => return p.start_selection(token), - }; - token = t; - unsafe { - mem::swap(self.inner_mut(), new_port.inner_mut()); - } - } - } - - fn abort_selection(&self) -> bool { - let mut was_upgrade = false; - loop { - let result = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => p.abort_selection(), - Flavor::Stream(ref p) => p.abort_selection(was_upgrade), - Flavor::Shared(ref p) => return p.abort_selection(was_upgrade), - Flavor::Sync(ref p) => return p.abort_selection(), - }; - let new_port = match result { Ok(b) => return b, Err(p) => p }; - was_upgrade = true; - unsafe { - mem::swap(self.inner_mut(), - new_port.inner_mut()); - } - } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Iterator for Iter<'a, T> { type Item = T; @@ -1636,21 +1557,21 @@ impl Drop for Receiver { #[stable(feature = "mpsc_debug", since = "1.8.0")] impl fmt::Debug for Receiver { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Receiver").finish() } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for SendError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "SendError(..)".fmt(f) } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for SendError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "sending on a closed channel".fmt(f) } } @@ -1668,7 +1589,7 @@ impl error::Error for SendError { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for TrySendError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { TrySendError::Full(..) => "Full(..)".fmt(f), TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f), @@ -1678,7 +1599,7 @@ impl fmt::Debug for TrySendError { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for TrySendError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { TrySendError::Full(..) => { "sending on a full channel".fmt(f) @@ -1720,7 +1641,7 @@ impl From> for TrySendError { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for RecvError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "receiving on a closed channel".fmt(f) } } @@ -1739,7 +1660,7 @@ impl error::Error for RecvError { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for TryRecvError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { TryRecvError::Empty => { "receiving on an empty channel".fmt(f) @@ -1781,7 +1702,7 @@ impl From for TryRecvError { #[stable(feature = "mpsc_recv_timeout_error", since = "1.15.0")] impl fmt::Display for RecvTimeoutError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { RecvTimeoutError::Timeout => { "timed out waiting on channel".fmt(f) @@ -1951,7 +1872,7 @@ mod tests { for _ in 0..10000 { assert_eq!(rx.recv().unwrap(), 1); } - t.join().ok().unwrap(); + t.join().ok().expect("thread panicked"); } #[test] @@ -1977,7 +1898,7 @@ mod tests { }); } drop(tx); - t.join().ok().unwrap(); + t.join().ok().expect("thread panicked"); } #[test] @@ -1996,8 +1917,8 @@ mod tests { tx2.send(1).unwrap(); } }); - t1.join().ok().unwrap(); - t2.join().ok().unwrap(); + t1.join().ok().expect("thread panicked"); + t2.join().ok().expect("thread panicked"); } #[test] @@ -2011,7 +1932,7 @@ mod tests { for _ in 0..40 { tx.send(1).unwrap(); } - t.join().ok().unwrap(); + t.join().ok().expect("thread panicked"); } #[test] @@ -2026,8 +1947,8 @@ mod tests { tx1.send(1).unwrap(); assert_eq!(rx2.recv().unwrap(), 2); }); - t1.join().ok().unwrap(); - t2.join().ok().unwrap(); + t1.join().ok().expect("thread panicked"); + t2.join().ok().expect("thread panicked"); } #[test] @@ -2225,6 +2146,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn oneshot_single_thread_recv_timeout() { let (tx, rx) = channel(); tx.send(()).unwrap(); @@ -2235,6 +2157,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn stress_recv_timeout_two_threads() { let (tx, rx) = channel(); let stress = stress_factor() + 100; @@ -2265,6 +2188,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn recv_timeout_upgrade() { let (tx, rx) = channel::<()>(); let timeout = Duration::from_millis(1); @@ -2276,6 +2200,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn stress_recv_timeout_shared() { let (tx, rx) = channel(); let stress = stress_factor() + 100; @@ -2306,6 +2231,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn very_long_recv_timeout_wont_panic() { let (tx, rx) = channel::<()>(); let join_handle = thread::spawn(move || { @@ -2325,6 +2251,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn shared_recv_timeout() { let (tx, rx) = channel(); let total = 5; @@ -2550,6 +2477,7 @@ mod sync_tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn recv_timeout() { let (tx, rx) = sync_channel::(1); assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); @@ -2639,6 +2567,7 @@ mod sync_tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn stress_recv_timeout_two_threads() { let (tx, rx) = sync_channel::(0); @@ -2662,6 +2591,7 @@ mod sync_tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn stress_recv_timeout_shared() { const AMT: u32 = 1000; const NTHREADS: u32 = 8; diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs index 5c516d5de0f17..e7a5cc46b31a8 100644 --- a/src/libstd/sync/mpsc/oneshot.rs +++ b/src/libstd/sync/mpsc/oneshot.rs @@ -24,7 +24,6 @@ pub use self::Failure::*; pub use self::UpgradeResult::*; -pub use self::SelectionResult::*; use self::MyUpgrade::*; use crate::sync::mpsc::Receiver; @@ -66,12 +65,6 @@ pub enum UpgradeResult { UpWoke(SignalToken), } -pub enum SelectionResult { - SelCanceled, - SelUpgraded(SignalToken, Receiver), - SelSuccess, -} - enum MyUpgrade { NothingSent, SendUsed, @@ -264,71 +257,6 @@ impl Packet { // select implementation //////////////////////////////////////////////////////////////////////////// - // If Ok, the value is whether this port has data, if Err, then the upgraded - // port needs to be checked instead of this one. - pub fn can_recv(&self) -> Result> { - unsafe { - match self.state.load(Ordering::SeqCst) { - EMPTY => Ok(false), // Welp, we tried - DATA => Ok(true), // we have some un-acquired data - DISCONNECTED if (*self.data.get()).is_some() => Ok(true), // we have data - DISCONNECTED => { - match ptr::replace(self.upgrade.get(), SendUsed) { - // The other end sent us an upgrade, so we need to - // propagate upwards whether the upgrade can receive - // data - GoUp(upgrade) => Err(upgrade), - - // If the other end disconnected without sending an - // upgrade, then we have data to receive (the channel is - // disconnected). - up => { ptr::write(self.upgrade.get(), up); Ok(true) } - } - } - _ => unreachable!(), // we're the "one blocker" - } - } - } - - // Attempts to start selection on this port. This can either succeed, fail - // because there is data, or fail because there is an upgrade pending. - pub fn start_selection(&self, token: SignalToken) -> SelectionResult { - unsafe { - let ptr = token.cast_to_usize(); - match self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) { - EMPTY => SelSuccess, - DATA => { - drop(SignalToken::cast_from_usize(ptr)); - SelCanceled - } - DISCONNECTED if (*self.data.get()).is_some() => { - drop(SignalToken::cast_from_usize(ptr)); - SelCanceled - } - DISCONNECTED => { - match ptr::replace(self.upgrade.get(), SendUsed) { - // The other end sent us an upgrade, so we need to - // propagate upwards whether the upgrade can receive - // data - GoUp(upgrade) => { - SelUpgraded(SignalToken::cast_from_usize(ptr), upgrade) - } - - // If the other end disconnected without sending an - // upgrade, then we have data to receive (the channel is - // disconnected). - up => { - ptr::write(self.upgrade.get(), up); - drop(SignalToken::cast_from_usize(ptr)); - SelCanceled - } - } - } - _ => unreachable!(), // we're the "one blocker" - } - } - } - // Remove a previous selecting thread from this port. This ensures that the // blocked thread will no longer be visible to any other threads. // diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs deleted file mode 100644 index 19c9490864545..0000000000000 --- a/src/libstd/sync/mpsc/select.rs +++ /dev/null @@ -1,352 +0,0 @@ -//! Selection over an array of receivers -//! -//! This module contains the implementation machinery necessary for selecting -//! over a number of receivers. One large goal of this module is to provide an -//! efficient interface to selecting over any receiver of any type. -//! -//! This is achieved through an architecture of a "receiver set" in which -//! receivers are added to a set and then the entire set is waited on at once. -//! The set can be waited on multiple times to prevent re-adding each receiver -//! to the set. -//! -//! Usage of this module is currently encouraged to go through the use of the -//! `select!` macro. This macro allows naturally binding of variables to the -//! received values of receivers in a much more natural syntax then usage of the -//! `Select` structure directly. -//! -//! # Examples -//! -//! ```rust -//! #![feature(mpsc_select)] -//! -//! use std::sync::mpsc::channel; -//! -//! let (tx1, rx1) = channel(); -//! let (tx2, rx2) = channel(); -//! -//! tx1.send(1).unwrap(); -//! tx2.send(2).unwrap(); -//! -//! select! { -//! val = rx1.recv() => { -//! assert_eq!(val.unwrap(), 1); -//! }, -//! val = rx2.recv() => { -//! assert_eq!(val.unwrap(), 2); -//! } -//! } -//! ``` - -#![allow(dead_code)] -#![unstable(feature = "mpsc_select", - reason = "This implementation, while likely sufficient, is unsafe and \ - likely to be error prone. At some point in the future this \ - module will be removed.", - issue = "27800")] -#![rustc_deprecated(since = "1.32.0", - reason = "channel selection will be removed in a future release")] - -use core::cell::{Cell, UnsafeCell}; -use core::marker; -use core::ptr; -use core::usize; - -use crate::fmt; -use crate::sync::mpsc::{Receiver, RecvError}; -use crate::sync::mpsc::blocking::{self, SignalToken}; - -/// The "receiver set" of the select interface. This structure is used to manage -/// a set of receivers which are being selected over. -pub struct Select { - inner: UnsafeCell, - next_id: Cell, -} - -struct SelectInner { - head: *mut Handle<'static, ()>, - tail: *mut Handle<'static, ()>, -} - -impl !marker::Send for Select {} - -/// A handle to a receiver which is currently a member of a `Select` set of -/// receivers. This handle is used to keep the receiver in the set as well as -/// interact with the underlying receiver. -pub struct Handle<'rx, T:Send+'rx> { - /// The ID of this handle, used to compare against the return value of - /// `Select::wait()`. - id: usize, - selector: *mut SelectInner, - next: *mut Handle<'static, ()>, - prev: *mut Handle<'static, ()>, - added: bool, - packet: &'rx (dyn Packet+'rx), - - // due to our fun transmutes, we be sure to place this at the end. (nothing - // previous relies on T) - rx: &'rx Receiver, -} - -struct Packets { cur: *mut Handle<'static, ()> } - -#[doc(hidden)] -#[derive(PartialEq, Eq)] -pub enum StartResult { - Installed, - Abort, -} - -#[doc(hidden)] -pub trait Packet { - fn can_recv(&self) -> bool; - fn start_selection(&self, token: SignalToken) -> StartResult; - fn abort_selection(&self) -> bool; -} - -impl Select { - /// Creates a new selection structure. This set is initially empty. - /// - /// Usage of this struct directly can sometimes be burdensome, and usage is much easier through - /// the `select!` macro. - /// - /// # Examples - /// - /// ``` - /// #![feature(mpsc_select)] - /// - /// use std::sync::mpsc::Select; - /// - /// let select = Select::new(); - /// ``` - pub fn new() -> Select { - Select { - inner: UnsafeCell::new(SelectInner { - head: ptr::null_mut(), - tail: ptr::null_mut(), - }), - next_id: Cell::new(1), - } - } - - /// Creates a new handle into this receiver set for a new receiver. Note - /// that this does *not* add the receiver to the receiver set, for that you - /// must call the `add` method on the handle itself. - pub fn handle<'a, T: Send>(&'a self, rx: &'a Receiver) -> Handle<'a, T> { - let id = self.next_id.get(); - self.next_id.set(id + 1); - Handle { - id, - selector: self.inner.get(), - next: ptr::null_mut(), - prev: ptr::null_mut(), - added: false, - rx, - packet: rx, - } - } - - /// Waits for an event on this receiver set. The returned value is *not* an - /// index, but rather an ID. This ID can be queried against any active - /// `Handle` structures (each one has an `id` method). The handle with - /// the matching `id` will have some sort of event available on it. The - /// event could either be that data is available or the corresponding - /// channel has been closed. - pub fn wait(&self) -> usize { - self.wait2(true) - } - - /// Helper method for skipping the preflight checks during testing - pub(super) fn wait2(&self, do_preflight_checks: bool) -> usize { - // Note that this is currently an inefficient implementation. We in - // theory have knowledge about all receivers in the set ahead of time, - // so this method shouldn't really have to iterate over all of them yet - // again. The idea with this "receiver set" interface is to get the - // interface right this time around, and later this implementation can - // be optimized. - // - // This implementation can be summarized by: - // - // fn select(receivers) { - // if any receiver ready { return ready index } - // deschedule { - // block on all receivers - // } - // unblock on all receivers - // return ready index - // } - // - // Most notably, the iterations over all of the receivers shouldn't be - // necessary. - unsafe { - // Stage 1: preflight checks. Look for any packets ready to receive - if do_preflight_checks { - for handle in self.iter() { - if (*handle).packet.can_recv() { - return (*handle).id(); - } - } - } - - // Stage 2: begin the blocking process - // - // Create a number of signal tokens, and install each one - // sequentially until one fails. If one fails, then abort the - // selection on the already-installed tokens. - let (wait_token, signal_token) = blocking::tokens(); - for (i, handle) in self.iter().enumerate() { - match (*handle).packet.start_selection(signal_token.clone()) { - StartResult::Installed => {} - StartResult::Abort => { - // Go back and abort the already-begun selections - for handle in self.iter().take(i) { - (*handle).packet.abort_selection(); - } - return (*handle).id; - } - } - } - - // Stage 3: no messages available, actually block - wait_token.wait(); - - // Stage 4: there *must* be message available; find it. - // - // Abort the selection process on each receiver. If the abort - // process returns `true`, then that means that the receiver is - // ready to receive some data. Note that this also means that the - // receiver may have yet to have fully read the `to_wake` field and - // woken us up (although the wakeup is guaranteed to fail). - // - // This situation happens in the window of where a sender invokes - // increment(), sees -1, and then decides to wake up the thread. After - // all this is done, the sending thread will set `selecting` to - // `false`. Until this is done, we cannot return. If we were to - // return, then a sender could wake up a receiver which has gone - // back to sleep after this call to `select`. - // - // Note that it is a "fairly small window" in which an increment() - // views that it should wake a thread up until the `selecting` bit - // is set to false. For now, the implementation currently just spins - // in a yield loop. This is very distasteful, but this - // implementation is already nowhere near what it should ideally be. - // A rewrite should focus on avoiding a yield loop, and for now this - // implementation is tying us over to a more efficient "don't - // iterate over everything every time" implementation. - let mut ready_id = usize::MAX; - for handle in self.iter() { - if (*handle).packet.abort_selection() { - ready_id = (*handle).id; - } - } - - // We must have found a ready receiver - assert!(ready_id != usize::MAX); - return ready_id; - } - } - - fn iter(&self) -> Packets { Packets { cur: unsafe { &*self.inner.get() }.head } } -} - -impl<'rx, T: Send> Handle<'rx, T> { - /// Retrieves the ID of this handle. - #[inline] - pub fn id(&self) -> usize { self.id } - - /// Blocks to receive a value on the underlying receiver, returning `Some` on - /// success or `None` if the channel disconnects. This function has the same - /// semantics as `Receiver.recv` - pub fn recv(&mut self) -> Result { self.rx.recv() } - - /// Adds this handle to the receiver set that the handle was created from. This - /// method can be called multiple times, but it has no effect if `add` was - /// called previously. - /// - /// This method is unsafe because it requires that the `Handle` is not moved - /// while it is added to the `Select` set. - pub unsafe fn add(&mut self) { - if self.added { return } - let selector = &mut *self.selector; - let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>; - - if selector.head.is_null() { - selector.head = me; - selector.tail = me; - } else { - (*me).prev = selector.tail; - assert!((*me).next.is_null()); - (*selector.tail).next = me; - selector.tail = me; - } - self.added = true; - } - - /// Removes this handle from the `Select` set. This method is unsafe because - /// it has no guarantee that the `Handle` was not moved since `add` was - /// called. - pub unsafe fn remove(&mut self) { - if !self.added { return } - - let selector = &mut *self.selector; - let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>; - - if self.prev.is_null() { - assert_eq!(selector.head, me); - selector.head = self.next; - } else { - (*self.prev).next = self.next; - } - if self.next.is_null() { - assert_eq!(selector.tail, me); - selector.tail = self.prev; - } else { - (*self.next).prev = self.prev; - } - - self.next = ptr::null_mut(); - self.prev = ptr::null_mut(); - - self.added = false; - } -} - -impl Drop for Select { - fn drop(&mut self) { - unsafe { - assert!((&*self.inner.get()).head.is_null()); - assert!((&*self.inner.get()).tail.is_null()); - } - } -} - -impl Drop for Handle<'_, T> { - fn drop(&mut self) { - unsafe { self.remove() } - } -} - -impl Iterator for Packets { - type Item = *mut Handle<'static, ()>; - - fn next(&mut self) -> Option<*mut Handle<'static, ()>> { - if self.cur.is_null() { - None - } else { - let ret = Some(self.cur); - unsafe { self.cur = (*self.cur).next; } - ret - } - } -} - -impl fmt::Debug for Select { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Select").finish() - } -} - -impl fmt::Debug for Handle<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Handle").finish() - } -} diff --git a/src/libstd/sync/mpsc/select_tests.rs b/src/libstd/sync/mpsc/select_tests.rs deleted file mode 100644 index 18d93462c78db..0000000000000 --- a/src/libstd/sync/mpsc/select_tests.rs +++ /dev/null @@ -1,413 +0,0 @@ -#![allow(unused_imports)] - -/// This file exists to hack around https://github.com/rust-lang/rust/issues/47238 - -use crate::thread; -use crate::sync::mpsc::*; - -// Don't use the libstd version so we can pull in the right Select structure -// (std::comm points at the wrong one) -macro_rules! select { - ( - $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ - ) => ({ - let sel = Select::new(); - $( let mut $rx = sel.handle(&$rx); )+ - unsafe { - $( $rx.add(); )+ - } - let ret = sel.wait(); - $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+ - { unreachable!() } - }) -} - -#[test] -fn smoke() { - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - tx1.send(1).unwrap(); - select! { - foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); }, - _bar = rx2.recv() => { panic!() } - } - tx2.send(2).unwrap(); - select! { - _foo = rx1.recv() => { panic!() }, - bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) } - } - drop(tx1); - select! { - foo = rx1.recv() => { assert!(foo.is_err()); }, - _bar = rx2.recv() => { panic!() } - } - drop(tx2); - select! { - bar = rx2.recv() => { assert!(bar.is_err()); } - } -} - -#[test] -fn smoke2() { - let (_tx1, rx1) = channel::(); - let (_tx2, rx2) = channel::(); - let (_tx3, rx3) = channel::(); - let (_tx4, rx4) = channel::(); - let (tx5, rx5) = channel::(); - tx5.send(4).unwrap(); - select! { - _foo = rx1.recv() => { panic!("1") }, - _foo = rx2.recv() => { panic!("2") }, - _foo = rx3.recv() => { panic!("3") }, - _foo = rx4.recv() => { panic!("4") }, - foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); } - } -} - -#[test] -fn closed() { - let (_tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - drop(tx2); - - select! { - _a1 = rx1.recv() => { panic!() }, - a2 = rx2.recv() => { assert!(a2.is_err()); } - } -} - -#[test] -fn unblocks() { - let (tx1, rx1) = channel::(); - let (_tx2, rx2) = channel::(); - let (tx3, rx3) = channel::(); - - let _t = thread::spawn(move|| { - for _ in 0..20 { thread::yield_now(); } - tx1.send(1).unwrap(); - rx3.recv().unwrap(); - for _ in 0..20 { thread::yield_now(); } - }); - - select! { - a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, - _b = rx2.recv() => { panic!() } - } - tx3.send(1).unwrap(); - select! { - a = rx1.recv() => { assert!(a.is_err()) }, - _b = rx2.recv() => { panic!() } - } -} - -#[test] -fn both_ready() { - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - let (tx3, rx3) = channel::<()>(); - - let _t = thread::spawn(move|| { - for _ in 0..20 { thread::yield_now(); } - tx1.send(1).unwrap(); - tx2.send(2).unwrap(); - rx3.recv().unwrap(); - }); - - select! { - a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, - a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } - } - select! { - a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, - a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } - } - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty)); - tx3.send(()).unwrap(); -} - -#[test] -fn stress() { - const AMT: i32 = 10000; - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - let (tx3, rx3) = channel::<()>(); - - let _t = thread::spawn(move|| { - for i in 0..AMT { - if i % 2 == 0 { - tx1.send(i).unwrap(); - } else { - tx2.send(i).unwrap(); - } - rx3.recv().unwrap(); - } - }); - - for i in 0..AMT { - select! { - i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); }, - i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); } - } - tx3.send(()).unwrap(); - } -} - -#[allow(unused_must_use)] -#[test] -fn cloning() { - let (tx1, rx1) = channel::(); - let (_tx2, rx2) = channel::(); - let (tx3, rx3) = channel::<()>(); - - let _t = thread::spawn(move|| { - rx3.recv().unwrap(); - tx1.clone(); - assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); - tx1.send(2).unwrap(); - rx3.recv().unwrap(); - }); - - tx3.send(()).unwrap(); - select! { - _i1 = rx1.recv() => {}, - _i2 = rx2.recv() => panic!() - } - tx3.send(()).unwrap(); -} - -#[allow(unused_must_use)] -#[test] -fn cloning2() { - let (tx1, rx1) = channel::(); - let (_tx2, rx2) = channel::(); - let (tx3, rx3) = channel::<()>(); - - let _t = thread::spawn(move|| { - rx3.recv().unwrap(); - tx1.clone(); - assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); - tx1.send(2).unwrap(); - rx3.recv().unwrap(); - }); - - tx3.send(()).unwrap(); - select! { - _i1 = rx1.recv() => {}, - _i2 = rx2.recv() => panic!() - } - tx3.send(()).unwrap(); -} - -#[test] -fn cloning3() { - let (tx1, rx1) = channel::<()>(); - let (tx2, rx2) = channel::<()>(); - let (tx3, rx3) = channel::<()>(); - let _t = thread::spawn(move|| { - let s = Select::new(); - let mut h1 = s.handle(&rx1); - let mut h2 = s.handle(&rx2); - unsafe { h2.add(); } - unsafe { h1.add(); } - assert_eq!(s.wait(), h2.id()); - tx3.send(()).unwrap(); - }); - - for _ in 0..1000 { thread::yield_now(); } - drop(tx1.clone()); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); -} - -#[test] -fn preflight1() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - select! { - _n = rx.recv() => {} - } -} - -#[test] -fn preflight2() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - tx.send(()).unwrap(); - select! { - _n = rx.recv() => {} - } -} - -#[test] -fn preflight3() { - let (tx, rx) = channel(); - drop(tx.clone()); - tx.send(()).unwrap(); - select! { - _n = rx.recv() => {} - } -} - -#[test] -fn preflight4() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id()); -} - -#[test] -fn preflight5() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - tx.send(()).unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id()); -} - -#[test] -fn preflight6() { - let (tx, rx) = channel(); - drop(tx.clone()); - tx.send(()).unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id()); -} - -#[test] -fn preflight7() { - let (tx, rx) = channel::<()>(); - drop(tx); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id()); -} - -#[test] -fn preflight8() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - drop(tx); - rx.recv().unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id()); -} - -#[test] -fn preflight9() { - let (tx, rx) = channel(); - drop(tx.clone()); - tx.send(()).unwrap(); - drop(tx); - rx.recv().unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id()); -} - -#[test] -fn oneshot_data_waiting() { - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move|| { - select! { - _n = rx1.recv() => {} - } - tx2.send(()).unwrap(); - }); - - for _ in 0..100 { thread::yield_now() } - tx1.send(()).unwrap(); - rx2.recv().unwrap(); -} - -#[test] -fn stream_data_waiting() { - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - tx1.send(()).unwrap(); - tx1.send(()).unwrap(); - rx1.recv().unwrap(); - rx1.recv().unwrap(); - let _t = thread::spawn(move|| { - select! { - _n = rx1.recv() => {} - } - tx2.send(()).unwrap(); - }); - - for _ in 0..100 { thread::yield_now() } - tx1.send(()).unwrap(); - rx2.recv().unwrap(); -} - -#[test] -fn shared_data_waiting() { - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - drop(tx1.clone()); - tx1.send(()).unwrap(); - rx1.recv().unwrap(); - let _t = thread::spawn(move|| { - select! { - _n = rx1.recv() => {} - } - tx2.send(()).unwrap(); - }); - - for _ in 0..100 { thread::yield_now() } - tx1.send(()).unwrap(); - rx2.recv().unwrap(); -} - -#[test] -fn sync1() { - let (tx, rx) = sync_channel::(1); - tx.send(1).unwrap(); - select! { - n = rx.recv() => { assert_eq!(n.unwrap(), 1); } - } -} - -#[test] -fn sync2() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move|| { - for _ in 0..100 { thread::yield_now() } - tx.send(1).unwrap(); - }); - select! { - n = rx.recv() => { assert_eq!(n.unwrap(), 1); } - } -} - -#[test] -fn sync3() { - let (tx1, rx1) = sync_channel::(0); - let (tx2, rx2): (Sender, Receiver) = channel(); - let _t = thread::spawn(move|| { tx1.send(1).unwrap(); }); - let _t = thread::spawn(move|| { tx2.send(2).unwrap(); }); - select! { - n = rx1.recv() => { - let n = n.unwrap(); - assert_eq!(n, 1); - assert_eq!(rx2.recv().unwrap(), 2); - }, - n = rx2.recv() => { - let n = n.unwrap(); - assert_eq!(n, 2); - assert_eq!(rx1.recv().unwrap(), 1); - } - } -} diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs index 6a5d861f0e9cd..dbcdcdac93268 100644 --- a/src/libstd/sync/mpsc/shared.rs +++ b/src/libstd/sync/mpsc/shared.rs @@ -9,6 +9,7 @@ /// channels are quite similar, and this is no coincidence! pub use self::Failure::*; +use self::StartResult::*; use core::cmp; use core::intrinsics::abort; @@ -19,8 +20,6 @@ use crate::ptr; use crate::sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering}; use crate::sync::mpsc::blocking::{self, SignalToken}; use crate::sync::mpsc::mpsc_queue as mpsc; -use crate::sync::mpsc::select::StartResult::*; -use crate::sync::mpsc::select::StartResult; use crate::sync::{Mutex, MutexGuard}; use crate::thread; use crate::time::Instant; @@ -57,6 +56,12 @@ pub enum Failure { Disconnected, } +#[derive(PartialEq, Eq)] +enum StartResult { + Installed, + Abort, +} + impl Packet { // Creation of a packet *must* be followed by a call to postinit_lock // and later by inherit_blocker @@ -78,7 +83,7 @@ impl Packet { // In other case mutex data will be duplicated while cloning // and that could cause problems on platforms where it is // represented by opaque data structure - pub fn postinit_lock(&self) -> MutexGuard<()> { + pub fn postinit_lock(&self) -> MutexGuard<'_, ()> { self.select_lock.lock().unwrap() } @@ -89,7 +94,7 @@ impl Packet { // This can only be called at channel-creation time pub fn inherit_blocker(&self, token: Option, - guard: MutexGuard<()>) { + guard: MutexGuard<'_, ()>) { token.map(|token| { assert_eq!(self.cnt.load(Ordering::SeqCst), 0); assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); @@ -394,16 +399,6 @@ impl Packet { // select implementation //////////////////////////////////////////////////////////////////////////// - // Helper function for select, tests whether this port can receive without - // blocking (obviously not an atomic decision). - // - // This is different than the stream version because there's no need to peek - // at the queue, we can just look at the local count. - pub fn can_recv(&self) -> bool { - let cnt = self.cnt.load(Ordering::SeqCst); - cnt == DISCONNECTED || cnt - unsafe { *self.steals.get() } > 0 - } - // increment the count on the channel (used for selection) fn bump(&self, amt: isize) -> isize { match self.cnt.fetch_add(amt, Ordering::SeqCst) { @@ -415,22 +410,6 @@ impl Packet { } } - // Inserts the signal token for selection on this port, returning true if - // blocking should proceed. - // - // The code here is the same as in stream.rs, except that it doesn't need to - // peek at the channel to see if an upgrade is pending. - pub fn start_selection(&self, token: SignalToken) -> StartResult { - match self.decrement(token) { - Installed => Installed, - Abort => { - let prev = self.bump(1); - assert!(prev == DISCONNECTED || prev >= 0); - Abort - } - } - } - // Cancels a previous thread waiting on this port, returning whether there's // data on the port. // diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs index 7ae6f68b51459..4087728276179 100644 --- a/src/libstd/sync/mpsc/stream.rs +++ b/src/libstd/sync/mpsc/stream.rs @@ -9,7 +9,6 @@ pub use self::Failure::*; pub use self::UpgradeResult::*; -pub use self::SelectionResult::*; use self::Message::*; use core::cmp; @@ -60,12 +59,6 @@ pub enum UpgradeResult { UpWoke(SignalToken), } -pub enum SelectionResult { - SelSuccess, - SelCanceled, - SelUpgraded(SignalToken, Receiver), -} - // Any message could contain an "upgrade request" to a new shared port, so the // internal queue it's a queue of T, but rather Message enum Message { @@ -338,27 +331,6 @@ impl Packet { // select implementation //////////////////////////////////////////////////////////////////////////// - // Tests to see whether this port can receive without blocking. If Ok is - // returned, then that's the answer. If Err is returned, then the returned - // port needs to be queried instead (an upgrade happened) - pub fn can_recv(&self) -> Result> { - // We peek at the queue to see if there's anything on it, and we use - // this return value to determine if we should pop from the queue and - // upgrade this channel immediately. If it looks like we've got an - // upgrade pending, then go through the whole recv rigamarole to update - // the internal state. - match self.queue.peek() { - Some(&mut GoUp(..)) => { - match self.recv(None) { - Err(Upgraded(port)) => Err(port), - _ => unreachable!(), - } - } - Some(..) => Ok(true), - None => Ok(false) - } - } - // increment the count on the channel (used for selection) fn bump(&self, amt: isize) -> isize { match self.queue.producer_addition().cnt.fetch_add(amt, Ordering::SeqCst) { @@ -370,31 +342,6 @@ impl Packet { } } - // Attempts to start selecting on this port. Like a oneshot, this can fail - // immediately because of an upgrade. - pub fn start_selection(&self, token: SignalToken) -> SelectionResult { - match self.decrement(token) { - Ok(()) => SelSuccess, - Err(token) => { - let ret = match self.queue.peek() { - Some(&mut GoUp(..)) => { - match self.queue.pop() { - Some(GoUp(port)) => SelUpgraded(token, port), - _ => unreachable!(), - } - } - Some(..) => SelCanceled, - None => SelCanceled, - }; - // Undo our decrement above, and we should be guaranteed that the - // previous value is positive because we're not going to sleep - let prev = self.bump(1); - assert!(prev == DISCONNECTED || prev >= 0); - ret - } - } - } - // Removes a previous thread from being blocked in this port pub fn abort_selection(&self, was_upgrade: bool) -> Result> { diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs index 485234a9495f3..3c4f8e077c922 100644 --- a/src/libstd/sync/mpsc/sync.rs +++ b/src/libstd/sync/mpsc/sync.rs @@ -33,7 +33,6 @@ use core::ptr; use crate::sync::atomic::{Ordering, AtomicUsize}; use crate::sync::mpsc::blocking::{self, WaitToken, SignalToken}; -use crate::sync::mpsc::select::StartResult::{self, Installed, Abort}; use crate::sync::{Mutex, MutexGuard}; use crate::time::Instant; @@ -153,7 +152,7 @@ fn abort_selection<'a, T>(guard: &mut MutexGuard<'a , State>) -> bool { } /// Wakes up a thread, dropping the lock at the correct time -fn wakeup(token: SignalToken, guard: MutexGuard>) { +fn wakeup(token: SignalToken, guard: MutexGuard<'_, State>) { // We need to be careful to wake up the waiting thread *outside* of the mutex // in case it incurs a context switch. drop(guard); @@ -184,7 +183,7 @@ impl Packet { // wait until a send slot is available, returning locked access to // the channel state. - fn acquire_send_slot(&self) -> MutexGuard> { + fn acquire_send_slot(&self) -> MutexGuard<'_, State> { let mut node = Node { token: None, next: ptr::null_mut() }; loop { let mut guard = self.lock.lock().unwrap(); @@ -316,7 +315,7 @@ impl Packet { // * `waited` - flag if the receiver blocked to receive some data, or if it // just picked up some data on the way out // * `guard` - the lock guard that is held over this channel's lock - fn wakeup_senders(&self, waited: bool, mut guard: MutexGuard>) { + fn wakeup_senders(&self, waited: bool, mut guard: MutexGuard<'_, State>) { let pending_sender1: Option = guard.queue.dequeue(); // If this is a no-buffer channel (cap == 0), then if we didn't wait we @@ -406,42 +405,6 @@ impl Packet { while let Some(token) = queue.dequeue() { token.signal(); } waiter.map(|t| t.signal()); } - - //////////////////////////////////////////////////////////////////////////// - // select implementation - //////////////////////////////////////////////////////////////////////////// - - // If Ok, the value is whether this port has data, if Err, then the upgraded - // port needs to be checked instead of this one. - pub fn can_recv(&self) -> bool { - let guard = self.lock.lock().unwrap(); - guard.disconnected || guard.buf.size() > 0 - } - - // Attempts to start selection on this port. This can either succeed or fail - // because there is data waiting. - pub fn start_selection(&self, token: SignalToken) -> StartResult { - let mut guard = self.lock.lock().unwrap(); - if guard.disconnected || guard.buf.size() > 0 { - Abort - } else { - match mem::replace(&mut guard.blocker, BlockedReceiver(token)) { - NoneBlocked => {} - BlockedSender(..) => unreachable!(), - BlockedReceiver(..) => unreachable!(), - } - Installed - } - } - - // Remove a previous selecting thread from this port. This ensures that the - // blocked thread will no longer be visible to any other threads. - // - // The return value indicates whether there's data on this port. - pub fn abort_selection(&self) -> bool { - let mut guard = self.lock.lock().unwrap(); - abort_selection(&mut guard) - } } impl Drop for Packet { diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 6b812e65b7269..87c2318a9377c 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -215,7 +215,7 @@ impl Mutex { /// assert_eq!(*mutex.lock().unwrap(), 10); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> LockResult> { + pub fn lock(&self) -> LockResult> { unsafe { self.inner.raw_lock(); MutexGuard::new(self) @@ -258,7 +258,7 @@ impl Mutex { /// assert_eq!(*mutex.lock().unwrap(), 10); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn try_lock(&self) -> TryLockResult> { + pub fn try_lock(&self) -> TryLockResult> { unsafe { if self.inner.try_lock() { Ok(MutexGuard::new(self)?) @@ -376,6 +376,8 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex { impl From for Mutex { /// Creates a new mutex in an unlocked state ready for use. /// This is equivalent to [`Mutex::new`]. + /// + /// [`Mutex::new`]: ../../std/sync/struct.Mutex.html#method.new fn from(t: T) -> Self { Mutex::new(t) } @@ -391,7 +393,7 @@ impl Default for Mutex { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Mutex { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.try_lock() { Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(), Err(TryLockError::Poisoned(err)) => { @@ -400,7 +402,9 @@ impl fmt::Debug for Mutex { Err(TryLockError::WouldBlock) => { struct LockedPlaceholder; impl fmt::Debug for LockedPlaceholder { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("") } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("") + } } f.debug_struct("Mutex").field("data", &LockedPlaceholder).finish() @@ -449,14 +453,14 @@ impl Drop for MutexGuard<'_, T> { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for MutexGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } #[stable(feature = "std_guard_impls", since = "1.20.0")] impl fmt::Display for MutexGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index a036c2666625c..e529b8c4227fa 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -115,6 +115,11 @@ pub struct OnceState { /// static START: Once = ONCE_INIT; /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_deprecated( + since = "1.38.0", + reason = "the `new` function is now preferred", + suggestion = "Once::new()", +)] pub const ONCE_INIT: Once = Once::new(); // Four states that a Once can be in, encoded into the lower bits of `state` in @@ -431,7 +436,7 @@ impl Once { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Once { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Once { .. }") } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 0be83c76d6259..b1b56f321fc6b 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -180,7 +180,7 @@ impl RwLock { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn read(&self) -> LockResult> { + pub fn read(&self) -> LockResult> { unsafe { self.inner.read(); RwLockReadGuard::new(self) @@ -219,7 +219,7 @@ impl RwLock { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn try_read(&self) -> TryLockResult> { + pub fn try_read(&self) -> TryLockResult> { unsafe { if self.inner.try_read() { Ok(RwLockReadGuard::new(self)?) @@ -262,7 +262,7 @@ impl RwLock { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn write(&self) -> LockResult> { + pub fn write(&self) -> LockResult> { unsafe { self.inner.write(); RwLockWriteGuard::new(self) @@ -301,7 +301,7 @@ impl RwLock { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn try_write(&self) -> TryLockResult> { + pub fn try_write(&self) -> TryLockResult> { unsafe { if self.inner.try_write() { Ok(RwLockWriteGuard::new(self)?) @@ -421,7 +421,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for RwLock { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.try_read() { Ok(guard) => f.debug_struct("RwLock").field("data", &&*guard).finish(), Err(TryLockError::Poisoned(err)) => { @@ -430,7 +430,9 @@ impl fmt::Debug for RwLock { Err(TryLockError::WouldBlock) => { struct LockedPlaceholder; impl fmt::Debug for LockedPlaceholder { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("") } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("") + } } f.debug_struct("RwLock").field("data", &LockedPlaceholder).finish() @@ -451,6 +453,8 @@ impl Default for RwLock { impl From for RwLock { /// Creates a new instance of an `RwLock` which is unlocked. /// This is equivalent to [`RwLock::new`]. + /// + /// [`RwLock::new`]: ../../std/sync/struct.RwLock.html#method.new fn from(t: T) -> Self { RwLock::new(t) } @@ -481,7 +485,7 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for RwLockReadGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RwLockReadGuard") .field("lock", &self.__lock) .finish() @@ -490,14 +494,14 @@ impl fmt::Debug for RwLockReadGuard<'_, T> { #[stable(feature = "std_guard_impls", since = "1.20.0")] impl fmt::Display for RwLockReadGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for RwLockWriteGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RwLockWriteGuard") .field("lock", &self.__lock) .finish() @@ -506,7 +510,7 @@ impl fmt::Debug for RwLockWriteGuard<'_, T> { #[stable(feature = "std_guard_impls", since = "1.20.0")] impl fmt::Display for RwLockWriteGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } diff --git a/src/libstd/sys/cloudabi/backtrace.rs b/src/libstd/sys/cloudabi/backtrace.rs deleted file mode 100644 index a15d2238e5563..0000000000000 --- a/src/libstd/sys/cloudabi/backtrace.rs +++ /dev/null @@ -1,115 +0,0 @@ -use crate::error::Error; -use crate::ffi::CStr; -use crate::fmt; -use crate::intrinsics; -use crate::io; -use crate::sys_common::backtrace::Frame; - -use unwind as uw; - -pub struct BacktraceContext; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl fmt::Display for UnwindError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { - let mut cx = Context { idx: 0, frames }; - let result_unwind = - unsafe { uw::_Unwind_Backtrace(trace_fn, &mut cx as *mut Context as *mut libc::c_void) }; - // See libunwind:src/unwind/Backtrace.c for the return values. - // No, there is no doc. - match result_unwind { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => Err(io::Error::new( - io::ErrorKind::Other, - UnwindError(result_unwind), - )), - } -} - -extern "C" fn trace_fn( - ctx: *mut uw::_Unwind_Context, - arg: *mut libc::c_void, -) -> uw::_Unwind_Reason_Code { - let cx = unsafe { &mut *(arg as *mut Context) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - let mut ip_before_insn = 0; - let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void }; - if !ip.is_null() && ip_before_insn == 0 { - // this is a non-signaling frame, so `ip` refers to the address - // after the calling instruction. account for that. - ip = (ip as usize - 1) as *mut _; - } - - let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) }; - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} - -pub fn foreach_symbol_fileline(_: Frame, _: F, _: &BacktraceContext) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()>, -{ - // No way to obtain this information on CloudABI. - Ok(false) -} - -pub fn resolve_symname(frame: Frame, callback: F, _: &BacktraceContext) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()>, -{ - unsafe { - let mut info: Dl_info = intrinsics::init(); - let symname = - if dladdr(frame.exact_position as *mut _, &mut info) == 0 || info.dli_sname.is_null() { - None - } else { - CStr::from_ptr(info.dli_sname).to_str().ok() - }; - callback(symname) - } -} - -#[repr(C)] -struct Dl_info { - dli_fname: *const libc::c_char, - dli_fbase: *mut libc::c_void, - dli_sname: *const libc::c_char, - dli_saddr: *mut libc::c_void, -} - -extern "C" { - fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int; -} diff --git a/src/libstd/sys/cloudabi/io.rs b/src/libstd/sys/cloudabi/io.rs index 8b02d3fd19d30..4b423a5cbc11a 100644 --- a/src/libstd/sys/cloudabi/io.rs +++ b/src/libstd/sys/cloudabi/io.rs @@ -1,9 +1,9 @@ -pub struct IoVec<'a>(&'a [u8]); +pub struct IoSlice<'a>(&'a [u8]); -impl<'a> IoVec<'a> { +impl<'a> IoSlice<'a> { #[inline] - pub fn new(buf: &'a [u8]) -> IoVec<'a> { - IoVec(buf) + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice(buf) } #[inline] @@ -12,12 +12,12 @@ impl<'a> IoVec<'a> { } } -pub struct IoVecMut<'a>(&'a mut [u8]); +pub struct IoSliceMut<'a>(&'a mut [u8]); -impl<'a> IoVecMut<'a> { +impl<'a> IoSliceMut<'a> { #[inline] - pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { - IoVecMut(buf) + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut(buf) } #[inline] diff --git a/src/libstd/sys/cloudabi/mod.rs b/src/libstd/sys/cloudabi/mod.rs index 47c90fddd867f..c3b8bbd042606 100644 --- a/src/libstd/sys/cloudabi/mod.rs +++ b/src/libstd/sys/cloudabi/mod.rs @@ -4,8 +4,6 @@ use crate::mem; #[path = "../unix/alloc.rs"] pub mod alloc; pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; #[path = "../unix/cmath.rs"] pub mod cmath; pub mod condvar; @@ -14,8 +12,6 @@ pub mod io; pub mod memchr; pub mod mutex; pub mod os; -#[path = "../unix/os_str.rs"] -pub mod os_str; pub mod rwlock; pub mod stack_overflow; pub mod stdio; @@ -24,6 +20,8 @@ pub mod thread; pub mod thread_local; pub mod time; +pub use crate::sys_common::os_str_bytes as os_str; + mod abi; mod shims; diff --git a/src/libstd/sys/cloudabi/shims/fs.rs b/src/libstd/sys/cloudabi/shims/fs.rs index 56667bef00706..05f91541011e6 100644 --- a/src/libstd/sys/cloudabi/shims/fs.rs +++ b/src/libstd/sys/cloudabi/shims/fs.rs @@ -1,7 +1,7 @@ use crate::ffi::OsString; use crate::fmt; use crate::hash::{Hash, Hasher}; -use crate::io::{self, SeekFrom}; +use crate::io::{self, SeekFrom, IoSlice, IoSliceMut}; use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; use crate::sys::{unsupported, Void}; @@ -81,7 +81,7 @@ impl PartialEq for FilePermissions { impl Eq for FilePermissions {} impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } @@ -123,13 +123,13 @@ impl Hash for FileType { } impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } @@ -198,10 +198,18 @@ impl File { match self.0 {} } + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } + pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { + match self.0 {} + } + pub fn flush(&self) -> io::Result<()> { match self.0 {} } @@ -234,7 +242,7 @@ impl DirBuilder { } impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } diff --git a/src/libstd/sys/cloudabi/shims/net.rs b/src/libstd/sys/cloudabi/shims/net.rs index 50d72dc7b240b..8d609cdfad5dc 100644 --- a/src/libstd/sys/cloudabi/shims/net.rs +++ b/src/libstd/sys/cloudabi/shims/net.rs @@ -1,5 +1,5 @@ use crate::fmt; -use crate::io::{self, IoVec, IoVecMut}; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::time::Duration; use crate::sys::{unsupported, Void}; @@ -43,7 +43,7 @@ impl TcpStream { match self.0 {} } - pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result { + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { match self.0 {} } @@ -51,7 +51,7 @@ impl TcpStream { match self.0 {} } - pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result { + pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { match self.0 {} } @@ -97,7 +97,7 @@ impl TcpStream { } impl fmt::Debug for TcpStream { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } @@ -147,7 +147,7 @@ impl TcpListener { } impl fmt::Debug for TcpListener { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } @@ -159,6 +159,10 @@ impl UdpSocket { unsupported() } + pub fn peer_addr(&self) -> io::Result { + match self.0 {} + } + pub fn socket_addr(&self) -> io::Result { match self.0 {} } @@ -277,7 +281,7 @@ impl UdpSocket { } impl fmt::Debug for UdpSocket { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } @@ -297,10 +301,10 @@ impl Iterator for LookupHost { } } -impl<'a> TryFrom<&'a str> for LookupHost { +impl TryFrom<&str> for LookupHost { type Error = io::Error; - fn try_from(_v: &'a str) -> io::Result { + fn try_from(_v: &str) -> io::Result { unsupported() } } diff --git a/src/libstd/sys/cloudabi/shims/os.rs b/src/libstd/sys/cloudabi/shims/os.rs index 0c4690e12b052..944b9525b3b60 100644 --- a/src/libstd/sys/cloudabi/shims/os.rs +++ b/src/libstd/sys/cloudabi/shims/os.rs @@ -34,7 +34,7 @@ pub fn unsetenv(_: &OsStr) -> io::Result<()> { pub struct SplitPaths<'a>(&'a Void); -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths { +pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { panic!("unsupported") } @@ -57,7 +57,7 @@ where } impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "not supported on CloudABI yet".fmt(f) } } diff --git a/src/libstd/sys/cloudabi/shims/pipe.rs b/src/libstd/sys/cloudabi/shims/pipe.rs index f3debb9504742..fb14dc5910181 100644 --- a/src/libstd/sys/cloudabi/shims/pipe.rs +++ b/src/libstd/sys/cloudabi/shims/pipe.rs @@ -1,4 +1,4 @@ -use crate::io; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::sys::Void; pub struct AnonPipe(Void); @@ -8,10 +8,18 @@ impl AnonPipe { match self.0 {} } + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } + pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/cloudabi/shims/process.rs b/src/libstd/sys/cloudabi/shims/process.rs index 710c42c114902..e719b362cbf55 100644 --- a/src/libstd/sys/cloudabi/shims/process.rs +++ b/src/libstd/sys/cloudabi/shims/process.rs @@ -71,7 +71,7 @@ impl From for Stdio { } impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { Ok(()) } } @@ -105,13 +105,13 @@ impl PartialEq for ExitStatus { impl Eq for ExitStatus {} impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index f853346e0e63c..7da16c4d247aa 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -1,4 +1,3 @@ -use crate::boxed::FnBox; use crate::cmp; use crate::ffi::CStr; use crate::io; @@ -22,7 +21,7 @@ unsafe impl Sync for Thread {} impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, p: Box) -> io::Result { + pub unsafe fn new(stack: usize, p: Box) -> io::Result { let p = box p; let mut native: libc::pthread_t = mem::zeroed(); let mut attr: libc::pthread_attr_t = mem::zeroed(); diff --git a/src/libstd/sys/cloudabi/time.rs b/src/libstd/sys/cloudabi/time.rs index d7502c61eff2c..49a234e115804 100644 --- a/src/libstd/sys/cloudabi/time.rs +++ b/src/libstd/sys/cloudabi/time.rs @@ -33,11 +33,9 @@ impl Instant { Instant { t: 0 } } - pub fn sub_instant(&self, other: &Instant) -> Duration { - let diff = self.t - .checked_sub(other.t) - .expect("second instant is later than self"); - Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32) + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + let diff = self.t.checked_sub(other.t)?; + Some(Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32)) } pub fn checked_add_duration(&self, other: &Duration) -> Option { diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs index 5ba9304c09b99..21360e2e0f028 100644 --- a/src/libstd/sys/mod.rs +++ b/src/libstd/sys/mod.rs @@ -22,7 +22,7 @@ #![allow(missing_debug_implementations)] -cfg_if! { +cfg_if::cfg_if! { if #[cfg(unix)] { mod unix; pub use self::unix::*; @@ -35,6 +35,9 @@ cfg_if! { } else if #[cfg(target_os = "redox")] { mod redox; pub use self::redox::*; + } else if #[cfg(target_os = "wasi")] { + mod wasi; + pub use self::wasi::*; } else if #[cfg(target_arch = "wasm32")] { mod wasm; pub use self::wasm::*; @@ -51,7 +54,7 @@ cfg_if! { // Windows when we're compiling for Linux. #[cfg(rustdoc)] -cfg_if! { +cfg_if::cfg_if! { if #[cfg(any(unix, target_os = "redox"))] { // On unix we'll document what's already available #[stable(feature = "rust1", since = "1.0.0")] @@ -74,7 +77,7 @@ cfg_if! { } #[cfg(rustdoc)] -cfg_if! { +cfg_if::cfg_if! { if #[cfg(windows)] { // On windows we'll just be documenting what's already available #[allow(missing_docs)] diff --git a/src/libstd/sys/redox/backtrace/mod.rs b/src/libstd/sys/redox/backtrace/mod.rs deleted file mode 100644 index 8ea2783580a47..0000000000000 --- a/src/libstd/sys/redox/backtrace/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -/// See sys/unix/backtrace/mod.rs for an explanation of the method used here. - -pub use self::tracing::unwind_backtrace; -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; - -// tracing impls: -mod tracing; -// symbol resolvers: -mod printing; - -pub mod gnu { - use crate::io; - use crate::fs; - use crate::vec::Vec; - use crate::ffi::OsStr; - use crate::os::unix::ffi::OsStrExt; - use crate::io::Read; - use libc::c_char; - - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - let mut exefile = fs::File::open("sys:exe")?; - let mut exename = Vec::new(); - exefile.read_to_end(&mut exename)?; - if exename.last() == Some(&b'\n') { - exename.pop(); - } - let file = fs::File::open(OsStr::from_bytes(&exename))?; - Ok((exename.into_iter().map(|c| c as c_char).collect(), file)) - } -} - -pub struct BacktraceContext; diff --git a/src/libstd/sys/redox/backtrace/printing.rs b/src/libstd/sys/redox/backtrace/printing.rs deleted file mode 100644 index 489eed4562deb..0000000000000 --- a/src/libstd/sys/redox/backtrace/printing.rs +++ /dev/null @@ -1 +0,0 @@ -pub use crate::sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; diff --git a/src/libstd/sys/redox/backtrace/tracing.rs b/src/libstd/sys/redox/backtrace/tracing.rs deleted file mode 100644 index e7a68eadbde3a..0000000000000 --- a/src/libstd/sys/redox/backtrace/tracing.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::error::Error; -use crate::fmt; -use crate::io; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -use unwind as uw; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl fmt::Display for UnwindError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - let mut cx = Context { - idx: 0, - frames: frames, - }; - let result_unwind = unsafe { - uw::_Unwind_Backtrace(trace_fn, - &mut cx as *mut Context - as *mut libc::c_void) - }; - // See libunwind:src/unwind/Backtrace.c for the return values. - // No, there is no doc. - match result_unwind { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => { - Err(io::Error::new(io::ErrorKind::Other, - UnwindError(result_unwind))) - } - } -} - -extern fn trace_fn(ctx: *mut uw::_Unwind_Context, - arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { - let cx = unsafe { &mut *(arg as *mut Context) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - let mut ip_before_insn = 0; - let mut ip = unsafe { - uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void - }; - if !ip.is_null() && ip_before_insn == 0 { - // this is a non-signaling frame, so `ip` refers to the address - // after the calling instruction. account for that. - ip = (ip as usize - 1) as *mut _; - } - - // dladdr() on osx gets whiny when we use FindEnclosingFunction, and - // it appears to work fine without it, so we only use - // FindEnclosingFunction on non-osx platforms. In doing so, we get a - // slightly more accurate stack trace in the process. - // - // This is often because panic involves the last instruction of a - // function being "call std::rt::begin_unwind", with no ret - // instructions after it. This means that the return instruction - // pointer points *outside* of the calling function, and by - // unwinding it we go back to the original function. - let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { - ip - } else { - unsafe { uw::_Unwind_FindEnclosingFunction(ip) } - }; - - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} diff --git a/src/libstd/sys/redox/ext/ffi.rs b/src/libstd/sys/redox/ext/ffi.rs index 671498bc39037..974d7b82c125f 100644 --- a/src/libstd/sys/redox/ext/ffi.rs +++ b/src/libstd/sys/redox/ext/ffi.rs @@ -1,55 +1,38 @@ //! Redox-specific extension to the primitives in the `std::ffi` module. +//! +//! # Examples +//! +//! ``` +//! use std::ffi::OsString; +//! use std::os::redox::ffi::OsStringExt; +//! +//! let bytes = b"foo".to_vec(); +//! +//! // OsStringExt::from_vec +//! let os_string = OsString::from_vec(bytes); +//! assert_eq!(os_string.to_str(), Some("foo")); +//! +//! // OsStringExt::into_vec +//! let bytes = os_string.into_vec(); +//! assert_eq!(bytes, b"foo"); +//! ``` +//! +//! ``` +//! use std::ffi::OsStr; +//! use std::os::redox::ffi::OsStrExt; +//! +//! let bytes = b"foo"; +//! +//! // OsStrExt::from_bytes +//! let os_str = OsStr::from_bytes(bytes); +//! assert_eq!(os_str.to_str(), Some("foo")); +//! +//! // OsStrExt::as_bytes +//! let bytes = os_str.as_bytes(); +//! assert_eq!(bytes, b"foo"); +//! ``` #![stable(feature = "rust1", since = "1.0.0")] -use crate::ffi::{OsStr, OsString}; -use crate::mem; -use crate::sys::os_str::Buf; -use crate::sys_common::{FromInner, IntoInner, AsInner}; - -/// Redox-specific extensions to [`OsString`]. -/// -/// [`OsString`]: ../../../../std/ffi/struct.OsString.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStringExt { - /// Creates an `OsString` from a byte vector. - #[stable(feature = "rust1", since = "1.0.0")] - fn from_vec(vec: Vec) -> Self; - - /// Yields the underlying byte vector of this `OsString`. - #[stable(feature = "rust1", since = "1.0.0")] - fn into_vec(self) -> Vec; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStringExt for OsString { - fn from_vec(vec: Vec) -> OsString { - FromInner::from_inner(Buf { inner: vec }) - } - fn into_vec(self) -> Vec { - self.into_inner().inner - } -} - -/// Redox-specific extensions to [`OsStr`]. -/// -/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStrExt { - #[stable(feature = "rust1", since = "1.0.0")] - fn from_bytes(slice: &[u8]) -> &Self; - - /// Gets the underlying byte view of the `OsStr` slice. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_bytes(&self) -> &[u8]; -} - #[stable(feature = "rust1", since = "1.0.0")] -impl OsStrExt for OsStr { - fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } - } - fn as_bytes(&self) -> &[u8] { - &self.as_inner().inner - } -} +pub use crate::sys_common::os_str_bytes::*; diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs index 53b9dd68f734f..4ddc1f09a319b 100644 --- a/src/libstd/sys/redox/ext/fs.rs +++ b/src/libstd/sys/redox/ext/fs.rs @@ -27,7 +27,7 @@ pub trait PermissionsExt { /// let metadata = f.metadata()?; /// let permissions = metadata.permissions(); /// - /// println!("permissions: {}", permissions.mode()); + /// println!("permissions: {:o}", permissions.mode()); /// Ok(()) /// } /// ``` diff --git a/src/libstd/sys/redox/ext/io.rs b/src/libstd/sys/redox/ext/io.rs index f431f96c541f7..c21d216478fb7 100644 --- a/src/libstd/sys/redox/ext/io.rs +++ b/src/libstd/sys/redox/ext/io.rs @@ -115,6 +115,21 @@ impl AsRawFd for io::Stderr { fn as_raw_fd(&self) -> RawFd { 2 } } +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StdinLock<'a> { + fn as_raw_fd(&self) -> RawFd { 0 } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StdoutLock<'a> { + fn as_raw_fd(&self) -> RawFd { 1 } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StderrLock<'a> { + fn as_raw_fd(&self) -> RawFd { 2 } +} + #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawFd for net::TcpStream { unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index 2c121787804d1..b3ef5f3064c16 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -1,4 +1,4 @@ -#![stable(feature = "unix_socket_redox", since = "1.29")] +#![stable(feature = "unix_socket_redox", since = "1.29.0")] //! Unix-specific networking functionality @@ -27,7 +27,7 @@ use crate::sys::{cvt, fd::FileDesc, syscall}; /// let addr = socket.local_addr().expect("Couldn't get local address"); /// ``` #[derive(Clone)] -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] pub struct SocketAddr(()); impl SocketAddr { @@ -55,7 +55,7 @@ impl SocketAddr { /// let addr = socket.local_addr().expect("Couldn't get local address"); /// assert_eq!(addr.as_pathname(), None); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn as_pathname(&self) -> Option<&Path> { None } @@ -83,14 +83,14 @@ impl SocketAddr { /// let addr = socket.local_addr().expect("Couldn't get local address"); /// assert_eq!(addr.is_unnamed(), true); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn is_unnamed(&self) -> bool { false } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "SocketAddr") } } @@ -109,12 +109,12 @@ impl fmt::Debug for SocketAddr { /// stream.read_to_string(&mut response).unwrap(); /// println!("{}", response); /// ``` -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] pub struct UnixStream(FileDesc); -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl fmt::Debug for UnixStream { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut builder = fmt.debug_struct("UnixStream"); builder.field("fd", &self.0.raw()); if let Ok(addr) = self.local_addr() { @@ -143,7 +143,7 @@ impl UnixStream { /// } /// }; /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn connect>(path: P) -> io::Result { if let Some(s) = path.as_ref().to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) @@ -174,7 +174,7 @@ impl UnixStream { /// } /// }; /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn pair() -> io::Result<(UnixStream, UnixStream)> { let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) .map(FileDesc::new)?; @@ -198,7 +198,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixStream) } @@ -213,7 +213,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let addr = socket.local_addr().expect("Couldn't get local address"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) } @@ -228,7 +228,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let addr = socket.peer_addr().expect("Couldn't get peer address"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn peer_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) } @@ -267,7 +267,7 @@ impl UnixStream { /// let err = result.unwrap_err(); /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) } @@ -306,7 +306,7 @@ impl UnixStream { /// let err = result.unwrap_err(); /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) } @@ -323,7 +323,7 @@ impl UnixStream { /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn read_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) } @@ -340,7 +340,7 @@ impl UnixStream { /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn write_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) } @@ -355,7 +355,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } @@ -375,7 +375,7 @@ impl UnixStream { /// /// # Platform specific /// On Redox this always returns `None`. - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -397,13 +397,13 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl io::Read for UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { io::Read::read(&mut &*self, buf) @@ -415,7 +415,7 @@ impl io::Read for UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl<'a> io::Read for &'a UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -427,7 +427,7 @@ impl<'a> io::Read for &'a UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl io::Write for UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { io::Write::write(&mut &*self, buf) @@ -438,7 +438,7 @@ impl io::Write for UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl<'a> io::Write for &'a UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) @@ -449,21 +449,21 @@ impl<'a> io::Write for &'a UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl AsRawFd for UnixStream { fn as_raw_fd(&self) -> RawFd { self.0.raw() } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl FromRawFd for UnixStream { unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { UnixStream(FileDesc::new(fd)) } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl IntoRawFd for UnixStream { fn into_raw_fd(self) -> RawFd { self.0.into_raw() @@ -498,12 +498,12 @@ impl IntoRawFd for UnixStream { /// } /// } /// ``` -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] pub struct UnixListener(FileDesc); -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl fmt::Debug for UnixListener { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut builder = fmt.debug_struct("UnixListener"); builder.field("fd", &self.0.raw()); if let Ok(addr) = self.local_addr() { @@ -529,7 +529,7 @@ impl UnixListener { /// } /// }; /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn bind>(path: P) -> io::Result { if let Some(s) = path.as_ref().to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) @@ -563,7 +563,7 @@ impl UnixListener { /// Err(e) => println!("accept function failed: {:?}", e), /// } /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(()))) } @@ -583,7 +583,7 @@ impl UnixListener { /// /// let listener_copy = listener.try_clone().expect("try_clone failed"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixListener) } @@ -599,7 +599,7 @@ impl UnixListener { /// /// let addr = listener.local_addr().expect("Couldn't get local address"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) } @@ -615,7 +615,7 @@ impl UnixListener { /// /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } @@ -636,7 +636,7 @@ impl UnixListener { /// /// # Platform specific /// On Redox this always returns `None`. - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -672,34 +672,34 @@ impl UnixListener { /// } /// } /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn incoming<'a>(&'a self) -> Incoming<'a> { Incoming { listener: self } } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl AsRawFd for UnixListener { fn as_raw_fd(&self) -> RawFd { self.0.raw() } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl FromRawFd for UnixListener { unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { UnixListener(FileDesc::new(fd)) } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl IntoRawFd for UnixListener { fn into_raw_fd(self) -> RawFd { self.0.into_raw() } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl<'a> IntoIterator for &'a UnixListener { type Item = io::Result; type IntoIter = Incoming<'a>; @@ -740,12 +740,12 @@ impl<'a> IntoIterator for &'a UnixListener { /// } /// ``` #[derive(Debug)] -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] pub struct Incoming<'a> { listener: &'a UnixListener, } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl<'a> Iterator for Incoming<'a> { type Item = io::Result; diff --git a/src/libstd/sys/redox/fast_thread_local.rs b/src/libstd/sys/redox/fast_thread_local.rs index 1202708a4769a..05464787a05d3 100644 --- a/src/libstd/sys/redox/fast_thread_local.rs +++ b/src/libstd/sys/redox/fast_thread_local.rs @@ -1,111 +1,4 @@ #![cfg(target_thread_local)] #![unstable(feature = "thread_local_internals", issue = "0")] -use crate::cell::{Cell, UnsafeCell}; -use crate::mem; -use crate::ptr; - - -pub struct Key { - inner: UnsafeCell>, - - // Metadata to keep track of the state of the destructor. Remember that - // these variables are thread-local, not global. - dtor_registered: Cell, - dtor_running: Cell, -} - -unsafe impl Sync for Key { } - -impl Key { - pub const fn new() -> Key { - Key { - inner: UnsafeCell::new(None), - dtor_registered: Cell::new(false), - dtor_running: Cell::new(false) - } - } - - pub fn get(&'static self) -> Option<&'static UnsafeCell>> { - unsafe { - if mem::needs_drop::() && self.dtor_running.get() { - return None - } - self.register_dtor(); - } - Some(&self.inner) - } - - unsafe fn register_dtor(&self) { - if !mem::needs_drop::() || self.dtor_registered.get() { - return - } - - register_dtor(self as *const _ as *mut u8, - destroy_value::); - self.dtor_registered.set(true); - } -} - -pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - // The fallback implementation uses a vanilla OS-based TLS key to track - // the list of destructors that need to be run for this thread. The key - // then has its own destructor which runs all the other destructors. - // - // The destructor for DTORS is a little special in that it has a `while` - // loop to continuously drain the list of registered destructors. It - // *should* be the case that this loop always terminates because we - // provide the guarantee that a TLS key cannot be set after it is - // flagged for destruction. - use crate::sys_common::thread_local as os; - - static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors)); - type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; - if DTORS.get().is_null() { - let v: Box = box Vec::new(); - DTORS.set(Box::into_raw(v) as *mut u8); - } - let list: &mut List = &mut *(DTORS.get() as *mut List); - list.push((t, dtor)); - - unsafe extern fn run_dtors(mut ptr: *mut u8) { - while !ptr.is_null() { - let list: Box = Box::from_raw(ptr as *mut List); - for (ptr, dtor) in list.into_iter() { - dtor(ptr); - } - ptr = DTORS.get(); - DTORS.set(ptr::null_mut()); - } - } -} - -pub unsafe extern fn destroy_value(ptr: *mut u8) { - let ptr = ptr as *mut Key; - // Right before we run the user destructor be sure to flag the - // destructor as running for this thread so calls to `get` will return - // `None`. - (*ptr).dtor_running.set(true); - - // The macOS implementation of TLS apparently had an odd aspect to it - // where the pointer we have may be overwritten while this destructor - // is running. Specifically if a TLS destructor re-accesses TLS it may - // trigger a re-initialization of all TLS variables, paving over at - // least some destroyed ones with initial values. - // - // This means that if we drop a TLS value in place on macOS that we could - // revert the value to its original state halfway through the - // destructor, which would be bad! - // - // Hence, we use `ptr::read` on macOS (to move to a "safe" location) - // instead of drop_in_place. - if cfg!(target_os = "macos") { - ptr::read((*ptr).inner.get()); - } else { - ptr::drop_in_place((*ptr).inner.get()); - } -} - -pub fn requires_move_before_drop() -> bool { - false -} +pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor; diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 159ee9911bd3a..b80a1a349e338 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -2,7 +2,7 @@ use crate::os::unix::prelude::*; use crate::ffi::{OsString, OsStr}; use crate::fmt; -use crate::io::{self, Error, ErrorKind, SeekFrom}; +use crate::io::{self, Error, SeekFrom, IoSlice, IoSliceMut}; use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::fd::FileDesc; @@ -10,6 +10,9 @@ use crate::sys::time::SystemTime; use crate::sys::{cvt, syscall}; use crate::sys_common::{AsInner, FromInner}; +pub use crate::sys_common::fs::copy; +pub use crate::sys_common::fs::remove_dir_all; + pub struct File(FileDesc); #[derive(Clone)] @@ -123,7 +126,7 @@ impl FromInner for FilePermissions { } impl fmt::Debug for ReadDir { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. // Thus the result will be e g 'ReadDir("/home")' fmt::Debug::fmt(&*self.root, f) @@ -275,10 +278,18 @@ impl File { self.0.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|buf| self.read(buf), bufs) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|buf| self.write(buf), bufs) + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } pub fn seek(&self, pos: SeekFrom) -> io::Result { @@ -341,7 +352,7 @@ impl FromInner for File { } impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut b = f.debug_struct("File"); b.field("fd", &self.0.raw()); if let Ok(path) = self.path() { @@ -392,27 +403,6 @@ pub fn rmdir(p: &Path) -> io::Result<()> { Ok(()) } -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = lstat(path)?.file_type(); - if filetype.is_symlink() { - unlink(path) - } else { - remove_dir_all_recursive(path) - } -} - -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in readdir(path)? { - let child = child?; - if child.file_type()?.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else { - unlink(&child.path())?; - } - } - rmdir(path) -} - pub fn readlink(p: &Path) -> io::Result { let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_SYMLINK | syscall::O_RDONLY))?; @@ -455,19 +445,3 @@ pub fn canonicalize(p: &Path) -> io::Result { let file = File(FileDesc::new(fd)); file.path() } - -pub fn copy(from: &Path, to: &Path) -> io::Result { - use crate::fs::{File, set_permissions}; - if !from.is_file() { - return Err(Error::new(ErrorKind::InvalidInput, - "the source path is not an existing regular file")) - } - - let mut reader = File::open(from)?; - let mut writer = File::create(to)?; - let perm = reader.metadata()?.permissions(); - - let ret = io::copy(&mut reader, &mut writer)?; - set_permissions(to, perm)?; - Ok(ret) -} diff --git a/src/libstd/sys/redox/io.rs b/src/libstd/sys/redox/io.rs index 8b02d3fd19d30..4b423a5cbc11a 100644 --- a/src/libstd/sys/redox/io.rs +++ b/src/libstd/sys/redox/io.rs @@ -1,9 +1,9 @@ -pub struct IoVec<'a>(&'a [u8]); +pub struct IoSlice<'a>(&'a [u8]); -impl<'a> IoVec<'a> { +impl<'a> IoSlice<'a> { #[inline] - pub fn new(buf: &'a [u8]) -> IoVec<'a> { - IoVec(buf) + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice(buf) } #[inline] @@ -12,12 +12,12 @@ impl<'a> IoVec<'a> { } } -pub struct IoVecMut<'a>(&'a mut [u8]); +pub struct IoSliceMut<'a>(&'a mut [u8]); -impl<'a> IoVecMut<'a> { +impl<'a> IoSliceMut<'a> { #[inline] - pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { - IoVecMut(buf) + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut(buf) } #[inline] diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs index 7f3ac1f1bb5b3..354184f8af6e7 100644 --- a/src/libstd/sys/redox/mod.rs +++ b/src/libstd/sys/redox/mod.rs @@ -8,8 +8,6 @@ pub use self::rand::hashmap_random_keys; #[path = "../unix/alloc.rs"] pub mod alloc; pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; pub mod cmath; pub mod condvar; pub mod env; @@ -22,7 +20,6 @@ pub mod memchr; pub mod mutex; pub mod net; pub mod os; -pub mod os_str; pub mod path; pub mod pipe; pub mod process; @@ -35,6 +32,8 @@ pub mod thread; pub mod thread_local; pub mod time; +pub use crate::sys_common::os_str_bytes as os_str; + #[cfg(not(test))] pub fn init() {} diff --git a/src/libstd/sys/redox/net/mod.rs b/src/libstd/sys/redox/net/mod.rs index a172763f61313..dbaa140ed8a0f 100644 --- a/src/libstd/sys/redox/net/mod.rs +++ b/src/libstd/sys/redox/net/mod.rs @@ -35,7 +35,7 @@ impl Iterator for LookupHost { } } -impl<'a> TryFrom<&'a str> for LookupHost { +impl TryFrom<&str> for LookupHost { type Error = io::Error; fn try_from(s: &str) -> io::Result { diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs index 5081c3de73c5a..494f943c96b53 100644 --- a/src/libstd/sys/redox/net/tcp.rs +++ b/src/libstd/sys/redox/net/tcp.rs @@ -1,5 +1,5 @@ use crate::cmp; -use crate::io::{self, Error, ErrorKind, Result, IoVec, IoVecMut}; +use crate::io::{self, Error, ErrorKind, Result, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{SocketAddr, Shutdown}; use crate::path::Path; @@ -34,22 +34,16 @@ impl TcpStream { self.0.read(buf) } - pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result { - match bufs.iter_mut().find(|b| !b.is_empty()) { - Some(buf) => self.read(buf), - None => Ok(0), - } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + io::default_read_vectored(|b| self.read(b), bufs) } pub fn write(&self, buf: &[u8]) -> Result { self.0.write(buf) } - pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result { - match bufs.iter().find(|b| !b.is_empty()) { - Some(buf) => self.write(buf), - None => Ok(0), - } + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + io::default_write_vectored(|b| self.write(b), bufs) } pub fn take_error(&self) -> Result> { diff --git a/src/libstd/sys/redox/net/udp.rs b/src/libstd/sys/redox/net/udp.rs index b1a60b1457083..274123dce4b58 100644 --- a/src/libstd/sys/redox/net/udp.rs +++ b/src/libstd/sys/redox/net/udp.rs @@ -72,6 +72,11 @@ impl UdpSocket { Ok(None) } + pub fn peer_addr(&self) -> Result { + let path = self.0.path()?; + Ok(path_to_peer_addr(path.to_str().unwrap_or(""))) + } + pub fn socket_addr(&self) -> Result { let path = self.0.path()?; Ok(path_to_local_addr(path.to_str().unwrap_or(""))) diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs index 76e43a83b7372..3ae201f698c2b 100644 --- a/src/libstd/sys/redox/os.rs +++ b/src/libstd/sys/redox/os.rs @@ -58,7 +58,7 @@ pub struct SplitPaths<'a> { fn(&'a [u8]) -> PathBuf>, } -pub fn split_paths(unparsed: &OsStr) -> SplitPaths { +pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> { fn bytes_to_path(b: &[u8]) -> PathBuf { PathBuf::from(::from_bytes(b)) } @@ -97,7 +97,7 @@ pub fn join_paths(paths: I) -> Result } impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "path segment contains separator `:`".fmt(f) } } diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs deleted file mode 100644 index 79b43458d00f3..0000000000000 --- a/src/libstd/sys/redox/os_str.rs +++ /dev/null @@ -1,180 +0,0 @@ -/// The underlying OsString/OsStr implementation on Unix systems: just -/// a `Vec`/`[u8]`. - -use crate::borrow::Cow; -use crate::fmt; -use crate::str; -use crate::mem; -use crate::rc::Rc; -use crate::sync::Arc; -use crate::sys_common::{AsInner, IntoInner}; -use crate::sys_common::bytestring::debug_fmt_bytestring; - -use core::str::lossy::Utf8Lossy; - -#[derive(Clone, Hash)] -pub struct Buf { - pub inner: Vec -} - -pub struct Slice { - pub inner: [u8] -} - -impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - debug_fmt_bytestring(&self.inner, formatter) - } -} - -impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) - } -} - -impl fmt::Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), formatter) - } -} - -impl fmt::Display for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), formatter) - } -} - -impl IntoInner> for Buf { - fn into_inner(self) -> Vec { - self.inner - } -} - -impl AsInner<[u8]> for Buf { - fn as_inner(&self) -> &[u8] { - &self.inner - } -} - - -impl Buf { - pub fn from_string(s: String) -> Buf { - Buf { inner: s.into_bytes() } - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Buf { - Buf { - inner: Vec::with_capacity(capacity) - } - } - - #[inline] - pub fn clear(&mut self) { - self.inner.clear() - } - - #[inline] - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.inner.reserve(additional) - } - - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - self.inner.reserve_exact(additional) - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.inner.shrink_to(min_capacity) - } - - pub fn as_slice(&self) -> &Slice { - unsafe { mem::transmute(&*self.inner) } - } - - pub fn into_string(self) -> Result { - String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } ) - } - - pub fn push_slice(&mut self, s: &Slice) { - self.inner.extend_from_slice(&s.inner) - } - - #[inline] - pub fn into_box(self) -> Box { - unsafe { mem::transmute(self.inner.into_boxed_slice()) } - } - - #[inline] - pub fn from_box(boxed: Box) -> Buf { - let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; - Buf { inner: inner.into_vec() } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - self.as_slice().into_arc() - } - - #[inline] - pub fn into_rc(&self) -> Rc { - self.as_slice().into_rc() - } -} - -impl Slice { - fn from_u8_slice(s: &[u8]) -> &Slice { - unsafe { mem::transmute(s) } - } - - pub fn from_str(s: &str) -> &Slice { - Slice::from_u8_slice(s.as_bytes()) - } - - pub fn to_str(&self) -> Option<&str> { - str::from_utf8(&self.inner).ok() - } - - pub fn to_string_lossy(&self) -> Cow { - String::from_utf8_lossy(&self.inner) - } - - pub fn to_owned(&self) -> Buf { - Buf { inner: self.inner.to_vec() } - } - - #[inline] - pub fn into_box(&self) -> Box { - let boxed: Box<[u8]> = self.inner.into(); - unsafe { mem::transmute(boxed) } - } - - pub fn empty_box() -> Box { - let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - let arc: Arc<[u8]> = Arc::from(&self.inner); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } - } - - #[inline] - pub fn into_rc(&self) -> Rc { - let rc: Rc<[u8]> = Rc::from(&self.inner); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } - } -} diff --git a/src/libstd/sys/redox/path.rs b/src/libstd/sys/redox/path.rs index 618d61e6fcb45..b62d6c9878211 100644 --- a/src/libstd/sys/redox/path.rs +++ b/src/libstd/sys/redox/path.rs @@ -11,7 +11,7 @@ pub fn is_verbatim_sep(b: u8) -> bool { b == b'/' } -pub fn parse_prefix(path: &OsStr) -> Option { +pub fn parse_prefix(path: &OsStr) -> Option> { if let Some(path_str) = path.to_str() { if let Some(_i) = path_str.find(':') { // FIXME: Redox specific prefix diff --git a/src/libstd/sys/redox/pipe.rs b/src/libstd/sys/redox/pipe.rs index 911ba9c3f6524..29cacb6d562f2 100644 --- a/src/libstd/sys/redox/pipe.rs +++ b/src/libstd/sys/redox/pipe.rs @@ -1,4 +1,4 @@ -use crate::io; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::sys::{cvt, syscall}; use crate::sys::fd::FileDesc; @@ -24,10 +24,18 @@ impl AnonPipe { self.0.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|buf| self.read(buf), bufs) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|buf| self.write(buf), bufs) + } + pub fn fd(&self) -> &FileDesc { &self.0 } pub fn into_fd(self) -> FileDesc { self.0 } } diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 8830cdf333ef8..2a553b2c93bd3 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -150,7 +150,7 @@ impl Command { match cvt(syscall::clone(0))? { 0 => { drop(input); - let err = self.do_exec(theirs); + let Err(err) = self.do_exec(theirs); let errno = err.raw_os_error().unwrap_or(syscall::EINVAL) as u32; let bytes = [ (errno >> 24) as u8, @@ -218,7 +218,10 @@ impl Command { } match self.setup_io(default, true) { - Ok((_, theirs)) => unsafe { self.do_exec(theirs) }, + Ok((_, theirs)) => unsafe { + let Err(e) = self.do_exec(theirs); + e + }, Err(e) => e, } } @@ -253,45 +256,38 @@ impl Command { // allocation). Instead we just close it manually. This will never // have the drop glue anyway because this code never returns (the // child will either exec() or invoke syscall::exit) - unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Error { - macro_rules! t { - ($e:expr) => (match $e { - Ok(e) => e, - Err(e) => return e, - }) - } - + unsafe fn do_exec(&mut self, stdio: ChildPipes) -> Result { if let Some(fd) = stdio.stderr.fd() { - t!(cvt(syscall::dup2(fd, 2, &[]))); - let mut flags = t!(cvt(syscall::fcntl(2, syscall::F_GETFD, 0))); + cvt(syscall::dup2(fd, 2, &[]))?; + let mut flags = cvt(syscall::fcntl(2, syscall::F_GETFD, 0))?; flags &= ! syscall::O_CLOEXEC; - t!(cvt(syscall::fcntl(2, syscall::F_SETFD, flags))); + cvt(syscall::fcntl(2, syscall::F_SETFD, flags))?; } if let Some(fd) = stdio.stdout.fd() { - t!(cvt(syscall::dup2(fd, 1, &[]))); - let mut flags = t!(cvt(syscall::fcntl(1, syscall::F_GETFD, 0))); + cvt(syscall::dup2(fd, 1, &[]))?; + let mut flags = cvt(syscall::fcntl(1, syscall::F_GETFD, 0))?; flags &= ! syscall::O_CLOEXEC; - t!(cvt(syscall::fcntl(1, syscall::F_SETFD, flags))); + cvt(syscall::fcntl(1, syscall::F_SETFD, flags))?; } if let Some(fd) = stdio.stdin.fd() { - t!(cvt(syscall::dup2(fd, 0, &[]))); - let mut flags = t!(cvt(syscall::fcntl(0, syscall::F_GETFD, 0))); + cvt(syscall::dup2(fd, 0, &[]))?; + let mut flags = cvt(syscall::fcntl(0, syscall::F_GETFD, 0))?; flags &= ! syscall::O_CLOEXEC; - t!(cvt(syscall::fcntl(0, syscall::F_SETFD, flags))); + cvt(syscall::fcntl(0, syscall::F_SETFD, flags))?; } if let Some(g) = self.gid { - t!(cvt(syscall::setregid(g as usize, g as usize))); + cvt(syscall::setregid(g as usize, g as usize))?; } if let Some(u) = self.uid { - t!(cvt(syscall::setreuid(u as usize, u as usize))); + cvt(syscall::setreuid(u as usize, u as usize))?; } if let Some(ref cwd) = self.cwd { - t!(cvt(syscall::chdir(cwd))); + cvt(syscall::chdir(cwd))?; } for callback in self.closures.iter_mut() { - t!(callback()); + callback()?; } self.env.apply(); @@ -313,9 +309,9 @@ impl Command { }; let mut file = if let Some(program) = program { - t!(File::open(program.as_os_str())) + File::open(program.as_os_str())? } else { - return io::Error::from_raw_os_error(syscall::ENOENT); + return Err(io::Error::from_raw_os_error(syscall::ENOENT)); }; // Push all the arguments @@ -327,7 +323,7 @@ impl Command { let mut shebang = [0; 2]; let mut read = 0; loop { - match t!(reader.read(&mut shebang[read..])) { + match reader.read(&mut shebang[read..])? { 0 => break, n => read += n, } @@ -338,9 +334,9 @@ impl Command { // First of all, since we'll be passing another file to // fexec(), we need to manually check that we have permission // to execute this file: - let uid = t!(cvt(syscall::getuid())); - let gid = t!(cvt(syscall::getgid())); - let meta = t!(file.metadata()); + let uid = cvt(syscall::getuid())?; + let gid = cvt(syscall::getgid())?; + let meta = file.metadata()?; let mode = if uid == meta.uid() as usize { meta.mode() >> 3*2 & 0o7 @@ -350,12 +346,12 @@ impl Command { meta.mode() & 0o7 }; if mode & 1 == 0 { - return io::Error::from_raw_os_error(syscall::EPERM); + return Err(io::Error::from_raw_os_error(syscall::EPERM)); } // Second of all, we need to actually read which interpreter it wants let mut interpreter = Vec::new(); - t!(reader.read_until(b'\n', &mut interpreter)); + reader.read_until(b'\n', &mut interpreter)?; // Pop one trailing newline, if any if interpreter.ends_with(&[b'\n']) { interpreter.pop().unwrap(); @@ -373,11 +369,11 @@ impl Command { }; if let Some(ref interpreter) = interpreter { let path: &OsStr = OsStr::from_bytes(&interpreter); - file = t!(File::open(path)); + file = File::open(path)?; args.push([interpreter.as_ptr() as usize, interpreter.len()]); } else { - t!(file.seek(SeekFrom::Start(0))); + file.seek(SeekFrom::Start(0))?; } args.push([self.program.as_ptr() as usize, self.program.len()]); @@ -396,13 +392,12 @@ impl Command { } if let Err(err) = syscall::fexec(file.as_raw_fd(), &args, &vars) { - io::Error::from_raw_os_error(err.errno as i32) + Err(io::Error::from_raw_os_error(err.errno as i32)) } else { panic!("return from exec without err"); } } - fn setup_io(&self, default: Stdio, needs_stdin: bool) -> io::Result<(StdioPipes, ChildPipes)> { let null = Stdio::Null; @@ -492,7 +487,7 @@ impl ChildStdio { } impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self.program)?; for arg in &self.args { write!(f, " {:?}", arg)?; @@ -542,7 +537,7 @@ impl From for ExitStatus { } impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(code) = self.code() { write!(f, "exit code: {}", code) } else { diff --git a/src/libstd/sys/redox/syscall/error.rs b/src/libstd/sys/redox/syscall/error.rs index f5b7bf75f305b..da84ffb042359 100644 --- a/src/libstd/sys/redox/syscall/error.rs +++ b/src/libstd/sys/redox/syscall/error.rs @@ -38,13 +38,13 @@ impl Error { } impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.text()) } } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.text()) } } diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index ae0b91b4d6c7d..9d40a7e8bb8b3 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -1,4 +1,3 @@ -use crate::boxed::FnBox; use crate::ffi::CStr; use crate::io; use crate::mem; @@ -19,7 +18,7 @@ unsafe impl Sync for Thread {} impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, p: Box) -> io::Result { + pub unsafe fn new(_stack: usize, p: Box) -> io::Result { let p = box p; let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?; diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs index 9db3e85ca9c8b..081437459cc40 100644 --- a/src/libstd/sys/redox/time.rs +++ b/src/libstd/sys/redox/time.rs @@ -137,10 +137,8 @@ impl Instant { false } - pub fn sub_instant(&self, other: &Instant) -> Duration { - self.t.sub_timespec(&other.t).unwrap_or_else(|_| { - panic!("specified instant was later than self") - }) + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + self.t.sub_timespec(&other.t).ok() } pub fn checked_add_duration(&self, other: &Duration) -> Option { @@ -153,7 +151,7 @@ impl Instant { } impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Instant") .field("tv_sec", &self.t.t.tv_sec) .field("tv_nsec", &self.t.t.tv_nsec) @@ -187,7 +185,7 @@ impl From for SystemTime { } impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SystemTime") .field("tv_sec", &self.t.t.tv_sec) .field("tv_nsec", &self.t.t.tv_nsec) diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S index c03e3869aa3c8..c35e49b1dc6ea 100644 --- a/src/libstd/sys/sgx/abi/entry.S +++ b/src/libstd/sys/sgx/abi/entry.S @@ -65,10 +65,6 @@ IMAGE_BASE: /* The size in bytes of enclacve EH_FRM_HDR section */ globvar EH_FRM_HDR_SIZE 8 -.Lreentry_panic_msg: - .asciz "Re-entered aborted enclave!" -.Lreentry_panic_msg_end: - .org .Lxsave_clear+512 .Lxsave_header: .int 0, 0 /* XSTATE_BV */ @@ -210,10 +206,8 @@ sgx_entry: /* end sgx_entry */ .Lreentry_panic: - lea .Lreentry_panic_msg(%rip),%rdi - mov $.Lreentry_panic_msg_end-.Lreentry_panic_msg,%esi orq $8,%rsp - jmp panic_msg + jmp abort_reentry /* This *MUST* be called with 6 parameters, otherwise register information */ /* might leak! */ @@ -279,10 +273,8 @@ usercall: /* The following functions need to be defined externally: ``` -// Called by entry code when it needs to panic -extern "C" fn panic_msg(msg: &'static str) -> ! { - panic!(msg) -} +// Called by entry code on re-entry after exit +extern "C" fn abort_reentry() -> !; // Called once when a TCS is first entered extern "C" fn tcs_init(secondary: bool); diff --git a/src/libstd/sys/sgx/abi/mem.rs b/src/libstd/sys/sgx/abi/mem.rs index 808f1ce3ff2c7..d9051733da24d 100644 --- a/src/libstd/sys/sgx/abi/mem.rs +++ b/src/libstd/sys/sgx/abi/mem.rs @@ -27,19 +27,23 @@ pub fn image_base() -> u64 { } /// Returns `true` if the specified memory range is in the enclave. +/// +/// `p + len` must not overflow. #[unstable(feature = "sgx_platform", issue = "56975")] pub fn is_enclave_range(p: *const u8, len: usize) -> bool { - let start=p as u64; - let end=start + (len as u64); + let start = p as u64; + let end = start + (len as u64); start >= image_base() && end <= image_base() + (unsafe { ENCLAVE_SIZE } as u64) // unsafe ok: link-time constant } /// Returns `true` if the specified memory range is in userspace. +/// +/// `p + len` must not overflow. #[unstable(feature = "sgx_platform", issue = "56975")] pub fn is_user_range(p: *const u8, len: usize) -> bool { - let start=p as u64; - let end=start + (len as u64); + let start = p as u64; + let end = start + (len as u64); end <= image_base() || start >= image_base() + (unsafe { ENCLAVE_SIZE } as u64) // unsafe ok: link-time constant } diff --git a/src/libstd/sys/sgx/abi/mod.rs b/src/libstd/sys/sgx/abi/mod.rs index 7426f7be9e961..0f107de83f062 100644 --- a/src/libstd/sys/sgx/abi/mod.rs +++ b/src/libstd/sys/sgx/abi/mod.rs @@ -1,3 +1,5 @@ +#![cfg_attr(test, allow(unused))] // RT initialization logic is not compiled for test + use core::sync::atomic::{AtomicUsize, Ordering}; use crate::io::Write; @@ -12,8 +14,10 @@ pub mod tls; #[macro_use] pub mod usercalls; +#[cfg(not(test))] global_asm!(include_str!("entry.S")); +#[cfg(not(test))] #[no_mangle] unsafe extern "C" fn tcs_init(secondary: bool) { // Be very careful when changing this code: it runs before the binary has been @@ -25,7 +29,7 @@ unsafe extern "C" fn tcs_init(secondary: bool) { static RELOC_STATE: AtomicUsize = AtomicUsize::new(UNINIT); if secondary && RELOC_STATE.load(Ordering::Relaxed) != DONE { - panic::panic_msg("Entered secondary TCS before main TCS!") + rtabort!("Entered secondary TCS before main TCS!") } // Try to atomically swap UNINIT with BUSY. The returned state can be: @@ -48,6 +52,7 @@ unsafe extern "C" fn tcs_init(secondary: bool) { // FIXME: this item should only exist if this is linked into an executable // (main function exists). If this is a library, the crate author should be // able to specify this +#[cfg(not(test))] #[no_mangle] extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) { // FIXME: how to support TLS in library mode? @@ -64,9 +69,9 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64 } // check entry is being called according to ABI - assert_eq!(p3, 0); - assert_eq!(p4, 0); - assert_eq!(p5, 0); + rtassert!(p3 == 0); + rtassert!(p4 == 0); + rtassert!(p5 == 0); unsafe { // The actual types of these arguments are `p1: *const Arg, p2: @@ -87,3 +92,9 @@ pub(super) fn exit_with_code(code: isize) -> ! { } usercalls::exit(code != 0); } + +#[cfg(not(test))] +#[no_mangle] +extern "C" fn abort_reentry() -> ! { + usercalls::exit(false) +} diff --git a/src/libstd/sys/sgx/abi/panic.rs b/src/libstd/sys/sgx/abi/panic.rs index 83411cb5b4c26..2401476716f4f 100644 --- a/src/libstd/sys/sgx/abi/panic.rs +++ b/src/libstd/sys/sgx/abi/panic.rs @@ -1,4 +1,4 @@ -use super::usercalls::{alloc::UserRef, self}; +use super::usercalls::alloc::UserRef; use crate::cmp; use crate::io::{self, Write}; use crate::mem; @@ -48,9 +48,3 @@ impl Write for SgxPanicOutput { Ok(()) } } - -#[no_mangle] -pub extern "C" fn panic_msg(msg: &str) -> ! { - let _ = SgxPanicOutput::new().map(|mut out| out.write(msg.as_bytes())); - usercalls::exit(true) -} diff --git a/src/libstd/sys/sgx/abi/reloc.rs b/src/libstd/sys/sgx/abi/reloc.rs index a39841bc36f53..6dd24c524fc30 100644 --- a/src/libstd/sys/sgx/abi/reloc.rs +++ b/src/libstd/sys/sgx/abi/reloc.rs @@ -23,7 +23,7 @@ pub fn relocate_elf_rela() { }; for rela in relas { if rela.info != (/*0 << 32 |*/ R_X86_64_RELATIVE as u64) { - panic!("Invalid relocation"); + rtabort!("Invalid relocation"); } unsafe { *mem::rel_ptr_mut::<*const ()>(rela.offset) = mem::rel_ptr(rela.addend) }; } diff --git a/src/libstd/sys/sgx/abi/thread.rs b/src/libstd/sys/sgx/abi/thread.rs index 86fe09d003520..c17fa2d00159e 100644 --- a/src/libstd/sys/sgx/abi/thread.rs +++ b/src/libstd/sys/sgx/abi/thread.rs @@ -4,6 +4,7 @@ use fortanix_sgx_abi::Tcs; /// all currently running threads in the enclave, and it is guaranteed to be /// constant for the lifetime of the thread. More specifically for SGX, there /// is a one-to-one correspondence of the ID to the address of the TCS. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn current() -> Tcs { extern "C" { fn get_tcs_addr() -> Tcs; } unsafe { get_tcs_addr() } diff --git a/src/libstd/sys/sgx/abi/tls.rs b/src/libstd/sys/sgx/abi/tls.rs index b2a812c7231da..03e08ad547d36 100644 --- a/src/libstd/sys/sgx/abi/tls.rs +++ b/src/libstd/sys/sgx/abi/tls.rs @@ -10,45 +10,16 @@ const USIZE_BITS: usize = 64; const TLS_KEYS: usize = 128; // Same as POSIX minimum const TLS_KEYS_BITSET_SIZE: usize = (TLS_KEYS + (USIZE_BITS - 1)) / USIZE_BITS; +#[cfg_attr(test, linkage = "available_externally")] +#[export_name = "_ZN16__rust_internals3std3sys3sgx3abi3tls14TLS_KEY_IN_USEE"] static TLS_KEY_IN_USE: SyncBitset = SYNC_BITSET_INIT; macro_rules! dup { ((* $($exp:tt)*) $($val:tt)*) => (dup!( ($($exp)*) $($val)* $($val)* )); (() $($val:tt)*) => ([$($val),*]) } -static TLS_DESTRUCTOR: [AtomicUsize; TLS_KEYS] = [ - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), -]; +#[cfg_attr(test, linkage = "available_externally")] +#[export_name = "_ZN16__rust_internals3std3sys3sgx3abi3tls14TLS_DESTRUCTORE"] +static TLS_DESTRUCTOR: [AtomicUsize; TLS_KEYS] = dup!((* * * * * * *) (AtomicUsize::new(0))); extern "C" { fn get_tls_ptr() -> *const u8; @@ -113,7 +84,7 @@ impl Tls { Tls { data: dup!((* * * * * * *) (Cell::new(ptr::null_mut()))) } } - pub unsafe fn activate(&self) -> ActiveTls { + pub unsafe fn activate(&self) -> ActiveTls<'_> { set_tls_ptr(self as *const Tls as _); ActiveTls { tls: self } } @@ -129,20 +100,24 @@ impl Tls { } pub fn create(dtor: Option) -> Key { - let index = TLS_KEY_IN_USE.set().expect("TLS limit exceeded"); + let index = if let Some(index) = TLS_KEY_IN_USE.set() { + index + } else { + rtabort!("TLS limit exceeded") + }; TLS_DESTRUCTOR[index].store(dtor.map_or(0, |f| f as usize), Ordering::Relaxed); Key::from_index(index) } pub fn set(key: Key, value: *mut u8) { let index = key.to_index(); - assert!(TLS_KEY_IN_USE.get(index)); + rtassert!(TLS_KEY_IN_USE.get(index)); unsafe { Self::current() }.data[index].set(value); } pub fn get(key: Key) -> *mut u8 { let index = key.to_index(); - assert!(TLS_KEY_IN_USE.get(index)); + rtassert!(TLS_KEY_IN_USE.get(index)); unsafe { Self::current() }.data[index].get() } @@ -170,7 +145,7 @@ mod sync_bitset { } /// Not atomic. - pub fn iter(&self) -> SyncBitsetIter { + pub fn iter(&self) -> SyncBitsetIter<'_> { SyncBitsetIter { iter: self.0.iter().enumerate().peekable(), elem_idx: 0, diff --git a/src/libstd/sys/sgx/abi/usercalls/alloc.rs b/src/libstd/sys/sgx/abi/usercalls/alloc.rs index b787bd1a5abac..c9ff53d0a4fd6 100644 --- a/src/libstd/sys/sgx/abi/usercalls/alloc.rs +++ b/src/libstd/sys/sgx/abi/usercalls/alloc.rs @@ -85,8 +85,10 @@ pub unsafe trait UserSafe { /// /// * the pointer is not aligned. /// * the pointer is null. + /// * the pointed-to range does not fit in the address space. /// * the pointed-to range is not in user memory. unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull { + assert!(ptr.wrapping_add(size) >= ptr); let ret = Self::from_raw_sized_unchecked(ptr, size); Self::check_ptr(ret); NonNull::new_unchecked(ret as _) @@ -188,8 +190,17 @@ impl User where T: UserSafe { // from outside as obtained by `super::alloc`. fn new_uninit_bytes(size: usize) -> Self { unsafe { - let ptr = super::alloc(size, T::align_of()).expect("User memory allocation failed"); - User(NonNull::new_userref(T::from_raw_sized(ptr as _, size))) + // Mustn't call alloc with size 0. + let ptr = if size > 0 { + rtunwrap!(Ok, super::alloc(size, T::align_of())) as _ + } else { + T::align_of() as _ // dangling pointer ok for size 0 + }; + if let Ok(v) = crate::panic::catch_unwind(|| T::from_raw_sized(ptr, size)) { + User(NonNull::new_userref(v)) + } else { + rtabort!("Got invalid pointer from alloc() usercall") + } } } @@ -259,6 +270,7 @@ impl User<[T]> where [T]: UserSafe { /// /// * The pointer is not aligned /// * The pointer is null + /// * The pointed-to range does not fit in the address space /// * The pointed-to range is not in user memory pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self { User(NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::()))) @@ -363,6 +375,7 @@ impl UserRef<[T]> where [T]: UserSafe { /// /// * The pointer is not aligned /// * The pointer is null + /// * The pointed-to range does not fit in the address space /// * The pointed-to range is not in user memory pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self { &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::()).as_ptr() as *const Self) @@ -380,6 +393,7 @@ impl UserRef<[T]> where [T]: UserSafe { /// /// * The pointer is not aligned /// * The pointer is null + /// * The pointed-to range does not fit in the address space /// * The pointed-to range is not in user memory pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self { &mut*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::()).as_ptr() as *mut Self) @@ -424,7 +438,7 @@ impl UserRef<[T]> where [T]: UserSafe { } /// Returns an iterator over the slice. - pub fn iter(&self) -> Iter + pub fn iter(&self) -> Iter<'_, T> where T: UserSafe // FIXME: should be implied by [T]: UserSafe? { unsafe { @@ -433,7 +447,7 @@ impl UserRef<[T]> where [T]: UserSafe { } /// Returns an iterator that allows modifying each value. - pub fn iter_mut(&mut self) -> IterMut + pub fn iter_mut(&mut self) -> IterMut<'_, T> where T: UserSafe // FIXME: should be implied by [T]: UserSafe? { unsafe { @@ -514,7 +528,11 @@ impl> Index for UserRef<[T]> where [T]: UserSafe, I::Ou #[inline] fn index(&self, index: I) -> &UserRef { unsafe { - UserRef::from_ptr(index.index(&*self.as_raw_ptr())) + if let Some(slice) = index.get(&*self.as_raw_ptr()) { + UserRef::from_ptr(slice) + } else { + rtabort!("index out of range for user slice"); + } } } } @@ -524,7 +542,11 @@ impl> IndexMut for UserRef<[T]> where [T]: UserSafe, I: #[inline] fn index_mut(&mut self, index: I) -> &mut UserRef { unsafe { - UserRef::from_mut_ptr(index.index_mut(&mut*self.as_raw_mut_ptr())) + if let Some(slice) = index.get_mut(&mut*self.as_raw_mut_ptr()) { + UserRef::from_mut_ptr(slice) + } else { + rtabort!("index out of range for user slice"); + } } } } @@ -535,10 +557,11 @@ impl UserRef { /// enclave memory. /// /// # Panics - /// This function panics if: + /// This function panics if, in the user `ByteBuffer`: /// - /// * The pointer in the user `ByteBuffer` is null - /// * The pointed-to range in the user `ByteBuffer` is not in user memory + /// * The pointer is null + /// * The pointed-to range does not fit in the address space + /// * The pointed-to range is not in user memory pub fn copy_user_buffer(&self) -> Vec { unsafe { let buf = self.to_enclave(); diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs index d84b6154cbebf..fca62e028deab 100644 --- a/src/libstd/sys/sgx/abi/usercalls/mod.rs +++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs @@ -1,4 +1,5 @@ -use crate::io::{Error as IoError, Result as IoResult}; +use crate::cmp; +use crate::io::{Error as IoError, Result as IoResult, IoSlice, IoSliceMut}; use crate::time::Duration; pub(crate) mod alloc; @@ -8,13 +9,27 @@ pub(crate) mod raw; use self::raw::*; /// Usercall `read`. See the ABI documentation for more information. +/// +/// This will do a single `read` usercall and scatter the read data among +/// `bufs`. To read to a single buffer, just pass a slice of length one. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn read(fd: Fd, buf: &mut [u8]) -> IoResult { +pub fn read(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> IoResult { unsafe { - let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.len()); - let len = raw::read(fd, userbuf.as_mut_ptr(), userbuf.len()).from_sgx_result()?; - userbuf[..len].copy_to_enclave(&mut buf[..len]); - Ok(len) + let total_len = bufs.iter().fold(0usize, |sum, buf| sum.saturating_add(buf.len())); + let mut userbuf = alloc::User::<[u8]>::uninitialized(total_len); + let ret_len = raw::read(fd, userbuf.as_mut_ptr(), userbuf.len()).from_sgx_result()?; + let userbuf = &userbuf[..ret_len]; + let mut index = 0; + for buf in bufs { + let end = cmp::min(index + buf.len(), userbuf.len()); + if let Some(buflen) = end.checked_sub(index) { + userbuf[index..end].copy_to_enclave(&mut buf[..buflen]); + index += buf.len(); + } else { + break + } + } + Ok(userbuf.len()) } } @@ -30,10 +45,24 @@ pub fn read_alloc(fd: Fd) -> IoResult> { } /// Usercall `write`. See the ABI documentation for more information. +/// +/// This will do a single `write` usercall and gather the written data from +/// `bufs`. To write from a single buffer, just pass a slice of length one. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn write(fd: Fd, buf: &[u8]) -> IoResult { +pub fn write(fd: Fd, bufs: &[IoSlice<'_>]) -> IoResult { unsafe { - let userbuf = alloc::User::new_from_enclave(buf); + let total_len = bufs.iter().fold(0usize, |sum, buf| sum.saturating_add(buf.len())); + let mut userbuf = alloc::User::<[u8]>::uninitialized(total_len); + let mut index = 0; + for buf in bufs { + let end = cmp::min(index + buf.len(), userbuf.len()); + if let Some(buflen) = end.checked_sub(index) { + userbuf[index..end].copy_from_enclave(&buf[..buflen]); + index += buf.len(); + } else { + break + } + } raw::write(fd, userbuf.as_ptr(), userbuf.len()).from_sgx_result() } } @@ -52,7 +81,7 @@ pub fn close(fd: Fd) { fn string_from_bytebuffer(buf: &alloc::UserRef, usercall: &str, arg: &str) -> String { String::from_utf8(buf.copy_user_buffer()) - .unwrap_or_else(|_| panic!("Usercall {}: expected {} to be valid UTF-8", usercall, arg)) + .unwrap_or_else(|_| rtabort!("Usercall {}: expected {} to be valid UTF-8", usercall, arg)) } /// Usercall `bind_stream`. See the ABI documentation for more information. @@ -176,7 +205,7 @@ fn check_os_error(err: Result) -> i32 { { err } else { - panic!("Usercall: returned invalid error value {}", err) + rtabort!("Usercall: returned invalid error value {}", err) } } diff --git a/src/libstd/sys/sgx/abi/usercalls/raw.rs b/src/libstd/sys/sgx/abi/usercalls/raw.rs index ad0b6d7b3d8ec..e4694a8827a0d 100644 --- a/src/libstd/sys/sgx/abi/usercalls/raw.rs +++ b/src/libstd/sys/sgx/abi/usercalls/raw.rs @@ -131,22 +131,22 @@ impl RegisterArgument for Option> { impl ReturnValue for ! { fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self { - panic!("Usercall {}: did not expect to be re-entered", call); + rtabort!("Usercall {}: did not expect to be re-entered", call); } } impl ReturnValue for () { - fn from_registers(call: &'static str, regs: (Register, Register)) -> Self { - assert_eq!(regs.0, 0, "Usercall {}: expected {} return value to be 0", call, "1st"); - assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd"); + fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self { + rtassert!(usercall_retval.0 == 0); + rtassert!(usercall_retval.1 == 0); () } } impl ReturnValue for T { - fn from_registers(call: &'static str, regs: (Register, Register)) -> Self { - assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd"); - T::from_register(regs.0) + fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self { + rtassert!(usercall_retval.1 == 0); + T::from_register(usercall_retval.0) } } @@ -174,8 +174,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[inline(always)] pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( - NonZeroU64::new(Usercalls::$f as Register) - .expect("Usercall number must be non-zero"), + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), RegisterArgument::into_register($n1), RegisterArgument::into_register($n2), RegisterArgument::into_register($n3), @@ -191,8 +190,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[inline(always)] pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( - NonZeroU64::new(Usercalls::$f as Register) - .expect("Usercall number must be non-zero"), + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), RegisterArgument::into_register($n1), RegisterArgument::into_register($n2), RegisterArgument::into_register($n3), @@ -208,8 +206,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[inline(always)] pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( - NonZeroU64::new(Usercalls::$f as Register) - .expect("Usercall number must be non-zero"), + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), RegisterArgument::into_register($n1), RegisterArgument::into_register($n2), 0,0, @@ -224,8 +221,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[inline(always)] pub unsafe fn $f($n1: $t1) -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( - NonZeroU64::new(Usercalls::$f as Register) - .expect("Usercall number must be non-zero"), + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), RegisterArgument::into_register($n1), 0,0,0, return_type_is_abort!($r) @@ -239,8 +235,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[inline(always)] pub unsafe fn $f() -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( - NonZeroU64::new(Usercalls::$f as Register) - .expect("Usercall number must be non-zero"), + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), 0,0,0,0, return_type_is_abort!($r) )) diff --git a/src/libstd/sys/sgx/alloc.rs b/src/libstd/sys/sgx/alloc.rs index 94dc8ec25b587..40daec758a9fc 100644 --- a/src/libstd/sys/sgx/alloc.rs +++ b/src/libstd/sys/sgx/alloc.rs @@ -4,6 +4,8 @@ use super::waitqueue::SpinMutex; // Using a SpinMutex because we never want to exit the enclave waiting for the // allocator. +#[cfg_attr(test, linkage = "available_externally")] +#[export_name = "_ZN16__rust_internals3std3sys3sgx5alloc8DLMALLOCE"] static DLMALLOC: SpinMutex = SpinMutex::new(dlmalloc::DLMALLOC_INIT); #[stable(feature = "alloc_system_type", since = "1.28.0")] @@ -28,3 +30,17 @@ unsafe impl GlobalAlloc for System { DLMALLOC.lock().realloc(ptr, layout.size(), layout.align(), new_size) } } + +// The following functions are needed by libunwind. These symbols are named +// in pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 { + crate::alloc::alloc(Layout::from_size_align_unchecked(size, align)) +} + +#[cfg(not(test))] +#[no_mangle] +pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) { + crate::alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) +} diff --git a/src/libstd/sys/sgx/args.rs b/src/libstd/sys/sgx/args.rs index b73bf9213b772..a84ab4138761e 100644 --- a/src/libstd/sys/sgx/args.rs +++ b/src/libstd/sys/sgx/args.rs @@ -5,9 +5,12 @@ use crate::sys::os_str::Buf; use crate::sys_common::FromInner; use crate::slice; +#[cfg_attr(test, linkage = "available_externally")] +#[export_name = "_ZN16__rust_internals3std3sys3sgx4args4ARGSE"] static ARGS: AtomicUsize = AtomicUsize::new(0); type ArgsStore = Vec; +#[cfg_attr(test, allow(dead_code))] pub unsafe fn init(argc: isize, argv: *const *const u8) { if argc != 0 { let args = alloc::User::<[ByteBuffer]>::from_raw_parts(argv as _, argc as _); diff --git a/src/libstd/sys/sgx/backtrace.rs b/src/libstd/sys/sgx/backtrace.rs deleted file mode 100644 index d0361574e39d6..0000000000000 --- a/src/libstd/sys/sgx/backtrace.rs +++ /dev/null @@ -1,97 +0,0 @@ -use crate::io; -use crate::error::Error; -use crate::fmt; -use crate::sys_common::backtrace::Frame; -use crate::sys::sgx::abi::mem::image_base; - -use unwind as uw; - -pub struct BacktraceContext; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl fmt::Display for UnwindError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[inline(never)] // this function call can be skipped it when tracing. -pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { - let mut cx = Context { idx: 0, frames }; - let result_unwind = - unsafe { uw::_Unwind_Backtrace(trace_fn, &mut cx as *mut Context as *mut libc::c_void) }; - // See libunwind:src/unwind/Backtrace.c for the return values. - // No, there is no doc. - let res = match result_unwind { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => Err(io::Error::new( - io::ErrorKind::Other, - UnwindError(result_unwind), - )), - }; - res -} - -extern "C" fn trace_fn( - ctx: *mut uw::_Unwind_Context, - arg: *mut libc::c_void, -) -> uw::_Unwind_Reason_Code { - let cx = unsafe { &mut *(arg as *mut Context) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - let mut ip_before_insn = 0; - let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void }; - if !ip.is_null() && ip_before_insn == 0 { - // this is a non-signaling frame, so `ip` refers to the address - // after the calling instruction. account for that. - ip = (ip as usize - 1) as *mut _; - } - - let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) }; - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} - -// To reduce TCB size in Sgx enclave, we do not want to implement resolve_symname functionality. -// Rather, we print the offset of the address here, which could be later mapped to correct function. -pub fn resolve_symname(frame: Frame, - callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - callback(Some(&format!("0x{:x}", - (frame.symbol_addr.wrapping_offset_from(image_base() as _))))) -} - -pub fn foreach_symbol_fileline(_: Frame, - _: F, - _: &BacktraceContext) -> io::Result - where F: FnMut(&[u8], u32) -> io::Result<()> -{ - Ok(false) -} diff --git a/src/libstd/sys/sgx/condvar.rs b/src/libstd/sys/sgx/condvar.rs index e9a7684f74d00..000bb19f2692a 100644 --- a/src/libstd/sys/sgx/condvar.rs +++ b/src/libstd/sys/sgx/condvar.rs @@ -33,7 +33,7 @@ impl Condvar { } pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { - panic!("timeout not supported in SGX"); + rtabort!("timeout not supported in SGX"); } #[inline] diff --git a/src/libstd/sys/sgx/ext/arch.rs b/src/libstd/sys/sgx/ext/arch.rs index 53fb371947a99..5056e388112ce 100644 --- a/src/libstd/sys/sgx/ext/arch.rs +++ b/src/libstd/sys/sgx/ext/arch.rs @@ -28,7 +28,7 @@ const ENCLU_EGETKEY: u32 = 1; #[unstable(feature = "sgx_platform", issue = "56975")] pub fn egetkey(request: &Align512<[u8; 512]>) -> Result, u32> { unsafe { - let mut out = MaybeUninit::uninitialized(); + let mut out = MaybeUninit::uninit(); let error; asm!( @@ -41,7 +41,7 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result, u32> ); match error { - 0 => Ok(out.into_initialized()), + 0 => Ok(out.assume_init()), err => Err(err), } } @@ -58,7 +58,7 @@ pub fn ereport( reportdata: &Align128<[u8; 64]>, ) -> Align512<[u8; 432]> { unsafe { - let mut report = MaybeUninit::uninitialized(); + let mut report = MaybeUninit::uninit(); asm!( "enclu" @@ -69,6 +69,6 @@ pub fn ereport( "{rdx}"(report.as_mut_ptr()) ); - report.into_initialized() + report.assume_init() } } diff --git a/src/libstd/sys/sgx/ext/ffi.rs b/src/libstd/sys/sgx/ext/ffi.rs index ad7ade9b17d81..63fc5ff2866a8 100644 --- a/src/libstd/sys/sgx/ext/ffi.rs +++ b/src/libstd/sys/sgx/ext/ffi.rs @@ -1,109 +1,38 @@ //! SGX-specific extension to the primitives in the `std::ffi` module +//! +//! # Examples +//! +//! ``` +//! use std::ffi::OsString; +//! use std::os::fortanix_sgx::ffi::OsStringExt; +//! +//! let bytes = b"foo".to_vec(); +//! +//! // OsStringExt::from_vec +//! let os_string = OsString::from_vec(bytes); +//! assert_eq!(os_string.to_str(), Some("foo")); +//! +//! // OsStringExt::into_vec +//! let bytes = os_string.into_vec(); +//! assert_eq!(bytes, b"foo"); +//! ``` +//! +//! ``` +//! use std::ffi::OsStr; +//! use std::os::fortanix_sgx::ffi::OsStrExt; +//! +//! let bytes = b"foo"; +//! +//! // OsStrExt::from_bytes +//! let os_str = OsStr::from_bytes(bytes); +//! assert_eq!(os_str.to_str(), Some("foo")); +//! +//! // OsStrExt::as_bytes +//! let bytes = os_str.as_bytes(); +//! assert_eq!(bytes, b"foo"); +//! ``` #![unstable(feature = "sgx_platform", issue = "56975")] -use crate::ffi::{OsStr, OsString}; -use crate::mem; -use crate::sys::os_str::Buf; -use crate::sys_common::{FromInner, IntoInner, AsInner}; - -/// SGX-specific extensions to [`OsString`]. -/// -/// [`OsString`]: ../../../../std/ffi/struct.OsString.html -#[unstable(feature = "sgx_platform", issue = "56975")] -pub trait OsStringExt { - /// Creates an [`OsString`] from a byte vector. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// use std::os::unix::ffi::OsStringExt; - /// - /// let bytes = b"foo".to_vec(); - /// let os_string = OsString::from_vec(bytes); - /// assert_eq!(os_string.to_str(), Some("foo")); - /// ``` - /// - /// [`OsString`]: ../../../ffi/struct.OsString.html - #[unstable(feature = "sgx_platform", issue = "56975")] - fn from_vec(vec: Vec) -> Self; - - /// Yields the underlying byte vector of this [`OsString`]. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// use std::os::unix::ffi::OsStringExt; - /// - /// let mut os_string = OsString::new(); - /// os_string.push("foo"); - /// let bytes = os_string.into_vec(); - /// assert_eq!(bytes, b"foo"); - /// ``` - /// - /// [`OsString`]: ../../../ffi/struct.OsString.html - #[unstable(feature = "sgx_platform", issue = "56975")] - fn into_vec(self) -> Vec; -} - -#[unstable(feature = "sgx_platform", issue = "56975")] -impl OsStringExt for OsString { - fn from_vec(vec: Vec) -> OsString { - FromInner::from_inner(Buf { inner: vec }) - } - fn into_vec(self) -> Vec { - self.into_inner().inner - } -} - -/// SGX-specific extensions to [`OsStr`]. -/// -/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html -#[unstable(feature = "sgx_platform", issue = "56975")] -pub trait OsStrExt { - #[unstable(feature = "sgx_platform", issue = "56975")] - /// Creates an [`OsStr`] from a byte slice. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// use std::os::unix::ffi::OsStrExt; - /// - /// let bytes = b"foo"; - /// let os_str = OsStr::from_bytes(bytes); - /// assert_eq!(os_str.to_str(), Some("foo")); - /// ``` - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html - fn from_bytes(slice: &[u8]) -> &Self; - - /// Gets the underlying byte view of the [`OsStr`] slice. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// use std::os::unix::ffi::OsStrExt; - /// - /// let mut os_str = OsStr::new("foo"); - /// let bytes = os_str.as_bytes(); - /// assert_eq!(bytes, b"foo"); - /// ``` - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html - #[unstable(feature = "sgx_platform", issue = "56975")] - fn as_bytes(&self) -> &[u8]; -} - #[unstable(feature = "sgx_platform", issue = "56975")] -impl OsStrExt for OsStr { - fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } - } - fn as_bytes(&self) -> &[u8] { - &self.as_inner().inner - } -} +pub use crate::sys_common::os_str_bytes::*; diff --git a/src/libstd/sys/sgx/fd.rs b/src/libstd/sys/sgx/fd.rs index a9924f55f12b0..a1c4af81966b2 100644 --- a/src/libstd/sys/sgx/fd.rs +++ b/src/libstd/sys/sgx/fd.rs @@ -1,6 +1,6 @@ use fortanix_sgx_abi::Fd; -use crate::io; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem; use crate::sys::{AsInner, FromInner, IntoInner}; use super::abi::usercalls; @@ -25,11 +25,19 @@ impl FileDesc { } pub fn read(&self, buf: &mut [u8]) -> io::Result { - usercalls::read(self.fd, buf) + usercalls::read(self.fd, &mut [IoSliceMut::new(buf)]) + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + usercalls::read(self.fd, bufs) } pub fn write(&self, buf: &[u8]) -> io::Result { - usercalls::write(self.fd, buf) + usercalls::write(self.fd, &[IoSlice::new(buf)]) + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + usercalls::write(self.fd, bufs) } pub fn flush(&self) -> io::Result<()> { diff --git a/src/libstd/sys/sgx/fs.rs b/src/libstd/sys/sgx/fs.rs index 485d2c87fbd2d..e9095b375fe5d 100644 --- a/src/libstd/sys/sgx/fs.rs +++ b/src/libstd/sys/sgx/fs.rs @@ -1,7 +1,7 @@ use crate::ffi::OsString; use crate::fmt; use crate::hash::{Hash, Hasher}; -use crate::io::{self, SeekFrom}; +use crate::io::{self, SeekFrom, IoSlice, IoSliceMut}; use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; use crate::sys::{unsupported, Void}; @@ -82,7 +82,7 @@ impl Eq for FilePermissions { } impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } @@ -125,13 +125,13 @@ impl Hash for FileType { } impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } @@ -200,10 +200,18 @@ impl File { match self.0 {} } + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } + pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { + match self.0 {} + } + pub fn flush(&self) -> io::Result<()> { match self.0 {} } @@ -236,7 +244,7 @@ impl DirBuilder { } impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } diff --git a/src/libstd/sys/sgx/io.rs b/src/libstd/sys/sgx/io.rs index 8b02d3fd19d30..4b423a5cbc11a 100644 --- a/src/libstd/sys/sgx/io.rs +++ b/src/libstd/sys/sgx/io.rs @@ -1,9 +1,9 @@ -pub struct IoVec<'a>(&'a [u8]); +pub struct IoSlice<'a>(&'a [u8]); -impl<'a> IoVec<'a> { +impl<'a> IoSlice<'a> { #[inline] - pub fn new(buf: &'a [u8]) -> IoVec<'a> { - IoVec(buf) + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice(buf) } #[inline] @@ -12,12 +12,12 @@ impl<'a> IoVec<'a> { } } -pub struct IoVecMut<'a>(&'a mut [u8]); +pub struct IoSliceMut<'a>(&'a mut [u8]); -impl<'a> IoVecMut<'a> { +impl<'a> IoSliceMut<'a> { #[inline] - pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { - IoVecMut(buf) + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut(buf) } #[inline] diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index 325df7688f37b..01f5536ed7a65 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -12,8 +12,6 @@ mod waitqueue; pub mod alloc; pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; pub mod cmath; pub mod condvar; pub mod env; @@ -25,7 +23,6 @@ pub mod memchr; pub mod mutex; pub mod net; pub mod os; -pub mod os_str; pub mod path; pub mod pipe; pub mod process; @@ -36,6 +33,8 @@ pub mod thread_local; pub mod time; pub mod stdio; +pub use crate::sys_common::os_str_bytes as os_str; + #[cfg(not(test))] pub fn init() { } @@ -129,6 +128,15 @@ pub unsafe fn abort_internal() -> ! { abi::usercalls::exit(true) } +// This function is needed by the panic runtime. The symbol is named in +// pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +// NB. used by both libunwind and libpanic_abort +pub unsafe extern "C" fn __rust_abort() { + abort_internal(); +} + pub fn hashmap_random_keys() -> (u64, u64) { fn rdrand64() -> u64 { unsafe { @@ -138,7 +146,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { return ret; } } - panic!("Failed to obtain random data"); + rtabort!("Failed to obtain random data"); } } (rdrand64(), rdrand64()) diff --git a/src/libstd/sys/sgx/net.rs b/src/libstd/sys/sgx/net.rs index ab8b2681393f8..f9eca9f4cb3c1 100644 --- a/src/libstd/sys/sgx/net.rs +++ b/src/libstd/sys/sgx/net.rs @@ -1,5 +1,5 @@ use crate::fmt; -use crate::io::{self, IoVec, IoVecMut}; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr, ToSocketAddrs}; use crate::time::Duration; use crate::sys::{unsupported, Void, sgx_ineffective, AsInner, FromInner, IntoInner, TryIntoInner}; @@ -41,12 +41,29 @@ impl FromInner for Socket { } } -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct TcpStream { inner: Socket, peer_addr: Option, } +impl fmt::Debug for TcpStream { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut res = f.debug_struct("TcpStream"); + + if let Some(ref addr) = self.inner.local_addr { + res.field("addr", addr); + } + + if let Some(ref peer) = self.peer_addr { + res.field("peer", peer); + } + + res.field("fd", &self.inner.inner.as_inner()) + .finish() + } +} + fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result { match result { Ok(saddr) => Ok(saddr.to_string()), @@ -75,16 +92,32 @@ impl TcpStream { Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) }) } - pub fn connect_timeout(addr: &SocketAddr, _: Duration) -> io::Result { + pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result { + if dur == Duration::default() { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } Self::connect(Ok(addr)) // FIXME: ignoring timeout } - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - sgx_ineffective(()) + pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { + match dur { + Some(dur) if dur == Duration::default() => { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } + _ => sgx_ineffective(()) + } } - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - sgx_ineffective(()) + pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { + match dur { + Some(dur) if dur == Duration::default() => { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } + _ => sgx_ineffective(()) + } } pub fn read_timeout(&self) -> io::Result> { @@ -103,24 +136,16 @@ impl TcpStream { self.inner.inner.read(buf) } - pub fn read_vectored(&self, buf: &mut [IoVecMut<'_>]) -> io::Result { - let buf = match buf.get_mut(0) { - Some(buf) => buf, - None => return Ok(0), - }; - self.read(buf) + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.inner.inner.read_vectored(bufs) } pub fn write(&self, buf: &[u8]) -> io::Result { self.inner.inner.write(buf) } - pub fn write_vectored(&self, buf: &[IoVec<'_>]) -> io::Result { - let buf = match buf.get(0) { - Some(buf) => buf, - None => return Ok(0), - }; - self.write(buf) + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + self.inner.inner.write_vectored(bufs) } pub fn peer_addr(&self) -> io::Result { @@ -182,11 +207,24 @@ impl FromInner<(Socket, Option)> for TcpStream { } } -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct TcpListener { inner: Socket, } +impl fmt::Debug for TcpListener { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut res = f.debug_struct("TcpListener"); + + if let Some(ref addr) = self.inner.local_addr { + res.field("addr", addr); + } + + res.field("fd", &self.inner.inner.as_inner()) + .finish() + } +} + impl TcpListener { pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result { let addr = io_err_to_addr(addr)?; @@ -257,6 +295,10 @@ impl UdpSocket { unsupported() } + pub fn peer_addr(&self) -> io::Result { + match self.0 {} + } + pub fn socket_addr(&self) -> io::Result { match self.0 {} } @@ -379,7 +421,7 @@ impl UdpSocket { } impl fmt::Debug for UdpSocket { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } @@ -396,7 +438,7 @@ impl error::Error for NonIpSockAddr { } impl fmt::Display for NonIpSockAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Failed to convert address to SocketAddr: {}", self.host) } } @@ -420,10 +462,10 @@ impl Iterator for LookupHost { } } -impl<'a> TryFrom<&'a str> for LookupHost { +impl TryFrom<&str> for LookupHost { type Error = io::Error; - fn try_from(v: &'a str) -> io::Result { + fn try_from(v: &str) -> io::Result { LookupHost::new(v.to_owned()) } } diff --git a/src/libstd/sys/sgx/os.rs b/src/libstd/sys/sgx/os.rs index 2725e66ce5de4..8b12c49edbaae 100644 --- a/src/libstd/sys/sgx/os.rs +++ b/src/libstd/sys/sgx/os.rs @@ -37,7 +37,7 @@ pub fn chdir(_: &path::Path) -> io::Result<()> { pub struct SplitPaths<'a>(&'a Void); -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths { +pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { panic!("unsupported") } @@ -58,7 +58,7 @@ pub fn join_paths(_paths: I) -> Result } impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "not supported in SGX yet".fmt(f) } } @@ -73,7 +73,11 @@ pub fn current_exe() -> io::Result { unsupported() } +#[cfg_attr(test, linkage = "available_externally")] +#[export_name = "_ZN16__rust_internals3std3sys3sgx2os3ENVE"] static ENV: AtomicUsize = AtomicUsize::new(0); +#[cfg_attr(test, linkage = "available_externally")] +#[export_name = "_ZN16__rust_internals3std3sys3sgx2os8ENV_INITE"] static ENV_INIT: Once = Once::new(); type EnvStore = Mutex>; diff --git a/src/libstd/sys/sgx/os_str.rs b/src/libstd/sys/sgx/os_str.rs deleted file mode 100644 index 79b43458d00f3..0000000000000 --- a/src/libstd/sys/sgx/os_str.rs +++ /dev/null @@ -1,180 +0,0 @@ -/// The underlying OsString/OsStr implementation on Unix systems: just -/// a `Vec`/`[u8]`. - -use crate::borrow::Cow; -use crate::fmt; -use crate::str; -use crate::mem; -use crate::rc::Rc; -use crate::sync::Arc; -use crate::sys_common::{AsInner, IntoInner}; -use crate::sys_common::bytestring::debug_fmt_bytestring; - -use core::str::lossy::Utf8Lossy; - -#[derive(Clone, Hash)] -pub struct Buf { - pub inner: Vec -} - -pub struct Slice { - pub inner: [u8] -} - -impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - debug_fmt_bytestring(&self.inner, formatter) - } -} - -impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) - } -} - -impl fmt::Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), formatter) - } -} - -impl fmt::Display for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), formatter) - } -} - -impl IntoInner> for Buf { - fn into_inner(self) -> Vec { - self.inner - } -} - -impl AsInner<[u8]> for Buf { - fn as_inner(&self) -> &[u8] { - &self.inner - } -} - - -impl Buf { - pub fn from_string(s: String) -> Buf { - Buf { inner: s.into_bytes() } - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Buf { - Buf { - inner: Vec::with_capacity(capacity) - } - } - - #[inline] - pub fn clear(&mut self) { - self.inner.clear() - } - - #[inline] - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.inner.reserve(additional) - } - - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - self.inner.reserve_exact(additional) - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.inner.shrink_to(min_capacity) - } - - pub fn as_slice(&self) -> &Slice { - unsafe { mem::transmute(&*self.inner) } - } - - pub fn into_string(self) -> Result { - String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } ) - } - - pub fn push_slice(&mut self, s: &Slice) { - self.inner.extend_from_slice(&s.inner) - } - - #[inline] - pub fn into_box(self) -> Box { - unsafe { mem::transmute(self.inner.into_boxed_slice()) } - } - - #[inline] - pub fn from_box(boxed: Box) -> Buf { - let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; - Buf { inner: inner.into_vec() } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - self.as_slice().into_arc() - } - - #[inline] - pub fn into_rc(&self) -> Rc { - self.as_slice().into_rc() - } -} - -impl Slice { - fn from_u8_slice(s: &[u8]) -> &Slice { - unsafe { mem::transmute(s) } - } - - pub fn from_str(s: &str) -> &Slice { - Slice::from_u8_slice(s.as_bytes()) - } - - pub fn to_str(&self) -> Option<&str> { - str::from_utf8(&self.inner).ok() - } - - pub fn to_string_lossy(&self) -> Cow { - String::from_utf8_lossy(&self.inner) - } - - pub fn to_owned(&self) -> Buf { - Buf { inner: self.inner.to_vec() } - } - - #[inline] - pub fn into_box(&self) -> Box { - let boxed: Box<[u8]> = self.inner.into(); - unsafe { mem::transmute(boxed) } - } - - pub fn empty_box() -> Box { - let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - let arc: Arc<[u8]> = Arc::from(&self.inner); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } - } - - #[inline] - pub fn into_rc(&self) -> Rc { - let rc: Rc<[u8]> = Rc::from(&self.inner); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } - } -} diff --git a/src/libstd/sys/sgx/path.rs b/src/libstd/sys/sgx/path.rs index 1115de1fbe5ba..b5fd7e3ae6d1e 100644 --- a/src/libstd/sys/sgx/path.rs +++ b/src/libstd/sys/sgx/path.rs @@ -11,7 +11,7 @@ pub fn is_verbatim_sep(b: u8) -> bool { b == b'/' } -pub fn parse_prefix(_: &OsStr) -> Option { +pub fn parse_prefix(_: &OsStr) -> Option> { None } diff --git a/src/libstd/sys/sgx/pipe.rs b/src/libstd/sys/sgx/pipe.rs index 2582b993b608e..fb14dc5910181 100644 --- a/src/libstd/sys/sgx/pipe.rs +++ b/src/libstd/sys/sgx/pipe.rs @@ -1,4 +1,4 @@ -use crate::io; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::sys::Void; pub struct AnonPipe(Void); @@ -8,18 +8,23 @@ impl AnonPipe { match self.0 {} } + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } + pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } } -pub fn read2(p1: AnonPipe, - _v1: &mut Vec, - _p2: AnonPipe, - _v2: &mut Vec) -> io::Result<()> { +pub fn read2(p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { match p1.0 {} } diff --git a/src/libstd/sys/sgx/process.rs b/src/libstd/sys/sgx/process.rs index c49daaa16320e..a02e009d95356 100644 --- a/src/libstd/sys/sgx/process.rs +++ b/src/libstd/sys/sgx/process.rs @@ -73,7 +73,7 @@ impl From for Stdio { } impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { Ok(()) } } @@ -108,13 +108,13 @@ impl Eq for ExitStatus { } impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs index 372760bbf26b4..30c47e44eef8e 100644 --- a/src/libstd/sys/sgx/rwlock.rs +++ b/src/libstd/sys/sgx/rwlock.rs @@ -1,7 +1,4 @@ -use crate::alloc::{self, Layout}; use crate::num::NonZeroUsize; -use crate::slice; -use crate::str; use super::waitqueue::{ try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable, @@ -90,8 +87,8 @@ impl RWLock { #[inline] unsafe fn __read_unlock( &self, - mut rguard: SpinMutexGuard>>, - wguard: SpinMutexGuard>, + mut rguard: SpinMutexGuard<'_, WaitVariable>>, + wguard: SpinMutexGuard<'_, WaitVariable>, ) { *rguard.lock_var_mut() = NonZeroUsize::new(rguard.lock_var().unwrap().get() - 1); if rguard.lock_var().is_some() { @@ -102,7 +99,7 @@ impl RWLock { *wguard.lock_var_mut() = true; } else { // No writers were waiting, the lock is released - assert!(rguard.queue_empty()); + rtassert!(rguard.queue_empty()); } } } @@ -117,8 +114,8 @@ impl RWLock { #[inline] unsafe fn __write_unlock( &self, - rguard: SpinMutexGuard>>, - wguard: SpinMutexGuard>, + rguard: SpinMutexGuard<'_, WaitVariable>>, + wguard: SpinMutexGuard<'_, WaitVariable>, ) { if let Err(mut wguard) = WaitQueue::notify_one(wguard) { // No writers waiting, release the write lock @@ -147,6 +144,7 @@ impl RWLock { // only used by __rust_rwlock_unlock below #[inline] + #[cfg_attr(test, allow(dead_code))] unsafe fn unlock(&self) { let rguard = self.readers.lock(); let wguard = self.writer.lock(); @@ -161,9 +159,12 @@ impl RWLock { pub unsafe fn destroy(&self) {} } +// The following functions are needed by libunwind. These symbols are named +// in pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] const EINVAL: i32 = 22; -// used by libunwind port +#[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 { if p.is_null() { @@ -173,6 +174,7 @@ pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 { return 0; } +#[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 { if p.is_null() { @@ -181,6 +183,7 @@ pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 { (*p).write(); return 0; } +#[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 { if p.is_null() { @@ -190,46 +193,15 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 { return 0; } -// the following functions are also used by the libunwind port. They're -// included here to make sure parallel codegen and LTO don't mess things up. -#[no_mangle] -pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { - if s < 0 { - return; - } - let buf = slice::from_raw_parts(m as *const u8, s as _); - if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { - eprint!("{}", s); - } -} - -#[no_mangle] -// NB. used by both libunwind and libpanic_abort -pub unsafe extern "C" fn __rust_abort() { - crate::sys::abort_internal(); -} - -#[no_mangle] -pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 { - alloc::alloc(Layout::from_size_align_unchecked(size, align)) -} - -#[no_mangle] -pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) { - alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) -} - #[cfg(test)] mod tests { - use super::*; use core::array::FixedSizeArray; - use crate::mem::MaybeUninit; - use crate::{mem, ptr}; + use crate::mem::{self, MaybeUninit}; - // The below test verifies that the bytes of initialized RWLock are the ones - // we use in libunwind. - // If they change we need to update src/UnwindRustSgx.h in libunwind. + // Verify that the bytes of initialized RWLock are the same as in + // libunwind. If they change, `src/UnwindRustSgx.h` in libunwind needs to + // be changed too. #[test] fn test_c_rwlock_initializer() { const RWLOCK_INIT: &[u8] = &[ @@ -251,11 +223,28 @@ mod tests { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ]; - let mut init = MaybeUninit::::zeroed(); - init.set(RWLock::new()); - assert_eq!( - mem::transmute::<_, [u8; 128]>(init.into_inner()).as_slice(), - RWLOCK_INIT - ); + #[inline(never)] + fn zero_stack() { + test::black_box(MaybeUninit::<[RWLock; 16]>::zeroed()); + } + + #[inline(never)] + unsafe fn rwlock_new(init: &mut MaybeUninit) { + init.write(RWLock::new()); + } + + unsafe { + // try hard to make sure that the padding/unused bytes in RWLock + // get initialized as 0. If the assertion below fails, that might + // just be an issue with the test code and not with the value of + // RWLOCK_INIT. + zero_stack(); + let mut init = MaybeUninit::::zeroed(); + rwlock_new(&mut init); + assert_eq!( + mem::transmute::<_, [u8; 128]>(init.assume_init()).as_slice(), + RWLOCK_INIT + ) + }; } } diff --git a/src/libstd/sys/sgx/stack_overflow.rs b/src/libstd/sys/sgx/stack_overflow.rs index c0e7c824615c8..e63fa2bed65d5 100644 --- a/src/libstd/sys/sgx/stack_overflow.rs +++ b/src/libstd/sys/sgx/stack_overflow.rs @@ -6,6 +6,7 @@ impl Handler { } } +#[cfg_attr(test, allow(dead_code))] pub unsafe fn init() { } diff --git a/src/libstd/sys/sgx/stdio.rs b/src/libstd/sys/sgx/stdio.rs index f2c6892bfb7fd..a575401f5f60d 100644 --- a/src/libstd/sys/sgx/stdio.rs +++ b/src/libstd/sys/sgx/stdio.rs @@ -2,6 +2,10 @@ use fortanix_sgx_abi as abi; use crate::io; use crate::sys::fd::FileDesc; +#[cfg(not(test))] +use crate::slice; +#[cfg(not(test))] +use crate::str; pub struct Stdin(()); pub struct Stdout(()); @@ -62,3 +66,17 @@ pub fn is_ebadf(err: &io::Error) -> bool { pub fn panic_output() -> Option { super::abi::panic::SgxPanicOutput::new() } + +// This function is needed by libunwind. The symbol is named in pre-link args +// for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { + if s < 0 { + return; + } + let buf = slice::from_raw_parts(m as *const u8, s as _); + if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { + eprint!("{}", s); + } +} diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs index 13569062ac184..b9f42d4ad1c59 100644 --- a/src/libstd/sys/sgx/thread.rs +++ b/src/libstd/sys/sgx/thread.rs @@ -1,4 +1,4 @@ -use crate::boxed::FnBox; +#![cfg_attr(test, allow(dead_code))] // why is this necessary? use crate::ffi::CStr; use crate::io; use crate::time::Duration; @@ -12,17 +12,16 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; mod task_queue { use crate::sync::{Mutex, MutexGuard, Once}; use crate::sync::mpsc; - use crate::boxed::FnBox; pub type JoinHandle = mpsc::Receiver<()>; pub(super) struct Task { - p: Box, + p: Box, done: mpsc::Sender<()>, } impl Task { - pub(super) fn new(p: Box) -> (Task, JoinHandle) { + pub(super) fn new(p: Box) -> (Task, JoinHandle) { let (done, recv) = mpsc::channel(); (Task { p, done }, recv) } @@ -33,7 +32,11 @@ mod task_queue { } } + #[cfg_attr(test, linkage = "available_externally")] + #[export_name = "_ZN16__rust_internals3std3sys3sgx6thread15TASK_QUEUE_INITE"] static TASK_QUEUE_INIT: Once = Once::new(); + #[cfg_attr(test, linkage = "available_externally")] + #[export_name = "_ZN16__rust_internals3std3sys3sgx6thread10TASK_QUEUEE"] static mut TASK_QUEUE: Option>> = None; pub(super) fn lock() -> MutexGuard<'static, Vec> { @@ -46,7 +49,7 @@ mod task_queue { impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, p: Box) + pub unsafe fn new(_stack: usize, p: Box) -> io::Result { let mut queue_lock = task_queue::lock(); @@ -57,17 +60,15 @@ impl Thread { } pub(super) fn entry() { - let mut guard = task_queue::lock(); - let task = guard.pop().expect("Thread started but no tasks pending"); - drop(guard); // make sure to not hold the task queue lock longer than necessary + let mut pending_tasks = task_queue::lock(); + let task = rtunwrap!(Some, pending_tasks.pop()); + drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary task.run() } pub fn yield_now() { - assert_eq!( - usercalls::wait(0, usercalls::raw::WAIT_NO).unwrap_err().kind(), - io::ErrorKind::WouldBlock - ); + let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO)); + rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock); } pub fn set_name(_name: &CStr) { @@ -75,7 +76,7 @@ impl Thread { } pub fn sleep(_dur: Duration) { - panic!("can't sleep"); // FIXME + rtabort!("can't sleep"); // FIXME } pub fn join(self) { diff --git a/src/libstd/sys/sgx/time.rs b/src/libstd/sys/sgx/time.rs index e4f789c3e3656..4659f7ba71fe0 100644 --- a/src/libstd/sys/sgx/time.rs +++ b/src/libstd/sys/sgx/time.rs @@ -14,8 +14,8 @@ impl Instant { Instant(usercalls::insecure_time()) } - pub fn sub_instant(&self, other: &Instant) -> Duration { - self.0 - other.0 + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + self.0.checked_sub(other.0) } pub fn checked_add_duration(&self, other: &Duration) -> Option { diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs index 1dbf2afbf4987..d542f9b410127 100644 --- a/src/libstd/sys/sgx/waitqueue.rs +++ b/src/libstd/sys/sgx/waitqueue.rs @@ -121,7 +121,7 @@ impl<'a, T> Drop for WaitGuard<'a, T> { NotifiedTcs::Single(tcs) => Some(tcs), NotifiedTcs::All { .. } => None }; - usercalls::send(EV_UNPARK, target_tcs).unwrap(); + rtunwrap!(Ok, usercalls::send(EV_UNPARK, target_tcs)); } } @@ -140,7 +140,8 @@ impl WaitQueue { /// until a wakeup event. /// /// This function does not return until this thread has been awoken. - pub fn wait(mut guard: SpinMutexGuard>) { + pub fn wait(mut guard: SpinMutexGuard<'_, WaitVariable>) { + // very unsafe: check requirements of UnsafeList::push unsafe { let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry { tcs: thread::current(), @@ -149,10 +150,9 @@ impl WaitQueue { let entry = guard.queue.inner.push(&mut entry); drop(guard); while !entry.lock().wake { - assert_eq!( - usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap() & EV_UNPARK, - EV_UNPARK - ); + // don't panic, this would invalidate `entry` during unwinding + let eventset = rtunwrap!(Ok, usercalls::wait(EV_UNPARK, WAIT_INDEFINITE)); + rtassert!(eventset & EV_UNPARK == EV_UNPARK); } } } @@ -162,8 +162,8 @@ impl WaitQueue { /// /// If a waiter is found, a `WaitGuard` is returned which will notify the /// waiter when it is dropped. - pub fn notify_one(mut guard: SpinMutexGuard>) - -> Result, SpinMutexGuard>> + pub fn notify_one(mut guard: SpinMutexGuard<'_, WaitVariable>) + -> Result, SpinMutexGuard<'_, WaitVariable>> { unsafe { if let Some(entry) = guard.queue.inner.pop() { @@ -186,8 +186,8 @@ impl WaitQueue { /// /// If at least one waiter is found, a `WaitGuard` is returned which will /// notify all waiters when it is dropped. - pub fn notify_all(mut guard: SpinMutexGuard>) - -> Result, SpinMutexGuard>> + pub fn notify_all(mut guard: SpinMutexGuard<'_, WaitVariable>) + -> Result, SpinMutexGuard<'_, WaitVariable>> { unsafe { let mut count = 0; @@ -269,7 +269,7 @@ mod unsafe_list { // ,-------> /---------\ next ---, // | |head_tail| | // `--- prev \---------/ <-------` - assert_eq!(self.head_tail.as_ref().prev, first); + rtassert!(self.head_tail.as_ref().prev == first); true } else { false @@ -285,7 +285,9 @@ mod unsafe_list { /// # Safety /// /// The entry must remain allocated until the entry is removed from the - /// list AND the caller who popped is done using the entry. + /// list AND the caller who popped is done using the entry. Special + /// care must be taken in the caller of `push` to ensure unwinding does + /// not destroy the stack frame containing the entry. pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry) -> &'a T { self.init(); @@ -303,6 +305,7 @@ mod unsafe_list { entry.as_mut().prev = prev_tail; entry.as_mut().next = self.head_tail; prev_tail.as_mut().next = entry; + // unwrap ok: always `Some` on non-dummy entries (*entry.as_ptr()).value.as_ref().unwrap() } @@ -333,6 +336,7 @@ mod unsafe_list { second.as_mut().prev = self.head_tail; first.as_mut().next = NonNull::dangling(); first.as_mut().prev = NonNull::dangling(); + // unwrap ok: always `Some` on non-dummy entries Some((*first.as_ptr()).value.as_ref().unwrap()) } } @@ -433,7 +437,7 @@ mod spin_mutex { } #[inline(always)] - pub fn lock(&self) -> SpinMutexGuard { + pub fn lock(&self) -> SpinMutexGuard<'_, T> { loop { match self.try_lock() { None => while self.lock.load(Ordering::Relaxed) { @@ -445,7 +449,7 @@ mod spin_mutex { } #[inline(always)] - pub fn try_lock(&self) -> Option> { + pub fn try_lock(&self) -> Option> { if !self.lock.compare_and_swap(false, true, Ordering::Acquire) { Some(SpinMutexGuard { mutex: self, @@ -498,6 +502,7 @@ mod spin_mutex { use super::*; use crate::sync::Arc; use crate::thread; + use crate::time::{SystemTime, Duration}; #[test] fn sleep() { @@ -507,7 +512,13 @@ mod spin_mutex { let t1 = thread::spawn(move || { *mutex2.lock() = 1; }); - thread::sleep_ms(50); + + // "sleep" for 50ms + // FIXME: https://github.com/fortanix/rust-sgx/issues/31 + let start = SystemTime::now(); + let max = Duration::from_millis(50); + while start.elapsed().unwrap() < max {} + assert_eq!(*guard, 0); drop(guard); t1.join().unwrap(); @@ -530,7 +541,8 @@ mod tests { let locked = wq.lock(); let t1 = thread::spawn(move || { - assert!(WaitQueue::notify_one(wq2.lock()).is_none()) + // if we obtain the lock, the main thread should be waiting + assert!(WaitQueue::notify_one(wq2.lock()).is_ok()); }); WaitQueue::wait(locked); diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs index 18de1096df2a2..3b4de56f2c9b7 100644 --- a/src/libstd/sys/unix/args.rs +++ b/src/libstd/sys/unix/args.rs @@ -49,7 +49,6 @@ impl DoubleEndedIterator for Args { target_os = "android", target_os = "freebsd", target_os = "dragonfly", - target_os = "bitrig", target_os = "netbsd", target_os = "openbsd", target_os = "solaris", diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs deleted file mode 100644 index 0887e5a4df937..0000000000000 --- a/src/libstd/sys/unix/backtrace/mod.rs +++ /dev/null @@ -1,110 +0,0 @@ -/// Backtrace support built on libgcc with some extra OS-specific support -/// -/// Some methods of getting a backtrace: -/// -/// * The backtrace() functions on unix. It turns out this doesn't work very -/// well for green threads on macOS, and the address to symbol portion of it -/// suffers problems that are described below. -/// -/// * Using libunwind. This is more difficult than it sounds because libunwind -/// isn't installed everywhere by default. It's also a bit of a hefty library, -/// so possibly not the best option. When testing, libunwind was excellent at -/// getting both accurate backtraces and accurate symbols across platforms. -/// This route was not chosen in favor of the next option, however. -/// -/// * We're already using libgcc_s for exceptions in rust (triggering thread -/// unwinding and running destructors on the stack), and it turns out that it -/// conveniently comes with a function that also gives us a backtrace. All of -/// these functions look like _Unwind_*, but it's not quite the full -/// repertoire of the libunwind API. Due to it already being in use, this was -/// the chosen route of getting a backtrace. -/// -/// After choosing libgcc_s for backtraces, the sad part is that it will only -/// give us a stack trace of instruction pointers. Thankfully these instruction -/// pointers are accurate (they work for green and native threads), but it's -/// then up to us again to figure out how to translate these addresses to -/// symbols. As with before, we have a few options. Before, that, a little bit -/// of an interlude about symbols. This is my very limited knowledge about -/// symbol tables, and this information is likely slightly wrong, but the -/// general idea should be correct. -/// -/// When talking about symbols, it's helpful to know a few things about where -/// symbols are located. Some symbols are located in the dynamic symbol table -/// of the executable which in theory means that they're available for dynamic -/// linking and lookup. Other symbols end up only in the local symbol table of -/// the file. This loosely corresponds to pub and priv functions in Rust. -/// -/// Armed with this knowledge, we know that our solution for address to symbol -/// translation will need to consult both the local and dynamic symbol tables. -/// With that in mind, here's our options of translating an address to -/// a symbol. -/// -/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr() -/// behind the scenes to translate, and this is why backtrace() was not used. -/// Conveniently, this method works fantastically on macOS. It appears dladdr() -/// uses magic to consult the local symbol table, or we're putting everything -/// in the dynamic symbol table anyway. Regardless, for macOS, this is the -/// method used for translation. It's provided by the system and easy to do.o -/// -/// Sadly, all other systems have a dladdr() implementation that does not -/// consult the local symbol table. This means that most functions are blank -/// because they don't have symbols. This means that we need another solution. -/// -/// * Use unw_get_proc_name(). This is part of the libunwind api (not the -/// libgcc_s version of the libunwind api), but involves taking a dependency -/// to libunwind. We may pursue this route in the future if we bundle -/// libunwind, but libunwind was unwieldy enough that it was not chosen at -/// this time to provide this functionality. -/// -/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a -/// semi-reasonable solution. The stdlib already knows how to spawn processes, -/// so in theory it could invoke readelf, parse the output, and consult the -/// local/dynamic symbol tables from there. This ended up not getting chosen -/// due to the craziness of the idea plus the advent of the next option. -/// -/// * Use `libbacktrace`. It turns out that this is a small library bundled in -/// the gcc repository which provides backtrace and symbol translation -/// functionality. All we really need from it is the backtrace functionality, -/// and we only really need this on everything that's not macOS, so this is the -/// chosen route for now. -/// -/// In summary, the current situation uses libgcc_s to get a trace of stack -/// pointers, and we use dladdr() or libbacktrace to translate these addresses -/// to symbols. This is a bit of a hokey implementation as-is, but it works for -/// all unix platforms we support right now, so it at least gets the job done. - -pub use self::tracing::unwind_backtrace; -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; - -// tracing impls: -mod tracing; -// symbol resolvers: -mod printing; - -#[cfg(not(target_os = "emscripten"))] -pub mod gnu { - use crate::io; - use crate::fs; - - use libc::c_char; - - #[cfg(not(any(target_os = "macos", target_os = "ios")))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) - } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - use crate::env; - use crate::os::unix::ffi::OsStrExt; - - let filename = env::current_exe()?; - let file = fs::File::open(&filename)?; - let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter() - .map(|&x| x as c_char).collect(); - filename_cstr.push(0); // Null terminate - Ok((filename_cstr, file)) - } -} - -pub struct BacktraceContext; diff --git a/src/libstd/sys/unix/backtrace/printing/dladdr.rs b/src/libstd/sys/unix/backtrace/printing/dladdr.rs deleted file mode 100644 index cf3bda640e92b..0000000000000 --- a/src/libstd/sys/unix/backtrace/printing/dladdr.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::io; -use crate::intrinsics; -use crate::ffi::CStr; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -pub fn resolve_symname(frame: Frame, - callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - unsafe { - let mut info: Dl_info = intrinsics::init(); - let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 || - info.dli_sname.is_null() { - None - } else { - CStr::from_ptr(info.dli_sname).to_str().ok() - }; - callback(symname) - } -} - -#[repr(C)] -struct Dl_info { - dli_fname: *const libc::c_char, - dli_fbase: *mut libc::c_void, - dli_sname: *const libc::c_char, - dli_saddr: *mut libc::c_void, -} - -extern { - fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int; -} diff --git a/src/libstd/sys/unix/backtrace/printing/mod.rs b/src/libstd/sys/unix/backtrace/printing/mod.rs deleted file mode 100644 index d090caede437a..0000000000000 --- a/src/libstd/sys/unix/backtrace/printing/mod.rs +++ /dev/null @@ -1,33 +0,0 @@ -mod dladdr; - -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; -use crate::io; - -#[cfg(target_os = "emscripten")] -pub use self::dladdr::resolve_symname; - -#[cfg(target_os = "emscripten")] -pub fn foreach_symbol_fileline(_: Frame, _: F, _: &BacktraceContext) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()> -{ - Ok(false) -} - -#[cfg(not(target_os = "emscripten"))] -pub use crate::sys_common::gnu::libbacktrace::foreach_symbol_fileline; - -#[cfg(not(target_os = "emscripten"))] -pub fn resolve_symname(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()> -{ - crate::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| { - if symname.is_some() { - callback(symname) - } else { - dladdr::resolve_symname(frame, callback, bc) - } - }, bc) -} diff --git a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs deleted file mode 100644 index a628d107ad6fb..0000000000000 --- a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs +++ /dev/null @@ -1,39 +0,0 @@ -/// As always - iOS on arm uses SjLj exceptions and -/// _Unwind_Backtrace is even not available there. Still, -/// backtraces could be extracted using a backtrace function, -/// which thanks god is public -/// -/// As mentioned in a huge comment block in `super::super`, backtrace -/// doesn't play well with green threads, so while it is extremely nice and -/// simple to use it should be used only on iOS devices as the only viable -/// option. - -use crate::io; -use crate::ptr; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - const FRAME_LEN: usize = 100; - assert!(FRAME_LEN >= frames.len()); - let mut raw_frames = [ptr::null_mut(); FRAME_LEN]; - let nb_frames = unsafe { - backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int) - } as usize; - for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) { - *to = Frame { - exact_position: *from as *mut u8, - symbol_addr: *from as *mut u8, - inline_context: 0, - }; - } - Ok((nb_frames as usize, BacktraceContext)) -} - -extern { - fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int; -} diff --git a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs deleted file mode 100644 index abbeca0fde6e7..0000000000000 --- a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::error::Error; -use crate::fmt; -use crate::io; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -use unwind as uw; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl fmt::Display for UnwindError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - let mut cx = Context { - idx: 0, - frames, - }; - let result_unwind = unsafe { - uw::_Unwind_Backtrace(trace_fn, - &mut cx as *mut Context - as *mut libc::c_void) - }; - // See libunwind:src/unwind/Backtrace.c for the return values. - // No, there is no doc. - match result_unwind { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => { - Err(io::Error::new(io::ErrorKind::Other, - UnwindError(result_unwind))) - } - } -} - -extern fn trace_fn(ctx: *mut uw::_Unwind_Context, - arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { - let cx = unsafe { &mut *(arg as *mut Context) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - let mut ip_before_insn = 0; - let mut ip = unsafe { - uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void - }; - if !ip.is_null() && ip_before_insn == 0 { - // this is a non-signaling frame, so `ip` refers to the address - // after the calling instruction. account for that. - ip = (ip as usize - 1) as *mut _; - } - - // dladdr() on osx gets whiny when we use FindEnclosingFunction, and - // it appears to work fine without it, so we only use - // FindEnclosingFunction on non-osx platforms. In doing so, we get a - // slightly more accurate stack trace in the process. - // - // This is often because panic involves the last instruction of a - // function being "call std::rt::begin_unwind", with no ret - // instructions after it. This means that the return instruction - // pointer points *outside* of the calling function, and by - // unwinding it we go back to the original function. - let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { - ip - } else { - unsafe { uw::_Unwind_FindEnclosingFunction(ip) } - }; - - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} diff --git a/src/libstd/sys/unix/backtrace/tracing/mod.rs b/src/libstd/sys/unix/backtrace/tracing/mod.rs deleted file mode 100644 index 11863e6454525..0000000000000 --- a/src/libstd/sys/unix/backtrace/tracing/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub use self::imp::*; - -#[cfg(not(all(target_os = "ios", target_arch = "arm")))] -#[path = "gcc_s.rs"] -mod imp; -#[cfg(all(target_os = "ios", target_arch = "arm"))] -#[path = "backtrace_fn.rs"] -mod imp; diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs index 47fb6792f08ae..4201de794b708 100644 --- a/src/libstd/sys/unix/condvar.rs +++ b/src/libstd/sys/unix/condvar.rs @@ -40,15 +40,15 @@ impl Condvar { target_os = "android", target_os = "hermit")))] pub unsafe fn init(&mut self) { - use crate::mem; - let mut attr: libc::pthread_condattr_t = mem::uninitialized(); - let r = libc::pthread_condattr_init(&mut attr); + use crate::mem::MaybeUninit; + let mut attr = MaybeUninit::::uninit(); + let r = libc::pthread_condattr_init(attr.as_mut_ptr()); assert_eq!(r, 0); - let r = libc::pthread_condattr_setclock(&mut attr, libc::CLOCK_MONOTONIC); + let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC); assert_eq!(r, 0); - let r = libc::pthread_cond_init(self.inner.get(), &attr); + let r = libc::pthread_cond_init(self.inner.get(), attr.as_ptr()); assert_eq!(r, 0); - let r = libc::pthread_condattr_destroy(&mut attr); + let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); assert_eq!(r, 0); } diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs index f9592d5c45f94..891013406a169 100644 --- a/src/libstd/sys/unix/env.rs +++ b/src/libstd/sys/unix/env.rs @@ -53,17 +53,6 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } -#[cfg(target_os = "bitrig")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "bitrig"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - #[cfg(target_os = "netbsd")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/src/libstd/sys/unix/ext/ffi.rs b/src/libstd/sys/unix/ext/ffi.rs index 0c02323981521..76b34a6b5d84a 100644 --- a/src/libstd/sys/unix/ext/ffi.rs +++ b/src/libstd/sys/unix/ext/ffi.rs @@ -1,109 +1,38 @@ //! Unix-specific extension to the primitives in the `std::ffi` module +//! +//! # Examples +//! +//! ``` +//! use std::ffi::OsString; +//! use std::os::unix::ffi::OsStringExt; +//! +//! let bytes = b"foo".to_vec(); +//! +//! // OsStringExt::from_vec +//! let os_string = OsString::from_vec(bytes); +//! assert_eq!(os_string.to_str(), Some("foo")); +//! +//! // OsStringExt::into_vec +//! let bytes = os_string.into_vec(); +//! assert_eq!(bytes, b"foo"); +//! ``` +//! +//! ``` +//! use std::ffi::OsStr; +//! use std::os::unix::ffi::OsStrExt; +//! +//! let bytes = b"foo"; +//! +//! // OsStrExt::from_bytes +//! let os_str = OsStr::from_bytes(bytes); +//! assert_eq!(os_str.to_str(), Some("foo")); +//! +//! // OsStrExt::as_bytes +//! let bytes = os_str.as_bytes(); +//! assert_eq!(bytes, b"foo"); +//! ``` #![stable(feature = "rust1", since = "1.0.0")] -use crate::ffi::{OsStr, OsString}; -use crate::mem; -use crate::sys::os_str::Buf; -use crate::sys_common::{FromInner, IntoInner, AsInner}; - -/// Unix-specific extensions to [`OsString`]. -/// -/// [`OsString`]: ../../../../std/ffi/struct.OsString.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStringExt { - /// Creates an [`OsString`] from a byte vector. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// use std::os::unix::ffi::OsStringExt; - /// - /// let bytes = b"foo".to_vec(); - /// let os_string = OsString::from_vec(bytes); - /// assert_eq!(os_string.to_str(), Some("foo")); - /// ``` - /// - /// [`OsString`]: ../../../ffi/struct.OsString.html - #[stable(feature = "rust1", since = "1.0.0")] - fn from_vec(vec: Vec) -> Self; - - /// Yields the underlying byte vector of this [`OsString`]. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// use std::os::unix::ffi::OsStringExt; - /// - /// let mut os_string = OsString::new(); - /// os_string.push("foo"); - /// let bytes = os_string.into_vec(); - /// assert_eq!(bytes, b"foo"); - /// ``` - /// - /// [`OsString`]: ../../../ffi/struct.OsString.html - #[stable(feature = "rust1", since = "1.0.0")] - fn into_vec(self) -> Vec; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStringExt for OsString { - fn from_vec(vec: Vec) -> OsString { - FromInner::from_inner(Buf { inner: vec }) - } - fn into_vec(self) -> Vec { - self.into_inner().inner - } -} - -/// Unix-specific extensions to [`OsStr`]. -/// -/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStrExt { - #[stable(feature = "rust1", since = "1.0.0")] - /// Creates an [`OsStr`] from a byte slice. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// use std::os::unix::ffi::OsStrExt; - /// - /// let bytes = b"foo"; - /// let os_str = OsStr::from_bytes(bytes); - /// assert_eq!(os_str.to_str(), Some("foo")); - /// ``` - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html - fn from_bytes(slice: &[u8]) -> &Self; - - /// Gets the underlying byte view of the [`OsStr`] slice. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// use std::os::unix::ffi::OsStrExt; - /// - /// let mut os_str = OsStr::new("foo"); - /// let bytes = os_str.as_bytes(); - /// assert_eq!(bytes, b"foo"); - /// ``` - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html - #[stable(feature = "rust1", since = "1.0.0")] - fn as_bytes(&self) -> &[u8]; -} - #[stable(feature = "rust1", since = "1.0.0")] -impl OsStrExt for OsStr { - fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } - } - fn as_bytes(&self) -> &[u8] { - &self.as_inner().inner - } -} +pub use crate::sys_common::os_str_bytes::*; diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index d9baac993c42c..c033c60cbe9e1 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -238,7 +238,7 @@ pub trait PermissionsExt { /// let metadata = f.metadata()?; /// let permissions = metadata.permissions(); /// - /// println!("permissions: {}", permissions.mode()); + /// println!("permissions: {:o}", permissions.mode()); /// Ok(()) } /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs index 1a0b3b8962bd1..6bcc59495e363 100644 --- a/src/libstd/sys/unix/ext/io.rs +++ b/src/libstd/sys/unix/ext/io.rs @@ -95,3 +95,18 @@ impl AsRawFd for io::Stdout { impl AsRawFd for io::Stderr { fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO } } + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StdinLock<'a> { + fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StdoutLock<'a> { + fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StderrLock<'a> { + fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO } +} diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 4fc79efe7ceb5..41090caee8459 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -18,7 +18,7 @@ mod libc { use crate::ascii; use crate::ffi::OsStr; use crate::fmt; -use crate::io::{self, Initializer, IoVec, IoVecMut}; +use crate::io::{self, Initializer, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{self, Shutdown}; use crate::os::unix::ffi::OsStrExt; @@ -32,18 +32,17 @@ use crate::sys_common::{self, AsInner, FromInner, IntoInner}; #[cfg(any(target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", - target_os = "haiku", target_os = "bitrig"))] + target_os = "haiku"))] use libc::MSG_NOSIGNAL; #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", - target_os = "haiku", target_os = "bitrig")))] + target_os = "haiku")))] const MSG_NOSIGNAL: libc::c_int = 0x0; -fn sun_path_offset() -> usize { +fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { // Work with an actual instance of the type since using a null pointer is UB - let addr: libc::sockaddr_un = unsafe { mem::uninitialized() }; - let base = &addr as *const _ as usize; + let base = addr as *const _ as usize; let path = &addr.sun_path as *const _ as usize; path - base } @@ -69,7 +68,7 @@ unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::sockl // null byte for pathname addresses is already there because we zeroed the // struct - let mut len = sun_path_offset() + bytes.len(); + let mut len = sun_path_offset(&addr) + bytes.len(); match bytes.get(0) { Some(&0) | None => {} Some(_) => len += 1, @@ -122,7 +121,7 @@ impl SocketAddr { if len == 0 { // When there is a datagram from unnamed unix socket // linux returns zero bytes of address - len = sun_path_offset() as libc::socklen_t; // i.e., zero-length address + len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { return Err(io::Error::new(io::ErrorKind::InvalidInput, "file descriptor did not correspond to a Unix socket")); @@ -200,7 +199,7 @@ impl SocketAddr { } fn address<'a>(&'a self) -> AddressKind<'a> { - let len = self.len as usize - sun_path_offset(); + let len = self.len as usize - sun_path_offset(&self.addr); let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses @@ -219,7 +218,7 @@ impl SocketAddr { #[stable(feature = "unix_socket", since = "1.10.0")] impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self.address() { AddressKind::Unnamed => write!(fmt, "(unnamed)"), AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), @@ -231,7 +230,7 @@ impl fmt::Debug for SocketAddr { struct AsciiEscaped<'a>(&'a [u8]); impl<'a> fmt::Display for AsciiEscaped<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "\"")?; for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { write!(fmt, "{}", byte as char)?; @@ -259,7 +258,7 @@ pub struct UnixStream(Socket); #[stable(feature = "unix_socket", since = "1.10.0")] impl fmt::Debug for UnixStream { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut builder = fmt.debug_struct("UnixStream"); builder.field("fd", self.0.as_inner()); if let Ok(addr) = self.local_addr() { @@ -551,7 +550,7 @@ impl io::Read for UnixStream { io::Read::read(&mut &*self, buf) } - fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { io::Read::read_vectored(&mut &*self, bufs) } @@ -567,7 +566,7 @@ impl<'a> io::Read for &'a UnixStream { self.0.read(buf) } - fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } @@ -583,7 +582,7 @@ impl io::Write for UnixStream { io::Write::write(&mut &*self, buf) } - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { io::Write::write_vectored(&mut &*self, bufs) } @@ -598,7 +597,7 @@ impl<'a> io::Write for &'a UnixStream { self.0.write(buf) } - fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.0.write_vectored(bufs) } @@ -719,7 +718,7 @@ pub struct UnixListener(Socket); #[stable(feature = "unix_socket", since = "1.10.0")] impl fmt::Debug for UnixListener { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut builder = fmt.debug_struct("UnixListener"); builder.field("fd", self.0.as_inner()); if let Ok(addr) = self.local_addr() { @@ -998,7 +997,7 @@ pub struct UnixDatagram(Socket); #[stable(feature = "unix_socket", since = "1.10.0")] impl fmt::Debug for UnixDatagram { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut builder = fmt.debug_struct("UnixDatagram"); builder.field("fd", self.0.as_inner()); if let Ok(addr) = self.local_addr() { @@ -1531,14 +1530,14 @@ mod test { let (mut s1, mut s2) = or_panic!(UnixStream::pair()); let len = or_panic!(s1.write_vectored( - &[IoVec::new(b"hello"), IoVec::new(b" "), IoVec::new(b"world!")], + &[IoSlice::new(b"hello"), IoSlice::new(b" "), IoSlice::new(b"world!")], )); assert_eq!(len, 12); let mut buf1 = [0; 6]; let mut buf2 = [0; 7]; let len = or_panic!(s2.read_vectored( - &mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)], + &mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)], )); assert_eq!(len, 12); assert_eq!(&buf1, b"hello "); diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs index 17478dce4fe51..c34c2e6e786ec 100644 --- a/src/libstd/sys/unix/fast_thread_local.rs +++ b/src/libstd/sys/unix/fast_thread_local.rs @@ -82,7 +82,3 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { } } } - -pub fn requires_move_before_drop() -> bool { - false -} diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index c274ad26cb1fe..6d23963e141aa 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -1,7 +1,7 @@ #![unstable(reason = "not public", issue = "0", feature = "fd")] use crate::cmp; -use crate::io::{self, Read, Initializer, IoVec, IoVecMut}; +use crate::io::{self, Read, Initializer, IoSlice, IoSliceMut}; use crate::mem; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::cvt; @@ -53,7 +53,7 @@ impl FileDesc { Ok(ret as usize) } - pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let ret = cvt(unsafe { libc::readv(self.fd, bufs.as_ptr() as *const libc::iovec, @@ -115,7 +115,7 @@ impl FileDesc { Ok(ret as usize) } - pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result { + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { let ret = cvt(unsafe { libc::writev(self.fd, bufs.as_ptr() as *const libc::iovec, diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 3b80b475a93db..cc1f0790d4334 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -2,7 +2,7 @@ use crate::os::unix::prelude::*; use crate::ffi::{CString, CStr, OsString, OsStr}; use crate::fmt; -use crate::io::{self, Error, ErrorKind, SeekFrom}; +use crate::io::{self, Error, ErrorKind, SeekFrom, IoSlice, IoSliceMut}; use crate::mem; use crate::path::{Path, PathBuf}; use crate::ptr; @@ -36,6 +36,8 @@ use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t, target_os = "fuchsia")))] use libc::{readdir_r as readdir64_r}; +pub use crate::sys_common::fs::remove_dir_all; + pub struct File(FileDesc); #[derive(Clone)] @@ -145,8 +147,7 @@ impl FileAttr { })) } - #[cfg(any(target_os = "bitrig", - target_os = "freebsd", + #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "macos", target_os = "ios"))] @@ -157,8 +158,7 @@ impl FileAttr { })) } - #[cfg(not(any(target_os = "bitrig", - target_os = "freebsd", + #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "macos", target_os = "ios")))] @@ -206,7 +206,7 @@ impl FromInner for FilePermissions { } impl fmt::Debug for ReadDir { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. // Thus the result will be e g 'ReadDir("/home")' fmt::Debug::fmt(&*self.inner.root, f) @@ -353,7 +353,6 @@ impl DirEntry { #[cfg(any(target_os = "freebsd", target_os = "openbsd", - target_os = "bitrig", target_os = "netbsd", target_os = "dragonfly"))] pub fn ino(&self) -> u64 { @@ -365,8 +364,7 @@ impl DirEntry { target_os = "netbsd", target_os = "openbsd", target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig"))] + target_os = "dragonfly"))] fn name_bytes(&self) -> &[u8] { use crate::slice; unsafe { @@ -524,8 +522,15 @@ impl File { } pub fn fsync(&self) -> io::Result<()> { - cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?; - Ok(()) + cvt_r(|| unsafe { os_fsync(self.0.raw()) })?; + return Ok(()); + + #[cfg(any(target_os = "macos", target_os = "ios"))] + unsafe fn os_fsync(fd: c_int) -> c_int { + libc::fcntl(fd, libc::F_FULLFSYNC) + } + #[cfg(not(any(target_os = "macos", target_os = "ios")))] + unsafe fn os_fsync(fd: c_int) -> c_int { libc::fsync(fd) } } pub fn datasync(&self) -> io::Result<()> { @@ -558,6 +563,10 @@ impl File { self.0.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { self.0.read_at(buf, offset) } @@ -566,6 +575,10 @@ impl File { self.0.write(buf) } + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { self.0.write_at(buf, offset) } @@ -627,7 +640,7 @@ impl FromInner for File { } impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[cfg(target_os = "linux")] fn get_path(fd: c_int) -> Option { let mut p = PathBuf::from("/proc/self/fd"); @@ -734,27 +747,6 @@ pub fn rmdir(p: &Path) -> io::Result<()> { Ok(()) } -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = lstat(path)?.file_type(); - if filetype.is_symlink() { - unlink(path) - } else { - remove_dir_all_recursive(path) - } -} - -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in readdir(path)? { - let child = child?; - if child.file_type()?.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else { - unlink(&child.path())?; - } - } - rmdir(path) -} - pub fn readlink(p: &Path) -> io::Result { let c_path = cstr(p)?; let p = c_path.as_ptr(); @@ -827,27 +819,59 @@ pub fn canonicalize(p: &Path) -> io::Result { Ok(PathBuf::from(OsString::from_vec(buf))) } -#[cfg(not(any(target_os = "linux", target_os = "android")))] -pub fn copy(from: &Path, to: &Path) -> io::Result { +fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)> { use crate::fs::File; - if !from.is_file() { - return Err(Error::new(ErrorKind::InvalidInput, - "the source path is not an existing regular file")) + + let reader = File::open(from)?; + let metadata = reader.metadata()?; + if !metadata.is_file() { + return Err(Error::new( + ErrorKind::InvalidInput, + "the source path is not an existing regular file", + )); } + Ok((reader, metadata)) +} - let mut reader = File::open(from)?; - let mut writer = File::create(to)?; - let perm = reader.metadata()?.permissions(); +fn open_to_and_set_permissions( + to: &Path, + reader_metadata: crate::fs::Metadata, +) -> io::Result<(crate::fs::File, crate::fs::Metadata)> { + use crate::fs::OpenOptions; + use crate::os::unix::fs::{OpenOptionsExt, PermissionsExt}; + + let perm = reader_metadata.permissions(); + let writer = OpenOptions::new() + // create the file with the correct mode right away + .mode(perm.mode()) + .write(true) + .create(true) + .truncate(true) + .open(to)?; + let writer_metadata = writer.metadata()?; + if writer_metadata.is_file() { + // Set the correct file permissions, in case the file already existed. + // Don't set the permissions on already existing non-files like + // pipes/FIFOs or device nodes. + writer.set_permissions(perm)?; + } + Ok((writer, writer_metadata)) +} + +#[cfg(not(any(target_os = "linux", + target_os = "android", + target_os = "macos", + target_os = "ios")))] +pub fn copy(from: &Path, to: &Path) -> io::Result { + let (mut reader, reader_metadata) = open_from(from)?; + let (mut writer, _) = open_to_and_set_permissions(to, reader_metadata)?; - let ret = io::copy(&mut reader, &mut writer)?; - writer.set_permissions(perm)?; - Ok(ret) + io::copy(&mut reader, &mut writer) } #[cfg(any(target_os = "linux", target_os = "android"))] pub fn copy(from: &Path, to: &Path) -> io::Result { use crate::cmp; - use crate::fs::File; use crate::sync::atomic::{AtomicBool, Ordering}; // Kernel prior to 4.5 don't have copy_file_range @@ -873,17 +897,9 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { ) } - if !from.is_file() { - return Err(Error::new(ErrorKind::InvalidInput, - "the source path is not an existing regular file")) - } - - let mut reader = File::open(from)?; - let mut writer = File::create(to)?; - let (perm, len) = { - let metadata = reader.metadata()?; - (metadata.permissions(), metadata.size()) - }; + let (mut reader, reader_metadata) = open_from(from)?; + let len = reader_metadata.len(); + let (mut writer, _) = open_to_and_set_permissions(to, reader_metadata)?; let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed); let mut written = 0u64; @@ -893,13 +909,14 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { let copy_result = unsafe { // We actually don't have to adjust the offsets, // because copy_file_range adjusts the file offset automatically - cvt(copy_file_range(reader.as_raw_fd(), - ptr::null_mut(), - writer.as_raw_fd(), - ptr::null_mut(), - bytes_to_copy, - 0) - ) + cvt(copy_file_range( + reader.as_raw_fd(), + ptr::null_mut(), + writer.as_raw_fd(), + ptr::null_mut(), + bytes_to_copy, + 0, + )) }; if let Err(ref copy_err) = copy_result { match copy_err.raw_os_error() { @@ -917,23 +934,152 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { Ok(ret) => written += ret as u64, Err(err) => { match err.raw_os_error() { - Some(os_err) if os_err == libc::ENOSYS - || os_err == libc::EXDEV - || os_err == libc::EPERM => { - // Try fallback io::copy if either: - // - Kernel version is < 4.5 (ENOSYS) - // - Files are mounted on different fs (EXDEV) - // - copy_file_range is disallowed, for example by seccomp (EPERM) - assert_eq!(written, 0); - let ret = io::copy(&mut reader, &mut writer)?; - writer.set_permissions(perm)?; - return Ok(ret) - }, + Some(os_err) + if os_err == libc::ENOSYS + || os_err == libc::EXDEV + || os_err == libc::EINVAL + || os_err == libc::EPERM => + { + // Try fallback io::copy if either: + // - Kernel version is < 4.5 (ENOSYS) + // - Files are mounted on different fs (EXDEV) + // - copy_file_range is disallowed, for example by seccomp (EPERM) + // - copy_file_range cannot be used with pipes or device nodes (EINVAL) + assert_eq!(written, 0); + return io::copy(&mut reader, &mut writer); + } _ => return Err(err), } } } } - writer.set_permissions(perm)?; Ok(written) } + +#[cfg(any(target_os = "macos", target_os = "ios"))] +pub fn copy(from: &Path, to: &Path) -> io::Result { + use crate::sync::atomic::{AtomicBool, Ordering}; + + const COPYFILE_ACL: u32 = 1 << 0; + const COPYFILE_STAT: u32 = 1 << 1; + const COPYFILE_XATTR: u32 = 1 << 2; + const COPYFILE_DATA: u32 = 1 << 3; + + const COPYFILE_SECURITY: u32 = COPYFILE_STAT | COPYFILE_ACL; + const COPYFILE_METADATA: u32 = COPYFILE_SECURITY | COPYFILE_XATTR; + const COPYFILE_ALL: u32 = COPYFILE_METADATA | COPYFILE_DATA; + + const COPYFILE_STATE_COPIED: u32 = 8; + + #[allow(non_camel_case_types)] + type copyfile_state_t = *mut libc::c_void; + #[allow(non_camel_case_types)] + type copyfile_flags_t = u32; + + extern "C" { + fn fcopyfile( + from: libc::c_int, + to: libc::c_int, + state: copyfile_state_t, + flags: copyfile_flags_t, + ) -> libc::c_int; + fn copyfile_state_alloc() -> copyfile_state_t; + fn copyfile_state_free(state: copyfile_state_t) -> libc::c_int; + fn copyfile_state_get( + state: copyfile_state_t, + flag: u32, + dst: *mut libc::c_void, + ) -> libc::c_int; + } + + struct FreeOnDrop(copyfile_state_t); + impl Drop for FreeOnDrop { + fn drop(&mut self) { + // The code below ensures that `FreeOnDrop` is never a null pointer + unsafe { + // `copyfile_state_free` returns -1 if the `to` or `from` files + // cannot be closed. However, this is not considerd this an + // error. + copyfile_state_free(self.0); + } + } + } + + // MacOS prior to 10.12 don't support `fclonefileat` + // We store the availability in a global to avoid unnecessary syscalls + static HAS_FCLONEFILEAT: AtomicBool = AtomicBool::new(true); + syscall! { + fn fclonefileat( + srcfd: libc::c_int, + dst_dirfd: libc::c_int, + dst: *const libc::c_char, + flags: libc::c_int + ) -> libc::c_int + } + + let (reader, reader_metadata) = open_from(from)?; + + // Opportunistically attempt to create a copy-on-write clone of `from` + // using `fclonefileat`. + if HAS_FCLONEFILEAT.load(Ordering::Relaxed) { + let to = cstr(to)?; + let clonefile_result = cvt(unsafe { + fclonefileat( + reader.as_raw_fd(), + libc::AT_FDCWD, + to.as_ptr(), + 0, + ) + }); + match clonefile_result { + Ok(_) => return Ok(reader_metadata.len()), + Err(err) => match err.raw_os_error() { + // `fclonefileat` will fail on non-APFS volumes, if the + // destination already exists, or if the source and destination + // are on different devices. In all these cases `fcopyfile` + // should succeed. + Some(libc::ENOTSUP) | Some(libc::EEXIST) | Some(libc::EXDEV) => (), + Some(libc::ENOSYS) => HAS_FCLONEFILEAT.store(false, Ordering::Relaxed), + _ => return Err(err), + } + } + } + + // Fall back to using `fcopyfile` if `fclonefileat` does not succeed. + let (writer, writer_metadata) = open_to_and_set_permissions(to, reader_metadata)?; + + // We ensure that `FreeOnDrop` never contains a null pointer so it is + // always safe to call `copyfile_state_free` + let state = unsafe { + let state = copyfile_state_alloc(); + if state.is_null() { + return Err(crate::io::Error::last_os_error()); + } + FreeOnDrop(state) + }; + + let flags = if writer_metadata.is_file() { + COPYFILE_ALL + } else { + COPYFILE_DATA + }; + + cvt(unsafe { + fcopyfile( + reader.as_raw_fd(), + writer.as_raw_fd(), + state.0, + flags, + ) + })?; + + let mut bytes_copied: libc::off_t = 0; + cvt(unsafe { + copyfile_state_get( + state.0, + COPYFILE_STATE_COPIED, + &mut bytes_copied as *mut libc::off_t as *mut libc::c_void, + ) + })?; + Ok(bytes_copied as u64) +} diff --git a/src/libstd/sys/unix/io.rs b/src/libstd/sys/unix/io.rs index eb3fa470a6525..72954ff20ef95 100644 --- a/src/libstd/sys/unix/io.rs +++ b/src/libstd/sys/unix/io.rs @@ -4,15 +4,15 @@ use crate::slice; use libc::{iovec, c_void}; #[repr(transparent)] -pub struct IoVec<'a> { +pub struct IoSlice<'a> { vec: iovec, _p: PhantomData<&'a [u8]>, } -impl<'a> IoVec<'a> { +impl<'a> IoSlice<'a> { #[inline] - pub fn new(buf: &'a [u8]) -> IoVec<'a> { - IoVec { + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice { vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() @@ -29,15 +29,15 @@ impl<'a> IoVec<'a> { } } -pub struct IoVecMut<'a> { +pub struct IoSliceMut<'a> { vec: iovec, _p: PhantomData<&'a mut [u8]>, } -impl<'a> IoVecMut<'a> { +impl<'a> IoSliceMut<'a> { #[inline] - pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { - IoVecMut { + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut { vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() diff --git a/src/libstd/sys/unix/l4re.rs b/src/libstd/sys/unix/l4re.rs index b6e8cc738946b..2c6f21aa21a3a 100644 --- a/src/libstd/sys/unix/l4re.rs +++ b/src/libstd/sys/unix/l4re.rs @@ -5,7 +5,7 @@ macro_rules! unimpl { pub mod net { #![allow(warnings)] use crate::fmt; - use crate::io::{self, IoVec, IoVecMut}; + use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::sys::fd::FileDesc; @@ -46,7 +46,7 @@ pub mod net { unimpl!(); } - pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result { + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { unimpl!(); } @@ -66,7 +66,7 @@ pub mod net { unimpl!(); } - pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result { + pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { unimpl!(); } @@ -152,7 +152,7 @@ pub mod net { unimpl!(); } - pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result { + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { unimpl!(); } @@ -160,7 +160,7 @@ pub mod net { unimpl!(); } - pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result { + pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { unimpl!(); } @@ -212,7 +212,7 @@ pub mod net { } impl fmt::Debug for TcpStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "No networking support available on L4Re") } } @@ -274,7 +274,7 @@ pub mod net { } impl fmt::Debug for TcpListener { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "No networking support available on L4Re.") } } @@ -292,6 +292,10 @@ pub mod net { pub fn into_socket(self) -> Socket { self.inner } + pub fn peer_addr(&self) -> io::Result { + unimpl!(); + } + pub fn socket_addr(&self) -> io::Result { unimpl!(); } @@ -420,7 +424,7 @@ pub mod net { } impl fmt::Debug for UdpSocket { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "No networking support on L4Re available.") } } @@ -447,10 +451,10 @@ pub mod net { unsafe impl Send for LookupHost {} - impl<'a> TryFrom<&'a str> for LookupHost { + impl TryFrom<&str> for LookupHost { type Error = io::Error; - fn try_from(_v: &'a str) -> io::Result { + fn try_from(_v: &str) -> io::Result { unimpl!(); } } @@ -463,4 +467,3 @@ pub mod net { } } } - diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index fbe3444311e5f..821623db2721e 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -5,7 +5,6 @@ use crate::io::ErrorKind; #[cfg(any(rustdoc, target_os = "linux"))] pub use crate::os::linux as platform; #[cfg(all(not(rustdoc), target_os = "android"))] pub use crate::os::android as platform; -#[cfg(all(not(rustdoc), target_os = "bitrig"))] pub use crate::os::bitrig as platform; #[cfg(all(not(rustdoc), target_os = "dragonfly"))] pub use crate::os::dragonfly as platform; #[cfg(all(not(rustdoc), target_os = "freebsd"))] pub use crate::os::freebsd as platform; #[cfg(all(not(rustdoc), target_os = "haiku"))] pub use crate::os::haiku as platform; @@ -28,8 +27,6 @@ pub mod weak; pub mod alloc; pub mod args; pub mod android; -#[cfg(feature = "backtrace")] -pub mod backtrace; pub mod cmath; pub mod condvar; pub mod env; @@ -47,7 +44,6 @@ mod l4re; #[cfg(target_os = "l4re")] pub use self::l4re::net; pub mod os; -pub mod os_str; pub mod path; pub mod pipe; pub mod process; @@ -59,6 +55,8 @@ pub mod thread_local; pub mod time; pub mod stdio; +pub use crate::sys_common::os_str_bytes as os_str; + #[cfg(not(test))] pub fn init() { // By default, some platforms will send a *signal* when an EPIPE error diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs index b6a22e1962ab8..b43af8fdcaaa1 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -1,5 +1,5 @@ use crate::cell::UnsafeCell; -use crate::mem; +use crate::mem::MaybeUninit; pub struct Mutex { inner: UnsafeCell } @@ -40,14 +40,14 @@ impl Mutex { // references, we instead create the mutex with type // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to // re-lock it from the same thread, thus avoiding undefined behavior. - let mut attr: libc::pthread_mutexattr_t = mem::uninitialized(); - let r = libc::pthread_mutexattr_init(&mut attr); + let mut attr = MaybeUninit::::uninit(); + let r = libc::pthread_mutexattr_init(attr.as_mut_ptr()); debug_assert_eq!(r, 0); - let r = libc::pthread_mutexattr_settype(&mut attr, libc::PTHREAD_MUTEX_NORMAL); + let r = libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_NORMAL); debug_assert_eq!(r, 0); - let r = libc::pthread_mutex_init(self.inner.get(), &attr); + let r = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr()); debug_assert_eq!(r, 0); - let r = libc::pthread_mutexattr_destroy(&mut attr); + let r = libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); debug_assert_eq!(r, 0); } #[inline] @@ -89,19 +89,19 @@ unsafe impl Sync for ReentrantMutex {} impl ReentrantMutex { pub unsafe fn uninitialized() -> ReentrantMutex { - ReentrantMutex { inner: mem::uninitialized() } + ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } } pub unsafe fn init(&mut self) { - let mut attr: libc::pthread_mutexattr_t = mem::uninitialized(); - let result = libc::pthread_mutexattr_init(&mut attr as *mut _); + let mut attr = MaybeUninit::::uninit(); + let result = libc::pthread_mutexattr_init(attr.as_mut_ptr()); debug_assert_eq!(result, 0); - let result = libc::pthread_mutexattr_settype(&mut attr as *mut _, + let result = libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE); debug_assert_eq!(result, 0); - let result = libc::pthread_mutex_init(self.inner.get(), &attr as *const _); + let result = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr()); debug_assert_eq!(result, 0); - let result = libc::pthread_mutexattr_destroy(&mut attr as *mut _); + let result = libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); debug_assert_eq!(result, 0); } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 7712a41ded46f..75750b5c4e588 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -1,5 +1,5 @@ use crate::ffi::CStr; -use crate::io::{self, IoVec, IoVecMut}; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{SocketAddr, Shutdown}; use crate::str; @@ -244,7 +244,7 @@ impl Socket { self.recv_with_flags(buf, MSG_PEEK) } - pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } @@ -276,7 +276,7 @@ impl Socket { self.0.write(buf) } - pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result { + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { self.0.write_vectored(bufs) } diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index e16d50d437b22..dad19eabf7db7 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -33,8 +33,7 @@ extern { target_os = "fuchsia", target_os = "l4re"), link_name = "__errno_location")] - #[cfg_attr(any(target_os = "bitrig", - target_os = "netbsd", + #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "hermit", @@ -152,7 +151,7 @@ pub struct SplitPaths<'a> { fn(&'a [u8]) -> PathBuf>, } -pub fn split_paths(unparsed: &OsStr) -> SplitPaths { +pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> { fn bytes_to_path(b: &[u8]) -> PathBuf { PathBuf::from(::from_bytes(b)) } @@ -191,7 +190,7 @@ pub fn join_paths(paths: I) -> Result } impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "path segment contains separator `:`".fmt(f) } } @@ -257,7 +256,7 @@ pub fn current_exe() -> io::Result { sysctl().or_else(|_| procfs()) } -#[cfg(any(target_os = "bitrig", target_os = "openbsd"))] +#[cfg(target_os = "openbsd")] pub fn current_exe() -> io::Result { unsafe { let mut mib = [libc::CTL_KERN, diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs deleted file mode 100644 index 79b43458d00f3..0000000000000 --- a/src/libstd/sys/unix/os_str.rs +++ /dev/null @@ -1,180 +0,0 @@ -/// The underlying OsString/OsStr implementation on Unix systems: just -/// a `Vec`/`[u8]`. - -use crate::borrow::Cow; -use crate::fmt; -use crate::str; -use crate::mem; -use crate::rc::Rc; -use crate::sync::Arc; -use crate::sys_common::{AsInner, IntoInner}; -use crate::sys_common::bytestring::debug_fmt_bytestring; - -use core::str::lossy::Utf8Lossy; - -#[derive(Clone, Hash)] -pub struct Buf { - pub inner: Vec -} - -pub struct Slice { - pub inner: [u8] -} - -impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - debug_fmt_bytestring(&self.inner, formatter) - } -} - -impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) - } -} - -impl fmt::Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), formatter) - } -} - -impl fmt::Display for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), formatter) - } -} - -impl IntoInner> for Buf { - fn into_inner(self) -> Vec { - self.inner - } -} - -impl AsInner<[u8]> for Buf { - fn as_inner(&self) -> &[u8] { - &self.inner - } -} - - -impl Buf { - pub fn from_string(s: String) -> Buf { - Buf { inner: s.into_bytes() } - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Buf { - Buf { - inner: Vec::with_capacity(capacity) - } - } - - #[inline] - pub fn clear(&mut self) { - self.inner.clear() - } - - #[inline] - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.inner.reserve(additional) - } - - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - self.inner.reserve_exact(additional) - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.inner.shrink_to(min_capacity) - } - - pub fn as_slice(&self) -> &Slice { - unsafe { mem::transmute(&*self.inner) } - } - - pub fn into_string(self) -> Result { - String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } ) - } - - pub fn push_slice(&mut self, s: &Slice) { - self.inner.extend_from_slice(&s.inner) - } - - #[inline] - pub fn into_box(self) -> Box { - unsafe { mem::transmute(self.inner.into_boxed_slice()) } - } - - #[inline] - pub fn from_box(boxed: Box) -> Buf { - let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; - Buf { inner: inner.into_vec() } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - self.as_slice().into_arc() - } - - #[inline] - pub fn into_rc(&self) -> Rc { - self.as_slice().into_rc() - } -} - -impl Slice { - fn from_u8_slice(s: &[u8]) -> &Slice { - unsafe { mem::transmute(s) } - } - - pub fn from_str(s: &str) -> &Slice { - Slice::from_u8_slice(s.as_bytes()) - } - - pub fn to_str(&self) -> Option<&str> { - str::from_utf8(&self.inner).ok() - } - - pub fn to_string_lossy(&self) -> Cow { - String::from_utf8_lossy(&self.inner) - } - - pub fn to_owned(&self) -> Buf { - Buf { inner: self.inner.to_vec() } - } - - #[inline] - pub fn into_box(&self) -> Box { - let boxed: Box<[u8]> = self.inner.into(); - unsafe { mem::transmute(boxed) } - } - - pub fn empty_box() -> Box { - let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - let arc: Arc<[u8]> = Arc::from(&self.inner); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } - } - - #[inline] - pub fn into_rc(&self) -> Rc { - let rc: Rc<[u8]> = Rc::from(&self.inner); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } - } -} diff --git a/src/libstd/sys/unix/path.rs b/src/libstd/sys/unix/path.rs index 5c062e7c97cd3..7a18395610785 100644 --- a/src/libstd/sys/unix/path.rs +++ b/src/libstd/sys/unix/path.rs @@ -11,7 +11,7 @@ pub fn is_verbatim_sep(b: u8) -> bool { b == b'/' } -pub fn parse_prefix(_: &OsStr) -> Option { +pub fn parse_prefix(_: &OsStr) -> Option> { None } diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index bc3c026adab8f..d36e94df63f8c 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -1,4 +1,4 @@ -use crate::io; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::fd::FileDesc; @@ -60,10 +60,18 @@ impl AnonPipe { self.0.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + pub fn fd(&self) -> &FileDesc { &self.0 } pub fn into_fd(self) -> FileDesc { self.0 } } diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 856d202be03f3..3ff4f194cd1a9 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -330,7 +330,7 @@ impl ChildStdio { } impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self.program)?; for arg in &self.args { write!(f, " {:?}", arg)?; @@ -380,7 +380,7 @@ impl From for ExitStatus { } impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(code) = self.code() { write!(f, "exit code: {}", code) } else { @@ -437,7 +437,7 @@ mod tests { #[cfg(target_os = "android")] unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int { - libc::memset(set as *mut _, 0, mem::size_of::()); + set.write_bytes(0u8, 1); return 0; } @@ -466,11 +466,11 @@ mod tests { // Test to make sure that a signal mask does not get inherited. let mut cmd = Command::new(OsStr::new("cat")); - let mut set: libc::sigset_t = mem::uninitialized(); - let mut old_set: libc::sigset_t = mem::uninitialized(); - t!(cvt(sigemptyset(&mut set))); - t!(cvt(sigaddset(&mut set, libc::SIGINT))); - t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set))); + let mut set = mem::MaybeUninit::::uninit(); + let mut old_set = mem::MaybeUninit::::uninit(); + t!(cvt(sigemptyset(set.as_mut_ptr()))); + t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT))); + t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), old_set.as_mut_ptr()))); cmd.stdin(Stdio::MakePipe); cmd.stdout(Stdio::MakePipe); @@ -479,7 +479,7 @@ mod tests { let stdin_write = pipes.stdin.take().unwrap(); let stdout_read = pipes.stdout.take().unwrap(); - t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &old_set, + t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut()))); t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT))); diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 220b1fd453131..be38a1334ec32 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -47,7 +47,7 @@ impl Command { match result { 0 => { drop(input); - let err = self.do_exec(theirs, envp.as_ref()); + let Err(err) = self.do_exec(theirs, envp.as_ref()); let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32; let bytes = [ (errno >> 24) as u8, @@ -123,7 +123,8 @@ impl Command { // environment lock before we try to exec. let _lock = sys::os::env_lock(); - self.do_exec(theirs, envp.as_ref()) + let Err(e) = self.do_exec(theirs, envp.as_ref()); + e } } Err(e) => e, @@ -164,29 +165,22 @@ impl Command { &mut self, stdio: ChildPipes, maybe_envp: Option<&CStringArray> - ) -> io::Error { + ) -> Result { use crate::sys::{self, cvt_r}; - macro_rules! t { - ($e:expr) => (match $e { - Ok(e) => e, - Err(e) => return e, - }) - } - if let Some(fd) = stdio.stdin.fd() { - t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO))); + cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO))?; } if let Some(fd) = stdio.stdout.fd() { - t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO))); + cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO))?; } if let Some(fd) = stdio.stderr.fd() { - t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO))); + cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO))?; } if cfg!(not(any(target_os = "l4re"))) { if let Some(u) = self.get_gid() { - t!(cvt(libc::setgid(u as gid_t))); + cvt(libc::setgid(u as gid_t))?; } if let Some(u) = self.get_uid() { // When dropping privileges from root, the `setgroups` call @@ -198,17 +192,17 @@ impl Command { // privilege dropping function. let _ = libc::setgroups(0, ptr::null()); - t!(cvt(libc::setuid(u as uid_t))); + cvt(libc::setuid(u as uid_t))?; } } if let Some(ref cwd) = *self.get_cwd() { - t!(cvt(libc::chdir(cwd.as_ptr()))); + cvt(libc::chdir(cwd.as_ptr()))?; } // emscripten has no signal support. #[cfg(not(any(target_os = "emscripten")))] { - use crate::mem; + use crate::mem::MaybeUninit; // Reset signal handling so the child process starts in a // standardized state. libstd ignores SIGPIPE, and signal-handling // libraries often set a mask. Child processes inherit ignored @@ -216,27 +210,25 @@ impl Command { // UNIX programs do not reset these things on their own, so we // need to clean things up now to avoid confusing the program // we're about to run. - let mut set: libc::sigset_t = mem::uninitialized(); + let mut set = MaybeUninit::::uninit(); if cfg!(target_os = "android") { // Implementing sigemptyset allow us to support older Android // versions. See the comment about Android and sig* functions in // process_common.rs - libc::memset(&mut set as *mut _ as *mut _, - 0, - mem::size_of::()); + set.as_mut_ptr().write_bytes(0u8, 1); } else { - t!(cvt(libc::sigemptyset(&mut set))); + cvt(libc::sigemptyset(set.as_mut_ptr()))?; } - t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, - ptr::null_mut()))); + cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), + ptr::null_mut()))?; let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL); if ret == libc::SIG_ERR { - return io::Error::last_os_error() + return Err(io::Error::last_os_error()) } } for callback in self.get_closures().iter_mut() { - t!(callback()); + callback()?; } // Although we're performing an exec here we may also return with an @@ -261,7 +253,7 @@ impl Command { } libc::execvp(self.get_argv()[0], self.get_argv().as_ptr()); - io::Error::last_os_error() + Err(io::Error::last_os_error()) } #[cfg(not(any(target_os = "macos", target_os = "freebsd", @@ -279,7 +271,7 @@ impl Command { fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) -> io::Result> { - use crate::mem; + use crate::mem::MaybeUninit; use crate::sys; if self.get_gid().is_some() || @@ -321,63 +313,63 @@ impl Command { let mut p = Process { pid: 0, status: None }; - struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t); + struct PosixSpawnFileActions(MaybeUninit); impl Drop for PosixSpawnFileActions { fn drop(&mut self) { unsafe { - libc::posix_spawn_file_actions_destroy(&mut self.0); + libc::posix_spawn_file_actions_destroy(self.0.as_mut_ptr()); } } } - struct PosixSpawnattr(libc::posix_spawnattr_t); + struct PosixSpawnattr(MaybeUninit); impl Drop for PosixSpawnattr { fn drop(&mut self) { unsafe { - libc::posix_spawnattr_destroy(&mut self.0); + libc::posix_spawnattr_destroy(self.0.as_mut_ptr()); } } } unsafe { - let mut file_actions = PosixSpawnFileActions(mem::uninitialized()); - let mut attrs = PosixSpawnattr(mem::uninitialized()); + let mut file_actions = PosixSpawnFileActions(MaybeUninit::uninit()); + let mut attrs = PosixSpawnattr(MaybeUninit::uninit()); - libc::posix_spawnattr_init(&mut attrs.0); - libc::posix_spawn_file_actions_init(&mut file_actions.0); + libc::posix_spawnattr_init(attrs.0.as_mut_ptr()); + libc::posix_spawn_file_actions_init(file_actions.0.as_mut_ptr()); if let Some(fd) = stdio.stdin.fd() { - cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, + cvt(libc::posix_spawn_file_actions_adddup2(file_actions.0.as_mut_ptr(), fd, libc::STDIN_FILENO))?; } if let Some(fd) = stdio.stdout.fd() { - cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, + cvt(libc::posix_spawn_file_actions_adddup2(file_actions.0.as_mut_ptr(), fd, libc::STDOUT_FILENO))?; } if let Some(fd) = stdio.stderr.fd() { - cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, + cvt(libc::posix_spawn_file_actions_adddup2(file_actions.0.as_mut_ptr(), fd, libc::STDERR_FILENO))?; } if let Some((f, cwd)) = addchdir { - cvt(f(&mut file_actions.0, cwd.as_ptr()))?; + cvt(f(file_actions.0.as_mut_ptr(), cwd.as_ptr()))?; } - let mut set: libc::sigset_t = mem::uninitialized(); - cvt(libc::sigemptyset(&mut set))?; - cvt(libc::posix_spawnattr_setsigmask(&mut attrs.0, - &set))?; - cvt(libc::sigaddset(&mut set, libc::SIGPIPE))?; - cvt(libc::posix_spawnattr_setsigdefault(&mut attrs.0, - &set))?; + let mut set = MaybeUninit::::uninit(); + cvt(libc::sigemptyset(set.as_mut_ptr()))?; + cvt(libc::posix_spawnattr_setsigmask(attrs.0.as_mut_ptr(), + set.as_ptr()))?; + cvt(libc::sigaddset(set.as_mut_ptr(), libc::SIGPIPE))?; + cvt(libc::posix_spawnattr_setsigdefault(attrs.0.as_mut_ptr(), + set.as_ptr()))?; let flags = libc::POSIX_SPAWN_SETSIGDEF | libc::POSIX_SPAWN_SETSIGMASK; - cvt(libc::posix_spawnattr_setflags(&mut attrs.0, flags as _))?; + cvt(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?; // Make sure we synchronize access to the global `environ` resource let _env_lock = sys::os::env_lock(); @@ -386,8 +378,8 @@ impl Command { let ret = libc::posix_spawnp( &mut p.pid, self.get_argv()[0], - &file_actions.0, - &attrs.0, + file_actions.0.as_ptr(), + attrs.0.as_ptr(), self.get_argv().as_ptr() as *const _, envp as *const _, ); diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index 122f22b37a26b..71c62461ee9cb 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -47,7 +47,12 @@ mod imp { let err = errno() as libc::c_int; if err == libc::EINTR { continue; - } else if err == libc::ENOSYS { + } else if err == libc::ENOSYS || err == libc::EPERM { + // Fall back to reading /dev/urandom if `getrandom` is not + // supported on the current kernel. + // + // Also fall back in case it is disabled by something like + // seccomp or inside of virtual machines. GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed); return false; } else if err == libc::EAGAIN { @@ -99,6 +104,13 @@ mod imp { } } +// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with +// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded +// from `/dev/random` and which runs on its own thread accessed via GCD. +// This seems needlessly heavyweight for the purposes of generating two u64s +// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is +// only used on iOS where direct access to `/dev/urandom` is blocked by the +// sandbox. #[cfg(target_os = "ios")] mod imp { use crate::io; diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 8c60bddc23839..fe1095fa0c2f6 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -25,7 +25,6 @@ impl Drop for Handler { #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "bitrig", target_os = "dragonfly", target_os = "freebsd", target_os = "solaris", @@ -139,7 +138,7 @@ mod imp { #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "bitrig", + target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", target_os = "solaris"))] @@ -147,8 +146,7 @@ mod imp { libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ } } - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(target_os = "dragonfly")] unsafe fn get_stack() -> libc::stack_t { libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ } } @@ -185,7 +183,6 @@ mod imp { #[cfg(not(any(target_os = "linux", target_os = "macos", - target_os = "bitrig", target_os = "dragonfly", target_os = "freebsd", target_os = "solaris", diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index 35f163bbdb10f..f9b017df24088 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -1,5 +1,6 @@ -use crate::io; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::sys::fd::FileDesc; +use crate::mem::ManuallyDrop; pub struct Stdin(()); pub struct Stdout(()); @@ -11,10 +12,11 @@ impl Stdin { impl io::Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { - let fd = FileDesc::new(libc::STDIN_FILENO); - let ret = fd.read(buf); - fd.into_raw(); // do not close this FD - ret + ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read(buf) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read_vectored(bufs) } } @@ -24,10 +26,11 @@ impl Stdout { impl io::Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { - let fd = FileDesc::new(libc::STDOUT_FILENO); - let ret = fd.write(buf); - fd.into_raw(); // do not close this FD - ret + ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write_vectored(bufs) } fn flush(&mut self) -> io::Result<()> { @@ -41,10 +44,11 @@ impl Stderr { impl io::Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { - let fd = FileDesc::new(libc::STDERR_FILENO); - let ret = fd.write(buf); - fd.into_raw(); // do not close this FD - ret + ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write_vectored(bufs) } fn flush(&mut self) -> io::Result<()> { diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index feb15e8f585ab..f4a1783ce8903 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -1,4 +1,3 @@ -use crate::boxed::FnBox; use crate::cmp; use crate::ffi::CStr; use crate::io; @@ -39,7 +38,7 @@ unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t, impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, p: Box) + pub unsafe fn new(stack: usize, p: Box) -> io::Result { let p = box p; let mut native: libc::pthread_t = mem::zeroed(); @@ -100,7 +99,6 @@ impl Thread { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", - target_os = "bitrig", target_os = "openbsd"))] pub fn set_name(name: &CStr) { unsafe { @@ -190,7 +188,6 @@ impl Drop for Thread { #[cfg(all(not(all(target_os = "linux", not(target_env = "musl"))), not(target_os = "freebsd"), not(target_os = "macos"), - not(target_os = "bitrig"), not(all(target_os = "netbsd", not(target_vendor = "rumprun"))), not(target_os = "openbsd"), not(target_os = "solaris")))] @@ -206,7 +203,6 @@ pub mod guard { #[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "freebsd", target_os = "macos", - target_os = "bitrig", all(target_os = "netbsd", not(target_vendor = "rumprun")), target_os = "openbsd", target_os = "solaris"))] @@ -237,16 +233,15 @@ pub mod guard { Some(stackaddr as *mut libc::c_void) } - #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] + #[cfg(target_os = "openbsd")] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { let mut current_stack: libc::stack_t = crate::mem::zeroed(); assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), &mut current_stack), 0); - let extra = if cfg!(target_os = "bitrig") {3} else {1} * PAGE_SIZE; let stackaddr = if libc::pthread_main_np() == 1 { // main thread - current_stack.ss_sp as usize - current_stack.ss_size + extra + current_stack.ss_sp as usize - current_stack.ss_size + PAGE_SIZE } else { // new thread current_stack.ss_sp as usize - current_stack.ss_size @@ -344,7 +339,6 @@ pub mod guard { } #[cfg(any(target_os = "macos", - target_os = "bitrig", target_os = "openbsd", target_os = "solaris"))] pub unsafe fn current() -> Option { diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index cbb0615911adf..e21c32cd91b1e 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -114,7 +114,8 @@ impl Hash for Timespec { #[cfg(any(target_os = "macos", target_os = "ios"))] mod inner { use crate::fmt; - use crate::sync::Once; + use crate::mem; + use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use crate::sys::cvt; use crate::sys_common::mul_div_u64; use crate::time::Duration; @@ -149,12 +150,11 @@ mod inner { true } - pub fn sub_instant(&self, other: &Instant) -> Duration { + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + let diff = self.t.checked_sub(other.t)?; let info = info(); - let diff = self.t.checked_sub(other.t) - .expect("second instant is later than self"); let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64); - Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32) + Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32)) } pub fn checked_add_duration(&self, other: &Duration) -> Option { @@ -214,7 +214,7 @@ mod inner { } impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SystemTime") .field("tv_sec", &self.t.t.tv_sec) .field("tv_nsec", &self.t.t.tv_nsec) @@ -230,18 +230,30 @@ mod inner { Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64)) } - fn info() -> &'static libc::mach_timebase_info { + fn info() -> libc::mach_timebase_info { static mut INFO: libc::mach_timebase_info = libc::mach_timebase_info { numer: 0, denom: 0, }; - static ONCE: Once = Once::new(); + static STATE: AtomicUsize = AtomicUsize::new(0); unsafe { - ONCE.call_once(|| { - libc::mach_timebase_info(&mut INFO); - }); - &INFO + // If a previous thread has filled in this global state, use that. + if STATE.load(SeqCst) == 2 { + return INFO; + } + + // ... otherwise learn for ourselves ... + let mut info = mem::zeroed(); + libc::mach_timebase_info(&mut info); + + // ... and attempt to be the one thread that stores it globally for + // all other threads + if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() { + INFO = info; + STATE.store(2, SeqCst); + } + return info; } } } @@ -285,10 +297,8 @@ mod inner { false // last clause, used so `||` is always trailing above } - pub fn sub_instant(&self, other: &Instant) -> Duration { - self.t.sub_timespec(&other.t).unwrap_or_else(|_| { - panic!("specified instant was later than self") - }) + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + self.t.sub_timespec(&other.t).ok() } pub fn checked_add_duration(&self, other: &Duration) -> Option { @@ -301,7 +311,7 @@ mod inner { } impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Instant") .field("tv_sec", &self.t.t.tv_sec) .field("tv_nsec", &self.t.t.tv_nsec) @@ -335,7 +345,7 @@ mod inner { } impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SystemTime") .field("tv_sec", &self.t.t.tv_sec) .field("tv_nsec", &self.t.t.tv_nsec) diff --git a/src/libstd/sys/wasi/alloc.rs b/src/libstd/sys/wasi/alloc.rs new file mode 100644 index 0000000000000..c8529937bbde0 --- /dev/null +++ b/src/libstd/sys/wasi/alloc.rs @@ -0,0 +1,43 @@ +use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::ptr; +use crate::sys_common::alloc::{MIN_ALIGN, realloc_fallback}; +use libc; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + libc::malloc(layout.size()) as *mut u8 + } else { + libc::aligned_alloc(layout.size(), layout.align()) as *mut u8 + } + } + + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + libc::calloc(layout.size(), 1) as *mut u8 + } else { + let ptr = self.alloc(layout.clone()); + if !ptr.is_null() { + ptr::write_bytes(ptr, 0, layout.size()); + } + ptr + } + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { + libc::free(ptr as *mut libc::c_void) + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= new_size { + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 + } else { + realloc_fallback(self, ptr, layout, new_size) + } + } +} diff --git a/src/libstd/sys/wasi/args.rs b/src/libstd/sys/wasi/args.rs new file mode 100644 index 0000000000000..8b4b354d9fc20 --- /dev/null +++ b/src/libstd/sys/wasi/args.rs @@ -0,0 +1,76 @@ +use crate::ffi::CStr; +use crate::io; +use crate::sys::cvt_wasi; +use crate::ffi::OsString; +use crate::marker::PhantomData; +use crate::os::wasi::ffi::OsStringExt; +use crate::vec; + +pub unsafe fn init(_argc: isize, _argv: *const *const u8) { +} + +pub unsafe fn cleanup() { +} + +pub struct Args { + iter: vec::IntoIter, + _dont_send_or_sync_me: PhantomData<*mut ()>, +} + +/// Returns the command line arguments +pub fn args() -> Args { + maybe_args().unwrap_or_else(|_| { + Args { + iter: Vec::new().into_iter(), + _dont_send_or_sync_me: PhantomData + } + }) +} + +fn maybe_args() -> io::Result { + unsafe { + let (mut argc, mut argv_buf_size) = (0, 0); + cvt_wasi(libc::__wasi_args_sizes_get(&mut argc, &mut argv_buf_size))?; + + let mut argc = vec![core::ptr::null_mut::(); argc]; + let mut argv_buf = vec![0; argv_buf_size]; + cvt_wasi(libc::__wasi_args_get(argc.as_mut_ptr(), argv_buf.as_mut_ptr()))?; + + let args = argc.into_iter() + .map(|ptr| CStr::from_ptr(ptr).to_bytes().to_vec()) + .map(|bytes| OsString::from_vec(bytes)) + .collect::>(); + Ok(Args { + iter: args.into_iter(), + _dont_send_or_sync_me: PhantomData, + }) + } +} + +impl Args { + pub fn inner_debug(&self) -> &[OsString] { + self.iter.as_slice() + } +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} diff --git a/src/libstd/sys/wasi/env.rs b/src/libstd/sys/wasi/env.rs new file mode 100644 index 0000000000000..730e356d7fe95 --- /dev/null +++ b/src/libstd/sys/wasi/env.rs @@ -0,0 +1,9 @@ +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = ""; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".wasm"; + pub const DLL_EXTENSION: &str = "wasm"; + pub const EXE_SUFFIX: &str = ".wasm"; + pub const EXE_EXTENSION: &str = "wasm"; +} diff --git a/src/libstd/sys/wasi/ext/ffi.rs b/src/libstd/sys/wasi/ext/ffi.rs new file mode 100644 index 0000000000000..f71f316d1ba10 --- /dev/null +++ b/src/libstd/sys/wasi/ext/ffi.rs @@ -0,0 +1,6 @@ +//! WASI-specific extension to the primitives in the `std::ffi` module + +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::sys_common::os_str_bytes::*; diff --git a/src/libstd/sys/wasi/ext/fs.rs b/src/libstd/sys/wasi/ext/fs.rs new file mode 100644 index 0000000000000..0ec4122f385da --- /dev/null +++ b/src/libstd/sys/wasi/ext/fs.rs @@ -0,0 +1,412 @@ +//! WASI-specific extensions to primitives in the `std::fs` module. + +#![unstable(feature = "wasi_ext", issue = "0")] + +use crate::fs::{self, File, Metadata, OpenOptions}; +use crate::io::{self, IoSlice, IoSliceMut}; +use crate::os::wasi::ffi::OsStrExt; +use crate::path::{Path, PathBuf}; +use crate::sys_common::{AsInner, AsInnerMut, FromInner}; + +/// WASI-specific extensions to [`File`]. +/// +/// [`File`]: ../../../../std/fs/struct.File.html +pub trait FileExt { + /// Reads a number of bytes starting from a given offset. + /// + /// Returns the number of bytes read. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// Note that similar to [`File::read_vectored`], it is not an error to + /// return with a short read. + /// + /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read_vectored + fn read_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result; + + /// Writes a number of bytes starting from a given offset. + /// + /// Returns the number of bytes written. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// When writing beyond the end of the file, the file is appropriately + /// extended and the intermediate bytes are initialized with the value 0. + /// + /// Note that similar to [`File::write_vectored`], it is not an error to return a + /// short write. + /// + /// [`File::write`]: ../../../../std/fs/struct.File.html#method.write_vectored + fn write_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result; + + /// Returns the current position within the file. + /// + /// This corresponds to the `__wasi_fd_tell` syscall and is similar to + /// `seek` where you offset 0 bytes from the current position. + fn tell(&self) -> io::Result; + + /// Adjust the flags associated with this file. + /// + /// This corresponds to the `__wasi_fd_fdstat_set_flags` syscall. + fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>; + + /// Adjust the rights associated with this file. + /// + /// This corresponds to the `__wasi_fd_fdstat_set_rights` syscall. + fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>; + + /// Provide file advisory information on a file descriptor. + /// + /// This corresponds to the `__wasi_fd_advise` syscall. + fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>; + + /// Force the allocation of space in a file. + /// + /// This corresponds to the `__wasi_fd_allocate` syscall. + fn allocate(&self, offset: u64, len: u64) -> io::Result<()>; + + /// Create a directory. + /// + /// This corresponds to the `__wasi_path_create_directory` syscall. + fn create_directory>(&self, dir: P) -> io::Result<()>; + + /// Read the contents of a symbolic link. + /// + /// This corresponds to the `__wasi_path_readlink` syscall. + fn read_link>(&self, path: P) -> io::Result; + + /// Return the attributes of a file or directory. + /// + /// This corresponds to the `__wasi_path_filestat_get` syscall. + fn metadata_at>(&self, lookup_flags: u32, path: P) -> io::Result; + + /// Unlink a file. + /// + /// This corresponds to the `__wasi_path_unlink_file` syscall. + fn remove_file>(&self, path: P) -> io::Result<()>; + + /// Remove a directory. + /// + /// This corresponds to the `__wasi_path_remove_directory` syscall. + fn remove_directory>(&self, path: P) -> io::Result<()>; +} + +// FIXME: bind __wasi_fd_fdstat_get - need to define a custom return type +// FIXME: bind __wasi_fd_readdir - can't return `ReadDir` since we only have entry name +// FIXME: bind __wasi_fd_filestat_set_times maybe? - on crates.io for unix +// FIXME: bind __wasi_path_filestat_set_times maybe? - on crates.io for unix +// FIXME: bind __wasi_poll_oneoff maybe? - probably should wait for I/O to settle +// FIXME: bind __wasi_random_get maybe? - on crates.io for unix + +impl FileExt for fs::File { + fn read_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { + self.as_inner().fd().pread(bufs, offset) + } + + fn write_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { + self.as_inner().fd().pwrite(bufs, offset) + } + + fn tell(&self) -> io::Result { + self.as_inner().fd().tell() + } + + fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> { + self.as_inner().fd().set_flags(flags) + } + + fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()> { + self.as_inner().fd().set_rights(rights, inheriting) + } + + fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> { + self.as_inner().fd().advise(offset, len, advice) + } + + fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { + self.as_inner().fd().allocate(offset, len) + } + + fn create_directory>(&self, dir: P) -> io::Result<()> { + self.as_inner() + .fd() + .create_directory(dir.as_ref().as_os_str().as_bytes()) + } + + fn read_link>(&self, path: P) -> io::Result { + self.as_inner().read_link(path.as_ref()) + } + + fn metadata_at>(&self, lookup_flags: u32, path: P) -> io::Result { + let m = self.as_inner().metadata_at(lookup_flags, path.as_ref())?; + Ok(FromInner::from_inner(m)) + } + + fn remove_file>(&self, path: P) -> io::Result<()> { + self.as_inner() + .fd() + .unlink_file(path.as_ref().as_os_str().as_bytes()) + } + + fn remove_directory>(&self, path: P) -> io::Result<()> { + self.as_inner() + .fd() + .remove_directory(path.as_ref().as_os_str().as_bytes()) + } +} + +/// WASI-specific extensions to [`fs::OpenOptions`]. +/// +/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html +pub trait OpenOptionsExt { + /// Pass custom `dirflags` argument to `__wasi_path_open`. + /// + /// This option configures the `dirflags` argument to the + /// `__wasi_path_open` syscall which `OpenOptions` will eventually call. The + /// `dirflags` argument configures how the file is looked up, currently + /// primarily affecting whether symlinks are followed or not. + /// + /// By default this value is `__WASI_LOOKUP_SYMLINK_FOLLOW`, or symlinks are + /// followed. You can call this method with 0 to disable following symlinks + fn lookup_flags(&mut self, flags: u32) -> &mut Self; + + /// Indicates whether `OpenOptions` must open a directory or not. + /// + /// This method will configure whether the `__WASI_O_DIRECTORY` flag is + /// passed when opening a file. When passed it will require that the opened + /// path is a directory. + /// + /// This option is by default `false` + fn directory(&mut self, dir: bool) -> &mut Self; + + /// Indicates whether `__WASI_FDFLAG_DSYNC` is passed in the `fs_flags` + /// field of `__wasi_path_open`. + /// + /// This option is by default `false` + fn dsync(&mut self, dsync: bool) -> &mut Self; + + /// Indicates whether `__WASI_FDFLAG_NONBLOCK` is passed in the `fs_flags` + /// field of `__wasi_path_open`. + /// + /// This option is by default `false` + fn nonblock(&mut self, nonblock: bool) -> &mut Self; + + /// Indicates whether `__WASI_FDFLAG_RSYNC` is passed in the `fs_flags` + /// field of `__wasi_path_open`. + /// + /// This option is by default `false` + fn rsync(&mut self, rsync: bool) -> &mut Self; + + /// Indicates whether `__WASI_FDFLAG_SYNC` is passed in the `fs_flags` + /// field of `__wasi_path_open`. + /// + /// This option is by default `false` + fn sync(&mut self, sync: bool) -> &mut Self; + + /// Indicates the value that should be passed in for the `fs_rights_base` + /// parameter of `__wasi_path_open`. + /// + /// This option defaults based on the `read` and `write` configuration of + /// this `OpenOptions` builder. If this method is called, however, the + /// exact mask passed in will be used instead. + fn fs_rights_base(&mut self, rights: u64) -> &mut Self; + + /// Indicates the value that should be passed in for the + /// `fs_rights_inheriting` parameter of `__wasi_path_open`. + /// + /// The default for this option is the same value as what will be passed + /// for the `fs_rights_base` parameter but if this method is called then + /// the specified value will be used instead. + fn fs_rights_inheriting(&mut self, rights: u64) -> &mut Self; + + /// Open a file or directory. + /// + /// This corresponds to the `__wasi_path_open` syscall. + fn open_at>(&self, file: &File, path: P) -> io::Result; +} + +impl OpenOptionsExt for OpenOptions { + fn lookup_flags(&mut self, flags: u32) -> &mut OpenOptions { + self.as_inner_mut().lookup_flags(flags); + self + } + + fn directory(&mut self, dir: bool) -> &mut OpenOptions { + self.as_inner_mut().directory(dir); + self + } + + fn dsync(&mut self, enabled: bool) -> &mut OpenOptions { + self.as_inner_mut().dsync(enabled); + self + } + + fn nonblock(&mut self, enabled: bool) -> &mut OpenOptions { + self.as_inner_mut().nonblock(enabled); + self + } + + fn rsync(&mut self, enabled: bool) -> &mut OpenOptions { + self.as_inner_mut().rsync(enabled); + self + } + + fn sync(&mut self, enabled: bool) -> &mut OpenOptions { + self.as_inner_mut().sync(enabled); + self + } + + fn fs_rights_base(&mut self, rights: u64) -> &mut OpenOptions { + self.as_inner_mut().fs_rights_base(rights); + self + } + + fn fs_rights_inheriting(&mut self, rights: u64) -> &mut OpenOptions { + self.as_inner_mut().fs_rights_inheriting(rights); + self + } + + fn open_at>(&self, file: &File, path: P) -> io::Result { + let inner = file.as_inner().open_at(path.as_ref(), self.as_inner())?; + Ok(File::from_inner(inner)) + } +} + +/// WASI-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html +pub trait MetadataExt { + /// Returns the `st_dev` field of the internal `__wasi_filestat_t` + fn dev(&self) -> u64; + /// Returns the `st_ino` field of the internal `__wasi_filestat_t` + fn ino(&self) -> u64; + /// Returns the `st_nlink` field of the internal `__wasi_filestat_t` + fn nlink(&self) -> u32; + /// Returns the `st_atim` field of the internal `__wasi_filestat_t` + fn atim(&self) -> u64; + /// Returns the `st_mtim` field of the internal `__wasi_filestat_t` + fn mtim(&self) -> u64; + /// Returns the `st_ctim` field of the internal `__wasi_filestat_t` + fn ctim(&self) -> u64; +} + +impl MetadataExt for fs::Metadata { + fn dev(&self) -> u64 { + self.as_inner().as_wasi().st_dev + } + fn ino(&self) -> u64 { + self.as_inner().as_wasi().st_ino + } + fn nlink(&self) -> u32 { + self.as_inner().as_wasi().st_nlink + } + fn atim(&self) -> u64 { + self.as_inner().as_wasi().st_atim + } + fn mtim(&self) -> u64 { + self.as_inner().as_wasi().st_mtim + } + fn ctim(&self) -> u64 { + self.as_inner().as_wasi().st_ctim + } +} + +/// WASI-specific extensions for [`FileType`]. +/// +/// Adds support for special WASI file types such as block/character devices, +/// pipes, and sockets. +/// +/// [`FileType`]: ../../../../std/fs/struct.FileType.html +pub trait FileTypeExt { + /// Returns `true` if this file type is a block device. + fn is_block_device(&self) -> bool; + /// Returns `true` if this file type is a character device. + fn is_character_device(&self) -> bool; + /// Returns `true` if this file type is a socket datagram. + fn is_socket_dgram(&self) -> bool; + /// Returns `true` if this file type is a socket stream. + fn is_socket_stream(&self) -> bool; +} + +impl FileTypeExt for fs::FileType { + fn is_block_device(&self) -> bool { + self.as_inner().bits() == libc::__WASI_FILETYPE_BLOCK_DEVICE + } + fn is_character_device(&self) -> bool { + self.as_inner().bits() == libc::__WASI_FILETYPE_CHARACTER_DEVICE + } + fn is_socket_dgram(&self) -> bool { + self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_DGRAM + } + fn is_socket_stream(&self) -> bool { + self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_STREAM + } +} + +/// WASI-specific extension methods for [`fs::DirEntry`]. +/// +/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html +pub trait DirEntryExt { + /// Returns the underlying `d_ino` field of the `__wasi_dirent_t` + fn ino(&self) -> u64; +} + +impl DirEntryExt for fs::DirEntry { + fn ino(&self) -> u64 { + self.as_inner().ino() + } +} + +/// Create a hard link. +/// +/// This corresponds to the `__wasi_path_link` syscall. +pub fn link, U: AsRef>( + old_fd: &File, + old_flags: u32, + old_path: P, + new_fd: &File, + new_path: U, +) -> io::Result<()> { + old_fd.as_inner().fd().link( + old_flags, + old_path.as_ref().as_os_str().as_bytes(), + new_fd.as_inner().fd(), + new_path.as_ref().as_os_str().as_bytes(), + ) +} + +/// Rename a file or directory. +/// +/// This corresponds to the `__wasi_path_rename` syscall. +pub fn rename, U: AsRef>( + old_fd: &File, + old_path: P, + new_fd: &File, + new_path: U, +) -> io::Result<()> { + old_fd.as_inner().fd().rename( + old_path.as_ref().as_os_str().as_bytes(), + new_fd.as_inner().fd(), + new_path.as_ref().as_os_str().as_bytes(), + ) +} + +/// Create a symbolic link. +/// +/// This corresponds to the `__wasi_path_symlink` syscall. +pub fn symlink, U: AsRef>( + old_path: P, + fd: &File, + new_path: U, +) -> io::Result<()> { + fd.as_inner().fd().symlink( + old_path.as_ref().as_os_str().as_bytes(), + new_path.as_ref().as_os_str().as_bytes(), + ) +} diff --git a/src/libstd/sys/wasi/ext/io.rs b/src/libstd/sys/wasi/ext/io.rs new file mode 100644 index 0000000000000..12afd1d42dc19 --- /dev/null +++ b/src/libstd/sys/wasi/ext/io.rs @@ -0,0 +1,142 @@ +//! WASI-specific extensions to general I/O primitives + +#![unstable(feature = "wasi_ext", issue = "0")] + +use crate::fs; +use crate::io; +use crate::sys; +use crate::net; +use crate::sys_common::{AsInner, FromInner, IntoInner}; + +/// Raw file descriptors. +pub type RawFd = u32; + +/// A trait to extract the raw WASI file descriptor from an underlying +/// object. +pub trait AsRawFd { + /// Extracts the raw file descriptor. + /// + /// This method does **not** pass ownership of the raw file descriptor + /// to the caller. The descriptor is only guaranteed to be valid while + /// the original object has not yet been destroyed. + fn as_raw_fd(&self) -> RawFd; +} + +/// A trait to express the ability to construct an object from a raw file +/// descriptor. +pub trait FromRawFd { + /// Constructs a new instance of `Self` from the given raw file + /// descriptor. + /// + /// This function **consumes ownership** of the specified file + /// descriptor. The returned object will take responsibility for closing + /// it when the object goes out of scope. + /// + /// This function is also unsafe as the primitives currently returned + /// have the contract that they are the sole owner of the file + /// descriptor they are wrapping. Usage of this function could + /// accidentally allow violating this contract which can cause memory + /// unsafety in code that relies on it being true. + unsafe fn from_raw_fd(fd: RawFd) -> Self; +} + +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw file descriptor. +pub trait IntoRawFd { + /// Consumes this object, returning the raw underlying file descriptor. + /// + /// This function **transfers ownership** of the underlying file descriptor + /// to the caller. Callers are then the unique owners of the file descriptor + /// and must close the descriptor once it's no longer needed. + fn into_raw_fd(self) -> RawFd; +} + +impl AsRawFd for net::TcpStream { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().as_raw() + } +} + +impl FromRawFd for net::TcpStream { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { + net::TcpStream::from_inner(sys::net::TcpStream::from_inner(fd)) + } +} + +impl IntoRawFd for net::TcpStream { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl AsRawFd for net::TcpListener { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().as_raw() + } +} + +impl FromRawFd for net::TcpListener { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { + net::TcpListener::from_inner(sys::net::TcpListener::from_inner(fd)) + } +} + +impl IntoRawFd for net::TcpListener { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl AsRawFd for net::UdpSocket { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().as_raw() + } +} + +impl FromRawFd for net::UdpSocket { + unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { + net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(fd)) + } +} + +impl IntoRawFd for net::UdpSocket { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl AsRawFd for fs::File { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().as_raw() + } +} + +impl FromRawFd for fs::File { + unsafe fn from_raw_fd(fd: RawFd) -> fs::File { + fs::File::from_inner(sys::fs::File::from_inner(fd)) + } +} + +impl IntoRawFd for fs::File { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl AsRawFd for io::Stdin { + fn as_raw_fd(&self) -> RawFd { + libc::STDIN_FILENO as u32 + } +} + +impl AsRawFd for io::Stdout { + fn as_raw_fd(&self) -> RawFd { + libc::STDOUT_FILENO as u32 + } +} + +impl AsRawFd for io::Stderr { + fn as_raw_fd(&self) -> RawFd { + libc::STDERR_FILENO as u32 + } +} diff --git a/src/libstd/sys/wasi/ext/mod.rs b/src/libstd/sys/wasi/ext/mod.rs new file mode 100644 index 0000000000000..1c24b244b8cd0 --- /dev/null +++ b/src/libstd/sys/wasi/ext/mod.rs @@ -0,0 +1,18 @@ +pub mod ffi; +pub mod fs; +pub mod io; + +/// A prelude for conveniently writing platform-specific code. +/// +/// Includes all extension traits, and some important type definitions. +#[stable(feature = "rust1", since = "1.0.0")] +pub mod prelude { + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::sys::ext::ffi::{OsStringExt, OsStrExt}; + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::sys::ext::fs::{FileExt, DirEntryExt, MetadataExt, OpenOptionsExt}; + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::sys::ext::fs::FileTypeExt; + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::sys::ext::io::{AsRawFd, IntoRawFd, FromRawFd}; +} diff --git a/src/libstd/sys/wasi/fd.rs b/src/libstd/sys/wasi/fd.rs new file mode 100644 index 0000000000000..25692ec086801 --- /dev/null +++ b/src/libstd/sys/wasi/fd.rs @@ -0,0 +1,350 @@ +#![allow(dead_code)] + +use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; +use crate::mem; +use crate::net::Shutdown; +use crate::sys::cvt_wasi; +use libc::{self, c_char, c_void}; + +#[derive(Debug)] +pub struct WasiFd { + fd: libc::__wasi_fd_t, +} + +// FIXME: these should probably all be fancier structs, builders, enums, etc +pub type LookupFlags = u32; +pub type FdFlags = u16; +pub type Advice = u8; +pub type Rights = u64; +pub type Oflags = u16; +pub type DirCookie = u64; +pub type Timestamp = u64; +pub type FstFlags = u16; +pub type RiFlags = u16; +pub type RoFlags = u16; +pub type SiFlags = u16; + +fn iovec(a: &mut [IoSliceMut<'_>]) -> (*const libc::__wasi_iovec_t, usize) { + assert_eq!( + mem::size_of::>(), + mem::size_of::() + ); + assert_eq!( + mem::align_of::>(), + mem::align_of::() + ); + (a.as_ptr() as *const libc::__wasi_iovec_t, a.len()) +} + +fn ciovec(a: &[IoSlice<'_>]) -> (*const libc::__wasi_ciovec_t, usize) { + assert_eq!( + mem::size_of::>(), + mem::size_of::() + ); + assert_eq!( + mem::align_of::>(), + mem::align_of::() + ); + (a.as_ptr() as *const libc::__wasi_ciovec_t, a.len()) +} + +impl WasiFd { + pub unsafe fn from_raw(fd: libc::__wasi_fd_t) -> WasiFd { + WasiFd { fd } + } + + pub fn into_raw(self) -> libc::__wasi_fd_t { + let ret = self.fd; + mem::forget(self); + ret + } + + pub fn as_raw(&self) -> libc::__wasi_fd_t { + self.fd + } + + pub fn datasync(&self) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_datasync(self.fd) }) + } + + pub fn pread(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { + let mut read = 0; + let (ptr, len) = iovec(bufs); + cvt_wasi(unsafe { libc::__wasi_fd_pread(self.fd, ptr, len, offset, &mut read) })?; + Ok(read) + } + + pub fn pwrite(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { + let mut read = 0; + let (ptr, len) = ciovec(bufs); + cvt_wasi(unsafe { libc::__wasi_fd_pwrite(self.fd, ptr, len, offset, &mut read) })?; + Ok(read) + } + + pub fn read(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let mut read = 0; + let (ptr, len) = iovec(bufs); + cvt_wasi(unsafe { libc::__wasi_fd_read(self.fd, ptr, len, &mut read) })?; + Ok(read) + } + + pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result { + let mut read = 0; + let (ptr, len) = ciovec(bufs); + cvt_wasi(unsafe { libc::__wasi_fd_write(self.fd, ptr, len, &mut read) })?; + Ok(read) + } + + pub fn seek(&self, pos: SeekFrom) -> io::Result { + let (whence, offset) = match pos { + SeekFrom::Start(pos) => (libc::__WASI_WHENCE_SET, pos as i64), + SeekFrom::End(pos) => (libc::__WASI_WHENCE_END, pos), + SeekFrom::Current(pos) => (libc::__WASI_WHENCE_CUR, pos), + }; + let mut pos = 0; + cvt_wasi(unsafe { libc::__wasi_fd_seek(self.fd, offset, whence, &mut pos) })?; + Ok(pos) + } + + pub fn tell(&self) -> io::Result { + let mut pos = 0; + cvt_wasi(unsafe { libc::__wasi_fd_tell(self.fd, &mut pos) })?; + Ok(pos) + } + + // FIXME: __wasi_fd_fdstat_get + + pub fn set_flags(&self, flags: FdFlags) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_flags(self.fd, flags) }) + } + + pub fn set_rights(&self, base: Rights, inheriting: Rights) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_rights(self.fd, base, inheriting) }) + } + + pub fn sync(&self) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_sync(self.fd) }) + } + + pub fn advise(&self, offset: u64, len: u64, advice: Advice) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_advise(self.fd, offset, len, advice as u8) }) + } + + pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_allocate(self.fd, offset, len) }) + } + + pub fn create_directory(&self, path: &[u8]) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_create_directory(self.fd, path.as_ptr() as *const c_char, path.len()) + }) + } + + pub fn link( + &self, + old_flags: LookupFlags, + old_path: &[u8], + new_fd: &WasiFd, + new_path: &[u8], + ) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_link( + self.fd, + old_flags, + old_path.as_ptr() as *const c_char, + old_path.len(), + new_fd.fd, + new_path.as_ptr() as *const c_char, + new_path.len(), + ) + }) + } + + pub fn open( + &self, + dirflags: LookupFlags, + path: &[u8], + oflags: Oflags, + fs_rights_base: Rights, + fs_rights_inheriting: Rights, + fs_flags: FdFlags, + ) -> io::Result { + unsafe { + let mut fd = 0; + cvt_wasi(libc::__wasi_path_open( + self.fd, + dirflags, + path.as_ptr() as *const c_char, + path.len(), + oflags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + &mut fd, + ))?; + Ok(WasiFd::from_raw(fd)) + } + } + + pub fn readdir(&self, buf: &mut [u8], cookie: DirCookie) -> io::Result { + let mut used = 0; + cvt_wasi(unsafe { + libc::__wasi_fd_readdir( + self.fd, + buf.as_mut_ptr() as *mut c_void, + buf.len(), + cookie, + &mut used, + ) + })?; + Ok(used) + } + + pub fn readlink(&self, path: &[u8], buf: &mut [u8]) -> io::Result { + let mut used = 0; + cvt_wasi(unsafe { + libc::__wasi_path_readlink( + self.fd, + path.as_ptr() as *const c_char, + path.len(), + buf.as_mut_ptr() as *mut c_char, + buf.len(), + &mut used, + ) + })?; + Ok(used) + } + + pub fn rename(&self, old_path: &[u8], new_fd: &WasiFd, new_path: &[u8]) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_rename( + self.fd, + old_path.as_ptr() as *const c_char, + old_path.len(), + new_fd.fd, + new_path.as_ptr() as *const c_char, + new_path.len(), + ) + }) + } + + pub fn filestat_get(&self, buf: *mut libc::__wasi_filestat_t) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_filestat_get(self.fd, buf) }) + } + + pub fn filestat_set_times( + &self, + atim: Timestamp, + mtim: Timestamp, + fstflags: FstFlags, + ) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_times(self.fd, atim, mtim, fstflags) }) + } + + pub fn filestat_set_size(&self, size: u64) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_size(self.fd, size) }) + } + + pub fn path_filestat_get( + &self, + flags: LookupFlags, + path: &[u8], + buf: *mut libc::__wasi_filestat_t, + ) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_filestat_get( + self.fd, + flags, + path.as_ptr() as *const c_char, + path.len(), + buf, + ) + }) + } + + pub fn path_filestat_set_times( + &self, + flags: LookupFlags, + path: &[u8], + atim: Timestamp, + mtim: Timestamp, + fstflags: FstFlags, + ) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_filestat_set_times( + self.fd, + flags, + path.as_ptr() as *const c_char, + path.len(), + atim, + mtim, + fstflags, + ) + }) + } + + pub fn symlink(&self, old_path: &[u8], new_path: &[u8]) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_symlink( + old_path.as_ptr() as *const c_char, + old_path.len(), + self.fd, + new_path.as_ptr() as *const c_char, + new_path.len(), + ) + }) + } + + pub fn unlink_file(&self, path: &[u8]) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_unlink_file(self.fd, path.as_ptr() as *const c_char, path.len()) + }) + } + + pub fn remove_directory(&self, path: &[u8]) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_remove_directory(self.fd, path.as_ptr() as *const c_char, path.len()) + }) + } + + pub fn sock_recv( + &self, + ri_data: &mut [IoSliceMut<'_>], + ri_flags: RiFlags, + ) -> io::Result<(usize, RoFlags)> { + let mut ro_datalen = 0; + let mut ro_flags = 0; + let (ptr, len) = iovec(ri_data); + cvt_wasi(unsafe { + libc::__wasi_sock_recv(self.fd, ptr, len, ri_flags, &mut ro_datalen, &mut ro_flags) + })?; + Ok((ro_datalen, ro_flags)) + } + + pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: SiFlags) -> io::Result { + let mut so_datalen = 0; + let (ptr, len) = ciovec(si_data); + cvt_wasi(unsafe { libc::__wasi_sock_send(self.fd, ptr, len, si_flags, &mut so_datalen) })?; + Ok(so_datalen) + } + + pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> { + let how = match how { + Shutdown::Read => libc::__WASI_SHUT_RD, + Shutdown::Write => libc::__WASI_SHUT_WR, + Shutdown::Both => libc::__WASI_SHUT_WR | libc::__WASI_SHUT_RD, + }; + cvt_wasi(unsafe { libc::__wasi_sock_shutdown(self.fd, how) })?; + Ok(()) + } +} + +impl Drop for WasiFd { + fn drop(&mut self) { + unsafe { + // FIXME: can we handle the return code here even though we can't on + // unix? + libc::__wasi_fd_close(self.fd); + } + } +} diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs new file mode 100644 index 0000000000000..172c60385b317 --- /dev/null +++ b/src/libstd/sys/wasi/fs.rs @@ -0,0 +1,691 @@ +use crate::ffi::{CStr, CString, OsStr, OsString}; +use crate::fmt; +use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; +use crate::iter; +use crate::mem::{self, ManuallyDrop}; +use crate::os::wasi::ffi::{OsStrExt, OsStringExt}; +use crate::path::{Path, PathBuf}; +use crate::ptr; +use crate::sync::Arc; +use crate::sys::fd::{DirCookie, WasiFd}; +use crate::sys::time::SystemTime; +use crate::sys::unsupported; +use crate::sys_common::FromInner; + +pub use crate::sys_common::fs::copy; +pub use crate::sys_common::fs::remove_dir_all; + +pub struct File { + fd: WasiFd, +} + +#[derive(Clone)] +pub struct FileAttr { + meta: libc::__wasi_filestat_t, +} + +pub struct ReadDir { + inner: Arc, + cookie: Option, + buf: Vec, + offset: usize, + cap: usize, +} + +struct ReadDirInner { + root: PathBuf, + dir: File, +} + +pub struct DirEntry { + meta: libc::__wasi_dirent_t, + name: Vec, + inner: Arc, +} + +#[derive(Clone, Debug, Default)] +pub struct OpenOptions { + read: bool, + write: bool, + dirflags: libc::__wasi_lookupflags_t, + fdflags: libc::__wasi_fdflags_t, + oflags: libc::__wasi_oflags_t, + rights_base: Option, + rights_inheriting: Option, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FilePermissions { + readonly: bool, +} + +#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] +pub struct FileType { + bits: libc::__wasi_filetype_t, +} + +#[derive(Debug)] +pub struct DirBuilder {} + +impl FileAttr { + fn zero() -> FileAttr { + FileAttr { + meta: unsafe { mem::zeroed() }, + } + } + + pub fn size(&self) -> u64 { + self.meta.st_size + } + + pub fn perm(&self) -> FilePermissions { + // not currently implemented in wasi yet + FilePermissions { readonly: false } + } + + pub fn file_type(&self) -> FileType { + FileType { + bits: self.meta.st_filetype, + } + } + + pub fn modified(&self) -> io::Result { + Ok(SystemTime::from_wasi_timestamp(self.meta.st_mtim)) + } + + pub fn accessed(&self) -> io::Result { + Ok(SystemTime::from_wasi_timestamp(self.meta.st_atim)) + } + + pub fn created(&self) -> io::Result { + Ok(SystemTime::from_wasi_timestamp(self.meta.st_ctim)) + } + + pub fn as_wasi(&self) -> &libc::__wasi_filestat_t { + &self.meta + } +} + +impl FilePermissions { + pub fn readonly(&self) -> bool { + self.readonly + } + + pub fn set_readonly(&mut self, readonly: bool) { + self.readonly = readonly; + } +} + +impl FileType { + pub fn is_dir(&self) -> bool { + self.bits == libc::__WASI_FILETYPE_DIRECTORY + } + + pub fn is_file(&self) -> bool { + self.bits == libc::__WASI_FILETYPE_REGULAR_FILE + } + + pub fn is_symlink(&self) -> bool { + self.bits == libc::__WASI_FILETYPE_SYMBOLIC_LINK + } + + pub fn bits(&self) -> libc::__wasi_filetype_t { + self.bits + } +} + +impl fmt::Debug for ReadDir { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ReadDir").finish() + } +} + +impl Iterator for ReadDir { + type Item = io::Result; + + fn next(&mut self) -> Option> { + loop { + // If we've reached the capacity of our buffer then we need to read + // some more from the OS, otherwise we pick up at our old offset. + let offset = if self.offset == self.cap { + let cookie = self.cookie.take()?; + match self.inner.dir.fd.readdir(&mut self.buf, cookie) { + Ok(bytes) => self.cap = bytes, + Err(e) => return Some(Err(e)), + } + self.offset = 0; + self.cookie = Some(cookie); + + // If we didn't actually read anything, this is in theory the + // end of the directory. + if self.cap == 0 { + self.cookie = None; + return None; + } + + 0 + } else { + self.offset + }; + let data = &self.buf[offset..self.cap]; + + // If we're not able to read a directory entry then that means it + // must have been truncated at the end of the buffer, so reset our + // offset so we can go back and reread into the buffer, picking up + // where we last left off. + let dirent_size = mem::size_of::(); + if data.len() < dirent_size { + assert!(self.cookie.is_some()); + assert!(self.buf.len() >= dirent_size); + self.offset = self.cap; + continue; + } + let (dirent, data) = data.split_at(dirent_size); + let dirent = + unsafe { ptr::read_unaligned(dirent.as_ptr() as *const libc::__wasi_dirent_t) }; + + // If the file name was truncated, then we need to reinvoke + // `readdir` so we truncate our buffer to start over and reread this + // descriptor. Note that if our offset is 0 that means the file name + // is massive and we need a bigger buffer. + if data.len() < dirent.d_namlen as usize { + if offset == 0 { + let amt_to_add = self.buf.capacity(); + self.buf.extend(iter::repeat(0).take(amt_to_add)); + } + assert!(self.cookie.is_some()); + self.offset = self.cap; + continue; + } + self.cookie = Some(dirent.d_next); + self.offset = offset + dirent_size + dirent.d_namlen as usize; + + let name = &data[..(dirent.d_namlen as usize)]; + + // These names are skipped on all other platforms, so let's skip + // them here too + if name == b"." || name == b".." { + continue; + } + + return Some(Ok(DirEntry { + meta: dirent, + name: name.to_vec(), + inner: self.inner.clone(), + })); + } + } +} + +impl DirEntry { + pub fn path(&self) -> PathBuf { + let name = OsStr::from_bytes(&self.name); + self.inner.root.join(name) + } + + pub fn file_name(&self) -> OsString { + OsString::from_vec(self.name.clone()) + } + + pub fn metadata(&self) -> io::Result { + metadata_at( + &self.inner.dir.fd, + 0, + OsStr::from_bytes(&self.name).as_ref(), + ) + } + + pub fn file_type(&self) -> io::Result { + Ok(FileType { + bits: self.meta.d_type, + }) + } + + pub fn ino(&self) -> libc::__wasi_inode_t { + self.meta.d_ino + } +} + +impl OpenOptions { + pub fn new() -> OpenOptions { + let mut base = OpenOptions::default(); + base.dirflags = libc::__WASI_LOOKUP_SYMLINK_FOLLOW; + return base; + } + + pub fn read(&mut self, read: bool) { + self.read = read; + } + + pub fn write(&mut self, write: bool) { + self.write = write; + } + + pub fn truncate(&mut self, truncate: bool) { + self.oflag(libc::__WASI_O_TRUNC, truncate); + } + + pub fn create(&mut self, create: bool) { + self.oflag(libc::__WASI_O_CREAT, create); + } + + pub fn create_new(&mut self, create_new: bool) { + self.oflag(libc::__WASI_O_EXCL, create_new); + self.oflag(libc::__WASI_O_CREAT, create_new); + } + + pub fn directory(&mut self, directory: bool) { + self.oflag(libc::__WASI_O_DIRECTORY, directory); + } + + fn oflag(&mut self, bit: libc::__wasi_oflags_t, set: bool) { + if set { + self.oflags |= bit; + } else { + self.oflags &= !bit; + } + } + + pub fn append(&mut self, set: bool) { + self.fdflag(libc::__WASI_FDFLAG_APPEND, set); + } + + pub fn dsync(&mut self, set: bool) { + self.fdflag(libc::__WASI_FDFLAG_DSYNC, set); + } + + pub fn nonblock(&mut self, set: bool) { + self.fdflag(libc::__WASI_FDFLAG_NONBLOCK, set); + } + + pub fn rsync(&mut self, set: bool) { + self.fdflag(libc::__WASI_FDFLAG_RSYNC, set); + } + + pub fn sync(&mut self, set: bool) { + self.fdflag(libc::__WASI_FDFLAG_SYNC, set); + } + + fn fdflag(&mut self, bit: libc::__wasi_fdflags_t, set: bool) { + if set { + self.fdflags |= bit; + } else { + self.fdflags &= !bit; + } + } + + pub fn fs_rights_base(&mut self, rights: libc::__wasi_rights_t) { + self.rights_base = Some(rights); + } + + pub fn fs_rights_inheriting(&mut self, rights: libc::__wasi_rights_t) { + self.rights_inheriting = Some(rights); + } + + fn rights_base(&self) -> libc::__wasi_rights_t { + if let Some(rights) = self.rights_base { + return rights; + } + + // If rights haven't otherwise been specified try to pick a reasonable + // set. This can always be overridden by users via extension traits, and + // implementations may give us fewer rights silently than we ask for. So + // given that, just look at `read` and `write` and bucket permissions + // based on that. + let mut base = 0; + if self.read { + base |= libc::__WASI_RIGHT_FD_READ; + base |= libc::__WASI_RIGHT_FD_READDIR; + } + if self.write { + base |= libc::__WASI_RIGHT_FD_WRITE; + base |= libc::__WASI_RIGHT_FD_DATASYNC; + base |= libc::__WASI_RIGHT_FD_ALLOCATE; + base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_SIZE; + } + + // FIXME: some of these should probably be read-only or write-only... + base |= libc::__WASI_RIGHT_FD_ADVISE; + base |= libc::__WASI_RIGHT_FD_FDSTAT_SET_FLAGS; + base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_TIMES; + base |= libc::__WASI_RIGHT_FD_SEEK; + base |= libc::__WASI_RIGHT_FD_SYNC; + base |= libc::__WASI_RIGHT_FD_TELL; + base |= libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY; + base |= libc::__WASI_RIGHT_PATH_CREATE_FILE; + base |= libc::__WASI_RIGHT_PATH_FILESTAT_GET; + base |= libc::__WASI_RIGHT_PATH_LINK_SOURCE; + base |= libc::__WASI_RIGHT_PATH_LINK_TARGET; + base |= libc::__WASI_RIGHT_PATH_OPEN; + base |= libc::__WASI_RIGHT_PATH_READLINK; + base |= libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY; + base |= libc::__WASI_RIGHT_PATH_RENAME_SOURCE; + base |= libc::__WASI_RIGHT_PATH_RENAME_TARGET; + base |= libc::__WASI_RIGHT_PATH_SYMLINK; + base |= libc::__WASI_RIGHT_PATH_UNLINK_FILE; + base |= libc::__WASI_RIGHT_POLL_FD_READWRITE; + + return base; + } + + fn rights_inheriting(&self) -> libc::__wasi_rights_t { + self.rights_inheriting.unwrap_or_else(|| self.rights_base()) + } + + pub fn lookup_flags(&mut self, flags: libc::__wasi_lookupflags_t) { + self.dirflags = flags; + } +} + +impl File { + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + let (dir, file) = open_parent(path, libc::__WASI_RIGHT_PATH_OPEN)?; + open_at(&dir, &file, opts) + } + + pub fn open_at(&self, path: &Path, opts: &OpenOptions) -> io::Result { + open_at(&self.fd, path, opts) + } + + pub fn file_attr(&self) -> io::Result { + let mut ret = FileAttr::zero(); + self.fd.filestat_get(&mut ret.meta)?; + Ok(ret) + } + + pub fn metadata_at( + &self, + flags: libc::__wasi_lookupflags_t, + path: &Path, + ) -> io::Result { + metadata_at(&self.fd, flags, path) + } + + pub fn fsync(&self) -> io::Result<()> { + self.fd.sync() + } + + pub fn datasync(&self) -> io::Result<()> { + self.fd.datasync() + } + + pub fn truncate(&self, size: u64) -> io::Result<()> { + self.fd.filestat_set_size(size) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.read_vectored(&mut [IoSliceMut::new(buf)]) + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.fd.read(bufs) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + self.write_vectored(&[IoSlice::new(buf)]) + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + self.fd.write(bufs) + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } + + pub fn seek(&self, pos: SeekFrom) -> io::Result { + self.fd.seek(pos) + } + + pub fn duplicate(&self) -> io::Result { + // https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-rationale.md#why-no-dup + unsupported() + } + + pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { + // Permissions haven't been fully figured out in wasi yet, so this is + // likely temporary + unsupported() + } + + pub fn fd(&self) -> &WasiFd { + &self.fd + } + + pub fn into_fd(self) -> WasiFd { + self.fd + } + + pub fn read_link(&self, file: &Path) -> io::Result { + read_link(&self.fd, file) + } +} + +impl FromInner for File { + fn from_inner(fd: u32) -> File { + unsafe { + File { + fd: WasiFd::from_raw(fd), + } + } + } +} + +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder {} + } + + pub fn mkdir(&self, p: &Path) -> io::Result<()> { + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY)?; + dir.create_directory(file.as_os_str().as_bytes()) + } +} + +impl fmt::Debug for File { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("File") + .field("fd", &self.fd.as_raw()) + .finish() + } +} + +pub fn readdir(p: &Path) -> io::Result { + let mut opts = OpenOptions::new(); + opts.directory(true); + opts.read(true); + let dir = File::open(p, &opts)?; + Ok(ReadDir { + cookie: Some(0), + buf: vec![0; 128], + offset: 0, + cap: 0, + inner: Arc::new(ReadDirInner { + dir, + root: p.to_path_buf(), + }), + }) +} + +pub fn unlink(p: &Path) -> io::Result<()> { + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_UNLINK_FILE)?; + dir.unlink_file(file.as_os_str().as_bytes()) +} + +pub fn rename(old: &Path, new: &Path) -> io::Result<()> { + let (old, old_file) = open_parent(old, libc::__WASI_RIGHT_PATH_RENAME_SOURCE)?; + let (new, new_file) = open_parent(new, libc::__WASI_RIGHT_PATH_RENAME_TARGET)?; + old.rename( + old_file.as_os_str().as_bytes(), + &new, + new_file.as_os_str().as_bytes(), + ) +} + +pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { + // Permissions haven't been fully figured out in wasi yet, so this is + // likely temporary + unsupported() +} + +pub fn rmdir(p: &Path) -> io::Result<()> { + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY)?; + dir.remove_directory(file.as_os_str().as_bytes()) +} + +pub fn readlink(p: &Path) -> io::Result { + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_READLINK)?; + read_link(&dir, &file) +} + +fn read_link(fd: &WasiFd, file: &Path) -> io::Result { + // Try to get a best effort initial capacity for the vector we're going to + // fill. Note that if it's not a symlink we don't use a file to avoid + // allocating gigabytes if you read_link a huge movie file by accident. + // Additionally we add 1 to the initial size so if it doesn't change until + // when we call `readlink` the returned length will be less than the + // capacity, guaranteeing that we got all the data. + let meta = metadata_at(fd, 0, file)?; + let initial_size = if meta.file_type().is_symlink() { + (meta.size() as usize).saturating_add(1) + } else { + 1 // this'll fail in just a moment + }; + + // Now that we have an initial guess of how big to make our buffer, call + // `readlink` in a loop until it fails or reports it filled fewer bytes than + // we asked for, indicating we got everything. + let file = file.as_os_str().as_bytes(); + let mut destination = vec![0u8; initial_size]; + loop { + let len = fd.readlink(file, &mut destination)?; + if len < destination.len() { + destination.truncate(len); + destination.shrink_to_fit(); + return Ok(PathBuf::from(OsString::from_vec(destination))); + } + let amt_to_add = destination.len(); + destination.extend(iter::repeat(0).take(amt_to_add)); + } +} + +pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { + let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_SYMLINK)?; + dst.symlink(src.as_os_str().as_bytes(), dst_file.as_os_str().as_bytes()) +} + +pub fn link(src: &Path, dst: &Path) -> io::Result<()> { + let (src, src_file) = open_parent(src, libc::__WASI_RIGHT_PATH_LINK_SOURCE)?; + let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_LINK_TARGET)?; + src.link( + libc::__WASI_LOOKUP_SYMLINK_FOLLOW, + src_file.as_os_str().as_bytes(), + &dst, + dst_file.as_os_str().as_bytes(), + ) +} + +pub fn stat(p: &Path) -> io::Result { + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?; + metadata_at(&dir, libc::__WASI_LOOKUP_SYMLINK_FOLLOW, &file) +} + +pub fn lstat(p: &Path) -> io::Result { + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?; + metadata_at(&dir, 0, &file) +} + +fn metadata_at( + fd: &WasiFd, + flags: libc::__wasi_lookupflags_t, + path: &Path, +) -> io::Result { + let mut ret = FileAttr::zero(); + fd.path_filestat_get(flags, path.as_os_str().as_bytes(), &mut ret.meta)?; + Ok(ret) +} + +pub fn canonicalize(_p: &Path) -> io::Result { + // This seems to not be in wasi's API yet, and we may need to end up + // emulating it ourselves. For now just return an error. + unsupported() +} + +fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result { + let fd = fd.open( + opts.dirflags, + path.as_os_str().as_bytes(), + opts.oflags, + opts.rights_base(), + opts.rights_inheriting(), + opts.fdflags, + )?; + Ok(File { fd }) +} + +/// Attempts to open a bare path `p`. +/// +/// WASI has no fundamental capability to do this. All syscalls and operations +/// are relative to already-open file descriptors. The C library, however, +/// manages a map of preopened file descriptors to their path, and then the C +/// library provides an API to look at this. In other words, when you want to +/// open a path `p`, you have to find a previously opened file descriptor in a +/// global table and then see if `p` is relative to that file descriptor. +/// +/// This function, if successful, will return two items: +/// +/// * The first is a `ManuallyDrop`. This represents a preopened file +/// descriptor which we don't have ownership of, but we can use. You shouldn't +/// actually drop the `fd`. +/// +/// * The second is a path that should be a part of `p` and represents a +/// relative traversal from the file descriptor specified to the desired +/// location `p`. +/// +/// If successful you can use the returned file descriptor to perform +/// file-descriptor-relative operations on the path returned as well. The +/// `rights` argument indicates what operations are desired on the returned file +/// descriptor, and if successful the returned file descriptor should have the +/// appropriate rights for performing `rights` actions. +/// +/// Note that this can fail if `p` doesn't look like it can be opened relative +/// to any preopened file descriptor. +fn open_parent( + p: &Path, + rights: libc::__wasi_rights_t, +) -> io::Result<(ManuallyDrop, PathBuf)> { + let p = CString::new(p.as_os_str().as_bytes())?; + unsafe { + let mut ret = ptr::null(); + let fd = __wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret); + if fd == -1 { + let msg = format!( + "failed to find a preopened file descriptor \ + through which {:?} could be opened", + p + ); + return Err(io::Error::new(io::ErrorKind::Other, msg)); + } + let path = Path::new(OsStr::from_bytes(CStr::from_ptr(ret).to_bytes())); + + // FIXME: right now `path` is a pointer into `p`, the `CString` above. + // When we return `p` is deallocated and we can't use it, so we need to + // currently separately allocate `path`. If this becomes an issue though + // we should probably turn this into a closure-taking interface or take + // `&CString` and then pass off `&Path` tied to the same lifetime. + let path = path.to_path_buf(); + + return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path)); + } + + // FIXME(rust-lang/libc#1314) use the `libc` crate for this when the API + // there is published + extern "C" { + pub fn __wasilibc_find_relpath( + path: *const libc::c_char, + rights_base: libc::__wasi_rights_t, + rights_inheriting: libc::__wasi_rights_t, + relative_path: *mut *const libc::c_char, + ) -> libc::c_int; + } +} diff --git a/src/libstd/sys/wasi/io.rs b/src/libstd/sys/wasi/io.rs new file mode 100644 index 0000000000000..cc8f1e16fa01d --- /dev/null +++ b/src/libstd/sys/wasi/io.rs @@ -0,0 +1,62 @@ +use crate::marker::PhantomData; +use crate::slice; + +use libc::{__wasi_ciovec_t, __wasi_iovec_t, c_void}; + +#[repr(transparent)] +pub struct IoSlice<'a> { + vec: __wasi_ciovec_t, + _p: PhantomData<&'a [u8]>, +} + +impl<'a> IoSlice<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice { + vec: __wasi_ciovec_t { + buf: buf.as_ptr() as *const c_void, + buf_len: buf.len(), + }, + _p: PhantomData, + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len) + } + } +} + +pub struct IoSliceMut<'a> { + vec: __wasi_iovec_t, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoSliceMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut { + vec: __wasi_iovec_t { + buf: buf.as_mut_ptr() as *mut c_void, + buf_len: buf.len() + }, + _p: PhantomData, + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len) + } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) + } + } +} diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs new file mode 100644 index 0000000000000..e22434439f5bb --- /dev/null +++ b/src/libstd/sys/wasi/mod.rs @@ -0,0 +1,126 @@ +//! System bindings for the wasm/web platform +//! +//! This module contains the facade (aka platform-specific) implementations of +//! OS level functionality for wasm. Note that this wasm is *not* the emscripten +//! wasm, so we have no runtime here. +//! +//! This is all super highly experimental and not actually intended for +//! wide/production use yet, it's still all in the experimental category. This +//! will likely change over time. +//! +//! Currently all functions here are basically stubs that immediately return +//! errors. The hope is that with a portability lint we can turn actually just +//! remove all this and just omit parts of the standard library if we're +//! compiling for wasm. That way it's a compile time error for something that's +//! guaranteed to be a runtime error! + +use libc; +use crate::io::{Error, ErrorKind}; +use crate::mem; +use crate::os::raw::c_char; + +pub mod alloc; +pub mod args; +#[path = "../wasm/cmath.rs"] +pub mod cmath; +#[path = "../wasm/condvar.rs"] +pub mod condvar; +pub mod env; +pub mod fd; +pub mod fs; +#[path = "../wasm/memchr.rs"] +pub mod memchr; +#[path = "../wasm/mutex.rs"] +pub mod mutex; +pub mod net; +pub mod io; +pub mod os; +pub use crate::sys_common::os_str_bytes as os_str; +pub mod path; +pub mod pipe; +pub mod process; +#[path = "../wasm/rwlock.rs"] +pub mod rwlock; +#[path = "../wasm/stack_overflow.rs"] +pub mod stack_overflow; +pub mod stdio; +pub mod thread; +#[path = "../wasm/thread_local.rs"] +pub mod thread_local; +pub mod time; +pub mod ext; + +#[cfg(not(test))] +pub fn init() { +} + +pub fn unsupported() -> crate::io::Result { + Err(unsupported_err()) +} + +pub fn unsupported_err() -> Error { + Error::new(ErrorKind::Other, "operation not supported on wasm yet") +} + +pub fn decode_error_kind(_code: i32) -> ErrorKind { + ErrorKind::Other +} + +// This enum is used as the storage for a bunch of types which can't actually +// exist. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub enum Void {} + +pub unsafe fn strlen(mut s: *const c_char) -> usize { + let mut n = 0; + while *s != 0 { + n += 1; + s = s.offset(1); + } + return n +} + +pub unsafe fn abort_internal() -> ! { + libc::abort() +} + +pub fn hashmap_random_keys() -> (u64, u64) { + let mut ret = (0u64, 0u64); + unsafe { + let base = &mut ret as *mut (u64, u64) as *mut libc::c_void; + let len = mem::size_of_val(&ret); + cvt_wasi(libc::__wasi_random_get(base, len)).unwrap(); + } + return ret +} + +#[doc(hidden)] +pub trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) +} + +impl_is_minus_one! { i8 i16 i32 i64 isize } + +pub fn cvt(t: T) -> crate::io::Result { + if t.is_minus_one() { + Err(Error::last_os_error()) + } else { + Ok(t) + } +} + +pub fn cvt_wasi(r: u16) -> crate::io::Result<()> { + if r != libc::__WASI_ESUCCESS { + Err(Error::from_raw_os_error(r as i32)) + } else { + Ok(()) + } +} diff --git a/src/libstd/sys/wasi/net.rs b/src/libstd/sys/wasi/net.rs new file mode 100644 index 0000000000000..80f633a8e1f2b --- /dev/null +++ b/src/libstd/sys/wasi/net.rs @@ -0,0 +1,426 @@ +use crate::fmt; +use crate::io::{self, IoSlice, IoSliceMut}; +use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; +use crate::time::Duration; +use crate::sys::{unsupported, Void}; +use crate::convert::TryFrom; +use crate::sys::fd::{WasiFd}; +use crate::sys_common::FromInner; + +pub struct TcpStream { + fd: WasiFd, +} + +impl TcpStream { + pub fn connect(_: io::Result<&SocketAddr>) -> io::Result { + unsupported() + } + + pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { + unsupported() + } + + pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { + unsupported() + } + + pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { + unsupported() + } + + pub fn read_timeout(&self) -> io::Result> { + unsupported() + } + + pub fn write_timeout(&self) -> io::Result> { + unsupported() + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result { + unsupported() + } + + pub fn read(&self, _: &mut [u8]) -> io::Result { + unsupported() + } + + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { + unsupported() + } + + pub fn write(&self, _: &[u8]) -> io::Result { + unsupported() + } + + pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { + unsupported() + } + + pub fn peer_addr(&self) -> io::Result { + unsupported() + } + + pub fn socket_addr(&self) -> io::Result { + unsupported() + } + + pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { + unsupported() + } + + pub fn duplicate(&self) -> io::Result { + unsupported() + } + + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { + unsupported() + } + + pub fn nodelay(&self) -> io::Result { + unsupported() + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + unsupported() + } + + pub fn ttl(&self) -> io::Result { + unsupported() + } + + pub fn take_error(&self) -> io::Result> { + unsupported() + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + unsupported() + } + + pub fn fd(&self) -> &WasiFd { + &self.fd + } + + pub fn into_fd(self) -> WasiFd { + self.fd + } +} + +impl FromInner for TcpStream { + fn from_inner(fd: u32) -> TcpStream { + unsafe { + TcpStream { + fd: WasiFd::from_raw(fd), + } + } + } +} + +impl fmt::Debug for TcpStream { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TcpStream") + .field("fd", &self.fd.as_raw()) + .finish() + } +} + +pub struct TcpListener { + fd: WasiFd +} + +impl TcpListener { + pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + unsupported() + } + + pub fn socket_addr(&self) -> io::Result { + unsupported() + } + + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + unsupported() + } + + pub fn duplicate(&self) -> io::Result { + unsupported() + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + unsupported() + } + + pub fn ttl(&self) -> io::Result { + unsupported() + } + + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { + unsupported() + } + + pub fn only_v6(&self) -> io::Result { + unsupported() + } + + pub fn take_error(&self) -> io::Result> { + unsupported() + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + unsupported() + } + + pub fn fd(&self) -> &WasiFd { + &self.fd + } + + pub fn into_fd(self) -> WasiFd { + self.fd + } +} + +impl FromInner for TcpListener { + fn from_inner(fd: u32) -> TcpListener { + unsafe { + TcpListener { + fd: WasiFd::from_raw(fd), + } + } + } +} + +impl fmt::Debug for TcpListener { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TcpListener") + .field("fd", &self.fd.as_raw()) + .finish() + } +} + +pub struct UdpSocket { + fd: WasiFd, +} + +impl UdpSocket { + pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + unsupported() + } + + pub fn peer_addr(&self) -> io::Result { + unsupported() + } + + pub fn socket_addr(&self) -> io::Result { + unsupported() + } + + pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + unsupported() + } + + pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + unsupported() + } + + pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result { + unsupported() + } + + pub fn duplicate(&self) -> io::Result { + unsupported() + } + + pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { + unsupported() + } + + pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { + unsupported() + } + + pub fn read_timeout(&self) -> io::Result> { + unsupported() + } + + pub fn write_timeout(&self) -> io::Result> { + unsupported() + } + + pub fn set_broadcast(&self, _: bool) -> io::Result<()> { + unsupported() + } + + pub fn broadcast(&self) -> io::Result { + unsupported() + } + + pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { + unsupported() + } + + pub fn multicast_loop_v4(&self) -> io::Result { + unsupported() + } + + pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { + unsupported() + } + + pub fn multicast_ttl_v4(&self) -> io::Result { + unsupported() + } + + pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { + unsupported() + } + + pub fn multicast_loop_v6(&self) -> io::Result { + unsupported() + } + + pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) + -> io::Result<()> { + unsupported() + } + + pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) + -> io::Result<()> { + unsupported() + } + + pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) + -> io::Result<()> { + unsupported() + } + + pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) + -> io::Result<()> { + unsupported() + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + unsupported() + } + + pub fn ttl(&self) -> io::Result { + unsupported() + } + + pub fn take_error(&self) -> io::Result> { + unsupported() + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + unsupported() + } + + pub fn recv(&self, _: &mut [u8]) -> io::Result { + unsupported() + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result { + unsupported() + } + + pub fn send(&self, _: &[u8]) -> io::Result { + unsupported() + } + + pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + unsupported() + } + + pub fn fd(&self) -> &WasiFd { + &self.fd + } + + pub fn into_fd(self) -> WasiFd { + self.fd + } +} + +impl FromInner for UdpSocket { + fn from_inner(fd: u32) -> UdpSocket { + unsafe { + UdpSocket { + fd: WasiFd::from_raw(fd), + } + } + } +} + +impl fmt::Debug for UdpSocket { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("UdpSocket") + .field("fd", &self.fd.as_raw()) + .finish() + } +} + +pub struct LookupHost(Void); + +impl LookupHost { + pub fn port(&self) -> u16 { + match self.0 {} + } +} + +impl Iterator for LookupHost { + type Item = SocketAddr; + fn next(&mut self) -> Option { + match self.0 {} + } +} + +impl<'a> TryFrom<&'a str> for LookupHost { + type Error = io::Error; + + fn try_from(_v: &'a str) -> io::Result { + unsupported() + } +} + +impl<'a> TryFrom<(&'a str, u16)> for LookupHost { + type Error = io::Error; + + fn try_from(_v: (&'a str, u16)) -> io::Result { + unsupported() + } +} + +#[allow(nonstandard_style)] +pub mod netc { + pub const AF_INET: u8 = 0; + pub const AF_INET6: u8 = 1; + pub type sa_family_t = u8; + + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: u16, + pub sin_addr: in_addr, + } + + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: u16, + pub sin6_addr: in6_addr, + pub sin6_flowinfo: u32, + pub sin6_scope_id: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr { + } + + pub type socklen_t = usize; +} diff --git a/src/libstd/sys/wasi/os.rs b/src/libstd/sys/wasi/os.rs new file mode 100644 index 0000000000000..822ea02a11b89 --- /dev/null +++ b/src/libstd/sys/wasi/os.rs @@ -0,0 +1,184 @@ +use crate::any::Any; +use crate::error::Error as StdError; +use crate::ffi::{OsString, OsStr, CString, CStr}; +use crate::fmt; +use crate::io; +use crate::marker::PhantomData; +use crate::os::wasi::prelude::*; +use crate::path::{self, PathBuf}; +use crate::ptr; +use crate::str; +use crate::sys::memchr; +use crate::sys::{cvt, unsupported, Void}; +use crate::vec; + +#[cfg(not(target_feature = "atomics"))] +pub unsafe fn env_lock() -> impl Any { + // No need for a lock if we're single-threaded, but this function will need + // to get implemented for multi-threaded scenarios +} + +pub fn errno() -> i32 { + extern { + #[thread_local] + static errno: libc::c_int; + } + + unsafe { errno as i32 } +} + +pub fn error_string(errno: i32) -> String { + extern { + fn strerror_r(errnum: libc::c_int, buf: *mut libc::c_char, + buflen: libc::size_t) -> libc::c_int; + } + + let mut buf = [0 as libc::c_char; 1024]; + + let p = buf.as_mut_ptr(); + unsafe { + if strerror_r(errno as libc::c_int, p, buf.len()) < 0 { + panic!("strerror_r failure"); + } + str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() + } +} + +pub fn getcwd() -> io::Result { + unsupported() +} + +pub fn chdir(_: &path::Path) -> io::Result<()> { + unsupported() +} + +pub struct SplitPaths<'a>(&'a Void); + +pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { + panic!("unsupported") +} + +impl<'a> Iterator for SplitPaths<'a> { + type Item = PathBuf; + fn next(&mut self) -> Option { + match *self.0 {} + } +} + +#[derive(Debug)] +pub struct JoinPathsError; + +pub fn join_paths(_paths: I) -> Result + where I: Iterator, T: AsRef +{ + Err(JoinPathsError) +} + +impl fmt::Display for JoinPathsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "not supported on wasm yet".fmt(f) + } +} + +impl StdError for JoinPathsError { + fn description(&self) -> &str { + "not supported on wasm yet" + } +} + +pub fn current_exe() -> io::Result { + unsupported() +} + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, + _dont_send_or_sync_me: PhantomData<*mut ()>, +} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } +} + + +pub fn env() -> Env { + unsafe { + let _guard = env_lock(); + let mut environ = libc::environ; + let mut result = Vec::new(); + while environ != ptr::null_mut() && *environ != ptr::null_mut() { + if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { + result.push(key_value); + } + environ = environ.offset(1); + } + return Env { + iter: result.into_iter(), + _dont_send_or_sync_me: PhantomData, + } + } + + // See src/libstd/sys/unix/os.rs, same as that + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + if input.is_empty() { + return None; + } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p+1..].to_vec()), + )) + } +} + +pub fn getenv(k: &OsStr) -> io::Result> { + let k = CString::new(k.as_bytes())?; + unsafe { + let _guard = env_lock(); + let s = libc::getenv(k.as_ptr()) as *const libc::c_char; + let ret = if s.is_null() { + None + } else { + Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) + }; + Ok(ret) + } +} + +pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + let k = CString::new(k.as_bytes())?; + let v = CString::new(v.as_bytes())?; + + unsafe { + let _guard = env_lock(); + cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()) + } +} + +pub fn unsetenv(n: &OsStr) -> io::Result<()> { + let nbuf = CString::new(n.as_bytes())?; + + unsafe { + let _guard = env_lock(); + cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ()) + } +} + +pub fn temp_dir() -> PathBuf { + panic!("no filesystem on wasm") +} + +pub fn home_dir() -> Option { + None +} + +pub fn exit(code: i32) -> ! { + unsafe { + libc::exit(code) + } +} + +pub fn getpid() -> u32 { + panic!("unsupported"); +} diff --git a/src/libstd/sys/wasi/path.rs b/src/libstd/sys/wasi/path.rs new file mode 100644 index 0000000000000..7a18395610785 --- /dev/null +++ b/src/libstd/sys/wasi/path.rs @@ -0,0 +1,19 @@ +use crate::path::Prefix; +use crate::ffi::OsStr; + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'/' +} + +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'/' +} + +pub fn parse_prefix(_: &OsStr) -> Option> { + None +} + +pub const MAIN_SEP_STR: &str = "/"; +pub const MAIN_SEP: char = '/'; diff --git a/src/libstd/sys/wasi/pipe.rs b/src/libstd/sys/wasi/pipe.rs new file mode 100644 index 0000000000000..9f07f054362fe --- /dev/null +++ b/src/libstd/sys/wasi/pipe.rs @@ -0,0 +1,33 @@ +use crate::io::{self, IoSlice, IoSliceMut}; +use crate::sys::Void; + +pub struct AnonPipe(Void); + +impl AnonPipe { + pub fn read(&self, _buf: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { + match self.0 {} + } + + pub fn write(&self, _buf: &[u8]) -> io::Result { + match self.0 {} + } + + pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { + match self.0 {} + } + + pub fn diverge(&self) -> ! { + match self.0 {} + } +} + +pub fn read2(p1: AnonPipe, + _v1: &mut Vec, + _p2: AnonPipe, + _v2: &mut Vec) -> io::Result<()> { + match p1.0 {} +} diff --git a/src/libstd/sys/wasi/process.rs b/src/libstd/sys/wasi/process.rs new file mode 100644 index 0000000000000..788b829f4bac9 --- /dev/null +++ b/src/libstd/sys/wasi/process.rs @@ -0,0 +1,152 @@ +use crate::ffi::OsStr; +use crate::fmt; +use crate::io; +use crate::sys::fs::File; +use crate::sys::pipe::AnonPipe; +use crate::sys::{unsupported, Void}; +use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; + +//////////////////////////////////////////////////////////////////////////////// +// Command +//////////////////////////////////////////////////////////////////////////////// + +pub struct Command { + env: CommandEnv +} + +// passed back to std::process with the pipes connected to the child, if any +// were requested +pub struct StdioPipes { + pub stdin: Option, + pub stdout: Option, + pub stderr: Option, +} + +pub enum Stdio { + Inherit, + Null, + MakePipe, +} + +impl Command { + pub fn new(_program: &OsStr) -> Command { + Command { + env: Default::default() + } + } + + pub fn arg(&mut self, _arg: &OsStr) { + } + + pub fn env_mut(&mut self) -> &mut CommandEnv { + &mut self.env + } + + pub fn cwd(&mut self, _dir: &OsStr) { + } + + pub fn stdin(&mut self, _stdin: Stdio) { + } + + pub fn stdout(&mut self, _stdout: Stdio) { + } + + pub fn stderr(&mut self, _stderr: Stdio) { + } + + pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool) + -> io::Result<(Process, StdioPipes)> { + unsupported() + } +} + +impl From for Stdio { + fn from(pipe: AnonPipe) -> Stdio { + pipe.diverge() + } +} + +impl From for Stdio { + fn from(_file: File) -> Stdio { + panic!("unsupported") + } +} + +impl fmt::Debug for Command { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + Ok(()) + } +} + +pub struct ExitStatus(Void); + +impl ExitStatus { + pub fn success(&self) -> bool { + match self.0 {} + } + + pub fn code(&self) -> Option { + match self.0 {} + } +} + +impl Clone for ExitStatus { + fn clone(&self) -> ExitStatus { + match self.0 {} + } +} + +impl Copy for ExitStatus {} + +impl PartialEq for ExitStatus { + fn eq(&self, _other: &ExitStatus) -> bool { + match self.0 {} + } +} + +impl Eq for ExitStatus { +} + +impl fmt::Debug for ExitStatus { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.0 {} + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.0 {} + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(bool); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(false); + pub const FAILURE: ExitCode = ExitCode(true); + + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + +pub struct Process(Void); + +impl Process { + pub fn id(&self) -> u32 { + match self.0 {} + } + + pub fn kill(&mut self) -> io::Result<()> { + match self.0 {} + } + + pub fn wait(&mut self) -> io::Result { + match self.0 {} + } + + pub fn try_wait(&mut self) -> io::Result> { + match self.0 {} + } +} diff --git a/src/libstd/sys/wasi/stdio.rs b/src/libstd/sys/wasi/stdio.rs new file mode 100644 index 0000000000000..2bf8d803c01bb --- /dev/null +++ b/src/libstd/sys/wasi/stdio.rs @@ -0,0 +1,81 @@ +use crate::io::{self, IoSlice, IoSliceMut}; +use crate::libc; +use crate::mem::ManuallyDrop; +use crate::sys::fd::WasiFd; + +pub struct Stdin; +pub struct Stdout; +pub struct Stderr; + +impl Stdin { + pub fn new() -> io::Result { + Ok(Stdin) + } + + pub fn read(&self, data: &mut [u8]) -> io::Result { + self.read_vectored(&mut [IoSliceMut::new(data)]) + } + + pub fn read_vectored(&self, data: &mut [IoSliceMut<'_>]) -> io::Result { + ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) }) + .read(data) + } +} + +impl Stdout { + pub fn new() -> io::Result { + Ok(Stdout) + } + + pub fn write(&self, data: &[u8]) -> io::Result { + self.write_vectored(&[IoSlice::new(data)]) + } + + pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result { + ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDOUT_FILENO as u32) }) + .write(data) + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub fn new() -> io::Result { + Ok(Stderr) + } + + pub fn write(&self, data: &[u8]) -> io::Result { + self.write_vectored(&[IoSlice::new(data)]) + } + + pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result { + ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDERR_FILENO as u32) }) + .write(data) + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } +} + +impl io::Write for Stderr { + fn write(&mut self, data: &[u8]) -> io::Result { + (&*self).write(data) + } + + fn flush(&mut self) -> io::Result<()> { + (&*self).flush() + } +} + +pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; + +pub fn is_ebadf(err: &io::Error) -> bool { + err.raw_os_error() == Some(libc::__WASI_EBADF as i32) +} + +pub fn panic_output() -> Option { + Stderr::new().ok() +} diff --git a/src/libstd/sys/wasi/thread.rs b/src/libstd/sys/wasi/thread.rs new file mode 100644 index 0000000000000..5e69e4d948fee --- /dev/null +++ b/src/libstd/sys/wasi/thread.rs @@ -0,0 +1,56 @@ +use crate::cmp; +use crate::ffi::CStr; +use crate::io; +use crate::sys::cvt; +use crate::sys::{unsupported, Void}; +use crate::time::Duration; +use libc; + +pub struct Thread(Void); + +pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; + +impl Thread { + // unsafe: see thread::Builder::spawn_unchecked for safety requirements + pub unsafe fn new(_stack: usize, _p: Box) + -> io::Result + { + unsupported() + } + + pub fn yield_now() { + let ret = unsafe { libc::__wasi_sched_yield() }; + debug_assert_eq!(ret, 0); + } + + pub fn set_name(_name: &CStr) { + // nope + } + + pub fn sleep(dur: Duration) { + let mut secs = dur.as_secs(); + let mut nsecs = dur.subsec_nanos() as i32; + + unsafe { + while secs > 0 || nsecs > 0 { + let mut ts = libc::timespec { + tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t, + tv_nsec: nsecs, + }; + secs -= ts.tv_sec as u64; + cvt(libc::nanosleep(&ts, &mut ts)).unwrap(); + nsecs = 0; + } + } + } + + pub fn join(self) { + match self.0 {} + } +} + +pub mod guard { + pub type Guard = !; + pub unsafe fn current() -> Option { None } + pub unsafe fn init() -> Option { None } +} diff --git a/src/libstd/sys/wasi/time.rs b/src/libstd/sys/wasi/time.rs new file mode 100644 index 0000000000000..3f14c80928c67 --- /dev/null +++ b/src/libstd/sys/wasi/time.rs @@ -0,0 +1,76 @@ +use crate::time::Duration; +use crate::mem; +use crate::sys::cvt_wasi; +use libc; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Instant(Duration); + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SystemTime(Duration); + +pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); + +fn current_time(clock: u32) -> Duration { + unsafe { + let mut ts = mem::zeroed(); + cvt_wasi(libc::__wasi_clock_time_get( + clock, + 1, // precision... seems ignored though? + &mut ts, + )).unwrap(); + Duration::new( + (ts / 1_000_000_000) as u64, + (ts % 1_000_000_000) as u32, + ) + } +} + +impl Instant { + pub fn now() -> Instant { + Instant(current_time(libc::__WASI_CLOCK_MONOTONIC)) + } + + pub const fn zero() -> Instant { + Instant(Duration::from_secs(0)) + } + + pub fn actually_monotonic() -> bool { + true + } + + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + self.0.checked_sub(other.0) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(Instant(self.0.checked_add(*other)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(Instant(self.0.checked_sub(*other)?)) + } +} + +impl SystemTime { + pub fn now() -> SystemTime { + SystemTime(current_time(libc::__WASI_CLOCK_REALTIME)) + } + + pub fn from_wasi_timestamp(ts: libc::__wasi_timestamp_t) -> SystemTime { + SystemTime(Duration::from_nanos(ts)) + } + + pub fn sub_time(&self, other: &SystemTime) + -> Result { + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_add(*other)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_sub(*other)?)) + } +} diff --git a/src/libstd/sys/wasm/alloc.rs b/src/libstd/sys/wasm/alloc.rs index b9098548b9c1e..c1af6ec12623c 100644 --- a/src/libstd/sys/wasm/alloc.rs +++ b/src/libstd/sys/wasm/alloc.rs @@ -49,7 +49,6 @@ unsafe impl GlobalAlloc for System { #[cfg(target_feature = "atomics")] mod lock { - use crate::arch::wasm32; use crate::sync::atomic::{AtomicI32, Ordering::SeqCst}; static LOCKED: AtomicI32 = AtomicI32::new(0); @@ -61,14 +60,76 @@ mod lock { if LOCKED.swap(1, SeqCst) == 0 { return DropLock } - unsafe { - let r = wasm32::i32_atomic_wait( - &LOCKED as *const AtomicI32 as *mut i32, - 1, // expected value - -1, // timeout - ); - debug_assert!(r == 0 || r == 1); - } + // Ok so here's where things get a little depressing. At this point + // in time we need to synchronously acquire a lock, but we're + // contending with some other thread. Typically we'd execute some + // form of `i32.atomic.wait` like so: + // + // unsafe { + // let r = core::arch::wasm32::i32_atomic_wait( + // &LOCKED as *const AtomicI32 as *mut i32, + // 1, // expected value + // -1, // timeout + // ); + // debug_assert!(r == 0 || r == 1); + // } + // + // Unfortunately though in doing so we would cause issues for the + // main thread. The main thread in a web browser *cannot ever + // block*, no exceptions. This means that the main thread can't + // actually execute the `i32.atomic.wait` instruction. + // + // As a result if we want to work within the context of browsers we + // need to figure out some sort of allocation scheme for the main + // thread where when there's contention on the global malloc lock we + // do... something. + // + // Possible ideas include: + // + // 1. Attempt to acquire the global lock. If it fails, fall back to + // memory allocation via `memory.grow`. Later just ... somehow + // ... inject this raw page back into the main allocator as it + // gets sliced up over time. This strategy has the downside of + // forcing allocation of a page to happen whenever the main + // thread contents with other threads, which is unfortunate. + // + // 2. Maintain a form of "two level" allocator scheme where the main + // thread has its own allocator. Somehow this allocator would + // also be balanced with a global allocator, not only to have + // allocations cross between threads but also to ensure that the + // two allocators stay "balanced" in terms of free'd memory and + // such. This, however, seems significantly complicated. + // + // Out of a lack of other ideas, the current strategy implemented + // here is to simply spin. Typical spin loop algorithms have some + // form of "hint" here to the CPU that it's what we're doing to + // ensure that the CPU doesn't get too hot, but wasm doesn't have + // such an instruction. + // + // To be clear, spinning here is not a great solution. + // Another thread with the lock may take quite a long time to wake + // up. For example it could be in `memory.grow` or it could be + // evicted from the CPU for a timeslice like 10ms. For these periods + // of time our thread will "helpfully" sit here and eat CPU time + // until it itself is evicted or the lock holder finishes. This + // means we're just burning and wasting CPU time to no one's + // benefit. + // + // Spinning does have the nice properties, though, of being + // semantically correct, being fair to all threads for memory + // allocation, and being simple enough to implement. + // + // This will surely (hopefully) be replaced in the future with a + // real memory allocator that can handle the restriction of the main + // thread. + // + // + // FIXME: We can also possibly add an optimization here to detect + // when a thread is the main thread or not and block on all + // non-main-thread threads. Currently, however, we have no way + // of knowing which wasm thread is on the browser main thread, but + // if we could figure out we could at least somewhat mitigate the + // cost of this spinning. } } @@ -76,12 +137,16 @@ mod lock { fn drop(&mut self) { let r = LOCKED.swap(0, SeqCst); debug_assert_eq!(r, 1); - unsafe { - wasm32::atomic_notify( - &LOCKED as *const AtomicI32 as *mut i32, - 1, // only one thread - ); - } + + // Note that due to the above logic we don't actually need to wake + // anyone up, but if we did it'd likely look something like this: + // + // unsafe { + // core::arch::wasm32::atomic_notify( + // &LOCKED as *const AtomicI32 as *mut i32, + // 1, // only one thread + // ); + // } } } } diff --git a/src/libstd/sys/wasm/backtrace.rs b/src/libstd/sys/wasm/backtrace.rs deleted file mode 100644 index 7d56b298997aa..0000000000000 --- a/src/libstd/sys/wasm/backtrace.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::io; -use crate::sys::unsupported; -use crate::sys_common::backtrace::Frame; - -pub struct BacktraceContext; - -pub fn unwind_backtrace(_frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - unsupported() -} - -pub fn resolve_symname(_frame: Frame, - _callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - unsupported() -} - -pub fn foreach_symbol_fileline(_: Frame, - _: F, - _: &BacktraceContext) -> io::Result - where F: FnMut(&[u8], u32) -> io::Result<()> -{ - unsupported() -} diff --git a/src/libstd/sys/wasm/fs.rs b/src/libstd/sys/wasm/fs.rs index 485d2c87fbd2d..e9095b375fe5d 100644 --- a/src/libstd/sys/wasm/fs.rs +++ b/src/libstd/sys/wasm/fs.rs @@ -1,7 +1,7 @@ use crate::ffi::OsString; use crate::fmt; use crate::hash::{Hash, Hasher}; -use crate::io::{self, SeekFrom}; +use crate::io::{self, SeekFrom, IoSlice, IoSliceMut}; use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; use crate::sys::{unsupported, Void}; @@ -82,7 +82,7 @@ impl Eq for FilePermissions { } impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } @@ -125,13 +125,13 @@ impl Hash for FileType { } impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } @@ -200,10 +200,18 @@ impl File { match self.0 {} } + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } + pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { + match self.0 {} + } + pub fn flush(&self) -> io::Result<()> { match self.0 {} } @@ -236,7 +244,7 @@ impl DirBuilder { } impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } diff --git a/src/libstd/sys/wasm/io.rs b/src/libstd/sys/wasm/io.rs index 8b02d3fd19d30..4b423a5cbc11a 100644 --- a/src/libstd/sys/wasm/io.rs +++ b/src/libstd/sys/wasm/io.rs @@ -1,9 +1,9 @@ -pub struct IoVec<'a>(&'a [u8]); +pub struct IoSlice<'a>(&'a [u8]); -impl<'a> IoVec<'a> { +impl<'a> IoSlice<'a> { #[inline] - pub fn new(buf: &'a [u8]) -> IoVec<'a> { - IoVec(buf) + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice(buf) } #[inline] @@ -12,12 +12,12 @@ impl<'a> IoVec<'a> { } } -pub struct IoVecMut<'a>(&'a mut [u8]); +pub struct IoSliceMut<'a>(&'a mut [u8]); -impl<'a> IoVecMut<'a> { +impl<'a> IoSliceMut<'a> { #[inline] - pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { - IoVecMut(buf) + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut(buf) } #[inline] diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs index 1828cce4e520e..7d157709eb6bf 100644 --- a/src/libstd/sys/wasm/mod.rs +++ b/src/libstd/sys/wasm/mod.rs @@ -23,8 +23,6 @@ use crate::time::Duration; pub mod alloc; pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; pub mod cmath; pub mod env; pub mod fs; @@ -32,7 +30,6 @@ pub mod io; pub mod memchr; pub mod net; pub mod os; -pub mod os_str; pub mod path; pub mod pipe; pub mod process; @@ -41,7 +38,9 @@ pub mod thread; pub mod time; pub mod stdio; -cfg_if! { +pub use crate::sys_common::os_str_bytes as os_str; + +cfg_if::cfg_if! { if #[cfg(target_feature = "atomics")] { #[path = "condvar_atomics.rs"] pub mod condvar; diff --git a/src/libstd/sys/wasm/net.rs b/src/libstd/sys/wasm/net.rs index 1249832fb09d2..d50f989d2bb5f 100644 --- a/src/libstd/sys/wasm/net.rs +++ b/src/libstd/sys/wasm/net.rs @@ -1,5 +1,5 @@ use crate::fmt; -use crate::io::{self, IoVec, IoVecMut}; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; use crate::time::Duration; use crate::sys::{unsupported, Void}; @@ -40,7 +40,7 @@ impl TcpStream { match self.0 {} } - pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result { + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { match self.0 {} } @@ -48,7 +48,7 @@ impl TcpStream { match self.0 {} } - pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result { + pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { match self.0 {} } @@ -94,7 +94,7 @@ impl TcpStream { } impl fmt::Debug for TcpStream { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } @@ -144,7 +144,7 @@ impl TcpListener { } impl fmt::Debug for TcpListener { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } @@ -156,6 +156,10 @@ impl UdpSocket { unsupported() } + pub fn peer_addr(&self) -> io::Result { + match self.0 {} + } + pub fn socket_addr(&self) -> io::Result { match self.0 {} } @@ -278,7 +282,7 @@ impl UdpSocket { } impl fmt::Debug for UdpSocket { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } @@ -298,10 +302,10 @@ impl Iterator for LookupHost { } } -impl<'a> TryFrom<&'a str> for LookupHost { +impl TryFrom<&str> for LookupHost { type Error = io::Error; - fn try_from(_v: &'a str) -> io::Result { + fn try_from(_v: &str) -> io::Result { unsupported() } } diff --git a/src/libstd/sys/wasm/os.rs b/src/libstd/sys/wasm/os.rs index 145f9ccd73a8f..5d21999a991e1 100644 --- a/src/libstd/sys/wasm/os.rs +++ b/src/libstd/sys/wasm/os.rs @@ -24,7 +24,7 @@ pub fn chdir(_: &path::Path) -> io::Result<()> { pub struct SplitPaths<'a>(&'a Void); -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths { +pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { panic!("unsupported") } @@ -45,7 +45,7 @@ pub fn join_paths(_paths: I) -> Result } impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "not supported on wasm yet".fmt(f) } } diff --git a/src/libstd/sys/wasm/os_str.rs b/src/libstd/sys/wasm/os_str.rs deleted file mode 100644 index 79b43458d00f3..0000000000000 --- a/src/libstd/sys/wasm/os_str.rs +++ /dev/null @@ -1,180 +0,0 @@ -/// The underlying OsString/OsStr implementation on Unix systems: just -/// a `Vec`/`[u8]`. - -use crate::borrow::Cow; -use crate::fmt; -use crate::str; -use crate::mem; -use crate::rc::Rc; -use crate::sync::Arc; -use crate::sys_common::{AsInner, IntoInner}; -use crate::sys_common::bytestring::debug_fmt_bytestring; - -use core::str::lossy::Utf8Lossy; - -#[derive(Clone, Hash)] -pub struct Buf { - pub inner: Vec -} - -pub struct Slice { - pub inner: [u8] -} - -impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - debug_fmt_bytestring(&self.inner, formatter) - } -} - -impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) - } -} - -impl fmt::Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), formatter) - } -} - -impl fmt::Display for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), formatter) - } -} - -impl IntoInner> for Buf { - fn into_inner(self) -> Vec { - self.inner - } -} - -impl AsInner<[u8]> for Buf { - fn as_inner(&self) -> &[u8] { - &self.inner - } -} - - -impl Buf { - pub fn from_string(s: String) -> Buf { - Buf { inner: s.into_bytes() } - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Buf { - Buf { - inner: Vec::with_capacity(capacity) - } - } - - #[inline] - pub fn clear(&mut self) { - self.inner.clear() - } - - #[inline] - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.inner.reserve(additional) - } - - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - self.inner.reserve_exact(additional) - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.inner.shrink_to(min_capacity) - } - - pub fn as_slice(&self) -> &Slice { - unsafe { mem::transmute(&*self.inner) } - } - - pub fn into_string(self) -> Result { - String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } ) - } - - pub fn push_slice(&mut self, s: &Slice) { - self.inner.extend_from_slice(&s.inner) - } - - #[inline] - pub fn into_box(self) -> Box { - unsafe { mem::transmute(self.inner.into_boxed_slice()) } - } - - #[inline] - pub fn from_box(boxed: Box) -> Buf { - let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; - Buf { inner: inner.into_vec() } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - self.as_slice().into_arc() - } - - #[inline] - pub fn into_rc(&self) -> Rc { - self.as_slice().into_rc() - } -} - -impl Slice { - fn from_u8_slice(s: &[u8]) -> &Slice { - unsafe { mem::transmute(s) } - } - - pub fn from_str(s: &str) -> &Slice { - Slice::from_u8_slice(s.as_bytes()) - } - - pub fn to_str(&self) -> Option<&str> { - str::from_utf8(&self.inner).ok() - } - - pub fn to_string_lossy(&self) -> Cow { - String::from_utf8_lossy(&self.inner) - } - - pub fn to_owned(&self) -> Buf { - Buf { inner: self.inner.to_vec() } - } - - #[inline] - pub fn into_box(&self) -> Box { - let boxed: Box<[u8]> = self.inner.into(); - unsafe { mem::transmute(boxed) } - } - - pub fn empty_box() -> Box { - let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - let arc: Arc<[u8]> = Arc::from(&self.inner); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } - } - - #[inline] - pub fn into_rc(&self) -> Rc { - let rc: Rc<[u8]> = Rc::from(&self.inner); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } - } -} diff --git a/src/libstd/sys/wasm/path.rs b/src/libstd/sys/wasm/path.rs index 5c062e7c97cd3..7a18395610785 100644 --- a/src/libstd/sys/wasm/path.rs +++ b/src/libstd/sys/wasm/path.rs @@ -11,7 +11,7 @@ pub fn is_verbatim_sep(b: u8) -> bool { b == b'/' } -pub fn parse_prefix(_: &OsStr) -> Option { +pub fn parse_prefix(_: &OsStr) -> Option> { None } diff --git a/src/libstd/sys/wasm/pipe.rs b/src/libstd/sys/wasm/pipe.rs index 2582b993b608e..9f07f054362fe 100644 --- a/src/libstd/sys/wasm/pipe.rs +++ b/src/libstd/sys/wasm/pipe.rs @@ -1,4 +1,4 @@ -use crate::io; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::sys::Void; pub struct AnonPipe(Void); @@ -8,10 +8,18 @@ impl AnonPipe { match self.0 {} } + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } + pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/wasm/process.rs index c49daaa16320e..a02e009d95356 100644 --- a/src/libstd/sys/wasm/process.rs +++ b/src/libstd/sys/wasm/process.rs @@ -73,7 +73,7 @@ impl From for Stdio { } impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { Ok(()) } } @@ -108,13 +108,13 @@ impl Eq for ExitStatus { } impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 {} } } diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index a65c413119f8c..61b4003cd3d14 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -1,4 +1,3 @@ -use crate::boxed::FnBox; use crate::ffi::CStr; use crate::io; use crate::sys::{unsupported, Void}; @@ -10,7 +9,7 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, _p: Box) + pub unsafe fn new(_stack: usize, _p: Box) -> io::Result { unsupported() @@ -60,7 +59,7 @@ pub mod guard { pub unsafe fn init() -> Option { None } } -cfg_if! { +cfg_if::cfg_if! { if #[cfg(all(target_feature = "atomics", feature = "wasm-bindgen-threads"))] { #[link(wasm_import_module = "__wbindgen_thread_xform__")] extern { diff --git a/src/libstd/sys/wasm/thread_local_atomics.rs b/src/libstd/sys/wasm/thread_local_atomics.rs index b408ad0d5c1f8..3dc0bb24553fd 100644 --- a/src/libstd/sys/wasm/thread_local_atomics.rs +++ b/src/libstd/sys/wasm/thread_local_atomics.rs @@ -11,7 +11,7 @@ struct ThreadControlBlock { impl ThreadControlBlock { fn new() -> ThreadControlBlock { ThreadControlBlock { - keys: [0 as *mut u8; MAX_KEYS], + keys: [core::ptr::null_mut(); MAX_KEYS], } } diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs index c1228a1b75e39..3f71461eea487 100644 --- a/src/libstd/sys/wasm/time.rs +++ b/src/libstd/sys/wasm/time.rs @@ -22,8 +22,8 @@ impl Instant { false } - pub fn sub_instant(&self, other: &Instant) -> Duration { - self.0 - other.0 + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + self.0.checked_sub(other.0) } pub fn checked_add_duration(&self, other: &Duration) -> Option { diff --git a/src/libstd/sys/windows/args.rs b/src/libstd/sys/windows/args.rs index 3f10e6e5983eb..b04bb484eedb9 100644 --- a/src/libstd/sys/windows/args.rs +++ b/src/libstd/sys/windows/args.rs @@ -164,13 +164,13 @@ pub struct ArgsInnerDebug<'a> { } impl<'a> fmt::Debug for ArgsInnerDebug<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.args.parsed_args_list.as_slice().fmt(f) } } impl Args { - pub fn inner_debug(&self) -> ArgsInnerDebug { + pub fn inner_debug(&self) -> ArgsInnerDebug<'_> { ArgsInnerDebug { args: self } diff --git a/src/libstd/sys/windows/backtrace/backtrace_gnu.rs b/src/libstd/sys/windows/backtrace/backtrace_gnu.rs deleted file mode 100644 index 7ac1f8122f781..0000000000000 --- a/src/libstd/sys/windows/backtrace/backtrace_gnu.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::io; -use crate::sys::c; -use crate::path::PathBuf; -use crate::fs::{OpenOptions, File}; -use crate::sys::ext::fs::OpenOptionsExt; -use crate::sys::handle::Handle; - -use libc::c_char; -use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte}; - -fn query_full_process_image_name() -> io::Result { - unsafe { - let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION, - c::FALSE, - c::GetCurrentProcessId())); - fill_utf16_buf(|buf, mut sz| { - if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 { - 0 - } else { - sz - } - }, os2path) - } -} - -fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> { - // We query the current image name, open the file without FILE_SHARE_DELETE so it - // can't be moved and then get the current image name again. If the names are the - // same than we have successfully locked the file - let image_name1 = query_full_process_image_name()?; - let file = OpenOptions::new() - .read(true) - .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE) - .open(&image_name1)?; - let image_name2 = query_full_process_image_name()?; - - if image_name1 != image_name2 { - return Err(io::Error::new(io::ErrorKind::Other, - "executable moved while trying to lock it")); - } - - Ok((image_name1, file)) -} - -// Get the executable filename for libbacktrace -// This returns the path in the ANSI code page and a File which should remain open -// for as long as the path should remain valid -pub fn get_executable_filename() -> io::Result<(Vec, File)> { - let (executable, file) = lock_and_get_executable_filename()?; - let u16_executable = to_u16s(executable.into_os_string())?; - Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS, - &u16_executable, true)?, file)) -} diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs deleted file mode 100644 index c5b0cc8721087..0000000000000 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ /dev/null @@ -1,355 +0,0 @@ -//! As always, windows has something very different than unix, we mainly want -//! to avoid having to depend too much on libunwind for windows. -//! -//! If you google around, you'll find a fair bit of references to built-in -//! functions to get backtraces on windows. It turns out that most of these are -//! in an external library called dbghelp. I was unable to find this library -//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent -//! of it. -//! -//! You'll also find that there's a function called CaptureStackBackTrace -//! mentioned frequently (which is also easy to use), but sadly I didn't have a -//! copy of that function in my mingw install (maybe it was broken?). Instead, -//! this takes the route of using StackWalk64 in order to walk the stack. - -#![allow(deprecated)] // dynamic_lib - -use crate::io; -use crate::mem; -use crate::ptr; -use crate::sys::c; -use crate::sys::dynamic_lib::DynamicLibrary; -use crate::sys_common::backtrace::Frame; - -use libc::c_void; - -macro_rules! sym { - ($lib:expr, $e:expr, $t:ident) => ( - $lib.symbol($e).map(|f| unsafe { - $crate::mem::transmute::(f) - }) - ) -} - -mod printing; - -#[cfg(target_env = "gnu")] -#[path = "backtrace_gnu.rs"] -pub mod gnu; - -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; -use self::printing::{load_printing_fns_64, load_printing_fns_ex}; - -pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { - let dbghelp = DynamicLibrary::open("dbghelp.dll")?; - - // Fetch the symbols necessary from dbghelp.dll - let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; - let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; - - // StackWalkEx might not be present and we'll fall back to StackWalk64 - let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) { - Ok(StackWalkEx) => { - StackWalkVariant::StackWalkEx(StackWalkEx, load_printing_fns_ex(&dbghelp)?) - } - Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) { - Ok(StackWalk64) => { - StackWalkVariant::StackWalk64(StackWalk64, load_printing_fns_64(&dbghelp)?) - } - Err(..) => return Err(e), - }, - }; - - // Allocate necessary structures for doing the stack walk - let process = unsafe { c::GetCurrentProcess() }; - - let backtrace_context = BacktraceContext { - handle: process, - SymCleanup, - StackWalkVariant: sw_var, - dbghelp, - }; - - // Initialize this process's symbols - let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) }; - if ret != c::TRUE { - return Ok((0, backtrace_context)); - } - - // And now that we're done with all the setup, do the stack walking! - match backtrace_context.StackWalkVariant { - StackWalkVariant::StackWalkEx(StackWalkEx, _) => { - set_frames(StackWalkEx, frames).map(|i| (i, backtrace_context)) - } - - StackWalkVariant::StackWalk64(StackWalk64, _) => { - set_frames(StackWalk64, frames).map(|i| (i, backtrace_context)) - } - } -} - -fn set_frames(StackWalk: W, frames: &mut [Frame]) -> io::Result { - let process = unsafe { c::GetCurrentProcess() }; - let thread = unsafe { c::GetCurrentProcess() }; - let mut context: c::CONTEXT = unsafe { mem::zeroed() }; - unsafe { c::RtlCaptureContext(&mut context) }; - let mut frame = W::Item::new(); - let image = frame.init(&context); - - let mut i = 0; - while i < frames.len() - && StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE - { - let addr = frame.get_addr(); - frames[i] = Frame { - symbol_addr: addr, - exact_position: addr, - inline_context: frame.get_inline_context(), - }; - - i += 1 - } - Ok(i) -} - -type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL; -type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL; - -type StackWalkExFn = unsafe extern "system" fn( - c::DWORD, - c::HANDLE, - c::HANDLE, - *mut c::STACKFRAME_EX, - *mut c::CONTEXT, - *mut c_void, - *mut c_void, - *mut c_void, - *mut c_void, - c::DWORD, -) -> c::BOOL; - -type StackWalk64Fn = unsafe extern "system" fn( - c::DWORD, - c::HANDLE, - c::HANDLE, - *mut c::STACKFRAME64, - *mut c::CONTEXT, - *mut c_void, - *mut c_void, - *mut c_void, - *mut c_void, -) -> c::BOOL; - -trait StackWalker { - type Item: StackFrame; - - fn walk( - &self, - _: c::DWORD, - _: c::HANDLE, - _: c::HANDLE, - _: &mut Self::Item, - _: &mut c::CONTEXT - ) -> c::BOOL; -} - -impl StackWalker for StackWalkExFn { - type Item = c::STACKFRAME_EX; - fn walk( - &self, - image: c::DWORD, - process: c::HANDLE, - thread: c::HANDLE, - frame: &mut Self::Item, - context: &mut c::CONTEXT, - ) -> c::BOOL { - unsafe { - self( - image, - process, - thread, - frame, - context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - 0, - ) - } - } -} - -impl StackWalker for StackWalk64Fn { - type Item = c::STACKFRAME64; - fn walk( - &self, - image: c::DWORD, - process: c::HANDLE, - thread: c::HANDLE, - frame: &mut Self::Item, - context: &mut c::CONTEXT, - ) -> c::BOOL { - unsafe { - self( - image, - process, - thread, - frame, - context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ) - } - } -} - -trait StackFrame { - fn new() -> Self; - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD; - fn get_addr(&self) -> *const u8; - fn get_inline_context(&self) -> u32; -} - -impl StackFrame for c::STACKFRAME_EX { - fn new() -> c::STACKFRAME_EX { - unsafe { mem::zeroed() } - } - - #[cfg(target_arch = "x86")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Eip as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Esp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Ebp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_I386 - } - - #[cfg(target_arch = "x86_64")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Rip as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Rsp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Rbp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_AMD64 - } - - #[cfg(target_arch = "arm")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Pc as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Sp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.R11 as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_ARMNT - } - - #[cfg(target_arch = "aarch64")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Pc as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Sp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Fp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_ARM64 - } - - fn get_addr(&self) -> *const u8 { - (self.AddrPC.Offset - 1) as *const u8 - } - - fn get_inline_context(&self) -> u32 { - self.InlineFrameContext - } -} - -impl StackFrame for c::STACKFRAME64 { - fn new() -> c::STACKFRAME64 { - unsafe { mem::zeroed() } - } - - #[cfg(target_arch = "x86")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Eip as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Esp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Ebp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_I386 - } - - #[cfg(target_arch = "x86_64")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Rip as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Rsp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Rbp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_AMD64 - } - - #[cfg(target_arch = "arm")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Pc as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Sp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.R11 as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_ARMNT - } - - #[cfg(target_arch = "aarch64")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Pc as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Sp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Fp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_ARM64 - } - - fn get_addr(&self) -> *const u8 { - (self.AddrPC.Offset - 1) as *const u8 - } - - fn get_inline_context(&self) -> u32 { - 0 - } -} - -enum StackWalkVariant { - StackWalkEx(StackWalkExFn, printing::PrintingFnsEx), - StackWalk64(StackWalk64Fn, printing::PrintingFns64), -} - -pub struct BacktraceContext { - handle: c::HANDLE, - SymCleanup: SymCleanupFn, - // Only used in printing for msvc and not gnu - // The gnu version is effectively a ZST dummy. - #[allow(dead_code)] - StackWalkVariant: StackWalkVariant, - // keeping DynamycLibrary loaded until its functions no longer needed - #[allow(dead_code)] - dbghelp: DynamicLibrary, -} - -impl Drop for BacktraceContext { - fn drop(&mut self) { - unsafe { - (self.SymCleanup)(self.handle); - } - } -} diff --git a/src/libstd/sys/windows/backtrace/printing/mod.rs b/src/libstd/sys/windows/backtrace/printing/mod.rs deleted file mode 100644 index 9497d51ac1799..0000000000000 --- a/src/libstd/sys/windows/backtrace/printing/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -#[cfg(target_env = "msvc")] -#[path = "msvc.rs"] -mod printing; - -#[cfg(target_env = "gnu")] -mod printing { - pub use crate::sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; - - // dummy functions to mirror those present in msvc version. - use crate::sys::dynamic_lib::DynamicLibrary; - use crate::io; - pub struct PrintingFnsEx {} - pub struct PrintingFns64 {} - pub fn load_printing_fns_ex(_: &DynamicLibrary) -> io::Result { - Ok(PrintingFnsEx{}) - } - pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result { - Ok(PrintingFns64{}) - } -} - -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; -pub use self::printing::{load_printing_fns_ex, load_printing_fns_64, - PrintingFnsEx, PrintingFns64}; diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs deleted file mode 100644 index 13a1512d0eb39..0000000000000 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ /dev/null @@ -1,208 +0,0 @@ -use crate::ffi::CStr; -use crate::io; -use crate::mem; -use crate::sys::backtrace::BacktraceContext; -use crate::sys::backtrace::StackWalkVariant; -use crate::sys::c; -use crate::sys::dynamic_lib::DynamicLibrary; -use crate::sys_common::backtrace::Frame; - -use libc::{c_char, c_ulong}; - -// Structs holding printing functions and loaders for them -// Two versions depending on whether dbghelp.dll has StackWalkEx or not -// (the former being in newer Windows versions, the older being in Win7 and before) -pub struct PrintingFnsEx { - resolve_symname: SymFromInlineContextFn, - sym_get_line: SymGetLineFromInlineContextFn, -} -pub struct PrintingFns64 { - resolve_symname: SymFromAddrFn, - sym_get_line: SymGetLineFromAddr64Fn, -} - -pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result { - Ok(PrintingFnsEx { - resolve_symname: sym!(dbghelp, "SymFromInlineContext", SymFromInlineContextFn)?, - sym_get_line: sym!( - dbghelp, - "SymGetLineFromInlineContext", - SymGetLineFromInlineContextFn - )?, - }) -} -pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result { - Ok(PrintingFns64 { - resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?, - sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn)?, - }) -} - -type SymFromAddrFn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; -type SymFromInlineContextFn = - unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; - -type SymGetLineFromAddr64Fn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL; -type SymGetLineFromInlineContextFn = unsafe extern "system" fn( - c::HANDLE, - u64, - c::ULONG, - u64, - *mut c::DWORD, - *mut c::IMAGEHLP_LINE64, -) -> c::BOOL; - -/// Converts a pointer to symbol to its string value. -pub fn resolve_symname(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()>, -{ - match context.StackWalkVariant { - StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal( - |process: c::HANDLE, - symbol_address: u64, - inline_context: c::ULONG, - info: *mut c::SYMBOL_INFO| unsafe { - let mut displacement = 0u64; - (fns.resolve_symname)( - process, - symbol_address, - inline_context, - &mut displacement, - info, - ) - }, - frame, - callback, - context, - ), - StackWalkVariant::StackWalk64(_, ref fns) => resolve_symname_internal( - |process: c::HANDLE, - symbol_address: u64, - _inline_context: c::ULONG, - info: *mut c::SYMBOL_INFO| unsafe { - let mut displacement = 0u64; - (fns.resolve_symname)(process, symbol_address, &mut displacement, info) - }, - frame, - callback, - context, - ), - } -} - -fn resolve_symname_internal( - mut symbol_resolver: R, - frame: Frame, - callback: F, - context: &BacktraceContext, -) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()>, - R: FnMut(c::HANDLE, u64, c::ULONG, *mut c::SYMBOL_INFO) -> c::BOOL, -{ - unsafe { - let mut info: c::SYMBOL_INFO = mem::zeroed(); - info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; - // the struct size in C. the value is different to - // `size_of::() - MAX_SYM_NAME + 1` (== 81) - // due to struct alignment. - info.SizeOfStruct = 88; - - let ret = symbol_resolver( - context.handle, - frame.symbol_addr as u64, - frame.inline_context, - &mut info, - ); - let valid_range = if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize { - if info.Size != 0 { - (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize - } else { - true - } - } else { - false - }; - let symname = if valid_range { - let ptr = info.Name.as_ptr() as *const c_char; - CStr::from_ptr(ptr).to_str().ok() - } else { - None - }; - callback(symname) - } -} - -pub fn foreach_symbol_fileline( - frame: Frame, - callback: F, - context: &BacktraceContext, -) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()>, -{ - match context.StackWalkVariant { - StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal( - |process: c::HANDLE, - frame_address: u64, - inline_context: c::ULONG, - line: *mut c::IMAGEHLP_LINE64| unsafe { - let mut displacement = 0u32; - (fns.sym_get_line)( - process, - frame_address, - inline_context, - 0, - &mut displacement, - line, - ) - }, - frame, - callback, - context, - ), - StackWalkVariant::StackWalk64(_, ref fns) => foreach_symbol_fileline_iternal( - |process: c::HANDLE, - frame_address: u64, - _inline_context: c::ULONG, - line: *mut c::IMAGEHLP_LINE64| unsafe { - let mut displacement = 0u32; - (fns.sym_get_line)(process, frame_address, &mut displacement, line) - }, - frame, - callback, - context, - ), - } -} - -fn foreach_symbol_fileline_iternal( - mut line_getter: G, - frame: Frame, - mut callback: F, - context: &BacktraceContext, -) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()>, - G: FnMut(c::HANDLE, u64, c::ULONG, *mut c::IMAGEHLP_LINE64) -> c::BOOL, -{ - unsafe { - let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); - line.SizeOfStruct = mem::size_of::() as u32; - - let ret = line_getter( - context.handle, - frame.exact_position as u64, - frame.inline_context, - &mut line, - ); - if ret == c::TRUE { - let name = CStr::from_ptr(line.Filename).to_bytes(); - callback(name, line.LineNumber as u32)?; - } - Ok(false) - } -} diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 518eccf754cff..6ad338660c338 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -5,8 +5,6 @@ #![unstable(issue = "0", feature = "windows_c")] use crate::os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort, c_char}; -#[cfg(target_arch = "x86_64")] -use crate::os::raw::c_ulonglong; use crate::ptr; use libc::{wchar_t, size_t, c_void}; @@ -33,10 +31,6 @@ pub type WORD = u16; pub type CHAR = c_char; pub type ULONG_PTR = usize; pub type ULONG = c_ulong; -#[cfg(target_arch = "x86_64")] -pub type ULONGLONG = u64; -#[cfg(target_arch = "x86_64")] -pub type DWORDLONG = ULONGLONG; pub type LPBOOL = *mut BOOL; pub type LPBYTE = *mut BYTE; @@ -108,11 +102,6 @@ pub const SECURITY_SQOS_PRESENT: DWORD = 0x00100000; pub const FIONBIO: c_ulong = 0x8004667e; -#[cfg(target_arch = "arm")] -const ARM_MAX_BREAKPOINTS: usize = 8; -#[cfg(target_arch = "arm")] -const ARM_MAX_WATCHPOINTS: usize = 1; - #[repr(C)] #[derive(Copy)] pub struct WIN32_FIND_DATAW { @@ -270,22 +259,6 @@ pub const WAIT_OBJECT_0: DWORD = 0x00000000; pub const WAIT_TIMEOUT: DWORD = 258; pub const WAIT_FAILED: DWORD = 0xFFFFFFFF; -#[cfg(target_env = "msvc")] -#[cfg(feature = "backtrace")] -pub const MAX_SYM_NAME: usize = 2000; -#[cfg(target_arch = "x86")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c; -#[cfg(target_arch = "x86_64")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664; -#[cfg(target_arch = "aarch64")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_ARM64: DWORD = 0xAA64; -#[cfg(target_arch = "arm")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_ARMNT: DWORD = 0x01c4; - pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; @@ -580,41 +553,6 @@ pub struct OVERLAPPED { pub hEvent: HANDLE, } -#[repr(C)] -#[cfg(target_env = "msvc")] -#[cfg(feature = "backtrace")] -pub struct SYMBOL_INFO { - pub SizeOfStruct: c_ulong, - pub TypeIndex: c_ulong, - pub Reserved: [u64; 2], - pub Index: c_ulong, - pub Size: c_ulong, - pub ModBase: u64, - pub Flags: c_ulong, - pub Value: u64, - pub Address: u64, - pub Register: c_ulong, - pub Scope: c_ulong, - pub Tag: c_ulong, - pub NameLen: c_ulong, - pub MaxNameLen: c_ulong, - // note that windows has this as 1, but it basically just means that - // the name is inline at the end of the struct. For us, we just bump - // the struct size up to MAX_SYM_NAME. - pub Name: [c_char; MAX_SYM_NAME], -} - -#[repr(C)] -#[cfg(target_env = "msvc")] -#[cfg(feature = "backtrace")] -pub struct IMAGEHLP_LINE64 { - pub SizeOfStruct: u32, - pub Key: *const c_void, - pub LineNumber: u32, - pub Filename: *const c_char, - pub Address: u64, -} - #[repr(C)] #[allow(dead_code)] // we only use some variants pub enum ADDRESS_MODE { @@ -624,280 +562,8 @@ pub enum ADDRESS_MODE { AddrModeFlat, } -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct ADDRESS64 { - pub Offset: u64, - pub Segment: u16, - pub Mode: ADDRESS_MODE, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct STACKFRAME_EX { - pub AddrPC: ADDRESS64, - pub AddrReturn: ADDRESS64, - pub AddrFrame: ADDRESS64, - pub AddrStack: ADDRESS64, - pub AddrBStore: ADDRESS64, - pub FuncTableEntry: *mut c_void, - pub Params: [u64; 4], - pub Far: BOOL, - pub Virtual: BOOL, - pub Reserved: [u64; 3], - pub KdHelp: KDHELP64, - pub StackFrameSize: DWORD, - pub InlineFrameContext: DWORD, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct STACKFRAME64 { - pub AddrPC: ADDRESS64, - pub AddrReturn: ADDRESS64, - pub AddrFrame: ADDRESS64, - pub AddrStack: ADDRESS64, - pub AddrBStore: ADDRESS64, - pub FuncTableEntry: *mut c_void, - pub Params: [u64; 4], - pub Far: BOOL, - pub Virtual: BOOL, - pub Reserved: [u64; 3], - pub KdHelp: KDHELP64, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct KDHELP64 { - pub Thread: u64, - pub ThCallbackStack: DWORD, - pub ThCallbackBStore: DWORD, - pub NextCallback: DWORD, - pub FramePointer: DWORD, - pub KiCallUserMode: u64, - pub KeUserCallbackDispatcher: u64, - pub SystemRangeStart: u64, - pub KiUserExceptionDispatcher: u64, - pub StackBase: u64, - pub StackLimit: u64, - pub Reserved: [u64; 5], -} - -#[cfg(target_arch = "x86")] -#[repr(C)] -pub struct CONTEXT { - pub ContextFlags: DWORD, - pub Dr0: DWORD, - pub Dr1: DWORD, - pub Dr2: DWORD, - pub Dr3: DWORD, - pub Dr6: DWORD, - pub Dr7: DWORD, - pub FloatSave: FLOATING_SAVE_AREA, - pub SegGs: DWORD, - pub SegFs: DWORD, - pub SegEs: DWORD, - pub SegDs: DWORD, - pub Edi: DWORD, - pub Esi: DWORD, - pub Ebx: DWORD, - pub Edx: DWORD, - pub Ecx: DWORD, - pub Eax: DWORD, - pub Ebp: DWORD, - pub Eip: DWORD, - pub SegCs: DWORD, - pub EFlags: DWORD, - pub Esp: DWORD, - pub SegSs: DWORD, - pub ExtendedRegisters: [u8; 512], -} - -#[cfg(target_arch = "x86")] -#[repr(C)] -pub struct FLOATING_SAVE_AREA { - pub ControlWord: DWORD, - pub StatusWord: DWORD, - pub TagWord: DWORD, - pub ErrorOffset: DWORD, - pub ErrorSelector: DWORD, - pub DataOffset: DWORD, - pub DataSelector: DWORD, - pub RegisterArea: [u8; 80], - pub Cr0NpxState: DWORD, -} - -#[cfg(target_arch = "x86_64")] -#[repr(C, align(16))] -pub struct CONTEXT { - pub P1Home: DWORDLONG, - pub P2Home: DWORDLONG, - pub P3Home: DWORDLONG, - pub P4Home: DWORDLONG, - pub P5Home: DWORDLONG, - pub P6Home: DWORDLONG, - - pub ContextFlags: DWORD, - pub MxCsr: DWORD, - - pub SegCs: WORD, - pub SegDs: WORD, - pub SegEs: WORD, - pub SegFs: WORD, - pub SegGs: WORD, - pub SegSs: WORD, - pub EFlags: DWORD, - - pub Dr0: DWORDLONG, - pub Dr1: DWORDLONG, - pub Dr2: DWORDLONG, - pub Dr3: DWORDLONG, - pub Dr6: DWORDLONG, - pub Dr7: DWORDLONG, - - pub Rax: DWORDLONG, - pub Rcx: DWORDLONG, - pub Rdx: DWORDLONG, - pub Rbx: DWORDLONG, - pub Rsp: DWORDLONG, - pub Rbp: DWORDLONG, - pub Rsi: DWORDLONG, - pub Rdi: DWORDLONG, - pub R8: DWORDLONG, - pub R9: DWORDLONG, - pub R10: DWORDLONG, - pub R11: DWORDLONG, - pub R12: DWORDLONG, - pub R13: DWORDLONG, - pub R14: DWORDLONG, - pub R15: DWORDLONG, - - pub Rip: DWORDLONG, - - pub FltSave: FLOATING_SAVE_AREA, - - pub VectorRegister: [M128A; 26], - pub VectorControl: DWORDLONG, - - pub DebugControl: DWORDLONG, - pub LastBranchToRip: DWORDLONG, - pub LastBranchFromRip: DWORDLONG, - pub LastExceptionToRip: DWORDLONG, - pub LastExceptionFromRip: DWORDLONG, -} - -#[cfg(target_arch = "x86_64")] -#[repr(C, align(16))] -pub struct M128A { - pub Low: c_ulonglong, - pub High: c_longlong -} - -#[cfg(target_arch = "x86_64")] -#[repr(C, align(16))] -pub struct FLOATING_SAVE_AREA { - _Dummy: [u8; 512] // FIXME: Fill this out -} - -#[cfg(target_arch = "arm")] -#[repr(C)] -pub struct CONTEXT { - pub ContextFlags: ULONG, - pub R0: ULONG, - pub R1: ULONG, - pub R2: ULONG, - pub R3: ULONG, - pub R4: ULONG, - pub R5: ULONG, - pub R6: ULONG, - pub R7: ULONG, - pub R8: ULONG, - pub R9: ULONG, - pub R10: ULONG, - pub R11: ULONG, - pub R12: ULONG, - pub Sp: ULONG, - pub Lr: ULONG, - pub Pc: ULONG, - pub Cpsr: ULONG, - pub Fpscr: ULONG, - pub Padding: ULONG, - pub D: [u64; 32], - pub Bvr: [ULONG; ARM_MAX_BREAKPOINTS], - pub Bcr: [ULONG; ARM_MAX_BREAKPOINTS], - pub Wvr: [ULONG; ARM_MAX_WATCHPOINTS], - pub Wcr: [ULONG; ARM_MAX_WATCHPOINTS], - pub Padding2: [ULONG; 2] -} - -// FIXME(#43348): This structure is used for backtrace only, and a fake -// definition is provided here only to allow rustdoc to pass type-check. This -// will not appear in the final documentation. This should be also defined for -// other architectures supported by Windows such as ARM, and for historical -// interest, maybe MIPS and PowerPC as well. -#[cfg(all(rustdoc, not(any(target_arch = "x86_64", target_arch = "x86", - target_arch = "aarch64", target_arch = "arm"))))] pub enum CONTEXT {} -#[cfg(target_arch = "aarch64")] -pub const ARM64_MAX_BREAKPOINTS: usize = 8; - -#[cfg(target_arch = "aarch64")] -pub const ARM64_MAX_WATCHPOINTS: usize = 2; - -#[cfg(target_arch = "aarch64")] -#[repr(C)] -pub struct ARM64_NT_NEON128 { - pub D: [f64; 2], -} - -#[cfg(target_arch = "aarch64")] -#[repr(C, align(16))] -pub struct CONTEXT { - pub ContextFlags: DWORD, - pub Cpsr: DWORD, - pub X0: u64, - pub X1: u64, - pub X2: u64, - pub X3: u64, - pub X4: u64, - pub X5: u64, - pub X6: u64, - pub X7: u64, - pub X8: u64, - pub X9: u64, - pub X10: u64, - pub X11: u64, - pub X12: u64, - pub X13: u64, - pub X14: u64, - pub X15: u64, - pub X16: u64, - pub X17: u64, - pub X18: u64, - pub X19: u64, - pub X20: u64, - pub X21: u64, - pub X22: u64, - pub X23: u64, - pub X24: u64, - pub X25: u64, - pub X26: u64, - pub X27: u64, - pub X28: u64, - pub Fp: u64, - pub Lr: u64, - pub Sp: u64, - pub Pc: u64, - pub V: [ARM64_NT_NEON128; 32], - pub Fpcr: DWORD, - pub Fpsr: DWORD, - pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS], - pub Bvr: [DWORD; ARM64_MAX_BREAKPOINTS], - pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS], - pub Wvr: [DWORD; ARM64_MAX_WATCHPOINTS], -} - #[repr(C)] pub struct SOCKADDR_STORAGE_LH { pub ss_family: ADDRESS_FAMILY, @@ -1220,8 +886,6 @@ extern "system" { pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL; pub fn FindClose(findFile: HANDLE) -> BOOL; - #[cfg(feature = "backtrace")] - pub fn RtlCaptureContext(ctx: *mut CONTEXT); pub fn getsockopt(s: SOCKET, level: c_int, optname: c_int, @@ -1252,10 +916,6 @@ extern "system" { res: *mut *mut ADDRINFOA) -> c_int; pub fn freeaddrinfo(res: *mut ADDRINFOA); - #[cfg(feature = "backtrace")] - pub fn LoadLibraryW(name: LPCWSTR) -> HMODULE; - #[cfg(feature = "backtrace")] - pub fn FreeLibrary(handle: HMODULE) -> BOOL; pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void; pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; @@ -1361,34 +1021,3 @@ compat_fn! { panic!("rwlocks not available") } } - -#[cfg(all(target_env = "gnu", feature = "backtrace"))] -mod gnu { - use super::*; - - pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400; - - pub const CP_ACP: UINT = 0; - - pub const WC_NO_BEST_FIT_CHARS: DWORD = 0x00000400; - - extern "system" { - pub fn OpenProcess(dwDesiredAccess: DWORD, - bInheritHandle: BOOL, - dwProcessId: DWORD) -> HANDLE; - } - - compat_fn! { - kernel32: - - pub fn QueryFullProcessImageNameW(_hProcess: HANDLE, - _dwFlags: DWORD, - _lpExeName: LPWSTR, - _lpdwSize: LPDWORD) -> BOOL { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - } -} - -#[cfg(all(target_env = "gnu", feature = "backtrace"))] -pub use self::gnu::*; diff --git a/src/libstd/sys/windows/dynamic_lib.rs b/src/libstd/sys/windows/dynamic_lib.rs deleted file mode 100644 index b9d5105cb7307..0000000000000 --- a/src/libstd/sys/windows/dynamic_lib.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::os::windows::prelude::*; - -use crate::ffi::{CString, OsStr}; -use crate::io; -use crate::sys::c; - -pub struct DynamicLibrary { - handle: c::HMODULE, -} - -impl DynamicLibrary { - pub fn open(filename: &str) -> io::Result { - let filename = OsStr::new(filename) - .encode_wide() - .chain(Some(0)) - .collect::>(); - let result = unsafe { - c::LoadLibraryW(filename.as_ptr()) - }; - if result.is_null() { - Err(io::Error::last_os_error()) - } else { - Ok(DynamicLibrary { handle: result }) - } - } - - pub fn symbol(&self, symbol: &str) -> io::Result { - let symbol = CString::new(symbol)?; - unsafe { - match c::GetProcAddress(self.handle, symbol.as_ptr()) as usize { - 0 => Err(io::Error::last_os_error()), - n => Ok(n), - } - } - } -} - -impl Drop for DynamicLibrary { - fn drop(&mut self) { - unsafe { - c::FreeLibrary(self.handle); - } - } -} diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs index 547b1ef796b4a..1381825806f63 100644 --- a/src/libstd/sys/windows/ext/ffi.rs +++ b/src/libstd/sys/windows/ext/ffi.rs @@ -131,12 +131,12 @@ pub trait OsStrExt { /// /// [`OsString::from_wide`]: ./trait.OsStringExt.html#tymethod.from_wide #[stable(feature = "rust1", since = "1.0.0")] - fn encode_wide(&self) -> EncodeWide; + fn encode_wide(&self) -> EncodeWide<'_>; } #[stable(feature = "rust1", since = "1.0.0")] impl OsStrExt for OsStr { - fn encode_wide(&self) -> EncodeWide { + fn encode_wide(&self) -> EncodeWide<'_> { self.as_inner().inner.encode_wide() } } diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index b6da59502806b..268a14ff0aabb 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -220,13 +220,27 @@ pub trait OpenOptionsExt { /// the specified value (or combines it with `custom_flags` and `attributes` /// to set the `dwFlagsAndAttributes` for [`CreateFile`]). /// - /// By default, `security_qos_flags` is set to `SECURITY_ANONYMOUS`. For - /// information about possible values, see [Impersonation Levels] on the - /// Windows Dev Center site. - /// + /// By default `security_qos_flags` is not set. It should be specified when + /// opening a named pipe, to control to which degree a server process can + /// act on behalf of a client process (security impersonation level). + /// + /// When `security_qos_flags` is not set a malicious program can gain the + /// elevated privileges of a privileged Rust process when it allows opening + /// user-specified paths, by tricking it into opening a named pipe. So + /// arguably `security_qos_flags` should also be set when opening arbitrary + /// paths. However the bits can then conflict with other flags, specifically + /// `FILE_FLAG_OPEN_NO_RECALL`. + /// + /// For information about possible values, see [Impersonation Levels] on the + /// Windows Dev Center site. The `SECURITY_SQOS_PRESENT` flag is set + /// automatically when using this method. + /// # Examples /// /// ```no_run + /// # #[cfg(for_demonstration_only)] + /// extern crate winapi; + /// # mod winapi { pub const SECURITY_IDENTIFICATION: u32 = 0; } /// use std::fs::OpenOptions; /// use std::os::windows::prelude::*; /// @@ -235,9 +249,9 @@ pub trait OpenOptionsExt { /// .create(true) /// /// // Sets the flag value to `SecurityIdentification`. - /// .security_qos_flags(1) + /// .security_qos_flags(winapi::SECURITY_IDENTIFICATION) /// - /// .open("foo.txt"); + /// .open(r"\\.\pipe\MyPipe"); /// ``` /// /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx diff --git a/src/libstd/sys/windows/ext/io.rs b/src/libstd/sys/windows/ext/io.rs index 1a7d734b89e4b..ec47c2e9d5afd 100644 --- a/src/libstd/sys/windows/ext/io.rs +++ b/src/libstd/sys/windows/ext/io.rs @@ -83,6 +83,27 @@ impl AsRawHandle for io::Stderr { } } +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawHandle for io::StdinLock<'a> { + fn as_raw_handle(&self) -> RawHandle { + unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle } + } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawHandle for io::StdoutLock<'a> { + fn as_raw_handle(&self) -> RawHandle { + unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle } + } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawHandle for io::StderrLock<'a> { + fn as_raw_handle(&self) -> RawHandle { + unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle } + } +} + #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawHandle for fs::File { unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { diff --git a/src/libstd/sys/windows/fast_thread_local.rs b/src/libstd/sys/windows/fast_thread_local.rs index 0ccc67e3fd54e..31d0bd1e72ed2 100644 --- a/src/libstd/sys/windows/fast_thread_local.rs +++ b/src/libstd/sys/windows/fast_thread_local.rs @@ -2,7 +2,3 @@ #![cfg(target_thread_local)] pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor; - -pub fn requires_move_before_drop() -> bool { - false -} diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index f19c111f09aa2..d5cb205c85f52 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -2,7 +2,7 @@ use crate::os::windows::prelude::*; use crate::ffi::OsString; use crate::fmt; -use crate::io::{self, Error, SeekFrom}; +use crate::io::{self, Error, SeekFrom, IoSlice, IoSliceMut}; use crate::mem; use crate::path::{Path, PathBuf}; use crate::ptr; @@ -74,7 +74,7 @@ pub struct FilePermissions { attrs: c::DWORD } pub struct DirBuilder; impl fmt::Debug for ReadDir { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. // Thus the result will be e g 'ReadDir("C:\")' fmt::Debug::fmt(&*self.root, f) @@ -191,7 +191,11 @@ impl OpenOptions { pub fn access_mode(&mut self, access_mode: u32) { self.access_mode = Some(access_mode); } pub fn share_mode(&mut self, share_mode: u32) { self.share_mode = share_mode; } pub fn attributes(&mut self, attrs: u32) { self.attributes = attrs; } - pub fn security_qos_flags(&mut self, flags: u32) { self.security_qos_flags = flags; } + pub fn security_qos_flags(&mut self, flags: u32) { + // We have to set `SECURITY_SQOS_PRESENT` here, because one of the valid flags we can + // receive is `SECURITY_ANONYMOUS = 0x0`, which we can't check for later on. + self.security_qos_flags = flags | c::SECURITY_SQOS_PRESENT; + } pub fn security_attributes(&mut self, attrs: c::LPSECURITY_ATTRIBUTES) { self.security_attributes = attrs as usize; } @@ -239,7 +243,6 @@ impl OpenOptions { self.custom_flags | self.attributes | self.security_qos_flags | - if self.security_qos_flags != 0 { c::SECURITY_SQOS_PRESENT } else { 0 } | if self.create_new { c::FILE_FLAG_OPEN_REPARSE_POINT } else { 0 } } } @@ -311,6 +314,10 @@ impl File { self.handle.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.handle.read_vectored(bufs) + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { self.handle.read_at(buf, offset) } @@ -319,6 +326,10 @@ impl File { self.handle.write(buf) } + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + self.handle.write_vectored(bufs) + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { self.handle.write_at(buf, offset) } @@ -432,7 +443,7 @@ impl FromInner for File { } impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // FIXME(#24570): add more info here (e.g., mode) let mut b = f.debug_struct("File"); b.field("handle", &self.handle.raw()); diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index 02549088c8704..3e5aa69335461 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -1,7 +1,7 @@ #![unstable(issue = "0", feature = "windows_handle")] use crate::cmp; -use crate::io::{self, ErrorKind, Read}; +use crate::io::{self, ErrorKind, Read, IoSlice, IoSliceMut}; use crate::mem; use crate::ops::Deref; use crate::ptr; @@ -89,6 +89,10 @@ impl RawHandle { } } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|buf| self.read(buf), bufs) + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { let mut read = 0; let len = cmp::min(buf.len(), ::max_value() as usize) as c::DWORD; @@ -169,6 +173,10 @@ impl RawHandle { Ok(amt as usize) } + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|buf| self.write(buf), bufs) + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { let mut written = 0; let len = cmp::min(buf.len(), ::max_value() as usize) as c::DWORD; @@ -199,4 +207,8 @@ impl<'a> Read for &'a RawHandle { fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + (**self).read_vectored(bufs) + } } diff --git a/src/libstd/sys/windows/io.rs b/src/libstd/sys/windows/io.rs index 54dd271c9d666..c045a63e9118f 100644 --- a/src/libstd/sys/windows/io.rs +++ b/src/libstd/sys/windows/io.rs @@ -3,16 +3,16 @@ use crate::slice; use crate::sys::c; #[repr(transparent)] -pub struct IoVec<'a> { +pub struct IoSlice<'a> { vec: c::WSABUF, _p: PhantomData<&'a [u8]>, } -impl<'a> IoVec<'a> { +impl<'a> IoSlice<'a> { #[inline] - pub fn new(buf: &'a [u8]) -> IoVec<'a> { + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { assert!(buf.len() <= c::ULONG::max_value() as usize); - IoVec { + IoSlice { vec: c::WSABUF { len: buf.len() as c::ULONG, buf: buf.as_ptr() as *mut u8 as *mut c::CHAR, @@ -29,16 +29,16 @@ impl<'a> IoVec<'a> { } } -pub struct IoVecMut<'a> { +pub struct IoSliceMut<'a> { vec: c::WSABUF, _p: PhantomData<&'a mut [u8]>, } -impl<'a> IoVecMut<'a> { +impl<'a> IoSliceMut<'a> { #[inline] - pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { assert!(buf.len() <= c::ULONG::max_value() as usize); - IoVecMut { + IoSliceMut { vec: c::WSABUF { len: buf.len() as c::ULONG, buf: buf.as_mut_ptr() as *mut c::CHAR, diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 1425254a2e126..1cb5553912981 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -14,13 +14,9 @@ pub use self::rand::hashmap_random_keys; pub mod alloc; pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; pub mod c; pub mod cmath; pub mod condvar; -#[cfg(feature = "backtrace")] -pub mod dynamic_lib; pub mod env; pub mod ext; pub mod fast_thread_local; diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index 1aa910f05c9c3..37cbdcefcedcc 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -154,7 +154,7 @@ unsafe impl Sync for ReentrantMutex {} impl ReentrantMutex { pub fn uninitialized() -> ReentrantMutex { - ReentrantMutex { inner: UnsafeCell::new(MaybeUninit::uninitialized()) } + ReentrantMutex { inner: UnsafeCell::new(MaybeUninit::uninit()) } } pub unsafe fn init(&mut self) { diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index 1231fd55e252e..7dd1af5441bfb 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -1,7 +1,7 @@ #![unstable(issue = "0", feature = "windows_net")] use crate::cmp; -use crate::io::{self, Read, IoVec, IoVecMut}; +use crate::io::{self, Read, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{SocketAddr, Shutdown}; use crate::ptr; @@ -208,7 +208,7 @@ impl Socket { self.recv_with_flags(buf, 0) } - pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. let len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD; @@ -268,7 +268,7 @@ impl Socket { self.recv_from_with_flags(buf, c::MSG_PEEK) } - pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result { + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { let len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD; let mut nwritten = 0; unsafe { diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 5b433ddfb4a38..4e50b5521eb04 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -136,7 +136,7 @@ pub struct SplitPaths<'a> { must_yield: bool, } -pub fn split_paths(unparsed: &OsStr) -> SplitPaths { +pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> { SplitPaths { data: unparsed.encode_wide(), must_yield: true, @@ -212,7 +212,7 @@ pub fn join_paths(paths: I) -> Result } impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "path segment contains `\"`".fmt(f) } } diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 8befa66ecdc9c..c7a82e092528e 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -33,13 +33,13 @@ impl AsInner for Buf { } impl fmt::Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self.as_slice(), formatter) } } impl fmt::Display for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self.as_slice(), formatter) } } @@ -49,13 +49,13 @@ pub struct Slice { } impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.inner, formatter) } } impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.inner, formatter) } } @@ -139,7 +139,7 @@ impl Slice { self.inner.as_str() } - pub fn to_string_lossy(&self) -> Cow { + pub fn to_string_lossy(&self) -> Cow<'_, str> { self.inner.to_string_lossy() } diff --git a/src/libstd/sys/windows/path.rs b/src/libstd/sys/windows/path.rs index b8532ca9b0d4e..f3178a5e9e690 100644 --- a/src/libstd/sys/windows/path.rs +++ b/src/libstd/sys/windows/path.rs @@ -19,7 +19,7 @@ pub fn is_verbatim_sep(b: u8) -> bool { b == b'\\' } -pub fn parse_prefix<'a>(path: &'a OsStr) -> Option { +pub fn parse_prefix<'a>(path: &'a OsStr) -> Option> { use crate::path::Prefix::*; unsafe { // The unsafety here stems from converting between &OsStr and &[u8] diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index 07f4f5f0e58c4..493ee8a9a2d7c 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -1,7 +1,7 @@ use crate::os::windows::prelude::*; use crate::ffi::OsStr; -use crate::io; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem; use crate::path::Path; use crate::ptr; @@ -37,9 +37,9 @@ pub struct Pipes { /// /// The ours/theirs pipes are *not* specifically readable or writable. Each /// one only supports a read or a write, but which is which depends on the -/// boolean flag given. If `ours_readable` is true then `ours` is readable where -/// `theirs` is writable. Conversely if `ours_readable` is false then `ours` is -/// writable where `theirs` is readable. +/// boolean flag given. If `ours_readable` is `true`, then `ours` is readable and +/// `theirs` is writable. Conversely, if `ours_readable` is `false`, then `ours` +/// is writable and `theirs` is readable. /// /// Also note that the `ours` pipe is always a handle opened up in overlapped /// mode. This means that technically speaking it should only ever be used @@ -166,9 +166,17 @@ impl AnonPipe { self.inner.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.inner.read_vectored(bufs) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.inner.write(buf) } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + self.inner.write_vectored(bufs) + } } pub fn read2(p1: AnonPipe, diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 95f061d22bd43..e39b7ae889025 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -219,7 +219,7 @@ impl Command { } impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self.program)?; for arg in &self.args { write!(f, " {:?}", arg)?; @@ -393,7 +393,7 @@ impl From for ExitStatus { } impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Windows exit codes with the high bit set typically mean some form of // unhandled exception or warning. In this scenario printing the exit // code in decimal doesn't always make sense because it's a very large diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 1b0a811f13b72..ebdf3612e0602 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -1,4 +1,3 @@ -use crate::boxed::FnBox; use crate::io; use crate::ffi::CStr; use crate::mem; @@ -20,7 +19,7 @@ pub struct Thread { impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, p: Box) + pub unsafe fn new(stack: usize, p: Box) -> io::Result { let p = box p; diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index 2c99bca70095c..e0f0e3a1a45b9 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -49,17 +49,17 @@ impl Instant { Instant { t: Duration::from_secs(0) } } - pub fn sub_instant(&self, other: &Instant) -> Duration { + pub fn checked_sub_instant(&self, other: &Instant) -> Option { // On windows there's a threshold below which we consider two timestamps // equivalent due to measurement error. For more details + doc link, // check the docs on epsilon. let epsilon = perf_counter::PerformanceCounterInstant::epsilon(); if other.t > self.t && other.t - self.t <= epsilon { - return Duration::new(0, 0) + Some(Duration::new(0, 0)) + } else { + self.t.checked_sub(other.t) } - self.t.checked_sub(other.t) - .expect("specified instant was later than self") } pub fn checked_add_duration(&self, other: &Duration) -> Option { @@ -139,7 +139,7 @@ impl Ord for SystemTime { } impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SystemTime") .field("intervals", &self.intervals()) .finish() @@ -173,7 +173,7 @@ fn intervals2dur(intervals: u64) -> Duration { mod perf_counter { use super::{NANOS_PER_SEC}; - use crate::sync::Once; + use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use crate::sys_common::mul_div_u64; use crate::sys::c; use crate::sys::cvt; @@ -210,13 +210,25 @@ mod perf_counter { fn frequency() -> c::LARGE_INTEGER { static mut FREQUENCY: c::LARGE_INTEGER = 0; - static ONCE: Once = Once::new(); + static STATE: AtomicUsize = AtomicUsize::new(0); unsafe { - ONCE.call_once(|| { - cvt(c::QueryPerformanceFrequency(&mut FREQUENCY)).unwrap(); - }); - FREQUENCY + // If a previous thread has filled in this global state, use that. + if STATE.load(SeqCst) == 2 { + return FREQUENCY; + } + + // ... otherwise learn for ourselves ... + let mut frequency = 0; + cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap(); + + // ... and attempt to be the one thread that stores it globally for + // all other threads + if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() { + FREQUENCY = frequency; + STATE.store(2, SeqCst); + } + return frequency; } } diff --git a/src/libstd/sys_common/at_exit_imp.rs b/src/libstd/sys_common/at_exit_imp.rs index 1181b86161199..cdb72ee872e04 100644 --- a/src/libstd/sys_common/at_exit_imp.rs +++ b/src/libstd/sys_common/at_exit_imp.rs @@ -2,12 +2,11 @@ //! //! Documentation can be found on the `rt::at_exit` function. -use crate::boxed::FnBox; use crate::ptr; use crate::mem; use crate::sys_common::mutex::Mutex; -type Queue = Vec>; +type Queue = Vec>; // NB these are specifically not types from `std::sync` as they currently rely // on poisoning and this module needs to operate at a lower level than requiring @@ -61,7 +60,7 @@ pub fn cleanup() { } } -pub fn push(f: Box) -> bool { +pub fn push(f: Box) -> bool { unsafe { let _guard = LOCK.lock(); if init() { diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 1a80908779e1a..bf37ff7ddbd3a 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -2,40 +2,17 @@ /// supported platforms. use crate::env; -use crate::io::prelude::*; use crate::io; +use crate::io::prelude::*; +use crate::mem; use crate::path::{self, Path}; use crate::ptr; -use crate::str; use crate::sync::atomic::{self, Ordering}; use crate::sys::mutex::Mutex; -use rustc_demangle::demangle; - -pub use crate::sys::backtrace::{ - unwind_backtrace, - resolve_symname, - foreach_symbol_fileline, - BacktraceContext -}; - -#[cfg(target_pointer_width = "64")] -pub const HEX_WIDTH: usize = 18; - -#[cfg(target_pointer_width = "32")] -pub const HEX_WIDTH: usize = 10; - -/// Represents an item in the backtrace list. See `unwind_backtrace` for how -/// it is created. -#[derive(Debug, Copy, Clone)] -pub struct Frame { - /// Exact address of the call that failed. - pub exact_position: *const u8, - /// Address of the enclosing function. - pub symbol_addr: *const u8, - /// Which inlined function is this frame referring to - pub inline_context: u32, -} +use backtrace::{BytesOrWideString, Frame, Symbol}; + +pub const HEX_WIDTH: usize = 2 + 2 * mem::size_of::(); /// Max number of frames to print. const MAX_NB_FRAMES: usize = 100; @@ -49,7 +26,7 @@ pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { // test mode immediately return here to optimize away any references to the // libbacktrace symbols if cfg!(test) { - return Ok(()) + return Ok(()); } // Use a lock to prevent mixed output in multithreading context. @@ -63,75 +40,39 @@ pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { } fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { - let mut frames = [Frame { - exact_position: ptr::null(), - symbol_addr: ptr::null(), - inline_context: 0, - }; MAX_NB_FRAMES]; - let (nb_frames, context) = unwind_backtrace(&mut frames)?; - let (skipped_before, skipped_after) = - filter_frames(&frames[..nb_frames], format, &context); - if skipped_before + skipped_after > 0 { - writeln!(w, "note: Some details are omitted, \ - run with `RUST_BACKTRACE=full` for a verbose backtrace.")?; - } writeln!(w, "stack backtrace:")?; - let filtered_frames = &frames[..nb_frames - skipped_after]; - for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() { - resolve_symname(*frame, |symname| { - output(w, index, *frame, symname, format) - }, &context)?; - let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| { - output_fileline(w, file, line, format) - }, &context)?; - if has_more_filenames { - w.write_all(b" <... and possibly more>")?; - } - } - - Ok(()) -} - -/// Returns a number of frames to remove at the beginning and at the end of the -/// backtrace, according to the backtrace format. -fn filter_frames(frames: &[Frame], - format: PrintFormat, - context: &BacktraceContext) -> (usize, usize) -{ - if format == PrintFormat::Full { - return (0, 0); - } - - let skipped_before = 0; - - let skipped_after = frames.len() - frames.iter().position(|frame| { - let mut is_marker = false; - let _ = resolve_symname(*frame, |symname| { - if let Some(mangled_symbol_name) = symname { - // Use grep to find the concerned functions - if mangled_symbol_name.contains("__rust_begin_short_backtrace") { - is_marker = true; - } + let mut printer = Printer::new(format, w); + unsafe { + backtrace::trace_unsynchronized(|frame| { + let mut hit = false; + backtrace::resolve_frame_unsynchronized(frame, |symbol| { + hit = true; + printer.output(frame, Some(symbol)); + }); + if !hit { + printer.output(frame, None); } - Ok(()) - }, context); - is_marker - }).unwrap_or(frames.len()); - - if skipped_before + skipped_after >= frames.len() { - // Avoid showing completely empty backtraces - return (0, 0); + !printer.done + }); } - - (skipped_before, skipped_after) + if printer.skipped { + writeln!( + w, + "note: Some details are omitted, \ + run with `RUST_BACKTRACE=full` for a verbose backtrace." + )?; + } + Ok(()) } - /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. #[inline(never)] pub fn __rust_begin_short_backtrace(f: F) -> T - where F: FnOnce() -> T, F: Send, T: Send +where + F: FnOnce() -> T, + F: Send, + T: Send, { f() } @@ -156,7 +97,7 @@ pub fn log_enabled() -> Option { _ => return Some(PrintFormat::Full), } - let val = env::var_os("RUST_BACKTRACE").and_then(|x| + let val = env::var_os("RUST_BACKTRACE").and_then(|x| { if &x == "0" { None } else if &x == "full" { @@ -164,81 +105,141 @@ pub fn log_enabled() -> Option { } else { Some(PrintFormat::Short) } + }); + ENABLED.store( + match val { + Some(v) => v as isize, + None => 1, + }, + Ordering::SeqCst, ); - ENABLED.store(match val { - Some(v) => v as isize, - None => 1, - }, Ordering::SeqCst); val } -/// Prints the symbol of the backtrace frame. -/// -/// These output functions should now be used everywhere to ensure consistency. -/// You may want to also use `output_fileline`. -fn output(w: &mut dyn Write, idx: usize, frame: Frame, - s: Option<&str>, format: PrintFormat) -> io::Result<()> { - // Remove the `17: 0x0 - ` line. - if format == PrintFormat::Short && frame.exact_position == ptr::null() { - return Ok(()); +struct Printer<'a, 'b> { + format: PrintFormat, + done: bool, + skipped: bool, + idx: usize, + out: &'a mut (dyn Write + 'b), +} + +impl<'a, 'b> Printer<'a, 'b> { + fn new(format: PrintFormat, out: &'a mut (dyn Write + 'b)) -> Printer<'a, 'b> { + Printer { format, done: false, skipped: false, idx: 0, out } } - match format { - PrintFormat::Full => write!(w, - " {:2}: {:2$?} - ", - idx, - frame.exact_position, - HEX_WIDTH)?, - PrintFormat::Short => write!(w, " {:2}: ", idx)?, + + /// Prints the symbol of the backtrace frame. + /// + /// These output functions should now be used everywhere to ensure consistency. + /// You may want to also use `output_fileline`. + fn output(&mut self, frame: &Frame, symbol: Option<&Symbol>) { + if self.idx > MAX_NB_FRAMES { + self.done = true; + self.skipped = true; + return; + } + if self._output(frame, symbol).is_err() { + self.done = true; + } + self.idx += 1; } - match s { - Some(string) => { - let symbol = demangle(string); - match format { - PrintFormat::Full => write!(w, "{}", symbol)?, - // strip the trailing hash if short mode - PrintFormat::Short => write!(w, "{:#}", symbol)?, + + fn _output(&mut self, frame: &Frame, symbol: Option<&Symbol>) -> io::Result<()> { + if self.format == PrintFormat::Short { + if let Some(sym) = symbol.and_then(|s| s.name()).and_then(|s| s.as_str()) { + if sym.contains("__rust_begin_short_backtrace") { + self.skipped = true; + self.done = true; + return Ok(()); + } + } + + // Remove the `17: 0x0 - ` line. + if self.format == PrintFormat::Short && frame.ip() == ptr::null_mut() { + self.skipped = true; + return Ok(()); } } - None => w.write_all(b"")?, - } - w.write_all(b"\n") -} -/// Prints the filename and line number of the backtrace frame. -/// -/// See also `output`. -#[allow(dead_code)] -fn output_fileline(w: &mut dyn Write, - file: &[u8], - line: u32, - format: PrintFormat) -> io::Result<()> { - // prior line: " ##: {:2$} - func" - w.write_all(b"")?; - match format { - PrintFormat::Full => write!(w, - " {:1$}", - "", - HEX_WIDTH)?, - PrintFormat::Short => write!(w, " ")?, - } + match self.format { + PrintFormat::Full => { + write!(self.out, " {:2}: {:2$?} - ", self.idx, frame.ip(), HEX_WIDTH)? + } + PrintFormat::Short => write!(self.out, " {:2}: ", self.idx)?, + } - let file = str::from_utf8(file).unwrap_or(""); - let file_path = Path::new(file); - let mut already_printed = false; - if format == PrintFormat::Short && file_path.is_absolute() { - if let Ok(cwd) = env::current_dir() { - if let Ok(stripped) = file_path.strip_prefix(&cwd) { - if let Some(s) = stripped.to_str() { - write!(w, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?; - already_printed = true; + match symbol.and_then(|s| s.name()) { + Some(symbol) => { + match self.format { + PrintFormat::Full => write!(self.out, "{}", symbol)?, + // Strip the trailing hash if short mode. + PrintFormat::Short => write!(self.out, "{:#}", symbol)?, } } + None => self.out.write_all(b"")?, } - } - if !already_printed { - write!(w, " at {}:{}", file, line)?; + self.out.write_all(b"\n")?; + if let Some(sym) = symbol { + self.output_fileline(sym)?; + } + Ok(()) } - w.write_all(b"\n") -} + /// Prints the filename and line number of the backtrace frame. + /// + /// See also `output`. + fn output_fileline(&mut self, symbol: &Symbol) -> io::Result<()> { + #[cfg(windows)] + let path_buf; + let file = match symbol.filename_raw() { + #[cfg(unix)] + Some(BytesOrWideString::Bytes(bytes)) => { + use crate::os::unix::prelude::*; + Path::new(crate::ffi::OsStr::from_bytes(bytes)) + } + #[cfg(not(unix))] + Some(BytesOrWideString::Bytes(bytes)) => { + Path::new(crate::str::from_utf8(bytes).unwrap_or("")) + } + #[cfg(windows)] + Some(BytesOrWideString::Wide(wide)) => { + use crate::os::windows::prelude::*; + path_buf = crate::ffi::OsString::from_wide(wide); + Path::new(&path_buf) + } + #[cfg(not(windows))] + Some(BytesOrWideString::Wide(_wide)) => { + Path::new("") + } + None => return Ok(()), + }; + let line = match symbol.lineno() { + Some(line) => line, + None => return Ok(()), + }; + // prior line: " ##: {:2$} - func" + self.out.write_all(b"")?; + match self.format { + PrintFormat::Full => write!(self.out, " {:1$}", "", HEX_WIDTH)?, + PrintFormat::Short => write!(self.out, " ")?, + } + let mut already_printed = false; + if self.format == PrintFormat::Short && file.is_absolute() { + if let Ok(cwd) = env::current_dir() { + if let Ok(stripped) = file.strip_prefix(&cwd) { + if let Some(s) = stripped.to_str() { + write!(self.out, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?; + already_printed = true; + } + } + } + } + if !already_printed { + write!(self.out, " at {}:{}", file.display(), line)?; + } + + self.out.write_all(b"\n") + } +} diff --git a/src/libstd/sys_common/bytestring.rs b/src/libstd/sys_common/bytestring.rs index 273d586a5a0b2..429ecf6281b3e 100644 --- a/src/libstd/sys_common/bytestring.rs +++ b/src/libstd/sys_common/bytestring.rs @@ -3,9 +3,9 @@ use crate::fmt::{Formatter, Result, Write}; use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; -pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter) -> Result { +pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter<'_>) -> Result { // Writes out a valid unicode string with the correct escape sequences - fn write_str_escaped(f: &mut Formatter, s: &str) -> Result { + fn write_str_escaped(f: &mut Formatter<'_>, s: &str) -> Result { for c in s.chars().flat_map(|c| c.escape_debug()) { f.write_char(c)? } @@ -32,7 +32,7 @@ mod tests { struct Helper<'a>(&'a [u8]); impl Debug for Helper<'_> { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { debug_fmt_bytestring(self.0, f) } } diff --git a/src/libstd/sys_common/fs.rs b/src/libstd/sys_common/fs.rs new file mode 100644 index 0000000000000..7152fcd215c9a --- /dev/null +++ b/src/libstd/sys_common/fs.rs @@ -0,0 +1,41 @@ +#![allow(dead_code)] // not used on all platforms + +use crate::path::Path; +use crate::fs; +use crate::io::{self, Error, ErrorKind}; + +pub fn copy(from: &Path, to: &Path) -> io::Result { + if !from.is_file() { + return Err(Error::new(ErrorKind::InvalidInput, + "the source path is not an existing regular file")) + } + + let mut reader = fs::File::open(from)?; + let mut writer = fs::File::create(to)?; + let perm = reader.metadata()?.permissions(); + + let ret = io::copy(&mut reader, &mut writer)?; + fs::set_permissions(to, perm)?; + Ok(ret) +} + +pub fn remove_dir_all(path: &Path) -> io::Result<()> { + let filetype = fs::symlink_metadata(path)?.file_type(); + if filetype.is_symlink() { + fs::remove_file(path) + } else { + remove_dir_all_recursive(path) + } +} + +fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { + for child in fs::read_dir(path)? { + let child = child?; + if child.file_type()?.is_dir() { + remove_dir_all_recursive(&child.path())?; + } else { + fs::remove_file(&child.path())?; + } + } + fs::remove_dir(path) +} diff --git a/src/libstd/sys_common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs deleted file mode 100644 index 6cd050242dd95..0000000000000 --- a/src/libstd/sys_common/gnu/libbacktrace.rs +++ /dev/null @@ -1,175 +0,0 @@ -use backtrace_sys::backtrace_state; - -use crate::ffi::CStr; -use crate::io; -use crate::mem; -use crate::ptr; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -pub fn foreach_symbol_fileline(frame: Frame, - mut f: F, - _: &BacktraceContext) -> io::Result -where F: FnMut(&[u8], u32) -> io::Result<()> -{ - // pcinfo may return an arbitrary number of file:line pairs, - // in the order of stack trace (i.e., inlined calls first). - // in order to avoid allocation, we stack-allocate a fixed size of entries. - const FILELINE_SIZE: usize = 32; - let mut fileline_buf = [(ptr::null(), !0); FILELINE_SIZE]; - let ret; - let fileline_count = { - let state = unsafe { init_state() }; - if state.is_null() { - return Err(io::Error::new( - io::ErrorKind::Other, - "failed to allocate libbacktrace state") - ) - } - let mut fileline_win: &mut [FileLine] = &mut fileline_buf; - let fileline_addr = &mut fileline_win as *mut &mut [FileLine]; - ret = unsafe { - backtrace_sys::backtrace_pcinfo( - state, - frame.exact_position as libc::uintptr_t, - pcinfo_cb, - error_cb, - fileline_addr as *mut libc::c_void, - ) - }; - FILELINE_SIZE - fileline_win.len() - }; - if ret == 0 { - for &(file, line) in &fileline_buf[..fileline_count] { - if file.is_null() { continue; } // just to be sure - let file = unsafe { CStr::from_ptr(file).to_bytes() }; - f(file, line)?; - } - Ok(fileline_count == FILELINE_SIZE) - } else { - Ok(false) - } -} - -/// Converts a pointer to symbol to its string value. -pub fn resolve_symname(frame: Frame, - callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - let symname = { - let state = unsafe { init_state() }; - if state.is_null() { - return Err(io::Error::new( - io::ErrorKind::Other, - "failed to allocate libbacktrace state") - ) - } - let mut data: *const libc::c_char = ptr::null(); - let data_addr = &mut data as *mut *const libc::c_char; - let ret = unsafe { - backtrace_sys::backtrace_syminfo( - state, - frame.symbol_addr as libc::uintptr_t, - syminfo_cb, - error_cb, - data_addr as *mut libc::c_void, - ) - }; - if ret == 0 || data.is_null() { - None - } else { - unsafe { - CStr::from_ptr(data).to_str().ok() - } - } - }; - callback(symname) -} - -//////////////////////////////////////////////////////////////////////// -// helper callbacks -//////////////////////////////////////////////////////////////////////// - -type FileLine = (*const libc::c_char, u32); - -extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char, - _errnum: libc::c_int) { - // do nothing for now -} -extern fn syminfo_cb(data: *mut libc::c_void, - _pc: libc::uintptr_t, - symname: *const libc::c_char, - _symval: libc::uintptr_t, - _symsize: libc::uintptr_t) { - let slot = data as *mut *const libc::c_char; - unsafe { *slot = symname; } -} -extern fn pcinfo_cb(data: *mut libc::c_void, - _pc: libc::uintptr_t, - filename: *const libc::c_char, - lineno: libc::c_int, - _function: *const libc::c_char) -> libc::c_int { - if !filename.is_null() { - let slot = data as *mut &mut [FileLine]; - let buffer = unsafe {ptr::read(slot)}; - - // if the buffer is not full, add file:line to the buffer - // and adjust the buffer for next possible calls to pcinfo_cb. - if !buffer.is_empty() { - buffer[0] = (filename, lineno as u32); - unsafe { ptr::write(slot, &mut buffer[1..]); } - } - } - - 0 -} - -// The libbacktrace API supports creating a state, but it does not -// support destroying a state. I personally take this to mean that a -// state is meant to be created and then live forever. -// -// I would love to register an at_exit() handler which cleans up this -// state, but libbacktrace provides no way to do so. -// -// With these constraints, this function has a statically cached state -// that is calculated the first time this is requested. Remember that -// backtracing all happens serially (one global lock). -// -// Things don't work so well on not-Linux since libbacktrace can't track -// down that executable this is. We at one point used env::current_exe but -// it turns out that there are some serious security issues with that -// approach. -// -// Specifically, on certain platforms like BSDs, a malicious actor can cause -// an arbitrary file to be placed at the path returned by current_exe. -// libbacktrace does not behave defensively in the presence of ill-formed -// DWARF information, and has been demonstrated to segfault in at least one -// case. There is no evidence at the moment to suggest that a more carefully -// constructed file can't cause arbitrary code execution. As a result of all -// of this, we don't hint libbacktrace with the path to the current process. -unsafe fn init_state() -> *mut backtrace_state { - static mut STATE: *mut backtrace_state = ptr::null_mut(); - if !STATE.is_null() { return STATE } - - let filename = match crate::sys::backtrace::gnu::get_executable_filename() { - Ok((filename, file)) => { - // filename is purposely leaked here since libbacktrace requires - // it to stay allocated permanently, file is also leaked so that - // the file stays locked - let filename_ptr = filename.as_ptr(); - mem::forget(filename); - mem::forget(file); - filename_ptr - }, - Err(_) => ptr::null(), - }; - - STATE = backtrace_sys::backtrace_create_state( - filename, - 0, - error_cb, - ptr::null_mut(), - ); - STATE -} diff --git a/src/libstd/sys_common/gnu/mod.rs b/src/libstd/sys_common/gnu/mod.rs deleted file mode 100644 index d6959697f2a3d..0000000000000 --- a/src/libstd/sys_common/gnu/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![allow(missing_docs)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] - -pub mod libbacktrace; diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index 1fc32365408b8..13a59f66c5c2f 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -28,6 +28,17 @@ macro_rules! rtassert { }) } +#[allow(unused_macros)] // not used on all platforms +macro_rules! rtunwrap { + ($ok:ident, $e:expr) => (match $e { + $ok(v) => v, + ref err => { + let err = err.as_ref().map(|_|()); // map Ok/Some which might not be Debug + rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err) + }, + }) +} + pub mod alloc; pub mod at_exit_imp; #[cfg(feature = "backtrace")] @@ -35,6 +46,13 @@ pub mod backtrace; pub mod condvar; pub mod io; pub mod mutex; +#[cfg(any(rustdoc, // see `mod os`, docs are generated for multiple platforms + unix, + target_os = "redox", + target_os = "cloudabi", + target_arch = "wasm32", + all(target_vendor = "fortanix", target_env = "sgx")))] +pub mod os_str_bytes; pub mod poison; pub mod remutex; pub mod rwlock; @@ -45,8 +63,9 @@ pub mod util; pub mod wtf8; pub mod bytestring; pub mod process; +pub mod fs; -cfg_if! { +cfg_if::cfg_if! { if #[cfg(any(target_os = "cloudabi", target_os = "l4re", target_os = "redox", @@ -58,12 +77,6 @@ cfg_if! { } } -#[cfg(feature = "backtrace")] -#[cfg(any(all(unix, not(target_os = "emscripten")), - all(windows, target_env = "gnu"), - target_os = "redox"))] -pub mod gnu; - // common error constructors /// A trait for viewing representations from std types diff --git a/src/libstd/sys_common/mutex.rs b/src/libstd/sys_common/mutex.rs index 4b58cac7941b9..28d85949ffa3c 100644 --- a/src/libstd/sys_common/mutex.rs +++ b/src/libstd/sys_common/mutex.rs @@ -38,7 +38,7 @@ impl Mutex { /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex /// will be unlocked. #[inline] - pub unsafe fn lock(&self) -> MutexGuard { + pub unsafe fn lock(&self) -> MutexGuard<'_> { self.raw_lock(); MutexGuard(&self.0) } diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index 36721171b1733..391f670346f2a 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -1,7 +1,7 @@ use crate::cmp; use crate::ffi::CString; use crate::fmt; -use crate::io::{self, Error, ErrorKind, IoVec, IoVecMut}; +use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; use crate::ptr; @@ -37,12 +37,12 @@ use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP; #[cfg(any(target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", - target_os = "haiku", target_os = "bitrig"))] + target_os = "haiku"))] use libc::MSG_NOSIGNAL; #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", - target_os = "haiku", target_os = "bitrig")))] + target_os = "haiku")))] const MSG_NOSIGNAL: c_int = 0x0; //////////////////////////////////////////////////////////////////////////////// @@ -157,7 +157,7 @@ impl Drop for LookupHost { } } -impl<'a> TryFrom<&'a str> for LookupHost { +impl TryFrom<&str> for LookupHost { type Error = io::Error; fn try_from(s: &str) -> io::Result { @@ -256,7 +256,7 @@ impl TcpStream { self.inner.read(buf) } - pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result { + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.inner.read_vectored(bufs) } @@ -271,7 +271,7 @@ impl TcpStream { Ok(ret as usize) } - pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result { + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { self.inner.write_vectored(bufs) } @@ -328,7 +328,7 @@ impl FromInner for TcpStream { } impl fmt::Debug for TcpStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut res = f.debug_struct("TcpStream"); if let Ok(addr) = self.socket_addr() { @@ -435,7 +435,7 @@ impl FromInner for TcpListener { } impl fmt::Debug for TcpListener { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut res = f.debug_struct("TcpListener"); if let Ok(addr) = self.socket_addr() { @@ -472,6 +472,12 @@ impl UdpSocket { pub fn into_socket(self) -> Socket { self.inner } + pub fn peer_addr(&self) -> io::Result { + sockname(|buf, len| unsafe { + c::getpeername(*self.inner.as_inner(), buf, len) + }) + } + pub fn socket_addr(&self) -> io::Result { sockname(|buf, len| unsafe { c::getsockname(*self.inner.as_inner(), buf, len) @@ -638,7 +644,7 @@ impl FromInner for UdpSocket { } impl fmt::Debug for UdpSocket { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut res = f.debug_struct("UdpSocket"); if let Ok(addr) = self.socket_addr() { diff --git a/src/libstd/sys_common/os_str_bytes.rs b/src/libstd/sys_common/os_str_bytes.rs new file mode 100644 index 0000000000000..a4961974d89ab --- /dev/null +++ b/src/libstd/sys_common/os_str_bytes.rs @@ -0,0 +1,247 @@ +//! The underlying OsString/OsStr implementation on Unix and many other +//! systems: just a `Vec`/`[u8]`. + +use crate::borrow::Cow; +use crate::ffi::{OsStr, OsString}; +use crate::fmt; +use crate::str; +use crate::mem; +use crate::rc::Rc; +use crate::sync::Arc; +use crate::sys_common::{FromInner, IntoInner, AsInner}; +use crate::sys_common::bytestring::debug_fmt_bytestring; + +use core::str::lossy::Utf8Lossy; + +#[derive(Clone, Hash)] +pub(crate) struct Buf { + pub inner: Vec +} + +pub(crate) struct Slice { + pub inner: [u8] +} + +impl fmt::Debug for Slice { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + debug_fmt_bytestring(&self.inner, formatter) + } +} + +impl fmt::Display for Slice { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) + } +} + +impl fmt::Debug for Buf { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_slice(), formatter) + } +} + +impl fmt::Display for Buf { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_slice(), formatter) + } +} + +impl IntoInner> for Buf { + fn into_inner(self) -> Vec { + self.inner + } +} + +impl AsInner<[u8]> for Buf { + fn as_inner(&self) -> &[u8] { + &self.inner + } +} + + +impl Buf { + pub fn from_string(s: String) -> Buf { + Buf { inner: s.into_bytes() } + } + + #[inline] + pub fn with_capacity(capacity: usize) -> Buf { + Buf { + inner: Vec::with_capacity(capacity) + } + } + + #[inline] + pub fn clear(&mut self) { + self.inner.clear() + } + + #[inline] + pub fn capacity(&self) -> usize { + self.inner.capacity() + } + + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.inner.reserve(additional) + } + + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.inner.reserve_exact(additional) + } + + #[inline] + pub fn shrink_to_fit(&mut self) { + self.inner.shrink_to_fit() + } + + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + + pub fn as_slice(&self) -> &Slice { + unsafe { mem::transmute(&*self.inner) } + } + + pub fn into_string(self) -> Result { + String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } ) + } + + pub fn push_slice(&mut self, s: &Slice) { + self.inner.extend_from_slice(&s.inner) + } + + #[inline] + pub fn into_box(self) -> Box { + unsafe { mem::transmute(self.inner.into_boxed_slice()) } + } + + #[inline] + pub fn from_box(boxed: Box) -> Buf { + let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; + Buf { inner: inner.into_vec() } + } + + #[inline] + pub fn into_arc(&self) -> Arc { + self.as_slice().into_arc() + } + + #[inline] + pub fn into_rc(&self) -> Rc { + self.as_slice().into_rc() + } +} + +impl Slice { + fn from_u8_slice(s: &[u8]) -> &Slice { + unsafe { mem::transmute(s) } + } + + pub fn from_str(s: &str) -> &Slice { + Slice::from_u8_slice(s.as_bytes()) + } + + pub fn to_str(&self) -> Option<&str> { + str::from_utf8(&self.inner).ok() + } + + pub fn to_string_lossy(&self) -> Cow<'_, str> { + String::from_utf8_lossy(&self.inner) + } + + pub fn to_owned(&self) -> Buf { + Buf { inner: self.inner.to_vec() } + } + + #[inline] + pub fn into_box(&self) -> Box { + let boxed: Box<[u8]> = self.inner.into(); + unsafe { mem::transmute(boxed) } + } + + pub fn empty_box() -> Box { + let boxed: Box<[u8]> = Default::default(); + unsafe { mem::transmute(boxed) } + } + + #[inline] + pub fn into_arc(&self) -> Arc { + let arc: Arc<[u8]> = Arc::from(&self.inner); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } + } + + #[inline] + pub fn into_rc(&self) -> Rc { + let rc: Rc<[u8]> = Rc::from(&self.inner); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } + } +} + +/// Platform-specific extensions to [`OsString`]. +/// +/// [`OsString`]: ../../../../std/ffi/struct.OsString.html +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStringExt { + /// Creates an [`OsString`] from a byte vector. + /// + /// See the module docmentation for an example. + /// + /// [`OsString`]: ../../../ffi/struct.OsString.html + #[stable(feature = "rust1", since = "1.0.0")] + fn from_vec(vec: Vec) -> Self; + + /// Yields the underlying byte vector of this [`OsString`]. + /// + /// See the module docmentation for an example. + /// + /// [`OsString`]: ../../../ffi/struct.OsString.html + #[stable(feature = "rust1", since = "1.0.0")] + fn into_vec(self) -> Vec; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStringExt for OsString { + fn from_vec(vec: Vec) -> OsString { + FromInner::from_inner(Buf { inner: vec }) + } + fn into_vec(self) -> Vec { + self.into_inner().inner + } +} + +/// Platform-specific extensions to [`OsStr`]. +/// +/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStrExt { + #[stable(feature = "rust1", since = "1.0.0")] + /// Creates an [`OsStr`] from a byte slice. + /// + /// See the module docmentation for an example. + /// + /// [`OsStr`]: ../../../ffi/struct.OsStr.html + fn from_bytes(slice: &[u8]) -> &Self; + + /// Gets the underlying byte view of the [`OsStr`] slice. + /// + /// See the module docmentation for an example. + /// + /// [`OsStr`]: ../../../ffi/struct.OsStr.html + #[stable(feature = "rust1", since = "1.0.0")] + fn as_bytes(&self) -> &[u8]; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStrExt for OsStr { + #[inline] + fn from_bytes(slice: &[u8]) -> &OsStr { + unsafe { mem::transmute(slice) } + } + #[inline] + fn as_bytes(&self) -> &[u8] { + &self.as_inner().inner + } +} diff --git a/src/libstd/sys_common/poison.rs b/src/libstd/sys_common/poison.rs index d229423566649..adac45f2d59da 100644 --- a/src/libstd/sys_common/poison.rs +++ b/src/libstd/sys_common/poison.rs @@ -136,14 +136,14 @@ pub type TryLockResult = Result>; #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for PoisonError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "PoisonError { inner: .. }".fmt(f) } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for PoisonError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "poisoned lock: another task failed inside".fmt(f) } } @@ -214,7 +214,7 @@ impl From> for TryLockError { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for TryLockError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { TryLockError::Poisoned(..) => "Poisoned(..)".fmt(f), TryLockError::WouldBlock => "WouldBlock".fmt(f) @@ -224,7 +224,7 @@ impl fmt::Debug for TryLockError { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for TryLockError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { TryLockError::Poisoned(..) => "poisoned lock: another task failed inside", TryLockError::WouldBlock => "try_lock failed because the operation would block" diff --git a/src/libstd/sys_common/remutex.rs b/src/libstd/sys_common/remutex.rs index 2aec361d7a493..f08b13c4aa274 100644 --- a/src/libstd/sys_common/remutex.rs +++ b/src/libstd/sys_common/remutex.rs @@ -72,7 +72,7 @@ impl ReentrantMutex { /// If another user of this mutex panicked while holding the mutex, then /// this call will return failure if the mutex would otherwise be /// acquired. - pub fn lock(&self) -> LockResult> { + pub fn lock(&self) -> LockResult> { unsafe { self.inner.lock() } ReentrantMutexGuard::new(&self) } @@ -89,7 +89,7 @@ impl ReentrantMutex { /// If another user of this mutex panicked while holding the mutex, then /// this call will return failure if the mutex would otherwise be /// acquired. - pub fn try_lock(&self) -> TryLockResult> { + pub fn try_lock(&self) -> TryLockResult> { if unsafe { self.inner.try_lock() } { Ok(ReentrantMutexGuard::new(&self)?) } else { @@ -108,7 +108,7 @@ impl Drop for ReentrantMutex { } impl fmt::Debug for ReentrantMutex { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.try_lock() { Ok(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(), Err(TryLockError::Poisoned(err)) => { @@ -117,7 +117,9 @@ impl fmt::Debug for ReentrantMutex { Err(TryLockError::WouldBlock) => { struct LockedPlaceholder; impl fmt::Debug for LockedPlaceholder { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("") } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("") + } } f.debug_struct("ReentrantMutex").field("data", &LockedPlaceholder).finish() diff --git a/src/libstd/sys_common/thread.rs b/src/libstd/sys_common/thread.rs index b2142e753085a..6ab0d5cbe9c96 100644 --- a/src/libstd/sys_common/thread.rs +++ b/src/libstd/sys_common/thread.rs @@ -1,4 +1,3 @@ -use crate::boxed::FnBox; use crate::env; use crate::sync::atomic::{self, Ordering}; use crate::sys::stack_overflow; @@ -11,7 +10,7 @@ pub unsafe fn start_thread(main: *mut u8) { let _handler = stack_overflow::Handler::new(); // Finally, let's run some code. - Box::from_raw(main as *mut Box)() + Box::from_raw(main as *mut Box)() } pub fn min_stack() -> usize { diff --git a/src/libstd/sys_common/util.rs b/src/libstd/sys_common/util.rs index 206443a673692..7936dd35999e2 100644 --- a/src/libstd/sys_common/util.rs +++ b/src/libstd/sys_common/util.rs @@ -3,7 +3,7 @@ use crate::io::prelude::*; use crate::sys::stdio::panic_output; use crate::thread; -pub fn dumb_print(args: fmt::Arguments) { +pub fn dumb_print(args: fmt::Arguments<'_>) { if let Some(mut out) = panic_output() { let _ = out.write_fmt(args); } @@ -14,7 +14,7 @@ pub fn dumb_print(args: fmt::Arguments) { // crate::intrinsics::abort() may be used instead. The above implementations cover // all targets currently supported by libstd. -pub fn abort(args: fmt::Arguments) -> ! { +pub fn abort(args: fmt::Arguments<'_>) -> ! { dumb_print(format_args!("fatal runtime error: {}\n", args)); unsafe { crate::sys::abort_internal(); } } diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index b15239e8d877e..81e606fc16583 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -46,7 +46,7 @@ pub struct CodePoint { /// Example: `U+1F4A9` impl fmt::Debug for CodePoint { #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { write!(formatter, "U+{:04X}", self.value) } } @@ -134,7 +134,7 @@ impl ops::DerefMut for Wtf8Buf { /// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800] impl fmt::Debug for Wtf8Buf { #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, formatter) } } @@ -146,10 +146,10 @@ impl Wtf8Buf { Wtf8Buf { bytes: Vec::new() } } - /// Creates a new, empty WTF-8 string with pre-allocated capacity for `n` bytes. + /// Creates a new, empty WTF-8 string with pre-allocated capacity for `capacity` bytes. #[inline] - pub fn with_capacity(n: usize) -> Wtf8Buf { - Wtf8Buf { bytes: Vec::with_capacity(n) } + pub fn with_capacity(capacity: usize) -> Wtf8Buf { + Wtf8Buf { bytes: Vec::with_capacity(capacity) } } /// Creates a WTF-8 string from a UTF-8 `String`. @@ -388,9 +388,7 @@ impl Extend for Wtf8Buf { let (low, _high) = iterator.size_hint(); // Lower bound of one byte per code point (ASCII only) self.bytes.reserve(low); - for code_point in iterator { - self.push(code_point); - } + iterator.for_each(move |code_point| self.push(code_point)); } } @@ -411,8 +409,8 @@ impl AsInner<[u8]> for Wtf8 { /// and surrogates as `\u` followed by four hexadecimal digits. /// Example: `"a\u{D800}"` for a slice with code points [U+0061, U+D800] impl fmt::Debug for Wtf8 { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fn write_str_escaped(f: &mut fmt::Formatter, s: &str) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fn write_str_escaped(f: &mut fmt::Formatter<'_>, s: &str) -> fmt::Result { use crate::fmt::Write; for c in s.chars().flat_map(|c| c.escape_debug()) { f.write_char(c)? @@ -441,7 +439,7 @@ impl fmt::Debug for Wtf8 { } impl fmt::Display for Wtf8 { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let wtf8_bytes = &self.bytes; let mut pos = 0; loop { @@ -522,7 +520,7 @@ impl Wtf8 { /// Returns an iterator for the string’s code points. #[inline] - pub fn code_points(&self) -> Wtf8CodePoints { + pub fn code_points(&self) -> Wtf8CodePoints<'_> { Wtf8CodePoints { bytes: self.bytes.iter() } } @@ -547,7 +545,7 @@ impl Wtf8 { /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”). /// /// This only copies the data if necessary (if it contains any surrogate). - pub fn to_string_lossy(&self) -> Cow { + pub fn to_string_lossy(&self) -> Cow<'_, str> { let surrogate_pos = match self.next_surrogate(0) { None => return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }), Some((pos, _)) => pos, @@ -579,7 +577,7 @@ impl Wtf8 { /// calling `Wtf8Buf::from_ill_formed_utf16` on the resulting code units /// would always return the original WTF-8 string. #[inline] - pub fn encode_wide(&self) -> EncodeWide { + pub fn encode_wide(&self) -> EncodeWide<'_> { EncodeWide { code_points: self.code_points(), extra: 0 } } @@ -1228,7 +1226,7 @@ mod tests { assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩")); let mut string = Wtf8Buf::from_str("aé 💩"); string.push(CodePoint::from_u32(0xD800).unwrap()); - let expected: Cow = Cow::Owned(String::from("aé 💩�")); + let expected: Cow<'_, str> = Cow::Owned(String::from("aé 💩�")); assert_eq!(string.to_string_lossy(), expected); } diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index d1f53734d30e3..9b355aa2023ff 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -2,10 +2,7 @@ #![unstable(feature = "thread_local_internals", issue = "0")] -use crate::cell::UnsafeCell; use crate::fmt; -use crate::hint; -use crate::mem; /// A thread local storage key which owns its contents. /// @@ -40,13 +37,16 @@ use crate::mem; /// }); /// /// // each thread starts out with the initial value of 1 -/// thread::spawn(move|| { +/// let t = thread::spawn(move|| { /// FOO.with(|f| { /// assert_eq!(*f.borrow(), 1); /// *f.borrow_mut() = 3; /// }); /// }); /// +/// // wait for the thread to complete and bail out on panic +/// t.join().unwrap(); +/// /// // we retain our original value of 2 despite the child thread /// FOO.with(|f| { /// assert_eq!(*f.borrow(), 2); @@ -89,15 +89,12 @@ pub struct LocalKey { // trivially devirtualizable by LLVM because the value of `inner` never // changes and the constant should be readonly within a crate. This mainly // only runs into problems when TLS statics are exported across crates. - inner: unsafe fn() -> Option<&'static UnsafeCell>>, - - // initialization routine to invoke to create a value - init: fn() -> T, + inner: unsafe fn() -> Option<&'static T>, } #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for LocalKey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("LocalKey { .. }") } } @@ -126,8 +123,7 @@ impl fmt::Debug for LocalKey { /// [`std::thread::LocalKey`]: ../std/thread/struct.LocalKey.html #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(stage0, allow_internal_unstable)] -#[cfg_attr(not(stage0), allow_internal_unstable(thread_local_internals))] +#[allow_internal_unstable(thread_local_internals)] macro_rules! thread_local { // empty (base case for the recursion) () => {}; @@ -149,10 +145,7 @@ macro_rules! thread_local { reason = "should not be necessary", issue = "0")] #[macro_export] -#[cfg_attr(stage0, allow_internal_unstable)] -#[cfg_attr(not(stage0), allow_internal_unstable( - thread_local_internals, cfg_target_thread_local, thread_local, -))] +#[allow_internal_unstable(thread_local_internals, cfg_target_thread_local, thread_local)] #[allow_internal_unsafe] macro_rules! __thread_local_inner { (@key $(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => { @@ -160,10 +153,7 @@ macro_rules! __thread_local_inner { #[inline] fn __init() -> $t { $init } - unsafe fn __getit() -> $crate::option::Option< - &'static $crate::cell::UnsafeCell< - $crate::option::Option<$t>>> - { + unsafe fn __getit() -> $crate::option::Option<&'static $t> { #[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))] static __KEY: $crate::thread::__StaticLocalKeyInner<$t> = $crate::thread::__StaticLocalKeyInner::new(); @@ -183,11 +173,11 @@ macro_rules! __thread_local_inner { static __KEY: $crate::thread::__OsLocalKeyInner<$t> = $crate::thread::__OsLocalKeyInner::new(); - __KEY.get() + __KEY.get(__init) } unsafe { - $crate::thread::LocalKey::new(__getit, __init) + $crate::thread::LocalKey::new(__getit) } } }; @@ -205,14 +195,14 @@ pub struct AccessError { #[stable(feature = "thread_local_try_with", since = "1.26.0")] impl fmt::Debug for AccessError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AccessError").finish() } } #[stable(feature = "thread_local_try_with", since = "1.26.0")] impl fmt::Display for AccessError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt("already destroyed", f) } } @@ -222,11 +212,9 @@ impl LocalKey { #[unstable(feature = "thread_local_internals", reason = "recently added to create a key", issue = "0")] - pub const unsafe fn new(inner: unsafe fn() -> Option<&'static UnsafeCell>>, - init: fn() -> T) -> LocalKey { + pub const unsafe fn new(inner: unsafe fn() -> Option<&'static T>) -> LocalKey { LocalKey { inner, - init, } } @@ -247,37 +235,6 @@ impl LocalKey { after it is destroyed") } - unsafe fn init(&self, slot: &UnsafeCell>) -> &T { - // Execute the initialization up front, *then* move it into our slot, - // just in case initialization fails. - let value = (self.init)(); - let ptr = slot.get(); - - // note that this can in theory just be `*ptr = Some(value)`, but due to - // the compiler will currently codegen that pattern with something like: - // - // ptr::drop_in_place(ptr) - // ptr::write(ptr, Some(value)) - // - // Due to this pattern it's possible for the destructor of the value in - // `ptr` (e.g., if this is being recursively initialized) to re-access - // TLS, in which case there will be a `&` and `&mut` pointer to the same - // value (an aliasing violation). To avoid setting the "I'm running a - // destructor" flag we just use `mem::replace` which should sequence the - // operations a little differently and make this safe to call. - mem::replace(&mut *ptr, Some(value)); - - // After storing `Some` we want to get a reference to the contents of - // what we just stored. While we could use `unwrap` here and it should - // always work it empirically doesn't seem to always get optimized away, - // which means that using something like `try_with` can pull in - // panicking code and cause a large size bloat. - match *ptr { - Some(ref x) => x, - None => hint::unreachable_unchecked(), - } - } - /// Acquires a reference to the value in this TLS key. /// /// This will lazily initialize the value if this thread has not referenced @@ -294,13 +251,68 @@ impl LocalKey { F: FnOnce(&T) -> R, { unsafe { - let slot = (self.inner)().ok_or(AccessError { + let thread_local = (self.inner)().ok_or(AccessError { _private: (), })?; - Ok(f(match *slot.get() { - Some(ref inner) => inner, - None => self.init(slot), - })) + Ok(f(thread_local)) + } + } +} + +mod lazy { + use crate::cell::UnsafeCell; + use crate::mem; + use crate::hint; + + pub struct LazyKeyInner { + inner: UnsafeCell>, + } + + impl LazyKeyInner { + pub const fn new() -> LazyKeyInner { + LazyKeyInner { + inner: UnsafeCell::new(None), + } + } + + pub unsafe fn get(&self) -> Option<&'static T> { + (*self.inner.get()).as_ref() + } + + pub unsafe fn initialize T>(&self, init: F) -> &'static T { + // Execute the initialization up front, *then* move it into our slot, + // just in case initialization fails. + let value = init(); + let ptr = self.inner.get(); + + // note that this can in theory just be `*ptr = Some(value)`, but due to + // the compiler will currently codegen that pattern with something like: + // + // ptr::drop_in_place(ptr) + // ptr::write(ptr, Some(value)) + // + // Due to this pattern it's possible for the destructor of the value in + // `ptr` (e.g., if this is being recursively initialized) to re-access + // TLS, in which case there will be a `&` and `&mut` pointer to the same + // value (an aliasing violation). To avoid setting the "I'm running a + // destructor" flag we just use `mem::replace` which should sequence the + // operations a little differently and make this safe to call. + mem::replace(&mut *ptr, Some(value)); + + // After storing `Some` we want to get a reference to the contents of + // what we just stored. While we could use `unwrap` here and it should + // always work it empirically doesn't seem to always get optimized away, + // which means that using something like `try_with` can pull in + // panicking code and cause a large size bloat. + match *ptr { + Some(ref x) => x, + None => hint::unreachable_unchecked(), + } + } + + #[allow(unused)] + pub unsafe fn take(&mut self) -> Option { + (*self.inner.get()).take() } } } @@ -310,17 +322,17 @@ impl LocalKey { #[doc(hidden)] #[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))] pub mod statik { - use crate::cell::UnsafeCell; + use super::lazy::LazyKeyInner; use crate::fmt; pub struct Key { - inner: UnsafeCell>, + inner: LazyKeyInner, } unsafe impl Sync for Key { } impl fmt::Debug for Key { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Key { .. }") } } @@ -328,12 +340,16 @@ pub mod statik { impl Key { pub const fn new() -> Key { Key { - inner: UnsafeCell::new(None), + inner: LazyKeyInner::new(), } } - pub unsafe fn get(&self) -> Option<&'static UnsafeCell>> { - Some(&*(&self.inner as *const _)) + pub unsafe fn get(&self, init: fn() -> T) -> Option<&'static T> { + let value = match self.inner.get() { + Some(ref value) => value, + None => self.inner.initialize(init), + }; + Some(value) } } } @@ -341,23 +357,42 @@ pub mod statik { #[doc(hidden)] #[cfg(target_thread_local)] pub mod fast { - use crate::cell::{Cell, UnsafeCell}; + use super::lazy::LazyKeyInner; + use crate::cell::Cell; use crate::fmt; use crate::mem; - use crate::ptr; - use crate::sys::fast_thread_local::{register_dtor, requires_move_before_drop}; + use crate::sys::fast_thread_local::register_dtor; + + #[derive(Copy, Clone)] + enum DtorState { + Unregistered, + Registered, + RunningOrHasRun, + } + // This data structure has been carefully constructed so that the fast path + // only contains one branch on x86. That optimization is necessary to avoid + // duplicated tls lookups on OSX. + // + // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722 pub struct Key { - inner: UnsafeCell>, + // If `LazyKeyInner::get` returns `None`, that indicates either: + // * The value has never been initialized + // * The value is being recursively initialized + // * The value has already been destroyed or is being destroyed + // To determine which kind of `None`, check `dtor_state`. + // + // This is very optimizer friendly for the fast path - initialized but + // not yet dropped. + inner: LazyKeyInner, // Metadata to keep track of the state of the destructor. Remember that - // these variables are thread-local, not global. - dtor_registered: Cell, - dtor_running: Cell, + // this variable is thread-local, not global. + dtor_state: Cell, } impl fmt::Debug for Key { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Key { .. }") } } @@ -365,54 +400,75 @@ pub mod fast { impl Key { pub const fn new() -> Key { Key { - inner: UnsafeCell::new(None), - dtor_registered: Cell::new(false), - dtor_running: Cell::new(false) + inner: LazyKeyInner::new(), + dtor_state: Cell::new(DtorState::Unregistered), } } - pub unsafe fn get(&self) -> Option<&'static UnsafeCell>> { - if mem::needs_drop::() && self.dtor_running.get() { - return None + pub unsafe fn get T>(&self, init: F) -> Option<&'static T> { + match self.inner.get() { + Some(val) => Some(val), + None => self.try_initialize(init), } - self.register_dtor(); - Some(&*(&self.inner as *const _)) } - unsafe fn register_dtor(&self) { - if !mem::needs_drop::() || self.dtor_registered.get() { - return + // `try_initialize` is only called once per fast thread local variable, + // except in corner cases where thread_local dtors reference other + // thread_local's, or it is being recursively initialized. + // + // Macos: Inlining this function can cause two `tlv_get_addr` calls to + // be performed for every call to `Key::get`. The #[cold] hint makes + // that less likely. + // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722 + #[cold] + unsafe fn try_initialize T>(&self, init: F) -> Option<&'static T> { + if !mem::needs_drop::() || self.try_register_dtor() { + Some(self.inner.initialize(init)) + } else { + None } + } - register_dtor(self as *const _ as *mut u8, - destroy_value::); - self.dtor_registered.set(true); + // `try_register_dtor` is only called once per fast thread local + // variable, except in corner cases where thread_local dtors reference + // other thread_local's, or it is being recursively initialized. + unsafe fn try_register_dtor(&self) -> bool { + match self.dtor_state.get() { + DtorState::Unregistered => { + // dtor registration happens before initialization. + register_dtor(self as *const _ as *mut u8, + destroy_value::); + self.dtor_state.set(DtorState::Registered); + true + } + DtorState::Registered => { + // recursively initialized + true + } + DtorState::RunningOrHasRun => { + false + } + } } } unsafe extern fn destroy_value(ptr: *mut u8) { let ptr = ptr as *mut Key; - // Right before we run the user destructor be sure to flag the - // destructor as running for this thread so calls to `get` will return - // `None`. - (*ptr).dtor_running.set(true); - // Some implementations may require us to move the value before we drop - // it as it could get re-initialized in-place during destruction. - // - // Hence, we use `ptr::read` on those platforms (to move to a "safe" - // location) instead of drop_in_place. - if requires_move_before_drop() { - ptr::read((*ptr).inner.get()); - } else { - ptr::drop_in_place((*ptr).inner.get()); - } + // Right before we run the user destructor be sure to set the + // `Option` to `None`, and `dtor_state` to `RunningOrHasRun`. This + // causes future calls to `get` to run `try_initialize_drop` again, + // which will now fail, and return `None`. + let value = (*ptr).inner.take(); + (*ptr).dtor_state.set(DtorState::RunningOrHasRun); + drop(value); } } #[doc(hidden)] pub mod os { - use crate::cell::{Cell, UnsafeCell}; + use super::lazy::LazyKeyInner; + use crate::cell::Cell; use crate::fmt; use crate::marker; use crate::ptr; @@ -425,7 +481,7 @@ pub mod os { } impl fmt::Debug for Key { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Key { .. }") } } @@ -433,8 +489,8 @@ pub mod os { unsafe impl Sync for Key { } struct Value { + inner: LazyKeyInner, key: &'static Key, - value: UnsafeCell>, } impl Key { @@ -445,24 +501,43 @@ pub mod os { } } - pub unsafe fn get(&'static self) -> Option<&'static UnsafeCell>> { + pub unsafe fn get(&'static self, init: fn() -> T) -> Option<&'static T> { let ptr = self.os.get() as *mut Value; - if !ptr.is_null() { - if ptr as usize == 1 { - return None + if ptr as usize > 1 { + match (*ptr).inner.get() { + Some(ref value) => return Some(value), + None => {}, } - return Some(&(*ptr).value); } + self.try_initialize(init) + } - // If the lookup returned null, we haven't initialized our own - // local copy, so do that now. - let ptr: Box> = box Value { - key: self, - value: UnsafeCell::new(None), + // `try_initialize` is only called once per os thread local variable, + // except in corner cases where thread_local dtors reference other + // thread_local's, or it is being recursively initialized. + unsafe fn try_initialize(&'static self, init: fn() -> T) -> Option<&'static T> { + let ptr = self.os.get() as *mut Value; + if ptr as usize == 1 { + // destructor is running + return None + } + + let ptr = if ptr.is_null() { + // If the lookup returned null, we haven't initialized our own + // local copy, so do that now. + let ptr: Box> = box Value { + inner: LazyKeyInner::new(), + key: self, + }; + let ptr = Box::into_raw(ptr); + self.os.set(ptr as *mut u8); + ptr + } else { + // recursive initialization + ptr }; - let ptr = Box::into_raw(ptr); - self.os.set(ptr as *mut u8); - Some(&(*ptr).value) + + Some((*ptr).inner.initialize(init)) } } @@ -531,7 +606,7 @@ mod tests { thread::spawn(|| { assert!(FOO.try_with(|_| ()).is_ok()); - }).join().ok().unwrap(); + }).join().ok().expect("thread panicked"); } #[test] @@ -585,7 +660,7 @@ mod tests { thread::spawn(move|| { drop(S1); - }).join().ok().unwrap(); + }).join().ok().expect("thread panicked"); } #[test] @@ -601,7 +676,7 @@ mod tests { thread::spawn(move|| unsafe { K1.with(|s| *s.get() = Some(S1)); - }).join().ok().unwrap(); + }).join().ok().expect("thread panicked"); } // Note that this test will deadlock if TLS destructors aren't run (this diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 08f0aa2f0d206..35de4f4008b67 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -157,12 +157,12 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::any::Any; -use crate::boxed::FnBox; use crate::cell::UnsafeCell; use crate::ffi::{CStr, CString}; use crate::fmt; use crate::io; use crate::mem; +use crate::num::NonZeroU64; use crate::panic; use crate::panicking; use crate::str; @@ -269,7 +269,7 @@ impl Builder { /// /// let builder = thread::Builder::new() /// .name("foo".into()) - /// .stack_size(10); + /// .stack_size(32 * 1024); /// /// let handler = builder.spawn(|| { /// // thread code @@ -443,6 +443,7 @@ impl Builder { /// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn /// [`io::Result`]: ../../std/io/type.Result.html /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html + /// [`JoinHandle::join`]: ../../std/thread/struct.JoinHandle.html#method.join #[unstable(feature = "thread_spawn_unchecked", issue = "55132")] pub unsafe fn spawn_unchecked<'a, F, T>(self, f: F) -> io::Result> where F: FnOnce() -> T, F: Send + 'a, T: Send + 'a @@ -487,7 +488,9 @@ impl Builder { // returning. native: Some(imp::Thread::new( stack_size, - mem::transmute::, Box>(Box::new(main)) + mem::transmute::, Box>(Box::new( + main, + )), )?), thread: my_thread, packet: Packet(my_packet), @@ -1036,7 +1039,7 @@ pub fn park_timeout(dur: Duration) { /// [`Thread`]: ../../std/thread/struct.Thread.html #[stable(feature = "thread_id", since = "1.19.0")] #[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)] -pub struct ThreadId(u64); +pub struct ThreadId(NonZeroU64); impl ThreadId { // Generate a new unique thread ID. @@ -1044,7 +1047,7 @@ impl ThreadId { // We never call `GUARD.init()`, so it is UB to attempt to // acquire this mutex reentrantly! static GUARD: mutex::Mutex = mutex::Mutex::new(); - static mut COUNTER: u64 = 0; + static mut COUNTER: u64 = 1; unsafe { let _guard = GUARD.lock(); @@ -1058,7 +1061,7 @@ impl ThreadId { let id = COUNTER; COUNTER += 1; - ThreadId(id) + ThreadId(NonZeroU64::new(id).unwrap()) } } } @@ -1255,8 +1258,11 @@ impl Thread { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Thread { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.name(), f) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Thread") + .field("id", &self.id()) + .field("name", &self.name()) + .finish() } } @@ -1465,7 +1471,7 @@ impl IntoInner for JoinHandle { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for JoinHandle { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("JoinHandle { .. }") } } @@ -1484,9 +1490,10 @@ fn _assert_sync_and_send() { mod tests { use super::Builder; use crate::any::Any; + use crate::mem; use crate::sync::mpsc::{channel, Sender}; use crate::result; - use crate::thread; + use crate::thread::{self, ThreadId}; use crate::time::Duration; use crate::u32; @@ -1497,7 +1504,7 @@ mod tests { fn test_unnamed_thread() { thread::spawn(move|| { assert!(thread::current().name().is_none()); - }).join().ok().unwrap(); + }).join().ok().expect("thread panicked"); } #[test] @@ -1691,6 +1698,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn test_park_timeout_unpark_not_called() { for _ in 0..10 { thread::park_timeout(Duration::from_millis(10)); @@ -1698,6 +1706,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn test_park_timeout_unpark_called_other_thread() { for _ in 0..10 { let th = thread::current(); @@ -1712,10 +1721,16 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn sleep_ms_smoke() { thread::sleep(Duration::from_millis(2)); } + #[test] + fn test_size_of_option_thread_id() { + assert_eq!(mem::size_of::>(), mem::size_of::()); + } + #[test] fn test_thread_id_equal() { assert!(thread::current().id() == thread::current().id()); diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 6d7093ac33ea7..dc97f8c04a839 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -212,7 +212,7 @@ impl Instant { /// ``` #[stable(feature = "time2", since = "1.8.0")] pub fn duration_since(&self, earlier: Instant) -> Duration { - self.0.sub_instant(&earlier.0) + self.0.checked_sub_instant(&earlier.0).expect("supplied instant is later than self") } /// Returns the amount of time elapsed from another instant to this one, @@ -233,11 +233,7 @@ impl Instant { /// ``` #[unstable(feature = "checked_duration_since", issue = "58402")] pub fn checked_duration_since(&self, earlier: Instant) -> Option { - if self >= &earlier { - Some(self.0.sub_instant(&earlier.0)) - } else { - None - } + self.0.checked_sub_instant(&earlier.0) } /// Returns the amount of time elapsed from another instant to this one, @@ -353,7 +349,7 @@ impl Sub for Instant { #[stable(feature = "time2", since = "1.8.0")] impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } @@ -517,7 +513,7 @@ impl SubAssign for SystemTime { #[stable(feature = "time2", since = "1.8.0")] impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } @@ -585,7 +581,7 @@ impl Error for SystemTimeError { #[stable(feature = "time2", since = "1.8.0")] impl fmt::Display for SystemTimeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "second time provided was later than self") } } @@ -664,20 +660,23 @@ mod tests { #[test] #[should_panic] - fn instant_duration_panic() { + fn instant_duration_since_panic() { let a = Instant::now(); (a - Duration::new(1, 0)).duration_since(a); } #[test] - fn checked_instant_duration_nopanic() { - let a = Instant::now(); - let ret = (a - Duration::new(1, 0)).checked_duration_since(a); - assert_eq!(ret, None); + fn instant_checked_duration_since_nopanic() { + let now = Instant::now(); + let earlier = now - Duration::new(1, 0); + let later = now + Duration::new(1, 0); + assert_eq!(earlier.checked_duration_since(now), None); + assert_eq!(later.checked_duration_since(now), Some(Duration::new(1, 0))); + assert_eq!(now.checked_duration_since(now), Some(Duration::new(0, 0))); } #[test] - fn saturating_instant_duration_nopanic() { + fn instant_saturating_duration_since_nopanic() { let a = Instant::now(); let ret = (a - Duration::new(1, 0)).saturating_duration_since(a); assert_eq!(ret, Duration::new(0,0)); @@ -712,13 +711,6 @@ mod tests { assert_almost_eq!(a - second + second, a); assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a); - // A difference of 80 and 800 years cannot fit inside a 32-bit time_t - if !(cfg!(unix) && crate::mem::size_of::() <= 4) { - let eighty_years = second * 60 * 60 * 24 * 365 * 80; - assert_almost_eq!(a - eighty_years + eighty_years, a); - assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a); - } - let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0); let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000); @@ -747,8 +739,8 @@ mod tests { #[test] fn since_epoch() { let ts = SystemTime::now(); - let a = ts.duration_since(UNIX_EPOCH).unwrap(); - let b = ts.duration_since(UNIX_EPOCH - Duration::new(1, 0)).unwrap(); + let a = ts.duration_since(UNIX_EPOCH + Duration::new(1, 0)).unwrap(); + let b = ts.duration_since(UNIX_EPOCH).unwrap(); assert!(b > a); assert_eq!(b - a, Duration::new(1, 0)); diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 71c2ab82f65c3..b48f3c9b8b8d8 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -14,8 +14,10 @@ bitflags = "1.0" serialize = { path = "../libserialize" } log = "0.4" scoped-tls = "1.0" +lazy_static = "1.0.0" syntax_pos = { path = "../libsyntax_pos" } errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_macros = { path = "../librustc_macros" } rustc_target = { path = "../librustc_target" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a01a5bb0a3638..c627596bbdf20 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -6,16 +6,17 @@ pub use crate::symbol::{Ident, Symbol as Name}; pub use crate::util::parser::ExprPrecedence; use crate::ext::hygiene::{Mark, SyntaxContext}; +use crate::parse::token; use crate::print::pprust; use crate::ptr::P; use crate::source_map::{dummy_spanned, respan, Spanned}; -use crate::symbol::{keywords, Symbol}; +use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::TokenStream; use crate::ThinVec; use rustc_data_structures::indexed_vec::Idx; #[cfg(target_arch = "x86_64")] -use rustc_data_structures::static_assert; +use rustc_data_structures::static_assert_size; use rustc_target::spec::abi::Abi; use syntax_pos::{Span, DUMMY_SP}; @@ -64,13 +65,15 @@ impl fmt::Debug for Lifetime { pub struct Path { pub span: Span, /// The segments in the path: the things separated by `::`. - /// Global paths begin with `keywords::PathRoot`. + /// Global paths begin with `kw::PathRoot`. pub segments: Vec, } -impl<'a> PartialEq<&'a str> for Path { - fn eq(&self, string: &&'a str) -> bool { - self.segments.len() == 1 && self.segments[0].ident.name == *string +impl PartialEq for Path { + fn eq(&self, symbol: &Symbol) -> bool { + self.segments.len() == 1 && { + self.segments[0].ident.name == *symbol + } } } @@ -97,7 +100,7 @@ impl Path { } pub fn is_global(&self) -> bool { - !self.segments.is_empty() && self.segments[0].ident.name == keywords::PathRoot.name() + !self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot } } @@ -125,7 +128,7 @@ impl PathSegment { PathSegment { ident, id: DUMMY_NODE_ID, args: None } } pub fn path_root(span: Span) -> Self { - PathSegment::from_ident(Ident::new(keywords::PathRoot.name(), span)) + PathSegment::from_ident(Ident::new(kw::PathRoot, span)) } } @@ -187,9 +190,9 @@ pub struct AngleBracketedArgs { pub span: Span, /// The arguments for this path segment. pub args: Vec, - /// Bindings (equality constraints) on associated types, if present. - /// E.g., `Foo`. - pub bindings: Vec, + /// Constraints on associated types, if any. + /// E.g., `Foo`. + pub constraints: Vec, } impl Into>> for AngleBracketedArgs { @@ -210,7 +213,7 @@ pub struct ParenthesizedArgs { /// Overall span pub span: Span, - /// `(A,B)` + /// `(A, B)` pub inputs: Vec>, /// `C` @@ -222,7 +225,7 @@ impl ParenthesizedArgs { AngleBracketedArgs { span: self.span, args: self.inputs.iter().cloned().map(|input| GenericArg::Type(input)).collect(), - bindings: vec![], + constraints: vec![], } } } @@ -359,7 +362,6 @@ impl Default for Generics { Generics { params: Vec::new(), where_clause: WhereClause { - id: DUMMY_NODE_ID, predicates: Vec::new(), span: DUMMY_SP, }, @@ -371,7 +373,6 @@ impl Default for Generics { /// A where-clause in a definition. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct WhereClause { - pub id: NodeId, pub predicates: Vec, pub span: Span, } @@ -443,14 +444,11 @@ pub struct Crate { pub span: Span, } -/// A spanned compile-time attribute list item. -pub type NestedMetaItem = Spanned; - /// Possible values inside of compile-time attribute lists. /// /// E.g., the '..' in `#[name(..)]`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub enum NestedMetaItemKind { +pub enum NestedMetaItem { /// A full MetaItem, for recursive meta items. MetaItem(MetaItem), /// A literal. @@ -464,7 +462,7 @@ pub enum NestedMetaItemKind { /// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct MetaItem { - pub ident: Path, + pub path: Path, pub node: MetaItemKind, pub span: Span, } @@ -623,7 +621,7 @@ pub enum PatKind { /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). /// The `bool` is `true` in the presence of a `..`. - Struct(Path, Vec>, bool), + Struct(Path, Vec>, /* recovered */ bool), /// A tuple struct/variant pattern (`Variant(x, y, .., z)`). /// If the `..` pattern fragment is present, then `Option` denotes its position. @@ -895,13 +893,9 @@ pub struct Local { pub struct Arm { pub attrs: Vec, pub pats: Vec>, - pub guard: Option, + pub guard: Option>, pub body: P, -} - -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub enum Guard { - If(P), + pub span: Span, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -949,7 +943,7 @@ pub struct Expr { // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::() == 88); +static_assert_size!(Expr, 96); impl Expr { /// Whether this expression would be valid somewhere that expects a value; for example, an `if` @@ -1025,7 +1019,6 @@ impl Expr { pub fn precedence(&self) -> ExprPrecedence { match self.node { ExprKind::Box(_) => ExprPrecedence::Box, - ExprKind::ObsoleteInPlace(..) => ExprPrecedence::ObsoleteInPlace, ExprKind::Array(_) => ExprPrecedence::Array, ExprKind::Call(..) => ExprPrecedence::Call, ExprKind::MethodCall(..) => ExprPrecedence::MethodCall, @@ -1034,10 +1027,9 @@ impl Expr { ExprKind::Unary(..) => ExprPrecedence::Unary, ExprKind::Lit(_) => ExprPrecedence::Lit, ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast, + ExprKind::Let(..) => ExprPrecedence::Let, ExprKind::If(..) => ExprPrecedence::If, - ExprKind::IfLet(..) => ExprPrecedence::IfLet, ExprKind::While(..) => ExprPrecedence::While, - ExprKind::WhileLet(..) => ExprPrecedence::WhileLet, ExprKind::ForLoop(..) => ExprPrecedence::ForLoop, ExprKind::Loop(..) => ExprPrecedence::Loop, ExprKind::Match(..) => ExprPrecedence::Match, @@ -1045,6 +1037,7 @@ impl Expr { ExprKind::Block(..) => ExprPrecedence::Block, ExprKind::TryBlock(..) => ExprPrecedence::TryBlock, ExprKind::Async(..) => ExprPrecedence::Async, + ExprKind::Await(..) => ExprPrecedence::Await, ExprKind::Assign(..) => ExprPrecedence::Assign, ExprKind::AssignOp(..) => ExprPrecedence::AssignOp, ExprKind::Field(..) => ExprPrecedence::Field, @@ -1086,8 +1079,6 @@ pub enum RangeLimits { pub enum ExprKind { /// A `box x` expression. Box(P), - /// First expr is the place; second expr is the value. - ObsoleteInPlace(P, P), /// An array (`[a, b, c, d]`) Array(Vec>), /// A function call @@ -1117,27 +1108,22 @@ pub enum ExprKind { Lit(Lit), /// A cast (e.g., `foo as f64`). Cast(P, P), + /// A type ascription (e.g., `42: usize`). Type(P, P), + /// A `let pats = expr` expression that is only semantically allowed in the condition + /// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`). + /// + /// The `Vec>` is for or-patterns at the top level. + /// FIXME(54883): Change this to just `P`. + Let(Vec>, P), /// An `if` block, with an optional `else` block. /// /// `if expr { block } else { expr }` If(P, P, Option>), - /// An `if let` expression with an optional else block - /// - /// `if let pat = expr { block } else { expr }` - /// - /// This is desugared to a `match` expression. - IfLet(Vec>, P, P, Option>), - /// A while loop, with an optional label + /// A while loop, with an optional label. /// /// `'label: while expr { block }` While(P, P, Option` or +/// `A: TraitA + TraitB` in `Foo`). #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct TypeBinding { +pub struct AssocTyConstraint { pub id: NodeId, pub ident: Ident, - pub ty: P, + pub kind: AssocTyConstraintKind, pub span: Span, } +/// The kinds of an `AssocTyConstraint`. +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub enum AssocTyConstraintKind { + /// E.g., `A = Bar` in `Foo`. + Equality { + ty: P, + }, + /// E.g. `A: TraitA + TraitB` in `Foo`. + Bound { + bounds: GenericBounds, + }, +} + #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Ty { pub id: NodeId, @@ -1713,6 +1756,7 @@ pub struct InlineAsm { /// E.g., `bar: usize` as in `fn foo(bar: usize)`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Arg { + pub attrs: ThinVec, pub ty: P, pub pat: P, pub id: NodeId, @@ -1736,7 +1780,7 @@ pub type ExplicitSelf = Spanned; impl Arg { pub fn to_self(&self) -> Option { if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.node { - if ident.name == keywords::SelfLower.name() { + if ident.name == kw::SelfLower { return match self.ty.node { TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))), TyKind::Rptr(lt, MutTy { ref ty, mutbl }) if ty.node.is_implicit_self() => { @@ -1754,13 +1798,13 @@ impl Arg { pub fn is_self(&self) -> bool { if let PatKind::Ident(_, ident, _) = self.pat.node { - ident.name == keywords::SelfLower.name() + ident.name == kw::SelfLower } else { false } } - pub fn from_self(eself: ExplicitSelf, eself_ident: Ident) -> Arg { + pub fn from_self(attrs: ThinVec, eself: ExplicitSelf, eself_ident: Ident) -> Arg { let span = eself.span.to(eself_ident.span); let infer_ty = P(Ty { id: DUMMY_NODE_ID, @@ -1768,6 +1812,7 @@ impl Arg { span, }); let arg = |mutbl, ty| Arg { + attrs, pat: P(Pat { id: DUMMY_NODE_ID, node: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None), @@ -1787,7 +1832,7 @@ impl Arg { lt, MutTy { ty: infer_ty, - mutbl: mutbl, + mutbl, }, ), span, @@ -1797,7 +1842,7 @@ impl Arg { } } -/// Header (not the body) of a function declaration. +/// A header (not the body) of a function declaration. /// /// E.g., `fn foo(bar: baz)`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -1959,8 +2004,13 @@ pub struct EnumDef { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Variant_ { + /// Name of the variant. pub ident: Ident, + /// Attributes of the variant. pub attrs: Vec, + /// Id of the variant (not the constructor, see `VariantData::ctor_id()`). + pub id: NodeId, + /// Fields and constructor id of the variant. pub data: VariantData, /// Explicit discriminant, e.g., `Foo = 1`. pub disr_expr: Option, @@ -2056,10 +2106,10 @@ pub struct TraitRef { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct PolyTraitRef { - /// The `'a` in `<'a> Foo<&'a T>` + /// The `'a` in `<'a> Foo<&'a T>`. pub bound_generic_params: Vec, - /// The `Foo<&'a T>` in `<'a> Foo<&'a T>` + /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`. pub trait_ref: TraitRef, pub span: Span, @@ -2070,7 +2120,7 @@ impl PolyTraitRef { PolyTraitRef { bound_generic_params: generic_params, trait_ref: TraitRef { - path: path, + path, ref_id: DUMMY_NODE_ID, }, span, @@ -2120,23 +2170,13 @@ pub struct StructField { pub attrs: Vec, } -/// Fields and Ids of enum variants and structs -/// -/// For enum variants: `NodeId` represents both an Id of the variant itself (relevant for all -/// variant kinds) and an Id of the variant's constructor (not relevant for `Struct`-variants). -/// One shared Id can be successfully used for these two purposes. -/// Id of the whole enum lives in `Item`. -/// -/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually -/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of -/// the variant itself" from enum variants. -/// Id of the whole struct lives in `Item`. +/// Fields and constructor ids of enum variants and structs. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum VariantData { /// Struct variant. /// /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`. - Struct(Vec, NodeId), + Struct(Vec, bool), /// Tuple variant. /// /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`. @@ -2148,36 +2188,19 @@ pub enum VariantData { } impl VariantData { + /// Return the fields of this variant. pub fn fields(&self) -> &[StructField] { match *self { - VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => fields, + VariantData::Struct(ref fields, ..) | VariantData::Tuple(ref fields, _) => fields, _ => &[], } } - pub fn id(&self) -> NodeId { + + /// Return the `NodeId` of this variant's constructor, if it has one. + pub fn ctor_id(&self) -> Option { match *self { - VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id, - } - } - pub fn is_struct(&self) -> bool { - if let VariantData::Struct(..) = *self { - true - } else { - false - } - } - pub fn is_tuple(&self) -> bool { - if let VariantData::Tuple(..) = *self { - true - } else { - false - } - } - pub fn is_unit(&self) -> bool { - if let VariantData::Unit(..) = *self { - true - } else { - false + VariantData::Struct(..) => None, + VariantData::Tuple(_, id) | VariantData::Unit(id) => Some(id), } } } @@ -2207,7 +2230,7 @@ pub struct Item { impl Item { /// Return the span that encompasses the attributes. pub fn span_with_attributes(&self) -> Span { - self.attrs.iter().fold(self.span, |acc, attr| acc.to(attr.span())) + self.attrs.iter().fold(self.span, |acc, attr| acc.to(attr.span)) } } @@ -2353,9 +2376,8 @@ pub struct ForeignItem { pub enum ForeignItemKind { /// A foreign function. Fn(P, Generics), - /// A foreign static item (`static ext: u8`), with optional mutability. - /// (The boolean is `true` for mutable items). - Static(P, bool), + /// A foreign static item (`static ext: u8`). + Static(P, Mutability), /// A foreign type. Ty, /// A macro invocation. diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index e84adc01cf04a..bf6eab4ec9148 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -1,17 +1,17 @@ //! Parsing and validation of builtin attributes -use crate::ast::{self, Attribute, MetaItem, Name, NestedMetaItemKind}; +use crate::ast::{self, Attribute, MetaItem, NestedMetaItem}; use crate::feature_gate::{Features, GatedCfg}; use crate::parse::ParseSess; use errors::{Applicability, Handler}; -use syntax_pos::{symbol::Symbol, Span}; +use syntax_pos::{symbol::Symbol, symbol::sym, Span}; -use super::{list_contains_name, mark_used, MetaItemKind}; +use super::{mark_used, MetaItemKind}; enum AttrError { - MultipleItem(Name), - UnknownMetaItem(Name, &'static [&'static str]), + MultipleItem(String), + UnknownMetaItem(String, &'static [&'static str]), MissingSince, MissingFeature, MultipleStabilityLevels, @@ -79,45 +79,39 @@ pub enum UnwindAttr { /// Determine what `#[unwind]` attribute is present in `attrs`, if any. pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option { - let syntax_error = |attr: &Attribute| { - mark_used(attr); - diagnostic.map(|d| { - span_err!(d, attr.span, E0633, "malformed `#[unwind]` attribute"); - }); - None - }; - attrs.iter().fold(None, |ia, attr| { - if attr.path != "unwind" { - return ia; - } - let meta = match attr.meta() { - Some(meta) => meta.node, - None => return ia, - }; - match meta { - MetaItemKind::Word => { - syntax_error(attr) - } - MetaItemKind::List(ref items) => { - mark_used(attr); - if items.len() != 1 { - syntax_error(attr) - } else if list_contains_name(&items[..], "allowed") { - Some(UnwindAttr::Allowed) - } else if list_contains_name(&items[..], "aborts") { - Some(UnwindAttr::Aborts) - } else { - syntax_error(attr) + if attr.check_name(sym::unwind) { + if let Some(meta) = attr.meta() { + if let MetaItemKind::List(items) = meta.node { + if items.len() == 1 { + if items[0].check_name(sym::allowed) { + return Some(UnwindAttr::Allowed); + } else if items[0].check_name(sym::aborts) { + return Some(UnwindAttr::Aborts); + } + } + + diagnostic.map(|d| { + struct_span_err!(d, attr.span, E0633, "malformed `unwind` attribute input") + .span_label(attr.span, "invalid argument") + .span_suggestions( + attr.span, + "the allowed arguments are `allowed` and `aborts`", + (vec!["allowed", "aborts"]).into_iter() + .map(|s| format!("#[unwind({})]", s)), + Applicability::MachineApplicable, + ).emit(); + }); } } - _ => ia, } + + ia }) } /// Represents the #[stable], #[unstable], #[rustc_{deprecated,const_unstable}] attributes. -#[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct Stability { pub level: StabilityLevel, pub feature: Symbol, @@ -128,10 +122,12 @@ pub struct Stability { pub const_stability: Option, /// whether the function has a `#[rustc_promotable]` attribute pub promotable: bool, + /// whether the function has a `#[rustc_allow_const_fn_ptr]` attribute + pub allow_const_fn_ptr: bool, } /// The available stability levels. -#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] +#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)] pub enum StabilityLevel { // Reason for the current stability level and the relevant rust-lang issue Unstable { reason: Option, issue: u32 }, @@ -155,7 +151,7 @@ impl StabilityLevel { } } -#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] +#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)] pub struct RustcDeprecation { pub since: Symbol, pub reason: Symbol, @@ -165,14 +161,11 @@ pub struct RustcDeprecation { /// Checks if `attrs` contains an attribute like `#![feature(feature_name)]`. /// This will not perform any "sanity checks" on the form of the attributes. -pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool { +pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool { attrs.iter().any(|item| { - item.check_name("feature") && + item.check_name(sym::feature) && item.meta_item_list().map(|list| { - list.iter().any(|mi| { - mi.word().map(|w| w.name() == feature_name) - .unwrap_or(false) - }) + list.iter().any(|mi| mi.is_word() && mi.check_name(feature_name)) }).unwrap_or(false) }) } @@ -195,15 +188,17 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let mut rustc_depr: Option = None; let mut rustc_const_unstable: Option = None; let mut promotable = false; + let mut allow_const_fn_ptr = false; let diagnostic = &sess.span_diagnostic; 'outer: for attr in attrs_iter { if ![ - "rustc_deprecated", - "rustc_const_unstable", - "unstable", - "stable", - "rustc_promotable", + sym::rustc_deprecated, + sym::rustc_const_unstable, + sym::unstable, + sym::stable, + sym::rustc_promotable, + sym::rustc_allow_const_fn_ptr, ].iter().any(|&s| attr.path == s) { continue // not a stability level } @@ -212,15 +207,18 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let meta = attr.meta(); - if attr.path == "rustc_promotable" { + if attr.path == sym::rustc_promotable { promotable = true; } + if attr.path == sym::rustc_allow_const_fn_ptr { + allow_const_fn_ptr = true; + } // attributes with data else if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta { let meta = meta.as_ref().unwrap(); let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { - handle_errors(sess, meta.span, AttrError::MultipleItem(meta.name())); + handle_errors(sess, meta.span, AttrError::MultipleItem(meta.path.to_string())); return false } if let Some(v) = meta.value_str() { @@ -239,17 +237,16 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, )+ for meta in metas { if let Some(mi) = meta.meta_item() { - match &*mi.name().as_str() { + match mi.name_or_empty() { $( - stringify!($name) - => if !get(mi, &mut $name) { continue 'outer }, + sym::$name => if !get(mi, &mut $name) { continue 'outer }, )+ _ => { let expected = &[ $( stringify!($name) ),+ ]; handle_errors( sess, mi.span, - AttrError::UnknownMetaItem(mi.name(), expected), + AttrError::UnknownMetaItem(mi.path.to_string(), expected), ); continue 'outer } @@ -257,7 +254,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, } else { handle_errors( sess, - meta.span, + meta.span(), AttrError::UnsupportedLiteral( "unsupported literal", false, @@ -269,8 +266,8 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, } } - match &*meta.name().as_str() { - "rustc_deprecated" => { + match meta.name_or_empty() { + sym::rustc_deprecated => { if rustc_depr.is_some() { span_err!(diagnostic, item_sp, E0540, "multiple rustc_deprecated attributes"); @@ -288,16 +285,16 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, }) } (None, _) => { - handle_errors(sess, attr.span(), AttrError::MissingSince); + handle_errors(sess, attr.span, AttrError::MissingSince); continue } _ => { - span_err!(diagnostic, attr.span(), E0543, "missing 'reason'"); + span_err!(diagnostic, attr.span, E0543, "missing 'reason'"); continue } } } - "rustc_const_unstable" => { + sym::rustc_const_unstable => { if rustc_const_unstable.is_some() { span_err!(diagnostic, item_sp, E0553, "multiple rustc_const_unstable attributes"); @@ -308,13 +305,13 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, if let Some(feature) = feature { rustc_const_unstable = Some(feature); } else { - span_err!(diagnostic, attr.span(), E0629, "missing 'feature'"); + span_err!(diagnostic, attr.span, E0629, "missing 'feature'"); continue } } - "unstable" => { + sym::unstable => { if stab.is_some() { - handle_errors(sess, attr.span(), AttrError::MultipleStabilityLevels); + handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels); break } @@ -323,16 +320,16 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let mut issue = None; for meta in metas { if let Some(mi) = meta.meta_item() { - match &*mi.name().as_str() { - "feature" => if !get(mi, &mut feature) { continue 'outer }, - "reason" => if !get(mi, &mut reason) { continue 'outer }, - "issue" => if !get(mi, &mut issue) { continue 'outer }, + match mi.name_or_empty() { + sym::feature => if !get(mi, &mut feature) { continue 'outer }, + sym::reason => if !get(mi, &mut reason) { continue 'outer }, + sym::issue => if !get(mi, &mut issue) { continue 'outer }, _ => { handle_errors( sess, - meta.span, + meta.span(), AttrError::UnknownMetaItem( - mi.name(), + mi.path.to_string(), &["feature", "reason", "issue"] ), ); @@ -342,7 +339,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, } else { handle_errors( sess, - meta.span, + meta.span(), AttrError::UnsupportedLiteral( "unsupported literal", false, @@ -361,7 +358,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, if let Ok(issue) = issue.as_str().parse() { issue } else { - span_err!(diagnostic, attr.span(), E0545, + span_err!(diagnostic, attr.span, E0545, "incorrect 'issue'"); continue } @@ -371,45 +368,46 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, rustc_depr: None, const_stability: None, promotable: false, + allow_const_fn_ptr: false, }) } (None, _, _) => { - handle_errors(sess, attr.span(), AttrError::MissingFeature); + handle_errors(sess, attr.span, AttrError::MissingFeature); continue } _ => { - span_err!(diagnostic, attr.span(), E0547, "missing 'issue'"); + span_err!(diagnostic, attr.span, E0547, "missing 'issue'"); continue } } } - "stable" => { + sym::stable => { if stab.is_some() { - handle_errors(sess, attr.span(), AttrError::MultipleStabilityLevels); + handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels); break } let mut feature = None; let mut since = None; for meta in metas { - match &meta.node { - NestedMetaItemKind::MetaItem(mi) => { - match &*mi.name().as_str() { - "feature" => if !get(mi, &mut feature) { continue 'outer }, - "since" => if !get(mi, &mut since) { continue 'outer }, + match meta { + NestedMetaItem::MetaItem(mi) => { + match mi.name_or_empty() { + sym::feature => if !get(mi, &mut feature) { continue 'outer }, + sym::since => if !get(mi, &mut since) { continue 'outer }, _ => { handle_errors( sess, - meta.span, + meta.span(), AttrError::UnknownMetaItem( - mi.name(), &["since", "note"], + mi.path.to_string(), &["since", "note"], ), ); continue 'outer } } }, - NestedMetaItemKind::Literal(lit) => { + NestedMetaItem::Literal(lit) => { handle_errors( sess, lit.span, @@ -433,14 +431,15 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, rustc_depr: None, const_stability: None, promotable: false, + allow_const_fn_ptr: false, }) } (None, _) => { - handle_errors(sess, attr.span(), AttrError::MissingFeature); + handle_errors(sess, attr.span, AttrError::MissingFeature); continue } _ => { - handle_errors(sess, attr.span(), AttrError::MissingSince); + handle_errors(sess, attr.span, AttrError::MissingSince); continue } } @@ -473,13 +472,14 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, } // Merge the const-unstable info into the stability info - if promotable { + if promotable || allow_const_fn_ptr { if let Some(ref mut stab) = stab { - stab.promotable = true; + stab.promotable = promotable; + stab.allow_const_fn_ptr = allow_const_fn_ptr; } else { span_err!(diagnostic, item_sp, E0717, - "rustc_promotable attribute must be paired with \ - either stable or unstable attribute"); + "rustc_promotable and rustc_allow_const_fn_ptr attributes \ + must be paired with either stable or unstable attribute"); } } @@ -487,7 +487,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, } pub fn find_crate_name(attrs: &[Attribute]) -> Option { - super::first_attr_value_str_by_name(attrs, "crate_name") + super::first_attr_value_str_by_name(attrs, sym::crate_name) } /// Tests if a cfg-pattern matches the cfg set @@ -497,8 +497,8 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat gated_cfg.check_and_emit(sess, feats); } let error = |span, msg| { sess.span_diagnostic.span_err(span, msg); true }; - if cfg.ident.segments.len() != 1 { - return error(cfg.ident.span, "`cfg` predicate key must be an identifier"); + if cfg.path.segments.len() != 1 { + return error(cfg.path.span, "`cfg` predicate key must be an identifier"); } match &cfg.node { MetaItemKind::List(..) => { @@ -516,7 +516,8 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat true } MetaItemKind::NameValue(..) | MetaItemKind::Word => { - sess.config.contains(&(cfg.name(), cfg.value_str())) + let ident = cfg.ident().expect("multi-segment cfg predicate"); + sess.config.contains(&(ident.name, cfg.value_str())) } } }) @@ -534,7 +535,7 @@ pub fn eval_condition(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F) if !mi.is_meta_item() { handle_errors( sess, - mi.span, + mi.span(), AttrError::UnsupportedLiteral( "unsupported literal", false @@ -546,14 +547,14 @@ pub fn eval_condition(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F) // The unwraps below may look dangerous, but we've already asserted // that they won't fail with the loop above. - match &*cfg.name().as_str() { - "any" => mis.iter().any(|mi| { + match cfg.name_or_empty() { + sym::any => mis.iter().any(|mi| { eval_condition(mi.meta_item().unwrap(), sess, eval) }), - "all" => mis.iter().all(|mi| { + sym::all => mis.iter().all(|mi| { eval_condition(mi.meta_item().unwrap(), sess, eval) }), - "not" => { + sym::not => { if mis.len() != 1 { span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern"); return false; @@ -561,8 +562,9 @@ pub fn eval_condition(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F) !eval_condition(mis[0].meta_item().unwrap(), sess, eval) }, - p => { - span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p); + _ => { + span_err!(sess.span_diagnostic, cfg.span, E0537, + "invalid predicate `{}`", cfg.path); false } } @@ -596,7 +598,7 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess, let diagnostic = &sess.span_diagnostic; 'outer: for attr in attrs_iter { - if !attr.check_name("deprecated") { + if !attr.check_name(sym::deprecated) { continue; } @@ -616,7 +618,9 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess, MetaItemKind::List(list) => { let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { - handle_errors(sess, meta.span, AttrError::MultipleItem(meta.name())); + handle_errors( + sess, meta.span, AttrError::MultipleItem(meta.path.to_string()) + ); return false } if let Some(v) = meta.value_str() { @@ -644,22 +648,23 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess, let mut since = None; let mut note = None; for meta in list { - match &meta.node { - NestedMetaItemKind::MetaItem(mi) => { - match &*mi.name().as_str() { - "since" => if !get(mi, &mut since) { continue 'outer }, - "note" => if !get(mi, &mut note) { continue 'outer }, + match meta { + NestedMetaItem::MetaItem(mi) => { + match mi.name_or_empty() { + sym::since => if !get(mi, &mut since) { continue 'outer }, + sym::note => if !get(mi, &mut note) { continue 'outer }, _ => { handle_errors( sess, - meta.span, - AttrError::UnknownMetaItem(mi.name(), &["since", "note"]), + meta.span(), + AttrError::UnknownMetaItem(mi.path.to_string(), + &["since", "note"]), ); continue 'outer } } } - NestedMetaItemKind::Literal(lit) => { + NestedMetaItem::Literal(lit) => { handle_errors( sess, lit.span, @@ -721,14 +726,14 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { let mut acc = Vec::new(); let diagnostic = &sess.span_diagnostic; - if attr.path == "repr" { + if attr.path == sym::repr { if let Some(items) = attr.meta_item_list() { mark_used(attr); for item in items { if !item.is_meta_item() { handle_errors( sess, - item.span, + item.span(), AttrError::UnsupportedLiteral( "meta item in `repr` must be an identifier", false, @@ -738,19 +743,13 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { } let mut recognised = false; - if let Some(mi) = item.word() { - let word = &*mi.name().as_str(); - let hint = match word { - "C" => Some(ReprC), - "packed" => Some(ReprPacked(1)), - "simd" => Some(ReprSimd), - "transparent" => Some(ReprTransparent), - _ => match int_type_of_word(word) { - Some(ity) => Some(ReprInt(ity)), - None => { - None - } - } + if item.is_word() { + let hint = match item.name_or_empty() { + sym::C => Some(ReprC), + sym::packed => Some(ReprPacked(1)), + sym::simd => Some(ReprSimd), + sym::transparent => Some(ReprTransparent), + name => int_type_of_word(name).map(ReprInt), }; if let Some(h) = hint { @@ -776,14 +775,14 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { }; let mut literal_error = None; - if name == "align" { + if name == sym::align { recognised = true; match parse_alignment(&value.node) { Ok(literal) => acc.push(ReprAlign(literal)), Err(message) => literal_error = Some(message) }; } - else if name == "packed" { + else if name == sym::packed { recognised = true; match parse_alignment(&value.node) { Ok(literal) => acc.push(ReprPacked(literal)), @@ -791,20 +790,20 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { }; } if let Some(literal_error) = literal_error { - span_err!(diagnostic, item.span, E0589, + span_err!(diagnostic, item.span(), E0589, "invalid `repr(align)` attribute: {}", literal_error); } } else { if let Some(meta_item) = item.meta_item() { - if meta_item.name() == "align" { + if meta_item.check_name(sym::align) { if let MetaItemKind::NameValue(ref value) = meta_item.node { recognised = true; - let mut err = struct_span_err!(diagnostic, item.span, E0693, + let mut err = struct_span_err!(diagnostic, item.span(), E0693, "incorrect `repr(align)` attribute format"); match value.node { ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { err.span_suggestion( - item.span, + item.span(), "use parentheses instead", format!("align({})", int), Applicability::MachineApplicable @@ -812,7 +811,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { } ast::LitKind::Str(s, _) => { err.span_suggestion( - item.span, + item.span(), "use parentheses instead", format!("align({})", s), Applicability::MachineApplicable @@ -827,7 +826,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { } if !recognised { // Not a word we recognize - span_err!(diagnostic, item.span, E0552, + span_err!(diagnostic, item.span(), E0552, "unrecognized representation hint"); } } @@ -836,22 +835,22 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { acc } -fn int_type_of_word(s: &str) -> Option { +fn int_type_of_word(s: Symbol) -> Option { use IntType::*; match s { - "i8" => Some(SignedInt(ast::IntTy::I8)), - "u8" => Some(UnsignedInt(ast::UintTy::U8)), - "i16" => Some(SignedInt(ast::IntTy::I16)), - "u16" => Some(UnsignedInt(ast::UintTy::U16)), - "i32" => Some(SignedInt(ast::IntTy::I32)), - "u32" => Some(UnsignedInt(ast::UintTy::U32)), - "i64" => Some(SignedInt(ast::IntTy::I64)), - "u64" => Some(UnsignedInt(ast::UintTy::U64)), - "i128" => Some(SignedInt(ast::IntTy::I128)), - "u128" => Some(UnsignedInt(ast::UintTy::U128)), - "isize" => Some(SignedInt(ast::IntTy::Isize)), - "usize" => Some(UnsignedInt(ast::UintTy::Usize)), + sym::i8 => Some(SignedInt(ast::IntTy::I8)), + sym::u8 => Some(UnsignedInt(ast::UintTy::U8)), + sym::i16 => Some(SignedInt(ast::IntTy::I16)), + sym::u16 => Some(UnsignedInt(ast::UintTy::U16)), + sym::i32 => Some(SignedInt(ast::IntTy::I32)), + sym::u32 => Some(UnsignedInt(ast::UintTy::U32)), + sym::i64 => Some(SignedInt(ast::IntTy::I64)), + sym::u64 => Some(UnsignedInt(ast::UintTy::U64)), + sym::i128 => Some(SignedInt(ast::IntTy::I128)), + sym::u128 => Some(UnsignedInt(ast::UintTy::U128)), + sym::isize => Some(SignedInt(ast::IntTy::Isize)), + sym::usize => Some(UnsignedInt(ast::UintTy::Usize)), _ => None } } diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index b5fc850731404..436620ae7293b 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -13,16 +13,16 @@ pub use StabilityLevel::*; use crate::ast; use crate::ast::{AttrId, Attribute, AttrStyle, Name, Ident, Path, PathSegment}; -use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; -use crate::ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind, GenericParam}; +use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; +use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; -use crate::source_map::{BytePos, Spanned, respan, dummy_spanned}; +use crate::source_map::{BytePos, Spanned, dummy_spanned}; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use crate::parse::parser::Parser; use crate::parse::{self, ParseSess, PResult}; use crate::parse::token::{self, Token}; use crate::ptr::P; -use crate::symbol::Symbol; +use crate::symbol::{sym, Symbol}; use crate::ThinVec; use crate::tokenstream::{TokenStream, TokenTree, DelimSpan}; use crate::GLOBALS; @@ -64,36 +64,33 @@ pub fn is_known_lint_tool(m_item: Ident) -> bool { } impl NestedMetaItem { - /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem. + /// Returns the MetaItem if self is a NestedMetaItem::MetaItem. pub fn meta_item(&self) -> Option<&MetaItem> { - match self.node { - NestedMetaItemKind::MetaItem(ref item) => Some(item), + match *self { + NestedMetaItem::MetaItem(ref item) => Some(item), _ => None } } - /// Returns the Lit if self is a NestedMetaItemKind::Literal. + /// Returns the Lit if self is a NestedMetaItem::Literal. pub fn literal(&self) -> Option<&Lit> { - match self.node { - NestedMetaItemKind::Literal(ref lit) => Some(lit), + match *self { + NestedMetaItem::Literal(ref lit) => Some(lit), _ => None } } - /// Returns the Span for `self`. - pub fn span(&self) -> Span { - self.span - } - /// Returns `true` if this list item is a MetaItem with a name of `name`. - pub fn check_name(&self, name: &str) -> bool { + pub fn check_name(&self, name: Symbol) -> bool { self.meta_item().map_or(false, |meta_item| meta_item.check_name(name)) } - /// Returns the name of the meta item, e.g., `foo` in `#[foo]`, - /// `#[foo="bar"]` and `#[foo(bar)]`, if self is a MetaItem - pub fn name(&self) -> Option { - self.meta_item().and_then(|meta_item| Some(meta_item.name())) + /// For a single-segment meta-item returns its name, otherwise returns `None`. + pub fn ident(&self) -> Option { + self.meta_item().and_then(|meta_item| meta_item.ident()) + } + pub fn name_or_empty(&self) -> Symbol { + self.ident().unwrap_or(Ident::invalid()).name } /// Gets the string value if self is a MetaItem and the MetaItem is a @@ -108,25 +105,14 @@ impl NestedMetaItem { |meta_item| meta_item.meta_item_list().and_then( |meta_item_list| { if meta_item_list.len() == 1 { - let nested_item = &meta_item_list[0]; - if nested_item.is_literal() { - Some((meta_item.name(), nested_item.literal().unwrap())) - } else { - None + if let Some(ident) = meta_item.ident() { + if let Some(lit) = meta_item_list[0].literal() { + return Some((ident.name, lit)); + } } } - else { - None - }})) - } - - /// Returns a MetaItem if self is a MetaItem with Kind Word. - pub fn word(&self) -> Option<&MetaItem> { - self.meta_item().and_then(|meta_item| if meta_item.is_word() { - Some(meta_item) - } else { - None - }) + None + })) } /// Gets a list of inner meta items from a list MetaItem type. @@ -146,7 +132,7 @@ impl NestedMetaItem { /// Returns `true` if self is a MetaItem and the meta item is a word. pub fn is_word(&self) -> bool { - self.word().is_some() + self.meta_item().map_or(false, |meta_item| meta_item.is_word()) } /// Returns `true` if self is a MetaItem and the meta item is a ValueString. @@ -160,16 +146,12 @@ impl NestedMetaItem { } } -fn name_from_path(path: &Path) -> Name { - path.segments.last().expect("empty path in attribute").ident.name -} - impl Attribute { /// Returns `true` if the attribute's path matches the argument. If it matches, then the /// attribute is marked as used. /// /// To check the attribute name without marking it used, use the `path` field directly. - pub fn check_name(&self, name: &str) -> bool { + pub fn check_name(&self, name: Symbol) -> bool { let matches = self.path == name; if matches { mark_used(self); @@ -177,10 +159,16 @@ impl Attribute { matches } - /// Returns the **last** segment of the name of this attribute. - /// e.g., `foo` for `#[foo]`, `skip` for `#[rustfmt::skip]`. - pub fn name(&self) -> Name { - name_from_path(&self.path) + /// For a single-segment attribute returns its name, otherwise returns `None`. + pub fn ident(&self) -> Option { + if self.path.segments.len() == 1 { + Some(self.path.segments[0].ident) + } else { + None + } + } + pub fn name_or_empty(&self) -> Symbol { + self.ident().unwrap_or(Ident::invalid()).name } pub fn value_str(&self) -> Option { @@ -195,11 +183,7 @@ impl Attribute { } pub fn is_word(&self) -> bool { - self.path.segments.len() == 1 && self.tokens.is_empty() - } - - pub fn span(&self) -> Span { - self.span + self.tokens.is_empty() } pub fn is_meta_item_list(&self) -> bool { @@ -213,8 +197,16 @@ impl Attribute { } impl MetaItem { - pub fn name(&self) -> Name { - name_from_path(&self.ident) + /// For a single-segment meta-item returns its name, otherwise returns `None`. + pub fn ident(&self) -> Option { + if self.path.segments.len() == 1 { + Some(self.path.segments[0].ident) + } else { + None + } + } + pub fn name_or_empty(&self) -> Symbol { + self.ident().unwrap_or(Ident::invalid()).name } // #[attribute(name = "value")] @@ -252,10 +244,8 @@ impl MetaItem { } } - pub fn span(&self) -> Span { self.span } - - pub fn check_name(&self, name: &str) -> bool { - self.name() == name + pub fn check_name(&self, name: Symbol) -> bool { + self.path == name } pub fn is_value_str(&self) -> bool { @@ -265,14 +255,6 @@ impl MetaItem { pub fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() } - - pub fn is_scoped(&self) -> Option { - if self.ident.segments.len() > 1 { - Some(self.ident.segments[0].ident) - } else { - None - } - } } impl Attribute { @@ -280,7 +262,7 @@ impl Attribute { pub fn meta(&self) -> Option { let mut tokens = self.tokens.trees().peekable(); Some(MetaItem { - ident: self.path.clone(), + path: self.path.clone(), node: if let Some(node) = MetaItemKind::from_tokens(&mut tokens) { if tokens.peek().is_some() { return None; @@ -296,7 +278,14 @@ impl Attribute { pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T> where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { - let mut parser = Parser::new(sess, self.tokens.clone(), None, false, false); + let mut parser = Parser::new( + sess, + self.tokens.clone(), + None, + false, + false, + Some("attribute"), + ); let result = f(&mut parser)?; if parser.token != token::Eof { parser.unexpected()?; @@ -326,7 +315,7 @@ impl Attribute { pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { Ok(MetaItem { - ident: self.path.clone(), + path: self.path.clone(), node: self.parse(sess, |parser| parser.parse_meta_item_kind())?, span: self.span, }) @@ -341,7 +330,7 @@ impl Attribute { if self.is_sugared_doc { let comment = self.value_str().unwrap(); let meta = mk_name_value_item_str( - Ident::from_str("doc"), + Ident::with_empty_ctxt(sym::doc), dummy_spanned(Symbol::intern(&strip_doc_comment_decoration(&comment.as_str())))); let mut attr = if self.style == ast::AttrStyle::Outer { mk_attr_outer(self.span, self.id, meta) @@ -359,24 +348,25 @@ impl Attribute { /* Constructors */ pub fn mk_name_value_item_str(ident: Ident, value: Spanned) -> MetaItem { - let value = respan(value.span, LitKind::Str(value.node, ast::StrStyle::Cooked)); - mk_name_value_item(ident.span.to(value.span), ident, value) + let lit_kind = LitKind::Str(value.node, ast::StrStyle::Cooked); + mk_name_value_item(ident.span.to(value.span), ident, lit_kind, value.span) } -pub fn mk_name_value_item(span: Span, ident: Ident, value: ast::Lit) -> MetaItem { - MetaItem { ident: Path::from_ident(ident), span, node: MetaItemKind::NameValue(value) } +pub fn mk_name_value_item(span: Span, ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem { + let lit = Lit::from_lit_kind(lit_kind, lit_span); + MetaItem { path: Path::from_ident(ident), span, node: MetaItemKind::NameValue(lit) } } pub fn mk_list_item(span: Span, ident: Ident, items: Vec) -> MetaItem { - MetaItem { ident: Path::from_ident(ident), span, node: MetaItemKind::List(items) } + MetaItem { path: Path::from_ident(ident), span, node: MetaItemKind::List(items) } } pub fn mk_word_item(ident: Ident) -> MetaItem { - MetaItem { ident: Path::from_ident(ident), span: ident.span, node: MetaItemKind::Word } + MetaItem { path: Path::from_ident(ident), span: ident.span, node: MetaItemKind::Word } } pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem { - respan(ident.span, NestedMetaItemKind::MetaItem(mk_word_item(ident))) + NestedMetaItem::MetaItem(mk_word_item(ident)) } pub fn mk_attr_id() -> AttrId { @@ -400,7 +390,7 @@ pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: MetaItem) -> Attribute Attribute { id, style: ast::AttrStyle::Inner, - path: item.ident, + path: item.path, tokens: item.node.tokens(item.span), is_sugared_doc: false, span: sp, @@ -417,7 +407,7 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute Attribute { id, style: ast::AttrStyle::Outer, - path: item.ident, + path: item.path, tokens: item.node.tokens(item.span), is_sugared_doc: false, span: sp, @@ -426,39 +416,40 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, span: Span) -> Attribute { let style = doc_comment_style(&text.as_str()); - let lit = respan(span, LitKind::Str(text, ast::StrStyle::Cooked)); + let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked); + let lit = Lit::from_lit_kind(lit_kind, span); Attribute { id, style, - path: Path::from_ident(Ident::from_str("doc").with_span_pos(span)), + path: Path::from_ident(Ident::with_empty_ctxt(sym::doc).with_span_pos(span)), tokens: MetaItemKind::NameValue(lit).tokens(span), is_sugared_doc: true, span, } } -pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool { +pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { items.iter().any(|item| { item.check_name(name) }) } -pub fn contains_name(attrs: &[Attribute], name: &str) -> bool { +pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool { attrs.iter().any(|item| { item.check_name(name) }) } -pub fn find_by_name<'a>(attrs: &'a [Attribute], name: &str) -> Option<&'a Attribute> { +pub fn find_by_name<'a>(attrs: &'a [Attribute], name: Symbol) -> Option<&'a Attribute> { attrs.iter().find(|attr| attr.check_name(name)) } -pub fn filter_by_name<'a>(attrs: &'a [Attribute], name: &'a str) +pub fn filter_by_name<'a>(attrs: &'a [Attribute], name: Symbol) -> impl Iterator { attrs.iter().filter(move |attr| attr.check_name(name)) } -pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option { +pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option { attrs.iter() .find(|at| at.check_name(name)) .and_then(|at| at.value_str()) @@ -468,16 +459,15 @@ impl MetaItem { fn tokens(&self) -> TokenStream { let mut idents = vec![]; let mut last_pos = BytePos(0 as u32); - for (i, segment) in self.ident.segments.iter().enumerate() { + for (i, segment) in self.path.segments.iter().enumerate() { let is_first = i == 0; if !is_first { let mod_sep_span = Span::new(last_pos, segment.ident.span.lo(), segment.ident.span.ctxt()); - idents.push(TokenTree::Token(mod_sep_span, Token::ModSep).into()); + idents.push(TokenTree::token(token::ModSep, mod_sep_span).into()); } - idents.push(TokenTree::Token(segment.ident.span, - Token::from_ast_ident(segment.ident)).into()); + idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into()); last_pos = segment.ident.span.hi(); } self.node.tokens(self.span).append_to_tree_and_joint_vec(&mut idents); @@ -488,27 +478,29 @@ impl MetaItem { where I: Iterator, { // FIXME: Share code with `parse_path`. - let ident = match tokens.next() { - Some(TokenTree::Token(span, token @ Token::Ident(..))) | - Some(TokenTree::Token(span, token @ Token::ModSep)) => 'arm: { - let mut segments = if let Token::Ident(ident, _) = token { - if let Some(TokenTree::Token(_, Token::ModSep)) = tokens.peek() { + let path = match tokens.next() { + Some(TokenTree::Token(Token { kind: kind @ token::Ident(..), span })) | + Some(TokenTree::Token(Token { kind: kind @ token::ModSep, span })) => 'arm: { + let mut segments = if let token::Ident(name, _) = kind { + if let Some(TokenTree::Token(Token { kind: token::ModSep, .. })) + = tokens.peek() { tokens.next(); - vec![PathSegment::from_ident(ident.with_span_pos(span))] + vec![PathSegment::from_ident(Ident::new(name, span))] } else { - break 'arm Path::from_ident(ident.with_span_pos(span)); + break 'arm Path::from_ident(Ident::new(name, span)); } } else { vec![PathSegment::path_root(span)] }; loop { - if let Some(TokenTree::Token(span, - Token::Ident(ident, _))) = tokens.next() { - segments.push(PathSegment::from_ident(ident.with_span_pos(span))); + if let Some(TokenTree::Token(Token { kind: token::Ident(name, _), span })) + = tokens.next() { + segments.push(PathSegment::from_ident(Ident::new(name, span))); } else { return None; } - if let Some(TokenTree::Token(_, Token::ModSep)) = tokens.peek() { + if let Some(TokenTree::Token(Token { kind: token::ModSep, .. })) + = tokens.peek() { tokens.next(); } else { break; @@ -517,7 +509,7 @@ impl MetaItem { let span = span.with_hi(segments.last().unwrap().ident.span.hi()); Path { span, segments } } - Some(TokenTree::Token(_, Token::Interpolated(nt))) => match *nt { + Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt { token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident), token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()), token::Nonterminal::NtPath(ref path) => path.clone(), @@ -529,11 +521,11 @@ impl MetaItem { let node = MetaItemKind::from_tokens(tokens)?; let hi = match node { MetaItemKind::NameValue(ref lit) => lit.span.hi(), - MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(ident.span.hi()), - _ => ident.span.hi(), + MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()), + _ => path.span.hi(), }; - let span = ident.span.with_hi(hi); - Some(MetaItem { ident, node, span }) + let span = path.span.with_hi(hi); + Some(MetaItem { path, node, span }) } } @@ -542,7 +534,7 @@ impl MetaItemKind { match *self { MetaItemKind::Word => TokenStream::empty(), MetaItemKind::NameValue(ref lit) => { - let mut vec = vec![TokenTree::Token(span, Token::Eq).into()]; + let mut vec = vec![TokenTree::token(token::Eq, span).into()]; lit.tokens().append_to_tree_and_joint_vec(&mut vec); TokenStream::new(vec) } @@ -550,9 +542,9 @@ impl MetaItemKind { let mut tokens = Vec::new(); for (i, item) in list.iter().enumerate() { if i > 0 { - tokens.push(TokenTree::Token(span, Token::Comma).into()); + tokens.push(TokenTree::token(token::Comma, span).into()); } - item.node.tokens().append_to_tree_and_joint_vec(&mut tokens); + item.tokens().append_to_tree_and_joint_vec(&mut tokens); } TokenTree::Delimited( DelimSpan::from_single(span), @@ -567,11 +559,10 @@ impl MetaItemKind { where I: Iterator, { let delimited = match tokens.peek().cloned() { - Some(TokenTree::Token(_, token::Eq)) => { + Some(TokenTree::Token(token)) if token == token::Eq => { tokens.next(); - return if let Some(TokenTree::Token(span, token)) = tokens.next() { - LitKind::from_token(token) - .map(|lit| MetaItemKind::NameValue(Spanned { node: lit, span: span })) + return if let Some(TokenTree::Token(token)) = tokens.next() { + Lit::from_token(&token).ok().map(MetaItemKind::NameValue) } else { None }; @@ -586,10 +577,10 @@ impl MetaItemKind { let mut tokens = delimited.into_trees().peekable(); let mut result = Vec::new(); while let Some(..) = tokens.peek() { - let item = NestedMetaItemKind::from_tokens(&mut tokens)?; - result.push(respan(item.span(), item)); + let item = NestedMetaItem::from_tokens(&mut tokens)?; + result.push(item); match tokens.next() { - None | Some(TokenTree::Token(_, Token::Comma)) => {} + None | Some(TokenTree::Token(Token { kind: token::Comma, .. })) => {} _ => return None, } } @@ -597,107 +588,32 @@ impl MetaItemKind { } } -impl NestedMetaItemKind { - fn span(&self) -> Span { +impl NestedMetaItem { + pub fn span(&self) -> Span { match *self { - NestedMetaItemKind::MetaItem(ref item) => item.span, - NestedMetaItemKind::Literal(ref lit) => lit.span, + NestedMetaItem::MetaItem(ref item) => item.span, + NestedMetaItem::Literal(ref lit) => lit.span, } } fn tokens(&self) -> TokenStream { match *self { - NestedMetaItemKind::MetaItem(ref item) => item.tokens(), - NestedMetaItemKind::Literal(ref lit) => lit.tokens(), + NestedMetaItem::MetaItem(ref item) => item.tokens(), + NestedMetaItem::Literal(ref lit) => lit.tokens(), } } - fn from_tokens(tokens: &mut iter::Peekable) -> Option + fn from_tokens(tokens: &mut iter::Peekable) -> Option where I: Iterator, { - if let Some(TokenTree::Token(span, token)) = tokens.peek().cloned() { - if let Some(node) = LitKind::from_token(token) { + if let Some(TokenTree::Token(token)) = tokens.peek() { + if let Ok(lit) = Lit::from_token(token) { tokens.next(); - return Some(NestedMetaItemKind::Literal(respan(span, node))); + return Some(NestedMetaItem::Literal(lit)); } } - MetaItem::from_tokens(tokens).map(NestedMetaItemKind::MetaItem) - } -} - -impl Lit { - crate fn tokens(&self) -> TokenStream { - TokenTree::Token(self.span, self.node.token()).into() - } -} - -impl LitKind { - fn token(&self) -> Token { - use std::ascii; - - match *self { - LitKind::Str(string, ast::StrStyle::Cooked) => { - let escaped = string.as_str().escape_default().to_string(); - Token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None) - } - LitKind::Str(string, ast::StrStyle::Raw(n)) => { - Token::Literal(token::Lit::StrRaw(string, n), None) - } - LitKind::ByteStr(ref bytes) => { - let string = bytes.iter().cloned().flat_map(ascii::escape_default) - .map(Into::::into).collect::(); - Token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None) - } - LitKind::Byte(byte) => { - let string: String = ascii::escape_default(byte).map(Into::::into).collect(); - Token::Literal(token::Lit::Byte(Symbol::intern(&string)), None) - } - LitKind::Char(ch) => { - let string: String = ch.escape_default().map(Into::::into).collect(); - Token::Literal(token::Lit::Char(Symbol::intern(&string)), None) - } - LitKind::Int(n, ty) => { - let suffix = match ty { - ast::LitIntType::Unsigned(ty) => Some(Symbol::intern(ty.ty_to_string())), - ast::LitIntType::Signed(ty) => Some(Symbol::intern(ty.ty_to_string())), - ast::LitIntType::Unsuffixed => None, - }; - Token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())), suffix) - } - LitKind::Float(symbol, ty) => { - Token::Literal(token::Lit::Float(symbol), Some(Symbol::intern(ty.ty_to_string()))) - } - LitKind::FloatUnsuffixed(symbol) => Token::Literal(token::Lit::Float(symbol), None), - LitKind::Bool(value) => Token::Ident(Ident::with_empty_ctxt(Symbol::intern(if value { - "true" - } else { - "false" - })), false), - LitKind::Err(val) => Token::Literal(token::Lit::Err(val), None), - } - } - - fn from_token(token: Token) -> Option { - match token { - Token::Ident(ident, false) if ident.name == "true" => Some(LitKind::Bool(true)), - Token::Ident(ident, false) if ident.name == "false" => Some(LitKind::Bool(false)), - Token::Interpolated(nt) => match *nt { - token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node { - ExprKind::Lit(ref lit) => Some(lit.node.clone()), - _ => None, - }, - _ => None, - }, - Token::Literal(lit, suf) => { - let (suffix_illegal, result) = parse::lit_token(lit, suf, None); - if suffix_illegal && suf.is_some() { - return None; - } - result - } - _ => None, - } + MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem) } } @@ -807,7 +723,7 @@ macro_rules! derive_has_attrs { derive_has_attrs! { Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm, - ast::Field, ast::FieldPat, ast::Variant_ + ast::Field, ast::FieldPat, ast::Variant_, ast::Arg } pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { @@ -818,9 +734,9 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - raw_attr.clone(), ); - let start_span = parser.span; + let start_span = parser.token.span; let (path, tokens) = panictry!(parser.parse_meta_item_unrestricted()); - let end_span = parser.span; + let end_span = parser.token.span; if parser.token != token::Eof { parse_sess.span_diagnostic .span_err(start_span.to(end_span), "invalid crate attribute"); diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 4e4432a3f334d..1ab367f73c1b3 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -12,6 +12,7 @@ use crate::edition::Edition; use crate::mut_visit::*; use crate::parse::{token, ParseSess}; use crate::ptr::P; +use crate::symbol::sym; use crate::util::map_in_place::MapInPlace; use errors::Applicability; @@ -24,8 +25,8 @@ pub struct StripUnconfigured<'a> { } // `cfg_attr`-process the crate's attributes and compute the crate's features. -pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition) - -> (ast::Crate, Features) { +pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition, + allow_features: &Option>) -> (ast::Crate, Features) { let features; { let mut strip_unconfigured = StripUnconfigured { @@ -43,7 +44,7 @@ pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition) return (krate, Features::new()); } - features = get_features(&sess.span_diagnostic, &krate.attrs, edition); + features = get_features(&sess.span_diagnostic, &krate.attrs, edition, allow_features); // Avoid reconfiguring malformed `cfg_attr`s if err_count == sess.span_diagnostic.err_count() { @@ -90,9 +91,25 @@ impl<'a> StripUnconfigured<'a> { /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { - if !attr.check_name("cfg_attr") { + if attr.path != sym::cfg_attr { return vec![attr]; } + if attr.tokens.is_empty() { + self.sess.span_diagnostic + .struct_span_err( + attr.span, + "malformed `cfg_attr` attribute input", + ).span_suggestion( + attr.span, + "missing condition and attribute", + "#[cfg_attr(condition, attribute, other_attribute, ...)]".to_owned(), + Applicability::HasPlaceholders, + ).note("for more information, visit \ + ") + .emit(); + return vec![]; + } let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| { parser.expect(&token::OpenDelim(token::Paren))?; @@ -104,7 +121,7 @@ impl<'a> StripUnconfigured<'a> { let mut expanded_attrs = Vec::with_capacity(1); while !parser.check(&token::CloseDelim(token::Paren)) { - let lo = parser.span.lo(); + let lo = parser.token.span.lo(); let (path, tokens) = parser.parse_meta_item_unrestricted()?; expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo))); parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?; @@ -116,17 +133,18 @@ impl<'a> StripUnconfigured<'a> { Ok(result) => result, Err(mut e) => { e.emit(); - return Vec::new(); + return vec![]; } }; - // Check feature gate and lint on zero attributes in source. Even if the feature is gated, - // we still compute as if it wasn't, since the emitted error will stop compilation further - // along the compilation. - if expanded_attrs.len() == 0 { - // FIXME: Emit unused attribute lint here. + // Lint on zero attributes in source. + if expanded_attrs.is_empty() { + return vec![attr]; } + // At this point we know the attribute is considered used. + attr::mark_used(&attr); + if attr::cfg_matches(&cfg_predicate, self.sess, self.features) { // We call `process_cfg_attr` recursively in case there's a // `cfg_attr` inside of another `cfg_attr`. E.g. @@ -142,7 +160,7 @@ impl<'a> StripUnconfigured<'a> { })) .collect() } else { - Vec::new() + vec![] } } @@ -181,13 +199,13 @@ impl<'a> StripUnconfigured<'a> { if nested_meta_items.is_empty() { return error(meta_item.span, "`cfg` predicate is not specified", ""); } else if nested_meta_items.len() > 1 { - return error(nested_meta_items.last().unwrap().span, + return error(nested_meta_items.last().unwrap().span(), "multiple `cfg` predicates are specified", ""); } match nested_meta_items[0].meta_item() { Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features), - None => error(nested_meta_items[0].span, + None => error(nested_meta_items[0].span(), "`cfg` predicate key cannot be a literal", ""), } }) @@ -205,7 +223,7 @@ impl<'a> StripUnconfigured<'a> { pub fn maybe_emit_expr_attr_err(&self, attr: &ast::Attribute) { if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { let mut err = feature_err(self.sess, - "stmt_expr_attributes", + sym::stmt_expr_attributes, attr.span, GateIssue::Language, EXPLAIN_STMT_ATTR_SYNTAX); @@ -223,12 +241,15 @@ impl<'a> StripUnconfigured<'a> { items.flat_map_in_place(|item| self.configure(item)); } + pub fn configure_generic_params(&mut self, params: &mut Vec) { + params.flat_map_in_place(|param| self.configure(param)); + } + fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) { match vdata { - ast::VariantData::Struct(fields, _id) | - ast::VariantData::Tuple(fields, _id) => + ast::VariantData::Struct(fields, ..) | ast::VariantData::Tuple(fields, _) => fields.flat_map_in_place(|field| self.configure(field)), - ast::VariantData::Unit(_id) => {} + ast::VariantData::Unit(_) => {} } } @@ -282,20 +303,8 @@ impl<'a> StripUnconfigured<'a> { } } - /// Denies `#[cfg]` on generic parameters until we decide what to do with it. - /// See issue #51279. - pub fn disallow_cfg_on_generic_param(&mut self, param: &ast::GenericParam) { - for attr in param.attrs() { - let offending_attr = if attr.check_name("cfg") { - "cfg" - } else if attr.check_name("cfg_attr") { - "cfg_attr" - } else { - continue; - }; - let msg = format!("#[{}] cannot be applied on a generic parameter", offending_attr); - self.sess.span_diagnostic.span_err(attr.span, &msg); - } + pub fn configure_fn_decl(&mut self, fn_decl: &mut ast::FnDecl) { + fn_decl.inputs.flat_map_in_place(|arg| self.configure(arg)); } } @@ -348,8 +357,13 @@ impl<'a> MutVisitor for StripUnconfigured<'a> { self.configure_pat(pat); noop_visit_pat(pat, self) } + + fn visit_fn_decl(&mut self, mut fn_decl: &mut P) { + self.configure_fn_decl(&mut fn_decl); + noop_visit_fn_decl(fn_decl, self); + } } fn is_cfg(attr: &ast::Attribute) -> bool { - attr.check_name("cfg") + attr.check_name(sym::cfg) } diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs deleted file mode 100644 index 2c367f1f40242..0000000000000 --- a/src/libsyntax/diagnostic_list.rs +++ /dev/null @@ -1,407 +0,0 @@ -#![allow(non_snake_case)] - -// Error messages for EXXXX errors. -// Each message should start and end with a new line, and be wrapped to 80 characters. -// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. -register_long_diagnostics! { - -E0178: r##" -In types, the `+` type operator has low precedence, so it is often necessary -to use parentheses. - -For example: - -```compile_fail,E0178 -trait Foo {} - -struct Bar<'a> { - w: &'a Foo + Copy, // error, use &'a (Foo + Copy) - x: &'a Foo + 'a, // error, use &'a (Foo + 'a) - y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a) - z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a) -} -``` - -More details can be found in [RFC 438]. - -[RFC 438]: https://github.com/rust-lang/rfcs/pull/438 -"##, - -E0536: r##" -The `not` cfg-predicate was malformed. - -Erroneous code example: - -```compile_fail,E0536 -#[cfg(not())] // error: expected 1 cfg-pattern -pub fn something() {} - -pub fn main() {} -``` - -The `not` predicate expects one cfg-pattern. Example: - -``` -#[cfg(not(target_os = "linux"))] // ok! -pub fn something() {} - -pub fn main() {} -``` - -For more information about the cfg attribute, read: -https://doc.rust-lang.org/reference.html#conditional-compilation -"##, - -E0537: r##" -An unknown predicate was used inside the `cfg` attribute. - -Erroneous code example: - -```compile_fail,E0537 -#[cfg(unknown())] // error: invalid predicate `unknown` -pub fn something() {} - -pub fn main() {} -``` - -The `cfg` attribute supports only three kinds of predicates: - - * any - * all - * not - -Example: - -``` -#[cfg(not(target_os = "linux"))] // ok! -pub fn something() {} - -pub fn main() {} -``` - -For more information about the cfg attribute, read: -https://doc.rust-lang.org/reference.html#conditional-compilation -"##, - -E0538: r##" -Attribute contains same meta item more than once. - -Erroneous code example: - -```compile_fail,E0538 -#[deprecated( - since="1.0.0", - note="First deprecation note.", - note="Second deprecation note." // error: multiple same meta item -)] -fn deprecated_function() {} -``` - -Meta items are the key-value pairs inside of an attribute. Each key may only be -used once in each attribute. - -To fix the problem, remove all but one of the meta items with the same key. - -Example: - -``` -#[deprecated( - since="1.0.0", - note="First deprecation note." -)] -fn deprecated_function() {} -``` -"##, - -E0541: r##" -An unknown meta item was used. - -Erroneous code example: - -```compile_fail,E0541 -#[deprecated( - since="1.0.0", - // error: unknown meta item - reason="Example invalid meta item. Should be 'note'") -] -fn deprecated_function() {} -``` - -Meta items are the key-value pairs inside of an attribute. The keys provided -must be one of the valid keys for the specified attribute. - -To fix the problem, either remove the unknown meta item, or rename it if you -provided the wrong name. - -In the erroneous code example above, the wrong name was provided, so changing -to a correct one it will fix the error. Example: - -``` -#[deprecated( - since="1.0.0", - note="This is a valid meta item for the deprecated attribute." -)] -fn deprecated_function() {} -``` -"##, - -E0552: r##" -A unrecognized representation attribute was used. - -Erroneous code example: - -```compile_fail,E0552 -#[repr(D)] // error: unrecognized representation hint -struct MyStruct { - my_field: usize -} -``` - -You can use a `repr` attribute to tell the compiler how you want a struct or -enum to be laid out in memory. - -Make sure you're using one of the supported options: - -``` -#[repr(C)] // ok! -struct MyStruct { - my_field: usize -} -``` - -For more information about specifying representations, see the ["Alternative -Representations" section] of the Rustonomicon. - -["Alternative Representations" section]: https://doc.rust-lang.org/nomicon/other-reprs.html -"##, - -E0554: r##" -Feature attributes are only allowed on the nightly release channel. Stable or -beta compilers will not comply. - -Example of erroneous code (on a stable compiler): - -```ignore (depends on release channel) -#![feature(non_ascii_idents)] // error: #![feature] may not be used on the - // stable release channel -``` - -If you need the feature, make sure to use a nightly release of the compiler -(but be warned that the feature may be removed or altered in the future). -"##, - -E0557: r##" -A feature attribute named a feature that has been removed. - -Erroneous code example: - -```compile_fail,E0557 -#![feature(managed_boxes)] // error: feature has been removed -``` - -Delete the offending feature attribute. -"##, - -E0565: r##" -A literal was used in a built-in attribute that doesn't support literals. - -Erroneous code example: - -```ignore (compile_fail not working here; see Issue #43707) -#[inline("always")] // error: unsupported literal -pub fn something() {} -``` - -Literals in attributes are new and largely unsupported in built-in attributes. -Work to support literals where appropriate is ongoing. Try using an unquoted -name instead: - -``` -#[inline(always)] -pub fn something() {} -``` -"##, - -E0583: r##" -A file wasn't found for an out-of-line module. - -Erroneous code example: - -```ignore (compile_fail not working here; see Issue #43707) -mod file_that_doesnt_exist; // error: file not found for module - -fn main() {} -``` - -Please be sure that a file corresponding to the module exists. If you -want to use a module named `file_that_doesnt_exist`, you need to have a file -named `file_that_doesnt_exist.rs` or `file_that_doesnt_exist/mod.rs` in the -same directory. -"##, - -E0585: r##" -A documentation comment that doesn't document anything was found. - -Erroneous code example: - -```compile_fail,E0585 -fn main() { - // The following doc comment will fail: - /// This is a useless doc comment! -} -``` - -Documentation comments need to be followed by items, including functions, -types, modules, etc. Examples: - -``` -/// I'm documenting the following struct: -struct Foo; - -/// I'm documenting the following function: -fn foo() {} -``` -"##, - -E0586: r##" -An inclusive range was used with no end. - -Erroneous code example: - -```compile_fail,E0586 -fn main() { - let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; - let x = &tmp[1..=]; // error: inclusive range was used with no end -} -``` - -An inclusive range needs an end in order to *include* it. If you just need a -start and no end, use a non-inclusive range (with `..`): - -``` -fn main() { - let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; - let x = &tmp[1..]; // ok! -} -``` - -Or put an end to your inclusive range: - -``` -fn main() { - let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; - let x = &tmp[1..=3]; // ok! -} -``` -"##, - -E0589: r##" -The value of `N` that was specified for `repr(align(N))` was not a power -of two, or was greater than 2^29. - -```compile_fail,E0589 -#[repr(align(15))] // error: invalid `repr(align)` attribute: not a power of two -enum Foo { - Bar(u64), -} -``` -"##, - -E0658: r##" -An unstable feature was used. - -Erroneous code example: - -```compile_fail,E658 -#[repr(u128)] // error: use of unstable library feature 'repr128' -enum Foo { - Bar(u64), -} -``` - -If you're using a stable or a beta version of rustc, you won't be able to use -any unstable features. In order to do so, please switch to a nightly version of -rustc (by using rustup). - -If you're using a nightly version of rustc, just add the corresponding feature -to be able to use it: - -``` -#![feature(repr128)] - -#[repr(u128)] // ok! -enum Foo { - Bar(u64), -} -``` -"##, - -E0633: r##" -The `unwind` attribute was malformed. - -Erroneous code example: - -```ignore (compile_fail not working here; see Issue #43707) -#[unwind()] // error: expected one argument -pub extern fn something() {} - -fn main() {} -``` - -The `#[unwind]` attribute should be used as follows: - -- `#[unwind(aborts)]` -- specifies that if a non-Rust ABI function - should abort the process if it attempts to unwind. This is the safer - and preferred option. - -- `#[unwind(allowed)]` -- specifies that a non-Rust ABI function - should be allowed to unwind. This can easily result in Undefined - Behavior (UB), so be careful. - -NB. The default behavior here is "allowed", but this is unspecified -and likely to change in the future. - -"##, - -E0705: r##" -A `#![feature]` attribute was declared for a feature that is stable in -the current edition, but not in all editions. - -Erroneous code example: - -```ignore (limited to a warning during 2018 edition development) -#![feature(rust_2018_preview)] -#![feature(test_2018_feature)] // error: the feature - // `test_2018_feature` is - // included in the Rust 2018 edition -``` - -"##, - -} - -register_diagnostics! { - E0539, // incorrect meta item - E0540, // multiple rustc_deprecated attributes - E0542, // missing 'since' - E0543, // missing 'reason' - E0544, // multiple stability levels - E0545, // incorrect 'issue' - E0546, // missing 'feature' - E0547, // missing 'issue' -// E0548, // replaced with a generic attribute input check - E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute - E0550, // multiple deprecated attributes - E0551, // incorrect meta item - E0553, // multiple rustc_const_unstable attributes -// E0555, // replaced with a generic attribute input check - E0556, // malformed feature, expected just one word - E0584, // file for module `..` found at both .. and .. - E0629, // missing 'feature' (rustc_const_unstable) - E0630, // rustc_const_unstable attribute must be paired with stable/unstable attribute - E0693, // incorrect `repr(align)` attribute format - E0694, // an unknown tool name found in scoped attributes - E0703, // invalid ABI - E0704, // incorrect visibility restriction - E0717, // rustc_promotable without stability attribute -} diff --git a/src/libsyntax/diagnostics/metadata.rs b/src/libsyntax/diagnostics/metadata.rs index 704135fe1d589..53f37bb10bdc0 100644 --- a/src/libsyntax/diagnostics/metadata.rs +++ b/src/libsyntax/diagnostics/metadata.rs @@ -36,9 +36,9 @@ pub struct ErrorLocation { impl ErrorLocation { /// Creates an error location from a span. pub fn from_span(ecx: &ExtCtxt<'_>, sp: Span) -> ErrorLocation { - let loc = ecx.source_map().lookup_char_pos_adj(sp.lo()); + let loc = ecx.source_map().lookup_char_pos(sp.lo()); ErrorLocation { - filename: loc.filename, + filename: loc.file.name.clone(), line: loc.line } } diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 21024eb41ef50..ee640a1603a6c 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -5,9 +5,9 @@ use crate::ast::{self, Ident, Name}; use crate::source_map; use crate::ext::base::{ExtCtxt, MacEager, MacResult}; use crate::ext::build::AstBuilder; -use crate::parse::token; +use crate::parse::token::{self, Token}; use crate::ptr::P; -use crate::symbol::{keywords, Symbol}; +use crate::symbol::kw; use crate::tokenstream::{TokenTree}; use smallvec::smallvec; @@ -33,13 +33,15 @@ pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt<'_>, span: Span, token_tree: &[TokenTree]) -> Box { - let code = match (token_tree.len(), token_tree.get(0)) { - (1, Some(&TokenTree::Token(_, token::Ident(code, _)))) => code, + let code = match token_tree { + [ + TokenTree::Token(Token { kind: token::Ident(code, _), .. }) + ] => code, _ => unreachable!() }; ecx.parse_sess.registered_diagnostics.with_lock(|diagnostics| { - match diagnostics.get_mut(&code.name) { + match diagnostics.get_mut(&code) { // Previously used errors. Some(&mut ErrorInfo { description: _, use_site: Some(previous_span) }) => { ecx.struct_span_warn(span, &format!( @@ -66,20 +68,19 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt<'_>, span: Span, token_tree: &[TokenTree]) -> Box { - let (code, description) = match ( - token_tree.len(), - token_tree.get(0), - token_tree.get(1), - token_tree.get(2) - ) { - (1, Some(&TokenTree::Token(_, token::Ident(ref code, _))), None, None) => { - (code, None) + let (code, description) = match token_tree { + [ + TokenTree::Token(Token { kind: token::Ident(code, _), .. }) + ] => { + (*code, None) + }, + [ + TokenTree::Token(Token { kind: token::Ident(code, _), .. }), + TokenTree::Token(Token { kind: token::Comma, .. }), + TokenTree::Token(Token { kind: token::Literal(token::Lit { symbol, .. }), ..}) + ] => { + (*code, Some(*symbol)) }, - (3, Some(&TokenTree::Token(_, token::Ident(ref code, _))), - Some(&TokenTree::Token(_, token::Comma)), - Some(&TokenTree::Token(_, token::Literal(token::StrRaw(description, _), None)))) => { - (code, Some(description)) - } _ => unreachable!() }; @@ -112,26 +113,14 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt<'_>, description, use_site: None }; - if diagnostics.insert(code.name, info).is_some() { + if diagnostics.insert(code, info).is_some() { ecx.span_err(span, &format!( "diagnostic code {} already registered", code )); } }); - let span = span.apply_mark(ecx.current_expansion.mark); - - let sym = Ident::new(Symbol::gensym(&format!("__register_diagnostic_{}", code)), span); - - MacEager::items(smallvec![ - ecx.item_mod( - span, - span, - sym, - vec![], - vec![], - ) - ]) + MacEager::items(smallvec![]) } #[allow(deprecated)] @@ -140,13 +129,13 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt<'_>, token_tree: &[TokenTree]) -> Box { assert_eq!(token_tree.len(), 3); - let (crate_name, name) = match (&token_tree[0], &token_tree[2]) { + let (crate_name, ident) = match (&token_tree[0], &token_tree[2]) { ( // Crate name. - &TokenTree::Token(_, token::Ident(ref crate_name, _)), + &TokenTree::Token(Token { kind: token::Ident(crate_name, _), .. }), // DIAGNOSTICS ident. - &TokenTree::Token(_, token::Ident(ref name, _)) - ) => (*&crate_name, name), + &TokenTree::Token(Token { kind: token::Ident(name, _), span }) + ) => (crate_name, Ident::new(name, span)), _ => unreachable!() }; @@ -185,7 +174,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt<'_>, (descriptions.len(), ecx.expr_vec(span, descriptions)) }); - let static_ = ecx.lifetime(span, keywords::StaticLifetime.ident()); + let static_ = ecx.lifetime(span, Ident::with_empty_ctxt(kw::StaticLifetime)); let ty_str = ecx.ty_rptr( span, ecx.ty_ident(span, ecx.ident_of("str")), @@ -209,7 +198,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt<'_>, MacEager::items(smallvec![ P(ast::Item { - ident: *name, + ident, attrs: Vec::new(), id: ast::DUMMY_NODE_ID, node: ast::ItemKind::Const( diff --git a/src/libsyntax/early_buffered_lints.rs b/src/libsyntax/early_buffered_lints.rs index 29cb9cd7f30b5..b26a1165fed1d 100644 --- a/src/libsyntax/early_buffered_lints.rs +++ b/src/libsyntax/early_buffered_lints.rs @@ -3,17 +3,13 @@ //! Since we cannot have a dependency on `librustc`, we implement some types here that are somewhat //! redundant. Later, these types can be converted to types for use by the rest of the compiler. -use crate::syntax::ast::NodeId; +use crate::ast::NodeId; use syntax_pos::MultiSpan; /// Since we cannot import `LintId`s from `rustc::lint`, we define some Ids here which can later be /// passed to `rustc::lint::Lint::from_parser_lint_id` to get a `rustc::lint::Lint`. pub enum BufferedEarlyLintId { - /// Usage of `?` as a macro separator is deprecated. - QuestionMarkMacroSep, IllFormedAttributeInput, - /// Usage of a duplicate macro matcher binding name. - DuplicateMacroMatcherBindingName, } /// Stores buffered lint info which can later be passed to `librustc`. diff --git a/src/libsyntax/entry.rs b/src/libsyntax/entry.rs index 09e26e29d86a8..0b6cf30bd27d2 100644 --- a/src/libsyntax/entry.rs +++ b/src/libsyntax/entry.rs @@ -1,5 +1,6 @@ use crate::attr; use crate::ast::{Item, ItemKind}; +use crate::symbol::sym; pub enum EntryPointType { None, @@ -14,11 +15,11 @@ pub enum EntryPointType { pub fn entry_point_type(item: &Item, depth: usize) -> EntryPointType { match item.node { ItemKind::Fn(..) => { - if attr::contains_name(&item.attrs, "start") { + if attr::contains_name(&item.attrs, sym::start) { EntryPointType::Start - } else if attr::contains_name(&item.attrs, "main") { + } else if attr::contains_name(&item.attrs, sym::main) { EntryPointType::MainAttr - } else if item.ident.name == "main" { + } else if item.ident.name == sym::main { if depth == 1 { // This is a top-level function so can be 'main' EntryPointType::MainNamed diff --git a/src/libsyntax/error_codes.rs b/src/libsyntax/error_codes.rs new file mode 100644 index 0000000000000..e2d212eb721ff --- /dev/null +++ b/src/libsyntax/error_codes.rs @@ -0,0 +1,450 @@ +#![allow(non_snake_case)] + +// Error messages for EXXXX errors. +// Each message should start and end with a new line, and be wrapped to 80 characters. +// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. +register_long_diagnostics! { + +E0178: r##" +In types, the `+` type operator has low precedence, so it is often necessary +to use parentheses. + +For example: + +```compile_fail,E0178 +trait Foo {} + +struct Bar<'a> { + w: &'a Foo + Copy, // error, use &'a (Foo + Copy) + x: &'a Foo + 'a, // error, use &'a (Foo + 'a) + y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a) + z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a) +} +``` + +More details can be found in [RFC 438]. + +[RFC 438]: https://github.com/rust-lang/rfcs/pull/438 +"##, + +E0536: r##" +The `not` cfg-predicate was malformed. + +Erroneous code example: + +```compile_fail,E0536 +#[cfg(not())] // error: expected 1 cfg-pattern +pub fn something() {} + +pub fn main() {} +``` + +The `not` predicate expects one cfg-pattern. Example: + +``` +#[cfg(not(target_os = "linux"))] // ok! +pub fn something() {} + +pub fn main() {} +``` + +For more information about the cfg attribute, read: +https://doc.rust-lang.org/reference.html#conditional-compilation +"##, + +E0537: r##" +An unknown predicate was used inside the `cfg` attribute. + +Erroneous code example: + +```compile_fail,E0537 +#[cfg(unknown())] // error: invalid predicate `unknown` +pub fn something() {} + +pub fn main() {} +``` + +The `cfg` attribute supports only three kinds of predicates: + + * any + * all + * not + +Example: + +``` +#[cfg(not(target_os = "linux"))] // ok! +pub fn something() {} + +pub fn main() {} +``` + +For more information about the cfg attribute, read: +https://doc.rust-lang.org/reference.html#conditional-compilation +"##, + +E0538: r##" +Attribute contains same meta item more than once. + +Erroneous code example: + +```compile_fail,E0538 +#[deprecated( + since="1.0.0", + note="First deprecation note.", + note="Second deprecation note." // error: multiple same meta item +)] +fn deprecated_function() {} +``` + +Meta items are the key-value pairs inside of an attribute. Each key may only be +used once in each attribute. + +To fix the problem, remove all but one of the meta items with the same key. + +Example: + +``` +#[deprecated( + since="1.0.0", + note="First deprecation note." +)] +fn deprecated_function() {} +``` +"##, + +E0541: r##" +An unknown meta item was used. + +Erroneous code example: + +```compile_fail,E0541 +#[deprecated( + since="1.0.0", + // error: unknown meta item + reason="Example invalid meta item. Should be 'note'") +] +fn deprecated_function() {} +``` + +Meta items are the key-value pairs inside of an attribute. The keys provided +must be one of the valid keys for the specified attribute. + +To fix the problem, either remove the unknown meta item, or rename it if you +provided the wrong name. + +In the erroneous code example above, the wrong name was provided, so changing +to a correct one it will fix the error. Example: + +``` +#[deprecated( + since="1.0.0", + note="This is a valid meta item for the deprecated attribute." +)] +fn deprecated_function() {} +``` +"##, + +E0552: r##" +A unrecognized representation attribute was used. + +Erroneous code example: + +```compile_fail,E0552 +#[repr(D)] // error: unrecognized representation hint +struct MyStruct { + my_field: usize +} +``` + +You can use a `repr` attribute to tell the compiler how you want a struct or +enum to be laid out in memory. + +Make sure you're using one of the supported options: + +``` +#[repr(C)] // ok! +struct MyStruct { + my_field: usize +} +``` + +For more information about specifying representations, see the ["Alternative +Representations" section] of the Rustonomicon. + +["Alternative Representations" section]: https://doc.rust-lang.org/nomicon/other-reprs.html +"##, + +E0554: r##" +Feature attributes are only allowed on the nightly release channel. Stable or +beta compilers will not comply. + +Example of erroneous code (on a stable compiler): + +```ignore (depends on release channel) +#![feature(non_ascii_idents)] // error: #![feature] may not be used on the + // stable release channel +``` + +If you need the feature, make sure to use a nightly release of the compiler +(but be warned that the feature may be removed or altered in the future). +"##, + +E0557: r##" +A feature attribute named a feature that has been removed. + +Erroneous code example: + +```compile_fail,E0557 +#![feature(managed_boxes)] // error: feature has been removed +``` + +Delete the offending feature attribute. +"##, + +E0565: r##" +A literal was used in a built-in attribute that doesn't support literals. + +Erroneous code example: + +```ignore (compile_fail not working here; see Issue #43707) +#[inline("always")] // error: unsupported literal +pub fn something() {} +``` + +Literals in attributes are new and largely unsupported in built-in attributes. +Work to support literals where appropriate is ongoing. Try using an unquoted +name instead: + +``` +#[inline(always)] +pub fn something() {} +``` +"##, + +E0583: r##" +A file wasn't found for an out-of-line module. + +Erroneous code example: + +```ignore (compile_fail not working here; see Issue #43707) +mod file_that_doesnt_exist; // error: file not found for module + +fn main() {} +``` + +Please be sure that a file corresponding to the module exists. If you +want to use a module named `file_that_doesnt_exist`, you need to have a file +named `file_that_doesnt_exist.rs` or `file_that_doesnt_exist/mod.rs` in the +same directory. +"##, + +E0585: r##" +A documentation comment that doesn't document anything was found. + +Erroneous code example: + +```compile_fail,E0585 +fn main() { + // The following doc comment will fail: + /// This is a useless doc comment! +} +``` + +Documentation comments need to be followed by items, including functions, +types, modules, etc. Examples: + +``` +/// I'm documenting the following struct: +struct Foo; + +/// I'm documenting the following function: +fn foo() {} +``` +"##, + +E0586: r##" +An inclusive range was used with no end. + +Erroneous code example: + +```compile_fail,E0586 +fn main() { + let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; + let x = &tmp[1..=]; // error: inclusive range was used with no end +} +``` + +An inclusive range needs an end in order to *include* it. If you just need a +start and no end, use a non-inclusive range (with `..`): + +``` +fn main() { + let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; + let x = &tmp[1..]; // ok! +} +``` + +Or put an end to your inclusive range: + +``` +fn main() { + let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; + let x = &tmp[1..=3]; // ok! +} +``` +"##, + +E0589: r##" +The value of `N` that was specified for `repr(align(N))` was not a power +of two, or was greater than 2^29. + +```compile_fail,E0589 +#[repr(align(15))] // error: invalid `repr(align)` attribute: not a power of two +enum Foo { + Bar(u64), +} +``` +"##, + +E0658: r##" +An unstable feature was used. + +Erroneous code example: + +```compile_fail,E658 +#[repr(u128)] // error: use of unstable library feature 'repr128' +enum Foo { + Bar(u64), +} +``` + +If you're using a stable or a beta version of rustc, you won't be able to use +any unstable features. In order to do so, please switch to a nightly version of +rustc (by using rustup). + +If you're using a nightly version of rustc, just add the corresponding feature +to be able to use it: + +``` +#![feature(repr128)] + +#[repr(u128)] // ok! +enum Foo { + Bar(u64), +} +``` +"##, + +E0633: r##" +The `unwind` attribute was malformed. + +Erroneous code example: + +```ignore (compile_fail not working here; see Issue #43707) +#[unwind()] // error: expected one argument +pub extern fn something() {} + +fn main() {} +``` + +The `#[unwind]` attribute should be used as follows: + +- `#[unwind(aborts)]` -- specifies that if a non-Rust ABI function + should abort the process if it attempts to unwind. This is the safer + and preferred option. + +- `#[unwind(allowed)]` -- specifies that a non-Rust ABI function + should be allowed to unwind. This can easily result in Undefined + Behavior (UB), so be careful. + +NB. The default behavior here is "allowed", but this is unspecified +and likely to change in the future. + +"##, + +E0704: r##" +This error indicates that a incorrect visibility restriction was specified. + +Example of erroneous code: + +```compile_fail,E0704 +mod foo { + pub(foo) struct Bar { + x: i32 + } +} +``` + +To make struct `Bar` only visible in module `foo` the `in` keyword should be +used: +``` +mod foo { + pub(in crate::foo) struct Bar { + x: i32 + } +} +# fn main() {} +``` + +For more information see the Rust Reference on [Visibility]. + +[Visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html +"##, + +E0705: r##" +A `#![feature]` attribute was declared for a feature that is stable in +the current edition, but not in all editions. + +Erroneous code example: + +```ignore (limited to a warning during 2018 edition development) +#![feature(rust_2018_preview)] +#![feature(test_2018_feature)] // error: the feature + // `test_2018_feature` is + // included in the Rust 2018 edition +``` + +"##, + +E0725: r##" +A feature attribute named a feature that was disallowed in the compiler +command line flags. + +Erroneous code example: + +```ignore (can't specify compiler flags from doctests) +#![feature(never_type)] // error: the feature `never_type` is not in + // the list of allowed features +``` + +Delete the offending feature attribute, or add it to the list of allowed +features in the `-Z allow_features` flag. +"##, + +} + +register_diagnostics! { + E0539, // incorrect meta item + E0540, // multiple rustc_deprecated attributes + E0542, // missing 'since' + E0543, // missing 'reason' + E0544, // multiple stability levels + E0545, // incorrect 'issue' + E0546, // missing 'feature' + E0547, // missing 'issue' +// E0548, // replaced with a generic attribute input check + E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute + E0550, // multiple deprecated attributes + E0551, // incorrect meta item + E0553, // multiple rustc_const_unstable attributes +// E0555, // replaced with a generic attribute input check + E0556, // malformed feature, expected just one word + E0584, // file for module `..` found at both .. and .. + E0629, // missing 'feature' (rustc_const_unstable) + E0630, // rustc_const_unstable attribute must be paired with stable/unstable attribute + E0693, // incorrect `repr(align)` attribute format + E0694, // an unknown tool name found in scoped attributes + E0703, // invalid ABI + E0717, // rustc_promotable without stability attribute +} diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 452cc2f2c65cc..318a5a3a82a2e 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -1,22 +1,21 @@ -pub use SyntaxExtension::*; - -use crate::ast::{self, Attribute, Name, PatKind, MetaItem}; +use crate::ast::{self, Attribute, Name, PatKind}; use crate::attr::HasAttrs; use crate::source_map::{SourceMap, Spanned, respan}; use crate::edition::Edition; use crate::ext::expand::{self, AstFragment, Invocation}; -use crate::ext::hygiene::{self, Mark, SyntaxContext, Transparency}; +use crate::ext::hygiene::{Mark, SyntaxContext, Transparency}; use crate::mut_visit::{self, MutVisitor}; use crate::parse::{self, parser, DirectoryOwnership}; use crate::parse::token; use crate::ptr::P; -use crate::symbol::{keywords, Ident, Symbol}; -use crate::ThinVec; +use crate::symbol::{kw, sym, Ident, Symbol}; +use crate::{ThinVec, MACRO_ARGUMENTS}; use crate::tokenstream::{self, TokenStream}; use errors::{DiagnosticBuilder, DiagnosticId}; use smallvec::{smallvec, SmallVec}; use syntax_pos::{Span, MultiSpan, DUMMY_SP}; +use syntax_pos::hygiene::{ExpnInfo, ExpnFormat}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; @@ -137,29 +136,6 @@ impl Annotatable { } } -// A more flexible ItemDecorator. -pub trait MultiItemDecorator { - fn expand(&self, - ecx: &mut ExtCtxt<'_>, - sp: Span, - meta_item: &ast::MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)); -} - -impl MultiItemDecorator for F - where F : Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)) -{ - fn expand(&self, - ecx: &mut ExtCtxt<'_>, - sp: Span, - meta_item: &ast::MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { - (*self)(ecx, sp, meta_item, item, push) - } -} - // `meta_item` is the annotation, and `item` is the item being modified. // FIXME Decorators should follow the same pattern too. pub trait MultiItemModifier { @@ -265,10 +241,13 @@ impl TTMacroExpander for F impl MutVisitor for AvoidInterpolatedIdents { fn visit_tt(&mut self, tt: &mut tokenstream::TokenTree) { - if let tokenstream::TokenTree::Token(_, token::Interpolated(nt)) = tt { - if let token::NtIdent(ident, is_raw) = **nt { - *tt = tokenstream::TokenTree::Token(ident.span, - token::Ident(ident, is_raw)); + if let tokenstream::TokenTree::Token(token) = tt { + if let token::Interpolated(nt) = &token.kind { + if let token::NtIdent(ident, is_raw) = **nt { + *tt = tokenstream::TokenTree::token( + token::Ident(ident.name, is_raw), ident.span + ); + } } } mut_visit::noop_visit_tt(tt, self) @@ -285,34 +264,6 @@ impl TTMacroExpander for F } } -pub trait IdentMacroExpander { - fn expand<'cx>(&self, - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - ident: ast::Ident, - token_tree: Vec) - -> Box; -} - -pub type IdentMacroExpanderFn = - for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, ast::Ident, Vec) - -> Box; - -impl IdentMacroExpander for F - where F : for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, ast::Ident, - Vec) -> Box -{ - fn expand<'cx>(&self, - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - ident: ast::Ident, - token_tree: Vec) - -> Box - { - (*self)(cx, sp, ident, token_tree) - } -} - // Use a macro because forwarding to a simple function has type system issues macro_rules! make_stmts_default { ($me:expr) => { @@ -567,9 +518,6 @@ impl MacResult for DummyResult { } } -pub type BuiltinDeriveFn = - for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)); - /// Represents different kinds of macro invocations that can be resolved. #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum MacroKind { @@ -601,131 +549,144 @@ impl MacroKind { } } -/// An enum representing the different kinds of syntax extensions. -pub enum SyntaxExtension { - /// A trivial "extension" that does nothing, only keeps the attribute and marks it as known. - NonMacroAttr { mark_used: bool }, - - /// A syntax extension that is attached to an item and creates new items - /// based upon it. - /// - /// `#[derive(...)]` is a `MultiItemDecorator`. - /// - /// Prefer ProcMacro or MultiModifier since they are more flexible. - MultiDecorator(Box), - - /// A syntax extension that is attached to an item and modifies it - /// in-place. Also allows decoration, i.e., creating new items. - MultiModifier(Box), - - /// A function-like procedural macro. TokenStream -> TokenStream. - ProcMacro { - expander: Box, - /// Whitelist of unstable features that are treated as stable inside this macro - allow_internal_unstable: Option>, - edition: Edition, +/// A syntax extension kind. +pub enum SyntaxExtensionKind { + /// A token-based function-like macro. + Bang( + /// An expander with signature TokenStream -> TokenStream. + Box, + ), + + /// An AST-based function-like macro. + LegacyBang( + /// An expander with signature TokenStream -> AST. + Box, + ), + + /// A token-based attribute macro. + Attr( + /// An expander with signature (TokenStream, TokenStream) -> TokenStream. + /// The first TokenSteam is the attribute itself, the second is the annotated item. + /// The produced TokenSteam replaces the input TokenSteam. + Box, + ), + + /// An AST-based attribute macro. + LegacyAttr( + /// An expander with signature (AST, AST) -> AST. + /// The first AST fragment is the attribute itself, the second is the annotated item. + /// The produced AST fragment replaces the input AST fragment. + Box, + ), + + /// A trivial attribute "macro" that does nothing, + /// only keeps the attribute and marks it as inert, + /// thus making it ineligible for further expansion. + NonMacroAttr { + /// Suppresses the `unused_attributes` lint for this attribute. + mark_used: bool, }, - /// An attribute-like procedural macro. TokenStream, TokenStream -> TokenStream. - /// The first TokenSteam is the attribute, the second is the annotated item. - /// Allows modification of the input items and adding new items, similar to - /// MultiModifier, but uses TokenStreams, rather than AST nodes. - AttrProcMacro(Box, Edition), - - /// A normal, function-like syntax extension. - /// - /// `bytes!` is a `NormalTT`. - NormalTT { - expander: Box, - def_info: Option<(ast::NodeId, Span)>, - /// Whether the contents of the macro can - /// directly use `#[unstable]` things. - /// - /// Only allows things that require a feature gate in the given whitelist - allow_internal_unstable: Option>, - /// Whether the contents of the macro can use `unsafe` - /// without triggering the `unsafe_code` lint. - allow_internal_unsafe: bool, - /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) - /// for a given macro. - local_inner_macros: bool, - /// The macro's feature name if it is unstable, and the stability feature - unstable_feature: Option<(Symbol, u32)>, - /// Edition of the crate in which the macro is defined - edition: Edition, - }, - - /// A function-like syntax extension that has an extra ident before - /// the block. - IdentTT { - expander: Box, - span: Option, - allow_internal_unstable: Option>, - }, - - /// An attribute-like procedural macro. TokenStream -> TokenStream. - /// The input is the annotated item. - /// Allows generating code to implement a Trait for a given struct - /// or enum item. - ProcMacroDerive(Box, - Vec /* inert attribute names */, Edition), - - /// An attribute-like procedural macro that derives a builtin trait. - BuiltinDerive(BuiltinDeriveFn), - - /// A declarative macro, e.g., `macro m() {}`. - DeclMacro { - expander: Box, - def_info: Option<(ast::NodeId, Span)>, - is_transparent: bool, - edition: Edition, + /// A token-based derive macro. + Derive( + /// An expander with signature TokenStream -> TokenStream (not yet). + /// The produced TokenSteam is appended to the input TokenSteam. + Box, + ), + + /// An AST-based derive macro. + LegacyDerive( + /// An expander with signature AST -> AST. + /// The produced AST fragment is appended to the input AST fragment. + Box, + ), +} + +/// A struct representing a macro definition in "lowered" form ready for expansion. +pub struct SyntaxExtension { + /// A syntax extension kind. + pub kind: SyntaxExtensionKind, + /// Some info about the macro's definition point. + pub def_info: Option<(ast::NodeId, Span)>, + /// Hygienic properties of spans produced by this macro by default. + pub default_transparency: Transparency, + /// Whitelist of unstable features that are treated as stable inside this macro. + pub allow_internal_unstable: Option>, + /// Suppresses the `unsafe_code` lint for code produced by this macro. + pub allow_internal_unsafe: bool, + /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro. + pub local_inner_macros: bool, + /// The macro's feature name and tracking issue number if it is unstable. + pub unstable_feature: Option<(Symbol, u32)>, + /// Names of helper attributes registered by this macro. + pub helper_attrs: Vec, + /// Edition of the crate in which this macro is defined. + pub edition: Edition, +} + +impl SyntaxExtensionKind { + /// When a syntax extension is constructed, + /// its transparency can often be inferred from its kind. + fn default_transparency(&self) -> Transparency { + match self { + SyntaxExtensionKind::Bang(..) | + SyntaxExtensionKind::Attr(..) | + SyntaxExtensionKind::Derive(..) | + SyntaxExtensionKind::NonMacroAttr { .. } => Transparency::Opaque, + SyntaxExtensionKind::LegacyBang(..) | + SyntaxExtensionKind::LegacyAttr(..) | + SyntaxExtensionKind::LegacyDerive(..) => Transparency::SemiTransparent, + } } } impl SyntaxExtension { /// Returns which kind of macro calls this syntax extension. - pub fn kind(&self) -> MacroKind { - match *self { - SyntaxExtension::DeclMacro { .. } | - SyntaxExtension::NormalTT { .. } | - SyntaxExtension::IdentTT { .. } | - SyntaxExtension::ProcMacro { .. } => - MacroKind::Bang, - SyntaxExtension::NonMacroAttr { .. } | - SyntaxExtension::MultiDecorator(..) | - SyntaxExtension::MultiModifier(..) | - SyntaxExtension::AttrProcMacro(..) => - MacroKind::Attr, - SyntaxExtension::ProcMacroDerive(..) | - SyntaxExtension::BuiltinDerive(..) => - MacroKind::Derive, + pub fn macro_kind(&self) -> MacroKind { + match self.kind { + SyntaxExtensionKind::Bang(..) | + SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang, + SyntaxExtensionKind::Attr(..) | + SyntaxExtensionKind::LegacyAttr(..) | + SyntaxExtensionKind::NonMacroAttr { .. } => MacroKind::Attr, + SyntaxExtensionKind::Derive(..) | + SyntaxExtensionKind::LegacyDerive(..) => MacroKind::Derive, } } - pub fn default_transparency(&self) -> Transparency { - match *self { - SyntaxExtension::ProcMacro { .. } | - SyntaxExtension::AttrProcMacro(..) | - SyntaxExtension::ProcMacroDerive(..) | - SyntaxExtension::DeclMacro { is_transparent: false, .. } => Transparency::Opaque, - SyntaxExtension::DeclMacro { is_transparent: true, .. } => Transparency::Transparent, - _ => Transparency::SemiTransparent, + /// Constructs a syntax extension with default properties. + pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> SyntaxExtension { + SyntaxExtension { + def_info: None, + default_transparency: kind.default_transparency(), + allow_internal_unstable: None, + allow_internal_unsafe: false, + local_inner_macros: false, + unstable_feature: None, + helper_attrs: Vec::new(), + edition, + kind, } } - pub fn edition(&self) -> Edition { - match *self { - SyntaxExtension::NormalTT { edition, .. } | - SyntaxExtension::DeclMacro { edition, .. } | - SyntaxExtension::ProcMacro { edition, .. } | - SyntaxExtension::AttrProcMacro(.., edition) | - SyntaxExtension::ProcMacroDerive(.., edition) => edition, - // Unstable legacy stuff - SyntaxExtension::NonMacroAttr { .. } | - SyntaxExtension::IdentTT { .. } | - SyntaxExtension::MultiDecorator(..) | - SyntaxExtension::MultiModifier(..) | - SyntaxExtension::BuiltinDerive(..) => hygiene::default_edition(), + fn expn_format(&self, symbol: Symbol) -> ExpnFormat { + match self.kind { + SyntaxExtensionKind::Bang(..) | + SyntaxExtensionKind::LegacyBang(..) => ExpnFormat::MacroBang(symbol), + _ => ExpnFormat::MacroAttribute(symbol), + } + } + + pub fn expn_info(&self, call_site: Span, format: &str) -> ExpnInfo { + ExpnInfo { + call_site, + format: self.expn_format(Symbol::intern(format)), + def_site: self.def_info.map(|(_, span)| span), + default_transparency: self.default_transparency, + allow_internal_unstable: self.allow_internal_unstable.clone(), + allow_internal_unsafe: self.allow_internal_unsafe, + local_inner_macros: self.local_inner_macros, + edition: self.edition, } } } @@ -734,6 +695,7 @@ pub type NamedSyntaxExtension = (Name, SyntaxExtension); pub trait Resolver { fn next_node_id(&mut self) -> ast::NodeId; + fn get_module_scope(&mut self, id: ast::NodeId) -> Mark; fn resolve_dollar_crates(&mut self, fragment: &AstFragment); @@ -764,30 +726,6 @@ impl Determinacy { } } -pub struct DummyResolver; - -impl Resolver for DummyResolver { - fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID } - fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() } - - fn resolve_dollar_crates(&mut self, _fragment: &AstFragment) {} - fn visit_ast_fragment_with_placeholders(&mut self, _invoc: Mark, _fragment: &AstFragment, - _derives: &[Mark]) {} - fn add_builtin(&mut self, _ident: ast::Ident, _ext: Lrc) {} - - fn resolve_imports(&mut self) {} - fn resolve_macro_invocation(&mut self, _invoc: &Invocation, _invoc_id: Mark, _force: bool) - -> Result>, Determinacy> { - Err(Determinacy::Determined) - } - fn resolve_macro_path(&mut self, _path: &ast::Path, _kind: MacroKind, _invoc_id: Mark, - _derives_in_scope: Vec, _force: bool) - -> Result, Determinacy> { - Err(Determinacy::Determined) - } - fn check_unused_macros(&self) {} -} - #[derive(Clone)] pub struct ModuleData { pub mod_path: Vec, @@ -848,7 +786,7 @@ impl<'a> ExtCtxt<'a> { } pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree]) -> parser::Parser<'a> { - parse::stream_to_parser(self.parse_sess, tts.iter().cloned().collect()) + parse::stream_to_parser(self.parse_sess, tts.iter().cloned().collect(), MACRO_ARGUMENTS) } pub fn source_map(&self) -> &'a SourceMap { self.parse_sess.source_map() } pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess } @@ -870,8 +808,8 @@ impl<'a> ExtCtxt<'a> { let mut ctxt = self.backtrace(); let mut last_macro = None; loop { - if ctxt.outer().expn_info().map_or(None, |info| { - if info.format.name() == "include" { + if ctxt.outer_expn_info().map_or(None, |info| { + if info.format.name() == sym::include { // Stop going up the backtrace once include! is encountered return None; } @@ -967,10 +905,10 @@ impl<'a> ExtCtxt<'a> { pub fn ident_of(&self, st: &str) -> ast::Ident { ast::Ident::from_str(st) } - pub fn std_path(&self, components: &[&str]) -> Vec { + pub fn std_path(&self, components: &[Symbol]) -> Vec { let def_site = DUMMY_SP.apply_mark(self.current_expansion.mark); - iter::once(Ident::new(keywords::DollarCrate.name(), def_site)) - .chain(components.iter().map(|s| self.ident_of(s))) + iter::once(Ident::new(kw::DollarCrate, def_site)) + .chain(components.iter().map(|&s| Ident::with_empty_ctxt(s))) .collect() } pub fn name_of(&self, st: &str) -> ast::Name { @@ -998,6 +936,7 @@ pub fn expr_to_spanned_string<'a>( Err(match expr.node { ast::ExprKind::Lit(ref l) => match l.node { ast::LitKind::Str(s, style) => return Ok(respan(expr.span, (s, style))), + ast::LitKind::Err(_) => None, _ => Some(cx.struct_span_err(l.span, err_msg)) }, ast::ExprKind::Err => None, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index e95f05894491b..baf1031de1e7c 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -3,14 +3,14 @@ use crate::attr; use crate::source_map::{dummy_spanned, respan, Spanned}; use crate::ext::base::ExtCtxt; use crate::ptr::P; -use crate::symbol::{Symbol, keywords}; +use crate::symbol::{kw, sym, Symbol}; use crate::ThinVec; use rustc_target::spec::abi::Abi; -use syntax_pos::{Pos, Span, DUMMY_SP}; +use syntax_pos::{Pos, Span}; pub trait AstBuilder { - // paths + // Paths fn path(&self, span: Span, strs: Vec ) -> ast::Path; fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path; fn path_global(&self, span: Span, strs: Vec ) -> ast::Path; @@ -18,7 +18,7 @@ pub trait AstBuilder { global: bool, idents: Vec, args: Vec, - bindings: Vec) + constraints: Vec) -> ast::Path; fn qpath(&self, self_type: P, @@ -29,7 +29,7 @@ pub trait AstBuilder { trait_path: ast::Path, ident: ast::Ident, args: Vec, - bindings: Vec) + constraints: Vec) -> (ast::QSelf, ast::Path); // types and consts @@ -49,7 +49,6 @@ pub trait AstBuilder { ty: P, mutbl: ast::Mutability) -> P; - fn ty_option(&self, ty: P) -> P; fn ty_infer(&self, sp: Span) -> P; fn typaram(&self, @@ -70,7 +69,7 @@ pub trait AstBuilder { bounds: ast::GenericBounds) -> ast::GenericParam; - // statements + // Statements fn stmt_expr(&self, expr: P) -> ast::Stmt; fn stmt_semi(&self, expr: P) -> ast::Stmt; fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident, ex: P) -> ast::Stmt; @@ -84,11 +83,11 @@ pub trait AstBuilder { fn stmt_let_type_only(&self, span: Span, ty: P) -> ast::Stmt; fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt; - // blocks + // Blocks fn block(&self, span: Span, stmts: Vec) -> P; fn block_expr(&self, expr: P) -> P; - // expressions + // Expressions fn expr(&self, span: Span, node: ast::ExprKind) -> P; fn expr_path(&self, path: ast::Path) -> P; fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P; @@ -195,12 +194,12 @@ pub trait AstBuilder { fn lambda_stmts_1(&self, span: Span, stmts: Vec, ident: ast::Ident) -> P; - // items + // Items fn item(&self, span: Span, name: Ident, attrs: Vec , node: ast::ItemKind) -> P; fn arg(&self, span: Span, name: Ident, ty: P) -> ast::Arg; - // FIXME unused self + // FIXME: unused `self` fn fn_decl(&self, inputs: Vec , output: ast::FunctionRetTy) -> P; fn item_fn_poly(&self, @@ -303,7 +302,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { global: bool, mut idents: Vec , args: Vec, - bindings: Vec ) + constraints: Vec ) -> ast::Path { assert!(!idents.is_empty()); let add_root = global && !idents[0].is_path_segment_keyword(); @@ -315,8 +314,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { segments.extend(idents.into_iter().map(|ident| { ast::PathSegment::from_ident(ident.with_span_pos(span)) })); - let args = if !args.is_empty() || !bindings.is_empty() { - ast::AngleBracketedArgs { args, bindings, span }.into() + let args = if !args.is_empty() || !constraints.is_empty() { + ast::AngleBracketedArgs { args, constraints, span }.into() } else { None }; @@ -347,11 +346,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { trait_path: ast::Path, ident: ast::Ident, args: Vec, - bindings: Vec) + constraints: Vec) -> (ast::QSelf, ast::Path) { let mut path = trait_path; - let args = if !args.is_empty() || !bindings.is_empty() { - ast::AngleBracketedArgs { args, bindings, span: ident.span }.into() + let args = if !args.is_empty() || !constraints.is_empty() { + ast::AngleBracketedArgs { args, constraints, span: ident.span }.into() } else { None }; @@ -425,15 +424,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ast::TyKind::Ptr(self.ty_mt(ty, mutbl))) } - fn ty_option(&self, ty: P) -> P { - self.ty_path( - self.path_all(DUMMY_SP, - true, - self.std_path(&["option", "Option"]), - vec![ast::GenericArg::Type(ty)], - Vec::new())) - } - fn ty_infer(&self, span: Span) -> P { self.ty(span, ast::TyKind::Infer) } @@ -562,7 +552,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } } - // Generate `let _: Type;`, usually used for type assertions. + // Generates `let _: Type;`, which is usually used for type assertions. fn stmt_let_type_only(&self, span: Span, ty: P) -> ast::Stmt { let local = P(ast::Local { pat: self.pat_wild(span), @@ -616,7 +606,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr(path.span, ast::ExprKind::Path(None, path)) } - /// Constructs a QPath expression. + /// Constructs a `QPath` expression. fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P { self.expr(span, ast::ExprKind::Path(Some(qself), path)) } @@ -625,7 +615,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr_path(self.path_ident(span, id)) } fn expr_self(&self, span: Span) -> P { - self.expr_ident(span, keywords::SelfLower.ident()) + self.expr_ident(span, Ident::with_empty_ctxt(kw::SelfLower)) } fn expr_binary(&self, sp: Span, op: ast::BinOpKind, @@ -694,8 +684,9 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr_struct(span, self.path_ident(span, id), fields) } - fn expr_lit(&self, sp: Span, lit: ast::LitKind) -> P { - self.expr(sp, ast::ExprKind::Lit(respan(sp, lit))) + fn expr_lit(&self, span: Span, lit_kind: ast::LitKind) -> P { + let lit = ast::Lit::from_lit_kind(lit_kind, span); + self.expr(span, ast::ExprKind::Lit(lit)) } fn expr_usize(&self, span: Span, i: usize) -> P { self.expr_lit(span, ast::LitKind::Int(i as u128, @@ -731,7 +722,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr(sp, ast::ExprKind::Array(exprs)) } fn expr_vec_ng(&self, sp: Span) -> P { - self.expr_call_global(sp, self.std_path(&["vec", "Vec", "new"]), + self.expr_call_global(sp, self.std_path(&[sym::vec, sym::Vec, sym::new]), Vec::new()) } fn expr_vec_slice(&self, sp: Span, exprs: Vec>) -> P { @@ -745,24 +736,21 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr(sp, ast::ExprKind::Cast(expr, ty)) } - fn expr_some(&self, sp: Span, expr: P) -> P { - let some = self.std_path(&["option", "Option", "Some"]); + let some = self.std_path(&[sym::option, sym::Option, sym::Some]); self.expr_call_global(sp, some, vec![expr]) } fn expr_none(&self, sp: Span) -> P { - let none = self.std_path(&["option", "Option", "None"]); + let none = self.std_path(&[sym::option, sym::Option, sym::None]); let none = self.path_global(sp, none); self.expr_path(none) } - fn expr_break(&self, sp: Span) -> P { self.expr(sp, ast::ExprKind::Break(None, None)) } - fn expr_tuple(&self, sp: Span, exprs: Vec>) -> P { self.expr(sp, ast::ExprKind::Tup(exprs)) } @@ -776,7 +764,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let expr_loc_ptr = self.expr_addr_of(span, expr_loc_tuple); self.expr_call_global( span, - self.std_path(&["rt", "begin_panic"]), + self.std_path(&[sym::rt, sym::begin_panic]), vec![ self.expr_str(span, msg), expr_loc_ptr]) @@ -787,47 +775,47 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn expr_ok(&self, sp: Span, expr: P) -> P { - let ok = self.std_path(&["result", "Result", "Ok"]); + let ok = self.std_path(&[sym::result, sym::Result, sym::Ok]); self.expr_call_global(sp, ok, vec![expr]) } fn expr_err(&self, sp: Span, expr: P) -> P { - let err = self.std_path(&["result", "Result", "Err"]); + let err = self.std_path(&[sym::result, sym::Result, sym::Err]); self.expr_call_global(sp, err, vec![expr]) } fn expr_try(&self, sp: Span, head: P) -> P { - let ok = self.std_path(&["result", "Result", "Ok"]); + let ok = self.std_path(&[sym::result, sym::Result, sym::Ok]); let ok_path = self.path_global(sp, ok); - let err = self.std_path(&["result", "Result", "Err"]); + let err = self.std_path(&[sym::result, sym::Result, sym::Err]); let err_path = self.path_global(sp, err); let binding_variable = self.ident_of("__try_var"); let binding_pat = self.pat_ident(sp, binding_variable); let binding_expr = self.expr_ident(sp, binding_variable); - // Ok(__try_var) pattern + // `Ok(__try_var)` pattern let ok_pat = self.pat_tuple_struct(sp, ok_path, vec![binding_pat.clone()]); - // Err(__try_var) (pattern and expression resp.) + // `Err(__try_var)` (pattern and expression respectively) let err_pat = self.pat_tuple_struct(sp, err_path.clone(), vec![binding_pat]); let err_inner_expr = self.expr_call(sp, self.expr_path(err_path), vec![binding_expr.clone()]); - // return Err(__try_var) + // `return Err(__try_var)` let err_expr = self.expr(sp, ast::ExprKind::Ret(Some(err_inner_expr))); - // Ok(__try_var) => __try_var + // `Ok(__try_var) => __try_var` let ok_arm = self.arm(sp, vec![ok_pat], binding_expr); - // Err(__try_var) => return Err(__try_var) + // `Err(__try_var) => return Err(__try_var)` let err_arm = self.arm(sp, vec![err_pat], err_expr); - // match head { Ok() => ..., Err() => ... } + // `match head { Ok() => ..., Err() => ... }` self.expr_match(sp, head, vec![ok_arm, err_arm]) } fn pat(&self, span: Span, pat: PatKind) -> P { - P(ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span: span }) + P(ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span }) } fn pat_wild(&self, span: Span) -> P { self.pat(span, PatKind::Wild) @@ -863,35 +851,36 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn pat_some(&self, span: Span, pat: P) -> P { - let some = self.std_path(&["option", "Option", "Some"]); + let some = self.std_path(&[sym::option, sym::Option, sym::Some]); let path = self.path_global(span, some); self.pat_tuple_struct(span, path, vec![pat]) } fn pat_none(&self, span: Span) -> P { - let some = self.std_path(&["option", "Option", "None"]); + let some = self.std_path(&[sym::option, sym::Option, sym::None]); let path = self.path_global(span, some); self.pat_path(span, path) } fn pat_ok(&self, span: Span, pat: P) -> P { - let some = self.std_path(&["result", "Result", "Ok"]); + let some = self.std_path(&[sym::result, sym::Result, sym::Ok]); let path = self.path_global(span, some); self.pat_tuple_struct(span, path, vec![pat]) } fn pat_err(&self, span: Span, pat: P) -> P { - let some = self.std_path(&["result", "Result", "Err"]); + let some = self.std_path(&[sym::result, sym::Result, sym::Err]); let path = self.path_global(span, some); self.pat_tuple_struct(span, path, vec![pat]) } - fn arm(&self, _span: Span, pats: Vec>, expr: P) -> ast::Arm { + fn arm(&self, span: Span, pats: Vec>, expr: P) -> ast::Arm { ast::Arm { attrs: vec![], pats, guard: None, body: expr, + span, } } @@ -974,13 +963,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn arg(&self, span: Span, ident: ast::Ident, ty: P) -> ast::Arg { let arg_pat = self.pat_ident(span, ident); ast::Arg { - ty, + attrs: ThinVec::default(), + id: ast::DUMMY_NODE_ID, pat: arg_pat, - id: ast::DUMMY_NODE_ID + ty, } } - // FIXME unused self + // FIXME: unused `self` fn fn_decl(&self, inputs: Vec, output: ast::FunctionRetTy) -> P { P(ast::FnDecl { inputs, @@ -1062,6 +1052,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { respan(span, ast::Variant_ { ident, + id: ast::DUMMY_NODE_ID, attrs: Vec::new(), data: vdata, disr_expr: None, @@ -1159,17 +1150,17 @@ impl<'a> AstBuilder for ExtCtxt<'a> { attr::mk_list_item(sp, Ident::with_empty_ctxt(name).with_span_pos(sp), mis) } - fn meta_name_value(&self, sp: Span, name: ast::Name, value: ast::LitKind) + fn meta_name_value(&self, span: Span, name: ast::Name, lit_kind: ast::LitKind) -> ast::MetaItem { - attr::mk_name_value_item(sp, Ident::with_empty_ctxt(name).with_span_pos(sp), - respan(sp, value)) + attr::mk_name_value_item(span, Ident::with_empty_ctxt(name).with_span_pos(span), + lit_kind, span) } fn item_use(&self, sp: Span, vis: ast::Visibility, vp: P) -> P { P(ast::Item { id: ast::DUMMY_NODE_ID, - ident: keywords::Invalid.ident(), + ident: Ident::invalid(), attrs: vec![], node: ast::ItemKind::Use(vp), vis, diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 6df369133d01d..3b4243ed24f7c 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -1,10 +1,11 @@ use crate::attr::HasAttrs; use crate::ast; -use crate::source_map::{hygiene, ExpnInfo, ExpnFormat}; +use crate::source_map::{ExpnInfo, ExpnFormat}; use crate::ext::base::ExtCtxt; use crate::ext::build::AstBuilder; use crate::parse::parser::PathStyle; -use crate::symbol::Symbol; +use crate::symbol::{Symbol, sym}; +use crate::errors::Applicability; use syntax_pos::Span; @@ -13,21 +14,22 @@ use rustc_data_structures::fx::FxHashSet; pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) -> Vec { let mut result = Vec::new(); attrs.retain(|attr| { - if attr.path != "derive" { + if attr.path != sym::derive { return true; } if !attr.is_meta_item_list() { - cx.span_err(attr.span, - "attribute must be of the form `#[derive(Trait1, Trait2, ...)]`"); + cx.struct_span_err(attr.span, "malformed `derive` attribute input") + .span_suggestion( + attr.span, + "missing traits to be derived", + "#[derive(Trait1, Trait2, ...)]".to_owned(), + Applicability::HasPlaceholders, + ).emit(); return false; } match attr.parse_list(cx.parse_sess, |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) { - Ok(ref traits) if traits.is_empty() => { - cx.span_warn(attr.span, "empty trait list in `derive`"); - false - } Ok(traits) => { result.extend(traits); true @@ -54,18 +56,10 @@ pub fn add_derived_markers(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P } pretty_name.push(')'); - cx.current_expansion.mark.set_expn_info(ExpnInfo { - call_site: span, - def_site: None, - format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)), - allow_internal_unstable: Some(vec![ - Symbol::intern("rustc_attrs"), - Symbol::intern("structural_match"), - ].into()), - allow_internal_unsafe: false, - local_inner_macros: false, - edition: hygiene::default_edition(), - }); + cx.current_expansion.mark.set_expn_info(ExpnInfo::with_unstable( + ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)), span, cx.parse_sess.edition, + &[sym::rustc_attrs, sym::structural_match], + )); let span = span.with_ctxt(cx.backtrace()); item.visit_attrs(|attrs| { @@ -74,7 +68,7 @@ pub fn add_derived_markers(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P attrs.push(cx.attribute(span, meta)); } if names.contains(&Symbol::intern("Copy")) { - let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker")); + let meta = cx.meta_word(span, sym::rustc_copy_clone_marker); attrs.push(cx.attribute(span, meta)); } }); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index b805213bb1a4c..5473f55aa3370 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1,20 +1,20 @@ use crate::ast::{self, Block, Ident, LitKind, NodeId, PatKind, Path}; use crate::ast::{MacStmtStyle, StmtKind, ItemKind}; use crate::attr::{self, HasAttrs}; -use crate::source_map::{ExpnInfo, MacroBang, MacroAttribute, dummy_spanned, respan}; +use crate::source_map::{dummy_spanned, respan}; use crate::config::StripUnconfigured; use crate::ext::base::*; use crate::ext::derive::{add_derived_markers, collect_derives}; -use crate::ext::hygiene::{self, Mark, SyntaxContext}; +use crate::ext::hygiene::{Mark, SyntaxContext}; use crate::ext::placeholders::{placeholder, PlaceholderExpander}; use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}; use crate::mut_visit::*; use crate::parse::{DirectoryOwnership, PResult, ParseSess}; -use crate::parse::token::{self, Token}; +use crate::parse::token; use crate::parse::parser::Parser; use crate::ptr::P; use crate::symbol::Symbol; -use crate::symbol::keywords; +use crate::symbol::{kw, sym}; use crate::tokenstream::{TokenStream, TokenTree}; use crate::visit::{self, Visitor}; use crate::util::map_in_place::MapInPlace; @@ -22,7 +22,6 @@ use crate::util::map_in_place::MapInPlace; use errors::{Applicability, FatalError}; use smallvec::{smallvec, SmallVec}; use syntax_pos::{Span, DUMMY_SP, FileName}; -use syntax_pos::hygiene::ExpnFormat; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; @@ -99,9 +98,9 @@ macro_rules! ast_fragments { } }); } - $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)*)* + $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)* $($(AstFragment::$Kind(ast) => - ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)*)* + ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)* } } @@ -109,10 +108,10 @@ macro_rules! ast_fragments { match *self { AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), AstFragment::OptExpr(None) => {} - $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)*)* + $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)* $($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] { visitor.$visit_ast_elt(ast_elt); - })*)* + })?)* } } } @@ -123,10 +122,10 @@ macro_rules! ast_fragments { } $($(fn $mut_visit_ast(&mut self, ast: &mut $AstTy) { visit_clobber(ast, |ast| self.expand_fragment(AstFragment::$Kind(ast)).$make_ast()); - })*)* + })?)* $($(fn $flat_map_ast_elt(&mut self, ast_elt: <$AstTy as IntoIterator>::Item) -> $AstTy { self.expand_fragment(AstFragment::$Kind(smallvec![ast_elt])).$make_ast() - })*)* + })?)* } impl<'a> MacResult for crate::ext::tt::macro_rules::ParserAnyMacro<'a> { @@ -189,23 +188,6 @@ impl AstFragmentKind { } } -fn macro_bang_format(path: &ast::Path) -> ExpnFormat { - // We don't want to format a path using pretty-printing, - // `format!("{}", path)`, because that tries to insert - // line-breaks and is slow. - let mut path_str = String::with_capacity(64); - for (i, segment) in path.segments.iter().enumerate() { - if i != 0 { - path_str.push_str("::"); - } - if segment.ident.name != keywords::PathRoot.name() { - path_str.push_str(&segment.ident.as_str()) - } - } - - MacroBang(Symbol::intern(&path_str)) -} - pub struct Invocation { pub kind: InvocationKind, fragment_kind: AstFragmentKind, @@ -242,14 +224,14 @@ impl Invocation { } } -pub struct MacroExpander<'a, 'b:'a> { +pub struct MacroExpander<'a, 'b> { pub cx: &'a mut ExtCtxt<'b>, monotonic: bool, // cf. `cx.monotonic_expander()` } impl<'a, 'b> MacroExpander<'a, 'b> { pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { - MacroExpander { cx: cx, monotonic: monotonic } + MacroExpander { cx, monotonic } } pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { @@ -271,7 +253,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { attrs: krate.attrs, span: krate.span, node: ast::ItemKind::Mod(krate.module), - ident: keywords::Invalid.ident(), + ident: Ident::invalid(), id: ast::DUMMY_NODE_ID, vis: respan(krate.span.shrink_to_lo(), ast::VisibilityKind::Public), tokens: None, @@ -356,7 +338,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.collect_invocations(fragment, &[]) } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { if !item.derive_allowed() { - let attr = attr::find_by_name(item.attrs(), "derive") + let attr = attr::find_by_name(item.attrs(), sym::derive) .expect("`derive` attribute should exist"); let span = attr.span; let mut err = self.cx.mut_span_err(span, @@ -376,7 +358,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } let mut item = self.fully_configure(item); - item.visit_attrs(|attrs| attrs.retain(|a| a.path != "derive")); + item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); let mut item_with_markers = item.clone(); add_derived_markers(&mut self.cx, item.span(), &traits, &mut item_with_markers); let derives = derives.entry(invoc.expansion_data.mark).or_default(); @@ -388,14 +370,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { derives.push(mark); let item = match self.cx.resolver.resolve_macro_path( path, MacroKind::Derive, Mark::root(), Vec::new(), false) { - Ok(ext) => match *ext { - BuiltinDerive(..) => item_with_markers.clone(), + Ok(ext) => match ext.kind { + SyntaxExtensionKind::LegacyDerive(..) => item_with_markers.clone(), _ => item.clone(), }, _ => item.clone(), }; invocations.push(Invocation { - kind: InvocationKind::Derive { path: path.clone(), item: item }, + kind: InvocationKind::Derive { path: path.clone(), item }, fragment_kind: invoc.fragment_kind, expansion_data: ExpansionData { mark, @@ -509,8 +491,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option { if invoc.fragment_kind == AstFragmentKind::ForeignItems && !self.cx.ecfg.macros_in_extern_enabled() { - if let SyntaxExtension::NonMacroAttr { .. } = *ext {} else { - emit_feature_err(&self.cx.parse_sess, "macros_in_extern", + if let SyntaxExtensionKind::NonMacroAttr { .. } = ext.kind {} else { + emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern, invoc.span(), GateIssue::Language, "macro invocations in `extern {}` blocks are experimental"); } @@ -548,60 +530,40 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => unreachable!(), }; - if let NonMacroAttr { mark_used: false } = *ext {} else { - // Macro attrs are always used when expanded, - // non-macro attrs are considered used when the field says so. - attr::mark_used(&attr); - } - invoc.expansion_data.mark.set_expn_info(ExpnInfo { - call_site: attr.span, - def_site: None, - format: MacroAttribute(Symbol::intern(&attr.path.to_string())), - allow_internal_unstable: None, - allow_internal_unsafe: false, - local_inner_macros: false, - edition: ext.edition(), - }); - - match *ext { - NonMacroAttr { .. } => { + match &ext.kind { + SyntaxExtensionKind::NonMacroAttr { mark_used } => { attr::mark_known(&attr); + if *mark_used { + attr::mark_used(&attr); + } item.visit_attrs(|attrs| attrs.push(attr)); Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item))) } - MultiModifier(ref mac) => { + SyntaxExtensionKind::LegacyAttr(expander) => { let meta = attr.parse_meta(self.cx.parse_sess) .map_err(|mut e| { e.emit(); }).ok()?; - let item = mac.expand(self.cx, attr.span, &meta, item); + let item = expander.expand(self.cx, attr.span, &meta, item); Some(invoc.fragment_kind.expect_from_annotatables(item)) } - MultiDecorator(ref mac) => { - let mut items = Vec::new(); - let meta = attr.parse_meta(self.cx.parse_sess) - .expect("derive meta should already have been parsed"); - mac.expand(self.cx, attr.span, &meta, &item, &mut |item| items.push(item)); - items.push(item); - Some(invoc.fragment_kind.expect_from_annotatables(items)) - } - AttrProcMacro(ref mac, ..) => { + SyntaxExtensionKind::Attr(expander) => { self.gate_proc_macro_attr_item(attr.span, &item); - let item_tok = TokenTree::Token(DUMMY_SP, Token::Interpolated(Lrc::new(match item { + let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item { Annotatable::Item(item) => token::NtItem(item), Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()), Annotatable::ImplItem(item) => token::NtImplItem(item.into_inner()), Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()), Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), Annotatable::Expr(expr) => token::NtExpr(expr), - }))).into(); + })), DUMMY_SP).into(); let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span); - let tok_result = mac.expand(self.cx, attr.span, input, item_tok); + let tok_result = expander.expand(self.cx, attr.span, input, item_tok); let res = self.parse_ast_fragment(tok_result, invoc.fragment_kind, &attr.path, attr.span); self.gate_proc_macro_expansion(attr.span, &res); res } - ProcMacroDerive(..) | BuiltinDerive(..) => { - self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path)); + SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => { + self.cx.span_err(attr.span, &format!("`{}` is a derive macro", attr.path)); self.cx.trace_macros_diag(); invoc.fragment_kind.dummy(attr.span) } @@ -636,7 +598,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Annotatable::Item(ref item) => { match item.node { ItemKind::Mod(_) if self.cx.ecfg.proc_macro_hygiene() => return, - ItemKind::Mod(_) => ("modules", "proc_macro_hygiene"), + ItemKind::Mod(_) => ("modules", sym::proc_macro_hygiene), _ => return, } } @@ -645,8 +607,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Annotatable::ForeignItem(_) => return, Annotatable::Stmt(_) | Annotatable::Expr(_) if self.cx.ecfg.proc_macro_hygiene() => return, - Annotatable::Stmt(_) => ("statements", "proc_macro_hygiene"), - Annotatable::Expr(_) => ("expressions", "proc_macro_hygiene"), + Annotatable::Stmt(_) => ("statements", sym::proc_macro_hygiene), + Annotatable::Expr(_) => ("expressions", sym::proc_macro_hygiene), }; emit_feature_err( self.cx.parse_sess, @@ -681,7 +643,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { if let ast::ItemKind::MacroDef(_) = i.node { emit_feature_err( self.parse_sess, - "proc_macro_hygiene", + sym::proc_macro_hygiene, self.span, GateIssue::Language, "procedural macros cannot expand to macro definitions", @@ -701,134 +663,73 @@ impl<'a, 'b> MacroExpander<'a, 'b> { invoc: Invocation, ext: &SyntaxExtension) -> Option { - let (mark, kind) = (invoc.expansion_data.mark, invoc.fragment_kind); + let kind = invoc.fragment_kind; let (mac, ident, span) = match invoc.kind { InvocationKind::Bang { mac, ident, span } => (mac, ident, span), _ => unreachable!(), }; let path = &mac.node.path; - let ident = ident.unwrap_or_else(|| keywords::Invalid.ident()); - let validate_and_set_expn_info = |this: &mut Self, // arg instead of capture - def_site_span: Option, - allow_internal_unstable, - allow_internal_unsafe, - local_inner_macros, - // can't infer this type - unstable_feature: Option<(Symbol, u32)>, - edition| { - + let ident = ident.unwrap_or_else(|| Ident::invalid()); + let validate = |this: &mut Self| { // feature-gate the macro invocation - if let Some((feature, issue)) = unstable_feature { + if let Some((feature, issue)) = ext.unstable_feature { let crate_span = this.cx.current_expansion.crate_span.unwrap(); // don't stability-check macros in the same crate // (the only time this is null is for syntax extensions registered as macros) - if def_site_span.map_or(false, |def_span| !crate_span.contains(def_span)) - && !span.allows_unstable(&feature.as_str()) + if ext.def_info.map_or(false, |(_, def_span)| !crate_span.contains(def_span)) + && !span.allows_unstable(feature) && this.cx.ecfg.features.map_or(true, |feats| { // macro features will count as lib features !feats.declared_lib_features.iter().any(|&(feat, _)| feat == feature) }) { let explain = format!("macro {}! is unstable", path); - emit_feature_err(this.cx.parse_sess, &*feature.as_str(), span, + emit_feature_err(this.cx.parse_sess, feature, span, GateIssue::Library(Some(issue)), &explain); this.cx.trace_macros_diag(); } } - if ident.name != keywords::Invalid.name() { + if ident.name != kw::Invalid { let msg = format!("macro {}! expects no ident argument, given '{}'", path, ident); this.cx.span_err(path.span, &msg); this.cx.trace_macros_diag(); return Err(kind.dummy(span)); } - mark.set_expn_info(ExpnInfo { - call_site: span, - def_site: def_site_span, - format: macro_bang_format(path), - allow_internal_unstable, - allow_internal_unsafe, - local_inner_macros, - edition, - }); Ok(()) }; - let opt_expanded = match *ext { - DeclMacro { ref expander, def_info, edition, .. } => { - if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s), - None, false, false, None, - edition) { - dummy_span - } else { - kind.make_from(expander.expand(self.cx, span, mac.node.stream(), None)) - } - } - - NormalTT { - ref expander, - def_info, - ref allow_internal_unstable, - allow_internal_unsafe, - local_inner_macros, - unstable_feature, - edition, - } => { - if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s), - allow_internal_unstable.clone(), - allow_internal_unsafe, - local_inner_macros, - unstable_feature, - edition) { + let opt_expanded = match &ext.kind { + SyntaxExtensionKind::LegacyBang(expander) => { + if let Err(dummy_span) = validate(self) { dummy_span } else { kind.make_from(expander.expand( self.cx, span, mac.node.stream(), - def_info.map(|(_, s)| s), + ext.def_info.map(|(_, s)| s), )) } } - IdentTT { ref expander, span: tt_span, ref allow_internal_unstable } => { - if ident.name == keywords::Invalid.name() { - self.cx.span_err(path.span, - &format!("macro {}! expects an ident argument", path)); - self.cx.trace_macros_diag(); - kind.dummy(span) - } else { - invoc.expansion_data.mark.set_expn_info(ExpnInfo { - call_site: span, - def_site: tt_span, - format: macro_bang_format(path), - allow_internal_unstable: allow_internal_unstable.clone(), - allow_internal_unsafe: false, - local_inner_macros: false, - edition: hygiene::default_edition(), - }); - - let input: Vec<_> = mac.node.stream().into_trees().collect(); - kind.make_from(expander.expand(self.cx, span, ident, input)) - } - } - - MultiDecorator(..) | MultiModifier(..) | - AttrProcMacro(..) | SyntaxExtension::NonMacroAttr { .. } => { + SyntaxExtensionKind::Attr(..) | + SyntaxExtensionKind::LegacyAttr(..) | + SyntaxExtensionKind::NonMacroAttr { .. } => { self.cx.span_err(path.span, &format!("`{}` can only be used in attributes", path)); self.cx.trace_macros_diag(); kind.dummy(span) } - ProcMacroDerive(..) | BuiltinDerive(..) => { - self.cx.span_err(path.span, &format!("`{}` is a derive mode", path)); + SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => { + self.cx.span_err(path.span, &format!("`{}` is a derive macro", path)); self.cx.trace_macros_diag(); kind.dummy(span) } - SyntaxExtension::ProcMacro { ref expander, ref allow_internal_unstable, edition } => { - if ident.name != keywords::Invalid.name() { + SyntaxExtensionKind::Bang(expander) => { + if ident.name != kw::Invalid { let msg = format!("macro {}! expects no ident argument, given '{}'", path, ident); self.cx.span_err(path.span, &msg); @@ -836,19 +737,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { kind.dummy(span) } else { self.gate_proc_macro_expansion_kind(span, kind); - invoc.expansion_data.mark.set_expn_info(ExpnInfo { - call_site: span, - // FIXME procedural macros do not have proper span info - // yet, when they do, we should use it here. - def_site: None, - format: macro_bang_format(path), - // FIXME probably want to follow macro_rules macros here. - allow_internal_unstable: allow_internal_unstable.clone(), - allow_internal_unsafe: false, - local_inner_macros: false, - edition, - }); - let tok_result = expander.expand(self.cx, span, mac.node.stream()); let result = self.parse_ast_fragment(tok_result, kind, path, span); self.gate_proc_macro_expansion(span, &result); @@ -885,7 +773,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } emit_feature_err( self.cx.parse_sess, - "proc_macro_hygiene", + sym::proc_macro_hygiene, span, GateIssue::Language, &format!("procedural macros cannot be expanded to {}", kind), @@ -905,55 +793,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return None; } - let pretty_name = Symbol::intern(&format!("derive({})", path)); - let span = path.span; - let attr = ast::Attribute { - path, span, - tokens: TokenStream::empty(), - // irrelevant: - id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false, - }; - - let mut expn_info = ExpnInfo { - call_site: span, - def_site: None, - format: MacroAttribute(pretty_name), - allow_internal_unstable: None, - allow_internal_unsafe: false, - local_inner_macros: false, - edition: ext.edition(), - }; - - match *ext { - ProcMacroDerive(ref ext, ..) => { - invoc.expansion_data.mark.set_expn_info(expn_info); - let span = span.with_ctxt(self.cx.backtrace()); - let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this - ident: Path::from_ident(keywords::Invalid.ident()), - span: DUMMY_SP, - node: ast::MetaItemKind::Word, - }; - let items = ext.expand(self.cx, span, &dummy, item); - Some(invoc.fragment_kind.expect_from_annotatables(items)) - } - BuiltinDerive(func) => { - expn_info.allow_internal_unstable = Some(vec![ - Symbol::intern("rustc_attrs"), - Symbol::intern("derive_clone_copy"), - Symbol::intern("derive_eq"), - Symbol::intern("libstd_sys_internals"), // RustcDeserialize and RustcSerialize - ].into()); - invoc.expansion_data.mark.set_expn_info(expn_info); - let span = span.with_ctxt(self.cx.backtrace()); - let mut items = Vec::new(); - func(self.cx, span, &attr.meta()?, &item, &mut |a| items.push(a)); + match &ext.kind { + SyntaxExtensionKind::Derive(expander) | + SyntaxExtensionKind::LegacyDerive(expander) => { + let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span: path.span, path }; + let span = meta.span.with_ctxt(self.cx.backtrace()); + let items = expander.expand(self.cx, span, &meta, item); Some(invoc.fragment_kind.expect_from_annotatables(items)) } _ => { - let msg = &format!("macro `{}` may not be used for derive attributes", attr.path); - self.cx.span_err(span, msg); + let msg = &format!("macro `{}` may not be used for derive attributes", path); + self.cx.span_err(path.span, msg); self.cx.trace_macros_diag(); - invoc.fragment_kind.dummy(span) + invoc.fragment_kind.dummy(path.span) } } } @@ -1041,7 +893,7 @@ impl<'a> Parser<'a> { let msg = format!("macro expansion ignores token `{}` and any following", self.this_token_to_string()); // Avoid emitting backtrace info twice. - let def_site_span = self.span.with_ctxt(SyntaxContext::empty()); + let def_site_span = self.token.span.with_ctxt(SyntaxContext::empty()); let mut err = self.diagnostic().struct_span_err(def_site_span, &msg); err.span_label(span, "caused by the macro expansion here"); let msg = format!( @@ -1069,7 +921,7 @@ impl<'a> Parser<'a> { } } -struct InvocationCollector<'a, 'b: 'a> { +struct InvocationCollector<'a, 'b> { cx: &'a mut ExtCtxt<'b>, cfg: StripUnconfigured<'a>, invocations: Vec, @@ -1092,7 +944,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment { - self.collect(kind, InvocationKind::Bang { mac: mac, ident: None, span: span }) + self.collect(kind, InvocationKind::Bang { mac, ident: None, span }) } fn collect_attr(&mut self, @@ -1109,7 +961,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { -> Option { let attr = attrs.iter() .position(|a| { - if a.path == "derive" { + if a.path == sym::derive { *after_derive = true; } !attr::is_known(a) && !is_builtin_attr(a) @@ -1117,8 +969,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { .map(|i| attrs.remove(i)); if let Some(attr) = &attr { if !self.cx.ecfg.enable_custom_inner_attributes() && - attr.style == ast::AttrStyle::Inner && attr.path != "test" { - emit_feature_err(&self.cx.parse_sess, "custom_inner_attributes", + attr.style == ast::AttrStyle::Inner && attr.path != sym::test { + emit_feature_err(&self.cx.parse_sess, sym::custom_inner_attributes, attr.span, GateIssue::Language, "non-builtin inner attributes are unstable"); } @@ -1167,7 +1019,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.check_attribute_inner(attr, features); // macros are expanded before any lint passes so this warning has to be hardcoded - if attr.path == "derive" { + if attr.path == sym::derive { self.cx.struct_span_warn(attr.span, "`#[derive]` does nothing on macro invocations") .note("this may become a hard error in a future release") .emit(); @@ -1338,7 +1190,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { }) } ast::ItemKind::Mod(ast::Mod { inner, .. }) => { - if item.ident == keywords::Invalid.ident() { + if item.ident == Ident::invalid() { return noop_flat_map_item(item, self); } @@ -1352,7 +1204,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let inline_module = item.span.contains(inner) || inner.is_dummy(); if inline_module { - if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") { + if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, sym::path) { self.cx.current_expansion.directory_ownership = DirectoryOwnership::Owned { relative: None }; module.directory.push(&*path.as_str()); @@ -1477,27 +1329,27 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } } - fn visit_generic_param(&mut self, param: &mut ast::GenericParam) { - self.cfg.disallow_cfg_on_generic_param(¶m); - noop_visit_generic_param(param, self) + fn visit_generic_params(&mut self, params: &mut Vec) { + self.cfg.configure_generic_params(params); + noop_visit_generic_params(params, self); } fn visit_attribute(&mut self, at: &mut ast::Attribute) { // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename", // contents="file contents")]` attributes - if !at.check_name("doc") { + if !at.check_name(sym::doc) { return noop_visit_attribute(at, self); } if let Some(list) = at.meta_item_list() { - if !list.iter().any(|it| it.check_name("include")) { + if !list.iter().any(|it| it.check_name(sym::include)) { return noop_visit_attribute(at, self); } let mut items = vec![]; for mut it in list { - if !it.check_name("include") { + if !it.check_name(sym::include) { items.push({ noop_visit_meta_list_item(&mut it, self); it }); continue; } @@ -1520,23 +1372,23 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.cx.source_map().new_source_file(filename.into(), src); let include_info = vec![ - dummy_spanned(ast::NestedMetaItemKind::MetaItem( + ast::NestedMetaItem::MetaItem( attr::mk_name_value_item_str( - Ident::from_str("file"), + Ident::with_empty_ctxt(sym::file), dummy_spanned(file), ), - )), - dummy_spanned(ast::NestedMetaItemKind::MetaItem( + ), + ast::NestedMetaItem::MetaItem( attr::mk_name_value_item_str( - Ident::from_str("contents"), + Ident::with_empty_ctxt(sym::contents), dummy_spanned(src_interned), ), - )), + ), ]; - let include_ident = Ident::from_str("include"); + let include_ident = Ident::with_empty_ctxt(sym::include); let item = attr::mk_list_item(DUMMY_SP, include_ident, include_info); - items.push(dummy_spanned(ast::NestedMetaItemKind::MetaItem(item))); + items.push(ast::NestedMetaItem::MetaItem(item)); } Err(e) => { let lit = it @@ -1569,7 +1421,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } } else { let mut err = self.cx.struct_span_err( - it.span, + it.span(), &format!("expected path to external documentation"), ); @@ -1590,7 +1442,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { }; err.span_suggestion( - it.span, + it.span(), "provide a file path with `=`", format!("include = \"{}\"", path), applicability, @@ -1600,7 +1452,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } } - let meta = attr::mk_list_item(DUMMY_SP, Ident::from_str("doc"), items); + let meta = attr::mk_list_item(DUMMY_SP, Ident::with_empty_ctxt(sym::doc), items); match at.style { ast::AttrStyle::Inner => *at = attr::mk_spanned_attr_inner(at.span, at.id, meta), ast::AttrStyle::Outer => *at = attr::mk_spanned_attr_outer(at.span, at.id, meta), @@ -1616,6 +1468,11 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { *id = self.cx.resolver.next_node_id() } } + + fn visit_fn_decl(&mut self, mut fn_decl: &mut P) { + self.cfg.configure_fn_decl(&mut fn_decl); + noop_visit_fn_decl(fn_decl, self); + } } pub struct ExpansionConfig<'feat> { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 3e60dd81a3bc8..b2b8bfb09b45e 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -6,7 +6,6 @@ use crate::ext::hygiene::Mark; use crate::tokenstream::TokenStream; use crate::mut_visit::*; use crate::ptr::P; -use crate::symbol::keywords; use crate::ThinVec; use smallvec::{smallvec, SmallVec}; @@ -22,7 +21,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment { }) } - let ident = keywords::Invalid.ident(); + let ident = ast::Ident::invalid(); let attrs = Vec::new(); let generics = ast::Generics::default(); let vis = dummy_spanned(ast::VisibilityKind::Inherited); @@ -70,7 +69,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment { } } -pub struct PlaceholderExpander<'a, 'b: 'a> { +pub struct PlaceholderExpander<'a, 'b> { expanded_fragments: FxHashMap, cx: &'a mut ExtCtxt<'b>, monotonic: bool, diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 549de1628eb55..4e2aab46542d2 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -4,7 +4,7 @@ use crate::ext::build::AstBuilder; use crate::parse::{self, token, DirectoryOwnership}; use crate::print::pprust; use crate::ptr::P; -use crate::symbol::Symbol; +use crate::symbol::{Symbol, sym}; use crate::tokenstream; use smallvec::SmallVec; @@ -44,7 +44,7 @@ pub fn expand_column(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTr /* __rust_unstable_column!(): expands to the current column number */ pub fn expand_column_gated(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree]) -> Box { - if sp.allows_unstable("__rust_unstable_column") { + if sp.allows_unstable(sym::__rust_unstable_column) { expand_column(cx, sp, tts) } else { cx.span_fatal(sp, "the __rust_unstable_column macro is unstable"); @@ -105,7 +105,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstrea while self.p.token != token::Eof { match panictry!(self.p.parse_item()) { Some(item) => ret.push(item), - None => self.p.diagnostic().span_fatal(self.p.span, + None => self.p.diagnostic().span_fatal(self.p.token.span, &format!("expected item, found `{}`", self.p.this_token_to_string())) .raise() diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index fe1cffb092b1c..92ce3779a3c81 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -74,13 +74,13 @@ pub use NamedMatch::*; pub use ParseResult::*; use TokenTreeOrTokenTreeSlice::*; -use crate::ast::Ident; +use crate::ast::{Ident, Name}; use crate::ext::tt::quoted::{self, TokenTree}; use crate::parse::{Directory, ParseSess}; use crate::parse::parser::{Parser, PathStyle}; use crate::parse::token::{self, DocComment, Nonterminal, Token}; use crate::print::pprust; -use crate::symbol::keywords; +use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{DelimSpan, TokenStream}; use errors::FatalError; @@ -156,7 +156,7 @@ type NamedMatchVec = SmallVec<[NamedMatch; 4]>; /// all the elements in that `SmallVec` strictly outlive the root stack slot /// lifetime. By separating `'tt` from `'root`, we can show that. #[derive(Clone)] -struct MatcherPos<'root, 'tt: 'root> { +struct MatcherPos<'root, 'tt> { /// The token or sequence of tokens that make up the matcher top_elts: TokenTreeOrTokenTreeSlice<'tt>, @@ -233,7 +233,7 @@ impl<'root, 'tt> MatcherPos<'root, 'tt> { // Therefore, the initial MatcherPos is always allocated on the stack, // subsequent ones (of which there aren't that many) are allocated on the heap, // and this type is used to encapsulate both cases. -enum MatcherPosHandle<'root, 'tt: 'root> { +enum MatcherPosHandle<'root, 'tt> { Ref(&'root mut MatcherPos<'root, 'tt>), Box(Box>), } @@ -273,7 +273,7 @@ pub enum ParseResult { Success(T), /// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected /// end of macro invocation. Otherwise, it indicates that no rules expected the given token. - Failure(syntax_pos::Span, Token, &'static str), + Failure(Token, &'static str), /// Fatal error (malformed macro?). Abort compilation. Error(syntax_pos::Span, String), } @@ -382,7 +382,7 @@ fn nameize>( TokenTree::Delimited(_, ref delim) => for next_m in &delim.tts { n_rec(sess, next_m, res.by_ref(), ret_val)?; }, - TokenTree::MetaVarDecl(span, _, id) if id.name == keywords::Invalid.name() => { + TokenTree::MetaVarDecl(span, _, id) if id.name == kw::Invalid => { if sess.missing_fragment_specifiers.borrow_mut().remove(&span) { return Err((span, "missing fragment specifier".to_string())); } @@ -417,24 +417,24 @@ fn nameize>( /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For /// other tokens, this is "unexpected token...". -pub fn parse_failure_msg(tok: Token) -> String { - match tok { +pub fn parse_failure_msg(tok: &Token) -> String { + match tok.kind { token::Eof => "unexpected end of macro invocation".to_string(), _ => format!( "no rules expected the token `{}`", - pprust::token_to_string(&tok) + pprust::token_to_string(tok) ), } } /// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison) fn token_name_eq(t1: &Token, t2: &Token) -> bool { - if let (Some((id1, is_raw1)), Some((id2, is_raw2))) = (t1.ident(), t2.ident()) { - id1.name == id2.name && is_raw1 == is_raw2 - } else if let (Some(id1), Some(id2)) = (t1.lifetime(), t2.lifetime()) { - id1.name == id2.name + if let (Some((ident1, is_raw1)), Some((ident2, is_raw2))) = (t1.ident(), t2.ident()) { + ident1.name == ident2.name && is_raw1 == is_raw2 + } else if let (Some(ident1), Some(ident2)) = (t1.lifetime(), t2.lifetime()) { + ident1.name == ident2.name } else { - *t1 == *t2 + t1.kind == t2.kind } } @@ -467,7 +467,6 @@ fn inner_parse_loop<'root, 'tt>( eof_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, bb_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, token: &Token, - span: syntax_pos::Span, ) -> ParseResult<()> { // Pop items from `cur_items` until it is empty. while let Some(mut item) = cur_items.pop() { @@ -510,7 +509,7 @@ fn inner_parse_loop<'root, 'tt>( // Add matches from this repetition to the `matches` of `up` for idx in item.match_lo..item.match_hi { let sub = item.matches[idx].clone(); - let span = DelimSpan::from_pair(item.sp_open, span); + let span = DelimSpan::from_pair(item.sp_open, token.span); new_pos.push_match(idx, MatchedSeq(sub, span)); } @@ -554,7 +553,10 @@ fn inner_parse_loop<'root, 'tt>( match item.top_elts.get_tt(idx) { // Need to descend into a sequence TokenTree::Sequence(sp, seq) => { - // Examine the case where there are 0 matches of this sequence + // Examine the case where there are 0 matches of this sequence. We are + // implicitly disallowing OneOrMore from having 0 matches here. Thus, that will + // result in a "no rules expected token" error by virtue of this matcher not + // working. if seq.op == quoted::KleeneOp::ZeroOrMore || seq.op == quoted::KleeneOp::ZeroOrOne { @@ -584,7 +586,7 @@ fn inner_parse_loop<'root, 'tt>( } // We need to match a metavar (but the identifier is invalid)... this is an error - TokenTree::MetaVarDecl(span, _, id) if id.name == keywords::Invalid.name() => { + TokenTree::MetaVarDecl(span, _, id) if id.name == kw::Invalid => { if sess.missing_fragment_specifiers.borrow_mut().remove(&span) { return Error(span, "missing fragment specifier".to_string()); } @@ -595,7 +597,7 @@ fn inner_parse_loop<'root, 'tt>( TokenTree::MetaVarDecl(_, _, id) => { // Built-in nonterminals never start with these tokens, // so we can eliminate them from consideration. - if may_begin_with(&*id.as_str(), token) { + if may_begin_with(token, id.name) { bb_items.push(item); } } @@ -606,7 +608,8 @@ fn inner_parse_loop<'root, 'tt>( // // At the beginning of the loop, if we reach the end of the delimited submatcher, // we pop the stack to backtrack out of the descent. - seq @ TokenTree::Delimited(..) | seq @ TokenTree::Token(_, DocComment(..)) => { + seq @ TokenTree::Delimited(..) | + seq @ TokenTree::Token(Token { kind: DocComment(..), .. }) => { let lower_elts = mem::replace(&mut item.top_elts, Tt(seq)); let idx = item.idx; item.stack.push(MatcherTtFrame { @@ -618,7 +621,7 @@ fn inner_parse_loop<'root, 'tt>( } // We just matched a normal token. We can just advance the parser. - TokenTree::Token(_, ref t) if token_name_eq(t, token) => { + TokenTree::Token(t) if token_name_eq(&t, token) => { item.idx += 1; next_items.push(item); } @@ -655,7 +658,14 @@ pub fn parse( recurse_into_modules: bool, ) -> NamedParseResult { // Create a parser that can be used for the "black box" parts. - let mut parser = Parser::new(sess, tts, directory, recurse_into_modules, true); + let mut parser = Parser::new( + sess, + tts, + directory, + recurse_into_modules, + true, + crate::MACRO_ARGUMENTS, + ); // A queue of possible matcher positions. We initialize it with the matcher position in which // the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then @@ -665,7 +675,7 @@ pub fn parse( // // This MatcherPos instance is allocated on the stack. All others -- and // there are frequently *no* others! -- are allocated on the heap. - let mut initial = initial_matcher_pos(ms, parser.span); + let mut initial = initial_matcher_pos(ms, parser.token.span); let mut cur_items = smallvec![MatcherPosHandle::Ref(&mut initial)]; let mut next_items = Vec::new(); @@ -687,10 +697,9 @@ pub fn parse( &mut eof_items, &mut bb_items, &parser.token, - parser.span, ) { Success(_) => {} - Failure(sp, tok, t) => return Failure(sp, tok, t), + Failure(token, msg) => return Failure(token, msg), Error(sp, msg) => return Error(sp, msg), } @@ -703,7 +712,7 @@ pub fn parse( // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise, // either the parse is ambiguous (which should never happen) or there is a syntax error. - if token_name_eq(&parser.token, &token::Eof) { + if parser.token == token::Eof { if eof_items.len() == 1 { let matches = eof_items[0] .matches @@ -712,17 +721,16 @@ pub fn parse( return nameize(sess, ms, matches); } else if eof_items.len() > 1 { return Error( - parser.span, + parser.token.span, "ambiguity: multiple successful parses".to_string(), ); } else { return Failure( - if parser.span.is_dummy() { - parser.span + Token::new(token::Eof, if parser.token.span.is_dummy() { + parser.token.span } else { - sess.source_map().next_point(parser.span) - }, - token::Eof, + sess.source_map().next_point(parser.token.span) + }), "missing tokens in macro arguments", ); } @@ -745,7 +753,7 @@ pub fn parse( .join(" or "); return Error( - parser.span, + parser.token.span, format!( "local ambiguity: multiple parsing options: {}", match next_items.len() { @@ -760,8 +768,7 @@ pub fn parse( // then there is a syntax error. else if bb_items.is_empty() && next_items.is_empty() { return Failure( - parser.span, - parser.token, + parser.token.take(), "no rules expected this token in macro call", ); } @@ -781,7 +788,7 @@ pub fn parse( let match_cur = item.match_cur; item.push_match( match_cur, - MatchedNonterminal(Lrc::new(parse_nt(&mut parser, span, &ident.as_str()))), + MatchedNonterminal(Lrc::new(parse_nt(&mut parser, span, ident.name))), ); item.idx += 1; item.match_cur += 1; @@ -797,10 +804,9 @@ pub fn parse( /// The token is an identifier, but not `_`. /// We prohibit passing `_` to macros expecting `ident` for now. -fn get_macro_ident(token: &Token) -> Option<(Ident, bool)> { - match *token { - token::Ident(ident, is_raw) if ident.name != keywords::Underscore.name() => - Some((ident, is_raw)), +fn get_macro_name(token: &Token) -> Option<(Name, bool)> { + match token.kind { + token::Ident(name, is_raw) if name != kw::Underscore => Some((name, is_raw)), _ => None, } } @@ -809,7 +815,7 @@ fn get_macro_ident(token: &Token) -> Option<(Ident, bool)> { /// /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that /// token. Be conservative (return true) if not sure. -fn may_begin_with(name: &str, token: &Token) -> bool { +fn may_begin_with(token: &Token, name: Name) -> bool { /// Checks whether the non-terminal may contain a single (non-keyword) identifier. fn may_be_ident(nt: &token::Nonterminal) -> bool { match *nt { @@ -819,18 +825,20 @@ fn may_begin_with(name: &str, token: &Token) -> bool { } match name { - "expr" => token.can_begin_expr(), - "ty" => token.can_begin_type(), - "ident" => get_macro_ident(token).is_some(), - "literal" => token.can_begin_literal_or_bool(), - "vis" => match *token { + sym::expr => token.can_begin_expr() + // This exception is here for backwards compatibility. + && !token.is_keyword(kw::Let), + sym::ty => token.can_begin_type(), + sym::ident => get_macro_name(token).is_some(), + sym::literal => token.can_begin_literal_or_bool(), + sym::vis => match token.kind { // The follow-set of :vis + "priv" keyword + interpolated - Token::Comma | Token::Ident(..) | Token::Interpolated(_) => true, + token::Comma | token::Ident(..) | token::Interpolated(_) => true, _ => token.can_begin_type(), }, - "block" => match *token { - Token::OpenDelim(token::Brace) => true, - Token::Interpolated(ref nt) => match **nt { + sym::block => match token.kind { + token::OpenDelim(token::Brace) => true, + token::Interpolated(ref nt) => match **nt { token::NtItem(_) | token::NtPat(_) | token::NtTy(_) @@ -842,39 +850,39 @@ fn may_begin_with(name: &str, token: &Token) -> bool { }, _ => false, }, - "path" | "meta" => match *token { - Token::ModSep | Token::Ident(..) => true, - Token::Interpolated(ref nt) => match **nt { + sym::path | sym::meta => match token.kind { + token::ModSep | token::Ident(..) => true, + token::Interpolated(ref nt) => match **nt { token::NtPath(_) | token::NtMeta(_) => true, _ => may_be_ident(&nt), }, _ => false, }, - "pat" => match *token { - Token::Ident(..) | // box, ref, mut, and other identifiers (can stricten) - Token::OpenDelim(token::Paren) | // tuple pattern - Token::OpenDelim(token::Bracket) | // slice pattern - Token::BinOp(token::And) | // reference - Token::BinOp(token::Minus) | // negative literal - Token::AndAnd | // double reference - Token::Literal(..) | // literal - Token::DotDot | // range pattern (future compat) - Token::DotDotDot | // range pattern (future compat) - Token::ModSep | // path - Token::Lt | // path (UFCS constant) - Token::BinOp(token::Shl) => true, // path (double UFCS) - Token::Interpolated(ref nt) => may_be_ident(nt), + sym::pat => match token.kind { + token::Ident(..) | // box, ref, mut, and other identifiers (can stricten) + token::OpenDelim(token::Paren) | // tuple pattern + token::OpenDelim(token::Bracket) | // slice pattern + token::BinOp(token::And) | // reference + token::BinOp(token::Minus) | // negative literal + token::AndAnd | // double reference + token::Literal(..) | // literal + token::DotDot | // range pattern (future compat) + token::DotDotDot | // range pattern (future compat) + token::ModSep | // path + token::Lt | // path (UFCS constant) + token::BinOp(token::Shl) => true, // path (double UFCS) + token::Interpolated(ref nt) => may_be_ident(nt), _ => false, }, - "lifetime" => match *token { - Token::Lifetime(_) => true, - Token::Interpolated(ref nt) => match **nt { + sym::lifetime => match token.kind { + token::Lifetime(_) => true, + token::Interpolated(ref nt) => match **nt { token::NtLifetime(_) | token::NtTT(_) => true, _ => false, }, _ => false, }, - _ => match *token { + _ => match token.kind { token::CloseDelim(_) => false, _ => true, }, @@ -893,46 +901,46 @@ fn may_begin_with(name: &str, token: &Token) -> bool { /// # Returns /// /// The parsed non-terminal. -fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { - if name == "tt" { +fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: Symbol) -> Nonterminal { + if name == sym::tt { return token::NtTT(p.parse_token_tree()); } // check at the beginning and the parser checks after each bump p.process_potential_macro_variable(); match name { - "item" => match panictry!(p.parse_item()) { + sym::item => match panictry!(p.parse_item()) { Some(i) => token::NtItem(i), None => { p.fatal("expected an item keyword").emit(); FatalError.raise(); } }, - "block" => token::NtBlock(panictry!(p.parse_block())), - "stmt" => match panictry!(p.parse_stmt()) { + sym::block => token::NtBlock(panictry!(p.parse_block())), + sym::stmt => match panictry!(p.parse_stmt()) { Some(s) => token::NtStmt(s), None => { p.fatal("expected a statement").emit(); FatalError.raise(); } }, - "pat" => token::NtPat(panictry!(p.parse_pat(None))), - "expr" => token::NtExpr(panictry!(p.parse_expr())), - "literal" => token::NtLiteral(panictry!(p.parse_literal_maybe_minus())), - "ty" => token::NtTy(panictry!(p.parse_ty())), + sym::pat => token::NtPat(panictry!(p.parse_pat(None))), + sym::expr => token::NtExpr(panictry!(p.parse_expr())), + sym::literal => token::NtLiteral(panictry!(p.parse_literal_maybe_minus())), + sym::ty => token::NtTy(panictry!(p.parse_ty())), // this could be handled like a token, since it is one - "ident" => if let Some((ident, is_raw)) = get_macro_ident(&p.token) { - let span = p.span; + sym::ident => if let Some((name, is_raw)) = get_macro_name(&p.token) { + let span = p.token.span; p.bump(); - token::NtIdent(Ident::new(ident.name, span), is_raw) + token::NtIdent(Ident::new(name, span), is_raw) } else { let token_str = pprust::token_to_string(&p.token); p.fatal(&format!("expected ident, found {}", &token_str)).emit(); FatalError.raise() } - "path" => token::NtPath(panictry!(p.parse_path_common(PathStyle::Type, false))), - "meta" => token::NtMeta(panictry!(p.parse_meta_item())), - "vis" => token::NtVis(panictry!(p.parse_visibility(true))), - "lifetime" => if p.check_lifetime() { + sym::path => token::NtPath(panictry!(p.parse_path(PathStyle::Type))), + sym::meta => token::NtMeta(panictry!(p.parse_meta_item())), + sym::vis => token::NtVis(panictry!(p.parse_visibility(true))), + sym::lifetime => if p.check_lifetime() { token::NtLifetime(p.expect_lifetime().ident) } else { let token_str = pprust::token_to_string(&p.token); diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index bd64bb010219b..1a448cb2a43cf 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -1,35 +1,37 @@ -use crate::{ast, attr}; use crate::edition::Edition; -use crate::ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension}; -use crate::ext::base::{NormalTT, TTMacroExpander}; +use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander}; +use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind}; use crate::ext::expand::{AstFragment, AstFragmentKind}; -use crate::ext::tt::macro_parser::{Success, Error, Failure}; -use crate::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; +use crate::ext::hygiene::Transparency; use crate::ext::tt::macro_parser::{parse, parse_failure_msg}; +use crate::ext::tt::macro_parser::{Error, Failure, Success}; +use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq}; use crate::ext::tt::quoted; use crate::ext::tt::transcribe::transcribe; use crate::feature_gate::Features; -use crate::parse::{Directory, ParseSess}; use crate::parse::parser::Parser; -use crate::parse::token::{self, NtTT}; -use crate::parse::token::Token::*; -use crate::symbol::Symbol; +use crate::parse::token::TokenKind::*; +use crate::parse::token::{self, NtTT, Token}; +use crate::parse::{Directory, ParseSess}; +use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree}; +use crate::{ast, attr}; use errors::FatalError; -use syntax_pos::{Span, DUMMY_SP, symbol::Ident}; use log::debug; +use syntax_pos::{symbol::Ident, Span}; -use rustc_data_structures::fx::{FxHashMap}; +use rustc_data_structures::fx::FxHashMap; use std::borrow::Cow; use std::collections::hash_map::Entry; +use std::slice; -use rustc_data_structures::sync::Lrc; use errors::Applicability; +use rustc_data_structures::sync::Lrc; const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \ - `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, \ - `path`, `meta`, `tt`, `item` and `vis`"; + `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \ + `literal`, `path`, `meta`, `tt`, `item` and `vis`"; pub struct ParserAnyMacro<'a> { parser: Parser<'a>, @@ -46,8 +48,9 @@ impl<'a> ParserAnyMacro<'a> { let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self; let fragment = panictry!(parser.parse_ast_fragment(kind, true).map_err(|mut e| { if parser.token == token::Eof && e.message().ends_with(", found ``") { - if !e.span.is_dummy() { // early end of macro arm (#52866) - e.replace_span_with(parser.sess.source_map().next_point(parser.span)); + if !e.span.is_dummy() { + // early end of macro arm (#52866) + e.replace_span_with(parser.sess.source_map().next_point(parser.token.span)); } let msg = &e.message[0]; e.message[0] = ( @@ -58,12 +61,13 @@ impl<'a> ParserAnyMacro<'a> { msg.1, ); } - if e.span.is_dummy() { // Get around lack of span in error (#30128) + if e.span.is_dummy() { + // Get around lack of span in error (#30128) e.replace_span_with(site_span); if parser.sess.source_map().span_to_filename(arm_span).is_real() { e.span_label(arm_span, "in this macro arm"); } - } else if !parser.sess.source_map().span_to_filename(parser.span).is_real() { + } else if !parser.sess.source_map().span_to_filename(parser.token.span).is_real() { e.span_label(site_span, "in this macro invocation"); } e @@ -97,17 +101,11 @@ impl TTMacroExpander for MacroRulesMacroExpander { sp: Span, input: TokenStream, def_span: Option, - ) -> Box { + ) -> Box { if !self.valid { return DummyResult::any(sp); } - generic_extension(cx, - sp, - def_span, - self.name, - input, - &self.lhses, - &self.rhses) + generic_extension(cx, sp, def_span, self.name, input, &self.lhses, &self.rhses) } } @@ -117,27 +115,27 @@ fn trace_macros_note(cx: &mut ExtCtxt<'_>, sp: Span, message: String) { } /// Given `lhses` and `rhses`, this is the new macro we create -fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>, - sp: Span, - def_span: Option, - name: ast::Ident, - arg: TokenStream, - lhses: &[quoted::TokenTree], - rhses: &[quoted::TokenTree]) - -> Box { +fn generic_extension<'cx>( + cx: &'cx mut ExtCtxt<'_>, + sp: Span, + def_span: Option, + name: ast::Ident, + arg: TokenStream, + lhses: &[quoted::TokenTree], + rhses: &[quoted::TokenTree], +) -> Box { if cx.trace_macros() { trace_macros_note(cx, sp, format!("expanding `{}! {{ {} }}`", name, arg)); } // Which arm's failure should we report? (the one furthest along) - let mut best_fail_spot = DUMMY_SP; - let mut best_fail_tok = None; - let mut best_fail_text = None; + let mut best_failure: Option<(Token, &str)> = None; - for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers + for (i, lhs) in lhses.iter().enumerate() { + // try each arm's matchers let lhs_tt = match *lhs { quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..], - _ => cx.span_bug(sp, "malformed macro lhs") + _ => cx.span_bug(sp, "malformed macro lhs"), }; match TokenTree::parse(cx, lhs_tt, arg.clone()) { @@ -151,7 +149,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>, let rhs_spans = rhs.iter().map(|t| t.span()).collect::>(); // rhs has holes ( `$id` and `$(...)` that need filled) - let mut tts = transcribe(cx, Some(named_matches), rhs); + let mut tts = transcribe(cx, &named_matches, rhs); // Replace all the tokens for the corresponding positions in the macro, to maintain // proper positions in error reporting, while maintaining the macro_backtrace. @@ -172,9 +170,9 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>, path: Cow::from(cx.current_expansion.module.directory.as_path()), ownership: cx.current_expansion.directory_ownership, }; - let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false); - p.root_module_name = cx.current_expansion.module.mod_path.last() - .map(|id| id.as_str().to_string()); + let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false, None); + p.root_module_name = + cx.current_expansion.module.mod_path.last().map(|id| id.as_str().to_string()); p.process_potential_macro_variable(); // Let the context choose how to interpret the result. @@ -188,23 +186,20 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>, site_span: sp, macro_ident: name, arm_span, - }) + }); } - Failure(sp, tok, t) => if sp.lo() >= best_fail_spot.lo() { - best_fail_spot = sp; - best_fail_tok = Some(tok); - best_fail_text = Some(t); + Failure(token, msg) => match best_failure { + Some((ref best_token, _)) if best_token.span.lo() >= token.span.lo() => {} + _ => best_failure = Some((token, msg)), }, - Error(err_sp, ref msg) => { - cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..]) - } + Error(err_sp, ref msg) => cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..]), } } - let best_fail_msg = parse_failure_msg(best_fail_tok.expect("ran no matchers")); - let span = best_fail_spot.substitute_dummy(sp); - let mut err = cx.struct_span_err(span, &best_fail_msg); - err.span_label(span, best_fail_text.unwrap_or(&best_fail_msg)); + let (token, label) = best_failure.expect("ran no matchers"); + let span = token.span.substitute_dummy(sp); + let mut err = cx.struct_span_err(span, &parse_failure_msg(&token)); + err.span_label(span, label); if let Some(sp) = def_span { if cx.source_map().span_to_filename(sp).is_real() && !sp.is_dummy() { err.span_label(cx.source_map().def_span(sp), "when calling this macro"); @@ -213,7 +208,8 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>, // Check whether there's a missing comma in this macro call, like `println!("{}" a);` if let Some((arg, comma_span)) = arg.add_comma() { - for lhs in lhses { // try each arm's matchers + for lhs in lhses { + // try each arm's matchers let lhs_tt = match *lhs { quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..], _ => continue, @@ -250,10 +246,11 @@ pub fn compile( sess: &ParseSess, features: &Features, def: &ast::Item, - edition: Edition + edition: Edition, ) -> SyntaxExtension { - let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs")); - let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs")); + let lhs_nm = ast::Ident::new(sym::lhs, def.span); + let rhs_nm = ast::Ident::new(sym::rhs, def.span); + let tt_spec = ast::Ident::new(sym::tt, def.span); // Parse the macro_rules! invocation let body = match def.node { @@ -267,32 +264,41 @@ pub fn compile( // ...quasiquoting this would be nice. // These spans won't matter, anyways let argument_gram = vec![ - quoted::TokenTree::Sequence(DelimSpan::dummy(), Lrc::new(quoted::SequenceRepetition { - tts: vec![ - quoted::TokenTree::MetaVarDecl(DUMMY_SP, lhs_nm, ast::Ident::from_str("tt")), - quoted::TokenTree::Token(DUMMY_SP, token::FatArrow), - quoted::TokenTree::MetaVarDecl(DUMMY_SP, rhs_nm, ast::Ident::from_str("tt")), - ], - separator: Some(if body.legacy { token::Semi } else { token::Comma }), - op: quoted::KleeneOp::OneOrMore, - num_captures: 2, - })), + quoted::TokenTree::Sequence( + DelimSpan::dummy(), + Lrc::new(quoted::SequenceRepetition { + tts: vec![ + quoted::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec), + quoted::TokenTree::token(token::FatArrow, def.span), + quoted::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec), + ], + separator: Some(Token::new( + if body.legacy { token::Semi } else { token::Comma }, + def.span, + )), + op: quoted::KleeneOp::OneOrMore, + num_captures: 2, + }), + ), // to phase into semicolon-termination instead of semicolon-separation - quoted::TokenTree::Sequence(DelimSpan::dummy(), Lrc::new(quoted::SequenceRepetition { - tts: vec![quoted::TokenTree::Token(DUMMY_SP, token::Semi)], - separator: None, - op: quoted::KleeneOp::ZeroOrMore, - num_captures: 0 - })), + quoted::TokenTree::Sequence( + DelimSpan::dummy(), + Lrc::new(quoted::SequenceRepetition { + tts: vec![quoted::TokenTree::token(token::Semi, def.span)], + separator: None, + op: quoted::KleeneOp::ZeroOrMore, + num_captures: 0, + }), + ), ]; let argument_map = match parse(sess, body.stream(), &argument_gram, None, true) { Success(m) => m, - Failure(sp, tok, t) => { - let s = parse_failure_msg(tok); - let sp = sp.substitute_dummy(def.span); + Failure(token, msg) => { + let s = parse_failure_msg(&token); + let sp = token.span.substitute_dummy(def.span); let mut err = sess.span_diagnostic.struct_span_fatal(sp, &s); - err.span_label(sp, t); + err.span_label(sp, msg); err.emit(); FatalError.raise(); } @@ -305,8 +311,9 @@ pub fn compile( // Extract the arguments: let lhses = match *argument_map[&lhs_nm] { - MatchedSeq(ref s, _) => { - s.iter().map(|m| { + MatchedSeq(ref s, _) => s + .iter() + .map(|m| { if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { let tt = quoted::parse( @@ -325,14 +332,15 @@ pub fn compile( } } sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") - }).collect::>() - } - _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") + }) + .collect::>(), + _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"), }; let rhses = match *argument_map[&rhs_nm] { - MatchedSeq(ref s, _) => { - s.iter().map(|m| { + MatchedSeq(ref s, _) => s + .iter() + .map(|m| { if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { return quoted::parse( @@ -343,14 +351,15 @@ pub fn compile( &def.attrs, edition, def.id, - ).pop() - .unwrap(); + ) + .pop() + .unwrap(); } } sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") - }).collect::>() - } - _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs") + }) + .collect::>(), + _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"), }; for rhs in &rhses { @@ -359,51 +368,66 @@ pub fn compile( // don't abort iteration early, so that errors for multiple lhses can be reported for lhs in &lhses { - valid &= check_lhs_no_empty_seq(sess, &[lhs.clone()]); + valid &= check_lhs_no_empty_seq(sess, slice::from_ref(lhs)); valid &= check_lhs_duplicate_matcher_bindings( sess, - &[lhs.clone()], + slice::from_ref(lhs), &mut FxHashMap::default(), - def.id + def.id, ); } - let expander: Box<_> = Box::new(MacroRulesMacroExpander { - name: def.ident, - lhses, - rhses, - valid, - }); - - if body.legacy { - let allow_internal_unstable = attr::find_by_name(&def.attrs, "allow_internal_unstable") - .map(|attr| attr - .meta_item_list() - .map(|list| list.iter() - .map(|it| it.name().unwrap_or_else(|| sess.span_diagnostic.span_bug( - it.span, "allow internal unstable expects feature names", - ))) - .collect::>().into() - ) + let expander: Box<_> = + Box::new(MacroRulesMacroExpander { name: def.ident, lhses, rhses, valid }); + + let default_transparency = if attr::contains_name(&def.attrs, sym::rustc_transparent_macro) { + Transparency::Transparent + } else if body.legacy { + Transparency::SemiTransparent + } else { + Transparency::Opaque + }; + + let allow_internal_unstable = + attr::find_by_name(&def.attrs, sym::allow_internal_unstable).map(|attr| { + attr.meta_item_list() + .map(|list| { + list.iter() + .filter_map(|it| { + let name = it.ident().map(|ident| ident.name); + if name.is_none() { + sess.span_diagnostic.span_err( + it.span(), + "allow internal unstable expects feature names", + ) + } + name + }) + .collect::>() + .into() + }) .unwrap_or_else(|| { sess.span_diagnostic.span_warn( - attr.span, "allow_internal_unstable expects list of feature names. In the \ - future this will become a hard error. Please use `allow_internal_unstable(\ - foo, bar)` to only allow the `foo` and `bar` features", + attr.span, + "allow_internal_unstable expects list of feature names. In the \ + future this will become a hard error. Please use `allow_internal_unstable(\ + foo, bar)` to only allow the `foo` and `bar` features", ); - vec![Symbol::intern("allow_internal_unstable_backcompat_hack")].into() + vec![sym::allow_internal_unstable_backcompat_hack].into() }) - ); - let allow_internal_unsafe = attr::contains_name(&def.attrs, "allow_internal_unsafe"); - let mut local_inner_macros = false; - if let Some(macro_export) = attr::find_by_name(&def.attrs, "macro_export") { - if let Some(l) = macro_export.meta_item_list() { - local_inner_macros = attr::list_contains_name(&l, "local_inner_macros"); - } + }); + + let allow_internal_unsafe = attr::contains_name(&def.attrs, sym::allow_internal_unsafe); + + let mut local_inner_macros = false; + if let Some(macro_export) = attr::find_by_name(&def.attrs, sym::macro_export) { + if let Some(l) = macro_export.meta_item_list() { + local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros); } + } - let unstable_feature = attr::find_stability(&sess, - &def.attrs, def.span).and_then(|stability| { + let unstable_feature = + attr::find_stability(&sess, &def.attrs, def.span).and_then(|stability| { if let attr::StabilityLevel::Unstable { issue, .. } = stability.level { Some((stability.feature, issue)) } else { @@ -411,31 +435,25 @@ pub fn compile( } }); - NormalTT { - expander, - def_info: Some((def.id, def.span)), - allow_internal_unstable, - allow_internal_unsafe, - local_inner_macros, - unstable_feature, - edition, - } - } else { - let is_transparent = attr::contains_name(&def.attrs, "rustc_transparent_macro"); - - SyntaxExtension::DeclMacro { - expander, - def_info: Some((def.id, def.span)), - is_transparent, - edition, - } + SyntaxExtension { + kind: SyntaxExtensionKind::LegacyBang(expander), + def_info: Some((def.id, def.span)), + default_transparency, + allow_internal_unstable, + allow_internal_unsafe, + local_inner_macros, + unstable_feature, + helper_attrs: Vec::new(), + edition, } } -fn check_lhs_nt_follows(sess: &ParseSess, - features: &Features, - attrs: &[ast::Attribute], - lhs: "ed::TokenTree) -> bool { +fn check_lhs_nt_follows( + sess: &ParseSess, + features: &Features, + attrs: &[ast::Attribute], + lhs: "ed::TokenTree, +) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. if let quoted::TokenTree::Delimited(_, ref tts) = *lhs { @@ -456,19 +474,22 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool { for tt in tts { match *tt { TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => (), - TokenTree::Delimited(_, ref del) => if !check_lhs_no_empty_seq(sess, &del.tts) { - return false; - }, + TokenTree::Delimited(_, ref del) => { + if !check_lhs_no_empty_seq(sess, &del.tts) { + return false; + } + } TokenTree::Sequence(span, ref seq) => { - if seq.separator.is_none() && seq.tts.iter().all(|seq_tt| { - match *seq_tt { - TokenTree::MetaVarDecl(_, _, id) => id.name == "vis", - TokenTree::Sequence(_, ref sub_seq) => + if seq.separator.is_none() + && seq.tts.iter().all(|seq_tt| match *seq_tt { + TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis, + TokenTree::Sequence(_, ref sub_seq) => { sub_seq.op == quoted::KleeneOp::ZeroOrMore - || sub_seq.op == quoted::KleeneOp::ZeroOrOne, + || sub_seq.op == quoted::KleeneOp::ZeroOrOne + } _ => false, - } - }) { + }) + { let sp = span.entire(); sess.span_diagnostic.span_err(sp, "repetition matches empty token tree"); return false; @@ -492,22 +513,14 @@ fn check_lhs_duplicate_matcher_bindings( node_id: ast::NodeId, ) -> bool { use self::quoted::TokenTree; - use crate::early_buffered_lints::BufferedEarlyLintId; for tt in tts { match *tt { TokenTree::MetaVarDecl(span, name, _kind) => { if let Some(&prev_span) = metavar_names.get(&name) { - // FIXME(mark-i-m): in a few cycles, make this a hard error. - // sess.span_diagnostic - // .struct_span_err(span, "duplicate matcher binding") - // .span_note(prev_span, "previous declaration was here") - // .emit(); - sess.buffer_lint( - BufferedEarlyLintId::DuplicateMacroMatcherBindingName, - crate::source_map::MultiSpan::from(vec![prev_span, span]), - node_id, - "duplicate matcher binding" - ); + sess.span_diagnostic + .struct_span_err(span, "duplicate matcher binding") + .span_note(prev_span, "previous declaration was here") + .emit(); return false; } else { metavar_names.insert(name, span); @@ -517,7 +530,7 @@ fn check_lhs_duplicate_matcher_bindings( if !check_lhs_duplicate_matcher_bindings(sess, &del.tts, metavar_names, node_id) { return false; } - }, + } TokenTree::Sequence(_, ref seq) => { if !check_lhs_duplicate_matcher_bindings(sess, &seq.tts, metavar_names, node_id) { return false; @@ -533,15 +546,17 @@ fn check_lhs_duplicate_matcher_bindings( fn check_rhs(sess: &ParseSess, rhs: "ed::TokenTree) -> bool { match *rhs { quoted::TokenTree::Delimited(..) => return true, - _ => sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited") + _ => sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited"), } false } -fn check_matcher(sess: &ParseSess, - features: &Features, - attrs: &[ast::Attribute], - matcher: &[quoted::TokenTree]) -> bool { +fn check_matcher( + sess: &ParseSess, + features: &Features, + attrs: &[ast::Attribute], + matcher: &[quoted::TokenTree], +) -> bool { let first_sets = FirstSets::new(matcher); let empty_suffix = TokenSet::empty(); let err = sess.span_diagnostic.err_count(); @@ -614,15 +629,14 @@ impl FirstSets { // If the sequence contents can be empty, then the first // token could be the separator token itself. - if let (Some(ref sep), true) = (seq_rep.separator.clone(), - subfirst.maybe_empty) { - first.add_one_maybe(TokenTree::Token(sp.entire(), sep.clone())); + if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) { + first.add_one_maybe(TokenTree::Token(sep.clone())); } // Reverse scan: Sequence comes before `first`. if subfirst.maybe_empty - || seq_rep.op == quoted::KleeneOp::ZeroOrMore - || seq_rep.op == quoted::KleeneOp::ZeroOrOne + || seq_rep.op == quoted::KleeneOp::ZeroOrMore + || seq_rep.op == quoted::KleeneOp::ZeroOrOne { // If sequence is potentially empty, then // union them (preserving first emptiness). @@ -660,20 +674,18 @@ impl FirstSets { TokenTree::Sequence(sp, ref seq_rep) => { match self.first.get(&sp.entire()) { Some(&Some(ref subfirst)) => { - // If the sequence contents can be empty, then the first // token could be the separator token itself. - if let (Some(ref sep), true) = (seq_rep.separator.clone(), - subfirst.maybe_empty) { - first.add_one_maybe(TokenTree::Token(sp.entire(), sep.clone())); + if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) { + first.add_one_maybe(TokenTree::Token(sep.clone())); } assert!(first.maybe_empty); first.add_all(subfirst); if subfirst.maybe_empty - || seq_rep.op == quoted::KleeneOp::ZeroOrMore - || seq_rep.op == quoted::KleeneOp::ZeroOrOne + || seq_rep.op == quoted::KleeneOp::ZeroOrMore + || seq_rep.op == quoted::KleeneOp::ZeroOrOne { // continue scanning for more first // tokens, but also make sure we @@ -722,7 +734,9 @@ struct TokenSet { impl TokenSet { // Returns a set for the empty sequence. - fn empty() -> Self { TokenSet { tokens: Vec::new(), maybe_empty: true } } + fn empty() -> Self { + TokenSet { tokens: Vec::new(), maybe_empty: true } + } // Returns the set `{ tok }` for the single-token (and thus // non-empty) sequence [tok]. @@ -791,12 +805,14 @@ impl TokenSet { // // Requires that `first_sets` is pre-computed for `matcher`; // see `FirstSets::new`. -fn check_matcher_core(sess: &ParseSess, - features: &Features, - attrs: &[ast::Attribute], - first_sets: &FirstSets, - matcher: &[quoted::TokenTree], - follow: &TokenSet) -> TokenSet { +fn check_matcher_core( + sess: &ParseSess, + features: &Features, + attrs: &[ast::Attribute], + first_sets: &FirstSets, + matcher: &[quoted::TokenTree], + follow: &TokenSet, +) -> TokenSet { use quoted::TokenTree; let mut last = TokenSet::empty(); @@ -806,11 +822,13 @@ fn check_matcher_core(sess: &ParseSess, // then ensure T can also be followed by any element of FOLLOW. 'each_token: for i in 0..matcher.len() { let token = &matcher[i]; - let suffix = &matcher[i+1..]; + let suffix = &matcher[i + 1..]; let build_suffix_first = || { let mut s = first_sets.first(suffix); - if s.maybe_empty { s.add_all(follow); } + if s.maybe_empty { + s.add_all(follow); + } s }; @@ -826,7 +844,8 @@ fn check_matcher_core(sess: &ParseSess, let can_be_followed_by_any; if let Err(bad_frag) = has_legal_fragment_specifier(sess, features, attrs, token) { let msg = format!("invalid fragment specifier `{}`", bad_frag); - sess.span_diagnostic.struct_span_err(token.span(), &msg) + sess.span_diagnostic + .struct_span_err(token.span(), &msg) .help(VALID_FRAGMENT_NAMES_MSG) .emit(); // (This eliminates false positives and duplicates @@ -857,7 +876,7 @@ fn check_matcher_core(sess: &ParseSess, // against SUFFIX continue 'each_token; } - TokenTree::Sequence(sp, ref seq_rep) => { + TokenTree::Sequence(_, ref seq_rep) => { suffix_first = build_suffix_first(); // The trick here: when we check the interior, we want // to include the separator (if any) as a potential @@ -870,9 +889,9 @@ fn check_matcher_core(sess: &ParseSess, // work of cloning it? But then again, this way I may // get a "tighter" span? let mut new; - let my_suffix = if let Some(ref u) = seq_rep.separator { + let my_suffix = if let Some(sep) = &seq_rep.separator { new = suffix_first.clone(); - new.add_one_maybe(TokenTree::Token(sp.entire(), u.clone())); + new.add_one_maybe(TokenTree::Token(sep.clone())); &new } else { &suffix_first @@ -881,12 +900,8 @@ fn check_matcher_core(sess: &ParseSess, // At this point, `suffix_first` is built, and // `my_suffix` is some TokenSet that we can use // for checking the interior of `seq_rep`. - let next = check_matcher_core(sess, - features, - attrs, - first_sets, - &seq_rep.tts, - my_suffix); + let next = + check_matcher_core(sess, features, attrs, first_sets, &seq_rep.tts, my_suffix); if next.maybe_empty { last.add_all(&next); } else { @@ -908,16 +923,17 @@ fn check_matcher_core(sess: &ParseSess, for next_token in &suffix_first.tokens { match is_in_follow(next_token, &frag_spec.as_str()) { IsInFollow::Invalid(msg, help) => { - sess.span_diagnostic.struct_span_err(next_token.span(), &msg) - .help(help).emit(); + sess.span_diagnostic + .struct_span_err(next_token.span(), &msg) + .help(help) + .emit(); // don't bother reporting every source of // conflict for a particular element of `last`. continue 'each_last; } IsInFollow::Yes => {} - IsInFollow::No(ref possible) => { - let may_be = if last.tokens.len() == 1 && - suffix_first.tokens.len() == 1 + IsInFollow::No(possible) => { + let may_be = if last.tokens.len() == 1 && suffix_first.tokens.len() == 1 { "is" } else { @@ -927,33 +943,37 @@ fn check_matcher_core(sess: &ParseSess, let sp = next_token.span(); let mut err = sess.span_diagnostic.struct_span_err( sp, - &format!("`${name}:{frag}` {may_be} followed by `{next}`, which \ - is not allowed for `{frag}` fragments", - name=name, - frag=frag_spec, - next=quoted_tt_to_string(next_token), - may_be=may_be), + &format!( + "`${name}:{frag}` {may_be} followed by `{next}`, which \ + is not allowed for `{frag}` fragments", + name = name, + frag = frag_spec, + next = quoted_tt_to_string(next_token), + may_be = may_be + ), ); err.span_label( sp, format!("not allowed after `{}` fragments", frag_spec), ); let msg = "allowed there are: "; - match &possible[..] { + match possible { &[] => {} &[t] => { err.note(&format!( "only {} is allowed after `{}` fragments", - t, - frag_spec, + t, frag_spec, )); } ts => { err.note(&format!( "{}{} or {}", msg, - ts[..ts.len() - 1].iter().map(|s| *s) - .collect::>().join(", "), + ts[..ts.len() - 1] + .iter() + .map(|s| *s) + .collect::>() + .join(", "), ts[ts.len() - 1], )); } @@ -1003,7 +1023,7 @@ fn frag_can_be_followed_by_any(frag: &str) -> bool { enum IsInFollow { Yes, - No(Vec<&'static str>), + No(&'static [&'static str]), Invalid(String, &'static str), } @@ -1018,7 +1038,7 @@ enum IsInFollow { fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow { use quoted::TokenTree; - if let TokenTree::Token(_, token::CloseDelim(_)) = *tok { + if let TokenTree::Token(Token { kind: token::CloseDelim(_), .. }) = *tok { // closing a token tree can never be matched by any fragment; // iow, we always require that `(` and `)` match, etc. IsInFollow::Yes @@ -1028,110 +1048,131 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow { // since items *must* be followed by either a `;` or a `}`, we can // accept anything after them IsInFollow::Yes - }, + } "block" => { // anything can follow block, the braces provide an easy boundary to // maintain IsInFollow::Yes - }, - "stmt" | "expr" => { - let tokens = vec!["`=>`", "`,`", "`;`"]; - match *tok { - TokenTree::Token(_, ref tok) => match *tok { + } + "stmt" | "expr" => { + const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"]; + match tok { + TokenTree::Token(token) => match token.kind { FatArrow | Comma | Semi => IsInFollow::Yes, - _ => IsInFollow::No(tokens), + _ => IsInFollow::No(TOKENS), }, - _ => IsInFollow::No(tokens), + _ => IsInFollow::No(TOKENS), } - }, + } "pat" => { - let tokens = vec!["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"]; - match *tok { - TokenTree::Token(_, ref tok) => match *tok { + const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"]; + match tok { + TokenTree::Token(token) => match token.kind { FatArrow | Comma | Eq | BinOp(token::Or) => IsInFollow::Yes, - Ident(i, false) if i.name == "if" || i.name == "in" => IsInFollow::Yes, - _ => IsInFollow::No(tokens), + Ident(name, false) if name == kw::If || name == kw::In => IsInFollow::Yes, + _ => IsInFollow::No(TOKENS), }, - _ => IsInFollow::No(tokens), + _ => IsInFollow::No(TOKENS), } - }, + } "path" | "ty" => { - let tokens = vec![ - "`{`", "`[`", "`=>`", "`,`", "`>`","`=`", "`:`", "`;`", "`|`", "`as`", + const TOKENS: &[&str] = &[ + "`{`", "`[`", "`=>`", "`,`", "`>`", "`=`", "`:`", "`;`", "`|`", "`as`", "`where`", ]; - match *tok { - TokenTree::Token(_, ref tok) => match *tok { - OpenDelim(token::DelimToken::Brace) | - OpenDelim(token::DelimToken::Bracket) | - Comma | FatArrow | Colon | Eq | Gt | BinOp(token::Shr) | Semi | - BinOp(token::Or) => IsInFollow::Yes, - Ident(i, false) if i.name == "as" || i.name == "where" => IsInFollow::Yes, - _ => IsInFollow::No(tokens), + match tok { + TokenTree::Token(token) => match token.kind { + OpenDelim(token::DelimToken::Brace) + | OpenDelim(token::DelimToken::Bracket) + | Comma + | FatArrow + | Colon + | Eq + | Gt + | BinOp(token::Shr) + | Semi + | BinOp(token::Or) => IsInFollow::Yes, + Ident(name, false) if name == kw::As || name == kw::Where => { + IsInFollow::Yes + } + _ => IsInFollow::No(TOKENS), }, - TokenTree::MetaVarDecl(_, _, frag) if frag.name == "block" => IsInFollow::Yes, - _ => IsInFollow::No(tokens), + TokenTree::MetaVarDecl(_, _, frag) if frag.name == sym::block => { + IsInFollow::Yes + } + _ => IsInFollow::No(TOKENS), } - }, + } "ident" | "lifetime" => { // being a single token, idents and lifetimes are harmless IsInFollow::Yes - }, + } "literal" => { // literals may be of a single token, or two tokens (negative numbers) IsInFollow::Yes - }, + } "meta" | "tt" => { // being either a single token or a delimited sequence, tt is // harmless IsInFollow::Yes - }, + } "vis" => { // Explicitly disallow `priv`, on the off chance it comes back. - let tokens = vec!["`,`", "an ident", "a type"]; - match *tok { - TokenTree::Token(_, ref tok) => match *tok { + const TOKENS: &[&str] = &["`,`", "an ident", "a type"]; + match tok { + TokenTree::Token(token) => match token.kind { Comma => IsInFollow::Yes, - Ident(i, is_raw) if is_raw || i.name != "priv" => IsInFollow::Yes, - ref tok => if tok.can_begin_type() { - IsInFollow::Yes - } else { - IsInFollow::No(tokens) + Ident(name, is_raw) if is_raw || name != kw::Priv => IsInFollow::Yes, + _ => { + if token.can_begin_type() { + IsInFollow::Yes + } else { + IsInFollow::No(TOKENS) + } } }, - TokenTree::MetaVarDecl(_, _, frag) if frag.name == "ident" - || frag.name == "ty" - || frag.name == "path" => IsInFollow::Yes, - _ => IsInFollow::No(tokens), + TokenTree::MetaVarDecl(_, _, frag) + if frag.name == sym::ident + || frag.name == sym::ty + || frag.name == sym::path => + { + IsInFollow::Yes + } + _ => IsInFollow::No(TOKENS), } - }, - "" => IsInFollow::Yes, // keywords::Invalid - _ => IsInFollow::Invalid(format!("invalid fragment specifier `{}`", frag), - VALID_FRAGMENT_NAMES_MSG), + } + "" => IsInFollow::Yes, // kw::Invalid + _ => IsInFollow::Invalid( + format!("invalid fragment specifier `{}`", frag), + VALID_FRAGMENT_NAMES_MSG, + ), } } } -fn has_legal_fragment_specifier(sess: &ParseSess, - features: &Features, - attrs: &[ast::Attribute], - tok: "ed::TokenTree) -> Result<(), String> { +fn has_legal_fragment_specifier( + sess: &ParseSess, + features: &Features, + attrs: &[ast::Attribute], + tok: "ed::TokenTree, +) -> Result<(), String> { debug!("has_legal_fragment_specifier({:?})", tok); if let quoted::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok { - let frag_name = frag_spec.as_str(); let frag_span = tok.span(); - if !is_legal_fragment_specifier(sess, features, attrs, &frag_name, frag_span) { - return Err(frag_name.to_string()); + if !is_legal_fragment_specifier(sess, features, attrs, frag_spec.name, frag_span) { + return Err(frag_spec.to_string()); } } Ok(()) } -fn is_legal_fragment_specifier(_sess: &ParseSess, - _features: &Features, - _attrs: &[ast::Attribute], - frag_name: &str, - _frag_span: Span) -> bool { +fn is_legal_fragment_specifier( + _sess: &ParseSess, + _features: &Features, + _attrs: &[ast::Attribute], + frag_name: Symbol, + _frag_span: Span, +) -> bool { /* * If new fragment specifiers are invented in nightly, `_sess`, * `_features`, `_attrs`, and `_frag_span` will be useful here @@ -1139,19 +1180,32 @@ fn is_legal_fragment_specifier(_sess: &ParseSess, * this function. */ match frag_name { - "item" | "block" | "stmt" | "expr" | "pat" | "lifetime" | - "path" | "ty" | "ident" | "meta" | "tt" | "vis" | "literal" | - "" => true, + sym::item + | sym::block + | sym::stmt + | sym::expr + | sym::pat + | sym::lifetime + | sym::path + | sym::ty + | sym::ident + | sym::meta + | sym::tt + | sym::vis + | sym::literal + | kw::Invalid => true, _ => false, } } fn quoted_tt_to_string(tt: "ed::TokenTree) -> String { match *tt { - quoted::TokenTree::Token(_, ref tok) => crate::print::pprust::token_to_string(tok), + quoted::TokenTree::Token(ref token) => crate::print::pprust::token_to_string(&token), quoted::TokenTree::MetaVar(_, name) => format!("${}", name), quoted::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind), - _ => panic!("unexpected quoted::TokenTree::{{Sequence or Delimited}} \ - in follow set checker"), + _ => panic!( + "unexpected quoted::TokenTree::{{Sequence or Delimited}} \ + in follow set checker" + ), } } diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index b24edb57e527e..ccf9db842ab6e 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -1,12 +1,12 @@ +use crate::ast; use crate::ast::NodeId; -use crate::early_buffered_lints::BufferedEarlyLintId; use crate::ext::tt::macro_parser; use crate::feature_gate::Features; -use crate::parse::{token, ParseSess}; +use crate::parse::token::{self, Token, TokenKind}; +use crate::parse::ParseSess; use crate::print::pprust; +use crate::symbol::kw; use crate::tokenstream::{self, DelimSpan}; -use crate::ast; -use crate::symbol::keywords; use syntax_pos::{edition::Edition, BytePos, Span}; @@ -22,16 +22,6 @@ pub struct Delimited { } impl Delimited { - /// Returns the opening delimiter (possibly `NoDelim`). - pub fn open_token(&self) -> token::Token { - token::OpenDelim(self.delim) - } - - /// Returns the closing delimiter (possibly `NoDelim`). - pub fn close_token(&self) -> token::Token { - token::CloseDelim(self.delim) - } - /// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter. pub fn open_tt(&self, span: Span) -> TokenTree { let open_span = if span.is_dummy() { @@ -39,7 +29,7 @@ impl Delimited { } else { span.with_lo(span.lo() + BytePos(self.delim.len() as u32)) }; - TokenTree::Token(open_span, self.open_token()) + TokenTree::token(token::OpenDelim(self.delim), open_span) } /// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter. @@ -49,7 +39,7 @@ impl Delimited { } else { span.with_lo(span.hi() - BytePos(self.delim.len() as u32)) }; - TokenTree::Token(close_span, self.close_token()) + TokenTree::token(token::CloseDelim(self.delim), close_span) } } @@ -58,7 +48,7 @@ pub struct SequenceRepetition { /// The sequence of token trees pub tts: Vec, /// The optional separator - pub separator: Option, + pub separator: Option, /// Whether the sequence can be repeated zero (*), or one or more times (+) pub op: KleeneOp, /// The number of `Match`s that appear in the sequence (and subsequences) @@ -73,6 +63,7 @@ pub enum KleeneOp { ZeroOrMore, /// Kleene plus (`+`) for one or more repetitions OneOrMore, + /// Kleene optional (`?`) for zero or one reptitions ZeroOrOne, } @@ -80,7 +71,7 @@ pub enum KleeneOp { /// are "first-class" token trees. Useful for parsing macros. #[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)] pub enum TokenTree { - Token(Span, token::Token), + Token(Token), Delimited(DelimSpan, Lrc), /// A kleene-style repetition sequence Sequence(DelimSpan, Lrc), @@ -143,13 +134,16 @@ impl TokenTree { /// Retrieves the `TokenTree`'s span. pub fn span(&self) -> Span { match *self { - TokenTree::Token(sp, _) - | TokenTree::MetaVar(sp, _) - | TokenTree::MetaVarDecl(sp, _, _) => sp, - TokenTree::Delimited(sp, _) - | TokenTree::Sequence(sp, _) => sp.entire(), + TokenTree::Token(Token { span, .. }) + | TokenTree::MetaVar(span, _) + | TokenTree::MetaVarDecl(span, _, _) => span, + TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(), } } + + crate fn token(kind: TokenKind, span: Span) -> TokenTree { + TokenTree::Token(Token::new(kind, span)) + } } /// Takes a `tokenstream::TokenStream` and returns a `Vec`. Specifically, this @@ -204,31 +198,23 @@ pub fn parse( match tree { TokenTree::MetaVar(start_sp, ident) if expect_matchers => { let span = match trees.next() { - Some(tokenstream::TokenTree::Token(span, token::Colon)) => match trees.next() { - Some(tokenstream::TokenTree::Token(end_sp, ref tok)) => match tok.ident() { - Some((kind, _)) => { - let span = end_sp.with_lo(start_sp.lo()); - result.push(TokenTree::MetaVarDecl(span, ident, kind)); - continue; - } - _ => end_sp, - }, - tree => tree - .as_ref() - .map(tokenstream::TokenTree::span) - .unwrap_or(span), - }, - tree => tree - .as_ref() - .map(tokenstream::TokenTree::span) - .unwrap_or(start_sp), + Some(tokenstream::TokenTree::Token(Token { kind: token::Colon, span })) => { + match trees.next() { + Some(tokenstream::TokenTree::Token(token)) => match token.ident() { + Some((kind, _)) => { + let span = token.span.with_lo(start_sp.lo()); + result.push(TokenTree::MetaVarDecl(span, ident, kind)); + continue; + } + _ => token.span, + }, + tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span), + } + } + tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp), }; sess.missing_fragment_specifiers.borrow_mut().insert(span); - result.push(TokenTree::MetaVarDecl( - span, - ident, - keywords::Invalid.ident(), - )); + result.push(TokenTree::MetaVarDecl(span, ident, ast::Ident::invalid())); } // Not a metavar or no matchers allowed, so just return the tree @@ -253,29 +239,26 @@ pub fn parse( /// - `sess`: the parsing session. Any errors will be emitted to this session. /// - `features`, `attrs`: language feature flags and attributes so that we know whether to use /// unstable features or not. -fn parse_tree( +fn parse_tree( tree: tokenstream::TokenTree, - trees: &mut Peekable, + trees: &mut Peekable>, expect_matchers: bool, sess: &ParseSess, features: &Features, attrs: &[ast::Attribute], edition: Edition, macro_node_id: NodeId, -) -> TokenTree -where - I: Iterator, -{ +) -> TokenTree { // Depending on what `tree` is, we could be parsing different parts of a macro match tree { // `tree` is a `$` token. Look at the next token in `trees` - tokenstream::TokenTree::Token(span, token::Dollar) => match trees.next() { + tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }) => match trees.next() { // `tree` is followed by a delimited set of token trees. This indicates the beginning // of a repetition sequence in the macro (e.g. `$(pat)*`). Some(tokenstream::TokenTree::Delimited(span, delim, tts)) => { // Must have `(` not `{` or `[` if delim != token::Paren { - let tok = pprust::token_to_string(&token::OpenDelim(delim)); + let tok = pprust::token_kind_to_string(&token::OpenDelim(delim)); let msg = format!("expected `(`, found `{}`", tok); sess.span_diagnostic.span_err(span.entire(), &msg); } @@ -290,16 +273,7 @@ where macro_node_id, ); // Get the Kleene operator and optional separator - let (separator, op) = - parse_sep_and_kleene_op( - trees, - span.entire(), - sess, - features, - attrs, - edition, - macro_node_id, - ); + let (separator, op) = parse_sep_and_kleene_op(trees, span.entire(), sess); // Count the number of captured "names" (i.e., named metavars) let name_captures = macro_parser::count_names(&sequence); TokenTree::Sequence( @@ -315,40 +289,37 @@ where // `tree` is followed by an `ident`. This could be `$meta_var` or the `$crate` special // metavariable that names the crate of the invocation. - Some(tokenstream::TokenTree::Token(ident_span, ref token)) if token.is_ident() => { + Some(tokenstream::TokenTree::Token(token)) if token.is_ident() => { let (ident, is_raw) = token.ident().unwrap(); - let span = ident_span.with_lo(span.lo()); - if ident.name == keywords::Crate.name() && !is_raw { - let ident = ast::Ident::new(keywords::DollarCrate.name(), ident.span); - TokenTree::Token(span, token::Ident(ident, is_raw)) + let span = ident.span.with_lo(span.lo()); + if ident.name == kw::Crate && !is_raw { + TokenTree::token(token::Ident(kw::DollarCrate, is_raw), span) } else { TokenTree::MetaVar(span, ident) } } // `tree` is followed by a random token. This is an error. - Some(tokenstream::TokenTree::Token(span, tok)) => { - let msg = format!( - "expected identifier, found `{}`", - pprust::token_to_string(&tok) - ); - sess.span_diagnostic.span_err(span, &msg); - TokenTree::MetaVar(span, keywords::Invalid.ident()) + Some(tokenstream::TokenTree::Token(token)) => { + let msg = + format!("expected identifier, found `{}`", pprust::token_to_string(&token),); + sess.span_diagnostic.span_err(token.span, &msg); + TokenTree::MetaVar(token.span, ast::Ident::invalid()) } // There are no more tokens. Just return the `$` we already have. - None => TokenTree::Token(span, token::Dollar), + None => TokenTree::token(token::Dollar, span), }, // `tree` is an arbitrary token. Keep it. - tokenstream::TokenTree::Token(span, tok) => TokenTree::Token(span, tok), + tokenstream::TokenTree::Token(token) => TokenTree::Token(token), // `tree` is the beginning of a delimited set of tokens (e.g., `(` or `{`). We need to // descend into the delimited set and further parse it. tokenstream::TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited( span, Lrc::new(Delimited { - delim: delim, + delim, tts: parse( tts.into(), expect_matchers, @@ -365,8 +336,8 @@ where /// Takes a token and returns `Some(KleeneOp)` if the token is `+` `*` or `?`. Otherwise, return /// `None`. -fn kleene_op(token: &token::Token) -> Option { - match *token { +fn kleene_op(token: &Token) -> Option { + match token.kind { token::BinOp(token::Star) => Some(KleeneOp::ZeroOrMore), token::BinOp(token::Plus) => Some(KleeneOp::OneOrMore), token::Question => Some(KleeneOp::ZeroOrOne), @@ -379,22 +350,16 @@ fn kleene_op(token: &token::Token) -> Option { /// - Ok(Ok((op, span))) if the next token tree is a KleeneOp /// - Ok(Err(tok, span)) if the next token tree is a token but not a KleeneOp /// - Err(span) if the next token tree is not a token -fn parse_kleene_op( - input: &mut I, +fn parse_kleene_op( + input: &mut impl Iterator, span: Span, -) -> Result, Span> -where - I: Iterator, -{ +) -> Result, Span> { match input.next() { - Some(tokenstream::TokenTree::Token(span, tok)) => match kleene_op(&tok) { - Some(op) => Ok(Ok((op, span))), - None => Ok(Err((tok, span))), + Some(tokenstream::TokenTree::Token(token)) => match kleene_op(&token) { + Some(op) => Ok(Ok((op, token.span))), + None => Ok(Err(token)), }, - tree => Err(tree - .as_ref() - .map(tokenstream::TokenTree::span) - .unwrap_or(span)), + tree => Err(tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span)), } } @@ -410,181 +375,23 @@ where /// session `sess`. If the next one (or possibly two) tokens in `input` correspond to a Kleene /// operator and separator, then a tuple with `(separator, KleeneOp)` is returned. Otherwise, an /// error with the appropriate span is emitted to `sess` and a dummy value is returned. -/// -/// N.B., in the 2015 edition, `*` and `+` are the only Kleene operators, and `?` is a separator. -/// In the 2018 edition however, `?` is a Kleene operator, and not a separator. -fn parse_sep_and_kleene_op( - input: &mut Peekable, - span: Span, - sess: &ParseSess, - features: &Features, - attrs: &[ast::Attribute], - edition: Edition, - macro_node_id: NodeId, -) -> (Option, KleeneOp) -where - I: Iterator, -{ - match edition { - Edition::Edition2015 => parse_sep_and_kleene_op_2015( - input, - span, - sess, - features, - attrs, - macro_node_id, - ), - Edition::Edition2018 => parse_sep_and_kleene_op_2018(input, span, sess, features, attrs), - } -} - -// `?` is a separator (with a migration warning) and never a KleeneOp. -fn parse_sep_and_kleene_op_2015( - input: &mut Peekable, - span: Span, - sess: &ParseSess, - _features: &Features, - _attrs: &[ast::Attribute], - macro_node_id: NodeId, -) -> (Option, KleeneOp) -where - I: Iterator, -{ - // We basically look at two token trees here, denoted as #1 and #2 below - let span = match parse_kleene_op(input, span) { - // #1 is a `+` or `*` KleeneOp - // - // `?` is ambiguous: it could be a separator (warning) or a Kleene::ZeroOrOne (error), so - // we need to look ahead one more token to be sure. - Ok(Ok((op, _))) if op != KleeneOp::ZeroOrOne => return (None, op), - - // #1 is `?` token, but it could be a Kleene::ZeroOrOne (error in 2015) without a separator - // or it could be a `?` separator followed by any Kleene operator. We need to look ahead 1 - // token to find out which. - Ok(Ok((op, op1_span))) => { - assert_eq!(op, KleeneOp::ZeroOrOne); - - // Lookahead at #2. If it is a KleenOp, then #1 is a separator. - let is_1_sep = if let Some(&tokenstream::TokenTree::Token(_, ref tok2)) = input.peek() { - kleene_op(tok2).is_some() - } else { - false - }; - - if is_1_sep { - // #1 is a separator and #2 should be a KleepeOp. - // (N.B. We need to advance the input iterator.) - match parse_kleene_op(input, span) { - // #2 is `?`, which is not allowed as a Kleene op in 2015 edition, - // but is allowed in the 2018 edition. - Ok(Ok((op, op2_span))) if op == KleeneOp::ZeroOrOne => { - sess.span_diagnostic - .struct_span_err(op2_span, "expected `*` or `+`") - .note("`?` is not a macro repetition operator in the 2015 edition, \ - but is accepted in the 2018 edition") - .emit(); - - // Return a dummy - return (None, KleeneOp::ZeroOrMore); - } - - // #2 is a Kleene op, which is the only valid option - Ok(Ok((op, _))) => { - // Warn that `?` as a separator will be deprecated - sess.buffer_lint( - BufferedEarlyLintId::QuestionMarkMacroSep, - op1_span, - macro_node_id, - "using `?` as a separator is deprecated and will be \ - a hard error in an upcoming edition", - ); - - return (Some(token::Question), op); - } - - // #2 is a random token (this is an error) :( - Ok(Err((_, _))) => op1_span, - - // #2 is not even a token at all :( - Err(_) => op1_span, - } - } else { - // `?` is not allowed as a Kleene op in 2015, - // but is allowed in the 2018 edition - sess.span_diagnostic - .struct_span_err(op1_span, "expected `*` or `+`") - .note("`?` is not a macro repetition operator in the 2015 edition, \ - but is accepted in the 2018 edition") - .emit(); - - // Return a dummy - return (None, KleeneOp::ZeroOrMore); - } - } - - // #1 is a separator followed by #2, a KleeneOp - Ok(Err((tok, span))) => match parse_kleene_op(input, span) { - // #2 is a `?`, which is not allowed as a Kleene op in 2015 edition, - // but is allowed in the 2018 edition - Ok(Ok((op, op2_span))) if op == KleeneOp::ZeroOrOne => { - sess.span_diagnostic - .struct_span_err(op2_span, "expected `*` or `+`") - .note("`?` is not a macro repetition operator in the 2015 edition, \ - but is accepted in the 2018 edition") - .emit(); - - // Return a dummy - return (None, KleeneOp::ZeroOrMore); - } - - // #2 is a KleeneOp :D - Ok(Ok((op, _))) => return (Some(tok), op), - - // #2 is a random token :( - Ok(Err((_, span))) => span, - - // #2 is not a token at all :( - Err(span) => span, - }, - - // #1 is not a token - Err(span) => span, - }; - - sess.span_diagnostic.span_err(span, "expected `*` or `+`"); - - // Return a dummy - (None, KleeneOp::ZeroOrMore) -} - -// `?` is a Kleene op, not a separator -fn parse_sep_and_kleene_op_2018( - input: &mut Peekable, +fn parse_sep_and_kleene_op( + input: &mut Peekable>, span: Span, sess: &ParseSess, - _features: &Features, - _attrs: &[ast::Attribute], -) -> (Option, KleeneOp) -where - I: Iterator, -{ +) -> (Option, KleeneOp) { // We basically look at two token trees here, denoted as #1 and #2 below let span = match parse_kleene_op(input, span) { - // #1 is a `?` (needs feature gate) - Ok(Ok((op, _op1_span))) if op == KleeneOp::ZeroOrOne => { - return (None, op); - } - - // #1 is a `+` or `*` KleeneOp + // #1 is a `?`, `+`, or `*` KleeneOp Ok(Ok((op, _))) => return (None, op), // #1 is a separator followed by #2, a KleeneOp - Ok(Err((tok, span))) => match parse_kleene_op(input, span) { + Ok(Err(token)) => match parse_kleene_op(input, token.span) { // #2 is the `?` Kleene op, which does not take a separator (error) - Ok(Ok((op, _op2_span))) if op == KleeneOp::ZeroOrOne => { + Ok(Ok((KleeneOp::ZeroOrOne, _))) => { // Error! sess.span_diagnostic.span_err( - span, + token.span, "the `?` macro repetition operator does not take a separator", ); @@ -593,13 +400,10 @@ where } // #2 is a KleeneOp :D - Ok(Ok((op, _))) => return (Some(tok), op), - - // #2 is a random token :( - Ok(Err((_, span))) => span, + Ok(Ok((op, _))) => return (Some(token), op), - // #2 is not a token at all :( - Err(span) => span, + // #2 is a random token or not a token at all :( + Ok(Err(Token { span, .. })) | Err(span) => span, }, // #1 is not a token @@ -607,8 +411,7 @@ where }; // If we ever get to this point, we have experienced an "unexpected token" error - sess.span_diagnostic - .span_err(span, "expected one of: `*`, `+`, or `?`"); + sess.span_diagnostic.span_err(span, "expected one of: `*`, `+`, or `?`"); // Return a dummy (None, KleeneOp::ZeroOrMore) diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index bd2adb5ac13ba..ea7f8e356aa63 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -1,39 +1,30 @@ use crate::ast::Ident; use crate::ext::base::ExtCtxt; use crate::ext::expand::Marker; -use crate::ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; +use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; use crate::ext::tt::quoted; use crate::mut_visit::noop_visit_tt; -use crate::parse::token::{self, Token, NtTT}; +use crate::parse::token::{self, NtTT, Token}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use smallvec::{smallvec, SmallVec}; -use syntax_pos::DUMMY_SP; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use std::mem; -use std::ops::Add; use std::rc::Rc; -// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`). +/// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`). enum Frame { - Delimited { - forest: Lrc, - idx: usize, - span: DelimSpan, - }, - Sequence { - forest: Lrc, - idx: usize, - sep: Option, - }, + Delimited { forest: Lrc, idx: usize, span: DelimSpan }, + Sequence { forest: Lrc, idx: usize, sep: Option }, } impl Frame { + /// Construct a new frame around the delimited set of tokens. fn new(tts: Vec) -> Frame { - let forest = Lrc::new(quoted::Delimited { delim: token::NoDelim, tts: tts }); - Frame::Delimited { forest: forest, idx: 0, span: DelimSpan::dummy() } + let forest = Lrc::new(quoted::Delimited { delim: token::NoDelim, tts }); + Frame::Delimited { forest, idx: 0, span: DelimSpan::dummy() } } } @@ -54,84 +45,158 @@ impl Iterator for Frame { } } -/// This can do Macro-By-Example transcription. On the other hand, if -/// `src` contains no `TokenTree::{Sequence, MetaVar, MetaVarDecl}`s, `interp` can -/// (and should) be None. -pub fn transcribe(cx: &ExtCtxt<'_>, - interp: Option>>, - src: Vec) - -> TokenStream { +/// This can do Macro-By-Example transcription. +/// - `interp` is a map of meta-variables to the tokens (non-terminals) they matched in the +/// invocation. We are assuming we already know there is a match. +/// - `src` is the RHS of the MBE, that is, the "example" we are filling in. +/// +/// For example, +/// +/// ```rust +/// macro_rules! foo { +/// ($id:ident) => { println!("{}", stringify!($id)); } +/// } +/// +/// foo!(bar); +/// ``` +/// +/// `interp` would contain `$id => bar` and `src` would contain `println!("{}", stringify!($id));`. +/// +/// `transcribe` would return a `TokenStream` containing `println!("{}", stringify!(bar));`. +/// +/// Along the way, we do some additional error checking. +pub fn transcribe( + cx: &ExtCtxt<'_>, + interp: &FxHashMap>, + src: Vec, +) -> TokenStream { + // Nothing for us to transcribe... + if src.is_empty() { + return TokenStream::empty(); + } + + // We descend into the RHS (`src`), expanding things as we go. This stack contains the things + // we have yet to expand/are still expanding. We start the stack off with the whole RHS. let mut stack: SmallVec<[Frame; 1]> = smallvec![Frame::new(src)]; - let interpolations = interp.unwrap_or_else(FxHashMap::default); /* just a convenience */ + + // As we descend in the RHS, we will need to be able to match nested sequences of matchers. + // `repeats` keeps track of where we are in matching at each level, with the last element being + // the most deeply nested sequence. This is used as a stack. let mut repeats = Vec::new(); + + // `result` contains resulting token stream from the TokenTree we just finished processing. At + // the end, this will contain the full result of transcription, but at arbitrary points during + // `transcribe`, `result` will contain subsets of the final result. + // + // Specifically, as we descend into each TokenTree, we will push the existing results onto the + // `result_stack` and clear `results`. We will then produce the results of transcribing the + // TokenTree into `results`. Then, as we unwind back out of the `TokenTree`, we will pop the + // `result_stack` and append `results` too it to produce the new `results` up to that point. + // + // Thus, if we try to pop the `result_stack` and it is empty, we have reached the top-level + // again, and we are done transcribing. let mut result: Vec = Vec::new(); let mut result_stack = Vec::new(); loop { + // Look at the last frame on the stack. let tree = if let Some(tree) = stack.last_mut().unwrap().next() { + // If it still has a TokenTree we have not looked at yet, use that tree. tree - } else { - if let Frame::Sequence { ref mut idx, ref sep, .. } = *stack.last_mut().unwrap() { - let (ref mut repeat_idx, repeat_len) = *repeats.last_mut().unwrap(); + } + // The else-case never produces a value for `tree` (it `continue`s or `return`s). + else { + // Otherwise, if we have just reached the end of a sequence and we can keep repeating, + // go back to the beginning of the sequence. + if let Frame::Sequence { idx, sep, .. } = stack.last_mut().unwrap() { + let (repeat_idx, repeat_len) = repeats.last_mut().unwrap(); *repeat_idx += 1; - if *repeat_idx < repeat_len { + if repeat_idx < repeat_len { *idx = 0; - if let Some(sep) = sep.clone() { - // repeat same span, I guess - let prev_span = match result.last() { - Some((tt, _)) => tt.span(), - None => DUMMY_SP, - }; - result.push(TokenTree::Token(prev_span, sep).into()); + if let Some(sep) = sep { + result.push(TokenTree::Token(sep.clone()).into()); } - continue + continue; } } + // We are done with the top of the stack. Pop it. Depending on what it was, we do + // different things. Note that the outermost item must be the delimited, wrapped RHS + // that was passed in originally to `transcribe`. match stack.pop().unwrap() { + // Done with a sequence. Pop from repeats. Frame::Sequence { .. } => { repeats.pop(); } + + // We are done processing a Delimited. If this is the top-level delimited, we are + // done. Otherwise, we unwind the result_stack to append what we have produced to + // any previous results. Frame::Delimited { forest, span, .. } => { if result_stack.is_empty() { + // No results left to compute! We are back at the top-level. return TokenStream::new(result); } - let tree = TokenTree::Delimited( - span, - forest.delim, - TokenStream::new(result).into(), - ); + + // Step back into the parent Delimited. + let tree = + TokenTree::Delimited(span, forest.delim, TokenStream::new(result).into()); result = result_stack.pop().unwrap(); result.push(tree.into()); } } - continue + continue; }; + // At this point, we know we are in the middle of a TokenTree (the last one on `stack`). + // `tree` contains the next `TokenTree` to be processed. match tree { - quoted::TokenTree::Sequence(sp, seq) => { - // FIXME(pcwalton): Bad copy. - match lockstep_iter_size("ed::TokenTree::Sequence(sp, seq.clone()), - &interpolations, - &repeats) { + // We are descending into a sequence. We first make sure that the matchers in the RHS + // and the matches in `interp` have the same shape. Otherwise, either the caller or the + // macro writer has made a mistake. + seq @ quoted::TokenTree::Sequence(..) => { + match lockstep_iter_size(&seq, interp, &repeats) { LockstepIterSize::Unconstrained => { - cx.span_fatal(sp.entire(), /* blame macro writer */ - "attempted to repeat an expression \ - containing no syntax \ - variables matched as repeating at this depth"); + cx.span_fatal( + seq.span(), /* blame macro writer */ + "attempted to repeat an expression containing no syntax variables \ + matched as repeating at this depth", + ); } + LockstepIterSize::Contradiction(ref msg) => { - // FIXME #2887 blame macro invoker instead - cx.span_fatal(sp.entire(), &msg[..]); + // FIXME: this really ought to be caught at macro definition time... It + // happens when two meta-variables are used in the same repetition in a + // sequence, but they come from different sequence matchers and repeat + // different amounts. + cx.span_fatal(seq.span(), &msg[..]); } + LockstepIterSize::Constraint(len, _) => { + // We do this to avoid an extra clone above. We know that this is a + // sequence already. + let (sp, seq) = if let quoted::TokenTree::Sequence(sp, seq) = seq { + (sp, seq) + } else { + unreachable!() + }; + + // Is the repetition empty? if len == 0 { if seq.op == quoted::KleeneOp::OneOrMore { - // FIXME #2887 blame invoker + // FIXME: this really ought to be caught at macro definition + // time... It happens when the Kleene operator in the matcher and + // the body for the same meta-variable do not match. cx.span_fatal(sp.entire(), "this must repeat at least once"); } } else { + // 0 is the initial counter (we have done 0 repretitions so far). `len` + // is the total number of reptitions we should generate. repeats.push((0, len)); + + // The first time we encounter the sequence we push it to the stack. It + // then gets reused (see the beginning of the loop) until we are done + // repeating. stack.push(Frame::Sequence { idx: 0, sep: seq.separator.clone(), @@ -141,49 +206,78 @@ pub fn transcribe(cx: &ExtCtxt<'_>, } } } - // FIXME #2887: think about span stuff here + + // Replace the meta-var with the matched token tree from the invocation. quoted::TokenTree::MetaVar(mut sp, ident) => { - if let Some(cur_matched) = lookup_cur_matched(ident, &interpolations, &repeats) { + // Find the matched nonterminal from the macro invocation, and use it to replace + // the meta-var. + if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { if let MatchedNonterminal(ref nt) = *cur_matched { + // FIXME #2887: why do we apply a mark when matching a token tree meta-var + // (e.g. `$x:tt`), but not when we are matching any other type of token + // tree? if let NtTT(ref tt) = **nt { result.push(tt.clone().into()); } else { sp = sp.apply_mark(cx.current_expansion.mark); - let token = TokenTree::Token(sp, Token::Interpolated(nt.clone())); + let token = TokenTree::token(token::Interpolated(nt.clone()), sp); result.push(token.into()); } } else { - cx.span_fatal(sp, /* blame the macro writer */ - &format!("variable '{}' is still repeating at this depth", ident)); + // We were unable to descend far enough. This is an error. + cx.span_fatal( + sp, /* blame the macro writer */ + &format!("variable '{}' is still repeating at this depth", ident), + ); } } else { + // If we aren't able to match the meta-var, we push it back into the result but + // with modified syntax context. (I believe this supports nested macros). let ident = Ident::new(ident.name, ident.span.apply_mark(cx.current_expansion.mark)); sp = sp.apply_mark(cx.current_expansion.mark); - result.push(TokenTree::Token(sp, token::Dollar).into()); - result.push(TokenTree::Token(sp, token::Token::from_ast_ident(ident)).into()); + result.push(TokenTree::token(token::Dollar, sp).into()); + result.push(TokenTree::Token(Token::from_ast_ident(ident)).into()); } } + + // If we are entering a new delimiter, we push its contents to the `stack` to be + // processed, and we push all of the currently produced results to the `result_stack`. + // We will produce all of the results of the inside of the `Delimited` and then we will + // jump back out of the Delimited, pop the result_stack and add the new results back to + // the previous results (from outside the Delimited). quoted::TokenTree::Delimited(mut span, delimited) => { span = span.apply_mark(cx.current_expansion.mark); - stack.push(Frame::Delimited { forest: delimited, idx: 0, span: span }); + stack.push(Frame::Delimited { forest: delimited, idx: 0, span }); result_stack.push(mem::replace(&mut result, Vec::new())); } - quoted::TokenTree::Token(sp, tok) => { + + // Nothing much to do here. Just push the token to the result, being careful to + // preserve syntax context. + quoted::TokenTree::Token(token) => { let mut marker = Marker(cx.current_expansion.mark); - let mut tt = TokenTree::Token(sp, tok); + let mut tt = TokenTree::Token(token); noop_visit_tt(&mut tt, &mut marker); result.push(tt.into()); } + + // There should be no meta-var declarations in the invocation of a macro. quoted::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"), } } } -fn lookup_cur_matched(ident: Ident, - interpolations: &FxHashMap>, - repeats: &[(usize, usize)]) - -> Option> { +/// Lookup the meta-var named `ident` and return the matched token tree from the invocation using +/// the set of matches `interpolations`. +/// +/// See the definition of `repeats` in the `transcribe` function. `repeats` is used to descend +/// into the right place in nested matchers. If we attempt to descend too far, the macro writer has +/// made a mistake, and we return `None`. +fn lookup_cur_matched( + ident: Ident, + interpolations: &FxHashMap>, + repeats: &[(usize, usize)], +) -> Option> { interpolations.get(&ident).map(|matched| { let mut matched = matched.clone(); for &(idx, _) in repeats { @@ -198,17 +292,30 @@ fn lookup_cur_matched(ident: Ident, }) } +/// An accumulator over a TokenTree to be used with `fold`. During transcription, we need to make +/// sure that the size of each sequence and all of its nested sequences are the same as the sizes +/// of all the matched (nested) sequences in the macro invocation. If they don't match, somebody +/// has made a mistake (either the macro writer or caller). #[derive(Clone)] enum LockstepIterSize { + /// No constraints on length of matcher. This is true for any TokenTree variants except a + /// `MetaVar` with an actual `MatchedSeq` (as opposed to a `MatchedNonterminal`). Unconstrained, + + /// A `MetaVar` with an actual `MatchedSeq`. The length of the match and the name of the + /// meta-var are returned. Constraint(usize, Ident), + + /// Two `Constraint`s on the same sequence had different lengths. This is an error. Contradiction(String), } -impl Add for LockstepIterSize { - type Output = LockstepIterSize; - - fn add(self, other: LockstepIterSize) -> LockstepIterSize { +impl LockstepIterSize { + /// Find incompatibilities in matcher/invocation sizes. + /// - `Unconstrained` is compatible with everything. + /// - `Contradiction` is incompatible with everything. + /// - `Constraint(len)` is only compatible with other constraints of the same length. + fn with(self, other: LockstepIterSize) -> LockstepIterSize { match self { LockstepIterSize::Unconstrained => other, LockstepIterSize::Contradiction(_) => self, @@ -217,9 +324,10 @@ impl Add for LockstepIterSize { LockstepIterSize::Contradiction(_) => other, LockstepIterSize::Constraint(r_len, _) if l_len == r_len => self, LockstepIterSize::Constraint(r_len, r_id) => { - let msg = format!("inconsistent lockstep iteration: \ - '{}' has {} items, but '{}' has {}", - l_id, l_len, r_id, r_len); + let msg = format!( + "meta-variable `{}` repeats {} times, but `{}` repeats {} times", + l_id, l_len, r_id, r_len + ); LockstepIterSize::Contradiction(msg) } }, @@ -227,30 +335,38 @@ impl Add for LockstepIterSize { } } -fn lockstep_iter_size(tree: "ed::TokenTree, - interpolations: &FxHashMap>, - repeats: &[(usize, usize)]) - -> LockstepIterSize { +/// Given a `tree`, make sure that all sequences have the same length as the matches for the +/// appropriate meta-vars in `interpolations`. +/// +/// Note that if `repeats` does not match the exact correct depth of a meta-var, +/// `lookup_cur_matched` will return `None`, which is why this still works even in the presnece of +/// multiple nested matcher sequences. +fn lockstep_iter_size( + tree: "ed::TokenTree, + interpolations: &FxHashMap>, + repeats: &[(usize, usize)], +) -> LockstepIterSize { use quoted::TokenTree; match *tree { TokenTree::Delimited(_, ref delimed) => { delimed.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| { - size + lockstep_iter_size(tt, interpolations, repeats) + size.with(lockstep_iter_size(tt, interpolations, repeats)) }) - }, + } TokenTree::Sequence(_, ref seq) => { seq.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| { - size + lockstep_iter_size(tt, interpolations, repeats) + size.with(lockstep_iter_size(tt, interpolations, repeats)) }) - }, - TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => + } + TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => { match lookup_cur_matched(name, interpolations, repeats) { Some(matched) => match *matched { MatchedNonterminal(_) => LockstepIterSize::Unconstrained, MatchedSeq(ref ads, _) => LockstepIterSize::Constraint(ads.len(), name), }, - _ => LockstepIterSize::Unconstrained - }, + _ => LockstepIterSize::Unconstrained, + } + } TokenTree::Token(..) => LockstepIterSize::Unconstrained, } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1c0b931b289c2..e6a09e7f873ea 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -15,21 +15,26 @@ use AttributeType::*; use AttributeGate::*; -use crate::ast::{self, NodeId, GenericParam, GenericParamKind, PatKind, RangeEnd}; +use crate::ast::{ + self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, + PatKind, RangeEnd, +}; use crate::attr; use crate::early_buffered_lints::BufferedEarlyLintId; use crate::source_map::Spanned; use crate::edition::{ALL_EDITIONS, Edition}; use crate::visit::{self, FnKind, Visitor}; use crate::parse::{token, ParseSess}; -use crate::symbol::Symbol; +use crate::parse::parser::Parser; +use crate::symbol::{Symbol, sym}; use crate::tokenstream::TokenTree; -use errors::{DiagnosticBuilder, Handler}; +use errors::{Applicability, DiagnosticBuilder, Handler}; use rustc_data_structures::fx::FxHashMap; use rustc_target::spec::abi::Abi; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use log::debug; +use lazy_static::lazy_static; use std::env; @@ -47,8 +52,8 @@ macro_rules! declare_features { /// Represents active features that are currently being implemented or /// currently being considered for addition/removal. const ACTIVE_FEATURES: - &[(&str, &str, Option, Option, fn(&mut Features, Span))] = - &[$((stringify!($feature), $ver, $issue, $edition, set!($feature))),+]; + &[(Symbol, &str, Option, Option, fn(&mut Features, Span))] = + &[$((sym::$feature, $ver, $issue, $edition, set!($feature))),+]; /// A set of features to be used by later passes. #[derive(Clone)] @@ -79,22 +84,22 @@ macro_rules! declare_features { ($((removed, $feature: ident, $ver: expr, $issue: expr, None, $reason: expr),)+) => { /// Represents unstable features which have since been removed (it was once Active) - const REMOVED_FEATURES: &[(&str, &str, Option, Option<&str>)] = &[ - $((stringify!($feature), $ver, $issue, $reason)),+ + const REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ + $((sym::$feature, $ver, $issue, $reason)),+ ]; }; ($((stable_removed, $feature: ident, $ver: expr, $issue: expr, None),)+) => { /// Represents stable features which have since been removed (it was once Accepted) - const STABLE_REMOVED_FEATURES: &[(&str, &str, Option, Option<&str>)] = &[ - $((stringify!($feature), $ver, $issue, None)),+ + const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ + $((sym::$feature, $ver, $issue, None)),+ ]; }; ($((accepted, $feature: ident, $ver: expr, $issue: expr, None),)+) => { /// Those language feature has since been Accepted (it was once Active) - const ACCEPTED_FEATURES: &[(&str, &str, Option, Option<&str>)] = &[ - $((stringify!($feature), $ver, $issue, None)),+ + const ACCEPTED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ + $((sym::$feature, $ver, $issue, None)),+ ]; } } @@ -107,124 +112,231 @@ macro_rules! declare_features { // was set. This is most important for knowing when a particular feature became // stable (active). // +// Note that the features are grouped into internal/user-facing and then +// sorted by version inside those groups. This is inforced with tidy. +// // N.B., `tools/tidy/src/features.rs` parses this information directly out of the // source, so take care when modifying it. declare_features! ( - (active, asm, "1.0.0", Some(29722), None), - (active, concat_idents, "1.0.0", Some(29599), None), - (active, link_args, "1.0.0", Some(29596), None), - (active, log_syntax, "1.0.0", Some(29598), None), - (active, non_ascii_idents, "1.0.0", Some(55467), None), - (active, plugin_registrar, "1.0.0", Some(29597), None), - (active, thread_local, "1.0.0", Some(29594), None), - (active, trace_macros, "1.0.0", Some(29598), None), + // ------------------------------------------------------------------------- + // feature-group-start: internal feature gates + // ------------------------------------------------------------------------- - // rustc internal, for now + // no-tracking-issue-start + + // Allows using the `rust-intrinsic`'s "ABI". (active, intrinsics, "1.0.0", None, None), + + // Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. (active, lang_items, "1.0.0", None, None), - (active, format_args_nl, "1.29.0", None, None), - (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), - (active, linkage, "1.0.0", Some(29603), None), + // Allows using the `#[stable]` and `#[unstable]` attributes. + (active, staged_api, "1.0.0", None, None), + + // Allows using `#[allow_internal_unstable]`. This is an + // attribute on `macro_rules!` and can't use the attribute handling + // below (it has to be checked before expansion possibly makes + // macros disappear). + (active, allow_internal_unstable, "1.0.0", None, None), + + // Allows using `#[allow_internal_unsafe]`. This is an + // attribute on `macro_rules!` and can't use the attribute handling + // below (it has to be checked before expansion possibly makes + // macros disappear). + (active, allow_internal_unsafe, "1.0.0", None, None), - // rustc internal + // Allows using the macros: + // + `__diagnostic_used` + // + `__register_diagnostic` + // +`__build_diagnostic_array` (active, rustc_diagnostic_macros, "1.0.0", None, None), + + // Allows using `#[rustc_const_unstable(feature = "foo", ..)]` which + // lets a function to be `const` when opted into with `#![feature(foo)]`. (active, rustc_const_unstable, "1.0.0", None, None), + + // no-tracking-issue-end + + // Allows using `#[link_name="llvm.*"]`. + (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), + + // Allows using `rustc_*` attributes (RFC 572). + (active, rustc_attrs, "1.0.0", Some(29642), None), + + // Allows using `#[on_unimplemented(..)]` on traits. + (active, on_unimplemented, "1.0.0", Some(29628), None), + + // Allows using the `box $expr` syntax. (active, box_syntax, "1.0.0", Some(49733), None), - (active, unboxed_closures, "1.0.0", Some(29625), None), - (active, fundamental, "1.0.0", Some(29635), None), + // Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls. (active, main, "1.0.0", Some(29634), None), - (active, needs_allocator, "1.4.0", Some(27389), None), - (active, on_unimplemented, "1.0.0", Some(29628), None), - (active, plugin, "1.0.0", Some(29597), None), - (active, simd_ffi, "1.0.0", Some(27731), None), + + // Allows using `#[start]` on a function indicating that it is the program entrypoint. (active, start, "1.0.0", Some(29633), None), - (active, structural_match, "1.8.0", Some(31434), None), - (active, panic_runtime, "1.10.0", Some(32837), None), - (active, needs_panic_runtime, "1.10.0", Some(32837), None), - // Features specific to OIBIT (auto traits) - (active, optin_builtin_traits, "1.0.0", Some(13231), None), + // Allows using the `#[fundamental]` attribute. + (active, fundamental, "1.0.0", Some(29635), None), - // Allows `#[staged_api]`. - // - // rustc internal - (active, staged_api, "1.0.0", None, None), + // Allows using the `rust-call` ABI. + (active, unboxed_closures, "1.0.0", Some(29625), None), - // Allows `#![no_core]`. - (active, no_core, "1.3.0", Some(29639), None), + // Allows using the `#[linkage = ".."]` attribute. + (active, linkage, "1.0.0", Some(29603), None), + + // Allows features specific to OIBIT (auto traits). + (active, optin_builtin_traits, "1.0.0", Some(13231), None), - // Allows the use of `box` in patterns (RFC 469). + // Allows using `box` in patterns (RFC 469). (active, box_patterns, "1.0.0", Some(29641), None), - // Allows the use of the `unsafe_destructor_blind_to_params` attribute (RFC 1238). + // no-tracking-issue-start + + // Allows using `#[prelude_import]` on glob `use` items. + (active, prelude_import, "1.2.0", None, None), + + // no-tracking-issue-end + + // Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). (active, dropck_parametricity, "1.3.0", Some(28498), None), + // no-tracking-issue-start + + // Allows using `#[omit_gdb_pretty_printer_section]`. + (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), + + // Allows using the `vectorcall` ABI. + (active, abi_vectorcall, "1.7.0", None, None), + + // no-tracking-issue-end + + // Allows using `#[structural_match]` which indicates that a type is structurally matchable. + (active, structural_match, "1.8.0", Some(31434), None), + // Allows using the `may_dangle` attribute (RFC 1327). (active, dropck_eyepatch, "1.10.0", Some(34761), None), - // Allows the use of custom attributes (RFC 572). - (active, custom_attribute, "1.0.0", Some(29642), None), + // Allows using the `#![panic_runtime]` attribute. + (active, panic_runtime, "1.10.0", Some(32837), None), - // Allows the use of `rustc_*` attributes (RFC 572). - (active, rustc_attrs, "1.0.0", Some(29642), None), + // Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. + (active, needs_panic_runtime, "1.10.0", Some(32837), None), - // Allows the use of non lexical lifetimes (RFC 2094). - (active, nll, "1.0.0", Some(43234), None), + // no-tracking-issue-start - // Allows the use of `#[allow_internal_unstable]`. This is an - // attribute on `macro_rules!` and can't use the attribute handling - // below (it has to be checked before expansion possibly makes - // macros disappear). - // - // rustc internal - (active, allow_internal_unstable, "1.0.0", None, None), + // Allows identifying the `compiler_builtins` crate. + (active, compiler_builtins, "1.13.0", None, None), - // Allows the use of `#[allow_internal_unsafe]`. This is an - // attribute on `macro_rules!` and can't use the attribute handling - // below (it has to be checked before expansion possibly makes - // macros disappear). - // - // rustc internal - (active, allow_internal_unsafe, "1.0.0", None, None), + // Allows using the `unadjusted` ABI; perma-unstable. + (active, abi_unadjusted, "1.16.0", None, None), - // Allows the use of slice patterns (issue #23121). - (active, slice_patterns, "1.0.0", Some(23121), None), + // Allows identifying crates that contain sanitizer runtimes. + (active, sanitizer_runtime, "1.17.0", None, None), - // Allows the definition of `const` functions with some advanced features. - (active, const_fn, "1.2.0", Some(57563), None), + // Used to identify crates that contain the profiler runtime. + (active, profiler_runtime, "1.18.0", None, None), - // Allows accessing fields of unions inside `const` functions. - (active, const_fn_union, "1.27.0", Some(51909), None), + // Allows using the `thiscall` ABI. + (active, abi_thiscall, "1.19.0", None, None), - // Allows casting raw pointers to `usize` during const eval. - (active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None), + // Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. + (active, allocator_internals, "1.20.0", None, None), - // Allows dereferencing raw pointers during const eval. - (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), + // Allows using the `format_args_nl` macro. + (active, format_args_nl, "1.29.0", None, None), - // Allows reinterpretation of the bits of a value of one type as another type during const eval. - (active, const_transmute, "1.29.0", Some(53605), None), + // no-tracking-issue-end - // Allows comparing raw pointers during const eval. - (active, const_compare_raw_pointers, "1.27.0", Some(53020), None), + // Added for testing E0705; perma-unstable. + (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)), - // Allows panicking during const eval (producing compile-time errors). - (active, const_panic, "1.30.0", Some(51999), None), + // ------------------------------------------------------------------------- + // feature-group-end: internal feature gates + // ------------------------------------------------------------------------- - // Allows using `#[prelude_import]` on glob `use` items. - // - // rustc internal - (active, prelude_import, "1.2.0", None, None), + // ------------------------------------------------------------------------- + // feature-group-start: actual feature gates (target features) + // ------------------------------------------------------------------------- - // Allows default type parameters to influence type inference. - (active, default_type_parameter_fallback, "1.3.0", Some(27336), None), + // FIXME: Document these and merge with the list below. + + // Unstable `#[target_feature]` directives. + (active, arm_target_feature, "1.27.0", Some(44839), None), + (active, aarch64_target_feature, "1.27.0", Some(44839), None), + (active, hexagon_target_feature, "1.27.0", Some(44839), None), + (active, powerpc_target_feature, "1.27.0", Some(44839), None), + (active, mips_target_feature, "1.27.0", Some(44839), None), + (active, avx512_target_feature, "1.27.0", Some(44839), None), + (active, mmx_target_feature, "1.27.0", Some(44839), None), + (active, sse4a_target_feature, "1.27.0", Some(44839), None), + (active, tbm_target_feature, "1.27.0", Some(44839), None), + (active, wasm_target_feature, "1.30.0", Some(44839), None), + (active, adx_target_feature, "1.32.0", Some(44839), None), + (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None), + (active, movbe_target_feature, "1.34.0", Some(44839), None), + (active, rtm_target_feature, "1.35.0", Some(44839), None), + (active, f16c_target_feature, "1.36.0", Some(44839), None), + + // ------------------------------------------------------------------------- + // feature-group-end: actual feature gates (target features) + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: actual feature gates + // ------------------------------------------------------------------------- + + // Allows using `asm!` macro with which inline assembly can be embedded. + (active, asm, "1.0.0", Some(29722), None), + + // Allows using the `concat_idents!` macro with which identifiers can be concatenated. + (active, concat_idents, "1.0.0", Some(29599), None), + + // Allows using the `#[link_args]` attribute. + (active, link_args, "1.0.0", Some(29596), None), + + // Allows defining identifiers beyond ASCII. + (active, non_ascii_idents, "1.0.0", Some(55467), None), + + // Allows using `#[plugin_registrar]` on functions. + (active, plugin_registrar, "1.0.0", Some(29597), None), + + // Allows using `#![plugin(myplugin)]`. + (active, plugin, "1.0.0", Some(29597), None), + + // Allows using `#[thread_local]` on `static` items. + (active, thread_local, "1.0.0", Some(29594), None), + + // Allows using the `log_syntax!` macro. + (active, log_syntax, "1.0.0", Some(29598), None), + + // Allows using the `trace_macros!` macro. + (active, trace_macros, "1.0.0", Some(29598), None), + + // Allows the use of SIMD types in functions declared in `extern` blocks. + (active, simd_ffi, "1.0.0", Some(27731), None), + + // Allows using custom attributes (RFC 572). + (active, custom_attribute, "1.0.0", Some(29642), None), + + // Allows using non lexical lifetimes (RFC 2094). + (active, nll, "1.0.0", Some(43234), None), + + // Allows using slice patterns. + (active, slice_patterns, "1.0.0", Some(23121), None), + + // Allows the definition of `const` functions with some advanced features. + (active, const_fn, "1.2.0", Some(57563), None), // Allows associated type defaults. (active, associated_type_defaults, "1.2.0", Some(29661), None), + // Allows `#![no_core]`. + (active, no_core, "1.3.0", Some(29639), None), + + // Allows default type parameters to influence type inference. + (active, default_type_parameter_fallback, "1.3.0", Some(27336), None), + // Allows `repr(simd)` and importing the various simd intrinsics. (active, repr_simd, "1.4.0", Some(27731), None), @@ -236,17 +348,9 @@ declare_features! ( // Permits specifying whether a function should permit unwinding or abort on unwind. (active, unwind_attributes, "1.4.0", Some(58760), None), - // Allows the use of `#[naked]` on functions. - (active, naked_functions, "1.9.0", Some(32408), None), - // Allows `#[no_debug]`. (active, no_debug, "1.5.0", Some(29721), None), - // Allows `#[omit_gdb_pretty_printer_section]`. - // - // rustc internal - (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), - // Allows attributes on expressions and non-item statements. (active, stmt_expr_attributes, "1.6.0", Some(15701), None), @@ -256,19 +360,19 @@ declare_features! ( // Allows `cfg(target_thread_local)`. (active, cfg_target_thread_local, "1.7.0", Some(29594), None), - // rustc internal - (active, abi_vectorcall, "1.7.0", None, None), - - // Allows `X..Y` patterns. - (active, exclusive_range_pattern, "1.11.0", Some(37854), None), - - // impl specialization (RFC 1210) + // Allows specialization of implementations (RFC 1210). (active, specialization, "1.7.0", Some(31844), None), + // Allows using `#[naked]` on functions. + (active, naked_functions, "1.9.0", Some(32408), None), + // Allows `cfg(target_has_atomic = "...")`. (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), - // The `!` type. Does not imply 'exhaustive_patterns' (below) any more. + // Allows `X..Y` patterns. + (active, exclusive_range_pattern, "1.11.0", Some(37854), None), + + // Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. (active, never_type, "1.13.0", Some(35121), None), // Allows exhaustive pattern matching on types that contain uninhabited types. @@ -277,206 +381,218 @@ declare_features! ( // Allows untagged unions `union U { ... }`. (active, untagged_unions, "1.13.0", Some(32836), None), - // Used to identify the `compiler_builtins` crate. - // - // rustc internal. - (active, compiler_builtins, "1.13.0", None, None), - // Allows `#[link(..., cfg(..))]`. (active, link_cfg, "1.14.0", Some(37406), None), // Allows `extern "ptx-*" fn()`. (active, abi_ptx, "1.15.0", Some(38788), None), - // The `repr(i128)` annotation for enums. + // Allows the `#[repr(i128)]` attribute for enums. (active, repr128, "1.16.0", Some(35118), None), - // Allows the use of `#[ffi_returns_twice]` on foreign functions. - (active, ffi_returns_twice, "1.34.0", Some(58314), None), - - // The `unadjusted` ABI; perma-unstable. - // - // rustc internal - (active, abi_unadjusted, "1.16.0", None, None), - - // Declarative macros 2.0 (`macro`). - (active, decl_macro, "1.17.0", Some(39412), None), - // Allows `#[link(kind="static-nobundle"...)]`. (active, static_nobundle, "1.16.0", Some(37403), None), // Allows `extern "msp430-interrupt" fn()`. (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), - // Used to identify crates that contain sanitizer runtimes. - // - // rustc internal - (active, sanitizer_runtime, "1.17.0", None, None), - - // Used to identify crates that contain the profiler runtime. - // - // rustc internal - (active, profiler_runtime, "1.18.0", None, None), + // Allows declarative macros 2.0 (`macro`). + (active, decl_macro, "1.17.0", Some(39412), None), // Allows `extern "x86-interrupt" fn()`. (active, abi_x86_interrupt, "1.17.0", Some(40180), None), - // Allows the `try {...}` expression. - (active, try_blocks, "1.29.0", Some(31436), None), - // Allows module-level inline assembly by way of `global_asm!()`. (active, global_asm, "1.18.0", Some(35119), None), // Allows overlapping impls of marker traits. (active, overlapping_marker_traits, "1.18.0", Some(29864), None), - // Trait attribute to allow overlapping impls. - (active, marker_trait_attr, "1.30.0", Some(29864), None), - - // rustc internal - (active, abi_thiscall, "1.19.0", None, None), - // Allows a test to fail without failing the whole suite. (active, allow_fail, "1.19.0", Some(46488), None), // Allows unsized tuple coercion. (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), - // Generators + // Allows defining generators. (active, generators, "1.21.0", Some(43122), None), - // Trait aliases - (active, trait_alias, "1.24.0", Some(41517), None), - - // rustc internal - (active, allocator_internals, "1.20.0", None, None), - - // `#[doc(cfg(...))]` + // Allows `#[doc(cfg(...))]`. (active, doc_cfg, "1.21.0", Some(43781), None), - // `#[doc(masked)]` + + // Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), - // `#[doc(spotlight)]` + + // Allows `#[doc(spotlight)]`. (active, doc_spotlight, "1.22.0", Some(45040), None), - // `#[doc(include = "some-file")]` + + // Allows `#[doc(include = "some-file")]`. (active, external_doc, "1.22.0", Some(44732), None), - // Future-proofing enums/structs with `#[non_exhaustive]` attribute (RFC 2008). + // Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). (active, non_exhaustive, "1.22.0", Some(44109), None), - // Adds `crate` as visibility modifier, synonymous with `pub(crate)`. + // Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. (active, crate_visibility_modifier, "1.23.0", Some(53120), None), - // extern types + // Allows defining `extern type`s. (active, extern_types, "1.23.0", Some(43467), None), // Allows trait methods with arbitrary self types. (active, arbitrary_self_types, "1.23.0", Some(44874), None), - // In-band lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). + // Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). (active, in_band_lifetimes, "1.23.0", Some(44524), None), - // Generic associated types (RFC 1598) + // Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). (active, generic_associated_types, "1.23.0", Some(44265), None), - // Infer static outlives requirements (RFC 2093). + // Allows defining `trait X = A + B;` alias items. + (active, trait_alias, "1.24.0", Some(41517), None), + + // Allows infering `'static` outlives requirements (RFC 2093). (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), // Allows macro invocations in `extern {}` blocks. (active, macros_in_extern, "1.27.0", Some(49476), None), - // `existential type` - (active, existential_type, "1.28.0", Some(34511), None), + // Allows accessing fields of unions inside `const` functions. + (active, const_fn_union, "1.27.0", Some(51909), None), - // unstable `#[target_feature]` directives - (active, arm_target_feature, "1.27.0", Some(44839), None), - (active, aarch64_target_feature, "1.27.0", Some(44839), None), - (active, hexagon_target_feature, "1.27.0", Some(44839), None), - (active, powerpc_target_feature, "1.27.0", Some(44839), None), - (active, mips_target_feature, "1.27.0", Some(44839), None), - (active, avx512_target_feature, "1.27.0", Some(44839), None), - (active, mmx_target_feature, "1.27.0", Some(44839), None), - (active, sse4a_target_feature, "1.27.0", Some(44839), None), - (active, tbm_target_feature, "1.27.0", Some(44839), None), - (active, wasm_target_feature, "1.30.0", Some(44839), None), - (active, adx_target_feature, "1.32.0", Some(44839), None), - (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None), - (active, movbe_target_feature, "1.34.0", Some(44839), None), + // Allows casting raw pointers to `usize` during const eval. + (active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None), - // Allows macro invocations on modules expressions and statements and - // procedural macros to expand to non-items. - (active, proc_macro_hygiene, "1.30.0", Some(54727), None), + // Allows dereferencing raw pointers during const eval. + (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), + + // Allows comparing raw pointers during const eval. + (active, const_compare_raw_pointers, "1.27.0", Some(53020), None), - // `#[doc(alias = "...")]` + // Allows `#[doc(alias = "...")]`. (active, doc_alias, "1.27.0", Some(50146), None), - // inconsistent bounds in where clauses + // Allows defining `existential type`s. + (active, existential_type, "1.28.0", Some(34511), None), + + // Allows inconsistent bounds in where clauses. (active, trivial_bounds, "1.28.0", Some(48214), None), - // `'a: { break 'a; }` + // Allows `'a: { break 'a; }`. (active, label_break_value, "1.28.0", Some(48594), None), - // Exhaustive pattern matching on `usize` and `isize`. - (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), - - // `#[doc(keyword = "...")]` + // Allows using `#[doc(keyword = "...")]`. (active, doc_keyword, "1.28.0", Some(51315), None), // Allows async and await syntax. (active, async_await, "1.28.0", Some(50547), None), - // `#[alloc_error_handler]` + // Allows await! macro-like syntax. + // This will likely be removed prior to stabilization of async/await. + (active, await_macro, "1.28.0", Some(50547), None), + + // Allows reinterpretation of the bits of a value of one type as another type during const eval. + (active, const_transmute, "1.29.0", Some(53605), None), + + // Allows using `try {...}` expressions. + (active, try_blocks, "1.29.0", Some(31436), None), + + // Allows defining an `#[alloc_error_handler]`. (active, alloc_error_handler, "1.29.0", Some(51540), None), + // Allows using the `amdgpu-kernel` ABI. (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), - // Added for testing E0705; perma-unstable. - (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)), + // Allows panicking during const eval (producing compile-time errors). + (active, const_panic, "1.30.0", Some(51999), None), + + // Allows `#[marker]` on certain traits allowing overlapping implementations. + (active, marker_trait_attr, "1.30.0", Some(29864), None), + + // Allows macro invocations on modules expressions and statements and + // procedural macros to expand to non-items. + (active, proc_macro_hygiene, "1.30.0", Some(54727), None), // Allows unsized rvalues at arguments and parameters. (active, unsized_locals, "1.30.0", Some(48055), None), - // `#![test_runner]` - // `#[test_case]` + // Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. (active, custom_test_frameworks, "1.30.0", Some(50297), None), - // non-builtin attributes in inner attribute position + // Allows non-builtin attributes in inner attribute position. (active, custom_inner_attributes, "1.30.0", Some(54726), None), - // Allow mixing of bind-by-move in patterns and references to - // those identifiers in guards, *if* we are using MIR-borrowck - // (aka NLL). Essentially this means you need to be using the - // 2018 edition or later. + // Allows mixing bind-by-move in patterns and references to those identifiers in guards. (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None), // Allows `impl Trait` in bindings (`let`, `const`, `static`). (active, impl_trait_in_bindings, "1.30.0", Some(34511), None), - // Allows `const _: TYPE = VALUE`. - (active, underscore_const_names, "1.31.0", Some(54912), None), - - // Adds `reason` and `expect` lint attributes. + // Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. (active, lint_reasons, "1.31.0", Some(54503), None), - // Allows paths to enum variants on type aliases. - (active, type_alias_enum_variants, "1.31.0", Some(49683), None), + // Allows exhaustive integer pattern matching on `usize` and `isize`. + (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), - // Re-Rebalance coherence + // Allows relaxing the coherence rules such that + // `impl ForeignTrait for ForeignType is permitted. (active, re_rebalance_coherence, "1.32.0", Some(55437), None), - // Const generic types. + // Allows using `#[ffi_returns_twice]` on foreign functions. + (active, ffi_returns_twice, "1.34.0", Some(58314), None), + + // Allows const generic types (e.g. `struct Foo(...);`). (active, const_generics, "1.34.0", Some(44580), None), - // #[optimize(X)] + // Allows using `#[optimize(X)]`. (active, optimize_attribute, "1.34.0", Some(54882), None), - // #[repr(align(X))] on enums - (active, repr_align_enum, "1.34.0", Some(57996), None), - - // Allows the use of C-variadics + // Allows using C-variadics. (active, c_variadic, "1.34.0", Some(44930), None), + + // Allows the user of associated type bounds. + (active, associated_type_bounds, "1.34.0", Some(52662), None), + + // Attributes on formal function params. + (active, param_attrs, "1.36.0", Some(60406), None), + + // Allows calling constructor functions in `const fn`. + (active, const_constructor, "1.37.0", Some(61456), None), + + // Allows `if/while p && let q = r && ...` chains. + (active, let_chains, "1.37.0", Some(53667), None), + + // #[repr(transparent)] on enums. + (active, transparent_enums, "1.37.0", Some(60405), None), + + // #[repr(transparent)] on unions. + (active, transparent_unions, "1.37.0", Some(60405), None), + + // Allows explicit discriminants on non-unit enum variants. + (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), + + // Allows `impl Trait` with multiple unrelated lifetimes. + (active, member_constraints, "1.37.0", Some(61977), None), + + // ------------------------------------------------------------------------- + // feature-group-end: actual feature gates + // ------------------------------------------------------------------------- ); +// Some features are known to be incomplete and using them is likely to have +// unanticipated results, such as compiler crashes. We warn the user about these +// to alert them. +const INCOMPLETE_FEATURES: &[Symbol] = &[ + sym::impl_trait_in_bindings, + sym::generic_associated_types, + sym::const_generics, + sym::let_chains, +]; + declare_features! ( + // ------------------------------------------------------------------------- + // feature-group-start: removed features + // ------------------------------------------------------------------------- + (removed, import_shadowing, "1.0.0", None, None, None), (removed, managed_boxes, "1.0.0", None, None, None), // Allows use of unary negate on unsigned integers, e.g., -e for e: u8 @@ -490,9 +606,7 @@ declare_features! ( (removed, visible_private_types, "1.0.0", None, None, None), (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), // Allows using items which are missing stability attributes - // rustc internal (removed, unmarked_api, "1.0.0", None, None, None), - (removed, pushpop_unsafe, "1.2.0", None, None, None), (removed, allocator, "1.0.0", None, None, None), (removed, simd, "1.0.0", Some(27731), None, Some("removed in favor of `#[repr(simd)]`")), @@ -500,6 +614,9 @@ declare_features! ( Some("merged into `#![feature(slice_patterns)]`")), (removed, macro_reexport, "1.0.0", Some(29638), None, Some("subsumed by `pub use`")), + (removed, pushpop_unsafe, "1.2.0", None, None, None), + (removed, needs_allocator, "1.4.0", Some(27389), None, + Some("subsumed by `#![feature(allocator_internals)]`")), (removed, proc_macro_mod, "1.27.0", Some(54727), None, Some("subsumed by `#![feature(proc_macro_hygiene)]`")), (removed, proc_macro_expr, "1.27.0", Some(54727), None, @@ -511,12 +628,16 @@ declare_features! ( (removed, panic_implementation, "1.28.0", Some(44489), None, Some("subsumed by `#[panic_handler]`")), // Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. - (removed, custom_derive, "1.0.0", Some(29644), None, + (removed, custom_derive, "1.32.0", Some(29644), None, Some("subsumed by `#[proc_macro_derive]`")), // Paths of the form: `extern::foo::bar` (removed, extern_in_paths, "1.33.0", Some(55600), None, Some("subsumed by `::foo::bar` paths")), - (removed, quote, "1.0.0", Some(29601), None, None), + (removed, quote, "1.33.0", Some(29601), None, None), + + // ------------------------------------------------------------------------- + // feature-group-end: removed features + // ------------------------------------------------------------------------- ); declare_features! ( @@ -524,63 +645,85 @@ declare_features! ( ); declare_features! ( - (accepted, associated_types, "1.0.0", None, None), - // Allows overloading augmented assignment operations like `a += b`. - (accepted, augmented_assignments, "1.8.0", Some(28235), None), - // Allows empty structs and enum variants with braces. - (accepted, braced_empty_structs, "1.8.0", Some(29720), None), - // Allows indexing into constant arrays. - (accepted, const_indexing, "1.26.0", Some(29947), None), - (accepted, default_type_params, "1.0.0", None, None), - (accepted, globs, "1.0.0", None, None), - (accepted, if_let, "1.0.0", None, None), + // ------------------------------------------------------------------------- + // feature-group-start: for testing purposes + // ------------------------------------------------------------------------- + // A temporary feature gate used to enable parser extensions needed // to bootstrap fix for #5723. (accepted, issue_5723_bootstrap, "1.0.0", None, None), + // These are used to test this portion of the compiler, + // they don't actually mean anything. + (accepted, test_accepted_feature, "1.0.0", None, None), + + // ------------------------------------------------------------------------- + // feature-group-end: for testing purposes + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: accepted features + // ------------------------------------------------------------------------- + + // Allows using associated `type`s in `trait`s. + (accepted, associated_types, "1.0.0", None, None), + // Allows using assigning a default type to type parameters in algebraic data type definitions. + (accepted, default_type_params, "1.0.0", None, None), + // FIXME: explain `globs`. + (accepted, globs, "1.0.0", None, None), + // Allows `macro_rules!` items. (accepted, macro_rules, "1.0.0", None, None), - // Allows using `#![no_std]`. - (accepted, no_std, "1.6.0", None, None), + // Allows use of `&foo[a..b]` as a slicing syntax. (accepted, slicing_syntax, "1.0.0", None, None), + // Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418). (accepted, struct_variant, "1.0.0", None, None), - // These are used to test this portion of the compiler, they don't actually - // mean anything. - (accepted, test_accepted_feature, "1.0.0", None, None), + // Allows indexing tuples. (accepted, tuple_indexing, "1.0.0", None, None), - // Allows macros to appear in the type position. - (accepted, type_macros, "1.13.0", Some(27245), None), + // Allows the use of `if let` expressions. + (accepted, if_let, "1.0.0", None, None), + // Allows the use of `while let` expressions. (accepted, while_let, "1.0.0", None, None), + // Allows using `#![no_std]`. + (accepted, no_std, "1.6.0", None, None), + // Allows overloading augmented assignment operations like `a += b`. + (accepted, augmented_assignments, "1.8.0", Some(28235), None), + // Allows empty structs and enum variants with braces. + (accepted, braced_empty_structs, "1.8.0", Some(29720), None), // Allows `#[deprecated]` attribute. (accepted, deprecated, "1.9.0", Some(29935), None), - // `expr?` + // Allows macros to appear in the type position. + (accepted, type_macros, "1.13.0", Some(27245), None), + // Allows use of the postfix `?` operator in expressions. (accepted, question_mark, "1.13.0", Some(31436), None), // Allows `..` in tuple (struct) patterns. (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None), + // Allows some increased flexibility in the name resolution rules, + // especially around globs and shadowing (RFC 1560). (accepted, item_like_imports, "1.15.0", Some(35120), None), // Allows using `Self` and associated types in struct expressions and patterns. (accepted, more_struct_aliases, "1.16.0", Some(37544), None), - // elide `'static` lifetimes in `static`s and `const`s. + // Allows elision of `'static` lifetimes in `static`s and `const`s. (accepted, static_in_const, "1.17.0", Some(35897), None), // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. (accepted, field_init_shorthand, "1.17.0", Some(37340), None), // Allows the definition recursive static items. (accepted, static_recursion, "1.17.0", Some(29719), None), - // `pub(restricted)` visibilities (RFC 1422) + // Allows `pub(restricted)` visibilities (RFC 1422). (accepted, pub_restricted, "1.18.0", Some(32409), None), - // `#![windows_subsystem]` + // Allows `#![windows_subsystem]`. (accepted, windows_subsystem, "1.18.0", Some(37499), None), // Allows `break {expr}` with a value inside `loop`s. (accepted, loop_break_value, "1.19.0", Some(37339), None), - // Permits numeric fields in struct expressions and patterns. + // Allows numeric fields in struct expressions and patterns. (accepted, relaxed_adts, "1.19.0", Some(35626), None), - // Coerces non capturing closures to function pointers. + // Allows coercing non capturing closures to function pointers. (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), // Allows attributes on struct literal fields. (accepted, struct_field_attributes, "1.20.0", Some(38814), None), // Allows the definition of associated constants in `trait` or `impl` blocks. (accepted, associated_consts, "1.20.0", Some(29646), None), - // Usage of the `compile_error!` macro. + // Allows usage of the `compile_error!` macro. (accepted, compile_error, "1.20.0", Some(40872), None), - // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. + // Allows code like `let x: &'static u32 = &42` to work (RFC 1414). (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None), // Allows `Drop` types in constants (RFC 1440). (accepted, drop_types_in_const, "1.22.0", Some(33156), None), @@ -591,24 +734,27 @@ declare_features! ( (accepted, repr_align, "1.25.0", Some(33626), None), // Allows '|' at beginning of match arms (RFC 1925). (accepted, match_beginning_vert, "1.25.0", Some(44101), None), - // Nested groups in `use` (RFC 2128) + // Allows nested groups in `use` items (RFC 2128). (accepted, use_nested_groups, "1.25.0", Some(44494), None), - // `a..=b` and `..=b` + // Allows indexing into constant arrays. + (accepted, const_indexing, "1.26.0", Some(29947), None), + // Allows using `a..=b` and `..=b` as inclusive range syntaxes. (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), // Allows `..=` in patterns (RFC 1192). (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), - // Termination trait in main (RFC 1937) + // Allows `fn main()` with return types which implements `Termination` (RFC 1937). (accepted, termination_trait, "1.26.0", Some(43301), None), - // `Copy`/`Clone` closures (RFC 2132). + // Allows implementing `Clone` for closures where possible (RFC 2132). (accepted, clone_closures, "1.26.0", Some(44490), None), + // Allows implementing `Copy` for closures where possible (RFC 2132). (accepted, copy_closures, "1.26.0", Some(44490), None), // Allows `impl Trait` in function arguments. (accepted, universal_impl_trait, "1.26.0", Some(34511), None), // Allows `impl Trait` in function return types. (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), - // The `i128` type + // Allows using the `u128` and `i128` types. (accepted, i128_type, "1.26.0", Some(35118), None), - // Default match binding modes (RFC 2005) + // Allows default match binding modes (RFC 2005). (accepted, match_default_bindings, "1.26.0", Some(42640), None), // Allows `'_` placeholder lifetimes. (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), @@ -618,21 +764,21 @@ declare_features! ( (accepted, cfg_target_feature, "1.27.0", Some(29717), None), // Allows `#[target_feature(...)]`. (accepted, target_feature, "1.27.0", None, None), - // Trait object syntax with `dyn` prefix + // Allows using `dyn Trait` as a syntax for trait objects. (accepted, dyn_trait, "1.27.0", Some(44662), None), // Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940). (accepted, fn_must_use, "1.27.0", Some(43302), None), // Allows use of the `:lifetime` macro fragment specifier. (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None), - // Termination trait in tests (RFC 1937) + // Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). (accepted, termination_trait_test, "1.27.0", Some(48854), None), - // The `#[global_allocator]` attribute + // Allows the `#[global_allocator]` attribute. (accepted, global_allocator, "1.28.0", Some(27389), None), // Allows `#[repr(transparent)]` attribute on newtype structs. (accepted, repr_transparent, "1.28.0", Some(43036), None), - // Procedural macros in `proc-macro` crates + // Allows procedural macros in `proc-macro` crates. (accepted, proc_macro, "1.29.0", Some(38356), None), - // `foo.rs` as an alternative to `foo/mod.rs` + // Allows `foo.rs` as an alternative to `foo/mod.rs`. (accepted, non_modrs_mods, "1.30.0", Some(44660), None), // Allows use of the `:vis` macro fragment specifier (accepted, macro_vis_matcher, "1.30.0", Some(41022), None), @@ -641,47 +787,50 @@ declare_features! ( (accepted, use_extern_macros, "1.30.0", Some(35896), None), // Allows keywords to be escaped for use as identifiers. (accepted, raw_identifiers, "1.30.0", Some(48589), None), - // Attributes scoped to tools. + // Allows attributes scoped to tools. (accepted, tool_attributes, "1.30.0", Some(44690), None), // Allows multi-segment paths in attributes and derives. (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None), // Allows all literals in attribute lists and values of key-value pairs. (accepted, attr_literals, "1.30.0", Some(34981), None), - // Infer outlives requirements (RFC 2093). + // Allows inferring outlives requirements (RFC 2093). (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None), + // Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. + // This defines the behavior of panics. (accepted, panic_handler, "1.30.0", Some(44489), None), - // Used to preserve symbols (see llvm.used). + // Allows `#[used]` to preserve symbols (see llvm.used). (accepted, used, "1.30.0", Some(40289), None), - // `crate` in paths + // Allows `crate` in paths. (accepted, crate_in_paths, "1.30.0", Some(45477), None), - // Resolve absolute paths as paths from other crates. + // Allows resolving absolute paths as paths from other crates. (accepted, extern_absolute_paths, "1.30.0", Some(44660), None), - // Access to crate names passed via `--extern` through prelude. + // Allows access to crate names passed via `--extern` through prelude. (accepted, extern_prelude, "1.30.0", Some(44660), None), - // Parentheses in patterns + // Allows parentheses in patterns. (accepted, pattern_parentheses, "1.31.0", Some(51087), None), // Allows the definition of `const fn` functions. (accepted, min_const_fn, "1.31.0", Some(53555), None), - // Scoped lints + // Allows scoped lints. (accepted, tool_lints, "1.31.0", Some(44690), None), - // `impl Iterator for &mut Iterator` - // `impl Debug for Foo<'_>` + // Allows lifetime elision in `impl` headers. For example: + // + `impl Iterator for &mut Iterator` + // + `impl Debug for Foo<'_>` (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None), - // `extern crate foo as bar;` puts `bar` into extern prelude. + // Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None), // Allows use of the `:literal` macro fragment specifier (RFC 1576). (accepted, macro_literal_matcher, "1.32.0", Some(35625), None), - // Use `?` as the Kleene "at most one" operator. + // Allows use of `?` as the Kleene "at most one" operator in macros. (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None), - // `Self` struct constructor (RFC 2302) + // Allows `Self` struct constructor (RFC 2302). (accepted, self_struct_ctor, "1.32.0", Some(51994), None), - // `Self` in type definitions (RFC 2300) + // Allows `Self` in type definitions (RFC 2300). (accepted, self_in_typedefs, "1.32.0", Some(49303), None), // Allows `use x::y;` to search `x` in the current scope. (accepted, uniform_paths, "1.32.0", Some(53130), None), - // Integer match exhaustiveness checking (RFC 2591) + // Allows integer match exhaustiveness checking (RFC 2591). (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None), - // `use path as _;` and `extern crate c as _;` + // Allows `use path as _;` and `extern crate c as _;`. (accepted, underscore_imports, "1.33.0", Some(48216), None), // Allows `#[repr(packed(N))]` attribute on structs. (accepted, repr_packed, "1.33.0", Some(33158), None), @@ -693,16 +842,28 @@ declare_features! ( // As long as control flow is not implemented in const eval, `&&` and `||` may not be used // at the same time as let bindings. (accepted, const_let, "1.33.0", Some(48821), None), - // `#[cfg_attr(predicate, multiple, attributes, here)]` + // Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. (accepted, cfg_attr_multi, "1.33.0", Some(54881), None), - // Top level or-patterns (`p | q`) in `if let` and `while let`. + // Allows top level or-patterns (`p | q`) in `if let` and `while let`. (accepted, if_while_or_patterns, "1.33.0", Some(48215), None), // Allows `cfg(target_vendor = "...")`. (accepted, cfg_target_vendor, "1.33.0", Some(29718), None), - // `extern crate self as foo;` puts local crate root into extern prelude under name `foo`. + // Allows `extern crate self as foo;`. + // This puts local crate root into extern prelude under name `foo`. (accepted, extern_crate_self, "1.34.0", Some(56409), None), - // support for arbitrary delimited token streams in non-macro attributes + // Allows arbitrary delimited token streams in non-macro attributes. (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None), + // Allows paths to enum variants on type aliases including `Self`. + (accepted, type_alias_enum_variants, "1.37.0", Some(49683), None), + // Allows using `#[repr(align(X))]` on enums with equivalent semantics + // to wrapping an enum in a wrapper struct with `#[repr(align(X))]`. + (accepted, repr_align_enum, "1.37.0", Some(57996), None), + // Allows `const _: TYPE = VALUE`. + (accepted, underscore_const_names, "1.37.0", Some(54912), None), + + // ------------------------------------------------------------------------- + // feature-group-end: accepted features + // ------------------------------------------------------------------------- ); // If you change this, please modify `src/doc/unstable-book` as well. You must @@ -727,7 +888,7 @@ pub enum AttributeType { pub enum AttributeGate { /// Is gated by a given feature gate, reason /// and function to check if enabled - Gated(Stability, &'static str, &'static str, fn(&Features) -> bool), + Gated(Stability, Symbol, &'static str, fn(&Features) -> bool), /// Ungated attribute, can be used on all release channels Ungated, @@ -811,474 +972,588 @@ macro_rules! cfg_fn { }} } -pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, +pub fn deprecated_attributes() -> Vec<&'static (Symbol, AttributeType, AttributeTemplate, AttributeGate)> { BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect() } pub fn is_builtin_attr_name(name: ast::Name) -> bool { - BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, ..)| name == builtin_name) + BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() } pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { - BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, ..)| attr.path == builtin_name) + attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).is_some() } -// Attributes that have a special meaning to rustc or rustdoc -pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, AttributeGate)] = &[ +/// Attributes that have a special meaning to rustc or rustdoc +pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Normal attributes - ("warn", Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated), - ("allow", Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated), - ("forbid", Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated), - ("deny", Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated), - - ("macro_use", Normal, template!(Word, List: "name1, name2, ..."), Ungated), - ("macro_export", Normal, template!(Word, List: "local_inner_macros"), Ungated), - ("plugin_registrar", Normal, template!(Word), Ungated), - - ("cfg", Normal, template!(List: "predicate"), Ungated), - ("cfg_attr", Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated), - ("main", Normal, template!(Word), Ungated), - ("start", Normal, template!(Word), Ungated), - ("repr", Normal, template!(List: "C, packed, ..."), Ungated), - ("path", Normal, template!(NameValueStr: "file"), Ungated), - ("automatically_derived", Normal, template!(Word), Ungated), - ("no_mangle", Normal, template!(Word), Ungated), - ("no_link", Normal, template!(Word), Ungated), - ("derive", Normal, template!(List: "Trait1, Trait2, ..."), Ungated), - ("should_panic", Normal, template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), - Ungated), - ("ignore", Normal, template!(Word, NameValueStr: "reason"), Ungated), - ("no_implicit_prelude", Normal, template!(Word), Ungated), - ("reexport_test_harness_main", Normal, template!(NameValueStr: "name"), Ungated), - ("link_args", Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable, - "link_args", + ( + sym::warn, + Normal, + template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + Ungated + ), + ( + sym::allow, + Normal, + template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + Ungated + ), + ( + sym::forbid, + Normal, + template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + Ungated + ), + ( + sym::deny, + Normal, + template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + Ungated + ), + + (sym::macro_use, Normal, template!(Word, List: "name1, name2, ..."), Ungated), + (sym::macro_export, Normal, template!(Word, List: "local_inner_macros"), Ungated), + (sym::plugin_registrar, Normal, template!(Word), Ungated), + + (sym::cfg, Normal, template!(List: "predicate"), Ungated), + (sym::cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated), + (sym::main, Normal, template!(Word), Ungated), + (sym::start, Normal, template!(Word), Ungated), + (sym::repr, Normal, template!(List: "C, packed, ..."), Ungated), + (sym::path, Normal, template!(NameValueStr: "file"), Ungated), + (sym::automatically_derived, Normal, template!(Word), Ungated), + (sym::no_mangle, Whitelisted, template!(Word), Ungated), + (sym::no_link, Normal, template!(Word), Ungated), + (sym::derive, Normal, template!(List: "Trait1, Trait2, ..."), Ungated), + ( + sym::should_panic, + Normal, + template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), + Ungated + ), + (sym::ignore, Normal, template!(Word, NameValueStr: "reason"), Ungated), + (sym::no_implicit_prelude, Normal, template!(Word), Ungated), + (sym::reexport_test_harness_main, Normal, template!(NameValueStr: "name"), Ungated), + (sym::link_args, Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable, + sym::link_args, "the `link_args` attribute is experimental and not \ - portable across platforms, it is recommended to \ - use `#[link(name = \"foo\")] instead", + portable across platforms, it is recommended to \ + use `#[link(name = \"foo\")] instead", cfg_fn!(link_args))), - ("macro_escape", Normal, template!(Word), Ungated), + (sym::macro_escape, Normal, template!(Word), Ungated), // RFC #1445. - ("structural_match", Whitelisted, template!(Word), Gated(Stability::Unstable, - "structural_match", + (sym::structural_match, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::structural_match, "the semantics of constant patterns is \ - not yet settled", + not yet settled", cfg_fn!(structural_match))), // RFC #2008 - ("non_exhaustive", Whitelisted, template!(Word), Gated(Stability::Unstable, - "non_exhaustive", - "non exhaustive is an experimental feature", - cfg_fn!(non_exhaustive))), + (sym::non_exhaustive, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::non_exhaustive, + "non exhaustive is an experimental feature", + cfg_fn!(non_exhaustive))), // RFC #1268 - ("marker", Normal, template!(Word), Gated(Stability::Unstable, - "marker_trait_attr", - "marker traits is an experimental feature", - cfg_fn!(marker_trait_attr))), - - ("plugin", CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable, - "plugin", - "compiler plugins are experimental \ - and possibly buggy", - cfg_fn!(plugin))), - - ("no_std", CrateLevel, template!(Word), Ungated), - ("no_core", CrateLevel, template!(Word), Gated(Stability::Unstable, - "no_core", - "no_core is experimental", - cfg_fn!(no_core))), - ("lang", Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable, - "lang_items", - "language items are subject to change", - cfg_fn!(lang_items))), - ("linkage", Whitelisted, template!(NameValueStr: "external|internal|..."), - Gated(Stability::Unstable, - "linkage", - "the `linkage` attribute is experimental \ + (sym::marker, Normal, template!(Word), Gated(Stability::Unstable, + sym::marker_trait_attr, + "marker traits is an experimental feature", + cfg_fn!(marker_trait_attr))), + + (sym::plugin, CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable, + sym::plugin, + "compiler plugins are experimental \ + and possibly buggy", + cfg_fn!(plugin))), + + (sym::no_std, CrateLevel, template!(Word), Ungated), + (sym::no_core, CrateLevel, template!(Word), Gated(Stability::Unstable, + sym::no_core, + "no_core is experimental", + cfg_fn!(no_core))), + (sym::lang, Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable, + sym::lang_items, + "language items are subject to change", + cfg_fn!(lang_items))), + (sym::linkage, Whitelisted, template!(NameValueStr: "external|internal|..."), + Gated(Stability::Unstable, + sym::linkage, + "the `linkage` attribute is experimental \ and not portable across platforms", - cfg_fn!(linkage))), - ("thread_local", Whitelisted, template!(Word), Gated(Stability::Unstable, - "thread_local", + cfg_fn!(linkage))), + (sym::thread_local, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::thread_local, "`#[thread_local]` is an experimental feature, and does \ - not currently handle destructors.", + not currently handle destructors", cfg_fn!(thread_local))), - ("rustc_on_unimplemented", Normal, template!(List: - r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, - NameValueStr: "message"), - Gated(Stability::Unstable, - "on_unimplemented", - "the `#[rustc_on_unimplemented]` attribute \ - is an experimental feature", - cfg_fn!(on_unimplemented))), - ("rustc_const_unstable", Normal, template!(List: r#"feature = "name""#), - Gated(Stability::Unstable, - "rustc_const_unstable", - "the `#[rustc_const_unstable]` attribute \ - is an internal feature", - cfg_fn!(rustc_const_unstable))), - ("global_allocator", Normal, template!(Word), Ungated), - ("default_lib_allocator", Whitelisted, template!(Word), Gated(Stability::Unstable, - "allocator_internals", + (sym::rustc_on_unimplemented, Whitelisted, template!(List: + r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, + NameValueStr: "message"), + Gated(Stability::Unstable, + sym::on_unimplemented, + "the `#[rustc_on_unimplemented]` attribute \ + is an experimental feature", + cfg_fn!(on_unimplemented))), + (sym::rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), + Gated(Stability::Unstable, + sym::rustc_const_unstable, + "the `#[rustc_const_unstable]` attribute \ + is an internal feature", + cfg_fn!(rustc_const_unstable))), + (sym::global_allocator, Normal, template!(Word), Ungated), + (sym::default_lib_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::allocator_internals, "the `#[default_lib_allocator]` \ - attribute is an experimental feature", + attribute is an experimental feature", cfg_fn!(allocator_internals))), - ("needs_allocator", Normal, template!(Word), Gated(Stability::Unstable, - "allocator_internals", - "the `#[needs_allocator]` \ - attribute is an experimental \ - feature", - cfg_fn!(allocator_internals))), - ("panic_runtime", Whitelisted, template!(Word), Gated(Stability::Unstable, - "panic_runtime", - "the `#[panic_runtime]` attribute is \ - an experimental feature", - cfg_fn!(panic_runtime))), - ("needs_panic_runtime", Whitelisted, template!(Word), Gated(Stability::Unstable, - "needs_panic_runtime", - "the `#[needs_panic_runtime]` \ + (sym::needs_allocator, Normal, template!(Word), Gated(Stability::Unstable, + sym::allocator_internals, + "the `#[needs_allocator]` \ + attribute is an experimental \ + feature", + cfg_fn!(allocator_internals))), + (sym::panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::panic_runtime, + "the `#[panic_runtime]` attribute is \ + an experimental feature", + cfg_fn!(panic_runtime))), + (sym::needs_panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::needs_panic_runtime, + "the `#[needs_panic_runtime]` \ attribute is an experimental \ feature", - cfg_fn!(needs_panic_runtime))), - ("rustc_outlives", Normal, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "the `#[rustc_outlives]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_variance", Normal, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "the `#[rustc_variance]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_layout", Normal, template!(List: "field1, field2, ..."), - Gated(Stability::Unstable, - "rustc_attrs", - "the `#[rustc_layout]` attribute \ + cfg_fn!(needs_panic_runtime))), + (sym::rustc_outlives, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_outlives]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_variance, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_variance]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_layout, Normal, template!(List: "field1, field2, ..."), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_layout]` attribute \ is just used for rustc unit tests \ and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_regions", Normal, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + cfg_fn!(rustc_attrs))), + (sym::rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_layout_scalar_valid_range_start]` attribute \ + is just used to enable niche optimizations in libcore \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_layout_scalar_valid_range_end]` attribute \ + is just used to enable niche optimizations in libcore \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_nonnull_optimization_guaranteed, Whitelisted, template!(Word), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_nonnull_optimization_guaranteed]` attribute \ + is just used to enable niche optimizations in libcore \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_regions, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "the `#[rustc_regions]` attribute \ - is just used for rustc unit tests \ - and will never be stable", + is just used for rustc unit tests \ + and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_error", Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "the `#[rustc_error]` attribute \ + (sym::rustc_error, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_error]` attribute \ is just used for rustc unit tests \ and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_dump_user_substs", Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "this attribute \ + cfg_fn!(rustc_attrs))), + (sym::rustc_dump_user_substs, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "this attribute \ is just used for rustc unit tests \ and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_if_this_changed", Whitelisted, template!(Word, List: "DepNode"), - Gated(Stability::Unstable, - "rustc_attrs", - "the `#[rustc_if_this_changed]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_then_this_would_need", Whitelisted, template!(List: "DepNode"), - Gated(Stability::Unstable, - "rustc_attrs", - "the `#[rustc_if_this_changed]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_dirty", Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", + cfg_fn!(rustc_attrs))), + (sym::rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode"), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_if_this_changed]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_then_this_would_need, Whitelisted, template!(List: "DepNode"), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_if_this_changed]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_dirty, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), - Gated(Stability::Unstable, - "rustc_attrs", - "the `#[rustc_dirty]` attribute \ + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_dirty]` attribute \ is just used for rustc unit tests \ and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_clean", Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", + cfg_fn!(rustc_attrs))), + (sym::rustc_clean, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), - Gated(Stability::Unstable, - "rustc_attrs", - "the `#[rustc_clean]` attribute \ + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_clean]` attribute \ is just used for rustc unit tests \ and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_partition_reused", Whitelisted, template!(List: r#"cfg = "...", module = "...""#), - Gated(Stability::Unstable, - "rustc_attrs", - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_partition_codegened", Whitelisted, template!(List: r#"cfg = "...", module = "...""#), - Gated(Stability::Unstable, - "rustc_attrs", - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_expected_cgu_reuse", Whitelisted, template!(List: r#"cfg = "...", module = "...", - kind = "...""#), + cfg_fn!(rustc_attrs))), + ( + sym::rustc_partition_reused, + Whitelisted, + template!(List: r#"cfg = "...", module = "...""#), + Gated( + Stability::Unstable, + sym::rustc_attrs, + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs) + ) + ), + ( + sym::rustc_partition_codegened, + Whitelisted, + template!(List: r#"cfg = "...", module = "...""#), + Gated( + Stability::Unstable, + sym::rustc_attrs, + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs), + ) + ), + (sym::rustc_expected_cgu_reuse, Whitelisted, template!(List: r#"cfg = "...", module = "...", + kind = "...""#), Gated(Stability::Unstable, - "rustc_attrs", + sym::rustc_attrs, "this attribute \ - is just used for rustc unit tests \ - and will never be stable", + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_synthetic, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_symbol_name, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal rustc attributes will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_def_path, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal rustc attributes will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_mir, Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_mir]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + ( + sym::rustc_inherit_overflow_checks, + Whitelisted, + template!(Word), + Gated( + Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_inherit_overflow_checks]` \ + attribute is just used to control \ + overflow checking behavior of several \ + libcore functions that are inlined \ + across crates and will never be stable", + cfg_fn!(rustc_attrs), + ) + ), + + (sym::rustc_dump_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_dump_program_clauses]` \ + attribute is just used for rustc unit \ + tests and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_synthetic", Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_symbol_name", Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "internal rustc attributes will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_item_path", Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "internal rustc attributes will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_mir", Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable, - "rustc_attrs", - "the `#[rustc_mir]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_inherit_overflow_checks", Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "the `#[rustc_inherit_overflow_checks]` \ - attribute is just used to control \ - overflow checking behavior of several \ - libcore functions that are inlined \ - across crates and will never be stable", - cfg_fn!(rustc_attrs))), - - ("rustc_dump_program_clauses", Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "the `#[rustc_dump_program_clauses]` \ - attribute is just used for rustc unit \ - tests and will never be stable", - cfg_fn!(rustc_attrs))), - ("rustc_test_marker", Normal, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "the `#[rustc_test_marker]` attribute \ - is used internally to track tests", - cfg_fn!(rustc_attrs))), - ("rustc_transparent_macro", Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "used internally for testing macro hygiene", + (sym::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_test_marker]` attribute \ + is used internally to track tests", + cfg_fn!(rustc_attrs))), + (sym::rustc_transparent_macro, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "used internally for testing macro hygiene", cfg_fn!(rustc_attrs))), - ("compiler_builtins", Whitelisted, template!(Word), Gated(Stability::Unstable, - "compiler_builtins", - "the `#[compiler_builtins]` attribute is used to \ - identify the `compiler_builtins` crate which \ - contains compiler-rt intrinsics and will never be \ - stable", - cfg_fn!(compiler_builtins))), - ("sanitizer_runtime", Whitelisted, template!(Word), Gated(Stability::Unstable, - "sanitizer_runtime", - "the `#[sanitizer_runtime]` attribute is used to \ - identify crates that contain the runtime of a \ - sanitizer and will never be stable", - cfg_fn!(sanitizer_runtime))), - ("profiler_runtime", Whitelisted, template!(Word), Gated(Stability::Unstable, - "profiler_runtime", - "the `#[profiler_runtime]` attribute is used to \ - identify the `profiler_builtins` crate which \ - contains the profiler runtime and will never be \ - stable", - cfg_fn!(profiler_runtime))), - - ("allow_internal_unstable", Normal, template!(Word, List: "feat1, feat2, ..."), - Gated(Stability::Unstable, - "allow_internal_unstable", - EXPLAIN_ALLOW_INTERNAL_UNSTABLE, - cfg_fn!(allow_internal_unstable))), - - ("allow_internal_unsafe", Normal, template!(Word), Gated(Stability::Unstable, - "allow_internal_unsafe", + (sym::compiler_builtins, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::compiler_builtins, + "the `#[compiler_builtins]` attribute is used to \ + identify the `compiler_builtins` crate which \ + contains compiler-rt intrinsics and will never be \ + stable", + cfg_fn!(compiler_builtins))), + (sym::sanitizer_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::sanitizer_runtime, + "the `#[sanitizer_runtime]` attribute is used to \ + identify crates that contain the runtime of a \ + sanitizer and will never be stable", + cfg_fn!(sanitizer_runtime))), + (sym::profiler_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::profiler_runtime, + "the `#[profiler_runtime]` attribute is used to \ + identify the `profiler_builtins` crate which \ + contains the profiler runtime and will never be \ + stable", + cfg_fn!(profiler_runtime))), + + (sym::allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), + Gated(Stability::Unstable, + sym::allow_internal_unstable, + EXPLAIN_ALLOW_INTERNAL_UNSTABLE, + cfg_fn!(allow_internal_unstable))), + + (sym::allow_internal_unsafe, Normal, template!(Word), Gated(Stability::Unstable, + sym::allow_internal_unsafe, EXPLAIN_ALLOW_INTERNAL_UNSAFE, cfg_fn!(allow_internal_unsafe))), - ("fundamental", Whitelisted, template!(Word), Gated(Stability::Unstable, - "fundamental", - "the `#[fundamental]` attribute \ + (sym::fundamental, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::fundamental, + "the `#[fundamental]` attribute \ is an experimental feature", - cfg_fn!(fundamental))), + cfg_fn!(fundamental))), + + (sym::proc_macro_derive, Normal, template!(List: "TraitName, \ + /*opt*/ attributes(name1, name2, ...)"), + Ungated), - ("proc_macro_derive", Normal, template!(List: "TraitName, \ - /*opt*/ attributes(name1, name2, ...)"), - Ungated), + (sym::rustc_copy_clone_marker, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal implementation detail", + cfg_fn!(rustc_attrs))), - ("rustc_copy_clone_marker", Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "internal implementation detail", - cfg_fn!(rustc_attrs))), + (sym::rustc_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal implementation detail", + cfg_fn!(rustc_attrs))), + + (sym::rustc_dummy, Normal, template!(Word /* doesn't matter*/), Gated(Stability::Unstable, + sym::rustc_attrs, + "used by the test suite", + cfg_fn!(rustc_attrs))), // FIXME: #14408 whitelist docs since rustdoc looks at them - ("doc", Whitelisted, template!(List: "hidden|inline|...", NameValueStr: "string"), Ungated), + ( + sym::doc, + Whitelisted, + template!(List: "hidden|inline|...", NameValueStr: "string"), + Ungated + ), // FIXME: #14406 these are processed in codegen, which happens after the // lint pass - ("cold", Whitelisted, template!(Word), Ungated), - ("naked", Whitelisted, template!(Word), Gated(Stability::Unstable, - "naked_functions", - "the `#[naked]` attribute \ - is an experimental feature", - cfg_fn!(naked_functions))), - ("ffi_returns_twice", Whitelisted, template!(Word), Gated(Stability::Unstable, - "ffi_returns_twice", - "the `#[ffi_returns_twice]` attribute \ - is an experimental feature", - cfg_fn!(ffi_returns_twice))), - ("target_feature", Whitelisted, template!(List: r#"enable = "name""#), Ungated), - ("export_name", Whitelisted, template!(NameValueStr: "name"), Ungated), - ("inline", Whitelisted, template!(Word, List: "always|never"), Ungated), - ("link", Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", - /*opt*/ cfg = "...""#), Ungated), - ("link_name", Whitelisted, template!(NameValueStr: "name"), Ungated), - ("link_section", Whitelisted, template!(NameValueStr: "name"), Ungated), - ("no_builtins", Whitelisted, template!(Word), Ungated), - ("no_mangle", Whitelisted, template!(Word), Ungated), - ("no_debug", Whitelisted, template!(Word), Gated( + (sym::cold, Whitelisted, template!(Word), Ungated), + (sym::naked, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::naked_functions, + "the `#[naked]` attribute \ + is an experimental feature", + cfg_fn!(naked_functions))), + (sym::ffi_returns_twice, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::ffi_returns_twice, + "the `#[ffi_returns_twice]` attribute \ + is an experimental feature", + cfg_fn!(ffi_returns_twice))), + (sym::target_feature, Whitelisted, template!(List: r#"enable = "name""#), Ungated), + (sym::export_name, Whitelisted, template!(NameValueStr: "name"), Ungated), + (sym::inline, Whitelisted, template!(Word, List: "always|never"), Ungated), + (sym::link, Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", + /*opt*/ cfg = "...""#), Ungated), + (sym::link_name, Whitelisted, template!(NameValueStr: "name"), Ungated), + (sym::link_section, Whitelisted, template!(NameValueStr: "name"), Ungated), + (sym::no_builtins, Whitelisted, template!(Word), Ungated), + (sym::no_debug, Whitelisted, template!(Word), Gated( Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None), - "no_debug", + sym::no_debug, "the `#[no_debug]` attribute was an experimental feature that has been \ - deprecated due to lack of demand", + deprecated due to lack of demand", cfg_fn!(no_debug))), - ("omit_gdb_pretty_printer_section", Whitelisted, template!(Word), Gated(Stability::Unstable, - "omit_gdb_pretty_printer_section", - "the `#[omit_gdb_pretty_printer_section]` \ - attribute is just used for the Rust test \ - suite", - cfg_fn!(omit_gdb_pretty_printer_section))), - ("unsafe_destructor_blind_to_params", - Normal, - template!(Word), - Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761", - Some("replace this attribute with `#[may_dangle]`")), - "dropck_parametricity", - "unsafe_destructor_blind_to_params has been replaced by \ + ( + sym::omit_gdb_pretty_printer_section, + Whitelisted, + template!(Word), + Gated( + Stability::Unstable, + sym::omit_gdb_pretty_printer_section, + "the `#[omit_gdb_pretty_printer_section]` \ + attribute is just used for the Rust test \ + suite", + cfg_fn!(omit_gdb_pretty_printer_section) + ) + ), + (sym::unsafe_destructor_blind_to_params, + Normal, + template!(Word), + Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761", + Some("replace this attribute with `#[may_dangle]`")), + sym::dropck_parametricity, + "unsafe_destructor_blind_to_params has been replaced by \ may_dangle and will be removed in the future", - cfg_fn!(dropck_parametricity))), - ("may_dangle", - Normal, - template!(Word), - Gated(Stability::Unstable, - "dropck_eyepatch", - "may_dangle has unstable semantics and may be removed in the future", - cfg_fn!(dropck_eyepatch))), - ("unwind", Whitelisted, template!(List: "allowed"), Gated(Stability::Unstable, - "unwind_attributes", - "#[unwind] is experimental", - cfg_fn!(unwind_attributes))), - ("used", Whitelisted, template!(Word), Ungated), + cfg_fn!(dropck_parametricity))), + (sym::may_dangle, + Normal, + template!(Word), + Gated(Stability::Unstable, + sym::dropck_eyepatch, + "may_dangle has unstable semantics and may be removed in the future", + cfg_fn!(dropck_eyepatch))), + (sym::unwind, Whitelisted, template!(List: "allowed|aborts"), Gated(Stability::Unstable, + sym::unwind_attributes, + "#[unwind] is experimental", + cfg_fn!(unwind_attributes))), + (sym::used, Whitelisted, template!(Word), Ungated), // used in resolve - ("prelude_import", Whitelisted, template!(Word), Gated(Stability::Unstable, - "prelude_import", - "`#[prelude_import]` is for use by rustc only", - cfg_fn!(prelude_import))), + (sym::prelude_import, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::prelude_import, + "`#[prelude_import]` is for use by rustc only", + cfg_fn!(prelude_import))), // FIXME: #14407 these are only looked at on-demand so we can't // guarantee they'll have already been checked - ("rustc_deprecated", Whitelisted, template!(List: r#"since = "version", reason = "...""#), - Ungated), - ("must_use", Whitelisted, template!(Word, NameValueStr: "reason"), Ungated), - ("stable", Whitelisted, template!(List: r#"feature = "name", since = "version""#), Ungated), - ("unstable", Whitelisted, template!(List: r#"feature = "name", reason = "...", issue = "N""#), - Ungated), - ("deprecated", + ( + sym::rustc_deprecated, + Whitelisted, + template!(List: r#"since = "version", reason = "...""#), + Ungated + ), + (sym::must_use, Whitelisted, template!(Word, NameValueStr: "reason"), Ungated), + ( + sym::stable, + Whitelisted, + template!(List: r#"feature = "name", since = "version""#), + Ungated + ), + ( + sym::unstable, + Whitelisted, + template!(List: r#"feature = "name", reason = "...", issue = "N""#), + Ungated + ), + (sym::deprecated, Normal, template!( Word, - List: r#"/*opt*/ since = "version", /*opt*/ note = "reason"#, + List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, NameValueStr: "reason" ), Ungated ), - ("rustc_paren_sugar", Normal, template!(Word), Gated(Stability::Unstable, - "unboxed_closures", + (sym::rustc_paren_sugar, Normal, template!(Word), Gated(Stability::Unstable, + sym::unboxed_closures, "unboxed_closures are still evolving", cfg_fn!(unboxed_closures))), - ("windows_subsystem", Whitelisted, template!(NameValueStr: "windows|console"), Ungated), + (sym::windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console"), Ungated), - ("proc_macro_attribute", Normal, template!(Word), Ungated), - ("proc_macro", Normal, template!(Word), Ungated), + (sym::proc_macro_attribute, Normal, template!(Word), Ungated), + (sym::proc_macro, Normal, template!(Word), Ungated), - ("rustc_proc_macro_decls", Normal, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "used internally by rustc", - cfg_fn!(rustc_attrs))), + (sym::rustc_proc_macro_decls, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "used internally by rustc", + cfg_fn!(rustc_attrs))), - ("allow_fail", Normal, template!(Word), Gated(Stability::Unstable, - "allow_fail", - "allow_fail attribute is currently unstable", - cfg_fn!(allow_fail))), + (sym::allow_fail, Normal, template!(Word), Gated(Stability::Unstable, + sym::allow_fail, + "allow_fail attribute is currently unstable", + cfg_fn!(allow_fail))), - ("rustc_std_internal_symbol", Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "this is an internal attribute that will \ - never be stable", - cfg_fn!(rustc_attrs))), + (sym::rustc_std_internal_symbol, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "this is an internal attribute that will \ + never be stable", + cfg_fn!(rustc_attrs))), // whitelists "identity-like" conversion methods to suggest on type mismatch - ("rustc_conversion_suggestion", Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", - "this is an internal attribute that will \ + (sym::rustc_conversion_suggestion, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "this is an internal attribute that will \ never be stable", - cfg_fn!(rustc_attrs))), + cfg_fn!(rustc_attrs))), - ("rustc_args_required_const", Whitelisted, template!(List: "N"), Gated(Stability::Unstable, - "rustc_attrs", - "never will be stable", - cfg_fn!(rustc_attrs))), + ( + sym::rustc_args_required_const, + Whitelisted, + template!(List: "N"), + Gated(Stability::Unstable, sym::rustc_attrs, "never will be stable", + cfg_fn!(rustc_attrs)) + ), // RFC 2070 - ("panic_handler", Normal, template!(Word), Ungated), + (sym::panic_handler, Normal, template!(Word), Ungated), - ("alloc_error_handler", Normal, template!(Word), Gated(Stability::Unstable, - "alloc_error_handler", - "#[alloc_error_handler] is an unstable feature", - cfg_fn!(alloc_error_handler))), + (sym::alloc_error_handler, Normal, template!(Word), Gated(Stability::Unstable, + sym::alloc_error_handler, + "#[alloc_error_handler] is an unstable feature", + cfg_fn!(alloc_error_handler))), // RFC 2412 - ("optimize", Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable, - "optimize_attribute", - "#[optimize] attribute is an unstable feature", - cfg_fn!(optimize_attribute))), + (sym::optimize, Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable, + sym::optimize_attribute, + "#[optimize] attribute is an unstable feature", + cfg_fn!(optimize_attribute))), // Crate level attributes - ("crate_name", CrateLevel, template!(NameValueStr: "name"), Ungated), - ("crate_type", CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated), - ("crate_id", CrateLevel, template!(NameValueStr: "ignored"), Ungated), - ("feature", CrateLevel, template!(List: "name1, name1, ..."), Ungated), - ("no_start", CrateLevel, template!(Word), Ungated), - ("no_main", CrateLevel, template!(Word), Ungated), - ("no_builtins", CrateLevel, template!(Word), Ungated), - ("recursion_limit", CrateLevel, template!(NameValueStr: "N"), Ungated), - ("type_length_limit", CrateLevel, template!(NameValueStr: "N"), Ungated), - ("test_runner", CrateLevel, template!(List: "path"), Gated(Stability::Unstable, - "custom_test_frameworks", + (sym::crate_name, CrateLevel, template!(NameValueStr: "name"), Ungated), + (sym::crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated), + (sym::crate_id, CrateLevel, template!(NameValueStr: "ignored"), Ungated), + (sym::feature, CrateLevel, template!(List: "name1, name1, ..."), Ungated), + (sym::no_start, CrateLevel, template!(Word), Ungated), + (sym::no_main, CrateLevel, template!(Word), Ungated), + (sym::recursion_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), + (sym::type_length_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), + (sym::test_runner, CrateLevel, template!(List: "path"), Gated(Stability::Unstable, + sym::custom_test_frameworks, EXPLAIN_CUSTOM_TEST_FRAMEWORKS, cfg_fn!(custom_test_frameworks))), ]; +pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate); + +lazy_static! { + pub static ref BUILTIN_ATTRIBUTE_MAP: FxHashMap = { + let mut map = FxHashMap::default(); + for attr in BUILTIN_ATTRIBUTES.iter() { + if map.insert(attr.0, attr).is_some() { + panic!("duplicate builtin attribute `{}`", attr.0); + } + } + map + }; +} + // cfg(...)'s that are feature gated -const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[ +const GATED_CFGS: &[(Symbol, Symbol, fn(&Features) -> bool)] = &[ // (name in cfg, feature, function to check if the feature is enabled) - ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)), - ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)), - ("rustdoc", "doc_cfg", cfg_fn!(doc_cfg)), + (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), + (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), + (sym::rustdoc, sym::doc_cfg, cfg_fn!(doc_cfg)), ]; #[derive(Debug)] @@ -1289,9 +1564,8 @@ pub struct GatedCfg { impl GatedCfg { pub fn gate(cfg: &ast::MetaItem) -> Option { - let name = cfg.name().as_str(); GATED_CFGS.iter() - .position(|info| info.0 == name) + .position(|info| cfg.check_name(info.0)) .map(|idx| { GatedCfg { span: cfg.span, @@ -1312,7 +1586,7 @@ impl GatedCfg { struct Context<'a> { features: &'a Features, parse_sess: &'a ParseSess, - plugin_attributes: &'a [(String, AttributeType)], + plugin_attributes: &'a [(Symbol, AttributeType)], } macro_rules! gate_feature_fn { @@ -1331,41 +1605,43 @@ macro_rules! gate_feature_fn { macro_rules! gate_feature { ($cx: expr, $feature: ident, $span: expr, $explain: expr) => { gate_feature_fn!($cx, |x:&Features| x.$feature, $span, - stringify!($feature), $explain, GateStrength::Hard) + sym::$feature, $explain, GateStrength::Hard) }; ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => { gate_feature_fn!($cx, |x:&Features| x.$feature, $span, - stringify!($feature), $explain, $level) + sym::$feature, $explain, $level) }; } impl<'a> Context<'a> { - fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { + fn check_attribute( + &self, + attr: &ast::Attribute, + attr_info: Option<&BuiltinAttribute>, + is_macro: bool + ) { debug!("check_attribute(attr = {:?})", attr); - let name = attr.name().as_str(); - for &(n, ty, _template, ref gateage) in BUILTIN_ATTRIBUTES { - if name == n { - if let Gated(_, name, desc, ref has_feature) = *gateage { - if !attr.span.allows_unstable(name) { - gate_feature_fn!( - self, has_feature, attr.span, name, desc, GateStrength::Hard + if let Some(&(name, ty, _template, ref gateage)) = attr_info { + if let Gated(_, name, desc, ref has_feature) = *gateage { + if !attr.span.allows_unstable(name) { + gate_feature_fn!( + self, has_feature, attr.span, name, desc, GateStrength::Hard + ); + } + } else if name == sym::doc { + if let Some(content) = attr.meta_item_list() { + if content.iter().any(|c| c.check_name(sym::include)) { + gate_feature!(self, external_doc, attr.span, + "#[doc(include = \"...\")] is experimental" ); } - } else if name == "doc" { - if let Some(content) = attr.meta_item_list() { - if content.iter().any(|c| c.check_name("include")) { - gate_feature!(self, external_doc, attr.span, - "#[doc(include = \"...\")] is experimental" - ); - } - } } - debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage); - return; } + debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage); + return; } - for &(ref n, ref ty) in self.plugin_attributes { - if attr.path == &**n { + for &(n, ty) in self.plugin_attributes { + if attr.path == n { // Plugins can't gate attributes, so we don't check for it // unlike the code above; we only use this loop to // short-circuit to avoid the checks below. @@ -1374,7 +1650,7 @@ impl<'a> Context<'a> { } } if !attr::is_known(attr) { - if name.starts_with("rustc_") { + if attr.name_or_empty().as_str().starts_with("rustc_") { let msg = "unless otherwise specified, attributes with the prefix `rustc_` \ are reserved for internal compiler diagnostics"; gate_feature!(self, rustc_attrs, attr.span, msg); @@ -1391,11 +1667,15 @@ impl<'a> Context<'a> { } pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) { - let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] }; - cx.check_attribute(attr, true); + let cx = Context { features, parse_sess, plugin_attributes: &[] }; + cx.check_attribute( + attr, + attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name).map(|a| *a)), + true + ); } -fn find_lang_feature_issue(feature: &str) -> Option { +fn find_lang_feature_issue(feature: Symbol) -> Option { if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) { let issue = info.2; // FIXME (#28244): enforce that active features have issue numbers @@ -1425,18 +1705,34 @@ pub enum GateStrength { Soft, } -pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue, - explain: &str) { +pub fn emit_feature_err( + sess: &ParseSess, + feature: Symbol, + span: Span, + issue: GateIssue, + explain: &str, +) { feature_err(sess, feature, span, issue, explain).emit(); } -pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue, - explain: &str) -> DiagnosticBuilder<'a> { +pub fn feature_err<'a, S: Into>( + sess: &'a ParseSess, + feature: Symbol, + span: S, + issue: GateIssue, + explain: &str, +) -> DiagnosticBuilder<'a> { leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard) } -fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue, - explain: &str, level: GateStrength) -> DiagnosticBuilder<'a> { +fn leveled_feature_err<'a, S: Into>( + sess: &'a ParseSess, + feature: Symbol, + span: S, + issue: GateIssue, + explain: &str, + level: GateStrength, +) -> DiagnosticBuilder<'a> { let diag = &sess.span_diagnostic; let issue = match issue { @@ -1444,23 +1740,26 @@ fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue GateIssue::Library(lib) => lib, }; - let explanation = match issue { - None | Some(0) => explain.to_owned(), - Some(n) => format!("{} (see issue #{})", explain, n) - }; - let mut err = match level { GateStrength::Hard => { - diag.struct_span_err_with_code(span, &explanation, stringify_error_code!(E0658)) + diag.struct_span_err_with_code(span, explain, stringify_error_code!(E0658)) } - GateStrength::Soft => diag.struct_span_warn(span, &explanation), + GateStrength::Soft => diag.struct_span_warn(span, explain), }; + match issue { + None | Some(0) => {} // We still accept `0` as a stand-in for backwards compatibility + Some(n) => { + err.note(&format!( + "for more information, see https://github.com/rust-lang/rust/issues/{}", + n, + )); + } + } + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable if sess.unstable_features.is_nightly_build() { - err.help(&format!("add #![feature({})] to the \ - crate attributes to enable", - feature)); + err.help(&format!("add #![feature({})] to the crate attributes to enable", feature)); } // If we're on stable and only emitting a "soft" warning, add a note to @@ -1475,10 +1774,10 @@ fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue } const EXPLAIN_BOX_SYNTAX: &str = - "box expression syntax is experimental; you can call `Box::new` instead."; + "box expression syntax is experimental; you can call `Box::new` instead"; pub const EXPLAIN_STMT_ATTR_SYNTAX: &str = - "attributes on expressions are experimental."; + "attributes on expressions are experimental"; pub const EXPLAIN_ASM: &str = "inline assembly is not stable enough for use and is subject to change"; @@ -1510,18 +1809,19 @@ pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str = struct PostExpansionVisitor<'a> { context: &'a Context<'a>, + builtin_attributes: &'static FxHashMap, } macro_rules! gate_feature_post { ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ let (cx, span) = ($cx, $span); - if !span.allows_unstable(stringify!($feature)) { + if !span.allows_unstable(sym::$feature) { gate_feature!(cx.context, $feature, span, $explain) } }}; ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{ let (cx, span) = ($cx, $span); - if !span.allows_unstable(stringify!($feature)) { + if !span.allows_unstable(sym::$feature) { gate_feature!(cx.context, $feature, span, $explain, $level) } }} @@ -1583,36 +1883,44 @@ impl<'a> PostExpansionVisitor<'a> { } } - fn check_builtin_attribute(&mut self, attr: &ast::Attribute, name: &str, + fn check_builtin_attribute(&mut self, attr: &ast::Attribute, name: Symbol, template: AttributeTemplate) { // Some special attributes like `cfg` must be checked // before the generic check, so we skip them here. - let should_skip = |name| name == "cfg"; + let should_skip = |name| name == sym::cfg; // Some of previously accepted forms were used in practice, // report them as warnings for now. - let should_warn = |name| name == "doc" || name == "ignore" || - name == "inline" || name == "link"; + let should_warn = |name| name == sym::doc || name == sym::ignore || + name == sym::inline || name == sym::link; match attr.parse_meta(self.context.parse_sess) { Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) { + let error_msg = format!("malformed `{}` attribute input", name); let mut msg = "attribute must be of the form ".to_owned(); + let mut suggestions = vec![]; let mut first = true; if template.word { first = false; - msg.push_str(&format!("`#[{}{}]`", name, "")); + let code = format!("#[{}]", name); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); } if let Some(descr) = template.list { if !first { msg.push_str(" or "); } first = false; - msg.push_str(&format!("`#[{}({})]`", name, descr)); + let code = format!("#[{}({})]", name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); } if let Some(descr) = template.name_value_str { if !first { msg.push_str(" or "); } - msg.push_str(&format!("`#[{} = \"{}\"]`", name, descr)); + let code = format!("#[{} = \"{}\"]", name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); } if should_warn(name) { self.context.parse_sess.buffer_lint( @@ -1622,7 +1930,17 @@ impl<'a> PostExpansionVisitor<'a> { &msg, ); } else { - self.context.parse_sess.span_diagnostic.span_err(meta.span, &msg); + self.context.parse_sess.span_diagnostic.struct_span_err(meta.span, &error_msg) + .span_suggestions( + meta.span, + if suggestions.len() == 1 { + "must be of the form" + } else { + "the following are the possible correct uses" + }, + suggestions.into_iter(), + Applicability::HasPlaceholders, + ).emit(); } } Err(mut err) => err.emit(), @@ -1632,28 +1950,32 @@ impl<'a> PostExpansionVisitor<'a> { impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { - // check for gated attributes - self.context.check_attribute(attr, false); + let attr_info = attr.ident().and_then(|ident| { + self.builtin_attributes.get(&ident.name).map(|a| *a) + }); - if attr.check_name("doc") { + // Check for gated attributes. + self.context.check_attribute(attr, attr_info, false); + + if attr.check_name(sym::doc) { if let Some(content) = attr.meta_item_list() { - if content.len() == 1 && content[0].check_name("cfg") { + if content.len() == 1 && content[0].check_name(sym::cfg) { gate_feature_post!(&self, doc_cfg, attr.span, "#[doc(cfg(...))] is experimental" ); - } else if content.iter().any(|c| c.check_name("masked")) { + } else if content.iter().any(|c| c.check_name(sym::masked)) { gate_feature_post!(&self, doc_masked, attr.span, "#[doc(masked)] is experimental" ); - } else if content.iter().any(|c| c.check_name("spotlight")) { + } else if content.iter().any(|c| c.check_name(sym::spotlight)) { gate_feature_post!(&self, doc_spotlight, attr.span, "#[doc(spotlight)] is experimental" ); - } else if content.iter().any(|c| c.check_name("alias")) { + } else if content.iter().any(|c| c.check_name(sym::alias)) { gate_feature_post!(&self, doc_alias, attr.span, "#[doc(alias = \"...\")] is experimental" ); - } else if content.iter().any(|c| c.check_name("keyword")) { + } else if content.iter().any(|c| c.check_name(sym::keyword)) { gate_feature_post!(&self, doc_keyword, attr.span, "#[doc(keyword = \"...\")] is experimental" ); @@ -1661,49 +1983,48 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - match BUILTIN_ATTRIBUTES.iter().find(|(name, ..)| attr.path == name) { - Some(&(name, _, template, _)) => self.check_builtin_attribute(attr, name, template), - None => if let Some(TokenTree::Token(_, token::Eq)) = attr.tokens.trees().next() { - // All key-value attributes are restricted to meta-item syntax. - attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok(); + match attr_info { + // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. + Some(&(name, _, template, _)) if name != sym::rustc_dummy => + self.check_builtin_attribute(attr, name, template), + _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() { + if token == token::Eq { + // All key-value attributes are restricted to meta-item syntax. + attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok(); + } } } } fn visit_name(&mut self, sp: Span, name: ast::Name) { if !name.as_str().is_ascii() { - gate_feature_post!(&self, - non_ascii_idents, - self.context.parse_sess.source_map().def_span(sp), - "non-ascii idents are not fully supported."); + gate_feature_post!( + &self, + non_ascii_idents, + self.context.parse_sess.source_map().def_span(sp), + "non-ascii idents are not fully supported" + ); } } fn visit_item(&mut self, i: &'a ast::Item) { match i.node { - ast::ItemKind::Const(_,_) => { - if i.ident.name == "_" { - gate_feature_post!(&self, underscore_const_names, i.span, - "naming constants with `_` is unstable"); - } - } - ast::ItemKind::ForeignMod(ref foreign_module) => { self.check_abi(foreign_module.abi, i.span); } ast::ItemKind::Fn(..) => { - if attr::contains_name(&i.attrs[..], "plugin_registrar") { + if attr::contains_name(&i.attrs[..], sym::plugin_registrar) { gate_feature_post!(&self, plugin_registrar, i.span, "compiler plugins are experimental and possibly buggy"); } - if attr::contains_name(&i.attrs[..], "start") { + if attr::contains_name(&i.attrs[..], sym::start) { gate_feature_post!(&self, start, i.span, "a #[start] function is an experimental \ feature whose signature may change \ over time"); } - if attr::contains_name(&i.attrs[..], "main") { + if attr::contains_name(&i.attrs[..], sym::main) { gate_feature_post!(&self, main, i.span, "declaration of a nonstandard #[main] \ function may change over time, for now \ @@ -1712,9 +2033,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } ast::ItemKind::Struct(..) => { - for attr in attr::filter_by_name(&i.attrs[..], "repr") { + for attr in attr::filter_by_name(&i.attrs[..], sym::repr) { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { - if item.check_name("simd") { + if item.check_name(sym::simd) { gate_feature_post!(&self, repr_simd, attr.span, "SIMD types are experimental and possibly buggy"); } @@ -1722,15 +2043,27 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - ast::ItemKind::Enum(..) => { - for attr in attr::filter_by_name(&i.attrs[..], "repr") { - for item in attr.meta_item_list().unwrap_or_else(Vec::new) { - if item.check_name("align") { - gate_feature_post!(&self, repr_align_enum, attr.span, - "`#[repr(align(x))]` on enums is experimental"); - } + ast::ItemKind::Enum(ast::EnumDef{ref variants, ..}, ..) => { + for variant in variants { + match (&variant.node.data, &variant.node.disr_expr) { + (ast::VariantData::Unit(..), _) => {}, + (_, Some(disr_expr)) => + gate_feature_post!( + &self, + arbitrary_enum_discriminant, + disr_expr.value.span, + "discriminants on non-unit variants are experimental"), + _ => {}, } } + + let has_feature = self.context.features.arbitrary_enum_discriminant; + if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) { + Parser::maybe_report_invalid_custom_discriminants( + self.context.parse_sess, + &variants, + ); + } } ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { @@ -1787,7 +2120,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match i.node { ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => { - let link_name = attr::first_attr_value_str_by_name(&i.attrs, "link_name"); + let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); let links_to_llvm = match link_name { Some(val) => val.as_str().starts_with("llvm."), _ => false @@ -1824,7 +2157,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) { if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty { if let ast::TyKind::Never = output_ty.node { - // Do nothing + // Do nothing. } else { self.visit_ty(output_ty) } @@ -1837,11 +2170,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX); } ast::ExprKind::Type(..) => { - gate_feature_post!(&self, type_ascription, e.span, - "type ascription is experimental"); - } - ast::ExprKind::ObsoleteInPlace(..) => { - // these get a hard error in ast-validation + // To avoid noise about type ascription in common syntax errors, only emit if it + // is the *only* error. + if self.context.parse_sess.span_diagnostic.err_count() == 0 { + gate_feature_post!(&self, type_ascription, e.span, + "type ascription is experimental"); + } } ast::ExprKind::Yield(..) => { gate_feature_post!(&self, generators, @@ -1863,9 +2197,23 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ExprKind::Async(..) => { gate_feature_post!(&self, async_await, e.span, "async blocks are unstable"); } + ast::ExprKind::Await(origin, _) => { + match origin { + ast::AwaitOrigin::FieldLike => + gate_feature_post!(&self, async_await, e.span, "async/await is unstable"), + ast::AwaitOrigin::MacroLike => + gate_feature_post!( + &self, + await_macro, + e.span, + "`await!()` macro syntax is unstable, and will soon be removed \ + in favor of `.await` syntax." + ), + } + } _ => {} } - visit::walk_expr(self, e); + visit::walk_expr(self, e) } fn visit_arm(&mut self, arm: &'a ast::Arm) { @@ -1898,37 +2246,43 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn_decl: &'a ast::FnDecl, span: Span, _node_id: NodeId) { - match fn_kind { - FnKind::ItemFn(_, header, _, _) => { - // Check for const fn and async fn declarations. - if header.asyncness.node.is_async() { - gate_feature_post!(&self, async_await, span, "async fn is unstable"); - } + if let Some(header) = fn_kind.header() { + // Check for const fn and async fn declarations. + if header.asyncness.node.is_async() { + gate_feature_post!(&self, async_await, span, "async fn is unstable"); + } - if fn_decl.c_variadic { - gate_feature_post!(&self, c_variadic, span, - "C-varaidic functions are unstable"); - } - // Stability of const fn methods are covered in - // `visit_trait_item` and `visit_impl_item` below; this is - // because default methods don't pass through this point. + // Stability of const fn methods are covered in + // `visit_trait_item` and `visit_impl_item` below; this is + // because default methods don't pass through this point. + self.check_abi(header.abi, span); + } - self.check_abi(header.abi, span); - } - FnKind::Method(_, sig, _, _) => { - self.check_abi(sig.header.abi, span); - } - _ => {} + if fn_decl.c_variadic { + gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); } - visit::walk_fn(self, fn_kind, fn_decl, span); + + visit::walk_fn(self, fn_kind, fn_decl, span) } fn visit_generic_param(&mut self, param: &'a GenericParam) { - if let GenericParamKind::Const { .. } = param.kind { - gate_feature_post!(&self, const_generics, param.ident.span, - "const generics are unstable"); + match param.kind { + GenericParamKind::Const { .. } => + gate_feature_post!(&self, const_generics, param.ident.span, + "const generics are unstable"), + _ => {} + } + visit::walk_generic_param(self, param) + } + + fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) { + match constraint.kind { + AssocTyConstraintKind::Bound { .. } => + gate_feature_post!(&self, associated_type_bounds, constraint.span, + "associated type bounds are unstable"), + _ => {} } - visit::walk_generic_param(self, param); + visit::walk_assoc_ty_constraint(self, constraint) } fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) { @@ -1937,9 +2291,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if block.is_none() { self.check_abi(sig.header.abi, ti.span); } + if sig.header.asyncness.node.is_async() { + gate_feature_post!(&self, async_await, ti.span, "async fn is unstable"); + } if sig.decl.c_variadic { gate_feature_post!(&self, c_variadic, ti.span, - "C-varaidic functions are unstable"); + "C-variadic functions are unstable"); } if sig.header.constness.node == ast::Constness::Const { gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); @@ -1963,7 +2320,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } _ => {} } - visit::walk_trait_item(self, ti); + visit::walk_trait_item(self, ti) } fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) { @@ -1995,7 +2352,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } _ => {} } - visit::walk_impl_item(self, ii); + visit::walk_impl_item(self, ii) } fn visit_vis(&mut self, vis: &'a ast::Visibility) { @@ -2003,25 +2360,22 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, crate_visibility_modifier, vis.span, "`crate` visibility modifier is experimental"); } - visit::walk_vis(self, vis); + visit::walk_vis(self, vis) } } pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], - crate_edition: Edition) -> Features { + crate_edition: Edition, allow_features: &Option>) -> Features { fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed"); if let Some(reason) = reason { err.span_note(span, reason); + } else { + err.span_label(span, "feature has been removed"); } err.emit(); } - // Some features are known to be incomplete and using them is likely to have - // unanticipated results, such as compiler crashes. We warn the user about these - // to alert them. - let incomplete_features = ["generic_associated_types", "const_generics"]; - let mut features = Features::new(); let mut edition_enabled_features = FxHashMap::default(); @@ -2029,7 +2383,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], if edition <= crate_edition { // The `crate_edition` implies its respective umbrella feature-gate // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX). - edition_enabled_features.insert(Symbol::intern(edition.feature_name()), edition); + edition_enabled_features.insert(edition.feature_name(), edition); } } @@ -2037,7 +2391,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], if let Some(f_edition) = f_edition { if f_edition <= crate_edition { set(&mut features, DUMMY_SP); - edition_enabled_features.insert(Symbol::intern(name), crate_edition); + edition_enabled_features.insert(name, crate_edition); } } } @@ -2045,7 +2399,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], // Process the edition umbrella feature-gates first, to ensure // `edition_enabled_features` is completed before it's queried. for attr in krate_attrs { - if !attr.check_name("feature") { + if !attr.check_name(sym::feature) { continue } @@ -2055,15 +2409,14 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], }; for mi in list { - let name = if let Some(word) = mi.word() { - word.name() - } else { - continue - }; + if !mi.is_word() { + continue; + } - if incomplete_features.iter().any(|f| *f == name.as_str()) { + let name = mi.name_or_empty(); + if INCOMPLETE_FEATURES.iter().any(|f| name == *f) { span_handler.struct_span_warn( - mi.span, + mi.span(), &format!( "the feature `{}` is incomplete and may cause the compiler to crash", name @@ -2082,7 +2435,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], // FIXME(Manishearth) there is currently no way to set // lib features by edition set(&mut features, DUMMY_SP); - edition_enabled_features.insert(Symbol::intern(name), *edition); + edition_enabled_features.insert(name, *edition); } } } @@ -2091,7 +2444,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], } for attr in krate_attrs { - if !attr.check_name("feature") { + if !attr.check_name(sym::feature) { continue } @@ -2100,19 +2453,32 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], None => continue, }; + let bad_input = |span| { + struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input") + }; + for mi in list { - let name = if let Some(word) = mi.word() { - word.name() - } else { - span_err!(span_handler, mi.span, E0556, - "malformed feature, expected just one word"); - continue + let name = match mi.ident() { + Some(ident) if mi.is_word() => ident.name, + Some(ident) => { + bad_input(mi.span()).span_suggestion( + mi.span(), + "expected just one word", + format!("{}", ident.name), + Applicability::MaybeIncorrect, + ).emit(); + continue + } + None => { + bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit(); + continue + } }; if let Some(edition) = edition_enabled_features.get(&name) { struct_span_warn!( span_handler, - mi.span, + mi.span(), E0705, "the feature `{}` is included in the Rust {} edition", name, @@ -2126,26 +2492,35 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], continue; } - if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) { - set(&mut features, mi.span); - features.declared_lang_features.push((name, mi.span, None)); - continue - } - let removed = REMOVED_FEATURES.iter().find(|f| name == f.0); let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0); if let Some((.., reason)) = removed.or(stable_removed) { - feature_removed(span_handler, mi.span, *reason); - continue + feature_removed(span_handler, mi.span(), *reason); + continue; } if let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) { let since = Some(Symbol::intern(since)); - features.declared_lang_features.push((name, mi.span, since)); - continue + features.declared_lang_features.push((name, mi.span(), since)); + continue; } - features.declared_lib_features.push((name, mi.span)); + if let Some(allowed) = allow_features.as_ref() { + if allowed.iter().find(|f| *f == name.as_str()).is_none() { + span_err!(span_handler, mi.span(), E0725, + "the feature `{}` is not in the list of allowed features", + name); + continue; + } + } + + if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) { + set(&mut features, mi.span()); + features.declared_lang_features.push((name, mi.span(), None)); + continue; + } + + features.declared_lib_features.push((name, mi.span())); } } @@ -2155,7 +2530,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], pub fn check_crate(krate: &ast::Crate, sess: &ParseSess, features: &Features, - plugin_attributes: &[(String, AttributeType)], + plugin_attributes: &[(Symbol, AttributeType)], unstable: UnstableFeatures) { maybe_stage_features(&sess.span_diagnostic, krate, unstable); let ctx = Context { @@ -2164,7 +2539,32 @@ pub fn check_crate(krate: &ast::Crate, plugin_attributes, }; - let visitor = &mut PostExpansionVisitor { context: &ctx }; + sess + .param_attr_spans + .borrow() + .iter() + .for_each(|span| gate_feature!( + &ctx, + param_attrs, + *span, + "attributes on function parameters are unstable" + )); + + sess + .let_chains_spans + .borrow() + .iter() + .for_each(|span| gate_feature!( + &ctx, + let_chains, + *span, + "`let` expressions in this position are experimental" + )); + + let visitor = &mut PostExpansionVisitor { + context: &ctx, + builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP, + }; visit::walk_crate(visitor, krate); } @@ -2211,7 +2611,7 @@ fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, }; if !allow_features { for attr in &krate.attrs { - if attr.check_name("feature") { + if attr.check_name(sym::feature) { let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"); span_err!(span_handler, attr.span, E0554, "#![feature] may not be used on the {} release channel", diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index 9acd0d099a0e1..767ab74355e66 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -14,11 +14,12 @@ use crate::source_map::{SourceMap, FilePathMapping}; use errors::registry::Registry; use errors::{DiagnosticBuilder, SubDiagnostic, CodeSuggestion, SourceMapper}; use errors::{DiagnosticId, Applicability}; -use errors::emitter::{Emitter, EmitterWriter}; +use errors::emitter::{Emitter, HumanReadableErrorType}; use syntax_pos::{MacroBacktrace, Span, SpanLabel, MultiSpan}; use rustc_data_structures::sync::{self, Lrc}; use std::io::{self, Write}; +use std::path::Path; use std::vec; use std::sync::{Arc, Mutex}; @@ -30,37 +31,46 @@ pub struct JsonEmitter { sm: Lrc, pretty: bool, ui_testing: bool, + json_rendered: HumanReadableErrorType, } impl JsonEmitter { - pub fn stderr(registry: Option, - source_map: Lrc, - pretty: bool) -> JsonEmitter { + pub fn stderr( + registry: Option, + source_map: Lrc, + pretty: bool, + json_rendered: HumanReadableErrorType, + ) -> JsonEmitter { JsonEmitter { dst: Box::new(io::stderr()), registry, sm: source_map, pretty, ui_testing: false, + json_rendered, } } - pub fn basic(pretty: bool) -> JsonEmitter { + pub fn basic(pretty: bool, json_rendered: HumanReadableErrorType) -> JsonEmitter { let file_path_mapping = FilePathMapping::empty(); JsonEmitter::stderr(None, Lrc::new(SourceMap::new(file_path_mapping)), - pretty) + pretty, json_rendered) } - pub fn new(dst: Box, - registry: Option, - source_map: Lrc, - pretty: bool) -> JsonEmitter { + pub fn new( + dst: Box, + registry: Option, + source_map: Lrc, + pretty: bool, + json_rendered: HumanReadableErrorType, + ) -> JsonEmitter { JsonEmitter { dst, registry, sm: source_map, pretty, ui_testing: false, + json_rendered, } } @@ -70,7 +80,7 @@ impl JsonEmitter { } impl Emitter for JsonEmitter { - fn emit(&mut self, db: &DiagnosticBuilder<'_>) { + fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { let data = Diagnostic::from_diagnostic_builder(db, self); let result = if self.pretty { writeln!(&mut self.dst, "{}", as_pretty_json(&data)) @@ -81,6 +91,18 @@ impl Emitter for JsonEmitter { panic!("failed to print diagnostics: {:?}", e); } } + + fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) { + let data = ArtifactNotification { artifact: path, emit: artifact_type }; + let result = if self.pretty { + writeln!(&mut self.dst, "{}", as_pretty_json(&data)) + } else { + writeln!(&mut self.dst, "{}", as_json(&data)) + }; + if let Err(e) = result { + panic!("failed to print notification: {:?}", e); + } + } } // The following data types are provided just for serialisation. @@ -159,6 +181,14 @@ struct DiagnosticCode { explanation: Option<&'static str>, } +#[derive(RustcEncodable)] +struct ArtifactNotification<'a> { + /// The path of the artifact. + artifact: &'a Path, + /// What kind of artifact we're emitting. + emit: &'a str, +} + impl Diagnostic { fn from_diagnostic_builder(db: &DiagnosticBuilder<'_>, je: &JsonEmitter) @@ -190,8 +220,8 @@ impl Diagnostic { } let buf = BufWriter::default(); let output = buf.clone(); - EmitterWriter::new(Box::new(buf), Some(je.sm.clone()), false, false) - .ui_testing(je.ui_testing).emit(db); + je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false) + .ui_testing(je.ui_testing).emit_diagnostic(db); let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); let output = String::from_utf8(output).unwrap(); @@ -348,19 +378,17 @@ impl DiagnosticSpanLine { /// `span` within the line. fn from_span(span: Span, je: &JsonEmitter) -> Vec { je.sm.span_to_lines(span) - .map(|lines| { - let fm = &*lines.file; - lines.lines - .iter() - .map(|line| { - DiagnosticSpanLine::line_from_source_file(fm, - line.line_index, - line.start_col.0 + 1, - line.end_col.0 + 1) - }) - .collect() - }) - .unwrap_or_else(|_| vec![]) + .map(|lines| { + let fm = &*lines.file; + lines.lines + .iter() + .map(|line| DiagnosticSpanLine::line_from_source_file( + fm, + line.line_index, + line.start_col.0 + 1, + line.end_col.0 + 1, + )).collect() + }).unwrap_or_else(|_| vec![]) } } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index a6145d5dcb38c..337b84247361d 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -8,7 +8,12 @@ test(attr(deny(warnings))))] #![deny(rust_2018_idioms)] +#![deny(internal)] +#![deny(unused_lifetimes)] +#![feature(bind_by_move_pattern_guards)] +#![feature(const_fn)] +#![feature(const_transmute)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] #![feature(nll)] @@ -28,6 +33,9 @@ use rustc_data_structures::sync::Lock; use rustc_data_structures::bit_set::GrowableBitSet; pub use rustc_data_structures::thin_vec::ThinVec; use ast::AttrId; +use syntax_pos::edition::Edition; + +const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments"); // A variant of 'try!' that panics on an Err. This is used as a crutch on the // way towards a non-panic!-prone parser. It should be used for fatal parsing @@ -81,26 +89,32 @@ pub struct Globals { } impl Globals { - fn new() -> Globals { + fn new(edition: Edition) -> Globals { Globals { // We have no idea how many attributes their will be, so just // initiate the vectors with 0 bits. We'll grow them as necessary. used_attrs: Lock::new(GrowableBitSet::new_empty()), known_attrs: Lock::new(GrowableBitSet::new_empty()), - syntax_pos_globals: syntax_pos::Globals::new(), + syntax_pos_globals: syntax_pos::Globals::new(edition), } } } -pub fn with_globals(f: F) -> R +pub fn with_globals(edition: Edition, f: F) -> R where F: FnOnce() -> R { - let globals = Globals::new(); + let globals = Globals::new(edition); GLOBALS.set(&globals, || { syntax_pos::GLOBALS.set(&globals.syntax_pos_globals, f) }) } +pub fn with_default_globals(f: F) -> R + where F: FnOnce() -> R +{ + with_globals(edition::DEFAULT_EDITION, f) +} + scoped_tls::scoped_thread_local!(pub static GLOBALS: Globals); #[macro_use] @@ -113,7 +127,7 @@ pub mod diagnostics { // N.B., this module needs to be declared first so diagnostics are // registered before they are used. -pub mod diagnostic_list; +pub mod error_codes; pub mod util { pub mod lev_distance; @@ -126,12 +140,6 @@ pub mod util { pub mod json; -pub mod syntax { - pub use crate::ext; - pub use crate::parse; - pub use crate::ast; -} - pub mod ast; pub mod attr; pub mod source_map; diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 802b780869597..e23bc025f6e31 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -11,7 +11,6 @@ use crate::ast::*; use crate::source_map::{Spanned, respan}; use crate::parse::token::{self, Token}; use crate::ptr::P; -use crate::symbol::keywords; use crate::ThinVec; use crate::tokenstream::*; use crate::util::map_in_place::MapInPlace; @@ -132,10 +131,6 @@ pub trait MutVisitor: Sized { noop_visit_arm(a, self); } - fn visit_guard(&mut self, g: &mut Guard) { - noop_visit_guard(g, self); - } - fn visit_pat(&mut self, p: &mut P) { noop_visit_pat(p, self); } @@ -164,8 +159,8 @@ pub trait MutVisitor: Sized { noop_visit_lifetime(l, self); } - fn visit_ty_binding(&mut self, t: &mut TypeBinding) { - noop_visit_ty_binding(t, self); + fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) { + noop_visit_ty_constraint(t, self); } fn visit_mod(&mut self, m: &mut Mod) { @@ -384,24 +379,31 @@ pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arm(Arm { attrs, pats, guard, body }: &mut Arm, vis: &mut T) { +pub fn noop_visit_arm( + Arm { attrs, pats, guard, body, span }: &mut Arm, + vis: &mut T, +) { visit_attrs(attrs, vis); visit_vec(pats, |pat| vis.visit_pat(pat)); - visit_opt(guard, |guard| vis.visit_guard(guard)); + visit_opt(guard, |guard| vis.visit_expr(guard)); vis.visit_expr(body); + vis.visit_span(span); } -pub fn noop_visit_guard(g: &mut Guard, vis: &mut T) { - match g { - Guard::If(e) => vis.visit_expr(e), - } -} - -pub fn noop_visit_ty_binding(TypeBinding { id, ident, ty, span }: &mut TypeBinding, - vis: &mut T) { +pub fn noop_visit_ty_constraint( + AssocTyConstraint { id, ident, kind, span }: &mut AssocTyConstraint, + vis: &mut T +) { vis.visit_id(id); vis.visit_ident(ident); - vis.visit_ty(ty); + match kind { + AssocTyConstraintKind::Equality { ref mut ty } => { + vis.visit_ty(ty); + } + AssocTyConstraintKind::Bound { ref mut bounds } => { + visit_bounds(bounds, vis); + } + } vis.visit_span(span); } @@ -450,9 +452,10 @@ pub fn noop_visit_foreign_mod(foreign_mod: &mut ForeignMod, vis: } pub fn noop_visit_variant(variant: &mut Variant, vis: &mut T) { - let Spanned { node: Variant_ { ident, attrs, data, disr_expr }, span } = variant; + let Spanned { node: Variant_ { ident, attrs, id, data, disr_expr }, span } = variant; vis.visit_ident(ident); visit_attrs(attrs, vis); + vis.visit_id(id); vis.visit_variant_data(data); visit_opt(disr_expr, |disr_expr| vis.visit_anon_const(disr_expr)); vis.visit_span(span); @@ -495,9 +498,9 @@ pub fn noop_visit_generic_arg(arg: &mut GenericArg, vis: &mut T) pub fn noop_visit_angle_bracketed_parameter_data(data: &mut AngleBracketedArgs, vis: &mut T) { - let AngleBracketedArgs { args, bindings, span } = data; + let AngleBracketedArgs { args, constraints, span } = data; visit_vec(args, |arg| vis.visit_generic_arg(arg)); - visit_vec(bindings, |binding| vis.visit_ty_binding(binding)); + visit_vec(constraints, |constraint| vis.visit_ty_constraint(constraint)); vis.visit_span(span); } @@ -539,16 +542,14 @@ pub fn noop_visit_macro_def(macro_def: &mut MacroDef, vis: &mut T } pub fn noop_visit_meta_list_item(li: &mut NestedMetaItem, vis: &mut T) { - let Spanned { node, span } = li; - match node { - NestedMetaItemKind::MetaItem(mi) => vis.visit_meta_item(mi), - NestedMetaItemKind::Literal(_lit) => {} + match li { + NestedMetaItem::MetaItem(mi) => vis.visit_meta_item(mi), + NestedMetaItem::Literal(_lit) => {} } - vis.visit_span(span); } pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { - let MetaItem { ident: _, node, span } = mi; + let MetaItem { path: _, node, span } = mi; match node { MetaItemKind::Word => {} MetaItemKind::List(mis) => visit_vec(mis, |mi| vis.visit_meta_list_item(mi)), @@ -557,17 +558,17 @@ pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arg(Arg { id, pat, ty }: &mut Arg, vis: &mut T) { +pub fn noop_visit_arg(Arg { attrs, id, pat, ty }: &mut Arg, vis: &mut T) { vis.visit_id(id); + visit_thin_attrs(attrs, vis); vis.visit_pat(pat); vis.visit_ty(ty); } pub fn noop_visit_tt(tt: &mut TokenTree, vis: &mut T) { match tt { - TokenTree::Token(span, tok) => { - vis.visit_span(span); - vis.visit_token(tok); + TokenTree::Token(token) => { + vis.visit_token(token); } TokenTree::Delimited(DelimSpan { open, close }, _delim, tts) => { vis.visit_span(open); @@ -584,17 +585,26 @@ pub fn noop_visit_tts(TokenStream(tts): &mut TokenStream, vis: &m }) } -// apply ident visitor if it's an ident, apply other visits to interpolated nodes +// Apply ident visitor if it's an ident, apply other visits to interpolated nodes. +// In practice the ident part is not actually used by specific visitors right now, +// but there's a test below checking that it works. pub fn noop_visit_token(t: &mut Token, vis: &mut T) { - match t { - token::Ident(id, _is_raw) => vis.visit_ident(id), - token::Lifetime(id) => vis.visit_ident(id), + let Token { kind, span } = t; + match kind { + token::Ident(name, _) | token::Lifetime(name) => { + let mut ident = Ident::new(*name, *span); + vis.visit_ident(&mut ident); + *name = ident.name; + *span = ident.span; + return; // avoid visiting the span for the second time + } token::Interpolated(nt) => { let mut nt = Lrc::make_mut(nt); vis.visit_interpolated(&mut nt); } _ => {} } + vis.visit_span(span); } /// Apply visitor to elements of interpolated nodes. @@ -644,7 +654,6 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: token::NtMeta(meta) => vis.visit_meta_item(meta), token::NtPath(path) => vis.visit_path(path), token::NtTT(tt) => vis.visit_tt(tt), - token::NtArm(arm) => vis.visit_arm(arm), token::NtImplItem(item) => visit_clobber(item, |item| { // See reasoning above. @@ -657,9 +666,6 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: vis.flat_map_trait_item(item) .expect_one("expected visitor to produce exactly one item") }), - token::NtGenerics(generics) => vis.visit_generics(generics), - token::NtWhereClause(where_clause) => vis.visit_where_clause(where_clause), - token::NtArg(arg) => vis.visit_arg(arg), token::NtVis(visib) => vis.visit_vis(visib), token::NtForeignItem(item) => visit_clobber(item, |item| { @@ -734,8 +740,7 @@ pub fn noop_visit_generics(generics: &mut Generics, vis: &mut T) } pub fn noop_visit_where_clause(wc: &mut WhereClause, vis: &mut T) { - let WhereClause { id, predicates, span } = wc; - vis.visit_id(id); + let WhereClause { predicates, span } = wc; visit_vec(predicates, |predicate| vis.visit_where_predicate(predicate)); vis.visit_span(span); } @@ -767,11 +772,11 @@ pub fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: pub fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut T) { match vdata { - VariantData::Struct(fields, id) | + VariantData::Struct(fields, ..) => visit_vec(fields, |field| vis.visit_struct_field(field)), VariantData::Tuple(fields, id) => { visit_vec(fields, |field| vis.visit_struct_field(field)); vis.visit_id(id); - } + }, VariantData::Unit(id) => vis.visit_id(id), } } @@ -946,7 +951,7 @@ pub fn noop_visit_mod(Mod { inner, items, inline: _ }: &mut Mod, pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { visit_clobber(krate, |Crate { module, attrs, span }| { let item = P(Item { - ident: keywords::Invalid.ident(), + ident: Ident::invalid(), attrs, id: DUMMY_NODE_ID, vis: respan(span.shrink_to_lo(), VisibilityKind::Public), @@ -1065,10 +1070,6 @@ pub fn noop_visit_anon_const(AnonConst { id, value }: &mut AnonCo pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, vis: &mut T) { match node { ExprKind::Box(expr) => vis.visit_expr(expr), - ExprKind::ObsoleteInPlace(a, b) => { - vis.visit_expr(a); - vis.visit_expr(b); - } ExprKind::Array(exprs) => visit_exprs(exprs, vis), ExprKind::Repeat(expr, count) => { vis.visit_expr(expr); @@ -1090,7 +1091,6 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, vis.visit_expr(rhs); } ExprKind::Unary(_unop, ohs) => vis.visit_expr(ohs), - ExprKind::Lit(_lit) => {} ExprKind::Cast(expr, ty) => { vis.visit_expr(expr); vis.visit_ty(ty); @@ -1100,28 +1100,20 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, vis.visit_ty(ty); } ExprKind::AddrOf(_m, ohs) => vis.visit_expr(ohs), + ExprKind::Let(pats, scrutinee) => { + visit_vec(pats, |pat| vis.visit_pat(pat)); + vis.visit_expr(scrutinee); + } ExprKind::If(cond, tr, fl) => { vis.visit_expr(cond); vis.visit_block(tr); visit_opt(fl, |fl| vis.visit_expr(fl)); } - ExprKind::IfLet(pats, expr, tr, fl) => { - visit_vec(pats, |pat| vis.visit_pat(pat)); - vis.visit_expr(expr); - vis.visit_block(tr); - visit_opt(fl, |fl| vis.visit_expr(fl)); - } ExprKind::While(cond, body, label) => { vis.visit_expr(cond); vis.visit_block(body); visit_opt(label, |label| vis.visit_label(label)); } - ExprKind::WhileLet(pats, expr, body, label) => { - visit_vec(pats, |pat| vis.visit_pat(pat)); - vis.visit_expr(expr); - vis.visit_block(body); - visit_opt(label, |label| vis.visit_label(label)); - } ExprKind::ForLoop(pat, iter, body, label) => { vis.visit_pat(pat); vis.visit_expr(iter); @@ -1150,6 +1142,7 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, vis.visit_id(node_id); vis.visit_block(body); } + ExprKind::Await(_origin, expr) => vis.visit_expr(expr), ExprKind::Assign(el, er) => { vis.visit_expr(el); vis.visit_expr(er); @@ -1213,7 +1206,7 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, } ExprKind::Try(expr) => vis.visit_expr(expr), ExprKind::TryBlock(body) => vis.visit_block(body), - ExprKind::Err => {} + ExprKind::Lit(_) | ExprKind::Err => {} } vis.visit_id(id); vis.visit_span(span); @@ -1273,7 +1266,7 @@ mod tests { use crate::util::parser_testing::{string_to_crate, matches_codepattern}; use crate::print::pprust; use crate::mut_visit; - use crate::with_globals; + use crate::with_default_globals; use super::*; // this version doesn't care about getting comments or docstrings in. @@ -1311,7 +1304,7 @@ mod tests { // make sure idents get transformed everywhere #[test] fn ident_transformation () { - with_globals(|| { + with_default_globals(|| { let mut zz_visitor = ToZzIdentMutVisitor; let mut krate = string_to_crate( "#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}".to_string()); @@ -1326,7 +1319,7 @@ mod tests { // even inside macro defs.... #[test] fn ident_transformation_in_defs () { - with_globals(|| { + with_default_globals(|| { let mut zz_visitor = ToZzIdentMutVisitor; let mut krate = string_to_crate( "macro_rules! a {(b $c:expr $(d $e:token)f+ => \ @@ -1340,4 +1333,3 @@ mod tests { }) } } - diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index e7937f57002f3..b28d48b9445fd 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -1,12 +1,12 @@ use crate::attr; use crate::ast; -use crate::source_map::respan; use crate::parse::{SeqSep, PResult}; use crate::parse::token::{self, Nonterminal, DelimToken}; use crate::parse::parser::{Parser, TokenType, PathStyle}; use crate::tokenstream::{TokenStream, TokenTree}; use log::debug; +use smallvec::smallvec; #[derive(Debug)] enum InnerAttributeParsePolicy<'a> { @@ -18,13 +18,21 @@ const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ permitted in this context"; impl<'a> Parser<'a> { + crate fn parse_arg_attributes(&mut self) -> PResult<'a, Vec> { + let attrs = self.parse_outer_attributes()?; + attrs.iter().for_each(|a| + self.sess.param_attr_spans.borrow_mut().push(a.span) + ); + Ok(attrs) + } + /// Parse attributes that appear before an item crate fn parse_outer_attributes(&mut self) -> PResult<'a, Vec> { let mut attrs: Vec = Vec::new(); let mut just_parsed_doc_comment = false; loop { debug!("parse_outer_attributes: self.token={:?}", self.token); - match self.token { + match self.token.kind { token::Pound => { let inner_error_reason = if just_parsed_doc_comment { "an inner attribute is not permitted following an outer doc comment" @@ -35,11 +43,12 @@ impl<'a> Parser<'a> { }; let inner_parse_policy = InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason }; - attrs.push(self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?); + let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; + attrs.push(attr); just_parsed_doc_comment = false; } token::DocComment(s) => { - let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span); + let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.token.span); if attr.style != ast::AttrStyle::Outer { let mut err = self.fatal("expected outer doc comment"); err.note("inner doc comments like this (starting with \ @@ -81,9 +90,9 @@ impl<'a> Parser<'a> { debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", inner_parse_policy, self.token); - let (span, path, tokens, style) = match self.token { + let (span, path, tokens, style) = match self.token.kind { token::Pound => { - let lo = self.span; + let lo = self.token.span; self.bump(); if let InnerAttributeParsePolicy::Permitted = inner_parse_policy { @@ -93,7 +102,7 @@ impl<'a> Parser<'a> { self.bump(); if let InnerAttributeParsePolicy::NotPermitted { reason } = inner_parse_policy { - let span = self.span; + let span = self.token.span; self.diagnostic() .struct_span_err(span, reason) .note("inner attributes, like `#![no_std]`, annotate the item \ @@ -140,7 +149,7 @@ impl<'a> Parser<'a> { /// PATH `=` TOKEN_TREE /// The delimiters or `=` are still put into the resulting token stream. crate fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> { - let meta = match self.token { + let meta = match self.token.kind { token::Interpolated(ref nt) => match **nt { Nonterminal::NtMeta(ref meta) => Some(meta.clone()), _ => None, @@ -149,7 +158,7 @@ impl<'a> Parser<'a> { }; Ok(if let Some(meta) = meta { self.bump(); - (meta.ident, meta.node.tokens(meta.span)) + (meta.path, meta.node.tokens(meta.span)) } else { let path = self.parse_path(PathStyle::Mod)?; let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) || @@ -157,9 +166,9 @@ impl<'a> Parser<'a> { self.check(&token::OpenDelim(DelimToken::Brace)) { self.parse_token_tree().into() } else if self.eat(&token::Eq) { - let eq = TokenTree::Token(self.prev_span, token::Eq); + let eq = TokenTree::token(token::Eq, self.prev_span); let mut is_interpolated_expr = false; - if let token::Interpolated(nt) = &self.token { + if let token::Interpolated(nt) = &self.token.kind { if let token::NtExpr(..) = **nt { is_interpolated_expr = true; } @@ -172,7 +181,7 @@ impl<'a> Parser<'a> { } else { self.parse_unsuffixed_lit()?.tokens() }; - TokenStream::from_streams(vec![eq.into(), tokens]) + TokenStream::from_streams(smallvec![eq.into(), tokens]) } else { TokenStream::empty() }; @@ -188,7 +197,7 @@ impl<'a> Parser<'a> { crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec> { let mut attrs: Vec = vec![]; loop { - match self.token { + match self.token.kind { token::Pound => { // Don't even try to parse if it's not an inner attribute. if !self.look_ahead(1, |t| t == &token::Not) { @@ -201,7 +210,7 @@ impl<'a> Parser<'a> { } token::DocComment(s) => { // we need to get the position of this token before we bump. - let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span); + let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.token.span); if attr.style == ast::AttrStyle::Inner { attrs.push(attr); self.bump(); @@ -236,7 +245,7 @@ impl<'a> Parser<'a> { /// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { - let nt_meta = match self.token { + let nt_meta = match self.token.kind { token::Interpolated(ref nt) => match **nt { token::NtMeta(ref e) => Some(e.clone()), _ => None, @@ -249,11 +258,11 @@ impl<'a> Parser<'a> { return Ok(meta); } - let lo = self.span; - let ident = self.parse_path(PathStyle::Mod)?; + let lo = self.token.span; + let path = self.parse_path(PathStyle::Mod)?; let node = self.parse_meta_item_kind()?; let span = lo.to(self.prev_span); - Ok(ast::MetaItem { ident, node, span }) + Ok(ast::MetaItem { path, node, span }) } crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { @@ -268,25 +277,23 @@ impl<'a> Parser<'a> { /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ; fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { - let lo = self.span; - match self.parse_unsuffixed_lit() { Ok(lit) => { - return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::Literal(lit))) + return Ok(ast::NestedMetaItem::Literal(lit)) } Err(ref mut err) => self.diagnostic().cancel(err) } match self.parse_meta_item() { Ok(mi) => { - return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::MetaItem(mi))) + return Ok(ast::NestedMetaItem::MetaItem(mi)) } Err(ref mut err) => self.diagnostic().cancel(err) } let found = self.this_token_to_string(); - let msg = format!("expected unsuffixed literal or identifier, found {}", found); - Err(self.diagnostic().struct_span_err(lo, &msg)) + let msg = format!("expected unsuffixed literal or identifier, found `{}`", found); + Err(self.diagnostic().struct_span_err(self.token.span, &msg)) } /// matches meta_seq = ( COMMASEP(meta_item_inner) ) diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs index b4103440e3577..6ebfab3a133ef 100644 --- a/src/libsyntax/parse/classify.rs +++ b/src/libsyntax/parse/classify.rs @@ -14,27 +14,12 @@ use crate::ast; pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { match e.node { ast::ExprKind::If(..) | - ast::ExprKind::IfLet(..) | ast::ExprKind::Match(..) | ast::ExprKind::Block(..) | ast::ExprKind::While(..) | - ast::ExprKind::WhileLet(..) | ast::ExprKind::Loop(..) | ast::ExprKind::ForLoop(..) | ast::ExprKind::TryBlock(..) => false, _ => true, } } - -/// this statement requires a semicolon after it. -/// note that in one case (`stmt_semi`), we've already -/// seen the semicolon, and thus don't need another. -pub fn stmt_ends_with_semi(stmt: &ast::StmtKind) -> bool { - match *stmt { - ast::StmtKind::Local(_) => true, - ast::StmtKind::Expr(ref e) => expr_requires_semi_to_be_stmt(e), - ast::StmtKind::Item(_) | - ast::StmtKind::Semi(..) | - ast::StmtKind::Mac(..) => false, - } -} diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs new file mode 100644 index 0000000000000..0ea0b2a694d7d --- /dev/null +++ b/src/libsyntax/parse/diagnostics.rs @@ -0,0 +1,1273 @@ +use crate::ast::{ + self, Arg, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, + Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, VariantData, +}; +use crate::parse::{SeqSep, PResult, Parser, ParseSess}; +use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType}; +use crate::parse::token::{self, TokenKind}; +use crate::print::pprust; +use crate::ptr::P; +use crate::source_map::Spanned; +use crate::symbol::{kw, sym}; +use crate::ThinVec; +use crate::util::parser::AssocOp; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_data_structures::fx::FxHashSet; +use syntax_pos::{Span, DUMMY_SP, MultiSpan}; +use log::{debug, trace}; + +/// Creates a placeholder argument. +crate fn dummy_arg(ident: Ident) -> Arg { + let pat = P(Pat { + id: ast::DUMMY_NODE_ID, + node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), + span: ident.span, + }); + let ty = Ty { + node: TyKind::Err, + span: ident.span, + id: ast::DUMMY_NODE_ID + }; + Arg { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat, ty: P(ty) } +} + +pub enum Error { + FileNotFoundForModule { + mod_name: String, + default_path: String, + secondary_path: String, + dir_path: String, + }, + DuplicatePaths { + mod_name: String, + default_path: String, + secondary_path: String, + }, + UselessDocComment, + InclusiveRangeWithNoEnd, +} + +impl Error { + fn span_err>( + self, + sp: S, + handler: &errors::Handler, + ) -> DiagnosticBuilder<'_> { + match self { + Error::FileNotFoundForModule { + ref mod_name, + ref default_path, + ref secondary_path, + ref dir_path, + } => { + let mut err = struct_span_err!( + handler, + sp, + E0583, + "file not found for module `{}`", + mod_name, + ); + err.help(&format!( + "name the file either {} or {} inside the directory \"{}\"", + default_path, + secondary_path, + dir_path, + )); + err + } + Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => { + let mut err = struct_span_err!( + handler, + sp, + E0584, + "file for module `{}` found at both {} and {}", + mod_name, + default_path, + secondary_path, + ); + err.help("delete or rename one of them to remove the ambiguity"); + err + } + Error::UselessDocComment => { + let mut err = struct_span_err!( + handler, + sp, + E0585, + "found a documentation comment that doesn't document anything", + ); + err.help("doc comments must come before what they document, maybe a comment was \ + intended with `//`?"); + err + } + Error::InclusiveRangeWithNoEnd => { + let mut err = struct_span_err!( + handler, + sp, + E0586, + "inclusive range with no end", + ); + err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)"); + err + } + } + } +} + +pub trait RecoverQPath: Sized + 'static { + const PATH_STYLE: PathStyle = PathStyle::Expr; + fn to_ty(&self) -> Option>; + fn recovered(qself: Option, path: ast::Path) -> Self; +} + +impl RecoverQPath for Ty { + const PATH_STYLE: PathStyle = PathStyle::Type; + fn to_ty(&self) -> Option> { + Some(P(self.clone())) + } + fn recovered(qself: Option, path: ast::Path) -> Self { + Self { + span: path.span, + node: TyKind::Path(qself, path), + id: ast::DUMMY_NODE_ID, + } + } +} + +impl RecoverQPath for Pat { + fn to_ty(&self) -> Option> { + self.to_ty() + } + fn recovered(qself: Option, path: ast::Path) -> Self { + Self { + span: path.span, + node: PatKind::Path(qself, path), + id: ast::DUMMY_NODE_ID, + } + } +} + +impl RecoverQPath for Expr { + fn to_ty(&self) -> Option> { + self.to_ty() + } + fn recovered(qself: Option, path: ast::Path) -> Self { + Self { + span: path.span, + node: ExprKind::Path(qself, path), + attrs: ThinVec::new(), + id: ast::DUMMY_NODE_ID, + } + } +} + +impl<'a> Parser<'a> { + pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> { + self.span_fatal(self.token.span, m) + } + + pub fn span_fatal>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { + self.sess.span_diagnostic.struct_span_fatal(sp, m) + } + + pub fn span_fatal_err>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> { + err.span_err(sp, self.diagnostic()) + } + + pub fn bug(&self, m: &str) -> ! { + self.sess.span_diagnostic.span_bug(self.token.span, m) + } + + pub fn span_err>(&self, sp: S, m: &str) { + self.sess.span_diagnostic.span_err(sp, m) + } + + crate fn struct_span_err>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { + self.sess.span_diagnostic.struct_span_err(sp, m) + } + + crate fn span_bug>(&self, sp: S, m: &str) -> ! { + self.sess.span_diagnostic.span_bug(sp, m) + } + + crate fn cancel(&self, err: &mut DiagnosticBuilder<'_>) { + self.sess.span_diagnostic.cancel(err) + } + + crate fn diagnostic(&self) -> &'a errors::Handler { + &self.sess.span_diagnostic + } + + crate fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { + let mut err = self.struct_span_err( + self.token.span, + &format!("expected identifier, found {}", self.this_token_descr()), + ); + if let token::Ident(name, false) = self.token.kind { + if Ident::new(name, self.token.span).is_raw_guess() { + err.span_suggestion( + self.token.span, + "you can escape reserved keywords to use them as identifiers", + format!("r#{}", name), + Applicability::MaybeIncorrect, + ); + } + } + if let Some(token_descr) = self.token_descr() { + err.span_label(self.token.span, format!("expected identifier, found {}", token_descr)); + } else { + err.span_label(self.token.span, "expected identifier"); + if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { + err.span_suggestion( + self.token.span, + "remove this comma", + String::new(), + Applicability::MachineApplicable, + ); + } + } + err + } + + pub fn expected_one_of_not_found( + &mut self, + edible: &[TokenKind], + inedible: &[TokenKind], + ) -> PResult<'a, bool /* recovered */> { + fn tokens_to_string(tokens: &[TokenType]) -> String { + let mut i = tokens.iter(); + // This might be a sign we need a connect method on Iterator. + let b = i.next() + .map_or(String::new(), |t| t.to_string()); + i.enumerate().fold(b, |mut b, (i, a)| { + if tokens.len() > 2 && i == tokens.len() - 2 { + b.push_str(", or "); + } else if tokens.len() == 2 && i == tokens.len() - 2 { + b.push_str(" or "); + } else { + b.push_str(", "); + } + b.push_str(&a.to_string()); + b + }) + } + + let mut expected = edible.iter() + .map(|x| TokenType::Token(x.clone())) + .chain(inedible.iter().map(|x| TokenType::Token(x.clone()))) + .chain(self.expected_tokens.iter().cloned()) + .collect::>(); + expected.sort_by_cached_key(|x| x.to_string()); + expected.dedup(); + let expect = tokens_to_string(&expected[..]); + let actual = self.this_token_to_string(); + let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { + let short_expect = if expected.len() > 6 { + format!("{} possible tokens", expected.len()) + } else { + expect.clone() + }; + (format!("expected one of {}, found `{}`", expect, actual), + (self.sess.source_map().next_point(self.prev_span), + format!("expected one of {} here", short_expect))) + } else if expected.is_empty() { + (format!("unexpected token: `{}`", actual), + (self.prev_span, "unexpected token after this".to_string())) + } else { + (format!("expected {}, found `{}`", expect, actual), + (self.sess.source_map().next_point(self.prev_span), + format!("expected {} here", expect))) + }; + self.last_unexpected_token_span = Some(self.token.span); + let mut err = self.fatal(&msg_exp); + if self.token.is_ident_named(sym::and) { + err.span_suggestion_short( + self.token.span, + "use `&&` instead of `and` for the boolean operator", + "&&".to_string(), + Applicability::MaybeIncorrect, + ); + } + if self.token.is_ident_named(sym::or) { + err.span_suggestion_short( + self.token.span, + "use `||` instead of `or` for the boolean operator", + "||".to_string(), + Applicability::MaybeIncorrect, + ); + } + let sp = if self.token == token::Eof { + // This is EOF, don't want to point at the following char, but rather the last token + self.prev_span + } else { + label_sp + }; + match self.recover_closing_delimiter(&expected.iter().filter_map(|tt| match tt { + TokenType::Token(t) => Some(t.clone()), + _ => None, + }).collect::>(), err) { + Err(e) => err = e, + Ok(recovered) => { + return Ok(recovered); + } + } + + let is_semi_suggestable = expected.iter().any(|t| match t { + TokenType::Token(token::Semi) => true, // we expect a `;` here + _ => false, + }) && ( // a `;` would be expected before the current keyword + self.token.is_keyword(kw::Break) || + self.token.is_keyword(kw::Continue) || + self.token.is_keyword(kw::For) || + self.token.is_keyword(kw::If) || + self.token.is_keyword(kw::Let) || + self.token.is_keyword(kw::Loop) || + self.token.is_keyword(kw::Match) || + self.token.is_keyword(kw::Return) || + self.token.is_keyword(kw::While) + ); + let cm = self.sess.source_map(); + match (cm.lookup_line(self.token.span.lo()), cm.lookup_line(sp.lo())) { + (Ok(ref a), Ok(ref b)) if a.line != b.line && is_semi_suggestable => { + // The spans are in different lines, expected `;` and found `let` or `return`. + // High likelihood that it is only a missing `;`. + err.span_suggestion_short( + label_sp, + "a semicolon may be missing here", + ";".to_string(), + Applicability::MaybeIncorrect, + ); + err.emit(); + return Ok(true); + } + (Ok(ref a), Ok(ref b)) if a.line == b.line => { + // When the spans are in the same line, it means that the only content between + // them is whitespace, point at the found token in that case: + // + // X | () => { syntax error }; + // | ^^^^^ expected one of 8 possible tokens here + // + // instead of having: + // + // X | () => { syntax error }; + // | -^^^^^ unexpected token + // | | + // | expected one of 8 possible tokens here + err.span_label(self.token.span, label_exp); + } + _ if self.prev_span == syntax_pos::DUMMY_SP => { + // Account for macro context where the previous span might not be + // available to avoid incorrect output (#54841). + err.span_label(self.token.span, "unexpected token"); + } + _ => { + err.span_label(sp, label_exp); + err.span_label(self.token.span, "unexpected token"); + } + } + Err(err) + } + + /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, + /// passes through any errors encountered. Used for error recovery. + crate fn eat_to_tokens(&mut self, kets: &[&TokenKind]) { + let handler = self.diagnostic(); + + if let Err(ref mut err) = self.parse_seq_to_before_tokens( + kets, + SeqSep::none(), + TokenExpectType::Expect, + |p| Ok(p.parse_token_tree()), + ) { + handler.cancel(err); + } + } + + /// This function checks if there are trailing angle brackets and produces + /// a diagnostic to suggest removing them. + /// + /// ```ignore (diagnostic) + /// let _ = vec![1, 2, 3].into_iter().collect::>>>(); + /// ^^ help: remove extra angle brackets + /// ``` + crate fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) { + // This function is intended to be invoked after parsing a path segment where there are two + // cases: + // + // 1. A specific token is expected after the path segment. + // eg. `x.foo(`, `x.foo::(` (parenthesis - method call), + // `Foo::`, or `Foo::::` (mod sep - continued path). + // 2. No specific token is expected after the path segment. + // eg. `x.foo` (field access) + // + // This function is called after parsing `.foo` and before parsing the token `end` (if + // present). This includes any angle bracket arguments, such as `.foo::` or + // `Foo::`. + + // We only care about trailing angle brackets if we previously parsed angle bracket + // arguments. This helps stop us incorrectly suggesting that extra angle brackets be + // removed in this case: + // + // `x.foo >> (3)` (where `x.foo` is a `u32` for example) + // + // This case is particularly tricky as we won't notice it just looking at the tokens - + // it will appear the same (in terms of upcoming tokens) as below (since the `::` will + // have already been parsed): + // + // `x.foo::>>(3)` + let parsed_angle_bracket_args = segment.args + .as_ref() + .map(|args| args.is_angle_bracketed()) + .unwrap_or(false); + + debug!( + "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}", + parsed_angle_bracket_args, + ); + if !parsed_angle_bracket_args { + return; + } + + // Keep the span at the start so we can highlight the sequence of `>` characters to be + // removed. + let lo = self.token.span; + + // We need to look-ahead to see if we have `>` characters without moving the cursor forward + // (since we might have the field access case and the characters we're eating are + // actual operators and not trailing characters - ie `x.foo >> 3`). + let mut position = 0; + + // We can encounter `>` or `>>` tokens in any order, so we need to keep track of how + // many of each (so we can correctly pluralize our error messages) and continue to + // advance. + let mut number_of_shr = 0; + let mut number_of_gt = 0; + while self.look_ahead(position, |t| { + trace!("check_trailing_angle_brackets: t={:?}", t); + if *t == token::BinOp(token::BinOpToken::Shr) { + number_of_shr += 1; + true + } else if *t == token::Gt { + number_of_gt += 1; + true + } else { + false + } + }) { + position += 1; + } + + // If we didn't find any trailing `>` characters, then we have nothing to error about. + debug!( + "check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?}", + number_of_gt, number_of_shr, + ); + if number_of_gt < 1 && number_of_shr < 1 { + return; + } + + // Finally, double check that we have our end token as otherwise this is the + // second case. + if self.look_ahead(position, |t| { + trace!("check_trailing_angle_brackets: t={:?}", t); + *t == end + }) { + // Eat from where we started until the end token so that parsing can continue + // as if we didn't have those extra angle brackets. + self.eat_to_tokens(&[&end]); + let span = lo.until(self.token.span); + + let plural = number_of_gt > 1 || number_of_shr >= 1; + self.diagnostic() + .struct_span_err( + span, + &format!("unmatched angle bracket{}", if plural { "s" } else { "" }), + ) + .span_suggestion( + span, + &format!("remove extra angle bracket{}", if plural { "s" } else { "" }), + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + } + } + + /// Produce an error if comparison operators are chained (RFC #558). + /// We only need to check lhs, not rhs, because all comparison ops + /// have same precedence and are left-associative + crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) { + debug_assert!(outer_op.is_comparison(), + "check_no_chained_comparison: {:?} is not comparison", + outer_op); + match lhs.node { + ExprKind::Binary(op, _, _) if op.node.is_comparison() => { + // respan to include both operators + let op_span = op.span.to(self.token.span); + let mut err = self.diagnostic().struct_span_err(op_span, + "chained comparison operators require parentheses"); + if op.node == BinOpKind::Lt && + *outer_op == AssocOp::Less || // Include `<` to provide this recommendation + *outer_op == AssocOp::Greater // even in a case like the following: + { // Foo>> + err.help( + "use `::<...>` instead of `<...>` if you meant to specify type arguments"); + err.help("or use `(...)` if you meant to specify fn arguments"); + } + err.emit(); + } + _ => {} + } + } + + crate fn maybe_report_ambiguous_plus( + &mut self, + allow_plus: bool, + impl_dyn_multi: bool, + ty: &Ty, + ) { + if !allow_plus && impl_dyn_multi { + let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); + self.struct_span_err(ty.span, "ambiguous `+` in a type") + .span_suggestion( + ty.span, + "use parentheses to disambiguate", + sum_with_parens, + Applicability::MachineApplicable, + ) + .emit(); + } + } + + crate fn maybe_report_invalid_custom_discriminants( + sess: &ParseSess, + variants: &[Spanned], + ) { + let has_fields = variants.iter().any(|variant| match variant.node.data { + VariantData::Tuple(..) | VariantData::Struct(..) => true, + VariantData::Unit(..) => false, + }); + + let discriminant_spans = variants.iter().filter(|variant| match variant.node.data { + VariantData::Tuple(..) | VariantData::Struct(..) => false, + VariantData::Unit(..) => true, + }) + .filter_map(|variant| variant.node.disr_expr.as_ref().map(|c| c.value.span)) + .collect::>(); + + if !discriminant_spans.is_empty() && has_fields { + let mut err = crate::feature_gate::feature_err( + sess, + sym::arbitrary_enum_discriminant, + discriminant_spans.clone(), + crate::feature_gate::GateIssue::Language, + "custom discriminant values are not allowed in enums with tuple or struct variants", + ); + for sp in discriminant_spans { + err.span_label(sp, "disallowed custom discriminant"); + } + for variant in variants.iter() { + match &variant.node.data { + VariantData::Struct(..) => { + err.span_label( + variant.span, + "struct variant defined here", + ); + } + VariantData::Tuple(..) => { + err.span_label( + variant.span, + "tuple variant defined here", + ); + } + VariantData::Unit(..) => {} + } + } + err.emit(); + } + } + + crate fn maybe_recover_from_bad_type_plus( + &mut self, + allow_plus: bool, + ty: &Ty, + ) -> PResult<'a, ()> { + // Do not add `+` to expected tokens. + if !allow_plus || !self.token.is_like_plus() { + return Ok(()); + } + + self.bump(); // `+` + let bounds = self.parse_generic_bounds(None)?; + let sum_span = ty.span.to(self.prev_span); + + let mut err = struct_span_err!( + self.sess.span_diagnostic, + sum_span, + E0178, + "expected a path on the left-hand side of `+`, not `{}`", + pprust::ty_to_string(ty) + ); + + match ty.node { + TyKind::Rptr(ref lifetime, ref mut_ty) => { + let sum_with_parens = pprust::to_string(|s| { + use crate::print::pprust::PrintState; + + s.s.word("&")?; + s.print_opt_lifetime(lifetime)?; + s.print_mutability(mut_ty.mutbl)?; + s.popen()?; + s.print_type(&mut_ty.ty)?; + s.print_type_bounds(" +", &bounds)?; + s.pclose() + }); + err.span_suggestion( + sum_span, + "try adding parentheses", + sum_with_parens, + Applicability::MachineApplicable, + ); + } + TyKind::Ptr(..) | TyKind::BareFn(..) => { + err.span_label(sum_span, "perhaps you forgot parentheses?"); + } + _ => { + err.span_label(sum_span, "expected a path"); + } + } + err.emit(); + Ok(()) + } + + /// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`. + /// Attempt to convert the base expression/pattern/type into a type, parse the `::AssocItem` + /// tail, and combine them into a `::AssocItem` expression/pattern/type. + crate fn maybe_recover_from_bad_qpath( + &mut self, + base: P, + allow_recovery: bool, + ) -> PResult<'a, P> { + // Do not add `::` to expected tokens. + if allow_recovery && self.token == token::ModSep { + if let Some(ty) = base.to_ty() { + return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty); + } + } + Ok(base) + } + + /// Given an already parsed `Ty` parse the `::AssocItem` tail and + /// combine them into a `::AssocItem` expression/pattern/type. + crate fn maybe_recover_from_bad_qpath_stage_2( + &mut self, + ty_span: Span, + ty: P, + ) -> PResult<'a, P> { + self.expect(&token::ModSep)?; + + let mut path = ast::Path { + segments: Vec::new(), + span: DUMMY_SP, + }; + self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?; + path.span = ty_span.to(self.prev_span); + + let ty_str = self + .sess + .source_map() + .span_to_snippet(ty_span) + .unwrap_or_else(|_| pprust::ty_to_string(&ty)); + self.diagnostic() + .struct_span_err(path.span, "missing angle brackets in associated item path") + .span_suggestion( + // this is a best-effort recovery + path.span, + "try", + format!("<{}>::{}", ty_str, path), + Applicability::MaybeIncorrect, + ) + .emit(); + + let path_span = ty_span.shrink_to_hi(); // use an empty path since `position` == 0 + Ok(P(T::recovered( + Some(QSelf { + ty, + path_span, + position: 0, + }), + path, + ))) + } + + crate fn maybe_consume_incorrect_semicolon(&mut self, items: &[P]) -> bool { + if self.eat(&token::Semi) { + let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`"); + err.span_suggestion_short( + self.prev_span, + "remove this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + if !items.is_empty() { + let previous_item = &items[items.len() - 1]; + let previous_item_kind_name = match previous_item.node { + // say "braced struct" because tuple-structs and + // braceless-empty-struct declarations do take a semicolon + ItemKind::Struct(..) => Some("braced struct"), + ItemKind::Enum(..) => Some("enum"), + ItemKind::Trait(..) => Some("trait"), + ItemKind::Union(..) => Some("union"), + _ => None, + }; + if let Some(name) = previous_item_kind_name { + err.help(&format!( + "{} declarations are not followed by a semicolon", + name + )); + } + } + err.emit(); + true + } else { + false + } + } + + /// Create a `DiagnosticBuilder` for an unexpected token `t` and try to recover if it is a + /// closing delimiter. + pub fn unexpected_try_recover( + &mut self, + t: &TokenKind, + ) -> PResult<'a, bool /* recovered */> { + let token_str = pprust::token_kind_to_string(t); + let this_token_str = self.this_token_descr(); + let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) { + // Point at the end of the macro call when reaching end of macro arguments. + (token::Eof, Some(_)) => { + let sp = self.sess.source_map().next_point(self.token.span); + (sp, sp) + } + // We don't want to point at the following span after DUMMY_SP. + // This happens when the parser finds an empty TokenStream. + _ if self.prev_span == DUMMY_SP => (self.token.span, self.token.span), + // EOF, don't want to point at the following char, but rather the last token. + (token::Eof, None) => (self.prev_span, self.token.span), + _ => (self.sess.source_map().next_point(self.prev_span), self.token.span), + }; + let msg = format!( + "expected `{}`, found {}", + token_str, + match (&self.token.kind, self.subparser_name) { + (token::Eof, Some(origin)) => format!("end of {}", origin), + _ => this_token_str, + }, + ); + let mut err = self.struct_span_err(sp, &msg); + let label_exp = format!("expected `{}`", token_str); + match self.recover_closing_delimiter(&[t.clone()], err) { + Err(e) => err = e, + Ok(recovered) => { + return Ok(recovered); + } + } + let cm = self.sess.source_map(); + match (cm.lookup_line(prev_sp.lo()), cm.lookup_line(sp.lo())) { + (Ok(ref a), Ok(ref b)) if a.line == b.line => { + // When the spans are in the same line, it means that the only content + // between them is whitespace, point only at the found token. + err.span_label(sp, label_exp); + } + _ => { + err.span_label(prev_sp, label_exp); + err.span_label(sp, "unexpected token"); + } + } + Err(err) + } + + /// Consume alternative await syntaxes like `await `, `await? `, `await()` + /// and `await { }`. + crate fn parse_incorrect_await_syntax( + &mut self, + lo: Span, + await_sp: Span, + ) -> PResult<'a, (Span, ExprKind)> { + let is_question = self.eat(&token::Question); // Handle `await? `. + let expr = if self.token == token::OpenDelim(token::Brace) { + // Handle `await { }`. + // This needs to be handled separatedly from the next arm to avoid + // interpreting `await { }?` as `?.await`. + self.parse_block_expr( + None, + self.token.span, + BlockCheckMode::Default, + ThinVec::new(), + ) + } else { + self.parse_expr() + }.map_err(|mut err| { + err.span_label(await_sp, "while parsing this incorrect await expression"); + err + })?; + let expr_str = self.sess.source_map().span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" }); + let sp = lo.to(expr.span); + let app = match expr.node { + ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await ?` + _ => Applicability::MachineApplicable, + }; + self.struct_span_err(sp, "incorrect use of `await`") + .span_suggestion(sp, "`await` is a postfix operation", suggestion, app) + .emit(); + Ok((sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr))) + } + + /// If encountering `future.await()`, consume and emit error. + crate fn recover_from_await_method_call(&mut self) { + if self.token == token::OpenDelim(token::Paren) && + self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren)) + { + // future.await() + let lo = self.token.span; + self.bump(); // ( + let sp = lo.to(self.token.span); + self.bump(); // ) + self.struct_span_err(sp, "incorrect use of `await`") + .span_suggestion( + sp, + "`await` is not a method call, remove the parentheses", + String::new(), + Applicability::MachineApplicable, + ).emit() + } + } + + crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool { + self.token.is_ident() && + if let ast::ExprKind::Path(..) = node { true } else { false } && + !self.token.is_reserved_ident() && // v `foo:bar(baz)` + self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) || + self.look_ahead(1, |t| t == &token::Lt) && // `foo:bar, + lhs_span: Span, + cur_op_span: Span, + next_sp: Span, + maybe_path: bool, + ) { + err.span_label(self.token.span, "expecting a type here because of type ascription"); + let cm = self.sess.source_map(); + let next_pos = cm.lookup_char_pos(next_sp.lo()); + let op_pos = cm.lookup_char_pos(cur_op_span.hi()); + if op_pos.line != next_pos.line { + err.span_suggestion( + cur_op_span, + "try using a semicolon", + ";".to_string(), + Applicability::MaybeIncorrect, + ); + } else { + if maybe_path { + err.span_suggestion( + cur_op_span, + "maybe you meant to write a path separator here", + "::".to_string(), + Applicability::MaybeIncorrect, + ); + } else { + err.note("#![feature(type_ascription)] lets you annotate an \ + expression with a type: `: `") + .span_note( + lhs_span, + "this expression expects an ascribed type after the colon", + ) + .help("this might be indicative of a syntax error elsewhere"); + } + } + } + + crate fn recover_seq_parse_error( + &mut self, + delim: token::DelimToken, + lo: Span, + result: PResult<'a, P>, + ) -> P { + match result { + Ok(x) => x, + Err(mut err) => { + err.emit(); + // recover from parse error + self.consume_block(delim); + self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new()) + } + } + } + + crate fn recover_closing_delimiter( + &mut self, + tokens: &[TokenKind], + mut err: DiagnosticBuilder<'a>, + ) -> PResult<'a, bool> { + let mut pos = None; + // we want to use the last closing delim that would apply + for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() { + if tokens.contains(&token::CloseDelim(unmatched.expected_delim)) + && Some(self.token.span) > unmatched.unclosed_span + { + pos = Some(i); + } + } + match pos { + Some(pos) => { + // Recover and assume that the detected unclosed delimiter was meant for + // this location. Emit the diagnostic and act as if the delimiter was + // present for the parser's sake. + + // Don't attempt to recover from this unclosed delimiter more than once. + let unmatched = self.unclosed_delims.remove(pos); + let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim)); + + // We want to suggest the inclusion of the closing delimiter where it makes + // the most sense, which is immediately after the last token: + // + // {foo(bar {}} + // - ^ + // | | + // | help: `)` may belong here + // | + // unclosed delimiter + if let Some(sp) = unmatched.unclosed_span { + err.span_label(sp, "unclosed delimiter"); + } + err.span_suggestion_short( + self.sess.source_map().next_point(self.prev_span), + &format!("{} may belong here", delim.to_string()), + delim.to_string(), + Applicability::MaybeIncorrect, + ); + err.emit(); + self.expected_tokens.clear(); // reduce errors + Ok(true) + } + _ => Err(err), + } + } + + /// Recover from `pub` keyword in places where it seems _reasonable_ but isn't valid. + crate fn eat_bad_pub(&mut self) { + if self.token.is_keyword(kw::Pub) { + match self.parse_visibility(false) { + Ok(vis) => { + self.diagnostic() + .struct_span_err(vis.span, "unnecessary visibility qualifier") + .span_label(vis.span, "`pub` not permitted here") + .emit(); + } + Err(mut err) => err.emit(), + } + } + } + + // Eat tokens until we can be relatively sure we reached the end of the + // statement. This is something of a best-effort heuristic. + // + // We terminate when we find an unmatched `}` (without consuming it). + crate fn recover_stmt(&mut self) { + self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore) + } + + // If `break_on_semi` is `Break`, then we will stop consuming tokens after + // finding (and consuming) a `;` outside of `{}` or `[]` (note that this is + // approximate - it can mean we break too early due to macros, but that + // should only lead to sub-optimal recovery, not inaccurate parsing). + // + // If `break_on_block` is `Break`, then we will stop consuming tokens + // after finding (and consuming) a brace-delimited block. + crate fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) { + let mut brace_depth = 0; + let mut bracket_depth = 0; + let mut in_block = false; + debug!("recover_stmt_ enter loop (semi={:?}, block={:?})", + break_on_semi, break_on_block); + loop { + debug!("recover_stmt_ loop {:?}", self.token); + match self.token.kind { + token::OpenDelim(token::DelimToken::Brace) => { + brace_depth += 1; + self.bump(); + if break_on_block == BlockMode::Break && + brace_depth == 1 && + bracket_depth == 0 { + in_block = true; + } + } + token::OpenDelim(token::DelimToken::Bracket) => { + bracket_depth += 1; + self.bump(); + } + token::CloseDelim(token::DelimToken::Brace) => { + if brace_depth == 0 { + debug!("recover_stmt_ return - close delim {:?}", self.token); + break; + } + brace_depth -= 1; + self.bump(); + if in_block && bracket_depth == 0 && brace_depth == 0 { + debug!("recover_stmt_ return - block end {:?}", self.token); + break; + } + } + token::CloseDelim(token::DelimToken::Bracket) => { + bracket_depth -= 1; + if bracket_depth < 0 { + bracket_depth = 0; + } + self.bump(); + } + token::Eof => { + debug!("recover_stmt_ return - Eof"); + break; + } + token::Semi => { + self.bump(); + if break_on_semi == SemiColonMode::Break && + brace_depth == 0 && + bracket_depth == 0 { + debug!("recover_stmt_ return - Semi"); + break; + } + } + token::Comma if break_on_semi == SemiColonMode::Comma && + brace_depth == 0 && + bracket_depth == 0 => + { + debug!("recover_stmt_ return - Semi"); + break; + } + _ => { + self.bump() + } + } + } + } + + crate fn check_for_for_in_in_typo(&mut self, in_span: Span) { + if self.eat_keyword(kw::In) { + // a common typo: `for _ in in bar {}` + let mut err = self.sess.span_diagnostic.struct_span_err( + self.prev_span, + "expected iterable, found keyword `in`", + ); + err.span_suggestion_short( + in_span.until(self.prev_span), + "remove the duplicated `in`", + String::new(), + Applicability::MachineApplicable, + ); + err.emit(); + } + } + + crate fn expected_semi_or_open_brace(&mut self) -> PResult<'a, ast::TraitItem> { + let token_str = self.this_token_descr(); + let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str)); + err.span_label(self.token.span, "expected `;` or `{`"); + Err(err) + } + + crate fn eat_incorrect_doc_comment_for_arg_type(&mut self) { + if let token::DocComment(_) = self.token.kind { + let mut err = self.diagnostic().struct_span_err( + self.token.span, + "documentation comments cannot be applied to a function parameter's type", + ); + err.span_label(self.token.span, "doc comments are not allowed here"); + err.emit(); + self.bump(); + } else if self.token == token::Pound && self.look_ahead(1, |t| { + *t == token::OpenDelim(token::Bracket) + }) { + let lo = self.token.span; + // Skip every token until next possible arg. + while self.token != token::CloseDelim(token::Bracket) { + self.bump(); + } + let sp = lo.to(self.token.span); + self.bump(); + let mut err = self.diagnostic().struct_span_err( + sp, + "attributes cannot be applied to a function parameter's type", + ); + err.span_label(sp, "attributes are not allowed here"); + err.emit(); + } + } + + crate fn argument_without_type( + &mut self, + err: &mut DiagnosticBuilder<'_>, + pat: P, + require_name: bool, + is_trait_item: bool, + ) -> Option { + // If we find a pattern followed by an identifier, it could be an (incorrect) + // C-style parameter declaration. + if self.check_ident() && self.look_ahead(1, |t| { + *t == token::Comma || *t == token::CloseDelim(token::Paren) + }) { // `fn foo(String s) {}` + let ident = self.parse_ident().unwrap(); + let span = pat.span.with_hi(ident.span.hi()); + + err.span_suggestion( + span, + "declare the type after the parameter binding", + String::from(": "), + Applicability::HasPlaceholders, + ); + return Some(ident); + } else if let PatKind::Ident(_, ident, _) = pat.node { + if require_name && ( + is_trait_item || + self.token == token::Comma || + self.token == token::CloseDelim(token::Paren) + ) { // `fn foo(a, b) {}` or `fn foo(usize, usize) {}` + err.span_suggestion( + pat.span, + "if this was a parameter name, give it a type", + format!("{}: TypeName", ident), + Applicability::HasPlaceholders, + ); + err.span_suggestion( + pat.span, + "if this is a type, explicitly ignore the parameter name", + format!("_: {}", ident), + Applicability::MachineApplicable, + ); + err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)"); + return Some(ident); + } + } + None + } + + crate fn recover_arg_parse(&mut self) -> PResult<'a, (P, P)> { + let pat = self.parse_pat(Some("argument name"))?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; + + let mut err = self.diagnostic().struct_span_err_with_code( + pat.span, + "patterns aren't allowed in methods without bodies", + DiagnosticId::Error("E0642".into()), + ); + err.span_suggestion_short( + pat.span, + "give this argument a name or use an underscore to ignore it", + "_".to_owned(), + Applicability::MachineApplicable, + ); + err.emit(); + + // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. + let pat = P(Pat { + node: PatKind::Wild, + span: pat.span, + id: ast::DUMMY_NODE_ID + }); + Ok((pat, ty)) + } + + crate fn recover_bad_self_arg( + &mut self, + mut arg: ast::Arg, + is_trait_item: bool, + ) -> PResult<'a, ast::Arg> { + let sp = arg.pat.span; + arg.ty.node = TyKind::Err; + let mut err = self.struct_span_err(sp, "unexpected `self` parameter in function"); + if is_trait_item { + err.span_label(sp, "must be the first associated function parameter"); + } else { + err.span_label(sp, "not valid as function parameter"); + err.note("`self` is only valid as the first parameter of an associated function"); + } + err.emit(); + Ok(arg) + } + + crate fn consume_block(&mut self, delim: token::DelimToken) { + let mut brace_depth = 0; + loop { + if self.eat(&token::OpenDelim(delim)) { + brace_depth += 1; + } else if self.eat(&token::CloseDelim(delim)) { + if brace_depth == 0 { + return; + } else { + brace_depth -= 1; + continue; + } + } else if self.token == token::Eof || self.eat(&token::CloseDelim(token::NoDelim)) { + return; + } else { + self.bump(); + } + } + } + + crate fn expected_expression_found(&self) -> DiagnosticBuilder<'a> { + let (span, msg) = match (&self.token.kind, self.subparser_name) { + (&token::Eof, Some(origin)) => { + let sp = self.sess.source_map().next_point(self.token.span); + (sp, format!("expected expression, found end of {}", origin)) + } + _ => (self.token.span, format!( + "expected expression, found {}", + self.this_token_descr(), + )), + }; + let mut err = self.struct_span_err(span, &msg); + let sp = self.sess.source_map().start_point(self.token.span); + if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) { + self.sess.expr_parentheses_needed(&mut err, *sp, None); + } + err.span_label(span, "expected expression"); + err + } + + /// Replace duplicated recovered arguments with `_` pattern to avoid unecessary errors. + /// + /// This is necessary because at this point we don't know whether we parsed a function with + /// anonymous arguments or a function with names but no types. In order to minimize + /// unecessary errors, we assume the arguments are in the shape of `fn foo(a, b, c)` where + /// the arguments are *names* (so we don't emit errors about not being able to find `b` in + /// the local scope), but if we find the same name multiple times, like in `fn foo(i8, i8)`, + /// we deduplicate them to not complain about duplicated argument names. + crate fn deduplicate_recovered_arg_names(&self, fn_inputs: &mut Vec) { + let mut seen_inputs = FxHashSet::default(); + for input in fn_inputs.iter_mut() { + let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = ( + &input.pat.node, &input.ty.node, + ) { + Some(*ident) + } else { + None + }; + if let Some(ident) = opt_ident { + if seen_inputs.contains(&ident) { + input.pat.node = PatKind::Wild; + } + seen_inputs.insert(ident); + } + } + } +} diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs index 74fff3324eacf..97d3fc002e9b0 100644 --- a/src/libsyntax/parse/lexer/comments.rs +++ b/src/libsyntax/parse/lexer/comments.rs @@ -3,8 +3,7 @@ pub use CommentStyle::*; use crate::ast; use crate::source_map::SourceMap; use crate::parse::lexer::{is_block_doc_comment, is_pattern_whitespace}; -use crate::parse::lexer::{self, ParseSess, StringReader, TokenAndSpan}; -use crate::print::pprust; +use crate::parse::lexer::{self, ParseSess, StringReader}; use syntax_pos::{BytePos, CharPos, Pos, FileName}; use log::debug; @@ -339,16 +338,9 @@ fn consume_comment(rdr: &mut StringReader<'_>, debug!("<<< consume comment"); } -#[derive(Clone)] -pub struct Literal { - pub lit: String, - pub pos: BytePos, -} - // it appears this function is called only from pprust... that's // probably not a good thing. -pub fn gather_comments_and_literals(sess: &ParseSess, path: FileName, srdr: &mut dyn Read) - -> (Vec, Vec) +pub fn gather_comments(sess: &ParseSess, path: FileName, srdr: &mut dyn Read) -> Vec { let mut src = String::new(); srdr.read_to_string(&mut src).unwrap(); @@ -357,7 +349,6 @@ pub fn gather_comments_and_literals(sess: &ParseSess, path: FileName, srdr: &mut let mut rdr = lexer::StringReader::new_raw(sess, source_file, None); let mut comments: Vec = Vec::new(); - let mut literals: Vec = Vec::new(); let mut code_to_the_left = false; // Only code let mut anything_to_the_left = false; // Code or comments @@ -382,26 +373,12 @@ pub fn gather_comments_and_literals(sess: &ParseSess, path: FileName, srdr: &mut } } - let bstart = rdr.pos; rdr.next_token(); - // discard, and look ahead; we're working with internal state - let TokenAndSpan { tok, sp } = rdr.peek(); - if tok.is_lit() { - rdr.with_str_from(bstart, |s| { - debug!("tok lit: {}", s); - literals.push(Literal { - lit: s.to_string(), - pos: sp.lo(), - }); - }) - } else { - debug!("tok: {}", pprust::token_to_string(&tok)); - } code_to_the_left = true; anything_to_the_left = true; } - (comments, literals) + comments } #[cfg(test)] diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index a7cde5fbb92cd..4e4fe4256c9b0 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1,16 +1,16 @@ -use crate::ast::{self, Ident}; -use crate::source_map::{SourceMap, FilePathMapping}; -use crate::parse::{token, ParseSess}; -use crate::symbol::{Symbol, keywords}; - -use errors::{Applicability, FatalError, Diagnostic, DiagnosticBuilder}; -use syntax_pos::{BytePos, CharPos, Pos, Span, NO_EXPANSION}; +use crate::parse::ParseSess; +use crate::parse::token::{self, Token, TokenKind}; +use crate::symbol::{sym, Symbol}; +use crate::parse::unescape; +use crate::parse::unescape_error_reporting::{emit_unescape_error, push_escaped_char}; + +use errors::{FatalError, Diagnostic, DiagnosticBuilder}; +use syntax_pos::{BytePos, Pos, Span, NO_EXPANSION}; use core::unicode::property::Pattern_White_Space; use std::borrow::Cow; use std::char; use std::iter; -use std::mem::replace; use rustc_data_structures::sync::Lrc; use log::debug; @@ -18,21 +18,6 @@ pub mod comments; mod tokentrees; mod unicode_chars; -#[derive(Clone, Debug)] -pub struct TokenAndSpan { - pub tok: token::Token, - pub sp: Span, -} - -impl Default for TokenAndSpan { - fn default() -> Self { - TokenAndSpan { - tok: token::Whitespace, - sp: syntax_pos::DUMMY_SP, - } - } -} - #[derive(Clone, Debug)] pub struct UnmatchedBrace { pub expected_delim: token::DelimToken, @@ -43,37 +28,24 @@ pub struct UnmatchedBrace { } pub struct StringReader<'a> { - pub sess: &'a ParseSess, + crate sess: &'a ParseSess, /// The absolute offset within the source_map of the next character to read - pub next_pos: BytePos, + crate next_pos: BytePos, /// The absolute offset within the source_map of the current character - pub pos: BytePos, + crate pos: BytePos, /// The current character (which has been read from self.pos) - pub ch: Option, - pub source_file: Lrc, + crate ch: Option, + crate source_file: Lrc, /// Stop reading src at this index. - pub end_src_index: usize, + crate end_src_index: usize, // cached: - peek_tok: token::Token, - peek_span: Span, + peek_token: Token, peek_span_src_raw: Span, fatal_errs: Vec>, // cache a direct reference to the source text, so that we don't have to // retrieve it via `self.source_file.src.as_ref().unwrap()` all the time. src: Lrc, - token: token::Token, - span: Span, - /// The raw source span which *does not* take `override_span` into account - span_src_raw: Span, - /// Stack of open delimiters and their spans. Used for error message. - open_braces: Vec<(token::DelimToken, Span)>, - crate unmatched_braces: Vec, - /// The type and spans for all braces - /// - /// Used only for error recovery when arriving to EOF with mismatched braces. - matching_delim_spans: Vec<(token::DelimToken, Span, Span)>, - crate override_span: Option, - last_unclosed_found_span: Option, + override_span: Option, } impl<'a> StringReader<'a> { @@ -88,16 +60,7 @@ impl<'a> StringReader<'a> { (real, raw) } - fn mk_ident(&self, string: &str) -> Ident { - let mut ident = Ident::from_str(string); - if let Some(span) = self.override_span { - ident.span = span; - } - - ident - } - - fn unwrap_or_abort(&mut self, res: Result) -> TokenAndSpan { + fn unwrap_or_abort(&mut self, res: Result) -> Token { match res { Ok(tok) => tok, Err(_) => { @@ -107,26 +70,21 @@ impl<'a> StringReader<'a> { } } - fn next_token(&mut self) -> TokenAndSpan where Self: Sized { + fn next_token(&mut self) -> Token where Self: Sized { let res = self.try_next_token(); self.unwrap_or_abort(res) } /// Returns the next token. EFFECT: advances the string_reader. - pub fn try_next_token(&mut self) -> Result { + pub fn try_next_token(&mut self) -> Result { assert!(self.fatal_errs.is_empty()); - let ret_val = TokenAndSpan { - tok: replace(&mut self.peek_tok, token::Whitespace), - sp: self.peek_span, - }; + let ret_val = self.peek_token.take(); self.advance_token()?; - self.span_src_raw = self.peek_span_src_raw; - Ok(ret_val) } /// Immutably extract string if found at current position with given delimiters - pub fn peek_delimited(&self, from_ch: char, to_ch: char) -> Option { + fn peek_delimited(&self, from_ch: char, to_ch: char) -> Option { let mut pos = self.pos; let mut idx = self.src_index(pos); let mut ch = char_at(&self.src, idx); @@ -147,10 +105,10 @@ impl<'a> StringReader<'a> { return None; } - fn try_real_token(&mut self) -> Result { + fn try_real_token(&mut self) -> Result { let mut t = self.try_next_token()?; loop { - match t.tok { + match t.kind { token::Whitespace | token::Comment | token::Shebang(_) => { t = self.try_next_token()?; } @@ -158,13 +116,10 @@ impl<'a> StringReader<'a> { } } - self.token = t.tok.clone(); - self.span = t.sp; - Ok(t) } - pub fn real_token(&mut self) -> TokenAndSpan { + pub fn real_token(&mut self) -> Token { let res = self.try_real_token(); self.unwrap_or_abort(res) } @@ -174,7 +129,7 @@ impl<'a> StringReader<'a> { self.ch.is_none() } - fn fail_unterminated_raw_string(&self, pos: BytePos, hash_count: u16) { + fn fail_unterminated_raw_string(&self, pos: BytePos, hash_count: u16) -> ! { let mut err = self.struct_span_fatal(pos, pos, "unterminated raw string"); err.span_label(self.mk_sp(pos, pos), "unterminated raw string"); @@ -188,10 +143,10 @@ impl<'a> StringReader<'a> { } fn fatal(&self, m: &str) -> FatalError { - self.fatal_span(self.peek_span, m) + self.fatal_span(self.peek_token.span, m) } - pub fn emit_fatal_errors(&mut self) { + crate fn emit_fatal_errors(&mut self) { for err in &mut self.fatal_errs { err.emit(); } @@ -209,12 +164,8 @@ impl<'a> StringReader<'a> { buffer } - pub fn peek(&self) -> TokenAndSpan { - // FIXME(pcwalton): Bad copy! - TokenAndSpan { - tok: self.peek_tok.clone(), - sp: self.peek_span, - } + pub fn peek(&self) -> &Token { + &self.peek_token } /// For comments.rs, which hackily pokes into next_pos and ch @@ -244,35 +195,14 @@ impl<'a> StringReader<'a> { ch: Some('\n'), source_file, end_src_index: src.len(), - // dummy values; not read - peek_tok: token::Eof, - peek_span: syntax_pos::DUMMY_SP, + peek_token: Token::dummy(), peek_span_src_raw: syntax_pos::DUMMY_SP, src, fatal_errs: Vec::new(), - token: token::Eof, - span: syntax_pos::DUMMY_SP, - span_src_raw: syntax_pos::DUMMY_SP, - open_braces: Vec::new(), - unmatched_braces: Vec::new(), - matching_delim_spans: Vec::new(), override_span, - last_unclosed_found_span: None, } } - pub fn new(sess: &'a ParseSess, - source_file: Lrc, - override_span: Option) -> Self { - let mut sr = StringReader::new_raw(sess, source_file, override_span); - if sr.advance_token().is_err() { - sr.emit_fatal_errors(); - FatalError.raise(); - } - - sr - } - pub fn new_or_buffered_errs(sess: &'a ParseSess, source_file: Lrc, override_span: Option) -> Result> { @@ -335,25 +265,12 @@ impl<'a> StringReader<'a> { self.err_span(self.mk_sp(from_pos, to_pos), m) } - /// Pushes a character to a message string for error reporting - fn push_escaped_char_for_msg(m: &mut String, c: char) { - match c { - '\u{20}'..='\u{7e}' => { - // Don't escape \, ' or " for user-facing messages - m.push(c); - } - _ => { - m.extend(c.escape_default()); - } - } - } - /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an /// escaped character to the error message fn fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) -> FatalError { let mut m = m.to_string(); m.push_str(": "); - Self::push_escaped_char_for_msg(&mut m, c); + push_escaped_char(&mut m, c); self.fatal_span_(from_pos, to_pos, &m[..]) } @@ -369,64 +286,29 @@ impl<'a> StringReader<'a> { { let mut m = m.to_string(); m.push_str(": "); - Self::push_escaped_char_for_msg(&mut m, c); + push_escaped_char(&mut m, c); self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), &m[..]) } - /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an - /// escaped character to the error message - fn err_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) { - let mut m = m.to_string(); - m.push_str(": "); - Self::push_escaped_char_for_msg(&mut m, c); - self.err_span_(from_pos, to_pos, &m[..]); - } - - fn struct_err_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) - -> DiagnosticBuilder<'a> - { - let mut m = m.to_string(); - m.push_str(": "); - Self::push_escaped_char_for_msg(&mut m, c); - - self.sess.span_diagnostic.struct_span_err(self.mk_sp(from_pos, to_pos), &m[..]) - } - - /// Report a lexical error spanning [`from_pos`, `to_pos`), appending the - /// offending string to the error message - fn fatal_span_verbose(&self, from_pos: BytePos, to_pos: BytePos, mut m: String) -> FatalError { - m.push_str(": "); - m.push_str(&self.src[self.src_index(from_pos)..self.src_index(to_pos)]); - - self.fatal_span_(from_pos, to_pos, &m[..]) - } - - /// Advance peek_tok and peek_span to refer to the next token, and + /// Advance peek_token to refer to the next token, and /// possibly update the interner. fn advance_token(&mut self) -> Result<(), ()> { match self.scan_whitespace_or_comment() { Some(comment) => { - self.peek_span_src_raw = comment.sp; - self.peek_span = comment.sp; - self.peek_tok = comment.tok; + self.peek_span_src_raw = comment.span; + self.peek_token = comment; } None => { - if self.is_eof() { - self.peek_tok = token::Eof; - let (real, raw) = self.mk_sp_and_raw( - self.source_file.end_pos, - self.source_file.end_pos, - ); - self.peek_span = real; - self.peek_span_src_raw = raw; + let (kind, start_pos, end_pos) = if self.is_eof() { + (token::Eof, self.source_file.end_pos, self.source_file.end_pos) } else { - let start_bytepos = self.pos; - self.peek_tok = self.next_token_inner()?; - let (real, raw) = self.mk_sp_and_raw(start_bytepos, self.pos); - self.peek_span = real; - self.peek_span_src_raw = raw; + let start_pos = self.pos; + (self.next_token_inner()?, start_pos, self.pos) }; + let (real, raw) = self.mk_sp_and_raw(start_pos, end_pos); + self.peek_token = Token::new(kind, real); + self.peek_span_src_raw = raw; } } @@ -438,35 +320,29 @@ impl<'a> StringReader<'a> { (pos - self.source_file.start_pos).to_usize() } - /// Calls `f` with a string slice of the source text spanning from `start` - /// up to but excluding `self.pos`, meaning the slice does not include - /// the character `self.ch`. - fn with_str_from(&self, start: BytePos, f: F) -> T - where F: FnOnce(&str) -> T + /// Slice of the source text from `start` up to but excluding `self.pos`, + /// meaning the slice does not include the character `self.ch`. + fn str_from(&self, start: BytePos) -> &str { - self.with_str_from_to(start, self.pos, f) + self.str_from_to(start, self.pos) } - /// Creates a Name from a given offset to the current offset, each - /// adjusted 1 towards each other (assumes that on either side there is a - /// single-byte delimiter). - fn name_from(&self, start: BytePos) -> ast::Name { + /// Creates a Symbol from a given offset to the current offset. + fn symbol_from(&self, start: BytePos) -> Symbol { debug!("taking an ident from {:?} to {:?}", start, self.pos); - self.with_str_from(start, Symbol::intern) + Symbol::intern(self.str_from(start)) } - /// As name_from, with an explicit endpoint. - fn name_from_to(&self, start: BytePos, end: BytePos) -> ast::Name { + /// As symbol_from, with an explicit endpoint. + fn symbol_from_to(&self, start: BytePos, end: BytePos) -> Symbol { debug!("taking an ident from {:?} to {:?}", start, end); - self.with_str_from_to(start, end, Symbol::intern) + Symbol::intern(self.str_from_to(start, end)) } - /// Calls `f` with a string slice of the source text spanning from `start` - /// up to but excluding `end`. - fn with_str_from_to(&self, start: BytePos, end: BytePos, f: F) -> T - where F: FnOnce(&str) -> T + /// Slice of the source text spanning from `start` up to but excluding `end`. + fn str_from_to(&self, start: BytePos, end: BytePos) -> &str { - f(&self.src[self.src_index(start)..self.src_index(end)]) + &self.src[self.src_index(start)..self.src_index(end)] } /// Converts CRLF to LF in the given string, raising an error on bare CR. @@ -563,7 +439,7 @@ impl<'a> StringReader<'a> { } /// Eats *, if possible. - fn scan_optional_raw_name(&mut self) -> Option { + fn scan_optional_raw_name(&mut self) -> Option { if !ident_start(self.ch) { return None; } @@ -575,8 +451,8 @@ impl<'a> StringReader<'a> { self.bump(); } - self.with_str_from(start, |string| { - if string == "_" { + match self.str_from(start) { + "_" => { self.sess.span_diagnostic .struct_span_warn(self.mk_sp(start, self.pos), "underscore literal suffix is not allowed") @@ -587,15 +463,14 @@ impl<'a> StringReader<'a> { ") .emit(); None - } else { - Some(Symbol::intern(string)) } - }) + name => Some(Symbol::intern(name)) + } } /// PRECONDITION: self.ch is not whitespace /// Eats any kind of comment. - fn scan_comment(&mut self) -> Option { + fn scan_comment(&mut self) -> Option { if let Some(c) = self.ch { if c.is_whitespace() { let msg = "called consume_any_line_comment, but there was whitespace"; @@ -631,26 +506,12 @@ impl<'a> StringReader<'a> { self.bump(); } - if doc_comment { - self.with_str_from(start_bpos, |string| { - // comments with only more "/"s are not doc comments - let tok = if is_doc_comment(string) { - token::DocComment(Symbol::intern(string)) - } else { - token::Comment - }; - - Some(TokenAndSpan { - tok, - sp: self.mk_sp(start_bpos, self.pos), - }) - }) + let kind = if doc_comment { + token::DocComment(self.symbol_from(start_bpos)) } else { - Some(TokenAndSpan { - tok: token::Comment, - sp: self.mk_sp(start_bpos, self.pos), - }) - } + token::Comment + }; + Some(Token::new(kind, self.mk_sp(start_bpos, self.pos))) } Some('*') => { self.bump(); @@ -667,22 +528,17 @@ impl<'a> StringReader<'a> { return None; } - // I guess this is the only way to figure out if - // we're at the beginning of the file... - let smap = SourceMap::new(FilePathMapping::empty()); - smap.files.borrow_mut().source_files.push(self.source_file.clone()); - let loc = smap.lookup_char_pos_adj(self.pos); - debug!("Skipping a shebang"); - if loc.line == 1 && loc.col == CharPos(0) { - // FIXME: Add shebang "token", return it + let is_beginning_of_file = self.pos == self.source_file.start_pos; + if is_beginning_of_file { + debug!("Skipping a shebang"); let start = self.pos; while !self.ch_is('\n') && !self.is_eof() { self.bump(); } - return Some(TokenAndSpan { - tok: token::Shebang(self.name_from(start)), - sp: self.mk_sp(start, self.pos), - }); + return Some(Token::new( + token::Shebang(self.symbol_from(start)), + self.mk_sp(start, self.pos), + )); } } None @@ -693,7 +549,7 @@ impl<'a> StringReader<'a> { /// If there is whitespace, shebang, or a comment, scan it. Otherwise, /// return `None`. - fn scan_whitespace_or_comment(&mut self) -> Option { + fn scan_whitespace_or_comment(&mut self) -> Option { match self.ch.unwrap_or('\0') { // # to handle shebang at start of file -- this is the entry point // for skipping over all "junk" @@ -707,10 +563,7 @@ impl<'a> StringReader<'a> { while is_pattern_whitespace(self.ch) { self.bump(); } - let c = Some(TokenAndSpan { - tok: token::Whitespace, - sp: self.mk_sp(start_bpos, self.pos), - }); + let c = Some(Token::new(token::Whitespace, self.mk_sp(start_bpos, self.pos))); debug!("scanning whitespace: {:?}", c); c } @@ -719,7 +572,7 @@ impl<'a> StringReader<'a> { } /// Might return a sugared-doc-attr - fn scan_block_comment(&mut self) -> Option { + fn scan_block_comment(&mut self) -> Option { // block comments starting with "/**" or "/*!" are doc-comments let is_doc_comment = self.ch_is('*') || self.ch_is('!'); let start_bpos = self.pos - BytePos(2); @@ -754,26 +607,22 @@ impl<'a> StringReader<'a> { self.bump(); } - self.with_str_from(start_bpos, |string| { - // but comments with only "*"s between two "/"s are not - let tok = if is_block_doc_comment(string) { - let string = if has_cr { - self.translate_crlf(start_bpos, - string, - "bare CR not allowed in block doc-comment") - } else { - string.into() - }; - token::DocComment(Symbol::intern(&string[..])) + let string = self.str_from(start_bpos); + // but comments with only "*"s between two "/"s are not + let kind = if is_block_doc_comment(string) { + let string = if has_cr { + self.translate_crlf(start_bpos, + string, + "bare CR not allowed in block doc-comment") } else { - token::Comment + string.into() }; + token::DocComment(Symbol::intern(&string[..])) + } else { + token::Comment + }; - Some(TokenAndSpan { - tok, - sp: self.mk_sp(start_bpos, self.pos), - }) - }) + Some(Token::new(kind, self.mk_sp(start_bpos, self.pos))) } /// Scan through any digits (base `scan_radix`) or underscores, @@ -812,7 +661,7 @@ impl<'a> StringReader<'a> { } /// Lex a LIT_INTEGER or a LIT_FLOAT - fn scan_number(&mut self, c: char) -> token::Lit { + fn scan_number(&mut self, c: char) -> (token::LitKind, Symbol) { let mut base = 10; let start_bpos = self.pos; self.bump(); @@ -839,7 +688,7 @@ impl<'a> StringReader<'a> { } _ => { // just a 0 - return token::Integer(self.name_from(start_bpos)); + return (token::Integer, sym::integer(0)); } } } else if c.is_digit(10) { @@ -851,7 +700,7 @@ impl<'a> StringReader<'a> { if num_digits == 0 { self.err_span_(start_bpos, self.pos, "no valid digits found for number"); - return token::Integer(Symbol::intern("0")); + return (token::Integer, Symbol::intern("0")); } // might be a float, but don't be greedy if this is actually an @@ -869,285 +718,20 @@ impl<'a> StringReader<'a> { let pos = self.pos; self.check_float_base(start_bpos, pos, base); - token::Float(self.name_from(start_bpos)) + (token::Float, self.symbol_from(start_bpos)) } else { // it might be a float if it has an exponent if self.ch_is('e') || self.ch_is('E') { self.scan_float_exponent(); let pos = self.pos; self.check_float_base(start_bpos, pos, base); - return token::Float(self.name_from(start_bpos)); + return (token::Float, self.symbol_from(start_bpos)); } // but we certainly have an integer! - token::Integer(self.name_from(start_bpos)) - } - } - - /// Scan over `n_digits` hex digits, stopping at `delim`, reporting an - /// error if too many or too few digits are encountered. - fn scan_hex_digits(&mut self, n_digits: usize, delim: char, below_0x7f_only: bool) -> bool { - debug!("scanning {} digits until {:?}", n_digits, delim); - let start_bpos = self.pos; - let mut accum_int = 0; - - let mut valid = true; - for _ in 0..n_digits { - if self.is_eof() { - let last_bpos = self.pos; - self.fatal_span_(start_bpos, - last_bpos, - "unterminated numeric character escape").raise(); - } - if self.ch_is(delim) { - let last_bpos = self.pos; - self.err_span_(start_bpos, - last_bpos, - "numeric character escape is too short"); - valid = false; - break; - } - let c = self.ch.unwrap_or('\x00'); - accum_int *= 16; - accum_int += c.to_digit(16).unwrap_or_else(|| { - self.err_span_char(self.pos, - self.next_pos, - "invalid character in numeric character escape", - c); - - valid = false; - 0 - }); - self.bump(); - } - - if below_0x7f_only && accum_int >= 0x80 { - self.err_span_(start_bpos, - self.pos, - "this form of character escape may only be used with characters in \ - the range [\\x00-\\x7f]"); - valid = false; - } - - match char::from_u32(accum_int) { - Some(_) => valid, - None => { - let last_bpos = self.pos; - self.err_span_(start_bpos, last_bpos, "invalid numeric character escape"); - false - } + (token::Integer, self.symbol_from(start_bpos)) } } - /// Scan for a single (possibly escaped) byte or char - /// in a byte, (non-raw) byte string, char, or (non-raw) string literal. - /// `start` is the position of `first_source_char`, which is already consumed. - /// - /// Returns `true` if there was a valid char/byte. - fn scan_char_or_byte(&mut self, - start: BytePos, - first_source_char: char, - ascii_only: bool, - delim: char) - -> bool - { - match first_source_char { - '\\' => { - // '\X' for some X must be a character constant: - let escaped = self.ch; - let escaped_pos = self.pos; - self.bump(); - match escaped { - None => {} // EOF here is an error that will be checked later. - Some(e) => { - return match e { - 'n' | 'r' | 't' | '\\' | '\'' | '"' | '0' => true, - 'x' => self.scan_byte_escape(delim, !ascii_only), - 'u' => { - let valid = if self.ch_is('{') { - self.scan_unicode_escape(delim) && !ascii_only - } else { - let span = self.mk_sp(start, self.pos); - let mut suggestion = "\\u{".to_owned(); - let mut err = self.sess.span_diagnostic.struct_span_err( - span, - "incorrect unicode escape sequence", - ); - let mut i = 0; - while let (Some(ch), true) = (self.ch, i < 6) { - if ch.is_digit(16) { - suggestion.push(ch); - self.bump(); - i += 1; - } else { - break; - } - } - if i != 0 { - suggestion.push('}'); - err.span_suggestion( - self.mk_sp(start, self.pos), - "format of unicode escape sequences uses braces", - suggestion, - Applicability::MaybeIncorrect, - ); - } else { - err.span_help( - span, - "format of unicode escape sequences is `\\u{...}`", - ); - } - err.emit(); - false - }; - if ascii_only { - self.err_span_(start, - self.pos, - "unicode escape sequences cannot be used as a \ - byte or in a byte string"); - } - valid - - } - '\n' if delim == '"' => { - self.consume_whitespace(); - true - } - '\r' if delim == '"' && self.ch_is('\n') => { - self.consume_whitespace(); - true - } - c => { - let pos = self.pos; - let mut err = self.struct_err_span_char(escaped_pos, - pos, - if ascii_only { - "unknown byte escape" - } else { - "unknown character \ - escape" - }, - c); - if e == '\r' { - err.span_help(self.mk_sp(escaped_pos, pos), - "this is an isolated carriage return; consider \ - checking your editor and version control \ - settings"); - } - if (e == '{' || e == '}') && !ascii_only { - err.span_help(self.mk_sp(escaped_pos, pos), - "if used in a formatting string, curly braces \ - are escaped with `{{` and `}}`"); - } - err.emit(); - false - } - } - } - } - } - '\t' | '\n' | '\r' | '\'' if delim == '\'' => { - let pos = self.pos; - self.err_span_char(start, - pos, - if ascii_only { - "byte constant must be escaped" - } else { - "character constant must be escaped" - }, - first_source_char); - return false; - } - '\r' => { - if self.ch_is('\n') { - self.bump(); - return true; - } else { - self.err_span_(start, - self.pos, - "bare CR not allowed in string, use \\r instead"); - return false; - } - } - _ => { - if ascii_only && first_source_char > '\x7F' { - let pos = self.pos; - self.err_span_(start, - pos, - "byte constant must be ASCII. Use a \\xHH escape for a \ - non-ASCII byte"); - return false; - } - } - } - true - } - - /// Scan over a `\u{...}` escape - /// - /// At this point, we have already seen the `\` and the `u`, the `{` is the current character. - /// We will read a hex number (with `_` separators), with 1 to 6 actual digits, - /// and pass over the `}`. - fn scan_unicode_escape(&mut self, delim: char) -> bool { - self.bump(); // past the { - let start_bpos = self.pos; - let mut valid = true; - - if let Some('_') = self.ch { - // disallow leading `_` - self.err_span_(self.pos, - self.next_pos, - "invalid start of unicode escape"); - valid = false; - } - - let count = self.scan_digits(16, 16); - - if count > 6 { - self.err_span_(start_bpos, - self.pos, - "overlong unicode escape (must have at most 6 hex digits)"); - valid = false; - } - - loop { - match self.ch { - Some('}') => { - if valid && count == 0 { - self.err_span_(start_bpos, - self.pos, - "empty unicode escape (must have at least 1 hex digit)"); - valid = false; - } - self.bump(); // past the ending `}` - break; - }, - Some(c) => { - if c == delim { - self.err_span_(self.pos, - self.pos, - "unterminated unicode escape (needed a `}`)"); - valid = false; - break; - } else if valid { - self.err_span_char(start_bpos, - self.pos, - "invalid character in unicode escape", - c); - valid = false; - } - }, - None => { - self.fatal_span_(start_bpos, - self.pos, - "unterminated unicode escape (found EOF)").raise(); - } - } - self.bump(); - } - - valid - } - /// Scan over a float exponent. fn scan_float_exponent(&mut self) { if self.ch_is('e') || self.ch_is('E') { @@ -1197,7 +781,7 @@ impl<'a> StringReader<'a> { } } - fn binop(&mut self, op: token::BinOpToken) -> token::Token { + fn binop(&mut self, op: token::BinOpToken) -> TokenKind { self.bump(); if self.ch_is('=') { self.bump(); @@ -1209,7 +793,7 @@ impl<'a> StringReader<'a> { /// Returns the next token from the string, advances the input past that /// token, and updates the interner - fn next_token_inner(&mut self) -> Result { + fn next_token_inner(&mut self) -> Result { let c = self.ch; if ident_start(c) { @@ -1245,32 +829,25 @@ impl<'a> StringReader<'a> { self.bump(); } - return Ok(self.with_str_from(start, |string| { - // FIXME: perform NFKC normalization here. (Issue #2253) - let ident = self.mk_ident(string); - - if is_raw_ident && (ident.is_path_segment_keyword() || - ident.name == keywords::Underscore.name()) { - self.fatal_span_(raw_start, self.pos, - &format!("`r#{}` is not currently supported.", ident.name) - ).raise(); - } - - if is_raw_ident { - let span = self.mk_sp(raw_start, self.pos); - self.sess.raw_identifier_spans.borrow_mut().push(span); + // FIXME: perform NFKC normalization here. (Issue #2253) + let name = self.symbol_from(start); + if is_raw_ident { + let span = self.mk_sp(raw_start, self.pos); + if !name.can_be_raw() { + self.err_span(span, &format!("`{}` cannot be a raw identifier", name)); } + self.sess.raw_identifier_spans.borrow_mut().push(span); + } - token::Ident(ident, is_raw_ident) - })); + return Ok(token::Ident(name, is_raw_ident)); } } if is_dec_digit(c) { - let num = self.scan_number(c.unwrap()); + let (kind, symbol) = self.scan_number(c.unwrap()); let suffix = self.scan_optional_raw_name(); - debug!("next_token_inner: scanned number {:?}, {:?}", num, suffix); - return Ok(token::Literal(num, suffix)); + debug!("next_token_inner: scanned number {:?}, {:?}, {:?}", kind, symbol, suffix); + return Ok(TokenKind::lit(kind, symbol, suffix)); } match c.expect("next_token_inner called at EOF") { @@ -1417,200 +994,89 @@ impl<'a> StringReader<'a> { self.bump(); let start = self.pos; - // the eof will be picked up by the final `'` check below - let c2 = self.ch.unwrap_or('\x00'); - self.bump(); - // If the character is an ident start not followed by another single // quote, then this is a lifetime name: - if ident_start(Some(c2)) && !self.ch_is('\'') { + let starts_with_number = self.ch.unwrap_or('\x00').is_numeric(); + if (ident_start(self.ch) || starts_with_number) && !self.nextch_is('\'') { + self.bump(); while ident_continue(self.ch) { self.bump(); } // lifetimes shouldn't end with a single quote // if we find one, then this is an invalid character literal if self.ch_is('\'') { - self.err_span_(start_with_quote, self.next_pos, - "character literal may only contain one codepoint"); + let symbol = self.symbol_from(start); self.bump(); - return Ok(token::Literal(token::Err(Symbol::intern("??")), None)) + self.validate_char_escape(start_with_quote); + return Ok(TokenKind::lit(token::Char, symbol, None)); + } + if starts_with_number { + // this is a recovered lifetime written `'1`, error but accept it + self.err_span_( + start_with_quote, + self.pos, + "lifetimes cannot start with a number", + ); } // Include the leading `'` in the real identifier, for macro // expansion purposes. See #12512 for the gory details of why // this is necessary. - let ident = self.with_str_from(start, |lifetime_name| { - self.mk_ident(&format!("'{}", lifetime_name)) - }); - - return Ok(token::Lifetime(ident)); + return Ok(token::Lifetime(self.symbol_from(start_with_quote))); } - - let valid = self.scan_char_or_byte(start, c2, /* ascii_only */ false, '\''); - - if !self.ch_is('\'') { - let pos = self.pos; - - loop { - self.bump(); - if self.ch_is('\'') { - let start = self.src_index(start); - let end = self.src_index(self.pos); - self.bump(); - let span = self.mk_sp(start_with_quote, self.pos); - self.sess.span_diagnostic - .struct_span_err(span, - "character literal may only contain one codepoint") - .span_suggestion( - span, - "if you meant to write a `str` literal, use double quotes", - format!("\"{}\"", &self.src[start..end]), - Applicability::MachineApplicable - ).emit(); - return Ok(token::Literal(token::Err(Symbol::intern("??")), None)) - } - if self.ch_is('\n') || self.is_eof() || self.ch_is('/') { - // Only attempt to infer single line string literals. If we encounter - // a slash, bail out in order to avoid nonsensical suggestion when - // involving comments. - break; - } - } - - self.fatal_span_verbose(start_with_quote, pos, - String::from("character literal may only contain one codepoint")).raise(); - } - - let id = if valid { - self.name_from(start) - } else { - Symbol::intern("0") - }; - - self.bump(); // advance ch past token + let msg = "unterminated character literal"; + let symbol = self.scan_single_quoted_string(start_with_quote, msg); + self.validate_char_escape(start_with_quote); let suffix = self.scan_optional_raw_name(); - - Ok(token::Literal(token::Char(id), suffix)) + Ok(TokenKind::lit(token::Char, symbol, suffix)) } 'b' => { self.bump(); - let lit = match self.ch { - Some('\'') => self.scan_byte(), - Some('"') => self.scan_byte_string(), - Some('r') => self.scan_raw_byte_string(), + let (kind, symbol) = match self.ch { + Some('\'') => { + let start_with_quote = self.pos; + self.bump(); + let msg = "unterminated byte constant"; + let symbol = self.scan_single_quoted_string(start_with_quote, msg); + self.validate_byte_escape(start_with_quote); + (token::Byte, symbol) + }, + Some('"') => { + let start_with_quote = self.pos; + let msg = "unterminated double quote byte string"; + let symbol = self.scan_double_quoted_string(msg); + self.validate_byte_str_escape(start_with_quote); + (token::ByteStr, symbol) + }, + Some('r') => { + let (start, end, hash_count) = self.scan_raw_string(); + let symbol = self.symbol_from_to(start, end); + self.validate_raw_byte_str_escape(start, end); + + (token::ByteStrRaw(hash_count), symbol) + } _ => unreachable!(), // Should have been a token::Ident above. }; let suffix = self.scan_optional_raw_name(); - Ok(token::Literal(lit, suffix)) + Ok(TokenKind::lit(kind, symbol, suffix)) } '"' => { - let start_bpos = self.pos; - let mut valid = true; - self.bump(); - - while !self.ch_is('"') { - if self.is_eof() { - let last_bpos = self.pos; - self.fatal_span_(start_bpos, - last_bpos, - "unterminated double quote string").raise(); - } - - let ch_start = self.pos; - let ch = self.ch.unwrap(); - self.bump(); - valid &= self.scan_char_or_byte(ch_start, ch, /* ascii_only */ false, '"'); - } - // adjust for the ASCII " at the start of the literal - let id = if valid { - self.name_from(start_bpos + BytePos(1)) - } else { - Symbol::intern("??") - }; - self.bump(); + let start_with_quote = self.pos; + let msg = "unterminated double quote string"; + let symbol = self.scan_double_quoted_string(msg); + self.validate_str_escape(start_with_quote); let suffix = self.scan_optional_raw_name(); - - Ok(token::Literal(token::Str_(id), suffix)) + Ok(TokenKind::lit(token::Str, symbol, suffix)) } 'r' => { - let start_bpos = self.pos; - self.bump(); - let mut hash_count: u16 = 0; - while self.ch_is('#') { - if hash_count == 65535 { - let bpos = self.next_pos; - self.fatal_span_(start_bpos, - bpos, - "too many `#` symbols: raw strings may be \ - delimited by up to 65535 `#` symbols").raise(); - } - self.bump(); - hash_count += 1; - } - - if self.is_eof() { - self.fail_unterminated_raw_string(start_bpos, hash_count); - } else if !self.ch_is('"') { - let last_bpos = self.pos; - let curr_char = self.ch.unwrap(); - self.fatal_span_char(start_bpos, - last_bpos, - "found invalid character; only `#` is allowed \ - in raw string delimitation", - curr_char).raise(); - } - self.bump(); - let content_start_bpos = self.pos; - let mut content_end_bpos; - let mut valid = true; - 'outer: loop { - if self.is_eof() { - self.fail_unterminated_raw_string(start_bpos, hash_count); - } - // if self.ch_is('"') { - // content_end_bpos = self.pos; - // for _ in 0..hash_count { - // self.bump(); - // if !self.ch_is('#') { - // continue 'outer; - let c = self.ch.unwrap(); - match c { - '"' => { - content_end_bpos = self.pos; - for _ in 0..hash_count { - self.bump(); - if !self.ch_is('#') { - continue 'outer; - } - } - break; - } - '\r' => { - if !self.nextch_is('\n') { - let last_bpos = self.pos; - self.err_span_(start_bpos, - last_bpos, - "bare CR not allowed in raw string, use \\r \ - instead"); - valid = false; - } - } - _ => (), - } - self.bump(); - } - - self.bump(); - let id = if valid { - self.name_from_to(content_start_bpos, content_end_bpos) - } else { - Symbol::intern("??") - }; + let (start, end, hash_count) = self.scan_raw_string(); + let symbol = self.symbol_from_to(start, end); + self.validate_raw_str_escape(start, end); let suffix = self.scan_optional_raw_name(); - Ok(token::Literal(token::StrRaw(id, hash_count), suffix)) + Ok(TokenKind::lit(token::StrRaw(hash_count), symbol, suffix)) } '-' => { if self.nextch_is('>') { @@ -1672,12 +1138,6 @@ impl<'a> StringReader<'a> { } } - fn consume_whitespace(&mut self) { - while is_pattern_whitespace(self.ch) && !self.is_eof() { - self.bump(); - } - } - fn read_to_eol(&mut self) -> String { let mut val = String::new(); while !self.ch_is('\n') && !self.is_eof() { @@ -1711,85 +1171,77 @@ impl<'a> StringReader<'a> { (self.ch_is('#') && self.nextch_is('!') && !self.nextnextch_is('[')) } - fn scan_byte(&mut self) -> token::Lit { - self.bump(); + fn scan_single_quoted_string(&mut self, + start_with_quote: BytePos, + unterminated_msg: &str) -> Symbol { + // assumes that first `'` is consumed let start = self.pos; - - // the eof will be picked up by the final `'` check below - let c2 = self.ch.unwrap_or('\x00'); - self.bump(); - - let valid = self.scan_char_or_byte(start, - c2, - // ascii_only = - true, - '\''); - if !self.ch_is('\'') { - // Byte offsetting here is okay because the - // character before position `start` are an - // ascii single quote and ascii 'b'. - let pos = self.pos; - self.fatal_span_verbose(start - BytePos(2), - pos, - "unterminated byte constant".to_string()).raise(); - } - - let id = if valid { - self.name_from(start) + // lex `'''` as a single char, for recovery + if self.ch_is('\'') && self.nextch_is('\'') { + self.bump(); } else { - Symbol::intern("?") - }; - self.bump(); // advance ch past token - - token::Byte(id) - } + let mut first = true; + loop { + if self.ch_is('\'') { + break; + } + if self.ch_is('\\') && (self.nextch_is('\'') || self.nextch_is('\\')) { + self.bump(); + self.bump(); + } else { + // Only attempt to infer single line string literals. If we encounter + // a slash, bail out in order to avoid nonsensical suggestion when + // involving comments. + if self.is_eof() + || (self.ch_is('/') && !first) + || (self.ch_is('\n') && !self.nextch_is('\'')) { + + self.fatal_span_(start_with_quote, self.pos, unterminated_msg.into()) + .raise() + } + self.bump(); + } + first = false; + } + } - #[inline] - fn scan_byte_escape(&mut self, delim: char, below_0x7f_only: bool) -> bool { - self.scan_hex_digits(2, delim, below_0x7f_only) + let id = self.symbol_from(start); + self.bump(); + id } - fn scan_byte_string(&mut self) -> token::Lit { + fn scan_double_quoted_string(&mut self, unterminated_msg: &str) -> Symbol { + debug_assert!(self.ch_is('\"')); + let start_with_quote = self.pos; self.bump(); let start = self.pos; - let mut valid = true; - while !self.ch_is('"') { if self.is_eof() { let pos = self.pos; - self.fatal_span_(start, pos, "unterminated double quote byte string").raise(); + self.fatal_span_(start_with_quote, pos, unterminated_msg).raise(); + } + if self.ch_is('\\') && (self.nextch_is('\\') || self.nextch_is('"')) { + self.bump(); } - - let ch_start = self.pos; - let ch = self.ch.unwrap(); self.bump(); - valid &= self.scan_char_or_byte(ch_start, - ch, - // ascii_only = - true, - '"'); } - - let id = if valid { - self.name_from(start) - } else { - Symbol::intern("??") - }; + let id = self.symbol_from(start); self.bump(); - - token::ByteStr(id) + id } - fn scan_raw_byte_string(&mut self) -> token::Lit { + /// Scans a raw (byte) string, returning byte position range for `""` + /// (including quotes) along with `#` character count in `(b)r##...""##...`; + fn scan_raw_string(&mut self) -> (BytePos, BytePos, u16) { let start_bpos = self.pos; self.bump(); - let mut hash_count = 0; + let mut hash_count: u16 = 0; while self.ch_is('#') { if hash_count == 65535 { let bpos = self.next_pos; self.fatal_span_(start_bpos, bpos, - "too many `#` symbols: raw byte strings may be \ + "too many `#` symbols: raw strings may be \ delimited by up to 65535 `#` symbols").raise(); } self.bump(); @@ -1799,13 +1251,13 @@ impl<'a> StringReader<'a> { if self.is_eof() { self.fail_unterminated_raw_string(start_bpos, hash_count); } else if !self.ch_is('"') { - let pos = self.pos; - let ch = self.ch.unwrap(); + let last_bpos = self.pos; + let curr_char = self.ch.unwrap(); self.fatal_span_char(start_bpos, - pos, - "found invalid character; only `#` is allowed in raw \ - string delimitation", - ch).raise(); + last_bpos, + "found invalid character; only `#` is allowed \ + in raw string delimitation", + curr_char).raise(); } self.bump(); let content_start_bpos = self.pos; @@ -1825,19 +1277,106 @@ impl<'a> StringReader<'a> { } break; } - Some(c) => { - if c > '\x7F' { - let pos = self.pos; - self.err_span_char(pos, pos, "raw byte string must be ASCII", c); - } - } + _ => (), } self.bump(); } self.bump(); - token::ByteStrRaw(self.name_from_to(content_start_bpos, content_end_bpos), hash_count) + (content_start_bpos, content_end_bpos, hash_count) + } + + fn validate_char_escape(&self, start_with_quote: BytePos) { + let lit = self.str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1)); + if let Err((off, err)) = unescape::unescape_char(lit) { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(start_with_quote, self.pos), + unescape::Mode::Char, + 0..off, + err, + ) + } + } + + fn validate_byte_escape(&self, start_with_quote: BytePos) { + let lit = self.str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1)); + if let Err((off, err)) = unescape::unescape_byte(lit) { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(start_with_quote, self.pos), + unescape::Mode::Byte, + 0..off, + err, + ) + } + } + + fn validate_str_escape(&self, start_with_quote: BytePos) { + let lit = self.str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1)); + unescape::unescape_str(lit, &mut |range, c| { + if let Err(err) = c { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(start_with_quote, self.pos), + unescape::Mode::Str, + range, + err, + ) + } + }) + } + + fn validate_raw_str_escape(&self, content_start: BytePos, content_end: BytePos) { + let lit = self.str_from_to(content_start, content_end); + unescape::unescape_raw_str(lit, &mut |range, c| { + if let Err(err) = c { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)), + unescape::Mode::Str, + range, + err, + ) + } + }) + } + + fn validate_raw_byte_str_escape(&self, content_start: BytePos, content_end: BytePos) { + let lit = self.str_from_to(content_start, content_end); + unescape::unescape_raw_byte_str(lit, &mut |range, c| { + if let Err(err) = c { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)), + unescape::Mode::ByteStr, + range, + err, + ) + } + }) + } + + fn validate_byte_str_escape(&self, start_with_quote: BytePos) { + let lit = self.str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1)); + unescape::unescape_byte_str(lit, &mut |range, c| { + if let Err(err) = c { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(start_with_quote, self.pos), + unescape::Mode::ByteStr, + range, + err, + ) + } + }) } } @@ -1873,6 +1412,7 @@ fn is_block_doc_comment(s: &str) -> bool { res } +/// Determine whether `c` is a valid start for an ident. fn ident_start(c: Option) -> bool { let c = match c { Some(c) => c, @@ -1901,26 +1441,27 @@ fn char_at(s: &str, byte: usize) -> char { mod tests { use super::*; - use crate::ast::{Ident, CrateConfig}; + use crate::ast::CrateConfig; use crate::symbol::Symbol; - use crate::source_map::SourceMap; + use crate::source_map::{SourceMap, FilePathMapping}; use crate::feature_gate::UnstableFeatures; use crate::parse::token; use crate::diagnostics::plugin::ErrorMap; - use crate::with_globals; + use crate::with_default_globals; use std::io; use std::path::PathBuf; - use syntax_pos::{BytePos, Span, NO_EXPANSION}; - use rustc_data_structures::fx::FxHashSet; + use syntax_pos::{BytePos, Span, NO_EXPANSION, edition::Edition}; + use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc_data_structures::sync::Lock; fn mk_sess(sm: Lrc) -> ParseSess { let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()), Some(sm.clone()), false, + false, false); ParseSess { - span_diagnostic: errors::Handler::with_emitter(true, false, Box::new(emitter)), + span_diagnostic: errors::Handler::with_emitter(true, None, Box::new(emitter)), unstable_features: UnstableFeatures::from_environment(), config: CrateConfig::default(), included_mod_stack: Lock::new(Vec::new()), @@ -1929,6 +1470,10 @@ mod tests { raw_identifier_spans: Lock::new(Vec::new()), registered_diagnostics: Lock::new(ErrorMap::new()), buffered_lints: Lock::new(vec![]), + edition: Edition::from_session(), + ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), + param_attr_spans: Lock::new(Vec::new()), + let_chains_spans: Lock::new(Vec::new()), } } @@ -1938,39 +1483,43 @@ mod tests { teststr: String) -> StringReader<'a> { let sf = sm.new_source_file(PathBuf::from(teststr.clone()).into(), teststr); - StringReader::new(sess, sf, None) + let mut sr = StringReader::new_raw(sess, sf, None); + if sr.advance_token().is_err() { + sr.emit_fatal_errors(); + FatalError.raise(); + } + sr } #[test] fn t1() { - with_globals(|| { + with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); let mut string_reader = setup(&sm, &sh, "/* my source file */ fn main() { println!(\"zebra\"); }\n" .to_string()); - let id = Ident::from_str("fn"); - assert_eq!(string_reader.next_token().tok, token::Comment); - assert_eq!(string_reader.next_token().tok, token::Whitespace); + assert_eq!(string_reader.next_token(), token::Comment); + assert_eq!(string_reader.next_token(), token::Whitespace); let tok1 = string_reader.next_token(); - let tok2 = TokenAndSpan { - tok: token::Ident(id, false), - sp: Span::new(BytePos(21), BytePos(23), NO_EXPANSION), - }; - assert_eq!(tok1.tok, tok2.tok); - assert_eq!(tok1.sp, tok2.sp); - assert_eq!(string_reader.next_token().tok, token::Whitespace); + let tok2 = Token::new( + mk_ident("fn"), + Span::new(BytePos(21), BytePos(23), NO_EXPANSION), + ); + assert_eq!(tok1.kind, tok2.kind); + assert_eq!(tok1.span, tok2.span); + assert_eq!(string_reader.next_token(), token::Whitespace); // the 'main' id is already read: assert_eq!(string_reader.pos.clone(), BytePos(28)); // read another token: let tok3 = string_reader.next_token(); - let tok4 = TokenAndSpan { - tok: mk_ident("main"), - sp: Span::new(BytePos(24), BytePos(28), NO_EXPANSION), - }; - assert_eq!(tok3.tok, tok4.tok); - assert_eq!(tok3.sp, tok4.sp); + let tok4 = Token::new( + mk_ident("main"), + Span::new(BytePos(24), BytePos(28), NO_EXPANSION), + ); + assert_eq!(tok3.kind, tok4.kind); + assert_eq!(tok3.span, tok4.span); // the lparen is already read: assert_eq!(string_reader.pos.clone(), BytePos(29)) }) @@ -1978,20 +1527,24 @@ mod tests { // check that the given reader produces the desired stream // of tokens (stop checking after exhausting the expected vec) - fn check_tokenization(mut string_reader: StringReader<'_>, expected: Vec) { + fn check_tokenization(mut string_reader: StringReader<'_>, expected: Vec) { for expected_tok in &expected { - assert_eq!(&string_reader.next_token().tok, expected_tok); + assert_eq!(&string_reader.next_token(), expected_tok); } } // make the identifier by looking up the string in the interner - fn mk_ident(id: &str) -> token::Token { - token::Token::from_ast_ident(Ident::from_str(id)) + fn mk_ident(id: &str) -> TokenKind { + token::Ident(Symbol::intern(id), false) + } + + fn mk_lit(kind: token::LitKind, symbol: &str, suffix: Option<&str>) -> TokenKind { + TokenKind::lit(kind, Symbol::intern(symbol), suffix.map(Symbol::intern)) } #[test] fn doublecolonparsing() { - with_globals(|| { + with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); check_tokenization(setup(&sm, &sh, "a b".to_string()), @@ -2001,7 +1554,7 @@ mod tests { #[test] fn dcparsing_2() { - with_globals(|| { + with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); check_tokenization(setup(&sm, &sh, "a::b".to_string()), @@ -2011,7 +1564,7 @@ mod tests { #[test] fn dcparsing_3() { - with_globals(|| { + with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); check_tokenization(setup(&sm, &sh, "a ::b".to_string()), @@ -2021,7 +1574,7 @@ mod tests { #[test] fn dcparsing_4() { - with_globals(|| { + with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); check_tokenization(setup(&sm, &sh, "a:: b".to_string()), @@ -2031,76 +1584,72 @@ mod tests { #[test] fn character_a() { - with_globals(|| { + with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'a'".to_string()).next_token().tok, - token::Literal(token::Char(Symbol::intern("a")), None)); + assert_eq!(setup(&sm, &sh, "'a'".to_string()).next_token(), + mk_lit(token::Char, "a", None)); }) } #[test] fn character_space() { - with_globals(|| { + with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "' '".to_string()).next_token().tok, - token::Literal(token::Char(Symbol::intern(" ")), None)); + assert_eq!(setup(&sm, &sh, "' '".to_string()).next_token(), + mk_lit(token::Char, " ", None)); }) } #[test] fn character_escaped() { - with_globals(|| { + with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'\\n'".to_string()).next_token().tok, - token::Literal(token::Char(Symbol::intern("\\n")), None)); + assert_eq!(setup(&sm, &sh, "'\\n'".to_string()).next_token(), + mk_lit(token::Char, "\\n", None)); }) } #[test] fn lifetime_name() { - with_globals(|| { + with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'abc".to_string()).next_token().tok, - token::Lifetime(Ident::from_str("'abc"))); + assert_eq!(setup(&sm, &sh, "'abc".to_string()).next_token(), + token::Lifetime(Symbol::intern("'abc"))); }) } #[test] fn raw_string() { - with_globals(|| { + with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()) - .next_token() - .tok, - token::Literal(token::StrRaw(Symbol::intern("\"#a\\b\x00c\""), 3), None)); + assert_eq!(setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), + mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None)); }) } #[test] fn literal_suffixes() { - with_globals(|| { + with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); macro_rules! test { ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ - assert_eq!(setup(&sm, &sh, format!("{}suffix", $input)).next_token().tok, - token::Literal(token::$tok_type(Symbol::intern($tok_contents)), - Some(Symbol::intern("suffix")))); + assert_eq!(setup(&sm, &sh, format!("{}suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, Some("suffix"))); // with a whitespace separator: - assert_eq!(setup(&sm, &sh, format!("{} suffix", $input)).next_token().tok, - token::Literal(token::$tok_type(Symbol::intern($tok_contents)), - None)); + assert_eq!(setup(&sm, &sh, format!("{} suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, None)); }} } test!("'a'", Char, "a"); test!("b'a'", Byte, "a"); - test!("\"a\"", Str_, "a"); + test!("\"a\"", Str, "a"); test!("b\"a\"", ByteStr, "a"); test!("1234", Integer, "1234"); test!("0b101", Integer, "0b101"); @@ -2108,15 +1657,12 @@ mod tests { test!("1.0", Float, "1.0"); test!("1.0e10", Float, "1.0e10"); - assert_eq!(setup(&sm, &sh, "2us".to_string()).next_token().tok, - token::Literal(token::Integer(Symbol::intern("2")), - Some(Symbol::intern("us")))); - assert_eq!(setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token().tok, - token::Literal(token::StrRaw(Symbol::intern("raw"), 3), - Some(Symbol::intern("suffix")))); - assert_eq!(setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token().tok, - token::Literal(token::ByteStrRaw(Symbol::intern("raw"), 3), - Some(Symbol::intern("suffix")))); + assert_eq!(setup(&sm, &sh, "2us".to_string()).next_token(), + mk_lit(token::Integer, "2", Some("us"))); + assert_eq!(setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::StrRaw(3), "raw", Some("suffix"))); + assert_eq!(setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::ByteStrRaw(3), "raw", Some("suffix"))); }) } @@ -2129,31 +1675,26 @@ mod tests { #[test] fn nested_block_comments() { - with_globals(|| { + with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); let mut lexer = setup(&sm, &sh, "/* /* */ */'a'".to_string()); - match lexer.next_token().tok { - token::Comment => {} - _ => panic!("expected a comment!"), - } - assert_eq!(lexer.next_token().tok, - token::Literal(token::Char(Symbol::intern("a")), None)); + assert_eq!(lexer.next_token(), token::Comment); + assert_eq!(lexer.next_token(), mk_lit(token::Char, "a", None)); }) } #[test] fn crlf_comments() { - with_globals(|| { + with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); let mut lexer = setup(&sm, &sh, "// test\r\n/// test\r\n".to_string()); let comment = lexer.next_token(); - assert_eq!(comment.tok, token::Comment); - assert_eq!((comment.sp.lo(), comment.sp.hi()), (BytePos(0), BytePos(7))); - assert_eq!(lexer.next_token().tok, token::Whitespace); - assert_eq!(lexer.next_token().tok, - token::DocComment(Symbol::intern("/// test"))); + assert_eq!(comment.kind, token::Comment); + assert_eq!((comment.span.lo(), comment.span.hi()), (BytePos(0), BytePos(7))); + assert_eq!(lexer.next_token(), token::Whitespace); + assert_eq!(lexer.next_token(), token::DocComment(Symbol::intern("/// test"))); }) } } diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index 0db36c84cdfeb..99d9d40a45b93 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -1,13 +1,45 @@ +use syntax_pos::Span; + use crate::print::pprust::token_to_string; use crate::parse::lexer::{StringReader, UnmatchedBrace}; -use crate::parse::{token, PResult}; +use crate::parse::token::{self, Token}; +use crate::parse::PResult; use crate::tokenstream::{DelimSpan, IsJoint::*, TokenStream, TokenTree, TreeAndJoint}; impl<'a> StringReader<'a> { + crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { + let mut tt_reader = TokenTreesReader { + string_reader: self, + token: Token::dummy(), + open_braces: Vec::new(), + unmatched_braces: Vec::new(), + matching_delim_spans: Vec::new(), + last_unclosed_found_span: None, + }; + let res = tt_reader.parse_all_token_trees(); + (res, tt_reader.unmatched_braces) + } +} + +struct TokenTreesReader<'a> { + string_reader: StringReader<'a>, + token: Token, + /// Stack of open delimiters and their spans. Used for error message. + open_braces: Vec<(token::DelimToken, Span)>, + unmatched_braces: Vec, + /// The type and spans for all braces + /// + /// Used only for error recovery when arriving to EOF with mismatched braces. + matching_delim_spans: Vec<(token::DelimToken, Span, Span)>, + last_unclosed_found_span: Option, +} + +impl<'a> TokenTreesReader<'a> { // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`. - crate fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> { + fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> { let mut tts = Vec::new(); + self.real_token(); while self.token != token::Eof { tts.push(self.parse_token_tree()?); } @@ -19,7 +51,7 @@ impl<'a> StringReader<'a> { fn parse_token_trees_until_close_delim(&mut self) -> TokenStream { let mut tts = vec![]; loop { - if let token::CloseDelim(..) = self.token { + if let token::CloseDelim(..) = self.token.kind { return TokenStream::new(tts); } @@ -34,11 +66,12 @@ impl<'a> StringReader<'a> { } fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> { - let sm = self.sess.source_map(); - match self.token { + let sm = self.string_reader.sess.source_map(); + match self.token.kind { token::Eof => { let msg = "this file contains an un-closed delimiter"; - let mut err = self.sess.span_diagnostic.struct_span_err(self.span, msg); + let mut err = self.string_reader.sess.span_diagnostic + .struct_span_err(self.token.span, msg); for &(_, sp) in &self.open_braces { err.span_label(sp, "un-closed delimiter"); } @@ -46,13 +79,12 @@ impl<'a> StringReader<'a> { if let Some((delim, _)) = self.open_braces.last() { if let Some((_, open_sp, close_sp)) = self.matching_delim_spans.iter() .filter(|(d, open_sp, close_sp)| { - - if let Some(close_padding) = sm.span_to_margin(*close_sp) { - if let Some(open_padding) = sm.span_to_margin(*open_sp) { - return delim == d && close_padding != open_padding; + if let Some(close_padding) = sm.span_to_margin(*close_sp) { + if let Some(open_padding) = sm.span_to_margin(*open_sp) { + return delim == d && close_padding != open_padding; + } } - } - false + false }).next() // these are in reverse order as they get inserted on close, but { // we want the last open/first close err.span_label( @@ -69,10 +101,10 @@ impl<'a> StringReader<'a> { }, token::OpenDelim(delim) => { // The span for beginning of the delimited section - let pre_span = self.span; + let pre_span = self.token.span; // Parse the open delimiter. - self.open_braces.push((delim, self.span)); + self.open_braces.push((delim, self.token.span)); self.real_token(); // Parse the token trees within the delimiters. @@ -81,9 +113,9 @@ impl<'a> StringReader<'a> { let tts = self.parse_token_trees_until_close_delim(); // Expand to cover the entire delimited token tree - let delim_span = DelimSpan::from_pair(pre_span, self.span); + let delim_span = DelimSpan::from_pair(pre_span, self.token.span); - match self.token { + match self.token.kind { // Correct delimiter. token::CloseDelim(d) if d == delim => { let (open_brace, open_brace_span) = self.open_braces.pop().unwrap(); @@ -93,7 +125,7 @@ impl<'a> StringReader<'a> { self.matching_delim_spans.clear(); } else { self.matching_delim_spans.push( - (open_brace, open_brace_span, self.span), + (open_brace, open_brace_span, self.token.span), ); } // Parse the close delimiter. @@ -103,16 +135,16 @@ impl<'a> StringReader<'a> { token::CloseDelim(other) => { let mut unclosed_delimiter = None; let mut candidate = None; - if self.last_unclosed_found_span != Some(self.span) { + if self.last_unclosed_found_span != Some(self.token.span) { // do not complain about the same unclosed delimiter multiple times - self.last_unclosed_found_span = Some(self.span); + self.last_unclosed_found_span = Some(self.token.span); // This is a conservative error: only report the last unclosed // delimiter. The previous unclosed delimiters could actually be // closed! The parser just hasn't gotten to them yet. if let Some(&(_, sp)) = self.open_braces.last() { unclosed_delimiter = Some(sp); }; - if let Some(current_padding) = sm.span_to_margin(self.span) { + if let Some(current_padding) = sm.span_to_margin(self.token.span) { for (brace, brace_span) in &self.open_braces { if let Some(padding) = sm.span_to_margin(*brace_span) { // high likelihood of these two corresponding @@ -126,7 +158,7 @@ impl<'a> StringReader<'a> { self.unmatched_braces.push(UnmatchedBrace { expected_delim: tok, found_delim: other, - found_span: self.span, + found_span: self.token.span, unclosed_span: unclosed_delimiter, candidate_span: candidate, }); @@ -164,20 +196,28 @@ impl<'a> StringReader<'a> { // matching opening delimiter). let token_str = token_to_string(&self.token); let msg = format!("unexpected close delimiter: `{}`", token_str); - let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg); - err.span_label(self.span, "unexpected close delimiter"); + let mut err = self.string_reader.sess.span_diagnostic + .struct_span_err(self.token.span, &msg); + err.span_label(self.token.span, "unexpected close delimiter"); Err(err) }, _ => { - let tt = TokenTree::Token(self.span, self.token.clone()); + let tt = TokenTree::Token(self.token.take()); // Note that testing for joint-ness here is done via the raw // source span as the joint-ness is a property of the raw source // rather than wanting to take `override_span` into account. - let raw = self.span_src_raw; + // Additionally, we actually check if the *next* pair of tokens + // is joint, but this is equivalent to checking the current pair. + let raw = self.string_reader.peek_span_src_raw; self.real_token(); - let is_joint = raw.hi() == self.span_src_raw.lo() && token::is_op(&self.token); + let is_joint = raw.hi() == self.string_reader.peek_span_src_raw.lo() + && self.token.is_op(); Ok((tt, if is_joint { Joint } else { NonJoint })) } } } + + fn real_token(&mut self) { + self.token = self.string_reader.real_token(); + } } diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs new file mode 100644 index 0000000000000..ef55bf6b92933 --- /dev/null +++ b/src/libsyntax/parse/literal.rs @@ -0,0 +1,470 @@ +//! Code related to parsing literals. + +use crate::ast::{self, Lit, LitKind}; +use crate::parse::parser::Parser; +use crate::parse::PResult; +use crate::parse::token::{self, Token, TokenKind}; +use crate::parse::unescape::{unescape_char, unescape_byte}; +use crate::parse::unescape::{unescape_str, unescape_byte_str}; +use crate::parse::unescape::{unescape_raw_str, unescape_raw_byte_str}; +use crate::print::pprust; +use crate::symbol::{kw, sym, Symbol}; +use crate::tokenstream::{TokenStream, TokenTree}; + +use errors::{Applicability, Handler}; +use log::debug; +use rustc_data_structures::sync::Lrc; +use syntax_pos::Span; + +use std::ascii; + +crate enum LitError { + NotLiteral, + LexerError, + InvalidSuffix, + InvalidIntSuffix, + InvalidFloatSuffix, + NonDecimalFloat(u32), + IntTooLarge, +} + +impl LitError { + fn report(&self, diag: &Handler, lit: token::Lit, span: Span) { + let token::Lit { kind, suffix, .. } = lit; + match *self { + // `NotLiteral` is not an error by itself, so we don't report + // it and give the parser opportunity to try something else. + LitError::NotLiteral => {} + // `LexerError` *is* an error, but it was already reported + // by lexer, so here we don't report it the second time. + LitError::LexerError => {} + LitError::InvalidSuffix => { + expect_no_suffix( + diag, span, &format!("{} {} literal", kind.article(), kind.descr()), suffix + ); + } + LitError::InvalidIntSuffix => { + let suf = suffix.expect("suffix error with no suffix").as_str(); + if looks_like_width_suffix(&['i', 'u'], &suf) { + // If it looks like a width, try to be helpful. + let msg = format!("invalid width `{}` for integer literal", &suf[1..]); + diag.struct_span_err(span, &msg) + .help("valid widths are 8, 16, 32, 64 and 128") + .emit(); + } else { + let msg = format!("invalid suffix `{}` for integer literal", suf); + diag.struct_span_err(span, &msg) + .span_label(span, format!("invalid suffix `{}`", suf)) + .help("the suffix must be one of the integral types (`u32`, `isize`, etc)") + .emit(); + } + } + LitError::InvalidFloatSuffix => { + let suf = suffix.expect("suffix error with no suffix").as_str(); + if looks_like_width_suffix(&['f'], &suf) { + // If it looks like a width, try to be helpful. + let msg = format!("invalid width `{}` for float literal", &suf[1..]); + diag.struct_span_err(span, &msg) + .help("valid widths are 32 and 64") + .emit(); + } else { + let msg = format!("invalid suffix `{}` for float literal", suf); + diag.struct_span_err(span, &msg) + .span_label(span, format!("invalid suffix `{}`", suf)) + .help("valid suffixes are `f32` and `f64`") + .emit(); + } + } + LitError::NonDecimalFloat(base) => { + let descr = match base { + 16 => "hexadecimal", + 8 => "octal", + 2 => "binary", + _ => unreachable!(), + }; + diag.struct_span_err(span, &format!("{} float literal is not supported", descr)) + .span_label(span, "not supported") + .emit(); + } + LitError::IntTooLarge => { + diag.struct_span_err(span, "integer literal is too large") + .emit(); + } + } + } +} + +impl LitKind { + /// Converts literal token into a semantic literal. + fn from_lit_token(lit: token::Lit) -> Result { + let token::Lit { kind, symbol, suffix } = lit; + if suffix.is_some() && !kind.may_have_suffix() { + return Err(LitError::InvalidSuffix); + } + + Ok(match kind { + token::Bool => { + assert!(symbol == kw::True || symbol == kw::False); + LitKind::Bool(symbol == kw::True) + } + token::Byte => return unescape_byte(&symbol.as_str()) + .map(LitKind::Byte).map_err(|_| LitError::LexerError), + token::Char => return unescape_char(&symbol.as_str()) + .map(LitKind::Char).map_err(|_| LitError::LexerError), + + // There are some valid suffixes for integer and float literals, + // so all the handling is done internally. + token::Integer => return integer_lit(symbol, suffix), + token::Float => return float_lit(symbol, suffix), + + token::Str => { + // If there are no characters requiring special treatment we can + // reuse the symbol from the token. Otherwise, we must generate a + // new symbol because the string in the LitKind is different to the + // string in the token. + let s = symbol.as_str(); + let symbol = if s.contains(&['\\', '\r'][..]) { + let mut buf = String::with_capacity(s.len()); + let mut error = Ok(()); + unescape_str(&s, &mut |_, unescaped_char| { + match unescaped_char { + Ok(c) => buf.push(c), + Err(_) => error = Err(LitError::LexerError), + } + }); + error?; + Symbol::intern(&buf) + } else { + symbol + }; + LitKind::Str(symbol, ast::StrStyle::Cooked) + } + token::StrRaw(n) => { + // Ditto. + let s = symbol.as_str(); + let symbol = if s.contains('\r') { + let mut buf = String::with_capacity(s.len()); + let mut error = Ok(()); + unescape_raw_str(&s, &mut |_, unescaped_char| { + match unescaped_char { + Ok(c) => buf.push(c), + Err(_) => error = Err(LitError::LexerError), + } + }); + error?; + buf.shrink_to_fit(); + Symbol::intern(&buf) + } else { + symbol + }; + LitKind::Str(symbol, ast::StrStyle::Raw(n)) + } + token::ByteStr => { + let s = symbol.as_str(); + let mut buf = Vec::with_capacity(s.len()); + let mut error = Ok(()); + unescape_byte_str(&s, &mut |_, unescaped_byte| { + match unescaped_byte { + Ok(c) => buf.push(c), + Err(_) => error = Err(LitError::LexerError), + } + }); + error?; + buf.shrink_to_fit(); + LitKind::ByteStr(Lrc::new(buf)) + } + token::ByteStrRaw(_) => { + let s = symbol.as_str(); + let bytes = if s.contains('\r') { + let mut buf = Vec::with_capacity(s.len()); + let mut error = Ok(()); + unescape_raw_byte_str(&s, &mut |_, unescaped_byte| { + match unescaped_byte { + Ok(c) => buf.push(c), + Err(_) => error = Err(LitError::LexerError), + } + }); + error?; + buf.shrink_to_fit(); + buf + } else { + symbol.to_string().into_bytes() + }; + + LitKind::ByteStr(Lrc::new(bytes)) + }, + token::Err => LitKind::Err(symbol), + }) + } + + /// Attempts to recover a token from semantic literal. + /// This function is used when the original token doesn't exist (e.g. the literal is created + /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). + pub fn to_lit_token(&self) -> token::Lit { + let (kind, symbol, suffix) = match *self { + LitKind::Str(symbol, ast::StrStyle::Cooked) => { + // Don't re-intern unless the escaped string is different. + let s = &symbol.as_str(); + let escaped = s.escape_default().to_string(); + let symbol = if escaped == *s { symbol } else { Symbol::intern(&escaped) }; + (token::Str, symbol, None) + } + LitKind::Str(symbol, ast::StrStyle::Raw(n)) => { + (token::StrRaw(n), symbol, None) + } + LitKind::ByteStr(ref bytes) => { + let string = bytes.iter().cloned().flat_map(ascii::escape_default) + .map(Into::::into).collect::(); + (token::ByteStr, Symbol::intern(&string), None) + } + LitKind::Byte(byte) => { + let string: String = ascii::escape_default(byte).map(Into::::into).collect(); + (token::Byte, Symbol::intern(&string), None) + } + LitKind::Char(ch) => { + let string: String = ch.escape_default().map(Into::::into).collect(); + (token::Char, Symbol::intern(&string), None) + } + LitKind::Int(n, ty) => { + let suffix = match ty { + ast::LitIntType::Unsigned(ty) => Some(ty.to_symbol()), + ast::LitIntType::Signed(ty) => Some(ty.to_symbol()), + ast::LitIntType::Unsuffixed => None, + }; + (token::Integer, sym::integer(n), suffix) + } + LitKind::Float(symbol, ty) => { + (token::Float, symbol, Some(ty.to_symbol())) + } + LitKind::FloatUnsuffixed(symbol) => { + (token::Float, symbol, None) + } + LitKind::Bool(value) => { + let symbol = if value { kw::True } else { kw::False }; + (token::Bool, symbol, None) + } + LitKind::Err(symbol) => { + (token::Err, symbol, None) + } + }; + + token::Lit::new(kind, symbol, suffix) + } +} + +impl Lit { + /// Converts literal token into an AST literal. + fn from_lit_token(token: token::Lit, span: Span) -> Result { + Ok(Lit { token, node: LitKind::from_lit_token(token)?, span }) + } + + /// Converts arbitrary token into an AST literal. + crate fn from_token(token: &Token) -> Result { + let lit = match token.kind { + token::Ident(name, false) if name == kw::True || name == kw::False => + token::Lit::new(token::Bool, name, None), + token::Literal(lit) => + lit, + token::Interpolated(ref nt) => { + if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt { + if let ast::ExprKind::Lit(lit) = &expr.node { + return Ok(lit.clone()); + } + } + return Err(LitError::NotLiteral); + } + _ => return Err(LitError::NotLiteral) + }; + + Lit::from_lit_token(lit, token.span) + } + + /// Attempts to recover an AST literal from semantic literal. + /// This function is used when the original token doesn't exist (e.g. the literal is created + /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). + pub fn from_lit_kind(node: LitKind, span: Span) -> Lit { + Lit { token: node.to_lit_token(), node, span } + } + + /// Losslessly convert an AST literal into a token stream. + crate fn tokens(&self) -> TokenStream { + let token = match self.token.kind { + token::Bool => token::Ident(self.token.symbol, false), + _ => token::Literal(self.token), + }; + TokenTree::token(token, self.span).into() + } +} + +impl<'a> Parser<'a> { + /// Matches `lit = true | false | token_lit`. + crate fn parse_lit(&mut self) -> PResult<'a, Lit> { + let mut recovered = None; + if self.token == token::Dot { + // Attempt to recover `.4` as `0.4`. + recovered = self.look_ahead(1, |next_token| { + if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) + = next_token.kind { + if self.token.span.hi() == next_token.span.lo() { + let s = String::from("0.") + &symbol.as_str(); + let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix); + return Some(Token::new(kind, self.token.span.to(next_token.span))); + } + } + None + }); + if let Some(token) = &recovered { + self.bump(); + self.diagnostic() + .struct_span_err(token.span, "float literals must have an integer part") + .span_suggestion( + token.span, + "must have an integer part", + pprust::token_to_string(token), + Applicability::MachineApplicable, + ) + .emit(); + } + } + + let token = recovered.as_ref().unwrap_or(&self.token); + match Lit::from_token(token) { + Ok(lit) => { + self.bump(); + Ok(lit) + } + Err(LitError::NotLiteral) => { + let msg = format!("unexpected token: {}", self.this_token_descr()); + Err(self.span_fatal(token.span, &msg)) + } + Err(err) => { + let (lit, span) = (token.expect_lit(), token.span); + self.bump(); + err.report(&self.sess.span_diagnostic, lit, span); + // Pack possible quotes and prefixes from the original literal into + // the error literal's symbol so they can be pretty-printed faithfully. + let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None); + let symbol = Symbol::intern(&pprust::literal_to_string(suffixless_lit)); + let lit = token::Lit::new(token::Err, symbol, lit.suffix); + Lit::from_lit_token(lit, span).map_err(|_| unreachable!()) + } + } + } +} + +crate fn expect_no_suffix(diag: &Handler, sp: Span, kind: &str, suffix: Option) { + if let Some(suf) = suffix { + let mut err = if kind == "a tuple index" && + [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suf) { + // #59553: warn instead of reject out of hand to allow the fix to percolate + // through the ecosystem when people fix their macros + let mut err = diag.struct_span_warn( + sp, + &format!("suffixes on {} are invalid", kind), + ); + err.note(&format!( + "`{}` is *temporarily* accepted on tuple index fields as it was \ + incorrectly accepted on stable for a few releases", + suf, + )); + err.help( + "on proc macros, you'll want to use `syn::Index::from` or \ + `proc_macro::Literal::*_unsuffixed` for code that will desugar \ + to tuple field access", + ); + err.note( + "for more context, see https://github.com/rust-lang/rust/issues/60210", + ); + err + } else { + diag.struct_span_err(sp, &format!("suffixes on {} are invalid", kind)) + }; + err.span_label(sp, format!("invalid suffix `{}`", suf)); + err.emit(); + } +} + +// Checks if `s` looks like i32 or u1234 etc. +fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { + s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) +} + +fn strip_underscores(symbol: Symbol) -> Symbol { + // Do not allocate a new string unless necessary. + let s = symbol.as_str(); + if s.contains('_') { + let mut s = s.to_string(); + s.retain(|c| c != '_'); + return Symbol::intern(&s); + } + symbol +} + +fn filtered_float_lit(symbol: Symbol, suffix: Option, base: u32) + -> Result { + debug!("filtered_float_lit: {:?}, {:?}, {:?}", symbol, suffix, base); + if base != 10 { + return Err(LitError::NonDecimalFloat(base)); + } + Ok(match suffix { + Some(suf) => match suf { + sym::f32 => LitKind::Float(symbol, ast::FloatTy::F32), + sym::f64 => LitKind::Float(symbol, ast::FloatTy::F64), + _ => return Err(LitError::InvalidFloatSuffix), + } + None => LitKind::FloatUnsuffixed(symbol) + }) +} + +fn float_lit(symbol: Symbol, suffix: Option) -> Result { + debug!("float_lit: {:?}, {:?}", symbol, suffix); + filtered_float_lit(strip_underscores(symbol), suffix, 10) +} + +fn integer_lit(symbol: Symbol, suffix: Option) -> Result { + debug!("integer_lit: {:?}, {:?}", symbol, suffix); + let symbol = strip_underscores(symbol); + let s = symbol.as_str(); + + let mut base = 10; + if s.len() > 1 && s.as_bytes()[0] == b'0' { + match s.as_bytes()[1] { + b'x' => base = 16, + b'o' => base = 8, + b'b' => base = 2, + _ => {} + } + } + + let ty = match suffix { + Some(suf) => match suf { + sym::isize => ast::LitIntType::Signed(ast::IntTy::Isize), + sym::i8 => ast::LitIntType::Signed(ast::IntTy::I8), + sym::i16 => ast::LitIntType::Signed(ast::IntTy::I16), + sym::i32 => ast::LitIntType::Signed(ast::IntTy::I32), + sym::i64 => ast::LitIntType::Signed(ast::IntTy::I64), + sym::i128 => ast::LitIntType::Signed(ast::IntTy::I128), + sym::usize => ast::LitIntType::Unsigned(ast::UintTy::Usize), + sym::u8 => ast::LitIntType::Unsigned(ast::UintTy::U8), + sym::u16 => ast::LitIntType::Unsigned(ast::UintTy::U16), + sym::u32 => ast::LitIntType::Unsigned(ast::UintTy::U32), + sym::u64 => ast::LitIntType::Unsigned(ast::UintTy::U64), + sym::u128 => ast::LitIntType::Unsigned(ast::UintTy::U128), + // `1f64` and `2f32` etc. are valid float literals, and + // `fxxx` looks more like an invalid float literal than invalid integer literal. + _ if suf.as_str().starts_with('f') => return filtered_float_lit(symbol, suffix, base), + _ => return Err(LitError::InvalidIntSuffix), + } + _ => ast::LitIntType::Unsuffixed + }; + + let s = &s[if base != 10 { 2 } else { 0 } ..]; + u128::from_str_radix(s, base).map(|i| LitKind::Int(i, ty)).map_err(|_| { + // Small bases are lexed as if they were base 10, e.g, the string + // might be `0b10201`. This will cause the conversion above to fail, + // but these kinds of errors are already reported by the lexer. + let from_lexer = + base < 10 && s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base)); + if from_lexer { LitError::LexerError } else { LitError::IntTooLarge } + }) +} diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b2d4d97d57d89..e19eab371f44e 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -5,19 +5,19 @@ use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId}; use crate::source_map::{SourceMap, FilePathMapping}; use crate::feature_gate::UnstableFeatures; use crate::parse::parser::Parser; -use crate::symbol::Symbol; +use crate::parse::parser::emit_unclosed_delims; +use crate::parse::token::TokenKind; use crate::tokenstream::{TokenStream, TokenTree}; use crate::diagnostics::plugin::ErrorMap; -use crate::print::pprust::token_to_string; +use crate::print::pprust; -use errors::{FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder}; +use errors::{Applicability, FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder}; use rustc_data_structures::sync::{Lrc, Lock}; use syntax_pos::{Span, SourceFile, FileName, MultiSpan}; -use log::debug; +use syntax_pos::edition::Edition; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use std::borrow::Cow; -use std::iter; use std::path::{Path, PathBuf}; use std::str; @@ -25,18 +25,22 @@ pub type PResult<'a, T> = Result>; #[macro_use] pub mod parser; - +pub mod attr; pub mod lexer; pub mod token; -pub mod attr; -pub mod classify; +crate mod classify; +crate mod diagnostics; +crate mod literal; +crate mod unescape; +crate mod unescape_error_reporting; /// Info about a parsing session. pub struct ParseSess { pub span_diagnostic: Handler, pub unstable_features: UnstableFeatures, pub config: CrateConfig, + pub edition: Edition, pub missing_fragment_specifiers: Lock>, /// Places where raw identifiers were used. This is used for feature-gating raw identifiers. pub raw_identifier_spans: Lock>, @@ -46,6 +50,13 @@ pub struct ParseSess { included_mod_stack: Lock>, source_map: Lrc, pub buffered_lints: Lock>, + /// Contains the spans of block expressions that could have been incomplete based on the + /// operation token that followed it, but that the parser cannot identify without further + /// analysis. + pub ambiguous_block_expr_parse: Lock>, + pub param_attr_spans: Lock>, + // Places where `let` exprs were used and should be feature gated according to `let_chains`. + pub let_chains_spans: Lock>, } impl ParseSess { @@ -53,7 +64,7 @@ impl ParseSess { let cm = Lrc::new(SourceMap::new(file_path_mapping)); let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, - false, + None, Some(cm.clone())); ParseSess::with_span_handler(handler, cm) } @@ -69,6 +80,10 @@ impl ParseSess { included_mod_stack: Lock::new(vec![]), source_map, buffered_lints: Lock::new(vec![]), + edition: Edition::from_session(), + ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), + param_attr_spans: Lock::new(Vec::new()), + let_chains_spans: Lock::new(Vec::new()), } } @@ -92,6 +107,24 @@ impl ParseSess { }); }); } + + /// Extend an error with a suggestion to wrap an expression with parentheses to allow the + /// parser to continue parsing the following operation as part of the same expression. + pub fn expr_parentheses_needed( + &self, + err: &mut DiagnosticBuilder<'_>, + span: Span, + alt_snippet: Option, + ) { + if let Some(snippet) = self.source_map().span_to_snippet(span).ok().or(alt_snippet) { + err.span_suggestion( + span, + "parentheses are required to parse this as an expression", + format!("({})", snippet), + Applicability::MachineApplicable, + ); + } + } } #[derive(Clone)] @@ -141,8 +174,14 @@ pub fn parse_stream_from_source_str( source: String, sess: &ParseSess, override_span: Option, -) -> (TokenStream, Vec) { - source_file_to_stream(sess, sess.source_map().new_source_file(name, source), override_span) +) -> TokenStream { + let (stream, mut errors) = source_file_to_stream( + sess, + sess.source_map().new_source_file(name, source), + override_span, + ); + emit_unclosed_delims(&mut errors, &sess.span_diagnostic); + stream } /// Creates a new parser from a source string. @@ -178,7 +217,7 @@ pub fn maybe_new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path) /// Given a session, a crate config, a path, and a span, add /// the file at the given path to the source_map, and return a parser. /// On an error, use the given span as the source of the problem. -crate fn new_sub_parser_from_file<'a>(sess: &'a ParseSess, +pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess, path: &Path, directory_ownership: DirectoryOwnership, module_name: Option, @@ -203,10 +242,10 @@ fn maybe_source_file_to_parser( ) -> Result, Vec> { let end_pos = source_file.end_pos; let (stream, unclosed_delims) = maybe_file_to_stream(sess, source_file, None)?; - let mut parser = stream_to_parser(sess, stream); + let mut parser = stream_to_parser(sess, stream, None); parser.unclosed_delims = unclosed_delims; - if parser.token == token::Eof && parser.span.is_dummy() { - parser.span = Span::new(end_pos, end_pos, parser.span.ctxt()); + if parser.token == token::Eof && parser.token.span.is_dummy() { + parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt()); } Ok(parser) @@ -215,7 +254,7 @@ fn maybe_source_file_to_parser( // must preserve old name for now, because quote! from the *existing* // compiler expands into it pub fn new_parser_from_tts(sess: &ParseSess, tts: Vec) -> Parser<'_> { - stream_to_parser(sess, tts.into_iter().collect()) + stream_to_parser(sess, tts.into_iter().collect(), crate::MACRO_ARGUMENTS) } @@ -260,25 +299,25 @@ pub fn source_file_to_stream( } /// Given a source file, produces a sequence of token trees. Returns any buffered errors from -/// parsing the token tream. +/// parsing the token stream. pub fn maybe_file_to_stream( sess: &ParseSess, source_file: Lrc, override_span: Option, ) -> Result<(TokenStream, Vec), Vec> { - let mut srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?; - srdr.real_token(); + let srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?; + let (token_trees, unmatched_braces) = srdr.into_token_trees(); - match srdr.parse_all_token_trees() { - Ok(stream) => Ok((stream, srdr.unmatched_braces)), + match token_trees { + Ok(stream) => Ok((stream, unmatched_braces)), Err(err) => { let mut buffer = Vec::with_capacity(1); err.buffer(&mut buffer); // Not using `emit_unclosed_delims` to use `db.buffer` - for unmatched in srdr.unmatched_braces { + for unmatched in unmatched_braces { let mut db = sess.span_diagnostic.struct_span_err(unmatched.found_span, &format!( "incorrect close delimiter: `{}`", - token_to_string(&token::Token::CloseDelim(unmatched.found_delim)), + pprust::token_kind_to_string(&token::CloseDelim(unmatched.found_delim)), )); db.span_label(unmatched.found_span, "incorrect close delimiter"); if let Some(sp) = unmatched.candidate_span { @@ -295,477 +334,43 @@ pub fn maybe_file_to_stream( } /// Given stream and the `ParseSess`, produces a parser. -pub fn stream_to_parser(sess: &ParseSess, stream: TokenStream) -> Parser<'_> { - Parser::new(sess, stream, None, true, false) -} - -/// Parses a string representing a character literal into its final form. -/// Rather than just accepting/rejecting a given literal, unescapes it as -/// well. Can take any slice prefixed by a character escape. Returns the -/// character and the number of characters consumed. -fn char_lit(lit: &str, diag: Option<(Span, &Handler)>) -> (char, isize) { - use std::char; - - // Handle non-escaped chars first. - if lit.as_bytes()[0] != b'\\' { - // If the first byte isn't '\\' it might part of a multi-byte char, so - // get the char with chars(). - let c = lit.chars().next().unwrap(); - return (c, 1); - } - - // Handle escaped chars. - match lit.as_bytes()[1] as char { - '"' => ('"', 2), - 'n' => ('\n', 2), - 'r' => ('\r', 2), - 't' => ('\t', 2), - '\\' => ('\\', 2), - '\'' => ('\'', 2), - '0' => ('\0', 2), - 'x' => { - let v = u32::from_str_radix(&lit[2..4], 16).unwrap(); - let c = char::from_u32(v).unwrap(); - (c, 4) - } - 'u' => { - assert_eq!(lit.as_bytes()[2], b'{'); - let idx = lit.find('}').unwrap(); - - // All digits and '_' are ascii, so treat each byte as a char. - let mut v: u32 = 0; - for c in lit[3..idx].bytes() { - let c = char::from(c); - if c != '_' { - let x = c.to_digit(16).unwrap(); - v = v.checked_mul(16).unwrap().checked_add(x).unwrap(); - } - } - let c = char::from_u32(v).unwrap_or_else(|| { - if let Some((span, diag)) = diag { - let mut diag = diag.struct_span_err(span, "invalid unicode character escape"); - if v > 0x10FFFF { - diag.help("unicode escape must be at most 10FFFF").emit(); - } else { - diag.help("unicode escape must not be a surrogate").emit(); - } - } - '\u{FFFD}' - }); - (c, (idx + 1) as isize) - } - _ => panic!("lexer should have rejected a bad character escape {}", lit) - } -} - -/// Parses a string representing a string literal into its final form. Does unescaping. -pub fn str_lit(lit: &str, diag: Option<(Span, &Handler)>) -> String { - debug!("str_lit: given {}", lit.escape_default()); - let mut res = String::with_capacity(lit.len()); - - let error = |i| format!("lexer should have rejected {} at {}", lit, i); - - /// Eat everything up to a non-whitespace. - fn eat<'a>(it: &mut iter::Peekable>) { - loop { - match it.peek().map(|x| x.1) { - Some(' ') | Some('\n') | Some('\r') | Some('\t') => { - it.next(); - }, - _ => { break; } - } - } - } - - let mut chars = lit.char_indices().peekable(); - while let Some((i, c)) = chars.next() { - match c { - '\\' => { - let ch = chars.peek().unwrap_or_else(|| { - panic!("{}", error(i)) - }).1; - - if ch == '\n' { - eat(&mut chars); - } else if ch == '\r' { - chars.next(); - let ch = chars.peek().unwrap_or_else(|| { - panic!("{}", error(i)) - }).1; - - if ch != '\n' { - panic!("lexer accepted bare CR"); - } - eat(&mut chars); - } else { - // otherwise, a normal escape - let (c, n) = char_lit(&lit[i..], diag); - for _ in 0..n - 1 { // we don't need to move past the first \ - chars.next(); - } - res.push(c); - } - }, - '\r' => { - let ch = chars.peek().unwrap_or_else(|| { - panic!("{}", error(i)) - }).1; - - if ch != '\n' { - panic!("lexer accepted bare CR"); - } - chars.next(); - res.push('\n'); - } - c => res.push(c), - } - } - - res.shrink_to_fit(); // probably not going to do anything, unless there was an escape. - debug!("parse_str_lit: returning {}", res); - res -} - -/// Parses a string representing a raw string literal into its final form. The -/// only operation this does is convert embedded CRLF into a single LF. -fn raw_str_lit(lit: &str) -> String { - debug!("raw_str_lit: given {}", lit.escape_default()); - let mut res = String::with_capacity(lit.len()); - - let mut chars = lit.chars().peekable(); - while let Some(c) = chars.next() { - if c == '\r' { - if *chars.peek().unwrap() != '\n' { - panic!("lexer accepted bare CR"); - } - chars.next(); - res.push('\n'); - } else { - res.push(c); - } - } - - res.shrink_to_fit(); - res -} - -// check if `s` looks like i32 or u1234 etc. -fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { - s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) -} - -macro_rules! err { - ($opt_diag:expr, |$span:ident, $diag:ident| $($body:tt)*) => { - match $opt_diag { - Some(($span, $diag)) => { $($body)* } - None => return None, - } - } -} - -crate fn lit_token(lit: token::Lit, suf: Option, diag: Option<(Span, &Handler)>) - -> (bool /* suffix illegal? */, Option) { - use ast::LitKind; - - match lit { - token::Byte(i) => (true, Some(LitKind::Byte(byte_lit(&i.as_str()).0))), - token::Char(i) => (true, Some(LitKind::Char(char_lit(&i.as_str(), diag).0))), - token::Err(i) => (true, Some(LitKind::Err(i))), - - // There are some valid suffixes for integer and float literals, - // so all the handling is done internally. - token::Integer(s) => (false, integer_lit(&s.as_str(), suf, diag)), - token::Float(s) => (false, float_lit(&s.as_str(), suf, diag)), - - token::Str_(mut sym) => { - // If there are no characters requiring special treatment we can - // reuse the symbol from the Token. Otherwise, we must generate a - // new symbol because the string in the LitKind is different to the - // string in the Token. - let s = &sym.as_str(); - if s.as_bytes().iter().any(|&c| c == b'\\' || c == b'\r') { - sym = Symbol::intern(&str_lit(s, diag)); - } - (true, Some(LitKind::Str(sym, ast::StrStyle::Cooked))) - } - token::StrRaw(mut sym, n) => { - // Ditto. - let s = &sym.as_str(); - if s.contains('\r') { - sym = Symbol::intern(&raw_str_lit(s)); - } - (true, Some(LitKind::Str(sym, ast::StrStyle::Raw(n)))) - } - token::ByteStr(i) => { - (true, Some(LitKind::ByteStr(byte_str_lit(&i.as_str())))) - } - token::ByteStrRaw(i, _) => { - (true, Some(LitKind::ByteStr(Lrc::new(i.to_string().into_bytes())))) - } - } -} - -fn filtered_float_lit(data: Symbol, suffix: Option, diag: Option<(Span, &Handler)>) - -> Option { - debug!("filtered_float_lit: {}, {:?}", data, suffix); - let suffix = match suffix { - Some(suffix) => suffix, - None => return Some(ast::LitKind::FloatUnsuffixed(data)), - }; - - Some(match &*suffix.as_str() { - "f32" => ast::LitKind::Float(data, ast::FloatTy::F32), - "f64" => ast::LitKind::Float(data, ast::FloatTy::F64), - suf => { - err!(diag, |span, diag| { - if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { - // if it looks like a width, lets try to be helpful. - let msg = format!("invalid width `{}` for float literal", &suf[1..]); - diag.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit() - } else { - let msg = format!("invalid suffix `{}` for float literal", suf); - diag.struct_span_err(span, &msg) - .span_label(span, format!("invalid suffix `{}`", suf)) - .help("valid suffixes are `f32` and `f64`") - .emit(); - } - }); - - ast::LitKind::FloatUnsuffixed(data) - } - }) -} -fn float_lit(s: &str, suffix: Option, diag: Option<(Span, &Handler)>) - -> Option { - debug!("float_lit: {:?}, {:?}", s, suffix); - // FIXME #2252: bounds checking float literals is deferred until trans - - // Strip underscores without allocating a new String unless necessary. - let s2; - let s = if s.chars().any(|c| c == '_') { - s2 = s.chars().filter(|&c| c != '_').collect::(); - &s2 - } else { - s - }; - - filtered_float_lit(Symbol::intern(s), suffix, diag) -} - -/// Parses a string representing a byte literal into its final form. Similar to `char_lit`. -fn byte_lit(lit: &str) -> (u8, usize) { - let err = |i| format!("lexer accepted invalid byte literal {} step {}", lit, i); - - if lit.len() == 1 { - (lit.as_bytes()[0], 1) - } else { - assert_eq!(lit.as_bytes()[0], b'\\', "{}", err(0)); - let b = match lit.as_bytes()[1] { - b'"' => b'"', - b'n' => b'\n', - b'r' => b'\r', - b't' => b'\t', - b'\\' => b'\\', - b'\'' => b'\'', - b'0' => b'\0', - _ => { - match u64::from_str_radix(&lit[2..4], 16).ok() { - Some(c) => - if c > 0xFF { - panic!(err(2)) - } else { - return (c as u8, 4) - }, - None => panic!(err(3)) - } - } - }; - (b, 2) - } -} - -fn byte_str_lit(lit: &str) -> Lrc> { - let mut res = Vec::with_capacity(lit.len()); - - let error = |i| panic!("lexer should have rejected {} at {}", lit, i); - - /// Eat everything up to a non-whitespace. - fn eat>(it: &mut iter::Peekable) { - loop { - match it.peek().map(|x| x.1) { - Some(b' ') | Some(b'\n') | Some(b'\r') | Some(b'\t') => { - it.next(); - }, - _ => { break; } - } - } - } - - // byte string literals *must* be ASCII, but the escapes don't have to be - let mut chars = lit.bytes().enumerate().peekable(); - loop { - match chars.next() { - Some((i, b'\\')) => { - match chars.peek().unwrap_or_else(|| error(i)).1 { - b'\n' => eat(&mut chars), - b'\r' => { - chars.next(); - if chars.peek().unwrap_or_else(|| error(i)).1 != b'\n' { - panic!("lexer accepted bare CR"); - } - eat(&mut chars); - } - _ => { - // otherwise, a normal escape - let (c, n) = byte_lit(&lit[i..]); - // we don't need to move past the first \ - for _ in 0..n - 1 { - chars.next(); - } - res.push(c); - } - } - }, - Some((i, b'\r')) => { - if chars.peek().unwrap_or_else(|| error(i)).1 != b'\n' { - panic!("lexer accepted bare CR"); - } - chars.next(); - res.push(b'\n'); - } - Some((_, c)) => res.push(c), - None => break, - } - } - - Lrc::new(res) -} - -fn integer_lit(s: &str, suffix: Option, diag: Option<(Span, &Handler)>) - -> Option { - // s can only be ascii, byte indexing is fine - - // Strip underscores without allocating a new String unless necessary. - let s2; - let mut s = if s.chars().any(|c| c == '_') { - s2 = s.chars().filter(|&c| c != '_').collect::(); - &s2 - } else { - s - }; - - debug!("integer_lit: {}, {:?}", s, suffix); - - let mut base = 10; - let orig = s; - let mut ty = ast::LitIntType::Unsuffixed; - - if s.starts_with('0') && s.len() > 1 { - match s.as_bytes()[1] { - b'x' => base = 16, - b'o' => base = 8, - b'b' => base = 2, - _ => { } - } - } - - // 1f64 and 2f32 etc. are valid float literals. - if let Some(suf) = suffix { - if looks_like_width_suffix(&['f'], &suf.as_str()) { - let err = match base { - 16 => Some("hexadecimal float literal is not supported"), - 8 => Some("octal float literal is not supported"), - 2 => Some("binary float literal is not supported"), - _ => None, - }; - if let Some(err) = err { - err!(diag, |span, diag| { - diag.struct_span_err(span, err) - .span_label(span, "not supported") - .emit(); - }); - } - return filtered_float_lit(Symbol::intern(s), Some(suf), diag) - } - } - - if base != 10 { - s = &s[2..]; - } - - if let Some(suf) = suffix { - if suf.as_str().is_empty() { - err!(diag, |span, diag| diag.span_bug(span, "found empty literal suffix in Some")); - } - ty = match &*suf.as_str() { - "isize" => ast::LitIntType::Signed(ast::IntTy::Isize), - "i8" => ast::LitIntType::Signed(ast::IntTy::I8), - "i16" => ast::LitIntType::Signed(ast::IntTy::I16), - "i32" => ast::LitIntType::Signed(ast::IntTy::I32), - "i64" => ast::LitIntType::Signed(ast::IntTy::I64), - "i128" => ast::LitIntType::Signed(ast::IntTy::I128), - "usize" => ast::LitIntType::Unsigned(ast::UintTy::Usize), - "u8" => ast::LitIntType::Unsigned(ast::UintTy::U8), - "u16" => ast::LitIntType::Unsigned(ast::UintTy::U16), - "u32" => ast::LitIntType::Unsigned(ast::UintTy::U32), - "u64" => ast::LitIntType::Unsigned(ast::UintTy::U64), - "u128" => ast::LitIntType::Unsigned(ast::UintTy::U128), - suf => { - // i and u look like widths, so lets - // give an error message along those lines - err!(diag, |span, diag| { - if looks_like_width_suffix(&['i', 'u'], suf) { - let msg = format!("invalid width `{}` for integer literal", &suf[1..]); - diag.struct_span_err(span, &msg) - .help("valid widths are 8, 16, 32, 64 and 128") - .emit(); - } else { - let msg = format!("invalid suffix `{}` for numeric literal", suf); - diag.struct_span_err(span, &msg) - .span_label(span, format!("invalid suffix `{}`", suf)) - .help("the suffix must be one of the integral types \ - (`u32`, `isize`, etc)") - .emit(); - } - }); - - ty - } - } - } - - debug!("integer_lit: the type is {:?}, base {:?}, the new string is {:?}, the original \ - string was {:?}, the original suffix was {:?}", ty, base, s, orig, suffix); - - Some(match u128::from_str_radix(s, base) { - Ok(r) => ast::LitKind::Int(r, ty), - Err(_) => { - // small bases are lexed as if they were base 10, e.g, the string - // might be `0b10201`. This will cause the conversion above to fail, - // but these cases have errors in the lexer: we don't want to emit - // two errors, and we especially don't want to emit this error since - // it isn't necessarily true. - let already_errored = base < 10 && - s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base)); - - if !already_errored { - err!(diag, |span, diag| diag.span_err(span, "int literal is too large")); - } - ast::LitKind::Int(0, ty) - } - }) +pub fn stream_to_parser<'a>( + sess: &'a ParseSess, + stream: TokenStream, + subparser_name: Option<&'static str>, +) -> Parser<'a> { + Parser::new(sess, stream, None, true, false, subparser_name) +} + +/// Given stream, the `ParseSess` and the base directory, produces a parser. +/// +/// Use this function when you are creating a parser from the token stream +/// and also care about the current working directory of the parser (e.g., +/// you are trying to resolve modules defined inside a macro invocation). +/// +/// # Note +/// +/// The main usage of this function is outside of rustc, for those who uses +/// libsyntax as a library. Please do not remove this function while refactoring +/// just because it is not used in rustc codebase! +pub fn stream_to_parser_with_base_dir<'a>( + sess: &'a ParseSess, + stream: TokenStream, + base_dir: Directory<'a>, +) -> Parser<'a> { + Parser::new(sess, stream, Some(base_dir), true, false, None) } /// A sequence separator. pub struct SeqSep { /// The seperator token. - pub sep: Option, + pub sep: Option, /// `true` if a trailing separator is allowed. pub trailing_sep_allowed: bool, } impl SeqSep { - pub fn trailing_allowed(t: token::Token) -> SeqSep { + pub fn trailing_allowed(t: TokenKind) -> SeqSep { SeqSep { sep: Some(t), trailing_sep_allowed: true, @@ -783,14 +388,16 @@ impl SeqSep { #[cfg(test)] mod tests { use super::*; - use crate::ast::{self, Ident, PatKind}; + use crate::ast::{self, Name, PatKind}; use crate::attr::first_attr_value_str_by_name; use crate::ptr::P; + use crate::parse::token::Token; use crate::print::pprust::item_to_string; + use crate::symbol::{kw, sym}; use crate::tokenstream::{DelimSpan, TokenTree}; use crate::util::parser_testing::string_to_stream; use crate::util::parser_testing::{string_to_expr, string_to_item}; - use crate::with_globals; + use crate::with_default_globals; use syntax_pos::{Span, BytePos, Pos, NO_EXPANSION}; /// Parses an item. @@ -809,7 +416,7 @@ mod tests { #[should_panic] #[test] fn bad_path_expr_1() { - with_globals(|| { + with_default_globals(|| { string_to_expr("::abc::def::return".to_string()); }) } @@ -817,48 +424,43 @@ mod tests { // check the token-tree-ization of macros #[test] fn string_to_tts_macro () { - with_globals(|| { + with_default_globals(|| { let tts: Vec<_> = string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).trees().collect(); let tts: &[TokenTree] = &tts[..]; - match (tts.len(), tts.get(0), tts.get(1), tts.get(2), tts.get(3)) { - ( - 4, - Some(&TokenTree::Token(_, token::Ident(name_macro_rules, false))), - Some(&TokenTree::Token(_, token::Not)), - Some(&TokenTree::Token(_, token::Ident(name_zip, false))), - Some(&TokenTree::Delimited(_, macro_delim, ref macro_tts)), - ) - if name_macro_rules.name == "macro_rules" - && name_zip.name == "zip" => { + match tts { + [ + TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }), + TokenTree::Token(Token { kind: token::Not, .. }), + TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }), + TokenTree::Delimited(_, macro_delim, macro_tts) + ] + if name_macro_rules == &sym::macro_rules && name_zip.as_str() == "zip" => { let tts = ¯o_tts.trees().collect::>(); - match (tts.len(), tts.get(0), tts.get(1), tts.get(2)) { - ( - 3, - Some(&TokenTree::Delimited(_, first_delim, ref first_tts)), - Some(&TokenTree::Token(_, token::FatArrow)), - Some(&TokenTree::Delimited(_, second_delim, ref second_tts)), - ) - if macro_delim == token::Paren => { + match &tts[..] { + [ + TokenTree::Delimited(_, first_delim, first_tts), + TokenTree::Token(Token { kind: token::FatArrow, .. }), + TokenTree::Delimited(_, second_delim, second_tts), + ] + if macro_delim == &token::Paren => { let tts = &first_tts.trees().collect::>(); - match (tts.len(), tts.get(0), tts.get(1)) { - ( - 2, - Some(&TokenTree::Token(_, token::Dollar)), - Some(&TokenTree::Token(_, token::Ident(ident, false))), - ) - if first_delim == token::Paren && ident.name == "a" => {}, + match &tts[..] { + [ + TokenTree::Token(Token { kind: token::Dollar, .. }), + TokenTree::Token(Token { kind: token::Ident(name, false), .. }), + ] + if first_delim == &token::Paren && name.as_str() == "a" => {}, _ => panic!("value 3: {:?} {:?}", first_delim, first_tts), } let tts = &second_tts.trees().collect::>(); - match (tts.len(), tts.get(0), tts.get(1)) { - ( - 2, - Some(&TokenTree::Token(_, token::Dollar)), - Some(&TokenTree::Token(_, token::Ident(ident, false))), - ) - if second_delim == token::Paren && ident.name == "a" => {}, + match &tts[..] { + [ + TokenTree::Token(Token { kind: token::Dollar, .. }), + TokenTree::Token(Token { kind: token::Ident(name, false), .. }), + ] + if second_delim == &token::Paren && name.as_str() == "a" => {}, _ => panic!("value 4: {:?} {:?}", second_delim, second_tts), } }, @@ -872,30 +474,27 @@ mod tests { #[test] fn string_to_tts_1() { - with_globals(|| { + with_default_globals(|| { let tts = string_to_stream("fn a (b : i32) { b; }".to_string()); let expected = TokenStream::new(vec![ - TokenTree::Token(sp(0, 2), token::Ident(Ident::from_str("fn"), false)).into(), - TokenTree::Token(sp(3, 4), token::Ident(Ident::from_str("a"), false)).into(), + TokenTree::token(token::Ident(kw::Fn, false), sp(0, 2)).into(), + TokenTree::token(token::Ident(Name::intern("a"), false), sp(3, 4)).into(), TokenTree::Delimited( DelimSpan::from_pair(sp(5, 6), sp(13, 14)), token::DelimToken::Paren, TokenStream::new(vec![ - TokenTree::Token(sp(6, 7), - token::Ident(Ident::from_str("b"), false)).into(), - TokenTree::Token(sp(8, 9), token::Colon).into(), - TokenTree::Token(sp(10, 13), - token::Ident(Ident::from_str("i32"), false)).into(), + TokenTree::token(token::Ident(Name::intern("b"), false), sp(6, 7)).into(), + TokenTree::token(token::Colon, sp(8, 9)).into(), + TokenTree::token(token::Ident(sym::i32, false), sp(10, 13)).into(), ]).into(), ).into(), TokenTree::Delimited( DelimSpan::from_pair(sp(15, 16), sp(20, 21)), token::DelimToken::Brace, TokenStream::new(vec![ - TokenTree::Token(sp(17, 18), - token::Ident(Ident::from_str("b"), false)).into(), - TokenTree::Token(sp(18, 19), token::Semi).into(), + TokenTree::token(token::Ident(Name::intern("b"), false), sp(17, 18)).into(), + TokenTree::token(token::Semi, sp(18, 19)).into(), ]).into(), ).into() ]); @@ -905,7 +504,7 @@ mod tests { } #[test] fn parse_use() { - with_globals(|| { + with_default_globals(|| { let use_s = "use foo::bar::baz;"; let vitem = string_to_item(use_s.to_string()).unwrap(); let vitem_s = item_to_string(&vitem); @@ -919,7 +518,7 @@ mod tests { } #[test] fn parse_extern_crate() { - with_globals(|| { + with_default_globals(|| { let ex_s = "extern crate foo;"; let vitem = string_to_item(ex_s.to_string()).unwrap(); let vitem_s = item_to_string(&vitem); @@ -956,7 +555,7 @@ mod tests { } #[test] fn span_of_self_arg_pat_idents_are_correct() { - with_globals(|| { + with_default_globals(|| { let srcs = ["impl z { fn a (&self, &myarg: i32) {} }", "impl z { fn a (&mut self, &myarg: i32) {} }", @@ -976,7 +575,7 @@ mod tests { } #[test] fn parse_exprs () { - with_globals(|| { + with_default_globals(|| { // just make sure that they parse.... string_to_expr("3 + 4".to_string()); string_to_expr("a::z.froob(b,&(987+3))".to_string()); @@ -984,7 +583,7 @@ mod tests { } #[test] fn attrs_fix_bug () { - with_globals(|| { + with_default_globals(|| { string_to_item("pub fn mk_file_writer(path: &Path, flags: &[FileFlag]) -> Result, String> { #[cfg(windows)] @@ -1001,21 +600,21 @@ mod tests { } #[test] fn crlf_doc_comments() { - with_globals(|| { + with_default_globals(|| { let sess = ParseSess::new(FilePathMapping::empty()); let name_1 = FileName::Custom("crlf_source_1".to_string()); let source = "/// doc comment\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_1, source, &sess) .unwrap().unwrap(); - let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap(); - assert_eq!(doc, "/// doc comment"); + let doc = first_attr_value_str_by_name(&item.attrs, sym::doc).unwrap(); + assert_eq!(doc.as_str(), "/// doc comment"); let name_2 = FileName::Custom("crlf_source_2".to_string()); let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_2, source, &sess) .unwrap().unwrap(); - let docs = item.attrs.iter().filter(|a| a.path == "doc") + let docs = item.attrs.iter().filter(|a| a.path == sym::doc) .map(|a| a.value_str().unwrap().to_string()).collect::>(); let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; assert_eq!(&docs[..], b); @@ -1023,8 +622,8 @@ mod tests { let name_3 = FileName::Custom("clrf_source_3".to_string()); let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_3, source, &sess).unwrap().unwrap(); - let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap(); - assert_eq!(doc, "/** doc comment\n * with CRLF */"); + let doc = first_attr_value_str_by_name(&item.attrs, sym::doc).unwrap(); + assert_eq!(doc.as_str(), "/** doc comment\n * with CRLF */"); }); } @@ -1036,7 +635,7 @@ mod tests { new_parser_from_source_str(sess, name, source).parse_expr() } - with_globals(|| { + with_default_globals(|| { let sess = ParseSess::new(FilePathMapping::empty()); let expr = parse_expr_from_source_str(PathBuf::from("foo").into(), "foo!( fn main() { body } )".to_string(), &sess).unwrap(); @@ -1060,7 +659,7 @@ mod tests { // See `recurse_into_file_modules` in the parser. #[test] fn out_of_line_mod() { - with_globals(|| { + with_default_globals(|| { let sess = ParseSess::new(FilePathMapping::empty()); let item = parse_item_from_source_str( PathBuf::from("foo").into(), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fd5038a8614f2..b2e319a478e3a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1,7 +1,9 @@ +// ignore-tidy-filelength + use crate::ast::{AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy}; use crate::ast::{GenericBound, TraitBoundModifier}; use crate::ast::Unsafety; -use crate::ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind}; +use crate::ast::{Mod, AnonConst, Arg, Arm, Attribute, BindingMode, TraitItemKind}; use crate::ast::Block; use crate::ast::{BlockCheckMode, CaptureBy, Movability}; use crate::ast::{Constness, Crate}; @@ -13,7 +15,7 @@ use crate::ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; use crate::ast::{GenericParam, GenericParamKind}; use crate::ast::GenericArg; use crate::ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind}; -use crate::ast::{Label, Lifetime, Lit, LitKind}; +use crate::ast::{Label, Lifetime}; use crate::ast::Local; use crate::ast::MacStmtStyle; use crate::ast::{Mac, Mac_, MacDelimiter}; @@ -25,31 +27,33 @@ use crate::ast::{VariantData, StructField}; use crate::ast::StrStyle; use crate::ast::SelfKind; use crate::ast::{TraitItem, TraitRef, TraitObjectSyntax}; -use crate::ast::{Ty, TyKind, TypeBinding, GenericBounds}; +use crate::ast::{Ty, TyKind, AssocTyConstraint, AssocTyConstraintKind, GenericBounds}; use crate::ast::{Visibility, VisibilityKind, WhereClause, CrateSugar}; use crate::ast::{UseTree, UseTreeKind}; use crate::ast::{BinOpKind, UnOp}; use crate::ast::{RangeEnd, RangeSyntax}; use crate::{ast, attr}; use crate::ext::base::DummyResult; +use crate::ext::hygiene::SyntaxContext; use crate::source_map::{self, SourceMap, Spanned, respan}; -use crate::parse::{self, SeqSep, classify, token}; -use crate::parse::lexer::{TokenAndSpan, UnmatchedBrace}; +use crate::parse::{SeqSep, classify, literal, token}; +use crate::parse::lexer::UnmatchedBrace; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; -use crate::parse::token::DelimToken; +use crate::parse::token::{Token, TokenKind, DelimToken}; use crate::parse::{new_sub_parser_from_file, ParseSess, Directory, DirectoryOwnership}; -use crate::util::parser::{AssocOp, Fixity}; +use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par}; use crate::print::pprust; use crate::ptr::P; use crate::parse::PResult; use crate::ThinVec; use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; -use crate::symbol::{Symbol, keywords}; +use crate::symbol::{kw, sym, Symbol}; +use crate::parse::diagnostics::{Error, dummy_arg}; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; use rustc_target::spec::abi::{self, Abi}; -use syntax_pos::{Span, MultiSpan, BytePos, FileName}; -use log::{debug, trace}; +use syntax_pos::{Span, BytePos, DUMMY_SP, FileName}; +use log::debug; use std::borrow::Cow; use std::cmp; @@ -99,14 +103,14 @@ pub enum PathStyle { } #[derive(Clone, Copy, PartialEq, Debug)] -enum SemiColonMode { +crate enum SemiColonMode { Break, Ignore, Comma, } #[derive(Clone, Copy, PartialEq, Debug)] -enum BlockMode { +crate enum BlockMode { Break, Ignore, } @@ -118,23 +122,26 @@ enum BlockMode { /// `token::Interpolated` tokens. macro_rules! maybe_whole_expr { ($p:expr) => { - if let token::Interpolated(nt) = $p.token.clone() { - match *nt { - token::NtExpr(ref e) | token::NtLiteral(ref e) => { + if let token::Interpolated(nt) = &$p.token.kind { + match &**nt { + token::NtExpr(e) | token::NtLiteral(e) => { + let e = e.clone(); $p.bump(); - return Ok((*e).clone()); + return Ok(e); } - token::NtPath(ref path) => { + token::NtPath(path) => { + let path = path.clone(); $p.bump(); - let span = $p.span; - let kind = ExprKind::Path(None, (*path).clone()); - return Ok($p.mk_expr(span, kind, ThinVec::new())); + return Ok($p.mk_expr( + $p.token.span, ExprKind::Path(None, path), ThinVec::new() + )); } - token::NtBlock(ref block) => { + token::NtBlock(block) => { + let block = block.clone(); $p.bump(); - let span = $p.span; - let kind = ExprKind::Block((*block).clone(), None); - return Ok($p.mk_expr(span, kind, ThinVec::new())); + return Ok($p.mk_expr( + $p.token.span, ExprKind::Block(block, None), ThinVec::new() + )); } _ => {}, }; @@ -145,8 +152,9 @@ macro_rules! maybe_whole_expr { /// As maybe_whole_expr, but for things other than expressions macro_rules! maybe_whole { ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { - if let token::Interpolated(nt) = $p.token.clone() { - if let token::$constructor($x) = (*nt).clone() { + if let token::Interpolated(nt) = &$p.token.kind { + if let token::$constructor(x) = &**nt { + let $x = x.clone(); $p.bump(); return Ok($e); } @@ -154,6 +162,21 @@ macro_rules! maybe_whole { }; } +/// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`. +macro_rules! maybe_recover_from_interpolated_ty_qpath { + ($self: expr, $allow_qpath_recovery: expr) => { + if $allow_qpath_recovery && $self.look_ahead(1, |t| t == &token::ModSep) { + if let token::Interpolated(nt) = &$self.token.kind { + if let token::NtTy(ty) = &**nt { + let ty = ty.clone(); + $self.bump(); + return $self.maybe_recover_from_bad_qpath_stage_2($self.prev_span, ty); + } + } + } + } +} + fn maybe_append(mut lhs: Vec, mut rhs: Option>) -> Vec { if let Some(ref mut rhs) = rhs { lhs.append(rhs); @@ -169,81 +192,40 @@ enum PrevTokenKind { Interpolated, Eof, Ident, + BitOr, Other, } -trait RecoverQPath: Sized { - const PATH_STYLE: PathStyle = PathStyle::Expr; - fn to_ty(&self) -> Option>; - fn to_recovered(&self, qself: Option, path: ast::Path) -> Self; - fn to_string(&self) -> String; -} - -impl RecoverQPath for Ty { - const PATH_STYLE: PathStyle = PathStyle::Type; - fn to_ty(&self) -> Option> { - Some(P(self.clone())) - } - fn to_recovered(&self, qself: Option, path: ast::Path) -> Self { - Self { span: path.span, node: TyKind::Path(qself, path), id: self.id } - } - fn to_string(&self) -> String { - pprust::ty_to_string(self) - } -} - -impl RecoverQPath for Pat { - fn to_ty(&self) -> Option> { - self.to_ty() - } - fn to_recovered(&self, qself: Option, path: ast::Path) -> Self { - Self { span: path.span, node: PatKind::Path(qself, path), id: self.id } - } - fn to_string(&self) -> String { - pprust::pat_to_string(self) - } -} - -impl RecoverQPath for Expr { - fn to_ty(&self) -> Option> { - self.to_ty() - } - fn to_recovered(&self, qself: Option, path: ast::Path) -> Self { - Self { span: path.span, node: ExprKind::Path(qself, path), - id: self.id, attrs: self.attrs.clone() } - } - fn to_string(&self) -> String { - pprust::expr_to_string(self) - } -} - -/* ident is handled by common.rs */ +// NOTE: `Ident`s are handled by `common.rs`. #[derive(Clone)] pub struct Parser<'a> { pub sess: &'a ParseSess, - /// the current token: - pub token: token::Token, - /// the span of the current token: - pub span: Span, - /// the span of the previous token: + /// The current normalized token. + /// "Normalized" means that some interpolated tokens + /// (`$i: ident` and `$l: lifetime` meta-variables) are replaced + /// with non-interpolated identifier and lifetime tokens they refer to. + /// Perhaps the normalized / non-normalized setup can be simplified somehow. + pub token: Token, + /// Span of the current non-normalized token. meta_var_span: Option, + /// Span of the previous non-normalized token. pub prev_span: Span, - /// the previous token kind + /// Kind of the previous normalized token (in simplified form). prev_token_kind: PrevTokenKind, restrictions: Restrictions, - /// Used to determine the path to externally loaded source files + /// Used to determine the path to externally loaded source files. crate directory: Directory<'a>, - /// Whether to parse sub-modules in other files. + /// `true` to parse sub-modules in other files. pub recurse_into_file_modules: bool, /// Name of the root module this parser originated from. If `None`, then the /// name is not known. This does not change while the parser is descending /// into modules, and sub-parsers have new values for this name. pub root_module_name: Option, crate expected_tokens: Vec, - token_cursor: TokenCursor, + crate token_cursor: TokenCursor, desugar_doc_comments: bool, - /// Whether we should configure out of line modules as we parse. + /// `true` we should configure out of line modules as we parse. pub cfg_mods: bool, /// This field is used to keep track of how many left angle brackets we have seen. This is /// required in order to detect extra leading left angle brackets (`<` characters) and error @@ -256,23 +238,32 @@ pub struct Parser<'a> { /// it gets removed from here. Every entry left at the end gets emitted as an independent /// error. crate unclosed_delims: Vec, + crate last_unexpected_token_span: Option, + /// If present, this `Parser` is not parsing Rust code but rather a macro call. + crate subparser_name: Option<&'static str>, } +impl<'a> Drop for Parser<'a> { + fn drop(&mut self) { + let diag = self.diagnostic(); + emit_unclosed_delims(&mut self.unclosed_delims, diag); + } +} #[derive(Clone)] -struct TokenCursor { - frame: TokenCursorFrame, - stack: Vec, +crate struct TokenCursor { + crate frame: TokenCursorFrame, + crate stack: Vec, } #[derive(Clone)] -struct TokenCursorFrame { - delim: token::DelimToken, - span: DelimSpan, - open_delim: bool, - tree_cursor: tokenstream::Cursor, - close_delim: bool, - last_token: LastToken, +crate struct TokenCursorFrame { + crate delim: token::DelimToken, + crate span: DelimSpan, + crate open_delim: bool, + crate tree_cursor: tokenstream::Cursor, + crate close_delim: bool, + crate last_token: LastToken, } /// This is used in `TokenCursorFrame` above to track tokens that are consumed @@ -293,16 +284,16 @@ struct TokenCursorFrame { /// You can find some more example usage of this in the `collect_tokens` method /// on the parser. #[derive(Clone)] -enum LastToken { +crate enum LastToken { Collecting(Vec), Was(Option), } impl TokenCursorFrame { - fn new(sp: DelimSpan, delim: DelimToken, tts: &TokenStream) -> Self { + fn new(span: DelimSpan, delim: DelimToken, tts: &TokenStream) -> Self { TokenCursorFrame { - delim: delim, - span: sp, + delim, + span, open_delim: delim == token::NoDelim, tree_cursor: tts.clone().into_trees(), close_delim: delim == token::NoDelim, @@ -312,7 +303,7 @@ impl TokenCursorFrame { } impl TokenCursor { - fn next(&mut self) -> TokenAndSpan { + fn next(&mut self) -> Token { loop { let tree = if !self.frame.open_delim { self.frame.open_delim = true; @@ -326,7 +317,7 @@ impl TokenCursor { self.frame = frame; continue } else { - return TokenAndSpan { tok: token::Eof, sp: syntax_pos::DUMMY_SP } + return Token::new(token::Eof, DUMMY_SP); }; match self.frame.last_token { @@ -335,7 +326,7 @@ impl TokenCursor { } match tree { - TokenTree::Token(sp, tok) => return TokenAndSpan { tok: tok, sp: sp }, + TokenTree::Token(token) => return token, TokenTree::Delimited(sp, delim, tts) => { let frame = TokenCursorFrame::new(sp, delim, &tts); self.stack.push(mem::replace(&mut self.frame, frame)); @@ -344,9 +335,9 @@ impl TokenCursor { } } - fn next_desugared(&mut self) -> TokenAndSpan { - let (sp, name) = match self.next() { - TokenAndSpan { sp, tok: token::DocComment(name) } => (sp, name), + fn next_desugared(&mut self) -> Token { + let (name, sp) = match self.next() { + Token { kind: token::DocComment(name), span } => (name, span), tok => return tok, }; @@ -369,10 +360,12 @@ impl TokenCursor { let body = TokenTree::Delimited( delim_span, token::Bracket, - [TokenTree::Token(sp, token::Ident(ast::Ident::from_str("doc"), false)), - TokenTree::Token(sp, token::Eq), - TokenTree::Token(sp, token::Literal( - token::StrRaw(Symbol::intern(&stripped), num_of_hashes), None)) + [ + TokenTree::token(token::Ident(sym::doc, false), sp), + TokenTree::token(token::Eq, sp), + TokenTree::token(TokenKind::lit( + token::StrRaw(num_of_hashes), Symbol::intern(&stripped), None + ), sp), ] .iter().cloned().collect::().into(), ); @@ -381,10 +374,10 @@ impl TokenCursor { delim_span, token::NoDelim, &if doc_comment_style(&name.as_str()) == AttrStyle::Inner { - [TokenTree::Token(sp, token::Pound), TokenTree::Token(sp, token::Not), body] + [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body] .iter().cloned().collect::().into() } else { - [TokenTree::Token(sp, token::Pound), body] + [TokenTree::token(token::Pound, sp), body] .iter().cloned().collect::().into() }, ))); @@ -395,8 +388,8 @@ impl TokenCursor { #[derive(Clone, PartialEq)] crate enum TokenType { - Token(token::Token), - Keyword(keywords::Keyword), + Token(TokenKind), + Keyword(Symbol), Operator, Lifetime, Ident, @@ -406,10 +399,10 @@ crate enum TokenType { } impl TokenType { - fn to_string(&self) -> String { + crate fn to_string(&self) -> String { match *self { - TokenType::Token(ref t) => format!("`{}`", pprust::token_to_string(t)), - TokenType::Keyword(kw) => format!("`{}`", kw.name()), + TokenType::Token(ref t) => format!("`{}`", pprust::token_kind_to_string(t)), + TokenType::Keyword(kw) => format!("`{}`", kw), TokenType::Operator => "an operator".to_string(), TokenType::Lifetime => "lifetime".to_string(), TokenType::Ident => "identifier".to_string(), @@ -425,7 +418,7 @@ impl TokenType { /// /// Types can also be of the form `IDENT(u8, u8) -> u8`, however this assumes /// that `IDENT` is not the ident of a fn trait. -fn can_continue_type_after_non_fn_ident(t: &token::Token) -> bool { +fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { t == &token::ModSep || t == &token::Lt || t == &token::BinOp(token::Shl) } @@ -443,65 +436,6 @@ pub struct ModulePathSuccess { warn: bool, } -pub enum Error { - FileNotFoundForModule { - mod_name: String, - default_path: String, - secondary_path: String, - dir_path: String, - }, - DuplicatePaths { - mod_name: String, - default_path: String, - secondary_path: String, - }, - UselessDocComment, - InclusiveRangeWithNoEnd, -} - -impl Error { - fn span_err>(self, - sp: S, - handler: &errors::Handler) -> DiagnosticBuilder<'_> { - match self { - Error::FileNotFoundForModule { ref mod_name, - ref default_path, - ref secondary_path, - ref dir_path } => { - let mut err = struct_span_err!(handler, sp, E0583, - "file not found for module `{}`", mod_name); - err.help(&format!("name the file either {} or {} inside the directory \"{}\"", - default_path, - secondary_path, - dir_path)); - err - } - Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => { - let mut err = struct_span_err!(handler, sp, E0584, - "file for module `{}` found at both {} and {}", - mod_name, - default_path, - secondary_path); - err.help("delete or rename one of them to remove the ambiguity"); - err - } - Error::UselessDocComment => { - let mut err = struct_span_err!(handler, sp, E0585, - "found a documentation comment that doesn't document anything"); - err.help("doc comments must come before what they document, maybe a comment was \ - intended with `//`?"); - err - } - Error::InclusiveRangeWithNoEnd => { - let mut err = struct_span_err!(handler, sp, E0586, - "inclusive range with no end"); - err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)"); - err - } - } - } -} - #[derive(Debug)] enum LhsExpr { NotYetParsed, @@ -525,40 +459,25 @@ impl From> for LhsExpr { } } -/// Creates a placeholder argument. -fn dummy_arg(span: Span) -> Arg { - let ident = Ident::new(keywords::Invalid.name(), span); - let pat = P(Pat { - id: ast::DUMMY_NODE_ID, - node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), - span, - }); - let ty = Ty { - node: TyKind::Err, - span, - id: ast::DUMMY_NODE_ID - }; - Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID } -} - #[derive(Copy, Clone, Debug)] -enum TokenExpectType { +crate enum TokenExpectType { Expect, NoExpect, } impl<'a> Parser<'a> { - pub fn new(sess: &'a ParseSess, - tokens: TokenStream, - directory: Option>, - recurse_into_file_modules: bool, - desugar_doc_comments: bool) - -> Self { + pub fn new( + sess: &'a ParseSess, + tokens: TokenStream, + directory: Option>, + recurse_into_file_modules: bool, + desugar_doc_comments: bool, + subparser_name: Option<&'static str>, + ) -> Self { let mut parser = Parser { sess, - token: token::Whitespace, - span: syntax_pos::DUMMY_SP, - prev_span: syntax_pos::DUMMY_SP, + token: Token::dummy(), + prev_span: DUMMY_SP, meta_var_span: None, prev_token_kind: PrevTokenKind::Other, restrictions: Restrictions::empty(), @@ -582,16 +501,17 @@ impl<'a> Parser<'a> { unmatched_angle_bracket_count: 0, max_angle_bracket_count: 0, unclosed_delims: Vec::new(), + last_unexpected_token_span: None, + subparser_name, }; - let tok = parser.next_tok(); - parser.token = tok.tok; - parser.span = tok.sp; + parser.token = parser.next_tok(); if let Some(directory) = directory { parser.directory = directory; - } else if !parser.span.is_dummy() { - if let FileName::Real(mut path) = sess.source_map().span_to_unmapped_path(parser.span) { + } else if !parser.token.span.is_dummy() { + if let FileName::Real(mut path) = + sess.source_map().span_to_unmapped_path(parser.token.span) { path.pop(); parser.directory.path = Cow::from(path); } @@ -601,15 +521,15 @@ impl<'a> Parser<'a> { parser } - fn next_tok(&mut self) -> TokenAndSpan { + fn next_tok(&mut self) -> Token { let mut next = if self.desugar_doc_comments { self.token_cursor.next_desugared() } else { self.token_cursor.next() }; - if next.sp.is_dummy() { + if next.span.is_dummy() { // Tweak the location for better diagnostics, but keep syntactic context intact. - next.sp = self.prev_span.with_ctxt(next.sp.ctxt()); + next.span = self.prev_span.with_ctxt(next.span.ctxt()); } next } @@ -619,17 +539,17 @@ impl<'a> Parser<'a> { pprust::token_to_string(&self.token) } - fn token_descr(&self) -> Option<&'static str> { - Some(match &self.token { - t if t.is_special_ident() => "reserved identifier", - t if t.is_used_keyword() => "keyword", - t if t.is_unused_keyword() => "reserved keyword", + crate fn token_descr(&self) -> Option<&'static str> { + Some(match &self.token.kind { + _ if self.token.is_special_ident() => "reserved identifier", + _ if self.token.is_used_keyword() => "keyword", + _ if self.token.is_unused_keyword() => "reserved keyword", token::DocComment(..) => "doc comment", _ => return None, }) } - fn this_token_descr(&self) -> String { + crate fn this_token_descr(&self) -> String { if let Some(prefix) = self.token_descr() { format!("{} `{}`", prefix, self.this_token_to_string()) } else { @@ -637,11 +557,6 @@ impl<'a> Parser<'a> { } } - fn unexpected_last(&self, t: &token::Token) -> PResult<'a, T> { - let token_str = pprust::token_to_string(t); - Err(self.span_fatal(self.prev_span, &format!("unexpected token: `{}`", token_str))) - } - crate fn unexpected(&mut self) -> PResult<'a, T> { match self.expect_one_of(&[], &[]) { Err(e) => Err(e), @@ -650,226 +565,45 @@ impl<'a> Parser<'a> { } /// Expects and consumes the token `t`. Signals an error if the next token is not `t`. - pub fn expect(&mut self, t: &token::Token) -> PResult<'a, bool /* recovered */> { + pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, bool /* recovered */> { if self.expected_tokens.is_empty() { if self.token == *t { self.bump(); Ok(false) } else { - let token_str = pprust::token_to_string(t); - let this_token_str = self.this_token_descr(); - let mut err = self.fatal(&format!("expected `{}`, found {}", - token_str, - this_token_str)); - - let sp = if self.token == token::Token::Eof { - // EOF, don't want to point at the following char, but rather the last token - self.prev_span - } else { - self.sess.source_map().next_point(self.prev_span) - }; - let label_exp = format!("expected `{}`", token_str); - match self.recover_closing_delimiter(&[t.clone()], err) { - Err(e) => err = e, - Ok(recovered) => { - return Ok(recovered); - } - } - let cm = self.sess.source_map(); - match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) { - (Ok(ref a), Ok(ref b)) if a.line == b.line => { - // When the spans are in the same line, it means that the only content - // between them is whitespace, point only at the found token. - err.span_label(self.span, label_exp); - } - _ => { - err.span_label(sp, label_exp); - err.span_label(self.span, "unexpected token"); - } - } - Err(err) + self.unexpected_try_recover(t) } } else { self.expect_one_of(slice::from_ref(t), &[]) } } - fn recover_closing_delimiter( - &mut self, - tokens: &[token::Token], - mut err: DiagnosticBuilder<'a>, - ) -> PResult<'a, bool> { - let mut pos = None; - // we want to use the last closing delim that would apply - for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() { - if tokens.contains(&token::CloseDelim(unmatched.expected_delim)) - && Some(self.span) > unmatched.unclosed_span - { - pos = Some(i); - } - } - match pos { - Some(pos) => { - // Recover and assume that the detected unclosed delimiter was meant for - // this location. Emit the diagnostic and act as if the delimiter was - // present for the parser's sake. - - // Don't attempt to recover from this unclosed delimiter more than once. - let unmatched = self.unclosed_delims.remove(pos); - let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim)); - - // We want to suggest the inclusion of the closing delimiter where it makes - // the most sense, which is immediately after the last token: - // - // {foo(bar {}} - // - ^ - // | | - // | help: `)` may belong here (FIXME: #58270) - // | - // unclosed delimiter - if let Some(sp) = unmatched.unclosed_span { - err.span_label(sp, "unclosed delimiter"); - } - err.span_suggestion_short( - self.sess.source_map().next_point(self.prev_span), - &format!("{} may belong here", delim.to_string()), - delim.to_string(), - Applicability::MaybeIncorrect, - ); - err.emit(); - self.expected_tokens.clear(); // reduce errors - Ok(true) - } - _ => Err(err), - } - } - /// Expect next token to be edible or inedible token. If edible, /// then consume it; if inedible, then return without consuming /// anything. Signal a fatal error if next token is unexpected. pub fn expect_one_of( &mut self, - edible: &[token::Token], - inedible: &[token::Token], + edible: &[TokenKind], + inedible: &[TokenKind], ) -> PResult<'a, bool /* recovered */> { - fn tokens_to_string(tokens: &[TokenType]) -> String { - let mut i = tokens.iter(); - // This might be a sign we need a connect method on Iterator. - let b = i.next() - .map_or(String::new(), |t| t.to_string()); - i.enumerate().fold(b, |mut b, (i, a)| { - if tokens.len() > 2 && i == tokens.len() - 2 { - b.push_str(", or "); - } else if tokens.len() == 2 && i == tokens.len() - 2 { - b.push_str(" or "); - } else { - b.push_str(", "); - } - b.push_str(&a.to_string()); - b - }) - } - if edible.contains(&self.token) { + if edible.contains(&self.token.kind) { self.bump(); Ok(false) - } else if inedible.contains(&self.token) { + } else if inedible.contains(&self.token.kind) { // leave it in the input Ok(false) + } else if self.last_unexpected_token_span == Some(self.token.span) { + FatalError.raise(); } else { - let mut expected = edible.iter() - .map(|x| TokenType::Token(x.clone())) - .chain(inedible.iter().map(|x| TokenType::Token(x.clone()))) - .chain(self.expected_tokens.iter().cloned()) - .collect::>(); - expected.sort_by_cached_key(|x| x.to_string()); - expected.dedup(); - let expect = tokens_to_string(&expected[..]); - let actual = self.this_token_to_string(); - let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { - let short_expect = if expected.len() > 6 { - format!("{} possible tokens", expected.len()) - } else { - expect.clone() - }; - (format!("expected one of {}, found `{}`", expect, actual), - (self.sess.source_map().next_point(self.prev_span), - format!("expected one of {} here", short_expect))) - } else if expected.is_empty() { - (format!("unexpected token: `{}`", actual), - (self.prev_span, "unexpected token after this".to_string())) - } else { - (format!("expected {}, found `{}`", expect, actual), - (self.sess.source_map().next_point(self.prev_span), - format!("expected {} here", expect))) - }; - let mut err = self.fatal(&msg_exp); - if self.token.is_ident_named("and") { - err.span_suggestion_short( - self.span, - "use `&&` instead of `and` for the boolean operator", - "&&".to_string(), - Applicability::MaybeIncorrect, - ); - } - if self.token.is_ident_named("or") { - err.span_suggestion_short( - self.span, - "use `||` instead of `or` for the boolean operator", - "||".to_string(), - Applicability::MaybeIncorrect, - ); - } - let sp = if self.token == token::Token::Eof { - // This is EOF, don't want to point at the following char, but rather the last token - self.prev_span - } else { - label_sp - }; - match self.recover_closing_delimiter(&expected.iter().filter_map(|tt| match tt { - TokenType::Token(t) => Some(t.clone()), - _ => None, - }).collect::>(), err) { - Err(e) => err = e, - Ok(recovered) => { - return Ok(recovered); - } - } - - let cm = self.sess.source_map(); - match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) { - (Ok(ref a), Ok(ref b)) if a.line == b.line => { - // When the spans are in the same line, it means that the only content between - // them is whitespace, point at the found token in that case: - // - // X | () => { syntax error }; - // | ^^^^^ expected one of 8 possible tokens here - // - // instead of having: - // - // X | () => { syntax error }; - // | -^^^^^ unexpected token - // | | - // | expected one of 8 possible tokens here - err.span_label(self.span, label_exp); - } - _ if self.prev_span == syntax_pos::DUMMY_SP => { - // Account for macro context where the previous span might not be - // available to avoid incorrect output (#54841). - err.span_label(self.span, "unexpected token"); - } - _ => { - err.span_label(sp, label_exp); - err.span_label(self.span, "unexpected token"); - } - } - Err(err) + self.expected_one_of_not_found(edible, inedible) } } /// Returns the span of expr, if it was not interpolated or the span of the interpolated token. - fn interpolated_or_expr_span(&self, - expr: PResult<'a, P>) - -> PResult<'a, (Span, P)> { + fn interpolated_or_expr_span( + &self, + expr: PResult<'a, P>, + ) -> PResult<'a, (Span, P)> { expr.map(|e| { if self.prev_token_kind == PrevTokenKind::Interpolated { (self.prev_span, e) @@ -879,45 +613,13 @@ impl<'a> Parser<'a> { }) } - fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { - let mut err = self.struct_span_err(self.span, - &format!("expected identifier, found {}", - self.this_token_descr())); - if let token::Ident(ident, false) = &self.token { - if ident.is_reserved() && !ident.is_path_segment_keyword() && - ident.name != keywords::Underscore.name() - { - err.span_suggestion( - self.span, - "you can escape reserved keywords to use them as identifiers", - format!("r#{}", ident), - Applicability::MaybeIncorrect, - ); - } - } - if let Some(token_descr) = self.token_descr() { - err.span_label(self.span, format!("expected identifier, found {}", token_descr)); - } else { - err.span_label(self.span, "expected identifier"); - if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { - err.span_suggestion( - self.span, - "remove this comma", - String::new(), - Applicability::MachineApplicable, - ); - } - } - err - } - pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { self.parse_ident_common(true) } fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> { - match self.token { - token::Ident(ident, _) => { + match self.token.kind { + token::Ident(name, _) => { if self.token.is_reserved_ident() { let mut err = self.expected_ident_found(); if recover { @@ -926,16 +628,16 @@ impl<'a> Parser<'a> { return Err(err); } } - let span = self.span; + let span = self.token.span; self.bump(); - Ok(Ident::new(ident.name, span)) + Ok(Ident::new(name, span)) } _ => { Err(if self.prev_token_kind == PrevTokenKind::DocComment { - self.span_fatal_err(self.prev_span, Error::UselessDocComment) - } else { - self.expected_ident_found() - }) + self.span_fatal_err(self.prev_span, Error::UselessDocComment) + } else { + self.expected_ident_found() + }) } } } @@ -944,27 +646,27 @@ impl<'a> Parser<'a> { /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not /// encountered. - crate fn check(&mut self, tok: &token::Token) -> bool { + crate fn check(&mut self, tok: &TokenKind) -> bool { let is_present = self.token == *tok; if !is_present { self.expected_tokens.push(TokenType::Token(tok.clone())); } is_present } /// Consumes a token 'tok' if it exists. Returns whether the given token was present. - pub fn eat(&mut self, tok: &token::Token) -> bool { + pub fn eat(&mut self, tok: &TokenKind) -> bool { let is_present = self.check(tok); if is_present { self.bump() } is_present } - fn check_keyword(&mut self, kw: keywords::Keyword) -> bool { + fn check_keyword(&mut self, kw: Symbol) -> bool { self.expected_tokens.push(TokenType::Keyword(kw)); self.token.is_keyword(kw) } /// If the next token is the given keyword, eats it and returns /// `true`. Otherwise, returns `false`. - pub fn eat_keyword(&mut self, kw: keywords::Keyword) -> bool { + pub fn eat_keyword(&mut self, kw: Symbol) -> bool { if self.check_keyword(kw) { self.bump(); true @@ -973,7 +675,7 @@ impl<'a> Parser<'a> { } } - fn eat_keyword_noexpect(&mut self, kw: keywords::Keyword) -> bool { + fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool { if self.token.is_keyword(kw) { self.bump(); true @@ -985,7 +687,7 @@ impl<'a> Parser<'a> { /// If the given word is not a keyword, signals an error. /// If the next token is not the given word, signals an error. /// Otherwise, eats it. - fn expect_keyword(&mut self, kw: keywords::Keyword) -> PResult<'a, ()> { + fn expect_keyword(&mut self, kw: Symbol) -> PResult<'a, ()> { if !self.eat_keyword(kw) { self.unexpected() } else { @@ -993,7 +695,7 @@ impl<'a> Parser<'a> { } } - fn check_ident(&mut self) -> bool { + crate fn check_ident(&mut self) -> bool { if self.token.is_ident() { true } else { @@ -1036,13 +738,13 @@ impl<'a> Parser<'a> { /// See issue #47856 for an example of when this may occur. fn eat_plus(&mut self) -> bool { self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); - match self.token { + match self.token.kind { token::BinOp(token::Plus) => { self.bump(); true } token::BinOpEq(token::Plus) => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); self.bump_with(token::Eq, span); true } @@ -1067,13 +769,13 @@ impl<'a> Parser<'a> { /// `&` and continues. If an `&` is not seen, signals an error. fn expect_and(&mut self) -> PResult<'a, ()> { self.expected_tokens.push(TokenType::Token(token::BinOp(token::And))); - match self.token { + match self.token.kind { token::BinOp(token::And) => { self.bump(); Ok(()) } token::AndAnd => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); Ok(self.bump_with(token::BinOp(token::And), span)) } _ => self.unexpected() @@ -1084,13 +786,13 @@ impl<'a> Parser<'a> { /// `|` and continues. If an `|` is not seen, signals an error. fn expect_or(&mut self) -> PResult<'a, ()> { self.expected_tokens.push(TokenType::Token(token::BinOp(token::Or))); - match self.token { + match self.token.kind { token::BinOp(token::Or) => { self.bump(); Ok(()) } token::OrOr => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); Ok(self.bump_with(token::BinOp(token::Or), span)) } _ => self.unexpected() @@ -1098,19 +800,7 @@ impl<'a> Parser<'a> { } fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option) { - match suffix { - None => {/* everything ok */} - Some(suf) => { - let text = suf.as_str(); - if text.is_empty() { - self.span_bug(sp, "found empty literal suffix in Some") - } - let msg = format!("{} with a suffix is invalid", kind); - self.struct_span_err(sp, &msg) - .span_label(sp, msg) - .emit(); - } - } + literal::expect_no_suffix(&self.sess.span_diagnostic, sp, kind, suffix) } /// Attempts to consume a `<`. If `<<` is seen, replaces it with a single @@ -1121,18 +811,18 @@ impl<'a> Parser<'a> { /// starting token. fn eat_lt(&mut self) -> bool { self.expected_tokens.push(TokenType::Token(token::Lt)); - let ate = match self.token { + let ate = match self.token.kind { token::Lt => { self.bump(); true } token::BinOp(token::Shl) => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); self.bump_with(token::Lt, span); true } token::LArrow => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); self.bump_with(token::BinOp(token::Minus), span); true } @@ -1161,21 +851,21 @@ impl<'a> Parser<'a> { /// with a single `>` and continues. If a `>` is not seen, signals an error. fn expect_gt(&mut self) -> PResult<'a, ()> { self.expected_tokens.push(TokenType::Token(token::Gt)); - let ate = match self.token { + let ate = match self.token.kind { token::Gt => { self.bump(); Some(()) } token::BinOp(token::Shr) => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); Some(self.bump_with(token::Gt, span)) } token::BinOpEq(token::Shr) => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); Some(self.bump_with(token::Ge, span)) } token::Ge => { - let span = self.span.with_lo(self.span.lo() + BytePos(1)); + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); Some(self.bump_with(token::Eq, span)) } _ => None, @@ -1195,24 +885,11 @@ impl<'a> Parser<'a> { } } - /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, - /// passes through any errors encountered. Used for error recovery. - fn eat_to_tokens(&mut self, kets: &[&token::Token]) { - let handler = self.diagnostic(); - - if let Err(ref mut err) = self.parse_seq_to_before_tokens(kets, - SeqSep::none(), - TokenExpectType::Expect, - |p| Ok(p.parse_token_tree())) { - handler.cancel(err); - } - } - /// Parses a sequence, including the closing delimiter. The function /// `f` must consume tokens until reaching the next separator or /// closing bracket. pub fn parse_seq_to_end(&mut self, - ket: &token::Token, + ket: &TokenKind, sep: SeqSep, f: F) -> PResult<'a, Vec> where @@ -1230,7 +907,7 @@ impl<'a> Parser<'a> { /// closing bracket. pub fn parse_seq_to_before_end( &mut self, - ket: &token::Token, + ket: &TokenKind, sep: SeqSep, f: F, ) -> PResult<'a, (Vec, bool)> @@ -1239,9 +916,9 @@ impl<'a> Parser<'a> { self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) } - fn parse_seq_to_before_tokens( + crate fn parse_seq_to_before_tokens( &mut self, - kets: &[&token::Token], + kets: &[&TokenKind], sep: SeqSep, expect: TokenExpectType, mut f: F, @@ -1257,7 +934,7 @@ impl<'a> Parser<'a> { TokenExpectType::NoExpect => self.token == **k, } }) { - match self.token { + match self.token.kind { token::CloseDelim(..) | token::Eof => break, _ => {} }; @@ -1274,7 +951,7 @@ impl<'a> Parser<'a> { Err(mut e) => { // Attempt to keep parsing if it was a similar separator if let Some(ref tokens) = t.similar_tokens() { - if tokens.contains(&self.token) { + if tokens.contains(&self.token.kind) { self.bump(); } } @@ -1315,8 +992,8 @@ impl<'a> Parser<'a> { /// closing bracket. fn parse_unspanned_seq( &mut self, - bra: &token::Token, - ket: &token::Token, + bra: &TokenKind, + ket: &TokenKind, sep: SeqSep, f: F, ) -> PResult<'a, Vec> where @@ -1337,22 +1014,21 @@ impl<'a> Parser<'a> { self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); } - self.prev_span = self.meta_var_span.take().unwrap_or(self.span); + self.prev_span = self.meta_var_span.take().unwrap_or(self.token.span); // Record last token kind for possible error recovery. - self.prev_token_kind = match self.token { + self.prev_token_kind = match self.token.kind { token::DocComment(..) => PrevTokenKind::DocComment, token::Comma => PrevTokenKind::Comma, token::BinOp(token::Plus) => PrevTokenKind::Plus, + token::BinOp(token::Or) => PrevTokenKind::BitOr, token::Interpolated(..) => PrevTokenKind::Interpolated, token::Eof => PrevTokenKind::Eof, token::Ident(..) => PrevTokenKind::Ident, _ => PrevTokenKind::Other, }; - let next = self.next_tok(); - self.span = next.sp; - self.token = next.tok; + self.token = self.next_tok(); self.expected_tokens.clear(); // check after each token self.process_potential_macro_variable(); @@ -1360,79 +1036,44 @@ impl<'a> Parser<'a> { /// Advance the parser using provided token as a next one. Use this when /// consuming a part of a token. For example a single `<` from `<<`. - fn bump_with(&mut self, next: token::Token, span: Span) { - self.prev_span = self.span.with_hi(span.lo()); + fn bump_with(&mut self, next: TokenKind, span: Span) { + self.prev_span = self.token.span.with_hi(span.lo()); // It would be incorrect to record the kind of the current token, but // fortunately for tokens currently using `bump_with`, the // prev_token_kind will be of no use anyway. self.prev_token_kind = PrevTokenKind::Other; - self.span = span; - self.token = next; + self.token = Token::new(next, span); self.expected_tokens.clear(); } pub fn look_ahead(&self, dist: usize, f: F) -> R where - F: FnOnce(&token::Token) -> R, + F: FnOnce(&Token) -> R, { if dist == 0 { - return f(&self.token) + return f(&self.token); } - f(&match self.token_cursor.frame.tree_cursor.look_ahead(dist - 1) { + let frame = &self.token_cursor.frame; + f(&match frame.tree_cursor.look_ahead(dist - 1) { Some(tree) => match tree { - TokenTree::Token(_, tok) => tok, - TokenTree::Delimited(_, delim, _) => token::OpenDelim(delim), - }, - None => token::CloseDelim(self.token_cursor.frame.delim), + TokenTree::Token(token) => token, + TokenTree::Delimited(dspan, delim, _) => + Token::new(token::OpenDelim(delim), dspan.open), + } + None => Token::new(token::CloseDelim(frame.delim), frame.span.close) }) } - fn look_ahead_span(&self, dist: usize) -> Span { - if dist == 0 { - return self.span - } - - match self.token_cursor.frame.tree_cursor.look_ahead(dist - 1) { - Some(TokenTree::Token(span, _)) => span, - Some(TokenTree::Delimited(span, ..)) => span.entire(), - None => self.look_ahead_span(dist - 1), - } - } - pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> { - self.sess.span_diagnostic.struct_span_fatal(self.span, m) - } - pub fn span_fatal>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { - self.sess.span_diagnostic.struct_span_fatal(sp, m) - } - fn span_fatal_err>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> { - err.span_err(sp, self.diagnostic()) - } - fn bug(&self, m: &str) -> ! { - self.sess.span_diagnostic.span_bug(self.span, m) - } - fn span_err>(&self, sp: S, m: &str) { - self.sess.span_diagnostic.span_err(sp, m) - } - fn struct_span_err>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { - self.sess.span_diagnostic.struct_span_err(sp, m) - } - crate fn span_bug>(&self, sp: S, m: &str) -> ! { - self.sess.span_diagnostic.span_bug(sp, m) - } - - fn cancel(&self, err: &mut DiagnosticBuilder<'_>) { - self.sess.span_diagnostic.cancel(err) - } - - crate fn diagnostic(&self) -> &'a errors::Handler { - &self.sess.span_diagnostic + /// Returns whether any of the given keywords are `dist` tokens ahead of the current one. + fn is_keyword_ahead(&self, dist: usize, kws: &[Symbol]) -> bool { + self.look_ahead(dist, |t| kws.iter().any(|&kw| t.is_keyword(kw))) } /// Is the current token one of the keywords that signals a bare function type? fn token_is_bare_fn_keyword(&mut self) -> bool { - self.check_keyword(keywords::Fn) || - self.check_keyword(keywords::Unsafe) || - self.check_keyword(keywords::Extern) + self.check_keyword(kw::Fn) || + self.check_keyword(kw::Unsafe) || + self.check_keyword(kw::Extern) } /// Parses a `TyKind::BareFn` type. @@ -1450,13 +1091,13 @@ impl<'a> Parser<'a> { */ let unsafety = self.parse_unsafety(); - let abi = if self.eat_keyword(keywords::Extern) { + let abi = if self.eat_keyword(kw::Extern) { self.parse_opt_abi()?.unwrap_or(Abi::C) } else { Abi::Rust }; - self.expect_keyword(keywords::Fn)?; + self.expect_keyword(kw::Fn)?; let (inputs, c_variadic) = self.parse_fn_args(false, true)?; let ret_ty = self.parse_ret_ty(false)?; let decl = P(FnDecl { @@ -1474,7 +1115,7 @@ impl<'a> Parser<'a> { /// Parses asyncness: `async` or nothing. fn parse_asyncness(&mut self) -> IsAsync { - if self.eat_keyword(keywords::Async) { + if self.eat_keyword(kw::Async) { IsAsync::Async { closure_id: ast::DUMMY_NODE_ID, return_impl_trait_id: ast::DUMMY_NODE_ID, @@ -1486,7 +1127,7 @@ impl<'a> Parser<'a> { /// Parses unsafety: `unsafe` or nothing. fn parse_unsafety(&mut self) -> Unsafety { - if self.eat_keyword(keywords::Unsafe) { + if self.eat_keyword(kw::Unsafe) { Unsafety::Unsafe } else { Unsafety::Normal @@ -1497,9 +1138,13 @@ impl<'a> Parser<'a> { pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> { maybe_whole!(self, NtTraitItem, |x| x); let attrs = self.parse_outer_attributes()?; + let mut unclosed_delims = vec![]; let (mut item, tokens) = self.collect_tokens(|this| { - this.parse_trait_item_(at_end, attrs) + let item = this.parse_trait_item_(at_end, attrs); + unclosed_delims.append(&mut this.unclosed_delims); + item })?; + self.unclosed_delims.append(&mut unclosed_delims); // See `parse_item` for why this clause is here. if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { item.tokens = Some(tokens); @@ -1510,12 +1155,12 @@ impl<'a> Parser<'a> { fn parse_trait_item_(&mut self, at_end: &mut bool, mut attrs: Vec) -> PResult<'a, TraitItem> { - let lo = self.span; - - let (name, node, generics) = if self.eat_keyword(keywords::Type) { + let lo = self.token.span; + self.eat_bad_pub(); + let (name, node, generics) = if self.eat_keyword(kw::Type) { self.parse_trait_item_assoc_ty()? } else if self.is_const_item() { - self.expect_keyword(keywords::Const)?; + self.expect_keyword(kw::Const)?; let ident = self.parse_ident()?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; @@ -1530,20 +1175,21 @@ impl<'a> Parser<'a> { (ident, TraitItemKind::Const(ty, default), ast::Generics::default()) } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? { // trait item macro. - (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default()) + (Ident::invalid(), ast::TraitItemKind::Macro(mac), ast::Generics::default()) } else { let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { + let decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a // definition... // We don't allow argument names to be left off in edition 2018. - p.parse_arg_general(p.span.rust_2018(), true, false) + let is_name_required = p.token.span.rust_2018(); + p.parse_arg_general(true, false, |_| is_name_required) })?; generics.where_clause = self.parse_where_clause()?; @@ -1554,10 +1200,10 @@ impl<'a> Parser<'a> { abi, asyncness, }, - decl: d, + decl, }; - let body = match self.token { + let body = match self.token.kind { token::Semi => { self.bump(); *at_end = true; @@ -1580,20 +1226,12 @@ impl<'a> Parser<'a> { Some(body) } _ => { - let token_str = self.this_token_descr(); - let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", - token_str)); - err.span_label(self.span, "expected `;` or `{`"); - return Err(err); + return self.expected_semi_or_open_brace(); } } } _ => { - let token_str = self.this_token_descr(); - let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", - token_str)); - err.span_label(self.span, "expected `;` or `{`"); - return Err(err); + return self.expected_semi_or_open_brace(); } }; (ident, ast::TraitItemKind::Method(sig, body), generics) @@ -1615,7 +1253,7 @@ impl<'a> Parser<'a> { if self.eat(&token::RArrow) { Ok(FunctionRetTy::Ty(self.parse_ty_common(allow_plus, true, false)?)) } else { - Ok(FunctionRetTy::Default(self.span.shrink_to_lo())) + Ok(FunctionRetTy::Default(self.token.span.shrink_to_lo())) } } @@ -1636,9 +1274,10 @@ impl<'a> Parser<'a> { fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool, allow_c_variadic: bool) -> PResult<'a, P> { + maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); maybe_whole!(self, NtTy, |x| x); - let lo = self.span; + let lo = self.token.span; let mut impl_dyn_multi = false; let node = if self.eat(&token::OpenDelim(token::Paren)) { // `(TYPE)` is a parenthesized type. @@ -1702,7 +1341,7 @@ impl<'a> Parser<'a> { // Reference self.expect_and()?; self.parse_borrowed_pointee()? - } else if self.eat_keyword_noexpect(keywords::Typeof) { + } else if self.eat_keyword_noexpect(kw::Typeof) { // `typeof(EXPR)` // In order to not be ambiguous, the type must be surrounded by parens. self.expect(&token::OpenDelim(token::Paren))?; @@ -1712,17 +1351,17 @@ impl<'a> Parser<'a> { }; self.expect(&token::CloseDelim(token::Paren))?; TyKind::Typeof(e) - } else if self.eat_keyword(keywords::Underscore) { + } else if self.eat_keyword(kw::Underscore) { // A type to be inferred `_` TyKind::Infer } else if self.token_is_bare_fn_keyword() { // Function pointer type self.parse_ty_bare_fn(Vec::new())? - } else if self.check_keyword(keywords::For) { + } else if self.check_keyword(kw::For) { // Function pointer type or bound list (trait object type) starting with a poly-trait. // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` // `for<'lt> Trait1<'lt> + Trait2 + 'a` - let lo = self.span; + let lo = self.token.span; let lifetime_defs = self.parse_late_bound_lifetime_defs()?; if self.token_is_bare_fn_keyword() { self.parse_ty_bare_fn(lifetime_defs)? @@ -1731,13 +1370,13 @@ impl<'a> Parser<'a> { let parse_plus = allow_plus && self.check_plus(); self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? } - } else if self.eat_keyword(keywords::Impl) { + } else if self.eat_keyword(kw::Impl) { // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds(None)?; impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) - } else if self.check_keyword(keywords::Dyn) && - (self.span.rust_2018() || + } else if self.check_keyword(kw::Dyn) && + (self.token.span.rust_2018() || self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t))) { self.bump(); // `dyn` @@ -1787,14 +1426,12 @@ impl<'a> Parser<'a> { }; let span = lo.to(self.prev_span); - let ty = Ty { node, span, id: ast::DUMMY_NODE_ID }; + let ty = P(Ty { node, span, id: ast::DUMMY_NODE_ID }); // Try to recover from use of `+` with incorrect priority. self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty); self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?; - let ty = self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)?; - - Ok(P(ty)) + self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery) } fn parse_remaining_bounds(&mut self, generic_params: Vec, path: ast::Path, @@ -1803,111 +1440,22 @@ impl<'a> Parser<'a> { let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; if parse_plus { self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded - bounds.append(&mut self.parse_generic_bounds(None)?); + bounds.append(&mut self.parse_generic_bounds(Some(self.prev_span))?); } Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) } - fn maybe_report_ambiguous_plus(&mut self, allow_plus: bool, impl_dyn_multi: bool, ty: &Ty) { - if !allow_plus && impl_dyn_multi { - let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); - self.struct_span_err(ty.span, "ambiguous `+` in a type") - .span_suggestion( - ty.span, - "use parentheses to disambiguate", - sum_with_parens, - Applicability::MachineApplicable - ).emit(); - } - } - - fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { - // Do not add `+` to expected tokens. - if !allow_plus || !self.token.is_like_plus() { - return Ok(()) - } - - self.bump(); // `+` - let bounds = self.parse_generic_bounds(None)?; - let sum_span = ty.span.to(self.prev_span); - - let mut err = struct_span_err!(self.sess.span_diagnostic, sum_span, E0178, - "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(ty)); - - match ty.node { - TyKind::Rptr(ref lifetime, ref mut_ty) => { - let sum_with_parens = pprust::to_string(|s| { - use crate::print::pprust::PrintState; - - s.s.word("&")?; - s.print_opt_lifetime(lifetime)?; - s.print_mutability(mut_ty.mutbl)?; - s.popen()?; - s.print_type(&mut_ty.ty)?; - s.print_type_bounds(" +", &bounds)?; - s.pclose() - }); - err.span_suggestion( - sum_span, - "try adding parentheses", - sum_with_parens, - Applicability::MachineApplicable - ); - } - TyKind::Ptr(..) | TyKind::BareFn(..) => { - err.span_label(sum_span, "perhaps you forgot parentheses?"); - } - _ => { - err.span_label(sum_span, "expected a path"); - }, - } - err.emit(); - Ok(()) - } - - // Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`. - fn maybe_recover_from_bad_qpath(&mut self, base: T, allow_recovery: bool) - -> PResult<'a, T> { - // Do not add `::` to expected tokens. - if !allow_recovery || self.token != token::ModSep { - return Ok(base); - } - let ty = match base.to_ty() { - Some(ty) => ty, - None => return Ok(base), - }; - - self.bump(); // `::` - let mut segments = Vec::new(); - self.parse_path_segments(&mut segments, T::PATH_STYLE, true)?; - - let span = ty.span.to(self.prev_span); - let path_span = span.to(span); // use an empty path since `position` == 0 - let recovered = base.to_recovered( - Some(QSelf { ty, path_span, position: 0 }), - ast::Path { segments, span }, - ); - - self.diagnostic() - .struct_span_err(span, "missing angle brackets in associated item path") - .span_suggestion( // this is a best-effort recovery - span, "try", recovered.to_string(), Applicability::MaybeIncorrect - ).emit(); - - Ok(recovered) - } - fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; let mutbl = self.parse_mutability(); let ty = self.parse_ty_no_plus()?; - return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty: ty, mutbl: mutbl })); + return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl })); } fn parse_ptr(&mut self) -> PResult<'a, MutTy> { - let mutbl = if self.eat_keyword(keywords::Mut) { + let mutbl = if self.eat_keyword(kw::Mut) { Mutability::Mutable - } else if self.eat_keyword(keywords::Const) { + } else if self.eat_keyword(kw::Const) { Mutability::Immutable } else { let span = self.prev_span; @@ -1919,17 +1467,17 @@ impl<'a> Parser<'a> { Mutability::Immutable }; let t = self.parse_ty_no_plus()?; - Ok(MutTy { ty: t, mutbl: mutbl }) + Ok(MutTy { ty: t, mutbl }) } - fn is_named_argument(&mut self) -> bool { - let offset = match self.token { + fn is_named_argument(&self) -> bool { + let offset = match self.token.kind { token::Interpolated(ref nt) => match **nt { token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), _ => 0, } token::BinOp(token::And) | token::AndAnd => 1, - _ if self.token.is_keyword(keywords::Mut) => 1, + _ if self.token.is_keyword(kw::Mut) => 1, _ => 0, }; @@ -1939,90 +1487,47 @@ impl<'a> Parser<'a> { /// Skips unexpected attributes and doc comments in this position and emits an appropriate /// error. - fn eat_incorrect_doc_comment(&mut self, applied_to: &str) { - if let token::DocComment(_) = self.token { - let mut err = self.diagnostic().struct_span_err( - self.span, - &format!("documentation comments cannot be applied to {}", applied_to), - ); - err.span_label(self.span, "doc comments are not allowed here"); - err.emit(); - self.bump(); - } else if self.token == token::Pound && self.look_ahead(1, |t| { - *t == token::OpenDelim(token::Bracket) - }) { - let lo = self.span; - // Skip every token until next possible arg. - while self.token != token::CloseDelim(token::Bracket) { - self.bump(); - } - let sp = lo.to(self.span); - self.bump(); - let mut err = self.diagnostic().struct_span_err( - sp, - &format!("attributes cannot be applied to {}", applied_to), - ); - err.span_label(sp, "attributes are not allowed here"); - err.emit(); - } - } - /// This version of parse arg doesn't necessarily require identifier names. - fn parse_arg_general(&mut self, require_name: bool, is_trait_item: bool, - allow_c_variadic: bool) -> PResult<'a, Arg> { - maybe_whole!(self, NtArg, |x| x); - - if let Ok(Some(_)) = self.parse_self_arg() { - let mut err = self.struct_span_err(self.prev_span, - "unexpected `self` argument in function"); - err.span_label(self.prev_span, - "`self` is only valid as the first argument of an associated function"); - return Err(err); + fn parse_arg_general( + &mut self, + is_trait_item: bool, + allow_c_variadic: bool, + is_name_required: F, + ) -> PResult<'a, Arg> + where + F: Fn(&token::Token) -> bool + { + let attrs = self.parse_arg_attributes()?; + if let Some(mut arg) = self.parse_self_arg()? { + arg.attrs = attrs.into(); + return self.recover_bad_self_arg(arg, is_trait_item); } - let (pat, ty) = if require_name || self.is_named_argument() { - debug!("parse_arg_general parse_pat (require_name:{})", - require_name); - self.eat_incorrect_doc_comment("method arguments"); - let pat = self.parse_pat(Some("argument name"))?; + let is_name_required = is_name_required(&self.token); + let (pat, ty) = if is_name_required || self.is_named_argument() { + debug!("parse_arg_general parse_pat (is_name_required:{})", is_name_required); + let pat = self.parse_pat(Some("argument name"))?; if let Err(mut err) = self.expect(&token::Colon) { - // If we find a pattern followed by an identifier, it could be an (incorrect) - // C-style parameter declaration. - if self.check_ident() && self.look_ahead(1, |t| { - *t == token::Comma || *t == token::CloseDelim(token::Paren) - }) { - let ident = self.parse_ident().unwrap(); - let span = pat.span.with_hi(ident.span.hi()); - - err.span_suggestion( - span, - "declare the type after the parameter binding", - String::from(": "), - Applicability::HasPlaceholders, - ); - } else if require_name && is_trait_item { - if let PatKind::Ident(_, ident, _) = pat.node { - err.span_suggestion( - pat.span, - "explicitly ignore parameter", - format!("_: {}", ident), - Applicability::MachineApplicable, - ); - } - - err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)"); + if let Some(ident) = self.argument_without_type( + &mut err, + pat, + is_name_required, + is_trait_item, + ) { + err.emit(); + return Ok(dummy_arg(ident)); + } else { + return Err(err); } - - return Err(err); } - self.eat_incorrect_doc_comment("a method argument's type"); + self.eat_incorrect_doc_comment_for_arg_type(); (pat, self.parse_ty_common(true, true, allow_c_variadic)?) } else { debug!("parse_arg_general ident_to_pat"); let parser_snapshot_before_ty = self.clone(); - self.eat_incorrect_doc_comment("a method argument's type"); + self.eat_incorrect_doc_comment_for_arg_type(); let mut ty = self.parse_ty_common(true, true, allow_c_variadic); if ty.is_ok() && self.token != token::Comma && self.token != token::CloseDelim(token::Paren) { @@ -2032,7 +1537,7 @@ impl<'a> Parser<'a> { } match ty { Ok(ty) => { - let ident = Ident::new(keywords::Invalid.name(), self.prev_span); + let ident = Ident::new(kw::Invalid, self.prev_span); let pat = P(Pat { id: ast::DUMMY_NODE_ID, node: PatKind::Ident( @@ -2050,44 +1555,17 @@ impl<'a> Parser<'a> { // Recover from attempting to parse the argument as a type without pattern. err.cancel(); mem::replace(self, parser_snapshot_before_ty); - let pat = self.parse_pat(Some("argument name"))?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; - - let mut err = self.diagnostic().struct_span_err_with_code( - pat.span, - "patterns aren't allowed in methods without bodies", - DiagnosticId::Error("E0642".into()), - ); - err.span_suggestion_short( - pat.span, - "give this argument a name or use an underscore to ignore it", - "_".to_owned(), - Applicability::MachineApplicable, - ); - err.emit(); - - // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. - let pat = P(Pat { - node: PatKind::Wild, - span: pat.span, - id: ast::DUMMY_NODE_ID - }); - (pat, ty) + self.recover_arg_parse()? } } }; - Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID }) - } - - /// Parses a single function argument. - crate fn parse_arg(&mut self) -> PResult<'a, Arg> { - self.parse_arg_general(true, false, false) + Ok(Arg { attrs: attrs.into(), id: ast::DUMMY_NODE_ID, pat, ty }) } /// Parses an argument in a lambda header (e.g., `|arg, arg|`). fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> { + let attrs = self.parse_arg_attributes()?; let pat = self.parse_pat(Some("argument name"))?; let t = if self.eat(&token::Colon) { self.parse_ty()? @@ -2099,6 +1577,7 @@ impl<'a> Parser<'a> { }) }; Ok(Arg { + attrs: attrs.into(), ty: t, pat, id: ast::DUMMY_NODE_ID @@ -2113,93 +1592,13 @@ impl<'a> Parser<'a> { } } - /// Matches `token_lit = LIT_INTEGER | ...`. - fn parse_lit_token(&mut self) -> PResult<'a, LitKind> { - let out = match self.token { - token::Interpolated(ref nt) => match **nt { - token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node { - ExprKind::Lit(ref lit) => { lit.node.clone() } - _ => { return self.unexpected_last(&self.token); } - }, - _ => { return self.unexpected_last(&self.token); } - }, - token::Literal(lit, suf) => { - let diag = Some((self.span, &self.sess.span_diagnostic)); - let (suffix_illegal, result) = parse::lit_token(lit, suf, diag); - - if suffix_illegal { - let sp = self.span; - self.expect_no_suffix(sp, lit.literal_name(), suf) - } - - result.unwrap() - } - token::Dot if self.look_ahead(1, |t| match t { - token::Literal(parse::token::Lit::Integer(_) , _) => true, - _ => false, - }) => { // recover from `let x = .4;` - let lo = self.span; - self.bump(); - if let token::Literal( - parse::token::Lit::Integer(val), - suffix, - ) = self.token { - let suffix = suffix.and_then(|s| { - let s = s.as_str().get(); - if ["f32", "f64"].contains(&s) { - Some(s) - } else { - None - } - }).unwrap_or(""); - self.bump(); - let sp = lo.to(self.prev_span); - let mut err = self.diagnostic() - .struct_span_err(sp, "float literals must have an integer part"); - err.span_suggestion( - sp, - "must have an integer part", - format!("0.{}{}", val, suffix), - Applicability::MachineApplicable, - ); - err.emit(); - return Ok(match suffix { - "f32" => ast::LitKind::Float(val, ast::FloatTy::F32), - "f64" => ast::LitKind::Float(val, ast::FloatTy::F64), - _ => ast::LitKind::FloatUnsuffixed(val), - }); - } else { - unreachable!(); - }; - } - _ => { return self.unexpected_last(&self.token); } - }; - - self.bump(); - Ok(out) - } - - /// Matches `lit = true | false | token_lit`. - crate fn parse_lit(&mut self) -> PResult<'a, Lit> { - let lo = self.span; - let lit = if self.eat_keyword(keywords::True) { - LitKind::Bool(true) - } else if self.eat_keyword(keywords::False) { - LitKind::Bool(false) - } else { - let lit = self.parse_lit_token()?; - lit - }; - Ok(source_map::Spanned { node: lit, span: lo.to(self.prev_span) }) - } - /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). crate fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { maybe_whole_expr!(self); - let minus_lo = self.span; + let minus_lo = self.token.span; let minus_present = self.eat(&token::BinOp(token::Minus)); - let lo = self.span; + let lo = self.token.span; let literal = self.parse_lit()?; let hi = self.prev_span; let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new()); @@ -2214,22 +1613,22 @@ impl<'a> Parser<'a> { } fn parse_path_segment_ident(&mut self) -> PResult<'a, ast::Ident> { - match self.token { - token::Ident(ident, _) if self.token.is_path_segment_keyword() => { - let span = self.span; + match self.token.kind { + token::Ident(name, _) if name.is_path_segment_keyword() => { + let span = self.token.span; self.bump(); - Ok(Ident::new(ident.name, span)) + Ok(Ident::new(name, span)) } _ => self.parse_ident(), } } fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> { - match self.token { - token::Ident(ident, false) if ident.name == keywords::Underscore.name() => { - let span = self.span; + match self.token.kind { + token::Ident(name, false) if name == kw::Underscore => { + let span = self.token.span; self.bump(); - Ok(Ident::new(ident.name, span)) + Ok(Ident::new(name, span)) } _ => self.parse_ident(), } @@ -2254,13 +1653,13 @@ impl<'a> Parser<'a> { // above). `path_span` has the span of that path, or an empty // span in the case of something like `::Bar`. let (mut path, path_span); - if self.eat_keyword(keywords::As) { - let path_lo = self.span; + if self.eat_keyword(kw::As) { + let path_lo = self.token.span; path = self.parse_path(PathStyle::Type)?; path_span = path_lo.to(self.prev_span); } else { - path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP }; - path_span = self.span.to(self.span); + path_span = self.token.span.to(self.token.span); + path = ast::Path { segments: Vec::new(), span: path_span }; } // See doc comment for `unmatched_angle_bracket_count`. @@ -2273,7 +1672,7 @@ impl<'a> Parser<'a> { self.expect(&token::ModSep)?; let qself = QSelf { ty, path_span, position: path.segments.len() }; - self.parse_path_segments(&mut path.segments, style, true)?; + self.parse_path_segments(&mut path.segments, style)?; Ok((qself, ast::Path { segments: path.segments, span: lo.to(self.prev_span) })) } @@ -2289,11 +1688,6 @@ impl<'a> Parser<'a> { /// `Fn(Args)` (without disambiguator) /// `Fn::(Args)` (with disambiguator) pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, ast::Path> { - self.parse_path_common(style, true) - } - - crate fn parse_path_common(&mut self, style: PathStyle, enable_warning: bool) - -> PResult<'a, ast::Path> { maybe_whole!(self, NtPath, |path| { if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some()) { @@ -2302,13 +1696,13 @@ impl<'a> Parser<'a> { path }); - let lo = self.meta_var_span.unwrap_or(self.span); + let lo = self.meta_var_span.unwrap_or(self.token.span); let mut segments = Vec::new(); - let mod_sep_ctxt = self.span.ctxt(); + let mod_sep_ctxt = self.token.span.ctxt(); if self.eat(&token::ModSep) { segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))); } - self.parse_path_segments(&mut segments, style, enable_warning)?; + self.parse_path_segments(&mut segments, style)?; Ok(ast::Path { segments, span: lo.to(self.prev_span) }) } @@ -2317,10 +1711,10 @@ impl<'a> Parser<'a> { /// backwards-compatibility. This is used when parsing derive macro paths in `#[derive]` /// attributes. pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, ast::Path> { - let meta_ident = match self.token { + let meta_ident = match self.token.kind { token::Interpolated(ref nt) => match **nt { token::NtMeta(ref meta) => match meta.node { - ast::MetaItemKind::Word => Some(meta.ident.clone()), + ast::MetaItemKind::Word => Some(meta.path.clone()), _ => None, }, _ => None, @@ -2334,13 +1728,12 @@ impl<'a> Parser<'a> { self.parse_path(style) } - fn parse_path_segments(&mut self, + crate fn parse_path_segments(&mut self, segments: &mut Vec, - style: PathStyle, - enable_warning: bool) + style: PathStyle) -> PResult<'a, ()> { loop { - let segment = self.parse_path_segment(style, enable_warning)?; + let segment = self.parse_path_segment(style)?; if style == PathStyle::Expr { // In order to check for trailing angle brackets, we must have finished // recursing (`parse_path_segment` can indirectly call this function), @@ -2368,12 +1761,12 @@ impl<'a> Parser<'a> { } } - fn parse_path_segment(&mut self, style: PathStyle, enable_warning: bool) - -> PResult<'a, PathSegment> { + fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> { let ident = self.parse_path_segment_ident()?; - let is_args_start = |token: &token::Token| match *token { - token::Lt | token::BinOp(token::Shl) | token::OpenDelim(token::Paren) => true, + let is_args_start = |token: &Token| match token.kind { + token::Lt | token::BinOp(token::Shl) | token::OpenDelim(token::Paren) + | token::LArrow => true, _ => false, }; let check_args_start = |this: &mut Self| { @@ -2386,13 +1779,6 @@ impl<'a> Parser<'a> { Ok(if style == PathStyle::Type && check_args_start(self) || style != PathStyle::Mod && self.check(&token::ModSep) && self.look_ahead(1, |t| is_args_start(t)) { - // Generic arguments are found - `<`, `(`, `::<` or `::(`. - if self.eat(&token::ModSep) && style == PathStyle::Type && enable_warning { - self.diagnostic().struct_span_warn(self.prev_span, "unnecessary path disambiguator") - .span_label(self.prev_span, "try removing `::`").emit(); - } - let lo = self.span; - // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If // it isn't, then we reset the unmatched angle bracket count as we're about to start // parsing a new path. @@ -2401,13 +1787,16 @@ impl<'a> Parser<'a> { self.max_angle_bracket_count = 0; } + // Generic arguments are found - `<`, `(`, `::<` or `::(`. + self.eat(&token::ModSep); + let lo = self.token.span; let args = if self.eat_lt() { // `<'a, T, A = U>` - let (args, bindings) = + let (args, constraints) = self.parse_generic_args_with_leaning_angle_bracket_recovery(style, lo)?; self.expect_gt()?; let span = lo.to(self.prev_span); - AngleBracketedArgs { args, bindings, span }.into() + AngleBracketedArgs { args, constraints, span }.into() } else { // `(T, U) -> R` self.bump(); // `(` @@ -2443,17 +1832,17 @@ impl<'a> Parser<'a> { /// Parses a single lifetime `'a` or panics. crate fn expect_lifetime(&mut self) -> Lifetime { if let Some(ident) = self.token.lifetime() { - let span = self.span; + let span = self.token.span; self.bump(); Lifetime { ident: Ident::new(ident.name, span), id: ast::DUMMY_NODE_ID } } else { - self.span_bug(self.span, "not a lifetime") + self.span_bug(self.token.span, "not a lifetime") } } fn eat_label(&mut self) -> Option for () { + fn from(_: A) {} +} + +fn main() {} diff --git a/src/test/incremental/issue-61530.rs b/src/test/incremental/issue-61530.rs new file mode 100644 index 0000000000000..06b2957ac62c9 --- /dev/null +++ b/src/test/incremental/issue-61530.rs @@ -0,0 +1,17 @@ +#![feature(repr_simd, platform_intrinsics)] + +// revisions:rpass1 rpass2 + +#[repr(simd)] +struct I32x2(i32, i32); + +extern "platform-intrinsic" { + fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; +} + +fn main() { + unsafe { + let _: I32x2 = simd_shuffle2(I32x2(1, 2), I32x2(3, 4), [0, 0]); + let _: I32x2 = simd_shuffle2(I32x2(1, 2), I32x2(3, 4), [0, 0]); + } +} diff --git a/src/test/incremental/krate-inherent.rs b/src/test/incremental/krate-inherent.rs index e01ce317a2070..3e8d8fb1f94f1 100644 --- a/src/test/incremental/krate-inherent.rs +++ b/src/test/incremental/krate-inherent.rs @@ -21,4 +21,3 @@ pub mod x { #[cfg(cfail1)] pub fn bar() { } // remove this unrelated fn in cfail2, which should not affect `x::method` - diff --git a/src/test/incremental/krate_reassign_34991/auxiliary/a.rs b/src/test/incremental/krate_reassign_34991/auxiliary/a.rs index 33fa789fcae45..69be8d3bc0318 100644 --- a/src/test/incremental/krate_reassign_34991/auxiliary/a.rs +++ b/src/test/incremental/krate_reassign_34991/auxiliary/a.rs @@ -1,4 +1,3 @@ #![crate_type="rlib"] pub type X = u32; - diff --git a/src/test/incremental/no_mangle.rs b/src/test/incremental/no_mangle.rs new file mode 100644 index 0000000000000..b1c9b2bc37f64 --- /dev/null +++ b/src/test/incremental/no_mangle.rs @@ -0,0 +1,10 @@ +// revisions:cfail1 cfail2 +// check-pass +// compile-flags: --crate-type cdylib + +#![deny(unused_attributes)] + +#[no_mangle] +pub extern "C" fn rust_no_mangle() -> i32 { + 42 +} diff --git a/src/test/incremental/remapped_paths_cc/auxiliary/extern_crate.rs b/src/test/incremental/remapped_paths_cc/auxiliary/extern_crate.rs index 52e7f4bd7c782..627b99445ea81 100644 --- a/src/test/incremental/remapped_paths_cc/auxiliary/extern_crate.rs +++ b/src/test/incremental/remapped_paths_cc/auxiliary/extern_crate.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - //[rpass1] compile-flags: -g //[rpass2] compile-flags: -g //[rpass3] compile-flags: -g --remap-path-prefix={{src-base}}=/the/src diff --git a/src/test/incremental/rlib_cross_crate/b.rs b/src/test/incremental/rlib_cross_crate/b.rs index 7c3dcf3a8157b..81b84ba741dc8 100644 --- a/src/test/incremental/rlib_cross_crate/b.rs +++ b/src/test/incremental/rlib_cross_crate/b.rs @@ -12,15 +12,15 @@ extern crate a; -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] -#[rustc_clean(label="TypeckTables", cfg="rpass3")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass3")] pub fn use_X() -> u32 { let x: a::X = 22; x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] -#[rustc_clean(label="TypeckTables", cfg="rpass3")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass3")] pub fn use_Y() { let x: a::Y = 'c'; } diff --git a/src/test/incremental/span_hash_stable/main.rs b/src/test/incremental/span_hash_stable/main.rs index f19c99e1986e6..f1d7de1455938 100644 --- a/src/test/incremental/span_hash_stable/main.rs +++ b/src/test/incremental/span_hash_stable/main.rs @@ -21,4 +21,3 @@ fn main() { b: 3, }; } - diff --git a/src/test/incremental/spans_significant_w_panic.rs b/src/test/incremental/spans_significant_w_panic.rs index ecda56f7e942e..2574ef5199c86 100644 --- a/src/test/incremental/spans_significant_w_panic.rs +++ b/src/test/incremental/spans_significant_w_panic.rs @@ -13,7 +13,7 @@ pub fn main() { } #[cfg(rpass2)] -#[rustc_dirty(label="MirOptimized", cfg="rpass2")] +#[rustc_dirty(label="optimized_mir", cfg="rpass2")] pub fn main() { let _ = 0u8 + 1; } diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs index 41c72335d6305..c39d4145b586f 100644 --- a/src/test/incremental/string_constant.rs +++ b/src/test/incremental/string_constant.rs @@ -19,7 +19,7 @@ pub mod x { #[cfg(cfail2)] #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_dirty(label="MirOptimized", cfg="cfail2")] + #[rustc_dirty(label="optimized_mir", cfg="cfail2")] pub fn x() { println!("{}", "2"); } @@ -28,8 +28,8 @@ pub mod x { pub mod y { use x; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] - #[rustc_clean(label="MirOptimized", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] + #[rustc_clean(label="optimized_mir", cfg="cfail2")] pub fn y() { x::x(); } @@ -38,8 +38,8 @@ pub mod y { pub mod z { use y; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] - #[rustc_clean(label="MirOptimized", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] + #[rustc_clean(label="optimized_mir", cfg="cfail2")] pub fn z() { y::y(); } diff --git a/src/test/incremental/struct_add_field.rs b/src/test/incremental/struct_add_field.rs index d019a3d2ab887..d2e1e7decf54e 100644 --- a/src/test/incremental/struct_add_field.rs +++ b/src/test/incremental/struct_add_field.rs @@ -21,17 +21,17 @@ pub struct Y { pub y: char } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_X(x: X) -> u32 { x.x as u32 } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_change_field_name.rs b/src/test/incremental/struct_change_field_name.rs index 28011efed9cee..68356f703bcf8 100644 --- a/src/test/incremental/struct_change_field_name.rs +++ b/src/test/incremental/struct_change_field_name.rs @@ -24,7 +24,7 @@ pub struct Y { pub y: char } -#[rustc_dirty(label="TypeckTables", cfg="cfail2")] +#[rustc_dirty(label="typeck_tables_of", cfg="cfail2")] pub fn use_X() -> u32 { let x: X = X { x: 22 }; //[cfail2]~^ ERROR struct `X` has no field named `x` @@ -32,13 +32,13 @@ pub fn use_X() -> u32 { //[cfail2]~^ ERROR no field `x` on type `X` } -#[rustc_dirty(label="TypeckTables", cfg="cfail2")] +#[rustc_dirty(label="typeck_tables_of", cfg="cfail2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 //[cfail2]~^ ERROR no field `x` on type `X` } -#[rustc_clean(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_change_field_type.rs b/src/test/incremental/struct_change_field_type.rs index cb4a83c2f9a40..308ec84fa72ef 100644 --- a/src/test/incremental/struct_change_field_type.rs +++ b/src/test/incremental/struct_change_field_type.rs @@ -24,19 +24,19 @@ pub struct Y { pub y: char } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_X() -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_EmbedX(x: EmbedX) -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_change_field_type_cross_crate/b.rs b/src/test/incremental/struct_change_field_type_cross_crate/b.rs index ecfd24cbaf418..9d84c2cf773b8 100644 --- a/src/test/incremental/struct_change_field_type_cross_crate/b.rs +++ b/src/test/incremental/struct_change_field_type_cross_crate/b.rs @@ -8,18 +8,18 @@ extern crate a; use a::*; -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_X() -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_change_nothing.rs b/src/test/incremental/struct_change_nothing.rs index e62c004a83da0..bbded1da21619 100644 --- a/src/test/incremental/struct_change_nothing.rs +++ b/src/test/incremental/struct_change_nothing.rs @@ -24,19 +24,19 @@ pub struct Y { pub y: char } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_X() -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_EmbedX(x: EmbedX) -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_remove_field.rs b/src/test/incremental/struct_remove_field.rs index 572a2c640e6d2..4c4028bbe5bdd 100644 --- a/src/test/incremental/struct_remove_field.rs +++ b/src/test/incremental/struct_remove_field.rs @@ -25,17 +25,17 @@ pub struct Y { pub y: char } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_X(x: X) -> u32 { x.x as u32 } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/type_alias_cross_crate/b.rs b/src/test/incremental/type_alias_cross_crate/b.rs index 9261a0fb290ea..cef2e4bab12d7 100644 --- a/src/test/incremental/type_alias_cross_crate/b.rs +++ b/src/test/incremental/type_alias_cross_crate/b.rs @@ -6,15 +6,15 @@ extern crate a; -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] -#[rustc_clean(label="TypeckTables", cfg="rpass3")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass3")] pub fn use_X() -> u32 { let x: a::X = 22; x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] -#[rustc_clean(label="TypeckTables", cfg="rpass3")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass3")] pub fn use_Y() { let x: a::Y = 'c'; } diff --git a/src/test/mir-opt/array-index-is-temporary.rs b/src/test/mir-opt/array-index-is-temporary.rs index 856e1063f6001..00a6b26d0cf22 100644 --- a/src/test/mir-opt/array-index-is-temporary.rs +++ b/src/test/mir-opt/array-index-is-temporary.rs @@ -18,25 +18,24 @@ fn main() { // START rustc.main.EraseRegions.after.mir // bb0: { // ... -// _6 = &mut _2; -// _5 = &mut (*_6); -// _4 = move _5 as *mut usize (Misc); -// _3 = move _4; +// _5 = &mut _2; +// _4 = &mut (*_5); +// _3 = move _4 as *mut usize (Misc); // ... -// _8 = _3; -// _7 = const foo(move _8) -> bb1; +// _7 = _3; +// _6 = const foo(move _7) -> bb1; // } // // bb1: { // ... -// _9 = _2; -// _10 = Len(_1); -// _11 = Lt(_9, _10); -// assert(move _11, "index out of bounds: the len is move _10 but the index is _9") -> bb2; +// _8 = _2; +// _9 = Len(_1); +// _10 = Lt(_8, _9); +// assert(move _10, "index out of bounds: the len is move _9 but the index is _8") -> bb2; // } // // bb2: { -// _1[_9] = move _7; +// _1[_8] = move _6; // ... // return; // } diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs index 1bbbe67a12cb8..ca0e9fa811a26 100644 --- a/src/test/mir-opt/basic_assignment.rs +++ b/src/test/mir-opt/basic_assignment.rs @@ -5,8 +5,6 @@ // so subtle breakage in them can leave a quite hard-to-find trail of // destruction. -// ignore-tidy-linelength - fn main() { let nodrop_x = false; let nodrop_y; @@ -35,7 +33,7 @@ fn main() { // _2 = move _3; // StorageDead(_3); // StorageLive(_4); -// _4 = std::option::Option>::None; +// _4 = std::option::Option::>::None; // FakeRead(ForLet, _4); // AscribeUserType(_4, o, UserTypeProjection { base: UserType(1), projs: [] }); // StorageLive(_5); @@ -48,7 +46,7 @@ fn main() { // drop(_6) -> [return: bb6, unwind: bb4]; // } // ... -// bb5: { +// bb5 (cleanup): { // drop(_6) -> bb4; // } // END rustc.main.SimplifyCfg-initial.after.mir diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs index ad5cf42029e9d..d9fa3d3d4736d 100644 --- a/src/test/mir-opt/box_expr.rs +++ b/src/test/mir-opt/box_expr.rs @@ -22,15 +22,12 @@ impl Drop for S { // END RUST SOURCE // START rustc.main.ElaborateDrops.before.mir // let mut _0: (); -// scope 1 { -// } -// scope 2 { -// let _1: std::boxed::Box; -// } +// let _1: std::boxed::Box; // let mut _2: std::boxed::Box; -// let mut _3: (); +// let _3: (); // let mut _4: std::boxed::Box; -// +// scope 1 { +// } // bb0: { // StorageLive(_1); // StorageLive(_2); @@ -38,7 +35,7 @@ impl Drop for S { // (*_2) = const S::new() -> [return: bb2, unwind: bb3]; // } // -// bb1: { +// bb1 (cleanup): { // resume; // } // @@ -47,31 +44,33 @@ impl Drop for S { // drop(_2) -> bb4; // } // -// bb3: { +// bb3 (cleanup): { // drop(_2) -> bb1; // } // // bb4: { // StorageDead(_2); +// StorageLive(_3); // StorageLive(_4); // _4 = move _1; -// _3 = const std::mem::drop(move _4) -> [return: bb5, unwind: bb7]; +// _3 = const std::mem::drop::>(move _4) -> [return: bb5, unwind: bb7]; // } // // bb5: { // drop(_4) -> [return: bb8, unwind: bb6]; // } // -// bb6: { +// bb6 (cleanup): { // drop(_1) -> bb1; // } // -// bb7: { +// bb7 (cleanup): { // drop(_4) -> bb6; // } // // bb8: { // StorageDead(_4); +// StorageDead(_3); // _0 = (); // drop(_1) -> bb9; // } diff --git a/src/test/mir-opt/byte_slice.rs b/src/test/mir-opt/byte_slice.rs new file mode 100644 index 0000000000000..7edfa3e1124db --- /dev/null +++ b/src/test/mir-opt/byte_slice.rs @@ -0,0 +1,15 @@ +// compile-flags: -Z mir-opt-level=0 + +fn main() { + let x = b"foo"; + let y = [5u8, b'x']; +} + +// END RUST SOURCE +// START rustc.main.EraseRegions.after.mir +// ... +// _1 = const b"foo"; +// ... +// _2 = [const 5u8, const 120u8]; +// ... +// END rustc.main.EraseRegions.after.mir diff --git a/src/test/mir-opt/const_prop/array_index.rs b/src/test/mir-opt/const_prop/array_index.rs new file mode 100644 index 0000000000000..dd22eb5d604ea --- /dev/null +++ b/src/test/mir-opt/const_prop/array_index.rs @@ -0,0 +1,33 @@ +fn main() { + let x: u32 = [0, 1, 2, 3][2]; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _2 = [const 0u32, const 1u32, const 2u32, const 3u32]; +// ... +// _3 = const 2usize; +// _4 = const 4usize; +// _5 = Lt(_3, _4); +// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb1; +// } +// bb1: { +// _1 = _2[_3]; +// ... +// return; +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _5 = const true; +// assert(const true, "index out of bounds: the len is move _4 but the index is _3") -> bb1; +// } +// bb1: { +// _1 = _2[_3]; +// ... +// return; +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/mir-opt/const_prop/checked_add.rs b/src/test/mir-opt/const_prop/checked_add.rs new file mode 100644 index 0000000000000..fe98cf24eec00 --- /dev/null +++ b/src/test/mir-opt/const_prop/checked_add.rs @@ -0,0 +1,21 @@ +// compile-flags: -C overflow-checks=on + +fn main() { + let x: u32 = 1 + 1; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _2 = CheckedAdd(const 1u32, const 1u32); +// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1; +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _2 = (const 2u32, const false); +// assert(!const false, "attempt to add with overflow") -> bb1; +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs new file mode 100644 index 0000000000000..85ed8d55b243b --- /dev/null +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs @@ -0,0 +1,35 @@ +#[inline(never)] +fn read(_: usize) { } + +fn main() { + const FOO: &i32 = &1; + let x = FOO as *const i32 as usize; + read(x); +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _3 = _4; +// _2 = move _3 as *const i32 (Misc); +// ... +// _1 = move _2 as usize (Misc); +// ... +// _6 = _1; +// _5 = const read(move _6) -> bb1; +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _4 = const Scalar(AllocId(1).0x0) : &i32; +// _3 = const Scalar(AllocId(1).0x0) : &i32; +// _2 = const Scalar(AllocId(1).0x0) : *const i32; +// ... +// _1 = move _2 as usize (Misc); +// ... +// _6 = _1; +// _5 = const read(move _6) -> bb1; +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/mir-opt/const_prop/indirect.rs b/src/test/mir-opt/const_prop/indirect.rs new file mode 100644 index 0000000000000..b4ee18ed1b53b --- /dev/null +++ b/src/test/mir-opt/const_prop/indirect.rs @@ -0,0 +1,23 @@ +// compile-flags: -C overflow-checks=on + +fn main() { + let x = (2u32 as u8) + 1; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _2 = const 2u32 as u8 (Misc); +// _3 = CheckedAdd(move _2, const 1u8); +// assert(!move (_3.1: bool), "attempt to add with overflow") -> bb1; +//} +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _2 = const 2u8; +// _3 = (const 3u8, const false); +// assert(!const false, "attempt to add with overflow") -> bb1; +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/mir-opt/const_prop/ref_deref.rs b/src/test/mir-opt/const_prop/ref_deref.rs new file mode 100644 index 0000000000000..2d04822c0e789 --- /dev/null +++ b/src/test/mir-opt/const_prop/ref_deref.rs @@ -0,0 +1,21 @@ +fn main() { + *(&4); +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _2 = &(promoted[0]: i32); +// _1 = (*_2); +// ... +//} +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _2 = const Scalar(AllocId(0).0x0) : &i32; +// _1 = const 4i32; +// ... +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.rs b/src/test/mir-opt/const_prop/reify_fn_ptr.rs new file mode 100644 index 0000000000000..809eb19ade899 --- /dev/null +++ b/src/test/mir-opt/const_prop/reify_fn_ptr.rs @@ -0,0 +1,25 @@ +fn main() { + let _ = main as usize as *const fn(); +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _3 = const main as fn() (Pointer(ReifyFnPointer)); +// _2 = move _3 as usize (Misc); +// ... +// _1 = move _2 as *const fn() (Misc); +// ... +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _3 = const Scalar(AllocId(1).0x0) : fn(); +// _2 = move _3 as usize (Misc); +// ... +// _1 = const Scalar(AllocId(1).0x0) : *const fn(); +// ... +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/mir-opt/const_prop/slice_len.rs b/src/test/mir-opt/const_prop/slice_len.rs new file mode 100644 index 0000000000000..5babeb195a826 --- /dev/null +++ b/src/test/mir-opt/const_prop/slice_len.rs @@ -0,0 +1,41 @@ +fn main() { + (&[1u32, 2, 3] as &[u32])[1]; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _4 = &(promoted[0]: [u32; 3]); +// _3 = _4; +// _2 = move _3 as &[u32] (Pointer(Unsize)); +// ... +// _6 = const 1usize; +// _7 = Len((*_2)); +// _8 = Lt(_6, _7); +// assert(move _8, "index out of bounds: the len is move _7 but the index is _6") -> bb1; +// } +// bb1: { +// _1 = (*_2)[_6]; +// ... +// return; +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _4 = const Scalar(AllocId(0).0x0) : &[u32; 3]; +// _3 = const Scalar(AllocId(0).0x0) : &[u32; 3]; +// _2 = move _3 as &[u32] (Pointer(Unsize)); +// ... +// _6 = const 1usize; +// _7 = const 3usize; +// _8 = const true; +// assert(const true, "index out of bounds: the len is move _7 but the index is _6") -> bb1; +// } +// bb1: { +// _1 = (*_2)[_6]; +// ... +// return; +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/mir-opt/const_prop/switch_int.rs b/src/test/mir-opt/const_prop/switch_int.rs new file mode 100644 index 0000000000000..904d303d87e31 --- /dev/null +++ b/src/test/mir-opt/const_prop/switch_int.rs @@ -0,0 +1,38 @@ +#[inline(never)] +fn foo(_: i32) { } + +fn main() { + match 1 { + 1 => foo(0), + _ => foo(-1), + } +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _1 = const 1i32; +// switchInt(_1) -> [1i32: bb2, otherwise: bb1]; +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// switchInt(const 1i32) -> [1i32: bb2, otherwise: bb1]; +// } +// END rustc.main.ConstProp.after.mir +// START rustc.main.SimplifyBranches-after-const-prop.before.mir +// bb0: { +// ... +// _1 = const 1i32; +// switchInt(const 1i32) -> [1i32: bb2, otherwise: bb1]; +// } +// END rustc.main.SimplifyBranches-after-const-prop.before.mir +// START rustc.main.SimplifyBranches-after-const-prop.after.mir +// bb0: { +// ... +// _1 = const 1i32; +// goto -> bb2; +// } +// END rustc.main.SimplifyBranches-after-const-prop.after.mir diff --git a/src/test/mir-opt/copy_propagation_arg.rs b/src/test/mir-opt/copy_propagation_arg.rs index 4e05484a80c1e..5e5fed12fb5f3 100644 --- a/src/test/mir-opt/copy_propagation_arg.rs +++ b/src/test/mir-opt/copy_propagation_arg.rs @@ -61,12 +61,14 @@ fn main() { // END rustc.foo.CopyPropagation.after.mir // START rustc.bar.CopyPropagation.before.mir // bb0: { +// StorageLive(_2); // StorageLive(_3); // _3 = _1; // _2 = const dummy(move _3) -> bb1; // } // bb1: { // StorageDead(_3); +// StorageDead(_2); // _1 = const 5u8; // ... // return; diff --git a/src/test/mir-opt/deaggregator_test_enum_2.rs b/src/test/mir-opt/deaggregator_test_enum_2.rs index 59c75739d81a4..b39ad1bef8e34 100644 --- a/src/test/mir-opt/deaggregator_test_enum_2.rs +++ b/src/test/mir-opt/deaggregator_test_enum_2.rs @@ -21,30 +21,22 @@ fn main() { // END RUST SOURCE // START rustc.test1.Deaggregator.before.mir // bb1: { -// StorageLive(_4); -// _4 = _2; -// _0 = Foo::A(move _4,); -// StorageDead(_4); -// goto -> bb3; -// } -// bb2: { // StorageLive(_5); // _5 = _2; // _0 = Foo::B(move _5,); // StorageDead(_5); // goto -> bb3; // } -// END rustc.test1.Deaggregator.before.mir -// START rustc.test1.Deaggregator.after.mir -// bb1: { +// bb2: { // StorageLive(_4); // _4 = _2; -// ((_0 as A).0: i32) = move _4; -// discriminant(_0) = 0; +// _0 = Foo::A(move _4,); // StorageDead(_4); // goto -> bb3; // } -// bb2: { +// END rustc.test1.Deaggregator.before.mir +// START rustc.test1.Deaggregator.after.mir +// bb1: { // StorageLive(_5); // _5 = _2; // ((_0 as B).0: i32) = move _5; @@ -52,5 +44,13 @@ fn main() { // StorageDead(_5); // goto -> bb3; // } +// bb2: { +// StorageLive(_4); +// _4 = _2; +// ((_0 as A).0: i32) = move _4; +// discriminant(_0) = 0; +// StorageDead(_4); +// goto -> bb3; +// } // END rustc.test1.Deaggregator.after.mir // diff --git a/src/test/mir-opt/generator-drop-cleanup.rs b/src/test/mir-opt/generator-drop-cleanup.rs new file mode 100644 index 0000000000000..f97e1ba6c89d4 --- /dev/null +++ b/src/test/mir-opt/generator-drop-cleanup.rs @@ -0,0 +1,47 @@ +#![feature(generators, generator_trait)] + +// Regression test for #58892, generator drop shims should not have blocks +// spuriously marked as cleanup + +fn main() { + let gen = || { + yield; + }; +} + +// END RUST SOURCE + +// START rustc.main-{{closure}}.generator_drop.0.mir +// bb0: { +// _5 = discriminant((*_1)); +// switchInt(move _5) -> [0u32: bb4, 3u32: bb7, otherwise: bb8]; +// } +// bb1: { +// StorageDead(_3); +// StorageDead(_2); +// goto -> bb5; +// } +// bb2: { +// return; +// } +// bb3: { +// return; +// } +// bb4: { +// goto -> bb6; +// } +// bb5: { +// goto -> bb2; +// } +// bb6: { +// goto -> bb3; +// } +// bb7: { +// StorageLive(_2); +// StorageLive(_3); +// goto -> bb1; +// } +// bb8: { +// return; +// } +// END rustc.main-{{closure}}.generator_drop.0.mir diff --git a/src/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs new file mode 100644 index 0000000000000..bcdb937542716 --- /dev/null +++ b/src/test/mir-opt/generator-storage-dead-unwind.rs @@ -0,0 +1,112 @@ +// ignore-wasm32-bare compiled with panic=abort by default + +// Test that we generate StorageDead on unwind paths for generators. +// +// Basic block and local names can safely change, but the StorageDead statements +// should not go away. + +#![feature(generators, generator_trait)] + +struct Foo(i32); + +impl Drop for Foo { + fn drop(&mut self) {} +} + +struct Bar(i32); + +fn take(_x: T) {} + +fn main() { + let _gen = || { + let a = Foo(5); + let b = Bar(6); + yield; + take(a); + take(b); + }; +} + +// END RUST SOURCE + +// START rustc.main-{{closure}}.StateTransform.before.mir +// ... +// let _2: Foo; +// ... +// let mut _7: Foo; +// ... +// let mut _9: Bar; +// scope 1 { +// let _3: Bar; +// scope 2 { +// } +// } +// bb0: { +// StorageLive(_2); +// _2 = Foo(const 5i32,); +// StorageLive(_3); +// _3 = Bar(const 6i32,); +// ... +// _1 = suspend(move _5) -> [resume: bb2, drop: bb4]; +// } +// bb1 (cleanup): { +// resume; +// } +// bb2: { +// ... +// StorageLive(_6); +// StorageLive(_7); +// _7 = move _2; +// _6 = const take::(move _7) -> [return: bb9, unwind: bb8]; +// } +// bb3 (cleanup): { +// StorageDead(_2); +// drop(_1) -> bb1; +// } +// bb4: { +// ... +// StorageDead(_3); +// drop(_2) -> [return: bb5, unwind: bb3]; +// } +// bb5: { +// StorageDead(_2); +// drop(_1) -> [return: bb6, unwind: bb1]; +// } +// bb6: { +// generator_drop; +// } +// bb7 (cleanup): { +// StorageDead(_3); +// StorageDead(_2); +// drop(_1) -> bb1; +// } +// bb8 (cleanup): { +// StorageDead(_7); +// StorageDead(_6); +// goto -> bb7; +// } +// bb9: { +// StorageDead(_7); +// StorageDead(_6); +// StorageLive(_8); +// StorageLive(_9); +// _9 = move _3; +// _8 = const take::(move _9) -> [return: bb10, unwind: bb11]; +// } +// bb10: { +// StorageDead(_9); +// StorageDead(_8); +// ... +// StorageDead(_3); +// StorageDead(_2); +// drop(_1) -> [return: bb12, unwind: bb1]; +// } +// bb11 (cleanup): { +// StorageDead(_9); +// StorageDead(_8); +// goto -> bb7; +// } +// bb12: { +// return; +// } +// END rustc.main-{{closure}}.StateTransform.before.mir diff --git a/src/test/mir-opt/graphviz.rs b/src/test/mir-opt/graphviz.rs new file mode 100644 index 0000000000000..67a6d1d263bf5 --- /dev/null +++ b/src/test/mir-opt/graphviz.rs @@ -0,0 +1,23 @@ +// Test graphviz output +// compile-flags: -Z dump-mir-graphviz + +// ignore-tidy-linelength + +fn main() {} + +// END RUST SOURCE +// START rustc.main.mir_map.0.dot +// digraph Mir_0_12 { // The name here MUST be an ASCII identifier. +// graph [fontname="monospace"]; +// node [fontname="monospace"]; +// edge [fontname="monospace"]; +// label=>; +// bb0 [shape="none", label=<

    0
    _0 = ()
    goto
    +// >]; +// bb1 [shape="none", label=<
    1
    resume
    +// >]; +// bb2 [shape="none", label=<
    2
    return
    +// >]; +// bb0 -> bb2 [label=""]; +// } +// END rustc.main.mir_map.0.dot diff --git a/src/test/mir-opt/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline-closure-borrows-arg.rs index 9f925e891c0de..0e1db68f37255 100644 --- a/src/test/mir-opt/inline-closure-borrows-arg.rs +++ b/src/test/mir-opt/inline-closure-borrows-arg.rs @@ -20,7 +20,7 @@ fn foo(_t: T, q: &i32) -> i32 { // ... // bb0: { // ... -// _3 = [closure@NodeId(53)]; +// _3 = [closure@HirId { owner: DefIndex(13), local_id: 31 }]; // ... // _4 = &_3; // ... diff --git a/src/test/mir-opt/inline-closure.rs b/src/test/mir-opt/inline-closure.rs index 68c88da9c0294..fa8557f3b38a7 100644 --- a/src/test/mir-opt/inline-closure.rs +++ b/src/test/mir-opt/inline-closure.rs @@ -16,7 +16,7 @@ fn foo(_t: T, q: i32) -> i32 { // ... // bb0: { // ... -// _3 = [closure@NodeId(39)]; +// _3 = [closure@HirId { owner: DefIndex(13), local_id: 15 }]; // ... // _4 = &_3; // ... diff --git a/src/test/mir-opt/inline-trait-method.rs b/src/test/mir-opt/inline-trait-method.rs index 0f79f43ee2df0..a2c5fb920cd30 100644 --- a/src/test/mir-opt/inline-trait-method.rs +++ b/src/test/mir-opt/inline-trait-method.rs @@ -25,7 +25,7 @@ impl X for () { // ... // bb0: { // ... -// _0 = const X::y(move _2) -> bb1; +// _0 = const ::y(move _2) -> bb1; // } // ... // END rustc.test.Inline.after.mir diff --git a/src/test/mir-opt/inline-trait-method_2.rs b/src/test/mir-opt/inline-trait-method_2.rs index 8f9f2535aa5f8..4ad4311113a3a 100644 --- a/src/test/mir-opt/inline-trait-method_2.rs +++ b/src/test/mir-opt/inline-trait-method_2.rs @@ -30,7 +30,7 @@ fn main() { // ... // bb0: { // ... -// _0 = const X::y(move _2) -> bb1; +// _0 = const ::y(move _2) -> bb1; // } // ... // END rustc.test2.Inline.after.mir diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs index 618ee2f740746..d980cc891dc40 100644 --- a/src/test/mir-opt/issue-38669.rs +++ b/src/test/mir-opt/issue-38669.rs @@ -18,28 +18,33 @@ fn main() { // FakeRead(ForLet, _1); // goto -> bb2; // } -// bb1: { +// bb1 (cleanup): { // resume; // } // bb2: { // falseUnwind -> [real: bb3, cleanup: bb1]; // } // bb3: { +// StorageLive(_3); // StorageLive(_4); // _4 = _1; -// switchInt(move _4) -> [false: bb5, otherwise: bb4]; -// } -// bb4: { -// _0 = (); -// StorageDead(_4); -// StorageDead(_1); -// return; +// FakeRead(ForMatchedPlace, _4); +// switchInt(_4) -> [false: bb5, otherwise: bb4]; // } +// ... // bb5: { // _3 = (); // StorageDead(_4); +// StorageDead(_3); // _1 = const true; // _2 = (); // goto -> bb2; // } +// bb6: { +// _0 = (); +// StorageDead(_4); +// StorageDead(_3); +// StorageDead(_1); +// return; +// } // END rustc.main.SimplifyCfg-initial.after.mir diff --git a/src/test/mir-opt/issue-41110.rs b/src/test/mir-opt/issue-41110.rs index 31ad1ebd9ff62..e73390f52b5d5 100644 --- a/src/test/mir-opt/issue-41110.rs +++ b/src/test/mir-opt/issue-41110.rs @@ -29,27 +29,25 @@ impl S { // END RUST SOURCE // START rustc.main.ElaborateDrops.after.mir // let mut _0: (); -// scope 1 { -// } -// scope 2 { -// let _1: (); -// } +// let _1: (); // let mut _2: S; // let mut _3: S; // let mut _4: S; // let mut _5: bool; +// scope 1 { +// } +// ... // bb0: { // END rustc.main.ElaborateDrops.after.mir // START rustc.test.ElaborateDrops.after.mir // let mut _0: (); -// ... -// let mut _2: S; -// ... // let _1: S; -// ... -// let mut _3: (); +// let _3: (); // let mut _4: S; // let mut _5: S; // let mut _6: bool; +// ... +// let mut _2: S; +// ... // bb0: { // END rustc.test.ElaborateDrops.after.mir diff --git a/src/test/mir-opt/issue-41697.rs b/src/test/mir-opt/issue-41697.rs index 9db25b15f6835..5a461d6148254 100644 --- a/src/test/mir-opt/issue-41697.rs +++ b/src/test/mir-opt/issue-41697.rs @@ -1,7 +1,7 @@ // Regression test for #41697. Using dump-mir was triggering // artificial cycles: during type-checking, we had to get the MIR for // the constant expressions in `[u8; 2]`, which in turn would trigger -// an attempt to get the item-path, which in turn would request the +// an attempt to get the def-path, which in turn would request the // types of the impl, which would trigger a cycle. We suppressed this // cycle now by forcing mir-dump to avoid asking for types of an impl. diff --git a/src/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs index 0f0401a55eaca..d0dbcbd7515f8 100644 --- a/src/test/mir-opt/issue-49232.rs +++ b/src/test/mir-opt/issue-49232.rs @@ -17,16 +17,14 @@ fn main() { // START rustc.main.mir_map.0.mir // fn main() -> (){ // let mut _0: (); -// scope 1 { -// } -// scope 2 { -// let _2: i32; -// } // let mut _1: (); +// let _2: i32; // let mut _3: bool; // let mut _4: !; -// let mut _5: (); +// let _5: (); // let mut _6: &i32; +// scope 1 { +// } // bb0: { // goto -> bb1; // } @@ -34,77 +32,60 @@ fn main() { // falseUnwind -> [real: bb3, cleanup: bb4]; // } // bb2: { -// goto -> bb20; +// goto -> bb14; // } // bb3: { // StorageLive(_2); // StorageLive(_3); // _3 = const true; // FakeRead(ForMatchedPlace, _3); -// switchInt(_3) -> [false: bb9, otherwise: bb8]; +// switchInt(_3) -> [false: bb5, otherwise: bb6]; // } -// bb4: { +// bb4 (cleanup): { // resume; // } // bb5: { -// falseEdges -> [real: bb11, imaginary: bb6]; +// falseEdges -> [real: bb7, imaginary: bb6]; // } // bb6: { -// falseEdges -> [real: bb13, imaginary: bb7]; +// _0 = (); +// goto -> bb8; // } // bb7: { -// unreachable; -// } -// bb8: { -// goto -> bb6; -// } -// bb9: { -// goto -> bb5; -// } -// bb10: { // _2 = const 4i32; -// goto -> bb18; -// } -// bb11: { -// goto -> bb10; -// } -// bb12: { -// _0 = (); -// goto -> bb14; -// } -// bb13: { // goto -> bb12; // } -// bb14: { +// bb8: { // StorageDead(_3); -// goto -> bb15; +// goto -> bb9; // } -// bb15: { +// bb9: { // StorageDead(_2); // goto -> bb2; // } -// bb16: { +// bb10: { // _4 = (); // unreachable; // } -// bb17: { -// StorageDead(_4); -// goto -> bb18; +// bb11: { +// goto -> bb12; // } -// bb18: { +// bb12: { // FakeRead(ForLet, _2); // StorageDead(_3); +// StorageLive(_5); // StorageLive(_6); // _6 = &_2; -// _5 = const std::mem::drop(move _6) -> [return: bb19, unwind: bb4]; +// _5 = const std::mem::drop::<&i32>(move _6) -> [return: bb13, unwind: bb4]; // } -// bb19: { +// bb13: { // StorageDead(_6); +// StorageDead(_5); // _1 = (); // StorageDead(_2); // goto -> bb1; // } -// bb20: { +// bb14: { // return; // } // } diff --git a/src/test/mir-opt/loop_test.rs b/src/test/mir-opt/loop_test.rs index e44743aa4b780..177080c04f972 100644 --- a/src/test/mir-opt/loop_test.rs +++ b/src/test/mir-opt/loop_test.rs @@ -18,23 +18,26 @@ fn main() { // END RUST SOURCE // START rustc.main.SimplifyCfg-qualify-consts.after.mir // ... -// bb1: { // The cleanup block +// bb1 (cleanup): { // resume; // } // ... // bb3: { // Entry into the loop // _1 = (); -// goto -> bb4; +// StorageDead(_2); +// StorageDead(_1); +// goto -> bb5; // } -// bb4: { // The loop_block -// falseUnwind -> [real: bb5, cleanup: bb1]; +// ... +// bb5: { // The loop_block +// falseUnwind -> [real: bb6, cleanup: bb1]; // } -// bb5: { // The loop body (body_block) -// StorageLive(_5); -// _5 = const 1i32; -// FakeRead(ForLet, _5); -// StorageDead(_5); -// goto -> bb4; +// bb6: { // The loop body (body_block) +// StorageLive(_6); +// _6 = const 1i32; +// FakeRead(ForLet, _6); +// StorageDead(_6); +// goto -> bb5; // } // ... // END rustc.main.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/match-arm-scopes.rs b/src/test/mir-opt/match-arm-scopes.rs new file mode 100644 index 0000000000000..18e0642eb3427 --- /dev/null +++ b/src/test/mir-opt/match-arm-scopes.rs @@ -0,0 +1,227 @@ +// Test that StorageDead and Drops are generated properly for bindings in +// matches: +// * The MIR should only contain a single drop of `s` and `t`: at the end +// of their respective arms. +// * StorageDead and StorageLive statements are correctly matched up on +// non-unwind paths. +// * The visibility scopes of the match arms should be disjoint, and contain. +// all of the bindings for that scope. +// * No drop flags are used. + +#![feature(nll, bind_by_move_pattern_guards)] + +fn complicated_match(cond: bool, items: (bool, bool, String)) -> i32 { + match items { + (false, a, s) | (a, false, s) if if cond { return 3 } else { a } => 1, + (true, b, t) | (false, b, t) => 2, + } +} + +const CASES: &[(bool, bool, bool, i32)] = &[ + (false, false, false, 2), + (false, false, true, 1), + (false, true, false, 1), + (false, true, true, 2), + (true, false, false, 3), + (true, false, true, 3), + (true, true, false, 3), + (true, true, true, 2), +]; + +fn main() { + for &(cond, items_1, items_2, result) in CASES { + assert_eq!( + complicated_match(cond, (items_1, items_2, String::new())), + result, + ); + } +} + +// END RUST SOURCE +// START rustc.complicated_match.SimplifyCfg-initial.after.mir +// let mut _0: i32; +// let mut _3: &bool; // Temp for fake borrow of `items.0` +// let mut _4: &bool; // Temp for fake borrow of `items.1` +// let _5: bool; // `a` in arm +// let _6: &bool; // `a` in guard +// let _7: std::string::String; // `s` in arm +// let _8: &std::string::String; // `s` in guard +// let mut _9: bool; // `if cond { return 3 } else { a }` +// let mut _10: bool; // `cond` +// let mut _11: !; // `return 3` +// let mut _12: bool; // `if cond { return 3 } else { a }` +// let mut _13: bool; // `cond` +// let mut _14: !; // `return 3` +// let _15: bool; // `b` +// let _16: std::string::String; // `t` +// scope 1 { +// } +// scope 2 { +// } +// bb0: { +// FakeRead(ForMatchedPlace, _2); +// switchInt((_2.0: bool)) -> [false: bb2, otherwise: bb5]; +// } +// bb1 (cleanup): { +// resume; +// } +// bb2: { +// falseEdges -> [real: bb8, imaginary: bb3]; +// } +// bb3: { +// falseEdges -> [real: bb17, imaginary: bb4]; +// } +// bb4: { +// falseEdges -> [real: bb25, imaginary: bb26]; +// } +// bb5: { +// switchInt((_2.1: bool)) -> [false: bb3, otherwise: bb6]; +// } +// bb6: { +// switchInt((_2.0: bool)) -> [false: bb26, otherwise: bb4]; +// } +// bb7: { // arm 1 +// _0 = const 1i32; +// drop(_7) -> [return: bb23, unwind: bb13]; +// } +// bb8: { // guard - first time +// StorageLive(_6); +// _6 = &(_2.1: bool); +// StorageLive(_8); +// _8 = &(_2.2: std::string::String); +// _3 = &shallow (_2.0: bool); +// _4 = &shallow (_2.1: bool); +// StorageLive(_9); +// StorageLive(_10); +// _10 = _1; +// FakeRead(ForMatchedPlace, _10); +// switchInt(_10) -> [false: bb10, otherwise: bb9]; +// } +// bb9: { +// falseEdges -> [real: bb11, imaginary: bb10]; +// } +// bb10: { // `else` block - first time +// _9 = (*_6); +// StorageDead(_10); +// switchInt(move _9) -> [false: bb16, otherwise: bb15]; +// } +// bb11: { // `return 3` - first time +// _0 = const 3i32; +// StorageDead(_10); +// StorageDead(_9); +// StorageDead(_8); +// StorageDead(_6); +// goto -> bb14; +// } +// bb12: { +// return; +// } +// bb13 (cleanup): { +// drop(_2) -> bb1; +// } +// bb14: { +// drop(_2) -> [return: bb12, unwind: bb1]; +// } +// bb15: { +// StorageDead(_9); +// FakeRead(ForMatchGuard, _3); +// FakeRead(ForMatchGuard, _4); +// FakeRead(ForGuardBinding, _6); +// FakeRead(ForGuardBinding, _8); +// StorageLive(_5); +// _5 = (_2.1: bool); +// StorageLive(_7); +// _7 = move (_2.2: std::string::String); +// goto -> bb7; +// } +// bb16: { // guard otherwise case - first time +// StorageDead(_9); +// StorageDead(_8); +// StorageDead(_6); +// falseEdges -> [real: bb5, imaginary: bb3]; +// } +// bb17: { // guard - second time +// StorageLive(_6); +// _6 = &(_2.0: bool); +// StorageLive(_8); +// _8 = &(_2.2: std::string::String); +// _3 = &shallow (_2.0: bool); +// _4 = &shallow (_2.1: bool); +// StorageLive(_12); +// StorageLive(_13); +// _13 = _1; +// FakeRead(ForMatchedPlace, _13); +// switchInt(_13) -> [false: bb19, otherwise: bb18]; +// } +// bb18: { +// falseEdges -> [real: bb20, imaginary: bb19]; +// } +// bb19: { // `else` block - second time +// _12 = (*_6); +// StorageDead(_13); +// switchInt(move _12) -> [false: bb22, otherwise: bb21]; +// } +// bb20: { +// _0 = const 3i32; +// StorageDead(_13); +// StorageDead(_12); +// StorageDead(_8); +// StorageDead(_6); +// goto -> bb14; +// } +// bb21: { // bindings for arm 1 +// StorageDead(_12); +// FakeRead(ForMatchGuard, _3); +// FakeRead(ForMatchGuard, _4); +// FakeRead(ForGuardBinding, _6); +// FakeRead(ForGuardBinding, _8); +// StorageLive(_5); +// _5 = (_2.0: bool); +// StorageLive(_7); +// _7 = move (_2.2: std::string::String); +// goto -> bb7; +// } +// bb22: { // Guard otherwise case - second time +// StorageDead(_12); +// StorageDead(_8); +// StorageDead(_6); +// falseEdges -> [real: bb6, imaginary: bb4]; +// } +// bb23: { // rest of arm 1 +// StorageDead(_7); +// StorageDead(_5); +// StorageDead(_8); +// StorageDead(_6); +// goto -> bb28; +// } +// bb24: { // arm 2 +// _0 = const 2i32; +// drop(_16) -> [return: bb27, unwind: bb13]; +// } +// bb25: { // bindings for arm 2 - first pattern +// StorageLive(_15); +// _15 = (_2.1: bool); +// StorageLive(_16); +// _16 = move (_2.2: std::string::String); +// goto -> bb24; +// } +// bb26: { // bindings for arm 2 - second pattern +// StorageLive(_15); +// _15 = (_2.1: bool); +// StorageLive(_16); +// _16 = move (_2.2: std::string::String); +// goto -> bb24; +// } +// bb27: { // rest of arm 2 +// StorageDead(_16); +// StorageDead(_15); +// goto -> bb28; +// } +// bb28: { +// drop(_2) -> [return: bb12, unwind: bb1]; +// } +// END rustc.complicated_match.SimplifyCfg-initial.after.mir +// START rustc.complicated_match.ElaborateDrops.after.mir +// let _16: std::string::String; // No drop flags, which would come after this. +// scope 1 { +// END rustc.complicated_match.ElaborateDrops.after.mir diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index ab6de71d2894d..b275c06e05cd3 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -42,68 +42,70 @@ fn main() { // START rustc.full_tested_match.QualifyAndPromoteConstants.after.mir // bb0: { // ... -// _2 = std::option::Option::Some(const 42i32,); +// _2 = std::option::Option::::Some(const 42i32,); // FakeRead(ForMatchedPlace, _2); // _3 = discriminant(_2); -// switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb7]; +// switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb5]; // } -// bb1: { +// bb1 (cleanup): { // resume; // } // bb2: { -// falseEdges -> [real: bb8, imaginary: bb3]; //pre_binding1 +// falseEdges -> [real: bb6, imaginary: bb3]; //pre_binding1 // } // bb3: { -// falseEdges -> [real: bb11, imaginary: bb4]; //pre_binding2 +// falseEdges -> [real: bb10, imaginary: bb4]; //pre_binding2 // } -// bb4: { -// falseEdges -> [real: bb12, imaginary: bb5]; //pre_binding3 +// bb4: { //pre_binding3 and arm3 +// _1 = (const 3i32, const 3i32); +// goto -> bb11; // } // bb5: { // unreachable; // } -// bb6: { // to pre_binding2 -// falseEdges -> [real: bb3, imaginary: bb3]; -// } -// bb7: { -// unreachable; -// } -// bb8: { // binding1 and guard +// bb6: { // binding1 and guard // StorageLive(_6); -// _6 = &(((promoted[1]: std::option::Option) as Some).0: i32); -// _4 = &shallow (promoted[0]: std::option::Option); +// _6 = &(((promoted[0]: std::option::Option) as Some).0: i32); +// _4 = &shallow _2; // StorageLive(_7); -// _7 = const guard() -> [return: bb9, unwind: bb1]; +// _7 = const guard() -> [return: bb7, unwind: bb1]; +// } +// bb7: { // end of guard +// switchInt(move _7) -> [false: bb9, otherwise: bb8]; // } -// bb9: { +// bb8: { // arm1 +// StorageDead(_7); // FakeRead(ForMatchGuard, _4); // FakeRead(ForGuardBinding, _6); -// switchInt(move _7) -> [false: bb6, otherwise: bb10]; -// } -// bb10: { // StorageLive(_5); // _5 = ((_2 as Some).0: i32); // StorageLive(_8); // _8 = _5; // _1 = (const 1i32, move _8); // StorageDead(_8); -// goto -> bb13; +// StorageDead(_5); +// StorageDead(_6); +// goto -> bb11; // } -// bb11: { +// bb9: { // to pre_binding2 +// StorageDead(_7); +// StorageDead(_6); +// goto -> bb3; +// } +// bb10: { // arm2 // StorageLive(_9); // _9 = ((_2 as Some).0: i32); // StorageLive(_10); // _10 = _9; // _1 = (const 2i32, move _10); // StorageDead(_10); -// goto -> bb13; -// } -// bb12: { -// _1 = (const 3i32, const 3i32); -// goto -> bb13; +// StorageDead(_9); +// goto -> bb11; // } -// bb13: { -// ... +// bb11: { // arm3 +// StorageDead(_2); +// StorageDead(_1); +// _0 = (); // return; // } // END rustc.full_tested_match.QualifyAndPromoteConstants.after.mir @@ -111,157 +113,167 @@ fn main() { // START rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir // bb0: { // ... -// _2 = std::option::Option::Some(const 42i32,); +// _2 = std::option::Option::::Some(const 42i32,); // FakeRead(ForMatchedPlace, _2); // _3 = discriminant(_2); -// switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb7]; +// switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb4]; // } -// bb1: { +// bb1 (cleanup): { // resume; // } // bb2: { -// falseEdges -> [real: bb8, imaginary: bb3]; +// falseEdges -> [real: bb5, imaginary: bb3]; // } // bb3: { -// falseEdges -> [real: bb11, imaginary: bb4]; -// } -// bb4: { -// falseEdges -> [real: bb12, imaginary: bb5]; +// falseEdges -> [real: bb9, imaginary: bb10]; // } -// bb5: { +// bb4: { // to arm3 (can skip 2 since this is `Some`) // unreachable; // } -// bb6: { // to pre_binding3 (can skip 2 since this is `Some`) -// falseEdges -> [real: bb4, imaginary: bb3]; -// } -// bb7: { -// unreachable; -// } -// bb8: { // binding1 and guard +// bb5: { // binding1 and guard // StorageLive(_6); // _6 = &((_2 as Some).0: i32); // _4 = &shallow _2; // StorageLive(_7); -// _7 = const guard() -> [return: bb9, unwind: bb1]; +// _7 = const guard() -> [return: bb6, unwind: bb1]; +// } +// bb6: { // end of guard +// switchInt(move _7) -> [false: bb8, otherwise: bb7]; // } -// bb9: { // end of guard +// bb7: { +// StorageDead(_7); // FakeRead(ForMatchGuard, _4); // FakeRead(ForGuardBinding, _6); -// switchInt(move _7) -> [false: bb6, otherwise: bb10]; -// } -// bb10: { // arm1 // StorageLive(_5); // _5 = ((_2 as Some).0: i32); // StorageLive(_8); // _8 = _5; // _1 = (const 1i32, move _8); // StorageDead(_8); -// goto -> bb13; +// StorageDead(_5); +// StorageDead(_6); +// goto -> bb11; +// } +// bb8: { // to pre_binding3 (can skip 2 since this is `Some`) +// StorageDead(_7); +// StorageDead(_6); +// falseEdges -> [real: bb10, imaginary: bb3]; // } -// bb11: { // arm2 +// bb9: { // arm2 // _1 = (const 3i32, const 3i32); -// goto -> bb13; +// goto -> bb11; // } -// bb12: { // binding3 and arm3 +// bb10: { // binding3 and arm3 // StorageLive(_9); // _9 = ((_2 as Some).0: i32); // StorageLive(_10); // _10 = _9; // _1 = (const 2i32, move _10); // StorageDead(_10); -// goto -> bb13; +// StorageDead(_9); +// goto -> bb11; // } -// bb13: { -// ... +// bb11: { +// StorageDead(_2); +// StorageDead(_1); +// _0 = (); // return; // } // END rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir // // START rustc.main.QualifyAndPromoteConstants.before.mir -// bb0: { +// bb0: { // ... -// _2 = std::option::Option::Some(const 1i32,); +// _2 = std::option::Option::::Some(const 1i32,); // FakeRead(ForMatchedPlace, _2); -// _3 = discriminant(_2); -// switchInt(move _3) -> [1isize: bb2, otherwise: bb3]; +// _4 = discriminant(_2); +// switchInt(move _4) -> [1isize: bb2, otherwise: bb3]; // } -// bb1: { +// bb1 (cleanup): { // resume; // } // bb2: { -// falseEdges -> [real: bb9, imaginary: bb3]; +// falseEdges -> [real: bb5, imaginary: bb3]; // } // bb3: { -// falseEdges -> [real: bb12, imaginary: bb4]; +// falseEdges -> [real: bb9, imaginary: bb4]; // } // bb4: { -// falseEdges -> [real: bb13, imaginary: bb5]; +// falseEdges -> [real: bb10, imaginary: bb14]; // } // bb5: { -// falseEdges -> [real: bb16, imaginary: bb6]; -// } -// bb6: { -// unreachable; -// } -// bb7: { -// falseEdges -> [real: bb3, imaginary: bb3]; -// } -// bb8: { -// falseEdges -> [real: bb5, imaginary: bb5]; -// } -// bb9: { // binding1: Some(w) if guard() // StorageLive(_7); // _7 = &((_2 as Some).0: i32); // _5 = &shallow _2; // StorageLive(_8); -// _8 = const guard() -> [return: bb10, unwind: bb1]; +// _8 = const guard() -> [return: bb6, unwind: bb1]; +// } +// bb6: { //end of guard1 +// switchInt(move _8) -> [false: bb8, otherwise: bb7]; // } -// bb10: { //end of guard +// bb7: { +// StorageDead(_8); // FakeRead(ForMatchGuard, _5); // FakeRead(ForGuardBinding, _7); -// switchInt(move _8) -> [false: bb7, otherwise: bb11]; -// } -// bb11: { // set up bindings for arm1 // StorageLive(_6); // _6 = ((_2 as Some).0: i32); // _1 = const 1i32; -// goto -> bb17; +// StorageDead(_6); +// StorageDead(_7); +// goto -> bb15; +// } +// bb8: { +// StorageDead(_8); +// StorageDead(_7); +// falseEdges -> [real: bb3, imaginary: bb3]; // } -// bb12: { // binding2 & arm2 +// bb9: { // binding2 & arm2 // StorageLive(_9); // _9 = _2; // _1 = const 2i32; -// goto -> bb17; +// StorageDead(_9); +// goto -> bb15; // } -// bb13: { // binding3: Some(y) if guard2(y) +// bb10: { // binding3: Some(y) if guard2(y) // StorageLive(_11); // _11 = &((_2 as Some).0: i32); // _5 = &shallow _2; // StorageLive(_12); // StorageLive(_13); // _13 = (*_11); -// _12 = const guard2(move _13) -> [return: bb14, unwind: bb1]; +// _12 = const guard2(move _13) -> [return: bb11, unwind: bb1]; // } -// bb14: { // end of guard2 +// bb11: { // end of guard2 // StorageDead(_13); +// switchInt(move _12) -> [false: bb13, otherwise: bb12]; +// } +// bb12: { // binding4 & arm4 +// StorageDead(_12); // FakeRead(ForMatchGuard, _5); // FakeRead(ForGuardBinding, _11); -// switchInt(move _12) -> [false: bb8, otherwise: bb15]; -// } -// bb15: { // binding4 & arm4 // StorageLive(_10); // _10 = ((_2 as Some).0: i32); // _1 = const 3i32; -// goto -> bb17; +// StorageDead(_10); +// StorageDead(_11); +// goto -> bb15; // } -// bb16: { +// bb13: { +// StorageDead(_12); +// StorageDead(_11); +// falseEdges -> [real: bb14, imaginary: bb14]; +// } +// bb14: { // StorageLive(_14); // _14 = _2; // _1 = const 4i32; -// goto -> bb17; +// StorageDead(_14); +// goto -> bb15; // } -// bb17: { -// ... +// bb15: { +// StorageDead(_2); +// StorageDead(_1); +// _0 = (); // return; // } // END rustc.main.QualifyAndPromoteConstants.before.mir diff --git a/src/test/mir-opt/match_test.rs b/src/test/mir-opt/match_test.rs index 3f248f3d41a64..1ca75b100410b 100644 --- a/src/test/mir-opt/match_test.rs +++ b/src/test/mir-opt/match_test.rs @@ -20,64 +20,62 @@ fn main() { // START rustc.main.SimplifyCfg-initial.after.mir // bb0: { // ... -// switchInt(move _4) -> [false: bb7, otherwise: bb8]; +// switchInt(move _6) -> [false: bb6, otherwise: bb5]; // } // bb1: { -// falseEdges -> [real: bb12, imaginary: bb2]; +// falseEdges -> [real: bb9, imaginary: bb2]; // } // bb2: { -// falseEdges -> [real: bb13, imaginary: bb3]; +// falseEdges -> [real: bb12, imaginary: bb3]; // } // bb3: { -// falseEdges -> [real: bb14, imaginary: bb4]; +// falseEdges -> [real: bb13, imaginary: bb4]; // } // bb4: { -// falseEdges -> [real: bb15, imaginary: bb5]; +// _3 = const 3i32; +// goto -> bb14; // } // bb5: { -// unreachable; +// _7 = Lt(_1, const 10i32); +// switchInt(move _7) -> [false: bb6, otherwise: bb1]; // } // bb6: { -// falseEdges -> [real: bb4, imaginary: bb2]; +// _4 = Le(const 10i32, _1); +// switchInt(move _4) -> [false: bb8, otherwise: bb7]; // } // bb7: { -// _6 = Le(const 10i32, _1); -// switchInt(move _6) -> [false: bb9, otherwise: bb10]; +// _5 = Le(_1, const 20i32); +// switchInt(move _5) -> [false: bb8, otherwise: bb2]; // } // bb8: { -// _5 = Lt(_1, const 10i32); -// switchInt(move _5) -> [false: bb7, otherwise: bb1]; +// switchInt(_1) -> [-1i32: bb3, otherwise: bb4]; // } // bb9: { -// switchInt(_1) -> [-1i32: bb3, otherwise: bb4]; +// _8 = &shallow _1; +// StorageLive(_9); +// _9 = _2; +// switchInt(move _9) -> [false: bb11, otherwise: bb10]; // } // bb10: { -// _7 = Le(_1, const 20i32); -// switchInt(move _7) -> [false: bb9, otherwise: bb2]; +// StorageDead(_9); +// FakeRead(ForMatchGuard, _8); +// _3 = const 0i32; +// goto -> bb14; // } // bb11: { -// _3 = const 0i32; -// goto -> bb16; +// StorageDead(_9); +// falseEdges -> [real: bb4, imaginary: bb2]; // } // bb12: { -// StorageLive(_8); -// _8 = _2; -// switchInt(move _8) -> [false: bb6, otherwise: bb11]; -// } -// bb13: { // _3 = const 1i32; -// goto -> bb16; +// goto -> bb14; // } -// bb14: { +// bb13: { // _3 = const 2i32; -// goto -> bb16; +// goto -> bb14; // } -// bb15: { -// _3 = const 3i32; -// goto -> bb16; -// } -// bb16: { -// StorageDead(_8); +// bb14: { +// StorageDead(_3); // _0 = (); // StorageDead(_2); // StorageDead(_1); diff --git a/src/test/mir-opt/nll/named-lifetimes-basic.rs b/src/test/mir-opt/nll/named-lifetimes-basic.rs index 4833ba19554b9..2a6c2db03bec1 100644 --- a/src/test/mir-opt/nll/named-lifetimes-basic.rs +++ b/src/test/mir-opt/nll/named-lifetimes-basic.rs @@ -5,7 +5,6 @@ // compile-flags:-Zborrowck=mir -Zverbose // ^^^^^^^^^ force compiler to dump more region information -// ignore-tidy-linelength #![allow(warnings)] diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs index c2dda680b739d..8228d9740f0d3 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic.rs +++ b/src/test/mir-opt/nll/region-subtyping-basic.rs @@ -22,15 +22,15 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#2r | U0 | {bb2[0..=5], bb3[0..=1]} -// | '_#3r | U0 | {bb2[1..=5], bb3[0..=1]} -// | '_#4r | U0 | {bb2[4..=5], bb3[0..=1]} +// | '_#2r | U0 | {bb2[0..=8], bb3[0], bb5[0..=2]} +// | '_#3r | U0 | {bb2[1..=8], bb3[0], bb5[0..=2]} +// | '_#4r | U0 | {bb2[4..=8], bb3[0], bb5[0..=2]} // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir -// let _6: &'_#4r usize; -// ... // let _2: &'_#3r usize; // ... +// let _6: &'_#4r usize; +// ... // _2 = &'_#2r _1[_3]; // ... // _6 = _2; diff --git a/src/test/mir-opt/packed-struct-drop-aligned.rs b/src/test/mir-opt/packed-struct-drop-aligned.rs index 01402f261563c..da73cc96348f0 100644 --- a/src/test/mir-opt/packed-struct-drop-aligned.rs +++ b/src/test/mir-opt/packed-struct-drop-aligned.rs @@ -18,16 +18,14 @@ impl Drop for Droppy { // START rustc.main.EraseRegions.before.mir // fn main() -> () { // let mut _0: (); -// scope 1 { -// } -// scope 2 { -// let mut _1: Packed; -// } +// let mut _1: Packed; // let mut _2: Aligned; // let mut _3: Droppy; // let mut _4: Aligned; // let mut _5: Droppy; // let mut _6: Aligned; +// scope 1 { +// } // // bb0: { // StorageLive(_1); @@ -38,14 +36,14 @@ impl Drop for Droppy { // _6 = move (_1.0: Aligned); // drop(_6) -> [return: bb4, unwind: bb3]; // } -// bb1: { +// bb1 (cleanup): { // resume; // } // bb2: { // StorageDead(_1); // return; // } -// bb3: { +// bb3 (cleanup): { // (_1.0: Aligned) = move _4; // drop(_1) -> bb1; // } diff --git a/src/test/mir-opt/remove_fake_borrows.rs b/src/test/mir-opt/remove_fake_borrows.rs index 48d1c991b623e..3245d38b2580b 100644 --- a/src/test/mir-opt/remove_fake_borrows.rs +++ b/src/test/mir-opt/remove_fake_borrows.rs @@ -2,8 +2,6 @@ // ignore-wasm32-bare -#![feature(nll)] - fn match_guard(x: Option<&&i32>, c: bool) -> i32 { match x { Some(0) if c => 0, @@ -21,49 +19,44 @@ fn main() { // bb0: { // FakeRead(ForMatchedPlace, _1); // _3 = discriminant(_1); -// switchInt(move _3) -> [1isize: bb5, otherwise: bb2]; +// switchInt(move _3) -> [1isize: bb3, otherwise: bb2]; // } // bb1: { -// goto -> bb7; +// goto -> bb4; // } // bb2: { -// goto -> bb8; +// _0 = const 1i32; +// goto -> bb7; // } // bb3: { -// unreachable; -// } -// bb4: { -// goto -> bb2; -// } -// bb5: { // switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb1, otherwise: bb2]; // } -// bb6: { -// _0 = const 0i32; -// goto -> bb9; -// } -// bb7: { +// bb4: { // _4 = &shallow _1; // _5 = &shallow ((_1 as Some).0: &' &' i32); // _6 = &shallow (*((_1 as Some).0: &' &' i32)); // _7 = &shallow (*(*((_1 as Some).0: &' &' i32))); // StorageLive(_8); // _8 = _2; +// switchInt(move _8) -> [false: bb6, otherwise: bb5]; +// } +// bb5: { +// StorageDead(_8); // FakeRead(ForMatchGuard, _4); // FakeRead(ForMatchGuard, _5); // FakeRead(ForMatchGuard, _6); // FakeRead(ForMatchGuard, _7); -// switchInt(move _8) -> [false: bb4, otherwise: bb6]; -// } -// bb8: { -// _0 = const 1i32; -// goto -> bb9; +// _0 = const 0i32; +// goto -> bb7; // } -// bb9: { +// bb6: { // StorageDead(_8); +// goto -> bb2; +// } +// bb7: { // return; // } -// bb10: { +// bb8 (cleanup): { // resume; // } // END rustc.match_guard.CleanupNonCodegenStatements.before.mir @@ -72,49 +65,44 @@ fn main() { // bb0: { // nop; // _3 = discriminant(_1); -// switchInt(move _3) -> [1isize: bb5, otherwise: bb2]; +// switchInt(move _3) -> [1isize: bb3, otherwise: bb2]; // } // bb1: { -// goto -> bb7; +// goto -> bb4; // } // bb2: { -// goto -> bb8; +// _0 = const 1i32; +// goto -> bb7; // } // bb3: { -// unreachable; -// } -// bb4: { -// goto -> bb2; -// } -// bb5: { // switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb1, otherwise: bb2]; // } -// bb6: { -// _0 = const 0i32; -// goto -> bb9; -// } -// bb7: { +// bb4: { // nop; // nop; // nop; // nop; // StorageLive(_8); // _8 = _2; +// switchInt(move _8) -> [false: bb6, otherwise: bb5]; +// } +// bb5: { +// StorageDead(_8); // nop; // nop; // nop; // nop; -// switchInt(move _8) -> [false: bb4, otherwise: bb6]; -// } -// bb8: { -// _0 = const 1i32; -// goto -> bb9; +// _0 = const 0i32; +// goto -> bb7; // } -// bb9: { +// bb6: { // StorageDead(_8); +// goto -> bb2; +// } +// bb7: { // return; // } -// bb10: { +// bb8 (cleanup): { // resume; // } // END rustc.match_guard.CleanupNonCodegenStatements.after.mir diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs index bb794409ae01f..33ee0fe61b288 100644 --- a/src/test/mir-opt/retag.rs +++ b/src/test/mir-opt/retag.rs @@ -75,18 +75,18 @@ fn main() { // _10 = move _8; // Retag(_10); // ... -// _15 = &mut (*_10); -// Retag(_15); -// _14 = move _15 as *mut i32 (Misc); -// Retag([raw] _14); +// _13 = &mut (*_10); +// Retag(_13); +// _12 = move _13 as *mut i32 (Misc); +// Retag([raw] _12); // ... -// _18 = move _19(move _20) -> bb2; +// _16 = move _17(move _18) -> bb2; // } // // bb2: { -// Retag(_18); +// Retag(_16); // ... -// _22 = const Test::foo_shr(move _23, move _25) -> bb3; +// _20 = const Test::foo_shr(move _21, move _23) -> bb3; // } // // bb3: { @@ -98,7 +98,7 @@ fn main() { // } // END rustc.main.EraseRegions.after.mir // START rustc.main-{{closure}}.EraseRegions.after.mir -// fn main::{{closure}}(_1: &[closure@NodeId(124)], _2: &i32) -> &i32 { +// fn main::{{closure}}#0(_1: &[closure@HirId { owner: DefIndex(20), local_id: 72 }], _2: &i32) -> &i32 { // ... // bb0: { // Retag([fn entry] _1); diff --git a/src/test/mir-opt/simple-match.rs b/src/test/mir-opt/simple-match.rs new file mode 100644 index 0000000000000..fc1a3bb1bf453 --- /dev/null +++ b/src/test/mir-opt/simple-match.rs @@ -0,0 +1,39 @@ +// Test that we don't generate unnecessarily large MIR for very simple matches + +fn match_bool(x: bool) -> usize { + match x { + true => 10, + _ => 20, + } +} + +fn main() {} + + +// END RUST SOURCE +// START rustc.match_bool.mir_map.0.mir +// bb0: { +// FakeRead(ForMatchedPlace, _1); +// switchInt(_1) -> [false: bb3, otherwise: bb2]; +// } +// bb1 (cleanup): { +// resume; +// } +// bb2: { +// falseEdges -> [real: bb4, imaginary: bb3]; +// } +// bb3: { +// _0 = const 20usize; +// goto -> bb5; +// } +// bb4: { +// _0 = const 10usize; +// goto -> bb5; +// } +// bb5: { +// goto -> bb6; +// } +// bb6: { +// return; +// } +// END rustc.match_bool.mir_map.0.mir diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs index f6e6c6baf7a46..471c1df3300f0 100644 --- a/src/test/mir-opt/simplify_if.rs +++ b/src/test/mir-opt/simplify_if.rs @@ -5,13 +5,15 @@ fn main() { } // END RUST SOURCE -// START rustc.main.SimplifyBranches-initial.before.mir +// START rustc.main.SimplifyBranches-after-const-prop.before.mir // bb0: { -// switchInt(const false) -> [false: bb3, otherwise: bb2]; +// ... +// switchInt(const false) -> [false: bb1, otherwise: bb2]; // } -// END rustc.main.SimplifyBranches-initial.before.mir -// START rustc.main.SimplifyBranches-initial.after.mir +// END rustc.main.SimplifyBranches-after-const-prop.before.mir +// START rustc.main.SimplifyBranches-after-const-prop.after.mir // bb0: { -// goto -> bb3; +// ... +// goto -> bb1; // } -// END rustc.main.SimplifyBranches-initial.after.mir +// END rustc.main.SimplifyBranches-after-const-prop.after.mir diff --git a/src/test/mir-opt/simplify_match.rs b/src/test/mir-opt/simplify_match.rs new file mode 100644 index 0000000000000..8624899a0abf2 --- /dev/null +++ b/src/test/mir-opt/simplify_match.rs @@ -0,0 +1,22 @@ +fn main() { + match { let x = false; x } { + true => println!("hello world!"), + false => {}, + } +} + +// END RUST SOURCE +// START rustc.main.SimplifyBranches-after-copy-prop.before.mir +// bb0: { +// ... +// switchInt(const false) -> [false: bb1, otherwise: bb2]; +// } +// bb1: { +// END rustc.main.SimplifyBranches-after-copy-prop.before.mir +// START rustc.main.SimplifyBranches-after-copy-prop.after.mir +// bb0: { +// ... +// goto -> bb1; +// } +// bb1: { +// END rustc.main.SimplifyBranches-after-copy-prop.after.mir diff --git a/src/test/mir-opt/slice-drop-shim.rs b/src/test/mir-opt/slice-drop-shim.rs new file mode 100644 index 0000000000000..754fad51b21e7 --- /dev/null +++ b/src/test/mir-opt/slice-drop-shim.rs @@ -0,0 +1,88 @@ +fn main() { + std::ptr::drop_in_place::<[String]> as unsafe fn(_); +} + +// END RUST SOURCE + +// START rustc.ptr-real_drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir +// let mut _2: usize; +// let mut _3: usize; +// let mut _4: usize; +// let mut _5: &mut std::string::String; +// let mut _6: bool; +// let mut _7: &mut std::string::String; +// let mut _8: bool; +// let mut _9: *mut std::string::String; +// let mut _10: *mut std::string::String; +// let mut _11: &mut std::string::String; +// let mut _12: bool; +// let mut _13: &mut std::string::String; +// let mut _14: bool; +// let mut _15: *mut [std::string::String]; +// bb0: { +// goto -> bb15; +// } +// bb1: { +// return; +// } +// bb2 (cleanup): { +// resume; +// } +// bb3 (cleanup): { +// _5 = &mut (*_1)[_4]; +// _4 = Add(move _4, const 1usize); +// drop((*_5)) -> bb4; +// } +// bb4 (cleanup): { +// _6 = Eq(_4, _3); +// switchInt(move _6) -> [false: bb3, otherwise: bb2]; +// } +// bb5: { +// _7 = &mut (*_1)[_4]; +// _4 = Add(move _4, const 1usize); +// drop((*_7)) -> [return: bb6, unwind: bb4]; +// } +// bb6: { +// _8 = Eq(_4, _3); +// switchInt(move _8) -> [false: bb5, otherwise: bb1]; +// } +// bb7: { +// _4 = const 0usize; +// goto -> bb6; +// } +// bb8: { +// goto -> bb7; +// } +// bb9 (cleanup): { +// _11 = &mut (*_9); +// _9 = Offset(move _9, const 1usize); +// drop((*_11)) -> bb10; +// } +// bb10 (cleanup): { +// _12 = Eq(_9, _10); +// switchInt(move _12) -> [false: bb9, otherwise: bb2]; +// } +// bb11: { +// _13 = &mut (*_9); +// _9 = Offset(move _9, const 1usize); +// drop((*_13)) -> [return: bb12, unwind: bb10]; +// } +// bb12: { +// _14 = Eq(_9, _10); +// switchInt(move _14) -> [false: bb11, otherwise: bb1]; +// } +// bb13: { +// _15 = &mut (*_1); +// _9 = move _15 as *mut std::string::String (Misc); +// _10 = Offset(_9, move _3); +// goto -> bb12; +// } +// bb14: { +// goto -> bb13; +// } +// bb15: { +// _2 = SizeOf(std::string::String); +// _3 = Len((*_1)); +// switchInt(move _2) -> [0usize: bb8, otherwise: bb14]; +// } +// END rustc.ptr-real_drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir diff --git a/src/test/mir-opt/storage_live_dead_in_statics.rs b/src/test/mir-opt/storage_live_dead_in_statics.rs index e8ef1d9d3c38b..2ed34ecfad2c6 100644 --- a/src/test/mir-opt/storage_live_dead_in_statics.rs +++ b/src/test/mir-opt/storage_live_dead_in_statics.rs @@ -178,12 +178,12 @@ fn main() { // _6 = [move _7, move _8, move _9, move _10, move _11, move _12, move _13, move _14, move _15, move _16, move _17, move _18, move _19, move _20, move _21, move _22, move _23, move _24, move _25, move _26, move _27, move _28, move _29, move _30, move _31, move _32, move _33, move _34, move _35, move _36, move _37, move _38, move _39, move _40, move _41, move _42, move _43, move _44, move _45, move _46, move _47, move _48]; // _5 = &_6; // _4 = &(*_5); -// _3 = move _4 as &'static [(u32, u32)] (Unsize); +// _3 = move _4 as &'static [(u32, u32)] (Pointer(Unsize)); // _2 = Foo { tup: const "hi", data: move _3 }; // _1 = &_2; // _0 = &(*_1); -// StorageDead(_1); // StorageDead(_5); +// StorageDead(_1); // return; // } //} diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs index a5d6ced2b1772..95570ff76a6d0 100644 --- a/src/test/mir-opt/storage_ranges.rs +++ b/src/test/mir-opt/storage_ranges.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - fn main() { let a = 0; { @@ -9,22 +7,24 @@ fn main() { } // END RUST SOURCE -// START rustc.main.TypeckMir.before.mir +// START rustc.main.nll.0.mir // bb0: { // StorageLive(_1); // _1 = const 0i32; // FakeRead(ForLet, _1); +// StorageLive(_2); // StorageLive(_3); // StorageLive(_4); // StorageLive(_5); // _5 = _1; -// _4 = std::option::Option::Some(move _5,); +// _4 = std::option::Option::::Some(move _5,); // StorageDead(_5); // _3 = &_4; // FakeRead(ForLet, _3); // _2 = (); // StorageDead(_4); // StorageDead(_3); +// StorageDead(_2); // StorageLive(_6); // _6 = const 1i32; // FakeRead(ForLet, _6); @@ -33,4 +33,4 @@ fn main() { // StorageDead(_1); // return; // } -// END rustc.main.TypeckMir.before.mir +// END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs index fe85baa048e39..f4d848dfc7ad1 100644 --- a/src/test/mir-opt/unusual-item-types.rs +++ b/src/test/mir-opt/unusual-item-types.rs @@ -1,5 +1,6 @@ // Test that we don't ICE when trying to dump MIR for unusual item types and // that we don't create filenames containing `<` and `>` +// ignore-tidy-linelength struct A; @@ -7,11 +8,18 @@ impl A { const ASSOCIATED_CONSTANT: i32 = 2; } +// See #59021 +enum Test { + X(usize), + Y { a: usize }, +} + enum E { V = 5, } fn main() { + let f = Test::X as fn(usize) -> Test; let v = Vec::::new(); } @@ -22,7 +30,7 @@ fn main() { // _0 = const 2i32; // return; // } -// bb1: { +// bb1 (cleanup): { // resume; // } // END rustc.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir @@ -32,7 +40,7 @@ fn main() { // _0 = const 5isize; // return; // } -// bb1: { +// bb1 (cleanup): { // resume; // } // END rustc.E-V-{{constant}}.mir_map.0.mir @@ -44,16 +52,16 @@ fn main() { // bb1: { // return; // } -// bb2: { +// bb2 (cleanup): { // resume; // } // bb3: { // goto -> bb1; // } -// bb4: { +// bb4 (cleanup): { // goto -> bb2; // } -// bb5: { +// bb5 (cleanup): { // drop(((*_1).0: alloc::raw_vec::RawVec)) -> bb4; // } // bb6: { @@ -61,6 +69,18 @@ fn main() { // } // bb7: { // _2 = &mut (*_1); -// _3 = const std::ops::Drop::drop(move _2) -> [return: bb6, unwind: bb5]; +// _3 = const as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // } // END rustc.ptr-real_drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir + +// START rustc.Test-X-{{constructor}}.mir_map.0.mir +// fn Test::X(_1: usize) -> Test { +// let mut _0: Test; +// +// bb0: { +// ((_0 as X).0: usize) = move _1; +// discriminant(_0) = 0; +// return; +// } +// } +// END rustc.Test-X-{{constructor}}.mir_map.0.mir diff --git a/src/test/mir-opt/while-storage.rs b/src/test/mir-opt/while-storage.rs new file mode 100644 index 0000000000000..a486bd49a77d0 --- /dev/null +++ b/src/test/mir-opt/while-storage.rs @@ -0,0 +1,59 @@ +// Test that we correctly generate StorageDead statements for while loop +// conditions on all branches + +fn get_bool(c: bool) -> bool { + c +} + +fn while_loop(c: bool) { + while get_bool(c) { + if get_bool(c) { + break; + } + } +} + +fn main() { + while_loop(false); +} + +// END RUST SOURCE + +// START rustc.while_loop.PreCodegen.after.mir +// bb0: { +// StorageLive(_2); +// StorageLive(_3); +// _3 = _1; +// _2 = const get_bool(move _3) -> bb2; +// } +// bb1: { +// return; +// } +// bb2: { +// StorageDead(_3); +// switchInt(move _2) -> [false: bb4, otherwise: bb3]; +// } +// bb3: { +// StorageDead(_2); +// StorageLive(_4); +// StorageLive(_5); +// _5 = _1; +// _4 = const get_bool(move _5) -> bb5; +// } +// bb4: { +// StorageDead(_2); +// goto -> bb1; +// } +// bb5: { +// StorageDead(_5); +// switchInt(_4) -> [false: bb6, otherwise: bb7]; +// } +// bb6: { +// StorageDead(_4); +// goto -> bb0; +// } +// bb7: { +// StorageDead(_4); +// goto -> bb1; +// } +// END rustc.while_loop.PreCodegen.after.mir diff --git a/src/test/pretty/attr-fn-inner.rs b/src/test/pretty/attr-fn-inner.rs index f13339e334c6e..0a745e7d34fc1 100644 --- a/src/test/pretty/attr-fn-inner.rs +++ b/src/test/pretty/attr-fn-inner.rs @@ -1,15 +1,16 @@ -// pp-exact // Testing that both the inner item and next outer item are // preserved, and that the first outer item parsed in main is not // accidentally carried over to each inner function -#![feature(custom_attribute)] +// pp-exact + +#![feature(rustc_attrs)] fn main() { - #![inner_attr] - #[outer_attr] + #![rustc_dummy] + #[rustc_dummy] fn f() { } - #[outer_attr] + #[rustc_dummy] fn g() { } } diff --git a/src/test/pretty/attr-literals.rs b/src/test/pretty/attr-literals.rs index 355f3d5a3cfb8..44d2c5db3e668 100644 --- a/src/test/pretty/attr-literals.rs +++ b/src/test/pretty/attr-literals.rs @@ -1,13 +1,14 @@ -// pp-exact // Tests literals in attributes. -#![feature(custom_attribute)] +// pp-exact + +#![feature(rustc_attrs)] fn main() { - #![hello("hi", 1, 2, 1.012, pi = 3.14, bye, name("John"))] - #[align = 8] + #![rustc_dummy("hi", 1, 2, 1.012, pi = 3.14, bye, name("John"))] + #[rustc_dummy = 8] fn f() { } - #[vector(1, 2, 3)] + #[rustc_dummy(1, 2, 3)] fn g() { } } diff --git a/src/test/pretty/fn-variadic.rs b/src/test/pretty/fn-variadic.rs new file mode 100644 index 0000000000000..d499be424603b --- /dev/null +++ b/src/test/pretty/fn-variadic.rs @@ -0,0 +1,15 @@ +// Check that `fn foo(x: i32, ...)` does not print as `fn foo(x: i32, ..., ...)`. +// See issue #58853. + +// pp-exact +#![feature(c_variadic)] + +extern "C" { + pub fn foo(x: i32, ...); +} + +pub unsafe extern "C" fn bar(_: i32, mut ap: ...) -> usize { + ap.arg::() +} + +fn main() { } diff --git a/src/test/pretty/issue-12590-a.rs b/src/test/pretty/issue-12590-a.rs new file mode 100644 index 0000000000000..1a9e85c42d8fb --- /dev/null +++ b/src/test/pretty/issue-12590-a.rs @@ -0,0 +1,8 @@ +// pp-exact + +// The next line should not be expanded + +#[path = "issue-12590-b.rs"] +mod issue_12590_b; + +fn main() { } diff --git a/src/test/pretty/issue-12590-b.rs b/src/test/pretty/issue-12590-b.rs new file mode 100644 index 0000000000000..b14c7afa22142 --- /dev/null +++ b/src/test/pretty/issue-12590-b.rs @@ -0,0 +1,5 @@ +// Second part of two-file test + +fn b() { } + +fn main() { } diff --git a/src/test/pretty/issue-12590-c.pp b/src/test/pretty/issue-12590-c.pp new file mode 100644 index 0000000000000..1761c0653ce86 --- /dev/null +++ b/src/test/pretty/issue-12590-c.pp @@ -0,0 +1,19 @@ +#![feature(prelude_import)] +#![no_std] +#[prelude_import] +use ::std::prelude::v1::*; +#[macro_use] +extern crate std; +// pretty-compare-only +// pretty-mode:expanded +// pp-exact:issue-12590-c.pp + +// The next line should be expanded + +#[path = "issue-12590-b.rs"] +mod issue_12590_b { + + fn b() { } + fn main() { } +} +fn main() { } diff --git a/src/test/pretty/issue-12590-c.rs b/src/test/pretty/issue-12590-c.rs new file mode 100644 index 0000000000000..2cc444edda3d7 --- /dev/null +++ b/src/test/pretty/issue-12590-c.rs @@ -0,0 +1,10 @@ +// pretty-compare-only +// pretty-mode:expanded +// pp-exact:issue-12590-c.pp + +// The next line should be expanded + +#[path = "issue-12590-b.rs"] +mod issue_12590_b; + +fn main() { } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index b529beba78367..ad663412e7776 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -32,27 +32,27 @@ (($crate::fmt::format as for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<$crate::fmt::Arguments>::new_v1 as - fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})((&([("test" + fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments::<'_>::new_v1})((&([("test" + as + &'static str)] as - &'static str)] + [&str; 1]) as - [&str; 1]) - as - &[&str; 1]), - (&(match (() + &[&str; 1]), + (&(match (() + as + ()) + { + () + => + ([] as - ()) - { - () - => - ([] - as - [std::fmt::ArgumentV1<'_>; 0]), - } + [std::fmt::ArgumentV1<'_>; 0]), + } + as + [std::fmt::ArgumentV1<'_>; 0]) as - [std::fmt::ArgumentV1<'_>; 0]) - as - &[std::fmt::ArgumentV1<'_>; 0])) + &[std::fmt::ArgumentV1<'_>; 0])) as std::fmt::Arguments<'_>)) as std::string::String); diff --git a/src/test/pretty/issue_12590_a.rs b/src/test/pretty/issue_12590_a.rs deleted file mode 100644 index 1ddd3c0426371..0000000000000 --- a/src/test/pretty/issue_12590_a.rs +++ /dev/null @@ -1,7 +0,0 @@ -// pp-exact - -// The next line should not be expanded - -mod issue_12590_b; - -fn main() { } diff --git a/src/test/pretty/issue_12590_b.rs b/src/test/pretty/issue_12590_b.rs deleted file mode 100644 index f188f7bca6983..0000000000000 --- a/src/test/pretty/issue_12590_b.rs +++ /dev/null @@ -1,4 +0,0 @@ -// Second part of two file test -fn b() { } - -fn main() { } diff --git a/src/test/pretty/issue_12590_c.pp b/src/test/pretty/issue_12590_c.pp deleted file mode 100644 index 2418283530375..0000000000000 --- a/src/test/pretty/issue_12590_c.pp +++ /dev/null @@ -1,18 +0,0 @@ -#![feature(prelude_import)] -#![no_std] -#[prelude_import] -use ::std::prelude::v1::*; -#[macro_use] -extern crate std; -// pretty-compare-only -// pretty-mode:expanded -// pp-exact:issue_12590_c.pp - -// The next line should be expanded - -mod issue_12590_b { - - fn b() { } - fn main() { } -} -fn main() { } diff --git a/src/test/pretty/issue_12590_c.rs b/src/test/pretty/issue_12590_c.rs deleted file mode 100644 index c0da36c2100ef..0000000000000 --- a/src/test/pretty/issue_12590_c.rs +++ /dev/null @@ -1,9 +0,0 @@ -// pretty-compare-only -// pretty-mode:expanded -// pp-exact:issue_12590_c.pp - -// The next line should be expanded - -mod issue_12590_b; - -fn main() { } diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs index eb1768683e6e9..d81485b555fa6 100644 --- a/src/test/pretty/stmt_expr_attributes.rs +++ b/src/test/pretty/stmt_expr_attributes.rs @@ -1,20 +1,20 @@ // pp-exact -#![feature(custom_attribute)] #![feature(box_syntax)] +#![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] fn main() { } fn _0() { - #[attr] + #[rustc_dummy] foo(); } fn _1() { - #[attr] + #[rustc_dummy] unsafe { // code } @@ -22,11 +22,11 @@ fn _1() { fn _2() { - #[attr] + #[rustc_dummy] { foo(); } { - #![attr] + #![rustc_dummy] foo() } @@ -34,51 +34,51 @@ fn _2() { fn _3() { - #[attr] + #[rustc_dummy] match () { _ => { } } } fn _4() { - #[attr] + #[rustc_dummy] match () { - #![attr] + #![rustc_dummy] _ => (), } let _ = - #[attr] match () { - #![attr] - () => (), - }; + #[rustc_dummy] match () { + #![rustc_dummy] + () => (), + }; } fn _5() { - #[attr] + #[rustc_dummy] let x = 1; - let x = #[attr] 1; + let x = #[rustc_dummy] 1; let y = (); let z = (); - foo3(x, #[attr] y, z); + foo3(x, #[rustc_dummy] y, z); - qux(3 + #[attr] 2); + qux(3 + #[rustc_dummy] 2); } fn _6() { - #[attr] - [#![attr] 1, 2, 3]; + #[rustc_dummy] + [#![rustc_dummy] 1, 2, 3]; - let _ = #[attr] [#![attr] 1, 2, 3]; + let _ = #[rustc_dummy] [#![rustc_dummy] 1, 2, 3]; - #[attr] - [#![attr] 1; 4]; + #[rustc_dummy] + [#![rustc_dummy] 1; 4]; - let _ = #[attr] [#![attr] 1; 4]; + let _ = #[rustc_dummy] [#![rustc_dummy] 1; 4]; } struct Foo { @@ -89,45 +89,41 @@ struct Bar(()); fn _7() { - #[attr] - Foo{#![attr] data: (),}; + #[rustc_dummy] + Foo{#![rustc_dummy] data: (),}; - let _ = #[attr] Foo{#![attr] data: (),}; + let _ = #[rustc_dummy] Foo{#![rustc_dummy] data: (),}; } fn _8() { - #[attr] - (#![attr] ); + #[rustc_dummy] + (#![rustc_dummy] ); - #[attr] - (#![attr] 0); + #[rustc_dummy] + (#![rustc_dummy] 0); - #[attr] - (#![attr] 0,); + #[rustc_dummy] + (#![rustc_dummy] 0,); - #[attr] - (#![attr] 0, 1); + #[rustc_dummy] + (#![rustc_dummy] 0, 1); } fn _9() { macro_rules! stmt_mac(( ) => { let _ = ( ) ; }); - #[attr] + #[rustc_dummy] stmt_mac!(); - /* - // pre existing pp bug: delimiter styles gets lost: - - #[attr] + #[rustc_dummy] stmt_mac!{ }; - #[attr] + #[rustc_dummy] stmt_mac![]; - #[attr] - stmt_mac!{ } // pre-existing pp bug: compiler ICEs with a None unwrap - */ + #[rustc_dummy] + stmt_mac!{ } let _ = (); } @@ -135,138 +131,131 @@ fn _9() { macro_rules! expr_mac(( ) => { ( ) }); fn _10() { - - let _ = #[attr] expr_mac!(); - - /* - // pre existing pp bug: delimiter styles gets lost: - let _ = #[attr] expr_mac![]; - let _ = #[attr] expr_mac!{}; - */ + let _ = #[rustc_dummy] expr_mac!(); + let _ = #[rustc_dummy] expr_mac![]; + let _ = #[rustc_dummy] expr_mac!{ }; } fn _11() { - let _ = #[attr] box 0; - let _: [(); 0] = #[attr] [#![attr] ]; - let _ = #[attr] [#![attr] 0, 0]; - let _ = #[attr] [#![attr] 0; 0]; - let _ = #[attr] foo(); - let _ = #[attr] 1i32.clone(); - let _ = #[attr] (#![attr] ); - let _ = #[attr] (#![attr] 0); - let _ = #[attr] (#![attr] 0,); - let _ = #[attr] (#![attr] 0, 0); - let _ = #[attr] 0 + #[attr] 0; - let _ = #[attr] !0; - let _ = #[attr] -0i32; - let _ = #[attr] false; - let _ = #[attr] 'c'; - let _ = #[attr] 0; - let _ = #[attr] 0 as usize; + let _ = #[rustc_dummy] box 0; + let _: [(); 0] = #[rustc_dummy] [#![rustc_dummy] ]; + let _ = #[rustc_dummy] [#![rustc_dummy] 0, 0]; + let _ = #[rustc_dummy] [#![rustc_dummy] 0; 0]; + let _ = #[rustc_dummy] foo(); + let _ = #[rustc_dummy] 1i32.clone(); + let _ = #[rustc_dummy] (#![rustc_dummy] ); + let _ = #[rustc_dummy] (#![rustc_dummy] 0); + let _ = #[rustc_dummy] (#![rustc_dummy] 0,); + let _ = #[rustc_dummy] (#![rustc_dummy] 0, 0); + let _ = #[rustc_dummy] 0 + #[rustc_dummy] 0; + let _ = #[rustc_dummy] !0; + let _ = #[rustc_dummy] -0i32; + let _ = #[rustc_dummy] false; + let _ = #[rustc_dummy] 'c'; + let _ = #[rustc_dummy] 0; + let _ = #[rustc_dummy] 0 as usize; let _ = - #[attr] while false { - #![attr] - }; + #[rustc_dummy] while false { + #![rustc_dummy] + }; let _ = - #[attr] while let None = Some(()) { - #![attr] - }; + #[rustc_dummy] while let None = Some(()) { + #![rustc_dummy] + }; let _ = - #[attr] for _ in 0..0 { - #![attr] - }; + #[rustc_dummy] for _ in 0..0 { + #![rustc_dummy] + }; // FIXME: pp bug, two spaces after the loop let _ = - #[attr] loop { - #![attr] - }; + #[rustc_dummy] loop { + #![rustc_dummy] + }; let _ = - #[attr] match false { - #![attr] - _ => (), - }; - let _ = #[attr] || #[attr] (); - let _ = #[attr] move || #[attr] (); + #[rustc_dummy] match false { + #![rustc_dummy] + _ => (), + }; + let _ = #[rustc_dummy] || #[rustc_dummy] (); + let _ = #[rustc_dummy] move || #[rustc_dummy] (); let _ = - #[attr] || - { - #![attr] - #[attr] - () - }; + #[rustc_dummy] || + { + #![rustc_dummy] + #[rustc_dummy] + () + }; let _ = - #[attr] move || - { - #![attr] - #[attr] - () - }; + #[rustc_dummy] move || + { + #![rustc_dummy] + #[rustc_dummy] + () + }; let _ = - #[attr] { - #![attr] - }; + #[rustc_dummy] { + #![rustc_dummy] + }; let _ = - #[attr] { - #![attr] - let _ = (); - }; + #[rustc_dummy] { + #![rustc_dummy] + let _ = (); + }; let _ = - #[attr] { - #![attr] - let _ = (); - () - }; + #[rustc_dummy] { + #![rustc_dummy] + let _ = (); + () + }; let mut x = 0; - let _ = #[attr] x = 15; - let _ = #[attr] x += 15; + let _ = #[rustc_dummy] x = 15; + let _ = #[rustc_dummy] x += 15; let s = Foo{data: (),}; - let _ = #[attr] s.data; - let _ = (#[attr] s).data; + let _ = #[rustc_dummy] s.data; + let _ = (#[rustc_dummy] s).data; let t = Bar(()); - let _ = #[attr] t.0; - let _ = (#[attr] t).0; + let _ = #[rustc_dummy] t.0; + let _ = (#[rustc_dummy] t).0; let v = vec!(0); - let _ = #[attr] v[0]; - let _ = (#[attr] v)[0]; - let _ = #[attr] 0..#[attr] 0; - let _ = #[attr] 0..; - let _ = #[attr] (0..0); - let _ = #[attr] (0..); - let _ = #[attr] (..0); - let _ = #[attr] (..); - let _: fn(&u32) -> u32 = #[attr] std::clone::Clone::clone; - let _ = #[attr] &0; - let _ = #[attr] &mut 0; - let _ = #[attr] &#[attr] 0; - let _ = #[attr] &mut #[attr] 0; + let _ = #[rustc_dummy] v[0]; + let _ = (#[rustc_dummy] v)[0]; + let _ = #[rustc_dummy] 0..#[rustc_dummy] 0; + let _ = #[rustc_dummy] 0..; + let _ = #[rustc_dummy] (0..0); + let _ = #[rustc_dummy] (0..); + let _ = #[rustc_dummy] (..0); + let _ = #[rustc_dummy] (..); + let _: fn(&u32) -> u32 = #[rustc_dummy] std::clone::Clone::clone; + let _ = #[rustc_dummy] &0; + let _ = #[rustc_dummy] &mut 0; + let _ = #[rustc_dummy] &#[rustc_dummy] 0; + let _ = #[rustc_dummy] &mut #[rustc_dummy] 0; // FIXME: pp bug, extra space after keyword? - while false { let _ = #[attr] continue ; } - while true { let _ = #[attr] break ; } - || #[attr] return; - let _ = #[attr] expr_mac!(); - /* FIXME: pp bug, losing delimiter styles - let _ = #[attr] expr_mac![]; - let _ = #[attr] expr_mac!{}; - */ - let _ = #[attr] Foo{#![attr] data: (),}; - let _ = #[attr] Foo{#![attr] ..s}; - let _ = #[attr] Foo{#![attr] data: (), ..s}; - let _ = #[attr] (#![attr] 0); + while false { let _ = #[rustc_dummy] continue ; } + while true { let _ = #[rustc_dummy] break ; } + || #[rustc_dummy] return; + let _ = #[rustc_dummy] expr_mac!(); + let _ = #[rustc_dummy] expr_mac![]; + let _ = #[rustc_dummy] expr_mac!{ }; + let _ = #[rustc_dummy] Foo{#![rustc_dummy] data: (),}; + let _ = #[rustc_dummy] Foo{#![rustc_dummy] ..s}; + let _ = #[rustc_dummy] Foo{#![rustc_dummy] data: (), ..s}; + let _ = #[rustc_dummy] (#![rustc_dummy] 0); } fn _12() { - #[attr] + #[rustc_dummy] let _ = 0; - #[attr] + #[rustc_dummy] 0; - #[attr] + #[rustc_dummy] expr_mac!(); - #[attr] + #[rustc_dummy] { - #![attr] + #![rustc_dummy] } } diff --git a/src/test/run-fail/borrowck-local-borrow.rs b/src/test/run-fail/borrowck-local-borrow.rs index cb17a6305624b..d07f76b6252dc 100644 --- a/src/test/run-fail/borrowck-local-borrow.rs +++ b/src/test/run-fail/borrowck-local-borrow.rs @@ -1,6 +1,6 @@ // error-pattern:panic 1 -// revisions: ast mir +// revisions: migrate mir //[mir]compile-flags: -Z borrowck=mir fn main() { diff --git a/src/test/run-fail/call-fn-never-arg.rs b/src/test/run-fail/call-fn-never-arg.rs index d21a43ec5c50a..f5b2cfaefe022 100644 --- a/src/test/run-fail/call-fn-never-arg.rs +++ b/src/test/run-fail/call-fn-never-arg.rs @@ -12,4 +12,3 @@ fn foo(x: !) -> ! { fn main() { foo(panic!("wowzers!")) } - diff --git a/src/test/run-fail/cast-never.rs b/src/test/run-fail/cast-never.rs index 3620ddee47869..0b05a4b911284 100644 --- a/src/test/run-fail/cast-never.rs +++ b/src/test/run-fail/cast-never.rs @@ -8,4 +8,3 @@ fn main() { let x: ! = panic!(); let y: u32 = x as u32; } - diff --git a/src/test/run-fail/generator-resume-after-panic.rs b/src/test/run-fail/generator-resume-after-panic.rs new file mode 100644 index 0000000000000..910b4903bf6a3 --- /dev/null +++ b/src/test/run-fail/generator-resume-after-panic.rs @@ -0,0 +1,22 @@ +// error-pattern:generator resumed after panicking + +// Test that we get the correct message for resuming a panicked generator. + +#![feature(generators, generator_trait)] + +use std::{ + ops::Generator, + pin::Pin, + panic, +}; + +fn main() { + let mut g = || { + panic!(); + yield; + }; + panic::catch_unwind(panic::AssertUnwindSafe(|| { + let x = Pin::new(&mut g).resume(); + })); + Pin::new(&mut g).resume(); +} diff --git a/src/test/run-fail/issue-51345.rs b/src/test/run-fail/issue-51345.rs index 3c7f6a68db545..c62f98ea78d1e 100644 --- a/src/test/run-fail/issue-51345.rs +++ b/src/test/run-fail/issue-51345.rs @@ -1,7 +1,5 @@ // error-pattern: thread 'main' panicked at 'explicit panic' -#![feature(nll)] - fn main() { let mut vec = vec![]; vec.push((vec.len(), panic!())); diff --git a/src/test/run-fail/never-associated-type.rs b/src/test/run-fail/never-associated-type.rs index ba30b9ea0fe3d..587f0f72d5a62 100644 --- a/src/test/run-fail/never-associated-type.rs +++ b/src/test/run-fail/never-associated-type.rs @@ -21,4 +21,3 @@ impl Foo for Blah { fn main() { Blah.smeg(); } - diff --git a/src/test/run-fail/never-type-arg.rs b/src/test/run-fail/never-type-arg.rs index fc7f2fc90d704..1747e96eef4e3 100644 --- a/src/test/run-fail/never-type-arg.rs +++ b/src/test/run-fail/never-type-arg.rs @@ -15,4 +15,3 @@ impl PartialEq for Wub { fn main() { let _ = Wub == panic!("oh no!"); } - diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs index 5f76caabc796b..796729ac4cc28 100644 --- a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs +++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs @@ -1,4 +1,4 @@ -// compile-pass +// error-pattern:returned Box from main() // failure-status: 1 use std::error::Error; diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs index bd47a9768f94b..2f3a73a30ad95 100644 --- a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs +++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs @@ -1,4 +1,4 @@ -// compile-pass +// error-pattern:returned Box from main() // failure-status: 1 use std::io::{Error, ErrorKind}; diff --git a/src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile b/src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile index 0962ebfbff546..54526e8ef23b3 100644 --- a/src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile +++ b/src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile @@ -4,9 +4,12 @@ # of types, it will not run with a dylib that has a different set of # types. +# NOTE(eddyb) this test only works with the `legacy` mangling, +# and will probably get removed once `legacy` is gone. + all: - $(RUSTC) a.rs --cfg x -C prefer-dynamic - $(RUSTC) b.rs -C prefer-dynamic + $(RUSTC) a.rs --cfg x -C prefer-dynamic -Z symbol-mangling-version=legacy + $(RUSTC) b.rs -C prefer-dynamic -Z symbol-mangling-version=legacy $(call RUN,b) - $(RUSTC) a.rs --cfg y -C prefer-dynamic + $(RUSTC) a.rs --cfg y -C prefer-dynamic -Z symbol-mangling-version=legacy $(call FAIL,b) diff --git a/src/test/run-make-fulldeps/alloc-extern-crates/fakealloc.rs b/src/test/run-make-fulldeps/alloc-extern-crates/fakealloc.rs index 625c3afab921c..d4612c325d5ac 100644 --- a/src/test/run-make-fulldeps/alloc-extern-crates/fakealloc.rs +++ b/src/test/run-make-fulldeps/alloc-extern-crates/fakealloc.rs @@ -2,14 +2,16 @@ #![no_std] #[inline] -pub unsafe fn allocate(_size: usize, _align: usize) -> *mut u8 { 0 as *mut u8 } +pub unsafe fn allocate(_size: usize, _align: usize) -> *mut u8 { + core::ptr::null_mut() +} #[inline] pub unsafe fn deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) { } #[inline] pub unsafe fn reallocate(_ptr: *mut u8, _old_size: usize, _size: usize, _align: usize) -> *mut u8 { - 0 as *mut u8 + core::ptr::null_mut() } #[inline] diff --git a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs index 96a238afaec05..a0a5b141ec0e1 100644 --- a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs +++ b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs @@ -62,7 +62,7 @@ pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize { continue_if!(ap.arg::() == 16); continue_if!(ap.arg::() == 'A' as c_char); continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Skip Me!")); - ap.copy(|mut ap| { + ap.with_copy(|mut ap| { if compare_c_str(ap.arg::<*const c_char>(), "Correct") { 0 } else { @@ -88,6 +88,6 @@ pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize { } #[no_mangle] -pub unsafe extern "C" fn check_varargs_2(_: c_int, mut ap: ...) -> usize { +pub unsafe extern "C" fn check_varargs_2(_: c_int, _ap: ...) -> usize { 0 } diff --git a/src/test/run-make-fulldeps/cross-lang-lto-clang/Makefile b/src/test/run-make-fulldeps/cross-lang-lto-clang/Makefile index b3c5fb2d79647..3ca2a8afad0b1 100644 --- a/src/test/run-make-fulldeps/cross-lang-lto-clang/Makefile +++ b/src/test/run-make-fulldeps/cross-lang-lto-clang/Makefile @@ -12,14 +12,14 @@ cpp-executable: $(CLANG) -flto=thin -fuse-ld=lld -L $(TMPDIR) -lrustlib-xlto -o $(TMPDIR)/cmain ./cmain.c -O3 # Make sure we don't find a call instruction to the function we expect to # always be inlined. - llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -v -e "call.*rust_always_inlined" + "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -v -e "call.*rust_always_inlined" # As a sanity check, make sure we do find a call instruction to a # non-inlined function - llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -e "call.*rust_never_inlined" + "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -e "call.*rust_never_inlined" rust-executable: $(CLANG) ./clib.c -flto=thin -c -o $(TMPDIR)/clib.o -O2 (cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o) $(RUSTC) -Clinker-plugin-lto=on -L$(TMPDIR) -Copt-level=2 -Clinker=$(CLANG) -Clink-arg=-fuse-ld=lld ./main.rs -o $(TMPDIR)/rsmain - llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -e "call.*c_never_inlined" - llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -v -e "call.*c_always_inlined" + "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -e "call.*c_never_inlined" + "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -v -e "call.*c_always_inlined" diff --git a/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/Makefile b/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/Makefile new file mode 100644 index 0000000000000..f8efeca56141b --- /dev/null +++ b/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/Makefile @@ -0,0 +1,87 @@ +# needs-matching-clang + +# This test makes sure that cross-language inlining can be used in conjunction +# with profile-guided optimization. The test only tests that the whole workflow +# can be executed without anything crashing. It does not test whether PGO or +# xLTO have any specific effect on the generated code. + +-include ../tools.mk + +COMMON_FLAGS=-Copt-level=3 -Ccodegen-units=1 + +# LLVM doesn't support instrumenting binaries that use SEH: +# https://bugs.llvm.org/show_bug.cgi?id=41279 +# +# Things work fine with -Cpanic=abort though. +ifdef IS_MSVC +COMMON_FLAGS+= -Cpanic=abort +endif + +all: cpp-executable rust-executable + +cpp-executable: + $(RUSTC) -Clinker-plugin-lto=on \ + -Cprofile-generate="$(TMPDIR)"/cpp-profdata \ + -o "$(TMPDIR)"/librustlib-xlto.a \ + $(COMMON_FLAGS) \ + ./rustlib.rs + $(CLANG) -flto=thin \ + -fprofile-generate="$(TMPDIR)"/cpp-profdata \ + -fuse-ld=lld \ + -L "$(TMPDIR)" \ + -lrustlib-xlto \ + -o "$(TMPDIR)"/cmain \ + -O3 \ + ./cmain.c + $(TMPDIR)/cmain + # Postprocess the profiling data so it can be used by the compiler + "$(LLVM_BIN_DIR)"/llvm-profdata merge \ + -o "$(TMPDIR)"/cpp-profdata/merged.profdata \ + "$(TMPDIR)"/cpp-profdata/default_*.profraw + $(RUSTC) -Clinker-plugin-lto=on \ + -Cprofile-use="$(TMPDIR)"/cpp-profdata/merged.profdata \ + -o "$(TMPDIR)"/librustlib-xlto.a \ + $(COMMON_FLAGS) \ + ./rustlib.rs + $(CLANG) -flto=thin \ + -fprofile-use="$(TMPDIR)"/cpp-profdata/merged.profdata \ + -fuse-ld=lld \ + -L "$(TMPDIR)" \ + -lrustlib-xlto \ + -o "$(TMPDIR)"/cmain \ + -O3 \ + ./cmain.c + +rust-executable: + exit + $(CLANG) ./clib.c -fprofile-generate="$(TMPDIR)"/rs-profdata -flto=thin -c -o $(TMPDIR)/clib.o -O3 + (cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o) + $(RUSTC) -Clinker-plugin-lto=on \ + -Cprofile-generate="$(TMPDIR)"/rs-profdata \ + -L$(TMPDIR) \ + $(COMMON_FLAGS) \ + -Clinker=$(CLANG) \ + -Clink-arg=-fuse-ld=lld \ + -o $(TMPDIR)/rsmain \ + ./main.rs + $(TMPDIR)/rsmain + # Postprocess the profiling data so it can be used by the compiler + "$(LLVM_BIN_DIR)"/llvm-profdata merge \ + -o "$(TMPDIR)"/rs-profdata/merged.profdata \ + "$(TMPDIR)"/rs-profdata/default_*.profraw + $(CLANG) ./clib.c \ + -fprofile-use="$(TMPDIR)"/rs-profdata/merged.profdata \ + -flto=thin \ + -c \ + -o $(TMPDIR)/clib.o \ + -O3 + rm "$(TMPDIR)"/libxyz.a + (cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o) + $(RUSTC) -Clinker-plugin-lto=on \ + -Cprofile-use="$(TMPDIR)"/rs-profdata/merged.profdata \ + -L$(TMPDIR) \ + $(COMMON_FLAGS) \ + -Clinker=$(CLANG) \ + -Clink-arg=-fuse-ld=lld \ + -o $(TMPDIR)/rsmain \ + ./main.rs diff --git a/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/clib.c b/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/clib.c new file mode 100644 index 0000000000000..90f33f24dc424 --- /dev/null +++ b/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/clib.c @@ -0,0 +1,9 @@ +#include + +uint32_t c_always_inlined() { + return 1234; +} + +__attribute__((noinline)) uint32_t c_never_inlined() { + return 12345; +} diff --git a/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/cmain.c b/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/cmain.c new file mode 100644 index 0000000000000..e3f24828be371 --- /dev/null +++ b/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/cmain.c @@ -0,0 +1,12 @@ +#include + +// A trivial function defined in Rust, returning a constant value. This should +// always be inlined. +uint32_t rust_always_inlined(); + + +uint32_t rust_never_inlined(); + +int main(int argc, char** argv) { + return (rust_never_inlined() + rust_always_inlined()) * 0; +} diff --git a/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/main.rs b/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/main.rs new file mode 100644 index 0000000000000..8129dcb85d96a --- /dev/null +++ b/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/main.rs @@ -0,0 +1,11 @@ +#[link(name = "xyz")] +extern "C" { + fn c_always_inlined() -> u32; + fn c_never_inlined() -> u32; +} + +fn main() { + unsafe { + println!("blub: {}", c_always_inlined() + c_never_inlined()); + } +} diff --git a/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/rustlib.rs b/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/rustlib.rs new file mode 100644 index 0000000000000..8a74d74a420bd --- /dev/null +++ b/src/test/run-make-fulldeps/cross-lang-lto-pgo-smoketest/rustlib.rs @@ -0,0 +1,12 @@ +#![crate_type="staticlib"] + +#[no_mangle] +pub extern "C" fn rust_always_inlined() -> u32 { + 42 +} + +#[no_mangle] +#[inline(never)] +pub extern "C" fn rust_never_inlined() -> u32 { + 421 +} diff --git a/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile b/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile index c9da06ff93f86..f70b411d747e7 100644 --- a/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile +++ b/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile @@ -12,7 +12,7 @@ all: staticlib.rs upstream.rs # Check No LTO $(RUSTC) staticlib.rs -C linker-plugin-lto -Ccodegen-units=1 -L. -o $(TMPDIR)/staticlib.a - (cd $(TMPDIR); $(LD_LIB_PATH_ENVVAR)=$(REAL_LD_LIBRARY_PATH) llvm-ar x ./staticlib.a) + (cd $(TMPDIR); "$(LLVM_BIN_DIR)"/llvm-ar x ./staticlib.a) # Make sure the upstream object file was included ls $(TMPDIR)/upstream.*.rcgu.o @@ -22,7 +22,7 @@ all: staticlib.rs upstream.rs # Check ThinLTO $(RUSTC) upstream.rs -C linker-plugin-lto -Ccodegen-units=1 -Clto=thin $(RUSTC) staticlib.rs -C linker-plugin-lto -Ccodegen-units=1 -Clto=thin -L. -o $(TMPDIR)/staticlib.a - (cd $(TMPDIR); $(LD_LIB_PATH_ENVVAR)=$(REAL_LD_LIBRARY_PATH) llvm-ar x ./staticlib.a) + (cd $(TMPDIR); "$(LLVM_BIN_DIR)"/llvm-ar x ./staticlib.a) ls $(TMPDIR)/upstream.*.rcgu.o else diff --git a/src/test/run-make-fulldeps/cross-lang-lto/Makefile b/src/test/run-make-fulldeps/cross-lang-lto/Makefile index 43bd05a73592c..b4394cb5b4079 100644 --- a/src/test/run-make-fulldeps/cross-lang-lto/Makefile +++ b/src/test/run-make-fulldeps/cross-lang-lto/Makefile @@ -10,8 +10,8 @@ ifndef IS_WINDOWS # -Clinker-plugin-lto. # this only succeeds for bitcode files -ASSERT_IS_BITCODE_OBJ=($(LD_LIB_PATH_ENVVAR)=$(REAL_LD_LIBRARY_PATH) llvm-bcanalyzer $(1)) -EXTRACT_OBJS=(cd $(TMPDIR); rm -f ./*.o; $(LD_LIB_PATH_ENVVAR)=$(REAL_LD_LIBRARY_PATH) llvm-ar x $(1)) +ASSERT_IS_BITCODE_OBJ=("$(LLVM_BIN_DIR)"/llvm-bcanalyzer $(1)) +EXTRACT_OBJS=(cd $(TMPDIR); rm -f ./*.o; "$(LLVM_BIN_DIR)"/llvm-ar x $(1)) BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Clinker-plugin-lto -Ccodegen-units=1 BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Clinker-plugin-lto -Ccodegen-units=1 --emit=obj diff --git a/src/test/run-make-fulldeps/extern-prelude/Makefile b/src/test/run-make-fulldeps/extern-prelude/Makefile deleted file mode 100644 index 69af01ccf0369..0000000000000 --- a/src/test/run-make-fulldeps/extern-prelude/Makefile +++ /dev/null @@ -1,11 +0,0 @@ --include ../tools.mk - -all: - $(RUSTC) ep-lib.rs - $(RUSTC) ep-vec.rs - - $(RUSTC) basic.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib - $(RUSTC) shadow-mod.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib - $(RUSTC) shadow-prelude.rs --extern Vec=$(TMPDIR)/libep_vec.rlib - $(RUSTC) relative-only.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "unresolved import" - $(RUSTC) relative-only.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "failed to resolve" diff --git a/src/test/run-make-fulldeps/extern-prelude/basic.rs b/src/test/run-make-fulldeps/extern-prelude/basic.rs deleted file mode 100644 index dc7cc1f27b6f6..0000000000000 --- a/src/test/run-make-fulldeps/extern-prelude/basic.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![feature(extern_prelude)] - -fn main() { - let s = ep_lib::S; // It works - s.external(); -} diff --git a/src/test/run-make-fulldeps/extern-prelude/ep-lib.rs b/src/test/run-make-fulldeps/extern-prelude/ep-lib.rs deleted file mode 100644 index f5e129eca6631..0000000000000 --- a/src/test/run-make-fulldeps/extern-prelude/ep-lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![crate_type = "rlib"] - -pub struct S; - -impl S { - pub fn external(&self) {} -} diff --git a/src/test/run-make-fulldeps/extern-prelude/ep-vec.rs b/src/test/run-make-fulldeps/extern-prelude/ep-vec.rs deleted file mode 100644 index 148a4a987266f..0000000000000 --- a/src/test/run-make-fulldeps/extern-prelude/ep-vec.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![crate_type = "rlib"] - -pub fn new(arg1: f32, arg2: ()) {} diff --git a/src/test/run-make-fulldeps/extern-prelude/relative-only.rs b/src/test/run-make-fulldeps/extern-prelude/relative-only.rs deleted file mode 100644 index 0fdf3b49d96b4..0000000000000 --- a/src/test/run-make-fulldeps/extern-prelude/relative-only.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Extern prelude names are not available by absolute paths - -#![feature(extern_prelude)] - -use ep_lib::S; - -fn main() { - let s = ::ep_lib::S; -} diff --git a/src/test/run-make-fulldeps/extern-prelude/shadow-mod.rs b/src/test/run-make-fulldeps/extern-prelude/shadow-mod.rs deleted file mode 100644 index 69411aaf57c71..0000000000000 --- a/src/test/run-make-fulldeps/extern-prelude/shadow-mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Local module shadows `ep_lib` from extern prelude - -mod ep_lib { - pub struct S; - - impl S { - pub fn internal(&self) {} - } -} - -fn main() { - let s = ep_lib::S; - s.internal(); // OK -} diff --git a/src/test/run-make-fulldeps/extern-prelude/shadow-prelude.rs b/src/test/run-make-fulldeps/extern-prelude/shadow-prelude.rs deleted file mode 100644 index 6c6ce12708d79..0000000000000 --- a/src/test/run-make-fulldeps/extern-prelude/shadow-prelude.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Extern prelude shadows standard library prelude - -#![feature(extern_prelude)] - -fn main() { - let x = Vec::new(0f32, ()); // OK -} diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index 51891ed538770..75cad9ec8ff33 100644 --- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs @@ -3,36 +3,66 @@ extern crate syntax; extern crate rustc; extern crate rustc_codegen_utils; +#[macro_use] +extern crate rustc_data_structures; +extern crate rustc_target; use std::any::Any; -use std::sync::mpsc; +use std::sync::{Arc, mpsc}; +use std::path::Path; use syntax::symbol::Symbol; -use rustc::session::{Session, CompileIncomplete}; +use rustc::session::Session; use rustc::session::config::OutputFilenames; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; -use rustc::middle::cstore::MetadataLoader; +use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; use rustc::dep_graph::DepGraph; -use rustc_codegen_utils::codegen_backend::{CodegenBackend, MetadataOnlyCodegenBackend}; +use rustc::util::common::ErrorReported; +use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_data_structures::sync::MetadataRef; +use rustc_data_structures::owning_ref::OwningRef; +use rustc_target::spec::Target; -struct TheBackend(Box); +pub struct NoLlvmMetadataLoader; + +impl MetadataLoader for NoLlvmMetadataLoader { + fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result { + let buf = std::fs::read(filename).map_err(|e| format!("metadata file open err: {:?}", e))?; + let buf: OwningRef, [u8]> = OwningRef::new(buf); + Ok(rustc_erase_owner!(buf.map_owner_box())) + } + + fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result { + self.get_rlib_metadata(target, filename) + } +} + +struct TheBackend; impl CodegenBackend for TheBackend { fn metadata_loader(&self) -> Box { - self.0.metadata_loader() + Box::new(NoLlvmMetadataLoader) } fn provide(&self, providers: &mut Providers) { - self.0.provide(providers); + rustc_codegen_utils::symbol_names::provide(providers); + + providers.target_features_whitelist = |tcx, _cnum| { + tcx.arena.alloc(Default::default()) // Just a dummy + }; + providers.is_reachable_non_generic = |_tcx, _defid| true; + providers.exported_symbols = |_tcx, _crate| Arc::new(Vec::new()); } fn provide_extern(&self, providers: &mut Providers) { - self.0.provide_extern(providers); + providers.is_reachable_non_generic = |_tcx, _defid| true; } fn codegen_crate<'a, 'tcx>( &self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, + _metadata: EncodedMetadata, + _need_metadata_module: bool, _rx: mpsc::Receiver> ) -> Box { use rustc::hir::def_id::LOCAL_CRATE; @@ -46,7 +76,7 @@ impl CodegenBackend for TheBackend { sess: &Session, _dep_graph: &DepGraph, outputs: &OutputFilenames, - ) -> Result<(), CompileIncomplete> { + ) -> Result<(), ErrorReported> { use std::io::Write; use rustc::session::config::CrateType; use rustc_codegen_utils::link::out_filename; @@ -68,5 +98,5 @@ impl CodegenBackend for TheBackend { /// This is the entrypoint for a hot plugged rustc_codegen_llvm #[no_mangle] pub fn __rustc_codegen_backend() -> Box { - Box::new(TheBackend(MetadataOnlyCodegenBackend::boxed())) + Box::new(TheBackend) } diff --git a/src/test/run-make-fulldeps/issue-14500/Makefile b/src/test/run-make-fulldeps/issue-14500/Makefile index bd94db0952028..0c0e331da1d5a 100644 --- a/src/test/run-make-fulldeps/issue-14500/Makefile +++ b/src/test/run-make-fulldeps/issue-14500/Makefile @@ -6,10 +6,6 @@ # is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the # only way that `foo.c` will successfully compile. -ifeq ($(UNAME),Bitrig) - EXTRACFLAGS := -lc $(EXTRACFLAGS) $(EXTRACXXFLAGS) -endif - all: $(RUSTC) foo.rs --crate-type=rlib $(RUSTC) bar.rs --crate-type=staticlib -C lto -L. -o $(TMPDIR)/libbar.a diff --git a/src/test/run-make-fulldeps/issue-18943/foo.rs b/src/test/run-make-fulldeps/issue-18943/foo.rs index 0b29c8712802d..d18400dd3a54b 100644 --- a/src/test/run-make-fulldeps/issue-18943/foo.rs +++ b/src/test/run-make-fulldeps/issue-18943/foo.rs @@ -3,4 +3,3 @@ trait Foo { } trait Bar { } impl<'a> Foo for Bar + 'a { } - diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs index e9d825df2a46e..0cbdf40e2f908 100644 --- a/src/test/run-make-fulldeps/issue-19371/foo.rs +++ b/src/test/run-make-fulldeps/issue-19371/foo.rs @@ -1,26 +1,16 @@ #![feature(rustc_private)] extern crate rustc; -extern crate rustc_driver; -extern crate rustc_lint; -extern crate rustc_metadata; -extern crate rustc_errors; -extern crate rustc_codegen_utils; extern crate rustc_interface; extern crate syntax; -use rustc::session::{build_session, Session}; +use rustc::session::DiagnosticOutput; use rustc::session::config::{Input, Options, OutputType, OutputTypes}; -use rustc_driver::driver::{self, compile_input, CompileController}; -use rustc_metadata::cstore::CStore; -use rustc_errors::registry::Registry; -use rustc_interface::util; +use rustc_interface::interface; use syntax::source_map::FileName; -use rustc_codegen_utils::codegen_backend::CodegenBackend; use std::path::PathBuf; -use std::rc::Rc; fn main() { let src = r#" @@ -44,39 +34,33 @@ fn main() { compile(src.to_string(), tmpdir.join("out"), sysroot.clone()); } -fn basic_sess(opts: Options) -> (Session, Rc, Box) { - let descriptions = Registry::new(&rustc::DIAGNOSTICS); - let sess = build_session(opts, None, descriptions); - let codegen_backend = util::get_codegen_backend(&sess); - let cstore = Rc::new(CStore::new(codegen_backend.metadata_loader())); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - (sess, cstore, codegen_backend) -} - fn compile(code: String, output: PathBuf, sysroot: PathBuf) { - syntax::with_globals(|| { - let mut opts = Options::default(); - opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); - opts.maybe_sysroot = Some(sysroot); - if let Ok(linker) = std::env::var("RUSTC_LINKER") { - opts.cg.linker = Some(linker.into()); - } - driver::spawn_thread_pool(opts, |opts| { - let (sess, cstore, codegen_backend) = basic_sess(opts); - let control = CompileController::basic(); - let name = FileName::anon_source_code(&code); - let input = Input::Str { name, input: code }; - let _ = compile_input( - codegen_backend, - &sess, - &cstore, - &None, - &input, - &None, - &Some(output), - None, - &control - ); - }); + let mut opts = Options::default(); + opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); + opts.maybe_sysroot = Some(sysroot); + + if let Ok(linker) = std::env::var("RUSTC_LINKER") { + opts.cg.linker = Some(linker.into()); + } + + let name = FileName::anon_source_code(&code); + let input = Input::Str { name, input: code }; + + let config = interface::Config { + opts, + crate_cfg: Default::default(), + input, + input_path: None, + output_file: Some(output), + output_dir: None, + file_loader: None, + diagnostic_output: DiagnosticOutput::Default, + stderr: None, + crate_name: None, + lint_caps: Default::default(), + }; + + interface::run_compiler(config, |compiler| { + compiler.compile().ok(); }); } diff --git a/src/test/run-make-fulldeps/issue-28595/b.c b/src/test/run-make-fulldeps/issue-28595/b.c index 8343f5b229e1b..6aecb5f9e04c0 100644 --- a/src/test/run-make-fulldeps/issue-28595/b.c +++ b/src/test/run-make-fulldeps/issue-28595/b.c @@ -3,4 +3,3 @@ extern void a(void); void b(void) { a(); } - diff --git a/src/test/run-make-fulldeps/libs-through-symlinks/Makefile b/src/test/run-make-fulldeps/libs-through-symlinks/Makefile index 7c5ea7e402e56..8be2e234fea1f 100644 --- a/src/test/run-make-fulldeps/libs-through-symlinks/Makefile +++ b/src/test/run-make-fulldeps/libs-through-symlinks/Makefile @@ -8,4 +8,4 @@ all: mkdir -p $(TMPDIR)/outdir $(RUSTC) foo.rs -o $(TMPDIR)/outdir/$(NAME) ln -nsf outdir/$(NAME) $(TMPDIR) - RUST_LOG=rustc_metadata::loader $(RUSTC) bar.rs + RUSTC_LOG=rustc_metadata::loader $(RUSTC) bar.rs diff --git a/src/test/run-make-fulldeps/libtest-json/f.rs b/src/test/run-make-fulldeps/libtest-json/f.rs index 29d52ee96540f..f5e44c2c24407 100644 --- a/src/test/run-make-fulldeps/libtest-json/f.rs +++ b/src/test/run-make-fulldeps/libtest-json/f.rs @@ -19,4 +19,3 @@ fn c() { fn d() { assert!(false); } - diff --git a/src/test/run-make-fulldeps/libtest-json/output.json b/src/test/run-make-fulldeps/libtest-json/output.json index c8b3d08186929..0caf268aa007f 100644 --- a/src/test/run-make-fulldeps/libtest-json/output.json +++ b/src/test/run-make-fulldeps/libtest-json/output.json @@ -2,7 +2,7 @@ { "type": "test", "event": "started", "name": "a" } { "type": "test", "name": "a", "event": "ok" } { "type": "test", "event": "started", "name": "b" } -{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:8:5\nnote: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" } +{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:8:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" } { "type": "test", "event": "started", "name": "c" } { "type": "test", "name": "c", "event": "ok" } { "type": "test", "event": "started", "name": "d" } diff --git a/src/test/run-make-fulldeps/link-cfg/Makefile b/src/test/run-make-fulldeps/link-cfg/Makefile index 188cba5fe4127..2701b4a593cc6 100644 --- a/src/test/run-make-fulldeps/link-cfg/Makefile +++ b/src/test/run-make-fulldeps/link-cfg/Makefile @@ -2,7 +2,7 @@ all: $(call DYLIB,return1) $(call DYLIB,return2) $(call NATIVE_STATICLIB,return3) ls $(TMPDIR) - $(RUSTC) --print cfg --target x86_64-unknown-linux-musl | $(CGREP) crt-static + $(BARE_RUSTC) --print cfg --target x86_64-unknown-linux-musl | $(CGREP) crt-static $(RUSTC) no-deps.rs --cfg foo $(call RUN,no-deps) diff --git a/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile b/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile index 3fffd1e7aa2a2..b47ce17ec8baa 100644 --- a/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile +++ b/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile @@ -20,4 +20,4 @@ all: $(RUSTC) library.rs mkdir $(bad_dir) mv $(TMPDIR)/liblibrary.a $(bad_dir) - LIBRARY_PATH=$(bad_dir) $(RUSTC) exec.rs 2>&1 | $(CGREP) this_symbol_not_defined + $(RUSTC) -L $(bad_dir) exec.rs 2>&1 | $(CGREP) this_symbol_not_defined diff --git a/src/test/run-make-fulldeps/lto-dylib-dep/Makefile b/src/test/run-make-fulldeps/lto-dylib-dep/Makefile new file mode 100644 index 0000000000000..ab8ee6c2ef7e1 --- /dev/null +++ b/src/test/run-make-fulldeps/lto-dylib-dep/Makefile @@ -0,0 +1,10 @@ +-include ../tools.mk + +# Test that we don't run into an assertion when using a Rust dylib dependency +# while compiling with full LTO. +# See https://github.com/rust-lang/rust/issues/59137 + +all: + $(RUSTC) a_dylib.rs --crate-type=dylib -C prefer-dynamic + $(RUSTC) main.rs -C lto + $(call RUN,main) diff --git a/src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs b/src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs new file mode 100644 index 0000000000000..e63457e6eb953 --- /dev/null +++ b/src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs @@ -0,0 +1,3 @@ +pub fn foo() { + println!("bar"); +} diff --git a/src/test/run-make-fulldeps/lto-dylib-dep/main.rs b/src/test/run-make-fulldeps/lto-dylib-dep/main.rs new file mode 100644 index 0000000000000..4fb3c4730b2c6 --- /dev/null +++ b/src/test/run-make-fulldeps/lto-dylib-dep/main.rs @@ -0,0 +1,5 @@ +extern crate a_dylib; + +fn main() { + a_dylib::foo(); +} diff --git a/src/test/run-make-fulldeps/lto-no-link-whole-rlib/lib2.rs b/src/test/run-make-fulldeps/lto-no-link-whole-rlib/lib2.rs index 50b7882a05a53..c9e1baa434b12 100644 --- a/src/test/run-make-fulldeps/lto-no-link-whole-rlib/lib2.rs +++ b/src/test/run-make-fulldeps/lto-no-link-whole-rlib/lib2.rs @@ -10,4 +10,3 @@ extern { pub fn foo2() -> i32 { unsafe { foo() } } - diff --git a/src/test/run-make-fulldeps/override-aliased-flags/Makefile b/src/test/run-make-fulldeps/override-aliased-flags/Makefile new file mode 100644 index 0000000000000..bea610eeb9fd1 --- /dev/null +++ b/src/test/run-make-fulldeps/override-aliased-flags/Makefile @@ -0,0 +1,22 @@ +-include ../tools.mk + +# FIXME: it would be good to check that it's actually the rightmost flags +# that are used when multiple flags are specified, but I can't think of a +# reliable way to check this. + +all: + # Test that `-O` and `-C opt-level` can be specified multiple times. + # The rightmost flag will be used over any previous flags. + $(RUSTC) -O -O main.rs + $(RUSTC) -O -C opt-level=0 main.rs + $(RUSTC) -C opt-level=0 -O main.rs + $(RUSTC) -C opt-level=0 -C opt-level=2 main.rs + $(RUSTC) -C opt-level=2 -C opt-level=0 main.rs + + # Test that `-g` and `-C debuginfo` can be specified multiple times. + # The rightmost flag will be used over any previous flags. + $(RUSTC) -g -g main.rs + $(RUSTC) -g -C debuginfo=0 main.rs + $(RUSTC) -C debuginfo=0 -g main.rs + $(RUSTC) -C debuginfo=0 -C debuginfo=2 main.rs + $(RUSTC) -C debuginfo=2 -C debuginfo=0 main.rs diff --git a/src/test/run-make-fulldeps/override-aliased-flags/main.rs b/src/test/run-make-fulldeps/override-aliased-flags/main.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/src/test/run-make-fulldeps/override-aliased-flags/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile index e358314c0d09e..6c70d951c35ea 100644 --- a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile @@ -1,10 +1,18 @@ +# needs-profiler-support + -include ../tools.mk -# ignore-windows +COMPILE_FLAGS=-Copt-level=3 -Clto=fat -Cprofile-generate="$(TMPDIR)" + +# LLVM doesn't yet support instrumenting binaries that use unwinding on MSVC: +# https://github.com/rust-lang/rust/issues/61002 +# +# Things work fine with -Cpanic=abort though. +ifdef IS_MSVC +COMPILE_FLAGS+= -Cpanic=abort +endif all: -ifeq ($(PROFILER_SUPPORT),1) - $(RUSTC) -Copt-level=3 -Clto=fat -Z pgo-gen="$(TMPDIR)/test.profraw" test.rs + $(RUSTC) $(COMPILE_FLAGS) test.rs $(call RUN,test) || exit 1 - [ -e "$(TMPDIR)/test.profraw" ] || (echo "No .profraw file"; exit 1) -endif + [ -e "$(TMPDIR)"/default_*.profraw ] || (echo "No .profraw file"; exit 1) diff --git a/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile new file mode 100644 index 0000000000000..3fbfeb09eb373 --- /dev/null +++ b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile @@ -0,0 +1,21 @@ +# needs-profiler-support + +-include ../tools.mk + +COMPILE_FLAGS=-O -Ccodegen-units=1 -Cprofile-generate="$(TMPDIR)" + +# LLVM doesn't yet support instrumenting binaries that use unwinding on MSVC: +# https://github.com/rust-lang/rust/issues/61002 +# +# Things work fine with -Cpanic=abort though. +ifdef IS_MSVC +COMPILE_FLAGS+= -Cpanic=abort +endif + +all: + $(RUSTC) $(COMPILE_FLAGS) --emit=llvm-ir test.rs + # We expect symbols starting with "__llvm_profile_". + $(CGREP) "__llvm_profile_" < $(TMPDIR)/test.ll + # We do NOT expect the "__imp_" version of these symbols. + $(CGREP) -v "__imp___llvm_profile_" < $(TMPDIR)/test.ll # 64 bit + $(CGREP) -v "__imp____llvm_profile_" < $(TMPDIR)/test.ll # 32 bit diff --git a/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/test.rs b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/test.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/test.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/src/test/run-make-fulldeps/pgo-gen/Makefile b/src/test/run-make-fulldeps/pgo-gen/Makefile index 1961dff8d783e..3b66427c14c29 100644 --- a/src/test/run-make-fulldeps/pgo-gen/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen/Makefile @@ -1,10 +1,18 @@ +# needs-profiler-support + -include ../tools.mk -# ignore-windows +COMPILE_FLAGS=-g -Cprofile-generate="$(TMPDIR)" + +# LLVM doesn't yet support instrumenting binaries that use unwinding on MSVC: +# https://github.com/rust-lang/rust/issues/61002 +# +# Things work fine with -Cpanic=abort though. +ifdef IS_MSVC +COMPILE_FLAGS+= -Cpanic=abort +endif all: -ifeq ($(PROFILER_SUPPORT),1) - $(RUSTC) -g -Z pgo-gen="$(TMPDIR)/test.profraw" test.rs + $(RUSTC) $(COMPILE_FLAGS) test.rs $(call RUN,test) || exit 1 - [ -e "$(TMPDIR)/test.profraw" ] || (echo "No .profraw file"; exit 1) -endif + [ -e "$(TMPDIR)"/default_*.profraw ] || (echo "No .profraw file"; exit 1) diff --git a/src/test/run-make-fulldeps/pgo-use/Makefile b/src/test/run-make-fulldeps/pgo-use/Makefile new file mode 100644 index 0000000000000..61a73587759fe --- /dev/null +++ b/src/test/run-make-fulldeps/pgo-use/Makefile @@ -0,0 +1,51 @@ +# needs-profiler-support + +-include ../tools.mk + +# This test makes sure that PGO profiling data leads to cold functions being +# marked as `cold` and hot functions with `inlinehint`. +# The test program contains an `if` were actual execution only ever takes the +# `else` branch. Accordingly, we expect the function that is never called to +# be marked as cold. +# +# The program is compiled with `-Copt-level=s` because this setting disables +# LLVM's pre-inlining pass (i.e. a pass that does some inlining before it adds +# the profiling instrumentation). Disabling this pass leads to rather +# predictable IR which we need for this test to be stable. + +COMMON_FLAGS=-Copt-level=s -Ccodegen-units=1 + +# LLVM doesn't support instrumenting binaries that use SEH: +# https://github.com/rust-lang/rust/issues/61002 +# +# Things work fine with -Cpanic=abort though. +ifdef IS_MSVC +COMMON_FLAGS+= -Cpanic=abort +endif + +ifeq ($(UNAME),Darwin) +# macOS does not have the `tac` command, but `tail -r` does the same thing +TAC := tail -r +else +# some other platforms don't support the `-r` flag for `tail`, so use `tac` +TAC := tac +endif + +all: + # Compile the test program with instrumentation + $(RUSTC) $(COMMON_FLAGS) -Cprofile-generate="$(TMPDIR)" main.rs + # Run it in order to generate some profiling data + $(call RUN,main some-argument) || exit 1 + # Postprocess the profiling data so it can be used by the compiler + "$(LLVM_BIN_DIR)"/llvm-profdata merge \ + -o "$(TMPDIR)"/merged.profdata \ + "$(TMPDIR)"/default_*.profraw + # Compile the test program again, making use of the profiling data + $(RUSTC) $(COMMON_FLAGS) -Cprofile-use="$(TMPDIR)"/merged.profdata --emit=llvm-ir main.rs + # Check that the generate IR contains some things that we expect + # + # We feed the file into LLVM FileCheck tool *in reverse* so that we see the + # line with the function name before the line with the function attributes. + # FileCheck only supports checking that something matches on the next line, + # but not if something matches on the previous line. + $(TAC) "$(TMPDIR)"/main.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt diff --git a/src/test/run-make-fulldeps/pgo-use/filecheck-patterns.txt b/src/test/run-make-fulldeps/pgo-use/filecheck-patterns.txt new file mode 100644 index 0000000000000..6da34f88f2a74 --- /dev/null +++ b/src/test/run-make-fulldeps/pgo-use/filecheck-patterns.txt @@ -0,0 +1,11 @@ +# Add a check that the IR contains some expected metadata +CHECK: !{!"ProfileFormat", !"InstrProf"} +CHECK: !"ProfileSummary" + +# Make sure that the hot function is marked with `inlinehint` +CHECK: define {{.*}} @hot_function +CHECK-NEXT: Function Attrs:{{.*}}inlinehint + +# Make sure that the cold function is marked with `cold` +CHECK: define {{.*}} @cold_function +CHECK-NEXT: Function Attrs:{{.*}}cold diff --git a/src/test/run-make-fulldeps/pgo-use/main.rs b/src/test/run-make-fulldeps/pgo-use/main.rs new file mode 100644 index 0000000000000..eb9192c87e6f0 --- /dev/null +++ b/src/test/run-make-fulldeps/pgo-use/main.rs @@ -0,0 +1,23 @@ +#[no_mangle] +pub fn cold_function(c: u8) { + println!("cold {}", c); +} + +#[no_mangle] +pub fn hot_function(c: u8) { + std::env::set_var(format!("var{}", c), format!("hot {}", c)); +} + +fn main() { + let arg = std::env::args().skip(1).next().unwrap(); + + for i in 0 .. 1000_000 { + let some_value = arg.as_bytes()[i % arg.len()]; + if some_value == b'!' { + // This branch is never taken at runtime + cold_function(some_value); + } else { + hot_function(some_value); + } + } +} diff --git a/src/test/run-make-fulldeps/print-target-list/Makefile b/src/test/run-make-fulldeps/print-target-list/Makefile index 144c5ba10cccf..5f10f2aa3b0f4 100644 --- a/src/test/run-make-fulldeps/print-target-list/Makefile +++ b/src/test/run-make-fulldeps/print-target-list/Makefile @@ -2,14 +2,7 @@ # Checks that all the targets returned by `rustc --print target-list` are valid # target specifications -# TODO remove the '*ios*' case when rust-lang/rust#29812 is fixed all: for target in $(shell $(BARE_RUSTC) --print target-list); do \ - case $$target in \ - *ios*) \ - ;; \ - *) \ - $(BARE_RUSTC) --target $$target --print sysroot \ - ;; \ - esac \ + $(BARE_RUSTC) --target $$target --print sysroot; \ done diff --git a/src/test/run-make-fulldeps/profile/Makefile b/src/test/run-make-fulldeps/profile/Makefile index 7300bfc955363..c12712590e48f 100644 --- a/src/test/run-make-fulldeps/profile/Makefile +++ b/src/test/run-make-fulldeps/profile/Makefile @@ -1,9 +1,9 @@ +# needs-profiler-support + -include ../tools.mk all: -ifeq ($(PROFILER_SUPPORT),1) $(RUSTC) -g -Z profile test.rs $(call RUN,test) || exit 1 [ -e "$(TMPDIR)/test.gcno" ] || (echo "No .gcno file"; exit 1) [ -e "$(TMPDIR)/test.gcda" ] || (echo "No .gcda file"; exit 1) -endif diff --git a/src/test/run-make-fulldeps/redundant-libs/Makefile b/src/test/run-make-fulldeps/redundant-libs/Makefile new file mode 100644 index 0000000000000..9486e07d21bf7 --- /dev/null +++ b/src/test/run-make-fulldeps/redundant-libs/Makefile @@ -0,0 +1,27 @@ +-include ../tools.mk + +ifdef IS_WINDOWS +all: +else + +# rustc will remove one of the two redundant references to foo below. Depending +# on which one gets removed, we'll get a linker error on SOME platforms (like +# Linux). On these platforms, when a library is referenced, the linker will +# only pull in the symbols needed _at that point in time_. If a later library +# depends on additional symbols from the library, they will not have been pulled +# in, and you'll get undefined symbols errors. +# +# So in this example, we need to ensure that rustc keeps the _later_ reference +# to foo, and not the former one. +RUSTC_FLAGS = \ + -l static=bar \ + -l foo \ + -l static=baz \ + -l foo \ + -Z print-link-args + +all: $(call DYLIB,foo) $(call STATICLIB,bar) $(call STATICLIB,baz) + $(RUSTC) $(RUSTC_FLAGS) main.rs + $(call RUN,main) + +endif diff --git a/src/test/run-make-fulldeps/redundant-libs/bar.c b/src/test/run-make-fulldeps/redundant-libs/bar.c new file mode 100644 index 0000000000000..e42599986781f --- /dev/null +++ b/src/test/run-make-fulldeps/redundant-libs/bar.c @@ -0,0 +1 @@ +void bar() {} diff --git a/src/test/run-make-fulldeps/redundant-libs/baz.c b/src/test/run-make-fulldeps/redundant-libs/baz.c new file mode 100644 index 0000000000000..a4e2c2b717fdb --- /dev/null +++ b/src/test/run-make-fulldeps/redundant-libs/baz.c @@ -0,0 +1,7 @@ +extern void foo1(); +extern void foo2(); + +void baz() { + foo1(); + foo2(); +} diff --git a/src/test/run-make-fulldeps/redundant-libs/foo.c b/src/test/run-make-fulldeps/redundant-libs/foo.c new file mode 100644 index 0000000000000..339ee86c99eae --- /dev/null +++ b/src/test/run-make-fulldeps/redundant-libs/foo.c @@ -0,0 +1,2 @@ +void foo1() {} +void foo2() {} diff --git a/src/test/run-make-fulldeps/redundant-libs/main.rs b/src/test/run-make-fulldeps/redundant-libs/main.rs new file mode 100644 index 0000000000000..90d185ff51dbd --- /dev/null +++ b/src/test/run-make-fulldeps/redundant-libs/main.rs @@ -0,0 +1,11 @@ +extern "C" { + fn bar(); + fn baz(); +} + +fn main() { + unsafe { + bar(); + baz(); + } +} diff --git a/src/test/run-make-fulldeps/reproducible-build/Makefile b/src/test/run-make-fulldeps/reproducible-build/Makefile index ca76a5e5d77b6..a17ec212cfd58 100644 --- a/src/test/run-make-fulldeps/reproducible-build/Makefile +++ b/src/test/run-make-fulldeps/reproducible-build/Makefile @@ -1,4 +1,8 @@ -include ../tools.mk + +# ignore-musl +# Objects are reproducible but their path is not. + all: \ smoke \ debug \ diff --git a/src/test/run-make-fulldeps/rustdoc-error-lines/Makefile b/src/test/run-make-fulldeps/rustdoc-error-lines/Makefile index e09343aa93790..c9d41f0ec3b78 100644 --- a/src/test/run-make-fulldeps/rustdoc-error-lines/Makefile +++ b/src/test/run-make-fulldeps/rustdoc-error-lines/Makefile @@ -5,4 +5,9 @@ all: $(RUSTDOC) --test input.rs > $(TMPDIR)/output || true + $(CGREP) 'input.rs - foo (line 5)' < $(TMPDIR)/output $(CGREP) 'input.rs:7:15' < $(TMPDIR)/output + $(CGREP) 'input.rs - bar (line 15)' < $(TMPDIR)/output + $(CGREP) 'input.rs:17:15' < $(TMPDIR)/output + $(CGREP) 'input.rs - bar (line 24)' < $(TMPDIR)/output + $(CGREP) 'input.rs:26:15' < $(TMPDIR)/output diff --git a/src/test/run-make-fulldeps/rustdoc-error-lines/input.rs b/src/test/run-make-fulldeps/rustdoc-error-lines/input.rs index 7b07f38f25948..2d29fa89110bb 100644 --- a/src/test/run-make-fulldeps/rustdoc-error-lines/input.rs +++ b/src/test/run-make-fulldeps/rustdoc-error-lines/input.rs @@ -9,3 +9,20 @@ pub fn foo() { } + +/// Add some text around the test... +/// +/// ```rust +/// #![feature(nll)] +/// let x: char = 1; +/// ``` +/// +/// ...to make sure that the line number is still correct. +/// +/// Let's also add a second test in the same doc comment. +/// +/// ```rust +/// #![feature(nll)] +/// let x: char = 1; +/// ``` +pub fn bar() {} diff --git a/src/test/run-make-fulldeps/sanitizer-address/Makefile b/src/test/run-make-fulldeps/sanitizer-address/Makefile index 207615bfbd5c6..51d8a4a947adc 100644 --- a/src/test/run-make-fulldeps/sanitizer-address/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-address/Makefile @@ -1,3 +1,5 @@ +# needs-sanitizer-support + -include ../tools.mk LOG := $(TMPDIR)/log.txt @@ -5,11 +7,9 @@ LOG := $(TMPDIR)/log.txt # NOTE the address sanitizer only supports x86_64 linux and macOS ifeq ($(TARGET),x86_64-apple-darwin) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) EXTRA_RUSTFLAG=-C rpath else ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) # Apparently there are very specific Linux kernels, notably the one that's # currently on Travis CI, which contain a buggy commit that triggers failures in @@ -23,7 +23,5 @@ endif endif all: -ifeq ($(ASAN_SUPPORT),1) $(RUSTC) -g -Z sanitizer=address -Z print-link-args $(EXTRA_RUSTFLAG) overflow.rs | $(CGREP) librustc_asan $(TMPDIR)/overflow 2>&1 | $(CGREP) stack-buffer-overflow -endif diff --git a/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile index 4b7fece36d92a..35317dca1e824 100644 --- a/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile @@ -1,3 +1,7 @@ +# needs-sanitizer-support +# only-x86_64 +# only-linux + -include ../tools.mk LOG := $(TMPDIR)/log.txt @@ -7,16 +11,10 @@ LOG := $(TMPDIR)/log.txt # are compiled with address sanitizer, and we assert that a fault in the cdylib # is correctly detected. -ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) - # See comment in sanitizer-address/Makefile for why this is here EXTRA_RUSTFLAG=-C relocation-model=dynamic-no-pic -endif all: -ifeq ($(ASAN_SUPPORT),1) $(RUSTC) -g -Z sanitizer=address --crate-type cdylib --target $(TARGET) $(EXTRA_RUSTFLAG) library.rs $(RUSTC) -g -Z sanitizer=address --crate-type bin --target $(TARGET) $(EXTRA_RUSTFLAG) -llibrary program.rs LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | $(CGREP) stack-buffer-overflow -endif diff --git a/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile index 97f6172142224..24d2ebd8f48aa 100644 --- a/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile @@ -1,3 +1,7 @@ +# needs-sanitizer-support +# only-x86_64 +# only-linux + -include ../tools.mk LOG := $(TMPDIR)/log.txt @@ -7,16 +11,10 @@ LOG := $(TMPDIR)/log.txt # are compiled with address sanitizer, and we assert that a fault in the dylib # is correctly detected. -ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) - # See comment in sanitizer-address/Makefile for why this is here EXTRA_RUSTFLAG=-C relocation-model=dynamic-no-pic -endif all: -ifeq ($(ASAN_SUPPORT),1) $(RUSTC) -g -Z sanitizer=address --crate-type dylib --target $(TARGET) $(EXTRA_RUSTFLAG) library.rs $(RUSTC) -g -Z sanitizer=address --crate-type bin --target $(TARGET) $(EXTRA_RUSTFLAG) -llibrary program.rs LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | $(CGREP) stack-buffer-overflow -endif diff --git a/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile b/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile index dc37c0d0bc946..9581ac565ea02 100644 --- a/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile @@ -1,18 +1,16 @@ +# needs-sanitizer-support + -include ../tools.mk # NOTE the address sanitizer only supports x86_64 linux and macOS ifeq ($(TARGET),x86_64-apple-darwin) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) EXTRA_RUSTFLAG=-C rpath else ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) EXTRA_RUSTFLAG= endif endif all: -ifeq ($(ASAN_SUPPORT),1) $(RUSTC) -Z sanitizer=address --crate-type proc-macro --target $(TARGET) hello.rs 2>&1 | $(CGREP) '-Z sanitizer' -endif diff --git a/src/test/run-make-fulldeps/sanitizer-leak/Makefile b/src/test/run-make-fulldeps/sanitizer-leak/Makefile index 0f3c18f9293f5..101e8272ab91e 100644 --- a/src/test/run-make-fulldeps/sanitizer-leak/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-leak/Makefile @@ -1,12 +1,11 @@ -include ../tools.mk +# needs-sanitizer-support # only-linux # only-x86_64 # ignore-test # FIXME(#46126) ThinLTO for libstd broke this test all: -ifdef SANITIZER_SUPPORT $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | $(CGREP) librustc_lsan $(TMPDIR)/leak 2>&1 | $(CGREP) 'detected memory leaks' -endif diff --git a/src/test/run-make-fulldeps/sanitizer-memory/Makefile b/src/test/run-make-fulldeps/sanitizer-memory/Makefile index 718d9637ea06d..b3376f8a72358 100644 --- a/src/test/run-make-fulldeps/sanitizer-memory/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-memory/Makefile @@ -1,10 +1,9 @@ -include ../tools.mk +# needs-sanitizer-support # only-linux # only-x86_64 all: -ifdef SANITIZER_SUPPORT $(RUSTC) -g -Z sanitizer=memory -Z print-link-args uninit.rs | $(CGREP) librustc_msan $(TMPDIR)/uninit 2>&1 | $(CGREP) use-of-uninitialized-value -endif diff --git a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile index 2b444d667bfa3..200dc1be4dee6 100644 --- a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile @@ -1,18 +1,15 @@ +# needs-sanitizer-support +# only-x86_64 +# only-linux + -include ../tools.mk # This test builds a staticlib, then an executable that links to it. -# The staticlib and executable both are compiled with address sanitizer, +# The staticlib and executable both are compiled with address sanitizer, # and we assert that a fault in the staticlib is correctly detected. -ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) -EXTRA_RUSTFLAG= -endif - all: -ifeq ($(ASAN_SUPPORT),1) $(RUSTC) -g -Z sanitizer=address --crate-type staticlib --target $(TARGET) library.rs $(CC) program.c $(call STATICLIB,library) $(call OUT_EXE,program) $(EXTRACFLAGS) $(EXTRACXXFLAGS) LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | $(CGREP) stack-buffer-overflow -endif diff --git a/src/test/run-make-fulldeps/sanitizer-staticlib-link/program.c b/src/test/run-make-fulldeps/sanitizer-staticlib-link/program.c index abd5d508e7295..a6d3bcdc5ac9d 100644 --- a/src/test/run-make-fulldeps/sanitizer-staticlib-link/program.c +++ b/src/test/run-make-fulldeps/sanitizer-staticlib-link/program.c @@ -5,4 +5,3 @@ int main() { overflow(); return 0; } - diff --git a/src/test/run-make-fulldeps/stable-symbol-names/Makefile b/src/test/run-make-fulldeps/stable-symbol-names/Makefile index 3cbc5593ac0a2..451af809b2223 100644 --- a/src/test/run-make-fulldeps/stable-symbol-names/Makefile +++ b/src/test/run-make-fulldeps/stable-symbol-names/Makefile @@ -3,14 +3,15 @@ # The following command will: # 1. dump the symbols of a library using `nm` # 2. extract only those lines that we are interested in via `grep` -# 3. from those lines, extract just the symbol name via `sed` -# (symbol names always start with "_ZN" and end with "E") +# 3. from those lines, extract just the symbol name via `sed`, which: +# * always starts with "_ZN" and ends with "E" (`legacy` mangling) +# * always starts with "_R" (`v0` mangling) # 4. sort those symbol names for deterministic comparison # 5. write the result into a file dump-symbols = nm "$(TMPDIR)/lib$(1).rlib" \ | grep -E "$(2)" \ - | sed "s/.*\(_ZN.*E\).*/\1/" \ + | sed -E "s/.*(_ZN.*E|_R[a-zA-Z0-9_]*).*/\1/" \ | sort \ > "$(TMPDIR)/$(1)$(3).nm" diff --git a/src/test/run-make-fulldeps/stable-symbol-names/stable-symbol-names2.rs b/src/test/run-make-fulldeps/stable-symbol-names/stable-symbol-names2.rs index 6df74d2491b7d..33df9d6c68988 100644 --- a/src/test/run-make-fulldeps/stable-symbol-names/stable-symbol-names2.rs +++ b/src/test/run-make-fulldeps/stable-symbol-names/stable-symbol-names2.rs @@ -15,4 +15,3 @@ pub fn trait_impl_test_function() { use stable_symbol_names1::*; Bar::generic_method::(); } - diff --git a/src/test/run-make-fulldeps/symbol-visibility/Makefile b/src/test/run-make-fulldeps/symbol-visibility/Makefile index d99470e30d7ee..7901866015bf2 100644 --- a/src/test/run-make-fulldeps/symbol-visibility/Makefile +++ b/src/test/run-make-fulldeps/symbol-visibility/Makefile @@ -19,6 +19,9 @@ EXE_NAME=an_executable COMBINED_CDYLIB_NAME=libcombined_rlib_dylib.dylib endif +# `grep` regex for symbols produced by either `legacy` or `v0` mangling +RE_ANY_RUST_SYMBOL="_ZN.*h.*E\|_R[a-zA-Z0-9_]+" + all: $(RUSTC) -Zshare-generics=no an_rlib.rs $(RUSTC) -Zshare-generics=no a_cdylib.rs @@ -31,20 +34,20 @@ all: # Check that a cdylib exports the public #[no_mangle] functions of dependencies [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] # Check that a cdylib DOES NOT export any public Rust functions - [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ] # Check that a Rust dylib exports its monomorphic functions [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rust_dylib)" -eq "1" ] # Check that a Rust dylib does not export generics if -Zshare-generics=no - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rust_dylib.*E)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rust_dylib)" -eq "0" ] # Check that a Rust dylib exports the monomorphic functions from its dependencies [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ] # Check that a Rust dylib does not export generics if -Zshare-generics=no - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rlib.*E)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rlib)" -eq "0" ] # Check that an executable does not export any dynamic symbols [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ] @@ -58,7 +61,7 @@ all: # Check that a cdylib exports the public #[no_mangle] functions of dependencies [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] # Check that a cdylib DOES NOT export any public Rust functions - [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ] $(RUSTC) -Zshare-generics=yes an_rlib.rs @@ -71,17 +74,17 @@ all: # Check that a cdylib exports the public #[no_mangle] functions of dependencies [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] # Check that a cdylib DOES NOT export any public Rust functions - [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ] # Check that a Rust dylib exports its monomorphic functions, including generics this time [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rust_dylib.*E)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rust_dylib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rust_dylib)" -eq "1" ] # Check that a Rust dylib exports the monomorphic functions from its dependencies [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rlib.*E)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rlib)" -eq "1" ] # Check that an executable does not export any dynamic symbols [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ] diff --git a/src/test/run-make-fulldeps/sysroot-crates-are-unstable/test.py b/src/test/run-make-fulldeps/sysroot-crates-are-unstable/test.py index e0fa4e8f5debe..855b6421cf822 100644 --- a/src/test/run-make-fulldeps/sysroot-crates-are-unstable/test.py +++ b/src/test/run-make-fulldeps/sysroot-crates-are-unstable/test.py @@ -7,8 +7,8 @@ # This is a whitelist of files which are stable crates or simply are not crates, # we don't check for the instability of these crates as they're all stable! -STABLE_CRATES = ['std', 'core', 'proc_macro', 'rsbegin.o', 'rsend.o', 'dllcrt2.o', 'crt2.o', - 'clang_rt'] +STABLE_CRATES = ['std', 'alloc', 'core', 'proc_macro', + 'rsbegin.o', 'rsend.o', 'dllcrt2.o', 'crt2.o', 'clang_rt'] def convert_to_string(s): diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk index 79399281804fb..3b4df73cdfd6d 100644 --- a/src/test/run-make-fulldeps/tools.mk +++ b/src/test/run-make-fulldeps/tools.mk @@ -47,6 +47,7 @@ DYLIB = $(TMPDIR)/$(1).dll STATICLIB = $(TMPDIR)/$(1).lib STATICLIB_GLOB = $(1)*.lib BIN = $(1).exe +LLVM_FILECHECK := $(shell cygpath -u "$(LLVM_FILECHECK)") else RUN = $(TARGET_RPATH_ENV) $(RUN_BINFILE) FAIL = $(TARGET_RPATH_ENV) $(RUN_BINFILE) && exit 1 || exit 0 @@ -87,10 +88,6 @@ else ifeq ($(UNAME),FreeBSD) EXTRACFLAGS := -lm -lpthread -lgcc_s else -ifeq ($(UNAME),Bitrig) - EXTRACFLAGS := -lm -lpthread - EXTRACXXFLAGS := -lc++ -lc++abi -else ifeq ($(UNAME),SunOS) EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv else @@ -105,7 +102,6 @@ endif endif endif endif -endif REMOVE_DYLIBS = rm $(TMPDIR)/$(call DYLIB_GLOB,$(1)) REMOVE_RLIBS = rm $(TMPDIR)/$(call RLIB_GLOB,$(1)) diff --git a/src/test/run-make-fulldeps/treat-err-as-bug/Makefile b/src/test/run-make-fulldeps/treat-err-as-bug/Makefile index f99e4611174ca..9b3bcef2faf32 100644 --- a/src/test/run-make-fulldeps/treat-err-as-bug/Makefile +++ b/src/test/run-make-fulldeps/treat-err-as-bug/Makefile @@ -2,4 +2,4 @@ all: $(RUSTC) err.rs -Z treat-err-as-bug 2>&1 \ - | $(CGREP) "panicked at 'encountered error with \`-Z treat_err_as_bug'" + | $(CGREP) "panicked at 'aborting due to \`-Z treat-err-as-bug=1\`'" diff --git a/src/test/run-make-fulldeps/use-extern-for-plugins/Makefile b/src/test/run-make-fulldeps/use-extern-for-plugins/Makefile index 3976da3113190..838b1a2719b9f 100644 --- a/src/test/run-make-fulldeps/use-extern-for-plugins/Makefile +++ b/src/test/run-make-fulldeps/use-extern-for-plugins/Makefile @@ -2,7 +2,6 @@ # ignore-freebsd # ignore-openbsd -# ignore-bitrig # ignore-sunos HOST := $(shell $(RUSTC) -vV | grep 'host:' | sed 's/host: //') diff --git a/src/test/run-make-fulldeps/windows-subsystem/console.rs b/src/test/run-make-fulldeps/windows-subsystem/console.rs index 4a2e9bb3c5cf0..61a92eb6a9db7 100644 --- a/src/test/run-make-fulldeps/windows-subsystem/console.rs +++ b/src/test/run-make-fulldeps/windows-subsystem/console.rs @@ -1,4 +1,3 @@ #![windows_subsystem = "console"] fn main() {} - diff --git a/src/test/run-make/nvptx-binary-crate/Makefile b/src/test/run-make/nvptx-binary-crate/Makefile deleted file mode 100644 index 2c211b5c78507..0000000000000 --- a/src/test/run-make/nvptx-binary-crate/Makefile +++ /dev/null @@ -1,12 +0,0 @@ --include ../../run-make-fulldeps/tools.mk - -ifeq ($(TARGET),nvptx64-nvidia-cuda) -all: - $(RUSTC) main.rs --crate-type="bin" --target $(TARGET) -O -C link-arg=--arch=sm_60 -o $(TMPDIR)/main.link_arg.ptx - $(RUSTC) main.rs --crate-type="bin" --target $(TARGET) -O -C target-cpu=sm_60 -o $(TMPDIR)/main.target_cpu.ptx - - FileCheck main.rs --input-file $(TMPDIR)/main.link_arg.ptx - FileCheck main.rs --input-file $(TMPDIR)/main.target_cpu.ptx -else -all: -endif diff --git a/src/test/run-make/nvptx-binary-crate/main.rs b/src/test/run-make/nvptx-binary-crate/main.rs deleted file mode 100644 index 826bc3a47bbd6..0000000000000 --- a/src/test/run-make/nvptx-binary-crate/main.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![no_std] -#![no_main] -#![deny(warnings)] -#![feature(abi_ptx, core_intrinsics)] - -// Check the overriden CUDA arch. -// CHECK: .target sm_60 -// CHECK: .address_size 64 - -// Verify that no extra function declarations are present. -// CHECK-NOT: .func - -// CHECK-LABEL: .visible .entry top_kernel( -#[no_mangle] -pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { - // CHECK: add.s32 %{{r[0-9]+}}, %{{r[0-9]+}}, 5; - *b = *a + 5; -} - -// Verify that no extra function definitions are there. -// CHECK-NOT: .func -// CHECK-NOT: .entry - -#[panic_handler] -unsafe fn breakpoint_panic_handler(_: &::core::panic::PanicInfo) -> ! { - core::intrinsics::breakpoint(); - core::hint::unreachable_unchecked(); -} diff --git a/src/test/run-make/nvptx-dylib-crate/Makefile b/src/test/run-make/nvptx-dylib-crate/Makefile deleted file mode 100644 index 7284e9d1a7c99..0000000000000 --- a/src/test/run-make/nvptx-dylib-crate/Makefile +++ /dev/null @@ -1,10 +0,0 @@ --include ../../run-make-fulldeps/tools.mk - -ifeq ($(TARGET),nvptx64-nvidia-cuda) -all: - $(RUSTC) dep.rs --crate-type="rlib" --target $(TARGET) - $(RUSTC) kernel.rs --crate-type="cdylib" -O --target $(TARGET) - FileCheck kernel.rs --input-file $(TMPDIR)/kernel.ptx -else -all: -endif diff --git a/src/test/run-make/nvptx-dylib-crate/kernel.rs b/src/test/run-make/nvptx-dylib-crate/kernel.rs deleted file mode 100644 index 63fd6b063dd8c..0000000000000 --- a/src/test/run-make/nvptx-dylib-crate/kernel.rs +++ /dev/null @@ -1,59 +0,0 @@ -#![no_std] -#![deny(warnings)] -#![feature(abi_ptx, core_intrinsics)] - -extern crate dep; - -// Verify the default CUDA arch. -// CHECK: .target sm_30 -// CHECK: .address_size 64 - -// Make sure declarations are there. -// CHECK: .func (.param .b32 func_retval0) wrapping_external_fn -// CHECK: .func (.param .b32 func_retval0) panicking_external_fn -// CHECK: .func [[PANIC_HANDLER:_ZN4core9panicking5panic[a-zA-Z0-9]+]] - -// CHECK-LABEL: .visible .entry top_kernel( -#[no_mangle] -pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { - // CHECK: call.uni (retval0), - // CHECK-NEXT: wrapping_external_fn - // CHECK: ld.param.b32 %[[LHS:r[0-9]+]], [retval0+0]; - let lhs = dep::wrapping_external_fn(*a); - - // CHECK: call.uni (retval0), - // CHECK-NEXT: panicking_external_fn - // CHECK: ld.param.b32 %[[RHS:r[0-9]+]], [retval0+0]; - let rhs = dep::panicking_external_fn(*a); - - // CHECK: add.s32 %[[RES:r[0-9]+]], %[[RHS]], %[[LHS]]; - // CHECK: st.global.u32 [%{{rd[0-9]+}}], %[[RES]]; - *b = lhs + rhs; -} - -// Verify that external function bodies are available. -// CHECK-LABEL: .func (.param .b32 func_retval0) wrapping_external_fn -// CHECK: { -// CHECK: st.param.b32 [func_retval0+0], %{{r[0-9]+}}; -// CHECK: } - -// Also verify panic behavior. -// CHECK-LABEL: .func (.param .b32 func_retval0) panicking_external_fn -// CHECK: { -// CHECK: %{{p[0-9]+}} bra [[PANIC_LABEL:[a-zA-Z0-9_]+]]; -// CHECK: [[PANIC_LABEL]]: -// CHECK: call.uni -// CHECK: [[PANIC_HANDLER]] -// CHECK: } - -// Verify whether out dummy panic formatter has a correct body. -// CHECK: .func [[PANIC_FMT:_ZN4core9panicking9panic_fmt[a-zA-Z0-9]+]]() -// CHECK: { -// CHECK: trap; -// CHECK: } - -#[panic_handler] -unsafe fn breakpoint_panic_handler(_: &::core::panic::PanicInfo) -> ! { - core::intrinsics::breakpoint(); - core::hint::unreachable_unchecked(); -} diff --git a/src/test/run-make/nvptx-emit-asm/Makefile b/src/test/run-make/nvptx-emit-asm/Makefile deleted file mode 100644 index e03601878bdee..0000000000000 --- a/src/test/run-make/nvptx-emit-asm/Makefile +++ /dev/null @@ -1,9 +0,0 @@ --include ../../run-make-fulldeps/tools.mk - -ifeq ($(TARGET),nvptx64-nvidia-cuda) -all: - $(RUSTC) kernel.rs --crate-type="rlib" --emit asm,llvm-ir -O --target $(TARGET) - FileCheck kernel.rs --input-file $(TMPDIR)/kernel.s -else -all: -endif diff --git a/src/test/run-make/nvptx-emit-asm/kernel.rs b/src/test/run-make/nvptx-emit-asm/kernel.rs deleted file mode 100644 index b71e18d910391..0000000000000 --- a/src/test/run-make/nvptx-emit-asm/kernel.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![no_std] -#![deny(warnings)] -#![feature(abi_ptx)] - -// Verify the default CUDA arch. -// CHECK: .target sm_30 -// CHECK: .address_size 64 - -// Verify function name doesn't contain unacceaptable characters. -// CHECK: .func (.param .b32 func_retval0) [[IMPL_FN:_ZN[a-zA-Z0-9$_]+square[a-zA-Z0-9$_]+]] - -// CHECK-LABEL: .visible .entry top_kernel( -#[no_mangle] -pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { - // CHECK: call.uni (retval0), - // CHECK-NEXT: [[IMPL_FN]] - *b = deep::private::MyStruct::new(*a).square(); -} - -pub mod deep { - pub mod private { - pub struct MyStruct(T); - - impl MyStruct { - pub fn new(a: u32) -> Self { - MyStruct(a) - } - - #[inline(never)] - pub fn square(&self) -> u32 { - self.0.wrapping_mul(self.0) - } - } - } -} - -// Verify that external function bodies are available. -// CHECK: .func (.param .b32 func_retval0) [[IMPL_FN]] -// CHECK: { -// CHECK: mul.lo.s32 %{{r[0-9]+}}, %{{r[0-9]+}}, %{{r[0-9]+}} -// CHECK: } diff --git a/src/test/run-make/rustc-macro-dep-files/Makefile b/src/test/run-make/rustc-macro-dep-files/Makefile index 0420a389168f1..a08a63fb44bf5 100644 --- a/src/test/run-make/rustc-macro-dep-files/Makefile +++ b/src/test/run-make/rustc-macro-dep-files/Makefile @@ -2,7 +2,10 @@ # FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC` # instead of hardcoding them everywhere they're needed. +ifeq ($(IS_MUSL_HOST),1) +ADDITIONAL_ARGS := $(RUSTFLAGS) +endif all: - $(BARE_RUSTC) foo.rs --out-dir $(TMPDIR) + $(BARE_RUSTC) $(ADDITIONAL_ARGS) foo.rs --out-dir $(TMPDIR) $(RUSTC) bar.rs --target $(TARGET) --emit dep-info $(CGREP) -v "proc-macro source" < $(TMPDIR)/bar.d diff --git a/src/test/run-make/wasm-export-all-symbols/Makefile b/src/test/run-make/wasm-export-all-symbols/Makefile index 039481215f0a6..15403d8d4109d 100644 --- a/src/test/run-make/wasm-export-all-symbols/Makefile +++ b/src/test/run-make/wasm-export-all-symbols/Makefile @@ -6,8 +6,14 @@ all: $(RUSTC) bar.rs --target wasm32-unknown-unknown $(RUSTC) foo.rs --target wasm32-unknown-unknown $(NODE) verify.js $(TMPDIR)/foo.wasm + $(RUSTC) main.rs --target wasm32-unknown-unknown + $(NODE) verify.js $(TMPDIR)/main.wasm $(RUSTC) bar.rs --target wasm32-unknown-unknown -O $(RUSTC) foo.rs --target wasm32-unknown-unknown -O $(NODE) verify.js $(TMPDIR)/foo.wasm + $(RUSTC) main.rs --target wasm32-unknown-unknown -O + $(NODE) verify.js $(TMPDIR)/main.wasm $(RUSTC) foo.rs --target wasm32-unknown-unknown -C lto $(NODE) verify.js $(TMPDIR)/foo.wasm + $(RUSTC) main.rs --target wasm32-unknown-unknown -C lto + $(NODE) verify.js $(TMPDIR)/main.wasm diff --git a/src/test/run-make/wasm-export-all-symbols/main.rs b/src/test/run-make/wasm-export-all-symbols/main.rs new file mode 100644 index 0000000000000..0edda7d7b8842 --- /dev/null +++ b/src/test/run-make/wasm-export-all-symbols/main.rs @@ -0,0 +1,3 @@ +extern crate bar; + +fn main() {} diff --git a/src/test/run-make/wasm-export-all-symbols/verify.js b/src/test/run-make/wasm-export-all-symbols/verify.js index 0f56fa45c223d..7b6fc7a45682b 100644 --- a/src/test/run-make/wasm-export-all-symbols/verify.js +++ b/src/test/run-make/wasm-export-all-symbols/verify.js @@ -16,7 +16,13 @@ for (const entry of list) { nexports += 1; } -if (nexports != 1) - throw new Error("should only have one function export"); if (my_exports.foo === undefined) throw new Error("`foo` wasn't defined"); + +if (my_exports.main === undefined) { + if (nexports != 1) + throw new Error("should only have one function export"); +} else { + if (nexports != 2) + throw new Error("should only have two function exports"); +} diff --git a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs index d32fafd215c07..49e137549c049 100644 --- a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs +++ b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs @@ -105,7 +105,7 @@ fn reject_stmt_parse(es: &str) { } fn main() { - syntax::with_globals(|| run()); + syntax::with_default_globals(|| run()); } fn run() { diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs deleted file mode 100644 index 4d6ff47a3ee91..0000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs +++ /dev/null @@ -1,71 +0,0 @@ -// force-host - -#![feature(plugin_registrar, rustc_private)] - -extern crate syntax; -extern crate syntax_ext; -extern crate rustc_plugin; - -use syntax_ext::deriving; -use deriving::generic::*; -use deriving::generic::ty::*; - -use rustc_plugin::Registry; -use syntax::ast::*; -use syntax::source_map::Span; -use syntax::ext::base::*; -use syntax::ext::build::AstBuilder; -use syntax::symbol::Symbol; -use syntax::ptr::P; - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension(Symbol::intern("derive_CustomPartialEq"), - MultiDecorator(Box::new(expand_deriving_partial_eq))); -} - -fn expand_deriving_partial_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) { - // structures are equal if all fields are equal, and non equal, if - // any fields are not equal or if the enum variants are different - fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_fold(true, - |cx, span, subexpr, self_f, other_fs| { - let other_f = (other_fs.len(), other_fs.get(0)).1.unwrap(); - let eq = cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()); - cx.expr_binary(span, BinOpKind::And, subexpr, eq) - }, - cx.expr_bool(span, true), - Box::new(|cx, span, _, _| cx.expr_bool(span, false)), - cx, - span, - substr) - } - - let inline = cx.meta_word(span, Symbol::intern("inline")); - let attrs = vec![cx.attribute(span, inline)]; - let methods = vec![MethodDef { - name: "eq", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![(borrowed_self(), "other")], - ret_ty: Literal(deriving::generic::ty::Path::new_local("bool")), - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(cs_eq)), - }]; - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: deriving::generic::ty::Path::new(vec!["cmp", "PartialEq"]), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - supports_unions: false, - methods: methods, - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs deleted file mode 100644 index 874a0ec7c13fb..0000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs +++ /dev/null @@ -1,76 +0,0 @@ -// force-host - -#![feature(plugin_registrar)] -#![feature(box_syntax)] -#![feature(rustc_private)] - -extern crate syntax; -extern crate syntax_ext; -extern crate syntax_pos; -extern crate rustc; -extern crate rustc_plugin; - -use syntax::ast; -use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable}; -use syntax::ext::build::AstBuilder; -use syntax::symbol::Symbol; -use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure}; -use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self}; -use syntax_pos::Span; -use rustc_plugin::Registry; - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension( - Symbol::intern("derive_TotalSum"), - MultiDecorator(box expand)); - - reg.register_syntax_extension( - Symbol::intern("derive_Nothing"), - MultiDecorator(box noop)); -} - -fn noop(_: &mut ExtCtxt, _: Span, _: &ast::MetaItem, _: &Annotatable, _: &mut FnMut(Annotatable)) {} - -fn expand(cx: &mut ExtCtxt, - span: Span, - mitem: &ast::MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) { - let trait_def = TraitDef { - span: span, - attributes: vec![], - path: Path::new_local("TotalSum"), - additional_bounds: vec![], - generics: LifetimeBounds::empty(), - associated_types: vec![], - is_unsafe: false, - supports_unions: false, - methods: vec![ - MethodDef { - name: "total_sum", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![], - ret_ty: Literal(Path::new_local("isize")), - attributes: vec![], - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(box |cx, span, substr| { - let zero = cx.expr_isize(span, 0); - cs_fold(false, - |cx, span, subexpr, field, _| { - cx.expr_binary(span, ast::BinOpKind::Add, subexpr, - cx.expr_method_call(span, field, - ast::Ident::from_str("total_sum"), vec![])) - }, - zero, - box |cx, span, _, _| { cx.span_bug(span, "wtf??"); }, - cx, span, substr) - }), - }, - ], - }; - - trait_def.expand(cx, mitem, item, push) -} diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs deleted file mode 100644 index 699972c9a85bd..0000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs +++ /dev/null @@ -1,84 +0,0 @@ -// force-host - -#![feature(plugin_registrar)] -#![feature(box_syntax)] -#![feature(rustc_private)] - -extern crate syntax; -extern crate syntax_ext; -extern crate syntax_pos; -extern crate rustc; -extern crate rustc_plugin; - -use syntax::ast; -use syntax::attr; -use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable}; -use syntax::ext::build::AstBuilder; -use syntax::symbol::Symbol; -use syntax::ptr::P; -use syntax_ext::deriving::generic::{TraitDef, MethodDef, combine_substructure}; -use syntax_ext::deriving::generic::{Substructure, Struct, EnumMatching}; -use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self}; -use syntax_pos::Span; -use rustc_plugin::Registry; - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension( - Symbol::intern("rustc_derive_TotalSum"), - MultiDecorator(box expand)); -} - -fn expand(cx: &mut ExtCtxt, - span: Span, - mitem: &ast::MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) { - let trait_def = TraitDef { - span: span, - attributes: vec![], - path: Path::new_local("TotalSum"), - additional_bounds: vec![], - generics: LifetimeBounds::empty(), - associated_types: vec![], - is_unsafe: false, - supports_unions: false, - methods: vec![ - MethodDef { - name: "total_sum", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![], - ret_ty: Literal(Path::new_local("isize")), - attributes: vec![], - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(totalsum_substructure)), - }, - ], - }; - - trait_def.expand(cx, mitem, item, push) -} - -// Mostly copied from syntax::ext::deriving::hash -/// Defines how the implementation for `trace()` is to be generated -fn totalsum_substructure(cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure) -> P { - let fields = match *substr.fields { - Struct(_, ref fs) | EnumMatching(.., ref fs) => fs, - _ => cx.span_bug(trait_span, "impossible substructure") - }; - - fields.iter().fold(cx.expr_isize(trait_span, 0), |acc, ref item| { - if attr::contains_name(&item.attrs, "ignore") { - acc - } else { - cx.expr_binary(item.span, ast::BinOpKind::Add, acc, - cx.expr_method_call(item.span, - item.self_.clone(), - substr.method_ident, - Vec::new())) - } - }) -} diff --git a/src/test/run-pass-fulldeps/auxiliary/issue_24106.rs b/src/test/run-pass-fulldeps/auxiliary/issue-24106.rs similarity index 100% rename from src/test/run-pass-fulldeps/auxiliary/issue_24106.rs rename to src/test/run-pass-fulldeps/auxiliary/issue-24106.rs diff --git a/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs index 09aa106ebbd9f..64b795af9267f 100644 --- a/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs @@ -23,24 +23,17 @@ use syntax::{ast, source_map}; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box MissingWhitelistedAttrPass); - reg.register_attribute("whitelisted_attr".to_string(), Whitelisted); + reg.register_attribute(Symbol::intern("whitelisted_attr"), Whitelisted); } -declare_lint!(MISSING_WHITELISTED_ATTR, Deny, - "Checks for missing `whitelisted_attr` attribute"); - -struct MissingWhitelistedAttrPass; - -impl LintPass for MissingWhitelistedAttrPass { - fn name(&self) -> &'static str { - "MissingWhitelistedAttrPass" - } - - fn get_lints(&self) -> LintArray { - lint_array!(MISSING_WHITELISTED_ATTR) - } +declare_lint! { + MISSING_WHITELISTED_ATTR, + Deny, + "Checks for missing `whitelisted_attr` attribute" } +declare_lint_pass!(MissingWhitelistedAttrPass => [MISSING_WHITELISTED_ATTR]); + impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingWhitelistedAttrPass { fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, @@ -50,12 +43,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingWhitelistedAttrPass { span: source_map::Span, id: hir::HirId) { - let item = match cx.tcx.hir().get_by_hir_id(id) { + let item = match cx.tcx.hir().get(id) { Node::Item(item) => item, - _ => cx.tcx.hir().expect_item_by_hir_id(cx.tcx.hir().get_parent_item(id)), + _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id)), }; - if !attr::contains_name(&item.attrs, "whitelisted_attr") { + if !attr::contains_name(&item.attrs, Symbol::intern("whitelisted_attr")) { cx.span_lint(MISSING_WHITELISTED_ATTR, span, "Missing 'whitelisted_attr' attribute"); } diff --git a/src/test/run-pass-fulldeps/auxiliary/lint-for-crate.rs b/src/test/run-pass-fulldeps/auxiliary/lint-for-crate.rs new file mode 100644 index 0000000000000..8c7bd7222e73c --- /dev/null +++ b/src/test/run-pass-fulldeps/auxiliary/lint-for-crate.rs @@ -0,0 +1,73 @@ +// force-host + +#![feature(plugin_registrar, rustc_private)] +#![feature(box_syntax)] + +#[macro_use] extern crate rustc; +extern crate rustc_plugin; +extern crate syntax; + +use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; +use rustc_plugin::Registry; +use rustc::hir; +use syntax::attr; +use syntax::symbol::Symbol; + +macro_rules! fake_lint_pass { + ($struct:ident, $lints:expr, $($attr:expr),*) => { + struct $struct; + + impl LintPass for $struct { + fn name(&self) -> &'static str { + stringify!($struct) + } + + fn get_lints(&self) -> LintArray { + $lints + } + } + + impl<'a, 'tcx> LateLintPass<'a, 'tcx> for $struct { + fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { + $( + if !attr::contains_name(&krate.attrs, $attr) { + cx.span_lint(CRATE_NOT_OKAY, krate.span, + &format!("crate is not marked with #![{}]", $attr)); + } + )* + } + } + + } +} + +declare_lint!(CRATE_NOT_OKAY, Warn, "crate not marked with #![crate_okay]"); +declare_lint!(CRATE_NOT_RED, Warn, "crate not marked with #![crate_red]"); +declare_lint!(CRATE_NOT_BLUE, Warn, "crate not marked with #![crate_blue]"); +declare_lint!(CRATE_NOT_GREY, Warn, "crate not marked with #![crate_grey]"); +declare_lint!(CRATE_NOT_GREEN, Warn, "crate not marked with #![crate_green]"); + +fake_lint_pass! { + PassOkay, + lint_array!(CRATE_NOT_OKAY), // Single lint + Symbol::intern("rustc_crate_okay") +} + +fake_lint_pass! { + PassRedBlue, + lint_array!(CRATE_NOT_RED, CRATE_NOT_BLUE), // Multiple lints + Symbol::intern("rustc_crate_red"), Symbol::intern("rustc_crate_blue") +} + +fake_lint_pass! { + PassGreyGreen, + lint_array!(CRATE_NOT_GREY, CRATE_NOT_GREEN, ), // Trailing comma + Symbol::intern("rustc_crate_grey"), Symbol::intern("rustc_crate_green") +} + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_late_lint_pass(box PassOkay); + reg.register_late_lint_pass(box PassRedBlue); + reg.register_late_lint_pass(box PassGreyGreen); +} diff --git a/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs b/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs deleted file mode 100644 index f34e10218d455..0000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs +++ /dev/null @@ -1,72 +0,0 @@ -// force-host - -#![feature(plugin_registrar, rustc_private)] -#![feature(box_syntax)] - -#[macro_use] extern crate rustc; -extern crate rustc_plugin; -extern crate syntax; - -use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; -use rustc_plugin::Registry; -use rustc::hir; -use syntax::attr; - -macro_rules! fake_lint_pass { - ($struct:ident, $lints:expr, $($attr:expr),*) => { - struct $struct; - - impl LintPass for $struct { - fn name(&self) -> &'static str { - stringify!($struct) - } - - fn get_lints(&self) -> LintArray { - $lints - } - } - - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for $struct { - fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { - $( - if !attr::contains_name(&krate.attrs, $attr) { - cx.span_lint(CRATE_NOT_OKAY, krate.span, - &format!("crate is not marked with #![{}]", $attr)); - } - )* - } - } - - } -} - -declare_lint!(CRATE_NOT_OKAY, Warn, "crate not marked with #![crate_okay]"); -declare_lint!(CRATE_NOT_RED, Warn, "crate not marked with #![crate_red]"); -declare_lint!(CRATE_NOT_BLUE, Warn, "crate not marked with #![crate_blue]"); -declare_lint!(CRATE_NOT_GREY, Warn, "crate not marked with #![crate_grey]"); -declare_lint!(CRATE_NOT_GREEN, Warn, "crate not marked with #![crate_green]"); - -fake_lint_pass! { - PassOkay, - lint_array!(CRATE_NOT_OKAY), // Single lint - "rustc_crate_okay" -} - -fake_lint_pass! { - PassRedBlue, - lint_array!(CRATE_NOT_RED, CRATE_NOT_BLUE), // Multiple lints - "rustc_crate_red", "rustc_crate_blue" -} - -fake_lint_pass! { - PassGreyGreen, - lint_array!(CRATE_NOT_GREY, CRATE_NOT_GREEN, ), // Trailing comma - "rustc_crate_grey", "rustc_crate_green" -} - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_late_lint_pass(box PassOkay); - reg.register_late_lint_pass(box PassRedBlue); - reg.register_late_lint_pass(box PassGreyGreen); -} diff --git a/src/test/run-pass-fulldeps/auxiliary/llvm_pass_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/llvm-pass-plugin.rs similarity index 100% rename from src/test/run-pass-fulldeps/auxiliary/llvm_pass_plugin.rs rename to src/test/run-pass-fulldeps/auxiliary/llvm-pass-plugin.rs diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro-crate-test.rs similarity index 100% rename from src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs rename to src/test/run-pass-fulldeps/auxiliary/macro-crate-test.rs diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs new file mode 100644 index 0000000000000..4cf8a4e33c526 --- /dev/null +++ b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs @@ -0,0 +1,44 @@ +// force-host + +#![feature(plugin_registrar)] +#![feature(box_syntax, rustc_private)] + +extern crate syntax; +extern crate syntax_pos; +extern crate rustc; +extern crate rustc_plugin; + +use std::borrow::ToOwned; +use syntax::ast; +use syntax::ext::build::AstBuilder; +use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind}; +use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager}; +use syntax::print::pprust; +use syntax::symbol::Symbol; +use syntax_pos::Span; +use syntax::tokenstream::TokenStream; +use rustc_plugin::Registry; + +struct Expander { + args: Vec, +} + +impl TTMacroExpander for Expander { + fn expand<'cx>(&self, + ecx: &'cx mut ExtCtxt, + sp: Span, + _: TokenStream, + _: Option) -> Box { + let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i)) + .collect::>().join(", "); + MacEager::expr(ecx.expr_str(sp, Symbol::intern(&args))) + } +} + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + let args = reg.args().to_owned(); + reg.register_syntax_extension(Symbol::intern("plugin_args"), SyntaxExtension::default( + SyntaxExtensionKind::LegacyBang(Box::new(Expander { args })), reg.sess.edition() + )); +} diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs deleted file mode 100644 index 309acb25184a8..0000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs +++ /dev/null @@ -1,52 +0,0 @@ -// force-host - -#![feature(plugin_registrar)] -#![feature(box_syntax, rustc_private)] - -extern crate syntax; -extern crate syntax_pos; -extern crate rustc; -extern crate rustc_plugin; - -use std::borrow::ToOwned; -use syntax::ast; -use syntax::ext::hygiene; -use syntax::ext::build::AstBuilder; -use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager, NormalTT}; -use syntax::print::pprust; -use syntax::ptr::P; -use syntax::symbol::Symbol; -use syntax_pos::Span; -use syntax::tokenstream::TokenStream; -use rustc_plugin::Registry; - -struct Expander { - args: Vec, -} - -impl TTMacroExpander for Expander { - fn expand<'cx>(&self, - ecx: &'cx mut ExtCtxt, - sp: Span, - _: TokenStream, - _: Option) -> Box { - let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i)) - .collect::>().join(", "); - MacEager::expr(ecx.expr_str(sp, Symbol::intern(&args))) - } -} - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - let args = reg.args().to_owned(); - reg.register_syntax_extension(Symbol::intern("plugin_args"), - NormalTT { - expander: Box::new(Expander { args: args, }), - def_info: None, - allow_internal_unstable: None, - allow_internal_unsafe: false, - local_inner_macros: false, - unstable_feature: None, - edition: hygiene::default_edition(), - }); -} diff --git a/src/test/run-pass-fulldeps/auxiliary/roman-numerals.rs b/src/test/run-pass-fulldeps/auxiliary/roman-numerals.rs new file mode 100644 index 0000000000000..4d9e0129e54db --- /dev/null +++ b/src/test/run-pass-fulldeps/auxiliary/roman-numerals.rs @@ -0,0 +1,69 @@ +// WARNING WARNING WARNING WARNING WARNING +// ======================================= +// +// This code also appears in src/doc/unstable-book/src/language-features/plugin.md. +// Please keep the two copies in sync! FIXME: have rustdoc read this file + +// force-host + +#![crate_type="dylib"] +#![feature(plugin_registrar, rustc_private)] + +extern crate syntax; +extern crate syntax_pos; +extern crate rustc; +extern crate rustc_plugin; + +use syntax::parse::token::{self, Token}; +use syntax::tokenstream::TokenTree; +use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; +use syntax::ext::build::AstBuilder; // A trait for expr_usize. +use syntax_pos::Span; +use rustc_plugin::Registry; + +fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) + -> Box { + + static NUMERALS: &'static [(&'static str, usize)] = &[ + ("M", 1000), ("CM", 900), ("D", 500), ("CD", 400), + ("C", 100), ("XC", 90), ("L", 50), ("XL", 40), + ("X", 10), ("IX", 9), ("V", 5), ("IV", 4), + ("I", 1)]; + + if args.len() != 1 { + cx.span_err( + sp, + &format!("argument should be a single identifier, but got {} arguments", args.len())); + return DummyResult::any(sp); + } + + let text = match args[0] { + TokenTree::Token(Token { kind: token::Ident(s, _), .. }) => s.to_string(), + _ => { + cx.span_err(sp, "argument should be a single identifier"); + return DummyResult::any(sp); + } + }; + + let mut text = &*text; + let mut total = 0; + while !text.is_empty() { + match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) { + Some(&(rn, val)) => { + total += val; + text = &text[rn.len()..]; + } + None => { + cx.span_err(sp, "invalid Roman numeral"); + return DummyResult::any(sp); + } + } + } + + MacEager::expr(cx.expr_usize(sp, total)) +} + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_macro("rn", expand_rn); +} diff --git a/src/test/run-pass-fulldeps/auxiliary/roman_numerals.rs b/src/test/run-pass-fulldeps/auxiliary/roman_numerals.rs deleted file mode 100644 index 216c81ca34ce5..0000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/roman_numerals.rs +++ /dev/null @@ -1,69 +0,0 @@ -// force-host - -#![crate_type="dylib"] -#![feature(plugin_registrar, rustc_private)] - -extern crate syntax; -extern crate syntax_pos; -extern crate rustc; -extern crate rustc_plugin; - -use syntax::parse::token; -use syntax::tokenstream::TokenTree; -use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; -use syntax::ext::build::AstBuilder; // trait for expr_usize -use syntax_pos::Span; -use rustc_plugin::Registry; - -// WARNING WARNING WARNING WARNING WARNING -// ======================================= -// -// This code also appears in src/doc/unstable-book/src/language-features/plugin.md. -// Please keep the two copies in sync! FIXME: have rustdoc read this file - -fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) - -> Box { - - static NUMERALS: &'static [(&'static str, usize)] = &[ - ("M", 1000), ("CM", 900), ("D", 500), ("CD", 400), - ("C", 100), ("XC", 90), ("L", 50), ("XL", 40), - ("X", 10), ("IX", 9), ("V", 5), ("IV", 4), - ("I", 1)]; - - if args.len() != 1 { - cx.span_err( - sp, - &format!("argument should be a single identifier, but got {} arguments", args.len())); - return DummyResult::any(sp); - } - - let text = match args[0] { - TokenTree::Token(_, token::Ident(s, _)) => s.to_string(), - _ => { - cx.span_err(sp, "argument should be a single identifier"); - return DummyResult::any(sp); - } - }; - - let mut text = &*text; - let mut total = 0; - while !text.is_empty() { - match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) { - Some(&(rn, val)) => { - total += val; - text = &text[rn.len()..]; - } - None => { - cx.span_err(sp, "invalid Roman numeral"); - return DummyResult::any(sp); - } - } - } - - MacEager::expr(cx.expr_usize(sp, total)) -} - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_macro("rn", expand_rn); -} diff --git a/src/test/run-pass-fulldeps/auxiliary/syntax_extension_with_dll_deps_1.rs b/src/test/run-pass-fulldeps/auxiliary/syntax-extension-with-dll-deps-1.rs similarity index 100% rename from src/test/run-pass-fulldeps/auxiliary/syntax_extension_with_dll_deps_1.rs rename to src/test/run-pass-fulldeps/auxiliary/syntax-extension-with-dll-deps-1.rs diff --git a/src/test/run-pass-fulldeps/compiler-calls.rs b/src/test/run-pass-fulldeps/compiler-calls.rs index d3a328300ba03..b4731bbaeb5ca 100644 --- a/src/test/run-pass-fulldeps/compiler-calls.rs +++ b/src/test/run-pass-fulldeps/compiler-calls.rs @@ -1,91 +1,30 @@ -// Test that the CompilerCalls interface to the compiler works. +// Test that the Callbacks interface to the compiler works. // ignore-cross-compile // ignore-stage1 #![feature(rustc_private)] -extern crate getopts; -extern crate rustc; extern crate rustc_driver; -extern crate rustc_codegen_utils; -extern crate syntax; -extern crate rustc_errors as errors; -extern crate rustc_metadata; +extern crate rustc_interface; -use rustc::session::Session; -use rustc::session::config::{self, Input}; -use rustc_driver::{driver, CompilerCalls, Compilation}; -use rustc_codegen_utils::codegen_backend::CodegenBackend; -use rustc_metadata::cstore::CStore; -use syntax::ast; - -use std::path::PathBuf; +use rustc_interface::interface; struct TestCalls<'a> { count: &'a mut u32 } -impl<'a> CompilerCalls<'a> for TestCalls<'a> { - fn early_callback(&mut self, - _: &getopts::Matches, - _: &config::Options, - _: &ast::CrateConfig, - _: &errors::registry::Registry, - _: config::ErrorOutputType) - -> Compilation { +impl rustc_driver::Callbacks for TestCalls<'_> { + fn config(&mut self, _config: &mut interface::Config) { *self.count *= 2; - Compilation::Continue - } - - fn late_callback(&mut self, - _: &CodegenBackend, - _: &getopts::Matches, - _: &Session, - _: &CStore, - _: &Input, - _: &Option, - _: &Option) - -> Compilation { - *self.count *= 3; - Compilation::Stop - } - - fn some_input(&mut self, input: Input, input_path: Option) - -> (Input, Option) { - *self.count *= 5; - (input, input_path) - } - - fn no_input(&mut self, - _: &getopts::Matches, - _: &config::Options, - _: &ast::CrateConfig, - _: &Option, - _: &Option, - _: &errors::registry::Registry) - -> Option<(Input, Option)> { - panic!("This shouldn't happen"); - } - - fn build_controller(self: Box, - _: &Session, - _: &getopts::Matches) - -> driver::CompileController<'a> { - panic!("This shouldn't be called"); } } - fn main() { let mut count = 1; - { - let tc = TestCalls { count: &mut count }; - // we should never get use this filename, but lets make sure they are valid args. - let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()]; - syntax::with_globals(|| { - rustc_driver::run_compiler(&args, Box::new(tc), None, None); - }); - } - assert_eq!(count, 30); + let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()]; + rustc_driver::report_ices_to_stderr_if_any(|| { + rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count }, None, None).ok(); + }).ok(); + assert_eq!(count, 2); } diff --git a/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs b/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs deleted file mode 100644 index 21b8ec7be9892..0000000000000 --- a/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs +++ /dev/null @@ -1,10 +0,0 @@ -// aux-build:custom_derive_partial_eq.rs -// ignore-stage1 -#![feature(plugin)] -#![plugin(custom_derive_partial_eq)] -#![allow(unused)] - -#[derive_CustomPartialEq] // Check that this is not a stability error. -enum E { V1, V2 } - -fn main() {} diff --git a/src/test/run-pass-fulldeps/derive-totalsum-attr.rs b/src/test/run-pass-fulldeps/derive-totalsum-attr.rs deleted file mode 100644 index 769861e7c94ad..0000000000000 --- a/src/test/run-pass-fulldeps/derive-totalsum-attr.rs +++ /dev/null @@ -1,64 +0,0 @@ -// aux-build:custom_derive_plugin_attr.rs -// ignore-stage1 - -#![feature(plugin, rustc_attrs)] -#![plugin(custom_derive_plugin_attr)] - -trait TotalSum { - fn total_sum(&self) -> isize; -} - -impl TotalSum for isize { - fn total_sum(&self) -> isize { - *self - } -} - -struct Seven; - -impl TotalSum for Seven { - fn total_sum(&self) -> isize { - 7 - } -} - -#[rustc_derive_TotalSum] -struct Foo { - seven: Seven, - bar: Bar, - baz: isize, - #[ignore] - nan: NaN, -} - -#[rustc_derive_TotalSum] -struct Bar { - quux: isize, - bleh: isize, - #[ignore] - nan: NaN2 -} - -struct NaN; - -impl TotalSum for NaN { - fn total_sum(&self) -> isize { - panic!(); - } -} - -struct NaN2; - -pub fn main() { - let v = Foo { - seven: Seven, - bar: Bar { - quux: 9, - bleh: 3, - nan: NaN2 - }, - baz: 80, - nan: NaN - }; - assert_eq!(v.total_sum(), 99); -} diff --git a/src/test/run-pass-fulldeps/derive-totalsum.rs b/src/test/run-pass-fulldeps/derive-totalsum.rs deleted file mode 100644 index be26943b6dc16..0000000000000 --- a/src/test/run-pass-fulldeps/derive-totalsum.rs +++ /dev/null @@ -1,49 +0,0 @@ -// aux-build:custom_derive_plugin.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(custom_derive_plugin)] - -trait TotalSum { - fn total_sum(&self) -> isize; -} - -impl TotalSum for isize { - fn total_sum(&self) -> isize { - *self - } -} - -struct Seven; - -impl TotalSum for Seven { - fn total_sum(&self) -> isize { - 7 - } -} - -#[derive_TotalSum] -struct Foo { - seven: Seven, - bar: Bar, - baz: isize, -} - -#[derive_TotalSum] -struct Bar { - quux: isize, - bleh: isize, -} - - -pub fn main() { - let v = Foo { - seven: Seven, - bar: Bar { - quux: 9, - bleh: 3, - }, - baz: 80, - }; - assert_eq!(v.total_sum(), 99); -} diff --git a/src/test/run-pass-fulldeps/issue-15778-pass.rs b/src/test/run-pass-fulldeps/issue-15778-pass.rs index 50e9b14b26832..2add3ccbe36f2 100644 --- a/src/test/run-pass-fulldeps/issue-15778-pass.rs +++ b/src/test/run-pass-fulldeps/issue-15778-pass.rs @@ -1,4 +1,4 @@ -// aux-build:lint_for_crate.rs +// aux-build:lint-for-crate.rs // ignore-stage1 // compile-flags: -D crate-not-okay diff --git a/src/test/run-pass-fulldeps/issue-24106.rs b/src/test/run-pass-fulldeps/issue-24106.rs new file mode 100644 index 0000000000000..e8e85ff33772e --- /dev/null +++ b/src/test/run-pass-fulldeps/issue-24106.rs @@ -0,0 +1,7 @@ +// aux-build:issue-24106.rs + +extern crate issue_24106; + +fn main() { + issue_24106::go::<()>(); +} diff --git a/src/test/run-pass-fulldeps/issue-40663.rs b/src/test/run-pass-fulldeps/issue-40663.rs deleted file mode 100644 index cb01eddd7e49e..0000000000000 --- a/src/test/run-pass-fulldeps/issue-40663.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![allow(dead_code)] -// aux-build:custom_derive_plugin.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(custom_derive_plugin)] - -#[derive_Nothing] -#[derive_Nothing] -#[derive_Nothing] -struct S; - -fn main() {} diff --git a/src/test/run-pass-fulldeps/issue_24106.rs b/src/test/run-pass-fulldeps/issue_24106.rs deleted file mode 100644 index a497d9f33ae81..0000000000000 --- a/src/test/run-pass-fulldeps/issue_24106.rs +++ /dev/null @@ -1,7 +0,0 @@ -// aux-build:issue_24106.rs - -extern crate issue_24106; - -fn main() { - issue_24106::go::<()>(); -} diff --git a/src/test/run-pass-fulldeps/llvm-pass-plugin.rs b/src/test/run-pass-fulldeps/llvm-pass-plugin.rs index 3aad40ecfe8aa..411631104a4bc 100644 --- a/src/test/run-pass-fulldeps/llvm-pass-plugin.rs +++ b/src/test/run-pass-fulldeps/llvm-pass-plugin.rs @@ -1,4 +1,4 @@ -// aux-build:llvm_pass_plugin.rs +// aux-build:llvm-pass-plugin.rs // ignore-stage1 #![feature(plugin)] diff --git a/src/test/run-pass-fulldeps/macro-crate-multi-decorator.rs b/src/test/run-pass-fulldeps/macro-crate-multi-decorator.rs index dcac160c4c974..573bfca31683f 100644 --- a/src/test/run-pass-fulldeps/macro-crate-multi-decorator.rs +++ b/src/test/run-pass-fulldeps/macro-crate-multi-decorator.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] #![allow(unused_variables)] #![allow(unused_imports)] -// aux-build:macro_crate_test.rs +// aux-build:macro-crate-test.rs // ignore-stage1 #![feature(rustc_attrs)] diff --git a/src/test/run-pass-fulldeps/mod_dir_path_canonicalized.rs b/src/test/run-pass-fulldeps/mod_dir_path_canonicalized.rs index 22a76a3d968aa..a0dca9b1da4d2 100644 --- a/src/test/run-pass-fulldeps/mod_dir_path_canonicalized.rs +++ b/src/test/run-pass-fulldeps/mod_dir_path_canonicalized.rs @@ -13,7 +13,7 @@ use syntax::parse::{self, ParseSess}; mod gravy; pub fn main() { - syntax::with_globals(|| parse()); + syntax::with_default_globals(|| parse()); assert_eq!(gravy::foo(), 10); } diff --git a/src/test/run-pass-fulldeps/myriad-closures.rs b/src/test/run-pass-fulldeps/myriad-closures.rs index a1ea0e685d659..a6d3530f13902 100644 --- a/src/test/run-pass-fulldeps/myriad-closures.rs +++ b/src/test/run-pass-fulldeps/myriad-closures.rs @@ -32,7 +32,7 @@ macro_rules! mk_fn { } fn main() { - // Make 2^12 functions, each containing 16 closures, - // resulting in 2^16 closures overall. - go_bacterial!(mk_fn 1 1 1 1 1 1 1 1 1 1 1 1); + // Make 2^8 functions, each containing 16 closures, + // resulting in 2^12 closures overall. + go_bacterial!(mk_fn 1 1 1 1 1 1 1 1); } diff --git a/src/test/run-pass-fulldeps/newtype_index.rs b/src/test/run-pass-fulldeps/newtype_index.rs index 3cd622a33b173..18b845eeecb44 100644 --- a/src/test/run-pass-fulldeps/newtype_index.rs +++ b/src/test/run-pass-fulldeps/newtype_index.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs, rustc_private, step_trait)] #[macro_use] extern crate rustc_data_structures; -extern crate rustc_serialize; +extern crate serialize as rustc_serialize; use rustc_data_structures::indexed_vec::Idx; diff --git a/src/test/run-pass-fulldeps/plugin-args-1.rs b/src/test/run-pass-fulldeps/plugin-args-1.rs index 0111af1c76804..1bdf004e3052f 100644 --- a/src/test/run-pass-fulldeps/plugin-args-1.rs +++ b/src/test/run-pass-fulldeps/plugin-args-1.rs @@ -1,4 +1,4 @@ -// aux-build:plugin_args.rs +// aux-build:plugin-args.rs // ignore-stage1 #![feature(plugin)] diff --git a/src/test/run-pass-fulldeps/plugin-args-2.rs b/src/test/run-pass-fulldeps/plugin-args-2.rs index e4a3dfab5668d..83091df058283 100644 --- a/src/test/run-pass-fulldeps/plugin-args-2.rs +++ b/src/test/run-pass-fulldeps/plugin-args-2.rs @@ -1,4 +1,4 @@ -// aux-build:plugin_args.rs +// aux-build:plugin-args.rs // ignore-stage1 #![feature(plugin)] diff --git a/src/test/run-pass-fulldeps/plugin-args-3.rs b/src/test/run-pass-fulldeps/plugin-args-3.rs index 4696233f2818e..9cd9bee5a0fe9 100644 --- a/src/test/run-pass-fulldeps/plugin-args-3.rs +++ b/src/test/run-pass-fulldeps/plugin-args-3.rs @@ -1,4 +1,4 @@ -// aux-build:plugin_args.rs +// aux-build:plugin-args.rs // ignore-stage1 #![feature(plugin)] diff --git a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs index 80e0b0102af75..5716e6d45a0b6 100644 --- a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs @@ -1,23 +1,21 @@ // ignore-cross-compile - // The general idea of this test is to enumerate all "interesting" expressions and check that -// `parse(print(e)) == e` for all `e`. Here's what's interesting, for the purposes of this test: +// `parse(print(e)) == e` for all `e`. Here's what's interesting, for the purposes of this test: // -// 1. The test focuses on expression nesting, because interactions between different expression -// types are harder to test manually than single expression types in isolation. +// 1. The test focuses on expression nesting, because interactions between different expression +// types are harder to test manually than single expression types in isolation. // -// 2. The test only considers expressions of at most two nontrivial nodes. So it will check `x + -// x` and `x + (x - x)` but not `(x * x) + (x - x)`. The assumption here is that the correct -// handling of an expression might depend on the expression's parent, but doesn't depend on its -// siblings or any more distant ancestors. +// 2. The test only considers expressions of at most two nontrivial nodes. So it will check `x + +// x` and `x + (x - x)` but not `(x * x) + (x - x)`. The assumption here is that the correct +// handling of an expression might depend on the expression's parent, but doesn't depend on its +// siblings or any more distant ancestors. // -// 3. The test only checks certain expression kinds. The assumption is that similar expression -// types, such as `if` and `while` or `+` and `-`, will be handled identically in the printer -// and parser. So if all combinations of exprs involving `if` work correctly, then combinations +// 3. The test only checks certain expression kinds. The assumption is that similar expression +// types, such as `if` and `while` or `+` and `-`, will be handled identically in the printer +// and parser. So if all combinations of exprs involving `if` work correctly, then combinations // using `while`, `if let`, and so on will likely work as well. - #![feature(rustc_private)] extern crate rustc_data_structures; @@ -62,7 +60,7 @@ fn make_x() -> P { /// Iterate over exprs of depth up to `depth`. The goal is to explore all "interesting" /// combinations of expression nesting. For example, we explore combinations using `if`, but not /// `while` or `match`, since those should print and parse in much the same way as `if`. -fn iter_exprs(depth: usize, f: &mut FnMut(P)) { +fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { if depth == 0 { f(make_x()); return; @@ -70,7 +68,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { let mut g = |e| f(expr(e)); - for kind in 0 .. 16 { + for kind in 0..=19 { match kind { 0 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Box(e))), 1 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))), @@ -81,25 +79,26 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall( seg.clone(), vec![make_x(), e]))); }, - 3 => { - let op = Spanned { span: DUMMY_SP, node: BinOpKind::Add }; - iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x()))); - iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e))); - }, - 4 => { - let op = Spanned { span: DUMMY_SP, node: BinOpKind::Mul }; - iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x()))); - iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e))); - }, - 5 => { - let op = Spanned { span: DUMMY_SP, node: BinOpKind::Shl }; + 3..=8 => { + let op = Spanned { + span: DUMMY_SP, + node: match kind { + 3 => BinOpKind::Add, + 4 => BinOpKind::Mul, + 5 => BinOpKind::Shl, + 6 => BinOpKind::And, + 7 => BinOpKind::Or, + 8 => BinOpKind::Lt, + _ => unreachable!(), + } + }; iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x()))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e))); }, - 6 => { + 9 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Unary(UnOp::Deref, e))); }, - 7 => { + 10 => { let block = P(Block { stmts: Vec::new(), id: DUMMY_NODE_ID, @@ -108,7 +107,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { }); iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None))); }, - 8 => { + 11 => { let decl = P(FnDecl { inputs: vec![], output: FunctionRetTy::Default(DUMMY_SP), @@ -122,42 +121,50 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { e, DUMMY_SP))); }, - 9 => { + 12 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x()))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e))); }, - 10 => { + 13 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f")))); }, - 11 => { + 14 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Range( Some(e), Some(make_x()), RangeLimits::HalfOpen))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Range( Some(make_x()), Some(e), RangeLimits::HalfOpen))); }, - 12 => { + 15 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::AddrOf(Mutability::Immutable, e))); }, - 13 => { + 16 => { g(ExprKind::Ret(None)); iter_exprs(depth - 1, &mut |e| g(ExprKind::Ret(Some(e)))); }, - 14 => { + 17 => { let path = Path::from_ident(Ident::from_str("S")); g(ExprKind::Struct(path, vec![], Some(make_x()))); }, - 15 => { + 18 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e))); }, + 19 => { + let ps = vec![P(Pat { + id: DUMMY_NODE_ID, + node: PatKind::Wild, + span: DUMMY_SP, + })]; + iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(ps.clone(), e))) + }, _ => panic!("bad counter value in iter_exprs"), } } } -// Folders for manipulating the placement of `Paren` nodes. See below for why this is needed. +// Folders for manipulating the placement of `Paren` nodes. See below for why this is needed. -/// MutVisitor that removes all `ExprKind::Paren` nodes. +/// `MutVisitor` that removes all `ExprKind::Paren` nodes. struct RemoveParens; impl MutVisitor for RemoveParens { @@ -171,7 +178,7 @@ impl MutVisitor for RemoveParens { } -/// MutVisitor that inserts `ExprKind::Paren` nodes around every `Expr`. +/// `MutVisitor` that inserts `ExprKind::Paren` nodes around every `Expr`. struct AddParens; impl MutVisitor for AddParens { @@ -189,7 +196,7 @@ impl MutVisitor for AddParens { } fn main() { - syntax::with_globals(|| run()); + syntax::with_default_globals(|| run()); } fn run() { @@ -205,8 +212,8 @@ fn run() { // We want to know if `parsed` is structurally identical to `e`, ignoring trivial // differences like placement of `Paren`s or the exact ranges of node spans. - // Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s - // everywhere we can, then pretty-print. This should give an unambiguous representation of + // Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s + // everywhere we can, then pretty-print. This should give an unambiguous representation of // each `Expr`, and it bypasses nearly all of the parenthesization logic, so we aren't // relying on the correctness of the very thing we're testing. RemoveParens.visit_expr(&mut e); diff --git a/src/test/run-pass-fulldeps/roman-numerals-macro.rs b/src/test/run-pass-fulldeps/roman-numerals-macro.rs index 59a2d132cdc26..49c12e426fee2 100644 --- a/src/test/run-pass-fulldeps/roman-numerals-macro.rs +++ b/src/test/run-pass-fulldeps/roman-numerals-macro.rs @@ -1,4 +1,4 @@ -// aux-build:roman_numerals.rs +// aux-build:roman-numerals.rs // ignore-stage1 #![feature(plugin)] diff --git a/src/test/run-pass-fulldeps/undef_mask.rs b/src/test/run-pass-fulldeps/undef_mask.rs new file mode 100644 index 0000000000000..cf6e6f7231638 --- /dev/null +++ b/src/test/run-pass-fulldeps/undef_mask.rs @@ -0,0 +1,26 @@ +// ignore-cross-compile +// ignore-stage1 + +#![feature(rustc_private)] + +extern crate rustc; + +use rustc::mir::interpret::UndefMask; +use rustc::ty::layout::Size; + +fn main() { + let mut mask = UndefMask::new(Size::from_bytes(500), false); + assert!(!mask.get(Size::from_bytes(499))); + mask.set(Size::from_bytes(499), true); + assert!(mask.get(Size::from_bytes(499))); + mask.set_range_inbounds(Size::from_bytes(100), Size::from_bytes(256), true); + for i in 0..100 { + assert!(!mask.get(Size::from_bytes(i))); + } + for i in 100..256 { + assert!(mask.get(Size::from_bytes(i))); + } + for i in 256..499 { + assert!(!mask.get(Size::from_bytes(i))); + } +} diff --git a/src/test/run-pass-valgrind/exit-flushes.rs b/src/test/run-pass-valgrind/exit-flushes.rs index c4d23c2938d63..cd5edb84bdfe4 100644 --- a/src/test/run-pass-valgrind/exit-flushes.rs +++ b/src/test/run-pass-valgrind/exit-flushes.rs @@ -1,6 +1,7 @@ // no-prefer-dynamic // ignore-cloudabi // ignore-emscripten +// ignore-sgx no processes // ignore-macos this needs valgrind 3.11 or higher; see // https://github.com/rust-lang/rust/pull/30365#issuecomment-165763679 diff --git a/src/test/run-pass/abi-sysv64-arg-passing.rs b/src/test/run-pass/abi-sysv64-arg-passing.rs index 0b9f9934fa9c8..fdf0573b5e3ec 100644 --- a/src/test/run-pass/abi-sysv64-arg-passing.rs +++ b/src/test/run-pass/abi-sysv64-arg-passing.rs @@ -20,6 +20,7 @@ // extern-return-TwoU64s // foreign-fn-with-byval // issue-28676 +// issue-62350-sysv-neg-reg-counts // struct-return // ignore-android @@ -83,6 +84,9 @@ mod tests { #[derive(Copy, Clone)] pub struct Quad { a: u64, b: u64, c: u64, d: u64 } + #[derive(Copy, Clone)] + pub struct QuadFloats { a: f32, b: f32, c: f32, d: f32 } + #[repr(C)] #[derive(Copy, Clone)] pub struct Floats { a: f64, b: u8, c: f64 } @@ -108,6 +112,16 @@ mod tests { pub fn get_z(x: S) -> u64; pub fn get_c_many_params(_: *const (), _: *const (), _: *const (), _: *const (), f: Quad) -> u64; + pub fn get_c_exhaust_sysv64_ints( + _: *const (), + _: *const (), + _: *const (), + _: *const (), + _: *const (), + _: *const (), + _: *const (), + h: QuadFloats, + ) -> f32; pub fn rust_dbg_abi_1(q: Quad) -> Quad; pub fn rust_dbg_abi_2(f: Floats) -> Floats; } @@ -263,6 +277,27 @@ mod tests { test(); } + fn test_62350() { + use std::ptr; + unsafe { + let null = ptr::null(); + let q = QuadFloats { + a: 10.2, + b: 20.3, + c: 30.4, + d: 40.5 + }; + assert_eq!( + get_c_exhaust_sysv64_ints(null, null, null, null, null, null, null, q), + q.c, + ); + } + } + + pub fn issue_62350() { + test_62350(); + } + fn test1() { unsafe { let q = Quad { a: 0xaaaa_aaaa_aaaa_aaaa, @@ -321,6 +356,7 @@ fn main() { extern_return_twou64s(); foreign_fn_with_byval(); issue_28676(); + issue_62350(); struct_return(); } diff --git a/src/test/run-pass/abi/issues/issue-62350-sysv-neg-reg-counts.rs b/src/test/run-pass/abi/issues/issue-62350-sysv-neg-reg-counts.rs new file mode 100644 index 0000000000000..df819306e4aa2 --- /dev/null +++ b/src/test/run-pass/abi/issues/issue-62350-sysv-neg-reg-counts.rs @@ -0,0 +1,46 @@ +// run-pass +#![allow(dead_code)] +#![allow(improper_ctypes)] + +// ignore-wasm32-bare no libc to test ffi with + +#[derive(Copy, Clone)] +pub struct QuadFloats { a: f32, b: f32, c: f32, d: f32 } + +mod rustrt { + use super::QuadFloats; + + #[link(name = "rust_test_helpers", kind = "static")] + extern { + pub fn get_c_exhaust_sysv64_ints( + _: *const (), + _: *const (), + _: *const (), + _: *const (), + _: *const (), + _: *const (), + _: *const (), + h: QuadFloats, + ) -> f32; + } +} + +fn test() { + unsafe { + let null = std::ptr::null(); + let q = QuadFloats { + a: 10.2, + b: 20.3, + c: 30.4, + d: 40.5 + }; + assert_eq!( + rustrt::get_c_exhaust_sysv64_ints(null, null, null, null, null, null, null, q), + q.c, + ); + } +} + +pub fn main() { + test(); +} diff --git a/src/test/run-pass/abort-on-c-abi.rs b/src/test/run-pass/abort-on-c-abi.rs index df94cd5718631..263f093c51a0b 100644 --- a/src/test/run-pass/abort-on-c-abi.rs +++ b/src/test/run-pass/abort-on-c-abi.rs @@ -1,15 +1,18 @@ #![allow(unused_must_use)] +#![feature(unwind_attributes)] // Since we mark some ABIs as "nounwind" to LLVM, we must make sure that // we never unwind through them. // ignore-cloudabi no env and process // ignore-emscripten no processes +// ignore-sgx no processes use std::{env, panic}; use std::io::prelude::*; use std::io; use std::process::{Command, Stdio}; +#[unwind(aborts)] // FIXME(#58794) extern "C" fn panic_in_ffi() { panic!("Test"); } diff --git a/src/test/run-pass/alignment-gep-tup-like-1.rs b/src/test/run-pass/alignment-gep-tup-like-1.rs index badd095d0ae12..7e6ee60e5194c 100644 --- a/src/test/run-pass/alignment-gep-tup-like-1.rs +++ b/src/test/run-pass/alignment-gep-tup-like-1.rs @@ -22,11 +22,11 @@ impl Invokable
    for Invoker { } } -fn f(a: A, b: u16) -> Box+'static> { +fn f(a: A, b: u16) -> Box+'static> { box Invoker { a: a, b: b, - } as (Box+'static>) + } as (Box+'static>) } pub fn main() { diff --git a/src/test/run-pass/array-slice-vec/estr-slice.rs b/src/test/run-pass/array-slice-vec/estr-slice.rs index 02b88f6a7abfc..cd2c17220655a 100644 --- a/src/test/run-pass/array-slice-vec/estr-slice.rs +++ b/src/test/run-pass/array-slice-vec/estr-slice.rs @@ -14,7 +14,7 @@ pub fn main() { let z : &str = "thing"; assert_eq!(v, x); - assert!(x != z); + assert_ne!(x, z); let a = "aaaa"; let b = "bbbb"; @@ -26,7 +26,7 @@ pub fn main() { assert!(a < b); assert!(a <= b); - assert!(a != b); + assert_ne!(a, b); assert!(b >= a); assert!(b > a); @@ -34,7 +34,7 @@ pub fn main() { assert!(a < c); assert!(a <= c); - assert!(a != c); + assert_ne!(a, c); assert!(c >= a); assert!(c > a); @@ -42,7 +42,7 @@ pub fn main() { assert!(c < cc); assert!(c <= cc); - assert!(c != cc); + assert_ne!(c, cc); assert!(cc >= c); assert!(cc > c); diff --git a/src/test/run-pass/array-slice-vec/vec-macro-no-std.rs b/src/test/run-pass/array-slice-vec/vec-macro-no-std.rs index 7f7f1e4331507..443895f7c4824 100644 --- a/src/test/run-pass/array-slice-vec/vec-macro-no-std.rs +++ b/src/test/run-pass/array-slice-vec/vec-macro-no-std.rs @@ -2,7 +2,7 @@ // ignore-emscripten no no_std executables -#![feature(lang_items, start, rustc_private, alloc)] +#![feature(lang_items, start, rustc_private)] #![no_std] extern crate std as other; diff --git a/src/test/run-pass/asm-concat-src.rs b/src/test/run-pass/asm-concat-src.rs index b24586464d673..c629519e8fe62 100644 --- a/src/test/run-pass/asm-concat-src.rs +++ b/src/test/run-pass/asm-concat-src.rs @@ -6,4 +6,3 @@ pub fn main() { unsafe { asm!(concat!("", "")) }; } - diff --git a/src/test/run-pass/asm-in-moved.rs b/src/test/run-pass/asm-in-moved.rs index dc73f83a940e0..8726db355551b 100644 --- a/src/test/run-pass/asm-in-moved.rs +++ b/src/test/run-pass/asm-in-moved.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - #![feature(asm)] #![allow(dead_code)] diff --git a/src/test/run-pass/asm-out-assign.rs b/src/test/run-pass/asm-out-assign.rs index d0978cc834297..5c46cb92c6b10 100644 --- a/src/test/run-pass/asm-out-assign.rs +++ b/src/test/run-pass/asm-out-assign.rs @@ -1,6 +1,3 @@ -// revisions ast mir -//[mir]compile-flags: -Z borrowck=mir - #![feature(asm)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] diff --git a/src/test/run-pass/associated-consts/associated-const-range-match-patterns.rs b/src/test/run-pass/associated-consts/associated-const-range-match-patterns.rs index 4801369cfd1a8..5276869a702ee 100644 --- a/src/test/run-pass/associated-consts/associated-const-range-match-patterns.rs +++ b/src/test/run-pass/associated-consts/associated-const-range-match-patterns.rs @@ -1,5 +1,6 @@ // run-pass #![allow(dead_code, unreachable_patterns)] +#![allow(ellipsis_inclusive_range_patterns)] struct Foo; @@ -23,4 +24,17 @@ fn main() { ::NUM ... ::NUM => true, _ => false, }); + + assert!(match 2 { + Foo::NUM ..= 3 => true, + _ => false, + }); + assert!(match 0 { + -1 ..= ::NUM => true, + _ => false, + }); + assert!(match 1 { + ::NUM ..= ::NUM => true, + _ => false, + }); } diff --git a/src/test/run-pass/associated-types/associated-types-doubleendediterator-object.rs b/src/test/run-pass/associated-types/associated-types-doubleendediterator-object.rs index 5f86888aef020..96ba2ee3b62b8 100644 --- a/src/test/run-pass/associated-types/associated-types-doubleendediterator-object.rs +++ b/src/test/run-pass/associated-types/associated-types-doubleendediterator-object.rs @@ -1,7 +1,7 @@ // run-pass #![feature(box_syntax)] -fn pairwise_sub(mut t: Box>) -> isize { +fn pairwise_sub(mut t: Box>) -> isize { let mut result = 0; loop { let front = t.next(); diff --git a/src/test/run-pass/associated-types/associated-types-eq-obj.rs b/src/test/run-pass/associated-types/associated-types-eq-obj.rs index 0f3dfe338a33c..c202c376c5fe6 100644 --- a/src/test/run-pass/associated-types/associated-types-eq-obj.rs +++ b/src/test/run-pass/associated-types/associated-types-eq-obj.rs @@ -15,7 +15,7 @@ impl Foo for char { fn boo(&self) -> Bar { Bar } } -fn baz(x: &Foo) -> Bar { +fn baz(x: &dyn Foo) -> Bar { x.boo() } diff --git a/src/test/run-pass/associated-types/associated-types-projection-in-object-type.rs b/src/test/run-pass/associated-types/associated-types-projection-in-object-type.rs index 0dc32f2fd94ec..eec95a141f5cf 100644 --- a/src/test/run-pass/associated-types/associated-types-projection-in-object-type.rs +++ b/src/test/run-pass/associated-types/associated-types-projection-in-object-type.rs @@ -19,7 +19,7 @@ pub trait Subscriber { pub trait Publisher<'a> { type Output; - fn subscribe(&mut self, _: Box + 'a>); + fn subscribe(&mut self, _: Box + 'a>); } pub trait Processor<'a> : Subscriber + Publisher<'a> { } @@ -27,12 +27,12 @@ pub trait Processor<'a> : Subscriber + Publisher<'a> { } impl<'a, P> Processor<'a> for P where P : Subscriber + Publisher<'a> { } struct MyStruct<'a> { - sub: Box + 'a> + sub: Box + 'a> } impl<'a> Publisher<'a> for MyStruct<'a> { type Output = u64; - fn subscribe(&mut self, t : Box + 'a>) { + fn subscribe(&mut self, t : Box + 'a>) { self.sub = t; } } diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs deleted file mode 100644 index 1843feed927a2..0000000000000 --- a/src/test/run-pass/async-await.rs +++ /dev/null @@ -1,185 +0,0 @@ -// edition:2018 -// aux-build:arc_wake.rs - -#![feature(arbitrary_self_types, async_await, await_macro, futures_api)] - -extern crate arc_wake; - -use std::pin::Pin; -use std::future::Future; -use std::sync::{ - Arc, - atomic::{self, AtomicUsize}, -}; -use std::task::{ - Poll, Waker, -}; -use arc_wake::ArcWake; - -struct Counter { - wakes: AtomicUsize, -} - -impl ArcWake for Counter { - fn wake(arc_self: &Arc) { - arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); - } -} - -struct WakeOnceThenComplete(bool); - -fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) } - -impl Future for WakeOnceThenComplete { - type Output = (); - fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll<()> { - if self.0 { - Poll::Ready(()) - } else { - waker.wake(); - self.0 = true; - Poll::Pending - } - } -} - -fn async_block(x: u8) -> impl Future { - async move { - await!(wake_and_yield_once()); - x - } -} - -fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future + 'a { - async move { - await!(wake_and_yield_once()); - *x - } -} - -fn async_nonmove_block(x: u8) -> impl Future { - async move { - let future = async { - await!(wake_and_yield_once()); - x - }; - await!(future) - } -} - -fn async_closure(x: u8) -> impl Future { - (async move |x: u8| -> u8 { - await!(wake_and_yield_once()); - x - })(x) -} - -async fn async_fn(x: u8) -> u8 { - await!(wake_and_yield_once()); - x -} - -async fn async_fn_with_borrow(x: &u8) -> u8 { - await!(wake_and_yield_once()); - *x -} - -async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 { - await!(wake_and_yield_once()); - *x -} - -fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future + 'a { - async move { - await!(wake_and_yield_once()); - *x - } -} - -async fn async_fn_with_named_lifetime_multiple_args<'a>(x: &'a u8, _y: &'a u8) -> u8 { - await!(wake_and_yield_once()); - *x -} - -fn async_fn_with_internal_borrow(y: u8) -> impl Future { - async move { - await!(async_fn_with_borrow(&y)) - } -} - -unsafe async fn unsafe_async_fn(x: u8) -> u8 { - await!(wake_and_yield_once()); - x -} - -struct Foo; - -trait Bar { - fn foo() {} -} - -impl Foo { - async fn async_method(x: u8) -> u8 { - unsafe { - await!(unsafe_async_fn(x)) - } - } -} - -fn test_future_yields_once_then_returns(f: F) -where - F: FnOnce(u8) -> Fut, - Fut: Future, -{ - let mut fut = Box::pin(f(9)); - let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); - let waker = ArcWake::into_waker(counter.clone()); - assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst)); - assert_eq!(Poll::Pending, fut.as_mut().poll(&waker)); - assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst)); - assert_eq!(Poll::Ready(9), fut.as_mut().poll(&waker)); -} - -fn main() { - macro_rules! test { - ($($fn_name:expr,)*) => { $( - test_future_yields_once_then_returns($fn_name); - )* } - } - - macro_rules! test_with_borrow { - ($($fn_name:expr,)*) => { $( - test_future_yields_once_then_returns(|x| { - async move { - await!($fn_name(&x)) - } - }); - )* } - } - - test! { - async_block, - async_nonmove_block, - async_closure, - async_fn, - async_fn_with_internal_borrow, - Foo::async_method, - |x| { - async move { - unsafe { await!(unsafe_async_fn(x)) } - } - }, - } - - test_with_borrow! { - async_block_with_borrow_named_lifetime, - async_fn_with_borrow, - async_fn_with_borrow_named_lifetime, - async_fn_with_impl_future_named_lifetime, - |x| { - async move { - await!(async_fn_with_named_lifetime_multiple_args(x, x)) - } - }, - } -} diff --git a/src/test/run-pass/async-await/async-fn-size-moved-locals.rs b/src/test/run-pass/async-await/async-fn-size-moved-locals.rs new file mode 100644 index 0000000000000..139be7fe0132b --- /dev/null +++ b/src/test/run-pass/async-await/async-fn-size-moved-locals.rs @@ -0,0 +1,98 @@ +// Test that we don't duplicate storage for futures moved around in .await, and +// for futures moved into other futures. +// +// The exact sizes can change by a few bytes (we'd like to know when they do). +// What we don't want to see is the wrong multiple of 1024 (the size of BigFut) +// being reflected in the size. +// +// See issue #59123 for a full explanation. + +// edition:2018 + +#![feature(async_await)] + +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +const BIG_FUT_SIZE: usize = 1024; +struct BigFut([u8; BIG_FUT_SIZE]); + +impl BigFut { + fn new() -> Self { + BigFut([0; BIG_FUT_SIZE]) + } } + +impl Drop for BigFut { + fn drop(&mut self) {} +} + +impl Future for BigFut { + type Output = (); + + fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll { + Poll::Ready(()) + } +} + +#[allow(dead_code)] +struct Joiner { + a: Option, + b: Option, + c: Option, +} + +impl Future for Joiner { + type Output = (); + + fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll { + Poll::Ready(()) + } +} + +fn noop() {} + +async fn single() { + let x = BigFut::new(); + x.await; +} + +async fn single_with_noop() { + let x = BigFut::new(); + noop(); + x.await; +} + +async fn joined() { + let a = BigFut::new(); + let b = BigFut::new(); + let c = BigFut::new(); + + let joiner = Joiner { + a: Some(a), + b: Some(b), + c: Some(c), + }; + joiner.await +} + +async fn joined_with_noop() { + let a = BigFut::new(); + let b = BigFut::new(); + let c = BigFut::new(); + + let joiner = Joiner { + a: Some(a), + b: Some(b), + c: Some(c), + }; + noop(); + joiner.await +} + +fn main() { + assert_eq!(1028, std::mem::size_of_val(&single())); + assert_eq!(1032, std::mem::size_of_val(&single_with_noop())); + assert_eq!(3084, std::mem::size_of_val(&joined())); + assert_eq!(3084, std::mem::size_of_val(&joined_with_noop())); +} diff --git a/src/test/run-pass/async-await/async-fn-size.rs b/src/test/run-pass/async-await/async-fn-size.rs new file mode 100644 index 0000000000000..c4e328560ddf7 --- /dev/null +++ b/src/test/run-pass/async-await/async-fn-size.rs @@ -0,0 +1,106 @@ +// edition:2018 + +#![feature(async_await, await_macro)] + +#[path = "../auxiliary/arc_wake.rs"] +mod arc_wake; + +use std::pin::Pin; +use std::future::Future; +use std::sync::{ + Arc, + atomic::{self, AtomicUsize}, +}; +use std::task::{Context, Poll}; +use arc_wake::ArcWake; + +struct Counter { + wakes: AtomicUsize, +} + +impl ArcWake for Counter { + fn wake(self: Arc) { + Self::wake_by_ref(&self) + } + fn wake_by_ref(arc_self: &Arc) { + arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); + } +} + +struct WakeOnceThenComplete(bool, u8); + +impl Future for WakeOnceThenComplete { + type Output = u8; + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if self.0 { + Poll::Ready(self.1) + } else { + cx.waker().wake_by_ref(); + self.0 = true; + Poll::Pending + } + } +} + +fn wait(fut: impl Future) -> u8 { + let mut fut = Box::pin(fut); + let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); + let waker = ArcWake::into_waker(counter.clone()); + let mut cx = Context::from_waker(&waker); + loop { + match fut.as_mut().poll(&mut cx) { + Poll::Ready(out) => return out, + Poll::Pending => (), + } + } +} + +fn base() -> WakeOnceThenComplete { WakeOnceThenComplete(false, 1) } + +async fn await1_level1() -> u8 { + await!(base()) +} + +async fn await2_level1() -> u8 { + await!(base()) + await!(base()) +} + +async fn await3_level1() -> u8 { + await!(base()) + await!(base()) + await!(base()) +} + +async fn await3_level2() -> u8 { + await!(await3_level1()) + await!(await3_level1()) + await!(await3_level1()) +} + +async fn await3_level3() -> u8 { + await!(await3_level2()) + await!(await3_level2()) + await!(await3_level2()) +} + +async fn await3_level4() -> u8 { + await!(await3_level3()) + await!(await3_level3()) + await!(await3_level3()) +} + +async fn await3_level5() -> u8 { + await!(await3_level4()) + await!(await3_level4()) + await!(await3_level4()) +} + +fn main() { + assert_eq!(2, std::mem::size_of_val(&base())); + assert_eq!(8, std::mem::size_of_val(&await1_level1())); + assert_eq!(12, std::mem::size_of_val(&await2_level1())); + assert_eq!(12, std::mem::size_of_val(&await3_level1())); + assert_eq!(20, std::mem::size_of_val(&await3_level2())); + assert_eq!(28, std::mem::size_of_val(&await3_level3())); + assert_eq!(36, std::mem::size_of_val(&await3_level4())); + assert_eq!(44, std::mem::size_of_val(&await3_level5())); + + assert_eq!(1, wait(base())); + assert_eq!(1, wait(await1_level1())); + assert_eq!(2, wait(await2_level1())); + assert_eq!(3, wait(await3_level1())); + assert_eq!(9, wait(await3_level2())); + assert_eq!(27, wait(await3_level3())); + assert_eq!(81, wait(await3_level4())); + assert_eq!(243, wait(await3_level5())); +} diff --git a/src/test/run-pass/async-await/issue-60709.rs b/src/test/run-pass/async-await/issue-60709.rs new file mode 100644 index 0000000000000..778d3ee0c7083 --- /dev/null +++ b/src/test/run-pass/async-await/issue-60709.rs @@ -0,0 +1,28 @@ +// This used to compile the future down to ud2, due to uninhabited types being +// handled incorrectly in generators. +// compile-flags: -Copt-level=z -Cdebuginfo=2 --edition=2018 + +#![feature(async_await, await_macro)] +#![allow(unused)] + +use std::future::Future; +use std::task::Poll; +use std::task::Context; +use std::pin::Pin; +use std::rc::Rc; + +struct Never(); +impl Future for Never { + type Output = (); + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + Poll::Pending + } +} + +fn main() { + let fut = async { + let _rc = Rc::new(()); // Also crashes with Arc + await!(Never()); + }; + let _bla = fut; // Moving the future is required. +} diff --git a/src/test/run-pass/atomic-print.rs b/src/test/run-pass/atomic-print.rs index 566aeeb2c395d..ee76ef9b25fb8 100644 --- a/src/test/run-pass/atomic-print.rs +++ b/src/test/run-pass/atomic-print.rs @@ -2,6 +2,7 @@ #![allow(deprecated)] // ignore-cloudabi no process support // ignore-emscripten no threads support +// ignore-sgx no processes use std::{env, fmt, process, sync, thread}; diff --git a/src/test/run-pass/attr-before-view-item.rs b/src/test/run-pass/attr-before-view-item.rs deleted file mode 100644 index 14b4189684f9c..0000000000000 --- a/src/test/run-pass/attr-before-view-item.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![allow(unused_attributes)] - -// pretty-expanded FIXME #23616 - -#![feature(custom_attribute, test)] - -#[foo = "bar"] -extern crate test; - -pub fn main() { -} diff --git a/src/test/run-pass/attr-before-view-item2.rs b/src/test/run-pass/attr-before-view-item2.rs deleted file mode 100644 index 6fc1e35d47ac5..0000000000000 --- a/src/test/run-pass/attr-before-view-item2.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![allow(unused_attributes)] - -// pretty-expanded FIXME #23616 - -#![feature(custom_attribute, test)] - -mod m { - #[foo = "bar"] - extern crate test; -} - -pub fn main() { -} diff --git a/src/test/run-pass/attr-mix-new.rs b/src/test/run-pass/attr-mix-new.rs deleted file mode 100644 index 223a434dbb9e7..0000000000000 --- a/src/test/run-pass/attr-mix-new.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![allow(unused_attributes)] -#![allow(unknown_lints)] - -// pretty-expanded FIXME #23616 - -#![allow(unused_attribute)] -#![feature(custom_attribute)] - -#[foo(bar)] -mod foo { - #![feature(globs)] -} - -pub fn main() {} diff --git a/src/test/run-pass/autoref-autoderef/autoderef-method-on-trait.rs b/src/test/run-pass/autoref-autoderef/autoderef-method-on-trait.rs index 0a54db7f5cd8a..fadb0784e7525 100644 --- a/src/test/run-pass/autoref-autoderef/autoderef-method-on-trait.rs +++ b/src/test/run-pass/autoref-autoderef/autoderef-method-on-trait.rs @@ -11,6 +11,6 @@ impl double for usize { } pub fn main() { - let x: Box<_> = box (box 3usize as Box); + let x: Box<_> = box (box 3usize as Box); assert_eq!(x.double(), 6); } diff --git a/src/test/run-pass/auxiliary/allocator-dummy.rs b/src/test/run-pass/auxiliary/allocator-dummy.rs deleted file mode 100644 index bedf3020c8be0..0000000000000 --- a/src/test/run-pass/auxiliary/allocator-dummy.rs +++ /dev/null @@ -1,59 +0,0 @@ -// no-prefer-dynamic - -#![feature(allocator, core_intrinsics, panic_unwind)] -#![allocator] -#![crate_type = "rlib"] -#![no_std] - -extern crate unwind; - -pub static mut HITS: usize = 0; - -type size_t = usize; - -extern { - fn malloc(size: usize) -> *mut u8; - fn free(ptr: *mut u8); - fn calloc(size: usize, amt: usize) -> *mut u8; - fn realloc(ptr: *mut u8, size: usize) -> *mut u8; -} - -#[no_mangle] -pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 { - unsafe { - HITS += 1; - malloc(size as size_t) as *mut u8 - } -} - -#[no_mangle] -pub extern fn __rust_allocate_zeroed(size: usize, _align: usize) -> *mut u8 { - unsafe { calloc(size as size_t, 1) as *mut u8 } -} - -#[no_mangle] -pub extern fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) { - unsafe { - HITS += 1; - free(ptr as *mut _) - } -} - -#[no_mangle] -pub extern fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, - align: usize) -> *mut u8 { - unsafe { - realloc(ptr as *mut _, size as size_t) as *mut u8 - } -} - -#[no_mangle] -pub extern fn __rust_reallocate_inplace(ptr: *mut u8, old_size: usize, - size: usize, align: usize) -> usize { - unsafe { core::intrinsics::abort() } -} - -#[no_mangle] -pub extern fn __rust_usable_size(size: usize, align: usize) -> usize { - unsafe { core::intrinsics::abort() } -} diff --git a/src/test/run-pass/auxiliary/arc_wake.rs b/src/test/run-pass/auxiliary/arc_wake.rs index 034e378af7f19..c21886f26f467 100644 --- a/src/test/run-pass/auxiliary/arc_wake.rs +++ b/src/test/run-pass/auxiliary/arc_wake.rs @@ -1,36 +1,39 @@ // edition:2018 -#![feature(arbitrary_self_types, futures_api)] - use std::sync::Arc; use std::task::{ - Poll, Waker, RawWaker, RawWakerVTable, + Waker, RawWaker, RawWakerVTable, }; macro_rules! waker_vtable { ($ty:ident) => { - &RawWakerVTable { - clone: clone_arc_raw::<$ty>, - drop: drop_arc_raw::<$ty>, - wake: wake_arc_raw::<$ty>, - } + &RawWakerVTable::new( + clone_arc_raw::<$ty>, + wake_arc_raw::<$ty>, + wake_by_ref_arc_raw::<$ty>, + drop_arc_raw::<$ty>, + ) }; } pub trait ArcWake { - fn wake(arc_self: &Arc); + fn wake(self: Arc); + + fn wake_by_ref(arc_self: &Arc) { + arc_self.clone().wake() + } fn into_waker(wake: Arc) -> Waker where Self: Sized { - let ptr = Arc::into_raw(wake) as *const(); + let ptr = Arc::into_raw(wake) as *const (); unsafe { - Waker::new_unchecked(RawWaker::new(ptr, waker_vtable!(Self))) + Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self))) } } } -unsafe fn increase_refcount(data: *const()) { +unsafe fn increase_refcount(data: *const ()) { // Retain Arc by creating a copy let arc: Arc = Arc::from_raw(data as *const T); let arc_clone = arc.clone(); @@ -39,18 +42,23 @@ unsafe fn increase_refcount(data: *const()) { let _ = Arc::into_raw(arc_clone); } -unsafe fn clone_arc_raw(data: *const()) -> RawWaker { +unsafe fn clone_arc_raw(data: *const ()) -> RawWaker { increase_refcount::(data); RawWaker::new(data, waker_vtable!(T)) } -unsafe fn drop_arc_raw(data: *const()) { +unsafe fn drop_arc_raw(data: *const ()) { // Drop Arc let _: Arc = Arc::from_raw(data as *const T); } -unsafe fn wake_arc_raw(data: *const()) { +unsafe fn wake_arc_raw(data: *const ()) { + let arc: Arc = Arc::from_raw(data as *const T); + ArcWake::wake(arc); +} + +unsafe fn wake_by_ref_arc_raw(data: *const ()) { let arc: Arc = Arc::from_raw(data as *const T); - ArcWake::wake(&arc); + ArcWake::wake_by_ref(&arc); let _ = Arc::into_raw(arc); } diff --git a/src/test/run-pass/auxiliary/rmeta_rlib.rs b/src/test/run-pass/auxiliary/rmeta-rlib.rs similarity index 100% rename from src/test/run-pass/auxiliary/rmeta_rlib.rs rename to src/test/run-pass/auxiliary/rmeta-rlib.rs diff --git a/src/test/run-pass/auxiliary/rmeta_rmeta.rs b/src/test/run-pass/auxiliary/rmeta-rmeta.rs similarity index 100% rename from src/test/run-pass/auxiliary/rmeta_rmeta.rs rename to src/test/run-pass/auxiliary/rmeta-rmeta.rs diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index 37c889e9df4ad..69ce1f70322ab 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -10,9 +10,12 @@ // ignore-pretty issue #37195 // ignore-cloudabi spawning processes is not supported // ignore-emscripten spawning processes is not supported +// normalize-stderr-test ".*\n" -> "" +// ignore-sgx no processes -// note that above `-opt-bisect-limit=0` is used to basically disable -// optimizations +// Note that above `-opt-bisect-limit=0` is used to basically disable +// optimizations. It creates tons of output on stderr, hence we normalize +// that away entirely. use std::env; @@ -30,7 +33,6 @@ macro_rules! dump_and_die { all(target_os = "linux", target_arch = "arm"), target_os = "freebsd", target_os = "dragonfly", - target_os = "bitrig", target_os = "openbsd")) { // skip these platforms as this support isn't implemented yet. } else { diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index da3871aba095c..c73ba293ee25b 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -2,6 +2,7 @@ // ignore-cloudabi spawning processes is not supported // ignore-emscripten spawning processes is not supported // ignore-openbsd no support for libbacktrace without filename +// ignore-sgx no processes // compile-flags:-g use std::env; @@ -41,6 +42,21 @@ fn expected(fn_name: &str) -> String { format!(" backtrace::{}", fn_name) } +fn contains_verbose_expected(s: &str, fn_name: &str) -> bool { + // HACK(eddyb) work around the fact that verbosely demangled stack traces + // (from `RUST_BACKTRACE=full`, or, as is the case here, panic-in-panic) + // may contain symbols with hashes in them, i.e. `backtrace[...]::`. + let prefix = " backtrace"; + let suffix = &format!("::{}", fn_name); + s.match_indices(prefix).any(|(i, _)| { + s[i + prefix.len()..] + .trim_start_matches('[') + .trim_start_matches(char::is_alphanumeric) + .trim_start_matches(']') + .starts_with(suffix) + }) +} + fn runtest(me: &str) { // Make sure that the stack trace is printed let p = template(me).arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap(); @@ -78,7 +94,7 @@ fn runtest(me: &str) { let s = str::from_utf8(&out.stderr).unwrap(); // loosened the following from double::h to double:: due to // spurious failures on mac, 32bit, optimized - assert!(s.contains("stack backtrace") && s.contains(&expected("double")), + assert!(s.contains("stack backtrace") && contains_verbose_expected(s, "double"), "bad output3: {}", s); // Make sure a stack trace isn't printed too many times diff --git a/src/test/run-pass/binding/empty-types-in-patterns.rs b/src/test/run-pass/binding/empty-types-in-patterns.rs index d9fb176c818da..2b8b1b29df8c9 100644 --- a/src/test/run-pass/binding/empty-types-in-patterns.rs +++ b/src/test/run-pass/binding/empty-types-in-patterns.rs @@ -56,4 +56,3 @@ fn main() { bar(&[]); } - diff --git a/src/test/run-pass/binding/match-arm-statics.rs b/src/test/run-pass/binding/match-arm-statics.rs index 359c39211588c..5f7e357eeb2a9 100644 --- a/src/test/run-pass/binding/match-arm-statics.rs +++ b/src/test/run-pass/binding/match-arm-statics.rs @@ -45,8 +45,6 @@ pub mod glfw { } fn issue_6533() { - use glfw; - fn action_to_str(state: glfw::InputState) -> &'static str { use glfw::{RELEASE, PRESS, REPEAT}; match state { diff --git a/src/test/run-pass/binding/match-pipe-binding.rs b/src/test/run-pass/binding/match-pipe-binding.rs index 40dbd2468950e..7d4a7c708ddd7 100644 --- a/src/test/run-pass/binding/match-pipe-binding.rs +++ b/src/test/run-pass/binding/match-pipe-binding.rs @@ -1,5 +1,4 @@ // run-pass -// compile-flags: -Z borrowck=compare fn test1() { // from issue 6338 diff --git a/src/test/run-pass/binding/pat-ranges.rs b/src/test/run-pass/binding/pat-ranges.rs index b3729a79615a6..19b3045784f86 100644 --- a/src/test/run-pass/binding/pat-ranges.rs +++ b/src/test/run-pass/binding/pat-ranges.rs @@ -1,6 +1,8 @@ // run-pass // Parsing of range patterns +#![allow(ellipsis_inclusive_range_patterns)] + const NUM1: i32 = 10; mod m { @@ -11,4 +13,8 @@ fn main() { if let NUM1 ... m::NUM2 = 10 {} else { panic!() } if let ::NUM1 ... ::m::NUM2 = 11 {} else { panic!() } if let -13 ... -10 = 12 { panic!() } else {} + + if let NUM1 ..= m::NUM2 = 10 {} else { panic!() } + if let ::NUM1 ..= ::m::NUM2 = 11 {} else { panic!() } + if let -13 ..= -10 = 12 { panic!() } else {} } diff --git a/src/test/run-pass/borrowck/borrowck-assignment-to-static-mut.rs b/src/test/run-pass/borrowck/borrowck-assignment-to-static-mut.rs index 25ef48d0d5ce3..72bf43da95e57 100644 --- a/src/test/run-pass/borrowck/borrowck-assignment-to-static-mut.rs +++ b/src/test/run-pass/borrowck/borrowck-assignment-to-static-mut.rs @@ -2,9 +2,6 @@ #![allow(dead_code)] // Test taken from #45641 (https://github.com/rust-lang/rust/issues/45641) -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - static mut Y: u32 = 0; unsafe fn should_ok() { diff --git a/src/test/run-pass/borrowck/borrowck-multiple-borrows-interior-boxes.rs b/src/test/run-pass/borrowck/borrowck-multiple-borrows-interior-boxes.rs index c953bed26f491..96d2663500ef0 100644 --- a/src/test/run-pass/borrowck/borrowck-multiple-borrows-interior-boxes.rs +++ b/src/test/run-pass/borrowck/borrowck-multiple-borrows-interior-boxes.rs @@ -3,8 +3,6 @@ #![allow(unused_variables)] // Test case from #39963. -#![feature(nll)] - #[derive(Clone)] struct Foo(Option>, Option>); diff --git a/src/test/run-pass/borrowck/borrowck-trait-lifetime.rs b/src/test/run-pass/borrowck/borrowck-trait-lifetime.rs index 9721b08233e39..8a6dfe76d6065 100644 --- a/src/test/run-pass/borrowck/borrowck-trait-lifetime.rs +++ b/src/test/run-pass/borrowck/borrowck-trait-lifetime.rs @@ -12,7 +12,7 @@ use std::marker; fn main() { trait T { fn foo(&self) {} } - fn f<'a, V: T>(v: &'a V) -> &'a T { - v as &'a T + fn f<'a, V: T>(v: &'a V) -> &'a dyn T { + v as &'a dyn T } } diff --git a/src/test/run-pass/borrowck/borrowck-unsafe-static-mutable-borrows.rs b/src/test/run-pass/borrowck/borrowck-unsafe-static-mutable-borrows.rs index 0487c179e3688..adc7dfd541f48 100644 --- a/src/test/run-pass/borrowck/borrowck-unsafe-static-mutable-borrows.rs +++ b/src/test/run-pass/borrowck/borrowck-unsafe-static-mutable-borrows.rs @@ -1,6 +1,4 @@ // run-pass -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir // Test file taken from issue 45129 (https://github.com/rust-lang/rust/issues/45129) diff --git a/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs b/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs index 8f0434c0e2b58..fd0e346e2b42d 100644 --- a/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs +++ b/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(nll)] #![deny(unused_mut)] #[derive(Debug)] diff --git a/src/test/run-pass/borrowck/issue-62007-assign-box.rs b/src/test/run-pass/borrowck/issue-62007-assign-box.rs new file mode 100644 index 0000000000000..f6fbea821b521 --- /dev/null +++ b/src/test/run-pass/borrowck/issue-62007-assign-box.rs @@ -0,0 +1,27 @@ +// run-pass + +// Issue #62007: assigning over a deref projection of a box (in this +// case, `*list = n;`) should be able to kill all borrows of `*list`, +// so that `*list` can be borrowed on the next iteration through the +// loop. + +#![allow(dead_code)] + +struct List { + value: T, + next: Option>>, +} + +fn to_refs(mut list: Box<&mut List>) -> Vec<&mut T> { + let mut result = vec![]; + loop { + result.push(&mut list.value); + if let Some(n) = list.next.as_mut() { + *list = n; + } else { + return result; + } + } +} + +fn main() {} diff --git a/src/test/run-pass/borrowck/issue-62007-assign-field.rs b/src/test/run-pass/borrowck/issue-62007-assign-field.rs new file mode 100644 index 0000000000000..5b21c083816a4 --- /dev/null +++ b/src/test/run-pass/borrowck/issue-62007-assign-field.rs @@ -0,0 +1,26 @@ +// run-pass + +// Issue #62007: assigning over a field projection (`list.0 = n;` in +// this case) should be able to kill all borrows of `list.0`, so that +// `list.0` can be borrowed on the next iteration through the loop. + +#![allow(dead_code)] + +struct List { + value: T, + next: Option>>, +} + +fn to_refs(mut list: (&mut List,)) -> Vec<&mut T> { + let mut result = vec![]; + loop { + result.push(&mut (list.0).value); + if let Some(n) = (list.0).next.as_mut() { + list.0 = n; + } else { + return result; + } + } +} + +fn main() {} diff --git a/src/test/run-pass/borrowck/two-phase-baseline.rs b/src/test/run-pass/borrowck/two-phase-baseline.rs index aa8d18312941a..994dc823dfc0c 100644 --- a/src/test/run-pass/borrowck/two-phase-baseline.rs +++ b/src/test/run-pass/borrowck/two-phase-baseline.rs @@ -1,5 +1,4 @@ // run-pass -// compile-flags: -Z borrowck=mir -Z two-phase-borrows // This is the "goto example" for why we want two phase borrows. diff --git a/src/test/run-pass/borrowck/two-phase-bin-ops.rs b/src/test/run-pass/borrowck/two-phase-bin-ops.rs index 5e1d436e31bf2..1242ae307d39c 100644 --- a/src/test/run-pass/borrowck/two-phase-bin-ops.rs +++ b/src/test/run-pass/borrowck/two-phase-bin-ops.rs @@ -1,8 +1,4 @@ // run-pass -// revisions: lxl nll - -#![cfg_attr(nll, feature(nll))] - use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign}; diff --git a/src/test/run-pass/borrowck/two-phase-control-flow-split-before-activation.rs b/src/test/run-pass/borrowck/two-phase-control-flow-split-before-activation.rs index 9759223a1ba4e..0b20e1945e6f2 100644 --- a/src/test/run-pass/borrowck/two-phase-control-flow-split-before-activation.rs +++ b/src/test/run-pass/borrowck/two-phase-control-flow-split-before-activation.rs @@ -1,8 +1,4 @@ // run-pass -// revisions: lxl nll -//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows - -#![cfg_attr(nll, feature(nll))] fn main() { let mut a = 0; diff --git a/src/test/run-pass/c-stack-returning-int64.rs b/src/test/run-pass/c-stack-returning-int64.rs index f376bb7fde2e5..ec162b40bf8b6 100644 --- a/src/test/run-pass/c-stack-returning-int64.rs +++ b/src/test/run-pass/c-stack-returning-int64.rs @@ -1,4 +1,5 @@ // ignore-wasm32-bare no libc to test with +// ignore-sgx no libc #![feature(rustc_private)] diff --git a/src/test/run-pass/cast-rfc0401-vtable-kinds.rs b/src/test/run-pass/cast-rfc0401-vtable-kinds.rs index e53ab7919228b..a27dd9eef52ec 100644 --- a/src/test/run-pass/cast-rfc0401-vtable-kinds.rs +++ b/src/test/run-pass/cast-rfc0401-vtable-kinds.rs @@ -15,9 +15,9 @@ impl Foo for () {} impl Foo for u32 { fn foo(&self, _: u32) -> u32 { self+43 } } impl Bar for () {} -unsafe fn round_trip_and_call<'a>(t: *const (Foo+'a)) -> u32 { - let foo_e : *const Foo = t as *const _; - let r_1 = foo_e as *mut Foo; +unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo+'a)) -> u32 { + let foo_e : *const dyn Foo = t as *const _; + let r_1 = foo_e as *mut dyn Foo; (&*r_1).foo(0) } @@ -38,8 +38,8 @@ fn tuple_i32_to_u32(u: *const (i32, T)) -> *const (u32, T) { fn main() { let x = 4u32; - let y : &Foo = &x; - let fl = unsafe { round_trip_and_call(y as *const Foo) }; + let y : &dyn Foo = &x; + let fl = unsafe { round_trip_and_call(y as *const dyn Foo) }; assert_eq!(fl, (43+4)); let s = FooS([0,1,2]); diff --git a/src/test/run-pass/cast-rfc0401.rs b/src/test/run-pass/cast-rfc0401.rs index 324860e53e198..017b63c737493 100644 --- a/src/test/run-pass/cast-rfc0401.rs +++ b/src/test/run-pass/cast-rfc0401.rs @@ -25,8 +25,8 @@ fn main() // coercion-cast let mut it = vec![137].into_iter(); let itr: &mut vec::IntoIter = &mut it; - assert_eq!((itr as &mut Iterator).next(), Some(137)); - assert_eq!((itr as &mut Iterator).next(), None); + assert_eq!((itr as &mut dyn Iterator).next(), Some(137)); + assert_eq!((itr as &mut dyn Iterator).next(), None); assert_eq!(Some(4u32) as Option, Some(4u32)); assert_eq!((1u32,2u32) as (u32,u32), (1,2)); diff --git a/src/test/run-pass/cast.rs b/src/test/run-pass/cast.rs index 37add8446f400..c7977f461dfcc 100644 --- a/src/test/run-pass/cast.rs +++ b/src/test/run-pass/cast.rs @@ -15,5 +15,5 @@ pub fn main() { // Test that `_` is correctly inferred. let x = &"hello"; let mut y = x as *const _; - y = 0 as *const _; + y = core::ptr::null_mut(); } diff --git a/src/test/run-pass/cfg/cfg-family.rs b/src/test/run-pass/cfg/cfg-family.rs index 282ac4abcee98..9fb7c7669219d 100644 --- a/src/test/run-pass/cfg/cfg-family.rs +++ b/src/test/run-pass/cfg/cfg-family.rs @@ -2,6 +2,7 @@ // pretty-expanded FIXME #23616 // ignore-cloudabi no target_family // ignore-wasm32-bare no target_family +// ignore-sgx #[cfg(windows)] pub fn main() { diff --git a/src/test/run-pass/cfg/cfg-target-family.rs b/src/test/run-pass/cfg/cfg-target-family.rs index 2cd0ba5bf881c..ecf802f728148 100644 --- a/src/test/run-pass/cfg/cfg-target-family.rs +++ b/src/test/run-pass/cfg/cfg-target-family.rs @@ -1,6 +1,7 @@ // run-pass // ignore-cloudabi no target_family // ignore-wasm32-bare no target_family +// ignore-sgx // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/chalkify/builtin-copy-clone.rs b/src/test/run-pass/chalkify/builtin-copy-clone.rs new file mode 100644 index 0000000000000..4f69714bc747d --- /dev/null +++ b/src/test/run-pass/chalkify/builtin-copy-clone.rs @@ -0,0 +1,43 @@ +// compile-flags: -Z chalk + +// Test that `Clone` is correctly implemented for builtin types. + +#[derive(Copy, Clone)] +struct S(i32); + +fn test_clone(arg: T) { + let _ = arg.clone(); +} + +fn test_copy(arg: T) { + let _ = arg; + let _ = arg; +} + +fn test_copy_clone(arg: T) { + test_copy(arg); + test_clone(arg); +} + +fn foo() { } + +fn main() { + test_copy_clone(foo); + let f: fn() = foo; + test_copy_clone(f); + // FIXME: add closures when they're considered WF + test_copy_clone([1; 56]); + test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)); + test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, true, 'a', 1.1)); + test_copy_clone(()); + test_copy_clone(((1, 1), (1, 1, 1), (1.1, 1, 1, 'a'), ())); + + let a = ( + (S(1), S(0)), + ( + (S(0), S(0), S(1)), + S(0) + ) + ); + test_copy_clone(a); +} diff --git a/src/test/run-pass/check-static-recursion-foreign.rs b/src/test/run-pass/check-static-recursion-foreign.rs index c423bf666e5fb..361f8a1d3406e 100644 --- a/src/test/run-pass/check-static-recursion-foreign.rs +++ b/src/test/run-pass/check-static-recursion-foreign.rs @@ -6,7 +6,7 @@ // pretty-expanded FIXME #23616 -#![feature(custom_attribute, rustc_private)] +#![feature(rustc_private)] extern crate check_static_recursion_foreign_helper; extern crate libc; diff --git a/src/test/run-pass/cleanup-shortcircuit.rs b/src/test/run-pass/cleanup-shortcircuit.rs index 118fa0083ab47..6e67a276d4f1c 100644 --- a/src/test/run-pass/cleanup-shortcircuit.rs +++ b/src/test/run-pass/cleanup-shortcircuit.rs @@ -16,6 +16,6 @@ pub fn main() { if args.len() >= 2 && args[1] == "signal" { // Raise a segfault. - unsafe { *(0 as *mut isize) = 0; } + unsafe { *std::ptr::null_mut::() = 0; } } } diff --git a/src/test/run-pass/close-over-big-then-small-data.rs b/src/test/run-pass/close-over-big-then-small-data.rs index 2ae0b6c7d3de5..0eead0194efa2 100644 --- a/src/test/run-pass/close-over-big-then-small-data.rs +++ b/src/test/run-pass/close-over-big-then-small-data.rs @@ -24,11 +24,11 @@ impl Invokable for Invoker { } } -fn f(a: A, b: u16) -> Box+'static> { +fn f(a: A, b: u16) -> Box+'static> { box Invoker { a: a, b: b, - } as (Box+'static>) + } as (Box+'static>) } pub fn main() { diff --git a/src/test/run-pass/codegen-object-shim.rs b/src/test/run-pass/codegen-object-shim.rs index 4e2d7ac608653..26f53a9c18213 100644 --- a/src/test/run-pass/codegen-object-shim.rs +++ b/src/test/run-pass/codegen-object-shim.rs @@ -1,4 +1,4 @@ fn main() { - assert_eq!((ToString::to_string as fn(&(ToString+'static)) -> String)(&"foo"), + assert_eq!((ToString::to_string as fn(&(dyn ToString+'static)) -> String)(&"foo"), String::from("foo")); } diff --git a/src/test/run-pass/coerce/coerce-expect-unsized.rs b/src/test/run-pass/coerce/coerce-expect-unsized.rs index a7e80afbf767c..b44aa6ab37760 100644 --- a/src/test/run-pass/coerce/coerce-expect-unsized.rs +++ b/src/test/run-pass/coerce/coerce-expect-unsized.rs @@ -12,16 +12,16 @@ pub fn main() { let _: Box<[isize]> = Box::new({ [1, 2, 3] }); let _: Box<[isize]> = Box::new(if true { [1, 2, 3] } else { [1, 3, 4] }); let _: Box<[isize]> = Box::new(match true { true => [1, 2, 3], false => [1, 3, 4] }); - let _: Box _> = Box::new({ |x| (x as u8) }); - let _: Box = Box::new(if true { false } else { true }); - let _: Box = Box::new(match true { true => 'a', false => 'b' }); + let _: Box _> = Box::new({ |x| (x as u8) }); + let _: Box = Box::new(if true { false } else { true }); + let _: Box = Box::new(match true { true => 'a', false => 'b' }); let _: &[isize] = &{ [1, 2, 3] }; let _: &[isize] = &if true { [1, 2, 3] } else { [1, 3, 4] }; let _: &[isize] = &match true { true => [1, 2, 3], false => [1, 3, 4] }; - let _: &Fn(isize) -> _ = &{ |x| (x as u8) }; - let _: &Debug = &if true { false } else { true }; - let _: &Debug = &match true { true => 'a', false => 'b' }; + let _: &dyn Fn(isize) -> _ = &{ |x| (x as u8) }; + let _: &dyn Debug = &if true { false } else { true }; + let _: &dyn Debug = &match true { true => 'a', false => 'b' }; let _: &str = &{ String::new() }; let _: &str = &if true { String::from("...") } else { 5.to_string() }; @@ -31,12 +31,12 @@ pub fn main() { }; let _: Box<[isize]> = Box::new([1, 2, 3]); - let _: Box _> = Box::new(|x| (x as u8)); + let _: Box _> = Box::new(|x| (x as u8)); let _: Rc> = Rc::new(RefCell::new([1, 2, 3])); - let _: Rc _>> = Rc::new(RefCell::new(|x| (x as u8))); + let _: Rc _>> = Rc::new(RefCell::new(|x| (x as u8))); - let _: Vec _>> = vec![ + let _: Vec _>> = vec![ Box::new(|x| (x as u8)), Box::new(|x| (x as i16 as u8)), ]; diff --git a/src/test/run-pass/coherence/auxiliary/re_rebalance_coherence_lib.rs b/src/test/run-pass/coherence/auxiliary/re_rebalance_coherence_lib.rs index c8d027b25c748..41b9d64d5f71e 100644 --- a/src/test/run-pass/coherence/auxiliary/re_rebalance_coherence_lib.rs +++ b/src/test/run-pass/coherence/auxiliary/re_rebalance_coherence_lib.rs @@ -1,5 +1,4 @@ - -pub trait Backend{} +pub trait Backend {} pub trait SupportsDefaultKeyword {} impl SupportsDefaultKeyword for Postgres {} diff --git a/src/test/run-pass/command-exec.rs b/src/test/run-pass/command-exec.rs index ab3d3ebbaad13..aa5a3a377058d 100644 --- a/src/test/run-pass/command-exec.rs +++ b/src/test/run-pass/command-exec.rs @@ -3,6 +3,7 @@ // ignore-pretty issue #37199 // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes #![feature(process_exec)] diff --git a/src/test/run-pass/command-pre-exec.rs b/src/test/run-pass/command-pre-exec.rs index 21783fedd39c9..5c3cc31de5818 100644 --- a/src/test/run-pass/command-pre-exec.rs +++ b/src/test/run-pass/command-pre-exec.rs @@ -2,6 +2,7 @@ // ignore-windows - this is a unix-specific test // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes #![feature(process_exec, rustc_private)] extern crate libc; diff --git a/src/test/run-pass/compiletest-skip-codegen.rs b/src/test/run-pass/compiletest-skip-codegen.rs deleted file mode 100644 index 3c0e22613128a..0000000000000 --- a/src/test/run-pass/compiletest-skip-codegen.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Test that with the `skip-codegen` option the test isn't executed. - -// skip-codegen - -fn main() { - unreachable!(); -} diff --git a/src/test/run-pass/const-int-conversion.rs b/src/test/run-pass/const-int-conversion.rs deleted file mode 100644 index 19d65860179b2..0000000000000 --- a/src/test/run-pass/const-int-conversion.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![feature(const_int_conversion, reverse_bits)] - -const REVERSE: u32 = 0x12345678_u32.reverse_bits(); -const FROM_BE_BYTES: i32 = i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]); -const FROM_LE_BYTES: i32 = i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]); -const FROM_NE_BYTES: i32 = i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0])); -const TO_BE_BYTES: [u8; 4] = 0x12_34_56_78_i32.to_be_bytes(); -const TO_LE_BYTES: [u8; 4] = 0x12_34_56_78_i32.to_le_bytes(); -const TO_NE_BYTES: [u8; 4] = i32::min_value().to_be().to_ne_bytes(); - -fn ident(ident: T) -> T { - ident -} - -fn main() { - assert_eq!(REVERSE, ident(0x1e6a2c48)); - assert_eq!(FROM_BE_BYTES, ident(0x12_34_56_78)); - assert_eq!(FROM_LE_BYTES, ident(0x78_56_34_12)); - assert_eq!(FROM_NE_BYTES, ident(i32::min_value())); - assert_eq!(TO_BE_BYTES, ident([0x12, 0x34, 0x56, 0x78])); - assert_eq!(TO_LE_BYTES, ident([0x78, 0x56, 0x34, 0x12])); - assert_eq!(TO_NE_BYTES, ident([0x80, 0, 0, 0])); -} diff --git a/src/test/run-pass/const-int-overflowing.rs b/src/test/run-pass/const-int-overflowing.rs deleted file mode 100644 index 82057868b73bb..0000000000000 --- a/src/test/run-pass/const-int-overflowing.rs +++ /dev/null @@ -1,41 +0,0 @@ -const ADD_A: (u32, bool) = 5u32.overflowing_add(2); -const ADD_B: (u32, bool) = u32::max_value().overflowing_add(1); - -const SUB_A: (u32, bool) = 5u32.overflowing_sub(2); -const SUB_B: (u32, bool) = 0u32.overflowing_sub(1); - -const MUL_A: (u32, bool) = 5u32.overflowing_mul(2); -const MUL_B: (u32, bool) = 1_000_000_000u32.overflowing_mul(10); - -const SHL_A: (u32, bool) = 0x1u32.overflowing_shl(4); -const SHL_B: (u32, bool) = 0x1u32.overflowing_shl(132); - -const SHR_A: (u32, bool) = 0x10u32.overflowing_shr(4); -const SHR_B: (u32, bool) = 0x10u32.overflowing_shr(132); - -const NEG_A: (u32, bool) = 0u32.overflowing_neg(); -const NEG_B: (u32, bool) = core::u32::MAX.overflowing_neg(); - -fn ident(ident: T) -> T { - ident -} - -fn main() { - assert_eq!(ADD_A, ident((7, false))); - assert_eq!(ADD_B, ident((0, true))); - - assert_eq!(SUB_A, ident((3, false))); - assert_eq!(SUB_B, ident((u32::max_value(), true))); - - assert_eq!(MUL_A, ident((10, false))); - assert_eq!(MUL_B, ident((1410065408, true))); - - assert_eq!(SHL_A, ident((0x10, false))); - assert_eq!(SHL_B, ident((0x10, true))); - - assert_eq!(SHR_A, ident((0x1, false))); - assert_eq!(SHR_B, ident((0x1, true))); - - assert_eq!(NEG_A, ident((0, false))); - assert_eq!(NEG_B, ident((1, true))); -} diff --git a/src/test/run-pass/const-int-rotate.rs b/src/test/run-pass/const-int-rotate.rs deleted file mode 100644 index c014e97ef19b8..0000000000000 --- a/src/test/run-pass/const-int-rotate.rs +++ /dev/null @@ -1,11 +0,0 @@ -const LEFT: u32 = 0x10000b3u32.rotate_left(8); -const RIGHT: u32 = 0xb301u32.rotate_right(8); - -fn ident(ident: T) -> T { - ident -} - -fn main() { - assert_eq!(LEFT, ident(0xb301)); - assert_eq!(RIGHT, ident(0x10000b3)); -} diff --git a/src/test/run-pass/const-int-sign.rs b/src/test/run-pass/const-int-sign.rs deleted file mode 100644 index 9d656a0203069..0000000000000 --- a/src/test/run-pass/const-int-sign.rs +++ /dev/null @@ -1,11 +0,0 @@ -const NEGATIVE_A: bool = (-10i32).is_negative(); -const NEGATIVE_B: bool = 10i32.is_negative(); -const POSITIVE_A: bool= (-10i32).is_positive(); -const POSITIVE_B: bool= 10i32.is_positive(); - -fn main() { - assert!(NEGATIVE_A); - assert!(!NEGATIVE_B); - assert!(!POSITIVE_A); - assert!(POSITIVE_B); -} diff --git a/src/test/run-pass/const-int-wrapping.rs b/src/test/run-pass/const-int-wrapping.rs deleted file mode 100644 index 140fd57ecb802..0000000000000 --- a/src/test/run-pass/const-int-wrapping.rs +++ /dev/null @@ -1,41 +0,0 @@ -const ADD_A: u32 = 200u32.wrapping_add(55); -const ADD_B: u32 = 200u32.wrapping_add(u32::max_value()); - -const SUB_A: u32 = 100u32.wrapping_sub(100); -const SUB_B: u32 = 100u32.wrapping_sub(u32::max_value()); - -const MUL_A: u8 = 10u8.wrapping_mul(12); -const MUL_B: u8 = 25u8.wrapping_mul(12); - -const SHL_A: u32 = 1u32.wrapping_shl(7); -const SHL_B: u32 = 1u32.wrapping_shl(128); - -const SHR_A: u32 = 128u32.wrapping_shr(7); -const SHR_B: u32 = 128u32.wrapping_shr(128); - -const NEG_A: u32 = 5u32.wrapping_neg(); -const NEG_B: u32 = 1234567890u32.wrapping_neg(); - -fn ident(ident: T) -> T { - ident -} - -fn main() { - assert_eq!(ADD_A, ident(255)); - assert_eq!(ADD_B, ident(199)); - - assert_eq!(SUB_A, ident(0)); - assert_eq!(SUB_B, ident(101)); - - assert_eq!(MUL_A, ident(120)); - assert_eq!(MUL_B, ident(44)); - - assert_eq!(SHL_A, ident(128)); - assert_eq!(SHL_B, ident(1)); - - assert_eq!(SHR_A, ident(1)); - assert_eq!(SHR_B, ident(128)); - - assert_eq!(NEG_A, ident(4294967291)); - assert_eq!(NEG_B, ident(3060399406)); -} diff --git a/src/test/run-pass/ctfe/assoc-const.rs b/src/test/run-pass/consts/assoc-const.rs similarity index 100% rename from src/test/run-pass/ctfe/assoc-const.rs rename to src/test/run-pass/consts/assoc-const.rs diff --git a/src/test/run-pass/ctfe/bswap-const.rs b/src/test/run-pass/consts/bswap-const.rs similarity index 100% rename from src/test/run-pass/ctfe/bswap-const.rs rename to src/test/run-pass/consts/bswap-const.rs diff --git a/src/test/run-pass/ctfe/chained-constants-stackoverflow.rs b/src/test/run-pass/consts/chained-constants-stackoverflow.rs similarity index 100% rename from src/test/run-pass/ctfe/chained-constants-stackoverflow.rs rename to src/test/run-pass/consts/chained-constants-stackoverflow.rs diff --git a/src/test/run-pass/ctfe/const-block-non-item-statement-3.rs b/src/test/run-pass/consts/const-block-non-item-statement-3.rs similarity index 100% rename from src/test/run-pass/ctfe/const-block-non-item-statement-3.rs rename to src/test/run-pass/consts/const-block-non-item-statement-3.rs diff --git a/src/test/run-pass/ctfe/const-block-non-item-statement.rs b/src/test/run-pass/consts/const-block-non-item-statement.rs similarity index 100% rename from src/test/run-pass/ctfe/const-block-non-item-statement.rs rename to src/test/run-pass/consts/const-block-non-item-statement.rs diff --git a/src/test/run-pass/consts/const-block.rs b/src/test/run-pass/consts/const-block.rs index 012523a61efcf..7172a34c8cfeb 100644 --- a/src/test/run-pass/consts/const-block.rs +++ b/src/test/run-pass/consts/const-block.rs @@ -21,7 +21,7 @@ static BLOCK_EXPLICIT_UNIT: () = { () }; static BLOCK_IMPLICIT_UNIT: () = { }; static BLOCK_FLOAT: f64 = { 1.0 }; static BLOCK_ENUM: Option = { Some(100) }; -static BLOCK_STRUCT: Foo = { Foo { a: 12, b: 0 as *const () } }; +static BLOCK_STRUCT: Foo = { Foo { a: 12, b: std::ptr::null::<()>() } }; static BLOCK_UNSAFE: usize = unsafe { 1000 }; static BLOCK_FN_INFERRED: fn(usize) -> usize = { foo }; @@ -36,7 +36,7 @@ pub fn main() { assert_eq!(BLOCK_IMPLICIT_UNIT, ()); assert_eq!(BLOCK_FLOAT, 1.0_f64); assert_eq!(BLOCK_STRUCT.a, 12); - assert_eq!(BLOCK_STRUCT.b, 0 as *const ()); + assert_eq!(BLOCK_STRUCT.b, std::ptr::null::<()>()); assert_eq!(BLOCK_ENUM, Some(100)); assert_eq!(BLOCK_UNSAFE, 1000); assert_eq!(BLOCK_FN_INFERRED(300), 300); diff --git a/src/test/run-pass/consts/const-endianess.rs b/src/test/run-pass/consts/const-endianess.rs index cbe6d864c9c3a..936f31954d3dd 100644 --- a/src/test/run-pass/consts/const-endianess.rs +++ b/src/test/run-pass/consts/const-endianess.rs @@ -2,7 +2,7 @@ #![feature(test)] extern crate test; -use test::black_box as b; +use test::black_box as b; // prevent promotion of the argument and const-propagation of the result const BE_U32: u32 = 55u32.to_be(); const LE_U32: u32 = 55u32.to_le(); diff --git a/src/test/run-pass/consts/const-enum-cast.rs b/src/test/run-pass/consts/const-enum-cast.rs index 3b140d147579b..a3255c2f601b3 100644 --- a/src/test/run-pass/consts/const-enum-cast.rs +++ b/src/test/run-pass/consts/const-enum-cast.rs @@ -1,9 +1,8 @@ // run-pass -#![allow(dead_code)] #![allow(non_upper_case_globals)] enum A { A1, A2 } -enum B { B1=0, B2=2 } +enum B { B1=4, B2=2 } pub fn main () { static c1: isize = A::A2 as isize; @@ -14,4 +13,14 @@ pub fn main () { assert_eq!(c2, 2); assert_eq!(a1, 1); assert_eq!(a2, 2); + + // Turns out that adding a let-binding generates totally different MIR. + static c1_2: isize = { let v = A::A1; v as isize }; + static c2_2: isize = { let v = B::B1; v as isize }; + let a1_2 = { let v = A::A1; v as isize }; + let a2_2 = { let v = B::B1; v as isize }; + assert_eq!(c1_2, 0); + assert_eq!(c2_2, 4); + assert_eq!(a1_2, 0); + assert_eq!(a2_2, 4); } diff --git a/src/test/run-pass/consts/const-fn-feature-flags.rs b/src/test/run-pass/consts/const-fn-feature-flags.rs index 83a98f0f8e9ef..30e7e102b8635 100644 --- a/src/test/run-pass/consts/const-fn-feature-flags.rs +++ b/src/test/run-pass/consts/const-fn-feature-flags.rs @@ -11,4 +11,3 @@ fn main() { assert_eq!(CELL.get(), v); } - diff --git a/src/test/run-pass/consts/const-fn-type-name.rs b/src/test/run-pass/consts/const-fn-type-name.rs new file mode 100644 index 0000000000000..2ee6415aa68b7 --- /dev/null +++ b/src/test/run-pass/consts/const-fn-type-name.rs @@ -0,0 +1,37 @@ +// run-pass + +#![feature(core_intrinsics)] +#![feature(const_fn)] +#![allow(dead_code)] + +const fn type_name_wrapper(_: &T) -> &'static str { + unsafe { core::intrinsics::type_name::() } +} + +struct Struct { + a: TA, + b: TB, + c: TC, +} + +type StructInstantiation = Struct; + +const CONST_STRUCT: StructInstantiation = StructInstantiation { + a: 12, + b: 13.7, + c: false, +}; + +const CONST_STRUCT_NAME: &'static str = type_name_wrapper(&CONST_STRUCT); + +fn main() { + let non_const_struct = StructInstantiation { + a: 87, + b: 65.99, + c: true, + }; + + let non_const_struct_name = type_name_wrapper(&non_const_struct); + + assert_eq!(CONST_STRUCT_NAME, non_const_struct_name); +} diff --git a/src/test/run-pass/consts/const-int-conversion.rs b/src/test/run-pass/consts/const-int-conversion.rs new file mode 100644 index 0000000000000..1d3123d216ebf --- /dev/null +++ b/src/test/run-pass/consts/const-int-conversion.rs @@ -0,0 +1,19 @@ +#![feature(const_int_conversion)] + +const REVERSE: u32 = 0x12345678_u32.reverse_bits(); +const FROM_BE_BYTES: i32 = i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]); +const FROM_LE_BYTES: i32 = i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]); +const FROM_NE_BYTES: i32 = i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0])); +const TO_BE_BYTES: [u8; 4] = 0x12_34_56_78_i32.to_be_bytes(); +const TO_LE_BYTES: [u8; 4] = 0x12_34_56_78_i32.to_le_bytes(); +const TO_NE_BYTES: [u8; 4] = i32::min_value().to_be().to_ne_bytes(); + +fn main() { + assert_eq!(REVERSE, 0x1e6a2c48); + assert_eq!(FROM_BE_BYTES, 0x12_34_56_78); + assert_eq!(FROM_LE_BYTES, 0x78_56_34_12); + assert_eq!(FROM_NE_BYTES, i32::min_value()); + assert_eq!(TO_BE_BYTES, [0x12, 0x34, 0x56, 0x78]); + assert_eq!(TO_LE_BYTES, [0x78, 0x56, 0x34, 0x12]); + assert_eq!(TO_NE_BYTES, [0x80, 0, 0, 0]); +} diff --git a/src/test/run-pass/consts/const-int-overflowing.rs b/src/test/run-pass/consts/const-int-overflowing.rs new file mode 100644 index 0000000000000..9597393df72d2 --- /dev/null +++ b/src/test/run-pass/consts/const-int-overflowing.rs @@ -0,0 +1,37 @@ +const ADD_A: (u32, bool) = 5u32.overflowing_add(2); +const ADD_B: (u32, bool) = u32::max_value().overflowing_add(1); + +const SUB_A: (u32, bool) = 5u32.overflowing_sub(2); +const SUB_B: (u32, bool) = 0u32.overflowing_sub(1); + +const MUL_A: (u32, bool) = 5u32.overflowing_mul(2); +const MUL_B: (u32, bool) = 1_000_000_000u32.overflowing_mul(10); + +const SHL_A: (u32, bool) = 0x1u32.overflowing_shl(4); +const SHL_B: (u32, bool) = 0x1u32.overflowing_shl(132); + +const SHR_A: (u32, bool) = 0x10u32.overflowing_shr(4); +const SHR_B: (u32, bool) = 0x10u32.overflowing_shr(132); + +const NEG_A: (u32, bool) = 0u32.overflowing_neg(); +const NEG_B: (u32, bool) = core::u32::MAX.overflowing_neg(); + +fn main() { + assert_eq!(ADD_A, (7, false)); + assert_eq!(ADD_B, (0, true)); + + assert_eq!(SUB_A, (3, false)); + assert_eq!(SUB_B, (u32::max_value(), true)); + + assert_eq!(MUL_A, (10, false)); + assert_eq!(MUL_B, (1410065408, true)); + + assert_eq!(SHL_A, (0x10, false)); + assert_eq!(SHL_B, (0x10, true)); + + assert_eq!(SHR_A, (0x1, false)); + assert_eq!(SHR_B, (0x1, true)); + + assert_eq!(NEG_A, (0, false)); + assert_eq!(NEG_B, (1, true)); +} diff --git a/src/test/run-pass/consts/const-int-rotate.rs b/src/test/run-pass/consts/const-int-rotate.rs new file mode 100644 index 0000000000000..16946eadd632a --- /dev/null +++ b/src/test/run-pass/consts/const-int-rotate.rs @@ -0,0 +1,41 @@ +const LEFT: u32 = 0x10000b3u32.rotate_left(8); +const RIGHT: u32 = 0xb301u32.rotate_right(8); + +// Rotating these should make no difference +// +// We test using 124 bits because to ensure that overlong bit shifts do +// not cause undefined behaviour. See #10183. +const LEFT_OVERFLOW: i16 = 0i16.rotate_left(124); +const RIGHT_OVERFLOW: i16 = 0i16.rotate_right(124); +const ONE_LEFT_OVERFLOW: u16 = 1u16.rotate_left(124); +const ONE_RIGHT_OVERFLOW: u16 = 1u16.rotate_right(124); + +const NON_ZERO_LEFT_OVERFLOW: u16 = 0b10u16.rotate_left(124); +const NON_ZERO_RIGHT_OVERFLOW: u16 = 0b10u16.rotate_right(124); + +// Rotating by 0 should have no effect +const ZERO_ROTATE_LEFT: i8 = 0b0010_0001i8.rotate_left(0); +const ZERO_ROTATE_RIGHT: i8 = 0b0111_1001i8.rotate_right(0); + +// Rotating by a multiple of word size should also have no effect +const MULTIPLE_ROTATE_LEFT: i32 = 0b0010_0001i32.rotate_left(128); +const MULTIPLE_ROTATE_RIGHT: i32 = 0b0010_0001i32.rotate_right(128); + +fn main() { + assert_eq!(LEFT, 0xb301); + assert_eq!(RIGHT, 0x0100_00b3); + + assert_eq!(LEFT_OVERFLOW, 0); + assert_eq!(RIGHT_OVERFLOW, 0); + assert_eq!(ONE_LEFT_OVERFLOW, 0b0001_0000_0000_0000); + assert_eq!(ONE_RIGHT_OVERFLOW, 0b0001_0000); + + assert_eq!(NON_ZERO_LEFT_OVERFLOW, 0b0010_0000_0000_0000); + assert_eq!(NON_ZERO_RIGHT_OVERFLOW, 0b0000_0000_0010_0000); + + assert_eq!(ZERO_ROTATE_LEFT, 0b0010_0001); + assert_eq!(ZERO_ROTATE_RIGHT, 0b0111_1001); + + assert_eq!(MULTIPLE_ROTATE_LEFT, 0b0010_0001); + assert_eq!(MULTIPLE_ROTATE_RIGHT, 0b0010_0001); +} diff --git a/src/test/run-pass/const-int-saturating-arith.rs b/src/test/run-pass/consts/const-int-saturating-arith.rs similarity index 100% rename from src/test/run-pass/const-int-saturating-arith.rs rename to src/test/run-pass/consts/const-int-saturating-arith.rs diff --git a/src/test/run-pass/consts/const-int-sign.rs b/src/test/run-pass/consts/const-int-sign.rs new file mode 100644 index 0000000000000..fcd3ef4ea025b --- /dev/null +++ b/src/test/run-pass/consts/const-int-sign.rs @@ -0,0 +1,21 @@ +#![feature(const_int_sign)] + +const NEGATIVE_A: bool = (-10i32).is_negative(); +const NEGATIVE_B: bool = 10i32.is_negative(); +const POSITIVE_A: bool = (-10i32).is_positive(); +const POSITIVE_B: bool = 10i32.is_positive(); + +const SIGNUM_POS: i32 = 10i32.signum(); +const SIGNUM_NIL: i32 = 0i32.signum(); +const SIGNUM_NEG: i32 = (-42i32).signum(); + +fn main() { + assert!(NEGATIVE_A); + assert!(!NEGATIVE_B); + assert!(!POSITIVE_A); + assert!(POSITIVE_B); + + assert_eq!(SIGNUM_POS, 1); + assert_eq!(SIGNUM_NIL, 0); + assert_eq!(SIGNUM_NEG, -1); +} diff --git a/src/test/run-pass/consts/const-int-wrapping.rs b/src/test/run-pass/consts/const-int-wrapping.rs new file mode 100644 index 0000000000000..db86c25194f08 --- /dev/null +++ b/src/test/run-pass/consts/const-int-wrapping.rs @@ -0,0 +1,37 @@ +const ADD_A: u32 = 200u32.wrapping_add(55); +const ADD_B: u32 = 200u32.wrapping_add(u32::max_value()); + +const SUB_A: u32 = 100u32.wrapping_sub(100); +const SUB_B: u32 = 100u32.wrapping_sub(u32::max_value()); + +const MUL_A: u8 = 10u8.wrapping_mul(12); +const MUL_B: u8 = 25u8.wrapping_mul(12); + +const SHL_A: u32 = 1u32.wrapping_shl(7); +const SHL_B: u32 = 1u32.wrapping_shl(128); + +const SHR_A: u32 = 128u32.wrapping_shr(7); +const SHR_B: u32 = 128u32.wrapping_shr(128); + +const NEG_A: u32 = 5u32.wrapping_neg(); +const NEG_B: u32 = 1234567890u32.wrapping_neg(); + +fn main() { + assert_eq!(ADD_A, 255); + assert_eq!(ADD_B, 199); + + assert_eq!(SUB_A, 0); + assert_eq!(SUB_B, 101); + + assert_eq!(MUL_A, 120); + assert_eq!(MUL_B, 44); + + assert_eq!(SHL_A, 128); + assert_eq!(SHL_B, 1); + + assert_eq!(SHR_A, 1); + assert_eq!(SHR_B, 128); + + assert_eq!(NEG_A, 4294967291); + assert_eq!(NEG_B, 3060399406); +} diff --git a/src/test/run-pass/consts/const-labeled-break.rs b/src/test/run-pass/consts/const-labeled-break.rs new file mode 100644 index 0000000000000..9417159e6fb78 --- /dev/null +++ b/src/test/run-pass/consts/const-labeled-break.rs @@ -0,0 +1,10 @@ +// Using labeled break in a while loop has caused an illegal instruction being +// generated, and an ICE later. +// +// See https://github.com/rust-lang/rust/issues/51350 for more information. + +const CRASH: () = 'a: while break 'a {}; + +fn main() { + println!("{:?}", CRASH); +} diff --git a/src/test/run-pass/const-needs_drop.rs b/src/test/run-pass/consts/const-needs_drop.rs similarity index 96% rename from src/test/run-pass/const-needs_drop.rs rename to src/test/run-pass/consts/const-needs_drop.rs index 9d9dffb530737..871300defaf8a 100644 --- a/src/test/run-pass/const-needs_drop.rs +++ b/src/test/run-pass/consts/const-needs_drop.rs @@ -1,5 +1,3 @@ -#![feature(const_needs_drop)] - use std::mem; struct Trivial(u8, f32); diff --git a/src/test/run-pass/consts/const-ptr-nonnull.rs b/src/test/run-pass/consts/const-ptr-nonnull.rs new file mode 100644 index 0000000000000..67d52ad08246a --- /dev/null +++ b/src/test/run-pass/consts/const-ptr-nonnull.rs @@ -0,0 +1,17 @@ +// run-pass + +#![feature(ptr_internals, test)] + +extern crate test; +use test::black_box as b; // prevent promotion of the argument and const-propagation of the result + +use std::ptr::NonNull; + +const DANGLING: NonNull = NonNull::dangling(); +const CASTED: NonNull = NonNull::cast(NonNull::::dangling()); + +pub fn main() { + // Be super-extra paranoid and cast the fn items to fn pointers before blackboxing them. + assert_eq!(DANGLING, b:: _>(NonNull::dangling)()); + assert_eq!(CASTED, b:: _>(NonNull::dangling)()); +} diff --git a/src/test/run-pass/consts/const-ptr-unique.rs b/src/test/run-pass/consts/const-ptr-unique.rs new file mode 100644 index 0000000000000..e8735e1a32c2c --- /dev/null +++ b/src/test/run-pass/consts/const-ptr-unique.rs @@ -0,0 +1,16 @@ +// run-pass + +#![feature(ptr_internals, test)] + +extern crate test; +use test::black_box as b; // prevent promotion of the argument and const-propagation of the result + +use std::ptr::Unique; + + +const PTR: *mut u32 = Unique::empty().as_ptr(); + +pub fn main() { + // Be super-extra paranoid and cast the fn items to fn pointers before blackboxing them. + assert_eq!(PTR, b:: _>(Unique::::empty)().as_ptr()); +} diff --git a/src/test/run-pass/consts/const-trait-to-trait.rs b/src/test/run-pass/consts/const-trait-to-trait.rs index a324d73a3a9df..12a2999d79d47 100644 --- a/src/test/run-pass/consts/const-trait-to-trait.rs +++ b/src/test/run-pass/consts/const-trait-to-trait.rs @@ -8,7 +8,7 @@ struct Bar; impl Trait for Bar {} fn main() { - let x: &[&Trait] = &[{ &Bar }]; + let x: &[&dyn Trait] = &[{ &Bar }]; } // Issue #25748 - the cast causes an &Encoding -> &Encoding coercion: @@ -16,9 +16,9 @@ pub struct UTF8Encoding; pub const UTF_8: &'static UTF8Encoding = &UTF8Encoding; pub trait Encoding {} impl Encoding for UTF8Encoding {} -pub fn f() -> &'static Encoding { UTF_8 as &'static Encoding } +pub fn f() -> &'static dyn Encoding { UTF_8 as &'static dyn Encoding } // Root of the problem: &Trait -> &Trait coercions: -const FOO: &'static Trait = &Bar; -const BAR: &'static Trait = FOO; +const FOO: &'static dyn Trait = &Bar; +const BAR: &'static dyn Trait = FOO; fn foo() { let _x = BAR; } diff --git a/src/test/run-pass/ctfe/deref_in_pattern.rs b/src/test/run-pass/consts/deref_in_pattern.rs similarity index 100% rename from src/test/run-pass/ctfe/deref_in_pattern.rs rename to src/test/run-pass/consts/deref_in_pattern.rs diff --git a/src/test/run-pass/ctfe/ice-48279.rs b/src/test/run-pass/consts/ice-48279.rs similarity index 100% rename from src/test/run-pass/ctfe/ice-48279.rs rename to src/test/run-pass/consts/ice-48279.rs diff --git a/src/test/run-pass/ctfe/issue-37550.rs b/src/test/run-pass/consts/issue-37550.rs similarity index 100% rename from src/test/run-pass/ctfe/issue-37550.rs rename to src/test/run-pass/consts/issue-37550.rs diff --git a/src/test/run-pass/ctfe/issue-broken-mir.rs b/src/test/run-pass/consts/issue-broken-mir.rs similarity index 100% rename from src/test/run-pass/ctfe/issue-broken-mir.rs rename to src/test/run-pass/consts/issue-broken-mir.rs diff --git a/src/test/run-pass/ctfe/locals-in-const-fn.rs b/src/test/run-pass/consts/locals-in-const-fn.rs similarity index 100% rename from src/test/run-pass/ctfe/locals-in-const-fn.rs rename to src/test/run-pass/consts/locals-in-const-fn.rs diff --git a/src/test/run-pass/ctfe/match-const-fn-structs.rs b/src/test/run-pass/consts/match-const-fn-structs.rs similarity index 100% rename from src/test/run-pass/ctfe/match-const-fn-structs.rs rename to src/test/run-pass/consts/match-const-fn-structs.rs diff --git a/src/test/run-pass/ctfe/mozjs-error.rs b/src/test/run-pass/consts/mozjs-error.rs similarity index 100% rename from src/test/run-pass/ctfe/mozjs-error.rs rename to src/test/run-pass/consts/mozjs-error.rs diff --git a/src/test/run-pass/ctfe/non-scalar-cast.rs b/src/test/run-pass/consts/non-scalar-cast.rs similarity index 100% rename from src/test/run-pass/ctfe/non-scalar-cast.rs rename to src/test/run-pass/consts/non-scalar-cast.rs diff --git a/src/test/run-pass/ctfe/promotion.rs b/src/test/run-pass/consts/promotion.rs similarity index 100% rename from src/test/run-pass/ctfe/promotion.rs rename to src/test/run-pass/consts/promotion.rs diff --git a/src/test/run-pass/ctfe/references.rs b/src/test/run-pass/consts/references.rs similarity index 100% rename from src/test/run-pass/ctfe/references.rs rename to src/test/run-pass/consts/references.rs diff --git a/src/test/run-pass/ctfe/repeat_match.rs b/src/test/run-pass/consts/repeat_match.rs similarity index 100% rename from src/test/run-pass/ctfe/repeat_match.rs rename to src/test/run-pass/consts/repeat_match.rs diff --git a/src/test/run-pass/ctfe/return-in-const-fn.rs b/src/test/run-pass/consts/return-in-const-fn.rs similarity index 100% rename from src/test/run-pass/ctfe/return-in-const-fn.rs rename to src/test/run-pass/consts/return-in-const-fn.rs diff --git a/src/test/run-pass/ctfe/signed_enum_discr.rs b/src/test/run-pass/consts/signed_enum_discr.rs similarity index 100% rename from src/test/run-pass/ctfe/signed_enum_discr.rs rename to src/test/run-pass/consts/signed_enum_discr.rs diff --git a/src/test/run-pass/ctfe/transmute-const.rs b/src/test/run-pass/consts/transmute-const.rs similarity index 100% rename from src/test/run-pass/ctfe/transmute-const.rs rename to src/test/run-pass/consts/transmute-const.rs diff --git a/src/test/run-pass/ctfe/tuple-struct-constructors.rs b/src/test/run-pass/consts/tuple-struct-constructors.rs similarity index 100% rename from src/test/run-pass/ctfe/tuple-struct-constructors.rs rename to src/test/run-pass/consts/tuple-struct-constructors.rs diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index 55d389952cc40..625e51793814e 100644 --- a/src/test/run-pass/core-run-destroy.rs +++ b/src/test/run-pass/core-run-destroy.rs @@ -5,6 +5,7 @@ // compile-flags:--test // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes // N.B., these tests kill child processes. Valgrind sees these children as leaking // memory, which makes for some *confusing* logs. That's why these are here diff --git a/src/test/run-pass/default-alloc-error-hook.rs b/src/test/run-pass/default-alloc-error-hook.rs index 8dcc8ad5433e0..7d1624320e679 100644 --- a/src/test/run-pass/default-alloc-error-hook.rs +++ b/src/test/run-pass/default-alloc-error-hook.rs @@ -1,5 +1,6 @@ // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::alloc::{Layout, handle_alloc_error}; use std::env; diff --git a/src/test/run-pass/deriving/auxiliary/derive-no-std.rs b/src/test/run-pass/deriving/auxiliary/derive-no-std.rs index 21bfd5a2909b1..3893dc1be079c 100644 --- a/src/test/run-pass/deriving/auxiliary/derive-no-std.rs +++ b/src/test/run-pass/deriving/auxiliary/derive-no-std.rs @@ -27,4 +27,3 @@ pub struct Empty; #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Copy)] pub struct AlsoEmpty {} - diff --git a/src/test/run-pass/deriving/derive-no-std.rs b/src/test/run-pass/deriving/derive-no-std.rs index 22edd3eed5926..74c73b99cb923 100644 --- a/src/test/run-pass/deriving/derive-no-std.rs +++ b/src/test/run-pass/deriving/derive-no-std.rs @@ -10,4 +10,3 @@ fn main() { assert!(Bar::Qux < Bar::Quux(42)); } - diff --git a/src/test/run-pass/deriving/deriving-show.rs b/src/test/run-pass/deriving/deriving-show.rs index 98c1f3ac0273e..eb3a8948fc80d 100644 --- a/src/test/run-pass/deriving/deriving-show.rs +++ b/src/test/run-pass/deriving/deriving-show.rs @@ -17,7 +17,7 @@ enum Enum { } #[derive(Debug)] -struct Pointers(*const Send, *mut Sync); +struct Pointers(*const dyn Send, *mut dyn Sync); macro_rules! t { ($x:expr, $expected:expr) => { diff --git a/src/test/run-pass/dispatch_from_dyn_zst.rs b/src/test/run-pass/dispatch_from_dyn_zst.rs new file mode 100644 index 0000000000000..a2181336e00f5 --- /dev/null +++ b/src/test/run-pass/dispatch_from_dyn_zst.rs @@ -0,0 +1,49 @@ +#![feature(unsize, dispatch_from_dyn, never_type)] + +#![allow(dead_code)] + +use std::{ + ops::DispatchFromDyn, + marker::{Unsize, PhantomData}, +}; + +struct Zst; +struct NestedZst(PhantomData<()>, Zst); + + +struct WithUnit(Box, ()); +impl DispatchFromDyn> for WithUnit + where T: Unsize {} + +struct WithPhantom(Box, PhantomData<()>); +impl DispatchFromDyn> for WithPhantom + where T: Unsize {} + +struct WithNever(Box, !); +impl DispatchFromDyn> for WithNever + where T: Unsize {} + +struct WithZst(Box, Zst); +impl DispatchFromDyn> for WithZst + where T: Unsize {} + +struct WithNestedZst(Box, NestedZst); +impl DispatchFromDyn> for WithNestedZst + where T: Unsize {} + + +struct Generic(Box, A); +impl DispatchFromDyn> for Generic + where T: Unsize {} +impl DispatchFromDyn>> + for Generic> + where T: Unsize {} +impl DispatchFromDyn> for Generic + where T: Unsize {} +impl DispatchFromDyn> for Generic + where T: Unsize {} +impl DispatchFromDyn> for Generic + where T: Unsize {} + + +fn main() {} diff --git a/src/test/run-pass/drop/drop-struct-as-object.rs b/src/test/run-pass/drop/drop-struct-as-object.rs index 307b3f1d6dc2b..1bc3b4c157ca8 100644 --- a/src/test/run-pass/drop/drop-struct-as-object.rs +++ b/src/test/run-pass/drop/drop-struct-as-object.rs @@ -30,7 +30,7 @@ impl Drop for Cat { pub fn main() { { let x = box Cat {name: 22}; - let nyan: Box = x as Box; + let nyan: Box = x as Box; } unsafe { assert_eq!(value, 22); diff --git a/src/test/run-pass/drop/dynamic-drop.rs b/src/test/run-pass/drop/dynamic-drop.rs index 97e4cded80b9a..eb1a3f3a9f9cb 100644 --- a/src/test/run-pass/drop/dynamic-drop.rs +++ b/src/test/run-pass/drop/dynamic-drop.rs @@ -1,8 +1,6 @@ // run-pass #![allow(unused_assignments)] #![allow(unused_variables)] -// revisions:lexical nll -#![cfg_attr(nll, feature(nll))] // ignore-wasm32-bare compiled with panic=abort by default @@ -43,7 +41,7 @@ impl Allocator { data: RefCell::new(vec![]) } } - fn alloc(&self) -> Ptr { + fn alloc(&self) -> Ptr<'_> { self.cur_ops.set(self.cur_ops.get() + 1); if self.cur_ops.get() == self.failing_op { @@ -55,6 +53,20 @@ impl Allocator { data.push(true); Ptr(addr, self) } + // FIXME(#47949) Any use of this indicates a bug in rustc: we should never + // be leaking values in the cases here. + // + // Creates a `Ptr<'_>` and checks that the allocated value is leaked if the + // `failing_op` is in the list of exception. + fn alloc_leaked(&self, exceptions: Vec) -> Ptr<'_> { + let ptr = self.alloc(); + + if exceptions.iter().any(|operation| *operation == self.failing_op) { + let mut data = self.data.borrow_mut(); + data[ptr.0] = false; + } + ptr + } } struct Ptr<'a>(usize, &'a Allocator); @@ -257,6 +269,72 @@ fn subslice_pattern_reassign(a: &Allocator) { let[_, _y..] = ar; } +fn panic_after_return(a: &Allocator) -> Ptr<'_> { + // Panic in the drop of `p` or `q` can leak + let exceptions = vec![8, 9]; + a.alloc(); + let p = a.alloc(); + { + a.alloc(); + let p = a.alloc(); + // FIXME (#47949) We leak values when we panic in a destructor after + // evaluating an expression with `rustc_mir::build::Builder::into`. + a.alloc_leaked(exceptions) + } +} + +fn panic_after_return_expr(a: &Allocator) -> Ptr<'_> { + // Panic in the drop of `p` or `q` can leak + let exceptions = vec![8, 9]; + a.alloc(); + let p = a.alloc(); + { + a.alloc(); + let q = a.alloc(); + // FIXME (#47949) + return a.alloc_leaked(exceptions); + } +} + +fn panic_after_init(a: &Allocator) { + // Panic in the drop of `r` can leak + let exceptions = vec![8]; + a.alloc(); + let p = a.alloc(); + let q = { + a.alloc(); + let r = a.alloc(); + // FIXME (#47949) + a.alloc_leaked(exceptions) + }; +} + +fn panic_after_init_temp(a: &Allocator) { + // Panic in the drop of `r` can leak + let exceptions = vec![8]; + a.alloc(); + let p = a.alloc(); + { + a.alloc(); + let r = a.alloc(); + // FIXME (#47949) + a.alloc_leaked(exceptions) + }; +} + +fn panic_after_init_by_loop(a: &Allocator) { + // Panic in the drop of `r` can leak + let exceptions = vec![8]; + a.alloc(); + let p = a.alloc(); + let q = loop { + a.alloc(); + let r = a.alloc(); + // FIXME (#47949) + break a.alloc_leaked(exceptions); + }; +} + fn run_test(mut f: F) where F: FnMut(&Allocator) { @@ -344,5 +422,15 @@ fn main() { run_test(|a| slice_pattern_reassign(a)); run_test(|a| subslice_pattern_reassign(a)); + run_test(|a| { + panic_after_return(a); + }); + run_test(|a| { + panic_after_return_expr(a); + }); + run_test(|a| panic_after_init(a)); + run_test(|a| panic_after_init_temp(a)); + run_test(|a| panic_after_init_by_loop(a)); + run_test_nopanic(|a| union1(a)); } diff --git a/src/test/run-pass/dupe-first-attr.rc b/src/test/run-pass/dupe-first-attr.rc index cb6a82a15da1f..8b7025b7be7da 100644 --- a/src/test/run-pass/dupe-first-attr.rc +++ b/src/test/run-pass/dupe-first-attr.rc @@ -18,9 +18,6 @@ mod hello; #[cfg(target_os = "dragonfly")] mod hello; -#[cfg(target_os = "bitrig")] -mod hello; - #[cfg(target_os = "android")] mod hello; diff --git a/src/test/run-pass/dynamically-sized-types/dst-coerce-custom.rs b/src/test/run-pass/dynamically-sized-types/dst-coerce-custom.rs index 35927bde027a3..24d83eb5343ec 100644 --- a/src/test/run-pass/dynamically-sized-types/dst-coerce-custom.rs +++ b/src/test/run-pass/dynamically-sized-types/dst-coerce-custom.rs @@ -36,7 +36,7 @@ fn main() { // Trait objects. let a: Bar = Bar { x: &42 }; - let b: Bar = a; + let b: Bar = a; unsafe { assert_eq!((*b.x).get(), 42); } diff --git a/src/test/run-pass/dynamically-sized-types/dst-coerce-rc.rs b/src/test/run-pass/dynamically-sized-types/dst-coerce-rc.rs index bbd0b1f8be1f7..683fa6850fd81 100644 --- a/src/test/run-pass/dynamically-sized-types/dst-coerce-rc.rs +++ b/src/test/run-pass/dynamically-sized-types/dst-coerce-rc.rs @@ -26,17 +26,17 @@ fn main() { assert_eq!(b[2], 3); let a: Rc = Rc::new(42); - let b: Rc = a.clone(); + let b: Rc = a.clone(); assert_eq!(b.get(), 42); let c: Weak = Rc::downgrade(&a); - let d: Weak = c.clone(); + let d: Weak = c.clone(); let _c = b.clone(); let a: Rc> = Rc::new(RefCell::new(42)); - let b: Rc> = a.clone(); + let b: Rc> = a.clone(); assert_eq!(b.borrow().get(), 42); // FIXME - let c: Weak> = Rc::downgrade(&a) as Weak<_>; + let c: Weak> = Rc::downgrade(&a) as Weak<_>; } diff --git a/src/test/run-pass/dynamically-sized-types/dst-coercions.rs b/src/test/run-pass/dynamically-sized-types/dst-coercions.rs index 06c2892b69ea2..66688e93fb80d 100644 --- a/src/test/run-pass/dynamically-sized-types/dst-coercions.rs +++ b/src/test/run-pass/dynamically-sized-types/dst-coercions.rs @@ -9,20 +9,20 @@ trait T { fn dummy(&self) { } } impl T for S {} pub fn main() { - let x: &T = &S; + let x: &dyn T = &S; // Test we can convert from &-ptr to *-ptr of trait objects - let x: *const T = &S; + let x: *const dyn T = &S; // Test we can convert from &-ptr to *-ptr of struct pointer (not DST) let x: *const S = &S; // As above, but mut - let x: &mut T = &mut S; - let x: *mut T = &mut S; + let x: &mut dyn T = &mut S; + let x: *mut dyn T = &mut S; let x: *mut S = &mut S; // Test we can change the mutability from mut to const. - let x: &T = &mut S; - let x: *const T = &mut S; + let x: &dyn T = &mut S; + let x: *const dyn T = &mut S; } diff --git a/src/test/run-pass/dynamically-sized-types/dst-field-align.rs b/src/test/run-pass/dynamically-sized-types/dst-field-align.rs index 9c81f5652d1ff..6c338e99912ec 100644 --- a/src/test/run-pass/dynamically-sized-types/dst-field-align.rs +++ b/src/test/run-pass/dynamically-sized-types/dst-field-align.rs @@ -26,7 +26,7 @@ fn main() { // Test that zero-offset works properly let b : Baz = Baz { a: 7 }; assert_eq!(b.a.get(), 7); - let b : &Baz = &b; + let b : &Baz = &b; assert_eq!(b.a.get(), 7); // Test that the field is aligned properly @@ -34,7 +34,7 @@ fn main() { assert_eq!(f.b.get(), 11); let ptr1 : *const u8 = &f.b as *const _ as *const u8; - let f : &Foo = &f; + let f : &Foo = &f; let ptr2 : *const u8 = &f.b as *const _ as *const u8; assert_eq!(f.b.get(), 11); @@ -44,13 +44,13 @@ fn main() { // Test that nested DSTs work properly let f : Foo> = Foo { a: 0, b: Foo { a: 1, b: 17 }}; assert_eq!(f.b.b.get(), 17); - let f : &Foo> = &f; + let f : &Foo> = &f; assert_eq!(f.b.b.get(), 17); // Test that get the pointer via destructuring works let f : Foo = Foo { a: 0, b: 11 }; - let f : &Foo = &f; + let f : &Foo = &f; let &Foo { a: _, b: ref bar } = f; assert_eq!(bar.get(), 11); diff --git a/src/test/run-pass/dynamically-sized-types/dst-index.rs b/src/test/run-pass/dynamically-sized-types/dst-index.rs index 0728599f3239e..980d99a6d6c11 100644 --- a/src/test/run-pass/dynamically-sized-types/dst-index.rs +++ b/src/test/run-pass/dynamically-sized-types/dst-index.rs @@ -19,11 +19,11 @@ impl Index for S { struct T; impl Index for T { - type Output = Debug + 'static; + type Output = dyn Debug + 'static; - fn index<'a>(&'a self, idx: usize) -> &'a (Debug + 'static) { + fn index<'a>(&'a self, idx: usize) -> &'a (dyn Debug + 'static) { static X: usize = 42; - &X as &(Debug + 'static) + &X as &(dyn Debug + 'static) } } diff --git a/src/test/run-pass/dynamically-sized-types/dst-raw.rs b/src/test/run-pass/dynamically-sized-types/dst-raw.rs index 949adbbefcea7..0893b02e74e82 100644 --- a/src/test/run-pass/dynamically-sized-types/dst-raw.rs +++ b/src/test/run-pass/dynamically-sized-types/dst-raw.rs @@ -24,7 +24,7 @@ struct Foo { pub fn main() { // raw trait object let x = A { f: 42 }; - let z: *const Trait = &x; + let z: *const dyn Trait = &x; let r = unsafe { (&*z).foo() }; @@ -32,7 +32,7 @@ pub fn main() { // raw DST struct let p = Foo {f: A { f: 42 }}; - let o: *const Foo = &p; + let o: *const Foo = &p; let r = unsafe { (&*o).f.foo() }; @@ -40,7 +40,7 @@ pub fn main() { // raw DST tuple let p = (A { f: 42 },); - let o: *const (Trait,) = &p; + let o: *const (dyn Trait,) = &p; let r = unsafe { (&*o).0.foo() }; @@ -84,21 +84,21 @@ pub fn main() { // all of the above with *mut let mut x = A { f: 42 }; - let z: *mut Trait = &mut x; + let z: *mut dyn Trait = &mut x; let r = unsafe { (&*z).foo() }; assert_eq!(r, 42); let mut p = Foo {f: A { f: 42 }}; - let o: *mut Foo = &mut p; + let o: *mut Foo = &mut p; let r = unsafe { (&*o).f.foo() }; assert_eq!(r, 42); let mut p = (A { f: 42 },); - let o: *mut (Trait,) = &mut p; + let o: *mut (dyn Trait,) = &mut p; let r = unsafe { (&*o).0.foo() }; diff --git a/src/test/run-pass/dynamically-sized-types/dst-trait-tuple.rs b/src/test/run-pass/dynamically-sized-types/dst-trait-tuple.rs index ca88605ee3a8f..70bcc3de07d29 100644 --- a/src/test/run-pass/dynamically-sized-types/dst-trait-tuple.rs +++ b/src/test/run-pass/dynamically-sized-types/dst-trait-tuple.rs @@ -38,7 +38,7 @@ impl ToBar for Bar1 { } // x is a fat pointer -fn foo(x: &Fat) { +fn foo(x: &Fat) { assert_eq!(x.0, 5); assert_eq!(x.1, "some str"); assert_eq!(x.2.to_bar(), Bar); @@ -49,12 +49,12 @@ fn foo(x: &Fat) { assert_eq!(y.to_val(), 42); } -fn bar(x: &ToBar) { +fn bar(x: &dyn ToBar) { assert_eq!(x.to_bar(), Bar); assert_eq!(x.to_val(), 42); } -fn baz(x: &Fat>) { +fn baz(x: &Fat>) { assert_eq!(x.0, 5); assert_eq!(x.1, "some str"); assert_eq!((x.2).0, 8); @@ -73,20 +73,20 @@ pub fn main() { foo(&f1); let f2 = &f1; foo(f2); - let f3: &Fat = f2; + let f3: &Fat = f2; foo(f3); - let f4: &Fat = &f1; + let f4: &Fat = &f1; foo(f4); - let f5: &Fat = &(5, "some str", Bar1 {f :42}); + let f5: &Fat = &(5, "some str", Bar1 {f :42}); foo(f5); // Zero size object. - let f6: &Fat = &(5, "some str", Bar); + let f6: &Fat = &(5, "some str", Bar); assert_eq!(f6.2.to_bar(), Bar); // &* // - let f7: Box = Box::new(Bar1 {f :42}); + let f7: Box = Box::new(Bar1 {f :42}); bar(&*f7); // Deep nesting @@ -94,10 +94,10 @@ pub fn main() { baz(&f1); let f2 = &f1; baz(f2); - let f3: &Fat> = f2; + let f3: &Fat> = f2; baz(f3); - let f4: &Fat> = &f1; + let f4: &Fat> = &f1; baz(f4); - let f5: &Fat> = &(5, "some str", (8, "deep str", Bar1 {f :42})); + let f5: &Fat> = &(5, "some str", (8, "deep str", Bar1 {f :42})); baz(f5); } diff --git a/src/test/run-pass/dynamically-sized-types/dst-trait.rs b/src/test/run-pass/dynamically-sized-types/dst-trait.rs index 9a9bd12d50f4f..ec6bc72192d4f 100644 --- a/src/test/run-pass/dynamically-sized-types/dst-trait.rs +++ b/src/test/run-pass/dynamically-sized-types/dst-trait.rs @@ -38,7 +38,7 @@ impl ToBar for Bar1 { } // x is a fat pointer -fn foo(x: &Fat) { +fn foo(x: &Fat) { assert_eq!(x.f1, 5); assert_eq!(x.f2, "some str"); assert_eq!(x.ptr.to_bar(), Bar); @@ -49,12 +49,12 @@ fn foo(x: &Fat) { assert_eq!(y.to_val(), 42); } -fn bar(x: &ToBar) { +fn bar(x: &dyn ToBar) { assert_eq!(x.to_bar(), Bar); assert_eq!(x.to_val(), 42); } -fn baz(x: &Fat>) { +fn baz(x: &Fat>) { assert_eq!(x.f1, 5); assert_eq!(x.f2, "some str"); assert_eq!(x.ptr.f1, 8); @@ -73,20 +73,20 @@ pub fn main() { foo(&f1); let f2 = &f1; foo(f2); - let f3: &Fat = f2; + let f3: &Fat = f2; foo(f3); - let f4: &Fat = &f1; + let f4: &Fat = &f1; foo(f4); - let f5: &Fat = &Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + let f5: &Fat = &Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; foo(f5); // Zero size object. - let f6: &Fat = &Fat { f1: 5, f2: "some str", ptr: Bar }; + let f6: &Fat = &Fat { f1: 5, f2: "some str", ptr: Bar }; assert_eq!(f6.ptr.to_bar(), Bar); // &* // - let f7: Box = Box::new(Bar1 {f :42}); + let f7: Box = Box::new(Bar1 {f :42}); bar(&*f7); // Deep nesting @@ -95,11 +95,11 @@ pub fn main() { baz(&f1); let f2 = &f1; baz(f2); - let f3: &Fat> = f2; + let f3: &Fat> = f2; baz(f3); - let f4: &Fat> = &f1; + let f4: &Fat> = &f1; baz(f4); - let f5: &Fat> = + let f5: &Fat> = &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: Bar1 {f :42}} }; baz(f5); } diff --git a/src/test/run-pass/env-args-reverse-iterator.rs b/src/test/run-pass/env-args-reverse-iterator.rs index 78548fd9bc570..d677aa8500103 100644 --- a/src/test/run-pass/env-args-reverse-iterator.rs +++ b/src/test/run-pass/env-args-reverse-iterator.rs @@ -1,5 +1,6 @@ // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::env::args; use std::process::Command; diff --git a/src/test/run-pass/env-funky-keys.rs b/src/test/run-pass/env-funky-keys.rs index 79f32bd6c29e3..3b236e2b3afbd 100644 --- a/src/test/run-pass/env-funky-keys.rs +++ b/src/test/run-pass/env-funky-keys.rs @@ -4,6 +4,7 @@ // ignore-windows // ignore-cloudabi no execve // ignore-emscripten no execve +// ignore-sgx no execve // no-prefer-dynamic #![feature(rustc_private)] diff --git a/src/test/run-pass/env-home-dir.rs b/src/test/run-pass/env-home-dir.rs index 90b753447308f..62f45d0a2eb2a 100644 --- a/src/test/run-pass/env-home-dir.rs +++ b/src/test/run-pass/env-home-dir.rs @@ -2,6 +2,7 @@ #![allow(deprecated)] // ignore-cloudabi no environment variables present // ignore-emscripten env vars don't work? +// ignore-sgx env vars cannot be modified use std::env::*; use std::path::PathBuf; diff --git a/src/test/run-pass/exec-env.rs b/src/test/run-pass/exec-env.rs index 1327b558fc967..c1b8e0825143b 100644 --- a/src/test/run-pass/exec-env.rs +++ b/src/test/run-pass/exec-env.rs @@ -1,6 +1,7 @@ // exec-env:TEST_EXEC_ENV=22 // ignore-cloudabi no env vars // ignore-emscripten FIXME: issue #31622 +// ignore-sgx unsupported use std::env; diff --git a/src/test/run-pass/existential_type.rs b/src/test/run-pass/existential_type.rs index dfb195ec83062..b36435cf113f1 100644 --- a/src/test/run-pass/existential_type.rs +++ b/src/test/run-pass/existential_type.rs @@ -68,14 +68,14 @@ fn my_other_iter(u: U) -> MyOtherIter { } trait Trait {} -existential type GenericBound<'a, T: Trait>: 'a; +existential type GenericBound<'a, T: Trait>: Sized + 'a; fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> { t } mod pass_through { - pub existential type Passthrough: 'static; + pub existential type Passthrough: Sized + 'static; fn define_passthrough(t: T) -> Passthrough { t diff --git a/src/test/run-pass/extern/extern-prelude-core.rs b/src/test/run-pass/extern/extern-prelude-core.rs index a5d31009f9cee..f0d43404b0046 100644 --- a/src/test/run-pass/extern/extern-prelude-core.rs +++ b/src/test/run-pass/extern/extern-prelude-core.rs @@ -1,5 +1,5 @@ // run-pass -#![feature(extern_prelude, lang_items, start, alloc)] +#![feature(extern_prelude, lang_items, start)] #![no_std] extern crate std as other; diff --git a/src/test/run-pass/extern/extern-prelude-core.stderr b/src/test/run-pass/extern/extern-prelude-core.stderr index 417483af707ca..8d2a0b7425f2a 100644 --- a/src/test/run-pass/extern/extern-prelude-core.stderr +++ b/src/test/run-pass/extern/extern-prelude-core.stderr @@ -1,7 +1,7 @@ warning: the feature `extern_prelude` has been stable since 1.30.0 and no longer requires an attribute to enable --> $DIR/extern-prelude-core.rs:2:12 | -LL | #![feature(extern_prelude, lang_items, start, alloc)] +LL | #![feature(extern_prelude, lang_items, start)] | ^^^^^^^^^^^^^^ | = note: #[warn(stable_features)] on by default diff --git a/src/test/run-pass/extern/extern-types-trait-impl.rs b/src/test/run-pass/extern/extern-types-trait-impl.rs index ac4c70a71ce76..6cce6c723c5a2 100644 --- a/src/test/run-pass/extern/extern-types-trait-impl.rs +++ b/src/test/run-pass/extern/extern-types-trait-impl.rs @@ -18,7 +18,7 @@ impl Foo for A { fn assert_foo() { } -fn use_foo(x: &Foo) { +fn use_foo(x: &dyn Foo) { x.foo(); } diff --git a/src/test/run-pass/fat-lto.rs b/src/test/run-pass/fat-lto.rs index 7e50b44430c11..fb741200d3cb7 100644 --- a/src/test/run-pass/fat-lto.rs +++ b/src/test/run-pass/fat-lto.rs @@ -4,4 +4,3 @@ fn main() { println!("hello!"); } - diff --git a/src/test/run-pass/fat-ptr-cast.rs b/src/test/run-pass/fat-ptr-cast.rs index 367b57d5ea0a2..1943abe9e14da 100644 --- a/src/test/run-pass/fat-ptr-cast.rs +++ b/src/test/run-pass/fat-ptr-cast.rs @@ -25,7 +25,7 @@ fn main() { assert_eq!(a as usize, b as *const () as usize); // And conversion to a void pointer/address for trait objects too. - let a: *mut Foo = &mut Bar; + let a: *mut dyn Foo = &mut Bar; let b = a as *mut (); let c = a as *const () as usize; let d = unsafe { diff --git a/src/test/run-pass/fds-are-cloexec.rs b/src/test/run-pass/fds-are-cloexec.rs index 3bc0ceb5cf2fa..c4091f84af98c 100644 --- a/src/test/run-pass/fds-are-cloexec.rs +++ b/src/test/run-pass/fds-are-cloexec.rs @@ -3,6 +3,7 @@ // ignore-cloudabi no processes // ignore-emscripten no processes // ignore-haiku +// ignore-sgx no processes #![feature(rustc_private)] diff --git a/src/test/run-pass/for-loop-while/for-loop-no-std.rs b/src/test/run-pass/for-loop-while/for-loop-no-std.rs index 877429f5d3900..65a33c5f16f1d 100644 --- a/src/test/run-pass/for-loop-while/for-loop-no-std.rs +++ b/src/test/run-pass/for-loop-while/for-loop-no-std.rs @@ -1,6 +1,6 @@ // run-pass #![allow(unused_imports)] -#![feature(lang_items, start, alloc)] +#![feature(lang_items, start)] #![no_std] extern crate std as other; diff --git a/src/test/run-pass/foreign/foreign-fn-linkname.rs b/src/test/run-pass/foreign/foreign-fn-linkname.rs index 5ed8d19bc5a42..1f048159064b3 100644 --- a/src/test/run-pass/foreign/foreign-fn-linkname.rs +++ b/src/test/run-pass/foreign/foreign-fn-linkname.rs @@ -1,5 +1,6 @@ // run-pass // ignore-wasm32-bare no libc to test ffi with +// ignore-sgx no libc #![feature(rustc_private)] diff --git a/src/test/run-pass/format-no-std.rs b/src/test/run-pass/format-no-std.rs index 0f3a5c277b4c5..32f7a4a07c499 100644 --- a/src/test/run-pass/format-no-std.rs +++ b/src/test/run-pass/format-no-std.rs @@ -1,6 +1,6 @@ // ignore-emscripten no no_std executables -#![feature(lang_items, start, alloc)] +#![feature(lang_items, start)] #![no_std] extern crate std as other; diff --git a/src/test/run-pass/functions-closures/closure-expected-type/expect-infer-supply-two-infers.rs b/src/test/run-pass/functions-closures/closure-expected-type/expect-infer-supply-two-infers.rs index fb0bc3c436d9b..6d5a9876c373c 100644 --- a/src/test/run-pass/functions-closures/closure-expected-type/expect-infer-supply-two-infers.rs +++ b/src/test/run-pass/functions-closures/closure-expected-type/expect-infer-supply-two-infers.rs @@ -12,7 +12,7 @@ fn expect_free_supply_free<'x>(x: &'x u32) { x.push(22_u32); // ...since we now know the type of `y` and can resolve the method call. - y.wrapping_add(1); + let _ = y.wrapping_add(1); }); } diff --git a/src/test/run-pass/functions-closures/closure-expected-type/issue-38714.rs b/src/test/run-pass/functions-closures/closure-expected-type/issue-38714.rs index 96b7a66d07587..e97785b5cacdf 100644 --- a/src/test/run-pass/functions-closures/closure-expected-type/issue-38714.rs +++ b/src/test/run-pass/functions-closures/closure-expected-type/issue-38714.rs @@ -5,7 +5,7 @@ struct UsizeRef<'a> { a: &'a usize } -type RefTo = Box Fn(&'r Vec) -> UsizeRef<'r>>; +type RefTo = Box Fn(&'r Vec) -> UsizeRef<'r>>; fn ref_to<'a>(vec: &'a Vec) -> UsizeRef<'a> { UsizeRef{ a: &vec[0]} diff --git a/src/test/run-pass/functions-closures/parallel-codegen-closures.rs b/src/test/run-pass/functions-closures/parallel-codegen-closures.rs index 921fbaf4942ca..79759daba501c 100644 --- a/src/test/run-pass/functions-closures/parallel-codegen-closures.rs +++ b/src/test/run-pass/functions-closures/parallel-codegen-closures.rs @@ -6,7 +6,6 @@ // Tests parallel codegen - this can fail if the symbol for the anonymous // closure in `sum` pollutes the second codegen unit from the first. -// ignore-bitrig // compile-flags: -C codegen_units=2 #![feature(iter_arith)] diff --git a/src/test/run-pass/futures-api.rs b/src/test/run-pass/futures-api.rs index fd4b585d34572..ee77053fd5b6a 100644 --- a/src/test/run-pass/futures-api.rs +++ b/src/test/run-pass/futures-api.rs @@ -1,8 +1,5 @@ // aux-build:arc_wake.rs -#![feature(arbitrary_self_types, futures_api)] -#![allow(unused)] - extern crate arc_wake; use std::future::Future; @@ -12,7 +9,7 @@ use std::sync::{ atomic::{self, AtomicUsize}, }; use std::task::{ - Poll, Waker, + Context, Poll, }; use arc_wake::ArcWake; @@ -21,7 +18,10 @@ struct Counter { } impl ArcWake for Counter { - fn wake(arc_self: &Arc) { + fn wake(self: Arc) { + Self::wake_by_ref(&self) + } + fn wake_by_ref(arc_self: &Arc) { arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); } } @@ -30,10 +30,11 @@ struct MyFuture; impl Future for MyFuture { type Output = (); - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // Wake twice - waker.wake(); - waker.wake(); + let waker = cx.waker(); + waker.wake_by_ref(); + waker.wake_by_ref(); Poll::Ready(()) } } @@ -44,10 +45,11 @@ fn test_waker() { }); let waker = ArcWake::into_waker(counter.clone()); assert_eq!(2, Arc::strong_count(&counter)); - - assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(&waker)); - assert_eq!(2, counter.wakes.load(atomic::Ordering::SeqCst)); - + { + let mut context = Context::from_waker(&waker); + assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(&mut context)); + assert_eq!(2, counter.wakes.load(atomic::Ordering::SeqCst)); + } drop(waker); assert_eq!(1, Arc::strong_count(&counter)); } diff --git a/src/test/run-pass/generator/addassign-yield.rs b/src/test/run-pass/generator/addassign-yield.rs new file mode 100644 index 0000000000000..6a417936384b9 --- /dev/null +++ b/src/test/run-pass/generator/addassign-yield.rs @@ -0,0 +1,34 @@ +// Regression test for broken MIR error (#61442) +// Due to the two possible evaluation orders for +// a '+=' expression (depending on whether or not the 'AddAssign' trait +// is being used), we were failing to account for all types that might +// possibly be live across a yield point. + +#![feature(generators)] + +fn foo() { + let _x = static || { + let mut s = String::new(); + s += { yield; "" }; + }; + + let _y = static || { + let x = &mut 0; + *{ yield; x } += match String::new() { _ => 0 }; + }; + + // Please don't ever actually write something like this + let _z = static || { + let x = &mut 0; + *{ + let inner = &mut 1; + *{ yield (); inner } += match String::new() { _ => 1}; + yield; + x + } += match String::new() { _ => 2 }; + }; +} + +fn main() { + foo() +} diff --git a/src/test/run-pass/generator/drop-and-replace.rs b/src/test/run-pass/generator/drop-and-replace.rs new file mode 100644 index 0000000000000..042e1276db5c6 --- /dev/null +++ b/src/test/run-pass/generator/drop-and-replace.rs @@ -0,0 +1,44 @@ +// Regression test for incorrect DropAndReplace behavior introduced in #60840 +// and fixed in #61373. When combined with the optimization implemented in +// #60187, this produced incorrect code for generators when a saved local was +// re-assigned. + +#![feature(generators, generator_trait)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; + +#[derive(Debug, PartialEq)] +struct Foo(i32); + +impl Drop for Foo { + fn drop(&mut self) { } +} + +fn main() { + let mut a = || { + let mut x = Foo(4); + yield; + assert_eq!(x.0, 4); + + // At one point this tricked our dataflow analysis into thinking `x` was + // StorageDead after the assignment. + x = Foo(5); + assert_eq!(x.0, 5); + + { + let y = Foo(6); + yield; + assert_eq!(y.0, 6); + } + + assert_eq!(x.0, 5); + }; + + loop { + match Pin::new(&mut a).resume() { + GeneratorState::Complete(()) => break, + _ => (), + } + } +} diff --git a/src/test/run-pass/generator/issue-57084.rs b/src/test/run-pass/generator/issue-57084.rs new file mode 100644 index 0000000000000..8aaa6a0e427d1 --- /dev/null +++ b/src/test/run-pass/generator/issue-57084.rs @@ -0,0 +1,28 @@ +// This issue reproduces an ICE on compile (E.g. fails on 2018-12-19 nightly). +// "cannot relate bound region: ReLateBound(DebruijnIndex(1), BrAnon(1)) <= '_#1r" +// run-pass +// edition:2018 +#![feature(generators,generator_trait)] +use std::ops::Generator; + +fn with(f: F) -> impl Generator +where F: Fn() -> () +{ + move || { + loop { + match f() { + _ => yield, + } + } + } +} + +fn main() { + let data = &vec![1]; + || { + let _to_pin = with(move || println!("{:p}", data)); + loop { + yield + } + }; +} diff --git a/src/test/run-pass/generator/issue-58888.rs b/src/test/run-pass/generator/issue-58888.rs new file mode 100644 index 0000000000000..43b37a9afc2cc --- /dev/null +++ b/src/test/run-pass/generator/issue-58888.rs @@ -0,0 +1,27 @@ +// run-pass +// compile-flags: -g + +#![feature(generators, generator_trait)] + +use std::ops::Generator; + +struct Database; + +impl Database { + fn get_connection(&self) -> impl Iterator { + Some(()).into_iter() + } + + fn check_connection(&self) -> impl Generator + '_ { + move || { + let iter = self.get_connection(); + for i in iter { + yield i + } + } + } +} + +fn main() { + Database.check_connection(); +} diff --git a/src/test/run-pass/generator/overlap-locals.rs b/src/test/run-pass/generator/overlap-locals.rs new file mode 100644 index 0000000000000..704484a480e26 --- /dev/null +++ b/src/test/run-pass/generator/overlap-locals.rs @@ -0,0 +1,27 @@ +#![feature(generators)] + +fn main() { + let a = || { + { + let w: i32 = 4; + yield; + println!("{:?}", w); + } + { + let x: i32 = 5; + yield; + println!("{:?}", x); + } + { + let y: i32 = 6; + yield; + println!("{:?}", y); + } + { + let z: i32 = 7; + yield; + println!("{:?}", z); + } + }; + assert_eq!(8, std::mem::size_of_val(&a)); +} diff --git a/src/test/run-pass/generator/size-moved-locals.rs b/src/test/run-pass/generator/size-moved-locals.rs new file mode 100644 index 0000000000000..37e2e0cfdcccf --- /dev/null +++ b/src/test/run-pass/generator/size-moved-locals.rs @@ -0,0 +1,62 @@ +// Test that we don't duplicate storage for a variable that is moved to another +// binding. This used to happen in the presence of unwind and drop edges (see +// `complex` below.) +// +// The exact sizes here can change (we'd like to know when they do). What we +// don't want to see is the `complex` generator size being upwards of 2048 bytes +// (which would indicate it is reserving space for two copies of Foo.) +// +// See issue #59123 for a full explanation. + +// edition:2018 + +#![feature(generators, generator_trait)] + +use std::ops::Generator; + +const FOO_SIZE: usize = 1024; +struct Foo([u8; FOO_SIZE]); + +impl Drop for Foo { + fn drop(&mut self) {} +} + +fn move_before_yield() -> impl Generator { + static || { + let first = Foo([0; FOO_SIZE]); + let _second = first; + yield; + // _second dropped here + } +} + +fn noop() {} + +fn move_before_yield_with_noop() -> impl Generator { + static || { + let first = Foo([0; FOO_SIZE]); + noop(); + let _second = first; + yield; + // _second dropped here + } +} + +// Today we don't have NRVO (we allocate space for both `first` and `second`,) +// but we can overlap `first` with `_third`. +fn overlap_move_points() -> impl Generator { + static || { + let first = Foo([0; FOO_SIZE]); + yield; + let second = first; + yield; + let _third = second; + yield; + } +} + +fn main() { + assert_eq!(1028, std::mem::size_of_val(&move_before_yield())); + assert_eq!(1032, std::mem::size_of_val(&move_before_yield_with_noop())); + assert_eq!(2056, std::mem::size_of_val(&overlap_move_points())); +} diff --git a/src/test/run-pass/generator/yield-subtype.rs b/src/test/run-pass/generator/yield-subtype.rs index c38524857b4a2..fe88d424dd165 100644 --- a/src/test/run-pass/generator/yield-subtype.rs +++ b/src/test/run-pass/generator/yield-subtype.rs @@ -2,9 +2,6 @@ #![allow(dead_code)] #![allow(dead_code)] -// revisions:lexical nll -#![cfg_attr(nll, feature(nll))] - #![feature(generators)] fn bar<'a>() { diff --git a/src/test/run-pass/generics/generic-object.rs b/src/test/run-pass/generics/generic-object.rs index 054425989c318..870ff980ec64d 100644 --- a/src/test/run-pass/generics/generic-object.rs +++ b/src/test/run-pass/generics/generic-object.rs @@ -17,6 +17,6 @@ impl Foo for S { pub fn main() { let x = box S { x: 1 }; - let y = x as Box>; + let y = x as Box>; assert_eq!(y.get(), 1); } diff --git a/src/test/run-pass/hashmap-memory.rs b/src/test/run-pass/hashmap-memory.rs index 364661e565e2c..987a3e414f5c0 100644 --- a/src/test/run-pass/hashmap-memory.rs +++ b/src/test/run-pass/hashmap-memory.rs @@ -19,7 +19,7 @@ mod map_reduce { use std::str; use std::thread; - pub type putter<'a> = Box; + pub type putter<'a> = Box; pub type mapper = extern fn(String, putter); diff --git a/src/test/run-pass/higher-rank-trait-bounds/hrtb-binder-levels-in-object-types.rs b/src/test/run-pass/higher-rank-trait-bounds/hrtb-binder-levels-in-object-types.rs index 1591d616cac78..cc766c0605c9f 100644 --- a/src/test/run-pass/higher-rank-trait-bounds/hrtb-binder-levels-in-object-types.rs +++ b/src/test/run-pass/higher-rank-trait-bounds/hrtb-binder-levels-in-object-types.rs @@ -19,7 +19,7 @@ struct Tcx<'tcx> { impl<'tcx> Typer<'tcx> for Tcx<'tcx> { } -fn g<'tcx>(typer: &Typer<'tcx>) { +fn g<'tcx>(typer: &dyn Typer<'tcx>) { } fn check_static_type<'x>(tcx: &Tcx<'x>) { diff --git a/src/test/run-pass/higher-rank-trait-bounds/hrtb-debruijn-object-types-in-closures.rs b/src/test/run-pass/higher-rank-trait-bounds/hrtb-debruijn-object-types-in-closures.rs index 09152970fdcd2..8431226a3ece1 100644 --- a/src/test/run-pass/higher-rank-trait-bounds/hrtb-debruijn-object-types-in-closures.rs +++ b/src/test/run-pass/higher-rank-trait-bounds/hrtb-debruijn-object-types-in-closures.rs @@ -7,7 +7,7 @@ trait Typer<'tcx> { fn dummy(&self) { } } -fn g(_: F) where F: FnOnce(&Typer) {} +fn g(_: F) where F: FnOnce(&dyn Typer) {} fn h() { g(|typer| typer.dummy()) diff --git a/src/test/run-pass/higher-rank-trait-bounds/hrtb-fn-like-trait-object.rs b/src/test/run-pass/higher-rank-trait-bounds/hrtb-fn-like-trait-object.rs index 7ef8ea046b81a..ff84ad9d2988e 100644 --- a/src/test/run-pass/higher-rank-trait-bounds/hrtb-fn-like-trait-object.rs +++ b/src/test/run-pass/higher-rank-trait-bounds/hrtb-fn-like-trait-object.rs @@ -6,7 +6,7 @@ trait FnLike { fn call(&self, arg: A) -> R; } -type FnObject<'b> = for<'a> FnLike<&'a isize, &'a isize> + 'b; +type FnObject<'b> = dyn for<'a> FnLike<&'a isize, &'a isize> + 'b; struct Identity; diff --git a/src/test/run-pass/higher-rank-trait-bounds/hrtb-parse.rs b/src/test/run-pass/higher-rank-trait-bounds/hrtb-parse.rs index 3fb0b3290eb02..1fab9758c5c83 100644 --- a/src/test/run-pass/higher-rank-trait-bounds/hrtb-parse.rs +++ b/src/test/run-pass/higher-rank-trait-bounds/hrtb-parse.rs @@ -24,8 +24,8 @@ fn foo01 Get<&'a i32, &'a i32>>(t: T) // Parse HRTB with explicit `for` in various sorts of types: -fn foo10(t: Box Get>) { } -fn foo11(t: Box Fn(i32) -> i32>) { } +fn foo10(t: Box Get>) { } +fn foo11(t: Box Fn(i32) -> i32>) { } fn foo20(t: for<'a> fn(i32) -> i32) { } fn foo21(t: for<'a> unsafe fn(i32) -> i32) { } diff --git a/src/test/run-pass/higher-rank-trait-bounds/hrtb-precedence-of-plus.rs b/src/test/run-pass/higher-rank-trait-bounds/hrtb-precedence-of-plus.rs index 5fda4b826e00c..6834c392d4e96 100644 --- a/src/test/run-pass/higher-rank-trait-bounds/hrtb-precedence-of-plus.rs +++ b/src/test/run-pass/higher-rank-trait-bounds/hrtb-precedence-of-plus.rs @@ -6,7 +6,7 @@ // 'static` and not `Fn(isize) -> (isize + 'static)`. The latter would // cause a compilation error. Issue #18772. -fn adder(y: isize) -> Box isize + 'static> { +fn adder(y: isize) -> Box isize + 'static> { Box::new(move |x| y + x) } diff --git a/src/test/run-pass/higher-rank-trait-bounds/hrtb-resolve-lifetime.rs b/src/test/run-pass/higher-rank-trait-bounds/hrtb-resolve-lifetime.rs index 917f6f9611844..b97fdf4df508f 100644 --- a/src/test/run-pass/higher-rank-trait-bounds/hrtb-resolve-lifetime.rs +++ b/src/test/run-pass/higher-rank-trait-bounds/hrtb-resolve-lifetime.rs @@ -8,7 +8,7 @@ trait FnLike { fn call(&self, arg: A) -> R; } -type FnObject<'b> = for<'a> FnLike<&'a isize, &'a isize> + 'b; +type FnObject<'b> = dyn for<'a> FnLike<&'a isize, &'a isize> + 'b; fn main() { } diff --git a/src/test/run-pass/higher-rank-trait-bounds/hrtb-trait-object-paren-notation.rs b/src/test/run-pass/higher-rank-trait-bounds/hrtb-trait-object-paren-notation.rs index 0ed8f7ee52ae9..d8c726cdd71e5 100644 --- a/src/test/run-pass/higher-rank-trait-bounds/hrtb-trait-object-paren-notation.rs +++ b/src/test/run-pass/higher-rank-trait-bounds/hrtb-trait-object-paren-notation.rs @@ -5,7 +5,7 @@ trait FnLike { fn call(&self, arg: A) -> R; } -type FnObject<'b> = for<'a> FnLike<(&'a i32,), &'a i32> + 'b; +type FnObject<'b> = dyn for<'a> FnLike<(&'a i32,), &'a i32> + 'b; struct Identity; diff --git a/src/test/run-pass/higher-rank-trait-bounds/hrtb-trait-object-passed-to-closure.rs b/src/test/run-pass/higher-rank-trait-bounds/hrtb-trait-object-passed-to-closure.rs index 4cb9242f0ed80..41ebb3f5a14ab 100644 --- a/src/test/run-pass/higher-rank-trait-bounds/hrtb-trait-object-passed-to-closure.rs +++ b/src/test/run-pass/higher-rank-trait-bounds/hrtb-trait-object-passed-to-closure.rs @@ -17,7 +17,7 @@ struct NoAnn<'ast> { impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> { } -fn foo<'ast, G>(f: Option<&'ast usize>, g: G) where G: FnOnce(&PrinterSupport) { +fn foo<'ast, G>(f: Option<&'ast usize>, g: G) where G: FnOnce(&dyn PrinterSupport) { let annotation = NoAnn { f: f }; g(&annotation) } diff --git a/src/test/run-pass/if-ret.stderr b/src/test/run-pass/if-ret.stderr new file mode 100644 index 0000000000000..a64281833e5cb --- /dev/null +++ b/src/test/run-pass/if-ret.stderr @@ -0,0 +1,8 @@ +warning: unreachable block in `if` expression + --> $DIR/if-ret.rs:4:24 + | +LL | fn foo() { if (return) { } } + | ^^^ + | + = note: #[warn(unreachable_code)] on by default + diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 56222fa46f7c9..6660f393f7dac 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -93,7 +93,7 @@ pub fn main() { t!(format!("{:#4}", C), "☃123"); t!(format!("{:b}", D), "aa☃bb"); - let a: &fmt::Debug = &1; + let a: &dyn fmt::Debug = &1; t!(format!("{:?}", a), "1"); @@ -238,7 +238,6 @@ pub fn main() { // Basic test to make sure that we can invoke the `write!` macro with an // fmt::Write instance. fn test_write() { - use std::fmt::Write; let mut buf = String::new(); write!(&mut buf, "{}", 3); { @@ -267,7 +266,6 @@ fn test_print() { // Just make sure that the macros are defined, there's not really a lot that we // can do with them just yet (to test the output) fn test_format_args() { - use std::fmt::Write; let mut buf = String::new(); { let w = &mut buf; diff --git a/src/test/run-pass/impl-for-never.rs b/src/test/run-pass/impl-for-never.rs index d2dbae61767b7..a5287123008f2 100644 --- a/src/test/run-pass/impl-for-never.rs +++ b/src/test/run-pass/impl-for-never.rs @@ -23,4 +23,3 @@ fn main() { println!("! is {}", ::stringify_type()); println!("None is {}", maybe_stringify(None::)); } - diff --git a/src/test/run-pass/impl-trait-in-bindings.rs b/src/test/run-pass/impl-trait-in-bindings.rs index 9a1f53b48933a..1e3a641b7cf94 100644 --- a/src/test/run-pass/impl-trait-in-bindings.rs +++ b/src/test/run-pass/impl-trait-in-bindings.rs @@ -1,4 +1,5 @@ #![feature(impl_trait_in_bindings)] +//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash use std::fmt::Debug; diff --git a/src/test/run-pass/impl-trait-in-bindings.stderr b/src/test/run-pass/impl-trait-in-bindings.stderr new file mode 100644 index 0000000000000..4896deb9d5c91 --- /dev/null +++ b/src/test/run-pass/impl-trait-in-bindings.stderr @@ -0,0 +1,6 @@ +warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash + --> $DIR/impl-trait-in-bindings.rs:1:12 + | +LL | #![feature(impl_trait_in_bindings)] + | ^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/src/test/run-pass/impl-trait/example-calendar.rs b/src/test/run-pass/impl-trait/example-calendar.rs index cd3d48f1a03b2..f1b1656745e7c 100644 --- a/src/test/run-pass/impl-trait/example-calendar.rs +++ b/src/test/run-pass/impl-trait/example-calendar.rs @@ -1,8 +1,5 @@ // run-pass -// revisions: normal nll -//[nll] compile-flags:-Zborrowck=mir - #![feature(fn_traits, step_trait, unboxed_closures, @@ -183,6 +180,10 @@ impl std::iter::Step for NaiveDate { fn add_usize(&self, _: usize) -> Option { unimplemented!() } + + fn sub_usize(&self, _: usize) -> Option { + unimplemented!() + } } #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs index 5a21e1dd81759..9a9843375e4c5 100644 --- a/src/test/run-pass/impl-trait/lifetimes.rs +++ b/src/test/run-pass/impl-trait/lifetimes.rs @@ -1,6 +1,7 @@ // run-pass #![allow(warnings)] +#![feature(generators)] use std::fmt::Debug; @@ -112,6 +113,11 @@ impl<'unnecessary_lifetime> MyVec { fn iter_doesnt_capture_unnecessary_lifetime<'s>(&'s self) -> impl Iterator { self.0.iter().flat_map(|inner_vec| inner_vec.iter()) } + + fn generator_doesnt_capture_unnecessary_lifetime<'s: 's>() -> impl Sized { + || yield + } } + fn main() {} diff --git a/src/test/run-pass/inc-range-pat.rs b/src/test/run-pass/inc-range-pat.rs index 6b99a9d0a7422..a648ff17492ee 100644 --- a/src/test/run-pass/inc-range-pat.rs +++ b/src/test/run-pass/inc-range-pat.rs @@ -1,5 +1,7 @@ // Test old and new syntax for inclusive range patterns. +#![allow(ellipsis_inclusive_range_patterns)] + fn main() { assert!(match 42 { 0 ... 100 => true, _ => false }); assert!(match 42 { 0 ..= 100 => true, _ => false }); @@ -7,4 +9,3 @@ fn main() { assert!(match 'x' { 'a' ... 'z' => true, _ => false }); assert!(match 'x' { 'a' ..= 'z' => true, _ => false }); } - diff --git a/src/test/run-pass/inherit-env.rs b/src/test/run-pass/inherit-env.rs index 856d3a5f72d34..229953f1b18d4 100644 --- a/src/test/run-pass/inherit-env.rs +++ b/src/test/run-pass/inherit-env.rs @@ -1,5 +1,6 @@ // ignore-emscripten // ignore-wasm32 +// ignore-sgx no processes use std::env; use std::process::Command; @@ -22,4 +23,3 @@ fn main() { k, v, output); } } - diff --git a/src/test/run-pass/intrinsics/intrinsic-alignment.rs b/src/test/run-pass/intrinsics/intrinsic-alignment.rs index 19e5671062054..6a67d04a54cf4 100644 --- a/src/test/run-pass/intrinsics/intrinsic-alignment.rs +++ b/src/test/run-pass/intrinsics/intrinsic-alignment.rs @@ -40,7 +40,7 @@ mod m { } } -#[cfg(target_os = "bitrig")] +#[cfg(target_env = "sgx")] mod m { #[main] #[cfg(target_arch = "x86_64")] diff --git a/src/test/run-pass/invalid_const_promotion.rs b/src/test/run-pass/invalid_const_promotion.rs index 1524373895d9b..ddf4dc42424db 100644 --- a/src/test/run-pass/invalid_const_promotion.rs +++ b/src/test/run-pass/invalid_const_promotion.rs @@ -1,6 +1,7 @@ #![allow(unused_mut)] // ignore-wasm32 // ignore-emscripten +// ignore-sgx no processes // compile-flags: -C debug_assertions=yes @@ -25,7 +26,6 @@ fn foo() { #[cfg(unix)] fn check_status(status: std::process::ExitStatus) { - use libc; use std::os::unix::process::ExitStatusExt; assert!(status.signal() == Some(libc::SIGILL) diff --git a/src/test/run-pass/issue-59020.rs b/src/test/run-pass/issue-59020.rs new file mode 100644 index 0000000000000..e7544934da0c8 --- /dev/null +++ b/src/test/run-pass/issue-59020.rs @@ -0,0 +1,28 @@ +// edition:2018 +// run-pass +// ignore-emscripten no threads support +// ignore-sgx no thread sleep support + +use std::thread; +use std::time::Duration; + +fn main() { + let t1 = thread::spawn(|| { + let sleep = Duration::new(0,100_000); + for _ in 0..100 { + println!("Parking1"); + thread::park_timeout(sleep); + } + }); + + let t2 = thread::spawn(|| { + let sleep = Duration::new(0,100_000); + for _ in 0..100 { + println!("Parking2"); + thread::park_timeout(sleep); + } + }); + + t1.join().expect("Couldn't join thread 1"); + t2.join().expect("Couldn't join thread 2"); +} diff --git a/src/test/run-pass/issues/auxiliary/issue_10031_aux.rs b/src/test/run-pass/issues/auxiliary/issue-10031-aux.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_10031_aux.rs rename to src/test/run-pass/issues/auxiliary/issue-10031-aux.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_12612_1.rs b/src/test/run-pass/issues/auxiliary/issue-12612-1.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_12612_1.rs rename to src/test/run-pass/issues/auxiliary/issue-12612-1.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_12612_2.rs b/src/test/run-pass/issues/auxiliary/issue-12612-2.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_12612_2.rs rename to src/test/run-pass/issues/auxiliary/issue-12612-2.rs diff --git a/src/test/run-pass/issues/auxiliary/issue13507.rs b/src/test/run-pass/issues/auxiliary/issue-13507.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue13507.rs rename to src/test/run-pass/issues/auxiliary/issue-13507.rs diff --git a/src/test/run-pass/issues/auxiliary/issue-17718-aux.rs b/src/test/run-pass/issues/auxiliary/issue-17718-aux.rs index 1cba9709f9116..91abdbff868fe 100644 --- a/src/test/run-pass/issues/auxiliary/issue-17718-aux.rs +++ b/src/test/run-pass/issues/auxiliary/issue-17718-aux.rs @@ -8,4 +8,3 @@ pub const C5: &'static usize = &C4; pub static S1: usize = 3; pub static S2: atomic::AtomicUsize = atomic::AtomicUsize::new(0); - diff --git a/src/test/run-pass/issues/auxiliary/issue_19293.rs b/src/test/run-pass/issues/auxiliary/issue-19293.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_19293.rs rename to src/test/run-pass/issues/auxiliary/issue-19293.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_20389.rs b/src/test/run-pass/issues/auxiliary/issue-20389.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_20389.rs rename to src/test/run-pass/issues/auxiliary/issue-20389.rs diff --git a/src/test/run-pass/issues/auxiliary/issue2170lib.rs b/src/test/run-pass/issues/auxiliary/issue-2170-lib.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue2170lib.rs rename to src/test/run-pass/issues/auxiliary/issue-2170-lib.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_2316_a.rs b/src/test/run-pass/issues/auxiliary/issue-2316-a.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_2316_a.rs rename to src/test/run-pass/issues/auxiliary/issue-2316-a.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_2316_b.rs b/src/test/run-pass/issues/auxiliary/issue-2316-b.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_2316_b.rs rename to src/test/run-pass/issues/auxiliary/issue-2316-b.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_2472_b.rs b/src/test/run-pass/issues/auxiliary/issue-2472-b.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_2472_b.rs rename to src/test/run-pass/issues/auxiliary/issue-2472-b.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_2723_a.rs b/src/test/run-pass/issues/auxiliary/issue-2723-a.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_2723_a.rs rename to src/test/run-pass/issues/auxiliary/issue-2723-a.rs diff --git a/src/test/run-pass/issues/auxiliary/issue-3136-a.rc b/src/test/run-pass/issues/auxiliary/issue-3136-a.rc new file mode 100644 index 0000000000000..cd5fd3145055c --- /dev/null +++ b/src/test/run-pass/issues/auxiliary/issue-3136-a.rc @@ -0,0 +1,4 @@ +#![crate_type = "lib"] + +#[path = "issue-3136-a.rs"] +pub mod issue_3136_a; diff --git a/src/test/run-pass/issues/auxiliary/issue_3136_a.rs b/src/test/run-pass/issues/auxiliary/issue-3136-a.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_3136_a.rs rename to src/test/run-pass/issues/auxiliary/issue-3136-a.rs diff --git a/src/test/run-pass/issues/auxiliary/issue34796aux.rs b/src/test/run-pass/issues/auxiliary/issue-34796-aux.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue34796aux.rs rename to src/test/run-pass/issues/auxiliary/issue-34796-aux.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_38190.rs b/src/test/run-pass/issues/auxiliary/issue-38190.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_38190.rs rename to src/test/run-pass/issues/auxiliary/issue-38190.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_38226_aux.rs b/src/test/run-pass/issues/auxiliary/issue-38226-aux.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_38226_aux.rs rename to src/test/run-pass/issues/auxiliary/issue-38226-aux.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_38715-modern.rs b/src/test/run-pass/issues/auxiliary/issue-38715-modern.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_38715-modern.rs rename to src/test/run-pass/issues/auxiliary/issue-38715-modern.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_38715.rs b/src/test/run-pass/issues/auxiliary/issue-38715.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_38715.rs rename to src/test/run-pass/issues/auxiliary/issue-38715.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_3979_traits.rs b/src/test/run-pass/issues/auxiliary/issue-3979-traits.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_3979_traits.rs rename to src/test/run-pass/issues/auxiliary/issue-3979-traits.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_39823.rs b/src/test/run-pass/issues/auxiliary/issue-39823.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_39823.rs rename to src/test/run-pass/issues/auxiliary/issue-39823.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_40469.rs b/src/test/run-pass/issues/auxiliary/issue-40469.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_40469.rs rename to src/test/run-pass/issues/auxiliary/issue-40469.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_41053.rs b/src/test/run-pass/issues/auxiliary/issue-41053.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_41053.rs rename to src/test/run-pass/issues/auxiliary/issue-41053.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_42007_s.rs b/src/test/run-pass/issues/auxiliary/issue-42007-s.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_42007_s.rs rename to src/test/run-pass/issues/auxiliary/issue-42007-s.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_8401.rs b/src/test/run-pass/issues/auxiliary/issue-8401.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_8401.rs rename to src/test/run-pass/issues/auxiliary/issue-8401.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_9123.rs b/src/test/run-pass/issues/auxiliary/issue-9123.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_9123.rs rename to src/test/run-pass/issues/auxiliary/issue-9123.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_9155.rs b/src/test/run-pass/issues/auxiliary/issue-9155.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_9155.rs rename to src/test/run-pass/issues/auxiliary/issue-9155.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_9188.rs b/src/test/run-pass/issues/auxiliary/issue-9188.rs similarity index 100% rename from src/test/run-pass/issues/auxiliary/issue_9188.rs rename to src/test/run-pass/issues/auxiliary/issue-9188.rs diff --git a/src/test/run-pass/issues/auxiliary/issue_3136_a.rc b/src/test/run-pass/issues/auxiliary/issue_3136_a.rc deleted file mode 100644 index 46da4132b82d7..0000000000000 --- a/src/test/run-pass/issues/auxiliary/issue_3136_a.rc +++ /dev/null @@ -1,3 +0,0 @@ -#![crate_type = "lib"] - -pub mod issue_3136_a; diff --git a/src/test/run-pass/issues/issue-10031.rs b/src/test/run-pass/issues/issue-10031.rs index ba1fbac48453a..136df05c2397a 100644 --- a/src/test/run-pass/issues/issue-10031.rs +++ b/src/test/run-pass/issues/issue-10031.rs @@ -1,5 +1,5 @@ // run-pass -// aux-build:issue_10031_aux.rs +// aux-build:issue-10031-aux.rs // pretty-expanded FIXME #23616 extern crate issue_10031_aux; diff --git a/src/test/run-pass/issues/issue-10626.rs b/src/test/run-pass/issues/issue-10626.rs index 9c10fd2cea682..78fa8b7c6fb07 100644 --- a/src/test/run-pass/issues/issue-10626.rs +++ b/src/test/run-pass/issues/issue-10626.rs @@ -1,6 +1,7 @@ // run-pass // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes // Make sure that if a process doesn't have its stdio/stderr descriptors set up // that we don't die in a large ball of fire diff --git a/src/test/run-pass/issues/issue-10802.rs b/src/test/run-pass/issues/issue-10802.rs index 8872eae6f8bfb..f1d6b37a6843f 100644 --- a/src/test/run-pass/issues/issue-10802.rs +++ b/src/test/run-pass/issues/issue-10802.rs @@ -24,9 +24,9 @@ trait MyTrait { fn dummy(&self) { } } impl MyTrait for Box {} impl MyTrait for Box {} -struct Whatever { w: Box } +struct Whatever { w: Box } impl Whatever { - fn new(w: Box) -> Whatever { + fn new(w: Box) -> Whatever { Whatever { w: w } } } @@ -34,13 +34,13 @@ impl Whatever { fn main() { { let f: Box<_> = box DroppableStruct; - let _a = Whatever::new(box f as Box); + let _a = Whatever::new(box f as Box); } assert!(unsafe { DROPPED }); unsafe { DROPPED = false; } { let f: Box<_> = box DroppableEnum::DroppableVariant1; - let _a = Whatever::new(box f as Box); + let _a = Whatever::new(box f as Box); } assert!(unsafe { DROPPED }); } diff --git a/src/test/run-pass/issues/issue-11205.rs b/src/test/run-pass/issues/issue-11205.rs index b628bf601968d..ce0951eafdd34 100644 --- a/src/test/run-pass/issues/issue-11205.rs +++ b/src/test/run-pass/issues/issue-11205.rs @@ -5,44 +5,44 @@ trait Foo { fn dummy(&self) { } } impl Foo for isize {} -fn foo(_: [&Foo; 2]) {} -fn foos(_: &[&Foo]) {} +fn foo(_: [&dyn Foo; 2]) {} +fn foos(_: &[&dyn Foo]) {} fn foog(_: &[T], _: &[T]) {} -fn bar(_: [Box; 2]) {} -fn bars(_: &[Box]) {} +fn bar(_: [Box; 2]) {} +fn bars(_: &[Box]) {} fn main() { - let x: [&Foo; 2] = [&1, &2]; + let x: [&dyn Foo; 2] = [&1, &2]; foo(x); foo([&1, &2]); let r = &1; - let x: [&Foo; 2] = [r; 2]; + let x: [&dyn Foo; 2] = [r; 2]; foo(x); foo([&1; 2]); - let x: &[&Foo] = &[&1, &2]; + let x: &[&dyn Foo] = &[&1, &2]; foos(x); foos(&[&1, &2]); - let x: &[&Foo] = &[&1, &2]; + let x: &[&dyn Foo] = &[&1, &2]; let r = &1; foog(x, &[r]); - let x: [Box; 2] = [Box::new(1), Box::new(2)]; + let x: [Box; 2] = [Box::new(1), Box::new(2)]; bar(x); bar([Box::new(1), Box::new(2)]); - let x: &[Box] = &[Box::new(1), Box::new(2)]; + let x: &[Box] = &[Box::new(1), Box::new(2)]; bars(x); bars(&[Box::new(1), Box::new(2)]); - let x: &[Box] = &[Box::new(1), Box::new(2)]; + let x: &[Box] = &[Box::new(1), Box::new(2)]; foog(x, &[Box::new(1)]); struct T<'a> { - t: [&'a (Foo+'a); 2] + t: [&'a (dyn Foo+'a); 2] } let _n = T { t: [&1, &2] @@ -51,34 +51,34 @@ fn main() { let _n = T { t: [r; 2] }; - let x: [&Foo; 2] = [&1, &2]; + let x: [&dyn Foo; 2] = [&1, &2]; let _n = T { t: x }; struct F<'b> { - t: &'b [&'b (Foo+'b)] + t: &'b [&'b (dyn Foo+'b)] } let _n = F { t: &[&1, &2] }; let r = &1; - let r: [&Foo; 2] = [r; 2]; + let r: [&dyn Foo; 2] = [r; 2]; let _n = F { t: &r }; - let x: [&Foo; 2] = [&1, &2]; + let x: [&dyn Foo; 2] = [&1, &2]; let _n = F { t: &x }; struct M<'a> { - t: &'a [Box] + t: &'a [Box] } let _n = M { t: &[Box::new(1), Box::new(2)] }; - let x: [Box; 2] = [Box::new(1), Box::new(2)]; + let x: [Box; 2] = [Box::new(1), Box::new(2)]; let _n = M { t: &x }; diff --git a/src/test/run-pass/issues/issue-11267.rs b/src/test/run-pass/issues/issue-11267.rs index 1aaeaa62ad005..848ed6ac7a8ff 100644 --- a/src/test/run-pass/issues/issue-11267.rs +++ b/src/test/run-pass/issues/issue-11267.rs @@ -10,7 +10,7 @@ impl T for Empty { fn next(&mut self) -> Option { None } } -fn do_something_with(a : &mut T) { +fn do_something_with(a : &mut dyn T) { println!("{:?}", a.next()) } diff --git a/src/test/run-pass/issues/issue-11677.rs b/src/test/run-pass/issues/issue-11677.rs index 5dabecc48f9c1..be18c736f1483 100644 --- a/src/test/run-pass/issues/issue-11677.rs +++ b/src/test/run-pass/issues/issue-11677.rs @@ -11,8 +11,8 @@ trait X { fn dummy(&self) -> T { panic!() } } -struct S {f: Box+'static>, - g: Box+'static>} +struct S {f: Box+'static>, + g: Box+'static>} struct F; impl X for F { diff --git a/src/test/run-pass/issues/issue-11709.rs b/src/test/run-pass/issues/issue-11709.rs index f191a203f03a8..cb5e3dff3b31b 100644 --- a/src/test/run-pass/issues/issue-11709.rs +++ b/src/test/run-pass/issues/issue-11709.rs @@ -9,7 +9,7 @@ struct S {x:()} -fn test(slot: &mut Option Box>>) -> () { +fn test(slot: &mut Option Box>>) -> () { let a = slot.take(); let _a = match a { // `{let .. a(); }` would break diff --git a/src/test/run-pass/issues/issue-12133-3.rs b/src/test/run-pass/issues/issue-12133-3.rs index c87a37ab6b787..c8aa9bf46491f 100644 --- a/src/test/run-pass/issues/issue-12133-3.rs +++ b/src/test/run-pass/issues/issue-12133-3.rs @@ -5,6 +5,7 @@ // ignore-cloudabi no dylib support // ignore-emscripten no dylib support // ignore-musl +// ignore-sgx no dylib support // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/issues/issue-12612.rs b/src/test/run-pass/issues/issue-12612.rs index 158c2aed13724..d254f6941a339 100644 --- a/src/test/run-pass/issues/issue-12612.rs +++ b/src/test/run-pass/issues/issue-12612.rs @@ -1,7 +1,7 @@ // run-pass #![allow(unused_imports)] -// aux-build:issue_12612_1.rs -// aux-build:issue_12612_2.rs +// aux-build:issue-12612-1.rs +// aux-build:issue-12612-2.rs // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/issues/issue-12699.rs b/src/test/run-pass/issues/issue-12699.rs index b23853074fa32..e26c2d7cde234 100644 --- a/src/test/run-pass/issues/issue-12699.rs +++ b/src/test/run-pass/issues/issue-12699.rs @@ -1,5 +1,6 @@ // run-pass // ignore-wasm32-bare can't block the thread +// ignore-sgx not supported #![allow(deprecated)] use std::thread; diff --git a/src/test/run-pass/issues/issue-12744.rs b/src/test/run-pass/issues/issue-12744.rs index d02620ee1a471..e2756ec970c39 100644 --- a/src/test/run-pass/issues/issue-12744.rs +++ b/src/test/run-pass/issues/issue-12744.rs @@ -1,5 +1,5 @@ // run-pass fn main() { - fn test() -> Box { Box::new(1) } + fn test() -> Box { Box::new(1) } println!("{:?}", test()) } diff --git a/src/test/run-pass/issues/issue-13259-windows-tcb-trash.rs b/src/test/run-pass/issues/issue-13259-windows-tcb-trash.rs index d79d34de571df..740e7780de67a 100644 --- a/src/test/run-pass/issues/issue-13259-windows-tcb-trash.rs +++ b/src/test/run-pass/issues/issue-13259-windows-tcb-trash.rs @@ -23,8 +23,8 @@ mod imp { pub fn test() { let mut buf: [u16; 50] = [0; 50]; let ret = unsafe { - FormatMessageW(0x1000, 0 as *mut _, 1, 0x400, - buf.as_mut_ptr(), buf.len() as u32, 0 as *const _) + FormatMessageW(0x1000, core::ptr::null_mut(), 1, 0x400, + buf.as_mut_ptr(), buf.len() as u32, core::ptr::null()) }; // On some 32-bit Windowses (Win7-8 at least) this will panic with segmented // stacks taking control of pvArbitrary diff --git a/src/test/run-pass/issues/issue-13304.rs b/src/test/run-pass/issues/issue-13304.rs index cd74ce38dea6f..5698536ab5d05 100644 --- a/src/test/run-pass/issues/issue-13304.rs +++ b/src/test/run-pass/issues/issue-13304.rs @@ -2,6 +2,7 @@ #![allow(unused_mut)] // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::env; use std::io::prelude::*; diff --git a/src/test/run-pass/issues/issue-13494.rs b/src/test/run-pass/issues/issue-13494.rs deleted file mode 100644 index 12be97702a9f4..0000000000000 --- a/src/test/run-pass/issues/issue-13494.rs +++ /dev/null @@ -1,35 +0,0 @@ -// run-pass -#![allow(unused_must_use)] -// ignore-emscripten no threads support - -// This test may not always fail, but it can be flaky if the race it used to -// expose is still present. - -#![feature(mpsc_select)] -#![allow(deprecated)] - -use std::sync::mpsc::{channel, Sender, Receiver}; -use std::thread; - -fn helper(rx: Receiver>) { - for tx in rx.iter() { - let _ = tx.send(()); - } -} - -fn main() { - let (tx, rx) = channel(); - let t = thread::spawn(move|| { helper(rx) }); - let (snd, rcv) = channel::(); - for _ in 1..100000 { - snd.send(1).unwrap(); - let (tx2, rx2) = channel(); - tx.send(tx2).unwrap(); - select! { - _ = rx2.recv() => (), - _ = rcv.recv() => () - } - } - drop(tx); - t.join(); -} diff --git a/src/test/run-pass/issues/issue-13507-2.rs b/src/test/run-pass/issues/issue-13507-2.rs index 4ea95149dc6b5..63f3589c6cc63 100644 --- a/src/test/run-pass/issues/issue-13507-2.rs +++ b/src/test/run-pass/issues/issue-13507-2.rs @@ -1,14 +1,14 @@ // run-pass #![allow(unused_imports)] -// aux-build:issue13507.rs +// aux-build:issue-13507.rs -extern crate issue13507; -use issue13507::testtypes; +extern crate issue_13507; +use issue_13507::testtypes; use std::any::TypeId; pub fn type_ids() -> Vec { - use issue13507::testtypes::*; + use issue_13507::testtypes::*; vec![ TypeId::of::(), TypeId::of::(), @@ -23,14 +23,14 @@ pub fn type_ids() -> Vec { TypeId::of::(), TypeId::of::(), TypeId::of::(), - TypeId::of::(), + TypeId::of::(), TypeId::of::(), TypeId::of::() ] } pub fn main() { - let othercrate = issue13507::testtypes::type_ids(); + let othercrate = issue_13507::testtypes::type_ids(); let thiscrate = type_ids(); assert_eq!(thiscrate, othercrate); } diff --git a/src/test/run-pass/issues/issue-13808.rs b/src/test/run-pass/issues/issue-13808.rs index d1b94c7186462..9f9db067bf4b5 100644 --- a/src/test/run-pass/issues/issue-13808.rs +++ b/src/test/run-pass/issues/issue-13808.rs @@ -4,7 +4,7 @@ // pretty-expanded FIXME #23616 struct Foo<'a> { - listener: Box, + listener: Box, } impl<'a> Foo<'a> { diff --git a/src/test/run-pass/issues/issue-14399.rs b/src/test/run-pass/issues/issue-14399.rs index 1b57856e95566..6bf8a589959c5 100644 --- a/src/test/run-pass/issues/issue-14399.rs +++ b/src/test/run-pass/issues/issue-14399.rs @@ -16,5 +16,5 @@ impl A for B1 {} fn main() { let v: Box<_> = box B1; - let _c: Box = v.clone(); + let _c: Box = v.clone(); } diff --git a/src/test/run-pass/issues/issue-14456.rs b/src/test/run-pass/issues/issue-14456.rs index 23347d35178e0..164d7ef8af27d 100644 --- a/src/test/run-pass/issues/issue-14456.rs +++ b/src/test/run-pass/issues/issue-14456.rs @@ -2,6 +2,7 @@ #![allow(unused_mut)] // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::env; use std::io::prelude::*; diff --git a/src/test/run-pass/issues/issue-14589.rs b/src/test/run-pass/issues/issue-14589.rs index d495602dff7e7..5d8aab2ce74ce 100644 --- a/src/test/run-pass/issues/issue-14589.rs +++ b/src/test/run-pass/issues/issue-14589.rs @@ -5,9 +5,9 @@ // pretty-expanded FIXME #23616 fn main() { - send::>(Box::new(Output(0))); - Test::>::foo(Box::new(Output(0))); - Test::>::new().send(Box::new(Output(0))); + send::>(Box::new(Output(0))); + Test::>::foo(Box::new(Output(0))); + Test::>::new().send(Box::new(Output(0))); } fn send(_: T) {} diff --git a/src/test/run-pass/issues/issue-14821.rs b/src/test/run-pass/issues/issue-14821.rs index 5ac0d0df0d7d4..00b2e3607fcba 100644 --- a/src/test/run-pass/issues/issue-14821.rs +++ b/src/test/run-pass/issues/issue-14821.rs @@ -6,16 +6,16 @@ struct Meow; impl SomeTrait for Meow {} struct Foo<'a> { - x: &'a SomeTrait, - y: &'a SomeTrait, + x: &'a dyn SomeTrait, + y: &'a dyn SomeTrait, } impl<'a> Foo<'a> { - pub fn new<'b>(x: &'b SomeTrait, y: &'b SomeTrait) -> Foo<'b> { Foo { x: x, y: y } } + pub fn new<'b>(x: &'b dyn SomeTrait, y: &'b dyn SomeTrait) -> Foo<'b> { Foo { x: x, y: y } } } fn main() { let r = Meow; let s = Meow; - let q = Foo::new(&r as &SomeTrait, &s as &SomeTrait); + let q = Foo::new(&r as &dyn SomeTrait, &s as &dyn SomeTrait); } diff --git a/src/test/run-pass/issues/issue-14919.rs b/src/test/run-pass/issues/issue-14919.rs index c6ccb7575bb83..943615433549e 100644 --- a/src/test/run-pass/issues/issue-14919.rs +++ b/src/test/run-pass/issues/issue-14919.rs @@ -9,7 +9,7 @@ trait Matcher { struct CharPredMatcher<'a, 'b> { str: &'a str, - pred: Box bool + 'b>, + pred: Box bool + 'b>, } impl<'a, 'b> Matcher for CharPredMatcher<'a, 'b> { diff --git a/src/test/run-pass/issues/issue-14940.rs b/src/test/run-pass/issues/issue-14940.rs index ce47a623f0011..785ad6a2c49da 100644 --- a/src/test/run-pass/issues/issue-14940.rs +++ b/src/test/run-pass/issues/issue-14940.rs @@ -1,6 +1,7 @@ // run-pass // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::env; use std::process::Command; diff --git a/src/test/run-pass/issues/issue-14958.rs b/src/test/run-pass/issues/issue-14958.rs index 17f7f159fd2db..a12564ca9c0ee 100644 --- a/src/test/run-pass/issues/issue-14958.rs +++ b/src/test/run-pass/issues/issue-14958.rs @@ -7,17 +7,17 @@ trait Foo { fn dummy(&self) { }} struct Bar; -impl<'a> std::ops::Fn<(&'a (Foo+'a),)> for Bar { - extern "rust-call" fn call(&self, _: (&'a Foo,)) {} +impl<'a> std::ops::Fn<(&'a (dyn Foo+'a),)> for Bar { + extern "rust-call" fn call(&self, _: (&'a dyn Foo,)) {} } -impl<'a> std::ops::FnMut<(&'a (Foo+'a),)> for Bar { - extern "rust-call" fn call_mut(&mut self, a: (&'a Foo,)) { self.call(a) } +impl<'a> std::ops::FnMut<(&'a (dyn Foo+'a),)> for Bar { + extern "rust-call" fn call_mut(&mut self, a: (&'a dyn Foo,)) { self.call(a) } } -impl<'a> std::ops::FnOnce<(&'a (Foo+'a),)> for Bar { +impl<'a> std::ops::FnOnce<(&'a (dyn Foo+'a),)> for Bar { type Output = (); - extern "rust-call" fn call_once(self, a: (&'a Foo,)) { self.call(a) } + extern "rust-call" fn call_once(self, a: (&'a dyn Foo,)) { self.call(a) } } struct Baz; diff --git a/src/test/run-pass/issues/issue-15155.rs b/src/test/run-pass/issues/issue-15155.rs index 3e513a3d5ecbe..7b137b4af56a7 100644 --- a/src/test/run-pass/issues/issue-15155.rs +++ b/src/test/run-pass/issues/issue-15155.rs @@ -4,18 +4,18 @@ trait IndirectTraitWithSend: TraitWithSend {} // Check struct instantiation (Box will only have Send if TraitWithSend has Send) #[allow(dead_code)] -struct Blah { x: Box } +struct Blah { x: Box } impl TraitWithSend for Blah {} // Struct instantiation 2-levels deep #[allow(dead_code)] -struct IndirectBlah { x: Box } +struct IndirectBlah { x: Box } impl TraitWithSend for IndirectBlah {} impl IndirectTraitWithSend for IndirectBlah {} fn test_trait() { println!("got here!") } fn main() { - test_trait::(); - test_trait::(); + test_trait::(); + test_trait::(); } diff --git a/src/test/run-pass/issues/issue-15763.rs b/src/test/run-pass/issues/issue-15763.rs index 4438d1f2ceca3..9ceffff2e3806 100644 --- a/src/test/run-pass/issues/issue-15763.rs +++ b/src/test/run-pass/issues/issue-15763.rs @@ -78,12 +78,12 @@ fn main() { assert_eq!(cc().unwrap(), 3); assert_eq!(dd().unwrap(), 3); - let i = box 32isize as Box; + let i = box 32isize as Box; assert_eq!(i.aaa(), 3); - let i = box 32isize as Box; + let i = box 32isize as Box; assert_eq!(i.bbb(), 3); - let i = box 32isize as Box; + let i = box 32isize as Box; assert_eq!(i.ccc().unwrap(), 3); - let i = box 32isize as Box; + let i = box 32isize as Box; assert_eq!(i.ddd().unwrap(), 3); } diff --git a/src/test/run-pass/issues/issue-15881-model-lexer-dotdotdot.rs b/src/test/run-pass/issues/issue-15881-model-lexer-dotdotdot.rs index 2470e37e1820b..dee7f25d7bb3a 100644 --- a/src/test/run-pass/issues/issue-15881-model-lexer-dotdotdot.rs +++ b/src/test/run-pass/issues/issue-15881-model-lexer-dotdotdot.rs @@ -1,5 +1,6 @@ // run-pass #![allow(illegal_floating_point_literal_pattern)] // FIXME #41620 +#![allow(ellipsis_inclusive_range_patterns)] // regression test for the model lexer handling the DOTDOTDOT syntax (#15877) diff --git a/src/test/run-pass/issues/issue-16272.rs b/src/test/run-pass/issues/issue-16272.rs index a2570e763f6da..3ba2483f4306d 100644 --- a/src/test/run-pass/issues/issue-16272.rs +++ b/src/test/run-pass/issues/issue-16272.rs @@ -1,6 +1,7 @@ // run-pass // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::process::Command; use std::env; diff --git a/src/test/run-pass/issues/issue-16278.rs b/src/test/run-pass/issues/issue-16278.rs index a9fa0db44d346..2f47b694ae912 100644 --- a/src/test/run-pass/issues/issue-16278.rs +++ b/src/test/run-pass/issues/issue-16278.rs @@ -8,4 +8,3 @@ fn main() {assert_eq!(b"", b"\ assert_eq!(b"\n", b" "); } - diff --git a/src/test/run-pass/issues/issue-16671.rs b/src/test/run-pass/issues/issue-16671.rs index 81a6b669b70ef..eff8e275bb58b 100644 --- a/src/test/run-pass/issues/issue-16671.rs +++ b/src/test/run-pass/issues/issue-16671.rs @@ -1,5 +1,4 @@ // run-pass -//compile-flags: -Z borrowck=compare #![deny(warnings)] diff --git a/src/test/run-pass/issues/issue-16739.rs b/src/test/run-pass/issues/issue-16739.rs index 6868eae6ea4f7..54ad8fd076e4e 100644 --- a/src/test/run-pass/issues/issue-16739.rs +++ b/src/test/run-pass/issues/issue-16739.rs @@ -39,12 +39,12 @@ impl FnOnce<(u32,u32)> for Foo { } fn main() { - let mut f = box Foo { foo: 42 } as Box u32>; + let mut f = box Foo { foo: 42 } as Box u32>; assert_eq!(f.call_mut(()), 42); - let mut f = box Foo { foo: 40 } as Box u32>; + let mut f = box Foo { foo: 40 } as Box u32>; assert_eq!(f.call_mut((2,)), 42); - let mut f = box Foo { foo: 40 } as Box u32>; + let mut f = box Foo { foo: 40 } as Box u32>; assert_eq!(f.call_mut((1, 1)), 42); } diff --git a/src/test/run-pass/issues/issue-16922.rs b/src/test/run-pass/issues/issue-16922.rs index 82a3943e9efa5..c3c6ff304888d 100644 --- a/src/test/run-pass/issues/issue-16922.rs +++ b/src/test/run-pass/issues/issue-16922.rs @@ -7,5 +7,5 @@ fn foo(_: &u8) { } fn main() { - let _ = &foo as &Any; + let _ = &foo as &dyn Any; } diff --git a/src/test/run-pass/issues/issue-17322.rs b/src/test/run-pass/issues/issue-17322.rs index 79b6a5ae5337c..20a8d13612469 100644 --- a/src/test/run-pass/issues/issue-17322.rs +++ b/src/test/run-pass/issues/issue-17322.rs @@ -5,11 +5,11 @@ use std::io::{self, Write}; -fn f(wr: &mut Write) { +fn f(wr: &mut dyn Write) { wr.write_all(b"hello").ok().expect("failed"); } fn main() { - let mut wr = box io::stdout() as Box; + let mut wr = box io::stdout() as Box; f(&mut wr); } diff --git a/src/test/run-pass/issues/issue-17351.rs b/src/test/run-pass/issues/issue-17351.rs index f51f0b3ca0171..62f6bcf15e3e7 100644 --- a/src/test/run-pass/issues/issue-17351.rs +++ b/src/test/run-pass/issues/issue-17351.rs @@ -6,5 +6,5 @@ impl Str for str {} impl<'a, S: ?Sized> Str for &'a S where S: Str {} fn main() { - let _: &Str = &"x"; + let _: &dyn Str = &"x"; } diff --git a/src/test/run-pass/issues/issue-17771.rs b/src/test/run-pass/issues/issue-17771.rs index 7eea5ce6589b5..2f6464668c2ce 100644 --- a/src/test/run-pass/issues/issue-17771.rs +++ b/src/test/run-pass/issues/issue-17771.rs @@ -4,13 +4,13 @@ trait Aaa { fn dummy(&self) { } } -impl<'a> Aaa for &'a mut (Aaa + 'a) {} +impl<'a> Aaa for &'a mut (dyn Aaa + 'a) {} struct Bar<'a> { - writer: &'a mut (Aaa + 'a), + writer: &'a mut (dyn Aaa + 'a), } -fn baz(_: &mut Aaa) { +fn baz(_: &mut dyn Aaa) { } fn foo<'a>(mut bar: Bar<'a>) { diff --git a/src/test/run-pass/issues/issue-17897.rs b/src/test/run-pass/issues/issue-17897.rs index 291bd3f1718a2..6873c7ccb7f1c 100644 --- a/src/test/run-pass/issues/issue-17897.rs +++ b/src/test/run-pass/issues/issue-17897.rs @@ -1,5 +1,5 @@ // run-pass -fn action(mut cb: Box usize>) -> usize { +fn action(mut cb: Box usize>) -> usize { cb(1) } diff --git a/src/test/run-pass/issues/issue-18075.rs b/src/test/run-pass/issues/issue-18075.rs index dcd67d8d15ab6..ee6845c1278b8 100644 --- a/src/test/run-pass/issues/issue-18075.rs +++ b/src/test/run-pass/issues/issue-18075.rs @@ -1,5 +1,5 @@ // run-pass -// exec-env:RUST_LOG=rustc::middle=debug +// exec-env:RUSTC_LOG=rustc::middle=debug fn main() { let b = 1isize; diff --git a/src/test/run-pass/issues/issue-18353.rs b/src/test/run-pass/issues/issue-18353.rs index aaa896b66c5d4..3d15c9980c352 100644 --- a/src/test/run-pass/issues/issue-18353.rs +++ b/src/test/run-pass/issues/issue-18353.rs @@ -11,5 +11,5 @@ struct Str { fn main() { let str: Option<&Str> = None; - str.is_some(); + let _ = str.is_some(); } diff --git a/src/test/run-pass/issue-18952.rs b/src/test/run-pass/issues/issue-18952.rs similarity index 100% rename from src/test/run-pass/issue-18952.rs rename to src/test/run-pass/issues/issue-18952.rs diff --git a/src/test/run-pass/issues/issue-19001.rs b/src/test/run-pass/issues/issue-19001.rs index 85f7a84ac295f..76c380c2fc97e 100644 --- a/src/test/run-pass/issues/issue-19001.rs +++ b/src/test/run-pass/issues/issue-19001.rs @@ -7,5 +7,5 @@ struct Loopy { } fn main() { - let _t = Loopy { ptr: 0 as *mut _ }; + let _t = Loopy { ptr: core::ptr::null_mut() }; } diff --git a/src/test/run-pass/issues/issue-19293.rs b/src/test/run-pass/issues/issue-19293.rs index 90f96566f382b..b6e9e3d065a48 100644 --- a/src/test/run-pass/issues/issue-19293.rs +++ b/src/test/run-pass/issues/issue-19293.rs @@ -1,5 +1,5 @@ // run-pass -// aux-build:issue_19293.rs +// aux-build:issue-19293.rs // pretty-expanded FIXME #23616 extern crate issue_19293; diff --git a/src/test/run-pass/issues/issue-20055-box-trait.rs b/src/test/run-pass/issues/issue-20055-box-trait.rs index cb7b5a638fc2b..772cd9d7eda82 100644 --- a/src/test/run-pass/issues/issue-20055-box-trait.rs +++ b/src/test/run-pass/issues/issue-20055-box-trait.rs @@ -22,7 +22,7 @@ pub fn foo(box_1: fn () -> Box<[i8; 1]>, box_4: fn () -> Box<[i8; 4]>, ) { println!("Hello World 1"); - let _: Box = match 3 { + let _: Box = match 3 { 1 => box_1(), 2 => box_2(), 3 => box_3(), diff --git a/src/test/run-pass/issues/issue-20389.rs b/src/test/run-pass/issues/issue-20389.rs index 9c5a1844e293b..9bc3efcc1c4bf 100644 --- a/src/test/run-pass/issues/issue-20389.rs +++ b/src/test/run-pass/issues/issue-20389.rs @@ -1,6 +1,6 @@ // run-pass #![allow(dead_code)] -// aux-build:issue_20389.rs +// aux-build:issue-20389.rs // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/issues/issue-20575.rs b/src/test/run-pass/issues/issue-20575.rs index 95273edcf7e82..0ca67d9dc710e 100644 --- a/src/test/run-pass/issues/issue-20575.rs +++ b/src/test/run-pass/issues/issue-20575.rs @@ -4,7 +4,7 @@ // pretty-expanded FIXME #23616 fn main() { - let functions: [Box Option<()>>; 1] = [Box::new(|| None)]; + let functions: [Box Option<()>>; 1] = [Box::new(|| None)]; let _: Option> = functions.iter().map(|f| (*f)()).collect(); } diff --git a/src/test/run-pass/issues/issue-20676.rs b/src/test/run-pass/issues/issue-20676.rs index 27bbff09a00f2..2bc5034960a1b 100644 --- a/src/test/run-pass/issues/issue-20676.rs +++ b/src/test/run-pass/issues/issue-20676.rs @@ -7,6 +7,6 @@ use std::fmt; fn main() { - let a: &fmt::Debug = &1; + let a: &dyn fmt::Debug = &1; format!("{:?}", a); } diff --git a/src/test/run-pass/issues/issue-20953.rs b/src/test/run-pass/issues/issue-20953.rs index f5c743d0d8262..4ec7e3195ebe0 100644 --- a/src/test/run-pass/issues/issue-20953.rs +++ b/src/test/run-pass/issues/issue-20953.rs @@ -2,11 +2,11 @@ #![allow(unused_mut)] #![allow(unused_variables)] fn main() { - let mut shrinker: Box> = Box::new(vec![1].into_iter()); + let mut shrinker: Box> = Box::new(vec![1].into_iter()); println!("{:?}", shrinker.next()); for v in shrinker { assert!(false); } - let mut shrinker: &mut Iterator = &mut vec![1].into_iter(); + let mut shrinker: &mut dyn Iterator = &mut vec![1].into_iter(); println!("{:?}", shrinker.next()); for v in shrinker { assert!(false); } } diff --git a/src/test/run-pass/issues/issue-21058.rs b/src/test/run-pass/issues/issue-21058.rs index e0cf26f7034ca..3efa94ce6835c 100644 --- a/src/test/run-pass/issues/issue-21058.rs +++ b/src/test/run-pass/issues/issue-21058.rs @@ -2,21 +2,64 @@ #![allow(dead_code)] #![feature(core_intrinsics)] +use std::fmt::Debug; + struct NT(str); struct DST { a: u32, b: str } +macro_rules! check { + (val: $ty_of:expr, $expected:expr) => { + assert_eq!(type_name_of_val($ty_of), $expected); + }; + ($ty:ty, $expected:expr) => { + assert_eq!(unsafe { std::intrinsics::type_name::<$ty>()}, $expected); + }; +} + fn main() { // type_name should support unsized types - assert_eq!(unsafe {( - // Slice - std::intrinsics::type_name::<[u8]>(), - // str - std::intrinsics::type_name::(), - // Trait - std::intrinsics::type_name::(), - // Newtype - std::intrinsics::type_name::(), - // DST - std::intrinsics::type_name::() - )}, ("[u8]", "str", "dyn std::marker::Send", "NT", "DST")); + check!([u8], "[u8]"); + check!(str, "str"); + check!(dyn Send, "dyn core::marker::Send"); + check!(NT, "issue_21058::NT"); + check!(DST, "issue_21058::DST"); + check!(&i32, "&i32"); + check!(&'static i32, "&i32"); + check!((i32, u32), "(i32, u32)"); + check!(val: foo(), "issue_21058::Foo"); + check!(val: Foo::new, "issue_21058::Foo::new"); + check!(val: + ::fmt, + "::fmt" + ); + check!(val: || {}, "issue_21058::main::{{closure}}"); + bar::(); +} + +trait Trait { + type Assoc; +} + +impl Trait for i32 { + type Assoc = String; +} + +fn bar() { + check!(T::Assoc, "alloc::string::String"); + check!(T, "i32"); +} + +fn type_name_of_val(_: T) -> &'static str { + unsafe { std::intrinsics::type_name::() } +} + +#[derive(Debug)] +struct Foo; + +impl Foo { + fn new() -> Self { Foo } +} + +fn foo() -> impl Debug { + Foo } diff --git a/src/test/run-pass/issues/issue-21361.rs b/src/test/run-pass/issues/issue-21361.rs index 5297a4a7b29e2..c970e77abb72b 100644 --- a/src/test/run-pass/issues/issue-21361.rs +++ b/src/test/run-pass/issues/issue-21361.rs @@ -2,10 +2,10 @@ fn main() { let v = vec![1, 2, 3]; - let boxed: Box> = Box::new(v.into_iter()); + let boxed: Box> = Box::new(v.into_iter()); assert_eq!(boxed.max(), Some(3)); let v = vec![1, 2, 3]; - let boxed: &mut Iterator = &mut v.into_iter(); + let boxed: &mut dyn Iterator = &mut v.into_iter(); assert_eq!(boxed.max(), Some(3)); } diff --git a/src/test/run-pass/issues/issue-21400.rs b/src/test/run-pass/issues/issue-21400.rs index 0f297e9b8f290..4a85158d97a45 100644 --- a/src/test/run-pass/issues/issue-21400.rs +++ b/src/test/run-pass/issues/issue-21400.rs @@ -54,4 +54,3 @@ impl GitConnect { Ok(out) } } - diff --git a/src/test/run-pass/issues/issue-21655.rs b/src/test/run-pass/issues/issue-21655.rs index cddd48349f9d0..d1cd4ec7b8a01 100644 --- a/src/test/run-pass/issues/issue-21655.rs +++ b/src/test/run-pass/issues/issue-21655.rs @@ -1,6 +1,6 @@ // run-pass -fn test(it: &mut Iterator) { +fn test(it: &mut dyn Iterator) { for x in it { assert_eq!(x, 1) } diff --git a/src/test/run-pass/issues/issue-2170-exe.rs b/src/test/run-pass/issues/issue-2170-exe.rs new file mode 100644 index 0000000000000..a89579706c8dc --- /dev/null +++ b/src/test/run-pass/issues/issue-2170-exe.rs @@ -0,0 +1,9 @@ +// run-pass +// aux-build:issue-2170-lib.rs +// pretty-expanded FIXME #23616 + +extern crate issue_2170_lib; + +pub fn main() { + // let _ = issue_2170_lib::rsrc(2); +} diff --git a/src/test/run-pass/issues/issue-2190-1.rs b/src/test/run-pass/issues/issue-2190-1.rs index 34a80ab00516b..e67a924b9eedc 100644 --- a/src/test/run-pass/issues/issue-2190-1.rs +++ b/src/test/run-pass/issues/issue-2190-1.rs @@ -9,11 +9,11 @@ use std::thread::Builder; static generations: usize = 1024+256+128+49; -fn spawn(mut f: Box) { +fn spawn(mut f: Box) { Builder::new().stack_size(32 * 1024).spawn(move|| f()); } -fn child_no(x: usize) -> Box { +fn child_no(x: usize) -> Box { Box::new(move|| { if x < generations { spawn(child_no(x+1)); diff --git a/src/test/run-pass/issues/issue-2214.rs b/src/test/run-pass/issues/issue-2214.rs index 6e538f711de7c..22f33545cb909 100644 --- a/src/test/run-pass/issues/issue-2214.rs +++ b/src/test/run-pass/issues/issue-2214.rs @@ -1,6 +1,6 @@ // run-pass // ignore-wasm32-bare no libc to test ffi with - +// ignore-sgx no libc #![feature(rustc_private)] extern crate libc; diff --git a/src/test/run-pass/issues/issue-22346.rs b/src/test/run-pass/issues/issue-22346.rs index b728911e54170..5f6d9dcc9ae43 100644 --- a/src/test/run-pass/issues/issue-22346.rs +++ b/src/test/run-pass/issues/issue-22346.rs @@ -3,7 +3,7 @@ // pretty-expanded FIXME #23616 // This used to cause an ICE because the retslot for the "return" had the wrong type -fn testcase<'a>() -> Box + 'a> { +fn testcase<'a>() -> Box + 'a> { return Box::new((0..3).map(|i| { return i; })); } diff --git a/src/test/run-pass/issues/issue-2288.rs b/src/test/run-pass/issues/issue-2288.rs index 963e7e62c7f11..c74e53fca60fd 100644 --- a/src/test/run-pass/issues/issue-2288.rs +++ b/src/test/run-pass/issues/issue-2288.rs @@ -23,13 +23,13 @@ fn foo(b: A) -> foo { } } -fn f(x: Box>, a: A) { +fn f(x: Box>, a: A) { x.chowder(a); } pub fn main() { let c = foo(42); - let d: Box> = box c as Box>; + let d: Box> = box c as Box>; f(d, c.x); } diff --git a/src/test/run-pass/issues/issue-2316-c.rs b/src/test/run-pass/issues/issue-2316-c.rs index 6783f3fcfc691..d975aa695c836 100644 --- a/src/test/run-pass/issues/issue-2316-c.rs +++ b/src/test/run-pass/issues/issue-2316-c.rs @@ -1,6 +1,6 @@ // run-pass -// aux-build:issue_2316_a.rs -// aux-build:issue_2316_b.rs +// aux-build:issue-2316-a.rs +// aux-build:issue-2316-b.rs // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/issues/issue-23261.rs b/src/test/run-pass/issues/issue-23261.rs index 0b34653a34535..e21f86351eeee 100644 --- a/src/test/run-pass/issues/issue-23261.rs +++ b/src/test/run-pass/issues/issue-23261.rs @@ -41,7 +41,7 @@ fn check_both(val: &Foo<[u8]>) { } } -fn check_trait_obj(val: &Foo) { +fn check_trait_obj(val: &Foo) { match *val { Foo { a, ref inner } => { assert_eq!(a, 32); @@ -56,6 +56,6 @@ fn main() { check_dst_val(foo); check_both(foo); - let foo: &Foo = &Foo { a: 32, inner: 32 }; + let foo: &Foo = &Foo { a: 32, inner: 32 }; check_trait_obj(foo); } diff --git a/src/test/run-pass/issues/issue-23485.rs b/src/test/run-pass/issues/issue-23485.rs index a55846f40dfbd..1dd3d9293bcc6 100644 --- a/src/test/run-pass/issues/issue-23485.rs +++ b/src/test/run-pass/issues/issue-23485.rs @@ -45,6 +45,6 @@ impl Iterator for Counter { } fn main() { - let mut x: Box> = Box::new(Counter { value: 22 }); + let mut x: Box> = Box::new(Counter { value: 22 }); assert_eq!(x.next().unwrap().value, 22); } diff --git a/src/test/run-pass/issues/issue-23699.rs b/src/test/run-pass/issues/issue-23699.rs index 11b65d7a67aec..952548837e418 100644 --- a/src/test/run-pass/issues/issue-23699.rs +++ b/src/test/run-pass/issues/issue-23699.rs @@ -12,4 +12,3 @@ fn main() { let t = test as fn (i32); t(0i32); } - diff --git a/src/test/run-pass/issues/issue-24010.rs b/src/test/run-pass/issues/issue-24010.rs index 1f68d47d97b63..264e1ee22cdda 100644 --- a/src/test/run-pass/issues/issue-24010.rs +++ b/src/test/run-pass/issues/issue-24010.rs @@ -2,7 +2,7 @@ trait Foo: Fn(i32) -> i32 + Send {} impl i32 + Send> Foo for T {} -fn wants_foo(f: Box) -> i32 { +fn wants_foo(f: Box) -> i32 { f(42) } diff --git a/src/test/run-pass/issues/issue-24086.rs b/src/test/run-pass/issues/issue-24086.rs index 86fa5a6f3682e..54622afbcfc13 100644 --- a/src/test/run-pass/issues/issue-24086.rs +++ b/src/test/run-pass/issues/issue-24086.rs @@ -7,8 +7,8 @@ pub struct Registry<'a> { } pub struct Listener<'a> { - pub announce: Option>, - pub remove: Option>, + pub announce: Option>, + pub remove: Option>, } impl<'a> Drop for Registry<'a> { diff --git a/src/test/run-pass/issues/issue-24313.rs b/src/test/run-pass/issues/issue-24313.rs index d6426361faeec..2c420dc056fda 100644 --- a/src/test/run-pass/issues/issue-24313.rs +++ b/src/test/run-pass/issues/issue-24313.rs @@ -1,6 +1,7 @@ // run-pass // ignore-cloudabi no processes // ignore-emscripten no threads +// ignore-sgx no processes use std::thread; use std::env; @@ -30,4 +31,3 @@ fn main() { }).join().unwrap(); } } - diff --git a/src/test/run-pass/issues/issue-24535-allow-mutable-borrow-in-match-guard.rs b/src/test/run-pass/issues/issue-24535-allow-mutable-borrow-in-match-guard.rs index 68f7dfd38f4f4..48362d0bb6282 100644 --- a/src/test/run-pass/issues/issue-24535-allow-mutable-borrow-in-match-guard.rs +++ b/src/test/run-pass/issues/issue-24535-allow-mutable-borrow-in-match-guard.rs @@ -5,7 +5,6 @@ // See further discussion on rust-lang/rust#24535, // rust-lang/rfcs#1006, and rust-lang/rfcs#107 -#![feature(nll)] #![feature(bind_by_move_pattern_guards)] fn main() { diff --git a/src/test/run-pass/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-lib.rs b/src/test/run-pass/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-lib.rs new file mode 100644 index 0000000000000..5b1b1389cebb3 --- /dev/null +++ b/src/test/run-pass/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-lib.rs @@ -0,0 +1,10 @@ +#![crate_type="lib"] + +// This is a file that pulls in a separate file as a submodule, where +// that separate file has many multi-byte characters, to try to +// encourage the compiler to trip on them. + +#[path = "issue-24687-mbcs-in-comments.rs"] +mod issue_24687_mbcs_in_comments; + +pub use issue_24687_mbcs_in_comments::D; diff --git a/src/test/run-pass/issues/issue24687-embed-debuginfo/auxiliary/issue24687_mbcs_in_comments.rs b/src/test/run-pass/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-mbcs-in-comments.rs similarity index 100% rename from src/test/run-pass/issues/issue24687-embed-debuginfo/auxiliary/issue24687_mbcs_in_comments.rs rename to src/test/run-pass/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-mbcs-in-comments.rs diff --git a/src/test/run-pass/issues/issue-24687-embed-debuginfo/main.rs b/src/test/run-pass/issues/issue-24687-embed-debuginfo/main.rs new file mode 100644 index 0000000000000..773792c7a3f1f --- /dev/null +++ b/src/test/run-pass/issues/issue-24687-embed-debuginfo/main.rs @@ -0,0 +1,13 @@ +// run-pass +// aux-build:issue-24687-lib.rs +// compile-flags:-g + +extern crate issue_24687_lib as d; + +fn main() { + // Create a `D`, which has a destructor whose body will be codegen'ed + // into the generated code here, and thus the local debuginfo will + // need references into the original source locations from + // `importer` above. + let _d = d::D("Hi"); +} diff --git a/src/test/run-pass/issues/issue-2472.rs b/src/test/run-pass/issues/issue-2472.rs index cadd0151b4e81..c790bc2d09548 100644 --- a/src/test/run-pass/issues/issue-2472.rs +++ b/src/test/run-pass/issues/issue-2472.rs @@ -1,5 +1,5 @@ // run-pass -// aux-build:issue_2472_b.rs +// aux-build:issue-2472-b.rs // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/issues/issue-25339.rs b/src/test/run-pass/issues/issue-25339.rs index 602f458e4cf54..6f8ec700951e2 100644 --- a/src/test/run-pass/issues/issue-25339.rs +++ b/src/test/run-pass/issues/issue-25339.rs @@ -12,7 +12,7 @@ pub trait Routing { pub trait ToRouting { type Input; - type Routing : ?Sized = Routing; + type Routing : ?Sized = dyn Routing; fn to_routing(self) -> Self::Routing; } diff --git a/src/test/run-pass/issues/issue-25515.rs b/src/test/run-pass/issues/issue-25515.rs index 75af16d8dda8e..e7b9ea3acfc01 100644 --- a/src/test/run-pass/issues/issue-25515.rs +++ b/src/test/run-pass/issues/issue-25515.rs @@ -13,7 +13,7 @@ fn main() { let mut drops = 0; { - let _: Rc = Rc::new(Foo(&mut drops)); + let _: Rc = Rc::new(Foo(&mut drops)); } assert_eq!(1, drops); diff --git a/src/test/run-pass/issues/issue-25549-multiple-drop.rs b/src/test/run-pass/issues/issue-25549-multiple-drop.rs index db9261f6ef48f..25a2da707dc0f 100644 --- a/src/test/run-pass/issues/issue-25549-multiple-drop.rs +++ b/src/test/run-pass/issues/issue-25549-multiple-drop.rs @@ -25,7 +25,7 @@ fn main() { drops = 0; { - let y = &Holder(Foo(&mut drops)) as &Holder; + let y = &Holder(Foo(&mut drops)) as &Holder; // this used to cause an extra drop of the Foo instance let x = &y.0; } diff --git a/src/test/run-pass/issues/issue-25700-2.rs b/src/test/run-pass/issues/issue-25700-2.rs index 65de5edce48dd..b161e68abafd0 100644 --- a/src/test/run-pass/issues/issue-25700-2.rs +++ b/src/test/run-pass/issues/issue-25700-2.rs @@ -18,5 +18,5 @@ fn record_type(i: Id::Untyped) -> u8 { } pub fn main() { - assert_eq!(record_type::(3), 42); + assert_eq!(record_type::(3), 42); } diff --git a/src/test/run-pass/issues/issue-25757.rs b/src/test/run-pass/issues/issue-25757.rs index caade6defdd49..ec1864d7deb58 100644 --- a/src/test/run-pass/issues/issue-25757.rs +++ b/src/test/run-pass/issues/issue-25757.rs @@ -9,7 +9,7 @@ impl Foo { } } -const FUNC: &'static Fn(&mut Foo) -> () = &Foo::x; +const FUNC: &'static dyn Fn(&mut Foo) -> () = &Foo::x; fn main() { let mut foo = Foo { a: 137 }; diff --git a/src/test/run-pass/issues/issue-26641.rs b/src/test/run-pass/issues/issue-26641.rs index 297b1d689a6b1..4b6f2c2b3bc7d 100644 --- a/src/test/run-pass/issues/issue-26641.rs +++ b/src/test/run-pass/issues/issue-26641.rs @@ -1,5 +1,5 @@ // run-pass -struct Parser<'a>(Box); +struct Parser<'a>(Box); fn main() { let _x = Parser(Box::new(|_|{})); diff --git a/src/test/run-pass/issues/issue-26709.rs b/src/test/run-pass/issues/issue-26709.rs index 84cd21373672e..281ae13399dd2 100644 --- a/src/test/run-pass/issues/issue-26709.rs +++ b/src/test/run-pass/issues/issue-26709.rs @@ -11,7 +11,7 @@ fn main() { let mut x = 0; { let wrapper = Box::new(Wrapper(&mut x, 123)); - let _: Box> = wrapper; + let _: Box> = wrapper; } assert_eq!(432, x) } diff --git a/src/test/run-pass/issues/issue-26802.rs b/src/test/run-pass/issues/issue-26802.rs index c4aa70d50222d..307a67160980d 100644 --- a/src/test/run-pass/issues/issue-26802.rs +++ b/src/test/run-pass/issues/issue-26802.rs @@ -5,7 +5,7 @@ trait Foo<'a> { pub struct FooBar; impl Foo<'static> for FooBar {} -fn test(foobar: FooBar) -> Box> { +fn test(foobar: FooBar) -> Box> { Box::new(foobar) } diff --git a/src/test/run-pass/issues/issue-26805.rs b/src/test/run-pass/issues/issue-26805.rs index 950d98315d049..bcf8a6731910f 100644 --- a/src/test/run-pass/issues/issue-26805.rs +++ b/src/test/run-pass/issues/issue-26805.rs @@ -2,5 +2,5 @@ struct NonOrd; fn main() { - let _: Box> = Box::new(vec![NonOrd].into_iter()); + let _: Box> = Box::new(vec![NonOrd].into_iter()); } diff --git a/src/test/run-pass/issues/issue-26873-multifile.rs b/src/test/run-pass/issues/issue-26873-multifile.rs index 7b19713fcc661..da2acf6c9f704 100644 --- a/src/test/run-pass/issues/issue-26873-multifile.rs +++ b/src/test/run-pass/issues/issue-26873-multifile.rs @@ -5,6 +5,7 @@ // ignore-pretty issue #37195 -mod issue_26873_multifile; +#[path = "issue-26873-multifile/mod.rs"] +mod multifile; fn main() {} diff --git a/src/test/run-pass/issues/issue_26873_multifile/A/B.rs b/src/test/run-pass/issues/issue-26873-multifile/A/B.rs similarity index 97% rename from src/test/run-pass/issues/issue_26873_multifile/A/B.rs rename to src/test/run-pass/issues/issue-26873-multifile/A/B.rs index d1b802ff3cd48..ab7b0d81605f3 100644 --- a/src/test/run-pass/issues/issue_26873_multifile/A/B.rs +++ b/src/test/run-pass/issues/issue-26873-multifile/A/B.rs @@ -2,4 +2,3 @@ use super::*; pub struct S; - diff --git a/src/test/run-pass/issues/issue_26873_multifile/A/C.rs b/src/test/run-pass/issues/issue-26873-multifile/A/C.rs similarity index 98% rename from src/test/run-pass/issues/issue_26873_multifile/A/C.rs rename to src/test/run-pass/issues/issue-26873-multifile/A/C.rs index 88f3eb04afbdc..b287283df5389 100644 --- a/src/test/run-pass/issues/issue_26873_multifile/A/C.rs +++ b/src/test/run-pass/issues/issue-26873-multifile/A/C.rs @@ -4,4 +4,3 @@ use super::*; use super::B::S; pub struct T { i: i32 } - diff --git a/src/test/run-pass/issues/issue-26873-multifile/A/mod.rs b/src/test/run-pass/issues/issue-26873-multifile/A/mod.rs new file mode 100644 index 0000000000000..0f18772bf1b25 --- /dev/null +++ b/src/test/run-pass/issues/issue-26873-multifile/A/mod.rs @@ -0,0 +1,5 @@ +// run-pass +pub mod B; +pub mod C; + +pub use self::C::T; diff --git a/src/test/run-pass/issues/issue_26873_multifile/compiletest-ignore-dir b/src/test/run-pass/issues/issue-26873-multifile/compiletest-ignore-dir similarity index 100% rename from src/test/run-pass/issues/issue_26873_multifile/compiletest-ignore-dir rename to src/test/run-pass/issues/issue-26873-multifile/compiletest-ignore-dir diff --git a/src/test/run-pass/issues/issue-26873-multifile/mod.rs b/src/test/run-pass/issues/issue-26873-multifile/mod.rs new file mode 100644 index 0000000000000..a1ba53f919171 --- /dev/null +++ b/src/test/run-pass/issues/issue-26873-multifile/mod.rs @@ -0,0 +1,4 @@ +// run-pass +mod A; + +use self::A::*; diff --git a/src/test/run-pass/issues/issue-26873-onefile.rs b/src/test/run-pass/issues/issue-26873-onefile.rs index 4cfffb08e8f4a..f06c6499eb0fb 100644 --- a/src/test/run-pass/issues/issue-26873-onefile.rs +++ b/src/test/run-pass/issues/issue-26873-onefile.rs @@ -23,4 +23,3 @@ mod A { use A::*; fn main() {} - diff --git a/src/test/run-pass/issues/issue-26905.rs b/src/test/run-pass/issues/issue-26905.rs index 309e2f7e5719b..2d5827f476b9e 100644 --- a/src/test/run-pass/issues/issue-26905.rs +++ b/src/test/run-pass/issues/issue-26905.rs @@ -17,6 +17,5 @@ fn main() { let data = [1, 2, 3]; let iter = data.iter(); let x = MyRc { _ptr: &iter, _boo: PhantomData }; - let _y: MyRc> = x; + let _y: MyRc> = x; } - diff --git a/src/test/run-pass/issues/issue-26996.rs b/src/test/run-pass/issues/issue-26996.rs index 8c5d2441780a1..04382be27d7a5 100644 --- a/src/test/run-pass/issues/issue-26996.rs +++ b/src/test/run-pass/issues/issue-26996.rs @@ -2,9 +2,9 @@ // This test is bogus (i.e., should be compile-fail) during the period // where #54986 is implemented and #54987 is *not* implemented. For -// now: just ignore it under nll +// now: just ignore it // -// ignore-compare-mode-nll +// ignore-test // This test is checking that the write to `c.0` (which has been moved out of) // won't overwrite the state in `c2`. diff --git a/src/test/run-pass/issues/issue-27021.rs b/src/test/run-pass/issues/issue-27021.rs index ecb065b196400..3055137545082 100644 --- a/src/test/run-pass/issues/issue-27021.rs +++ b/src/test/run-pass/issues/issue-27021.rs @@ -2,9 +2,9 @@ // This test is bogus (i.e., should be compile-fail) during the period // where #54986 is implemented and #54987 is *not* implemented. For -// now: just ignore it under nll +// now: just ignore it // -// ignore-compare-mode-nll +// ignore-test // These are variants of issue-26996.rs. In all cases we are writing // into a record field that has been moved out of, and ensuring that diff --git a/src/test/run-pass/issues/issue-2723-b.rs b/src/test/run-pass/issues/issue-2723-b.rs index 41f264b6dc075..1910561d0ba43 100644 --- a/src/test/run-pass/issues/issue-2723-b.rs +++ b/src/test/run-pass/issues/issue-2723-b.rs @@ -1,5 +1,5 @@ // run-pass -// aux-build:issue_2723_a.rs +// aux-build:issue-2723-a.rs extern crate issue_2723_a; use issue_2723_a::f; diff --git a/src/test/run-pass/issues/issue-27268.rs b/src/test/run-pass/issues/issue-27268.rs index fccea452fbcef..161e2d4d204eb 100644 --- a/src/test/run-pass/issues/issue-27268.rs +++ b/src/test/run-pass/issues/issue-27268.rs @@ -1,4 +1,4 @@ // run-pass fn main() { - const _C: &'static Fn() = &||{}; + const _C: &'static dyn Fn() = &||{}; } diff --git a/src/test/run-pass/issues/issue-2734.rs b/src/test/run-pass/issues/issue-2734.rs index fcb224e2d043d..d449f6449aa09 100644 --- a/src/test/run-pass/issues/issue-2734.rs +++ b/src/test/run-pass/issues/issue-2734.rs @@ -11,8 +11,8 @@ trait hax { } impl hax for A { } -fn perform_hax(x: Box) -> Box { - box x as Box +fn perform_hax(x: Box) -> Box { + box x as Box } fn deadcode() { diff --git a/src/test/run-pass/issues/issue-2735.rs b/src/test/run-pass/issues/issue-2735.rs index c48bedf14f7b7..794c7d4edaa11 100644 --- a/src/test/run-pass/issues/issue-2735.rs +++ b/src/test/run-pass/issues/issue-2735.rs @@ -11,8 +11,8 @@ trait hax { } impl hax for A { } -fn perform_hax(x: Box) -> Box { - box x as Box +fn perform_hax(x: Box) -> Box { + box x as Box } fn deadcode() { diff --git a/src/test/run-pass/issues/issue-27890.rs b/src/test/run-pass/issues/issue-27890.rs index 0f6a932e4b886..9f85473380f82 100644 --- a/src/test/run-pass/issues/issue-27890.rs +++ b/src/test/run-pass/issues/issue-27890.rs @@ -1,6 +1,6 @@ // run-pass -static PLUS_ONE: &'static (Fn(i32) -> i32 + Sync) = (&|x: i32| { x + 1 }) - as &'static (Fn(i32) -> i32 + Sync); +static PLUS_ONE: &'static (dyn Fn(i32) -> i32 + Sync) = (&|x: i32| { x + 1 }) + as &'static (dyn Fn(i32) -> i32 + Sync); fn main() { assert_eq!(PLUS_ONE(2), 3); diff --git a/src/test/run-pass/issues/issue28498-must-work-ex1.rs b/src/test/run-pass/issues/issue-28498-must-work-ex1.rs similarity index 100% rename from src/test/run-pass/issues/issue28498-must-work-ex1.rs rename to src/test/run-pass/issues/issue-28498-must-work-ex1.rs diff --git a/src/test/run-pass/issues/issue-28498-must-work-ex2.rs b/src/test/run-pass/issues/issue-28498-must-work-ex2.rs new file mode 100644 index 0000000000000..cadf62461fdf5 --- /dev/null +++ b/src/test/run-pass/issues/issue-28498-must-work-ex2.rs @@ -0,0 +1,20 @@ +// run-pass +// Example taken from RFC 1238 text + +// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md +// #examples-of-code-that-must-continue-to-work + +use std::cell::Cell; + +struct Concrete<'a>(u32, Cell>>); + +struct Foo { data: Vec } + +fn main() { + let mut foo = Foo { data: Vec::new() }; + foo.data.push(Concrete(0, Cell::new(None))); + foo.data.push(Concrete(0, Cell::new(None))); + + foo.data[0].1.set(Some(&foo.data[1])); + foo.data[1].1.set(Some(&foo.data[0])); +} diff --git a/src/test/run-pass/issues/issue-28498-ugeh-ex1.rs b/src/test/run-pass/issues/issue-28498-ugeh-ex1.rs new file mode 100644 index 0000000000000..c4f249c45f13c --- /dev/null +++ b/src/test/run-pass/issues/issue-28498-ugeh-ex1.rs @@ -0,0 +1,29 @@ +// run-pass +#![allow(deprecated)] // FIXME: switch to `#[may_dangle]` below. + +// Example taken from RFC 1238 text + +// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md +// #example-of-the-unguarded-escape-hatch + +#![feature(dropck_parametricity)] +use std::cell::Cell; + +struct Concrete<'a>(u32, Cell>>); + +struct Foo { data: Vec } + +impl Drop for Foo { + // Below is the UGEH attribute + #[unsafe_destructor_blind_to_params] + fn drop(&mut self) { } +} + +fn main() { + let mut foo = Foo { data: Vec::new() }; + foo.data.push(Concrete(0, Cell::new(None))); + foo.data.push(Concrete(0, Cell::new(None))); + + foo.data[0].1.set(Some(&foo.data[1])); + foo.data[1].1.set(Some(&foo.data[0])); +} diff --git a/src/test/run-pass/issues/issue28498-ugeh-with-lifetime-param.rs b/src/test/run-pass/issues/issue-28498-ugeh-with-lifetime-param.rs similarity index 100% rename from src/test/run-pass/issues/issue28498-ugeh-with-lifetime-param.rs rename to src/test/run-pass/issues/issue-28498-ugeh-with-lifetime-param.rs diff --git a/src/test/run-pass/issues/issue28498-ugeh-with-passed-to-fn.rs b/src/test/run-pass/issues/issue-28498-ugeh-with-passed-to-fn.rs similarity index 100% rename from src/test/run-pass/issues/issue28498-ugeh-with-passed-to-fn.rs rename to src/test/run-pass/issues/issue-28498-ugeh-with-passed-to-fn.rs diff --git a/src/test/run-pass/issues/issue28498-ugeh-with-trait-bound.rs b/src/test/run-pass/issues/issue-28498-ugeh-with-trait-bound.rs similarity index 100% rename from src/test/run-pass/issues/issue28498-ugeh-with-trait-bound.rs rename to src/test/run-pass/issues/issue-28498-ugeh-with-trait-bound.rs diff --git a/src/test/run-pass/issues/issue-2935.rs b/src/test/run-pass/issues/issue-2935.rs index 58ade32b2502c..11641ca738018 100644 --- a/src/test/run-pass/issues/issue-2935.rs +++ b/src/test/run-pass/issues/issue-2935.rs @@ -20,7 +20,7 @@ pub fn main() { // let y = box ({a: 4}); // let z = box ({a: 4} as it); // let z = box ({a: true} as it); - let z: Box<_> = box (box true as Box); + let z: Box<_> = box (box true as Box); // x.f(); // y.f(); // (*z).f(); diff --git a/src/test/run-pass/issues/issue-29466.rs b/src/test/run-pass/issues/issue-29466.rs index e28185bc3a2d7..f8785a6321792 100644 --- a/src/test/run-pass/issues/issue-29466.rs +++ b/src/test/run-pass/issues/issue-29466.rs @@ -1,5 +1,9 @@ +// ignore-tidy-filelength +// // run-pass + #![allow(unused_variables)] + macro_rules! m( ($e1:expr => $e2:expr) => ({ $e1 }) ); diff --git a/src/test/run-pass/issues/issue29927-1.rs b/src/test/run-pass/issues/issue-29927-1.rs similarity index 100% rename from src/test/run-pass/issues/issue29927-1.rs rename to src/test/run-pass/issues/issue-29927-1.rs diff --git a/src/test/run-pass/issues/issue-30371.rs b/src/test/run-pass/issues/issue-30371.rs index 093d4b8c11924..58521b95cf637 100644 --- a/src/test/run-pass/issues/issue-30371.rs +++ b/src/test/run-pass/issues/issue-30371.rs @@ -8,4 +8,3 @@ fn main() { () => Some(0), } {} } - diff --git a/src/test/run-pass/issues/issue-30490.rs b/src/test/run-pass/issues/issue-30490.rs index 231d41cd86a97..76e72246887b6 100644 --- a/src/test/run-pass/issues/issue-30490.rs +++ b/src/test/run-pass/issues/issue-30490.rs @@ -1,6 +1,7 @@ // run-pass // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes // Previously libstd would set stdio descriptors of a child process // by `dup`ing the requested descriptors to inherit directly into the diff --git a/src/test/run-pass/issues/issue-3052.rs b/src/test/run-pass/issues/issue-3052.rs index 927102981e7f9..ee2456da3e215 100644 --- a/src/test/run-pass/issues/issue-3052.rs +++ b/src/test/run-pass/issues/issue-3052.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] // pretty-expanded FIXME #23616 -type Connection = Box) + 'static>; +type Connection = Box) + 'static>; fn f() -> Option { let mock_connection: Connection = Box::new(|_| {}); diff --git a/src/test/run-pass/issues/issue-30530.rs b/src/test/run-pass/issues/issue-30530.rs index 0ae270200a6a2..111fb8aa506a4 100644 --- a/src/test/run-pass/issues/issue-30530.rs +++ b/src/test/run-pass/issues/issue-30530.rs @@ -8,15 +8,17 @@ pub enum Handler { Default, #[allow(dead_code)] - Custom(*mut Box), + Custom(*mut Box), } fn main() { - take(Handler::Default, Box::new(main)); + #[allow(unused_must_use)] { + take(Handler::Default, Box::new(main)); + } } #[inline(never)] -pub fn take(h: Handler, f: Box) -> Box { +pub fn take(h: Handler, f: Box) -> Box { unsafe { match h { Handler::Custom(ptr) => *Box::from_raw(ptr), diff --git a/src/test/run-pass/issues/issue-30615.rs b/src/test/run-pass/issues/issue-30615.rs index 236a181fc1d25..c718449d84eed 100644 --- a/src/test/run-pass/issues/issue-30615.rs +++ b/src/test/run-pass/issues/issue-30615.rs @@ -1,5 +1,5 @@ // run-pass fn main() { - &0u8 as *const u8 as *const PartialEq; + &0u8 as *const u8 as *const dyn PartialEq; &[0u8] as *const [u8; 1] as *const [u8]; } diff --git a/src/test/run-pass/issues/issue-3136-b.rs b/src/test/run-pass/issues/issue-3136-b.rs new file mode 100644 index 0000000000000..c4ca7236e7615 --- /dev/null +++ b/src/test/run-pass/issues/issue-3136-b.rs @@ -0,0 +1,8 @@ +// run-pass +// aux-build:issue-3136-a.rc + +// pretty-expanded FIXME #23616 + +extern crate issue_3136_a; + +pub fn main() {} diff --git a/src/test/run-pass/issues/issue-32389.rs b/src/test/run-pass/issues/issue-32389.rs index 6824c66cb3751..cc94cc819d665 100644 --- a/src/test/run-pass/issues/issue-32389.rs +++ b/src/test/run-pass/issues/issue-32389.rs @@ -2,7 +2,7 @@ fn foo() -> T { loop {} } fn test() { - let ref mut a: &mut FnMut((i8,), i16) = foo(); + let ref mut a: &mut dyn FnMut((i8,), i16) = foo(); a((0,), 0); } diff --git a/src/test/run-pass/issues/issue-33387.rs b/src/test/run-pass/issues/issue-33387.rs index 792ff95200a1d..499fa7c1f27ac 100644 --- a/src/test/run-pass/issues/issue-33387.rs +++ b/src/test/run-pass/issues/issue-33387.rs @@ -15,18 +15,18 @@ impl Foo for [u8; 2] { struct Bar(T); -fn unsize_fat_ptr<'a>(x: &'a Bar) -> &'a Bar { +fn unsize_fat_ptr<'a>(x: &'a Bar) -> &'a Bar { x } -fn unsize_nested_fat_ptr(x: Arc) -> Arc { +fn unsize_nested_fat_ptr(x: Arc) -> Arc { x } fn main() { - let x: Box> = Box::new(Bar([1,2])); + let x: Box> = Box::new(Bar([1,2])); assert_eq!(unsize_fat_ptr(&*x).0.get(), [1, 2]); - let x: Arc = Arc::new([3, 4]); + let x: Arc = Arc::new([3, 4]); assert_eq!(unsize_nested_fat_ptr(x).get(), [3, 4]); } diff --git a/src/test/run-pass/issues/issue-33461.rs b/src/test/run-pass/issues/issue-33461.rs index 9c6c5bfe78c73..4e01d4d3061f9 100644 --- a/src/test/run-pass/issues/issue-33461.rs +++ b/src/test/run-pass/issues/issue-33461.rs @@ -24,5 +24,5 @@ impl Shape

    for TheType { fn main() { let ball = TheType { t: PhantomData }; - let handle: &Shape<()> = &ball; + let handle: &dyn Shape<()> = &ball; } diff --git a/src/test/run-pass/issues/issue-33770.rs b/src/test/run-pass/issues/issue-33770.rs index 7962509003f50..39ae009c99650 100644 --- a/src/test/run-pass/issues/issue-33770.rs +++ b/src/test/run-pass/issues/issue-33770.rs @@ -1,6 +1,7 @@ // run-pass // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::process::{Command, Stdio}; use std::env; diff --git a/src/test/run-pass/issues/issue-34503.rs b/src/test/run-pass/issues/issue-34503.rs index 1fb4b8759bd58..26e7358408f48 100644 --- a/src/test/run-pass/issues/issue-34503.rs +++ b/src/test/run-pass/issues/issue-34503.rs @@ -7,5 +7,5 @@ fn main() { where Option: Ord { *x < *x } } impl Foo for () {} - let _ = &() as &Foo; + let _ = &() as &dyn Foo; } diff --git a/src/test/run-pass/issues/issue-34784.rs b/src/test/run-pass/issues/issue-34784.rs index 4392637c39f26..d3206e9943009 100644 --- a/src/test/run-pass/issues/issue-34784.rs +++ b/src/test/run-pass/issues/issue-34784.rs @@ -17,4 +17,3 @@ fn main() { _ => {} } } - diff --git a/src/test/run-pass/issues/issue-34796.rs b/src/test/run-pass/issues/issue-34796.rs index a81040b8f4db3..88d5c50a27d29 100644 --- a/src/test/run-pass/issues/issue-34796.rs +++ b/src/test/run-pass/issues/issue-34796.rs @@ -8,8 +8,8 @@ // the symbol name. // The fix was to make the order in which predicates get encoded stable. -// aux-build:issue34796aux.rs -extern crate issue34796aux; +// aux-build:issue-34796-aux.rs +extern crate issue_34796_aux; fn mk() -> T { loop {} } @@ -19,7 +19,7 @@ struct Data { } fn main() { - issue34796aux::bar(|()| { + issue_34796_aux::bar(|()| { Data::<(), std::io::Error> { data: mk(), error: mk(), diff --git a/src/test/run-pass/issues/issue-35815.rs b/src/test/run-pass/issues/issue-35815.rs index 70e0ed9f7ce01..05fd1b15d43d0 100644 --- a/src/test/run-pass/issues/issue-35815.rs +++ b/src/test/run-pass/issues/issue-35815.rs @@ -10,6 +10,6 @@ struct Foo { fn main() { let foo: &Foo = &Foo { a: 1, b: false, c: 2i32 }; - let foo_unsized: &Foo = foo; + let foo_unsized: &Foo = foo; assert_eq!(mem::size_of_val(foo), mem::size_of_val(foo_unsized)); } diff --git a/src/test/run-pass/issues/issue-36260.rs b/src/test/run-pass/issues/issue-36260.rs index 728dd5ec8d0d6..d96dc80ea719c 100644 --- a/src/test/run-pass/issues/issue-36260.rs +++ b/src/test/run-pass/issues/issue-36260.rs @@ -2,7 +2,7 @@ // Make sure this compiles without getting a linker error because of missing // drop-glue because the collector missed adding drop-glue for the closure: -fn create_fn() -> Box { +fn create_fn() -> Box { let text = String::new(); Box::new(move || { let _ = &text; }) diff --git a/src/test/run-pass/issues/issue-36786-resolve-call.rs b/src/test/run-pass/issues/issue-36786-resolve-call.rs index 38461db544ffb..e5341ba7dbedd 100644 --- a/src/test/run-pass/issues/issue-36786-resolve-call.rs +++ b/src/test/run-pass/issues/issue-36786-resolve-call.rs @@ -3,6 +3,6 @@ // correctly fn main() { - let x : Vec> = vec![Box::new(|| ())]; + let x : Vec> = vec![Box::new(|| ())]; x[0]() } diff --git a/src/test/run-pass/issues/issue-3702.rs b/src/test/run-pass/issues/issue-3702.rs index 1420dff063cfa..f48d549b3eb2c 100644 --- a/src/test/run-pass/issues/issue-3702.rs +++ b/src/test/run-pass/issues/issue-3702.rs @@ -6,7 +6,7 @@ pub fn main() { fn to_string(&self) -> String; } - fn to_string(t: Box) { + fn to_string(t: Box) { println!("{}", (*t).to_string()); } diff --git a/src/test/run-pass/issues/issue-3794.rs b/src/test/run-pass/issues/issue-3794.rs index d6af65f787d70..408d8d866d862 100644 --- a/src/test/run-pass/issues/issue-3794.rs +++ b/src/test/run-pass/issues/issue-3794.rs @@ -16,7 +16,7 @@ impl T for S { } } -fn print_t(t: &T) { +fn print_t(t: &dyn T) { t.print(); } @@ -27,6 +27,6 @@ fn print_s(s: &S) { pub fn main() { let s: Box = box S { s: 5 }; print_s(&*s); - let t: Box = s as Box; + let t: Box = s as Box; print_t(&*t); } diff --git a/src/test/run-pass/issues/issue-38190.rs b/src/test/run-pass/issues/issue-38190.rs index 4f83dd263830e..cfa0420c80d1d 100644 --- a/src/test/run-pass/issues/issue-38190.rs +++ b/src/test/run-pass/issues/issue-38190.rs @@ -1,12 +1,15 @@ // run-pass -// aux-build:issue_38190.rs +// aux-build:issue-38190.rs // ignore-pretty issue #37195 #[macro_use] extern crate issue_38190; mod auxiliary { - m!([mod issue_38190;]); + m!([ + #[path = "issue-38190.rs"] + mod issue_38190; + ]); } fn main() {} diff --git a/src/test/run-pass/issues/issue-38226.rs b/src/test/run-pass/issues/issue-38226.rs index cd569c583f3a7..3213e3618a88b 100644 --- a/src/test/run-pass/issues/issue-38226.rs +++ b/src/test/run-pass/issues/issue-38226.rs @@ -2,7 +2,7 @@ // This test makes sure that we don't run into a linker error because of the // middle::reachable pass missing trait methods with default impls. -// aux-build:issue_38226_aux.rs +// aux-build:issue-38226-aux.rs // Need -Cno-prepopulate-passes to really disable inlining, otherwise the faulty // code gets optimized out: diff --git a/src/test/run-pass/issues/issue-38556.rs b/src/test/run-pass/issues/issue-38556.rs index 0cc247f5b9ca5..63fd9db08ff2f 100644 --- a/src/test/run-pass/issues/issue-38556.rs +++ b/src/test/run-pass/issues/issue-38556.rs @@ -9,6 +9,5 @@ macro_rules! reexport { reexport!(); fn main() { - use Bar; fn f(_: Bar) {} } diff --git a/src/test/run-pass/issues/issue-38715.rs b/src/test/run-pass/issues/issue-38715.rs index 9d793147e2475..e3c3a027f3cd0 100644 --- a/src/test/run-pass/issues/issue-38715.rs +++ b/src/test/run-pass/issues/issue-38715.rs @@ -1,6 +1,6 @@ // run-pass -// aux-build:issue_38715.rs -// aux-build:issue_38715-modern.rs +// aux-build:issue-38715.rs +// aux-build:issue-38715-modern.rs // Test that `#[macro_export] macro_rules!` shadow earlier `#[macro_export] macro_rules!` diff --git a/src/test/run-pass/issues/issue-39292.rs b/src/test/run-pass/issues/issue-39292.rs index 0b8139dd79514..968cf08916fd6 100644 --- a/src/test/run-pass/issues/issue-39292.rs +++ b/src/test/run-pass/issues/issue-39292.rs @@ -13,5 +13,5 @@ trait Bar: for<'a> Foo<&'a ()> { } impl Bar for () {} fn main() { - (&() as &Bar).print(); // Segfault + (&() as &dyn Bar).print(); // Segfault } diff --git a/src/test/run-pass/issues/issue-39367.rs b/src/test/run-pass/issues/issue-39367.rs index bd92224bce161..8314be3d14cc5 100644 --- a/src/test/run-pass/issues/issue-39367.rs +++ b/src/test/run-pass/issues/issue-39367.rs @@ -11,14 +11,13 @@ fn arena() -> &'static ArenaSet> { ArenaSet(vec![], &Z) } unsafe { - use std::sync::{Once, ONCE_INIT}; + use std::sync::Once; fn require_sync(_: &T) { } unsafe fn __stability() -> &'static ArenaSet> { use std::mem::transmute; - use std::boxed::Box; - static mut DATA: *const ArenaSet> = 0 as *const ArenaSet>; + static mut DATA: *const ArenaSet> = std::ptr::null_mut(); - static mut ONCE: Once = ONCE_INIT; + static mut ONCE: Once = Once::new(); ONCE.call_once(|| { DATA = transmute ::>>, *const ArenaSet>> diff --git a/src/test/run-pass/issues/issue-39709.rs b/src/test/run-pass/issues/issue-39709.rs index 8ea49c2082b8a..69ef2700ef367 100644 --- a/src/test/run-pass/issues/issue-39709.rs +++ b/src/test/run-pass/issues/issue-39709.rs @@ -3,4 +3,3 @@ fn main() { println!("{}", { macro_rules! x { ($(t:tt)*) => {} } 33 }); } - diff --git a/src/test/run-pass/issues/issue-3979-xcrate.rs b/src/test/run-pass/issues/issue-3979-xcrate.rs index 0e47dee5b65be..fcb1f55c32f9c 100644 --- a/src/test/run-pass/issues/issue-3979-xcrate.rs +++ b/src/test/run-pass/issues/issue-3979-xcrate.rs @@ -1,6 +1,6 @@ // run-pass #![allow(dead_code)] -// aux-build:issue_3979_traits.rs +// aux-build:issue-3979-traits.rs extern crate issue_3979_traits; use issue_3979_traits::{Positioned, Movable}; diff --git a/src/test/run-pass/issues/issue-39823.rs b/src/test/run-pass/issues/issue-39823.rs index 8a52399273b9f..148cf527e7cb7 100644 --- a/src/test/run-pass/issues/issue-39823.rs +++ b/src/test/run-pass/issues/issue-39823.rs @@ -1,5 +1,5 @@ // run-pass -// aux-build:issue_39823.rs +// aux-build:issue-39823.rs extern crate issue_39823; use issue_39823::{RemoteC, RemoteG}; @@ -11,15 +11,15 @@ struct LocalC(u32); struct LocalG(T); fn main() { - let virtual_localc : &Fn(_) -> LocalC = &LocalC; + let virtual_localc : &dyn Fn(_) -> LocalC = &LocalC; assert_eq!(virtual_localc(1), LocalC(1)); - let virtual_localg : &Fn(_) -> LocalG = &LocalG; + let virtual_localg : &dyn Fn(_) -> LocalG = &LocalG; assert_eq!(virtual_localg(1), LocalG(1)); - let virtual_remotec : &Fn(_) -> RemoteC = &RemoteC; + let virtual_remotec : &dyn Fn(_) -> RemoteC = &RemoteC; assert_eq!(virtual_remotec(1), RemoteC(1)); - let virtual_remoteg : &Fn(_) -> RemoteG = &RemoteG; + let virtual_remoteg : &dyn Fn(_) -> RemoteG = &RemoteG; assert_eq!(virtual_remoteg(1), RemoteG(1)); } diff --git a/src/test/run-pass/issues/issue-40469.rs b/src/test/run-pass/issues/issue-40469.rs index 2e8247e032b02..25e08ef85e967 100644 --- a/src/test/run-pass/issues/issue-40469.rs +++ b/src/test/run-pass/issues/issue-40469.rs @@ -3,7 +3,7 @@ #![allow(dead_code)] -include!("auxiliary/issue_40469.rs"); +include!("auxiliary/issue-40469.rs"); fn f() { m!(); } fn main() {} diff --git a/src/test/run-pass/issues/issue-41053.rs b/src/test/run-pass/issues/issue-41053.rs index b9d8f00ff21d6..967edfd441576 100644 --- a/src/test/run-pass/issues/issue-41053.rs +++ b/src/test/run-pass/issues/issue-41053.rs @@ -1,13 +1,13 @@ // run-pass -// aux-build:issue_41053.rs +// aux-build:issue-41053.rs pub trait Trait { fn foo(&self) {} } pub struct Foo; impl Iterator for Foo { - type Item = Box; - fn next(&mut self) -> Option> { + type Item = Box; + fn next(&mut self) -> Option> { extern crate issue_41053; impl ::Trait for issue_41053::Test { fn foo(&self) {} diff --git a/src/test/run-pass/issues/issue-41744.rs b/src/test/run-pass/issues/issue-41744.rs index edc4354b25336..dcdd1c21ee527 100644 --- a/src/test/run-pass/issues/issue-41744.rs +++ b/src/test/run-pass/issues/issue-41744.rs @@ -3,5 +3,5 @@ trait Tc {} impl Tc for bool {} fn main() { - let _: &[&Tc] = &[&true]; + let _: &[&dyn Tc] = &[&true]; } diff --git a/src/test/run-pass/issues/issue-42007.rs b/src/test/run-pass/issues/issue-42007.rs index de1367ec80f17..a477e476eb9f6 100644 --- a/src/test/run-pass/issues/issue-42007.rs +++ b/src/test/run-pass/issues/issue-42007.rs @@ -1,6 +1,6 @@ // run-pass #![allow(dead_code)] -// aux-build:issue_42007_s.rs +// aux-build:issue-42007-s.rs extern crate issue_42007_s; diff --git a/src/test/run-pass/issues/issue-42210.rs b/src/test/run-pass/issues/issue-42210.rs index cf4a698f516f3..318e3099f98ba 100644 --- a/src/test/run-pass/issues/issue-42210.rs +++ b/src/test/run-pass/issues/issue-42210.rs @@ -12,9 +12,9 @@ struct Bar; trait Baz { } -impl Foo for (Bar, Baz) { } +impl Foo for (Bar, dyn Baz) { } fn main() { - <(Bar, Baz) as Foo>::foo() + <(Bar, dyn Baz) as Foo>::foo() } diff --git a/src/test/run-pass/issues/issue-42453.rs b/src/test/run-pass/issues/issue-42453.rs index bea441c2bea33..92fefceabc131 100644 --- a/src/test/run-pass/issues/issue-42453.rs +++ b/src/test/run-pass/issues/issue-42453.rs @@ -8,4 +8,3 @@ struct builder; fn main() { } - diff --git a/src/test/run-pass/issues/issue-43132.rs b/src/test/run-pass/issues/issue-43132.rs index 726a86142f6a5..c886f4b0a2d6b 100644 --- a/src/test/run-pass/issues/issue-43132.rs +++ b/src/test/run-pass/issues/issue-43132.rs @@ -6,7 +6,7 @@ fn main() { fn foo() { let b = mk::< - Forward<(Box>,)>, + Forward<(Box>,)>, >(); b.map_err(|_| ()).join(); } diff --git a/src/test/run-pass/issues/issue-4333.rs b/src/test/run-pass/issues/issue-4333.rs index ae9f4c8bdb523..3df319b683f47 100644 --- a/src/test/run-pass/issues/issue-4333.rs +++ b/src/test/run-pass/issues/issue-4333.rs @@ -5,6 +5,6 @@ use std::io; pub fn main() { - let stdout = &mut io::stdout() as &mut io::Write; + let stdout = &mut io::stdout() as &mut dyn io::Write; stdout.write(b"Hello!"); } diff --git a/src/test/run-pass/issue-45510.rs b/src/test/run-pass/issues/issue-45510.rs similarity index 100% rename from src/test/run-pass/issue-45510.rs rename to src/test/run-pass/issues/issue-45510.rs diff --git a/src/test/run-pass/issues/issue-46069.rs b/src/test/run-pass/issues/issue-46069.rs index fba2a2ebe3b04..1d4f789828d8b 100644 --- a/src/test/run-pass/issues/issue-46069.rs +++ b/src/test/run-pass/issues/issue-46069.rs @@ -17,7 +17,7 @@ fn copy_ex() { } fn main() { - let _f = 0 as *mut >> as Iterator>::Item; + let _f: *mut >> as Iterator>::Item = std::ptr::null_mut(); copy_ex(); } diff --git a/src/test/run-pass/issues/issue-47638.rs b/src/test/run-pass/issues/issue-47638.rs index 357364ee61273..a1ed3c3654401 100644 --- a/src/test/run-pass/issues/issue-47638.rs +++ b/src/test/run-pass/issues/issue-47638.rs @@ -1,10 +1,10 @@ // run-pass #![allow(unused_variables)] -fn id<'c, 'b>(f: &'c &'b Fn(&i32)) -> &'c &'b Fn(&'static i32) { +fn id<'c, 'b>(f: &'c &'b dyn Fn(&i32)) -> &'c &'b dyn Fn(&'static i32) { f } fn main() { - let f: &Fn(&i32) = &|x| {}; + let f: &dyn Fn(&i32) = &|x| {}; id(&f); } diff --git a/src/test/run-pass/issue-48006.rs b/src/test/run-pass/issues/issue-48006.rs similarity index 100% rename from src/test/run-pass/issue-48006.rs rename to src/test/run-pass/issues/issue-48006.rs diff --git a/src/test/run-pass/issues/issue-48962.rs b/src/test/run-pass/issues/issue-48962.rs index 7c644789834d4..80d815379bec2 100644 --- a/src/test/run-pass/issues/issue-48962.rs +++ b/src/test/run-pass/issues/issue-48962.rs @@ -1,7 +1,6 @@ // run-pass #![allow(unused_must_use)] // Test that we are able to reinitialize box with moved referent -#![feature(nll)] static mut ORDER: [usize; 3] = [0, 0, 0]; static mut INDEX: usize = 0; diff --git a/src/test/run-pass/issues/issue-49298.rs b/src/test/run-pass/issues/issue-49298.rs index 56443f410205e..697a160b4ecb4 100644 --- a/src/test/run-pass/issues/issue-49298.rs +++ b/src/test/run-pass/issues/issue-49298.rs @@ -4,9 +4,9 @@ // This test is bogus (i.e., should be compile-fail) during the period // where #54986 is implemented and #54987 is *not* implemented. For -// now: just ignore it under nll +// now: just ignore it // -// ignore-compare-mode-nll +// ignore-test // This test is checking that the space allocated for `x.1` does not // overlap with `y`. (The reason why such a thing happened at one diff --git a/src/test/run-pass/issues/issue-49955.rs b/src/test/run-pass/issues/issue-49955.rs index aa114ec0c1383..f2f3ebff2db18 100644 --- a/src/test/run-pass/issues/issue-49955.rs +++ b/src/test/run-pass/issues/issue-49955.rs @@ -1,5 +1,4 @@ // run-pass -// compile-flags: -Z borrowck=compare const ALL_THE_NUMS: [u32; 1] = [ 1 diff --git a/src/test/run-pass/issues/issue-5008-borrowed-traitobject-method-call.rs b/src/test/run-pass/issues/issue-5008-borrowed-traitobject-method-call.rs index 457fca3fedf06..fc869ae4fec26 100644 --- a/src/test/run-pass/issues/issue-5008-borrowed-traitobject-method-call.rs +++ b/src/test/run-pass/issues/issue-5008-borrowed-traitobject-method-call.rs @@ -23,12 +23,12 @@ impl Debuggable for Thing { fn debug_name(&self) -> String { self.name.clone() } } -fn print_name(x: &Debuggable) +fn print_name(x: &dyn Debuggable) { println!("debug_name = {}", x.debug_name()); } pub fn main() { let thing = Thing::new(); - print_name(&thing as &Debuggable); + print_name(&thing as &dyn Debuggable); } diff --git a/src/test/run-pass/issues/issue-51345.rs b/src/test/run-pass/issues/issue-51345.rs index 29a0a328503e1..15571e8bf5b28 100644 --- a/src/test/run-pass/issues/issue-51345.rs +++ b/src/test/run-pass/issues/issue-51345.rs @@ -1,6 +1,5 @@ // run-pass #![allow(unreachable_code)] -#![feature(nll)] fn main() { let mut v = Vec::new(); diff --git a/src/test/run-pass/issues/issue-5192.rs b/src/test/run-pass/issues/issue-5192.rs index 74d8d861a7d05..5a83d1c2ff9fd 100644 --- a/src/test/run-pass/issues/issue-5192.rs +++ b/src/test/run-pass/issues/issue-5192.rs @@ -24,12 +24,12 @@ impl EventLoop for UvEventLoop { } pub struct Scheduler { - event_loop: Box, + event_loop: Box, } impl Scheduler { - pub fn new(event_loop: Box) -> Scheduler { + pub fn new(event_loop: Box) -> Scheduler { Scheduler { event_loop: event_loop, } @@ -37,5 +37,5 @@ impl Scheduler { } pub fn main() { - let _sched = Scheduler::new(box UvEventLoop::new() as Box); + let _sched = Scheduler::new(box UvEventLoop::new() as Box); } diff --git a/src/test/run-pass/issue-53728.rs b/src/test/run-pass/issues/issue-53728.rs similarity index 100% rename from src/test/run-pass/issue-53728.rs rename to src/test/run-pass/issues/issue-53728.rs diff --git a/src/test/run-pass/issue-53843.rs b/src/test/run-pass/issues/issue-53843.rs similarity index 100% rename from src/test/run-pass/issue-53843.rs rename to src/test/run-pass/issues/issue-53843.rs diff --git a/src/test/run-pass/issue-54462-mutable-noalias-correctness.rs b/src/test/run-pass/issues/issue-54462-mutable-noalias-correctness.rs similarity index 100% rename from src/test/run-pass/issue-54462-mutable-noalias-correctness.rs rename to src/test/run-pass/issues/issue-54462-mutable-noalias-correctness.rs diff --git a/src/test/run-pass/issue-54467.rs b/src/test/run-pass/issues/issue-54467.rs similarity index 100% rename from src/test/run-pass/issue-54467.rs rename to src/test/run-pass/issues/issue-54467.rs diff --git a/src/test/run-pass/issue-55376.rs b/src/test/run-pass/issues/issue-55376.rs similarity index 100% rename from src/test/run-pass/issue-55376.rs rename to src/test/run-pass/issues/issue-55376.rs diff --git a/src/test/run-pass/issue-55380.rs b/src/test/run-pass/issues/issue-55380.rs similarity index 100% rename from src/test/run-pass/issue-55380.rs rename to src/test/run-pass/issues/issue-55380.rs diff --git a/src/test/run-pass/issue-56237.rs b/src/test/run-pass/issues/issue-56237.rs similarity index 100% rename from src/test/run-pass/issue-56237.rs rename to src/test/run-pass/issues/issue-56237.rs diff --git a/src/test/run-pass/issues/issue-5666.rs b/src/test/run-pass/issues/issue-5666.rs index bf919ed5b1073..aa51327783012 100644 --- a/src/test/run-pass/issues/issue-5666.rs +++ b/src/test/run-pass/issues/issue-5666.rs @@ -19,7 +19,7 @@ impl Barks for Dog { pub fn main() { let snoopy = box Dog{name: "snoopy".to_string()}; let bubbles = box Dog{name: "bubbles".to_string()}; - let barker = [snoopy as Box, bubbles as Box]; + let barker = [snoopy as Box, bubbles as Box]; for pup in &barker { println!("{}", pup.bark()); diff --git a/src/test/run-pass/issues/issue-5708.rs b/src/test/run-pass/issues/issue-5708.rs index d3a2858873caf..6fe9943d3689f 100644 --- a/src/test/run-pass/issues/issue-5708.rs +++ b/src/test/run-pass/issues/issue-5708.rs @@ -21,11 +21,11 @@ impl Inner for isize { } struct Outer<'a> { - inner: &'a (Inner+'a) + inner: &'a (dyn Inner+'a) } impl<'a> Outer<'a> { - fn new(inner: &Inner) -> Outer { + fn new(inner: &dyn Inner) -> Outer { Outer { inner: inner } @@ -34,7 +34,7 @@ impl<'a> Outer<'a> { pub fn main() { let inner: isize = 5; - let outer = Outer::new(&inner as &Inner); + let outer = Outer::new(&inner as &dyn Inner); outer.inner.print(); } @@ -45,11 +45,11 @@ pub trait MyTrait { } pub struct MyContainer<'a, T:'a> { - foos: Vec<&'a (MyTrait+'a)> , + foos: Vec<&'a (dyn MyTrait+'a)> , } impl<'a, T> MyContainer<'a, T> { - pub fn add (&mut self, foo: &'a MyTrait) { + pub fn add (&mut self, foo: &'a dyn MyTrait) { self.foos.push(foo); } } diff --git a/src/test/run-pass/issues/issue-58435-ice-with-assoc-const.rs b/src/test/run-pass/issues/issue-58435-ice-with-assoc-const.rs new file mode 100644 index 0000000000000..94e2b2563df59 --- /dev/null +++ b/src/test/run-pass/issues/issue-58435-ice-with-assoc-const.rs @@ -0,0 +1,17 @@ +// The const-evaluator was at one point ICE'ing while trying to +// evaluate the body of `fn id` during the `s.id()` call in main. + +struct S(T); + +impl S { + const ID: fn(&S) -> &S = |s| s; + pub fn id(&self) -> &Self { + Self::ID(self) // This, plus call below ... + } +} + +fn main() { + let s = S(10u32); + assert!(S::::ID(&s).0 == 10); // Works fine + assert!(s.id().0 == 10); // ... causes compiler to panic +} diff --git a/src/test/run-pass/issues/issue-58463.rs b/src/test/run-pass/issues/issue-58463.rs new file mode 100644 index 0000000000000..8ab845366b7b4 --- /dev/null +++ b/src/test/run-pass/issues/issue-58463.rs @@ -0,0 +1,8 @@ +// run-pass +// compile-flags:-C debuginfo=2 +fn foo() -> impl Copy { + foo +} +fn main() { + foo(); +} diff --git a/src/test/run-pass/issues/issue-5988.rs b/src/test/run-pass/issues/issue-5988.rs index db77ca4375fc3..303fb4fbc9416 100644 --- a/src/test/run-pass/issues/issue-5988.rs +++ b/src/test/run-pass/issues/issue-5988.rs @@ -19,6 +19,6 @@ impl T for A { fn main() { let a = A; - let br = &a as &B; + let br = &a as &dyn B; br.f(); } diff --git a/src/test/run-pass/issues/issue-6128.rs b/src/test/run-pass/issues/issue-6128.rs index f23a317c6ba6a..8859fbe6afb7b 100644 --- a/src/test/run-pass/issues/issue-6128.rs +++ b/src/test/run-pass/issues/issue-6128.rs @@ -20,5 +20,5 @@ impl Graph for HashMap { pub fn main() { let g : Box> = box HashMap::new(); - let _g2 : Box> = g as Box>; + let _g2 : Box> = g as Box>; } diff --git a/src/test/run-pass/issues/issue-6157.rs b/src/test/run-pass/issues/issue-6157.rs index 354797cb2a784..b7a44ed862395 100644 --- a/src/test/run-pass/issues/issue-6157.rs +++ b/src/test/run-pass/issues/issue-6157.rs @@ -9,7 +9,7 @@ impl OpInt for F where F: FnMut(isize, isize) -> isize { } } -fn squarei<'a>(x: isize, op: &'a mut OpInt) -> isize { op.call(x, x) } +fn squarei<'a>(x: isize, op: &'a mut dyn OpInt) -> isize { op.call(x, x) } fn muli(x:isize, y:isize) -> isize { x * y } @@ -17,7 +17,7 @@ pub fn main() { let mut f = |x, y| muli(x, y); { let g = &mut f; - let h = g as &mut OpInt; + let h = g as &mut dyn OpInt; squarei(3, h); } } diff --git a/src/test/run-pass/issues/issue-61894.rs b/src/test/run-pass/issues/issue-61894.rs new file mode 100644 index 0000000000000..9ab969be46a45 --- /dev/null +++ b/src/test/run-pass/issues/issue-61894.rs @@ -0,0 +1,19 @@ +#![feature(core_intrinsics)] + +use std::intrinsics::type_name; + +struct Bar(M); + +impl Bar { + fn foo(&self) -> &'static str { + fn f() {} + fn type_name_of(_: T) -> &'static str { + unsafe { type_name::() } + } + type_name_of(f) + } +} + +fn main() { + assert_eq!(Bar(()).foo(), "issue_61894::Bar<_>::foo::f"); +} diff --git a/src/test/run-pass/issues/issue-6318.rs b/src/test/run-pass/issues/issue-6318.rs index d416048265fa5..d8bd83f0dc6ad 100644 --- a/src/test/run-pass/issues/issue-6318.rs +++ b/src/test/run-pass/issues/issue-6318.rs @@ -4,7 +4,7 @@ #![feature(box_syntax)] pub enum Thing { - A(Box) + A(Box) } pub trait Foo { @@ -16,7 +16,7 @@ pub struct Struct; impl Foo for Struct {} pub fn main() { - match Thing::A(box Struct as Box) { + match Thing::A(box Struct as Box) { Thing::A(_a) => 0, }; } diff --git a/src/test/run-pass/issues/issue-7563.rs b/src/test/run-pass/issues/issue-7563.rs index 820fffd1056a9..c62405554b4d1 100644 --- a/src/test/run-pass/issues/issue-7563.rs +++ b/src/test/run-pass/issues/issue-7563.rs @@ -16,7 +16,7 @@ struct B<'a> { b: isize, pa: &'a A } } impl<'a> B<'a> { - fn get_pa(&self) -> &'a IDummy { self.pa as &'a IDummy } + fn get_pa(&self) -> &'a dyn IDummy { self.pa as &'a dyn IDummy } } pub fn main() { diff --git a/src/test/run-pass/issues/issue-7911.rs b/src/test/run-pass/issues/issue-7911.rs index cb7e009d074e5..de833324bd20f 100644 --- a/src/test/run-pass/issues/issue-7911.rs +++ b/src/test/run-pass/issues/issue-7911.rs @@ -12,18 +12,18 @@ struct Foo { bar: Bar } impl FooBar for Bar {} trait Test { - fn get_immut(&self) -> &FooBar; - fn get_mut(&mut self) -> &mut FooBar; + fn get_immut(&self) -> &dyn FooBar; + fn get_mut(&mut self) -> &mut dyn FooBar; } macro_rules! generate_test { ($type_:path, $slf:ident, $field:expr) => ( impl Test for $type_ { - fn get_immut(&$slf) -> &FooBar { - &$field as &FooBar + fn get_immut(&$slf) -> &dyn FooBar { + &$field as &dyn FooBar } - fn get_mut(&mut $slf) -> &mut FooBar { - &mut $field as &mut FooBar + fn get_mut(&mut $slf) -> &mut dyn FooBar { + &mut $field as &mut dyn FooBar } } )} diff --git a/src/test/run-pass/issues/issue-8248.rs b/src/test/run-pass/issues/issue-8248.rs index 239c432e457bf..31a305c31bee2 100644 --- a/src/test/run-pass/issues/issue-8248.rs +++ b/src/test/run-pass/issues/issue-8248.rs @@ -7,9 +7,9 @@ trait A { struct B; impl A for B {} -fn foo(_: &mut A) {} +fn foo(_: &mut dyn A) {} pub fn main() { let mut b = B; - foo(&mut b as &mut A); + foo(&mut b as &mut dyn A); } diff --git a/src/test/run-pass/issues/issue-8249.rs b/src/test/run-pass/issues/issue-8249.rs index db49f354a3929..d09dff3a69709 100644 --- a/src/test/run-pass/issues/issue-8249.rs +++ b/src/test/run-pass/issues/issue-8249.rs @@ -9,10 +9,10 @@ struct B; impl A for B {} struct C<'a> { - foo: &'a mut (A+'a), + foo: &'a mut (dyn A+'a), } -fn foo(a: &mut A) { +fn foo(a: &mut dyn A) { C{ foo: a }; } diff --git a/src/test/run-pass/issues/issue-8401.rs b/src/test/run-pass/issues/issue-8401.rs index 97d66c5e40f04..1257bab6c0cd6 100644 --- a/src/test/run-pass/issues/issue-8401.rs +++ b/src/test/run-pass/issues/issue-8401.rs @@ -1,5 +1,5 @@ // run-pass -// aux-build:issue_8401.rs +// aux-build:issue-8401.rs // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/issues/issue-8860.rs b/src/test/run-pass/issues/issue-8860.rs index 7925ef3b5dfab..b89a80c1307cf 100644 --- a/src/test/run-pass/issues/issue-8860.rs +++ b/src/test/run-pass/issues/issue-8860.rs @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -// compile-flags: -Z borrowck=compare static mut DROP: isize = 0; static mut DROP_S: isize = 0; diff --git a/src/test/run-pass/issues/issue-9123.rs b/src/test/run-pass/issues/issue-9123.rs index 5072ca6ba5374..8c21d06c4776f 100644 --- a/src/test/run-pass/issues/issue-9123.rs +++ b/src/test/run-pass/issues/issue-9123.rs @@ -1,5 +1,5 @@ // run-pass -// aux-build:issue_9123.rs +// aux-build:issue-9123.rs // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/issues/issue-9129.rs b/src/test/run-pass/issues/issue-9129.rs index c81b9b1a10d0d..3d87e1c203783 100644 --- a/src/test/run-pass/issues/issue-9129.rs +++ b/src/test/run-pass/issues/issue-9129.rs @@ -20,7 +20,7 @@ fn Ident_new() -> Ident { Ident {name: 0x6789ABCD } } -pub fn light_fuse(fld: Box) { +pub fn light_fuse(fld: Box) { int3!(); let f = || { int3!(); @@ -30,6 +30,6 @@ pub fn light_fuse(fld: Box) { } pub fn main() { - let b = box S as Box; + let b = box S as Box; light_fuse(b); } diff --git a/src/test/run-pass/issues/issue-9155.rs b/src/test/run-pass/issues/issue-9155.rs new file mode 100644 index 0000000000000..4b5c451e853ed --- /dev/null +++ b/src/test/run-pass/issues/issue-9155.rs @@ -0,0 +1,12 @@ +// run-pass +// aux-build:issue-9155.rs + +// pretty-expanded FIXME #23616 + +extern crate issue_9155; + +struct Baz; + +pub fn main() { + issue_9155::Foo::new(Baz); +} diff --git a/src/test/run-pass/issues/issue-9188.rs b/src/test/run-pass/issues/issue-9188.rs index d7c39e9d50556..34e61fdf68bc0 100644 --- a/src/test/run-pass/issues/issue-9188.rs +++ b/src/test/run-pass/issues/issue-9188.rs @@ -1,5 +1,5 @@ // run-pass -// aux-build:issue_9188.rs +// aux-build:issue-9188.rs extern crate issue_9188; diff --git a/src/test/run-pass/issues/issue-9394-inherited-trait-calls.rs b/src/test/run-pass/issues/issue-9394-inherited-trait-calls.rs index c4c95aa1aaed1..cc0dd4fc14a0d 100644 --- a/src/test/run-pass/issues/issue-9394-inherited-trait-calls.rs +++ b/src/test/run-pass/issues/issue-9394-inherited-trait-calls.rs @@ -52,7 +52,7 @@ impl Super for X { pub fn main() { let n = X; - let s = &n as &Super; + let s = &n as &dyn Super; assert_eq!(s.bar(),"super bar".to_string()); assert_eq!(s.foo(),"base foo".to_string()); assert_eq!(s.foo1(),"base foo1".to_string()); diff --git a/src/test/run-pass/issues/issue-9396.rs b/src/test/run-pass/issues/issue-9396.rs index 3e7e9a51cdd3a..27b5185377d97 100644 --- a/src/test/run-pass/issues/issue-9396.rs +++ b/src/test/run-pass/issues/issue-9396.rs @@ -2,6 +2,7 @@ #![allow(unused_must_use)] #![allow(deprecated)] // ignore-emscripten no threads support +// ignore-sgx no thread sleep support use std::sync::mpsc::{TryRecvError, channel}; use std::thread; diff --git a/src/test/run-pass/issues/issue-9951.rs b/src/test/run-pass/issues/issue-9951.rs index 4e14bdbd73429..2698a3b17c6c2 100644 --- a/src/test/run-pass/issues/issue-9951.rs +++ b/src/test/run-pass/issues/issue-9951.rs @@ -11,11 +11,11 @@ impl Bar for u8 { } fn main() { - let (a, b) = (&5u8 as &Bar, &9u8 as &Bar); - let (c, d): (&Bar, &Bar) = (a, b); + let (a, b) = (&5u8 as &dyn Bar, &9u8 as &dyn Bar); + let (c, d): (&dyn Bar, &dyn Bar) = (a, b); - let (a, b) = (Box::new(5u8) as Box, Box::new(9u8) as Box); - let (c, d): (&Bar, &Bar) = (&*a, &*b); + let (a, b) = (Box::new(5u8) as Box, Box::new(9u8) as Box); + let (c, d): (&dyn Bar, &dyn Bar) = (&*a, &*b); - let (c, d): (&Bar, &Bar) = (&5, &9); + let (c, d): (&dyn Bar, &dyn Bar) = (&5, &9); } diff --git a/src/test/run-pass/issues/issue2170exe.rs b/src/test/run-pass/issues/issue2170exe.rs deleted file mode 100644 index 4169ddf9bb7f7..0000000000000 --- a/src/test/run-pass/issues/issue2170exe.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass -// aux-build:issue2170lib.rs -// pretty-expanded FIXME #23616 - -extern crate issue2170lib; - -pub fn main() { - // let _ = issue2170lib::rsrc(2); -} diff --git a/src/test/run-pass/issues/issue24687-embed-debuginfo/auxiliary/issue24687_lib.rs b/src/test/run-pass/issues/issue24687-embed-debuginfo/auxiliary/issue24687_lib.rs deleted file mode 100644 index 3ae53baa82a5a..0000000000000 --- a/src/test/run-pass/issues/issue24687-embed-debuginfo/auxiliary/issue24687_lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![crate_type="lib"] - -// This is a file that pulls in a separate file as a submodule, where -// that separate file has many multi-byte characters, to try to -// encourage the compiler to trip on them. - -mod issue24687_mbcs_in_comments; - -pub use issue24687_mbcs_in_comments::D; - diff --git a/src/test/run-pass/issues/issue24687-embed-debuginfo/main.rs b/src/test/run-pass/issues/issue24687-embed-debuginfo/main.rs deleted file mode 100644 index a0cda4fad26f5..0000000000000 --- a/src/test/run-pass/issues/issue24687-embed-debuginfo/main.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass -// aux-build:issue24687_lib.rs -// compile-flags:-g - -extern crate issue24687_lib as d; - -fn main() { - // Create a d, which has a destructor whose body will be codegen'ed - // into the generated code here, and thus the local debuginfo will - // need references into the original source locations from - // `importer` above. - let _d = d::D("Hi"); -} diff --git a/src/test/run-pass/issues/issue28498-must-work-ex2.rs b/src/test/run-pass/issues/issue28498-must-work-ex2.rs deleted file mode 100644 index 17111308555d8..0000000000000 --- a/src/test/run-pass/issues/issue28498-must-work-ex2.rs +++ /dev/null @@ -1,21 +0,0 @@ -// run-pass -// Example taken from RFC 1238 text - -// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md -// #examples-of-code-that-must-continue-to-work - -use std::cell::Cell; - -struct Concrete<'a>(u32, Cell>>); - -struct Foo { data: Vec } - -fn main() { - let mut foo = Foo { data: Vec::new() }; - foo.data.push(Concrete(0, Cell::new(None))); - foo.data.push(Concrete(0, Cell::new(None))); - - foo.data[0].1.set(Some(&foo.data[1])); - foo.data[1].1.set(Some(&foo.data[0])); -} - diff --git a/src/test/run-pass/issues/issue28498-ugeh-ex1.rs b/src/test/run-pass/issues/issue28498-ugeh-ex1.rs deleted file mode 100644 index 65d5588871b65..0000000000000 --- a/src/test/run-pass/issues/issue28498-ugeh-ex1.rs +++ /dev/null @@ -1,30 +0,0 @@ -// run-pass -#![allow(deprecated)] // FIXME: switch to `#[may_dangle]` below. - -// Example taken from RFC 1238 text - -// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md -// #example-of-the-unguarded-escape-hatch - -#![feature(dropck_parametricity)] -use std::cell::Cell; - -struct Concrete<'a>(u32, Cell>>); - -struct Foo { data: Vec } - -impl Drop for Foo { - // Below is the UGEH attribute - #[unsafe_destructor_blind_to_params] - fn drop(&mut self) { } -} - -fn main() { - let mut foo = Foo { data: Vec::new() }; - foo.data.push(Concrete(0, Cell::new(None))); - foo.data.push(Concrete(0, Cell::new(None))); - - foo.data[0].1.set(Some(&foo.data[1])); - foo.data[1].1.set(Some(&foo.data[0])); -} - diff --git a/src/test/run-pass/issues/issue_26873_multifile/A/mod.rs b/src/test/run-pass/issues/issue_26873_multifile/A/mod.rs deleted file mode 100644 index 20f40a06782ae..0000000000000 --- a/src/test/run-pass/issues/issue_26873_multifile/A/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -// run-pass -pub mod B; -pub mod C; - -pub use self::C::T; - diff --git a/src/test/run-pass/issues/issue_26873_multifile/mod.rs b/src/test/run-pass/issues/issue_26873_multifile/mod.rs deleted file mode 100644 index 52deea79a20c7..0000000000000 --- a/src/test/run-pass/issues/issue_26873_multifile/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -// run-pass -mod A; - -use self::A::*; - diff --git a/src/test/run-pass/issues/issue_3136_b.rs b/src/test/run-pass/issues/issue_3136_b.rs deleted file mode 100644 index f0bdd2b5ec050..0000000000000 --- a/src/test/run-pass/issues/issue_3136_b.rs +++ /dev/null @@ -1,7 +0,0 @@ -// run-pass -// aux-build:issue_3136_a.rc - -// pretty-expanded FIXME #23616 - -extern crate issue_3136_a; -pub fn main() {} diff --git a/src/test/run-pass/issues/issue_9155.rs b/src/test/run-pass/issues/issue_9155.rs deleted file mode 100644 index 87c453be1420b..0000000000000 --- a/src/test/run-pass/issues/issue_9155.rs +++ /dev/null @@ -1,12 +0,0 @@ -// run-pass -// aux-build:issue_9155.rs - -// pretty-expanded FIXME #23616 - -extern crate issue_9155; - -struct Baz; - -pub fn main() { - issue_9155::Foo::new(Baz); -} diff --git a/src/test/run-pass/item-attributes.rs b/src/test/run-pass/item-attributes.rs deleted file mode 100644 index e3ed350f29a94..0000000000000 --- a/src/test/run-pass/item-attributes.rs +++ /dev/null @@ -1,184 +0,0 @@ -#![allow(non_camel_case_types)] -#![allow(non_upper_case_globals)] -#![allow(unused_attributes)] -#![allow(dead_code)] -#![allow(unknown_lints)] -// These are attributes of the implicit crate. Really this just needs to parse -// for completeness since .rs files linked from .rc files support this -// notation to specify their module's attributes - -#![feature(custom_attribute)] -#![allow(unused_attribute)] -#![attr1 = "val"] -#![attr2 = "val"] -#![attr3] -#![attr4(attr5)] - -#![crate_id="foobar#0.1"] - -// These are attributes of the following mod -#[attr1 = "val"] -#[attr2 = "val"] -mod test_first_item_in_file_mod {} - -mod test_single_attr_outer { - #[attr = "val"] - pub static x: isize = 10; - - #[attr = "val"] - pub fn f() { } - - #[attr = "val"] - pub mod mod1 {} - - pub mod rustrt { - #[attr = "val"] - extern {} - } -} - -mod test_multi_attr_outer { - #[attr1 = "val"] - #[attr2 = "val"] - pub static x: isize = 10; - - #[attr1 = "val"] - #[attr2 = "val"] - pub fn f() { } - - #[attr1 = "val"] - #[attr2 = "val"] - pub mod mod1 {} - - pub mod rustrt { - #[attr1 = "val"] - #[attr2 = "val"] - extern {} - } - - #[attr1 = "val"] - #[attr2 = "val"] - struct t {x: isize} -} - -mod test_stmt_single_attr_outer { - pub fn f() { - #[attr = "val"] - static x: isize = 10; - - #[attr = "val"] - fn f() { } - - #[attr = "val"] - mod mod1 { - } - - mod rustrt { - #[attr = "val"] - extern { - } - } - } -} - -mod test_stmt_multi_attr_outer { - pub fn f() { - - #[attr1 = "val"] - #[attr2 = "val"] - static x: isize = 10; - - #[attr1 = "val"] - #[attr2 = "val"] - fn f() { } - - #[attr1 = "val"] - #[attr2 = "val"] - mod mod1 { - } - - mod rustrt { - #[attr1 = "val"] - #[attr2 = "val"] - extern { - } - } - } -} - -mod test_attr_inner { - pub mod m { - // This is an attribute of mod m - #![attr = "val"] - } -} - -mod test_attr_inner_then_outer { - pub mod m { - // This is an attribute of mod m - #![attr = "val"] - // This is an attribute of fn f - #[attr = "val"] - fn f() { } - } -} - -mod test_attr_inner_then_outer_multi { - pub mod m { - // This is an attribute of mod m - #![attr1 = "val"] - #![attr2 = "val"] - // This is an attribute of fn f - #[attr1 = "val"] - #[attr2 = "val"] - fn f() { } - } -} - -mod test_distinguish_syntax_ext { - pub fn f() { - format!("test{}", "s"); - #[attr = "val"] - fn g() { } - } -} - -mod test_other_forms { - #[attr] - #[attr(word)] - #[attr(attr(word))] - #[attr(key1 = "val", key2 = "val", attr)] - pub fn f() { } -} - -mod test_foreign_items { - pub mod rustrt { - extern { - #![attr] - - #[attr] - fn rust_get_test_int() -> u32; - } - } -} - - -// FIXME(#623): - these aren't supported yet -/*mod test_literals { - #![str = "s"] - #![char = 'c'] - #![isize = 100] - #![usize = 100_usize] - #![mach_int = 100u32] - #![float = 1.0] - #![mach_float = 1.0f32] - #![nil = ()] - #![bool = true] - mod m {} -}*/ - -fn test_fn_inner() { - #![inner_fn_attr] -} - -pub fn main() { } diff --git a/src/test/run-pass/last-use-in-cap-clause.rs b/src/test/run-pass/last-use-in-cap-clause.rs index b77f7b5d7822c..42dc6a4b06e1d 100644 --- a/src/test/run-pass/last-use-in-cap-clause.rs +++ b/src/test/run-pass/last-use-in-cap-clause.rs @@ -3,7 +3,7 @@ struct A { a: Box } -fn foo() -> Box isize + 'static> { +fn foo() -> Box isize + 'static> { let k: Box<_> = Box::new(22); let _u = A {a: k.clone()}; let result = || 22; diff --git a/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs b/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs index 126cab67c1c04..f9d1b17b8dd82 100644 --- a/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs +++ b/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs @@ -30,6 +30,9 @@ literal"; let s = r"string literal"; assert_eq!(s, "string\nliteral"); + let s = br"byte string +literal"; + assert_eq!(s, "byte string\nliteral".as_bytes()); // validate that our source file has CRLF endings let source = include_str!("lexer-crlf-line-endings-string-literal-doc-comment.rs"); diff --git a/src/test/run-pass/link-cfg-works.rs b/src/test/run-pass/link-cfg-works.rs index a4888292c7dfe..d7a248fd4d57e 100644 --- a/src/test/run-pass/link-cfg-works.rs +++ b/src/test/run-pass/link-cfg-works.rs @@ -10,4 +10,3 @@ extern crate link_cfg_works_transitive_dylib; extern {} fn main() {} - diff --git a/src/test/run-pass/linkage1.rs b/src/test/run-pass/linkage1.rs index 4e404f26eec5e..da07385ead748 100644 --- a/src/test/run-pass/linkage1.rs +++ b/src/test/run-pass/linkage1.rs @@ -1,6 +1,7 @@ // ignore-windows // ignore-macos // ignore-emscripten doesn't support this linkage +// ignore-sgx weak linkage not permitted // aux-build:linkage1.rs #![feature(linkage)] diff --git a/src/test/run-pass/lint-cap.rs b/src/test/run-pass/lint-cap.rs index 0e8bdbdc6aaf4..f03bb69189272 100644 --- a/src/test/run-pass/lint-cap.rs +++ b/src/test/run-pass/lint-cap.rs @@ -5,4 +5,3 @@ use std::option; fn main() {} - diff --git a/src/test/run-pass/logging-only-prints-once.rs b/src/test/run-pass/logging-only-prints-once.rs index 7b10560022565..1a4c4d89e7dc8 100644 --- a/src/test/run-pass/logging-only-prints-once.rs +++ b/src/test/run-pass/logging-only-prints-once.rs @@ -1,6 +1,6 @@ // ignore-windows // ignore-emscripten no threads support -// exec-env:RUST_LOG=debug +// exec-env:RUSTC_LOG=debug use std::cell::Cell; use std::fmt; diff --git a/src/test/run-pass/logging_before_rt_started.rs b/src/test/run-pass/logging_before_rt_started.rs index 0cba1080de265..69cfc54c465b5 100644 --- a/src/test/run-pass/logging_before_rt_started.rs +++ b/src/test/run-pass/logging_before_rt_started.rs @@ -1,4 +1,4 @@ -// exec-env:RUST_LOG=std::ptr +// exec-env:RUSTC_LOG=std::ptr // In issue #9487, it was realized that std::ptr was invoking the logging // infrastructure, and when std::ptr was used during runtime initialization, diff --git a/src/test/run-pass/macros/colorful-write-macros.rs b/src/test/run-pass/macros/colorful-write-macros.rs index aba4383c73441..eb1872cc7f094 100644 --- a/src/test/run-pass/macros/colorful-write-macros.rs +++ b/src/test/run-pass/macros/colorful-write-macros.rs @@ -4,7 +4,7 @@ use std::io::Write; use std::fmt; struct Foo<'a> { - writer: &'a mut (Write+'a), + writer: &'a mut (dyn Write+'a), other: &'a str, } @@ -22,7 +22,7 @@ fn borrowing_writer_from_struct_and_formatting_struct_field(foo: Foo) { fn main() { let mut w = Vec::new(); - write!(&mut w as &mut Write, "").unwrap(); + write!(&mut w as &mut dyn Write, "").unwrap(); write!(&mut w, "").unwrap(); // should coerce println!("ok"); diff --git a/src/test/run-pass/macros/macro-at-most-once-rep-2015.rs b/src/test/run-pass/macros/macro-at-most-once-rep-2015.rs new file mode 100644 index 0000000000000..66597c0acf628 --- /dev/null +++ b/src/test/run-pass/macros/macro-at-most-once-rep-2015.rs @@ -0,0 +1,50 @@ +// run-pass + +#![allow(unused_mut)] + +// Check that when `?` is followed by what looks like a Kleene operator (?, +, and *) +// then that `?` is not interpreted as a separator. In other words, `$(pat)?+` matches `pat +` +// or `+` but does not match `pat` or `pat ? pat`. + +// edition:2015 + +macro_rules! foo { + // Check for `?`. + ($($a:ident)? ? $num:expr) => { + foo!($($a)? ; $num); + }; + // Check for `+`. + ($($a:ident)? + $num:expr) => { + foo!($($a)? ; $num); + }; + // Check for `*`. + ($($a:ident)? * $num:expr) => { + foo!($($a)? ; $num); + }; + // Check for `;`, not a kleene operator. + ($($a:ident)? ; $num:expr) => { + let mut x = 0; + + $( + x += $a; + )? + + assert_eq!(x, $num); + }; +} + +pub fn main() { + let a = 1; + + // Accept 0 repetitions. + foo!( ; 0); + foo!( + 0); + foo!( * 0); + foo!( ? 0); + + // Accept 1 repetition. + foo!(a ; 1); + foo!(a + 1); + foo!(a * 1); + foo!(a ? 1); +} diff --git a/src/test/run-pass/macros/macro-at-most-once-rep-2018.rs b/src/test/run-pass/macros/macro-at-most-once-rep-2018.rs new file mode 100644 index 0000000000000..b37f3853016a6 --- /dev/null +++ b/src/test/run-pass/macros/macro-at-most-once-rep-2018.rs @@ -0,0 +1,50 @@ +// run-pass + +#![allow(unused_mut)] + +// Check that when `?` is followed by what looks like a Kleene operator (?, +, and *) +// then that `?` is not interpreted as a separator. In other words, `$(pat)?+` matches `pat +` +// or `+` but does not match `pat` or `pat ? pat`. + +// edition:2018 + +macro_rules! foo { + // Check for `?`. + ($($a:ident)? ? $num:expr) => { + foo!($($a)? ; $num); + }; + // Check for `+`. + ($($a:ident)? + $num:expr) => { + foo!($($a)? ; $num); + }; + // Check for `*`. + ($($a:ident)? * $num:expr) => { + foo!($($a)? ; $num); + }; + // Check for `;`, not a kleene operator. + ($($a:ident)? ; $num:expr) => { + let mut x = 0; + + $( + x += $a; + )? + + assert_eq!(x, $num); + }; +} + +pub fn main() { + let a = 1; + + // Accept 0 repetitions. + foo!( ; 0); + foo!( + 0); + foo!( * 0); + foo!( ? 0); + + // Accept 1 repetition. + foo!(a ; 1); + foo!(a + 1); + foo!(a * 1); + foo!(a ? 1); +} diff --git a/src/test/run-pass/macros/macro-at-most-once-rep.rs b/src/test/run-pass/macros/macro-at-most-once-rep.rs deleted file mode 100644 index 582ef088a73c9..0000000000000 --- a/src/test/run-pass/macros/macro-at-most-once-rep.rs +++ /dev/null @@ -1,33 +0,0 @@ -// run-pass -#![allow(unused_mut)] -// The logic for parsing Kleene operators in macros has a special case to disambiguate `?`. -// Specifically, `$(pat)?` is the ZeroOrOne operator whereas `$(pat)?+` or `$(pat)?*` are the -// ZeroOrMore and OneOrMore operators using `?` as a separator. These tests are intended to -// exercise that logic in the macro parser. -// -// Moreover, we also throw in some tests for using a separator with `?`, which is meaningless but -// included for consistency with `+` and `*`. -// -// This test focuses on non-error cases and making sure the correct number of repetitions happen. - -// edition:2018 - -macro_rules! foo { - ($($a:ident)? ; $num:expr) => { { - let mut x = 0; - - $( - x += $a; - )? - - assert_eq!(x, $num); - } } -} - -pub fn main() { - let a = 1; - - // accept 0 or 1 repetitions - foo!( ; 0); - foo!(a ; 1); -} diff --git a/src/test/run-pass/macros/macro-attributes.rs b/src/test/run-pass/macros/macro-attributes.rs index 953f6be53c5d4..d382e8b719713 100644 --- a/src/test/run-pass/macros/macro-attributes.rs +++ b/src/test/run-pass/macros/macro-attributes.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(custom_attribute)] macro_rules! compiles_fine { (#[$at:meta]) => { diff --git a/src/test/run-pass/macros/macro-comma-support.rs b/src/test/run-pass/macros/macro-comma-support.rs index 904f2e2c7fd7e..12a612c153ad6 100644 --- a/src/test/run-pass/macros/macro-comma-support.rs +++ b/src/test/run-pass/macros/macro-comma-support.rs @@ -233,8 +233,6 @@ fn println() { println!("hello {}", "world",); } -// select! is too troublesome and unlikely to be stabilized - // stringify! is N/A #[cfg(std)] diff --git a/src/test/run-pass/macros/macro-first-set.rs b/src/test/run-pass/macros/macro-first-set.rs index 8b09e72ed2951..a21e4cd201a4f 100644 --- a/src/test/run-pass/macros/macro-first-set.rs +++ b/src/test/run-pass/macros/macro-first-set.rs @@ -275,4 +275,3 @@ fn main() { test_24189(); test_51477(); } - diff --git a/src/test/run-pass/macros/macro-follow.rs b/src/test/run-pass/macros/macro-follow.rs index 488339b025dce..ca93655631f7e 100644 --- a/src/test/run-pass/macros/macro-follow.rs +++ b/src/test/run-pass/macros/macro-follow.rs @@ -181,4 +181,3 @@ macro_rules! follow_meta { } fn main() {} - diff --git a/src/test/run-pass/macros/macro-nested_expr.rs b/src/test/run-pass/macros/macro-nested_expr.rs index 2f93ffec4abb8..f1433cbf4f910 100644 --- a/src/test/run-pass/macros/macro-nested_expr.rs +++ b/src/test/run-pass/macros/macro-nested_expr.rs @@ -20,4 +20,3 @@ fn main() { define_f!(concat!("exported_", "f")); m!(stringify!(foo)); } - diff --git a/src/test/run-pass/macros/macro-pat-neg-lit.rs b/src/test/run-pass/macros/macro-pat-neg-lit.rs index 5345df2e84e62..79c68fd254137 100644 --- a/src/test/run-pass/macros/macro-pat-neg-lit.rs +++ b/src/test/run-pass/macros/macro-pat-neg-lit.rs @@ -23,4 +23,3 @@ enum_number!(Change { fn main() { if let Some(Change::Down) = foo(-1) {} else { panic!() } } - diff --git a/src/test/run-pass/macros/type-macros-simple.rs b/src/test/run-pass/macros/type-macros-simple.rs index 579b485a2a56e..dd3ad2ef0ac0f 100644 --- a/src/test/run-pass/macros/type-macros-simple.rs +++ b/src/test/run-pass/macros/type-macros-simple.rs @@ -16,7 +16,7 @@ fn issue_36540() { let x: m!() = m!(); std::cell::Cell::::new(m!()); - impl std::ops::Index for Trait<(m!(), T)> + impl std::ops::Index for dyn Trait<(m!(), T)> where T: Trait { type Output = m!(); diff --git a/src/test/run-pass/methods/method-argument-inference-associated-type.rs b/src/test/run-pass/methods/method-argument-inference-associated-type.rs index b5ba1f9455697..acd4a8465b075 100644 --- a/src/test/run-pass/methods/method-argument-inference-associated-type.rs +++ b/src/test/run-pass/methods/method-argument-inference-associated-type.rs @@ -10,13 +10,13 @@ pub trait Service { pub struct S(T); impl Service for ClientMap { - type Request = S>; + type Request = S>; fn call(&self, _req: Self::Request) {} } impl Service for ClientMap2 { - type Request = (Box,); + type Request = (Box,); fn call(&self, _req: Self::Request) {} } diff --git a/src/test/run-pass/methods/method-attributes.rs b/src/test/run-pass/methods/method-attributes.rs deleted file mode 100644 index c7d8b3b1403ab..0000000000000 --- a/src/test/run-pass/methods/method-attributes.rs +++ /dev/null @@ -1,31 +0,0 @@ -// run-pass -#![allow(unused_attributes)] -#![allow(non_camel_case_types)] - -// pp-exact - Make sure we print all the attributes -// pretty-expanded FIXME #23616 - -#![feature(custom_attribute)] - -#[frobable] -trait frobable { - #[frob_attr] - fn frob(&self); - #[defrob_attr] - fn defrob(&self); -} - -#[int_frobable] -impl frobable for isize { - #[frob_attr1] - fn frob(&self) { - #![frob_attr2] - } - - #[defrob_attr1] - fn defrob(&self) { - #![defrob_attr2] - } -} - -pub fn main() { } diff --git a/src/test/run-pass/mir/mir_build_match_comparisons.rs b/src/test/run-pass/mir/mir_build_match_comparisons.rs index 8913009f69156..04570055763a9 100644 --- a/src/test/run-pass/mir/mir_build_match_comparisons.rs +++ b/src/test/run-pass/mir/mir_build_match_comparisons.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] fn test1(x: i8) -> i32 { match x { - 1...10 => 0, + 1..=10 => 0, _ => 1, } } diff --git a/src/test/run-pass/mir/mir_codegen_calls.rs b/src/test/run-pass/mir/mir_codegen_calls.rs index 075d266d34d74..fc0db03e3a968 100644 --- a/src/test/run-pass/mir/mir_codegen_calls.rs +++ b/src/test/run-pass/mir/mir_codegen_calls.rs @@ -42,7 +42,7 @@ fn test4(x: &Foo, a: isize) -> isize { x.extension_method(a) } -fn test5(x: &Bar, a: isize) -> isize { +fn test5(x: &dyn Bar, a: isize) -> isize { // Test calling method on trait object x.extension_method(a) } @@ -88,11 +88,11 @@ fn test_closure(f: &F, x: i32, y: i32) -> i32 f(x, y) } -fn test_fn_object(f: &Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { +fn test_fn_object(f: &dyn Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { f(x, y) } -fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { +fn test_fn_impl(f: &&dyn Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { // This call goes through the Fn implementation for &Fn provided in // core::ops::impls. It expands to a static Fn::call() that calls the // Fn::call() implementation of the object shim underneath. @@ -174,7 +174,7 @@ fn main() { let closure = |x: i32, y: i32| { r*(x + (y*2)) }; assert_eq!(test_fn_const_call(&closure), 294); assert_eq!(test_closure(&closure, 100, 1), 306); - let function_object = &closure as &Fn(i32, i32) -> i32; + let function_object = &closure as &dyn Fn(i32, i32) -> i32; assert_eq!(test_fn_object(function_object, 100, 2), 312); assert_eq!(test_fn_impl(&function_object, 100, 3), 318); assert_eq!(test_fn_direct_call(&closure, 100, 4), 324); diff --git a/src/test/run-pass/mir/mir_codegen_critical_edge.rs b/src/test/run-pass/mir/mir_codegen_critical_edge.rs index 03b111e93dd25..5c1f1c3b70135 100644 --- a/src/test/run-pass/mir/mir_codegen_critical_edge.rs +++ b/src/test/run-pass/mir/mir_codegen_critical_edge.rs @@ -37,7 +37,7 @@ where A: Iterator, B: Iterator } // Make sure we actually codegen a version of the function -pub fn do_stuff(mut f: Foo>, Box>>) { +pub fn do_stuff(mut f: Foo>, Box>>) { let _x = f.next(); } diff --git a/src/test/run-pass/mir/mir_coercions.rs b/src/test/run-pass/mir/mir_coercions.rs index b673345db7045..f3dcc6b85fd98 100644 --- a/src/test/run-pass/mir/mir_coercions.rs +++ b/src/test/run-pass/mir/mir_coercions.rs @@ -4,12 +4,12 @@ use std::ops::CoerceUnsized; use std::marker::Unsize; -fn identity_coercion(x: &(Fn(u32)->u32 + Send)) -> &Fn(u32)->u32 { +fn identity_coercion(x: &(dyn Fn(u32)->u32 + Send)) -> &dyn Fn(u32)->u32 { x } fn fn_coercions(f: &fn(u32) -> u32) -> (unsafe fn(u32) -> u32, - &(Fn(u32) -> u32+Send)) + &(dyn Fn(u32) -> u32+Send)) { (*f, f) } @@ -35,8 +35,8 @@ fn coerce_triv_ptr_wrapper(p: TrivPtrWrapper<[u8; 3]>) -> TrivPtrWrapper<[u8]> { p } -fn coerce_fat_ptr_wrapper(p: PtrWrapper u32+Send>) - -> PtrWrapper u32> { +fn coerce_fat_ptr_wrapper(p: PtrWrapper u32+Send>) + -> PtrWrapper u32> { p } @@ -65,7 +65,7 @@ fn main() { let z = coerce_fat_ptr_wrapper(PtrWrapper(2,3,(),&square_local)); assert_eq!((z.3)(6), 36); - let z: PtrWrapper u32> = + let z: PtrWrapper u32> = coerce_ptr_wrapper_poly(PtrWrapper(2,3,(),&square_local)); assert_eq!((z.3)(6), 36); } diff --git a/src/test/run-pass/mir/mir_constval_adts.rs b/src/test/run-pass/mir/mir_constval_adts.rs index 3156be3584e1f..ee9d73451f45f 100644 --- a/src/test/run-pass/mir/mir_constval_adts.rs +++ b/src/test/run-pass/mir/mir_constval_adts.rs @@ -32,4 +32,3 @@ fn main(){ assert_eq!(mir(), (STRUCT, TUPLE1, TUPLE2, PAIR_NEWTYPE)); test_promoted_newtype_str_ref(); } - diff --git a/src/test/run-pass/mir/mir_raw_fat_ptr.rs b/src/test/run-pass/mir/mir_raw_fat_ptr.rs index 328c8c502cbc9..6583852aa9bb6 100644 --- a/src/test/run-pass/mir/mir_raw_fat_ptr.rs +++ b/src/test/run-pass/mir/mir_raw_fat_ptr.rs @@ -63,7 +63,7 @@ fn compare_au8(a: *const [u8], b: *const [u8]) -> ComparisonResults { } } -fn compare_foo<'a>(a: *const (Foo+'a), b: *const (Foo+'a)) -> ComparisonResults { +fn compare_foo<'a>(a: *const (dyn Foo+'a), b: *const (dyn Foo+'a)) -> ComparisonResults { ComparisonResults { lt: a < b, le: a <= b, @@ -74,7 +74,7 @@ fn compare_foo<'a>(a: *const (Foo+'a), b: *const (Foo+'a)) -> ComparisonResults } } -fn simple_eq<'a>(a: *const (Foo+'a), b: *const (Foo+'a)) -> bool { +fn simple_eq<'a>(a: *const (dyn Foo+'a), b: *const (dyn Foo+'a)) -> bool { let result = a == b; result } @@ -128,7 +128,7 @@ fn main() { let u32_ = (4u32, 5u32); // check ordering for ptrs - let buf: &mut [*const Foo] = &mut [ + let buf: &mut [*const dyn Foo] = &mut [ &u8_, &u8_.0, &u32_, &u32_.0, ]; diff --git a/src/test/run-pass/mir/mir_static_subtype.rs b/src/test/run-pass/mir/mir_static_subtype.rs new file mode 100644 index 0000000000000..5b1ccd7ddf6d9 --- /dev/null +++ b/src/test/run-pass/mir/mir_static_subtype.rs @@ -0,0 +1,8 @@ +// Test that subtyping the body of a static doesn't cause an ICE. + +fn foo(_ : &()) {} +static X: fn(&'static ()) = foo; + +fn main() { + let _ = X; +} diff --git a/src/test/run-pass/mpsc_stress.rs b/src/test/run-pass/mpsc_stress.rs index cd30dd62bc4ce..cf8d92b227893 100644 --- a/src/test/run-pass/mpsc_stress.rs +++ b/src/test/run-pass/mpsc_stress.rs @@ -1,5 +1,6 @@ // compile-flags:--test // ignore-emscripten +// ignore-sgx no thread sleep support use std::sync::mpsc::channel; use std::sync::mpsc::TryRecvError; diff --git a/src/test/run-pass/multi-panic.rs b/src/test/run-pass/multi-panic.rs index 3f24d989c8c3f..8bc0002065271 100644 --- a/src/test/run-pass/multi-panic.rs +++ b/src/test/run-pass/multi-panic.rs @@ -1,5 +1,6 @@ // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes fn check_for_no_backtrace(test: std::process::Output) { assert!(!test.status.success()); @@ -7,7 +8,7 @@ fn check_for_no_backtrace(test: std::process::Output) { let mut it = err.lines(); assert_eq!(it.next().map(|l| l.starts_with("thread '' panicked at")), Some(true)); - assert_eq!(it.next(), Some("note: Run with `RUST_BACKTRACE=1` \ + assert_eq!(it.next(), Some("note: run with `RUST_BACKTRACE=1` \ environment variable to display a backtrace.")); assert_eq!(it.next().map(|l| l.starts_with("thread 'main' panicked at")), Some(true)); assert_eq!(it.next(), None); diff --git a/src/test/run-pass/never-result.rs b/src/test/run-pass/never-result.rs index 2b395aa7f66bd..808377ffa1189 100644 --- a/src/test/run-pass/never-result.rs +++ b/src/test/run-pass/never-result.rs @@ -16,4 +16,3 @@ fn main() { }, } } - diff --git a/src/test/run-pass/never_coercions.rs b/src/test/run-pass/never_coercions.rs index 70f67fd3da1b2..f32e2973813c6 100644 --- a/src/test/run-pass/never_coercions.rs +++ b/src/test/run-pass/never_coercions.rs @@ -9,4 +9,3 @@ fn main() { _ => &v[..], }; } - diff --git a/src/test/run-pass/new-box.rs b/src/test/run-pass/new-box.rs index b35c5445a4405..5539518c37072 100644 --- a/src/test/run-pass/new-box.rs +++ b/src/test/run-pass/new-box.rs @@ -18,13 +18,13 @@ impl Trait for Struct { } } -fn g(x: Box) { +fn g(x: Box) { x.printme(); - let y: &Trait = &*x; + let y: &dyn Trait = &*x; y.printme(); } fn main() { f(box 1234); - g(box Struct as Box); + g(box Struct as Box); } diff --git a/src/test/run-pass/newlambdas-ret-infer.rs b/src/test/run-pass/newlambdas-ret-infer.rs index 969868486e6eb..79c9f7dc01103 100644 --- a/src/test/run-pass/newlambdas-ret-infer.rs +++ b/src/test/run-pass/newlambdas-ret-infer.rs @@ -4,7 +4,7 @@ // pretty-expanded FIXME #23616 -fn unique() -> Box { return Box::new(|| ()); } +fn unique() -> Box { return Box::new(|| ()); } pub fn main() { } diff --git a/src/test/run-pass/newlambdas-ret-infer2.rs b/src/test/run-pass/newlambdas-ret-infer2.rs index 676b3507c5740..104f5be7767d3 100644 --- a/src/test/run-pass/newlambdas-ret-infer2.rs +++ b/src/test/run-pass/newlambdas-ret-infer2.rs @@ -4,7 +4,7 @@ // pretty-expanded FIXME #23616 -fn unique() -> Box { Box::new(|| ()) } +fn unique() -> Box { Box::new(|| ()) } pub fn main() { } diff --git a/src/test/run-pass/nll/issue-47153-generic-const.rs b/src/test/run-pass/nll/issue-47153-generic-const.rs index 4f021fda4e344..9f4d57111bbe9 100644 --- a/src/test/run-pass/nll/issue-47153-generic-const.rs +++ b/src/test/run-pass/nll/issue-47153-generic-const.rs @@ -3,7 +3,6 @@ // Regression test for #47153: constants in a generic context (such as // a trait) used to ICE. -#![feature(nll)] #![allow(warnings)] trait Foo { diff --git a/src/test/run-pass/nll/issue-47589.rs b/src/test/run-pass/nll/issue-47589.rs index 5bbed3a85904c..280bf081138cc 100644 --- a/src/test/run-pass/nll/issue-47589.rs +++ b/src/test/run-pass/nll/issue-47589.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(nll)] - pub struct DescriptorSet<'a> { pub slots: Vec> } diff --git a/src/test/run-pass/nll/issue-48623-closure.rs b/src/test/run-pass/nll/issue-48623-closure.rs index 5a41fff11a1f0..3f8587eed41b9 100644 --- a/src/test/run-pass/nll/issue-48623-closure.rs +++ b/src/test/run-pass/nll/issue-48623-closure.rs @@ -2,8 +2,6 @@ #![allow(path_statements)] #![allow(dead_code)] -#![feature(nll)] - struct WithDrop; impl Drop for WithDrop { diff --git a/src/test/run-pass/nll/issue-48623-generator.rs b/src/test/run-pass/nll/issue-48623-generator.rs index b404daca72568..ba3eccff495e5 100644 --- a/src/test/run-pass/nll/issue-48623-generator.rs +++ b/src/test/run-pass/nll/issue-48623-generator.rs @@ -2,7 +2,6 @@ #![allow(path_statements)] #![allow(dead_code)] -#![feature(nll)] #![feature(generators, generator_trait)] struct WithDrop; diff --git a/src/test/run-pass/nll/issue-50343.rs b/src/test/run-pass/nll/issue-50343.rs index 8d2992b3b4f88..55a2d231e19ff 100644 --- a/src/test/run-pass/nll/issue-50343.rs +++ b/src/test/run-pass/nll/issue-50343.rs @@ -1,6 +1,5 @@ // run-pass -#![feature(nll)] #![deny(unused_mut)] fn main() { diff --git a/src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs b/src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs index dc5257cfb9225..69d7cdd83a6a1 100644 --- a/src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs +++ b/src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs @@ -1,6 +1,5 @@ // run-pass -#![feature(nll)] #![deny(unused_mut)] struct Foo { diff --git a/src/test/run-pass/nll/issue-53123-raw-pointer-cast.rs b/src/test/run-pass/nll/issue-53123-raw-pointer-cast.rs index c3f818812aa5f..941c9eeb411d9 100644 --- a/src/test/run-pass/nll/issue-53123-raw-pointer-cast.rs +++ b/src/test/run-pass/nll/issue-53123-raw-pointer-cast.rs @@ -1,6 +1,5 @@ // run-pass -#![feature(nll)] #![allow(unused_variables)] pub trait TryTransform { diff --git a/src/test/run-pass/nll/mutating_references.rs b/src/test/run-pass/nll/mutating_references.rs index 0af8751494e0d..eb46b30b6b94a 100644 --- a/src/test/run-pass/nll/mutating_references.rs +++ b/src/test/run-pass/nll/mutating_references.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(nll)] - struct List { value: T, next: Option>>, diff --git a/src/test/run-pass/nll/process_or_insert_default.rs b/src/test/run-pass/nll/process_or_insert_default.rs index e9cd4014bc351..84ac9bbd0ddc4 100644 --- a/src/test/run-pass/nll/process_or_insert_default.rs +++ b/src/test/run-pass/nll/process_or_insert_default.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(nll)] - use std::collections::HashMap; fn process_or_insert_default(map: &mut HashMap, key: usize) { diff --git a/src/test/run-pass/nll/rc-loop.rs b/src/test/run-pass/nll/rc-loop.rs index 2c54ee8693902..e59303d1f788f 100644 --- a/src/test/run-pass/nll/rc-loop.rs +++ b/src/test/run-pass/nll/rc-loop.rs @@ -6,8 +6,6 @@ // `x`. The lexical checker makes this very painful. The NLL checker // does not. -#![feature(nll)] - use std::rc::Rc; #[derive(Debug, PartialEq, Eq)] @@ -28,4 +26,3 @@ fn main() { let base = find_base(chain); assert_eq!(&*base, &Foo::Base(44)); } - diff --git a/src/test/run-pass/no-core-2.rs b/src/test/run-pass/no-core-2.rs new file mode 100644 index 0000000000000..e09f8f6b7a87c --- /dev/null +++ b/src/test/run-pass/no-core-2.rs @@ -0,0 +1,18 @@ +#![allow(dead_code, unused_imports)] +#![feature(no_core)] +#![no_core] +// edition:2018 + +extern crate std; +extern crate core; +use core::{prelude::v1::*, *}; + +fn foo() { + for _ in &[()] {} +} + +fn bar() -> Option<()> { + None? +} + +fn main() {} diff --git a/src/test/run-pass/no-stdio.rs b/src/test/run-pass/no-stdio.rs index 005781e1d2f0f..aae1d0b7f81c7 100644 --- a/src/test/run-pass/no-stdio.rs +++ b/src/test/run-pass/no-stdio.rs @@ -1,6 +1,7 @@ // ignore-android // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes #![feature(rustc_private)] diff --git a/src/test/run-pass/numbers-arithmetic/i128.rs b/src/test/run-pass/numbers-arithmetic/i128.rs index f3b5506ae32a6..ea0ef95e4f1af 100644 --- a/src/test/run-pass/numbers-arithmetic/i128.rs +++ b/src/test/run-pass/numbers-arithmetic/i128.rs @@ -3,7 +3,6 @@ // ignore-emscripten i128 doesn't work -// compile-flags: -Z borrowck=compare #![feature(test)] diff --git a/src/test/run-pass/numbers-arithmetic/u128.rs b/src/test/run-pass/numbers-arithmetic/u128.rs index 56d1f221d844c..9394071632377 100644 --- a/src/test/run-pass/numbers-arithmetic/u128.rs +++ b/src/test/run-pass/numbers-arithmetic/u128.rs @@ -1,7 +1,6 @@ // run-pass // ignore-emscripten u128 not supported -// compile-flags: -Z borrowck=compare #![feature(test)] diff --git a/src/test/run-pass/object-lifetime-default-default-to-static.rs b/src/test/run-pass/object-lifetime-default-default-to-static.rs index cf836c1a7deda..cd61dea03788f 100644 --- a/src/test/run-pass/object-lifetime-default-default-to-static.rs +++ b/src/test/run-pass/object-lifetime-default-default-to-static.rs @@ -10,23 +10,23 @@ trait Test { } struct SomeStruct { - t: Box, - u: Box, + t: Box, + u: Box, } -fn a(t: Box, mut ss: SomeStruct) { +fn a(t: Box, mut ss: SomeStruct) { ss.t = t; } -fn b(t: Box, mut ss: SomeStruct) { +fn b(t: Box, mut ss: SomeStruct) { ss.t = t; } -fn c(t: Box, mut ss: SomeStruct) { +fn c(t: Box, mut ss: SomeStruct) { ss.u = t; } -fn d(t: Box, mut ss: SomeStruct) { +fn d(t: Box, mut ss: SomeStruct) { ss.u = t; } diff --git a/src/test/run-pass/object-lifetime-default-from-rptr-box.rs b/src/test/run-pass/object-lifetime-default-from-rptr-box.rs index 3f69c9274889c..9212f2802c018 100644 --- a/src/test/run-pass/object-lifetime-default-from-rptr-box.rs +++ b/src/test/run-pass/object-lifetime-default-from-rptr-box.rs @@ -10,21 +10,21 @@ trait Test { } struct SomeStruct<'a> { - t: &'a Box, - u: &'a Box, + t: &'a Box, + u: &'a Box, } -fn a<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { +fn a<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { ss.t = t; } -fn b<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { +fn b<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { ss.u = t; } // see also compile-fail/object-lifetime-default-from-rptr-box-error.rs -fn d<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { +fn d<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { ss.u = t; } diff --git a/src/test/run-pass/object-lifetime-default-from-rptr-mut.rs b/src/test/run-pass/object-lifetime-default-from-rptr-mut.rs index dc9e292f0de38..061f3a116fcbb 100644 --- a/src/test/run-pass/object-lifetime-default-from-rptr-mut.rs +++ b/src/test/run-pass/object-lifetime-default-from-rptr-mut.rs @@ -10,23 +10,23 @@ trait Test { } struct SomeStruct<'a> { - t: &'a mut Test, - u: &'a mut (Test+'a), + t: &'a mut dyn Test, + u: &'a mut (dyn Test+'a), } -fn a<'a>(t: &'a mut Test, mut ss: SomeStruct<'a>) { +fn a<'a>(t: &'a mut dyn Test, mut ss: SomeStruct<'a>) { ss.t = t; } -fn b<'a>(t: &'a mut Test, mut ss: SomeStruct<'a>) { +fn b<'a>(t: &'a mut dyn Test, mut ss: SomeStruct<'a>) { ss.u = t; } -fn c<'a>(t: &'a mut (Test+'a), mut ss: SomeStruct<'a>) { +fn c<'a>(t: &'a mut (dyn Test+'a), mut ss: SomeStruct<'a>) { ss.t = t; } -fn d<'a>(t: &'a mut (Test+'a), mut ss: SomeStruct<'a>) { +fn d<'a>(t: &'a mut (dyn Test+'a), mut ss: SomeStruct<'a>) { ss.u = t; } diff --git a/src/test/run-pass/object-lifetime-default-from-rptr.rs b/src/test/run-pass/object-lifetime-default-from-rptr.rs index 061f71b9ae6bf..cfa4af0d7a53f 100644 --- a/src/test/run-pass/object-lifetime-default-from-rptr.rs +++ b/src/test/run-pass/object-lifetime-default-from-rptr.rs @@ -12,30 +12,30 @@ trait Test { } struct SomeStruct<'a> { - t: &'a Test, - u: &'a (Test+'a), + t: &'a dyn Test, + u: &'a (dyn Test+'a), } -fn a<'a>(t: &'a Test, mut ss: SomeStruct<'a>) { +fn a<'a>(t: &'a dyn Test, mut ss: SomeStruct<'a>) { ss.t = t; } -fn b<'a>(t: &'a Test, mut ss: SomeStruct<'a>) { +fn b<'a>(t: &'a dyn Test, mut ss: SomeStruct<'a>) { ss.u = t; } -fn c<'a>(t: &'a (Test+'a), mut ss: SomeStruct<'a>) { +fn c<'a>(t: &'a (dyn Test+'a), mut ss: SomeStruct<'a>) { ss.t = t; } -fn d<'a>(t: &'a (Test+'a), mut ss: SomeStruct<'a>) { +fn d<'a>(t: &'a (dyn Test+'a), mut ss: SomeStruct<'a>) { ss.u = t; } -fn e<'a>(_: &'a (Display+'static)) {} +fn e<'a>(_: &'a (dyn Display+'static)) {} fn main() { // Inside a function body, we can just infer both // lifetimes, to allow &'tmp (Display+'static). - e(&0 as &Display); + e(&0 as &dyn Display); } diff --git a/src/test/run-pass/object-method-numbering.rs b/src/test/run-pass/object-method-numbering.rs index 455af78c7a08e..7f24ab2cbb5ff 100644 --- a/src/test/run-pass/object-method-numbering.rs +++ b/src/test/run-pass/object-method-numbering.rs @@ -21,7 +21,7 @@ impl SomeTrait for i32 { fn main() { let x = 22; - let x1: &SomeTrait = &x; + let x1: &dyn SomeTrait = &x; let y = get_int(x1); assert_eq!(x, y); } diff --git a/src/test/run-pass/objects-coerce-freeze-borrored.rs b/src/test/run-pass/objects-coerce-freeze-borrored.rs index 872b9d3e9160b..47196f108c02c 100644 --- a/src/test/run-pass/objects-coerce-freeze-borrored.rs +++ b/src/test/run-pass/objects-coerce-freeze-borrored.rs @@ -17,7 +17,7 @@ impl Foo for usize { } } -fn do_it_mut(obj: &mut Foo) { +fn do_it_mut(obj: &mut dyn Foo) { let x = obj.bar(); let y = obj.foo(); assert_eq!(x, y); @@ -25,14 +25,14 @@ fn do_it_mut(obj: &mut Foo) { do_it_imm(obj, y); } -fn do_it_imm(obj: &Foo, v: usize) { +fn do_it_imm(obj: &dyn Foo, v: usize) { let y = obj.foo(); assert_eq!(v, y); } pub fn main() { let mut x: usize = 22; - let obj = &mut x as &mut Foo; + let obj = &mut x as &mut dyn Foo; do_it_mut(obj); do_it_imm(obj, 23); do_it_mut(obj); diff --git a/src/test/run-pass/objects-owned-object-borrowed-method-headerless.rs b/src/test/run-pass/objects-owned-object-borrowed-method-headerless.rs index a96772bfb6312..58327237494ed 100644 --- a/src/test/run-pass/objects-owned-object-borrowed-method-headerless.rs +++ b/src/test/run-pass/objects-owned-object-borrowed-method-headerless.rs @@ -20,10 +20,10 @@ impl FooTrait for BarStruct { } pub fn main() { - let foos: Vec> = vec![ - box BarStruct{ x: 0 } as Box, - box BarStruct{ x: 1 } as Box, - box BarStruct{ x: 2 } as Box + let foos: Vec> = vec![ + box BarStruct{ x: 0 } as Box, + box BarStruct{ x: 1 } as Box, + box BarStruct{ x: 2 } as Box ]; for i in 0..foos.len() { diff --git a/src/test/run-pass/objects-owned-object-owned-method.rs b/src/test/run-pass/objects-owned-object-owned-method.rs index 6ca5233b198e0..69984fbb62f14 100644 --- a/src/test/run-pass/objects-owned-object-owned-method.rs +++ b/src/test/run-pass/objects-owned-object-owned-method.rs @@ -19,6 +19,6 @@ impl FooTrait for BarStruct { } pub fn main() { - let foo = box BarStruct{ x: 22 } as Box; + let foo = box BarStruct{ x: 22 } as Box; assert_eq!(22, foo.foo()); } diff --git a/src/test/run-pass/optimization-fuel-0.rs b/src/test/run-pass/optimization-fuel-0.rs index 0920bc9c4b91a..77f21b3fcc0af 100644 --- a/src/test/run-pass/optimization-fuel-0.rs +++ b/src/test/run-pass/optimization-fuel-0.rs @@ -12,4 +12,3 @@ fn main() { assert_eq!(size_of::(), 6); assert_eq!(size_of::(), 6); } - diff --git a/src/test/run-pass/out-of-stack.rs b/src/test/run-pass/out-of-stack.rs index 72d6d6806229e..f03935e3d27cc 100644 --- a/src/test/run-pass/out-of-stack.rs +++ b/src/test/run-pass/out-of-stack.rs @@ -4,6 +4,7 @@ // ignore-musl // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes #![feature(asm)] #![feature(rustc_private)] @@ -36,7 +37,6 @@ fn loud_recurse() { #[cfg(unix)] fn check_status(status: std::process::ExitStatus) { - use libc; use std::os::unix::process::ExitStatusExt; assert!(!status.success()); diff --git a/src/test/run-pass/overloaded/overloaded-calls-object-one-arg.rs b/src/test/run-pass/overloaded/overloaded-calls-object-one-arg.rs index ff484418c1dbe..1afab9a1ffbe7 100644 --- a/src/test/run-pass/overloaded/overloaded-calls-object-one-arg.rs +++ b/src/test/run-pass/overloaded/overloaded-calls-object-one-arg.rs @@ -3,7 +3,7 @@ // This is a bit tricky due to rust-call ABI. -fn foo(f: &mut FnMut(isize) -> isize) -> isize { +fn foo(f: &mut dyn FnMut(isize) -> isize) -> isize { f(22) } diff --git a/src/test/run-pass/overloaded/overloaded-calls-object-two-args.rs b/src/test/run-pass/overloaded/overloaded-calls-object-two-args.rs index 0d0136bc29ac7..38087bc8710fc 100644 --- a/src/test/run-pass/overloaded/overloaded-calls-object-two-args.rs +++ b/src/test/run-pass/overloaded/overloaded-calls-object-two-args.rs @@ -3,7 +3,7 @@ // This is a bit tricky due to rust-call ABI. -fn foo(f: &mut FnMut(isize, isize) -> isize) -> isize { +fn foo(f: &mut dyn FnMut(isize, isize) -> isize) -> isize { f(1, 2) } diff --git a/src/test/run-pass/overloaded/overloaded-calls-object-zero-args.rs b/src/test/run-pass/overloaded/overloaded-calls-object-zero-args.rs index bbea6a909c880..9a7bfaa9bf4f0 100644 --- a/src/test/run-pass/overloaded/overloaded-calls-object-zero-args.rs +++ b/src/test/run-pass/overloaded/overloaded-calls-object-zero-args.rs @@ -3,7 +3,7 @@ // This is a bit tricky due to rust-call ABI. -fn foo(f: &mut FnMut() -> isize) -> isize { +fn foo(f: &mut dyn FnMut() -> isize) -> isize { f() } diff --git a/src/test/run-pass/packed/packed-struct-generic-size.rs b/src/test/run-pass/packed/packed-struct-generic-size.rs index 08d4674d2a88a..7c93e46c30c23 100644 --- a/src/test/run-pass/packed/packed-struct-generic-size.rs +++ b/src/test/run-pass/packed/packed-struct-generic-size.rs @@ -33,12 +33,12 @@ macro_rules! check { } pub fn main() { - check!(P1::, 1, 3); - check!(P1::, 1, 11); + check!(P1, 1, 3); + check!(P1, 1, 11); - check!(P2::, 1, 3); - check!(P2::, 2, 12); + check!(P2, 1, 3); + check!(P2, 2, 12); - check!(P4C::, 1, 3); - check!(P4C::, 4, 12); + check!(P4C, 1, 3); + check!(P4C, 4, 12); } diff --git a/src/test/run-pass/packed/packed-struct-generic-size.stderr b/src/test/run-pass/packed/packed-struct-generic-size.stderr deleted file mode 100644 index 1af476c156866..0000000000000 --- a/src/test/run-pass/packed/packed-struct-generic-size.stderr +++ /dev/null @@ -1,36 +0,0 @@ -warning: unnecessary path disambiguator - --> $DIR/packed-struct-generic-size.rs:36:14 - | -LL | check!(P1::, 1, 3); - | ^^ try removing `::` - -warning: unnecessary path disambiguator - --> $DIR/packed-struct-generic-size.rs:37:14 - | -LL | check!(P1::, 1, 11); - | ^^ try removing `::` - -warning: unnecessary path disambiguator - --> $DIR/packed-struct-generic-size.rs:39:14 - | -LL | check!(P2::, 1, 3); - | ^^ try removing `::` - -warning: unnecessary path disambiguator - --> $DIR/packed-struct-generic-size.rs:40:14 - | -LL | check!(P2::, 2, 12); - | ^^ try removing `::` - -warning: unnecessary path disambiguator - --> $DIR/packed-struct-generic-size.rs:42:15 - | -LL | check!(P4C::, 1, 3); - | ^^ try removing `::` - -warning: unnecessary path disambiguator - --> $DIR/packed-struct-generic-size.rs:43:15 - | -LL | check!(P4C::, 4, 12); - | ^^ try removing `::` - diff --git a/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs b/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs index e2dbb0d175d01..9c099911eab4d 100644 --- a/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs +++ b/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs @@ -5,6 +5,7 @@ // no-prefer-dynamic // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes // ignore-macos extern crate exit_success_if_unwind; diff --git a/src/test/run-pass/panic-runtime/abort.rs b/src/test/run-pass/panic-runtime/abort.rs index 719034bd11e78..f625fe35d7205 100644 --- a/src/test/run-pass/panic-runtime/abort.rs +++ b/src/test/run-pass/panic-runtime/abort.rs @@ -4,6 +4,7 @@ // no-prefer-dynamic // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes // ignore-macos use std::process::Command; diff --git a/src/test/run-pass/panic-runtime/lto-abort.rs b/src/test/run-pass/panic-runtime/lto-abort.rs index 9015a8f25a9b6..8fff71a629a49 100644 --- a/src/test/run-pass/panic-runtime/lto-abort.rs +++ b/src/test/run-pass/panic-runtime/lto-abort.rs @@ -4,6 +4,7 @@ // no-prefer-dynamic // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::process::Command; use std::env; diff --git a/src/test/run-pass/panic-runtime/lto-unwind.rs b/src/test/run-pass/panic-runtime/lto-unwind.rs index b14cdfc193fa8..94a0b596e4a71 100644 --- a/src/test/run-pass/panic-runtime/lto-unwind.rs +++ b/src/test/run-pass/panic-runtime/lto-unwind.rs @@ -5,6 +5,7 @@ // no-prefer-dynamic // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::process::Command; use std::env; diff --git a/src/test/run-pass/panic-uninitialized-zeroed.rs b/src/test/run-pass/panic-uninitialized-zeroed.rs index 31c0d2994d415..4ca4b407bd4ff 100644 --- a/src/test/run-pass/panic-uninitialized-zeroed.rs +++ b/src/test/run-pass/panic-uninitialized-zeroed.rs @@ -2,7 +2,7 @@ // This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results // in a runtime panic. -#![feature(never_type, maybe_uninit)] +#![feature(never_type)] use std::{mem, panic}; @@ -36,7 +36,7 @@ fn main() { assert_eq!( panic::catch_unwind(|| { - mem::MaybeUninit::::uninitialized().into_initialized() + mem::MaybeUninit::::uninit().assume_init() }).err().and_then(|a| a.downcast_ref::().map(|s| { s == "Attempted to instantiate uninhabited type !" })), @@ -63,7 +63,7 @@ fn main() { assert_eq!( panic::catch_unwind(|| { - mem::MaybeUninit::::uninitialized().into_initialized() + mem::MaybeUninit::::uninit().assume_init() }).err().and_then(|a| a.downcast_ref::().map(|s| { s == "Attempted to instantiate uninhabited type Foo" })), @@ -90,7 +90,7 @@ fn main() { assert_eq!( panic::catch_unwind(|| { - mem::MaybeUninit::::uninitialized().into_initialized() + mem::MaybeUninit::::uninit().assume_init() }).err().and_then(|a| a.downcast_ref::().map(|s| { s == "Attempted to instantiate uninhabited type Bar" })), diff --git a/src/test/run-pass/panics/panic-handler-flail-wildly.rs b/src/test/run-pass/panics/panic-handler-flail-wildly.rs index ebe4f70378cf0..6badd203842ff 100644 --- a/src/test/run-pass/panics/panic-handler-flail-wildly.rs +++ b/src/test/run-pass/panics/panic-handler-flail-wildly.rs @@ -1,5 +1,7 @@ // run-pass + #![allow(stable_features)] +#![allow(unused_must_use)] // ignore-emscripten no threads support diff --git a/src/test/run-pass/panics/panic-safe.rs b/src/test/run-pass/panics/panic-safe.rs index 3798a4fc5cba1..9867cc56406ef 100644 --- a/src/test/run-pass/panics/panic-safe.rs +++ b/src/test/run-pass/panics/panic-safe.rs @@ -33,7 +33,7 @@ fn main() { assert::>(); trait Trait: UnwindSafe {} - assert::>(); + assert::>(); fn bar() { assert::>(); diff --git a/src/test/run-pass/paths-containing-nul.rs b/src/test/run-pass/paths-containing-nul.rs index 8c800089d1ce3..64ee7319fdde5 100644 --- a/src/test/run-pass/paths-containing-nul.rs +++ b/src/test/run-pass/paths-containing-nul.rs @@ -1,6 +1,8 @@ #![allow(deprecated)] // ignore-cloudabi no files or I/O // ignore-wasm32-bare no files or I/O +// ignore-emscripten no files +// ignore-sgx no files use std::fs; use std::io; @@ -22,14 +24,18 @@ fn main() { assert_invalid_input("remove_file", fs::remove_file("\0")); assert_invalid_input("metadata", fs::metadata("\0")); assert_invalid_input("symlink_metadata", fs::symlink_metadata("\0")); + + // If `dummy_file` does not exist, then we might get another unrelated error + let dummy_file = std::env::current_exe().unwrap(); + assert_invalid_input("rename1", fs::rename("\0", "a")); - assert_invalid_input("rename2", fs::rename("a", "\0")); + assert_invalid_input("rename2", fs::rename(&dummy_file, "\0")); assert_invalid_input("copy1", fs::copy("\0", "a")); - assert_invalid_input("copy2", fs::copy("a", "\0")); + assert_invalid_input("copy2", fs::copy(&dummy_file, "\0")); assert_invalid_input("hard_link1", fs::hard_link("\0", "a")); - assert_invalid_input("hard_link2", fs::hard_link("a", "\0")); + assert_invalid_input("hard_link2", fs::hard_link(&dummy_file, "\0")); assert_invalid_input("soft_link1", fs::soft_link("\0", "a")); - assert_invalid_input("soft_link2", fs::soft_link("a", "\0")); + assert_invalid_input("soft_link2", fs::soft_link(&dummy_file, "\0")); assert_invalid_input("read_link", fs::read_link("\0")); assert_invalid_input("canonicalize", fs::canonicalize("\0")); assert_invalid_input("create_dir", fs::create_dir("\0")); diff --git a/src/test/run-pass/print-stdout-eprint-stderr.rs b/src/test/run-pass/print-stdout-eprint-stderr.rs index 9c47a734d7b84..65130a1a9f2c0 100644 --- a/src/test/run-pass/print-stdout-eprint-stderr.rs +++ b/src/test/run-pass/print-stdout-eprint-stderr.rs @@ -1,5 +1,6 @@ // ignore-cloudabi spawning processes is not supported // ignore-emscripten spawning processes is not supported +// ignore-sgx no processes use std::{env, process}; diff --git a/src/test/run-pass/privacy/privacy-ns.rs b/src/test/run-pass/privacy/privacy-ns.rs index b1b03eae5db5f..c32e3f17880db 100644 --- a/src/test/run-pass/privacy/privacy-ns.rs +++ b/src/test/run-pass/privacy/privacy-ns.rs @@ -28,19 +28,19 @@ fn test_unused1() { fn test_single1() { use foo1::Bar; - let _x: Box; + let _x: Box; } fn test_list1() { use foo1::{Bar,Baz}; - let _x: Box; + let _x: Box; } fn test_glob1() { use foo1::*; - let _x: Box; + let _x: Box; } // private type, public value @@ -93,21 +93,21 @@ fn test_single3() { use foo3::Bar; Bar(); - let _x: Box; + let _x: Box; } fn test_list3() { use foo3::{Bar,Baz}; Bar(); - let _x: Box; + let _x: Box; } fn test_glob3() { use foo3::*; Bar(); - let _x: Box; + let _x: Box; } fn main() { diff --git a/src/test/run-pass/proc-macro/auxiliary/expand-with-a-macro.rs b/src/test/run-pass/proc-macro/auxiliary/expand-with-a-macro.rs index 8580005f4fc3b..5155a4b855865 100644 --- a/src/test/run-pass/proc-macro/auxiliary/expand-with-a-macro.rs +++ b/src/test/run-pass/proc-macro/auxiliary/expand-with-a-macro.rs @@ -20,4 +20,3 @@ pub fn derive(input: TokenStream) -> TokenStream { } "#.parse().unwrap() } - diff --git a/src/test/run-pass/proc-macro/auxiliary/external-crate-var.rs b/src/test/run-pass/proc-macro/auxiliary/external-crate-var.rs index 09e5aea9b8305..4319e921225e0 100644 --- a/src/test/run-pass/proc-macro/auxiliary/external-crate-var.rs +++ b/src/test/run-pass/proc-macro/auxiliary/external-crate-var.rs @@ -38,4 +38,3 @@ macro_rules! external { () => { } } } } - diff --git a/src/test/run-pass/proc-macro/auxiliary/span-api-tests.rs b/src/test/run-pass/proc-macro/auxiliary/span-api-tests.rs index cb71291f9090d..ad1e770a4dcbe 100644 --- a/src/test/run-pass/proc-macro/auxiliary/span-api-tests.rs +++ b/src/test/run-pass/proc-macro/auxiliary/span-api-tests.rs @@ -33,3 +33,13 @@ pub fn assert_source_file(input: TokenStream) -> TokenStream { "".parse().unwrap() } + +#[proc_macro] +pub fn macro_stringify(input: TokenStream) -> TokenStream { + let mut tokens = input.into_iter(); + let first_span = tokens.next().expect("first token").span(); + let last_span = tokens.last().map(|x| x.span()).unwrap_or(first_span); + let span = first_span.join(last_span).expect("joined span"); + let src = span.source_text().expect("source_text"); + TokenTree::Literal(Literal::string(&src)).into() +} diff --git a/src/test/run-pass/proc-macro/expand-with-a-macro.rs b/src/test/run-pass/proc-macro/expand-with-a-macro.rs index 46c8e0ef5e599..097520b993a79 100644 --- a/src/test/run-pass/proc-macro/expand-with-a-macro.rs +++ b/src/test/run-pass/proc-macro/expand-with-a-macro.rs @@ -17,4 +17,3 @@ fn main() { A.a(); }).is_err()); } - diff --git a/src/test/run-pass/proc-macro/span-api-tests.rs b/src/test/run-pass/proc-macro/span-api-tests.rs index 0076c08621f7a..9b977b8fa75cd 100644 --- a/src/test/run-pass/proc-macro/span-api-tests.rs +++ b/src/test/run-pass/proc-macro/span-api-tests.rs @@ -3,12 +3,14 @@ // ignore-pretty +#![feature(proc_macro_hygiene)] + #[macro_use] extern crate span_test_macros; extern crate span_api_tests; -use span_api_tests::{reemit, assert_fake_source_file, assert_source_file}; +use span_api_tests::{reemit, assert_fake_source_file, assert_source_file, macro_stringify}; macro_rules! say_hello { ($macname:ident) => ( $macname! { "Hello, world!" }) @@ -28,4 +30,32 @@ reemit! { assert_source_file! { "Hello, world!" } } -fn main() {} +fn main() { + let s = macro_stringify!(Hello, world!); + assert_eq!(s, "Hello, world!"); + assert_eq!(macro_stringify!(Hello, world!), "Hello, world!"); + assert_eq!(reemit_legacy!(macro_stringify!(Hello, world!)), "Hello, world!"); + reemit_legacy!(assert_eq!(macro_stringify!(Hello, world!), "Hello, world!")); + // reemit change the span to be that of the call site + assert_eq!( + reemit!(macro_stringify!(Hello, world!)), + "reemit!(macro_stringify!(Hello, world!))" + ); + let r = "reemit!(assert_eq!(macro_stringify!(Hello, world!), r));"; + reemit!(assert_eq!(macro_stringify!(Hello, world!), r)); + + assert_eq!(macro_stringify!( + Hello, + world! + ), "Hello,\n world!"); + + assert_eq!(macro_stringify!(Hello, /*world */ !), "Hello, /*world */ !"); + assert_eq!(macro_stringify!( + Hello, + // comment + world! + ), "Hello,\n // comment\n world!"); + + assert_eq!(say_hello! { macro_stringify }, "\"Hello, world!\""); + assert_eq!(say_hello_extern! { macro_stringify }, "\"Hello, world!\""); +} diff --git a/src/test/run-pass/process/process-envs.rs b/src/test/run-pass/process/process-envs.rs index 1ff0fbbdd08df..a7779c55f1f92 100644 --- a/src/test/run-pass/process/process-envs.rs +++ b/src/test/run-pass/process/process-envs.rs @@ -1,6 +1,7 @@ // run-pass // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::process::Command; use std::env; diff --git a/src/test/run-pass/process/process-exit.rs b/src/test/run-pass/process/process-exit.rs index ecc7b72c0f3ee..da3b4ca85c2a3 100644 --- a/src/test/run-pass/process/process-exit.rs +++ b/src/test/run-pass/process/process-exit.rs @@ -2,6 +2,7 @@ #![allow(unused_imports)] // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::env; use std::process::{self, Command, Stdio}; diff --git a/src/test/run-pass/process/process-remove-from-env.rs b/src/test/run-pass/process/process-remove-from-env.rs index 9c2aa871e0dc5..32cbb6ac85ac8 100644 --- a/src/test/run-pass/process/process-remove-from-env.rs +++ b/src/test/run-pass/process/process-remove-from-env.rs @@ -1,6 +1,7 @@ // run-pass // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::process::Command; use std::env; diff --git a/src/test/run-pass/process/process-spawn-nonexistent.rs b/src/test/run-pass/process/process-spawn-nonexistent.rs index 2fe9f33de38b7..182cf1748fec6 100644 --- a/src/test/run-pass/process/process-spawn-nonexistent.rs +++ b/src/test/run-pass/process/process-spawn-nonexistent.rs @@ -1,6 +1,7 @@ // run-pass // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::io::ErrorKind; use std::process::Command; diff --git a/src/test/run-pass/process/process-spawn-with-unicode-params.rs b/src/test/run-pass/process/process-spawn-with-unicode-params.rs index e3508cb4e8fc9..edd3cb26ec362 100644 --- a/src/test/run-pass/process/process-spawn-with-unicode-params.rs +++ b/src/test/run-pass/process/process-spawn-with-unicode-params.rs @@ -9,6 +9,7 @@ // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::io::prelude::*; use std::io; diff --git a/src/test/run-pass/process/process-status-inherits-stdin.rs b/src/test/run-pass/process/process-status-inherits-stdin.rs index e2e17b7fb66c1..f9b2da7e401ee 100644 --- a/src/test/run-pass/process/process-status-inherits-stdin.rs +++ b/src/test/run-pass/process/process-status-inherits-stdin.rs @@ -1,6 +1,7 @@ // run-pass // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::env; use std::io; diff --git a/src/test/run-pass/project-cache-issue-31849.rs b/src/test/run-pass/project-cache-issue-31849.rs index 086883e5cb3cd..4920678af1a06 100644 --- a/src/test/run-pass/project-cache-issue-31849.rs +++ b/src/test/run-pass/project-cache-issue-31849.rs @@ -62,4 +62,3 @@ fn main() { let it = ((((((((((),()),()),()),()),()),()),()),()),()); it.build(); } - diff --git a/src/test/run-pass/range_inclusive_gate.rs b/src/test/run-pass/range_inclusive_gate.rs index 7f72bf5d32578..d4d830ef22317 100644 --- a/src/test/run-pass/range_inclusive_gate.rs +++ b/src/test/run-pass/range_inclusive_gate.rs @@ -10,4 +10,3 @@ fn main() { } assert_eq!(count, 55); } - diff --git a/src/test/run-pass/raw-fat-ptr.rs b/src/test/run-pass/raw-fat-ptr.rs index df69db1cc9a25..511a35b25a3e8 100644 --- a/src/test/run-pass/raw-fat-ptr.rs +++ b/src/test/run-pass/raw-fat-ptr.rs @@ -78,7 +78,7 @@ fn main() { let mut u32_ = (4u32, 5u32); // check ordering for ptrs - let buf: &mut [*const Foo] = &mut [ + let buf: &mut [*const dyn Foo] = &mut [ &u8_, &u8_.0, &u32_, &u32_.0, ]; @@ -90,7 +90,7 @@ fn main() { assert_inorder(buf); // check ordering for mut ptrs - let buf: &mut [*mut Foo] = &mut [ + let buf: &mut [*mut dyn Foo] = &mut [ &mut u8_, &mut u8_.0, &mut u32_, &mut u32_.0, ]; diff --git a/src/test/run-pass/regions/regions-bound-lists-feature-gate.rs b/src/test/run-pass/regions/regions-bound-lists-feature-gate.rs index 204f4f8130dea..3815498f86fbb 100644 --- a/src/test/run-pass/regions/regions-bound-lists-feature-gate.rs +++ b/src/test/run-pass/regions/regions-bound-lists-feature-gate.rs @@ -9,7 +9,7 @@ trait Foo { fn dummy(&self) { } } -fn foo<'a>(x: Box) { +fn foo<'a>(x: Box) { } fn bar<'a, T: 'a>() { diff --git a/src/test/run-pass/regions/regions-close-over-type-parameter-successfully.rs b/src/test/run-pass/regions/regions-close-over-type-parameter-successfully.rs index 85c9c64c64386..4b47ed8c6aeb7 100644 --- a/src/test/run-pass/regions/regions-close-over-type-parameter-successfully.rs +++ b/src/test/run-pass/regions/regions-close-over-type-parameter-successfully.rs @@ -12,8 +12,8 @@ impl<'a> SomeTrait for &'a isize { } } -fn make_object<'a,A:SomeTrait+'a>(v: A) -> Box { - box v as Box +fn make_object<'a,A:SomeTrait+'a>(v: A) -> Box { + box v as Box } fn main() { diff --git a/src/test/run-pass/regions/regions-copy-closure.rs b/src/test/run-pass/regions/regions-copy-closure.rs index 6545ddf72c76a..43640079777a3 100644 --- a/src/test/run-pass/regions/regions-copy-closure.rs +++ b/src/test/run-pass/regions/regions-copy-closure.rs @@ -2,10 +2,10 @@ #![allow(non_camel_case_types)] struct closure_box<'a> { - cl: Box, + cl: Box, } -fn box_it<'a>(x: Box) -> closure_box<'a> { +fn box_it<'a>(x: Box) -> closure_box<'a> { closure_box {cl: x} } diff --git a/src/test/run-pass/regions/regions-debruijn-of-object.rs b/src/test/run-pass/regions/regions-debruijn-of-object.rs index 24c0cf53317e0..0b5510489fb45 100644 --- a/src/test/run-pass/regions/regions-debruijn-of-object.rs +++ b/src/test/run-pass/regions/regions-debruijn-of-object.rs @@ -13,9 +13,9 @@ trait AstConv<'tcx> { fn tcx<'a>(&'a self) -> &'a ctxt<'tcx>; } -fn foo(conv: &AstConv) { } +fn foo(conv: &dyn AstConv) { } -fn bar<'tcx>(conv: &AstConv<'tcx>) { +fn bar<'tcx>(conv: &dyn AstConv<'tcx>) { foo(conv) } diff --git a/src/test/run-pass/regions/regions-early-bound-trait-param.rs b/src/test/run-pass/regions/regions-early-bound-trait-param.rs index c71e47db22d41..cc2bde78d8594 100644 --- a/src/test/run-pass/regions/regions-early-bound-trait-param.rs +++ b/src/test/run-pass/regions/regions-early-bound-trait-param.rs @@ -15,14 +15,14 @@ fn poly_invoke<'c, T: Trait<'c>>(x: &'c T) -> (isize, isize) { (l,s) } -fn object_invoke1<'d>(x: &'d Trait<'d>) -> (isize, isize) { +fn object_invoke1<'d>(x: &'d dyn Trait<'d>) -> (isize, isize) { let l = x.long(); let s = x.short(); (l,s) } struct Struct1<'e> { - f: &'e (Trait<'e>+'e) + f: &'e (dyn Trait<'e>+'e) } fn field_invoke1<'f, 'g>(x: &'g Struct1<'f>) -> (isize,isize) { @@ -32,10 +32,10 @@ fn field_invoke1<'f, 'g>(x: &'g Struct1<'f>) -> (isize,isize) { } struct Struct2<'h, 'i:'h> { - f: &'h (Trait<'i>+'h) + f: &'h (dyn Trait<'i>+'h) } -fn object_invoke2<'j, 'k>(x: &'k Trait<'j>) -> isize { +fn object_invoke2<'j, 'k>(x: &'k dyn Trait<'j>) -> isize { x.short() } @@ -70,10 +70,10 @@ impl<'s> Trait<'s> for (isize,isize) { } } -impl<'t> MakerTrait for Box+'static> { - fn mk() -> Box+'static> { +impl<'t> MakerTrait for Box+'static> { + fn mk() -> Box+'static> { let tup: Box<(isize, isize)> = box (4,5); - tup as Box + tup as Box } } @@ -105,7 +105,7 @@ impl<'t> RefMakerTrait<'t> for List<'t> { pub fn main() { let t = (2,3); - let o = &t as &Trait; + let o = &t as &dyn Trait; let s1 = Struct1 { f: o }; let s2 = Struct2 { f: o }; assert_eq!(poly_invoke(&t), (2,3)); @@ -114,7 +114,7 @@ pub fn main() { assert_eq!(object_invoke2(&t), 3); assert_eq!(field_invoke2(&s2), 3); - let m : Box = make_val(); + let m : Box = make_val(); // assert_eq!(object_invoke1(&*m), (4,5)); // ~~~~~~~~~~~~~~~~~~~ // this call yields a compilation error; see compile-fail/dropck-object-cycle.rs diff --git a/src/test/run-pass/regions/regions-fn-subtyping-2.rs b/src/test/run-pass/regions/regions-fn-subtyping-2.rs index cbd88ebde0d1e..83949ddba3d1e 100644 --- a/src/test/run-pass/regions/regions-fn-subtyping-2.rs +++ b/src/test/run-pass/regions/regions-fn-subtyping-2.rs @@ -7,13 +7,13 @@ // that `x` is in. // pretty-expanded FIXME #23616 -fn has_same_region(f: Box FnMut(&'a isize, Box)>) { +fn has_same_region(f: Box FnMut(&'a isize, Box)>) { // `f` should be the type that `wants_same_region` wants, but // right now the compiler complains that it isn't. wants_same_region(f); } -fn wants_same_region(_f: Box FnMut(&'b isize, Box)>) { +fn wants_same_region(_f: Box FnMut(&'b isize, Box)>) { } pub fn main() { diff --git a/src/test/run-pass/regions/regions-fn-subtyping.rs b/src/test/run-pass/regions/regions-fn-subtyping.rs index a1da966659a21..9570359c69e31 100644 --- a/src/test/run-pass/regions/regions-fn-subtyping.rs +++ b/src/test/run-pass/regions/regions-fn-subtyping.rs @@ -8,21 +8,21 @@ #![allow(unused_variables)] // Should pass region checking. -fn ok(f: Box) { +fn ok(f: Box) { // Here, g is a function that can accept a usize pointer with // lifetime r, and f is a function that can accept a usize pointer // with any lifetime. The assignment g = f should be OK (i.e., // f's type should be a subtype of g's type), because f can be // used in any context that expects g's type. But this currently // fails. - let mut g: Box FnMut(&'r usize)> = Box::new(|x| { }); + let mut g: Box FnMut(&'r usize)> = Box::new(|x| { }); g = f; } // This version is the same as above, except that here, g's type is // inferred. -fn ok_inferred(f: Box) { - let mut g: Box FnMut(&'r usize)> = Box::new(|_| {}); +fn ok_inferred(f: Box) { + let mut g: Box FnMut(&'r usize)> = Box::new(|_| {}); g = f; } diff --git a/src/test/run-pass/regions/regions-infer-region-in-fn-but-not-type.rs b/src/test/run-pass/regions/regions-infer-region-in-fn-but-not-type.rs index dff36e6d183b9..6aa5d8217a466 100644 --- a/src/test/run-pass/regions/regions-infer-region-in-fn-but-not-type.rs +++ b/src/test/run-pass/regions/regions-infer-region-in-fn-but-not-type.rs @@ -8,7 +8,7 @@ // contains region pointers // pretty-expanded FIXME #23616 -struct foo(Box); +struct foo(Box); fn take_foo(x: T) {} diff --git a/src/test/run-pass/regions/regions-lifetime-nonfree-late-bound.rs b/src/test/run-pass/regions/regions-lifetime-nonfree-late-bound.rs index 189f617202968..c8106f32c65c2 100644 --- a/src/test/run-pass/regions/regions-lifetime-nonfree-late-bound.rs +++ b/src/test/run-pass/regions/regions-lifetime-nonfree-late-bound.rs @@ -19,15 +19,15 @@ pub fn main() { fn explicit() { - fn test(_x: Option>) where F: FnMut(Box FnMut(&'a isize)>) {} - test(Some(box |_f: Box FnMut(&'a isize)>| {})); + fn test(_x: Option>) where F: FnMut(Box FnMut(&'a isize)>) {} + test(Some(box |_f: Box FnMut(&'a isize)>| {})); } // The code below is shorthand for the code above (and more likely // to represent what one encounters in practice). fn implicit() { - fn test(_x: Option>) where F: FnMut(Box< FnMut(& isize)>) {} - test(Some(box |_f: Box< FnMut(& isize)>| {})); + fn test(_x: Option>) where F: FnMut(Box) {} + test(Some(box |_f: Box| {})); } explicit(); diff --git a/src/test/run-pass/regions/regions-lub-ref-ref-rc.rs b/src/test/run-pass/regions/regions-lub-ref-ref-rc.rs index cd095f6f3a4a3..96c71b084b13e 100644 --- a/src/test/run-pass/regions/regions-lub-ref-ref-rc.rs +++ b/src/test/run-pass/regions/regions-lub-ref-ref-rc.rs @@ -11,16 +11,16 @@ use std::rc::Rc; #[derive(Clone)] -enum CachedMir<'mir> { +enum Cached<'mir> { Ref(&'mir String), Owned(Rc), } -impl<'mir> CachedMir<'mir> { +impl<'mir> Cached<'mir> { fn get_ref<'a>(&'a self) -> &'a String { match *self { - CachedMir::Ref(r) => r, - CachedMir::Owned(ref rc) => &rc, + Cached::Ref(r) => r, + Cached::Owned(ref rc) => &rc, } } } diff --git a/src/test/run-pass/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs b/src/test/run-pass/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs index f26ef85ef7234..aec05161c1afb 100644 --- a/src/test/run-pass/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs +++ b/src/test/run-pass/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs @@ -44,7 +44,7 @@ impl<'a,'tcx> Foo<'a,'tcx> { fn elaborate_bounds( &mut self, - mut mk_cand: Box FnMut(&mut Foo<'b, 'tcx>) -> isize>) + mut mk_cand: Box FnMut(&mut Foo<'b, 'tcx>) -> isize>) -> isize { mk_cand(self) diff --git a/src/test/run-pass/regions/regions-static-closure.rs b/src/test/run-pass/regions/regions-static-closure.rs index 6d00f7501ca9f..09cd56220323d 100644 --- a/src/test/run-pass/regions/regions-static-closure.rs +++ b/src/test/run-pass/regions/regions-static-closure.rs @@ -2,10 +2,10 @@ #![allow(non_camel_case_types)] struct closure_box<'a> { - cl: Box, + cl: Box, } -fn box_it<'a>(x: Box) -> closure_box<'a> { +fn box_it<'a>(x: Box) -> closure_box<'a> { closure_box {cl: x} } diff --git a/src/test/run-pass/regions/regions-trait-object-1.rs b/src/test/run-pass/regions/regions-trait-object-1.rs index 242142588eafe..679bf4dd8117c 100644 --- a/src/test/run-pass/regions/regions-trait-object-1.rs +++ b/src/test/run-pass/regions/regions-trait-object-1.rs @@ -21,10 +21,10 @@ impl<'d> M for P<'d> { fn n(&self) -> u8 { *self.g } } -fn extension<'e>(x: &'e E<'e>) -> Box { +fn extension<'e>(x: &'e E<'e>) -> Box { loop { let p = P { g: x.m() }; - return Box::new(p) as Box; + return Box::new(p) as Box; } } diff --git a/src/test/run-pass/rfcs/rfc-1014.rs b/src/test/run-pass/rfcs/rfc-1014.rs index 3b7b96d0d0207..41a036958bfea 100644 --- a/src/test/run-pass/rfcs/rfc-1014.rs +++ b/src/test/run-pass/rfcs/rfc-1014.rs @@ -2,6 +2,7 @@ #![allow(dead_code)] // ignore-cloudabi stdout does not map to file descriptor 1 by default // ignore-wasm32-bare no libc +// ignore-sgx no libc #![feature(rustc_private)] diff --git a/src/test/run-pass/rfcs/rfc-1789-as-cell/from-mut.rs b/src/test/run-pass/rfcs/rfc-1789-as-cell/from-mut.rs index f275c67fdf01f..ea3ad7aed4926 100644 --- a/src/test/run-pass/rfcs/rfc-1789-as-cell/from-mut.rs +++ b/src/test/run-pass/rfcs/rfc-1789-as-cell/from-mut.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(as_cell)] use std::cell::Cell; diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs deleted file mode 100644 index b3e2fa2c6208e..0000000000000 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs +++ /dev/null @@ -1,10 +0,0 @@ -// run-pass -#![crate_type = "rlib"] -#![feature(non_exhaustive)] - -#[non_exhaustive] -pub enum NonExhaustiveEnum { - Unit, - Tuple(u32), - Struct { field: u32 } -} diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs deleted file mode 100644 index 08b14d0df9408..0000000000000 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs +++ /dev/null @@ -1,14 +0,0 @@ -// run-pass -#![feature(non_exhaustive)] - -#[non_exhaustive] -pub struct NormalStruct { - pub first_field: u16, - pub second_field: u16, -} - -#[non_exhaustive] -pub struct UnitStruct; - -#[non_exhaustive] -pub struct TupleStruct (pub u16, pub u16); diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs deleted file mode 100644 index 56a73d8ab6088..0000000000000 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass -#![crate_type = "rlib"] -#![feature(non_exhaustive)] - -pub enum NonExhaustiveVariants { - #[non_exhaustive] Unit, - #[non_exhaustive] Tuple(u32), - #[non_exhaustive] Struct { field: u32 } -} diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs deleted file mode 100644 index f7e9c53849612..0000000000000 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs +++ /dev/null @@ -1,53 +0,0 @@ -// run-pass -// aux-build:enums.rs -extern crate enums; - -// ignore-pretty issue #37199 - -use enums::NonExhaustiveEnum; - -fn main() { - let enum_unit = NonExhaustiveEnum::Unit; - - match enum_unit { - NonExhaustiveEnum::Unit => 1, - NonExhaustiveEnum::Tuple(_) => 2, - // This particular arm tests that a enum marked as non-exhaustive - // will not error if its variants are matched exhaustively. - NonExhaustiveEnum::Struct { field } => field, - _ => 0 // no error with wildcard - }; - - match enum_unit { - _ => "no error with only wildcard" - }; - - - // issue #53549 - check that variant constructors can still be called normally. - - match NonExhaustiveEnum::Unit { - NonExhaustiveEnum::Unit => {}, - _ => {} - }; - - match NonExhaustiveEnum::Tuple(2) { - NonExhaustiveEnum::Tuple(2) => {}, - _ => {} - }; - - match (NonExhaustiveEnum::Unit {}) { - NonExhaustiveEnum::Unit {} => {}, - _ => {} - }; - - match (NonExhaustiveEnum::Tuple { 0: 2 }) { - NonExhaustiveEnum::Tuple { 0: 2 } => {}, - _ => {} - }; - - match (NonExhaustiveEnum::Struct { field: 2 }) { - NonExhaustiveEnum::Struct { field: 2 } => {}, - _ => {} - }; - -} diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs deleted file mode 100644 index 384e099275e9b..0000000000000 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs +++ /dev/null @@ -1,19 +0,0 @@ -// run-pass -#![feature(non_exhaustive)] - -#[non_exhaustive] -pub enum NonExhaustiveEnum { - Unit, - Tuple(u32), - Struct { field: u32 } -} - -fn main() { - let enum_unit = NonExhaustiveEnum::Unit; - - match enum_unit { - NonExhaustiveEnum::Unit => "first", - NonExhaustiveEnum::Tuple(_) => "second", - NonExhaustiveEnum::Struct { .. } => "third", - }; -} diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs deleted file mode 100644 index 3cd7234269e1d..0000000000000 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs +++ /dev/null @@ -1,20 +0,0 @@ -// run-pass -#![allow(dead_code)] -#![allow(unused_variables)] -// aux-build:structs.rs -extern crate structs; - -use structs::{NormalStruct, UnitStruct, TupleStruct}; - -// We only test matching here as we cannot create non-exhaustive -// structs from another crate. ie. they'll never pass in run-pass tests. - -fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) { - let NormalStruct { first_field, second_field, .. } = ns; - - let TupleStruct { 0: first, 1: second, .. } = ts; - - let UnitStruct { .. } = us; -} - -fn main() { } diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs deleted file mode 100644 index 90b8219e2a3c0..0000000000000 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs +++ /dev/null @@ -1,22 +0,0 @@ -// run-pass -// aux-build:variants.rs -extern crate variants; - -use variants::NonExhaustiveVariants; - -/* - * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for - * variants. See issue #44109 and PR 45394. - */ -// ignore-test - -fn main() { - let variant_tuple = NonExhaustiveVariants::Tuple { 0: 340 }; - let variant_struct = NonExhaustiveVariants::Struct { field: 340 }; - - match variant_struct { - NonExhaustiveVariants::Unit => "", - NonExhaustiveVariants::Struct { field, .. } => "", - NonExhaustiveVariants::Tuple(fe_tpl, ..) => "" - }; -} diff --git a/src/test/run-pass/rfcs/rfc-2126-extern-absolute-paths/basic.rs b/src/test/run-pass/rfcs/rfc-2126-extern-absolute-paths/basic.rs index 15449a6b83e2e..566b3581046d9 100644 --- a/src/test/run-pass/rfcs/rfc-2126-extern-absolute-paths/basic.rs +++ b/src/test/run-pass/rfcs/rfc-2126-extern-absolute-paths/basic.rs @@ -4,6 +4,8 @@ // compile-flags:--extern xcrate // edition:2018 +#![allow(unused_imports)] + use xcrate::Z; fn f() { diff --git a/src/test/run-pass/rmeta.rs b/src/test/run-pass/rmeta.rs index bd8125bbb5648..cbbdd78dc204b 100644 --- a/src/test/run-pass/rmeta.rs +++ b/src/test/run-pass/rmeta.rs @@ -1,8 +1,8 @@ // Test that using rlibs and rmeta dep crates work together. Specifically, that // there can be both an rmeta and an rlib file and rustc will prefer the rlib. -// aux-build:rmeta_rmeta.rs -// aux-build:rmeta_rlib.rs +// aux-build:rmeta-rmeta.rs +// aux-build:rmeta-rlib.rs extern crate rmeta_aux; use rmeta_aux::Foo; diff --git a/src/test/run-pass/running-with-no-runtime.rs b/src/test/run-pass/running-with-no-runtime.rs index 7f8a0f01dde04..ab1bf3a5b91d6 100644 --- a/src/test/run-pass/running-with-no-runtime.rs +++ b/src/test/run-pass/running-with-no-runtime.rs @@ -1,5 +1,6 @@ // ignore-cloudabi spawning processes is not supported // ignore-emscripten spawning processes is not supported +// ignore-sgx no processes #![feature(start)] diff --git a/src/test/run-pass/rustc-rust-log.rs b/src/test/run-pass/rustc-rust-log.rs index 4360a15401534..b664257241833 100644 --- a/src/test/run-pass/rustc-rust-log.rs +++ b/src/test/run-pass/rustc-rust-log.rs @@ -8,6 +8,6 @@ // dont-check-compiler-stderr // compile-flags: --error-format human -// rustc-env:RUST_LOG=debug +// rustc-env:RUSTC_LOG=debug fn main() {} diff --git a/src/test/run-pass/segfault-no-out-of-stack.rs b/src/test/run-pass/segfault-no-out-of-stack.rs index ce485d771f01d..e90efface687b 100644 --- a/src/test/run-pass/segfault-no-out-of-stack.rs +++ b/src/test/run-pass/segfault-no-out-of-stack.rs @@ -1,6 +1,7 @@ #![allow(unused_imports)] // ignore-cloudabi can't run commands // ignore-emscripten can't run commands +// ignore-sgx no processes #![feature(rustc_private)] diff --git a/src/test/run-pass/sepcomp/sepcomp-cci.rs b/src/test/run-pass/sepcomp/sepcomp-cci.rs index f5c633d250b9e..02bbab30e9c6e 100644 --- a/src/test/run-pass/sepcomp/sepcomp-cci.rs +++ b/src/test/run-pass/sepcomp/sepcomp-cci.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-bitrig // compile-flags: -C codegen-units=3 // aux-build:sepcomp_cci_lib.rs diff --git a/src/test/run-pass/sepcomp/sepcomp-extern.rs b/src/test/run-pass/sepcomp/sepcomp-extern.rs index 18af785c1bea1..c4ccf23c47ab4 100644 --- a/src/test/run-pass/sepcomp/sepcomp-extern.rs +++ b/src/test/run-pass/sepcomp/sepcomp-extern.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-bitrig // compile-flags: -C codegen-units=3 // aux-build:sepcomp-extern-lib.rs diff --git a/src/test/run-pass/sepcomp/sepcomp-fns-backwards.rs b/src/test/run-pass/sepcomp/sepcomp-fns-backwards.rs index 96bcc260bdf5c..f56769e2b8c6d 100644 --- a/src/test/run-pass/sepcomp/sepcomp-fns-backwards.rs +++ b/src/test/run-pass/sepcomp/sepcomp-fns-backwards.rs @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -// ignore-bitrig // compile-flags: -C codegen-units=3 // Test references to items that haven't been codegened yet. diff --git a/src/test/run-pass/sepcomp/sepcomp-fns.rs b/src/test/run-pass/sepcomp/sepcomp-fns.rs index c4ea17225b44e..a432c89606e33 100644 --- a/src/test/run-pass/sepcomp/sepcomp-fns.rs +++ b/src/test/run-pass/sepcomp/sepcomp-fns.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-bitrig // compile-flags: -C codegen-units=3 // Test basic separate compilation functionality. The functions should be able diff --git a/src/test/run-pass/sepcomp/sepcomp-statics.rs b/src/test/run-pass/sepcomp/sepcomp-statics.rs index e0c6b268b177c..5457c8a0ae97d 100644 --- a/src/test/run-pass/sepcomp/sepcomp-statics.rs +++ b/src/test/run-pass/sepcomp/sepcomp-statics.rs @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -// ignore-bitrig // compile-flags: -C codegen-units=3 // Test references to static items across compilation units. diff --git a/src/test/run-pass/sepcomp/sepcomp-unwind.rs b/src/test/run-pass/sepcomp/sepcomp-unwind.rs index 01dbea08098bd..50a4e043943f0 100644 --- a/src/test/run-pass/sepcomp/sepcomp-unwind.rs +++ b/src/test/run-pass/sepcomp/sepcomp-unwind.rs @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -// ignore-bitrig // compile-flags: -C codegen-units=3 // ignore-emscripten no threads support diff --git a/src/test/run-pass/signal-alternate-stack-cleanup.rs b/src/test/run-pass/signal-alternate-stack-cleanup.rs index 3958e72040d3d..6f2fa2a370dfe 100644 --- a/src/test/run-pass/signal-alternate-stack-cleanup.rs +++ b/src/test/run-pass/signal-alternate-stack-cleanup.rs @@ -5,6 +5,7 @@ // ignore-cloudabi no signal handling support // ignore-wasm32-bare no libc // ignore-windows +// ignore-sgx no libc #![feature(rustc_private)] extern crate libc; @@ -33,4 +34,3 @@ fn main() { atexit(send_signal); } } - diff --git a/src/test/run-pass/signal-exit-status.rs b/src/test/run-pass/signal-exit-status.rs index 9e1e55ad54d8a..c22c0352286dc 100644 --- a/src/test/run-pass/signal-exit-status.rs +++ b/src/test/run-pass/signal-exit-status.rs @@ -1,5 +1,6 @@ // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes // ignore-windows use std::env; diff --git a/src/test/run-pass/sigpipe-should-be-ignored.rs b/src/test/run-pass/sigpipe-should-be-ignored.rs index 2ded71670d29a..6c5bbd45a3c35 100644 --- a/src/test/run-pass/sigpipe-should-be-ignored.rs +++ b/src/test/run-pass/sigpipe-should-be-ignored.rs @@ -4,6 +4,7 @@ // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::env; use std::io::prelude::*; diff --git a/src/test/run-pass/simd/simd-size-align.rs b/src/test/run-pass/simd/simd-size-align.rs index 0a537071a3c63..556013788c335 100644 --- a/src/test/run-pass/simd/simd-size-align.rs +++ b/src/test/run-pass/simd/simd-size-align.rs @@ -37,6 +37,22 @@ fn main() { check::(); check::(); check::(); + + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); } #[repr(simd)] struct u8x2(u8, u8); @@ -62,3 +78,19 @@ fn main() { #[repr(simd)] struct f32x6(f32, f32, f32, f32, f32, f32); #[repr(simd)] struct f32x7(f32, f32, f32, f32, f32, f32, f32); #[repr(simd)] struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); + +#[repr(simd)] struct usizex2(usize, usize); +#[repr(simd)] struct usizex3(usize, usize, usize); +#[repr(simd)] struct usizex4(usize, usize, usize, usize); +#[repr(simd)] struct usizex5(usize, usize, usize, usize, usize); +#[repr(simd)] struct usizex6(usize, usize, usize, usize, usize, usize); +#[repr(simd)] struct usizex7(usize, usize, usize, usize, usize, usize, usize); +#[repr(simd)] struct usizex8(usize, usize, usize, usize, usize, usize, usize, usize); + +#[repr(simd)] struct isizex2(isize, isize); +#[repr(simd)] struct isizex3(isize, isize, isize); +#[repr(simd)] struct isizex4(isize, isize, isize, isize); +#[repr(simd)] struct isizex5(isize, isize, isize, isize, isize); +#[repr(simd)] struct isizex6(isize, isize, isize, isize, isize, isize); +#[repr(simd)] struct isizex7(isize, isize, isize, isize, isize, isize, isize); +#[repr(simd)] struct isizex8(isize, isize, isize, isize, isize, isize, isize, isize); diff --git a/src/test/run-pass/simd/simd-target-feature-mixup.rs b/src/test/run-pass/simd/simd-target-feature-mixup.rs index 5842a7fcdf7e3..6d7688191b7f1 100644 --- a/src/test/run-pass/simd/simd-target-feature-mixup.rs +++ b/src/test/run-pass/simd/simd-target-feature-mixup.rs @@ -4,6 +4,7 @@ #![allow(overflowing_literals)] // ignore-emscripten +// ignore-sgx no processes #![feature(repr_simd, target_feature, cfg_target_feature)] #![feature(avx512_target_feature)] diff --git a/src/test/run-pass/sleep.rs b/src/test/run-pass/sleep.rs index f0411876c8a0a..7128b3cc7c3ad 100644 --- a/src/test/run-pass/sleep.rs +++ b/src/test/run-pass/sleep.rs @@ -1,4 +1,5 @@ // ignore-emscripten no threads support +// ignore-sgx no thread sleep support use std::thread::{self, sleep}; use std::time::Duration; diff --git a/src/test/run-pass/stack-probes-lto.rs b/src/test/run-pass/stack-probes-lto.rs index 2705950b01424..1274f032a3e29 100644 --- a/src/test/run-pass/stack-probes-lto.rs +++ b/src/test/run-pass/stack-probes-lto.rs @@ -9,6 +9,7 @@ // ignore-wasm // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes // ignore-musl FIXME #31506 // ignore-pretty // compile-flags: -C lto diff --git a/src/test/run-pass/stack-probes.rs b/src/test/run-pass/stack-probes.rs index ff264421cfbcf..92a0cc3a07b52 100644 --- a/src/test/run-pass/stack-probes.rs +++ b/src/test/run-pass/stack-probes.rs @@ -9,6 +9,7 @@ // ignore-wasm // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes // ignore-musl FIXME #31506 use std::mem; diff --git a/src/test/run-pass/stdio-is-blocking.rs b/src/test/run-pass/stdio-is-blocking.rs index 281c6a17aa997..1824162b8bac6 100644 --- a/src/test/run-pass/stdio-is-blocking.rs +++ b/src/test/run-pass/stdio-is-blocking.rs @@ -1,5 +1,6 @@ // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes use std::env; use std::io::prelude::*; diff --git a/src/test/run-pass/string-box-error.rs b/src/test/run-pass/string-box-error.rs index debbe665a89f9..944157d0b2009 100644 --- a/src/test/run-pass/string-box-error.rs +++ b/src/test/run-pass/string-box-error.rs @@ -4,8 +4,8 @@ use std::error::Error; fn main() { - let _err1: Box = From::from("test".to_string()); - let _err2: Box = From::from("test".to_string()); - let _err3: Box = From::from("test"); - let _err4: Box = From::from("test"); + let _err1: Box = From::from("test".to_string()); + let _err2: Box = From::from("test".to_string()); + let _err3: Box = From::from("test"); + let _err4: Box = From::from("test"); } diff --git a/src/test/run-pass/struct-ctor-mangling.rs b/src/test/run-pass/struct-ctor-mangling.rs new file mode 100644 index 0000000000000..5f5ee7cfe4410 --- /dev/null +++ b/src/test/run-pass/struct-ctor-mangling.rs @@ -0,0 +1,12 @@ +fn size_of_val(_: &T) -> usize { + std::mem::size_of::() +} + +struct Foo(i64); + +// Test that the (symbol) mangling of `Foo` (the `struct` type) and that of +// `typeof Foo` (the function type of the `struct` constructor) don't collide. +fn main() { + size_of_val(&Foo(0)); + size_of_val(&Foo); +} diff --git a/src/test/run-pass/structs-enums/align-enum.rs b/src/test/run-pass/structs-enums/align-enum.rs index 8d72b1f6f0d24..fa872caa3b47e 100644 --- a/src/test/run-pass/structs-enums/align-enum.rs +++ b/src/test/run-pass/structs-enums/align-enum.rs @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -#![feature(repr_align_enum)] use std::mem; diff --git a/src/test/run-pass/structs-enums/class-attributes-1.rs b/src/test/run-pass/structs-enums/class-attributes-1.rs deleted file mode 100644 index 11ea29ece8a02..0000000000000 --- a/src/test/run-pass/structs-enums/class-attributes-1.rs +++ /dev/null @@ -1,21 +0,0 @@ -// run-pass -#![allow(unused_attributes)] -#![allow(non_camel_case_types)] - -// pp-exact - Make sure we actually print the attributes -#![feature(custom_attribute)] - -struct cat { - name: String, -} - -impl Drop for cat { - #[cat_dropper] - fn drop(&mut self) { println!("{} landed on hir feet" , self . name); } -} - - -#[cat_maker] -fn cat(name: String) -> cat { cat{name: name,} } - -pub fn main() { let _kitty = cat("Spotty".to_string()); } diff --git a/src/test/run-pass/structs-enums/class-attributes-2.rs b/src/test/run-pass/structs-enums/class-attributes-2.rs deleted file mode 100644 index d6cf63e62fea2..0000000000000 --- a/src/test/run-pass/structs-enums/class-attributes-2.rs +++ /dev/null @@ -1,33 +0,0 @@ -// run-pass -#![allow(unused_attributes)] -#![allow(non_camel_case_types)] - -#![feature(custom_attribute)] - -struct cat { - name: String, -} - -impl Drop for cat { - #[cat_dropper] - /** - Actually, cats don't always land on their feet when you drop them. - */ - fn drop(&mut self) { - println!("{} landed on hir feet", self.name); - } -} - -#[cat_maker] -/** -Maybe it should technically be a kitten_maker. -*/ -fn cat(name: String) -> cat { - cat { - name: name - } -} - -pub fn main() { - let _kitty = cat("Spotty".to_string()); -} diff --git a/src/test/run-pass/structs-enums/class-cast-to-trait-cross-crate-2.rs b/src/test/run-pass/structs-enums/class-cast-to-trait-cross-crate-2.rs index cb4a67f609d95..bf1ba8a643fea 100644 --- a/src/test/run-pass/structs-enums/class-cast-to-trait-cross-crate-2.rs +++ b/src/test/run-pass/structs-enums/class-cast-to-trait-cross-crate-2.rs @@ -8,13 +8,13 @@ extern crate cci_class_cast; use std::string::ToString; use cci_class_cast::kitty::cat; -fn print_out(thing: Box, expected: String) { +fn print_out(thing: Box, expected: String) { let actual = (*thing).to_string(); println!("{}", actual); assert_eq!(actual.to_string(), expected); } pub fn main() { - let nyan: Box = box cat(0, 2, "nyan".to_string()) as Box; + let nyan: Box = box cat(0, 2, "nyan".to_string()) as Box; print_out(nyan, "nyan".to_string()); } diff --git a/src/test/run-pass/structs-enums/class-cast-to-trait-multiple-types.rs b/src/test/run-pass/structs-enums/class-cast-to-trait-multiple-types.rs index 5ce6538fcb361..55975cbdb5342 100644 --- a/src/test/run-pass/structs-enums/class-cast-to-trait-multiple-types.rs +++ b/src/test/run-pass/structs-enums/class-cast-to-trait-multiple-types.rs @@ -79,7 +79,7 @@ fn cat(in_x: usize, in_y: isize, in_name: String) -> cat { } -fn annoy_neighbors(critter: &mut noisy) { +fn annoy_neighbors(critter: &mut dyn noisy) { for _i in 0_usize..10 { critter.speak(); } } diff --git a/src/test/run-pass/structs-enums/class-cast-to-trait.rs b/src/test/run-pass/structs-enums/class-cast-to-trait.rs index 7fa60da6e5762..1019bb30015a9 100644 --- a/src/test/run-pass/structs-enums/class-cast-to-trait.rs +++ b/src/test/run-pass/structs-enums/class-cast-to-trait.rs @@ -55,6 +55,6 @@ fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { pub fn main() { let mut nyan = cat(0, 2, "nyan".to_string()); - let mut nyan: &mut noisy = &mut nyan; + let mut nyan: &mut dyn noisy = &mut nyan; nyan.speak(); } diff --git a/src/test/run-pass/structs-enums/class-separate-impl.rs b/src/test/run-pass/structs-enums/class-separate-impl.rs index 2b10a46e8e25d..947690b51f422 100644 --- a/src/test/run-pass/structs-enums/class-separate-impl.rs +++ b/src/test/run-pass/structs-enums/class-separate-impl.rs @@ -53,13 +53,13 @@ impl fmt::Display for cat { } } -fn print_out(thing: Box, expected: String) { +fn print_out(thing: Box, expected: String) { let actual = (*thing).to_string(); println!("{}", actual); assert_eq!(actual.to_string(), expected); } pub fn main() { - let nyan: Box = box cat(0, 2, "nyan".to_string()) as Box; + let nyan: Box = box cat(0, 2, "nyan".to_string()) as Box; print_out(nyan, "nyan".to_string()); } diff --git a/src/test/run-pass/structs-enums/enum-null-pointer-opt.rs b/src/test/run-pass/structs-enums/enum-null-pointer-opt.rs index 5e3b5942a8209..32fdbf620a98d 100644 --- a/src/test/run-pass/structs-enums/enum-null-pointer-opt.rs +++ b/src/test/run-pass/structs-enums/enum-null-pointer-opt.rs @@ -1,4 +1,6 @@ // run-pass +#![feature(transparent_unions)] + use std::mem::size_of; use std::num::NonZeroUsize; use std::ptr::NonNull; @@ -10,6 +12,11 @@ trait Mirror { type Image; } impl Mirror for T { type Image = T; } struct ParamTypeStruct(T); struct AssocTypeStruct(::Image); +#[repr(transparent)] +union MaybeUninitUnion { + _value: T, + _uninit: (), +} fn main() { // Functions @@ -22,16 +29,19 @@ fn main() { assert_eq!(size_of::<&mut [isize]>(), size_of::>()); // Traits - Box / &Trait / &mut Trait - assert_eq!(size_of::>(), size_of::>>()); - assert_eq!(size_of::<&Trait>(), size_of::>()); - assert_eq!(size_of::<&mut Trait>(), size_of::>()); + assert_eq!(size_of::>(), size_of::>>()); + assert_eq!(size_of::<&dyn Trait>(), size_of::>()); + assert_eq!(size_of::<&mut dyn Trait>(), size_of::>()); // Pointers - Box assert_eq!(size_of::>(), size_of::>>()); - // The optimization can't apply to raw pointers + // The optimization can't apply to raw pointers or unions with a ZST field. assert!(size_of::>() != size_of::<*const isize>()); - assert!(Some(0 as *const isize).is_some()); // Can't collapse None to null + assert!(Some(std::ptr::null::()).is_some()); // Can't collapse None to null + assert_ne!(size_of::(), size_of::>>()); + assert_ne!(size_of::<&str>(), size_of::>>()); + assert_ne!(size_of::>(), size_of::>>>()); struct Foo { _a: Box diff --git a/src/test/run-pass/structs-enums/object-lifetime-default-from-ref-struct.rs b/src/test/run-pass/structs-enums/object-lifetime-default-from-ref-struct.rs index 0a48725cbe44a..e1a865fa50399 100644 --- a/src/test/run-pass/structs-enums/object-lifetime-default-from-ref-struct.rs +++ b/src/test/run-pass/structs-enums/object-lifetime-default-from-ref-struct.rs @@ -22,37 +22,37 @@ struct Ref2<'a,'b,T:'a+'b+?Sized> { } struct SomeStruct<'a> { - t: Ref<'a,Test>, - u: Ref<'a,Test+'a>, + t: Ref<'a, dyn Test>, + u: Ref<'a, dyn Test+'a>, } -fn a<'a>(t: Ref<'a,Test>, mut ss: SomeStruct<'a>) { +fn a<'a>(t: Ref<'a, dyn Test>, mut ss: SomeStruct<'a>) { ss.t = t; } -fn b<'a>(t: Ref<'a,Test>, mut ss: SomeStruct<'a>) { +fn b<'a>(t: Ref<'a, dyn Test>, mut ss: SomeStruct<'a>) { ss.u = t; } -fn c<'a>(t: Ref<'a,Test+'a>, mut ss: SomeStruct<'a>) { +fn c<'a>(t: Ref<'a, dyn Test+'a>, mut ss: SomeStruct<'a>) { ss.t = t; } -fn d<'a>(t: Ref<'a,Test+'a>, mut ss: SomeStruct<'a>) { +fn d<'a>(t: Ref<'a, dyn Test+'a>, mut ss: SomeStruct<'a>) { ss.u = t; } -fn e<'a>(_: Ref<'a, Display+'static>) {} -fn g<'a, 'b>(_: Ref2<'a, 'b, Display+'static>) {} +fn e<'a>(_: Ref<'a, dyn Display+'static>) {} +fn g<'a, 'b>(_: Ref2<'a, 'b, dyn Display+'static>) {} fn main() { // Inside a function body, we can just infer all // lifetimes, to allow Ref<'tmp, Display+'static> // and Ref2<'tmp, 'tmp, Display+'static>. - let x = &0 as &(Display+'static); - let r: Ref = Ref { r: x }; - let r2: Ref2 = Ref2 { a: x, b: x }; + let x = &0 as &(dyn Display+'static); + let r: Ref = Ref { r: x }; + let r2: Ref2 = Ref2 { a: x, b: x }; e(r); g(r2); } diff --git a/src/test/run-pass/structs-enums/object-lifetime-default-from-rptr-struct.rs b/src/test/run-pass/structs-enums/object-lifetime-default-from-rptr-struct.rs index 48ee5a2ed5450..1fc52ead48e0e 100644 --- a/src/test/run-pass/structs-enums/object-lifetime-default-from-rptr-struct.rs +++ b/src/test/run-pass/structs-enums/object-lifetime-default-from-rptr-struct.rs @@ -11,25 +11,25 @@ trait Test { } struct SomeStruct<'a> { - t: &'a MyBox, - u: &'a MyBox, + t: &'a MyBox, + u: &'a MyBox, } struct MyBox { b: Box } -fn a<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { +fn a<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { ss.t = t; } -fn b<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { +fn b<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { ss.u = t; } // see also compile-fail/object-lifetime-default-from-rptr-box-error.rs -fn d<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { +fn d<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { ss.u = t; } diff --git a/src/test/run-pass/structs-enums/rec-align-u64.rs b/src/test/run-pass/structs-enums/rec-align-u64.rs index d211eed131e5d..c4e9e9ea5ee1a 100644 --- a/src/test/run-pass/structs-enums/rec-align-u64.rs +++ b/src/test/run-pass/structs-enums/rec-align-u64.rs @@ -55,7 +55,7 @@ mod m { } } -#[cfg(target_os = "bitrig")] +#[cfg(target_env = "sgx")] mod m { #[cfg(target_arch = "x86_64")] pub mod m { diff --git a/src/test/run-pass/structs-enums/unit-like-struct-drop-run.rs b/src/test/run-pass/structs-enums/unit-like-struct-drop-run.rs index dfe73875215c5..980fd97e2c678 100644 --- a/src/test/run-pass/structs-enums/unit-like-struct-drop-run.rs +++ b/src/test/run-pass/structs-enums/unit-like-struct-drop-run.rs @@ -3,9 +3,6 @@ // Make sure the destructor is run for unit-like structs. - -#![feature(alloc)] - use std::thread; struct Foo; diff --git a/src/test/run-pass/tcp-stress.rs b/src/test/run-pass/tcp-stress.rs index c90f9024af141..391cbbdd42daf 100644 --- a/src/test/run-pass/tcp-stress.rs +++ b/src/test/run-pass/tcp-stress.rs @@ -1,9 +1,9 @@ // ignore-android needs extra network permissions -// ignore-bitrig system ulimit (Too many open files) // ignore-cloudabi no global network namespace access // ignore-emscripten no threads or sockets support // ignore-netbsd system ulimit (Too many open files) // ignore-openbsd system ulimit (Too many open files) +// ignore-sgx no thread sleep support use std::io::prelude::*; use std::net::{TcpListener, TcpStream}; diff --git a/src/test/run-pass/thinlto/thin-lto-inlines2.rs b/src/test/run-pass/thinlto/thin-lto-inlines2.rs index f053dd35a21b5..1eb29657c70d6 100644 --- a/src/test/run-pass/thinlto/thin-lto-inlines2.rs +++ b/src/test/run-pass/thinlto/thin-lto-inlines2.rs @@ -26,4 +26,3 @@ fn main() { assert_eq!(*foo, *bar); } } - diff --git a/src/test/run-pass/threads-sendsync/spawning-with-debug.rs b/src/test/run-pass/threads-sendsync/spawning-with-debug.rs index c78ae78dd1ba2..388d62aa7101c 100644 --- a/src/test/run-pass/threads-sendsync/spawning-with-debug.rs +++ b/src/test/run-pass/threads-sendsync/spawning-with-debug.rs @@ -2,7 +2,7 @@ #![allow(unused_must_use)] #![allow(unused_mut)] // ignore-windows -// exec-env:RUST_LOG=debug +// exec-env:RUSTC_LOG=debug // ignore-emscripten no threads support // regression test for issue #10405, make sure we don't call println! too soon. diff --git a/src/test/run-pass/threads-sendsync/sync-send-in-std.rs b/src/test/run-pass/threads-sendsync/sync-send-in-std.rs index 981ac16635602..15e10dc250f19 100644 --- a/src/test/run-pass/threads-sendsync/sync-send-in-std.rs +++ b/src/test/run-pass/threads-sendsync/sync-send-in-std.rs @@ -2,6 +2,7 @@ // ignore-cloudabi networking not available // ignore-wasm32-bare networking not available +// ignore-sgx ToSocketAddrs cannot be used for DNS Resolution use std::net::ToSocketAddrs; diff --git a/src/test/run-pass/threads-sendsync/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/threads-sendsync/sync-send-iterators-in-libcollections.rs index 812cf89751efd..fd53bb607f79d 100644 --- a/src/test/run-pass/threads-sendsync/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/threads-sendsync/sync-send-iterators-in-libcollections.rs @@ -53,6 +53,7 @@ fn main() { is_sync_send!(BTreeSet::::new(), union(&BTreeSet::::new())); all_sync_send!(HashMap::::new(), iter, iter_mut, drain, into_iter, keys, values); + is_sync_send!(HashMap::::new(), entry(0)); all_sync_send!(HashSet::::new(), iter, drain, into_iter); is_sync_send!(HashSet::::new(), difference(&HashSet::::new())); is_sync_send!(HashSet::::new(), symmetric_difference(&HashSet::::new())); diff --git a/src/test/run-pass/traits/auto-traits.rs b/src/test/run-pass/traits/auto-traits.rs index 7702725e640cd..c495b97b25bfe 100644 --- a/src/test/run-pass/traits/auto-traits.rs +++ b/src/test/run-pass/traits/auto-traits.rs @@ -27,5 +27,5 @@ fn main() { take_auto_unsafe(AutoBool(true)); /// Auto traits are allowed in trait object bounds. - let _: &(Send + Auto) = &0; + let _: &(dyn Send + Auto) = &0; } diff --git a/src/test/run-pass/traits/auxiliary/trait_alias.rs b/src/test/run-pass/traits/auxiliary/trait_alias.rs new file mode 100644 index 0000000000000..9e412215512c9 --- /dev/null +++ b/src/test/run-pass/traits/auxiliary/trait_alias.rs @@ -0,0 +1,13 @@ +#![feature(trait_alias)] + +pub trait Hello { + fn hello(&self); +} + +pub struct Hi; + +impl Hello for Hi { + fn hello(&self) {} +} + +pub trait Greet = Hello; diff --git a/src/test/run-pass/traits/impl-inherent-prefer-over-trait.rs b/src/test/run-pass/traits/impl-inherent-prefer-over-trait.rs index 140dcaf6a27b6..82760788897a5 100644 --- a/src/test/run-pass/traits/impl-inherent-prefer-over-trait.rs +++ b/src/test/run-pass/traits/impl-inherent-prefer-over-trait.rs @@ -11,7 +11,7 @@ impl Foo { fn bar(&self) {} } -impl Trait { +impl dyn Trait { fn baz(_: &Foo) {} } @@ -26,5 +26,5 @@ fn main() { // Should work even if Trait::baz doesn't exist. // N.B: `::bar` would be ambiguous. - ::baz(&Foo); + ::baz(&Foo); } diff --git a/src/test/run-pass/traits/infer-from-object-trait-issue-26952.rs b/src/test/run-pass/traits/infer-from-object-trait-issue-26952.rs index 1deb17e00da61..ed258dbb24c3f 100644 --- a/src/test/run-pass/traits/infer-from-object-trait-issue-26952.rs +++ b/src/test/run-pass/traits/infer-from-object-trait-issue-26952.rs @@ -14,7 +14,7 @@ trait Trait { fn foo(&self); } struct Type { a: PhantomData } -fn as_trait(t: &Type) -> &Trait { loop { } } +fn as_trait(t: &Type) -> &dyn Trait { loop { } } fn want+?Sized>(t: &T) { } diff --git a/src/test/run-pass/traits/kindck-owned-trait-contains-1.rs b/src/test/run-pass/traits/kindck-owned-trait-contains-1.rs index f7a58c6f92671..23b91f924b553 100644 --- a/src/test/run-pass/traits/kindck-owned-trait-contains-1.rs +++ b/src/test/run-pass/traits/kindck-owned-trait-contains-1.rs @@ -12,8 +12,8 @@ impl repeat for Box { } } -fn repeater(v: Box) -> Box+'static> { - box v as Box+'static> // No +fn repeater(v: Box) -> Box+'static> { + box v as Box+'static> // No } pub fn main() { diff --git a/src/test/run-pass/traits/object-one-type-two-traits.rs b/src/test/run-pass/traits/object-one-type-two-traits.rs index 12e4a34a233e0..b92a2ab7b4bc2 100644 --- a/src/test/run-pass/traits/object-one-type-two-traits.rs +++ b/src/test/run-pass/traits/object-one-type-two-traits.rs @@ -10,24 +10,24 @@ use std::any::Any; trait Wrap { fn get(&self) -> isize; - fn wrap(self: Box) -> Box; + fn wrap(self: Box) -> Box; } impl Wrap for isize { fn get(&self) -> isize { *self } - fn wrap(self: Box) -> Box { - self as Box + fn wrap(self: Box) -> Box { + self as Box } } -fn is(x: &Any) -> bool { +fn is(x: &dyn Any) -> bool { x.is::() } fn main() { - let x = box 22isize as Box; + let x = box 22isize as Box; println!("x={}", x.get()); let y = x.wrap(); } diff --git a/src/test/run-pass/traits/parameterized-trait-with-bounds.rs b/src/test/run-pass/traits/parameterized-trait-with-bounds.rs index b1339b207ebae..832d4f6c89f09 100644 --- a/src/test/run-pass/traits/parameterized-trait-with-bounds.rs +++ b/src/test/run-pass/traits/parameterized-trait-with-bounds.rs @@ -12,10 +12,10 @@ mod foo { pub trait D<'a, T> { fn get(self) -> &'a T; } } -fn foo1(_: &(A + Send)) {} -fn foo2(_: Box + Send + Sync>) {} -fn foo3(_: Box + 'static>) {} -fn foo4<'a, T>(_: Box + 'static + Send>) {} -fn foo5<'a, T>(_: Box + 'static + Send>) {} +fn foo1(_: &(dyn A + Send)) {} +fn foo2(_: Box + Send + Sync>) {} +fn foo3(_: Box + 'static>) {} +fn foo4<'a, T>(_: Box + 'static + Send>) {} +fn foo5<'a, T>(_: Box + 'static + Send>) {} pub fn main() {} diff --git a/src/test/run-pass/traits/trait-alias-import-cross-crate.rs b/src/test/run-pass/traits/trait-alias-import-cross-crate.rs new file mode 100644 index 0000000000000..975542ab49b59 --- /dev/null +++ b/src/test/run-pass/traits/trait-alias-import-cross-crate.rs @@ -0,0 +1,14 @@ +// run-pass +// aux-build:trait_alias.rs + +#![feature(trait_alias)] + +extern crate trait_alias; + +// Import only the alias, not the real trait. +use trait_alias::{Greet, Hi}; + +fn main() { + let hi = Hi; + hi.hello(); // From `Hello`, via `Greet` alias. +} diff --git a/src/test/run-pass/traits/trait-alias-import.rs b/src/test/run-pass/traits/trait-alias-import.rs new file mode 100644 index 0000000000000..7d63320b9aad4 --- /dev/null +++ b/src/test/run-pass/traits/trait-alias-import.rs @@ -0,0 +1,38 @@ +#![feature(trait_alias)] + +mod inner { + pub trait Foo { + fn foo(&self); + } + + pub struct Qux; + + impl Foo for Qux { + fn foo(&self) {} + } + + pub trait Bar = Foo; +} + +mod two { + pub trait A { + fn foo(); + } + + impl A for u8 { + fn foo() {} + } +} + +// Import only the alias, not the `Foo` trait. +use inner::{Bar, Qux}; + +// Declaring an alias also brings in aliased methods. +trait Two = two::A; + +fn main() { + let q = Qux; + q.foo(); // From Bar. + + u8::foo(); // From A. +} diff --git a/src/test/run-pass/traits/trait-alias-object.rs b/src/test/run-pass/traits/trait-alias-object.rs deleted file mode 100644 index 1cf9e34edf307..0000000000000 --- a/src/test/run-pass/traits/trait-alias-object.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(trait_alias)] - -trait Foo = PartialEq + Send; -trait Bar = Foo + Sync; - -trait I32Iterator = Iterator; - -pub fn main() { - let a: &dyn Bar = &123; - assert!(*a == 123); - let b = Box::new(456) as Box; - assert!(*b == 456); - - let c: &mut dyn I32Iterator = &mut vec![123].into_iter(); - assert_eq!(c.next(), Some(123)); -} diff --git a/src/test/run-pass/traits/trait-bounds-basic.rs b/src/test/run-pass/traits/trait-bounds-basic.rs index af6392e565859..8c8a7eb7d9da1 100644 --- a/src/test/run-pass/traits/trait-bounds-basic.rs +++ b/src/test/run-pass/traits/trait-bounds-basic.rs @@ -7,18 +7,18 @@ trait Foo { } -fn b(_x: Box) { +fn b(_x: Box) { } -fn c(x: Box) { +fn c(x: Box) { e(x); } -fn d(x: Box) { +fn d(x: Box) { e(x); } -fn e(x: Box) { +fn e(x: Box) { e(x); } diff --git a/src/test/run-pass/traits/trait-bounds-in-arc.rs b/src/test/run-pass/traits/trait-bounds-in-arc.rs index 82bdcdcf7c50b..a45d834297eed 100644 --- a/src/test/run-pass/traits/trait-bounds-in-arc.rs +++ b/src/test/run-pass/traits/trait-bounds-in-arc.rs @@ -12,7 +12,7 @@ use std::sync::mpsc::channel; use std::thread; trait Pet { - fn name(&self, blk: Box); + fn name(&self, blk: Box); fn num_legs(&self) -> usize; fn of_good_pedigree(&self) -> bool; } @@ -34,19 +34,19 @@ struct Goldfyshe { } impl Pet for Catte { - fn name(&self, mut blk: Box) { blk(&self.name) } + fn name(&self, mut blk: Box) { blk(&self.name) } fn num_legs(&self) -> usize { 4 } fn of_good_pedigree(&self) -> bool { self.num_whiskers >= 4 } } impl Pet for Dogge { - fn name(&self, mut blk: Box) { blk(&self.name) } + fn name(&self, mut blk: Box) { blk(&self.name) } fn num_legs(&self) -> usize { 4 } fn of_good_pedigree(&self) -> bool { self.bark_decibels < 70 || self.tricks_known > 20 } } impl Pet for Goldfyshe { - fn name(&self, mut blk: Box) { blk(&self.name) } + fn name(&self, mut blk: Box) { blk(&self.name) } fn num_legs(&self) -> usize { 0 } fn of_good_pedigree(&self) -> bool { self.swim_speed >= 500 } } @@ -67,10 +67,10 @@ pub fn main() { swim_speed: 998, name: "alec_guinness".to_string(), }; - let arc = Arc::new(vec![box catte as Box, - box dogge1 as Box, - box fishe as Box, - box dogge2 as Box]); + let arc = Arc::new(vec![box catte as Box, + box dogge1 as Box, + box fishe as Box, + box dogge2 as Box]); let (tx1, rx1) = channel(); let arc1 = arc.clone(); let t1 = thread::spawn(move|| { check_legs(arc1); tx1.send(()); }); @@ -88,21 +88,21 @@ pub fn main() { t3.join(); } -fn check_legs(arc: Arc>>) { +fn check_legs(arc: Arc>>) { let mut legs = 0; for pet in arc.iter() { legs += pet.num_legs(); } assert!(legs == 12); } -fn check_names(arc: Arc>>) { +fn check_names(arc: Arc>>) { for pet in arc.iter() { pet.name(Box::new(|name| { assert!(name.as_bytes()[0] == 'a' as u8 && name.as_bytes()[1] == 'l' as u8); })) } } -fn check_pedigree(arc: Arc>>) { +fn check_pedigree(arc: Arc>>) { for pet in arc.iter() { assert!(pet.of_good_pedigree()); } diff --git a/src/test/run-pass/traits/trait-bounds-on-structs-and-enums.rs b/src/test/run-pass/traits/trait-bounds-on-structs-and-enums.rs index 18b25b852d173..4dc4fecc91fcf 100644 --- a/src/test/run-pass/traits/trait-bounds-on-structs-and-enums.rs +++ b/src/test/run-pass/traits/trait-bounds-on-structs-and-enums.rs @@ -7,11 +7,11 @@ trait U {} trait T { fn get(self) -> X; } trait S2 { - fn m(x: Box+'static>) {} + fn m(x: Box+'static>) {} } struct St { - f: Box+'static>, + f: Box+'static>, } impl St { diff --git a/src/test/run-pass/traits/trait-coercion-generic.rs b/src/test/run-pass/traits/trait-coercion-generic.rs index 5d1b442afcc70..bf4dda4951910 100644 --- a/src/test/run-pass/traits/trait-coercion-generic.rs +++ b/src/test/run-pass/traits/trait-coercion-generic.rs @@ -18,8 +18,8 @@ impl Trait<&'static str> for Struct { pub fn main() { let a = Struct { x: 1, y: 2 }; - let b: Box> = Box::new(a); + let b: Box> = Box::new(a); b.f("Mary"); - let c: &Trait<&'static str> = &a; + let c: &dyn Trait<&'static str> = &a; c.f("Joe"); } diff --git a/src/test/run-pass/traits/trait-coercion.rs b/src/test/run-pass/traits/trait-coercion.rs index 1a40b81c89fe9..cba33af1f1aca 100644 --- a/src/test/run-pass/traits/trait-coercion.rs +++ b/src/test/run-pass/traits/trait-coercion.rs @@ -22,13 +22,13 @@ impl Trait for Struct { } } -fn foo(mut a: Box) {} +fn foo(mut a: Box) {} pub fn main() { let a = Struct { x: 1, y: 2 }; - let b: Box = Box::new(a); + let b: Box = Box::new(a); b.f(); - let c: &Trait = &a; + let c: &dyn Trait = &a; c.f(); let out = io::stdout(); diff --git a/src/test/run-pass/traits/trait-impl-2.rs b/src/test/run-pass/traits/trait-impl-2.rs index b28d74a7b35b1..804ffec12c2bf 100644 --- a/src/test/run-pass/traits/trait-impl-2.rs +++ b/src/test/run-pass/traits/trait-impl-2.rs @@ -11,7 +11,7 @@ pub mod Foo { } mod Bar { - impl<'a> ::Foo::Trait+'a { + impl<'a> dyn (::Foo::Trait) + 'a { fn bar(&self) { self.foo() } } } diff --git a/src/test/run-pass/traits/trait-impl.rs b/src/test/run-pass/traits/trait-impl.rs index 6b22ac08bb8a6..14796ce19c88e 100644 --- a/src/test/run-pass/traits/trait-impl.rs +++ b/src/test/run-pass/traits/trait-impl.rs @@ -12,7 +12,7 @@ trait T { fn t(&self) {} } -impl<'a> T+'a { +impl<'a> dyn T+'a { fn foo(&self) { unsafe { COUNT *= 2; } } @@ -27,7 +27,7 @@ struct Foo; impl<'a> Bar<'a> for Foo {} fn main() { - let x: &T = &42; + let x: &dyn T = &42; x.foo(); T::foo(x); @@ -36,6 +36,6 @@ fn main() { unsafe { assert_eq!(COUNT, 12); } // Cross-crait case - let x: &Bar = &Foo; + let x: &dyn Bar = &Foo; x.bar(); } diff --git a/src/test/run-pass/traits/trait-inheritance-cast-without-call-to-supertrait.rs b/src/test/run-pass/traits/trait-inheritance-cast-without-call-to-supertrait.rs index c0b5db63bd452..25159c1adb6f6 100644 --- a/src/test/run-pass/traits/trait-inheritance-cast-without-call-to-supertrait.rs +++ b/src/test/run-pass/traits/trait-inheritance-cast-without-call-to-supertrait.rs @@ -26,8 +26,8 @@ impl Bar for A { pub fn main() { let a = &A { x: 3 }; - let afoo = a as &Foo; - let abar = a as &Bar; + let afoo = a as &dyn Foo; + let abar = a as &dyn Bar; assert_eq!(afoo.f(), 10); assert_eq!(abar.g(), 20); } diff --git a/src/test/run-pass/traits/trait-inheritance-cast.rs b/src/test/run-pass/traits/trait-inheritance-cast.rs index 38e5c79e9e033..9070b9d1f5606 100644 --- a/src/test/run-pass/traits/trait-inheritance-cast.rs +++ b/src/test/run-pass/traits/trait-inheritance-cast.rs @@ -25,8 +25,8 @@ impl Bar for A { pub fn main() { let a = &A { x: 3 }; - let afoo = a as &Foo; - let abar = a as &Bar; + let afoo = a as &dyn Foo; + let abar = a as &dyn Bar; assert_eq!(afoo.f(), 10); assert_eq!(abar.g(), 20); assert_eq!(abar.f(), 10); diff --git a/src/test/run-pass/traits/trait-object-auto-dedup.rs b/src/test/run-pass/traits/trait-object-auto-dedup.rs index 98a386e4c6e1d..39d25eb7fe05b 100644 --- a/src/test/run-pass/traits/trait-object-auto-dedup.rs +++ b/src/test/run-pass/traits/trait-object-auto-dedup.rs @@ -1,14 +1,15 @@ // run-pass + #![allow(unused_assignments)] + // Test that duplicate auto trait bounds in trait objects don't create new types. #[allow(unused_assignments)] - use std::marker::Send as SendAlias; // A dummy trait for the non-auto trait. trait Trait {} -// A dummy struct to implement Trait, Send, and . +// A dummy struct to implement `Trait` and `Send`. struct Struct; impl Trait for Struct {} @@ -23,12 +24,12 @@ impl dyn Trait + Send + Send { } fn main() { - // 1. Moving into a variable with more Sends and back. + // 1. Moving into a variable with more `Send`s and back. let mut dyn_trait_send = Box::new(Struct) as Box; let dyn_trait_send_send: Box = dyn_trait_send; dyn_trait_send = dyn_trait_send_send; - // 2. Calling methods with different number of Sends. + // 2. Calling methods with different number of `Send`s. let dyn_trait_send = Box::new(Struct) as Box; takes_dyn_trait_send_send(dyn_trait_send); diff --git a/src/test/run-pass/traits/trait-object-exclusion.rs b/src/test/run-pass/traits/trait-object-exclusion.rs index 248804d144a25..0b8b0e2f5ef4d 100644 --- a/src/test/run-pass/traits/trait-object-exclusion.rs +++ b/src/test/run-pass/traits/trait-object-exclusion.rs @@ -4,7 +4,7 @@ trait Future: 'static { // Future::forget in vtables, otherwise there's an infinite type // recursion through as Future>::forget. fn forget(self) where Self: Sized { - Box::new(Map(self)) as Box; + Box::new(Map(self)) as Box; } } diff --git a/src/test/run-pass/traits/trait-object-generics.rs b/src/test/run-pass/traits/trait-object-generics.rs index 168bffa0e4814..c18754302b75b 100644 --- a/src/test/run-pass/traits/trait-object-generics.rs +++ b/src/test/run-pass/traits/trait-object-generics.rs @@ -16,7 +16,7 @@ pub struct Impl { * task failed at 'index out of bounds: the len is 1 but the index is 1', * src/librustc/middle/subst.rs:58 */ - t: Box+'static> + t: Box+'static> } impl Impl { @@ -38,6 +38,6 @@ impl Trait for () { } pub fn main() { - let a = box () as Box>; + let a = box () as Box>; assert_eq!(a.method(Type::Constant((1, 2))), 0); } diff --git a/src/test/run-pass/traits/trait-object-lifetime-first.rs b/src/test/run-pass/traits/trait-object-lifetime-first.rs index e95a652057d5c..33757cb7c0ab1 100644 --- a/src/test/run-pass/traits/trait-object-lifetime-first.rs +++ b/src/test/run-pass/traits/trait-object-lifetime-first.rs @@ -4,8 +4,8 @@ use std::fmt::Display; static BYTE: u8 = 33; fn main() { - let x: &('static + Display) = &BYTE; - let y: Box<'static + Display> = Box::new(BYTE); + let x: &(dyn 'static + Display) = &BYTE; + let y: Box = Box::new(BYTE); let xstr = format!("{}", x); let ystr = format!("{}", y); assert_eq!(xstr, "33"); diff --git a/src/test/run-pass/traits/trait-object-with-lifetime-bound.rs b/src/test/run-pass/traits/trait-object-with-lifetime-bound.rs index 9060380db17e2..05aab5e3b085c 100644 --- a/src/test/run-pass/traits/trait-object-with-lifetime-bound.rs +++ b/src/test/run-pass/traits/trait-object-with-lifetime-bound.rs @@ -20,10 +20,10 @@ impl<'d> M for P<'d> { fn n(&self) -> u8 { *self.g } } -fn extension<'e>(x: &'e E<'e>) -> Box { +fn extension<'e>(x: &'e E<'e>) -> Box { loop { let p = P { g: x.m() }; - return Box::new(p) as Box; + return Box::new(p) as Box; } } diff --git a/src/test/run-pass/traits/trait-region-pointer-simple.rs b/src/test/run-pass/traits/trait-region-pointer-simple.rs index 6584182d38a4b..0456ca931156e 100644 --- a/src/test/run-pass/traits/trait-region-pointer-simple.rs +++ b/src/test/run-pass/traits/trait-region-pointer-simple.rs @@ -16,6 +16,6 @@ impl Foo for A { pub fn main() { let a = A { x: 3 }; - let b = (&a) as &Foo; + let b = (&a) as &dyn Foo; assert_eq!(b.f(), 3); } diff --git a/src/test/run-pass/traits/traits-impl-object-overlap-issue-23853.rs b/src/test/run-pass/traits/traits-impl-object-overlap-issue-23853.rs index c9745e06d8fb4..e490967b69047 100644 --- a/src/test/run-pass/traits/traits-impl-object-overlap-issue-23853.rs +++ b/src/test/run-pass/traits/traits-impl-object-overlap-issue-23853.rs @@ -14,5 +14,5 @@ impl Foo for T { } fn want_foo() { } fn main() { - want_foo::(); + want_foo::(); } diff --git a/src/test/run-pass/traits/traits-issue-26339.rs b/src/test/run-pass/traits/traits-issue-26339.rs index 0f831be248500..bedd87cc4cc79 100644 --- a/src/test/run-pass/traits/traits-issue-26339.rs +++ b/src/test/run-pass/traits/traits-issue-26339.rs @@ -25,7 +25,7 @@ impl PartialEq for Aimpl { impl A for Aimpl { } fn main() { - let a = &Aimpl as &A; + let a = &Aimpl as &dyn A; assert!(*a == Foo); } diff --git a/src/test/run-pass/traits/traits-multidispatch-infer-convert-target.rs b/src/test/run-pass/traits/traits-multidispatch-infer-convert-target.rs index ca47d9736f63c..626e1ae71bc2f 100644 --- a/src/test/run-pass/traits/traits-multidispatch-infer-convert-target.rs +++ b/src/test/run-pass/traits/traits-multidispatch-infer-convert-target.rs @@ -28,7 +28,6 @@ where T : Convert } fn main() { - use std::default::Default; // T = i16, U = u32 test(22_i16, Default::default(), 2, 4); diff --git a/src/test/run-pass/traits/traits-repeated-supertrait.rs b/src/test/run-pass/traits/traits-repeated-supertrait.rs index c8318bdf15476..391d19c438558 100644 --- a/src/test/run-pass/traits/traits-repeated-supertrait.rs +++ b/src/test/run-pass/traits/traits-repeated-supertrait.rs @@ -22,7 +22,7 @@ impl CompareTo for i64 { impl CompareToInts for i64 { } -fn with_obj(c: &CompareToInts) -> bool { +fn with_obj(c: &dyn CompareToInts) -> bool { c.same_as(22_i64) && c.same_as(22_u64) } diff --git a/src/test/run-pass/traits/ufcs-trait-object.rs b/src/test/run-pass/traits/ufcs-trait-object.rs index abe164a5720bd..700488c22d678 100644 --- a/src/test/run-pass/traits/ufcs-trait-object.rs +++ b/src/test/run-pass/traits/ufcs-trait-object.rs @@ -12,6 +12,6 @@ impl Foo for i32 { } fn main() { - let a: &Foo = &22; + let a: &dyn Foo = &22; assert_eq!(Foo::test(a), 22); } diff --git a/src/test/run-pass/trivial_casts.rs b/src/test/run-pass/trivial_casts.rs index bc56d0158d4df..f06b0708290bc 100644 --- a/src/test/run-pass/trivial_casts.rs +++ b/src/test/run-pass/trivial_casts.rs @@ -36,21 +36,21 @@ pub fn main() { // unsize trait let x: &Bar = &Bar; - let _ = x as &Foo; - let _ = x as *const Foo; + let _ = x as &dyn Foo; + let _ = x as *const dyn Foo; let x: &mut Bar = &mut Bar; - let _ = x as &mut Foo; - let _ = x as *mut Foo; + let _ = x as &mut dyn Foo; + let _ = x as *mut dyn Foo; let x: Box = Box::new(Bar); - let _ = x as Box; + let _ = x as Box; // functions fn baz(_x: i32) {} - let _ = &baz as &Fn(i32); + let _ = &baz as &dyn Fn(i32); let x = |_x: i32| {}; - let _ = &x as &Fn(i32); + let _ = &x as &dyn Fn(i32); } // subtyping diff --git a/src/test/run-pass/try-wait.rs b/src/test/run-pass/try-wait.rs index 05871ba7d4c60..97caddde41214 100644 --- a/src/test/run-pass/try-wait.rs +++ b/src/test/run-pass/try-wait.rs @@ -1,6 +1,7 @@ #![allow(stable_features)] // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes #![feature(process_try_wait)] diff --git a/src/test/run-pass/try_from.rs b/src/test/run-pass/try_from.rs index e42f2c3e3930d..98344491aecf4 100644 --- a/src/test/run-pass/try_from.rs +++ b/src/test/run-pass/try_from.rs @@ -34,4 +34,3 @@ impl Into> for Foo { pub fn main() { let _: Result, Infallible> = Foo { t: 10 }.try_into(); } - diff --git a/src/test/run-pass/tydesc-name.rs b/src/test/run-pass/tydesc-name.rs index 94de30e88e1fb..91578b71d04ae 100644 --- a/src/test/run-pass/tydesc-name.rs +++ b/src/test/run-pass/tydesc-name.rs @@ -11,6 +11,6 @@ struct Foo { pub fn main() { unsafe { assert_eq!(type_name::(), "isize"); - assert_eq!(type_name::>(), "Foo"); + assert_eq!(type_name::>(), "tydesc_name::Foo"); } } diff --git a/src/test/run-pass/type-alias-enum-variants-2.rs b/src/test/run-pass/type-alias-enum-variants-2.rs deleted file mode 100644 index 0cf413babcbf6..0000000000000 --- a/src/test/run-pass/type-alias-enum-variants-2.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![feature(type_alias_enum_variants)] - -#[derive(Debug, PartialEq, Eq)] -enum Foo { - Bar(i32), - Baz { i: i32 }, -} - -type FooAlias = Foo; -type OptionAlias = Option; - -impl Foo { - fn foo() -> Self { - Self::Bar(3) - } -} - -fn main() { - let t = FooAlias::Bar(1); - assert_eq!(t, Foo::Bar(1)); - let t = FooAlias::Baz { i: 2 }; - assert_eq!(t, Foo::Baz { i: 2 }); - match t { - FooAlias::Bar(_i) => {} - FooAlias::Baz { i } => { assert_eq!(i, 2); } - } - assert_eq!(Foo::foo(), Foo::Bar(3)); - - assert_eq!(OptionAlias::Some(4), Option::Some(4)); -} diff --git a/src/test/run-pass/type-alias-enum-variants.rs b/src/test/run-pass/type-alias-enum-variants.rs deleted file mode 100644 index 0cf413babcbf6..0000000000000 --- a/src/test/run-pass/type-alias-enum-variants.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![feature(type_alias_enum_variants)] - -#[derive(Debug, PartialEq, Eq)] -enum Foo { - Bar(i32), - Baz { i: i32 }, -} - -type FooAlias = Foo; -type OptionAlias = Option; - -impl Foo { - fn foo() -> Self { - Self::Bar(3) - } -} - -fn main() { - let t = FooAlias::Bar(1); - assert_eq!(t, Foo::Bar(1)); - let t = FooAlias::Baz { i: 2 }; - assert_eq!(t, Foo::Baz { i: 2 }); - match t { - FooAlias::Bar(_i) => {} - FooAlias::Baz { i } => { assert_eq!(i, 2); } - } - assert_eq!(Foo::foo(), Foo::Bar(3)); - - assert_eq!(OptionAlias::Some(4), Option::Some(4)); -} diff --git a/src/test/run-pass/type-id-higher-rank-2.rs b/src/test/run-pass/type-id-higher-rank-2.rs index d9280cf97f920..469bc8ed7e153 100644 --- a/src/test/run-pass/type-id-higher-rank-2.rs +++ b/src/test/run-pass/type-id-higher-rank-2.rs @@ -7,7 +7,7 @@ struct Foo<'a>(&'a str); fn good(s: &String) -> Foo { Foo(s) } fn bad1(s: String) -> Option<&'static str> { - let a: Box = Box::new(good as fn(&String) -> Foo); + let a: Box = Box::new(good as fn(&String) -> Foo); a.downcast_ref:: Foo<'static>>().map(|f| f(&s).0) } @@ -20,8 +20,8 @@ impl<'a> AsStr<'a, 'a> for String { } fn bad2(s: String) -> Option<&'static str> { - let a: Box = Box::new(Box::new(s) as Box AsStr<'a, 'a>>); - a.downcast_ref:: AsStr<'a, 'static>>>().map(|x| x.get()) + let a: Box = Box::new(Box::new(s) as Box AsStr<'a, 'a>>); + a.downcast_ref:: AsStr<'a, 'static>>>().map(|x| x.get()) } fn main() { diff --git a/src/test/run-pass/type-id-higher-rank.rs b/src/test/run-pass/type-id-higher-rank.rs index 55d70e31b1641..b98dff0d72b8d 100644 --- a/src/test/run-pass/type-id-higher-rank.rs +++ b/src/test/run-pass/type-id-higher-rank.rs @@ -26,9 +26,9 @@ fn main() { assert!(e != f); // Make sure lifetime parameters of items are not ignored. - let g = TypeId::of:: fn(&'a Trait<'a>) -> Struct<'a>>(); - let h = TypeId::of:: fn(&'a Trait<'a>) -> Struct<'static>>(); - let i = TypeId::of:: fn(&'a Trait<'b>) -> Struct<'b>>(); + let g = TypeId::of:: fn(&'a dyn Trait<'a>) -> Struct<'a>>(); + let h = TypeId::of:: fn(&'a dyn Trait<'a>) -> Struct<'static>>(); + let i = TypeId::of:: fn(&'a dyn Trait<'b>) -> Struct<'b>>(); assert!(g != h); assert!(g != i); assert!(h != i); @@ -40,10 +40,10 @@ fn main() { } // Boxed unboxed closures { - let a = TypeId::of::>(); - let b = TypeId::of:: Fn(&'static isize, &'a isize)>>(); - let c = TypeId::of:: Fn(&'a isize, &'b isize)>>(); - let d = TypeId::of:: Fn(&'b isize, &'a isize)>>(); + let a = TypeId::of::>(); + let b = TypeId::of:: Fn(&'static isize, &'a isize)>>(); + let c = TypeId::of:: Fn(&'a isize, &'b isize)>>(); + let d = TypeId::of:: Fn(&'b isize, &'a isize)>>(); assert!(a != b); assert!(a != c); assert!(a != d); @@ -52,8 +52,8 @@ fn main() { assert_eq!(c, d); // Make sure De Bruijn indices are handled correctly - let e = TypeId::of:: Fn(Box &'a isize>)>>(); - let f = TypeId::of:: Fn(&'a isize) -> &'a isize>)>>(); + let e = TypeId::of:: Fn(Box &'a isize>)>>(); + let f = TypeId::of:: Fn(&'a isize) -> &'a isize>)>>(); assert!(e != f); } // Raw unboxed closures diff --git a/src/test/run-pass/type-infer-generalize-ty-var.rs b/src/test/run-pass/type-infer-generalize-ty-var.rs index 244a72c80fa23..6298156452e49 100644 --- a/src/test/run-pass/type-infer-generalize-ty-var.rs +++ b/src/test/run-pass/type-infer-generalize-ty-var.rs @@ -23,8 +23,8 @@ trait Get { fn get(&self) -> &T; } -impl Get for Wrap { - fn get(&self) -> &(MyShow + 'static) { +impl Get for Wrap { + fn get(&self) -> &(dyn MyShow + 'static) { static x: usize = 42; &x } @@ -38,9 +38,9 @@ impl Get for Wrap { } trait MyShow { fn dummy(&self) { } } -impl<'a> MyShow for &'a (MyShow + 'a) { } +impl<'a> MyShow for &'a (dyn MyShow + 'a) { } impl MyShow for usize { } -fn constrain<'a>(rc: RefCell<&'a (MyShow + 'a)>) { } +fn constrain<'a>(rc: RefCell<&'a (dyn MyShow + 'a)>) { } fn main() { let mut collection: Wrap<_> = WrapNone; diff --git a/src/test/run-pass/typeck-closure-to-unsafe-fn-ptr.rs b/src/test/run-pass/typeck-closure-to-unsafe-fn-ptr.rs new file mode 100644 index 0000000000000..fe15b912d6029 --- /dev/null +++ b/src/test/run-pass/typeck-closure-to-unsafe-fn-ptr.rs @@ -0,0 +1,7 @@ +unsafe fn call_unsafe(func: unsafe fn() -> ()) -> () { + func() +} + +pub fn main() { + unsafe { call_unsafe(|| {}); } +} diff --git a/src/test/run-pass/unboxed-closures/unboxed-closures-blanket-fn-mut.rs b/src/test/run-pass/unboxed-closures/unboxed-closures-blanket-fn-mut.rs index 08a9796ea29c5..a1001673506f0 100644 --- a/src/test/run-pass/unboxed-closures/unboxed-closures-blanket-fn-mut.rs +++ b/src/test/run-pass/unboxed-closures/unboxed-closures-blanket-fn-mut.rs @@ -8,7 +8,7 @@ fn a i32>(mut f: F) -> i32 { f() } -fn b(f: &mut FnMut() -> i32) -> i32 { +fn b(f: &mut dyn FnMut() -> i32) -> i32 { a(f) } diff --git a/src/test/run-pass/unboxed-closures/unboxed-closures-blanket-fn.rs b/src/test/run-pass/unboxed-closures/unboxed-closures-blanket-fn.rs index 76ad40b8f3d63..ca1d31ca54470 100644 --- a/src/test/run-pass/unboxed-closures/unboxed-closures-blanket-fn.rs +++ b/src/test/run-pass/unboxed-closures/unboxed-closures-blanket-fn.rs @@ -8,7 +8,7 @@ fn a i32>(f: F) -> i32 { f() } -fn b(f: &Fn() -> i32) -> i32 { +fn b(f: &dyn Fn() -> i32) -> i32 { a(f) } diff --git a/src/test/run-pass/unboxed-closures/unboxed-closures-boxed.rs b/src/test/run-pass/unboxed-closures/unboxed-closures-boxed.rs index 6d55fe997b092..b2596e49aa78e 100644 --- a/src/test/run-pass/unboxed-closures/unboxed-closures-boxed.rs +++ b/src/test/run-pass/unboxed-closures/unboxed-closures-boxed.rs @@ -3,9 +3,9 @@ use std::ops::FnMut; - fn make_adder(x: i32) -> Boxi32+'static> { + fn make_adder(x: i32) -> Boxi32+'static> { (box move |y: i32| -> i32 { x + y }) as - Boxi32+'static> + Boxi32+'static> } pub fn main() { diff --git a/src/test/run-pass/unboxed-closures/unboxed-closures-call-sugar-object-autoderef.rs b/src/test/run-pass/unboxed-closures/unboxed-closures-call-sugar-object-autoderef.rs index 22fc148c3522a..d47ceea0f4f4d 100644 --- a/src/test/run-pass/unboxed-closures/unboxed-closures-call-sugar-object-autoderef.rs +++ b/src/test/run-pass/unboxed-closures/unboxed-closures-call-sugar-object-autoderef.rs @@ -3,7 +3,7 @@ use std::ops::FnMut; -fn make_adder(x: isize) -> Boxisize + 'static> { +fn make_adder(x: isize) -> Boxisize + 'static> { Box::new(move |y| { x + y }) } diff --git a/src/test/run-pass/unboxed-closures/unboxed-closures-call-sugar-object.rs b/src/test/run-pass/unboxed-closures/unboxed-closures-call-sugar-object.rs index 91311fba2e80f..f77733d106d4f 100644 --- a/src/test/run-pass/unboxed-closures/unboxed-closures-call-sugar-object.rs +++ b/src/test/run-pass/unboxed-closures/unboxed-closures-call-sugar-object.rs @@ -1,7 +1,7 @@ // run-pass use std::ops::FnMut; -fn make_adder(x: isize) -> Boxisize + 'static> { +fn make_adder(x: isize) -> Boxisize + 'static> { Box::new(move |y| { x + y }) } diff --git a/src/test/run-pass/unboxed-closures/unboxed-closures-extern-fn-hr.rs b/src/test/run-pass/unboxed-closures/unboxed-closures-extern-fn-hr.rs index 0fd23a2d79646..3ee1aeb109b18 100644 --- a/src/test/run-pass/unboxed-closures/unboxed-closures-extern-fn-hr.rs +++ b/src/test/run-pass/unboxed-closures/unboxed-closures-extern-fn-hr.rs @@ -7,7 +7,7 @@ fn call_itisize>(f: &F, x: isize) -> isize { (*f)(&x) } -fn call_it_boxed(f: &Fn(&isize) -> isize, x: isize) -> isize { +fn call_it_boxed(f: &dyn Fn(&isize) -> isize, x: isize) -> isize { f(&x) } diff --git a/src/test/run-pass/unboxed-closures/unboxed-closures-infer-arg-types-from-expected-object-type.rs b/src/test/run-pass/unboxed-closures/unboxed-closures-infer-arg-types-from-expected-object-type.rs index 4f23f85b649e4..d2eaee304104a 100644 --- a/src/test/run-pass/unboxed-closures/unboxed-closures-infer-arg-types-from-expected-object-type.rs +++ b/src/test/run-pass/unboxed-closures/unboxed-closures-infer-arg-types-from-expected-object-type.rs @@ -12,7 +12,7 @@ impl ToPrimitive for isize {} impl ToPrimitive for i32 {} impl ToPrimitive for usize {} -fn doit(val: T, f: &Fn(T)) { f(val) } +fn doit(val: T, f: &dyn Fn(T)) { f(val) } pub fn main() { doit(0, &|x /*: isize*/ | { x.to_int(); }); diff --git a/src/test/run-pass/unboxed-closures/unboxed-closures-infer-recursive-fn.rs b/src/test/run-pass/unboxed-closures/unboxed-closures-infer-recursive-fn.rs index 72d658f393bd9..86834f49407fc 100644 --- a/src/test/run-pass/unboxed-closures/unboxed-closures-infer-recursive-fn.rs +++ b/src/test/run-pass/unboxed-closures/unboxed-closures-infer-recursive-fn.rs @@ -20,23 +20,23 @@ impl YCombinator { } } -impl R, A) -> R> Fn<(A,)> for YCombinator { +impl R, A) -> R> Fn<(A,)> for YCombinator { extern "rust-call" fn call(&self, (arg,): (A,)) -> R { (self.func)(self, arg) } } -impl R, A) -> R> FnMut<(A,)> for YCombinator { +impl R, A) -> R> FnMut<(A,)> for YCombinator { extern "rust-call" fn call_mut(&mut self, args: (A,)) -> R { self.call(args) } } -impl R, A) -> R> FnOnce<(A,)> for YCombinator { +impl R, A) -> R> FnOnce<(A,)> for YCombinator { type Output = R; extern "rust-call" fn call_once(self, args: (A,)) -> R { self.call(args) } } fn main() { - let factorial = |recur: &Fn(u32) -> u32, arg: u32| -> u32 { + let factorial = |recur: &dyn Fn(u32) -> u32, arg: u32| -> u32 { if arg == 0 {1} else {arg * recur(arg-1)} }; let factorial: YCombinator<_,u32,u32> = YCombinator::new(factorial); diff --git a/src/test/run-pass/unboxed-closures/unboxed-closures-manual-impl.rs b/src/test/run-pass/unboxed-closures/unboxed-closures-manual-impl.rs index 5c7aafdc57361..df60b42ab126a 100644 --- a/src/test/run-pass/unboxed-closures/unboxed-closures-manual-impl.rs +++ b/src/test/run-pass/unboxed-closures/unboxed-closures-manual-impl.rs @@ -19,7 +19,7 @@ fn call_iti32>(mut f: F, x: i32) -> i32 { f(x) + 3 } -fn call_box(f: &mut FnMut(i32) -> i32, x: i32) -> i32 { +fn call_box(f: &mut dyn FnMut(i32) -> i32, x: i32) -> i32 { f(x) + 3 } diff --git a/src/test/run-pass/unboxed-closures/unboxed-closures-monomorphization.rs b/src/test/run-pass/unboxed-closures/unboxed-closures-monomorphization.rs index 092224b793457..2df360d4a30a4 100644 --- a/src/test/run-pass/unboxed-closures/unboxed-closures-monomorphization.rs +++ b/src/test/run-pass/unboxed-closures/unboxed-closures-monomorphization.rs @@ -3,7 +3,7 @@ // monomorphize correctly (issue #16791) fn main(){ - fn bar<'a, T:Clone+'a> (t: T) -> BoxT + 'a> { + fn bar<'a, T:Clone+'a> (t: T) -> BoxT + 'a> { Box::new(move || t.clone()) } diff --git a/src/test/run-pass/unboxed-closures/unboxed-closures-prelude.rs b/src/test/run-pass/unboxed-closures/unboxed-closures-prelude.rs index 7e53c4d9eb613..89a273b7a43ff 100644 --- a/src/test/run-pass/unboxed-closures/unboxed-closures-prelude.rs +++ b/src/test/run-pass/unboxed-closures/unboxed-closures-prelude.rs @@ -4,10 +4,10 @@ // pretty-expanded FIXME #23616 fn main() { - let task: Box isize> = Box::new(|x| x); + let task: Box isize> = Box::new(|x| x); task(0); - let mut task: Box isize> = Box::new(|x| x); + let mut task: Box isize> = Box::new(|x| x); task(0); call(|x| x, 22); diff --git a/src/test/run-pass/unboxed-closures/unboxed-closures-sugar-object.rs b/src/test/run-pass/unboxed-closures/unboxed-closures-sugar-object.rs index 45ab5df94b22c..1ca25517c3c5f 100644 --- a/src/test/run-pass/unboxed-closures/unboxed-closures-sugar-object.rs +++ b/src/test/run-pass/unboxed-closures/unboxed-closures-sugar-object.rs @@ -19,7 +19,7 @@ impl Getter for Identity { } fn main() { - let x: &Getter<(i32,), (i32,)> = &Identity; + let x: &dyn Getter<(i32,), (i32,)> = &Identity; let (y,) = x.get((22,)); assert_eq!(y, 22); } diff --git a/src/test/run-pass/union/union-nonzero.rs b/src/test/run-pass/union/union-nonzero.rs new file mode 100644 index 0000000000000..bd84b46bf3d23 --- /dev/null +++ b/src/test/run-pass/union/union-nonzero.rs @@ -0,0 +1,51 @@ +// run-pass +#![allow(dead_code)] + +// Tests that unions aren't subject to unsafe non-zero/niche-filling optimizations. +// +// For example, if a union `U` can contain both a `&T` and a `*const T`, there's definitely no +// bit-value that an `Option` could reuse as `None`; this test makes sure that isn't done. +// +// Secondly, this tests the status quo (not a guarantee; subject to change!) to not apply such +// optimizations to types containing unions even if they're theoretically possible. (discussion: +// https://github.com/rust-lang/rust/issues/36394) +// +// Notably this nails down part of the behavior that `MaybeUninit` assumes: that a +// `Option>` does not take advantage of non-zero optimization, and thus is a safe +// construct. + +use std::mem::{size_of, transmute}; + +union U1 { + a: A, +} + +union U2 { + a: A, + b: B, +} + +// Option uses a value other than 0 and 1 as None +#[derive(Clone,Copy)] +enum E { + A = 0, + B = 1, +} + +fn main() { + // Unions do not participate in niche-filling/non-zero optimization... + assert!(size_of::>>() > size_of::>()); + assert!(size_of::>>() > size_of::>()); + assert!(size_of::>>() > size_of::>()); + + // ...even when theoretically possible: + assert!(size_of::>>() > size_of::>()); + assert!(size_of::>>() > size_of::>()); + + // The unused bits of the () variant can have any value. + let zeroed: U2<&u8, ()> = unsafe { transmute(std::ptr::null::()) }; + + if let None = Some(zeroed) { + panic!() + } +} diff --git a/src/test/run-pass/unique/unique-object-move.rs b/src/test/run-pass/unique/unique-object-move.rs index 4bd3764fa15a7..84e8cdb32b84e 100644 --- a/src/test/run-pass/unique/unique-object-move.rs +++ b/src/test/run-pass/unique/unique-object-move.rs @@ -15,6 +15,6 @@ pub struct UvEventLoop { impl EventLoop for UvEventLoop { } pub fn main() { - let loop_: Box = box UvEventLoop { uvio: 0 } as Box; + let loop_: Box = box UvEventLoop { uvio: 0 } as Box; let _loop2_ = loop_; } diff --git a/src/test/run-pass/unsized-locals/box-fnonce.rs b/src/test/run-pass/unsized-locals/box-fnonce.rs new file mode 100644 index 0000000000000..16bdeae4fad41 --- /dev/null +++ b/src/test/run-pass/unsized-locals/box-fnonce.rs @@ -0,0 +1,8 @@ +fn call_it(f: Box T>) -> T { + f() +} + +fn main() { + let s = "hello".to_owned(); + assert_eq!(&call_it(Box::new(|| s)) as &str, "hello"); +} diff --git a/src/test/run-pass/unsized2.rs b/src/test/run-pass/unsized2.rs index c3eae299b86c8..c9a8b2e7c664b 100644 --- a/src/test/run-pass/unsized2.rs +++ b/src/test/run-pass/unsized2.rs @@ -60,26 +60,26 @@ fn f7(x: &X) { trait T4 { fn dummy(&self) { } - fn m1(&self, x: &T4, y: X); - fn m2(&self, x: &T5, y: X); + fn m1(&self, x: &dyn T4, y: X); + fn m2(&self, x: &dyn T5, y: X); } trait T5 { fn dummy(&self) { } // not an error (for now) - fn m1(&self, x: &T4); - fn m2(&self, x: &T5); + fn m1(&self, x: &dyn T4); + fn m2(&self, x: &dyn T5); } trait T6 { fn dummy(&self) { } - fn m1(&self, x: &T4); - fn m2(&self, x: &T5); + fn m1(&self, x: &dyn T4); + fn m2(&self, x: &dyn T5); } trait T7 { fn dummy(&self) { } // not an error (for now) - fn m1(&self, x: &T4); - fn m2(&self, x: &T5); + fn m1(&self, x: &dyn T4); + fn m2(&self, x: &dyn T5); } // The last field in a struct may be unsized diff --git a/src/test/run-pass/variadic-ffi.rs b/src/test/run-pass/variadic-ffi.rs index 3539c8d6b72ad..d6fbb1773b29f 100644 --- a/src/test/run-pass/variadic-ffi.rs +++ b/src/test/run-pass/variadic-ffi.rs @@ -1,8 +1,45 @@ // ignore-wasm32-bare no libc to test ffi with +#![feature(c_variadic)] + +use std::ffi::VaList; #[link(name = "rust_test_helpers", kind = "static")] extern { fn rust_interesting_average(_: u64, ...) -> f64; + + // FIXME: we need to disable this lint for `VaList`, + // since it contains a `MaybeUninit` on the asmjs target, + // and this type isn't FFI-safe. This is OK for now, + // since the type is layout-compatible with `i32`. + #[cfg_attr(target_arch = "asmjs", allow(improper_ctypes))] + fn rust_valist_interesting_average(_: u64, _: VaList) -> f64; +} + +pub unsafe extern "C" fn test_valist_forward(n: u64, mut ap: ...) -> f64 { + rust_valist_interesting_average(n, ap.as_va_list()) +} + +pub unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) { + let mut ap2 = ap.clone(); + assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 30); + + // Advance one pair in the copy before checking + let mut ap2 = ap.clone(); + let _ = ap2.arg::(); + let _ = ap2.arg::(); + assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 50); + + // Advance one pair in the original + let _ = ap.arg::(); + let _ = ap.arg::(); + + let mut ap2 = ap.clone(); + assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 50); + + let mut ap2 = ap.clone(); + let _ = ap2.arg::(); + let _ = ap2.arg::(); + assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 70); } pub fn main() { @@ -35,4 +72,12 @@ pub fn main() { let x: unsafe extern fn(u64, ...) -> f64 = rust_interesting_average; call(x); } + + unsafe { + assert_eq!(test_valist_forward(2, 10i64, 10f64, 20i64, 20f64) as i64, 30); + } + + unsafe { + test_va_copy(4, 10i64, 10f64, 20i64, 20f64, 30i64, 30f64, 40i64, 40f64); + } } diff --git a/src/test/run-pass/variant-attributes.rs b/src/test/run-pass/variant-attributes.rs deleted file mode 100644 index 19de3ff2f63f3..0000000000000 --- a/src/test/run-pass/variant-attributes.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![allow(unused_attributes)] -#![allow(non_camel_case_types)] -#![allow(dead_code)] -// pp-exact - Make sure we actually print the attributes -// pretty-expanded FIXME #23616 - -#![feature(custom_attribute)] - -enum crew_of_enterprise_d { - - #[captain] - jean_luc_picard, - - #[oldcommander] - william_t_riker, - - #[chief_medical_officer] - beverly_crusher, - - #[ships_councellor] - deanna_troi, - - #[lieutenant_oldcommander] - data, - - #[chief_of_security] - worf, - - #[chief_engineer] - geordi_la_forge, -} - -fn boldly_go(_crew_member: crew_of_enterprise_d, _where: String) { } - -pub fn main() { - boldly_go(crew_of_enterprise_d::worf, - "where no one has gone before".to_string()); -} diff --git a/src/test/run-pass/wait-forked-but-failed-child.rs b/src/test/run-pass/wait-forked-but-failed-child.rs index e9869866a9bfc..1f32bd00a037c 100644 --- a/src/test/run-pass/wait-forked-but-failed-child.rs +++ b/src/test/run-pass/wait-forked-but-failed-child.rs @@ -1,5 +1,6 @@ // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes #![feature(rustc_private)] diff --git a/src/test/run-pass/weird-exprs.rs b/src/test/run-pass/weird-exprs.rs index 7ce7e29e87235..7b2b46c45d27c 100644 --- a/src/test/run-pass/weird-exprs.rs +++ b/src/test/run-pass/weird-exprs.rs @@ -1,8 +1,9 @@ +#![feature(generators)] + #![allow(non_camel_case_types)] #![allow(dead_code)] #![allow(unreachable_code)] #![allow(unused_parens)] -// compile-flags: -Z borrowck=compare #![recursion_limit = "256"] @@ -127,6 +128,35 @@ fn punch_card() -> impl std::fmt::Debug { ..=.. ..=.. .. ..=..=.. ..=..=.. .. .. ..=.. .. } +fn r#match() { + let val = match match match match match () { + () => () + } { + () => () + } { + () => () + } { + () => () + } { + () => () + }; + assert_eq!(val, ()); +} + +fn i_yield() { + static || { + yield yield yield yield yield yield yield yield yield; + }; +} + +fn match_nested_if() { + let val = match () { + () if if if if true {true} else {false} {true} else {false} {true} else {false} => true, + _ => false, + }; + assert!(val); +} + pub fn main() { strange(); funny(); @@ -142,4 +172,7 @@ pub fn main() { union(); special_characters(); punch_card(); + r#match(); + i_yield(); + match_nested_if(); } diff --git a/src/test/run-pass/wf-bound-region-in-object-type.rs b/src/test/run-pass/wf-bound-region-in-object-type.rs index d81059ca6a844..6814e2baab597 100644 --- a/src/test/run-pass/wf-bound-region-in-object-type.rs +++ b/src/test/run-pass/wf-bound-region-in-object-type.rs @@ -12,7 +12,7 @@ pub struct Context<'tcx> { pub type Cmd<'a> = &'a isize; pub type DecodeInlinedItem<'a> = - Box FnMut(Cmd, &Context<'tcx>) -> Result<&'tcx isize, ()> + 'a>; + Box FnMut(Cmd, &Context<'tcx>) -> Result<&'tcx isize, ()> + 'a>; fn foo(d: DecodeInlinedItem) { } diff --git a/src/test/run-pass/x86stdcall.rs b/src/test/run-pass/x86stdcall.rs index 11a45a58895d9..cd9450a5697c6 100644 --- a/src/test/run-pass/x86stdcall.rs +++ b/src/test/run-pass/x86stdcall.rs @@ -1,5 +1,5 @@ // ignore-wasm32-bare no libc to test ffi with - +// ignore-sgx no libc // GetLastError doesn't seem to work with stack switching #[cfg(windows)] @@ -23,7 +23,6 @@ pub fn main() { } #[cfg(any(target_os = "android", - target_os = "bitrig", target_os = "cloudabi", target_os = "dragonfly", target_os = "emscripten", diff --git a/src/test/rustdoc-js/alias-1.js b/src/test/rustdoc-js-std/alias-1.js similarity index 100% rename from src/test/rustdoc-js/alias-1.js rename to src/test/rustdoc-js-std/alias-1.js diff --git a/src/test/rustdoc-js/alias-2.js b/src/test/rustdoc-js-std/alias-2.js similarity index 100% rename from src/test/rustdoc-js/alias-2.js rename to src/test/rustdoc-js-std/alias-2.js diff --git a/src/test/rustdoc-js/alias-3.js b/src/test/rustdoc-js-std/alias-3.js similarity index 100% rename from src/test/rustdoc-js/alias-3.js rename to src/test/rustdoc-js-std/alias-3.js diff --git a/src/test/rustdoc-js/alias.js b/src/test/rustdoc-js-std/alias.js similarity index 100% rename from src/test/rustdoc-js/alias.js rename to src/test/rustdoc-js-std/alias.js diff --git a/src/test/rustdoc-js-std/basic.js b/src/test/rustdoc-js-std/basic.js new file mode 100644 index 0000000000000..824cac7108332 --- /dev/null +++ b/src/test/rustdoc-js-std/basic.js @@ -0,0 +1,15 @@ +const QUERY = 'String'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::string', 'name': 'String' }, + { 'path': 'std::ffi', 'name': 'CString' }, + { 'path': 'std::ffi', 'name': 'OsString' }, + ], + 'in_args': [ + { 'path': 'std::str', 'name': 'eq' }, + ], + 'returned': [ + { 'path': 'std::string::String', 'name': 'add' }, + ], +}; diff --git a/src/test/rustdoc-js/deduplication.js b/src/test/rustdoc-js-std/deduplication.js similarity index 100% rename from src/test/rustdoc-js/deduplication.js rename to src/test/rustdoc-js-std/deduplication.js diff --git a/src/test/rustdoc-js/enum-option.js b/src/test/rustdoc-js-std/enum-option.js similarity index 100% rename from src/test/rustdoc-js/enum-option.js rename to src/test/rustdoc-js-std/enum-option.js diff --git a/src/test/rustdoc-js/filter-crate.js b/src/test/rustdoc-js-std/filter-crate.js similarity index 100% rename from src/test/rustdoc-js/filter-crate.js rename to src/test/rustdoc-js-std/filter-crate.js diff --git a/src/test/rustdoc-js/fn-forget.js b/src/test/rustdoc-js-std/fn-forget.js similarity index 100% rename from src/test/rustdoc-js/fn-forget.js rename to src/test/rustdoc-js-std/fn-forget.js diff --git a/src/test/rustdoc-js/from_u.js b/src/test/rustdoc-js-std/from_u.js similarity index 100% rename from src/test/rustdoc-js/from_u.js rename to src/test/rustdoc-js-std/from_u.js diff --git a/src/test/rustdoc-js/keyword.js b/src/test/rustdoc-js-std/keyword.js similarity index 100% rename from src/test/rustdoc-js/keyword.js rename to src/test/rustdoc-js-std/keyword.js diff --git a/src/test/rustdoc-js/macro-check.js b/src/test/rustdoc-js-std/macro-check.js similarity index 100% rename from src/test/rustdoc-js/macro-check.js rename to src/test/rustdoc-js-std/macro-check.js diff --git a/src/test/rustdoc-js/macro-print.js b/src/test/rustdoc-js-std/macro-print.js similarity index 100% rename from src/test/rustdoc-js/macro-print.js rename to src/test/rustdoc-js-std/macro-print.js diff --git a/src/test/rustdoc-js/multi-query.js b/src/test/rustdoc-js-std/multi-query.js similarity index 100% rename from src/test/rustdoc-js/multi-query.js rename to src/test/rustdoc-js-std/multi-query.js diff --git a/src/test/rustdoc-js/never.js b/src/test/rustdoc-js-std/never.js similarity index 100% rename from src/test/rustdoc-js/never.js rename to src/test/rustdoc-js-std/never.js diff --git a/src/test/rustdoc-js/quoted.js b/src/test/rustdoc-js-std/quoted.js similarity index 100% rename from src/test/rustdoc-js/quoted.js rename to src/test/rustdoc-js-std/quoted.js diff --git a/src/test/rustdoc-js/should-fail.js b/src/test/rustdoc-js-std/should-fail.js similarity index 100% rename from src/test/rustdoc-js/should-fail.js rename to src/test/rustdoc-js-std/should-fail.js diff --git a/src/test/rustdoc-js/string-from_ut.js b/src/test/rustdoc-js-std/string-from_ut.js similarity index 100% rename from src/test/rustdoc-js/string-from_ut.js rename to src/test/rustdoc-js-std/string-from_ut.js diff --git a/src/test/rustdoc-js/struct-vec.js b/src/test/rustdoc-js-std/struct-vec.js similarity index 100% rename from src/test/rustdoc-js/struct-vec.js rename to src/test/rustdoc-js-std/struct-vec.js diff --git a/src/test/rustdoc-js/vec-new.js b/src/test/rustdoc-js-std/vec-new.js similarity index 100% rename from src/test/rustdoc-js/vec-new.js rename to src/test/rustdoc-js-std/vec-new.js diff --git a/src/test/rustdoc-js/basic.js b/src/test/rustdoc-js/basic.js index 824cac7108332..d99b23468b60c 100644 --- a/src/test/rustdoc-js/basic.js +++ b/src/test/rustdoc-js/basic.js @@ -1,15 +1,7 @@ -const QUERY = 'String'; +const QUERY = 'Fo'; const EXPECTED = { 'others': [ - { 'path': 'std::string', 'name': 'String' }, - { 'path': 'std::ffi', 'name': 'CString' }, - { 'path': 'std::ffi', 'name': 'OsString' }, - ], - 'in_args': [ - { 'path': 'std::str', 'name': 'eq' }, - ], - 'returned': [ - { 'path': 'std::string::String', 'name': 'add' }, + { 'path': 'basic', 'name': 'Foo' }, ], }; diff --git a/src/test/rustdoc-js/basic.rs b/src/test/rustdoc-js/basic.rs new file mode 100644 index 0000000000000..1b4963fcebea8 --- /dev/null +++ b/src/test/rustdoc-js/basic.rs @@ -0,0 +1,2 @@ +/// Foo +pub struct Foo; diff --git a/src/test/rustdoc-js/search-short-types.js b/src/test/rustdoc-js/search-short-types.js new file mode 100644 index 0000000000000..0ebf4860cfa58 --- /dev/null +++ b/src/test/rustdoc-js/search-short-types.js @@ -0,0 +1,8 @@ +const QUERY = 'P'; + +const EXPECTED = { + 'others': [ + { 'path': 'search_short_types', 'name': 'P' }, + { 'path': 'search_short_types', 'name': 'Ap' }, + ], +}; diff --git a/src/test/rustdoc-js/search-short-types.rs b/src/test/rustdoc-js/search-short-types.rs new file mode 100644 index 0000000000000..2eacc0a358284 --- /dev/null +++ b/src/test/rustdoc-js/search-short-types.rs @@ -0,0 +1,68 @@ +macro_rules! imp { + ($name:ident) => { + pub struct $name { + pub op: usize, + } + impl $name { + pub fn op() {} + pub fn cmp() {} + pub fn map() {} + pub fn pop() {} + pub fn ptr() {} + pub fn rpo() {} + pub fn drop() {} + pub fn copy() {} + pub fn zip() {} + pub fn sup() {} + pub fn pa() {} + pub fn pb() {} + pub fn pc() {} + pub fn pd() {} + pub fn pe() {} + pub fn pf() {} + pub fn pg() {} + pub fn ph() {} + pub fn pi() {} + pub fn pj() {} + pub fn pk() {} + pub fn pl() {} + pub fn pm() {} + pub fn pn() {} + pub fn po() {} + } + }; + ($name:ident, $($names:ident),*) => { + imp!($name); + imp!($($names),*); + }; +} +macro_rules! en { + ($name:ident) => { + pub enum $name { + Ptr, + Rp, + Rpo, + Pt, + Drop, + Dr, + Dro, + Sup, + Op, + Cmp, + Map, + Mp, + } + }; + ($name:ident, $($names:ident),*) => { + en!($name); + en!($($names),*); + }; +} + +imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd); +imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp); +imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp); + +en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar); + +pub struct P; diff --git a/src/test/rustdoc-js/substring.js b/src/test/rustdoc-js/substring.js new file mode 100644 index 0000000000000..af05cd1ad34d1 --- /dev/null +++ b/src/test/rustdoc-js/substring.js @@ -0,0 +1,8 @@ +const QUERY = 'waker_from'; + +const EXPECTED = { + 'others': [ + { 'path': 'substring::SuperWaker', 'name': 'local_waker_from_nonlocal' }, + { 'path': 'substring::SuperWakerTask', 'name': 'local_waker_from_nonlocal' }, + ], +}; diff --git a/src/test/rustdoc-js/substring.rs b/src/test/rustdoc-js/substring.rs new file mode 100644 index 0000000000000..e729c722c7999 --- /dev/null +++ b/src/test/rustdoc-js/substring.rs @@ -0,0 +1,21 @@ +pub struct SuperWaker; + +impl SuperWaker { + pub fn local_waker_from_nonlocal() {} + pub fn local_waker_frm_nonlocal() {} + pub fn some_method() {} + pub fn some_other_method() {} + pub fn waker_non_local() {} + pub fn from_non_local() {} +} + +pub struct SuperWakerTask; + +impl SuperWakerTask { + pub fn local_waker_from_nonlocal() {} + pub fn local_waker_frm_nonlocal() {} + pub fn some_method() {} + pub fn some_other_method() {} + pub fn waker_non_local() {} + pub fn from_non_local() {} +} diff --git a/src/test/rustdoc-ui/cfg-test.rs b/src/test/rustdoc-ui/cfg-test.rs new file mode 100644 index 0000000000000..6112e9b30e837 --- /dev/null +++ b/src/test/rustdoc-ui/cfg-test.rs @@ -0,0 +1,22 @@ +// compile-pass +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" + +// Crates like core have doctests gated on `cfg(not(test))` so we need to make +// sure `cfg(test)` is not active when running `rustdoc --test`. + +/// this doctest will be ignored: +/// +/// ``` +/// assert!(false); +/// ``` +#[cfg(test)] +pub struct Foo; + +/// this doctest will be tested: +/// +/// ``` +/// assert!(true); +/// ``` +#[cfg(not(test))] +pub struct Foo; diff --git a/src/test/rustdoc-ui/cfg-test.stdout b/src/test/rustdoc-ui/cfg-test.stdout new file mode 100644 index 0000000000000..67873870e89b2 --- /dev/null +++ b/src/test/rustdoc-ui/cfg-test.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/cfg-test.rs - Foo (line 18) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/test/rustdoc-ui/coverage/basic.rs b/src/test/rustdoc-ui/coverage/basic.rs new file mode 100644 index 0000000000000..4247fdf989556 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/basic.rs @@ -0,0 +1,50 @@ +// compile-flags:-Z unstable-options --show-coverage +// compile-pass + +#![feature(extern_types)] + +//! Make sure to have some docs on your crate root + +/// This struct is documented, but its fields are not. +/// +/// However, one field is private, so it shouldn't show in the total. +pub struct SomeStruct { + pub some_field: usize, + other_field: usize, +} + +impl SomeStruct { + /// Method with docs + pub fn this_fn(&self) {} + + // Method without docs + pub fn other_method(&self) {} +} + +// struct without docs +pub struct OtherStruct; + +// function with no docs +pub fn some_fn() {} + +/// Function with docs +pub fn other_fn() {} + +pub enum SomeEnum { + /// Some of these variants are documented... + VarOne, + /// ...but some of them are not. + VarTwo, + // (like this one) + VarThree, +} + +/// There's a macro here, too +#[macro_export] +macro_rules! some_macro { + () => {}; +} + +extern { + pub type ExternType; +} diff --git a/src/test/rustdoc-ui/coverage/basic.stdout b/src/test/rustdoc-ui/coverage/basic.stdout new file mode 100644 index 0000000000000..3e91660631626 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/basic.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+ +| File | Documented | Total | Percentage | ++-------------------------------------+------------+------------+------------+ +| ...est/rustdoc-ui/coverage/basic.rs | 7 | 14 | 50.0% | ++-------------------------------------+------------+------------+------------+ +| Total | 7 | 14 | 50.0% | ++-------------------------------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/empty.rs b/src/test/rustdoc-ui/coverage/empty.rs new file mode 100644 index 0000000000000..463617a1143df --- /dev/null +++ b/src/test/rustdoc-ui/coverage/empty.rs @@ -0,0 +1,4 @@ +// compile-flags:-Z unstable-options --show-coverage +// compile-pass + +// an empty crate still has one item to document: the crate root diff --git a/src/test/rustdoc-ui/coverage/empty.stdout b/src/test/rustdoc-ui/coverage/empty.stdout new file mode 100644 index 0000000000000..11b514fbfeaef --- /dev/null +++ b/src/test/rustdoc-ui/coverage/empty.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+ +| File | Documented | Total | Percentage | ++-------------------------------------+------------+------------+------------+ +| ...est/rustdoc-ui/coverage/empty.rs | 0 | 1 | 0.0% | ++-------------------------------------+------------+------------+------------+ +| Total | 0 | 1 | 0.0% | ++-------------------------------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/enums.rs b/src/test/rustdoc-ui/coverage/enums.rs new file mode 100644 index 0000000000000..5cd7f490d1a9a --- /dev/null +++ b/src/test/rustdoc-ui/coverage/enums.rs @@ -0,0 +1,22 @@ +// compile-flags:-Z unstable-options --show-coverage +// compile-pass + +//! (remember the crate root is still a module) + +/// so check out this enum here +pub enum ThisEnum { + /// this variant has some weird stuff going on + VarOne { + /// like, it has some named fields inside + field_one: usize, + // (these show up as struct fields) + field_two: usize, + }, + /// here's another variant for you + VarTwo(String), + // but not all of them need to be documented as thoroughly + VarThree, +} + +/// uninhabited enums? sure, let's throw one of those around +pub enum OtherEnum {} diff --git a/src/test/rustdoc-ui/coverage/enums.stdout b/src/test/rustdoc-ui/coverage/enums.stdout new file mode 100644 index 0000000000000..87e2ad9f20df6 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/enums.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+ +| File | Documented | Total | Percentage | ++-------------------------------------+------------+------------+------------+ +| ...est/rustdoc-ui/coverage/enums.rs | 6 | 8 | 75.0% | ++-------------------------------------+------------+------------+------------+ +| Total | 6 | 8 | 75.0% | ++-------------------------------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/exotic.rs b/src/test/rustdoc-ui/coverage/exotic.rs new file mode 100644 index 0000000000000..b4adf45b90b8a --- /dev/null +++ b/src/test/rustdoc-ui/coverage/exotic.rs @@ -0,0 +1,15 @@ +// compile-flags:-Z unstable-options --show-coverage +// compile-pass + +#![feature(doc_keyword)] + +//! the features only used in std also have entries in the table, so make sure those get pulled out +//! properly as well + +/// woo, check it out, we can write our own primitive docs lol +#[doc(primitive="unit")] +mod prim_unit {} + +/// keywords? sure, pile them on +#[doc(keyword="where")] +mod where_keyword {} diff --git a/src/test/rustdoc-ui/coverage/exotic.stdout b/src/test/rustdoc-ui/coverage/exotic.stdout new file mode 100644 index 0000000000000..2bacfcfcecabe --- /dev/null +++ b/src/test/rustdoc-ui/coverage/exotic.stdout @@ -0,0 +1,8 @@ ++-------------------------------------+------------+------------+------------+ +| File | Documented | Total | Percentage | ++-------------------------------------+------------+------------+------------+ +| ...st/rustdoc-ui/coverage/exotic.rs | 1 | 1 | 100.0% | +| | 2 | 2 | 100.0% | ++-------------------------------------+------------+------------+------------+ +| Total | 3 | 3 | 100.0% | ++-------------------------------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/private.rs b/src/test/rustdoc-ui/coverage/private.rs new file mode 100644 index 0000000000000..9024185856daa --- /dev/null +++ b/src/test/rustdoc-ui/coverage/private.rs @@ -0,0 +1,21 @@ +// compile-flags:-Z unstable-options --show-coverage --document-private-items +// compile-pass + +#![allow(unused)] + +//! when `--document-private-items` is passed, nothing is safe. everything must have docs or your +//! score will suffer the consequences + +mod this_mod { + fn private_fn() {} +} + +/// See, our public items have docs! +pub struct SomeStruct { + /// Look, all perfectly documented! + pub field: usize, + other: usize, +} + +/// Nothing shady going on here. Just a bunch of well-documented code. (cough) +pub fn public_fn() {} diff --git a/src/test/rustdoc-ui/coverage/private.stdout b/src/test/rustdoc-ui/coverage/private.stdout new file mode 100644 index 0000000000000..0d4c7c68fd05e --- /dev/null +++ b/src/test/rustdoc-ui/coverage/private.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+ +| File | Documented | Total | Percentage | ++-------------------------------------+------------+------------+------------+ +| ...t/rustdoc-ui/coverage/private.rs | 4 | 7 | 57.1% | ++-------------------------------------+------------+------------+------------+ +| Total | 4 | 7 | 57.1% | ++-------------------------------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/statics-consts.rs b/src/test/rustdoc-ui/coverage/statics-consts.rs new file mode 100644 index 0000000000000..3c1dd35dfe1ab --- /dev/null +++ b/src/test/rustdoc-ui/coverage/statics-consts.rs @@ -0,0 +1,23 @@ +// compile-flags:-Z unstable-options --show-coverage +// compile-pass + +//! gotta make sure we can count statics and consts correctly, too + +/// static like electricity, right? +pub static THIS_STATIC: usize = 0; + +/// (it's not electricity, is it) +pub const THIS_CONST: usize = 1; + +/// associated consts show up separately, but let's throw them in as well +pub trait SomeTrait { + /// just like that, yeah + const ASSOC_CONST: usize; +} + +pub struct SomeStruct; + +impl SomeStruct { + /// wait, structs can have them too, can't forget those + pub const ASSOC_CONST: usize = 100; +} diff --git a/src/test/rustdoc-ui/coverage/statics-consts.stdout b/src/test/rustdoc-ui/coverage/statics-consts.stdout new file mode 100644 index 0000000000000..8459f90ae7b31 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/statics-consts.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+ +| File | Documented | Total | Percentage | ++-------------------------------------+------------+------------+------------+ +| ...oc-ui/coverage/statics-consts.rs | 6 | 7 | 85.7% | ++-------------------------------------+------------+------------+------------+ +| Total | 6 | 7 | 85.7% | ++-------------------------------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/traits.rs b/src/test/rustdoc-ui/coverage/traits.rs new file mode 100644 index 0000000000000..5f32d5b0cccc7 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/traits.rs @@ -0,0 +1,37 @@ +// compile-flags:-Z unstable-options --show-coverage +// compile-pass + +#![feature(trait_alias)] + +/// look at this trait right here +pub trait ThisTrait { + /// that's a trait all right + fn right_here(&self); + + /// even the provided functions show up as trait methods + fn aww_yeah(&self) {} + + /// gotta check those associated types, they're slippery + type SomeType; +} + +/// so what happens if we take some struct... +pub struct SomeStruct; + +/// ...and slap this trait on it? +impl ThisTrait for SomeStruct { + /// nothing! trait impls are totally ignored in this calculation, sorry. + fn right_here(&self) {} + + type SomeType = String; +} + +/// but what about those aliases? i hear they're pretty exotic +pub trait MyAlias = ThisTrait + Send + Sync; + +// FIXME(58624): once rustdoc can process existential types, we need to make sure they're counted +// /// woah, getting all existential in here +// pub existential type ThisExists: ThisTrait; +// +// /// why don't we get a little more concrete +// pub fn defines() -> ThisExists { SomeStruct {} } diff --git a/src/test/rustdoc-ui/coverage/traits.stdout b/src/test/rustdoc-ui/coverage/traits.stdout new file mode 100644 index 0000000000000..e347a4da0b978 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/traits.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+ +| File | Documented | Total | Percentage | ++-------------------------------------+------------+------------+------------+ +| ...st/rustdoc-ui/coverage/traits.rs | 6 | 7 | 85.7% | ++-------------------------------------+------------+------------+------------+ +| Total | 6 | 7 | 85.7% | ++-------------------------------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr index e18b9909f586e..1a120dcb18654 100644 --- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr @@ -1,7 +1,7 @@ error: `[v2]` cannot be resolved, ignoring it... --> $DIR/deny-intra-link-resolution-failure.rs:3:6 | -LL | /// [v2] //~ ERROR +LL | /// [v2] | ^^ cannot be resolved, ignoring | note: lint level defined here @@ -9,5 +9,7 @@ note: lint level defined here | LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + +error: aborting due to previous error diff --git a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr index 1cfd6092cb3a5..9cd50d26766ea 100644 --- a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr +++ b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr @@ -1,22 +1,22 @@ error: missing documentation for crate --> $DIR/deny-missing-docs-crate.rs:1:1 | -LL | / #![deny(missing_docs)] //~ ERROR +LL | / #![deny(missing_docs)] LL | | -LL | | pub struct Foo; //~ ERROR +LL | | pub struct Foo; | |_______________^ | note: lint level defined here --> $DIR/deny-missing-docs-crate.rs:1:9 | -LL | #![deny(missing_docs)] //~ ERROR +LL | #![deny(missing_docs)] | ^^^^^^^^^^^^ error: missing documentation for a struct --> $DIR/deny-missing-docs-crate.rs:3:1 | -LL | pub struct Foo; //~ ERROR +LL | pub struct Foo; | ^^^^^^^^^^^^^^^ -error: Compilation failed, aborting rustdoc +error: aborting due to 2 previous errors diff --git a/src/test/rustdoc-ui/deny-missing-docs-macro.stderr b/src/test/rustdoc-ui/deny-missing-docs-macro.stderr index b87e60d8269ea..ef15bf05d54ef 100644 --- a/src/test/rustdoc-ui/deny-missing-docs-macro.stderr +++ b/src/test/rustdoc-ui/deny-missing-docs-macro.stderr @@ -1,7 +1,7 @@ error: missing documentation for macro --> $DIR/deny-missing-docs-macro.rs:6:1 | -LL | macro_rules! foo { //~ ERROR +LL | macro_rules! foo { | ^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -10,5 +10,5 @@ note: lint level defined here LL | #![deny(missing_docs)] | ^^^^^^^^^^^^ -error: Compilation failed, aborting rustdoc +error: aborting due to previous error diff --git a/src/test/rustdoc-ui/doc-without-codeblock.rs b/src/test/rustdoc-ui/doc-without-codeblock.rs index aa3f539ba32a3..4b2a91e9c8127 100644 --- a/src/test/rustdoc-ui/doc-without-codeblock.rs +++ b/src/test/rustdoc-ui/doc-without-codeblock.rs @@ -1,6 +1,4 @@ -//~ ERROR Missing code example in this documentation - -#![deny(missing_doc_code_examples)] +#![deny(missing_doc_code_examples)] //~ ERROR Missing code example in this documentation /// Some docs. //~^ ERROR Missing code example in this documentation diff --git a/src/test/rustdoc-ui/doc-without-codeblock.stderr b/src/test/rustdoc-ui/doc-without-codeblock.stderr index c07965a6ab968..23c07c4d32d64 100644 --- a/src/test/rustdoc-ui/doc-without-codeblock.stderr +++ b/src/test/rustdoc-ui/doc-without-codeblock.stderr @@ -1,26 +1,38 @@ error: Missing code example in this documentation + --> $DIR/doc-without-codeblock.rs:1:1 + | +LL | / #![deny(missing_doc_code_examples)] +LL | | +LL | | /// Some docs. +LL | | +... | +LL | | pub fn bar() {} +LL | | } + | |_^ | note: lint level defined here - --> $DIR/doc-without-codeblock.rs:3:9 + --> $DIR/doc-without-codeblock.rs:1:9 | LL | #![deny(missing_doc_code_examples)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: Missing code example in this documentation - --> $DIR/doc-without-codeblock.rs:5:1 + --> $DIR/doc-without-codeblock.rs:3:1 | LL | /// Some docs. | ^^^^^^^^^^^^^^ error: Missing code example in this documentation - --> $DIR/doc-without-codeblock.rs:9:1 + --> $DIR/doc-without-codeblock.rs:7:1 | LL | /// And then, the princess died. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Missing code example in this documentation - --> $DIR/doc-without-codeblock.rs:12:5 + --> $DIR/doc-without-codeblock.rs:10:5 | LL | /// Or maybe not because she saved herself! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: aborting due to 4 previous errors + diff --git a/src/test/rustdoc-ui/failed-doctest-compile-fail.rs b/src/test/rustdoc-ui/failed-doctest-compile-fail.rs new file mode 100644 index 0000000000000..297d6efd45fee --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-compile-fail.rs @@ -0,0 +1,11 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// failure-status: 101 + +/// ```compile_fail +/// println!("Hello"); +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout b/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout new file mode 100644 index 0000000000000..74e33d7beebeb --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout @@ -0,0 +1,14 @@ + +running 1 test +test $DIR/failed-doctest-compile-fail.rs - Foo (line 8) ... FAILED + +failures: + +---- $DIR/failed-doctest-compile-fail.rs - Foo (line 8) stdout ---- +Test compiled successfully, but it's marked `compile_fail`. + +failures: + $DIR/failed-doctest-compile-fail.rs - Foo (line 8) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/test/rustdoc-ui/failed-doctest-missing-codes.rs b/src/test/rustdoc-ui/failed-doctest-missing-codes.rs new file mode 100644 index 0000000000000..62102062d4991 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-missing-codes.rs @@ -0,0 +1,11 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// failure-status: 101 + +/// ```compile_fail,E0004 +/// let x: () = 5i32; +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout new file mode 100644 index 0000000000000..d206b721765b2 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout @@ -0,0 +1,26 @@ + +running 1 test +test $DIR/failed-doctest-missing-codes.rs - Foo (line 8) ... FAILED + +failures: + +---- $DIR/failed-doctest-missing-codes.rs - Foo (line 8) stdout ---- +error[E0308]: mismatched types + --> $DIR/failed-doctest-missing-codes.rs:9:13 + | +3 | let x: () = 5i32; + | ^^^^ expected (), found i32 + | + = note: expected type `()` + found type `i32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. +Some expected error codes were not found: ["E0004"] + +failures: + $DIR/failed-doctest-missing-codes.rs - Foo (line 8) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs index 48f1424e6b23d..d2cdeb8f8f50e 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.rs +++ b/src/test/rustdoc-ui/failed-doctest-output.rs @@ -5,10 +5,13 @@ // compile-flags:--test // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // failure-status: 101 -// rustc-env:RUST_BACKTRACE=0 // doctest fails at runtime /// ``` +/// println!("stdout 1"); +/// eprintln!("stderr 1"); +/// println!("stdout 2"); +/// eprintln!("stderr 2"); /// panic!("oh no"); /// ``` pub struct SomeStruct; diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout index 895c40e4cab26..e362ecf349e45 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.stdout +++ b/src/test/rustdoc-ui/failed-doctest-output.stdout @@ -1,32 +1,39 @@ running 2 tests -test $DIR/failed-doctest-output.rs - OtherStruct (line 17) ... FAILED -test $DIR/failed-doctest-output.rs - SomeStruct (line 11) ... FAILED +test $DIR/failed-doctest-output.rs - OtherStruct (line 20) ... FAILED +test $DIR/failed-doctest-output.rs - SomeStruct (line 10) ... FAILED failures: ----- $DIR/failed-doctest-output.rs - OtherStruct (line 17) stdout ---- +---- $DIR/failed-doctest-output.rs - OtherStruct (line 20) stdout ---- error[E0425]: cannot find value `no` in this scope - --> $DIR/failed-doctest-output.rs:18:1 + --> $DIR/failed-doctest-output.rs:21:1 | 3 | no | ^^ not found in this scope -thread '$DIR/failed-doctest-output.rs - OtherStruct (line 17)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:352:13 -note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +error: aborting due to previous error ----- $DIR/failed-doctest-output.rs - SomeStruct (line 11) stdout ---- -thread '$DIR/failed-doctest-output.rs - SomeStruct (line 11)' panicked at 'test executable failed: +For more information about this error, try `rustc --explain E0425`. +Couldn't compile the test. +---- $DIR/failed-doctest-output.rs - SomeStruct (line 10) stdout ---- +Test executable failed (exit code 101). -thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:3:1 -note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +stdout: +stdout 1 +stdout 2 + +stderr: +stderr 1 +stderr 2 +thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:7:1 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. -', src/librustdoc/test.rs:373:17 failures: - $DIR/failed-doctest-output.rs - OtherStruct (line 17) - $DIR/failed-doctest-output.rs - SomeStruct (line 11) + $DIR/failed-doctest-output.rs - OtherStruct (line 20) + $DIR/failed-doctest-output.rs - SomeStruct (line 10) test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/src/test/rustdoc-ui/failed-doctest-should-panic.rs b/src/test/rustdoc-ui/failed-doctest-should-panic.rs new file mode 100644 index 0000000000000..400fb97804aab --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-should-panic.rs @@ -0,0 +1,11 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// failure-status: 101 + +/// ```should_panic +/// println!("Hello, world!"); +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/failed-doctest-should-panic.stdout b/src/test/rustdoc-ui/failed-doctest-should-panic.stdout new file mode 100644 index 0000000000000..081b64b50af9b --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-should-panic.stdout @@ -0,0 +1,14 @@ + +running 1 test +test $DIR/failed-doctest-should-panic.rs - Foo (line 8) ... FAILED + +failures: + +---- $DIR/failed-doctest-should-panic.rs - Foo (line 8) stdout ---- +Test executable succeeded, but it's marked `should_panic`. + +failures: + $DIR/failed-doctest-should-panic.rs - Foo (line 8) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr index ced56897e2a21..cebb14cba7c11 100644 --- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr @@ -1,7 +1,7 @@ error: `[TypeAlias::hoge]` cannot be resolved, ignoring it... --> $DIR/intra-doc-alias-ice.rs:5:30 | -LL | /// [broken cross-reference](TypeAlias::hoge) //~ ERROR +LL | /// [broken cross-reference](TypeAlias::hoge) | ^^^^^^^^^^^^^^^ cannot be resolved, ignoring | note: lint level defined here @@ -9,5 +9,7 @@ note: lint level defined here | LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + +error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.rs b/src/test/rustdoc-ui/intra-link-span-ice-55723.rs index 5891a553e3255..c7a13bbf606cb 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.rs +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.rs @@ -1,5 +1,3 @@ -// ignore-tidy-end-whitespace - #![deny(intra_doc_link_resolution_failure)] // An error in calculating spans while reporting intra-doc link resolution errors caused rustdoc to diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr index 4eb1861062872..79702a1a546b7 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr @@ -1,13 +1,15 @@ error: `[i]` cannot be resolved, ignoring it... - --> $DIR/intra-link-span-ice-55723.rs:11:10 + --> $DIR/intra-link-span-ice-55723.rs:9:10 | LL | /// (arr[i]) | ^ cannot be resolved, ignoring | note: lint level defined here - --> $DIR/intra-link-span-ice-55723.rs:3:9 + --> $DIR/intra-link-span-ice-55723.rs:1:9 | LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + +error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.rs b/src/test/rustdoc-ui/intra-links-ambiguity.rs new file mode 100644 index 0000000000000..7316fcdad6772 --- /dev/null +++ b/src/test/rustdoc-ui/intra-links-ambiguity.rs @@ -0,0 +1,36 @@ +#![deny(intra_doc_link_resolution_failure)] +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] + +pub fn ambiguous() {} + +pub struct ambiguous {} + +#[macro_export] +macro_rules! multi_conflict { () => {} } + +#[allow(non_camel_case_types)] +pub struct multi_conflict {} + +pub fn multi_conflict() {} + +pub mod type_and_value {} + +pub const type_and_value: i32 = 0; + +pub mod foo { + pub enum bar {} + + pub fn bar() {} +} + +/// [`ambiguous`] is ambiguous. //~ERROR `ambiguous` +/// +/// [ambiguous] is ambiguous. //~ERROR ambiguous +/// +/// [`multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` +/// +/// Ambiguous [type_and_value]. //~ERROR type_and_value +/// +/// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar` +pub struct Docs {} diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr new file mode 100644 index 0000000000000..5d66cc1364c5f --- /dev/null +++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr @@ -0,0 +1,82 @@ +error: `ambiguous` is both a struct and a function + --> $DIR/intra-links-ambiguity.rs:27:6 + | +LL | /// [`ambiguous`] is ambiguous. + | ^^^^^^^^^^^ ambiguous link + | +note: lint level defined here + --> $DIR/intra-links-ambiguity.rs:1:9 + | +LL | #![deny(intra_doc_link_resolution_failure)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the struct, prefix with the item type + | +LL | /// [`struct@ambiguous`] is ambiguous. + | ^^^^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// [`ambiguous()`] is ambiguous. + | ^^^^^^^^^^^^^ + +error: `ambiguous` is both a struct and a function + --> $DIR/intra-links-ambiguity.rs:29:6 + | +LL | /// [ambiguous] is ambiguous. + | ^^^^^^^^^ ambiguous link +help: to link to the struct, prefix with the item type + | +LL | /// [struct@ambiguous] is ambiguous. + | ^^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// [ambiguous()] is ambiguous. + | ^^^^^^^^^^^ + +error: `multi_conflict` is a struct, a function, and a macro + --> $DIR/intra-links-ambiguity.rs:31:6 + | +LL | /// [`multi_conflict`] is a three-way conflict. + | ^^^^^^^^^^^^^^^^ ambiguous link +help: to link to the struct, prefix with the item type + | +LL | /// [`struct@multi_conflict`] is a three-way conflict. + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// [`multi_conflict()`] is a three-way conflict. + | ^^^^^^^^^^^^^^^^^^ +help: to link to the macro, add an exclamation mark + | +LL | /// [`multi_conflict!`] is a three-way conflict. + | ^^^^^^^^^^^^^^^^^ + +error: `type_and_value` is both a module and a constant + --> $DIR/intra-links-ambiguity.rs:33:16 + | +LL | /// Ambiguous [type_and_value]. + | ^^^^^^^^^^^^^^ ambiguous link +help: to link to the module, prefix with the item type + | +LL | /// Ambiguous [module@type_and_value]. + | ^^^^^^^^^^^^^^^^^^^^^ +help: to link to the constant, prefix with the item type + | +LL | /// Ambiguous [const@type_and_value]. + | ^^^^^^^^^^^^^^^^^^^^ + +error: `foo::bar` is both an enum and a function + --> $DIR/intra-links-ambiguity.rs:35:42 + | +LL | /// Ambiguous non-implied shortcut link [`foo::bar`]. + | ^^^^^^^^^^ ambiguous link +help: to link to the enum, prefix with the item type + | +LL | /// Ambiguous non-implied shortcut link [`enum@foo::bar`]. + | ^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// Ambiguous non-implied shortcut link [`foo::bar()`]. + | ^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr index 62537f2ce2dc9..8ccc04a4c0bcd 100644 --- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr +++ b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr @@ -5,7 +5,7 @@ LL | /// [error] | ^^^^^ cannot be resolved, ignoring | = note: #[warn(intra_doc_link_resolution_failure)] on by default - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[error1]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning-crlf.rs:12:11 @@ -13,7 +13,7 @@ warning: `[error1]` cannot be resolved, ignoring it... LL | /// docs [error1] | ^^^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[error2]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning-crlf.rs:14:11 @@ -21,7 +21,7 @@ warning: `[error2]` cannot be resolved, ignoring it... LL | /// docs [error2] | ^^^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[error]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning-crlf.rs:21:20 @@ -29,5 +29,5 @@ warning: `[error]` cannot be resolved, ignoring it... LL | * It also has an [error]. | ^^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index 60fc131dbda17..1eec3c57b68de 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -5,7 +5,7 @@ LL | //! Test with [Foo::baz], [Bar::foo], ... | ^^^^^^^^ cannot be resolved, ignoring | = note: #[warn(intra_doc_link_resolution_failure)] on by default - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[Bar::foo]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:3:35 @@ -13,7 +13,7 @@ warning: `[Bar::foo]` cannot be resolved, ignoring it... LL | //! Test with [Foo::baz], [Bar::foo], ... | ^^^^^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[Uniooon::X]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:4:13 @@ -21,7 +21,7 @@ warning: `[Uniooon::X]` cannot be resolved, ignoring it... LL | //! , [Uniooon::X] and [Qux::Z]. | ^^^^^^^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[Qux::Z]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:4:30 @@ -29,7 +29,7 @@ warning: `[Qux::Z]` cannot be resolved, ignoring it... LL | //! , [Uniooon::X] and [Qux::Z]. | ^^^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[Uniooon::X]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:6:14 @@ -37,7 +37,7 @@ warning: `[Uniooon::X]` cannot be resolved, ignoring it... LL | //! , [Uniooon::X] and [Qux::Z]. | ^^^^^^^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[Qux::Z]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:6:31 @@ -45,7 +45,7 @@ warning: `[Qux::Z]` cannot be resolved, ignoring it... LL | //! , [Uniooon::X] and [Qux::Z]. | ^^^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[Qux:Y]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:8:13 @@ -53,7 +53,7 @@ warning: `[Qux:Y]` cannot be resolved, ignoring it... LL | /// [Qux:Y] | ^^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[error]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:51:30 @@ -61,7 +61,7 @@ warning: `[error]` cannot be resolved, ignoring it... LL | * time to introduce a link [error]*/ | ^^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[error]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:57:30 @@ -69,7 +69,7 @@ warning: `[error]` cannot be resolved, ignoring it... LL | * time to introduce a link [error] | ^^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[error]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:61:1 @@ -81,19 +81,19 @@ LL | #[doc = "single line [error]"] single line [error] ^^^^^ - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[error]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:64:1 | -LL | #[doc = "single line with /"escaping/" [error]"] +LL | #[doc = "single line with \"escaping\" [error]"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the link appears in this line: single line with "escaping" [error] ^^^^^ - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[error]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:67:1 @@ -107,7 +107,7 @@ LL | | /// [error] [error] ^^^^^ - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[error1]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:73:11 @@ -115,7 +115,7 @@ warning: `[error1]` cannot be resolved, ignoring it... LL | /// docs [error1] | ^^^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[error2]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:75:11 @@ -123,7 +123,7 @@ warning: `[error2]` cannot be resolved, ignoring it... LL | /// docs [error2] | ^^^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[BarA]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:14:10 @@ -131,7 +131,7 @@ warning: `[BarA]` cannot be resolved, ignoring it... LL | /// bar [BarA] bar | ^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[BarB]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:20:9 @@ -139,7 +139,7 @@ warning: `[BarB]` cannot be resolved, ignoring it... LL | * bar [BarB] bar | ^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[BarC]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:27:6 @@ -147,19 +147,19 @@ warning: `[BarC]` cannot be resolved, ignoring it... LL | bar [BarC] bar | ^^^^ cannot be resolved, ignoring | - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[BarD]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:38:1 | -LL | #[doc = "Foo/nbar [BarD] bar/nbaz"] +LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the link appears in this line: bar [BarD] bar ^^^^ - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` warning: `[BarF]` cannot be resolved, ignoring it... --> $DIR/intra-links-warning.rs:43:9 @@ -167,12 +167,12 @@ warning: `[BarF]` cannot be resolved, ignoring it... LL | #[doc = $f] | ^^^^^^^^^^^ ... -LL | f!("Foo/nbar [BarF] bar/nbaz"); +LL | f!("Foo\nbar [BarF] bar\nbaz"); | ------------------------------- in this macro invocation | = note: the link appears in this line: bar [BarF] bar ^^^^ - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr index 10800380a05d3..b4ed747b44c81 100644 --- a/src/test/rustdoc-ui/invalid-syntax.stderr +++ b/src/test/rustdoc-ui/invalid-syntax.stderr @@ -3,11 +3,11 @@ warning: could not parse code block as Rust code | LL | /// ``` | _____^ -LL | | /// /__________pkt->size___________/ /_result->size_/ /__pkt->size__/ +LL | | /// \__________pkt->size___________/ \_result->size_/ \__pkt->size__/ LL | | /// ``` | |_______^ | - = note: error from rustc: unknown start of token: / + = note: error from rustc: unknown start of token: \ help: mark blocks that do not contain Rust code as text | LL | /// ```text @@ -35,11 +35,11 @@ warning: could not parse code block as Rust code | LL | /// ``` | _____^ -LL | | /// /_ +LL | | /// \_ LL | | /// ``` | |_______^ | - = note: error from rustc: unknown start of token: / + = note: error from rustc: unknown start of token: \ help: mark blocks that do not contain Rust code as text | LL | /// ```text @@ -50,21 +50,21 @@ warning: could not parse code block as Rust code | LL | /// ```rust | _____^ -LL | | /// /_ +LL | | /// \_ LL | | /// ``` | |_______^ | - = note: error from rustc: unknown start of token: / + = note: error from rustc: unknown start of token: \ warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:41:9 | LL | /// code with bad syntax | _________^ -LL | | /// /_ +LL | | /// \_ | |__________^ | - = note: error from rustc: unknown start of token: / + = note: error from rustc: unknown start of token: \ warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:55:9 @@ -79,17 +79,17 @@ warning: could not parse code block as Rust code | LL | /// ```edition2018 | _____^ -LL | | /// /_ +LL | | /// \_ LL | | /// ``` | |_______^ | - = note: error from rustc: unknown start of token: / + = note: error from rustc: unknown start of token: \ warning: doc comment contains an invalid Rust code block --> $DIR/invalid-syntax.rs:63:1 | LL | / #[doc = "```"] -LL | | /// /_ +LL | | /// \_ LL | | #[doc = "```"] | |______________^ | diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr index 48ae7910b0f15..24db3453ec509 100644 --- a/src/test/rustdoc-ui/lint-group.stderr +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -27,7 +27,7 @@ note: lint level defined here LL | #![deny(rustdoc)] | ^^^^^^^ = note: #[deny(intra_doc_link_resolution_failure)] implied by #[deny(rustdoc)] - = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` error: Missing code example in this documentation --> $DIR/lint-group.rs:16:1 @@ -42,3 +42,5 @@ LL | #![deny(rustdoc)] | ^^^^^^^ = note: #[deny(missing_doc_code_examples)] implied by #[deny(rustdoc)] +error: aborting due to 3 previous errors + diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs new file mode 100644 index 0000000000000..ffe0ddcd8c9b2 --- /dev/null +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs @@ -0,0 +1,40 @@ +#![deny(missing_docs)] +#![deny(missing_doc_code_examples)] + +//! crate level doc +//! ``` +//! println!("hello"): +//! ``` + + +/// doc +/// +/// ``` +/// println!("hello"); +/// ``` +fn test() { +} + +#[allow(missing_docs)] +mod module1 { //~ ERROR +} + +#[allow(missing_doc_code_examples)] +/// doc +mod module2 { + + /// doc + pub fn test() {} +} + +/// doc +/// +/// ``` +/// println!("hello"); +/// ``` +pub mod module3 { + + /// doc + //~^ ERROR + pub fn test() {} +} diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr new file mode 100644 index 0000000000000..97a52a13e3f65 --- /dev/null +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr @@ -0,0 +1,21 @@ +error: Missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:19:1 + | +LL | / mod module1 { +LL | | } + | |_^ + | +note: lint level defined here + --> $DIR/lint-missing-doc-code-example.rs:2:9 + | +LL | #![deny(missing_doc_code_examples)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:37:3 + | +LL | /// doc + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/rustdoc-ui/private-item-doc-test.stderr b/src/test/rustdoc-ui/private-item-doc-test.stderr index 38062758e92c7..20f3eb8b12025 100644 --- a/src/test/rustdoc-ui/private-item-doc-test.stderr +++ b/src/test/rustdoc-ui/private-item-doc-test.stderr @@ -14,3 +14,5 @@ note: lint level defined here LL | #![deny(private_doc_tests)] | ^^^^^^^^^^^^^^^^^ +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/unparseable-doc-test.rs b/src/test/rustdoc-ui/unparseable-doc-test.rs new file mode 100644 index 0000000000000..18d6b32bf4037 --- /dev/null +++ b/src/test/rustdoc-ui/unparseable-doc-test.rs @@ -0,0 +1,10 @@ +// compile-flags: --test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// failure-status: 101 +// rustc-env: RUST_BACKTRACE=0 + +/// ```rust +/// let x = 7; +/// "unterminated +/// ``` +pub fn foo() {} diff --git a/src/test/rustdoc-ui/unparseable-doc-test.stdout b/src/test/rustdoc-ui/unparseable-doc-test.stdout new file mode 100644 index 0000000000000..0350c01643607 --- /dev/null +++ b/src/test/rustdoc-ui/unparseable-doc-test.stdout @@ -0,0 +1,22 @@ + +running 1 test +test $DIR/unparseable-doc-test.rs - foo (line 6) ... FAILED + +failures: + +---- $DIR/unparseable-doc-test.rs - foo (line 6) stdout ---- +error: unterminated double quote string + --> $DIR/unparseable-doc-test.rs:8:1 + | +2 | "unterminated + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +Couldn't compile the test. + +failures: + $DIR/unparseable-doc-test.rs - foo (line 6) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/test/rustdoc/assoc-consts-version.rs b/src/test/rustdoc/assoc-consts-version.rs index c561269cf9a85..6060bc0a6fd5c 100644 --- a/src/test/rustdoc/assoc-consts-version.rs +++ b/src/test/rustdoc/assoc-consts-version.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - #![crate_name = "foo"] #![feature(staged_api)] @@ -10,7 +8,8 @@ pub struct SomeStruct; impl SomeStruct { - // @has 'foo/struct.SomeStruct.html' '//*[@id="associatedconstant.SOME_CONST"]//div[@class="since"]' '1.1.2' + // @has 'foo/struct.SomeStruct.html' \ + // '//*[@id="associatedconstant.SOME_CONST"]//span[@class="since"]' '1.1.2' #[stable(since="1.1.2", feature="rust2")] pub const SOME_CONST: usize = 0; } diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs index ba4997a7f9b5b..7384f7027d185 100644 --- a/src/test/rustdoc/async-fn.rs +++ b/src/test/rustdoc/async-fn.rs @@ -1,6 +1,6 @@ // edition:2018 -#![feature(async_await, futures_api)] +#![feature(async_await)] // @has async_fn/fn.foo.html '//pre[@class="rust fn"]' 'pub async fn foo() -> Option' pub async fn foo() -> Option { diff --git a/src/test/rustdoc/async-move-doctest.rs b/src/test/rustdoc/async-move-doctest.rs new file mode 100644 index 0000000000000..42723132782ca --- /dev/null +++ b/src/test/rustdoc/async-move-doctest.rs @@ -0,0 +1,14 @@ +// compile-flags:--test +// edition:2018 + +// prior to setting the default edition for the doctest pre-parser, this doctest would fail due to +// a fatal parsing error +// see https://github.com/rust-lang/rust/issues/59313 + +//! ``` +//! #![feature(async_await)] +//! +//! fn foo() { +//! drop(async move {}); +//! } +//! ``` diff --git a/src/test/rustdoc/attributes.rs b/src/test/rustdoc/attributes.rs index eb0e3f065c7b3..6ecdad3ec0000 100644 --- a/src/test/rustdoc/attributes.rs +++ b/src/test/rustdoc/attributes.rs @@ -8,8 +8,8 @@ pub extern "C" fn f() {} #[export_name = "bar"] pub extern "C" fn g() {} -// @has foo/enum.Foo.html '//*[@class="docblock attributes"]' '#[repr(i64)]' -// @has foo/enum.Foo.html '//*[@class="docblock attributes"]' '#[must_use]' +// @has foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' '#[repr(i64)]' +// @has foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' '#[must_use]' #[repr(i64)] #[must_use] pub enum Foo { diff --git a/src/test/rustdoc/auxiliary/enum_primitive.rs b/src/test/rustdoc/auxiliary/enum-primitive.rs similarity index 100% rename from src/test/rustdoc/auxiliary/enum_primitive.rs rename to src/test/rustdoc/auxiliary/enum-primitive.rs diff --git a/src/test/rustdoc/auxiliary/intra-links-external-traits.rs b/src/test/rustdoc/auxiliary/intra-links-external-traits.rs new file mode 100644 index 0000000000000..6142dcda986cf --- /dev/null +++ b/src/test/rustdoc/auxiliary/intra-links-external-traits.rs @@ -0,0 +1,6 @@ +pub trait ThisTrait { + fn asdf(&self); + + /// let's link to [`asdf`](ThisTrait::asdf) + fn qwop(&self); +} diff --git a/src/test/rustdoc/auxiliary/issue-23207-2.rs b/src/test/rustdoc/auxiliary/issue-23207-2.rs index e1afb68dc7921..b92b16653167b 100644 --- a/src/test/rustdoc/auxiliary/issue-23207-2.rs +++ b/src/test/rustdoc/auxiliary/issue-23207-2.rs @@ -3,4 +3,3 @@ extern crate issue_23207_1; pub mod fmt { pub use issue_23207_1::fmt::Error; } - diff --git a/src/test/rustdoc/auxiliary/reexp_stripped.rs b/src/test/rustdoc/auxiliary/reexp-stripped.rs similarity index 100% rename from src/test/rustdoc/auxiliary/reexp_stripped.rs rename to src/test/rustdoc/auxiliary/reexp-stripped.rs diff --git a/src/test/rustdoc/blanket-reexport-item.rs b/src/test/rustdoc/blanket-reexport-item.rs index a1db90d7606d9..f247ee637b975 100644 --- a/src/test/rustdoc/blanket-reexport-item.rs +++ b/src/test/rustdoc/blanket-reexport-item.rs @@ -1,6 +1,6 @@ #![crate_name = "foo"] -// @has foo/struct.S.html '//h3[@id="impl-Into"]//code' 'impl Into for T' +// @has foo/struct.S.html '//h3[@id="impl-Into%3CU%3E"]//code' 'impl Into for T' pub struct S2 {} mod m { pub struct S {} diff --git a/src/test/rustdoc/const-generics/add-impl.rs b/src/test/rustdoc/const-generics/add-impl.rs new file mode 100644 index 0000000000000..ed45d339728bc --- /dev/null +++ b/src/test/rustdoc/const-generics/add-impl.rs @@ -0,0 +1,21 @@ +// ignore-tidy-linelength + +#![feature(const_generics)] + +#![crate_name = "foo"] + +use std::ops::Add; + +// @has foo/struct.Simd.html '//pre[@class="rust struct"]' 'pub struct Simd' +pub struct Simd { + inner: T, +} + +// @has foo/struct.Simd.html '//div[@id="implementations-list"]/h3/code' 'impl Add> for Simd' +impl Add for Simd { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self { inner: 0 } + } +} diff --git a/src/test/rustdoc/const-generics/const-generic-slice.rs b/src/test/rustdoc/const-generics/const-generic-slice.rs new file mode 100644 index 0000000000000..60d96770f7eae --- /dev/null +++ b/src/test/rustdoc/const-generics/const-generic-slice.rs @@ -0,0 +1,12 @@ +#![crate_name = "foo"] +#![feature(const_generics)] + +pub trait Array { + type Item; +} + +// @has foo/trait.Array.html +// @has - '//h3[@class="impl"]' 'impl Array for [T; N]' +impl Array for [T; N] { + type Item = T; +} diff --git a/src/test/rustdoc/const-generics/const-impl.rs b/src/test/rustdoc/const-generics/const-impl.rs new file mode 100644 index 0000000000000..85ee6d3376b27 --- /dev/null +++ b/src/test/rustdoc/const-generics/const-impl.rs @@ -0,0 +1,31 @@ +// ignore-tidy-linelength + +#![feature(const_generics)] + +#![crate_name = "foo"] + +pub enum Order { + Sorted, + Unsorted, +} + +// @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet' +// @has foo/struct.VSet.html '//h3[@id="impl-Send"]/code' 'impl Send for VSet' +// @has foo/struct.VSet.html '//h3[@id="impl-Sync"]/code' 'impl Sync for VSet' +pub struct VSet { + inner: Vec, +} + +// @has foo/struct.VSet.html '//h3[@id="impl"]/code' 'impl VSet' +impl VSet { + pub fn new() -> Self { + Self { inner: Vec::new() } + } +} + +// @has foo/struct.VSet.html '//h3[@id="impl-1"]/code' 'impl VSet' +impl VSet { + pub fn new() -> Self { + Self { inner: Vec::new() } + } +} diff --git a/src/test/rustdoc/deep-structures.rs b/src/test/rustdoc/deep-structures.rs new file mode 100644 index 0000000000000..cd3b0d3ec9706 --- /dev/null +++ b/src/test/rustdoc/deep-structures.rs @@ -0,0 +1,104 @@ +// This test verifies that we do not hit recursion limit trying to prove auto-trait bounds for +// reasonably deep structures. + +#![crate_type="rlib"] + +pub struct A01(A02); +pub struct A02(A03); +pub struct A03(A04); +pub struct A04(A05); +pub struct A05(A06); +pub struct A06(A07); +pub struct A07(A08); +pub struct A08(A09); +pub struct A09(A10); +pub struct A10(A11); +pub struct A11(A12); +pub struct A12(A13); +pub struct A13(A14); +pub struct A14(A15); +pub struct A15(A16); +pub struct A16(A17); +pub struct A17(A18); +pub struct A18(A19); +pub struct A19(A20); +pub struct A20(A21); +pub struct A21(A22); +pub struct A22(A23); +pub struct A23(A24); +pub struct A24(A25); +pub struct A25(A26); +pub struct A26(A27); +pub struct A27(A28); +pub struct A28(A29); +pub struct A29(A30); +pub struct A30(A31); +pub struct A31(A32); +pub struct A32(A33); +pub struct A33(A34); +pub struct A34(A35); +pub struct A35(A36); +pub struct A36(A37); +pub struct A37(A38); +pub struct A38(A39); +pub struct A39(A40); +pub struct A40(A41); +pub struct A41(A42); +pub struct A42(A43); +pub struct A43(A44); +pub struct A44(A45); +pub struct A45(A46); +pub struct A46(A47); +pub struct A47(A48); +pub struct A48(A49); +pub struct A49(A50); +pub struct A50(A51); +pub struct A51(A52); +pub struct A52(A53); +pub struct A53(A54); +pub struct A54(A55); +pub struct A55(A56); +pub struct A56(A57); +pub struct A57(A58); +pub struct A58(A59); +pub struct A59(A60); +pub struct A60(A61); +pub struct A61(A62); +pub struct A62(A63); +pub struct A63(A64); +pub struct A64(A65); +pub struct A65(A66); +pub struct A66(A67); +pub struct A67(A68); +pub struct A68(A69); +pub struct A69(A70); +pub struct A70(A71); +pub struct A71(A72); +pub struct A72(A73); +pub struct A73(A74); +pub struct A74(A75); +pub struct A75(A76); +pub struct A76(A77); +pub struct A77(A78); +pub struct A78(A79); +pub struct A79(A80); +pub struct A80(A81); +pub struct A81(A82); +pub struct A82(A83); +pub struct A83(A84); +pub struct A84(A85); +pub struct A85(A86); +pub struct A86(A87); +pub struct A87(A88); +pub struct A88(A89); +pub struct A89(A90); +pub struct A90(A91); +pub struct A91(A92); +pub struct A92(A93); +pub struct A93(A94); +pub struct A94(A95); +pub struct A95(A96); +pub struct A96(A97); +pub struct A97(A98); +pub struct A98(A99); +pub struct A99; diff --git a/src/test/rustdoc/default-trait-method.rs b/src/test/rustdoc/default-trait-method.rs new file mode 100644 index 0000000000000..3d6ebef5a1d5b --- /dev/null +++ b/src/test/rustdoc/default-trait-method.rs @@ -0,0 +1,26 @@ +#![feature(specialization)] + +// @has default_trait_method/trait.Item.html +// @has - '//*[@id="tymethod.foo"]' 'fn foo()' +// @!has - '//*[@id="tymethod.foo"]' 'default fn foo()' +// @has - '//*[@id="tymethod.bar"]' 'fn bar()' +// @!has - '//*[@id="tymethod.bar"]' 'default fn bar()' +// @has - '//*[@id="method.baz"]' 'fn baz()' +// @!has - '//*[@id="method.baz"]' 'default fn baz()' +pub trait Item { + fn foo(); + fn bar(); + fn baz() {} +} + +// @has default_trait_method/struct.Foo.html +// @has - '//*[@id="method.foo"]' 'default fn foo()' +// @has - '//*[@id="method.bar"]' 'fn bar()' +// @!has - '//*[@id="method.bar"]' 'default fn bar()' +// @has - '//*[@id="method.baz"]' 'fn baz()' +// @!has - '//*[@id="method.baz"]' 'default fn baz()' +pub struct Foo; +impl Item for Foo { + default fn foo() {} + fn bar() {} +} diff --git a/src/test/rustdoc/empty-mod-private.rs b/src/test/rustdoc/empty-mod-private.rs index 12576a1b535f7..c2a98049a48cb 100644 --- a/src/test/rustdoc/empty-mod-private.rs +++ b/src/test/rustdoc/empty-mod-private.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // compile-flags: --document-private-items // @has 'empty_mod_private/index.html' '//a[@href="foo/index.html"]' 'foo' diff --git a/src/test/rustdoc/empty-section.rs b/src/test/rustdoc/empty-section.rs index 619f2d688a1b0..d95f3a80365cd 100644 --- a/src/test/rustdoc/empty-section.rs +++ b/src/test/rustdoc/empty-section.rs @@ -8,3 +8,6 @@ pub struct Foo; // @!has - 'Auto Trait Implementations' impl !Send for Foo {} impl !Sync for Foo {} +impl !std::marker::Unpin for Foo {} +impl !std::panic::RefUnwindSafe for Foo {} +impl !std::panic::UnwindSafe for Foo {} diff --git a/src/test/rustdoc/extern-html-root-url.rs b/src/test/rustdoc/extern-html-root-url.rs index 674d0305f2eae..60b7b28ae4acf 100644 --- a/src/test/rustdoc/extern-html-root-url.rs +++ b/src/test/rustdoc/extern-html-root-url.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - // compile-flags:-Z unstable-options --extern-html-root-url core=https://example.com/core/0.1.0 // @has extern_html_root_url/index.html diff --git a/src/test/rustdoc/index-page.rs b/src/test/rustdoc/index-page.rs index 6998e73529727..f0476f083b8a1 100644 --- a/src/test/rustdoc/index-page.rs +++ b/src/test/rustdoc/index-page.rs @@ -1,3 +1,5 @@ +// aux-build:all-item-types.rs +// build-aux-docs // compile-flags: -Z unstable-options --enable-index-page #![crate_name = "foo"] @@ -5,4 +7,5 @@ // @has foo/../index.html // @has - '//span[@class="in-band"]' 'List of all crates' // @has - '//ul[@class="mod"]//a[@href="foo/index.html"]' 'foo' +// @has - '//ul[@class="mod"]//a[@href="all_item_types/index.html"]' 'all_item_types' pub struct Foo; diff --git a/src/test/rustdoc/inline_cross/auxiliary/default-trait-method.rs b/src/test/rustdoc/inline_cross/auxiliary/default-trait-method.rs new file mode 100644 index 0000000000000..ce60bbfb4b0de --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/default-trait-method.rs @@ -0,0 +1,16 @@ +#![feature(specialization)] + +#![crate_name = "foo"] + +pub trait Item { + fn foo(); + fn bar(); + fn baz() {} +} + +pub struct Foo; + +impl Item for Foo { + default fn foo() {} + fn bar() {} +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs index 9836b6ba2edfd..c99ef74433358 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs @@ -25,4 +25,3 @@ pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream { pub fn some_derive(_item: TokenStream) -> TokenStream { TokenStream::new() } - diff --git a/src/test/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs index 76913f02cfd82..11d8733c40d12 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs @@ -11,4 +11,3 @@ impl<'a> fmt::Debug for Bar + 'a { Ok(()) } } - diff --git a/src/test/rustdoc/inline_cross/default-trait-method.rs b/src/test/rustdoc/inline_cross/default-trait-method.rs new file mode 100644 index 0000000000000..a4ec73a127d4e --- /dev/null +++ b/src/test/rustdoc/inline_cross/default-trait-method.rs @@ -0,0 +1,20 @@ +// aux-build:default-trait-method.rs + +extern crate foo; + +// @has default_trait_method/trait.Item.html +// @has - '//*[@id="tymethod.foo"]' 'fn foo()' +// @!has - '//*[@id="tymethod.foo"]' 'default fn foo()' +// @has - '//*[@id="tymethod.bar"]' 'fn bar()' +// @!has - '//*[@id="tymethod.bar"]' 'default fn bar()' +// @has - '//*[@id="method.baz"]' 'fn baz()' +// @!has - '//*[@id="method.baz"]' 'default fn baz()' +pub use foo::Item; + +// @has default_trait_method/struct.Foo.html +// @has - '//*[@id="method.foo"]' 'default fn foo()' +// @has - '//*[@id="method.bar"]' 'fn bar()' +// @!has - '//*[@id="method.bar"]' 'default fn bar()' +// @has - '//*[@id="method.baz"]' 'fn baz()' +// @!has - '//*[@id="method.baz"]' 'default fn baz()' +pub use foo::Foo; diff --git a/src/test/rustdoc/inline_cross/issue-32881.rs b/src/test/rustdoc/inline_cross/issue-32881.rs index f783837d06054..5f31e6cd3ad1f 100644 --- a/src/test/rustdoc/inline_cross/issue-32881.rs +++ b/src/test/rustdoc/inline_cross/issue-32881.rs @@ -9,4 +9,3 @@ extern crate rustdoc_trait_object_impl; // @has - '//code' "impl<'a> Debug for dyn Bar" pub use rustdoc_trait_object_impl::Bar; - diff --git a/src/test/rustdoc/intra-link-libstd-re-export.rs b/src/test/rustdoc/intra-link-libstd-re-export.rs new file mode 100644 index 0000000000000..6f239292ec200 --- /dev/null +++ b/src/test/rustdoc/intra-link-libstd-re-export.rs @@ -0,0 +1,3 @@ +#![deny(intra_doc_link_resolution_failure)] + +pub use std::*; diff --git a/src/test/rustdoc/intra-links-external-traits.rs b/src/test/rustdoc/intra-links-external-traits.rs new file mode 100644 index 0000000000000..d6b4a8ad58ad7 --- /dev/null +++ b/src/test/rustdoc/intra-links-external-traits.rs @@ -0,0 +1,12 @@ +// aux-build:intra-links-external-traits.rs +// ignore-cross-compile + +#![crate_name = "outer"] +#![deny(intra_doc_link_resolution_failure)] + +// using a trait that has intra-doc links on it from another crate (whether re-exporting or just +// implementing it) used to give spurious resolution failure warnings + +extern crate intra_links_external_traits; + +pub use intra_links_external_traits::ThisTrait; diff --git a/src/test/rustdoc/intra-links.rs b/src/test/rustdoc/intra-links.rs index 9139fc51b092e..c356ab3a8ac52 100644 --- a/src/test/rustdoc/intra-links.rs +++ b/src/test/rustdoc/intra-links.rs @@ -22,6 +22,7 @@ //! * [`ThisType::this_method`](ThisType::this_method) //! * [`ThisEnum`](ThisEnum) //! * [`ThisEnum::ThisVariant`](ThisEnum::ThisVariant) +//! * [`ThisEnum::ThisVariantCtor`](ThisEnum::ThisVariantCtor) //! * [`ThisTrait`](ThisTrait) //! * [`ThisTrait::this_associated_method`](ThisTrait::this_associated_method) //! * [`ThisTrait::ThisAssociatedType`](ThisTrait::ThisAssociatedType) @@ -50,7 +51,7 @@ pub struct ThisType; impl ThisType { pub fn this_method() {} } -pub enum ThisEnum { ThisVariant, } +pub enum ThisEnum { ThisVariant, ThisVariantCtor(u32), } pub trait ThisTrait { type ThisAssociatedType; const THIS_ASSOCIATED_CONST: u8; diff --git a/src/test/rustdoc/issue-15318-2.rs b/src/test/rustdoc/issue-15318-2.rs index 1dbfba988efee..2af811ad5bbe8 100644 --- a/src/test/rustdoc/issue-15318-2.rs +++ b/src/test/rustdoc/issue-15318-2.rs @@ -9,4 +9,3 @@ pub use issue_15318::ptr; // '//*[@href="primitive.pointer.html"]' \ // '*mut T' pub fn bar(ptr: *mut T) {} - diff --git a/src/test/rustdoc/issue-19190-3.rs b/src/test/rustdoc/issue-19190-3.rs index f7366302a1e67..4d34ce6509fe3 100644 --- a/src/test/rustdoc/issue-19190-3.rs +++ b/src/test/rustdoc/issue-19190-3.rs @@ -25,4 +25,3 @@ impl Deref for MyBar { type Target = Baz; fn deref(&self) -> &Baz { loop {} } } - diff --git a/src/test/rustdoc/issue-20727-2.rs b/src/test/rustdoc/issue-20727-2.rs index 7c8b82fbe2114..022ff290e1a71 100644 --- a/src/test/rustdoc/issue-20727-2.rs +++ b/src/test/rustdoc/issue-20727-2.rs @@ -20,4 +20,3 @@ pub mod reexport { // @has - '//*[@class="rust trait"]' 'fn add(self, rhs: RHS) -> Self::Output;' pub use issue_20727::Add; } - diff --git a/src/test/rustdoc/issue-23207.rs b/src/test/rustdoc/issue-23207.rs index 747c59bba6aa5..1a4b849ee8209 100644 --- a/src/test/rustdoc/issue-23207.rs +++ b/src/test/rustdoc/issue-23207.rs @@ -7,4 +7,3 @@ extern crate issue_23207_2; // @has issue_23207/fmt/index.html // @count - '//*[@class="struct"]' 1 pub use issue_23207_2::fmt; - diff --git a/src/test/rustdoc/issue-34473.rs b/src/test/rustdoc/issue-34473.rs index 3f824e6404431..d96301f3ae736 100644 --- a/src/test/rustdoc/issue-34473.rs +++ b/src/test/rustdoc/issue-34473.rs @@ -7,6 +7,5 @@ mod second { // @has foo/index.html // @!has - SomeTypeWithLongName // @has foo/struct.SomeType.html -// @!has - SomeTypeWithLongName // @!has foo/struct.SomeTypeWithLongName.html pub use second::{SomeTypeWithLongName as SomeType}; diff --git a/src/test/rustdoc/issue-38129.rs b/src/test/rustdoc/issue-38129.rs index bf9d5e433046b..156d50fa52a64 100644 --- a/src/test/rustdoc/issue-38129.rs +++ b/src/test/rustdoc/issue-38129.rs @@ -97,4 +97,3 @@ pub fn both_attrs() {} /// assert_eq!(1 + 1, 2); /// ``` pub fn both_attrs_reverse() {} - diff --git a/src/test/rustdoc/issue-50159.rs b/src/test/rustdoc/issue-50159.rs index d175c82ec87be..74502be622a4f 100644 --- a/src/test/rustdoc/issue-50159.rs +++ b/src/test/rustdoc/issue-50159.rs @@ -14,7 +14,7 @@ impl Signal2 for B where B: Signal { // @has - '//code' 'impl Send for Switch where ::Item: Send' // @has - '//code' 'impl Sync for Switch where ::Item: Sync' // @count - '//*[@id="implementations-list"]/*[@class="impl"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 2 +// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 5 pub struct Switch { pub inner: ::Item2, } diff --git a/src/test/rustdoc/issue-56701.rs b/src/test/rustdoc/issue-56701.rs index 6fb30a4ff4c30..ba00743fcd12e 100644 --- a/src/test/rustdoc/issue-56701.rs +++ b/src/test/rustdoc/issue-56701.rs @@ -31,4 +31,3 @@ impl>> Deref for Unrelated(PhantomDataT>); + +impl InterfaceType for FooInterface { + type Send=False; +} + + +pub struct DynTrait{ + _interface:PhantomDataI>, + _unsync_unsend:PhantomData<::std::rc::Rc<()>>, +} + +unsafe impl Send for DynTrait +where + I:InterfaceType +{} + +// @has issue_60726/struct.IntoIter.html +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl !Send for \ +// IntoIter" +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl !Sync for \ +// IntoIter" +pub struct IntoIter{ + hello:DynTrait>, +} diff --git a/src/test/rustdoc/method-list.rs b/src/test/rustdoc/method-list.rs index f84be3eb3f718..9f24e817fd3eb 100644 --- a/src/test/rustdoc/method-list.rs +++ b/src/test/rustdoc/method-list.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - #![crate_name = "foo"] // @has foo/struct.Foo.html diff --git a/src/test/rustdoc/no-stack-overflow-25295.rs b/src/test/rustdoc/no-stack-overflow-25295.rs index 7e5c0279031b9..dd79f1e4baaa0 100644 --- a/src/test/rustdoc/no-stack-overflow-25295.rs +++ b/src/test/rustdoc/no-stack-overflow-25295.rs @@ -1,5 +1,5 @@ -// ensure this code doesn't stack overflow -// aux-build:enum_primitive.rs +// Ensure this code doesn't stack overflow. +// aux-build:enum-primitive.rs #[macro_use] extern crate enum_primitive; @@ -33,4 +33,3 @@ enum_from_primitive! { Z1,Z2,Z3,Z4,Z5,Z6, } } - diff --git a/src/test/rustdoc/playground-arg.rs b/src/test/rustdoc/playground-arg.rs index fb1be7397e65d..018716ad45af3 100644 --- a/src/test/rustdoc/playground-arg.rs +++ b/src/test/rustdoc/playground-arg.rs @@ -11,4 +11,4 @@ pub fn dummy() {} // ensure that `extern crate foo;` was inserted into code snips automatically: -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D&edition=2015"]' "Run" diff --git a/src/test/rustdoc/playground.rs b/src/test/rustdoc/playground.rs index 1b76e6c885349..9971c7b4297a2 100644 --- a/src/test/rustdoc/playground.rs +++ b/src/test/rustdoc/playground.rs @@ -24,6 +24,6 @@ //! } //! ``` -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run" -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run" -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&version=nightly"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&version=nightly&edition=2015"]' "Run" diff --git a/src/test/rustdoc/pub-method.rs b/src/test/rustdoc/pub-method.rs index 01e5141fe2584..8e88b2b59015d 100644 --- a/src/test/rustdoc/pub-method.rs +++ b/src/test/rustdoc/pub-method.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // compile-flags: --document-private-items #![crate_name = "foo"] diff --git a/src/test/rustdoc/redirect.rs b/src/test/rustdoc/redirect.rs index 65c57ab65bee9..e3a14c7a74a00 100644 --- a/src/test/rustdoc/redirect.rs +++ b/src/test/rustdoc/redirect.rs @@ -1,4 +1,4 @@ -// aux-build:reexp_stripped.rs +// aux-build:reexp-stripped.rs // build-aux-docs // ignore-cross-compile diff --git a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs new file mode 100644 index 0000000000000..6219a2c3b9073 --- /dev/null +++ b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs @@ -0,0 +1,16 @@ +// issue #56018: "Implementations on Foreign Types" sidebar items should link to specific impls + +#![crate_name = "foo"] + +// @has foo/trait.Foo.html +// @has - '//*[@class="sidebar-title"][@href="#foreign-impls"]' 'Implementations on Foreign Types' +// @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types' +// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-u32"]' 'u32' +// @has - '//h3[@id="impl-Foo-for-u32"]//code' 'impl Foo for u32' +// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str" +// @has - '//h3[@id="impl-Foo-for-%26%27a%20str"]//code' "impl<'a> Foo for &'a str" +pub trait Foo {} + +impl Foo for u32 {} + +impl<'a> Foo for &'a str {} diff --git a/src/test/rustdoc/static-root-path.rs b/src/test/rustdoc/static-root-path.rs index 84b32f90c89a4..2f7c89c5f1e6b 100644 --- a/src/test/rustdoc/static-root-path.rs +++ b/src/test/rustdoc/static-root-path.rs @@ -12,3 +12,7 @@ pub struct SomeStruct; // @!matches - '"\.\./\.\./source-script\.js"' // @matches - '"\.\./\.\./source-files.js"' // @!matches - '"/cache/source-files\.js"' + +// @has settings.html +// @matches - '/cache/settings\.js' +// @!matches - '\./settings\.js' diff --git a/src/test/rustdoc/synthetic_auto/basic.rs b/src/test/rustdoc/synthetic_auto/basic.rs index d5f1269d08a4c..38de5316b6cf5 100644 --- a/src/test/rustdoc/synthetic_auto/basic.rs +++ b/src/test/rustdoc/synthetic_auto/basic.rs @@ -2,7 +2,7 @@ // @has - '//code' 'impl Send for Foo where T: Send' // @has - '//code' 'impl Sync for Foo where T: Sync' // @count - '//*[@id="implementations-list"]/*[@class="impl"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 2 +// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 5 pub struct Foo { field: T, } diff --git a/src/test/rustdoc/synthetic_auto/complex.rs b/src/test/rustdoc/synthetic_auto/complex.rs index 609cefc7115e2..80a717718c22b 100644 --- a/src/test/rustdoc/synthetic_auto/complex.rs +++ b/src/test/rustdoc/synthetic_auto/complex.rs @@ -21,7 +21,7 @@ mod foo { // @has complex/struct.NotOuter.html // @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'a, T, K: \ -// ?Sized> Send for NotOuter<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \ +// ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \ // -> &'b i8, T: MyTrait<'a>, >::MyItem: Copy, 'a: 'static" pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter}; diff --git a/src/test/rustdoc/synthetic_auto/crate-local.rs b/src/test/rustdoc/synthetic_auto/crate-local.rs new file mode 100644 index 0000000000000..341dd572f81c8 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/crate-local.rs @@ -0,0 +1,9 @@ +#![feature(optin_builtin_traits)] + +pub auto trait Banana {} + +// @has crate_local/struct.Peach.html +// @has - '//code' 'impl Banana for Peach' +// @has - '//code' 'impl Send for Peach' +// @has - '//code' 'impl Sync for Peach' +pub struct Peach; diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs index 413ba187f4556..458403462d64a 100644 --- a/src/test/rustdoc/synthetic_auto/manual.rs +++ b/src/test/rustdoc/synthetic_auto/manual.rs @@ -6,7 +6,7 @@ // 'impl Send for Foo' // // @count - '//*[@id="implementations-list"]/*[@class="impl"]' 1 -// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 1 +// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 4 pub struct Foo { field: T, } diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs index 7d15434afe6db..905aa20918bef 100644 --- a/src/test/rustdoc/synthetic_auto/self-referential.rs +++ b/src/test/rustdoc/synthetic_auto/self-referential.rs @@ -27,4 +27,3 @@ impl Pattern for Wrapper { // WriteAndThen where ::Value: Send" pub struct WriteAndThen(pub P1::Value,pub > as Pattern>::Value) where P1: Pattern; - diff --git a/src/test/rustdoc/trait-attributes.rs b/src/test/rustdoc/trait-attributes.rs index 971e6b554cca7..a6ee046edec8b 100644 --- a/src/test/rustdoc/trait-attributes.rs +++ b/src/test/rustdoc/trait-attributes.rs @@ -3,7 +3,7 @@ // ignore-tidy-linelength pub trait Foo { - // @has foo/trait.Foo.html '//h3[@id="tymethod.foo"]//div[@class="docblock attributes"]' '#[must_use]' + // @has foo/trait.Foo.html '//h3[@id="tymethod.foo"]//span[@class="docblock attributes"]' '#[must_use]' #[must_use] fn foo(); } @@ -12,11 +12,11 @@ pub trait Foo { pub struct Bar; impl Bar { - // @has foo/struct.Bar.html '//h4[@id="method.bar"]//div[@class="docblock attributes"]' '#[must_use]' + // @has foo/struct.Bar.html '//h4[@id="method.bar"]//span[@class="docblock attributes"]' '#[must_use]' #[must_use] pub fn bar() {} - // @has foo/struct.Bar.html '//h4[@id="method.bar2"]//div[@class="docblock attributes"]' '#[must_use]' + // @has foo/struct.Bar.html '//h4[@id="method.bar2"]//span[@class="docblock attributes"]' '#[must_use]' #[must_use] pub fn bar2() {} } diff --git a/src/test/rustdoc/useless_lifetime_bound.rs b/src/test/rustdoc/useless_lifetime_bound.rs new file mode 100644 index 0000000000000..f530d8a654f01 --- /dev/null +++ b/src/test/rustdoc/useless_lifetime_bound.rs @@ -0,0 +1,13 @@ +use std::marker::PhantomData; + +// @has useless_lifetime_bound/struct.Scope.html +// @!has - '//*[@class="rust struct"]' "'env: 'env" +pub struct Scope<'env> { + _marker: PhantomData<&'env mut &'env ()>, +} + +// @has useless_lifetime_bound/struct.Scope.html +// @!has - '//*[@class="rust struct"]' "T: 'a + 'a" +pub struct SomeStruct<'a, T: 'a> { + _marker: PhantomData<&'a T>, +} diff --git a/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs new file mode 100644 index 0000000000000..039124f31ff42 --- /dev/null +++ b/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs @@ -0,0 +1,21 @@ +// force-host + +#![feature(plugin_registrar)] +#![feature(rustc_private)] + +extern crate syntax; + +extern crate rustc; +extern crate rustc_plugin; + +use syntax::symbol::Symbol; +use syntax::feature_gate::AttributeType; +use rustc_plugin::Registry; + + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_attribute(Symbol::intern("foo"), AttributeType::Normal); + reg.register_attribute(Symbol::intern("bar"), AttributeType::CrateLevel); + reg.register_attribute(Symbol::intern("baz"), AttributeType::Whitelisted); +} diff --git a/src/test/ui-fulldeps/auxiliary/attr_plugin_test.rs b/src/test/ui-fulldeps/auxiliary/attr_plugin_test.rs deleted file mode 100644 index c83e7bdb9983e..0000000000000 --- a/src/test/ui-fulldeps/auxiliary/attr_plugin_test.rs +++ /dev/null @@ -1,21 +0,0 @@ -// force-host - -#![feature(plugin_registrar)] -#![feature(rustc_private)] - -extern crate syntax; - -extern crate rustc; -extern crate rustc_plugin; - -use syntax::feature_gate::AttributeType; -use rustc_plugin::Registry; - - - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_attribute("foo".to_owned(), AttributeType::Normal); - reg.register_attribute("bar".to_owned(), AttributeType::CrateLevel); - reg.register_attribute("baz".to_owned(), AttributeType::Whitelisted); -} diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs new file mode 100644 index 0000000000000..7656b15721ada --- /dev/null +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -0,0 +1,36 @@ +// force-host + +#![feature(plugin_registrar, rustc_private)] +#![feature(box_syntax)] + +#[macro_use] extern crate rustc; +extern crate rustc_plugin; +extern crate syntax; + +use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; +use rustc_plugin::Registry; +use rustc::hir; +use syntax::attr; +use syntax::symbol::Symbol; + +declare_lint! { + CRATE_NOT_OKAY, + Warn, + "crate not marked with #![crate_okay]" +} + +declare_lint_pass!(Pass => [CRATE_NOT_OKAY]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { + if !attr::contains_name(&krate.attrs, Symbol::intern("crate_okay")) { + cx.span_lint(CRATE_NOT_OKAY, krate.span, + "crate is not marked with #![crate_okay]"); + } + } +} + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_late_lint_pass(box Pass); +} diff --git a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs new file mode 100644 index 0000000000000..941fe25b14c70 --- /dev/null +++ b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs @@ -0,0 +1,35 @@ +// force-host + +#![feature(plugin_registrar)] +#![feature(box_syntax, rustc_private)] + +// Load rustc as a plugin to get macros. +#[macro_use] +extern crate rustc; +extern crate rustc_plugin; + +use rustc::hir; +use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; +use rustc_plugin::Registry; + +declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); + +declare_lint!(PLEASE_LINT, Warn, "Warn about items named 'pleaselintme'"); + +declare_lint_pass!(Pass => [TEST_LINT, PLEASE_LINT]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + match &*it.ident.as_str() { + "lintme" => cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"), + "pleaselintme" => cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'"), + _ => {} + } + } +} + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_late_lint_pass(box Pass); + reg.register_lint_group("lint_me", None, vec![TEST_LINT, PLEASE_LINT]); +} diff --git a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs new file mode 100644 index 0000000000000..0deb1bf091508 --- /dev/null +++ b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs @@ -0,0 +1,32 @@ +// force-host + +#![feature(plugin_registrar)] +#![feature(box_syntax, rustc_private)] + +extern crate syntax; + +// Load rustc as a plugin to get macros +#[macro_use] +extern crate rustc; +extern crate rustc_plugin; + +use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, + EarlyLintPassObject, LintArray}; +use rustc_plugin::Registry; +use syntax::ast; +declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); + +declare_lint_pass!(Pass => [TEST_LINT]); + +impl EarlyLintPass for Pass { + fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { + if it.ident.name.as_str() == "lintme" { + cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); + } + } +} + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_early_lint_pass(box Pass as EarlyLintPassObject); +} diff --git a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs new file mode 100644 index 0000000000000..64664377cd943 --- /dev/null +++ b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs @@ -0,0 +1,39 @@ +#![feature(plugin_registrar)] +#![feature(box_syntax, rustc_private)] + +extern crate syntax; + +// Load rustc as a plugin to get macros +#[macro_use] +extern crate rustc; +extern crate rustc_plugin; + +use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, + LintArray}; +use rustc_plugin::Registry; +use syntax::ast; +declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff"); +declare_tool_lint!( + /// Some docs + pub clippy::TEST_GROUP, + Warn, "Warn about other stuff" +); + +declare_lint_pass!(Pass => [TEST_LINT, TEST_GROUP]); + +impl EarlyLintPass for Pass { + fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { + if it.ident.name.as_str() == "lintme" { + cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); + } + if it.ident.name.as_str() == "lintmetoo" { + cx.span_lint(TEST_GROUP, it.span, "item is named 'lintmetoo'"); + } + } +} + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_early_lint_pass(box Pass); + reg.register_lint_group("clippy::group", Some("clippy_group"), vec![TEST_LINT, TEST_GROUP]); +} diff --git a/src/test/ui-fulldeps/auxiliary/lint_for_crate.rs b/src/test/ui-fulldeps/auxiliary/lint_for_crate.rs deleted file mode 100644 index 82aa28b26b648..0000000000000 --- a/src/test/ui-fulldeps/auxiliary/lint_for_crate.rs +++ /dev/null @@ -1,41 +0,0 @@ -// force-host - -#![feature(plugin_registrar, rustc_private)] -#![feature(box_syntax)] - -#[macro_use] extern crate rustc; -extern crate rustc_plugin; -extern crate syntax; - -use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; -use rustc_plugin::Registry; -use rustc::hir; -use syntax::attr; - -declare_lint!(CRATE_NOT_OKAY, Warn, "crate not marked with #![crate_okay]"); - -struct Pass; - -impl LintPass for Pass { - fn name(&self) -> &'static str { - "Pass" - } - - fn get_lints(&self) -> LintArray { - lint_array!(CRATE_NOT_OKAY) - } -} - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { - fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { - if !attr::contains_name(&krate.attrs, "crate_okay") { - cx.span_lint(CRATE_NOT_OKAY, krate.span, - "crate is not marked with #![crate_okay]"); - } - } -} - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_late_lint_pass(box Pass); -} diff --git a/src/test/ui-fulldeps/auxiliary/lint_group_plugin_test.rs b/src/test/ui-fulldeps/auxiliary/lint_group_plugin_test.rs deleted file mode 100644 index 16630e2b31285..0000000000000 --- a/src/test/ui-fulldeps/auxiliary/lint_group_plugin_test.rs +++ /dev/null @@ -1,45 +0,0 @@ -// force-host - -#![feature(plugin_registrar)] -#![feature(box_syntax, rustc_private)] - -// Load rustc as a plugin to get macros. -#[macro_use] -extern crate rustc; -extern crate rustc_plugin; - -use rustc::hir; -use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; -use rustc_plugin::Registry; - -declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); - -declare_lint!(PLEASE_LINT, Warn, "Warn about items named 'pleaselintme'"); - -struct Pass; - -impl LintPass for Pass { - fn name(&self) -> &'static str { - "Pass" - } - - fn get_lints(&self) -> LintArray { - lint_array!(TEST_LINT, PLEASE_LINT) - } -} - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { - match &*it.ident.as_str() { - "lintme" => cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"), - "pleaselintme" => cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'"), - _ => {} - } - } -} - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_late_lint_pass(box Pass); - reg.register_lint_group("lint_me", None, vec![TEST_LINT, PLEASE_LINT]); -} diff --git a/src/test/ui-fulldeps/auxiliary/lint_plugin_test.rs b/src/test/ui-fulldeps/auxiliary/lint_plugin_test.rs deleted file mode 100644 index 4e45189b42427..0000000000000 --- a/src/test/ui-fulldeps/auxiliary/lint_plugin_test.rs +++ /dev/null @@ -1,42 +0,0 @@ -// force-host - -#![feature(plugin_registrar)] -#![feature(box_syntax, rustc_private)] - -extern crate syntax; - -// Load rustc as a plugin to get macros -#[macro_use] -extern crate rustc; -extern crate rustc_plugin; - -use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, - EarlyLintPassObject, LintArray}; -use rustc_plugin::Registry; -use syntax::ast; -declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); - -struct Pass; - -impl LintPass for Pass { - fn name(&self) -> &'static str { - "Pass" - } - - fn get_lints(&self) -> LintArray { - lint_array!(TEST_LINT) - } -} - -impl EarlyLintPass for Pass { - fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { - if it.ident.name == "lintme" { - cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); - } - } -} - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_early_lint_pass(box Pass as EarlyLintPassObject); -} diff --git a/src/test/ui-fulldeps/auxiliary/lint_tool_test.rs b/src/test/ui-fulldeps/auxiliary/lint_tool_test.rs deleted file mode 100644 index 1a9bd9e66dbac..0000000000000 --- a/src/test/ui-fulldeps/auxiliary/lint_tool_test.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![feature(plugin_registrar)] -#![feature(box_syntax, rustc_private)] - -extern crate syntax; - -// Load rustc as a plugin to get macros -#[macro_use] -extern crate rustc; -extern crate rustc_plugin; - -use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, - LintArray}; -use rustc_plugin::Registry; -use syntax::ast; -declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff"); -declare_tool_lint!(pub clippy::TEST_GROUP, Warn, "Warn about other stuff"); - -struct Pass; - -impl LintPass for Pass { - fn name(&self) -> &'static str { - "Pass" - } - - fn get_lints(&self) -> LintArray { - lint_array!(TEST_LINT, TEST_GROUP) - } -} - -impl EarlyLintPass for Pass { - fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { - if it.ident.name == "lintme" { - cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); - } - if it.ident.name == "lintmetoo" { - cx.span_lint(TEST_GROUP, it.span, "item is named 'lintmetoo'"); - } - } -} - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_early_lint_pass(box Pass); - reg.register_lint_group("clippy::group", Some("clippy_group"), vec![TEST_LINT, TEST_GROUP]); -} diff --git a/src/test/ui-fulldeps/auxiliary/rlib_crate_test.rs b/src/test/ui-fulldeps/auxiliary/rlib-crate-test.rs similarity index 100% rename from src/test/ui-fulldeps/auxiliary/rlib_crate_test.rs rename to src/test/ui-fulldeps/auxiliary/rlib-crate-test.rs diff --git a/src/test/ui-fulldeps/dropck_tarena_cycle_checked.rs b/src/test/ui-fulldeps/dropck-tarena-cycle-checked.rs similarity index 100% rename from src/test/ui-fulldeps/dropck_tarena_cycle_checked.rs rename to src/test/ui-fulldeps/dropck-tarena-cycle-checked.rs diff --git a/src/test/ui-fulldeps/dropck-tarena-cycle-checked.stderr b/src/test/ui-fulldeps/dropck-tarena-cycle-checked.stderr new file mode 100644 index 0000000000000..7009c0bba6981 --- /dev/null +++ b/src/test/ui-fulldeps/dropck-tarena-cycle-checked.stderr @@ -0,0 +1,14 @@ +error[E0597]: `arena` does not live long enough + --> $DIR/dropck-tarena-cycle-checked.rs:116:7 + | +LL | f(&arena); + | ^^^^^^ borrowed value does not live long enough +LL | } + | - + | | + | `arena` dropped here while still borrowed + | borrow might be used here, when `arena` is dropped and runs the `Drop` code for type `arena::TypedArena` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui-fulldeps/dropck-tarena-unsound-drop.rs b/src/test/ui-fulldeps/dropck-tarena-unsound-drop.rs new file mode 100644 index 0000000000000..e454f44d1af6b --- /dev/null +++ b/src/test/ui-fulldeps/dropck-tarena-unsound-drop.rs @@ -0,0 +1,42 @@ +// Check that an arena (TypedArena) cannot carry elements whose drop +// methods might access borrowed data of lifetime that does not +// strictly outlive the arena itself. +// +// Compare against run-pass/dropck_tarena_sound_drop.rs, which shows a +// similar setup, but loosens `f` so that the struct `C<'a>` can be +// fed a lifetime longer than that of the arena. +// +// (Also compare against dropck_tarena_cycle_checked.rs, from which +// this was reduced to better understand its error message.) + +#![feature(rustc_private)] + +extern crate arena; + +use arena::TypedArena; + +trait HasId { fn count(&self) -> usize; } + +struct CheckId { v: T } + +// In the code below, the impl of HasId for `&'a usize` does not +// actually access the borrowed data, but the point is that the +// interface to CheckId does not (and cannot) know that, and therefore +// when encountering a value V of type CheckId, we must +// conservatively force the type S to strictly outlive V. +impl Drop for CheckId { + fn drop(&mut self) { + assert!(self.v.count() > 0); + } +} + +struct C<'a> { v: CheckId<&'a usize>, } + +impl<'a> HasId for &'a usize { fn count(&self) -> usize { 1 } } + +fn f<'a>(_arena: &'a TypedArena>) {} + +fn main() { + let arena: TypedArena = TypedArena::default(); + f(&arena); +} //~^ ERROR `arena` does not live long enough diff --git a/src/test/ui-fulldeps/dropck-tarena-unsound-drop.stderr b/src/test/ui-fulldeps/dropck-tarena-unsound-drop.stderr new file mode 100644 index 0000000000000..319848b989634 --- /dev/null +++ b/src/test/ui-fulldeps/dropck-tarena-unsound-drop.stderr @@ -0,0 +1,14 @@ +error[E0597]: `arena` does not live long enough + --> $DIR/dropck-tarena-unsound-drop.rs:41:7 + | +LL | f(&arena); + | ^^^^^^ borrowed value does not live long enough +LL | } + | - + | | + | `arena` dropped here while still borrowed + | borrow might be used here, when `arena` is dropped and runs the `Drop` code for type `arena::TypedArena` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui-fulldeps/dropck_tarena_cycle_checked.stderr b/src/test/ui-fulldeps/dropck_tarena_cycle_checked.stderr deleted file mode 100644 index 34d026e957d6f..0000000000000 --- a/src/test/ui-fulldeps/dropck_tarena_cycle_checked.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0597]: `arena` does not live long enough - --> $DIR/dropck_tarena_cycle_checked.rs:116:8 - | -LL | f(&arena); - | ^^^^^ borrowed value does not live long enough -LL | } //~^ ERROR `arena` does not live long enough - | - `arena` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui-fulldeps/dropck_tarena_unsound_drop.rs b/src/test/ui-fulldeps/dropck_tarena_unsound_drop.rs deleted file mode 100644 index 3103aef36cb9f..0000000000000 --- a/src/test/ui-fulldeps/dropck_tarena_unsound_drop.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Check that an arena (TypedArena) cannot carry elements whose drop -// methods might access borrowed data of lifetime that does not -// strictly outlive the arena itself. -// -// Compare against run-pass/dropck_tarena_sound_drop.rs, which shows a -// similar setup, but loosens `f` so that the struct `C<'a>` can be -// fed a lifetime longer than that of the arena. -// -// (Also compare against dropck_tarena_cycle_checked.rs, from which -// this was reduced to better understand its error message.) - -#![feature(rustc_private)] - -extern crate arena; - -use arena::TypedArena; - -trait HasId { fn count(&self) -> usize; } - -struct CheckId { v: T } - -// In the code below, the impl of HasId for `&'a usize` does not -// actually access the borrowed data, but the point is that the -// interface to CheckId does not (and cannot) know that, and therefore -// when encountering a value V of type CheckId, we must -// conservatively force the type S to strictly outlive V. -impl Drop for CheckId { - fn drop(&mut self) { - assert!(self.v.count() > 0); - } -} - -struct C<'a> { v: CheckId<&'a usize>, } - -impl<'a> HasId for &'a usize { fn count(&self) -> usize { 1 } } - -fn f<'a>(_arena: &'a TypedArena>) {} - -fn main() { - let arena: TypedArena = TypedArena::default(); - f(&arena); -} //~^ ERROR `arena` does not live long enough - diff --git a/src/test/ui-fulldeps/dropck_tarena_unsound_drop.stderr b/src/test/ui-fulldeps/dropck_tarena_unsound_drop.stderr deleted file mode 100644 index 47754da8b78d9..0000000000000 --- a/src/test/ui-fulldeps/dropck_tarena_unsound_drop.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0597]: `arena` does not live long enough - --> $DIR/dropck_tarena_unsound_drop.rs:41:8 - | -LL | f(&arena); - | ^^^^^ borrowed value does not live long enough -LL | } //~^ ERROR `arena` does not live long enough - | - `arena` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui-fulldeps/gated-plugin.rs b/src/test/ui-fulldeps/gated-plugin.rs index a647585e621fe..be1ec0614803b 100644 --- a/src/test/ui-fulldeps/gated-plugin.rs +++ b/src/test/ui-fulldeps/gated-plugin.rs @@ -1,4 +1,4 @@ -// aux-build:attr_plugin_test.rs +// aux-build:attr-plugin-test.rs #![plugin(attr_plugin_test)] //~^ ERROR compiler plugins are experimental and possibly buggy diff --git a/src/test/ui-fulldeps/gated-plugin.stderr b/src/test/ui-fulldeps/gated-plugin.stderr index 37c2b4432470d..4f8bcda9020ab 100644 --- a/src/test/ui-fulldeps/gated-plugin.stderr +++ b/src/test/ui-fulldeps/gated-plugin.stderr @@ -1,9 +1,10 @@ -error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597) +error[E0658]: compiler plugins are experimental and possibly buggy --> $DIR/gated-plugin.rs:3:1 | LL | #![plugin(attr_plugin_test)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29597 = help: add #![feature(plugin)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui-fulldeps/hash-stable-is-unstable.rs b/src/test/ui-fulldeps/hash-stable-is-unstable.rs new file mode 100644 index 0000000000000..9f67f642df1ce --- /dev/null +++ b/src/test/ui-fulldeps/hash-stable-is-unstable.rs @@ -0,0 +1,15 @@ +// ignore-stage1 + +extern crate rustc_data_structures; +//~^ use of unstable library feature 'rustc_private' +extern crate rustc; +//~^ use of unstable library feature 'rustc_private' +extern crate rustc_macros; +//~^ use of unstable library feature 'rustc_private' + +use rustc_macros::HashStable; +//~^ use of unstable library feature 'rustc_private' + +#[derive(HashStable)] +//~^ use of unstable library feature 'rustc_private' +struct Test; diff --git a/src/test/ui-fulldeps/hash-stable-is-unstable.stderr b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr new file mode 100644 index 0000000000000..2c1aa1f5d869e --- /dev/null +++ b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr @@ -0,0 +1,53 @@ +error[E0601]: `main` function not found in crate `hash_stable_is_unstable` + | + = note: consider adding a `main` function to `$DIR/hash-stable-is-unstable.rs` + +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? + --> $DIR/hash-stable-is-unstable.rs:3:1 + | +LL | extern crate rustc_data_structures; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/27812 + = help: add #![feature(rustc_private)] to the crate attributes to enable + +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? + --> $DIR/hash-stable-is-unstable.rs:5:1 + | +LL | extern crate rustc; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/27812 + = help: add #![feature(rustc_private)] to the crate attributes to enable + +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? + --> $DIR/hash-stable-is-unstable.rs:7:1 + | +LL | extern crate rustc_macros; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/27812 + = help: add #![feature(rustc_private)] to the crate attributes to enable + +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? + --> $DIR/hash-stable-is-unstable.rs:10:5 + | +LL | use rustc_macros::HashStable; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/27812 + = help: add #![feature(rustc_private)] to the crate attributes to enable + +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? + --> $DIR/hash-stable-is-unstable.rs:13:10 + | +LL | #[derive(HashStable)] + | ^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/27812 + = help: add #![feature(rustc_private)] to the crate attributes to enable + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0601, E0658. +For more information about an error, try `rustc --explain E0601`. diff --git a/src/test/ui-fulldeps/internal-lints/default_hash_types.rs b/src/test/ui-fulldeps/internal-lints/default_hash_types.rs new file mode 100644 index 0000000000000..3264099c876d0 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/default_hash_types.rs @@ -0,0 +1,22 @@ +// compile-flags: -Z unstable-options + +#![feature(rustc_private)] + +extern crate rustc_data_structures; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use std::collections::{HashMap, HashSet}; + +#[deny(default_hash_types)] +fn main() { + let _map: HashMap = HashMap::default(); + //~^ ERROR Prefer FxHashMap over HashMap, it has better performance + //~^^ ERROR Prefer FxHashMap over HashMap, it has better performance + let _set: HashSet = HashSet::default(); + //~^ ERROR Prefer FxHashSet over HashSet, it has better performance + //~^^ ERROR Prefer FxHashSet over HashSet, it has better performance + + // test that the lint doesn't also match the Fx variants themselves + let _fx_map: FxHashMap = FxHashMap::default(); + let _fx_set: FxHashSet = FxHashSet::default(); +} diff --git a/src/test/ui-fulldeps/internal-lints/default_hash_types.stderr b/src/test/ui-fulldeps/internal-lints/default_hash_types.stderr new file mode 100644 index 0000000000000..64f322cb0c165 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/default_hash_types.stderr @@ -0,0 +1,39 @@ +error: Prefer FxHashMap over HashMap, it has better performance + --> $DIR/default_hash_types.rs:12:15 + | +LL | let _map: HashMap = HashMap::default(); + | ^^^^^^^ help: use: `FxHashMap` + | +note: lint level defined here + --> $DIR/default_hash_types.rs:10:8 + | +LL | #[deny(default_hash_types)] + | ^^^^^^^^^^^^^^^^^^ + = note: a `use rustc_data_structures::fx::FxHashMap` may be necessary + +error: Prefer FxHashMap over HashMap, it has better performance + --> $DIR/default_hash_types.rs:12:41 + | +LL | let _map: HashMap = HashMap::default(); + | ^^^^^^^ help: use: `FxHashMap` + | + = note: a `use rustc_data_structures::fx::FxHashMap` may be necessary + +error: Prefer FxHashSet over HashSet, it has better performance + --> $DIR/default_hash_types.rs:15:15 + | +LL | let _set: HashSet = HashSet::default(); + | ^^^^^^^ help: use: `FxHashSet` + | + = note: a `use rustc_data_structures::fx::FxHashSet` may be necessary + +error: Prefer FxHashSet over HashSet, it has better performance + --> $DIR/default_hash_types.rs:15:33 + | +LL | let _set: HashSet = HashSet::default(); + | ^^^^^^^ help: use: `FxHashSet` + | + = note: a `use rustc_data_structures::fx::FxHashSet` may be necessary + +error: aborting due to 4 previous errors + diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.rs b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.rs new file mode 100644 index 0000000000000..9534ddbbc6471 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.rs @@ -0,0 +1,64 @@ +// compile-flags: -Z unstable-options + +#![feature(rustc_private)] +#![deny(ty_pass_by_reference)] +#![allow(unused)] + +extern crate rustc; + +use rustc::ty::{Ty, TyCtxt}; + +fn ty_by_ref( + ty_val: Ty<'_>, + ty_ref: &Ty<'_>, //~ ERROR passing `Ty<'_>` by reference + ty_ctxt_val: TyCtxt<'_>, + ty_ctxt_ref: &TyCtxt<'_>, //~ ERROR passing `TyCtxt<'_>` by reference +) { +} + +fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} +//~^ ERROR passing `Ty<'_>` by reference +//~^^ ERROR passing `TyCtxt<'_>` by reference + +trait T { + fn ty_by_ref_in_trait( + ty_val: Ty<'_>, + ty_ref: &Ty<'_>, //~ ERROR passing `Ty<'_>` by reference + ty_ctxt_val: TyCtxt<'_>, + ty_ctxt_ref: &TyCtxt<'_>, //~ ERROR passing `TyCtxt<'_>` by reference + ); + + fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>); + //~^ ERROR passing `Ty<'_>` by reference + //~^^ ERROR passing `TyCtxt<'_>` by reference +} + +struct Foo; + +impl T for Foo { + fn ty_by_ref_in_trait( + ty_val: Ty<'_>, + ty_ref: &Ty<'_>, + ty_ctxt_val: TyCtxt<'_>, + ty_ctxt_ref: &TyCtxt<'_>, + ) { + } + + fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} +} + +impl Foo { + fn ty_by_ref_assoc( + ty_val: Ty<'_>, + ty_ref: &Ty<'_>, //~ ERROR passing `Ty<'_>` by reference + ty_ctxt_val: TyCtxt<'_>, + ty_ctxt_ref: &TyCtxt<'_>, //~ ERROR passing `TyCtxt<'_>` by reference + ) { + } + + fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} + //~^ ERROR passing `Ty<'_>` by reference + //~^^ ERROR passing `TyCtxt<'_>` by reference +} + +fn main() {} diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr new file mode 100644 index 0000000000000..0f9f24b98a08c --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr @@ -0,0 +1,80 @@ +error: passing `Ty<'_>` by reference + --> $DIR/pass_ty_by_ref.rs:13:13 + | +LL | ty_ref: &Ty<'_>, + | ^^^^^^^ help: try passing by value: `Ty<'_>` + | +note: lint level defined here + --> $DIR/pass_ty_by_ref.rs:4:9 + | +LL | #![deny(ty_pass_by_reference)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: passing `TyCtxt<'_>` by reference + --> $DIR/pass_ty_by_ref.rs:15:18 + | +LL | ty_ctxt_ref: &TyCtxt<'_>, + | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` + +error: passing `Ty<'_>` by reference + --> $DIR/pass_ty_by_ref.rs:19:28 + | +LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} + | ^^^^^^^ help: try passing by value: `Ty<'_>` + +error: passing `TyCtxt<'_>` by reference + --> $DIR/pass_ty_by_ref.rs:19:55 + | +LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} + | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` + +error: passing `Ty<'_>` by reference + --> $DIR/pass_ty_by_ref.rs:26:17 + | +LL | ty_ref: &Ty<'_>, + | ^^^^^^^ help: try passing by value: `Ty<'_>` + +error: passing `TyCtxt<'_>` by reference + --> $DIR/pass_ty_by_ref.rs:28:22 + | +LL | ty_ctxt_ref: &TyCtxt<'_>, + | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` + +error: passing `Ty<'_>` by reference + --> $DIR/pass_ty_by_ref.rs:31:41 + | +LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>); + | ^^^^^^^ help: try passing by value: `Ty<'_>` + +error: passing `TyCtxt<'_>` by reference + --> $DIR/pass_ty_by_ref.rs:31:68 + | +LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>); + | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` + +error: passing `Ty<'_>` by reference + --> $DIR/pass_ty_by_ref.rs:53:17 + | +LL | ty_ref: &Ty<'_>, + | ^^^^^^^ help: try passing by value: `Ty<'_>` + +error: passing `TyCtxt<'_>` by reference + --> $DIR/pass_ty_by_ref.rs:55:22 + | +LL | ty_ctxt_ref: &TyCtxt<'_>, + | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` + +error: passing `Ty<'_>` by reference + --> $DIR/pass_ty_by_ref.rs:59:38 + | +LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} + | ^^^^^^^ help: try passing by value: `Ty<'_>` + +error: passing `TyCtxt<'_>` by reference + --> $DIR/pass_ty_by_ref.rs:59:65 + | +LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {} + | ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>` + +error: aborting due to 12 previous errors + diff --git a/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.rs b/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.rs new file mode 100644 index 0000000000000..56033100344a6 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.rs @@ -0,0 +1,35 @@ +// compile-flags: -Z unstable-options + +#![feature(rustc_private)] +#![deny(usage_of_qualified_ty)] +#![allow(unused)] + +extern crate rustc; + +use rustc::ty::{self, Ty, TyCtxt}; + +macro_rules! qualified_macro { + ($a:ident) => { + fn ty_in_macro( + ty_q: ty::Ty<'_>, + ty: Ty<'_>, + ty_ctxt_q: ty::TyCtxt<'_>, + ty_ctxt: TyCtxt<'_>, + ) { + println!("{}", stringify!($a)); + } + }; +} + +fn ty_qualified( + ty_q: ty::Ty<'_>, //~ ERROR usage of qualified `ty::Ty<'_>` + ty: Ty<'_>, + ty_ctxt_q: ty::TyCtxt<'_>, //~ ERROR usage of qualified `ty::TyCtxt<'_>` + ty_ctxt: TyCtxt<'_>, +) { +} + + +fn main() { + qualified_macro!(a); +} diff --git a/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr b/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr new file mode 100644 index 0000000000000..c3642e6a4ba74 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr @@ -0,0 +1,20 @@ +error: usage of qualified `ty::Ty<'_>` + --> $DIR/qualified_ty_ty_ctxt.rs:25:11 + | +LL | ty_q: ty::Ty<'_>, + | ^^^^^^^^^^ help: try using it unqualified: `Ty<'_>` + | +note: lint level defined here + --> $DIR/qualified_ty_ty_ctxt.rs:4:9 + | +LL | #![deny(usage_of_qualified_ty)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: usage of qualified `ty::TyCtxt<'_>` + --> $DIR/qualified_ty_ty_ctxt.rs:27:16 + | +LL | ty_ctxt_q: ty::TyCtxt<'_>, + | ^^^^^^^^^^^^^^ help: try using it unqualified: `TyCtxt<'_>` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs new file mode 100644 index 0000000000000..dba0db69b7f39 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs @@ -0,0 +1,49 @@ +// compile-flags: -Z unstable-options + +#![feature(rustc_private)] + +extern crate rustc; + +use rustc::ty::{self, Ty, TyKind}; + +#[deny(usage_of_ty_tykind)] +fn main() { + let sty = TyKind::Bool; //~ ERROR usage of `ty::TyKind::` + + match sty { + TyKind::Bool => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Char => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Int(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Uint(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Float(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Adt(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Foreign(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Str => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Array(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Slice(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::RawPtr(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Ref(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::FnDef(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::FnPtr(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Dynamic(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Closure(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Generator(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::GeneratorWitness(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Never => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Tuple(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Projection(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::UnnormalizedProjection(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Opaque(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Param(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Bound(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Placeholder(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Infer(..) => (), //~ ERROR usage of `ty::TyKind::` + TyKind::Error => (), //~ ERROR usage of `ty::TyKind::` + } + + if let ty::Int(int_ty) = sty {} + + if let TyKind::Int(int_ty) = sty {} //~ ERROR usage of `ty::TyKind::` + + fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} //~ ERROR usage of `ty::TyKind` +} diff --git a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr new file mode 100644 index 0000000000000..10229a331c285 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr @@ -0,0 +1,196 @@ +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:11:15 + | +LL | let sty = TyKind::Bool; + | ^^^^^^ help: try using ty:: directly: `ty` + | +note: lint level defined here + --> $DIR/ty_tykind_usage.rs:9:8 + | +LL | #[deny(usage_of_ty_tykind)] + | ^^^^^^^^^^^^^^^^^^ + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:14:9 + | +LL | TyKind::Bool => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:15:9 + | +LL | TyKind::Char => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:16:9 + | +LL | TyKind::Int(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:17:9 + | +LL | TyKind::Uint(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:18:9 + | +LL | TyKind::Float(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:19:9 + | +LL | TyKind::Adt(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:20:9 + | +LL | TyKind::Foreign(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:21:9 + | +LL | TyKind::Str => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:22:9 + | +LL | TyKind::Array(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:23:9 + | +LL | TyKind::Slice(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:24:9 + | +LL | TyKind::RawPtr(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:25:9 + | +LL | TyKind::Ref(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:26:9 + | +LL | TyKind::FnDef(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:27:9 + | +LL | TyKind::FnPtr(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:28:9 + | +LL | TyKind::Dynamic(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:29:9 + | +LL | TyKind::Closure(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:30:9 + | +LL | TyKind::Generator(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:31:9 + | +LL | TyKind::GeneratorWitness(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:32:9 + | +LL | TyKind::Never => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:33:9 + | +LL | TyKind::Tuple(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:34:9 + | +LL | TyKind::Projection(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:35:9 + | +LL | TyKind::UnnormalizedProjection(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:36:9 + | +LL | TyKind::Opaque(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:37:9 + | +LL | TyKind::Param(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:38:9 + | +LL | TyKind::Bound(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:39:9 + | +LL | TyKind::Placeholder(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:40:9 + | +LL | TyKind::Infer(..) => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:41:9 + | +LL | TyKind::Error => (), + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind::` + --> $DIR/ty_tykind_usage.rs:46:12 + | +LL | if let TyKind::Int(int_ty) = sty {} + | ^^^^^^ help: try using ty:: directly: `ty` + +error: usage of `ty::TyKind` + --> $DIR/ty_tykind_usage.rs:48:24 + | +LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} + | ^^^^^^^^^^ + | + = help: try using `Ty` instead + +error: aborting due to 31 previous errors + diff --git a/src/test/ui-fulldeps/issue-15778-fail.rs b/src/test/ui-fulldeps/issue-15778-fail.rs index 91c379673b3da..75c52fdb4bd28 100644 --- a/src/test/ui-fulldeps/issue-15778-fail.rs +++ b/src/test/ui-fulldeps/issue-15778-fail.rs @@ -1,4 +1,4 @@ -// aux-build:lint_for_crate.rs +// aux-build:lint-for-crate.rs // ignore-stage1 // compile-flags: -D crate-not-okay diff --git a/src/test/ui-fulldeps/issue-15778-fail.stderr b/src/test/ui-fulldeps/issue-15778-fail.stderr index 8eafd1cefa6c4..d689286177644 100644 --- a/src/test/ui-fulldeps/issue-15778-fail.stderr +++ b/src/test/ui-fulldeps/issue-15778-fail.stderr @@ -1,7 +1,7 @@ error: crate is not marked with #![crate_okay] --> $DIR/issue-15778-fail.rs:5:1 | -LL | / #![feature(plugin)] //~ ERROR crate is not marked with #![crate_okay] +LL | / #![feature(plugin)] LL | | #![plugin(lint_for_crate)] LL | | LL | | pub fn main() { } diff --git a/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.rs b/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.rs index 75e0a8fc31f7c..c9d8654a90974 100644 --- a/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.rs +++ b/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.rs @@ -1,4 +1,4 @@ -// aux-build:lint_group_plugin_test.rs +// aux-build:lint-group-plugin-test.rs // ignore-stage1 // compile-flags: -D lint-me diff --git a/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.stderr b/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.stderr index 9b629ca6778e5..cd0bff92bf112 100644 --- a/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.stderr +++ b/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.stderr @@ -1,7 +1,7 @@ error: item is named 'lintme' --> $DIR/lint-group-plugin-deny-cmdline.rs:8:1 | -LL | fn lintme() { } //~ ERROR item is named 'lintme' +LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | = note: `-D test-lint` implied by `-D lint-me` @@ -9,7 +9,7 @@ LL | fn lintme() { } //~ ERROR item is named 'lintme' error: item is named 'pleaselintme' --> $DIR/lint-group-plugin-deny-cmdline.rs:10:1 | -LL | fn pleaselintme() { } //~ ERROR item is named 'pleaselintme' +LL | fn pleaselintme() { } | ^^^^^^^^^^^^^^^^^^^^^ | = note: `-D please-lint` implied by `-D lint-me` diff --git a/src/test/ui-fulldeps/lint-group-plugin.rs b/src/test/ui-fulldeps/lint-group-plugin.rs index 7a650afe5f8fa..55a880be0f985 100644 --- a/src/test/ui-fulldeps/lint-group-plugin.rs +++ b/src/test/ui-fulldeps/lint-group-plugin.rs @@ -1,5 +1,5 @@ // run-pass -// aux-build:lint_group_plugin_test.rs +// aux-build:lint-group-plugin-test.rs // ignore-stage1 #![feature(plugin)] diff --git a/src/test/ui-fulldeps/lint-group-plugin.stderr b/src/test/ui-fulldeps/lint-group-plugin.stderr index b566048c75ee6..8ccf9700b9fc8 100644 --- a/src/test/ui-fulldeps/lint-group-plugin.stderr +++ b/src/test/ui-fulldeps/lint-group-plugin.stderr @@ -1,7 +1,7 @@ warning: item is named 'lintme' --> $DIR/lint-group-plugin.rs:9:1 | -LL | fn lintme() { } //~ WARNING item is named 'lintme' +LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | = note: #[warn(test_lint)] on by default @@ -9,7 +9,7 @@ LL | fn lintme() { } //~ WARNING item is named 'lintme' warning: item is named 'pleaselintme' --> $DIR/lint-group-plugin.rs:10:1 | -LL | fn pleaselintme() { } //~ WARNING item is named 'pleaselintme' +LL | fn pleaselintme() { } | ^^^^^^^^^^^^^^^^^^^^^ | = note: #[warn(please_lint)] on by default diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-allow.rs b/src/test/ui-fulldeps/lint-plugin-cmdline-allow.rs index 21042c5e7d084..8017379ab3d44 100644 --- a/src/test/ui-fulldeps/lint-plugin-cmdline-allow.rs +++ b/src/test/ui-fulldeps/lint-plugin-cmdline-allow.rs @@ -1,5 +1,5 @@ // run-pass -// aux-build:lint_plugin_test.rs +// aux-build:lint-plugin-test.rs // ignore-stage1 // compile-flags: -A test-lint diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-load.rs b/src/test/ui-fulldeps/lint-plugin-cmdline-load.rs index 0dca00040bfe6..fd681536b5b2b 100644 --- a/src/test/ui-fulldeps/lint-plugin-cmdline-load.rs +++ b/src/test/ui-fulldeps/lint-plugin-cmdline-load.rs @@ -1,5 +1,5 @@ // run-pass -// aux-build:lint_plugin_test.rs +// aux-build:lint-plugin-test.rs // ignore-stage1 // compile-flags: -Z extra-plugins=lint_plugin_test diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr b/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr index 1beb5b7816cb5..0b2dbad884c54 100644 --- a/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr +++ b/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr @@ -1,7 +1,7 @@ warning: item is named 'lintme' --> $DIR/lint-plugin-cmdline-load.rs:8:1 | -LL | fn lintme() { } //~ WARNING item is named 'lintme' +LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | = note: #[warn(test_lint)] on by default diff --git a/src/test/ui-fulldeps/lint-plugin-deny-attr.rs b/src/test/ui-fulldeps/lint-plugin-deny-attr.rs index 65a3623618020..2d424af870707 100644 --- a/src/test/ui-fulldeps/lint-plugin-deny-attr.rs +++ b/src/test/ui-fulldeps/lint-plugin-deny-attr.rs @@ -1,4 +1,4 @@ -// aux-build:lint_plugin_test.rs +// aux-build:lint-plugin-test.rs // ignore-stage1 #![feature(plugin)] diff --git a/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr b/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr index 81fee10e56ff8..5bfde8551ed37 100644 --- a/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr +++ b/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr @@ -1,7 +1,7 @@ error: item is named 'lintme' --> $DIR/lint-plugin-deny-attr.rs:8:1 | -LL | fn lintme() { } //~ ERROR item is named 'lintme' +LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui-fulldeps/lint-plugin-deny-cmdline.rs b/src/test/ui-fulldeps/lint-plugin-deny-cmdline.rs index b0c4dc0bce516..87324e85b3be7 100644 --- a/src/test/ui-fulldeps/lint-plugin-deny-cmdline.rs +++ b/src/test/ui-fulldeps/lint-plugin-deny-cmdline.rs @@ -1,4 +1,4 @@ -// aux-build:lint_plugin_test.rs +// aux-build:lint-plugin-test.rs // ignore-stage1 // compile-flags: -D test-lint diff --git a/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr b/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr index 9b84abf704c7f..e4257dfde6f90 100644 --- a/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr +++ b/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr @@ -1,7 +1,7 @@ error: item is named 'lintme' --> $DIR/lint-plugin-deny-cmdline.rs:8:1 | -LL | fn lintme() { } //~ ERROR item is named 'lintme' +LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | = note: requested on the command line with `-D test-lint` diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs index 964fed3b37d11..c7f7f2be99ed5 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs +++ b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs @@ -1,4 +1,4 @@ -// aux-build:lint_plugin_test.rs +// aux-build:lint-plugin-test.rs // ignore-stage1 #![feature(plugin)] diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr index 11dd75621bf51..092d0eb7a81a4 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr +++ b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr @@ -10,7 +10,7 @@ LL | #[allow(test_lint)] error: item is named 'lintme' --> $DIR/lint-plugin-forbid-attrs.rs:8:1 | -LL | fn lintme() { } //~ ERROR item is named 'lintme' +LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs index 07bd785ee7137..91fe3b65be6fc 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs +++ b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs @@ -1,4 +1,4 @@ -// aux-build:lint_plugin_test.rs +// aux-build:lint-plugin-test.rs // ignore-stage1 // compile-flags: -F test-lint diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr index b03051250fca8..fc2906da5f5fc 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr +++ b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr @@ -1,7 +1,7 @@ error[E0453]: allow(test_lint) overruled by outer forbid(test_lint) --> $DIR/lint-plugin-forbid-cmdline.rs:10:9 | -LL | #[allow(test_lint)] //~ ERROR allow(test_lint) overruled by outer forbid(test_lint) +LL | #[allow(test_lint)] | ^^^^^^^^^ overruled by previous forbid | = note: `forbid` lint level was set on command line @@ -9,7 +9,7 @@ LL | #[allow(test_lint)] //~ ERROR allow(test_lint) overruled by outer forbid(te error: item is named 'lintme' --> $DIR/lint-plugin-forbid-cmdline.rs:8:1 | -LL | fn lintme() { } //~ ERROR item is named 'lintme' +LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | = note: requested on the command line with `-F test-lint` diff --git a/src/test/ui-fulldeps/lint-plugin.rs b/src/test/ui-fulldeps/lint-plugin.rs index 031f3b86b1438..5f8bc16301a74 100644 --- a/src/test/ui-fulldeps/lint-plugin.rs +++ b/src/test/ui-fulldeps/lint-plugin.rs @@ -1,5 +1,5 @@ // run-pass -// aux-build:lint_plugin_test.rs +// aux-build:lint-plugin-test.rs // ignore-stage1 #![feature(plugin)] #![plugin(lint_plugin_test)] diff --git a/src/test/ui-fulldeps/lint-plugin.stderr b/src/test/ui-fulldeps/lint-plugin.stderr index 11e3222a1a51c..94791e369fc30 100644 --- a/src/test/ui-fulldeps/lint-plugin.stderr +++ b/src/test/ui-fulldeps/lint-plugin.stderr @@ -1,7 +1,7 @@ warning: item is named 'lintme' --> $DIR/lint-plugin.rs:8:1 | -LL | fn lintme() { } //~ WARNING item is named 'lintme' +LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | = note: #[warn(test_lint)] on by default diff --git a/src/test/ui-fulldeps/lint-tool-cmdline-allow.rs b/src/test/ui-fulldeps/lint-tool-cmdline-allow.rs new file mode 100644 index 0000000000000..529f04c6fc4dd --- /dev/null +++ b/src/test/ui-fulldeps/lint-tool-cmdline-allow.rs @@ -0,0 +1,12 @@ +// run-pass +// aux-build:lint-tool-test.rs +// ignore-stage1 +// compile-flags: -A test-lint + +#![feature(plugin)] +#![warn(unused)] +#![plugin(lint_tool_test)] + +fn lintme() {} + +pub fn main() {} diff --git a/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr b/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr new file mode 100644 index 0000000000000..1d85101383136 --- /dev/null +++ b/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr @@ -0,0 +1,25 @@ +warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint + | + = note: requested on the command line with `-A test_lint` + +warning: item is named 'lintme' + --> $DIR/lint-tool-cmdline-allow.rs:10:1 + | +LL | fn lintme() {} + | ^^^^^^^^^^^^^^ + | + = note: #[warn(clippy::test_lint)] on by default + +warning: function is never used: `lintme` + --> $DIR/lint-tool-cmdline-allow.rs:10:1 + | +LL | fn lintme() {} + | ^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-tool-cmdline-allow.rs:7:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: #[warn(dead_code)] implied by #[warn(unused)] + diff --git a/src/test/ui-fulldeps/lint-tool-test.rs b/src/test/ui-fulldeps/lint-tool-test.rs new file mode 100644 index 0000000000000..8bd06d1f1e34f --- /dev/null +++ b/src/test/ui-fulldeps/lint-tool-test.rs @@ -0,0 +1,30 @@ +// aux-build:lint-tool-test.rs +// ignore-stage1 +// compile-flags: --cfg foo + +#![feature(plugin)] +#![plugin(lint_tool_test)] +#![allow(dead_code)] +#![cfg_attr(foo, warn(test_lint))] +//~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future +//~^^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future +#![deny(clippy_group)] +//~^ WARNING lint name `clippy_group` is deprecated and may not have an effect in the future + +fn lintme() { } //~ ERROR item is named 'lintme' + +#[allow(clippy::group)] +fn lintmetoo() {} + +#[allow(clippy::test_lint)] +pub fn main() { + fn lintme() { } + fn lintmetoo() { } //~ ERROR item is named 'lintmetoo' +} + +#[allow(test_group)] +//~^ WARNING lint name `test_group` is deprecated and may not have an effect in the future +#[deny(this_lint_does_not_exist)] //~ WARNING unknown lint: `this_lint_does_not_exist` +fn hello() { + fn lintmetoo() { } +} diff --git a/src/test/ui-fulldeps/lint-tool-test.stderr b/src/test/ui-fulldeps/lint-tool-test.stderr new file mode 100644 index 0000000000000..67e55e65c7e77 --- /dev/null +++ b/src/test/ui-fulldeps/lint-tool-test.stderr @@ -0,0 +1,62 @@ +warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore + --> $DIR/lint-tool-test.rs:8:23 + | +LL | #![cfg_attr(foo, warn(test_lint))] + | ^^^^^^^^^ help: change it to: `clippy::test_lint` + | + = note: #[warn(renamed_and_removed_lints)] on by default + +warning: lint name `clippy_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore + --> $DIR/lint-tool-test.rs:11:9 + | +LL | #![deny(clippy_group)] + | ^^^^^^^^^^^^ help: change it to: `clippy::group` + +warning: lint name `test_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore + --> $DIR/lint-tool-test.rs:25:9 + | +LL | #[allow(test_group)] + | ^^^^^^^^^^ help: change it to: `clippy::test_group` + +warning: unknown lint: `this_lint_does_not_exist` + --> $DIR/lint-tool-test.rs:27:8 + | +LL | #[deny(this_lint_does_not_exist)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: #[warn(unknown_lints)] on by default + +warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore + --> $DIR/lint-tool-test.rs:8:23 + | +LL | #![cfg_attr(foo, warn(test_lint))] + | ^^^^^^^^^ help: change it to: `clippy::test_lint` + +error: item is named 'lintme' + --> $DIR/lint-tool-test.rs:14:1 + | +LL | fn lintme() { } + | ^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-tool-test.rs:11:9 + | +LL | #![deny(clippy_group)] + | ^^^^^^^^^^^^ + = note: #[deny(clippy::test_lint)] implied by #[deny(clippy::group)] + +error: item is named 'lintmetoo' + --> $DIR/lint-tool-test.rs:22:5 + | +LL | fn lintmetoo() { } + | ^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-tool-test.rs:11:9 + | +LL | #![deny(clippy_group)] + | ^^^^^^^^^^^^ + = note: #[deny(clippy::test_group)] implied by #[deny(clippy::group)] + +error: aborting due to 2 previous errors + diff --git a/src/test/ui-fulldeps/lint_tool_cmdline_allow.rs b/src/test/ui-fulldeps/lint_tool_cmdline_allow.rs deleted file mode 100644 index d60f41dd5a327..0000000000000 --- a/src/test/ui-fulldeps/lint_tool_cmdline_allow.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass -// aux-build:lint_tool_test.rs -// ignore-stage1 -// compile-flags: -A test-lint - -#![feature(plugin)] -#![warn(unused)] -#![plugin(lint_tool_test)] - -fn lintme() { } - -pub fn main() { -} diff --git a/src/test/ui-fulldeps/lint_tool_cmdline_allow.stderr b/src/test/ui-fulldeps/lint_tool_cmdline_allow.stderr deleted file mode 100644 index 9634f1d572fca..0000000000000 --- a/src/test/ui-fulldeps/lint_tool_cmdline_allow.stderr +++ /dev/null @@ -1,25 +0,0 @@ -warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint - | - = note: requested on the command line with `-A test_lint` - -warning: item is named 'lintme' - --> $DIR/lint_tool_cmdline_allow.rs:10:1 - | -LL | fn lintme() { } - | ^^^^^^^^^^^^^^^ - | - = note: #[warn(clippy::test_lint)] on by default - -warning: function is never used: `lintme` - --> $DIR/lint_tool_cmdline_allow.rs:10:1 - | -LL | fn lintme() { } - | ^^^^^^^^^^^ - | -note: lint level defined here - --> $DIR/lint_tool_cmdline_allow.rs:7:9 - | -LL | #![warn(unused)] - | ^^^^^^ - = note: #[warn(dead_code)] implied by #[warn(unused)] - diff --git a/src/test/ui-fulldeps/lint_tool_test.rs b/src/test/ui-fulldeps/lint_tool_test.rs deleted file mode 100644 index 04608b62f43c1..0000000000000 --- a/src/test/ui-fulldeps/lint_tool_test.rs +++ /dev/null @@ -1,30 +0,0 @@ -// aux-build:lint_tool_test.rs -// ignore-stage1 -// compile-flags: --cfg foo - -#![feature(plugin)] -#![plugin(lint_tool_test)] -#![allow(dead_code)] -#![cfg_attr(foo, warn(test_lint))] -//~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future -//~^^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future -#![deny(clippy_group)] -//~^ WARNING lint name `clippy_group` is deprecated and may not have an effect in the future - -fn lintme() { } //~ ERROR item is named 'lintme' - -#[allow(clippy::group)] -fn lintmetoo() {} - -#[allow(clippy::test_lint)] -pub fn main() { - fn lintme() { } - fn lintmetoo() { } //~ ERROR item is named 'lintmetoo' -} - -#[allow(test_group)] -//~^ WARNING lint name `test_group` is deprecated and may not have an effect in the future -#[deny(this_lint_does_not_exist)] //~ WARNING unknown lint: `this_lint_does_not_exist` -fn hello() { - fn lintmetoo() { } -} diff --git a/src/test/ui-fulldeps/lint_tool_test.stderr b/src/test/ui-fulldeps/lint_tool_test.stderr deleted file mode 100644 index 95db7ec455db7..0000000000000 --- a/src/test/ui-fulldeps/lint_tool_test.stderr +++ /dev/null @@ -1,62 +0,0 @@ -warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore - --> $DIR/lint_tool_test.rs:8:23 - | -LL | #![cfg_attr(foo, warn(test_lint))] - | ^^^^^^^^^ help: change it to: `clippy::test_lint` - | - = note: #[warn(renamed_and_removed_lints)] on by default - -warning: lint name `clippy_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore - --> $DIR/lint_tool_test.rs:11:9 - | -LL | #![deny(clippy_group)] - | ^^^^^^^^^^^^ help: change it to: `clippy::group` - -warning: lint name `test_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore - --> $DIR/lint_tool_test.rs:25:9 - | -LL | #[allow(test_group)] - | ^^^^^^^^^^ help: change it to: `clippy::test_group` - -warning: unknown lint: `this_lint_does_not_exist` - --> $DIR/lint_tool_test.rs:27:8 - | -LL | #[deny(this_lint_does_not_exist)] //~ WARNING unknown lint: `this_lint_does_not_exist` - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: #[warn(unknown_lints)] on by default - -warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore - --> $DIR/lint_tool_test.rs:8:23 - | -LL | #![cfg_attr(foo, warn(test_lint))] - | ^^^^^^^^^ help: change it to: `clippy::test_lint` - -error: item is named 'lintme' - --> $DIR/lint_tool_test.rs:14:1 - | -LL | fn lintme() { } //~ ERROR item is named 'lintme' - | ^^^^^^^^^^^^^^^ - | -note: lint level defined here - --> $DIR/lint_tool_test.rs:11:9 - | -LL | #![deny(clippy_group)] - | ^^^^^^^^^^^^ - = note: #[deny(clippy::test_lint)] implied by #[deny(clippy::group)] - -error: item is named 'lintmetoo' - --> $DIR/lint_tool_test.rs:22:5 - | -LL | fn lintmetoo() { } //~ ERROR item is named 'lintmetoo' - | ^^^^^^^^^^^^^^^^^^ - | -note: lint level defined here - --> $DIR/lint_tool_test.rs:11:9 - | -LL | #![deny(clippy_group)] - | ^^^^^^^^^^^^ - = note: #[deny(clippy::test_group)] implied by #[deny(clippy::group)] - -error: aborting due to 2 previous errors - diff --git a/src/test/ui-fulldeps/macro-crate-rlib.rs b/src/test/ui-fulldeps/macro-crate-rlib.rs index 21e62171f0f0d..2962bb51fc418 100644 --- a/src/test/ui-fulldeps/macro-crate-rlib.rs +++ b/src/test/ui-fulldeps/macro-crate-rlib.rs @@ -1,4 +1,4 @@ -// aux-build:rlib_crate_test.rs +// aux-build:rlib-crate-test.rs // ignore-tidy-linelength // ignore-cross-compile gives a different error message diff --git a/src/test/ui-fulldeps/macro-crate-rlib.stderr b/src/test/ui-fulldeps/macro-crate-rlib.stderr index 0651cee56f772..a5a5456a316d1 100644 --- a/src/test/ui-fulldeps/macro-crate-rlib.stderr +++ b/src/test/ui-fulldeps/macro-crate-rlib.stderr @@ -6,4 +6,3 @@ LL | #![plugin(rlib_crate_test)] error: aborting due to previous error -For more information about this error, try `rustc --explain E0457`. diff --git a/src/test/ui-fulldeps/plugin-as-extern-crate.rs b/src/test/ui-fulldeps/plugin-as-extern-crate.rs index 37ac8dfa39101..c671ab581efbe 100644 --- a/src/test/ui-fulldeps/plugin-as-extern-crate.rs +++ b/src/test/ui-fulldeps/plugin-as-extern-crate.rs @@ -1,4 +1,4 @@ -// aux-build:attr_plugin_test.rs +// aux-build:attr-plugin-test.rs // ignore-cross-compile // // attr_plugin_test will not compile on a cross-compiled target because diff --git a/src/test/ui-fulldeps/plugin-as-extern-crate.stderr b/src/test/ui-fulldeps/plugin-as-extern-crate.stderr index 4a5a53980eb8a..ccc9580a60c29 100644 --- a/src/test/ui-fulldeps/plugin-as-extern-crate.stderr +++ b/src/test/ui-fulldeps/plugin-as-extern-crate.stderr @@ -1,7 +1,7 @@ error: compiler plugin used as an ordinary library --> $DIR/plugin-as-extern-crate.rs:10:1 | -LL | extern crate attr_plugin_test; //~ ERROR compiler plugin used as an ordinary library +LL | extern crate attr_plugin_test; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui-fulldeps/plugin-attr-register-deny.rs b/src/test/ui-fulldeps/plugin-attr-register-deny.rs index f9922f7f6060e..8be73e330abf7 100644 --- a/src/test/ui-fulldeps/plugin-attr-register-deny.rs +++ b/src/test/ui-fulldeps/plugin-attr-register-deny.rs @@ -1,4 +1,4 @@ -// aux-build:attr_plugin_test.rs +// aux-build:attr-plugin-test.rs // ignore-stage1 #![feature(plugin)] diff --git a/src/test/ui/E0501.ast.nll.stderr b/src/test/ui/E0501.ast.nll.stderr deleted file mode 100644 index 1d0102d100e4d..0000000000000 --- a/src/test/ui/E0501.ast.nll.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0501]: cannot borrow `*a` as mutable because previous closure requires unique access - --> $DIR/E0501.rs:18:23 - | -LL | let bar = || { - | -- closure construction occurs here -LL | inside_closure(a) - | - first borrow occurs due to use of `a` in closure -LL | }; -LL | outside_closure_1(a); //[ast]~ ERROR cannot borrow `*a` as mutable because previous closure requires unique access - | ^ second borrow occurs here -... -LL | drop(bar); - | --- first borrow later used here - -error[E0501]: cannot borrow `*a` as immutable because previous closure requires unique access - --> $DIR/E0501.rs:21:23 - | -LL | let bar = || { - | -- closure construction occurs here -LL | inside_closure(a) - | - first borrow occurs due to use of `a` in closure -... -LL | outside_closure_2(a); //[ast]~ ERROR cannot borrow `*a` as immutable because previous closure requires unique access - | ^ second borrow occurs here -... -LL | drop(bar); - | --- first borrow later used here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0501`. diff --git a/src/test/ui/E0501.ast.stderr b/src/test/ui/E0501.ast.stderr deleted file mode 100644 index e0bd7a08d7f5b..0000000000000 --- a/src/test/ui/E0501.ast.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0501]: cannot borrow `*a` as mutable because previous closure requires unique access - --> $DIR/E0501.rs:18:23 - | -LL | let bar = || { - | -- closure construction occurs here -LL | inside_closure(a) - | - previous borrow occurs due to use of `a` in closure -LL | }; -LL | outside_closure_1(a); //[ast]~ ERROR cannot borrow `*a` as mutable because previous closure requires unique access - | ^ borrow occurs here -... -LL | } - | - borrow from closure ends here - -error[E0501]: cannot borrow `*a` as immutable because previous closure requires unique access - --> $DIR/E0501.rs:21:23 - | -LL | let bar = || { - | -- closure construction occurs here -LL | inside_closure(a) - | - previous borrow occurs due to use of `a` in closure -... -LL | outside_closure_2(a); //[ast]~ ERROR cannot borrow `*a` as immutable because previous closure requires unique access - | ^ borrow occurs here -... -LL | } - | - borrow from closure ends here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0501`. diff --git a/src/test/ui/E0501.mir.stderr b/src/test/ui/E0501.mir.stderr deleted file mode 100644 index 1d0102d100e4d..0000000000000 --- a/src/test/ui/E0501.mir.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0501]: cannot borrow `*a` as mutable because previous closure requires unique access - --> $DIR/E0501.rs:18:23 - | -LL | let bar = || { - | -- closure construction occurs here -LL | inside_closure(a) - | - first borrow occurs due to use of `a` in closure -LL | }; -LL | outside_closure_1(a); //[ast]~ ERROR cannot borrow `*a` as mutable because previous closure requires unique access - | ^ second borrow occurs here -... -LL | drop(bar); - | --- first borrow later used here - -error[E0501]: cannot borrow `*a` as immutable because previous closure requires unique access - --> $DIR/E0501.rs:21:23 - | -LL | let bar = || { - | -- closure construction occurs here -LL | inside_closure(a) - | - first borrow occurs due to use of `a` in closure -... -LL | outside_closure_2(a); //[ast]~ ERROR cannot borrow `*a` as immutable because previous closure requires unique access - | ^ second borrow occurs here -... -LL | drop(bar); - | --- first borrow later used here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0501`. diff --git a/src/test/ui/E0501.rs b/src/test/ui/E0501.rs deleted file mode 100644 index a710e23a67049..0000000000000 --- a/src/test/ui/E0501.rs +++ /dev/null @@ -1,28 +0,0 @@ -// ignore-tidy-linelength -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - -fn inside_closure(x: &mut i32) { -} - -fn outside_closure_1(x: &mut i32) { -} - -fn outside_closure_2(x: &i32) { -} - -fn foo(a: &mut i32) { - let bar = || { - inside_closure(a) - }; - outside_closure_1(a); //[ast]~ ERROR cannot borrow `*a` as mutable because previous closure requires unique access - //[mir]~^ ERROR cannot borrow `*a` as mutable because previous closure requires unique access - - outside_closure_2(a); //[ast]~ ERROR cannot borrow `*a` as immutable because previous closure requires unique access - //[mir]~^ ERROR cannot borrow `*a` as immutable because previous closure requires unique access - - drop(bar); -} - -fn main() { -} diff --git a/src/test/ui/E0506.ast.nll.stderr b/src/test/ui/E0506.ast.nll.stderr deleted file mode 100644 index b66c1d129a79a..0000000000000 --- a/src/test/ui/E0506.ast.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0506]: cannot assign to `fancy_num` because it is borrowed - --> $DIR/E0506.rs:11:5 - | -LL | let fancy_ref = &fancy_num; - | ---------- borrow of `fancy_num` occurs here -LL | fancy_num = FancyNum { num: 6 }; //[ast]~ ERROR E0506 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `fancy_num` occurs here -... -LL | println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num); - | ------------- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/E0506.ast.stderr b/src/test/ui/E0506.ast.stderr deleted file mode 100644 index d459dcdc21994..0000000000000 --- a/src/test/ui/E0506.ast.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0506]: cannot assign to `fancy_num` because it is borrowed - --> $DIR/E0506.rs:11:5 - | -LL | let fancy_ref = &fancy_num; - | --------- borrow of `fancy_num` occurs here -LL | fancy_num = FancyNum { num: 6 }; //[ast]~ ERROR E0506 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `fancy_num` occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/E0506.mir.stderr b/src/test/ui/E0506.mir.stderr deleted file mode 100644 index b66c1d129a79a..0000000000000 --- a/src/test/ui/E0506.mir.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0506]: cannot assign to `fancy_num` because it is borrowed - --> $DIR/E0506.rs:11:5 - | -LL | let fancy_ref = &fancy_num; - | ---------- borrow of `fancy_num` occurs here -LL | fancy_num = FancyNum { num: 6 }; //[ast]~ ERROR E0506 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `fancy_num` occurs here -... -LL | println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num); - | ------------- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/E0506.rs b/src/test/ui/E0506.rs deleted file mode 100644 index 04aaa008b5a2e..0000000000000 --- a/src/test/ui/E0506.rs +++ /dev/null @@ -1,15 +0,0 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy_num = FancyNum { num: 5 }; - let fancy_ref = &fancy_num; - fancy_num = FancyNum { num: 6 }; //[ast]~ ERROR E0506 - //[mir]~^ ERROR [E0506] - - println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num); -} diff --git a/src/test/ui/E0508-fail.ast.nll.stderr b/src/test/ui/E0508-fail.ast.nll.stderr deleted file mode 100644 index 4cc1cf89d6cb9..0000000000000 --- a/src/test/ui/E0508-fail.ast.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array - --> $DIR/E0508-fail.rs:8:18 - | -LL | let _value = array[0]; //[ast]~ ERROR [E0508] - | ^^^^^^^^ - | | - | cannot move out of here - | help: consider borrowing here: `&array[0]` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/E0508-fail.ast.stderr b/src/test/ui/E0508-fail.ast.stderr deleted file mode 100644 index 57959c96f63ec..0000000000000 --- a/src/test/ui/E0508-fail.ast.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array - --> $DIR/E0508-fail.rs:8:18 - | -LL | let _value = array[0]; //[ast]~ ERROR [E0508] - | ^^^^^^^^ - | | - | cannot move out of here - | help: consider using a reference instead: `&array[0]` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/E0508-fail.mir.stderr b/src/test/ui/E0508-fail.mir.stderr deleted file mode 100644 index 4cc1cf89d6cb9..0000000000000 --- a/src/test/ui/E0508-fail.mir.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array - --> $DIR/E0508-fail.rs:8:18 - | -LL | let _value = array[0]; //[ast]~ ERROR [E0508] - | ^^^^^^^^ - | | - | cannot move out of here - | help: consider borrowing here: `&array[0]` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/E0508-fail.rs b/src/test/ui/E0508-fail.rs deleted file mode 100644 index 20eac6cd3519f..0000000000000 --- a/src/test/ui/E0508-fail.rs +++ /dev/null @@ -1,10 +0,0 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - -struct NonCopy; - -fn main() { - let array = [NonCopy; 1]; - let _value = array[0]; //[ast]~ ERROR [E0508] - //[mir]~^ ERROR [E0508] -} diff --git a/src/test/ui/E0508.ast.stderr b/src/test/ui/E0508.ast.stderr deleted file mode 100644 index 5878b795b771c..0000000000000 --- a/src/test/ui/E0508.ast.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array - --> $DIR/E0508.rs:18:18 - | -LL | let _value = array[0]; //[ast]~ ERROR [E0508] - | ^^^^^^^^ - | | - | cannot move out of here - | help: consider using a reference instead: `&array[0]` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/E0508.mir.stderr b/src/test/ui/E0508.mir.stderr deleted file mode 100644 index 5878b795b771c..0000000000000 --- a/src/test/ui/E0508.mir.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array - --> $DIR/E0508.rs:18:18 - | -LL | let _value = array[0]; //[ast]~ ERROR [E0508] - | ^^^^^^^^ - | | - | cannot move out of here - | help: consider using a reference instead: `&array[0]` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/E0508.nll.stderr b/src/test/ui/E0508.nll.stderr deleted file mode 100644 index 82fdce2112ecf..0000000000000 --- a/src/test/ui/E0508.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array - --> $DIR/E0508.rs:5:18 - | -LL | let _value = array[0]; //~ ERROR [E0508] - | ^^^^^^^^ - | | - | cannot move out of here - | help: consider borrowing here: `&array[0]` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/E0508.stderr b/src/test/ui/E0508.stderr deleted file mode 100644 index 1e7b4071d5d79..0000000000000 --- a/src/test/ui/E0508.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array - --> $DIR/E0508.rs:5:18 - | -LL | let _value = array[0]; //~ ERROR [E0508] - | ^^^^^^^^ - | | - | cannot move out of here - | help: consider using a reference instead: `&array[0]` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/E0594.ast.nll.stderr b/src/test/ui/E0594.ast.nll.stderr deleted file mode 100644 index 54681a29b81bc..0000000000000 --- a/src/test/ui/E0594.ast.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0594]: cannot assign to immutable static item `NUM` - --> $DIR/E0594.rs:7:5 - | -LL | NUM = 20; //[ast]~ ERROR E0594 - | ^^^^^^^^ cannot assign - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/E0594.ast.stderr b/src/test/ui/E0594.ast.stderr deleted file mode 100644 index 4eb9ba133ae55..0000000000000 --- a/src/test/ui/E0594.ast.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0594]: cannot assign to immutable static item - --> $DIR/E0594.rs:7:5 - | -LL | NUM = 20; //[ast]~ ERROR E0594 - | ^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/E0594.mir.stderr b/src/test/ui/E0594.mir.stderr deleted file mode 100644 index 54681a29b81bc..0000000000000 --- a/src/test/ui/E0594.mir.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0594]: cannot assign to immutable static item `NUM` - --> $DIR/E0594.rs:7:5 - | -LL | NUM = 20; //[ast]~ ERROR E0594 - | ^^^^^^^^ cannot assign - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/E0594.rs b/src/test/ui/E0594.rs deleted file mode 100644 index a8ca2fe61613a..0000000000000 --- a/src/test/ui/E0594.rs +++ /dev/null @@ -1,9 +0,0 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - -static NUM: i32 = 18; - -fn main() { - NUM = 20; //[ast]~ ERROR E0594 - //[mir]~^ ERROR cannot assign to immutable static item `NUM` -} diff --git a/src/test/ui/E0596.ast.nll.stderr b/src/test/ui/E0596.ast.nll.stderr deleted file mode 100644 index e5da6649f5aaf..0000000000000 --- a/src/test/ui/E0596.ast.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/E0596.rs:6:13 - | -LL | let x = 1; - | - help: consider changing this to be mutable: `mut x` -LL | let y = &mut x; //[ast]~ ERROR [E0596] - | ^^^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/E0596.ast.stderr b/src/test/ui/E0596.ast.stderr deleted file mode 100644 index 6e65cc855e7f1..0000000000000 --- a/src/test/ui/E0596.ast.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow immutable local variable `x` as mutable - --> $DIR/E0596.rs:6:18 - | -LL | let x = 1; - | - help: make this binding mutable: `mut x` -LL | let y = &mut x; //[ast]~ ERROR [E0596] - | ^ cannot borrow mutably - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/E0596.mir.stderr b/src/test/ui/E0596.mir.stderr deleted file mode 100644 index e5da6649f5aaf..0000000000000 --- a/src/test/ui/E0596.mir.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/E0596.rs:6:13 - | -LL | let x = 1; - | - help: consider changing this to be mutable: `mut x` -LL | let y = &mut x; //[ast]~ ERROR [E0596] - | ^^^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/E0596.rs b/src/test/ui/E0596.rs deleted file mode 100644 index 3ea2d64a404c7..0000000000000 --- a/src/test/ui/E0596.rs +++ /dev/null @@ -1,8 +0,0 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - -fn main() { - let x = 1; - let y = &mut x; //[ast]~ ERROR [E0596] - //[mir]~^ ERROR [E0596] -} diff --git a/src/test/ui/E0642.stderr b/src/test/ui/E0642.stderr deleted file mode 100644 index 4c82a6cbd21b4..0000000000000 --- a/src/test/ui/E0642.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0642]: patterns aren't allowed in methods without bodies - --> $DIR/E0642.rs:5:12 - | -LL | fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies - | ^^^^^^ -help: give this argument a name or use an underscore to ignore it - | -LL | fn foo(_: (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies - | ^ - -error[E0642]: patterns aren't allowed in methods without bodies - --> $DIR/E0642.rs:7:12 - | -LL | fn bar((x, y): (i32, i32)) {} //~ ERROR patterns aren't allowed in methods without bodies - | ^^^^^^ -help: give this argument a name or use an underscore to ignore it - | -LL | fn bar(_: (i32, i32)) {} //~ ERROR patterns aren't allowed in methods without bodies - | ^ - -error[E0642]: patterns aren't allowed in methods without bodies - --> $DIR/E0642.rs:9:15 - | -LL | fn method(S { .. }: S) {} //~ ERROR patterns aren't allowed in methods without bodies - | ^^^^^^^^ -help: give this argument a name or use an underscore to ignore it - | -LL | fn method(_: S) {} //~ ERROR patterns aren't allowed in methods without bodies - | ^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0642`. diff --git a/src/test/ui/E0661.stderr b/src/test/ui/E0661.stderr deleted file mode 100644 index 1f41f89608fdf..0000000000000 --- a/src/test/ui/E0661.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0661]: output operand constraint lacks '=' or '+' - --> $DIR/E0661.rs:5:18 - | -LL | asm!("nop" : "r"(a)); - | ^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0661`. diff --git a/src/test/ui/E0662.stderr b/src/test/ui/E0662.stderr deleted file mode 100644 index 2156b43973fc3..0000000000000 --- a/src/test/ui/E0662.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0662]: input operand constraint contains '=' - --> $DIR/E0662.rs:6:12 - | -LL | : "=test"("a") //~ ERROR E0662 - | ^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0662`. diff --git a/src/test/ui/E0663.stderr b/src/test/ui/E0663.stderr deleted file mode 100644 index 66667a6dc884f..0000000000000 --- a/src/test/ui/E0663.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0663]: input operand constraint contains '+' - --> $DIR/E0663.rs:6:12 - | -LL | : "+test"("a") //~ ERROR E0663 - | ^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0663`. diff --git a/src/test/ui/E0664.stderr b/src/test/ui/E0664.stderr deleted file mode 100644 index 972b10379d430..0000000000000 --- a/src/test/ui/E0664.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0664]: clobber should not be surrounded by braces - --> $DIR/E0664.rs:7:12 - | -LL | : "{eax}" //~ ERROR E0664 - | ^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0664`. diff --git a/src/test/ui/E0665.stderr b/src/test/ui/E0665.stderr deleted file mode 100644 index e044d60653121..0000000000000 --- a/src/test/ui/E0665.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0665]: `Default` cannot be derived for enums, only structs - --> $DIR/E0665.rs:1:10 - | -LL | #[derive(Default)] //~ ERROR E0665 - | ^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0665`. diff --git a/src/test/ui/absolute-paths-in-nested-use-groups.stderr b/src/test/ui/absolute-paths-in-nested-use-groups.stderr index 72ad0509e46a9..e41590ac45eed 100644 --- a/src/test/ui/absolute-paths-in-nested-use-groups.stderr +++ b/src/test/ui/absolute-paths-in-nested-use-groups.stderr @@ -1,19 +1,19 @@ error[E0433]: failed to resolve: crate root in paths can only be used in start position --> $DIR/absolute-paths-in-nested-use-groups.rs:6:5 | -LL | ::bar, //~ ERROR crate root in paths can only be used in start position +LL | ::bar, | ^ crate root in paths can only be used in start position error[E0433]: failed to resolve: `super` in paths can only be used in start position --> $DIR/absolute-paths-in-nested-use-groups.rs:7:5 | -LL | super::bar, //~ ERROR `super` in paths can only be used in start position +LL | super::bar, | ^^^^^ `super` in paths can only be used in start position error[E0433]: failed to resolve: `self` in paths can only be used in start position --> $DIR/absolute-paths-in-nested-use-groups.rs:8:5 | -LL | self::bar, //~ ERROR `self` in paths can only be used in start position +LL | self::bar, | ^^^^ `self` in paths can only be used in start position error: aborting due to 3 previous errors diff --git a/src/test/ui/access-mode-in-closures.nll.stderr b/src/test/ui/access-mode-in-closures.nll.stderr deleted file mode 100644 index 0c9a62351d20d..0000000000000 --- a/src/test/ui/access-mode-in-closures.nll.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/access-mode-in-closures.rs:8:15 - | -LL | match *s { S(v) => v } //~ ERROR cannot move out - | ^^ - data moved here - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `s` - | -note: move occurs because `v` has type `std::vec::Vec`, which does not implement the `Copy` trait - --> $DIR/access-mode-in-closures.rs:8:22 - | -LL | match *s { S(v) => v } //~ ERROR cannot move out - | ^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/access-mode-in-closures.stderr b/src/test/ui/access-mode-in-closures.stderr index 0423c713531f7..349e3f4a836a0 100644 --- a/src/test/ui/access-mode-in-closures.stderr +++ b/src/test/ui/access-mode-in-closures.stderr @@ -1,10 +1,12 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `s.0` which is behind a shared reference --> $DIR/access-mode-in-closures.rs:8:15 | -LL | match *s { S(v) => v } //~ ERROR cannot move out - | ^^ - hint: to prevent move, use `ref v` or `ref mut v` - | | - | cannot move out of borrowed content +LL | match *s { S(v) => v } + | ^^ - + | | | + | | data moved here + | | move occurs because `v` has type `std::vec::Vec`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*s` error: aborting due to previous error diff --git a/src/test/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr b/src/test/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr index 8efbf7f78d91e..34e09da45ad53 100644 --- a/src/test/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr +++ b/src/test/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr @@ -1,13 +1,13 @@ error: return type should be `!` --> $DIR/alloc-error-handler-bad-signature-1.rs:12:6 | -LL | ) -> () //~ ERROR return type should be `!` +LL | ) -> () | ^^ error: argument should be `Layout` --> $DIR/alloc-error-handler-bad-signature-1.rs:11:11 | -LL | info: &Layout, //~ ERROR argument should be `Layout` +LL | info: &Layout, | ^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr b/src/test/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr index 95ef9a0522c34..85544b0c3849e 100644 --- a/src/test/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr +++ b/src/test/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr @@ -1,13 +1,13 @@ error: return type should be `!` --> $DIR/alloc-error-handler-bad-signature-2.rs:12:3 | -LL | ) { //~ ERROR return type should be `!` +LL | ) { | ^ error: argument should be `Layout` --> $DIR/alloc-error-handler-bad-signature-2.rs:11:11 | -LL | info: Layout, //~ ERROR argument should be `Layout` +LL | info: Layout, | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr b/src/test/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr index 284802f21b9d3..8575e7508f125 100644 --- a/src/test/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr +++ b/src/test/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr @@ -1,7 +1,7 @@ error: function should have one argument --> $DIR/alloc-error-handler-bad-signature-3.rs:10:1 | -LL | fn oom() -> ! { //~ ERROR function should have one argument +LL | fn oom() -> ! { | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/allocator-submodule.rs b/src/test/ui/allocator-submodule.rs index a1cca50ba9817..7a8d86b8da18c 100644 --- a/src/test/ui/allocator-submodule.rs +++ b/src/test/ui/allocator-submodule.rs @@ -1,8 +1,6 @@ // Tests that it is possible to create a global allocator in a submodule, rather than in the crate // root. -#![feature(alloc, allocator_api, global_allocator)] - extern crate alloc; use std::{ diff --git a/src/test/ui/allocator-submodule.stderr b/src/test/ui/allocator-submodule.stderr index 32c7211cd1641..91c7c0f6b8e24 100644 --- a/src/test/ui/allocator-submodule.stderr +++ b/src/test/ui/allocator-submodule.stderr @@ -1,7 +1,7 @@ error: `global_allocator` cannot be used in submodules - --> $DIR/allocator-submodule.rs:27:5 + --> $DIR/allocator-submodule.rs:25:5 | -LL | static MY_HEAP: MyAlloc = MyAlloc; //~ ERROR global_allocator +LL | static MY_HEAP: MyAlloc = MyAlloc; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/allocator/function-allocator.stderr b/src/test/ui/allocator/function-allocator.stderr index ecb6e4d4ecde2..5e47b0f0cc7ac 100644 --- a/src/test/ui/allocator/function-allocator.stderr +++ b/src/test/ui/allocator/function-allocator.stderr @@ -1,7 +1,7 @@ error: allocators must be statics --> $DIR/function-allocator.rs:2:1 | -LL | fn foo() {} //~ ERROR: allocators must be statics +LL | fn foo() {} | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/allocator/two-allocators.rs b/src/test/ui/allocator/two-allocators.rs index c967a45c7b485..10fb03c39302b 100644 --- a/src/test/ui/allocator/two-allocators.rs +++ b/src/test/ui/allocator/two-allocators.rs @@ -7,4 +7,3 @@ static B: System = System; //~^ ERROR: cannot define more than one #[global_allocator] fn main() {} - diff --git a/src/test/ui/allocator/two-allocators2.rs b/src/test/ui/allocator/two-allocators2.rs index b7a07cc274e1d..96da780e4a254 100644 --- a/src/test/ui/allocator/two-allocators2.rs +++ b/src/test/ui/allocator/two-allocators2.rs @@ -10,4 +10,3 @@ use std::alloc::System; static A: System = System; fn main() {} - diff --git a/src/test/ui/always-inhabited-union-ref.stderr b/src/test/ui/always-inhabited-union-ref.stderr index 212f5d7c525f5..792ab6f59a439 100644 --- a/src/test/ui/always-inhabited-union-ref.stderr +++ b/src/test/ui/always-inhabited-union-ref.stderr @@ -4,11 +4,7 @@ error[E0004]: non-exhaustive patterns: type `&'static !` is non-empty LL | match uninhab_ref() { | ^^^^^^^^^^^^^ | -help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - --> $DIR/always-inhabited-union-ref.rs:23:11 - | -LL | match uninhab_ref() { - | ^^^^^^^^^^^^^ + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: type `Foo` is non-empty --> $DIR/always-inhabited-union-ref.rs:27:11 @@ -16,11 +12,7 @@ error[E0004]: non-exhaustive patterns: type `Foo` is non-empty LL | match uninhab_union() { | ^^^^^^^^^^^^^^^ | -help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - --> $DIR/always-inhabited-union-ref.rs:27:11 - | -LL | match uninhab_union() { - | ^^^^^^^^^^^^^^^ + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to 2 previous errors diff --git a/src/test/ui/annotate-snippet/missing-type.rs b/src/test/ui/annotate-snippet/missing-type.rs new file mode 100644 index 0000000000000..d0814a9537d0c --- /dev/null +++ b/src/test/ui/annotate-snippet/missing-type.rs @@ -0,0 +1,5 @@ +// compile-flags: --error-format human-annotate-rs + +pub fn main() { + let x: Iter; //~ ERROR cannot find type `Iter` in this scope +} diff --git a/src/test/ui/annotate-snippet/missing-type.stderr b/src/test/ui/annotate-snippet/missing-type.stderr new file mode 100644 index 0000000000000..8857ae7d85034 --- /dev/null +++ b/src/test/ui/annotate-snippet/missing-type.stderr @@ -0,0 +1,6 @@ +error[E0412]: cannot find type `Iter` in this scope + --> $DIR/missing-type.rs:4:11 + | +4 | let x: Iter; + | ^^^^ not found in this scope + | diff --git a/src/test/ui/anon-params-denied-2018.rs b/src/test/ui/anon-params-denied-2018.rs index 5e77aa8fbb923..abff8275064e2 100644 --- a/src/test/ui/anon-params-denied-2018.rs +++ b/src/test/ui/anon-params-denied-2018.rs @@ -6,7 +6,13 @@ trait T { fn foo(i32); //~ expected one of `:` or `@`, found `)` fn bar_with_default_impl(String, String) {} - //~^ ERROR expected one of `:` or `@`, found `,` + //~^ ERROR expected one of `:` + //~| ERROR expected one of `:` + + // do not complain about missing `b` + fn baz(a:usize, b, c: usize) -> usize { //~ ERROR expected one of `:` + a + b + c + } } fn main() {} diff --git a/src/test/ui/anon-params-denied-2018.stderr b/src/test/ui/anon-params-denied-2018.stderr index dd9e933542fa7..438bcf4274daa 100644 --- a/src/test/ui/anon-params-denied-2018.stderr +++ b/src/test/ui/anon-params-denied-2018.stderr @@ -1,22 +1,66 @@ error: expected one of `:` or `@`, found `)` --> $DIR/anon-params-denied-2018.rs:6:15 | -LL | fn foo(i32); //~ expected one of `:` or `@`, found `)` - | ---^ expected one of `:` or `@` here - | | - | help: explicitly ignore parameter: `_: i32` +LL | fn foo(i32); + | ^ expected one of `:` or `@` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this was a parameter name, give it a type + | +LL | fn foo(i32: TypeName); + | ^^^^^^^^^^^^^ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn foo(_: i32); + | ^^^^^^ error: expected one of `:` or `@`, found `,` --> $DIR/anon-params-denied-2018.rs:8:36 | LL | fn bar_with_default_impl(String, String) {} - | ------^ expected one of `:` or `@` here - | | - | help: explicitly ignore parameter: `_: String` + | ^ expected one of `:` or `@` here + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this was a parameter name, give it a type + | +LL | fn bar_with_default_impl(String: TypeName, String) {} + | ^^^^^^^^^^^^^^^^ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn bar_with_default_impl(_: String, String) {} + | ^^^^^^^^^ + +error: expected one of `:` or `@`, found `)` + --> $DIR/anon-params-denied-2018.rs:8:44 + | +LL | fn bar_with_default_impl(String, String) {} + | ^ expected one of `:` or `@` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this was a parameter name, give it a type + | +LL | fn bar_with_default_impl(String, String: TypeName) {} + | ^^^^^^^^^^^^^^^^ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn bar_with_default_impl(String, _: String) {} + | ^^^^^^^^^ + +error: expected one of `:` or `@`, found `,` + --> $DIR/anon-params-denied-2018.rs:13:22 + | +LL | fn baz(a:usize, b, c: usize) -> usize { + | ^ expected one of `:` or `@` here + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this was a parameter name, give it a type + | +LL | fn baz(a:usize, b: TypeName, c: usize) -> usize { + | ^^^^^^^^^^^ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn baz(a:usize, _: b, c: usize) -> usize { + | ^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors diff --git a/src/test/ui/anon-params-deprecated.stderr b/src/test/ui/anon-params-deprecated.stderr index 691c3159a5261..e97dbc15f9cde 100644 --- a/src/test/ui/anon-params-deprecated.stderr +++ b/src/test/ui/anon-params-deprecated.stderr @@ -1,7 +1,7 @@ warning: anonymous parameters are deprecated and will be removed in the next edition. --> $DIR/anon-params-deprecated.rs:9:12 | -LL | fn foo(i32); //~ WARNING anonymous parameters are deprecated +LL | fn foo(i32); | ^^^ help: Try naming the parameter or explicitly ignoring it: `_: i32` | note: lint level defined here diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.rs b/src/test/ui/anonymous-higher-ranked-lifetime.rs index 2e2a124db9a5d..8a1744ed5f8ae 100644 --- a/src/test/ui/anonymous-higher-ranked-lifetime.rs +++ b/src/test/ui/anonymous-higher-ranked-lifetime.rs @@ -31,11 +31,11 @@ fn f4(_: F) where F: for<'r> Fn(&(), &'r ()) {} fn f5(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} // Nested -fn g1(_: F) where F: Fn(&(), Box) {} +fn g1(_: F) where F: Fn(&(), Box) {} fn g2(_: F) where F: Fn(&(), fn(&())) {} -fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} +fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} fn g4(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} // Mixed -fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} -fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} +fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} +fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr index 378f352cb9228..0ca3ca8437463 100644 --- a/src/test/ui/anonymous-higher-ranked-lifetime.stderr +++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr @@ -1,7 +1,7 @@ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:2:5 | -LL | f1(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | f1(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r, 's> fn(&'r (), &'s ()) -> _` @@ -15,7 +15,7 @@ LL | fn f1(_: F) where F: Fn(&(), &()) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:2:5 | -LL | f1(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | f1(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&(), &()) -> _` @@ -29,7 +29,7 @@ LL | fn f1(_: F) where F: Fn(&(), &()) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5 | -LL | f2(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | f2(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'a, 'r> fn(&'a (), &'r ()) -> _` @@ -43,7 +43,7 @@ LL | fn f2(_: F) where F: for<'a> Fn(&'a (), &()) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5 | -LL | f2(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | f2(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&'a (), &()) -> _` @@ -57,7 +57,7 @@ LL | fn f2(_: F) where F: for<'a> Fn(&'a (), &()) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 | -LL | f3(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | f3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r> fn(&(), &'r ()) -> _` @@ -71,7 +71,7 @@ LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 | -LL | f3(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | f3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&(), &()) -> _` @@ -85,7 +85,7 @@ LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 | -LL | f4(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | f4(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'s, 'r> fn(&'s (), &'r ()) -> _` @@ -99,7 +99,7 @@ LL | fn f4(_: F) where F: for<'r> Fn(&(), &'r ()) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 | -LL | f4(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | f4(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&(), &'r ()) -> _` @@ -113,7 +113,7 @@ LL | fn f4(_: F) where F: for<'r> Fn(&(), &'r ()) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 | -LL | f5(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | f5(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r> fn(&'r (), &'r ()) -> _` @@ -127,7 +127,7 @@ LL | fn f5(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 | -LL | f5(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | f5(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&'r (), &'r ()) -> _` @@ -141,7 +141,7 @@ LL | fn f5(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 | -LL | g1(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | g1(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>) -> _` @@ -149,13 +149,13 @@ LL | g1(|_: (), _: ()| {}); //~ ERROR type mismatch note: required by `g1` --> $DIR/anonymous-higher-ranked-lifetime.rs:34:1 | -LL | fn g1(_: F) where F: Fn(&(), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn g1(_: F) where F: Fn(&(), Box) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 | -LL | g1(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | g1(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _` @@ -163,13 +163,13 @@ LL | g1(|_: (), _: ()| {}); //~ ERROR type mismatch note: required by `g1` --> $DIR/anonymous-higher-ranked-lifetime.rs:34:1 | -LL | fn g1(_: F) where F: Fn(&(), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn g1(_: F) where F: Fn(&(), Box) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5 | -LL | g2(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | g2(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r> fn(&'r (), for<'s> fn(&'s ())) -> _` @@ -183,7 +183,7 @@ LL | fn g2(_: F) where F: Fn(&(), fn(&())) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5 | -LL | g2(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | g2(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&(), for<'r> fn(&'r ())) -> _` @@ -197,7 +197,7 @@ LL | fn g2(_: F) where F: Fn(&(), fn(&())) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5 | -LL | g3(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | g3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'s> fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _` @@ -205,13 +205,13 @@ LL | g3(|_: (), _: ()| {}); //~ ERROR type mismatch note: required by `g3` --> $DIR/anonymous-higher-ranked-lifetime.rs:36:1 | -LL | fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5 | -LL | g3(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | g3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _` @@ -219,13 +219,13 @@ LL | g3(|_: (), _: ()| {}); //~ ERROR type mismatch note: required by `g3` --> $DIR/anonymous-higher-ranked-lifetime.rs:36:1 | -LL | fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5 | -LL | g4(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | g4(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'s> fn(&'s (), for<'r> fn(&'r ())) -> _` @@ -239,7 +239,7 @@ LL | fn g4(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5 | -LL | g4(|_: (), _: ()| {}); //~ ERROR type mismatch +LL | g4(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&(), for<'r> fn(&'r ())) -> _` @@ -253,7 +253,7 @@ LL | fn g4(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5 | -LL | h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch +LL | h1(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | | expected signature of `for<'r, 's> fn(&'r (), std::boxed::Box<(dyn for<'t0> std::ops::Fn(&'t0 ()) + 'static)>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _` @@ -261,13 +261,13 @@ LL | h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch note: required by `h1` --> $DIR/anonymous-higher-ranked-lifetime.rs:40:1 | -LL | fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5 | -LL | h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch +LL | h1(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | | expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &(), for<'r, 's> fn(&'r (), &'s ())) -> _` @@ -275,13 +275,13 @@ LL | h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch note: required by `h1` --> $DIR/anonymous-higher-ranked-lifetime.rs:40:1 | -LL | fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5 | -LL | h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch +LL | h2(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | | expected signature of `for<'r, 't0> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _` @@ -289,13 +289,13 @@ LL | h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch note: required by `h2` --> $DIR/anonymous-higher-ranked-lifetime.rs:41:1 | -LL | fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5 | -LL | h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch +LL | h2(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | | expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &'t0 (), for<'r, 's> fn(&'r (), &'s ())) -> _` @@ -303,9 +303,8 @@ LL | h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch note: required by `h2` --> $DIR/anonymous-higher-ranked-lifetime.rs:41:1 | -LL | fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 22 previous errors -For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/array-break-length.rs b/src/test/ui/array-break-length.rs index ab15ce6e8d8e0..2696aea5e8993 100644 --- a/src/test/ui/array-break-length.rs +++ b/src/test/ui/array-break-length.rs @@ -1,9 +1,11 @@ fn main() { loop { |_: [_; break]| {} //~ ERROR: `break` outside of loop + //~^ ERROR mismatched types } loop { |_: [_; continue]| {} //~ ERROR: `continue` outside of loop + //~^ ERROR mismatched types } } diff --git a/src/test/ui/array-break-length.stderr b/src/test/ui/array-break-length.stderr index bba4753046109..0e0dc8f623e68 100644 --- a/src/test/ui/array-break-length.stderr +++ b/src/test/ui/array-break-length.stderr @@ -1,15 +1,34 @@ error[E0268]: `break` outside of loop --> $DIR/array-break-length.rs:3:17 | -LL | |_: [_; break]| {} //~ ERROR: `break` outside of loop +LL | |_: [_; break]| {} | ^^^^^ cannot break outside of a loop error[E0268]: `continue` outside of loop - --> $DIR/array-break-length.rs:7:17 + --> $DIR/array-break-length.rs:8:17 | -LL | |_: [_; continue]| {} //~ ERROR: `continue` outside of loop +LL | |_: [_; continue]| {} | ^^^^^^^^ cannot break outside of a loop -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/array-break-length.rs:3:9 + | +LL | |_: [_; break]| {} + | ^^^^^^^^^^^^^^^^^^ expected (), found closure + | + = note: expected type `()` + found type `[closure@$DIR/array-break-length.rs:3:9: 3:27]` + +error[E0308]: mismatched types + --> $DIR/array-break-length.rs:8:9 + | +LL | |_: [_; continue]| {} + | ^^^^^^^^^^^^^^^^^^^^^ expected (), found closure + | + = note: expected type `()` + found type `[closure@$DIR/array-break-length.rs:8:9: 8:30]` + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0268`. +Some errors have detailed explanations: E0268, E0308. +For more information about an error, try `rustc --explain E0268`. diff --git a/src/test/ui/array_const_index-0.stderr b/src/test/ui/array_const_index-0.stderr index dfc89e0ae86ad..78d456d6c2e0e 100644 --- a/src/test/ui/array_const_index-0.stderr +++ b/src/test/ui/array_const_index-0.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error - --> $DIR/array_const_index-0.rs:2:1 + --> $DIR/array_const_index-0.rs:2:16 | LL | const B: i32 = (&A)[1]; - | ^^^^^^^^^^^^^^^-------^ + | ---------------^^^^^^^- | | | index out of bounds: the len is 0 but the index is 1 | diff --git a/src/test/ui/array_const_index-1.stderr b/src/test/ui/array_const_index-1.stderr index 3e912fad53a5f..3e7360f935bb9 100644 --- a/src/test/ui/array_const_index-1.stderr +++ b/src/test/ui/array_const_index-1.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error - --> $DIR/array_const_index-1.rs:2:1 + --> $DIR/array_const_index-1.rs:2:16 | LL | const B: i32 = A[1]; - | ^^^^^^^^^^^^^^^----^ + | ---------------^^^^- | | | index out of bounds: the len is 0 but the index is 1 | diff --git a/src/test/ui/asm/asm-bad-clobber.stderr b/src/test/ui/asm/asm-bad-clobber.stderr index a279421241fac..15a14e776babd 100644 --- a/src/test/ui/asm/asm-bad-clobber.stderr +++ b/src/test/ui/asm/asm-bad-clobber.stderr @@ -6,4 +6,3 @@ LL | asm!("xor %eax, %eax" : : : "{eax}"); error: aborting due to previous error -For more information about this error, try `rustc --explain E0664`. diff --git a/src/test/ui/asm/asm-in-bad-modifier.stderr b/src/test/ui/asm/asm-in-bad-modifier.stderr index 339875390185d..b71eb8649bae0 100644 --- a/src/test/ui/asm/asm-in-bad-modifier.stderr +++ b/src/test/ui/asm/asm-in-bad-modifier.stderr @@ -1,16 +1,14 @@ error[E0662]: input operand constraint contains '=' --> $DIR/asm-in-bad-modifier.rs:23:39 | -LL | asm!("mov $1, $0" : "=r"(x) : "=r"(5)); //~ ERROR operand constraint contains '=' +LL | asm!("mov $1, $0" : "=r"(x) : "=r"(5)); | ^^^^ error[E0663]: input operand constraint contains '+' --> $DIR/asm-in-bad-modifier.rs:24:39 | -LL | asm!("mov $1, $0" : "=r"(y) : "+r"(5)); //~ ERROR operand constraint contains '+' +LL | asm!("mov $1, $0" : "=r"(y) : "+r"(5)); | ^^^^ error: aborting due to 2 previous errors -Some errors occurred: E0662, E0663. -For more information about an error, try `rustc --explain E0662`. diff --git a/src/test/ui/asm/asm-misplaced-option.rs b/src/test/ui/asm/asm-misplaced-option.rs index 5c202a158f401..14ff4c2e981b3 100644 --- a/src/test/ui/asm/asm-misplaced-option.rs +++ b/src/test/ui/asm/asm-misplaced-option.rs @@ -1,3 +1,4 @@ +// check-pass // ignore-android // ignore-arm // ignore-aarch64 @@ -11,14 +12,11 @@ // ignore-mips // ignore-mips64 -// compile-pass -// skip-codegen #![feature(asm)] -#![allow(dead_code, non_upper_case_globals)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub fn main() { +fn main() { // assignment not dead let mut x: isize = 0; unsafe { diff --git a/src/test/ui/asm/asm-misplaced-option.stderr b/src/test/ui/asm/asm-misplaced-option.stderr index 39d88e3fb56dc..3d4b28c3dc444 100644 --- a/src/test/ui/asm/asm-misplaced-option.stderr +++ b/src/test/ui/asm/asm-misplaced-option.stderr @@ -1,11 +1,11 @@ warning: unrecognized option - --> $DIR/asm-misplaced-option.rs:26:64 + --> $DIR/asm-misplaced-option.rs:24:64 | LL | asm!("mov $1, $0" : "=r"(x) : "r"(5_usize), "0"(x) : : "cc"); | ^^^^ warning: expected a clobber, found an option - --> $DIR/asm-misplaced-option.rs:33:80 + --> $DIR/asm-misplaced-option.rs:31:80 | LL | asm!("add $2, $1; mov $1, $0" : "=r"(x) : "r"(x), "r"(8_usize) : "cc", "volatile"); | ^^^^^^^^^^ diff --git a/src/test/ui/asm/asm-out-assign-imm.nll.stderr b/src/test/ui/asm/asm-out-assign-imm.nll.stderr deleted file mode 100644 index ac38218b8492f..0000000000000 --- a/src/test/ui/asm/asm-out-assign-imm.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/asm-out-assign-imm.rs:24:34 - | -LL | let x: isize; - | - help: make this binding mutable: `mut x` -LL | x = 1; - | ----- first assignment to `x` -... -LL | asm!("mov $1, $0" : "=r"(x) : "r"(5)); - | ^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/asm/asm-out-assign-imm.stderr b/src/test/ui/asm/asm-out-assign-imm.stderr index 98f2f68a8f3c1..ac38218b8492f 100644 --- a/src/test/ui/asm/asm-out-assign-imm.stderr +++ b/src/test/ui/asm/asm-out-assign-imm.stderr @@ -1,6 +1,8 @@ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/asm-out-assign-imm.rs:24:34 | +LL | let x: isize; + | - help: make this binding mutable: `mut x` LL | x = 1; | ----- first assignment to `x` ... diff --git a/src/test/ui/asm/asm-out-no-modifier.stderr b/src/test/ui/asm/asm-out-no-modifier.stderr index 12a33e451fb05..387a603f90e3a 100644 --- a/src/test/ui/asm/asm-out-no-modifier.stderr +++ b/src/test/ui/asm/asm-out-no-modifier.stderr @@ -1,9 +1,8 @@ error[E0661]: output operand constraint lacks '=' or '+' --> $DIR/asm-out-no-modifier.rs:22:29 | -LL | asm!("mov $1, $0" : "r"(x) : "r"(5)); //~ ERROR output operand constraint lacks '=' +LL | asm!("mov $1, $0" : "r"(x) : "r"(5)); | ^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0661`. diff --git a/src/test/ui/asm/asm-out-read-uninit.ast.stderr b/src/test/ui/asm/asm-out-read-uninit.ast.stderr deleted file mode 100644 index cf74298be4a5d..0000000000000 --- a/src/test/ui/asm/asm-out-read-uninit.ast.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `x` - --> $DIR/asm-out-read-uninit.rs:25:43 - | -LL | asm!("mov $1, $0" : "=r"(x) : "r"(x)); - | ^ use of possibly uninitialized `x` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/asm/asm-out-read-uninit.mir.stderr b/src/test/ui/asm/asm-out-read-uninit.mir.stderr deleted file mode 100644 index cf74298be4a5d..0000000000000 --- a/src/test/ui/asm/asm-out-read-uninit.mir.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `x` - --> $DIR/asm-out-read-uninit.rs:25:43 - | -LL | asm!("mov $1, $0" : "=r"(x) : "r"(x)); - | ^ use of possibly uninitialized `x` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/asm/asm-out-read-uninit.rs b/src/test/ui/asm/asm-out-read-uninit.rs index 44dd0503c3bbf..003f1fc5bb62b 100644 --- a/src/test/ui/asm/asm-out-read-uninit.rs +++ b/src/test/ui/asm/asm-out-read-uninit.rs @@ -8,9 +8,6 @@ // ignore-mips // ignore-mips64 -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - #![feature(asm)] fn foo(x: isize) { println!("{}", x); } @@ -23,8 +20,7 @@ pub fn main() { let x: isize; unsafe { asm!("mov $1, $0" : "=r"(x) : "r"(x)); - //[ast]~^ ERROR use of possibly uninitialized variable: `x` - //[mir]~^^ ERROR use of possibly uninitialized variable: `x` + //~^ ERROR use of possibly uninitialized variable: `x` } foo(x); } diff --git a/src/test/ui/asm/asm-out-read-uninit.stderr b/src/test/ui/asm/asm-out-read-uninit.stderr new file mode 100644 index 0000000000000..6d0445d4b7a61 --- /dev/null +++ b/src/test/ui/asm/asm-out-read-uninit.stderr @@ -0,0 +1,9 @@ +error[E0381]: use of possibly uninitialized variable: `x` + --> $DIR/asm-out-read-uninit.rs:22:43 + | +LL | asm!("mov $1, $0" : "=r"(x) : "r"(x)); + | ^ use of possibly uninitialized `x` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/asm/asm-parse-errors.stderr b/src/test/ui/asm/asm-parse-errors.stderr index 37b61b80b2b89..9fe59d12e12cd 100644 --- a/src/test/ui/asm/asm-parse-errors.stderr +++ b/src/test/ui/asm/asm-parse-errors.stderr @@ -1,67 +1,67 @@ error: macro requires a string literal as an argument --> $DIR/asm-parse-errors.rs:4:5 | -LL | asm!(); //~ ERROR requires a string literal as an argument +LL | asm!(); | ^^^^^^^ string literal required error: expected string literal --> $DIR/asm-parse-errors.rs:5:18 | -LL | asm!("nop" : struct); //~ ERROR expected string literal +LL | asm!("nop" : struct); | ^^^^^^ expected string literal error: expected string literal --> $DIR/asm-parse-errors.rs:6:30 | -LL | asm!("mov %eax, $$0x2" : struct); //~ ERROR expected string literal +LL | asm!("mov %eax, $$0x2" : struct); | ^^^^^^ expected string literal error: expected `(`, found keyword `struct` --> $DIR/asm-parse-errors.rs:7:39 | -LL | asm!("mov %eax, $$0x2" : "={eax}" struct); //~ ERROR expected `(` +LL | asm!("mov %eax, $$0x2" : "={eax}" struct); | ^^^^^^ expected `(` error: expected expression, found keyword `struct` --> $DIR/asm-parse-errors.rs:8:39 | -LL | asm!("mov %eax, $$0x2" : "={eax}"(struct)); //~ ERROR expected expression +LL | asm!("mov %eax, $$0x2" : "={eax}"(struct)); | ^^^^^^ expected expression error: expected string literal --> $DIR/asm-parse-errors.rs:9:44 | -LL | asm!("in %dx, %al" : "={al}"(result) : struct); //~ ERROR expected string literal +LL | asm!("in %dx, %al" : "={al}"(result) : struct); | ^^^^^^ expected string literal error: expected `(`, found keyword `struct` --> $DIR/asm-parse-errors.rs:10:51 | -LL | asm!("in %dx, %al" : "={al}"(result) : "{dx}" struct); //~ ERROR expected `(` +LL | asm!("in %dx, %al" : "={al}"(result) : "{dx}" struct); | ^^^^^^ expected `(` error: expected expression, found keyword `struct` --> $DIR/asm-parse-errors.rs:11:51 | -LL | asm!("in %dx, %al" : "={al}"(result) : "{dx}"(struct)); //~ ERROR expected expression +LL | asm!("in %dx, %al" : "={al}"(result) : "{dx}"(struct)); | ^^^^^^ expected expression error: expected string literal --> $DIR/asm-parse-errors.rs:12:36 | -LL | asm!("mov $$0x200, %eax" : : : struct); //~ ERROR expected string literal +LL | asm!("mov $$0x200, %eax" : : : struct); | ^^^^^^ expected string literal error: expected string literal --> $DIR/asm-parse-errors.rs:13:45 | -LL | asm!("mov eax, 2" : "={eax}"(foo) : : : struct); //~ ERROR expected string literal +LL | asm!("mov eax, 2" : "={eax}"(foo) : : : struct); | ^^^^^^ expected string literal error: inline assembly must be a string literal --> $DIR/asm-parse-errors.rs:14:10 | -LL | asm!(123); //~ ERROR inline assembly must be a string literal +LL | asm!(123); | ^^^ error: aborting due to 11 previous errors diff --git a/src/test/ui/assign-imm-local-twice.ast.nll.stderr b/src/test/ui/assign-imm-local-twice.ast.nll.stderr deleted file mode 100644 index 311a83a76f933..0000000000000 --- a/src/test/ui/assign-imm-local-twice.ast.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `v` - --> $DIR/assign-imm-local-twice.rs:11:5 - | -LL | let v: isize; - | - help: make this binding mutable: `mut v` -... -LL | v = 1; //[ast]~ NOTE first assignment - | ----- first assignment to `v` -... -LL | v = 2; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/assign-imm-local-twice.ast.stderr b/src/test/ui/assign-imm-local-twice.ast.stderr deleted file mode 100644 index d57acb2c62154..0000000000000 --- a/src/test/ui/assign-imm-local-twice.ast.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `v` - --> $DIR/assign-imm-local-twice.rs:11:5 - | -LL | v = 1; //[ast]~ NOTE first assignment - | ----- first assignment to `v` -... -LL | v = 2; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/assign-imm-local-twice.mir.stderr b/src/test/ui/assign-imm-local-twice.mir.stderr deleted file mode 100644 index 311a83a76f933..0000000000000 --- a/src/test/ui/assign-imm-local-twice.mir.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `v` - --> $DIR/assign-imm-local-twice.rs:11:5 - | -LL | let v: isize; - | - help: make this binding mutable: `mut v` -... -LL | v = 1; //[ast]~ NOTE first assignment - | ----- first assignment to `v` -... -LL | v = 2; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/assign-imm-local-twice.rs b/src/test/ui/assign-imm-local-twice.rs index de966a17857c6..c1c9bf62819af 100644 --- a/src/test/ui/assign-imm-local-twice.rs +++ b/src/test/ui/assign-imm-local-twice.rs @@ -1,17 +1,11 @@ -// revisions: ast mir -//[mir]compile-flags: -Zborrowck=mir - fn test() { let v: isize; - //[mir]~^ HELP make this binding mutable - //[mir]~| SUGGESTION mut v - v = 1; //[ast]~ NOTE first assignment - //[mir]~^ NOTE first assignment + //~^ HELP make this binding mutable + //~| SUGGESTION mut v + v = 1; //~ NOTE first assignment println!("v={}", v); - v = 2; //[ast]~ ERROR cannot assign twice to immutable variable - //[mir]~^ ERROR cannot assign twice to immutable variable `v` - //[ast]~| NOTE cannot assign twice to immutable - //[mir]~| NOTE cannot assign twice to immutable + v = 2; //~ ERROR cannot assign twice to immutable variable + //~| NOTE cannot assign twice to immutable println!("v={}", v); } diff --git a/src/test/ui/assign-imm-local-twice.stderr b/src/test/ui/assign-imm-local-twice.stderr new file mode 100644 index 0000000000000..df0f4c4d80608 --- /dev/null +++ b/src/test/ui/assign-imm-local-twice.stderr @@ -0,0 +1,15 @@ +error[E0384]: cannot assign twice to immutable variable `v` + --> $DIR/assign-imm-local-twice.rs:7:5 + | +LL | let v: isize; + | - help: make this binding mutable: `mut v` +... +LL | v = 1; + | ----- first assignment to `v` +LL | println!("v={}", v); +LL | v = 2; + | ^^^^^ cannot assign twice to immutable variable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/assign-to-method.stderr b/src/test/ui/assign-to-method.stderr index f79f0750d8904..feceadb67220b 100644 --- a/src/test/ui/assign-to-method.stderr +++ b/src/test/ui/assign-to-method.stderr @@ -1,7 +1,7 @@ error[E0615]: attempted to take value of method `speak` on type `Cat` --> $DIR/assign-to-method.rs:20:8 | -LL | nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method +LL | nyan.speak = || println!("meow"); | ^^^^^ | = help: methods are immutable and cannot be assigned to @@ -9,7 +9,7 @@ LL | nyan.speak = || println!("meow"); //~ ERROR attempted to take value of me error[E0615]: attempted to take value of method `speak` on type `Cat` --> $DIR/assign-to-method.rs:21:8 | -LL | nyan.speak += || println!("meow"); //~ ERROR attempted to take value of method +LL | nyan.speak += || println!("meow"); | ^^^^^ | = help: methods are immutable and cannot be assigned to diff --git a/src/test/ui/assignment-operator-unimplemented.stderr b/src/test/ui/assignment-operator-unimplemented.stderr index 1d7adb129d0e1..5304b09de5efe 100644 --- a/src/test/ui/assignment-operator-unimplemented.stderr +++ b/src/test/ui/assignment-operator-unimplemented.stderr @@ -1,7 +1,7 @@ error[E0368]: binary assignment operation `+=` cannot be applied to type `Foo` --> $DIR/assignment-operator-unimplemented.rs:6:3 | -LL | a += *b; //~ Error: binary assignment operation `+=` cannot be applied to type `Foo` +LL | a += *b; | -^^^^^^ | | | cannot use `+=` on type `Foo` diff --git a/src/test/ui/assoc-inherent.stderr b/src/test/ui/assoc-inherent.stderr index f438ac8df4a09..f9ea3365cb8d3 100644 --- a/src/test/ui/assoc-inherent.stderr +++ b/src/test/ui/assoc-inherent.stderr @@ -1,7 +1,7 @@ error[E0202]: associated types are not yet supported in inherent impls (see #8995) --> $DIR/assoc-inherent.rs:6:5 | -LL | type Bar = isize; //~ERROR associated types are not yet supported in inherent impls (see #8995) +LL | type Bar = isize; | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr index 47748609b1629..5f2b9c47e8c2a 100644 --- a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr +++ b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr @@ -1,7 +1,7 @@ error[E0034]: multiple applicable items in scope --> $DIR/associated-const-ambiguity-report.rs:17:16 | -LL | const X: i32 = ::ID; //~ ERROR E0034 +LL | const X: i32 = ::ID; | ^^^^^^^^^ multiple `ID` found | note: candidate #1 is defined in an impl of the trait `Foo` for the type `i32` diff --git a/src/test/ui/associated-const/associated-const-generic-obligations.rs b/src/test/ui/associated-const/associated-const-generic-obligations.rs index e0b502edaa15e..498e315b5c83c 100644 --- a/src/test/ui/associated-const/associated-const-generic-obligations.rs +++ b/src/test/ui/associated-const/associated-const-generic-obligations.rs @@ -12,7 +12,7 @@ trait Bar: Foo { impl Bar for T { const FROM: &'static str = "foo"; - //~^ ERROR the trait bound `T: Foo` is not satisfied [E0277] + //~^ ERROR implemented const `FROM` has an incompatible type for trait [E0326] } fn main() {} diff --git a/src/test/ui/associated-const/associated-const-generic-obligations.stderr b/src/test/ui/associated-const/associated-const-generic-obligations.stderr index e4b86d84cafc9..eeee26a75671f 100644 --- a/src/test/ui/associated-const/associated-const-generic-obligations.stderr +++ b/src/test/ui/associated-const/associated-const-generic-obligations.stderr @@ -1,11 +1,15 @@ -error[E0277]: the trait bound `T: Foo` is not satisfied - --> $DIR/associated-const-generic-obligations.rs:14:5 +error[E0326]: implemented const `FROM` has an incompatible type for trait + --> $DIR/associated-const-generic-obligations.rs:14:17 | +LL | const FROM: Self::Out; + | --------- type in trait +... LL | const FROM: &'static str = "foo"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `T` + | ^^^^^^^^^^^^ expected associated type, found reference | - = help: consider adding a `where T: Foo` bound + = note: expected type `::Out` + found type `&'static str` error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0326`. diff --git a/src/test/ui/associated-const/associated-const-in-trait.rs b/src/test/ui/associated-const/associated-const-in-trait.rs index 187708a60b449..cc3acd5395622 100644 --- a/src/test/ui/associated-const/associated-const-in-trait.rs +++ b/src/test/ui/associated-const/associated-const-in-trait.rs @@ -6,7 +6,7 @@ trait Trait { const N: usize; } -impl Trait { +impl dyn Trait { //~^ ERROR the trait `Trait` cannot be made into an object [E0038] const fn n() -> usize { Self::N } } diff --git a/src/test/ui/associated-const/associated-const-in-trait.stderr b/src/test/ui/associated-const/associated-const-in-trait.stderr index 44a92639b5d7e..dff268a55c909 100644 --- a/src/test/ui/associated-const/associated-const-in-trait.stderr +++ b/src/test/ui/associated-const/associated-const-in-trait.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/associated-const-in-trait.rs:9:6 | -LL | impl Trait { - | ^^^^^ the trait `Trait` cannot be made into an object +LL | impl dyn Trait { + | ^^^^^^^^^ the trait `Trait` cannot be made into an object | = note: the trait cannot contain associated consts like `N` diff --git a/src/test/ui/associated-const/associated-const-no-item.stderr b/src/test/ui/associated-const/associated-const-no-item.stderr index de172049872f5..d96cf67b87578 100644 --- a/src/test/ui/associated-const/associated-const-no-item.stderr +++ b/src/test/ui/associated-const/associated-const-no-item.stderr @@ -2,9 +2,7 @@ error[E0599]: no associated item named `ID` found for type `i32` in the current --> $DIR/associated-const-no-item.rs:5:23 | LL | const X: i32 = ::ID; - | -------^^ - | | - | associated item not found in `i32` + | ^^ associated item not found in `i32` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `ID`, perhaps you need to implement it: diff --git a/src/test/ui/associated-const/associated-const-trait-bound.rs b/src/test/ui/associated-const/associated-const-trait-bound.rs new file mode 100644 index 0000000000000..0ce46d312afef --- /dev/null +++ b/src/test/ui/associated-const/associated-const-trait-bound.rs @@ -0,0 +1,21 @@ +// compile-pass + +trait ConstDefault { + const DEFAULT: Self; +} + +trait Foo: Sized {} + +trait FooExt: Foo { + type T: ConstDefault; +} + +trait Bar { + const T: F::T; +} + +impl Bar for () { + const T: F::T = ::DEFAULT; +} + +fn main() {} diff --git a/src/test/ui/associated-item/associated-item-duplicate-names-2.stderr b/src/test/ui/associated-item/associated-item-duplicate-names-2.stderr index 6cc63de35d746..ea475ffc5547a 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-names-2.stderr +++ b/src/test/ui/associated-item/associated-item-duplicate-names-2.stderr @@ -3,7 +3,7 @@ error[E0201]: duplicate definitions with name `bar`: | LL | const bar: bool = true; | ----------------------- previous definition of `bar` here -LL | fn bar() {} //~ ERROR duplicate definitions +LL | fn bar() {} | ^^^^^^^^^^^ duplicate definition error: aborting due to previous error diff --git a/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr b/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr index 07ce5e621a626..57495863c9891 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr +++ b/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr @@ -3,7 +3,7 @@ error[E0201]: duplicate definitions with name `Bar`: | LL | type Bar = i16; | --------------- previous definition of `Bar` here -LL | type Bar = u16; //~ ERROR duplicate definitions +LL | type Bar = u16; | ^^^^^^^^^^^^^^^ duplicate definition error: aborting due to previous error diff --git a/src/test/ui/associated-item/associated-item-duplicate-names.stderr b/src/test/ui/associated-item/associated-item-duplicate-names.stderr index 2bbe912521455..f4af9e0293950 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-names.stderr +++ b/src/test/ui/associated-item/associated-item-duplicate-names.stderr @@ -3,7 +3,7 @@ error[E0201]: duplicate definitions with name `Ty`: | LL | type Ty = (); | ------------- previous definition of `Ty` here -LL | type Ty = usize; //~ ERROR duplicate definitions +LL | type Ty = usize; | ^^^^^^^^^^^^^^^^ duplicate definition error[E0201]: duplicate definitions with name `BAR`: @@ -11,7 +11,7 @@ error[E0201]: duplicate definitions with name `BAR`: | LL | const BAR: u32 = 7; | ------------------- previous definition of `BAR` here -LL | const BAR: u32 = 8; //~ ERROR duplicate definitions +LL | const BAR: u32 = 8; | ^^^^^^^^^^^^^^^^^^^ duplicate definition error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-item/associated-item-enum.rs b/src/test/ui/associated-item/associated-item-enum.rs new file mode 100644 index 0000000000000..30ba258155bb9 --- /dev/null +++ b/src/test/ui/associated-item/associated-item-enum.rs @@ -0,0 +1,20 @@ +enum Enum { Variant } + +impl Enum { + const MISSPELLABLE: i32 = 0; + fn misspellable() {} +} + +trait Trait { + fn misspellable_trait() {} +} + +impl Trait for Enum { + fn misspellable_trait() {} +} + +fn main() { + Enum::mispellable(); //~ ERROR no variant or associated item + Enum::mispellable_trait(); //~ ERROR no variant or associated item + Enum::MISPELLABLE; //~ ERROR no variant or associated item +} diff --git a/src/test/ui/associated-item/associated-item-enum.stderr b/src/test/ui/associated-item/associated-item-enum.stderr new file mode 100644 index 0000000000000..5a62b9736dedd --- /dev/null +++ b/src/test/ui/associated-item/associated-item-enum.stderr @@ -0,0 +1,36 @@ +error[E0599]: no variant or associated item named `mispellable` found for type `Enum` in the current scope + --> $DIR/associated-item-enum.rs:17:11 + | +LL | enum Enum { Variant } + | --------- variant or associated item `mispellable` not found here +... +LL | Enum::mispellable(); + | ^^^^^^^^^^^ + | | + | variant or associated item not found in `Enum` + | help: there is a method with a similar name: `misspellable` + +error[E0599]: no variant or associated item named `mispellable_trait` found for type `Enum` in the current scope + --> $DIR/associated-item-enum.rs:18:11 + | +LL | enum Enum { Variant } + | --------- variant or associated item `mispellable_trait` not found here +... +LL | Enum::mispellable_trait(); + | ^^^^^^^^^^^^^^^^^ variant or associated item not found in `Enum` + +error[E0599]: no variant or associated item named `MISPELLABLE` found for type `Enum` in the current scope + --> $DIR/associated-item-enum.rs:19:11 + | +LL | enum Enum { Variant } + | --------- variant or associated item `MISPELLABLE` not found here +... +LL | Enum::MISPELLABLE; + | ^^^^^^^^^^^ + | | + | variant or associated item not found in `Enum` + | help: there is an associated constant with a similar name: `MISSPELLABLE` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/associated-path-shl.stderr b/src/test/ui/associated-path-shl.stderr index 3b62b1b01f48c..23918ed2e3912 100644 --- a/src/test/ui/associated-path-shl.stderr +++ b/src/test/ui/associated-path-shl.stderr @@ -1,37 +1,37 @@ error[E0412]: cannot find type `A` in this scope --> $DIR/associated-path-shl.rs:4:14 | -LL | let _: <::B>::C; //~ ERROR cannot find type `A` in this scope +LL | let _: <::B>::C; | ^ not found in this scope error[E0412]: cannot find type `A` in this scope --> $DIR/associated-path-shl.rs:5:15 | -LL | let _ = <::B>::C; //~ ERROR cannot find type `A` in this scope +LL | let _ = <::B>::C; | ^ not found in this scope error[E0412]: cannot find type `A` in this scope --> $DIR/associated-path-shl.rs:6:11 | -LL | let <::B>::C; //~ ERROR cannot find type `A` in this scope +LL | let <::B>::C; | ^ not found in this scope error[E0412]: cannot find type `A` in this scope --> $DIR/associated-path-shl.rs:7:17 | -LL | let 0 ..= <::B>::C; //~ ERROR cannot find type `A` in this scope +LL | let 0 ..= <::B>::C; | ^ not found in this scope error[E0412]: cannot find type `A` in this scope --> $DIR/associated-path-shl.rs:9:7 | -LL | <::B>::C; //~ ERROR cannot find type `A` in this scope +LL | <::B>::C; | ^ not found in this scope error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/associated-path-shl.rs:7:15 | -LL | let 0 ..= <::B>::C; //~ ERROR cannot find type `A` in this scope +LL | let 0 ..= <::B>::C; | ^^^^^^^^^^^ ranges require char or numeric types | = note: start type: {integer} @@ -39,5 +39,5 @@ LL | let 0 ..= <::B>::C; //~ ERROR cannot find type `A` in this scope error: aborting due to 6 previous errors -Some errors occurred: E0029, E0412. +Some errors have detailed explanations: E0029, E0412. For more information about an error, try `rustc --explain E0029`. diff --git a/src/test/ui/associated-type-bounds/auxiliary/fn-aux.rs b/src/test/ui/associated-type-bounds/auxiliary/fn-aux.rs new file mode 100644 index 0000000000000..0ea23ad1dbffa --- /dev/null +++ b/src/test/ui/associated-type-bounds/auxiliary/fn-aux.rs @@ -0,0 +1,177 @@ +// Traits: + +pub trait Alpha { + fn alpha(self) -> usize; +} + +pub trait Beta { + type Gamma; + fn gamma(self) -> Self::Gamma; +} + +pub trait Delta { + fn delta(self) -> usize; +} + +pub trait Epsilon<'a> { + type Zeta; + fn zeta(&'a self) -> Self::Zeta; + + fn epsilon(&'a self) -> usize; +} + +pub trait Eta { + fn eta(self) -> usize; +} + +// Assertions: + +pub fn assert_alpha(x: T) -> usize { x.alpha() } +pub fn assert_static(_: T) -> usize { 24 } +pub fn assert_delta(x: T) -> usize { x.delta() } +pub fn assert_epsilon_specific<'a, T: 'a + Epsilon<'a>>(x: &'a T) -> usize { x.epsilon() } +pub fn assert_epsilon_forall Epsilon<'a>>() {} +pub fn assert_forall_epsilon_zeta_satisfies_eta(x: T) -> usize +where + T: for<'a> Epsilon<'a>, + for<'a> >::Zeta: Eta, +{ + x.epsilon() + x.zeta().eta() +} + +// Implementations and types: + +#[derive(Copy, Clone)] +pub struct BetaType; + +#[derive(Copy, Clone)] +pub struct GammaType; + +#[derive(Copy, Clone)] +pub struct ZetaType; + +impl Beta for BetaType { + type Gamma = GammaType; + fn gamma(self) -> Self::Gamma { GammaType } +} + +impl<'a> Beta for &'a BetaType { + type Gamma = GammaType; + fn gamma(self) -> Self::Gamma { GammaType } +} + +impl Beta for GammaType { + type Gamma = Self; + fn gamma(self) -> Self::Gamma { self } +} + +impl Alpha for GammaType { + fn alpha(self) -> usize { 42 } +} + +impl Delta for GammaType { + fn delta(self) -> usize { 1337 } +} + +impl<'a> Epsilon<'a> for GammaType { + type Zeta = ZetaType; + fn zeta(&'a self) -> Self::Zeta { ZetaType } + + fn epsilon(&'a self) -> usize { 7331 } +} + +impl Eta for ZetaType { + fn eta(self) -> usize { 7 } +} + +// Desugared forms to check against: + +pub fn desugared_bound(beta: B) -> usize +where + B: Beta, + B::Gamma: Alpha +{ + let gamma: B::Gamma = beta.gamma(); + assert_alpha::(gamma) +} + +pub fn desugared_bound_region(beta: B) -> usize +where + B: Beta, + B::Gamma: 'static, +{ + assert_static::(beta.gamma()) +} + +pub fn desugared_bound_multi(beta: B) -> usize +where + B: Copy + Beta, + B::Gamma: Alpha + 'static + Delta, +{ + assert_alpha::(beta.gamma()) + + assert_static::(beta.gamma()) + + assert_delta::(beta.gamma()) +} + +pub fn desugared_bound_region_specific<'a, B>(gamma: &'a B::Gamma) -> usize +where + B: Beta, + B::Gamma: 'a + Epsilon<'a>, +{ + assert_epsilon_specific::(gamma) +} + +pub fn desugared_bound_region_forall(beta: B) -> usize +where + B: Beta, + B::Gamma: Copy + for<'a> Epsilon<'a>, +{ + assert_epsilon_forall::(); + let g1: B::Gamma = beta.gamma(); + let g2: B::Gamma = g1; + assert_epsilon_specific::(&g1) + + assert_epsilon_specific::(&g2) +} + +pub fn desugared_bound_region_forall2(beta: B) -> usize +where + B: Beta, + B::Gamma: Copy + for<'a> Epsilon<'a>, + for<'a> >::Zeta: Eta, +{ + let gamma = beta.gamma(); + assert_forall_epsilon_zeta_satisfies_eta::(gamma) +} + +pub fn desugared_contraint_region_forall(beta: B) -> usize +where + for<'a> &'a B: Beta, + for<'a> <&'a B as Beta>::Gamma: Alpha, +{ + let g1 = beta.gamma(); + let g2 = beta.gamma(); + assert_alpha(g1) + assert_alpha(g2) +} + +pub fn desugared_bound_nested(beta: B) -> usize +where + B: Beta, + B::Gamma: Copy + Alpha + Beta, + ::Gamma: Delta, +{ + let go = beta.gamma(); + let gi = go.gamma(); + go.alpha() + gi.delta() +} + +pub fn desugared() { + let beta = BetaType; + let gamma = beta.gamma(); + + assert_eq!(42, desugared_bound(beta)); + assert_eq!(24, desugared_bound_region(beta)); + assert_eq!(42 + 24 + 1337, desugared_bound_multi(beta)); + assert_eq!(7331, desugared_bound_region_specific::(&gamma)); + assert_eq!(7331 * 2, desugared_bound_region_forall(beta)); + assert_eq!(42 + 1337, desugared_bound_nested(beta)); +} diff --git a/src/test/ui/associated-type-bounds/auxiliary/fn-dyn-aux.rs b/src/test/ui/associated-type-bounds/auxiliary/fn-dyn-aux.rs new file mode 100644 index 0000000000000..85d6c5aaf3c6f --- /dev/null +++ b/src/test/ui/associated-type-bounds/auxiliary/fn-dyn-aux.rs @@ -0,0 +1,182 @@ +// Traits: + +pub trait Alpha { + fn alpha(self) -> usize; +} + +pub trait Beta { + type Gamma; + fn gamma(&self) -> Self::Gamma; +} + +pub trait Delta { + fn delta(self) -> usize; +} + +pub trait Epsilon<'a> { + type Zeta; + fn zeta(&'a self) -> Self::Zeta; + + fn epsilon(&'a self) -> usize; +} + +pub trait Eta { + fn eta(self) -> usize; +} + +// Assertions: + +pub fn assert_alpha(x: T) -> usize { x.alpha() } +pub fn assert_static(_: T) -> usize { 24 } +pub fn assert_delta(x: T) -> usize { x.delta() } +pub fn assert_epsilon_specific<'a, T: 'a + Epsilon<'a>>(x: &'a T) -> usize { x.epsilon() } +pub fn assert_epsilon_forall Epsilon<'a>>() {} +pub fn assert_forall_epsilon_zeta_satisfies_eta(x: T) -> usize +where + T: for<'a> Epsilon<'a>, + for<'a> >::Zeta: Eta, +{ + x.epsilon() + x.zeta().eta() +} + +// Implementations and types: + +#[derive(Copy, Clone)] +pub struct BetaType; + +#[derive(Copy, Clone)] +pub struct GammaType; + +#[derive(Copy, Clone)] +pub struct ZetaType; + +impl Beta for &(dyn Beta + Send) { + type Gamma = T; + fn gamma(&self) -> Self::Gamma { (*self).gamma() } +} + +impl Beta for BetaType { + type Gamma = GammaType; + fn gamma(&self) -> Self::Gamma { GammaType } +} + +impl<'a> Beta for &'a BetaType { + type Gamma = GammaType; + fn gamma(&self) -> Self::Gamma { GammaType } +} + +impl Beta for GammaType { + type Gamma = Self; + fn gamma(&self) -> Self::Gamma { Self } +} + +impl Alpha for GammaType { + fn alpha(self) -> usize { 42 } +} + +impl Delta for GammaType { + fn delta(self) -> usize { 1337 } +} + +impl<'a> Epsilon<'a> for GammaType { + type Zeta = ZetaType; + fn zeta(&'a self) -> Self::Zeta { ZetaType } + + fn epsilon(&'a self) -> usize { 7331 } +} + +impl Eta for ZetaType { + fn eta(self) -> usize { 7 } +} + +// Desugared forms to check against: + +pub fn desugared_bound(beta: &B) -> usize +where + B: Beta, + B::Gamma: Alpha +{ + let gamma: B::Gamma = beta.gamma(); + assert_alpha::(gamma) +} + +pub fn desugared_bound_region(beta: &B) -> usize +where + B: Beta, + B::Gamma: 'static, +{ + assert_static::(beta.gamma()) +} + +pub fn desugared_bound_multi(beta: B) -> usize +where + B: Copy + Beta, + B::Gamma: Alpha + 'static + Delta, +{ + assert_alpha::(beta.gamma()) + + assert_static::(beta.gamma()) + + assert_delta::(beta.gamma()) +} + +pub fn desugared_bound_region_specific<'a, B: ?Sized>(gamma: &'a B::Gamma) -> usize +where + B: Beta, + B::Gamma: 'a + Epsilon<'a>, +{ + assert_epsilon_specific::(gamma) +} + +pub fn desugared_bound_region_forall(beta: &B) -> usize +where + B: Beta, + B::Gamma: Copy + for<'a> Epsilon<'a>, +{ + assert_epsilon_forall::(); + let g1: B::Gamma = beta.gamma(); + let g2: B::Gamma = g1; + assert_epsilon_specific::(&g1) + + assert_epsilon_specific::(&g2) +} + +pub fn desugared_bound_region_forall2(beta: &B) -> usize +where + B: Beta, + B::Gamma: Copy + for<'a> Epsilon<'a>, + for<'a> >::Zeta: Eta, +{ + let gamma = beta.gamma(); + assert_forall_epsilon_zeta_satisfies_eta::(gamma) +} + +pub fn desugared_contraint_region_forall(beta: &B) -> usize +where + for<'a> &'a B: Beta, + for<'a> <&'a B as Beta>::Gamma: Alpha, +{ + let g1 = beta.gamma(); + let g2 = beta.gamma(); + assert_alpha(g1) + assert_alpha(g2) +} + +pub fn desugared_bound_nested(beta: &B) -> usize +where + B: Beta, + B::Gamma: Copy + Alpha + Beta, + ::Gamma: Delta, +{ + let go = beta.gamma(); + let gi = go.gamma(); + go.alpha() + gi.delta() +} + +pub fn desugared() { + let beta = BetaType; + let gamma = beta.gamma(); + + assert_eq!(42, desugared_bound(&beta)); + assert_eq!(24, desugared_bound_region(&beta)); + assert_eq!(42 + 24 + 1337, desugared_bound_multi(beta)); + assert_eq!(7331, desugared_bound_region_specific::(&gamma)); + assert_eq!(7331 * 2, desugared_bound_region_forall(&beta)); + assert_eq!(42 + 1337, desugared_bound_nested(&beta)); +} diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs new file mode 100644 index 0000000000000..78704a9b51239 --- /dev/null +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs @@ -0,0 +1,60 @@ +// compile-fail +// ignore-tidy-linelength + +// NOTE: rustc cannot currently handle bounds of the form `for<'a> >::Assoc: Baz`. +// This should hopefully be fixed with Chalk. + +#![feature(associated_type_bounds)] + +use std::fmt::Debug; +use std::iter::Once; + +trait Lam { type App; } + +#[derive(Clone)] +struct L1; +impl<'a> Lam<&'a u8> for L1 { type App = u8; } + +#[derive(Clone)] +struct L2; +impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; } + +trait Case1 { + type C: Clone + Iterator Lam<&'a u8, App: + Debug + > + > + Sync>; +} + +pub struct S1; +impl Case1 for S1 { +//~^ ERROR `>::App` doesn't implement `std::fmt::Debug` [E0277] + type C = Once>; +} + +fn assume_case1() { +//~^ ERROR `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` [E0277] +//~| ERROR `<::C as std::iter::Iterator>::Item` is not an iterator [E0277] +//~| ERROR `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely [E0277] +//~| ERROR `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely [E0277] + fn assert_a<_0, A>() where A: Iterator, _0: Debug {} + assert_a::<_, T::A>(); + + fn assert_b<_0, B>() where B: Iterator, _0: 'static {} + assert_b::<_, T::B>(); + + fn assert_c<_0, _1, _2, C>() + where + C: Clone + Iterator, + _2: Send + Iterator, + _1: for<'a> Lam<&'a u8, App = _0>, + _0: Debug, + {} + assert_c::<_, _, _, T::C>(); +} + +fn main() { + assume_case1(S1); +} diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr new file mode 100644 index 0000000000000..aebf29cc332ab --- /dev/null +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr @@ -0,0 +1,85 @@ +error[E0277]: `>::App` doesn't implement `std::fmt::Debug` + --> $DIR/bad-bounds-on-assoc-in-trait.rs:32:6 + | +LL | impl Case1 for S1 { + | ^^^^^ `>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | + = help: the trait `for<'a> std::fmt::Debug` is not implemented for `>::App` + +error[E0277]: `<::C as std::iter::Iterator>::Item` is not an iterator + --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 + | +LL | / fn assume_case1() { +LL | | +LL | | +LL | | +... | +LL | | assert_c::<_, _, _, T::C>(); +LL | | } + | |_^ `<::C as std::iter::Iterator>::Item` is not an iterator + | + = help: the trait `std::iter::Iterator` is not implemented for `<::C as std::iter::Iterator>::Item` + = help: consider adding a `where <::C as std::iter::Iterator>::Item: std::iter::Iterator` bound + +error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely + --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 + | +LL | / fn assume_case1() { +LL | | +LL | | +LL | | +... | +LL | | assert_c::<_, _, _, T::C>(); +LL | | } + | |_^ `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely + | + = help: the trait `std::marker::Send` is not implemented for `<::C as std::iter::Iterator>::Item` + = help: consider adding a `where <::C as std::iter::Iterator>::Item: std::marker::Send` bound +note: required by `Case1` + --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1 + | +LL | trait Case1 { + | ^^^^^^^^^^^ + +error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely + --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 + | +LL | / fn assume_case1() { +LL | | +LL | | +LL | | +... | +LL | | assert_c::<_, _, _, T::C>(); +LL | | } + | |_^ `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely + | + = help: the trait `std::marker::Sync` is not implemented for `<::C as std::iter::Iterator>::Item` + = help: consider adding a `where <::C as std::iter::Iterator>::Item: std::marker::Sync` bound +note: required by `Case1` + --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1 + | +LL | trait Case1 { + | ^^^^^^^^^^^ + +error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` + --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 + | +LL | / fn assume_case1() { +LL | | +LL | | +LL | | +... | +LL | | assert_c::<_, _, _, T::C>(); +LL | | } + | |_^ `<_ as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | + = help: the trait `for<'a> std::fmt::Debug` is not implemented for `<_ as Lam<&'a u8>>::App` +note: required by `Case1` + --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1 + | +LL | trait Case1 { + | ^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs new file mode 100644 index 0000000000000..8c9110d03ec16 --- /dev/null +++ b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs @@ -0,0 +1,51 @@ +// run-pass + +#![feature(associated_type_bounds)] + +use std::fmt::Debug; +use std::iter::Empty; +use std::ops::Range; + +trait Lam { type App; } + +#[derive(Clone)] +struct L1; +impl<'a> Lam<&'a u8> for L1 { type App = u8; } + +#[derive(Clone)] +struct L2; +impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; } + +trait Case1 { + type A: Iterator; + + type B: Iterator; +} + +pub struct S1; +impl Case1 for S1 { + type A = Empty; + type B = Range; +} + +// Ensure we don't have existential desugaring: + +pub trait Foo { type Out: Baz; } +pub trait Baz { type Assoc; } + +#[derive(Default)] +struct S2; +#[derive(Default)] +struct S3; +struct S4; +struct S5; +struct S6; +struct S7; + +impl Foo for S6 { type Out = S4; } +impl Foo for S7 { type Out = S5; } + +impl Baz for S4 { type Assoc = S2; } +impl Baz for S5 { type Assoc = S3; } + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs new file mode 100644 index 0000000000000..bee56d6f68990 --- /dev/null +++ b/src/test/ui/associated-type-bounds/duplicate.rs @@ -0,0 +1,161 @@ +// compile-fail +// ignore-tidy-linelength +// error-pattern:could not find defining uses + +#![feature(associated_type_bounds)] +#![feature(existential_type)] +#![feature(impl_trait_in_bindings)] +#![feature(untagged_unions)] + +use std::iter; + +struct SI1> { f: T } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +struct SI2> { f: T } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +struct SI3> { f: T } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +struct SW1 where T: Iterator { f: T } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +struct SW2 where T: Iterator { f: T } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +struct SW3 where T: Iterator { f: T } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] + +enum EI1> { V(T) } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +enum EI2> { V(T) } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +enum EI3> { V(T) } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +enum EW1 where T: Iterator { V(T) } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +enum EW2 where T: Iterator { V(T) } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +enum EW3 where T: Iterator { V(T) } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] + +union UI1> { f: T } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +union UI2> { f: T } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +union UI3> { f: T } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +union UW1 where T: Iterator { f: T } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +union UW2 where T: Iterator { f: T } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +union UW3 where T: Iterator { f: T } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] + +fn FI1>() {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +fn FI2>() {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +fn FI3>() {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +fn FW1() where T: Iterator {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +fn FW2() where T: Iterator {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +fn FW3() where T: Iterator {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] + +fn FRPIT1() -> impl Iterator { iter::empty() } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +fn FRPIT2() -> impl Iterator { iter::empty() } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +fn FRPIT3() -> impl Iterator { iter::empty() } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +fn FAPIT1(_: impl Iterator) {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +fn FAPIT2(_: impl Iterator) {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +fn FAPIT3(_: impl Iterator) {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] + +const CIT1: impl Iterator = iter::empty(); +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +const CIT2: impl Iterator = iter::empty(); +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +const CIT3: impl Iterator = iter::empty(); +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +static SIT1: impl Iterator = iter::empty(); +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +static SIT2: impl Iterator = iter::empty(); +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +static SIT3: impl Iterator = iter::empty(); +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] + +fn lit1() { let _: impl Iterator = iter::empty(); } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +fn lit2() { let _: impl Iterator = iter::empty(); } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +fn lit3() { let _: impl Iterator = iter::empty(); } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] + +type TAI1> = T; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +type TAI2> = T; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +type TAI3> = T; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +type TAW1 where T: Iterator = T; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +type TAW2 where T: Iterator = T; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +type TAW3 where T: Iterator = T; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] + +existential type ETAI1>: Copy; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +existential type ETAI2>: Copy; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +existential type ETAI3>: Copy; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +existential type ETAI4: Iterator; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +existential type ETAI5: Iterator; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +existential type ETAI6: Iterator; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] + +trait TRI1> {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRI2> {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRI3> {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRS1: Iterator {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRS2: Iterator {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRS3: Iterator {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRW1 where T: Iterator {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRW2 where T: Iterator {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRW3 where T: Iterator {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRSW1 where Self: Iterator {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRSW2 where Self: Iterator {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRSW3 where Self: Iterator {} +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRA1 { type A: Iterator; } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRA2 { type A: Iterator; } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +trait TRA3 { type A: Iterator; } +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] + +type TADyn1 = dyn Iterator; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +type TADyn2 = Box>; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] +type TADyn3 = dyn Iterator; +//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719] + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr new file mode 100644 index 0000000000000..68367c916546c --- /dev/null +++ b/src/test/ui/associated-type-bounds/duplicate.stderr @@ -0,0 +1,632 @@ +warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash + --> $DIR/duplicate.rs:7:12 + | +LL | #![feature(impl_trait_in_bindings)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:12:36 + | +LL | struct SI1> { f: T } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:14:36 + | +LL | struct SI2> { f: T } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:16:39 + | +LL | struct SI3> { f: T } + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:18:45 + | +LL | struct SW1 where T: Iterator { f: T } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:20:45 + | +LL | struct SW2 where T: Iterator { f: T } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:22:48 + | +LL | struct SW3 where T: Iterator { f: T } + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:25:34 + | +LL | enum EI1> { V(T) } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:27:34 + | +LL | enum EI2> { V(T) } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:29:37 + | +LL | enum EI3> { V(T) } + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:31:43 + | +LL | enum EW1 where T: Iterator { V(T) } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:33:43 + | +LL | enum EW2 where T: Iterator { V(T) } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:35:46 + | +LL | enum EW3 where T: Iterator { V(T) } + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:38:35 + | +LL | union UI1> { f: T } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:40:35 + | +LL | union UI2> { f: T } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:42:38 + | +LL | union UI3> { f: T } + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:44:44 + | +LL | union UW1 where T: Iterator { f: T } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:46:44 + | +LL | union UW2 where T: Iterator { f: T } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:48:47 + | +LL | union UW3 where T: Iterator { f: T } + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:51:32 + | +LL | fn FI1>() {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:53:32 + | +LL | fn FI2>() {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:55:35 + | +LL | fn FI3>() {} + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:57:43 + | +LL | fn FW1() where T: Iterator {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:59:43 + | +LL | fn FW2() where T: Iterator {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:61:46 + | +LL | fn FW3() where T: Iterator {} + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:70:40 + | +LL | fn FAPIT1(_: impl Iterator) {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:72:40 + | +LL | fn FAPIT2(_: impl Iterator) {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:74:43 + | +LL | fn FAPIT3(_: impl Iterator) {} + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:64:42 + | +LL | fn FRPIT1() -> impl Iterator { iter::empty() } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:66:42 + | +LL | fn FRPIT2() -> impl Iterator { iter::empty() } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:68:45 + | +LL | fn FRPIT3() -> impl Iterator { iter::empty() } + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:77:39 + | +LL | const CIT1: impl Iterator = iter::empty(); + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:79:39 + | +LL | const CIT2: impl Iterator = iter::empty(); + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:81:42 + | +LL | const CIT3: impl Iterator = iter::empty(); + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:83:40 + | +LL | static SIT1: impl Iterator = iter::empty(); + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:85:40 + | +LL | static SIT2: impl Iterator = iter::empty(); + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:87:43 + | +LL | static SIT3: impl Iterator = iter::empty(); + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:90:46 + | +LL | fn lit1() { let _: impl Iterator = iter::empty(); } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:92:46 + | +LL | fn lit2() { let _: impl Iterator = iter::empty(); } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:94:49 + | +LL | fn lit3() { let _: impl Iterator = iter::empty(); } + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:97:35 + | +LL | type TAI1> = T; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:99:35 + | +LL | type TAI2> = T; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:101:38 + | +LL | type TAI3> = T; + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:103:44 + | +LL | type TAW1 where T: Iterator = T; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:105:44 + | +LL | type TAW2 where T: Iterator = T; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:107:47 + | +LL | type TAW3 where T: Iterator = T; + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error: could not find defining uses + --> $DIR/duplicate.rs:110:1 + | +LL | existential type ETAI1>: Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:110:48 + | +LL | existential type ETAI1>: Copy; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error: could not find defining uses + --> $DIR/duplicate.rs:112:1 + | +LL | existential type ETAI2>: Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:112:48 + | +LL | existential type ETAI2>: Copy; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error: could not find defining uses + --> $DIR/duplicate.rs:114:1 + | +LL | existential type ETAI3>: Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:114:51 + | +LL | existential type ETAI3>: Copy; + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error: could not find defining uses + --> $DIR/duplicate.rs:116:1 + | +LL | existential type ETAI4: Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:116:46 + | +LL | existential type ETAI4: Iterator; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error: could not find defining uses + --> $DIR/duplicate.rs:118:1 + | +LL | existential type ETAI5: Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:118:46 + | +LL | existential type ETAI5: Iterator; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error: could not find defining uses + --> $DIR/duplicate.rs:120:1 + | +LL | existential type ETAI6: Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:120:49 + | +LL | existential type ETAI6: Iterator; + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:123:36 + | +LL | trait TRI1> {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:125:36 + | +LL | trait TRI2> {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:127:39 + | +LL | trait TRI3> {} + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:129:34 + | +LL | trait TRS1: Iterator {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:131:34 + | +LL | trait TRS2: Iterator {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:133:37 + | +LL | trait TRS3: Iterator {} + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:135:45 + | +LL | trait TRW1 where T: Iterator {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:137:45 + | +LL | trait TRW2 where T: Iterator {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:139:48 + | +LL | trait TRW3 where T: Iterator {} + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:141:46 + | +LL | trait TRSW1 where Self: Iterator {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:143:46 + | +LL | trait TRSW2 where Self: Iterator {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:145:49 + | +LL | trait TRSW3 where Self: Iterator {} + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:147:43 + | +LL | trait TRA1 { type A: Iterator; } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:149:43 + | +LL | trait TRA2 { type A: Iterator; } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:151:46 + | +LL | trait TRA3 { type A: Iterator; } + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:154:40 + | +LL | type TADyn1 = dyn Iterator; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:156:44 + | +LL | type TADyn2 = Box>; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:158:43 + | +LL | type TADyn3 = dyn Iterator; + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: aborting due to 93 previous errors + diff --git a/src/test/ui/associated-type-bounds/dyn-existential-type.rs b/src/test/ui/associated-type-bounds/dyn-existential-type.rs new file mode 100644 index 0000000000000..dc0afaa934a9e --- /dev/null +++ b/src/test/ui/associated-type-bounds/dyn-existential-type.rs @@ -0,0 +1,67 @@ +// run-pass + +#![feature(associated_type_bounds)] +#![feature(existential_type)] + +use std::ops::Add; + +trait Tr1 { type As1; fn mk(&self) -> Self::As1; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } + +fn assert_copy(x: T) { let _x = x; let _x = x; } +fn assert_static(_: T) {} +fn assert_forall_tr2 Tr2<'a>>(_: T) {} + +struct S1; +#[derive(Copy, Clone)] +struct S2; +impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } } + +type Et1 = Box>; +fn def_et1() -> Et1 { Box::new(S1) } +pub fn use_et1() { assert_copy(def_et1().mk()); } + +type Et2 = Box>; +fn def_et2() -> Et2 { Box::new(S1) } +pub fn use_et2() { assert_static(def_et2().mk()); } + +type Et3 = Box>>>>; +fn def_et3() -> Et3 { + struct A; + impl Tr1 for A { + type As1 = core::ops::Range; + fn mk(&self) -> Self::As1 { 0..10 } + }; + Box::new(A) +} +pub fn use_et3() { + let _0 = def_et3().mk().clone(); + let mut s = 0u8; + for _1 in _0 { + let _2 = _1 + 1u8; + s += _2.into(); + } + assert_eq!(s, (0..10).map(|x| x + 1).sum()); +} + +type Et4 = Box Tr2<'a>>>; +fn def_et4() -> Et4 { + #[derive(Copy, Clone)] + struct A; + impl Tr1 for A { + type As1 = A; + fn mk(&self) -> A { A } + } + impl<'a> Tr2<'a> for A { + fn tr2(self) -> &'a Self { &A } + } + Box::new(A) +} +pub fn use_et4() { assert_forall_tr2(def_et4().mk()); } + +fn main() { + let _ = use_et1(); + let _ = use_et2(); + let _ = use_et3(); + let _ = use_et4(); +} diff --git a/src/test/ui/associated-type-bounds/dyn-lcsit.rs b/src/test/ui/associated-type-bounds/dyn-lcsit.rs new file mode 100644 index 0000000000000..439304fd309c8 --- /dev/null +++ b/src/test/ui/associated-type-bounds/dyn-lcsit.rs @@ -0,0 +1,69 @@ +// run-pass + +#![feature(associated_type_bounds)] +#![feature(impl_trait_in_bindings)] + +#![allow(non_upper_case_globals)] + +use std::ops::Add; + +trait Tr1 { type As1; fn mk(&self) -> Self::As1; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } + +fn assert_copy(x: T) { let _x = x; let _x = x; } +fn assert_static(_: T) {} +fn assert_forall_tr2 Tr2<'a>>(_: T) {} + +#[derive(Copy, Clone)] +struct S1; +#[derive(Copy, Clone)] +struct S2; +impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } } + +const cdef_et1: &dyn Tr1 = &S1; +const sdef_et1: &dyn Tr1 = &S1; +pub fn use_et1() { assert_copy(cdef_et1.mk()); assert_copy(sdef_et1.mk()); } + +const cdef_et2: &(dyn Tr1 + Sync) = &S1; +static sdef_et2: &(dyn Tr1 + Sync) = &S1; +pub fn use_et2() { assert_static(cdef_et2.mk()); assert_static(sdef_et2.mk()); } + +const cdef_et3: &dyn Tr1>>> = { + struct A; + impl Tr1 for A { + type As1 = core::ops::Range; + fn mk(&self) -> Self::As1 { 0..10 } + }; + &A +}; +pub fn use_et3() { + let _0 = cdef_et3.mk().clone(); + let mut s = 0u8; + for _1 in _0 { + let _2 = _1 + 1u8; + s += _2.into(); + } + assert_eq!(s, (0..10).map(|x| x + 1).sum()); +} + +const cdef_et4: &(dyn Tr1 Tr2<'a>> + Sync) = { + #[derive(Copy, Clone)] + struct A; + impl Tr1 for A { + type As1 = A; + fn mk(&self) -> A { A } + } + impl<'a> Tr2<'a> for A { + fn tr2(self) -> &'a Self { &A } + } + &A +}; +static sdef_et4: &(dyn Tr1 Tr2<'a>> + Sync) = cdef_et4; +pub fn use_et4() { assert_forall_tr2(cdef_et4.mk()); assert_forall_tr2(sdef_et4.mk()); } + +fn main() { + let _ = use_et1(); + let _ = use_et2(); + let _ = use_et3(); + let _ = use_et4(); +} diff --git a/src/test/ui/associated-type-bounds/dyn-lcsit.stderr b/src/test/ui/associated-type-bounds/dyn-lcsit.stderr new file mode 100644 index 0000000000000..5fe4818ef8fed --- /dev/null +++ b/src/test/ui/associated-type-bounds/dyn-lcsit.stderr @@ -0,0 +1,6 @@ +warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash + --> $DIR/dyn-lcsit.rs:4:12 + | +LL | #![feature(impl_trait_in_bindings)] + | ^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/src/test/ui/associated-type-bounds/dyn-rpit-and-let.rs b/src/test/ui/associated-type-bounds/dyn-rpit-and-let.rs new file mode 100644 index 0000000000000..f22a6c44cb84d --- /dev/null +++ b/src/test/ui/associated-type-bounds/dyn-rpit-and-let.rs @@ -0,0 +1,73 @@ +// run-pass + +// FIXME: uncomment let binding types below when `impl_trait_in_bindings` feature is fixed. + +#![feature(associated_type_bounds)] + +use std::ops::Add; + +trait Tr1 { type As1; fn mk(&self) -> Self::As1; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } + +fn assert_copy(x: T) { let _x = x; let _x = x; } +fn assert_static(_: T) {} +fn assert_forall_tr2 Tr2<'a>>(_: T) {} + +struct S1; +#[derive(Copy, Clone)] +struct S2; +impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } } + +fn def_et1() -> Box> { + let x /* : Box> */ = Box::new(S1); + x +} +pub fn use_et1() { assert_copy(def_et1().mk()); } + +fn def_et2() -> Box> { + let x /* : Box> */ = Box::new(S1); + x +} +pub fn use_et2() { assert_static(def_et2().mk()); } + +fn def_et3() -> Box>>>> { + struct A; + impl Tr1 for A { + type As1 = core::ops::Range; + fn mk(&self) -> Self::As1 { 0..10 } + }; + let x /* : Box>>>> */ + = Box::new(A); + x +} +pub fn use_et3() { + let _0 = def_et3().mk().clone(); + let mut s = 0u8; + for _1 in _0 { + let _2 = _1 + 1u8; + s += _2.into(); + } + assert_eq!(s, (0..10).map(|x| x + 1).sum()); +} + +fn def_et4() -> Box Tr2<'a>>> { + #[derive(Copy, Clone)] + struct A; + impl Tr1 for A { + type As1 = A; + fn mk(&self) -> A { A } + } + impl<'a> Tr2<'a> for A { + fn tr2(self) -> &'a Self { &A } + } + let x /* : Box Tr2<'a>>> */ = Box::new(A); + x +} +pub fn use_et4() { assert_forall_tr2(def_et4().mk()); } + +fn main() { + let _ = use_et1(); + let _ = use_et2(); + let _ = use_et3(); + let _ = use_et4(); +} diff --git a/src/test/ui/associated-type-bounds/entails-sized-object-safety.rs b/src/test/ui/associated-type-bounds/entails-sized-object-safety.rs new file mode 100644 index 0000000000000..1b3e978594d69 --- /dev/null +++ b/src/test/ui/associated-type-bounds/entails-sized-object-safety.rs @@ -0,0 +1,26 @@ +// compile-pass + +#![feature(associated_type_bounds)] + +trait Tr1: Sized { type As1; } +trait Tr2<'a>: Sized { type As2; } + +trait ObjTr1 { fn foo() -> Self where Self: Tr1; } +fn _assert_obj_safe_1(_: Box) {} + +trait ObjTr2 { fn foo() -> Self where Self: Tr1; } +fn _assert_obj_safe_2(_: Box) {} + +trait ObjTr3 { fn foo() -> Self where Self: Tr1 + 'static + Copy>; } +fn _assert_obj_safe_3(_: Box) {} + +trait ObjTr4 { fn foo() -> Self where Self: Tr1 Tr2<'a>>; } +fn _assert_obj_safe_4(_: Box) {} + +trait ObjTr5 { fn foo() -> Self where for<'a> Self: Tr1>; } +fn _assert_obj_safe_5(_: Box) {} + +trait ObjTr6 { fn foo() -> Self where Self: for<'a> Tr1 Tr2<'b>>>; } +fn _assert_obj_safe_6(_: Box) {} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/enum-bounds.rs b/src/test/ui/associated-type-bounds/enum-bounds.rs new file mode 100644 index 0000000000000..a6b0bb7070b7a --- /dev/null +++ b/src/test/ui/associated-type-bounds/enum-bounds.rs @@ -0,0 +1,122 @@ +// run-pass + +#![feature(associated_type_bounds)] + +trait Tr1 { type As1; } +trait Tr2 { type As2; } +trait Tr3 { type As3; } +trait Tr4<'a> { type As4; } +trait Tr5 { type As5; } + +impl Tr1 for &str { type As1 = bool; } +impl Tr2 for bool { type As2 = u8; } +impl Tr3 for u8 { type As3 = fn() -> u8; } +impl Tr1 for () { type As1 = (usize,); } +impl<'a> Tr4<'a> for (usize,) { type As4 = u8; } +impl Tr5 for bool { type As5 = u16; } + +enum En1> { + Outest(T), + Outer(T::As1), + Inner(::As2), +} + +fn wrap_en1_1(x: T) -> En1 where T: Tr1, T::As1: Tr2 { + En1::Outest(x) +} + +fn wrap_en1_2(x: T::As1) -> En1 where T: Tr1, T::As1: Tr2 { + En1::Outer(x) +} + +fn wrap_en1_3(x: ::As2) -> En1 where T: Tr1, T::As1: Tr2 { + En1::Inner(x) +} + +enum En2>> { + V0(T), + V1(T::As1), + V2(::As2), + V3(<::As2 as Tr3>::As3), +} + +enum En3> { + V0(T), + V1(&'static T::As1), +} + +enum En4<'x1, 'x2, T: Tr1 Tr4<'l>>> { + V0(&'x1 >::As4), + V1(&'x2 >::As4), +} + +enum _En5<'x1, 'x2, T: Tr1 Tr4<'l, As4: Copy>>> { + _V0(&'x1 >::As4), + _V1(&'x2 >::As4), +} + +enum En6 +where + T: Tr1, +{ + V0(T), + V1(::As2), + V2(&'static T::As1), + V3(::As5), +} + +enum _En7<'a, 'b, T> // `::As2: 'a` is implied. +where + T: Tr1, +{ + V0(&'a T), + V1(&'b ::As2), +} + +fn _make_en7<'a, 'b, T>(x: _En7<'a, 'b, T>) +where + T: Tr1, +{ + match x { + _En7::V0(x) => { + let _: &'a T = &x; + }, + _En7::V1(_) => {}, + } +} + +enum EnSelf where Self: Tr1 { + V0(T), + V1(::As1), + V2(<::As1 as Tr2>::As2), +} + +impl Tr1 for EnSelf<&'static str> { type As1 = bool; } + +fn main() { + if let En1::Outest("foo") = wrap_en1_1::<_>("foo") {} else { panic!() }; + if let En1::Outer(true) = wrap_en1_2::<&str>(true) {} else { panic!() }; + if let En1::Inner(24u8) = wrap_en1_3::<&str>(24u8) {} else { panic!() }; + + let _ = En2::<_>::V0("151571"); + let _ = En2::<&str>::V1(false); + let _ = En2::<&str>::V2(42u8); + let _ = En2::<&str>::V3(|| 12u8); + + let _ = En3::<_>::V0("deadbeef"); + let _ = En3::<&str>::V1(&true); + + let f1 = (1,); + let f2 = (2,); + let _ = En4::<()>::V0(&f1.0); + let _ = En4::<()>::V1(&f2.0); + + let _ = En6::<_>::V0("bar"); + let _ = En6::<&str>::V1(24u8); + let _ = En6::<&str>::V2(&false); + let _ = En6::<&str>::V3(12u16); + + let _ = EnSelf::<_>::V0("foo"); + let _ = EnSelf::<&'static str>::V1(true); + let _ = EnSelf::<&'static str>::V2(24u8); +} diff --git a/src/test/ui/associated-type-bounds/existential-type.rs b/src/test/ui/associated-type-bounds/existential-type.rs new file mode 100644 index 0000000000000..87046aec5c4ab --- /dev/null +++ b/src/test/ui/associated-type-bounds/existential-type.rs @@ -0,0 +1,67 @@ +// run-pass + +#![feature(associated_type_bounds)] +#![feature(existential_type)] + +use std::ops::Add; + +trait Tr1 { type As1; fn mk(self) -> Self::As1; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } + +fn assert_copy(x: T) { let _x = x; let _x = x; } +fn assert_static(_: T) {} +fn assert_forall_tr2 Tr2<'a>>(_: T) {} + +struct S1; +#[derive(Copy, Clone)] +struct S2; +impl Tr1 for S1 { type As1 = S2; fn mk(self) -> Self::As1 { S2 } } + +existential type Et1: Tr1; +fn def_et1() -> Et1 { S1 } +pub fn use_et1() { assert_copy(def_et1().mk()); } + +existential type Et2: Tr1; +fn def_et2() -> Et2 { S1 } +pub fn use_et2() { assert_static(def_et2().mk()); } + +existential type Et3: Tr1>>>; +fn def_et3() -> Et3 { + struct A; + impl Tr1 for A { + type As1 = core::ops::Range; + fn mk(self) -> Self::As1 { 0..10 } + }; + A +} +pub fn use_et3() { + let _0 = def_et3().mk().clone(); + let mut s = 0u8; + for _1 in _0 { + let _2 = _1 + 1u8; + s += _2.into(); + } + assert_eq!(s, (0..10).map(|x| x + 1).sum()); +} + +existential type Et4: Tr1 Tr2<'a>>; +fn def_et4() -> Et4 { + #[derive(Copy, Clone)] + struct A; + impl Tr1 for A { + type As1 = A; + fn mk(self) -> A { A } + } + impl<'a> Tr2<'a> for A { + fn tr2(self) -> &'a Self { &A } + } + A +} +pub fn use_et4() { assert_forall_tr2(def_et4().mk()); } + +fn main() { + let _ = use_et1(); + let _ = use_et2(); + let _ = use_et3(); + let _ = use_et4(); +} diff --git a/src/test/ui/associated-type-bounds/fn-apit.rs b/src/test/ui/associated-type-bounds/fn-apit.rs new file mode 100644 index 0000000000000..7e208b4e70d81 --- /dev/null +++ b/src/test/ui/associated-type-bounds/fn-apit.rs @@ -0,0 +1,58 @@ +// run-pass +// aux-build:fn-aux.rs + +#![feature(associated_type_bounds)] + +extern crate fn_aux; + +use fn_aux::*; + +fn apit_bound(beta: impl Beta) -> usize { + desugared_bound(beta) +} + +fn apit_bound_region(beta: impl Beta) -> usize { + desugared_bound_region(beta) +} + +fn apit_bound_multi( + beta: impl Copy + Beta +) -> usize { + desugared_bound_multi(beta) +} + +fn apit_bound_region_forall( + beta: impl Beta Epsilon<'a>> +) -> usize { + desugared_bound_region_forall(beta) +} + +fn apit_bound_region_forall2( + beta: impl Beta Epsilon<'a, Zeta: Eta>> +) -> usize { + desugared_bound_region_forall2(beta) +} + +fn apit_bound_nested( + beta: impl Beta> +) -> usize { + desugared_bound_nested(beta) +} + +fn apit_bound_nested2( + beta: impl Beta> +) -> usize { + desugared_bound_nested(beta) +} + +fn main() { + let beta = BetaType; + let _gamma = beta.gamma(); + + assert_eq!(42, apit_bound(beta)); + assert_eq!(24, apit_bound_region(beta)); + assert_eq!(42 + 24 + 1337, apit_bound_multi(beta)); + assert_eq!(7331 * 2, apit_bound_region_forall(beta)); + assert_eq!(42 + 1337, apit_bound_nested(beta)); + assert_eq!(42 + 1337, apit_bound_nested2(beta)); +} diff --git a/src/test/ui/associated-type-bounds/fn-aux.rs b/src/test/ui/associated-type-bounds/fn-aux.rs new file mode 100644 index 0000000000000..434bdbe996c63 --- /dev/null +++ b/src/test/ui/associated-type-bounds/fn-aux.rs @@ -0,0 +1,12 @@ +// run-pass +// aux-build:fn-aux.rs + +#![feature(associated_type_bounds)] + +extern crate fn_aux; + +use fn_aux::*; + +fn main() { + desugared(); +} diff --git a/src/test/ui/associated-type-bounds/fn-dyn-apit.rs b/src/test/ui/associated-type-bounds/fn-dyn-apit.rs new file mode 100644 index 0000000000000..9ff4a50e1e6e4 --- /dev/null +++ b/src/test/ui/associated-type-bounds/fn-dyn-apit.rs @@ -0,0 +1,60 @@ +// run-pass +// aux-build:fn-dyn-aux.rs + +#![feature(associated_type_bounds)] + +extern crate fn_dyn_aux; + +use fn_dyn_aux::*; + +// ATB, APIT (dyn trait): + +fn dyn_apit_bound(beta: &dyn Beta) -> usize { + desugared_bound(beta) +} + +fn dyn_apit_bound_region(beta: &dyn Beta) -> usize { + desugared_bound_region(beta) +} + +fn dyn_apit_bound_multi( + beta: &(dyn Beta + Send) +) -> usize { + desugared_bound_multi(beta) +} + +fn dyn_apit_bound_region_forall( + beta: &dyn Beta Epsilon<'a>> +) -> usize { + desugared_bound_region_forall(beta) +} + +fn dyn_apit_bound_region_forall2( + beta: &dyn Beta Epsilon<'a, Zeta: Eta>> +) -> usize { + desugared_bound_region_forall2(beta) +} + +fn dyn_apit_bound_nested( + beta: &dyn Beta> +) -> usize { + desugared_bound_nested(beta) +} + +fn dyn_apit_bound_nested2( + beta: &dyn Beta> +) -> usize { + desugared_bound_nested(beta) +} + +fn main() { + let beta = BetaType; + let _gamma = beta.gamma(); + + assert_eq!(42, dyn_apit_bound(&beta)); + assert_eq!(24, dyn_apit_bound_region(&beta)); + assert_eq!(42 + 24 + 1337, dyn_apit_bound_multi(&beta)); + assert_eq!(7331 * 2, dyn_apit_bound_region_forall(&beta)); + assert_eq!(42 + 1337, dyn_apit_bound_nested(&beta)); + assert_eq!(42 + 1337, dyn_apit_bound_nested2(&beta)); +} diff --git a/src/test/ui/associated-type-bounds/fn-inline.rs b/src/test/ui/associated-type-bounds/fn-inline.rs new file mode 100644 index 0000000000000..7b188763b7a5e --- /dev/null +++ b/src/test/ui/associated-type-bounds/fn-inline.rs @@ -0,0 +1,62 @@ +// run-pass +// aux-build:fn-aux.rs + +#![feature(associated_type_bounds)] + +extern crate fn_aux; + +use fn_aux::*; + +// ATB, Type parameters, Inline bounds: + +fn inline_bound>(beta: B) -> usize { + desugared_bound(beta) +} + +fn inline_bound_region>(beta: B) -> usize { + desugared_bound_region(beta) +} + +fn inline_bound_multi>( + beta: B +) -> usize { + desugared_bound_multi(beta) +} + +fn inline_bound_region_specific<'a, B: Beta>>( + gamma: &'a B::Gamma +) -> usize { + desugared_bound_region_specific::(gamma) +} + +fn inline_bound_region_forall Epsilon<'a>>>( + beta: B +) -> usize { + desugared_bound_region_forall(beta) +} + +fn inline_bound_region_forall2 Epsilon<'a, Zeta: Eta>>>( + beta: B +) -> usize { + desugared_bound_region_forall2(beta) +} + +fn inline_bound_nested>>( + beta: B +) -> usize { + desugared_bound_nested(beta) +} + +fn main() { + let beta = BetaType; + let gamma = beta.gamma(); + + assert_eq!(42, inline_bound(beta)); + assert_eq!(24, inline_bound_region(beta)); + assert_eq!(42 + 24 + 1337, inline_bound_multi(beta)); + assert_eq!(7331, inline_bound_region_specific::(&gamma)); + assert_eq!(7331 * 2, inline_bound_region_forall(beta)); + // FIXME: requires lazy normalization. + // assert_eq!(7331 * 2, inline_bound_region_forall2(beta)); + assert_eq!(42 + 1337, inline_bound_nested(beta)); +} diff --git a/src/test/ui/associated-type-bounds/fn-where.rs b/src/test/ui/associated-type-bounds/fn-where.rs new file mode 100644 index 0000000000000..60d7149a56f25 --- /dev/null +++ b/src/test/ui/associated-type-bounds/fn-where.rs @@ -0,0 +1,78 @@ +// run-pass +// aux-build:fn-aux.rs + +#![feature(associated_type_bounds)] + +extern crate fn_aux; + +use fn_aux::*; + +// ATB, Type parameters, Where-clauses: + +fn where_bound(beta: B) -> usize +where + B: Beta +{ + desugared_bound(beta) +} + +fn where_bound_region(beta: B) -> usize +where + B: Beta +{ + desugared_bound_region(beta) +} + +fn where_bound_multi(beta: B) -> usize +where + B: Copy + Beta, +{ + desugared_bound_multi(beta) +} + +fn where_bound_region_specific<'a, B>(gamma: &'a B::Gamma) -> usize +where + B: Beta>, +{ + desugared_bound_region_specific::(gamma) +} + +fn where_bound_region_forall(beta: B) -> usize +where + B: Beta Epsilon<'a>>, +{ + desugared_bound_region_forall(beta) +} + +fn where_bound_region_forall2(beta: B) -> usize +where + B: Beta Epsilon<'a, Zeta: Eta>>, +{ + desugared_bound_region_forall2(beta) +} + +fn where_contraint_region_forall(beta: B) -> usize +where + for<'a> &'a B: Beta, +{ + desugared_contraint_region_forall(beta) +} + +fn where_bound_nested(beta: B) -> usize +where + B: Beta>, +{ + desugared_bound_nested(beta) +} + +fn main() { + let beta = BetaType; + let gamma = beta.gamma(); + + assert_eq!(42, where_bound(beta)); + assert_eq!(24, where_bound_region(beta)); + assert_eq!(42 + 24 + 1337, where_bound_multi(beta)); + assert_eq!(7331, where_bound_region_specific::(&gamma)); + assert_eq!(7331 * 2, where_bound_region_forall::(beta)); + assert_eq!(42 + 1337, where_bound_nested::(beta)); +} diff --git a/src/test/ui/associated-type-bounds/fn-wrap-apit.rs b/src/test/ui/associated-type-bounds/fn-wrap-apit.rs new file mode 100644 index 0000000000000..23790d416e1f7 --- /dev/null +++ b/src/test/ui/associated-type-bounds/fn-wrap-apit.rs @@ -0,0 +1,64 @@ +// run-pass +// aux-build:fn-aux.rs + +#![feature(associated_type_bounds)] + +extern crate fn_aux; + +use fn_aux::*; + +// ATB, APIT + Wrap: + +struct Wrap(T); + +fn wrap_apit_bound(beta: Wrap>) -> usize { + desugared_bound(beta.0) +} + +fn wrap_apit_bound_region(beta: Wrap>) -> usize { + desugared_bound_region(beta.0) +} + +fn wrap_apit_bound_multi( + beta: Wrap> +) -> usize { + desugared_bound_multi(beta.0) +} + +fn wrap_apit_bound_region_forall( + beta: Wrap Epsilon<'a>>> +) -> usize { + desugared_bound_region_forall(beta.0) +} + +fn wrap_apit_bound_region_forall2( + beta: Wrap Epsilon<'a, Zeta: Eta>>> +) -> usize { + desugared_bound_region_forall2(beta.0) +} + +fn wrap_apit_bound_nested( + beta: Wrap>> +) -> usize { + desugared_bound_nested(beta.0) +} + +fn wrap_apit_bound_nested2( + beta: Wrap>> +) -> usize { + desugared_bound_nested(beta.0) +} + +fn main() { + let beta = BetaType; + let _gamma = beta.gamma(); + + assert_eq!(42, wrap_apit_bound(Wrap(beta))); + assert_eq!(24, wrap_apit_bound_region(Wrap(beta))); + assert_eq!(42 + 24 + 1337, wrap_apit_bound_multi(Wrap(beta))); + assert_eq!(7331 * 2, wrap_apit_bound_region_forall(Wrap(beta))); + // FIXME: requires lazy normalization. + // assert_eq!(7331 * 2, wrap_apit_bound_region_forall2(Wrap(beta))); + assert_eq!(42 + 1337, wrap_apit_bound_nested(Wrap(beta))); + assert_eq!(42 + 1337, wrap_apit_bound_nested2(Wrap(beta))); +} diff --git a/src/test/ui/associated-type-bounds/implied-region-constraints.nll.stderr b/src/test/ui/associated-type-bounds/implied-region-constraints.nll.stderr new file mode 100644 index 0000000000000..32d099fce759e --- /dev/null +++ b/src/test/ui/associated-type-bounds/implied-region-constraints.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/implied-region-constraints.rs:19:56 + | +LL | fn _bad_st<'a, 'b, T>(x: St<'a, 'b, T>) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _failure_proves_not_implied_outlives_region_b: &'b T = &x.f0; + | ^^^^^ type annotation requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/implied-region-constraints.rs:40:64 + | +LL | fn _bad_en7<'a, 'b, T>(x: En7<'a, 'b, T>) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _failure_proves_not_implied_outlives_region_b: &'b T = &x; + | ^^^^^ type annotation requires that `'a` must outlive `'b` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/associated-type-bounds/implied-region-constraints.rs b/src/test/ui/associated-type-bounds/implied-region-constraints.rs new file mode 100644 index 0000000000000..4dbaab50a61db --- /dev/null +++ b/src/test/ui/associated-type-bounds/implied-region-constraints.rs @@ -0,0 +1,47 @@ +// compile-fail + +#![feature(associated_type_bounds)] + +trait Tr1 { type As1; } +trait Tr2 { type As2; } + +struct St<'a, 'b, T: Tr1> { // `T: 'b` is *not* implied! + f0: &'a T, // `T: 'a` is implied. + f1: &'b ::As2, // `::As2: 'a` is implied. +} + +fn _bad_st<'a, 'b, T>(x: St<'a, 'b, T>) +where + T: Tr1, + T::As1: Tr2, +{ + // This should fail because `T: 'b` is not implied from `WF(St<'a, 'b, T>)`. + let _failure_proves_not_implied_outlives_region_b: &'b T = &x.f0; + //~^ ERROR lifetime mismatch [E0623] +} + +enum En7<'a, 'b, T> // `::As2: 'a` is implied. +where + T: Tr1, + T::As1: Tr2, +{ + V0(&'a T), + V1(&'b ::As2), +} + +fn _bad_en7<'a, 'b, T>(x: En7<'a, 'b, T>) +where + T: Tr1, + T::As1: Tr2, +{ + match x { + En7::V0(x) => { + // Also fails for the same reason as above: + let _failure_proves_not_implied_outlives_region_b: &'b T = &x; + //~^ ERROR lifetime mismatch [E0623] + }, + En7::V1(_) => {}, + } +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/implied-region-constraints.stderr b/src/test/ui/associated-type-bounds/implied-region-constraints.stderr new file mode 100644 index 0000000000000..9968f3e8bac5e --- /dev/null +++ b/src/test/ui/associated-type-bounds/implied-region-constraints.stderr @@ -0,0 +1,20 @@ +error[E0623]: lifetime mismatch + --> $DIR/implied-region-constraints.rs:19:64 + | +LL | fn _bad_st<'a, 'b, T>(x: St<'a, 'b, T>) + | ------------- this type is declared with multiple lifetimes... +... +LL | let _failure_proves_not_implied_outlives_region_b: &'b T = &x.f0; + | ^^^^^ ...but data with one lifetime flows into the other here + +error[E0623]: lifetime mismatch + --> $DIR/implied-region-constraints.rs:40:72 + | +LL | fn _bad_en7<'a, 'b, T>(x: En7<'a, 'b, T>) + | -------------- this type is declared with multiple lifetimes... +... +LL | let _failure_proves_not_implied_outlives_region_b: &'b T = &x; + | ^^ ...but data with one lifetime flows into the other here + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs new file mode 100644 index 0000000000000..1257dc6e94b39 --- /dev/null +++ b/src/test/ui/associated-type-bounds/inside-adt.rs @@ -0,0 +1,36 @@ +// compile-fail +// ignore-tidy-linelength +// error-pattern:could not find defining uses + +#![feature(associated_type_bounds)] +#![feature(untagged_unions)] + +struct S1 { f: dyn Iterator } +//~^ associated type bounds are not allowed within structs, enums, or unions +//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +struct S2 { f: Box> } +//~^ associated type bounds are not allowed within structs, enums, or unions +//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +struct S3 { f: dyn Iterator } +//~^ associated type bounds are not allowed within structs, enums, or unions +//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] + +enum E1 { V(dyn Iterator) } +//~^ associated type bounds are not allowed within structs, enums, or unions +//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +enum E2 { V(Box>) } +//~^ associated type bounds are not allowed within structs, enums, or unions +//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +enum E3 { V(dyn Iterator) } +//~^ associated type bounds are not allowed within structs, enums, or unions +//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] + +union U1 { f: dyn Iterator } +//~^ associated type bounds are not allowed within structs, enums, or unions +//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +union U2 { f: Box> } +//~^ associated type bounds are not allowed within structs, enums, or unions +//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] +union U3 { f: dyn Iterator } +//~^ associated type bounds are not allowed within structs, enums, or unions +//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191] diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr new file mode 100644 index 0000000000000..7bdd71b8296ff --- /dev/null +++ b/src/test/ui/associated-type-bounds/inside-adt.stderr @@ -0,0 +1,79 @@ +error: associated type bounds are not allowed within structs, enums, or unions + --> $DIR/inside-adt.rs:8:29 + | +LL | struct S1 { f: dyn Iterator } + | ^^^^^^^^^^ + +error: associated type bounds are not allowed within structs, enums, or unions + --> $DIR/inside-adt.rs:11:33 + | +LL | struct S2 { f: Box> } + | ^^^^^^^^^^ + +error: associated type bounds are not allowed within structs, enums, or unions + --> $DIR/inside-adt.rs:14:29 + | +LL | struct S3 { f: dyn Iterator } + | ^^^^^^^^^^^^^ + +error: associated type bounds are not allowed within structs, enums, or unions + --> $DIR/inside-adt.rs:18:26 + | +LL | enum E1 { V(dyn Iterator) } + | ^^^^^^^^^^ + +error: associated type bounds are not allowed within structs, enums, or unions + --> $DIR/inside-adt.rs:21:30 + | +LL | enum E2 { V(Box>) } + | ^^^^^^^^^^ + +error: associated type bounds are not allowed within structs, enums, or unions + --> $DIR/inside-adt.rs:24:26 + | +LL | enum E3 { V(dyn Iterator) } + | ^^^^^^^^^^^^^ + +error: associated type bounds are not allowed within structs, enums, or unions + --> $DIR/inside-adt.rs:28:28 + | +LL | union U1 { f: dyn Iterator } + | ^^^^^^^^^^ + +error: associated type bounds are not allowed within structs, enums, or unions + --> $DIR/inside-adt.rs:31:32 + | +LL | union U2 { f: Box> } + | ^^^^^^^^^^ + +error: associated type bounds are not allowed within structs, enums, or unions + --> $DIR/inside-adt.rs:34:28 + | +LL | union U3 { f: dyn Iterator } + | ^^^^^^^^^^^^^ + +error[E0601]: `main` function not found in crate `inside_adt` + | + = note: consider adding a `main` function to `$DIR/inside-adt.rs` + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: could not find defining uses + +error: aborting due to 19 previous errors + +For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/associated-type-bounds/lcsit.rs b/src/test/ui/associated-type-bounds/lcsit.rs new file mode 100644 index 0000000000000..85b6e804b4ef6 --- /dev/null +++ b/src/test/ui/associated-type-bounds/lcsit.rs @@ -0,0 +1,78 @@ +// run-pass + +#![feature(associated_type_bounds)] +#![feature(impl_trait_in_bindings)] + +#![allow(non_upper_case_globals)] + +use std::ops::Add; + +trait Tr1 { type As1; fn mk(&self) -> Self::As1; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } + +fn assert_copy(x: T) { let _x = x; let _x = x; } +fn assert_static(_: T) {} +fn assert_forall_tr2 Tr2<'a>>(_: T) {} + +#[derive(Copy, Clone)] +struct S1; +#[derive(Copy, Clone)] +struct S2; +impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } } + +const cdef_et1: impl Copy + Tr1 = { + let x: impl Copy + Tr1 = S1; + x +}; +static sdef_et1: impl Copy + Tr1 = cdef_et1; +pub fn use_et1() { assert_copy(cdef_et1.mk()); assert_copy(sdef_et1.mk()); } + +const cdef_et2: impl Tr1 = { + let x: impl Tr1 = S1; + x +}; +static sdef_et2: impl Tr1 = cdef_et2; +pub fn use_et2() { assert_static(cdef_et2.mk()); assert_static(sdef_et2.mk()); } + +const cdef_et3: impl Tr1>>> = { + struct A; + impl Tr1 for A { + type As1 = core::ops::Range; + fn mk(&self) -> Self::As1 { 0..10 } + }; + let x: impl Tr1>>> = A; + x +}; +pub fn use_et3() { + let _0 = cdef_et3.mk().clone(); + let mut s = 0u8; + for _1 in _0 { + let _2 = _1 + 1u8; + s += _2.into(); + } + assert_eq!(s, (0..10).map(|x| x + 1).sum()); +} + +const cdef_et4: impl Copy + Tr1 Tr2<'a>> = { + #[derive(Copy, Clone)] + struct A; + impl Tr1 for A { + type As1 = A; + fn mk(&self) -> A { A } + } + impl<'a> Tr2<'a> for A { + fn tr2(self) -> &'a Self { &A } + } + let x: impl Copy + Tr1 Tr2<'a>> = A; + x +}; + +static sdef_et4: impl Copy + Tr1 Tr2<'a>> = cdef_et4; +pub fn use_et4() { assert_forall_tr2(cdef_et4.mk()); assert_forall_tr2(sdef_et4.mk()); } + +fn main() { + let _ = use_et1(); + let _ = use_et2(); + let _ = use_et3(); + let _ = use_et4(); +} diff --git a/src/test/ui/associated-type-bounds/lcsit.stderr b/src/test/ui/associated-type-bounds/lcsit.stderr new file mode 100644 index 0000000000000..8fda11beddc4f --- /dev/null +++ b/src/test/ui/associated-type-bounds/lcsit.stderr @@ -0,0 +1,6 @@ +warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash + --> $DIR/lcsit.rs:4:12 + | +LL | #![feature(impl_trait_in_bindings)] + | ^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/src/test/ui/associated-type-bounds/rpit.rs b/src/test/ui/associated-type-bounds/rpit.rs new file mode 100644 index 0000000000000..7b640d5a457df --- /dev/null +++ b/src/test/ui/associated-type-bounds/rpit.rs @@ -0,0 +1,64 @@ +// run-pass + +#![feature(associated_type_bounds)] + +use std::ops::Add; + +trait Tr1 { type As1; fn mk(self) -> Self::As1; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } + +fn assert_copy(x: T) { let _x = x; let _x = x; } +fn assert_static(_: T) {} +fn assert_forall_tr2 Tr2<'a>>(_: T) {} + +struct S1; +#[derive(Copy, Clone)] +struct S2; +impl Tr1 for S1 { type As1 = S2; fn mk(self) -> Self::As1 { S2 } } + +fn def_et1() -> impl Tr1 { S1 } +pub fn use_et1() { assert_copy(def_et1().mk()); } + +fn def_et2() -> impl Tr1 { S1 } +pub fn use_et2() { assert_static(def_et2().mk()); } + +fn def_et3() -> impl Tr1>>> { + struct A; + impl Tr1 for A { + type As1 = core::ops::Range; + fn mk(self) -> Self::As1 { 0..10 } + }; + A +} + +pub fn use_et3() { + let _0 = def_et3().mk().clone(); + let mut s = 0u8; + for _1 in _0 { + let _2 = _1 + 1u8; + s += _2.into(); + } + assert_eq!(s, (0..10).map(|x| x + 1).sum()); +} + +fn def_et4() -> impl Tr1 Tr2<'a>> { + #[derive(Copy, Clone)] + struct A; + impl Tr1 for A { + type As1 = A; + fn mk(self) -> A { A } + } + impl<'a> Tr2<'a> for A { + fn tr2(self) -> &'a Self { &A } + } + A +} + +pub fn use_et4() { assert_forall_tr2(def_et4().mk()); } + +fn main() { + let _ = use_et1(); + let _ = use_et2(); + let _ = use_et3(); + let _ = use_et4(); +} diff --git a/src/test/ui/associated-type-bounds/struct-bounds.rs b/src/test/ui/associated-type-bounds/struct-bounds.rs new file mode 100644 index 0000000000000..2d189cd66724a --- /dev/null +++ b/src/test/ui/associated-type-bounds/struct-bounds.rs @@ -0,0 +1,115 @@ +// run-pass + +#![feature(associated_type_bounds)] + +trait Tr1 { type As1; } +trait Tr2 { type As2; } +trait Tr3 {} +trait Tr4<'a> { type As4; } +trait Tr5 { type As5; } + +impl Tr1 for &str { type As1 = bool; } +impl Tr2 for bool { type As2 = u8; } +impl Tr3 for u8 {} +impl Tr1 for () { type As1 = (usize,); } +impl<'a> Tr4<'a> for (usize,) { type As4 = u8; } +impl Tr5 for bool { type As5 = u16; } + +struct St1> { + outest: T, + outer: T::As1, + inner: ::As2, +} + +fn unwrap_1_st1>(x: St1) -> (T, T::As1, ::As2) { + (x.outest, x.outer, x.inner) +} + +fn unwrap_2_st1(x: St1) -> (T, T::As1, ::As2) +where + T: Tr1, + T::As1: Tr2, +{ + unwrap_1_st1(x) +} + +struct St2>> { + outest: T, + outer: T::As1, + inner: ::As2, +} + +struct St3> { + outest: T, + outer: &'static T::As1, +} + +struct St4<'x1, 'x2, T: Tr1 Tr4<'l>>> { + f1: &'x1 >::As4, + f2: &'x2 >::As4, +} + +struct St5<'x1, 'x2, T: Tr1 Tr4<'l, As4: Copy>>> { + f1: &'x1 >::As4, + f2: &'x2 >::As4, +} + +struct St6 +where + T: Tr1, +{ + f0: T, + f1: ::As2, + f2: &'static T::As1, + f3: ::As5, +} + +struct St7<'a, 'b, T> // `::As2: 'a` is implied. +where + T: Tr1, +{ + f0: &'a T, + f1: &'b ::As2, +} + +fn _use_st7<'a, 'b, T>(x: St7<'a, 'b, T>) +where + T: Tr1, + T::As1: Tr2, +{ + let _: &'a T = &x.f0; +} + +struct StSelf where Self: Tr1 { + f2: <::As1 as Tr2>::As2, +} + +impl Tr1 for StSelf<&'static str> { type As1 = bool; } + +fn main() { + let st1 = St1 { outest: "foo", outer: true, inner: 42u8 }; + assert_eq!(("foo", true, 42), unwrap_1_st1(st1)); + + let _ = St2 { outest: "foo", outer: true, inner: 42u8 }; + + let _ = St3 { outest: "foo", outer: &true }; + + let f1 = (1,); + let f2 = (2,); + let st4 = St4::<()> { f1: &f1.0, f2: &f2.0, }; + assert_eq!((&1, &2), (st4.f1, st4.f2)); + + // FIXME: requires lazy normalization. + /* + let f1 = (1,); + let f2 = (2,); + let st5 = St5::<()> { f1: &f1.0, f2: &f2.0, }; + assert_eq!((&1, &2), (st5.f1, st5.f2)); + */ + + let st6 = St6 { f0: "bar", f1: 24u8, f2: &true, f3: 12u16, }; + assert_eq!(("bar", 24, &true, 12), (st6.f0, st6.f1, st6.f2, st6.f3)); + + let stself = StSelf::<&'static str> { f2: 42u8 }; + assert_eq!(stself.f2, 42u8); +} diff --git a/src/test/ui/associated-type-bounds/trait-params.rs b/src/test/ui/associated-type-bounds/trait-params.rs new file mode 100644 index 0000000000000..a9081d50cfc5d --- /dev/null +++ b/src/test/ui/associated-type-bounds/trait-params.rs @@ -0,0 +1,116 @@ +// compile-pass + +#![feature(associated_type_bounds)] + +use std::iter::Once; +use std::ops::Range; + +pub trait Three { type A; type B; type C; } +pub fn assert_three() {} +pub fn assert_iterator() {} +pub fn assert_copy() {} +pub fn assert_static() {} +pub fn assert_send() {} +pub fn assert_forall_into Into<&'a u8>>() {} + +struct A; struct B; +impl<'a> Into<&'a u8> for A { fn into(self) -> &'a u8 { &0 } } +impl Three for B { type A = Range; type B = Range; type C = Range; } + +trait Case1 +where + A: Iterator, + B: Iterator, + C: Iterator, + D: Iterator Into<&'a u8>>, + E: Three, B: Iterator, C: Iterator>, + Self: Three, +{ + fn _a() { + assert_iterator::(); + assert_copy::(); + } + fn _b() { + assert_iterator::(); + assert_static::(); + } + fn _c() { + assert_iterator::(); + assert_copy::(); + assert_static::(); + assert_send::(); + } + fn _d() { + assert_iterator::(); + assert_forall_into::(); + } + fn _e() { + assert_three::(); + assert_iterator::(); + assert_iterator::(); + assert_iterator::(); + assert_copy::<::Item>(); + assert_copy::<::Item>(); + assert_copy::<::Item>(); + } + fn _self() { + assert_three::(); + assert_copy::(); + assert_static::(); + assert_send::(); + } +} + +struct DataCase1; +impl Three for DataCase1 { type A = u8; type B = u8; type C = u8; } +impl Case1, Range, Range, Once, B> for DataCase1 {} + +trait Case2< + A: Iterator, + B: Iterator, + C: Iterator, + D: Iterator Into<&'a u8>>, + E: Three, B: Iterator, C: Iterator>, +>: + Three +{ + fn _a() { + assert_iterator::(); + assert_copy::(); + } + fn _b() { + assert_iterator::(); + assert_static::(); + } + fn _c() { + assert_iterator::(); + assert_copy::(); + assert_static::(); + assert_send::(); + } + fn _d() { + assert_iterator::(); + assert_forall_into::(); + } + fn _e() { + assert_three::(); + assert_iterator::(); + assert_iterator::(); + assert_iterator::(); + assert_copy::<::Item>(); + assert_copy::<::Item>(); + assert_copy::<::Item>(); + } + fn _self() { + assert_three::(); + assert_copy::(); + assert_static::(); + assert_send::(); + } +} + +struct DataCase2; +impl Three for DataCase2 { type A = u8; type B = u8; type C = u8; } +impl Case2, Range, Range, Once, B> for DataCase2 {} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/type-alias.rs b/src/test/ui/associated-type-bounds/type-alias.rs new file mode 100644 index 0000000000000..1602fdd275a2e --- /dev/null +++ b/src/test/ui/associated-type-bounds/type-alias.rs @@ -0,0 +1,19 @@ +// compile-pass + +#![feature(associated_type_bounds)] + +type _TaWhere1 where T: Iterator = T; +type _TaWhere2 where T: Iterator = T; +type _TaWhere3 where T: Iterator = T; +type _TaWhere4 where T: Iterator = T; +type _TaWhere5 where T: Iterator Into<&'a u8>> = T; +type _TaWhere6 where T: Iterator> = T; + +type _TaInline1> = T; +type _TaInline2> = T; +type _TaInline3> = T; +type _TaInline4> = T; +type _TaInline5 Into<&'a u8>>> = T; +type _TaInline6>> = T; + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/type-alias.stderr b/src/test/ui/associated-type-bounds/type-alias.stderr new file mode 100644 index 0000000000000..b93fc393ae32c --- /dev/null +++ b/src/test/ui/associated-type-bounds/type-alias.stderr @@ -0,0 +1,97 @@ +warning: where clauses are not enforced in type aliases + --> $DIR/type-alias.rs:5:25 + | +LL | type _TaWhere1 where T: Iterator = T; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: #[warn(type_alias_bounds)] on by default + = help: the clause will not be checked when the type alias is used, and should be removed + +warning: where clauses are not enforced in type aliases + --> $DIR/type-alias.rs:6:25 + | +LL | type _TaWhere2 where T: Iterator = T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the clause will not be checked when the type alias is used, and should be removed + +warning: where clauses are not enforced in type aliases + --> $DIR/type-alias.rs:7:25 + | +LL | type _TaWhere3 where T: Iterator = T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the clause will not be checked when the type alias is used, and should be removed + +warning: where clauses are not enforced in type aliases + --> $DIR/type-alias.rs:8:25 + | +LL | type _TaWhere4 where T: Iterator = T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the clause will not be checked when the type alias is used, and should be removed + +warning: where clauses are not enforced in type aliases + --> $DIR/type-alias.rs:9:25 + | +LL | type _TaWhere5 where T: Iterator Into<&'a u8>> = T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the clause will not be checked when the type alias is used, and should be removed + +warning: where clauses are not enforced in type aliases + --> $DIR/type-alias.rs:10:25 + | +LL | type _TaWhere6 where T: Iterator> = T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the clause will not be checked when the type alias is used, and should be removed + +warning: bounds on generic parameters are not enforced in type aliases + --> $DIR/type-alias.rs:12:20 + | +LL | type _TaInline1> = T; + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: the bound will not be checked when the type alias is used, and should be removed + +warning: bounds on generic parameters are not enforced in type aliases + --> $DIR/type-alias.rs:13:20 + | +LL | type _TaInline2> = T; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the bound will not be checked when the type alias is used, and should be removed + +warning: bounds on generic parameters are not enforced in type aliases + --> $DIR/type-alias.rs:14:20 + | +LL | type _TaInline3> = T; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the bound will not be checked when the type alias is used, and should be removed + +warning: bounds on generic parameters are not enforced in type aliases + --> $DIR/type-alias.rs:15:20 + | +LL | type _TaInline4> = T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the bound will not be checked when the type alias is used, and should be removed + +warning: bounds on generic parameters are not enforced in type aliases + --> $DIR/type-alias.rs:16:20 + | +LL | type _TaInline5 Into<&'a u8>>> = T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the bound will not be checked when the type alias is used, and should be removed + +warning: bounds on generic parameters are not enforced in type aliases + --> $DIR/type-alias.rs:17:20 + | +LL | type _TaInline6>> = T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the bound will not be checked when the type alias is used, and should be removed + diff --git a/src/test/ui/associated-type-bounds/union-bounds.rs b/src/test/ui/associated-type-bounds/union-bounds.rs new file mode 100644 index 0000000000000..ce482fff401c8 --- /dev/null +++ b/src/test/ui/associated-type-bounds/union-bounds.rs @@ -0,0 +1,123 @@ +// run-pass + +#![feature(associated_type_bounds)] +#![feature(untagged_unions)] + +#![allow(unions_with_drop_fields, unused_assignments)] + +trait Tr1 { type As1; } +trait Tr2 { type As2; } +trait Tr3 { type As3; } +trait Tr4<'a> { type As4; } +trait Tr5 { type As5; } + +impl Tr1 for &str { type As1 = bool; } +impl Tr2 for bool { type As2 = u8; } +impl Tr3 for u8 { type As3 = fn() -> u8; } +impl Tr1 for () { type As1 = (usize,); } +impl<'a> Tr4<'a> for (usize,) { type As4 = u8; } +impl Tr5 for bool { type As5 = u16; } + +union Un1> { + outest: T, + outer: T::As1, + inner: ::As2, +} + +union Un2>> { + outest: T, + outer: T::As1, + inner: ::As2, +} + +union Un3> { + outest: T, + outer: &'static T::As1, +} + +union Un4<'x1, 'x2, T: Tr1 Tr4<'l>>> { + f1: &'x1 >::As4, + f2: &'x2 >::As4, +} + +union _Un5<'x1, 'x2, T: Tr1 Tr4<'l, As4: Copy>>> { + f1: &'x1 >::As4, + f2: &'x2 >::As4, +} + +union Un6 +where + T: Tr1, +{ + f0: T, + f1: ::As2, + f2: &'static T::As1, + f3: ::As5, +} + +union _Un7<'a, 'b, T> // `::As2: 'a` is implied. +where + T: Tr1, +{ + f0: &'a T, + f1: &'b ::As2, +} + +unsafe fn _use_un7<'a, 'b, T>(x: _Un7<'a, 'b, T>) +where + T: Tr1, + T::As1: Tr2, +{ + let _: &'a T = &x.f0; +} + +union UnSelf where Self: Tr1 { + f0: T, + f1: ::As1, + f2: <::As1 as Tr2>::As2, +} + +impl Tr1 for UnSelf<&'static str> { type As1 = bool; } + +fn main() { + let mut un1 = Un1 { outest: "foo" }; + un1 = Un1 { outer: true }; + assert_eq!(unsafe { un1.outer }, true); + un1 = Un1 { inner: 42u8 }; + assert_eq!(unsafe { un1.inner }, 42u8); + + let mut un2 = Un2 { outest: "bar" }; + assert_eq!(unsafe { un2.outest }, "bar"); + un2 = Un2 { outer: true }; + assert_eq!(unsafe { un2.outer }, true); + un2 = Un2 { inner: 42u8 }; + assert_eq!(unsafe { un2.inner }, 42u8); + + let mut un3 = Un3 { outest: "baz" }; + assert_eq!(unsafe { un3.outest }, "baz"); + un3 = Un3 { outer: &true }; + assert_eq!(unsafe { *un3.outer }, true); + + let f1 = (1,); + let f2 = (2,); + let mut un4 = Un4::<()> { f1: &f1.0 }; + assert_eq!(1, unsafe { *un4.f1 }); + un4 = Un4 { f2: &f2.0 }; + assert_eq!(2, unsafe { *un4.f2 }); + + let mut un6 = Un6 { f0: "bar" }; + assert_eq!(unsafe { un6.f0 }, "bar"); + un6 = Un6 { f1: 24u8 }; + assert_eq!(unsafe { un6.f1 }, 24u8); + un6 = Un6 { f2: &true }; + assert_eq!(unsafe { un6.f2 }, &true); + un6 = Un6 { f3: 12u16 }; + assert_eq!(unsafe { un6.f3 }, 12u16); + + let mut unself = UnSelf::<_> { f0: "selfish" }; + assert_eq!(unsafe { unself.f0 }, "selfish"); + unself = UnSelf { f1: true }; + assert_eq!(unsafe { unself.f1 }, true); + unself = UnSelf { f2: 24u8 }; + assert_eq!(unsafe { unself.f2 }, 24u8); +} diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs index df9143d685ff3..7a678445796e6 100644 --- a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs +++ b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs @@ -20,7 +20,7 @@ fn dent(c: C, color: C::Color) { //~^ ERROR ambiguous associated type `Color` in bounds of `C` } -fn dent_object(c: BoxCar) { +fn dent_object(c: dyn BoxCar) { //~^ ERROR ambiguous associated type //~| ERROR the value of the associated type `Color` (from the trait `Vehicle`) must be specified } diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr index 0994dc87c994b..6118ebef125a5 100644 --- a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr +++ b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr @@ -11,7 +11,7 @@ LL | fn dent(c: C, color: C::Color) { | ^^^^^^^^ ambiguous associated type `Color` error[E0221]: ambiguous associated type `Color` in bounds of `BoxCar` - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:33 + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:37 | LL | type Color; | ----------- ambiguous `Color` from `Vehicle` @@ -19,8 +19,8 @@ LL | type Color; LL | type Color; | ----------- ambiguous `Color` from `Box` ... -LL | fn dent_object(c: BoxCar) { - | ^^^^^^^^^^^ ambiguous associated type `Color` +LL | fn dent_object(c: dyn BoxCar) { + | ^^^^^^^^^^^ ambiguous associated type `Color` error[E0191]: the value of the associated type `Color` (from the trait `Vehicle`) must be specified --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:26 @@ -28,8 +28,8 @@ error[E0191]: the value of the associated type `Color` (from the trait `Vehicle` LL | type Color; | ----------- `Color` defined here ... -LL | fn dent_object(c: BoxCar) { - | ^^^^^^^^^^^^^^^^^^^ associated type `Color` must be specified +LL | fn dent_object(c: dyn BoxCar) { + | ^^^^^^^^^^^^^^^^^^^^^^^ associated type `Color` must be specified error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-from-multiple-supertraits.rs:28:29 @@ -45,5 +45,5 @@ LL | fn paint(c: C, d: C::Color) { error: aborting due to 4 previous errors -Some errors occurred: E0191, E0221. +Some errors have detailed explanations: E0191, E0221. For more information about an error, try `rustc --explain E0191`. diff --git a/src/test/ui/associated-type/associated-type-projection-from-supertrait.stderr b/src/test/ui/associated-type/associated-type-projection-from-supertrait.stderr index 8c7b4a1333c1f..06f1a1cc64c42 100644 --- a/src/test/ui/associated-type/associated-type-projection-from-supertrait.stderr +++ b/src/test/ui/associated-type/associated-type-projection-from-supertrait.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/associated-type-projection-from-supertrait.rs:33:23 | -LL | fn b() { dent(ModelT, Blue); } //~ ERROR mismatched types +LL | fn b() { dent(ModelT, Blue); } | ^^^^ expected struct `Black`, found struct `Blue` | = note: expected type `Black` @@ -10,7 +10,7 @@ LL | fn b() { dent(ModelT, Blue); } //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/associated-type-projection-from-supertrait.rs:34:23 | -LL | fn c() { dent(ModelU, Black); } //~ ERROR mismatched types +LL | fn c() { dent(ModelU, Black); } | ^^^^^ expected struct `Blue`, found struct `Black` | = note: expected type `Blue` @@ -19,7 +19,7 @@ LL | fn c() { dent(ModelU, Black); } //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/associated-type-projection-from-supertrait.rs:40:28 | -LL | fn f() { ModelT.chip_paint(Blue); } //~ ERROR mismatched types +LL | fn f() { ModelT.chip_paint(Blue); } | ^^^^ expected struct `Black`, found struct `Blue` | = note: expected type `Black` @@ -28,7 +28,7 @@ LL | fn f() { ModelT.chip_paint(Blue); } //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/associated-type-projection-from-supertrait.rs:41:28 | -LL | fn g() { ModelU.chip_paint(Black); } //~ ERROR mismatched types +LL | fn g() { ModelU.chip_paint(Black); } | ^^^^^ expected struct `Blue`, found struct `Black` | = note: expected type `Blue` diff --git a/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr b/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr index 126fb572d992a..4b548604983df 100644 --- a/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr +++ b/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr @@ -1,7 +1,7 @@ error[E0271]: type mismatch resolving `::Color == Blue` --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:37:10 | -LL | fn b() { blue_car(ModelT); } //~ ERROR type mismatch +LL | fn b() { blue_car(ModelT); } | ^^^^^^^^ expected struct `Black`, found struct `Blue` | = note: expected type `Black` @@ -15,7 +15,7 @@ LL | fn blue_car>(c: C) { error[E0271]: type mismatch resolving `::Color == Black` --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:38:10 | -LL | fn c() { black_car(ModelU); } //~ ERROR type mismatch +LL | fn c() { black_car(ModelU); } | ^^^^^^^^^ expected struct `Blue`, found struct `Black` | = note: expected type `Blue` diff --git a/src/test/ui/associated-types/associated-types-bound-failure.stderr b/src/test/ui/associated-types/associated-types-bound-failure.stderr index 784a53f106a99..502fb4f1c3033 100644 --- a/src/test/ui/associated-types/associated-types-bound-failure.stderr +++ b/src/test/ui/associated-types/associated-types-bound-failure.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `::R: ToInt` is not satisfied --> $DIR/associated-types-bound-failure.rs:17:5 | -LL | ToInt::to_int(&g.get()) //~ ERROR E0277 +LL | ToInt::to_int(&g.get()) | ^^^^^^^^^^^^^ the trait `ToInt` is not implemented for `::R` | = help: consider adding a `where ::R: ToInt` bound diff --git a/src/test/ui/associated-types/associated-types-eq-1.stderr b/src/test/ui/associated-types/associated-types-eq-1.stderr index 0935d6ae3e611..aa987316801a7 100644 --- a/src/test/ui/associated-types/associated-types-eq-1.stderr +++ b/src/test/ui/associated-types/associated-types-eq-1.stderr @@ -1,7 +1,7 @@ error[E0412]: cannot find type `A` in this scope --> $DIR/associated-types-eq-1.rs:10:12 | -LL | let _: A = x.boo(); //~ ERROR cannot find type `A` in this scope +LL | let _: A = x.boo(); | ^ help: a type parameter with a similar name exists: `I` error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-eq-3.rs b/src/test/ui/associated-types/associated-types-eq-3.rs index 1a58dcca9e249..9366148b587d2 100644 --- a/src/test/ui/associated-types/associated-types-eq-3.rs +++ b/src/test/ui/associated-types/associated-types-eq-3.rs @@ -28,7 +28,7 @@ fn foo2(x: I) { } -pub fn baz(x: &Foo) { +pub fn baz(x: &dyn Foo) { let _: Bar = x.boo(); } diff --git a/src/test/ui/associated-types/associated-types-eq-3.stderr b/src/test/ui/associated-types/associated-types-eq-3.stderr index c1a8e2002be61..66fa4c288ca46 100644 --- a/src/test/ui/associated-types/associated-types-eq-3.stderr +++ b/src/test/ui/associated-types/associated-types-eq-3.stderr @@ -29,9 +29,9 @@ LL | baz(&a); | = note: expected type `usize` found type `Bar` - = note: required for the cast to the object type `dyn Foo` + = note: required for the cast to the object type `dyn Foo` error: aborting due to 3 previous errors -Some errors occurred: E0271, E0308. +Some errors have detailed explanations: E0271, E0308. For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr index 3721b69898876..353829c2f7631 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.stderr +++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr @@ -1,7 +1,7 @@ error[E0271]: type mismatch resolving `for<'x> >::A == &'x isize` --> $DIR/associated-types-eq-hr.rs:82:5 | -LL | foo::(); //~ ERROR type mismatch +LL | foo::(); | ^^^^^^^^^^^^^^^^^ expected usize, found isize | = note: expected type `&usize` @@ -19,7 +19,7 @@ LL | | } error[E0271]: type mismatch resolving `for<'x> >::A == &'x usize` --> $DIR/associated-types-eq-hr.rs:86:5 | -LL | bar::(); //~ ERROR type mismatch +LL | bar::(); | ^^^^^^^^^^^^^^^^ expected isize, found usize | = note: expected type `&isize` @@ -122,5 +122,5 @@ LL | | } error: aborting due to 7 previous errors -Some errors occurred: E0271, E0277. +Some errors have detailed explanations: E0271, E0277. For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/associated-types/associated-types-incomplete-object.rs b/src/test/ui/associated-types/associated-types-incomplete-object.rs index c93f3bec4d7d5..4993b13121549 100644 --- a/src/test/ui/associated-types/associated-types-incomplete-object.rs +++ b/src/test/ui/associated-types/associated-types-incomplete-object.rs @@ -18,14 +18,14 @@ impl Foo for isize { } pub fn main() { - let a = &42isize as &Foo; + let a = &42isize as &dyn Foo; - let b = &42isize as &Foo; + let b = &42isize as &dyn Foo; //~^ ERROR the value of the associated type `B` (from the trait `Foo`) must be specified - let c = &42isize as &Foo; + let c = &42isize as &dyn Foo; //~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified - let d = &42isize as &Foo; + let d = &42isize as &dyn Foo; //~^ ERROR the value of the associated types `A` (from the trait `Foo`), `B` (from the trait } diff --git a/src/test/ui/associated-types/associated-types-incomplete-object.stderr b/src/test/ui/associated-types/associated-types-incomplete-object.stderr index d152e028eb733..b4c08f4a4cce5 100644 --- a/src/test/ui/associated-types/associated-types-incomplete-object.stderr +++ b/src/test/ui/associated-types/associated-types-incomplete-object.stderr @@ -4,8 +4,8 @@ error[E0191]: the value of the associated type `B` (from the trait `Foo`) must b LL | type B; | ------- `B` defined here ... -LL | let b = &42isize as &Foo; - | ^^^^^^^^^^^^ associated type `B` must be specified +LL | let b = &42isize as &dyn Foo; + | ^^^^^^^^^^^^^^^^ associated type `B` must be specified error[E0191]: the value of the associated type `A` (from the trait `Foo`) must be specified --> $DIR/associated-types-incomplete-object.rs:26:26 @@ -13,8 +13,8 @@ error[E0191]: the value of the associated type `A` (from the trait `Foo`) must b LL | type A; | ------- `A` defined here ... -LL | let c = &42isize as &Foo; - | ^^^^^^^^^^^ associated type `A` must be specified +LL | let c = &42isize as &dyn Foo; + | ^^^^^^^^^^^^^^^ associated type `A` must be specified error[E0191]: the value of the associated types `A` (from the trait `Foo`), `B` (from the trait `Foo`) must be specified --> $DIR/associated-types-incomplete-object.rs:29:26 @@ -24,8 +24,8 @@ LL | type A; LL | type B; | ------- `B` defined here ... -LL | let d = &42isize as &Foo; - | ^^^ +LL | let d = &42isize as &dyn Foo; + | ^^^^^^^ | | | associated type `A` must be specified | associated type `B` must be specified diff --git a/src/test/ui/associated-types/associated-types-issue-17359.stderr b/src/test/ui/associated-types/associated-types-issue-17359.stderr index e05da8c4e4e8b..575a072c558bd 100644 --- a/src/test/ui/associated-types/associated-types-issue-17359.stderr +++ b/src/test/ui/associated-types/associated-types-issue-17359.stderr @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `Type` LL | type Type; | ---------- `Type` from trait ... -LL | impl Trait for isize {} //~ ERROR missing: `Type` +LL | impl Trait for isize {} | ^^^^^^^^^^^^^^^^^^^^ missing `Type` in implementation error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-issue-20346.stderr b/src/test/ui/associated-types/associated-types-issue-20346.stderr index 27b5b1e00f9ec..7d5b16c6e62d0 100644 --- a/src/test/ui/associated-types/associated-types-issue-20346.stderr +++ b/src/test/ui/associated-types/associated-types-issue-20346.stderr @@ -1,7 +1,7 @@ error[E0271]: type mismatch resolving ` as Iterator>::Item == std::option::Option` --> $DIR/associated-types-issue-20346.rs:34:5 | -LL | is_iterator_of::, _>(&adapter); //~ ERROR type mismatch +LL | is_iterator_of::, _>(&adapter); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found enum `std::option::Option` | = note: expected type `T` diff --git a/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr b/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr index ec8852d9f186e..2926bdae0525b 100644 --- a/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr +++ b/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr @@ -1,7 +1,7 @@ error[E0271]: type mismatch resolving `::Y == i32` --> $DIR/associated-types-multiple-types-one-trait.rs:13:5 | -LL | want_y(t); //~ ERROR type mismatch +LL | want_y(t); | ^^^^^^ expected associated type, found i32 | = note: expected type `::Y` @@ -15,7 +15,7 @@ LL | fn want_y>(t: &T) { } error[E0271]: type mismatch resolving `::X == u32` --> $DIR/associated-types-multiple-types-one-trait.rs:18:5 | -LL | want_x(t); //~ ERROR type mismatch +LL | want_x(t); | ^^^^^^ expected associated type, found u32 | = note: expected type `::X` diff --git a/src/test/ui/associated-types/associated-types-outlives.nll.stderr b/src/test/ui/associated-types/associated-types-outlives.nll.stderr deleted file mode 100644 index c58dc314e8a9d..0000000000000 --- a/src/test/ui/associated-types/associated-types-outlives.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/associated-types-outlives.rs:22:14 - | -LL | 's: loop { y = denormalise(&x); break } - | -- borrow of `x` occurs here -LL | drop(x); //~ ERROR cannot move out of `x` because it is borrowed - | ^ move out of `x` occurs here -LL | return f(y); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/associated-types/associated-types-outlives.stderr b/src/test/ui/associated-types/associated-types-outlives.stderr index 4cf3e473cf192..840e33b4b8a8e 100644 --- a/src/test/ui/associated-types/associated-types-outlives.stderr +++ b/src/test/ui/associated-types/associated-types-outlives.stderr @@ -2,9 +2,11 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/associated-types-outlives.rs:22:14 | LL | 's: loop { y = denormalise(&x); break } - | - borrow of `x` occurs here -LL | drop(x); //~ ERROR cannot move out of `x` because it is borrowed + | -- borrow of `x` occurs here +LL | drop(x); | ^ move out of `x` occurs here +LL | return f(y); + | - borrow later used here error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-overridden-binding-2.rs b/src/test/ui/associated-types/associated-types-overridden-binding-2.rs index 7467f33204725..109feb8e969a5 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding-2.rs +++ b/src/test/ui/associated-types/associated-types-overridden-binding-2.rs @@ -3,6 +3,6 @@ trait I32Iterator = Iterator; fn main() { - let _: &I32Iterator = &vec![42].into_iter(); + let _: &dyn I32Iterator = &vec![42].into_iter(); //~^ ERROR type mismatch } diff --git a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr index 8c0e5570d198d..aff067c289107 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr @@ -1,12 +1,12 @@ error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == i32` - --> $DIR/associated-types-overridden-binding-2.rs:6:39 + --> $DIR/associated-types-overridden-binding-2.rs:6:43 | -LL | let _: &I32Iterator = &vec![42].into_iter(); - | ^^^^^^^^^^^^^^^^^^^^^ expected u32, found i32 +LL | let _: &dyn I32Iterator = &vec![42].into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^ expected u32, found i32 | = note: expected type `u32` found type `i32` - = note: required for the cast to the object type `dyn I32Iterator` + = note: required for the cast to the object type `dyn std::iter::Iterator` error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.rs b/src/test/ui/associated-types/associated-types-overridden-binding.rs index ea3a61b2befae..fa1889389fd5c 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding.rs +++ b/src/test/ui/associated-types/associated-types-overridden-binding.rs @@ -7,5 +7,5 @@ trait I32Iterator = Iterator; trait U32Iterator = I32Iterator; fn main() { - let _: &I32Iterator; + let _: &dyn I32Iterator; } diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.stderr b/src/test/ui/associated-types/associated-types-overridden-binding.stderr index b54d2037f5d20..a26ee23894f6d 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding.stderr @@ -1,7 +1,7 @@ error[E0284]: type annotations required: cannot resolve `::Item == i32` --> $DIR/associated-types-overridden-binding.rs:4:1 | -LL | trait Bar: Foo {} //~ ERROR type annotations required +LL | trait Bar: Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by `Foo` diff --git a/src/test/ui/associated-types/associated-types-path-1.stderr b/src/test/ui/associated-types/associated-types-path-1.stderr index 5f5fb7a273bfd..a10cf7f890c15 100644 --- a/src/test/ui/associated-types/associated-types-path-1.stderr +++ b/src/test/ui/associated-types/associated-types-path-1.stderr @@ -1,7 +1,7 @@ error[E0220]: associated type `A` not found for `T` --> $DIR/associated-types-path-1.rs:10:23 | -LL | pub fn f1(a: T, x: T::A) {} //~ERROR associated type `A` not found +LL | pub fn f1(a: T, x: T::A) {} | ^^^^ associated type `A` not found error[E0221]: ambiguous associated type `A` in bounds of `T` @@ -13,10 +13,10 @@ LL | type A; LL | type A; | ------- ambiguous `A` from `Bar` ... -LL | pub fn f2(a: T, x: T::A) {} //~ERROR ambiguous associated type `A` +LL | pub fn f2(a: T, x: T::A) {} | ^^^^ ambiguous associated type `A` error: aborting due to 2 previous errors -Some errors occurred: E0220, E0221. +Some errors have detailed explanations: E0220, E0221. For more information about an error, try `rustc --explain E0220`. diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr index be7097a018255..1405cb1b4736c 100644 --- a/src/test/ui/associated-types/associated-types-path-2.stderr +++ b/src/test/ui/associated-types/associated-types-path-2.stderr @@ -3,6 +3,10 @@ error[E0308]: mismatched types | LL | f1(2i32, 4i32); | ^^^^ expected u32, found i32 +help: change the type of the numeric literal from `i32` to `u32` + | +LL | f1(2i32, 4u32); + | ^^^^ error[E0277]: the trait bound `u32: Foo` is not satisfied --> $DIR/associated-types-path-2.rs:29:5 @@ -45,8 +49,12 @@ error[E0308]: mismatched types | LL | let _: i32 = f2(2i32); | ^^^^^^^^ expected i32, found u32 +help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit + | +LL | let _: i32 = f2(2i32).try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.nll.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.nll.stderr new file mode 100644 index 0000000000000..ca99304f9b4a0 --- /dev/null +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/associated-types-project-from-hrtb-in-fn-body.rs:22:29 + | +LL | fn bar<'a, 'b, I : for<'x> Foo<&'x isize>>( + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let z: I::A = if cond { x } else { y }; + | ^ assignment requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/associated-types-project-from-hrtb-in-fn-body.rs:22:40 + | +LL | fn bar<'a, 'b, I : for<'x> Foo<&'x isize>>( + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let z: I::A = if cond { x } else { y }; + | ^ assignment requires that `'b` must outlive `'a` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.stderr index d5310c47fcf1e..63d662f44658a 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.stderr @@ -11,4 +11,3 @@ LL | let z: I::A = if cond { x } else { y }; error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr index e06ad648613d9..09f4f99703f9c 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr @@ -6,4 +6,3 @@ LL | x: I::A) error: aborting due to previous error -For more information about this error, try `rustc --explain E0212`. diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr index 4c9b7951393c5..189b19461f479 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr @@ -6,4 +6,3 @@ LL | field: I::A error: aborting due to previous error -For more information about this error, try `rustc --explain E0212`. diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr index 445e1b19023f5..e1c169028c5c4 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr @@ -6,4 +6,3 @@ LL | fn some_method(&self, arg: I::A); error: aborting due to previous error -For more information about this error, try `rustc --explain E0212`. diff --git a/src/test/ui/associated-types/associated-types-subtyping-1.nll.stderr b/src/test/ui/associated-types/associated-types-subtyping-1.nll.stderr new file mode 100644 index 0000000000000..d8506b9c8c81c --- /dev/null +++ b/src/test/ui/associated-types/associated-types-subtyping-1.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/associated-types-subtyping-1.rs:24:12 + | +LL | fn method2<'a,'b,T>(x: &'a T, y: &'b T) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let a: >::Type = make_any(); + | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + +error: lifetime may not live long enough + --> $DIR/associated-types-subtyping-1.rs:35:13 + | +LL | fn method3<'a,'b,T>(x: &'a T, y: &'b T) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _c: >::Type = b; + | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/associated-types/associated-types-subtyping-1.stderr b/src/test/ui/associated-types/associated-types-subtyping-1.stderr index 77914dbae795a..660e5b3928acf 100644 --- a/src/test/ui/associated-types/associated-types-subtyping-1.stderr +++ b/src/test/ui/associated-types/associated-types-subtyping-1.stderr @@ -4,7 +4,7 @@ error[E0623]: lifetime mismatch LL | fn method2<'a,'b,T>(x: &'a T, y: &'b T) | ----- ----- these two types are declared with different lifetimes... ... -LL | let _c: >::Type = a; //~ ERROR E0623 +LL | let _c: >::Type = a; | ^ ...but data from `y` flows into `x` here error[E0623]: lifetime mismatch @@ -13,9 +13,8 @@ error[E0623]: lifetime mismatch LL | fn method3<'a,'b,T>(x: &'a T, y: &'b T) | ----- ----- these two types are declared with different lifetimes... ... -LL | let _c: >::Type = b; //~ ERROR E0623 +LL | let _c: >::Type = b; | ^ ...but data from `y` flows into `x` here error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/associated-types/associated-types-unsized.stderr b/src/test/ui/associated-types/associated-types-unsized.stderr index c83b14374f712..b5db9743932e9 100644 --- a/src/test/ui/associated-types/associated-types-unsized.stderr +++ b/src/test/ui/associated-types/associated-types-unsized.stderr @@ -1,7 +1,7 @@ error[E0277]: the size for values of type `::Value` cannot be known at compilation time --> $DIR/associated-types-unsized.rs:7:9 | -LL | let x = t.get(); //~ ERROR the size for values of type +LL | let x = t.get(); | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `::Value` diff --git a/src/test/ui/associated-types/bound-lifetime-constrained.object.stderr b/src/test/ui/associated-types/bound-lifetime-constrained.object.stderr index 9258854245c84..36fa06cce4dd6 100644 --- a/src/test/ui/associated-types/bound-lifetime-constrained.object.stderr +++ b/src/test/ui/associated-types/bound-lifetime-constrained.object.stderr @@ -1,14 +1,14 @@ error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types - --> $DIR/bound-lifetime-constrained.rs:28:56 + --> $DIR/bound-lifetime-constrained.rs:28:60 | -LL | fn object1(_: Box Fn(<() as Foo<'a>>::Item) -> &'a i32>) { - | ^^^^^^^ +LL | fn object1(_: Box Fn(<() as Foo<'a>>::Item) -> &'a i32>) { + | ^^^^^^^ error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types - --> $DIR/bound-lifetime-constrained.rs:33:35 + --> $DIR/bound-lifetime-constrained.rs:33:39 | -LL | fn object2(_: Box Fn() -> <() as Foo<'a>>::Item>) { - | ^^^^^^^^^^^^^^^^^^^^^ +LL | fn object2(_: Box Fn() -> <() as Foo<'a>>::Item>) { + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/bound-lifetime-constrained.rs b/src/test/ui/associated-types/bound-lifetime-constrained.rs index b590f88b60dca..fb82b3fa66660 100644 --- a/src/test/ui/associated-types/bound-lifetime-constrained.rs +++ b/src/test/ui/associated-types/bound-lifetime-constrained.rs @@ -25,12 +25,12 @@ fn func2(_: for<'a> fn() -> <() as Foo<'a>>::Item) { } #[cfg(object)] -fn object1(_: Box Fn(<() as Foo<'a>>::Item) -> &'a i32>) { +fn object1(_: Box Fn(<() as Foo<'a>>::Item) -> &'a i32>) { //[object]~^ ERROR E0582 } #[cfg(object)] -fn object2(_: Box Fn() -> <() as Foo<'a>>::Item>) { +fn object2(_: Box Fn() -> <() as Foo<'a>>::Item>) { //[object]~^ ERROR E0582 } diff --git a/src/test/ui/associated-types/bound-lifetime-in-binding-only.angle.stderr b/src/test/ui/associated-types/bound-lifetime-in-binding-only.angle.stderr index fee64c0f663b7..54f4bb9076b28 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-binding-only.angle.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-binding-only.angle.stderr @@ -17,10 +17,10 @@ LL | fn angle2() where for<'a> T: Foo { | ^^^^^^^^^^^^ error[E0582]: binding for associated type `Item` references lifetime `'a`, which does not appear in the trait input types - --> $DIR/bound-lifetime-in-binding-only.rs:27:27 + --> $DIR/bound-lifetime-in-binding-only.rs:27:31 | -LL | fn angle3(_: &for<'a> Foo) { - | ^^^^^^^^^^^^ +LL | fn angle3(_: &dyn for<'a> Foo) { + | ^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr b/src/test/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr index 3a5ff9d795631..fcdb371a6e599 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr @@ -1,7 +1,7 @@ error: compilation successful --> $DIR/bound-lifetime-in-binding-only.rs:71:1 | -LL | fn main() { } //[ok]~ ERROR compilation successful +LL | fn main() { } | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/bound-lifetime-in-binding-only.paren.stderr b/src/test/ui/associated-types/bound-lifetime-in-binding-only.paren.stderr index 8c9480027e62a..74bc84c222aa7 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-binding-only.paren.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-binding-only.paren.stderr @@ -17,10 +17,10 @@ LL | fn paren2() where for<'a> T: Fn() -> &'a i32 { | ^^^^^^^ error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types - --> $DIR/bound-lifetime-in-binding-only.rs:47:31 + --> $DIR/bound-lifetime-in-binding-only.rs:47:35 | -LL | fn paren3(_: &for<'a> Fn() -> &'a i32) { - | ^^^^^^^ +LL | fn paren3(_: &dyn for<'a> Fn() -> &'a i32) { + | ^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/associated-types/bound-lifetime-in-binding-only.rs b/src/test/ui/associated-types/bound-lifetime-in-binding-only.rs index e1989d35bbb8c..843f5f0619588 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-binding-only.rs +++ b/src/test/ui/associated-types/bound-lifetime-in-binding-only.rs @@ -24,7 +24,7 @@ fn angle2() where for<'a> T: Foo { } #[cfg(angle)] -fn angle3(_: &for<'a> Foo) { +fn angle3(_: &dyn for<'a> Foo) { //[angle]~^ ERROR binding for associated type `Item` references lifetime `'a` } @@ -44,7 +44,7 @@ fn paren2() where for<'a> T: Fn() -> &'a i32 { } #[cfg(paren)] -fn paren3(_: &for<'a> Fn() -> &'a i32) { +fn paren3(_: &dyn for<'a> Fn() -> &'a i32) { //[paren]~^ ERROR binding for associated type `Output` references lifetime `'a` } diff --git a/src/test/ui/associated-types/bound-lifetime-in-return-only.ok.stderr b/src/test/ui/associated-types/bound-lifetime-in-return-only.ok.stderr index 650383b531cfa..504d68e66e23e 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-return-only.ok.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-return-only.ok.stderr @@ -1,7 +1,7 @@ error: compilation successful --> $DIR/bound-lifetime-in-return-only.rs:49:1 | -LL | fn main() { } //[ok]~ ERROR compilation successful +LL | fn main() { } | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/bound-lifetime-in-return-only.rs b/src/test/ui/associated-types/bound-lifetime-in-return-only.rs index 5a7e086fd476c..9c0dc61494d1f 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-return-only.rs +++ b/src/test/ui/associated-types/bound-lifetime-in-return-only.rs @@ -38,11 +38,11 @@ fn elision(_: fn() -> &i32) { struct Parameterized<'a> { x: &'a str } #[cfg(ok)] -fn ok1(_: &for<'a> Fn(&Parameterized<'a>) -> &'a i32) { +fn ok1(_: &dyn for<'a> Fn(&Parameterized<'a>) -> &'a i32) { } #[cfg(ok)] -fn ok2(_: &for<'a,'b> Fn<(&'b Parameterized<'a>,), Output=&'a i32>) { +fn ok2(_: &dyn for<'a,'b> Fn<(&'b Parameterized<'a>,), Output=&'a i32>) { } #[rustc_error] diff --git a/src/test/ui/associated-types/cache/chrono-scan.rs b/src/test/ui/associated-types/cache/chrono-scan.rs index 00d47c92a374c..8ddd347ff3607 100644 --- a/src/test/ui/associated-types/cache/chrono-scan.rs +++ b/src/test/ui/associated-types/cache/chrono-scan.rs @@ -1,10 +1,10 @@ -// compile-pass -// skip-codegen -#![allow(warnings)] +// check-pass + pub type ParseResult = Result; -pub enum Item<'a> { Literal(&'a str), - } +pub enum Item<'a> { + Literal(&'a str) +} pub fn colon_or_space(s: &str) -> ParseResult<&str> { unimplemented!() @@ -20,10 +20,9 @@ pub fn parse<'a, I>(mut s: &str, items: I) -> ParseResult<()> macro_rules! try_consume { ($e:expr) => ({ let (s_, v) = try!($e); s = s_; v }) } - let offset = try_consume!(timezone_offset_zulu(s.trim_left(), colon_or_space)); - let offset = try_consume!(timezone_offset_zulu(s.trim_left(), colon_or_space)); + let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space)); + let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space)); Ok(()) } - -fn main() { } +fn main() {} diff --git a/src/test/ui/associated-types/cache/elision.rs b/src/test/ui/associated-types/cache/elision.rs index 2b49cd33ba09b..b3e1ec8ad703c 100644 --- a/src/test/ui/associated-types/cache/elision.rs +++ b/src/test/ui/associated-types/cache/elision.rs @@ -1,10 +1,9 @@ -// compile-pass -// skip-codegen -#![allow(warnings)] // Check that you are allowed to implement using elision but write // trait without elision (a bug in this cropped up during // bootstrapping, so this is a regression test). +// check-pass + pub struct SplitWhitespace<'a> { x: &'a u8 } diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.krisskross.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.krisskross.nll.stderr new file mode 100644 index 0000000000000..779e6dac92e25 --- /dev/null +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.krisskross.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/project-fn-ret-contravariant.rs:45:4 + | +LL | fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | (a, b) + | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + +error: lifetime may not live long enough + --> $DIR/project-fn-ret-contravariant.rs:45:4 + | +LL | fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | (a, b) + | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.krisskross.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.krisskross.stderr index 0fed413f14418..dc9a549586bab 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.krisskross.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.krisskross.stderr @@ -6,7 +6,7 @@ LL | fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) { | | | this parameter and the return type are declared with different lifetimes... ... -LL | (a, b) //[krisskross]~ ERROR lifetime mismatch [E0623] +LL | (a, b) | ^ ...but data from `y` is returned here error[E0623]: lifetime mismatch @@ -17,9 +17,8 @@ LL | fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) { | | | this parameter and the return type are declared with different lifetimes... ... -LL | (a, b) //[krisskross]~ ERROR lifetime mismatch [E0623] +LL | (a, b) | ^ ...but data from `x` is returned here error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr new file mode 100644 index 0000000000000..f532c96ed2cc7 --- /dev/null +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/project-fn-ret-contravariant.rs:38:4 + | +LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | bar(foo, x) + | ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr index ab148365c9199..15bebce47dd6a 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr @@ -1,7 +1,7 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/project-fn-ret-contravariant.rs:38:8 | -LL | bar(foo, x) //[transmute]~ ERROR E0495 +LL | bar(foo, x) | ^^^ | note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 37:8... @@ -12,15 +12,14 @@ LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 { note: ...so that reference does not outlive borrowed content --> $DIR/project-fn-ret-contravariant.rs:38:13 | -LL | bar(foo, x) //[transmute]~ ERROR E0495 +LL | bar(foo, x) | ^ = note: but, the lifetime must be valid for the static lifetime... note: ...so that reference does not outlive borrowed content --> $DIR/project-fn-ret-contravariant.rs:38:4 | -LL | bar(foo, x) //[transmute]~ ERROR E0495 +LL | bar(foo, x) | ^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr new file mode 100644 index 0000000000000..c45082fb0538f --- /dev/null +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/project-fn-ret-invariant.rs:55:4 + | +LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | (a, b) + | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + +error: lifetime may not live long enough + --> $DIR/project-fn-ret-invariant.rs:55:4 + | +LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | (a, b) + | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr index fa831ea81dcfb..6accf8110ad1e 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr @@ -5,7 +5,7 @@ LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { | -------- -------------------- | | | this parameter and the return type are declared with different lifetimes... -LL | let a = bar(foo, y); //[krisskross]~ ERROR E0623 +LL | let a = bar(foo, y); | ^ ...but data from `x` is returned here error[E0623]: lifetime mismatch @@ -15,10 +15,9 @@ LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { | -------- -------------------- | | | this parameter and the return type are declared with different lifetimes... -LL | let a = bar(foo, y); //[krisskross]~ ERROR E0623 -LL | let b = bar(foo, x); //[krisskross]~ ERROR E0623 +LL | let a = bar(foo, y); +LL | let b = bar(foo, x); | ^ ...but data from `y` is returned here error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr new file mode 100644 index 0000000000000..2c11e7ffe930d --- /dev/null +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/project-fn-ret-invariant.rs:38:12 + | +LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let f = foo; // <-- No consistent type can be inferred for `f` here. +LL | let a = bar(f, x); + | ^^^^^^^^^ argument requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/project-fn-ret-invariant.rs:39:12 + | +LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let b = bar(f, y); + | ^^^^^^^^^ argument requires that `'b` must outlive `'a` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr index 6b78d66a2d484..ef036bd8fbaa8 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr @@ -6,9 +6,8 @@ LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { | | | this parameter and the return type are declared with different lifetimes... ... -LL | let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623] +LL | let b = bar(f, y); | ^ ...but data from `x` is returned here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr new file mode 100644 index 0000000000000..8be0ad6e88f3a --- /dev/null +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/project-fn-ret-invariant.rs:48:4 + | +LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> { + | -- lifetime `'a` defined here +... +LL | bar(foo, x) + | ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index dd1212eaac91d..62b4cb10911fb 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -1,7 +1,7 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/project-fn-ret-invariant.rs:48:8 | -LL | bar(foo, x) //[transmute]~ ERROR E0495 +LL | bar(foo, x) | ^^^ | note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 44:8... @@ -19,4 +19,3 @@ LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> { error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/associated-types/higher-ranked-projection.good.stderr b/src/test/ui/associated-types/higher-ranked-projection.good.stderr index 165e5213e0d34..16fef0510f871 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.good.stderr +++ b/src/test/ui/associated-types/higher-ranked-projection.good.stderr @@ -1,9 +1,9 @@ error: compilation successful --> $DIR/higher-ranked-projection.rs:24:1 | -LL | / fn main() { //[good]~ ERROR compilation successful +LL | / fn main() { LL | | foo(()); -LL | | //[bad]~^ ERROR type mismatch +LL | | LL | | } | |_^ diff --git a/src/test/ui/async-await/argument-patterns.rs b/src/test/ui/async-await/argument-patterns.rs new file mode 100644 index 0000000000000..3750c2bcb701a --- /dev/null +++ b/src/test/ui/async-await/argument-patterns.rs @@ -0,0 +1,30 @@ +// edition:2018 +// run-pass + +#![allow(unused_variables)] +#![deny(unused_mut)] +#![feature(async_await)] + +type A = Vec; + +async fn a(n: u32, mut vec: A) { + vec.push(n); +} + +async fn b(n: u32, ref mut vec: A) { + vec.push(n); +} + +async fn c(ref vec: A) { + vec.contains(&0); +} + +async fn d((a, mut b): (A, A)) { + b.push(1); +} + +async fn f((ref mut a, ref b): (A, A)) {} + +async fn g(((ref a, ref mut b), (ref mut c, ref d)): ((A, A), (A, A))) {} + +fn main() {} diff --git a/src/test/ui/async-await/async-await.rs b/src/test/ui/async-await/async-await.rs new file mode 100644 index 0000000000000..0eae1467fbfa0 --- /dev/null +++ b/src/test/ui/async-await/async-await.rs @@ -0,0 +1,210 @@ +// run-pass + +// edition:2018 +// aux-build:arc_wake.rs + +#![feature(async_await)] + +extern crate arc_wake; + +use std::pin::Pin; +use std::future::Future; +use std::sync::{ + Arc, + atomic::{self, AtomicUsize}, +}; +use std::task::{Context, Poll}; +use arc_wake::ArcWake; + +struct Counter { + wakes: AtomicUsize, +} + +impl ArcWake for Counter { + fn wake(self: Arc) { + Self::wake_by_ref(&self) + } + fn wake_by_ref(arc_self: &Arc) { + arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); + } +} + +struct WakeOnceThenComplete(bool); + +fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) } + +impl Future for WakeOnceThenComplete { + type Output = (); + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + if self.0 { + Poll::Ready(()) + } else { + cx.waker().wake_by_ref(); + self.0 = true; + Poll::Pending + } + } +} + +fn async_block(x: u8) -> impl Future { + async move { + wake_and_yield_once().await; + x + } +} + +fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future + 'a { + async move { + wake_and_yield_once().await; + *x + } +} + +fn async_nonmove_block(x: u8) -> impl Future { + async move { + let future = async { + wake_and_yield_once().await; + x + }; + future.await + } +} + +fn async_closure(x: u8) -> impl Future { + (async move |x: u8| -> u8 { + wake_and_yield_once().await; + x + })(x) +} + +async fn async_fn(x: u8) -> u8 { + wake_and_yield_once().await; + x +} + +async fn generic_async_fn(x: T) -> T { + wake_and_yield_once().await; + x +} + +async fn async_fn_with_borrow(x: &u8) -> u8 { + wake_and_yield_once().await; + *x +} + +async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 { + wake_and_yield_once().await; + *x +} + +fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future + 'a { + async move { + wake_and_yield_once().await; + *x + } +} + +/* FIXME(cramertj) support when `existential type T<'a, 'b>:;` works +async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 { + await!(wake_and_yield_once()); + *x +} +*/ + +async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 { + wake_and_yield_once().await; + *x +} + +fn async_fn_with_internal_borrow(y: u8) -> impl Future { + async move { + async_fn_with_borrow_named_lifetime(&y).await + } +} + +async unsafe fn unsafe_async_fn(x: u8) -> u8 { + wake_and_yield_once().await; + x +} + +struct Foo; + +trait Bar { + fn foo() {} +} + +impl Foo { + async fn async_assoc_item(x: u8) -> u8 { + unsafe { + unsafe_async_fn(x).await + } + } + + async unsafe fn async_unsafe_assoc_item(x: u8) -> u8 { + unsafe_async_fn(x).await + } +} + +fn test_future_yields_once_then_returns(f: F) +where + F: FnOnce(u8) -> Fut, + Fut: Future, +{ + let mut fut = Box::pin(f(9)); + let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); + let waker = ArcWake::into_waker(counter.clone()); + let mut cx = Context::from_waker(&waker); + assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx)); + assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx)); +} + +fn main() { + macro_rules! test { + ($($fn_name:expr,)*) => { $( + test_future_yields_once_then_returns($fn_name); + )* } + } + + macro_rules! test_with_borrow { + ($($fn_name:expr,)*) => { $( + test_future_yields_once_then_returns(|x| { + async move { + $fn_name(&x).await + } + }); + )* } + } + + test! { + async_block, + async_nonmove_block, + async_closure, + async_fn, + generic_async_fn, + async_fn_with_internal_borrow, + Foo::async_assoc_item, + |x| { + async move { + unsafe { unsafe_async_fn(x).await } + } + }, + |x| { + async move { + unsafe { Foo::async_unsafe_assoc_item(x).await } + } + }, + } + test_with_borrow! { + async_block_with_borrow_named_lifetime, + async_fn_with_borrow, + async_fn_with_borrow_named_lifetime, + async_fn_with_impl_future_named_lifetime, + |x| { + async move { + async_fn_multiple_args_named_lifetime(x, x).await + } + }, + } +} diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs new file mode 100644 index 0000000000000..612c1e29d82bd --- /dev/null +++ b/src/test/ui/async-await/async-fn-nonsend.rs @@ -0,0 +1,59 @@ +// compile-fail +// edition:2018 +// compile-flags: --crate-type lib + +#![feature(async_await)] + +use std::{ + cell::RefCell, + fmt::Debug, + rc::Rc, +}; + +fn non_sync() -> impl Debug { RefCell::new(()) } + +fn non_send() -> impl Debug { Rc::new(()) } + +fn take_ref(_: &T) {} + +async fn fut() {} + +async fn fut_arg(_: T) {} + +async fn local_dropped_before_await() { + // FIXME: it'd be nice for this to be allowed in a `Send` `async fn` + let x = non_send(); + drop(x); + fut().await; +} + +async fn non_send_temporary_in_match() { + // We could theoretically make this work as well (produce a `Send` future) + // for scrutinees / temporaries that can or will + // be dropped prior to the match body + // (e.g. `Copy` types). + match Some(non_send()) { + Some(_) => fut().await, + None => {} + } +} + +async fn non_sync_with_method_call() { + // FIXME: it'd be nice for this to work. + let f: &mut std::fmt::Formatter = panic!(); + if non_sync().fmt(f).unwrap() == () { + fut().await; + } +} + +fn assert_send(_: impl Send) {} + +pub fn pass_assert() { + assert_send(local_dropped_before_await()); + //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely + assert_send(non_send_temporary_in_match()); + //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely + assert_send(non_sync_with_method_call()); + //~^ ERROR `dyn std::fmt::Write` cannot be sent between threads safely + //~^^ ERROR `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely +} diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr new file mode 100644 index 0000000000000..7776a36a28f2b --- /dev/null +++ b/src/test/ui/async-await/async-fn-nonsend.stderr @@ -0,0 +1,87 @@ +error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:52:5 + | +LL | assert_send(local_dropped_before_await()); + | ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely + | + = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + = note: required because it appears within the type `impl std::fmt::Debug` + = note: required because it appears within the type `{impl std::fmt::Debug, impl std::future::Future, ()}` + = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:23:39: 28:2 {impl std::fmt::Debug, impl std::future::Future, ()}]` + = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:23:39: 28:2 {impl std::fmt::Debug, impl std::future::Future, ()}]>` + = note: required because it appears within the type `impl std::future::Future` + = note: required because it appears within the type `impl std::future::Future` +note: required by `assert_send` + --> $DIR/async-fn-nonsend.rs:49:1 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:54:5 + | +LL | assert_send(non_send_temporary_in_match()); + | ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely + | + = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + = note: required because it appears within the type `impl std::fmt::Debug` + = note: required because it appears within the type `{fn(impl std::fmt::Debug) -> std::option::Option {std::option::Option::::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option, impl std::future::Future, ()}` + = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:30:40: 39:2 {fn(impl std::fmt::Debug) -> std::option::Option {std::option::Option::::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option, impl std::future::Future, ()}]` + = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:30:40: 39:2 {fn(impl std::fmt::Debug) -> std::option::Option {std::option::Option::::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option, impl std::future::Future, ()}]>` + = note: required because it appears within the type `impl std::future::Future` + = note: required because it appears within the type `impl std::future::Future` +note: required by `assert_send` + --> $DIR/async-fn-nonsend.rs:49:1 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `dyn std::fmt::Write` cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:56:5 + | +LL | assert_send(non_sync_with_method_call()); + | ^^^^^^^^^^^ `dyn std::fmt::Write` cannot be sent between threads safely + | + = help: the trait `std::marker::Send` is not implemented for `dyn std::fmt::Write` + = note: required because of the requirements on the impl of `std::marker::Send` for `&mut dyn std::fmt::Write` + = note: required because it appears within the type `std::fmt::Formatter<'_>` + = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>` + = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}` + = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]` + = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>` + = note: required because it appears within the type `impl std::future::Future` + = note: required because it appears within the type `impl std::future::Future` +note: required by `assert_send` + --> $DIR/async-fn-nonsend.rs:49:1 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely + --> $DIR/async-fn-nonsend.rs:56:5 + | +LL | assert_send(non_sync_with_method_call()); + | ^^^^^^^^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely + | + = help: within `std::fmt::ArgumentV1<'_>`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)` + = note: required because it appears within the type `std::marker::PhantomData<*mut (dyn std::ops::Fn() + 'static)>` + = note: required because it appears within the type `core::fmt::Void` + = note: required because it appears within the type `&core::fmt::Void` + = note: required because it appears within the type `std::fmt::ArgumentV1<'_>` + = note: required because of the requirements on the impl of `std::marker::Send` for `std::slice::Iter<'_, std::fmt::ArgumentV1<'_>>` + = note: required because it appears within the type `std::fmt::Formatter<'_>` + = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>` + = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}` + = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]` + = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>` + = note: required because it appears within the type `impl std::future::Future` + = note: required because it appears within the type `impl std::future::Future` +note: required by `assert_send` + --> $DIR/async-fn-nonsend.rs:49:1 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/async-fn-path-elision.rs b/src/test/ui/async-await/async-fn-path-elision.rs new file mode 100644 index 0000000000000..8db7631ef4108 --- /dev/null +++ b/src/test/ui/async-await/async-fn-path-elision.rs @@ -0,0 +1,16 @@ +// edition:2018 + +#![feature(async_await, await_macro)] +#![allow(dead_code)] + +struct HasLifetime<'a>(&'a bool); + +async fn error(lt: HasLifetime) { //~ ERROR implicit elided lifetime not allowed here + if *lt.0 {} +} + +fn no_error(lt: HasLifetime) { + if *lt.0 {} +} + +fn main() {} diff --git a/src/test/ui/async-await/async-fn-path-elision.stderr b/src/test/ui/async-await/async-fn-path-elision.stderr new file mode 100644 index 0000000000000..3b311baba01de --- /dev/null +++ b/src/test/ui/async-await/async-fn-path-elision.stderr @@ -0,0 +1,8 @@ +error[E0726]: implicit elided lifetime not allowed here + --> $DIR/async-fn-path-elision.rs:8:20 + | +LL | async fn error(lt: HasLifetime) { + | ^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>` + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/async-fn-send-uses-nonsend.rs b/src/test/ui/async-await/async-fn-send-uses-nonsend.rs new file mode 100644 index 0000000000000..f07fc2fceb5b6 --- /dev/null +++ b/src/test/ui/async-await/async-fn-send-uses-nonsend.rs @@ -0,0 +1,59 @@ +// compile-pass +// edition:2018 +// compile-flags: --crate-type lib + +#![feature(async_await)] + +use std::{ + cell::RefCell, + fmt::Debug, + rc::Rc, +}; + +fn non_sync() -> impl Debug { RefCell::new(()) } + +fn non_send() -> impl Debug { Rc::new(()) } + +fn take_ref(_: &T) {} + +async fn fut() {} + +async fn fut_arg(_: T) {} + +async fn still_send() { + fut().await; + println!("{:?} {:?}", non_send(), non_sync()); + fut().await; + drop(non_send()); + drop(non_sync()); + fut().await; + fut_arg(non_sync()).await; + + // Note: all temporaries in `if let` and `match` scrutinee + // are dropped at the *end* of the blocks, so using `non_send()` + // in either of those positions with an await in the middle will + // cause a `!Send` future. It might be nice in the future to allow + // this for `Copy` types, since they can be "dropped" early without + // affecting the end user. + if let Some(_) = Some(non_sync()) { + fut().await; + } + match Some(non_sync()) { + Some(_) => fut().await, + None => fut().await, + } + + let _ = non_send(); + fut().await; + + { + let _x = non_send(); + } + fut().await; +} + +fn assert_send(_: impl Send) {} + +pub fn pass_assert() { + assert_send(still_send()); +} diff --git a/src/test/ui/async-matches-expr.rs b/src/test/ui/async-await/async-matches-expr.rs similarity index 100% rename from src/test/ui/async-matches-expr.rs rename to src/test/ui/async-await/async-matches-expr.rs diff --git a/src/test/ui/async-await/async-with-closure.rs b/src/test/ui/async-await/async-with-closure.rs new file mode 100644 index 0000000000000..e94a5f0853d72 --- /dev/null +++ b/src/test/ui/async-await/async-with-closure.rs @@ -0,0 +1,26 @@ +// compile-pass +// edition:2018 + +#![feature(async_await, await_macro)] + +trait MyClosure { + type Args; +} + +impl MyClosure for dyn FnMut() -> R +where R: 'static { + type Args = (); +} + +struct MyStream { + x: C::Args, +} + +async fn get_future(_stream: MyStream) {} + +async fn f() { + let messages: MyStream = unimplemented!(); + await!(get_future(messages)); +} + +fn main() {} diff --git a/src/test/ui/async-await/auxiliary/arc_wake.rs b/src/test/ui/async-await/auxiliary/arc_wake.rs new file mode 100644 index 0000000000000..c21886f26f467 --- /dev/null +++ b/src/test/ui/async-await/auxiliary/arc_wake.rs @@ -0,0 +1,64 @@ +// edition:2018 + +use std::sync::Arc; +use std::task::{ + Waker, RawWaker, RawWakerVTable, +}; + +macro_rules! waker_vtable { + ($ty:ident) => { + &RawWakerVTable::new( + clone_arc_raw::<$ty>, + wake_arc_raw::<$ty>, + wake_by_ref_arc_raw::<$ty>, + drop_arc_raw::<$ty>, + ) + }; +} + +pub trait ArcWake { + fn wake(self: Arc); + + fn wake_by_ref(arc_self: &Arc) { + arc_self.clone().wake() + } + + fn into_waker(wake: Arc) -> Waker where Self: Sized + { + let ptr = Arc::into_raw(wake) as *const (); + + unsafe { + Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self))) + } + } +} + +unsafe fn increase_refcount(data: *const ()) { + // Retain Arc by creating a copy + let arc: Arc = Arc::from_raw(data as *const T); + let arc_clone = arc.clone(); + // Forget the Arcs again, so that the refcount isn't decrased + let _ = Arc::into_raw(arc); + let _ = Arc::into_raw(arc_clone); +} + +unsafe fn clone_arc_raw(data: *const ()) -> RawWaker { + increase_refcount::(data); + RawWaker::new(data, waker_vtable!(T)) +} + +unsafe fn drop_arc_raw(data: *const ()) { + // Drop Arc + let _: Arc = Arc::from_raw(data as *const T); +} + +unsafe fn wake_arc_raw(data: *const ()) { + let arc: Arc = Arc::from_raw(data as *const T); + ArcWake::wake(arc); +} + +unsafe fn wake_by_ref_arc_raw(data: *const ()) { + let arc: Arc = Arc::from_raw(data as *const T); + ArcWake::wake_by_ref(&arc); + let _ = Arc::into_raw(arc); +} diff --git a/src/test/ui/async-await/await-keyword/2015-edition-error-in-non-macro-position.rs b/src/test/ui/async-await/await-keyword/2015-edition-error-in-non-macro-position.rs new file mode 100644 index 0000000000000..c4f3f3edc486e --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2015-edition-error-in-non-macro-position.rs @@ -0,0 +1,36 @@ +#![feature(async_await, await_macro)] +#![allow(non_camel_case_types)] +#![deny(keyword_idents)] + +mod outer_mod { + pub mod await { //~ ERROR `await` is a keyword in the 2018 edition + //~^ WARN this was previously accepted by the compiler + pub struct await; //~ ERROR `await` is a keyword in the 2018 edition + //~^ WARN this was previously accepted by the compiler + } +} +use outer_mod::await::await; //~ ERROR `await` is a keyword in the 2018 edition +//~^ ERROR `await` is a keyword in the 2018 edition +//~^^ WARN this was previously accepted by the compiler +//~^^^ WARN this was previously accepted by the compiler + +struct Foo { await: () } +//~^ ERROR `await` is a keyword in the 2018 edition +//~^^ WARN this was previously accepted by the compiler + +impl Foo { fn await() {} } +//~^ ERROR `await` is a keyword in the 2018 edition +//~^^ WARN this was previously accepted by the compiler + +macro_rules! await { +//~^ ERROR `await` is a keyword in the 2018 edition +//~^^ WARN this was previously accepted by the compiler + () => {} +} + +fn main() { + match await { await => {} } //~ ERROR `await` is a keyword in the 2018 edition + //~^ ERROR `await` is a keyword in the 2018 edition + //~^^ WARN this was previously accepted by the compiler + //~^^^ WARN this was previously accepted by the compiler +} diff --git a/src/test/ui/async-await/await-keyword/2015-edition-error-in-non-macro-position.stderr b/src/test/ui/async-await/await-keyword/2015-edition-error-in-non-macro-position.stderr new file mode 100644 index 0000000000000..067ecd6a5138d --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2015-edition-error-in-non-macro-position.stderr @@ -0,0 +1,88 @@ +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:6:13 + | +LL | pub mod await { + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | +note: lint level defined here + --> $DIR/2015-edition-error-in-non-macro-position.rs:3:9 + | +LL | #![deny(keyword_idents)] + | ^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:8:20 + | +LL | pub struct await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:12:16 + | +LL | use outer_mod::await::await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:12:23 + | +LL | use outer_mod::await::await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:17:14 + | +LL | struct Foo { await: () } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:21:15 + | +LL | impl Foo { fn await() {} } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:25:14 + | +LL | macro_rules! await { + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:32:11 + | +LL | match await { await => {} } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:32:19 + | +LL | match await { await => {} } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/await-keyword/2015-edition-warning.fixed b/src/test/ui/async-await/await-keyword/2015-edition-warning.fixed similarity index 100% rename from src/test/ui/await-keyword/2015-edition-warning.fixed rename to src/test/ui/async-await/await-keyword/2015-edition-warning.fixed diff --git a/src/test/ui/await-keyword/2015-edition-warning.rs b/src/test/ui/async-await/await-keyword/2015-edition-warning.rs similarity index 100% rename from src/test/ui/await-keyword/2015-edition-warning.rs rename to src/test/ui/async-await/await-keyword/2015-edition-warning.rs diff --git a/src/test/ui/await-keyword/2015-edition-warning.stderr b/src/test/ui/async-await/await-keyword/2015-edition-warning.stderr similarity index 100% rename from src/test/ui/await-keyword/2015-edition-warning.stderr rename to src/test/ui/async-await/await-keyword/2015-edition-warning.stderr diff --git a/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.rs b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.rs new file mode 100644 index 0000000000000..f59f1160e703e --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.rs @@ -0,0 +1,25 @@ +// edition:2018 + +#![allow(non_camel_case_types)] +#![feature(async_await, await_macro)] + +mod outer_mod { + pub mod await { //~ ERROR expected identifier, found reserved keyword `await` + pub struct await; //~ ERROR expected identifier, found reserved keyword `await` + } +} +use self::outer_mod::await::await; //~ ERROR expected identifier, found reserved keyword `await` +//~^ ERROR expected identifier, found reserved keyword `await` + +struct Foo { await: () } +//~^ ERROR expected identifier, found reserved keyword `await` + +impl Foo { fn await() {} } +//~^ ERROR expected identifier, found reserved keyword `await` + +macro_rules! await { +//~^ ERROR expected identifier, found reserved keyword `await` + () => {} +} + +fn main() {} diff --git a/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr new file mode 100644 index 0000000000000..c4b82b29f0270 --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr @@ -0,0 +1,72 @@ +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:7:13 + | +LL | pub mod await { + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | pub mod r#await { + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:8:20 + | +LL | pub struct await; + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | pub struct r#await; + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:11:22 + | +LL | use self::outer_mod::await::await; + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | use self::outer_mod::r#await::await; + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:11:29 + | +LL | use self::outer_mod::await::await; + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | use self::outer_mod::await::r#await; + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:14:14 + | +LL | struct Foo { await: () } + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | struct Foo { r#await: () } + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:17:15 + | +LL | impl Foo { fn await() {} } + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | impl Foo { fn r#await() {} } + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:20:14 + | +LL | macro_rules! await { + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | macro_rules! r#await { + | ^^^^^^^ + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/async-await/await-keyword/2018-edition-error.rs b/src/test/ui/async-await/await-keyword/2018-edition-error.rs new file mode 100644 index 0000000000000..d856869684266 --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2018-edition-error.rs @@ -0,0 +1,12 @@ +// edition:2018 +#![allow(non_camel_case_types)] + +mod outer_mod { + pub mod await { //~ ERROR expected identifier + pub struct await; //~ ERROR expected identifier + } +} +use self::outer_mod::await::await; //~ ERROR expected identifier + //~^ ERROR expected identifier, found reserved keyword `await` + +fn main() {} diff --git a/src/test/ui/async-await/await-keyword/2018-edition-error.stderr b/src/test/ui/async-await/await-keyword/2018-edition-error.stderr new file mode 100644 index 0000000000000..8afe5c1a36b36 --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2018-edition-error.stderr @@ -0,0 +1,42 @@ +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error.rs:5:13 + | +LL | pub mod await { + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | pub mod r#await { + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error.rs:6:20 + | +LL | pub struct await; + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | pub struct r#await; + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error.rs:9:22 + | +LL | use self::outer_mod::await::await; + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | use self::outer_mod::r#await::await; + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error.rs:9:29 + | +LL | use self::outer_mod::await::await; + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | use self::outer_mod::await::r#await; + | ^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs new file mode 100644 index 0000000000000..e1e5bdd3d1b92 --- /dev/null +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs @@ -0,0 +1,111 @@ +// edition:2018 + +#![feature(async_await)] + +async fn bar() -> Result<(), ()> { + Ok(()) +} + +async fn foo1() -> Result<(), ()> { + let _ = await bar(); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo2() -> Result<(), ()> { + let _ = await? bar(); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo3() -> Result<(), ()> { + let _ = await bar()?; //~ ERROR incorrect use of `await` + //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + Ok(()) +} +async fn foo21() -> Result<(), ()> { + let _ = await { bar() }; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo22() -> Result<(), ()> { + let _ = await(bar()); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo23() -> Result<(), ()> { + let _ = await { bar() }?; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo4() -> Result<(), ()> { + let _ = (await bar())?; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo5() -> Result<(), ()> { + let _ = bar().await(); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo6() -> Result<(), ()> { + let _ = bar().await()?; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo7() -> Result<(), ()> { + let _ = bar().await; // OK + Ok(()) +} +async fn foo8() -> Result<(), ()> { + let _ = bar().await?; // OK + Ok(()) +} +fn foo9() -> Result<(), ()> { + let _ = await bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo10() -> Result<(), ()> { + let _ = await? bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo11() -> Result<(), ()> { + let _ = await bar()?; //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo12() -> Result<(), ()> { + let _ = (await bar())?; //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo13() -> Result<(), ()> { + let _ = bar().await(); //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo14() -> Result<(), ()> { + let _ = bar().await()?; //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo15() -> Result<(), ()> { + let _ = bar().await; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) +} +fn foo16() -> Result<(), ()> { + let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) +} +fn foo24() -> Result<(), ()> { + fn foo() -> Result<(), ()> { + let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) + } + foo() +} +fn foo25() -> Result<(), ()> { + let foo = || { + let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) + }; + foo() +} + +fn main() { + match await { await => () } + //~^ ERROR expected expression, found `=>` + //~| ERROR incorrect use of `await` +} //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `}` diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr new file mode 100644 index 0000000000000..380da4448ad32 --- /dev/null +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -0,0 +1,207 @@ +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:10:13 + | +LL | let _ = await bar(); + | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:14:13 + | +LL | let _ = await? bar(); + | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:18:13 + | +LL | let _ = await bar()?; + | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:23:13 + | +LL | let _ = await { bar() }; + | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:27:13 + | +LL | let _ = await(bar()); + | ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:31:13 + | +LL | let _ = await { bar() }?; + | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:35:14 + | +LL | let _ = (await bar())?; + | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:39:24 + | +LL | let _ = bar().await(); + | ^^ help: `await` is not a method call, remove the parentheses + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:43:24 + | +LL | let _ = bar().await()?; + | ^^ help: `await` is not a method call, remove the parentheses + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:55:13 + | +LL | let _ = await bar(); + | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:60:13 + | +LL | let _ = await? bar(); + | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:65:13 + | +LL | let _ = await bar()?; + | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:70:14 + | +LL | let _ = (await bar())?; + | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:75:24 + | +LL | let _ = bar().await(); + | ^^ help: `await` is not a method call, remove the parentheses + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:80:24 + | +LL | let _ = bar().await()?; + | ^^ help: `await` is not a method call, remove the parentheses + +error: expected expression, found `=>` + --> $DIR/incorrect-syntax-suggestions.rs:108:25 + | +LL | match await { await => () } + | ----- ^^ expected expression + | | + | while parsing this incorrect await expression + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:108:11 + | +LL | match await { await => () } + | ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await` + +error: expected one of `.`, `?`, `{`, or an operator, found `}` + --> $DIR/incorrect-syntax-suggestions.rs:111:1 + | +LL | match await { await => () } + | ----- - expected one of `.`, `?`, `{`, or an operator here + | | + | while parsing this match expression +... +LL | } + | ^ unexpected token + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:55:13 + | +LL | fn foo9() -> Result<(), ()> { + | ---- this is not `async` +LL | let _ = await bar(); + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:60:13 + | +LL | fn foo10() -> Result<(), ()> { + | ----- this is not `async` +LL | let _ = await? bar(); + | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:65:13 + | +LL | fn foo11() -> Result<(), ()> { + | ----- this is not `async` +LL | let _ = await bar()?; + | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:70:14 + | +LL | fn foo12() -> Result<(), ()> { + | ----- this is not `async` +LL | let _ = (await bar())?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:75:13 + | +LL | fn foo13() -> Result<(), ()> { + | ----- this is not `async` +LL | let _ = bar().await(); + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:80:13 + | +LL | fn foo14() -> Result<(), ()> { + | ----- this is not `async` +LL | let _ = bar().await()?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:85:13 + | +LL | fn foo15() -> Result<(), ()> { + | ----- this is not `async` +LL | let _ = bar().await; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:89:13 + | +LL | fn foo16() -> Result<(), ()> { + | ----- this is not `async` +LL | let _ = bar().await?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:94:17 + | +LL | fn foo() -> Result<(), ()> { + | --- this is not `async` +LL | let _ = bar().await?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:101:17 + | +LL | let foo = || { + | -- this is not `async` +LL | let _ = bar().await?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/incorrect-syntax-suggestions.rs:18:19 + | +LL | let _ = await bar()?; + | ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future` + | + = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` + = note: required by `std::ops::Try::into_result` + +error: aborting due to 29 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/await-keyword/post_expansion_error.rs b/src/test/ui/async-await/await-keyword/post_expansion_error.rs new file mode 100644 index 0000000000000..b4c899b0d0295 --- /dev/null +++ b/src/test/ui/async-await/await-keyword/post_expansion_error.rs @@ -0,0 +1,10 @@ +// edition:2018 + +macro_rules! r#await { + () => { println!("Hello, world!") } +} + +fn main() { + await!() + //~^ ERROR expected expression, found `)` +} diff --git a/src/test/ui/async-await/await-keyword/post_expansion_error.stderr b/src/test/ui/async-await/await-keyword/post_expansion_error.stderr new file mode 100644 index 0000000000000..4e525974c2c6f --- /dev/null +++ b/src/test/ui/async-await/await-keyword/post_expansion_error.stderr @@ -0,0 +1,10 @@ +error: expected expression, found `)` + --> $DIR/post_expansion_error.rs:8:12 + | +LL | await!() + | ----- ^ expected expression + | | + | while parsing this await macro call + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/await-macro.rs b/src/test/ui/async-await/await-macro.rs new file mode 100644 index 0000000000000..7d8b7a257dad9 --- /dev/null +++ b/src/test/ui/async-await/await-macro.rs @@ -0,0 +1,201 @@ +// run-pass + +// edition:2018 +// aux-build:arc_wake.rs + +#![feature(async_await, await_macro)] + +extern crate arc_wake; + +use std::pin::Pin; +use std::future::Future; +use std::sync::{ + Arc, + atomic::{self, AtomicUsize}, +}; +use std::task::{Context, Poll}; +use arc_wake::ArcWake; + +struct Counter { + wakes: AtomicUsize, +} + +impl ArcWake for Counter { + fn wake(self: Arc) { + Self::wake_by_ref(&self) + } + fn wake_by_ref(arc_self: &Arc) { + arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); + } +} + +struct WakeOnceThenComplete(bool); + +fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) } + +impl Future for WakeOnceThenComplete { + type Output = (); + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + if self.0 { + Poll::Ready(()) + } else { + cx.waker().wake_by_ref(); + self.0 = true; + Poll::Pending + } + } +} + +fn async_block(x: u8) -> impl Future { + async move { + await!(wake_and_yield_once()); + x + } +} + +fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future + 'a { + async move { + await!(wake_and_yield_once()); + *x + } +} + +fn async_nonmove_block(x: u8) -> impl Future { + async move { + let future = async { + await!(wake_and_yield_once()); + x + }; + await!(future) + } +} + +fn async_closure(x: u8) -> impl Future { + (async move |x: u8| -> u8 { + await!(wake_and_yield_once()); + x + })(x) +} + +async fn async_fn(x: u8) -> u8 { + await!(wake_and_yield_once()); + x +} + +async fn generic_async_fn(x: T) -> T { + await!(wake_and_yield_once()); + x +} + +async fn async_fn_with_borrow(x: &u8) -> u8 { + await!(wake_and_yield_once()); + *x +} + +async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 { + await!(wake_and_yield_once()); + *x +} + +fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future + 'a { + async move { + await!(wake_and_yield_once()); + *x + } +} + +/* FIXME(cramertj) support when `existential type T<'a, 'b>:;` works +async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 { + await!(wake_and_yield_once()); + *x +} +*/ + +async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 { + await!(wake_and_yield_once()); + *x +} + +fn async_fn_with_internal_borrow(y: u8) -> impl Future { + async move { + await!(async_fn_with_borrow_named_lifetime(&y)) + } +} + +async unsafe fn unsafe_async_fn(x: u8) -> u8 { + await!(wake_and_yield_once()); + x +} + +struct Foo; + +trait Bar { + fn foo() {} +} + +impl Foo { + async fn async_method(x: u8) -> u8 { + unsafe { + await!(unsafe_async_fn(x)) + } + } +} + +fn test_future_yields_once_then_returns(f: F) +where + F: FnOnce(u8) -> Fut, + Fut: Future, +{ + let mut fut = Box::pin(f(9)); + let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); + let waker = ArcWake::into_waker(counter.clone()); + let mut cx = Context::from_waker(&waker); + assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx)); + assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx)); +} + +fn main() { + macro_rules! test { + ($($fn_name:expr,)*) => { $( + test_future_yields_once_then_returns($fn_name); + )* } + } + + macro_rules! test_with_borrow { + ($($fn_name:expr,)*) => { $( + test_future_yields_once_then_returns(|x| { + async move { + await!($fn_name(&x)) + } + }); + )* } + } + + test! { + async_block, + async_nonmove_block, + async_closure, + async_fn, + generic_async_fn, + async_fn_with_internal_borrow, + Foo::async_method, + |x| { + async move { + unsafe { await!(unsafe_async_fn(x)) } + } + }, + } + test_with_borrow! { + async_block_with_borrow_named_lifetime, + async_fn_with_borrow, + async_fn_with_borrow_named_lifetime, + async_fn_with_impl_future_named_lifetime, + |x| { + async move { + await!(async_fn_multiple_args_named_lifetime(x, x)) + } + }, + } +} diff --git a/src/test/ui/async-await/dont-print-desugared-async.rs b/src/test/ui/async-await/dont-print-desugared-async.rs new file mode 100644 index 0000000000000..8150a260866b9 --- /dev/null +++ b/src/test/ui/async-await/dont-print-desugared-async.rs @@ -0,0 +1,9 @@ +// Test that we don't show variables with from async fn desugaring + +// edition:2018 +#![feature(async_await)] + +async fn async_fn(&ref mut s: &[i32]) {} +//~^ ERROR cannot borrow data in a `&` reference as mutable [E0596] + +fn main() {} diff --git a/src/test/ui/async-await/dont-print-desugared-async.stderr b/src/test/ui/async-await/dont-print-desugared-async.stderr new file mode 100644 index 0000000000000..47726ba65df98 --- /dev/null +++ b/src/test/ui/async-await/dont-print-desugared-async.stderr @@ -0,0 +1,12 @@ +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/dont-print-desugared-async.rs:6:20 + | +LL | async fn async_fn(&ref mut s: &[i32]) {} + | -^^^^^^^^^ + | || + | |cannot borrow as mutable through `&` reference + | help: consider changing this to be a mutable reference: `&mut ref mut s` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/async-await/dont-suggest-missing-await.rs b/src/test/ui/async-await/dont-suggest-missing-await.rs new file mode 100644 index 0000000000000..d551ef57985a1 --- /dev/null +++ b/src/test/ui/async-await/dont-suggest-missing-await.rs @@ -0,0 +1,21 @@ +// edition:2018 + +// This test ensures we don't make the suggestion in bodies that aren't `async`. + +#![feature(async_await)] + +fn take_u32(x: u32) {} + +async fn make_u32() -> u32 { + 22 +} + +async fn dont_suggest_await_in_closure() { + || { + let x = make_u32(); + take_u32(x) + //~^ ERROR mismatched types [E0308] + }; +} + +fn main() {} diff --git a/src/test/ui/async-await/dont-suggest-missing-await.stderr b/src/test/ui/async-await/dont-suggest-missing-await.stderr new file mode 100644 index 0000000000000..c60b0d1f30e80 --- /dev/null +++ b/src/test/ui/async-await/dont-suggest-missing-await.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/dont-suggest-missing-await.rs:16:18 + | +LL | take_u32(x) + | ^ expected u32, found opaque type + | + = note: expected type `u32` + found type `impl std::future::Future` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/async-await/drop-order/auxiliary/arc_wake.rs b/src/test/ui/async-await/drop-order/auxiliary/arc_wake.rs new file mode 100644 index 0000000000000..c21886f26f467 --- /dev/null +++ b/src/test/ui/async-await/drop-order/auxiliary/arc_wake.rs @@ -0,0 +1,64 @@ +// edition:2018 + +use std::sync::Arc; +use std::task::{ + Waker, RawWaker, RawWakerVTable, +}; + +macro_rules! waker_vtable { + ($ty:ident) => { + &RawWakerVTable::new( + clone_arc_raw::<$ty>, + wake_arc_raw::<$ty>, + wake_by_ref_arc_raw::<$ty>, + drop_arc_raw::<$ty>, + ) + }; +} + +pub trait ArcWake { + fn wake(self: Arc); + + fn wake_by_ref(arc_self: &Arc) { + arc_self.clone().wake() + } + + fn into_waker(wake: Arc) -> Waker where Self: Sized + { + let ptr = Arc::into_raw(wake) as *const (); + + unsafe { + Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self))) + } + } +} + +unsafe fn increase_refcount(data: *const ()) { + // Retain Arc by creating a copy + let arc: Arc = Arc::from_raw(data as *const T); + let arc_clone = arc.clone(); + // Forget the Arcs again, so that the refcount isn't decrased + let _ = Arc::into_raw(arc); + let _ = Arc::into_raw(arc_clone); +} + +unsafe fn clone_arc_raw(data: *const ()) -> RawWaker { + increase_refcount::(data); + RawWaker::new(data, waker_vtable!(T)) +} + +unsafe fn drop_arc_raw(data: *const ()) { + // Drop Arc + let _: Arc = Arc::from_raw(data as *const T); +} + +unsafe fn wake_arc_raw(data: *const ()) { + let arc: Arc = Arc::from_raw(data as *const T); + ArcWake::wake(arc); +} + +unsafe fn wake_by_ref_arc_raw(data: *const ()) { + let arc: Arc = Arc::from_raw(data as *const T); + ArcWake::wake_by_ref(&arc); + let _ = Arc::into_raw(arc); +} diff --git a/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs b/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs new file mode 100644 index 0000000000000..c2b59eecb9993 --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs @@ -0,0 +1,271 @@ +// aux-build:arc_wake.rs +// edition:2018 +// run-pass + +#![allow(unused_variables)] +#![feature(async_await, await_macro)] + +// Test that the drop order for parameters in a fn and async fn matches up. Also test that +// parameters (used or unused) are not dropped until the async fn completes execution. +// See also #54716. + +extern crate arc_wake; + +use arc_wake::ArcWake; +use std::cell::RefCell; +use std::future::Future; +use std::marker::PhantomData; +use std::sync::Arc; +use std::rc::Rc; +use std::task::Context; + +struct EmptyWaker; + +impl ArcWake for EmptyWaker { + fn wake(self: Arc) {} +} + +#[derive(Debug, Eq, PartialEq)] +enum DropOrder { + Function, + Val(&'static str), +} + +type DropOrderListPtr = Rc>>; + +struct D(&'static str, DropOrderListPtr); + +impl Drop for D { + fn drop(&mut self) { + self.1.borrow_mut().push(DropOrder::Val(self.0)); + } +} + +/// Check that unused bindings are dropped after the function is polled. +async fn foo_async(ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foo_sync(ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns are dropped after the function is polled. +async fn bar_async(ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn bar_sync(ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns within more complex patterns are dropped after the function +/// is polled. +async fn baz_async((ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn baz_sync((ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore and unused bindings within and outwith more complex patterns are dropped +/// after the function is polled. +async fn foobar_async(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foobar_sync(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +struct Foo; + +impl Foo { + /// Check that unused bindings are dropped after the method is polled. + async fn foo_async(ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method is polled. + async fn bar_async(ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// is polled. + async fn baz_async((ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync((ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method is polled. + async fn foobar_async( + ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D, + ) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync( + ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D, + ) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +struct Bar<'a>(PhantomData<&'a ()>); + +impl<'a> Bar<'a> { + /// Check that unused bindings are dropped after the method with self is polled. + async fn foo_async(&'a self, ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(&'a self, ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method with self is polled. + async fn bar_async(&'a self, ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(&'a self, ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// with self is polled. + async fn baz_async(&'a self, (ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync(&'a self, (ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method with self is polled. + async fn foobar_async( + &'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D, + ) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync( + &'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D, + ) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +fn assert_drop_order_after_poll>( + f: impl FnOnce(DropOrderListPtr) -> Fut, + g: impl FnOnce(DropOrderListPtr), +) { + let empty = Arc::new(EmptyWaker); + let waker = ArcWake::into_waker(empty); + let mut cx = Context::from_waker(&waker); + + let actual_order = Rc::new(RefCell::new(Vec::new())); + let mut fut = Box::pin(f(actual_order.clone())); + let _ = fut.as_mut().poll(&mut cx); + + let expected_order = Rc::new(RefCell::new(Vec::new())); + g(expected_order.clone()); + + assert_eq!(*actual_order.borrow(), *expected_order.borrow()); +} + +fn main() { + // Free functions (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())), + |l| bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods w/out self (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())), + |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + Foo::foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + Foo::foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods (see doc comment on function for what it tests). + let b = Bar(Default::default()); + assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())), + |l| b.bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| b.baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + b.foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + b.foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); +} diff --git a/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs b/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs new file mode 100644 index 0000000000000..708c570498460 --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs @@ -0,0 +1,263 @@ +// aux-build:arc_wake.rs +// edition:2018 +// run-pass + +#![allow(unused_variables)] +#![feature(async_await, await_macro)] + +// Test that the drop order for parameters in a fn and async fn matches up. Also test that +// parameters (used or unused) are not dropped until the async fn completes execution. +// See also #54716. + +extern crate arc_wake; + +use arc_wake::ArcWake; +use std::cell::RefCell; +use std::future::Future; +use std::marker::PhantomData; +use std::sync::Arc; +use std::rc::Rc; +use std::task::Context; + +struct EmptyWaker; + +impl ArcWake for EmptyWaker { + fn wake(self: Arc) {} +} + +#[derive(Debug, Eq, PartialEq)] +enum DropOrder { + Function, + Val(&'static str), +} + +type DropOrderListPtr = Rc>>; + +struct D(&'static str, DropOrderListPtr); + +impl Drop for D { + fn drop(&mut self) { + self.1.borrow_mut().push(DropOrder::Val(self.0)); + } +} + +/// Check that unused bindings are dropped after the function is polled. +async fn foo_async(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foo_sync(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns are dropped after the function is polled. +async fn bar_async(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn bar_sync(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns within more complex patterns are dropped after the function +/// is polled. +async fn baz_async((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn baz_sync((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore and unused bindings within and outwith more complex patterns are dropped +/// after the function is polled. +async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +struct Foo; + +impl Foo { + /// Check that unused bindings are dropped after the method is polled. + async fn foo_async(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method is polled. + async fn bar_async(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// is polled. + async fn baz_async((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method is polled. + async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +struct Bar<'a>(PhantomData<&'a ()>); + +impl<'a> Bar<'a> { + /// Check that unused bindings are dropped after the method with self is polled. + async fn foo_async(&'a self, x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(&'a self, x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method with self is polled. + async fn bar_async(&'a self, x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(&'a self, x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// with self is polled. + async fn baz_async(&'a self, (x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync(&'a self, (x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method with self is polled. + async fn foobar_async(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +fn assert_drop_order_after_poll>( + f: impl FnOnce(DropOrderListPtr) -> Fut, + g: impl FnOnce(DropOrderListPtr), +) { + let empty = Arc::new(EmptyWaker); + let waker = ArcWake::into_waker(empty); + let mut cx = Context::from_waker(&waker); + + let actual_order = Rc::new(RefCell::new(Vec::new())); + let mut fut = Box::pin(f(actual_order.clone())); + let _ = fut.as_mut().poll(&mut cx); + + let expected_order = Rc::new(RefCell::new(Vec::new())); + g(expected_order.clone()); + + assert_eq!(*actual_order.borrow(), *expected_order.borrow()); +} + +fn main() { + // Free functions (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())), + |l| bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods w/out self (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())), + |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + Foo::foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + Foo::foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods (see doc comment on function for what it tests). + let b = Bar(Default::default()); + assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())), + |l| b.bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| b.baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + b.foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + b.foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); +} diff --git a/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.rs b/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.rs new file mode 100644 index 0000000000000..bcdb8878eb5d2 --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.rs @@ -0,0 +1,16 @@ +// edition:2018 + +#![allow(unused_variables)] +#![feature(async_await)] + +async fn foobar_async(x: u32, (a, _, _c): (u32, u32, u32), _: u32, _y: u32) { + assert_eq!(__arg1, (1, 2, 3)); //~ ERROR cannot find value `__arg1` in this scope [E0425] + assert_eq!(__arg2, 4); //~ ERROR cannot find value `__arg2` in this scope [E0425] +} + +async fn baz_async(ref mut x: u32, ref y: u32) { + assert_eq!(__arg0, 1); //~ ERROR cannot find value `__arg0` in this scope [E0425] + assert_eq!(__arg1, 2); //~ ERROR cannot find value `__arg1` in this scope [E0425] +} + +fn main() {} diff --git a/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr b/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr new file mode 100644 index 0000000000000..484e1f4f4269e --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr @@ -0,0 +1,27 @@ +error[E0425]: cannot find value `__arg1` in this scope + --> $DIR/drop-order-locals-are-hidden.rs:7:16 + | +LL | assert_eq!(__arg1, (1, 2, 3)); + | ^^^^^^ not found in this scope + +error[E0425]: cannot find value `__arg2` in this scope + --> $DIR/drop-order-locals-are-hidden.rs:8:16 + | +LL | assert_eq!(__arg2, 4); + | ^^^^^^ not found in this scope + +error[E0425]: cannot find value `__arg0` in this scope + --> $DIR/drop-order-locals-are-hidden.rs:12:16 + | +LL | assert_eq!(__arg0, 1); + | ^^^^^^ not found in this scope + +error[E0425]: cannot find value `__arg1` in this scope + --> $DIR/drop-order-locals-are-hidden.rs:13:16 + | +LL | assert_eq!(__arg1, 2); + | ^^^^^^ not found in this scope + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/editions/edition-deny-async-fns-2015.rs b/src/test/ui/async-await/edition-deny-async-fns-2015.rs similarity index 84% rename from src/test/ui/editions/edition-deny-async-fns-2015.rs rename to src/test/ui/async-await/edition-deny-async-fns-2015.rs index 2105aa5835d0d..a5bc181015475 100644 --- a/src/test/ui/editions/edition-deny-async-fns-2015.rs +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.rs @@ -1,6 +1,6 @@ // edition:2015 -#![feature(futures_api, async_await)] +#![feature(async_await)] async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition @@ -28,6 +28,12 @@ fn main() { async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition } + accept_item! { + impl Foo { + async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition + } + } + let inside_closure = || { async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition }; diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr new file mode 100644 index 0000000000000..efb4462095d0d --- /dev/null +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -0,0 +1,63 @@ +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:5:1 + | +LL | async fn foo() {} + | ^^^^^ + +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:7:12 + | +LL | fn baz() { async fn foo() {} } + | ^^^^^ + +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:10:5 + | +LL | async fn bar() {} + | ^^^^^ + +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:9:1 + | +LL | async fn async_baz() { + | ^^^^^ + +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:16:5 + | +LL | async fn foo() {} + | ^^^^^ + +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:20:5 + | +LL | async fn foo() {} + | ^^^^^ + +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:38:9 + | +LL | async fn bar() {} + | ^^^^^ + +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:28:9 + | +LL | async fn foo() {} + | ^^^^^ + +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:33:13 + | +LL | async fn bar() {} + | ^^^^^ + +error[E0706]: trait fns cannot be declared `async` + --> $DIR/edition-deny-async-fns-2015.rs:20:5 + | +LL | async fn foo() {} + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0670`. diff --git a/src/test/ui/async-await/generics-and-bounds.rs b/src/test/ui/async-await/generics-and-bounds.rs new file mode 100644 index 0000000000000..913f1435c6adf --- /dev/null +++ b/src/test/ui/async-await/generics-and-bounds.rs @@ -0,0 +1,90 @@ +// compile-pass +// edition:2018 +// compile-flags: --crate-type lib + +#![feature(async_await)] + +use std::future::Future; + +pub async fn simple_generic() {} + +pub trait Foo { + fn foo(&self) {} +} + +struct FooType; +impl Foo for FooType {} + +pub async fn call_generic_bound(f: F) { + f.foo() +} + +pub async fn call_where_clause(f: F) +where + F: Foo, +{ + f.foo() +} + +pub async fn call_impl_trait(f: impl Foo) { + f.foo() +} + +pub async fn call_with_ref(f: &impl Foo) { + f.foo() +} + +pub fn async_fn_with_same_generic_params_unifies() { + let mut a = call_generic_bound(FooType); + a = call_generic_bound(FooType); + + let mut b = call_where_clause(FooType); + b = call_where_clause(FooType); + + let mut c = call_impl_trait(FooType); + c = call_impl_trait(FooType); + + let f_one = FooType; + let f_two = FooType; + let mut d = call_with_ref(&f_one); + d = call_with_ref(&f_two); +} + +pub fn simple_generic_block() -> impl Future { + async move {} +} + +pub fn call_generic_bound_block(f: F) -> impl Future { + async move { f.foo() } +} + +pub fn call_where_clause_block(f: F) -> impl Future +where + F: Foo, +{ + async move { f.foo() } +} + +pub fn call_impl_trait_block(f: impl Foo) -> impl Future { + async move { f.foo() } +} + +pub fn call_with_ref_block<'a>(f: &'a (impl Foo + 'a)) -> impl Future + 'a { + async move { f.foo() } +} + +pub fn async_block_with_same_generic_params_unifies() { + let mut a = call_generic_bound_block(FooType); + a = call_generic_bound_block(FooType); + + let mut b = call_where_clause_block(FooType); + b = call_where_clause_block(FooType); + + let mut c = call_impl_trait_block(FooType); + c = call_impl_trait_block(FooType); + + let f_one = FooType; + let f_two = FooType; + let mut d = call_with_ref_block(&f_one); + d = call_with_ref_block(&f_two); +} diff --git a/src/test/ui/async-await/issue-61452.rs b/src/test/ui/async-await/issue-61452.rs new file mode 100644 index 0000000000000..20b9b645daead --- /dev/null +++ b/src/test/ui/async-await/issue-61452.rs @@ -0,0 +1,14 @@ +// edition:2018 +#![feature(async_await)] + +pub async fn f(x: Option) { + x.take(); + //~^ ERROR cannot borrow `x` as mutable, as it is not declared as mutable [E0596] +} + +pub async fn g(x: usize) { + x += 1; + //~^ ERROR cannot assign twice to immutable variable `x` [E0384] +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-61452.stderr b/src/test/ui/async-await/issue-61452.stderr new file mode 100644 index 0000000000000..742490d8de43c --- /dev/null +++ b/src/test/ui/async-await/issue-61452.stderr @@ -0,0 +1,23 @@ +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/issue-61452.rs:5:5 + | +LL | pub async fn f(x: Option) { + | - help: consider changing this to be mutable: `mut x` +LL | x.take(); + | ^ cannot borrow as mutable + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/issue-61452.rs:10:5 + | +LL | pub async fn g(x: usize) { + | - + | | + | first assignment to `x` + | help: make this binding mutable: `mut x` +LL | x += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0384, E0596. +For more information about an error, try `rustc --explain E0384`. diff --git a/src/test/ui/async-await/issue-61793.rs b/src/test/ui/async-await/issue-61793.rs new file mode 100644 index 0000000000000..bccdf0113ff69 --- /dev/null +++ b/src/test/ui/async-await/issue-61793.rs @@ -0,0 +1,19 @@ +// This testcase used to ICE in codegen due to inconsistent field reordering +// in the generator state, claiming a ZST field was after a non-ZST field, +// while those two fields were at the same offset (which is impossible). +// That is, memory ordering of `(X, ())`, but offsets of `((), X)`. + +// compile-pass +// edition:2018 + +#![feature(async_await)] +#![allow(unused)] + +async fn foo(_: &(), _: F) {} + +fn main() { + foo(&(), || {}); + async { + foo(&(), || {}).await; + }; +} diff --git a/src/test/ui/async-await/issues/auxiliary/issue-60674.rs b/src/test/ui/async-await/issues/auxiliary/issue-60674.rs new file mode 100644 index 0000000000000..680c6e55e5668 --- /dev/null +++ b/src/test/ui/async-await/issues/auxiliary/issue-60674.rs @@ -0,0 +1,12 @@ +// force-host +// no-prefer-dynamic +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn attr(_args: TokenStream, input: TokenStream) -> TokenStream { + println!("{}", input); + TokenStream::new() +} diff --git a/src/test/ui/async-await/issues/issue-51719.rs b/src/test/ui/async-await/issues/issue-51719.rs new file mode 100644 index 0000000000000..361a49c2774ec --- /dev/null +++ b/src/test/ui/async-await/issues/issue-51719.rs @@ -0,0 +1,14 @@ +// edition:2018 +// +// Tests that the .await syntax can't be used to make a generator + +#![feature(async_await)] + +async fn foo() {} + +fn make_generator() { + let _gen = || foo().await; + //~^ ERROR `await` is only allowed inside `async` functions and blocks +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-51719.stderr b/src/test/ui/async-await/issues/issue-51719.stderr new file mode 100644 index 0000000000000..2a9fb6cf0df6e --- /dev/null +++ b/src/test/ui/async-await/issues/issue-51719.stderr @@ -0,0 +1,10 @@ +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-51719.rs:10:19 + | +LL | let _gen = || foo().await; + | -- ^^^^^^^^^^^ only allowed inside `async` functions and blocks + | | + | this is not `async` + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issues/issue-51751.rs b/src/test/ui/async-await/issues/issue-51751.rs new file mode 100644 index 0000000000000..7afd7ecc82649 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-51751.rs @@ -0,0 +1,13 @@ +// edition:2018 + +#![feature(async_await)] + +async fn inc(limit: i64) -> i64 { + limit + 1 +} + +fn main() { + let result = inc(10000); + let finished = result.await; + //~^ ERROR `await` is only allowed inside `async` functions and blocks +} diff --git a/src/test/ui/async-await/issues/issue-51751.stderr b/src/test/ui/async-await/issues/issue-51751.stderr new file mode 100644 index 0000000000000..97b63d1590ec6 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-51751.stderr @@ -0,0 +1,11 @@ +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-51751.rs:11:20 + | +LL | fn main() { + | ---- this is not `async` +LL | let result = inc(10000); +LL | let finished = result.await; + | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issues/issue-53249.rs b/src/test/ui/async-await/issues/issue-53249.rs new file mode 100644 index 0000000000000..2157cf7d4f7ab --- /dev/null +++ b/src/test/ui/async-await/issues/issue-53249.rs @@ -0,0 +1,47 @@ +// compile-pass +// edition:2018 + +#![feature(arbitrary_self_types, async_await, await_macro)] + +use std::task::{self, Poll}; +use std::future::Future; +use std::marker::Unpin; +use std::pin::Pin; + +// This is a regression test for a ICE/unbounded recursion issue relating to async-await. + +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct Lazy { + f: Option +} + +impl Unpin for Lazy {} + +pub fn lazy(f: F) -> Lazy + where F: FnOnce(&mut task::Context) -> R, +{ + Lazy { f: Some(f) } +} + +impl Future for Lazy + where F: FnOnce(&mut task::Context) -> R, +{ + type Output = R; + + fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context) -> Poll { + Poll::Ready((self.f.take().unwrap())(cx)) + } +} + +async fn __receive(want: WantFn) -> () + where Fut: Future, WantFn: Fn(&Box) -> Fut, +{ + await!(lazy(|_| ())); +} + +pub fn basic_spawn_receive() { + async { await!(__receive(|_| async { () })) }; +} + +fn main() {} diff --git a/src/test/pretty/issue-54752-async-block.rs b/src/test/ui/async-await/issues/issue-54752-async-block.rs similarity index 90% rename from src/test/pretty/issue-54752-async-block.rs rename to src/test/ui/async-await/issues/issue-54752-async-block.rs index 6930ee1a386fe..0036de90b2579 100644 --- a/src/test/pretty/issue-54752-async-block.rs +++ b/src/test/ui/async-await/issues/issue-54752-async-block.rs @@ -1,7 +1,9 @@ -#![feature(async_await)] -#![allow(unused_parens)] +// run-pass // edition:2018 // pp-exact +#![feature(async_await)] +#![allow(unused_parens)] + fn main() { let _a = (async { }); } diff --git a/src/test/ui/async-await/issues/issue-54974.rs b/src/test/ui/async-await/issues/issue-54974.rs new file mode 100644 index 0000000000000..ad18f41187569 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-54974.rs @@ -0,0 +1,16 @@ +// compile-pass +// edition:2018 + +#![feature(async_await, await_macro)] + +use std::sync::Arc; + +trait SomeTrait: Send + Sync + 'static { + fn do_something(&self); +} + +async fn my_task(obj: Arc) { + unimplemented!() +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-55324.rs b/src/test/ui/async-await/issues/issue-55324.rs new file mode 100644 index 0000000000000..4572e543f22de --- /dev/null +++ b/src/test/ui/async-await/issues/issue-55324.rs @@ -0,0 +1,14 @@ +// compile-pass +// edition:2018 + +#![feature(async_await, await_macro)] + +use std::future::Future; + +#[allow(unused)] +async fn foo>(x: &i32, future: F) -> i32 { + let y = await!(future); + *x + y +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-55809.rs b/src/test/ui/async-await/issues/issue-55809.rs new file mode 100644 index 0000000000000..b7e60b773b416 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-55809.rs @@ -0,0 +1,30 @@ +// edition:2018 +// run-pass + +#![feature(async_await)] + +trait Foo { } + +impl Foo for () { } + +impl<'a, T> Foo for &'a mut T where T: Foo { } + +async fn foo_async(_v: T) -> u8 where T: Foo { + 0 +} + +async fn bad(v: T) -> u8 where T: Foo { + foo_async(v).await +} + +async fn async_main() { + let mut v = (); + + let _ = bad(&mut v).await; + let _ = foo_async(&mut v).await; + let _ = bad(v).await; +} + +fn main() { + let _ = async_main(); +} diff --git a/src/test/ui/async-await/issues/issue-58885.rs b/src/test/ui/async-await/issues/issue-58885.rs new file mode 100644 index 0000000000000..99d87b2273c2f --- /dev/null +++ b/src/test/ui/async-await/issues/issue-58885.rs @@ -0,0 +1,21 @@ +// compile-pass +// edition:2018 + +#![feature(async_await, await_macro)] + +struct Xyz { + a: u64, +} + +trait Foo {} + +impl Xyz { + async fn do_sth<'a>( + &'a self, foo: &'a dyn Foo + ) -> bool + { + true + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-59001.rs b/src/test/ui/async-await/issues/issue-59001.rs new file mode 100644 index 0000000000000..c758244002ff6 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-59001.rs @@ -0,0 +1,17 @@ +// compile-pass +// edition:2018 + +#![feature(async_await, await_macro)] + +use std::future::Future; + +#[allow(unused)] +async fn enter<'a, F, R>(mut callback: F) +where + F: FnMut(&'a mut i32) -> R, + R: Future + 'a, +{ + unimplemented!() +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-59972.rs b/src/test/ui/async-await/issues/issue-59972.rs new file mode 100644 index 0000000000000..31e7a65dc98e3 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-59972.rs @@ -0,0 +1,25 @@ +// run-pass + +// compile-flags: --edition=2018 + +#![feature(async_await, await_macro)] + +pub enum Uninhabited { } + +fn uninhabited_async() -> Uninhabited { + unreachable!() +} + +async fn noop() { } + +#[allow(unused)] +async fn contains_never() { + let error = uninhabited_async(); + await!(noop()); + let error2 = error; +} + +#[allow(unused_must_use)] +fn main() { + contains_never(); +} diff --git a/src/test/ui/async-await/issues/issue-60518.rs b/src/test/ui/async-await/issues/issue-60518.rs new file mode 100644 index 0000000000000..f603c5bd3f946 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-60518.rs @@ -0,0 +1,12 @@ +// compile-pass +// edition:2018 + +#![feature(async_await)] + +// This is a regression test to ensure that simple bindings (where replacement arguments aren't +// created during async fn lowering) that have their DefId used during HIR lowering (such as impl +// trait) are visited during def collection and thus have a DefId. + +async fn foo(ws: impl Iterator) {} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-60655-latebound-regions.rs b/src/test/ui/async-await/issues/issue-60655-latebound-regions.rs new file mode 100644 index 0000000000000..a4fe86501299f --- /dev/null +++ b/src/test/ui/async-await/issues/issue-60655-latebound-regions.rs @@ -0,0 +1,30 @@ +// Test that existential types are allowed to contain late-bound regions. + +// compile-pass +// edition:2018 + +#![feature(async_await, existential_type)] + +use std::future::Future; + +pub existential type Func: Sized; + +// Late bound region should be allowed to escape the function, since it's bound +// in the type. +fn null_function_ptr() -> Func { + None:: fn(&'a ())> +} + +async fn async_nop(_: &u8) {} + +pub existential type ServeFut: Future; + +// Late bound regions occur in the generator witness type here. +fn serve() -> ServeFut { + async move { + let x = 5; + async_nop(&x).await + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-60674.rs b/src/test/ui/async-await/issues/issue-60674.rs new file mode 100644 index 0000000000000..ecb80803383b4 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-60674.rs @@ -0,0 +1,20 @@ +// aux-build:issue-60674.rs +// compile-pass +// edition:2018 +#![feature(async_await)] + +// This is a regression test that ensures that `mut` patterns are not lost when provided as input +// to a proc macro. + +extern crate issue_60674; + +#[issue_60674::attr] +async fn f(mut x: u8) {} + +#[issue_60674::attr] +async fn g((mut x, y, mut z): (u8, u8, u8)) {} + +#[issue_60674::attr] +async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) {} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-60674.stdout b/src/test/ui/async-await/issues/issue-60674.stdout new file mode 100644 index 0000000000000..86c3591b3afc0 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-60674.stdout @@ -0,0 +1,3 @@ +async fn f(mut x: u8) { } +async fn g((mut x, y, mut z): (u8, u8, u8)) { } +async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) { } diff --git a/src/test/ui/async-await/issues/issue-61187.rs b/src/test/ui/async-await/issues/issue-61187.rs new file mode 100644 index 0000000000000..8b939b43b8bd4 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-61187.rs @@ -0,0 +1,9 @@ +// edition:2018 +#![feature(async_await)] + +fn main() { +} + +async fn response(data: Vec) { + data.reverse(); //~ ERROR E0596 +} diff --git a/src/test/ui/async-await/issues/issue-61187.stderr b/src/test/ui/async-await/issues/issue-61187.stderr new file mode 100644 index 0000000000000..a03142263202e --- /dev/null +++ b/src/test/ui/async-await/issues/issue-61187.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow `data` as mutable, as it is not declared as mutable + --> $DIR/issue-61187.rs:8:5 + | +LL | async fn response(data: Vec) { + | ---- help: consider changing this to be mutable: `mut data` +LL | data.reverse(); + | ^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/async-await/issues/issue-61986.rs b/src/test/ui/async-await/issues/issue-61986.rs new file mode 100644 index 0000000000000..da8b22bc104bf --- /dev/null +++ b/src/test/ui/async-await/issues/issue-61986.rs @@ -0,0 +1,21 @@ +// compile-pass +// edition:2018 +// +// Tests that we properly handle StorageDead/StorageLives for temporaries +// created in async loop bodies. + +#![feature(async_await)] + +async fn bar() -> Option<()> { + Some(()) +} + +async fn listen() { + while let Some(_) = bar().await { + String::new(); + } +} + +fn main() { + listen(); +} diff --git a/src/test/ui/async-await/issues/issue-62009.rs b/src/test/ui/async-await/issues/issue-62009.rs new file mode 100644 index 0000000000000..e2d58cac24d94 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62009.rs @@ -0,0 +1,19 @@ +// edition:2018 + +#![feature(async_await)] + +async fn print_dur() {} + +fn main() { + async { let (); }.await; + //~^ ERROR `await` is only allowed inside `async` functions and blocks + async { + //~^ ERROR `await` is only allowed inside `async` functions and blocks + let task1 = print_dur().await; + }.await; + (async || 2333)().await; + //~^ ERROR `await` is only allowed inside `async` functions and blocks + (|_| 2333).await; + //~^ ERROR `await` is only allowed inside `async` functions and blocks + //~^^ ERROR +} diff --git a/src/test/ui/async-await/issues/issue-62009.stderr b/src/test/ui/async-await/issues/issue-62009.stderr new file mode 100644 index 0000000000000..53d1f34fe4f9b --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62009.stderr @@ -0,0 +1,49 @@ +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-62009.rs:8:5 + | +LL | fn main() { + | ---- this is not `async` +LL | async { let (); }.await; + | ^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-62009.rs:10:5 + | +LL | fn main() { + | ---- this is not `async` +... +LL | / async { +LL | | +LL | | let task1 = print_dur().await; +LL | | }.await; + | |___________^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-62009.rs:14:5 + | +LL | fn main() { + | ---- this is not `async` +... +LL | (async || 2333)().await; + | ^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-62009.rs:16:5 + | +LL | fn main() { + | ---- this is not `async` +... +LL | (|_| 2333).await; + | ^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0277]: the trait bound `[closure@$DIR/issue-62009.rs:16:5: 16:15]: std::future::Future` is not satisfied + --> $DIR/issue-62009.rs:16:5 + | +LL | (|_| 2333).await; + | ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009.rs:16:5: 16:15]` + | + = note: required by `std::future::poll_with_tls_context` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/multiple-lifetimes/elided.rs b/src/test/ui/async-await/multiple-lifetimes/elided.rs new file mode 100644 index 0000000000000..45f3170d4c309 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/elided.rs @@ -0,0 +1,12 @@ +// edition:2018 +// run-pass + +// Test that we can use async fns with multiple arbitrary lifetimes. + +#![feature(async_await)] + +async fn multiple_elided_lifetimes(_: &u8, _: &u8) {} + +fn main() { + let _ = multiple_elided_lifetimes(&22, &44); +} diff --git a/src/test/ui/async-await/multiple-lifetimes/fn-ptr.rs b/src/test/ui/async-await/multiple-lifetimes/fn-ptr.rs new file mode 100644 index 0000000000000..a7254cee75526 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/fn-ptr.rs @@ -0,0 +1,14 @@ +// edition:2018 +// run-pass + +// Test that we can use async fns with multiple arbitrary lifetimes. + +#![feature(async_await)] + +async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8, _: fn(&u8)) {} + +fn gimme(_: &u8) { } + +fn main() { + let _ = multiple_named_lifetimes(&22, &44, gimme); +} diff --git a/src/test/ui/async-await/multiple-lifetimes/hrtb.rs b/src/test/ui/async-await/multiple-lifetimes/hrtb.rs new file mode 100644 index 0000000000000..620b0080966b9 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/hrtb.rs @@ -0,0 +1,17 @@ +// edition:2018 +// run-pass + +// Test that we can use async fns with multiple arbitrary lifetimes. + +#![feature(arbitrary_self_types, async_await, await_macro)] +#![allow(dead_code)] + +use std::ops::Add; + +async fn multiple_hrtb_and_single_named_lifetime_ok<'c>( + _: impl for<'a> Add<&'a u8>, + _: impl for<'b> Add<&'b u8>, + _: &'c u8, +) {} + +fn main() {} diff --git a/src/test/ui/async-await/multiple-lifetimes/named.rs b/src/test/ui/async-await/multiple-lifetimes/named.rs new file mode 100644 index 0000000000000..7d13d48bc8bbd --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/named.rs @@ -0,0 +1,12 @@ +// edition:2018 +// run-pass + +// Test that we can use async fns with multiple arbitrary lifetimes. + +#![feature(arbitrary_self_types, async_await, await_macro)] + +async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {} + +fn main() { + let _ = multiple_named_lifetimes(&22, &44); +} diff --git a/src/test/ui/async-await/multiple-lifetimes/partial-relation.rs b/src/test/ui/async-await/multiple-lifetimes/partial-relation.rs new file mode 100644 index 0000000000000..903c43950a5c4 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/partial-relation.rs @@ -0,0 +1,15 @@ +// edition:2018 +// run-pass + +#![feature(async_await)] + +async fn lotsa_lifetimes<'a, 'b, 'c>(a: &'a u32, b: &'b u32, c: &'c u32) -> (&'a u32, &'b u32) + where 'b: 'a +{ + drop((a, c)); + (b, b) +} + +fn main() { + let _ = lotsa_lifetimes(&22, &44, &66); +} diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs new file mode 100644 index 0000000000000..08622311f7b1c --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs @@ -0,0 +1,18 @@ +// edition:2018 +// run-pass + +// Test that a feature gate is needed to use `impl Trait` as the +// return type of an async. + +#![feature(async_await, member_constraints)] + +trait Trait<'a, 'b> { } +impl Trait<'_, '_> for T { } + +async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { + (a, b) +} + +fn main() { + let _ = async_ret_impl_trait(&22, &44); +} diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs new file mode 100644 index 0000000000000..08ecea4cc85fc --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs @@ -0,0 +1,18 @@ +// edition:2018 + +// Test that a feature gate is needed to use `impl Trait` as the +// return type of an async. + +#![feature(async_await)] + +trait Trait<'a, 'b> { } +impl Trait<'_, '_> for T { } + +async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { + //~^ ERROR ambiguous lifetime bound + (a, b) +} + +fn main() { + let _ = async_ret_impl_trait(&22, &44); +} diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr new file mode 100644 index 0000000000000..de2c85d772a72 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr @@ -0,0 +1,10 @@ +error: ambiguous lifetime bound in `impl Trait` + --> $DIR/ret-impl-trait-no-fg.rs:11:64 + | +LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { + | ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other + | + = help: add #![feature(member_constraints)] to the crate attributes to enable + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr new file mode 100644 index 0000000000000..b4d5d3ec051e2 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/ret-impl-trait-one.rs:12:80 + | +LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> { + | ________________________________--__--__________________________________________^ + | | | | + | | | lifetime `'b` defined here + | | lifetime `'a` defined here +LL | | +LL | | (a, b) +LL | | } + | |_^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs new file mode 100644 index 0000000000000..e1b714652737f --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs @@ -0,0 +1,27 @@ +// edition:2018 + +// Test that a feature gate is needed to use `impl Trait` as the +// return type of an async. + +#![feature(async_await, member_constraints)] + +trait Trait<'a> { } +impl Trait<'_> for T { } + +// Only `'a` permitted in return type, not `'b`. +async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> { + //~^ ERROR lifetime mismatch + (a, b) +} + +// As above, but `'b: 'a`, so return type can be inferred to `(&'a u8, +// &'a u8)`. +async fn async_ret_impl_trait2<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> +where + 'b: 'a, +{ + (a, b) +} + +fn main() { +} diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr new file mode 100644 index 0000000000000..f6d611517bc8f --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr @@ -0,0 +1,11 @@ +error[E0623]: lifetime mismatch + --> $DIR/ret-impl-trait-one.rs:12:65 + | +LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> { + | ------ ^^^^^^^^^^^^^^ + | | | + | | ...but data from `b` is returned here + | this parameter and the return type are declared with different lifetimes... + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-ref.rs b/src/test/ui/async-await/multiple-lifetimes/ret-ref.rs new file mode 100644 index 0000000000000..98da90161e5fd --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/ret-ref.rs @@ -0,0 +1,46 @@ +// edition:2018 + +// Test that we get the expected borrow check errors when an async +// function (which takes multiple lifetimes) only returns data from +// one of them. + +#![feature(async_await)] + +async fn multiple_named_lifetimes<'a, 'b>(a: &'a u8, _: &'b u8) -> &'a u8 { + a +} + +// Both are borrowed whilst the future is live. +async fn future_live() { + let mut a = 22; + let mut b = 44; + let future = multiple_named_lifetimes(&a, &b); + a += 1; //~ ERROR cannot assign + b += 1; //~ ERROR cannot assign + let p = future.await; + drop(p); +} + +// Just the return value is live after future is awaited. +async fn just_return_live() { + let mut a = 22; + let mut b = 44; + let future = multiple_named_lifetimes(&a, &b); + let p = future.await; + a += 1; //~ ERROR cannot assign + b += 1; + drop(p); +} + +// Once `p` is dead, both `a` and `b` are unborrowed. +async fn after_both_dead() { + let mut a = 22; + let mut b = 44; + let future = multiple_named_lifetimes(&a, &b); + let p = future.await; + drop(p); + a += 1; + b += 1; +} + +fn main() { } diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-ref.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-ref.stderr new file mode 100644 index 0000000000000..fe70d35942c7c --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/ret-ref.stderr @@ -0,0 +1,37 @@ +error[E0506]: cannot assign to `a` because it is borrowed + --> $DIR/ret-ref.rs:18:5 + | +LL | let future = multiple_named_lifetimes(&a, &b); + | -- borrow of `a` occurs here +LL | a += 1; + | ^^^^^^ assignment to borrowed `a` occurs here +LL | b += 1; +LL | let p = future.await; + | ------ borrow later used here + +error[E0506]: cannot assign to `b` because it is borrowed + --> $DIR/ret-ref.rs:19:5 + | +LL | let future = multiple_named_lifetimes(&a, &b); + | -- borrow of `b` occurs here +LL | a += 1; +LL | b += 1; + | ^^^^^^ assignment to borrowed `b` occurs here +LL | let p = future.await; + | ------ borrow later used here + +error[E0506]: cannot assign to `a` because it is borrowed + --> $DIR/ret-ref.rs:30:5 + | +LL | let future = multiple_named_lifetimes(&a, &b); + | -- borrow of `a` occurs here +LL | let p = future.await; +LL | a += 1; + | ^^^^^^ assignment to borrowed `a` occurs here +LL | b += 1; +LL | drop(p); + | - borrow later used here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/async-await/multiple-lifetimes/variance.rs b/src/test/ui/async-await/multiple-lifetimes/variance.rs new file mode 100644 index 0000000000000..b52ad17d5631d --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/variance.rs @@ -0,0 +1,18 @@ +// edition:2018 +// run-pass + +// Test for async fn where the parameters have distinct lifetime +// parameters that appear in all possible variances. + +#![feature(async_await)] + +#[allow(dead_code)] +async fn lotsa_lifetimes<'a, 'b, 'c>(_: fn(&'a u8), _: fn(&'b u8) -> &'b u8, _: fn() -> &'c u8) { } + +fn take_any(_: &u8) { } +fn identify(x: &u8) -> &u8 { x } +fn give_back() -> &'static u8 { &22 } + +fn main() { + let _ = lotsa_lifetimes(take_any, identify, give_back); +} diff --git a/src/test/ui/async-await/no-args-non-move-async-closure.rs b/src/test/ui/async-await/no-args-non-move-async-closure.rs new file mode 100644 index 0000000000000..345f19b06233b --- /dev/null +++ b/src/test/ui/async-await/no-args-non-move-async-closure.rs @@ -0,0 +1,8 @@ +// edition:2018 + +#![feature(async_await, await_macro)] + +fn main() { + let _ = async |x: u8| {}; + //~^ ERROR `async` non-`move` closures with arguments are not currently supported +} diff --git a/src/test/ui/no-args-non-move-async-closure.stderr b/src/test/ui/async-await/no-args-non-move-async-closure.stderr similarity index 84% rename from src/test/ui/no-args-non-move-async-closure.stderr rename to src/test/ui/async-await/no-args-non-move-async-closure.stderr index e1d16f669a99c..1b4b86210f840 100644 --- a/src/test/ui/no-args-non-move-async-closure.stderr +++ b/src/test/ui/async-await/no-args-non-move-async-closure.stderr @@ -8,4 +8,3 @@ LL | let _ = async |x: u8| {}; error: aborting due to previous error -For more information about this error, try `rustc --explain E0708`. diff --git a/src/test/ui/async-await/no-async-const.rs b/src/test/ui/async-await/no-async-const.rs new file mode 100644 index 0000000000000..1db314a5aa208 --- /dev/null +++ b/src/test/ui/async-await/no-async-const.rs @@ -0,0 +1,8 @@ +// compile-fail +// edition:2018 +// compile-flags: --crate-type lib + +#![feature(async_await)] + +pub async const fn x() {} +//~^ ERROR expected one of `fn` or `unsafe`, found `const` diff --git a/src/test/ui/async-await/no-async-const.stderr b/src/test/ui/async-await/no-async-const.stderr new file mode 100644 index 0000000000000..cdb1c6e2d7bd9 --- /dev/null +++ b/src/test/ui/async-await/no-async-const.stderr @@ -0,0 +1,8 @@ +error: expected one of `fn` or `unsafe`, found `const` + --> $DIR/no-async-const.rs:7:11 + | +LL | pub async const fn x() {} + | ^^^^^ expected one of `fn` or `unsafe` here + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/no-const-async.rs b/src/test/ui/async-await/no-const-async.rs new file mode 100644 index 0000000000000..9f09d2188c7c0 --- /dev/null +++ b/src/test/ui/async-await/no-const-async.rs @@ -0,0 +1,9 @@ +// compile-fail +// edition:2018 +// compile-flags: --crate-type lib + +#![feature(async_await)] + +pub const async fn x() {} +//~^ ERROR expected identifier, found reserved keyword `async` +//~^^ expected `:`, found keyword `fn` diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr new file mode 100644 index 0000000000000..693fbf186f913 --- /dev/null +++ b/src/test/ui/async-await/no-const-async.stderr @@ -0,0 +1,18 @@ +error: expected identifier, found reserved keyword `async` + --> $DIR/no-const-async.rs:7:11 + | +LL | pub const async fn x() {} + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | pub const r#async fn x() {} + | ^^^^^^^ + +error: expected `:`, found keyword `fn` + --> $DIR/no-const-async.rs:7:17 + | +LL | pub const async fn x() {} + | ^^ expected `:` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/async-await/no-unsafe-async.rs b/src/test/ui/async-await/no-unsafe-async.rs new file mode 100644 index 0000000000000..81e0cd799ad70 --- /dev/null +++ b/src/test/ui/async-await/no-unsafe-async.rs @@ -0,0 +1,11 @@ +// edition:2018 + +struct S; + +impl S { + #[cfg(FALSE)] + unsafe async fn g() {} //~ ERROR expected one of `extern` or `fn`, found `async` +} + +#[cfg(FALSE)] +unsafe async fn f() {} //~ ERROR expected one of `extern`, `fn`, or `{`, found `async` diff --git a/src/test/ui/async-await/no-unsafe-async.stderr b/src/test/ui/async-await/no-unsafe-async.stderr new file mode 100644 index 0000000000000..c339c7c3bf5bf --- /dev/null +++ b/src/test/ui/async-await/no-unsafe-async.stderr @@ -0,0 +1,14 @@ +error: expected one of `extern` or `fn`, found `async` + --> $DIR/no-unsafe-async.rs:7:12 + | +LL | unsafe async fn g() {} + | ^^^^^ expected one of `extern` or `fn` here + +error: expected one of `extern`, `fn`, or `{`, found `async` + --> $DIR/no-unsafe-async.rs:11:8 + | +LL | unsafe async fn f() {} + | ^^^^^ expected one of `extern`, `fn`, or `{` here + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/impl-trait/recursive-async-impl-trait-type.rs b/src/test/ui/async-await/recursive-async-impl-trait-type.rs similarity index 80% rename from src/test/ui/impl-trait/recursive-async-impl-trait-type.rs rename to src/test/ui/async-await/recursive-async-impl-trait-type.rs index 40642523be255..a4e080119345e 100644 --- a/src/test/ui/impl-trait/recursive-async-impl-trait-type.rs +++ b/src/test/ui/async-await/recursive-async-impl-trait-type.rs @@ -2,7 +2,7 @@ // Test that impl trait does not allow creating recursive types that are // otherwise forbidden when using `async` and `await`. -#![feature(await_macro, async_await, futures_api, generators)] +#![feature(await_macro, async_await, generators)] async fn recursive_async_function() -> () { //~ ERROR await!(recursive_async_function()); diff --git a/src/test/ui/impl-trait/recursive-async-impl-trait-type.stderr b/src/test/ui/async-await/recursive-async-impl-trait-type.stderr similarity index 88% rename from src/test/ui/impl-trait/recursive-async-impl-trait-type.stderr rename to src/test/ui/async-await/recursive-async-impl-trait-type.stderr index acdeabb2f9892..abc9ff54bdee8 100644 --- a/src/test/ui/impl-trait/recursive-async-impl-trait-type.stderr +++ b/src/test/ui/async-await/recursive-async-impl-trait-type.stderr @@ -1,7 +1,7 @@ error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-async-impl-trait-type.rs:7:40 | -LL | async fn recursive_async_function() -> () { //~ ERROR +LL | async fn recursive_async_function() -> () { | ^^ expands to self-referential type | = note: expanded type is `std::future::GenFuture<[static generator@$DIR/recursive-async-impl-trait-type.rs:7:43: 9:2 {impl std::future::Future, ()}]>` diff --git a/src/test/ui/async-await/suggest-missing-await.fixed b/src/test/ui/async-await/suggest-missing-await.fixed new file mode 100644 index 0000000000000..282be368c69cd --- /dev/null +++ b/src/test/ui/async-await/suggest-missing-await.fixed @@ -0,0 +1,32 @@ +// edition:2018 +// run-rustfix + +#![feature(async_await)] + +fn take_u32(_x: u32) {} + +async fn make_u32() -> u32 { + 22 +} + +#[allow(unused)] +async fn suggest_await_in_async_fn() { + let x = make_u32(); + take_u32(x.await) + //~^ ERROR mismatched types [E0308] + //~| HELP consider using `.await` here + //~| SUGGESTION x.await +} + +#[allow(unused)] +async fn suggest_await_in_async_closure() { + async || { + let x = make_u32(); + take_u32(x.await) + //~^ ERROR mismatched types [E0308] + //~| HELP consider using `.await` here + //~| SUGGESTION x.await + }; +} + +fn main() {} diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs new file mode 100644 index 0000000000000..36103f050c147 --- /dev/null +++ b/src/test/ui/async-await/suggest-missing-await.rs @@ -0,0 +1,32 @@ +// edition:2018 +// run-rustfix + +#![feature(async_await)] + +fn take_u32(_x: u32) {} + +async fn make_u32() -> u32 { + 22 +} + +#[allow(unused)] +async fn suggest_await_in_async_fn() { + let x = make_u32(); + take_u32(x) + //~^ ERROR mismatched types [E0308] + //~| HELP consider using `.await` here + //~| SUGGESTION x.await +} + +#[allow(unused)] +async fn suggest_await_in_async_closure() { + async || { + let x = make_u32(); + take_u32(x) + //~^ ERROR mismatched types [E0308] + //~| HELP consider using `.await` here + //~| SUGGESTION x.await + }; +} + +fn main() {} diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr new file mode 100644 index 0000000000000..59c20dcfbc947 --- /dev/null +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -0,0 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/suggest-missing-await.rs:15:14 + | +LL | take_u32(x) + | ^ + | | + | expected u32, found opaque type + | help: consider using `.await` here: `x.await` + | + = note: expected type `u32` + found type `impl std::future::Future` + +error[E0308]: mismatched types + --> $DIR/suggest-missing-await.rs:25:18 + | +LL | take_u32(x) + | ^ + | | + | expected u32, found opaque type + | help: consider using `.await` here: `x.await` + | + = note: expected type `u32` + found type `impl std::future::Future` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs new file mode 100644 index 0000000000000..578d41fe0df0b --- /dev/null +++ b/src/test/ui/async-await/unresolved_type_param.rs @@ -0,0 +1,15 @@ +// Provoke an unresolved type error (T). +// Error message should pinpoint the type parameter T as needing to be bound +// (rather than give a general error message) +// edition:2018 +#![feature(async_await)] +async fn bar() -> () {} + +async fn foo() { + bar().await; + //~^ ERROR type inside `async` object must be known in this context + //~| NOTE cannot infer type for `T` + //~| NOTE the type is part of the `async` object because of this `await` + //~| NOTE in this expansion of desugaring of `await` +} +fn main() {} diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr new file mode 100644 index 0000000000000..f3090a2b980e8 --- /dev/null +++ b/src/test/ui/async-await/unresolved_type_param.stderr @@ -0,0 +1,15 @@ +error[E0698]: type inside `async` object must be known in this context + --> $DIR/unresolved_type_param.rs:9:5 + | +LL | bar().await; + | ^^^ cannot infer type for `T` + | +note: the type is part of the `async` object because of this `await` + --> $DIR/unresolved_type_param.rs:9:5 + | +LL | bar().await; + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0698`. diff --git a/src/test/ui/async-fn-multiple-lifetimes.rs b/src/test/ui/async-fn-multiple-lifetimes.rs deleted file mode 100644 index 6156617c4da65..0000000000000 --- a/src/test/ui/async-fn-multiple-lifetimes.rs +++ /dev/null @@ -1,20 +0,0 @@ -// edition:2018 - -#![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)] - -use std::ops::Add; - -async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {} -//~^ ERROR multiple different lifetimes used in arguments of `async fn` - -async fn multiple_hrtb_and_single_named_lifetime_ok<'c>( - _: impl for<'a> Add<&'a u8>, - _: impl for<'b> Add<&'b u8>, - _: &'c u8, -) {} - -async fn multiple_elided_lifetimes(_: &u8, _: &u8) {} -//~^ ERROR multiple elided lifetimes used -//~^^ ERROR missing lifetime specifier - -fn main() {} diff --git a/src/test/ui/async-fn-multiple-lifetimes.stderr b/src/test/ui/async-fn-multiple-lifetimes.stderr deleted file mode 100644 index 071349b23facc..0000000000000 --- a/src/test/ui/async-fn-multiple-lifetimes.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error[E0709]: multiple different lifetimes used in arguments of `async fn` - --> $DIR/async-fn-multiple-lifetimes.rs:7:47 - | -LL | async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {} - | ^^ ^^ different lifetime here - | | - | first lifetime here - | - = help: `async fn` can only accept borrowed values with identical lifetimes - -error[E0707]: multiple elided lifetimes used in arguments of `async fn` - --> $DIR/async-fn-multiple-lifetimes.rs:16:39 - | -LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {} - | ^ ^ different lifetime here - | | - | first lifetime here - | - = help: consider giving these arguments named lifetimes - -error[E0106]: missing lifetime specifier - --> $DIR/async-fn-multiple-lifetimes.rs:16:39 - | -LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {} - | ^ expected lifetime parameter - | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_` or `_` - -error: aborting due to 3 previous errors - -Some errors occurred: E0106, E0707, E0709. -For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/attempted-access-non-fatal.stderr b/src/test/ui/attempted-access-non-fatal.stderr index 2fee49acdf4b7..5b7db0e9d6fb4 100644 --- a/src/test/ui/attempted-access-non-fatal.stderr +++ b/src/test/ui/attempted-access-non-fatal.stderr @@ -1,13 +1,13 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> $DIR/attempted-access-non-fatal.rs:4:15 | -LL | let _ = x.foo; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] +LL | let _ = x.foo; | ^^^ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> $DIR/attempted-access-non-fatal.rs:5:15 | -LL | let _ = x.bar; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] +LL | let _ = x.bar; | ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/attr-eq-token-tree.rs b/src/test/ui/attr-eq-token-tree.rs index 6aacb9d572aea..c301492b9e21a 100644 --- a/src/test/ui/attr-eq-token-tree.rs +++ b/src/test/ui/attr-eq-token-tree.rs @@ -1,4 +1,2 @@ -#![feature(custom_attribute)] - #[my_attr = !] //~ ERROR unexpected token: `!` fn main() {} diff --git a/src/test/ui/attr-eq-token-tree.stderr b/src/test/ui/attr-eq-token-tree.stderr index 57d6a4e0f16a2..bb37c2e0cc473 100644 --- a/src/test/ui/attr-eq-token-tree.stderr +++ b/src/test/ui/attr-eq-token-tree.stderr @@ -1,8 +1,8 @@ error: unexpected token: `!` - --> $DIR/attr-eq-token-tree.rs:3:11 + --> $DIR/attr-eq-token-tree.rs:1:13 | -LL | #[my_attr = !] //~ ERROR unexpected token: `!` - | ^ +LL | #[my_attr = !] + | ^ error: aborting due to previous error diff --git a/src/test/ui/attr-usage-inline.stderr b/src/test/ui/attr-usage-inline.stderr index 3030a2f8f1d62..d8d7f6adb82b5 100644 --- a/src/test/ui/attr-usage-inline.stderr +++ b/src/test/ui/attr-usage-inline.stderr @@ -1,7 +1,7 @@ error[E0518]: attribute should be applied to function or closure --> $DIR/attr-usage-inline.rs:6:1 | -LL | #[inline] //~ ERROR: attribute should be applied to function or closure +LL | #[inline] | ^^^^^^^^^ LL | struct S; | --------- not a function or closure diff --git a/src/test/ui/attr-usage-repr.rs b/src/test/ui/attr-usage-repr.rs index 1df2947cbe2dd..a0b82375e777d 100644 --- a/src/test/ui/attr-usage-repr.rs +++ b/src/test/ui/attr-usage-repr.rs @@ -1,7 +1,6 @@ #![feature(repr_simd)] -#![feature(repr_align_enum)] -#[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union +#[repr(C)] //~ ERROR: attribute should be applied to struct, enum, or union fn f() {} #[repr(C)] diff --git a/src/test/ui/attr-usage-repr.stderr b/src/test/ui/attr-usage-repr.stderr index abb8685e4cef0..82d80d8d0b173 100644 --- a/src/test/ui/attr-usage-repr.stderr +++ b/src/test/ui/attr-usage-repr.stderr @@ -1,31 +1,31 @@ -error[E0517]: attribute should be applied to struct, enum or union - --> $DIR/attr-usage-repr.rs:4:8 +error[E0517]: attribute should be applied to struct, enum, or union + --> $DIR/attr-usage-repr.rs:3:8 | -LL | #[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union +LL | #[repr(C)] | ^ LL | fn f() {} - | --------- not a struct, enum or union + | --------- not a struct, enum, or union error[E0517]: attribute should be applied to enum - --> $DIR/attr-usage-repr.rs:16:8 + --> $DIR/attr-usage-repr.rs:15:8 | -LL | #[repr(i8)] //~ ERROR: attribute should be applied to enum +LL | #[repr(i8)] | ^^ LL | struct SInt(f64, f64); | ---------------------- not an enum error[E0517]: attribute should be applied to struct or union - --> $DIR/attr-usage-repr.rs:25:8 + --> $DIR/attr-usage-repr.rs:24:8 | -LL | #[repr(packed)] //~ ERROR: attribute should be applied to struct +LL | #[repr(packed)] | ^^^^^^ LL | enum EPacked { A, B } | --------------------- not a struct or union error[E0517]: attribute should be applied to struct - --> $DIR/attr-usage-repr.rs:28:8 + --> $DIR/attr-usage-repr.rs:27:8 | -LL | #[repr(simd)] //~ ERROR: attribute should be applied to struct +LL | #[repr(simd)] | ^^^^ LL | enum ESimd { A, B } | ------------------- not a struct diff --git a/src/test/ui/attribute-with-no-generics-in-parameter-list.stderr b/src/test/ui/attribute-with-no-generics-in-parameter-list.stderr index f08f107a62ffe..4c5964715db7e 100644 --- a/src/test/ui/attribute-with-no-generics-in-parameter-list.stderr +++ b/src/test/ui/attribute-with-no-generics-in-parameter-list.stderr @@ -1,7 +1,7 @@ error: attribute without generic parameters --> $DIR/attribute-with-no-generics-in-parameter-list.rs:1:8 | -LL | fn foo<#[attr]>() {} //~ ERROR attribute without generic parameters +LL | fn foo<#[attr]>() {} | ^^^^^^^ attributes are only permitted when preceding parameters error: aborting due to previous error diff --git a/src/test/ui/attributes/attr-before-view-item.rs b/src/test/ui/attributes/attr-before-view-item.rs new file mode 100644 index 0000000000000..fc040bd1a5d10 --- /dev/null +++ b/src/test/ui/attributes/attr-before-view-item.rs @@ -0,0 +1,10 @@ +// compile-pass +// pretty-expanded FIXME #23616 + +#![feature(rustc_attrs)] +#![feature(test)] + +#[rustc_dummy = "bar"] +extern crate test; + +fn main() {} diff --git a/src/test/ui/attributes/attr-before-view-item2.rs b/src/test/ui/attributes/attr-before-view-item2.rs new file mode 100644 index 0000000000000..c7fad3802e9d6 --- /dev/null +++ b/src/test/ui/attributes/attr-before-view-item2.rs @@ -0,0 +1,12 @@ +// compile-pass +// pretty-expanded FIXME #23616 + +#![feature(rustc_attrs)] +#![feature(test)] + +mod m { + #[rustc_dummy = "bar"] + extern crate test; +} + +fn main() {} diff --git a/src/test/ui/attributes/attr-mix-new.rs b/src/test/ui/attributes/attr-mix-new.rs new file mode 100644 index 0000000000000..d9cb551096092 --- /dev/null +++ b/src/test/ui/attributes/attr-mix-new.rs @@ -0,0 +1,11 @@ +// compile-pass +// pretty-expanded FIXME #23616 + +#![feature(rustc_attrs)] + +#[rustc_dummy(bar)] +mod foo { + #![feature(globs)] +} + +fn main() {} diff --git a/src/test/ui/attrs-with-no-formal-in-generics/attrs-with-no-formal-in-generics-1.rs b/src/test/ui/attributes/attrs-with-no-formal-in-generics-1.rs similarity index 100% rename from src/test/ui/attrs-with-no-formal-in-generics/attrs-with-no-formal-in-generics-1.rs rename to src/test/ui/attributes/attrs-with-no-formal-in-generics-1.rs diff --git a/src/test/ui/attrs-with-no-formal-in-generics/attrs-with-no-formal-in-generics-1.stderr b/src/test/ui/attributes/attrs-with-no-formal-in-generics-1.stderr similarity index 100% rename from src/test/ui/attrs-with-no-formal-in-generics/attrs-with-no-formal-in-generics-1.stderr rename to src/test/ui/attributes/attrs-with-no-formal-in-generics-1.stderr diff --git a/src/test/ui/attrs-with-no-formal-in-generics/attrs-with-no-formal-in-generics-2.rs b/src/test/ui/attributes/attrs-with-no-formal-in-generics-2.rs similarity index 100% rename from src/test/ui/attrs-with-no-formal-in-generics/attrs-with-no-formal-in-generics-2.rs rename to src/test/ui/attributes/attrs-with-no-formal-in-generics-2.rs diff --git a/src/test/ui/attrs-with-no-formal-in-generics/attrs-with-no-formal-in-generics-2.stderr b/src/test/ui/attributes/attrs-with-no-formal-in-generics-2.stderr similarity index 100% rename from src/test/ui/attrs-with-no-formal-in-generics/attrs-with-no-formal-in-generics-2.stderr rename to src/test/ui/attributes/attrs-with-no-formal-in-generics-2.stderr diff --git a/src/test/ui/attrs-with-no-formal-in-generics/attrs-with-no-formal-in-generics-3.rs b/src/test/ui/attributes/attrs-with-no-formal-in-generics-3.rs similarity index 100% rename from src/test/ui/attrs-with-no-formal-in-generics/attrs-with-no-formal-in-generics-3.rs rename to src/test/ui/attributes/attrs-with-no-formal-in-generics-3.rs diff --git a/src/test/ui/attrs-with-no-formal-in-generics/attrs-with-no-formal-in-generics-3.stderr b/src/test/ui/attributes/attrs-with-no-formal-in-generics-3.stderr similarity index 100% rename from src/test/ui/attrs-with-no-formal-in-generics/attrs-with-no-formal-in-generics-3.stderr rename to src/test/ui/attributes/attrs-with-no-formal-in-generics-3.stderr diff --git a/src/test/ui/attributes/class-attributes-1.rs b/src/test/ui/attributes/class-attributes-1.rs new file mode 100644 index 0000000000000..7808367f2c10f --- /dev/null +++ b/src/test/ui/attributes/class-attributes-1.rs @@ -0,0 +1,19 @@ +// compile-pass +// pp-exact - Make sure we actually print the attributes + +#![feature(rustc_attrs)] + +struct Cat { + name: String, +} + +impl Drop for Cat { + #[rustc_dummy] + fn drop(&mut self) { println!("{} landed on hir feet" , self . name); } +} + + +#[rustc_dummy] +fn cat(name: String) -> Cat { Cat{name: name,} } + +fn main() { let _kitty = cat("Spotty".to_string()); } diff --git a/src/test/ui/attributes/class-attributes-2.rs b/src/test/ui/attributes/class-attributes-2.rs new file mode 100644 index 0000000000000..348c70f35c328 --- /dev/null +++ b/src/test/ui/attributes/class-attributes-2.rs @@ -0,0 +1,31 @@ +// compile-pass + +#![feature(rustc_attrs)] + +struct Cat { + name: String, +} + +impl Drop for Cat { + #[rustc_dummy] + /** + Actually, cats don't always land on their feet when you drop them. + */ + fn drop(&mut self) { + println!("{} landed on hir feet", self.name); + } +} + +#[rustc_dummy] +/** +Maybe it should technically be a kitten_maker. +*/ +fn cat(name: String) -> Cat { + Cat { + name: name + } +} + +fn main() { + let _kitty = cat("Spotty".to_string()); +} diff --git a/src/test/ui/attributes/item-attributes.rs b/src/test/ui/attributes/item-attributes.rs new file mode 100644 index 0000000000000..72c9a35dc07f0 --- /dev/null +++ b/src/test/ui/attributes/item-attributes.rs @@ -0,0 +1,181 @@ +// These are attributes of the implicit crate. Really this just needs to parse +// for completeness since .rs files linked from .rc files support this +// notation to specify their module's attributes + +// compile-pass + +#![feature(rustc_attrs)] + +#![rustc_dummy = "val"] +#![rustc_dummy = "val"] +#![rustc_dummy] +#![rustc_dummy(attr5)] + +#![crate_id="foobar#0.1"] + +// These are attributes of the following mod +#[rustc_dummy = "val"] +#[rustc_dummy = "val"] +mod test_first_item_in_file_mod {} + +mod test_single_attr_outer { + #[rustc_dummy = "val"] + pub static X: isize = 10; + + #[rustc_dummy = "val"] + pub fn f() { } + + #[rustc_dummy = "val"] + pub mod mod1 {} + + pub mod rustrt { + #[rustc_dummy = "val"] + extern {} + } +} + +mod test_multi_attr_outer { + #[rustc_dummy = "val"] + #[rustc_dummy = "val"] + pub static X: isize = 10; + + #[rustc_dummy = "val"] + #[rustc_dummy = "val"] + pub fn f() { } + + #[rustc_dummy = "val"] + #[rustc_dummy = "val"] + pub mod mod1 {} + + pub mod rustrt { + #[rustc_dummy = "val"] + #[rustc_dummy = "val"] + extern {} + } + + #[rustc_dummy = "val"] + #[rustc_dummy = "val"] + struct T {x: isize} +} + +mod test_stmt_single_attr_outer { + pub fn f() { + #[rustc_dummy = "val"] + static X: isize = 10; + + #[rustc_dummy = "val"] + fn f() { } + + #[rustc_dummy = "val"] + mod mod1 { + } + + mod rustrt { + #[rustc_dummy = "val"] + extern { + } + } + } +} + +mod test_stmt_multi_attr_outer { + pub fn f() { + + #[rustc_dummy = "val"] + #[rustc_dummy = "val"] + static X: isize = 10; + + #[rustc_dummy = "val"] + #[rustc_dummy = "val"] + fn f() { } + + #[rustc_dummy = "val"] + #[rustc_dummy = "val"] + mod mod1 { + } + + mod rustrt { + #[rustc_dummy = "val"] + #[rustc_dummy = "val"] + extern { + } + } + } +} + +mod test_attr_inner { + pub mod m { + // This is an attribute of mod m + #![rustc_dummy = "val"] + } +} + +mod test_attr_inner_then_outer { + pub mod m { + // This is an attribute of mod m + #![rustc_dummy = "val"] + // This is an attribute of fn f + #[rustc_dummy = "val"] + fn f() { } + } +} + +mod test_attr_inner_then_outer_multi { + pub mod m { + // This is an attribute of mod m + #![rustc_dummy = "val"] + #![rustc_dummy = "val"] + // This is an attribute of fn f + #[rustc_dummy = "val"] + #[rustc_dummy = "val"] + fn f() { } + } +} + +mod test_distinguish_syntax_ext { + pub fn f() { + format!("test{}", "s"); + #[rustc_dummy = "val"] + fn g() { } + } +} + +mod test_other_forms { + #[rustc_dummy] + #[rustc_dummy(word)] + #[rustc_dummy(attr(word))] + #[rustc_dummy(key1 = "val", key2 = "val", attr)] + pub fn f() { } +} + +mod test_foreign_items { + pub mod rustrt { + extern { + #![rustc_dummy] + + #[rustc_dummy] + fn rust_get_test_int() -> u32; + } + } +} + + +// FIXME(#623): - these aren't supported yet +/*mod test_literals { + #![str = "s"] + #![char = 'c'] + #![isize = 100] + #![usize = 100_usize] + #![mach_int = 100u32] + #![float = 1.0] + #![mach_float = 1.0f32] + #![nil = ()] + #![bool = true] + mod m {} +}*/ + +fn test_fn_inner() { + #![rustc_dummy] +} + +fn main() {} diff --git a/src/test/ui/attributes/method-attributes.rs b/src/test/ui/attributes/method-attributes.rs new file mode 100644 index 0000000000000..2d608acc71f71 --- /dev/null +++ b/src/test/ui/attributes/method-attributes.rs @@ -0,0 +1,28 @@ +// compile-pass +// pp-exact - Make sure we print all the attributes +// pretty-expanded FIXME #23616 + +#![feature(rustc_attrs)] + +#[rustc_dummy] +trait Frobable { + #[rustc_dummy] + fn frob(&self); + #[rustc_dummy] + fn defrob(&self); +} + +#[rustc_dummy] +impl Frobable for isize { + #[rustc_dummy] + fn frob(&self) { + #![rustc_dummy] + } + + #[rustc_dummy] + fn defrob(&self) { + #![rustc_dummy] + } +} + +fn main() {} diff --git a/src/test/ui/attributes/obsolete-attr.rs b/src/test/ui/attributes/obsolete-attr.rs new file mode 100644 index 0000000000000..89e2ad2669cbe --- /dev/null +++ b/src/test/ui/attributes/obsolete-attr.rs @@ -0,0 +1,7 @@ +// Obsolete attributes fall back to feature gated custom attributes. + +#[ab_isize="stdcall"] extern {} //~ ERROR attribute `ab_isize` is currently unknown + +#[fixed_stack_segment] fn f() {} //~ ERROR attribute `fixed_stack_segment` is currently unknown + +fn main() {} diff --git a/src/test/ui/attributes/obsolete-attr.stderr b/src/test/ui/attributes/obsolete-attr.stderr new file mode 100644 index 0000000000000..2ed7f87935fca --- /dev/null +++ b/src/test/ui/attributes/obsolete-attr.stderr @@ -0,0 +1,21 @@ +error[E0658]: The attribute `fixed_stack_segment` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/obsolete-attr.rs:5:3 + | +LL | #[fixed_stack_segment] fn f() {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `ab_isize` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/obsolete-attr.rs:3:3 + | +LL | #[ab_isize="stdcall"] extern {} + | ^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/attributes/unknown-attr.rs b/src/test/ui/attributes/unknown-attr.rs new file mode 100644 index 0000000000000..e2a4f3226d562 --- /dev/null +++ b/src/test/ui/attributes/unknown-attr.rs @@ -0,0 +1,9 @@ +// Unknown attributes fall back to feature gated custom attributes. + +#![feature(custom_inner_attributes)] + +#![mutable_doc] //~ ERROR attribute `mutable_doc` is currently unknown + +#[dance] mod a {} //~ ERROR attribute `dance` is currently unknown + +#[dance] fn main() {} //~ ERROR attribute `dance` is currently unknown diff --git a/src/test/ui/attributes/unknown-attr.stderr b/src/test/ui/attributes/unknown-attr.stderr new file mode 100644 index 0000000000000..d0ac58108fc8d --- /dev/null +++ b/src/test/ui/attributes/unknown-attr.stderr @@ -0,0 +1,30 @@ +error[E0658]: The attribute `mutable_doc` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/unknown-attr.rs:5:4 + | +LL | #![mutable_doc] + | ^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `dance` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/unknown-attr.rs:7:3 + | +LL | #[dance] mod a {} + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `dance` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/unknown-attr.rs:9:3 + | +LL | #[dance] fn main() {} + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/attributes/variant-attributes.rs b/src/test/ui/attributes/variant-attributes.rs new file mode 100644 index 0000000000000..a910340f4a06d --- /dev/null +++ b/src/test/ui/attributes/variant-attributes.rs @@ -0,0 +1,37 @@ +// compile-pass +// pp-exact - Make sure we actually print the attributes +// pretty-expanded FIXME #23616 + +#![allow(non_camel_case_types)] +#![feature(rustc_attrs)] + +enum crew_of_enterprise_d { + + #[rustc_dummy] + jean_luc_picard, + + #[rustc_dummy] + william_t_riker, + + #[rustc_dummy] + beverly_crusher, + + #[rustc_dummy] + deanna_troi, + + #[rustc_dummy] + data, + + #[rustc_dummy] + worf, + + #[rustc_dummy] + geordi_la_forge, +} + +fn boldly_go(_crew_member: crew_of_enterprise_d, _where: String) { } + +fn main() { + boldly_go(crew_of_enterprise_d::worf, + "where no one has gone before".to_string()); +} diff --git a/src/test/ui/augmented-assignments.nll.stderr b/src/test/ui/augmented-assignments.nll.stderr deleted file mode 100644 index 33c94d6e3a59e..0000000000000 --- a/src/test/ui/augmented-assignments.nll.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/augmented-assignments.rs:16:5 - | -LL | x //~ error: use of moved value: `x` - | - - | | - | _____borrow of `x` occurs here - | | -LL | | //~^ value used here after move -LL | | += -LL | | x; //~ value moved here - | | ^ - | | | - | |_____move out of `x` occurs here - | borrow later used here - -error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable - --> $DIR/augmented-assignments.rs:21:5 - | -LL | let y = Int(2); - | - help: consider changing this to be mutable: `mut y` -... -LL | y //~ error: cannot borrow immutable local variable `y` as mutable - | ^ cannot borrow as mutable - -error: aborting due to 2 previous errors - -Some errors occurred: E0505, E0596. -For more information about an error, try `rustc --explain E0505`. diff --git a/src/test/ui/augmented-assignments.rs b/src/test/ui/augmented-assignments.rs index eea15eae879e6..1b4ac6edcb0d5 100644 --- a/src/test/ui/augmented-assignments.rs +++ b/src/test/ui/augmented-assignments.rs @@ -10,16 +10,18 @@ impl AddAssign for Int { fn main() { let mut x = Int(1); - x //~ error: use of moved value: `x` - //~^ value used here after move + x + //~^ NOTE borrow of `x` occurs here += - x; //~ value moved here + x; + //~^ ERROR cannot move out of `x` because it is borrowed + //~| move out of `x` occurs here let y = Int(2); - //~^ HELP make this binding mutable + //~^ HELP consider changing this to be mutable //~| SUGGESTION mut y - y //~ error: cannot borrow immutable local variable `y` as mutable - //~| cannot borrow + y //~ ERROR cannot borrow `y` as mutable, as it is not declared as mutable + //~| cannot borrow as mutable += Int(1); } diff --git a/src/test/ui/augmented-assignments.stderr b/src/test/ui/augmented-assignments.stderr index 73de315e542a2..ce555da8975a7 100644 --- a/src/test/ui/augmented-assignments.stderr +++ b/src/test/ui/augmented-assignments.stderr @@ -1,24 +1,22 @@ -error[E0596]: cannot borrow immutable local variable `y` as mutable - --> $DIR/augmented-assignments.rs:21:5 +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/augmented-assignments.rs:16:5 | -LL | let y = Int(2); - | - help: make this binding mutable: `mut y` +LL | x + | - borrow of `x` occurs here ... -LL | y //~ error: cannot borrow immutable local variable `y` as mutable - | ^ cannot borrow mutably +LL | x; + | ^ move out of `x` occurs here -error[E0382]: use of moved value: `x` - --> $DIR/augmented-assignments.rs:13:5 +error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable + --> $DIR/augmented-assignments.rs:23:5 | -LL | x //~ error: use of moved value: `x` - | ^ value used here after move +LL | let y = Int(2); + | - help: consider changing this to be mutable: `mut y` ... -LL | x; //~ value moved here - | - value moved here - | - = note: move occurs because `x` has type `Int`, which does not implement the `Copy` trait +LL | y + | ^ cannot borrow as mutable error: aborting due to 2 previous errors -Some errors occurred: E0382, E0596. -For more information about an error, try `rustc --explain E0382`. +Some errors have detailed explanations: E0505, E0596. +For more information about an error, try `rustc --explain E0505`. diff --git a/src/test/ui/auto-ref-slice-plus-ref.stderr b/src/test/ui/auto-ref-slice-plus-ref.stderr index 356e24d18a78f..f2e0d379d1b30 100644 --- a/src/test/ui/auto-ref-slice-plus-ref.stderr +++ b/src/test/ui/auto-ref-slice-plus-ref.stderr @@ -1,8 +1,8 @@ error[E0599]: no method named `test_mut` found for type `std::vec::Vec<{integer}>` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:7:7 | -LL | a.test_mut(); //~ ERROR no method named `test_mut` found - | ^^^^^^^^ help: did you mean: `get_mut` +LL | a.test_mut(); + | ^^^^^^^^ help: there is a method with a similar name: `get_mut` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `test_mut`, perhaps you need to implement it: @@ -11,7 +11,7 @@ LL | a.test_mut(); //~ ERROR no method named `test_mut` found error[E0599]: no method named `test` found for type `std::vec::Vec<{integer}>` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:8:7 | -LL | a.test(); //~ ERROR no method named `test` found +LL | a.test(); | ^^^^ | = help: items from traits can only be used if the trait is implemented and in scope @@ -21,7 +21,7 @@ LL | a.test(); //~ ERROR no method named `test` found error[E0599]: no method named `test` found for type `[{integer}; 1]` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:10:11 | -LL | ([1]).test(); //~ ERROR no method named `test` found +LL | ([1]).test(); | ^^^^ | = help: items from traits can only be used if the trait is implemented and in scope @@ -31,7 +31,7 @@ LL | ([1]).test(); //~ ERROR no method named `test` found error[E0599]: no method named `test` found for type `&[{integer}; 1]` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:11:12 | -LL | (&[1]).test(); //~ ERROR no method named `test` found +LL | (&[1]).test(); | ^^^^ | = help: items from traits can only be used if the trait is implemented and in scope diff --git a/src/test/ui/auto-trait-validation.stderr b/src/test/ui/auto-trait-validation.stderr index e077982069e07..ae21984c06d72 100644 --- a/src/test/ui/auto-trait-validation.stderr +++ b/src/test/ui/auto-trait-validation.stderr @@ -18,5 +18,4 @@ LL | auto trait MyTrait { fn foo() {} } error: aborting due to 3 previous errors -Some errors occurred: E0380, E0567, E0568. -For more information about an error, try `rustc --explain E0380`. +For more information about this error, try `rustc --explain E0380`. diff --git a/src/test/ui/autoderef-full-lval.stderr b/src/test/ui/autoderef-full-lval.stderr index b92259b69df8e..c9f3e8b2e26c5 100644 --- a/src/test/ui/autoderef-full-lval.stderr +++ b/src/test/ui/autoderef-full-lval.stderr @@ -1,16 +1,20 @@ error[E0369]: binary operation `+` cannot be applied to type `std::boxed::Box` - --> $DIR/autoderef-full-lval.rs:15:20 + --> $DIR/autoderef-full-lval.rs:15:24 | LL | let z: isize = a.x + b.y; - | ^^^^^^^^^ + | --- ^ --- std::boxed::Box + | | + | std::boxed::Box | = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box` error[E0369]: binary operation `+` cannot be applied to type `std::boxed::Box` - --> $DIR/autoderef-full-lval.rs:21:25 + --> $DIR/autoderef-full-lval.rs:21:33 | LL | let answer: isize = forty.a + two.a; - | ^^^^^^^^^^^^^^^ + | ------- ^ ----- std::boxed::Box + | | + | std::boxed::Box | = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box` diff --git a/src/test/ui/auxiliary/default-ty-param-cross-crate-crate.rs b/src/test/ui/auxiliary/default-ty-param-cross-crate-crate.rs new file mode 100644 index 0000000000000..d722b78768a47 --- /dev/null +++ b/src/test/ui/auxiliary/default-ty-param-cross-crate-crate.rs @@ -0,0 +1,9 @@ +#![crate_type = "lib"] +#![crate_name = "default_param_test"] +#![feature(default_type_parameter_fallback)] + +use std::marker::PhantomData; + +pub struct Foo(PhantomData<(A, B)>); + +pub fn bleh() -> Foo { Foo(PhantomData) } diff --git a/src/test/ui/auxiliary/default_ty_param_cross_crate_crate.rs b/src/test/ui/auxiliary/default_ty_param_cross_crate_crate.rs deleted file mode 100644 index 612f99dbcf884..0000000000000 --- a/src/test/ui/auxiliary/default_ty_param_cross_crate_crate.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![crate_type = "lib"] -#![crate_name = "default_param_test"] -#![feature(default_type_parameter_fallback)] - -use std::marker::PhantomData; - -pub struct Foo(PhantomData<(A, B)>); - -pub fn bleh() -> Foo { Foo(PhantomData) } - diff --git a/src/test/ui/auxiliary/define_macro.rs b/src/test/ui/auxiliary/define-macro.rs similarity index 100% rename from src/test/ui/auxiliary/define_macro.rs rename to src/test/ui/auxiliary/define-macro.rs diff --git a/src/test/ui/auxiliary/extern-prelude-vec.rs b/src/test/ui/auxiliary/extern-prelude-vec.rs new file mode 100644 index 0000000000000..a643c8889109a --- /dev/null +++ b/src/test/ui/auxiliary/extern-prelude-vec.rs @@ -0,0 +1,3 @@ +#![crate_name = "Vec"] + +pub fn new(arg1: f32, arg2: ()) {} diff --git a/src/test/ui/auxiliary/extern-prelude.rs b/src/test/ui/auxiliary/extern-prelude.rs new file mode 100644 index 0000000000000..2fdfd85a1da30 --- /dev/null +++ b/src/test/ui/auxiliary/extern-prelude.rs @@ -0,0 +1,5 @@ +pub struct S; + +impl S { + pub fn external(&self) {} +} diff --git a/src/test/ui/auxiliary/orphan_check_diagnostics.rs b/src/test/ui/auxiliary/orphan-check-diagnostics.rs similarity index 100% rename from src/test/ui/auxiliary/orphan_check_diagnostics.rs rename to src/test/ui/auxiliary/orphan-check-diagnostics.rs diff --git a/src/test/ui/auxiliary/pub_and_stability.rs b/src/test/ui/auxiliary/pub-and-stability.rs similarity index 100% rename from src/test/ui/auxiliary/pub_and_stability.rs rename to src/test/ui/auxiliary/pub-and-stability.rs diff --git a/src/test/ui/auxiliary/rmeta_meta.rs b/src/test/ui/auxiliary/rmeta-meta.rs similarity index 100% rename from src/test/ui/auxiliary/rmeta_meta.rs rename to src/test/ui/auxiliary/rmeta-meta.rs diff --git a/src/test/ui/auxiliary/rmeta_rlib.rs b/src/test/ui/auxiliary/rmeta-rlib.rs similarity index 100% rename from src/test/ui/auxiliary/rmeta_rlib.rs rename to src/test/ui/auxiliary/rmeta-rlib.rs diff --git a/src/test/ui/auxiliary/stability_cfg2.rs b/src/test/ui/auxiliary/stability-cfg2.rs similarity index 100% rename from src/test/ui/auxiliary/stability_cfg2.rs rename to src/test/ui/auxiliary/stability-cfg2.rs diff --git a/src/test/ui/auxiliary/xc_private_method_lib.rs b/src/test/ui/auxiliary/xc-private-method-lib.rs similarity index 100% rename from src/test/ui/auxiliary/xc_private_method_lib.rs rename to src/test/ui/auxiliary/xc-private-method-lib.rs diff --git a/src/test/ui/await-keyword/2015-edition-no-warnings-with-feature-gate.rs b/src/test/ui/await-keyword/2015-edition-no-warnings-with-feature-gate.rs deleted file mode 100644 index 92c60e7d6eed0..0000000000000 --- a/src/test/ui/await-keyword/2015-edition-no-warnings-with-feature-gate.rs +++ /dev/null @@ -1,16 +0,0 @@ -// compile-pass - -#![feature(async_await)] -#![allow(non_camel_case_types)] -#![deny(keyword_idents)] - -mod outer_mod { - pub mod await { - pub struct await; - } -} -use outer_mod::await::await; - -fn main() { - match await { await => {} } -} diff --git a/src/test/ui/await-keyword/2018-edition-error.rs b/src/test/ui/await-keyword/2018-edition-error.rs deleted file mode 100644 index 7ba3382ddf129..0000000000000 --- a/src/test/ui/await-keyword/2018-edition-error.rs +++ /dev/null @@ -1,15 +0,0 @@ -// edition:2018 -#![allow(non_camel_case_types)] - -mod outer_mod { - pub mod await { //~ ERROR `await` is a keyword - pub struct await; //~ ERROR `await` is a keyword - } -} -use self::outer_mod::await::await; //~ ERROR `await` is a keyword - //~^ ERROR `await` is a keyword - -fn main() { - match await { await => () } //~ ERROR `await` is a keyword - //~^ ERROR `await` is a keyword -} diff --git a/src/test/ui/await-keyword/2018-edition-error.stderr b/src/test/ui/await-keyword/2018-edition-error.stderr deleted file mode 100644 index 9ddb27916d184..0000000000000 --- a/src/test/ui/await-keyword/2018-edition-error.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0721]: `await` is a keyword in the 2018 edition - --> $DIR/2018-edition-error.rs:5:13 - | -LL | pub mod await { //~ ERROR `await` is a keyword - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` - -error[E0721]: `await` is a keyword in the 2018 edition - --> $DIR/2018-edition-error.rs:6:20 - | -LL | pub struct await; //~ ERROR `await` is a keyword - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` - -error[E0721]: `await` is a keyword in the 2018 edition - --> $DIR/2018-edition-error.rs:9:22 - | -LL | use self::outer_mod::await::await; //~ ERROR `await` is a keyword - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` - -error[E0721]: `await` is a keyword in the 2018 edition - --> $DIR/2018-edition-error.rs:9:29 - | -LL | use self::outer_mod::await::await; //~ ERROR `await` is a keyword - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` - -error[E0721]: `await` is a keyword in the 2018 edition - --> $DIR/2018-edition-error.rs:13:11 - | -LL | match await { await => () } //~ ERROR `await` is a keyword - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` - -error[E0721]: `await` is a keyword in the 2018 edition - --> $DIR/2018-edition-error.rs:13:19 - | -LL | match await { await => () } //~ ERROR `await` is a keyword - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0721`. diff --git a/src/test/ui/await-keyword/2018-edition-no-error-with-feature-gate.rs b/src/test/ui/await-keyword/2018-edition-no-error-with-feature-gate.rs deleted file mode 100644 index 52d32c8351080..0000000000000 --- a/src/test/ui/await-keyword/2018-edition-no-error-with-feature-gate.rs +++ /dev/null @@ -1,16 +0,0 @@ -// compile-pass -// edition:2018 - -#![allow(non_camel_case_types)] -#![feature(async_await)] - -mod outer_mod { - pub mod await { - pub struct await; - } -} -use self::outer_mod::await::await; - -fn main() { - match await { await => () } -} diff --git a/src/test/ui/await-keyword/post_expansion_error.rs b/src/test/ui/await-keyword/post_expansion_error.rs deleted file mode 100644 index 96dd48052def8..0000000000000 --- a/src/test/ui/await-keyword/post_expansion_error.rs +++ /dev/null @@ -1,10 +0,0 @@ -// edition:2018 - -macro_rules! r#await { - () => { println!("Hello, world!") } -} - -fn main() { - await!() - //~^ ERROR `await` is a keyword -} diff --git a/src/test/ui/await-keyword/post_expansion_error.stderr b/src/test/ui/await-keyword/post_expansion_error.stderr deleted file mode 100644 index 76ae35b7517e3..0000000000000 --- a/src/test/ui/await-keyword/post_expansion_error.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0721]: `await` is a keyword in the 2018 edition - --> $DIR/post_expansion_error.rs:8:5 - | -LL | await!() - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0721`. diff --git a/src/test/ui/bad/bad-env-capture.stderr b/src/test/ui/bad/bad-env-capture.stderr index 04975b0378098..f78a38a3dd45e 100644 --- a/src/test/ui/bad/bad-env-capture.stderr +++ b/src/test/ui/bad/bad-env-capture.stderr @@ -20,5 +20,5 @@ LL | fn bar() { log(debug, x); } error: aborting due to 3 previous errors -Some errors occurred: E0425, E0434. +Some errors have detailed explanations: E0425, E0434. For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/bad/bad-env-capture2.stderr b/src/test/ui/bad/bad-env-capture2.stderr index f7524c6a09f0e..57c807fd7dfdf 100644 --- a/src/test/ui/bad/bad-env-capture2.stderr +++ b/src/test/ui/bad/bad-env-capture2.stderr @@ -20,5 +20,5 @@ LL | fn bar() { log(debug, x); } error: aborting due to 3 previous errors -Some errors occurred: E0425, E0434. +Some errors have detailed explanations: E0425, E0434. For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/bad/bad-env-capture3.stderr b/src/test/ui/bad/bad-env-capture3.stderr index 137612c979088..d6eb4f86e11e0 100644 --- a/src/test/ui/bad/bad-env-capture3.stderr +++ b/src/test/ui/bad/bad-env-capture3.stderr @@ -20,5 +20,5 @@ LL | fn bar() { log(debug, x); } error: aborting due to 3 previous errors -Some errors occurred: E0425, E0434. +Some errors have detailed explanations: E0425, E0434. For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/bad/bad-expr-lhs.stderr b/src/test/ui/bad/bad-expr-lhs.stderr index 590d73bc3f5ef..a0de6a73797e2 100644 --- a/src/test/ui/bad/bad-expr-lhs.stderr +++ b/src/test/ui/bad/bad-expr-lhs.stderr @@ -1,34 +1,34 @@ error[E0070]: invalid left-hand side expression --> $DIR/bad-expr-lhs.rs:2:5 | -LL | 1 = 2; //~ ERROR invalid left-hand side expression +LL | 1 = 2; | ^^^^^ left-hand of expression not valid error[E0067]: invalid left-hand side expression --> $DIR/bad-expr-lhs.rs:3:5 | -LL | 1 += 2; //~ ERROR invalid left-hand side expression +LL | 1 += 2; | ^ invalid expression for left-hand side error[E0070]: invalid left-hand side expression --> $DIR/bad-expr-lhs.rs:4:5 | -LL | (1, 2) = (3, 4); //~ ERROR invalid left-hand side expression +LL | (1, 2) = (3, 4); | ^^^^^^^^^^^^^^^ left-hand of expression not valid error[E0070]: invalid left-hand side expression --> $DIR/bad-expr-lhs.rs:7:5 | -LL | (a, b) = (3, 4); //~ ERROR invalid left-hand side expression +LL | (a, b) = (3, 4); | ^^^^^^^^^^^^^^^ left-hand of expression not valid error[E0070]: invalid left-hand side expression --> $DIR/bad-expr-lhs.rs:9:5 | -LL | None = Some(3); //~ ERROR invalid left-hand side expression +LL | None = Some(3); | ^^^^^^^^^^^^^^ left-hand of expression not valid error: aborting due to 5 previous errors -Some errors occurred: E0067, E0070. +Some errors have detailed explanations: E0067, E0070. For more information about an error, try `rustc --explain E0067`. diff --git a/src/test/ui/bad/bad-expr-path.stderr b/src/test/ui/bad/bad-expr-path.stderr index 71ac9a16ba62c..15ac7f2b86f59 100644 --- a/src/test/ui/bad/bad-expr-path.stderr +++ b/src/test/ui/bad/bad-expr-path.stderr @@ -19,7 +19,7 @@ LL | log(debug, m1::arguments); error[E0580]: main function has wrong type --> $DIR/bad-expr-path.rs:3:1 | -LL | fn main(arguments: Vec) { //~ ERROR main function has wrong type +LL | fn main(arguments: Vec) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | = note: expected type `fn()` @@ -27,5 +27,5 @@ LL | fn main(arguments: Vec) { //~ ERROR main function has wrong type error: aborting due to 4 previous errors -Some errors occurred: E0425, E0580. +Some errors have detailed explanations: E0425, E0580. For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/bad/bad-expr-path2.stderr b/src/test/ui/bad/bad-expr-path2.stderr index 343de94182e9a..45723168f197b 100644 --- a/src/test/ui/bad/bad-expr-path2.stderr +++ b/src/test/ui/bad/bad-expr-path2.stderr @@ -19,7 +19,7 @@ LL | log(debug, m1::arguments); error[E0580]: main function has wrong type --> $DIR/bad-expr-path2.rs:5:1 | -LL | fn main(arguments: Vec) { //~ ERROR main function has wrong type +LL | fn main(arguments: Vec) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | = note: expected type `fn()` @@ -27,5 +27,5 @@ LL | fn main(arguments: Vec) { //~ ERROR main function has wrong type error: aborting due to 4 previous errors -Some errors occurred: E0423, E0425, E0580. +Some errors have detailed explanations: E0423, E0425, E0580. For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/bad/bad-extern-link-attrs.stderr b/src/test/ui/bad/bad-extern-link-attrs.stderr index 6732e8553f3f1..18b0dc9ea386e 100644 --- a/src/test/ui/bad/bad-extern-link-attrs.stderr +++ b/src/test/ui/bad/bad-extern-link-attrs.stderr @@ -1,24 +1,24 @@ error[E0459]: #[link(...)] specified without `name = "foo"` --> $DIR/bad-extern-link-attrs.rs:1:1 | -LL | #[link()] //~ ERROR: specified without `name = +LL | #[link()] | ^^^^^^^^^ missing `name` argument error[E0454]: #[link(name = "")] given with empty name --> $DIR/bad-extern-link-attrs.rs:2:1 | -LL | #[link(name = "")] //~ ERROR: with empty name +LL | #[link(name = "")] | ^^^^^^^^^^^^^^^^^^ empty name given error[E0458]: unknown kind: `bar` - --> $DIR/bad-extern-link-attrs.rs:4:1 + --> $DIR/bad-extern-link-attrs.rs:4:22 | -LL | #[link(name = "foo", kind = "bar")] //~ ERROR: unknown kind - | ^^^^^^^^^^^^^^^^^^^^^------------^^ +LL | #[link(name = "foo", kind = "bar")] + | ---------------------^^^^^^^^^^^^-- | | | unknown kind error: aborting due to 3 previous errors -Some errors occurred: E0454, E0458, E0459. +Some errors have detailed explanations: E0454, E0458, E0459. For more information about an error, try `rustc --explain E0454`. diff --git a/src/test/ui/bad/bad-intrinsic-monomorphization.stderr b/src/test/ui/bad/bad-intrinsic-monomorphization.stderr index dee33f574d84a..34fdba11367ea 100644 --- a/src/test/ui/bad/bad-intrinsic-monomorphization.stderr +++ b/src/test/ui/bad/bad-intrinsic-monomorphization.stderr @@ -18,4 +18,3 @@ LL | simd_add(a, b) error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/bad/bad-lint-cap2.stderr b/src/test/ui/bad/bad-lint-cap2.stderr index d7ec41489d156..f6e67e6d78df0 100644 --- a/src/test/ui/bad/bad-lint-cap2.stderr +++ b/src/test/ui/bad/bad-lint-cap2.stderr @@ -1,7 +1,7 @@ error: unused import: `std::option` --> $DIR/bad-lint-cap2.rs:6:5 | -LL | use std::option; //~ ERROR +LL | use std::option; | ^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/bad/bad-lint-cap3.rs b/src/test/ui/bad/bad-lint-cap3.rs index 8aab38ee5ecf4..c38105870e4c0 100644 --- a/src/test/ui/bad/bad-lint-cap3.rs +++ b/src/test/ui/bad/bad-lint-cap3.rs @@ -1,11 +1,9 @@ +// check-pass // compile-flags: --cap-lints warn #![warn(unused)] #![deny(warnings)] -// compile-pass -// skip-codegen -use std::option; //~ WARN +use std::option; //~ WARN fn main() {} - diff --git a/src/test/ui/bad/bad-lint-cap3.stderr b/src/test/ui/bad/bad-lint-cap3.stderr index 5bf0b089afa20..b898d792f65ca 100644 --- a/src/test/ui/bad/bad-lint-cap3.stderr +++ b/src/test/ui/bad/bad-lint-cap3.stderr @@ -1,11 +1,11 @@ warning: unused import: `std::option` --> $DIR/bad-lint-cap3.rs:7:5 | -LL | use std::option; //~ WARN +LL | use std::option; | ^^^^^^^^^^^ | note: lint level defined here - --> $DIR/bad-lint-cap3.rs:4:9 + --> $DIR/bad-lint-cap3.rs:5:9 | LL | #![deny(warnings)] | ^^^^^^^^ diff --git a/src/test/ui/bad/bad-main.stderr b/src/test/ui/bad/bad-main.stderr index 1a9c11f7b42af..c7f15e7a4fa50 100644 --- a/src/test/ui/bad/bad-main.stderr +++ b/src/test/ui/bad/bad-main.stderr @@ -1,7 +1,7 @@ error[E0580]: main function has wrong type --> $DIR/bad-main.rs:1:1 | -LL | fn main(x: isize) { } //~ ERROR: main function has wrong type [E0580] +LL | fn main(x: isize) { } | ^^^^^^^^^^^^^^^^^ incorrect number of function parameters | = note: expected type `fn()` diff --git a/src/test/ui/bad/bad-method-typaram-kind.stderr b/src/test/ui/bad/bad-method-typaram-kind.stderr index 8232bdd23a643..c72b965236006 100644 --- a/src/test/ui/bad/bad-method-typaram-kind.stderr +++ b/src/test/ui/bad/bad-method-typaram-kind.stderr @@ -1,7 +1,7 @@ error[E0277]: `T` cannot be sent between threads safely --> $DIR/bad-method-typaram-kind.rs:2:7 | -LL | 1.bar::(); //~ ERROR `T` cannot be sent between threads safely +LL | 1.bar::(); | ^^^ `T` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `T` diff --git a/src/test/ui/bad/bad-sized.rs b/src/test/ui/bad/bad-sized.rs index 0da4e456f088d..b899c59ff2ea7 100644 --- a/src/test/ui/bad/bad-sized.rs +++ b/src/test/ui/bad/bad-sized.rs @@ -1,7 +1,7 @@ trait Trait {} pub fn main() { - let x: Vec = Vec::new(); + let x: Vec = Vec::new(); //~^ ERROR only auto traits can be used as additional traits in a trait object //~| ERROR the size for values of type //~| ERROR the size for values of type diff --git a/src/test/ui/bad/bad-sized.stderr b/src/test/ui/bad/bad-sized.stderr index 9565888dcc022..e9ded557281a4 100644 --- a/src/test/ui/bad/bad-sized.stderr +++ b/src/test/ui/bad/bad-sized.stderr @@ -1,30 +1,35 @@ error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/bad-sized.rs:4:24 + --> $DIR/bad-sized.rs:4:28 | -LL | let x: Vec = Vec::new(); - | ^^^^^ non-auto additional trait +LL | let x: Vec = Vec::new(); + | ----- ^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time --> $DIR/bad-sized.rs:4:12 | -LL | let x: Vec = Vec::new(); - | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time +LL | let x: Vec = Vec::new(); + | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn Trait` = note: to learn more, visit = note: required by `std::vec::Vec` error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time - --> $DIR/bad-sized.rs:4:33 + --> $DIR/bad-sized.rs:4:37 | -LL | let x: Vec = Vec::new(); - | ^^^^^^^^ doesn't have a size known at compile-time +LL | let x: Vec = Vec::new(); + | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn Trait` = note: to learn more, visit - = note: required by `>::new` + = note: required by `std::vec::Vec::::new` error: aborting due to 3 previous errors -Some errors occurred: E0225, E0277. +Some errors have detailed explanations: E0225, E0277. For more information about an error, try `rustc --explain E0225`. diff --git a/src/test/ui/bad/bad-type-env-capture.stderr b/src/test/ui/bad/bad-type-env-capture.stderr index ce803e96801f9..6f24c0d86997e 100644 --- a/src/test/ui/bad/bad-type-env-capture.stderr +++ b/src/test/ui/bad/bad-type-env-capture.stderr @@ -2,8 +2,8 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/bad-type-env-capture.rs:2:15 | LL | fn foo() { - | - type variable from outer function -LL | fn bar(b: T) { } //~ ERROR can't use generic parameters from outer + | - type parameter from outer function +LL | fn bar(b: T) { } | --- ^ use of generic parameter from outer function | | | help: try using a local generic parameter instead: `bar` diff --git a/src/test/ui/binary-op-on-double-ref.stderr b/src/test/ui/binary-op-on-double-ref.stderr index f298902e3ff12..d036f06a8c7d0 100644 --- a/src/test/ui/binary-op-on-double-ref.stderr +++ b/src/test/ui/binary-op-on-double-ref.stderr @@ -1,8 +1,10 @@ error[E0369]: binary operation `%` cannot be applied to type `&&{integer}` - --> $DIR/binary-op-on-double-ref.rs:4:9 + --> $DIR/binary-op-on-double-ref.rs:4:11 | LL | x % 2 == 0 - | ^^^^^ + | - ^ - {integer} + | | + | &&{integer} | = help: `%` can be used on '{integer}', you can dereference `x`: `*x` diff --git a/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-2.stderr b/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-2.stderr index 427b1a722d994..9157fe0b070d0 100644 --- a/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-2.stderr +++ b/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-2.stderr @@ -1,7 +1,7 @@ error[E0009]: cannot bind by-move and by-ref in the same pattern --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-2.rs:12:23 | -LL | Some((ref _y, _z)) => { }, //~ ERROR cannot bind by-move and by-ref in the same pattern +LL | Some((ref _y, _z)) => { }, | ------ ^^ by-move pattern here | | | both by-ref and by-move used diff --git a/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-4.stderr b/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-4.stderr index 9ebbedcfe6009..267a9dff926a2 100644 --- a/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-4.stderr +++ b/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-4.stderr @@ -1,7 +1,7 @@ error[E0009]: cannot bind by-move and by-ref in the same pattern --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-4.rs:12:15 | -LL | Some((_y, ref _z)) => { }, //~ ERROR cannot bind by-move and by-ref in the same pattern +LL | Some((_y, ref _z)) => { }, | ^^ ------ both by-ref and by-move used | | | by-move pattern here diff --git a/src/test/ui/bind-by-move/bind-by-move-no-guards.nll.stderr b/src/test/ui/bind-by-move/bind-by-move-no-guards.nll.stderr deleted file mode 100644 index 5f8b7007f304c..0000000000000 --- a/src/test/ui/bind-by-move/bind-by-move-no-guards.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0008]: cannot bind by-move into a pattern guard - --> $DIR/bind-by-move-no-guards.rs:8:14 - | -LL | Some(z) if z.recv().unwrap() => { panic!() }, - | ^ moves value into pattern guard - | - = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0008`. diff --git a/src/test/ui/bind-by-move/bind-by-move-no-guards.stderr b/src/test/ui/bind-by-move/bind-by-move-no-guards.stderr index 2af2b0d660efa..5f8b7007f304c 100644 --- a/src/test/ui/bind-by-move/bind-by-move-no-guards.stderr +++ b/src/test/ui/bind-by-move/bind-by-move-no-guards.stderr @@ -3,6 +3,8 @@ error[E0008]: cannot bind by-move into a pattern guard | LL | Some(z) if z.recv().unwrap() => { panic!() }, | ^ moves value into pattern guard + | + = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/binop/binop-bitxor-str.stderr b/src/test/ui/binop/binop-bitxor-str.stderr index 4404fde9200c8..9e8992235edd1 100644 --- a/src/test/ui/binop/binop-bitxor-str.stderr +++ b/src/test/ui/binop/binop-bitxor-str.stderr @@ -1,8 +1,10 @@ error[E0369]: binary operation `^` cannot be applied to type `std::string::String` - --> $DIR/binop-bitxor-str.rs:3:21 + --> $DIR/binop-bitxor-str.rs:3:37 | LL | fn main() { let x = "a".to_string() ^ "b".to_string(); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | --------------- ^ --------------- std::string::String + | | + | std::string::String | = note: an implementation of `std::ops::BitXor` might be missing for `std::string::String` diff --git a/src/test/ui/binop/binop-consume-args.nll.stderr b/src/test/ui/binop/binop-consume-args.nll.stderr deleted file mode 100644 index 59b5aba93cad4..0000000000000 --- a/src/test/ui/binop/binop-consume-args.nll.stderr +++ /dev/null @@ -1,253 +0,0 @@ -error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:7:10 - | -LL | fn add, B>(lhs: A, rhs: B) { - | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs + rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:8:10 - | -LL | fn add, B>(lhs: A, rhs: B) { - | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs + rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:13:10 - | -LL | fn sub, B>(lhs: A, rhs: B) { - | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs - rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:14:10 - | -LL | fn sub, B>(lhs: A, rhs: B) { - | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs - rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:19:10 - | -LL | fn mul, B>(lhs: A, rhs: B) { - | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs * rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:20:10 - | -LL | fn mul, B>(lhs: A, rhs: B) { - | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs * rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:25:10 - | -LL | fn div, B>(lhs: A, rhs: B) { - | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs / rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:26:10 - | -LL | fn div, B>(lhs: A, rhs: B) { - | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs / rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:31:10 - | -LL | fn rem, B>(lhs: A, rhs: B) { - | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs % rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:32:10 - | -LL | fn rem, B>(lhs: A, rhs: B) { - | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs % rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:37:10 - | -LL | fn bitand, B>(lhs: A, rhs: B) { - | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs & rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:38:10 - | -LL | fn bitand, B>(lhs: A, rhs: B) { - | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs & rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:43:10 - | -LL | fn bitor, B>(lhs: A, rhs: B) { - | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs | rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:44:10 - | -LL | fn bitor, B>(lhs: A, rhs: B) { - | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs | rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:49:10 - | -LL | fn bitxor, B>(lhs: A, rhs: B) { - | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs ^ rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:50:10 - | -LL | fn bitxor, B>(lhs: A, rhs: B) { - | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs ^ rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:55:10 - | -LL | fn shl, B>(lhs: A, rhs: B) { - | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs << rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:56:10 - | -LL | fn shl, B>(lhs: A, rhs: B) { - | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs << rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `lhs` - --> $DIR/binop-consume-args.rs:61:10 - | -LL | fn shr, B>(lhs: A, rhs: B) { - | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs >> rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` - | ^^^ value used here after move - -error[E0382]: use of moved value: `rhs` - --> $DIR/binop-consume-args.rs:62:10 - | -LL | fn shr, B>(lhs: A, rhs: B) { - | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | lhs >> rhs; - | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` - | ^^^ value used here after move - -error: aborting due to 20 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/binop/binop-consume-args.stderr b/src/test/ui/binop/binop-consume-args.stderr index 0b5d2200b9ffc..5751af27fcb42 100644 --- a/src/test/ui/binop/binop-consume-args.stderr +++ b/src/test/ui/binop/binop-consume-args.stderr @@ -1,212 +1,252 @@ error[E0382]: use of moved value: `lhs` --> $DIR/binop-consume-args.rs:7:10 | +LL | fn add, B>(lhs: A, rhs: B) { + | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs + rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` +LL | drop(lhs); | ^^^ value used here after move - | - = note: move occurs because `lhs` has type `A`, which does not implement the `Copy` trait error[E0382]: use of moved value: `rhs` --> $DIR/binop-consume-args.rs:8:10 | +LL | fn add, B>(lhs: A, rhs: B) { + | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs + rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` +LL | drop(lhs); +LL | drop(rhs); | ^^^ value used here after move - | - = note: move occurs because `rhs` has type `B`, which does not implement the `Copy` trait error[E0382]: use of moved value: `lhs` --> $DIR/binop-consume-args.rs:13:10 | +LL | fn sub, B>(lhs: A, rhs: B) { + | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs - rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` +LL | drop(lhs); | ^^^ value used here after move - | - = note: move occurs because `lhs` has type `A`, which does not implement the `Copy` trait error[E0382]: use of moved value: `rhs` --> $DIR/binop-consume-args.rs:14:10 | +LL | fn sub, B>(lhs: A, rhs: B) { + | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs - rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` +LL | drop(lhs); +LL | drop(rhs); | ^^^ value used here after move - | - = note: move occurs because `rhs` has type `B`, which does not implement the `Copy` trait error[E0382]: use of moved value: `lhs` --> $DIR/binop-consume-args.rs:19:10 | +LL | fn mul, B>(lhs: A, rhs: B) { + | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs * rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` +LL | drop(lhs); | ^^^ value used here after move - | - = note: move occurs because `lhs` has type `A`, which does not implement the `Copy` trait error[E0382]: use of moved value: `rhs` --> $DIR/binop-consume-args.rs:20:10 | +LL | fn mul, B>(lhs: A, rhs: B) { + | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs * rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` +LL | drop(lhs); +LL | drop(rhs); | ^^^ value used here after move - | - = note: move occurs because `rhs` has type `B`, which does not implement the `Copy` trait error[E0382]: use of moved value: `lhs` --> $DIR/binop-consume-args.rs:25:10 | +LL | fn div, B>(lhs: A, rhs: B) { + | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs / rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` +LL | drop(lhs); | ^^^ value used here after move - | - = note: move occurs because `lhs` has type `A`, which does not implement the `Copy` trait error[E0382]: use of moved value: `rhs` --> $DIR/binop-consume-args.rs:26:10 | +LL | fn div, B>(lhs: A, rhs: B) { + | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs / rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` +LL | drop(lhs); +LL | drop(rhs); | ^^^ value used here after move - | - = note: move occurs because `rhs` has type `B`, which does not implement the `Copy` trait error[E0382]: use of moved value: `lhs` --> $DIR/binop-consume-args.rs:31:10 | +LL | fn rem, B>(lhs: A, rhs: B) { + | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs % rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` +LL | drop(lhs); | ^^^ value used here after move - | - = note: move occurs because `lhs` has type `A`, which does not implement the `Copy` trait error[E0382]: use of moved value: `rhs` --> $DIR/binop-consume-args.rs:32:10 | +LL | fn rem, B>(lhs: A, rhs: B) { + | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs % rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` +LL | drop(lhs); +LL | drop(rhs); | ^^^ value used here after move - | - = note: move occurs because `rhs` has type `B`, which does not implement the `Copy` trait error[E0382]: use of moved value: `lhs` --> $DIR/binop-consume-args.rs:37:10 | +LL | fn bitand, B>(lhs: A, rhs: B) { + | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs & rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` +LL | drop(lhs); | ^^^ value used here after move - | - = note: move occurs because `lhs` has type `A`, which does not implement the `Copy` trait error[E0382]: use of moved value: `rhs` --> $DIR/binop-consume-args.rs:38:10 | +LL | fn bitand, B>(lhs: A, rhs: B) { + | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs & rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` +LL | drop(lhs); +LL | drop(rhs); | ^^^ value used here after move - | - = note: move occurs because `rhs` has type `B`, which does not implement the `Copy` trait error[E0382]: use of moved value: `lhs` --> $DIR/binop-consume-args.rs:43:10 | +LL | fn bitor, B>(lhs: A, rhs: B) { + | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs | rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` +LL | drop(lhs); | ^^^ value used here after move - | - = note: move occurs because `lhs` has type `A`, which does not implement the `Copy` trait error[E0382]: use of moved value: `rhs` --> $DIR/binop-consume-args.rs:44:10 | +LL | fn bitor, B>(lhs: A, rhs: B) { + | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs | rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` +LL | drop(lhs); +LL | drop(rhs); | ^^^ value used here after move - | - = note: move occurs because `rhs` has type `B`, which does not implement the `Copy` trait error[E0382]: use of moved value: `lhs` --> $DIR/binop-consume-args.rs:49:10 | +LL | fn bitxor, B>(lhs: A, rhs: B) { + | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs ^ rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` +LL | drop(lhs); | ^^^ value used here after move - | - = note: move occurs because `lhs` has type `A`, which does not implement the `Copy` trait error[E0382]: use of moved value: `rhs` --> $DIR/binop-consume-args.rs:50:10 | +LL | fn bitxor, B>(lhs: A, rhs: B) { + | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs ^ rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` +LL | drop(lhs); +LL | drop(rhs); | ^^^ value used here after move - | - = note: move occurs because `rhs` has type `B`, which does not implement the `Copy` trait error[E0382]: use of moved value: `lhs` --> $DIR/binop-consume-args.rs:55:10 | +LL | fn shl, B>(lhs: A, rhs: B) { + | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs << rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` +LL | drop(lhs); | ^^^ value used here after move - | - = note: move occurs because `lhs` has type `A`, which does not implement the `Copy` trait error[E0382]: use of moved value: `rhs` --> $DIR/binop-consume-args.rs:56:10 | +LL | fn shl, B>(lhs: A, rhs: B) { + | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs << rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` +LL | drop(lhs); +LL | drop(rhs); | ^^^ value used here after move - | - = note: move occurs because `rhs` has type `B`, which does not implement the `Copy` trait error[E0382]: use of moved value: `lhs` --> $DIR/binop-consume-args.rs:61:10 | +LL | fn shr, B>(lhs: A, rhs: B) { + | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs >> rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` +LL | drop(lhs); | ^^^ value used here after move - | - = note: move occurs because `lhs` has type `A`, which does not implement the `Copy` trait error[E0382]: use of moved value: `rhs` --> $DIR/binop-consume-args.rs:62:10 | +LL | fn shr, B>(lhs: A, rhs: B) { + | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | lhs >> rhs; | --- value moved here -LL | drop(lhs); //~ ERROR use of moved value: `lhs` -LL | drop(rhs); //~ ERROR use of moved value: `rhs` +LL | drop(lhs); +LL | drop(rhs); | ^^^ value used here after move - | - = note: move occurs because `rhs` has type `B`, which does not implement the `Copy` trait error: aborting due to 20 previous errors diff --git a/src/test/ui/binop/binop-logic-float.rs b/src/test/ui/binop/binop-logic-float.rs index c95c1d30d1ce3..1750d97ba815a 100644 --- a/src/test/ui/binop/binop-logic-float.rs +++ b/src/test/ui/binop/binop-logic-float.rs @@ -1,4 +1,3 @@ fn main() { let x = 1.0_f32 || 2.0_f32; } //~^ ERROR mismatched types //~| ERROR mismatched types - diff --git a/src/test/ui/binop/binop-move-semantics.nll.stderr b/src/test/ui/binop/binop-move-semantics.nll.stderr deleted file mode 100644 index 7c84e8833a9e6..0000000000000 --- a/src/test/ui/binop/binop-move-semantics.nll.stderr +++ /dev/null @@ -1,95 +0,0 @@ -error[E0382]: use of moved value: `x` - --> $DIR/binop-move-semantics.rs:8:5 - | -LL | fn double_move>(x: T) { - | - - move occurs because `x` has type `T`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | x - | - value moved here -LL | + -LL | x; //~ ERROR: use of moved value - | ^ value used here after move - -error[E0382]: borrow of moved value: `x` - --> $DIR/binop-move-semantics.rs:14:5 - | -LL | fn move_then_borrow + Clone>(x: T) { - | - - move occurs because `x` has type `T`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | x - | - value moved here -LL | + -LL | x.clone(); //~ ERROR: use of moved value - | ^ value borrowed here after move - -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/binop-move-semantics.rs:21:5 - | -LL | let m = &x; - | -- borrow of `x` occurs here -... -LL | x //~ ERROR: cannot move out of `x` because it is borrowed - | ^ move out of `x` occurs here -... -LL | use_mut(n); use_imm(m); - | - borrow later used here - -error[E0505]: cannot move out of `y` because it is borrowed - --> $DIR/binop-move-semantics.rs:23:5 - | -LL | let n = &mut y; - | ------ borrow of `y` occurs here -... -LL | y; //~ ERROR: cannot move out of `y` because it is borrowed - | ^ move out of `y` occurs here -LL | use_mut(n); use_imm(m); - | - borrow later used here - -error[E0507]: cannot move out of borrowed content - --> $DIR/binop-move-semantics.rs:30:5 - | -LL | *m //~ ERROR: cannot move out of borrowed content - | ^^ cannot move out of borrowed content - -error[E0507]: cannot move out of borrowed content - --> $DIR/binop-move-semantics.rs:32:5 - | -LL | *n; //~ ERROR: cannot move out of borrowed content - | ^^ cannot move out of borrowed content - -error[E0502]: cannot borrow `f` as immutable because it is also borrowed as mutable - --> $DIR/binop-move-semantics.rs:54:5 - | -LL | &mut f - | ------ - | | - | _____mutable borrow occurs here - | | -LL | | + -LL | | &f; //~ ERROR: cannot borrow `f` as immutable because it is also borrowed as mutable - | | ^- - | |_____|| - | |mutable borrow later used here - | immutable borrow occurs here - -error[E0502]: cannot borrow `f` as mutable because it is also borrowed as immutable - --> $DIR/binop-move-semantics.rs:62:5 - | -LL | &f - | -- - | | - | _____immutable borrow occurs here - | | -LL | | + -LL | | &mut f; //~ ERROR: cannot borrow `f` as mutable because it is also borrowed as immutable - | | ^^^^^- - | |_____|____| - | | immutable borrow later used here - | mutable borrow occurs here - -error: aborting due to 8 previous errors - -Some errors occurred: E0382, E0502, E0505, E0507. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/binop/binop-move-semantics.rs b/src/test/ui/binop/binop-move-semantics.rs index 2bcf16f8ba88c..b5133ea7c92a0 100644 --- a/src/test/ui/binop/binop-move-semantics.rs +++ b/src/test/ui/binop/binop-move-semantics.rs @@ -11,7 +11,7 @@ fn double_move>(x: T) { fn move_then_borrow + Clone>(x: T) { x + - x.clone(); //~ ERROR: use of moved value + x.clone(); //~ ERROR: borrow of moved value } fn move_borrowed>(x: T, mut y: T) { @@ -27,9 +27,9 @@ fn illegal_dereference>(mut x: T, y: T) { let m = &mut x; let n = &y; - *m //~ ERROR: cannot move out of borrowed content + *m //~ ERROR: cannot move + - *n; //~ ERROR: cannot move out of borrowed content + *n; //~ ERROR: cannot move use_imm(n); use_mut(m); } struct Foo; diff --git a/src/test/ui/binop/binop-move-semantics.stderr b/src/test/ui/binop/binop-move-semantics.stderr index b1dc70d379d40..897607dc2d8d5 100644 --- a/src/test/ui/binop/binop-move-semantics.stderr +++ b/src/test/ui/binop/binop-move-semantics.stderr @@ -1,80 +1,95 @@ error[E0382]: use of moved value: `x` --> $DIR/binop-move-semantics.rs:8:5 | +LL | fn double_move>(x: T) { + | - - move occurs because `x` has type `T`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | x | - value moved here LL | + -LL | x; //~ ERROR: use of moved value +LL | x; | ^ value used here after move - | - = note: move occurs because `x` has type `T`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `x` +error[E0382]: borrow of moved value: `x` --> $DIR/binop-move-semantics.rs:14:5 | +LL | fn move_then_borrow + Clone>(x: T) { + | - - move occurs because `x` has type `T`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | x | - value moved here LL | + -LL | x.clone(); //~ ERROR: use of moved value - | ^ value used here after move - | - = note: move occurs because `x` has type `T`, which does not implement the `Copy` trait +LL | x.clone(); + | ^ value borrowed here after move error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/binop-move-semantics.rs:21:5 | LL | let m = &x; - | - borrow of `x` occurs here + | -- borrow of `x` occurs here ... -LL | x //~ ERROR: cannot move out of `x` because it is borrowed +LL | x | ^ move out of `x` occurs here +... +LL | use_mut(n); use_imm(m); + | - borrow later used here error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/binop-move-semantics.rs:23:5 | LL | let n = &mut y; - | - borrow of `y` occurs here + | ------ borrow of `y` occurs here ... -LL | y; //~ ERROR: cannot move out of `y` because it is borrowed +LL | y; | ^ move out of `y` occurs here +LL | use_mut(n); use_imm(m); + | - borrow later used here -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `*m` which is behind a mutable reference --> $DIR/binop-move-semantics.rs:30:5 | -LL | *m //~ ERROR: cannot move out of borrowed content - | ^^ cannot move out of borrowed content +LL | *m + | ^^ move occurs because `*m` has type `T`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `*n` which is behind a shared reference --> $DIR/binop-move-semantics.rs:32:5 | -LL | *n; //~ ERROR: cannot move out of borrowed content - | ^^ cannot move out of borrowed content +LL | *n; + | ^^ move occurs because `*n` has type `T`, which does not implement the `Copy` trait error[E0502]: cannot borrow `f` as immutable because it is also borrowed as mutable - --> $DIR/binop-move-semantics.rs:54:6 + --> $DIR/binop-move-semantics.rs:54:5 | -LL | &mut f - | - mutable borrow occurs here -LL | + -LL | &f; //~ ERROR: cannot borrow `f` as immutable because it is also borrowed as mutable - | ^ - | | - | immutable borrow occurs here - | mutable borrow ends here +LL | &mut f + | ------ + | | + | _____mutable borrow occurs here + | | +LL | | + +LL | | &f; + | | ^- + | |_____|| + | |mutable borrow later used here + | immutable borrow occurs here error[E0502]: cannot borrow `f` as mutable because it is also borrowed as immutable - --> $DIR/binop-move-semantics.rs:62:10 + --> $DIR/binop-move-semantics.rs:62:5 | -LL | &f - | - immutable borrow occurs here -LL | + -LL | &mut f; //~ ERROR: cannot borrow `f` as mutable because it is also borrowed as immutable - | ^ - | | - | mutable borrow occurs here - | immutable borrow ends here +LL | &f + | -- + | | + | _____immutable borrow occurs here + | | +LL | | + +LL | | &mut f; + | | ^^^^^- + | |_____|____| + | | immutable borrow later used here + | mutable borrow occurs here error: aborting due to 8 previous errors -Some errors occurred: E0382, E0502, E0505, E0507. +Some errors have detailed explanations: E0382, E0502, E0505, E0507. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/binop/binop-mul-bool.stderr b/src/test/ui/binop/binop-mul-bool.stderr index 194181b9c11c3..92e14bccccd58 100644 --- a/src/test/ui/binop/binop-mul-bool.stderr +++ b/src/test/ui/binop/binop-mul-bool.stderr @@ -1,8 +1,10 @@ error[E0369]: binary operation `*` cannot be applied to type `bool` - --> $DIR/binop-mul-bool.rs:3:21 + --> $DIR/binop-mul-bool.rs:3:26 | LL | fn main() { let x = true * false; } - | ^^^^^^^^^^^^ + | ---- ^ ----- bool + | | + | bool | = note: an implementation of `std::ops::Mul` might be missing for `bool` diff --git a/src/test/ui/binop/binop-typeck.stderr b/src/test/ui/binop/binop-typeck.stderr index 928e836c0b51e..d33cff313e7f9 100644 --- a/src/test/ui/binop/binop-typeck.stderr +++ b/src/test/ui/binop/binop-typeck.stderr @@ -1,8 +1,10 @@ error[E0369]: binary operation `+` cannot be applied to type `bool` - --> $DIR/binop-typeck.rs:6:13 + --> $DIR/binop-typeck.rs:6:15 | LL | let z = x + y; - | ^^^^^ + | - ^ - {integer} + | | + | bool | = note: an implementation of `std::ops::Add` might be missing for `bool` diff --git a/src/test/ui/block-expression-remove-semicolon.rs b/src/test/ui/block-expression-remove-semicolon.rs new file mode 100644 index 0000000000000..afa10b38b9144 --- /dev/null +++ b/src/test/ui/block-expression-remove-semicolon.rs @@ -0,0 +1,10 @@ +fn foo() -> i32 { + 0 +} + +fn main() { + let x: i32 = { + //~^ ERROR mismatched types + foo(); //~ HELP consider removing this semicolon + }; +} diff --git a/src/test/ui/block-expression-remove-semicolon.stderr b/src/test/ui/block-expression-remove-semicolon.stderr new file mode 100644 index 0000000000000..51942f3d920f5 --- /dev/null +++ b/src/test/ui/block-expression-remove-semicolon.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/block-expression-remove-semicolon.rs:6:18 + | +LL | let x: i32 = { + | __________________^ +LL | | +LL | | foo(); + | | - help: consider removing this semicolon +LL | | }; + | |_____^ expected i32, found () + | + = note: expected type `i32` + found type `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/block-result/block-must-not-have-result-do.stderr b/src/test/ui/block-result/block-must-not-have-result-do.stderr index 151315d34f27c..5981b8b60794c 100644 --- a/src/test/ui/block-result/block-must-not-have-result-do.stderr +++ b/src/test/ui/block-result/block-must-not-have-result-do.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/block-must-not-have-result-do.rs:3:9 | -LL | true //~ ERROR mismatched types +LL | true | ^^^^ expected (), found bool | = note: expected type `()` diff --git a/src/test/ui/block-result/block-must-not-have-result-res.stderr b/src/test/ui/block-result/block-must-not-have-result-res.stderr index 29885cac234fb..8a41f8b8e3dff 100644 --- a/src/test/ui/block-result/block-must-not-have-result-res.stderr +++ b/src/test/ui/block-result/block-must-not-have-result-res.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | fn drop(&mut self) { | - expected `()` because of default return type -LL | true //~ ERROR mismatched types +LL | true | ^^^^ expected (), found bool | = note: expected type `()` diff --git a/src/test/ui/block-result/block-must-not-have-result-while.stderr b/src/test/ui/block-result/block-must-not-have-result-while.stderr index d41eae1a43299..302d2972f7de1 100644 --- a/src/test/ui/block-result/block-must-not-have-result-while.stderr +++ b/src/test/ui/block-result/block-must-not-have-result-while.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/block-must-not-have-result-while.rs:3:9 | -LL | true //~ ERROR mismatched types +LL | true | ^^^^ expected (), found bool | = note: expected type `()` diff --git a/src/test/ui/block-result/consider-removing-last-semi.stderr b/src/test/ui/block-result/consider-removing-last-semi.stderr index 1bf17db21ac5a..618d020ce08b5 100644 --- a/src/test/ui/block-result/consider-removing-last-semi.stderr +++ b/src/test/ui/block-result/consider-removing-last-semi.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/consider-removing-last-semi.rs:1:11 | -LL | fn f() -> String { //~ ERROR mismatched types +LL | fn f() -> String { | - ^^^^^^ expected struct `std::string::String`, found () | | | this function's body doesn't return @@ -15,7 +15,7 @@ LL | "bla".to_string(); error[E0308]: mismatched types --> $DIR/consider-removing-last-semi.rs:6:11 | -LL | fn g() -> String { //~ ERROR mismatched types +LL | fn g() -> String { | - ^^^^^^ expected struct `std::string::String`, found () | | | this function's body doesn't return diff --git a/src/test/ui/block-result/issue-11714.stderr b/src/test/ui/block-result/issue-11714.stderr index 2c13b28766943..d73489a602df4 100644 --- a/src/test/ui/block-result/issue-11714.stderr +++ b/src/test/ui/block-result/issue-11714.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-11714.rs:1:14 | -LL | fn blah() -> i32 { //~ ERROR mismatched types +LL | fn blah() -> i32 { | ---- ^^^ expected i32, found () | | | this function's body doesn't return diff --git a/src/test/ui/block-result/issue-13428.stderr b/src/test/ui/block-result/issue-13428.stderr index 91e926eb5a73b..18adb15c9615d 100644 --- a/src/test/ui/block-result/issue-13428.stderr +++ b/src/test/ui/block-result/issue-13428.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-13428.rs:3:13 | -LL | fn foo() -> String { //~ ERROR mismatched types +LL | fn foo() -> String { | --- ^^^^^^ expected struct `std::string::String`, found () | | | this function's body doesn't return @@ -15,7 +15,7 @@ LL | ; error[E0308]: mismatched types --> $DIR/issue-13428.rs:11:13 | -LL | fn bar() -> String { //~ ERROR mismatched types +LL | fn bar() -> String { | --- ^^^^^^ expected struct `std::string::String`, found () | | | this function's body doesn't return diff --git a/src/test/ui/block-result/issue-20862.stderr b/src/test/ui/block-result/issue-20862.stderr index fce06f5b45d2c..6dc17815facd5 100644 --- a/src/test/ui/block-result/issue-20862.stderr +++ b/src/test/ui/block-result/issue-20862.stderr @@ -14,7 +14,7 @@ error[E0618]: expected function, found `()` | LL | / fn foo(x: i32) { LL | | |y| x + y -LL | | //~^ ERROR: mismatched types +LL | | LL | | } | |_- `foo` defined here returns `()` ... @@ -25,5 +25,5 @@ LL | let x = foo(5)(2); error: aborting due to 2 previous errors -Some errors occurred: E0308, E0618. +Some errors have detailed explanations: E0308, E0618. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/block-result/issue-22645.stderr b/src/test/ui/block-result/issue-22645.stderr index 9cb1a6c5d7d52..d2ec0dc06bd80 100644 --- a/src/test/ui/block-result/issue-22645.stderr +++ b/src/test/ui/block-result/issue-22645.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `{integer}: Scalar` is not satisfied --> $DIR/issue-22645.rs:15:5 | -LL | b + 3 //~ ERROR E0277 +LL | b + 3 | ^ the trait `Scalar` is not implemented for `{integer}` | = help: the following implementations were found: @@ -14,7 +14,7 @@ error[E0308]: mismatched types LL | fn main() { | - expected `()` because of default return type LL | let b = Bob + 3.5; -LL | b + 3 //~ ERROR E0277 +LL | b + 3 | ^^^^^ expected (), found struct `Bob` | = note: expected type `()` @@ -22,5 +22,5 @@ LL | b + 3 //~ ERROR E0277 error: aborting due to 2 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/block-result/issue-3563.stderr b/src/test/ui/block-result/issue-3563.stderr index a6346a5233f4c..237b8c54ce301 100644 --- a/src/test/ui/block-result/issue-3563.stderr +++ b/src/test/ui/block-result/issue-3563.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `b` found for type `&Self` in the current scope --> $DIR/issue-3563.rs:3:17 | LL | || self.b() - | ^ help: did you mean: `a` + | ^ help: there is a method with a similar name: `a` error: aborting due to previous error diff --git a/src/test/ui/block-result/issue-5500.stderr b/src/test/ui/block-result/issue-5500.stderr index 0d9c9d8143d31..6a13b31fe932f 100644 --- a/src/test/ui/block-result/issue-5500.stderr +++ b/src/test/ui/block-result/issue-5500.stderr @@ -4,7 +4,10 @@ error[E0308]: mismatched types LL | fn main() { | - expected `()` because of default return type LL | &panic!() - | ^^^^^^^^^ expected (), found reference + | ^^^^^^^^^ + | | + | expected (), found reference + | help: consider removing the borrow: `panic!()` | = note: expected type `()` found type `&_` diff --git a/src/test/ui/block-result/unexpected-return-on-unit.stderr b/src/test/ui/block-result/unexpected-return-on-unit.stderr index 50af4734202dd..3ceff81ec4d63 100644 --- a/src/test/ui/block-result/unexpected-return-on-unit.stderr +++ b/src/test/ui/block-result/unexpected-return-on-unit.stderr @@ -1,14 +1,14 @@ error[E0308]: mismatched types --> $DIR/unexpected-return-on-unit.rs:9:5 | -LL | foo() //~ ERROR mismatched types +LL | foo() | ^^^^^ expected (), found usize | = note: expected type `()` found type `usize` help: try adding a semicolon | -LL | foo(); //~ ERROR mismatched types +LL | foo(); | ^ help: try adding a return type | diff --git a/src/test/ui/bogus-tag.stderr b/src/test/ui/bogus-tag.stderr index 3750df841720c..890f6800c22af 100644 --- a/src/test/ui/bogus-tag.stderr +++ b/src/test/ui/bogus-tag.stderr @@ -1,11 +1,11 @@ -error[E0599]: no variant named `Hsl` found for type `Color` in the current scope +error[E0599]: no variant or associated item named `Hsl` found for type `Color` in the current scope --> $DIR/bogus-tag.rs:7:16 | LL | enum Color { Rgb(isize, isize, isize), Rgba(isize, isize, isize, isize), } - | ---------- variant `Hsl` not found here + | ---------- variant or associated item `Hsl` not found here ... LL | Color::Hsl(h, s, l) => { println!("hsl"); } - | -------^^^--------- variant not found in `Color` + | ^^^ variant or associated item not found in `Color` error: aborting due to previous error diff --git a/src/test/ui/borrowck/assign_mutable_fields.nll.stderr b/src/test/ui/borrowck/assign_mutable_fields.nll.stderr deleted file mode 100644 index 35101df4e0a6e..0000000000000 --- a/src/test/ui/borrowck/assign_mutable_fields.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0381]: assign to part of possibly uninitialized variable: `x` - --> $DIR/assign_mutable_fields.rs:9:5 - | -LL | x.0 = 1; - | ^^^^^^^ use of possibly uninitialized `x` - -error[E0381]: assign to part of possibly uninitialized variable: `x` - --> $DIR/assign_mutable_fields.rs:17:5 - | -LL | x.0 = 1; - | ^^^^^^^ use of possibly uninitialized `x` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/assign_mutable_fields.rs b/src/test/ui/borrowck/assign_mutable_fields.rs index 85d6f3b74c02f..b60726d0c8b38 100644 --- a/src/test/ui/borrowck/assign_mutable_fields.rs +++ b/src/test/ui/borrowck/assign_mutable_fields.rs @@ -1,22 +1,22 @@ -// Currently, we permit you to assign to individual fields of a mut -// var, but we do not permit you to use the complete var afterwards. +// Currently, we do permit you to assign to individual fields of an +// uninitialized var. // We hope to fix this at some point. // // FIXME(#54987) fn assign_both_fields_and_use() { let mut x: (u32, u32); - x.0 = 1; + x.0 = 1; //~ ERROR x.1 = 22; - drop(x.0); //~ ERROR - drop(x.1); //~ ERROR + drop(x.0); + drop(x.1); } fn assign_both_fields_the_use_var() { let mut x: (u32, u32); - x.0 = 1; + x.0 = 1; //~ ERROR x.1 = 22; - drop(x); //~ ERROR + drop(x); } fn main() { } diff --git a/src/test/ui/borrowck/assign_mutable_fields.stderr b/src/test/ui/borrowck/assign_mutable_fields.stderr index 9024e7cf01cb4..35101df4e0a6e 100644 --- a/src/test/ui/borrowck/assign_mutable_fields.stderr +++ b/src/test/ui/borrowck/assign_mutable_fields.stderr @@ -1,21 +1,15 @@ -error[E0381]: use of possibly uninitialized variable: `x.0` - --> $DIR/assign_mutable_fields.rs:11:10 +error[E0381]: assign to part of possibly uninitialized variable: `x` + --> $DIR/assign_mutable_fields.rs:9:5 | -LL | drop(x.0); //~ ERROR - | ^^^ use of possibly uninitialized `x.0` +LL | x.0 = 1; + | ^^^^^^^ use of possibly uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x.1` - --> $DIR/assign_mutable_fields.rs:12:10 +error[E0381]: assign to part of possibly uninitialized variable: `x` + --> $DIR/assign_mutable_fields.rs:17:5 | -LL | drop(x.1); //~ ERROR - | ^^^ use of possibly uninitialized `x.1` +LL | x.0 = 1; + | ^^^^^^^ use of possibly uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x` - --> $DIR/assign_mutable_fields.rs:19:10 - | -LL | drop(x); //~ ERROR - | ^ use of possibly uninitialized `x` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.nll.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.nll.stderr deleted file mode 100644 index 9174a6976113b..0000000000000 --- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.nll.stderr +++ /dev/null @@ -1,76 +0,0 @@ -error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:15:27 - | -LL | let _f = to_fn(|| x = 42); //~ ERROR cannot assign - | ^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-immutable-upvar-mutation.rs:15:24 - | -LL | let _f = to_fn(|| x = 42); //~ ERROR cannot assign - | ^^^^^^^^^ - -error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:18:31 - | -LL | let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow - | ^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-immutable-upvar-mutation.rs:18:24 - | -LL | let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow - | ^^^^^^^^^^^^^^ - -error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:21:55 - | -LL | let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); //~ ERROR cannot assign - | ^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-immutable-upvar-mutation.rs:21:52 - | -LL | let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); //~ ERROR cannot assign - | ^^^^^^^^^ - -error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:27:32 - | -LL | let _f = to_fn(move || x = 42); //~ ERROR cannot assign - | ^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-immutable-upvar-mutation.rs:27:24 - | -LL | let _f = to_fn(move || x = 42); //~ ERROR cannot assign - | ^^^^^^^^^^^^^^ - -error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:30:36 - | -LL | let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow - | ^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-immutable-upvar-mutation.rs:30:24 - | -LL | let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow - | ^^^^^^^^^^^^^^^^^^^ - -error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:33:65 - | -LL | let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign - | ^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/borrow-immutable-upvar-mutation.rs:33:57 - | -LL | let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign - | ^^^^^^^^^^^^^^ - -error: aborting due to 6 previous errors - -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr index 505604ab597d4..17969137a9881 100644 --- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr @@ -1,78 +1,75 @@ -error[E0387]: cannot assign to data in a captured outer variable in an `Fn` closure +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/borrow-immutable-upvar-mutation.rs:15:27 | -LL | let _f = to_fn(|| x = 42); //~ ERROR cannot assign - | ^^^^^^ +LL | let _f = to_fn(|| x = 42); + | ^^^^^^ cannot assign | -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/borrow-immutable-upvar-mutation.rs:15:24 | -LL | let _f = to_fn(|| x = 42); //~ ERROR cannot assign +LL | let _f = to_fn(|| x = 42); | ^^^^^^^^^ -error[E0387]: cannot borrow data mutably in a captured outer variable in an `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:18:36 +error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation.rs:18:31 | -LL | let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow - | ^ +LL | let _g = to_fn(|| set(&mut y)); + | ^^^^^^ cannot borrow as mutable | -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/borrow-immutable-upvar-mutation.rs:18:24 | -LL | let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow +LL | let _g = to_fn(|| set(&mut y)); | ^^^^^^^^^^^^^^ -error[E0387]: cannot assign to data in a captured outer variable in an `Fn` closure +error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure --> $DIR/borrow-immutable-upvar-mutation.rs:21:55 | -LL | let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); //~ ERROR cannot assign - | ^^^^^^ +LL | let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); + | ^^^^^^ cannot assign | -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/borrow-immutable-upvar-mutation.rs:21:52 | -LL | let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); //~ ERROR cannot assign +LL | let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); | ^^^^^^^^^ -error[E0594]: cannot assign to captured outer variable in an `Fn` closure +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/borrow-immutable-upvar-mutation.rs:27:32 | -LL | let _f = to_fn(move || x = 42); //~ ERROR cannot assign - | ^^^^^^ +LL | let _f = to_fn(move || x = 42); + | ^^^^^^ cannot assign | - = note: `Fn` closures cannot capture their enclosing environment for modifications -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/borrow-immutable-upvar-mutation.rs:27:24 | -LL | let _f = to_fn(move || x = 42); //~ ERROR cannot assign +LL | let _f = to_fn(move || x = 42); | ^^^^^^^^^^^^^^ -error[E0596]: cannot borrow captured outer variable in an `Fn` closure as mutable - --> $DIR/borrow-immutable-upvar-mutation.rs:30:41 +error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation.rs:30:36 | -LL | let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow - | ^ +LL | let _g = to_fn(move || set(&mut y)); + | ^^^^^^ cannot borrow as mutable | -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/borrow-immutable-upvar-mutation.rs:30:24 | -LL | let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow +LL | let _g = to_fn(move || set(&mut y)); | ^^^^^^^^^^^^^^^^^^^ -error[E0594]: cannot assign to captured outer variable in an `Fn` closure +error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure --> $DIR/borrow-immutable-upvar-mutation.rs:33:65 | -LL | let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign - | ^^^^^^ +LL | let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); + | ^^^^^^ cannot assign | - = note: `Fn` closures cannot capture their enclosing environment for modifications -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/borrow-immutable-upvar-mutation.rs:33:57 | -LL | let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign +LL | let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); | ^^^^^^^^^^^^^^ error: aborting due to 6 previous errors -Some errors occurred: E0387, E0594, E0596. -For more information about an error, try `rustc --explain E0387`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/borrow-tuple-fields.nll.stderr b/src/test/ui/borrowck/borrow-tuple-fields.nll.stderr deleted file mode 100644 index 72a29b864a4f1..0000000000000 --- a/src/test/ui/borrowck/borrow-tuple-fields.nll.stderr +++ /dev/null @@ -1,65 +0,0 @@ -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/borrow-tuple-fields.rs:12:13 - | -LL | let r = &x.0; - | ---- borrow of `x.0` occurs here -LL | let y = x; //~ ERROR cannot move out of `x` because it is borrowed - | ^ move out of `x` occurs here -LL | -LL | r.use_ref(); - | - borrow later used here - -error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable - --> $DIR/borrow-tuple-fields.rs:18:13 - | -LL | let a = &x.0; - | ---- immutable borrow occurs here -LL | let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as - | ^^^^^^^^ mutable borrow occurs here -LL | a.use_ref(); - | - immutable borrow later used here - -error[E0499]: cannot borrow `x.0` as mutable more than once at a time - --> $DIR/borrow-tuple-fields.rs:23:13 - | -LL | let a = &mut x.0; - | -------- first mutable borrow occurs here -LL | let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time - | ^^^^^^^^ second mutable borrow occurs here -LL | a.use_ref(); - | - first borrow later used here - -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/borrow-tuple-fields.rs:28:13 - | -LL | let r = &x.0; - | ---- borrow of `x.0` occurs here -LL | let y = x; //~ ERROR cannot move out of `x` because it is borrowed - | ^ move out of `x` occurs here -LL | r.use_ref(); - | - borrow later used here - -error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable - --> $DIR/borrow-tuple-fields.rs:33:13 - | -LL | let a = &x.0; - | ---- immutable borrow occurs here -LL | let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as - | ^^^^^^^^ mutable borrow occurs here -LL | a.use_ref(); - | - immutable borrow later used here - -error[E0499]: cannot borrow `x.0` as mutable more than once at a time - --> $DIR/borrow-tuple-fields.rs:38:13 - | -LL | let a = &mut x.0; - | -------- first mutable borrow occurs here -LL | let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time - | ^^^^^^^^ second mutable borrow occurs here -LL | a.use_mut(); - | - first borrow later used here - -error: aborting due to 6 previous errors - -Some errors occurred: E0499, E0502, E0505. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrow-tuple-fields.stderr b/src/test/ui/borrowck/borrow-tuple-fields.stderr index a62e7287e683f..503ea49d74ee0 100644 --- a/src/test/ui/borrowck/borrow-tuple-fields.stderr +++ b/src/test/ui/borrowck/borrow-tuple-fields.stderr @@ -1,64 +1,65 @@ error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/borrow-tuple-fields.rs:12:9 + --> $DIR/borrow-tuple-fields.rs:12:13 | LL | let r = &x.0; - | --- borrow of `x.0` occurs here -LL | let y = x; //~ ERROR cannot move out of `x` because it is borrowed - | ^ move out of `x` occurs here + | ---- borrow of `x.0` occurs here +LL | let y = x; + | ^ move out of `x` occurs here +LL | +LL | r.use_ref(); + | - borrow later used here error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable - --> $DIR/borrow-tuple-fields.rs:18:18 + --> $DIR/borrow-tuple-fields.rs:18:13 | LL | let a = &x.0; - | --- immutable borrow occurs here -LL | let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here + | ---- immutable borrow occurs here +LL | let b = &mut x.0; + | ^^^^^^^^ mutable borrow occurs here +LL | a.use_ref(); + | - immutable borrow later used here error[E0499]: cannot borrow `x.0` as mutable more than once at a time - --> $DIR/borrow-tuple-fields.rs:23:18 + --> $DIR/borrow-tuple-fields.rs:23:13 | LL | let a = &mut x.0; - | --- first mutable borrow occurs here -LL | let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time - | ^^^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here + | -------- first mutable borrow occurs here +LL | let b = &mut x.0; + | ^^^^^^^^ second mutable borrow occurs here +LL | a.use_ref(); + | - first borrow later used here error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/borrow-tuple-fields.rs:28:9 + --> $DIR/borrow-tuple-fields.rs:28:13 | LL | let r = &x.0; - | --- borrow of `x.0` occurs here -LL | let y = x; //~ ERROR cannot move out of `x` because it is borrowed - | ^ move out of `x` occurs here + | ---- borrow of `x.0` occurs here +LL | let y = x; + | ^ move out of `x` occurs here +LL | r.use_ref(); + | - borrow later used here error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable - --> $DIR/borrow-tuple-fields.rs:33:18 + --> $DIR/borrow-tuple-fields.rs:33:13 | LL | let a = &x.0; - | --- immutable borrow occurs here -LL | let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here + | ---- immutable borrow occurs here +LL | let b = &mut x.0; + | ^^^^^^^^ mutable borrow occurs here +LL | a.use_ref(); + | - immutable borrow later used here error[E0499]: cannot borrow `x.0` as mutable more than once at a time - --> $DIR/borrow-tuple-fields.rs:38:18 + --> $DIR/borrow-tuple-fields.rs:38:13 | LL | let a = &mut x.0; - | --- first mutable borrow occurs here -LL | let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time - | ^^^ second mutable borrow occurs here + | -------- first mutable borrow occurs here +LL | let b = &mut x.0; + | ^^^^^^^^ second mutable borrow occurs here LL | a.use_mut(); -LL | } - | - first borrow ends here + | - first borrow later used here error: aborting due to 6 previous errors -Some errors occurred: E0499, E0502, E0505. +Some errors have detailed explanations: E0499, E0502, E0505. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-access-permissions.ast.nll.stderr b/src/test/ui/borrowck/borrowck-access-permissions.ast.nll.stderr deleted file mode 100644 index 0d771a55d5995..0000000000000 --- a/src/test/ui/borrowck/borrowck-access-permissions.ast.nll.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/borrowck-access-permissions.rs:12:19 - | -LL | let x = 1; - | - help: consider changing this to be mutable: `mut x` -... -LL | let _y1 = &mut x; //[ast]~ ERROR [E0596] - | ^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow immutable static item `static_x` as mutable - --> $DIR/borrowck-access-permissions.rs:18:19 - | -LL | let _y1 = &mut static_x; //[ast]~ ERROR [E0596] - | ^^^^^^^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `*box_x` as mutable, as `box_x` is not declared as mutable - --> $DIR/borrowck-access-permissions.rs:27:19 - | -LL | let box_x = Box::new(1); - | ----- help: consider changing this to be mutable: `mut box_x` -... -LL | let _y1 = &mut *box_x; //[ast]~ ERROR [E0596] - | ^^^^^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `*ref_x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-access-permissions.rs:36:19 - | -LL | let ref_x = &x; - | -- help: consider changing this to be a mutable reference: `&mut x` -... -LL | let _y1 = &mut *ref_x; //[ast]~ ERROR [E0596] - | ^^^^^^^^^^^ `ref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `*ptr_x` as mutable, as it is behind a `*const` pointer - --> $DIR/borrowck-access-permissions.rs:46:23 - | -LL | let ptr_x : *const _ = &x; - | -- help: consider changing this to be a mutable pointer: `&mut x` -... -LL | let _y1 = &mut *ptr_x; //[ast]~ ERROR [E0596] - | ^^^^^^^^^^^ `ptr_x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `*foo_ref.f` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-access-permissions.rs:56:18 - | -LL | let foo_ref = &foo; - | ---- help: consider changing this to be a mutable reference: `&mut foo` -LL | let _y = &mut *foo_ref.f; //[ast]~ ERROR [E0389] - | ^^^^^^^^^^^^^^^ `foo_ref` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/borrowck-access-permissions.ast.stderr b/src/test/ui/borrowck/borrowck-access-permissions.ast.stderr deleted file mode 100644 index 4b0e261b17461..0000000000000 --- a/src/test/ui/borrowck/borrowck-access-permissions.ast.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error[E0596]: cannot borrow immutable local variable `x` as mutable - --> $DIR/borrowck-access-permissions.rs:12:24 - | -LL | let x = 1; - | - help: make this binding mutable: `mut x` -... -LL | let _y1 = &mut x; //[ast]~ ERROR [E0596] - | ^ cannot borrow mutably - -error[E0596]: cannot borrow immutable static item as mutable - --> $DIR/borrowck-access-permissions.rs:18:24 - | -LL | let _y1 = &mut static_x; //[ast]~ ERROR [E0596] - | ^^^^^^^^ - -error[E0596]: cannot borrow immutable `Box` content `*box_x` as mutable - --> $DIR/borrowck-access-permissions.rs:27:24 - | -LL | let box_x = Box::new(1); - | ----- help: make this binding mutable: `mut box_x` -... -LL | let _y1 = &mut *box_x; //[ast]~ ERROR [E0596] - | ^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow immutable borrowed content `*ref_x` as mutable - --> $DIR/borrowck-access-permissions.rs:36:24 - | -LL | let _y1 = &mut *ref_x; //[ast]~ ERROR [E0596] - | ^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow immutable dereference of raw pointer `*ptr_x` as mutable - --> $DIR/borrowck-access-permissions.rs:46:28 - | -LL | let _y1 = &mut *ptr_x; //[ast]~ ERROR [E0596] - | ^^^^^^ cannot borrow as mutable - -error[E0389]: cannot borrow data mutably in a `&` reference - --> $DIR/borrowck-access-permissions.rs:56:23 - | -LL | let _y = &mut *foo_ref.f; //[ast]~ ERROR [E0389] - | ^^^^^^^^^^ assignment into an immutable reference - -error: aborting due to 6 previous errors - -Some errors occurred: E0389, E0596. -For more information about an error, try `rustc --explain E0389`. diff --git a/src/test/ui/borrowck/borrowck-access-permissions.mir.stderr b/src/test/ui/borrowck/borrowck-access-permissions.mir.stderr deleted file mode 100644 index 0d771a55d5995..0000000000000 --- a/src/test/ui/borrowck/borrowck-access-permissions.mir.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/borrowck-access-permissions.rs:12:19 - | -LL | let x = 1; - | - help: consider changing this to be mutable: `mut x` -... -LL | let _y1 = &mut x; //[ast]~ ERROR [E0596] - | ^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow immutable static item `static_x` as mutable - --> $DIR/borrowck-access-permissions.rs:18:19 - | -LL | let _y1 = &mut static_x; //[ast]~ ERROR [E0596] - | ^^^^^^^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `*box_x` as mutable, as `box_x` is not declared as mutable - --> $DIR/borrowck-access-permissions.rs:27:19 - | -LL | let box_x = Box::new(1); - | ----- help: consider changing this to be mutable: `mut box_x` -... -LL | let _y1 = &mut *box_x; //[ast]~ ERROR [E0596] - | ^^^^^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `*ref_x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-access-permissions.rs:36:19 - | -LL | let ref_x = &x; - | -- help: consider changing this to be a mutable reference: `&mut x` -... -LL | let _y1 = &mut *ref_x; //[ast]~ ERROR [E0596] - | ^^^^^^^^^^^ `ref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `*ptr_x` as mutable, as it is behind a `*const` pointer - --> $DIR/borrowck-access-permissions.rs:46:23 - | -LL | let ptr_x : *const _ = &x; - | -- help: consider changing this to be a mutable pointer: `&mut x` -... -LL | let _y1 = &mut *ptr_x; //[ast]~ ERROR [E0596] - | ^^^^^^^^^^^ `ptr_x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `*foo_ref.f` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-access-permissions.rs:56:18 - | -LL | let foo_ref = &foo; - | ---- help: consider changing this to be a mutable reference: `&mut foo` -LL | let _y = &mut *foo_ref.f; //[ast]~ ERROR [E0389] - | ^^^^^^^^^^^^^^^ `foo_ref` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/borrowck-access-permissions.rs b/src/test/ui/borrowck/borrowck-access-permissions.rs index 993742f427e03..469ad508b0e77 100644 --- a/src/test/ui/borrowck/borrowck-access-permissions.rs +++ b/src/test/ui/borrowck/borrowck-access-permissions.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - static static_x : i32 = 1; static mut static_x_mut : i32 = 1; @@ -9,14 +6,12 @@ fn main() { let mut x_mut = 1; { // borrow of local - let _y1 = &mut x; //[ast]~ ERROR [E0596] - //[mir]~^ ERROR [E0596] + let _y1 = &mut x; //~ ERROR [E0596] let _y2 = &mut x_mut; // No error } { // borrow of static - let _y1 = &mut static_x; //[ast]~ ERROR [E0596] - //[mir]~^ ERROR [E0596] + let _y1 = &mut static_x; //~ ERROR [E0596] unsafe { let _y2 = &mut static_x_mut; } // No error } @@ -24,8 +19,7 @@ fn main() { let box_x = Box::new(1); let mut box_x_mut = Box::new(1); - let _y1 = &mut *box_x; //[ast]~ ERROR [E0596] - //[mir]~^ ERROR [E0596] + let _y1 = &mut *box_x; //~ ERROR [E0596] let _y2 = &mut *box_x_mut; // No error } @@ -33,8 +27,7 @@ fn main() { let ref_x = &x; let ref_x_mut = &mut x_mut; - let _y1 = &mut *ref_x; //[ast]~ ERROR [E0596] - //[mir]~^ ERROR [E0596] + let _y1 = &mut *ref_x; //~ ERROR [E0596] let _y2 = &mut *ref_x_mut; // No error } @@ -43,8 +36,7 @@ fn main() { let ptr_mut_x : *mut _ = &mut x_mut; unsafe { - let _y1 = &mut *ptr_x; //[ast]~ ERROR [E0596] - //[mir]~^ ERROR [E0596] + let _y1 = &mut *ptr_x; //~ ERROR [E0596] let _y2 = &mut *ptr_mut_x; // No error } } @@ -53,8 +45,6 @@ fn main() { struct Foo<'a> { f: &'a mut i32, g: &'a i32 }; let mut foo = Foo { f: &mut x_mut, g: &x }; let foo_ref = &foo; - let _y = &mut *foo_ref.f; //[ast]~ ERROR [E0389] - //[mir]~^ ERROR [E0596] - // FIXME: Wrong error in MIR + let _y = &mut *foo_ref.f; //~ ERROR [E0596] } } diff --git a/src/test/ui/borrowck/borrowck-access-permissions.stderr b/src/test/ui/borrowck/borrowck-access-permissions.stderr new file mode 100644 index 0000000000000..e3a35c38a7c03 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-access-permissions.stderr @@ -0,0 +1,53 @@ +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/borrowck-access-permissions.rs:9:19 + | +LL | let x = 1; + | - help: consider changing this to be mutable: `mut x` +... +LL | let _y1 = &mut x; + | ^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable static item `static_x` as mutable + --> $DIR/borrowck-access-permissions.rs:14:19 + | +LL | let _y1 = &mut static_x; + | ^^^^^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `*box_x` as mutable, as `box_x` is not declared as mutable + --> $DIR/borrowck-access-permissions.rs:22:19 + | +LL | let box_x = Box::new(1); + | ----- help: consider changing this to be mutable: `mut box_x` +... +LL | let _y1 = &mut *box_x; + | ^^^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `*ref_x` as mutable, as it is behind a `&` reference + --> $DIR/borrowck-access-permissions.rs:30:19 + | +LL | let ref_x = &x; + | -- help: consider changing this to be a mutable reference: `&mut x` +... +LL | let _y1 = &mut *ref_x; + | ^^^^^^^^^^^ `ref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + +error[E0596]: cannot borrow `*ptr_x` as mutable, as it is behind a `*const` pointer + --> $DIR/borrowck-access-permissions.rs:39:23 + | +LL | let ptr_x : *const _ = &x; + | -- help: consider changing this to be a mutable pointer: `&mut x` +... +LL | let _y1 = &mut *ptr_x; + | ^^^^^^^^^^^ `ptr_x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable + +error[E0596]: cannot borrow `*foo_ref.f` as mutable, as it is behind a `&` reference + --> $DIR/borrowck-access-permissions.rs:48:18 + | +LL | let foo_ref = &foo; + | ---- help: consider changing this to be a mutable reference: `&mut foo` +LL | let _y = &mut *foo_ref.f; + | ^^^^^^^^^^^^^^^ `foo_ref` is a `&` reference, so the data it refers to cannot be borrowed as mutable + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/borrowck-and-init.nll.stderr b/src/test/ui/borrowck/borrowck-and-init.nll.stderr deleted file mode 100644 index b4b02cf208ae7..0000000000000 --- a/src/test/ui/borrowck/borrowck-and-init.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `i` - --> $DIR/borrowck-and-init.rs:5:20 - | -LL | println!("{}", i); //~ ERROR use of possibly uninitialized variable: `i` - | ^ use of possibly uninitialized `i` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-and-init.rs b/src/test/ui/borrowck/borrowck-and-init.rs index ff076c55cad24..4427e25186103 100644 --- a/src/test/ui/borrowck/borrowck-and-init.rs +++ b/src/test/ui/borrowck/borrowck-and-init.rs @@ -2,5 +2,5 @@ fn main() { let i: isize; println!("{}", false && { i = 5; true }); - println!("{}", i); //~ ERROR use of possibly uninitialized variable: `i` + println!("{}", i); //~ ERROR borrow of possibly uninitialized variable: `i` } diff --git a/src/test/ui/borrowck/borrowck-and-init.stderr b/src/test/ui/borrowck/borrowck-and-init.stderr index 42b658871dfaa..2db075194810e 100644 --- a/src/test/ui/borrowck/borrowck-and-init.stderr +++ b/src/test/ui/borrowck/borrowck-and-init.stderr @@ -1,7 +1,7 @@ -error[E0381]: use of possibly uninitialized variable: `i` +error[E0381]: borrow of possibly uninitialized variable: `i` --> $DIR/borrowck-and-init.rs:5:20 | -LL | println!("{}", i); //~ ERROR use of possibly uninitialized variable: `i` +LL | println!("{}", i); | ^ use of possibly uninitialized `i` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-anon-fields-struct.nll.stderr b/src/test/ui/borrowck/borrowck-anon-fields-struct.nll.stderr deleted file mode 100644 index 43c74988f9ea5..0000000000000 --- a/src/test/ui/borrowck/borrowck-anon-fields-struct.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0499]: cannot borrow `y.0` as mutable more than once at a time - --> $DIR/borrowck-anon-fields-struct.rs:29:11 - | -LL | Y(ref mut a, _) => a - | --------- first mutable borrow occurs here -... -LL | Y(ref mut b, _) => b //~ ERROR cannot borrow - | ^^^^^^^^^ second mutable borrow occurs here -... -LL | *a += 1; - | ------- first borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-anon-fields-struct.stderr b/src/test/ui/borrowck/borrowck-anon-fields-struct.stderr index 9c36a9fe875f5..7a959fb6ec62f 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-struct.stderr +++ b/src/test/ui/borrowck/borrowck-anon-fields-struct.stderr @@ -4,11 +4,11 @@ error[E0499]: cannot borrow `y.0` as mutable more than once at a time LL | Y(ref mut a, _) => a | --------- first mutable borrow occurs here ... -LL | Y(ref mut b, _) => b //~ ERROR cannot borrow +LL | Y(ref mut b, _) => b | ^^^^^^^^^ second mutable borrow occurs here ... -LL | } - | - first borrow ends here +LL | *a += 1; + | ------- first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-anon-fields-tuple.nll.stderr b/src/test/ui/borrowck/borrowck-anon-fields-tuple.nll.stderr deleted file mode 100644 index 15859040f060a..0000000000000 --- a/src/test/ui/borrowck/borrowck-anon-fields-tuple.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0499]: cannot borrow `y.0` as mutable more than once at a time - --> $DIR/borrowck-anon-fields-tuple.rs:27:10 - | -LL | (ref mut a, _) => a - | --------- first mutable borrow occurs here -... -LL | (ref mut b, _) => b //~ ERROR cannot borrow - | ^^^^^^^^^ second mutable borrow occurs here -... -LL | *a += 1; - | ------- first borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-anon-fields-tuple.stderr b/src/test/ui/borrowck/borrowck-anon-fields-tuple.stderr index 4b823f396afc5..88a8867f5ee08 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-tuple.stderr +++ b/src/test/ui/borrowck/borrowck-anon-fields-tuple.stderr @@ -4,11 +4,11 @@ error[E0499]: cannot borrow `y.0` as mutable more than once at a time LL | (ref mut a, _) => a | --------- first mutable borrow occurs here ... -LL | (ref mut b, _) => b //~ ERROR cannot borrow +LL | (ref mut b, _) => b | ^^^^^^^^^ second mutable borrow occurs here ... -LL | } - | - first borrow ends here +LL | *a += 1; + | ------- first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr b/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr index 2f4cf7dd800e1..f66994b3f100a 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr +++ b/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr @@ -1,4 +1,4 @@ -warning[E0503]: cannot use `y` because it was mutably borrowed +error[E0503]: cannot use `y` because it was mutably borrowed --> $DIR/borrowck-anon-fields-variant.rs:17:7 | LL | Foo::Y(ref mut a, _) => a, @@ -9,35 +9,32 @@ LL | Foo::Y(_, ref mut b) => b, ... LL | *a += 1; | ------- borrow later used here - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future error[E0503]: cannot use `y` because it was mutably borrowed - --> $DIR/borrowck-anon-fields-variant.rs:34:7 + --> $DIR/borrowck-anon-fields-variant.rs:37:7 | LL | Foo::Y(ref mut a, _) => a, | --------- borrow of `y.0` occurs here ... -LL | Foo::Y(ref mut b, _) => b, //~ ERROR cannot borrow +LL | Foo::Y(ref mut b, _) => b, | ^^^^^^^^^^^^^^^^^^^^ use of borrowed `y.0` ... LL | *a += 1; | ------- borrow later used here error[E0499]: cannot borrow `y.0` as mutable more than once at a time - --> $DIR/borrowck-anon-fields-variant.rs:34:14 + --> $DIR/borrowck-anon-fields-variant.rs:37:14 | LL | Foo::Y(ref mut a, _) => a, | --------- first mutable borrow occurs here ... -LL | Foo::Y(ref mut b, _) => b, //~ ERROR cannot borrow +LL | Foo::Y(ref mut b, _) => b, | ^^^^^^^^^ second mutable borrow occurs here ... LL | *a += 1; | ------- first borrow later used here -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -Some errors occurred: E0499, E0503. +Some errors have detailed explanations: E0499, E0503. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-anon-fields-variant.rs b/src/test/ui/borrowck/borrowck-anon-fields-variant.rs index c27435608c4a4..695809f58c551 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-variant.rs +++ b/src/test/ui/borrowck/borrowck-anon-fields-variant.rs @@ -1,6 +1,3 @@ -// Tests that we are able to distinguish when loans borrow different -// anonymous fields of an enum variant vs the same anonymous field. - enum Foo { X, Y(usize, usize) } @@ -13,8 +10,14 @@ fn distinct_variant() { Foo::X => panic!() }; + // While `a` and `b` are disjoint, borrowck doesn't know that `a` is not + // also used for the discriminant of `Foo`, which it would be if `a` was a + // reference. let b = match y { Foo::Y(_, ref mut b) => b, + //~^ WARNING cannot use `y` + //~| WARNING this error has been downgraded to a warning + //~| WARNING this warning will become a hard error in the future Foo::X => panic!() }; @@ -31,7 +34,8 @@ fn same_variant() { }; let b = match y { - Foo::Y(ref mut b, _) => b, //~ ERROR cannot borrow + Foo::Y(ref mut b, _) => b, //~ ERROR cannot use `y` + //~| ERROR cannot borrow `y.0` as mutable Foo::X => panic!() }; diff --git a/src/test/ui/borrowck/borrowck-anon-fields-variant.stderr b/src/test/ui/borrowck/borrowck-anon-fields-variant.stderr index 1e94cdebaec6a..e2d3e417ac3ac 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-variant.stderr +++ b/src/test/ui/borrowck/borrowck-anon-fields-variant.stderr @@ -1,15 +1,44 @@ +warning[E0503]: cannot use `y` because it was mutably borrowed + --> $DIR/borrowck-anon-fields-variant.rs:17:7 + | +LL | Foo::Y(ref mut a, _) => a, + | --------- borrow of `y.0` occurs here +... +LL | Foo::Y(_, ref mut b) => b, + | ^^^^^^^^^^^^^^^^^^^^ use of borrowed `y.0` +... +LL | *a += 1; + | ------- borrow later used here + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + +error[E0503]: cannot use `y` because it was mutably borrowed + --> $DIR/borrowck-anon-fields-variant.rs:37:7 + | +LL | Foo::Y(ref mut a, _) => a, + | --------- borrow of `y.0` occurs here +... +LL | Foo::Y(ref mut b, _) => b, + | ^^^^^^^^^^^^^^^^^^^^ use of borrowed `y.0` +... +LL | *a += 1; + | ------- borrow later used here + error[E0499]: cannot borrow `y.0` as mutable more than once at a time - --> $DIR/borrowck-anon-fields-variant.rs:34:14 + --> $DIR/borrowck-anon-fields-variant.rs:37:14 | LL | Foo::Y(ref mut a, _) => a, | --------- first mutable borrow occurs here ... -LL | Foo::Y(ref mut b, _) => b, //~ ERROR cannot borrow +LL | Foo::Y(ref mut b, _) => b, | ^^^^^^^^^ second mutable borrow occurs here ... -LL | } - | - first borrow ends here +LL | *a += 1; + | ------- first borrow later used here -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0499`. +Some errors have detailed explanations: E0499, E0503. +For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-argument.nll.stderr b/src/test/ui/borrowck/borrowck-argument.nll.stderr deleted file mode 100644 index 9e7f0930ee57d..0000000000000 --- a/src/test/ui/borrowck/borrowck-argument.nll.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable - --> $DIR/borrowck-argument.rs:10:5 - | -LL | fn func(arg: S) { - | --- help: consider changing this to be mutable: `mut arg` -LL | arg.mutate(); //~ ERROR: cannot borrow immutable argument - | ^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable - --> $DIR/borrowck-argument.rs:15:9 - | -LL | fn method(&self, arg: S) { - | --- help: consider changing this to be mutable: `mut arg` -LL | arg.mutate(); //~ ERROR: cannot borrow immutable argument - | ^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable - --> $DIR/borrowck-argument.rs:21:9 - | -LL | fn default(&self, arg: S) { - | --- help: consider changing this to be mutable: `mut arg` -LL | arg.mutate(); //~ ERROR: cannot borrow immutable argument - | ^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable - --> $DIR/borrowck-argument.rs:32:17 - | -LL | (|arg: S| { arg.mutate() })(s); //~ ERROR: cannot borrow immutable argument - | --- ^^^ cannot borrow as mutable - | | - | help: consider changing this to be mutable: `mut arg` - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/borrowck-argument.rs b/src/test/ui/borrowck/borrowck-argument.rs index e1f1adec8380c..5d776d4fca475 100644 --- a/src/test/ui/borrowck/borrowck-argument.rs +++ b/src/test/ui/borrowck/borrowck-argument.rs @@ -7,18 +7,18 @@ impl S { } fn func(arg: S) { - arg.mutate(); //~ ERROR: cannot borrow immutable argument + arg.mutate(); //~ ERROR: cannot borrow `arg` as mutable, as it is not declared as mutable } impl S { fn method(&self, arg: S) { - arg.mutate(); //~ ERROR: cannot borrow immutable argument + arg.mutate(); //~ ERROR: cannot borrow `arg` as mutable, as it is not declared as mutable } } trait T { fn default(&self, arg: S) { - arg.mutate(); //~ ERROR: cannot borrow immutable argument + arg.mutate(); //~ ERROR: cannot borrow `arg` as mutable, as it is not declared as mutable } } @@ -29,5 +29,6 @@ fn main() { func(s); s.method(s); s.default(s); - (|arg: S| { arg.mutate() })(s); //~ ERROR: cannot borrow immutable argument + (|arg: S| { arg.mutate() })(s); + //~^ ERROR: cannot borrow `arg` as mutable, as it is not declared as mutable } diff --git a/src/test/ui/borrowck/borrowck-argument.stderr b/src/test/ui/borrowck/borrowck-argument.stderr index fa82b1c00cc7f..cf15833140927 100644 --- a/src/test/ui/borrowck/borrowck-argument.stderr +++ b/src/test/ui/borrowck/borrowck-argument.stderr @@ -1,34 +1,34 @@ -error[E0596]: cannot borrow immutable argument `arg` as mutable +error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable --> $DIR/borrowck-argument.rs:10:5 | LL | fn func(arg: S) { - | --- help: make this binding mutable: `mut arg` -LL | arg.mutate(); //~ ERROR: cannot borrow immutable argument - | ^^^ cannot borrow mutably + | --- help: consider changing this to be mutable: `mut arg` +LL | arg.mutate(); + | ^^^ cannot borrow as mutable -error[E0596]: cannot borrow immutable argument `arg` as mutable +error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable --> $DIR/borrowck-argument.rs:15:9 | LL | fn method(&self, arg: S) { - | --- help: make this binding mutable: `mut arg` -LL | arg.mutate(); //~ ERROR: cannot borrow immutable argument - | ^^^ cannot borrow mutably + | --- help: consider changing this to be mutable: `mut arg` +LL | arg.mutate(); + | ^^^ cannot borrow as mutable -error[E0596]: cannot borrow immutable argument `arg` as mutable +error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable --> $DIR/borrowck-argument.rs:21:9 | LL | fn default(&self, arg: S) { - | --- help: make this binding mutable: `mut arg` -LL | arg.mutate(); //~ ERROR: cannot borrow immutable argument - | ^^^ cannot borrow mutably + | --- help: consider changing this to be mutable: `mut arg` +LL | arg.mutate(); + | ^^^ cannot borrow as mutable -error[E0596]: cannot borrow immutable argument `arg` as mutable +error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable --> $DIR/borrowck-argument.rs:32:17 | -LL | (|arg: S| { arg.mutate() })(s); //~ ERROR: cannot borrow immutable argument - | --- ^^^ cannot borrow mutably +LL | (|arg: S| { arg.mutate() })(s); + | --- ^^^ cannot borrow as mutable | | - | help: make this binding mutable: `mut arg` + | help: consider changing this to be mutable: `mut arg` error: aborting due to 4 previous errors diff --git a/src/test/ui/borrowck/borrowck-asm.ast.nll.stderr b/src/test/ui/borrowck/borrowck-asm.ast.nll.stderr deleted file mode 100644 index 86e4832b3873c..0000000000000 --- a/src/test/ui/borrowck/borrowck-asm.ast.nll.stderr +++ /dev/null @@ -1,81 +0,0 @@ -error[E0382]: use of moved value: `x` - --> $DIR/borrowck-asm.rs:27:17 - | -LL | let x = &mut 0isize; - | - move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait -LL | unsafe { -LL | asm!("nop" : : "r"(x)); - | - value moved here -LL | } -LL | let z = x; //[ast]~ ERROR use of moved value: `x` - | ^ value used here after move - -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-asm.rs:35:32 - | -LL | let y = &mut x; - | ------ borrow of `x` occurs here -LL | unsafe { -LL | asm!("nop" : : "r"(x)); //[ast]~ ERROR cannot use - | ^ use of borrowed `x` -... -LL | let z = y; - | - borrow later used here - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-asm.rs:44:31 - | -LL | let x = 3; - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | unsafe { -LL | asm!("nop" : "=r"(x)); //[ast]~ ERROR cannot assign twice - | ^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-asm.rs:60:31 - | -LL | let x = 3; - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | unsafe { -LL | asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign twice - | ^ cannot assign twice to immutable variable - -error[E0381]: use of possibly uninitialized variable: `x` - --> $DIR/borrowck-asm.rs:68:32 - | -LL | asm!("nop" : "=*r"(x)); //[ast]~ ERROR use of possibly uninitialized variable - | ^ use of possibly uninitialized `x` - -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-asm.rs:77:31 - | -LL | let y = &*x; - | --- borrow of `x` occurs here -LL | unsafe { -LL | asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign to `x` because it is borrowed - | ^ assignment to borrowed `x` occurs here -... -LL | let z = y; - | - borrow later used here - -error[E0382]: use of moved value: `x` - --> $DIR/borrowck-asm.rs:86:40 - | -LL | let x = &mut 2; - | - move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait -LL | unsafe { -LL | asm!("nop" : : "r"(x), "r"(x) ); //[ast]~ ERROR use of moved value - | - ^ value used here after move - | | - | value moved here - -error: aborting due to 7 previous errors - -Some errors occurred: E0381, E0382, E0384, E0503, E0506. -For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-asm.ast.stderr b/src/test/ui/borrowck/borrowck-asm.ast.stderr deleted file mode 100644 index 73eb08b59b069..0000000000000 --- a/src/test/ui/borrowck/borrowck-asm.ast.stderr +++ /dev/null @@ -1,76 +0,0 @@ -error[E0382]: use of moved value: `x` - --> $DIR/borrowck-asm.rs:27:13 - | -LL | asm!("nop" : : "r"(x)); - | - value moved here -LL | } -LL | let z = x; //[ast]~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait - -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-asm.rs:35:32 - | -LL | let y = &mut x; - | - borrow of `x` occurs here -LL | unsafe { -LL | asm!("nop" : : "r"(x)); //[ast]~ ERROR cannot use - | ^ use of borrowed `x` - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-asm.rs:44:31 - | -LL | let x = 3; - | - first assignment to `x` -LL | unsafe { -LL | asm!("nop" : "=r"(x)); //[ast]~ ERROR cannot assign twice - | ^ cannot assign twice to immutable variable - -error[E0506]: cannot assign to `a` because it is borrowed - --> $DIR/borrowck-asm.rs:50:31 - | -LL | let b = &*a; - | -- borrow of `a` occurs here -LL | unsafe { -LL | asm!("nop" : "=r"(a)); //[ast]~ ERROR cannot assign to `a` because it is borrowed - | ^ assignment to borrowed `a` occurs here - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-asm.rs:60:31 - | -LL | let x = 3; - | - first assignment to `x` -LL | unsafe { -LL | asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign twice - | ^ cannot assign twice to immutable variable - -error[E0381]: use of possibly uninitialized variable: `x` - --> $DIR/borrowck-asm.rs:68:32 - | -LL | asm!("nop" : "=*r"(x)); //[ast]~ ERROR use of possibly uninitialized variable - | ^ use of possibly uninitialized `x` - -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-asm.rs:77:31 - | -LL | let y = &*x; - | -- borrow of `x` occurs here -LL | unsafe { -LL | asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign to `x` because it is borrowed - | ^ assignment to borrowed `x` occurs here - -error[E0382]: use of moved value: `x` - --> $DIR/borrowck-asm.rs:86:40 - | -LL | asm!("nop" : : "r"(x), "r"(x) ); //[ast]~ ERROR use of moved value - | - ^ value used here after move - | | - | value moved here - | - = note: move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait - -error: aborting due to 8 previous errors - -Some errors occurred: E0381, E0382, E0384, E0503, E0506. -For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-asm.mir.stderr b/src/test/ui/borrowck/borrowck-asm.mir.stderr deleted file mode 100644 index 86e4832b3873c..0000000000000 --- a/src/test/ui/borrowck/borrowck-asm.mir.stderr +++ /dev/null @@ -1,81 +0,0 @@ -error[E0382]: use of moved value: `x` - --> $DIR/borrowck-asm.rs:27:17 - | -LL | let x = &mut 0isize; - | - move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait -LL | unsafe { -LL | asm!("nop" : : "r"(x)); - | - value moved here -LL | } -LL | let z = x; //[ast]~ ERROR use of moved value: `x` - | ^ value used here after move - -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-asm.rs:35:32 - | -LL | let y = &mut x; - | ------ borrow of `x` occurs here -LL | unsafe { -LL | asm!("nop" : : "r"(x)); //[ast]~ ERROR cannot use - | ^ use of borrowed `x` -... -LL | let z = y; - | - borrow later used here - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-asm.rs:44:31 - | -LL | let x = 3; - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | unsafe { -LL | asm!("nop" : "=r"(x)); //[ast]~ ERROR cannot assign twice - | ^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-asm.rs:60:31 - | -LL | let x = 3; - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | unsafe { -LL | asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign twice - | ^ cannot assign twice to immutable variable - -error[E0381]: use of possibly uninitialized variable: `x` - --> $DIR/borrowck-asm.rs:68:32 - | -LL | asm!("nop" : "=*r"(x)); //[ast]~ ERROR use of possibly uninitialized variable - | ^ use of possibly uninitialized `x` - -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-asm.rs:77:31 - | -LL | let y = &*x; - | --- borrow of `x` occurs here -LL | unsafe { -LL | asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign to `x` because it is borrowed - | ^ assignment to borrowed `x` occurs here -... -LL | let z = y; - | - borrow later used here - -error[E0382]: use of moved value: `x` - --> $DIR/borrowck-asm.rs:86:40 - | -LL | let x = &mut 2; - | - move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait -LL | unsafe { -LL | asm!("nop" : : "r"(x), "r"(x) ); //[ast]~ ERROR use of moved value - | - ^ value used here after move - | | - | value moved here - -error: aborting due to 7 previous errors - -Some errors occurred: E0381, E0382, E0384, E0503, E0506. -For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-asm.rs b/src/test/ui/borrowck/borrowck-asm.rs index 560c87c8d7220..9c9cc04baafee 100644 --- a/src/test/ui/borrowck/borrowck-asm.rs +++ b/src/test/ui/borrowck/borrowck-asm.rs @@ -6,9 +6,6 @@ // ignore-sparc // ignore-sparc64 -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - #![feature(asm)] #[cfg(any(target_arch = "x86", @@ -24,16 +21,14 @@ mod test_cases { unsafe { asm!("nop" : : "r"(x)); } - let z = x; //[ast]~ ERROR use of moved value: `x` - //[mir]~^ ERROR use of moved value: `x` + let z = x; //~ ERROR use of moved value: `x` } fn in_is_read() { let mut x = 3; let y = &mut x; unsafe { - asm!("nop" : : "r"(x)); //[ast]~ ERROR cannot use - //[mir]~^ ERROR cannot use + asm!("nop" : : "r"(x)); //~ ERROR cannot use } let z = y; } @@ -41,14 +36,12 @@ mod test_cases { fn out_is_assign() { let x = 3; unsafe { - asm!("nop" : "=r"(x)); //[ast]~ ERROR cannot assign twice - //[mir]~^ ERROR cannot assign twice + asm!("nop" : "=r"(x)); //~ ERROR cannot assign twice } let mut a = &mut 3; let b = &*a; unsafe { - asm!("nop" : "=r"(a)); //[ast]~ ERROR cannot assign to `a` because it is borrowed - // No MIR error, this is a shallow write. + asm!("nop" : "=r"(a)); // OK, Shallow write to `a` } let c = b; let d = *a; @@ -57,16 +50,14 @@ mod test_cases { fn rw_is_assign() { let x = 3; unsafe { - asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign twice - //[mir]~^ ERROR cannot assign twice + asm!("nop" : "+r"(x)); //~ ERROR cannot assign twice } } fn indirect_is_not_init() { let x: i32; unsafe { - asm!("nop" : "=*r"(x)); //[ast]~ ERROR use of possibly uninitialized variable - //[mir]~^ ERROR use of possibly uninitialized variable + asm!("nop" : "=*r"(x)); //~ ERROR use of possibly uninitialized variable } } @@ -74,8 +65,7 @@ mod test_cases { let mut x = &mut 3; let y = &*x; unsafe { - asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign to `x` because it is borrowed - //[mir]~^ ERROR cannot assign to `x` because it is borrowed + asm!("nop" : "+r"(x)); //~ ERROR cannot assign to `x` because it is borrowed } let z = y; } @@ -83,8 +73,7 @@ mod test_cases { fn two_moves() { let x = &mut 2; unsafe { - asm!("nop" : : "r"(x), "r"(x) ); //[ast]~ ERROR use of moved value - //[mir]~^ ERROR use of moved value + asm!("nop" : : "r"(x), "r"(x) ); //~ ERROR use of moved value } } } diff --git a/src/test/ui/borrowck/borrowck-asm.stderr b/src/test/ui/borrowck/borrowck-asm.stderr new file mode 100644 index 0000000000000..c771373022ac4 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-asm.stderr @@ -0,0 +1,81 @@ +error[E0382]: use of moved value: `x` + --> $DIR/borrowck-asm.rs:24:17 + | +LL | let x = &mut 0isize; + | - move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait +LL | unsafe { +LL | asm!("nop" : : "r"(x)); + | - value moved here +LL | } +LL | let z = x; + | ^ value used here after move + +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/borrowck-asm.rs:31:32 + | +LL | let y = &mut x; + | ------ borrow of `x` occurs here +LL | unsafe { +LL | asm!("nop" : : "r"(x)); + | ^ use of borrowed `x` +LL | } +LL | let z = y; + | - borrow later used here + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/borrowck-asm.rs:39:31 + | +LL | let x = 3; + | - + | | + | first assignment to `x` + | help: make this binding mutable: `mut x` +LL | unsafe { +LL | asm!("nop" : "=r"(x)); + | ^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/borrowck-asm.rs:53:31 + | +LL | let x = 3; + | - + | | + | first assignment to `x` + | help: make this binding mutable: `mut x` +LL | unsafe { +LL | asm!("nop" : "+r"(x)); + | ^ cannot assign twice to immutable variable + +error[E0381]: use of possibly uninitialized variable: `x` + --> $DIR/borrowck-asm.rs:60:32 + | +LL | asm!("nop" : "=*r"(x)); + | ^ use of possibly uninitialized `x` + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/borrowck-asm.rs:68:31 + | +LL | let y = &*x; + | --- borrow of `x` occurs here +LL | unsafe { +LL | asm!("nop" : "+r"(x)); + | ^ assignment to borrowed `x` occurs here +LL | } +LL | let z = y; + | - borrow later used here + +error[E0382]: use of moved value: `x` + --> $DIR/borrowck-asm.rs:76:40 + | +LL | let x = &mut 2; + | - move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait +LL | unsafe { +LL | asm!("nop" : : "r"(x), "r"(x) ); + | - ^ value used here after move + | | + | value moved here + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0381, E0382, E0384, E0503, E0506. +For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-assign-comp-idx.nll.stderr b/src/test/ui/borrowck/borrowck-assign-comp-idx.nll.stderr deleted file mode 100644 index 71f36c2b045a8..0000000000000 --- a/src/test/ui/borrowck/borrowck-assign-comp-idx.nll.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-assign-comp-idx.rs:12:5 - | -LL | let q: &isize = &p[0]; - | - immutable borrow occurs here -LL | -LL | p[0] = 5; //~ ERROR cannot borrow - | ^ mutable borrow occurs here -LL | -LL | println!("{}", *q); - | -- immutable borrow later used here - -error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-assign-comp-idx.rs:27:9 - | -LL | borrow( - | ------ immutable borrow later used by call -LL | &p, - | -- immutable borrow occurs here -LL | || p[0] = 5); //~ ERROR cannot borrow `p` as mutable - | ^^ - second borrow occurs due to use of `p` in closure - | | - | mutable borrow occurs here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-assign-comp-idx.stderr b/src/test/ui/borrowck/borrowck-assign-comp-idx.stderr index 9997aa4190e3f..93f1d8c525863 100644 --- a/src/test/ui/borrowck/borrowck-assign-comp-idx.stderr +++ b/src/test/ui/borrowck/borrowck-assign-comp-idx.stderr @@ -4,21 +4,22 @@ error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immuta LL | let q: &isize = &p[0]; | - immutable borrow occurs here LL | -LL | p[0] = 5; //~ ERROR cannot borrow +LL | p[0] = 5; | ^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here +LL | +LL | println!("{}", *q); + | -- immutable borrow later used here error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable --> $DIR/borrowck-assign-comp-idx.rs:27:9 | +LL | borrow( + | ------ immutable borrow later used by call LL | &p, - | - immutable borrow occurs here -LL | || p[0] = 5); //~ ERROR cannot borrow `p` as mutable - | ^^ - - immutable borrow ends here - | | | - | | borrow occurs due to use of `p` in closure + | -- immutable borrow occurs here +LL | || p[0] = 5); + | ^^ - second borrow occurs due to use of `p` in closure + | | | mutable borrow occurs here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-assign-comp.ast.nll.stderr b/src/test/ui/borrowck/borrowck-assign-comp.ast.nll.stderr deleted file mode 100644 index c204248d81a27..0000000000000 --- a/src/test/ui/borrowck/borrowck-assign-comp.ast.nll.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error[E0506]: cannot assign to `p.x` because it is borrowed - --> $DIR/borrowck-assign-comp.rs:13:5 - | -LL | let q = &p; - | -- borrow of `p.x` occurs here -... -LL | p.x = 5; //[ast]~ ERROR cannot assign to `p.x` - | ^^^^^^^ assignment to borrowed `p.x` occurs here -LL | //[mir]~^ ERROR cannot assign to `p.x` because it is borrowed -LL | q.x; - | --- borrow later used here - -error[E0506]: cannot assign to `p` because it is borrowed - --> $DIR/borrowck-assign-comp.rs:24:5 - | -LL | let q = &p.y; - | ---- borrow of `p` occurs here -LL | p = Point {x: 5, y: 7};//[ast]~ ERROR cannot assign to `p` - | ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `p` occurs here -... -LL | *q; // stretch loan - | -- borrow later used here - -error[E0506]: cannot assign to `p.y` because it is borrowed - --> $DIR/borrowck-assign-comp.rs:36:5 - | -LL | let q = &p.y; - | ---- borrow of `p.y` occurs here -LL | p.y = 5; //[ast]~ ERROR cannot assign to `p.y` - | ^^^^^^^ assignment to borrowed `p.y` occurs here -LL | //[mir]~^ ERROR cannot assign to `p.y` because it is borrowed -LL | *q; - | -- borrow later used here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-assign-comp.ast.stderr b/src/test/ui/borrowck/borrowck-assign-comp.ast.stderr deleted file mode 100644 index 735c168d7df10..0000000000000 --- a/src/test/ui/borrowck/borrowck-assign-comp.ast.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error[E0506]: cannot assign to `p.x` because it is borrowed - --> $DIR/borrowck-assign-comp.rs:13:5 - | -LL | let q = &p; - | - borrow of `p.x` occurs here -... -LL | p.x = 5; //[ast]~ ERROR cannot assign to `p.x` - | ^^^^^^^ assignment to borrowed `p.x` occurs here - -error[E0506]: cannot assign to `p` because it is borrowed - --> $DIR/borrowck-assign-comp.rs:24:5 - | -LL | let q = &p.y; - | --- borrow of `p` occurs here -LL | p = Point {x: 5, y: 7};//[ast]~ ERROR cannot assign to `p` - | ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `p` occurs here - -error[E0506]: cannot assign to `p.y` because it is borrowed - --> $DIR/borrowck-assign-comp.rs:36:5 - | -LL | let q = &p.y; - | --- borrow of `p.y` occurs here -LL | p.y = 5; //[ast]~ ERROR cannot assign to `p.y` - | ^^^^^^^ assignment to borrowed `p.y` occurs here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-assign-comp.mir.stderr b/src/test/ui/borrowck/borrowck-assign-comp.mir.stderr deleted file mode 100644 index c204248d81a27..0000000000000 --- a/src/test/ui/borrowck/borrowck-assign-comp.mir.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error[E0506]: cannot assign to `p.x` because it is borrowed - --> $DIR/borrowck-assign-comp.rs:13:5 - | -LL | let q = &p; - | -- borrow of `p.x` occurs here -... -LL | p.x = 5; //[ast]~ ERROR cannot assign to `p.x` - | ^^^^^^^ assignment to borrowed `p.x` occurs here -LL | //[mir]~^ ERROR cannot assign to `p.x` because it is borrowed -LL | q.x; - | --- borrow later used here - -error[E0506]: cannot assign to `p` because it is borrowed - --> $DIR/borrowck-assign-comp.rs:24:5 - | -LL | let q = &p.y; - | ---- borrow of `p` occurs here -LL | p = Point {x: 5, y: 7};//[ast]~ ERROR cannot assign to `p` - | ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `p` occurs here -... -LL | *q; // stretch loan - | -- borrow later used here - -error[E0506]: cannot assign to `p.y` because it is borrowed - --> $DIR/borrowck-assign-comp.rs:36:5 - | -LL | let q = &p.y; - | ---- borrow of `p.y` occurs here -LL | p.y = 5; //[ast]~ ERROR cannot assign to `p.y` - | ^^^^^^^ assignment to borrowed `p.y` occurs here -LL | //[mir]~^ ERROR cannot assign to `p.y` because it is borrowed -LL | *q; - | -- borrow later used here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-assign-comp.rs b/src/test/ui/borrowck/borrowck-assign-comp.rs index 0cacc3882d800..98bb2d85ad7c1 100644 --- a/src/test/ui/borrowck/borrowck-assign-comp.rs +++ b/src/test/ui/borrowck/borrowck-assign-comp.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - struct Point { x: isize, y: isize } fn a() { @@ -10,8 +7,7 @@ fn a() { // This assignment is illegal because the field x is not // inherently mutable; since `p` was made immutable, `p.x` is now // immutable. Otherwise the type of &_q.x (&isize) would be wrong. - p.x = 5; //[ast]~ ERROR cannot assign to `p.x` - //[mir]~^ ERROR cannot assign to `p.x` because it is borrowed + p.x = 5; //~ ERROR cannot assign to `p.x` because it is borrowed q.x; } @@ -21,8 +17,7 @@ fn c() { let mut p = Point {x: 3, y: 4}; let q = &p.y; - p = Point {x: 5, y: 7};//[ast]~ ERROR cannot assign to `p` - //[mir]~^ ERROR cannot assign to `p` because it is borrowed + p = Point {x: 5, y: 7};//~ ERROR cannot assign to `p` because it is borrowed p.x; // silence warning *q; // stretch loan } @@ -33,8 +28,7 @@ fn d() { let mut p = Point {x: 3, y: 4}; let q = &p.y; - p.y = 5; //[ast]~ ERROR cannot assign to `p.y` - //[mir]~^ ERROR cannot assign to `p.y` because it is borrowed + p.y = 5; //~ ERROR cannot assign to `p.y` because it is borrowed *q; } diff --git a/src/test/ui/borrowck/borrowck-assign-comp.stderr b/src/test/ui/borrowck/borrowck-assign-comp.stderr new file mode 100644 index 0000000000000..2b7cef7b3253b --- /dev/null +++ b/src/test/ui/borrowck/borrowck-assign-comp.stderr @@ -0,0 +1,35 @@ +error[E0506]: cannot assign to `p.x` because it is borrowed + --> $DIR/borrowck-assign-comp.rs:10:5 + | +LL | let q = &p; + | -- borrow of `p.x` occurs here +... +LL | p.x = 5; + | ^^^^^^^ assignment to borrowed `p.x` occurs here +LL | q.x; + | --- borrow later used here + +error[E0506]: cannot assign to `p` because it is borrowed + --> $DIR/borrowck-assign-comp.rs:20:5 + | +LL | let q = &p.y; + | ---- borrow of `p` occurs here +LL | p = Point {x: 5, y: 7}; + | ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `p` occurs here +LL | p.x; // silence warning +LL | *q; // stretch loan + | -- borrow later used here + +error[E0506]: cannot assign to `p.y` because it is borrowed + --> $DIR/borrowck-assign-comp.rs:31:5 + | +LL | let q = &p.y; + | ---- borrow of `p.y` occurs here +LL | p.y = 5; + | ^^^^^^^ assignment to borrowed `p.y` occurs here +LL | *q; + | -- borrow later used here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.nll.stderr b/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.nll.stderr deleted file mode 100644 index 469199d69b91e..0000000000000 --- a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.nll.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0594]: cannot assign to `*s.pointer` which is behind a `&` reference - --> $DIR/borrowck-assign-to-andmut-in-aliasable-loc.rs:9:5 - | -LL | fn a(s: &S) { - | -- help: consider changing this to be a mutable reference: `&mut S<'_>` -LL | *s.pointer += 1; //~ ERROR cannot assign - | ^^^^^^^^^^^^^^^ `s` is a `&` reference, so the data it refers to cannot be written - -error[E0594]: cannot assign to `*s.pointer` which is behind a `&` reference - --> $DIR/borrowck-assign-to-andmut-in-aliasable-loc.rs:17:5 - | -LL | fn c(s: & &mut S) { - | -------- help: consider changing this to be a mutable reference: `&mut &mut S<'_>` -LL | *s.pointer += 1; //~ ERROR cannot assign - | ^^^^^^^^^^^^^^^ `s` is a `&` reference, so the data it refers to cannot be written - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr b/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr index 76e7ee841f827..38fcfbfc2a026 100644 --- a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr +++ b/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr @@ -1,19 +1,18 @@ -error[E0389]: cannot assign to data in a `&` reference +error[E0594]: cannot assign to `*s.pointer` which is behind a `&` reference --> $DIR/borrowck-assign-to-andmut-in-aliasable-loc.rs:9:5 | LL | fn a(s: &S) { - | -- use `&mut S` here to make mutable -LL | *s.pointer += 1; //~ ERROR cannot assign - | ^^^^^^^^^^^^^^^ assignment into an immutable reference + | -- help: consider changing this to be a mutable reference: `&mut S<'_>` +LL | *s.pointer += 1; + | ^^^^^^^^^^^^^^^ `s` is a `&` reference, so the data it refers to cannot be written -error[E0389]: cannot assign to data in a `&` reference +error[E0594]: cannot assign to `*s.pointer` which is behind a `&` reference --> $DIR/borrowck-assign-to-andmut-in-aliasable-loc.rs:17:5 | LL | fn c(s: & &mut S) { - | -------- use `&mut &mut S` here to make mutable -LL | *s.pointer += 1; //~ ERROR cannot assign - | ^^^^^^^^^^^^^^^ assignment into an immutable reference + | -------- help: consider changing this to be a mutable reference: `&mut &mut S<'_>` +LL | *s.pointer += 1; + | ^^^^^^^^^^^^^^^ `s` is a `&` reference, so the data it refers to cannot be written error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0389`. diff --git a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.nll.stderr b/src/test/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.nll.stderr deleted file mode 100644 index 8e3e9d41f8c0e..0000000000000 --- a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.nll.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0503]: cannot use `*y.pointer` because it was mutably borrowed - --> $DIR/borrowck-assign-to-andmut-in-borrowed-loc.rs:18:9 - | -LL | let z = copy_borrowed_ptr(&mut y); - | ------ borrow of `y` occurs here -LL | *y.pointer += 1; //~ ERROR cannot assign - | ^^^^^^^^^^^^^^^ use of borrowed `y` -LL | *z.pointer += 1; - | --------------- borrow later used here - -error[E0506]: cannot assign to `*y.pointer` because it is borrowed - --> $DIR/borrowck-assign-to-andmut-in-borrowed-loc.rs:18:9 - | -LL | let z = copy_borrowed_ptr(&mut y); - | ------ borrow of `*y.pointer` occurs here -LL | *y.pointer += 1; //~ ERROR cannot assign - | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here -LL | *z.pointer += 1; - | --------------- borrow later used here - -error: aborting due to 2 previous errors - -Some errors occurred: E0503, E0506. -For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.rs b/src/test/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.rs index 98080d47c647b..f7aee2b8a939a 100644 --- a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.rs +++ b/src/test/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.rs @@ -15,7 +15,9 @@ fn main() { { let mut y = S { pointer: &mut x }; let z = copy_borrowed_ptr(&mut y); - *y.pointer += 1; //~ ERROR cannot assign + *y.pointer += 1; + //~^ ERROR cannot use `*y.pointer` + //~| ERROR cannot assign to `*y.pointer` *z.pointer += 1; } } diff --git a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr b/src/test/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr index d4639581223de..0b21d113f74ee 100644 --- a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr +++ b/src/test/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr @@ -1,11 +1,26 @@ +error[E0503]: cannot use `*y.pointer` because it was mutably borrowed + --> $DIR/borrowck-assign-to-andmut-in-borrowed-loc.rs:18:9 + | +LL | let z = copy_borrowed_ptr(&mut y); + | ------ borrow of `y` occurs here +LL | *y.pointer += 1; + | ^^^^^^^^^^^^^^^ use of borrowed `y` +... +LL | *z.pointer += 1; + | --------------- borrow later used here + error[E0506]: cannot assign to `*y.pointer` because it is borrowed --> $DIR/borrowck-assign-to-andmut-in-borrowed-loc.rs:18:9 | LL | let z = copy_borrowed_ptr(&mut y); - | - borrow of `*y.pointer` occurs here -LL | *y.pointer += 1; //~ ERROR cannot assign + | ------ borrow of `*y.pointer` occurs here +LL | *y.pointer += 1; | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here +... +LL | *z.pointer += 1; + | --------------- borrow later used here -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0506`. +Some errors have detailed explanations: E0503, E0506. +For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/borrowck/borrowck-assign-to-constants.ast.nll.stderr b/src/test/ui/borrowck/borrowck-assign-to-constants.ast.nll.stderr deleted file mode 100644 index 0a30a490a643b..0000000000000 --- a/src/test/ui/borrowck/borrowck-assign-to-constants.ast.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0594]: cannot assign to immutable static item `foo` - --> $DIR/borrowck-assign-to-constants.rs:8:5 - | -LL | foo = 6; //[ast]~ ERROR cannot assign to immutable static item - | ^^^^^^^ cannot assign - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrowck-assign-to-constants.ast.stderr b/src/test/ui/borrowck/borrowck-assign-to-constants.ast.stderr deleted file mode 100644 index 4111f55d9f2b2..0000000000000 --- a/src/test/ui/borrowck/borrowck-assign-to-constants.ast.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0594]: cannot assign to immutable static item - --> $DIR/borrowck-assign-to-constants.rs:8:5 - | -LL | foo = 6; //[ast]~ ERROR cannot assign to immutable static item - | ^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrowck-assign-to-constants.mir.stderr b/src/test/ui/borrowck/borrowck-assign-to-constants.mir.stderr deleted file mode 100644 index 0a30a490a643b..0000000000000 --- a/src/test/ui/borrowck/borrowck-assign-to-constants.mir.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0594]: cannot assign to immutable static item `foo` - --> $DIR/borrowck-assign-to-constants.rs:8:5 - | -LL | foo = 6; //[ast]~ ERROR cannot assign to immutable static item - | ^^^^^^^ cannot assign - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrowck-assign-to-constants.rs b/src/test/ui/borrowck/borrowck-assign-to-constants.rs index 768b2a5f7438e..5881dccf61ab3 100644 --- a/src/test/ui/borrowck/borrowck-assign-to-constants.rs +++ b/src/test/ui/borrowck/borrowck-assign-to-constants.rs @@ -1,10 +1,6 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - static foo: isize = 5; fn main() { // assigning to various global constants - foo = 6; //[ast]~ ERROR cannot assign to immutable static item - //[mir]~^ ERROR cannot assign to immutable static item `foo` + foo = 6; //~ ERROR cannot assign to immutable static item `foo` } diff --git a/src/test/ui/borrowck/borrowck-assign-to-constants.stderr b/src/test/ui/borrowck/borrowck-assign-to-constants.stderr new file mode 100644 index 0000000000000..800003caa0f34 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-assign-to-constants.stderr @@ -0,0 +1,8 @@ +error[E0594]: cannot assign to immutable static item `foo` + --> $DIR/borrowck-assign-to-constants.rs:5:5 + | +LL | foo = 6; + | ^^^^^^^ cannot assign + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.nll.stderr b/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.nll.stderr deleted file mode 100644 index 53aaa4a2957e9..0000000000000 --- a/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/borrowck-auto-mut-ref-to-immut-var.rs:15:5 - | -LL | let x = Foo { x: 3 }; - | - help: consider changing this to be mutable: `mut x` -LL | x.printme(); //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr b/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr index b48473a884c2f..3ed76c13f6a7b 100644 --- a/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr +++ b/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr @@ -1,10 +1,10 @@ -error[E0596]: cannot borrow immutable local variable `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-auto-mut-ref-to-immut-var.rs:15:5 | LL | let x = Foo { x: 3 }; - | - help: make this binding mutable: `mut x` -LL | x.printme(); //~ ERROR cannot borrow - | ^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut x` +LL | x.printme(); + | ^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-autoref-3261.nll.stderr b/src/test/ui/borrowck/borrowck-autoref-3261.nll.stderr deleted file mode 100644 index 9e62534c6718a..0000000000000 --- a/src/test/ui/borrowck/borrowck-autoref-3261.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-autoref-3261.rs:15:9 - | -LL | (&mut x).with( - | -------- ---- first borrow later used by call - | | - | first mutable borrow occurs here -LL | |opt| { //~ ERROR cannot borrow `x` as mutable more than once at a time - | ^^^^^ second mutable borrow occurs here -... -LL | x = X(Either::Left((0, 0))); - | - second borrow occurs due to use of `x` in closure - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-autoref-3261.stderr b/src/test/ui/borrowck/borrowck-autoref-3261.stderr index 7a5430ac15c37..c2dfb687e8ee9 100644 --- a/src/test/ui/borrowck/borrowck-autoref-3261.stderr +++ b/src/test/ui/borrowck/borrowck-autoref-3261.stderr @@ -2,15 +2,14 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/borrowck-autoref-3261.rs:15:9 | LL | (&mut x).with( - | - first mutable borrow occurs here -LL | |opt| { //~ ERROR cannot borrow `x` as mutable more than once at a time + | -------- ---- first borrow later used by call + | | + | first mutable borrow occurs here +LL | |opt| { | ^^^^^ second mutable borrow occurs here ... LL | x = X(Either::Left((0, 0))); - | - borrow occurs due to use of `x` in closure -... -LL | }) - | - first borrow ends here + | - second borrow occurs due to use of `x` in closure error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-bad-nested-calls-free.nll.stderr b/src/test/ui/borrowck/borrowck-bad-nested-calls-free.nll.stderr deleted file mode 100644 index 1732628d40f83..0000000000000 --- a/src/test/ui/borrowck/borrowck-bad-nested-calls-free.nll.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-bad-nested-calls-free.rs:25:17 - | -LL | add( - | --- immutable borrow later used by call -LL | &*a, - | --- immutable borrow occurs here -LL | rewrite(&mut a)); //~ ERROR cannot borrow - | ^^^^^^ mutable borrow occurs here - -error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-bad-nested-calls-free.rs:32:17 - | -LL | add( - | --- immutable borrow later used by call -LL | &*a, - | --- immutable borrow occurs here -LL | rewrite(&mut a)); //~ ERROR cannot borrow - | ^^^^^^ mutable borrow occurs here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-bad-nested-calls-free.stderr b/src/test/ui/borrowck/borrowck-bad-nested-calls-free.stderr index 165530d270af9..e273a778fdad5 100644 --- a/src/test/ui/borrowck/borrowck-bad-nested-calls-free.stderr +++ b/src/test/ui/borrowck/borrowck-bad-nested-calls-free.stderr @@ -1,22 +1,22 @@ -error[E0502]: cannot borrow `a` as mutable because `*a` is also borrowed as immutable - --> $DIR/borrowck-bad-nested-calls-free.rs:25:22 +error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-bad-nested-calls-free.rs:25:17 | +LL | add( + | --- immutable borrow later used by call LL | &*a, - | -- immutable borrow occurs here -LL | rewrite(&mut a)); //~ ERROR cannot borrow - | ^ - immutable borrow ends here - | | - | mutable borrow occurs here + | --- immutable borrow occurs here +LL | rewrite(&mut a)); + | ^^^^^^ mutable borrow occurs here -error[E0502]: cannot borrow `a` as mutable because `*a` is also borrowed as immutable - --> $DIR/borrowck-bad-nested-calls-free.rs:32:22 +error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-bad-nested-calls-free.rs:32:17 | +LL | add( + | --- immutable borrow later used by call LL | &*a, - | -- immutable borrow occurs here -LL | rewrite(&mut a)); //~ ERROR cannot borrow - | ^ - immutable borrow ends here - | | - | mutable borrow occurs here + | --- immutable borrow occurs here +LL | rewrite(&mut a)); + | ^^^^^^ mutable borrow occurs here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-bad-nested-calls-move.nll.stderr b/src/test/ui/borrowck/borrowck-bad-nested-calls-move.nll.stderr deleted file mode 100644 index 117567cba192b..0000000000000 --- a/src/test/ui/borrowck/borrowck-bad-nested-calls-move.nll.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0505]: cannot move out of `a` because it is borrowed - --> $DIR/borrowck-bad-nested-calls-move.rs:25:9 - | -LL | add( - | --- borrow later used by call -LL | &*a, - | --- borrow of `*a` occurs here -LL | a); //~ ERROR cannot move - | ^ move out of `a` occurs here - -error[E0505]: cannot move out of `a` because it is borrowed - --> $DIR/borrowck-bad-nested-calls-move.rs:32:9 - | -LL | add( - | --- borrow later used by call -LL | &*a, - | --- borrow of `*a` occurs here -LL | a); //~ ERROR cannot move - | ^ move out of `a` occurs here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-bad-nested-calls-move.stderr b/src/test/ui/borrowck/borrowck-bad-nested-calls-move.stderr index b2c680f39521e..371bcf2b69cf8 100644 --- a/src/test/ui/borrowck/borrowck-bad-nested-calls-move.stderr +++ b/src/test/ui/borrowck/borrowck-bad-nested-calls-move.stderr @@ -1,17 +1,21 @@ error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/borrowck-bad-nested-calls-move.rs:25:9 | +LL | add( + | --- borrow later used by call LL | &*a, - | -- borrow of `*a` occurs here -LL | a); //~ ERROR cannot move + | --- borrow of `*a` occurs here +LL | a); | ^ move out of `a` occurs here error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/borrowck-bad-nested-calls-move.rs:32:9 | +LL | add( + | --- borrow later used by call LL | &*a, - | -- borrow of `*a` occurs here -LL | a); //~ ERROR cannot move + | --- borrow of `*a` occurs here +LL | a); | ^ move out of `a` occurs here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-block-unint.nll.stderr b/src/test/ui/borrowck/borrowck-block-unint.nll.stderr deleted file mode 100644 index ea17fafc93908..0000000000000 --- a/src/test/ui/borrowck/borrowck-block-unint.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/borrowck-block-unint.rs:4:11 - | -LL | force(|| { //~ ERROR capture of possibly uninitialized variable: `x` - | ^^ use of possibly uninitialized `x` -LL | println!("{}", x); - | - borrow occurs due to use in closure - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-block-unint.rs b/src/test/ui/borrowck/borrowck-block-unint.rs index 3c6e9cb5578b4..1fed2d503bd35 100644 --- a/src/test/ui/borrowck/borrowck-block-unint.rs +++ b/src/test/ui/borrowck/borrowck-block-unint.rs @@ -1,7 +1,7 @@ fn force(f: F) where F: FnOnce() { f(); } fn main() { let x: isize; - force(|| { //~ ERROR capture of possibly uninitialized variable: `x` + force(|| { //~ ERROR borrow of possibly uninitialized variable: `x` println!("{}", x); }); } diff --git a/src/test/ui/borrowck/borrowck-block-unint.stderr b/src/test/ui/borrowck/borrowck-block-unint.stderr index 6e7af76fc2e89..d2a49962bafca 100644 --- a/src/test/ui/borrowck/borrowck-block-unint.stderr +++ b/src/test/ui/borrowck/borrowck-block-unint.stderr @@ -1,8 +1,10 @@ -error[E0381]: capture of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly uninitialized variable: `x` --> $DIR/borrowck-block-unint.rs:4:11 | -LL | force(|| { //~ ERROR capture of possibly uninitialized variable: `x` +LL | force(|| { | ^^ use of possibly uninitialized `x` +LL | println!("{}", x); + | - borrow occurs due to use in closure error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.nll.stderr deleted file mode 100644 index d1377fd439a4f..0000000000000 --- a/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.nll.stderr +++ /dev/null @@ -1,116 +0,0 @@ -error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-owned-ptr.rs:18:17 - | -LL | let bar1 = &mut foo.bar1; - | ------------- first mutable borrow occurs here -LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ second mutable borrow occurs here -LL | *bar1; - | ----- first borrow later used here - -error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:25:17 - | -LL | let bar1 = &mut foo.bar1; - | ------------- mutable borrow occurs here -LL | let _bar2 = &foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^ immutable borrow occurs here -LL | *bar1; - | ----- mutable borrow later used here - -error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:32:17 - | -LL | let bar1 = &foo.bar1; - | --------- immutable borrow occurs here -LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ mutable borrow occurs here -LL | *bar1; - | ----- immutable borrow later used here - -error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-owned-ptr.rs:62:21 - | -LL | let bar1 = &mut foo.bar1; - | ------------- first mutable borrow occurs here -LL | match *foo { -LL | Foo { bar1: ref mut _bar1, bar2: _ } => {} - | ^^^^^^^^^^^^^ second mutable borrow occurs here -... -LL | *bar1; - | ----- first borrow later used here - -error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:71:17 - | -LL | let bar1 = &mut foo.bar1.int1; - | ------------------ mutable borrow occurs here -LL | let _foo1 = &foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^ immutable borrow occurs here -LL | let _foo2 = &*foo; //~ ERROR cannot borrow -LL | *bar1; - | ----- mutable borrow later used here - -error[E0502]: cannot borrow `*foo` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:72:17 - | -LL | let bar1 = &mut foo.bar1.int1; - | ------------------ mutable borrow occurs here -LL | let _foo1 = &foo.bar1; //~ ERROR cannot borrow -LL | let _foo2 = &*foo; //~ ERROR cannot borrow - | ^^^^^ immutable borrow occurs here -LL | *bar1; - | ----- mutable borrow later used here - -error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-owned-ptr.rs:79:17 - | -LL | let bar1 = &mut foo.bar1.int1; - | ------------------ first mutable borrow occurs here -LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ second mutable borrow occurs here -LL | *bar1; - | ----- first borrow later used here - -error[E0499]: cannot borrow `*foo` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-owned-ptr.rs:86:17 - | -LL | let bar1 = &mut foo.bar1.int1; - | ------------------ first mutable borrow occurs here -LL | let _foo2 = &mut *foo; //~ ERROR cannot borrow - | ^^^^^^^^^ second mutable borrow occurs here -LL | *bar1; - | ----- first borrow later used here - -error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:93:17 - | -LL | let bar1 = &foo.bar1.int1; - | -------------- immutable borrow occurs here -LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ mutable borrow occurs here -LL | *bar1; - | ----- immutable borrow later used here - -error[E0502]: cannot borrow `*foo` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:100:17 - | -LL | let bar1 = &foo.bar1.int1; - | -------------- immutable borrow occurs here -LL | let _foo2 = &mut *foo; //~ ERROR cannot borrow - | ^^^^^^^^^ mutable borrow occurs here -LL | *bar1; - | ----- immutable borrow later used here - -error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:121:16 - | -LL | let foo = make_foo(); - | --- help: consider changing this to be mutable: `mut foo` -LL | let bar1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ cannot borrow as mutable - -error: aborting due to 11 previous errors - -Some errors occurred: E0499, E0502, E0596. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.rs b/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.rs index 1435837bf3bae..353e4e9f75e6c 100644 --- a/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.rs +++ b/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.rs @@ -43,15 +43,17 @@ fn borrow_same_field_twice_imm_imm() { fn borrow_both_fields_mut() { let mut foo = make_foo(); let bar1 = &mut foo.bar1; - let _bar2 = &mut foo.bar2; //~ ERROR cannot borrow + let _bar2 = &mut foo.bar2; *bar1; } fn borrow_both_mut_pattern() { let mut foo = make_foo(); match *foo { - Foo { bar1: ref mut _bar1, bar2: ref mut _bar2 } => {} - //~^ ERROR cannot borrow + Foo { bar1: ref mut _bar1, bar2: ref mut _bar2 } => { + *_bar1; + *_bar2; + } } } @@ -112,8 +114,7 @@ fn borrow_imm_and_base_imm() { fn borrow_mut_and_imm() { let mut foo = make_foo(); let bar1 = &mut foo.bar1; - let _foo1 = &foo.bar2; //~ ERROR cannot borrow - *bar1; + let _foo1 = &foo.bar2; } fn borrow_mut_from_imm() { @@ -125,7 +126,7 @@ fn borrow_mut_from_imm() { fn borrow_long_path_both_mut() { let mut foo = make_foo(); let bar1 = &mut foo.bar1.int1; - let foo1 = &mut foo.bar2.int2; //~ ERROR cannot borrow + let foo1 = &mut foo.bar2.int2; *bar1; *foo1; } diff --git a/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr b/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr index e116cb70c1c31..e00d69f89d36e 100644 --- a/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr @@ -1,168 +1,116 @@ error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-owned-ptr.rs:18:22 + --> $DIR/borrowck-borrow-from-owned-ptr.rs:18:17 | LL | let bar1 = &mut foo.bar1; - | -------- first mutable borrow occurs here -LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ second mutable borrow occurs here + | ------------- first mutable borrow occurs here +LL | let _bar2 = &mut foo.bar1; + | ^^^^^^^^^^^^^ second mutable borrow occurs here LL | *bar1; -LL | } - | - first borrow ends here + | ----- first borrow later used here error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:25:18 + --> $DIR/borrowck-borrow-from-owned-ptr.rs:25:17 | LL | let bar1 = &mut foo.bar1; - | -------- mutable borrow occurs here -LL | let _bar2 = &foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ immutable borrow occurs here + | ------------- mutable borrow occurs here +LL | let _bar2 = &foo.bar1; + | ^^^^^^^^^ immutable borrow occurs here LL | *bar1; -LL | } - | - mutable borrow ends here + | ----- mutable borrow later used here error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:32:22 + --> $DIR/borrowck-borrow-from-owned-ptr.rs:32:17 | LL | let bar1 = &foo.bar1; - | -------- immutable borrow occurs here -LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ mutable borrow occurs here + | --------- immutable borrow occurs here +LL | let _bar2 = &mut foo.bar1; + | ^^^^^^^^^^^^^ mutable borrow occurs here LL | *bar1; -LL | } - | - immutable borrow ends here - -error[E0499]: cannot borrow `foo` (via `foo.bar2`) as mutable more than once at a time - --> $DIR/borrowck-borrow-from-owned-ptr.rs:46:22 - | -LL | let bar1 = &mut foo.bar1; - | -------- first mutable borrow occurs here (via `foo.bar1`) -LL | let _bar2 = &mut foo.bar2; //~ ERROR cannot borrow - | ^^^^^^^^ second mutable borrow occurs here (via `foo.bar2`) -LL | *bar1; -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `foo` (via `foo.bar2`) as mutable more than once at a time - --> $DIR/borrowck-borrow-from-owned-ptr.rs:53:42 - | -LL | Foo { bar1: ref mut _bar1, bar2: ref mut _bar2 } => {} - | ------------- ^^^^^^^^^^^^^ second mutable borrow occurs here (via `foo.bar2`) - | | - | first mutable borrow occurs here (via `foo.bar1`) -LL | //~^ ERROR cannot borrow -LL | } - | - first borrow ends here + | ----- immutable borrow later used here error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-owned-ptr.rs:62:21 + --> $DIR/borrowck-borrow-from-owned-ptr.rs:64:21 | LL | let bar1 = &mut foo.bar1; - | -------- first mutable borrow occurs here + | ------------- first mutable borrow occurs here LL | match *foo { LL | Foo { bar1: ref mut _bar1, bar2: _ } => {} | ^^^^^^^^^^^^^ second mutable borrow occurs here ... -LL | } - | - first borrow ends here +LL | *bar1; + | ----- first borrow later used here -error[E0502]: cannot borrow `foo.bar1` as immutable because `foo.bar1.int1` is also borrowed as mutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:71:18 +error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-borrow-from-owned-ptr.rs:73:17 | LL | let bar1 = &mut foo.bar1.int1; - | ------------- mutable borrow occurs here -LL | let _foo1 = &foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here + | ------------------ mutable borrow occurs here +LL | let _foo1 = &foo.bar1; + | ^^^^^^^^^ immutable borrow occurs here +LL | let _foo2 = &*foo; +LL | *bar1; + | ----- mutable borrow later used here -error[E0502]: cannot borrow `*foo` as immutable because `foo.bar1.int1` is also borrowed as mutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:72:18 +error[E0502]: cannot borrow `*foo` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-borrow-from-owned-ptr.rs:74:17 | LL | let bar1 = &mut foo.bar1.int1; - | ------------- mutable borrow occurs here -LL | let _foo1 = &foo.bar1; //~ ERROR cannot borrow -LL | let _foo2 = &*foo; //~ ERROR cannot borrow - | ^^^^ immutable borrow occurs here + | ------------------ mutable borrow occurs here +LL | let _foo1 = &foo.bar1; +LL | let _foo2 = &*foo; + | ^^^^^ immutable borrow occurs here LL | *bar1; -LL | } - | - mutable borrow ends here + | ----- mutable borrow later used here error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-owned-ptr.rs:79:22 + --> $DIR/borrowck-borrow-from-owned-ptr.rs:81:17 | LL | let bar1 = &mut foo.bar1.int1; - | ------------- first mutable borrow occurs here -LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ second mutable borrow occurs here + | ------------------ first mutable borrow occurs here +LL | let _foo1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ second mutable borrow occurs here LL | *bar1; -LL | } - | - first borrow ends here + | ----- first borrow later used here error[E0499]: cannot borrow `*foo` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-owned-ptr.rs:86:22 + --> $DIR/borrowck-borrow-from-owned-ptr.rs:88:17 | LL | let bar1 = &mut foo.bar1.int1; - | ------------- first mutable borrow occurs here -LL | let _foo2 = &mut *foo; //~ ERROR cannot borrow - | ^^^^ second mutable borrow occurs here + | ------------------ first mutable borrow occurs here +LL | let _foo2 = &mut *foo; + | ^^^^^^^^^ second mutable borrow occurs here LL | *bar1; -LL | } - | - first borrow ends here + | ----- first borrow later used here -error[E0502]: cannot borrow `foo.bar1` as mutable because `foo.bar1.int1` is also borrowed as immutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:93:22 +error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-borrow-from-owned-ptr.rs:95:17 | LL | let bar1 = &foo.bar1.int1; - | ------------- immutable borrow occurs here -LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ mutable borrow occurs here + | -------------- immutable borrow occurs here +LL | let _foo1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ mutable borrow occurs here LL | *bar1; -LL | } - | - immutable borrow ends here + | ----- immutable borrow later used here -error[E0502]: cannot borrow `*foo` as mutable because `foo.bar1.int1` is also borrowed as immutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:100:22 +error[E0502]: cannot borrow `*foo` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-borrow-from-owned-ptr.rs:102:17 | LL | let bar1 = &foo.bar1.int1; - | ------------- immutable borrow occurs here -LL | let _foo2 = &mut *foo; //~ ERROR cannot borrow - | ^^^^ mutable borrow occurs here -LL | *bar1; -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `foo` (via `foo.bar2`) as immutable because `foo` is also borrowed as mutable (via `foo.bar1`) - --> $DIR/borrowck-borrow-from-owned-ptr.rs:115:18 - | -LL | let bar1 = &mut foo.bar1; - | -------- mutable borrow occurs here (via `foo.bar1`) -LL | let _foo1 = &foo.bar2; //~ ERROR cannot borrow - | ^^^^^^^^ immutable borrow of `foo.bar2` -- which overlaps with `foo.bar1` -- occurs here + | -------------- immutable borrow occurs here +LL | let _foo2 = &mut *foo; + | ^^^^^^^^^ mutable borrow occurs here LL | *bar1; -LL | } - | - mutable borrow ends here + | ----- immutable borrow later used here -error[E0596]: cannot borrow field `foo.bar1` of immutable binding as mutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:121:21 +error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable + --> $DIR/borrowck-borrow-from-owned-ptr.rs:122:16 | LL | let foo = make_foo(); - | --- help: make this binding mutable: `mut foo` -LL | let bar1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0499]: cannot borrow `foo` (via `foo.bar2.int2`) as mutable more than once at a time - --> $DIR/borrowck-borrow-from-owned-ptr.rs:128:21 - | -LL | let bar1 = &mut foo.bar1.int1; - | ------------- first mutable borrow occurs here (via `foo.bar1.int1`) -LL | let foo1 = &mut foo.bar2.int2; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ second mutable borrow occurs here (via `foo.bar2.int2`) -... -LL | } - | - first borrow ends here + | --- help: consider changing this to be mutable: `mut foo` +LL | let bar1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ cannot borrow as mutable -error: aborting due to 15 previous errors +error: aborting due to 11 previous errors -Some errors occurred: E0499, E0502, E0596. +Some errors have detailed explanations: E0499, E0502, E0596. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.nll.stderr deleted file mode 100644 index f53cb32a5679e..0000000000000 --- a/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.nll.stderr +++ /dev/null @@ -1,116 +0,0 @@ -error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-stack-variable.rs:18:17 - | -LL | let bar1 = &mut foo.bar1; - | ------------- first mutable borrow occurs here -LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ second mutable borrow occurs here -LL | *bar1; - | ----- first borrow later used here - -error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:25:17 - | -LL | let bar1 = &mut foo.bar1; - | ------------- mutable borrow occurs here -LL | let _bar2 = &foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^ immutable borrow occurs here -LL | *bar1; - | ----- mutable borrow later used here - -error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:32:17 - | -LL | let bar1 = &foo.bar1; - | --------- immutable borrow occurs here -LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ mutable borrow occurs here -LL | *bar1; - | ----- immutable borrow later used here - -error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-stack-variable.rs:61:21 - | -LL | let bar1 = &mut foo.bar1; - | ------------- first mutable borrow occurs here -LL | match foo { -LL | Foo { bar1: ref mut _bar1, bar2: _ } => {} // - | ^^^^^^^^^^^^^ second mutable borrow occurs here -... -LL | *bar1; - | ----- first borrow later used here - -error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:70:17 - | -LL | let bar1 = &mut foo.bar1.int1; - | ------------------ mutable borrow occurs here -LL | let _foo1 = &foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^ immutable borrow occurs here -LL | let _foo2 = &foo; //~ ERROR cannot borrow -LL | *bar1; - | ----- mutable borrow later used here - -error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:71:17 - | -LL | let bar1 = &mut foo.bar1.int1; - | ------------------ mutable borrow occurs here -LL | let _foo1 = &foo.bar1; //~ ERROR cannot borrow -LL | let _foo2 = &foo; //~ ERROR cannot borrow - | ^^^^ immutable borrow occurs here -LL | *bar1; - | ----- mutable borrow later used here - -error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-stack-variable.rs:78:17 - | -LL | let bar1 = &mut foo.bar1.int1; - | ------------------ first mutable borrow occurs here -LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ second mutable borrow occurs here -LL | *bar1; - | ----- first borrow later used here - -error[E0499]: cannot borrow `foo` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-stack-variable.rs:85:17 - | -LL | let bar1 = &mut foo.bar1.int1; - | ------------------ first mutable borrow occurs here -LL | let _foo2 = &mut foo; //~ ERROR cannot borrow - | ^^^^^^^^ second mutable borrow occurs here -LL | *bar1; - | ----- first borrow later used here - -error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:92:17 - | -LL | let bar1 = &foo.bar1.int1; - | -------------- immutable borrow occurs here -LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ mutable borrow occurs here -LL | *bar1; - | ----- immutable borrow later used here - -error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:99:17 - | -LL | let bar1 = &foo.bar1.int1; - | -------------- immutable borrow occurs here -LL | let _foo2 = &mut foo; //~ ERROR cannot borrow - | ^^^^^^^^ mutable borrow occurs here -LL | *bar1; - | ----- immutable borrow later used here - -error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:120:16 - | -LL | let foo = make_foo(); - | --- help: consider changing this to be mutable: `mut foo` -LL | let bar1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ cannot borrow as mutable - -error: aborting due to 11 previous errors - -Some errors occurred: E0499, E0502, E0596. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.stderr b/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.stderr index 2c446dfee44b2..ce5ce56dea27f 100644 --- a/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.stderr @@ -1,124 +1,116 @@ error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-stack-variable.rs:18:22 + --> $DIR/borrowck-borrow-from-stack-variable.rs:18:17 | LL | let bar1 = &mut foo.bar1; - | -------- first mutable borrow occurs here -LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ second mutable borrow occurs here + | ------------- first mutable borrow occurs here +LL | let _bar2 = &mut foo.bar1; + | ^^^^^^^^^^^^^ second mutable borrow occurs here LL | *bar1; -LL | } - | - first borrow ends here + | ----- first borrow later used here error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:25:18 + --> $DIR/borrowck-borrow-from-stack-variable.rs:25:17 | LL | let bar1 = &mut foo.bar1; - | -------- mutable borrow occurs here -LL | let _bar2 = &foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ immutable borrow occurs here + | ------------- mutable borrow occurs here +LL | let _bar2 = &foo.bar1; + | ^^^^^^^^^ immutable borrow occurs here LL | *bar1; -LL | } - | - mutable borrow ends here + | ----- mutable borrow later used here error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:32:22 + --> $DIR/borrowck-borrow-from-stack-variable.rs:32:17 | LL | let bar1 = &foo.bar1; - | -------- immutable borrow occurs here -LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ mutable borrow occurs here + | --------- immutable borrow occurs here +LL | let _bar2 = &mut foo.bar1; + | ^^^^^^^^^^^^^ mutable borrow occurs here LL | *bar1; -LL | } - | - immutable borrow ends here + | ----- immutable borrow later used here error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time --> $DIR/borrowck-borrow-from-stack-variable.rs:61:21 | LL | let bar1 = &mut foo.bar1; - | -------- first mutable borrow occurs here + | ------------- first mutable borrow occurs here LL | match foo { LL | Foo { bar1: ref mut _bar1, bar2: _ } => {} // | ^^^^^^^^^^^^^ second mutable borrow occurs here ... -LL | } - | - first borrow ends here +LL | *bar1; + | ----- first borrow later used here -error[E0502]: cannot borrow `foo.bar1` as immutable because `foo.bar1.int1` is also borrowed as mutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:70:18 +error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-borrow-from-stack-variable.rs:70:17 | LL | let bar1 = &mut foo.bar1.int1; - | ------------- mutable borrow occurs here -LL | let _foo1 = &foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here + | ------------------ mutable borrow occurs here +LL | let _foo1 = &foo.bar1; + | ^^^^^^^^^ immutable borrow occurs here +LL | let _foo2 = &foo; +LL | *bar1; + | ----- mutable borrow later used here -error[E0502]: cannot borrow `foo` as immutable because `foo.bar1.int1` is also borrowed as mutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:71:18 +error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-borrow-from-stack-variable.rs:71:17 | LL | let bar1 = &mut foo.bar1.int1; - | ------------- mutable borrow occurs here -LL | let _foo1 = &foo.bar1; //~ ERROR cannot borrow -LL | let _foo2 = &foo; //~ ERROR cannot borrow - | ^^^ immutable borrow occurs here + | ------------------ mutable borrow occurs here +LL | let _foo1 = &foo.bar1; +LL | let _foo2 = &foo; + | ^^^^ immutable borrow occurs here LL | *bar1; -LL | } - | - mutable borrow ends here + | ----- mutable borrow later used here error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-stack-variable.rs:78:22 + --> $DIR/borrowck-borrow-from-stack-variable.rs:78:17 | LL | let bar1 = &mut foo.bar1.int1; - | ------------- first mutable borrow occurs here -LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ second mutable borrow occurs here + | ------------------ first mutable borrow occurs here +LL | let _foo1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ second mutable borrow occurs here LL | *bar1; -LL | } - | - first borrow ends here + | ----- first borrow later used here error[E0499]: cannot borrow `foo` as mutable more than once at a time - --> $DIR/borrowck-borrow-from-stack-variable.rs:85:22 + --> $DIR/borrowck-borrow-from-stack-variable.rs:85:17 | LL | let bar1 = &mut foo.bar1.int1; - | ------------- first mutable borrow occurs here -LL | let _foo2 = &mut foo; //~ ERROR cannot borrow - | ^^^ second mutable borrow occurs here + | ------------------ first mutable borrow occurs here +LL | let _foo2 = &mut foo; + | ^^^^^^^^ second mutable borrow occurs here LL | *bar1; -LL | } - | - first borrow ends here + | ----- first borrow later used here -error[E0502]: cannot borrow `foo.bar1` as mutable because `foo.bar1.int1` is also borrowed as immutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:92:22 +error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-borrow-from-stack-variable.rs:92:17 | LL | let bar1 = &foo.bar1.int1; - | ------------- immutable borrow occurs here -LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ mutable borrow occurs here + | -------------- immutable borrow occurs here +LL | let _foo1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ mutable borrow occurs here LL | *bar1; -LL | } - | - immutable borrow ends here + | ----- immutable borrow later used here -error[E0502]: cannot borrow `foo` as mutable because `foo.bar1.int1` is also borrowed as immutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:99:22 +error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-borrow-from-stack-variable.rs:99:17 | LL | let bar1 = &foo.bar1.int1; - | ------------- immutable borrow occurs here -LL | let _foo2 = &mut foo; //~ ERROR cannot borrow - | ^^^ mutable borrow occurs here + | -------------- immutable borrow occurs here +LL | let _foo2 = &mut foo; + | ^^^^^^^^ mutable borrow occurs here LL | *bar1; -LL | } - | - immutable borrow ends here + | ----- immutable borrow later used here -error[E0596]: cannot borrow field `foo.bar1` of immutable binding as mutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:120:21 +error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable + --> $DIR/borrowck-borrow-from-stack-variable.rs:120:16 | LL | let foo = make_foo(); - | --- help: make this binding mutable: `mut foo` -LL | let bar1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ cannot mutably borrow field of immutable binding + | --- help: consider changing this to be mutable: `mut foo` +LL | let bar1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to 11 previous errors -Some errors occurred: E0499, E0502, E0596. +Some errors have detailed explanations: E0499, E0502, E0596. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-borrow-from-temporary.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-from-temporary.nll.stderr deleted file mode 100644 index 52bc3e9829674..0000000000000 --- a/src/test/ui/borrowck/borrowck-borrow-from-temporary.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0515]: cannot return value referencing temporary value - --> $DIR/borrowck-borrow-from-temporary.rs:10:5 - | -LL | let &Foo(ref x) = &id(Foo(3)); //~ ERROR borrowed value does not live long enough - | ---------- temporary value created here -LL | x - | ^ returns a value referencing data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/borrowck-borrow-from-temporary.rs b/src/test/ui/borrowck/borrowck-borrow-from-temporary.rs index e7ca1a90f8c93..92f3ffd57a17d 100644 --- a/src/test/ui/borrowck/borrowck-borrow-from-temporary.rs +++ b/src/test/ui/borrowck/borrowck-borrow-from-temporary.rs @@ -6,8 +6,8 @@ fn id(x: T) -> T { x } struct Foo(isize); fn foo<'a>() -> &'a isize { - let &Foo(ref x) = &id(Foo(3)); //~ ERROR borrowed value does not live long enough - x + let &Foo(ref x) = &id(Foo(3)); + x //~ ERROR cannot return value referencing temporary value } pub fn main() { diff --git a/src/test/ui/borrowck/borrowck-borrow-from-temporary.stderr b/src/test/ui/borrowck/borrowck-borrow-from-temporary.stderr index 0726e3d5d5e60..71bf052c93d61 100644 --- a/src/test/ui/borrowck/borrowck-borrow-from-temporary.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-from-temporary.stderr @@ -1,18 +1,11 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/borrowck-borrow-from-temporary.rs:9:24 +error[E0515]: cannot return value referencing temporary value + --> $DIR/borrowck-borrow-from-temporary.rs:10:5 | -LL | let &Foo(ref x) = &id(Foo(3)); //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^^ temporary value does not live long enough +LL | let &Foo(ref x) = &id(Foo(3)); + | ---------- temporary value created here LL | x -LL | } - | - temporary value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 8:8... - --> $DIR/borrowck-borrow-from-temporary.rs:8:8 - | -LL | fn foo<'a>() -> &'a isize { - | ^^ + | ^ returns a value referencing data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.nll.stderr deleted file mode 100644 index 7d7e305a31f31..0000000000000 --- a/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `*a` as mutable, as `a` is not declared as mutable - --> $DIR/borrowck-borrow-immut-deref-of-box-as-mut.rs:12:5 - | -LL | let a: Box<_> = box A; - | - help: consider changing this to be mutable: `mut a` -LL | a.foo(); - | ^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs b/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs index 8d528182c0d35..bc820ee9f9141 100644 --- a/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs +++ b/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs @@ -10,5 +10,5 @@ impl A { pub fn main() { let a: Box<_> = box A; a.foo(); - //~^ ERROR cannot borrow immutable `Box` content `*a` as mutable + //~^ ERROR cannot borrow `*a` as mutable, as `a` is not declared as mutable [E0596] } diff --git a/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr b/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr index 2c989b2957617..7d7e305a31f31 100644 --- a/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr @@ -1,8 +1,8 @@ -error[E0596]: cannot borrow immutable `Box` content `*a` as mutable +error[E0596]: cannot borrow `*a` as mutable, as `a` is not declared as mutable --> $DIR/borrowck-borrow-immut-deref-of-box-as-mut.rs:12:5 | LL | let a: Box<_> = box A; - | - help: make this binding mutable: `mut a` + | - help: consider changing this to be mutable: `mut a` LL | a.foo(); | ^ cannot borrow as mutable diff --git a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.nll.stderr deleted file mode 100644 index 82b9449de5071..0000000000000 --- a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.nll.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0594]: cannot assign to `**t1` which is behind a `&` reference - --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:9:5 - | -LL | let t1 = t0; - | -- help: consider changing this to be a mutable reference: `&mut &mut isize` -LL | let p: &isize = &**t0; -LL | **t1 = 22; //~ ERROR cannot assign - | ^^^^^^^^^ `t1` is a `&` reference, so the data it refers to cannot be written - -error[E0502]: cannot borrow `**t0` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:14:21 - | -LL | let t1 = &mut *t0; - | -------- mutable borrow occurs here -LL | let p: &isize = &**t0; //~ ERROR cannot borrow - | ^^^^^ immutable borrow occurs here -LL | **t1 = 22; - | --------- mutable borrow later used here - -error[E0596]: cannot borrow `**t0` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:19:26 - | -LL | fn foo4(t0: & &mut isize) { - | ------------ help: consider changing this to be a mutable reference: `&mut &mut isize` -LL | let x: &mut isize = &mut **t0; //~ ERROR cannot borrow - | ^^^^^^^^^ `t0` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to 3 previous errors - -Some errors occurred: E0502, E0594, E0596. -For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr b/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr index ff2969f53480c..8115e3150fbce 100644 --- a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr @@ -1,29 +1,31 @@ -error[E0389]: cannot assign to data in a `&` reference +error[E0594]: cannot assign to `**t1` which is behind a `&` reference --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:9:5 | -LL | **t1 = 22; //~ ERROR cannot assign - | ^^^^^^^^^ assignment into an immutable reference +LL | let t1 = t0; + | -- help: consider changing this to be a mutable reference: `&mut &mut isize` +LL | let p: &isize = &**t0; +LL | **t1 = 22; + | ^^^^^^^^^ `t1` is a `&` reference, so the data it refers to cannot be written -error[E0502]: cannot borrow `**t0` as immutable because `*t0` is also borrowed as mutable - --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:14:22 +error[E0502]: cannot borrow `**t0` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:14:21 | LL | let t1 = &mut *t0; - | --- mutable borrow occurs here -LL | let p: &isize = &**t0; //~ ERROR cannot borrow - | ^^^^ immutable borrow occurs here + | -------- mutable borrow occurs here +LL | let p: &isize = &**t0; + | ^^^^^ immutable borrow occurs here LL | **t1 = 22; -LL | } - | - mutable borrow ends here + | --------- mutable borrow later used here -error[E0389]: cannot borrow data mutably in a `&` reference - --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:19:31 +error[E0596]: cannot borrow `**t0` as mutable, as it is behind a `&` reference + --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:19:26 | LL | fn foo4(t0: & &mut isize) { - | ------------ use `&mut &mut isize` here to make mutable -LL | let x: &mut isize = &mut **t0; //~ ERROR cannot borrow - | ^^^^ assignment into an immutable reference + | ------------ help: consider changing this to be a mutable reference: `&mut &mut isize` +LL | let x: &mut isize = &mut **t0; + | ^^^^^^^^^ `t0` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to 3 previous errors -Some errors occurred: E0389, E0502. -For more information about an error, try `rustc --explain E0389`. +Some errors have detailed explanations: E0502, E0596. +For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.nll.stderr deleted file mode 100644 index c329fc9e91083..0000000000000 --- a/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/borrowck-borrow-mut-object-twice.rs:13:5 - | -LL | let y = x.f1(); - | - first mutable borrow occurs here -LL | x.f2(); //~ ERROR cannot borrow `*x` as mutable - | ^ second mutable borrow occurs here -LL | y.use_ref(); - | - first borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.rs b/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.rs index 5e853afd38c87..b4d85b60cd5af 100644 --- a/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.rs +++ b/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.rs @@ -8,7 +8,7 @@ trait Foo { fn f2(&mut self); } -fn test(x: &mut Foo) { +fn test(x: &mut dyn Foo) { let y = x.f1(); x.f2(); //~ ERROR cannot borrow `*x` as mutable y.use_ref(); diff --git a/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.stderr b/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.stderr index abfce9857f7c1..fa0ae318e72cd 100644 --- a/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.stderr @@ -3,11 +3,10 @@ error[E0499]: cannot borrow `*x` as mutable more than once at a time | LL | let y = x.f1(); | - first mutable borrow occurs here -LL | x.f2(); //~ ERROR cannot borrow `*x` as mutable +LL | x.f2(); | ^ second mutable borrow occurs here LL | y.use_ref(); -LL | } - | - first borrow ends here + | - first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.nll.stderr deleted file mode 100644 index ecb013b7a1603..0000000000000 --- a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.nll.stderr +++ /dev/null @@ -1,88 +0,0 @@ -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:47:19 - | -LL | let __isize = &mut x.y; //~ ERROR cannot borrow - | ^^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:51:19 - | -LL | let __isize = &mut x.y; //~ ERROR cannot borrow - | ^^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:59:5 - | -LL | &mut x.y //~ ERROR cannot borrow - | ^^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:63:5 - | -LL | &mut x.y //~ ERROR cannot borrow - | ^^^^^^^^ cannot borrow as mutable - -error[E0594]: cannot assign to data in a `&` reference - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:67:5 - | -LL | x.y = 3; //~ ERROR cannot assign - | ^^^^^^^ cannot assign - -error[E0594]: cannot assign to data in a `&` reference - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:71:5 - | -LL | x.y = 3; //~ ERROR cannot assign - | ^^^^^^^ cannot assign - -error[E0594]: cannot assign to data in a `&` reference - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:75:5 - | -LL | x.y = 3; //~ ERROR cannot assign - | ^^^^^^^ cannot assign - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:83:5 - | -LL | x.set(0, 0); //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:87:5 - | -LL | x.set(0, 0); //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:95:5 - | -LL | x.y_mut() //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:99:5 - | -LL | x.y_mut() //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:103:6 - | -LL | *x.y_mut() = 3; //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:107:6 - | -LL | *x.y_mut() = 3; //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:111:6 - | -LL | *x.y_mut() = 3; //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error: aborting due to 14 previous errors - -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr b/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr index c6f9c655a11dc..dc52685363e39 100644 --- a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr @@ -1,88 +1,87 @@ -error[E0596]: cannot borrow field of immutable binding as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:47:24 +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:47:19 | -LL | let __isize = &mut x.y; //~ ERROR cannot borrow - | ^^^ cannot mutably borrow field of immutable binding +LL | let __isize = &mut x.y; + | ^^^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow field of immutable binding as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:51:24 +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:51:19 | -LL | let __isize = &mut x.y; //~ ERROR cannot borrow - | ^^^ cannot mutably borrow field of immutable binding +LL | let __isize = &mut x.y; + | ^^^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow field of immutable binding as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:59:10 +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:59:5 | -LL | &mut x.y //~ ERROR cannot borrow - | ^^^ cannot mutably borrow field of immutable binding +LL | &mut x.y + | ^^^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow field of immutable binding as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:63:10 +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:63:5 | -LL | &mut x.y //~ ERROR cannot borrow - | ^^^ cannot mutably borrow field of immutable binding +LL | &mut x.y + | ^^^^^^^^ cannot borrow as mutable -error[E0594]: cannot assign to field of immutable binding +error[E0594]: cannot assign to data in a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:67:5 | -LL | x.y = 3; //~ ERROR cannot assign - | ^^^^^^^ cannot mutably borrow field of immutable binding +LL | x.y = 3; + | ^^^^^^^ cannot assign -error[E0594]: cannot assign to field of immutable binding +error[E0594]: cannot assign to data in a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:71:5 | -LL | x.y = 3; //~ ERROR cannot assign - | ^^^^^^^ cannot mutably borrow field of immutable binding +LL | x.y = 3; + | ^^^^^^^ cannot assign -error[E0594]: cannot assign to field of immutable binding +error[E0594]: cannot assign to data in a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:75:5 | -LL | x.y = 3; //~ ERROR cannot assign - | ^^^^^^^ cannot mutably borrow field of immutable binding +LL | x.y = 3; + | ^^^^^^^ cannot assign -error[E0596]: cannot borrow immutable borrowed content as mutable +error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:83:5 | -LL | x.set(0, 0); //~ ERROR cannot borrow +LL | x.set(0, 0); | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content as mutable +error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:87:5 | -LL | x.set(0, 0); //~ ERROR cannot borrow +LL | x.set(0, 0); | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content as mutable +error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:95:5 | -LL | x.y_mut() //~ ERROR cannot borrow +LL | x.y_mut() | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content as mutable +error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:99:5 | -LL | x.y_mut() //~ ERROR cannot borrow +LL | x.y_mut() | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content as mutable +error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:103:6 | -LL | *x.y_mut() = 3; //~ ERROR cannot borrow +LL | *x.y_mut() = 3; | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content as mutable +error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:107:6 | -LL | *x.y_mut() = 3; //~ ERROR cannot borrow +LL | *x.y_mut() = 3; | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content as mutable +error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:111:6 | -LL | *x.y_mut() = 3; //~ ERROR cannot borrow +LL | *x.y_mut() = 3; | ^ cannot borrow as mutable error: aborting due to 14 previous errors -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.nll.stderr deleted file mode 100644 index 1c3131806be2d..0000000000000 --- a/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.nll.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-deref.rs:23:19 - | -LL | let __isize = &mut *x; //~ ERROR cannot borrow - | ^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-deref.rs:27:19 - | -LL | let __isize = &mut *x; //~ ERROR cannot borrow - | ^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-deref.rs:35:5 - | -LL | &mut **x //~ ERROR cannot borrow - | ^^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-borrow-overloaded-deref.rs:39:5 - | -LL | &mut **x //~ ERROR cannot borrow - | ^^^^^^^^ cannot borrow as mutable - -error[E0594]: cannot assign to data in a `&` reference - --> $DIR/borrowck-borrow-overloaded-deref.rs:43:5 - | -LL | *x = 3; //~ ERROR cannot assign - | ^^^^^^ cannot assign - -error[E0594]: cannot assign to data in a `&` reference - --> $DIR/borrowck-borrow-overloaded-deref.rs:47:5 - | -LL | **x = 3; //~ ERROR cannot assign - | ^^^^^^^ cannot assign - -error[E0594]: cannot assign to data in a `&` reference - --> $DIR/borrowck-borrow-overloaded-deref.rs:51:5 - | -LL | **x = 3; //~ ERROR cannot assign - | ^^^^^^^ cannot assign - -error: aborting due to 7 previous errors - -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr b/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr index 41e7cc210c8f5..1755b22f59dc2 100644 --- a/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr @@ -1,46 +1,45 @@ -error[E0596]: cannot borrow immutable borrowed content as mutable - --> $DIR/borrowck-borrow-overloaded-deref.rs:23:24 +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-borrow-overloaded-deref.rs:23:19 | -LL | let __isize = &mut *x; //~ ERROR cannot borrow - | ^^ cannot borrow as mutable +LL | let __isize = &mut *x; + | ^^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content as mutable - --> $DIR/borrowck-borrow-overloaded-deref.rs:27:24 +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-borrow-overloaded-deref.rs:27:19 | -LL | let __isize = &mut *x; //~ ERROR cannot borrow - | ^^ cannot borrow as mutable +LL | let __isize = &mut *x; + | ^^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content as mutable - --> $DIR/borrowck-borrow-overloaded-deref.rs:35:10 +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-borrow-overloaded-deref.rs:35:5 | -LL | &mut **x //~ ERROR cannot borrow - | ^^^ cannot borrow as mutable +LL | &mut **x + | ^^^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content as mutable - --> $DIR/borrowck-borrow-overloaded-deref.rs:39:10 +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-borrow-overloaded-deref.rs:39:5 | -LL | &mut **x //~ ERROR cannot borrow - | ^^^ cannot borrow as mutable +LL | &mut **x + | ^^^^^^^^ cannot borrow as mutable -error[E0594]: cannot assign to immutable borrowed content +error[E0594]: cannot assign to data in a `&` reference --> $DIR/borrowck-borrow-overloaded-deref.rs:43:5 | -LL | *x = 3; //~ ERROR cannot assign - | ^^^^^^ cannot borrow as mutable +LL | *x = 3; + | ^^^^^^ cannot assign -error[E0594]: cannot assign to immutable borrowed content +error[E0594]: cannot assign to data in a `&` reference --> $DIR/borrowck-borrow-overloaded-deref.rs:47:5 | -LL | **x = 3; //~ ERROR cannot assign - | ^^^^^^^ cannot borrow as mutable +LL | **x = 3; + | ^^^^^^^ cannot assign -error[E0594]: cannot assign to immutable borrowed content +error[E0594]: cannot assign to data in a `&` reference --> $DIR/borrowck-borrow-overloaded-deref.rs:51:5 | -LL | **x = 3; //~ ERROR cannot assign - | ^^^^^^^ cannot borrow as mutable +LL | **x = 3; + | ^^^^^^^ cannot assign error: aborting due to 7 previous errors -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.nll.stderr b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.nll.stderr deleted file mode 100644 index 97dc59c954385..0000000000000 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-borrowed-uniq-rvalue-2.rs:20:20 - | -LL | let x = defer(&vec!["Goodbye", "world!"]); //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary which is freed while still in use -LL | x.x[0]; - | ------ borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.rs b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.rs index 6e943ffabe3e3..e384aacb71845 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.rs +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.rs @@ -17,6 +17,6 @@ fn defer<'r>(x: &'r [&'r str]) -> Defer<'r> { } fn main() { - let x = defer(&vec!["Goodbye", "world!"]); //~ ERROR borrowed value does not live long enough + let x = defer(&vec!["Goodbye", "world!"]); //~ ERROR temporary value dropped while borrowed x.x[0]; } diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr index b94926951192a..1dd18c12fc8de 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr @@ -1,17 +1,16 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/borrowck-borrowed-uniq-rvalue-2.rs:20:20 | -LL | let x = defer(&vec!["Goodbye", "world!"]); //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value dropped here while still borrowed +LL | let x = defer(&vec!["Goodbye", "world!"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use LL | x.x[0]; -LL | } - | - temporary value needs to live until here + | ------ borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.nll.stderr b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.nll.stderr deleted file mode 100644 index d6e599d1abf93..0000000000000 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-borrowed-uniq-rvalue.rs:10:28 - | -LL | buggy_map.insert(42, &*Box::new(1)); //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary which is freed while still in use -... -LL | buggy_map.insert(43, &*tmp); - | --------- borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs index 88bd106d6f35e..a78c66f47cd14 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs @@ -7,7 +7,7 @@ use std::collections::HashMap; fn main() { let tmp: Box<_>; let mut buggy_map: HashMap = HashMap::new(); - buggy_map.insert(42, &*Box::new(1)); //~ ERROR borrowed value does not live long enough + buggy_map.insert(42, &*Box::new(1)); //~ ERROR temporary value dropped while borrowed // but it is ok if we use a temporary tmp = box 2; diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr index bf4674035ead2..c91a4377b4c67 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr @@ -1,16 +1,16 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/borrowck-borrowed-uniq-rvalue.rs:10:27 +error[E0716]: temporary value dropped while borrowed + --> $DIR/borrowck-borrowed-uniq-rvalue.rs:10:28 | -LL | buggy_map.insert(42, &*Box::new(1)); //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^^^^ - borrowed value dropped here while still borrowed - | | - | borrowed value does not live long enough +LL | buggy_map.insert(42, &*Box::new(1)); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use ... -LL | } - | - borrowed value needs to live until here +LL | buggy_map.insert(43, &*tmp); + | --------- borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/borrowck/borrowck-box-insensitivity.ast.stderr b/src/test/ui/borrowck/borrowck-box-insensitivity.ast.stderr deleted file mode 100644 index 236064da3e8b6..0000000000000 --- a/src/test/ui/borrowck/borrowck-box-insensitivity.ast.stderr +++ /dev/null @@ -1,165 +0,0 @@ -error[E0382]: use of moved value: `a` - --> $DIR/borrowck-box-insensitivity.rs:37:9 - | -LL | let _x = a.x; - | -- value moved here -LL | //[ast]~^ value moved here -LL | let _y = a.y; //[ast]~ ERROR use of moved - | ^^ value used here after move - | - = note: move occurs because `a.x` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `a` - --> $DIR/borrowck-box-insensitivity.rs:46:9 - | -LL | let _x = a.x; - | -- value moved here -LL | //[ast]~^ value moved here -LL | let _y = a.y; //[ast]~ ERROR use of moved - | ^^ value used here after move - | - = note: move occurs because `a.x` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `a` - --> $DIR/borrowck-box-insensitivity.rs:55:15 - | -LL | let _x = a.x; - | -- value moved here -LL | //[ast]~^ value moved here -LL | let _y = &a.y; //[ast]~ ERROR use of moved - | ^^^ value used here after move - | - = note: move occurs because `a.x` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0505]: cannot move out of `a.y` because it is borrowed - --> $DIR/borrowck-box-insensitivity.rs:63:9 - | -LL | let _x = &a.x; - | --- borrow of `a.x` occurs here -LL | let _y = a.y; - | ^^ move out of `a.y` occurs here - -error[E0503]: cannot use `a.y` because it was mutably borrowed - --> $DIR/borrowck-box-insensitivity.rs:71:9 - | -LL | let _x = &mut a.x; - | --- borrow of `a.x` occurs here -LL | let _y = a.y; //[ast]~ ERROR cannot use - | ^^ use of borrowed `a.x` - -error[E0505]: cannot move out of `a.y` because it is borrowed - --> $DIR/borrowck-box-insensitivity.rs:77:9 - | -LL | let _x = &mut a.x; - | --- borrow of `a.x` occurs here -LL | let _y = a.y; - | ^^ move out of `a.y` occurs here - -error[E0502]: cannot borrow `a` (via `a.y`) as immutable because `a` is also borrowed as mutable (via `a.x`) - --> $DIR/borrowck-box-insensitivity.rs:85:15 - | -LL | let _x = &mut a.x; - | --- mutable borrow occurs here (via `a.x`) -LL | let _y = &a.y; //[ast]~ ERROR cannot borrow - | ^^^ immutable borrow of `a.y` -- which overlaps with `a.x` -- occurs here -... -LL | } - | - mutable borrow ends here - -error[E0502]: cannot borrow `a` (via `a.y`) as mutable because `a` is also borrowed as immutable (via `a.x`) - --> $DIR/borrowck-box-insensitivity.rs:92:19 - | -LL | let _x = &a.x; - | --- immutable borrow occurs here (via `a.x`) -LL | let _y = &mut a.y; //[ast]~ ERROR cannot borrow - | ^^^ mutable borrow of `a.y` -- which overlaps with `a.x` -- occurs here -... -LL | } - | - immutable borrow ends here - -error[E0382]: use of collaterally moved value: `a.y` - --> $DIR/borrowck-box-insensitivity.rs:100:9 - | -LL | let _x = a.x.x; - | -- value moved here -LL | //[ast]~^ value moved here -LL | let _y = a.y; //[ast]~ ERROR use of collaterally moved - | ^^ value used here after move - | - = note: move occurs because `a.x.x` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of collaterally moved value: `a.y` - --> $DIR/borrowck-box-insensitivity.rs:108:9 - | -LL | let _x = a.x.x; - | -- value moved here -LL | //[ast]~^ value moved here -LL | let _y = a.y; //[ast]~ ERROR use of collaterally moved - | ^^ value used here after move - | - = note: move occurs because `a.x.x` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of collaterally moved value: `a.y` - --> $DIR/borrowck-box-insensitivity.rs:116:15 - | -LL | let _x = a.x.x; - | -- value moved here -LL | //[ast]~^ value moved here -LL | let _y = &a.y; //[ast]~ ERROR use of collaterally moved - | ^^^ value used here after move - | - = note: move occurs because `a.x.x` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0505]: cannot move out of `a.y` because it is borrowed - --> $DIR/borrowck-box-insensitivity.rs:124:9 - | -LL | let _x = &a.x.x; - | ----- borrow of `a.x.x` occurs here -LL | //[ast]~^ borrow of `a.x.x` occurs here -LL | let _y = a.y; - | ^^ move out of `a.y` occurs here - -error[E0503]: cannot use `a.y` because it was mutably borrowed - --> $DIR/borrowck-box-insensitivity.rs:132:9 - | -LL | let _x = &mut a.x.x; - | ----- borrow of `a.x.x` occurs here -LL | let _y = a.y; //[ast]~ ERROR cannot use - | ^^ use of borrowed `a.x.x` - -error[E0505]: cannot move out of `a.y` because it is borrowed - --> $DIR/borrowck-box-insensitivity.rs:138:9 - | -LL | let _x = &mut a.x.x; - | ----- borrow of `a.x.x` occurs here -LL | let _y = a.y; - | ^^ move out of `a.y` occurs here - -error[E0502]: cannot borrow `a.y` as immutable because `a.x.x` is also borrowed as mutable - --> $DIR/borrowck-box-insensitivity.rs:147:15 - | -LL | let _x = &mut a.x.x; - | ----- mutable borrow occurs here -LL | //[ast]~^ mutable borrow occurs here -LL | let _y = &a.y; //[ast]~ ERROR cannot borrow - | ^^^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here - -error[E0502]: cannot borrow `a.y` as mutable because `a.x.x` is also borrowed as immutable - --> $DIR/borrowck-box-insensitivity.rs:155:19 - | -LL | let _x = &a.x.x; - | ----- immutable borrow occurs here -LL | //[ast]~^ immutable borrow occurs here -LL | let _y = &mut a.y; //[ast]~ ERROR cannot borrow - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error: aborting due to 16 previous errors - -Some errors occurred: E0382, E0502, E0503, E0505. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-box-insensitivity.mir.stderr b/src/test/ui/borrowck/borrowck-box-insensitivity.mir.stderr deleted file mode 100644 index 171e992e8a628..0000000000000 --- a/src/test/ui/borrowck/borrowck-box-insensitivity.mir.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: compilation successful - --> $DIR/borrowck-box-insensitivity.rs:160:1 - | -LL | / fn main() { //[mir]~ ERROR compilation successful -LL | | copy_after_move(); -LL | | move_after_move(); -LL | | borrow_after_move(); -... | -LL | | mut_borrow_after_borrow_nested(); -LL | | } - | |_^ - -error: aborting due to previous error - diff --git a/src/test/ui/borrowck/borrowck-box-insensitivity.nll.stderr b/src/test/ui/borrowck/borrowck-box-insensitivity.nll.stderr deleted file mode 100644 index 0e380e90e7591..0000000000000 --- a/src/test/ui/borrowck/borrowck-box-insensitivity.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: compilation successful - --> $DIR/borrowck-box-insensitivity.rs:160:1 - | -LL | / fn main() { -LL | | copy_after_move(); -LL | | move_after_move(); -LL | | borrow_after_move(); -... | -LL | | mut_borrow_after_borrow_nested(); -LL | | } - | |_^ - -error: aborting due to previous error - diff --git a/src/test/ui/borrowck/borrowck-box-insensitivity.rs b/src/test/ui/borrowck/borrowck-box-insensitivity.rs deleted file mode 100644 index e72048d0ea4bc..0000000000000 --- a/src/test/ui/borrowck/borrowck-box-insensitivity.rs +++ /dev/null @@ -1,185 +0,0 @@ -// This test is an artifact of the old policy that `Box` should not -// be treated specially by the AST-borrowck. -// -// NLL goes back to treating `Box` specially (namely, knowing that -// it uniquely owns the data it holds). See rust-lang/rfcs#130. - -// revisions: ast mir -//[ast] compile-flags: -Z borrowck=ast -//[mir] compile-flags: -Z borrowck=mir -// ignore-compare-mode-nll -#![feature(box_syntax, rustc_attrs)] - -struct A { - x: Box, - y: isize, -} - -struct B { - x: Box, - y: Box, -} - -struct C { - x: Box, - y: isize, -} - -struct D { - x: Box, - y: Box, -} - -fn copy_after_move() { - let a: Box<_> = box A { x: box 0, y: 1 }; - let _x = a.x; - //[ast]~^ value moved here - let _y = a.y; //[ast]~ ERROR use of moved - //[ast]~^ move occurs because `a.x` has type `std::boxed::Box` - //[ast]~| value used here after move -} - -fn move_after_move() { - let a: Box<_> = box B { x: box 0, y: box 1 }; - let _x = a.x; - //[ast]~^ value moved here - let _y = a.y; //[ast]~ ERROR use of moved - //[ast]~^ move occurs because `a.x` has type `std::boxed::Box` - //[ast]~| value used here after move -} - -fn borrow_after_move() { - let a: Box<_> = box A { x: box 0, y: 1 }; - let _x = a.x; - //[ast]~^ value moved here - let _y = &a.y; //[ast]~ ERROR use of moved - //[ast]~^ move occurs because `a.x` has type `std::boxed::Box` - //[ast]~| value used here after move -} - -fn move_after_borrow() { - let a: Box<_> = box B { x: box 0, y: box 1 }; - let _x = &a.x; - let _y = a.y; - //[ast]~^ ERROR cannot move - //[ast]~| move out of - use_imm(_x); -} -fn copy_after_mut_borrow() { - let mut a: Box<_> = box A { x: box 0, y: 1 }; - let _x = &mut a.x; - let _y = a.y; //[ast]~ ERROR cannot use - use_mut(_x); -} -fn move_after_mut_borrow() { - let mut a: Box<_> = box B { x: box 0, y: box 1 }; - let _x = &mut a.x; - let _y = a.y; - //[ast]~^ ERROR cannot move - //[ast]~| move out of - use_mut(_x); -} -fn borrow_after_mut_borrow() { - let mut a: Box<_> = box A { x: box 0, y: 1 }; - let _x = &mut a.x; - let _y = &a.y; //[ast]~ ERROR cannot borrow - //[ast]~^ immutable borrow of `a.y` -- which overlaps with `a.x` -- occurs here - use_mut(_x); -} -fn mut_borrow_after_borrow() { - let mut a: Box<_> = box A { x: box 0, y: 1 }; - let _x = &a.x; - let _y = &mut a.y; //[ast]~ ERROR cannot borrow - //[ast]~^ mutable borrow of `a.y` -- which overlaps with `a.x` -- occurs here - use_imm(_x); -} -fn copy_after_move_nested() { - let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; - let _x = a.x.x; - //[ast]~^ value moved here - let _y = a.y; //[ast]~ ERROR use of collaterally moved - //[ast]~| value used here after move -} - -fn move_after_move_nested() { - let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; - let _x = a.x.x; - //[ast]~^ value moved here - let _y = a.y; //[ast]~ ERROR use of collaterally moved - //[ast]~| value used here after move -} - -fn borrow_after_move_nested() { - let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; - let _x = a.x.x; - //[ast]~^ value moved here - let _y = &a.y; //[ast]~ ERROR use of collaterally moved - //[ast]~| value used here after move -} - -fn move_after_borrow_nested() { - let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; - let _x = &a.x.x; - //[ast]~^ borrow of `a.x.x` occurs here - let _y = a.y; - //[ast]~^ ERROR cannot move - //[ast]~| move out of - use_imm(_x); -} -fn copy_after_mut_borrow_nested() { - let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; - let _x = &mut a.x.x; - let _y = a.y; //[ast]~ ERROR cannot use - use_mut(_x); -} -fn move_after_mut_borrow_nested() { - let mut a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; - let _x = &mut a.x.x; - let _y = a.y; - //[ast]~^ ERROR cannot move - //[ast]~| move out of - use_mut(_x); -} -fn borrow_after_mut_borrow_nested() { - let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; - let _x = &mut a.x.x; - //[ast]~^ mutable borrow occurs here - let _y = &a.y; //[ast]~ ERROR cannot borrow - //[ast]~^ immutable borrow occurs here - use_mut(_x); -} -fn mut_borrow_after_borrow_nested() { - let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; - let _x = &a.x.x; - //[ast]~^ immutable borrow occurs here - let _y = &mut a.y; //[ast]~ ERROR cannot borrow - //[ast]~^ mutable borrow occurs here - use_imm(_x); -} -#[rustc_error] -fn main() { //[mir]~ ERROR compilation successful - copy_after_move(); - move_after_move(); - borrow_after_move(); - - move_after_borrow(); - - copy_after_mut_borrow(); - move_after_mut_borrow(); - borrow_after_mut_borrow(); - mut_borrow_after_borrow(); - - copy_after_move_nested(); - move_after_move_nested(); - borrow_after_move_nested(); - - move_after_borrow_nested(); - - copy_after_mut_borrow_nested(); - move_after_mut_borrow_nested(); - borrow_after_mut_borrow_nested(); - mut_borrow_after_borrow_nested(); -} - -fn use_mut(_: &mut T) { } -fn use_imm(_: &T) { } diff --git a/src/test/ui/borrowck/borrowck-box-sensitivity.rs b/src/test/ui/borrowck/borrowck-box-sensitivity.rs new file mode 100644 index 0000000000000..e5591f500380b --- /dev/null +++ b/src/test/ui/borrowck/borrowck-box-sensitivity.rs @@ -0,0 +1,150 @@ +// Test that `Box` is treated specially by borrow checking. This is the case +// because NLL reverted the deicision in rust-lang/rfcs#130. + +// run-pass + +#![feature(box_syntax)] + +struct A { + x: Box, + y: isize, +} + +struct B { + x: Box, + y: Box, +} + +struct C { + x: Box, + y: isize, +} + +struct D { + x: Box, + y: Box, +} + +fn copy_after_move() { + let a: Box<_> = box A { x: box 0, y: 1 }; + let _x = a.x; + let _y = a.y; +} + +fn move_after_move() { + let a: Box<_> = box B { x: box 0, y: box 1 }; + let _x = a.x; + let _y = a.y; +} + +fn borrow_after_move() { + let a: Box<_> = box A { x: box 0, y: 1 }; + let _x = a.x; + let _y = &a.y; +} + +fn move_after_borrow() { + let a: Box<_> = box B { x: box 0, y: box 1 }; + let _x = &a.x; + let _y = a.y; + use_imm(_x); +} +fn copy_after_mut_borrow() { + let mut a: Box<_> = box A { x: box 0, y: 1 }; + let _x = &mut a.x; + let _y = a.y; + use_mut(_x); +} +fn move_after_mut_borrow() { + let mut a: Box<_> = box B { x: box 0, y: box 1 }; + let _x = &mut a.x; + let _y = a.y; + use_mut(_x); +} +fn borrow_after_mut_borrow() { + let mut a: Box<_> = box A { x: box 0, y: 1 }; + let _x = &mut a.x; + let _y = &a.y; + use_mut(_x); +} +fn mut_borrow_after_borrow() { + let mut a: Box<_> = box A { x: box 0, y: 1 }; + let _x = &a.x; + let _y = &mut a.y; + use_imm(_x); +} +fn copy_after_move_nested() { + let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let _x = a.x.x; + let _y = a.y; +} + +fn move_after_move_nested() { + let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; + let _x = a.x.x; + let _y = a.y; +} + +fn borrow_after_move_nested() { + let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let _x = a.x.x; + let _y = &a.y; +} + +fn move_after_borrow_nested() { + let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; + let _x = &a.x.x; + let _y = a.y; + use_imm(_x); +} +fn copy_after_mut_borrow_nested() { + let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let _x = &mut a.x.x; + let _y = a.y; + use_mut(_x); +} +fn move_after_mut_borrow_nested() { + let mut a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; + let _x = &mut a.x.x; + let _y = a.y; + use_mut(_x); +} +fn borrow_after_mut_borrow_nested() { + let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let _x = &mut a.x.x; + let _y = &a.y; + use_mut(_x); +} +fn mut_borrow_after_borrow_nested() { + let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let _x = &a.x.x; + let _y = &mut a.y; + use_imm(_x); +} + +fn main() { + copy_after_move(); + move_after_move(); + borrow_after_move(); + + move_after_borrow(); + + copy_after_mut_borrow(); + move_after_mut_borrow(); + borrow_after_mut_borrow(); + mut_borrow_after_borrow(); + + copy_after_move_nested(); + move_after_move_nested(); + borrow_after_move_nested(); + + move_after_borrow_nested(); + + copy_after_mut_borrow_nested(); + move_after_mut_borrow_nested(); + borrow_after_mut_borrow_nested(); + mut_borrow_after_borrow_nested(); +} + +fn use_mut(_: &mut T) { } +fn use_imm(_: &T) { } diff --git a/src/test/ui/borrowck/borrowck-break-uninit-2.nll.stderr b/src/test/ui/borrowck/borrowck-break-uninit-2.nll.stderr deleted file mode 100644 index 177a27387728e..0000000000000 --- a/src/test/ui/borrowck/borrowck-break-uninit-2.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/borrowck-break-uninit-2.rs:9:20 - | -LL | println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` - | ^ use of possibly uninitialized `x` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-break-uninit-2.rs b/src/test/ui/borrowck/borrowck-break-uninit-2.rs index 95ccb2e1b931c..dad5325cb8750 100644 --- a/src/test/ui/borrowck/borrowck-break-uninit-2.rs +++ b/src/test/ui/borrowck/borrowck-break-uninit-2.rs @@ -6,7 +6,7 @@ fn foo() -> isize { x = 0; } - println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` + println!("{}", x); //~ ERROR borrow of possibly uninitialized variable: `x` return 17; } diff --git a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr index e574c0ff8a85b..e40d8d9dfccb9 100644 --- a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr +++ b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr @@ -1,7 +1,7 @@ -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly uninitialized variable: `x` --> $DIR/borrowck-break-uninit-2.rs:9:20 | -LL | println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` +LL | println!("{}", x); | ^ use of possibly uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-break-uninit.nll.stderr b/src/test/ui/borrowck/borrowck-break-uninit.nll.stderr deleted file mode 100644 index 64d1e629fecdb..0000000000000 --- a/src/test/ui/borrowck/borrowck-break-uninit.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/borrowck-break-uninit.rs:9:20 - | -LL | println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` - | ^ use of possibly uninitialized `x` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-break-uninit.rs b/src/test/ui/borrowck/borrowck-break-uninit.rs index 827637cfb956f..9af02b387d8b0 100644 --- a/src/test/ui/borrowck/borrowck-break-uninit.rs +++ b/src/test/ui/borrowck/borrowck-break-uninit.rs @@ -6,7 +6,7 @@ fn foo() -> isize { x = 0; } - println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` + println!("{}", x); //~ ERROR borrow of possibly uninitialized variable: `x` return 17; } diff --git a/src/test/ui/borrowck/borrowck-break-uninit.stderr b/src/test/ui/borrowck/borrowck-break-uninit.stderr index 1a853c35d00e0..bbf9b9f1241a2 100644 --- a/src/test/ui/borrowck/borrowck-break-uninit.stderr +++ b/src/test/ui/borrowck/borrowck-break-uninit.stderr @@ -1,7 +1,7 @@ -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly uninitialized variable: `x` --> $DIR/borrowck-break-uninit.rs:9:20 | -LL | println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` +LL | println!("{}", x); | ^ use of possibly uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.ast.nll.stderr b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.ast.nll.stderr deleted file mode 100644 index ed3d1ff38ec77..0000000000000 --- a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.ast.nll.stderr +++ /dev/null @@ -1,116 +0,0 @@ -error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-closures-mut-and-imm.rs:21:14 - | -LL | let c1 = || x = 4; - | -- - first borrow occurs due to use of `x` in closure - | | - | mutable borrow occurs here -LL | let c2 = || x * 5; //[ast]~ ERROR cannot borrow `x` - | ^^ - second borrow occurs due to use of `x` in closure - | | - | immutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable -LL | drop(c1); - | -- mutable borrow later used here - -error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-closures-mut-and-imm.rs:29:14 - | -LL | let c1 = || set(&mut x); - | -- - first borrow occurs due to use of `x` in closure - | | - | mutable borrow occurs here -LL | let c2 = || get(&x); //[ast]~ ERROR cannot borrow `x` - | ^^ - second borrow occurs due to use of `x` in closure - | | - | immutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable -LL | drop(c1); - | -- mutable borrow later used here - -error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-closures-mut-and-imm.rs:37:14 - | -LL | let c1 = || set(&mut x); - | -- - first borrow occurs due to use of `x` in closure - | | - | mutable borrow occurs here -LL | let c2 = || x * 5; //[ast]~ ERROR cannot borrow `x` - | ^^ - second borrow occurs due to use of `x` in closure - | | - | immutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable -LL | drop(c1); - | -- mutable borrow later used here - -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-closures-mut-and-imm.rs:45:5 - | -LL | let c2 = || x * 5; - | -- - borrow occurs due to use in closure - | | - | borrow of `x` occurs here -LL | x = 5; //[ast]~ ERROR cannot assign - | ^^^^^ assignment to borrowed `x` occurs here -LL | //[mir]~^ ERROR cannot assign to `x` because it is borrowed -LL | drop(c2); - | -- borrow later used here - -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-closures-mut-and-imm.rs:53:5 - | -LL | let c1 = || get(&x); - | -- - borrow occurs due to use in closure - | | - | borrow of `x` occurs here -LL | x = 5; //[ast]~ ERROR cannot assign - | ^^^^^ assignment to borrowed `x` occurs here -LL | //[mir]~^ ERROR cannot assign to `x` because it is borrowed -LL | drop(c1); - | -- borrow later used here - -error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/borrowck-closures-mut-and-imm.rs:61:5 - | -LL | let c1 = || get(&*x); - | -- - borrow occurs due to use in closure - | | - | borrow of `*x` occurs here -LL | *x = 5; //[ast]~ ERROR cannot assign to `*x` - | ^^^^^^ assignment to borrowed `*x` occurs here -LL | //[mir]~^ ERROR cannot assign to `*x` because it is borrowed -LL | drop(c1); - | -- borrow later used here - -error[E0506]: cannot assign to `*x.f` because it is borrowed - --> $DIR/borrowck-closures-mut-and-imm.rs:73:5 - | -LL | let c1 = || get(&*x.f); - | -- - borrow occurs due to use in closure - | | - | borrow of `*x.f` occurs here -LL | *x.f = 5; //[ast]~ ERROR cannot assign to `*x.f` - | ^^^^^^^^ assignment to borrowed `*x.f` occurs here -LL | //[mir]~^ ERROR cannot assign to `*x.f` because it is borrowed -LL | drop(c1); - | -- borrow later used here - -error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-closures-mut-and-imm.rs:85:14 - | -LL | let c1 = || get(&*x.f); - | -- - first borrow occurs due to use of `x` in closure - | | - | immutable borrow occurs here -LL | let c2 = || *x.f = 5; //[ast]~ ERROR cannot borrow `x` as mutable - | ^^ - second borrow occurs due to use of `x` in closure - | | - | mutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable -LL | drop(c1); - | -- immutable borrow later used here - -error: aborting due to 8 previous errors - -Some errors occurred: E0502, E0506. -For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.ast.stderr b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.ast.stderr deleted file mode 100644 index 363889c684626..0000000000000 --- a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.ast.stderr +++ /dev/null @@ -1,96 +0,0 @@ -error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-closures-mut-and-imm.rs:21:14 - | -LL | let c1 = || x = 4; - | -- - previous borrow occurs due to use of `x` in closure - | | - | mutable borrow occurs here -LL | let c2 = || x * 5; //[ast]~ ERROR cannot borrow `x` - | ^^ - borrow occurs due to use of `x` in closure - | | - | immutable borrow occurs here -... -LL | } - | - mutable borrow ends here - -error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-closures-mut-and-imm.rs:29:14 - | -LL | let c1 = || set(&mut x); - | -- - previous borrow occurs due to use of `x` in closure - | | - | mutable borrow occurs here -LL | let c2 = || get(&x); //[ast]~ ERROR cannot borrow `x` - | ^^ - borrow occurs due to use of `x` in closure - | | - | immutable borrow occurs here -... -LL | } - | - mutable borrow ends here - -error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-closures-mut-and-imm.rs:37:14 - | -LL | let c1 = || set(&mut x); - | -- - previous borrow occurs due to use of `x` in closure - | | - | mutable borrow occurs here -LL | let c2 = || x * 5; //[ast]~ ERROR cannot borrow `x` - | ^^ - borrow occurs due to use of `x` in closure - | | - | immutable borrow occurs here -... -LL | } - | - mutable borrow ends here - -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-closures-mut-and-imm.rs:45:5 - | -LL | let c2 = || x * 5; - | -- borrow of `x` occurs here -LL | x = 5; //[ast]~ ERROR cannot assign - | ^^^^^ assignment to borrowed `x` occurs here - -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-closures-mut-and-imm.rs:53:5 - | -LL | let c1 = || get(&x); - | -- borrow of `x` occurs here -LL | x = 5; //[ast]~ ERROR cannot assign - | ^^^^^ assignment to borrowed `x` occurs here - -error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/borrowck-closures-mut-and-imm.rs:61:5 - | -LL | let c1 = || get(&*x); - | -- borrow of `*x` occurs here -LL | *x = 5; //[ast]~ ERROR cannot assign to `*x` - | ^^^^^^ assignment to borrowed `*x` occurs here - -error[E0506]: cannot assign to `*x.f` because it is borrowed - --> $DIR/borrowck-closures-mut-and-imm.rs:73:5 - | -LL | let c1 = || get(&*x.f); - | -- borrow of `*x.f` occurs here -LL | *x.f = 5; //[ast]~ ERROR cannot assign to `*x.f` - | ^^^^^^^^ assignment to borrowed `*x.f` occurs here - -error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-closures-mut-and-imm.rs:85:14 - | -LL | let c1 = || get(&*x.f); - | -- - previous borrow occurs due to use of `x` in closure - | | - | immutable borrow occurs here -LL | let c2 = || *x.f = 5; //[ast]~ ERROR cannot borrow `x` as mutable - | ^^ - borrow occurs due to use of `x` in closure - | | - | mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error: aborting due to 8 previous errors - -Some errors occurred: E0502, E0506. -For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.mir.stderr b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.mir.stderr deleted file mode 100644 index ed3d1ff38ec77..0000000000000 --- a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.mir.stderr +++ /dev/null @@ -1,116 +0,0 @@ -error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-closures-mut-and-imm.rs:21:14 - | -LL | let c1 = || x = 4; - | -- - first borrow occurs due to use of `x` in closure - | | - | mutable borrow occurs here -LL | let c2 = || x * 5; //[ast]~ ERROR cannot borrow `x` - | ^^ - second borrow occurs due to use of `x` in closure - | | - | immutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable -LL | drop(c1); - | -- mutable borrow later used here - -error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-closures-mut-and-imm.rs:29:14 - | -LL | let c1 = || set(&mut x); - | -- - first borrow occurs due to use of `x` in closure - | | - | mutable borrow occurs here -LL | let c2 = || get(&x); //[ast]~ ERROR cannot borrow `x` - | ^^ - second borrow occurs due to use of `x` in closure - | | - | immutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable -LL | drop(c1); - | -- mutable borrow later used here - -error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-closures-mut-and-imm.rs:37:14 - | -LL | let c1 = || set(&mut x); - | -- - first borrow occurs due to use of `x` in closure - | | - | mutable borrow occurs here -LL | let c2 = || x * 5; //[ast]~ ERROR cannot borrow `x` - | ^^ - second borrow occurs due to use of `x` in closure - | | - | immutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable -LL | drop(c1); - | -- mutable borrow later used here - -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-closures-mut-and-imm.rs:45:5 - | -LL | let c2 = || x * 5; - | -- - borrow occurs due to use in closure - | | - | borrow of `x` occurs here -LL | x = 5; //[ast]~ ERROR cannot assign - | ^^^^^ assignment to borrowed `x` occurs here -LL | //[mir]~^ ERROR cannot assign to `x` because it is borrowed -LL | drop(c2); - | -- borrow later used here - -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-closures-mut-and-imm.rs:53:5 - | -LL | let c1 = || get(&x); - | -- - borrow occurs due to use in closure - | | - | borrow of `x` occurs here -LL | x = 5; //[ast]~ ERROR cannot assign - | ^^^^^ assignment to borrowed `x` occurs here -LL | //[mir]~^ ERROR cannot assign to `x` because it is borrowed -LL | drop(c1); - | -- borrow later used here - -error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/borrowck-closures-mut-and-imm.rs:61:5 - | -LL | let c1 = || get(&*x); - | -- - borrow occurs due to use in closure - | | - | borrow of `*x` occurs here -LL | *x = 5; //[ast]~ ERROR cannot assign to `*x` - | ^^^^^^ assignment to borrowed `*x` occurs here -LL | //[mir]~^ ERROR cannot assign to `*x` because it is borrowed -LL | drop(c1); - | -- borrow later used here - -error[E0506]: cannot assign to `*x.f` because it is borrowed - --> $DIR/borrowck-closures-mut-and-imm.rs:73:5 - | -LL | let c1 = || get(&*x.f); - | -- - borrow occurs due to use in closure - | | - | borrow of `*x.f` occurs here -LL | *x.f = 5; //[ast]~ ERROR cannot assign to `*x.f` - | ^^^^^^^^ assignment to borrowed `*x.f` occurs here -LL | //[mir]~^ ERROR cannot assign to `*x.f` because it is borrowed -LL | drop(c1); - | -- borrow later used here - -error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-closures-mut-and-imm.rs:85:14 - | -LL | let c1 = || get(&*x.f); - | -- - first borrow occurs due to use of `x` in closure - | | - | immutable borrow occurs here -LL | let c2 = || *x.f = 5; //[ast]~ ERROR cannot borrow `x` as mutable - | ^^ - second borrow occurs due to use of `x` in closure - | | - | mutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable -LL | drop(c1); - | -- immutable borrow later used here - -error: aborting due to 8 previous errors - -Some errors occurred: E0502, E0506. -For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs index 3a802bcbb3e42..2dc405ffcd4c0 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs +++ b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs @@ -1,10 +1,6 @@ // Tests that two closures cannot simultaneously have mutable // and immutable access to the variable. Issue #6801. -// ignore-tidy-linelength -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - #![feature(box_syntax)] fn get(x: &isize) -> isize { @@ -18,48 +14,48 @@ fn set(x: &mut isize) { fn a() { let mut x = 3; let c1 = || x = 4; - let c2 = || x * 5; //[ast]~ ERROR cannot borrow `x` - //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable + let c2 = || x * 5; + //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable drop(c1); } fn b() { let mut x = 3; let c1 = || set(&mut x); - let c2 = || get(&x); //[ast]~ ERROR cannot borrow `x` - //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable + let c2 = || get(&x); + //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable drop(c1); } fn c() { let mut x = 3; let c1 = || set(&mut x); - let c2 = || x * 5; //[ast]~ ERROR cannot borrow `x` - //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable + let c2 = || x * 5; + //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable drop(c1); } fn d() { let mut x = 3; let c2 = || x * 5; - x = 5; //[ast]~ ERROR cannot assign - //[mir]~^ ERROR cannot assign to `x` because it is borrowed + x = 5; + //~^ ERROR cannot assign to `x` because it is borrowed drop(c2); } fn e() { let mut x = 3; let c1 = || get(&x); - x = 5; //[ast]~ ERROR cannot assign - //[mir]~^ ERROR cannot assign to `x` because it is borrowed + x = 5; + //~^ ERROR cannot assign to `x` because it is borrowed drop(c1); } fn f() { let mut x: Box<_> = box 3; let c1 = || get(&*x); - *x = 5; //[ast]~ ERROR cannot assign to `*x` - //[mir]~^ ERROR cannot assign to `*x` because it is borrowed + *x = 5; + //~^ ERROR cannot assign to `*x` because it is borrowed drop(c1); } @@ -70,8 +66,8 @@ fn g() { let mut x: Box<_> = box Foo { f: box 3 }; let c1 = || get(&*x.f); - *x.f = 5; //[ast]~ ERROR cannot assign to `*x.f` - //[mir]~^ ERROR cannot assign to `*x.f` because it is borrowed + *x.f = 5; + //~^ ERROR cannot assign to `*x.f` because it is borrowed drop(c1); } @@ -82,8 +78,8 @@ fn h() { let mut x: Box<_> = box Foo { f: box 3 }; let c1 = || get(&*x.f); - let c2 = || *x.f = 5; //[ast]~ ERROR cannot borrow `x` as mutable - //[mir]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable + let c2 = || *x.f = 5; + //~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable drop(c1); } diff --git a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr new file mode 100644 index 0000000000000..edeb21c16d3c8 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr @@ -0,0 +1,116 @@ +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-closures-mut-and-imm.rs:17:14 + | +LL | let c1 = || x = 4; + | -- - first borrow occurs due to use of `x` in closure + | | + | mutable borrow occurs here +LL | let c2 = || x * 5; + | ^^ - second borrow occurs due to use of `x` in closure + | | + | immutable borrow occurs here +LL | +LL | drop(c1); + | -- mutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-closures-mut-and-imm.rs:25:14 + | +LL | let c1 = || set(&mut x); + | -- - first borrow occurs due to use of `x` in closure + | | + | mutable borrow occurs here +LL | let c2 = || get(&x); + | ^^ - second borrow occurs due to use of `x` in closure + | | + | immutable borrow occurs here +LL | +LL | drop(c1); + | -- mutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-closures-mut-and-imm.rs:33:14 + | +LL | let c1 = || set(&mut x); + | -- - first borrow occurs due to use of `x` in closure + | | + | mutable borrow occurs here +LL | let c2 = || x * 5; + | ^^ - second borrow occurs due to use of `x` in closure + | | + | immutable borrow occurs here +LL | +LL | drop(c1); + | -- mutable borrow later used here + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/borrowck-closures-mut-and-imm.rs:41:5 + | +LL | let c2 = || x * 5; + | -- - borrow occurs due to use in closure + | | + | borrow of `x` occurs here +LL | x = 5; + | ^^^^^ assignment to borrowed `x` occurs here +LL | +LL | drop(c2); + | -- borrow later used here + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/borrowck-closures-mut-and-imm.rs:49:5 + | +LL | let c1 = || get(&x); + | -- - borrow occurs due to use in closure + | | + | borrow of `x` occurs here +LL | x = 5; + | ^^^^^ assignment to borrowed `x` occurs here +LL | +LL | drop(c1); + | -- borrow later used here + +error[E0506]: cannot assign to `*x` because it is borrowed + --> $DIR/borrowck-closures-mut-and-imm.rs:57:5 + | +LL | let c1 = || get(&*x); + | -- - borrow occurs due to use in closure + | | + | borrow of `*x` occurs here +LL | *x = 5; + | ^^^^^^ assignment to borrowed `*x` occurs here +LL | +LL | drop(c1); + | -- borrow later used here + +error[E0506]: cannot assign to `*x.f` because it is borrowed + --> $DIR/borrowck-closures-mut-and-imm.rs:69:5 + | +LL | let c1 = || get(&*x.f); + | -- - borrow occurs due to use in closure + | | + | borrow of `*x.f` occurs here +LL | *x.f = 5; + | ^^^^^^^^ assignment to borrowed `*x.f` occurs here +LL | +LL | drop(c1); + | -- borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-closures-mut-and-imm.rs:81:14 + | +LL | let c1 = || get(&*x.f); + | -- - first borrow occurs due to use of `x` in closure + | | + | immutable borrow occurs here +LL | let c2 = || *x.f = 5; + | ^^ - second borrow occurs due to use of `x` in closure + | | + | mutable borrow occurs here +LL | +LL | drop(c1); + | -- immutable borrow later used here + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0502, E0506. +For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.nll.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.nll.stderr deleted file mode 100644 index 8123e17ce9da2..0000000000000 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.nll.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-closures-mut-of-imm.rs:13:25 - | -LL | let mut c1 = || set(&mut *x); - | ^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-closures-mut-of-imm.rs:15:25 - | -LL | let mut c2 = || set(&mut *x); - | ^^^^^^^ cannot borrow as mutable - -error[E0524]: two closures require unique access to `x` at the same time - --> $DIR/borrowck-closures-mut-of-imm.rs:15:18 - | -LL | let mut c1 = || set(&mut *x); - | -- - first borrow occurs due to use of `x` in closure - | | - | first closure is constructed here -LL | //~^ ERROR cannot borrow -LL | let mut c2 = || set(&mut *x); - | ^^ - second borrow occurs due to use of `x` in closure - | | - | second closure is constructed here -... -LL | c2(); c1(); - | -- first borrow later used here - -error: aborting due to 3 previous errors - -Some errors occurred: E0524, E0596. -For more information about an error, try `rustc --explain E0524`. diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr index f529247b1b6f6..3be7d725eda3a 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr +++ b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr @@ -1,32 +1,31 @@ +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference + --> $DIR/borrowck-closures-mut-of-imm.rs:13:25 + | +LL | let mut c1 = || set(&mut *x); + | ^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference + --> $DIR/borrowck-closures-mut-of-imm.rs:15:25 + | +LL | let mut c2 = || set(&mut *x); + | ^^^^^^^ cannot borrow as mutable + error[E0524]: two closures require unique access to `x` at the same time --> $DIR/borrowck-closures-mut-of-imm.rs:15:18 | LL | let mut c1 = || set(&mut *x); - | -- - previous borrow occurs due to use of `x` in closure + | -- - first borrow occurs due to use of `x` in closure | | | first closure is constructed here -LL | //~^ ERROR cannot borrow +LL | LL | let mut c2 = || set(&mut *x); - | ^^ - borrow occurs due to use of `x` in closure + | ^^ - second borrow occurs due to use of `x` in closure | | | second closure is constructed here ... -LL | } - | - borrow from first closure ends here - -error[E0596]: cannot borrow immutable borrowed content `***x` as mutable - --> $DIR/borrowck-closures-mut-of-imm.rs:13:30 - | -LL | let mut c1 = || set(&mut *x); - | ^^ cannot borrow as mutable - -error[E0596]: cannot borrow immutable borrowed content `***x` as mutable - --> $DIR/borrowck-closures-mut-of-imm.rs:15:30 - | -LL | let mut c2 = || set(&mut *x); - | ^^ cannot borrow as mutable +LL | c2(); c1(); + | -- first borrow later used here error: aborting due to 3 previous errors -Some errors occurred: E0524, E0596. -For more information about an error, try `rustc --explain E0524`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.nll.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-mut.nll.stderr deleted file mode 100644 index 18f95f232cdd3..0000000000000 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.nll.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0524]: two closures require unique access to `x` at the same time - --> $DIR/borrowck-closures-mut-of-mut.rs:14:18 - | -LL | let mut c1 = || set(&mut *x); - | -- - first borrow occurs due to use of `x` in closure - | | - | first closure is constructed here -LL | let mut c2 = || set(&mut *x); - | ^^ - second borrow occurs due to use of `x` in closure - | | - | second closure is constructed here -LL | //~^ ERROR two closures require unique access to `x` at the same time -LL | c2(); c1(); - | -- first borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0524`. diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr index 2c5587710a154..a174388712158 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr +++ b/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr @@ -2,17 +2,16 @@ error[E0524]: two closures require unique access to `x` at the same time --> $DIR/borrowck-closures-mut-of-mut.rs:14:18 | LL | let mut c1 = || set(&mut *x); - | -- - previous borrow occurs due to use of `x` in closure + | -- - first borrow occurs due to use of `x` in closure | | | first closure is constructed here LL | let mut c2 = || set(&mut *x); - | ^^ - borrow occurs due to use of `x` in closure + | ^^ - second borrow occurs due to use of `x` in closure | | | second closure is constructed here -... -LL | } - | - borrow from first closure ends here +LL | +LL | c2(); c1(); + | -- first borrow later used here error: aborting due to previous error -For more information about this error, try `rustc --explain E0524`. diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut-fail.nll.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut-fail.nll.stderr deleted file mode 100644 index d3d11e8451cf8..0000000000000 --- a/src/test/ui/borrowck/borrowck-closures-two-mut-fail.nll.stderr +++ /dev/null @@ -1,75 +0,0 @@ -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-closures-two-mut-fail.rs:16:24 - | -LL | let c1 = to_fn_mut(|| x = 4); - | -- - first borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once - | ^^ - second borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -LL | c1; - | -- first borrow later used here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-closures-two-mut-fail.rs:27:24 - | -LL | let c1 = to_fn_mut(|| set(&mut x)); - | -- - first borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once - | ^^ - second borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -LL | c1; - | -- first borrow later used here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-closures-two-mut-fail.rs:34:24 - | -LL | let c1 = to_fn_mut(|| x = 5); - | -- - first borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once - | ^^ - second borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -LL | c1; - | -- first borrow later used here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-closures-two-mut-fail.rs:41:24 - | -LL | let c1 = to_fn_mut(|| x = 5); - | -- - first borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) - | ^^ - second borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -LL | //~^ ERROR cannot borrow `x` as mutable more than once -LL | c1; - | -- first borrow later used here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-closures-two-mut-fail.rs:53:24 - | -LL | let c1 = to_fn_mut(|| set(&mut *x.f)); - | -- - first borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| set(&mut *x.f)); - | ^^ - second borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -LL | //~^ ERROR cannot borrow `x` as mutable more than once -LL | c1; - | -- first borrow later used here - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr index cb8f5b4366bfd..07f477d17868f 100644 --- a/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr +++ b/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr @@ -2,76 +2,73 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/borrowck-closures-two-mut-fail.rs:16:24 | LL | let c1 = to_fn_mut(|| x = 4); - | -- - previous borrow occurs due to use of `x` in closure + | -- - first borrow occurs due to use of `x` in closure | | | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once - | ^^ - borrow occurs due to use of `x` in closure +LL | let c2 = to_fn_mut(|| x = 5); + | ^^ - second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here LL | c1; -LL | } - | - first borrow ends here + | -- first borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/borrowck-closures-two-mut-fail.rs:27:24 | LL | let c1 = to_fn_mut(|| set(&mut x)); - | -- - previous borrow occurs due to use of `x` in closure + | -- - first borrow occurs due to use of `x` in closure | | | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once - | ^^ - borrow occurs due to use of `x` in closure +LL | let c2 = to_fn_mut(|| set(&mut x)); + | ^^ - second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here LL | c1; -LL | } - | - first borrow ends here + | -- first borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/borrowck-closures-two-mut-fail.rs:34:24 | LL | let c1 = to_fn_mut(|| x = 5); - | -- - previous borrow occurs due to use of `x` in closure + | -- - first borrow occurs due to use of `x` in closure | | | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once - | ^^ - borrow occurs due to use of `x` in closure +LL | let c2 = to_fn_mut(|| set(&mut x)); + | ^^ - second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here LL | c1; -LL | } - | - first borrow ends here + | -- first borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/borrowck-closures-two-mut-fail.rs:41:24 | LL | let c1 = to_fn_mut(|| x = 5); - | -- - previous borrow occurs due to use of `x` in closure + | -- - first borrow occurs due to use of `x` in closure | | | first mutable borrow occurs here LL | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) - | ^^ - borrow occurs due to use of `x` in closure + | ^^ - second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here -... -LL | } - | - first borrow ends here +LL | +LL | c1; + | -- first borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/borrowck-closures-two-mut-fail.rs:53:24 | LL | let c1 = to_fn_mut(|| set(&mut *x.f)); - | -- - previous borrow occurs due to use of `x` in closure + | -- - first borrow occurs due to use of `x` in closure | | | first mutable borrow occurs here LL | let c2 = to_fn_mut(|| set(&mut *x.f)); - | ^^ - borrow occurs due to use of `x` in closure + | ^^ - second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here -... -LL | } - | - first borrow ends here +LL | +LL | c1; + | -- first borrow later used here error: aborting due to 5 previous errors diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut.rs b/src/test/ui/borrowck/borrowck-closures-two-mut.rs index 1fced982f8d68..5fe51654f3b79 100644 --- a/src/test/ui/borrowck/borrowck-closures-two-mut.rs +++ b/src/test/ui/borrowck/borrowck-closures-two-mut.rs @@ -2,8 +2,6 @@ // access to the variable, whether that mutable access be used // for direct assignment or for taking mutable ref. Issue #6801. -// compile-flags: -Z borrowck=compare - #![feature(box_syntax)] fn to_fn_mut(f: F) -> F { f } @@ -12,7 +10,6 @@ fn a() { let mut x = 3; let c1 = to_fn_mut(|| x = 4); let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once - //~| ERROR cannot borrow `x` as mutable more than once drop((c1, c2)); } @@ -24,7 +21,6 @@ fn b() { let mut x = 3; let c1 = to_fn_mut(|| set(&mut x)); let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once - //~| ERROR cannot borrow `x` as mutable more than once drop((c1, c2)); } @@ -32,7 +28,6 @@ fn c() { let mut x = 3; let c1 = to_fn_mut(|| x = 5); let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once - //~| ERROR cannot borrow `x` as mutable more than once drop((c1, c2)); } @@ -41,7 +36,6 @@ fn d() { let c1 = to_fn_mut(|| x = 5); let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) //~^ ERROR cannot borrow `x` as mutable more than once - //~| ERROR cannot borrow `x` as mutable more than once drop((c1, c2)); } @@ -54,7 +48,6 @@ fn g() { let c1 = to_fn_mut(|| set(&mut *x.f)); let c2 = to_fn_mut(|| set(&mut *x.f)); //~^ ERROR cannot borrow `x` as mutable more than once - //~| ERROR cannot borrow `x` as mutable more than once drop((c1, c2)); } diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr index bfb7069461588..bffb11640744c 100644 --- a/src/test/ui/borrowck/borrowck-closures-two-mut.stderr +++ b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr @@ -1,125 +1,47 @@ -error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) - --> $DIR/borrowck-closures-two-mut.rs:14:24 - | -LL | let c1 = to_fn_mut(|| x = 4); - | -- - previous borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once - | ^^ - borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) - --> $DIR/borrowck-closures-two-mut.rs:26:24 - | -LL | let c1 = to_fn_mut(|| set(&mut x)); - | -- - previous borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once - | ^^ - borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) - --> $DIR/borrowck-closures-two-mut.rs:34:24 - | -LL | let c1 = to_fn_mut(|| x = 5); - | -- - previous borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once - | ^^ - borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) - --> $DIR/borrowck-closures-two-mut.rs:42:24 - | -LL | let c1 = to_fn_mut(|| x = 5); - | -- - previous borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) - | ^^ - borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) - --> $DIR/borrowck-closures-two-mut.rs:55:24 - | -LL | let c1 = to_fn_mut(|| set(&mut *x.f)); - | -- - previous borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| set(&mut *x.f)); - | ^^ - borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir) - --> $DIR/borrowck-closures-two-mut.rs:14:24 +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut.rs:12:24 | LL | let c1 = to_fn_mut(|| x = 4); | -- - first borrow occurs due to use of `x` in closure | | | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once +LL | let c2 = to_fn_mut(|| x = 5); | ^^ - second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here -LL | //~| ERROR cannot borrow `x` as mutable more than once LL | drop((c1, c2)); | -- first borrow later used here -error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir) - --> $DIR/borrowck-closures-two-mut.rs:26:24 +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut.rs:23:24 | LL | let c1 = to_fn_mut(|| set(&mut x)); | -- - first borrow occurs due to use of `x` in closure | | | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once +LL | let c2 = to_fn_mut(|| set(&mut x)); | ^^ - second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here -LL | //~| ERROR cannot borrow `x` as mutable more than once LL | drop((c1, c2)); | -- first borrow later used here -error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir) - --> $DIR/borrowck-closures-two-mut.rs:34:24 +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut.rs:30:24 | LL | let c1 = to_fn_mut(|| x = 5); | -- - first borrow occurs due to use of `x` in closure | | | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once +LL | let c2 = to_fn_mut(|| set(&mut x)); | ^^ - second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here -LL | //~| ERROR cannot borrow `x` as mutable more than once LL | drop((c1, c2)); | -- first borrow later used here -error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir) - --> $DIR/borrowck-closures-two-mut.rs:42:24 +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut.rs:37:24 | LL | let c1 = to_fn_mut(|| x = 5); | -- - first borrow occurs due to use of `x` in closure @@ -129,12 +51,12 @@ LL | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nes | ^^ - second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here -... +LL | LL | drop((c1, c2)); | -- first borrow later used here -error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir) - --> $DIR/borrowck-closures-two-mut.rs:55:24 +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut.rs:49:24 | LL | let c1 = to_fn_mut(|| set(&mut *x.f)); | -- - first borrow occurs due to use of `x` in closure @@ -144,10 +66,10 @@ LL | let c2 = to_fn_mut(|| set(&mut *x.f)); | ^^ - second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here -... +LL | LL | drop((c1, c2)); | -- first borrow later used here -error: aborting due to 10 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-closures-unique-imm.nll.stderr b/src/test/ui/borrowck/borrowck-closures-unique-imm.nll.stderr deleted file mode 100644 index 80e042fc8fc45..0000000000000 --- a/src/test/ui/borrowck/borrowck-closures-unique-imm.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0502]: cannot borrow `this.x` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-closures-unique-imm.rs:11:9 - | -LL | let p = &this.x; - | ------- immutable borrow occurs here -LL | &mut this.x; //~ ERROR cannot borrow - | ^^^^^^^^^^^ mutable borrow occurs here -LL | p.use_ref(); - | - immutable borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-closures-unique-imm.stderr b/src/test/ui/borrowck/borrowck-closures-unique-imm.stderr index 1b661b70d7f5b..b8bbb31a3550f 100644 --- a/src/test/ui/borrowck/borrowck-closures-unique-imm.stderr +++ b/src/test/ui/borrowck/borrowck-closures-unique-imm.stderr @@ -1,13 +1,12 @@ error[E0502]: cannot borrow `this.x` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-closures-unique-imm.rs:11:14 + --> $DIR/borrowck-closures-unique-imm.rs:11:9 | LL | let p = &this.x; - | ------ immutable borrow occurs here -LL | &mut this.x; //~ ERROR cannot borrow - | ^^^^^^ mutable borrow occurs here + | ------- immutable borrow occurs here +LL | &mut this.x; + | ^^^^^^^^^^^ mutable borrow occurs here LL | p.use_ref(); -LL | }; - | - immutable borrow ends here + | - immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-closures-unique.nll.stderr b/src/test/ui/borrowck/borrowck-closures-unique.nll.stderr deleted file mode 100644 index d6082734451f2..0000000000000 --- a/src/test/ui/borrowck/borrowck-closures-unique.nll.stderr +++ /dev/null @@ -1,54 +0,0 @@ -error[E0500]: closure requires unique access to `x` but it is already borrowed - --> $DIR/borrowck-closures-unique.rs:26:14 - | -LL | let c1 = || get(x); - | -- - first borrow occurs due to use of `x` in closure - | | - | borrow occurs here -LL | let c2 = || set(x); //~ ERROR closure requires unique access to `x` - | ^^ - second borrow occurs due to use of `x` in closure - | | - | closure construction occurs here -LL | c1; - | -- first borrow later used here - -error[E0500]: closure requires unique access to `x` but it is already borrowed - --> $DIR/borrowck-closures-unique.rs:32:14 - | -LL | let c1 = || get(x); - | -- - first borrow occurs due to use of `x` in closure - | | - | borrow occurs here -LL | let c2 = || { get(x); set(x); }; //~ ERROR closure requires unique access to `x` - | ^^ - second borrow occurs due to use of `x` in closure - | | - | closure construction occurs here -LL | c1; - | -- first borrow later used here - -error[E0524]: two closures require unique access to `x` at the same time - --> $DIR/borrowck-closures-unique.rs:38:14 - | -LL | let c1 = || set(x); - | -- - first borrow occurs due to use of `x` in closure - | | - | first closure is constructed here -LL | let c2 = || set(x); //~ ERROR two closures require unique access to `x` at the same time - | ^^ - second borrow occurs due to use of `x` in closure - | | - | second closure is constructed here -LL | c1; - | -- first borrow later used here - -error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/borrowck-closures-unique.rs:47:38 - | -LL | fn e(x: &'static mut isize) { - | - help: consider changing this to be mutable: `mut x` -LL | let c1 = |y: &'static mut isize| x = y; //~ ERROR closure cannot assign to immutable argument - | ^^^^^ cannot assign - -error: aborting due to 4 previous errors - -Some errors occurred: E0500, E0524, E0594. -For more information about an error, try `rustc --explain E0500`. diff --git a/src/test/ui/borrowck/borrowck-closures-unique.rs b/src/test/ui/borrowck/borrowck-closures-unique.rs index a4655ebba116e..67f91dfa8420e 100644 --- a/src/test/ui/borrowck/borrowck-closures-unique.rs +++ b/src/test/ui/borrowck/borrowck-closures-unique.rs @@ -39,17 +39,14 @@ fn d(x: &mut isize) { c1; } -// This test was originally encoded in the form shown as `fn f` below. -// However, since MIR-borrowck and thus NLL takes more control-flow information -// into account, it was necessary to change the test in order to witness the -// same (expected) error under both AST-borrowck and NLL. fn e(x: &'static mut isize) { - let c1 = |y: &'static mut isize| x = y; //~ ERROR closure cannot assign to immutable argument + let c1 = |y: &'static mut isize| x = y; + //~^ ERROR cannot assign to `x`, as it is not declared as mutable c1; } fn f(x: &'static mut isize) { - let c1 = || x = panic!(); //~ ERROR closure cannot assign to immutable argument + let c1 = || x = panic!(); // OK assignment is unreachable. c1; } diff --git a/src/test/ui/borrowck/borrowck-closures-unique.stderr b/src/test/ui/borrowck/borrowck-closures-unique.stderr index 94181ad2400d7..9b53af4c01f59 100644 --- a/src/test/ui/borrowck/borrowck-closures-unique.stderr +++ b/src/test/ui/borrowck/borrowck-closures-unique.stderr @@ -2,68 +2,52 @@ error[E0500]: closure requires unique access to `x` but it is already borrowed --> $DIR/borrowck-closures-unique.rs:26:14 | LL | let c1 = || get(x); - | -- - previous borrow occurs due to use of `x` in closure + | -- - first borrow occurs due to use of `x` in closure | | | borrow occurs here -LL | let c2 = || set(x); //~ ERROR closure requires unique access to `x` - | ^^ - borrow occurs due to use of `x` in closure +LL | let c2 = || set(x); + | ^^ - second borrow occurs due to use of `x` in closure | | | closure construction occurs here LL | c1; -LL | } - | - borrow ends here + | -- first borrow later used here error[E0500]: closure requires unique access to `x` but it is already borrowed --> $DIR/borrowck-closures-unique.rs:32:14 | LL | let c1 = || get(x); - | -- - previous borrow occurs due to use of `x` in closure + | -- - first borrow occurs due to use of `x` in closure | | | borrow occurs here -LL | let c2 = || { get(x); set(x); }; //~ ERROR closure requires unique access to `x` - | ^^ - borrow occurs due to use of `x` in closure +LL | let c2 = || { get(x); set(x); }; + | ^^ - second borrow occurs due to use of `x` in closure | | | closure construction occurs here LL | c1; -LL | } - | - borrow ends here + | -- first borrow later used here error[E0524]: two closures require unique access to `x` at the same time --> $DIR/borrowck-closures-unique.rs:38:14 | LL | let c1 = || set(x); - | -- - previous borrow occurs due to use of `x` in closure + | -- - first borrow occurs due to use of `x` in closure | | | first closure is constructed here -LL | let c2 = || set(x); //~ ERROR two closures require unique access to `x` at the same time - | ^^ - borrow occurs due to use of `x` in closure +LL | let c2 = || set(x); + | ^^ - second borrow occurs due to use of `x` in closure | | | second closure is constructed here LL | c1; -LL | } - | - borrow from first closure ends here + | -- first borrow later used here -error[E0595]: closure cannot assign to immutable argument `x` - --> $DIR/borrowck-closures-unique.rs:47:14 +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/borrowck-closures-unique.rs:43:38 | -LL | let c1 = |y: &'static mut isize| x = y; //~ ERROR closure cannot assign to immutable argument - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow mutably -help: consider removing the `&mut`, as it is an immutable binding to a mutable reference - | -LL | x //~ ERROR closure cannot assign to immutable argument - | ^ - -error[E0595]: closure cannot assign to immutable argument `x` - --> $DIR/borrowck-closures-unique.rs:52:14 - | -LL | let c1 = || x = panic!(); //~ ERROR closure cannot assign to immutable argument - | ^^ cannot borrow mutably -help: consider removing the `&mut`, as it is an immutable binding to a mutable reference - | -LL | x //~ ERROR closure cannot assign to immutable argument - | ^ +LL | fn e(x: &'static mut isize) { + | - help: consider changing this to be mutable: `mut x` +LL | let c1 = |y: &'static mut isize| x = y; + | ^^^^^ cannot assign -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors -Some errors occurred: E0500, E0524, E0595. -For more information about an error, try `rustc --explain E0500`. +For more information about this error, try `rustc --explain E0500`. diff --git a/src/test/ui/borrowck/borrowck-closures-use-after-free.nll.stderr b/src/test/ui/borrowck/borrowck-closures-use-after-free.nll.stderr deleted file mode 100644 index 4501e28a18816..0000000000000 --- a/src/test/ui/borrowck/borrowck-closures-use-after-free.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-closures-use-after-free.rs:22:8 - | -LL | let mut test = |foo: &Foo| { - | ----------- mutable borrow occurs here -LL | ptr = box Foo { x: ptr.x + 1 }; - | --- first borrow occurs due to use of `ptr` in closure -LL | }; -LL | test(&*ptr); //~ ERROR cannot borrow `*ptr` - | ---- ^^^^^ immutable borrow occurs here - | | - | mutable borrow later used by call - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr b/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr index b41a4a0c6768c..f22b7da811949 100644 --- a/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr +++ b/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr @@ -1,15 +1,15 @@ -error[E0502]: cannot borrow `*ptr` as immutable because `ptr` is also borrowed as mutable - --> $DIR/borrowck-closures-use-after-free.rs:22:9 +error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-closures-use-after-free.rs:22:8 | LL | let mut test = |foo: &Foo| { | ----------- mutable borrow occurs here LL | ptr = box Foo { x: ptr.x + 1 }; - | --- previous borrow occurs due to use of `ptr` in closure + | --- first borrow occurs due to use of `ptr` in closure LL | }; -LL | test(&*ptr); //~ ERROR cannot borrow `*ptr` - | ^^^^ immutable borrow occurs here -LL | } - | - mutable borrow ends here +LL | test(&*ptr); + | ---- ^^^^^ immutable borrow occurs here + | | + | mutable borrow later used by call error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-consume-unsize-vec.nll.stderr b/src/test/ui/borrowck/borrowck-consume-unsize-vec.nll.stderr deleted file mode 100644 index ea7683a91adfe..0000000000000 --- a/src/test/ui/borrowck/borrowck-consume-unsize-vec.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: use of moved value: `b` - --> $DIR/borrowck-consume-unsize-vec.rs:8:13 - | -LL | fn foo(b: Box<[i32;5]>) { - | - move occurs because `b` has type `std::boxed::Box<[i32; 5]>`, which does not implement the `Copy` trait -LL | consume(b); - | - value moved here -LL | consume(b); //~ ERROR use of moved value - | ^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr index 2fc2248000f3d..c69237fa95f65 100644 --- a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr +++ b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr @@ -1,12 +1,12 @@ error[E0382]: use of moved value: `b` --> $DIR/borrowck-consume-unsize-vec.rs:8:13 | +LL | fn foo(b: Box<[i32;5]>) { + | - move occurs because `b` has type `std::boxed::Box<[i32; 5]>`, which does not implement the `Copy` trait LL | consume(b); | - value moved here -LL | consume(b); //~ ERROR use of moved value +LL | consume(b); | ^ value used here after move - | - = note: move occurs because `b` has type `std::boxed::Box<[i32; 5]>`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-consume-upcast-box.nll.stderr b/src/test/ui/borrowck/borrowck-consume-upcast-box.nll.stderr deleted file mode 100644 index 15cf359326be9..0000000000000 --- a/src/test/ui/borrowck/borrowck-consume-upcast-box.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: use of moved value: `b` - --> $DIR/borrowck-consume-upcast-box.rs:10:13 - | -LL | fn foo(b: Box) { - | - move occurs because `b` has type `std::boxed::Box`, which does not implement the `Copy` trait -LL | consume(b); - | - value moved here -LL | consume(b); //~ ERROR use of moved value - | ^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-consume-upcast-box.rs b/src/test/ui/borrowck/borrowck-consume-upcast-box.rs index ed669c4d90151..6b32d185b6fdf 100644 --- a/src/test/ui/borrowck/borrowck-consume-upcast-box.rs +++ b/src/test/ui/borrowck/borrowck-consume-upcast-box.rs @@ -2,10 +2,10 @@ trait Foo { fn dummy(&self); } -fn consume(_: Box) { +fn consume(_: Box) { } -fn foo(b: Box) { +fn foo(b: Box) { consume(b); consume(b); //~ ERROR use of moved value } diff --git a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr index aef1671342ef4..356cda01e29c8 100644 --- a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr +++ b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr @@ -1,12 +1,12 @@ error[E0382]: use of moved value: `b` --> $DIR/borrowck-consume-upcast-box.rs:10:13 | +LL | fn foo(b: Box) { + | - move occurs because `b` has type `std::boxed::Box`, which does not implement the `Copy` trait LL | consume(b); | - value moved here -LL | consume(b); //~ ERROR use of moved value +LL | consume(b); | ^ value used here after move - | - = note: move occurs because `b` has type `std::boxed::Box<(dyn Foo + std::marker::Send + 'static)>`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr deleted file mode 100644 index 24467faa90ca9..0000000000000 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr +++ /dev/null @@ -1,383 +0,0 @@ -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:285:13 - | -LL | let y = &mut x; - | ------ first mutable borrow occurs here -LL | &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time - | ^^^^^^ second mutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time -LL | *y = 1; - | ------ first borrow later used here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:296:20 - | -LL | let y = &mut x; - | ------ first mutable borrow occurs here -LL | &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time - | ^^^^^^ second mutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time -LL | *y = 1; - | ------ first borrow later used here - -error: captured variable cannot escape `FnMut` closure body - --> $DIR/borrowck-describe-lvalue.rs:294:16 - | -LL | || { - | - inferred to be a `FnMut` closure -LL | / || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body -LL | | let y = &mut x; -LL | | &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time -LL | | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time -LL | | *y = 1; -LL | | drop(y); -LL | | } - | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body - | - = note: `FnMut` closures only have access to their captured variables while they are executing... - = note: ...therefore, they cannot allow references to captured variables to escape - -error[E0503]: cannot use `f.x` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:43:9 - | -LL | let x = f.x(); - | - borrow of `f` occurs here -LL | f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed - | ^^^ use of borrowed `f` -LL | //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `g.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:51:9 - | -LL | let x = g.x(); - | - borrow of `g` occurs here -LL | g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed - | ^^^ use of borrowed `g` -LL | //[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `h.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:59:9 - | -LL | let x = &mut h.0; - | -------- borrow of `h.0` occurs here -LL | h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed - | ^^^ use of borrowed `h.0` -LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `e.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:68:20 - | -LL | let x = e.x(); - | - borrow of `e` occurs here -LL | match e { -LL | Baz::X(value) => value - | ^^^^^ use of borrowed `e` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `u.a` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:78:9 - | -LL | let x = &mut u.a; - | -------- borrow of `u.a` occurs here -LL | u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed - | ^^^ use of borrowed `u.a` -LL | //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `f.x` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:86:9 - | -LL | let x = f.x(); - | - borrow of `*f` occurs here -LL | f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed - | ^^^ use of borrowed `*f` -LL | //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `g.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:94:9 - | -LL | let x = g.x(); - | - borrow of `*g` occurs here -LL | g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed - | ^^^ use of borrowed `*g` -LL | //[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `h.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:102:9 - | -LL | let x = &mut h.0; - | -------- borrow of `h.0` occurs here -LL | h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed - | ^^^ use of borrowed `h.0` -LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `e.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:111:20 - | -LL | let x = e.x(); - | - borrow of `*e` occurs here -LL | match *e { -LL | Baz::X(value) => value - | ^^^^^ use of borrowed `*e` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `u.a` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:121:9 - | -LL | let x = &mut u.a; - | -------- borrow of `u.a` occurs here -LL | u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed - | ^^^ use of borrowed `u.a` -LL | //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:130:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { -LL | &[x, _, .., _, _] => println!("{}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:136:18 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, x, .., _, _] => println!("{}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:142:25 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, _, .., x, _] => println!("{}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:148:28 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, _, .., _, x] => println!("{}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:160:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { -LL | &[x..] => println!("{:?}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:166:18 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, x..] => println!("{:?}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:172:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[x.., _] => println!("{:?}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:178:18 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, x.., _] => println!("{:?}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:192:13 - | -LL | let x = &mut e; - | ------ borrow of `e` occurs here -LL | match e { -LL | E::A(ref ax) => - | ^^^^^^^^^^^^ use of borrowed `e` -... -LL | drop(x); - | - borrow later used here - -error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:192:18 - | -LL | let x = &mut e; - | ------ mutable borrow occurs here -LL | match e { -LL | E::A(ref ax) => - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0502]: cannot borrow `e.x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:197:23 - | -LL | let x = &mut e; - | ------ mutable borrow occurs here -... -LL | E::B { x: ref bx } => - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:211:22 - | -LL | let x = &mut s; - | ------ mutable borrow occurs here -LL | match s { -LL | S { y: (ref y0, _), .. } => - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:218:28 - | -LL | let x = &mut s; - | ------ mutable borrow occurs here -... -LL | S { x: F { y: ref x0, .. }, .. } => - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0503]: cannot use `*v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:261:9 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | v[0].y; - | ^^^^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[_].y` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:261:9 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | v[0].y; - | ^^^^^^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:273:24 - | -LL | let x = &mut v; - | ------ mutable borrow occurs here -LL | match v { -LL | &[_, F {x: ref xf, ..}] => println!("{}", xf), - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:235:29 - | -LL | let x = &mut block; - | ---------- mutable borrow occurs here -LL | let p: &'a u8 = &*block.current; - | ^^^^^^^^^^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - -warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:250:33 - | -LL | let x = &mut block; - | ---------- mutable borrow occurs here -LL | let p : *const u8 = &*(*block).current; - | ^^^^^^^^^^^^^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - -error[E0382]: use of moved value: `x` - --> $DIR/borrowck-describe-lvalue.rs:307:22 - | -LL | drop(x); - | - value moved here -LL | drop(x); //[ast]~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait - -error: aborting due to 30 previous errors - -Some errors occurred: E0382, E0499, E0502, E0503. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr deleted file mode 100644 index 278929eedb008..0000000000000 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr +++ /dev/null @@ -1,246 +0,0 @@ -error[E0503]: cannot use `f.x` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:43:9 - | -LL | let x = f.x(); - | - borrow of `f` occurs here -LL | f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed - | ^^^ use of borrowed `f` - -error[E0503]: cannot use `g.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:51:9 - | -LL | let x = g.x(); - | - borrow of `g` occurs here -LL | g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed - | ^^^ use of borrowed `g` - -error[E0503]: cannot use `h.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:59:9 - | -LL | let x = &mut h.0; - | --- borrow of `h.0` occurs here -LL | h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed - | ^^^ use of borrowed `h.0` - -error[E0503]: cannot use `e.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:68:20 - | -LL | let x = e.x(); - | - borrow of `e` occurs here -LL | match e { -LL | Baz::X(value) => value - | ^^^^^ use of borrowed `e` - -error[E0503]: cannot use `u.a` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:78:9 - | -LL | let x = &mut u.a; - | --- borrow of `u.a` occurs here -LL | u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed - | ^^^ use of borrowed `u.a` - -error[E0503]: cannot use `f.x` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:86:9 - | -LL | let x = f.x(); - | - borrow of `*f` occurs here -LL | f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed - | ^^^ use of borrowed `*f` - -error[E0503]: cannot use `g.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:94:9 - | -LL | let x = g.x(); - | - borrow of `*g` occurs here -LL | g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed - | ^^^ use of borrowed `*g` - -error[E0503]: cannot use `h.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:102:9 - | -LL | let x = &mut h.0; - | --- borrow of `h.0` occurs here -LL | h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed - | ^^^ use of borrowed `h.0` - -error[E0503]: cannot use `e.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:111:20 - | -LL | let x = e.x(); - | - borrow of `*e` occurs here -LL | match *e { -LL | Baz::X(value) => value - | ^^^^^ use of borrowed `*e` - -error[E0503]: cannot use `u.a` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:121:9 - | -LL | let x = &mut u.a; - | --- borrow of `u.a` occurs here -LL | u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed - | ^^^ use of borrowed `u.a` - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:130:15 - | -LL | let x = &mut v; - | - borrow of `v` occurs here -LL | match v { -LL | &[x, _, .., _, _] => println!("{}", x), - | ^ use of borrowed `v` - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:136:18 - | -LL | let x = &mut v; - | - borrow of `v` occurs here -... -LL | &[_, x, .., _, _] => println!("{}", x), - | ^ use of borrowed `v` - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:142:25 - | -LL | let x = &mut v; - | - borrow of `v` occurs here -... -LL | &[_, _, .., x, _] => println!("{}", x), - | ^ use of borrowed `v` - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:148:28 - | -LL | let x = &mut v; - | - borrow of `v` occurs here -... -LL | &[_, _, .., _, x] => println!("{}", x), - | ^ use of borrowed `v` - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:160:15 - | -LL | let x = &mut v; - | - borrow of `v` occurs here -LL | match v { -LL | &[x..] => println!("{:?}", x), - | ^ use of borrowed `v` - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:166:18 - | -LL | let x = &mut v; - | - borrow of `v` occurs here -... -LL | &[_, x..] => println!("{:?}", x), - | ^ use of borrowed `v` - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:172:15 - | -LL | let x = &mut v; - | - borrow of `v` occurs here -... -LL | &[x.., _] => println!("{:?}", x), - | ^ use of borrowed `v` - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:178:18 - | -LL | let x = &mut v; - | - borrow of `v` occurs here -... -LL | &[_, x.., _] => println!("{:?}", x), - | ^ use of borrowed `v` - -error[E0502]: cannot borrow `e.0` as immutable because `e` is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:192:18 - | -LL | let x = &mut e; - | - mutable borrow occurs here -LL | match e { -LL | E::A(ref ax) => - | ^^^^^^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here - -error[E0502]: cannot borrow `e.x` as immutable because `e` is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:197:23 - | -LL | let x = &mut e; - | - mutable borrow occurs here -... -LL | E::B { x: ref bx } => - | ^^^^^^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here - -error[E0502]: cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:211:22 - | -LL | let x = &mut s; - | - mutable borrow occurs here -LL | match s { -LL | S { y: (ref y0, _), .. } => - | ^^^^^^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here - -error[E0502]: cannot borrow `s.x.y` as immutable because `s` is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:218:28 - | -LL | let x = &mut s; - | - mutable borrow occurs here -... -LL | S { x: F { y: ref x0, .. }, .. } => - | ^^^^^^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here - -error[E0503]: cannot use `v[..].y` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:261:9 - | -LL | let x = &mut v; - | - borrow of `v` occurs here -LL | v[0].y; - | ^^^^^^ use of borrowed `v` - -error[E0499]: cannot borrow `**x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:285:18 - | -LL | let y = &mut x; - | - first mutable borrow occurs here -LL | &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time - | ^ second mutable borrow occurs here -... -LL | }; - | - first borrow ends here - -error[E0499]: cannot borrow `**x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:296:25 - | -LL | let y = &mut x; - | - first mutable borrow occurs here -LL | &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time - | ^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0382]: use of moved value: `x` - --> $DIR/borrowck-describe-lvalue.rs:307:22 - | -LL | drop(x); - | - value moved here -LL | drop(x); //[ast]~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait - -error: aborting due to 26 previous errors - -Some errors occurred: E0382, E0499, E0502, E0503. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr deleted file mode 100644 index 279548f870fd0..0000000000000 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr +++ /dev/null @@ -1,377 +0,0 @@ -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:285:13 - | -LL | let y = &mut x; - | ------ first mutable borrow occurs here -LL | &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time - | ^^^^^^ second mutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time -LL | *y = 1; - | ------ first borrow later used here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:296:20 - | -LL | let y = &mut x; - | ------ first mutable borrow occurs here -LL | &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time - | ^^^^^^ second mutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time -LL | *y = 1; - | ------ first borrow later used here - -error: captured variable cannot escape `FnMut` closure body - --> $DIR/borrowck-describe-lvalue.rs:294:16 - | -LL | || { - | - inferred to be a `FnMut` closure -LL | / || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body -LL | | let y = &mut x; -LL | | &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time -LL | | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time -LL | | *y = 1; -LL | | drop(y); -LL | | } - | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body - | - = note: `FnMut` closures only have access to their captured variables while they are executing... - = note: ...therefore, they cannot allow references to captured variables to escape - -error[E0503]: cannot use `f.x` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:43:9 - | -LL | let x = f.x(); - | - borrow of `f` occurs here -LL | f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed - | ^^^ use of borrowed `f` -LL | //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `g.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:51:9 - | -LL | let x = g.x(); - | - borrow of `g` occurs here -LL | g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed - | ^^^ use of borrowed `g` -LL | //[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `h.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:59:9 - | -LL | let x = &mut h.0; - | -------- borrow of `h.0` occurs here -LL | h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed - | ^^^ use of borrowed `h.0` -LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `e.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:68:20 - | -LL | let x = e.x(); - | - borrow of `e` occurs here -LL | match e { -LL | Baz::X(value) => value - | ^^^^^ use of borrowed `e` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `u.a` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:78:9 - | -LL | let x = &mut u.a; - | -------- borrow of `u.a` occurs here -LL | u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed - | ^^^ use of borrowed `u.a` -LL | //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `f.x` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:86:9 - | -LL | let x = f.x(); - | - borrow of `*f` occurs here -LL | f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed - | ^^^ use of borrowed `*f` -LL | //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `g.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:94:9 - | -LL | let x = g.x(); - | - borrow of `*g` occurs here -LL | g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed - | ^^^ use of borrowed `*g` -LL | //[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `h.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:102:9 - | -LL | let x = &mut h.0; - | -------- borrow of `h.0` occurs here -LL | h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed - | ^^^ use of borrowed `h.0` -LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `e.0` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:111:20 - | -LL | let x = e.x(); - | - borrow of `*e` occurs here -LL | match *e { -LL | Baz::X(value) => value - | ^^^^^ use of borrowed `*e` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `u.a` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:121:9 - | -LL | let x = &mut u.a; - | -------- borrow of `u.a` occurs here -LL | u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed - | ^^^ use of borrowed `u.a` -LL | //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:130:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { -LL | &[x, _, .., _, _] => println!("{}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:136:18 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, x, .., _, _] => println!("{}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:142:25 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, _, .., x, _] => println!("{}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:148:28 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, _, .., _, x] => println!("{}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:160:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { -LL | &[x..] => println!("{:?}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:166:18 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, x..] => println!("{:?}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:172:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[x.., _] => println!("{:?}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[..]` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:178:18 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | &[_, x.., _] => println!("{:?}", x), - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:192:13 - | -LL | let x = &mut e; - | ------ borrow of `e` occurs here -LL | match e { -LL | E::A(ref ax) => - | ^^^^^^^^^^^^ use of borrowed `e` -... -LL | drop(x); - | - borrow later used here - -error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:192:18 - | -LL | let x = &mut e; - | ------ mutable borrow occurs here -LL | match e { -LL | E::A(ref ax) => - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0502]: cannot borrow `e.x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:197:23 - | -LL | let x = &mut e; - | ------ mutable borrow occurs here -... -LL | E::B { x: ref bx } => - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:211:22 - | -LL | let x = &mut s; - | ------ mutable borrow occurs here -LL | match s { -LL | S { y: (ref y0, _), .. } => - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:218:28 - | -LL | let x = &mut s; - | ------ mutable borrow occurs here -... -LL | S { x: F { y: ref x0, .. }, .. } => - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0503]: cannot use `*v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:261:9 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | v[0].y; - | ^^^^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0503]: cannot use `v[_].y` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:261:9 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | v[0].y; - | ^^^^^^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - -error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:273:24 - | -LL | let x = &mut v; - | ------ mutable borrow occurs here -LL | match v { -LL | &[_, F {x: ref xf, ..}] => println!("{}", xf), - | ^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:235:29 - | -LL | let x = &mut block; - | ---------- mutable borrow occurs here -LL | let p: &'a u8 = &*block.current; - | ^^^^^^^^^^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:250:33 - | -LL | let x = &mut block; - | ---------- mutable borrow occurs here -LL | let p : *const u8 = &*(*block).current; - | ^^^^^^^^^^^^^^^^^^ immutable borrow occurs here -... -LL | drop(x); - | - mutable borrow later used here - -error[E0382]: use of moved value: `x` - --> $DIR/borrowck-describe-lvalue.rs:307:22 - | -LL | drop(x); - | - value moved here -LL | drop(x); //[ast]~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait - -error: aborting due to 32 previous errors - -Some errors occurred: E0382, E0499, E0502, E0503. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr new file mode 100644 index 0000000000000..f1e1ae18839c4 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr @@ -0,0 +1,366 @@ +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-describe-lvalue.rs:262:13 + | +LL | let y = &mut x; + | ------ first mutable borrow occurs here +LL | &mut x; + | ^^^^^^ second mutable borrow occurs here +LL | *y = 1; + | ------ first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-describe-lvalue.rs:272:20 + | +LL | let y = &mut x; + | ------ first mutable borrow occurs here +LL | &mut x; + | ^^^^^^ second mutable borrow occurs here +LL | *y = 1; + | ------ first borrow later used here + +error: captured variable cannot escape `FnMut` closure body + --> $DIR/borrowck-describe-lvalue.rs:270:16 + | +LL | || { + | - inferred to be a `FnMut` closure +LL | / || { +LL | | let y = &mut x; +LL | | &mut x; +LL | | *y = 1; +LL | | drop(y); +LL | | } + | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + +error[E0503]: cannot use `f.x` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:41:9 + | +LL | let x = f.x(); + | - borrow of `f` occurs here +LL | f.x; + | ^^^ use of borrowed `f` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `g.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:48:9 + | +LL | let x = g.x(); + | - borrow of `g` occurs here +LL | g.0; + | ^^^ use of borrowed `g` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `h.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:55:9 + | +LL | let x = &mut h.0; + | -------- borrow of `h.0` occurs here +LL | h.0; + | ^^^ use of borrowed `h.0` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `e.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:63:20 + | +LL | let x = e.x(); + | - borrow of `e` occurs here +LL | match e { +LL | Baz::X(value) => value + | ^^^^^ use of borrowed `e` +LL | }; +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `u.a` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:71:9 + | +LL | let x = &mut u.a; + | -------- borrow of `u.a` occurs here +LL | u.a; + | ^^^ use of borrowed `u.a` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `f.x` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:78:9 + | +LL | let x = f.x(); + | - borrow of `*f` occurs here +LL | f.x; + | ^^^ use of borrowed `*f` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `g.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:85:9 + | +LL | let x = g.x(); + | - borrow of `*g` occurs here +LL | g.0; + | ^^^ use of borrowed `*g` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `h.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:92:9 + | +LL | let x = &mut h.0; + | -------- borrow of `h.0` occurs here +LL | h.0; + | ^^^ use of borrowed `h.0` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `e.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:100:20 + | +LL | let x = e.x(); + | - borrow of `*e` occurs here +LL | match *e { +LL | Baz::X(value) => value + | ^^^^^ use of borrowed `*e` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `u.a` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:109:9 + | +LL | let x = &mut u.a; + | -------- borrow of `u.a` occurs here +LL | u.a; + | ^^^ use of borrowed `u.a` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:117:15 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +LL | match v { +LL | &[x, _, .., _, _] => println!("{}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:122:18 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, x, .., _, _] => println!("{}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:127:25 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, _, .., x, _] => println!("{}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:132:28 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, _, .., _, x] => println!("{}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:143:15 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +LL | match v { +LL | &[x..] => println!("{:?}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:148:18 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, x..] => println!("{:?}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:153:15 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[x.., _] => println!("{:?}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:158:18 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, x.., _] => println!("{:?}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `e` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:171:13 + | +LL | let x = &mut e; + | ------ borrow of `e` occurs here +LL | match e { +LL | E::A(ref ax) => + | ^^^^^^^^^^^^ use of borrowed `e` +... +LL | drop(x); + | - borrow later used here + +error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:171:18 + | +LL | let x = &mut e; + | ------ mutable borrow occurs here +LL | match e { +LL | E::A(ref ax) => + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0502]: cannot borrow `e.x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:175:23 + | +LL | let x = &mut e; + | ------ mutable borrow occurs here +... +LL | E::B { x: ref bx } => + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:188:22 + | +LL | let x = &mut s; + | ------ mutable borrow occurs here +LL | match s { +LL | S { y: (ref y0, _), .. } => + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:194:28 + | +LL | let x = &mut s; + | ------ mutable borrow occurs here +... +LL | S { x: F { y: ref x0, .. }, .. } => + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0503]: cannot use `*v` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:240:9 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +LL | v[0].y; + | ^^^^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[_].y` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:240:9 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +LL | v[0].y; + | ^^^^^^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:251:24 + | +LL | let x = &mut v; + | ------ mutable borrow occurs here +LL | match v { +LL | &[_, F {x: ref xf, ..}] => println!("{}", xf), + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:210:29 + | +LL | let x = &mut block; + | ---------- mutable borrow occurs here +LL | let p: &'a u8 = &*block.current; + | ^^^^^^^^^^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:227:33 + | +LL | let x = &mut block; + | ---------- mutable borrow occurs here +LL | let p : *const u8 = &*(*block).current; + | ^^^^^^^^^^^^^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0382]: use of moved value: `x` + --> $DIR/borrowck-describe-lvalue.rs:282:22 + | +LL | drop(x); + | - value moved here +LL | drop(x); + | ^ value used here after move + | + = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + +error: aborting due to 32 previous errors + +Some errors have detailed explanations: E0382, E0499, E0502, E0503. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.rs b/src/test/ui/borrowck/borrowck-describe-lvalue.rs index eb622ac10addf..c8dbf4e691816 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.rs @@ -1,6 +1,4 @@ // ignore-tidy-linelength -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir #![feature(slice_patterns)] @@ -40,24 +38,21 @@ fn main() { { let mut f = Foo { x: 22 }; let x = f.x(); - f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed - //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed + f.x; //~ ERROR cannot use `f.x` because it was mutably borrowed drop(x); } // Local and field from tuple-struct { let mut g = Bar(22); let x = g.x(); - g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed - //[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed + g.0; //~ ERROR cannot use `g.0` because it was mutably borrowed drop(x); } // Local and field from tuple { let mut h = (22, 23); let x = &mut h.0; - h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed - //[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed + h.0; //~ ERROR cannot use `h.0` because it was mutably borrowed drop(x); } // Local and field from enum @@ -65,9 +60,7 @@ fn main() { let mut e = Baz::X(2); let x = e.x(); match e { - Baz::X(value) => value - //[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed - //[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed + Baz::X(value) => value //~ ERROR cannot use `e.0` because it was mutably borrowed }; drop(x); } @@ -75,32 +68,28 @@ fn main() { unsafe { let mut u = U { b: 0 }; let x = &mut u.a; - u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed - //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed + u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed drop(x); } // Deref and field from struct { let mut f = Box::new(Foo { x: 22 }); let x = f.x(); - f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed - //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed + f.x; //~ ERROR cannot use `f.x` because it was mutably borrowed drop(x); } // Deref and field from tuple-struct { let mut g = Box::new(Bar(22)); let x = g.x(); - g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed - //[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed + g.0; //~ ERROR cannot use `g.0` because it was mutably borrowed drop(x); } // Deref and field from tuple { let mut h = Box::new((22, 23)); let x = &mut h.0; - h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed - //[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed + h.0; //~ ERROR cannot use `h.0` because it was mutably borrowed drop(x); } // Deref and field from enum @@ -109,8 +98,7 @@ fn main() { let x = e.x(); match *e { Baz::X(value) => value - //[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed - //[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed + //~^ ERROR cannot use `e.0` because it was mutably borrowed }; drop(x); } @@ -118,8 +106,7 @@ fn main() { unsafe { let mut u = Box::new(U { b: 0 }); let x = &mut u.a; - u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed - //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed + u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed drop(x); } // Constant index @@ -128,26 +115,22 @@ fn main() { let x = &mut v; match v { &[x, _, .., _, _] => println!("{}", x), - //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed - //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed + //~^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } match v { &[_, x, .., _, _] => println!("{}", x), - //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed - //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed + //~^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } match v { &[_, _, .., x, _] => println!("{}", x), - //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed - //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed + //~^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } match v { &[_, _, .., _, x] => println!("{}", x), - //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed - //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed + //~^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } drop(x); @@ -158,26 +141,22 @@ fn main() { let x = &mut v; match v { &[x..] => println!("{:?}", x), - //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed - //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed + //~^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } match v { &[_, x..] => println!("{:?}", x), - //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed - //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed + //~^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } match v { &[x.., _] => println!("{:?}", x), - //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed - //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed + //~^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } match v { &[_, x.., _] => println!("{:?}", x), - //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed - //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed + //~^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } drop(x); @@ -190,13 +169,11 @@ fn main() { let x = &mut e; match e { E::A(ref ax) => - //[ast]~^ ERROR cannot borrow `e.0` as immutable because `e` is also borrowed as mutable - //[mir]~^^ ERROR cannot borrow `e.0` as immutable because it is also borrowed as mutable - //[mir]~| ERROR cannot use `e` because it was mutably borrowed + //~^ ERROR cannot borrow `e.0` as immutable because it is also borrowed as mutable + //~| ERROR cannot use `e` because it was mutably borrowed println!("e.ax: {:?}", ax), E::B { x: ref bx } => - //[ast]~^ ERROR cannot borrow `e.x` as immutable because `e` is also borrowed as mutable - //[mir]~^^ ERROR cannot borrow `e.x` as immutable because it is also borrowed as mutable + //~^ ERROR cannot borrow `e.x` as immutable because it is also borrowed as mutable println!("e.bx: {:?}", bx), } drop(x); @@ -209,15 +186,13 @@ fn main() { let x = &mut s; match s { S { y: (ref y0, _), .. } => - //[ast]~^ ERROR cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable - //[mir]~^^ ERROR cannot borrow `s.y.0` as immutable because it is also borrowed as mutable + //~^ ERROR cannot borrow `s.y.0` as immutable because it is also borrowed as mutable println!("y0: {:?}", y0), _ => panic!("other case"), } match s { S { x: F { y: ref x0, .. }, .. } => - //[ast]~^ ERROR cannot borrow `s.x.y` as immutable because `s` is also borrowed as mutable - //[mir]~^^ ERROR cannot borrow `s.x.y` as immutable because it is also borrowed as mutable + //~^ ERROR cannot borrow `s.x.y` as immutable because it is also borrowed as mutable println!("x0: {:?}", x0), _ => panic!("other case"), } @@ -233,8 +208,10 @@ fn main() { fn bump<'a>(mut block: &mut Block<'a>) { let x = &mut block; let p: &'a u8 = &*block.current; - //[mir]~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable - // No errors in AST because of issue rust#38899 + //~^ WARNING cannot borrow `*block.current` as immutable because it is also borrowed as mutable + //~| this error has been downgraded + //~| this warning will become a hard error in the future + // Warning because of issue rust#38899 drop(x); } } @@ -248,8 +225,10 @@ fn main() { unsafe fn bump2(mut block: *mut Block2) { let x = &mut block; let p : *const u8 = &*(*block).current; - //[mir]~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable - // No errors in AST because of issue rust#38899 + //~^ WARNING cannot borrow `*block.current` as immutable because it is also borrowed as mutable + //~| this error has been downgraded + //~| this warning will become a hard error in the future + // Warning because of issue rust#38899 drop(x); } } @@ -259,9 +238,8 @@ fn main() { let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}]; let x = &mut v; v[0].y; - //[ast]~^ ERROR cannot use `v[..].y` because it was mutably borrowed - //[mir]~^^ ERROR cannot use `v[_].y` because it was mutably borrowed - //[mir]~| ERROR cannot use `*v` because it was mutably borrowed + //~^ ERROR cannot use `v[_].y` because it was mutably borrowed + //~| ERROR cannot use `*v` because it was mutably borrowed drop(x); } // Field of constant index @@ -271,8 +249,7 @@ fn main() { let x = &mut v; match v { &[_, F {x: ref xf, ..}] => println!("{}", xf), - //[mir]~^ ERROR cannot borrow `v[..].x` as immutable because it is also borrowed as mutable - // No errors in AST + //~^ ERROR cannot borrow `v[..].x` as immutable because it is also borrowed as mutable _ => panic!("other case") } drop(x); @@ -282,8 +259,7 @@ fn main() { let mut x = 0; || { let y = &mut x; - &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time - //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time + &mut x; //~ ERROR cannot borrow `x` as mutable more than once at a time *y = 1; }; } @@ -291,10 +267,9 @@ fn main() { { let mut x = 0; || { - || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body + || { //~ ERROR captured variable cannot escape `FnMut` closure body let y = &mut x; - &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time - //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time + &mut x; //~ ERROR cannot borrow `x` as mutable more than once at a time *y = 1; drop(y); } @@ -304,8 +279,7 @@ fn main() { fn foo(x: Vec) { let c = || { drop(x); - drop(x); //[ast]~ ERROR use of moved value: `x` - //[mir]~^ ERROR use of moved value: `x` + drop(x); //~ ERROR use of moved value: `x` }; c(); } diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr new file mode 100644 index 0000000000000..14b9b50f0c32a --- /dev/null +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr @@ -0,0 +1,374 @@ +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-describe-lvalue.rs:262:13 + | +LL | let y = &mut x; + | ------ first mutable borrow occurs here +LL | &mut x; + | ^^^^^^ second mutable borrow occurs here +LL | *y = 1; + | ------ first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-describe-lvalue.rs:272:20 + | +LL | let y = &mut x; + | ------ first mutable borrow occurs here +LL | &mut x; + | ^^^^^^ second mutable borrow occurs here +LL | *y = 1; + | ------ first borrow later used here + +error: captured variable cannot escape `FnMut` closure body + --> $DIR/borrowck-describe-lvalue.rs:270:16 + | +LL | || { + | - inferred to be a `FnMut` closure +LL | / || { +LL | | let y = &mut x; +LL | | &mut x; +LL | | *y = 1; +LL | | drop(y); +LL | | } + | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + +error[E0503]: cannot use `f.x` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:41:9 + | +LL | let x = f.x(); + | - borrow of `f` occurs here +LL | f.x; + | ^^^ use of borrowed `f` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `g.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:48:9 + | +LL | let x = g.x(); + | - borrow of `g` occurs here +LL | g.0; + | ^^^ use of borrowed `g` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `h.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:55:9 + | +LL | let x = &mut h.0; + | -------- borrow of `h.0` occurs here +LL | h.0; + | ^^^ use of borrowed `h.0` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `e.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:63:20 + | +LL | let x = e.x(); + | - borrow of `e` occurs here +LL | match e { +LL | Baz::X(value) => value + | ^^^^^ use of borrowed `e` +LL | }; +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `u.a` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:71:9 + | +LL | let x = &mut u.a; + | -------- borrow of `u.a` occurs here +LL | u.a; + | ^^^ use of borrowed `u.a` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `f.x` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:78:9 + | +LL | let x = f.x(); + | - borrow of `*f` occurs here +LL | f.x; + | ^^^ use of borrowed `*f` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `g.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:85:9 + | +LL | let x = g.x(); + | - borrow of `*g` occurs here +LL | g.0; + | ^^^ use of borrowed `*g` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `h.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:92:9 + | +LL | let x = &mut h.0; + | -------- borrow of `h.0` occurs here +LL | h.0; + | ^^^ use of borrowed `h.0` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `e.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:100:20 + | +LL | let x = e.x(); + | - borrow of `*e` occurs here +LL | match *e { +LL | Baz::X(value) => value + | ^^^^^ use of borrowed `*e` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `u.a` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:109:9 + | +LL | let x = &mut u.a; + | -------- borrow of `u.a` occurs here +LL | u.a; + | ^^^ use of borrowed `u.a` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:117:15 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +LL | match v { +LL | &[x, _, .., _, _] => println!("{}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:122:18 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, x, .., _, _] => println!("{}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:127:25 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, _, .., x, _] => println!("{}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:132:28 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, _, .., _, x] => println!("{}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:143:15 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +LL | match v { +LL | &[x..] => println!("{:?}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:148:18 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, x..] => println!("{:?}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:153:15 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[x.., _] => println!("{:?}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:158:18 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, x.., _] => println!("{:?}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `e` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:171:13 + | +LL | let x = &mut e; + | ------ borrow of `e` occurs here +LL | match e { +LL | E::A(ref ax) => + | ^^^^^^^^^^^^ use of borrowed `e` +... +LL | drop(x); + | - borrow later used here + +error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:171:18 + | +LL | let x = &mut e; + | ------ mutable borrow occurs here +LL | match e { +LL | E::A(ref ax) => + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0502]: cannot borrow `e.x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:175:23 + | +LL | let x = &mut e; + | ------ mutable borrow occurs here +... +LL | E::B { x: ref bx } => + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:188:22 + | +LL | let x = &mut s; + | ------ mutable borrow occurs here +LL | match s { +LL | S { y: (ref y0, _), .. } => + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:194:28 + | +LL | let x = &mut s; + | ------ mutable borrow occurs here +... +LL | S { x: F { y: ref x0, .. }, .. } => + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0503]: cannot use `*v` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:240:9 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +LL | v[0].y; + | ^^^^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[_].y` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:240:9 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +LL | v[0].y; + | ^^^^^^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:251:24 + | +LL | let x = &mut v; + | ------ mutable borrow occurs here +LL | match v { +LL | &[_, F {x: ref xf, ..}] => println!("{}", xf), + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:210:29 + | +LL | let x = &mut block; + | ---------- mutable borrow occurs here +LL | let p: &'a u8 = &*block.current; + | ^^^^^^^^^^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + +warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:227:33 + | +LL | let x = &mut block; + | ---------- mutable borrow occurs here +LL | let p : *const u8 = &*(*block).current; + | ^^^^^^^^^^^^^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + +error[E0382]: use of moved value: `x` + --> $DIR/borrowck-describe-lvalue.rs:282:22 + | +LL | drop(x); + | - value moved here +LL | drop(x); + | ^ value used here after move + | + = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + +error: aborting due to 30 previous errors + +Some errors have detailed explanations: E0382, E0499, E0502, E0503. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr index 07b597f480feb..a2b42fa495e0e 100644 --- a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr +++ b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr @@ -7,7 +7,7 @@ LL | match Some(42) { LL | Some(_) if { drop(my_str); false } => {} | ------ value moved here LL | Some(_) => {} -LL | None => { foo(my_str); } //~ ERROR [E0382] +LL | None => { foo(my_str); } | ^^^^^^ value used here after move error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-escaping-closure-error-1.nll.stderr b/src/test/ui/borrowck/borrowck-escaping-closure-error-1.nll.stderr deleted file mode 100644 index 3195120cba281..0000000000000 --- a/src/test/ui/borrowck/borrowck-escaping-closure-error-1.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0373]: closure may outlive the current function, but it borrows `books`, which is owned by the current function - --> $DIR/borrowck-escaping-closure-error-1.rs:13:11 - | -LL | spawn(|| books.push(4)); - | ^^ ----- `books` is borrowed here - | | - | may outlive borrowed value `books` - | -note: function requires argument type to outlive `'static` - --> $DIR/borrowck-escaping-closure-error-1.rs:13:5 - | -LL | spawn(|| books.push(4)); - | ^^^^^^^^^^^^^^^^^^^^^^^ -help: to force the closure to take ownership of `books` (and any other referenced variables), use the `move` keyword - | -LL | spawn(move || books.push(4)); - | ^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/borrowck/borrowck-escaping-closure-error-1.stderr b/src/test/ui/borrowck/borrowck-escaping-closure-error-1.stderr index 16ba61d9972c4..3195120cba281 100644 --- a/src/test/ui/borrowck/borrowck-escaping-closure-error-1.stderr +++ b/src/test/ui/borrowck/borrowck-escaping-closure-error-1.stderr @@ -5,6 +5,12 @@ LL | spawn(|| books.push(4)); | ^^ ----- `books` is borrowed here | | | may outlive borrowed value `books` + | +note: function requires argument type to outlive `'static` + --> $DIR/borrowck-escaping-closure-error-1.rs:13:5 + | +LL | spawn(|| books.push(4)); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: to force the closure to take ownership of `books` (and any other referenced variables), use the `move` keyword | LL | spawn(move || books.push(4)); diff --git a/src/test/ui/borrowck/borrowck-escaping-closure-error-2.nll.stderr b/src/test/ui/borrowck/borrowck-escaping-closure-error-2.nll.stderr deleted file mode 100644 index 3227aa9bb6829..0000000000000 --- a/src/test/ui/borrowck/borrowck-escaping-closure-error-2.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0373]: closure may outlive the current function, but it borrows `books`, which is owned by the current function - --> $DIR/borrowck-escaping-closure-error-2.rs:11:14 - | -LL | Box::new(|| books.push(4)) - | ^^ ----- `books` is borrowed here - | | - | may outlive borrowed value `books` - | -note: closure is returned here - --> $DIR/borrowck-escaping-closure-error-2.rs:11:5 - | -LL | Box::new(|| books.push(4)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: to force the closure to take ownership of `books` (and any other referenced variables), use the `move` keyword - | -LL | Box::new(move || books.push(4)) - | ^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/borrowck/borrowck-escaping-closure-error-2.rs b/src/test/ui/borrowck/borrowck-escaping-closure-error-2.rs index a44e3031e256f..b50d455637b9a 100644 --- a/src/test/ui/borrowck/borrowck-escaping-closure-error-2.rs +++ b/src/test/ui/borrowck/borrowck-escaping-closure-error-2.rs @@ -6,7 +6,7 @@ // closure may outlive the current function, but it borrows `books`, // which is owned by the current function -fn foo<'a>(x: &'a i32) -> Box { +fn foo<'a>(x: &'a i32) -> Box { let mut books = vec![1,2,3]; Box::new(|| books.push(4)) //~^ ERROR E0373 diff --git a/src/test/ui/borrowck/borrowck-escaping-closure-error-2.stderr b/src/test/ui/borrowck/borrowck-escaping-closure-error-2.stderr index 960f65da5f0b2..3227aa9bb6829 100644 --- a/src/test/ui/borrowck/borrowck-escaping-closure-error-2.stderr +++ b/src/test/ui/borrowck/borrowck-escaping-closure-error-2.stderr @@ -5,6 +5,12 @@ LL | Box::new(|| books.push(4)) | ^^ ----- `books` is borrowed here | | | may outlive borrowed value `books` + | +note: closure is returned here + --> $DIR/borrowck-escaping-closure-error-2.rs:11:5 + | +LL | Box::new(|| books.push(4)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: to force the closure to take ownership of `books` (and any other referenced variables), use the `move` keyword | LL | Box::new(move || books.push(4)) diff --git a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr index 9059ef438d0f5..ebdacee7f65d8 100644 --- a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr +++ b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr @@ -1,8 +1,14 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-feature-nll-overrides-migrate.rs:22:17 +error[E0507]: cannot move out of `foo` in pattern guard + --> $DIR/borrowck-feature-nll-overrides-migrate.rs:22:18 | LL | (|| { let bar = foo; bar.take() })(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | ^^ --- + | | | + | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs due to use in closure + | move out of `foo` occurs here + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.rs b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.rs index 4eefc5859ff54..a6f3905bebd53 100644 --- a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.rs +++ b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.rs @@ -20,8 +20,8 @@ fn main() { ref mut foo if { (|| { let bar = foo; bar.take() })(); - //[zflag]~^ ERROR cannot move out of borrowed content [E0507] - //[edition]~^^ ERROR cannot move out of borrowed content [E0507] + //[zflag]~^ ERROR cannot move out of `foo` in pattern guard [E0507] + //[edition]~^^ ERROR cannot move out of `foo` in pattern guard [E0507] false } => {}, Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."), diff --git a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr index 9059ef438d0f5..ebdacee7f65d8 100644 --- a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr +++ b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr @@ -1,8 +1,14 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-feature-nll-overrides-migrate.rs:22:17 +error[E0507]: cannot move out of `foo` in pattern guard + --> $DIR/borrowck-feature-nll-overrides-migrate.rs:22:18 | LL | (|| { let bar = foo; bar.take() })(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | ^^ --- + | | | + | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs due to use in closure + | move out of `foo` occurs here + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity.nll.stderr b/src/test/ui/borrowck/borrowck-field-sensitivity.nll.stderr deleted file mode 100644 index 25a9a11204430..0000000000000 --- a/src/test/ui/borrowck/borrowck-field-sensitivity.nll.stderr +++ /dev/null @@ -1,132 +0,0 @@ -error[E0382]: use of moved value: `x.b` - --> $DIR/borrowck-field-sensitivity.rs:8:10 - | -LL | drop(x.b); - | --- value moved here -LL | drop(*x.b); //~ ERROR use of moved value: `*x.b` - | ^^^^ value used here after move - | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `x.b` - --> $DIR/borrowck-field-sensitivity.rs:14:10 - | -LL | let y = A { a: 3, .. x }; - | ---------------- value moved here -LL | drop(*x.b); //~ ERROR use of moved value: `*x.b` - | ^^^^ value used here after move - | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: borrow of moved value: `x.b` - --> $DIR/borrowck-field-sensitivity.rs:20:13 - | -LL | drop(x.b); - | --- value moved here -LL | let p = &x.b; //~ ERROR use of moved value: `x.b` - | ^^^^ value borrowed here after move - | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: borrow of moved value: `x.b` - --> $DIR/borrowck-field-sensitivity.rs:27:13 - | -LL | let _y = A { a: 3, .. x }; - | ---------------- value moved here -LL | let p = &x.b; //~ ERROR use of moved value: `x.b` - | ^^^^ value borrowed here after move - | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0505]: cannot move out of `x.b` because it is borrowed - --> $DIR/borrowck-field-sensitivity.rs:34:10 - | -LL | let p = &x.b; - | ---- borrow of `x.b` occurs here -LL | drop(x.b); //~ ERROR cannot move out of `x.b` because it is borrowed - | ^^^ move out of `x.b` occurs here -LL | drop(**p); - | --- borrow later used here - -error[E0505]: cannot move out of `x.b` because it is borrowed - --> $DIR/borrowck-field-sensitivity.rs:41:14 - | -LL | let p = &x.b; - | ---- borrow of `x.b` occurs here -LL | let _y = A { a: 3, .. x }; //~ ERROR cannot move out of `x.b` because it is borrowed - | ^^^^^^^^^^^^^^^^ move out of `x.b` occurs here -LL | drop(**p); - | --- borrow later used here - -error[E0499]: cannot borrow `x.a` as mutable more than once at a time - --> $DIR/borrowck-field-sensitivity.rs:48:13 - | -LL | let p = &mut x.a; - | -------- first mutable borrow occurs here -LL | let q = &mut x.a; //~ ERROR cannot borrow `x.a` as mutable more than once at a time - | ^^^^^^^^ second mutable borrow occurs here -LL | drop(*p); - | -- first borrow later used here - -error[E0382]: use of moved value: `x.b` - --> $DIR/borrowck-field-sensitivity.rs:56:10 - | -LL | drop(x.b); - | --- value moved here -LL | drop(x.b); //~ ERROR use of moved value: `x.b` - | ^^^ value used here after move - | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `x.b` - --> $DIR/borrowck-field-sensitivity.rs:62:10 - | -LL | let _y = A { a: 3, .. x }; - | ---------------- value moved here -LL | drop(x.b); //~ ERROR use of moved value: `x.b` - | ^^^ value used here after move - | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `x.b` - --> $DIR/borrowck-field-sensitivity.rs:68:14 - | -LL | drop(x.b); - | --- value moved here -LL | let _z = A { a: 3, .. x }; //~ ERROR use of moved value: `x.b` - | ^^^^^^^^^^^^^^^^ value used here after move - | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `x.b` - --> $DIR/borrowck-field-sensitivity.rs:74:14 - | -LL | let _y = A { a: 3, .. x }; - | ---------------- value moved here -LL | let _z = A { a: 4, .. x }; //~ ERROR use of moved value: `x.b` - | ^^^^^^^^^^^^^^^^ value used here after move - | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0381]: assign to part of possibly uninitialized variable: `x` - --> $DIR/borrowck-field-sensitivity.rs:81:5 - | -LL | x.a = 1; - | ^^^^^^^ use of possibly uninitialized `x` - -error[E0381]: assign to part of possibly uninitialized variable: `x` - --> $DIR/borrowck-field-sensitivity.rs:87:5 - | -LL | x.a = 1; - | ^^^^^^^ use of possibly uninitialized `x` - -error[E0381]: assign to part of possibly uninitialized variable: `x` - --> $DIR/borrowck-field-sensitivity.rs:94:5 - | -LL | x.b = box 1; - | ^^^ use of possibly uninitialized `x` - -error: aborting due to 14 previous errors - -Some errors occurred: E0381, E0382, E0499, E0505. -For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity.rs b/src/test/ui/borrowck/borrowck-field-sensitivity.rs index 1e9e6d68a518a..88f74d1ed3300 100644 --- a/src/test/ui/borrowck/borrowck-field-sensitivity.rs +++ b/src/test/ui/borrowck/borrowck-field-sensitivity.rs @@ -5,26 +5,26 @@ struct A { a: isize, b: Box } fn deref_after_move() { let x = A { a: 1, b: box 2 }; drop(x.b); - drop(*x.b); //~ ERROR use of moved value: `*x.b` + drop(*x.b); //~ ERROR use of moved value: `x.b` } fn deref_after_fu_move() { let x = A { a: 1, b: box 2 }; let y = A { a: 3, .. x }; - drop(*x.b); //~ ERROR use of moved value: `*x.b` + drop(*x.b); //~ ERROR use of moved value: `x.b` } fn borrow_after_move() { let x = A { a: 1, b: box 2 }; drop(x.b); - let p = &x.b; //~ ERROR use of moved value: `x.b` + let p = &x.b; //~ ERROR borrow of moved value: `x.b` drop(**p); } fn borrow_after_fu_move() { let x = A { a: 1, b: box 2 }; let _y = A { a: 3, .. x }; - let p = &x.b; //~ ERROR use of moved value: `x.b` + let p = &x.b; //~ ERROR borrow of moved value: `x.b` drop(**p); } @@ -78,21 +78,21 @@ fn fu_move_after_fu_move() { fn copy_after_field_assign_after_uninit() { let mut x: A; - x.a = 1; - drop(x.a); //~ ERROR use of possibly uninitialized variable: `x.a` + x.a = 1; //~ ERROR assign to part of possibly uninitialized variable: `x` + drop(x.a); } fn borrow_after_field_assign_after_uninit() { let mut x: A; - x.a = 1; - let p = &x.a; //~ ERROR use of possibly uninitialized variable: `x.a` + x.a = 1; //~ ERROR assign to part of possibly uninitialized variable: `x` + let p = &x.a; drop(*p); } fn move_after_field_assign_after_uninit() { let mut x: A; - x.b = box 1; - drop(x.b); //~ ERROR use of possibly uninitialized variable: `x.b` + x.b = box 1; //~ ERROR assign to part of possibly uninitialized variable: `x` + drop(x.b); } fn main() { diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr index bfab5cbe536dd..89523235481ad 100644 --- a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr +++ b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr @@ -1,40 +1,40 @@ -error[E0382]: use of moved value: `*x.b` +error[E0382]: use of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:8:10 | LL | drop(x.b); | --- value moved here -LL | drop(*x.b); //~ ERROR use of moved value: `*x.b` +LL | drop(*x.b); | ^^^^ value used here after move | = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `*x.b` +error[E0382]: use of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:14:10 | LL | let y = A { a: 3, .. x }; - | - value moved here -LL | drop(*x.b); //~ ERROR use of moved value: `*x.b` + | ---------------- value moved here +LL | drop(*x.b); | ^^^^ value used here after move | = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `x.b` - --> $DIR/borrowck-field-sensitivity.rs:20:14 +error[E0382]: borrow of moved value: `x.b` + --> $DIR/borrowck-field-sensitivity.rs:20:13 | LL | drop(x.b); | --- value moved here -LL | let p = &x.b; //~ ERROR use of moved value: `x.b` - | ^^^ value used here after move +LL | let p = &x.b; + | ^^^^ value borrowed here after move | = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `x.b` - --> $DIR/borrowck-field-sensitivity.rs:27:14 +error[E0382]: borrow of moved value: `x.b` + --> $DIR/borrowck-field-sensitivity.rs:27:13 | LL | let _y = A { a: 3, .. x }; - | - value moved here -LL | let p = &x.b; //~ ERROR use of moved value: `x.b` - | ^^^ value used here after move + | ---------------- value moved here +LL | let p = &x.b; + | ^^^^ value borrowed here after move | = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait @@ -42,35 +42,38 @@ error[E0505]: cannot move out of `x.b` because it is borrowed --> $DIR/borrowck-field-sensitivity.rs:34:10 | LL | let p = &x.b; - | --- borrow of `x.b` occurs here -LL | drop(x.b); //~ ERROR cannot move out of `x.b` because it is borrowed + | ---- borrow of `x.b` occurs here +LL | drop(x.b); | ^^^ move out of `x.b` occurs here +LL | drop(**p); + | --- borrow later used here error[E0505]: cannot move out of `x.b` because it is borrowed - --> $DIR/borrowck-field-sensitivity.rs:41:27 + --> $DIR/borrowck-field-sensitivity.rs:41:14 | LL | let p = &x.b; - | --- borrow of `x.b` occurs here -LL | let _y = A { a: 3, .. x }; //~ ERROR cannot move out of `x.b` because it is borrowed - | ^ move out of `x.b` occurs here + | ---- borrow of `x.b` occurs here +LL | let _y = A { a: 3, .. x }; + | ^^^^^^^^^^^^^^^^ move out of `x.b` occurs here +LL | drop(**p); + | --- borrow later used here error[E0499]: cannot borrow `x.a` as mutable more than once at a time - --> $DIR/borrowck-field-sensitivity.rs:48:18 + --> $DIR/borrowck-field-sensitivity.rs:48:13 | LL | let p = &mut x.a; - | --- first mutable borrow occurs here -LL | let q = &mut x.a; //~ ERROR cannot borrow `x.a` as mutable more than once at a time - | ^^^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here + | -------- first mutable borrow occurs here +LL | let q = &mut x.a; + | ^^^^^^^^ second mutable borrow occurs here +LL | drop(*p); + | -- first borrow later used here error[E0382]: use of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:56:10 | LL | drop(x.b); | --- value moved here -LL | drop(x.b); //~ ERROR use of moved value: `x.b` +LL | drop(x.b); | ^^^ value used here after move | = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait @@ -79,51 +82,51 @@ error[E0382]: use of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:62:10 | LL | let _y = A { a: 3, .. x }; - | - value moved here -LL | drop(x.b); //~ ERROR use of moved value: `x.b` + | ---------------- value moved here +LL | drop(x.b); | ^^^ value used here after move | = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x.b` - --> $DIR/borrowck-field-sensitivity.rs:68:27 + --> $DIR/borrowck-field-sensitivity.rs:68:14 | LL | drop(x.b); | --- value moved here -LL | let _z = A { a: 3, .. x }; //~ ERROR use of moved value: `x.b` - | ^ value used here after move +LL | let _z = A { a: 3, .. x }; + | ^^^^^^^^^^^^^^^^ value used here after move | = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x.b` - --> $DIR/borrowck-field-sensitivity.rs:74:27 + --> $DIR/borrowck-field-sensitivity.rs:74:14 | LL | let _y = A { a: 3, .. x }; - | - value moved here -LL | let _z = A { a: 4, .. x }; //~ ERROR use of moved value: `x.b` - | ^ value used here after move + | ---------------- value moved here +LL | let _z = A { a: 4, .. x }; + | ^^^^^^^^^^^^^^^^ value used here after move | = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait -error[E0381]: use of possibly uninitialized variable: `x.a` - --> $DIR/borrowck-field-sensitivity.rs:82:10 +error[E0381]: assign to part of possibly uninitialized variable: `x` + --> $DIR/borrowck-field-sensitivity.rs:81:5 | -LL | drop(x.a); //~ ERROR use of possibly uninitialized variable: `x.a` - | ^^^ use of possibly uninitialized `x.a` +LL | x.a = 1; + | ^^^^^^^ use of possibly uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x.a` - --> $DIR/borrowck-field-sensitivity.rs:88:14 +error[E0381]: assign to part of possibly uninitialized variable: `x` + --> $DIR/borrowck-field-sensitivity.rs:87:5 | -LL | let p = &x.a; //~ ERROR use of possibly uninitialized variable: `x.a` - | ^^^ use of possibly uninitialized `x.a` +LL | x.a = 1; + | ^^^^^^^ use of possibly uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x.b` - --> $DIR/borrowck-field-sensitivity.rs:95:10 +error[E0381]: assign to part of possibly uninitialized variable: `x` + --> $DIR/borrowck-field-sensitivity.rs:94:5 | -LL | drop(x.b); //~ ERROR use of possibly uninitialized variable: `x.b` - | ^^^ use of possibly uninitialized `x.b` +LL | x.b = box 1; + | ^^^ use of possibly uninitialized `x` error: aborting due to 14 previous errors -Some errors occurred: E0381, E0382, E0499, E0505. +Some errors have detailed explanations: E0381, E0382, E0499, E0505. For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-fn-in-const-a.ast.stderr b/src/test/ui/borrowck/borrowck-fn-in-const-a.ast.stderr deleted file mode 100644 index 6a5c5047fb237..0000000000000 --- a/src/test/ui/borrowck/borrowck-fn-in-const-a.ast.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-fn-in-const-a.rs:9:16 - | -LL | return *x //[ast]~ ERROR cannot move out of borrowed content [E0507] - | ^^ cannot move out of borrowed content - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-fn-in-const-a.mir.stderr b/src/test/ui/borrowck/borrowck-fn-in-const-a.mir.stderr deleted file mode 100644 index 6a5c5047fb237..0000000000000 --- a/src/test/ui/borrowck/borrowck-fn-in-const-a.mir.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-fn-in-const-a.rs:9:16 - | -LL | return *x //[ast]~ ERROR cannot move out of borrowed content [E0507] - | ^^ cannot move out of borrowed content - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-fn-in-const-a.rs b/src/test/ui/borrowck/borrowck-fn-in-const-a.rs index 17663a30ca76d..d4ceae2963b34 100644 --- a/src/test/ui/borrowck/borrowck-fn-in-const-a.rs +++ b/src/test/ui/borrowck/borrowck-fn-in-const-a.rs @@ -1,13 +1,9 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - // Check that we check fns appearing in constant declarations. // Issue #22382. const MOVE: fn(&String) -> String = { fn broken(x: &String) -> String { - return *x //[ast]~ ERROR cannot move out of borrowed content [E0507] - //[mir]~^ ERROR [E0507] + return *x //~ ERROR cannot move } broken }; diff --git a/src/test/ui/borrowck/borrowck-fn-in-const-a.stderr b/src/test/ui/borrowck/borrowck-fn-in-const-a.stderr new file mode 100644 index 0000000000000..4c9cfa60ad463 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-fn-in-const-a.stderr @@ -0,0 +1,9 @@ +error[E0507]: cannot move out of `*x` which is behind a shared reference + --> $DIR/borrowck-fn-in-const-a.rs:6:16 + | +LL | return *x + | ^^ move occurs because `*x` has type `std::string::String`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-fn-in-const-c.nll.stderr b/src/test/ui/borrowck/borrowck-fn-in-const-c.nll.stderr deleted file mode 100644 index 7d8618e16d974..0000000000000 --- a/src/test/ui/borrowck/borrowck-fn-in-const-c.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0713]: borrow may still be in use when destructor runs - --> $DIR/borrowck-fn-in-const-c.rs:17:16 - | -LL | return &local.inner; //~ ERROR does not live long enough - | ^^^^^^^^^^^^ returning this value requires that `local.inner` is borrowed for `'static` -LL | } - | - here, drop of `local` needs exclusive access to `local.inner`, because the type `DropString` implements the `Drop` trait - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0713`. diff --git a/src/test/ui/borrowck/borrowck-fn-in-const-c.rs b/src/test/ui/borrowck/borrowck-fn-in-const-c.rs index d0a2e5b037df4..c638cd08bc9ae 100644 --- a/src/test/ui/borrowck/borrowck-fn-in-const-c.rs +++ b/src/test/ui/borrowck/borrowck-fn-in-const-c.rs @@ -14,7 +14,7 @@ impl Drop for DropString { const LOCAL_REF: fn() -> &'static str = { fn broken() -> &'static str { let local = DropString { inner: format!("Some local string") }; - return &local.inner; //~ ERROR does not live long enough + return &local.inner; //~ borrow may still be in use when destructor runs } broken }; diff --git a/src/test/ui/borrowck/borrowck-fn-in-const-c.stderr b/src/test/ui/borrowck/borrowck-fn-in-const-c.stderr index f6e7e99393c8c..d48866dce0423 100644 --- a/src/test/ui/borrowck/borrowck-fn-in-const-c.stderr +++ b/src/test/ui/borrowck/borrowck-fn-in-const-c.stderr @@ -1,13 +1,11 @@ -error[E0597]: `local.inner` does not live long enough - --> $DIR/borrowck-fn-in-const-c.rs:17:17 +error[E0713]: borrow may still be in use when destructor runs + --> $DIR/borrowck-fn-in-const-c.rs:17:16 | -LL | return &local.inner; //~ ERROR does not live long enough - | ^^^^^^^^^^^ borrowed value does not live long enough +LL | return &local.inner; + | ^^^^^^^^^^^^ returning this value requires that `local.inner` is borrowed for `'static` LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - here, drop of `local` needs exclusive access to `local.inner`, because the type `DropString` implements the `Drop` trait error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0713`. diff --git a/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.nll.stderr b/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.nll.stderr deleted file mode 100644 index 8ba6a07b3d2d4..0000000000000 --- a/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.nll.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:12:15 - | -LL | for &a in x.iter() { //~ ERROR cannot move out - | -- ^^^^^^^^ cannot move out of borrowed content - | || - | |data moved here - | help: consider removing the `&`: `a` - | -note: move occurs because `a` has type `&mut i32`, which does not implement the `Copy` trait - --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:12:10 - | -LL | for &a in x.iter() { //~ ERROR cannot move out - | ^ - -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:18:15 - | -LL | for &a in &f.a { //~ ERROR cannot move out - | -- ^^^^ cannot move out of borrowed content - | || - | |data moved here - | help: consider removing the `&`: `a` - | -note: move occurs because `a` has type `std::boxed::Box`, which does not implement the `Copy` trait - --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:18:10 - | -LL | for &a in &f.a { //~ ERROR cannot move out - | ^ - -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:22:15 - | -LL | for &a in x.iter() { //~ ERROR cannot move out - | -- ^^^^^^^^ cannot move out of borrowed content - | || - | |data moved here - | help: consider removing the `&`: `a` - | -note: move occurs because `a` has type `std::boxed::Box`, which does not implement the `Copy` trait - --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:22:10 - | -LL | for &a in x.iter() { //~ ERROR cannot move out - | ^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr b/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr index 1a7e2cb69632c..38e41f315fc52 100644 --- a/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr +++ b/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr @@ -1,29 +1,32 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:12:9 +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:12:15 | -LL | for &a in x.iter() { //~ ERROR cannot move out - | ^- +LL | for &a in x.iter() { + | -- ^^^^^^^^ | || - | |hint: to prevent move, use `ref a` or `ref mut a` - | cannot move out of borrowed content + | |data moved here + | |move occurs because `a` has type `&mut i32`, which does not implement the `Copy` trait + | help: consider removing the `&`: `a` -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:18:9 +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:18:15 | -LL | for &a in &f.a { //~ ERROR cannot move out - | ^- +LL | for &a in &f.a { + | -- ^^^^ | || - | |hint: to prevent move, use `ref a` or `ref mut a` - | cannot move out of borrowed content + | |data moved here + | |move occurs because `a` has type `std::boxed::Box`, which does not implement the `Copy` trait + | help: consider removing the `&`: `a` -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:22:9 +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:22:15 | -LL | for &a in x.iter() { //~ ERROR cannot move out - | ^- +LL | for &a in x.iter() { + | -- ^^^^^^^^ | || - | |hint: to prevent move, use `ref a` or `ref mut a` - | cannot move out of borrowed content + | |data moved here + | |move occurs because `a` has type `std::boxed::Box`, which does not implement the `Copy` trait + | help: consider removing the `&`: `a` error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr b/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr index 32ca24ba6ec43..3468f29fb1a23 100644 --- a/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr +++ b/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr @@ -7,8 +7,8 @@ LL | for &x in &vector { | immutable borrow occurs here | immutable borrow later used here LL | let cap = vector.capacity(); -LL | vector.extend(repeat(0)); //~ ERROR cannot borrow - | ^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | vector.extend(repeat(0)); + | ^^^^^^ mutable borrow occurs here error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable --> $DIR/borrowck-for-loop-head-linkage.rs:8:9 @@ -19,7 +19,7 @@ LL | for &x in &vector { | immutable borrow occurs here | immutable borrow later used here ... -LL | vector[1] = 5; //~ ERROR cannot borrow +LL | vector[1] = 5; | ^^^^^^ mutable borrow occurs here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-for-loop-head-linkage.stderr b/src/test/ui/borrowck/borrowck-for-loop-head-linkage.stderr index 85008948a1c0f..f47dce453696e 100644 --- a/src/test/ui/borrowck/borrowck-for-loop-head-linkage.stderr +++ b/src/test/ui/borrowck/borrowck-for-loop-head-linkage.stderr @@ -2,24 +2,24 @@ error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as i --> $DIR/borrowck-for-loop-head-linkage.rs:7:9 | LL | for &x in &vector { - | ------ - | | | - | | immutable borrow ends here - | immutable borrow occurs here + | ------- + | | + | immutable borrow occurs here + | immutable borrow later used here LL | let cap = vector.capacity(); -LL | vector.extend(repeat(0)); //~ ERROR cannot borrow - | ^^^^^^ mutable borrow occurs here +LL | vector.extend(repeat(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable --> $DIR/borrowck-for-loop-head-linkage.rs:8:9 | LL | for &x in &vector { - | ------ - | | | - | | immutable borrow ends here - | immutable borrow occurs here + | ------- + | | + | immutable borrow occurs here + | immutable borrow later used here ... -LL | vector[1] = 5; //~ ERROR cannot borrow +LL | vector[1] = 5; | ^^^^^^ mutable borrow occurs here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-if-no-else.stderr b/src/test/ui/borrowck/borrowck-if-no-else.stderr index f6d199d788bf8..1223e409d4df6 100644 --- a/src/test/ui/borrowck/borrowck-if-no-else.stderr +++ b/src/test/ui/borrowck/borrowck-if-no-else.stderr @@ -1,7 +1,7 @@ error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-if-no-else.rs:5:9 | -LL | foo(x); //~ ERROR use of possibly uninitialized variable: `x` +LL | foo(x); | ^ use of possibly uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-if-with-else.stderr b/src/test/ui/borrowck/borrowck-if-with-else.stderr index e569fbdeca1e7..d11f29b05f565 100644 --- a/src/test/ui/borrowck/borrowck-if-with-else.stderr +++ b/src/test/ui/borrowck/borrowck-if-with-else.stderr @@ -1,7 +1,7 @@ error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-if-with-else.rs:10:9 | -LL | foo(x); //~ ERROR use of possibly uninitialized variable: `x` +LL | foo(x); | ^ use of possibly uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.ast.nll.stderr b/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.ast.nll.stderr deleted file mode 100644 index d3708b5cf2bbb..0000000000000 --- a/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.ast.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0506]: cannot assign to `_a` because it is borrowed - --> $DIR/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs:9:9 - | -LL | let b = &mut _a; - | ------- borrow of `_a` occurs here -... -LL | _a = 4; //[ast]~ ERROR cannot assign to `_a` - | ^^^^^^ assignment to borrowed `_a` occurs here -... -LL | drop(b); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.ast.stderr b/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.ast.stderr deleted file mode 100644 index 618edf57bb26e..0000000000000 --- a/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.ast.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0506]: cannot assign to `_a` because it is borrowed - --> $DIR/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs:9:9 - | -LL | let b = &mut _a; - | -- borrow of `_a` occurs here -... -LL | _a = 4; //[ast]~ ERROR cannot assign to `_a` - | ^^^^^^ assignment to borrowed `_a` occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.mir.stderr b/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.mir.stderr deleted file mode 100644 index d3708b5cf2bbb..0000000000000 --- a/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.mir.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0506]: cannot assign to `_a` because it is borrowed - --> $DIR/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs:9:9 - | -LL | let b = &mut _a; - | ------- borrow of `_a` occurs here -... -LL | _a = 4; //[ast]~ ERROR cannot assign to `_a` - | ^^^^^^ assignment to borrowed `_a` occurs here -... -LL | drop(b); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs b/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs index 334d2e008b956..97107c2e30f00 100644 --- a/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs +++ b/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs @@ -1,13 +1,9 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - fn main() { let mut _a = 3; let b = &mut _a; { let c = &*b; - _a = 4; //[ast]~ ERROR cannot assign to `_a` - //[mir]~^ ERROR cannot assign to `_a` because it is borrowed + _a = 4; //~ ERROR cannot assign to `_a` because it is borrowed drop(c); } drop(b); diff --git a/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr b/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr new file mode 100644 index 0000000000000..a66db05ccc5fc --- /dev/null +++ b/src/test/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr @@ -0,0 +1,15 @@ +error[E0506]: cannot assign to `_a` because it is borrowed + --> $DIR/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs:6:9 + | +LL | let b = &mut _a; + | ------- borrow of `_a` occurs here +... +LL | _a = 4; + | ^^^^^^ assignment to borrowed `_a` occurs here +... +LL | drop(b); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-in-static.nll.stderr b/src/test/ui/borrowck/borrowck-in-static.nll.stderr deleted file mode 100644 index ff094ecf70746..0000000000000 --- a/src/test/ui/borrowck/borrowck-in-static.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/borrowck-in-static.rs:5:17 - | -LL | let x = Box::new(0); - | - captured outer variable -LL | Box::new(|| x) //~ ERROR cannot move out of captured outer variable - | ^ cannot move out of captured variable in an `Fn` closure - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-in-static.rs b/src/test/ui/borrowck/borrowck-in-static.rs index c08f4138bfb39..a45f7b18e07d6 100644 --- a/src/test/ui/borrowck/borrowck-in-static.rs +++ b/src/test/ui/borrowck/borrowck-in-static.rs @@ -1,8 +1,8 @@ // check that borrowck looks inside consts/statics -static FN : &'static (Fn() -> (BoxBox>) + Sync) = &|| { +static FN : &'static (dyn Fn() -> (BoxBox>) + Sync) = &|| { let x = Box::new(0); - Box::new(|| x) //~ ERROR cannot move out of captured outer variable + Box::new(|| x) //~ ERROR cannot move out of `x`, a captured variable in an `Fn` closure }; fn main() { diff --git a/src/test/ui/borrowck/borrowck-in-static.stderr b/src/test/ui/borrowck/borrowck-in-static.stderr index 400f3cd1c3e78..77d6d7c231d19 100644 --- a/src/test/ui/borrowck/borrowck-in-static.stderr +++ b/src/test/ui/borrowck/borrowck-in-static.stderr @@ -1,10 +1,10 @@ -error[E0507]: cannot move out of captured outer variable in an `Fn` closure +error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure --> $DIR/borrowck-in-static.rs:5:17 | LL | let x = Box::new(0); | - captured outer variable -LL | Box::new(|| x) //~ ERROR cannot move out of captured outer variable - | ^ cannot move out of captured outer variable in an `Fn` closure +LL | Box::new(|| x) + | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr index 0195dc60eb3ee..82a602c6359c1 100644 --- a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr +++ b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr @@ -1,7 +1,7 @@ error[E0381]: use of possibly uninitialized variable: `i` --> $DIR/borrowck-init-in-called-fn-expr.rs:4:9 | -LL | i //~ ERROR use of possibly uninitialized variable: `i` +LL | i | ^ use of possibly uninitialized `i` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr b/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr index dfa63f71c6956..899739378524c 100644 --- a/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr +++ b/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr @@ -1,7 +1,7 @@ error[E0381]: use of possibly uninitialized variable: `i` --> $DIR/borrowck-init-in-fn-expr.rs:4:9 | -LL | i //~ ERROR use of possibly uninitialized variable: `i` +LL | i | ^ use of possibly uninitialized `i` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-in-fru.ast.nll.stderr b/src/test/ui/borrowck/borrowck-init-in-fru.ast.nll.stderr deleted file mode 100644 index 35649b1bb2a50..0000000000000 --- a/src/test/ui/borrowck/borrowck-init-in-fru.ast.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `origin` - --> $DIR/borrowck-init-in-fru.rs:12:5 - | -LL | origin = Point { x: 10, ..origin }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly uninitialized `origin.y` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-init-in-fru.ast.stderr b/src/test/ui/borrowck/borrowck-init-in-fru.ast.stderr deleted file mode 100644 index 3ba01098766dc..0000000000000 --- a/src/test/ui/borrowck/borrowck-init-in-fru.ast.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `origin.y` - --> $DIR/borrowck-init-in-fru.rs:12:31 - | -LL | origin = Point { x: 10, ..origin }; - | ^^^^^^ use of possibly uninitialized `origin.y` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-init-in-fru.mir.stderr b/src/test/ui/borrowck/borrowck-init-in-fru.mir.stderr deleted file mode 100644 index 35649b1bb2a50..0000000000000 --- a/src/test/ui/borrowck/borrowck-init-in-fru.mir.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `origin` - --> $DIR/borrowck-init-in-fru.rs:12:5 - | -LL | origin = Point { x: 10, ..origin }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly uninitialized `origin.y` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-init-in-fru.rs b/src/test/ui/borrowck/borrowck-init-in-fru.rs index 9a06c7ab77286..6da3098dc9336 100644 --- a/src/test/ui/borrowck/borrowck-init-in-fru.rs +++ b/src/test/ui/borrowck/borrowck-init-in-fru.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - #[derive(Clone)] struct Point { x: isize, @@ -10,7 +7,6 @@ struct Point { fn main() { let mut origin: Point; origin = Point { x: 10, ..origin }; - //[ast]~^ ERROR use of possibly uninitialized variable: `origin.y` [E0381] - //[mir]~^^ ERROR [E0381] + //~^ ERROR use of possibly uninitialized variable: `origin` [E0381] origin.clone(); } diff --git a/src/test/ui/borrowck/borrowck-init-in-fru.stderr b/src/test/ui/borrowck/borrowck-init-in-fru.stderr new file mode 100644 index 0000000000000..fe55bc2fd95c0 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-init-in-fru.stderr @@ -0,0 +1,9 @@ +error[E0381]: use of possibly uninitialized variable: `origin` + --> $DIR/borrowck-init-in-fru.rs:9:5 + | +LL | origin = Point { x: 10, ..origin }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly uninitialized `origin.y` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-init-op-equal.stderr b/src/test/ui/borrowck/borrowck-init-op-equal.stderr index 414124040aa26..9863ceb14240f 100644 --- a/src/test/ui/borrowck/borrowck-init-op-equal.stderr +++ b/src/test/ui/borrowck/borrowck-init-op-equal.stderr @@ -1,7 +1,7 @@ error[E0381]: use of possibly uninitialized variable: `v` --> $DIR/borrowck-init-op-equal.rs:3:5 | -LL | v += 1; //~ ERROR use of possibly uninitialized variable: `v` +LL | v += 1; | ^^^^^^ use of possibly uninitialized `v` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-plus-equal.stderr b/src/test/ui/borrowck/borrowck-init-plus-equal.stderr index 124a60b8a5021..80c4e0c80483d 100644 --- a/src/test/ui/borrowck/borrowck-init-plus-equal.stderr +++ b/src/test/ui/borrowck/borrowck-init-plus-equal.stderr @@ -1,7 +1,7 @@ error[E0381]: use of possibly uninitialized variable: `v` --> $DIR/borrowck-init-plus-equal.rs:3:9 | -LL | v = v + 1; //~ ERROR use of possibly uninitialized variable: `v` +LL | v = v + 1; | ^ use of possibly uninitialized `v` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-insert-during-each.nll.stderr b/src/test/ui/borrowck/borrowck-insert-during-each.nll.stderr deleted file mode 100644 index b99d5e813c7c2..0000000000000 --- a/src/test/ui/borrowck/borrowck-insert-during-each.nll.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0501]: cannot borrow `*f` as mutable because previous closure requires unique access - --> $DIR/borrowck-insert-during-each.rs:16:3 - | -LL | f.foo( - | ^ --- first borrow later used by call - | ___| - | | -LL | | |a| { //~ ERROR closure requires unique access to `f` - | | --- closure construction occurs here -LL | | f.n.insert(*a); - | | - first borrow occurs due to use of `f` in closure -LL | | }) - | |__________^ second borrow occurs here - -error[E0500]: closure requires unique access to `f` but it is already borrowed - --> $DIR/borrowck-insert-during-each.rs:17:9 - | -LL | f.foo( - | - --- first borrow later used by call - | | - | borrow occurs here -LL | |a| { //~ ERROR closure requires unique access to `f` - | ^^^ closure construction occurs here -LL | f.n.insert(*a); - | - second borrow occurs due to use of `f` in closure - -error: aborting due to 2 previous errors - -Some errors occurred: E0500, E0501. -For more information about an error, try `rustc --explain E0500`. diff --git a/src/test/ui/borrowck/borrowck-insert-during-each.rs b/src/test/ui/borrowck/borrowck-insert-during-each.rs index 025da4d613dbb..df967e6118932 100644 --- a/src/test/ui/borrowck/borrowck-insert-during-each.rs +++ b/src/test/ui/borrowck/borrowck-insert-during-each.rs @@ -13,7 +13,8 @@ impl Foo { } fn bar(f: &mut Foo) { - f.foo( + f.foo( + //~^ ERROR cannot borrow `*f` as mutable |a| { //~ ERROR closure requires unique access to `f` f.n.insert(*a); }) diff --git a/src/test/ui/borrowck/borrowck-insert-during-each.stderr b/src/test/ui/borrowck/borrowck-insert-during-each.stderr index 021b5b27ae702..796390c093b10 100644 --- a/src/test/ui/borrowck/borrowck-insert-during-each.stderr +++ b/src/test/ui/borrowck/borrowck-insert-during-each.stderr @@ -1,15 +1,32 @@ -error[E0500]: closure requires unique access to `f` but `*f` is already borrowed - --> $DIR/borrowck-insert-during-each.rs:17:9 +error[E0501]: cannot borrow `*f` as mutable because previous closure requires unique access + --> $DIR/borrowck-insert-during-each.rs:16:5 | -LL | f.foo( - | - borrow occurs here -LL | |a| { //~ ERROR closure requires unique access to `f` +LL | f.foo( + | ^ --- first borrow later used by call + | _____| + | | +LL | | +LL | | |a| { + | | --- closure construction occurs here +LL | | f.n.insert(*a); + | | - first borrow occurs due to use of `f` in closure +LL | | }) + | |__________^ second borrow occurs here + +error[E0500]: closure requires unique access to `f` but it is already borrowed + --> $DIR/borrowck-insert-during-each.rs:18:9 + | +LL | f.foo( + | - --- first borrow later used by call + | | + | borrow occurs here +LL | +LL | |a| { | ^^^ closure construction occurs here LL | f.n.insert(*a); - | - borrow occurs due to use of `f` in closure -LL | }) - | - borrow ends here + | - second borrow occurs due to use of `f` in closure -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0500`. +Some errors have detailed explanations: E0500, E0501. +For more information about an error, try `rustc --explain E0500`. diff --git a/src/test/ui/borrowck/borrowck-issue-14498.ast.nll.stderr b/src/test/ui/borrowck/borrowck-issue-14498.ast.nll.stderr deleted file mode 100644 index 81610536c52b8..0000000000000 --- a/src/test/ui/borrowck/borrowck-issue-14498.ast.nll.stderr +++ /dev/null @@ -1,108 +0,0 @@ -error[E0594]: cannot assign to `***p` which is behind a `&` reference - --> $DIR/borrowck-issue-14498.rs:19:5 - | -LL | let p = &y; - | -- help: consider changing this to be a mutable reference: `&mut y` -LL | ***p = 2; //[ast]~ ERROR cannot assign to data in a `&` reference - | ^^^^^^^^ `p` is a `&` reference, so the data it refers to cannot be written - -error[E0506]: cannot assign to `**y` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:29:5 - | -LL | let p = &y; - | -- borrow of `**y` occurs here -LL | let q = &***p; -LL | **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - | ^^^^^^^ assignment to borrowed `**y` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:40:5 - | -LL | let p = &y; - | -- borrow of `**y` occurs here -LL | let q = &***p; -LL | **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - | ^^^^^^^ assignment to borrowed `**y` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:51:5 - | -LL | let p = &y; - | -- borrow of `**y` occurs here -LL | let q = &***p; -LL | **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - | ^^^^^^^ assignment to borrowed `**y` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:62:5 - | -LL | let p = &y; - | -- borrow of `**y` occurs here -LL | let q = &***p; -LL | **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - | ^^^^^^^ assignment to borrowed `**y` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y.a` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:73:5 - | -LL | let p = &y.a; - | ---- borrow of `**y.a` occurs here -LL | let q = &***p; -LL | **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y.a` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:84:5 - | -LL | let p = &y.a; - | ---- borrow of `**y.a` occurs here -LL | let q = &***p; -LL | **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y.a` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:95:5 - | -LL | let p = &y.a; - | ---- borrow of `**y.a` occurs here -LL | let q = &***p; -LL | **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y.a` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:106:5 - | -LL | let p = &y.a; - | ---- borrow of `**y.a` occurs here -LL | let q = &***p; -LL | **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed -LL | drop(p); - | - borrow later used here - -error: aborting due to 9 previous errors - -Some errors occurred: E0506, E0594. -For more information about an error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-issue-14498.ast.stderr b/src/test/ui/borrowck/borrowck-issue-14498.ast.stderr deleted file mode 100644 index 59249dadcb0a6..0000000000000 --- a/src/test/ui/borrowck/borrowck-issue-14498.ast.stderr +++ /dev/null @@ -1,82 +0,0 @@ -error[E0389]: cannot assign to data in a `&` reference - --> $DIR/borrowck-issue-14498.rs:19:5 - | -LL | ***p = 2; //[ast]~ ERROR cannot assign to data in a `&` reference - | ^^^^^^^^ assignment into an immutable reference - -error[E0506]: cannot assign to `**y` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:29:5 - | -LL | let p = &y; - | - borrow of `**y` occurs here -LL | let q = &***p; -LL | **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - | ^^^^^^^ assignment to borrowed `**y` occurs here - -error[E0506]: cannot assign to `**y` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:40:5 - | -LL | let p = &y; - | - borrow of `**y` occurs here -LL | let q = &***p; -LL | **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - | ^^^^^^^ assignment to borrowed `**y` occurs here - -error[E0506]: cannot assign to `**y` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:51:5 - | -LL | let p = &y; - | - borrow of `**y` occurs here -LL | let q = &***p; -LL | **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - | ^^^^^^^ assignment to borrowed `**y` occurs here - -error[E0506]: cannot assign to `**y` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:62:5 - | -LL | let p = &y; - | - borrow of `**y` occurs here -LL | let q = &***p; -LL | **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - | ^^^^^^^ assignment to borrowed `**y` occurs here - -error[E0506]: cannot assign to `**y.a` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:73:5 - | -LL | let p = &y.a; - | --- borrow of `**y.a` occurs here -LL | let q = &***p; -LL | **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here - -error[E0506]: cannot assign to `**y.a` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:84:5 - | -LL | let p = &y.a; - | --- borrow of `**y.a` occurs here -LL | let q = &***p; -LL | **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here - -error[E0506]: cannot assign to `**y.a` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:95:5 - | -LL | let p = &y.a; - | --- borrow of `**y.a` occurs here -LL | let q = &***p; -LL | **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here - -error[E0506]: cannot assign to `**y.a` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:106:5 - | -LL | let p = &y.a; - | --- borrow of `**y.a` occurs here -LL | let q = &***p; -LL | **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here - -error: aborting due to 9 previous errors - -Some errors occurred: E0389, E0506. -For more information about an error, try `rustc --explain E0389`. diff --git a/src/test/ui/borrowck/borrowck-issue-14498.mir.stderr b/src/test/ui/borrowck/borrowck-issue-14498.mir.stderr deleted file mode 100644 index 81610536c52b8..0000000000000 --- a/src/test/ui/borrowck/borrowck-issue-14498.mir.stderr +++ /dev/null @@ -1,108 +0,0 @@ -error[E0594]: cannot assign to `***p` which is behind a `&` reference - --> $DIR/borrowck-issue-14498.rs:19:5 - | -LL | let p = &y; - | -- help: consider changing this to be a mutable reference: `&mut y` -LL | ***p = 2; //[ast]~ ERROR cannot assign to data in a `&` reference - | ^^^^^^^^ `p` is a `&` reference, so the data it refers to cannot be written - -error[E0506]: cannot assign to `**y` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:29:5 - | -LL | let p = &y; - | -- borrow of `**y` occurs here -LL | let q = &***p; -LL | **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - | ^^^^^^^ assignment to borrowed `**y` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:40:5 - | -LL | let p = &y; - | -- borrow of `**y` occurs here -LL | let q = &***p; -LL | **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - | ^^^^^^^ assignment to borrowed `**y` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:51:5 - | -LL | let p = &y; - | -- borrow of `**y` occurs here -LL | let q = &***p; -LL | **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - | ^^^^^^^ assignment to borrowed `**y` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:62:5 - | -LL | let p = &y; - | -- borrow of `**y` occurs here -LL | let q = &***p; -LL | **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - | ^^^^^^^ assignment to borrowed `**y` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y.a` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:73:5 - | -LL | let p = &y.a; - | ---- borrow of `**y.a` occurs here -LL | let q = &***p; -LL | **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y.a` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:84:5 - | -LL | let p = &y.a; - | ---- borrow of `**y.a` occurs here -LL | let q = &***p; -LL | **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y.a` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:95:5 - | -LL | let p = &y.a; - | ---- borrow of `**y.a` occurs here -LL | let q = &***p; -LL | **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed -LL | drop(p); - | - borrow later used here - -error[E0506]: cannot assign to `**y.a` because it is borrowed - --> $DIR/borrowck-issue-14498.rs:106:5 - | -LL | let p = &y.a; - | ---- borrow of `**y.a` occurs here -LL | let q = &***p; -LL | **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here -LL | //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed -LL | drop(p); - | - borrow later used here - -error: aborting due to 9 previous errors - -Some errors occurred: E0506, E0594. -For more information about an error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-issue-14498.rs b/src/test/ui/borrowck/borrowck-issue-14498.rs index da62c5a950731..e8c9019264fe7 100644 --- a/src/test/ui/borrowck/borrowck-issue-14498.rs +++ b/src/test/ui/borrowck/borrowck-issue-14498.rs @@ -4,9 +4,6 @@ // Also includes tests of the errors reported when the Box in question // is immutable (#14270). -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - #![feature(box_syntax)] struct A { a: isize } @@ -16,8 +13,7 @@ fn indirect_write_to_imm_box() { let mut x: isize = 1; let y: Box<_> = box &mut x; let p = &y; - ***p = 2; //[ast]~ ERROR cannot assign to data in a `&` reference - //[mir]~^ ERROR cannot assign to `***p` + ***p = 2; //~ ERROR cannot assign to `***p` drop(p); } @@ -26,8 +22,7 @@ fn borrow_in_var_from_var() { let mut y: Box<_> = box &mut x; let p = &y; let q = &***p; - **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - //[mir]~^ ERROR cannot assign to `**y` because it is borrowed + **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed drop(p); drop(q); } @@ -37,8 +32,7 @@ fn borrow_in_var_from_var_via_imm_box() { let y: Box<_> = box &mut x; let p = &y; let q = &***p; - **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - //[mir]~^ ERROR cannot assign to `**y` because it is borrowed + **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed drop(p); drop(q); } @@ -48,8 +42,7 @@ fn borrow_in_var_from_field() { let mut y: Box<_> = box &mut x.a; let p = &y; let q = &***p; - **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - //[mir]~^ ERROR cannot assign to `**y` because it is borrowed + **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed drop(p); drop(q); } @@ -59,8 +52,7 @@ fn borrow_in_var_from_field_via_imm_box() { let y: Box<_> = box &mut x.a; let p = &y; let q = &***p; - **y = 2; //[ast]~ ERROR cannot assign to `**y` because it is borrowed - //[mir]~^ ERROR cannot assign to `**y` because it is borrowed + **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed drop(p); drop(q); } @@ -70,8 +62,7 @@ fn borrow_in_field_from_var() { let mut y = B { a: box &mut x }; let p = &y.a; let q = &***p; - **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed + **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed drop(p); drop(q); } @@ -81,8 +72,7 @@ fn borrow_in_field_from_var_via_imm_box() { let y = B { a: box &mut x }; let p = &y.a; let q = &***p; - **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed + **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed drop(p); drop(q); } @@ -92,8 +82,7 @@ fn borrow_in_field_from_field() { let mut y = B { a: box &mut x.a }; let p = &y.a; let q = &***p; - **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed + **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed drop(p); drop(q); } @@ -103,8 +92,7 @@ fn borrow_in_field_from_field_via_imm_box() { let y = B { a: box &mut x.a }; let p = &y.a; let q = &***p; - **y.a = 2; //[ast]~ ERROR cannot assign to `**y.a` because it is borrowed - //[mir]~^ ERROR cannot assign to `**y.a` because it is borrowed + **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed drop(p); drop(q); } diff --git a/src/test/ui/borrowck/borrowck-issue-14498.stderr b/src/test/ui/borrowck/borrowck-issue-14498.stderr new file mode 100644 index 0000000000000..fec4c27520cf3 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-issue-14498.stderr @@ -0,0 +1,99 @@ +error[E0594]: cannot assign to `***p` which is behind a `&` reference + --> $DIR/borrowck-issue-14498.rs:16:5 + | +LL | let p = &y; + | -- help: consider changing this to be a mutable reference: `&mut y` +LL | ***p = 2; + | ^^^^^^^^ `p` is a `&` reference, so the data it refers to cannot be written + +error[E0506]: cannot assign to `**y` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:25:5 + | +LL | let p = &y; + | -- borrow of `**y` occurs here +LL | let q = &***p; +LL | **y = 2; + | ^^^^^^^ assignment to borrowed `**y` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:35:5 + | +LL | let p = &y; + | -- borrow of `**y` occurs here +LL | let q = &***p; +LL | **y = 2; + | ^^^^^^^ assignment to borrowed `**y` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:45:5 + | +LL | let p = &y; + | -- borrow of `**y` occurs here +LL | let q = &***p; +LL | **y = 2; + | ^^^^^^^ assignment to borrowed `**y` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:55:5 + | +LL | let p = &y; + | -- borrow of `**y` occurs here +LL | let q = &***p; +LL | **y = 2; + | ^^^^^^^ assignment to borrowed `**y` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y.a` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:65:5 + | +LL | let p = &y.a; + | ---- borrow of `**y.a` occurs here +LL | let q = &***p; +LL | **y.a = 2; + | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y.a` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:75:5 + | +LL | let p = &y.a; + | ---- borrow of `**y.a` occurs here +LL | let q = &***p; +LL | **y.a = 2; + | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y.a` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:85:5 + | +LL | let p = &y.a; + | ---- borrow of `**y.a` occurs here +LL | let q = &***p; +LL | **y.a = 2; + | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y.a` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:95:5 + | +LL | let p = &y.a; + | ---- borrow of `**y.a` occurs here +LL | let q = &***p; +LL | **y.a = 2; + | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here +LL | drop(p); + | - borrow later used here + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-issue-2657-1.nll.stderr b/src/test/ui/borrowck/borrowck-issue-2657-1.nll.stderr deleted file mode 100644 index 3da8d8f8c4757..0000000000000 --- a/src/test/ui/borrowck/borrowck-issue-2657-1.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/borrowck-issue-2657-1.rs:9:18 - | -LL | Some(ref _y) => { - | ------ borrow of `x.0` occurs here -LL | let _a = x; //~ ERROR cannot move - | ^ move out of `x` occurs here -LL | _y.use_ref(); - | -- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-issue-2657-1.stderr b/src/test/ui/borrowck/borrowck-issue-2657-1.stderr index 7663822094d86..4ea4eb8f00759 100644 --- a/src/test/ui/borrowck/borrowck-issue-2657-1.stderr +++ b/src/test/ui/borrowck/borrowck-issue-2657-1.stderr @@ -1,10 +1,12 @@ error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/borrowck-issue-2657-1.rs:9:13 + --> $DIR/borrowck-issue-2657-1.rs:9:18 | LL | Some(ref _y) => { | ------ borrow of `x.0` occurs here -LL | let _a = x; //~ ERROR cannot move - | ^^ move out of `x` occurs here +LL | let _a = x; + | ^ move out of `x` occurs here +LL | _y.use_ref(); + | -- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-issue-2657-2.nll.stderr b/src/test/ui/borrowck/borrowck-issue-2657-2.nll.stderr deleted file mode 100644 index 061c458f73e58..0000000000000 --- a/src/test/ui/borrowck/borrowck-issue-2657-2.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-issue-2657-2.rs:7:18 - | -LL | let _b = *y; //~ ERROR cannot move out - | ^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `y` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-issue-2657-2.stderr b/src/test/ui/borrowck/borrowck-issue-2657-2.stderr index 7e718786caa37..5880a1abb818c 100644 --- a/src/test/ui/borrowck/borrowck-issue-2657-2.stderr +++ b/src/test/ui/borrowck/borrowck-issue-2657-2.stderr @@ -1,11 +1,11 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `*y` which is behind a shared reference --> $DIR/borrowck-issue-2657-2.rs:7:18 | -LL | let _b = *y; //~ ERROR cannot move out +LL | let _b = *y; | ^^ | | - | cannot move out of borrowed content - | help: consider using a reference instead: `&*y` + | move occurs because `*y` has type `std::boxed::Box`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*y` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-issue-48962.rs b/src/test/ui/borrowck/borrowck-issue-48962.rs index e7df319a0bb70..86061c8cd6e87 100644 --- a/src/test/ui/borrowck/borrowck-issue-48962.rs +++ b/src/test/ui/borrowck/borrowck-issue-48962.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - struct Node { elem: i32, next: Option>, diff --git a/src/test/ui/borrowck/borrowck-issue-48962.stderr b/src/test/ui/borrowck/borrowck-issue-48962.stderr index de4894d5b526b..ee174f6736e1e 100644 --- a/src/test/ui/borrowck/borrowck-issue-48962.stderr +++ b/src/test/ui/borrowck/borrowck-issue-48962.stderr @@ -1,21 +1,21 @@ error[E0382]: use of moved value: `src` - --> $DIR/borrowck-issue-48962.rs:16:5 + --> $DIR/borrowck-issue-48962.rs:14:5 | LL | let mut src = &mut node; | ------- move occurs because `src` has type `&mut Node`, which does not implement the `Copy` trait LL | {src}; | --- value moved here -LL | src.next = None; //~ ERROR use of moved value: `src` [E0382] +LL | src.next = None; | ^^^^^^^^ value used here after move error[E0382]: use of moved value: `src` - --> $DIR/borrowck-issue-48962.rs:22:5 + --> $DIR/borrowck-issue-48962.rs:20:5 | LL | let mut src = &mut (22, 44); | ------- move occurs because `src` has type `&mut (i32, i32)`, which does not implement the `Copy` trait LL | {src}; | --- value moved here -LL | src.0 = 66; //~ ERROR use of moved value: `src` [E0382] +LL | src.0 = 66; | ^^^^^^^^^^ value used here after move error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-lend-flow-if.nll.stderr b/src/test/ui/borrowck/borrowck-lend-flow-if.nll.stderr deleted file mode 100644 index 0c99edeb1a455..0000000000000 --- a/src/test/ui/borrowck/borrowck-lend-flow-if.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0502]: cannot borrow `*v` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-lend-flow-if.rs:29:16 - | -LL | _w = &v; - | -- immutable borrow occurs here -LL | } -LL | borrow_mut(&mut *v); //~ ERROR cannot borrow - | ^^^^^^^ mutable borrow occurs here -LL | _w.use_ref(); - | -- immutable borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-lend-flow-if.stderr b/src/test/ui/borrowck/borrowck-lend-flow-if.stderr index d1b6bb0c7c96c..68a82bdb57c55 100644 --- a/src/test/ui/borrowck/borrowck-lend-flow-if.stderr +++ b/src/test/ui/borrowck/borrowck-lend-flow-if.stderr @@ -1,14 +1,13 @@ -error[E0502]: cannot borrow `*v` as mutable because `v` is also borrowed as immutable - --> $DIR/borrowck-lend-flow-if.rs:29:21 +error[E0502]: cannot borrow `*v` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-lend-flow-if.rs:29:16 | LL | _w = &v; - | - immutable borrow occurs here + | -- immutable borrow occurs here LL | } -LL | borrow_mut(&mut *v); //~ ERROR cannot borrow - | ^^ mutable borrow occurs here +LL | borrow_mut(&mut *v); + | ^^^^^^^ mutable borrow occurs here LL | _w.use_ref(); -LL | } - | - immutable borrow ends here + | -- immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-lend-flow-loop.ast.stderr b/src/test/ui/borrowck/borrowck-lend-flow-loop.ast.stderr deleted file mode 100644 index 1844d8275999d..0000000000000 --- a/src/test/ui/borrowck/borrowck-lend-flow-loop.ast.stderr +++ /dev/null @@ -1,93 +0,0 @@ -error[E0502]: cannot borrow `*v` as immutable because `v` is also borrowed as mutable - --> $DIR/borrowck-lend-flow-loop.rs:35:17 - | -LL | let mut x = &mut v; - | - mutable borrow occurs here -... -LL | borrow(&*v); //[ast]~ ERROR cannot borrow - | ^^ immutable borrow occurs here -LL | } -LL | } - | - mutable borrow ends here - -error[E0502]: cannot borrow `*v` as immutable because `v` is also borrowed as mutable - --> $DIR/borrowck-lend-flow-loop.rs:45:17 - | -LL | let mut x = &mut v; - | - mutable borrow occurs here -LL | for _ in 0..3 { -LL | borrow(&*v); //[ast]~ ERROR cannot borrow - | ^^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here - -error[E0502]: cannot borrow `*v` as mutable because `v` is also borrowed as immutable - --> $DIR/borrowck-lend-flow-loop.rs:57:25 - | -LL | borrow_mut(&mut *v); //[ast]~ ERROR cannot borrow - | ^^ mutable borrow occurs here -LL | _x = &v; - | - immutable borrow occurs here -LL | } -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*v` as mutable because `v` is also borrowed as immutable - --> $DIR/borrowck-lend-flow-loop.rs:69:25 - | -LL | borrow_mut(&mut *v); //[ast]~ ERROR cannot borrow - | ^^ mutable borrow occurs here -LL | _x = &v; - | - immutable borrow occurs here -LL | } -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*v` as mutable because `v` is also borrowed as immutable - --> $DIR/borrowck-lend-flow-loop.rs:86:21 - | -LL | _x = &v; - | - immutable borrow occurs here -... -LL | borrow_mut(&mut *v); //[ast]~ ERROR cannot borrow - | ^^ mutable borrow occurs here -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*v` as mutable because `v` is also borrowed as immutable - --> $DIR/borrowck-lend-flow-loop.rs:100:21 - | -LL | _x = &v; - | - immutable borrow occurs here -... -LL | borrow_mut(&mut *v); //[ast]~ ERROR cannot borrow - | ^^ mutable borrow occurs here -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*v` as immutable because `v` is also borrowed as mutable - --> $DIR/borrowck-lend-flow-loop.rs:109:17 - | -LL | borrow(&*v); //[ast]~ ERROR cannot borrow - | ^^ immutable borrow occurs here -... -LL | x = &mut v; //[ast]~ ERROR cannot borrow - | - mutable borrow occurs here -... -LL | } - | - mutable borrow ends here - -error[E0499]: cannot borrow `v` as mutable more than once at a time - --> $DIR/borrowck-lend-flow-loop.rs:112:22 - | -LL | x = &mut v; //[ast]~ ERROR cannot borrow - | ^ mutable borrow starts here in previous iteration of loop -... -LL | } - | - mutable borrow ends here - -error: aborting due to 8 previous errors - -Some errors occurred: E0499, E0502. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-lend-flow-loop.nll.stderr b/src/test/ui/borrowck/borrowck-lend-flow-loop.nll.stderr deleted file mode 100644 index 396fd6ffa0c6b..0000000000000 --- a/src/test/ui/borrowck/borrowck-lend-flow-loop.nll.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-lend-flow-loop.rs:45:16 - | -LL | let mut x = &mut v; - | ------ mutable borrow occurs here -LL | for _ in 0..3 { -LL | borrow(&*v); //[ast]~ ERROR cannot borrow - | ^^^ immutable borrow occurs here -... -LL | *x = box 5; - | -- mutable borrow later used here - -error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-lend-flow-loop.rs:109:16 - | -LL | **x += 1; - | -------- mutable borrow later used here -LL | borrow(&*v); //[ast]~ ERROR cannot borrow - | ^^^ immutable borrow occurs here -... -LL | x = &mut v; //[ast]~ ERROR cannot borrow - | ------ mutable borrow occurs here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-lend-flow-loop.rs b/src/test/ui/borrowck/borrowck-lend-flow-loop.rs index 7008e5cef4b75..b650df91ca23c 100644 --- a/src/test/ui/borrowck/borrowck-lend-flow-loop.rs +++ b/src/test/ui/borrowck/borrowck-lend-flow-loop.rs @@ -1,19 +1,3 @@ -// revisions: ast nll - -// Since we are testing nll migration explicitly as a separate -// revision, don't worry about the --compare-mode=nll on this test. - -// ignore-compare-mode-nll - -//[ast]compile-flags: -Z borrowck=ast -//[nll]compile-flags: -Z borrowck=migrate -Z two-phase-borrows - -// Note: the borrowck analysis was originally a flow-insensitive pass -// over the AST. Therefore, some of these (AST) errors are marked as -// spurious and are corrected by the flow-sensitive (NLL) analysis. -// The others are either genuine or would require more advanced -// changes. The latter cases are noted. - #![feature(box_syntax)] fn borrow(_v: &isize) {} @@ -26,13 +10,13 @@ fn inc(v: &mut Box) { } fn loop_overarching_alias_mut() { - // In this instance, the borrow encompasses the entire loop. + // In this instance, the borrow ends on the line before the loop let mut v: Box<_> = box 3; let mut x = &mut v; **x += 1; loop { - borrow(&*v); //[ast]~ ERROR cannot borrow + borrow(&*v); // OK } } @@ -42,38 +26,37 @@ fn block_overarching_alias_mut() { let mut v: Box<_> = box 3; let mut x = &mut v; for _ in 0..3 { - borrow(&*v); //[ast]~ ERROR cannot borrow - //[nll]~^ ERROR cannot borrow + borrow(&*v); //~ ERROR cannot borrow } *x = box 5; } fn loop_aliased_mut() { - // In this instance, the borrow is carried through the loop. + // In this instance, the borrow ends right after each assignment to _x let mut v: Box<_> = box 3; let mut w: Box<_> = box 4; let mut _x = &w; loop { - borrow_mut(&mut *v); //[ast]~ ERROR cannot borrow + borrow_mut(&mut *v); // OK _x = &v; } } fn while_aliased_mut() { - // In this instance, the borrow is carried through the loop. + // In this instance, the borrow ends right after each assignment to _x let mut v: Box<_> = box 3; let mut w: Box<_> = box 4; let mut _x = &w; while cond() { - borrow_mut(&mut *v); //[ast]~ ERROR cannot borrow + borrow_mut(&mut *v); // OK _x = &v; } } fn loop_aliased_mut_break() { - // In this instance, the borrow is carried through the loop. + // In this instance, the borrow ends right after each assignment to _x let mut v: Box<_> = box 3; let mut w: Box<_> = box 4; @@ -83,11 +66,11 @@ fn loop_aliased_mut_break() { _x = &v; break; } - borrow_mut(&mut *v); //[ast]~ ERROR cannot borrow + borrow_mut(&mut *v); // OK } fn while_aliased_mut_break() { - // In this instance, the borrow is carried through the loop. + // In this instance, the borrow ends right after each assignment to _x let mut v: Box<_> = box 3; let mut w: Box<_> = box 4; @@ -97,7 +80,7 @@ fn while_aliased_mut_break() { _x = &v; break; } - borrow_mut(&mut *v); //[ast]~ ERROR cannot borrow + borrow_mut(&mut *v); // OK } fn while_aliased_mut_cond(cond: bool, cond2: bool) { @@ -106,10 +89,9 @@ fn while_aliased_mut_cond(cond: bool, cond2: bool) { let mut x = &mut w; while cond { **x += 1; - borrow(&*v); //[ast]~ ERROR cannot borrow - //[nll]~^ ERROR cannot borrow + borrow(&*v); //~ ERROR cannot borrow if cond2 { - x = &mut v; //[ast]~ ERROR cannot borrow + x = &mut v; // OK } } } diff --git a/src/test/ui/borrowck/borrowck-lend-flow-loop.stderr b/src/test/ui/borrowck/borrowck-lend-flow-loop.stderr new file mode 100644 index 0000000000000..f02c357f48b4c --- /dev/null +++ b/src/test/ui/borrowck/borrowck-lend-flow-loop.stderr @@ -0,0 +1,26 @@ +error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-lend-flow-loop.rs:29:16 + | +LL | let mut x = &mut v; + | ------ mutable borrow occurs here +LL | for _ in 0..3 { +LL | borrow(&*v); + | ^^^ immutable borrow occurs here +LL | } +LL | *x = box 5; + | -- mutable borrow later used here + +error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-lend-flow-loop.rs:92:16 + | +LL | **x += 1; + | -------- mutable borrow later used here +LL | borrow(&*v); + | ^^^ immutable borrow occurs here +LL | if cond2 { +LL | x = &mut v; // OK + | ------ mutable borrow occurs here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-lend-flow-match.ast.nll.stderr b/src/test/ui/borrowck/borrowck-lend-flow-match.ast.nll.stderr deleted file mode 100644 index 02289e0f4ec98..0000000000000 --- a/src/test/ui/borrowck/borrowck-lend-flow-match.ast.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-lend-flow-match.rs:18:13 - | -LL | Some(ref r) => { - | ----- borrow of `x` occurs here -LL | x = Some(1); //[ast]~ ERROR cannot assign - | ^^^^^^^^^^^ assignment to borrowed `x` occurs here -LL | //[mir]~^ ERROR cannot assign to `x` because it is borrowed -LL | drop(r); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-lend-flow-match.ast.stderr b/src/test/ui/borrowck/borrowck-lend-flow-match.ast.stderr deleted file mode 100644 index 23eb814788f65..0000000000000 --- a/src/test/ui/borrowck/borrowck-lend-flow-match.ast.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-lend-flow-match.rs:18:13 - | -LL | Some(ref r) => { - | ----- borrow of `x` occurs here -LL | x = Some(1); //[ast]~ ERROR cannot assign - | ^^^^^^^^^^^ assignment to borrowed `x` occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-lend-flow-match.mir.stderr b/src/test/ui/borrowck/borrowck-lend-flow-match.mir.stderr deleted file mode 100644 index 02289e0f4ec98..0000000000000 --- a/src/test/ui/borrowck/borrowck-lend-flow-match.mir.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-lend-flow-match.rs:18:13 - | -LL | Some(ref r) => { - | ----- borrow of `x` occurs here -LL | x = Some(1); //[ast]~ ERROR cannot assign - | ^^^^^^^^^^^ assignment to borrowed `x` occurs here -LL | //[mir]~^ ERROR cannot assign to `x` because it is borrowed -LL | drop(r); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-lend-flow-match.rs b/src/test/ui/borrowck/borrowck-lend-flow-match.rs index 4cd2a239b4e78..9737bc7695d10 100644 --- a/src/test/ui/borrowck/borrowck-lend-flow-match.rs +++ b/src/test/ui/borrowck/borrowck-lend-flow-match.rs @@ -1,11 +1,5 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - -#![allow(unused_variables)] -#![allow(unused_assignments)] - fn separate_arms() { - // Here both arms perform assignments, but only is illegal. + // Here both arms perform assignments, but only one is illegal. let mut x = None; match x { @@ -15,12 +9,10 @@ fn separate_arms() { x = Some(0); } Some(ref r) => { - x = Some(1); //[ast]~ ERROR cannot assign - //[mir]~^ ERROR cannot assign to `x` because it is borrowed + x = Some(1); //~ ERROR cannot assign to `x` because it is borrowed drop(r); } } - x.clone(); // just to prevent liveness warnings } fn main() {} diff --git a/src/test/ui/borrowck/borrowck-lend-flow-match.stderr b/src/test/ui/borrowck/borrowck-lend-flow-match.stderr new file mode 100644 index 0000000000000..66f1cd9bd5664 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-lend-flow-match.stderr @@ -0,0 +1,13 @@ +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/borrowck-lend-flow-match.rs:12:13 + | +LL | Some(ref r) => { + | ----- borrow of `x` occurs here +LL | x = Some(1); + | ^^^^^^^^^^^ assignment to borrowed `x` occurs here +LL | drop(r); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-lend-flow.nll.stderr b/src/test/ui/borrowck/borrowck-lend-flow.nll.stderr deleted file mode 100644 index ae3313597a3e4..0000000000000 --- a/src/test/ui/borrowck/borrowck-lend-flow.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0502]: cannot borrow `*v` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-lend-flow.rs:24:16 - | -LL | let _w = &v; - | -- immutable borrow occurs here -LL | borrow_mut(&mut *v); //~ ERROR cannot borrow - | ^^^^^^^ mutable borrow occurs here -LL | _w.use_ref(); - | -- immutable borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-lend-flow.stderr b/src/test/ui/borrowck/borrowck-lend-flow.stderr index d9080d0055391..07b11b3e72828 100644 --- a/src/test/ui/borrowck/borrowck-lend-flow.stderr +++ b/src/test/ui/borrowck/borrowck-lend-flow.stderr @@ -1,13 +1,12 @@ -error[E0502]: cannot borrow `*v` as mutable because `v` is also borrowed as immutable - --> $DIR/borrowck-lend-flow.rs:24:21 +error[E0502]: cannot borrow `*v` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-lend-flow.rs:24:16 | LL | let _w = &v; - | - immutable borrow occurs here -LL | borrow_mut(&mut *v); //~ ERROR cannot borrow - | ^^ mutable borrow occurs here + | -- immutable borrow occurs here +LL | borrow_mut(&mut *v); + | ^^^^^^^ mutable borrow occurs here LL | _w.use_ref(); -LL | } - | - immutable borrow ends here + | -- immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.nll.stderr b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.nll.stderr deleted file mode 100644 index 4497cfb71d19a..0000000000000 --- a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.nll.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0505]: cannot move out of `v` because it is borrowed - --> $DIR/borrowck-loan-blocks-move-cc.rs:14:19 - | -LL | let w = &v; - | -- borrow of `v` occurs here -LL | thread::spawn(move|| { - | ^^^^^^ move out of `v` occurs here -LL | println!("v={}", *v); - | - move occurs due to use in closure -... -LL | w.use_ref(); - | - borrow later used here - -error[E0505]: cannot move out of `v` because it is borrowed - --> $DIR/borrowck-loan-blocks-move-cc.rs:24:19 - | -LL | let w = &v; - | -- borrow of `v` occurs here -LL | thread::spawn(move|| { - | ^^^^^^ move out of `v` occurs here -LL | println!("v={}", *v); - | - move occurs due to use in closure -... -LL | w.use_ref(); - | - borrow later used here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.rs b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.rs index 29a20473f4847..9fa46563fdf80 100644 --- a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.rs +++ b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.rs @@ -12,8 +12,8 @@ fn box_imm() { let v: Box<_> = box 3; let w = &v; thread::spawn(move|| { + //~^ ERROR cannot move out of `v` because it is borrowed println!("v={}", *v); - //~^ ERROR cannot move `v` into closure }); w.use_ref(); } @@ -22,8 +22,8 @@ fn box_imm_explicit() { let v: Box<_> = box 3; let w = &v; thread::spawn(move|| { + //~^ ERROR cannot move println!("v={}", *v); - //~^ ERROR cannot move }); w.use_ref(); } diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr index b170635b4b997..2acbcd94f8bbf 100644 --- a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr +++ b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr @@ -1,21 +1,31 @@ -error[E0504]: cannot move `v` into closure because it is borrowed - --> $DIR/borrowck-loan-blocks-move-cc.rs:15:27 +error[E0505]: cannot move out of `v` because it is borrowed + --> $DIR/borrowck-loan-blocks-move-cc.rs:14:19 | LL | let w = &v; - | - borrow of `v` occurs here + | -- borrow of `v` occurs here LL | thread::spawn(move|| { + | ^^^^^^ move out of `v` occurs here +LL | LL | println!("v={}", *v); - | ^ move into closure occurs here + | - move occurs due to use in closure +LL | }); +LL | w.use_ref(); + | - borrow later used here -error[E0504]: cannot move `v` into closure because it is borrowed - --> $DIR/borrowck-loan-blocks-move-cc.rs:25:27 +error[E0505]: cannot move out of `v` because it is borrowed + --> $DIR/borrowck-loan-blocks-move-cc.rs:24:19 | LL | let w = &v; - | - borrow of `v` occurs here + | -- borrow of `v` occurs here LL | thread::spawn(move|| { + | ^^^^^^ move out of `v` occurs here +LL | LL | println!("v={}", *v); - | ^ move into closure occurs here + | - move occurs due to use in closure +LL | }); +LL | w.use_ref(); + | - borrow later used here error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0504`. +For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-move.nll.stderr b/src/test/ui/borrowck/borrowck-loan-blocks-move.nll.stderr deleted file mode 100644 index 450102f0c6622..0000000000000 --- a/src/test/ui/borrowck/borrowck-loan-blocks-move.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0505]: cannot move out of `v` because it is borrowed - --> $DIR/borrowck-loan-blocks-move.rs:11:10 - | -LL | let w = &v; - | -- borrow of `v` occurs here -LL | take(v); //~ ERROR cannot move out of `v` because it is borrowed - | ^ move out of `v` occurs here -LL | w.use_ref(); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-move.stderr b/src/test/ui/borrowck/borrowck-loan-blocks-move.stderr index ba6e34c2ec826..615660febbce2 100644 --- a/src/test/ui/borrowck/borrowck-loan-blocks-move.stderr +++ b/src/test/ui/borrowck/borrowck-loan-blocks-move.stderr @@ -2,9 +2,11 @@ error[E0505]: cannot move out of `v` because it is borrowed --> $DIR/borrowck-loan-blocks-move.rs:11:10 | LL | let w = &v; - | - borrow of `v` occurs here -LL | take(v); //~ ERROR cannot move out of `v` because it is borrowed + | -- borrow of `v` occurs here +LL | take(v); | ^ move out of `v` occurs here +LL | w.use_ref(); + | - borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.nll.stderr b/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.nll.stderr deleted file mode 100644 index 281a8103f9778..0000000000000 --- a/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-loan-blocks-mut-uniq.rs:10:12 - | -LL | borrow(&*v, - | ------ --- immutable borrow occurs here - | | - | immutable borrow later used by call -LL | |w| { //~ ERROR cannot borrow `v` as mutable - | ^^^ mutable borrow occurs here -LL | v = box 4; - | - second borrow occurs due to use of `v` in closure - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr b/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr index 6aa2d5d189d25..1d1522a15b1ed 100644 --- a/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr +++ b/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr @@ -1,15 +1,14 @@ -error[E0502]: cannot borrow `v` as mutable because `*v` is also borrowed as immutable +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable --> $DIR/borrowck-loan-blocks-mut-uniq.rs:10:12 | LL | borrow(&*v, - | -- immutable borrow occurs here -LL | |w| { //~ ERROR cannot borrow `v` as mutable + | ------ --- immutable borrow occurs here + | | + | immutable borrow later used by call +LL | |w| { | ^^^ mutable borrow occurs here LL | v = box 4; - | - borrow occurs due to use of `v` in closure -... -LL | }) - | - immutable borrow ends here + | - second borrow occurs due to use of `v` in closure error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.nll.stderr b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.nll.stderr deleted file mode 100644 index 095ae7f56b22e..0000000000000 --- a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: borrow of moved value: `x` - --> $DIR/borrowck-loan-in-overloaded-op.rs:21:20 - | -LL | let x = Foo(box 3); - | - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait -LL | let _y = {x} + x.clone(); // the `{x}` forces a move to occur - | - ^ value borrowed here after move - | | - | value moved here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.rs b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.rs index 464f01ca74c82..1baa94edfbe58 100644 --- a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.rs +++ b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.rs @@ -19,5 +19,5 @@ impl Add for Foo { fn main() { let x = Foo(box 3); let _y = {x} + x.clone(); // the `{x}` forces a move to occur - //~^ ERROR use of moved value: `x` + //~^ ERROR borrow of moved value: `x` } diff --git a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr index b6147aae8da5a..095ae7f56b22e 100644 --- a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr +++ b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `x` +error[E0382]: borrow of moved value: `x` --> $DIR/borrowck-loan-in-overloaded-op.rs:21:20 | +LL | let x = Foo(box 3); + | - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait LL | let _y = {x} + x.clone(); // the `{x}` forces a move to occur - | - ^ value used here after move + | - ^ value borrowed here after move | | | value moved here - | - = note: move occurs because `x` has type `Foo`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-loan-of-static-data-issue-27616.nll.stderr b/src/test/ui/borrowck/borrowck-loan-of-static-data-issue-27616.nll.stderr deleted file mode 100644 index 6984575890308..0000000000000 --- a/src/test/ui/borrowck/borrowck-loan-of-static-data-issue-27616.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0506]: cannot assign to `*s` because it is borrowed - --> $DIR/borrowck-loan-of-static-data-issue-27616.rs:16:5 - | -LL | let alias: &'static mut String = s; - | ------------------- - borrow of `*s` occurs here - | | - | type annotation requires that `*s` is borrowed for `'static` -... -LL | *s = String::new(); //~ ERROR cannot assign - | ^^ assignment to borrowed `*s` occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr b/src/test/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr index eceb923e776b7..6994c837dfcbe 100644 --- a/src/test/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr +++ b/src/test/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr @@ -2,10 +2,12 @@ error[E0506]: cannot assign to `*s` because it is borrowed --> $DIR/borrowck-loan-of-static-data-issue-27616.rs:16:5 | LL | let alias: &'static mut String = s; - | - borrow of `*s` occurs here + | ------------------- - borrow of `*s` occurs here + | | + | type annotation requires that `*s` is borrowed for `'static` ... -LL | *s = String::new(); //~ ERROR cannot assign - | ^^^^^^^^^^^^^^^^^^ assignment to borrowed `*s` occurs here +LL | *s = String::new(); + | ^^ assignment to borrowed `*s` occurs here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.nll.stderr b/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.nll.stderr deleted file mode 100644 index 421af61ff78c3..0000000000000 --- a/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.nll.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error[E0503]: cannot use `p` because it was mutably borrowed - --> $DIR/borrowck-loan-rcvr-overloaded-op.rs:38:5 - | -LL | let q = &mut p; - | ------ borrow of `p` occurs here -LL | -LL | p + 3; //~ ERROR cannot use `p` - | ^ use of borrowed `p` -... -LL | *q + 3; // OK to use the new alias `q` - | -- borrow later used here - -error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-loan-rcvr-overloaded-op.rs:39:5 - | -LL | let q = &mut p; - | ------ mutable borrow occurs here -... -LL | p.times(3); //~ ERROR cannot borrow `p` - | ^ immutable borrow occurs here -LL | -LL | *q + 3; // OK to use the new alias `q` - | -- mutable borrow later used here - -error: aborting due to 2 previous errors - -Some errors occurred: E0502, E0503. -For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr b/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr index b4f7a9af666f4..aa874c34a22ed 100644 --- a/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr +++ b/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr @@ -2,24 +2,27 @@ error[E0503]: cannot use `p` because it was mutably borrowed --> $DIR/borrowck-loan-rcvr-overloaded-op.rs:38:5 | LL | let q = &mut p; - | - borrow of `p` occurs here + | ------ borrow of `p` occurs here LL | -LL | p + 3; //~ ERROR cannot use `p` +LL | p + 3; | ^ use of borrowed `p` +... +LL | *q + 3; // OK to use the new alias `q` + | -- borrow later used here error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable --> $DIR/borrowck-loan-rcvr-overloaded-op.rs:39:5 | LL | let q = &mut p; - | - mutable borrow occurs here + | ------ mutable borrow occurs here ... -LL | p.times(3); //~ ERROR cannot borrow `p` +LL | p.times(3); | ^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here +LL | +LL | *q + 3; // OK to use the new alias `q` + | -- mutable borrow later used here error: aborting due to 2 previous errors -Some errors occurred: E0502, E0503. +Some errors have detailed explanations: E0502, E0503. For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-loan-rcvr.nll.stderr b/src/test/ui/borrowck/borrowck-loan-rcvr.nll.stderr deleted file mode 100644 index bded4d1e0a3b3..0000000000000 --- a/src/test/ui/borrowck/borrowck-loan-rcvr.nll.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-loan-rcvr.rs:23:14 - | -LL | p.blockm(|| { //~ ERROR cannot borrow `p` as mutable - | - ------ ^^ mutable borrow occurs here - | | | - | | immutable borrow later used by call - | immutable borrow occurs here -LL | p.x = 10; - | - second borrow occurs due to use of `p` in closure - -error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-loan-rcvr.rs:34:5 - | -LL | let l = &mut p; - | ------ mutable borrow occurs here -LL | p.impurem(); //~ ERROR cannot borrow - | ^ immutable borrow occurs here -LL | -LL | l.x += 1; - | -------- mutable borrow later used here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-loan-rcvr.stderr b/src/test/ui/borrowck/borrowck-loan-rcvr.stderr index eb0bbec0bc772..ec3edc80323f5 100644 --- a/src/test/ui/borrowck/borrowck-loan-rcvr.stderr +++ b/src/test/ui/borrowck/borrowck-loan-rcvr.stderr @@ -1,25 +1,24 @@ error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable --> $DIR/borrowck-loan-rcvr.rs:23:14 | -LL | p.blockm(|| { //~ ERROR cannot borrow `p` as mutable - | - ^^ mutable borrow occurs here - | | +LL | p.blockm(|| { + | - ------ ^^ mutable borrow occurs here + | | | + | | immutable borrow later used by call | immutable borrow occurs here LL | p.x = 10; - | - borrow occurs due to use of `p` in closure -LL | }) - | - immutable borrow ends here + | - second borrow occurs due to use of `p` in closure error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable --> $DIR/borrowck-loan-rcvr.rs:34:5 | LL | let l = &mut p; - | - mutable borrow occurs here -LL | p.impurem(); //~ ERROR cannot borrow + | ------ mutable borrow occurs here +LL | p.impurem(); | ^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here +LL | +LL | l.x += 1; + | -------- mutable borrow later used here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-loan-vec-content.nll.stderr b/src/test/ui/borrowck/borrowck-loan-vec-content.nll.stderr deleted file mode 100644 index be48f217ef19b..0000000000000 --- a/src/test/ui/borrowck/borrowck-loan-vec-content.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-loan-vec-content.rs:18:9 - | -LL | takes_imm_elt( - | ------------- immutable borrow later used by call -LL | &v[0], - | - immutable borrow occurs here -LL | || { //~ ERROR cannot borrow `v` as mutable - | ^^ mutable borrow occurs here -LL | v[1] = 4; - | - second borrow occurs due to use of `v` in closure - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-loan-vec-content.stderr b/src/test/ui/borrowck/borrowck-loan-vec-content.stderr index 6a565ff2f10d4..6691a2396a1da 100644 --- a/src/test/ui/borrowck/borrowck-loan-vec-content.stderr +++ b/src/test/ui/borrowck/borrowck-loan-vec-content.stderr @@ -1,14 +1,14 @@ error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable --> $DIR/borrowck-loan-vec-content.rs:18:9 | +LL | takes_imm_elt( + | ------------- immutable borrow later used by call LL | &v[0], | - immutable borrow occurs here -LL | || { //~ ERROR cannot borrow `v` as mutable +LL | || { | ^^ mutable borrow occurs here LL | v[1] = 4; - | - borrow occurs due to use of `v` in closure -LL | }) - | - immutable borrow ends here + | - second borrow occurs due to use of `v` in closure error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.ast.nll.stderr b/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.ast.nll.stderr deleted file mode 100644 index df89e85ebe201..0000000000000 --- a/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.ast.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0515]: cannot return reference to function parameter `x` - --> $DIR/borrowck-local-borrow-outlives-fn.rs:5:5 - | -LL | &x - | ^^ returns a reference to data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.ast.stderr b/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.ast.stderr deleted file mode 100644 index 6eda8a439baa4..0000000000000 --- a/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.ast.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0597]: `x` does not live long enough - --> $DIR/borrowck-local-borrow-outlives-fn.rs:5:6 - | -LL | &x - | ^ borrowed value does not live long enough -... -LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.mir.stderr b/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.mir.stderr deleted file mode 100644 index df89e85ebe201..0000000000000 --- a/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.mir.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0515]: cannot return reference to function parameter `x` - --> $DIR/borrowck-local-borrow-outlives-fn.rs:5:5 - | -LL | &x - | ^^ returns a reference to data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.rs b/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.rs index 6137ac914ddfb..b6eebd4e3256f 100644 --- a/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.rs +++ b/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.rs @@ -1,10 +1,6 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - fn cplusplus_mode(x: isize) -> &'static isize { &x - //[ast]~^ ERROR `x` does not live long enough [E0597] - //[mir]~^^ ERROR cannot return reference to function parameter `x` [E0515] + //~^ ERROR cannot return reference to function parameter `x` [E0515] } fn main() {} diff --git a/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.stderr b/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.stderr new file mode 100644 index 0000000000000..9d19de211a5e0 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-local-borrow-outlives-fn.stderr @@ -0,0 +1,9 @@ +error[E0515]: cannot return reference to function parameter `x` + --> $DIR/borrowck-local-borrow-outlives-fn.rs:2:5 + | +LL | &x + | ^^ returns a reference to data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.ast.nll.stderr b/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.ast.nll.stderr deleted file mode 100644 index ac9e73fadec06..0000000000000 --- a/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.ast.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0597]: `z.1` does not live long enough - --> $DIR/borrowck-local-borrow-with-panic-outlives-fn.rs:6:15 - | -LL | *x = Some(&mut z.1); - | ----------^^^^^^^^- - | | | - | | borrowed value does not live long enough - | assignment requires that `z.1` is borrowed for `'static` -... -LL | } - | - `z.1` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.ast.stderr b/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.ast.stderr deleted file mode 100644 index 89a0e6cd8290c..0000000000000 --- a/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.ast.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0597]: `z.1` does not live long enough - --> $DIR/borrowck-local-borrow-with-panic-outlives-fn.rs:6:20 - | -LL | *x = Some(&mut z.1); - | ^^^ borrowed value does not live long enough -... -LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.mir.stderr b/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.mir.stderr deleted file mode 100644 index ac9e73fadec06..0000000000000 --- a/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.mir.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0597]: `z.1` does not live long enough - --> $DIR/borrowck-local-borrow-with-panic-outlives-fn.rs:6:15 - | -LL | *x = Some(&mut z.1); - | ----------^^^^^^^^- - | | | - | | borrowed value does not live long enough - | assignment requires that `z.1` is borrowed for `'static` -... -LL | } - | - `z.1` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs b/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs index 9ead465eadab7..ffb2da280232f 100644 --- a/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs +++ b/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs @@ -1,11 +1,7 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - fn cplusplus_mode_exceptionally_unsafe(x: &mut Option<&'static mut isize>) { let mut z = (0, 0); *x = Some(&mut z.1); - //[ast]~^ ERROR `z.1` does not live long enough [E0597] - //[mir]~^^ ERROR `z.1` does not live long enough [E0597] + //~^ ERROR `z.1` does not live long enough [E0597] panic!("catch me for a dangling pointer!") } diff --git a/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr b/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr new file mode 100644 index 0000000000000..6ea6951ad9665 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr @@ -0,0 +1,15 @@ +error[E0597]: `z.1` does not live long enough + --> $DIR/borrowck-local-borrow-with-panic-outlives-fn.rs:3:15 + | +LL | *x = Some(&mut z.1); + | ----------^^^^^^^^- + | | | + | | borrowed value does not live long enough + | assignment requires that `z.1` is borrowed for `'static` +... +LL | } + | - `z.1` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.nll.stderr b/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.nll.stderr deleted file mode 100644 index b2b82fba5b064..0000000000000 --- a/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.nll.stderr +++ /dev/null @@ -1,51 +0,0 @@ -error[E0503]: cannot use `foo` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:13:9 - | -LL | let p = &mut foo; - | -------- borrow of `foo` occurs here -LL | let _ = match foo { -LL | Foo::B => 1, //[mir]~ ERROR [E0503] - | ^^^^^^ use of borrowed `foo` -... -LL | drop(p); - | - borrow later used here - -error[E0503]: cannot use `foo.0` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:15:16 - | -LL | let p = &mut foo; - | -------- borrow of `foo` occurs here -... -LL | Foo::A(x) => x //[ast]~ ERROR [E0503] - | ^ use of borrowed `foo` -... -LL | drop(p); - | - borrow later used here - -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:26:9 - | -LL | let r = &mut x; - | ------ borrow of `x` occurs here -LL | let _ = match x { -LL | x => x + 1, //[ast]~ ERROR [E0503] - | ^ use of borrowed `x` -... -LL | drop(r); - | - borrow later used here - -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:28:9 - | -LL | let r = &mut x; - | ------ borrow of `x` occurs here -... -LL | y => y + 2, //[ast]~ ERROR [E0503] - | ^ use of borrowed `x` -... -LL | drop(r); - | - borrow later used here - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.stderr b/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.stderr deleted file mode 100644 index cfbbef93f1f99..0000000000000 --- a/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0503]: cannot use `(foo as Foo::A).0` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:15:16 - | -LL | let p = &mut foo; - | --- borrow of `foo` occurs here -... -LL | Foo::A(x) => x //[ast]~ ERROR [E0503] - | ^ use of borrowed `foo` - -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:26:9 - | -LL | let r = &mut x; - | - borrow of `x` occurs here -LL | let _ = match x { -LL | x => x + 1, //[ast]~ ERROR [E0503] - | ^ use of borrowed `x` - -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:28:9 - | -LL | let r = &mut x; - | - borrow of `x` occurs here -... -LL | y => y + 2, //[ast]~ ERROR [E0503] - | ^ use of borrowed `x` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/borrowck/borrowck-match-already-borrowed.mir.stderr b/src/test/ui/borrowck/borrowck-match-already-borrowed.mir.stderr deleted file mode 100644 index b2b82fba5b064..0000000000000 --- a/src/test/ui/borrowck/borrowck-match-already-borrowed.mir.stderr +++ /dev/null @@ -1,51 +0,0 @@ -error[E0503]: cannot use `foo` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:13:9 - | -LL | let p = &mut foo; - | -------- borrow of `foo` occurs here -LL | let _ = match foo { -LL | Foo::B => 1, //[mir]~ ERROR [E0503] - | ^^^^^^ use of borrowed `foo` -... -LL | drop(p); - | - borrow later used here - -error[E0503]: cannot use `foo.0` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:15:16 - | -LL | let p = &mut foo; - | -------- borrow of `foo` occurs here -... -LL | Foo::A(x) => x //[ast]~ ERROR [E0503] - | ^ use of borrowed `foo` -... -LL | drop(p); - | - borrow later used here - -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:26:9 - | -LL | let r = &mut x; - | ------ borrow of `x` occurs here -LL | let _ = match x { -LL | x => x + 1, //[ast]~ ERROR [E0503] - | ^ use of borrowed `x` -... -LL | drop(r); - | - borrow later used here - -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:28:9 - | -LL | let r = &mut x; - | ------ borrow of `x` occurs here -... -LL | y => y + 2, //[ast]~ ERROR [E0503] - | ^ use of borrowed `x` -... -LL | drop(r); - | - borrow later used here - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/borrowck/borrowck-match-already-borrowed.rs b/src/test/ui/borrowck/borrowck-match-already-borrowed.rs index 7f4cdbd0e7c59..c766e6c108086 100644 --- a/src/test/ui/borrowck/borrowck-match-already-borrowed.rs +++ b/src/test/ui/borrowck/borrowck-match-already-borrowed.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - enum Foo { A(i32), B @@ -10,10 +7,9 @@ fn match_enum() { let mut foo = Foo::B; let p = &mut foo; let _ = match foo { - Foo::B => 1, //[mir]~ ERROR [E0503] + Foo::B => 1, //~ ERROR [E0503] _ => 2, - Foo::A(x) => x //[ast]~ ERROR [E0503] - //[mir]~^ ERROR [E0503] + Foo::A(x) => x //~ ERROR [E0503] }; drop(p); } @@ -23,10 +19,8 @@ fn main() { let mut x = 1; let r = &mut x; let _ = match x { - x => x + 1, //[ast]~ ERROR [E0503] - //[mir]~^ ERROR [E0503] - y => y + 2, //[ast]~ ERROR [E0503] - //[mir]~^ ERROR [E0503] + x => x + 1, //~ ERROR [E0503] + y => y + 2, //~ ERROR [E0503] }; drop(r); } diff --git a/src/test/ui/borrowck/borrowck-match-already-borrowed.stderr b/src/test/ui/borrowck/borrowck-match-already-borrowed.stderr new file mode 100644 index 0000000000000..286a925bb7f6c --- /dev/null +++ b/src/test/ui/borrowck/borrowck-match-already-borrowed.stderr @@ -0,0 +1,51 @@ +error[E0503]: cannot use `foo` because it was mutably borrowed + --> $DIR/borrowck-match-already-borrowed.rs:10:9 + | +LL | let p = &mut foo; + | -------- borrow of `foo` occurs here +LL | let _ = match foo { +LL | Foo::B => 1, + | ^^^^^^ use of borrowed `foo` +... +LL | drop(p); + | - borrow later used here + +error[E0503]: cannot use `foo.0` because it was mutably borrowed + --> $DIR/borrowck-match-already-borrowed.rs:12:16 + | +LL | let p = &mut foo; + | -------- borrow of `foo` occurs here +... +LL | Foo::A(x) => x + | ^ use of borrowed `foo` +LL | }; +LL | drop(p); + | - borrow later used here + +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/borrowck-match-already-borrowed.rs:22:9 + | +LL | let r = &mut x; + | ------ borrow of `x` occurs here +LL | let _ = match x { +LL | x => x + 1, + | ^ use of borrowed `x` +... +LL | drop(r); + | - borrow later used here + +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/borrowck-match-already-borrowed.rs:23:9 + | +LL | let r = &mut x; + | ------ borrow of `x` occurs here +... +LL | y => y + 2, + | ^ use of borrowed `x` +LL | }; +LL | drop(r); + | - borrow later used here + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/borrowck/borrowck-match-binding-is-assignment.ast.nll.stderr b/src/test/ui/borrowck/borrowck-match-binding-is-assignment.ast.nll.stderr deleted file mode 100644 index cd88d69323895..0000000000000 --- a/src/test/ui/borrowck/borrowck-match-binding-is-assignment.ast.nll.stderr +++ /dev/null @@ -1,58 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:17:13 - | -LL | x => { - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:24:13 - | -LL | E::Foo(x) => { - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:31:13 - | -LL | S { bar: x } => { - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:38:13 - | -LL | (x,) => { - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:45:13 - | -LL | [x,_,_] => { - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/borrowck/borrowck-match-binding-is-assignment.ast.stderr b/src/test/ui/borrowck/borrowck-match-binding-is-assignment.ast.stderr deleted file mode 100644 index e7bd9dfee12f4..0000000000000 --- a/src/test/ui/borrowck/borrowck-match-binding-is-assignment.ast.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:17:13 - | -LL | x => { - | - first assignment to `x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:24:13 - | -LL | E::Foo(x) => { - | - first assignment to `x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:31:13 - | -LL | S { bar: x } => { - | - first assignment to `x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:38:13 - | -LL | (x,) => { - | - first assignment to `x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:45:13 - | -LL | [x,_,_] => { - | - first assignment to `x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/borrowck/borrowck-match-binding-is-assignment.mir.stderr b/src/test/ui/borrowck/borrowck-match-binding-is-assignment.mir.stderr deleted file mode 100644 index cd88d69323895..0000000000000 --- a/src/test/ui/borrowck/borrowck-match-binding-is-assignment.mir.stderr +++ /dev/null @@ -1,58 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:17:13 - | -LL | x => { - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:24:13 - | -LL | E::Foo(x) => { - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:31:13 - | -LL | S { bar: x } => { - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:38:13 - | -LL | (x,) => { - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/borrowck-match-binding-is-assignment.rs:45:13 - | -LL | [x,_,_] => { - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - | ^^^^^^ cannot assign twice to immutable variable - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/borrowck/borrowck-match-binding-is-assignment.rs b/src/test/ui/borrowck/borrowck-match-binding-is-assignment.rs index 2c9c41ca10e09..064bf69ae7900 100644 --- a/src/test/ui/borrowck/borrowck-match-binding-is-assignment.rs +++ b/src/test/ui/borrowck/borrowck-match-binding-is-assignment.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - // Test that immutable pattern bindings cannot be reassigned. enum E { @@ -14,36 +11,31 @@ struct S { pub fn main() { match 1 { x => { - x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - //[mir]~^ ERROR [E0384] + x += 1; //~ ERROR [E0384] } } match E::Foo(1) { E::Foo(x) => { - x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - //[mir]~^ ERROR [E0384] + x += 1; //~ ERROR [E0384] } } match (S { bar: 1 }) { S { bar: x } => { - x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - //[mir]~^ ERROR [E0384] + x += 1; //~ ERROR [E0384] } } match (1,) { (x,) => { - x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - //[mir]~^ ERROR [E0384] + x += 1; //~ ERROR [E0384] } } match [1,2,3] { [x,_,_] => { - x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x` - //[mir]~^ ERROR [E0384] + x += 1; //~ ERROR [E0384] } } } diff --git a/src/test/ui/borrowck/borrowck-match-binding-is-assignment.stderr b/src/test/ui/borrowck/borrowck-match-binding-is-assignment.stderr new file mode 100644 index 0000000000000..5661ca52cbabc --- /dev/null +++ b/src/test/ui/borrowck/borrowck-match-binding-is-assignment.stderr @@ -0,0 +1,58 @@ +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/borrowck-match-binding-is-assignment.rs:14:13 + | +LL | x => { + | - + | | + | first assignment to `x` + | help: make this binding mutable: `mut x` +LL | x += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/borrowck-match-binding-is-assignment.rs:20:13 + | +LL | E::Foo(x) => { + | - + | | + | first assignment to `x` + | help: make this binding mutable: `mut x` +LL | x += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/borrowck-match-binding-is-assignment.rs:26:13 + | +LL | S { bar: x } => { + | - + | | + | first assignment to `x` + | help: make this binding mutable: `mut x` +LL | x += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/borrowck-match-binding-is-assignment.rs:32:13 + | +LL | (x,) => { + | - + | | + | first assignment to `x` + | help: make this binding mutable: `mut x` +LL | x += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/borrowck-match-binding-is-assignment.rs:38:13 + | +LL | [x,_,_] => { + | - + | | + | first assignment to `x` + | help: make this binding mutable: `mut x` +LL | x += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr b/src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr index 8dba34bd8086b..663164cfc2c1c 100644 --- a/src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr +++ b/src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr @@ -1,9 +1,15 @@ -warning[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-migrate-to-nll.rs:25:17 +warning[E0507]: cannot move out of `foo` in pattern guard + --> $DIR/borrowck-migrate-to-nll.rs:25:18 | LL | (|| { let bar = foo; bar.take() })(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | ^^ --- + | | | + | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs due to use in closure + | move out of `foo` occurs here | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard = warning: this error has been downgraded to a warning for backwards compatibility with previous releases = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` diff --git a/src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr b/src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr index 8dba34bd8086b..663164cfc2c1c 100644 --- a/src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr +++ b/src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr @@ -1,9 +1,15 @@ -warning[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-migrate-to-nll.rs:25:17 +warning[E0507]: cannot move out of `foo` in pattern guard + --> $DIR/borrowck-migrate-to-nll.rs:25:18 | LL | (|| { let bar = foo; bar.take() })(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | ^^ --- + | | | + | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs due to use in closure + | move out of `foo` occurs here | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard = warning: this error has been downgraded to a warning for backwards compatibility with previous releases = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.nll.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.nll.stderr deleted file mode 100644 index b8a0117441779..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-by-capture.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/borrowck-move-by-capture.rs:9:29 - | -LL | let bar: Box<_> = box 3; - | --- captured outer variable -LL | let _g = to_fn_mut(|| { -LL | let _h = to_fn_once(move || -> isize { *bar }); //~ ERROR cannot move out of - | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of captured variable in an `FnMut` closure - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.stderr index 9c485fb48ca74..0eceaf561b44c 100644 --- a/src/test/ui/borrowck/borrowck-move-by-capture.stderr +++ b/src/test/ui/borrowck/borrowck-move-by-capture.stderr @@ -1,11 +1,15 @@ -error[E0507]: cannot move out of captured outer variable in an `FnMut` closure +error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure --> $DIR/borrowck-move-by-capture.rs:9:29 | LL | let bar: Box<_> = box 3; | --- captured outer variable LL | let _g = to_fn_mut(|| { -LL | let _h = to_fn_once(move || -> isize { *bar }); //~ ERROR cannot move out of - | ^^^^^^^^^^^^^^^^ cannot move out of captured outer variable in an `FnMut` closure +LL | let _h = to_fn_once(move || -> isize { *bar }); + | ^^^^^^^^^^^^^^^^ --- + | | | + | | move occurs because `bar` has type `std::boxed::Box`, which does not implement the `Copy` trait + | | move occurs due to use in closure + | move out of `bar` occurs here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-error-with-note.nll.stderr b/src/test/ui/borrowck/borrowck-move-error-with-note.nll.stderr deleted file mode 100644 index 9386278886f6b..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-error-with-note.nll.stderr +++ /dev/null @@ -1,67 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-error-with-note.rs:11:11 - | -LL | match *f { //~ ERROR cannot move out of - | ^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `f` -LL | //~| cannot move out -LL | Foo::Foo1(num1, - | ---- data moved here -LL | num2) => (), - | ---- ...and here -LL | Foo::Foo2(num) => (), - | --- ...and here - | -note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/borrowck-move-error-with-note.rs:13:19 - | -LL | Foo::Foo1(num1, - | ^^^^ -LL | num2) => (), - | ^^^^ -LL | Foo::Foo2(num) => (), - | ^^^ - -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-error-with-note.rs:29:11 - | -LL | match (S {f: "foo".to_string(), g: "bar".to_string()}) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here -... -LL | f: _s, - | -- data moved here -LL | g: _t - | -- ...and here - | -note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/borrowck-move-error-with-note.rs:32:16 - | -LL | f: _s, - | ^^ -LL | g: _t - | ^^ - -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-error-with-note.rs:47:11 - | -LL | match a.a { //~ ERROR cannot move out of - | ^^^ - | | - | cannot move out of borrowed content - | help: consider borrowing here: `&a.a` -LL | //~| cannot move out -LL | n => { - | - data moved here - | -note: move occurs because `n` has type `std::boxed::Box`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-error-with-note.rs:49:9 - | -LL | n => { - | ^ - -error: aborting due to 3 previous errors - -Some errors occurred: E0507, E0509. -For more information about an error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-error-with-note.rs b/src/test/ui/borrowck/borrowck-move-error-with-note.rs index d2dab2eacca42..7ef59f50c0332 100644 --- a/src/test/ui/borrowck/borrowck-move-error-with-note.rs +++ b/src/test/ui/borrowck/borrowck-move-error-with-note.rs @@ -9,7 +9,6 @@ enum Foo { fn blah() { let f = &Foo::Foo1(box 1, box 2); match *f { //~ ERROR cannot move out of - //~| cannot move out Foo::Foo1(num1, num2) => (), Foo::Foo2(num) => (), @@ -27,8 +26,8 @@ impl Drop for S { fn move_in_match() { match (S {f: "foo".to_string(), g: "bar".to_string()}) { - S { //~ ERROR cannot move out of type `S`, which implements the `Drop` trait - //~| cannot move out of here + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait + S { f: _s, g: _t } => {} @@ -45,7 +44,6 @@ fn free(_: T) {} fn blah2() { let a = &A { a: box 1 }; match a.a { //~ ERROR cannot move out of - //~| cannot move out n => { free(n) } diff --git a/src/test/ui/borrowck/borrowck-move-error-with-note.stderr b/src/test/ui/borrowck/borrowck-move-error-with-note.stderr index 07009b42e4da1..d56b9f562c932 100644 --- a/src/test/ui/borrowck/borrowck-move-error-with-note.stderr +++ b/src/test/ui/borrowck/borrowck-move-error-with-note.stderr @@ -1,38 +1,56 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `f.0` which is behind a shared reference --> $DIR/borrowck-move-error-with-note.rs:11:11 | -LL | match *f { //~ ERROR cannot move out of - | ^^ cannot move out of borrowed content -LL | //~| cannot move out +LL | match *f { + | ^^ help: consider borrowing here: `&*f` LL | Foo::Foo1(num1, - | ---- hint: to prevent move, use `ref num1` or `ref mut num1` + | ---- data moved here LL | num2) => (), - | ---- ...and here (use `ref num2` or `ref mut num2`) + | ---- ...and here LL | Foo::Foo2(num) => (), - | --- ...and here (use `ref num` or `ref mut num`) + | --- ...and here + | +note: move occurs because these variables have types that don't implement the `Copy` trait + --> $DIR/borrowck-move-error-with-note.rs:12:19 + | +LL | Foo::Foo1(num1, + | ^^^^ +LL | num2) => (), + | ^^^^ +LL | Foo::Foo2(num) => (), + | ^^^ error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-error-with-note.rs:30:9 + --> $DIR/borrowck-move-error-with-note.rs:28:11 + | +LL | match (S {f: "foo".to_string(), g: "bar".to_string()}) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here +... +LL | f: _s, + | -- data moved here +LL | g: _t + | -- ...and here + | +note: move occurs because these variables have types that don't implement the `Copy` trait + --> $DIR/borrowck-move-error-with-note.rs:31:16 | -LL | / S { //~ ERROR cannot move out of type `S`, which implements the `Drop` trait -LL | | //~| cannot move out of here -LL | | f: _s, - | | -- hint: to prevent move, use `ref _s` or `ref mut _s` -LL | | g: _t - | | -- ...and here (use `ref _t` or `ref mut _t`) -LL | | } => {} - | |_________^ cannot move out of here +LL | f: _s, + | ^^ +LL | g: _t + | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-error-with-note.rs:47:11 +error[E0507]: cannot move out of `a.a` which is behind a shared reference + --> $DIR/borrowck-move-error-with-note.rs:46:11 | -LL | match a.a { //~ ERROR cannot move out of - | ^ cannot move out of borrowed content -LL | //~| cannot move out +LL | match a.a { + | ^^^ help: consider borrowing here: `&a.a` LL | n => { - | - hint: to prevent move, use `ref n` or `ref mut n` + | - + | | + | data moved here + | move occurs because `n` has type `std::boxed::Box`, which does not implement the `Copy` trait error: aborting due to 3 previous errors -Some errors occurred: E0507, E0509. +Some errors have detailed explanations: E0507, E0509. For more information about an error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.nll.stderr b/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.nll.stderr deleted file mode 100644 index b7fa2247e32f7..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0505]: cannot move out of `*a` because it is borrowed - --> $DIR/borrowck-move-from-subpath-of-borrowed-path.rs:12:13 - | -LL | let b = &a; - | -- borrow of `a` occurs here -LL | -LL | let z = *a; //~ ERROR: cannot move out of `*a` because it is borrowed - | ^^ move out of `*a` occurs here -LL | b.use_ref(); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr b/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr index 2ed888051f61e..e4840fba67299 100644 --- a/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr +++ b/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr @@ -1,11 +1,13 @@ error[E0505]: cannot move out of `*a` because it is borrowed - --> $DIR/borrowck-move-from-subpath-of-borrowed-path.rs:12:9 + --> $DIR/borrowck-move-from-subpath-of-borrowed-path.rs:12:13 | LL | let b = &a; - | - borrow of `a` occurs here + | -- borrow of `a` occurs here LL | -LL | let z = *a; //~ ERROR: cannot move out of `*a` because it is borrowed - | ^ move out of `*a` occurs here +LL | let z = *a; + | ^^ move out of `*a` occurs here +LL | b.use_ref(); + | - borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.nll.stderr b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.nll.stderr deleted file mode 100644 index 5b78465795362..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0507]: cannot move out of dereference of raw pointer - --> $DIR/borrowck-move-from-unsafe-ptr.rs:2:13 - | -LL | let y = *x; //~ ERROR cannot move out of dereference of raw pointer - | ^^ - | | - | cannot move out of dereference of raw pointer - | help: consider removing the `*`: `x` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.rs b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.rs index bf8ff9cf0a9da..824da5ceb07a0 100644 --- a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.rs +++ b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.rs @@ -1,5 +1,5 @@ unsafe fn foo(x: *const Box) -> Box { - let y = *x; //~ ERROR cannot move out of dereference of raw pointer + let y = *x; //~ ERROR cannot move out of `*x` which is behind a raw pointer return y; } diff --git a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr index 62a522600388d..7dfae33920e1c 100644 --- a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr +++ b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr @@ -1,11 +1,11 @@ -error[E0507]: cannot move out of dereference of raw pointer +error[E0507]: cannot move out of `*x` which is behind a raw pointer --> $DIR/borrowck-move-from-unsafe-ptr.rs:2:13 | -LL | let y = *x; //~ ERROR cannot move out of dereference of raw pointer +LL | let y = *x; | ^^ | | - | cannot move out of dereference of raw pointer - | help: consider using a reference instead: `&*x` + | move occurs because `*x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.ast.nll.stderr b/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.ast.nll.stderr deleted file mode 100644 index c18fce9f4fd55..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.ast.nll.stderr +++ /dev/null @@ -1,50 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-in-irrefut-pat.rs:6:13 - | -LL | fn arg_item(&_x: &String) {} - | ^-- - | || - | |data moved here - | cannot move out of borrowed content - | help: consider removing the `&`: `_x` - | -note: move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-in-irrefut-pat.rs:6:14 - | -LL | fn arg_item(&_x: &String) {} - | ^^ - -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-in-irrefut-pat.rs:11:11 - | -LL | with(|&_x| ()) - | ^-- - | || - | |data moved here - | cannot move out of borrowed content - | help: consider removing the `&`: `_x` - | -note: move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-in-irrefut-pat.rs:11:12 - | -LL | with(|&_x| ()) - | ^^ - -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-in-irrefut-pat.rs:17:15 - | -LL | let &_x = &"hi".to_string(); - | --- ^^^^^^^^^^^^^^^^^ cannot move out of borrowed content - | || - | |data moved here - | help: consider removing the `&`: `_x` - | -note: move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-in-irrefut-pat.rs:17:10 - | -LL | let &_x = &"hi".to_string(); - | ^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.ast.stderr b/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.ast.stderr deleted file mode 100644 index 019ed96661fc2..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.ast.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-in-irrefut-pat.rs:6:13 - | -LL | fn arg_item(&_x: &String) {} - | ^-- - | || - | |hint: to prevent move, use `ref _x` or `ref mut _x` - | cannot move out of borrowed content - -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-in-irrefut-pat.rs:11:11 - | -LL | with(|&_x| ()) - | ^-- - | || - | |hint: to prevent move, use `ref _x` or `ref mut _x` - | cannot move out of borrowed content - -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-in-irrefut-pat.rs:17:9 - | -LL | let &_x = &"hi".to_string(); - | ^-- - | || - | |hint: to prevent move, use `ref _x` or `ref mut _x` - | cannot move out of borrowed content - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.mir.stderr b/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.mir.stderr deleted file mode 100644 index c18fce9f4fd55..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.mir.stderr +++ /dev/null @@ -1,50 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-in-irrefut-pat.rs:6:13 - | -LL | fn arg_item(&_x: &String) {} - | ^-- - | || - | |data moved here - | cannot move out of borrowed content - | help: consider removing the `&`: `_x` - | -note: move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-in-irrefut-pat.rs:6:14 - | -LL | fn arg_item(&_x: &String) {} - | ^^ - -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-in-irrefut-pat.rs:11:11 - | -LL | with(|&_x| ()) - | ^-- - | || - | |data moved here - | cannot move out of borrowed content - | help: consider removing the `&`: `_x` - | -note: move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-in-irrefut-pat.rs:11:12 - | -LL | with(|&_x| ()) - | ^^ - -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-in-irrefut-pat.rs:17:15 - | -LL | let &_x = &"hi".to_string(); - | --- ^^^^^^^^^^^^^^^^^ cannot move out of borrowed content - | || - | |data moved here - | help: consider removing the `&`: `_x` - | -note: move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-in-irrefut-pat.rs:17:10 - | -LL | let &_x = &"hi".to_string(); - | ^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.rs b/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.rs index c63f4f60bef48..f4f402dd96ab6 100644 --- a/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.rs +++ b/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.rs @@ -1,22 +1,16 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - fn with(f: F) where F: FnOnce(&String) {} fn arg_item(&_x: &String) {} - //[ast]~^ ERROR cannot move out of borrowed content [E0507] - //[mir]~^^ ERROR [E0507] + //~^ ERROR [E0507] fn arg_closure() { with(|&_x| ()) - //[ast]~^ ERROR cannot move out of borrowed content [E0507] - //[mir]~^^ ERROR [E0507] + //~^ ERROR [E0507] } fn let_pat() { let &_x = &"hi".to_string(); - //[ast]~^ ERROR cannot move out of borrowed content [E0507] - //[mir]~^^ ERROR [E0507] + //~^ ERROR [E0507] } pub fn main() {} diff --git a/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.stderr b/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.stderr new file mode 100644 index 0000000000000..f0a490d359dc6 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.stderr @@ -0,0 +1,33 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-move-in-irrefut-pat.rs:3:13 + | +LL | fn arg_item(&_x: &String) {} + | ^-- + | || + | |data moved here + | |move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait + | help: consider removing the `&`: `_x` + +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-move-in-irrefut-pat.rs:7:11 + | +LL | with(|&_x| ()) + | ^-- + | || + | |data moved here + | |move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait + | help: consider removing the `&`: `_x` + +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-move-in-irrefut-pat.rs:12:15 + | +LL | let &_x = &"hi".to_string(); + | --- ^^^^^^^^^^^^^^^^^ + | || + | |data moved here + | |move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait + | help: consider removing the `&`: `_x` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.ast.nll.stderr b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.ast.nll.stderr deleted file mode 100644 index 0789926563ce7..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.ast.nll.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0382]: use of moved value: `t` - --> $DIR/borrowck-move-moved-value-into-closure.rs:14:12 - | -LL | let t: Box<_> = box 3; - | - move occurs because `t` has type `std::boxed::Box`, which does not implement the `Copy` trait -LL | -LL | call_f(move|| { *t + 1 }); - | ------ - variable moved due to use in closure - | | - | value moved into closure here -LL | call_f(move|| { *t + 1 }); //[ast]~ ERROR capture of moved value - | ^^^^^^ - use occurs due to use in closure - | | - | value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.ast.stderr b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.ast.stderr deleted file mode 100644 index 308dac8329294..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.ast.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: capture of moved value: `t` - --> $DIR/borrowck-move-moved-value-into-closure.rs:14:22 - | -LL | call_f(move|| { *t + 1 }); - | ------ value moved (into closure) here -LL | call_f(move|| { *t + 1 }); //[ast]~ ERROR capture of moved value - | ^ value captured here after move - | - = note: move occurs because `t` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.mir.stderr b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.mir.stderr deleted file mode 100644 index 0789926563ce7..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.mir.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0382]: use of moved value: `t` - --> $DIR/borrowck-move-moved-value-into-closure.rs:14:12 - | -LL | let t: Box<_> = box 3; - | - move occurs because `t` has type `std::boxed::Box`, which does not implement the `Copy` trait -LL | -LL | call_f(move|| { *t + 1 }); - | ------ - variable moved due to use in closure - | | - | value moved into closure here -LL | call_f(move|| { *t + 1 }); //[ast]~ ERROR capture of moved value - | ^^^^^^ - use occurs due to use in closure - | | - | value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.rs b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.rs index 271553370e3fb..233d0a733e316 100644 --- a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.rs +++ b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - #![feature(box_syntax)] fn call_f isize>(f: F) -> isize { @@ -11,6 +8,5 @@ fn main() { let t: Box<_> = box 3; call_f(move|| { *t + 1 }); - call_f(move|| { *t + 1 }); //[ast]~ ERROR capture of moved value - //[mir]~^ ERROR use of moved value + call_f(move|| { *t + 1 }); //~ ERROR use of moved value } diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr new file mode 100644 index 0000000000000..557e27aae502e --- /dev/null +++ b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr @@ -0,0 +1,18 @@ +error[E0382]: use of moved value: `t` + --> $DIR/borrowck-move-moved-value-into-closure.rs:11:12 + | +LL | let t: Box<_> = box 3; + | - move occurs because `t` has type `std::boxed::Box`, which does not implement the `Copy` trait +LL | +LL | call_f(move|| { *t + 1 }); + | ------ - variable moved due to use in closure + | | + | value moved into closure here +LL | call_f(move|| { *t + 1 }); + | ^^^^^^ - use occurs due to use in closure + | | + | value used here after move + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-move-mut-base-ptr.nll.stderr b/src/test/ui/borrowck/borrowck-move-mut-base-ptr.nll.stderr deleted file mode 100644 index ce6433d5a527f..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-mut-base-ptr.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0505]: cannot move out of `t0` because it is borrowed - --> $DIR/borrowck-move-mut-base-ptr.rs:10:14 - | -LL | let p: &isize = &*t0; // Freezes `*t0` - | ---- borrow of `*t0` occurs here -LL | let t1 = t0; //~ ERROR cannot move out of `t0` - | ^^ move out of `t0` occurs here -LL | *t1 = 22; -LL | p.use_ref(); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-move-mut-base-ptr.stderr b/src/test/ui/borrowck/borrowck-move-mut-base-ptr.stderr index 224bf0fded875..77f5b72e51c5d 100644 --- a/src/test/ui/borrowck/borrowck-move-mut-base-ptr.stderr +++ b/src/test/ui/borrowck/borrowck-move-mut-base-ptr.stderr @@ -1,10 +1,13 @@ error[E0505]: cannot move out of `t0` because it is borrowed - --> $DIR/borrowck-move-mut-base-ptr.rs:10:9 + --> $DIR/borrowck-move-mut-base-ptr.rs:10:14 | LL | let p: &isize = &*t0; // Freezes `*t0` - | --- borrow of `*t0` occurs here -LL | let t1 = t0; //~ ERROR cannot move out of `t0` - | ^^ move out of `t0` occurs here + | ---- borrow of `*t0` occurs here +LL | let t1 = t0; + | ^^ move out of `t0` occurs here +LL | *t1 = 22; +LL | p.use_ref(); + | - borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.ast.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.ast.stderr deleted file mode 100644 index f866ff9e9bae1..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-out-from-array.ast.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0382]: use of moved value: `a[..]` - --> $DIR/borrowck-move-out-from-array.rs:10:14 - | -LL | let [_, _x] = a; - | -- value moved here -LL | let [.., _y] = a; //[ast]~ ERROR [E0382] - | ^^ value used here after move - | - = note: move occurs because `a[..]` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `a[..]` - --> $DIR/borrowck-move-out-from-array.rs:17:10 - | -LL | let [_x, _] = a; - | -- value moved here -LL | let [_y..] = a; //[ast]~ ERROR [E0382] - | ^^ value used here after move - | - = note: move occurs because `a[..]` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.mir.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.mir.stderr deleted file mode 100644 index f866ff9e9bae1..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-out-from-array.mir.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0382]: use of moved value: `a[..]` - --> $DIR/borrowck-move-out-from-array.rs:10:14 - | -LL | let [_, _x] = a; - | -- value moved here -LL | let [.., _y] = a; //[ast]~ ERROR [E0382] - | ^^ value used here after move - | - = note: move occurs because `a[..]` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `a[..]` - --> $DIR/borrowck-move-out-from-array.rs:17:10 - | -LL | let [_x, _] = a; - | -- value moved here -LL | let [_y..] = a; //[ast]~ ERROR [E0382] - | ^^ value used here after move - | - = note: move occurs because `a[..]` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.rs b/src/test/ui/borrowck/borrowck-move-out-from-array.rs index 503e7b99525eb..856b03edd2d72 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array.rs +++ b/src/test/ui/borrowck/borrowck-move-out-from-array.rs @@ -1,21 +1,16 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - #![feature(box_syntax)] #![feature(slice_patterns)] fn move_out_from_begin_and_end() { let a = [box 1, box 2]; let [_, _x] = a; - let [.., _y] = a; //[ast]~ ERROR [E0382] - //[mir]~^ ERROR [E0382] + let [.., _y] = a; //~ ERROR [E0382] } fn move_out_by_const_index_and_subslice() { let a = [box 1, box 2]; let [_x, _] = a; - let [_y..] = a; //[ast]~ ERROR [E0382] - //[mir]~^ ERROR [E0382] + let [_y..] = a; //~ ERROR [E0382] } fn main() {} diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr new file mode 100644 index 0000000000000..16722a456defa --- /dev/null +++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr @@ -0,0 +1,23 @@ +error[E0382]: use of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array.rs:7:14 + | +LL | let [_, _x] = a; + | -- value moved here +LL | let [.., _y] = a; + | ^^ value used here after move + | + = note: move occurs because `a[..]` has type `std::boxed::Box`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array.rs:13:10 + | +LL | let [_x, _] = a; + | -- value moved here +LL | let [_y..] = a; + | ^^ value used here after move + | + = note: move occurs because `a[..]` has type `std::boxed::Box`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.ast.nll.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.ast.nll.stderr deleted file mode 100644 index 81afb104c9d4d..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.ast.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0507]: cannot move out of an `Rc` - --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:7:14 - | -LL | let _x = Rc::new(vec![1, 2]).into_iter(); - | ^^^^^^^^^^^^^^^^^^^ cannot move out of an `Rc` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.ast.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.ast.stderr deleted file mode 100644 index e55898aca5c06..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.ast.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:7:14 - | -LL | let _x = Rc::new(vec![1, 2]).into_iter(); - | ^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.mir.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.mir.stderr deleted file mode 100644 index 81afb104c9d4d..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.mir.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0507]: cannot move out of an `Rc` - --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:7:14 - | -LL | let _x = Rc::new(vec![1, 2]).into_iter(); - | ^^^^^^^^^^^^^^^^^^^ cannot move out of an `Rc` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs index 5ced89478dc9c..0b9e7102cd54f 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs +++ b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs @@ -1,10 +1,6 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - use std::rc::Rc; pub fn main() { let _x = Rc::new(vec![1, 2]).into_iter(); - //[ast]~^ ERROR cannot move out of borrowed content [E0507] - //[mir]~^^ ERROR [E0507] + //~^ ERROR [E0507] } diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr new file mode 100644 index 0000000000000..8a94c85ef27eb --- /dev/null +++ b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr @@ -0,0 +1,9 @@ +error[E0507]: cannot move out of an `Rc` + --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:4:14 + | +LL | let _x = Rc::new(vec![1, 2]).into_iter(); + | ^^^^^^^^^^^^^^^^^^^ move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.nll.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.nll.stderr deleted file mode 100644 index e6af992c4d95b..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0507]: cannot move out of an `Rc` - --> $DIR/borrowck-move-out-of-overloaded-deref.rs:4:14 - | -LL | let _x = *Rc::new("hi".to_string()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | cannot move out of an `Rc` - | help: consider removing the `*`: `Rc::new("hi".to_string())` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.rs b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.rs index d5b60139fa6b1..ecb135f68d5af 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.rs +++ b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.rs @@ -2,5 +2,5 @@ use std::rc::Rc; pub fn main() { let _x = *Rc::new("hi".to_string()); - //~^ ERROR cannot move out of borrowed content + //~^ ERROR cannot move out of an `Rc` } diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr index cd8d146ab1eaa..1501644fac758 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr @@ -1,11 +1,11 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of an `Rc` --> $DIR/borrowck-move-out-of-overloaded-deref.rs:4:14 | LL | let _x = *Rc::new("hi".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | cannot move out of borrowed content - | help: consider using a reference instead: `&*Rc::new("hi".to_string())` + | move occurs because value has type `std::string::String`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*Rc::new("hi".to_string())` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-out-of-static-item.ast.stderr b/src/test/ui/borrowck/borrowck-move-out-of-static-item.ast.stderr deleted file mode 100644 index 752d5330e0279..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-out-of-static-item.ast.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0507]: cannot move out of static item - --> $DIR/borrowck-move-out-of-static-item.rs:18:10 - | -LL | test(BAR); //[ast]~ ERROR cannot move out of static item [E0507] - | ^^^ cannot move out of static item - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-static-item.mir.stderr b/src/test/ui/borrowck/borrowck-move-out-of-static-item.mir.stderr deleted file mode 100644 index 752d5330e0279..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-out-of-static-item.mir.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0507]: cannot move out of static item - --> $DIR/borrowck-move-out-of-static-item.rs:18:10 - | -LL | test(BAR); //[ast]~ ERROR cannot move out of static item [E0507] - | ^^^ cannot move out of static item - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-static-item.rs b/src/test/ui/borrowck/borrowck-move-out-of-static-item.rs index d68d5de5c014b..d01fb261894c8 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-static-item.rs +++ b/src/test/ui/borrowck/borrowck-move-out-of-static-item.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - // Ensure that moves out of static items is forbidden struct Foo { @@ -15,6 +12,5 @@ fn test(f: Foo) { } fn main() { - test(BAR); //[ast]~ ERROR cannot move out of static item [E0507] - //[mir]~^ ERROR [E0507] + test(BAR); //~ ERROR cannot move out of static item `BAR` [E0507] } diff --git a/src/test/ui/borrowck/borrowck-move-out-of-static-item.stderr b/src/test/ui/borrowck/borrowck-move-out-of-static-item.stderr new file mode 100644 index 0000000000000..edf8c954f816b --- /dev/null +++ b/src/test/ui/borrowck/borrowck-move-out-of-static-item.stderr @@ -0,0 +1,9 @@ +error[E0507]: cannot move out of static item `BAR` + --> $DIR/borrowck-move-out-of-static-item.rs:15:10 + | +LL | test(BAR); + | ^^^ move occurs because `BAR` has type `Foo`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.ast.nll.stderr b/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.ast.nll.stderr deleted file mode 100644 index 7025ce08fedf6..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.ast.nll.stderr +++ /dev/null @@ -1,47 +0,0 @@ -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:10:11 - | -LL | match (S {f:"foo".to_string()}) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here -LL | //[mir]~^ ERROR [E0509] -LL | S {f:_s} => {} - | -- data moved here - | -note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:12:14 - | -LL | S {f:_s} => {} - | ^^ - -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:18:20 - | -LL | let S {f:_s} = S {f:"foo".to_string()}; - | -- ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here - | | - | data moved here - | -note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:18:14 - | -LL | let S {f:_s} = S {f:"foo".to_string()}; - | ^^ - -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:23:19 - | -LL | fn move_in_fn_arg(S {f:_s}: S) { - | ^^^^^--^ - | | | - | | data moved here - | cannot move out of here - | -note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:23:24 - | -LL | fn move_in_fn_arg(S {f:_s}: S) { - | ^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.ast.stderr b/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.ast.stderr deleted file mode 100644 index 0b025fa175a5f..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.ast.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:12:9 - | -LL | S {f:_s} => {} - | ^^^^^--^ - | | | - | | hint: to prevent move, use `ref _s` or `ref mut _s` - | cannot move out of here - -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:18:9 - | -LL | let S {f:_s} = S {f:"foo".to_string()}; - | ^^^^^--^ - | | | - | | hint: to prevent move, use `ref _s` or `ref mut _s` - | cannot move out of here - -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:23:19 - | -LL | fn move_in_fn_arg(S {f:_s}: S) { - | ^^^^^--^ - | | | - | | hint: to prevent move, use `ref _s` or `ref mut _s` - | cannot move out of here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.mir.stderr b/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.mir.stderr deleted file mode 100644 index 7025ce08fedf6..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.mir.stderr +++ /dev/null @@ -1,47 +0,0 @@ -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:10:11 - | -LL | match (S {f:"foo".to_string()}) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here -LL | //[mir]~^ ERROR [E0509] -LL | S {f:_s} => {} - | -- data moved here - | -note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:12:14 - | -LL | S {f:_s} => {} - | ^^ - -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:18:20 - | -LL | let S {f:_s} = S {f:"foo".to_string()}; - | -- ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here - | | - | data moved here - | -note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:18:14 - | -LL | let S {f:_s} = S {f:"foo".to_string()}; - | ^^ - -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:23:19 - | -LL | fn move_in_fn_arg(S {f:_s}: S) { - | ^^^^^--^ - | | | - | | data moved here - | cannot move out of here - | -note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:23:24 - | -LL | fn move_in_fn_arg(S {f:_s}: S) { - | ^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.rs b/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.rs index cdd71d889ab2f..a429f4bc33b06 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.rs +++ b/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - struct S {f:String} impl Drop for S { fn drop(&mut self) { println!("{}", self.f); } @@ -8,21 +5,18 @@ impl Drop for S { fn move_in_match() { match (S {f:"foo".to_string()}) { - //[mir]~^ ERROR [E0509] + //~^ ERROR [E0509] S {f:_s} => {} - //[ast]~^ ERROR cannot move out of type `S`, which implements the `Drop` trait [E0509] } } fn move_in_let() { let S {f:_s} = S {f:"foo".to_string()}; - //[ast]~^ ERROR cannot move out of type `S`, which implements the `Drop` trait [E0509] - //[mir]~^^ ERROR [E0509] + //~^ ERROR [E0509] } fn move_in_fn_arg(S {f:_s}: S) { - //[ast]~^ ERROR cannot move out of type `S`, which implements the `Drop` trait [E0509] - //[mir]~^^ ERROR [E0509] + //~^ ERROR [E0509] } fn main() {} diff --git a/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr b/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr new file mode 100644 index 0000000000000..a2f66f3ec465d --- /dev/null +++ b/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr @@ -0,0 +1,34 @@ +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:7:11 + | +LL | match (S {f:"foo".to_string()}) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here +LL | +LL | S {f:_s} => {} + | -- + | | + | data moved here + | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:14:20 + | +LL | let S {f:_s} = S {f:"foo".to_string()}; + | -- ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here + | | + | data moved here + | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:18:19 + | +LL | fn move_in_fn_arg(S {f:_s}: S) { + | ^^^^^--^ + | | | + | | data moved here + | | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + | cannot move out of here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.nll.stderr b/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.nll.stderr deleted file mode 100644 index cecba15acce96..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.nll.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:7:11 - | -LL | match S("foo".to_string()) { - | ^^^^^^^^^^^^^^^^^^^^ cannot move out of here -LL | S(_s) => {} - | -- data moved here - | -note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:8:11 - | -LL | S(_s) => {} - | ^^ - -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:14:17 - | -LL | let S(_s) = S("foo".to_string()); - | -- ^^^^^^^^^^^^^^^^^^^^ cannot move out of here - | | - | data moved here - | -note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:14:11 - | -LL | let S(_s) = S("foo".to_string()); - | ^^ - -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:18:19 - | -LL | fn move_in_fn_arg(S(_s): S) { - | ^^--^ - | | | - | | data moved here - | cannot move out of here - | -note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:18:21 - | -LL | fn move_in_fn_arg(S(_s): S) { - | ^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs b/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs index bb294111add7e..5bd32f82ebc44 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs +++ b/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs @@ -5,8 +5,8 @@ impl Drop for S { fn move_in_match() { match S("foo".to_string()) { - S(_s) => {} //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait + S(_s) => {} } } diff --git a/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr b/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr index 134b5e3481efd..f9a539c1c9fd1 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr @@ -1,20 +1,23 @@ error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:8:9 + --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:7:11 | +LL | match S("foo".to_string()) { + | ^^^^^^^^^^^^^^^^^^^^ cannot move out of here +LL | LL | S(_s) => {} - | ^^--^ - | | | - | | hint: to prevent move, use `ref _s` or `ref mut _s` - | cannot move out of here + | -- + | | + | data moved here + | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:14:9 + --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:14:17 | LL | let S(_s) = S("foo".to_string()); - | ^^--^ - | | | - | | hint: to prevent move, use `ref _s` or `ref mut _s` - | cannot move out of here + | -- ^^^^^^^^^^^^^^^^^^^^ cannot move out of here + | | + | data moved here + | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `S`, which implements the `Drop` trait --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:18:19 @@ -22,7 +25,8 @@ error[E0509]: cannot move out of type `S`, which implements the `Drop` trait LL | fn move_in_fn_arg(S(_s): S) { | ^^--^ | | | - | | hint: to prevent move, use `ref _s` or `ref mut _s` + | | data moved here + | | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait | cannot move out of here error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr b/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr deleted file mode 100644 index 9aaeefd4cfc32..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0508]: cannot move out of type `[Foo]`, a non-copy slice - --> $DIR/borrowck-move-out-of-vec-tail.rs:19:19 - | -LL | match tail { - | ^^^^ cannot move out of here -LL | &[Foo { string: a }, - | - data moved here -... -LL | Foo { string: b }] => { - | - ...and here - | -note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/borrowck-move-out-of-vec-tail.rs:20:33 - | -LL | &[Foo { string: a }, - | ^ -... -LL | Foo { string: b }] => { - | ^ -help: consider removing the `&` - | -LL | [Foo { string: a }, -LL | //~^ ERROR cannot move out of type `[Foo]` -LL | //~| cannot move out -LL | //~| to prevent move -LL | Foo { string: b }] => { - | - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.rs b/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.rs index 5f6e01f2df0ff..cc524c1ac3e6e 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.rs +++ b/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.rs @@ -17,10 +17,8 @@ pub fn main() { match *x { [_, ref tail..] => { match tail { + //~^ ERROR cannot move out of type `[Foo]` &[Foo { string: a }, - //~^ ERROR cannot move out of type `[Foo]` - //~| cannot move out - //~| to prevent move Foo { string: b }] => { } _ => { diff --git a/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.stderr b/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.stderr index 156ba0d4d7bb2..9f0670c6bc72d 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.stderr @@ -1,17 +1,26 @@ error[E0508]: cannot move out of type `[Foo]`, a non-copy slice - --> $DIR/borrowck-move-out-of-vec-tail.rs:20:18 + --> $DIR/borrowck-move-out-of-vec-tail.rs:19:19 + | +LL | match tail { + | ^^^^ cannot move out of here +LL | +LL | &[Foo { string: a }, + | - data moved here +LL | Foo { string: b }] => { + | - ...and here + | +note: move occurs because these variables have types that don't implement the `Copy` trait + --> $DIR/borrowck-move-out-of-vec-tail.rs:21:33 + | +LL | &[Foo { string: a }, + | ^ +LL | Foo { string: b }] => { + | ^ +help: consider removing the `&` + | +LL | [Foo { string: a }, +LL | Foo { string: b }] => { | -LL | &[Foo { string: a }, - | ^ - hint: to prevent move, use `ref a` or `ref mut a` - | __________________| - | | -LL | | //~^ ERROR cannot move out of type `[Foo]` -LL | | //~| cannot move out -LL | | //~| to prevent move -LL | | Foo { string: b }] => { - | |_________________________________-__^ cannot move out of here - | | - | ...and here (use `ref b` or `ref mut b`) error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-subcomponent.nll.stderr b/src/test/ui/borrowck/borrowck-move-subcomponent.nll.stderr deleted file mode 100644 index 3bb5351f97ba3..0000000000000 --- a/src/test/ui/borrowck/borrowck-move-subcomponent.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0505]: cannot move out of `a.x` because it is borrowed - --> $DIR/borrowck-move-subcomponent.rs:15:14 - | -LL | let pb = &a; - | -- borrow of `a` occurs here -LL | let S { x: ax } = a; //~ ERROR cannot move out - | ^^ move out of `a.x` occurs here -LL | f(pb); - | -- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-move-subcomponent.stderr b/src/test/ui/borrowck/borrowck-move-subcomponent.stderr index 187cdbbf81565..8c9083fcf1356 100644 --- a/src/test/ui/borrowck/borrowck-move-subcomponent.stderr +++ b/src/test/ui/borrowck/borrowck-move-subcomponent.stderr @@ -2,9 +2,11 @@ error[E0505]: cannot move out of `a.x` because it is borrowed --> $DIR/borrowck-move-subcomponent.rs:15:14 | LL | let pb = &a; - | - borrow of `a` occurs here -LL | let S { x: ax } = a; //~ ERROR cannot move out + | -- borrow of `a` occurs here +LL | let S { x: ax } = a; | ^^ move out of `a.x` occurs here +LL | f(pb); + | -- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr b/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr deleted file mode 100644 index d0065a2e7dc3d..0000000000000 --- a/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr +++ /dev/null @@ -1,103 +0,0 @@ -error[E0505]: cannot move out of `x1` because it is borrowed - --> $DIR/borrowck-multiple-captures.rs:12:19 - | -LL | let p1 = &x1; - | --- borrow of `x1` occurs here -... -LL | thread::spawn(move|| { - | ^^^^^^ move out of `x1` occurs here -LL | drop(x1); //~ ERROR cannot move `x1` into closure because it is borrowed - | -- move occurs due to use in closure -... -LL | borrow(&*p1); - | ---- borrow later used here - -error[E0505]: cannot move out of `x2` because it is borrowed - --> $DIR/borrowck-multiple-captures.rs:12:19 - | -LL | let p2 = &x2; - | --- borrow of `x2` occurs here -LL | thread::spawn(move|| { - | ^^^^^^ move out of `x2` occurs here -LL | drop(x1); //~ ERROR cannot move `x1` into closure because it is borrowed -LL | drop(x2); //~ ERROR cannot move `x2` into closure because it is borrowed - | -- move occurs due to use in closure -... -LL | borrow(&*p2); - | ---- borrow later used here - -error[E0382]: use of moved value: `x1` - --> $DIR/borrowck-multiple-captures.rs:25:19 - | -LL | let x1: Box<_> = box 1; - | -- move occurs because `x1` has type `std::boxed::Box`, which does not implement the `Copy` trait -LL | drop(x1); - | -- value moved here -... -LL | thread::spawn(move|| { - | ^^^^^^ value used here after move -LL | drop(x1); //~ ERROR capture of moved value: `x1` - | -- use occurs due to use in closure - -error[E0382]: use of moved value: `x2` - --> $DIR/borrowck-multiple-captures.rs:25:19 - | -LL | let x2: Box<_> = box 2; - | -- move occurs because `x2` has type `std::boxed::Box`, which does not implement the `Copy` trait -LL | drop(x2); - | -- value moved here -LL | thread::spawn(move|| { - | ^^^^^^ value used here after move -LL | drop(x1); //~ ERROR capture of moved value: `x1` -LL | drop(x2); //~ ERROR capture of moved value: `x2` - | -- use occurs due to use in closure - -error[E0382]: use of moved value: `x` - --> $DIR/borrowck-multiple-captures.rs:36:14 - | -LL | drop(x); //~ ERROR cannot move `x` into closure because it is borrowed - | - value moved here -LL | drop(x); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/borrowck-multiple-captures.rs:34:19 - | -LL | let p = &x; - | -- borrow of `x` occurs here -LL | thread::spawn(move|| { - | ^^^^^^ move out of `x` occurs here -LL | drop(x); //~ ERROR cannot move `x` into closure because it is borrowed - | - move occurs due to use in closure -... -LL | borrow(&*p); - | --- borrow later used here - -error[E0382]: use of moved value: `x` - --> $DIR/borrowck-multiple-captures.rs:46:14 - | -LL | drop(x); //~ ERROR capture of moved value: `x` - | - value moved here -LL | drop(x); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `x` - --> $DIR/borrowck-multiple-captures.rs:44:19 - | -LL | let x: Box<_> = box 1; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait -LL | drop(x); - | - value moved here -LL | thread::spawn(move|| { - | ^^^^^^ value used here after move -LL | drop(x); //~ ERROR capture of moved value: `x` - | - use occurs due to use in closure - -error: aborting due to 8 previous errors - -Some errors occurred: E0382, E0505. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.rs b/src/test/ui/borrowck/borrowck-multiple-captures.rs index ad753781cd60f..9f09f8442c044 100644 --- a/src/test/ui/borrowck/borrowck-multiple-captures.rs +++ b/src/test/ui/borrowck/borrowck-multiple-captures.rs @@ -10,8 +10,10 @@ fn different_vars_after_borrows() { let x2: Box<_> = box 2; let p2 = &x2; thread::spawn(move|| { - drop(x1); //~ ERROR cannot move `x1` into closure because it is borrowed - drop(x2); //~ ERROR cannot move `x2` into closure because it is borrowed + //~^ ERROR cannot move out of `x1` because it is borrowed + //~| ERROR cannot move out of `x2` because it is borrowed + drop(x1); + drop(x2); }); borrow(&*p1); borrow(&*p2); @@ -23,8 +25,10 @@ fn different_vars_after_moves() { let x2: Box<_> = box 2; drop(x2); thread::spawn(move|| { - drop(x1); //~ ERROR capture of moved value: `x1` - drop(x2); //~ ERROR capture of moved value: `x2` + //~^ ERROR use of moved value: `x1` + //~| ERROR use of moved value: `x2` + drop(x1); + drop(x2); }); } @@ -32,7 +36,8 @@ fn same_var_after_borrow() { let x: Box<_> = box 1; let p = &x; thread::spawn(move|| { - drop(x); //~ ERROR cannot move `x` into closure because it is borrowed + //~^ ERROR cannot move out of `x` because it is borrowed + drop(x); drop(x); //~ ERROR use of moved value: `x` }); borrow(&*p); @@ -42,7 +47,8 @@ fn same_var_after_move() { let x: Box<_> = box 1; drop(x); thread::spawn(move|| { - drop(x); //~ ERROR capture of moved value: `x` + //~^ ERROR use of moved value: `x` + drop(x); drop(x); //~ ERROR use of moved value: `x` }); } diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.stderr b/src/test/ui/borrowck/borrowck-multiple-captures.stderr index 3cdd094260833..298482b3c581f 100644 --- a/src/test/ui/borrowck/borrowck-multiple-captures.stderr +++ b/src/test/ui/borrowck/borrowck-multiple-captures.stderr @@ -1,84 +1,107 @@ -error[E0504]: cannot move `x1` into closure because it is borrowed - --> $DIR/borrowck-multiple-captures.rs:13:14 +error[E0505]: cannot move out of `x1` because it is borrowed + --> $DIR/borrowck-multiple-captures.rs:12:19 | LL | let p1 = &x1; - | -- borrow of `x1` occurs here + | --- borrow of `x1` occurs here ... -LL | drop(x1); //~ ERROR cannot move `x1` into closure because it is borrowed - | ^^ move into closure occurs here +LL | thread::spawn(move|| { + | ^^^^^^ move out of `x1` occurs here +... +LL | drop(x1); + | -- move occurs due to use in closure +... +LL | borrow(&*p1); + | ---- borrow later used here -error[E0504]: cannot move `x2` into closure because it is borrowed - --> $DIR/borrowck-multiple-captures.rs:14:14 +error[E0505]: cannot move out of `x2` because it is borrowed + --> $DIR/borrowck-multiple-captures.rs:12:19 | LL | let p2 = &x2; - | -- borrow of `x2` occurs here + | --- borrow of `x2` occurs here +LL | thread::spawn(move|| { + | ^^^^^^ move out of `x2` occurs here ... -LL | drop(x2); //~ ERROR cannot move `x2` into closure because it is borrowed - | ^^ move into closure occurs here +LL | drop(x2); + | -- move occurs due to use in closure +... +LL | borrow(&*p2); + | ---- borrow later used here -error[E0382]: capture of moved value: `x1` - --> $DIR/borrowck-multiple-captures.rs:26:14 +error[E0382]: use of moved value: `x1` + --> $DIR/borrowck-multiple-captures.rs:27:19 | +LL | let x1: Box<_> = box 1; + | -- move occurs because `x1` has type `std::boxed::Box`, which does not implement the `Copy` trait LL | drop(x1); | -- value moved here ... -LL | drop(x1); //~ ERROR capture of moved value: `x1` - | ^^ value captured here after move - | - = note: move occurs because `x1` has type `std::boxed::Box`, which does not implement the `Copy` trait +LL | thread::spawn(move|| { + | ^^^^^^ value used here after move +... +LL | drop(x1); + | -- use occurs due to use in closure -error[E0382]: capture of moved value: `x2` - --> $DIR/borrowck-multiple-captures.rs:27:14 +error[E0382]: use of moved value: `x2` + --> $DIR/borrowck-multiple-captures.rs:27:19 | +LL | let x2: Box<_> = box 2; + | -- move occurs because `x2` has type `std::boxed::Box`, which does not implement the `Copy` trait LL | drop(x2); | -- value moved here -... -LL | drop(x2); //~ ERROR capture of moved value: `x2` - | ^^ value captured here after move - | - = note: move occurs because `x2` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0504]: cannot move `x` into closure because it is borrowed - --> $DIR/borrowck-multiple-captures.rs:35:14 - | -LL | let p = &x; - | - borrow of `x` occurs here LL | thread::spawn(move|| { -LL | drop(x); //~ ERROR cannot move `x` into closure because it is borrowed - | ^ move into closure occurs here + | ^^^^^^ value used here after move +... +LL | drop(x2); + | -- use occurs due to use in closure error[E0382]: use of moved value: `x` - --> $DIR/borrowck-multiple-captures.rs:36:14 + --> $DIR/borrowck-multiple-captures.rs:41:14 | -LL | drop(x); //~ ERROR cannot move `x` into closure because it is borrowed +LL | drop(x); | - value moved here -LL | drop(x); //~ ERROR use of moved value: `x` +LL | drop(x); | ^ value used here after move | = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait -error[E0382]: capture of moved value: `x` - --> $DIR/borrowck-multiple-captures.rs:45:14 +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/borrowck-multiple-captures.rs:38:19 | -LL | drop(x); - | - value moved here +LL | let p = &x; + | -- borrow of `x` occurs here LL | thread::spawn(move|| { -LL | drop(x); //~ ERROR capture of moved value: `x` - | ^ value captured here after move - | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^^^^^^ move out of `x` occurs here +LL | +LL | drop(x); + | - move occurs due to use in closure +... +LL | borrow(&*p); + | --- borrow later used here error[E0382]: use of moved value: `x` - --> $DIR/borrowck-multiple-captures.rs:46:14 + --> $DIR/borrowck-multiple-captures.rs:52:14 | -LL | drop(x); //~ ERROR capture of moved value: `x` +LL | drop(x); | - value moved here -LL | drop(x); //~ ERROR use of moved value: `x` +LL | drop(x); | ^ value used here after move | = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait +error[E0382]: use of moved value: `x` + --> $DIR/borrowck-multiple-captures.rs:49:19 + | +LL | let x: Box<_> = box 1; + | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait +LL | drop(x); + | - value moved here +LL | thread::spawn(move|| { + | ^^^^^^ value used here after move +LL | +LL | drop(x); + | - use occurs due to use in closure + error: aborting due to 8 previous errors -Some errors occurred: E0382, E0504. +Some errors have detailed explanations: E0382, E0505. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-mut-addr-of-imm-var.nll.stderr b/src/test/ui/borrowck/borrowck-mut-addr-of-imm-var.nll.stderr deleted file mode 100644 index be69be6341172..0000000000000 --- a/src/test/ui/borrowck/borrowck-mut-addr-of-imm-var.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/borrowck-mut-addr-of-imm-var.rs:3:25 - | -LL | let x: isize = 3; - | - help: consider changing this to be mutable: `mut x` -LL | let y: &mut isize = &mut x; //~ ERROR cannot borrow - | ^^^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/borrowck-mut-addr-of-imm-var.stderr b/src/test/ui/borrowck/borrowck-mut-addr-of-imm-var.stderr index 95635f7f67031..d58548f22049a 100644 --- a/src/test/ui/borrowck/borrowck-mut-addr-of-imm-var.stderr +++ b/src/test/ui/borrowck/borrowck-mut-addr-of-imm-var.stderr @@ -1,10 +1,10 @@ -error[E0596]: cannot borrow immutable local variable `x` as mutable - --> $DIR/borrowck-mut-addr-of-imm-var.rs:3:30 +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/borrowck-mut-addr-of-imm-var.rs:3:25 | LL | let x: isize = 3; - | - help: make this binding mutable: `mut x` -LL | let y: &mut isize = &mut x; //~ ERROR cannot borrow - | ^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut x` +LL | let y: &mut isize = &mut x; + | ^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.ast.nll.stderr b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.ast.nll.stderr deleted file mode 100644 index 0f07776533608..0000000000000 --- a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.ast.nll.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-mut-borrow-linear-errors.rs:13:30 - | -LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ---- ^^^^^^ second mutable borrow occurs here - | | - | first borrow later used here -... -LL | _ => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ------ first mutable borrow occurs here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-mut-borrow-linear-errors.rs:15:30 - | -LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ---- first borrow later used here -LL | //[mir]~^ ERROR [E0499] -LL | 2 => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ^^^^^^ second mutable borrow occurs here -LL | //[mir]~^ ERROR [E0499] -LL | _ => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ------ first mutable borrow occurs here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-mut-borrow-linear-errors.rs:17:30 - | -LL | _ => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ^^^^^^ mutable borrow starts here in previous iteration of loop - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.ast.stderr b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.ast.stderr deleted file mode 100644 index dafb60c959afd..0000000000000 --- a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.ast.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-mut-borrow-linear-errors.rs:13:35 - | -LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ^ mutable borrow starts here in previous iteration of loop -... -LL | } - | - mutable borrow ends here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-mut-borrow-linear-errors.rs:15:35 - | -LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | - first mutable borrow occurs here -LL | //[mir]~^ ERROR [E0499] -LL | 2 => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-mut-borrow-linear-errors.rs:17:35 - | -LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | - first mutable borrow occurs here -... -LL | _ => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.mir.stderr b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.mir.stderr deleted file mode 100644 index 0f07776533608..0000000000000 --- a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.mir.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-mut-borrow-linear-errors.rs:13:30 - | -LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ---- ^^^^^^ second mutable borrow occurs here - | | - | first borrow later used here -... -LL | _ => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ------ first mutable borrow occurs here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-mut-borrow-linear-errors.rs:15:30 - | -LL | 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ---- first borrow later used here -LL | //[mir]~^ ERROR [E0499] -LL | 2 => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ^^^^^^ second mutable borrow occurs here -LL | //[mir]~^ ERROR [E0499] -LL | _ => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ------ first mutable borrow occurs here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-mut-borrow-linear-errors.rs:17:30 - | -LL | _ => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - | ^^^^^^ mutable borrow starts here in previous iteration of loop - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.rs b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.rs index bb0b26ecf0663..e3d76398bc26f 100644 --- a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.rs +++ b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.rs @@ -2,20 +2,14 @@ // conflicts with a new loan, as opposed to every issued loan. This keeps us // down to O(n) errors (for n problem lines), instead of O(n^2) errors. -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - fn main() { let mut x = 1; let mut addr = vec![]; loop { match 1 { - 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - //[mir]~^ ERROR [E0499] - 2 => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - //[mir]~^ ERROR [E0499] - _ => { addr.push(&mut x); } //[ast]~ ERROR [E0499] - //[mir]~^ ERROR [E0499] + 1 => { addr.push(&mut x); } //~ ERROR [E0499] + 2 => { addr.push(&mut x); } //~ ERROR [E0499] + _ => { addr.push(&mut x); } //~ ERROR [E0499] } } } diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr new file mode 100644 index 0000000000000..ca1496a6c8d9b --- /dev/null +++ b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr @@ -0,0 +1,30 @@ +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-mut-borrow-linear-errors.rs:10:30 + | +LL | 1 => { addr.push(&mut x); } + | ^^^^^^ second mutable borrow occurs here +LL | 2 => { addr.push(&mut x); } +LL | _ => { addr.push(&mut x); } + | ---- ------ first mutable borrow occurs here + | | + | first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-mut-borrow-linear-errors.rs:11:30 + | +LL | 2 => { addr.push(&mut x); } + | ^^^^^^ second mutable borrow occurs here +LL | _ => { addr.push(&mut x); } + | ---- ------ first mutable borrow occurs here + | | + | first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-mut-borrow-linear-errors.rs:12:30 + | +LL | _ => { addr.push(&mut x); } + | ^^^^^^ mutable borrow starts here in previous iteration of loop + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.nll.stderr b/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.nll.stderr deleted file mode 100644 index 666ccf35a7c9b..0000000000000 --- a/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.nll.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0502]: cannot borrow `t0` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-mut-borrow-of-mut-base-ptr.rs:11:18 - | -LL | let p: &isize = &*t0; // Freezes `*t0` - | ---- immutable borrow occurs here -LL | let mut t2 = &mut t0; //~ ERROR cannot borrow `t0` - | ^^^^^^^ mutable borrow occurs here -LL | **t2 += 1; // Mutates `*t0` -LL | p.use_ref(); - | - immutable borrow later used here - -error[E0499]: cannot borrow `t0` as mutable more than once at a time - --> $DIR/borrowck-mut-borrow-of-mut-base-ptr.rs:19:18 - | -LL | let p: &mut isize = &mut *t0; // Claims `*t0` - | -------- first mutable borrow occurs here -LL | let mut t2 = &mut t0; //~ ERROR cannot borrow `t0` - | ^^^^^^^ second mutable borrow occurs here -LL | **t2 += 1; // Mutates `*t0` but not through `*p` -LL | p.use_mut(); - | - first borrow later used here - -error: aborting due to 2 previous errors - -Some errors occurred: E0499, E0502. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr b/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr index 154a283b43b5b..f2baee09376e2 100644 --- a/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr +++ b/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr @@ -1,26 +1,26 @@ -error[E0502]: cannot borrow `t0` as mutable because `*t0` is also borrowed as immutable - --> $DIR/borrowck-mut-borrow-of-mut-base-ptr.rs:11:23 +error[E0502]: cannot borrow `t0` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-mut-borrow-of-mut-base-ptr.rs:11:18 | LL | let p: &isize = &*t0; // Freezes `*t0` - | --- immutable borrow occurs here -LL | let mut t2 = &mut t0; //~ ERROR cannot borrow `t0` - | ^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here + | ---- immutable borrow occurs here +LL | let mut t2 = &mut t0; + | ^^^^^^^ mutable borrow occurs here +LL | **t2 += 1; // Mutates `*t0` +LL | p.use_ref(); + | - immutable borrow later used here error[E0499]: cannot borrow `t0` as mutable more than once at a time - --> $DIR/borrowck-mut-borrow-of-mut-base-ptr.rs:19:23 + --> $DIR/borrowck-mut-borrow-of-mut-base-ptr.rs:19:18 | LL | let p: &mut isize = &mut *t0; // Claims `*t0` - | --- first mutable borrow occurs here -LL | let mut t2 = &mut t0; //~ ERROR cannot borrow `t0` - | ^^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here + | -------- first mutable borrow occurs here +LL | let mut t2 = &mut t0; + | ^^^^^^^ second mutable borrow occurs here +LL | **t2 += 1; // Mutates `*t0` but not through `*p` +LL | p.use_mut(); + | - first borrow later used here error: aborting due to 2 previous errors -Some errors occurred: E0499, E0502. +Some errors have detailed explanations: E0499, E0502. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-mut-slice-of-imm-vec.nll.stderr b/src/test/ui/borrowck/borrowck-mut-slice-of-imm-vec.nll.stderr deleted file mode 100644 index 5a9ec98a2db06..0000000000000 --- a/src/test/ui/borrowck/borrowck-mut-slice-of-imm-vec.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable - --> $DIR/borrowck-mut-slice-of-imm-vec.rs:7:11 - | -LL | let v = vec![1, 2, 3]; - | - help: consider changing this to be mutable: `mut v` -LL | write(&mut v); //~ ERROR cannot borrow - | ^^^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/borrowck-mut-slice-of-imm-vec.stderr b/src/test/ui/borrowck/borrowck-mut-slice-of-imm-vec.stderr index 41ee2adf8aa0c..8e7ffdc6819a5 100644 --- a/src/test/ui/borrowck/borrowck-mut-slice-of-imm-vec.stderr +++ b/src/test/ui/borrowck/borrowck-mut-slice-of-imm-vec.stderr @@ -1,10 +1,10 @@ -error[E0596]: cannot borrow immutable local variable `v` as mutable - --> $DIR/borrowck-mut-slice-of-imm-vec.rs:7:16 +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/borrowck-mut-slice-of-imm-vec.rs:7:11 | LL | let v = vec![1, 2, 3]; - | - help: make this binding mutable: `mut v` -LL | write(&mut v); //~ ERROR cannot borrow - | ^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut v` +LL | write(&mut v); + | ^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.nll.stderr b/src/test/ui/borrowck/borrowck-mutate-in-guard.nll.stderr index c1b794fc86e3b..7e4a6322d5f5c 100644 --- a/src/test/ui/borrowck/borrowck-mutate-in-guard.nll.stderr +++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.nll.stderr @@ -5,7 +5,7 @@ LL | Enum::A(_) if { x = Enum::B(false); false } => 1, | ^^^^^^^^^^^^^^^^^^ assignment in pattern guard error[E0301]: cannot mutably borrow in a pattern guard - --> $DIR/borrowck-mutate-in-guard.rs:12:38 + --> $DIR/borrowck-mutate-in-guard.rs:15:38 | LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, | ^ borrowed mutably in pattern guard @@ -13,12 +13,29 @@ LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable error[E0302]: cannot assign in a pattern guard - --> $DIR/borrowck-mutate-in-guard.rs:12:41 + --> $DIR/borrowck-mutate-in-guard.rs:15:41 | LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, | ^^^^^^^^^^^^^^^^^^^ assignment in pattern guard -error: aborting due to 3 previous errors +error[E0510]: cannot assign `x` in match guard + --> $DIR/borrowck-mutate-in-guard.rs:10:25 + | +LL | match x { + | - value is immutable in match guard +LL | Enum::A(_) if { x = Enum::B(false); false } => 1, + | ^^^^^^^^^^^^^^^^^^ cannot assign + +error[E0510]: cannot mutably borrow `x` in match guard + --> $DIR/borrowck-mutate-in-guard.rs:15:33 + | +LL | match x { + | - value is immutable in match guard +... +LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, + | ^^^^^^ cannot mutably borrow + +error: aborting due to 5 previous errors -Some errors occurred: E0301, E0302. +Some errors have detailed explanations: E0301, E0302, E0510. For more information about an error, try `rustc --explain E0301`. diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.rs b/src/test/ui/borrowck/borrowck-mutate-in-guard.rs index 2bda3deee1596..9ea5e5cd145a0 100644 --- a/src/test/ui/borrowck/borrowck-mutate-in-guard.rs +++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.rs @@ -9,9 +9,15 @@ fn foo() -> isize { match x { Enum::A(_) if { x = Enum::B(false); false } => 1, //~^ ERROR cannot assign in a pattern guard + //~| WARN cannot assign `x` in match guard + //~| WARN this error has been downgraded to a warning for backwards compatibility + //~| WARN this represents potential undefined behavior in your code and this warning will Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, //~^ ERROR cannot mutably borrow in a pattern guard - //~^^ ERROR cannot assign in a pattern guard + //~| ERROR cannot assign in a pattern guard + //~| WARN cannot mutably borrow `x` in match guard + //~| WARN this error has been downgraded to a warning for backwards compatibility + //~| WARN this represents potential undefined behavior in your code and this warning will Enum::A(p) => *p, Enum::B(_) => 2, } diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr b/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr index 9e40856deb031..ac6bed6137fa3 100644 --- a/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr +++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr @@ -5,18 +5,45 @@ LL | Enum::A(_) if { x = Enum::B(false); false } => 1, | ^^^^^^^^^^^^^^^^^^ assignment in pattern guard error[E0301]: cannot mutably borrow in a pattern guard - --> $DIR/borrowck-mutate-in-guard.rs:12:38 + --> $DIR/borrowck-mutate-in-guard.rs:15:38 | LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, | ^ borrowed mutably in pattern guard + | + = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable error[E0302]: cannot assign in a pattern guard - --> $DIR/borrowck-mutate-in-guard.rs:12:41 + --> $DIR/borrowck-mutate-in-guard.rs:15:41 | LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, | ^^^^^^^^^^^^^^^^^^^ assignment in pattern guard +warning[E0510]: cannot assign `x` in match guard + --> $DIR/borrowck-mutate-in-guard.rs:10:25 + | +LL | match x { + | - value is immutable in match guard +LL | Enum::A(_) if { x = Enum::B(false); false } => 1, + | ^^^^^^^^^^^^^^^^^^ cannot assign + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + +warning[E0510]: cannot mutably borrow `x` in match guard + --> $DIR/borrowck-mutate-in-guard.rs:15:33 + | +LL | match x { + | - value is immutable in match guard +... +LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, + | ^^^^^^ cannot mutably borrow + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + error: aborting due to 3 previous errors -Some errors occurred: E0301, E0302. +Some errors have detailed explanations: E0301, E0302, E0510. For more information about an error, try `rustc --explain E0301`. diff --git a/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.nll.stderr b/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.nll.stderr deleted file mode 100644 index b106708352ef6..0000000000000 --- a/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/borrowck-no-cycle-in-exchange-heap.rs:16:15 - | -LL | Cycle::Node(ref mut y) => { - | --------- borrow of `x.0` occurs here -LL | y.a = x; //~ ERROR cannot move out of - | --- ^ move out of `x` occurs here - | | - | borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.stderr b/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.stderr index 5aaf825a3c368..3462b7610d38b 100644 --- a/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.stderr +++ b/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.stderr @@ -3,8 +3,10 @@ error[E0505]: cannot move out of `x` because it is borrowed | LL | Cycle::Node(ref mut y) => { | --------- borrow of `x.0` occurs here -LL | y.a = x; //~ ERROR cannot move out of - | ^ move out of `x` occurs here +LL | y.a = x; + | --- ^ move out of `x` occurs here + | | + | borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr b/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr index ff0cc93323257..49c3f861ea993 100644 --- a/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr +++ b/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr @@ -3,8 +3,8 @@ error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immut | LL | let y = x.borrowed(); | - immutable borrow occurs here -LL | let z = x.mut_borrowed(); //~ ERROR cannot borrow - | ^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | let z = x.mut_borrowed(); + | ^ mutable borrow occurs here LL | y.use_ref(); | - immutable borrow later used here @@ -13,7 +13,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta | LL | let y = x.borrowed(); | - immutable borrow occurs here -LL | let z = &mut x; //~ ERROR cannot borrow +LL | let z = &mut x; | ^^^^^^ mutable borrow occurs here LL | y.use_ref(); | - immutable borrow later used here diff --git a/src/test/ui/borrowck/borrowck-object-lifetime.rs b/src/test/ui/borrowck/borrowck-object-lifetime.rs index 495516cf97634..137a9adbc40ac 100644 --- a/src/test/ui/borrowck/borrowck-object-lifetime.rs +++ b/src/test/ui/borrowck/borrowck-object-lifetime.rs @@ -8,26 +8,26 @@ trait Foo { fn mut_borrowed(&mut self) -> &(); } -fn borrowed_receiver(x: &Foo) { +fn borrowed_receiver(x: &dyn Foo) { let y = x.borrowed(); let z = x.borrowed(); z.use_ref(); y.use_ref(); } -fn mut_borrowed_receiver(x: &mut Foo) { +fn mut_borrowed_receiver(x: &mut dyn Foo) { let y = x.borrowed(); let z = x.mut_borrowed(); //~ ERROR cannot borrow y.use_ref(); } -fn mut_owned_receiver(mut x: Box) { +fn mut_owned_receiver(mut x: Box) { let y = x.borrowed(); let z = &mut x; //~ ERROR cannot borrow y.use_ref(); } -fn imm_owned_receiver(mut x: Box) { +fn imm_owned_receiver(mut x: Box) { let y = x.borrowed(); let z = &x; z.use_ref(); diff --git a/src/test/ui/borrowck/borrowck-object-lifetime.stderr b/src/test/ui/borrowck/borrowck-object-lifetime.stderr index b22d05b8a2a82..cf94c74dec222 100644 --- a/src/test/ui/borrowck/borrowck-object-lifetime.stderr +++ b/src/test/ui/borrowck/borrowck-object-lifetime.stderr @@ -3,22 +3,20 @@ error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immut | LL | let y = x.borrowed(); | - immutable borrow occurs here -LL | let z = x.mut_borrowed(); //~ ERROR cannot borrow - | ^ mutable borrow occurs here +LL | let z = x.mut_borrowed(); + | ^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | y.use_ref(); -LL | } - | - immutable borrow ends here + | - immutable borrow later used here -error[E0502]: cannot borrow `x` as mutable because `*x` is also borrowed as immutable - --> $DIR/borrowck-object-lifetime.rs:26:18 +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-object-lifetime.rs:26:13 | LL | let y = x.borrowed(); | - immutable borrow occurs here -LL | let z = &mut x; //~ ERROR cannot borrow - | ^ mutable borrow occurs here +LL | let z = &mut x; + | ^^^^^^ mutable borrow occurs here LL | y.use_ref(); -LL | } - | - immutable borrow ends here + | - immutable borrow later used here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-or-init.nll.stderr b/src/test/ui/borrowck/borrowck-or-init.nll.stderr deleted file mode 100644 index dcd2c18dcaa23..0000000000000 --- a/src/test/ui/borrowck/borrowck-or-init.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `i` - --> $DIR/borrowck-or-init.rs:5:20 - | -LL | println!("{}", i); //~ ERROR use of possibly uninitialized variable: `i` - | ^ use of possibly uninitialized `i` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-or-init.rs b/src/test/ui/borrowck/borrowck-or-init.rs index 5b1487831a689..c0d6c9c2739b2 100644 --- a/src/test/ui/borrowck/borrowck-or-init.rs +++ b/src/test/ui/borrowck/borrowck-or-init.rs @@ -2,5 +2,5 @@ fn main() { let i: isize; println!("{}", false || { i = 5; true }); - println!("{}", i); //~ ERROR use of possibly uninitialized variable: `i` + println!("{}", i); //~ ERROR borrow of possibly uninitialized variable: `i` } diff --git a/src/test/ui/borrowck/borrowck-or-init.stderr b/src/test/ui/borrowck/borrowck-or-init.stderr index 60024c08303ac..122f5192720cc 100644 --- a/src/test/ui/borrowck/borrowck-or-init.stderr +++ b/src/test/ui/borrowck/borrowck-or-init.stderr @@ -1,7 +1,7 @@ -error[E0381]: use of possibly uninitialized variable: `i` +error[E0381]: borrow of possibly uninitialized variable: `i` --> $DIR/borrowck-or-init.rs:5:20 | -LL | println!("{}", i); //~ ERROR use of possibly uninitialized variable: `i` +LL | println!("{}", i); | ^ use of possibly uninitialized `i` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-overloaded-call.nll.stderr b/src/test/ui/borrowck/borrowck-overloaded-call.nll.stderr deleted file mode 100644 index c5a4c4e005aa7..0000000000000 --- a/src/test/ui/borrowck/borrowck-overloaded-call.nll.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-overloaded-call.rs:59:5 - | -LL | let sp = &mut s; - | ------ mutable borrow occurs here -LL | s(3); //~ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable - | ^ immutable borrow occurs here -LL | use_mut(sp); - | -- mutable borrow later used here - -error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable - --> $DIR/borrowck-overloaded-call.rs:67:5 - | -LL | let s = SFnMut { - | - help: consider changing this to be mutable: `mut s` -... -LL | s(3); //~ ERROR cannot borrow immutable local variable `s` as mutable - | ^ cannot borrow as mutable - -error[E0382]: use of moved value: `s` - --> $DIR/borrowck-overloaded-call.rs:75:5 - | -LL | let s = SFnOnce { - | - move occurs because `s` has type `SFnOnce`, which does not implement the `Copy` trait -... -LL | s(" world".to_string()); - | - value moved here -LL | s(" world".to_string()); //~ ERROR use of moved value: `s` - | ^ value used here after move - -error: aborting due to 3 previous errors - -Some errors occurred: E0382, E0502, E0596. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-call.rs b/src/test/ui/borrowck/borrowck-overloaded-call.rs index 8601449b331a3..7b16bf666d062 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-call.rs +++ b/src/test/ui/borrowck/borrowck-overloaded-call.rs @@ -64,7 +64,7 @@ fn g() { x: 1, y: 2, }; - s(3); //~ ERROR cannot borrow immutable local variable `s` as mutable + s(3); //~ ERROR cannot borrow `s` as mutable, as it is not declared as mutable } fn h() { diff --git a/src/test/ui/borrowck/borrowck-overloaded-call.stderr b/src/test/ui/borrowck/borrowck-overloaded-call.stderr index 0429226130656..ddb63b5ec0fbe 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-call.stderr +++ b/src/test/ui/borrowck/borrowck-overloaded-call.stderr @@ -2,33 +2,33 @@ error[E0502]: cannot borrow `s` as immutable because it is also borrowed as muta --> $DIR/borrowck-overloaded-call.rs:59:5 | LL | let sp = &mut s; - | - mutable borrow occurs here -LL | s(3); //~ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable + | ------ mutable borrow occurs here +LL | s(3); | ^ immutable borrow occurs here LL | use_mut(sp); -LL | } - | - mutable borrow ends here + | -- mutable borrow later used here -error[E0596]: cannot borrow immutable local variable `s` as mutable +error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable --> $DIR/borrowck-overloaded-call.rs:67:5 | LL | let s = SFnMut { - | - help: make this binding mutable: `mut s` + | - help: consider changing this to be mutable: `mut s` ... -LL | s(3); //~ ERROR cannot borrow immutable local variable `s` as mutable - | ^ cannot borrow mutably +LL | s(3); + | ^ cannot borrow as mutable error[E0382]: use of moved value: `s` --> $DIR/borrowck-overloaded-call.rs:75:5 | +LL | let s = SFnOnce { + | - move occurs because `s` has type `SFnOnce`, which does not implement the `Copy` trait +... LL | s(" world".to_string()); | - value moved here -LL | s(" world".to_string()); //~ ERROR use of moved value: `s` +LL | s(" world".to_string()); | ^ value used here after move - | - = note: move occurs because `s` has type `SFnOnce`, which does not implement the `Copy` trait error: aborting due to 3 previous errors -Some errors occurred: E0382, E0502, E0596. +Some errors have detailed explanations: E0382, E0502, E0596. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.ast.nll.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.ast.nll.stderr deleted file mode 100644 index f33fb55f9cdfc..0000000000000 --- a/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.ast.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0506]: cannot assign to `v` because it is borrowed - --> $DIR/borrowck-overloaded-index-and-overloaded-deref.rs:34:5 - | -LL | let i = &v[0].f; - | - borrow of `v` occurs here -LL | v = MyVec { x: MyPtr { x: Foo { f: 23 } } }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `v` occurs here -... -LL | read(*i); - | -- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.ast.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.ast.stderr deleted file mode 100644 index 59841ee2dbedd..0000000000000 --- a/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.ast.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0506]: cannot assign to `v` because it is borrowed - --> $DIR/borrowck-overloaded-index-and-overloaded-deref.rs:34:5 - | -LL | let i = &v[0].f; - | - borrow of `v` occurs here -LL | v = MyVec { x: MyPtr { x: Foo { f: 23 } } }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `v` occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.mir.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.mir.stderr deleted file mode 100644 index f33fb55f9cdfc..0000000000000 --- a/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.mir.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0506]: cannot assign to `v` because it is borrowed - --> $DIR/borrowck-overloaded-index-and-overloaded-deref.rs:34:5 - | -LL | let i = &v[0].f; - | - borrow of `v` occurs here -LL | v = MyVec { x: MyPtr { x: Foo { f: 23 } } }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `v` occurs here -... -LL | read(*i); - | -- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.rs b/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.rs index 348d99f4f9898..0e3e01a9332cf 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.rs +++ b/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.rs @@ -3,9 +3,6 @@ // operator. The accounting of the all the implicit things going on // here is rather subtle. Issue #20232. -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - use std::ops::{Deref, Index}; struct MyVec { x: T } @@ -32,8 +29,7 @@ fn main() { let mut v = MyVec { x: MyPtr { x: Foo { f: 22 } } }; let i = &v[0].f; v = MyVec { x: MyPtr { x: Foo { f: 23 } } }; - //[ast]~^ ERROR cannot assign to `v` - //[mir]~^^ ERROR cannot assign to `v` because it is borrowed + //~^ ERROR cannot assign to `v` because it is borrowed read(*i); } diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr new file mode 100644 index 0000000000000..5d52e49191831 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `v` because it is borrowed + --> $DIR/borrowck-overloaded-index-and-overloaded-deref.rs:31:5 + | +LL | let i = &v[0].f; + | - borrow of `v` occurs here +LL | v = MyVec { x: MyPtr { x: Foo { f: 23 } } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `v` occurs here +LL | +LL | read(*i); + | -- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.nll.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.nll.stderr deleted file mode 100644 index 13ace0178f892..0000000000000 --- a/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.nll.stderr +++ /dev/null @@ -1,84 +0,0 @@ -error[E0502]: cannot borrow `*f` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-overloaded-index-autoderef.rs:37:14 - | -LL | let p = &mut f[&s]; - | - mutable borrow occurs here -LL | let q = &f[&s]; //~ ERROR cannot borrow - | ^ immutable borrow occurs here -LL | p.use_mut(); - | - mutable borrow later used here - -error[E0499]: cannot borrow `*f` as mutable more than once at a time - --> $DIR/borrowck-overloaded-index-autoderef.rs:43:18 - | -LL | let p = &mut f[&s]; - | - first mutable borrow occurs here -LL | let q = &mut f[&s]; //~ ERROR cannot borrow - | ^ second mutable borrow occurs here -LL | p.use_mut(); - | - first borrow later used here - -error[E0499]: cannot borrow `f.foo` as mutable more than once at a time - --> $DIR/borrowck-overloaded-index-autoderef.rs:53:18 - | -LL | let p = &mut f.foo[&s]; - | ----- first mutable borrow occurs here -LL | let q = &mut f.foo[&s]; //~ ERROR cannot borrow - | ^^^^^ second mutable borrow occurs here -LL | p.use_mut(); - | - first borrow later used here - -error[E0502]: cannot borrow `f.foo` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-overloaded-index-autoderef.rs:65:18 - | -LL | let p = &f.foo[&s]; - | ----- immutable borrow occurs here -LL | let q = &mut f.foo[&s]; //~ ERROR cannot borrow - | ^^^^^ mutable borrow occurs here -LL | p.use_ref(); - | - immutable borrow later used here - -error[E0506]: cannot assign to `f.foo` because it is borrowed - --> $DIR/borrowck-overloaded-index-autoderef.rs:71:5 - | -LL | let p = &f.foo[&s]; - | ----- borrow of `f.foo` occurs here -LL | f.foo = g; //~ ERROR cannot assign - | ^^^^^^^^^ assignment to borrowed `f.foo` occurs here -LL | p.use_ref(); - | - borrow later used here - -error[E0506]: cannot assign to `*f` because it is borrowed - --> $DIR/borrowck-overloaded-index-autoderef.rs:77:5 - | -LL | let p = &f.foo[&s]; - | ----- borrow of `*f` occurs here -LL | *f = g; //~ ERROR cannot assign - | ^^^^^^ assignment to borrowed `*f` occurs here -LL | p.use_ref(); - | - borrow later used here - -error[E0506]: cannot assign to `f.foo` because it is borrowed - --> $DIR/borrowck-overloaded-index-autoderef.rs:83:5 - | -LL | let p = &mut f.foo[&s]; - | ----- borrow of `f.foo` occurs here -LL | f.foo = g; //~ ERROR cannot assign - | ^^^^^^^^^ assignment to borrowed `f.foo` occurs here -LL | p.use_mut(); - | - borrow later used here - -error[E0506]: cannot assign to `*f` because it is borrowed - --> $DIR/borrowck-overloaded-index-autoderef.rs:89:5 - | -LL | let p = &mut f.foo[&s]; - | ----- borrow of `*f` occurs here -LL | *f = g; //~ ERROR cannot assign - | ^^^^^^ assignment to borrowed `*f` occurs here -LL | p.use_mut(); - | - borrow later used here - -error: aborting due to 8 previous errors - -Some errors occurred: E0499, E0502, E0506. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.stderr index 9bc83f84339c7..978e1291722a3 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.stderr +++ b/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.stderr @@ -3,78 +3,82 @@ error[E0502]: cannot borrow `*f` as immutable because it is also borrowed as mut | LL | let p = &mut f[&s]; | - mutable borrow occurs here -LL | let q = &f[&s]; //~ ERROR cannot borrow +LL | let q = &f[&s]; | ^ immutable borrow occurs here LL | p.use_mut(); -LL | } - | - mutable borrow ends here + | - mutable borrow later used here error[E0499]: cannot borrow `*f` as mutable more than once at a time --> $DIR/borrowck-overloaded-index-autoderef.rs:43:18 | LL | let p = &mut f[&s]; | - first mutable borrow occurs here -LL | let q = &mut f[&s]; //~ ERROR cannot borrow +LL | let q = &mut f[&s]; | ^ second mutable borrow occurs here LL | p.use_mut(); -LL | } - | - first borrow ends here + | - first borrow later used here error[E0499]: cannot borrow `f.foo` as mutable more than once at a time --> $DIR/borrowck-overloaded-index-autoderef.rs:53:18 | LL | let p = &mut f.foo[&s]; | ----- first mutable borrow occurs here -LL | let q = &mut f.foo[&s]; //~ ERROR cannot borrow +LL | let q = &mut f.foo[&s]; | ^^^^^ second mutable borrow occurs here LL | p.use_mut(); -LL | } - | - first borrow ends here + | - first borrow later used here error[E0502]: cannot borrow `f.foo` as mutable because it is also borrowed as immutable --> $DIR/borrowck-overloaded-index-autoderef.rs:65:18 | LL | let p = &f.foo[&s]; | ----- immutable borrow occurs here -LL | let q = &mut f.foo[&s]; //~ ERROR cannot borrow +LL | let q = &mut f.foo[&s]; | ^^^^^ mutable borrow occurs here LL | p.use_ref(); -LL | } - | - immutable borrow ends here + | - immutable borrow later used here error[E0506]: cannot assign to `f.foo` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:71:5 | LL | let p = &f.foo[&s]; | ----- borrow of `f.foo` occurs here -LL | f.foo = g; //~ ERROR cannot assign +LL | f.foo = g; | ^^^^^^^^^ assignment to borrowed `f.foo` occurs here +LL | p.use_ref(); + | - borrow later used here error[E0506]: cannot assign to `*f` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:77:5 | LL | let p = &f.foo[&s]; | ----- borrow of `*f` occurs here -LL | *f = g; //~ ERROR cannot assign +LL | *f = g; | ^^^^^^ assignment to borrowed `*f` occurs here +LL | p.use_ref(); + | - borrow later used here error[E0506]: cannot assign to `f.foo` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:83:5 | LL | let p = &mut f.foo[&s]; | ----- borrow of `f.foo` occurs here -LL | f.foo = g; //~ ERROR cannot assign +LL | f.foo = g; | ^^^^^^^^^ assignment to borrowed `f.foo` occurs here +LL | p.use_mut(); + | - borrow later used here error[E0506]: cannot assign to `*f` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:89:5 | LL | let p = &mut f.foo[&s]; | ----- borrow of `*f` occurs here -LL | *f = g; //~ ERROR cannot assign +LL | *f = g; | ^^^^^^ assignment to borrowed `*f` occurs here +LL | p.use_mut(); + | - borrow later used here error: aborting due to 8 previous errors -Some errors occurred: E0499, E0502, E0506. +Some errors have detailed explanations: E0499, E0502, E0506. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.nll.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.nll.stderr deleted file mode 100644 index dbd805f1d2652..0000000000000 --- a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-overloaded-index-move-from-vec.rs:20:15 - | -LL | let bad = v[0]; - | ^^^^ - | | - | cannot move out of borrowed content - | help: consider borrowing here: `&v[0]` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs index 76dd97ea242e3..ddc210f9aa233 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs +++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs @@ -18,5 +18,5 @@ fn main() { let v = MyVec::> { data: vec![box 1, box 2, box 3] }; let good = &v[0]; // Shouldn't fail here let bad = v[0]; - //~^ ERROR cannot move out of indexed content + //~^ ERROR cannot move out of index of `MyVec>` } diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr index fe655dc8b131f..57f42ede21cd0 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr +++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr @@ -1,11 +1,11 @@ -error[E0507]: cannot move out of indexed content +error[E0507]: cannot move out of index of `MyVec>` --> $DIR/borrowck-overloaded-index-move-from-vec.rs:20:15 | LL | let bad = v[0]; | ^^^^ | | - | cannot move out of indexed content - | help: consider using a reference instead: `&v[0]` + | move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + | help: consider borrowing here: `&v[0]` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.nll.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.nll.stderr deleted file mode 100644 index de60067f1a613..0000000000000 --- a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.nll.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error[E0505]: cannot move out of `s` because it is borrowed - --> $DIR/borrowck-overloaded-index-move-index.rs:50:22 - | -LL | let rs = &mut s; - | ------ borrow of `s` occurs here -LL | -LL | println!("{}", f[s]); - | ^ move out of `s` occurs here -... -LL | use_mut(rs); - | -- borrow later used here - -error[E0505]: cannot move out of `s` because it is borrowed - --> $DIR/borrowck-overloaded-index-move-index.rs:53:7 - | -LL | let rs = &mut s; - | ------ borrow of `s` occurs here -... -LL | f[s] = 10; - | ^ move out of `s` occurs here -... -LL | use_mut(rs); - | -- borrow later used here - -error[E0382]: use of moved value: `s` - --> $DIR/borrowck-overloaded-index-move-index.rs:53:7 - | -LL | let mut s = "hello".to_string(); - | ----- move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait -... -LL | println!("{}", f[s]); - | - value moved here -... -LL | f[s] = 10; - | ^ value used here after move - -error: aborting due to 3 previous errors - -Some errors occurred: E0382, E0505. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr index 7ea311f3e7f2f..5414b01cb0d60 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr +++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr @@ -2,32 +2,39 @@ error[E0505]: cannot move out of `s` because it is borrowed --> $DIR/borrowck-overloaded-index-move-index.rs:50:22 | LL | let rs = &mut s; - | - borrow of `s` occurs here + | ------ borrow of `s` occurs here LL | LL | println!("{}", f[s]); | ^ move out of `s` occurs here +... +LL | use_mut(rs); + | -- borrow later used here error[E0505]: cannot move out of `s` because it is borrowed --> $DIR/borrowck-overloaded-index-move-index.rs:53:7 | LL | let rs = &mut s; - | - borrow of `s` occurs here + | ------ borrow of `s` occurs here ... LL | f[s] = 10; | ^ move out of `s` occurs here +... +LL | use_mut(rs); + | -- borrow later used here error[E0382]: use of moved value: `s` --> $DIR/borrowck-overloaded-index-move-index.rs:53:7 | +LL | let mut s = "hello".to_string(); + | ----- move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait +... LL | println!("{}", f[s]); | - value moved here ... LL | f[s] = 10; | ^ value used here after move - | - = note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait error: aborting due to 3 previous errors -Some errors occurred: E0382, E0505. +Some errors have detailed explanations: E0382, E0505. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.ast.nll.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.ast.nll.stderr deleted file mode 100644 index 2010e8f496245..0000000000000 --- a/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.ast.nll.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-overloaded-index-ref-index.rs:52:22 - | -LL | let rs = &mut s; - | ------ mutable borrow occurs here -LL | println!("{}", f[&s]); - | ^^ immutable borrow occurs here -... -LL | drop(rs); - | -- mutable borrow later used here - -error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-overloaded-index-ref-index.rs:55:7 - | -LL | let rs = &mut s; - | ------ mutable borrow occurs here -... -LL | f[&s] = 10; - | ^^ immutable borrow occurs here -... -LL | drop(rs); - | -- mutable borrow later used here - -error[E0594]: cannot assign to data in a `&` reference - --> $DIR/borrowck-overloaded-index-ref-index.rs:61:5 - | -LL | s[2] = 20; - | ^^^^^^^^^ cannot assign - -error: aborting due to 3 previous errors - -Some errors occurred: E0502, E0594. -For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.ast.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.ast.stderr deleted file mode 100644 index f97f0464fc009..0000000000000 --- a/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.ast.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0594]: cannot assign to immutable indexed content - --> $DIR/borrowck-overloaded-index-ref-index.rs:61:5 - | -LL | s[2] = 20; - | ^^^^^^^^^ cannot borrow as mutable - | - = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `Bar` - -error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-overloaded-index-ref-index.rs:52:23 - | -LL | let rs = &mut s; - | - mutable borrow occurs here -LL | println!("{}", f[&s]); - | ^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here - -error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-overloaded-index-ref-index.rs:55:8 - | -LL | let rs = &mut s; - | - mutable borrow occurs here -... -LL | f[&s] = 10; - | ^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here - -error: aborting due to 3 previous errors - -Some errors occurred: E0502, E0594. -For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.mir.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.mir.stderr deleted file mode 100644 index 2010e8f496245..0000000000000 --- a/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.mir.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-overloaded-index-ref-index.rs:52:22 - | -LL | let rs = &mut s; - | ------ mutable borrow occurs here -LL | println!("{}", f[&s]); - | ^^ immutable borrow occurs here -... -LL | drop(rs); - | -- mutable borrow later used here - -error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-overloaded-index-ref-index.rs:55:7 - | -LL | let rs = &mut s; - | ------ mutable borrow occurs here -... -LL | f[&s] = 10; - | ^^ immutable borrow occurs here -... -LL | drop(rs); - | -- mutable borrow later used here - -error[E0594]: cannot assign to data in a `&` reference - --> $DIR/borrowck-overloaded-index-ref-index.rs:61:5 - | -LL | s[2] = 20; - | ^^^^^^^^^ cannot assign - -error: aborting due to 3 previous errors - -Some errors occurred: E0502, E0594. -For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.rs b/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.rs index 53cab520e4361..cb20873432b7c 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.rs +++ b/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - use std::ops::{Index, IndexMut}; struct Foo { @@ -50,16 +47,13 @@ fn main() { let mut s = "hello".to_string(); let rs = &mut s; println!("{}", f[&s]); - //[ast]~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable - //[mir]~^^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable + //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable f[&s] = 10; - //[ast]~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable - //[mir]~^^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable + //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable let s = Bar { x: 1, }; s[2] = 20; - //[ast]~^ ERROR cannot assign to immutable indexed content - //[mir]~^^ ERROR cannot assign to data in a `&` reference + //~^ ERROR cannot assign to data in a `&` reference drop(rs); } diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.stderr new file mode 100644 index 0000000000000..fcbfe72a34b96 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.stderr @@ -0,0 +1,32 @@ +error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-overloaded-index-ref-index.rs:49:22 + | +LL | let rs = &mut s; + | ------ mutable borrow occurs here +LL | println!("{}", f[&s]); + | ^^ immutable borrow occurs here +... +LL | drop(rs); + | -- mutable borrow later used here + +error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-overloaded-index-ref-index.rs:51:7 + | +LL | let rs = &mut s; + | ------ mutable borrow occurs here +... +LL | f[&s] = 10; + | ^^ immutable borrow occurs here +... +LL | drop(rs); + | -- mutable borrow later used here + +error[E0594]: cannot assign to data in a `&` reference + --> $DIR/borrowck-overloaded-index-ref-index.rs:56:5 + | +LL | s[2] = 20; + | ^^^^^^^^^ cannot assign + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-1.nll.stderr b/src/test/ui/borrowck/borrowck-partial-reinit-1.nll.stderr deleted file mode 100644 index 65f2bd6cfbda9..0000000000000 --- a/src/test/ui/borrowck/borrowck-partial-reinit-1.nll.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0382]: assign of moved value: `t` - --> $DIR/borrowck-partial-reinit-1.rs:27:5 - | -LL | let mut t = Test2 { b: None }; - | ----- move occurs because `t` has type `Test2`, which does not implement the `Copy` trait -LL | let u = Test; -LL | drop(t); - | - value moved here -LL | t.b = Some(u); - | ^^^ value assigned here after move - -error[E0382]: assign of moved value: `t` - --> $DIR/borrowck-partial-reinit-1.rs:33:5 - | -LL | let mut t = Test3(None); - | ----- move occurs because `t` has type `Test3`, which does not implement the `Copy` trait -LL | let u = Test; -LL | drop(t); - | - value moved here -LL | t.0 = Some(u); - | ^^^ value assigned here after move - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-1.rs b/src/test/ui/borrowck/borrowck-partial-reinit-1.rs index f763759152cb3..4e695158154e7 100644 --- a/src/test/ui/borrowck/borrowck-partial-reinit-1.rs +++ b/src/test/ui/borrowck/borrowck-partial-reinit-1.rs @@ -25,13 +25,13 @@ fn stuff() { let u = Test; drop(t); t.b = Some(u); - //~^ ERROR partial reinitialization of uninitialized structure `t` + //~^ ERROR assign of moved value: `t` let mut t = Test3(None); let u = Test; drop(t); t.0 = Some(u); - //~^ ERROR partial reinitialization of uninitialized structure `t` + //~^ ERROR assign of moved value: `t` } fn main() { diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-1.stderr b/src/test/ui/borrowck/borrowck-partial-reinit-1.stderr index 23f5035369d62..65f2bd6cfbda9 100644 --- a/src/test/ui/borrowck/borrowck-partial-reinit-1.stderr +++ b/src/test/ui/borrowck/borrowck-partial-reinit-1.stderr @@ -1,15 +1,25 @@ -error[E0383]: partial reinitialization of uninitialized structure `t` +error[E0382]: assign of moved value: `t` --> $DIR/borrowck-partial-reinit-1.rs:27:5 | +LL | let mut t = Test2 { b: None }; + | ----- move occurs because `t` has type `Test2`, which does not implement the `Copy` trait +LL | let u = Test; +LL | drop(t); + | - value moved here LL | t.b = Some(u); - | ^^^^^^^^^^^^^ + | ^^^ value assigned here after move -error[E0383]: partial reinitialization of uninitialized structure `t` +error[E0382]: assign of moved value: `t` --> $DIR/borrowck-partial-reinit-1.rs:33:5 | +LL | let mut t = Test3(None); + | ----- move occurs because `t` has type `Test3`, which does not implement the `Copy` trait +LL | let u = Test; +LL | drop(t); + | - value moved here LL | t.0 = Some(u); - | ^^^^^^^^^^^^^ + | ^^^ value assigned here after move error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0383`. +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-2.nll.stderr b/src/test/ui/borrowck/borrowck-partial-reinit-2.nll.stderr deleted file mode 100644 index 36a871fbb12a1..0000000000000 --- a/src/test/ui/borrowck/borrowck-partial-reinit-2.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: assign of moved value: `t` - --> $DIR/borrowck-partial-reinit-2.rs:15:5 - | -LL | let mut t = Test { a: 1, b: None}; - | ----- move occurs because `t` has type `Test`, which does not implement the `Copy` trait -LL | let mut u = Test { a: 2, b: Some(Box::new(t))}; - | - value moved here -LL | t.b = Some(Box::new(u)); - | ^^^ value assigned here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-2.rs b/src/test/ui/borrowck/borrowck-partial-reinit-2.rs index 986c20e361c30..06cd322e77ea7 100644 --- a/src/test/ui/borrowck/borrowck-partial-reinit-2.rs +++ b/src/test/ui/borrowck/borrowck-partial-reinit-2.rs @@ -13,7 +13,7 @@ fn stuff() { let mut t = Test { a: 1, b: None}; let mut u = Test { a: 2, b: Some(Box::new(t))}; t.b = Some(Box::new(u)); - //~^ ERROR partial reinitialization of uninitialized structure `t` + //~^ ERROR assign of moved value: `t` println!("done"); } diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-2.stderr b/src/test/ui/borrowck/borrowck-partial-reinit-2.stderr index 891f608850808..36a871fbb12a1 100644 --- a/src/test/ui/borrowck/borrowck-partial-reinit-2.stderr +++ b/src/test/ui/borrowck/borrowck-partial-reinit-2.stderr @@ -1,9 +1,13 @@ -error[E0383]: partial reinitialization of uninitialized structure `t` +error[E0382]: assign of moved value: `t` --> $DIR/borrowck-partial-reinit-2.rs:15:5 | +LL | let mut t = Test { a: 1, b: None}; + | ----- move occurs because `t` has type `Test`, which does not implement the `Copy` trait +LL | let mut u = Test { a: 2, b: Some(Box::new(t))}; + | - value moved here LL | t.b = Some(Box::new(u)); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ value assigned here after move error: aborting due to previous error -For more information about this error, try `rustc --explain E0383`. +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-3.nll.stderr b/src/test/ui/borrowck/borrowck-partial-reinit-3.nll.stderr deleted file mode 100644 index 05f5411eed68c..0000000000000 --- a/src/test/ui/borrowck/borrowck-partial-reinit-3.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: assign of moved value: `x.0` - --> $DIR/borrowck-partial-reinit-3.rs:11:5 - | -LL | mem::drop(x.0); - | --- value moved here -LL | x.0.f = 3; - | ^^^^^^^^^ value assigned here after move - | - = note: move occurs because `x.0` has type `Test`, which does not implement the `Copy` trait - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-3.rs b/src/test/ui/borrowck/borrowck-partial-reinit-3.rs index c7fbd7fc88135..ca484315ba5d6 100644 --- a/src/test/ui/borrowck/borrowck-partial-reinit-3.rs +++ b/src/test/ui/borrowck/borrowck-partial-reinit-3.rs @@ -9,5 +9,5 @@ fn main() { let mut x = (Test { f: 2 }, Test { f: 4 }); mem::drop(x.0); x.0.f = 3; - //~^ ERROR partial reinitialization of uninitialized structure `x.0` + //~^ ERROR assign of moved value: `x.0` } diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-3.stderr b/src/test/ui/borrowck/borrowck-partial-reinit-3.stderr index 262317444cb45..05f5411eed68c 100644 --- a/src/test/ui/borrowck/borrowck-partial-reinit-3.stderr +++ b/src/test/ui/borrowck/borrowck-partial-reinit-3.stderr @@ -1,9 +1,13 @@ -error[E0383]: partial reinitialization of uninitialized structure `x.0` +error[E0382]: assign of moved value: `x.0` --> $DIR/borrowck-partial-reinit-3.rs:11:5 | +LL | mem::drop(x.0); + | --- value moved here LL | x.0.f = 3; - | ^^^^^^^^^ + | ^^^^^^^^^ value assigned here after move + | + = note: move occurs because `x.0` has type `Test`, which does not implement the `Copy` trait error: aborting due to previous error -For more information about this error, try `rustc --explain E0383`. +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-4.nll.stderr b/src/test/ui/borrowck/borrowck-partial-reinit-4.nll.stderr deleted file mode 100644 index f0a9a7dd5e243..0000000000000 --- a/src/test/ui/borrowck/borrowck-partial-reinit-4.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: assign of possibly uninitialized variable: `x.0` - --> $DIR/borrowck-partial-reinit-4.rs:17:5 - | -LL | (x.0).0 = Some(Test); - | ^^^^^^^ use of possibly uninitialized `x.0` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-4.rs b/src/test/ui/borrowck/borrowck-partial-reinit-4.rs index ffa6b11b6fa62..0fb955d201d03 100644 --- a/src/test/ui/borrowck/borrowck-partial-reinit-4.rs +++ b/src/test/ui/borrowck/borrowck-partial-reinit-4.rs @@ -15,7 +15,7 @@ impl Drop for Test2 { fn stuff() { let mut x : (Test2, Test2); (x.0).0 = Some(Test); - //~^ ERROR partial reinitialization of uninitialized structure `x.0` + //~^ ERROR assign of possibly uninitialized variable: `x.0` } fn main() { diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr b/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr index 8ca8e7e13c6e2..f0a9a7dd5e243 100644 --- a/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr +++ b/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr @@ -1,9 +1,9 @@ -error[E0383]: partial reinitialization of uninitialized structure `x.0` +error[E0381]: assign of possibly uninitialized variable: `x.0` --> $DIR/borrowck-partial-reinit-4.rs:17:5 | LL | (x.0).0 = Some(Test); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ use of possibly uninitialized `x.0` error: aborting due to previous error -For more information about this error, try `rustc --explain E0383`. +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-pat-reassign-binding.ast.nll.stderr b/src/test/ui/borrowck/borrowck-pat-reassign-binding.ast.nll.stderr deleted file mode 100644 index d65ba12295d5d..0000000000000 --- a/src/test/ui/borrowck/borrowck-pat-reassign-binding.ast.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-pat-reassign-binding.rs:13:11 - | -LL | Some(ref i) => { - | ----- borrow of `x` occurs here -LL | // But on this branch, `i` is an outstanding borrow -LL | x = Some(*i+1); //[ast]~ ERROR cannot assign to `x` - | ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here -LL | //[mir]~^ ERROR cannot assign to `x` because it is borrowed -LL | drop(i); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-pat-reassign-binding.ast.stderr b/src/test/ui/borrowck/borrowck-pat-reassign-binding.ast.stderr deleted file mode 100644 index 207f971acff7d..0000000000000 --- a/src/test/ui/borrowck/borrowck-pat-reassign-binding.ast.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-pat-reassign-binding.rs:13:11 - | -LL | Some(ref i) => { - | ----- borrow of `x` occurs here -LL | // But on this branch, `i` is an outstanding borrow -LL | x = Some(*i+1); //[ast]~ ERROR cannot assign to `x` - | ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-pat-reassign-binding.mir.stderr b/src/test/ui/borrowck/borrowck-pat-reassign-binding.mir.stderr deleted file mode 100644 index d65ba12295d5d..0000000000000 --- a/src/test/ui/borrowck/borrowck-pat-reassign-binding.mir.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/borrowck-pat-reassign-binding.rs:13:11 - | -LL | Some(ref i) => { - | ----- borrow of `x` occurs here -LL | // But on this branch, `i` is an outstanding borrow -LL | x = Some(*i+1); //[ast]~ ERROR cannot assign to `x` - | ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here -LL | //[mir]~^ ERROR cannot assign to `x` because it is borrowed -LL | drop(i); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-pat-reassign-binding.rs b/src/test/ui/borrowck/borrowck-pat-reassign-binding.rs index 9befa9162d51c..f02c46fb8f0fd 100644 --- a/src/test/ui/borrowck/borrowck-pat-reassign-binding.rs +++ b/src/test/ui/borrowck/borrowck-pat-reassign-binding.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - fn main() { let mut x: Option = None; match x { @@ -10,8 +7,7 @@ fn main() { } Some(ref i) => { // But on this branch, `i` is an outstanding borrow - x = Some(*i+1); //[ast]~ ERROR cannot assign to `x` - //[mir]~^ ERROR cannot assign to `x` because it is borrowed + x = Some(*i+1); //~ ERROR cannot assign to `x` because it is borrowed drop(i); } } diff --git a/src/test/ui/borrowck/borrowck-pat-reassign-binding.stderr b/src/test/ui/borrowck/borrowck-pat-reassign-binding.stderr new file mode 100644 index 0000000000000..9e65ccf5a1913 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-pat-reassign-binding.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/borrowck-pat-reassign-binding.rs:10:11 + | +LL | Some(ref i) => { + | ----- borrow of `x` occurs here +LL | // But on this branch, `i` is an outstanding borrow +LL | x = Some(*i+1); + | ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here +LL | drop(i); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-reborrow-from-mut.nll.stderr b/src/test/ui/borrowck/borrowck-reborrow-from-mut.nll.stderr deleted file mode 100644 index 6b41b6f9c4fd4..0000000000000 --- a/src/test/ui/borrowck/borrowck-reborrow-from-mut.nll.stderr +++ /dev/null @@ -1,116 +0,0 @@ -error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-reborrow-from-mut.rs:13:17 - | -LL | let _bar1 = &mut foo.bar1; - | ------------- first mutable borrow occurs here -LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ second mutable borrow occurs here -LL | use_mut(_bar1); - | ----- first borrow later used here - -error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-reborrow-from-mut.rs:18:17 - | -LL | let _bar1 = &mut foo.bar1; - | ------------- mutable borrow occurs here -LL | let _bar2 = &foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^ immutable borrow occurs here -LL | use_mut(_bar1); - | ----- mutable borrow later used here - -error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-reborrow-from-mut.rs:23:17 - | -LL | let _bar1 = &foo.bar1; - | --------- immutable borrow occurs here -LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ mutable borrow occurs here -LL | use_imm(_bar1); - | ----- immutable borrow later used here - -error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-reborrow-from-mut.rs:45:21 - | -LL | let _bar1 = &mut foo.bar1; - | ------------- first mutable borrow occurs here -LL | match *foo { -LL | Foo { bar1: ref mut _bar1, bar2: _ } => {} - | ^^^^^^^^^^^^^ second mutable borrow occurs here -... -LL | use_mut(_bar1); - | ----- first borrow later used here - -error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-reborrow-from-mut.rs:52:17 - | -LL | let _bar1 = &mut foo.bar1.int1; - | ------------------ mutable borrow occurs here -LL | let _foo1 = &foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^ immutable borrow occurs here -LL | let _foo2 = &*foo; //~ ERROR cannot borrow -LL | use_mut(_bar1); - | ----- mutable borrow later used here - -error[E0502]: cannot borrow `*foo` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-reborrow-from-mut.rs:53:17 - | -LL | let _bar1 = &mut foo.bar1.int1; - | ------------------ mutable borrow occurs here -LL | let _foo1 = &foo.bar1; //~ ERROR cannot borrow -LL | let _foo2 = &*foo; //~ ERROR cannot borrow - | ^^^^^ immutable borrow occurs here -LL | use_mut(_bar1); - | ----- mutable borrow later used here - -error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-reborrow-from-mut.rs:58:17 - | -LL | let _bar1 = &mut foo.bar1.int1; - | ------------------ first mutable borrow occurs here -LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ second mutable borrow occurs here -LL | use_mut(_bar1); - | ----- first borrow later used here - -error[E0499]: cannot borrow `*foo` as mutable more than once at a time - --> $DIR/borrowck-reborrow-from-mut.rs:63:17 - | -LL | let _bar1 = &mut foo.bar1.int1; - | ------------------ first mutable borrow occurs here -LL | let _foo2 = &mut *foo; //~ ERROR cannot borrow - | ^^^^^^^^^ second mutable borrow occurs here -LL | use_mut(_bar1); - | ----- first borrow later used here - -error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-reborrow-from-mut.rs:68:17 - | -LL | let _bar1 = &foo.bar1.int1; - | -------------- immutable borrow occurs here -LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ mutable borrow occurs here -LL | use_imm(_bar1); - | ----- immutable borrow later used here - -error[E0502]: cannot borrow `*foo` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-reborrow-from-mut.rs:73:17 - | -LL | let _bar1 = &foo.bar1.int1; - | -------------- immutable borrow occurs here -LL | let _foo2 = &mut *foo; //~ ERROR cannot borrow - | ^^^^^^^^^ mutable borrow occurs here -LL | use_imm(_bar1); - | ----- immutable borrow later used here - -error[E0596]: cannot borrow `foo.bar1` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-reborrow-from-mut.rs:88:17 - | -LL | fn borrow_mut_from_imm(foo: &Foo) { - | ---- help: consider changing this to be a mutable reference: `&mut Foo` -LL | let _bar1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to 11 previous errors - -Some errors occurred: E0499, E0502, E0596. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-reborrow-from-mut.stderr b/src/test/ui/borrowck/borrowck-reborrow-from-mut.stderr index c20df9f5ff3ff..284cab2960842 100644 --- a/src/test/ui/borrowck/borrowck-reborrow-from-mut.stderr +++ b/src/test/ui/borrowck/borrowck-reborrow-from-mut.stderr @@ -1,124 +1,116 @@ error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-reborrow-from-mut.rs:13:22 + --> $DIR/borrowck-reborrow-from-mut.rs:13:17 | LL | let _bar1 = &mut foo.bar1; - | -------- first mutable borrow occurs here -LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ second mutable borrow occurs here + | ------------- first mutable borrow occurs here +LL | let _bar2 = &mut foo.bar1; + | ^^^^^^^^^^^^^ second mutable borrow occurs here LL | use_mut(_bar1); -LL | } - | - first borrow ends here + | ----- first borrow later used here error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-reborrow-from-mut.rs:18:18 + --> $DIR/borrowck-reborrow-from-mut.rs:18:17 | LL | let _bar1 = &mut foo.bar1; - | -------- mutable borrow occurs here -LL | let _bar2 = &foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ immutable borrow occurs here + | ------------- mutable borrow occurs here +LL | let _bar2 = &foo.bar1; + | ^^^^^^^^^ immutable borrow occurs here LL | use_mut(_bar1); -LL | } - | - mutable borrow ends here + | ----- mutable borrow later used here error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-reborrow-from-mut.rs:23:22 + --> $DIR/borrowck-reborrow-from-mut.rs:23:17 | LL | let _bar1 = &foo.bar1; - | -------- immutable borrow occurs here -LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ mutable borrow occurs here + | --------- immutable borrow occurs here +LL | let _bar2 = &mut foo.bar1; + | ^^^^^^^^^^^^^ mutable borrow occurs here LL | use_imm(_bar1); -LL | } - | - immutable borrow ends here + | ----- immutable borrow later used here error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time --> $DIR/borrowck-reborrow-from-mut.rs:45:21 | LL | let _bar1 = &mut foo.bar1; - | -------- first mutable borrow occurs here + | ------------- first mutable borrow occurs here LL | match *foo { LL | Foo { bar1: ref mut _bar1, bar2: _ } => {} | ^^^^^^^^^^^^^ second mutable borrow occurs here ... -LL | } - | - first borrow ends here +LL | use_mut(_bar1); + | ----- first borrow later used here -error[E0502]: cannot borrow `foo.bar1` as immutable because `foo.bar1.int1` is also borrowed as mutable - --> $DIR/borrowck-reborrow-from-mut.rs:52:18 +error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-reborrow-from-mut.rs:52:17 | LL | let _bar1 = &mut foo.bar1.int1; - | ------------- mutable borrow occurs here -LL | let _foo1 = &foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here + | ------------------ mutable borrow occurs here +LL | let _foo1 = &foo.bar1; + | ^^^^^^^^^ immutable borrow occurs here +LL | let _foo2 = &*foo; +LL | use_mut(_bar1); + | ----- mutable borrow later used here -error[E0502]: cannot borrow `*foo` as immutable because `foo.bar1.int1` is also borrowed as mutable - --> $DIR/borrowck-reborrow-from-mut.rs:53:18 +error[E0502]: cannot borrow `*foo` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-reborrow-from-mut.rs:53:17 | LL | let _bar1 = &mut foo.bar1.int1; - | ------------- mutable borrow occurs here -LL | let _foo1 = &foo.bar1; //~ ERROR cannot borrow -LL | let _foo2 = &*foo; //~ ERROR cannot borrow - | ^^^^ immutable borrow occurs here + | ------------------ mutable borrow occurs here +LL | let _foo1 = &foo.bar1; +LL | let _foo2 = &*foo; + | ^^^^^ immutable borrow occurs here LL | use_mut(_bar1); -LL | } - | - mutable borrow ends here + | ----- mutable borrow later used here error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time - --> $DIR/borrowck-reborrow-from-mut.rs:58:22 + --> $DIR/borrowck-reborrow-from-mut.rs:58:17 | LL | let _bar1 = &mut foo.bar1.int1; - | ------------- first mutable borrow occurs here -LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ second mutable borrow occurs here + | ------------------ first mutable borrow occurs here +LL | let _foo1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ second mutable borrow occurs here LL | use_mut(_bar1); -LL | } - | - first borrow ends here + | ----- first borrow later used here error[E0499]: cannot borrow `*foo` as mutable more than once at a time - --> $DIR/borrowck-reborrow-from-mut.rs:63:22 + --> $DIR/borrowck-reborrow-from-mut.rs:63:17 | LL | let _bar1 = &mut foo.bar1.int1; - | ------------- first mutable borrow occurs here -LL | let _foo2 = &mut *foo; //~ ERROR cannot borrow - | ^^^^ second mutable borrow occurs here + | ------------------ first mutable borrow occurs here +LL | let _foo2 = &mut *foo; + | ^^^^^^^^^ second mutable borrow occurs here LL | use_mut(_bar1); -LL | } - | - first borrow ends here + | ----- first borrow later used here -error[E0502]: cannot borrow `foo.bar1` as mutable because `foo.bar1.int1` is also borrowed as immutable - --> $DIR/borrowck-reborrow-from-mut.rs:68:22 +error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-reborrow-from-mut.rs:68:17 | LL | let _bar1 = &foo.bar1.int1; - | ------------- immutable borrow occurs here -LL | let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ mutable borrow occurs here + | -------------- immutable borrow occurs here +LL | let _foo1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ mutable borrow occurs here LL | use_imm(_bar1); -LL | } - | - immutable borrow ends here + | ----- immutable borrow later used here -error[E0502]: cannot borrow `*foo` as mutable because `foo.bar1.int1` is also borrowed as immutable - --> $DIR/borrowck-reborrow-from-mut.rs:73:22 +error[E0502]: cannot borrow `*foo` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-reborrow-from-mut.rs:73:17 | LL | let _bar1 = &foo.bar1.int1; - | ------------- immutable borrow occurs here -LL | let _foo2 = &mut *foo; //~ ERROR cannot borrow - | ^^^^ mutable borrow occurs here + | -------------- immutable borrow occurs here +LL | let _foo2 = &mut *foo; + | ^^^^^^^^^ mutable borrow occurs here LL | use_imm(_bar1); -LL | } - | - immutable borrow ends here + | ----- immutable borrow later used here -error[E0596]: cannot borrow field `foo.bar1` of immutable binding as mutable - --> $DIR/borrowck-reborrow-from-mut.rs:88:22 +error[E0596]: cannot borrow `foo.bar1` as mutable, as it is behind a `&` reference + --> $DIR/borrowck-reborrow-from-mut.rs:88:17 | LL | fn borrow_mut_from_imm(foo: &Foo) { - | ---- use `&mut Foo` here to make mutable -LL | let _bar1 = &mut foo.bar1; //~ ERROR cannot borrow - | ^^^^^^^^ cannot mutably borrow field of immutable binding + | ---- help: consider changing this to be a mutable reference: `&mut Foo` +LL | let _bar1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to 11 previous errors -Some errors occurred: E0499, E0502, E0596. +Some errors have detailed explanations: E0499, E0502, E0596. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.nll.stderr b/src/test/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.nll.stderr new file mode 100644 index 0000000000000..e6d0f88e3ea8b --- /dev/null +++ b/src/test/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/borrowck-reborrow-from-shorter-lived-andmut.rs:9:5 + | +LL | fn copy_borrowed_ptr<'a,'b>(p: &'a mut S<'b>) -> S<'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | S { pointer: &mut *p.pointer } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.stderr b/src/test/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.stderr index 67b6f64eaa64f..4142fc488c0dd 100644 --- a/src/test/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.stderr +++ b/src/test/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.stderr @@ -10,4 +10,3 @@ LL | S { pointer: &mut *p.pointer } error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/borrowck/borrowck-ref-mut-of-imm.nll.stderr b/src/test/ui/borrowck/borrowck-ref-mut-of-imm.nll.stderr deleted file mode 100644 index 67948ad387928..0000000000000 --- a/src/test/ui/borrowck/borrowck-ref-mut-of-imm.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable - --> $DIR/borrowck-ref-mut-of-imm.rs:4:12 - | -LL | fn destructure(x: Option) -> isize { - | - help: consider changing this to be mutable: `mut x` -... -LL | Some(ref mut v) => *v //~ ERROR cannot borrow - | ^^^^^^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/borrowck-ref-mut-of-imm.stderr b/src/test/ui/borrowck/borrowck-ref-mut-of-imm.stderr index 4eb41758fc19b..e744fc6b54b1a 100644 --- a/src/test/ui/borrowck/borrowck-ref-mut-of-imm.stderr +++ b/src/test/ui/borrowck/borrowck-ref-mut-of-imm.stderr @@ -1,11 +1,11 @@ -error[E0596]: cannot borrow field `(x as std::prelude::v1::Some).0` of immutable binding as mutable +error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable --> $DIR/borrowck-ref-mut-of-imm.rs:4:12 | LL | fn destructure(x: Option) -> isize { - | - help: make this binding mutable: `mut x` + | - help: consider changing this to be mutable: `mut x` ... -LL | Some(ref mut v) => *v //~ ERROR cannot borrow - | ^^^^^^^^^ cannot mutably borrow field of immutable binding +LL | Some(ref mut v) => *v + | ^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-reinit.rs b/src/test/ui/borrowck/borrowck-reinit.rs index e8e38a92c81e9..866b3a2a8af9b 100644 --- a/src/test/ui/borrowck/borrowck-reinit.rs +++ b/src/test/ui/borrowck/borrowck-reinit.rs @@ -1,10 +1,7 @@ -// compile-flags: -Z borrowck=compare - fn main() { let mut x = Box::new(0); let _u = x; // error shouldn't note this move x = Box::new(1); drop(x); - let _ = (1,x); //~ ERROR use of moved value: `x` (Ast) - //~^ ERROR use of moved value: `x` (Mir) + let _ = (1,x); //~ ERROR use of moved value: `x` } diff --git a/src/test/ui/borrowck/borrowck-reinit.stderr b/src/test/ui/borrowck/borrowck-reinit.stderr index 96f3981ac2fe6..f8f14b6435f08 100644 --- a/src/test/ui/borrowck/borrowck-reinit.stderr +++ b/src/test/ui/borrowck/borrowck-reinit.stderr @@ -1,24 +1,14 @@ -error[E0382]: use of moved value: `x` (Ast) - --> $DIR/borrowck-reinit.rs:8:16 - | -LL | drop(x); - | - value moved here -LL | let _ = (1,x); //~ ERROR use of moved value: `x` (Ast) - | ^ value used here after move - | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `x` (Mir) - --> $DIR/borrowck-reinit.rs:8:16 +error[E0382]: use of moved value: `x` + --> $DIR/borrowck-reinit.rs:6:16 | LL | let mut x = Box::new(0); | ----- move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait ... LL | drop(x); | - value moved here -LL | let _ = (1,x); //~ ERROR use of moved value: `x` (Ast) +LL | let _ = (1,x); | ^ value used here after move -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.nll.stderr b/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.nll.stderr deleted file mode 100644 index 7b026ee995118..0000000000000 --- a/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.nll.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-report-with-custom-diagnostic.rs:8:13 - | -LL | let y = &mut x; - | ------ mutable borrow occurs here -LL | //~^ mutable borrow occurs here -LL | let z = &x; //~ ERROR cannot borrow - | ^^ immutable borrow occurs here -... -LL | y.use_mut(); - | - mutable borrow later used here - -error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-report-with-custom-diagnostic.rs:21:21 - | -LL | let y = &x; - | -- immutable borrow occurs here -LL | //~^ immutable borrow occurs here -LL | let z = &mut x; //~ ERROR cannot borrow - | ^^^^^^ mutable borrow occurs here -... -LL | y.use_ref(); - | - immutable borrow later used here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-report-with-custom-diagnostic.rs:36:17 - | -LL | let y = &mut x; - | ------ first mutable borrow occurs here -LL | //~^ first mutable borrow occurs here -LL | let z = &mut x; //~ ERROR cannot borrow - | ^^^^^^ second mutable borrow occurs here -... -LL | y.use_mut(); - | - first borrow later used here - -error: aborting due to 3 previous errors - -Some errors occurred: E0499, E0502. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr b/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr index cb65ea11205d7..db73d4c04acc8 100644 --- a/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr +++ b/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr @@ -1,40 +1,40 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-report-with-custom-diagnostic.rs:8:14 + --> $DIR/borrowck-report-with-custom-diagnostic.rs:8:13 | LL | let y = &mut x; - | - mutable borrow occurs here -LL | //~^ mutable borrow occurs here -LL | let z = &x; //~ ERROR cannot borrow - | ^ immutable borrow occurs here + | ------ mutable borrow occurs here +LL | +LL | let z = &x; + | ^^ immutable borrow occurs here ... -LL | } - | - mutable borrow ends here +LL | y.use_mut(); + | - mutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-report-with-custom-diagnostic.rs:21:26 + --> $DIR/borrowck-report-with-custom-diagnostic.rs:21:21 | LL | let y = &x; - | - immutable borrow occurs here -LL | //~^ immutable borrow occurs here -LL | let z = &mut x; //~ ERROR cannot borrow - | ^ mutable borrow occurs here + | -- immutable borrow occurs here +LL | +LL | let z = &mut x; + | ^^^^^^ mutable borrow occurs here ... -LL | } - | - immutable borrow ends here +LL | y.use_ref(); + | - immutable borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-report-with-custom-diagnostic.rs:36:22 + --> $DIR/borrowck-report-with-custom-diagnostic.rs:36:17 | LL | let y = &mut x; - | - first mutable borrow occurs here -LL | //~^ first mutable borrow occurs here -LL | let z = &mut x; //~ ERROR cannot borrow - | ^ second mutable borrow occurs here + | ------ first mutable borrow occurs here +LL | +LL | let z = &mut x; + | ^^^^^^ second mutable borrow occurs here ... -LL | }; - | - first borrow ends here +LL | y.use_mut(); + | - first borrow later used here error: aborting due to 3 previous errors -Some errors occurred: E0499, E0502. +Some errors have detailed explanations: E0499, E0502. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-return-variable-on-stack-via-clone.nll.stderr b/src/test/ui/borrowck/borrowck-return-variable-on-stack-via-clone.nll.stderr deleted file mode 100644 index 65f910de4c3b3..0000000000000 --- a/src/test/ui/borrowck/borrowck-return-variable-on-stack-via-clone.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0515]: cannot return value referencing function parameter `x` - --> $DIR/borrowck-return-variable-on-stack-via-clone.rs:7:5 - | -LL | (&x).clone() //~ ERROR `x` does not live long enough - | ----^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `x` is borrowed here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/borrowck-return-variable-on-stack-via-clone.rs b/src/test/ui/borrowck/borrowck-return-variable-on-stack-via-clone.rs index f8cdc3ed97c40..75e5e7fd4211a 100644 --- a/src/test/ui/borrowck/borrowck-return-variable-on-stack-via-clone.rs +++ b/src/test/ui/borrowck/borrowck-return-variable-on-stack-via-clone.rs @@ -4,7 +4,7 @@ // Issue #19261. fn leak<'a, T>(x: T) -> &'a T { - (&x).clone() //~ ERROR `x` does not live long enough + (&x).clone() //~ ERROR cannot return value referencing function parameter `x` } fn main() { } diff --git a/src/test/ui/borrowck/borrowck-return-variable-on-stack-via-clone.stderr b/src/test/ui/borrowck/borrowck-return-variable-on-stack-via-clone.stderr index b54941eed1be5..d54449ac4ad46 100644 --- a/src/test/ui/borrowck/borrowck-return-variable-on-stack-via-clone.stderr +++ b/src/test/ui/borrowck/borrowck-return-variable-on-stack-via-clone.stderr @@ -1,17 +1,12 @@ -error[E0597]: `x` does not live long enough - --> $DIR/borrowck-return-variable-on-stack-via-clone.rs:7:7 +error[E0515]: cannot return value referencing function parameter `x` + --> $DIR/borrowck-return-variable-on-stack-via-clone.rs:7:5 | -LL | (&x).clone() //~ ERROR `x` does not live long enough - | ^ borrowed value does not live long enough -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 6:9... - --> $DIR/borrowck-return-variable-on-stack-via-clone.rs:6:9 - | -LL | fn leak<'a, T>(x: T) -> &'a T { - | ^^ +LL | (&x).clone() + | ----^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `x` is borrowed here error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/borrowck-return.stderr b/src/test/ui/borrowck/borrowck-return.stderr index b8a5ce8dc99bf..a2b65af5dbfcd 100644 --- a/src/test/ui/borrowck/borrowck-return.stderr +++ b/src/test/ui/borrowck/borrowck-return.stderr @@ -1,7 +1,7 @@ error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-return.rs:3:12 | -LL | return x; //~ ERROR use of possibly uninitialized variable: `x` +LL | return x; | ^ use of possibly uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr index b1629c0e056ca..f716ee68b0002 100644 --- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr @@ -3,7 +3,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im | LL | if let [ref first, ref second, ..] = *s { | ---------- immutable borrow occurs here -LL | if let [_, ref mut second2, ref mut third, ..] = *s { //~ERROR +LL | if let [_, ref mut second2, ref mut third, ..] = *s { | ^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[first, second, second2, third]); | ------ immutable borrow later used here @@ -13,7 +13,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im | LL | if let [.., ref fourth, ref third, _, ref first] = *s { | --------- immutable borrow occurs here -LL | if let [.., ref mut third2, _, _] = *s { //~ERROR +LL | if let [.., ref mut third2, _, _] = *s { | ^^^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[first, third, third2, fourth]); | ----- immutable borrow later used here @@ -24,7 +24,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { | ------------- immutable borrow occurs here ... -LL | if let [_, ref mut from_begin1, ..] = *s { //~ERROR +LL | if let [_, ref mut from_begin1, ..] = *s { | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[from_begin1, from_end1, from_end3, from_end4]); | --------- immutable borrow later used here @@ -35,7 +35,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { | ------------- immutable borrow occurs here ... -LL | if let [_, _, ref mut from_begin2, ..] = *s { //~ERROR +LL | if let [_, _, ref mut from_begin2, ..] = *s { | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[from_begin2, from_end1, from_end3, from_end4]); | --------- immutable borrow later used here @@ -46,7 +46,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { | ------------- immutable borrow occurs here ... -LL | if let [_, _, _, ref mut from_begin3, ..] = *s { //~ERROR +LL | if let [_, _, _, ref mut from_begin3, ..] = *s { | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[from_begin3, from_end1, from_end3, from_end4]); | --------- immutable borrow later used here @@ -57,7 +57,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { | --------------- immutable borrow occurs here ... -LL | if let [.., ref mut from_end2, _] = *s { //~ERROR +LL | if let [.., ref mut from_end2, _] = *s { | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[from_begin0, from_begin1, from_begin3, from_end2]); | ----------- immutable borrow later used here @@ -68,7 +68,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { | --------------- immutable borrow occurs here ... -LL | if let [.., ref mut from_end3, _, _] = *s { //~ERROR +LL | if let [.., ref mut from_end3, _, _] = *s { | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[from_begin0, from_begin1, from_begin3, from_end3]); | ----------- immutable borrow later used here @@ -79,7 +79,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { | --------------- immutable borrow occurs here ... -LL | if let [.., ref mut from_end4, _, _, _] = *s { //~ERROR +LL | if let [.., ref mut from_end4, _, _, _] = *s { | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[from_begin0, from_begin1, from_begin3, from_end4]); | ----------- immutable borrow later used here @@ -89,7 +89,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im | LL | if let [ref first, ref second, ..] = *s { | ---------- immutable borrow occurs here -LL | if let [_, ref mut tail..] = *s { //~ERROR +LL | if let [_, ref mut tail..] = *s { | ^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[first, second]); | ------ immutable borrow later used here @@ -99,7 +99,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im | LL | if let [.., ref second, ref first] = *s { | ---------- immutable borrow occurs here -LL | if let [ref mut tail.., _] = *s { //~ERROR +LL | if let [ref mut tail.., _] = *s { | ^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[first, second]); | ------ immutable borrow later used here @@ -109,7 +109,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im | LL | if let [_, _, _, ref s1..] = *s { | ------ immutable borrow occurs here -LL | if let [ref mut s2.., _, _, _] = *s { //~ERROR +LL | if let [ref mut s2.., _, _, _] = *s { | ^^^^^^^^^^ mutable borrow occurs here LL | nop_subslice(s1); | -- immutable borrow later used here diff --git a/src/test/ui/borrowck/borrowck-storage-dead.rs b/src/test/ui/borrowck/borrowck-storage-dead.rs index 72c3bc1371985..fe9844610425e 100644 --- a/src/test/ui/borrowck/borrowck-storage-dead.rs +++ b/src/test/ui/borrowck/borrowck-storage-dead.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z borrowck=compare - fn ok() { loop { let _x = 1; @@ -15,8 +13,7 @@ fn also_ok() { fn fail() { loop { let x: i32; - let _ = x + 1; //~ERROR (Ast) [E0381] - //~^ ERROR (Mir) [E0381] + let _ = x + 1; //~ERROR [E0381] } } diff --git a/src/test/ui/borrowck/borrowck-storage-dead.stderr b/src/test/ui/borrowck/borrowck-storage-dead.stderr index 057d40d74cfe9..5b9f49c2e7c92 100644 --- a/src/test/ui/borrowck/borrowck-storage-dead.stderr +++ b/src/test/ui/borrowck/borrowck-storage-dead.stderr @@ -1,15 +1,9 @@ -error[E0381]: use of possibly uninitialized variable: `x` (Ast) - --> $DIR/borrowck-storage-dead.rs:18:17 +error[E0381]: use of possibly uninitialized variable: `x` + --> $DIR/borrowck-storage-dead.rs:16:17 | -LL | let _ = x + 1; //~ERROR (Ast) [E0381] +LL | let _ = x + 1; | ^ use of possibly uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x` (Mir) - --> $DIR/borrowck-storage-dead.rs:18:17 - | -LL | let _ = x + 1; //~ERROR (Ast) [E0381] - | ^ use of possibly uninitialized `x` - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-struct-update-with-dtor.ast.nll.stderr b/src/test/ui/borrowck/borrowck-struct-update-with-dtor.ast.nll.stderr deleted file mode 100644 index dbc9ece0c8f86..0000000000000 --- a/src/test/ui/borrowck/borrowck-struct-update-with-dtor.ast.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-struct-update-with-dtor.rs:15:15 - | -LL | let _s2 = S{a: 2, ..s0}; - | ^^^^^^^^^^^^^ cannot move out of here - -error[E0509]: cannot move out of type `T`, which implements the `Drop` trait - --> $DIR/borrowck-struct-update-with-dtor.rs:21:15 - | -LL | let _s2 = T{a: 2, ..s0}; - | ^^^^^^^^^^^^^ cannot move out of here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/borrowck/borrowck-struct-update-with-dtor.ast.stderr b/src/test/ui/borrowck/borrowck-struct-update-with-dtor.ast.stderr deleted file mode 100644 index bc0a954b46d01..0000000000000 --- a/src/test/ui/borrowck/borrowck-struct-update-with-dtor.ast.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-struct-update-with-dtor.rs:15:25 - | -LL | let _s2 = S{a: 2, ..s0}; - | ^^ cannot move out of here - -error[E0509]: cannot move out of type `T`, which implements the `Drop` trait - --> $DIR/borrowck-struct-update-with-dtor.rs:21:25 - | -LL | let _s2 = T{a: 2, ..s0}; - | ^^ cannot move out of here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/borrowck/borrowck-struct-update-with-dtor.mir.stderr b/src/test/ui/borrowck/borrowck-struct-update-with-dtor.mir.stderr deleted file mode 100644 index dbc9ece0c8f86..0000000000000 --- a/src/test/ui/borrowck/borrowck-struct-update-with-dtor.mir.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0509]: cannot move out of type `S`, which implements the `Drop` trait - --> $DIR/borrowck-struct-update-with-dtor.rs:15:15 - | -LL | let _s2 = S{a: 2, ..s0}; - | ^^^^^^^^^^^^^ cannot move out of here - -error[E0509]: cannot move out of type `T`, which implements the `Drop` trait - --> $DIR/borrowck-struct-update-with-dtor.rs:21:15 - | -LL | let _s2 = T{a: 2, ..s0}; - | ^^^^^^^^^^^^^ cannot move out of here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/borrowck/borrowck-struct-update-with-dtor.rs b/src/test/ui/borrowck/borrowck-struct-update-with-dtor.rs index da5bb6366314a..1f6ed6d46aa69 100644 --- a/src/test/ui/borrowck/borrowck-struct-update-with-dtor.rs +++ b/src/test/ui/borrowck/borrowck-struct-update-with-dtor.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - // Issue 4691: Ensure that functional-struct-update can only copy, not // move, when the struct implements Drop. @@ -13,14 +10,12 @@ impl Drop for T { fn drop(&mut self) { } } fn f(s0:S) { let _s2 = S{a: 2, ..s0}; - //[ast]~^ error: cannot move out of type `S`, which implements the `Drop` trait - //[mir]~^^ ERROR [E0509] + //~^ ERROR [E0509] } fn g(s0:T) { let _s2 = T{a: 2, ..s0}; - //[ast]~^ error: cannot move out of type `T`, which implements the `Drop` trait - //[mir]~^^ ERROR [E0509] + //~^ ERROR [E0509] } fn main() { } diff --git a/src/test/ui/borrowck/borrowck-struct-update-with-dtor.stderr b/src/test/ui/borrowck/borrowck-struct-update-with-dtor.stderr new file mode 100644 index 0000000000000..c92c65ba736f4 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-struct-update-with-dtor.stderr @@ -0,0 +1,21 @@ +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:12:15 + | +LL | let _s2 = S{a: 2, ..s0}; + | ^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait + +error[E0509]: cannot move out of type `T`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:17:15 + | +LL | let _s2 = T{a: 2, ..s0}; + | ^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.mv` has type `std::boxed::Box`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.nll.stderr b/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.nll.stderr deleted file mode 100644 index 8fdd5ef4ca6be..0000000000000 --- a/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0502]: cannot borrow `t0` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-swap-mut-base-ptr.rs:13:10 - | -LL | let p: &isize = &*t0; // Freezes `*t0` - | ---- immutable borrow occurs here -LL | swap(&mut t0, &mut t1); //~ ERROR cannot borrow `t0` - | ^^^^^^^ mutable borrow occurs here -LL | *t1 = 22; -LL | p.use_ref(); - | - immutable borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.stderr b/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.stderr index 35007216dace1..1c55953c91fb7 100644 --- a/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.stderr +++ b/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.stderr @@ -1,13 +1,13 @@ -error[E0502]: cannot borrow `t0` as mutable because `*t0` is also borrowed as immutable - --> $DIR/borrowck-swap-mut-base-ptr.rs:13:15 +error[E0502]: cannot borrow `t0` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-swap-mut-base-ptr.rs:13:10 | LL | let p: &isize = &*t0; // Freezes `*t0` - | --- immutable borrow occurs here -LL | swap(&mut t0, &mut t1); //~ ERROR cannot borrow `t0` - | ^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here + | ---- immutable borrow occurs here +LL | swap(&mut t0, &mut t1); + | ^^^^^^^ mutable borrow occurs here +LL | *t1 = 22; +LL | p.use_ref(); + | - immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.ast.nll.stderr b/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.ast.nll.stderr deleted file mode 100644 index 34d08a026dd35..0000000000000 --- a/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.ast.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0712]: thread-local variable borrowed past end of function - --> $DIR/borrowck-thread-local-static-borrow-outlives-fn.rs:11:20 - | -LL | assert_static(&FOO); //[ast]~ ERROR [E0597] - | ^^^^ thread-local variables cannot be borrowed beyond the end of the function -LL | //[mir]~^ ERROR [E0712] -LL | } - | - end of enclosing function is here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0712`. diff --git a/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.ast.stderr b/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.ast.stderr deleted file mode 100644 index 4724f1772bafd..0000000000000 --- a/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.ast.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/borrowck-thread-local-static-borrow-outlives-fn.rs:11:21 - | -LL | assert_static(&FOO); //[ast]~ ERROR [E0597] - | ^^^ - borrowed value only lives until here - | | - | borrowed value does not live long enough - | - = note: borrowed value must be valid for the static lifetime... - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.mir.stderr b/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.mir.stderr deleted file mode 100644 index 34d08a026dd35..0000000000000 --- a/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.mir.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0712]: thread-local variable borrowed past end of function - --> $DIR/borrowck-thread-local-static-borrow-outlives-fn.rs:11:20 - | -LL | assert_static(&FOO); //[ast]~ ERROR [E0597] - | ^^^^ thread-local variables cannot be borrowed beyond the end of the function -LL | //[mir]~^ ERROR [E0712] -LL | } - | - end of enclosing function is here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0712`. diff --git a/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs b/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs index 6fd6acc834666..1cf8d187c25f4 100644 --- a/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs +++ b/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - #![feature(thread_local)] #[thread_local] @@ -8,6 +5,5 @@ static FOO: u8 = 3; fn assert_static(_t: &'static u8) {} fn main() { - assert_static(&FOO); //[ast]~ ERROR [E0597] - //[mir]~^ ERROR [E0712] + assert_static(&FOO); //~ ERROR [E0712] } diff --git a/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr b/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr new file mode 100644 index 0000000000000..26453b42fa94a --- /dev/null +++ b/src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr @@ -0,0 +1,11 @@ +error[E0712]: thread-local variable borrowed past end of function + --> $DIR/borrowck-thread-local-static-borrow-outlives-fn.rs:8:20 + | +LL | assert_static(&FOO); + | ^^^^ thread-local variables cannot be borrowed beyond the end of the function +LL | } + | - end of enclosing function is here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0712`. diff --git a/src/test/ui/borrowck/borrowck-unary-move.ast.nll.stderr b/src/test/ui/borrowck/borrowck-unary-move.ast.nll.stderr deleted file mode 100644 index 53dc6a77887d4..0000000000000 --- a/src/test/ui/borrowck/borrowck-unary-move.ast.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/borrowck-unary-move.rs:7:10 - | -LL | let y = &*x; - | --- borrow of `*x` occurs here -LL | free(x); //[ast]~ ERROR cannot move out of `x` because it is borrowed - | ^ move out of `x` occurs here -LL | //[mir]~^ ERROR cannot move out of `x` because it is borrowed -LL | *y - | -- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-unary-move.ast.stderr b/src/test/ui/borrowck/borrowck-unary-move.ast.stderr deleted file mode 100644 index 9383298af9bfe..0000000000000 --- a/src/test/ui/borrowck/borrowck-unary-move.ast.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/borrowck-unary-move.rs:7:10 - | -LL | let y = &*x; - | -- borrow of `*x` occurs here -LL | free(x); //[ast]~ ERROR cannot move out of `x` because it is borrowed - | ^ move out of `x` occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-unary-move.mir.stderr b/src/test/ui/borrowck/borrowck-unary-move.mir.stderr deleted file mode 100644 index 53dc6a77887d4..0000000000000 --- a/src/test/ui/borrowck/borrowck-unary-move.mir.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/borrowck-unary-move.rs:7:10 - | -LL | let y = &*x; - | --- borrow of `*x` occurs here -LL | free(x); //[ast]~ ERROR cannot move out of `x` because it is borrowed - | ^ move out of `x` occurs here -LL | //[mir]~^ ERROR cannot move out of `x` because it is borrowed -LL | *y - | -- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-unary-move.rs b/src/test/ui/borrowck/borrowck-unary-move.rs index 4e023ac859937..3b4c0731fc5c7 100644 --- a/src/test/ui/borrowck/borrowck-unary-move.rs +++ b/src/test/ui/borrowck/borrowck-unary-move.rs @@ -1,11 +1,6 @@ -// ignore-tidy-linelength -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - fn foo(x: Box) -> isize { let y = &*x; - free(x); //[ast]~ ERROR cannot move out of `x` because it is borrowed - //[mir]~^ ERROR cannot move out of `x` because it is borrowed + free(x); //~ ERROR cannot move out of `x` because it is borrowed *y } diff --git a/src/test/ui/borrowck/borrowck-unary-move.stderr b/src/test/ui/borrowck/borrowck-unary-move.stderr new file mode 100644 index 0000000000000..aab225ed4a429 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-unary-move.stderr @@ -0,0 +1,13 @@ +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/borrowck-unary-move.rs:3:10 + | +LL | let y = &*x; + | --- borrow of `*x` occurs here +LL | free(x); + | ^ move out of `x` occurs here +LL | *y + | -- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-unboxed-closures.nll.stderr b/src/test/ui/borrowck/borrowck-unboxed-closures.nll.stderr deleted file mode 100644 index 363a5a69a07e3..0000000000000 --- a/src/test/ui/borrowck/borrowck-unboxed-closures.nll.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0502]: cannot borrow `f` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-unboxed-closures.rs:3:5 - | -LL | let g = &mut f; - | ------ mutable borrow occurs here -LL | f(1, 2); //~ ERROR cannot borrow `f` as immutable - | ^ immutable borrow occurs here -LL | use_mut(g); - | - mutable borrow later used here - -error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable - --> $DIR/borrowck-unboxed-closures.rs:7:5 - | -LL | fn b isize>(f: F) { - | - help: consider changing this to be mutable: `mut f` -LL | f(1, 2); //~ ERROR cannot borrow immutable argument - | ^ cannot borrow as mutable - -error[E0382]: use of moved value: `f` - --> $DIR/borrowck-unboxed-closures.rs:12:5 - | -LL | fn c isize>(f: F) { - | - - move occurs because `f` has type `F`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | f(1, 2); - | - value moved here -LL | f(1, 2); //~ ERROR use of moved value - | ^ value used here after move - -error: aborting due to 3 previous errors - -Some errors occurred: E0382, E0502, E0596. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-unboxed-closures.rs b/src/test/ui/borrowck/borrowck-unboxed-closures.rs index bfd0fbb30505f..f0048dd7de03f 100644 --- a/src/test/ui/borrowck/borrowck-unboxed-closures.rs +++ b/src/test/ui/borrowck/borrowck-unboxed-closures.rs @@ -4,7 +4,7 @@ fn a isize>(mut f: F) { use_mut(g); } fn b isize>(f: F) { - f(1, 2); //~ ERROR cannot borrow immutable argument + f(1, 2); //~ ERROR cannot borrow `f` as mutable, as it is not declared as mutable } fn c isize>(f: F) { diff --git a/src/test/ui/borrowck/borrowck-unboxed-closures.stderr b/src/test/ui/borrowck/borrowck-unboxed-closures.stderr index 044119f508950..40b8e31348470 100644 --- a/src/test/ui/borrowck/borrowck-unboxed-closures.stderr +++ b/src/test/ui/borrowck/borrowck-unboxed-closures.stderr @@ -2,32 +2,33 @@ error[E0502]: cannot borrow `f` as immutable because it is also borrowed as muta --> $DIR/borrowck-unboxed-closures.rs:3:5 | LL | let g = &mut f; - | - mutable borrow occurs here -LL | f(1, 2); //~ ERROR cannot borrow `f` as immutable + | ------ mutable borrow occurs here +LL | f(1, 2); | ^ immutable borrow occurs here LL | use_mut(g); -LL | } - | - mutable borrow ends here + | - mutable borrow later used here -error[E0596]: cannot borrow immutable argument `f` as mutable +error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable --> $DIR/borrowck-unboxed-closures.rs:7:5 | LL | fn b isize>(f: F) { - | - help: make this binding mutable: `mut f` -LL | f(1, 2); //~ ERROR cannot borrow immutable argument - | ^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut f` +LL | f(1, 2); + | ^ cannot borrow as mutable error[E0382]: use of moved value: `f` --> $DIR/borrowck-unboxed-closures.rs:12:5 | +LL | fn c isize>(f: F) { + | - - move occurs because `f` has type `F`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | f(1, 2); | - value moved here -LL | f(1, 2); //~ ERROR use of moved value +LL | f(1, 2); | ^ value used here after move - | - = note: move occurs because `f` has type `F`, which does not implement the `Copy` trait error: aborting due to 3 previous errors -Some errors occurred: E0382, E0502, E0596. +Some errors have detailed explanations: E0382, E0502, E0596. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-uninit-after-item.stderr b/src/test/ui/borrowck/borrowck-uninit-after-item.stderr index f658b64f11f41..2d0b21dd0d6fb 100644 --- a/src/test/ui/borrowck/borrowck-uninit-after-item.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-after-item.stderr @@ -1,7 +1,7 @@ error[E0381]: use of possibly uninitialized variable: `bar` --> $DIR/borrowck-uninit-after-item.rs:4:9 | -LL | baz(bar); //~ ERROR use of possibly uninitialized variable: `bar` +LL | baz(bar); | ^^^ use of possibly uninitialized `bar` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.ast.nll.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.ast.nll.stderr deleted file mode 100644 index 99cbf64fd5d46..0000000000000 --- a/src/test/ui/borrowck/borrowck-uninit-field-access.ast.nll.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `a` - --> $DIR/borrowck-uninit-field-access.rs:24:13 - | -LL | let _ = a.x + 1; //[ast]~ ERROR use of possibly uninitialized variable: `a.x` - | ^^^ use of possibly uninitialized `a.x` - -error[E0382]: use of moved value: `line1.origin` - --> $DIR/borrowck-uninit-field-access.rs:29:13 - | -LL | let _moved = line1.origin; - | ------------ value moved here -LL | let _ = line1.origin.x + 1; //[ast]~ ERROR use of moved value: `line1.origin.x` - | ^^^^^^^^^^^^^^ value used here after move - | - = note: move occurs because `line1.origin` has type `Point`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `line2` - --> $DIR/borrowck-uninit-field-access.rs:34:5 - | -LL | let _moved = (line2.origin, line2.middle); - | ------------ value moved here -LL | line2.consume(); //[ast]~ ERROR use of partially moved value: `line2` [E0382] - | ^^^^^ value used here after partial move - | - = note: move occurs because `line2.middle` has type `Point`, which does not implement the `Copy` trait - -error: aborting due to 3 previous errors - -Some errors occurred: E0381, E0382. -For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.ast.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.ast.stderr deleted file mode 100644 index 8c05272e5fbae..0000000000000 --- a/src/test/ui/borrowck/borrowck-uninit-field-access.ast.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `a.x` - --> $DIR/borrowck-uninit-field-access.rs:24:13 - | -LL | let _ = a.x + 1; //[ast]~ ERROR use of possibly uninitialized variable: `a.x` - | ^^^ use of possibly uninitialized `a.x` - -error[E0382]: use of moved value: `line1.origin.x` - --> $DIR/borrowck-uninit-field-access.rs:29:13 - | -LL | let _moved = line1.origin; - | ------ value moved here -LL | let _ = line1.origin.x + 1; //[ast]~ ERROR use of moved value: `line1.origin.x` - | ^^^^^^^^^^^^^^ value used here after move - | - = note: move occurs because `line1.origin` has type `Point`, which does not implement the `Copy` trait - -error[E0382]: use of partially moved value: `line2` - --> $DIR/borrowck-uninit-field-access.rs:34:5 - | -LL | let _moved = (line2.origin, line2.middle); - | ------------ value moved here -LL | line2.consume(); //[ast]~ ERROR use of partially moved value: `line2` [E0382] - | ^^^^^ value used here after move - | - = note: move occurs because `line2.origin` has type `Point`, which does not implement the `Copy` trait - -error: aborting due to 3 previous errors - -Some errors occurred: E0381, E0382. -For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.mir.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.mir.stderr deleted file mode 100644 index 99cbf64fd5d46..0000000000000 --- a/src/test/ui/borrowck/borrowck-uninit-field-access.mir.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `a` - --> $DIR/borrowck-uninit-field-access.rs:24:13 - | -LL | let _ = a.x + 1; //[ast]~ ERROR use of possibly uninitialized variable: `a.x` - | ^^^ use of possibly uninitialized `a.x` - -error[E0382]: use of moved value: `line1.origin` - --> $DIR/borrowck-uninit-field-access.rs:29:13 - | -LL | let _moved = line1.origin; - | ------------ value moved here -LL | let _ = line1.origin.x + 1; //[ast]~ ERROR use of moved value: `line1.origin.x` - | ^^^^^^^^^^^^^^ value used here after move - | - = note: move occurs because `line1.origin` has type `Point`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `line2` - --> $DIR/borrowck-uninit-field-access.rs:34:5 - | -LL | let _moved = (line2.origin, line2.middle); - | ------------ value moved here -LL | line2.consume(); //[ast]~ ERROR use of partially moved value: `line2` [E0382] - | ^^^^^ value used here after partial move - | - = note: move occurs because `line2.middle` has type `Point`, which does not implement the `Copy` trait - -error: aborting due to 3 previous errors - -Some errors occurred: E0381, E0382. -For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.rs b/src/test/ui/borrowck/borrowck-uninit-field-access.rs index ab19b2d773519..bc931eef93a8b 100644 --- a/src/test/ui/borrowck/borrowck-uninit-field-access.rs +++ b/src/test/ui/borrowck/borrowck-uninit-field-access.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - // Check that do not allow access to fields of uninitialized or moved // structs. @@ -21,16 +18,13 @@ impl Line { fn consume(self) { } } fn main() { let mut a: Point; - let _ = a.x + 1; //[ast]~ ERROR use of possibly uninitialized variable: `a.x` - //[mir]~^ ERROR [E0381] + let _ = a.x + 1; //~ ERROR [E0381] let mut line1 = Line::default(); let _moved = line1.origin; - let _ = line1.origin.x + 1; //[ast]~ ERROR use of moved value: `line1.origin.x` - //[mir]~^ [E0382] + let _ = line1.origin.x + 1; //~ ERROR [E0382] let mut line2 = Line::default(); let _moved = (line2.origin, line2.middle); - line2.consume(); //[ast]~ ERROR use of partially moved value: `line2` [E0382] - //[mir]~^ [E0382] + line2.consume(); //~ ERROR [E0382] } diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr new file mode 100644 index 0000000000000..aa214f9c2f590 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr @@ -0,0 +1,30 @@ +error[E0381]: use of possibly uninitialized variable: `a` + --> $DIR/borrowck-uninit-field-access.rs:21:13 + | +LL | let _ = a.x + 1; + | ^^^ use of possibly uninitialized `a.x` + +error[E0382]: use of moved value: `line1.origin` + --> $DIR/borrowck-uninit-field-access.rs:25:13 + | +LL | let _moved = line1.origin; + | ------------ value moved here +LL | let _ = line1.origin.x + 1; + | ^^^^^^^^^^^^^^ value used here after move + | + = note: move occurs because `line1.origin` has type `Point`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `line2` + --> $DIR/borrowck-uninit-field-access.rs:29:5 + | +LL | let _moved = (line2.origin, line2.middle); + | ------------ value moved here +LL | line2.consume(); + | ^^^^^ value used here after partial move + | + = note: move occurs because `line2.middle` has type `Point`, which does not implement the `Copy` trait + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0381, E0382. +For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr b/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr index a685f0ecf3c04..163395e42d252 100644 --- a/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr @@ -1,61 +1,61 @@ error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:6:5 | -LL | x += 1; //~ ERROR use of possibly uninitialized variable: `x` +LL | x += 1; | ^^^^^^ use of possibly uninitialized `x` error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:9:5 | -LL | x -= 1; //~ ERROR use of possibly uninitialized variable: `x` +LL | x -= 1; | ^^^^^^ use of possibly uninitialized `x` error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:12:5 | -LL | x *= 1; //~ ERROR use of possibly uninitialized variable: `x` +LL | x *= 1; | ^^^^^^ use of possibly uninitialized `x` error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:15:5 | -LL | x /= 1; //~ ERROR use of possibly uninitialized variable: `x` +LL | x /= 1; | ^^^^^^ use of possibly uninitialized `x` error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:18:5 | -LL | x %= 1; //~ ERROR use of possibly uninitialized variable: `x` +LL | x %= 1; | ^^^^^^ use of possibly uninitialized `x` error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:21:5 | -LL | x ^= 1; //~ ERROR use of possibly uninitialized variable: `x` +LL | x ^= 1; | ^^^^^^ use of possibly uninitialized `x` error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:24:5 | -LL | x &= 1; //~ ERROR use of possibly uninitialized variable: `x` +LL | x &= 1; | ^^^^^^ use of possibly uninitialized `x` error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:27:5 | -LL | x |= 1; //~ ERROR use of possibly uninitialized variable: `x` +LL | x |= 1; | ^^^^^^ use of possibly uninitialized `x` error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:30:5 | -LL | x <<= 1; //~ ERROR use of possibly uninitialized variable: `x` +LL | x <<= 1; | ^^^^^^^ use of possibly uninitialized `x` error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-uninit-in-assignop.rs:33:5 | -LL | x >>= 1; //~ ERROR use of possibly uninitialized variable: `x` +LL | x >>= 1; | ^^^^^^^ use of possibly uninitialized `x` error: aborting due to 10 previous errors diff --git a/src/test/ui/borrowck/borrowck-uninit-ref-chain.ast.nll.stderr b/src/test/ui/borrowck/borrowck-uninit-ref-chain.ast.nll.stderr deleted file mode 100644 index 7687176947a73..0000000000000 --- a/src/test/ui/borrowck/borrowck-uninit-ref-chain.ast.nll.stderr +++ /dev/null @@ -1,45 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/borrowck-uninit-ref-chain.rs:11:14 - | -LL | let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] - | ^^^^ use of possibly uninitialized `**x` - -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/borrowck-uninit-ref-chain.rs:15:14 - | -LL | let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] - | ^^^^ use of possibly uninitialized `**x` - -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/borrowck-uninit-ref-chain.rs:19:14 - | -LL | let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] - | ^^^^ use of possibly uninitialized `**x` - -error[E0381]: assign to part of possibly uninitialized variable: `a` - --> $DIR/borrowck-uninit-ref-chain.rs:24:5 - | -LL | a.x = 0; //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] - | ^^^^^^^ use of possibly uninitialized `a` - -error[E0381]: assign to part of possibly uninitialized variable: `a` - --> $DIR/borrowck-uninit-ref-chain.rs:29:5 - | -LL | a.x = &&0; //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] - | ^^^^^^^^^ use of possibly uninitialized `a` - -error[E0381]: assign to part of possibly uninitialized variable: `a` - --> $DIR/borrowck-uninit-ref-chain.rs:35:5 - | -LL | a.x = 0; //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] - | ^^^^^^^ use of possibly uninitialized `a` - -error[E0381]: assign to part of possibly uninitialized variable: `a` - --> $DIR/borrowck-uninit-ref-chain.rs:40:5 - | -LL | a.x = &&0; //[mir]~ assign to part of possibly uninitialized variable: `a` [E0381] - | ^^^^^^^^^ use of possibly uninitialized `a` - -error: aborting due to 7 previous errors - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-uninit-ref-chain.ast.stderr b/src/test/ui/borrowck/borrowck-uninit-ref-chain.ast.stderr deleted file mode 100644 index e8ebf8c2dd048..0000000000000 --- a/src/test/ui/borrowck/borrowck-uninit-ref-chain.ast.stderr +++ /dev/null @@ -1,45 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `**x` - --> $DIR/borrowck-uninit-ref-chain.rs:11:15 - | -LL | let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] - | ^^^ use of possibly uninitialized `**x` - -error[E0381]: use of possibly uninitialized variable: `**x` - --> $DIR/borrowck-uninit-ref-chain.rs:15:15 - | -LL | let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] - | ^^^ use of possibly uninitialized `**x` - -error[E0381]: use of possibly uninitialized variable: `**x` - --> $DIR/borrowck-uninit-ref-chain.rs:19:15 - | -LL | let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] - | ^^^ use of possibly uninitialized `**x` - -error[E0381]: use of possibly uninitialized variable: `a.x` - --> $DIR/borrowck-uninit-ref-chain.rs:25:15 - | -LL | let _b = &a.x; //[ast]~ ERROR use of possibly uninitialized variable: `a.x` [E0381] - | ^^^ use of possibly uninitialized `a.x` - -error[E0381]: use of possibly uninitialized variable: `**a.x` - --> $DIR/borrowck-uninit-ref-chain.rs:30:15 - | -LL | let _b = &**a.x; //[ast]~ ERROR use of possibly uninitialized variable: `**a.x` [E0381] - | ^^^^^ use of possibly uninitialized `**a.x` - -error[E0381]: use of possibly uninitialized variable: `a.y` - --> $DIR/borrowck-uninit-ref-chain.rs:36:15 - | -LL | let _b = &a.y; //[ast]~ ERROR use of possibly uninitialized variable: `a.y` [E0381] - | ^^^ use of possibly uninitialized `a.y` - -error[E0381]: use of possibly uninitialized variable: `**a.y` - --> $DIR/borrowck-uninit-ref-chain.rs:41:15 - | -LL | let _b = &**a.y; //[ast]~ ERROR use of possibly uninitialized variable: `**a.y` [E0381] - | ^^^^^ use of possibly uninitialized `**a.y` - -error: aborting due to 7 previous errors - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-uninit-ref-chain.mir.stderr b/src/test/ui/borrowck/borrowck-uninit-ref-chain.mir.stderr deleted file mode 100644 index 7687176947a73..0000000000000 --- a/src/test/ui/borrowck/borrowck-uninit-ref-chain.mir.stderr +++ /dev/null @@ -1,45 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/borrowck-uninit-ref-chain.rs:11:14 - | -LL | let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] - | ^^^^ use of possibly uninitialized `**x` - -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/borrowck-uninit-ref-chain.rs:15:14 - | -LL | let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] - | ^^^^ use of possibly uninitialized `**x` - -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/borrowck-uninit-ref-chain.rs:19:14 - | -LL | let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] - | ^^^^ use of possibly uninitialized `**x` - -error[E0381]: assign to part of possibly uninitialized variable: `a` - --> $DIR/borrowck-uninit-ref-chain.rs:24:5 - | -LL | a.x = 0; //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] - | ^^^^^^^ use of possibly uninitialized `a` - -error[E0381]: assign to part of possibly uninitialized variable: `a` - --> $DIR/borrowck-uninit-ref-chain.rs:29:5 - | -LL | a.x = &&0; //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] - | ^^^^^^^^^ use of possibly uninitialized `a` - -error[E0381]: assign to part of possibly uninitialized variable: `a` - --> $DIR/borrowck-uninit-ref-chain.rs:35:5 - | -LL | a.x = 0; //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] - | ^^^^^^^ use of possibly uninitialized `a` - -error[E0381]: assign to part of possibly uninitialized variable: `a` - --> $DIR/borrowck-uninit-ref-chain.rs:40:5 - | -LL | a.x = &&0; //[mir]~ assign to part of possibly uninitialized variable: `a` [E0381] - | ^^^^^^^^^ use of possibly uninitialized `a` - -error: aborting due to 7 previous errors - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs b/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs index 562012a23da67..fa9148f984077 100644 --- a/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs +++ b/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - struct S { x: X, y: Y, @@ -8,36 +5,29 @@ struct S { fn main() { let x: &&Box; - let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] - //[mir]~^ [E0381] + let _y = &**x; //~ [E0381] let x: &&S; - let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] - //[mir]~^ [E0381] + let _y = &**x; //~ [E0381] let x: &&i32; - let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381] - //[mir]~^ [E0381] + let _y = &**x; //~ [E0381] let mut a: S; - a.x = 0; //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] - let _b = &a.x; //[ast]~ ERROR use of possibly uninitialized variable: `a.x` [E0381] - + a.x = 0; //~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] + let _b = &a.x; let mut a: S<&&i32, &&i32>; - a.x = &&0; //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] - let _b = &**a.x; //[ast]~ ERROR use of possibly uninitialized variable: `**a.x` [E0381] - + a.x = &&0; //~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] + let _b = &**a.x; let mut a: S; - a.x = 0; //[mir]~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] - let _b = &a.y; //[ast]~ ERROR use of possibly uninitialized variable: `a.y` [E0381] - + a.x = 0; //~ ERROR assign to part of possibly uninitialized variable: `a` [E0381] + let _b = &a.y; let mut a: S<&&i32, &&i32>; - a.x = &&0; //[mir]~ assign to part of possibly uninitialized variable: `a` [E0381] - let _b = &**a.y; //[ast]~ ERROR use of possibly uninitialized variable: `**a.y` [E0381] - + a.x = &&0; //~ assign to part of possibly uninitialized variable: `a` [E0381] + let _b = &**a.y; } diff --git a/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr b/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr new file mode 100644 index 0000000000000..d87621f04d653 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr @@ -0,0 +1,45 @@ +error[E0381]: borrow of possibly uninitialized variable: `x` + --> $DIR/borrowck-uninit-ref-chain.rs:8:14 + | +LL | let _y = &**x; + | ^^^^ use of possibly uninitialized `**x` + +error[E0381]: borrow of possibly uninitialized variable: `x` + --> $DIR/borrowck-uninit-ref-chain.rs:11:14 + | +LL | let _y = &**x; + | ^^^^ use of possibly uninitialized `**x` + +error[E0381]: borrow of possibly uninitialized variable: `x` + --> $DIR/borrowck-uninit-ref-chain.rs:14:14 + | +LL | let _y = &**x; + | ^^^^ use of possibly uninitialized `**x` + +error[E0381]: assign to part of possibly uninitialized variable: `a` + --> $DIR/borrowck-uninit-ref-chain.rs:18:5 + | +LL | a.x = 0; + | ^^^^^^^ use of possibly uninitialized `a` + +error[E0381]: assign to part of possibly uninitialized variable: `a` + --> $DIR/borrowck-uninit-ref-chain.rs:22:5 + | +LL | a.x = &&0; + | ^^^^^^^^^ use of possibly uninitialized `a` + +error[E0381]: assign to part of possibly uninitialized variable: `a` + --> $DIR/borrowck-uninit-ref-chain.rs:27:5 + | +LL | a.x = 0; + | ^^^^^^^ use of possibly uninitialized `a` + +error[E0381]: assign to part of possibly uninitialized variable: `a` + --> $DIR/borrowck-uninit-ref-chain.rs:31:5 + | +LL | a.x = &&0; + | ^^^^^^^^^ use of possibly uninitialized `a` + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-uninit.stderr b/src/test/ui/borrowck/borrowck-uninit.stderr index 5e3428e20b1fb..5db9c1b250cc2 100644 --- a/src/test/ui/borrowck/borrowck-uninit.stderr +++ b/src/test/ui/borrowck/borrowck-uninit.stderr @@ -1,7 +1,7 @@ error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-uninit.rs:5:9 | -LL | foo(x); //~ ERROR use of possibly uninitialized variable: `x` +LL | foo(x); | ^ use of possibly uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-union-borrow-nested.nll.stderr b/src/test/ui/borrowck/borrowck-union-borrow-nested.nll.stderr deleted file mode 100644 index 6bb6fc4cf29a1..0000000000000 --- a/src/test/ui/borrowck/borrowck-union-borrow-nested.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0503]: cannot use `u.c` because it was mutably borrowed - --> $DIR/borrowck-union-borrow-nested.rs:24:21 - | -LL | let ra = &mut u.s.a; - | ---------- borrow of `u.s.a` occurs here -LL | let b = u.c; //~ ERROR cannot use `u.c` because it was mutably borrowed - | ^^^ use of borrowed `u.s.a` -LL | ra.use_mut(); - | -- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/borrowck/borrowck-union-borrow-nested.stderr b/src/test/ui/borrowck/borrowck-union-borrow-nested.stderr index 199a13352c4a0..61569b9cac106 100644 --- a/src/test/ui/borrowck/borrowck-union-borrow-nested.stderr +++ b/src/test/ui/borrowck/borrowck-union-borrow-nested.stderr @@ -1,10 +1,12 @@ error[E0503]: cannot use `u.c` because it was mutably borrowed - --> $DIR/borrowck-union-borrow-nested.rs:24:17 + --> $DIR/borrowck-union-borrow-nested.rs:24:21 | LL | let ra = &mut u.s.a; - | ----- borrow of `u.s.a` occurs here -LL | let b = u.c; //~ ERROR cannot use `u.c` because it was mutably borrowed - | ^ use of borrowed `u.s.a` + | ---------- borrow of `u.s.a` occurs here +LL | let b = u.c; + | ^^^ use of borrowed `u.s.a` +LL | ra.use_mut(); + | -- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-union-borrow.mir.stderr b/src/test/ui/borrowck/borrowck-union-borrow.mir.stderr deleted file mode 100644 index 1a2433c8f6afd..0000000000000 --- a/src/test/ui/borrowck/borrowck-union-borrow.mir.stderr +++ /dev/null @@ -1,136 +0,0 @@ -error[E0502]: cannot borrow `u.a` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-union-borrow.rs:27:23 - | -LL | let ra = &u.a; - | ---- immutable borrow occurs here -LL | let rma = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable - | ^^^^^^^^ mutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable -LL | drop(ra); - | -- immutable borrow later used here - -error[E0506]: cannot assign to `u.a` because it is borrowed - --> $DIR/borrowck-union-borrow.rs:33:13 - | -LL | let ra = &u.a; - | ---- borrow of `u.a` occurs here -LL | u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed - | ^^^^^^^ assignment to borrowed `u.a` occurs here -LL | //[mir]~^ ERROR cannot assign to `u.a` because it is borrowed -LL | drop(ra); - | -- borrow later used here - -error[E0502]: cannot borrow `u.b` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-union-borrow.rs:50:23 - | -LL | let ra = &u.a; - | ---- immutable borrow occurs here -LL | let rmb = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`) - | ^^^^^^^^ mutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `u.b` as mutable because it is also borrowed as immutable -LL | drop(ra); - | -- immutable borrow later used here - -error[E0506]: cannot assign to `u.b` because it is borrowed - --> $DIR/borrowck-union-borrow.rs:56:13 - | -LL | let ra = &u.a; - | ---- borrow of `u.b` occurs here -LL | u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed - | ^^^^^^^ assignment to borrowed `u.b` occurs here -LL | //[mir]~^ ERROR cannot assign to `u.b` because it is borrowed -LL | drop(ra); - | -- borrow later used here - -error[E0502]: cannot borrow `u.a` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-union-borrow.rs:63:22 - | -LL | let rma = &mut u.a; - | -------- mutable borrow occurs here -LL | let ra = &u.a; //[ast]~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable - | ^^^^ immutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable -LL | drop(rma); - | --- mutable borrow later used here - -error[E0503]: cannot use `u.a` because it was mutably borrowed - --> $DIR/borrowck-union-borrow.rs:69:21 - | -LL | let ra = &mut u.a; - | -------- borrow of `u.a` occurs here -LL | let a = u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed - | ^^^ use of borrowed `u.a` -LL | //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed -LL | drop(ra); - | -- borrow later used here - -error[E0499]: cannot borrow `u.a` as mutable more than once at a time - --> $DIR/borrowck-union-borrow.rs:75:24 - | -LL | let rma = &mut u.a; - | -------- first mutable borrow occurs here -LL | let rma2 = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable more than once at a time - | ^^^^^^^^ second mutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `u.a` as mutable more than once at a time -LL | drop(rma); - | --- first borrow later used here - -error[E0506]: cannot assign to `u.a` because it is borrowed - --> $DIR/borrowck-union-borrow.rs:81:13 - | -LL | let rma = &mut u.a; - | -------- borrow of `u.a` occurs here -LL | u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed - | ^^^^^^^ assignment to borrowed `u.a` occurs here -LL | //[mir]~^ ERROR cannot assign to `u.a` because it is borrowed -LL | drop(rma); - | --- borrow later used here - -error[E0502]: cannot borrow `u.b` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-union-borrow.rs:88:22 - | -LL | let rma = &mut u.a; - | -------- mutable borrow occurs here -LL | let rb = &u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`) - | ^^^^ immutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `u.b` as immutable because it is also borrowed as mutable -LL | drop(rma); - | --- mutable borrow later used here - -error[E0503]: cannot use `u.b` because it was mutably borrowed - --> $DIR/borrowck-union-borrow.rs:94:21 - | -LL | let ra = &mut u.a; - | -------- borrow of `u.a` occurs here -LL | let b = u.b; //[ast]~ ERROR cannot use `u.b` because it was mutably borrowed - | ^^^ use of borrowed `u.a` -... -LL | drop(ra); - | -- borrow later used here - -error[E0499]: cannot borrow `u.b` as mutable more than once at a time - --> $DIR/borrowck-union-borrow.rs:101:24 - | -LL | let rma = &mut u.a; - | -------- first mutable borrow occurs here -LL | let rmb2 = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time - | ^^^^^^^^ second mutable borrow occurs here -LL | //[mir]~^ ERROR cannot borrow `u.b` as mutable more than once at a time -LL | drop(rma); - | --- first borrow later used here - -error[E0506]: cannot assign to `u.b` because it is borrowed - --> $DIR/borrowck-union-borrow.rs:107:13 - | -LL | let rma = &mut u.a; - | -------- borrow of `u.b` occurs here -LL | u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed - | ^^^^^^^ assignment to borrowed `u.b` occurs here -LL | //[mir]~^ ERROR cannot assign to `u.b` because it is borrowed -LL | drop(rma); - | --- borrow later used here - -error: aborting due to 12 previous errors - -Some errors occurred: E0499, E0502, E0503, E0506. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-union-borrow.nll.stderr b/src/test/ui/borrowck/borrowck-union-borrow.nll.stderr deleted file mode 100644 index 5cba30b43b8a0..0000000000000 --- a/src/test/ui/borrowck/borrowck-union-borrow.nll.stderr +++ /dev/null @@ -1,131 +0,0 @@ -error[E0502]: cannot borrow `u.a` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-union-borrow.rs:25:23 - | -LL | let ra = &u.a; - | ---- immutable borrow occurs here -LL | let rma = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable - | ^^^^^^^^ mutable borrow occurs here -LL | drop(ra); - | -- immutable borrow later used here - -error[E0506]: cannot assign to `u.a` because it is borrowed - --> $DIR/borrowck-union-borrow.rs:30:13 - | -LL | let ra = &u.a; - | ---- borrow of `u.a` occurs here -LL | u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed - | ^^^^^^^ assignment to borrowed `u.a` occurs here -LL | drop(ra); - | -- borrow later used here - -error[E0502]: cannot borrow `u` (via `u.b`) as mutable because it is also borrowed as immutable (via `u.a`) - --> $DIR/borrowck-union-borrow.rs:46:23 - | -LL | let ra = &u.a; - | ---- immutable borrow occurs here (via `u.a`) -LL | let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`) - | ^^^^^^^^ mutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here -LL | drop(ra); - | -- immutable borrow later used here - | - = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a` - -error[E0506]: cannot assign to `u.b` because it is borrowed - --> $DIR/borrowck-union-borrow.rs:51:13 - | -LL | let ra = &u.a; - | ---- borrow of `u.b` occurs here -LL | u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed - | ^^^^^^^ assignment to borrowed `u.b` occurs here -LL | drop(ra); - | -- borrow later used here - -error[E0502]: cannot borrow `u.a` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-union-borrow.rs:57:22 - | -LL | let rma = &mut u.a; - | -------- mutable borrow occurs here -LL | let ra = &u.a; //~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable - | ^^^^ immutable borrow occurs here -LL | drop(rma); - | --- mutable borrow later used here - -error[E0503]: cannot use `u.a` because it was mutably borrowed - --> $DIR/borrowck-union-borrow.rs:62:21 - | -LL | let ra = &mut u.a; - | -------- borrow of `u.a` occurs here -LL | let a = u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed - | ^^^ use of borrowed `u.a` -LL | drop(ra); - | -- borrow later used here - -error[E0499]: cannot borrow `u.a` as mutable more than once at a time - --> $DIR/borrowck-union-borrow.rs:67:24 - | -LL | let rma = &mut u.a; - | -------- first mutable borrow occurs here -LL | let rma2 = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable more than once at a time - | ^^^^^^^^ second mutable borrow occurs here -LL | drop(rma); - | --- first borrow later used here - -error[E0506]: cannot assign to `u.a` because it is borrowed - --> $DIR/borrowck-union-borrow.rs:72:13 - | -LL | let rma = &mut u.a; - | -------- borrow of `u.a` occurs here -LL | u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed - | ^^^^^^^ assignment to borrowed `u.a` occurs here -LL | drop(rma); - | --- borrow later used here - -error[E0502]: cannot borrow `u` (via `u.b`) as immutable because it is also borrowed as mutable (via `u.a`) - --> $DIR/borrowck-union-borrow.rs:78:22 - | -LL | let rma = &mut u.a; - | -------- mutable borrow occurs here (via `u.a`) -LL | let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`) - | ^^^^ immutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here -LL | drop(rma); - | --- mutable borrow later used here - | - = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a` - -error[E0503]: cannot use `u.b` because it was mutably borrowed - --> $DIR/borrowck-union-borrow.rs:83:21 - | -LL | let ra = &mut u.a; - | -------- borrow of `u.a` occurs here -LL | let b = u.b; //~ ERROR cannot use `u.b` because it was mutably borrowed - | ^^^ use of borrowed `u.a` -LL | -LL | drop(ra); - | -- borrow later used here - -error[E0499]: cannot borrow `u` (via `u.b`) as mutable more than once at a time - --> $DIR/borrowck-union-borrow.rs:89:24 - | -LL | let rma = &mut u.a; - | -------- first mutable borrow occurs here (via `u.a`) -LL | let rmb2 = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time - | ^^^^^^^^ second mutable borrow occurs here (via `u.b`) -LL | drop(rma); - | --- first borrow later used here - | - = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a` - -error[E0506]: cannot assign to `u.b` because it is borrowed - --> $DIR/borrowck-union-borrow.rs:94:13 - | -LL | let rma = &mut u.a; - | -------- borrow of `u.b` occurs here -LL | u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed - | ^^^^^^^ assignment to borrowed `u.b` occurs here -LL | drop(rma); - | --- borrow later used here - -error: aborting due to 12 previous errors - -Some errors occurred: E0499, E0502, E0503, E0506. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-union-borrow.rs b/src/test/ui/borrowck/borrowck-union-borrow.rs index 8afc0be8b55c5..63901680bd157 100644 --- a/src/test/ui/borrowck/borrowck-union-borrow.rs +++ b/src/test/ui/borrowck/borrowck-union-borrow.rs @@ -43,7 +43,7 @@ fn main() { } { let ra = &u.a; - let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`) + let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because it is also borrowed as immutable (via `u.a`) drop(ra); } { @@ -75,7 +75,7 @@ fn main() { // Mut borrow, other field { let rma = &mut u.a; - let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`) + let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because it is also borrowed as mutable (via `u.a`) drop(rma); } { diff --git a/src/test/ui/borrowck/borrowck-union-borrow.stderr b/src/test/ui/borrowck/borrowck-union-borrow.stderr index ef6a331eda04c..ca10e299c5857 100644 --- a/src/test/ui/borrowck/borrowck-union-borrow.stderr +++ b/src/test/ui/borrowck/borrowck-union-borrow.stderr @@ -1,118 +1,131 @@ error[E0502]: cannot borrow `u.a` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-union-borrow.rs:25:28 + --> $DIR/borrowck-union-borrow.rs:25:23 | LL | let ra = &u.a; - | --- immutable borrow occurs here -LL | let rma = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable - | ^^^ mutable borrow occurs here + | ---- immutable borrow occurs here +LL | let rma = &mut u.a; + | ^^^^^^^^ mutable borrow occurs here LL | drop(ra); -LL | } - | - immutable borrow ends here + | -- immutable borrow later used here error[E0506]: cannot assign to `u.a` because it is borrowed --> $DIR/borrowck-union-borrow.rs:30:13 | LL | let ra = &u.a; - | --- borrow of `u.a` occurs here -LL | u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed + | ---- borrow of `u.a` occurs here +LL | u.a = 1; | ^^^^^^^ assignment to borrowed `u.a` occurs here +LL | drop(ra); + | -- borrow later used here -error[E0502]: cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`) - --> $DIR/borrowck-union-borrow.rs:46:28 +error[E0502]: cannot borrow `u` (via `u.b`) as mutable because it is also borrowed as immutable (via `u.a`) + --> $DIR/borrowck-union-borrow.rs:46:23 | LL | let ra = &u.a; - | --- immutable borrow occurs here (via `u.a`) -LL | let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`) - | ^^^ mutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here + | ---- immutable borrow occurs here (via `u.a`) +LL | let rmb = &mut u.b; + | ^^^^^^^^ mutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here LL | drop(ra); -LL | } - | - immutable borrow ends here + | -- immutable borrow later used here + | + = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a` error[E0506]: cannot assign to `u.b` because it is borrowed --> $DIR/borrowck-union-borrow.rs:51:13 | LL | let ra = &u.a; - | --- borrow of `u.b` occurs here -LL | u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed + | ---- borrow of `u.b` occurs here +LL | u.b = 1; | ^^^^^^^ assignment to borrowed `u.b` occurs here +LL | drop(ra); + | -- borrow later used here error[E0502]: cannot borrow `u.a` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-union-borrow.rs:57:23 + --> $DIR/borrowck-union-borrow.rs:57:22 | LL | let rma = &mut u.a; - | --- mutable borrow occurs here -LL | let ra = &u.a; //~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable - | ^^^ immutable borrow occurs here + | -------- mutable borrow occurs here +LL | let ra = &u.a; + | ^^^^ immutable borrow occurs here LL | drop(rma); -LL | } - | - mutable borrow ends here + | --- mutable borrow later used here error[E0503]: cannot use `u.a` because it was mutably borrowed - --> $DIR/borrowck-union-borrow.rs:62:17 + --> $DIR/borrowck-union-borrow.rs:62:21 | LL | let ra = &mut u.a; - | --- borrow of `u.a` occurs here -LL | let a = u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed - | ^ use of borrowed `u.a` + | -------- borrow of `u.a` occurs here +LL | let a = u.a; + | ^^^ use of borrowed `u.a` +LL | drop(ra); + | -- borrow later used here error[E0499]: cannot borrow `u.a` as mutable more than once at a time - --> $DIR/borrowck-union-borrow.rs:67:29 + --> $DIR/borrowck-union-borrow.rs:67:24 | LL | let rma = &mut u.a; - | --- first mutable borrow occurs here -LL | let rma2 = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable more than once at a time - | ^^^ second mutable borrow occurs here + | -------- first mutable borrow occurs here +LL | let rma2 = &mut u.a; + | ^^^^^^^^ second mutable borrow occurs here LL | drop(rma); -LL | } - | - first borrow ends here + | --- first borrow later used here error[E0506]: cannot assign to `u.a` because it is borrowed --> $DIR/borrowck-union-borrow.rs:72:13 | LL | let rma = &mut u.a; - | --- borrow of `u.a` occurs here -LL | u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed + | -------- borrow of `u.a` occurs here +LL | u.a = 1; | ^^^^^^^ assignment to borrowed `u.a` occurs here +LL | drop(rma); + | --- borrow later used here -error[E0502]: cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`) - --> $DIR/borrowck-union-borrow.rs:78:23 +error[E0502]: cannot borrow `u` (via `u.b`) as immutable because it is also borrowed as mutable (via `u.a`) + --> $DIR/borrowck-union-borrow.rs:78:22 | LL | let rma = &mut u.a; - | --- mutable borrow occurs here (via `u.a`) -LL | let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`) - | ^^^ immutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here + | -------- mutable borrow occurs here (via `u.a`) +LL | let rb = &u.b; + | ^^^^ immutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here LL | drop(rma); -LL | } - | - mutable borrow ends here + | --- mutable borrow later used here + | + = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a` error[E0503]: cannot use `u.b` because it was mutably borrowed - --> $DIR/borrowck-union-borrow.rs:83:17 + --> $DIR/borrowck-union-borrow.rs:83:21 | LL | let ra = &mut u.a; - | --- borrow of `u.a` occurs here -LL | let b = u.b; //~ ERROR cannot use `u.b` because it was mutably borrowed - | ^ use of borrowed `u.a` + | -------- borrow of `u.a` occurs here +LL | let b = u.b; + | ^^^ use of borrowed `u.a` +LL | +LL | drop(ra); + | -- borrow later used here error[E0499]: cannot borrow `u` (via `u.b`) as mutable more than once at a time - --> $DIR/borrowck-union-borrow.rs:89:29 + --> $DIR/borrowck-union-borrow.rs:89:24 | LL | let rma = &mut u.a; - | --- first mutable borrow occurs here (via `u.a`) -LL | let rmb2 = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time - | ^^^ second mutable borrow occurs here (via `u.b`) + | -------- first mutable borrow occurs here (via `u.a`) +LL | let rmb2 = &mut u.b; + | ^^^^^^^^ second mutable borrow occurs here (via `u.b`) LL | drop(rma); -LL | } - | - first borrow ends here + | --- first borrow later used here + | + = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a` error[E0506]: cannot assign to `u.b` because it is borrowed --> $DIR/borrowck-union-borrow.rs:94:13 | LL | let rma = &mut u.a; - | --- borrow of `u.b` occurs here -LL | u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed + | -------- borrow of `u.b` occurs here +LL | u.b = 1; | ^^^^^^^ assignment to borrowed `u.b` occurs here +LL | drop(rma); + | --- borrow later used here error: aborting due to 12 previous errors -Some errors occurred: E0499, E0502, E0503, E0506. +Some errors have detailed explanations: E0499, E0502, E0503, E0506. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-union-move-assign.nll.stderr b/src/test/ui/borrowck/borrowck-union-move-assign.nll.stderr deleted file mode 100644 index e59fef2dc0d2f..0000000000000 --- a/src/test/ui/borrowck/borrowck-union-move-assign.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: use of moved value: `u` - --> $DIR/borrowck-union-move-assign.rs:17:21 - | -LL | let mut u = U { a: A }; - | ----- move occurs because `u` has type `U`, which does not implement the `Copy` trait -LL | let a = u.a; - | --- value moved here -LL | let a = u.a; //~ ERROR use of moved value: `u.a` - | ^^^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-union-move-assign.rs b/src/test/ui/borrowck/borrowck-union-move-assign.rs index 1bb4325203610..a24f42d2ddf87 100644 --- a/src/test/ui/borrowck/borrowck-union-move-assign.rs +++ b/src/test/ui/borrowck/borrowck-union-move-assign.rs @@ -14,7 +14,7 @@ fn main() { { let mut u = U { a: A }; let a = u.a; - let a = u.a; //~ ERROR use of moved value: `u.a` + let a = u.a; //~ ERROR use of moved value: `u` } { let mut u = U { a: A }; diff --git a/src/test/ui/borrowck/borrowck-union-move-assign.stderr b/src/test/ui/borrowck/borrowck-union-move-assign.stderr index f304dc3a12427..0b1714fd75dc0 100644 --- a/src/test/ui/borrowck/borrowck-union-move-assign.stderr +++ b/src/test/ui/borrowck/borrowck-union-move-assign.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `u.a` - --> $DIR/borrowck-union-move-assign.rs:17:17 +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move-assign.rs:17:21 | +LL | let mut u = U { a: A }; + | ----- move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = u.a; - | - value moved here -LL | let a = u.a; //~ ERROR use of moved value: `u.a` - | ^ value used here after move - | - = note: move occurs because `u.a` has type `A`, which does not implement the `Copy` trait + | --- value moved here +LL | let a = u.a; + | ^^^ value used here after move error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-union-move.nll.stderr b/src/test/ui/borrowck/borrowck-union-move.nll.stderr deleted file mode 100644 index 1392a7931c30a..0000000000000 --- a/src/test/ui/borrowck/borrowck-union-move.nll.stderr +++ /dev/null @@ -1,63 +0,0 @@ -error[E0382]: use of moved value: `u` - --> $DIR/borrowck-union-move.rs:26:21 - | -LL | let mut u = Unn { n1: NonCopy }; - | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait -LL | let a = u.n1; - | ---- value moved here -LL | let a = u.n1; //~ ERROR use of moved value: `u.n1` - | ^^^^ value used here after move - -error[E0382]: use of moved value: `u` - --> $DIR/borrowck-union-move.rs:31:21 - | -LL | let mut u = Unn { n1: NonCopy }; - | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait -LL | let a = u.n1; - | ---- value moved here -LL | let a = u; //~ ERROR use of partially moved value: `u` - | ^ value used here after move - -error[E0382]: use of moved value: `u` - --> $DIR/borrowck-union-move.rs:36:21 - | -LL | let mut u = Unn { n1: NonCopy }; - | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait -LL | let a = u.n1; - | ---- value moved here -LL | let a = u.n2; //~ ERROR use of moved value: `u.n2` - | ^^^^ value used here after move - -error[E0382]: use of moved value: `u` - --> $DIR/borrowck-union-move.rs:63:21 - | -LL | let mut u = Ucn { c: Copy }; - | ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait -LL | let a = u.n; - | --- value moved here -LL | let a = u.n; //~ ERROR use of moved value: `u.n` - | ^^^ value used here after move - -error[E0382]: use of moved value: `u` - --> $DIR/borrowck-union-move.rs:68:21 - | -LL | let mut u = Ucn { c: Copy }; - | ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait -LL | let a = u.n; - | --- value moved here -LL | let a = u.c; //~ ERROR use of moved value: `u.c` - | ^^^ value used here after move - -error[E0382]: use of moved value: `u` - --> $DIR/borrowck-union-move.rs:83:21 - | -LL | let mut u = Ucn { c: Copy }; - | ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait -LL | let a = u.n; - | --- value moved here -LL | let a = u; //~ ERROR use of partially moved value: `u` - | ^ value used here after move - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-union-move.rs b/src/test/ui/borrowck/borrowck-union-move.rs index e2480604f29c7..d0aa6dff74410 100644 --- a/src/test/ui/borrowck/borrowck-union-move.rs +++ b/src/test/ui/borrowck/borrowck-union-move.rs @@ -23,17 +23,17 @@ fn main() { { let mut u = Unn { n1: NonCopy }; let a = u.n1; - let a = u.n1; //~ ERROR use of moved value: `u.n1` + let a = u.n1; //~ ERROR use of moved value: `u` } { let mut u = Unn { n1: NonCopy }; let a = u.n1; - let a = u; //~ ERROR use of partially moved value: `u` + let a = u; //~ ERROR use of moved value: `u` } { let mut u = Unn { n1: NonCopy }; let a = u.n1; - let a = u.n2; //~ ERROR use of moved value: `u.n2` + let a = u.n2; //~ ERROR use of moved value: `u` } // 2 Copy { @@ -60,12 +60,12 @@ fn main() { { let mut u = Ucn { c: Copy }; let a = u.n; - let a = u.n; //~ ERROR use of moved value: `u.n` + let a = u.n; //~ ERROR use of moved value: `u` } { let mut u = Ucn { c: Copy }; let a = u.n; - let a = u.c; //~ ERROR use of moved value: `u.c` + let a = u.c; //~ ERROR use of moved value: `u` } { let mut u = Ucn { c: Copy }; @@ -80,7 +80,7 @@ fn main() { { let mut u = Ucn { c: Copy }; let a = u.n; - let a = u; //~ ERROR use of partially moved value: `u` + let a = u; //~ ERROR use of moved value: `u` } } } diff --git a/src/test/ui/borrowck/borrowck-union-move.stderr b/src/test/ui/borrowck/borrowck-union-move.stderr index ebd8bdc69c023..abbb0142a9c30 100644 --- a/src/test/ui/borrowck/borrowck-union-move.stderr +++ b/src/test/ui/borrowck/borrowck-union-move.stderr @@ -1,62 +1,62 @@ -error[E0382]: use of moved value: `u.n1` - --> $DIR/borrowck-union-move.rs:26:17 +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move.rs:26:21 | +LL | let mut u = Unn { n1: NonCopy }; + | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait LL | let a = u.n1; - | - value moved here -LL | let a = u.n1; //~ ERROR use of moved value: `u.n1` - | ^ value used here after move - | - = note: move occurs because `u.n1` has type `NonCopy`, which does not implement the `Copy` trait + | ---- value moved here +LL | let a = u.n1; + | ^^^^ value used here after move -error[E0382]: use of partially moved value: `u` - --> $DIR/borrowck-union-move.rs:31:17 +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move.rs:31:21 | +LL | let mut u = Unn { n1: NonCopy }; + | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait LL | let a = u.n1; - | - value moved here -LL | let a = u; //~ ERROR use of partially moved value: `u` - | ^ value used here after move - | - = note: move occurs because `u.n2` has type `[type error]`, which does not implement the `Copy` trait + | ---- value moved here +LL | let a = u; + | ^ value used here after move -error[E0382]: use of moved value: `u.n2` - --> $DIR/borrowck-union-move.rs:36:17 +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move.rs:36:21 | +LL | let mut u = Unn { n1: NonCopy }; + | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait LL | let a = u.n1; - | - value moved here -LL | let a = u.n2; //~ ERROR use of moved value: `u.n2` - | ^ value used here after move - | - = note: move occurs because `u.n2` has type `[type error]`, which does not implement the `Copy` trait + | ---- value moved here +LL | let a = u.n2; + | ^^^^ value used here after move -error[E0382]: use of moved value: `u.n` - --> $DIR/borrowck-union-move.rs:63:17 +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move.rs:63:21 | +LL | let mut u = Ucn { c: Copy }; + | ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait LL | let a = u.n; - | - value moved here -LL | let a = u.n; //~ ERROR use of moved value: `u.n` - | ^ value used here after move - | - = note: move occurs because `u.n` has type `NonCopy`, which does not implement the `Copy` trait + | --- value moved here +LL | let a = u.n; + | ^^^ value used here after move -error[E0382]: use of moved value: `u.c` - --> $DIR/borrowck-union-move.rs:68:17 +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move.rs:68:21 | +LL | let mut u = Ucn { c: Copy }; + | ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait LL | let a = u.n; - | - value moved here -LL | let a = u.c; //~ ERROR use of moved value: `u.c` - | ^ value used here after move - | - = note: move occurs because `u.c` has type `[type error]`, which does not implement the `Copy` trait + | --- value moved here +LL | let a = u.c; + | ^^^ value used here after move -error[E0382]: use of partially moved value: `u` - --> $DIR/borrowck-union-move.rs:83:17 +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move.rs:83:21 | +LL | let mut u = Ucn { c: Copy }; + | ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait LL | let a = u.n; - | - value moved here -LL | let a = u; //~ ERROR use of partially moved value: `u` - | ^ value used here after move - | - = note: move occurs because `u.c` has type `[type error]`, which does not implement the `Copy` trait + | --- value moved here +LL | let a = u; + | ^ value used here after move error: aborting due to 6 previous errors diff --git a/src/test/ui/borrowck/borrowck-union-uninitialized.nll.stderr b/src/test/ui/borrowck/borrowck-union-uninitialized.nll.stderr deleted file mode 100644 index 06c884e244667..0000000000000 --- a/src/test/ui/borrowck/borrowck-union-uninitialized.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0381]: assign to part of possibly uninitialized variable: `s` - --> $DIR/borrowck-union-uninitialized.rs:13:9 - | -LL | s.a = 0; - | ^^^^^^^ use of possibly uninitialized `s` - -error[E0381]: assign to part of possibly uninitialized variable: `u` - --> $DIR/borrowck-union-uninitialized.rs:14:9 - | -LL | u.a = 0; - | ^^^^^^^ use of possibly uninitialized `u` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-union-uninitialized.rs b/src/test/ui/borrowck/borrowck-union-uninitialized.rs index e7d456ea746cf..9cab0b19202a0 100644 --- a/src/test/ui/borrowck/borrowck-union-uninitialized.rs +++ b/src/test/ui/borrowck/borrowck-union-uninitialized.rs @@ -10,9 +10,9 @@ fn main() { unsafe { let mut s: S; let mut u: U; - s.a = 0; - u.a = 0; - let sa = s.a; //~ ERROR use of possibly uninitialized variable: `s.a` - let ua = u.a; //~ ERROR use of possibly uninitialized variable: `u.a` + s.a = 0; //~ ERROR assign to part of possibly uninitialized variable: `s` + u.a = 0; //~ ERROR assign to part of possibly uninitialized variable: `u` + let sa = s.a; + let ua = u.a; } } diff --git a/src/test/ui/borrowck/borrowck-union-uninitialized.stderr b/src/test/ui/borrowck/borrowck-union-uninitialized.stderr index c8b22dd1c9efd..06c884e244667 100644 --- a/src/test/ui/borrowck/borrowck-union-uninitialized.stderr +++ b/src/test/ui/borrowck/borrowck-union-uninitialized.stderr @@ -1,14 +1,14 @@ -error[E0381]: use of possibly uninitialized variable: `s.a` - --> $DIR/borrowck-union-uninitialized.rs:15:13 +error[E0381]: assign to part of possibly uninitialized variable: `s` + --> $DIR/borrowck-union-uninitialized.rs:13:9 | -LL | let sa = s.a; //~ ERROR use of possibly uninitialized variable: `s.a` - | ^^ use of possibly uninitialized `s.a` +LL | s.a = 0; + | ^^^^^^^ use of possibly uninitialized `s` -error[E0381]: use of possibly uninitialized variable: `u.a` - --> $DIR/borrowck-union-uninitialized.rs:16:13 +error[E0381]: assign to part of possibly uninitialized variable: `u` + --> $DIR/borrowck-union-uninitialized.rs:14:9 | -LL | let ua = u.a; //~ ERROR use of possibly uninitialized variable: `u.a` - | ^^ use of possibly uninitialized `u.a` +LL | u.a = 0; + | ^^^^^^^ use of possibly uninitialized `u` error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-uniq-via-lend.nll.stderr b/src/test/ui/borrowck/borrowck-uniq-via-lend.nll.stderr deleted file mode 100644 index 7ca277ac07428..0000000000000 --- a/src/test/ui/borrowck/borrowck-uniq-via-lend.nll.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-uniq-via-lend.rs:36:12 - | -LL | let w = &mut v; - | ------ mutable borrow occurs here -LL | borrow(&*v); //~ ERROR cannot borrow `*v` - | ^^^ immutable borrow occurs here -LL | w.use_mut(); - | - mutable borrow later used here - -error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-uniq-via-lend.rs:53:12 - | -LL | x = &mut v; - | ------ mutable borrow occurs here -LL | borrow(&*v); //~ ERROR cannot borrow `*v` - | ^^^ immutable borrow occurs here -LL | x.use_mut(); - | - mutable borrow later used here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-uniq-via-lend.stderr b/src/test/ui/borrowck/borrowck-uniq-via-lend.stderr index 14a9551acc6ea..923edc8edae7d 100644 --- a/src/test/ui/borrowck/borrowck-uniq-via-lend.stderr +++ b/src/test/ui/borrowck/borrowck-uniq-via-lend.stderr @@ -1,24 +1,22 @@ -error[E0502]: cannot borrow `*v` as immutable because `v` is also borrowed as mutable - --> $DIR/borrowck-uniq-via-lend.rs:36:13 +error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-uniq-via-lend.rs:36:12 | LL | let w = &mut v; - | - mutable borrow occurs here -LL | borrow(&*v); //~ ERROR cannot borrow `*v` - | ^^ immutable borrow occurs here + | ------ mutable borrow occurs here +LL | borrow(&*v); + | ^^^ immutable borrow occurs here LL | w.use_mut(); -LL | } - | - mutable borrow ends here + | - mutable borrow later used here -error[E0502]: cannot borrow `*v` as immutable because `v` is also borrowed as mutable - --> $DIR/borrowck-uniq-via-lend.rs:53:13 +error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-uniq-via-lend.rs:53:12 | LL | x = &mut v; - | - mutable borrow occurs here -LL | borrow(&*v); //~ ERROR cannot borrow `*v` - | ^^ immutable borrow occurs here + | ------ mutable borrow occurs here +LL | borrow(&*v); + | ^^^ immutable borrow occurs here LL | x.use_mut(); -LL | } - | - mutable borrow ends here + | - mutable borrow later used here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.ast.nll.stderr b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.ast.nll.stderr deleted file mode 100644 index 181912320e57b..0000000000000 --- a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.ast.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `w` - --> $DIR/borrowck-use-in-index-lvalue.rs:6:5 - | -LL | w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381] - | ^^^^ use of possibly uninitialized `*w` - -error[E0381]: use of possibly uninitialized variable: `w` - --> $DIR/borrowck-use-in-index-lvalue.rs:10:5 - | -LL | w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381] - | ^^^^ use of possibly uninitialized `*w` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.ast.stderr b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.ast.stderr deleted file mode 100644 index abe515788292b..0000000000000 --- a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.ast.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `*w` - --> $DIR/borrowck-use-in-index-lvalue.rs:6:5 - | -LL | w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381] - | ^^^^^^^^ use of possibly uninitialized `*w` - -error[E0381]: use of possibly uninitialized variable: `*w` - --> $DIR/borrowck-use-in-index-lvalue.rs:10:5 - | -LL | w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381] - | ^^^^^^^^ use of possibly uninitialized `*w` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.mir.stderr b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.mir.stderr deleted file mode 100644 index 181912320e57b..0000000000000 --- a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.mir.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `w` - --> $DIR/borrowck-use-in-index-lvalue.rs:6:5 - | -LL | w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381] - | ^^^^ use of possibly uninitialized `*w` - -error[E0381]: use of possibly uninitialized variable: `w` - --> $DIR/borrowck-use-in-index-lvalue.rs:10:5 - | -LL | w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381] - | ^^^^ use of possibly uninitialized `*w` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.rs b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.rs index f953dec444ab9..d30b1de5cd00f 100644 --- a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.rs +++ b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.rs @@ -1,14 +1,9 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - fn test() { let w: &mut [isize]; - w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381] - //[mir]~^ ERROR [E0381] + w[5] = 0; //~ ERROR [E0381] let mut w: &mut [isize]; - w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381] - //[mir]~^ ERROR [E0381] + w[5] = 0; //~ ERROR [E0381] } fn main() { test(); } diff --git a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr new file mode 100644 index 0000000000000..c03ef759f570a --- /dev/null +++ b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr @@ -0,0 +1,15 @@ +error[E0381]: use of possibly uninitialized variable: `w` + --> $DIR/borrowck-use-in-index-lvalue.rs:3:5 + | +LL | w[5] = 0; + | ^^^^ use of possibly uninitialized `*w` + +error[E0381]: use of possibly uninitialized variable: `w` + --> $DIR/borrowck-use-in-index-lvalue.rs:6:5 + | +LL | w[5] = 0; + | ^^^^ use of possibly uninitialized `*w` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-use-mut-borrow.nll.stderr b/src/test/ui/borrowck/borrowck-use-mut-borrow.nll.stderr deleted file mode 100644 index e7b972fb0141a..0000000000000 --- a/src/test/ui/borrowck/borrowck-use-mut-borrow.nll.stderr +++ /dev/null @@ -1,95 +0,0 @@ -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-use-mut-borrow.rs:11:10 - | -LL | let p = &mut x; - | ------ borrow of `x` occurs here -LL | drop(x); //~ ERROR cannot use `x` because it was mutably borrowed - | ^ use of borrowed `x` -LL | *p = 2; - | ------ borrow later used here - -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-use-mut-borrow.rs:18:10 - | -LL | let p = &mut x.a; - | -------- borrow of `x.a` occurs here -LL | drop(x); //~ ERROR cannot use `x` because it was mutably borrowed - | ^ use of borrowed `x.a` -LL | *p = 3; - | ------ borrow later used here - -error[E0503]: cannot use `x.a` because it was mutably borrowed - --> $DIR/borrowck-use-mut-borrow.rs:25:10 - | -LL | let p = &mut x; - | ------ borrow of `x` occurs here -LL | drop(x.a); //~ ERROR cannot use `x.a` because it was mutably borrowed - | ^^^ use of borrowed `x` -LL | p.a = 3; - | ------- borrow later used here - -error[E0503]: cannot use `x.a` because it was mutably borrowed - --> $DIR/borrowck-use-mut-borrow.rs:32:10 - | -LL | let p = &mut x.a; - | -------- borrow of `x.a` occurs here -LL | drop(x.a); //~ ERROR cannot use `x.a` because it was mutably borrowed - | ^^^ use of borrowed `x.a` -LL | *p = 3; - | ------ borrow later used here - -error[E0503]: cannot use `x.a` because it was mutably borrowed - --> $DIR/borrowck-use-mut-borrow.rs:39:13 - | -LL | let p = &mut x; - | ------ borrow of `x` occurs here -LL | let y = A { b: 3, .. x }; //~ ERROR cannot use `x.a` because it was mutably borrowed - | ^^^^^^^^^^^^^^^^ use of borrowed `x` -LL | drop(y); -LL | p.a = 4; - | ------- borrow later used here - -error[E0503]: cannot use `x.a` because it was mutably borrowed - --> $DIR/borrowck-use-mut-borrow.rs:47:13 - | -LL | let p = &mut x.a; - | -------- borrow of `x.a` occurs here -LL | let y = A { b: 3, .. x }; //~ ERROR cannot use `x.a` because it was mutably borrowed - | ^^^^^^^^^^^^^^^^ use of borrowed `x.a` -LL | drop(y); -LL | *p = 4; - | ------ borrow later used here - -error[E0503]: cannot use `*x` because it was mutably borrowed - --> $DIR/borrowck-use-mut-borrow.rs:55:10 - | -LL | let p = &mut x; - | ------ borrow of `x` occurs here -LL | drop(*x); //~ ERROR cannot use `*x` because it was mutably borrowed - | ^^ use of borrowed `x` -LL | **p = 2; - | ------- borrow later used here - -error[E0503]: cannot use `*x.b` because it was mutably borrowed - --> $DIR/borrowck-use-mut-borrow.rs:62:10 - | -LL | let p = &mut x; - | ------ borrow of `x` occurs here -LL | drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed - | ^^^^ use of borrowed `x` -LL | p.a = 3; - | ------- borrow later used here - -error[E0503]: cannot use `*x.b` because it was mutably borrowed - --> $DIR/borrowck-use-mut-borrow.rs:69:10 - | -LL | let p = &mut x.b; - | -------- borrow of `x.b` occurs here -LL | drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed - | ^^^^ use of borrowed `x.b` -LL | **p = 3; - | ------- borrow later used here - -error: aborting due to 9 previous errors - -For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/borrowck/borrowck-use-mut-borrow.stderr b/src/test/ui/borrowck/borrowck-use-mut-borrow.stderr index b6b09f008a4e0..91d69c51e8180 100644 --- a/src/test/ui/borrowck/borrowck-use-mut-borrow.stderr +++ b/src/test/ui/borrowck/borrowck-use-mut-borrow.stderr @@ -2,73 +2,93 @@ error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:11:10 | LL | let p = &mut x; - | - borrow of `x` occurs here -LL | drop(x); //~ ERROR cannot use `x` because it was mutably borrowed + | ------ borrow of `x` occurs here +LL | drop(x); | ^ use of borrowed `x` +LL | *p = 2; + | ------ borrow later used here error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:18:10 | LL | let p = &mut x.a; - | --- borrow of `x.a` occurs here -LL | drop(x); //~ ERROR cannot use `x` because it was mutably borrowed + | -------- borrow of `x.a` occurs here +LL | drop(x); | ^ use of borrowed `x.a` +LL | *p = 3; + | ------ borrow later used here error[E0503]: cannot use `x.a` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:25:10 | LL | let p = &mut x; - | - borrow of `x` occurs here -LL | drop(x.a); //~ ERROR cannot use `x.a` because it was mutably borrowed + | ------ borrow of `x` occurs here +LL | drop(x.a); | ^^^ use of borrowed `x` +LL | p.a = 3; + | ------- borrow later used here error[E0503]: cannot use `x.a` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:32:10 | LL | let p = &mut x.a; - | --- borrow of `x.a` occurs here -LL | drop(x.a); //~ ERROR cannot use `x.a` because it was mutably borrowed + | -------- borrow of `x.a` occurs here +LL | drop(x.a); | ^^^ use of borrowed `x.a` +LL | *p = 3; + | ------ borrow later used here error[E0503]: cannot use `x.a` because it was mutably borrowed - --> $DIR/borrowck-use-mut-borrow.rs:39:26 + --> $DIR/borrowck-use-mut-borrow.rs:39:13 | LL | let p = &mut x; - | - borrow of `x` occurs here -LL | let y = A { b: 3, .. x }; //~ ERROR cannot use `x.a` because it was mutably borrowed - | ^ use of borrowed `x` + | ------ borrow of `x` occurs here +LL | let y = A { b: 3, .. x }; + | ^^^^^^^^^^^^^^^^ use of borrowed `x` +LL | drop(y); +LL | p.a = 4; + | ------- borrow later used here error[E0503]: cannot use `x.a` because it was mutably borrowed - --> $DIR/borrowck-use-mut-borrow.rs:47:26 + --> $DIR/borrowck-use-mut-borrow.rs:47:13 | LL | let p = &mut x.a; - | --- borrow of `x.a` occurs here -LL | let y = A { b: 3, .. x }; //~ ERROR cannot use `x.a` because it was mutably borrowed - | ^ use of borrowed `x.a` + | -------- borrow of `x.a` occurs here +LL | let y = A { b: 3, .. x }; + | ^^^^^^^^^^^^^^^^ use of borrowed `x.a` +LL | drop(y); +LL | *p = 4; + | ------ borrow later used here error[E0503]: cannot use `*x` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:55:10 | LL | let p = &mut x; - | - borrow of `x` occurs here -LL | drop(*x); //~ ERROR cannot use `*x` because it was mutably borrowed + | ------ borrow of `x` occurs here +LL | drop(*x); | ^^ use of borrowed `x` +LL | **p = 2; + | ------- borrow later used here error[E0503]: cannot use `*x.b` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:62:10 | LL | let p = &mut x; - | - borrow of `x` occurs here -LL | drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed + | ------ borrow of `x` occurs here +LL | drop(*x.b); | ^^^^ use of borrowed `x` +LL | p.a = 3; + | ------- borrow later used here error[E0503]: cannot use `*x.b` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:69:10 | LL | let p = &mut x.b; - | --- borrow of `x.b` occurs here -LL | drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed + | -------- borrow of `x.b` occurs here +LL | drop(*x.b); | ^^^^ use of borrowed `x.b` +LL | **p = 3; + | ------- borrow later used here error: aborting due to 9 previous errors diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.ast.nll.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.ast.nll.stderr deleted file mode 100644 index 8f4b02a1df3a4..0000000000000 --- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.ast.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:12:13 - | -LL | let y = x as *const Foo; //[ast]~ ERROR use of possibly uninitialized variable: `*x` - | ^ use of possibly uninitialized `*x` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.ast.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.ast.stderr deleted file mode 100644 index ecb8922ff8df8..0000000000000 --- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.ast.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `*x` - --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:12:13 - | -LL | let y = x as *const Foo; //[ast]~ ERROR use of possibly uninitialized variable: `*x` - | ^ use of possibly uninitialized `*x` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.mir.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.mir.stderr deleted file mode 100644 index 8f4b02a1df3a4..0000000000000 --- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.mir.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:12:13 - | -LL | let y = x as *const Foo; //[ast]~ ERROR use of possibly uninitialized variable: `*x` - | ^ use of possibly uninitialized `*x` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs index 518228a50ff56..3ce7216181494 100644 --- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs +++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - // Variation on `borrowck-use-uninitialized-in-cast` in which we do a // trait cast from an uninitialized source. Issue #20791. @@ -9,6 +6,5 @@ impl Foo for i32 { } fn main() { let x: &i32; - let y = x as *const Foo; //[ast]~ ERROR use of possibly uninitialized variable: `*x` - //[mir]~^ ERROR [E0381] + let y = x as *const dyn Foo; //~ ERROR [E0381] } diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr new file mode 100644 index 0000000000000..2b80140c6b376 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr @@ -0,0 +1,9 @@ +error[E0381]: borrow of possibly uninitialized variable: `x` + --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:9:13 + | +LL | let y = x as *const dyn Foo; + | ^ use of possibly uninitialized `*x` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.ast.nll.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.ast.nll.stderr deleted file mode 100644 index dd0a7509a2b06..0000000000000 --- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.ast.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/borrowck-use-uninitialized-in-cast.rs:10:13 - | -LL | let y = x as *const i32; //[ast]~ ERROR use of possibly uninitialized variable: `*x` [E0381] - | ^ use of possibly uninitialized `*x` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.ast.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.ast.stderr deleted file mode 100644 index d3ddf24d22dd1..0000000000000 --- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.ast.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `*x` - --> $DIR/borrowck-use-uninitialized-in-cast.rs:10:13 - | -LL | let y = x as *const i32; //[ast]~ ERROR use of possibly uninitialized variable: `*x` [E0381] - | ^ use of possibly uninitialized `*x` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.mir.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.mir.stderr deleted file mode 100644 index dd0a7509a2b06..0000000000000 --- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.mir.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/borrowck-use-uninitialized-in-cast.rs:10:13 - | -LL | let y = x as *const i32; //[ast]~ ERROR use of possibly uninitialized variable: `*x` [E0381] - | ^ use of possibly uninitialized `*x` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.rs b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.rs index e15479bde283d..a355a546dc6bf 100644 --- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.rs +++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.rs @@ -1,12 +1,8 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - // Check that we detect unused values that are cast to other things. // The problem was specified to casting to `*`, as creating unsafe // pointers was not being fully checked. Issue #20791. fn main() { let x: &i32; - let y = x as *const i32; //[ast]~ ERROR use of possibly uninitialized variable: `*x` [E0381] - //[mir]~^ ERROR [E0381] + let y = x as *const i32; //~ ERROR [E0381] } diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr new file mode 100644 index 0000000000000..84e717a4639cd --- /dev/null +++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr @@ -0,0 +1,9 @@ +error[E0381]: borrow of possibly uninitialized variable: `x` + --> $DIR/borrowck-use-uninitialized-in-cast.rs:7:13 + | +LL | let y = x as *const i32; + | ^ use of possibly uninitialized `*x` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.nll.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.nll.stderr deleted file mode 100644 index eabd0731388dc..0000000000000 --- a/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.nll.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0515]: cannot return value referencing local variable `vec` - --> $DIR/borrowck-vec-pattern-element-loan.rs:10:5 - | -LL | let vec: &[isize] = &vec; //~ ERROR does not live long enough - | ---- `vec` is borrowed here -... -LL | tail - | ^^^^ returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing local variable `vec` - --> $DIR/borrowck-vec-pattern-element-loan.rs:20:5 - | -LL | let vec: &[isize] = &vec; //~ ERROR does not live long enough - | ---- `vec` is borrowed here -... -LL | init - | ^^^^ returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing local variable `vec` - --> $DIR/borrowck-vec-pattern-element-loan.rs:30:5 - | -LL | let vec: &[isize] = &vec; //~ ERROR does not live long enough - | ---- `vec` is borrowed here -... -LL | slice - | ^^^^^ returns a value referencing data owned by the current function - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.rs b/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.rs index 0de5132466bfb..100384d78c8ea 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.rs +++ b/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.rs @@ -2,32 +2,32 @@ fn a<'a>() -> &'a [isize] { let vec = vec![1, 2, 3, 4]; - let vec: &[isize] = &vec; //~ ERROR does not live long enough + let vec: &[isize] = &vec; let tail = match vec { &[_, ref tail..] => tail, _ => panic!("a") }; - tail + tail //~ ERROR cannot return value referencing local variable `vec` } fn b<'a>() -> &'a [isize] { let vec = vec![1, 2, 3, 4]; - let vec: &[isize] = &vec; //~ ERROR does not live long enough + let vec: &[isize] = &vec; let init = match vec { &[ref init.., _] => init, _ => panic!("b") }; - init + init //~ ERROR cannot return value referencing local variable `vec` } fn c<'a>() -> &'a [isize] { let vec = vec![1, 2, 3, 4]; - let vec: &[isize] = &vec; //~ ERROR does not live long enough + let vec: &[isize] = &vec; let slice = match vec { &[_, ref slice.., _] => slice, _ => panic!("c") }; - slice + slice //~ ERROR cannot return value referencing local variable `vec` } fn main() {} diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.stderr index b2fcb2f8cd1b7..da6d9293b408a 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.stderr @@ -1,48 +1,30 @@ -error[E0597]: `vec` does not live long enough - --> $DIR/borrowck-vec-pattern-element-loan.rs:5:26 +error[E0515]: cannot return value referencing local variable `vec` + --> $DIR/borrowck-vec-pattern-element-loan.rs:10:5 | -LL | let vec: &[isize] = &vec; //~ ERROR does not live long enough - | ^^^ borrowed value does not live long enough +LL | let vec: &[isize] = &vec; + | ---- `vec` is borrowed here ... -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 3:6... - --> $DIR/borrowck-vec-pattern-element-loan.rs:3:6 - | -LL | fn a<'a>() -> &'a [isize] { - | ^^ +LL | tail + | ^^^^ returns a value referencing data owned by the current function -error[E0597]: `vec` does not live long enough - --> $DIR/borrowck-vec-pattern-element-loan.rs:15:26 +error[E0515]: cannot return value referencing local variable `vec` + --> $DIR/borrowck-vec-pattern-element-loan.rs:20:5 | -LL | let vec: &[isize] = &vec; //~ ERROR does not live long enough - | ^^^ borrowed value does not live long enough +LL | let vec: &[isize] = &vec; + | ---- `vec` is borrowed here ... -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:6... - --> $DIR/borrowck-vec-pattern-element-loan.rs:13:6 - | -LL | fn b<'a>() -> &'a [isize] { - | ^^ +LL | init + | ^^^^ returns a value referencing data owned by the current function -error[E0597]: `vec` does not live long enough - --> $DIR/borrowck-vec-pattern-element-loan.rs:25:26 +error[E0515]: cannot return value referencing local variable `vec` + --> $DIR/borrowck-vec-pattern-element-loan.rs:30:5 | -LL | let vec: &[isize] = &vec; //~ ERROR does not live long enough - | ^^^ borrowed value does not live long enough +LL | let vec: &[isize] = &vec; + | ---- `vec` is borrowed here ... -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 23:6... - --> $DIR/borrowck-vec-pattern-element-loan.rs:23:6 - | -LL | fn c<'a>() -> &'a [isize] { - | ^^ +LL | slice + | ^^^^^ returns a value referencing data owned by the current function error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.nll.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.nll.stderr deleted file mode 100644 index 0059dd60f8407..0000000000000 --- a/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0499]: cannot borrow `v` as mutable more than once at a time - --> $DIR/borrowck-vec-pattern-loan-from-mut.rs:8:13 - | -LL | let vb: &mut [isize] = &mut v; - | ------ first mutable borrow occurs here -... -LL | v.push(tail[0] + tail[1]); //~ ERROR cannot borrow - | ^ ------- first borrow later used here - | | - | second mutable borrow occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr index caadcb3611545..251f44592905d 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr @@ -2,13 +2,12 @@ error[E0499]: cannot borrow `v` as mutable more than once at a time --> $DIR/borrowck-vec-pattern-loan-from-mut.rs:8:13 | LL | let vb: &mut [isize] = &mut v; - | - first mutable borrow occurs here + | ------ first mutable borrow occurs here ... -LL | v.push(tail[0] + tail[1]); //~ ERROR cannot borrow - | ^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here +LL | v.push(tail[0] + tail[1]); + | ^ ------- first borrow later used here + | | + | second mutable borrow occurs here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.ast.nll.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.ast.nll.stderr deleted file mode 100644 index 6dc2778892d2e..0000000000000 --- a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.ast.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0506]: cannot assign to `a[_]` because it is borrowed - --> $DIR/borrowck-vec-pattern-move-tail.rs:16:5 - | -LL | [1, 2, ref tail..] => tail, - | -------- borrow of `a[_]` occurs here -... -LL | a[2] = 0; //[ast]~ ERROR cannot assign to `a[..]` because it is borrowed - | ^^^^^^^^ assignment to borrowed `a[_]` occurs here -... -LL | println!("t[0]: {}", t[0]); - | ---- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.ast.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.ast.stderr deleted file mode 100644 index c456dac316db8..0000000000000 --- a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.ast.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0506]: cannot assign to `a[..]` because it is borrowed - --> $DIR/borrowck-vec-pattern-move-tail.rs:16:5 - | -LL | [1, 2, ref tail..] => tail, - | -------- borrow of `a[..]` occurs here -... -LL | a[2] = 0; //[ast]~ ERROR cannot assign to `a[..]` because it is borrowed - | ^^^^^^^^ assignment to borrowed `a[..]` occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.cmp.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.cmp.stderr deleted file mode 100644 index 6eb9eac760f00..0000000000000 --- a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.cmp.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0506]: cannot assign to `a[..]` because it is borrowed (Ast) - --> $DIR/borrowck-vec-pattern-move-tail.rs:16:5 - | -LL | [1, 2, ref tail..] => tail, - | -------- borrow of `a[..]` occurs here -... -LL | a[2] = 0; //[ast]~ ERROR cannot assign to `a[..]` because it is borrowed - | ^^^^^^^^ assignment to borrowed `a[..]` occurs here - -error[E0506]: cannot assign to `a[_]` because it is borrowed (Mir) - --> $DIR/borrowck-vec-pattern-move-tail.rs:16:5 - | -LL | [1, 2, ref tail..] => tail, - | -------- borrow of `a[_]` occurs here -... -LL | a[2] = 0; //[ast]~ ERROR cannot assign to `a[..]` because it is borrowed - | ^^^^^^^^ assignment to borrowed `a[_]` occurs here -... -LL | println!("t[0]: {}", t[0]); - | ---- borrow later used here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.rs b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.rs index e14ecd90d56fb..efc52530716c8 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.rs +++ b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.rs @@ -1,8 +1,4 @@ // http://rust-lang.org/COPYRIGHT. -// - -// revisions: ast cmp -//[cmp]compile-flags: -Z borrowck=compare #![feature(slice_patterns)] @@ -13,9 +9,7 @@ fn main() { _ => unreachable!() }; println!("t[0]: {}", t[0]); - a[2] = 0; //[ast]~ ERROR cannot assign to `a[..]` because it is borrowed - //[cmp]~^ ERROR cannot assign to `a[..]` because it is borrowed (Ast) - //[cmp]~| ERROR cannot assign to `a[_]` because it is borrowed (Mir) + a[2] = 0; //~ ERROR cannot assign to `a[_]` because it is borrowed println!("t[0]: {}", t[0]); t[0]; } diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr new file mode 100644 index 0000000000000..b2f553ba49f70 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `a[_]` because it is borrowed + --> $DIR/borrowck-vec-pattern-move-tail.rs:12:5 + | +LL | [1, 2, ref tail..] => tail, + | -------- borrow of `a[_]` occurs here +... +LL | a[2] = 0; + | ^^^^^^^^ assignment to borrowed `a[_]` occurs here +LL | println!("t[0]: {}", t[0]); + | ---- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr deleted file mode 100644 index 018a3173af1b0..0000000000000 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr +++ /dev/null @@ -1,117 +0,0 @@ -error[E0506]: cannot assign to `vec[_]` because it is borrowed - --> $DIR/borrowck-vec-pattern-nesting.rs:10:13 - | -LL | [box ref _a, _, _] => { - | ------ borrow of `vec[_]` occurs here -LL | //~^ borrow of `vec[..]` occurs here -LL | vec[0] = box 4; //~ ERROR cannot assign - | ^^^^^^ assignment to borrowed `vec[_]` occurs here -LL | //~^ assignment to borrowed `vec[..]` occurs here -LL | _a.use_ref(); - | -- borrow later used here - -error[E0506]: cannot assign to `vec[_]` because it is borrowed - --> $DIR/borrowck-vec-pattern-nesting.rs:23:13 - | -LL | &mut [ref _b..] => { - | ------ borrow of `vec[_]` occurs here -LL | //~^ borrow of `vec[..]` occurs here -LL | vec[0] = box 4; //~ ERROR cannot assign - | ^^^^^^ assignment to borrowed `vec[_]` occurs here -LL | //~^ assignment to borrowed `vec[..]` occurs here -LL | _b.use_ref(); - | -- borrow later used here - -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:33:11 - | -LL | match vec { - | ^^^ cannot move out of here -LL | &mut [_a, //~ ERROR cannot move out - | -- data moved here - | -note: move occurs because `_a` has type `std::boxed::Box`, which does not implement the `Copy` trait - --> $DIR/borrowck-vec-pattern-nesting.rs:34:15 - | -LL | &mut [_a, //~ ERROR cannot move out - | ^^ -help: consider removing the `&mut` - | -LL | [_a, //~ ERROR cannot move out -LL | //~| cannot move out -LL | //~| to prevent move -LL | .. -LL | ] => { - | - -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:47:13 - | -LL | let a = vec[0]; //~ ERROR cannot move out - | ^^^^^^ - | | - | cannot move out of here - | help: consider borrowing here: `&vec[0]` - -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:54:11 - | -LL | match vec { - | ^^^ cannot move out of here -... -LL | _b] => {} - | -- data moved here - | -note: move occurs because `_b` has type `std::boxed::Box`, which does not implement the `Copy` trait - --> $DIR/borrowck-vec-pattern-nesting.rs:57:10 - | -LL | _b] => {} - | ^^ -help: consider removing the `&mut` - | -LL | [ //~ ERROR cannot move out -LL | //~^ cannot move out -LL | _b] => {} - | - -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:60:13 - | -LL | let a = vec[0]; //~ ERROR cannot move out - | ^^^^^^ - | | - | cannot move out of here - | help: consider borrowing here: `&vec[0]` - -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:67:11 - | -LL | match vec { - | ^^^ cannot move out of here -LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out - | ----------------- - | | | | | - | | | | ...and here - | | | ...and here - | | data moved here - | help: consider removing the `&mut`: `[_a, _b, _c]` - | -note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/borrowck-vec-pattern-nesting.rs:68:15 - | -LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out - | ^^ ^^ ^^ - -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:72:13 - | -LL | let a = vec[0]; //~ ERROR cannot move out - | ^^^^^^ - | | - | cannot move out of here - | help: consider borrowing here: `&vec[0]` - -error: aborting due to 8 previous errors - -Some errors occurred: E0506, E0508. -For more information about an error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs index 46203b7a3deed..6448149391def 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs @@ -6,10 +6,11 @@ fn a() { let mut vec = [box 1, box 2, box 3]; match vec { [box ref _a, _, _] => { - //~^ borrow of `vec[..]` occurs here + //~^ NOTE borrow of `vec[_]` occurs here vec[0] = box 4; //~ ERROR cannot assign - //~^ assignment to borrowed `vec[..]` occurs here + //~^ NOTE assignment to borrowed `vec[_]` occurs here _a.use_ref(); + //~^ NOTE borrow later used here } } } @@ -19,10 +20,11 @@ fn b() { let vec: &mut [Box] = &mut vec; match vec { &mut [ref _b..] => { - //~^ borrow of `vec[..]` occurs here + //~^ borrow of `vec[_]` occurs here vec[0] = box 4; //~ ERROR cannot assign - //~^ assignment to borrowed `vec[..]` occurs here + //~^ NOTE assignment to borrowed `vec[_]` occurs here _b.use_ref(); + //~^ NOTE borrow later used here } } } @@ -31,46 +33,60 @@ fn c() { let mut vec = vec![box 1, box 2, box 3]; let vec: &mut [Box] = &mut vec; match vec { - &mut [_a, //~ ERROR cannot move out - //~| cannot move out - //~| to prevent move + //~^ ERROR cannot move out + //~| NOTE cannot move out + &mut [_a, + //~^ NOTE data moved here + //~| NOTE move occurs because `_a` has type + //~| HELP consider removing the `&mut` .. ] => { - // Note: `_a` is *moved* here, but `b` is borrowing, - // hence illegal. - // - // See comment in middle/borrowck/gather_loans/mod.rs - // in the case covering these sorts of vectors. } _ => {} } let a = vec[0]; //~ ERROR cannot move out - //~| cannot move out of here + //~| NOTE cannot move out of here + //~| NOTE move occurs because + //~| HELP consider borrowing here } fn d() { let mut vec = vec![box 1, box 2, box 3]; let vec: &mut [Box] = &mut vec; match vec { - &mut [ //~ ERROR cannot move out - //~^ cannot move out + //~^ ERROR cannot move out + //~| NOTE cannot move out + &mut [ + //~^ HELP consider removing the `&mut` _b] => {} + //~^ NOTE data moved here + //~| NOTE move occurs because `_b` has type _ => {} } let a = vec[0]; //~ ERROR cannot move out - //~| cannot move out of here + //~| NOTE cannot move out of here + //~| NOTE move occurs because + //~| HELP consider borrowing here } fn e() { let mut vec = vec![box 1, box 2, box 3]; let vec: &mut [Box] = &mut vec; match vec { - &mut [_a, _b, _c] => {} //~ ERROR cannot move out - //~| cannot move out + //~^ ERROR cannot move out + //~| NOTE cannot move out + &mut [_a, _b, _c] => {} + //~^ NOTE data moved here + //~| NOTE and here + //~| NOTE and here + //~| HELP consider removing the `&mut` + //~| NOTE move occurs because these variables have types _ => {} } let a = vec[0]; //~ ERROR cannot move out - //~| cannot move out of here + //~| NOTE cannot move out of here + //~| NOTE move occurs because + //~| HELP consider borrowing here } fn main() {} diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr index 25825fea15877..072501f23ff84 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -1,84 +1,117 @@ -error[E0506]: cannot assign to `vec[..]` because it is borrowed +error[E0506]: cannot assign to `vec[_]` because it is borrowed --> $DIR/borrowck-vec-pattern-nesting.rs:10:13 | LL | [box ref _a, _, _] => { - | ------ borrow of `vec[..]` occurs here -LL | //~^ borrow of `vec[..]` occurs here -LL | vec[0] = box 4; //~ ERROR cannot assign - | ^^^^^^^^^^^^^^ assignment to borrowed `vec[..]` occurs here + | ------ borrow of `vec[_]` occurs here +LL | +LL | vec[0] = box 4; + | ^^^^^^ assignment to borrowed `vec[_]` occurs here +LL | +LL | _a.use_ref(); + | -- borrow later used here -error[E0506]: cannot assign to `vec[..]` because it is borrowed - --> $DIR/borrowck-vec-pattern-nesting.rs:23:13 +error[E0506]: cannot assign to `vec[_]` because it is borrowed + --> $DIR/borrowck-vec-pattern-nesting.rs:24:13 | LL | &mut [ref _b..] => { - | ------ borrow of `vec[..]` occurs here -LL | //~^ borrow of `vec[..]` occurs here -LL | vec[0] = box 4; //~ ERROR cannot assign - | ^^^^^^^^^^^^^^ assignment to borrowed `vec[..]` occurs here + | ------ borrow of `vec[_]` occurs here +LL | +LL | vec[0] = box 4; + | ^^^^^^ assignment to borrowed `vec[_]` occurs here +LL | +LL | _b.use_ref(); + | -- borrow later used here error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:34:14 + --> $DIR/borrowck-vec-pattern-nesting.rs:35:11 + | +LL | match vec { + | ^^^ cannot move out of here +... +LL | &mut [_a, + | -- + | | + | data moved here + | move occurs because `_a` has type `std::boxed::Box`, which does not implement the `Copy` trait +help: consider removing the `&mut` + | +LL | [_a, +LL | +LL | +LL | +LL | .. +LL | ] => { | -LL | &mut [_a, //~ ERROR cannot move out - | ^-- hint: to prevent move, use `ref _a` or `ref mut _a` - | ______________| - | | -LL | | //~| cannot move out -LL | | //~| to prevent move -LL | | .. -LL | | ] => { - | |_________^ cannot move out of here error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:47:13 | -LL | let a = vec[0]; //~ ERROR cannot move out +LL | let a = vec[0]; | ^^^^^^ | | | cannot move out of here - | help: consider using a reference instead: `&vec[0]` + | move occurs because `vec[_]` has type `std::boxed::Box`, which does not implement the `Copy` trait + | help: consider borrowing here: `&vec[0]` error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:55:14 + --> $DIR/borrowck-vec-pattern-nesting.rs:56:11 + | +LL | match vec { + | ^^^ cannot move out of here +... +LL | _b] => {} + | -- + | | + | data moved here + | move occurs because `_b` has type `std::boxed::Box`, which does not implement the `Copy` trait +help: consider removing the `&mut` + | +LL | [ +LL | +LL | _b] => {} | -LL | &mut [ //~ ERROR cannot move out - | ______________^ -LL | | //~^ cannot move out -LL | | _b] => {} - | |__________--^ cannot move out of here - | | - | hint: to prevent move, use `ref _b` or `ref mut _b` error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:60:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:66:13 | -LL | let a = vec[0]; //~ ERROR cannot move out +LL | let a = vec[0]; | ^^^^^^ | | | cannot move out of here - | help: consider using a reference instead: `&vec[0]` + | move occurs because `vec[_]` has type `std::boxed::Box`, which does not implement the `Copy` trait + | help: consider borrowing here: `&vec[0]` error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:68:14 + --> $DIR/borrowck-vec-pattern-nesting.rs:75:11 + | +LL | match vec { + | ^^^ cannot move out of here +... +LL | &mut [_a, _b, _c] => {} + | ----------------- + | | | | | + | | | | ...and here + | | | ...and here + | | data moved here + | help: consider removing the `&mut`: `[_a, _b, _c]` + | +note: move occurs because these variables have types that don't implement the `Copy` trait + --> $DIR/borrowck-vec-pattern-nesting.rs:78:15 | -LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out - | ^--^^--^^--^ - | || | | - | || | ...and here (use `ref _c` or `ref mut _c`) - | || ...and here (use `ref _b` or `ref mut _b`) - | |hint: to prevent move, use `ref _a` or `ref mut _a` - | cannot move out of here +LL | &mut [_a, _b, _c] => {} + | ^^ ^^ ^^ error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:72:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:86:13 | -LL | let a = vec[0]; //~ ERROR cannot move out +LL | let a = vec[0]; | ^^^^^^ | | | cannot move out of here - | help: consider using a reference instead: `&vec[0]` + | move occurs because `vec[_]` has type `std::boxed::Box`, which does not implement the `Copy` trait + | help: consider borrowing here: `&vec[0]` error: aborting due to 8 previous errors -Some errors occurred: E0506, E0508. +Some errors have detailed explanations: E0506, E0508. For more information about an error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.nll.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.nll.stderr deleted file mode 100644 index d9d3930dc49a7..0000000000000 --- a/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0515]: cannot return value referencing local variable `vec` - --> $DIR/borrowck-vec-pattern-tail-element-loan.rs:10:5 - | -LL | let vec: &[isize] = &vec; //~ ERROR `vec` does not live long enough - | ---- `vec` is borrowed here -... -LL | tail - | ^^^^ returns a value referencing data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs b/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs index b18052a689936..e602e75886d95 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs +++ b/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs @@ -2,12 +2,12 @@ fn a<'a>() -> &'a isize { let vec = vec![1, 2, 3, 4]; - let vec: &[isize] = &vec; //~ ERROR `vec` does not live long enough + let vec: &[isize] = &vec; let tail = match vec { &[_a, ref tail..] => &tail[0], _ => panic!("foo") }; - tail + tail //~ ERROR cannot return value referencing local variable `vec` } fn main() { diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.stderr index a4584aac0e8d7..c1290a6f63f33 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.stderr @@ -1,18 +1,12 @@ -error[E0597]: `vec` does not live long enough - --> $DIR/borrowck-vec-pattern-tail-element-loan.rs:5:26 +error[E0515]: cannot return value referencing local variable `vec` + --> $DIR/borrowck-vec-pattern-tail-element-loan.rs:10:5 | -LL | let vec: &[isize] = &vec; //~ ERROR `vec` does not live long enough - | ^^^ borrowed value does not live long enough +LL | let vec: &[isize] = &vec; + | ---- `vec` is borrowed here ... -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 3:6... - --> $DIR/borrowck-vec-pattern-tail-element-loan.rs:3:6 - | -LL | fn a<'a>() -> &'a isize { - | ^^ +LL | tail + | ^^^^ returns a value referencing data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/borrowck-while-break.nll.stderr b/src/test/ui/borrowck/borrowck-while-break.nll.stderr deleted file mode 100644 index 1defa3da60ce8..0000000000000 --- a/src/test/ui/borrowck/borrowck-while-break.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `v` - --> $DIR/borrowck-while-break.rs:7:20 - | -LL | println!("{}", v); //~ ERROR use of possibly uninitialized variable: `v` - | ^ use of possibly uninitialized `v` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-while-break.rs b/src/test/ui/borrowck/borrowck-while-break.rs index 293760efba5e5..e16bc58656d81 100644 --- a/src/test/ui/borrowck/borrowck-while-break.rs +++ b/src/test/ui/borrowck/borrowck-while-break.rs @@ -4,7 +4,7 @@ fn test(cond: bool) { v = 3; break; } - println!("{}", v); //~ ERROR use of possibly uninitialized variable: `v` + println!("{}", v); //~ ERROR borrow of possibly uninitialized variable: `v` } fn main() { diff --git a/src/test/ui/borrowck/borrowck-while-break.stderr b/src/test/ui/borrowck/borrowck-while-break.stderr index f35d43162b244..0fe3cdc96a874 100644 --- a/src/test/ui/borrowck/borrowck-while-break.stderr +++ b/src/test/ui/borrowck/borrowck-while-break.stderr @@ -1,7 +1,7 @@ -error[E0381]: use of possibly uninitialized variable: `v` +error[E0381]: borrow of possibly uninitialized variable: `v` --> $DIR/borrowck-while-break.rs:7:20 | -LL | println!("{}", v); //~ ERROR use of possibly uninitialized variable: `v` +LL | println!("{}", v); | ^ use of possibly uninitialized `v` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-while-cond.stderr b/src/test/ui/borrowck/borrowck-while-cond.stderr index 2b5414b42cd0d..06deae345ab60 100644 --- a/src/test/ui/borrowck/borrowck-while-cond.stderr +++ b/src/test/ui/borrowck/borrowck-while-cond.stderr @@ -1,7 +1,7 @@ error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-while-cond.rs:3:11 | -LL | while x { } //~ ERROR use of possibly uninitialized variable: `x` +LL | while x { } | ^ use of possibly uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-while.stderr b/src/test/ui/borrowck/borrowck-while.stderr index e8aff0d22c2c0..60622d648dd23 100644 --- a/src/test/ui/borrowck/borrowck-while.stderr +++ b/src/test/ui/borrowck/borrowck-while.stderr @@ -1,7 +1,7 @@ error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/borrowck-while.rs:4:12 | -LL | return x; //~ ERROR use of possibly uninitialized variable: `x` +LL | return x; | ^ use of possibly uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/immutable-arg.rs b/src/test/ui/borrowck/immutable-arg.rs index 5a5e619ef31f2..2352d1bbe6456 100644 --- a/src/test/ui/borrowck/immutable-arg.rs +++ b/src/test/ui/borrowck/immutable-arg.rs @@ -1,10 +1,6 @@ -//compile-flags: -Z borrowck=compare - fn foo(_x: u32) { _x = 4; - //~^ ERROR cannot assign to immutable argument `_x` (Mir) - //~^^ ERROR cannot assign twice to immutable variable `_x` (Ast) + //~^ ERROR cannot assign to immutable argument `_x` } fn main() {} - diff --git a/src/test/ui/borrowck/immutable-arg.stderr b/src/test/ui/borrowck/immutable-arg.stderr index 8b21e92666674..7255ca327e753 100644 --- a/src/test/ui/borrowck/immutable-arg.stderr +++ b/src/test/ui/borrowck/immutable-arg.stderr @@ -1,19 +1,11 @@ -error[E0384]: cannot assign twice to immutable variable `_x` (Ast) - --> $DIR/immutable-arg.rs:4:5 - | -LL | fn foo(_x: u32) { - | -- first assignment to `_x` -LL | _x = 4; - | ^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign to immutable argument `_x` (Mir) - --> $DIR/immutable-arg.rs:4:5 +error[E0384]: cannot assign to immutable argument `_x` + --> $DIR/immutable-arg.rs:2:5 | LL | fn foo(_x: u32) { | -- help: make this binding mutable: `mut _x` LL | _x = 4; | ^^^^^^ cannot assign to immutable argument -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/borrowck/index-mut-help-with-impl.nll.stderr b/src/test/ui/borrowck/index-mut-help-with-impl.nll.stderr deleted file mode 100644 index cd88e25cc42c7..0000000000000 --- a/src/test/ui/borrowck/index-mut-help-with-impl.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/index-mut-help-with-impl.rs:9:5 - | -LL | Index::index(&v, 1..2).make_ascii_uppercase(); //~ ERROR - | ^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable - | - = help: trait `IndexMut` is required to modify indexed content - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/index-mut-help-with-impl.stderr b/src/test/ui/borrowck/index-mut-help-with-impl.stderr index 260ef7c92d0f5..4b29beb02b35e 100644 --- a/src/test/ui/borrowck/index-mut-help-with-impl.stderr +++ b/src/test/ui/borrowck/index-mut-help-with-impl.stderr @@ -1,8 +1,10 @@ -error[E0596]: cannot borrow immutable borrowed content as mutable +error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/index-mut-help-with-impl.rs:9:5 | -LL | Index::index(&v, 1..2).make_ascii_uppercase(); //~ ERROR +LL | Index::index(&v, 1..2).make_ascii_uppercase(); | ^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | + = help: trait `IndexMut` is required to modify indexed content error: aborting due to previous error diff --git a/src/test/ui/borrowck/index-mut-help.nll.stderr b/src/test/ui/borrowck/index-mut-help.nll.stderr deleted file mode 100644 index e7047f0048db3..0000000000000 --- a/src/test/ui/borrowck/index-mut-help.nll.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/index-mut-help.rs:11:5 - | -LL | map["peter"].clear(); //~ ERROR - | ^^^^^^^^^^^^ cannot borrow as mutable - | - = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>` - -error[E0594]: cannot assign to data in a `&` reference - --> $DIR/index-mut-help.rs:12:5 - | -LL | map["peter"] = "0".to_string(); //~ ERROR - | ^^^^^^^^^^^^ cannot assign - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/index-mut-help.rs:13:13 - | -LL | let _ = &mut map["peter"]; //~ ERROR - | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable - | - = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>` - -error: aborting due to 3 previous errors - -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/index-mut-help.stderr b/src/test/ui/borrowck/index-mut-help.stderr index 985fa9f0361ee..fbc427a6e6d09 100644 --- a/src/test/ui/borrowck/index-mut-help.stderr +++ b/src/test/ui/borrowck/index-mut-help.stderr @@ -1,28 +1,25 @@ -error[E0596]: cannot borrow immutable indexed content as mutable +error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/index-mut-help.rs:11:5 | -LL | map["peter"].clear(); //~ ERROR +LL | map["peter"].clear(); | ^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>` -error[E0594]: cannot assign to immutable indexed content +error[E0594]: cannot assign to data in a `&` reference --> $DIR/index-mut-help.rs:12:5 | -LL | map["peter"] = "0".to_string(); //~ ERROR - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable - | - = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>` +LL | map["peter"] = "0".to_string(); + | ^^^^^^^^^^^^ cannot assign -error[E0596]: cannot borrow immutable indexed content as mutable - --> $DIR/index-mut-help.rs:13:18 +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/index-mut-help.rs:13:13 | -LL | let _ = &mut map["peter"]; //~ ERROR - | ^^^^^^^^^^^^ cannot borrow as mutable +LL | let _ = &mut map["peter"]; + | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>` error: aborting due to 3 previous errors -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/issue-10876.rs b/src/test/ui/borrowck/issue-10876.rs new file mode 100644 index 0000000000000..20ab905fec46e --- /dev/null +++ b/src/test/ui/borrowck/issue-10876.rs @@ -0,0 +1,17 @@ +// run-pass + +enum Nat { + S(Box), + Z +} +fn test(x: &mut Nat) { + let mut p = &mut *x; + loop { + match p { + &mut Nat::Z => break, + &mut Nat::S(ref mut n) => p = &mut *n + } + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-41962.rs b/src/test/ui/borrowck/issue-41962.rs index 2bcc074542d17..38a01b138e47d 100644 --- a/src/test/ui/borrowck/issue-41962.rs +++ b/src/test/ui/borrowck/issue-41962.rs @@ -1,13 +1,9 @@ -// compile-flags: -Z borrowck=compare - pub fn main(){ let maybe = Some(vec![true, true]); loop { if let Some(thing) = maybe { } - //~^^ ERROR use of partially moved value: `maybe` (Ast) [E0382] - //~| ERROR use of moved value: `(maybe as std::prelude::v1::Some).0` (Ast) [E0382] - //~| ERROR use of moved value (Mir) [E0382] + //~^^ ERROR use of moved value [E0382] } } diff --git a/src/test/ui/borrowck/issue-41962.stderr b/src/test/ui/borrowck/issue-41962.stderr index fd4d318b5ddf1..422d1605aa46b 100644 --- a/src/test/ui/borrowck/issue-41962.stderr +++ b/src/test/ui/borrowck/issue-41962.stderr @@ -1,29 +1,11 @@ -error[E0382]: use of partially moved value: `maybe` (Ast) - --> $DIR/issue-41962.rs:7:30 - | -LL | if let Some(thing) = maybe { - | ----- ^^^^^ value used here after move - | | - | value moved here - | - = note: move occurs because the value has type `std::vec::Vec`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `(maybe as std::prelude::v1::Some).0` (Ast) - --> $DIR/issue-41962.rs:7:21 - | -LL | if let Some(thing) = maybe { - | ^^^^^ value moved here in previous iteration of loop - | - = note: move occurs because the value has type `std::vec::Vec`, which does not implement the `Copy` trait - -error[E0382]: use of moved value (Mir) - --> $DIR/issue-41962.rs:7:21 +error[E0382]: use of moved value + --> $DIR/issue-41962.rs:5:21 | LL | if let Some(thing) = maybe { | ^^^^^ value moved here, in previous iteration of loop | = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait -error: aborting due to 3 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/issue-45983.ast.stderr b/src/test/ui/borrowck/issue-45983.ast.stderr deleted file mode 100644 index 9cb83c92cae84..0000000000000 --- a/src/test/ui/borrowck/issue-45983.ast.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error: borrowed data cannot be stored outside of its closure - --> $DIR/issue-45983.rs:26:27 - | -LL | let x = None; - | - borrowed data cannot be stored into here... -LL | give_any(|y| x = Some(y)); - | --- ^ cannot be stored outside of its closure - | | - | ...because it cannot outlive this closure - -error: aborting due to previous error - diff --git a/src/test/ui/borrowck/issue-45983.migrate.stderr b/src/test/ui/borrowck/issue-45983.migrate.stderr index 9cb83c92cae84..3a6b2f69a1ffc 100644 --- a/src/test/ui/borrowck/issue-45983.migrate.stderr +++ b/src/test/ui/borrowck/issue-45983.migrate.stderr @@ -1,5 +1,5 @@ error: borrowed data cannot be stored outside of its closure - --> $DIR/issue-45983.rs:26:27 + --> $DIR/issue-45983.rs:19:27 | LL | let x = None; | - borrowed data cannot be stored into here... diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr index 0a03858d568ee..94360b65ffe36 100644 --- a/src/test/ui/borrowck/issue-45983.nll.stderr +++ b/src/test/ui/borrowck/issue-45983.nll.stderr @@ -1,5 +1,5 @@ error[E0521]: borrowed data escapes outside of closure - --> $DIR/issue-45983.rs:26:18 + --> $DIR/issue-45983.rs:19:18 | LL | let x = None; | - `x` is declared here, outside of the closure body @@ -9,7 +9,7 @@ LL | give_any(|y| x = Some(y)); | `y` is a reference that is only valid in the closure body error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-45983.rs:26:18 + --> $DIR/issue-45983.rs:19:18 | LL | let x = None; | - help: consider changing this to be mutable: `mut x` @@ -18,5 +18,3 @@ LL | give_any(|y| x = Some(y)); error: aborting due to 2 previous errors -Some errors occurred: E0521, E0594. -For more information about an error, try `rustc --explain E0521`. diff --git a/src/test/ui/borrowck/issue-45983.rs b/src/test/ui/borrowck/issue-45983.rs index 4dac67d9ae900..a2656f5939aa1 100644 --- a/src/test/ui/borrowck/issue-45983.rs +++ b/src/test/ui/borrowck/issue-45983.rs @@ -1,21 +1,14 @@ // As documented in Issue #45983, this test is evaluating the quality // of our diagnostics on erroneous code using higher-ranked closures. -// -// However, as documented on Issue #53026, this test also became a -// prime example of our need to test the NLL migration mode -// *separately* from the existing test suites that focus solely on -// AST-borrwock and NLL. -// revisions: ast migrate nll +// revisions: migrate nll // Since we are testing nll (and migration) explicitly as a separate // revisions, don't worry about the --compare-mode=nll on this test. // ignore-compare-mode-nll -//[ast]compile-flags: -Z borrowck=ast -//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows -//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows +//[nll]compile-flags: -Z borrowck=mir fn give_any FnOnce(&'r ())>(f: F) { f(&()); @@ -24,8 +17,7 @@ fn give_any FnOnce(&'r ())>(f: F) { fn main() { let x = None; give_any(|y| x = Some(y)); - //[ast]~^ ERROR borrowed data cannot be stored outside of its closure - //[migrate]~^^ ERROR borrowed data cannot be stored outside of its closure - //[nll]~^^^ ERROR borrowed data escapes outside of closure + //[migrate]~^ ERROR borrowed data cannot be stored outside of its closure + //[nll]~^^ ERROR borrowed data escapes outside of closure //[nll]~| ERROR cannot assign to `x`, as it is not declared as mutable } diff --git a/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.nll.stderr b/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.nll.stderr deleted file mode 100644 index 255eb757a4989..0000000000000 --- a/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0507]: cannot move out of static item - --> $DIR/issue-47215-ice-from-drop-elab.rs:17:21 - | -LL | let mut x = X; //~ ERROR cannot move out of thread-local static item [E0507] - | ^ - | | - | cannot move out of static item - | help: consider borrowing here: `&X` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.rs b/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.rs index 7477947b89ca4..e95a6b7c88b95 100644 --- a/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.rs +++ b/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.rs @@ -14,7 +14,7 @@ static mut X: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::AtomicUsiz fn main() { unsafe { - let mut x = X; //~ ERROR cannot move out of thread-local static item [E0507] + let mut x = X; //~ ERROR cannot move out of static item `X` [E0507] let _y = x.get_mut(); } } diff --git a/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.stderr b/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.stderr index 219a1fd2e7727..249a05192b282 100644 --- a/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.stderr +++ b/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.stderr @@ -1,11 +1,11 @@ -error[E0507]: cannot move out of thread-local static item +error[E0507]: cannot move out of static item `X` --> $DIR/issue-47215-ice-from-drop-elab.rs:17:21 | -LL | let mut x = X; //~ ERROR cannot move out of thread-local static item [E0507] +LL | let mut x = X; | ^ | | - | cannot move out of thread-local static item - | help: consider using a reference instead: `&X` + | move occurs because `X` has type `std::sync::atomic::AtomicUsize`, which does not implement the `Copy` trait + | help: consider borrowing here: `&X` error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-51117.nll.stderr b/src/test/ui/borrowck/issue-51117.nll.stderr deleted file mode 100644 index 140be098a99de..0000000000000 --- a/src/test/ui/borrowck/issue-51117.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0499]: cannot borrow `*bar` as mutable more than once at a time - --> $DIR/issue-51117.rs:10:13 - | -LL | Some(baz) => { - | --- first mutable borrow occurs here -LL | bar.take(); //~ ERROR cannot borrow - | ^^^ second mutable borrow occurs here -LL | drop(baz); - | --- first borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/issue-51117.stderr b/src/test/ui/borrowck/issue-51117.stderr index 783ba8df1a6e7..f8a9608ad373a 100644 --- a/src/test/ui/borrowck/issue-51117.stderr +++ b/src/test/ui/borrowck/issue-51117.stderr @@ -3,11 +3,10 @@ error[E0499]: cannot borrow `*bar` as mutable more than once at a time | LL | Some(baz) => { | --- first mutable borrow occurs here -LL | bar.take(); //~ ERROR cannot borrow +LL | bar.take(); | ^^^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here +LL | drop(baz); + | --- first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs b/src/test/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs index a8bfdbad38ba4..7d5acb95751ed 100644 --- a/src/test/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs +++ b/src/test/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs @@ -8,8 +8,6 @@ // run-pass -#![feature(nll)] - fn foo(x: &mut Result<(u32, u32), (u32, u32)>) -> u32 { match *x { Ok((ref mut v, _)) | Err((_, ref mut v)) if *v > 0 => { *v } diff --git a/src/test/ui/borrowck/issue-51415.nll.stderr b/src/test/ui/borrowck/issue-51415.nll.stderr deleted file mode 100644 index b025374257f7c..0000000000000 --- a/src/test/ui/borrowck/issue-51415.nll.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/issue-51415.rs:6:42 - | -LL | let opt = a.iter().enumerate().find(|(_, &s)| { - | ^^^^^-^ - | | | - | | data moved here - | cannot move out of borrowed content - | -note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/issue-51415.rs:6:47 - | -LL | let opt = a.iter().enumerate().find(|(_, &s)| { - | ^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/issue-51415.stderr b/src/test/ui/borrowck/issue-51415.stderr index 895c35e4e776a..96175b1496063 100644 --- a/src/test/ui/borrowck/issue-51415.stderr +++ b/src/test/ui/borrowck/issue-51415.stderr @@ -1,11 +1,11 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/issue-51415.rs:6:46 +error[E0507]: cannot move out of a shared reference + --> $DIR/issue-51415.rs:6:42 | LL | let opt = a.iter().enumerate().find(|(_, &s)| { - | ^- - | || - | |hint: to prevent move, use `ref s` or `ref mut s` - | cannot move out of borrowed content + | ^^^^^-^ + | | + | data moved here + | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-52713-bug.rs b/src/test/ui/borrowck/issue-52713-bug.rs index 460e6b4bbae4d..671e83dfadc8b 100644 --- a/src/test/ui/borrowck/issue-52713-bug.rs +++ b/src/test/ui/borrowck/issue-52713-bug.rs @@ -2,8 +2,6 @@ // computing liveness that wound up accidentally causing the program // below to be accepted. -#![feature(nll)] - fn foo<'a>(x: &'a mut u32) -> u32 { let mut x = 22; let y = &x; diff --git a/src/test/ui/borrowck/issue-52713-bug.stderr b/src/test/ui/borrowck/issue-52713-bug.stderr index 4e6d0d45bf081..4abb6fb2c7186 100644 --- a/src/test/ui/borrowck/issue-52713-bug.stderr +++ b/src/test/ui/borrowck/issue-52713-bug.stderr @@ -1,10 +1,10 @@ error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/issue-52713-bug.rs:14:5 + --> $DIR/issue-52713-bug.rs:12:5 | LL | let y = &x; | -- borrow of `x` occurs here ... -LL | x += 1; //~ ERROR +LL | x += 1; | ^^^^^^ assignment to borrowed `x` occurs here LL | println!("{}", y); | - borrow later used here diff --git a/src/test/ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs b/src/test/ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs index dcf047c545fe9..fc8a075540b3f 100644 --- a/src/test/ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs +++ b/src/test/ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs @@ -2,9 +2,8 @@ // the initial deployment of NLL for the 2018 edition, I forgot to // turn on two-phase-borrows in addition to `-Z borrowck=migrate`. -// revisions: ast zflags edition -//[zflags]compile-flags: -Z borrowck=migrate -Z two-phase-borrows -//[edition]edition:2018 +// revisions: edition2015 edition2018 +//[edition2018]edition:2018 // run-pass diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.ast.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.ast.stderr deleted file mode 100644 index d72cc20971b0e..0000000000000 --- a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.ast.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `t.0` - --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:25:31 - | -LL | println!("{:?} {:?}", t.0, t.1); - | ^^^ use of possibly uninitialized `t.0` - -error[E0381]: use of possibly uninitialized variable: `t.1` - --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:25:36 - | -LL | println!("{:?} {:?}", t.0, t.1); - | ^^^ use of possibly uninitialized `t.1` - -error[E0381]: use of possibly uninitialized variable: `u.0` - --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:35:31 - | -LL | println!("{:?} {:?}", u.0, u.1); - | ^^^ use of possibly uninitialized `u.0` - -error[E0381]: use of possibly uninitialized variable: `u.1` - --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:35:36 - | -LL | println!("{:?} {:?}", u.0, u.1); - | ^^^ use of possibly uninitialized `u.1` - -error[E0381]: use of possibly uninitialized variable: `v.x` - --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:45:31 - | -LL | println!("{:?} {:?}", v.x, v.y); - | ^^^ use of possibly uninitialized `v.x` - -error[E0381]: use of possibly uninitialized variable: `v.y` - --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:45:36 - | -LL | println!("{:?} {:?}", v.x, v.y); - | ^^^ use of possibly uninitialized `v.y` - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.nll.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.nll.stderr deleted file mode 100644 index ebc6c7fca62b9..0000000000000 --- a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0381]: assign to part of possibly uninitialized variable: `t` - --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:22:9 - | -LL | t.0 = S(1); - | ^^^^^^^^^^ use of possibly uninitialized `t` - -error[E0381]: assign to part of possibly uninitialized variable: `u` - --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:32:9 - | -LL | u.0 = S(1); - | ^^^^^^^^^^ use of possibly uninitialized `u` - -error[E0381]: assign to part of possibly uninitialized variable: `v` - --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:42:9 - | -LL | v.x = S(1); - | ^^^^^^^^^^ use of possibly uninitialized `v` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs index 4358e8e440237..8d8ac279b23a8 100644 --- a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs +++ b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs @@ -1,13 +1,3 @@ -// revisions: ast nll - -// Since we are testing nll migration explicitly as a separate -// revision, don't worry about the --compare-mode=nll on this test. - -// ignore-compare-mode-nll - -//[ast]compile-flags: -Z borrowck=ast -//[nll]compile-flags: -Z borrowck=migrate -Z two-phase-borrows - #![warn(unused)] #[derive(Debug)] struct S(i32); @@ -20,30 +10,24 @@ fn main() { { let mut t: Tuple; t.0 = S(1); - //[nll]~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] t.1 = 2; println!("{:?} {:?}", t.0, t.1); - //[ast]~^ ERROR use of possibly uninitialized variable: `t.0` [E0381] - //[ast]~| ERROR use of possibly uninitialized variable: `t.1` [E0381] } { let mut u: Tpair; u.0 = S(1); - //[nll]~^ ERROR assign to part of possibly uninitialized variable: `u` [E0381] + //~^ ERROR assign to part of possibly uninitialized variable: `u` [E0381] u.1 = 2; println!("{:?} {:?}", u.0, u.1); - //[ast]~^ ERROR use of possibly uninitialized variable: `u.0` [E0381] - //[ast]~| ERROR use of possibly uninitialized variable: `u.1` [E0381] } { let mut v: Spair; v.x = S(1); - //[nll]~^ ERROR assign to part of possibly uninitialized variable: `v` [E0381] + //~^ ERROR assign to part of possibly uninitialized variable: `v` [E0381] v.y = 2; println!("{:?} {:?}", v.x, v.y); - //[ast]~^ ERROR use of possibly uninitialized variable: `v.x` [E0381] - //[ast]~| ERROR use of possibly uninitialized variable: `v.y` [E0381] } } diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr new file mode 100644 index 0000000000000..6f18ff161372a --- /dev/null +++ b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr @@ -0,0 +1,21 @@ +error[E0381]: assign to part of possibly uninitialized variable: `t` + --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:12:9 + | +LL | t.0 = S(1); + | ^^^^^^^^^^ use of possibly uninitialized `t` + +error[E0381]: assign to part of possibly uninitialized variable: `u` + --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:20:9 + | +LL | u.0 = S(1); + | ^^^^^^^^^^ use of possibly uninitialized `u` + +error[E0381]: assign to part of possibly uninitialized variable: `v` + --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:28:9 + | +LL | v.x = S(1); + | ^^^^^^^^^^ use of possibly uninitialized `v` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.ast.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.ast.stderr deleted file mode 100644 index 4f845d87aa2f8..0000000000000 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.ast.stderr +++ /dev/null @@ -1,69 +0,0 @@ -error[E0382]: use of moved value: `t.0` - --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:26:31 - | -LL | drop(t); - | - value moved here -... -LL | println!("{:?} {:?}", t.0, t.1); - | ^^^ value used here after move - | - = note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `t.1` - --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:26:36 - | -LL | drop(t); - | - value moved here -... -LL | println!("{:?} {:?}", t.0, t.1); - | ^^^ value used here after move - | - = note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `u.0` - --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:37:31 - | -LL | drop(u); - | - value moved here -... -LL | println!("{:?} {:?}", u.0, u.1); - | ^^^ value used here after move - | - = note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `u.1` - --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:37:36 - | -LL | drop(u); - | - value moved here -... -LL | println!("{:?} {:?}", u.0, u.1); - | ^^^ value used here after move - | - = note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `v.x` - --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:48:31 - | -LL | drop(v); - | - value moved here -... -LL | println!("{:?} {:?}", v.x, v.y); - | ^^^ value used here after move - | - = note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `v.y` - --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:48:36 - | -LL | drop(v); - | - value moved here -... -LL | println!("{:?} {:?}", v.x, v.y); - | ^^^ value used here after move - | - = note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.nll.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.nll.stderr deleted file mode 100644 index 42aa038170238..0000000000000 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.nll.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0382]: assign to part of moved value: `t` - --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:23:9 - | -LL | let mut t: Tuple = (S(0), 0); - | ----- move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait -LL | drop(t); - | - value moved here -LL | t.0 = S(1); - | ^^^^^^^^^^ value partially assigned here after move - -error[E0382]: assign to part of moved value: `u` - --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:34:9 - | -LL | let mut u: Tpair = Tpair(S(0), 0); - | ----- move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait -LL | drop(u); - | - value moved here -LL | u.0 = S(1); - | ^^^^^^^^^^ value partially assigned here after move - -error[E0382]: assign to part of moved value: `v` - --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:45:9 - | -LL | let mut v: Spair = Spair { x: S(0), y: 0 }; - | ----- move occurs because `v` has type `Spair`, which does not implement the `Copy` trait -LL | drop(v); - | - value moved here -LL | v.x = S(1); - | ^^^^^^^^^^ value partially assigned here after move - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs index 358a5dd1cbdcf..f7fb2fd4da914 100644 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs +++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs @@ -1,13 +1,3 @@ -// revisions: ast nll - -// Since we are testing nll migration explicitly as a separate -// revision, don't worry about the --compare-mode=nll on this test. - -// ignore-compare-mode-nll - -//[ast]compile-flags: -Z borrowck=ast -//[nll]compile-flags: -Z borrowck=migrate -Z two-phase-borrows - #![warn(unused)] #[derive(Debug)] struct S(i32); @@ -21,32 +11,26 @@ fn main() { let mut t: Tuple = (S(0), 0); drop(t); t.0 = S(1); - //[nll]~^ ERROR assign to part of moved value + //~^ ERROR assign to part of moved value t.1 = 2; println!("{:?} {:?}", t.0, t.1); - //[ast]~^ ERROR use of moved value - //[ast]~^^ ERROR use of moved value } { let mut u: Tpair = Tpair(S(0), 0); drop(u); u.0 = S(1); - //[nll]~^ ERROR assign to part of moved value + //~^ ERROR assign to part of moved value u.1 = 2; println!("{:?} {:?}", u.0, u.1); - //[ast]~^ ERROR use of moved value - //[ast]~^^ ERROR use of moved value } { let mut v: Spair = Spair { x: S(0), y: 0 }; drop(v); v.x = S(1); - //[nll]~^ ERROR assign to part of moved value + //~^ ERROR assign to part of moved value v.y = 2; println!("{:?} {:?}", v.x, v.y); - //[ast]~^ ERROR use of moved value - //[ast]~^^ ERROR use of moved value } } diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr new file mode 100644 index 0000000000000..b188766e221be --- /dev/null +++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr @@ -0,0 +1,33 @@ +error[E0382]: assign to part of moved value: `t` + --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:13:9 + | +LL | let mut t: Tuple = (S(0), 0); + | ----- move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait +LL | drop(t); + | - value moved here +LL | t.0 = S(1); + | ^^^^^^^^^^ value partially assigned here after move + +error[E0382]: assign to part of moved value: `u` + --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:22:9 + | +LL | let mut u: Tpair = Tpair(S(0), 0); + | ----- move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait +LL | drop(u); + | - value moved here +LL | u.0 = S(1); + | ^^^^^^^^^^ value partially assigned here after move + +error[E0382]: assign to part of moved value: `v` + --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:31:9 + | +LL | let mut v: Spair = Spair { x: S(0), y: 0 }; + | ----- move occurs because `v` has type `Spair`, which does not implement the `Copy` trait +LL | drop(v); + | - value moved here +LL | v.x = S(1); + | ^^^^^^^^^^ value partially assigned here after move + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.ast.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.ast.stderr deleted file mode 100644 index 565272af39049..0000000000000 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.ast.stderr +++ /dev/null @@ -1,124 +0,0 @@ -error[E0594]: cannot assign to field `t.0` of immutable binding - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:23:9 - | -LL | let t: Tuple = (S(0), 0); - | - help: make this binding mutable: `mut t` -LL | drop(t); -LL | t.0 = S(1); - | ^^^^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0594]: cannot assign to field `t.1` of immutable binding - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9 - | -LL | let t: Tuple = (S(0), 0); - | - help: make this binding mutable: `mut t` -... -LL | t.1 = 2; - | ^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0594]: cannot assign to field `u.0` of immutable binding - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9 - | -LL | let u: Tpair = Tpair(S(0), 0); - | - help: make this binding mutable: `mut u` -LL | drop(u); -LL | u.0 = S(1); - | ^^^^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0594]: cannot assign to field `u.1` of immutable binding - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:42:9 - | -LL | let u: Tpair = Tpair(S(0), 0); - | - help: make this binding mutable: `mut u` -... -LL | u.1 = 2; - | ^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0594]: cannot assign to field `v.x` of immutable binding - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:53:9 - | -LL | let v: Spair = Spair { x: S(0), y: 0 }; - | - help: make this binding mutable: `mut v` -LL | drop(v); -LL | v.x = S(1); - | ^^^^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0594]: cannot assign to field `v.y` of immutable binding - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:57:9 - | -LL | let v: Spair = Spair { x: S(0), y: 0 }; - | - help: make this binding mutable: `mut v` -... -LL | v.y = 2; - | ^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0382]: use of moved value: `t.0` - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:30:31 - | -LL | drop(t); - | - value moved here -... -LL | println!("{:?} {:?}", t.0, t.1); - | ^^^ value used here after move - | - = note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `t.1` - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:30:36 - | -LL | drop(t); - | - value moved here -... -LL | println!("{:?} {:?}", t.0, t.1); - | ^^^ value used here after move - | - = note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `u.0` - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:45:31 - | -LL | drop(u); - | - value moved here -... -LL | println!("{:?} {:?}", u.0, u.1); - | ^^^ value used here after move - | - = note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `u.1` - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:45:36 - | -LL | drop(u); - | - value moved here -... -LL | println!("{:?} {:?}", u.0, u.1); - | ^^^ value used here after move - | - = note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `v.x` - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:60:31 - | -LL | drop(v); - | - value moved here -... -LL | println!("{:?} {:?}", v.x, v.y); - | ^^^ value used here after move - | - = note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `v.y` - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:60:36 - | -LL | drop(v); - | - value moved here -... -LL | println!("{:?} {:?}", v.x, v.y); - | ^^^ value used here after move - | - = note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait - -error: aborting due to 12 previous errors - -Some errors occurred: E0382, E0594. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.nll.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.nll.stderr deleted file mode 100644 index 1184907f307cb..0000000000000 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.nll.stderr +++ /dev/null @@ -1,88 +0,0 @@ -error[E0594]: cannot assign to `t.0`, as `t` is not declared as mutable - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:23:9 - | -LL | let t: Tuple = (S(0), 0); - | - help: consider changing this to be mutable: `mut t` -LL | drop(t); -LL | t.0 = S(1); - | ^^^^^^^^^^ cannot assign - -error[E0382]: assign to part of moved value: `t` - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:23:9 - | -LL | let t: Tuple = (S(0), 0); - | - move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait -LL | drop(t); - | - value moved here -LL | t.0 = S(1); - | ^^^^^^^^^^ value partially assigned here after move - -error[E0594]: cannot assign to `t.1`, as `t` is not declared as mutable - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9 - | -LL | let t: Tuple = (S(0), 0); - | - help: consider changing this to be mutable: `mut t` -... -LL | t.1 = 2; - | ^^^^^^^ cannot assign - -error[E0594]: cannot assign to `u.0`, as `u` is not declared as mutable - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9 - | -LL | let u: Tpair = Tpair(S(0), 0); - | - help: consider changing this to be mutable: `mut u` -LL | drop(u); -LL | u.0 = S(1); - | ^^^^^^^^^^ cannot assign - -error[E0382]: assign to part of moved value: `u` - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9 - | -LL | let u: Tpair = Tpair(S(0), 0); - | - move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait -LL | drop(u); - | - value moved here -LL | u.0 = S(1); - | ^^^^^^^^^^ value partially assigned here after move - -error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:42:9 - | -LL | let u: Tpair = Tpair(S(0), 0); - | - help: consider changing this to be mutable: `mut u` -... -LL | u.1 = 2; - | ^^^^^^^ cannot assign - -error[E0594]: cannot assign to `v.x`, as `v` is not declared as mutable - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:53:9 - | -LL | let v: Spair = Spair { x: S(0), y: 0 }; - | - help: consider changing this to be mutable: `mut v` -LL | drop(v); -LL | v.x = S(1); - | ^^^^^^^^^^ cannot assign - -error[E0382]: assign to part of moved value: `v` - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:53:9 - | -LL | let v: Spair = Spair { x: S(0), y: 0 }; - | - move occurs because `v` has type `Spair`, which does not implement the `Copy` trait -LL | drop(v); - | - value moved here -LL | v.x = S(1); - | ^^^^^^^^^^ value partially assigned here after move - -error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable - --> $DIR/issue-54499-field-mutation-of-moved-out.rs:57:9 - | -LL | let v: Spair = Spair { x: S(0), y: 0 }; - | - help: consider changing this to be mutable: `mut v` -... -LL | v.y = 2; - | ^^^^^^^ cannot assign - -error: aborting due to 9 previous errors - -Some errors occurred: E0382, E0594. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs index b19dcd65a6c7e..498ca01e9729f 100644 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs +++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs @@ -1,13 +1,3 @@ -// revisions: ast nll - -// Since we are testing nll migration explicitly as a separate -// revision, don't worry about the --compare-mode=nll on this test. - -// ignore-compare-mode-nll - -//[ast]compile-flags: -Z borrowck=ast -//[nll]compile-flags: -Z borrowck=migrate -Z two-phase-borrows - #![warn(unused)] #[derive(Debug)] struct S(i32); @@ -21,44 +11,32 @@ fn main() { let t: Tuple = (S(0), 0); drop(t); t.0 = S(1); - //[ast]~^ ERROR cannot assign to field `t.0` of immutable binding [E0594] - //[nll]~^^ ERROR assign to part of moved value: `t` [E0382] - //[nll]~| ERROR cannot assign to `t.0`, as `t` is not declared as mutable [E0594] + //~^ ERROR assign to part of moved value: `t` [E0382] + //~| ERROR cannot assign to `t.0`, as `t` is not declared as mutable [E0594] t.1 = 2; - //[ast]~^ ERROR cannot assign to field `t.1` of immutable binding [E0594] - //[nll]~^^ ERROR cannot assign to `t.1`, as `t` is not declared as mutable [E0594] + //~^ ERROR cannot assign to `t.1`, as `t` is not declared as mutable [E0594] println!("{:?} {:?}", t.0, t.1); - //[ast]~^ ERROR use of moved value: `t.0` [E0382] - //[ast]~| ERROR use of moved value: `t.1` [E0382] } { let u: Tpair = Tpair(S(0), 0); drop(u); u.0 = S(1); - //[ast]~^ ERROR cannot assign to field `u.0` of immutable binding [E0594] - //[nll]~^^ ERROR assign to part of moved value: `u` [E0382] - //[nll]~| ERROR cannot assign to `u.0`, as `u` is not declared as mutable [E0594] + //~^ ERROR assign to part of moved value: `u` [E0382] + //~| ERROR cannot assign to `u.0`, as `u` is not declared as mutable [E0594] u.1 = 2; - //[ast]~^ ERROR cannot assign to field `u.1` of immutable binding [E0594] - //[nll]~^^ ERROR cannot assign to `u.1`, as `u` is not declared as mutable [E0594] + //~^ ERROR cannot assign to `u.1`, as `u` is not declared as mutable [E0594] println!("{:?} {:?}", u.0, u.1); - //[ast]~^ ERROR use of moved value: `u.0` [E0382] - //[ast]~| ERROR use of moved value: `u.1` [E0382] } { let v: Spair = Spair { x: S(0), y: 0 }; drop(v); v.x = S(1); - //[ast]~^ ERROR cannot assign to field `v.x` of immutable binding [E0594] - //[nll]~^^ ERROR assign to part of moved value: `v` [E0382] - //[nll]~| ERROR cannot assign to `v.x`, as `v` is not declared as mutable [E0594] + //~^ ERROR assign to part of moved value: `v` [E0382] + //~| ERROR cannot assign to `v.x`, as `v` is not declared as mutable [E0594] v.y = 2; - //[ast]~^ ERROR cannot assign to field `v.y` of immutable binding [E0594] - //[nll]~^^ ERROR cannot assign to `v.y`, as `v` is not declared as mutable [E0594] + //~^ ERROR cannot assign to `v.y`, as `v` is not declared as mutable [E0594] println!("{:?} {:?}", v.x, v.y); - //[ast]~^ ERROR use of moved value: `v.x` [E0382] - //[ast]~| ERROR use of moved value: `v.y` [E0382] } } diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr new file mode 100644 index 0000000000000..7dfd71c81c30d --- /dev/null +++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr @@ -0,0 +1,87 @@ +error[E0594]: cannot assign to `t.0`, as `t` is not declared as mutable + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9 + | +LL | let t: Tuple = (S(0), 0); + | - help: consider changing this to be mutable: `mut t` +LL | drop(t); +LL | t.0 = S(1); + | ^^^^^^^^^^ cannot assign + +error[E0382]: assign to part of moved value: `t` + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9 + | +LL | let t: Tuple = (S(0), 0); + | - move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait +LL | drop(t); + | - value moved here +LL | t.0 = S(1); + | ^^^^^^^^^^ value partially assigned here after move + +error[E0594]: cannot assign to `t.1`, as `t` is not declared as mutable + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:16:9 + | +LL | let t: Tuple = (S(0), 0); + | - help: consider changing this to be mutable: `mut t` +... +LL | t.1 = 2; + | ^^^^^^^ cannot assign + +error[E0594]: cannot assign to `u.0`, as `u` is not declared as mutable + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9 + | +LL | let u: Tpair = Tpair(S(0), 0); + | - help: consider changing this to be mutable: `mut u` +LL | drop(u); +LL | u.0 = S(1); + | ^^^^^^^^^^ cannot assign + +error[E0382]: assign to part of moved value: `u` + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9 + | +LL | let u: Tpair = Tpair(S(0), 0); + | - move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait +LL | drop(u); + | - value moved here +LL | u.0 = S(1); + | ^^^^^^^^^^ value partially assigned here after move + +error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9 + | +LL | let u: Tpair = Tpair(S(0), 0); + | - help: consider changing this to be mutable: `mut u` +... +LL | u.1 = 2; + | ^^^^^^^ cannot assign + +error[E0594]: cannot assign to `v.x`, as `v` is not declared as mutable + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9 + | +LL | let v: Spair = Spair { x: S(0), y: 0 }; + | - help: consider changing this to be mutable: `mut v` +LL | drop(v); +LL | v.x = S(1); + | ^^^^^^^^^^ cannot assign + +error[E0382]: assign to part of moved value: `v` + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9 + | +LL | let v: Spair = Spair { x: S(0), y: 0 }; + | - move occurs because `v` has type `Spair`, which does not implement the `Copy` trait +LL | drop(v); + | - value moved here +LL | v.x = S(1); + | ^^^^^^^^^^ value partially assigned here after move + +error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9 + | +LL | let v: Spair = Spair { x: S(0), y: 0 }; + | - help: consider changing this to be mutable: `mut v` +... +LL | v.y = 2; + | ^^^^^^^ cannot assign + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.ast.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.ast.stderr deleted file mode 100644 index ea6b63b7a297d..0000000000000 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.ast.stderr +++ /dev/null @@ -1,91 +0,0 @@ -error[E0594]: cannot assign to field `t.0` of immutable binding - --> $DIR/issue-54499-field-mutation-of-never-init.rs:22:9 - | -LL | let t: Tuple; - | - help: make this binding mutable: `mut t` -LL | t.0 = S(1); - | ^^^^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0594]: cannot assign to field `t.1` of immutable binding - --> $DIR/issue-54499-field-mutation-of-never-init.rs:25:9 - | -LL | let t: Tuple; - | - help: make this binding mutable: `mut t` -... -LL | t.1 = 2; - | ^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0594]: cannot assign to field `u.0` of immutable binding - --> $DIR/issue-54499-field-mutation-of-never-init.rs:34:9 - | -LL | let u: Tpair; - | - help: make this binding mutable: `mut u` -LL | u.0 = S(1); - | ^^^^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0594]: cannot assign to field `u.1` of immutable binding - --> $DIR/issue-54499-field-mutation-of-never-init.rs:37:9 - | -LL | let u: Tpair; - | - help: make this binding mutable: `mut u` -... -LL | u.1 = 2; - | ^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0594]: cannot assign to field `v.x` of immutable binding - --> $DIR/issue-54499-field-mutation-of-never-init.rs:46:9 - | -LL | let v: Spair; - | - help: make this binding mutable: `mut v` -LL | v.x = S(1); - | ^^^^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0594]: cannot assign to field `v.y` of immutable binding - --> $DIR/issue-54499-field-mutation-of-never-init.rs:49:9 - | -LL | let v: Spair; - | - help: make this binding mutable: `mut v` -... -LL | v.y = 2; - | ^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0381]: use of possibly uninitialized variable: `t.0` - --> $DIR/issue-54499-field-mutation-of-never-init.rs:27:31 - | -LL | println!("{:?} {:?}", t.0, t.1); - | ^^^ use of possibly uninitialized `t.0` - -error[E0381]: use of possibly uninitialized variable: `t.1` - --> $DIR/issue-54499-field-mutation-of-never-init.rs:27:36 - | -LL | println!("{:?} {:?}", t.0, t.1); - | ^^^ use of possibly uninitialized `t.1` - -error[E0381]: use of possibly uninitialized variable: `u.0` - --> $DIR/issue-54499-field-mutation-of-never-init.rs:39:31 - | -LL | println!("{:?} {:?}", u.0, u.1); - | ^^^ use of possibly uninitialized `u.0` - -error[E0381]: use of possibly uninitialized variable: `u.1` - --> $DIR/issue-54499-field-mutation-of-never-init.rs:39:36 - | -LL | println!("{:?} {:?}", u.0, u.1); - | ^^^ use of possibly uninitialized `u.1` - -error[E0381]: use of possibly uninitialized variable: `v.x` - --> $DIR/issue-54499-field-mutation-of-never-init.rs:51:31 - | -LL | println!("{:?} {:?}", v.x, v.y); - | ^^^ use of possibly uninitialized `v.x` - -error[E0381]: use of possibly uninitialized variable: `v.y` - --> $DIR/issue-54499-field-mutation-of-never-init.rs:51:36 - | -LL | println!("{:?} {:?}", v.x, v.y); - | ^^^ use of possibly uninitialized `v.y` - -error: aborting due to 12 previous errors - -Some errors occurred: E0381, E0594. -For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.nll.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.nll.stderr deleted file mode 100644 index 3dc2b5b3b8f9f..0000000000000 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0381]: assign to part of possibly uninitialized variable: `t` - --> $DIR/issue-54499-field-mutation-of-never-init.rs:22:9 - | -LL | t.0 = S(1); - | ^^^^^^^^^^ use of possibly uninitialized `t` - -error[E0381]: assign to part of possibly uninitialized variable: `u` - --> $DIR/issue-54499-field-mutation-of-never-init.rs:34:9 - | -LL | u.0 = S(1); - | ^^^^^^^^^^ use of possibly uninitialized `u` - -error[E0381]: assign to part of possibly uninitialized variable: `v` - --> $DIR/issue-54499-field-mutation-of-never-init.rs:46:9 - | -LL | v.x = S(1); - | ^^^^^^^^^^ use of possibly uninitialized `v` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs index 03eb9621ee215..1a1b376bf9bcf 100644 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs +++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs @@ -1,13 +1,3 @@ -// revisions: ast nll - -// Since we are testing nll migration explicitly as a separate -// revision, don't worry about the --compare-mode=nll on this test. - -// ignore-compare-mode-nll - -//[ast]compile-flags: -Z borrowck=ast -//[nll]compile-flags: -Z borrowck=migrate -Z two-phase-borrows - #![warn(unused)] #[derive(Debug)] struct S(i32); @@ -20,36 +10,24 @@ fn main() { { let t: Tuple; t.0 = S(1); - //[ast]~^ ERROR cannot assign to field `t.0` of immutable binding [E0594] - //[nll]~^^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] + //~^ ERROR assign to part of possibly uninitialized variable: `t` [E0381] t.1 = 2; - //[ast]~^ ERROR cannot assign to field `t.1` of immutable binding [E0594] println!("{:?} {:?}", t.0, t.1); - //[ast]~^ ERROR use of possibly uninitialized variable: `t.0` [E0381] - //[ast]~| ERROR use of possibly uninitialized variable: `t.1` [E0381] } { let u: Tpair; u.0 = S(1); - //[ast]~^ ERROR cannot assign to field `u.0` of immutable binding [E0594] - //[nll]~^^ ERROR assign to part of possibly uninitialized variable: `u` [E0381] + //~^ ERROR assign to part of possibly uninitialized variable: `u` [E0381] u.1 = 2; - //[ast]~^ ERROR cannot assign to field `u.1` of immutable binding [E0594] println!("{:?} {:?}", u.0, u.1); - //[ast]~^ ERROR use of possibly uninitialized variable: `u.0` [E0381] - //[ast]~| ERROR use of possibly uninitialized variable: `u.1` [E0381] } { let v: Spair; v.x = S(1); - //[ast]~^ ERROR cannot assign to field `v.x` of immutable binding [E0594] - //[nll]~^^ ERROR assign to part of possibly uninitialized variable: `v` [E0381] + //~^ ERROR assign to part of possibly uninitialized variable: `v` [E0381] v.y = 2; - //[ast]~^ ERROR cannot assign to field `v.y` of immutable binding [E0594] println!("{:?} {:?}", v.x, v.y); - //[ast]~^ ERROR use of possibly uninitialized variable: `v.x` [E0381] - //[ast]~| ERROR use of possibly uninitialized variable: `v.y` [E0381] } } diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr new file mode 100644 index 0000000000000..68873ac5c02e2 --- /dev/null +++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr @@ -0,0 +1,21 @@ +error[E0381]: assign to part of possibly uninitialized variable: `t` + --> $DIR/issue-54499-field-mutation-of-never-init.rs:12:9 + | +LL | t.0 = S(1); + | ^^^^^^^^^^ use of possibly uninitialized `t` + +error[E0381]: assign to part of possibly uninitialized variable: `u` + --> $DIR/issue-54499-field-mutation-of-never-init.rs:20:9 + | +LL | u.0 = S(1); + | ^^^^^^^^^^ use of possibly uninitialized `u` + +error[E0381]: assign to part of possibly uninitialized variable: `v` + --> $DIR/issue-54499-field-mutation-of-never-init.rs:28:9 + | +LL | v.x = S(1); + | ^^^^^^^^^^ use of possibly uninitialized `v` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs index ad4accbbeeef9..3e46ee6f0789a 100644 --- a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs +++ b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - #![allow(dead_code)] #[derive(Debug)] @@ -13,7 +11,7 @@ impl Value { fn foo(val: Value) { let _reviewers_original: Vec = match val.as_array() { Some(array) => { - *array //~ ERROR cannot move out of borrowed content + *array //~ ERROR cannot move out of `*array` } None => vec![] }; diff --git a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr index d1d7d13088bcc..78d44f3206199 100644 --- a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr +++ b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr @@ -1,11 +1,11 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/issue-54597-reject-move-out-of-borrow-via-pat.rs:16:13 +error[E0507]: cannot move out of `*array` which is behind a shared reference + --> $DIR/issue-54597-reject-move-out-of-borrow-via-pat.rs:14:13 | -LL | *array //~ ERROR cannot move out of borrowed content +LL | *array | ^^^^^^ | | - | cannot move out of borrowed content - | help: consider removing the `*`: `array` + | move occurs because `*array` has type `std::vec::Vec`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*array` error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.ast.stderr b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.ast.stderr deleted file mode 100644 index f3e9ce364d9b4..0000000000000 --- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.ast.stderr +++ /dev/null @@ -1,55 +0,0 @@ -error[E0595]: closure cannot assign to immutable argument `x` - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:21:22 - | -LL | let mut c1 = |y: &'static mut isize| x = y; - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow mutably -help: consider removing the `&mut`, as it is an immutable binding to a mutable reference - | -LL | x - | - -error[E0595]: closure cannot assign to immutable argument `x` - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:32:22 - | -LL | let mut c1 = |z: &'static mut isize| { - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow mutably -help: consider removing the `&mut`, as it is an immutable binding to a mutable reference - | -LL | x - | - -error[E0595]: closure cannot assign to immutable argument `x` - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:46:9 - | -LL | pub fn capture_assign_whole(x: (i32,)) { - | - help: make this binding mutable: `mut x` -LL | || { x = (1,); }; - | ^^ cannot borrow mutably - -error[E0595]: closure cannot assign to immutable argument `x` - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:52:9 - | -LL | pub fn capture_assign_part(x: (i32,)) { - | - help: make this binding mutable: `mut x` -LL | || { x.0 = 1; }; - | ^^ cannot borrow mutably - -error[E0595]: closure cannot assign to immutable argument `x` - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:58:9 - | -LL | pub fn capture_reborrow_whole(x: (i32,)) { - | - help: make this binding mutable: `mut x` -LL | || { &mut x; }; - | ^^ cannot borrow mutably - -error[E0595]: closure cannot assign to immutable argument `x` - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:64:9 - | -LL | pub fn capture_reborrow_part(x: (i32,)) { - | - help: make this binding mutable: `mut x` -LL | || { &mut x.0; }; - | ^^ cannot borrow mutably - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0595`. diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr index 434f318ad1449..f1d28eed922af 100644 --- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr +++ b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr @@ -1,5 +1,5 @@ error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:21:46 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:46 | LL | pub fn e(x: &'static mut isize) { | - help: consider changing this to be mutable: `mut x` @@ -8,7 +8,7 @@ LL | let mut c1 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:34:50 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:50 | LL | pub fn ee(x: &'static mut isize) { | - help: consider changing this to be mutable: `mut x` @@ -17,7 +17,7 @@ LL | let mut c2 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:46:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14 | LL | pub fn capture_assign_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -25,7 +25,7 @@ LL | || { x = (1,); }; | ^^^^^^^^ cannot assign error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:52:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:47:14 | LL | pub fn capture_assign_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -33,7 +33,7 @@ LL | || { x.0 = 1; }; | ^^^^^^^ cannot assign error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:58:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:52:14 | LL | pub fn capture_reborrow_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -41,7 +41,7 @@ LL | || { &mut x; }; | ^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:64:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:57:14 | LL | pub fn capture_reborrow_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -50,5 +50,4 @@ LL | || { &mut x.0; }; error: aborting due to 6 previous errors -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr index 434f318ad1449..f1d28eed922af 100644 --- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr +++ b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr @@ -1,5 +1,5 @@ error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:21:46 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:46 | LL | pub fn e(x: &'static mut isize) { | - help: consider changing this to be mutable: `mut x` @@ -8,7 +8,7 @@ LL | let mut c1 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:34:50 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:50 | LL | pub fn ee(x: &'static mut isize) { | - help: consider changing this to be mutable: `mut x` @@ -17,7 +17,7 @@ LL | let mut c2 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:46:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14 | LL | pub fn capture_assign_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -25,7 +25,7 @@ LL | || { x = (1,); }; | ^^^^^^^^ cannot assign error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:52:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:47:14 | LL | pub fn capture_assign_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -33,7 +33,7 @@ LL | || { x.0 = 1; }; | ^^^^^^^ cannot assign error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:58:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:52:14 | LL | pub fn capture_reborrow_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -41,7 +41,7 @@ LL | || { &mut x; }; | ^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:64:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:57:14 | LL | pub fn capture_reborrow_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -50,5 +50,4 @@ LL | || { &mut x.0; }; error: aborting due to 6 previous errors -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs index 2bd71ec25f841..751a911a6bb86 100644 --- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs +++ b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs @@ -2,16 +2,14 @@ // analysis of a closure body may only be caught when AST-borrowck // looks at some parent. -// revisions: ast migrate nll +// revisions: migrate nll // Since we are testing nll (and migration) explicitly as a separate // revisions, don't worry about the --compare-mode=nll on this test. // ignore-compare-mode-nll -//[ast]compile-flags: -Z borrowck=ast -//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows -//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows +//[nll]compile-flags: -Z borrowck=mir // transcribed from borrowck-closures-unique.rs @@ -21,7 +19,6 @@ mod borrowck_closures_unique { let mut c1 = |y: &'static mut isize| x = y; //[migrate]~^ ERROR is not declared as mutable //[nll]~^^ ERROR is not declared as mutable - //[ast]~^^^ closure cannot assign to immutable unsafe { c1(&mut Y); } } } @@ -30,7 +27,6 @@ mod borrowck_closures_unique_grandparent { pub fn ee(x: &'static mut isize) { static mut Z: isize = 3; let mut c1 = |z: &'static mut isize| { - //[ast]~^ closure cannot assign to immutable let mut c2 = |y: &'static mut isize| x = y; //[migrate]~^ ERROR is not declared as mutable //[nll]~^^ ERROR is not declared as mutable @@ -44,27 +40,23 @@ mod borrowck_closures_unique_grandparent { mod mutability_errors { pub fn capture_assign_whole(x: (i32,)) { || { x = (1,); }; - //[ast]~^ ERROR immutable argument - //[migrate]~^^ ERROR is not declared as mutable - //[nll]~^^^ ERROR is not declared as mutable + //[migrate]~^ ERROR is not declared as mutable + //[nll]~^^ ERROR is not declared as mutable } pub fn capture_assign_part(x: (i32,)) { || { x.0 = 1; }; - //[ast]~^ ERROR immutable argument - //[migrate]~^^ ERROR is not declared as mutable - //[nll]~^^^ ERROR is not declared as mutable + //[migrate]~^ ERROR is not declared as mutable + //[nll]~^^ ERROR is not declared as mutable } pub fn capture_reborrow_whole(x: (i32,)) { || { &mut x; }; - //[ast]~^ ERROR immutable argument - //[migrate]~^^ ERROR is not declared as mutable - //[nll]~^^^ ERROR is not declared as mutable + //[migrate]~^ ERROR is not declared as mutable + //[nll]~^^ ERROR is not declared as mutable } pub fn capture_reborrow_part(x: (i32,)) { || { &mut x.0; }; - //[ast]~^ ERROR immutable argument - //[migrate]~^^ ERROR is not declared as mutable - //[nll]~^^^ ERROR is not declared as mutable + //[migrate]~^ ERROR is not declared as mutable + //[nll]~^^ ERROR is not declared as mutable } } diff --git a/src/test/ui/borrowck/issue-58776-borrowck-scans-children.migrate.stderr b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.migrate.stderr new file mode 100644 index 0000000000000..efd4e1a1716d3 --- /dev/null +++ b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.migrate.stderr @@ -0,0 +1,32 @@ +error[E0506]: cannot assign to `greeting` because it is borrowed + --> $DIR/issue-58776-borrowck-scans-children.rs:11:5 + | +LL | let res = (|| (|| &greeting)())(); + | -- -------- borrow occurs due to use in closure + | | + | borrow of `greeting` occurs here +LL | +LL | greeting = "DEALLOCATED".to_string(); + | ^^^^^^^^ assignment to borrowed `greeting` occurs here +... +LL | println!("thread result: {:?}", res); + | --- borrow later used here + +error[E0505]: cannot move out of `greeting` because it is borrowed + --> $DIR/issue-58776-borrowck-scans-children.rs:14:10 + | +LL | let res = (|| (|| &greeting)())(); + | -- -------- borrow occurs due to use in closure + | | + | borrow of `greeting` occurs here +... +LL | drop(greeting); + | ^^^^^^^^ move out of `greeting` occurs here +... +LL | println!("thread result: {:?}", res); + | --- borrow later used here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0505, E0506. +For more information about an error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/issue-58776-borrowck-scans-children.rs b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.rs new file mode 100644 index 0000000000000..efa313a9d23f4 --- /dev/null +++ b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.rs @@ -0,0 +1,11 @@ +fn main() { + let mut greeting = "Hello world!".to_string(); + let res = (|| (|| &greeting)())(); + + greeting = "DEALLOCATED".to_string(); + //~^ ERROR cannot assign + drop(greeting); + //~^ ERROR cannot move + + println!("thread result: {:?}", res); +} diff --git a/src/test/ui/borrowck/issue-58776-borrowck-scans-children.stderr b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.stderr new file mode 100644 index 0000000000000..9b1d6fa7d3575 --- /dev/null +++ b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.stderr @@ -0,0 +1,32 @@ +error[E0506]: cannot assign to `greeting` because it is borrowed + --> $DIR/issue-58776-borrowck-scans-children.rs:5:5 + | +LL | let res = (|| (|| &greeting)())(); + | -- -------- borrow occurs due to use in closure + | | + | borrow of `greeting` occurs here +LL | +LL | greeting = "DEALLOCATED".to_string(); + | ^^^^^^^^ assignment to borrowed `greeting` occurs here +... +LL | println!("thread result: {:?}", res); + | --- borrow later used here + +error[E0505]: cannot move out of `greeting` because it is borrowed + --> $DIR/issue-58776-borrowck-scans-children.rs:7:10 + | +LL | let res = (|| (|| &greeting)())(); + | -- -------- borrow occurs due to use in closure + | | + | borrow of `greeting` occurs here +... +LL | drop(greeting); + | ^^^^^^^^ move out of `greeting` occurs here +... +LL | println!("thread result: {:?}", res); + | --- borrow later used here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0505, E0506. +For more information about an error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/issue-7573.nll.stderr b/src/test/ui/borrowck/issue-7573.nll.stderr new file mode 100644 index 0000000000000..0da715bbdb764 --- /dev/null +++ b/src/test/ui/borrowck/issue-7573.nll.stderr @@ -0,0 +1,14 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/issue-7573.rs:21:9 + | +LL | let mut lines_to_use: Vec<&CrateId> = Vec::new(); + | ---------------- `lines_to_use` is declared here, outside of the closure body +LL | +LL | let push_id = |installed_id: &CrateId| { + | ------------ `installed_id` is a reference that is only valid in the closure body +... +LL | lines_to_use.push(installed_id); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `installed_id` escapes the closure body here + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/issue-7573.stderr b/src/test/ui/borrowck/issue-7573.stderr index fed79ef4f559e..32b3ef72d8bda 100644 --- a/src/test/ui/borrowck/issue-7573.stderr +++ b/src/test/ui/borrowck/issue-7573.stderr @@ -3,7 +3,7 @@ error: borrowed data cannot be stored outside of its closure | LL | let mut lines_to_use: Vec<&CrateId> = Vec::new(); | - cannot infer an appropriate lifetime... -LL | //~^ NOTE cannot infer an appropriate lifetime +LL | LL | let push_id = |installed_id: &CrateId| { | ------- ------------------------ borrowed data cannot outlive this closure | | diff --git a/src/test/ui/borrowck/move-in-static-initializer-issue-38520.ast.stderr b/src/test/ui/borrowck/move-in-static-initializer-issue-38520.ast.stderr deleted file mode 100644 index 6793e1a1312da..0000000000000 --- a/src/test/ui/borrowck/move-in-static-initializer-issue-38520.ast.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/move-in-static-initializer-issue-38520.rs:15:23 - | -LL | static Y: usize = get(*&X); //[ast]~ ERROR E0507 - | ^^^ cannot move out of borrowed content - -error[E0507]: cannot move out of borrowed content - --> $DIR/move-in-static-initializer-issue-38520.rs:17:22 - | -LL | const Z: usize = get(*&X); //[ast]~ ERROR E0507 - | ^^^ cannot move out of borrowed content - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/move-in-static-initializer-issue-38520.mir.stderr b/src/test/ui/borrowck/move-in-static-initializer-issue-38520.mir.stderr deleted file mode 100644 index 6793e1a1312da..0000000000000 --- a/src/test/ui/borrowck/move-in-static-initializer-issue-38520.mir.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/move-in-static-initializer-issue-38520.rs:15:23 - | -LL | static Y: usize = get(*&X); //[ast]~ ERROR E0507 - | ^^^ cannot move out of borrowed content - -error[E0507]: cannot move out of borrowed content - --> $DIR/move-in-static-initializer-issue-38520.rs:17:22 - | -LL | const Z: usize = get(*&X); //[ast]~ ERROR E0507 - | ^^^ cannot move out of borrowed content - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/move-in-static-initializer-issue-38520.rs b/src/test/ui/borrowck/move-in-static-initializer-issue-38520.rs index a7b17f7d6516b..c2a59a1054c75 100644 --- a/src/test/ui/borrowck/move-in-static-initializer-issue-38520.rs +++ b/src/test/ui/borrowck/move-in-static-initializer-issue-38520.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - // Regression test for #38520. Check that moves of `Foo` are not // permitted as `Foo` is not copy (even in a static/const // initializer). @@ -12,10 +9,8 @@ const fn get(x: Foo) -> usize { } const X: Foo = Foo(22); -static Y: usize = get(*&X); //[ast]~ ERROR E0507 - //[mir]~^ ERROR [E0507] -const Z: usize = get(*&X); //[ast]~ ERROR E0507 - //[mir]~^ ERROR [E0507] +static Y: usize = get(*&X); //~ ERROR [E0507] +const Z: usize = get(*&X); //~ ERROR [E0507] fn main() { } diff --git a/src/test/ui/borrowck/move-in-static-initializer-issue-38520.stderr b/src/test/ui/borrowck/move-in-static-initializer-issue-38520.stderr new file mode 100644 index 0000000000000..6619fb42c281a --- /dev/null +++ b/src/test/ui/borrowck/move-in-static-initializer-issue-38520.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/move-in-static-initializer-issue-38520.rs:12:23 + | +LL | static Y: usize = get(*&X); + | ^^^ move occurs because value has type `Foo`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of a shared reference + --> $DIR/move-in-static-initializer-issue-38520.rs:13:22 + | +LL | const Z: usize = get(*&X); + | ^^^ move occurs because value has type `Foo`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr b/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr deleted file mode 100644 index ab05358d03f86..0000000000000 --- a/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0499]: cannot borrow `*arg` as mutable more than once at a time - --> $DIR/mut-borrow-in-loop.rs:10:25 - | -LL | impl<'a, T : 'a> FuncWrapper<'a, T> { - | -- lifetime `'a` defined here -... -LL | (self.func)(arg) //~ ERROR cannot borrow - | ------------^^^- - | | | - | | mutable borrow starts here in previous iteration of loop - | argument requires that `*arg` is borrowed for `'a` - -error[E0499]: cannot borrow `*arg` as mutable more than once at a time - --> $DIR/mut-borrow-in-loop.rs:16:25 - | -LL | impl<'a, T : 'a> FuncWrapper<'a, T> { - | -- lifetime `'a` defined here -... -LL | (self.func)(arg) //~ ERROR cannot borrow - | ------------^^^- - | | | - | | mutable borrow starts here in previous iteration of loop - | argument requires that `*arg` is borrowed for `'a` - -error[E0499]: cannot borrow `*arg` as mutable more than once at a time - --> $DIR/mut-borrow-in-loop.rs:23:25 - | -LL | impl<'a, T : 'a> FuncWrapper<'a, T> { - | -- lifetime `'a` defined here -... -LL | (self.func)(arg) //~ ERROR cannot borrow - | ------------^^^- - | | | - | | mutable borrow starts here in previous iteration of loop - | argument requires that `*arg` is borrowed for `'a` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/mut-borrow-in-loop.rs b/src/test/ui/borrowck/mut-borrow-in-loop.rs index 6b65b903757ac..09f3e4f9b76d8 100644 --- a/src/test/ui/borrowck/mut-borrow-in-loop.rs +++ b/src/test/ui/borrowck/mut-borrow-in-loop.rs @@ -27,4 +27,3 @@ impl<'a, T : 'a> FuncWrapper<'a, T> { fn main() { } - diff --git a/src/test/ui/borrowck/mut-borrow-in-loop.stderr b/src/test/ui/borrowck/mut-borrow-in-loop.stderr index 749e0e172f775..eda2f518f9246 100644 --- a/src/test/ui/borrowck/mut-borrow-in-loop.stderr +++ b/src/test/ui/borrowck/mut-borrow-in-loop.stderr @@ -1,29 +1,38 @@ error[E0499]: cannot borrow `*arg` as mutable more than once at a time --> $DIR/mut-borrow-in-loop.rs:10:25 | -LL | (self.func)(arg) //~ ERROR cannot borrow - | ^^^ mutable borrow starts here in previous iteration of loop -LL | } -LL | } - | - mutable borrow ends here +LL | impl<'a, T : 'a> FuncWrapper<'a, T> { + | -- lifetime `'a` defined here +... +LL | (self.func)(arg) + | ------------^^^- + | | | + | | mutable borrow starts here in previous iteration of loop + | argument requires that `*arg` is borrowed for `'a` error[E0499]: cannot borrow `*arg` as mutable more than once at a time --> $DIR/mut-borrow-in-loop.rs:16:25 | -LL | (self.func)(arg) //~ ERROR cannot borrow - | ^^^ mutable borrow starts here in previous iteration of loop -LL | } -LL | } - | - mutable borrow ends here +LL | impl<'a, T : 'a> FuncWrapper<'a, T> { + | -- lifetime `'a` defined here +... +LL | (self.func)(arg) + | ------------^^^- + | | | + | | mutable borrow starts here in previous iteration of loop + | argument requires that `*arg` is borrowed for `'a` error[E0499]: cannot borrow `*arg` as mutable more than once at a time --> $DIR/mut-borrow-in-loop.rs:23:25 | -LL | (self.func)(arg) //~ ERROR cannot borrow - | ^^^ mutable borrow starts here in previous iteration of loop -LL | } -LL | } - | - mutable borrow ends here +LL | impl<'a, T : 'a> FuncWrapper<'a, T> { + | -- lifetime `'a` defined here +... +LL | (self.func)(arg) + | ------------^^^- + | | | + | | mutable borrow starts here in previous iteration of loop + | argument requires that `*arg` is borrowed for `'a` error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/mut-borrow-of-mut-ref.nll.stderr b/src/test/ui/borrowck/mut-borrow-of-mut-ref.nll.stderr deleted file mode 100644 index 5ee31b5efd091..0000000000000 --- a/src/test/ui/borrowck/mut-borrow-of-mut-ref.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable - --> $DIR/mut-borrow-of-mut-ref.rs:8:7 - | -LL | fn f(b: &mut i32) { - | - help: consider changing this to be mutable: `mut b` -LL | g(&mut b) //~ ERROR cannot borrow - | ^^^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr b/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr index 5278056ac0f51..09dabbc89b425 100644 --- a/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr +++ b/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr @@ -1,12 +1,10 @@ -error[E0596]: cannot borrow immutable argument `b` as mutable - --> $DIR/mut-borrow-of-mut-ref.rs:8:12 +error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable + --> $DIR/mut-borrow-of-mut-ref.rs:8:7 | -LL | g(&mut b) //~ ERROR cannot borrow - | ^ cannot borrow mutably -help: consider removing the `&mut`, as it is an immutable binding to a mutable reference - | -LL | g(b) //~ ERROR cannot borrow - | ^ +LL | fn f(b: &mut i32) { + | - help: consider changing this to be mutable: `mut b` +LL | g(&mut b) + | ^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/borrowck/mut-borrow-outside-loop.nll.stderr b/src/test/ui/borrowck/mut-borrow-outside-loop.nll.stderr deleted file mode 100644 index 9b20fc0231934..0000000000000 --- a/src/test/ui/borrowck/mut-borrow-outside-loop.nll.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0499]: cannot borrow `void` as mutable more than once at a time - --> $DIR/mut-borrow-outside-loop.rs:7:18 - | -LL | let first = &mut void; - | --------- first mutable borrow occurs here -LL | let second = &mut void; //~ ERROR cannot borrow - | ^^^^^^^^^ second mutable borrow occurs here -LL | first.use_mut(); - | ----- first borrow later used here - -error[E0499]: cannot borrow `inner_void` as mutable more than once at a time - --> $DIR/mut-borrow-outside-loop.rs:15:28 - | -LL | let inner_first = &mut inner_void; - | --------------- first mutable borrow occurs here -LL | let inner_second = &mut inner_void; //~ ERROR cannot borrow - | ^^^^^^^^^^^^^^^ second mutable borrow occurs here -LL | inner_second.use_mut(); -LL | inner_first.use_mut(); - | ----------- first borrow later used here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/mut-borrow-outside-loop.stderr b/src/test/ui/borrowck/mut-borrow-outside-loop.stderr index 1b32d8589b522..4fcb693f1bf1d 100644 --- a/src/test/ui/borrowck/mut-borrow-outside-loop.stderr +++ b/src/test/ui/borrowck/mut-borrow-outside-loop.stderr @@ -1,24 +1,23 @@ error[E0499]: cannot borrow `void` as mutable more than once at a time - --> $DIR/mut-borrow-outside-loop.rs:7:23 + --> $DIR/mut-borrow-outside-loop.rs:7:18 | LL | let first = &mut void; - | ---- first mutable borrow occurs here -LL | let second = &mut void; //~ ERROR cannot borrow - | ^^^^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here + | --------- first mutable borrow occurs here +LL | let second = &mut void; + | ^^^^^^^^^ second mutable borrow occurs here +LL | first.use_mut(); + | ----- first borrow later used here error[E0499]: cannot borrow `inner_void` as mutable more than once at a time - --> $DIR/mut-borrow-outside-loop.rs:15:33 + --> $DIR/mut-borrow-outside-loop.rs:15:28 | LL | let inner_first = &mut inner_void; - | ---------- first mutable borrow occurs here -LL | let inner_second = &mut inner_void; //~ ERROR cannot borrow - | ^^^^^^^^^^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here + | --------------- first mutable borrow occurs here +LL | let inner_second = &mut inner_void; + | ^^^^^^^^^^^^^^^ second mutable borrow occurs here +LL | inner_second.use_mut(); +LL | inner_first.use_mut(); + | ----------- first borrow later used here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/mutability-errors.nll.stderr b/src/test/ui/borrowck/mutability-errors.nll.stderr deleted file mode 100644 index 6dd3582f95f5d..0000000000000 --- a/src/test/ui/borrowck/mutability-errors.nll.stderr +++ /dev/null @@ -1,379 +0,0 @@ -error[E0594]: cannot assign to `*x` which is behind a `&` reference - --> $DIR/mutability-errors.rs:9:5 - | -LL | fn named_ref(x: &(i32,)) { - | ------- help: consider changing this to be a mutable reference: `&mut (i32,)` -LL | *x = (1,); //~ ERROR - | ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written - -error[E0594]: cannot assign to `x.0` which is behind a `&` reference - --> $DIR/mutability-errors.rs:10:5 - | -LL | fn named_ref(x: &(i32,)) { - | ------- help: consider changing this to be a mutable reference: `&mut (i32,)` -LL | *x = (1,); //~ ERROR -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written - -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/mutability-errors.rs:11:5 - | -LL | fn named_ref(x: &(i32,)) { - | ------- help: consider changing this to be a mutable reference: `&mut (i32,)` -... -LL | &mut *x; //~ ERROR - | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `&` reference - --> $DIR/mutability-errors.rs:12:5 - | -LL | fn named_ref(x: &(i32,)) { - | ------- help: consider changing this to be a mutable reference: `&mut (i32,)` -... -LL | &mut x.0; //~ ERROR - | ^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0594]: cannot assign to data in a `&` reference - --> $DIR/mutability-errors.rs:16:5 - | -LL | *f() = (1,); //~ ERROR - | ^^^^^^^^^^^ cannot assign - -error[E0594]: cannot assign to data in a `&` reference - --> $DIR/mutability-errors.rs:17:5 - | -LL | f().0 = 1; //~ ERROR - | ^^^^^^^^^ cannot assign - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/mutability-errors.rs:18:5 - | -LL | &mut *f(); //~ ERROR - | ^^^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/mutability-errors.rs:19:5 - | -LL | &mut f().0; //~ ERROR - | ^^^^^^^^^^ cannot borrow as mutable - -error[E0594]: cannot assign to `*x` which is behind a `*const` pointer - --> $DIR/mutability-errors.rs:23:5 - | -LL | unsafe fn named_ptr(x: *const (i32,)) { - | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)` -LL | *x = (1,); //~ ERROR - | ^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written - -error[E0594]: cannot assign to `x.0` which is behind a `*const` pointer - --> $DIR/mutability-errors.rs:24:5 - | -LL | unsafe fn named_ptr(x: *const (i32,)) { - | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)` -LL | *x = (1,); //~ ERROR -LL | (*x).0 = 1; //~ ERROR - | ^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written - -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer - --> $DIR/mutability-errors.rs:25:5 - | -LL | unsafe fn named_ptr(x: *const (i32,)) { - | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)` -... -LL | &mut *x; //~ ERROR - | ^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `*const` pointer - --> $DIR/mutability-errors.rs:26:5 - | -LL | unsafe fn named_ptr(x: *const (i32,)) { - | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)` -... -LL | &mut (*x).0; //~ ERROR - | ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable - -error[E0594]: cannot assign to data in a `*const` pointer - --> $DIR/mutability-errors.rs:30:5 - | -LL | *f() = (1,); //~ ERROR - | ^^^^^^^^^^^ cannot assign - -error[E0594]: cannot assign to data in a `*const` pointer - --> $DIR/mutability-errors.rs:31:5 - | -LL | (*f()).0 = 1; //~ ERROR - | ^^^^^^^^^^^^ cannot assign - -error[E0596]: cannot borrow data in a `*const` pointer as mutable - --> $DIR/mutability-errors.rs:32:5 - | -LL | &mut *f(); //~ ERROR - | ^^^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow data in a `*const` pointer as mutable - --> $DIR/mutability-errors.rs:33:5 - | -LL | &mut (*f()).0; //~ ERROR - | ^^^^^^^^^^^^^ cannot borrow as mutable - -error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/mutability-errors.rs:40:9 - | -LL | x = (1,); //~ ERROR - | ^^^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:39:12 - | -LL | fn_ref(|| { - | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR -LL | | }); - | |_____^ - -error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables - --> $DIR/mutability-errors.rs:41:9 - | -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:39:12 - | -LL | fn_ref(|| { - | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR -LL | | }); - | |_____^ - -error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/mutability-errors.rs:42:9 - | -LL | &mut x; //~ ERROR - | ^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:39:12 - | -LL | fn_ref(|| { - | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR -LL | | }); - | |_____^ - -error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables - --> $DIR/mutability-errors.rs:43:9 - | -LL | &mut x.0; //~ ERROR - | ^^^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:39:12 - | -LL | fn_ref(|| { - | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR -LL | | }); - | |_____^ - -error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/mutability-errors.rs:46:9 - | -LL | x = (1,); //~ ERROR - | ^^^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:45:12 - | -LL | fn_ref(move || { - | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR -LL | | }); - | |_____^ - -error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables - --> $DIR/mutability-errors.rs:47:9 - | -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:45:12 - | -LL | fn_ref(move || { - | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR -LL | | }); - | |_____^ - -error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/mutability-errors.rs:48:9 - | -LL | &mut x; //~ ERROR - | ^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:45:12 - | -LL | fn_ref(move || { - | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR -LL | | }); - | |_____^ - -error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables - --> $DIR/mutability-errors.rs:49:9 - | -LL | &mut x.0; //~ ERROR - | ^^^^^^^^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/mutability-errors.rs:45:12 - | -LL | fn_ref(move || { - | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR -LL | | }); - | |_____^ - -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/mutability-errors.rs:54:5 - | -LL | fn imm_local(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -LL | &mut x; //~ ERROR - | ^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable - --> $DIR/mutability-errors.rs:55:5 - | -LL | fn imm_local(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -LL | &mut x; //~ ERROR -LL | &mut x.0; //~ ERROR - | ^^^^^^^^ cannot borrow as mutable - -error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/mutability-errors.rs:60:9 - | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -LL | || { //~ ERROR -LL | x = (1,); - | ^^^^^^^^ cannot assign - -error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable - --> $DIR/mutability-errors.rs:61:9 - | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... -LL | x.0 = 1; - | ^^^^^^^ cannot assign - -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/mutability-errors.rs:62:9 - | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... -LL | &mut x; - | ^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable - --> $DIR/mutability-errors.rs:63:9 - | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... -LL | &mut x.0; - | ^^^^^^^^ cannot borrow as mutable - -error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/mutability-errors.rs:66:9 - | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... -LL | x = (1,); //~ ERROR - | ^^^^^^^^ cannot assign - -error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable - --> $DIR/mutability-errors.rs:67:9 - | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ cannot assign - -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/mutability-errors.rs:68:9 - | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... -LL | &mut x; //~ ERROR - | ^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable - --> $DIR/mutability-errors.rs:69:9 - | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... -LL | &mut x.0; //~ ERROR - | ^^^^^^^^ cannot borrow as mutable - -error[E0594]: cannot assign to immutable static item `X` - --> $DIR/mutability-errors.rs:76:5 - | -LL | X = (1,); //~ ERROR - | ^^^^^^^^ cannot assign - -error[E0594]: cannot assign to `X.0`, as `X` is an immutable static item - --> $DIR/mutability-errors.rs:77:5 - | -LL | X.0 = 1; //~ ERROR - | ^^^^^^^ cannot assign - -error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/mutability-errors.rs:78:5 - | -LL | &mut X; //~ ERROR - | ^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `X.0` as mutable, as `X` is an immutable static item - --> $DIR/mutability-errors.rs:79:5 - | -LL | &mut X.0; //~ ERROR - | ^^^^^^^^ cannot borrow as mutable - -error: aborting due to 38 previous errors - -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/mutability-errors.rs b/src/test/ui/borrowck/mutability-errors.rs index 26f7f605ebeb8..5be0df1376135 100644 --- a/src/test/ui/borrowck/mutability-errors.rs +++ b/src/test/ui/borrowck/mutability-errors.rs @@ -56,11 +56,11 @@ fn imm_local(x: (i32,)) { } fn imm_capture(x: (i32,)) { - || { //~ ERROR - x = (1,); - x.0 = 1; - &mut x; - &mut x.0; + || { + x = (1,); //~ ERROR + x.0 = 1; //~ ERROR + &mut x; //~ ERROR + &mut x.0; //~ ERROR }; move || { x = (1,); //~ ERROR diff --git a/src/test/ui/borrowck/mutability-errors.stderr b/src/test/ui/borrowck/mutability-errors.stderr index b7fd6ee7214f1..545de5d0e75bf 100644 --- a/src/test/ui/borrowck/mutability-errors.stderr +++ b/src/test/ui/borrowck/mutability-errors.stderr @@ -1,308 +1,378 @@ -error[E0594]: cannot assign to immutable borrowed content `*x` +error[E0594]: cannot assign to `*x` which is behind a `&` reference --> $DIR/mutability-errors.rs:9:5 | LL | fn named_ref(x: &(i32,)) { - | ------- use `&mut (i32,)` here to make mutable -LL | *x = (1,); //~ ERROR - | ^^^^^^^^^ cannot borrow as mutable + | ------- help: consider changing this to be a mutable reference: `&mut (i32,)` +LL | *x = (1,); + | ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written -error[E0594]: cannot assign to field `x.0` of immutable binding +error[E0594]: cannot assign to `x.0` which is behind a `&` reference --> $DIR/mutability-errors.rs:10:5 | LL | fn named_ref(x: &(i32,)) { - | ------- use `&mut (i32,)` here to make mutable -LL | *x = (1,); //~ ERROR -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ cannot mutably borrow field of immutable binding + | ------- help: consider changing this to be a mutable reference: `&mut (i32,)` +LL | *x = (1,); +LL | x.0 = 1; + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written -error[E0596]: cannot borrow immutable borrowed content `*x` as mutable - --> $DIR/mutability-errors.rs:11:10 +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference + --> $DIR/mutability-errors.rs:11:5 | LL | fn named_ref(x: &(i32,)) { - | ------- use `&mut (i32,)` here to make mutable + | ------- help: consider changing this to be a mutable reference: `&mut (i32,)` ... -LL | &mut *x; //~ ERROR - | ^^ cannot borrow as mutable +LL | &mut *x; + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow field `x.0` of immutable binding as mutable - --> $DIR/mutability-errors.rs:12:10 +error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `&` reference + --> $DIR/mutability-errors.rs:12:5 | LL | fn named_ref(x: &(i32,)) { - | ------- use `&mut (i32,)` here to make mutable + | ------- help: consider changing this to be a mutable reference: `&mut (i32,)` ... -LL | &mut x.0; //~ ERROR - | ^^^ cannot mutably borrow field of immutable binding +LL | &mut x.0; + | ^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0594]: cannot assign to immutable borrowed content +error[E0594]: cannot assign to data in a `&` reference --> $DIR/mutability-errors.rs:16:5 | -LL | *f() = (1,); //~ ERROR - | ^^^^^^^^^^^ cannot borrow as mutable +LL | *f() = (1,); + | ^^^^^^^^^^^ cannot assign -error[E0594]: cannot assign to field of immutable binding +error[E0594]: cannot assign to data in a `&` reference --> $DIR/mutability-errors.rs:17:5 | -LL | f().0 = 1; //~ ERROR - | ^^^^^^^^^ cannot mutably borrow field of immutable binding +LL | f().0 = 1; + | ^^^^^^^^^ cannot assign -error[E0596]: cannot borrow immutable borrowed content as mutable - --> $DIR/mutability-errors.rs:18:10 +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/mutability-errors.rs:18:5 | -LL | &mut *f(); //~ ERROR - | ^^^^ cannot borrow as mutable +LL | &mut *f(); + | ^^^^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow field of immutable binding as mutable - --> $DIR/mutability-errors.rs:19:10 +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/mutability-errors.rs:19:5 | -LL | &mut f().0; //~ ERROR - | ^^^^^ cannot mutably borrow field of immutable binding +LL | &mut f().0; + | ^^^^^^^^^^ cannot borrow as mutable -error[E0594]: cannot assign to immutable dereference of raw pointer `*x` +error[E0594]: cannot assign to `*x` which is behind a `*const` pointer --> $DIR/mutability-errors.rs:23:5 | -LL | *x = (1,); //~ ERROR - | ^^^^^^^^^ cannot borrow as mutable +LL | unsafe fn named_ptr(x: *const (i32,)) { + | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)` +LL | *x = (1,); + | ^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written -error[E0594]: cannot assign to field `x.0` of immutable binding +error[E0594]: cannot assign to `x.0` which is behind a `*const` pointer --> $DIR/mutability-errors.rs:24:5 | -LL | (*x).0 = 1; //~ ERROR - | ^^^^^^^^^^ cannot mutably borrow field of immutable binding +LL | unsafe fn named_ptr(x: *const (i32,)) { + | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)` +LL | *x = (1,); +LL | (*x).0 = 1; + | ^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written -error[E0596]: cannot borrow immutable dereference of raw pointer `*x` as mutable - --> $DIR/mutability-errors.rs:25:10 +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer + --> $DIR/mutability-errors.rs:25:5 | -LL | &mut *x; //~ ERROR - | ^^ cannot borrow as mutable +LL | unsafe fn named_ptr(x: *const (i32,)) { + | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)` +... +LL | &mut *x; + | ^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow field `x.0` of immutable binding as mutable - --> $DIR/mutability-errors.rs:26:10 +error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `*const` pointer + --> $DIR/mutability-errors.rs:26:5 | -LL | &mut (*x).0; //~ ERROR - | ^^^^^^ cannot mutably borrow field of immutable binding +LL | unsafe fn named_ptr(x: *const (i32,)) { + | ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)` +... +LL | &mut (*x).0; + | ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable -error[E0594]: cannot assign to immutable dereference of raw pointer +error[E0594]: cannot assign to data in a `*const` pointer --> $DIR/mutability-errors.rs:30:5 | -LL | *f() = (1,); //~ ERROR - | ^^^^^^^^^^^ cannot borrow as mutable +LL | *f() = (1,); + | ^^^^^^^^^^^ cannot assign -error[E0594]: cannot assign to field of immutable binding +error[E0594]: cannot assign to data in a `*const` pointer --> $DIR/mutability-errors.rs:31:5 | -LL | (*f()).0 = 1; //~ ERROR - | ^^^^^^^^^^^^ cannot mutably borrow field of immutable binding +LL | (*f()).0 = 1; + | ^^^^^^^^^^^^ cannot assign -error[E0596]: cannot borrow immutable dereference of raw pointer as mutable - --> $DIR/mutability-errors.rs:32:10 +error[E0596]: cannot borrow data in a `*const` pointer as mutable + --> $DIR/mutability-errors.rs:32:5 | -LL | &mut *f(); //~ ERROR - | ^^^^ cannot borrow as mutable +LL | &mut *f(); + | ^^^^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow field of immutable binding as mutable - --> $DIR/mutability-errors.rs:33:10 +error[E0596]: cannot borrow data in a `*const` pointer as mutable + --> $DIR/mutability-errors.rs:33:5 | -LL | &mut (*f()).0; //~ ERROR - | ^^^^^^^^ cannot mutably borrow field of immutable binding +LL | &mut (*f()).0; + | ^^^^^^^^^^^^^ cannot borrow as mutable -error[E0387]: cannot assign to data in a captured outer variable in an `Fn` closure +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/mutability-errors.rs:40:9 | -LL | x = (1,); //~ ERROR - | ^^^^^^^^ +LL | x = (1,); + | ^^^^^^^^ cannot assign | -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/mutability-errors.rs:39:12 | LL | fn_ref(|| { | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR +LL | | x = (1,); +LL | | x.0 = 1; +LL | | &mut x; +LL | | &mut x.0; LL | | }); | |_____^ -error[E0387]: cannot assign to data in a captured outer variable in an `Fn` closure +error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables --> $DIR/mutability-errors.rs:41:9 | -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ +LL | x.0 = 1; + | ^^^^^^^ cannot assign | -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/mutability-errors.rs:39:12 | LL | fn_ref(|| { | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR +LL | | x = (1,); +LL | | x.0 = 1; +LL | | &mut x; +LL | | &mut x.0; LL | | }); | |_____^ -error[E0387]: cannot borrow data mutably in a captured outer variable in an `Fn` closure - --> $DIR/mutability-errors.rs:42:14 +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/mutability-errors.rs:42:9 | -LL | &mut x; //~ ERROR - | ^ +LL | &mut x; + | ^^^^^^ cannot borrow as mutable | -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/mutability-errors.rs:39:12 | LL | fn_ref(|| { | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR +LL | | x = (1,); +LL | | x.0 = 1; +LL | | &mut x; +LL | | &mut x.0; LL | | }); | |_____^ -error[E0387]: cannot borrow data mutably in a captured outer variable in an `Fn` closure - --> $DIR/mutability-errors.rs:43:14 +error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables + --> $DIR/mutability-errors.rs:43:9 | -LL | &mut x.0; //~ ERROR - | ^^^ +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable | -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/mutability-errors.rs:39:12 | LL | fn_ref(|| { | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR +LL | | x = (1,); +LL | | x.0 = 1; +LL | | &mut x; +LL | | &mut x.0; LL | | }); | |_____^ -error[E0594]: cannot assign to captured outer variable in an `Fn` closure +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/mutability-errors.rs:46:9 | -LL | x = (1,); //~ ERROR - | ^^^^^^^^ +LL | x = (1,); + | ^^^^^^^^ cannot assign | - = note: `Fn` closures cannot capture their enclosing environment for modifications -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/mutability-errors.rs:45:12 | LL | fn_ref(move || { | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR +LL | | x = (1,); +LL | | x.0 = 1; +LL | | &mut x; +LL | | &mut x.0; LL | | }); | |_____^ -error[E0594]: cannot assign to field `x.0` of immutable binding +error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables --> $DIR/mutability-errors.rs:47:9 | -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ cannot mutably borrow field of immutable binding +LL | x.0 = 1; + | ^^^^^^^ cannot assign + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/mutability-errors.rs:45:12 + | +LL | fn_ref(move || { + | ____________^ +LL | | x = (1,); +LL | | x.0 = 1; +LL | | &mut x; +LL | | &mut x.0; +LL | | }); + | |_____^ -error[E0596]: cannot borrow captured outer variable in an `Fn` closure as mutable - --> $DIR/mutability-errors.rs:48:14 +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/mutability-errors.rs:48:9 | -LL | &mut x; //~ ERROR - | ^ +LL | &mut x; + | ^^^^^^ cannot borrow as mutable | -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/mutability-errors.rs:45:12 | LL | fn_ref(move || { | ____________^ -LL | | x = (1,); //~ ERROR -LL | | x.0 = 1; //~ ERROR -LL | | &mut x; //~ ERROR -LL | | &mut x.0; //~ ERROR +LL | | x = (1,); +LL | | x.0 = 1; +LL | | &mut x; +LL | | &mut x.0; LL | | }); | |_____^ -error[E0596]: cannot borrow field `x.0` of immutable binding as mutable - --> $DIR/mutability-errors.rs:49:14 +error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables + --> $DIR/mutability-errors.rs:49:9 | -LL | &mut x.0; //~ ERROR - | ^^^ cannot mutably borrow field of immutable binding +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/mutability-errors.rs:45:12 + | +LL | fn_ref(move || { + | ____________^ +LL | | x = (1,); +LL | | x.0 = 1; +LL | | &mut x; +LL | | &mut x.0; +LL | | }); + | |_____^ -error[E0596]: cannot borrow immutable argument `x` as mutable - --> $DIR/mutability-errors.rs:54:10 +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/mutability-errors.rs:54:5 | LL | fn imm_local(x: (i32,)) { - | - help: make this binding mutable: `mut x` -LL | &mut x; //~ ERROR - | ^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut x` +LL | &mut x; + | ^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow field `x.0` of immutable binding as mutable - --> $DIR/mutability-errors.rs:55:10 +error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable + --> $DIR/mutability-errors.rs:55:5 | LL | fn imm_local(x: (i32,)) { - | - help: make this binding mutable: `mut x` -LL | &mut x; //~ ERROR -LL | &mut x.0; //~ ERROR - | ^^^ cannot mutably borrow field of immutable binding + | - help: consider changing this to be mutable: `mut x` +LL | &mut x; +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/mutability-errors.rs:60:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +LL | || { +LL | x = (1,); + | ^^^^^^^^ cannot assign + +error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable + --> $DIR/mutability-errors.rs:61:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | x.0 = 1; + | ^^^^^^^ cannot assign -error[E0595]: closure cannot assign to immutable argument `x` - --> $DIR/mutability-errors.rs:59:5 +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/mutability-errors.rs:62:9 | LL | fn imm_capture(x: (i32,)) { - | - help: make this binding mutable: `mut x` -LL | || { //~ ERROR - | ^^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut x` +... +LL | &mut x; + | ^^^^^^ cannot borrow as mutable -error[E0594]: cannot assign to captured outer variable in an `FnMut` closure +error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable + --> $DIR/mutability-errors.rs:63:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/mutability-errors.rs:66:9 | LL | fn imm_capture(x: (i32,)) { - | - help: consider making `x` mutable: `mut x` + | - help: consider changing this to be mutable: `mut x` ... -LL | x = (1,); //~ ERROR - | ^^^^^^^^ +LL | x = (1,); + | ^^^^^^^^ cannot assign -error[E0594]: cannot assign to field `x.0` of immutable binding +error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable --> $DIR/mutability-errors.rs:67:9 | -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ cannot mutably borrow field of immutable binding +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | x.0 = 1; + | ^^^^^^^ cannot assign -error[E0596]: cannot borrow captured outer variable in an `FnMut` closure as mutable - --> $DIR/mutability-errors.rs:68:14 +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/mutability-errors.rs:68:9 | -LL | &mut x; //~ ERROR - | ^ +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | &mut x; + | ^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow field `x.0` of immutable binding as mutable - --> $DIR/mutability-errors.rs:69:14 +error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable + --> $DIR/mutability-errors.rs:69:9 | -LL | &mut x.0; //~ ERROR - | ^^^ cannot mutably borrow field of immutable binding +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable -error[E0594]: cannot assign to immutable static item +error[E0594]: cannot assign to immutable static item `X` --> $DIR/mutability-errors.rs:76:5 | -LL | X = (1,); //~ ERROR - | ^^^^^^^^ +LL | X = (1,); + | ^^^^^^^^ cannot assign -error[E0594]: cannot assign to field of immutable binding +error[E0594]: cannot assign to `X.0`, as `X` is an immutable static item --> $DIR/mutability-errors.rs:77:5 | -LL | X.0 = 1; //~ ERROR - | ^^^^^^^ cannot mutably borrow field of immutable binding +LL | X.0 = 1; + | ^^^^^^^ cannot assign -error[E0596]: cannot borrow immutable static item as mutable - --> $DIR/mutability-errors.rs:78:10 +error[E0596]: cannot borrow immutable static item `X` as mutable + --> $DIR/mutability-errors.rs:78:5 | -LL | &mut X; //~ ERROR - | ^ +LL | &mut X; + | ^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow field of immutable binding as mutable - --> $DIR/mutability-errors.rs:79:10 +error[E0596]: cannot borrow `X.0` as mutable, as `X` is an immutable static item + --> $DIR/mutability-errors.rs:79:5 | -LL | &mut X.0; //~ ERROR - | ^^^ cannot mutably borrow field of immutable binding +LL | &mut X.0; + | ^^^^^^^^ cannot borrow as mutable -error: aborting due to 35 previous errors +error: aborting due to 38 previous errors -Some errors occurred: E0387, E0594, E0595, E0596. -For more information about an error, try `rustc --explain E0387`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.nll.stderr b/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.nll.stderr deleted file mode 100644 index 66e3c4056a229..0000000000000 --- a/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.nll.stderr +++ /dev/null @@ -1,50 +0,0 @@ -error[E0515]: cannot return value referencing temporary value - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:6:5 - | -LL | let ref mut x = 1234543; //~ ERROR - | ------- temporary value created here -LL | x - | ^ returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing temporary value - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:11:5 - | -LL | let (ref mut x, ) = (1234543, ); //~ ERROR - | ----------- temporary value created here -LL | x - | ^ returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing temporary value - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:15:5 - | -LL | match 1234543 { - | ^ ------- temporary value created here - | _____| - | | -LL | | ref mut x => x //~ ERROR -LL | | } - | |_____^ returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing temporary value - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:21:5 - | -LL | match (123443,) { - | ^ --------- temporary value created here - | _____| - | | -LL | | (ref mut x,) => x, //~ ERROR -LL | | } - | |_____^ returns a value referencing data owned by the current function - -error[E0515]: cannot return reference to temporary value - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:27:5 - | -LL | &mut 1234543 //~ ERROR - | ^^^^^------- - | | | - | | temporary value created here - | returns a reference to data owned by the current function - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.rs b/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.rs index ae305b68941e7..3576734de3c5b 100644 --- a/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.rs +++ b/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.rs @@ -2,24 +2,24 @@ // mut` borrow. fn gimme_static_mut_let() -> &'static mut u32 { - let ref mut x = 1234543; //~ ERROR - x + let ref mut x = 1234543; + x //~ ERROR } fn gimme_static_mut_let_nested() -> &'static mut u32 { - let (ref mut x, ) = (1234543, ); //~ ERROR - x + let (ref mut x, ) = (1234543, ); + x //~ ERROR } fn gimme_static_mut_match() -> &'static mut u32 { - match 1234543 { - ref mut x => x //~ ERROR + match 1234543 { //~ ERROR + ref mut x => x } } fn gimme_static_mut_match_nested() -> &'static mut u32 { - match (123443,) { - (ref mut x,) => x, //~ ERROR + match (123443,) { //~ ERROR + (ref mut x,) => x, } } diff --git a/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.stderr b/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.stderr index 51e47fd44d90b..60af412373542 100644 --- a/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.stderr +++ b/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.stderr @@ -1,57 +1,50 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:5:9 +error[E0515]: cannot return value referencing temporary value + --> $DIR/promote-ref-mut-in-let-issue-46557.rs:6:5 | -LL | let ref mut x = 1234543; //~ ERROR - | ^^^^^^^^^ temporary value does not live long enough +LL | let ref mut x = 1234543; + | ------- temporary value created here LL | x -LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | ^ returns a value referencing data owned by the current function -error[E0597]: borrowed value does not live long enough - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:10:10 +error[E0515]: cannot return value referencing temporary value + --> $DIR/promote-ref-mut-in-let-issue-46557.rs:11:5 | -LL | let (ref mut x, ) = (1234543, ); //~ ERROR - | ^^^^^^^^^ borrowed value does not live long enough +LL | let (ref mut x, ) = (1234543, ); + | ----------- temporary value created here LL | x -LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | ^ returns a value referencing data owned by the current function -error[E0597]: borrowed value does not live long enough - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:16:9 - | -LL | ref mut x => x //~ ERROR - | ^^^^^^^^^ temporary value does not live long enough -LL | } -LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... +error[E0515]: cannot return value referencing temporary value + --> $DIR/promote-ref-mut-in-let-issue-46557.rs:15:5 + | +LL | match 1234543 { + | ^ ------- temporary value created here + | _____| + | | +LL | | ref mut x => x +LL | | } + | |_____^ returns a value referencing data owned by the current function -error[E0597]: borrowed value does not live long enough - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:22:10 - | -LL | (ref mut x,) => x, //~ ERROR - | ^^^^^^^^^ borrowed value does not live long enough -LL | } -LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... +error[E0515]: cannot return value referencing temporary value + --> $DIR/promote-ref-mut-in-let-issue-46557.rs:21:5 + | +LL | match (123443,) { + | ^ --------- temporary value created here + | _____| + | | +LL | | (ref mut x,) => x, +LL | | } + | |_____^ returns a value referencing data owned by the current function -error[E0597]: borrowed value does not live long enough - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:27:10 - | -LL | &mut 1234543 //~ ERROR - | ^^^^^^^ temporary value does not live long enough -LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... +error[E0515]: cannot return reference to temporary value + --> $DIR/promote-ref-mut-in-let-issue-46557.rs:27:5 + | +LL | &mut 1234543 + | ^^^^^------- + | | | + | | temporary value created here + | returns a reference to data owned by the current function error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/reassignment_immutable_fields.nll.stderr b/src/test/ui/borrowck/reassignment_immutable_fields.nll.stderr deleted file mode 100644 index bf9084259c834..0000000000000 --- a/src/test/ui/borrowck/reassignment_immutable_fields.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0381]: assign to part of possibly uninitialized variable: `x` - --> $DIR/reassignment_immutable_fields.rs:7:5 - | -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ use of possibly uninitialized `x` - -error[E0381]: assign to part of possibly uninitialized variable: `x` - --> $DIR/reassignment_immutable_fields.rs:15:5 - | -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ use of possibly uninitialized `x` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/reassignment_immutable_fields.rs b/src/test/ui/borrowck/reassignment_immutable_fields.rs index 4529e32a6928e..fd2ab62a40f1d 100644 --- a/src/test/ui/borrowck/reassignment_immutable_fields.rs +++ b/src/test/ui/borrowck/reassignment_immutable_fields.rs @@ -5,16 +5,16 @@ fn assign_both_fields_and_use() { let x: (u32, u32); x.0 = 1; //~ ERROR - x.1 = 22; //~ ERROR - drop(x.0); //~ ERROR - drop(x.1); //~ ERROR + x.1 = 22; + drop(x.0); + drop(x.1); } fn assign_both_fields_the_use_var() { let x: (u32, u32); x.0 = 1; //~ ERROR - x.1 = 22; //~ ERROR - drop(x); //~ ERROR + x.1 = 22; + drop(x); } fn main() { } diff --git a/src/test/ui/borrowck/reassignment_immutable_fields.stderr b/src/test/ui/borrowck/reassignment_immutable_fields.stderr index c63f56702ab69..d455a8f078743 100644 --- a/src/test/ui/borrowck/reassignment_immutable_fields.stderr +++ b/src/test/ui/borrowck/reassignment_immutable_fields.stderr @@ -1,56 +1,15 @@ -error[E0594]: cannot assign to field `x.0` of immutable binding +error[E0381]: assign to part of possibly uninitialized variable: `x` --> $DIR/reassignment_immutable_fields.rs:7:5 | -LL | let x: (u32, u32); - | - help: make this binding mutable: `mut x` -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ cannot mutably borrow field of immutable binding +LL | x.0 = 1; + | ^^^^^^^ use of possibly uninitialized `x` -error[E0594]: cannot assign to field `x.1` of immutable binding - --> $DIR/reassignment_immutable_fields.rs:8:5 - | -LL | let x: (u32, u32); - | - help: make this binding mutable: `mut x` -LL | x.0 = 1; //~ ERROR -LL | x.1 = 22; //~ ERROR - | ^^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0381]: use of possibly uninitialized variable: `x.0` - --> $DIR/reassignment_immutable_fields.rs:9:10 - | -LL | drop(x.0); //~ ERROR - | ^^^ use of possibly uninitialized `x.0` - -error[E0381]: use of possibly uninitialized variable: `x.1` - --> $DIR/reassignment_immutable_fields.rs:10:10 - | -LL | drop(x.1); //~ ERROR - | ^^^ use of possibly uninitialized `x.1` - -error[E0594]: cannot assign to field `x.0` of immutable binding +error[E0381]: assign to part of possibly uninitialized variable: `x` --> $DIR/reassignment_immutable_fields.rs:15:5 | -LL | let x: (u32, u32); - | - help: make this binding mutable: `mut x` -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0594]: cannot assign to field `x.1` of immutable binding - --> $DIR/reassignment_immutable_fields.rs:16:5 - | -LL | let x: (u32, u32); - | - help: make this binding mutable: `mut x` -LL | x.0 = 1; //~ ERROR -LL | x.1 = 22; //~ ERROR - | ^^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0381]: use of possibly uninitialized variable: `x` - --> $DIR/reassignment_immutable_fields.rs:17:10 - | -LL | drop(x); //~ ERROR - | ^ use of possibly uninitialized `x` +LL | x.0 = 1; + | ^^^^^^^ use of possibly uninitialized `x` -error: aborting due to 7 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0381, E0594. -For more information about an error, try `rustc --explain E0381`. +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.nll.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.nll.stderr deleted file mode 100644 index 53b51eb894ae7..0000000000000 --- a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.nll.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0381]: assign to part of possibly uninitialized variable: `x` - --> $DIR/reassignment_immutable_fields_overlapping.rs:12:5 - | -LL | x.a = 1; //~ ERROR - | ^^^^^^^ use of possibly uninitialized `x` - -error[E0594]: cannot assign to `x.b`, as `x` is not declared as mutable - --> $DIR/reassignment_immutable_fields_overlapping.rs:13:5 - | -LL | let x: Foo; - | - help: consider changing this to be mutable: `mut x` -LL | x.a = 1; //~ ERROR -LL | x.b = 22; //~ ERROR - | ^^^^^^^^ cannot assign - -error: aborting due to 2 previous errors - -Some errors occurred: E0381, E0594. -For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr index e34024736c6a2..649c127dcc9d4 100644 --- a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr +++ b/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr @@ -1,20 +1,18 @@ -error[E0594]: cannot assign to field `x.a` of immutable binding +error[E0381]: assign to part of possibly uninitialized variable: `x` --> $DIR/reassignment_immutable_fields_overlapping.rs:12:5 | -LL | let x: Foo; - | - help: make this binding mutable: `mut x` -LL | x.a = 1; //~ ERROR - | ^^^^^^^ cannot mutably borrow field of immutable binding +LL | x.a = 1; + | ^^^^^^^ use of possibly uninitialized `x` -error[E0594]: cannot assign to field `x.b` of immutable binding +error[E0594]: cannot assign to `x.b`, as `x` is not declared as mutable --> $DIR/reassignment_immutable_fields_overlapping.rs:13:5 | LL | let x: Foo; - | - help: make this binding mutable: `mut x` -LL | x.a = 1; //~ ERROR -LL | x.b = 22; //~ ERROR - | ^^^^^^^^ cannot mutably borrow field of immutable binding + | - help: consider changing this to be mutable: `mut x` +LL | x.a = 1; +LL | x.b = 22; + | ^^^^^^^^ cannot assign error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0594`. +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_twice.nll.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_twice.nll.stderr deleted file mode 100644 index 910b8292ec8ff..0000000000000 --- a/src/test/ui/borrowck/reassignment_immutable_fields_twice.nll.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable - --> $DIR/reassignment_immutable_fields_twice.rs:7:5 - | -LL | let x: (u32, u32); - | - help: consider changing this to be mutable: `mut x` -LL | x = (22, 44); -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ cannot assign - -error[E0381]: assign to part of possibly uninitialized variable: `x` - --> $DIR/reassignment_immutable_fields_twice.rs:12:5 - | -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ use of possibly uninitialized `x` - -error: aborting due to 2 previous errors - -Some errors occurred: E0381, E0594. -For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_twice.rs b/src/test/ui/borrowck/reassignment_immutable_fields_twice.rs index a10baf627f30b..2775a54c8304b 100644 --- a/src/test/ui/borrowck/reassignment_immutable_fields_twice.rs +++ b/src/test/ui/borrowck/reassignment_immutable_fields_twice.rs @@ -10,8 +10,8 @@ fn var_then_field() { fn same_field_twice() { let x: (u32, u32); x.0 = 1; //~ ERROR - x.0 = 22; //~ ERROR - x.1 = 44; //~ ERROR + x.0 = 22; + x.1 = 44; } fn main() { } diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr index 75d7f99ed0c8c..9a2824ccb3cd2 100644 --- a/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr +++ b/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr @@ -1,38 +1,18 @@ -error[E0594]: cannot assign to field `x.0` of immutable binding +error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable --> $DIR/reassignment_immutable_fields_twice.rs:7:5 | LL | let x: (u32, u32); - | - help: make this binding mutable: `mut x` + | - help: consider changing this to be mutable: `mut x` LL | x = (22, 44); -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ cannot mutably borrow field of immutable binding +LL | x.0 = 1; + | ^^^^^^^ cannot assign -error[E0594]: cannot assign to field `x.0` of immutable binding +error[E0381]: assign to part of possibly uninitialized variable: `x` --> $DIR/reassignment_immutable_fields_twice.rs:12:5 | -LL | let x: (u32, u32); - | - help: make this binding mutable: `mut x` -LL | x.0 = 1; //~ ERROR - | ^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0594]: cannot assign to field `x.0` of immutable binding - --> $DIR/reassignment_immutable_fields_twice.rs:13:5 - | -LL | let x: (u32, u32); - | - help: make this binding mutable: `mut x` -LL | x.0 = 1; //~ ERROR -LL | x.0 = 22; //~ ERROR - | ^^^^^^^^ cannot mutably borrow field of immutable binding - -error[E0594]: cannot assign to field `x.1` of immutable binding - --> $DIR/reassignment_immutable_fields_twice.rs:14:5 - | -LL | let x: (u32, u32); - | - help: make this binding mutable: `mut x` -... -LL | x.1 = 44; //~ ERROR - | ^^^^^^^^ cannot mutably borrow field of immutable binding +LL | x.0 = 1; + | ^^^^^^^ use of possibly uninitialized `x` -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0594`. +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr index 8d6ac6275062e..4c7c0d1a0dfa5 100644 --- a/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr +++ b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr @@ -36,13 +36,13 @@ LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d | ^^ error[E0195]: lifetime parameters or bounds on method `wrong_bound2` do not match the trait declaration - --> $DIR/regions-bound-missing-bound-in-impl.rs:41:5 + --> $DIR/regions-bound-missing-bound-in-impl.rs:41:20 | LL | fn wrong_bound2<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>); | ---------------- lifetimes in impl do not match this method in trait ... LL | fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait + | ^ lifetimes do not match method in trait error[E0276]: impl has stricter requirements than trait --> $DIR/regions-bound-missing-bound-in-impl.rs:48:5 @@ -55,5 +55,5 @@ LL | fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) { error: aborting due to 5 previous errors -Some errors occurred: E0195, E0276, E0308. +Some errors have detailed explanations: E0195, E0276, E0308. For more information about an error, try `rustc --explain E0195`. diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr new file mode 100644 index 0000000000000..4797a9d456cc1 --- /dev/null +++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr @@ -0,0 +1,12 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/regions-escape-bound-fn-2.rs:8:18 + | +LL | let mut x = None; + | ----- `x` is declared here, outside of the closure body +LL | with_int(|y| x = Some(y)); + | - ^^^^^^^^^^^ `y` escapes the closure body here + | | + | `y` is a reference that is only valid in the closure body + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr new file mode 100644 index 0000000000000..2b3a9816e454d --- /dev/null +++ b/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr @@ -0,0 +1,12 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/regions-escape-bound-fn.rs:8:18 + | +LL | let mut x: Option<&isize> = None; + | ----- `x` is declared here, outside of the closure body +LL | with_int(|y| x = Some(y)); + | - ^^^^^^^^^^^ `y` escapes the closure body here + | | + | `y` is a reference that is only valid in the closure body + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr b/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr new file mode 100644 index 0000000000000..8ceefd25344a4 --- /dev/null +++ b/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr @@ -0,0 +1,12 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/regions-escape-unboxed-closure.rs:6:23 + | +LL | let mut x: Option<&isize> = None; + | ----- `x` is declared here, outside of the closure body +LL | with_int(&mut |y| x = Some(y)); + | - ^^^^^^^^^^^ `y` escapes the closure body here + | | + | `y` is a reference that is only valid in the closure body + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.rs b/src/test/ui/borrowck/regions-escape-unboxed-closure.rs index 62ddf4decfcab..d8bef927fd722 100644 --- a/src/test/ui/borrowck/regions-escape-unboxed-closure.rs +++ b/src/test/ui/borrowck/regions-escape-unboxed-closure.rs @@ -1,4 +1,4 @@ -fn with_int(f: &mut FnMut(&isize)) { +fn with_int(f: &mut dyn FnMut(&isize)) { } fn main() { diff --git a/src/test/ui/borrowck/return-local-binding-from-desugaring.rs b/src/test/ui/borrowck/return-local-binding-from-desugaring.rs new file mode 100644 index 0000000000000..b2dcd54ec2e90 --- /dev/null +++ b/src/test/ui/borrowck/return-local-binding-from-desugaring.rs @@ -0,0 +1,33 @@ +// To avoid leaking the names of local bindings from expressions like for loops, #60984 +// explicitly ignored them, but an assertion that `LocalKind::Var` *must* have a name would +// trigger an ICE. Before this change, this file's output would be: +// ``` +// error[E0515]: cannot return value referencing local variable `__next` +// --> return-local-binding-from-desugaring.rs:LL:CC +// | +// LL | for ref x in xs { +// | ----- `__next` is borrowed here +// ... +// LL | result +// | ^^^^^^ returns a value referencing data owned by the current function +// ``` +// FIXME: ideally `LocalKind` would carry more information to more accurately explain the problem. + +use std::collections::HashMap; +use std::hash::Hash; + +fn group_by(xs: &mut I, f: F) -> HashMap> +where + I: Iterator, + F: Fn(&I::Item) -> T, + T: Eq + Hash, +{ + let mut result = HashMap::new(); + for ref x in xs { + let key = f(x); + result.entry(key).or_insert(Vec::new()).push(x); + } + result //~ ERROR cannot return value referencing local binding +} + +fn main() {} diff --git a/src/test/ui/borrowck/return-local-binding-from-desugaring.stderr b/src/test/ui/borrowck/return-local-binding-from-desugaring.stderr new file mode 100644 index 0000000000000..293dbe6281313 --- /dev/null +++ b/src/test/ui/borrowck/return-local-binding-from-desugaring.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return value referencing local binding + --> $DIR/return-local-binding-from-desugaring.rs:30:5 + | +LL | for ref x in xs { + | -- local binding introduced here +... +LL | result + | ^^^^^^ returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/two-phase-across-loop.rs b/src/test/ui/borrowck/two-phase-across-loop.rs index b1a4c54f49b15..12222342c95a1 100644 --- a/src/test/ui/borrowck/two-phase-across-loop.rs +++ b/src/test/ui/borrowck/two-phase-across-loop.rs @@ -1,8 +1,6 @@ // Test that a borrow which starts as a 2-phase borrow and gets // carried around a loop winds up conflicting with itself. -#![feature(nll)] - struct Foo { x: String } impl Foo { diff --git a/src/test/ui/borrowck/two-phase-across-loop.stderr b/src/test/ui/borrowck/two-phase-across-loop.stderr index 10ff0ca604c5a..38993a50bf6b2 100644 --- a/src/test/ui/borrowck/two-phase-across-loop.stderr +++ b/src/test/ui/borrowck/two-phase-across-loop.stderr @@ -1,7 +1,7 @@ error[E0499]: cannot borrow `foo` as mutable more than once at a time - --> $DIR/two-phase-across-loop.rs:19:22 + --> $DIR/two-phase-across-loop.rs:17:22 | -LL | strings.push(foo.get_string()); //~ ERROR cannot borrow `foo` as mutable +LL | strings.push(foo.get_string()); | ^^^ mutable borrow starts here in previous iteration of loop error: aborting due to previous error diff --git a/src/test/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr b/src/test/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr index 7bae14382d048..40786c032b180 100644 --- a/src/test/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr +++ b/src/test/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr @@ -1,27 +1,27 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-activation-sharing-interference.rs:32:15 + --> $DIR/two-phase-activation-sharing-interference.rs:30:15 | LL | let y = &mut x; | ------ mutable borrow occurs here LL | { let z = &x; read(z); } | ^^ immutable borrow occurs here -LL | //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable +LL | LL | *y += 1; | ------- mutable borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-activation-sharing-interference.rs:40:13 + --> $DIR/two-phase-activation-sharing-interference.rs:38:13 | LL | let y = &mut x; | ------ mutable borrow occurs here LL | let z = &x; | ^^ immutable borrow occurs here -LL | //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable +LL | LL | *y += 1; | ------- mutable borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-activation-sharing-interference.rs:51:13 + --> $DIR/two-phase-activation-sharing-interference.rs:49:13 | LL | let y = &mut x; | ------ mutable borrow occurs here @@ -32,13 +32,13 @@ LL | *y += 1; | ------- mutable borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-activation-sharing-interference.rs:62:14 + --> $DIR/two-phase-activation-sharing-interference.rs:60:14 | LL | let y = &mut x; | ------ mutable borrow occurs here LL | let _z = &x; | ^^ immutable borrow occurs here -LL | //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable +LL | LL | *y += 1; | ------- mutable borrow later used here diff --git a/src/test/ui/borrowck/two-phase-activation-sharing-interference.rs b/src/test/ui/borrowck/two-phase-activation-sharing-interference.rs index 5754220e824f5..4d77ac915b1e7 100644 --- a/src/test/ui/borrowck/two-phase-activation-sharing-interference.rs +++ b/src/test/ui/borrowck/two-phase-activation-sharing-interference.rs @@ -1,11 +1,9 @@ -// ignore-tidy-linelength - // revisions: nll_target // The following revisions are disabled due to missing support from two-phase beyond autorefs -//[nll_beyond] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref +//[nll_beyond] compile-flags: -Z borrowck=mir -Z two-phase-beyond-autoref -//[nll_target] compile-flags: -Z borrowck=mir -Z two-phase-borrows +//[nll_target] compile-flags: -Z borrowck=mir // This is an important corner case pointed out by Niko: one is // allowed to initiate a shared borrow during a reservation, but it diff --git a/src/test/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr b/src/test/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr index 232876e6f0b74..9f31c3f87c37d 100644 --- a/src/test/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr +++ b/src/test/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr @@ -16,7 +16,7 @@ error[E0503]: cannot use `i` because it was mutably borrowed LL | /*1*/ let p = &mut i; // (reservation of `i` starts here) | ------ borrow of `i` occurs here ... -LL | /*4*/ let k = i; //[nll_beyond]~ ERROR cannot use `i` because it was mutably borrowed [E0503] +LL | /*4*/ let k = i; | ^ use of borrowed `i` ... LL | /*5*/ *p += 1; diff --git a/src/test/ui/borrowck/two-phase-allow-access-during-reservation.rs b/src/test/ui/borrowck/two-phase-allow-access-during-reservation.rs index e428964939aff..07169afefc988 100644 --- a/src/test/ui/borrowck/two-phase-allow-access-during-reservation.rs +++ b/src/test/ui/borrowck/two-phase-allow-access-during-reservation.rs @@ -3,9 +3,9 @@ // revisions: nll_target // The following revisions are disabled due to missing support for two_phase_beyond_autoref -//[nll_beyond] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two_phase_beyond_autoref +//[nll_beyond] compile-flags: -Z borrowck=mir -Z two_phase_beyond_autoref -//[nll_target] compile-flags: -Z borrowck=mir -Z two-phase-borrows +//[nll_target] compile-flags: -Z borrowck=mir // This is the second counter-example from Niko's blog post // smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/ diff --git a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.rs b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.rs index fd1b8841b4e8a..f2097fdf823f1 100644 --- a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.rs +++ b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z borrowck=mir -Z two-phase-borrows +// compile-flags: -Z borrowck=mir // This is the third counter-example from Niko's blog post // smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/ diff --git a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr index 9123e1890fe9a..9bfd8b994bf23 100644 --- a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr +++ b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr @@ -7,7 +7,7 @@ LL | vec.get({ | immutable borrow occurs here LL | LL | vec.push(2); - | ^^^^^^^^^^^ mutable borrow occurs here + | ^^^ mutable borrow occurs here error: aborting due to previous error diff --git a/src/test/ui/borrowck/two-phase-method-receivers.rs b/src/test/ui/borrowck/two-phase-method-receivers.rs index f1df1a6a2c899..6838f6c7efd5d 100644 --- a/src/test/ui/borrowck/two-phase-method-receivers.rs +++ b/src/test/ui/borrowck/two-phase-method-receivers.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z borrowck=mir -Z two-phase-borrows +// compile-flags: -Z borrowck=mir // run-pass diff --git a/src/test/ui/borrowck/two-phase-multi-mut.rs b/src/test/ui/borrowck/two-phase-multi-mut.rs index ed3d257da9f0f..bb646d7caf1e2 100644 --- a/src/test/ui/borrowck/two-phase-multi-mut.rs +++ b/src/test/ui/borrowck/two-phase-multi-mut.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - struct Foo { } diff --git a/src/test/ui/borrowck/two-phase-multi-mut.stderr b/src/test/ui/borrowck/two-phase-multi-mut.stderr index c4168503e4cca..33fa4a3a15075 100644 --- a/src/test/ui/borrowck/two-phase-multi-mut.stderr +++ b/src/test/ui/borrowck/two-phase-multi-mut.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `foo` as mutable more than once at a time - --> $DIR/two-phase-multi-mut.rs:13:5 + --> $DIR/two-phase-multi-mut.rs:11:5 | LL | foo.method(&mut foo); | ^^^^------^--------^ @@ -9,7 +9,7 @@ LL | foo.method(&mut foo); | second mutable borrow occurs here error[E0499]: cannot borrow `foo` as mutable more than once at a time - --> $DIR/two-phase-multi-mut.rs:13:16 + --> $DIR/two-phase-multi-mut.rs:11:16 | LL | foo.method(&mut foo); | --- ------ ^^^^^^^^ second mutable borrow occurs here diff --git a/src/test/ui/borrowck/two-phase-multiple-activations.rs b/src/test/ui/borrowck/two-phase-multiple-activations.rs index 38ba094864069..a7fa7fac13e73 100644 --- a/src/test/ui/borrowck/two-phase-multiple-activations.rs +++ b/src/test/ui/borrowck/two-phase-multiple-activations.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z borrowck=mir -Z two-phase-borrows +// compile-flags: -Z borrowck=mir // run-pass diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr deleted file mode 100644 index d026f81b7aad6..0000000000000 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr +++ /dev/null @@ -1,85 +0,0 @@ -error[E0499]: cannot borrow `*f` as mutable more than once at a time - --> $DIR/two-phase-nonrecv-autoref.rs:60:11 - | -LL | f(f(10)); - | - ^ second mutable borrow occurs here - | | - | first mutable borrow occurs here - | first borrow later used by call - -error[E0382]: use of moved value: `*f` - --> $DIR/two-phase-nonrecv-autoref.rs:69:11 - | -LL | fn twice_ten_so i32>(f: Box) { - | - consider adding a `Copy` constraint to this type argument -LL | f(f(10)); - | - ^ value used here after move - | | - | value moved here - | - = note: move occurs because `*f` has type `F`, which does not implement the `Copy` trait - -error[E0499]: cannot borrow `*f` as mutable more than once at a time - --> $DIR/two-phase-nonrecv-autoref.rs:76:11 - | -LL | f(f(10)); - | - ^ second mutable borrow occurs here - | | - | first mutable borrow occurs here - | first borrow later used by call - -error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined - --> $DIR/two-phase-nonrecv-autoref.rs:85:9 - | -LL | f(f(10)); - | ^ - -error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined - --> $DIR/two-phase-nonrecv-autoref.rs:85:11 - | -LL | f(f(10)); - | ^ - -error[E0382]: use of moved value: `*f` - --> $DIR/two-phase-nonrecv-autoref.rs:85:11 - | -LL | f(f(10)); - | - ^ value used here after move - | | - | value moved here - | - = note: move occurs because `*f` has type `dyn std::ops::FnOnce(i32) -> i32`, which does not implement the `Copy` trait - -error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:129:27 - | -LL | double_access(&mut a, &a); - | ------------- ------ ^^ immutable borrow occurs here - | | | - | | mutable borrow occurs here - | mutable borrow later used by call - -error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:157:7 - | -LL | i[i[3]] = 4; - | --^---- - | | | - | | immutable borrow occurs here - | mutable borrow occurs here - | mutable borrow later used here - -error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:163:7 - | -LL | i[i[3]] = i[4]; - | --^---- - | | | - | | immutable borrow occurs here - | mutable borrow occurs here - | mutable borrow later used here - -error: aborting due to 9 previous errors - -Some errors occurred: E0161, E0382, E0499, E0502. -For more information about an error, try `rustc --explain E0161`. diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.stderr deleted file mode 100644 index 426939f371ca5..0000000000000 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.stderr +++ /dev/null @@ -1,113 +0,0 @@ -error[E0503]: cannot use `*x` because it was mutably borrowed - --> $DIR/two-phase-nonrecv-autoref.rs:31:12 - | -LL | foo(x, *x); - | - ^^ use of borrowed `*x` - | | - | borrow of `*x` occurs here - -error[E0499]: cannot borrow `*f` as mutable more than once at a time - --> $DIR/two-phase-nonrecv-autoref.rs:60:11 - | -LL | f(f(10)); - | - ^ - first borrow ends here - | | | - | | second mutable borrow occurs here - | first mutable borrow occurs here - -error[E0382]: use of moved value: `*f` - --> $DIR/two-phase-nonrecv-autoref.rs:69:11 - | -LL | f(f(10)); - | - ^ value used here after move - | | - | value moved here - | - = note: move occurs because `*f` has type `F`, which does not implement the `Copy` trait - -error[E0499]: cannot borrow `*f` as mutable more than once at a time - --> $DIR/two-phase-nonrecv-autoref.rs:76:11 - | -LL | f(f(10)); - | - ^ - first borrow ends here - | | | - | | second mutable borrow occurs here - | first mutable borrow occurs here - -error[E0382]: use of moved value: `*f` - --> $DIR/two-phase-nonrecv-autoref.rs:85:11 - | -LL | f(f(10)); - | - ^ value used here after move - | | - | value moved here - | - = note: move occurs because `*f` has type `(dyn std::ops::FnOnce(i32) -> i32 + 'static)`, which does not implement the `Copy` trait - -error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:129:28 - | -LL | double_access(&mut a, &a); - | - ^- mutable borrow ends here - | | | - | | immutable borrow occurs here - | mutable borrow occurs here - -error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:135:9 - | -LL | a.m(a.i(10)); - | - ^ - mutable borrow ends here - | | | - | | immutable borrow occurs here - | mutable borrow occurs here - -error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:157:7 - | -LL | i[i[3]] = 4; - | - ^ - mutable borrow ends here - | | | - | | immutable borrow occurs here - | mutable borrow occurs here - -error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:163:7 - | -LL | i[i[3]] = i[4]; - | - ^ - mutable borrow ends here - | | | - | | immutable borrow occurs here - | mutable borrow occurs here - -error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:172:12 - | -LL | v.push(v.len()); - | - ^ - mutable borrow ends here - | | | - | | immutable borrow occurs here - | mutable borrow occurs here - -error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:183:9 - | -LL | s.m(s.i(10)); - | - ^ - mutable borrow ends here - | | | - | | immutable borrow occurs here - | mutable borrow occurs here - -error[E0502]: cannot borrow `t` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:188:9 - | -LL | t.m(t.i(10)); - | - ^ - mutable borrow ends here - | | | - | | immutable borrow occurs here - | mutable borrow occurs here - -error: aborting due to 12 previous errors - -Some errors occurred: E0382, E0499, E0502, E0503. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr index d026f81b7aad6..baf122df5e268 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `*f` as mutable more than once at a time - --> $DIR/two-phase-nonrecv-autoref.rs:60:11 + --> $DIR/two-phase-nonrecv-autoref.rs:58:11 | LL | f(f(10)); | - ^ second mutable borrow occurs here @@ -7,20 +7,18 @@ LL | f(f(10)); | first mutable borrow occurs here | first borrow later used by call -error[E0382]: use of moved value: `*f` - --> $DIR/two-phase-nonrecv-autoref.rs:69:11 +error[E0382]: use of moved value: `f` + --> $DIR/two-phase-nonrecv-autoref.rs:66:11 | LL | fn twice_ten_so i32>(f: Box) { - | - consider adding a `Copy` constraint to this type argument + | - move occurs because `f` has type `std::boxed::Box`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | | value moved here - | - = note: move occurs because `*f` has type `F`, which does not implement the `Copy` trait error[E0499]: cannot borrow `*f` as mutable more than once at a time - --> $DIR/two-phase-nonrecv-autoref.rs:76:11 + --> $DIR/two-phase-nonrecv-autoref.rs:72:11 | LL | f(f(10)); | - ^ second mutable borrow occurs here @@ -28,30 +26,18 @@ LL | f(f(10)); | first mutable borrow occurs here | first borrow later used by call -error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined - --> $DIR/two-phase-nonrecv-autoref.rs:85:9 - | -LL | f(f(10)); - | ^ - -error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined - --> $DIR/two-phase-nonrecv-autoref.rs:85:11 - | -LL | f(f(10)); - | ^ - -error[E0382]: use of moved value: `*f` - --> $DIR/two-phase-nonrecv-autoref.rs:85:11 +error[E0382]: use of moved value: `f` + --> $DIR/two-phase-nonrecv-autoref.rs:80:11 | +LL | fn twice_ten_oo(f: Box i32>) { + | - move occurs because `f` has type `std::boxed::Box i32>`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | | value moved here - | - = note: move occurs because `*f` has type `dyn std::ops::FnOnce(i32) -> i32`, which does not implement the `Copy` trait error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:129:27 + --> $DIR/two-phase-nonrecv-autoref.rs:119:27 | LL | double_access(&mut a, &a); | ------------- ------ ^^ immutable borrow occurs here @@ -60,7 +46,7 @@ LL | double_access(&mut a, &a); | mutable borrow later used by call error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:157:7 + --> $DIR/two-phase-nonrecv-autoref.rs:145:7 | LL | i[i[3]] = 4; | --^---- @@ -70,7 +56,7 @@ LL | i[i[3]] = 4; | mutable borrow later used here error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:163:7 + --> $DIR/two-phase-nonrecv-autoref.rs:150:7 | LL | i[i[3]] = i[4]; | --^---- @@ -79,7 +65,7 @@ LL | i[i[3]] = i[4]; | mutable borrow occurs here | mutable borrow later used here -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors -Some errors occurred: E0161, E0382, E0499, E0502. -For more information about an error, try `rustc --explain E0161`. +Some errors have detailed explanations: E0382, E0499, E0502. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs b/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs index 1a14cb90f38ef..b29664e3d8cbd 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs @@ -1,8 +1,7 @@ -// revisions: ast nll -//[ast]compile-flags: -//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows +// revisions: nll +//[nll]compile-flags: -Z borrowck=mir -//[g2p]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref +//[g2p]compile-flags: -Z borrowck=mir -Z two-phase-beyond-autoref // the above revision is disabled until two-phase-beyond-autoref support is better // This is a test checking that when we limit two-phase borrows to @@ -29,7 +28,6 @@ fn foo(x: &mut u32, y: u32) { fn deref_coercion(x: &mut u32) { foo(x, *x); - //[ast]~^ ERROR cannot use `*x` because it was mutably borrowed [E0503] // Above error is a known limitation of AST borrowck } @@ -60,36 +58,28 @@ fn overloaded_call_traits() { f(f(10)); //[nll]~^ ERROR cannot borrow `*f` as mutable more than once at a time //[g2p]~^^ ERROR cannot borrow `*f` as mutable more than once at a time - //[ast]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time } fn twice_ten_si i32>(f: &mut F) { f(f(10)); } fn twice_ten_so i32>(f: Box) { f(f(10)); - //[nll]~^ ERROR use of moved value: `*f` - //[g2p]~^^ ERROR use of moved value: `*f` - //[ast]~^^^ ERROR use of moved value: `*f` + //[nll]~^ ERROR use of moved value: `f` + //[g2p]~^^ ERROR use of moved value: `f` } - fn twice_ten_om(f: &mut FnMut(i32) -> i32) { + fn twice_ten_om(f: &mut dyn FnMut(i32) -> i32) { f(f(10)); //[nll]~^ ERROR cannot borrow `*f` as mutable more than once at a time //[g2p]~^^ ERROR cannot borrow `*f` as mutable more than once at a time - //[ast]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time } - fn twice_ten_oi(f: &mut Fn(i32) -> i32) { + fn twice_ten_oi(f: &mut dyn Fn(i32) -> i32) { f(f(10)); } - fn twice_ten_oo(f: Box i32>) { + fn twice_ten_oo(f: Box i32>) { f(f(10)); - //[nll]~^ ERROR cannot move a value of type - //[nll]~^^ ERROR cannot move a value of type - //[nll]~^^^ ERROR use of moved value: `*f` - //[g2p]~^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^^ ERROR use of moved value: `*f` - //[ast]~^^^^^^^ ERROR use of moved value: `*f` + //[nll]~^ ERROR use of moved value: `f` + //[g2p]~^^ ERROR use of moved value: `f` } twice_ten_sm(&mut |x| x + 1); @@ -129,11 +119,9 @@ fn coerce_unsized() { double_access(&mut a, &a); //[nll]~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502] //[g2p]~^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502] - //[ast]~^^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502] // But this is okay. a.m(a.i(10)); - //[ast]~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502] // Above error is an expected limitation of AST borrowck } @@ -156,13 +144,11 @@ fn coerce_index_op() { let mut i = I(10); i[i[3]] = 4; //[nll]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502] - //[ast]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502] i[3] = i[4]; i[i[3]] = i[4]; //[nll]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502] - //[ast]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502] } fn main() { @@ -170,7 +156,6 @@ fn main() { // As a reminder, this is the basic case we want to ensure we handle. let mut v = vec![1, 2, 3]; v.push(v.len()); - //[ast]~^ ERROR cannot borrow `v` as immutable because it is also borrowed as mutable [E0502] // Error above is an expected limitation of AST borrowck // (as a rule, pnkfelix does not like to write tests with dead code.) @@ -181,12 +166,10 @@ fn main() { let mut s = S; s.m(s.i(10)); - //[ast]~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable [E0502] // Error above is an expected limitation of AST borrowck let mut t = T; t.m(t.i(10)); - //[ast]~^ ERROR cannot borrow `t` as immutable because it is also borrowed as mutable [E0502] // Error above is an expected limitation of AST borrowck coerce_unsized(); diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr new file mode 100644 index 0000000000000..8eb468892f24a --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr @@ -0,0 +1,40 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:18:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.extend(shared); + | ^^------^^^^^^^^ + | | | + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:28:5 + | +LL | v.extend(&v); + | ^^------^--^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +warning: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:39:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + | + = note: #[warn(mutable_borrow_reservation_conflict)] on by default + = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future + = note: for more information, see issue #59159 + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr new file mode 100644 index 0000000000000..8eb468892f24a --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr @@ -0,0 +1,40 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:18:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.extend(shared); + | ^^------^^^^^^^^ + | | | + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:28:5 + | +LL | v.extend(&v); + | ^^------^--^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +warning: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:39:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + | + = note: #[warn(mutable_borrow_reservation_conflict)] on by default + = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future + = note: for more information, see issue #59159 + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr new file mode 100644 index 0000000000000..730741c7a9ae2 --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr @@ -0,0 +1,35 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:18:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.extend(shared); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:28:5 + | +LL | v.extend(&v); + | ^^------^--^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:39:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr new file mode 100644 index 0000000000000..730741c7a9ae2 --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr @@ -0,0 +1,35 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:18:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.extend(shared); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:28:5 + | +LL | v.extend(&v); + | ^^------^--^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:39:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.rs b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.rs index 13c1df7db2bc7..de1af3aaa05e4 100644 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.rs +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.rs @@ -1,24 +1,49 @@ -// compile-flags: -Z borrowck=mir -Z two-phase-borrows - -// This is similar to two-phase-reservation-sharing-interference.rs -// in that it shows a reservation that overlaps with a shared borrow. -// -// Currently, this test fails with lexical lifetimes, but succeeds -// with non-lexical lifetimes. (The reason is because the activation -// of the mutable borrow ends up overlapping with a lexically-scoped -// shared borrow; but a non-lexical shared borrow can end before the -// activation occurs.) -// -// So this test is just making a note of the current behavior. - -#![feature(rustc_attrs)] - -#[rustc_error] -fn main() { //~ ERROR compilation successful +// Test for #56254, we previously allowed the last example on the 2018 +// edition. Make sure that we now emit a warning in that case and an error for +// everyone else. + +//ignore-compare-mode-nll + +//revisions: migrate2015 migrate2018 nll2015 nll2018 + +//[migrate2018] edition:2018 +//[nll2018] edition:2018 + +#![cfg_attr(any(nll2015, nll2018), feature(nll))] + +fn double_conflicts() { + let mut v = vec![0, 1, 2]; + let shared = &v; + + v.extend(shared); + //[migrate2015]~^ ERROR cannot borrow `v` as mutable + //[nll2015]~^^ ERROR cannot borrow `v` as mutable + //[migrate2018]~^^^ ERROR cannot borrow `v` as mutable + //[nll2018]~^^^^ ERROR cannot borrow `v` as mutable +} + +fn activation_conflict() { + let mut v = vec![0, 1, 2]; + + v.extend(&v); + //[migrate2015]~^ ERROR cannot borrow `v` as mutable + //[nll2015]~^^ ERROR cannot borrow `v` as mutable + //[migrate2018]~^^^ ERROR cannot borrow `v` as mutable + //[nll2018]~^^^^ ERROR cannot borrow `v` as mutable +} + +fn reservation_conflict() { let mut v = vec![0, 1, 2]; let shared = &v; v.push(shared.len()); + //[nll2015]~^ ERROR cannot borrow `v` as mutable + //[nll2018]~^^ ERROR cannot borrow `v` as mutable + //[migrate2015]~^^^ WARNING cannot borrow `v` as mutable + //[migrate2015]~| WARNING may become a hard error in the future - assert_eq!(v, [0, 1, 2, 3]); + //[migrate2018]~^^^^^^ WARNING cannot borrow `v` as mutable + //[migrate2018]~| WARNING may become a hard error in the future } + +fn main() {} diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr deleted file mode 100644 index ad4636a4a91c6..0000000000000 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: compilation successful - --> $DIR/two-phase-reservation-sharing-interference-2.rs:17:1 - | -LL | / fn main() { //~ ERROR compilation successful -LL | | let mut v = vec![0, 1, 2]; -LL | | let shared = &v; -LL | | -... | -LL | | assert_eq!(v, [0, 1, 2, 3]); -LL | | } - | |_^ - -error: aborting due to previous error - diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr new file mode 100644 index 0000000000000..d2ea5ab2077e5 --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr @@ -0,0 +1,36 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:13:9 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:24:9 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:37:9 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.rs b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.rs new file mode 100644 index 0000000000000..0e1d77ace3f70 --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.rs @@ -0,0 +1,43 @@ +// Check that the future-compat-lint for the reservation conflict is +// handled like any other lint. + +// edition:2018 + +mod future_compat_allow { + #![allow(mutable_borrow_reservation_conflict)] + + fn reservation_conflict() { + let mut v = vec![0, 1, 2]; + let shared = &v; + + v.push(shared.len()); + } +} + +mod future_compat_warn { + #![warn(mutable_borrow_reservation_conflict)] + + fn reservation_conflict() { + let mut v = vec![0, 1, 2]; + let shared = &v; + + v.push(shared.len()); + //~^ WARNING cannot borrow `v` as mutable + //~| WARNING may become a hard error in the future + } +} + +mod future_compat_deny { + #![deny(mutable_borrow_reservation_conflict)] + + fn reservation_conflict() { + let mut v = vec![0, 1, 2]; + let shared = &v; + + v.push(shared.len()); + //~^ ERROR cannot borrow `v` as mutable + //~| WARNING may become a hard error in the future + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr new file mode 100644 index 0000000000000..77fbfb37addd0 --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr @@ -0,0 +1,40 @@ +warning: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:24:9 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + | +note: lint level defined here + --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:18:13 + | +LL | #![warn(mutable_borrow_reservation_conflict)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future + = note: for more information, see issue #59159 + +error: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:37:9 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + | +note: lint level defined here + --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:31:13 + | +LL | #![deny(mutable_borrow_reservation_conflict)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future + = note: for more information, see issue #59159 + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference.rs b/src/test/ui/borrowck/two-phase-reservation-sharing-interference.rs index f5fa8218edc71..de6f66c1c3f9b 100644 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference.rs +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference.rs @@ -3,10 +3,10 @@ // revisions: nll_target // The following revisions are disabled due to missing support from two-phase beyond autorefs -//[nll_beyond]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref +//[nll_beyond]compile-flags: -Z borrowck=mir -Z two-phase-beyond-autoref //[nll_beyond] should-fail -//[nll_target]compile-flags: -Z borrowck=mir -Z two-phase-borrows +//[nll_target]compile-flags: -Z borrowck=mir // This is a corner case that the current implementation is (probably) // treating more conservatively than is necessary. But it also does @@ -47,4 +47,3 @@ fn main() { // flummoxes our attmpt to delay the activation point here.) delay.push(2); } - diff --git a/src/test/ui/borrowck/two-phase-sneaky.nll.stderr b/src/test/ui/borrowck/two-phase-sneaky.nll.stderr deleted file mode 100644 index c66f3cbed918d..0000000000000 --- a/src/test/ui/borrowck/two-phase-sneaky.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0499]: cannot borrow `v` as mutable more than once at a time - --> $DIR/two-phase-sneaky.rs:12:9 - | -LL | v[0].push_str({ - | - -------- first borrow later used by call - | | - | first mutable borrow occurs here -LL | -LL | v.push(format!("foo")); - | ^ second mutable borrow occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/two-phase-sneaky.rs b/src/test/ui/borrowck/two-phase-sneaky.rs index abfa13da6af00..b6e33d5d1b82f 100644 --- a/src/test/ui/borrowck/two-phase-sneaky.rs +++ b/src/test/ui/borrowck/two-phase-sneaky.rs @@ -1,4 +1,4 @@ -// cmpile-flags: -Z borrowck=mir -Z two-phase-borrows +// cmpile-flags: -Z borrowck=mir // This is the first counter-example from Niko's blog post // smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/ diff --git a/src/test/ui/borrowck/two-phase-sneaky.stderr b/src/test/ui/borrowck/two-phase-sneaky.stderr index 38f24ccd6068b..c66f3cbed918d 100644 --- a/src/test/ui/borrowck/two-phase-sneaky.stderr +++ b/src/test/ui/borrowck/two-phase-sneaky.stderr @@ -2,13 +2,12 @@ error[E0499]: cannot borrow `v` as mutable more than once at a time --> $DIR/two-phase-sneaky.rs:12:9 | LL | v[0].push_str({ - | - first mutable borrow occurs here + | - -------- first borrow later used by call + | | + | first mutable borrow occurs here LL | LL | v.push(format!("foo")); | ^ second mutable borrow occurs here -... -LL | }); - | - first borrow ends here error: aborting due to previous error diff --git a/src/test/ui/borrowck/two-phase-surprise-no-conflict.ast.stderr b/src/test/ui/borrowck/two-phase-surprise-no-conflict.ast.stderr deleted file mode 100644 index a2e5c7e88e820..0000000000000 --- a/src/test/ui/borrowck/two-phase-surprise-no-conflict.ast.stderr +++ /dev/null @@ -1,133 +0,0 @@ -error[E0503]: cannot use `self.cx` because it was mutably borrowed - --> $DIR/two-phase-surprise-no-conflict.rs:30:13 - | -LL | let _mut_borrow = &mut *self; - | ----- borrow of `*self` occurs here -LL | let _access = self.cx; - | ^^^^^^^ use of borrowed `*self` - -error[E0502]: cannot borrow `*self.cx_mut` as immutable because `*self` is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:69:33 - | -LL | self.hash_expr(&self.cx_mut.body(eid).value); - | ---- ^^^^^^^^^^^ - mutable borrow ends here - | | | - | | immutable borrow occurs here - | mutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because `*reg` is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:121:52 - | -LL | reg.register_static(Box::new(TrivialPass::new(®.sess_mut))); - | --- ^^^^^^^^^^^^ - mutable borrow ends here - | | | - | mutable borrow occurs here immutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because `*reg` is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:125:51 - | -LL | reg.register_bound(Box::new(TrivialPass::new(®.sess_mut))); - | --- ^^^^^^^^^^^^ - mutable borrow ends here - | | | - | mutable borrow occurs here immutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because `*reg` is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:129:50 - | -LL | reg.register_univ(Box::new(TrivialPass::new(®.sess_mut))); - | --- ^^^^^^^^^^^^ - mutable borrow ends here - | | | - | mutable borrow occurs here immutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because `*reg` is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:133:41 - | -LL | reg.register_ref(&TrivialPass::new(®.sess_mut)); - | --- ^^^^^^^^^^^^ - mutable borrow ends here - | | | - | mutable borrow occurs here immutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:141:56 - | -LL | reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut))); - | --- ^^^^^^^^^^^^ - first borrow ends here - | | | - | first mutable borrow occurs here second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:146:59 - | -LL | reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- ^^^^^^^^^^^^ - first borrow ends here - | | | - | first mutable borrow occurs here second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:151:58 - | -LL | reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- ^^^^^^^^^^^^ - first borrow ends here - | | | - | first mutable borrow occurs here second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:156:49 - | -LL | reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut)); - | --- ^^^^^^^^^^^^ - first borrow ends here - | | | - | first mutable borrow occurs here second mutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because `*reg` is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:168:51 - | -LL | reg.register_bound(Box::new(CapturePass::new(®.sess_mut))); - | --- ^^^^^^^^^^^^ - mutable borrow ends here - | | | - | mutable borrow occurs here immutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because `*reg` is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:173:50 - | -LL | reg.register_univ(Box::new(CapturePass::new(®.sess_mut))); - | --- ^^^^^^^^^^^^ - mutable borrow ends here - | | | - | mutable borrow occurs here immutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because `*reg` is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:178:41 - | -LL | reg.register_ref(&CapturePass::new(®.sess_mut)); - | --- ^^^^^^^^^^^^ - mutable borrow ends here - | | | - | mutable borrow occurs here immutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:190:59 - | -LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- ^^^^^^^^^^^^ - first borrow ends here - | | | - | first mutable borrow occurs here second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:196:58 - | -LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- ^^^^^^^^^^^^ - first borrow ends here - | | | - | first mutable borrow occurs here second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:202:49 - | -LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); - | --- ^^^^^^^^^^^^ - first borrow ends here - | | | - | first mutable borrow occurs here second mutable borrow occurs here - -error: aborting due to 16 previous errors - -Some errors occurred: E0499, E0502, E0503. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/two-phase-surprise-no-conflict.nll.stderr b/src/test/ui/borrowck/two-phase-surprise-no-conflict.nll.stderr deleted file mode 100644 index 1ac3a696704bb..0000000000000 --- a/src/test/ui/borrowck/two-phase-surprise-no-conflict.nll.stderr +++ /dev/null @@ -1,154 +0,0 @@ -error[E0503]: cannot use `self.cx` because it was mutably borrowed - --> $DIR/two-phase-surprise-no-conflict.rs:30:23 - | -LL | let _mut_borrow = &mut *self; - | ---------- borrow of `*self` occurs here -LL | let _access = self.cx; - | ^^^^^^^ use of borrowed `*self` -... -LL | _mut_borrow; - | ----------- borrow later used here - -error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable - --> $DIR/two-phase-surprise-no-conflict.rs:69:17 - | -LL | self.hash_expr(&self.cx_mut.body(eid).value); - | ^^^^^---------^^-----------^^^^^^^^^^^^^^^^^ - | | | | - | | | immutable borrow occurs here - | | immutable borrow later used by call - | mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:141:51 - | -LL | reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut))); - | --- --------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:146:54 - | -LL | reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:151:53 - | -LL | reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:156:44 - | -LL | reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable - --> $DIR/two-phase-surprise-no-conflict.rs:168:5 - | -LL | reg.register_bound(Box::new(CapturePass::new(®.sess_mut))); - | ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^ - | | | | - | | | immutable borrow occurs here - | | immutable borrow later used by call - | mutable borrow occurs here - -error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable - --> $DIR/two-phase-surprise-no-conflict.rs:173:5 - | -LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) { - | -- lifetime `'a` defined here -... -LL | reg.register_univ(Box::new(CapturePass::new(®.sess_mut))); - | ^^^^^^^^^^^^^^^^^^-----------------------------------------^ - | | | | - | | | immutable borrow occurs here - | | cast requires that `reg.sess_mut` is borrowed for `'a` - | mutable borrow occurs here - -error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable - --> $DIR/two-phase-surprise-no-conflict.rs:178:5 - | -LL | reg.register_ref(&CapturePass::new(®.sess_mut)); - | ^^^^------------^^^^^^^^^^^^^^^^^^^-------------^^ - | | | | - | | | immutable borrow occurs here - | | immutable borrow later used by call - | mutable borrow occurs here - -error[E0499]: cannot borrow `*reg` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:190:5 - | -LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^^ - | | | | - | | | first mutable borrow occurs here - | | first borrow later used by call - | second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:190:54 - | -LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `*reg` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:196:5 - | -LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) { - | -- lifetime `'a` defined here -... -LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | ^^^^^^^^^^^^^^^^^^-------------------------------------------------^ - | | | | - | | | first mutable borrow occurs here - | | cast requires that `reg.sess_mut` is borrowed for `'a` - | second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:196:53 - | -LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `*reg` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:202:5 - | -LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); - | ^^^^------------^^^^^^^^^^^^^^^^^^^^^^^-----------------^^ - | | | | - | | | first mutable borrow occurs here - | | first borrow later used by call - | second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:202:44 - | -LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error: aborting due to 15 previous errors - -Some errors occurred: E0499, E0502, E0503. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/two-phase-surprise-no-conflict.no2pb.stderr b/src/test/ui/borrowck/two-phase-surprise-no-conflict.no2pb.stderr deleted file mode 100644 index 9b46567318c05..0000000000000 --- a/src/test/ui/borrowck/two-phase-surprise-no-conflict.no2pb.stderr +++ /dev/null @@ -1,159 +0,0 @@ -error[E0503]: cannot use `self.cx` because it was mutably borrowed - --> $DIR/two-phase-surprise-no-conflict.rs:30:23 - | -LL | let _mut_borrow = &mut *self; - | ---------- borrow of `*self` occurs here -LL | let _access = self.cx; - | ^^^^^^^ use of borrowed `*self` -... -LL | _mut_borrow; - | ----------- borrow later used here - -error[E0502]: cannot borrow `*self.cx` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:54:33 - | -LL | self.hash_expr(&self.cx.body(eid).value); - | ---- --------- ^^^^^^^ immutable borrow occurs here - | | | - | | mutable borrow later used by call - | mutable borrow occurs here - -error[E0502]: cannot borrow `*self.cx_mut` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:69:33 - | -LL | self.hash_expr(&self.cx_mut.body(eid).value); - | ---- --------- ^^^^^^^^^^^ immutable borrow occurs here - | | | - | | mutable borrow later used by call - | mutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:121:51 - | -LL | reg.register_static(Box::new(TrivialPass::new(®.sess_mut))); - | --- --------------- ^^^^^^^^^^^^^ immutable borrow occurs here - | | | - | | mutable borrow later used by call - | mutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:125:50 - | -LL | reg.register_bound(Box::new(TrivialPass::new(®.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^ immutable borrow occurs here - | | | - | | mutable borrow later used by call - | mutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:129:49 - | -LL | reg.register_univ(Box::new(TrivialPass::new(®.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^ immutable borrow occurs here - | | | - | | mutable borrow later used by call - | mutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:133:40 - | -LL | reg.register_ref(&TrivialPass::new(®.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^ immutable borrow occurs here - | | | - | | mutable borrow later used by call - | mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:141:51 - | -LL | reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut))); - | --- --------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:146:54 - | -LL | reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:151:53 - | -LL | reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:156:44 - | -LL | reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:168:50 - | -LL | reg.register_bound(Box::new(CapturePass::new(®.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^ immutable borrow occurs here - | | | - | | mutable borrow later used by call - | mutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:173:49 - | -LL | reg.register_univ(Box::new(CapturePass::new(®.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^ immutable borrow occurs here - | | | - | | mutable borrow later used by call - | mutable borrow occurs here - -error[E0502]: cannot borrow `reg.sess_mut` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-surprise-no-conflict.rs:178:40 - | -LL | reg.register_ref(&CapturePass::new(®.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^ immutable borrow occurs here - | | | - | | mutable borrow later used by call - | mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:190:54 - | -LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:196:53 - | -LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:202:44 - | -LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error: aborting due to 17 previous errors - -Some errors occurred: E0499, E0502, E0503. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/two-phase-surprise-no-conflict.rs b/src/test/ui/borrowck/two-phase-surprise-no-conflict.rs index f097defa2240e..3fd24bbf290b5 100644 --- a/src/test/ui/borrowck/two-phase-surprise-no-conflict.rs +++ b/src/test/ui/borrowck/two-phase-surprise-no-conflict.rs @@ -5,15 +5,6 @@ // that we decided it warranted its own unit test, and pnkfelix // decided to use that test as an opportunity to illustrate the cases. -// revisions: ast no2pb nll -//[ast]compile-flags: -Z borrowck=ast -//[no2pb]compile-flags: -Z borrowck=mir -//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows - -// (Since we are manually toggling NLL variations on and off, don't -// bother with compare-mode=nll) -// ignore-compare-mode-nll - #[derive(Copy, Clone)] struct BodyId; enum Expr { Closure(BodyId), Others } @@ -28,9 +19,7 @@ impl <'a> SpanlessHash<'a> { fn demo(&mut self) { let _mut_borrow = &mut *self; let _access = self.cx; - //[ast]~^ ERROR cannot use `self.cx` because it was mutably borrowed [E0503] - //[no2pb]~^^ ERROR cannot use `self.cx` because it was mutably borrowed [E0503] - //[nll]~^^^ ERROR cannot use `self.cx` because it was mutably borrowed [E0503] + //~^ ERROR cannot use `self.cx` because it was mutably borrowed [E0503] _mut_borrow; } @@ -52,7 +41,6 @@ impl <'a> SpanlessHash<'a> { // nothing in the activation for `self.hash_expr(..)` // can interfere with that immutable borrow. self.hash_expr(&self.cx.body(eid).value); - //[no2pb]~^ ERROR cannot borrow `*self.cx` }, _ => {} } @@ -67,9 +55,7 @@ impl <'a> SpanlessHash<'a> { // eventual activation of the `self` mutable borrow // for `self.hash_expr(..)` self.hash_expr(&self.cx_mut.body(eid).value); - //[ast]~^ ERROR cannot borrow `*self.cx_mut` - //[no2pb]~^^ ERROR cannot borrow `*self.cx_mut` - //[nll]~^^^ ERROR cannot borrow `*self` + //~^ ERROR cannot borrow `*self` }, _ => {} } @@ -119,44 +105,28 @@ fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) { // cannot (according to its type) keep them alive. let reg = mk_reg(); reg.register_static(Box::new(TrivialPass::new(®.sess_mut))); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` let reg = mk_reg(); reg.register_bound(Box::new(TrivialPass::new(®.sess_mut))); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` let reg = mk_reg(); reg.register_univ(Box::new(TrivialPass::new(®.sess_mut))); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` let reg = mk_reg(); reg.register_ref(&TrivialPass::new(®.sess_mut)); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` // These are not okay: the inner mutable borrows immediately // conflict with the outer borrow/reservation, even with support // for two-phase borrows. let reg = mk_reg(); reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut))); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` - //[nll]~^^^ ERROR cannot borrow `reg.sess_mut` + //~^ ERROR cannot borrow `reg.sess_mut` let reg = mk_reg(); reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` - //[nll]~^^^ ERROR cannot borrow `reg.sess_mut` + //~^ ERROR cannot borrow `reg.sess_mut` let reg = mk_reg(); reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` - //[nll]~^^^ ERROR cannot borrow `reg.sess_mut` + //~^ ERROR cannot borrow `reg.sess_mut` let reg = mk_reg(); reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut)); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` - //[nll]~^^^ ERROR cannot borrow `reg.sess_mut` + //~^ ERROR cannot borrow `reg.sess_mut` // These are not okay: the inner borrows may reach the actual // method invocation, because `CapturePass::new` might (according @@ -166,19 +136,13 @@ fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) { // that will fail to get past lifetime inference.) let reg = mk_reg(); reg.register_bound(Box::new(CapturePass::new(®.sess_mut))); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` - //[nll]~^^^ ERROR cannot borrow `*reg` as mutable + //~^ ERROR cannot borrow `*reg` as mutable let reg = mk_reg(); reg.register_univ(Box::new(CapturePass::new(®.sess_mut))); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` - //[nll]~^^^ ERROR cannot borrow `*reg` as mutable + //~^ ERROR cannot borrow `*reg` as mutable let reg = mk_reg(); reg.register_ref(&CapturePass::new(®.sess_mut)); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` - //[nll]~^^^ ERROR cannot borrow `*reg` as mutable + //~^ ERROR cannot borrow `*reg` as mutable // These are not okay: the inner mutable borrows immediately // conflict with the outer borrow/reservation, even with support @@ -188,22 +152,16 @@ fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) { // that will fail to get past lifetime inference.) let reg = mk_reg(); reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` - //[nll]~^^^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time - //[nll]~^^^^ ERROR cannot borrow `*reg` as mutable more than once at a time + //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time + //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time let reg = mk_reg(); reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` - //[nll]~^^^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time - //[nll]~^^^^ ERROR cannot borrow `*reg` as mutable more than once at a time + //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time + //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time let reg = mk_reg(); reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); - //[ast]~^ ERROR cannot borrow `reg.sess_mut` - //[no2pb]~^^ ERROR cannot borrow `reg.sess_mut` - //[nll]~^^^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time - //[nll]~^^^^ ERROR cannot borrow `*reg` as mutable more than once at a time + //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time + //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time } fn main() { } diff --git a/src/test/ui/borrowck/two-phase-surprise-no-conflict.stderr b/src/test/ui/borrowck/two-phase-surprise-no-conflict.stderr new file mode 100644 index 0000000000000..7d0e15667505d --- /dev/null +++ b/src/test/ui/borrowck/two-phase-surprise-no-conflict.stderr @@ -0,0 +1,154 @@ +error[E0503]: cannot use `self.cx` because it was mutably borrowed + --> $DIR/two-phase-surprise-no-conflict.rs:21:23 + | +LL | let _mut_borrow = &mut *self; + | ---------- borrow of `*self` occurs here +LL | let _access = self.cx; + | ^^^^^^^ use of borrowed `*self` +LL | +LL | _mut_borrow; + | ----------- borrow later used here + +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-surprise-no-conflict.rs:57:17 + | +LL | self.hash_expr(&self.cx_mut.body(eid).value); + | ^^^^^---------^^-----------^^^^^^^^^^^^^^^^^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:119:51 + | +LL | reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut))); + | --- --------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here + | | | + | | first borrow later used by call + | first mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:122:54 + | +LL | reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); + | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here + | | | + | | first borrow later used by call + | first mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:125:53 + | +LL | reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); + | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here + | | | + | | first borrow later used by call + | first mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:128:44 + | +LL | reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut)); + | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here + | | | + | | first borrow later used by call + | first mutable borrow occurs here + +error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-surprise-no-conflict.rs:138:5 + | +LL | reg.register_bound(Box::new(CapturePass::new(®.sess_mut))); + | ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-surprise-no-conflict.rs:141:5 + | +LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) { + | -- lifetime `'a` defined here +... +LL | reg.register_univ(Box::new(CapturePass::new(®.sess_mut))); + | ^^^^^^^^^^^^^^^^^^-----------------------------------------^ + | | | | + | | | immutable borrow occurs here + | | cast requires that `reg.sess_mut` is borrowed for `'a` + | mutable borrow occurs here + +error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-surprise-no-conflict.rs:144:5 + | +LL | reg.register_ref(&CapturePass::new(®.sess_mut)); + | ^^^^------------^^^^^^^^^^^^^^^^^^^-------------^^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0499]: cannot borrow `*reg` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:154:5 + | +LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); + | ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^^ + | | | | + | | | first mutable borrow occurs here + | | first borrow later used by call + | second mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:154:54 + | +LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); + | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here + | | | + | | first borrow later used by call + | first mutable borrow occurs here + +error[E0499]: cannot borrow `*reg` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:158:5 + | +LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) { + | -- lifetime `'a` defined here +... +LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); + | ^^^^^^^^^^^^^^^^^^-------------------------------------------------^ + | | | | + | | | first mutable borrow occurs here + | | cast requires that `reg.sess_mut` is borrowed for `'a` + | second mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:158:53 + | +LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); + | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here + | | | + | | first borrow later used by call + | first mutable borrow occurs here + +error[E0499]: cannot borrow `*reg` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:162:5 + | +LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); + | ^^^^------------^^^^^^^^^^^^^^^^^^^^^^^-----------------^^ + | | | | + | | | first mutable borrow occurs here + | | first borrow later used by call + | second mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:162:44 + | +LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); + | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here + | | | + | | first borrow later used by call + | first mutable borrow occurs here + +error: aborting due to 15 previous errors + +Some errors have detailed explanations: E0499, E0502, E0503. +For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr deleted file mode 100644 index d6125cfd72108..0000000000000 --- a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:11:9 - | -LL | let y = vec![format!("World")]; - | - captured outer variable -LL | call(|| { -LL | y.into_iter(); - | ^ cannot move out of captured variable in an `Fn` closure - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs index 4c6a05338a1ea..d54b09c5da95a 100644 --- a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs +++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs @@ -9,6 +9,6 @@ fn main() { let y = vec![format!("World")]; call(|| { y.into_iter(); - //~^ ERROR cannot move out of captured outer variable in an `Fn` closure + //~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure }); } diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr index bdfd6fb7e5539..73cea6fc361ec 100644 --- a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr +++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr @@ -1,11 +1,11 @@ -error[E0507]: cannot move out of captured outer variable in an `Fn` closure +error[E0507]: cannot move out of `y`, a captured variable in an `Fn` closure --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:11:9 | LL | let y = vec![format!("World")]; | - captured outer variable LL | call(|| { LL | y.into_iter(); - | ^ cannot move out of captured outer variable in an `Fn` closure + | ^ move occurs because `y` has type `std::vec::Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/bounds-lifetime.rs b/src/test/ui/bounds-lifetime.rs index 8abfe3e4b7623..31aa4011b9114 100644 --- a/src/test/ui/bounds-lifetime.rs +++ b/src/test/ui/bounds-lifetime.rs @@ -2,6 +2,6 @@ type A = for<'b, 'a: 'b> fn(); //~ ERROR lifetime bounds cannot be used in this type B = for<'b, 'a: 'b,> fn(); //~ ERROR lifetime bounds cannot be used in this context type C = for<'b, 'a: 'b +> fn(); //~ ERROR lifetime bounds cannot be used in this context type D = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context -type E = for Fn(); //~ ERROR only lifetime parameters can be used in this context +type E = dyn for Fn(); //~ ERROR only lifetime parameters can be used in this context fn main() {} diff --git a/src/test/ui/bounds-lifetime.stderr b/src/test/ui/bounds-lifetime.stderr index d57cb40b2a84d..a0395ed49045f 100644 --- a/src/test/ui/bounds-lifetime.stderr +++ b/src/test/ui/bounds-lifetime.stderr @@ -1,32 +1,32 @@ error: lifetime bounds cannot be used in this context --> $DIR/bounds-lifetime.rs:1:22 | -LL | type A = for<'b, 'a: 'b> fn(); //~ ERROR lifetime bounds cannot be used in this context +LL | type A = for<'b, 'a: 'b> fn(); | ^^ error: lifetime bounds cannot be used in this context --> $DIR/bounds-lifetime.rs:2:22 | -LL | type B = for<'b, 'a: 'b,> fn(); //~ ERROR lifetime bounds cannot be used in this context +LL | type B = for<'b, 'a: 'b,> fn(); | ^^ error: lifetime bounds cannot be used in this context --> $DIR/bounds-lifetime.rs:3:22 | -LL | type C = for<'b, 'a: 'b +> fn(); //~ ERROR lifetime bounds cannot be used in this context +LL | type C = for<'b, 'a: 'b +> fn(); | ^^ error: only lifetime parameters can be used in this context --> $DIR/bounds-lifetime.rs:4:18 | -LL | type D = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context +LL | type D = for<'a, T> fn(); | ^ error: only lifetime parameters can be used in this context - --> $DIR/bounds-lifetime.rs:5:14 + --> $DIR/bounds-lifetime.rs:5:18 | -LL | type E = for Fn(); //~ ERROR only lifetime parameters can be used in this context - | ^ +LL | type E = dyn for Fn(); + | ^ error: aborting due to 5 previous errors diff --git a/src/test/ui/break-outside-loop.stderr b/src/test/ui/break-outside-loop.stderr index 5e008a064772b..8f4656ab394cd 100644 --- a/src/test/ui/break-outside-loop.stderr +++ b/src/test/ui/break-outside-loop.stderr @@ -1,34 +1,34 @@ error[E0268]: `break` outside of loop --> $DIR/break-outside-loop.rs:10:15 | -LL | let pth = break; //~ ERROR: `break` outside of loop +LL | let pth = break; | ^^^^^ cannot break outside of a loop error[E0268]: `continue` outside of loop --> $DIR/break-outside-loop.rs:11:17 | -LL | if cond() { continue } //~ ERROR: `continue` outside of loop +LL | if cond() { continue } | ^^^^^^^^ cannot break outside of a loop error[E0267]: `break` inside of a closure --> $DIR/break-outside-loop.rs:17:25 | -LL | if cond() { break } //~ ERROR: `break` inside of a closure +LL | if cond() { break } | ^^^^^ cannot break inside of a closure error[E0267]: `continue` inside of a closure --> $DIR/break-outside-loop.rs:18:25 | -LL | if cond() { continue } //~ ERROR: `continue` inside of a closure +LL | if cond() { continue } | ^^^^^^^^ cannot break inside of a closure error[E0268]: `break` outside of loop --> $DIR/break-outside-loop.rs:24:25 | -LL | let unconstrained = break; //~ ERROR: `break` outside of loop +LL | let unconstrained = break; | ^^^^^ cannot break outside of a loop error: aborting due to 5 previous errors -Some errors occurred: E0267, E0268. +Some errors have detailed explanations: E0267, E0268. For more information about an error, try `rustc --explain E0267`. diff --git a/src/test/ui/break-while-condition.stderr b/src/test/ui/break-while-condition.stderr index 3e81753a4105f..a08edee07ea0a 100644 --- a/src/test/ui/break-while-condition.stderr +++ b/src/test/ui/break-while-condition.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/break-while-condition.rs:9:20 | -LL | let _: ! = { //~ ERROR mismatched types +LL | let _: ! = { | ____________________^ LL | | 'a: while break 'a {}; LL | | }; @@ -13,7 +13,7 @@ LL | | }; error[E0308]: mismatched types --> $DIR/break-while-condition.rs:16:13 | -LL | / while false { //~ ERROR mismatched types +LL | / while false { LL | | break LL | | } | |_____________^ expected !, found () @@ -24,7 +24,7 @@ LL | | } error[E0308]: mismatched types --> $DIR/break-while-condition.rs:24:13 | -LL | / while false { //~ ERROR mismatched types +LL | / while false { LL | | return LL | | } | |_____________^ expected !, found () diff --git a/src/test/ui/by-move-pattern-binding.nll.stderr b/src/test/ui/by-move-pattern-binding.nll.stderr deleted file mode 100644 index 4b4a989368a78..0000000000000 --- a/src/test/ui/by-move-pattern-binding.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/by-move-pattern-binding.rs:14:11 - | -LL | match &s.x { - | ^^^^ cannot move out of borrowed content -LL | &E::Foo => {} -LL | &E::Bar(identifier) => f(identifier.clone()) //~ ERROR cannot move - | ------------------- - | | | - | | data moved here - | help: consider removing the `&`: `E::Bar(identifier)` - | -note: move occurs because `identifier` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/by-move-pattern-binding.rs:16:17 - | -LL | &E::Bar(identifier) => f(identifier.clone()) //~ ERROR cannot move - | ^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/by-move-pattern-binding.rs b/src/test/ui/by-move-pattern-binding.rs index 455b206e53f1a..d4c9f23164f8b 100644 --- a/src/test/ui/by-move-pattern-binding.rs +++ b/src/test/ui/by-move-pattern-binding.rs @@ -11,9 +11,9 @@ fn f(x: String) {} fn main() { let s = S { x: E::Bar("hello".to_string()) }; - match &s.x { + match &s.x { //~ ERROR cannot move &E::Foo => {} - &E::Bar(identifier) => f(identifier.clone()) //~ ERROR cannot move + &E::Bar(identifier) => f(identifier.clone()) }; match &s.x { &E::Foo => {} diff --git a/src/test/ui/by-move-pattern-binding.stderr b/src/test/ui/by-move-pattern-binding.stderr index d3c5e2caa4294..1db4e2a66dbde 100644 --- a/src/test/ui/by-move-pattern-binding.stderr +++ b/src/test/ui/by-move-pattern-binding.stderr @@ -1,11 +1,15 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/by-move-pattern-binding.rs:16:9 +error[E0507]: cannot move out of a shared reference + --> $DIR/by-move-pattern-binding.rs:14:11 | -LL | &E::Bar(identifier) => f(identifier.clone()) //~ ERROR cannot move - | ^^^^^^^^----------^ +LL | match &s.x { + | ^^^^ +LL | &E::Foo => {} +LL | &E::Bar(identifier) => f(identifier.clone()) + | ------------------- | | | - | | hint: to prevent move, use `ref identifier` or `ref mut identifier` - | cannot move out of borrowed content + | | data moved here + | | move occurs because `identifier` has type `std::string::String`, which does not implement the `Copy` trait + | help: consider removing the `&`: `E::Bar(identifier)` error: aborting due to previous error diff --git a/src/test/ui/c-variadic/variadic-ffi-1.rs b/src/test/ui/c-variadic/variadic-ffi-1.rs index 61b2ad4bed576..6a3ff24b6740f 100644 --- a/src/test/ui/c-variadic/variadic-ffi-1.rs +++ b/src/test/ui/c-variadic/variadic-ffi-1.rs @@ -12,20 +12,18 @@ extern { extern "C" fn bar(f: isize, x: u8) {} fn main() { - // errors below are no longer checked because error above aborts - // compilation; see variadic-ffi-3.rs for corresponding test. unsafe { - foo(); - foo(1); + foo(); //~ ERROR this function takes at least 2 parameters but 0 parameters were supplied + foo(1); //~ ERROR this function takes at least 2 parameters but 1 parameter was supplied - let x: unsafe extern "C" fn(f: isize, x: u8) = foo; - let y: extern "C" fn(f: isize, x: u8, ...) = bar; + let x: unsafe extern "C" fn(f: isize, x: u8) = foo; //~ ERROR mismatched types + let y: extern "C" fn(f: isize, x: u8, ...) = bar; //~ ERROR mismatched types - foo(1, 2, 3f32); - foo(1, 2, true); - foo(1, 2, 1i8); - foo(1, 2, 1u8); - foo(1, 2, 1i16); - foo(1, 2, 1u16); + foo(1, 2, 3f32); //~ ERROR can't pass + foo(1, 2, true); //~ ERROR can't pass + foo(1, 2, 1i8); //~ ERROR can't pass + foo(1, 2, 1u8); //~ ERROR can't pass + foo(1, 2, 1i16); //~ ERROR can't pass + foo(1, 2, 1u16); //~ ERROR can't pass } } diff --git a/src/test/ui/c-variadic/variadic-ffi-1.stderr b/src/test/ui/c-variadic/variadic-ffi-1.stderr index 61d55ce0d3ef9..695eba2a7ee40 100644 --- a/src/test/ui/c-variadic/variadic-ffi-1.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-1.stderr @@ -1,9 +1,82 @@ error[E0045]: C-variadic function must have C or cdecl calling convention --> $DIR/variadic-ffi-1.rs:5:5 | -LL | fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C or cdecl calling +LL | fn printf(_: *const u8, ...); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadics require C or cdecl calling convention -error: aborting due to previous error +error[E0060]: this function takes at least 2 parameters but 0 parameters were supplied + --> $DIR/variadic-ffi-1.rs:16:9 + | +LL | fn foo(f: isize, x: u8, ...); + | ----------------------------- defined here +... +LL | foo(); + | ^^^^^ expected at least 2 parameters + +error[E0060]: this function takes at least 2 parameters but 1 parameter was supplied + --> $DIR/variadic-ffi-1.rs:17:9 + | +LL | fn foo(f: isize, x: u8, ...); + | ----------------------------- defined here +... +LL | foo(1); + | ^^^^^^ expected at least 2 parameters + +error[E0308]: mismatched types + --> $DIR/variadic-ffi-1.rs:19:56 + | +LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo; + | ^^^ expected non-variadic fn, found variadic function + | + = note: expected type `unsafe extern "C" fn(isize, u8)` + found type `for<'r> unsafe extern "C" fn(isize, u8, std::ffi::VaListImpl<'r>, ...) {foo}` + +error[E0308]: mismatched types + --> $DIR/variadic-ffi-1.rs:20:54 + | +LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar; + | ^^^ expected variadic fn, found non-variadic function + | + = note: expected type `for<'r> extern "C" fn(isize, u8, std::ffi::VaListImpl<'r>, ...)` + found type `extern "C" fn(isize, u8) {bar}` + +error[E0617]: can't pass `f32` to variadic function + --> $DIR/variadic-ffi-1.rs:22:19 + | +LL | foo(1, 2, 3f32); + | ^^^^ help: cast the value to `c_double`: `3f32 as c_double` + +error[E0617]: can't pass `bool` to variadic function + --> $DIR/variadic-ffi-1.rs:23:19 + | +LL | foo(1, 2, true); + | ^^^^ help: cast the value to `c_int`: `true as c_int` + +error[E0617]: can't pass `i8` to variadic function + --> $DIR/variadic-ffi-1.rs:24:19 + | +LL | foo(1, 2, 1i8); + | ^^^ help: cast the value to `c_int`: `1i8 as c_int` + +error[E0617]: can't pass `u8` to variadic function + --> $DIR/variadic-ffi-1.rs:25:19 + | +LL | foo(1, 2, 1u8); + | ^^^ help: cast the value to `c_uint`: `1u8 as c_uint` + +error[E0617]: can't pass `i16` to variadic function + --> $DIR/variadic-ffi-1.rs:26:19 + | +LL | foo(1, 2, 1i16); + | ^^^^ help: cast the value to `c_int`: `1i16 as c_int` + +error[E0617]: can't pass `u16` to variadic function + --> $DIR/variadic-ffi-1.rs:27:19 + | +LL | foo(1, 2, 1u16); + | ^^^^ help: cast the value to `c_uint`: `1u16 as c_uint` + +error: aborting due to 11 previous errors -For more information about this error, try `rustc --explain E0045`. +Some errors have detailed explanations: E0045, E0060, E0308, E0617. +For more information about an error, try `rustc --explain E0045`. diff --git a/src/test/ui/c-variadic/variadic-ffi-3.rs b/src/test/ui/c-variadic/variadic-ffi-3.rs deleted file mode 100644 index c02d1f54e5649..0000000000000 --- a/src/test/ui/c-variadic/variadic-ffi-3.rs +++ /dev/null @@ -1,29 +0,0 @@ -extern { - fn foo(f: isize, x: u8, ...); - //~^ defined here - //~| defined here -} - -extern "C" fn bar(f: isize, x: u8) {} - -fn main() { - unsafe { - foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied - foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied - - let x: unsafe extern "C" fn(f: isize, x: u8) = foo; - //~^ ERROR: mismatched types - //~| expected type `unsafe extern "C" fn(isize, u8)` - - let y: extern "C" fn(f: isize, x: u8, ...) = bar; - //~^ ERROR: mismatched types - //~| expected type `for<'r> extern "C" fn(isize, u8, std::ffi::VaList<'r>, ...)` - - foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function - foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function - foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function - foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function - foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function - foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function - } -} diff --git a/src/test/ui/c-variadic/variadic-ffi-3.stderr b/src/test/ui/c-variadic/variadic-ffi-3.stderr deleted file mode 100644 index 82e3c6cd06fc5..0000000000000 --- a/src/test/ui/c-variadic/variadic-ffi-3.stderr +++ /dev/null @@ -1,76 +0,0 @@ -error[E0060]: this function takes at least 2 parameters but 0 parameters were supplied - --> $DIR/variadic-ffi-3.rs:11:9 - | -LL | fn foo(f: isize, x: u8, ...); - | ----------------------------- defined here -... -LL | foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied - | ^^^^^ expected at least 2 parameters - -error[E0060]: this function takes at least 2 parameters but 1 parameter was supplied - --> $DIR/variadic-ffi-3.rs:12:9 - | -LL | fn foo(f: isize, x: u8, ...); - | ----------------------------- defined here -... -LL | foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied - | ^^^^^^ expected at least 2 parameters - -error[E0308]: mismatched types - --> $DIR/variadic-ffi-3.rs:14:56 - | -LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo; - | ^^^ expected non-variadic fn, found variadic function - | - = note: expected type `unsafe extern "C" fn(isize, u8)` - found type `for<'r> unsafe extern "C" fn(isize, u8, std::ffi::VaList<'r>, ...) {foo}` - -error[E0308]: mismatched types - --> $DIR/variadic-ffi-3.rs:18:54 - | -LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar; - | ^^^ expected variadic fn, found non-variadic function - | - = note: expected type `for<'r> extern "C" fn(isize, u8, std::ffi::VaList<'r>, ...)` - found type `extern "C" fn(isize, u8) {bar}` - -error[E0617]: can't pass `f32` to variadic function - --> $DIR/variadic-ffi-3.rs:22:19 - | -LL | foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function - | ^^^^ help: cast the value to `c_double`: `3f32 as c_double` - -error[E0617]: can't pass `bool` to variadic function - --> $DIR/variadic-ffi-3.rs:23:19 - | -LL | foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function - | ^^^^ help: cast the value to `c_int`: `true as c_int` - -error[E0617]: can't pass `i8` to variadic function - --> $DIR/variadic-ffi-3.rs:24:19 - | -LL | foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function - | ^^^ help: cast the value to `c_int`: `1i8 as c_int` - -error[E0617]: can't pass `u8` to variadic function - --> $DIR/variadic-ffi-3.rs:25:19 - | -LL | foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function - | ^^^ help: cast the value to `c_uint`: `1u8 as c_uint` - -error[E0617]: can't pass `i16` to variadic function - --> $DIR/variadic-ffi-3.rs:26:19 - | -LL | foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function - | ^^^^ help: cast the value to `c_int`: `1i16 as c_int` - -error[E0617]: can't pass `u16` to variadic function - --> $DIR/variadic-ffi-3.rs:27:19 - | -LL | foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function - | ^^^^ help: cast the value to `c_uint`: `1u16 as c_uint` - -error: aborting due to 10 previous errors - -Some errors occurred: E0060, E0308, E0617. -For more information about an error, try `rustc --explain E0060`. diff --git a/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr new file mode 100644 index 0000000000000..3c5131835b572 --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr @@ -0,0 +1,91 @@ +error[E0621]: explicit lifetime required in the type of `ap` + --> $DIR/variadic-ffi-4.rs:8:5 + | +LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { + | --- help: add explicit lifetime `'f` to the type of `ap`: `core::ffi::VaListImpl<'f>` +LL | ap + | ^^ lifetime `'f` required + +error[E0621]: explicit lifetime required in the type of `ap` + --> $DIR/variadic-ffi-4.rs:12:5 + | +LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { + | --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaListImpl<'static>` +LL | ap + | ^^ lifetime `'static` required + +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:16:33 + | +LL | let _ = ap.with_copy(|ap| { ap }); + | --- ^^ returning this value requires that `'1` must outlive `'2` + | | | + | | return type of closure is core::ffi::VaList<'2, '_> + | has type `core::ffi::VaList<'1, '_>` + +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:20:5 + | +LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + | ------- ------- has type `core::ffi::VaListImpl<'1>` + | | + | has type `&mut core::ffi::VaListImpl<'2>` +LL | *ap0 = ap1; + | ^^^^ assignment requires that `'1` must outlive `'2` + +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:24:5 + | +LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { + | --- ------- has type `core::ffi::VaListImpl<'2>` + | | + | has type `&mut core::ffi::VaListImpl<'1>` +LL | ap0 = &mut ap1; + | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` + +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:24:5 + | +LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { + | --- ------- has type `core::ffi::VaListImpl<'1>` + | | + | has type `&mut core::ffi::VaListImpl<'2>` +LL | ap0 = &mut ap1; + | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` + +error[E0384]: cannot assign to immutable argument `ap0` + --> $DIR/variadic-ffi-4.rs:24:5 + | +LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { + | --- help: make this binding mutable: `mut ap0` +LL | ap0 = &mut ap1; + | ^^^^^^^^^^^^^^ cannot assign to immutable argument + +error[E0597]: `ap1` does not live long enough + --> $DIR/variadic-ffi-4.rs:24:11 + | +LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { + | - let's call the lifetime of this reference `'1` +LL | ap0 = &mut ap1; + | ------^^^^^^^^ + | | | + | | borrowed value does not live long enough + | assignment requires that `ap1` is borrowed for `'1` +... +LL | } + | - `ap1` dropped here while still borrowed + +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:32:5 + | +LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + | ------- ------- has type `core::ffi::VaListImpl<'1>` + | | + | has type `&mut core::ffi::VaListImpl<'2>` +LL | *ap0 = ap1.clone(); + | ^^^^ assignment requires that `'1` must outlive `'2` + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0384, E0597, E0621. +For more information about an error, try `rustc --explain E0384`. diff --git a/src/test/ui/c-variadic/variadic-ffi-4.rs b/src/test/ui/c-variadic/variadic-ffi-4.rs index 9101be5645646..07c32ecbfc2dc 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.rs +++ b/src/test/ui/c-variadic/variadic-ffi-4.rs @@ -2,28 +2,32 @@ #![no_std] #![feature(c_variadic)] -use core::ffi::VaList; +use core::ffi::{VaList, VaListImpl}; -pub unsafe extern "C" fn no_escape0<'a>(_: usize, ap: ...) -> VaList<'a> { +pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { ap //~ ERROR: explicit lifetime required } -pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { +pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { ap //~ ERROR: explicit lifetime required } pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) { - let _ = ap.copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime + let _ = ap.with_copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime } -pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { +pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { *ap0 = ap1; //~ ERROR: mismatched types } -pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { ap0 = &mut ap1; - //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long + //~^ ERROR: a value of type `core::ffi::VaListImpl<'_>` is borrowed for too long //~^^ ERROR: mismatched types //~^^^ ERROR: mismatched types //~^^^^ ERROR: cannot infer an appropriate lifetime } + +pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + *ap0 = ap1.clone(); //~ ERROR: cannot infer an appropriate lifetime +} diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr index 1d752be065c4a..72d4d8b63445a 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr @@ -1,68 +1,68 @@ error[E0621]: explicit lifetime required in the type of `ap` --> $DIR/variadic-ffi-4.rs:8:5 | -LL | pub unsafe extern "C" fn no_escape0<'a>(_: usize, ap: ...) -> VaList<'a> { - | --- help: add explicit lifetime `'a` to the type of `ap`: `core::ffi::VaList<'a>` -LL | ap //~ ERROR: explicit lifetime required - | ^^ lifetime `'a` required +LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { + | --- help: add explicit lifetime `'f` to the type of `ap`: `core::ffi::VaListImpl<'f>` +LL | ap + | ^^ lifetime `'f` required error[E0621]: explicit lifetime required in the type of `ap` --> $DIR/variadic-ffi-4.rs:12:5 | -LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { - | --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaList<'static>` -LL | ap //~ ERROR: explicit lifetime required +LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { + | --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaListImpl<'static>` +LL | ap | ^^ lifetime `'static` required error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/variadic-ffi-4.rs:16:28 + --> $DIR/variadic-ffi-4.rs:16:33 | -LL | let _ = ap.copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime - | ^^ +LL | let _ = ap.with_copy(|ap| { ap }); + | ^^ | -note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 16:21... - --> $DIR/variadic-ffi-4.rs:16:21 +note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 16:26... + --> $DIR/variadic-ffi-4.rs:16:26 | -LL | let _ = ap.copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime - | ^^^^^^^^^^^ +LL | let _ = ap.with_copy(|ap| { ap }); + | ^^^^^^^^^^^ = note: ...so that the expression is assignable: - expected core::ffi::VaList<'_> - found core::ffi::VaList<'_> + expected core::ffi::VaList<'_, '_> + found core::ffi::VaList<'_, '_> note: but, the lifetime must be valid for the method call at 16:13... --> $DIR/variadic-ffi-4.rs:16:13 | -LL | let _ = ap.copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime - | ^^^^^^^^^^^^^^^^^^^^ -note: ...so type `core::ffi::VaList<'_>` of expression is valid during the expression +LL | let _ = ap.with_copy(|ap| { ap }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...so type `core::ffi::VaList<'_, '_>` of expression is valid during the expression --> $DIR/variadic-ffi-4.rs:16:13 | -LL | let _ = ap.copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime - | ^^^^^^^^^^^^^^^^^^^^ +LL | let _ = ap.with_copy(|ap| { ap }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/variadic-ffi-4.rs:20:12 | -LL | *ap0 = ap1; //~ ERROR: mismatched types +LL | *ap0 = ap1; | ^^^ lifetime mismatch | - = note: expected type `core::ffi::VaList<'_>` - found type `core::ffi::VaList<'_>` + = note: expected type `core::ffi::VaListImpl<'_>` + found type `core::ffi::VaListImpl<'_>` note: the anonymous lifetime #3 defined on the function body at 19:1... --> $DIR/variadic-ffi-4.rs:19:1 | -LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { -LL | | *ap0 = ap1; //~ ERROR: mismatched types +LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { +LL | | *ap0 = ap1; LL | | } | |_^ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 19:1 --> $DIR/variadic-ffi-4.rs:19:1 | -LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { -LL | | *ap0 = ap1; //~ ERROR: mismatched types +LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { +LL | | *ap0 = ap1; LL | | } | |_^ -error[E0490]: a value of type `core::ffi::VaList<'_>` is borrowed for too long +error[E0490]: a value of type `core::ffi::VaListImpl<'_>` is borrowed for too long --> $DIR/variadic-ffi-4.rs:24:11 | LL | ap0 = &mut ap1; @@ -71,23 +71,23 @@ LL | ap0 = &mut ap1; note: the type is valid for the anonymous lifetime #1 defined on the function body at 23:1 --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; -LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long -LL | | //~^^ ERROR: mismatched types -LL | | //~^^^ ERROR: mismatched types -LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | +LL | | +LL | | +LL | | LL | | } | |_^ note: but the borrow lasts for the anonymous lifetime #3 defined on the function body at 23:1 --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; -LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long -LL | | //~^^ ERROR: mismatched types -LL | | //~^^^ ERROR: mismatched types -LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | +LL | | +LL | | +LL | | LL | | } | |_^ @@ -97,28 +97,28 @@ error[E0308]: mismatched types LL | ap0 = &mut ap1; | ^^^^^^^^ lifetime mismatch | - = note: expected type `&mut core::ffi::VaList<'_>` - found type `&mut core::ffi::VaList<'_>` + = note: expected type `&mut core::ffi::VaListImpl<'_>` + found type `&mut core::ffi::VaListImpl<'_>` note: the anonymous lifetime #3 defined on the function body at 23:1... --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; -LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long -LL | | //~^^ ERROR: mismatched types -LL | | //~^^^ ERROR: mismatched types -LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | +LL | | +LL | | +LL | | LL | | } | |_^ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 23:1 --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; -LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long -LL | | //~^^ ERROR: mismatched types -LL | | //~^^^ ERROR: mismatched types -LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | +LL | | +LL | | +LL | | LL | | } | |_^ @@ -128,28 +128,28 @@ error[E0308]: mismatched types LL | ap0 = &mut ap1; | ^^^^^^^^ lifetime mismatch | - = note: expected type `&mut core::ffi::VaList<'_>` - found type `&mut core::ffi::VaList<'_>` + = note: expected type `&mut core::ffi::VaListImpl<'_>` + found type `&mut core::ffi::VaListImpl<'_>` note: the anonymous lifetime #2 defined on the function body at 23:1... --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; -LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long -LL | | //~^^ ERROR: mismatched types -LL | | //~^^^ ERROR: mismatched types -LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | +LL | | +LL | | +LL | | LL | | } | |_^ note: ...does not necessarily outlive the anonymous lifetime #3 defined on the function body at 23:1 --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; -LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long -LL | | //~^^ ERROR: mismatched types -LL | | //~^^^ ERROR: mismatched types -LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | +LL | | +LL | | +LL | | LL | | } | |_^ @@ -162,15 +162,15 @@ LL | ap0 = &mut ap1; note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the function body at 23:1... --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; -LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long -LL | | //~^^ ERROR: mismatched types -LL | | //~^^^ ERROR: mismatched types -LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | +LL | | +LL | | +LL | | LL | | } | |_^ -note: ...so that the type `core::ffi::VaList<'_>` is not borrowed for too long +note: ...so that the type `core::ffi::VaListImpl<'_>` is not borrowed for too long --> $DIR/variadic-ffi-4.rs:24:11 | LL | ap0 = &mut ap1; @@ -178,12 +178,12 @@ LL | ap0 = &mut ap1; note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the function body at 23:1... --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; -LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long -LL | | //~^^ ERROR: mismatched types -LL | | //~^^^ ERROR: mismatched types -LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | +LL | | +LL | | +LL | | LL | | } | |_^ note: ...so that reference does not outlive borrowed content @@ -192,7 +192,34 @@ note: ...so that reference does not outlive borrowed content LL | ap0 = &mut ap1; | ^^^^^^^^ -error: aborting due to 8 previous errors +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements + --> $DIR/variadic-ffi-4.rs:32:16 + | +LL | *ap0 = ap1.clone(); + | ^^^^^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the function body at 31:1... + --> $DIR/variadic-ffi-4.rs:31:1 + | +LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { +LL | | *ap0 = ap1.clone(); +LL | | } + | |_^ + = note: ...so that the types are compatible: + expected &core::ffi::VaListImpl<'_> + found &core::ffi::VaListImpl<'_> +note: but, the lifetime must be valid for the anonymous lifetime #2 defined on the function body at 31:1... + --> $DIR/variadic-ffi-4.rs:31:1 + | +LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { +LL | | *ap0 = ap1.clone(); +LL | | } + | |_^ + = note: ...so that the expression is assignable: + expected core::ffi::VaListImpl<'_> + found core::ffi::VaListImpl<'_> + +error: aborting due to 9 previous errors -Some errors occurred: E0308, E0490, E0495, E0621. +Some errors have detailed explanations: E0308, E0621. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/c-variadic/variadic-ffi-5.rs b/src/test/ui/c-variadic/variadic-ffi-5.rs deleted file mode 100644 index d96482ff4d17a..0000000000000 --- a/src/test/ui/c-variadic/variadic-ffi-5.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![crate_type="lib"] -#![no_std] -#![feature(c_variadic)] -// The tests in this file are similar to that of variadic-ffi-4, but this -// one enables nll. -#![feature(nll)] - -use core::ffi::VaList; - -pub unsafe extern "C" fn no_escape0<'a>(_: usize, ap: ...) -> VaList<'a> { - ap //~ ERROR: explicit lifetime required -} - -pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { - ap //~ ERROR: explicit lifetime required -} - -pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) { - let _ = ap.copy(|ap| { ap }); //~ ERROR: lifetime may not live long enough -} - -pub unsafe extern "C" fn no_escape3(_: usize, ap0: &mut VaList, mut ap1: ...) { - *ap0 = ap1; //~ ERROR: lifetime may not live long enough -} - -pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { - ap0 = &mut ap1; - //~^ ERROR: lifetime may not live long enough - //~^^ ERROR: lifetime may not live long enough - //~^^^ ERROR: `ap1` does not live long enough -} diff --git a/src/test/ui/c-variadic/variadic-ffi-5.stderr b/src/test/ui/c-variadic/variadic-ffi-5.stderr deleted file mode 100644 index 2d452872baf4e..0000000000000 --- a/src/test/ui/c-variadic/variadic-ffi-5.stderr +++ /dev/null @@ -1,73 +0,0 @@ -error[E0621]: explicit lifetime required in the type of `ap` - --> $DIR/variadic-ffi-5.rs:11:5 - | -LL | pub unsafe extern "C" fn no_escape0<'a>(_: usize, ap: ...) -> VaList<'a> { - | --- help: add explicit lifetime `'a` to the type of `ap`: `core::ffi::VaList<'a>` -LL | ap //~ ERROR: explicit lifetime required - | ^^ lifetime `'a` required - -error[E0621]: explicit lifetime required in the type of `ap` - --> $DIR/variadic-ffi-5.rs:15:5 - | -LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { - | --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaList<'static>` -LL | ap //~ ERROR: explicit lifetime required - | ^^ lifetime `'static` required - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-5.rs:19:28 - | -LL | let _ = ap.copy(|ap| { ap }); //~ ERROR: lifetime may not live long enough - | --- ^^ returning this value requires that `'1` must outlive `'2` - | | | - | | return type of closure is core::ffi::VaList<'2> - | has type `core::ffi::VaList<'1>` - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-5.rs:23:5 - | -LL | pub unsafe extern "C" fn no_escape3(_: usize, ap0: &mut VaList, mut ap1: ...) { - | --- ------- has type `core::ffi::VaList<'1>` - | | - | has type `&mut core::ffi::VaList<'2>` -LL | *ap0 = ap1; //~ ERROR: lifetime may not live long enough - | ^^^^^^^^^^ assignment requires that `'1` must outlive `'2` - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-5.rs:27:5 - | -LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaList<'2>` - | | - | has type `&mut core::ffi::VaList<'1>` -LL | ap0 = &mut ap1; - | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-5.rs:27:5 - | -LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaList<'1>` - | | - | has type `&mut core::ffi::VaList<'2>` -LL | ap0 = &mut ap1; - | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` - -error[E0597]: `ap1` does not live long enough - --> $DIR/variadic-ffi-5.rs:27:11 - | -LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { - | - let's call the lifetime of this reference `'1` -LL | ap0 = &mut ap1; - | ------^^^^^^^^ - | | | - | | borrowed value does not live long enough - | assignment requires that `ap1` is borrowed for `'1` -... -LL | } - | - `ap1` dropped here while still borrowed - -error: aborting due to 7 previous errors - -Some errors occurred: E0597, E0621. -For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/c-variadic/variadic-ffi-6.stderr b/src/test/ui/c-variadic/variadic-ffi-6.stderr index 76bd18959a51f..882e7f89f2a0d 100644 --- a/src/test/ui/c-variadic/variadic-ffi-6.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-6.stderr @@ -1,7 +1,7 @@ error[E0106]: missing lifetime specifier --> $DIR/variadic-ffi-6.rs:7:6 | -LL | ) -> &usize { //~ ERROR missing lifetime specifier +LL | ) -> &usize { | ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static` | = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments diff --git a/src/test/ui/call-fn-never-arg-wrong-type.rs b/src/test/ui/call-fn-never-arg-wrong-type.rs index 7ed1162171f1c..d06637e74a2f2 100644 --- a/src/test/ui/call-fn-never-arg-wrong-type.rs +++ b/src/test/ui/call-fn-never-arg-wrong-type.rs @@ -9,4 +9,3 @@ fn foo(x: !) -> ! { fn main() { foo("wow"); //~ ERROR mismatched types } - diff --git a/src/test/ui/call-fn-never-arg-wrong-type.stderr b/src/test/ui/call-fn-never-arg-wrong-type.stderr index 602963ee89cd5..7a50fd367d2d5 100644 --- a/src/test/ui/call-fn-never-arg-wrong-type.stderr +++ b/src/test/ui/call-fn-never-arg-wrong-type.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/call-fn-never-arg-wrong-type.rs:10:9 | -LL | foo("wow"); //~ ERROR mismatched types +LL | foo("wow"); | ^^^^^ expected !, found reference | = note: expected type `!` diff --git a/src/test/ui/can-begin-expr-check.stderr b/src/test/ui/can-begin-expr-check.stderr index f25b348816b6a..676c2cb661e7b 100644 --- a/src/test/ui/can-begin-expr-check.stderr +++ b/src/test/ui/can-begin-expr-check.stderr @@ -1,7 +1,7 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `enum` --> $DIR/can-begin-expr-check.rs:19:12 | -LL | return enum; //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `enum` +LL | return enum; | ^^^^ expected one of `.`, `;`, `?`, `}`, or an operator here error: aborting due to previous error diff --git a/src/test/ui/cannot-mutate-captured-non-mut-var.ast.nll.stderr b/src/test/ui/cannot-mutate-captured-non-mut-var.ast.nll.stderr deleted file mode 100644 index 581dcde59f5e9..0000000000000 --- a/src/test/ui/cannot-mutate-captured-non-mut-var.ast.nll.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/cannot-mutate-captured-non-mut-var.rs:13:25 - | -LL | let x = 1; - | - help: consider changing this to be mutable: `mut x` -LL | to_fn_once(move|| { x = 2; }); - | ^^^^^ cannot assign - -error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable - --> $DIR/cannot-mutate-captured-non-mut-var.rs:18:25 - | -LL | let s = std::io::stdin(); - | - help: consider changing this to be mutable: `mut s` -LL | to_fn_once(move|| { s.read_to_end(&mut Vec::new()); }); - | ^ cannot borrow as mutable - -error: aborting due to 2 previous errors - -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/cannot-mutate-captured-non-mut-var.ast.stderr b/src/test/ui/cannot-mutate-captured-non-mut-var.ast.stderr deleted file mode 100644 index 1098c16aaf63f..0000000000000 --- a/src/test/ui/cannot-mutate-captured-non-mut-var.ast.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0594]: cannot assign to immutable captured outer variable in an `FnOnce` closure `x` - --> $DIR/cannot-mutate-captured-non-mut-var.rs:13:25 - | -LL | to_fn_once(move|| { x = 2; }); - | ^^^^^ - -error[E0596]: cannot borrow immutable captured outer variable in an `FnOnce` closure `s` as mutable - --> $DIR/cannot-mutate-captured-non-mut-var.rs:18:25 - | -LL | to_fn_once(move|| { s.read_to_end(&mut Vec::new()); }); - | ^ - -error: aborting due to 2 previous errors - -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/cannot-mutate-captured-non-mut-var.mir.stderr b/src/test/ui/cannot-mutate-captured-non-mut-var.mir.stderr deleted file mode 100644 index 581dcde59f5e9..0000000000000 --- a/src/test/ui/cannot-mutate-captured-non-mut-var.mir.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/cannot-mutate-captured-non-mut-var.rs:13:25 - | -LL | let x = 1; - | - help: consider changing this to be mutable: `mut x` -LL | to_fn_once(move|| { x = 2; }); - | ^^^^^ cannot assign - -error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable - --> $DIR/cannot-mutate-captured-non-mut-var.rs:18:25 - | -LL | let s = std::io::stdin(); - | - help: consider changing this to be mutable: `mut s` -LL | to_fn_once(move|| { s.read_to_end(&mut Vec::new()); }); - | ^ cannot borrow as mutable - -error: aborting due to 2 previous errors - -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/cannot-mutate-captured-non-mut-var.rs b/src/test/ui/cannot-mutate-captured-non-mut-var.rs index 18257d09fa090..a83884acb1d29 100644 --- a/src/test/ui/cannot-mutate-captured-non-mut-var.rs +++ b/src/test/ui/cannot-mutate-captured-non-mut-var.rs @@ -1,7 +1,3 @@ -// ignore-tidy-linelength -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - #![feature(unboxed_closures)] use std::io::Read; @@ -11,11 +7,9 @@ fn to_fn_once>(f: F) -> F { f } fn main() { let x = 1; to_fn_once(move|| { x = 2; }); - //[ast]~^ ERROR: cannot assign to immutable captured outer variable - //[mir]~^^ ERROR: cannot assign to `x`, as it is not declared as mutable + //~^ ERROR: cannot assign to `x`, as it is not declared as mutable let s = std::io::stdin(); to_fn_once(move|| { s.read_to_end(&mut Vec::new()); }); - //[ast]~^ ERROR: cannot borrow immutable captured outer variable - //[mir]~^^ ERROR: cannot borrow `s` as mutable, as it is not declared as mutable + //~^ ERROR: cannot borrow `s` as mutable, as it is not declared as mutable } diff --git a/src/test/ui/cannot-mutate-captured-non-mut-var.stderr b/src/test/ui/cannot-mutate-captured-non-mut-var.stderr new file mode 100644 index 0000000000000..2961497ef9f5c --- /dev/null +++ b/src/test/ui/cannot-mutate-captured-non-mut-var.stderr @@ -0,0 +1,19 @@ +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/cannot-mutate-captured-non-mut-var.rs:9:25 + | +LL | let x = 1; + | - help: consider changing this to be mutable: `mut x` +LL | to_fn_once(move|| { x = 2; }); + | ^^^^^ cannot assign + +error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable + --> $DIR/cannot-mutate-captured-non-mut-var.rs:13:25 + | +LL | let s = std::io::stdin(); + | - help: consider changing this to be mutable: `mut s` +LL | to_fn_once(move|| { s.read_to_end(&mut Vec::new()); }); + | ^ cannot borrow as mutable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/cast-char.rs b/src/test/ui/cast-char.rs new file mode 100644 index 0000000000000..9634ed56f7b72 --- /dev/null +++ b/src/test/ui/cast-char.rs @@ -0,0 +1,10 @@ +#![deny(overflowing_literals)] + +fn main() { + const XYZ: char = 0x1F888 as char; + //~^ ERROR only `u8` can be cast into `char` + const XY: char = 129160 as char; + //~^ ERROR only `u8` can be cast into `char` + const ZYX: char = '\u{01F888}'; + println!("{}", XYZ); +} diff --git a/src/test/ui/cast-char.stderr b/src/test/ui/cast-char.stderr new file mode 100644 index 0000000000000..1729e5cbf0931 --- /dev/null +++ b/src/test/ui/cast-char.stderr @@ -0,0 +1,20 @@ +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:4:23 + | +LL | const XYZ: char = 0x1F888 as char; + | ^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'` + | +note: lint level defined here + --> $DIR/cast-char.rs:1:9 + | +LL | #![deny(overflowing_literals)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:6:22 + | +LL | const XY: char = 129160 as char; + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/cast/cast-as-bool.stderr b/src/test/ui/cast/cast-as-bool.stderr index 6099a4195b329..30f8459c2e1e1 100644 --- a/src/test/ui/cast/cast-as-bool.stderr +++ b/src/test/ui/cast/cast-as-bool.stderr @@ -1,19 +1,19 @@ error[E0054]: cannot cast as `bool` --> $DIR/cast-as-bool.rs:2:13 | -LL | let u = 5 as bool; //~ ERROR cannot cast as `bool` +LL | let u = 5 as bool; | ^^^^^^^^^ help: compare with zero instead: `5 != 0` error[E0054]: cannot cast as `bool` --> $DIR/cast-as-bool.rs:5:13 | -LL | let t = (1 + 2) as bool; //~ ERROR cannot cast as `bool` +LL | let t = (1 + 2) as bool; | ^^^^^^^^^^^^^^^ help: compare with zero instead: `(1 + 2) != 0` error[E0054]: cannot cast as `bool` --> $DIR/cast-as-bool.rs:8:13 | -LL | let v = "hello" as bool; //~ ERROR cannot cast as `bool` +LL | let v = "hello" as bool; | ^^^^^^^^^^^^^^^ unsupported cast error: aborting due to 3 previous errors diff --git a/src/test/ui/cast/cast-errors-issue-43825.stderr b/src/test/ui/cast/cast-errors-issue-43825.stderr index cfd1ca25a96a3..1e77f5dbdc643 100644 --- a/src/test/ui/cast/cast-errors-issue-43825.stderr +++ b/src/test/ui/cast/cast-errors-issue-43825.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `error` in this scope --> $DIR/cast-errors-issue-43825.rs:2:17 | -LL | let error = error; //~ ERROR cannot find value `error` +LL | let error = error; | ^^^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/cast/cast-ptr-to-int-const.stderr b/src/test/ui/cast/cast-ptr-to-int-const.stderr index d04595ee4e887..c40accfd7c4a1 100644 --- a/src/test/ui/cast/cast-ptr-to-int-const.stderr +++ b/src/test/ui/cast/cast-ptr-to-int-const.stderr @@ -1,17 +1,19 @@ -error[E0658]: casting pointers to integers in constants is unstable (see issue #51910) +error[E0658]: casting pointers to integers in constants is unstable --> $DIR/cast-ptr-to-int-const.rs:5:9 | -LL | main as u32 //~ ERROR casting pointers to integers in constants is unstable +LL | main as u32 | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51910 = help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable -error[E0658]: casting pointers to integers in constants is unstable (see issue #51910) +error[E0658]: casting pointers to integers in constants is unstable --> $DIR/cast-ptr-to-int-const.rs:9:9 | -LL | &Y as *const u32 as u32 //~ ERROR is unstable +LL | &Y as *const u32 as u32 | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51910 = help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.rs b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.rs index ac859c512637e..5342b595c7c5e 100644 --- a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.rs +++ b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.rs @@ -1,4 +1,4 @@ fn main() { - &1 as Send; //~ ERROR cast to unsized - Box::new(1) as Send; //~ ERROR cast to unsized + &1 as dyn Send; //~ ERROR cast to unsized + Box::new(1) as dyn Send; //~ ERROR cast to unsized } diff --git a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr index 37c6ba1b909c9..ffa02533d8b66 100644 --- a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr +++ b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr @@ -1,18 +1,18 @@ error[E0620]: cast to unsized type: `&{integer}` as `dyn std::marker::Send` --> $DIR/cast-to-unsized-trait-object-suggestion.rs:2:5 | -LL | &1 as Send; //~ ERROR cast to unsized - | ^^^^^^---- +LL | &1 as dyn Send; + | ^^^^^^-------- | | - | help: try casting to a reference instead: `&Send` + | help: try casting to a reference instead: `&dyn Send` error[E0620]: cast to unsized type: `std::boxed::Box<{integer}>` as `dyn std::marker::Send` --> $DIR/cast-to-unsized-trait-object-suggestion.rs:3:5 | -LL | Box::new(1) as Send; //~ ERROR cast to unsized - | ^^^^^^^^^^^^^^^---- +LL | Box::new(1) as dyn Send; + | ^^^^^^^^^^^^^^^-------- | | - | help: try casting to a `Box` instead: `Box` + | help: try casting to a `Box` instead: `Box` error: aborting due to 2 previous errors diff --git a/src/test/ui/cast_char.rs b/src/test/ui/cast_char.rs deleted file mode 100644 index 8c319af9c96e7..0000000000000 --- a/src/test/ui/cast_char.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![deny(overflowing_literals)] - -fn main() { - const XYZ: char = 0x1F888 as char; - //~^ ERROR only u8 can be cast into char - const XY: char = 129160 as char; - //~^ ERROR only u8 can be cast into char - const ZYX: char = '\u{01F888}'; - println!("{}", XYZ); -} diff --git a/src/test/ui/cast_char.stderr b/src/test/ui/cast_char.stderr deleted file mode 100644 index 570ca7cba8635..0000000000000 --- a/src/test/ui/cast_char.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: only u8 can be cast into char - --> $DIR/cast_char.rs:4:23 - | -LL | const XYZ: char = 0x1F888 as char; - | ^^^^^^^^^^^^^^^ help: use a char literal instead: `'/u{1F888}'` - | -note: lint level defined here - --> $DIR/cast_char.rs:1:9 - | -LL | #![deny(overflowing_literals)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: only u8 can be cast into char - --> $DIR/cast_char.rs:6:22 - | -LL | const XY: char = 129160 as char; - | ^^^^^^^^^^^^^^ help: use a char literal instead: `'/u{1F888}'` - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/casts-differing-anon.rs b/src/test/ui/casts-differing-anon.rs index cba178104c99f..d4a0f9613055e 100644 --- a/src/test/ui/casts-differing-anon.rs +++ b/src/test/ui/casts-differing-anon.rs @@ -5,7 +5,7 @@ fn foo() -> Box { x } fn bar() -> Box { - let y: Box = Box::new([0]); + let y: Box = Box::new([0]); y } diff --git a/src/test/ui/casts-differing-anon.stderr b/src/test/ui/casts-differing-anon.stderr index 8e09a7cd83b53..fbbb8e3bb332d 100644 --- a/src/test/ui/casts-differing-anon.stderr +++ b/src/test/ui/casts-differing-anon.stderr @@ -1,7 +1,7 @@ error[E0606]: casting `*mut impl std::fmt::Debug+?Sized` as `*mut impl std::fmt::Debug+?Sized` is invalid --> $DIR/casts-differing-anon.rs:21:13 | -LL | b_raw = f_raw as *mut _; //~ ERROR is invalid +LL | b_raw = f_raw as *mut _; | ^^^^^^^^^^^^^^^ | = note: vtable kinds may not match diff --git a/src/test/ui/casts-issue-46365.rs b/src/test/ui/casts-issue-46365.rs index 2e7c26b54e41b..3d0fea245c0c2 100644 --- a/src/test/ui/casts-issue-46365.rs +++ b/src/test/ui/casts-issue-46365.rs @@ -3,5 +3,5 @@ struct Lorem { } fn main() { - let _foo: *mut Lorem = 0 as *mut _; // no error here + let _foo: *mut Lorem = core::ptr::null_mut(); // no error here } diff --git a/src/test/ui/casts-issue-46365.stderr b/src/test/ui/casts-issue-46365.stderr index 91edfaf410ea6..84175473696df 100644 --- a/src/test/ui/casts-issue-46365.stderr +++ b/src/test/ui/casts-issue-46365.stderr @@ -1,7 +1,7 @@ error[E0412]: cannot find type `Ipsum` in this scope --> $DIR/casts-issue-46365.rs:2:12 | -LL | ipsum: Ipsum //~ ERROR cannot find type `Ipsum` +LL | ipsum: Ipsum | ^^^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/cdylib-deps-must-be-static.rs b/src/test/ui/cdylib-deps-must-be-static.rs index 241cc96fec04f..8530c9e24b200 100644 --- a/src/test/ui/cdylib-deps-must-be-static.rs +++ b/src/test/ui/cdylib-deps-must-be-static.rs @@ -3,7 +3,7 @@ // ignore-musl // ignore-cloudabi // ignore-emscripten - +// ignore-sgx no dynamic libraries #![crate_type = "cdylib"] extern crate cdylib_dep; diff --git a/src/test/ui/chalkify/lower_env1.stderr b/src/test/ui/chalkify/lower_env1.stderr index f4d16a09a367a..bc426e0707b7c 100644 --- a/src/test/ui/chalkify/lower_env1.stderr +++ b/src/test/ui/chalkify/lower_env1.stderr @@ -1,7 +1,7 @@ error: program clause dump --> $DIR/lower_env1.rs:6:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump +LL | #[rustc_dump_program_clauses] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: forall { FromEnv(Self: Foo) :- FromEnv(Self: Bar). } @@ -11,7 +11,7 @@ LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump error: program clause dump --> $DIR/lower_env1.rs:9:1 | -LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump +LL | #[rustc_dump_env_program_clauses] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: forall { FromEnv(Self: Foo) :- FromEnv(Self: Bar). } diff --git a/src/test/ui/chalkify/lower_env2.stderr b/src/test/ui/chalkify/lower_env2.stderr index f05b91c674d94..613a568a8549c 100644 --- a/src/test/ui/chalkify/lower_env2.stderr +++ b/src/test/ui/chalkify/lower_env2.stderr @@ -1,17 +1,17 @@ error: program clause dump --> $DIR/lower_env2.rs:6:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump +LL | #[rustc_dump_program_clauses] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: forall<'a, T> { FromEnv(T: Foo) :- FromEnv(S<'a, T>). } = note: forall<'a, T> { TypeOutlives(T: 'a) :- FromEnv(S<'a, T>). } - = note: forall<'a, T> { WellFormed(S<'a, T>) :- Implemented(T: Foo), TypeOutlives(T: 'a). } + = note: forall<'a, T> { WellFormed(S<'a, T>) :- WellFormed(T: Foo), TypeOutlives(T: 'a). } error: program clause dump --> $DIR/lower_env2.rs:11:1 | -LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump +LL | #[rustc_dump_env_program_clauses] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: forall<'a, T> { FromEnv(T: Foo) :- FromEnv(S<'a, T>). } diff --git a/src/test/ui/chalkify/lower_env3.stderr b/src/test/ui/chalkify/lower_env3.stderr index e602a8fcdaf85..a1fc83bfea8a3 100644 --- a/src/test/ui/chalkify/lower_env3.stderr +++ b/src/test/ui/chalkify/lower_env3.stderr @@ -1,19 +1,17 @@ error: program clause dump --> $DIR/lower_env3.rs:5:5 | -LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump +LL | #[rustc_dump_env_program_clauses] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: forall<'^0, ^1> { TypeOutlives(^1: '^0) :- FromEnv(&^1). } = note: forall { Implemented(Self: Foo) :- FromEnv(Self: Foo). } error: program clause dump --> $DIR/lower_env3.rs:10:5 | -LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump +LL | #[rustc_dump_env_program_clauses] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: forall<'^0, ^1> { TypeOutlives(^1: '^0) :- FromEnv(&^1). } = note: forall { FromEnv(Self: std::marker::Sized) :- FromEnv(Self: std::clone::Clone). } = note: forall { Implemented(Self: std::clone::Clone) :- FromEnv(Self: std::clone::Clone). } = note: forall { Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized). } diff --git a/src/test/ui/chalkify/lower_impl.stderr b/src/test/ui/chalkify/lower_impl.stderr index 48af37edec49e..d6827fbff3dd7 100644 --- a/src/test/ui/chalkify/lower_impl.stderr +++ b/src/test/ui/chalkify/lower_impl.stderr @@ -1,7 +1,7 @@ error: program clause dump --> $DIR/lower_impl.rs:5:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump +LL | #[rustc_dump_program_clauses] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: forall { Implemented(T: Foo) :- ProjectionEq(::Item == i32), TypeOutlives(T: 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized). } @@ -9,7 +9,7 @@ LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump error: program clause dump --> $DIR/lower_impl.rs:13:5 | -LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump +LL | #[rustc_dump_program_clauses] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: forall { Normalize(::Assoc -> std::vec::Vec) :- Implemented(T: Bar). } diff --git a/src/test/ui/chalkify/lower_struct.stderr b/src/test/ui/chalkify/lower_struct.stderr index e75e71450fbce..0331c2fca16db 100644 --- a/src/test/ui/chalkify/lower_struct.stderr +++ b/src/test/ui/chalkify/lower_struct.stderr @@ -1,13 +1,13 @@ error: program clause dump --> $DIR/lower_struct.rs:3:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump +LL | #[rustc_dump_program_clauses] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: forall<'a, T> { FromEnv(T: std::marker::Sized) :- FromEnv(Foo<'a, T>). } = note: forall<'a, T> { FromEnv(std::boxed::Box: std::clone::Clone) :- FromEnv(Foo<'a, T>). } = note: forall<'a, T> { TypeOutlives(T: 'a) :- FromEnv(Foo<'a, T>). } - = note: forall<'a, T> { WellFormed(Foo<'a, T>) :- Implemented(T: std::marker::Sized), Implemented(std::boxed::Box: std::clone::Clone), TypeOutlives(T: 'a). } + = note: forall<'a, T> { WellFormed(Foo<'a, T>) :- WellFormed(T: std::marker::Sized), WellFormed(std::boxed::Box: std::clone::Clone), TypeOutlives(T: 'a). } error: aborting due to previous error diff --git a/src/test/ui/chalkify/lower_trait.stderr b/src/test/ui/chalkify/lower_trait.stderr index 4546d2ede8235..ed3bded398ae3 100644 --- a/src/test/ui/chalkify/lower_trait.stderr +++ b/src/test/ui/chalkify/lower_trait.stderr @@ -1,7 +1,7 @@ error: program clause dump --> $DIR/lower_trait.rs:5:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump +LL | #[rustc_dump_program_clauses] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: forall { FromEnv(>::Assoc: Bar) :- FromEnv(Self: Foo). } @@ -12,13 +12,13 @@ LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump error: program clause dump --> $DIR/lower_trait.rs:7:5 | -LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump +LL | #[rustc_dump_program_clauses] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: forall { ProjectionEq(>::Assoc == ^3) :- Normalize(>::Assoc -> ^3). } = note: forall { FromEnv(Self: Foo) :- FromEnv(Unnormalized(>::Assoc)). } = note: forall { ProjectionEq(>::Assoc == Unnormalized(>::Assoc)). } - = note: forall { WellFormed(Unnormalized(>::Assoc)) :- Implemented(Self: Foo). } + = note: forall { WellFormed(Unnormalized(>::Assoc)) :- WellFormed(Self: Foo). } error: aborting due to 2 previous errors diff --git a/src/test/ui/chalkify/lower_trait_higher_rank.stderr b/src/test/ui/chalkify/lower_trait_higher_rank.stderr index d7e18596a7d22..79bbc9fa6b3a6 100644 --- a/src/test/ui/chalkify/lower_trait_higher_rank.stderr +++ b/src/test/ui/chalkify/lower_trait_higher_rank.stderr @@ -1,7 +1,7 @@ error: program clause dump --> $DIR/lower_trait_higher_rank.rs:3:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump +LL | #[rustc_dump_program_clauses] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: forall<'a, Self, F> { FromEnv(F: std::ops::Fn<(&'a (u8, u16),)>) :- FromEnv(Self: Foo). } diff --git a/src/test/ui/chalkify/lower_trait_where_clause.stderr b/src/test/ui/chalkify/lower_trait_where_clause.stderr index 5400224bdf42a..408f3712a7070 100644 --- a/src/test/ui/chalkify/lower_trait_where_clause.stderr +++ b/src/test/ui/chalkify/lower_trait_where_clause.stderr @@ -1,7 +1,7 @@ error: program clause dump --> $DIR/lower_trait_where_clause.rs:5:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump +LL | #[rustc_dump_program_clauses] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: forall<'a, 'b, Self, T, U> { FromEnv(T: std::borrow::Borrow) :- FromEnv(Self: Foo<'a, 'b, T, U>). } diff --git a/src/test/ui/chalkify/type_inference.stderr b/src/test/ui/chalkify/type_inference.stderr index d65b701307b43..6cb33f2f2c8c6 100644 --- a/src/test/ui/chalkify/type_inference.stderr +++ b/src/test/ui/chalkify/type_inference.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/type_inference.rs:21:14 | -LL | only_foo(x); //~ ERROR mismatched types +LL | only_foo(x); | ^ expected i32, found floating-point number | = note: expected type `i32` @@ -10,7 +10,7 @@ LL | only_foo(x); //~ ERROR mismatched types error[E0277]: the trait bound `{float}: Bar` is not satisfied --> $DIR/type_inference.rs:25:5 | -LL | only_bar(x); //~ ERROR the trait bound `{float}: Bar` is not satisfied +LL | only_bar(x); | ^^^^^^^^ the trait `Bar` is not implemented for `{float}` | = help: the following implementations were found: @@ -24,5 +24,5 @@ LL | fn only_bar(_x: T) { } error: aborting due to 2 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/changing-crates.stderr b/src/test/ui/changing-crates.stderr index a8b986d67f875..cc62a4d4d9d76 100644 --- a/src/test/ui/changing-crates.stderr +++ b/src/test/ui/changing-crates.stderr @@ -1,7 +1,7 @@ error[E0460]: found possibly newer version of crate `a` which `b` depends on --> $DIR/changing-crates.rs:10:1 | -LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on +LL | extern crate b; | ^^^^^^^^^^^^^^^ | = note: perhaps that crate needs to be recompiled? @@ -11,4 +11,3 @@ LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which error: aborting due to previous error -For more information about this error, try `rustc --explain E0460`. diff --git a/src/test/ui/check-static-values-constraints.nll.stderr b/src/test/ui/check-static-values-constraints.nll.stderr deleted file mode 100644 index f1a2312490813..0000000000000 --- a/src/test/ui/check-static-values-constraints.nll.stderr +++ /dev/null @@ -1,112 +0,0 @@ -error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/check-static-values-constraints.rs:65:43 - | -LL | ..SafeStruct{field1: SafeEnum::Variant3(WithDtor), - | ___________________________________________^ -LL | | //~^ ERROR destructors cannot be evaluated at compile-time -LL | | field2: SafeEnum::Variant1}}; - | |________________________________________________________________________________^ statics cannot evaluate destructors - -error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:79:33 - | -LL | static STATIC11: Box = box MyOwned; - | ^^^^^^^^^^^ allocation not allowed in statics - -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:79:37 - | -LL | static STATIC11: Box = box MyOwned; - | ^^^^^^^ - -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants - --> $DIR/check-static-values-constraints.rs:90:32 - | -LL | field2: SafeEnum::Variant4("str".to_string()) - | ^^^^^^^^^^^^^^^^^ - -error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:95:5 - | -LL | box MyOwned, //~ ERROR allocations are not allowed in statics - | ^^^^^^^^^^^ allocation not allowed in statics - -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:95:9 - | -LL | box MyOwned, //~ ERROR allocations are not allowed in statics - | ^^^^^^^ - -error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:97:5 - | -LL | box MyOwned, //~ ERROR allocations are not allowed in statics - | ^^^^^^^^^^^ allocation not allowed in statics - -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:97:9 - | -LL | box MyOwned, //~ ERROR allocations are not allowed in statics - | ^^^^^^^ - -error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:102:6 - | -LL | &box MyOwned, //~ ERROR allocations are not allowed in statics - | ^^^^^^^^^^^ allocation not allowed in statics - -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:102:10 - | -LL | &box MyOwned, //~ ERROR allocations are not allowed in statics - | ^^^^^^^ - -error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:104:6 - | -LL | &box MyOwned, //~ ERROR allocations are not allowed in statics - | ^^^^^^^^^^^ allocation not allowed in statics - -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:104:10 - | -LL | &box MyOwned, //~ ERROR allocations are not allowed in statics - | ^^^^^^^ - -error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:111:5 - | -LL | box 3; - | ^^^^^ allocation not allowed in statics - -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:111:9 - | -LL | box 3; - | ^ - -error[E0507]: cannot move out of static item - --> $DIR/check-static-values-constraints.rs:116:45 - | -LL | let y = { static x: Box = box 3; x }; - | ^ - | | - | cannot move out of static item - | help: consider borrowing here: `&x` - -error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:116:38 - | -LL | let y = { static x: Box = box 3; x }; - | ^^^^^ allocation not allowed in statics - -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:116:42 - | -LL | let y = { static x: Box = box 3; x }; - | ^ - -error: aborting due to 17 previous errors - -Some errors occurred: E0010, E0015, E0019, E0493, E0507. -For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/check-static-values-constraints.stderr b/src/test/ui/check-static-values-constraints.stderr index 5b1f265c34aef..a13c217483d5d 100644 --- a/src/test/ui/check-static-values-constraints.stderr +++ b/src/test/ui/check-static-values-constraints.stderr @@ -3,7 +3,7 @@ error[E0493]: destructors cannot be evaluated at compile-time | LL | ..SafeStruct{field1: SafeEnum::Variant3(WithDtor), | ___________________________________________^ -LL | | //~^ ERROR destructors cannot be evaluated at compile-time +LL | | LL | | field2: SafeEnum::Variant1}}; | |________________________________________________________________________________^ statics cannot evaluate destructors @@ -28,49 +28,49 @@ LL | field2: SafeEnum::Variant4("str".to_string()) error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:95:5 | -LL | box MyOwned, //~ ERROR allocations are not allowed in statics +LL | box MyOwned, | ^^^^^^^^^^^ allocation not allowed in statics error[E0019]: static contains unimplemented expression type --> $DIR/check-static-values-constraints.rs:95:9 | -LL | box MyOwned, //~ ERROR allocations are not allowed in statics +LL | box MyOwned, | ^^^^^^^ error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:97:5 | -LL | box MyOwned, //~ ERROR allocations are not allowed in statics +LL | box MyOwned, | ^^^^^^^^^^^ allocation not allowed in statics error[E0019]: static contains unimplemented expression type --> $DIR/check-static-values-constraints.rs:97:9 | -LL | box MyOwned, //~ ERROR allocations are not allowed in statics +LL | box MyOwned, | ^^^^^^^ error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:102:6 | -LL | &box MyOwned, //~ ERROR allocations are not allowed in statics +LL | &box MyOwned, | ^^^^^^^^^^^ allocation not allowed in statics error[E0019]: static contains unimplemented expression type --> $DIR/check-static-values-constraints.rs:102:10 | -LL | &box MyOwned, //~ ERROR allocations are not allowed in statics +LL | &box MyOwned, | ^^^^^^^ error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:104:6 | -LL | &box MyOwned, //~ ERROR allocations are not allowed in statics +LL | &box MyOwned, | ^^^^^^^^^^^ allocation not allowed in statics error[E0019]: static contains unimplemented expression type --> $DIR/check-static-values-constraints.rs:104:10 | -LL | &box MyOwned, //~ ERROR allocations are not allowed in statics +LL | &box MyOwned, | ^^^^^^^ error[E0010]: allocations are not allowed in statics @@ -85,11 +85,14 @@ error[E0019]: static contains unimplemented expression type LL | box 3; | ^ -error[E0507]: cannot move out of static item +error[E0507]: cannot move out of static item `x` --> $DIR/check-static-values-constraints.rs:116:45 | LL | let y = { static x: Box = box 3; x }; - | ^ cannot move out of static item + | ^ + | | + | move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | help: consider borrowing here: `&x` error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:116:38 @@ -105,5 +108,5 @@ LL | let y = { static x: Box = box 3; x }; error: aborting due to 17 previous errors -Some errors occurred: E0010, E0015, E0019, E0493, E0507. +Some errors have detailed explanations: E0010, E0015, E0019, E0507. For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/check_match/issue-35609.stderr b/src/test/ui/check_match/issue-35609.stderr index 7a517e856cbe2..af22535c55e5a 100644 --- a/src/test/ui/check_match/issue-35609.stderr +++ b/src/test/ui/check_match/issue-35609.stderr @@ -1,50 +1,72 @@ error[E0004]: non-exhaustive patterns: `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered --> $DIR/issue-35609.rs:10:11 | -LL | match (A, ()) { //~ ERROR non-exhaustive +LL | match (A, ()) { | ^^^^^^^ patterns `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered --> $DIR/issue-35609.rs:14:11 | -LL | match (A, A) { //~ ERROR non-exhaustive +LL | match (A, A) { | ^^^^^^ patterns `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered --> $DIR/issue-35609.rs:18:11 | -LL | match ((A, ()), ()) { //~ ERROR non-exhaustive +LL | match ((A, ()), ()) { | ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered --> $DIR/issue-35609.rs:22:11 | -LL | match ((A, ()), A) { //~ ERROR non-exhaustive +LL | match ((A, ()), A) { | ^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered --> $DIR/issue-35609.rs:26:11 | -LL | match ((A, ()), ()) { //~ ERROR non-exhaustive +LL | match ((A, ()), ()) { | ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered --> $DIR/issue-35609.rs:31:11 | -LL | match S(A, ()) { //~ ERROR non-exhaustive +LL | struct S(Enum, ()); + | ------------------- `S` defined here +... +LL | match S(A, ()) { | ^^^^^^^^ patterns `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered --> $DIR/issue-35609.rs:35:11 | -LL | match (Sd { x: A, y: () }) { //~ ERROR non-exhaustive +LL | struct Sd { x: Enum, y: () } + | ---------------------------- `Sd` defined here +... +LL | match (Sd { x: A, y: () }) { | ^^^^^^^^^^^^^^^^^^^^ patterns `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered --> $DIR/issue-35609.rs:39:11 | -LL | match Some(A) { //~ ERROR non-exhaustive +LL | match Some(A) { | ^^^^^^^ patterns `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to 8 previous errors diff --git a/src/test/ui/class-cast-to-trait.rs b/src/test/ui/class-cast-to-trait.rs index 3ae4987254fce..bb4c3fac93806 100644 --- a/src/test/ui/class-cast-to-trait.rs +++ b/src/test/ui/class-cast-to-trait.rs @@ -49,6 +49,6 @@ fn cat(in_x : usize, in_y : isize, in_name: String) -> Cat { } fn main() { - let nyan: Box = box cat(0, 2, "nyan".to_string()) as Box; + let nyan: Box = box cat(0, 2, "nyan".to_string()) as Box; nyan.eat(); //~ ERROR no method named `eat` found } diff --git a/src/test/ui/class-cast-to-trait.stderr b/src/test/ui/class-cast-to-trait.stderr index f5bd7a13aa485..39f308cdfd490 100644 --- a/src/test/ui/class-cast-to-trait.stderr +++ b/src/test/ui/class-cast-to-trait.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `eat` found for type `std::boxed::Box` in the current scope --> $DIR/class-cast-to-trait.rs:53:8 | -LL | nyan.eat(); //~ ERROR no method named `eat` found +LL | nyan.eat(); | ^^^ error: aborting due to previous error diff --git a/src/test/ui/class-missing-self.stderr b/src/test/ui/class-missing-self.stderr index 484778f83ec58..25cb85dadb903 100644 --- a/src/test/ui/class-missing-self.stderr +++ b/src/test/ui/class-missing-self.stderr @@ -1,13 +1,13 @@ error[E0425]: cannot find value `meows` in this scope --> $DIR/class-missing-self.rs:9:7 | -LL | meows += 1; //~ ERROR cannot find value `meows` in this scope - | ^^^^^ help: try: `self.meows` +LL | meows += 1; + | ^^^^^ help: you might have meant to use the available field: `self.meows` error[E0425]: cannot find function `sleep` in this scope --> $DIR/class-missing-self.rs:10:7 | -LL | sleep(); //~ ERROR cannot find function `sleep` in this scope +LL | sleep(); | ^^^^^ not found in this scope help: possible candidate is found in another module, you can import it into scope | diff --git a/src/test/ui/cleanup-rvalue-scopes-cf.rs b/src/test/ui/cleanup-rvalue-scopes-cf.rs index 106dbd324ff9e..e3cecb1bffed6 100644 --- a/src/test/ui/cleanup-rvalue-scopes-cf.rs +++ b/src/test/ui/cleanup-rvalue-scopes-cf.rs @@ -1,5 +1,3 @@ -// ignore-compare-mode-nll - // Test that the borrow checker prevents pointers to temporaries // with statement lifetimes from escaping. @@ -7,7 +5,7 @@ use std::ops::Drop; static mut FLAGS: u64 = 0; -struct Box { f: T } +struct StackBox { f: T } struct AddFlags { bits: u64 } fn AddFlags(bits: u64) -> AddFlags { @@ -25,11 +23,13 @@ impl AddFlags { } pub fn main() { - let _x = arg(&AddFlags(1)); //~ ERROR value does not live long enough - let _x = AddFlags(1).get(); //~ ERROR value does not live long enough - let _x = &*arg(&AddFlags(1)); //~ ERROR value does not live long enough - let ref _x = *arg(&AddFlags(1)); //~ ERROR value does not live long enough - let &ref _x = arg(&AddFlags(1)); //~ ERROR value does not live long enough - let _x = AddFlags(1).get(); //~ ERROR value does not live long enough - let Box { f: _x } = Box { f: AddFlags(1).get() }; //~ ERROR value does not live long enough + let x1 = arg(&AddFlags(1)); //~ ERROR temporary value dropped while borrowed + let x2 = AddFlags(1).get(); //~ ERROR temporary value dropped while borrowed + let x3 = &*arg(&AddFlags(1)); //~ ERROR temporary value dropped while borrowed + let ref x4 = *arg(&AddFlags(1)); //~ ERROR temporary value dropped while borrowed + let &ref x5 = arg(&AddFlags(1)); //~ ERROR temporary value dropped while borrowed + let x6 = AddFlags(1).get(); //~ ERROR temporary value dropped while borrowed + let StackBox { f: x7 } = StackBox { f: AddFlags(1).get() }; + //~^ ERROR temporary value dropped while borrowed + (x1, x2, x3, x4, x5, x6, x7); } diff --git a/src/test/ui/cleanup-rvalue-scopes-cf.stderr b/src/test/ui/cleanup-rvalue-scopes-cf.stderr index 561403d1b42de..04e599755fb29 100644 --- a/src/test/ui/cleanup-rvalue-scopes-cf.stderr +++ b/src/test/ui/cleanup-rvalue-scopes-cf.stderr @@ -1,93 +1,94 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/cleanup-rvalue-scopes-cf.rs:28:19 +error[E0716]: temporary value dropped while borrowed + --> $DIR/cleanup-rvalue-scopes-cf.rs:26:19 | -LL | let _x = arg(&AddFlags(1)); //~ ERROR value does not live long enough - | ^^^^^^^^^^^ - temporary value dropped here while still borrowed +LL | let x1 = arg(&AddFlags(1)); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... -LL | } - | - temporary value needs to live until here +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value -error[E0597]: borrowed value does not live long enough - --> $DIR/cleanup-rvalue-scopes-cf.rs:29:14 +error[E0716]: temporary value dropped while borrowed + --> $DIR/cleanup-rvalue-scopes-cf.rs:27:14 | -LL | let _x = AddFlags(1).get(); //~ ERROR value does not live long enough - | ^^^^^^^^^^^ - temporary value dropped here while still borrowed +LL | let x2 = AddFlags(1).get(); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... -LL | } - | - temporary value needs to live until here +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value -error[E0597]: borrowed value does not live long enough - --> $DIR/cleanup-rvalue-scopes-cf.rs:30:21 +error[E0716]: temporary value dropped while borrowed + --> $DIR/cleanup-rvalue-scopes-cf.rs:28:21 | -LL | let _x = &*arg(&AddFlags(1)); //~ ERROR value does not live long enough - | ^^^^^^^^^^^ - temporary value dropped here while still borrowed +LL | let x3 = &*arg(&AddFlags(1)); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... -LL | } - | - temporary value needs to live until here +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value -error[E0597]: borrowed value does not live long enough - --> $DIR/cleanup-rvalue-scopes-cf.rs:31:24 +error[E0716]: temporary value dropped while borrowed + --> $DIR/cleanup-rvalue-scopes-cf.rs:29:24 | -LL | let ref _x = *arg(&AddFlags(1)); //~ ERROR value does not live long enough - | ^^^^^^^^^^^ - temporary value dropped here while still borrowed +LL | let ref x4 = *arg(&AddFlags(1)); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... -LL | } - | - temporary value needs to live until here +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value -error[E0597]: borrowed value does not live long enough - --> $DIR/cleanup-rvalue-scopes-cf.rs:32:24 +error[E0716]: temporary value dropped while borrowed + --> $DIR/cleanup-rvalue-scopes-cf.rs:30:24 | -LL | let &ref _x = arg(&AddFlags(1)); //~ ERROR value does not live long enough - | ^^^^^^^^^^^ - temporary value dropped here while still borrowed +LL | let &ref x5 = arg(&AddFlags(1)); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... -LL | } - | - temporary value needs to live until here +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value -error[E0597]: borrowed value does not live long enough - --> $DIR/cleanup-rvalue-scopes-cf.rs:33:14 +error[E0716]: temporary value dropped while borrowed + --> $DIR/cleanup-rvalue-scopes-cf.rs:31:14 | -LL | let _x = AddFlags(1).get(); //~ ERROR value does not live long enough - | ^^^^^^^^^^^ - temporary value dropped here while still borrowed +LL | let x6 = AddFlags(1).get(); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough -LL | let Box { f: _x } = Box { f: AddFlags(1).get() }; //~ ERROR value does not live long enough -LL | } - | - temporary value needs to live until here + | creates a temporary which is freed while still in use +... +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value -error[E0597]: borrowed value does not live long enough - --> $DIR/cleanup-rvalue-scopes-cf.rs:34:34 +error[E0716]: temporary value dropped while borrowed + --> $DIR/cleanup-rvalue-scopes-cf.rs:32:44 | -LL | let Box { f: _x } = Box { f: AddFlags(1).get() }; //~ ERROR value does not live long enough - | ^^^^^^^^^^^ - temporary value dropped here while still borrowed - | | - | temporary value does not live long enough -LL | } - | - temporary value needs to live until here +LL | let StackBox { f: x7 } = StackBox { f: AddFlags(1).get() }; + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use +LL | +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr new file mode 100644 index 0000000000000..7e4ac4e8ce656 --- /dev/null +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr @@ -0,0 +1,53 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/expect-fn-supply-fn.rs:30:5 + | +LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _` + | | + | expected signature of `fn(fn(&'a u32), &i32) -> _` + | +note: required by `with_closure_expecting_fn_with_free_region` + --> $DIR/expect-fn-supply-fn.rs:1:1 + | +LL | / fn with_closure_expecting_fn_with_free_region(_: F) +LL | | where F: for<'a> FnOnce(fn(&'a u32), &i32) +LL | | { +LL | | } + | |_^ + +error[E0631]: type mismatch in closure arguments + --> $DIR/expect-fn-supply-fn.rs:37:5 + | +LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _` + | | + | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` + | +note: required by `with_closure_expecting_fn_with_bound_region` + --> $DIR/expect-fn-supply-fn.rs:6:1 + | +LL | / fn with_closure_expecting_fn_with_bound_region(_: F) +LL | | where F: FnOnce(fn(&u32), &i32) +LL | | { +LL | | } + | |_^ + +error[E0631]: type mismatch in closure arguments + --> $DIR/expect-fn-supply-fn.rs:46:5 + | +LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _` + | | + | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` + | +note: required by `with_closure_expecting_fn_with_bound_region` + --> $DIR/expect-fn-supply-fn.rs:6:1 + | +LL | / fn with_closure_expecting_fn_with_bound_region(_: F) +LL | | where F: FnOnce(fn(&u32), &i32) +LL | | { +LL | | } + | |_^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr index ab35aeff697b7..40fab4d4edf78 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr @@ -89,5 +89,4 @@ LL | | } error: aborting due to 5 previous errors -Some errors occurred: E0308, E0631. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr b/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr index 7a0938e9f7e5e..c9a697496de59 100644 --- a/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr +++ b/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr @@ -17,4 +17,3 @@ LL | | } error: aborting due to previous error -For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr index 7dd996cce5d45..2005bd4dd5ca7 100644 --- a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr +++ b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed --> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:27 | -LL | with_closure(|x: u32, y| {}); //~ ERROR E0282 +LL | with_closure(|x: u32, y| {}); | ^ consider giving this closure parameter a type error: aborting due to previous error diff --git a/src/test/ui/closure_context/issue-26046-fn-mut.rs b/src/test/ui/closure_context/issue-26046-fn-mut.rs index e5840181e41ef..0a015ea1436c5 100644 --- a/src/test/ui/closure_context/issue-26046-fn-mut.rs +++ b/src/test/ui/closure_context/issue-26046-fn-mut.rs @@ -1,4 +1,4 @@ -fn foo() -> Box { +fn foo() -> Box { let num = 5; let closure = || { //~ ERROR expected a closure that diff --git a/src/test/ui/closure_context/issue-26046-fn-mut.stderr b/src/test/ui/closure_context/issue-26046-fn-mut.stderr index bdfd26f6871ab..74d3c4977ee65 100644 --- a/src/test/ui/closure_context/issue-26046-fn-mut.stderr +++ b/src/test/ui/closure_context/issue-26046-fn-mut.stderr @@ -1,7 +1,7 @@ error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` --> $DIR/issue-26046-fn-mut.rs:4:19 | -LL | let closure = || { //~ ERROR expected a closure that +LL | let closure = || { | ^^ this closure implements `FnMut`, not `Fn` LL | num += 1; | --- closure is `FnMut` because it mutates the variable `num` here diff --git a/src/test/ui/closure_context/issue-26046-fn-once.rs b/src/test/ui/closure_context/issue-26046-fn-once.rs index d33420c52a035..511690e9dd4b3 100644 --- a/src/test/ui/closure_context/issue-26046-fn-once.rs +++ b/src/test/ui/closure_context/issue-26046-fn-once.rs @@ -1,4 +1,4 @@ -fn get_closure() -> Box Vec> { +fn get_closure() -> Box Vec> { let vec = vec![1u8, 2u8]; let closure = move || { //~ ERROR expected a closure diff --git a/src/test/ui/closure_context/issue-26046-fn-once.stderr b/src/test/ui/closure_context/issue-26046-fn-once.stderr index e7bcbb9e63083..473e8e8417e6e 100644 --- a/src/test/ui/closure_context/issue-26046-fn-once.stderr +++ b/src/test/ui/closure_context/issue-26046-fn-once.stderr @@ -1,7 +1,7 @@ error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` --> $DIR/issue-26046-fn-once.rs:4:19 | -LL | let closure = move || { //~ ERROR expected a closure +LL | let closure = move || { | ^^^^^^^ this closure implements `FnOnce`, not `Fn` LL | vec | --- closure is `FnOnce` because it moves the variable `vec` out of its environment diff --git a/src/test/ui/closure_promotion.rs b/src/test/ui/closure_promotion.rs index a80745e8bcc18..db9c0a6ef3be4 100644 --- a/src/test/ui/closure_promotion.rs +++ b/src/test/ui/closure_promotion.rs @@ -1,8 +1,7 @@ -// ignore-compare-mode-nll +// compile-pass #![allow(const_err)] -// nll successfully compiles this. fn main() { - let x: &'static _ = &|| { let z = 3; z }; //~ ERROR does not live long enough + let x: &'static _ = &|| { let z = 3; z }; } diff --git a/src/test/ui/closure_promotion.stderr b/src/test/ui/closure_promotion.stderr deleted file mode 100644 index 7b901e3011785..0000000000000 --- a/src/test/ui/closure_promotion.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/closure_promotion.rs:7:26 - | -LL | let x: &'static _ = &|| { let z = 3; z }; //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/closures/closure-array-break-length.rs b/src/test/ui/closures/closure-array-break-length.rs index ac17bfdc941c8..a7f16d70ba860 100644 --- a/src/test/ui/closures/closure-array-break-length.rs +++ b/src/test/ui/closures/closure-array-break-length.rs @@ -2,6 +2,8 @@ fn main() { |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of loop + //~^ ERROR mismatched types while |_: [_; break]| {} {} //~ ERROR: `break` outside of loop + //~^ ERROR mismatched types } diff --git a/src/test/ui/closures/closure-array-break-length.stderr b/src/test/ui/closures/closure-array-break-length.stderr index fa7a63b642e6f..46fbd3e0fae0b 100644 --- a/src/test/ui/closures/closure-array-break-length.stderr +++ b/src/test/ui/closures/closure-array-break-length.stderr @@ -1,21 +1,40 @@ error[E0268]: `continue` outside of loop --> $DIR/closure-array-break-length.rs:2:13 | -LL | |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop +LL | |_: [_; continue]| {}; | ^^^^^^^^ cannot break outside of a loop error[E0268]: `continue` outside of loop --> $DIR/closure-array-break-length.rs:4:19 | -LL | while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of loop +LL | while |_: [_; continue]| {} {} | ^^^^^^^^ cannot break outside of a loop error[E0268]: `break` outside of loop - --> $DIR/closure-array-break-length.rs:6:19 + --> $DIR/closure-array-break-length.rs:7:19 | -LL | while |_: [_; break]| {} {} //~ ERROR: `break` outside of loop +LL | while |_: [_; break]| {} {} | ^^^^^ cannot break outside of a loop -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/closure-array-break-length.rs:4:11 + | +LL | while |_: [_; continue]| {} {} + | ^^^^^^^^^^^^^^^^^^^^^ expected bool, found closure + | + = note: expected type `bool` + found type `[closure@$DIR/closure-array-break-length.rs:4:11: 4:32]` + +error[E0308]: mismatched types + --> $DIR/closure-array-break-length.rs:7:11 + | +LL | while |_: [_; break]| {} {} + | ^^^^^^^^^^^^^^^^^^ expected bool, found closure + | + = note: expected type `bool` + found type `[closure@$DIR/closure-array-break-length.rs:7:11: 7:29]` + +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0268`. +Some errors have detailed explanations: E0268, E0308. +For more information about an error, try `rustc --explain E0268`. diff --git a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr index 7d637fed8ab62..81c4f4e00aba0 100644 --- a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr +++ b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr @@ -2,7 +2,7 @@ error[E0277]: `F` cannot be sent between threads safely --> $DIR/closure-bounds-cant-promote-superkind-in-struct.rs:5:1 | LL | / fn foo(blk: F) -> X where F: FnOnce() + 'static { -LL | | //~^ ERROR `F` cannot be sent between threads safely +LL | | LL | | return X { field: blk }; LL | | } | |_^ `F` cannot be sent between threads safely diff --git a/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.nll.stderr b/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.nll.stderr new file mode 100644 index 0000000000000..1d12e2f585e8d --- /dev/null +++ b/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.nll.stderr @@ -0,0 +1,37 @@ +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/closure-bounds-static-cant-capture-borrowed.rs:5:5 + | +LL | fn foo(x: &()) { + | --- help: add explicit lifetime `'static` to the type of `x`: `&'static ()` +LL | / bar(|| { +LL | | +LL | | let _ = x; +LL | | }) + | |______^ lifetime `'static` required + +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/closure-bounds-static-cant-capture-borrowed.rs:5:9 + | +LL | bar(|| { + | ^^ may outlive borrowed value `x` +LL | +LL | let _ = x; + | - `x` is borrowed here + | +note: function requires argument type to outlive `'static` + --> $DIR/closure-bounds-static-cant-capture-borrowed.rs:5:5 + | +LL | / bar(|| { +LL | | +LL | | let _ = x; +LL | | }) + | |______^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | bar(move || { + | ^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0373, E0621. +For more information about an error, try `rustc --explain E0373`. diff --git a/src/test/ui/closures/closure-bounds-subtype.stderr b/src/test/ui/closures/closure-bounds-subtype.stderr index d018956d026c9..3b9fd10af3860 100644 --- a/src/test/ui/closures/closure-bounds-subtype.stderr +++ b/src/test/ui/closures/closure-bounds-subtype.stderr @@ -1,7 +1,7 @@ error[E0277]: `F` cannot be shared between threads safely --> $DIR/closure-bounds-subtype.rs:13:5 | -LL | take_const_owned(f); //~ ERROR `F` cannot be shared between threads safely [E0277] +LL | take_const_owned(f); | ^^^^^^^^^^^^^^^^ `F` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `F` diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr new file mode 100644 index 0000000000000..bbf75302d564a --- /dev/null +++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr @@ -0,0 +1,42 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/expect-region-supply-region.rs:18:9 + | +LL | let mut f: Option<&u32> = None; + | ----- `f` is declared here, outside of the closure body +LL | closure_expecting_bound(|x| { + | - `x` is a reference that is only valid in the closure body +LL | f = Some(x); + | ^^^^^^^^^^^ `x` escapes the closure body here + +error[E0521]: borrowed data escapes outside of closure + --> $DIR/expect-region-supply-region.rs:28:9 + | +LL | let mut f: Option<&u32> = None; + | ----- `f` is declared here, outside of the closure body +LL | closure_expecting_bound(|x: &u32| { + | - `x` is a reference that is only valid in the closure body +LL | f = Some(x); + | ^^^^^^^^^^^ `x` escapes the closure body here + +error: lifetime may not live long enough + --> $DIR/expect-region-supply-region.rs:37:30 + | +LL | fn expect_bound_supply_named<'x>() { + | -- lifetime `'x` defined here +... +LL | closure_expecting_bound(|x: &'x u32| { + | ^ - let's call the lifetime of this reference `'1` + | | + | requires that `'1` must outlive `'x` + +error: lifetime may not live long enough + --> $DIR/expect-region-supply-region.rs:37:30 + | +LL | fn expect_bound_supply_named<'x>() { + | -- lifetime `'x` defined here +... +LL | closure_expecting_bound(|x: &'x u32| { + | ^ requires that `'x` must outlive `'static` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr index 633dd4f5c62a6..e3b623d55248e 100644 --- a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr +++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr @@ -5,7 +5,7 @@ LL | let mut f: Option<&u32> = None; | ----- borrowed data cannot be stored into here... LL | closure_expecting_bound(|x| { | --- ...because it cannot outlive this closure -LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure +LL | f = Some(x); | ^ cannot be stored outside of its closure error: borrowed data cannot be stored outside of its closure @@ -15,7 +15,7 @@ LL | let mut f: Option<&u32> = None; | ----- borrowed data cannot be stored into here... LL | closure_expecting_bound(|x: &u32| { | --------- ...because it cannot outlive this closure -LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure +LL | f = Some(x); | ^ cannot be stored outside of its closure error[E0308]: mismatched types @@ -31,11 +31,11 @@ note: the anonymous lifetime #2 defined on the body at 37:29... | LL | closure_expecting_bound(|x: &'x u32| { | _____________________________^ -LL | | //~^ ERROR mismatched types -LL | | //~| ERROR mismatched types +LL | | +LL | | LL | | ... | -LL | | //~^ ERROR borrowed data cannot be stored outside of its closure +LL | | LL | | }); | |_____^ note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 32:30 @@ -62,11 +62,11 @@ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the b | LL | closure_expecting_bound(|x: &'x u32| { | _____________________________^ -LL | | //~^ ERROR mismatched types -LL | | //~| ERROR mismatched types +LL | | +LL | | LL | | ... | -LL | | //~^ ERROR borrowed data cannot be stored outside of its closure +LL | | LL | | }); | |_____^ diff --git a/src/test/ui/closures/closure-immutable-outer-variable.fixed b/src/test/ui/closures/closure-immutable-outer-variable.fixed index 22164a24d8bf0..102f1f94a36e1 100644 --- a/src/test/ui/closures/closure-immutable-outer-variable.fixed +++ b/src/test/ui/closures/closure-immutable-outer-variable.fixed @@ -2,11 +2,12 @@ // Point at the captured immutable outer variable -fn foo(mut f: Box) { +fn foo(mut f: Box) { f(); } fn main() { let mut y = true; - foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable + foo(Box::new(move || y = false) as Box<_>); + //~^ ERROR cannot assign to `y`, as it is not declared as mutable } diff --git a/src/test/ui/closures/closure-immutable-outer-variable.nll.stderr b/src/test/ui/closures/closure-immutable-outer-variable.nll.stderr deleted file mode 100644 index 0c4d90f4c531a..0000000000000 --- a/src/test/ui/closures/closure-immutable-outer-variable.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0594]: cannot assign to `y`, as it is not declared as mutable - --> $DIR/closure-immutable-outer-variable.rs:11:26 - | -LL | let y = true; - | - help: consider changing this to be mutable: `mut y` -LL | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable - | ^^^^^^^^^ cannot assign - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/closures/closure-immutable-outer-variable.rs b/src/test/ui/closures/closure-immutable-outer-variable.rs index fc4e3857268a8..6eb43b372c96c 100644 --- a/src/test/ui/closures/closure-immutable-outer-variable.rs +++ b/src/test/ui/closures/closure-immutable-outer-variable.rs @@ -2,11 +2,12 @@ // Point at the captured immutable outer variable -fn foo(mut f: Box) { +fn foo(mut f: Box) { f(); } fn main() { let y = true; - foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable + foo(Box::new(move || y = false) as Box<_>); + //~^ ERROR cannot assign to `y`, as it is not declared as mutable } diff --git a/src/test/ui/closures/closure-immutable-outer-variable.stderr b/src/test/ui/closures/closure-immutable-outer-variable.stderr index c6a6ebd931c68..558c9caeff336 100644 --- a/src/test/ui/closures/closure-immutable-outer-variable.stderr +++ b/src/test/ui/closures/closure-immutable-outer-variable.stderr @@ -1,11 +1,10 @@ -error[E0594]: cannot assign to captured outer variable in an `FnMut` closure +error[E0594]: cannot assign to `y`, as it is not declared as mutable --> $DIR/closure-immutable-outer-variable.rs:11:26 | LL | let y = true; - | - help: consider making `y` mutable: `mut y` -LL | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable - | ^^^^^^^^^ + | - help: consider changing this to be mutable: `mut y` +LL | foo(Box::new(move || y = false) as Box<_>); + | ^^^^^^^^^ cannot assign error: aborting due to previous error -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/closures/closure-referencing-itself-issue-25954.stderr b/src/test/ui/closures/closure-referencing-itself-issue-25954.stderr index f60be43bba813..8ca43cd1cffb1 100644 --- a/src/test/ui/closures/closure-referencing-itself-issue-25954.stderr +++ b/src/test/ui/closures/closure-referencing-itself-issue-25954.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/closure-referencing-itself-issue-25954.rs:15:13 | -LL | let q = || p.b.set(5i32); //~ ERROR mismatched types +LL | let q = || p.b.set(5i32); | ^^^^^^^^^^^^^^^^ cyclic type of infinite size error: aborting due to previous error diff --git a/src/test/ui/closures/closure-reform-bad.stderr b/src/test/ui/closures/closure-reform-bad.stderr index 76f88d0490745..5c5480912be43 100644 --- a/src/test/ui/closures/closure-reform-bad.stderr +++ b/src/test/ui/closures/closure-reform-bad.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/closure-reform-bad.rs:11:15 | -LL | call_bare(f) //~ ERROR mismatched types +LL | call_bare(f) | ^ expected fn pointer, found closure | = note: expected type `for<'r> fn(&'r str)` diff --git a/src/test/ui/closures/closure-wrong-kind.stderr b/src/test/ui/closures/closure-wrong-kind.stderr index b289ea2964426..65026128ae622 100644 --- a/src/test/ui/closures/closure-wrong-kind.stderr +++ b/src/test/ui/closures/closure-wrong-kind.stderr @@ -1,7 +1,7 @@ error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` --> $DIR/closure-wrong-kind.rs:10:19 | -LL | let closure = |_| foo(x); //~ ERROR E0525 +LL | let closure = |_| foo(x); | ^^^^^^^^-^ | | | | | closure is `FnOnce` because it moves the variable `x` out of its environment diff --git a/src/test/ui/codemap_tests/bad-format-args.stderr b/src/test/ui/codemap_tests/bad-format-args.stderr index 38320416b4509..c424eb08a7a98 100644 --- a/src/test/ui/codemap_tests/bad-format-args.stderr +++ b/src/test/ui/codemap_tests/bad-format-args.stderr @@ -1,7 +1,7 @@ error: requires at least a format string argument --> $DIR/bad-format-args.rs:2:5 | -LL | format!(); //~ ERROR requires at least a format string argument +LL | format!(); | ^^^^^^^^^^ | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) @@ -9,13 +9,13 @@ LL | format!(); //~ ERROR requires at least a format string argument error: expected token: `,` --> $DIR/bad-format-args.rs:3:16 | -LL | format!("" 1); //~ ERROR expected token: `,` +LL | format!("" 1); | ^ error: expected token: `,` --> $DIR/bad-format-args.rs:4:19 | -LL | format!("", 1 1); //~ ERROR expected token: `,` +LL | format!("", 1 1); | ^ error: aborting due to 3 previous errors diff --git a/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs index f35fbad7cd6df..414acfd84ce4e 100644 --- a/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs +++ b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] trait C {} -impl C { fn f() {} } //~ ERROR duplicate -impl C { fn f() {} } +impl dyn C { fn f() {} } //~ ERROR duplicate +impl dyn C { fn f() {} } fn main() { } diff --git a/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr index 5f8bc387a3d29..a60be6f23c415 100644 --- a/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr +++ b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr @@ -1,10 +1,10 @@ error[E0592]: duplicate definitions with name `f` - --> $DIR/coherence-overlapping-inherent-impl-trait.rs:4:10 + --> $DIR/coherence-overlapping-inherent-impl-trait.rs:4:14 | -LL | impl C { fn f() {} } //~ ERROR duplicate - | ^^^^^^^^^ duplicate definitions for `f` -LL | impl C { fn f() {} } - | --------- other definition for `f` +LL | impl dyn C { fn f() {} } + | ^^^^^^^^^ duplicate definitions for `f` +LL | impl dyn C { fn f() {} } + | --------- other definition for `f` error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/empty_span.stderr b/src/test/ui/codemap_tests/empty_span.stderr index f52856770978e..1dd99cfd64fa5 100644 --- a/src/test/ui/codemap_tests/empty_span.stderr +++ b/src/test/ui/codemap_tests/empty_span.stderr @@ -1,7 +1,7 @@ error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `&'static main::Foo` --> $DIR/empty_span.rs:7:5 | -LL | unsafe impl Send for &'static Foo { } //~ ERROR cross-crate traits with a default impl +LL | unsafe impl Send for &'static Foo { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.nll.stderr b/src/test/ui/codemap_tests/huge_multispan_highlight.nll.stderr deleted file mode 100644 index 7fdeb03acbd6c..0000000000000 --- a/src/test/ui/codemap_tests/huge_multispan_highlight.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/huge_multispan_highlight.rs:90:13 - | -LL | let x = "foo"; - | - help: consider changing this to be mutable: `mut x` -... -LL | let y = &mut x; //~ ERROR cannot borrow - | ^^^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr index 41df802b503d6..a60f1c77a5863 100644 --- a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr +++ b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr @@ -1,11 +1,11 @@ -error[E0596]: cannot borrow immutable local variable `x` as mutable - --> $DIR/huge_multispan_highlight.rs:90:18 +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/huge_multispan_highlight.rs:90:13 | LL | let x = "foo"; - | - help: make this binding mutable: `mut x` + | - help: consider changing this to be mutable: `mut x` ... -LL | let y = &mut x; //~ ERROR cannot borrow - | ^ cannot borrow mutably +LL | let y = &mut x; + | ^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/issue-11715.nll.stderr b/src/test/ui/codemap_tests/issue-11715.nll.stderr deleted file mode 100644 index 9f30f38542549..0000000000000 --- a/src/test/ui/codemap_tests/issue-11715.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/issue-11715.rs:5:13 - | -LL | let y = &mut x; - | ------ first mutable borrow occurs here -LL | let z = &mut x; //~ ERROR cannot borrow - | ^^^^^^ second mutable borrow occurs here -LL | z.use_mut(); -LL | y.use_mut(); - | - first borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/codemap_tests/issue-11715.stderr b/src/test/ui/codemap_tests/issue-11715.stderr index 8f320a4e19b2d..d0c29c768eb61 100644 --- a/src/test/ui/codemap_tests/issue-11715.stderr +++ b/src/test/ui/codemap_tests/issue-11715.stderr @@ -1,13 +1,13 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/issue-11715.rs:5:18 + --> $DIR/issue-11715.rs:5:13 | LL | let y = &mut x; - | - first mutable borrow occurs here -LL | let z = &mut x; //~ ERROR cannot borrow - | ^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here + | ------ first mutable borrow occurs here +LL | let z = &mut x; + | ^^^^^^ second mutable borrow occurs here +LL | z.use_mut(); +LL | y.use_mut(); + | - first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/one_line.nll.stderr b/src/test/ui/codemap_tests/one_line.nll.stderr deleted file mode 100644 index 0eb257c5976a5..0000000000000 --- a/src/test/ui/codemap_tests/one_line.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0499]: cannot borrow `v` as mutable more than once at a time - --> $DIR/one_line.rs:3:12 - | -LL | v.push(v.pop().unwrap()); //~ ERROR cannot borrow - | - ---- ^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/codemap_tests/one_line.stderr b/src/test/ui/codemap_tests/one_line.stderr index 2ea793c096942..eddbd29c0ef81 100644 --- a/src/test/ui/codemap_tests/one_line.stderr +++ b/src/test/ui/codemap_tests/one_line.stderr @@ -1,10 +1,10 @@ error[E0499]: cannot borrow `v` as mutable more than once at a time --> $DIR/one_line.rs:3:12 | -LL | v.push(v.pop().unwrap()); //~ ERROR cannot borrow - | - ^ - first borrow ends here - | | | - | | second mutable borrow occurs here +LL | v.push(v.pop().unwrap()); + | - ---- ^ second mutable borrow occurs here + | | | + | | first borrow later used by call | first mutable borrow occurs here error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr index 1b20b699d9f8d..70c1093e9ed48 100644 --- a/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr +++ b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr @@ -1,7 +1,7 @@ error[E0592]: duplicate definitions with name `id` --> $DIR/overlapping_inherent_impls.rs:9:5 | -LL | fn id() {} //~ ERROR duplicate definitions +LL | fn id() {} | ^^^^^^^^^^ duplicate definitions for `id` ... LL | fn id() {} @@ -10,7 +10,7 @@ LL | fn id() {} error[E0592]: duplicate definitions with name `bar` --> $DIR/overlapping_inherent_impls.rs:19:5 | -LL | fn bar(&self) {} //~ ERROR duplicate definitions +LL | fn bar(&self) {} | ^^^^^^^^^^^^^^^^ duplicate definitions for `bar` ... LL | fn bar(&self) {} @@ -19,7 +19,7 @@ LL | fn bar(&self) {} error[E0592]: duplicate definitions with name `baz` --> $DIR/overlapping_inherent_impls.rs:29:5 | -LL | fn baz(&self) {} //~ ERROR duplicate definitions +LL | fn baz(&self) {} | ^^^^^^^^^^^^^^^^ duplicate definitions for `baz` ... LL | fn baz(&self) {} diff --git a/src/test/ui/codemap_tests/tab.stderr b/src/test/ui/codemap_tests/tab.stderr index 80b5773fda33a..7b3f959c1cb38 100644 --- a/src/test/ui/codemap_tests/tab.stderr +++ b/src/test/ui/codemap_tests/tab.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `bar` in this scope --> $DIR/tab.rs:4:2 | -LL | bar; //~ ERROR cannot find value `bar` +LL | bar; | ^^^ not found in this scope error[E0308]: mismatched types @@ -9,7 +9,7 @@ error[E0308]: mismatched types | LL | fn foo() { | - help: try adding a return type: `-> &'static str` -LL | "bar boo" //~ ERROR mismatched types +LL | "bar boo" | ^^^^^^^^^^^^^^^^^^^^ expected (), found reference | = note: expected type `()` @@ -17,5 +17,5 @@ LL | "bar boo" //~ ERROR mismatched types error: aborting due to 2 previous errors -Some errors occurred: E0308, E0425. +Some errors have detailed explanations: E0308, E0425. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/codemap_tests/tab_2.stderr b/src/test/ui/codemap_tests/tab_2.stderr index f7eec3eb8da8e..70414bbd953d6 100644 --- a/src/test/ui/codemap_tests/tab_2.stderr +++ b/src/test/ui/codemap_tests/tab_2.stderr @@ -1,7 +1,7 @@ error: unterminated double quote string --> $DIR/tab_2.rs:4:7 | -LL | """; //~ ERROR unterminated double quote +LL | """; | ___________________^ LL | | } | |__^ diff --git a/src/test/ui/codemap_tests/tab_3.nll.stderr b/src/test/ui/codemap_tests/tab_3.nll.stderr deleted file mode 100644 index 3b8507a067ded..0000000000000 --- a/src/test/ui/codemap_tests/tab_3.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0382]: borrow of moved value: `some_vec` - --> $DIR/tab_3.rs:7:20 - | -LL | let some_vec = vec!["hi"]; - | -------- move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait -LL | some_vec.into_iter(); - | -------- value moved here -LL | { -LL | println!("{:?}", some_vec); //~ ERROR use of moved - | ^^^^^^^^ value borrowed here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/codemap_tests/tab_3.rs b/src/test/ui/codemap_tests/tab_3.rs index 4fd5b70f7ae37..58b034d0fcf18 100644 --- a/src/test/ui/codemap_tests/tab_3.rs +++ b/src/test/ui/codemap_tests/tab_3.rs @@ -4,6 +4,6 @@ fn main() { let some_vec = vec!["hi"]; some_vec.into_iter(); { - println!("{:?}", some_vec); //~ ERROR use of moved + println!("{:?}", some_vec); //~ ERROR borrow of moved } } diff --git a/src/test/ui/codemap_tests/tab_3.stderr b/src/test/ui/codemap_tests/tab_3.stderr index 6e93ae1306961..97816a76004d0 100644 --- a/src/test/ui/codemap_tests/tab_3.stderr +++ b/src/test/ui/codemap_tests/tab_3.stderr @@ -1,13 +1,13 @@ -error[E0382]: use of moved value: `some_vec` +error[E0382]: borrow of moved value: `some_vec` --> $DIR/tab_3.rs:7:20 | +LL | let some_vec = vec!["hi"]; + | -------- move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait LL | some_vec.into_iter(); | -------- value moved here LL | { -LL | println!("{:?}", some_vec); //~ ERROR use of moved - | ^^^^^^^^ value used here after move - | - = note: move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait +LL | println!("{:?}", some_vec); + | ^^^^^^^^ value borrowed here after move error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr index 65df3f382c047..5027b78b38e34 100644 --- a/src/test/ui/codemap_tests/two_files.stderr +++ b/src/test/ui/codemap_tests/two_files.stderr @@ -1,7 +1,7 @@ error[E0404]: expected trait, found type alias `Bar` --> $DIR/two_files.rs:5:6 | -LL | impl Bar for Baz { } //~ ERROR expected trait, found type alias +LL | impl Bar for Baz { } | ^^^ type aliases cannot be used as traits | = note: did you mean to use a trait alias? diff --git a/src/test/ui/codemap_tests/two_files_data.rs b/src/test/ui/codemap_tests/two_files_data.rs index db8ab14e67371..b4d2f5d3c6d09 100644 --- a/src/test/ui/codemap_tests/two_files_data.rs +++ b/src/test/ui/codemap_tests/two_files_data.rs @@ -2,4 +2,4 @@ trait Foo { } -type Bar = Foo; +type Bar = dyn Foo; diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index 1ba6ac447889b..1ba578b0c04d3 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -1,11 +1,10 @@ error[E0703]: invalid ABI: found `路濫狼á́́` --> $DIR/unicode.rs:1:8 | -LL | extern "路濫狼á́́" fn foo() {} //~ ERROR invalid ABI +LL | extern "路濫狼á́́" fn foo() {} | ^^^^^^^^^ invalid ABI | = help: valid ABIs: cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted error: aborting due to previous error -For more information about this error, try `rustc --explain E0703`. diff --git a/src/test/ui/codemap_tests/unicode_2.stderr b/src/test/ui/codemap_tests/unicode_2.stderr index 1bc7452b9f2db..92634d8e5f94c 100644 --- a/src/test/ui/codemap_tests/unicode_2.stderr +++ b/src/test/ui/codemap_tests/unicode_2.stderr @@ -1,7 +1,7 @@ error: invalid width `7` for integer literal --> $DIR/unicode_2.rs:4:25 | -LL | let _ = ("a̐éö̲", 0u7); //~ ERROR invalid width +LL | let _ = ("a̐éö̲", 0u7); | ^^^ | = help: valid widths are 8, 16, 32, 64 and 128 @@ -9,7 +9,7 @@ LL | let _ = ("a̐éö̲", 0u7); //~ ERROR invalid width error: invalid width `42` for integer literal --> $DIR/unicode_2.rs:5:20 | -LL | let _ = ("아あ", 1i42); //~ ERROR invalid width +LL | let _ = ("아あ", 1i42); | ^^^^ | = help: valid widths are 8, 16, 32, 64 and 128 @@ -17,7 +17,7 @@ LL | let _ = ("아あ", 1i42); //~ ERROR invalid width error[E0425]: cannot find value `a̐é` in this scope --> $DIR/unicode_2.rs:6:13 | -LL | let _ = a̐é; //~ ERROR cannot find +LL | let _ = a̐é; | ^^ not found in this scope error: aborting due to 3 previous errors diff --git a/src/test/ui/coercion/coerce-expect-unsized-ascribed.rs b/src/test/ui/coercion/coerce-expect-unsized-ascribed.rs index 9a4e134cb39a4..c139e823c2aef 100644 --- a/src/test/ui/coercion/coerce-expect-unsized-ascribed.rs +++ b/src/test/ui/coercion/coerce-expect-unsized-ascribed.rs @@ -10,23 +10,23 @@ pub fn main() { let _ = box if true { [1, 2, 3] } else { [1, 3, 4] }: Box<[i32]>; //~ ERROR mismatched types let _ = box match true { true => [1, 2, 3], false => [1, 3, 4] }: Box<[i32]>; //~^ ERROR mismatched types - let _ = box { |x| (x as u8) }: Box _>; //~ ERROR mismatched types - let _ = box if true { false } else { true }: Box; //~ ERROR mismatched types - let _ = box match true { true => 'a', false => 'b' }: Box; //~ ERROR mismatched types + let _ = box { |x| (x as u8) }: Box _>; //~ ERROR mismatched types + let _ = box if true { false } else { true }: Box; //~ ERROR mismatched types + let _ = box match true { true => 'a', false => 'b' }: Box; //~ ERROR mismatched types let _ = &{ [1, 2, 3] }: &[i32]; //~ ERROR mismatched types let _ = &if true { [1, 2, 3] } else { [1, 3, 4] }: &[i32]; //~ ERROR mismatched types let _ = &match true { true => [1, 2, 3], false => [1, 3, 4] }: &[i32]; //~^ ERROR mismatched types - let _ = &{ |x| (x as u8) }: &Fn(i32) -> _; //~ ERROR mismatched types - let _ = &if true { false } else { true }: &Debug; //~ ERROR mismatched types - let _ = &match true { true => 'a', false => 'b' }: &Debug; //~ ERROR mismatched types + let _ = &{ |x| (x as u8) }: &dyn Fn(i32) -> _; //~ ERROR mismatched types + let _ = &if true { false } else { true }: &dyn Debug; //~ ERROR mismatched types + let _ = &match true { true => 'a', false => 'b' }: &dyn Debug; //~ ERROR mismatched types let _ = Box::new([1, 2, 3]): Box<[i32]>; //~ ERROR mismatched types - let _ = Box::new(|x| (x as u8)): Box _>; //~ ERROR mismatched types + let _ = Box::new(|x| (x as u8)): Box _>; //~ ERROR mismatched types let _ = vec![ Box::new(|x| (x as u8)), box |x| (x as i16 as u8), - ]: Vec _>>; + ]: Vec _>>; } diff --git a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr index 5ad3889666b79..3b81610a06e09 100644 --- a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr +++ b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:9:13 | -LL | let _ = box { [1, 2, 3] }: Box<[i32]>; //~ ERROR mismatched types +LL | let _ = box { [1, 2, 3] }: Box<[i32]>; | ^^^^^^^^^^^^^^^^^ expected slice, found array of 3 elements | = note: expected type `std::boxed::Box<[i32]>` @@ -10,7 +10,7 @@ LL | let _ = box { [1, 2, 3] }: Box<[i32]>; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:10:13 | -LL | let _ = box if true { [1, 2, 3] } else { [1, 3, 4] }: Box<[i32]>; //~ ERROR mismatched types +LL | let _ = box if true { [1, 2, 3] } else { [1, 3, 4] }: Box<[i32]>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice, found array of 3 elements | = note: expected type `std::boxed::Box<[i32]>` @@ -28,7 +28,7 @@ LL | let _ = box match true { true => [1, 2, 3], false => [1, 3, 4] }: Box<[ error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:13:13 | -LL | let _ = box { |x| (x as u8) }: Box _>; //~ ERROR mismatched types +LL | let _ = box { |x| (x as u8) }: Box _>; | ^^^^^^^^^^^^^^^^^^^^^ expected trait std::ops::Fn, found closure | = note: expected type `std::boxed::Box u8>` @@ -37,7 +37,7 @@ LL | let _ = box { |x| (x as u8) }: Box _>; //~ ERROR mismatched error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:14:13 | -LL | let _ = box if true { false } else { true }: Box; //~ ERROR mismatched types +LL | let _ = box if true { false } else { true }: Box; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait std::fmt::Debug, found bool | = note: expected type `std::boxed::Box` @@ -46,7 +46,7 @@ LL | let _ = box if true { false } else { true }: Box; //~ ERROR mism error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:15:13 | -LL | let _ = box match true { true => 'a', false => 'b' }: Box; //~ ERROR mismatched types +LL | let _ = box match true { true => 'a', false => 'b' }: Box; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait std::fmt::Debug, found char | = note: expected type `std::boxed::Box` @@ -55,7 +55,7 @@ LL | let _ = box match true { true => 'a', false => 'b' }: Box; //~ E error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:17:13 | -LL | let _ = &{ [1, 2, 3] }: &[i32]; //~ ERROR mismatched types +LL | let _ = &{ [1, 2, 3] }: &[i32]; | ^^^^^^^^^^^^^^ expected slice, found array of 3 elements | = note: expected type `&[i32]` @@ -64,7 +64,7 @@ LL | let _ = &{ [1, 2, 3] }: &[i32]; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:18:13 | -LL | let _ = &if true { [1, 2, 3] } else { [1, 3, 4] }: &[i32]; //~ ERROR mismatched types +LL | let _ = &if true { [1, 2, 3] } else { [1, 3, 4] }: &[i32]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice, found array of 3 elements | = note: expected type `&[i32]` @@ -82,7 +82,7 @@ LL | let _ = &match true { true => [1, 2, 3], false => [1, 3, 4] }: &[i32]; error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:21:13 | -LL | let _ = &{ |x| (x as u8) }: &Fn(i32) -> _; //~ ERROR mismatched types +LL | let _ = &{ |x| (x as u8) }: &dyn Fn(i32) -> _; | ^^^^^^^^^^^^^^^^^^ expected trait std::ops::Fn, found closure | = note: expected type `&dyn std::ops::Fn(i32) -> u8` @@ -91,7 +91,7 @@ LL | let _ = &{ |x| (x as u8) }: &Fn(i32) -> _; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:22:13 | -LL | let _ = &if true { false } else { true }: &Debug; //~ ERROR mismatched types +LL | let _ = &if true { false } else { true }: &dyn Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait std::fmt::Debug, found bool | = note: expected type `&dyn std::fmt::Debug` @@ -100,7 +100,7 @@ LL | let _ = &if true { false } else { true }: &Debug; //~ ERROR mismatched error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:23:13 | -LL | let _ = &match true { true => 'a', false => 'b' }: &Debug; //~ ERROR mismatched types +LL | let _ = &match true { true => 'a', false => 'b' }: &dyn Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait std::fmt::Debug, found char | = note: expected type `&dyn std::fmt::Debug` @@ -109,7 +109,7 @@ LL | let _ = &match true { true => 'a', false => 'b' }: &Debug; //~ ERROR mi error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:25:13 | -LL | let _ = Box::new([1, 2, 3]): Box<[i32]>; //~ ERROR mismatched types +LL | let _ = Box::new([1, 2, 3]): Box<[i32]>; | ^^^^^^^^^^^^^^^^^^^ expected slice, found array of 3 elements | = note: expected type `std::boxed::Box<[i32]>` @@ -118,7 +118,7 @@ LL | let _ = Box::new([1, 2, 3]): Box<[i32]>; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:26:13 | -LL | let _ = Box::new(|x| (x as u8)): Box _>; //~ ERROR mismatched types +LL | let _ = Box::new(|x| (x as u8)): Box _>; | ^^^^^^^^^^^^^^^^^^^^^^^ expected trait std::ops::Fn, found closure | = note: expected type `std::boxed::Box _>` diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef.ast.nll.stderr b/src/test/ui/coercion/coerce-overloaded-autoderef.ast.nll.stderr deleted file mode 100644 index 5b9249cffaea4..0000000000000 --- a/src/test/ui/coercion/coerce-overloaded-autoderef.ast.nll.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/coerce-overloaded-autoderef.rs:12:24 - | -LL | let y = borrow_mut(x); - | - first mutable borrow occurs here -LL | let z = borrow_mut(x); - | ^ second mutable borrow occurs here -... -LL | drop((y, z)); - | - first borrow later used here - -error[E0506]: cannot assign to `**x` because it is borrowed - --> $DIR/coerce-overloaded-autoderef.rs:21:5 - | -LL | let y = borrow(x); - | - borrow of `**x` occurs here -LL | let z = borrow(x); -LL | **x += 1; - | ^^^^^^^^ assignment to borrowed `**x` occurs here -... -LL | drop((y, z)); - | - borrow later used here - -error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/coerce-overloaded-autoderef.rs:28:20 - | -LL | borrow_mut2(x, x); - | ----------- - ^ second mutable borrow occurs here - | | | - | | first mutable borrow occurs here - | first borrow later used by call - -error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable - --> $DIR/coerce-overloaded-autoderef.rs:34:5 - | -LL | borrow2(x, x); - | -------^^^^-^ - | | | - | | immutable borrow occurs here - | mutable borrow occurs here - | immutable borrow later used by call - -error: aborting due to 4 previous errors - -Some errors occurred: E0499, E0502, E0506. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef.ast.stderr b/src/test/ui/coercion/coerce-overloaded-autoderef.ast.stderr deleted file mode 100644 index 54215f56bca7a..0000000000000 --- a/src/test/ui/coercion/coerce-overloaded-autoderef.ast.stderr +++ /dev/null @@ -1,42 +0,0 @@ -error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/coerce-overloaded-autoderef.rs:12:24 - | -LL | let y = borrow_mut(x); - | - first mutable borrow occurs here -LL | let z = borrow_mut(x); - | ^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0506]: cannot assign to `**x` because it is borrowed - --> $DIR/coerce-overloaded-autoderef.rs:21:5 - | -LL | let y = borrow(x); - | - borrow of `**x` occurs here -LL | let z = borrow(x); -LL | **x += 1; - | ^^^^^^^^ assignment to borrowed `**x` occurs here - -error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/coerce-overloaded-autoderef.rs:28:20 - | -LL | borrow_mut2(x, x); - | - ^- first borrow ends here - | | | - | | second mutable borrow occurs here - | first mutable borrow occurs here - -error[E0502]: cannot borrow `*x` as immutable because it is also borrowed as mutable - --> $DIR/coerce-overloaded-autoderef.rs:34:16 - | -LL | borrow2(x, x); - | - ^- mutable borrow ends here - | | | - | | immutable borrow occurs here - | mutable borrow occurs here - -error: aborting due to 4 previous errors - -Some errors occurred: E0499, E0502, E0506. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef.mir.nll.stderr b/src/test/ui/coercion/coerce-overloaded-autoderef.mir.nll.stderr deleted file mode 100644 index 5b9249cffaea4..0000000000000 --- a/src/test/ui/coercion/coerce-overloaded-autoderef.mir.nll.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/coerce-overloaded-autoderef.rs:12:24 - | -LL | let y = borrow_mut(x); - | - first mutable borrow occurs here -LL | let z = borrow_mut(x); - | ^ second mutable borrow occurs here -... -LL | drop((y, z)); - | - first borrow later used here - -error[E0506]: cannot assign to `**x` because it is borrowed - --> $DIR/coerce-overloaded-autoderef.rs:21:5 - | -LL | let y = borrow(x); - | - borrow of `**x` occurs here -LL | let z = borrow(x); -LL | **x += 1; - | ^^^^^^^^ assignment to borrowed `**x` occurs here -... -LL | drop((y, z)); - | - borrow later used here - -error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/coerce-overloaded-autoderef.rs:28:20 - | -LL | borrow_mut2(x, x); - | ----------- - ^ second mutable borrow occurs here - | | | - | | first mutable borrow occurs here - | first borrow later used by call - -error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable - --> $DIR/coerce-overloaded-autoderef.rs:34:5 - | -LL | borrow2(x, x); - | -------^^^^-^ - | | | - | | immutable borrow occurs here - | mutable borrow occurs here - | immutable borrow later used by call - -error: aborting due to 4 previous errors - -Some errors occurred: E0499, E0502, E0506. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef.mir.stderr b/src/test/ui/coercion/coerce-overloaded-autoderef.mir.stderr deleted file mode 100644 index 8dc6fe50afb5f..0000000000000 --- a/src/test/ui/coercion/coerce-overloaded-autoderef.mir.stderr +++ /dev/null @@ -1,45 +0,0 @@ -error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/coerce-overloaded-autoderef.rs:12:24 - | -LL | let y = borrow_mut(x); - | - first mutable borrow occurs here -LL | let z = borrow_mut(x); - | ^ second mutable borrow occurs here -... -LL | drop((y, z)); - | - first borrow later used here - -error[E0506]: cannot assign to `**x` because it is borrowed - --> $DIR/coerce-overloaded-autoderef.rs:21:5 - | -LL | let y = borrow(x); - | - borrow of `**x` occurs here -LL | let z = borrow(x); -LL | **x += 1; - | ^^^^^^^^ assignment to borrowed `**x` occurs here -... -LL | drop((y, z)); - | - borrow later used here - -error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/coerce-overloaded-autoderef.rs:28:20 - | -LL | borrow_mut2(x, x); - | ----------- - ^ second mutable borrow occurs here - | | | - | | first mutable borrow occurs here - | first borrow later used by call - -error[E0502]: cannot borrow `*x` as immutable because it is also borrowed as mutable - --> $DIR/coerce-overloaded-autoderef.rs:34:16 - | -LL | borrow2(x, x); - | ------- - ^ immutable borrow occurs here - | | | - | | mutable borrow occurs here - | mutable borrow later used by call - -error: aborting due to 4 previous errors - -Some errors occurred: E0499, E0502, E0506. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef.rs b/src/test/ui/coercion/coerce-overloaded-autoderef.rs index ec72745cd71ed..01d9c1e486a42 100644 --- a/src/test/ui/coercion/coerce-overloaded-autoderef.rs +++ b/src/test/ui/coercion/coerce-overloaded-autoderef.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - fn borrow_mut(x: &mut T) -> &mut T { x } fn borrow(x: &T) -> &T { x } @@ -10,8 +7,7 @@ fn borrow2(_: &mut T, _: &T) {} fn double_mut_borrow(x: &mut Box) { let y = borrow_mut(x); let z = borrow_mut(x); - //[ast]~^ ERROR cannot borrow `*x` as mutable more than once at a time - //[mir]~^^ ERROR cannot borrow `*x` as mutable more than once at a time + //~^ ERROR cannot borrow `*x` as mutable more than once at a time drop((y, z)); } @@ -19,21 +15,18 @@ fn double_imm_borrow(x: &mut Box) { let y = borrow(x); let z = borrow(x); **x += 1; - //[ast]~^ ERROR cannot assign to `**x` because it is borrowed - //[mir]~^^ ERROR cannot assign to `**x` because it is borrowed + //~^ ERROR cannot assign to `**x` because it is borrowed drop((y, z)); } fn double_mut_borrow2(x: &mut Box) { borrow_mut2(x, x); - //[ast]~^ ERROR cannot borrow `*x` as mutable more than once at a time - //[mir]~^^ ERROR cannot borrow `*x` as mutable more than once at a time + //~^ ERROR cannot borrow `*x` as mutable more than once at a time } fn double_borrow2(x: &mut Box) { borrow2(x, x); - //[ast]~^ ERROR cannot borrow `*x` as immutable because it is also borrowed as mutable - //[mir]~^^ ERROR cannot borrow `*x` as immutable because it is also borrowed as mutable + //~^ ERROR cannot borrow `*x` as mutable because it is also borrowed as immutable } pub fn main() {} diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef.stderr b/src/test/ui/coercion/coerce-overloaded-autoderef.stderr new file mode 100644 index 0000000000000..7cdfcb5f4fc63 --- /dev/null +++ b/src/test/ui/coercion/coerce-overloaded-autoderef.stderr @@ -0,0 +1,46 @@ +error[E0499]: cannot borrow `*x` as mutable more than once at a time + --> $DIR/coerce-overloaded-autoderef.rs:9:24 + | +LL | let y = borrow_mut(x); + | - first mutable borrow occurs here +LL | let z = borrow_mut(x); + | ^ second mutable borrow occurs here +LL | +LL | drop((y, z)); + | - first borrow later used here + +error[E0506]: cannot assign to `**x` because it is borrowed + --> $DIR/coerce-overloaded-autoderef.rs:17:5 + | +LL | let y = borrow(x); + | - borrow of `**x` occurs here +LL | let z = borrow(x); +LL | **x += 1; + | ^^^^^^^^ assignment to borrowed `**x` occurs here +LL | +LL | drop((y, z)); + | - borrow later used here + +error[E0499]: cannot borrow `*x` as mutable more than once at a time + --> $DIR/coerce-overloaded-autoderef.rs:23:20 + | +LL | borrow_mut2(x, x); + | ----------- - ^ second mutable borrow occurs here + | | | + | | first mutable borrow occurs here + | first borrow later used by call + +error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable + --> $DIR/coerce-overloaded-autoderef.rs:28:5 + | +LL | borrow2(x, x); + | -------^^^^-^ + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + | immutable borrow later used by call + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0499, E0502, E0506. +For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/coercion/coerce-to-bang-cast.stderr b/src/test/ui/coercion/coerce-to-bang-cast.stderr index 2982801f4613c..ff30ebc09c63a 100644 --- a/src/test/ui/coercion/coerce-to-bang-cast.stderr +++ b/src/test/ui/coercion/coerce-to-bang-cast.stderr @@ -9,7 +9,7 @@ LL | let y = {return; 22} as !; error[E0605]: non-primitive cast: `i32` as `!` --> $DIR/coerce-to-bang-cast.rs:11:13 | -LL | let y = 22 as !; //~ ERROR non-primitive cast +LL | let y = 22 as !; | ^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait diff --git a/src/test/ui/coercion/coerce-to-bang.stderr b/src/test/ui/coercion/coerce-to-bang.stderr index 72e7211de7a7f..a46e97da8159b 100644 --- a/src/test/ui/coercion/coerce-to-bang.stderr +++ b/src/test/ui/coercion/coerce-to-bang.stderr @@ -10,7 +10,7 @@ LL | foo(return, 22, 44); error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:18:13 | -LL | foo(22, 44, return); //~ ERROR mismatched types +LL | foo(22, 44, return); | ^^ expected !, found integer | = note: expected type `!` @@ -28,7 +28,7 @@ LL | foo(a, b, c); // ... and hence a reference to `a` is expected to diverg error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:36:12 | -LL | foo(a, b, c); //~ ERROR mismatched types +LL | foo(a, b, c); | ^ expected !, found integer | = note: expected type `!` @@ -37,7 +37,7 @@ LL | foo(a, b, c); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:45:12 | -LL | foo(a, b, c); //~ ERROR mismatched types +LL | foo(a, b, c); | ^ expected !, found integer | = note: expected type `!` @@ -46,7 +46,7 @@ LL | foo(a, b, c); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:50:21 | -LL | let x: [!; 2] = [return, 22]; //~ ERROR mismatched types +LL | let x: [!; 2] = [return, 22]; | ^^^^^^^^^^^^ expected !, found integer | = note: expected type `[!; 2]` @@ -55,7 +55,7 @@ LL | let x: [!; 2] = [return, 22]; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:55:22 | -LL | let x: [!; 2] = [22, return]; //~ ERROR mismatched types +LL | let x: [!; 2] = [22, return]; | ^^ expected !, found integer | = note: expected type `!` @@ -64,7 +64,7 @@ LL | let x: [!; 2] = [22, return]; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:60:37 | -LL | let x: (usize, !, usize) = (22, 44, 66); //~ ERROR mismatched types +LL | let x: (usize, !, usize) = (22, 44, 66); | ^^ expected !, found integer | = note: expected type `!` @@ -82,7 +82,7 @@ LL | let x: (usize, !, usize) = (return, 44, 66); error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:76:37 | -LL | let x: (usize, !, usize) = (22, 44, return); //~ ERROR mismatched types +LL | let x: (usize, !, usize) = (22, 44, return); | ^^ expected !, found integer | = note: expected type `!` diff --git a/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr index c8ec2f0545e6b..057de5b625e87 100644 --- a/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr +++ b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/coercion-missing-tail-expected-type.rs:3:24 | -LL | fn plus_one(x: i32) -> i32 { //~ ERROR mismatched types +LL | fn plus_one(x: i32) -> i32 { | -------- ^^^ expected i32, found () | | | this function's body doesn't return @@ -14,7 +14,7 @@ LL | x + 1; error[E0308]: mismatched types --> $DIR/coercion-missing-tail-expected-type.rs:7:13 | -LL | fn foo() -> Result { //~ ERROR mismatched types +LL | fn foo() -> Result { | --- ^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found () | | | this function's body doesn't return diff --git a/src/test/ui/coherence/auxiliary/re_rebalance_coherence_lib.rs b/src/test/ui/coherence/auxiliary/re_rebalance_coherence_lib.rs index c8d027b25c748..41b9d64d5f71e 100644 --- a/src/test/ui/coherence/auxiliary/re_rebalance_coherence_lib.rs +++ b/src/test/ui/coherence/auxiliary/re_rebalance_coherence_lib.rs @@ -1,5 +1,4 @@ - -pub trait Backend{} +pub trait Backend {} pub trait SupportsDefaultKeyword {} impl SupportsDefaultKeyword for Postgres {} diff --git a/src/test/ui/coherence/coherence-cross-crate-conflict.old.stderr b/src/test/ui/coherence/coherence-cross-crate-conflict.old.stderr index 3ba32a528354e..93be25702810f 100644 --- a/src/test/ui/coherence/coherence-cross-crate-conflict.old.stderr +++ b/src/test/ui/coherence/coherence-cross-crate-conflict.old.stderr @@ -17,5 +17,5 @@ LL | impl Foo for A { error: aborting due to 2 previous errors -Some errors occurred: E0119, E0210. +Some errors have detailed explanations: E0119, E0210. For more information about an error, try `rustc --explain E0119`. diff --git a/src/test/ui/coherence/coherence-cross-crate-conflict.re.stderr b/src/test/ui/coherence/coherence-cross-crate-conflict.re.stderr index 3ba32a528354e..93be25702810f 100644 --- a/src/test/ui/coherence/coherence-cross-crate-conflict.re.stderr +++ b/src/test/ui/coherence/coherence-cross-crate-conflict.re.stderr @@ -17,5 +17,5 @@ LL | impl Foo for A { error: aborting due to 2 previous errors -Some errors occurred: E0119, E0210. +Some errors have detailed explanations: E0119, E0210. For more information about an error, try `rustc --explain E0119`. diff --git a/src/test/ui/coherence/coherence-default-trait-impl.old.stderr b/src/test/ui/coherence/coherence-default-trait-impl.old.stderr index 534f4b0dcdb3c..3f644e3a6e7fa 100644 --- a/src/test/ui/coherence/coherence-default-trait-impl.old.stderr +++ b/src/test/ui/coherence/coherence-default-trait-impl.old.stderr @@ -12,5 +12,5 @@ LL | impl MyUnsafeTrait for Foo {} error: aborting due to 2 previous errors -Some errors occurred: E0199, E0200. +Some errors have detailed explanations: E0199, E0200. For more information about an error, try `rustc --explain E0199`. diff --git a/src/test/ui/coherence/coherence-default-trait-impl.re.stderr b/src/test/ui/coherence/coherence-default-trait-impl.re.stderr index 534f4b0dcdb3c..3f644e3a6e7fa 100644 --- a/src/test/ui/coherence/coherence-default-trait-impl.re.stderr +++ b/src/test/ui/coherence/coherence-default-trait-impl.re.stderr @@ -12,5 +12,5 @@ LL | impl MyUnsafeTrait for Foo {} error: aborting due to 2 previous errors -Some errors occurred: E0199, E0200. +Some errors have detailed explanations: E0199, E0200. For more information about an error, try `rustc --explain E0199`. diff --git a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr index c8a146cdd4456..edadb9b93d6d5 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr @@ -1,19 +1,19 @@ error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1` --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:14:1 | -LL | impl !Marker1 for dyn Object + Marker2 { } //~ ERROR E0371 +LL | impl !Marker1 for dyn Object + Marker2 { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2` --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:16:1 | -LL | impl !Marker2 for dyn Object + Marker2 { } //~ ERROR E0371 +LL | impl !Marker2 for dyn Object + Marker2 { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2` error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:22:1 | -LL | impl !Send for dyn Marker2 {} //~ ERROR E0117 +LL | impl !Send for dyn Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate | = note: the impl does not reference only types defined in this crate @@ -22,16 +22,16 @@ LL | impl !Send for dyn Marker2 {} //~ ERROR E0117 error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:26:1 | -LL | impl !Send for dyn Object {} //~ ERROR E0321 +LL | impl !Send for dyn Object {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:27:1 | -LL | impl !Send for dyn Object + Marker2 {} //~ ERROR E0321 +LL | impl !Send for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type error: aborting due to 5 previous errors -Some errors occurred: E0117, E0321, E0371. +Some errors have detailed explanations: E0117, E0321, E0371. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr index 78ca2f5279d63..322e7a5af29f9 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr @@ -1,19 +1,19 @@ error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1` --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:14:1 | -LL | impl Marker1 for dyn Object + Marker2 { } //~ ERROR E0371 +LL | impl Marker1 for dyn Object + Marker2 { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2` --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:16:1 | -LL | impl Marker2 for dyn Object + Marker2 { } //~ ERROR E0371 +LL | impl Marker2 for dyn Object + Marker2 { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2` error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:22:1 | -LL | unsafe impl Send for dyn Marker2 {} //~ ERROR E0117 +LL | unsafe impl Send for dyn Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate | = note: the impl does not reference only types defined in this crate @@ -22,16 +22,16 @@ LL | unsafe impl Send for dyn Marker2 {} //~ ERROR E0117 error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:26:1 | -LL | unsafe impl Send for dyn Object {} //~ ERROR E0321 +LL | unsafe impl Send for dyn Object {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:27:1 | -LL | unsafe impl Send for dyn Object + Marker2 {} //~ ERROR E0321 +LL | unsafe impl Send for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type error: aborting due to 5 previous errors -Some errors occurred: E0117, E0321, E0371. +Some errors have detailed explanations: E0117, E0321, E0371. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.old.stderr b/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.old.stderr index b48f6bbfb9417..c38d7456a9952 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.old.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.old.stderr @@ -1,7 +1,7 @@ error[E0038]: the trait `NotObjectSafe` cannot be made into an object --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:11:6 | -LL | impl NotObjectSafe for NotObjectSafe { } +LL | impl NotObjectSafe for dyn NotObjectSafe { } | ^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object | = note: method `eq` references the `Self` type in its arguments or return type diff --git a/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.re.stderr b/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.re.stderr index b48f6bbfb9417..c38d7456a9952 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.re.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.re.stderr @@ -1,7 +1,7 @@ error[E0038]: the trait `NotObjectSafe` cannot be made into an object --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:11:6 | -LL | impl NotObjectSafe for NotObjectSafe { } +LL | impl NotObjectSafe for dyn NotObjectSafe { } | ^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object | = note: method `eq` references the `Self` type in its arguments or return type diff --git a/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs b/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs index 803e8fc6bca64..b4c88e937830e 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs +++ b/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs @@ -8,7 +8,7 @@ // If the trait is not object-safe, we give a more tailored message // because we're such schnuckels: trait NotObjectSafe { fn eq(&self, other: Self); } -impl NotObjectSafe for NotObjectSafe { } +impl NotObjectSafe for dyn NotObjectSafe { } //[old]~^ ERROR E0038 //[re]~^^ ERROR E0038 diff --git a/src/test/ui/coherence/coherence-impl-trait-for-trait.old.stderr b/src/test/ui/coherence/coherence-impl-trait-for-trait.old.stderr index 324747603f911..4819ce9260e70 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-trait.old.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-trait.old.stderr @@ -1,20 +1,20 @@ error[E0371]: the object type `(dyn Baz + 'static)` automatically implements the trait `Foo` --> $DIR/coherence-impl-trait-for-trait.rs:13:1 | -LL | impl Foo for Baz { } - | ^^^^^^^^^^^^^^^^ `(dyn Baz + 'static)` automatically implements trait `Foo` +LL | impl Foo for dyn Baz { } + | ^^^^^^^^^^^^^^^^^^^^ `(dyn Baz + 'static)` automatically implements trait `Foo` error[E0371]: the object type `(dyn Baz + 'static)` automatically implements the trait `Bar` --> $DIR/coherence-impl-trait-for-trait.rs:16:1 | -LL | impl Bar for Baz { } - | ^^^^^^^^^^^^^^^^ `(dyn Baz + 'static)` automatically implements trait `Bar` +LL | impl Bar for dyn Baz { } + | ^^^^^^^^^^^^^^^^^^^^ `(dyn Baz + 'static)` automatically implements trait `Bar` error[E0371]: the object type `(dyn Baz + 'static)` automatically implements the trait `Baz` --> $DIR/coherence-impl-trait-for-trait.rs:19:1 | -LL | impl Baz for Baz { } - | ^^^^^^^^^^^^^^^^ `(dyn Baz + 'static)` automatically implements trait `Baz` +LL | impl Baz for dyn Baz { } + | ^^^^^^^^^^^^^^^^^^^^ `(dyn Baz + 'static)` automatically implements trait `Baz` error: aborting due to 3 previous errors diff --git a/src/test/ui/coherence/coherence-impl-trait-for-trait.re.stderr b/src/test/ui/coherence/coherence-impl-trait-for-trait.re.stderr index 324747603f911..4819ce9260e70 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-trait.re.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-trait.re.stderr @@ -1,20 +1,20 @@ error[E0371]: the object type `(dyn Baz + 'static)` automatically implements the trait `Foo` --> $DIR/coherence-impl-trait-for-trait.rs:13:1 | -LL | impl Foo for Baz { } - | ^^^^^^^^^^^^^^^^ `(dyn Baz + 'static)` automatically implements trait `Foo` +LL | impl Foo for dyn Baz { } + | ^^^^^^^^^^^^^^^^^^^^ `(dyn Baz + 'static)` automatically implements trait `Foo` error[E0371]: the object type `(dyn Baz + 'static)` automatically implements the trait `Bar` --> $DIR/coherence-impl-trait-for-trait.rs:16:1 | -LL | impl Bar for Baz { } - | ^^^^^^^^^^^^^^^^ `(dyn Baz + 'static)` automatically implements trait `Bar` +LL | impl Bar for dyn Baz { } + | ^^^^^^^^^^^^^^^^^^^^ `(dyn Baz + 'static)` automatically implements trait `Bar` error[E0371]: the object type `(dyn Baz + 'static)` automatically implements the trait `Baz` --> $DIR/coherence-impl-trait-for-trait.rs:19:1 | -LL | impl Baz for Baz { } - | ^^^^^^^^^^^^^^^^ `(dyn Baz + 'static)` automatically implements trait `Baz` +LL | impl Baz for dyn Baz { } + | ^^^^^^^^^^^^^^^^^^^^ `(dyn Baz + 'static)` automatically implements trait `Baz` error: aborting due to 3 previous errors diff --git a/src/test/ui/coherence/coherence-impl-trait-for-trait.rs b/src/test/ui/coherence/coherence-impl-trait-for-trait.rs index dcaf564fdecfe..3ce3dca0660b9 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-trait.rs +++ b/src/test/ui/coherence/coherence-impl-trait-for-trait.rs @@ -10,18 +10,18 @@ trait Bar: Foo { } trait Baz: Bar { } // Supertraits of Baz are not legal: -impl Foo for Baz { } +impl Foo for dyn Baz { } //[old]~^ ERROR E0371 //[re]~^^ ERROR E0371 -impl Bar for Baz { } +impl Bar for dyn Baz { } //[old]~^ ERROR E0371 //[re]~^^ ERROR E0371 -impl Baz for Baz { } +impl Baz for dyn Baz { } //[old]~^ ERROR E0371 //[re]~^^ ERROR E0371 // But other random traits are: trait Other { } -impl Other for Baz { } // OK, Other not a supertrait of Baz +impl Other for dyn Baz { } // OK, Other not a supertrait of Baz fn main() { } diff --git a/src/test/ui/coherence/coherence-impls-copy.old.stderr b/src/test/ui/coherence/coherence-impls-copy.old.stderr index e870c267ce141..5c95cc173f2b0 100644 --- a/src/test/ui/coherence/coherence-impls-copy.old.stderr +++ b/src/test/ui/coherence/coherence-impls-copy.old.stderr @@ -83,5 +83,5 @@ LL | impl Copy for &'static [NotSync] {} error: aborting due to 10 previous errors -Some errors occurred: E0117, E0119, E0206. +Some errors have detailed explanations: E0117, E0119, E0206. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/coherence-impls-copy.re.stderr b/src/test/ui/coherence/coherence-impls-copy.re.stderr index e870c267ce141..5c95cc173f2b0 100644 --- a/src/test/ui/coherence/coherence-impls-copy.re.stderr +++ b/src/test/ui/coherence/coherence-impls-copy.re.stderr @@ -83,5 +83,5 @@ LL | impl Copy for &'static [NotSync] {} error: aborting due to 10 previous errors -Some errors occurred: E0117, E0119, E0206. +Some errors have detailed explanations: E0117, E0119, E0206. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/coherence-impls-send.old.stderr b/src/test/ui/coherence/coherence-impls-send.old.stderr index 3ede8363d119e..b67f4d517b1b7 100644 --- a/src/test/ui/coherence/coherence-impls-send.old.stderr +++ b/src/test/ui/coherence/coherence-impls-send.old.stderr @@ -33,5 +33,5 @@ LL | unsafe impl Send for &'static [NotSync] {} error: aborting due to 4 previous errors -Some errors occurred: E0117, E0321. +Some errors have detailed explanations: E0117, E0321. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/coherence-impls-send.re.stderr b/src/test/ui/coherence/coherence-impls-send.re.stderr index 3ede8363d119e..b67f4d517b1b7 100644 --- a/src/test/ui/coherence/coherence-impls-send.re.stderr +++ b/src/test/ui/coherence/coherence-impls-send.re.stderr @@ -33,5 +33,5 @@ LL | unsafe impl Send for &'static [NotSync] {} error: aborting due to 4 previous errors -Some errors occurred: E0117, E0321. +Some errors have detailed explanations: E0117, E0321. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/coherence-impls-sized.old.stderr b/src/test/ui/coherence/coherence-impls-sized.old.stderr index 86a0996554d41..a19ecfdc3c5b5 100644 --- a/src/test/ui/coherence/coherence-impls-sized.old.stderr +++ b/src/test/ui/coherence/coherence-impls-sized.old.stderr @@ -63,5 +63,5 @@ LL | impl Sized for &'static [NotSync] {} error: aborting due to 9 previous errors -Some errors occurred: E0117, E0322. +Some errors have detailed explanations: E0117, E0322. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/coherence-impls-sized.re.stderr b/src/test/ui/coherence/coherence-impls-sized.re.stderr index 86a0996554d41..a19ecfdc3c5b5 100644 --- a/src/test/ui/coherence/coherence-impls-sized.re.stderr +++ b/src/test/ui/coherence/coherence-impls-sized.re.stderr @@ -63,5 +63,5 @@ LL | impl Sized for &'static [NotSync] {} error: aborting due to 9 previous errors -Some errors occurred: E0117, E0322. +Some errors have detailed explanations: E0117, E0322. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/coherence-projection-ok-orphan.rs b/src/test/ui/coherence/coherence-projection-ok-orphan.rs index 652b438feb137..b34c31dcddb3d 100644 --- a/src/test/ui/coherence/coherence-projection-ok-orphan.rs +++ b/src/test/ui/coherence/coherence-projection-ok-orphan.rs @@ -1,11 +1,10 @@ -// compile-pass -// skip-codegen +// Here we do not get a coherence conflict because `Baz: Iterator` +// does not hold and (due to the orphan rules), we can rely on that. + +// check-pass // revisions: old re #![cfg_attr(re, feature(re_rebalance_coherence))] -#![allow(dead_code)] -// Here we do not get a coherence conflict because `Baz: Iterator` -// does not hold and (due to the orphan rules), we can rely on that. pub trait Foo

    {} @@ -18,5 +17,4 @@ impl Foo for Baz { } impl Foo for A { } - fn main() {} diff --git a/src/test/ui/coherence/coherence-projection-ok.rs b/src/test/ui/coherence/coherence-projection-ok.rs index f759a9e1b4508..f4f5ca64de738 100644 --- a/src/test/ui/coherence/coherence-projection-ok.rs +++ b/src/test/ui/coherence/coherence-projection-ok.rs @@ -1,8 +1,8 @@ -// compile-pass -// skip-codegen +// check-pass // revisions: old re #![cfg_attr(re, feature(re_rebalance_coherence))] + pub trait Foo

    {} pub trait Bar { @@ -17,5 +17,4 @@ impl Bar for i32 { type Output = u32; } - fn main() {} diff --git a/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_ref.rs b/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_ref.rs index bd8317e224699..0d677800f7949 100644 --- a/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_ref.rs +++ b/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_ref.rs @@ -1,13 +1,11 @@ // Test that we are able to introduce a negative constraint that // `MyType: !MyTrait` along with other "fundamental" wrappers. +// check-pass // aux-build:coherence_copy_like_lib.rs -// compile-pass -// skip-codegen // revisions: old re #![cfg_attr(re, feature(re_rebalance_coherence))] -#![allow(dead_code)] extern crate coherence_copy_like_lib as lib; @@ -23,5 +21,4 @@ impl MyTrait for T { } // Huzzah. impl<'a> MyTrait for lib::MyFundamentalStruct<&'a MyType> { } - fn main() { } diff --git a/src/test/ui/coherence/coherence_local.rs b/src/test/ui/coherence/coherence_local.rs index cac45b0b9edff..3eab6e03ae3e2 100644 --- a/src/test/ui/coherence/coherence_local.rs +++ b/src/test/ui/coherence/coherence_local.rs @@ -1,13 +1,11 @@ // Test that we are able to introduce a negative constraint that // `MyType: !MyTrait` along with other "fundamental" wrappers. +// check-pass // aux-build:coherence_copy_like_lib.rs -// compile-pass -// skip-codegen // revisions: old re #![cfg_attr(re, feature(re_rebalance_coherence))] -#![allow(dead_code)] extern crate coherence_copy_like_lib as lib; @@ -22,5 +20,4 @@ impl lib::MyCopy for Box { } impl lib::MyCopy for lib::MyFundamentalStruct { } impl lib::MyCopy for lib::MyFundamentalStruct> { } - -fn main() { } +fn main() {} diff --git a/src/test/ui/coherence/coherence_local_ref.rs b/src/test/ui/coherence/coherence_local_ref.rs index a52510b8ea9ca..dff684c1699af 100644 --- a/src/test/ui/coherence/coherence_local_ref.rs +++ b/src/test/ui/coherence/coherence_local_ref.rs @@ -1,13 +1,11 @@ // Test that we are able to introduce a negative constraint that // `MyType: !MyTrait` along with other "fundamental" wrappers. +// check-pass // aux-build:coherence_copy_like_lib.rs -// compile-pass -// skip-codegen // revisions: old re #![cfg_attr(re, feature(re_rebalance_coherence))] -#![allow(dead_code)] extern crate coherence_copy_like_lib as lib; @@ -16,5 +14,4 @@ struct MyType { x: i32 } // naturally, legal impl lib::MyCopy for MyType { } - fn main() { } diff --git a/src/test/ui/command-line-diagnostics.nll.stderr b/src/test/ui/command-line-diagnostics.nll.stderr deleted file mode 100644 index b3f8d8a643fb5..0000000000000 --- a/src/test/ui/command-line-diagnostics.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/command-line-diagnostics.rs:6:5 - | -LL | let x = 42; - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | x = 43; - | ^^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/command-line-diagnostics.stderr b/src/test/ui/command-line-diagnostics.stderr index 6f1156e0d36d7..b3f8d8a643fb5 100644 --- a/src/test/ui/command-line-diagnostics.stderr +++ b/src/test/ui/command-line-diagnostics.stderr @@ -2,7 +2,10 @@ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/command-line-diagnostics.rs:6:5 | LL | let x = 42; - | - first assignment to `x` + | - + | | + | first assignment to `x` + | help: make this binding mutable: `mut x` LL | x = 43; | ^^^^^^ cannot assign twice to immutable variable diff --git a/src/test/ui/compare-method/proj-outlives-region.stderr b/src/test/ui/compare-method/proj-outlives-region.stderr index ba0b04dca9d24..e5f5c5ed20d55 100644 --- a/src/test/ui/compare-method/proj-outlives-region.stderr +++ b/src/test/ui/compare-method/proj-outlives-region.stderr @@ -4,7 +4,7 @@ error[E0276]: impl has stricter requirements than trait LL | fn foo() where T: 'a; | --------------------- definition of `foo` from trait ... -LL | fn foo() where U: 'a { } //~ ERROR E0276 +LL | fn foo() where U: 'a { } | ^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `U: 'a` error: aborting due to previous error diff --git a/src/test/ui/compare-method/region-extra.stderr b/src/test/ui/compare-method/region-extra.stderr index 48ca690f425eb..5a584c7d6ed9f 100644 --- a/src/test/ui/compare-method/region-extra.stderr +++ b/src/test/ui/compare-method/region-extra.stderr @@ -4,7 +4,7 @@ error[E0276]: impl has stricter requirements than trait LL | fn foo(); | --------- definition of `foo` from trait ... -LL | fn foo() where 'a: 'b { } //~ ERROR impl has stricter +LL | fn foo() where 'a: 'b { } | ^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'a: 'b` error: aborting due to previous error diff --git a/src/test/ui/compare-method/reordered-type-param.stderr b/src/test/ui/compare-method/reordered-type-param.stderr index c162c720a48b2..a33908c01c842 100644 --- a/src/test/ui/compare-method/reordered-type-param.stderr +++ b/src/test/ui/compare-method/reordered-type-param.stderr @@ -4,7 +4,7 @@ error[E0053]: method `b` has an incompatible type for trait LL | fn b(&self, x: C) -> C; | - type in trait ... -LL | fn b(&self, _x: G) -> G { panic!() } //~ ERROR method `b` has an incompatible type +LL | fn b(&self, _x: G) -> G { panic!() } | ^ expected type parameter, found a different type parameter | = note: expected type `fn(&E, F) -> F` diff --git a/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr b/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr index 07f5a0a6cec46..5d09038076f98 100644 --- a/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr +++ b/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr @@ -4,7 +4,7 @@ error[E0276]: impl has stricter requirements than trait LL | fn b(&self, x: C) -> C; | ---------------------------- definition of `b` from trait ... -LL | fn b(&self, _x: F) -> F { panic!() } //~ ERROR E0276 +LL | fn b(&self, _x: F) -> F { panic!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `F: std::marker::Sync` error: aborting due to previous error diff --git a/src/test/ui/compile_error_macro.stderr b/src/test/ui/compile_error_macro.stderr index 9e11db68315e9..8aa1878c5d7cd 100644 --- a/src/test/ui/compile_error_macro.stderr +++ b/src/test/ui/compile_error_macro.stderr @@ -1,7 +1,7 @@ error: a very descriptive error message --> $DIR/compile_error_macro.rs:2:5 | -LL | compile_error!("a very descriptive error message"); //~ ERROR: a very descriptive error message +LL | compile_error!("a very descriptive error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/concat.stderr b/src/test/ui/concat.stderr index b6024972c7448..61fb9de1ef96c 100644 --- a/src/test/ui/concat.stderr +++ b/src/test/ui/concat.stderr @@ -1,19 +1,19 @@ error: cannot concatenate a byte string literal --> $DIR/concat.rs:2:13 | -LL | concat!(b'f'); //~ ERROR: cannot concatenate a byte string literal +LL | concat!(b'f'); | ^^^^ error: cannot concatenate a byte string literal --> $DIR/concat.rs:3:13 | -LL | concat!(b"foo"); //~ ERROR: cannot concatenate a byte string literal +LL | concat!(b"foo"); | ^^^^^^ error: expected a literal --> $DIR/concat.rs:4:13 | -LL | concat!(foo); //~ ERROR: expected a literal +LL | concat!(foo); | ^^^ | = note: only literals (like `"foo"`, `42` and `3.14`) can be passed to `concat!()` @@ -21,7 +21,7 @@ LL | concat!(foo); //~ ERROR: expected a literal error: expected a literal --> $DIR/concat.rs:5:13 | -LL | concat!(foo()); //~ ERROR: expected a literal +LL | concat!(foo()); | ^^^^^ | = note: only literals (like `"foo"`, `42` and `3.14`) can be passed to `concat!()` diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-1.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.stderr new file mode 100644 index 0000000000000..1e7922a9ff155 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.stderr @@ -0,0 +1,2 @@ +error: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`) + diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-2.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-2.stderr new file mode 100644 index 0000000000000..b92e1fd3d97cf --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-2.stderr @@ -0,0 +1,2 @@ +error: invalid `--cfg` argument: `a{b}` (expected `key` or `key="value"`) + diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-3.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-3.stderr new file mode 100644 index 0000000000000..5412f7ffd5c9c --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-3.stderr @@ -0,0 +1,2 @@ +error: invalid `--cfg` argument: `a::b` (argument key must be an identifier) + diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-4.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-4.stderr new file mode 100644 index 0000000000000..6853a69b9eb22 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-4.stderr @@ -0,0 +1,2 @@ +error: invalid `--cfg` argument: `a(b)` (expected `key` or `key="value"`) + diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-5.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-5.stderr new file mode 100644 index 0000000000000..aafc4e8980cb5 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-5.stderr @@ -0,0 +1,2 @@ +error: invalid `--cfg` argument: `a=10` (argument value must be a string) + diff --git a/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr index 37c7a571d0f58..ec77789449aef 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr @@ -1,9 +1,10 @@ -error[E0658]: no_core is experimental (see issue #29639) +error[E0658]: no_core is experimental --> $DIR/cfg-attr-crate-2.rs:6:21 | -LL | #![cfg_attr(broken, no_core)] //~ ERROR no_core is experimental +LL | #![cfg_attr(broken, no_core)] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29639 = help: add #![feature(no_core)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.rs b/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.rs new file mode 100644 index 0000000000000..4c96d6e7ca17d --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.rs @@ -0,0 +1,13 @@ +// Check that `#[cfg_attr($PREDICATE,)]` triggers the `unused_attribute` lint. + +// compile-flags: --cfg TRUE + +#![deny(unused)] + +#[cfg_attr(FALSE,)] //~ ERROR unused attribute +fn _f() {} + +#[cfg_attr(TRUE,)] //~ ERROR unused attribute +fn _g() {} + +fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr b/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr new file mode 100644 index 0000000000000..cd3563e66c720 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr @@ -0,0 +1,21 @@ +error: unused attribute + --> $DIR/cfg-attr-empty-is-unused.rs:7:1 + | +LL | #[cfg_attr(FALSE,)] + | ^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/cfg-attr-empty-is-unused.rs:5:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: #[deny(unused_attributes)] implied by #[deny(unused)] + +error: unused attribute + --> $DIR/cfg-attr-empty-is-unused.rs:10:1 + | +LL | #[cfg_attr(TRUE,)] + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.stderr b/src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.stderr index d75a0389851a8..96c571ebebdb4 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.stderr @@ -1,7 +1,7 @@ error[E0537]: invalid predicate `foo` --> $DIR/cfg-attr-invalid-predicate.rs:1:7 | -LL | #[cfg(foo(bar))] //~ ERROR invalid predicate `foo` +LL | #[cfg(foo(bar))] | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr index 8cdf4ec31e7fc..ad5177dc9c0e8 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr @@ -1,9 +1,10 @@ -error[E0658]: no_core is experimental (see issue #29639) +error[E0658]: no_core is experimental --> $DIR/cfg-attr-multi-invalid-1.rs:4:21 | -LL | #![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental +LL | #![cfg_attr(broken, no_core, no_std)] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29639 = help: add #![feature(no_core)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr index b3a3b0c0f97bd..675997758e6a5 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr @@ -1,9 +1,10 @@ -error[E0658]: no_core is experimental (see issue #29639) +error[E0658]: no_core is experimental --> $DIR/cfg-attr-multi-invalid-2.rs:4:29 | -LL | #![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental +LL | #![cfg_attr(broken, no_std, no_core)] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29639 = help: add #![feature(no_core)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr index 3d14c19739798..64e9570773a65 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr @@ -1,7 +1,7 @@ warning: use of deprecated item 'MustUseDeprecated' --> $DIR/cfg-attr-multi-true.rs:12:6 | -LL | impl MustUseDeprecated { //~ warning: use of deprecated item +LL | impl MustUseDeprecated { | ^^^^^^^^^^^^^^^^^ | = note: #[warn(deprecated)] on by default @@ -9,25 +9,25 @@ LL | impl MustUseDeprecated { //~ warning: use of deprecated item warning: use of deprecated item 'MustUseDeprecated' --> $DIR/cfg-attr-multi-true.rs:19:5 | -LL | MustUseDeprecated::new(); //~ warning: use of deprecated item +LL | MustUseDeprecated::new(); | ^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'MustUseDeprecated' --> $DIR/cfg-attr-multi-true.rs:13:17 | -LL | fn new() -> MustUseDeprecated { //~ warning: use of deprecated item +LL | fn new() -> MustUseDeprecated { | ^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'MustUseDeprecated' --> $DIR/cfg-attr-multi-true.rs:14:9 | -LL | MustUseDeprecated {} //~ warning: use of deprecated item +LL | MustUseDeprecated {} | ^^^^^^^^^^^^^^^^^ warning: unused `MustUseDeprecated` that must be used --> $DIR/cfg-attr-multi-true.rs:19:5 | -LL | MustUseDeprecated::new(); //~ warning: use of deprecated item +LL | MustUseDeprecated::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.stderr b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr index 36c7c817cb33d..3dfbd6df256eb 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-parse.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr @@ -1,31 +1,31 @@ error: expected identifier, found `)` --> $DIR/cfg-attr-parse.rs:4:12 | -LL | #[cfg_attr()] //~ error: expected identifier, found `)` +LL | #[cfg_attr()] | ^ expected identifier error: expected `,`, found `)` --> $DIR/cfg-attr-parse.rs:8:17 | -LL | #[cfg_attr(all())] //~ error: expected `,`, found `)` +LL | #[cfg_attr(all())] | ^ expected `,` error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:16:18 | -LL | #[cfg_attr(all(),,)] //~ ERROR expected identifier +LL | #[cfg_attr(all(),,)] | ^ expected identifier error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:28:28 | -LL | #[cfg_attr(all(), must_use,,)] //~ ERROR expected identifier +LL | #[cfg_attr(all(), must_use,,)] | ^ expected identifier error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:40:40 | -LL | #[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier +LL | #[cfg_attr(all(), must_use, deprecated,,)] | ^ expected identifier error: aborting due to 5 previous errors diff --git a/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs index c5aa903f9491f..7f0648b381dbd 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -28,7 +28,7 @@ struct S9; macro_rules! generate_s10 { ($expr: expr) => { #[cfg(feature = $expr)] - //~^ ERROR expected unsuffixed literal or identifier, found concat!("nonexistent") + //~^ ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")` struct S10; } } diff --git a/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index bcf13ead2f4f7..5bfe9e902dae8 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -1,67 +1,67 @@ error: `cfg` is not followed by parentheses --> $DIR/cfg-attr-syntax-validation.rs:1:1 | -LL | #[cfg] //~ ERROR `cfg` is not followed by parentheses +LL | #[cfg] | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)` error: `cfg` is not followed by parentheses --> $DIR/cfg-attr-syntax-validation.rs:4:1 | -LL | #[cfg = 10] //~ ERROR `cfg` is not followed by parentheses +LL | #[cfg = 10] | ^^^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` error: `cfg` predicate is not specified --> $DIR/cfg-attr-syntax-validation.rs:7:1 | -LL | #[cfg()] //~ ERROR `cfg` predicate is not specified +LL | #[cfg()] | ^^^^^^^^ error: multiple `cfg` predicates are specified --> $DIR/cfg-attr-syntax-validation.rs:10:10 | -LL | #[cfg(a, b)] //~ ERROR multiple `cfg` predicates are specified +LL | #[cfg(a, b)] | ^ error: `cfg` predicate key cannot be a literal --> $DIR/cfg-attr-syntax-validation.rs:13:7 | -LL | #[cfg("str")] //~ ERROR `cfg` predicate key cannot be a literal +LL | #[cfg("str")] | ^^^^^ error: `cfg` predicate key must be an identifier --> $DIR/cfg-attr-syntax-validation.rs:16:7 | -LL | #[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier +LL | #[cfg(a::b)] | ^^^^ error[E0537]: invalid predicate `a` --> $DIR/cfg-attr-syntax-validation.rs:19:7 | -LL | #[cfg(a())] //~ ERROR invalid predicate `a` +LL | #[cfg(a())] | ^^^ error[E0565]: literal in `cfg` predicate value must be a string --> $DIR/cfg-attr-syntax-validation.rs:22:11 | -LL | #[cfg(a = 10)] //~ ERROR literal in `cfg` predicate value must be a string +LL | #[cfg(a = 10)] | ^^ error[E0565]: literal in `cfg` predicate value must be a string --> $DIR/cfg-attr-syntax-validation.rs:25:11 | -LL | #[cfg(a = b"hi")] //~ ERROR literal in `cfg` predicate value must be a string +LL | #[cfg(a = b"hi")] | ^^^^^ help: consider removing the prefix: `"hi"` -error: expected unsuffixed literal or identifier, found concat!("nonexistent") - --> $DIR/cfg-attr-syntax-validation.rs:30:15 +error: expected unsuffixed literal or identifier, found `concat!("nonexistent")` + --> $DIR/cfg-attr-syntax-validation.rs:30:25 | LL | #[cfg(feature = $expr)] - | ^^^^^^^ + | ^^^^^ ... LL | generate_s10!(concat!("nonexistent")); | -------------------------------------- in this macro invocation error: aborting due to 10 previous errors -Some errors occurred: E0537, E0565. +Some errors have detailed explanations: E0537, E0565. For more information about an error, try `rustc --explain E0537`. diff --git a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr index c5097c15c3c81..ca3e3d9eff16d 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr @@ -1,12 +1,13 @@ -error[E0658]: The attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:3:27 | -LL | #[cfg_attr(all(), unknown)] //~ ERROR `unknown` is currently unknown +LL | #[cfg_attr(all(), unknown)] | ^^^^^^^ ... LL | foo!(); | ------- in this macro invocation | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/conditional-compilation/cfg-empty-codemap.stderr b/src/test/ui/conditional-compilation/cfg-empty-codemap.stderr new file mode 100644 index 0000000000000..128e3cd730680 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-empty-codemap.stderr @@ -0,0 +1,2 @@ +error: invalid `--cfg` argument: `""` (expected `key` or `key="value"`) + diff --git a/src/test/ui/conditional-compilation/cfg-generic-params.rs b/src/test/ui/conditional-compilation/cfg-generic-params.rs new file mode 100644 index 0000000000000..d80d3ea7b7fe9 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-generic-params.rs @@ -0,0 +1,38 @@ +// compile-flags:--cfg yes + +fn f_lt<#[cfg(yes)] 'a: 'a, #[cfg(no)] T>() {} +fn f_ty<#[cfg(no)] 'a: 'a, #[cfg(yes)] T>() {} + +type FnGood = for<#[cfg(yes)] 'a, #[cfg(no)] T> fn(); // OK +type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn(); +//~^ ERROR only lifetime parameters can be used in this context + +type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(no)] T> Copy; // OK +type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy; +//~^ ERROR only lifetime parameters can be used in this context + +struct WhereGood where for<#[cfg(yes)] 'a, #[cfg(no)] T> u8: Copy; // OK +struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy; +//~^ ERROR only lifetime parameters can be used in this context + +fn f_lt_no<#[cfg_attr(no, unknown)] 'a>() {} // OK +fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} //~ ERROR attribute `unknown` is currently unknown +fn f_ty_no<#[cfg_attr(no, unknown)] T>() {} // OK +fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} //~ ERROR attribute `unknown` is currently unknown + +type FnNo = for<#[cfg_attr(no, unknown)] 'a> fn(); // OK +type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn(); +//~^ ERROR attribute `unknown` is currently unknown + +type PolyNo = dyn for<#[cfg_attr(no, unknown)] 'a> Copy; // OK +type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; +//~^ ERROR attribute `unknown` is currently unknown + +struct WhereNo where for<#[cfg_attr(no, unknown)] 'a> u8: Copy; // OK +struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; +//~^ ERROR attribute `unknown` is currently unknown + +fn main() { + f_lt::<'static>(); + f_ty::(); +} diff --git a/src/test/ui/conditional-compilation/cfg-generic-params.stderr b/src/test/ui/conditional-compilation/cfg-generic-params.stderr new file mode 100644 index 0000000000000..40ca44d9db59c --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-generic-params.stderr @@ -0,0 +1,66 @@ +error: only lifetime parameters can be used in this context + --> $DIR/cfg-generic-params.rs:7:45 + | +LL | type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn(); + | ^ + +error: only lifetime parameters can be used in this context + --> $DIR/cfg-generic-params.rs:11:51 + | +LL | type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy; + | ^ + +error: only lifetime parameters can be used in this context + --> $DIR/cfg-generic-params.rs:15:54 + | +LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy; + | ^ + +error[E0658]: The attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/cfg-generic-params.rs:19:29 + | +LL | fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/cfg-generic-params.rs:21:29 + | +LL | fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/cfg-generic-params.rs:24:34 + | +LL | type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn(); + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/cfg-generic-params.rs:28:40 + | +LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/cfg-generic-params.rs:32:43 + | +LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/conditional-compilation/cfg_attr_path.rs b/src/test/ui/conditional-compilation/cfg_attr_path.rs index 9e9ff6622ce96..efb718b786fa6 100644 --- a/src/test/ui/conditional-compilation/cfg_attr_path.rs +++ b/src/test/ui/conditional-compilation/cfg_attr_path.rs @@ -1,13 +1,12 @@ -// compile-pass -// skip-codegen -#![allow(dead_code)] +// check-pass + #![deny(unused_attributes)] // c.f #35584 + mod auxiliary { #[cfg_attr(any(), path = "nonexistent_file.rs")] pub mod namespaced_enums; #[cfg_attr(all(), path = "namespaced_enums.rs")] pub mod nonexistent_file; } - fn main() { let _ = auxiliary::namespaced_enums::Foo::A; let _ = auxiliary::nonexistent_file::Foo::A; diff --git a/src/test/ui/conflicting-repr-hints.stderr b/src/test/ui/conflicting-repr-hints.stderr index 148f1211b0834..6b15b7ebbe9ee 100644 --- a/src/test/ui/conflicting-repr-hints.stderr +++ b/src/test/ui/conflicting-repr-hints.stderr @@ -1,49 +1,49 @@ warning[E0566]: conflicting representation hints --> $DIR/conflicting-repr-hints.rs:9:8 | -LL | #[repr(C, u64)] //~ WARNING conflicting representation hints +LL | #[repr(C, u64)] | ^ ^^^ warning[E0566]: conflicting representation hints --> $DIR/conflicting-repr-hints.rs:12:8 | -LL | #[repr(u32, u64)] //~ WARNING conflicting representation hints +LL | #[repr(u32, u64)] | ^^^ ^^^ error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:19:1 | -LL | struct F(i32); //~ ERROR type has conflicting packed and align representation hints +LL | struct F(i32); | ^^^^^^^^^^^^^^ error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:23:1 | -LL | struct G(i32); //~ ERROR type has conflicting packed and align representation hints +LL | struct G(i32); | ^^^^^^^^^^^^^^ error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:27:1 | -LL | struct H(i32); //~ ERROR type has conflicting packed and align representation hints +LL | struct H(i32); | ^^^^^^^^^^^^^^ error[E0634]: type has conflicting packed representation hints --> $DIR/conflicting-repr-hints.rs:30:1 | -LL | struct I(i32); //~ ERROR type has conflicting packed representation hints +LL | struct I(i32); | ^^^^^^^^^^^^^^ error[E0634]: type has conflicting packed representation hints --> $DIR/conflicting-repr-hints.rs:34:1 | -LL | struct J(i32); //~ ERROR type has conflicting packed representation hints +LL | struct J(i32); | ^^^^^^^^^^^^^^ error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:40:1 | -LL | / union X { //~ ERROR type has conflicting packed and align representation hints +LL | / union X { LL | | i: i32 LL | | } | |_^ @@ -51,7 +51,7 @@ LL | | } error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:46:1 | -LL | / union Y { //~ ERROR type has conflicting packed and align representation hints +LL | / union Y { LL | | i: i32 LL | | } | |_^ @@ -59,12 +59,10 @@ LL | | } error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:52:1 | -LL | / union Z { //~ ERROR type has conflicting packed and align representation hints +LL | / union Z { LL | | i: i32 LL | | } | |_^ error: aborting due to 8 previous errors -Some errors occurred: E0566, E0587, E0634. -For more information about an error, try `rustc --explain E0566`. diff --git a/src/test/ui/confuse-field-and-method/issue-18343.stderr b/src/test/ui/confuse-field-and-method/issue-18343.stderr index 36112cd0e10c9..03f9d990dbb23 100644 --- a/src/test/ui/confuse-field-and-method/issue-18343.stderr +++ b/src/test/ui/confuse-field-and-method/issue-18343.stderr @@ -6,8 +6,10 @@ LL | struct Obj where F: FnMut() -> u32 { ... LL | o.closure(); | ^^^^^^^ field, not a method +help: to call the function stored in `closure`, surround the field access with parentheses | - = help: use `(o.closure)(...)` if you meant to call the function stored in the `closure` field +LL | (o.closure)(); + | ^ ^ error: aborting due to previous error diff --git a/src/test/ui/confuse-field-and-method/issue-2392.rs b/src/test/ui/confuse-field-and-method/issue-2392.rs index 41287c2591497..8aef091fe3186 100644 --- a/src/test/ui/confuse-field-and-method/issue-2392.rs +++ b/src/test/ui/confuse-field-and-method/issue-2392.rs @@ -1,7 +1,3 @@ -#![feature(core, fnbox)] - -use std::boxed::FnBox; - struct FuncContainer { f1: fn(data: u8), f2: extern "C" fn(data: u8), @@ -18,7 +14,7 @@ struct Obj where F: FnOnce() -> u32 { } struct BoxedObj { - boxed_closure: Box u32>, + boxed_closure: Box u32>, } struct Wrapper where F: FnMut() -> u32 { @@ -29,8 +25,8 @@ fn func() -> u32 { 0 } -fn check_expression() -> Obj u32>> { - Obj { closure: Box::new(|| 42_u32) as Box u32>, not_closure: 42 } +fn check_expression() -> Obj u32>> { + Obj { closure: Box::new(|| 42_u32) as Box u32>, not_closure: 42 } } fn main() { @@ -48,7 +44,7 @@ fn main() { let boxed_fn = BoxedObj { boxed_closure: Box::new(func) }; boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found - let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box u32> }; + let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box u32> }; boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found // test expression writing in the notes diff --git a/src/test/ui/confuse-field-and-method/issue-2392.stderr b/src/test/ui/confuse-field-and-method/issue-2392.stderr index 0c09bd2284be4..351cfef1b53ea 100644 --- a/src/test/ui/confuse-field-and-method/issue-2392.stderr +++ b/src/test/ui/confuse-field-and-method/issue-2392.stderr @@ -1,123 +1,141 @@ -error[E0599]: no method named `closure` found for type `Obj<[closure@$DIR/issue-2392.rs:39:36: 39:41]>` in the current scope - --> $DIR/issue-2392.rs:40:15 +error[E0599]: no method named `closure` found for type `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope + --> $DIR/issue-2392.rs:36:15 | LL | struct Obj where F: FnOnce() -> u32 { | -------------------------------------- method `closure` not found for this ... -LL | o_closure.closure(); //~ ERROR no method named `closure` found +LL | o_closure.closure(); | ^^^^^^^ field, not a method +help: to call the function stored in `closure`, surround the field access with parentheses | - = help: use `(o_closure.closure)(...)` if you meant to call the function stored in the `closure` field +LL | (o_closure.closure)(); + | ^ ^ -error[E0599]: no method named `not_closure` found for type `Obj<[closure@$DIR/issue-2392.rs:39:36: 39:41]>` in the current scope - --> $DIR/issue-2392.rs:42:15 +error[E0599]: no method named `not_closure` found for type `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope + --> $DIR/issue-2392.rs:38:15 | LL | struct Obj where F: FnOnce() -> u32 { | -------------------------------------- method `not_closure` not found for this ... LL | o_closure.not_closure(); - | ^^^^^^^^^^^ field, not a method - | - = help: did you mean to write `o_closure.not_closure` instead of `o_closure.not_closure(...)`? + | ^^^^^^^^^^^-- help: remove the arguments + | | + | field, not a method error[E0599]: no method named `closure` found for type `Obj u32 {func}>` in the current scope - --> $DIR/issue-2392.rs:46:12 + --> $DIR/issue-2392.rs:42:12 | LL | struct Obj where F: FnOnce() -> u32 { | -------------------------------------- method `closure` not found for this ... -LL | o_func.closure(); //~ ERROR no method named `closure` found +LL | o_func.closure(); | ^^^^^^^ field, not a method +help: to call the function stored in `closure`, surround the field access with parentheses | - = help: use `(o_func.closure)(...)` if you meant to call the function stored in the `closure` field +LL | (o_func.closure)(); + | ^ ^ error[E0599]: no method named `boxed_closure` found for type `BoxedObj` in the current scope - --> $DIR/issue-2392.rs:49:14 + --> $DIR/issue-2392.rs:45:14 | LL | struct BoxedObj { | --------------- method `boxed_closure` not found for this ... -LL | boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found +LL | boxed_fn.boxed_closure(); | ^^^^^^^^^^^^^ field, not a method +help: to call the function stored in `boxed_closure`, surround the field access with parentheses | - = help: use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field +LL | (boxed_fn.boxed_closure)(); + | ^ ^ error[E0599]: no method named `boxed_closure` found for type `BoxedObj` in the current scope - --> $DIR/issue-2392.rs:52:19 + --> $DIR/issue-2392.rs:48:19 | LL | struct BoxedObj { | --------------- method `boxed_closure` not found for this ... -LL | boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found +LL | boxed_closure.boxed_closure(); | ^^^^^^^^^^^^^ field, not a method +help: to call the function stored in `boxed_closure`, surround the field access with parentheses | - = help: use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field +LL | (boxed_closure.boxed_closure)(); + | ^ ^ error[E0599]: no method named `closure` found for type `Obj u32 {func}>` in the current scope - --> $DIR/issue-2392.rs:57:12 + --> $DIR/issue-2392.rs:53:12 | LL | struct Obj where F: FnOnce() -> u32 { | -------------------------------------- method `closure` not found for this ... -LL | w.wrap.closure();//~ ERROR no method named `closure` found +LL | w.wrap.closure(); | ^^^^^^^ field, not a method +help: to call the function stored in `closure`, surround the field access with parentheses | - = help: use `(w.wrap.closure)(...)` if you meant to call the function stored in the `closure` field +LL | (w.wrap.closure)(); + | ^ ^ error[E0599]: no method named `not_closure` found for type `Obj u32 {func}>` in the current scope - --> $DIR/issue-2392.rs:59:12 + --> $DIR/issue-2392.rs:55:12 | LL | struct Obj where F: FnOnce() -> u32 { | -------------------------------------- method `not_closure` not found for this ... LL | w.wrap.not_closure(); - | ^^^^^^^^^^^ field, not a method - | - = help: did you mean to write `w.wrap.not_closure` instead of `w.wrap.not_closure(...)`? + | ^^^^^^^^^^^-- help: remove the arguments + | | + | field, not a method -error[E0599]: no method named `closure` found for type `Obj + 'static)>>` in the current scope - --> $DIR/issue-2392.rs:62:24 +error[E0599]: no method named `closure` found for type `Obj u32 + 'static)>>` in the current scope + --> $DIR/issue-2392.rs:58:24 | LL | struct Obj where F: FnOnce() -> u32 { | -------------------------------------- method `closure` not found for this ... -LL | check_expression().closure();//~ ERROR no method named `closure` found +LL | check_expression().closure(); | ^^^^^^^ field, not a method +help: to call the function stored in `closure`, surround the field access with parentheses | - = help: use `(check_expression().closure)(...)` if you meant to call the function stored in the `closure` field +LL | (check_expression().closure)(); + | ^ ^ error[E0599]: no method named `f1` found for type `FuncContainer` in the current scope - --> $DIR/issue-2392.rs:68:31 + --> $DIR/issue-2392.rs:64:31 | LL | struct FuncContainer { | -------------------- method `f1` not found for this ... -LL | (*self.container).f1(1); //~ ERROR no method named `f1` found +LL | (*self.container).f1(1); | ^^ field, not a method +help: to call the function stored in `f1`, surround the field access with parentheses | - = help: use `((*self.container).f1)(...)` if you meant to call the function stored in the `f1` field +LL | ((*self.container).f1)(1); + | ^ ^ error[E0599]: no method named `f2` found for type `FuncContainer` in the current scope - --> $DIR/issue-2392.rs:69:31 + --> $DIR/issue-2392.rs:65:31 | LL | struct FuncContainer { | -------------------- method `f2` not found for this ... -LL | (*self.container).f2(1); //~ ERROR no method named `f2` found +LL | (*self.container).f2(1); | ^^ field, not a method +help: to call the function stored in `f2`, surround the field access with parentheses | - = help: use `((*self.container).f2)(...)` if you meant to call the function stored in the `f2` field +LL | ((*self.container).f2)(1); + | ^ ^ error[E0599]: no method named `f3` found for type `FuncContainer` in the current scope - --> $DIR/issue-2392.rs:70:31 + --> $DIR/issue-2392.rs:66:31 | LL | struct FuncContainer { | -------------------- method `f3` not found for this ... -LL | (*self.container).f3(1); //~ ERROR no method named `f3` found +LL | (*self.container).f3(1); | ^^ field, not a method +help: to call the function stored in `f3`, surround the field access with parentheses | - = help: use `((*self.container).f3)(...)` if you meant to call the function stored in the `f3` field +LL | ((*self.container).f3)(1); + | ^ ^ error: aborting due to 11 previous errors diff --git a/src/test/ui/confuse-field-and-method/issue-32128.rs b/src/test/ui/confuse-field-and-method/issue-32128.rs index 02c6838d41941..5a024aa4b6749 100644 --- a/src/test/ui/confuse-field-and-method/issue-32128.rs +++ b/src/test/ui/confuse-field-and-method/issue-32128.rs @@ -1,5 +1,5 @@ struct Example { - example: Box i32> + example: Box i32> } fn main() { diff --git a/src/test/ui/confuse-field-and-method/issue-32128.stderr b/src/test/ui/confuse-field-and-method/issue-32128.stderr index 902f60668f2ed..fbabb3a88cc6c 100644 --- a/src/test/ui/confuse-field-and-method/issue-32128.stderr +++ b/src/test/ui/confuse-field-and-method/issue-32128.stderr @@ -6,8 +6,10 @@ LL | struct Example { ... LL | demo.example(1); | ^^^^^^^ field, not a method +help: to call the function stored in `example`, surround the field access with parentheses | - = help: use `(demo.example)(...)` if you meant to call the function stored in the `example` field +LL | (demo.example)(1); + | ^ ^ error: aborting due to previous error diff --git a/src/test/ui/confuse-field-and-method/issue-33784.stderr b/src/test/ui/confuse-field-and-method/issue-33784.stderr index 73bcf0fd9c07e..60f1a932f4442 100644 --- a/src/test/ui/confuse-field-and-method/issue-33784.stderr +++ b/src/test/ui/confuse-field-and-method/issue-33784.stderr @@ -1,26 +1,32 @@ error[E0599]: no method named `closure` found for type `&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:48]>` in the current scope --> $DIR/issue-33784.rs:27:7 | -LL | p.closure(); //~ ERROR no method named `closure` found +LL | p.closure(); | ^^^^^^^ field, not a method +help: to call the function stored in `closure`, surround the field access with parentheses | - = help: use `(p.closure)(...)` if you meant to call the function stored in the `closure` field +LL | (p.closure)(); + | ^ ^ error[E0599]: no method named `fn_ptr` found for type `&&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:48]>` in the current scope --> $DIR/issue-33784.rs:29:7 | -LL | q.fn_ptr(); //~ ERROR no method named `fn_ptr` found +LL | q.fn_ptr(); | ^^^^^^ field, not a method +help: to call the function stored in `fn_ptr`, surround the field access with parentheses | - = help: use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field +LL | (q.fn_ptr)(); + | ^ ^ error[E0599]: no method named `c_fn_ptr` found for type `&D` in the current scope --> $DIR/issue-33784.rs:32:7 | -LL | s.c_fn_ptr(); //~ ERROR no method named `c_fn_ptr` found +LL | s.c_fn_ptr(); | ^^^^^^^^ field, not a method +help: to call the function stored in `c_fn_ptr`, surround the field access with parentheses | - = help: use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` field +LL | (s.c_fn_ptr)(); + | ^ ^ error: aborting due to 3 previous errors diff --git a/src/test/ui/confuse-field-and-method/private-field.stderr b/src/test/ui/confuse-field-and-method/private-field.stderr index e3058ad0a9ea5..97c949e32e341 100644 --- a/src/test/ui/confuse-field-and-method/private-field.stderr +++ b/src/test/ui/confuse-field-and-method/private-field.stderr @@ -4,7 +4,7 @@ error[E0599]: no method named `dog_age` found for type `animal::Dog` in the curr LL | pub struct Dog { | -------------- method `dog_age` not found for this ... -LL | let dog_age = dog.dog_age(); //~ ERROR no method +LL | let dog_age = dog.dog_age(); | ^^^^^^^ private field, not a method error: aborting due to previous error diff --git a/src/test/ui/const-generics/apit-with-const-param.rs b/src/test/ui/const-generics/apit-with-const-param.rs new file mode 100644 index 0000000000000..70e718d889029 --- /dev/null +++ b/src/test/ui/const-generics/apit-with-const-param.rs @@ -0,0 +1,10 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +trait Trait {} + +fn f(_: impl Trait) {} + +fn main() {} diff --git a/src/test/ui/const-generics/apit-with-const-param.stderr b/src/test/ui/const-generics/apit-with-const-param.stderr new file mode 100644 index 0000000000000..b3038ee648851 --- /dev/null +++ b/src/test/ui/const-generics/apit-with-const-param.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/apit-with-const-param.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.rs b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs new file mode 100644 index 0000000000000..d83846fcf88d4 --- /dev/null +++ b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct ArrayStruct { + data: [T; N], +} + +struct ArrayTuple([T; N]); + +fn main() { + let _ = ArrayStruct { data: [0u32; 8] }; + let _ = ArrayTuple([0u32; 8]); +} diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr b/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr new file mode 100644 index 0000000000000..bd18264c1637d --- /dev/null +++ b/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/array-wrapper-struct-ctor.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/broken-mir-1.rs b/src/test/ui/const-generics/broken-mir-1.rs new file mode 100644 index 0000000000000..9a11bd3d0313a --- /dev/null +++ b/src/test/ui/const-generics/broken-mir-1.rs @@ -0,0 +1,17 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +pub trait Foo { + fn foo(&self); +} + + +impl Foo for [T; N] { + fn foo(&self) { + let _ = &self; + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/broken-mir-1.stderr b/src/test/ui/const-generics/broken-mir-1.stderr new file mode 100644 index 0000000000000..55dc7fcb7cc72 --- /dev/null +++ b/src/test/ui/const-generics/broken-mir-1.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/broken-mir-1.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/broken-mir-2.rs b/src/test/ui/const-generics/broken-mir-2.rs new file mode 100644 index 0000000000000..fb9a63ea738fa --- /dev/null +++ b/src/test/ui/const-generics/broken-mir-2.rs @@ -0,0 +1,9 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +use std::fmt::Debug; + +#[derive(Debug)] +struct S([T; N]); //~ ERROR `[T; _]` doesn't implement `std::fmt::Debug` + +fn main() {} diff --git a/src/test/ui/const-generics/broken-mir-2.stderr b/src/test/ui/const-generics/broken-mir-2.stderr new file mode 100644 index 0000000000000..fb9b88bde0a25 --- /dev/null +++ b/src/test/ui/const-generics/broken-mir-2.stderr @@ -0,0 +1,19 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/broken-mir-2.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0277]: `[T; _]` doesn't implement `std::fmt::Debug` + --> $DIR/broken-mir-2.rs:7:36 + | +LL | struct S([T; N]); + | ^^^^^^ `[T; _]` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | + = help: the trait `std::fmt::Debug` is not implemented for `[T; _]` + = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[T; _]` + = note: required for the cast to the object type `dyn std::fmt::Debug` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/cannot-infer-const-args.rs b/src/test/ui/const-generics/cannot-infer-const-args.rs new file mode 100644 index 0000000000000..e1061c6d1a33d --- /dev/null +++ b/src/test/ui/const-generics/cannot-infer-const-args.rs @@ -0,0 +1,10 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn foo() -> usize { + 0 +} + +fn main() { + foo(); //~ ERROR type annotations needed +} diff --git a/src/test/ui/const-generics/cannot-infer-const-args.stderr b/src/test/ui/const-generics/cannot-infer-const-args.stderr new file mode 100644 index 0000000000000..544cd05cdbebf --- /dev/null +++ b/src/test/ui/const-generics/cannot-infer-const-args.stderr @@ -0,0 +1,15 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/cannot-infer-const-args.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0282]: type annotations needed + --> $DIR/cannot-infer-const-args.rs:9:5 + | +LL | foo(); + | ^^^ cannot infer type for `fn() -> usize {foo::<_: usize>}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs b/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs new file mode 100644 index 0000000000000..f592e486be951 --- /dev/null +++ b/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs @@ -0,0 +1,13 @@ +// compile-pass +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +// This test confirms that the types can be inferred correctly for this example with const +// generics. Previously this would ICE, and more recently error. + +struct Foo(pub [u8; NUM_BYTES]); + +fn main() { + let _ = Foo::<3>([1, 2, 3]); //~ ERROR type annotations needed + //~^ ERROR mismatched types +} diff --git a/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr b/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr new file mode 100644 index 0000000000000..52907bbb67720 --- /dev/null +++ b/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/cannot-infer-type-for-const-param.rs:2:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/concrete-const-as-fn-arg.rs b/src/test/ui/const-generics/concrete-const-as-fn-arg.rs new file mode 100644 index 0000000000000..54981b77a2b84 --- /dev/null +++ b/src/test/ui/const-generics/concrete-const-as-fn-arg.rs @@ -0,0 +1,14 @@ +// Test that a concrete const type i.e. A<2>, can be used as an argument type in a function +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct A; // ok + +fn with_concrete_const_arg(_: A<2>) -> u32 { 17 } + +fn main() { + let val: A<2> = A; + assert_eq!(with_concrete_const_arg(val), 17); +} diff --git a/src/test/ui/const-generics/concrete-const-as-fn-arg.stderr b/src/test/ui/const-generics/concrete-const-as-fn-arg.stderr new file mode 100644 index 0000000000000..955b319d70044 --- /dev/null +++ b/src/test/ui/const-generics/concrete-const-as-fn-arg.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/concrete-const-as-fn-arg.rs:4:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/concrete-const-impl-method.rs b/src/test/ui/const-generics/concrete-const-impl-method.rs new file mode 100644 index 0000000000000..226ea4151806e --- /dev/null +++ b/src/test/ui/const-generics/concrete-const-impl-method.rs @@ -0,0 +1,24 @@ +// Test that a method/associated non-method within an impl block of a concrete const type i.e. A<2>, +// is callable. +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +pub struct A; + +impl A<2> { + fn impl_method(&self) -> u32 { + 17 + } + + fn associated_non_method() -> u32 { + 17 + } +} + +fn main() { + let val: A<2> = A; + assert_eq!(val.impl_method(), 17); + assert_eq!(A::<2>::associated_non_method(), 17); +} diff --git a/src/test/ui/const-generics/concrete-const-impl-method.stderr b/src/test/ui/const-generics/concrete-const-impl-method.stderr new file mode 100644 index 0000000000000..3ce488c62755a --- /dev/null +++ b/src/test/ui/const-generics/concrete-const-impl-method.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/concrete-const-impl-method.rs:5:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/condition-in-trait-const-arg.rs b/src/test/ui/const-generics/condition-in-trait-const-arg.rs new file mode 100644 index 0000000000000..091fe904826d4 --- /dev/null +++ b/src/test/ui/const-generics/condition-in-trait-const-arg.rs @@ -0,0 +1,12 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +trait IsZeroTrait{} + +impl IsZeroTrait<{0u8 == 0u8}> for () {} + +impl IsZeroTrait for ((),) {} + +fn main() {} diff --git a/src/test/ui/const-generics/condition-in-trait-const-arg.stderr b/src/test/ui/const-generics/condition-in-trait-const-arg.stderr new file mode 100644 index 0000000000000..7c85651e7082f --- /dev/null +++ b/src/test/ui/const-generics/condition-in-trait-const-arg.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/condition-in-trait-const-arg.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/const-arg-in-fn.rs b/src/test/ui/const-generics/const-arg-in-fn.rs new file mode 100644 index 0000000000000..3f86782838ca1 --- /dev/null +++ b/src/test/ui/const-generics/const-arg-in-fn.rs @@ -0,0 +1,13 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn const_u32_identity() -> u32 { + X +} + + fn main() { + let val = const_u32_identity::<18>(); + assert_eq!(val, 18); +} diff --git a/src/test/ui/const-generics/const-arg-in-fn.stderr b/src/test/ui/const-generics/const-arg-in-fn.stderr new file mode 100644 index 0000000000000..e32b714b25d36 --- /dev/null +++ b/src/test/ui/const-generics/const-arg-in-fn.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-arg-in-fn.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/const-expression-parameter.rs b/src/test/ui/const-generics/const-expression-parameter.rs index f4e9008dbd0f1..22c6c35162281 100644 --- a/src/test/ui/const-generics/const-expression-parameter.rs +++ b/src/test/ui/const-generics/const-expression-parameter.rs @@ -1,23 +1,22 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -fn u32_identity() -> u32 { - //~^ ERROR const generics in any position are currently unsupported +fn i32_identity() -> i32 { 5 } fn foo_a() { - u32_identity::<-1>(); //~ ERROR expected identifier, found `<-` + i32_identity::<-1>(); // ok } fn foo_b() { - u32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+` + i32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+` } fn foo_c() { - u32_identity::< -1 >(); // ok + i32_identity::< -1 >(); // ok } fn main() { - u32_identity::<5>(); // ok + i32_identity::<5>(); // ok } diff --git a/src/test/ui/const-generics/const-expression-parameter.stderr b/src/test/ui/const-generics/const-expression-parameter.stderr index 1dd3a960316d9..c255127c28079 100644 --- a/src/test/ui/const-generics/const-expression-parameter.stderr +++ b/src/test/ui/const-generics/const-expression-parameter.stderr @@ -1,13 +1,7 @@ -error: expected identifier, found `<-` - --> $DIR/const-expression-parameter.rs:10:19 - | -LL | u32_identity::<-1>(); //~ ERROR expected identifier, found `<-` - | ^^ expected identifier - error: expected one of `,` or `>`, found `+` - --> $DIR/const-expression-parameter.rs:14:22 + --> $DIR/const-expression-parameter.rs:13:22 | -LL | u32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+` +LL | i32_identity::<1 + 2>(); | ^ expected one of `,` or `>` here warning: the feature `const_generics` is incomplete and may cause the compiler to crash @@ -16,11 +10,5 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ -error: const generics in any position are currently unsupported - --> $DIR/const-expression-parameter.rs:4:23 - | -LL | fn u32_identity() -> u32 { - | ^ - -error: aborting due to 3 previous errors +error: aborting due to previous error diff --git a/src/test/ui/const-generics/const-fn-with-const-param.rs b/src/test/ui/const-generics/const-fn-with-const-param.rs index 052d723d96edb..f36bf3875c349 100644 --- a/src/test/ui/const-generics/const-fn-with-const-param.rs +++ b/src/test/ui/const-generics/const-fn-with-const-param.rs @@ -3,7 +3,6 @@ const fn const_u32_identity() -> u32 { //~^ ERROR const parameters are not permitted in `const fn` - //~^^ ERROR const generics in any position are currently unsupported X } diff --git a/src/test/ui/const-generics/const-fn-with-const-param.stderr b/src/test/ui/const-generics/const-fn-with-const-param.stderr index a08ebfb0d9766..c0cd7bace471c 100644 --- a/src/test/ui/const-generics/const-fn-with-const-param.stderr +++ b/src/test/ui/const-generics/const-fn-with-const-param.stderr @@ -8,17 +8,10 @@ error: const parameters are not permitted in `const fn` --> $DIR/const-fn-with-const-param.rs:4:1 | LL | / const fn const_u32_identity() -> u32 { -LL | | //~^ ERROR const parameters are not permitted in `const fn` -LL | | //~^^ ERROR const generics in any position are currently unsupported +LL | | LL | | X LL | | } | |_^ -error: const generics in any position are currently unsupported - --> $DIR/const-fn-with-const-param.rs:4:35 - | -LL | const fn const_u32_identity() -> u32 { - | ^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/const-generics/const-generic-array-wrapper.rs b/src/test/ui/const-generics/const-generic-array-wrapper.rs new file mode 100644 index 0000000000000..adffe32d67a30 --- /dev/null +++ b/src/test/ui/const-generics/const-generic-array-wrapper.rs @@ -0,0 +1,18 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct Foo([T; {N}]); + +impl Foo { + fn foo(&self) -> usize { + {N} + } +} + +fn main() { + let foo = Foo([0u32; 21]); + assert_eq!(foo.0, [0u32; 21]); + assert_eq!(foo.foo(), 21); +} diff --git a/src/test/ui/const-generics/const-generic-array-wrapper.stderr b/src/test/ui/const-generics/const-generic-array-wrapper.stderr new file mode 100644 index 0000000000000..f92e11d47ed37 --- /dev/null +++ b/src/test/ui/const-generics/const-generic-array-wrapper.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-generic-array-wrapper.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs index 47f826789e03e..2c81681b85e7d 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.rs +++ b/src/test/ui/const-generics/const-param-before-other-params.rs @@ -1,14 +1,12 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -fn foo(_: T) { - //~^ ERROR type parameters must be declared prior to const parameters - //~^^ ERROR const generics in any position are currently unsupported -} - fn bar(_: &'a ()) { //~^ ERROR lifetime parameters must be declared prior to const parameters - //~^^ ERROR const generics in any position are currently unsupported +} + +fn foo(_: &T) { + //~^ ERROR type parameters must be declared prior to const parameters } fn main() {} diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr index a43415d0e5a43..33f981d1eba9b 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.stderr +++ b/src/test/ui/const-generics/const-param-before-other-params.stderr @@ -4,29 +4,17 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ -error: type parameters must be declared prior to const parameters - --> $DIR/const-param-before-other-params.rs:4:21 - | -LL | fn foo(_: T) { - | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` - error: lifetime parameters must be declared prior to const parameters - --> $DIR/const-param-before-other-params.rs:9:21 + --> $DIR/const-param-before-other-params.rs:4:21 | LL | fn bar(_: &'a ()) { | --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>` -error: const generics in any position are currently unsupported - --> $DIR/const-param-before-other-params.rs:4:14 - | -LL | fn foo(_: T) { - | ^ - -error: const generics in any position are currently unsupported - --> $DIR/const-param-before-other-params.rs:9:14 +error: type parameters must be declared prior to const parameters + --> $DIR/const-param-before-other-params.rs:8:21 | -LL | fn bar(_: &'a ()) { - | ^ +LL | fn foo(_: &T) { + | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const-param-from-outer-fn.rs b/src/test/ui/const-generics/const-param-from-outer-fn.rs index 5a8dd92086f85..6534bcf5ce64c 100644 --- a/src/test/ui/const-generics/const-param-from-outer-fn.rs +++ b/src/test/ui/const-generics/const-param-from-outer-fn.rs @@ -2,7 +2,6 @@ //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash fn foo() { - //~^ ERROR const generics in any position are currently unsupported fn bar() -> u32 { X //~ ERROR can't use generic parameters from outer function } diff --git a/src/test/ui/const-generics/const-param-from-outer-fn.stderr b/src/test/ui/const-generics/const-param-from-outer-fn.stderr index b238b3a2aa453..f0b7562f62196 100644 --- a/src/test/ui/const-generics/const-param-from-outer-fn.stderr +++ b/src/test/ui/const-generics/const-param-from-outer-fn.stderr @@ -5,22 +5,15 @@ LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ error[E0401]: can't use generic parameters from outer function - --> $DIR/const-param-from-outer-fn.rs:7:9 + --> $DIR/const-param-from-outer-fn.rs:6:9 | LL | fn foo() { - | - const variable from outer function -LL | //~^ ERROR const generics in any position are currently unsupported + | - const parameter from outer function LL | fn bar() -> u32 { | --- try adding a local generic parameter in this method instead -LL | X //~ ERROR can't use generic parameters from outer function +LL | X | ^ use of generic parameter from outer function -error: const generics in any position are currently unsupported - --> $DIR/const-param-from-outer-fn.rs:4:14 - | -LL | fn foo() { - | ^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0401`. diff --git a/src/test/ui/const-generics/const-param-in-trait-ungated.rs b/src/test/ui/const-generics/const-param-in-trait-ungated.rs new file mode 100644 index 0000000000000..8a81bcc1a80c8 --- /dev/null +++ b/src/test/ui/const-generics/const-param-in-trait-ungated.rs @@ -0,0 +1,3 @@ +trait Trait {} //~ ERROR const generics are unstable + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-in-trait-ungated.stderr b/src/test/ui/const-generics/const-param-in-trait-ungated.stderr new file mode 100644 index 0000000000000..53bc973841416 --- /dev/null +++ b/src/test/ui/const-generics/const-param-in-trait-ungated.stderr @@ -0,0 +1,12 @@ +error[E0658]: const generics are unstable + --> $DIR/const-param-in-trait-ungated.rs:1:19 + | +LL | trait Trait {} + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 + = help: add #![feature(const_generics)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/const-generics/const-param-in-trait.rs b/src/test/ui/const-generics/const-param-in-trait.rs new file mode 100644 index 0000000000000..6e4f65fe6cac0 --- /dev/null +++ b/src/test/ui/const-generics/const-param-in-trait.rs @@ -0,0 +1,8 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +trait Trait {} + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-in-trait.stderr b/src/test/ui/const-generics/const-param-in-trait.stderr new file mode 100644 index 0000000000000..a48eefddaa844 --- /dev/null +++ b/src/test/ui/const-generics/const-param-in-trait.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-param-in-trait.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs new file mode 100644 index 0000000000000..af5e8f49754e8 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs @@ -0,0 +1,6 @@ +use std::marker::PhantomData; + +struct B(PhantomData<[T; N]>); //~ ERROR const generics are unstable +//~^ ERROR const parameters cannot depend on type parameters + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr new file mode 100644 index 0000000000000..e3adbcfe60204 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr @@ -0,0 +1,19 @@ +error[E0671]: const parameters cannot depend on type parameters + --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22 + | +LL | struct B(PhantomData<[T; N]>); + | ^ const parameter depends on type parameter + +error[E0658]: const generics are unstable + --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19 + | +LL | struct B(PhantomData<[T; N]>); + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 + = help: add #![feature(const_generics)] to the crate attributes to enable + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0658, E0671. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs new file mode 100644 index 0000000000000..28e0d6c2bb7e7 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs @@ -0,0 +1,13 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +// Currently, const parameters cannot depend on type parameters, because there is no way to +// enforce the `structural_match` property on an arbitrary type parameter. This restriction +// may be relaxed in the future. See https://github.com/rust-lang/rfcs/pull/2000 for more +// details. + +pub struct Dependent([(); X]); +//~^ ERROR const parameters cannot depend on type parameters +//~^^ ERROR parameter `T` is never used + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr new file mode 100644 index 0000000000000..c7dcbe1354266 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr @@ -0,0 +1,24 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-param-type-depends-on-type-param.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0671]: const parameters cannot depend on type parameters + --> $DIR/const-param-type-depends-on-type-param.rs:9:34 + | +LL | pub struct Dependent([(); X]); + | ^ const parameter depends on type parameter + +error[E0392]: parameter `T` is never used + --> $DIR/const-param-type-depends-on-type-param.rs:9:22 + | +LL | pub struct Dependent([(); X]); + | ^ unused parameter + | + = help: consider removing `T` or using a marker such as `std::marker::PhantomData` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0392, E0671. +For more information about an error, try `rustc --explain E0392`. diff --git a/src/test/ui/const-generics/const-parameter-uppercase-lint.rs b/src/test/ui/const-generics/const-parameter-uppercase-lint.rs index 37fe9af98b3df..164205dd75cbc 100644 --- a/src/test/ui/const-generics/const-parameter-uppercase-lint.rs +++ b/src/test/ui/const-generics/const-parameter-uppercase-lint.rs @@ -4,5 +4,7 @@ #![deny(non_upper_case_globals)] fn noop() { - //~^ ERROR const generics in any position are currently unsupported + //~^ ERROR const parameter `x` should have an upper case name } + +fn main() {} diff --git a/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr b/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr index 9683e91cef30c..190798d202bea 100644 --- a/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr +++ b/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr @@ -4,16 +4,17 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ -error[E0601]: `main` function not found in crate `const_parameter_uppercase_lint` - | - = note: consider adding a `main` function to `$DIR/const-parameter-uppercase-lint.rs` - -error: const generics in any position are currently unsupported +error: const parameter `x` should have an upper case name --> $DIR/const-parameter-uppercase-lint.rs:6:15 | LL | fn noop() { - | ^ + | ^ help: convert the identifier to upper case: `X` + | +note: lint level defined here + --> $DIR/const-parameter-uppercase-lint.rs:4:9 + | +LL | #![deny(non_upper_case_globals)] + | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/const-generics/const-types.rs b/src/test/ui/const-generics/const-types.rs new file mode 100644 index 0000000000000..11757cd588dab --- /dev/null +++ b/src/test/ui/const-generics/const-types.rs @@ -0,0 +1,16 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +#[allow(dead_code)] + +struct ConstArray { + array: [T; LEN], +} + +fn main() { + let arr = ConstArray:: { + array: [0; 8], + }; +} diff --git a/src/test/ui/const-generics/const-types.stderr b/src/test/ui/const-generics/const-types.stderr new file mode 100644 index 0000000000000..fbf5d53754164 --- /dev/null +++ b/src/test/ui/const-generics/const-types.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-types.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/derive-debug-array-wrapper.rs b/src/test/ui/const-generics/derive-debug-array-wrapper.rs new file mode 100644 index 0000000000000..a29cb90ebb79a --- /dev/null +++ b/src/test/ui/const-generics/derive-debug-array-wrapper.rs @@ -0,0 +1,9 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +#[derive(Debug)] +struct X { + a: [u32; N], //~ ERROR `[u32; _]` doesn't implement `std::fmt::Debug` +} + +fn main() {} diff --git a/src/test/ui/const-generics/derive-debug-array-wrapper.stderr b/src/test/ui/const-generics/derive-debug-array-wrapper.stderr new file mode 100644 index 0000000000000..5bab1d1b54a3e --- /dev/null +++ b/src/test/ui/const-generics/derive-debug-array-wrapper.stderr @@ -0,0 +1,19 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/derive-debug-array-wrapper.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0277]: `[u32; _]` doesn't implement `std::fmt::Debug` + --> $DIR/derive-debug-array-wrapper.rs:6:5 + | +LL | a: [u32; N], + | ^^^^^^^^^^^ `[u32; _]` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | + = help: the trait `std::fmt::Debug` is not implemented for `[u32; _]` + = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[u32; _]` + = note: required for the cast to the object type `dyn std::fmt::Debug` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/fn-taking-const-generic-array.rs b/src/test/ui/const-generics/fn-taking-const-generic-array.rs new file mode 100644 index 0000000000000..d3d17cca4da27 --- /dev/null +++ b/src/test/ui/const-generics/fn-taking-const-generic-array.rs @@ -0,0 +1,16 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +use std::fmt::Display; + +fn print_slice(slice: &[T; N]) { + for x in slice.iter() { + println!("{}", x); + } +} + +fn main() { + print_slice(&[1, 2, 3]); +} diff --git a/src/test/ui/const-generics/fn-taking-const-generic-array.stderr b/src/test/ui/const-generics/fn-taking-const-generic-array.stderr new file mode 100644 index 0000000000000..367041283251f --- /dev/null +++ b/src/test/ui/const-generics/fn-taking-const-generic-array.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/fn-taking-const-generic-array.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/impl-const-generic-struct.rs b/src/test/ui/const-generics/impl-const-generic-struct.rs new file mode 100644 index 0000000000000..7a0c0f2be5d7a --- /dev/null +++ b/src/test/ui/const-generics/impl-const-generic-struct.rs @@ -0,0 +1,16 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct S; + +impl S<{X}> { + fn x() -> u32 { + X + } +} + +fn main() { + assert_eq!(S::<19>::x(), 19); +} diff --git a/src/test/ui/const-generics/impl-const-generic-struct.stderr b/src/test/ui/const-generics/impl-const-generic-struct.stderr new file mode 100644 index 0000000000000..d443e060a9747 --- /dev/null +++ b/src/test/ui/const-generics/impl-const-generic-struct.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/impl-const-generic-struct.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/incorrect-number-of-const-args.rs b/src/test/ui/const-generics/incorrect-number-of-const-args.rs new file mode 100644 index 0000000000000..7059e9d8348e3 --- /dev/null +++ b/src/test/ui/const-generics/incorrect-number-of-const-args.rs @@ -0,0 +1,11 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn foo() -> usize { + 0 +} + +fn main() { + foo::<0>(); //~ ERROR wrong number of const arguments: expected 2, found 1 + foo::<0, 0, 0>(); //~ ERROR wrong number of const arguments: expected 2, found 3 +} diff --git a/src/test/ui/const-generics/incorrect-number-of-const-args.stderr b/src/test/ui/const-generics/incorrect-number-of-const-args.stderr new file mode 100644 index 0000000000000..11727733eb533 --- /dev/null +++ b/src/test/ui/const-generics/incorrect-number-of-const-args.stderr @@ -0,0 +1,21 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/incorrect-number-of-const-args.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0107]: wrong number of const arguments: expected 2, found 1 + --> $DIR/incorrect-number-of-const-args.rs:9:5 + | +LL | foo::<0>(); + | ^^^^^^^^ expected 2 const arguments + +error[E0107]: wrong number of const arguments: expected 2, found 3 + --> $DIR/incorrect-number-of-const-args.rs:10:17 + | +LL | foo::<0, 0, 0>(); + | ^ unexpected const argument + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/invalid-const-arg-for-type-param.rs b/src/test/ui/const-generics/invalid-const-arg-for-type-param.rs new file mode 100644 index 0000000000000..b069cd89680c1 --- /dev/null +++ b/src/test/ui/const-generics/invalid-const-arg-for-type-param.rs @@ -0,0 +1,9 @@ +use std::convert::TryInto; + +struct S; + +fn main() { + let _: u32 = 5i32.try_into::<32>().unwrap(); //~ ERROR wrong number of const arguments + S.f::<0>(); //~ ERROR no method named `f` + S::<0>; //~ ERROR wrong number of const arguments +} diff --git a/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr new file mode 100644 index 0000000000000..8f3f91651edfb --- /dev/null +++ b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr @@ -0,0 +1,25 @@ +error[E0107]: wrong number of const arguments: expected 0, found 1 + --> $DIR/invalid-const-arg-for-type-param.rs:6:34 + | +LL | let _: u32 = 5i32.try_into::<32>().unwrap(); + | ^^ unexpected const argument + +error[E0599]: no method named `f` found for type `S` in the current scope + --> $DIR/invalid-const-arg-for-type-param.rs:7:7 + | +LL | struct S; + | --------- method `f` not found for this +... +LL | S.f::<0>(); + | ^ + +error[E0107]: wrong number of const arguments: expected 0, found 1 + --> $DIR/invalid-const-arg-for-type-param.rs:8:9 + | +LL | S::<0>; + | ^ unexpected const argument + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0107, E0599. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/invalid-constant-in-args.rs b/src/test/ui/const-generics/invalid-constant-in-args.rs new file mode 100644 index 0000000000000..40df237ee72ed --- /dev/null +++ b/src/test/ui/const-generics/invalid-constant-in-args.rs @@ -0,0 +1,3 @@ +fn main() { + let _: Vec<&str, "a"> = Vec::new(); //~ ERROR wrong number of const arguments +} diff --git a/src/test/ui/const-generics/invalid-constant-in-args.stderr b/src/test/ui/const-generics/invalid-constant-in-args.stderr new file mode 100644 index 0000000000000..b9f874ff18bb3 --- /dev/null +++ b/src/test/ui/const-generics/invalid-constant-in-args.stderr @@ -0,0 +1,9 @@ +error[E0107]: wrong number of const arguments: expected 0, found 1 + --> $DIR/invalid-constant-in-args.rs:2:22 + | +LL | let _: Vec<&str, "a"> = Vec::new(); + | ^^^ unexpected const argument + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issue-60263.rs b/src/test/ui/const-generics/issue-60263.rs new file mode 100644 index 0000000000000..70cbc242c41a5 --- /dev/null +++ b/src/test/ui/const-generics/issue-60263.rs @@ -0,0 +1,9 @@ +struct B; //~ ERROR const generics are unstable + +impl B<0> { + fn bug() -> Self { + panic!() + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/issue-60263.stderr b/src/test/ui/const-generics/issue-60263.stderr new file mode 100644 index 0000000000000..ab1b9e4a7cd86 --- /dev/null +++ b/src/test/ui/const-generics/issue-60263.stderr @@ -0,0 +1,12 @@ +error[E0658]: const generics are unstable + --> $DIR/issue-60263.rs:1:16 + | +LL | struct B; + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 + = help: add #![feature(const_generics)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/const-generics/issue-60818-struct-constructors.rs b/src/test/ui/const-generics/issue-60818-struct-constructors.rs new file mode 100644 index 0000000000000..0b4aeae7a4a39 --- /dev/null +++ b/src/test/ui/const-generics/issue-60818-struct-constructors.rs @@ -0,0 +1,10 @@ +// compile-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct Generic; + +fn main() { + let _ = Generic::<0>; +} diff --git a/src/test/ui/const-generics/issue-60818-struct-constructors.stderr b/src/test/ui/const-generics/issue-60818-struct-constructors.stderr new file mode 100644 index 0000000000000..4b8f50b9b0219 --- /dev/null +++ b/src/test/ui/const-generics/issue-60818-struct-constructors.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-60818-struct-constructors.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/issue-61336-1.rs b/src/test/ui/const-generics/issue-61336-1.rs new file mode 100644 index 0000000000000..5b5e431bf2ff6 --- /dev/null +++ b/src/test/ui/const-generics/issue-61336-1.rs @@ -0,0 +1,12 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn f(x: T) -> [T; N] { + [x; N] + //~^ ERROR array lengths can't depend on generic parameters +} + +fn main() { + let x: [u32; 5] = f::(3); + assert_eq!(x, [3u32; 5]); +} diff --git a/src/test/ui/const-generics/issue-61336-1.stderr b/src/test/ui/const-generics/issue-61336-1.stderr new file mode 100644 index 0000000000000..1a5bb9f763bcf --- /dev/null +++ b/src/test/ui/const-generics/issue-61336-1.stderr @@ -0,0 +1,14 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-61336-1.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error: array lengths can't depend on generic parameters + --> $DIR/issue-61336-1.rs:5:9 + | +LL | [x; N] + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issue-61336-2.rs b/src/test/ui/const-generics/issue-61336-2.rs new file mode 100644 index 0000000000000..604c14ee120a8 --- /dev/null +++ b/src/test/ui/const-generics/issue-61336-2.rs @@ -0,0 +1,16 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn f(x: T) -> [T; N] { + [x; {N}] +} + +fn g(x: T) -> [T; N] { + [x; {N}] + //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied [E0277] +} + +fn main() { + let x: [u32; 5] = f::(3); + assert_eq!(x, [3u32; 5]); +} diff --git a/src/test/ui/const-generics/issue-61336-2.stderr b/src/test/ui/const-generics/issue-61336-2.stderr new file mode 100644 index 0000000000000..a7135b62f8cff --- /dev/null +++ b/src/test/ui/const-generics/issue-61336-2.stderr @@ -0,0 +1,18 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-61336-2.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/issue-61336-2.rs:9:5 + | +LL | [x; {N}] + | ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | + = help: consider adding a `where T: std::marker::Copy` bound + = note: the `Copy` trait is required because the repeated element will be copied + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issue-61336.rs b/src/test/ui/const-generics/issue-61336.rs new file mode 100644 index 0000000000000..95930371d5974 --- /dev/null +++ b/src/test/ui/const-generics/issue-61336.rs @@ -0,0 +1,16 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn f(x: T) -> [T; N] { + [x; N] +} + +fn g(x: T) -> [T; N] { + [x; N] + //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied [E0277] +} + +fn main() { + let x: [u32; 5] = f::(3); + assert_eq!(x, [3u32; 5]); +} diff --git a/src/test/ui/const-generics/issue-61336.stderr b/src/test/ui/const-generics/issue-61336.stderr new file mode 100644 index 0000000000000..9939a5998340f --- /dev/null +++ b/src/test/ui/const-generics/issue-61336.stderr @@ -0,0 +1,18 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-61336.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/issue-61336.rs:9:5 + | +LL | [x; N] + | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | + = help: consider adding a `where T: std::marker::Copy` bound + = note: the `Copy` trait is required because the repeated element will be copied + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issue-61422.rs b/src/test/ui/const-generics/issue-61422.rs new file mode 100644 index 0000000000000..3ccf38e561977 --- /dev/null +++ b/src/test/ui/const-generics/issue-61422.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +use std::mem; + +fn foo() { + let arr: [u8; SIZE] = unsafe { + let mut array: [u8; SIZE] = mem::uninitialized(); + array + }; +} + +fn main() {} diff --git a/src/test/ui/const-generics/issue-61422.stderr b/src/test/ui/const-generics/issue-61422.stderr new file mode 100644 index 0000000000000..4cb76ec4fe18c --- /dev/null +++ b/src/test/ui/const-generics/issue-61422.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-61422.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/mut-ref-const-param-array.rs b/src/test/ui/const-generics/mut-ref-const-param-array.rs new file mode 100644 index 0000000000000..f930fb8796325 --- /dev/null +++ b/src/test/ui/const-generics/mut-ref-const-param-array.rs @@ -0,0 +1,19 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +use std::ops::AddAssign; + +fn inc(v: &mut [T; N]) -> &mut [T; N] { + for x in v.iter_mut() { + *x += x.clone(); + } + v +} + +fn main() { + let mut v = [1, 2, 3]; + inc(&mut v); + assert_eq!(v, [2, 4, 6]); +} diff --git a/src/test/ui/const-generics/mut-ref-const-param-array.stderr b/src/test/ui/const-generics/mut-ref-const-param-array.stderr new file mode 100644 index 0000000000000..261d3578a11ac --- /dev/null +++ b/src/test/ui/const-generics/mut-ref-const-param-array.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/mut-ref-const-param-array.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/struct-with-invalid-const-param.rs b/src/test/ui/const-generics/struct-with-invalid-const-param.rs new file mode 100644 index 0000000000000..207b07bf69514 --- /dev/null +++ b/src/test/ui/const-generics/struct-with-invalid-const-param.rs @@ -0,0 +1,6 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct S(C); //~ ERROR expected type, found const parameter + +fn main() {} diff --git a/src/test/ui/const-generics/struct-with-invalid-const-param.stderr b/src/test/ui/const-generics/struct-with-invalid-const-param.stderr new file mode 100644 index 0000000000000..64354752fd2af --- /dev/null +++ b/src/test/ui/const-generics/struct-with-invalid-const-param.stderr @@ -0,0 +1,14 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/struct-with-invalid-const-param.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0573]: expected type, found const parameter `C` + --> $DIR/struct-with-invalid-const-param.rs:4:23 + | +LL | struct S(C); + | ^ help: a struct with a similar name exists: `S` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs b/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs new file mode 100644 index 0000000000000..794048174f903 --- /dev/null +++ b/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.rs @@ -0,0 +1,11 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +use std::mem::MaybeUninit; + +#[repr(transparent)] +pub struct MaybeUninitWrapper(MaybeUninit<[u64; N]>); + +fn main() {} diff --git a/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr b/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr new file mode 100644 index 0000000000000..661bbd113bc0d --- /dev/null +++ b/src/test/ui/const-generics/transparent-maybeunit-array-wrapper.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/transparent-maybeunit-array-wrapper.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs new file mode 100644 index 0000000000000..1e064fbd97064 --- /dev/null +++ b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs @@ -0,0 +1,18 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +use std::fmt; + +struct Array([T; N]); + +impl fmt::Debug for Array { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(self.0.iter()).finish() + } +} + +fn main() { + assert_eq!(format!("{:?}", Array([1, 2, 3])), "[1, 2, 3]"); +} diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr new file mode 100644 index 0000000000000..eb2e446396c33 --- /dev/null +++ b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/uninferred-consts-during-codegen-1.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs new file mode 100644 index 0000000000000..0cf505906f626 --- /dev/null +++ b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs @@ -0,0 +1,18 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +use std::fmt; + +struct Array(T); + +impl fmt::Debug for Array<[T; N]> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries((&self.0 as &[T]).iter()).finish() + } +} + +fn main() { + assert_eq!(format!("{:?}", Array([1, 2, 3])), "[1, 2, 3]"); +} diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr new file mode 100644 index 0000000000000..eaa20bb789222 --- /dev/null +++ b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/uninferred-consts-during-codegen-2.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/unused-const-param.rs b/src/test/ui/const-generics/unused-const-param.rs new file mode 100644 index 0000000000000..ee98e5eb4a01f --- /dev/null +++ b/src/test/ui/const-generics/unused-const-param.rs @@ -0,0 +1,8 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct A; // ok + +fn main() {} diff --git a/src/test/ui/const-generics/unused-const-param.stderr b/src/test/ui/const-generics/unused-const-param.stderr new file mode 100644 index 0000000000000..0e7acfb673d1d --- /dev/null +++ b/src/test/ui/const-generics/unused-const-param.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/unused-const-param.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/consts/array-literal-index-oob.rs b/src/test/ui/consts/array-literal-index-oob.rs new file mode 100644 index 0000000000000..76013c77de0c2 --- /dev/null +++ b/src/test/ui/consts/array-literal-index-oob.rs @@ -0,0 +1,6 @@ +fn main() { + &{[1, 2, 3][4]}; + //~^ ERROR index out of bounds + //~| ERROR reaching this expression at runtime will panic or abort + //~| ERROR this expression will panic at runtime +} diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr new file mode 100644 index 0000000000000..727ce9e57a47b --- /dev/null +++ b/src/test/ui/consts/array-literal-index-oob.stderr @@ -0,0 +1,24 @@ +error: index out of bounds: the len is 3 but the index is 4 + --> $DIR/array-literal-index-oob.rs:2:7 + | +LL | &{[1, 2, 3][4]}; + | ^^^^^^^^^^^^ + | + = note: #[deny(const_err)] on by default + +error: this expression will panic at runtime + --> $DIR/array-literal-index-oob.rs:2:5 + | +LL | &{[1, 2, 3][4]}; + | ^^^^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 4 + +error: reaching this expression at runtime will panic or abort + --> $DIR/array-literal-index-oob.rs:2:7 + | +LL | &{[1, 2, 3][4]}; + | --^^^^^^^^^^^^- + | | + | index out of bounds: the len is 3 but the index is 4 + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/consts/const-array-oob-arith.rs b/src/test/ui/consts/const-array-oob-arith.rs index 2f9b30b51d10a..2f5661e32a90e 100644 --- a/src/test/ui/consts/const-array-oob-arith.rs +++ b/src/test/ui/consts/const-array-oob-arith.rs @@ -4,8 +4,12 @@ const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47]; const IDX: usize = 3; const VAL: i32 = ARR[IDX]; const BONG: [i32; (ARR[0] - 41) as usize] = [5]; -const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; //~ ERROR: mismatched types -const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; //~ ERROR: mismatched types +const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; +//~^ ERROR: mismatched types +//~| expected an array with a fixed size of 2 elements, found one with 1 element +const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; +//~^ ERROR: mismatched types +//~| expected an array with a fixed size of 1 element, found one with 2 elements fn main() { let _ = VAL; diff --git a/src/test/ui/consts/const-array-oob-arith.stderr b/src/test/ui/consts/const-array-oob-arith.stderr index edd3095b0fc7d..987e7ddf4d91e 100644 --- a/src/test/ui/consts/const-array-oob-arith.stderr +++ b/src/test/ui/consts/const-array-oob-arith.stderr @@ -1,17 +1,17 @@ error[E0308]: mismatched types --> $DIR/const-array-oob-arith.rs:7:45 | -LL | const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; //~ ERROR: mismatched types - | ^^^ expected an array with a fixed size of 2 elements, found one with 1 elements +LL | const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; + | ^^^ expected an array with a fixed size of 2 elements, found one with 1 element | = note: expected type `[i32; 2]` found type `[i32; 1]` error[E0308]: mismatched types - --> $DIR/const-array-oob-arith.rs:8:44 + --> $DIR/const-array-oob-arith.rs:10:44 | -LL | const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; //~ ERROR: mismatched types - | ^^^^^^^ expected an array with a fixed size of 1 elements, found one with 2 elements +LL | const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; + | ^^^^^^^ expected an array with a fixed size of 1 element, found one with 2 elements | = note: expected type `[i32; 1]` found type `[i32; 2]` diff --git a/src/test/ui/consts/const-array-oob.rs b/src/test/ui/consts/const-array-oob.rs index 39ef45175f9e3..1174a76adabcb 100644 --- a/src/test/ui/consts/const-array-oob.rs +++ b/src/test/ui/consts/const-array-oob.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - #![feature(const_indexing)] const FOO: [usize; 3] = [1, 2, 3]; diff --git a/src/test/ui/consts/const-array-oob.stderr b/src/test/ui/consts/const-array-oob.stderr index 2d9a4fd0dea27..f25cac5cddd47 100644 --- a/src/test/ui/consts/const-array-oob.stderr +++ b/src/test/ui/consts/const-array-oob.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const-array-oob.rs:8:19 + --> $DIR/const-array-oob.rs:6:19 | LL | const BLUB: [u32; FOO[4]] = [5, 6]; | ^^^^^^ index out of bounds: the len is 3 but the index is 4 diff --git a/src/test/ui/consts/const-call.stderr b/src/test/ui/consts/const-call.stderr index 12a6983ba1f45..d11add818d939 100644 --- a/src/test/ui/consts/const-call.stderr +++ b/src/test/ui/consts/const-call.stderr @@ -12,5 +12,5 @@ LL | let _ = [0; f(2)]; error: aborting due to 2 previous errors -Some errors occurred: E0015, E0080. +Some errors have detailed explanations: E0015, E0080. For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/const-cast-different-types.stderr b/src/test/ui/consts/const-cast-different-types.stderr index ced9b9fb3c7c9..9960ccb4166b5 100644 --- a/src/test/ui/consts/const-cast-different-types.stderr +++ b/src/test/ui/consts/const-cast-different-types.stderr @@ -1,13 +1,13 @@ error[E0606]: casting `&'static str` as `*const u8` is invalid --> $DIR/const-cast-different-types.rs:2:23 | -LL | static b: *const u8 = a as *const u8; //~ ERROR casting +LL | static b: *const u8 = a as *const u8; | ^^^^^^^^^^^^^^ error[E0606]: casting `&&'static str` as `*const u8` is invalid --> $DIR/const-cast-different-types.rs:3:23 | -LL | static c: *const u8 = &a as *const u8; //~ ERROR casting +LL | static c: *const u8 = &a as *const u8; | ^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-cast-wrong-type.stderr b/src/test/ui/consts/const-cast-wrong-type.stderr index 7684822d9393b..ad816d9297bd0 100644 --- a/src/test/ui/consts/const-cast-wrong-type.stderr +++ b/src/test/ui/consts/const-cast-wrong-type.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/const-cast-wrong-type.rs:2:23 | -LL | static b: *const i8 = &a as *const i8; //~ ERROR mismatched types +LL | static b: *const i8 = &a as *const i8; | ^^^^^^^^^^^^^^^ expected u8, found i8 error: aborting due to previous error diff --git a/src/test/ui/consts/const-deref-ptr.stderr b/src/test/ui/consts/const-deref-ptr.stderr index 8de0f6c151450..23ac3b85ee66d 100644 --- a/src/test/ui/consts/const-deref-ptr.stderr +++ b/src/test/ui/consts/const-deref-ptr.stderr @@ -1,9 +1,10 @@ -error[E0658]: dereferencing raw pointers in statics is unstable (see issue #51911) +error[E0658]: dereferencing raw pointers in statics is unstable --> $DIR/const-deref-ptr.rs:4:29 | LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/consts/const-err-early.stderr b/src/test/ui/consts/const-err-early.stderr index a64f0e2594951..9b0ef94a5b8c3 100644 --- a/src/test/ui/consts/const-err-early.stderr +++ b/src/test/ui/consts/const-err-early.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error - --> $DIR/const-err-early.rs:3:1 + --> $DIR/const-err-early.rs:3:19 | -LL | pub const A: i8 = -std::i8::MIN; //~ ERROR const_err - | ^^^^^^^^^^^^^^^^^^-------------^ +LL | pub const A: i8 = -std::i8::MIN; + | ------------------^^^^^^^^^^^^^- | | | attempt to negate with overflow | @@ -13,34 +13,34 @@ LL | #![deny(const_err)] | ^^^^^^^^^ error: any use of this value will cause an error - --> $DIR/const-err-early.rs:4:1 + --> $DIR/const-err-early.rs:4:19 | -LL | pub const B: u8 = 200u8 + 200u8; //~ ERROR const_err - | ^^^^^^^^^^^^^^^^^^-------------^ +LL | pub const B: u8 = 200u8 + 200u8; + | ------------------^^^^^^^^^^^^^- | | | attempt to add with overflow error: any use of this value will cause an error - --> $DIR/const-err-early.rs:5:1 + --> $DIR/const-err-early.rs:5:19 | -LL | pub const C: u8 = 200u8 * 4; //~ ERROR const_err - | ^^^^^^^^^^^^^^^^^^---------^ +LL | pub const C: u8 = 200u8 * 4; + | ------------------^^^^^^^^^- | | | attempt to multiply with overflow error: any use of this value will cause an error - --> $DIR/const-err-early.rs:6:1 + --> $DIR/const-err-early.rs:6:19 | -LL | pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR const_err - | ^^^^^^^^^^^^^^^^^^-----------------^ +LL | pub const D: u8 = 42u8 - (42u8 + 1); + | ------------------^^^^^^^^^^^^^^^^^- | | | attempt to subtract with overflow error: any use of this value will cause an error - --> $DIR/const-err-early.rs:7:1 + --> $DIR/const-err-early.rs:7:19 | -LL | pub const E: u8 = [5u8][1]; //~ ERROR const_err - | ^^^^^^^^^^^^^^^^^^--------^ +LL | pub const E: u8 = [5u8][1]; + | ------------------^^^^^^^^- | | | index out of bounds: the len is 1 but the index is 1 diff --git a/src/test/ui/consts/const-err-multi.stderr b/src/test/ui/consts/const-err-multi.stderr index af62665c056b0..c647f13fc7520 100644 --- a/src/test/ui/consts/const-err-multi.stderr +++ b/src/test/ui/consts/const-err-multi.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error - --> $DIR/const-err-multi.rs:3:1 + --> $DIR/const-err-multi.rs:3:19 | LL | pub const A: i8 = -std::i8::MIN; - | ^^^^^^^^^^^^^^^^^^-------------^ + | ------------------^^^^^^^^^^^^^- | | | attempt to negate with overflow | @@ -13,26 +13,26 @@ LL | #![deny(const_err)] | ^^^^^^^^^ error: any use of this value will cause an error - --> $DIR/const-err-multi.rs:5:1 + --> $DIR/const-err-multi.rs:5:19 | LL | pub const B: i8 = A; - | ^^^^^^^^^^^^^^^^^^-^ + | ------------------^- | | | referenced constant has errors error: any use of this value will cause an error - --> $DIR/const-err-multi.rs:7:1 + --> $DIR/const-err-multi.rs:7:19 | LL | pub const C: u8 = A as u8; - | ^^^^^^^^^^^^^^^^^^-------^ + | ------------------^^^^^^^- | | | referenced constant has errors error: any use of this value will cause an error - --> $DIR/const-err-multi.rs:9:1 + --> $DIR/const-err-multi.rs:9:19 | LL | pub const D: i8 = 50 - A; - | ^^^^^^^^^^^^^^^^^^------^ + | ------------------^^^^^^- | | | referenced constant has errors diff --git a/src/test/ui/consts/const-err.rs b/src/test/ui/consts/const-err.rs index 8cc3dc7f58744..7dfcda69058ac 100644 --- a/src/test/ui/consts/const-err.rs +++ b/src/test/ui/consts/const-err.rs @@ -13,4 +13,5 @@ const FOO: u8 = [5u8][1]; fn main() { black_box((FOO, FOO)); //~^ ERROR erroneous constant used + //~| ERROR erroneous constant } diff --git a/src/test/ui/consts/const-err.stderr b/src/test/ui/consts/const-err.stderr index 082494b43c25b..429e2ae7600d6 100644 --- a/src/test/ui/consts/const-err.stderr +++ b/src/test/ui/consts/const-err.stderr @@ -1,8 +1,8 @@ warning: any use of this value will cause an error - --> $DIR/const-err.rs:10:1 + --> $DIR/const-err.rs:10:17 | LL | const FOO: u8 = [5u8][1]; - | ^^^^^^^^^^^^^^^^--------^ + | ----------------^^^^^^^^- | | | index out of bounds: the len is 1 but the index is 1 | @@ -13,11 +13,17 @@ LL | #![warn(const_err)] | ^^^^^^^^^ error[E0080]: erroneous constant used - --> $DIR/const-err.rs:14:15 + --> $DIR/const-err.rs:14:16 | LL | black_box((FOO, FOO)); - | ^^^^^^^^^^ referenced constant has errors + | ^^^ referenced constant has errors -error: aborting due to previous error +error[E0080]: erroneous constant used + --> $DIR/const-err.rs:14:21 + | +LL | black_box((FOO, FOO)); + | ^^^ referenced constant has errors + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr index be1be6c060071..148b1210d39e1 100644 --- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr @@ -1,7 +1,7 @@ error[E0019]: static contains unimplemented expression type --> $DIR/assign-to-static-within-other-static-2.rs:16:5 | -LL | *FOO.0.get() = 5; //~ ERROR contains unimplemented expression type +LL | *FOO.0.get() = 5; | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr index 31e49dc10ca60..02b72765b377e 100644 --- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr @@ -1,7 +1,7 @@ error: cannot mutate statics in the initializer of another static --> $DIR/assign-to-static-within-other-static.rs:10:5 | -LL | FOO = 5; //~ ERROR cannot mutate statics in the initializer of another static +LL | FOO = 5; | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr index 7722c7423fc87..7f94d849c006c 100644 --- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr +++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr @@ -1,8 +1,8 @@ warning: any use of this value will cause an error - --> $DIR/conditional_array_execution.rs:5:1 + --> $DIR/conditional_array_execution.rs:5:19 | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ^^^^^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------^^^^^--------------------------- | | | attempt to subtract with overflow | diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs index d9b06370dff79..db6f17a671aea 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs @@ -7,12 +7,6 @@ // types for the left- and right-hand sides of the addition do not // match (as well as overflow). - - - - - - #![allow(unused_imports)] use std::fmt; @@ -32,4 +26,3 @@ fn main() { fn foo(x: T) { println!("{:?}", x); } - diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr index 59a9d25c71907..f6b6b5882ba3c 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types - --> $DIR/const-eval-overflow-3b.rs:24:22 + --> $DIR/const-eval-overflow-3b.rs:18:22 | LL | = [0; (i8::MAX + 1u8) as usize]; | ^^^ expected i8, found u8 error[E0277]: cannot add `u8` to `i8` - --> $DIR/const-eval-overflow-3b.rs:24:20 + --> $DIR/const-eval-overflow-3b.rs:18:20 | LL | = [0; (i8::MAX + 1u8) as usize]; | ^ no implementation for `i8 + u8` @@ -14,5 +14,5 @@ LL | = [0; (i8::MAX + 1u8) as usize]; error: aborting due to 2 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr index 0c2f76a5582e9..3735b2fd5ff1a 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -20,5 +20,5 @@ LL | : [u32; 5i8 as char as usize] error: aborting due to 3 previous errors -Some errors occurred: E0277, E0308, E0604. +Some errors have detailed explanations: E0277, E0308, E0604. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2.rs b/src/test/ui/consts/const-eval/const-eval-overflow2.rs index 4700c63adbcb3..a0dbcc88cea8a 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow2.rs @@ -11,43 +11,51 @@ use std::fmt; use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; -const VALS_I8: (i8,) = //~ ERROR any use of this value will cause an error +const VALS_I8: (i8,) = ( i8::MIN - 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_I16: (i16,) = //~ ERROR any use of this value will cause an error +const VALS_I16: (i16,) = ( i16::MIN - 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_I32: (i32,) = //~ ERROR any use of this value will cause an error +const VALS_I32: (i32,) = ( i32::MIN - 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_I64: (i64,) = //~ ERROR any use of this value will cause an error +const VALS_I64: (i64,) = ( i64::MIN - 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_U8: (u8,) = //~ ERROR any use of this value will cause an error +const VALS_U8: (u8,) = ( u8::MIN - 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_U16: (u16,) = ( //~ ERROR any use of this value will cause an error +const VALS_U16: (u16,) = ( u16::MIN - 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_U32: (u32,) = ( //~ ERROR any use of this value will cause an error +const VALS_U32: (u32,) = ( u32::MIN - 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_U64: (u64,) = //~ ERROR any use of this value will cause an error +const VALS_U64: (u64,) = ( u64::MIN - 1, ); + //~^^ ERROR any use of this value will cause an error fn main() { foo(VALS_I8); diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr index 5ec2a2feb0978..419b3d52dbff1 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr @@ -1,12 +1,12 @@ error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:14:1 + --> $DIR/const-eval-overflow2.rs:16:6 | -LL | / const VALS_I8: (i8,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_I8: (i8,) = LL | | ( LL | | i8::MIN - 1, - | | ----------- attempt to subtract with overflow + | | ^^^^^^^^^^^ attempt to subtract with overflow LL | | ); - | |_______^ + | |_______- | note: lint level defined here --> $DIR/const-eval-overflow2.rs:8:9 @@ -15,72 +15,72 @@ LL | #![deny(const_err)] | ^^^^^^^^^ error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:19:1 + --> $DIR/const-eval-overflow2.rs:22:6 | -LL | / const VALS_I16: (i16,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_I16: (i16,) = LL | | ( LL | | i16::MIN - 1, - | | ------------ attempt to subtract with overflow + | | ^^^^^^^^^^^^ attempt to subtract with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:24:1 + --> $DIR/const-eval-overflow2.rs:28:6 | -LL | / const VALS_I32: (i32,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_I32: (i32,) = LL | | ( LL | | i32::MIN - 1, - | | ------------ attempt to subtract with overflow + | | ^^^^^^^^^^^^ attempt to subtract with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:29:1 + --> $DIR/const-eval-overflow2.rs:34:6 | -LL | / const VALS_I64: (i64,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_I64: (i64,) = LL | | ( LL | | i64::MIN - 1, - | | ------------ attempt to subtract with overflow + | | ^^^^^^^^^^^^ attempt to subtract with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:34:1 + --> $DIR/const-eval-overflow2.rs:40:6 | -LL | / const VALS_U8: (u8,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_U8: (u8,) = LL | | ( LL | | u8::MIN - 1, - | | ----------- attempt to subtract with overflow + | | ^^^^^^^^^^^ attempt to subtract with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:39:1 + --> $DIR/const-eval-overflow2.rs:45:6 | -LL | / const VALS_U16: (u16,) = ( //~ ERROR any use of this value will cause an error +LL | / const VALS_U16: (u16,) = ( LL | | u16::MIN - 1, - | | ------------ attempt to subtract with overflow + | | ^^^^^^^^^^^^ attempt to subtract with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:43:1 + --> $DIR/const-eval-overflow2.rs:50:6 | -LL | / const VALS_U32: (u32,) = ( //~ ERROR any use of this value will cause an error +LL | / const VALS_U32: (u32,) = ( LL | | u32::MIN - 1, - | | ------------ attempt to subtract with overflow + | | ^^^^^^^^^^^^ attempt to subtract with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:47:1 + --> $DIR/const-eval-overflow2.rs:56:6 | -LL | / const VALS_U64: (u64,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_U64: (u64,) = LL | | ( LL | | u64::MIN - 1, - | | ------------ attempt to subtract with overflow + | | ^^^^^^^^^^^^ attempt to subtract with overflow LL | | ); - | |_______^ + | |_______- error: aborting due to 8 previous errors diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2b.rs b/src/test/ui/consts/const-eval/const-eval-overflow2b.rs index 6bed90aa8ea65..da883671a60a3 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2b.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow2b.rs @@ -11,43 +11,51 @@ use std::fmt; use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; -const VALS_I8: (i8,) = //~ ERROR any use of this value will cause an error +const VALS_I8: (i8,) = ( i8::MAX + 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_I16: (i16,) = //~ ERROR any use of this value will cause an error +const VALS_I16: (i16,) = ( i16::MAX + 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_I32: (i32,) = //~ ERROR any use of this value will cause an error +const VALS_I32: (i32,) = ( i32::MAX + 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_I64: (i64,) = //~ ERROR any use of this value will cause an error +const VALS_I64: (i64,) = ( i64::MAX + 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_U8: (u8,) = //~ ERROR any use of this value will cause an error +const VALS_U8: (u8,) = ( u8::MAX + 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_U16: (u16,) = ( //~ ERROR any use of this value will cause an error +const VALS_U16: (u16,) = ( u16::MAX + 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_U32: (u32,) = ( //~ ERROR any use of this value will cause an error +const VALS_U32: (u32,) = ( u32::MAX + 1, ); + //~^^ ERROR any use of this value will cause an error -const VALS_U64: (u64,) = //~ ERROR any use of this value will cause an error +const VALS_U64: (u64,) = ( u64::MAX + 1, ); + //~^^ ERROR any use of this value will cause an error fn main() { foo(VALS_I8); diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr index 7866b6c30c3d6..2cfd34c9fc3c7 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr @@ -1,12 +1,12 @@ error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:14:1 + --> $DIR/const-eval-overflow2b.rs:16:6 | -LL | / const VALS_I8: (i8,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_I8: (i8,) = LL | | ( LL | | i8::MAX + 1, - | | ----------- attempt to add with overflow + | | ^^^^^^^^^^^ attempt to add with overflow LL | | ); - | |_______^ + | |_______- | note: lint level defined here --> $DIR/const-eval-overflow2b.rs:8:9 @@ -15,72 +15,72 @@ LL | #![deny(const_err)] | ^^^^^^^^^ error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:19:1 + --> $DIR/const-eval-overflow2b.rs:22:6 | -LL | / const VALS_I16: (i16,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_I16: (i16,) = LL | | ( LL | | i16::MAX + 1, - | | ------------ attempt to add with overflow + | | ^^^^^^^^^^^^ attempt to add with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:24:1 + --> $DIR/const-eval-overflow2b.rs:28:6 | -LL | / const VALS_I32: (i32,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_I32: (i32,) = LL | | ( LL | | i32::MAX + 1, - | | ------------ attempt to add with overflow + | | ^^^^^^^^^^^^ attempt to add with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:29:1 + --> $DIR/const-eval-overflow2b.rs:34:6 | -LL | / const VALS_I64: (i64,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_I64: (i64,) = LL | | ( LL | | i64::MAX + 1, - | | ------------ attempt to add with overflow + | | ^^^^^^^^^^^^ attempt to add with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:34:1 + --> $DIR/const-eval-overflow2b.rs:40:6 | -LL | / const VALS_U8: (u8,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_U8: (u8,) = LL | | ( LL | | u8::MAX + 1, - | | ----------- attempt to add with overflow + | | ^^^^^^^^^^^ attempt to add with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:39:1 + --> $DIR/const-eval-overflow2b.rs:45:6 | -LL | / const VALS_U16: (u16,) = ( //~ ERROR any use of this value will cause an error +LL | / const VALS_U16: (u16,) = ( LL | | u16::MAX + 1, - | | ------------ attempt to add with overflow + | | ^^^^^^^^^^^^ attempt to add with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:43:1 + --> $DIR/const-eval-overflow2b.rs:50:6 | -LL | / const VALS_U32: (u32,) = ( //~ ERROR any use of this value will cause an error +LL | / const VALS_U32: (u32,) = ( LL | | u32::MAX + 1, - | | ------------ attempt to add with overflow + | | ^^^^^^^^^^^^ attempt to add with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:47:1 + --> $DIR/const-eval-overflow2b.rs:56:6 | -LL | / const VALS_U64: (u64,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_U64: (u64,) = LL | | ( LL | | u64::MAX + 1, - | | ------------ attempt to add with overflow + | | ^^^^^^^^^^^^ attempt to add with overflow LL | | ); - | |_______^ + | |_______- error: aborting due to 8 previous errors diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2c.rs b/src/test/ui/consts/const-eval/const-eval-overflow2c.rs index 108251e4bd281..e87344405a103 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2c.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow2c.rs @@ -11,43 +11,51 @@ use std::fmt; use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; -const VALS_I8: (i8,) = //~ ERROR any use of this value will cause an error +const VALS_I8: (i8,) = ( i8::MIN * 2, ); + //~^^ ERROR any use of this value will cause an error -const VALS_I16: (i16,) = //~ ERROR any use of this value will cause an error +const VALS_I16: (i16,) = ( i16::MIN * 2, ); + //~^^ ERROR any use of this value will cause an error -const VALS_I32: (i32,) = //~ ERROR any use of this value will cause an error +const VALS_I32: (i32,) = ( i32::MIN * 2, ); + //~^^ ERROR any use of this value will cause an error -const VALS_I64: (i64,) = //~ ERROR any use of this value will cause an error +const VALS_I64: (i64,) = ( i64::MIN * 2, ); + //~^^ ERROR any use of this value will cause an error -const VALS_U8: (u8,) = //~ ERROR any use of this value will cause an error +const VALS_U8: (u8,) = ( u8::MAX * 2, ); + //~^^ ERROR any use of this value will cause an error -const VALS_U16: (u16,) = ( //~ ERROR any use of this value will cause an error +const VALS_U16: (u16,) = ( u16::MAX * 2, ); + //~^^ ERROR any use of this value will cause an error -const VALS_U32: (u32,) = ( //~ ERROR any use of this value will cause an error +const VALS_U32: (u32,) = ( u32::MAX * 2, ); + //~^^ ERROR any use of this value will cause an error -const VALS_U64: (u64,) = //~ ERROR any use of this value will cause an error +const VALS_U64: (u64,) = ( u64::MAX * 2, ); + //~^^ ERROR any use of this value will cause an error fn main() { foo(VALS_I8); diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr index 5370fdd25d820..5e63286c594d9 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr @@ -1,12 +1,12 @@ error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:14:1 + --> $DIR/const-eval-overflow2c.rs:16:6 | -LL | / const VALS_I8: (i8,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_I8: (i8,) = LL | | ( LL | | i8::MIN * 2, - | | ----------- attempt to multiply with overflow + | | ^^^^^^^^^^^ attempt to multiply with overflow LL | | ); - | |_______^ + | |_______- | note: lint level defined here --> $DIR/const-eval-overflow2c.rs:8:9 @@ -15,72 +15,72 @@ LL | #![deny(const_err)] | ^^^^^^^^^ error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:19:1 + --> $DIR/const-eval-overflow2c.rs:22:6 | -LL | / const VALS_I16: (i16,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_I16: (i16,) = LL | | ( LL | | i16::MIN * 2, - | | ------------ attempt to multiply with overflow + | | ^^^^^^^^^^^^ attempt to multiply with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:24:1 + --> $DIR/const-eval-overflow2c.rs:28:6 | -LL | / const VALS_I32: (i32,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_I32: (i32,) = LL | | ( LL | | i32::MIN * 2, - | | ------------ attempt to multiply with overflow + | | ^^^^^^^^^^^^ attempt to multiply with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:29:1 + --> $DIR/const-eval-overflow2c.rs:34:6 | -LL | / const VALS_I64: (i64,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_I64: (i64,) = LL | | ( LL | | i64::MIN * 2, - | | ------------ attempt to multiply with overflow + | | ^^^^^^^^^^^^ attempt to multiply with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:34:1 + --> $DIR/const-eval-overflow2c.rs:40:6 | -LL | / const VALS_U8: (u8,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_U8: (u8,) = LL | | ( LL | | u8::MAX * 2, - | | ----------- attempt to multiply with overflow + | | ^^^^^^^^^^^ attempt to multiply with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:39:1 + --> $DIR/const-eval-overflow2c.rs:45:6 | -LL | / const VALS_U16: (u16,) = ( //~ ERROR any use of this value will cause an error +LL | / const VALS_U16: (u16,) = ( LL | | u16::MAX * 2, - | | ------------ attempt to multiply with overflow + | | ^^^^^^^^^^^^ attempt to multiply with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:43:1 + --> $DIR/const-eval-overflow2c.rs:50:6 | -LL | / const VALS_U32: (u32,) = ( //~ ERROR any use of this value will cause an error +LL | / const VALS_U32: (u32,) = ( LL | | u32::MAX * 2, - | | ------------ attempt to multiply with overflow + | | ^^^^^^^^^^^^ attempt to multiply with overflow LL | | ); - | |_______^ + | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:47:1 + --> $DIR/const-eval-overflow2c.rs:56:6 | -LL | / const VALS_U64: (u64,) = //~ ERROR any use of this value will cause an error +LL | / const VALS_U64: (u64,) = LL | | ( LL | | u64::MAX * 2, - | | ------------ attempt to multiply with overflow + | | ^^^^^^^^^^^^ attempt to multiply with overflow LL | | ); - | |_______^ + | |_______- error: aborting due to 8 previous errors diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr index 786338222e3ba..284b06984a31c 100644 --- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr @@ -7,28 +7,28 @@ LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 } = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:27:5 + --> $DIR/const-pointer-values-in-various-types.rs:27:43 | LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^ + | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes | = note: #[deny(const_err)] on by default error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:30:5 + --> $DIR/const-pointer-values-in-various-types.rs:30:45 | LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^ + | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:33:5 + --> $DIR/const-pointer-values-in-various-types.rs:33:45 | LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^ + | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes @@ -49,26 +49,26 @@ LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.u = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:42:5 + --> $DIR/const-pointer-values-in-various-types.rs:42:43 | LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^^^ + | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:45:5 + --> $DIR/const-pointer-values-in-various-types.rs:45:45 | LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^ + | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:48:5 + --> $DIR/const-pointer-values-in-various-types.rs:48:45 | LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^ + | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes @@ -89,10 +89,10 @@ LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.i = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:57:5 + --> $DIR/const-pointer-values-in-various-types.rs:57:45 | LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes @@ -105,42 +105,42 @@ LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.flo = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:63:5 + --> $DIR/const-pointer-values-in-various-types.rs:63:47 | LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------------^^^ + | ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:66:5 + --> $DIR/const-pointer-values-in-various-types.rs:66:47 | LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------------^^^ + | ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:69:5 + --> $DIR/const-pointer-values-in-various-types.rs:69:39 | LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------^^^ + | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:72:5 + --> $DIR/const-pointer-values-in-various-types.rs:72:41 | LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^^^ + | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:75:5 + --> $DIR/const-pointer-values-in-various-types.rs:75:41 | LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^^^ + | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes @@ -153,34 +153,34 @@ LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 } = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:81:5 + --> $DIR/const-pointer-values-in-various-types.rs:81:43 | LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^ + | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:84:5 + --> $DIR/const-pointer-values-in-various-types.rs:84:39 | LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------^^^ + | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:87:5 + --> $DIR/const-pointer-values-in-various-types.rs:87:41 | LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------^^^ + | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:90:5 + --> $DIR/const-pointer-values-in-various-types.rs:90:41 | LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------^^^ + | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes @@ -193,18 +193,18 @@ LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:96:5 + --> $DIR/const-pointer-values-in-various-types.rs:96:43 | LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^^^ + | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:99:5 + --> $DIR/const-pointer-values-in-various-types.rs:99:41 | LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^ + | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes @@ -217,18 +217,18 @@ LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:105:5 + --> $DIR/const-pointer-values-in-various-types.rs:105:43 | LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^^^ + | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:108:5 + --> $DIR/const-pointer-values-in-various-types.rs:108:43 | LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^ + | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | a raw memory access tried to access part of a pointer value as raw bytes diff --git a/src/test/ui/consts/const-eval/const_panic.stderr b/src/test/ui/consts/const-eval/const_panic.stderr index eecac7c71075b..12c7e3d34ab9e 100644 --- a/src/test/ui/consts/const-eval/const_panic.stderr +++ b/src/test/ui/consts/const-eval/const_panic.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error - --> $DIR/const_panic.rs:4:1 + --> $DIR/const_panic.rs:4:19 | LL | pub const Z: () = panic!("cheese"); - | ^^^^^^^^^^^^^^^^^^----------------^ + | ------------------^^^^^^^^^^^^^^^^- | | | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:4:19 | @@ -10,20 +10,20 @@ LL | pub const Z: () = panic!("cheese"); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:7:1 + --> $DIR/const_panic.rs:7:19 | LL | pub const Y: () = unreachable!(); - | ^^^^^^^^^^^^^^^^^^--------------^ + | ------------------^^^^^^^^^^^^^^- | | | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:7:19 | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:10:1 + --> $DIR/const_panic.rs:10:19 | LL | pub const X: () = unimplemented!(); - | ^^^^^^^^^^^^^^^^^^----------------^ + | ------------------^^^^^^^^^^^^^^^^- | | | the evaluated program panicked at 'not yet implemented', $DIR/const_panic.rs:10:19 | diff --git a/src/test/ui/consts/const-eval/const_panic_libcore.stderr b/src/test/ui/consts/const-eval/const_panic_libcore.stderr index 83c89c329dcf5..9dddac49c92b8 100644 --- a/src/test/ui/consts/const-eval/const_panic_libcore.stderr +++ b/src/test/ui/consts/const-eval/const_panic_libcore.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error - --> $DIR/const_panic_libcore.rs:5:1 + --> $DIR/const_panic_libcore.rs:5:15 | LL | const Z: () = panic!("cheese"); - | ^^^^^^^^^^^^^^----------------^ + | --------------^^^^^^^^^^^^^^^^- | | | the evaluated program panicked at 'cheese', $DIR/const_panic_libcore.rs:5:15 | @@ -10,20 +10,20 @@ LL | const Z: () = panic!("cheese"); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic_libcore.rs:8:1 + --> $DIR/const_panic_libcore.rs:8:15 | LL | const Y: () = unreachable!(); - | ^^^^^^^^^^^^^^--------------^ + | --------------^^^^^^^^^^^^^^- | | | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore.rs:8:15 | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic_libcore.rs:11:1 + --> $DIR/const_panic_libcore.rs:11:15 | LL | const X: () = unimplemented!(); - | ^^^^^^^^^^^^^^----------------^ + | --------------^^^^^^^^^^^^^^^^- | | | the evaluated program panicked at 'not yet implemented', $DIR/const_panic_libcore.rs:11:15 | diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_main.stderr b/src/test/ui/consts/const-eval/const_panic_libcore_main.stderr index 4cc48618e3212..df04a03681127 100644 --- a/src/test/ui/consts/const-eval/const_panic_libcore_main.stderr +++ b/src/test/ui/consts/const-eval/const_panic_libcore_main.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error - --> $DIR/const_panic_libcore_main.rs:9:1 + --> $DIR/const_panic_libcore_main.rs:9:15 | LL | const Z: () = panic!("cheese"); - | ^^^^^^^^^^^^^^----------------^ + | --------------^^^^^^^^^^^^^^^^- | | | the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_main.rs:9:15 | @@ -10,20 +10,20 @@ LL | const Z: () = panic!("cheese"); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic_libcore_main.rs:12:1 + --> $DIR/const_panic_libcore_main.rs:12:15 | LL | const Y: () = unreachable!(); - | ^^^^^^^^^^^^^^--------------^ + | --------------^^^^^^^^^^^^^^- | | | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_main.rs:12:15 | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic_libcore_main.rs:15:1 + --> $DIR/const_panic_libcore_main.rs:15:15 | LL | const X: () = unimplemented!(); - | ^^^^^^^^^^^^^^----------------^ + | --------------^^^^^^^^^^^^^^^^- | | | the evaluated program panicked at 'not yet implemented', $DIR/const_panic_libcore_main.rs:15:15 | diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr index 6be54c0bad4f9..0d4c0b98879cc 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr @@ -1,34 +1,34 @@ error: any use of this value will cause an error - --> $DIR/const_raw_ptr_ops.rs:6:1 + --> $DIR/const_raw_ptr_ops.rs:6:26 | -LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR any use of this - | ^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ +LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; + | -------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | "pointer arithmetic or comparison" needs an rfc before being allowed inside constants | = note: #[deny(const_err)] on by default error: any use of this value will cause an error - --> $DIR/const_raw_ptr_ops.rs:12:1 + --> $DIR/const_raw_ptr_ops.rs:12:28 | -LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------^^^ +LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; + | ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | "pointer arithmetic or comparison" needs an rfc before being allowed inside constants error: any use of this value will cause an error - --> $DIR/const_raw_ptr_ops.rs:16:1 + --> $DIR/const_raw_ptr_ops.rs:16:26 | -LL | const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause - | ^^^^^^^^^^^^^^^^^^^^^^^^^-------------------^^^ +LL | const Z2: i32 = unsafe { *(42 as *const i32) }; + | -------------------------^^^^^^^^^^^^^^^^^^^--- | | | a memory access tried to interpret some bytes as a pointer error: any use of this value will cause an error - --> $DIR/const_raw_ptr_ops.rs:17:1 + --> $DIR/const_raw_ptr_ops.rs:17:26 | -LL | const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause - | ^^^^^^^^^^^^^^^^^^^^^^^^^-------------------^^^ +LL | const Z3: i32 = unsafe { *(44 as *const i32) }; + | -------------------------^^^^^^^^^^^^^^^^^^^--- | | | a memory access tried to interpret some bytes as a pointer diff --git a/src/test/ui/consts/const-eval/const_transmute.rs b/src/test/ui/consts/const-eval/const_transmute.rs index e4f7fb155ab90..0e0e003dcf476 100644 --- a/src/test/ui/consts/const-eval/const_transmute.rs +++ b/src/test/ui/consts/const-eval/const_transmute.rs @@ -1,4 +1,3 @@ -// compile-pass // run-pass #![feature(const_fn_union)] @@ -41,7 +40,7 @@ struct VTable { bar: for<'a> fn(&'a Foo) -> u32, } -const FOO: &Bar = &Foo { foo: 128, bar: false }; +const FOO: &dyn Bar = &Foo { foo: 128, bar: false }; const G: Fat = unsafe { Transmute { t: FOO }.u }; const F: Option fn(&'a mut Foo)> = G.1.drop; const H: for<'a> fn(&'a Foo) -> u32 = G.1.bar; diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr deleted file mode 100644 index 238db527e3883..0000000000000 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error: `foo` is not yet stable as a const fn - --> $DIR/dont_promote_unstable_const_fn.rs:15:25 - | -LL | const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn - | ^^^^^ - | - = help: add `#![feature(foo)]` to the crate attributes to enable - -error[E0716]: temporary value dropped while borrowed - --> $DIR/dont_promote_unstable_const_fn.rs:18:28 - | -LL | let _: &'static u32 = &foo(); //~ ERROR does not live long enough - | ------------ ^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/dont_promote_unstable_const_fn.rs:22:28 - | -LL | let _: &'static u32 = &meh(); //~ ERROR does not live long enough - | ------------ ^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/dont_promote_unstable_const_fn.rs:23:26 - | -LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | //~^ ERROR does not live long enough -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs index 7170be1b88baf..900286909902c 100644 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs @@ -15,11 +15,11 @@ fn meh() -> u32 { 42 } const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn fn a() { - let _: &'static u32 = &foo(); //~ ERROR does not live long enough + let _: &'static u32 = &foo(); //~ ERROR temporary value dropped while borrowed } fn main() { - let _: &'static u32 = &meh(); //~ ERROR does not live long enough + let _: &'static u32 = &meh(); //~ ERROR temporary value dropped while borrowed let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); - //~^ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr index fdbc4cb0c8d27..ca80a9ab39117 100644 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr @@ -1,43 +1,43 @@ error: `foo` is not yet stable as a const fn --> $DIR/dont_promote_unstable_const_fn.rs:15:25 | -LL | const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn +LL | const fn bar() -> u32 { foo() } | ^^^^^ | = help: add `#![feature(foo)]` to the crate attributes to enable -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/dont_promote_unstable_const_fn.rs:18:28 | -LL | let _: &'static u32 = &foo(); //~ ERROR does not live long enough - | ^^^^^ temporary value does not live long enough +LL | let _: &'static u32 = &foo(); + | ------------ ^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/dont_promote_unstable_const_fn.rs:22:28 | -LL | let _: &'static u32 = &meh(); //~ ERROR does not live long enough - | ^^^^^ temporary value does not live long enough +LL | let _: &'static u32 = &meh(); + | ------------ ^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/dont_promote_unstable_const_fn.rs:23:26 | LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -LL | //~^ ERROR does not live long enough + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr deleted file mode 100644 index 4355401987b01..0000000000000 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:8:28 - | -LL | let _: &'static u32 = &foo(); //~ ERROR does not live long enough - | ------------ ^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:9:29 - | -LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough - | ------------ ^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.rs b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.rs index 6dcfcfe6780c9..ea35f46807abb 100644 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.rs +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.rs @@ -5,6 +5,6 @@ extern crate stability; use stability::foo; fn main() { - let _: &'static u32 = &foo(); //~ ERROR does not live long enough - let _x: &'static u32 = &foo(); //~ ERROR does not live long enough + let _: &'static u32 = &foo(); //~ ERROR temporary value dropped while borrowed + let _x: &'static u32 = &foo(); //~ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.stderr index 8be7add22009e..129f06151074f 100644 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.stderr +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.stderr @@ -1,24 +1,24 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:8:28 | -LL | let _: &'static u32 = &foo(); //~ ERROR does not live long enough - | ^^^^^ temporary value does not live long enough -LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough +LL | let _: &'static u32 = &foo(); + | ------------ ^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | let _x: &'static u32 = &foo(); LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:9:29 | -LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough - | ^^^^^ temporary value does not live long enough +LL | let _x: &'static u32 = &foo(); + | ------------ ^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/double_check2.stderr b/src/test/ui/consts/const-eval/double_check2.stderr index 06b38bf710341..2b61d33852c98 100644 --- a/src/test/ui/consts/const-eval/double_check2.stderr +++ b/src/test/ui/consts/const-eval/double_check2.stderr @@ -1,7 +1,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/double_check2.rs:15:1 | -LL | / static FOO: (&Foo, &Bar) = unsafe {( //~ undefined behavior +LL | / static FOO: (&Foo, &Bar) = unsafe {( LL | | Union { u8: &BAR }.foo, LL | | Union { u8: &BAR }.bar, LL | | )}; diff --git a/src/test/ui/consts/const-eval/enum_discr.rs b/src/test/ui/consts/const-eval/enum_discr.rs index 4851e7520948d..e09258f11206e 100644 --- a/src/test/ui/consts/const-eval/enum_discr.rs +++ b/src/test/ui/consts/const-eval/enum_discr.rs @@ -1,4 +1,3 @@ -// compile-pass // run-pass enum Foo { diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr index c562c66389f97..069a8bfd4e704 100644 --- a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr +++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr @@ -1,9 +1,10 @@ -error[E0658]: unions in const fn are unstable (see issue #51909) +error[E0658]: unions in const fn are unstable --> $DIR/feature-gate-const_fn_union.rs:11:5 | -LL | Foo { u }.i //~ ERROR unions in const fn are unstable +LL | Foo { u }.i | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51909 = help: add #![feature(const_fn_union)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr b/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr index 0810341355669..5d3e88e4e58c2 100644 --- a/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr +++ b/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr @@ -1,27 +1,30 @@ -error[E0658]: panicking in constants is unstable (see issue #51999) +error[E0658]: panicking in constants is unstable --> $DIR/feature-gate-const_panic.rs:3:15 | LL | const Z: () = panic!("cheese"); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51999 = help: add #![feature(const_panic)] to the crate attributes to enable = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error[E0658]: panicking in constants is unstable (see issue #51999) +error[E0658]: panicking in constants is unstable --> $DIR/feature-gate-const_panic.rs:9:15 | LL | const X: () = unimplemented!(); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51999 = help: add #![feature(const_panic)] to the crate attributes to enable = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error[E0658]: panicking in constants is unstable (see issue #51999) +error[E0658]: panicking in constants is unstable --> $DIR/feature-gate-const_panic.rs:6:15 | LL | const Y: () = unreachable!(); | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51999 = help: add #![feature(const_panic)] to the crate attributes to enable = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/consts/const-eval/ice-generic-assoc-const.rs b/src/test/ui/consts/const-eval/ice-generic-assoc-const.rs index e92de84c27984..2ad1a633d125f 100644 --- a/src/test/ui/consts/const-eval/ice-generic-assoc-const.rs +++ b/src/test/ui/consts/const-eval/ice-generic-assoc-const.rs @@ -7,7 +7,7 @@ pub trait Nullable { } impl Nullable for *const T { - const NULL: Self = 0 as *const T; + const NULL: Self = core::ptr::null::(); fn is_null(&self) -> bool { *self == Self::NULL diff --git a/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr b/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr index 1a9e1b0ae8508..ac045f29b110d 100644 --- a/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr +++ b/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr @@ -1,7 +1,7 @@ error: index out of bounds: the len is 1 but the index is 1 --> $DIR/index_out_of_bounds_propagated.rs:3:5 | -LL | array[1]; //~ ERROR index out of bounds +LL | array[1]; | ^^^^^^^^ | = note: #[deny(const_err)] on by default diff --git a/src/test/ui/consts/const-eval/infinite_loop.stderr b/src/test/ui/consts/const-eval/infinite_loop.stderr index 422c2bab6ea90..3a7da9ff2c8d8 100644 --- a/src/test/ui/consts/const-eval/infinite_loop.stderr +++ b/src/test/ui/consts/const-eval/infinite_loop.stderr @@ -1,9 +1,9 @@ error[E0019]: constant contains unimplemented expression type --> $DIR/infinite_loop.rs:7:9 | -LL | / while n != 0 { //~ ERROR constant contains unimplemented expression type +LL | / while n != 0 { LL | | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; -LL | | //~^ ERROR evaluation of constant value failed +LL | | LL | | } | |_________^ @@ -12,9 +12,9 @@ warning: Constant evaluating a complex constant, this might take some time | LL | let _ = [(); { | __________________^ -LL | | //~^ WARNING Constant evaluating a complex constant, this might take some time +LL | | LL | | let mut n = 113383; // #20 in https://oeis.org/A006884 -LL | | while n != 0 { //~ ERROR constant contains unimplemented expression type +LL | | while n != 0 { ... | LL | | n LL | | }]; @@ -28,5 +28,5 @@ LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; error: aborting due to 2 previous errors -Some errors occurred: E0019, E0080. +Some errors have detailed explanations: E0019, E0080. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr index 84c686102609e..478e453fe0834 100644 --- a/src/test/ui/consts/const-eval/issue-43197.stderr +++ b/src/test/ui/consts/const-eval/issue-43197.stderr @@ -1,8 +1,8 @@ warning: any use of this value will cause an error - --> $DIR/issue-43197.rs:8:5 + --> $DIR/issue-43197.rs:8:20 | LL | const X: u32 = 0-1; - | ^^^^^^^^^^^^^^^---^ + | ---------------^^^- | | | attempt to subtract with overflow | @@ -13,10 +13,10 @@ LL | #![warn(const_err)] | ^^^^^^^^^ warning: any use of this value will cause an error - --> $DIR/issue-43197.rs:10:5 + --> $DIR/issue-43197.rs:10:24 | LL | const Y: u32 = foo(0-1); - | ^^^^^^^^^^^^^^^^^^^---^^ + | -------------------^^^-- | | | attempt to subtract with overflow diff --git a/src/test/ui/consts/const-eval/issue-49296.stderr b/src/test/ui/consts/const-eval/issue-49296.stderr index 37462db4c965e..5a59a8b2dffcd 100644 --- a/src/test/ui/consts/const-eval/issue-49296.stderr +++ b/src/test/ui/consts/const-eval/issue-49296.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error - --> $DIR/issue-49296.rs:18:1 + --> $DIR/issue-49296.rs:18:16 | LL | const X: u64 = *wat(42); - | ^^^^^^^^^^^^^^^--------^ + | ---------------^^^^^^^^- | | | dangling pointer was dereferenced | diff --git a/src/test/ui/consts/const-eval/issue-50814-2.stderr b/src/test/ui/consts/const-eval/issue-50814-2.stderr index 7c2cd7c5ca043..da560046c547c 100644 --- a/src/test/ui/consts/const-eval/issue-50814-2.stderr +++ b/src/test/ui/consts/const-eval/issue-50814-2.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error - --> $DIR/issue-50814-2.rs:12:5 + --> $DIR/issue-50814-2.rs:12:24 | -LL | const BAR: usize = [5, 6, 7][T::BOO]; //~ ERROR any use of this value will cause an error - | ^^^^^^^^^^^^^^^^^^^-----------------^ +LL | const BAR: usize = [5, 6, 7][T::BOO]; + | -------------------^^^^^^^^^^^^^^^^^- | | | index out of bounds: the len is 3 but the index is 42 | @@ -11,7 +11,7 @@ LL | const BAR: usize = [5, 6, 7][T::BOO]; //~ ERROR any use of this value w error[E0080]: evaluation of constant expression failed --> $DIR/issue-50814-2.rs:16:5 | -LL | & as Foo>::BAR //~ ERROR E0080 +LL | & as Foo>::BAR | ^--------------------- | | | referenced constant has errors diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr index 757e55fe31d35..bc9443b26f5fd 100644 --- a/src/test/ui/consts/const-eval/issue-50814.stderr +++ b/src/test/ui/consts/const-eval/issue-50814.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error - --> $DIR/issue-50814.rs:13:5 + --> $DIR/issue-50814.rs:13:21 | -LL | const MAX: u8 = A::MAX + B::MAX; //~ ERROR any use of this value will cause an error - | ^^^^^^^^^^^^^^^^---------------^ +LL | const MAX: u8 = A::MAX + B::MAX; + | ----------------^^^^^^^^^^^^^^^- | | | attempt to add with overflow | @@ -11,7 +11,7 @@ LL | const MAX: u8 = A::MAX + B::MAX; //~ ERROR any use of this value will c error[E0080]: evaluation of constant expression failed --> $DIR/issue-50814.rs:17:5 | -LL | &Sum::::MAX //~ ERROR E0080 +LL | &Sum::::MAX | ^----------------- | | | referenced constant has errors diff --git a/src/test/ui/consts/const-eval/issue-52442.stderr b/src/test/ui/consts/const-eval/issue-52442.stderr index 516796c1a42da..e9afec5766a0c 100644 --- a/src/test/ui/consts/const-eval/issue-52442.stderr +++ b/src/test/ui/consts/const-eval/issue-52442.stderr @@ -1,18 +1,18 @@ error[E0019]: constant contains unimplemented expression type --> $DIR/issue-52442.rs:2:14 | -LL | [(); { &loop { break } as *const _ as usize } ]; //~ ERROR unimplemented expression type +LL | [(); { &loop { break } as *const _ as usize } ]; | ^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-52442.rs:2:11 | -LL | [(); { &loop { break } as *const _ as usize } ]; //~ ERROR unimplemented expression type +LL | [(); { &loop { break } as *const _ as usize } ]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: aborting due to 2 previous errors -Some errors occurred: E0019, E0080. +Some errors have detailed explanations: E0019, E0080. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/const-eval/issue-52475.stderr b/src/test/ui/consts/const-eval/issue-52475.stderr index 4f1b2ab4c8f46..7a52a38d767cc 100644 --- a/src/test/ui/consts/const-eval/issue-52475.stderr +++ b/src/test/ui/consts/const-eval/issue-52475.stderr @@ -1,8 +1,8 @@ error[E0019]: constant contains unimplemented expression type --> $DIR/issue-52475.rs:6:9 | -LL | / while n < 5 { //~ ERROR constant contains unimplemented expression type -LL | | n = (n + 1) % 5; //~ ERROR evaluation of constant value failed +LL | / while n < 5 { +LL | | n = (n + 1) % 5; LL | | x = &0; // Materialize a new AllocId LL | | } | |_________^ @@ -12,7 +12,7 @@ warning: Constant evaluating a complex constant, this might take some time | LL | let _ = [(); { | __________________^ -LL | | //~^ WARNING Constant evaluating a complex constant, this might take some time +LL | | LL | | let mut x = &0; LL | | let mut n = 0; ... | @@ -23,10 +23,10 @@ LL | | }]; error[E0080]: evaluation of constant value failed --> $DIR/issue-52475.rs:7:17 | -LL | n = (n + 1) % 5; //~ ERROR evaluation of constant value failed +LL | n = (n + 1) % 5; | ^^^^^^^^^^^ duplicate interpreter state observed here, const evaluation will never terminate error: aborting due to 2 previous errors -Some errors occurred: E0019, E0080. +Some errors have detailed explanations: E0019, E0080. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/const-eval/issue-53401.rs b/src/test/ui/consts/const-eval/issue-53401.rs index 89834aa94fc51..e8ac5a90880ce 100644 --- a/src/test/ui/consts/const-eval/issue-53401.rs +++ b/src/test/ui/consts/const-eval/issue-53401.rs @@ -1,6 +1,6 @@ // compile-pass -pub const STATIC_TRAIT: &Test = &(); +pub const STATIC_TRAIT: &dyn Test = &(); fn main() {} diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.rs b/src/test/ui/consts/const-eval/match-test-ptr-null.rs index b27b816cf5016..50757afaf5651 100644 --- a/src/test/ui/consts/const-eval/match-test-ptr-null.rs +++ b/src/test/ui/consts/const-eval/match-test-ptr-null.rs @@ -3,7 +3,10 @@ fn main() { // that pointer comparison is disallowed, not that parts of a pointer are accessed as raw // bytes. let _: [u8; 0] = [4; { - match &1 as *const i32 as usize { //~ ERROR casting pointers to integers in constants + match &1 as *const i32 as usize { + //~^ ERROR casting pointers to integers in constants + //~| NOTE for more information, see + //~| ERROR constant contains unimplemented expression type 0 => 42, //~ ERROR constant contains unimplemented expression type //~^ NOTE "pointer arithmetic or comparison" needs an rfc before being allowed //~| ERROR evaluation of constant value failed diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr index 94615c019fe88..167d5ad8d61fe 100644 --- a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr +++ b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr @@ -1,24 +1,31 @@ -error[E0658]: casting pointers to integers in constants is unstable (see issue #51910) +error[E0658]: casting pointers to integers in constants is unstable --> $DIR/match-test-ptr-null.rs:6:15 | -LL | match &1 as *const i32 as usize { //~ ERROR casting pointers to integers in constants +LL | match &1 as *const i32 as usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51910 = help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable error[E0019]: constant contains unimplemented expression type - --> $DIR/match-test-ptr-null.rs:7:13 + --> $DIR/match-test-ptr-null.rs:6:15 + | +LL | match &1 as *const i32 as usize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0019]: constant contains unimplemented expression type + --> $DIR/match-test-ptr-null.rs:10:13 | -LL | 0 => 42, //~ ERROR constant contains unimplemented expression type +LL | 0 => 42, | ^ error[E0080]: evaluation of constant value failed - --> $DIR/match-test-ptr-null.rs:7:13 + --> $DIR/match-test-ptr-null.rs:10:13 | -LL | 0 => 42, //~ ERROR constant contains unimplemented expression type +LL | 0 => 42, | ^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -Some errors occurred: E0019, E0080, E0658. +Some errors have detailed explanations: E0019, E0080, E0658. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr index 9fad6868d2038..50cd3214507a3 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr @@ -12,5 +12,5 @@ LL | foo(); error: aborting due to 2 previous errors -Some errors occurred: E0015, E0019. +Some errors have detailed explanations: E0015, E0019. For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs b/src/test/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs index 06b1727258dc2..34f61ed5a3474 100644 --- a/src/test/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs +++ b/src/test/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs @@ -1,7 +1,5 @@ // compile-pass -#![feature(nll)] - pub fn main() { let y: &'static mut [u8; 0] = &mut []; } diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.nll.stderr b/src/test/ui/consts/const-eval/promoted_const_fn_fail.nll.stderr deleted file mode 100644 index a2a71fc2ce368..0000000000000 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_const_fn_fail.rs:20:27 - | -LL | let x: &'static u8 = &(bar() + 1); //~ ERROR does not live long enough - | ----------- ^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs index 80562b0ee830b..88181cb86100f 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs @@ -17,7 +17,7 @@ const fn bar() -> u8 { } fn main() { - let x: &'static u8 = &(bar() + 1); //~ ERROR does not live long enough + let x: &'static u8 = &(bar() + 1); //~ ERROR temporary value dropped while borrowed let y = *x; unreachable!(); } diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr b/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr index 9316d48ab4318..519ba7d84b087 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr @@ -1,14 +1,14 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/promoted_const_fn_fail.rs:20:27 | -LL | let x: &'static u8 = &(bar() + 1); //~ ERROR does not live long enough - | ^^^^^^^^^^^ temporary value does not live long enough +LL | let x: &'static u8 = &(bar() + 1); + | ----------- ^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.nll.stderr b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.nll.stderr deleted file mode 100644 index 987d2304ae871..0000000000000 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_const_fn_fail_deny_const_err.rs:21:27 - | -LL | let x: &'static u8 = &(bar() + 1); - | ----------- ^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs index f331e44de17d1..061ab7eeb029d 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs @@ -19,7 +19,7 @@ fn main() { // This will compile, but then hard-abort at runtime. // FIXME(oli-obk): this should instead panic (not hard-abort) at runtime. let x: &'static u8 = &(bar() + 1); - //~^ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed let y = *x; unreachable!(); } diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr index 9c786b0864cb6..987d2304ae871 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr @@ -1,14 +1,14 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/promoted_const_fn_fail_deny_const_err.rs:21:27 | LL | let x: &'static u8 = &(bar() + 1); - | ^^^^^^^^^^^ temporary value does not live long enough + | ----------- ^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs index ebf80e7d2e670..fa8859cbb3bb6 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.rs +++ b/src/test/ui/consts/const-eval/promoted_errors.rs @@ -1,19 +1,23 @@ -#![warn(const_err)] - -// compile-pass // compile-flags: -O + +#![deny(const_err)] + fn main() { println!("{}", 0u32 - 1); let _x = 0u32 - 1; - //~^ WARN const_err + //~^ ERROR this expression will panic at runtime [const_err] println!("{}", 1/(1-1)); - //~^ WARN const_err + //~^ ERROR this expression will panic at runtime [const_err] + //~| ERROR attempt to divide by zero [const_err] + //~| ERROR reaching this expression at runtime will panic or abort [const_err] let _x = 1/(1-1); - //~^ WARN const_err - //~| WARN const_err + //~^ ERROR const_err + //~| ERROR const_err println!("{}", 1/(false as u32)); - //~^ WARN const_err + //~^ ERROR this expression will panic at runtime [const_err] + //~| ERROR attempt to divide by zero [const_err] + //~| ERROR reaching this expression at runtime will panic or abort [const_err] let _x = 1/(false as u32); - //~^ WARN const_err - //~| WARN const_err + //~^ ERROR const_err + //~| ERROR const_err } diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr index c9d5ede61ade4..12407accf096f 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.stderr @@ -1,60 +1,74 @@ -warning: this expression will panic at runtime +error: this expression will panic at runtime --> $DIR/promoted_errors.rs:7:14 | LL | let _x = 0u32 - 1; | ^^^^^^^^ attempt to subtract with overflow | note: lint level defined here - --> $DIR/promoted_errors.rs:1:9 + --> $DIR/promoted_errors.rs:3:9 | -LL | #![warn(const_err)] +LL | #![deny(const_err)] | ^^^^^^^^^ -warning: attempt to divide by zero +error: attempt to divide by zero --> $DIR/promoted_errors.rs:9:20 | LL | println!("{}", 1/(1-1)); | ^^^^^^^ -warning: attempt to divide by zero - --> $DIR/promoted_errors.rs:11:14 +error: this expression will panic at runtime + --> $DIR/promoted_errors.rs:9:20 + | +LL | println!("{}", 1/(1-1)); + | ^^^^^^^ attempt to divide by zero + +error: attempt to divide by zero + --> $DIR/promoted_errors.rs:13:14 | LL | let _x = 1/(1-1); | ^^^^^^^ -warning: this expression will panic at runtime - --> $DIR/promoted_errors.rs:11:14 +error: this expression will panic at runtime + --> $DIR/promoted_errors.rs:13:14 | LL | let _x = 1/(1-1); | ^^^^^^^ attempt to divide by zero -warning: attempt to divide by zero - --> $DIR/promoted_errors.rs:14:20 +error: attempt to divide by zero + --> $DIR/promoted_errors.rs:16:20 | LL | println!("{}", 1/(false as u32)); | ^^^^^^^^^^^^^^^^ -warning: attempt to divide by zero - --> $DIR/promoted_errors.rs:16:14 +error: this expression will panic at runtime + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1/(false as u32)); + | ^^^^^^^^^^^^^^^^ attempt to divide by zero + +error: attempt to divide by zero + --> $DIR/promoted_errors.rs:20:14 | LL | let _x = 1/(false as u32); | ^^^^^^^^^^^^^^^^ -warning: this expression will panic at runtime - --> $DIR/promoted_errors.rs:16:14 +error: this expression will panic at runtime + --> $DIR/promoted_errors.rs:20:14 | LL | let _x = 1/(false as u32); | ^^^^^^^^^^^^^^^^ attempt to divide by zero -warning: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:14:20 +error: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:16:20 | LL | println!("{}", 1/(false as u32)); | ^^^^^^^^^^^^^^^^ attempt to divide by zero -warning: reaching this expression at runtime will panic or abort +error: reaching this expression at runtime will panic or abort --> $DIR/promoted_errors.rs:9:20 | LL | println!("{}", 1/(1-1)); | ^^^^^^^ attempt to divide by zero +error: aborting due to 11 previous errors + diff --git a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.nll.stderr b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.nll.stderr deleted file mode 100644 index 117090d89fd73..0000000000000 --- a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.nll.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_raw_ptr_ops.rs:4:29 - | -LL | let x: &'static bool = &(42 as *const i32 == 43 as *const i32); - | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_raw_ptr_ops.rs:6:30 - | -LL | let y: &'static usize = &(&1 as *const i32 as usize + 1); //~ ERROR does not live long enough - | -------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_raw_ptr_ops.rs:7:28 - | -LL | let z: &'static i32 = &(unsafe { *(42 as *const i32) }); //~ ERROR does not live long enough - | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | let a: &'static bool = &(main as fn() == main as fn()); //~ ERROR does not live long enough -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_raw_ptr_ops.rs:8:29 - | -LL | let a: &'static bool = &(main as fn() == main as fn()); //~ ERROR does not live long enough - | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs index ef7e5506f22ae..c6fb5eeab5aec 100644 --- a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs +++ b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs @@ -2,8 +2,11 @@ fn main() { let x: &'static bool = &(42 as *const i32 == 43 as *const i32); - //~^ ERROR does not live long enough - let y: &'static usize = &(&1 as *const i32 as usize + 1); //~ ERROR does not live long enough - let z: &'static i32 = &(unsafe { *(42 as *const i32) }); //~ ERROR does not live long enough - let a: &'static bool = &(main as fn() == main as fn()); //~ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed + let y: &'static usize = &(&1 as *const i32 as usize + 1); + //~^ ERROR temporary value dropped while borrowed + let z: &'static i32 = &(unsafe { *(42 as *const i32) }); + //~^ ERROR temporary value dropped while borrowed + let a: &'static bool = &(main as fn() == main as fn()); + //~^ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.stderr index 9d1dcfafa6363..7f2e4899184e3 100644 --- a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.stderr +++ b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.stderr @@ -1,46 +1,47 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/promoted_raw_ptr_ops.rs:4:29 | LL | let x: &'static bool = &(42 as *const i32 == 43 as *const i32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/promoted_raw_ptr_ops.rs:6:30 | -LL | let y: &'static usize = &(&1 as *const i32 as usize + 1); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough +LL | let y: &'static usize = &(&1 as *const i32 as usize + 1); + | -------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/promoted_raw_ptr_ops.rs:7:28 +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_raw_ptr_ops.rs:8:28 | -LL | let z: &'static i32 = &(unsafe { *(42 as *const i32) }); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -LL | let a: &'static bool = &(main as fn() == main as fn()); //~ ERROR does not live long enough +LL | let z: &'static i32 = &(unsafe { *(42 as *const i32) }); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/promoted_raw_ptr_ops.rs:8:29 - | -LL | let a: &'static bool = &(main as fn() == main as fn()); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_raw_ptr_ops.rs:10:29 + | +LL | let a: &'static bool = &(main as fn() == main as fn()); + | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/pub_const_err.stderr b/src/test/ui/consts/const-eval/pub_const_err.stderr index 9395832108d93..bd262b69da81a 100644 --- a/src/test/ui/consts/const-eval/pub_const_err.stderr +++ b/src/test/ui/consts/const-eval/pub_const_err.stderr @@ -1,8 +1,8 @@ warning: any use of this value will cause an error - --> $DIR/pub_const_err.rs:6:1 + --> $DIR/pub_const_err.rs:6:20 | LL | pub const Z: u32 = 0 - 1; - | ^^^^^^^^^^^^^^^^^^^-----^ + | -------------------^^^^^- | | | attempt to subtract with overflow | diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr index 6716f337f4148..866d1753edb95 100644 --- a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr +++ b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr @@ -1,8 +1,8 @@ warning: any use of this value will cause an error - --> $DIR/pub_const_err_bin.rs:4:1 + --> $DIR/pub_const_err_bin.rs:4:20 | LL | pub const Z: u32 = 0 - 1; - | ^^^^^^^^^^^^^^^^^^^-----^ + | -------------------^^^^^- | | | attempt to subtract with overflow | diff --git a/src/test/ui/consts/const-eval/ref_to_int_match.stderr b/src/test/ui/consts/const-eval/ref_to_int_match.stderr index 888fe065a6257..f8eafed68e43d 100644 --- a/src/test/ui/consts/const-eval/ref_to_int_match.stderr +++ b/src/test/ui/consts/const-eval/ref_to_int_match.stderr @@ -1,7 +1,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ref_to_int_match.rs:23:1 | -LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; //~ ERROR it is undefined behavior to use this value +LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -9,7 +9,7 @@ LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; //~ ERROR it is undefined beh error: could not evaluate constant pattern --> $DIR/ref_to_int_match.rs:7:14 | -LL | 10..=BAR => {}, //~ ERROR could not evaluate constant pattern +LL | 10..=BAR => {}, | ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/shift_overflow.stderr b/src/test/ui/consts/const-eval/shift_overflow.stderr index e5c34f94d2c53..5db231cd5b0df 100644 --- a/src/test/ui/consts/const-eval/shift_overflow.stderr +++ b/src/test/ui/consts/const-eval/shift_overflow.stderr @@ -1,7 +1,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/shift_overflow.rs:3:9 | -LL | X = 1 << ((u32::max_value() as u64) + 1), //~ ERROR E0080 +LL | X = 1 << ((u32::max_value() as u64) + 1), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left with overflow error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/transmute-const-promotion.nll.stderr b/src/test/ui/consts/const-eval/transmute-const-promotion.nll.stderr deleted file mode 100644 index 90fe7eebe4a76..0000000000000 --- a/src/test/ui/consts/const-eval/transmute-const-promotion.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/transmute-const-promotion.rs:6:37 - | -LL | let x: &'static u32 = unsafe { &mem::transmute(3.0f32) }; - | ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | //~^ ERROR value does not live long enough -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/transmute-const-promotion.rs b/src/test/ui/consts/const-eval/transmute-const-promotion.rs index a1da35039739e..8bd1b341e6e12 100644 --- a/src/test/ui/consts/const-eval/transmute-const-promotion.rs +++ b/src/test/ui/consts/const-eval/transmute-const-promotion.rs @@ -4,5 +4,5 @@ use std::mem; fn main() { let x: &'static u32 = unsafe { &mem::transmute(3.0f32) }; - //~^ ERROR value does not live long enough + //~^ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/const-eval/transmute-const-promotion.stderr b/src/test/ui/consts/const-eval/transmute-const-promotion.stderr index 996e84de06dcf..5aae8c12d16ec 100644 --- a/src/test/ui/consts/const-eval/transmute-const-promotion.stderr +++ b/src/test/ui/consts/const-eval/transmute-const-promotion.stderr @@ -1,14 +1,14 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/transmute-const-promotion.rs:6:37 | LL | let x: &'static u32 = unsafe { &mem::transmute(3.0f32) }; - | ^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -LL | //~^ ERROR value does not live long enough + | ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/ub-upvars.rs b/src/test/ui/consts/const-eval/ub-upvars.rs index 9b7bca6b72d61..0a427cd8857e8 100644 --- a/src/test/ui/consts/const-eval/ub-upvars.rs +++ b/src/test/ui/consts/const-eval/ub-upvars.rs @@ -3,7 +3,7 @@ use std::mem; -const BAD_UPVAR: &FnOnce() = &{ //~ ERROR it is undefined behavior to use this value +const BAD_UPVAR: &dyn FnOnce() = &{ //~ ERROR it is undefined behavior to use this value let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) }; let another_var = 13; move || { let _ = bad_ref; let _ = another_var; } diff --git a/src/test/ui/consts/const-eval/ub-upvars.stderr b/src/test/ui/consts/const-eval/ub-upvars.stderr index d18339f2434a6..f8273ba902a88 100644 --- a/src/test/ui/consts/const-eval/ub-upvars.stderr +++ b/src/test/ui/consts/const-eval/ub-upvars.stderr @@ -1,7 +1,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-upvars.rs:6:1 | -LL | / const BAD_UPVAR: &FnOnce() = &{ //~ ERROR it is undefined behavior to use this value +LL | / const BAD_UPVAR: &dyn FnOnce() = &{ LL | | let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) }; LL | | let another_var = 13; LL | | move || { let _ = bad_ref; let _ = another_var; } diff --git a/src/test/ui/consts/const-eval/union-ice.stderr b/src/test/ui/consts/const-eval/union-ice.stderr index 3edc52415717e..b25cb8c5aa021 100644 --- a/src/test/ui/consts/const-eval/union-ice.stderr +++ b/src/test/ui/consts/const-eval/union-ice.stderr @@ -1,7 +1,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/union-ice.rs:13:1 | -LL | const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR it is undefined behavior to use this value +LL | const FIELD3: Field3 = unsafe { UNION.field3 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -9,7 +9,7 @@ LL | const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR it is undefined b error[E0080]: it is undefined behavior to use this value --> $DIR/union-ice.rs:15:1 | -LL | / const FIELD_PATH: Struct = Struct { //~ ERROR it is undefined behavior to use this value +LL | / const FIELD_PATH: Struct = Struct { LL | | a: 42, LL | | b: unsafe { UNION.field3 }, LL | | }; @@ -20,7 +20,7 @@ LL | | }; error[E0080]: it is undefined behavior to use this value --> $DIR/union-ice.rs:25:1 | -LL | / const FIELD_PATH2: Struct2 = Struct2 { //~ ERROR it is undefined behavior to use this value +LL | / const FIELD_PATH2: Struct2 = Struct2 { LL | | b: [ LL | | 21, LL | | unsafe { UNION.field3 }, diff --git a/src/test/ui/consts/const-eval/union-ub-fat-ptr.rs b/src/test/ui/consts/const-eval/union-ub-fat-ptr.rs index 13489c50a1223..d5405f3441fec 100644 --- a/src/test/ui/consts/const-eval/union-ub-fat-ptr.rs +++ b/src/test/ui/consts/const-eval/union-ub-fat-ptr.rs @@ -59,7 +59,7 @@ union DynTransmute { repr: DynRepr, repr2: DynRepr2, bad: BadDynRepr, - rust: &'static Trait, + rust: &'static dyn Trait, } trait Trait {} @@ -94,17 +94,17 @@ const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: & //~^ ERROR it is undefined behavior to use this value // bad trait object -const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; +const D: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; //~^ ERROR it is undefined behavior to use this value // bad trait object -const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; +const E: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; //~^ ERROR it is undefined behavior to use this value // bad trait object -const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; +const F: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; //~^ ERROR it is undefined behavior to use this value // bad data *inside* the trait object -const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl }; +const G: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; //~^ ERROR it is undefined behavior to use this value // bad data *inside* the slice diff --git a/src/test/ui/consts/const-eval/union-ub-fat-ptr.stderr b/src/test/ui/consts/const-eval/union-ub-fat-ptr.stderr index 761a5fc4445ed..19db90c1cb53e 100644 --- a/src/test/ui/consts/const-eval/union-ub-fat-ptr.stderr +++ b/src/test/ui/consts/const-eval/union-ub-fat-ptr.stderr @@ -41,32 +41,32 @@ LL | const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, l error[E0080]: it is undefined behavior to use this value --> $DIR/union-ub-fat-ptr.rs:97:1 | -LL | const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop fn in vtable +LL | const D: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer or too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value --> $DIR/union-ub-fat-ptr.rs:100:1 | -LL | const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop fn in vtable +LL | const E: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer or too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value --> $DIR/union-ub-fat-ptr.rs:103:1 | -LL | const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-pointer vtable in fat pointer +LL | const F: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer or too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value --> $DIR/union-ub-fat-ptr.rs:107:1 | -LL | const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .., but expected something less or equal to 1 +LL | const G: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .., but expected something less or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/union_promotion.nll.stderr b/src/test/ui/consts/const-eval/union_promotion.nll.stderr deleted file mode 100644 index 11bc7f9da35f7..0000000000000 --- a/src/test/ui/consts/const-eval/union_promotion.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/union_promotion.rs:9:29 - | -LL | let x: &'static bool = &unsafe { //~ borrowed value does not live long enough - | ____________-------------____^ - | | | - | | type annotation requires that borrow lasts for `'static` -LL | | Foo { a: &1 }.b == Foo { a: &2 }.b -LL | | }; - | |_____^ creates a temporary which is freed while still in use -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/union_promotion.rs b/src/test/ui/consts/const-eval/union_promotion.rs index c308c81cf64b8..d3566511ef8ee 100644 --- a/src/test/ui/consts/const-eval/union_promotion.rs +++ b/src/test/ui/consts/const-eval/union_promotion.rs @@ -6,7 +6,7 @@ union Foo { } fn main() { - let x: &'static bool = &unsafe { //~ borrowed value does not live long enough + let x: &'static bool = &unsafe { //~ temporary value dropped while borrowed Foo { a: &1 }.b == Foo { a: &2 }.b }; } diff --git a/src/test/ui/consts/const-eval/union_promotion.stderr b/src/test/ui/consts/const-eval/union_promotion.stderr index 643c784ca08fc..b530c02f2fb93 100644 --- a/src/test/ui/consts/const-eval/union_promotion.stderr +++ b/src/test/ui/consts/const-eval/union_promotion.stderr @@ -1,16 +1,16 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/union_promotion.rs:9:29 | -LL | let x: &'static bool = &unsafe { //~ borrowed value does not live long enough - | _____________________________^ +LL | let x: &'static bool = &unsafe { + | ____________-------------____^ + | | | + | | type annotation requires that borrow lasts for `'static` LL | | Foo { a: &1 }.b == Foo { a: &2 }.b LL | | }; - | |_____^ temporary value does not live long enough + | |_____^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/unused-broken-const.stderr b/src/test/ui/consts/const-eval/unused-broken-const.stderr index c0061f8b30cbc..e45ce65d8bb35 100644 --- a/src/test/ui/consts/const-eval/unused-broken-const.stderr +++ b/src/test/ui/consts/const-eval/unused-broken-const.stderr @@ -1,10 +1,8 @@ -warning: due to multiple output types requested, the explicitly specified output file name will be adapted for each output type - error: any use of this value will cause an error - --> $DIR/unused-broken-const.rs:5:1 + --> $DIR/unused-broken-const.rs:5:18 | LL | const FOO: i32 = [][0]; - | ^^^^^^^^^^^^^^^^^-----^ + | -----------------^^^^^- | | | index out of bounds: the len is 0 but the index is 0 | diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.stderr b/src/test/ui/consts/const-fn-not-safe-for-const.stderr index 2003b137c272b..ba5d58a51d2dd 100644 --- a/src/test/ui/consts/const-fn-not-safe-for-const.stderr +++ b/src/test/ui/consts/const-fn-not-safe-for-const.stderr @@ -1,7 +1,7 @@ error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-fn-not-safe-for-const.rs:14:5 | -LL | random() //~ ERROR E0015 +LL | random() | ^^^^^^^^ error[E0013]: constant functions cannot refer to statics, use a constant instead @@ -18,5 +18,5 @@ LL | &Y error: aborting due to 3 previous errors -Some errors occurred: E0013, E0015. +Some errors have detailed explanations: E0013, E0015. For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/consts/const-fn-stability-calls-3.rs b/src/test/ui/consts/const-fn-stability-calls-3.rs index 44bcca8d8023a..b831dee580c1a 100644 --- a/src/test/ui/consts/const-fn-stability-calls-3.rs +++ b/src/test/ui/consts/const-fn-stability-calls-3.rs @@ -1,15 +1,12 @@ // Test use of const fn from another crate without a feature gate. -// compile-pass -// skip-codegen -#![allow(unused_variables)] +// check-pass // aux-build:const_fn_lib.rs extern crate const_fn_lib; use const_fn_lib::foo; - fn main() { let x = foo(); // use outside a constant is ok } diff --git a/src/test/ui/consts/const-int-conversion.nll.stderr b/src/test/ui/consts/const-int-conversion.nll.stderr deleted file mode 100644 index afc051013ed7c..0000000000000 --- a/src/test/ui/consts/const-int-conversion.nll.stderr +++ /dev/null @@ -1,80 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-conversion.rs:4:28 - | -LL | let x: &'static i32 = &(5_i32.reverse_bits()); - | ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-conversion.rs:6:28 - | -LL | let y: &'static i32 = &(i32::from_be_bytes([0x12, 0x34, 0x56, 0x78])); - | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-conversion.rs:8:28 - | -LL | let z: &'static i32 = &(i32::from_le_bytes([0x12, 0x34, 0x56, 0x78])); - | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-conversion.rs:10:28 - | -LL | let a: &'static i32 = &(i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0]))); - | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-conversion.rs:12:29 - | -LL | let b: &'static [u8] = &(0x12_34_56_78_i32.to_be_bytes()); - | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-conversion.rs:14:29 - | -LL | let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes()); - | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-conversion.rs:16:29 - | -LL | let d: &'static [u8] = &(i32::min_value().to_be().to_ne_bytes()); - | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | //~^ ERROR does not live long enough -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to 7 previous errors - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-int-conversion.rs b/src/test/ui/consts/const-int-conversion.rs index 8f0aa141a9d64..b80e616eae77e 100644 --- a/src/test/ui/consts/const-int-conversion.rs +++ b/src/test/ui/consts/const-int-conversion.rs @@ -1,18 +1,16 @@ -#![feature(reverse_bits)] - fn main() { let x: &'static i32 = &(5_i32.reverse_bits()); - //~^ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed let y: &'static i32 = &(i32::from_be_bytes([0x12, 0x34, 0x56, 0x78])); - //~^ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed let z: &'static i32 = &(i32::from_le_bytes([0x12, 0x34, 0x56, 0x78])); - //~^ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed let a: &'static i32 = &(i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0]))); - //~^ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed let b: &'static [u8] = &(0x12_34_56_78_i32.to_be_bytes()); - //~^ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes()); - //~^ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed let d: &'static [u8] = &(i32::min_value().to_be().to_ne_bytes()); - //~^ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/const-int-conversion.stderr b/src/test/ui/consts/const-int-conversion.stderr index b216d41727b5f..237f9627219bd 100644 --- a/src/test/ui/consts/const-int-conversion.stderr +++ b/src/test/ui/consts/const-int-conversion.stderr @@ -1,80 +1,80 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-conversion.rs:4:28 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:2:28 | LL | let x: &'static i32 = &(5_i32.reverse_bits()); - | ^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-conversion.rs:6:28 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:4:28 | LL | let y: &'static i32 = &(i32::from_be_bytes([0x12, 0x34, 0x56, 0x78])); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-conversion.rs:8:28 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:6:28 | LL | let z: &'static i32 = &(i32::from_le_bytes([0x12, 0x34, 0x56, 0x78])); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-conversion.rs:10:28 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:8:28 | LL | let a: &'static i32 = &(i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0]))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-conversion.rs:12:29 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:10:29 | LL | let b: &'static [u8] = &(0x12_34_56_78_i32.to_be_bytes()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-conversion.rs:14:29 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:12:29 | LL | let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-conversion.rs:16:29 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:14:29 | LL | let d: &'static [u8] = &(i32::min_value().to_be().to_ne_bytes()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -LL | //~^ ERROR does not live long enough + | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-int-overflowing.nll.stderr b/src/test/ui/consts/const-int-overflowing.nll.stderr deleted file mode 100644 index ffcac69c1af8b..0000000000000 --- a/src/test/ui/consts/const-int-overflowing.nll.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-overflowing.rs:2:36 - | -LL | let x: &'static (i32, bool) = &(5_i32.overflowing_add(3)); //~ ERROR does not live long enough - | -------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-overflowing.rs:3:36 - | -LL | let y: &'static (i32, bool) = &(5_i32.overflowing_sub(3)); //~ ERROR does not live long enough - | -------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); //~ ERROR does not live long enough -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-overflowing.rs:4:36 - | -LL | let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); //~ ERROR does not live long enough - | -------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-int-overflowing.rs b/src/test/ui/consts/const-int-overflowing.rs index 4e69e85780606..cd74c9990995e 100644 --- a/src/test/ui/consts/const-int-overflowing.rs +++ b/src/test/ui/consts/const-int-overflowing.rs @@ -1,5 +1,8 @@ fn main() { - let x: &'static (i32, bool) = &(5_i32.overflowing_add(3)); //~ ERROR does not live long enough - let y: &'static (i32, bool) = &(5_i32.overflowing_sub(3)); //~ ERROR does not live long enough - let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); //~ ERROR does not live long enough + let x: &'static (i32, bool) = &(5_i32.overflowing_add(3)); + //~^ ERROR temporary value dropped while borrowed + let y: &'static (i32, bool) = &(5_i32.overflowing_sub(3)); + //~^ ERROR temporary value dropped while borrowed + let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); + //~^ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/const-int-overflowing.stderr b/src/test/ui/consts/const-int-overflowing.stderr index 736909e093227..56c7f7f092d66 100644 --- a/src/test/ui/consts/const-int-overflowing.stderr +++ b/src/test/ui/consts/const-int-overflowing.stderr @@ -1,35 +1,36 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/const-int-overflowing.rs:2:36 | -LL | let x: &'static (i32, bool) = &(5_i32.overflowing_add(3)); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough +LL | let x: &'static (i32, bool) = &(5_i32.overflowing_add(3)); + | -------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-overflowing.rs:3:36 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-overflowing.rs:4:36 | -LL | let y: &'static (i32, bool) = &(5_i32.overflowing_sub(3)); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -LL | let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); //~ ERROR does not live long enough +LL | let y: &'static (i32, bool) = &(5_i32.overflowing_sub(3)); + | -------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-overflowing.rs:4:36 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-overflowing.rs:6:36 | -LL | let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough +LL | let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); + | -------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-int-rotate.nll.stderr b/src/test/ui/consts/const-int-rotate.nll.stderr deleted file mode 100644 index 9923096f46d63..0000000000000 --- a/src/test/ui/consts/const-int-rotate.nll.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-rotate.rs:2:28 - | -LL | let x: &'static i32 = &(5_i32.rotate_left(3)); //~ ERROR does not live long enough - | ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | let y: &'static i32 = &(5_i32.rotate_right(3)); //~ ERROR does not live long enough -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-rotate.rs:3:28 - | -LL | let y: &'static i32 = &(5_i32.rotate_right(3)); //~ ERROR does not live long enough - | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-int-rotate.rs b/src/test/ui/consts/const-int-rotate.rs index d07c00e0110c9..3aacf854db1da 100644 --- a/src/test/ui/consts/const-int-rotate.rs +++ b/src/test/ui/consts/const-int-rotate.rs @@ -1,4 +1,6 @@ fn main() { - let x: &'static i32 = &(5_i32.rotate_left(3)); //~ ERROR does not live long enough - let y: &'static i32 = &(5_i32.rotate_right(3)); //~ ERROR does not live long enough + let x: &'static i32 = &(5_i32.rotate_left(3)); + //~^ ERROR temporary value dropped while borrowed + let y: &'static i32 = &(5_i32.rotate_right(3)); + //~^ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/const-int-rotate.stderr b/src/test/ui/consts/const-int-rotate.stderr index c15727961f9f6..ed265804bbc6c 100644 --- a/src/test/ui/consts/const-int-rotate.stderr +++ b/src/test/ui/consts/const-int-rotate.stderr @@ -1,24 +1,25 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/const-int-rotate.rs:2:28 | -LL | let x: &'static i32 = &(5_i32.rotate_left(3)); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -LL | let y: &'static i32 = &(5_i32.rotate_right(3)); //~ ERROR does not live long enough +LL | let x: &'static i32 = &(5_i32.rotate_left(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-rotate.rs:3:28 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-rotate.rs:4:28 | -LL | let y: &'static i32 = &(5_i32.rotate_right(3)); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough +LL | let y: &'static i32 = &(5_i32.rotate_right(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-int-sign.nll.stderr b/src/test/ui/consts/const-int-sign.nll.stderr deleted file mode 100644 index 43fd002ff3a65..0000000000000 --- a/src/test/ui/consts/const-int-sign.nll.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-sign.rs:2:29 - | -LL | let x: &'static bool = &(5_i32.is_negative()); //~ ERROR does not live long enough - | ------------- ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | let y: &'static bool = &(5_i32.is_positive()); //~ ERROR does not live long enough -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-sign.rs:3:29 - | -LL | let y: &'static bool = &(5_i32.is_positive()); //~ ERROR does not live long enough - | ------------- ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-int-sign.rs b/src/test/ui/consts/const-int-sign.rs index a21797c5ce441..c3111ddf56ca2 100644 --- a/src/test/ui/consts/const-int-sign.rs +++ b/src/test/ui/consts/const-int-sign.rs @@ -1,4 +1,6 @@ fn main() { - let x: &'static bool = &(5_i32.is_negative()); //~ ERROR does not live long enough - let y: &'static bool = &(5_i32.is_positive()); //~ ERROR does not live long enough + let x: &'static bool = &(5_i32.is_negative()); + //~^ ERROR temporary value dropped while borrowed + let y: &'static bool = &(5_i32.is_positive()); + //~^ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/const-int-sign.stderr b/src/test/ui/consts/const-int-sign.stderr index 5a9a23af9d655..5f8fd4141804c 100644 --- a/src/test/ui/consts/const-int-sign.stderr +++ b/src/test/ui/consts/const-int-sign.stderr @@ -1,24 +1,25 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/const-int-sign.rs:2:29 | -LL | let x: &'static bool = &(5_i32.is_negative()); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -LL | let y: &'static bool = &(5_i32.is_positive()); //~ ERROR does not live long enough +LL | let x: &'static bool = &(5_i32.is_negative()); + | ------------- ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-sign.rs:3:29 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-sign.rs:4:29 | -LL | let y: &'static bool = &(5_i32.is_positive()); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough +LL | let y: &'static bool = &(5_i32.is_positive()); + | ------------- ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-int-unchecked.stderr b/src/test/ui/consts/const-int-unchecked.stderr index 4382d9174b757..0fa82008711c9 100644 --- a/src/test/ui/consts/const-int-unchecked.stderr +++ b/src/test/ui/consts/const-int-unchecked.stderr @@ -1,322 +1,322 @@ error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:14:1 + --> $DIR/const-int-unchecked.rs:14:29 | LL | const SHL_U8: u8 = unsafe { intrinsics::unchecked_shl(5_u8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^ + | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 8 in unchecked_shl | = note: #[deny(const_err)] on by default error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:16:1 + --> $DIR/const-int-unchecked.rs:16:31 | LL | const SHL_U16: u16 = unsafe { intrinsics::unchecked_shl(5_u16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 16 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:18:1 + --> $DIR/const-int-unchecked.rs:18:31 | LL | const SHL_U32: u32 = unsafe { intrinsics::unchecked_shl(5_u32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 32 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:20:1 + --> $DIR/const-int-unchecked.rs:20:31 | LL | const SHL_U64: u64 = unsafe { intrinsics::unchecked_shl(5_u64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 64 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:22:1 + --> $DIR/const-int-unchecked.rs:22:33 | LL | const SHL_U128: u128 = unsafe { intrinsics::unchecked_shl(5_u128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------^^^ + | --------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 128 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:27:1 + --> $DIR/const-int-unchecked.rs:27:29 | LL | const SHL_I8: i8 = unsafe { intrinsics::unchecked_shl(5_i8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^ + | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 8 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:29:1 + --> $DIR/const-int-unchecked.rs:29:31 | LL | const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^ + | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 16 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:31:1 + --> $DIR/const-int-unchecked.rs:31:31 | LL | const SHL_I32: i32 = unsafe { intrinsics::unchecked_shl(5_i32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 32 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:33:1 + --> $DIR/const-int-unchecked.rs:33:31 | LL | const SHL_I64: i64 = unsafe { intrinsics::unchecked_shl(5_i64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 64 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:35:1 + --> $DIR/const-int-unchecked.rs:35:33 | LL | const SHL_I128: i128 = unsafe { intrinsics::unchecked_shl(5_i128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------^^^ + | --------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 128 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:40:1 + --> $DIR/const-int-unchecked.rs:40:33 | LL | const SHL_I8_NEG: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^ + | --------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 255 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:42:1 + --> $DIR/const-int-unchecked.rs:42:35 | LL | const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_16, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^ + | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 65535 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:44:1 + --> $DIR/const-int-unchecked.rs:44:35 | LL | const SHL_I32_NEG: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 4294967295 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:46:1 + --> $DIR/const-int-unchecked.rs:46:35 | LL | const SHL_I64_NEG: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 18446744073709551615 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:48:1 + --> $DIR/const-int-unchecked.rs:48:37 | LL | const SHL_I128_NEG: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------------^^^ + | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 340282366920938463463374607431768211455 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:54:1 + --> $DIR/const-int-unchecked.rs:54:40 | LL | const SHL_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -6) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^ + | ---------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 250 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:56:1 + --> $DIR/const-int-unchecked.rs:56:42 | LL | const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_16, -13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 65523 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:58:1 + --> $DIR/const-int-unchecked.rs:58:42 | LL | const SHL_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -25) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------------^^^ + | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 4294967271 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:60:1 + --> $DIR/const-int-unchecked.rs:60:42 | LL | const SHL_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -30) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------------^^^ + | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 18446744073709551586 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:62:1 + --> $DIR/const-int-unchecked.rs:62:44 | LL | const SHL_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -93) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------^^^ + | -------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 340282366920938463463374607431768211363 in unchecked_shl error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:69:1 + --> $DIR/const-int-unchecked.rs:69:29 | LL | const SHR_U8: u8 = unsafe { intrinsics::unchecked_shr(5_u8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^ + | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 8 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:71:1 + --> $DIR/const-int-unchecked.rs:71:31 | LL | const SHR_U16: u16 = unsafe { intrinsics::unchecked_shr(5_u16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 16 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:73:1 + --> $DIR/const-int-unchecked.rs:73:31 | LL | const SHR_U32: u32 = unsafe { intrinsics::unchecked_shr(5_u32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 32 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:75:1 + --> $DIR/const-int-unchecked.rs:75:31 | LL | const SHR_U64: u64 = unsafe { intrinsics::unchecked_shr(5_u64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 64 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:77:1 + --> $DIR/const-int-unchecked.rs:77:33 | LL | const SHR_U128: u128 = unsafe { intrinsics::unchecked_shr(5_u128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------^^^ + | --------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 128 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:82:1 + --> $DIR/const-int-unchecked.rs:82:29 | LL | const SHR_I8: i8 = unsafe { intrinsics::unchecked_shr(5_i8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^ + | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 8 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:84:1 + --> $DIR/const-int-unchecked.rs:84:31 | LL | const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^ + | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 16 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:86:1 + --> $DIR/const-int-unchecked.rs:86:31 | LL | const SHR_I32: i32 = unsafe { intrinsics::unchecked_shr(5_i32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 32 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:88:1 + --> $DIR/const-int-unchecked.rs:88:31 | LL | const SHR_I64: i64 = unsafe { intrinsics::unchecked_shr(5_i64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 64 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:90:1 + --> $DIR/const-int-unchecked.rs:90:33 | LL | const SHR_I128: i128 = unsafe { intrinsics::unchecked_shr(5_i128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------^^^ + | --------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 128 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:95:1 + --> $DIR/const-int-unchecked.rs:95:33 | LL | const SHR_I8_NEG: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^ + | --------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 255 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:97:1 + --> $DIR/const-int-unchecked.rs:97:35 | LL | const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_16, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^ + | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 65535 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:99:1 + --> $DIR/const-int-unchecked.rs:99:35 | LL | const SHR_I32_NEG: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 4294967295 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:101:1 + --> $DIR/const-int-unchecked.rs:101:35 | LL | const SHR_I64_NEG: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 18446744073709551615 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:103:1 + --> $DIR/const-int-unchecked.rs:103:37 | LL | const SHR_I128_NEG: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------------^^^ + | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 340282366920938463463374607431768211455 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:109:1 + --> $DIR/const-int-unchecked.rs:109:40 | LL | const SHR_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -6) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^ + | ---------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 250 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:111:1 + --> $DIR/const-int-unchecked.rs:111:42 | LL | const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_16, -13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^ + | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 65523 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:113:1 + --> $DIR/const-int-unchecked.rs:113:42 | LL | const SHR_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -25) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------------^^^ + | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 4294967271 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:115:1 + --> $DIR/const-int-unchecked.rs:115:42 | LL | const SHR_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -30) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------------^^^ + | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 18446744073709551586 in unchecked_shr error: any use of this value will cause an error - --> $DIR/const-int-unchecked.rs:117:1 + --> $DIR/const-int-unchecked.rs:117:44 | LL | const SHR_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -93) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------^^^ + | -------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | Overflowing shift by 340282366920938463463374607431768211363 in unchecked_shr diff --git a/src/test/ui/consts/const-int-wrapping.nll.stderr b/src/test/ui/consts/const-int-wrapping.nll.stderr deleted file mode 100644 index 036c8b9d95e1a..0000000000000 --- a/src/test/ui/consts/const-int-wrapping.nll.stderr +++ /dev/null @@ -1,57 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-wrapping.rs:2:28 - | -LL | let x: &'static i32 = &(5_i32.wrapping_add(3)); //~ ERROR does not live long enough - | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-wrapping.rs:3:28 - | -LL | let y: &'static i32 = &(5_i32.wrapping_sub(3)); //~ ERROR does not live long enough - | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-wrapping.rs:4:28 - | -LL | let z: &'static i32 = &(5_i32.wrapping_mul(3)); //~ ERROR does not live long enough - | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-wrapping.rs:5:28 - | -LL | let a: &'static i32 = &(5_i32.wrapping_shl(3)); //~ ERROR does not live long enough - | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | let b: &'static i32 = &(5_i32.wrapping_shr(3)); //~ ERROR does not live long enough -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/const-int-wrapping.rs:6:28 - | -LL | let b: &'static i32 = &(5_i32.wrapping_shr(3)); //~ ERROR does not live long enough - | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-int-wrapping.rs b/src/test/ui/consts/const-int-wrapping.rs index 720e40b6ebdeb..50d04f9641d8b 100644 --- a/src/test/ui/consts/const-int-wrapping.rs +++ b/src/test/ui/consts/const-int-wrapping.rs @@ -1,7 +1,12 @@ fn main() { - let x: &'static i32 = &(5_i32.wrapping_add(3)); //~ ERROR does not live long enough - let y: &'static i32 = &(5_i32.wrapping_sub(3)); //~ ERROR does not live long enough - let z: &'static i32 = &(5_i32.wrapping_mul(3)); //~ ERROR does not live long enough - let a: &'static i32 = &(5_i32.wrapping_shl(3)); //~ ERROR does not live long enough - let b: &'static i32 = &(5_i32.wrapping_shr(3)); //~ ERROR does not live long enough + let x: &'static i32 = &(5_i32.wrapping_add(3)); + //~^ ERROR temporary value dropped while borrowed + let y: &'static i32 = &(5_i32.wrapping_sub(3)); + //~^ ERROR temporary value dropped while borrowed + let z: &'static i32 = &(5_i32.wrapping_mul(3)); + //~^ ERROR temporary value dropped while borrowed + let a: &'static i32 = &(5_i32.wrapping_shl(3)); + //~^ ERROR temporary value dropped while borrowed + let b: &'static i32 = &(5_i32.wrapping_shr(3)); + //~^ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/const-int-wrapping.stderr b/src/test/ui/consts/const-int-wrapping.stderr index ec9776b821194..5174b72659cd7 100644 --- a/src/test/ui/consts/const-int-wrapping.stderr +++ b/src/test/ui/consts/const-int-wrapping.stderr @@ -1,57 +1,58 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/const-int-wrapping.rs:2:28 | -LL | let x: &'static i32 = &(5_i32.wrapping_add(3)); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough +LL | let x: &'static i32 = &(5_i32.wrapping_add(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-wrapping.rs:3:28 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:4:28 | -LL | let y: &'static i32 = &(5_i32.wrapping_sub(3)); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough +LL | let y: &'static i32 = &(5_i32.wrapping_sub(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-wrapping.rs:4:28 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:6:28 | -LL | let z: &'static i32 = &(5_i32.wrapping_mul(3)); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough +LL | let z: &'static i32 = &(5_i32.wrapping_mul(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-wrapping.rs:5:28 +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:8:28 | -LL | let a: &'static i32 = &(5_i32.wrapping_shl(3)); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -LL | let b: &'static i32 = &(5_i32.wrapping_shr(3)); //~ ERROR does not live long enough +LL | let a: &'static i32 = &(5_i32.wrapping_shl(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough - --> $DIR/const-int-wrapping.rs:6:28 - | -LL | let b: &'static i32 = &(5_i32.wrapping_shr(3)); //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:10:28 + | +LL | let b: &'static i32 = &(5_i32.wrapping_shr(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-integer-bool-ops.stderr b/src/test/ui/consts/const-integer-bool-ops.stderr index 7885eb446f0dd..7fd973786d1b7 100644 --- a/src/test/ui/consts/const-integer-bool-ops.stderr +++ b/src/test/ui/consts/const-integer-bool-ops.stderr @@ -192,5 +192,5 @@ LL | const ARRR5: [i32; Y5] = [99; 0]; error: aborting due to 28 previous errors -Some errors occurred: E0080, E0308. +Some errors have detailed explanations: E0080, E0308. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-len-underflow-separate-spans.stderr b/src/test/ui/consts/const-len-underflow-separate-spans.stderr index 6ee92032bd777..ef4fa126dca32 100644 --- a/src/test/ui/consts/const-len-underflow-separate-spans.stderr +++ b/src/test/ui/consts/const-len-underflow-separate-spans.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error - --> $DIR/const-len-underflow-separate-spans.rs:7:1 + --> $DIR/const-len-underflow-separate-spans.rs:7:20 | LL | const LEN: usize = ONE - TWO; - | ^^^^^^^^^^^^^^^^^^^---------^ + | -------------------^^^^^^^^^- | | | attempt to subtract with overflow | diff --git a/src/test/ui/consts/const-match-pattern-arm.rs b/src/test/ui/consts/const-match-pattern-arm.rs index 3b985269a56c9..6ed3ac2356243 100644 --- a/src/test/ui/consts/const-match-pattern-arm.rs +++ b/src/test/ui/consts/const-match-pattern-arm.rs @@ -1,6 +1,7 @@ #![allow(warnings)] const x: bool = match Some(true) { + //~^ ERROR: constant contains unimplemented expression type [E0019] Some(value) => true, //~^ ERROR: constant contains unimplemented expression type [E0019] _ => false @@ -8,6 +9,7 @@ const x: bool = match Some(true) { const y: bool = { match Some(true) { + //~^ ERROR: constant contains unimplemented expression type [E0019] Some(value) => true, //~^ ERROR: constant contains unimplemented expression type [E0019] _ => false diff --git a/src/test/ui/consts/const-match-pattern-arm.stderr b/src/test/ui/consts/const-match-pattern-arm.stderr index c793cc0cd780a..709b66b7bf016 100644 --- a/src/test/ui/consts/const-match-pattern-arm.stderr +++ b/src/test/ui/consts/const-match-pattern-arm.stderr @@ -1,15 +1,27 @@ error[E0019]: constant contains unimplemented expression type - --> $DIR/const-match-pattern-arm.rs:4:5 + --> $DIR/const-match-pattern-arm.rs:3:23 + | +LL | const x: bool = match Some(true) { + | ^^^^^^^^^^ + +error[E0019]: constant contains unimplemented expression type + --> $DIR/const-match-pattern-arm.rs:5:5 | LL | Some(value) => true, | ^^^^^^^^^^^ error[E0019]: constant contains unimplemented expression type - --> $DIR/const-match-pattern-arm.rs:11:9 + --> $DIR/const-match-pattern-arm.rs:11:11 + | +LL | match Some(true) { + | ^^^^^^^^^^ + +error[E0019]: constant contains unimplemented expression type + --> $DIR/const-match-pattern-arm.rs:13:9 | LL | Some(value) => true, | ^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/const-pattern-irrefutable.stderr b/src/test/ui/consts/const-pattern-irrefutable.stderr index ee0d4d8837402..48fe24df4d044 100644 --- a/src/test/ui/consts/const-pattern-irrefutable.stderr +++ b/src/test/ui/consts/const-pattern-irrefutable.stderr @@ -1,19 +1,19 @@ error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered --> $DIR/const-pattern-irrefutable.rs:12:9 | -LL | let a = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered +LL | let a = 4; | ^ interpreted as a constant pattern, not new variable error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered --> $DIR/const-pattern-irrefutable.rs:13:9 | -LL | let c = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered +LL | let c = 4; | ^ interpreted as a constant pattern, not new variable error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered --> $DIR/const-pattern-irrefutable.rs:14:9 | -LL | let d = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered +LL | let d = 4; | ^ interpreted as a constant pattern, not new variable error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/const-prop-ice.stderr b/src/test/ui/consts/const-prop-ice.stderr index 749ef952b5ddb..8ec54b4438dda 100644 --- a/src/test/ui/consts/const-prop-ice.stderr +++ b/src/test/ui/consts/const-prop-ice.stderr @@ -1,7 +1,7 @@ error: index out of bounds: the len is 3 but the index is 3 --> $DIR/const-prop-ice.rs:2:5 | -LL | [0; 3][3u64 as usize]; //~ ERROR the len is 3 but the index is 3 +LL | [0; 3][3u64 as usize]; | ^^^^^^^^^^^^^^^^^^^^^ | = note: #[deny(const_err)] on by default diff --git a/src/test/ui/consts/const-prop-ice2.stderr b/src/test/ui/consts/const-prop-ice2.stderr index 4febd0ee1e391..68a7164da3d3c 100644 --- a/src/test/ui/consts/const-prop-ice2.stderr +++ b/src/test/ui/consts/const-prop-ice2.stderr @@ -1,7 +1,7 @@ error: index out of bounds: the len is 1 but the index is 1 --> $DIR/const-prop-ice2.rs:4:20 | -LL | println!("{}", xs[Enum::One as usize]); //~ ERROR the len is 1 but the index is 1 +LL | println!("{}", xs[Enum::One as usize]); | ^^^^^^^^^^^^^^^^^^^^^^ | = note: #[deny(const_err)] on by default diff --git a/src/test/ui/consts/const-ptr-nonnull.rs b/src/test/ui/consts/const-ptr-nonnull.rs new file mode 100644 index 0000000000000..25cf6cf4aaa6c --- /dev/null +++ b/src/test/ui/consts/const-ptr-nonnull.rs @@ -0,0 +1,11 @@ +use std::ptr::NonNull; + +fn main() { + let x: &'static NonNull = &(NonNull::dangling()); + //~^ ERROR temporary value dropped while borrowed + + let mut i: i32 = 10; + let non_null = NonNull::new(&mut i).unwrap(); + let x: &'static NonNull = &(non_null.cast()); + //~^ ERROR temporary value dropped while borrowed +} diff --git a/src/test/ui/consts/const-ptr-nonnull.stderr b/src/test/ui/consts/const-ptr-nonnull.stderr new file mode 100644 index 0000000000000..26946fb99024c --- /dev/null +++ b/src/test/ui/consts/const-ptr-nonnull.stderr @@ -0,0 +1,25 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-ptr-nonnull.rs:4:37 + | +LL | let x: &'static NonNull = &(NonNull::dangling()); + | --------------------- ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-ptr-nonnull.rs:9:37 + | +LL | let x: &'static NonNull = &(non_null.cast()); + | --------------------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-ptr-unique.rs b/src/test/ui/consts/const-ptr-unique.rs new file mode 100644 index 0000000000000..252c5d1a9cda5 --- /dev/null +++ b/src/test/ui/consts/const-ptr-unique.rs @@ -0,0 +1,10 @@ +#![feature(ptr_internals)] + +use std::ptr::Unique; + +fn main() { + let mut i: u32 = 10; + let unique = Unique::new(&mut i).unwrap(); + let x: &'static *mut u32 = &(unique.as_ptr()); + //~^ ERROR temporary value dropped while borrowed +} diff --git a/src/test/ui/consts/const-ptr-unique.stderr b/src/test/ui/consts/const-ptr-unique.stderr new file mode 100644 index 0000000000000..3644cf4cec7d3 --- /dev/null +++ b/src/test/ui/consts/const-ptr-unique.stderr @@ -0,0 +1,14 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-ptr-unique.rs:8:33 + | +LL | let x: &'static *mut u32 = &(unique.as_ptr()); + | ----------------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 8f8eb38e93873..113ec29239616 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -1,22 +1,22 @@ -error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{constant}}` +error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{constant}}#0` --> $DIR/const-size_of-cycle.rs:6:17 | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `Foo::bytes::{{constant}}`... - --> $SRC_DIR/libcore/mem.rs:LL:COL +note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`... + --> $SRC_DIR/libcore/mem/mod.rs:LL:COL | LL | intrinsics::size_of::() | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`... -note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}`... +note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... --> $DIR/const-size_of-cycle.rs:6:17 | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}`, completing the cycle + = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle note: cycle used when processing `Foo` --> $DIR/const-size_of-cycle.rs:5:1 | diff --git a/src/test/ui/consts/const-slice-oob.stderr b/src/test/ui/consts/const-slice-oob.stderr index 1122665cf8e55..c90cdbcb26970 100644 --- a/src/test/ui/consts/const-slice-oob.stderr +++ b/src/test/ui/consts/const-slice-oob.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error - --> $DIR/const-slice-oob.rs:4:1 + --> $DIR/const-slice-oob.rs:4:18 | LL | const BAR: u32 = FOO[5]; - | ^^^^^^^^^^^^^^^^^------^ + | -----------------^^^^^^- | | | index out of bounds: the len is 3 but the index is 5 | diff --git a/src/test/ui/consts/const-tup-index-span.stderr b/src/test/ui/consts/const-tup-index-span.stderr index ed631b824d569..2c4e273004506 100644 --- a/src/test/ui/consts/const-tup-index-span.stderr +++ b/src/test/ui/consts/const-tup-index-span.stderr @@ -15,5 +15,5 @@ LL | const ARR: [i32; TUP.0] = []; error: aborting due to 2 previous errors -Some errors occurred: E0080, E0308. +Some errors have detailed explanations: E0080, E0308. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-unsized.rs b/src/test/ui/consts/const-unsized.rs index e20ded68ceb96..319b8ef97deae 100644 --- a/src/test/ui/consts/const-unsized.rs +++ b/src/test/ui/consts/const-unsized.rs @@ -1,12 +1,12 @@ use std::fmt::Debug; -const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); +const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync)); //~^ ERROR the size for values of type const CONST_FOO: str = *"foo"; //~^ ERROR the size for values of type -static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); +static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); //~^ ERROR the size for values of type static STATIC_BAR: str = *"bar"; diff --git a/src/test/ui/consts/const-unsized.stderr b/src/test/ui/consts/const-unsized.stderr index 0f996fcd94340..beeea87bfb1d3 100644 --- a/src/test/ui/consts/const-unsized.stderr +++ b/src/test/ui/consts/const-unsized.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time --> $DIR/const-unsized.rs:3:16 | -LL | const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); - | ^^^^^^^^^^ doesn't have a size known at compile-time +LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync)); + | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)` = note: to learn more, visit @@ -19,8 +19,8 @@ LL | const CONST_FOO: str = *"foo"; error[E0277]: the size for values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time --> $DIR/const-unsized.rs:9:18 | -LL | static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); - | ^^^^^^^^^^ doesn't have a size known at compile-time +LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); + | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)` = note: to learn more, visit diff --git a/src/test/ui/consts/const_arg_local.rs b/src/test/ui/consts/const_arg_local.rs new file mode 100644 index 0000000000000..0da4b44a96839 --- /dev/null +++ b/src/test/ui/consts/const_arg_local.rs @@ -0,0 +1,13 @@ +// only-x86_64 + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; + +unsafe fn pclmul(a: __m128i, b: __m128i) -> __m128i { + let imm8 = 3; + _mm_clmulepi64_si128(a, b, imm8) //~ ERROR argument 3 is required to be a constant +} + +fn main() {} diff --git a/src/test/ui/consts/const_arg_local.stderr b/src/test/ui/consts/const_arg_local.stderr new file mode 100644 index 0000000000000..197b2f082e5a0 --- /dev/null +++ b/src/test/ui/consts/const_arg_local.stderr @@ -0,0 +1,8 @@ +error: argument 3 is required to be a constant + --> $DIR/const_arg_local.rs:10:5 + | +LL | _mm_clmulepi64_si128(a, b, imm8) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const_arg_promotable.rs b/src/test/ui/consts/const_arg_promotable.rs new file mode 100644 index 0000000000000..25f45104d6aa1 --- /dev/null +++ b/src/test/ui/consts/const_arg_promotable.rs @@ -0,0 +1,12 @@ +// only-x86_64 + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; + +unsafe fn pclmul(a: __m128i, b: __m128i) -> __m128i { + _mm_clmulepi64_si128(a, b, *&mut 42) //~ ERROR argument 3 is required to be a constant +} + +fn main() {} diff --git a/src/test/ui/consts/const_arg_promotable.stderr b/src/test/ui/consts/const_arg_promotable.stderr new file mode 100644 index 0000000000000..5de3ee6654ad9 --- /dev/null +++ b/src/test/ui/consts/const_arg_promotable.stderr @@ -0,0 +1,8 @@ +error: argument 3 is required to be a constant + --> $DIR/const_arg_promotable.rs:9:5 + | +LL | _mm_clmulepi64_si128(a, b, *&mut 42) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const_arg_promotable2.rs b/src/test/ui/consts/const_arg_promotable2.rs new file mode 100644 index 0000000000000..3399e51ed4edb --- /dev/null +++ b/src/test/ui/consts/const_arg_promotable2.rs @@ -0,0 +1,18 @@ +// This test is a regression test for a bug where we only checked function calls in no-const +// functions for `rustc_args_required_const` arguments. This meant that even though `bar` needs its +// argument to be const, inside a const fn (callable at runtime), the value for it may come from a +// non-constant (namely an argument to the const fn). + +#![feature(rustc_attrs)] +const fn foo(a: i32) { + bar(a); //~ ERROR argument 1 is required to be a constant +} + +#[rustc_args_required_const(0)] +const fn bar(_: i32) {} + +fn main() { + // this function call will pass a runtime-value (number of program arguments) to `foo`, which + // will in turn forward it to `bar`, which expects a compile-time argument + foo(std::env::args().count() as i32); +} diff --git a/src/test/ui/consts/const_arg_promotable2.stderr b/src/test/ui/consts/const_arg_promotable2.stderr new file mode 100644 index 0000000000000..149d1ce89408d --- /dev/null +++ b/src/test/ui/consts/const_arg_promotable2.stderr @@ -0,0 +1,8 @@ +error: argument 1 is required to be a constant + --> $DIR/const_arg_promotable2.rs:8:5 + | +LL | bar(a); + | ^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const_arg_wrapper.rs b/src/test/ui/consts/const_arg_wrapper.rs new file mode 100644 index 0000000000000..92ff264cd2b8e --- /dev/null +++ b/src/test/ui/consts/const_arg_wrapper.rs @@ -0,0 +1,12 @@ +// only-x86_64 + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; + +unsafe fn pclmul(a: __m128i, b: __m128i, imm8: i32) -> __m128i { + _mm_clmulepi64_si128(a, b, imm8) //~ ERROR argument 3 is required to be a constant +} + +fn main() {} diff --git a/src/test/ui/consts/const_arg_wrapper.stderr b/src/test/ui/consts/const_arg_wrapper.stderr new file mode 100644 index 0000000000000..4acf2f0f4d1e5 --- /dev/null +++ b/src/test/ui/consts/const_arg_wrapper.stderr @@ -0,0 +1,8 @@ +error: argument 3 is required to be a constant + --> $DIR/const_arg_wrapper.rs:9:5 + | +LL | _mm_clmulepi64_si128(a, b, imm8) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const_constructor/const-construct-call.rs b/src/test/ui/consts/const_constructor/const-construct-call.rs new file mode 100644 index 0000000000000..f2d2bda53c053 --- /dev/null +++ b/src/test/ui/consts/const_constructor/const-construct-call.rs @@ -0,0 +1,116 @@ +// Test that constructors are considered to be const fns with the required feature. + +// run-pass + +// revisions: min_const_fn const_fn + +#![cfg_attr(const_fn, feature(const_fn))] + +#![feature(const_constructor)] + +// Ctor(..) is transformed to Ctor { 0: ... } in HAIR lowering, so directly +// calling constructors doesn't require them to be const. + +type ExternalType = std::panic::AssertUnwindSafe<(Option, Result)>; + +const fn call_external_constructors_in_local_vars() -> ExternalType { + let f = Some; + let g = Err; + let h = std::panic::AssertUnwindSafe; + let x = f(5); + let y = g(false); + let z = h((x, y)); + z +} + +const CALL_EXTERNAL_CONSTRUCTORS_IN_LOCAL_VARS: ExternalType = { + let f = Some; + let g = Err; + let h = std::panic::AssertUnwindSafe; + let x = f(5); + let y = g(false); + let z = h((x, y)); + z +}; + +const fn call_external_constructors_in_temps() -> ExternalType { + let x = { Some }(5); + let y = (*&Err)(false); + let z = [std::panic::AssertUnwindSafe][0]((x, y)); + z +} + +const CALL_EXTERNAL_CONSTRUCTORS_IN_TEMPS: ExternalType = { + let x = { Some }(5); + let y = (*&Err)(false); + let z = [std::panic::AssertUnwindSafe][0]((x, y)); + z +}; + +#[derive(Debug, PartialEq)] +enum LocalOption { + Some(T), + _None, +} + +#[derive(Debug, PartialEq)] +enum LocalResult { + _Ok(T), + Err(E), +} + +#[derive(Debug, PartialEq)] +struct LocalAssertUnwindSafe(T); + +type LocalType = LocalAssertUnwindSafe<(LocalOption, LocalResult)>; + +const fn call_local_constructors_in_local_vars() -> LocalType { + let f = LocalOption::Some; + let g = LocalResult::Err; + let h = LocalAssertUnwindSafe; + let x = f(5); + let y = g(false); + let z = h((x, y)); + z +} + +const CALL_LOCAL_CONSTRUCTORS_IN_LOCAL_VARS: LocalType = { + let f = LocalOption::Some; + let g = LocalResult::Err; + let h = LocalAssertUnwindSafe; + let x = f(5); + let y = g(false); + let z = h((x, y)); + z +}; + +const fn call_local_constructors_in_temps() -> LocalType { + let x = { LocalOption::Some }(5); + let y = (*&LocalResult::Err)(false); + let z = [LocalAssertUnwindSafe][0]((x, y)); + z +} + +const CALL_LOCAL_CONSTRUCTORS_IN_TEMPS: LocalType = { + let x = { LocalOption::Some }(5); + let y = (*&LocalResult::Err)(false); + let z = [LocalAssertUnwindSafe][0]((x, y)); + z +}; + +fn main() { + assert_eq!( + ( + call_external_constructors_in_local_vars().0, + call_external_constructors_in_temps().0, + call_local_constructors_in_local_vars(), + call_local_constructors_in_temps(), + ), + ( + CALL_EXTERNAL_CONSTRUCTORS_IN_LOCAL_VARS.0, + CALL_EXTERNAL_CONSTRUCTORS_IN_TEMPS.0, + CALL_LOCAL_CONSTRUCTORS_IN_LOCAL_VARS, + CALL_LOCAL_CONSTRUCTORS_IN_TEMPS, + ) + ); +} diff --git a/src/test/ui/consts/const_constructor/feature-gate-const_constructor.const_fn.stderr b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.const_fn.stderr new file mode 100644 index 0000000000000..fa4f83ed01e15 --- /dev/null +++ b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.const_fn.stderr @@ -0,0 +1,34 @@ +error: `std::prelude::v1::Some` is not yet stable as a const fn + --> $DIR/feature-gate-const_constructor.rs:9:37 + | +LL | const EXTERNAL_CONST: Option = {Some}(1); + | ^^^^^^^^^ + | + = help: add `#![feature(const_constructor)]` to the crate attributes to enable + +error: `E::V` is not yet stable as a const fn + --> $DIR/feature-gate-const_constructor.rs:12:24 + | +LL | const LOCAL_CONST: E = {E::V}(1); + | ^^^^^^^^^ + | + = help: add `#![feature(const_constructor)]` to the crate attributes to enable + +error: `std::prelude::v1::Some` is not yet stable as a const fn + --> $DIR/feature-gate-const_constructor.rs:17:13 + | +LL | let _ = {Some}(1); + | ^^^^^^^^^ + | + = help: add `#![feature(const_constructor)]` to the crate attributes to enable + +error: `E::V` is not yet stable as a const fn + --> $DIR/feature-gate-const_constructor.rs:23:13 + | +LL | let _ = {E::V}(1); + | ^^^^^^^^^ + | + = help: add `#![feature(const_constructor)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/consts/const_constructor/feature-gate-const_constructor.min_const_fn.stderr b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.min_const_fn.stderr new file mode 100644 index 0000000000000..fa4f83ed01e15 --- /dev/null +++ b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.min_const_fn.stderr @@ -0,0 +1,34 @@ +error: `std::prelude::v1::Some` is not yet stable as a const fn + --> $DIR/feature-gate-const_constructor.rs:9:37 + | +LL | const EXTERNAL_CONST: Option = {Some}(1); + | ^^^^^^^^^ + | + = help: add `#![feature(const_constructor)]` to the crate attributes to enable + +error: `E::V` is not yet stable as a const fn + --> $DIR/feature-gate-const_constructor.rs:12:24 + | +LL | const LOCAL_CONST: E = {E::V}(1); + | ^^^^^^^^^ + | + = help: add `#![feature(const_constructor)]` to the crate attributes to enable + +error: `std::prelude::v1::Some` is not yet stable as a const fn + --> $DIR/feature-gate-const_constructor.rs:17:13 + | +LL | let _ = {Some}(1); + | ^^^^^^^^^ + | + = help: add `#![feature(const_constructor)]` to the crate attributes to enable + +error: `E::V` is not yet stable as a const fn + --> $DIR/feature-gate-const_constructor.rs:23:13 + | +LL | let _ = {E::V}(1); + | ^^^^^^^^^ + | + = help: add `#![feature(const_constructor)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/consts/const_constructor/feature-gate-const_constructor.rs b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.rs new file mode 100644 index 0000000000000..b37fd2fd243d1 --- /dev/null +++ b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.rs @@ -0,0 +1,28 @@ +// revisions: min_const_fn const_fn + +#![cfg_attr(const_fn, feature(const_fn))] + +enum E { + V(i32), +} + +const EXTERNAL_CONST: Option = {Some}(1); +//[min_const_fn]~^ ERROR is not yet stable as a const fn +//[const_fn]~^^ ERROR is not yet stable as a const fn +const LOCAL_CONST: E = {E::V}(1); +//[min_const_fn]~^ ERROR is not yet stable as a const fn +//[const_fn]~^^ ERROR is not yet stable as a const fn + +const fn external_fn() { + let _ = {Some}(1); + //[min_const_fn]~^ ERROR is not yet stable as a const fn + //[const_fn]~^^ ERROR is not yet stable as a const fn +} + +const fn local_fn() { + let _ = {E::V}(1); + //[min_const_fn]~^ ERROR is not yet stable as a const fn + //[const_fn]~^^ ERROR is not yet stable as a const fn +} + +fn main() {} diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index 6649fb997cce4..53b960b4ec0e0 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -7,7 +7,7 @@ LL | self.state = x; error[E0017]: references in constants may only refer to immutable values --> $DIR/const_let_assign3.rs:16:5 | -LL | s.foo(3); //~ ERROR references in constants may only refer to immutable values +LL | s.foo(3); | ^ constants require immutable values error[E0017]: references in constants may only refer to immutable values @@ -24,5 +24,5 @@ LL | *y = 42; error: aborting due to 4 previous errors -Some errors occurred: E0017, E0019. +Some errors have detailed explanations: E0017, E0019. For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/consts/const_let_refutable.nll.stderr b/src/test/ui/consts/const_let_refutable.nll.stderr new file mode 100644 index 0000000000000..3cc6de5bc4285 --- /dev/null +++ b/src/test/ui/consts/const_let_refutable.nll.stderr @@ -0,0 +1,31 @@ +error[E0005]: refutable pattern in function argument: `&[]` not covered + --> $DIR/const_let_refutable.rs:3:16 + | +LL | const fn slice([a, b]: &[i32]) -> i32 { + | ^^^^^^ pattern `&[]` not covered + +error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn` + --> $DIR/const_let_refutable.rs:4:5 + | +LL | a + b + | ^^^^^ + | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 + = help: add #![feature(const_fn)] to the crate attributes to enable + +error[E0381]: use of possibly uninitialized variable: `a` + --> $DIR/const_let_refutable.rs:4:5 + | +LL | a + b + | ^ use of possibly uninitialized `a` + +error[E0381]: use of possibly uninitialized variable: `b` + --> $DIR/const_let_refutable.rs:4:9 + | +LL | a + b + | ^ use of possibly uninitialized `b` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0005, E0381, E0723. +For more information about an error, try `rustc --explain E0005`. diff --git a/src/test/ui/consts/const_let_refutable.rs b/src/test/ui/consts/const_let_refutable.rs index 345f682868fbc..322048c7fbf3f 100644 --- a/src/test/ui/consts/const_let_refutable.rs +++ b/src/test/ui/consts/const_let_refutable.rs @@ -1,5 +1,11 @@ fn main() {} const fn slice([a, b]: &[i32]) -> i32 { //~ ERROR refutable pattern in function argument - a + b + a + b //~ ERROR can only call other `const fn` within a `const fn` + //~^ WARN use of possibly uninitialized variable: `a` + //~| WARN this error has been downgraded to a warning for backwards compatibility + //~| WARN this represents potential undefined behavior in your code and this warning will + //~| WARN use of possibly uninitialized variable: `b` + //~| WARN this error has been downgraded to a warning for backwards compatibility + //~| WARN this represents potential undefined behavior in your code and this warning will } diff --git a/src/test/ui/consts/const_let_refutable.stderr b/src/test/ui/consts/const_let_refutable.stderr index c5d2ba02a70c6..cdd696ee7fbff 100644 --- a/src/test/ui/consts/const_let_refutable.stderr +++ b/src/test/ui/consts/const_let_refutable.stderr @@ -1,9 +1,39 @@ error[E0005]: refutable pattern in function argument: `&[]` not covered --> $DIR/const_let_refutable.rs:3:16 | -LL | const fn slice([a, b]: &[i32]) -> i32 { //~ ERROR refutable pattern in function argument +LL | const fn slice([a, b]: &[i32]) -> i32 { | ^^^^^^ pattern `&[]` not covered -error: aborting due to previous error +error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn` + --> $DIR/const_let_refutable.rs:4:5 + | +LL | a + b + | ^^^^^ + | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 + = help: add #![feature(const_fn)] to the crate attributes to enable + +warning[E0381]: use of possibly uninitialized variable: `a` + --> $DIR/const_let_refutable.rs:4:5 + | +LL | a + b + | ^ use of possibly uninitialized `a` + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + +warning[E0381]: use of possibly uninitialized variable: `b` + --> $DIR/const_let_refutable.rs:4:9 + | +LL | a + b + | ^ use of possibly uninitialized `b` + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0005`. +Some errors have detailed explanations: E0005, E0381, E0723. +For more information about an error, try `rustc --explain E0005`. diff --git a/src/test/ui/consts/const_short_circuit.rs b/src/test/ui/consts/const_short_circuit.rs index 1e7b7ed319355..87b14a1117805 100644 --- a/src/test/ui/consts/const_short_circuit.rs +++ b/src/test/ui/consts/const_short_circuit.rs @@ -1,5 +1,3 @@ -#![feature(underscore_const_names)] - const _: bool = false && false; const _: bool = true && false; const _: bool = { diff --git a/src/test/ui/consts/const_short_circuit.stderr b/src/test/ui/consts/const_short_circuit.stderr index a67bb0b1b6d98..0a6536c88372a 100644 --- a/src/test/ui/consts/const_short_circuit.stderr +++ b/src/test/ui/consts/const_short_circuit.stderr @@ -1,23 +1,23 @@ error: new features like let bindings are not permitted in constants which also use short circuiting operators - --> $DIR/const_short_circuit.rs:6:9 + --> $DIR/const_short_circuit.rs:4:9 | LL | let mut x = true && false; | ^^^^^ | note: use of `&&` operator here does not actually short circuit due to the const evaluator presently not being able to do control flow. See https://github.com/rust-lang/rust/issues/49146 for more information. - --> $DIR/const_short_circuit.rs:6:22 + --> $DIR/const_short_circuit.rs:4:22 | LL | let mut x = true && false; | ^^ error: new features like let bindings are not permitted in constants which also use short circuiting operators - --> $DIR/const_short_circuit.rs:11:9 + --> $DIR/const_short_circuit.rs:9:9 | LL | let x = true && false; | ^ | note: use of `&&` operator here does not actually short circuit due to the const evaluator presently not being able to do control flow. See https://github.com/rust-lang/rust/issues/49146 for more information. - --> $DIR/const_short_circuit.rs:11:18 + --> $DIR/const_short_circuit.rs:9:18 | LL | let x = true && false; | ^^ diff --git a/src/test/ui/consts/dangling-alloc-id-ice.stderr b/src/test/ui/consts/dangling-alloc-id-ice.stderr index 2cd8711f03d31..87f84480bf66b 100644 --- a/src/test/ui/consts/dangling-alloc-id-ice.stderr +++ b/src/test/ui/consts/dangling-alloc-id-ice.stderr @@ -1,7 +1,7 @@ error: any use of this value will cause an error --> $DIR/dangling-alloc-id-ice.rs:8:1 | -LL | / const FOO: &() = { //~ ERROR any use of this value will cause an error +LL | / const FOO: &() = { LL | | let y = (); LL | | unsafe { Foo { y: &y }.long_live_the_unit } LL | | }; diff --git a/src/test/ui/consts/dangling_raw_ptr.stderr b/src/test/ui/consts/dangling_raw_ptr.stderr index 091f1f785cb02..0168c08f011d4 100644 --- a/src/test/ui/consts/dangling_raw_ptr.stderr +++ b/src/test/ui/consts/dangling_raw_ptr.stderr @@ -1,7 +1,7 @@ error: any use of this value will cause an error --> $DIR/dangling_raw_ptr.rs:1:1 | -LL | / const FOO: *const u32 = { //~ ERROR any use of this value will cause an error +LL | / const FOO: *const u32 = { LL | | let x = 42; LL | | &x LL | | }; diff --git a/src/test/ui/consts/enum-discr-type-err.rs b/src/test/ui/consts/enum-discr-type-err.rs new file mode 100644 index 0000000000000..d66c4f47d03ee --- /dev/null +++ b/src/test/ui/consts/enum-discr-type-err.rs @@ -0,0 +1,29 @@ +// Test that we mark enum discriminant values as having errors, even when the +// diagnostic is deduplicated. + +struct F; +struct T; + +impl F { + const V: i32 = 0; +} + +impl T { + const V: i32 = 0; +} + +macro_rules! mac { + ($( $v: ident = $s: ident,)*) => { + enum E { + $( $v = $s::V, )* + //~^ ERROR mismatched types + } + } +} + +mac! { + A = F, + B = T, +} + +fn main() {} diff --git a/src/test/ui/consts/enum-discr-type-err.stderr b/src/test/ui/consts/enum-discr-type-err.stderr new file mode 100644 index 0000000000000..3c4fac7327d40 --- /dev/null +++ b/src/test/ui/consts/enum-discr-type-err.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/enum-discr-type-err.rs:18:21 + | +LL | $( $v = $s::V, )* + | ^^^^^ expected isize, found i32 +... +LL | / mac! { +LL | | A = F, +LL | | B = T, +LL | | } + | |_- in this macro invocation +help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit + | +LL | $( $v = $s::V.try_into().unwrap(), )* + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/consts/invalid_promotion.rs b/src/test/ui/consts/invalid_promotion.rs new file mode 100644 index 0000000000000..f98406e50e9ae --- /dev/null +++ b/src/test/ui/consts/invalid_promotion.rs @@ -0,0 +1,18 @@ +// compile-pass +// note this was only reproducible with lib crates +// compile-flags: --crate-type=lib + +pub struct Hz; + +impl Hz { + pub const fn num(&self) -> u32 { + 42 + } + pub const fn normalized(&self) -> Hz { + Hz + } + + pub const fn as_u32(&self) -> u32 { + self.normalized().num() // this used to promote the `self.normalized()` + } +} diff --git a/src/test/ui/consts/issue-54224.rs b/src/test/ui/consts/issue-54224.rs index b5a8fe8819cdd..f1947933d6707 100644 --- a/src/test/ui/consts/issue-54224.rs +++ b/src/test/ui/consts/issue-54224.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]); //~ ERROR temporary value dropped while borrowed use std::borrow::Cow; diff --git a/src/test/ui/consts/issue-54224.stderr b/src/test/ui/consts/issue-54224.stderr index 451f49c1cb57a..8dcb4daca3b70 100644 --- a/src/test/ui/consts/issue-54224.stderr +++ b/src/test/ui/consts/issue-54224.stderr @@ -1,7 +1,7 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-54224.rs:3:39 + --> $DIR/issue-54224.rs:1:39 | -LL | const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]); //~ ERROR temporary value dropped while borrowed +LL | const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]); | ------^^^^^^^^^- | | | | | | | temporary value is freed at the end of this statement @@ -9,7 +9,7 @@ LL | const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]); //~ ERROR temporary value | using this value as a constant requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-54224.rs:11:57 + --> $DIR/issue-54224.rs:9:57 | LL | pub const Z: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[*b"ABC"]); | ---------------^^^^^^^^^- diff --git a/src/test/ui/consts/issue-62045.rs b/src/test/ui/consts/issue-62045.rs new file mode 100644 index 0000000000000..9f41ed9a24523 --- /dev/null +++ b/src/test/ui/consts/issue-62045.rs @@ -0,0 +1,5 @@ +// compile-pass + +fn main() { + assert_eq!(&mut [0; 1][..], &mut []); +} diff --git a/src/test/ui/consts/match_ice.rs b/src/test/ui/consts/match_ice.rs index 53c5782a4c70e..1c13bfceb6cc2 100644 --- a/src/test/ui/consts/match_ice.rs +++ b/src/test/ui/consts/match_ice.rs @@ -2,9 +2,17 @@ struct S; +#[derive(PartialEq, Eq)] +struct T; + fn main() { const C: &S = &S; - match C { //~ ERROR non-exhaustive - C => {} // this is a common bug around constants and references in patterns + match C { + C => {} + //~^ ERROR to use a constant of type `S` in a pattern, `S` must be annotated with + } + const K: &T = &T; + match K { //~ ERROR non-exhaustive patterns: `&T` not covered + K => {} } } diff --git a/src/test/ui/consts/match_ice.stderr b/src/test/ui/consts/match_ice.stderr index e6e04e2c46276..158581fcb1599 100644 --- a/src/test/ui/consts/match_ice.stderr +++ b/src/test/ui/consts/match_ice.stderr @@ -1,9 +1,17 @@ -error[E0004]: non-exhaustive patterns: `&S` not covered - --> $DIR/match_ice.rs:7:11 +error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/match_ice.rs:11:9 | -LL | match C { //~ ERROR non-exhaustive - | ^ pattern `&S` not covered +LL | C => {} + | ^ -error: aborting due to previous error +error[E0004]: non-exhaustive patterns: `&T` not covered + --> $DIR/match_ice.rs:15:11 + | +LL | match K { + | ^ pattern `&T` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs new file mode 100644 index 0000000000000..3992607c387e1 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs @@ -0,0 +1,10 @@ +#![feature(rustc_attrs, staged_api)] + +#[stable(feature = "rust1", since = "1.0.0")] +const fn error(_: fn()) {} //~ ERROR function pointers in const fn are unstable + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_allow_const_fn_ptr] +const fn compiles(_: fn()) {} + +fn main() {} diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr new file mode 100644 index 0000000000000..e6e1ced6592a2 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr @@ -0,0 +1,12 @@ +error[E0723]: function pointers in const fn are unstable + --> $DIR/allow_const_fn_ptr.rs:4:16 + | +LL | const fn error(_: fn()) {} + | ^ + | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 + = help: add #![feature(const_fn)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs new file mode 100644 index 0000000000000..0395795ef7bfe --- /dev/null +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs @@ -0,0 +1,11 @@ +#![feature(staged_api)] + +#[stable(feature = "rust1", since = "1.0.0")] +const fn error(_: fn()) {} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_allow_const_fn_ptr] +//~^ ERROR unless otherwise specified, attributes with the prefix `rustc_` are reserved +const fn compiles(_: fn()) {} + +fn main() {} diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr new file mode 100644 index 0000000000000..c934307e918b9 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr @@ -0,0 +1,12 @@ +error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics + --> $DIR/allow_const_fn_ptr_feature_gate.rs:7:3 + | +LL | #[rustc_allow_const_fn_ptr] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(rustc_attrs)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs new file mode 100644 index 0000000000000..1d8b95ab1a2fd --- /dev/null +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs @@ -0,0 +1,18 @@ +// run-pass + +#![feature(rustc_attrs, staged_api)] +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_allow_const_fn_ptr] +const fn takes_fn_ptr(_: fn()) {} + +const FN: fn() = || (); + +const fn gives_fn_ptr() { + takes_fn_ptr(FN) +} + +fn main() { + gives_fn_ptr(); +} diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr index 62f678790d21f..ac8d082fc1904 100644 --- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr @@ -1,9 +1,10 @@ -error[E0723]: heap allocations are not allowed in const fn (see issue #57563) +error[E0723]: heap allocations are not allowed in const fn --> $DIR/bad_const_fn_body_ice.rs:2:5 | -LL | vec![1, 2, 3] //~ ERROR heap allocations are not allowed in const fn +LL | vec![1, 2, 3] | ^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/consts/min_const_fn/cast_errors.stderr b/src/test/ui/consts/min_const_fn/cast_errors.stderr index b5af3e7ee4665..b1a50be99835d 100644 --- a/src/test/ui/consts/min_const_fn/cast_errors.stderr +++ b/src/test/ui/consts/min_const_fn/cast_errors.stderr @@ -1,41 +1,46 @@ -error[E0723]: unsizing casts are not allowed in const fn (see issue #57563) +error[E0723]: unsizing casts are not allowed in const fn --> $DIR/cast_errors.rs:3:41 | LL | const fn unsize(x: &[u8; 3]) -> &[u8] { x } | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable (see issue #57563) +error[E0723]: function pointers in const fn are unstable --> $DIR/cast_errors.rs:5:23 | LL | const fn closure() -> fn() { || {} } | ^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable (see issue #57563) +error[E0723]: function pointers in const fn are unstable --> $DIR/cast_errors.rs:8:5 | LL | (|| {}) as fn(); | ^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable (see issue #57563) +error[E0723]: function pointers in const fn are unstable --> $DIR/cast_errors.rs:11:28 | LL | const fn reify(f: fn()) -> unsafe fn() { f } | ^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable (see issue #57563) +error[E0723]: function pointers in const fn are unstable --> $DIR/cast_errors.rs:13:21 | LL | const fn reify2() { main as unsafe fn(); } | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to 5 previous errors diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr index d84e2651d4fc4..7f6132ce9cd5e 100644 --- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr +++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr @@ -1,9 +1,10 @@ -error[E0723]: function pointers in const fn are unstable (see issue #57563) +error[E0723]: function pointers in const fn are unstable --> $DIR/cmp_fn_pointers.rs:1:14 | -LL | const fn cmp(x: fn(), y: fn()) -> bool { //~ ERROR function pointers in const fn are unstable +LL | const fn cmp(x: fn(), y: fn()) -> bool { | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/consts/min_const_fn/loop_ice.stderr b/src/test/ui/consts/min_const_fn/loop_ice.stderr index 716e8380c45da..cb85956266b0e 100644 --- a/src/test/ui/consts/min_const_fn/loop_ice.stderr +++ b/src/test/ui/consts/min_const_fn/loop_ice.stderr @@ -1,9 +1,10 @@ -error[E0723]: loops are not allowed in const fn (see issue #57563) +error[E0723]: loops are not allowed in const fn --> $DIR/loop_ice.rs:2:5 | -LL | loop {} //~ ERROR loops are not allowed in const fn +LL | loop {} | ^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr index feb4960e0c746..abbdb4ab632dc 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr @@ -1,262 +1,292 @@ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/min_const_fn.rs:37:25 | -LL | const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated +LL | const fn into_inner(self) -> T { self.0 } | ^^^^ constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:39:36 | LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/min_const_fn.rs:44:28 | -LL | const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated +LL | const fn into_inner_lt(self) -> T { self.0 } | ^^^^ constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:46:42 | LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/min_const_fn.rs:51:27 | -LL | const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors +LL | const fn into_inner_s(self) -> T { self.0 } | ^^^^ constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:53:38 | LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:58:39 | LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:76:16 | LL | const fn foo11(t: T) -> T { t } | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:78:18 | LL | const fn foo11_2(t: T) -> T { t } | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn (see issue #57563) +error[E0723]: only int, `bool` and `char` operations are stable in const fn --> $DIR/min_const_fn.rs:80:33 | LL | const fn foo19(f: f32) -> f32 { f * 2.0 } | ^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn (see issue #57563) +error[E0723]: only int, `bool` and `char` operations are stable in const fn --> $DIR/min_const_fn.rs:82:35 | LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f } | ^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: only int and `bool` operations are stable in const fn (see issue #57563) +error[E0723]: only int and `bool` operations are stable in const fn --> $DIR/min_const_fn.rs:84:35 | LL | const fn foo19_3(f: f32) -> f32 { -f } | ^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn (see issue #57563) +error[E0723]: only int, `bool` and `char` operations are stable in const fn --> $DIR/min_const_fn.rs:86:43 | LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g } | ^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: cannot access `static` items in const fn (see issue #57563) +error[E0723]: cannot access `static` items in const fn --> $DIR/min_const_fn.rs:90:27 | -LL | const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn +LL | const fn foo25() -> u32 { BAR } | ^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: cannot access `static` items in const fn (see issue #57563) +error[E0723]: cannot access `static` items in const fn --> $DIR/min_const_fn.rs:91:36 | -LL | const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items +LL | const fn foo26() -> &'static u32 { &BAR } | ^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn (see issue #57563) +error[E0723]: casting pointers to ints is unstable in const fn --> $DIR/min_const_fn.rs:92:42 | LL | const fn foo30(x: *const u32) -> usize { x as usize } | ^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn (see issue #57563) +error[E0723]: casting pointers to ints is unstable in const fn --> $DIR/min_const_fn.rs:94:63 | LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn (see issue #57563) +error[E0723]: casting pointers to ints is unstable in const fn --> $DIR/min_const_fn.rs:96:42 | LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } | ^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn (see issue #57563) +error[E0723]: casting pointers to ints is unstable in const fn --> $DIR/min_const_fn.rs:98:63 | LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: `if`, `match`, `&&` and `||` are not stable in const fn (see issue #57563) +error[E0723]: loops and conditional expressions are not stable in const fn --> $DIR/min_const_fn.rs:100:38 | LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } } | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: `if`, `match`, `&&` and `||` are not stable in const fn (see issue #57563) +error[E0723]: loops and conditional expressions are not stable in const fn --> $DIR/min_const_fn.rs:102:29 | -LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn +LL | const fn foo30_5(b: bool) { while b { } } | ^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: `if`, `match`, `&&` and `||` are not stable in const fn (see issue #57563) +error[E0723]: loops and conditional expressions are not stable in const fn --> $DIR/min_const_fn.rs:104:44 | LL | const fn foo36(a: bool, b: bool) -> bool { a && b } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: `if`, `match`, `&&` and `||` are not stable in const fn (see issue #57563) +error[E0723]: loops and conditional expressions are not stable in const fn --> $DIR/min_const_fn.rs:106:44 | LL | const fn foo37(a: bool, b: bool) -> bool { a || b } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:108:14 | LL | const fn inc(x: &mut i32) { *x += 1 } | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:113:6 | LL | impl Foo { | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:118:6 | LL | impl Foo { | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:123:6 | LL | impl Foo { | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: `impl Trait` in const fn is unstable (see issue #57563) +error[E0723]: `impl Trait` in const fn is unstable --> $DIR/min_const_fn.rs:129:24 | LL | const fn no_rpit2() -> AlanTuring { AlanTuring(0) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:131:34 | LL | const fn no_apit2(_x: AlanTuring) {} | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:133:22 | -LL | const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` +LL | const fn no_apit(_x: impl std::fmt::Debug) {} | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: `impl Trait` in const fn is unstable (see issue #57563) +error[E0723]: `impl Trait` in const fn is unstable --> $DIR/min_const_fn.rs:134:23 | -LL | const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable +LL | const fn no_rpit() -> impl std::fmt::Debug {} | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:135:23 | -LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` +LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} | ^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:136:32 | LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -warning[E0515]: cannot return reference to temporary value +error[E0515]: cannot return reference to temporary value --> $DIR/min_const_fn.rs:136:63 | LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } @@ -264,35 +294,35 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } | || | |temporary value created here | returns a reference to data owned by the current function - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) - --> $DIR/min_const_fn.rs:141:41 +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:144:41 | -LL | const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable (see issue #57563) - --> $DIR/min_const_fn.rs:144:21 +error[E0723]: function pointers in const fn are unstable + --> $DIR/min_const_fn.rs:147:21 | LL | const fn no_fn_ptrs(_x: fn()) {} | ^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable (see issue #57563) - --> $DIR/min_const_fn.rs:146:27 +error[E0723]: function pointers in const fn are unstable + --> $DIR/min_const_fn.rs:149:27 | LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } | ^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error: aborting due to 36 previous errors +error: aborting due to 37 previous errors -Some errors occurred: E0493, E0515, E0723. -For more information about an error, try `rustc --explain E0493`. +Some errors have detailed explanations: E0515, E0723. +For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index ee3ffcd4026d3..9523fcbfc603f 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -69,8 +69,8 @@ const fn i32_ops3(c: i32, d: i32) -> bool { c != d } const fn i32_ops4(c: i32, d: i32) -> i32 { c + d } const fn char_cast(u: u8) -> char { u as char } const unsafe fn ret_i32_no_unsafe() -> i32 { 42 } -const unsafe fn ret_null_ptr_no_unsafe() -> *const T { 0 as *const T } -const unsafe fn ret_null_mut_ptr_no_unsafe() -> *mut T { 0 as *mut T } +const unsafe fn ret_null_ptr_no_unsafe() -> *const T { core::ptr::null() } +const unsafe fn ret_null_mut_ptr_no_unsafe() -> *mut T { core::ptr::null_mut() } // not ok const fn foo11(t: T) -> T { t } @@ -98,13 +98,13 @@ const fn foo30_2(x: *mut u32) -> usize { x as usize } const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } //~^ ERROR casting pointers to ints is unstable const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } } -//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn +//~^ ERROR loops and conditional expressions are not stable in const fn const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn const fn foo30_6() -> bool { let x = true; x } const fn foo36(a: bool, b: bool) -> bool { a && b } -//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn +//~^ ERROR loops and conditional expressions are not stable in const fn const fn foo37(a: bool, b: bool) -> bool { a || b } -//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn +//~^ ERROR loops and conditional expressions are not stable in const fn const fn inc(x: &mut i32) { *x += 1 } //~^ ERROR mutable references in const fn are unstable @@ -135,14 +135,16 @@ const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~^ ERROR trait bounds other than `Sized` +//~| WARNING cannot return reference to temporary value +//~| WARNING this error has been downgraded to a warning +//~| WARNING this warning will become a hard error in the future const fn no_unsafe() { unsafe {} } -const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 } +const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } //~^ ERROR trait bounds other than `Sized` const fn no_fn_ptrs(_x: fn()) {} //~^ ERROR function pointers in const fn are unstable const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } //~^ ERROR function pointers in const fn are unstable - diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index e095ccaf20e29..28a5ffb201594 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -1,286 +1,332 @@ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/min_const_fn.rs:37:25 | -LL | const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated +LL | const fn into_inner(self) -> T { self.0 } | ^^^^ constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:39:36 | LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/min_const_fn.rs:44:28 | -LL | const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated +LL | const fn into_inner_lt(self) -> T { self.0 } | ^^^^ constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:46:42 | LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/min_const_fn.rs:51:27 | -LL | const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors +LL | const fn into_inner_s(self) -> T { self.0 } | ^^^^ constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:53:38 | LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:58:39 | LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:76:16 | LL | const fn foo11(t: T) -> T { t } | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:78:18 | LL | const fn foo11_2(t: T) -> T { t } | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn (see issue #57563) +error[E0723]: only int, `bool` and `char` operations are stable in const fn --> $DIR/min_const_fn.rs:80:33 | LL | const fn foo19(f: f32) -> f32 { f * 2.0 } | ^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn (see issue #57563) +error[E0723]: only int, `bool` and `char` operations are stable in const fn --> $DIR/min_const_fn.rs:82:35 | LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f } | ^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: only int and `bool` operations are stable in const fn (see issue #57563) +error[E0723]: only int and `bool` operations are stable in const fn --> $DIR/min_const_fn.rs:84:35 | LL | const fn foo19_3(f: f32) -> f32 { -f } | ^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn (see issue #57563) +error[E0723]: only int, `bool` and `char` operations are stable in const fn --> $DIR/min_const_fn.rs:86:43 | LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g } | ^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: cannot access `static` items in const fn (see issue #57563) +error[E0723]: cannot access `static` items in const fn --> $DIR/min_const_fn.rs:90:27 | -LL | const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn +LL | const fn foo25() -> u32 { BAR } | ^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: cannot access `static` items in const fn (see issue #57563) +error[E0723]: cannot access `static` items in const fn --> $DIR/min_const_fn.rs:91:36 | -LL | const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items +LL | const fn foo26() -> &'static u32 { &BAR } | ^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn (see issue #57563) +error[E0723]: casting pointers to ints is unstable in const fn --> $DIR/min_const_fn.rs:92:42 | LL | const fn foo30(x: *const u32) -> usize { x as usize } | ^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn (see issue #57563) +error[E0723]: casting pointers to ints is unstable in const fn --> $DIR/min_const_fn.rs:94:63 | LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn (see issue #57563) +error[E0723]: casting pointers to ints is unstable in const fn --> $DIR/min_const_fn.rs:96:42 | LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } | ^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn (see issue #57563) +error[E0723]: casting pointers to ints is unstable in const fn --> $DIR/min_const_fn.rs:98:63 | LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: `if`, `match`, `&&` and `||` are not stable in const fn (see issue #57563) +error[E0723]: loops and conditional expressions are not stable in const fn --> $DIR/min_const_fn.rs:100:38 | LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } } | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: `if`, `match`, `&&` and `||` are not stable in const fn (see issue #57563) +error[E0723]: loops and conditional expressions are not stable in const fn --> $DIR/min_const_fn.rs:102:29 | -LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn +LL | const fn foo30_5(b: bool) { while b { } } | ^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: `if`, `match`, `&&` and `||` are not stable in const fn (see issue #57563) +error[E0723]: loops and conditional expressions are not stable in const fn --> $DIR/min_const_fn.rs:104:44 | LL | const fn foo36(a: bool, b: bool) -> bool { a && b } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: `if`, `match`, `&&` and `||` are not stable in const fn (see issue #57563) +error[E0723]: loops and conditional expressions are not stable in const fn --> $DIR/min_const_fn.rs:106:44 | LL | const fn foo37(a: bool, b: bool) -> bool { a || b } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:108:14 | LL | const fn inc(x: &mut i32) { *x += 1 } | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:113:6 | LL | impl Foo { | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:118:6 | LL | impl Foo { | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:123:6 | LL | impl Foo { | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: `impl Trait` in const fn is unstable (see issue #57563) +error[E0723]: `impl Trait` in const fn is unstable --> $DIR/min_const_fn.rs:129:24 | LL | const fn no_rpit2() -> AlanTuring { AlanTuring(0) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:131:34 | LL | const fn no_apit2(_x: AlanTuring) {} | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:133:22 | -LL | const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` +LL | const fn no_apit(_x: impl std::fmt::Debug) {} | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: `impl Trait` in const fn is unstable (see issue #57563) +error[E0723]: `impl Trait` in const fn is unstable --> $DIR/min_const_fn.rs:134:23 | -LL | const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable +LL | const fn no_rpit() -> impl std::fmt::Debug {} | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:135:23 | -LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` +LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} | ^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:136:32 | LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) - --> $DIR/min_const_fn.rs:141:41 +warning[E0515]: cannot return reference to temporary value + --> $DIR/min_const_fn.rs:136:63 | -LL | const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } + | ^-- + | || + | |temporary value created here + | returns a reference to data owned by the current function + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:144:41 + | +LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable (see issue #57563) - --> $DIR/min_const_fn.rs:144:21 +error[E0723]: function pointers in const fn are unstable + --> $DIR/min_const_fn.rs:147:21 | LL | const fn no_fn_ptrs(_x: fn()) {} | ^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable (see issue #57563) - --> $DIR/min_const_fn.rs:146:27 +error[E0723]: function pointers in const fn are unstable + --> $DIR/min_const_fn.rs:149:27 | LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } | ^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to 36 previous errors -Some errors occurred: E0493, E0723. -For more information about an error, try `rustc --explain E0493`. +Some errors have detailed explanations: E0515, E0723. +For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr index 2800d622f5353..9ffb549057bc6 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr @@ -1,20 +1,22 @@ -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn_dyn.rs:9:5 | LL | x.0.field; | ^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn_dyn.rs:12:66 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } | ^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -warning[E0716]: temporary value dropped while borrowed +error[E0716]: temporary value dropped while borrowed --> $DIR/min_const_fn_dyn.rs:12:67 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } @@ -22,11 +24,8 @@ LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } | || | |creates a temporary which is freed while still in use | cast requires that borrow lasts for `'static` - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -Some errors occurred: E0716, E0723. +Some errors have detailed explanations: E0716, E0723. For more information about an error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs index 6ca1e59b3af10..75b67192f0081 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs @@ -11,5 +11,8 @@ const fn no_inner_dyn_trait2(x: Hide) { } const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } //~^ ERROR trait bounds other than `Sized` +//~| WARNING temporary value dropped while borrowed +//~| WARNING this error has been downgraded to a warning +//~| WARNING this warning will become a hard error in the future fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr index 8ff963722cf15..9ded93c16727b 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr @@ -1,19 +1,35 @@ -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn_dyn.rs:9:5 | LL | x.0.field; | ^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable (see issue #57563) +error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn_dyn.rs:12:66 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } | ^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable +warning[E0716]: temporary value dropped while borrowed + --> $DIR/min_const_fn_dyn.rs:12:67 + | +LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } + | -^ - temporary value is freed at the end of this statement + | || + | |creates a temporary which is freed while still in use + | cast requires that borrow lasts for `'static` + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0723`. +Some errors have detailed explanations: E0716, E0723. +For more information about an error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr index 8838ababe2c0e..5316d07afa428 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr @@ -1,17 +1,19 @@ -error[E0723]: function pointers in const fn are unstable (see issue #57563) +error[E0723]: function pointers in const fn are unstable --> $DIR/min_const_fn_fn_ptr.rs:11:5 | LL | x.0.field; | ^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable (see issue #57563) +error[E0723]: function pointers in const fn are unstable --> $DIR/min_const_fn_fn_ptr.rs:14:59 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) } | ^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd.rs index 781d2891c26ed..23bd73325472e 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd.rs @@ -1,5 +1,3 @@ -#![feature(integer_atomics)] - // compile-pass use std::cell::UnsafeCell; diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs index db416e7eb03ac..759d9ab6a4081 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -12,14 +12,14 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn` +const fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn` #[unstable(feature = "rust1", issue="0")] const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn` +const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn` #[stable(feature = "rust1", since = "1.0.0")] // conformity is required, even with `const_fn` feature gate @@ -31,6 +31,6 @@ const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn` +const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn` fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index 1e6f698b3c8e3..c52d7c8511561 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -1,33 +1,37 @@ -error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563) +error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn` --> $DIR/min_const_fn_libstd_stability.rs:15:25 | -LL | const fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn` +LL | const fn bar() -> u32 { foo() } | ^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563) +error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn` --> $DIR/min_const_fn_libstd_stability.rs:22:26 | -LL | const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn` +LL | const fn bar2() -> u32 { foo2() } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn (see issue #57563) +error[E0723]: only int, `bool` and `char` operations are stable in const fn --> $DIR/min_const_fn_libstd_stability.rs:26:26 | -LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations +LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } | ^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563) +error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn` --> $DIR/min_const_fn_libstd_stability.rs:34:32 | -LL | const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn` +LL | const fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs index e25dafa74d7ab..0152561aefcb2 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs @@ -3,8 +3,8 @@ //------------------------------------------------------------------------------ const unsafe fn ret_i32_no_unsafe() -> i32 { 42 } -const unsafe fn ret_null_ptr_no_unsafe() -> *const T { 0 as *const T } -const unsafe fn ret_null_mut_ptr_no_unsafe() -> *mut T { 0 as *mut T } +const unsafe fn ret_null_ptr_no_unsafe() -> *const T { std::ptr::null() } +const unsafe fn ret_null_mut_ptr_no_unsafe() -> *mut T { std::ptr::null_mut() } const fn no_unsafe() { unsafe {} } const fn call_unsafe_const_fn() -> i32 { diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr index 95871749365f1..d1de5daa743ae 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr @@ -1,44 +1,48 @@ -error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) +error[E0658]: dereferencing raw pointers in constant functions is unstable --> $DIR/min_const_fn_unsafe.rs:50:77 | -LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe +LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable -error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) +error[E0658]: dereferencing raw pointers in constant functions is unstable --> $DIR/min_const_fn_unsafe.rs:53:70 | LL | const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable -error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) +error[E0658]: dereferencing raw pointers in constant functions is unstable --> $DIR/min_const_fn_unsafe.rs:56:83 | LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable -error[E0658]: unions in const fn are unstable (see issue #51909) +error[E0658]: unions in const fn are unstable --> $DIR/min_const_fn_unsafe.rs:63:5 | LL | Foo { x: () }.y | ^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51909 = help: add #![feature(const_fn_union)] to the crate attributes to enable error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block --> $DIR/min_const_fn_unsafe.rs:50:77 | -LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe +LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } | ^^^ dereference of raw pointer | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: aborting due to 5 previous errors -Some errors occurred: E0133, E0658. +Some errors have detailed explanations: E0133, E0658. For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs index 7faba480a233e..64057b012b8df 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -12,14 +12,14 @@ const unsafe fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn` +const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `const fn` #[unstable(feature = "rust1", issue="0")] const unsafe fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn` +const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `const fn` #[stable(feature = "rust1", since = "1.0.0")] // conformity is required, even with `const_fn` feature gate @@ -31,6 +31,7 @@ const unsafe fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other +const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } +//~^ ERROR can only call other `const fn` fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index 07d10984392d8..af39b99e90cc9 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -1,33 +1,37 @@ -error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563) +error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:15:41 | -LL | const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn` +LL | const unsafe fn bar() -> u32 { unsafe { foo() } } | ^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563) +error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:22:42 | -LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn` +LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn (see issue #57563) +error[E0723]: only int, `bool` and `char` operations are stable in const fn --> $DIR/min_const_unsafe_fn_libstd_stability.rs:26:33 | -LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op +LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } | ^^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563) +error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:34:48 | -LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other +LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | ^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs index bc1d5091f38d3..deb2cb6b619bb 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs @@ -12,14 +12,14 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn` +const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn` #[unstable(feature = "rust1", issue="0")] const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn` +const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue="0")] @@ -27,6 +27,6 @@ const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn` +const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn` fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr index 7cb8c6e62ec60..e4534d9ab98f6 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -1,25 +1,28 @@ -error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563) +error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn` --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:15:32 | -LL | const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn` +LL | const unsafe fn bar() -> u32 { foo() } | ^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563) +error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn` --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:22:33 | -LL | const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn` +LL | const unsafe fn bar2() -> u32 { foo2() } | ^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563) +error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn` --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:30:39 | -LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn` +LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/min_const_fn/mutable_borrow.stderr b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr index e5a3502a3dc52..ed55849124f27 100644 --- a/src/test/ui/consts/min_const_fn/mutable_borrow.stderr +++ b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr @@ -1,17 +1,19 @@ -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/mutable_borrow.rs:3:9 | -LL | let b = &mut a; //~ ERROR mutable references in const fn +LL | let b = &mut a; | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/mutable_borrow.rs:12:13 | -LL | let b = &mut a; //~ ERROR mutable references in const fn +LL | let b = &mut a; | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/min_const_fn/promotion.nll.stderr b/src/test/ui/consts/min_const_fn/promotion.nll.stderr deleted file mode 100644 index eb186ce495137..0000000000000 --- a/src/test/ui/consts/min_const_fn/promotion.nll.stderr +++ /dev/null @@ -1,68 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/promotion.rs:11:27 - | -LL | let x: &'static () = &foo1(); //~ ERROR does not live long enough - | ----------- ^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promotion.rs:12:28 - | -LL | let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough - | ------------ ^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promotion.rs:13:28 - | -LL | let z: &'static i32 = &foo3(); //~ ERROR does not live long enough - | ------------ ^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promotion.rs:14:34 - | -LL | let a: &'static Cell = &foo4(); //~ ERROR does not live long enough - | ------------------ ^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promotion.rs:15:42 - | -LL | let a: &'static Option> = &foo5(); //~ ERROR does not live long enough - | -------------------------- ^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | let a: &'static Option> = &foo6(); //~ ERROR does not live long enough -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promotion.rs:16:42 - | -LL | let a: &'static Option> = &foo6(); //~ ERROR does not live long enough - | -------------------------- ^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/min_const_fn/promotion.rs b/src/test/ui/consts/min_const_fn/promotion.rs index 969bf40a93ba7..fbe535c714b32 100644 --- a/src/test/ui/consts/min_const_fn/promotion.rs +++ b/src/test/ui/consts/min_const_fn/promotion.rs @@ -8,10 +8,10 @@ const fn foo5() -> Option> { Some(Cell::new(42)) } const fn foo6() -> Option> { None } fn main() { - let x: &'static () = &foo1(); //~ ERROR does not live long enough - let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough - let z: &'static i32 = &foo3(); //~ ERROR does not live long enough - let a: &'static Cell = &foo4(); //~ ERROR does not live long enough - let a: &'static Option> = &foo5(); //~ ERROR does not live long enough - let a: &'static Option> = &foo6(); //~ ERROR does not live long enough + let x: &'static () = &foo1(); //~ ERROR temporary value dropped while borrowed + let y: &'static i32 = &foo2(42); //~ ERROR temporary value dropped while borrowed + let z: &'static i32 = &foo3(); //~ ERROR temporary value dropped while borrowed + let a: &'static Cell = &foo4(); //~ ERROR temporary value dropped while borrowed + let a: &'static Option> = &foo5(); //~ ERROR temporary value dropped while borrowed + let a: &'static Option> = &foo6(); //~ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/min_const_fn/promotion.stderr b/src/test/ui/consts/min_const_fn/promotion.stderr index 7052f68c3ec61..550423c2d933c 100644 --- a/src/test/ui/consts/min_const_fn/promotion.stderr +++ b/src/test/ui/consts/min_const_fn/promotion.stderr @@ -1,68 +1,68 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/promotion.rs:11:27 | -LL | let x: &'static () = &foo1(); //~ ERROR does not live long enough - | ^^^^^^ temporary value does not live long enough +LL | let x: &'static () = &foo1(); + | ----------- ^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/promotion.rs:12:28 | -LL | let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough - | ^^^^^^^^ temporary value does not live long enough +LL | let y: &'static i32 = &foo2(42); + | ------------ ^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/promotion.rs:13:28 | -LL | let z: &'static i32 = &foo3(); //~ ERROR does not live long enough - | ^^^^^^ temporary value does not live long enough +LL | let z: &'static i32 = &foo3(); + | ------------ ^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/promotion.rs:14:34 | -LL | let a: &'static Cell = &foo4(); //~ ERROR does not live long enough - | ^^^^^^ temporary value does not live long enough +LL | let a: &'static Cell = &foo4(); + | ------------------ ^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` ... LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/promotion.rs:15:42 | -LL | let a: &'static Option> = &foo5(); //~ ERROR does not live long enough - | ^^^^^^ temporary value does not live long enough -LL | let a: &'static Option> = &foo6(); //~ ERROR does not live long enough +LL | let a: &'static Option> = &foo5(); + | -------------------------- ^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | let a: &'static Option> = &foo6(); LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/promotion.rs:16:42 | -LL | let a: &'static Option> = &foo6(); //~ ERROR does not live long enough - | ^^^^^^ temporary value does not live long enough +LL | let a: &'static Option> = &foo6(); + | -------------------------- ^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/miri_unleashed/assoc_const.stderr b/src/test/ui/consts/miri_unleashed/assoc_const.stderr index a40f8d46d0aa7..e814303923e18 100644 --- a/src/test/ui/consts/miri_unleashed/assoc_const.stderr +++ b/src/test/ui/consts/miri_unleashed/assoc_const.stderr @@ -1,13 +1,13 @@ warning: skipping const checks --> $DIR/assoc_const.rs:12:31 | -LL | const F: u32 = (U::X, 42).1; //~ WARN skipping const checks +LL | const F: u32 = (U::X, 42).1; | ^ error[E0080]: erroneous constant used --> $DIR/assoc_const.rs:29:13 | -LL | let y = , String>>::F; //~ ERROR erroneous constant +LL | let y = , String>>::F; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors error: aborting due to previous error diff --git a/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr b/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr index 77aab31d26ec3..dbfe1d93aa409 100644 --- a/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr +++ b/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr @@ -1,7 +1,7 @@ error[E0080]: erroneous constant used --> $DIR/assoc_const_2.rs:27:13 | -LL | let y = >::F; //~ ERROR erroneous constant +LL | let y = >::F; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors error: aborting due to previous error diff --git a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr index e23ed1c620639..c56ebf60df481 100644 --- a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr +++ b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr @@ -1,17 +1,16 @@ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:11:20 | -LL | const F: u32 = (U::X, 42).1; //~ ERROR destructors cannot be evaluated at compile-time +LL | const F: u32 = (U::X, 42).1; | ^^^^^^^^^^ constants cannot evaluate destructors -error: `>::new` is not yet stable as a const fn +error: `std::vec::Vec::::new` is not yet stable as a const fn --> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:18:25 | -LL | const X: Vec = Vec::new(); //~ ERROR not yet stable as a const fn +LL | const X: Vec = Vec::new(); | ^^^^^^^^^^ | = help: add `#![feature(const_vec_new)]` to the crate attributes to enable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.rs b/src/test/ui/consts/miri_unleashed/mutable_references.rs new file mode 100644 index 0000000000000..5f9888053a196 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/mutable_references.rs @@ -0,0 +1,35 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +#![allow(const_err)] + +use std::cell::UnsafeCell; + +// a test demonstrating what things we could allow with a smarter const qualification + +static FOO: &&mut u32 = &&mut 42; + +static BAR: &mut () = &mut (); + +struct Foo(T); + +static BOO: &mut Foo<()> = &mut Foo(()); + +struct Meh { + x: &'static UnsafeCell, +} + +unsafe impl Sync for Meh {} + +static MEH: Meh = Meh { + x: &UnsafeCell::new(42), +}; + +static OH_YES: &mut i32 = &mut 42; + +fn main() { + unsafe { + *MEH.x.get() = 99; //~ WARN skipping const checks + //~^ WARN skipping const checks + } + *OH_YES = 99; //~ ERROR cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item + //~^ WARN skipping const checks +} diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr new file mode 100644 index 0000000000000..b870aca640a0a --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr @@ -0,0 +1,26 @@ +warning: skipping const checks + --> $DIR/mutable_references.rs:30:10 + | +LL | *MEH.x.get() = 99; + | ^^^^^ + +warning: skipping const checks + --> $DIR/mutable_references.rs:30:9 + | +LL | *MEH.x.get() = 99; + | ^^^^^^^^^^^^^^^^^ + +warning: skipping const checks + --> $DIR/mutable_references.rs:33:5 + | +LL | *OH_YES = 99; + | ^^^^^^^^^^^^ + +error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item + --> $DIR/mutable_references.rs:33:5 + | +LL | *OH_YES = 99; + | ^^^^^^^^^^^^ cannot assign + +error: aborting due to previous error + diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs b/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs new file mode 100644 index 0000000000000..4fcd89a74db61 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs @@ -0,0 +1,29 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +// failure-status: 101 +// rustc-env:RUST_BACKTRACE=0 +// normalize-stderr-test "note: rustc 1.* running on .*" -> "note: rustc VERSION running on TARGET" +// normalize-stderr-test "note: compiler flags: .*" -> "note: compiler flags: FLAGS" +// normalize-stderr-test "interpret/intern.rs:[0-9]*:[0-9]*" -> "interpret/intern.rs:LL:CC" + +#![allow(const_err)] + +use std::cell::UnsafeCell; + +// this test ICEs to ensure that our mutability story is sound + +struct Meh { + x: &'static UnsafeCell, +} + +unsafe impl Sync for Meh {} + +// the following will never be ok! +const MUH: Meh = Meh { + x: &UnsafeCell::new(42), +}; + +fn main() { + unsafe { + *MUH.x.get() = 99; //~ WARN skipping const checks + } +} diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr new file mode 100644 index 0000000000000..82569e260143c --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/mutable_references_ice.stderr @@ -0,0 +1,21 @@ +warning: skipping const checks + --> $DIR/mutable_references_ice.rs:27:9 + | +LL | *MUH.x.get() = 99; + | ^^^^^^^^^^^^^^^^^ + +thread 'rustc' panicked at 'assertion failed: `(left != right)` + left: `Const`, + right: `Const`: UnsafeCells are not allowed behind references in constants. This should have been prevented statically by const qualification. If this were allowed one would be able to change a constant at one use site and other use sites may arbitrarily decide to change, too.', src/librustc_mir/interpret/intern.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. + +error: internal compiler error: unexpected panic + +note: the compiler unexpectedly panicked. this is a bug. + +note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports + +note: rustc VERSION running on TARGET + +note: compiler flags: FLAGS + diff --git a/src/test/ui/consts/packed_pattern.rs b/src/test/ui/consts/packed_pattern.rs new file mode 100644 index 0000000000000..37ae45b6df7ea --- /dev/null +++ b/src/test/ui/consts/packed_pattern.rs @@ -0,0 +1,19 @@ +// run-pass + +#[derive(PartialEq, Eq, Copy, Clone)] +#[repr(packed)] +struct Foo { + field: (i64, u32, u32, u32), +} + +const FOO: Foo = Foo { + field: (5, 6, 7, 8), +}; + +fn main() { + match FOO { + Foo { field: (5, 6, 7, 8) } => {}, + FOO => unreachable!(), + _ => unreachable!(), + } +} diff --git a/src/test/ui/consts/packed_pattern2.rs b/src/test/ui/consts/packed_pattern2.rs new file mode 100644 index 0000000000000..174161fbd9460 --- /dev/null +++ b/src/test/ui/consts/packed_pattern2.rs @@ -0,0 +1,27 @@ +// run-pass + +#[derive(PartialEq, Eq, Copy, Clone)] +#[repr(packed)] +struct Foo { + field: (u8, u16), +} + +#[derive(PartialEq, Eq, Copy, Clone)] +#[repr(align(2))] +struct Bar { + a: Foo, +} + +const FOO: Bar = Bar { + a: Foo { + field: (5, 6), + } +}; + +fn main() { + match FOO { + Bar { a: Foo { field: (5, 6) } } => {}, + FOO => unreachable!(), + _ => unreachable!(), + } +} diff --git a/src/test/ui/consts/partial_qualif.stderr b/src/test/ui/consts/partial_qualif.stderr index 967fb83b78b08..221e449b6f9a9 100644 --- a/src/test/ui/consts/partial_qualif.stderr +++ b/src/test/ui/consts/partial_qualif.stderr @@ -1,7 +1,7 @@ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead --> $DIR/partial_qualif.rs:6:5 | -LL | &{a} //~ ERROR cannot borrow a constant which may contain interior mutability +LL | &{a} | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/projection_qualif.stderr b/src/test/ui/consts/projection_qualif.stderr index 410c51c4b54e1..c270296ac8848 100644 --- a/src/test/ui/consts/projection_qualif.stderr +++ b/src/test/ui/consts/projection_qualif.stderr @@ -1,24 +1,25 @@ error[E0017]: references in constants may only refer to immutable values --> $DIR/projection_qualif.rs:6:27 | -LL | let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values +LL | let b: *mut u32 = &mut a; | ^^^^^^ constants require immutable values error[E0019]: constant contains unimplemented expression type --> $DIR/projection_qualif.rs:7:18 | -LL | unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants +LL | unsafe { *b = 5; } | ^^^^^^ -error[E0658]: dereferencing raw pointers in constants is unstable (see issue #51911) +error[E0658]: dereferencing raw pointers in constants is unstable --> $DIR/projection_qualif.rs:7:18 | -LL | unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants +LL | unsafe { *b = 5; } | ^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error: aborting due to 3 previous errors -Some errors occurred: E0017, E0019, E0658. +Some errors have detailed explanations: E0017, E0019, E0658. For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/consts/promote_const_let.nll.stderr b/src/test/ui/consts/promote_const_let.nll.stderr deleted file mode 100644 index e6ee1523a3b28..0000000000000 --- a/src/test/ui/consts/promote_const_let.nll.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0597]: `y` does not live long enough - --> $DIR/promote_const_let.rs:4:9 - | -LL | let x: &'static u32 = { - | ------------ type annotation requires that `y` is borrowed for `'static` -LL | let y = 42; -LL | &y //~ ERROR does not live long enough - | ^^ borrowed value does not live long enough -LL | }; - | - `y` dropped here while still borrowed - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote_const_let.rs:6:28 - | -LL | let x: &'static u32 = &{ //~ ERROR does not live long enough - | ____________------------____^ - | | | - | | type annotation requires that borrow lasts for `'static` -LL | | let y = 42; -LL | | y -LL | | }; - | |_____^ creates a temporary which is freed while still in use -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to 2 previous errors - -Some errors occurred: E0597, E0716. -For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/consts/promote_const_let.rs b/src/test/ui/consts/promote_const_let.rs index a8a6d4d99c6ff..51a0fec2e7bfe 100644 --- a/src/test/ui/consts/promote_const_let.rs +++ b/src/test/ui/consts/promote_const_let.rs @@ -3,7 +3,7 @@ fn main() { let y = 42; &y //~ ERROR does not live long enough }; - let x: &'static u32 = &{ //~ ERROR does not live long enough + let x: &'static u32 = &{ //~ ERROR temporary value dropped while borrowed let y = 42; y }; diff --git a/src/test/ui/consts/promote_const_let.stderr b/src/test/ui/consts/promote_const_let.stderr index d37bd49186032..c47d297c90409 100644 --- a/src/test/ui/consts/promote_const_let.stderr +++ b/src/test/ui/consts/promote_const_let.stderr @@ -1,27 +1,29 @@ error[E0597]: `y` does not live long enough - --> $DIR/promote_const_let.rs:4:10 + --> $DIR/promote_const_let.rs:4:9 | -LL | &y //~ ERROR does not live long enough - | ^ borrowed value does not live long enough +LL | let x: &'static u32 = { + | ------------ type annotation requires that `y` is borrowed for `'static` +LL | let y = 42; +LL | &y + | ^^ borrowed value does not live long enough LL | }; - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - `y` dropped here while still borrowed -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/promote_const_let.rs:6:28 | -LL | let x: &'static u32 = &{ //~ ERROR does not live long enough - | ____________________________^ +LL | let x: &'static u32 = &{ + | ____________------------____^ + | | | + | | type annotation requires that borrow lasts for `'static` LL | | let y = 42; LL | | y LL | | }; - | |_____^ temporary value does not live long enough + | |_____^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors have detailed explanations: E0597, E0716. +For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/consts/promote_evaluation_unused_result.rs b/src/test/ui/consts/promote_evaluation_unused_result.rs index d199e34775e4b..dc21b9fe8cd1b 100644 --- a/src/test/ui/consts/promote_evaluation_unused_result.rs +++ b/src/test/ui/consts/promote_evaluation_unused_result.rs @@ -1,7 +1,5 @@ //compile-pass -#![feature(nll)] - fn main() { let _: &'static usize = &(loop {}, 1).1; diff --git a/src/test/ui/consts/promote_fn_calls.rs b/src/test/ui/consts/promote_fn_calls.rs index 045322de34708..6b6eea36361bf 100644 --- a/src/test/ui/consts/promote_fn_calls.rs +++ b/src/test/ui/consts/promote_fn_calls.rs @@ -1,8 +1,6 @@ // compile-pass // aux-build:promotable_const_fn_lib.rs -#![feature(nll)] - extern crate promotable_const_fn_lib; use promotable_const_fn_lib::{foo, Foo}; diff --git a/src/test/ui/consts/promote_fn_calls_std.rs b/src/test/ui/consts/promote_fn_calls_std.rs index 0350708d673d7..d982f350208e2 100644 --- a/src/test/ui/consts/promote_fn_calls_std.rs +++ b/src/test/ui/consts/promote_fn_calls_std.rs @@ -1,7 +1,5 @@ // compile-pass -#![feature(nll)] - fn main() { let x: &'static u8 = &u8::max_value(); let x: &'static u16 = &u16::max_value(); diff --git a/src/test/ui/consts/qualif_overwrite.stderr b/src/test/ui/consts/qualif_overwrite.stderr index 30479139e314c..fbaae711d7c06 100644 --- a/src/test/ui/consts/qualif_overwrite.stderr +++ b/src/test/ui/consts/qualif_overwrite.stderr @@ -1,7 +1,7 @@ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead --> $DIR/qualif_overwrite.rs:10:5 | -LL | &{a} //~ ERROR cannot borrow a constant which may contain interior mutability +LL | &{a} | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/qualif_overwrite_2.stderr b/src/test/ui/consts/qualif_overwrite_2.stderr index 8276db99a12c0..a393c4e336d64 100644 --- a/src/test/ui/consts/qualif_overwrite_2.stderr +++ b/src/test/ui/consts/qualif_overwrite_2.stderr @@ -1,7 +1,7 @@ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead --> $DIR/qualif_overwrite_2.rs:8:5 | -LL | &{a.0} //~ ERROR cannot borrow a constant which may contain interior mutability +LL | &{a.0} | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/single_variant_match_ice.rs b/src/test/ui/consts/single_variant_match_ice.rs index 79dde3c18e8fa..75793c904838d 100644 --- a/src/test/ui/consts/single_variant_match_ice.rs +++ b/src/test/ui/consts/single_variant_match_ice.rs @@ -2,12 +2,12 @@ enum Foo { Prob, } -const FOO: u32 = match Foo::Prob { - Foo::Prob => 42, //~ ERROR unimplemented expression type +const FOO: u32 = match Foo::Prob { //~ ERROR unimplemented expression type + Foo::Prob => 42, }; -const BAR: u32 = match Foo::Prob { - x => 42, //~ ERROR unimplemented expression type +const BAR: u32 = match Foo::Prob { //~ ERROR unimplemented expression type + x => 42, }; impl Foo { @@ -15,7 +15,8 @@ impl Foo { use self::Foo::*; match *self { - Prob => 0x1, //~ ERROR `if`, `match`, `&&` and `||` are not stable in const fn + //~^ ERROR loops and conditional expressions are not stable in const fn + Prob => 0x1, } } } diff --git a/src/test/ui/consts/single_variant_match_ice.stderr b/src/test/ui/consts/single_variant_match_ice.stderr index 5272062ccfc14..851733726ac0f 100644 --- a/src/test/ui/consts/single_variant_match_ice.stderr +++ b/src/test/ui/consts/single_variant_match_ice.stderr @@ -1,24 +1,25 @@ error[E0019]: constant contains unimplemented expression type - --> $DIR/single_variant_match_ice.rs:6:5 + --> $DIR/single_variant_match_ice.rs:5:24 | -LL | Foo::Prob => 42, //~ ERROR unimplemented expression type - | ^^^^^^^^^ +LL | const FOO: u32 = match Foo::Prob { + | ^^^^^^^^^ error[E0019]: constant contains unimplemented expression type - --> $DIR/single_variant_match_ice.rs:10:5 + --> $DIR/single_variant_match_ice.rs:9:24 | -LL | x => 42, //~ ERROR unimplemented expression type - | ^ +LL | const BAR: u32 = match Foo::Prob { + | ^^^^^^^^^ -error[E0723]: `if`, `match`, `&&` and `||` are not stable in const fn (see issue #57563) - --> $DIR/single_variant_match_ice.rs:18:13 +error[E0723]: loops and conditional expressions are not stable in const fn + --> $DIR/single_variant_match_ice.rs:17:15 | -LL | Prob => 0x1, //~ ERROR `if`, `match`, `&&` and `||` are not stable in const fn - | ^^^^ +LL | match *self { + | ^^^^^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to 3 previous errors -Some errors occurred: E0019, E0723. +Some errors have detailed explanations: E0019, E0723. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/static-cycle-error.rs b/src/test/ui/consts/static-cycle-error.rs new file mode 100644 index 0000000000000..8e69d3eda6d2e --- /dev/null +++ b/src/test/ui/consts/static-cycle-error.rs @@ -0,0 +1,11 @@ +// compile-pass + +struct Foo { + foo: Option<&'static Foo> +} + +static FOO: Foo = Foo { + foo: Some(&FOO), +}; + +fn main() {} diff --git a/src/test/ui/consts/static-raw-pointer-interning.rs b/src/test/ui/consts/static-raw-pointer-interning.rs new file mode 100644 index 0000000000000..cab60c91e165c --- /dev/null +++ b/src/test/ui/consts/static-raw-pointer-interning.rs @@ -0,0 +1,15 @@ +// run-pass + +static FOO: Foo = Foo { + field: &42 as *const i32, +}; + +struct Foo { + field: *const i32, +} + +unsafe impl Sync for Foo {} + +fn main() { + assert_eq!(unsafe { *FOO.field }, 42); +} diff --git a/src/test/ui/consts/static-raw-pointer-interning2.rs b/src/test/ui/consts/static-raw-pointer-interning2.rs new file mode 100644 index 0000000000000..2b915fd7cb329 --- /dev/null +++ b/src/test/ui/consts/static-raw-pointer-interning2.rs @@ -0,0 +1,15 @@ +// run-pass + +static mut FOO: Foo = Foo { + field: &mut [42] as *mut [i32] as *mut i32, +}; + +struct Foo { + field: *mut i32, +} + +unsafe impl Sync for Foo {} + +fn main() { + assert_eq!(unsafe { *FOO.field = 69; *FOO.field }, 69); +} diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stderr index 72186571d697e..ca691b07be063 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stderr @@ -12,5 +12,5 @@ LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 4 error: aborting due to 2 previous errors -Some errors occurred: E0017, E0019. +Some errors have detailed explanations: E0017, E0019. For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/consts/std/alloc.rs b/src/test/ui/consts/std/alloc.rs new file mode 100644 index 0000000000000..65ac7e44926d0 --- /dev/null +++ b/src/test/ui/consts/std/alloc.rs @@ -0,0 +1,10 @@ +use std::alloc::Layout; + +// ok +const LAYOUT_VALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x08) }; + +// not ok, since alignment needs to be non-zero. +const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; +//~^ ERROR it is undefined behavior to use this value + +fn main() {} diff --git a/src/test/ui/consts/std/alloc.stderr b/src/test/ui/consts/std/alloc.stderr new file mode 100644 index 0000000000000..74a8f3daf6aaa --- /dev/null +++ b/src/test/ui/consts/std/alloc.stderr @@ -0,0 +1,11 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/alloc.rs:7:1 + | +LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0 at .align_, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/underscore_const_names.rs b/src/test/ui/consts/underscore_const_names.rs similarity index 88% rename from src/test/ui/underscore_const_names.rs rename to src/test/ui/consts/underscore_const_names.rs index 1db022e886208..8d57e5074f1b1 100644 --- a/src/test/ui/underscore_const_names.rs +++ b/src/test/ui/consts/underscore_const_names.rs @@ -1,9 +1,9 @@ // compile-pass -#![feature(underscore_const_names)] +#![deny(unused)] trait Trt {} -struct Str {} +pub struct Str {} impl Trt for Str {} macro_rules! check_impl { @@ -17,7 +17,6 @@ macro_rules! check_impl { } } -#[deny(unused)] const _ : () = (); const _ : i32 = 42; diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.rs b/src/test/ui/consts/uninhabited-const-issue-61744.rs new file mode 100644 index 0000000000000..21fbbf8cfb5a8 --- /dev/null +++ b/src/test/ui/consts/uninhabited-const-issue-61744.rs @@ -0,0 +1,19 @@ +// compile-fail + +pub const unsafe fn fake_type() -> T { + hint_unreachable() +} + +pub const unsafe fn hint_unreachable() -> ! { + fake_type() //~ ERROR any use of this value will cause an error +} + +trait Const { + const CONSTANT: i32 = unsafe { fake_type() }; +} + +impl Const for T {} + +pub fn main() -> () { + dbg!(i32::CONSTANT); //~ ERROR erroneous constant used +} diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.stderr b/src/test/ui/consts/uninhabited-const-issue-61744.stderr new file mode 100644 index 0000000000000..5c2855437118f --- /dev/null +++ b/src/test/ui/consts/uninhabited-const-issue-61744.stderr @@ -0,0 +1,24 @@ +error: any use of this value will cause an error + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ + | | + | tried to call a function with return type T passing return place of type ! + | inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside call to `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:12:36 +... +LL | const CONSTANT: i32 = unsafe { fake_type() }; + | --------------------------------------------- + | + = note: #[deny(const_err)] on by default + +error[E0080]: erroneous constant used + --> $DIR/uninhabited-const-issue-61744.rs:18:10 + | +LL | dbg!(i32::CONSTANT); + | ^^^^^^^^^^^^^ referenced constant has errors + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/union_constant.rs b/src/test/ui/consts/union_constant.rs new file mode 100644 index 0000000000000..16b05310b9fcb --- /dev/null +++ b/src/test/ui/consts/union_constant.rs @@ -0,0 +1,11 @@ +// compile-pass + +union Uninit { + _never_use: *const u8, + uninit: (), +} + +const UNINIT: Uninit = Uninit { uninit: () }; +const UNINIT2: (Uninit,) = (Uninit { uninit: () }, ); + +fn main() {} diff --git a/src/test/ui/consts/validate_never_arrays.stderr b/src/test/ui/consts/validate_never_arrays.stderr index b9d181a76dd9b..7a7d816873350 100644 --- a/src/test/ui/consts/validate_never_arrays.stderr +++ b/src/test/ui/consts/validate_never_arrays.stderr @@ -1,7 +1,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:3:1 | -LL | const FOO: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior +LL | const FOO: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at . | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/continue-after-missing-main.nll.stderr b/src/test/ui/continue-after-missing-main.nll.stderr new file mode 100644 index 0000000000000..aceabf3316479 --- /dev/null +++ b/src/test/ui/continue-after-missing-main.nll.stderr @@ -0,0 +1,7 @@ +error[E0601]: `main` function not found in crate `continue_after_missing_main` + | + = note: consider adding a `main` function to `$DIR/continue-after-missing-main.rs` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/continue-after-missing-main.rs b/src/test/ui/continue-after-missing-main.rs new file mode 100644 index 0000000000000..7455c2a431d62 --- /dev/null +++ b/src/test/ui/continue-after-missing-main.rs @@ -0,0 +1,32 @@ +#![allow(dead_code)] + +// error-pattern:`main` function not found in crate + +struct Tableau<'a, MP> { + provider: &'a MP, +} + +impl<'adapted_matrix_provider, 'original_data, MP> + Tableau<'adapted_matrix_provider, AdaptedMatrixProvider<'original_data, MP>> +{ + fn provider(&self) -> &'adapted_matrix_provider AdaptedMatrixProvider { + self.provider + } +} + +struct AdaptedMatrixProvider<'a, T> { + original_problem: &'a T, +} + +impl<'a, T> AdaptedMatrixProvider<'a, T> { + fn clone_with_extra_bound(&self) -> Self { + AdaptedMatrixProvider { original_problem: self.original_problem } + } +} + +fn create_and_solve_subproblems<'data_provider, 'original_data, MP>( + tableau: Tableau<'data_provider, AdaptedMatrixProvider<'original_data, MP>>, +) { + let _: AdaptedMatrixProvider<'original_data, MP> = tableau.provider().clone_with_extra_bound(); + //~^ ERROR lifetime mismatch +} diff --git a/src/test/ui/continue-after-missing-main.stderr b/src/test/ui/continue-after-missing-main.stderr new file mode 100644 index 0000000000000..cc5f87659079e --- /dev/null +++ b/src/test/ui/continue-after-missing-main.stderr @@ -0,0 +1,16 @@ +error[E0601]: `main` function not found in crate `continue_after_missing_main` + | + = note: consider adding a `main` function to `$DIR/continue-after-missing-main.rs` + +error[E0623]: lifetime mismatch + --> $DIR/continue-after-missing-main.rs:30:56 + | +LL | tableau: Tableau<'data_provider, AdaptedMatrixProvider<'original_data, MP>>, + | ------------------------------------------------------------------ these two types are declared with different lifetimes... +LL | ) { +LL | let _: AdaptedMatrixProvider<'original_data, MP> = tableau.provider().clone_with_extra_bound(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...but data from `tableau` flows into `tableau` here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/conversion-methods.stderr b/src/test/ui/conversion-methods.stderr index 33fff4a0f68ed..b9662e7607494 100644 --- a/src/test/ui/conversion-methods.stderr +++ b/src/test/ui/conversion-methods.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/conversion-methods.rs:5:41 | -LL | let _tis_an_instants_play: String = "'Tis a fond Ambush—"; //~ ERROR mismatched types +LL | let _tis_an_instants_play: String = "'Tis a fond Ambush—"; | ^^^^^^^^^^^^^^^^^^^^^ | | | expected struct `std::string::String`, found reference @@ -37,7 +37,7 @@ LL | let _but_should_the_play: String = 2; // Perhaps surprisingly, we sugge error[E0308]: mismatched types --> $DIR/conversion-methods.rs:12:47 | -LL | let _prove_piercing_earnest: Vec = &[1, 2, 3]; //~ ERROR mismatched types +LL | let _prove_piercing_earnest: Vec = &[1, 2, 3]; | ^^^^^^^^^^ | | | expected struct `std::vec::Vec`, found reference diff --git a/src/test/ui/cross/cross-borrow-trait.rs b/src/test/ui/cross/cross-borrow-trait.rs index d8d7537f24a61..274cdad75ec2a 100644 --- a/src/test/ui/cross/cross-borrow-trait.rs +++ b/src/test/ui/cross/cross-borrow-trait.rs @@ -6,8 +6,8 @@ trait Trait { fn foo(&self) {} } impl Trait for Foo {} pub fn main() { - let x: Box = Box::new(Foo); - let _y: &Trait = x; //~ ERROR E0308 - //~| expected type `&dyn Trait` - //~| found type `std::boxed::Box` + let x: Box = Box::new(Foo); + let _y: &dyn Trait = x; //~ ERROR E0308 + //~| expected type `&dyn Trait` + //~| found type `std::boxed::Box` } diff --git a/src/test/ui/cross/cross-borrow-trait.stderr b/src/test/ui/cross/cross-borrow-trait.stderr index 949b63ffbde6f..ada1c0204eb01 100644 --- a/src/test/ui/cross/cross-borrow-trait.stderr +++ b/src/test/ui/cross/cross-borrow-trait.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types - --> $DIR/cross-borrow-trait.rs:10:22 + --> $DIR/cross-borrow-trait.rs:10:26 | -LL | let _y: &Trait = x; //~ ERROR E0308 - | ^ - | | - | expected &dyn Trait, found struct `std::boxed::Box` - | help: consider borrowing here: `&x` +LL | let _y: &dyn Trait = x; + | ^ + | | + | expected &dyn Trait, found struct `std::boxed::Box` + | help: consider borrowing here: `&x` | = note: expected type `&dyn Trait` found type `std::boxed::Box` diff --git a/src/test/ui/cross/cross-fn-cache-hole.stderr b/src/test/ui/cross/cross-fn-cache-hole.stderr index 2cd57e363d0de..3bedd0dac23b4 100644 --- a/src/test/ui/cross/cross-fn-cache-hole.stderr +++ b/src/test/ui/cross/cross-fn-cache-hole.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `i32: Bar` is not satisfied --> $DIR/cross-fn-cache-hole.rs:15:1 | -LL | / fn vacuous() //~ ERROR the trait bound `i32: Bar` is not satisfied +LL | / fn vacuous() LL | | where i32: Foo LL | | { LL | | // ... the original intention was to check that we don't use that diff --git a/src/test/ui/custom-attribute-multisegment.rs b/src/test/ui/custom-attribute-multisegment.rs index 95cefe53938fb..2434921390245 100644 --- a/src/test/ui/custom-attribute-multisegment.rs +++ b/src/test/ui/custom-attribute-multisegment.rs @@ -1,7 +1,5 @@ // Unresolved multi-segment attributes are not treated as custom. -#![feature(custom_attribute)] - mod existent {} #[existent::nonexistent] //~ ERROR failed to resolve: could not find `nonexistent` in `existent` diff --git a/src/test/ui/custom-attribute-multisegment.stderr b/src/test/ui/custom-attribute-multisegment.stderr index 6f6a87dd1594d..57eca211ed10e 100644 --- a/src/test/ui/custom-attribute-multisegment.stderr +++ b/src/test/ui/custom-attribute-multisegment.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: could not find `nonexistent` in `existent` - --> $DIR/custom-attribute-multisegment.rs:7:13 + --> $DIR/custom-attribute-multisegment.rs:5:13 | -LL | #[existent::nonexistent] //~ ERROR failed to resolve: could not find `nonexistent` in `existent` +LL | #[existent::nonexistent] | ^^^^^^^^^^^ could not find `nonexistent` in `existent` error: aborting due to previous error diff --git a/src/test/ui/custom-derive/auxiliary/plugin.rs b/src/test/ui/custom-derive/auxiliary/plugin.rs deleted file mode 100644 index 5e500de607c1a..0000000000000 --- a/src/test/ui/custom-derive/auxiliary/plugin.rs +++ /dev/null @@ -1,28 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::TokenStream; - -#[proc_macro_derive(Foo)] -pub fn derive_foo(input: TokenStream) -> TokenStream { - input -} - -#[proc_macro_derive(Bar)] -pub fn derive_bar(input: TokenStream) -> TokenStream { - panic!("lolnope"); -} - -#[proc_macro_derive(WithHelper, attributes(helper))] -pub fn with_helper(input: TokenStream) -> TokenStream { - TokenStream::new() -} - -#[proc_macro_attribute] -pub fn helper(_: TokenStream, input: TokenStream) -> TokenStream { - input -} diff --git a/src/test/ui/custom-derive/derive-in-mod.rs b/src/test/ui/custom-derive/derive-in-mod.rs deleted file mode 100644 index 8478ff1a6ae6c..0000000000000 --- a/src/test/ui/custom-derive/derive-in-mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -// compile-pass -// aux-build:plugin.rs - -extern crate plugin; - -mod inner { - use plugin::WithHelper; - - #[derive(WithHelper)] - struct S; -} - -fn main() {} diff --git a/src/test/ui/custom-derive/helper-attr-blocked-by-import-ambig.rs b/src/test/ui/custom-derive/helper-attr-blocked-by-import-ambig.rs deleted file mode 100644 index ba072ba3568b7..0000000000000 --- a/src/test/ui/custom-derive/helper-attr-blocked-by-import-ambig.rs +++ /dev/null @@ -1,12 +0,0 @@ -// aux-build:plugin.rs - -#[macro_use(WithHelper)] -extern crate plugin; - -use plugin::helper; - -#[derive(WithHelper)] -#[helper] //~ ERROR `helper` is ambiguous -struct S; - -fn main() {} diff --git a/src/test/ui/custom-derive/helper-attr-blocked-by-import-ambig.stderr b/src/test/ui/custom-derive/helper-attr-blocked-by-import-ambig.stderr deleted file mode 100644 index 2c9d226cc9ef7..0000000000000 --- a/src/test/ui/custom-derive/helper-attr-blocked-by-import-ambig.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0659]: `helper` is ambiguous (derive helper attribute vs any other name) - --> $DIR/helper-attr-blocked-by-import-ambig.rs:9:3 - | -LL | #[helper] //~ ERROR `helper` is ambiguous - | ^^^^^^ ambiguous name - | -note: `helper` could refer to the derive helper attribute defined here - --> $DIR/helper-attr-blocked-by-import-ambig.rs:8:10 - | -LL | #[derive(WithHelper)] - | ^^^^^^^^^^ -note: `helper` could also refer to the attribute macro imported here - --> $DIR/helper-attr-blocked-by-import-ambig.rs:6:5 - | -LL | use plugin::helper; - | ^^^^^^^^^^^^^^ - = help: use `crate::helper` to refer to this attribute macro unambiguously - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0659`. diff --git a/src/test/ui/custom-derive/helper-attr-blocked-by-import.rs b/src/test/ui/custom-derive/helper-attr-blocked-by-import.rs deleted file mode 100644 index abbf014f55337..0000000000000 --- a/src/test/ui/custom-derive/helper-attr-blocked-by-import.rs +++ /dev/null @@ -1,28 +0,0 @@ -// compile-pass -// aux-build:plugin.rs - -#[macro_use(WithHelper)] -extern crate plugin; - -use self::one::*; -use self::two::*; - -mod helper {} - -mod one { - use helper; - - #[derive(WithHelper)] - #[helper] - struct One; -} - -mod two { - use helper; - - #[derive(WithHelper)] - #[helper] - struct Two; -} - -fn main() {} diff --git a/src/test/ui/custom-derive/issue-36935.rs b/src/test/ui/custom-derive/issue-36935.rs deleted file mode 100644 index 7a5d19f771f3c..0000000000000 --- a/src/test/ui/custom-derive/issue-36935.rs +++ /dev/null @@ -1,12 +0,0 @@ -// aux-build:plugin.rs - - -#[macro_use] extern crate plugin; - -#[derive(Foo, Bar)] //~ ERROR proc-macro derive panicked -struct Baz { - a: i32, - b: i32, -} - -fn main() {} diff --git a/src/test/ui/custom-derive/issue-36935.stderr b/src/test/ui/custom-derive/issue-36935.stderr deleted file mode 100644 index d4c91546329ad..0000000000000 --- a/src/test/ui/custom-derive/issue-36935.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: proc-macro derive panicked - --> $DIR/issue-36935.rs:6:15 - | -LL | #[derive(Foo, Bar)] //~ ERROR proc-macro derive panicked - | ^^^ - | - = help: message: lolnope - -error: aborting due to previous error - diff --git a/src/test/ui/custom-test-frameworks-simple.rs b/src/test/ui/custom-test-frameworks-simple.rs index a8aac6ec1427a..aee0040ef4de4 100644 --- a/src/test/ui/custom-test-frameworks-simple.rs +++ b/src/test/ui/custom-test-frameworks-simple.rs @@ -5,7 +5,7 @@ #![test_runner(crate::foo_runner)] #[cfg(test)] -fn foo_runner(ts: &[&Fn(usize)->()]) { +fn foo_runner(ts: &[&dyn Fn(usize)->()]) { for (i, t) in ts.iter().enumerate() { t(i); } diff --git a/src/test/ui/custom_attribute.stderr b/src/test/ui/custom_attribute.stderr index 1100d82f8406d..adb05e3fb2a1c 100644 --- a/src/test/ui/custom_attribute.stderr +++ b/src/test/ui/custom_attribute.stderr @@ -1,25 +1,28 @@ -error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/custom_attribute.rs:3:3 | -LL | #[foo] //~ ERROR The attribute `foo` +LL | #[foo] | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/custom_attribute.rs:5:7 | -LL | #[foo] //~ ERROR The attribute `foo` +LL | #[foo] | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/custom_attribute.rs:7:7 | -LL | #[foo] //~ ERROR The attribute `foo` +LL | #[foo] | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/cycle-projection-based-on-where-clause.rs b/src/test/ui/cycle-projection-based-on-where-clause.rs index 336b67852cd01..d3609acfdff63 100644 --- a/src/test/ui/cycle-projection-based-on-where-clause.rs +++ b/src/test/ui/cycle-projection-based-on-where-clause.rs @@ -16,7 +16,6 @@ struct A where T : Trait, T : Add //~^ ERROR cycle detected - //~| ERROR associated type `Item` not found for `T` { data: T } diff --git a/src/test/ui/cycle-projection-based-on-where-clause.stderr b/src/test/ui/cycle-projection-based-on-where-clause.stderr index b11a8bda9b4f4..59815138e2e36 100644 --- a/src/test/ui/cycle-projection-based-on-where-clause.stderr +++ b/src/test/ui/cycle-projection-based-on-where-clause.stderr @@ -11,13 +11,6 @@ note: cycle used when processing `A` LL | T : Add | ^^^^^^^ -error[E0220]: associated type `Item` not found for `T` - --> $DIR/cycle-projection-based-on-where-clause.rs:17:19 - | -LL | T : Add - | ^^^^^^^ associated type `Item` not found - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0220, E0391. -For more information about an error, try `rustc --explain E0220`. +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs index d658753eb242b..6175b7df1107a 100644 --- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs +++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs @@ -1,7 +1,7 @@ // Test a cycle where a type parameter on a trait has a default that // again references the trait. -trait Foo> { +trait Foo> { //~^ ERROR cycle detected } diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr index aa45462a52e41..e89d25742a0ac 100644 --- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr @@ -1,15 +1,15 @@ error[E0391]: cycle detected when processing `Foo::X` - --> $DIR/cycle-trait-default-type-trait.rs:4:19 + --> $DIR/cycle-trait-default-type-trait.rs:4:23 | -LL | trait Foo> { - | ^^^ +LL | trait Foo> { + | ^^^ | = note: ...which again requires processing `Foo::X`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-default-type-trait.rs:4:1 | -LL | trait Foo> { - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait Foo> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/dead-code-impl.rs b/src/test/ui/dead-code-impl.rs new file mode 100644 index 0000000000000..84829c98e5739 --- /dev/null +++ b/src/test/ui/dead-code-impl.rs @@ -0,0 +1,17 @@ +// run-pass + +#![deny(dead_code)] + +pub struct GenericFoo(T); + +type Foo = GenericFoo; + +impl Foo { + fn bar(self) -> u8 { + 0 + } +} + +fn main() { + println!("{}", GenericFoo(0).bar()); +} diff --git a/src/test/ui/defaulted-never-note.rs b/src/test/ui/defaulted-never-note.rs index acda4b42f15ee..cf1922ecc789f 100644 --- a/src/test/ui/defaulted-never-note.rs +++ b/src/test/ui/defaulted-never-note.rs @@ -32,4 +32,3 @@ fn smeg() { fn main() { smeg(); } - diff --git a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs index f3df57e6ff911..bcf7e3e6608ea 100644 --- a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs +++ b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs @@ -25,7 +25,7 @@ mod x { mod y { use Foo; - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn use_char_assoc() { // Careful here: in the representation, ::T gets // normalized away, so at a certain point we had no edge to diff --git a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr index a25a1786e813b..a603d71596ba6 100644 --- a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr +++ b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr @@ -1,8 +1,8 @@ error: OK --> $DIR/dep-graph-assoc-type-codegen.rs:28:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/dep-graph/dep-graph-caller-callee.rs b/src/test/ui/dep-graph/dep-graph-caller-callee.rs index f8276ea3ad638..18b4252a06b84 100644 --- a/src/test/ui/dep-graph/dep-graph-caller-callee.rs +++ b/src/test/ui/dep-graph/dep-graph-caller-callee.rs @@ -17,7 +17,7 @@ mod y { use x; // These dependencies SHOULD exist: - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn y() { x::x(); } @@ -28,7 +28,7 @@ mod z { // These are expected to yield errors, because changes to `x` // affect the BODY of `y`, but not its signature. - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path pub fn z() { y::y(); } diff --git a/src/test/ui/dep-graph/dep-graph-caller-callee.stderr b/src/test/ui/dep-graph/dep-graph-caller-callee.stderr index d7bf63822579f..de041e600672d 100644 --- a/src/test/ui/dep-graph/dep-graph-caller-callee.stderr +++ b/src/test/ui/dep-graph/dep-graph-caller-callee.stderr @@ -1,14 +1,14 @@ error: OK --> $DIR/dep-graph-caller-callee.rs:20:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `x::x` to `TypeckTables` +error: no path from `x::x` to `typeck_tables_of` --> $DIR/dep-graph-caller-callee.rs:31:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-struct-signature.rs b/src/test/ui/dep-graph/dep-graph-struct-signature.rs index 3d660aa8f4b32..8b78d39ecae33 100644 --- a/src/test/ui/dep-graph/dep-graph-struct-signature.rs +++ b/src/test/ui/dep-graph/dep-graph-struct-signature.rs @@ -24,63 +24,63 @@ struct WontChange { mod signatures { use WillChange; - #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path - #[rustc_then_this_would_need(AssociatedItems)] //~ ERROR no path - #[rustc_then_this_would_need(TraitDefOfItem)] //~ ERROR no path + #[rustc_then_this_would_need(type_of)] //~ ERROR no path + #[rustc_then_this_would_need(associated_item)] //~ ERROR no path + #[rustc_then_this_would_need(trait_def)] //~ ERROR no path trait Bar { - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK fn do_something(x: WillChange); } - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK fn some_fn(x: WillChange) { } - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK fn new_foo(x: u32, y: u32) -> WillChange { WillChange { x: x, y: y } } - #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK + #[rustc_then_this_would_need(type_of)] //~ ERROR OK impl WillChange { - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK fn new(x: u32, y: u32) -> WillChange { loop { } } } - #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK + #[rustc_then_this_would_need(type_of)] //~ ERROR OK impl WillChange { - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK fn method(&self, x: u32) { } } struct WillChanges { - #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK + #[rustc_then_this_would_need(type_of)] //~ ERROR OK x: WillChange, - #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK + #[rustc_then_this_would_need(type_of)] //~ ERROR OK y: WillChange } // The fields change, not the type itself. - #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path + #[rustc_then_this_would_need(type_of)] //~ ERROR no path fn indirect(x: WillChanges) { } } mod invalid_signatures { use WontChange; - #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path + #[rustc_then_this_would_need(type_of)] //~ ERROR no path trait A { - #[rustc_then_this_would_need(FnSignature)] //~ ERROR no path + #[rustc_then_this_would_need(fn_sig)] //~ ERROR no path fn do_something_else_twice(x: WontChange); } - #[rustc_then_this_would_need(FnSignature)] //~ ERROR no path + #[rustc_then_this_would_need(fn_sig)] //~ ERROR no path fn b(x: WontChange) { } - #[rustc_then_this_would_need(FnSignature)] //~ ERROR no path from `WillChange` - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path from `WillChange` + #[rustc_then_this_would_need(fn_sig)] //~ ERROR no path from `WillChange` + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path from `WillChange` fn c(x: u32) { } } diff --git a/src/test/ui/dep-graph/dep-graph-struct-signature.stderr b/src/test/ui/dep-graph/dep-graph-struct-signature.stderr index d7d56f219b42e..2e00e5a2cbd2f 100644 --- a/src/test/ui/dep-graph/dep-graph-struct-signature.stderr +++ b/src/test/ui/dep-graph/dep-graph-struct-signature.stderr @@ -1,134 +1,134 @@ -error: no path from `WillChange` to `TypeOfItem` +error: no path from `WillChange` to `type_of` --> $DIR/dep-graph-struct-signature.rs:27:5 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `AssociatedItems` +error: no path from `WillChange` to `associated_item` --> $DIR/dep-graph-struct-signature.rs:28:5 | -LL | #[rustc_then_this_would_need(AssociatedItems)] //~ ERROR no path +LL | #[rustc_then_this_would_need(associated_item)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `TraitDefOfItem` +error: no path from `WillChange` to `trait_def` --> $DIR/dep-graph-struct-signature.rs:29:5 | -LL | #[rustc_then_this_would_need(TraitDefOfItem)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(trait_def)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:35:5 | -LL | #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:36:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:39:5 | -LL | #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:40:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:45:5 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:52:5 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:60:9 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:62:9 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `TypeOfItem` +error: no path from `WillChange` to `type_of` --> $DIR/dep-graph-struct-signature.rs:67:5 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `TypeOfItem` +error: no path from `WillChange` to `type_of` --> $DIR/dep-graph-struct-signature.rs:74:5 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `FnSignature` +error: no path from `WillChange` to `fn_sig` --> $DIR/dep-graph-struct-signature.rs:80:5 | -LL | #[rustc_then_this_would_need(FnSignature)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `FnSignature` +error: no path from `WillChange` to `fn_sig` --> $DIR/dep-graph-struct-signature.rs:83:5 | -LL | #[rustc_then_this_would_need(FnSignature)] //~ ERROR no path from `WillChange` - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `TypeckTables` +error: no path from `WillChange` to `typeck_tables_of` --> $DIR/dep-graph-struct-signature.rs:84:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path from `WillChange` - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:31:9 | -LL | #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `FnSignature` +error: no path from `WillChange` to `fn_sig` --> $DIR/dep-graph-struct-signature.rs:76:9 | -LL | #[rustc_then_this_would_need(FnSignature)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:47:9 | -LL | #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:48:9 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:54:9 | -LL | #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:55:9 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 22 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs index 16e5a705d25e3..38622a754ddb2 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs @@ -29,7 +29,7 @@ mod x { mod y { use {Foo, Bar}; - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn with_char() { char::method('a'); } @@ -38,7 +38,7 @@ mod y { mod z { use y; - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path pub fn z() { y::with_char(); } diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr index 2fa1e1edc8722..3384fd7b4acf5 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr @@ -1,14 +1,14 @@ error: OK --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:32:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `x::` to `TypeckTables` +error: no path from `x::` to `typeck_tables_of` --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:41:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs index 064302c9c805f..82306b6539c15 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs @@ -28,7 +28,7 @@ mod x { mod y { use {Foo, Bar}; - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path pub fn call_bar() { char::bar('a'); } @@ -37,7 +37,7 @@ mod y { mod z { use y; - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path pub fn z() { y::call_bar(); } diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr index 8670e7deb4cda..d8a1f05dcaa79 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr @@ -1,14 +1,14 @@ -error: no path from `x::` to `TypeckTables` +error: no path from `x::` to `typeck_tables_of` --> $DIR/dep-graph-trait-impl-two-traits.rs:31:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `x::` to `TypeckTables` +error: no path from `x::` to `typeck_tables_of` --> $DIR/dep-graph-trait-impl-two-traits.rs:40:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl.rs b/src/test/ui/dep-graph/dep-graph-trait-impl.rs index 7d088082c7a4c..e4483b9f71ddb 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl.rs +++ b/src/test/ui/dep-graph/dep-graph-trait-impl.rs @@ -24,22 +24,22 @@ mod x { mod y { use Foo; - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn with_char() { char::method('a'); } - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn take_foo_with_char() { take_foo::('a'); } - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn with_u32() { u32::method(22); } - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn take_foo_with_u32() { take_foo::(22); } @@ -52,7 +52,7 @@ mod z { // These are expected to yield errors, because changes to `x` // affect the BODY of `y`, but not its signature. - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path pub fn z() { y::with_char(); y::with_u32(); diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl.stderr b/src/test/ui/dep-graph/dep-graph-trait-impl.stderr index fe97846d6cc26..ca9676a9478e4 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl.stderr +++ b/src/test/ui/dep-graph/dep-graph-trait-impl.stderr @@ -1,32 +1,32 @@ error: OK --> $DIR/dep-graph-trait-impl.rs:27:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-trait-impl.rs:32:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-trait-impl.rs:37:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-trait-impl.rs:42:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `x::` to `TypeckTables` +error: no path from `x::` to `typeck_tables_of` --> $DIR/dep-graph-trait-impl.rs:55:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-type-alias.rs b/src/test/ui/dep-graph/dep-graph-type-alias.rs index 0f703aeb0f7a3..2d4a18f2818b5 100644 --- a/src/test/ui/dep-graph/dep-graph-type-alias.rs +++ b/src/test/ui/dep-graph/dep-graph-type-alias.rs @@ -14,42 +14,42 @@ type TypeAlias = u32; // The type alias directly affects the type of the field, // not the enclosing struct: -#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path +#[rustc_then_this_would_need(type_of)] //~ ERROR no path struct Struct { - #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK + #[rustc_then_this_would_need(type_of)] //~ ERROR OK x: TypeAlias, y: u32 } -#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path +#[rustc_then_this_would_need(type_of)] //~ ERROR no path enum Enum { Variant1 { - #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK + #[rustc_then_this_would_need(type_of)] //~ ERROR OK t: TypeAlias }, Variant2(i32) } -#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path +#[rustc_then_this_would_need(type_of)] //~ ERROR no path trait Trait { - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK fn method(&self, _: TypeAlias); } struct SomeType; -#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path +#[rustc_then_this_would_need(type_of)] //~ ERROR no path impl SomeType { - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK fn method(&self, _: TypeAlias) {} } -#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK +#[rustc_then_this_would_need(type_of)] //~ ERROR OK type TypeAlias2 = TypeAlias; -#[rustc_then_this_would_need(FnSignature)] //~ ERROR OK -#[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK +#[rustc_then_this_would_need(fn_sig)] //~ ERROR OK +#[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK fn function(_: TypeAlias) { } diff --git a/src/test/ui/dep-graph/dep-graph-type-alias.stderr b/src/test/ui/dep-graph/dep-graph-type-alias.stderr index 72def33cbcf99..393e4badc1608 100644 --- a/src/test/ui/dep-graph/dep-graph-type-alias.stderr +++ b/src/test/ui/dep-graph/dep-graph-type-alias.stderr @@ -1,74 +1,74 @@ -error: no path from `TypeAlias` to `TypeOfItem` +error: no path from `TypeAlias` to `type_of` --> $DIR/dep-graph-type-alias.rs:17:1 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-type-alias.rs:19:5 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `TypeAlias` to `TypeOfItem` +error: no path from `TypeAlias` to `type_of` --> $DIR/dep-graph-type-alias.rs:24:1 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-type-alias.rs:27:9 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `TypeAlias` to `TypeOfItem` +error: no path from `TypeAlias` to `type_of` --> $DIR/dep-graph-type-alias.rs:33:1 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `TypeAlias` to `TypeOfItem` +error: no path from `TypeAlias` to `type_of` --> $DIR/dep-graph-type-alias.rs:41:1 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-type-alias.rs:48:1 | -LL | #[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(type_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-type-alias.rs:51:1 | -LL | #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-type-alias.rs:52:1 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-type-alias.rs:35:5 | -LL | #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-type-alias.rs:43:5 | -LL | #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-type-alias.rs:44:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 12 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-variance-alias.rs b/src/test/ui/dep-graph/dep-graph-variance-alias.rs index 0a70bfd08bf27..95645687307a3 100644 --- a/src/test/ui/dep-graph/dep-graph-variance-alias.rs +++ b/src/test/ui/dep-graph/dep-graph-variance-alias.rs @@ -16,7 +16,7 @@ struct Foo { #[rustc_if_this_changed(Krate)] type TypeAlias = Foo; -#[rustc_then_this_would_need(ItemVariances)] //~ ERROR OK +#[rustc_then_this_would_need(variances_of)] //~ ERROR OK struct Use { x: TypeAlias } diff --git a/src/test/ui/dep-graph/dep-graph-variance-alias.stderr b/src/test/ui/dep-graph/dep-graph-variance-alias.stderr index f7c7f01020d26..554ff455a2073 100644 --- a/src/test/ui/dep-graph/dep-graph-variance-alias.stderr +++ b/src/test/ui/dep-graph/dep-graph-variance-alias.stderr @@ -1,8 +1,8 @@ error: OK --> $DIR/dep-graph-variance-alias.rs:19:1 | -LL | #[rustc_then_this_would_need(ItemVariances)] //~ ERROR OK - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(variances_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/deprecation/atomic_initializers.stderr b/src/test/ui/deprecation/atomic_initializers.stderr index 77c370814f7af..b009ff9486be2 100644 --- a/src/test/ui/deprecation/atomic_initializers.stderr +++ b/src/test/ui/deprecation/atomic_initializers.stderr @@ -2,11 +2,7 @@ warning: use of deprecated item 'std::sync::atomic::ATOMIC_ISIZE_INIT': the `new --> $DIR/atomic_initializers.rs:8:27 | LL | static FOO: AtomicIsize = ATOMIC_ISIZE_INIT; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ help: replace the use of the deprecated item: `AtomicIsize::new(0)` | = note: #[warn(deprecated)] on by default -help: use of deprecated item 'std::sync::atomic::ATOMIC_ISIZE_INIT': the `new` function is now preferred - | -LL | static FOO: AtomicIsize = AtomicIsize::new(0); - | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/deprecation/deprecated-macro_escape-inner.stderr b/src/test/ui/deprecation/deprecated-macro_escape-inner.stderr index 94229386e5f59..a2cd196b21f8b 100644 --- a/src/test/ui/deprecation/deprecated-macro_escape-inner.stderr +++ b/src/test/ui/deprecation/deprecated-macro_escape-inner.stderr @@ -1,7 +1,7 @@ warning: macro_escape is a deprecated synonym for macro_use --> $DIR/deprecated-macro_escape-inner.rs:4:5 | -LL | #![macro_escape] //~ WARNING macro_escape is a deprecated synonym for macro_use +LL | #![macro_escape] | ^^^^^^^^^^^^^^^^ | = help: consider an outer attribute, #[macro_use] mod ... diff --git a/src/test/ui/deprecation/deprecated-macro_escape.stderr b/src/test/ui/deprecation/deprecated-macro_escape.stderr index f0edd838874e9..b76d6d73d972b 100644 --- a/src/test/ui/deprecation/deprecated-macro_escape.stderr +++ b/src/test/ui/deprecation/deprecated-macro_escape.stderr @@ -1,6 +1,6 @@ warning: macro_escape is a deprecated synonym for macro_use --> $DIR/deprecated-macro_escape.rs:3:1 | -LL | #[macro_escape] //~ WARNING macro_escape is a deprecated synonym for macro_use +LL | #[macro_escape] | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/deprecation/deprecated_no_stack_check.stderr b/src/test/ui/deprecation/deprecated_no_stack_check.stderr index c936a550b3aca..141664c109228 100644 --- a/src/test/ui/deprecation/deprecated_no_stack_check.stderr +++ b/src/test/ui/deprecation/deprecated_no_stack_check.stderr @@ -2,7 +2,7 @@ error[E0557]: feature has been removed --> $DIR/deprecated_no_stack_check.rs:2:12 | LL | #![feature(no_stack_check)] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ feature has been removed error: aborting due to previous error diff --git a/src/test/ui/deprecation/deprecation-in-future.rs b/src/test/ui/deprecation/deprecation-in-future.rs index 138d902621cbc..c4f9fdce74907 100644 --- a/src/test/ui/deprecation/deprecation-in-future.rs +++ b/src/test/ui/deprecation/deprecation-in-future.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - // run-pass #![deny(deprecated_in_future)] diff --git a/src/test/ui/deprecation/deprecation-in-future.stderr b/src/test/ui/deprecation/deprecation-in-future.stderr index 81d2461c1bd83..2284cfa8d685b 100644 --- a/src/test/ui/deprecation/deprecation-in-future.stderr +++ b/src/test/ui/deprecation/deprecation-in-future.stderr @@ -1,5 +1,5 @@ warning: use of deprecated item 'deprecated_future': text - --> $DIR/deprecation-in-future.rs:11:5 + --> $DIR/deprecation-in-future.rs:9:5 | LL | deprecated_future(); // ok; deprecated_in_future only applies to rustc_deprecated | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/deprecation/deprecation-in-staged-api.rs b/src/test/ui/deprecation/deprecation-in-staged-api.rs index bcc17c789f551..f667de83b56d4 100644 --- a/src/test/ui/deprecation/deprecation-in-staged-api.rs +++ b/src/test/ui/deprecation/deprecation-in-staged-api.rs @@ -1,8 +1,8 @@ -// #[deprecated] can't be used in staged api +// #[deprecated] cannot be used in staged API #![feature(staged_api)] #![stable(feature = "stable_test_feature", since = "1.0.0")] #[deprecated] -fn main() { } //~ERROR `#[deprecated]` cannot be used in staged api +fn main() { } //~ ERROR `#[deprecated]` cannot be used in staged API diff --git a/src/test/ui/deprecation/deprecation-in-staged-api.stderr b/src/test/ui/deprecation/deprecation-in-staged-api.stderr index 3e64d756e7e69..c6881d5a5735f 100644 --- a/src/test/ui/deprecation/deprecation-in-staged-api.stderr +++ b/src/test/ui/deprecation/deprecation-in-staged-api.stderr @@ -1,7 +1,7 @@ -error: `#[deprecated]` cannot be used in staged api, use `#[rustc_deprecated]` instead +error: `#[deprecated]` cannot be used in staged API; use `#[rustc_deprecated]` instead --> $DIR/deprecation-in-staged-api.rs:8:1 | -LL | fn main() { } //~ERROR `#[deprecated]` cannot be used in staged api +LL | fn main() { } | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/deprecation/deprecation-lint-nested.stderr b/src/test/ui/deprecation/deprecation-lint-nested.stderr index b30da3493350f..206e12cfb3ecf 100644 --- a/src/test/ui/deprecation/deprecation-lint-nested.stderr +++ b/src/test/ui/deprecation/deprecation-lint-nested.stderr @@ -1,7 +1,7 @@ error: use of deprecated item 'loud::DeprecatedType' --> $DIR/deprecation-lint-nested.rs:55:16 | -LL | struct Foo(DeprecatedType); //~ ERROR use of deprecated item +LL | struct Foo(DeprecatedType); | ^^^^^^^^^^^^^^ | note: lint level defined here @@ -13,31 +13,31 @@ LL | #![deny(deprecated)] error: use of deprecated item 'loud::DeprecatedTrait' --> $DIR/deprecation-lint-nested.rs:57:10 | -LL | impl DeprecatedTrait for Foo {} //~ ERROR use of deprecated item +LL | impl DeprecatedTrait for Foo {} | ^^^^^^^^^^^^^^^ error: use of deprecated item 'loud::DEPRECATED_STATIC' --> $DIR/deprecation-lint-nested.rs:66:9 | -LL | DEPRECATED_STATIC + //~ ERROR use of deprecated item +LL | DEPRECATED_STATIC + | ^^^^^^^^^^^^^^^^^ error: use of deprecated item 'loud::DEPRECATED_CONST' --> $DIR/deprecation-lint-nested.rs:67:9 | -LL | DEPRECATED_CONST //~ ERROR use of deprecated item +LL | DEPRECATED_CONST | ^^^^^^^^^^^^^^^^ error: use of deprecated item 'loud::DeprecatedTrait' --> $DIR/deprecation-lint-nested.rs:60:19 | -LL | fn bar() { //~ ERROR use of deprecated item +LL | fn bar() { | ^^^^^^^^^^^^^^^ error: use of deprecated item 'loud::deprecated_fn' --> $DIR/deprecation-lint-nested.rs:61:13 | -LL | deprecated_fn(); //~ ERROR use of deprecated item +LL | deprecated_fn(); | ^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/deprecation/deprecation-lint.rs b/src/test/ui/deprecation/deprecation-lint.rs index 033d6eebbb219..26271395005a7 100644 --- a/src/test/ui/deprecation/deprecation-lint.rs +++ b/src/test/ui/deprecation/deprecation-lint.rs @@ -314,7 +314,7 @@ mod this_crate { let _ = || { #[deprecated] fn bar() { } - bar(); //~ ERROR use of deprecated item 'this_crate::test_fn_closure_body::{{closure}}::bar' + bar(); //~ ERROR use of deprecated item 'this_crate::test_fn_closure_body::{{closure}}#0::bar' }; } diff --git a/src/test/ui/deprecation/deprecation-lint.stderr b/src/test/ui/deprecation/deprecation-lint.stderr index c48d06e86154d..ffbcb259754e7 100644 --- a/src/test/ui/deprecation/deprecation-lint.stderr +++ b/src/test/ui/deprecation/deprecation-lint.stderr @@ -1,7 +1,7 @@ error: use of deprecated item 'deprecation_lint::deprecated': text --> $DIR/deprecation-lint.rs:17:9 | -LL | deprecated(); //~ ERROR use of deprecated item 'deprecation_lint::deprecated' +LL | deprecated(); | ^^^^^^^^^^ | note: lint level defined here @@ -13,127 +13,127 @@ LL | #![deny(deprecated)] error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:22:9 | -LL | Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated' +LL | Trait::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:24:9 | -LL | ::trait_deprecated(&foo); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::deprecated_text': text --> $DIR/deprecation-lint.rs:26:9 | -LL | deprecated_text(); //~ ERROR use of deprecated item 'deprecation_lint::deprecated_text': text +LL | deprecated_text(); | ^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:31:9 | -LL | Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text +LL | Trait::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:33:9 | -LL | ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::DeprecatedStruct': text --> $DIR/deprecation-lint.rs:35:17 | -LL | let _ = DeprecatedStruct { //~ ERROR use of deprecated item 'deprecation_lint::DeprecatedStruct': text +LL | let _ = DeprecatedStruct { | ^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::DeprecatedUnitStruct': text --> $DIR/deprecation-lint.rs:39:17 | -LL | let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item 'deprecation_lint::DeprecatedUnitStruct': text +LL | let _ = DeprecatedUnitStruct; | ^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Enum::DeprecatedVariant': text --> $DIR/deprecation-lint.rs:41:17 | -LL | let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item 'deprecation_lint::Enum::DeprecatedVariant': text +LL | let _ = Enum::DeprecatedVariant; | ^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::DeprecatedTupleStruct': text --> $DIR/deprecation-lint.rs:43:17 | -LL | let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item 'deprecation_lint::DeprecatedTupleStruct': text +LL | let _ = DeprecatedTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::nested::DeprecatedStruct': text --> $DIR/deprecation-lint.rs:45:17 | -LL | let _ = nested::DeprecatedStruct { //~ ERROR use of deprecated item 'deprecation_lint::nested::DeprecatedStruct': text +LL | let _ = nested::DeprecatedStruct { | ^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::nested::DeprecatedUnitStruct': text --> $DIR/deprecation-lint.rs:49:17 | -LL | let _ = nested::DeprecatedUnitStruct; //~ ERROR use of deprecated item 'deprecation_lint::nested::DeprecatedUnitStruct': text +LL | let _ = nested::DeprecatedUnitStruct; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::nested::Enum::DeprecatedVariant': text --> $DIR/deprecation-lint.rs:51:17 | -LL | let _ = nested::Enum::DeprecatedVariant; //~ ERROR use of deprecated item 'deprecation_lint::nested::Enum::DeprecatedVariant': text +LL | let _ = nested::Enum::DeprecatedVariant; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::nested::DeprecatedTupleStruct': text --> $DIR/deprecation-lint.rs:53:17 | -LL | let _ = nested::DeprecatedTupleStruct (1); //~ ERROR use of deprecated item 'deprecation_lint::nested::DeprecatedTupleStruct': text +LL | let _ = nested::DeprecatedTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::deprecated_text': text --> $DIR/deprecation-lint.rs:60:25 | -LL | macro_test_arg!(deprecated_text()); //~ ERROR use of deprecated item 'deprecation_lint::deprecated_text': text +LL | macro_test_arg!(deprecated_text()); | ^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::deprecated_text': text --> $DIR/deprecation-lint.rs:61:41 | -LL | macro_test_arg!(macro_test_arg!(deprecated_text())); //~ ERROR use of deprecated item 'deprecation_lint::deprecated_text': text +LL | macro_test_arg!(macro_test_arg!(deprecated_text())); | ^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:66:9 | -LL | Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated' +LL | Trait::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:68:9 | -LL | ::trait_deprecated(&foo); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:70:9 | -LL | Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text +LL | Trait::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:72:9 | -LL | ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::DeprecatedTrait': text --> $DIR/deprecation-lint.rs:82:10 | -LL | impl DeprecatedTrait for S {} //~ ERROR use of deprecated item 'deprecation_lint::DeprecatedTrait': text +LL | impl DeprecatedTrait for S {} | ^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::DeprecatedTrait': text --> $DIR/deprecation-lint.rs:83:24 | -LL | trait LocalTrait : DeprecatedTrait { } //~ ERROR use of deprecated item 'deprecation_lint::DeprecatedTrait': text +LL | trait LocalTrait : DeprecatedTrait { } | ^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Deprecated': text @@ -175,55 +175,55 @@ LL | let Deprecated2 error: use of deprecated item 'deprecation_lint::deprecated_mod::deprecated': text --> $DIR/deprecation-lint.rs:163:9 | -LL | deprecated_mod::deprecated(); //~ ERROR use of deprecated item 'deprecation_lint::deprecated_mod::deprecated': text +LL | deprecated_mod::deprecated(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::deprecated': text --> $DIR/deprecation-lint.rs:246:9 | -LL | deprecated(); //~ ERROR use of deprecated item 'this_crate::deprecated' +LL | deprecated(); | ^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:251:9 | -LL | Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | Trait::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:253:9 | -LL | ::trait_deprecated(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::deprecated_text': text --> $DIR/deprecation-lint.rs:255:9 | -LL | deprecated_text(); //~ ERROR use of deprecated item 'this_crate::deprecated_text': text +LL | deprecated_text(); | ^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:260:9 | -LL | Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | Trait::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:262:9 | -LL | ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::deprecated_future': text --> $DIR/deprecation-lint.rs:265:9 | -LL | deprecated_future(); //~ ERROR use of deprecated item +LL | deprecated_future(); | ^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::deprecated_future_text': text --> $DIR/deprecation-lint.rs:266:9 | -LL | deprecated_future_text(); //~ ERROR use of deprecated item +LL | deprecated_future_text(); | ^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::DeprecatedStruct': text @@ -235,19 +235,19 @@ LL | let _ = DeprecatedStruct { error: use of deprecated item 'this_crate::DeprecatedUnitStruct': text --> $DIR/deprecation-lint.rs:273:17 | -LL | let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item 'this_crate::DeprecatedUnitStruct': text +LL | let _ = DeprecatedUnitStruct; | ^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Enum::DeprecatedVariant': text --> $DIR/deprecation-lint.rs:275:17 | -LL | let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item 'this_crate::Enum::DeprecatedVariant': text +LL | let _ = Enum::DeprecatedVariant; | ^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::DeprecatedTupleStruct': text --> $DIR/deprecation-lint.rs:277:17 | -LL | let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item 'this_crate::DeprecatedTupleStruct': text +LL | let _ = DeprecatedTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::nested::DeprecatedStruct': text @@ -259,61 +259,61 @@ LL | let _ = nested::DeprecatedStruct { error: use of deprecated item 'this_crate::nested::DeprecatedUnitStruct': text --> $DIR/deprecation-lint.rs:284:17 | -LL | let _ = nested::DeprecatedUnitStruct; //~ ERROR use of deprecated item 'this_crate::nested::DeprecatedUnitStruct': text +LL | let _ = nested::DeprecatedUnitStruct; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::nested::Enum::DeprecatedVariant': text --> $DIR/deprecation-lint.rs:286:17 | -LL | let _ = nested::Enum::DeprecatedVariant; //~ ERROR use of deprecated item 'this_crate::nested::Enum::DeprecatedVariant': text +LL | let _ = nested::Enum::DeprecatedVariant; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::nested::DeprecatedTupleStruct': text --> $DIR/deprecation-lint.rs:288:17 | -LL | let _ = nested::DeprecatedTupleStruct (1); //~ ERROR use of deprecated item 'this_crate::nested::DeprecatedTupleStruct': text +LL | let _ = nested::DeprecatedTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:293:9 | -LL | Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | Trait::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:295:9 | -LL | ::trait_deprecated(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:297:9 | -LL | Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | Trait::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:299:9 | -LL | ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: use of deprecated item 'this_crate::test_fn_closure_body::{{closure}}::bar' +error: use of deprecated item 'this_crate::test_fn_closure_body::{{closure}}#0::bar' --> $DIR/deprecation-lint.rs:317:13 | -LL | bar(); //~ ERROR use of deprecated item 'this_crate::test_fn_closure_body::{{closure}}::bar' +LL | bar(); | ^^^ error: use of deprecated item 'this_crate::DeprecatedTrait': text --> $DIR/deprecation-lint.rs:336:10 | -LL | impl DeprecatedTrait for S { } //~ ERROR use of deprecated item 'this_crate::DeprecatedTrait': text +LL | impl DeprecatedTrait for S { } | ^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::DeprecatedTrait': text --> $DIR/deprecation-lint.rs:338:24 | -LL | trait LocalTrait : DeprecatedTrait { } //~ ERROR use of deprecated item 'this_crate::DeprecatedTrait': text +LL | trait LocalTrait : DeprecatedTrait { } | ^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate2::Deprecated': text @@ -355,109 +355,109 @@ LL | let Deprecated2 error: use of deprecated item 'deprecation_lint::MethodTester::method_deprecated': text --> $DIR/deprecation-lint.rs:18:13 | -LL | foo.method_deprecated(); //~ ERROR use of deprecated item 'deprecation_lint::MethodTester::method_deprecated' +LL | foo.method_deprecated(); | ^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::MethodTester::method_deprecated': text --> $DIR/deprecation-lint.rs:19:9 | -LL | Foo::method_deprecated(&foo); //~ ERROR use of deprecated item 'deprecation_lint::MethodTester::method_deprecated' +LL | Foo::method_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::MethodTester::method_deprecated': text --> $DIR/deprecation-lint.rs:20:9 | -LL | ::method_deprecated(&foo); //~ ERROR use of deprecated item 'deprecation_lint::MethodTester::method_deprecated' +LL | ::method_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:21:13 | -LL | foo.trait_deprecated(); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated' +LL | foo.trait_deprecated(); | ^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:23:9 | -LL | ::trait_deprecated(&foo); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::MethodTester::method_deprecated_text': text --> $DIR/deprecation-lint.rs:27:13 | -LL | foo.method_deprecated_text(); //~ ERROR use of deprecated item 'deprecation_lint::MethodTester::method_deprecated_text': text +LL | foo.method_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::MethodTester::method_deprecated_text': text --> $DIR/deprecation-lint.rs:28:9 | -LL | Foo::method_deprecated_text(&foo); //~ ERROR use of deprecated item 'deprecation_lint::MethodTester::method_deprecated_text': text +LL | Foo::method_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::MethodTester::method_deprecated_text': text --> $DIR/deprecation-lint.rs:29:9 | -LL | ::method_deprecated_text(&foo); //~ ERROR use of deprecated item 'deprecation_lint::MethodTester::method_deprecated_text': text +LL | ::method_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:30:13 | -LL | foo.trait_deprecated_text(); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text +LL | foo.trait_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:32:9 | -LL | ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::DeprecatedStruct::i': text --> $DIR/deprecation-lint.rs:36:13 | -LL | i: 0 //~ ERROR use of deprecated item 'deprecation_lint::DeprecatedStruct::i': text +LL | i: 0 | ^^^^ error: use of deprecated item 'deprecation_lint::nested::DeprecatedStruct::i': text --> $DIR/deprecation-lint.rs:46:13 | -LL | i: 0 //~ ERROR use of deprecated item 'deprecation_lint::nested::DeprecatedStruct::i': text +LL | i: 0 | ^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:65:13 | -LL | foo.trait_deprecated(); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated' +LL | foo.trait_deprecated(); | ^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:67:9 | -LL | ::trait_deprecated(&foo); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:69:13 | -LL | foo.trait_deprecated_text(); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text +LL | foo.trait_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:71:9 | -LL | ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:76:13 | -LL | foo.trait_deprecated(); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated' +LL | foo.trait_deprecated(); | ^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:77:13 | -LL | foo.trait_deprecated_text(); //~ ERROR use of deprecated item 'deprecation_lint::Trait::trait_deprecated_text': text +LL | foo.trait_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'deprecation_lint::Stable::override2': text @@ -547,109 +547,109 @@ LL | _) error: use of deprecated item 'this_crate::MethodTester::method_deprecated': text --> $DIR/deprecation-lint.rs:247:13 | -LL | foo.method_deprecated(); //~ ERROR use of deprecated item 'this_crate::MethodTester::method_deprecated' +LL | foo.method_deprecated(); | ^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::MethodTester::method_deprecated': text --> $DIR/deprecation-lint.rs:248:9 | -LL | Foo::method_deprecated(&foo); //~ ERROR use of deprecated item 'this_crate::MethodTester::method_deprecated' +LL | Foo::method_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::MethodTester::method_deprecated': text --> $DIR/deprecation-lint.rs:249:9 | -LL | ::method_deprecated(&foo); //~ ERROR use of deprecated item 'this_crate::MethodTester::method_deprecated' +LL | ::method_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:250:13 | -LL | foo.trait_deprecated(); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | foo.trait_deprecated(); | ^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:252:9 | -LL | ::trait_deprecated(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text --> $DIR/deprecation-lint.rs:256:13 | -LL | foo.method_deprecated_text(); //~ ERROR use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text +LL | foo.method_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text --> $DIR/deprecation-lint.rs:257:9 | -LL | Foo::method_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text +LL | Foo::method_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text --> $DIR/deprecation-lint.rs:258:9 | -LL | ::method_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text +LL | ::method_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:259:13 | -LL | foo.trait_deprecated_text(); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | foo.trait_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:261:9 | -LL | ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::DeprecatedStruct::i': text --> $DIR/deprecation-lint.rs:270:13 | -LL | i: 0 //~ ERROR use of deprecated item 'this_crate::DeprecatedStruct::i': text +LL | i: 0 | ^^^^ error: use of deprecated item 'this_crate::nested::DeprecatedStruct::i': text --> $DIR/deprecation-lint.rs:281:13 | -LL | i: 0 //~ ERROR use of deprecated item 'this_crate::nested::DeprecatedStruct::i': text +LL | i: 0 | ^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:292:13 | -LL | foo.trait_deprecated(); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | foo.trait_deprecated(); | ^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:294:9 | -LL | ::trait_deprecated(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:296:13 | -LL | foo.trait_deprecated_text(); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | foo.trait_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:298:9 | -LL | ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/deprecation-lint.rs:303:13 | -LL | foo.trait_deprecated(); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | foo.trait_deprecated(); | ^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/deprecation-lint.rs:304:13 | -LL | foo.trait_deprecated_text(); //~ ERROR use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | foo.trait_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated item 'this_crate2::Stable::override2': text diff --git a/src/test/ui/deprecation/deprecation-sanity.stderr b/src/test/ui/deprecation/deprecation-sanity.stderr index a071a4fc10d51..7ff68a1038b1c 100644 --- a/src/test/ui/deprecation/deprecation-sanity.stderr +++ b/src/test/ui/deprecation/deprecation-sanity.stderr @@ -1,58 +1,58 @@ error[E0541]: unknown meta item 'reason' --> $DIR/deprecation-sanity.rs:4:43 | -LL | #[deprecated(since = "a", note = "a", reason)] //~ ERROR unknown meta item 'reason' +LL | #[deprecated(since = "a", note = "a", reason)] | ^^^^^^ expected one of `since`, `note` error[E0551]: incorrect meta item --> $DIR/deprecation-sanity.rs:7:31 | -LL | #[deprecated(since = "a", note)] //~ ERROR incorrect meta item +LL | #[deprecated(since = "a", note)] | ^^^^ error[E0551]: incorrect meta item --> $DIR/deprecation-sanity.rs:10:18 | -LL | #[deprecated(since, note = "a")] //~ ERROR incorrect meta item +LL | #[deprecated(since, note = "a")] | ^^^^^ error[E0551]: incorrect meta item --> $DIR/deprecation-sanity.rs:13:31 | -LL | #[deprecated(since = "a", note(b))] //~ ERROR incorrect meta item +LL | #[deprecated(since = "a", note(b))] | ^^^^^^^ error[E0551]: incorrect meta item --> $DIR/deprecation-sanity.rs:16:18 | -LL | #[deprecated(since(b), note = "a")] //~ ERROR incorrect meta item +LL | #[deprecated(since(b), note = "a")] | ^^^^^^^^ error[E0565]: literal in `deprecated` value must be a string --> $DIR/deprecation-sanity.rs:19:25 | -LL | #[deprecated(note = b"test")] //~ ERROR literal in `deprecated` value must be a string +LL | #[deprecated(note = b"test")] | ^^^^^^^ help: consider removing the prefix: `"test"` error[E0565]: item in `deprecated` must be a key/value pair --> $DIR/deprecation-sanity.rs:22:18 | -LL | #[deprecated("test")] //~ ERROR item in `deprecated` must be a key/value pair +LL | #[deprecated("test")] | ^^^^^^ error[E0550]: multiple deprecated attributes --> $DIR/deprecation-sanity.rs:28:1 | -LL | fn multiple1() { } //~ ERROR multiple deprecated attributes +LL | fn multiple1() { } | ^^^^^^^^^^^^^^^^^^ error[E0538]: multiple 'since' items --> $DIR/deprecation-sanity.rs:30:27 | -LL | #[deprecated(since = "a", since = "b", note = "c")] //~ ERROR multiple 'since' items +LL | #[deprecated(since = "a", since = "b", note = "c")] | ^^^^^^^^^^^ error: aborting due to 9 previous errors -Some errors occurred: E0538, E0541, E0550, E0551, E0565. +Some errors have detailed explanations: E0538, E0541, E0565. For more information about an error, try `rustc --explain E0538`. diff --git a/src/test/ui/deprecation/derive_on_deprecated.rs b/src/test/ui/deprecation/derive_on_deprecated.rs new file mode 100644 index 0000000000000..4980a7f5aa31c --- /dev/null +++ b/src/test/ui/deprecation/derive_on_deprecated.rs @@ -0,0 +1,9 @@ +// compile-pass + +#![deny(deprecated)] + +#[deprecated = "oh no"] +#[derive(Default)] +struct X; + +fn main() {} diff --git a/src/test/ui/deprecation/derive_on_deprecated_forbidden.rs b/src/test/ui/deprecation/derive_on_deprecated_forbidden.rs new file mode 100644 index 0000000000000..235146bad9c85 --- /dev/null +++ b/src/test/ui/deprecation/derive_on_deprecated_forbidden.rs @@ -0,0 +1,9 @@ +// compile-pass + +#![forbid(deprecated)] + +#[deprecated = "oh no"] +#[derive(Default)] +struct X; + +fn main() {} diff --git a/src/test/ui/deprecation/invalid-literal.rs b/src/test/ui/deprecation/invalid-literal.rs index 7e0d8cdfc2f72..fbdfbd1600d7a 100644 --- a/src/test/ui/deprecation/invalid-literal.rs +++ b/src/test/ui/deprecation/invalid-literal.rs @@ -1,4 +1,4 @@ -#[deprecated = b"test"] //~ ERROR attribute must be of the form +#[deprecated = b"test"] //~ ERROR malformed `deprecated` attribute fn foo() {} fn main() {} diff --git a/src/test/ui/deprecation/invalid-literal.stderr b/src/test/ui/deprecation/invalid-literal.stderr index f13d599c0b137..a82eed24814cf 100644 --- a/src/test/ui/deprecation/invalid-literal.stderr +++ b/src/test/ui/deprecation/invalid-literal.stderr @@ -1,8 +1,16 @@ -error: attribute must be of the form `#[deprecated]` or `#[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason)]` or `#[deprecated = "reason"]` +error: malformed `deprecated` attribute input --> $DIR/invalid-literal.rs:1:1 | -LL | #[deprecated = b"test"] //~ ERROR attribute must be of the form +LL | #[deprecated = b"test"] | ^^^^^^^^^^^^^^^^^^^^^^^ +help: the following are the possible correct uses + | +LL | #[deprecated] + | ^^^^^^^^^^^^^ +LL | #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[deprecated = "reason"] + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/deprecation/rustc_deprecation-in-future.stderr b/src/test/ui/deprecation/rustc_deprecation-in-future.stderr index bd8ade16ec0e8..4bbe79b55b323 100644 --- a/src/test/ui/deprecation/rustc_deprecation-in-future.stderr +++ b/src/test/ui/deprecation/rustc_deprecation-in-future.stderr @@ -1,7 +1,7 @@ error: use of item 'S' that will be deprecated in future version 99.99.99: effectively never --> $DIR/rustc_deprecation-in-future.rs:14:13 | -LL | let _ = S; //~ ERROR use of item 'S' that will be deprecated in future version 99.99.99: effectively never +LL | let _ = S; | ^ | note: lint level defined here diff --git a/src/test/ui/deprecation/suggestion.fixed b/src/test/ui/deprecation/suggestion.fixed new file mode 100644 index 0000000000000..eba72f88a8911 --- /dev/null +++ b/src/test/ui/deprecation/suggestion.fixed @@ -0,0 +1,28 @@ +// run-rustfix + +#![feature(staged_api)] + +#![stable(since = "1.0.0", feature = "test")] + +#![deny(deprecated)] +#![allow(dead_code)] + +struct Foo; + +impl Foo { + #[rustc_deprecated( + since = "1.0.0", + reason = "replaced by `replacement`", + suggestion = "replacement", + )] + #[stable(since = "1.0.0", feature = "test")] + fn deprecated(&self) {} + + fn replacement(&self) {} +} + +fn main() { + let foo = Foo; + + foo.replacement(); //~ ERROR use of deprecated +} diff --git a/src/test/ui/deprecation/suggestion.rs b/src/test/ui/deprecation/suggestion.rs new file mode 100644 index 0000000000000..8f9791c13e856 --- /dev/null +++ b/src/test/ui/deprecation/suggestion.rs @@ -0,0 +1,28 @@ +// run-rustfix + +#![feature(staged_api)] + +#![stable(since = "1.0.0", feature = "test")] + +#![deny(deprecated)] +#![allow(dead_code)] + +struct Foo; + +impl Foo { + #[rustc_deprecated( + since = "1.0.0", + reason = "replaced by `replacement`", + suggestion = "replacement", + )] + #[stable(since = "1.0.0", feature = "test")] + fn deprecated(&self) {} + + fn replacement(&self) {} +} + +fn main() { + let foo = Foo; + + foo.deprecated(); //~ ERROR use of deprecated +} diff --git a/src/test/ui/deprecation/suggestion.stderr b/src/test/ui/deprecation/suggestion.stderr new file mode 100644 index 0000000000000..6aaabfe957517 --- /dev/null +++ b/src/test/ui/deprecation/suggestion.stderr @@ -0,0 +1,14 @@ +error: use of deprecated item 'Foo::deprecated': replaced by `replacement` + --> $DIR/suggestion.rs:27:9 + | +LL | foo.deprecated(); + | ^^^^^^^^^^ help: replace the use of the deprecated item: `replacement` + | +note: lint level defined here + --> $DIR/suggestion.rs:7:9 + | +LL | #![deny(deprecated)] + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/deref-non-pointer.stderr b/src/test/ui/deref-non-pointer.stderr index 0852311b7b160..1297e496bcb30 100644 --- a/src/test/ui/deref-non-pointer.stderr +++ b/src/test/ui/deref-non-pointer.stderr @@ -1,7 +1,7 @@ error[E0614]: type `{integer}` cannot be dereferenced --> $DIR/deref-non-pointer.rs:2:9 | -LL | match *1 { //~ ERROR: cannot be dereferenced +LL | match *1 { | ^^ error: aborting due to previous error diff --git a/src/test/ui/deref-suggestion.rs b/src/test/ui/deref-suggestion.rs index 83e54b64f47c9..580410aecf4f8 100644 --- a/src/test/ui/deref-suggestion.rs +++ b/src/test/ui/deref-suggestion.rs @@ -15,6 +15,14 @@ fn foo4(u: &u32) { //~^ ERROR mismatched types } +struct S<'a> { + u: &'a u32, +} + +struct R { + i: u32, +} + fn main() { let s = String::new(); let r_s = &s; @@ -27,4 +35,14 @@ fn main() { foo4(&0); assert_eq!(3i32, &3i32); //~^ ERROR mismatched types + let u = 3; + let s = S { u }; + //~^ ERROR mismatched types + let s = S { u: u }; + //~^ ERROR mismatched types + let i = &4; + let r = R { i }; + //~^ ERROR mismatched types + let r = R { i: i }; + //~^ ERROR mismatched types } diff --git a/src/test/ui/deref-suggestion.stderr b/src/test/ui/deref-suggestion.stderr index 99e2b38c3f0d8..9c49f541c9309 100644 --- a/src/test/ui/deref-suggestion.stderr +++ b/src/test/ui/deref-suggestion.stderr @@ -23,7 +23,7 @@ LL | foo3(u); found type `&u32` error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:22:9 + --> $DIR/deref-suggestion.rs:30:9 | LL | foo(&"aaa".to_owned()); | ^^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | foo(&"aaa".to_owned()); found type `&std::string::String` error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:24:9 + --> $DIR/deref-suggestion.rs:32:9 | LL | foo(&mut "aaa".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | foo(&mut "aaa".to_owned()); error[E0308]: mismatched types --> $DIR/deref-suggestion.rs:2:20 | -LL | ($x:expr) => { &$x } //~ ERROR mismatched types +LL | ($x:expr) => { &$x } | ^^^ expected u32, found &{integer} ... LL | foo3(borrow!(0)); @@ -59,7 +59,7 @@ LL | foo3(borrow!(0)); found type `&{integer}` error[E0308]: mismatched types - --> $DIR/deref-suggestion.rs:28:5 + --> $DIR/deref-suggestion.rs:36:5 | LL | assert_eq!(3i32, &3i32); | ^^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found &i32 @@ -68,6 +68,54 @@ LL | assert_eq!(3i32, &3i32); found type `&i32` = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error: aborting due to 6 previous errors +error[E0308]: mismatched types + --> $DIR/deref-suggestion.rs:39:17 + | +LL | let s = S { u }; + | ^ + | | + | expected &u32, found integer + | help: consider borrowing here: `u: &u` + | + = note: expected type `&u32` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/deref-suggestion.rs:41:20 + | +LL | let s = S { u: u }; + | ^ + | | + | expected &u32, found integer + | help: consider borrowing here: `&u` + | + = note: expected type `&u32` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/deref-suggestion.rs:44:17 + | +LL | let r = R { i }; + | ^ + | | + | expected u32, found &{integer} + | help: consider dereferencing the borrow: `i: *i` + | + = note: expected type `u32` + found type `&{integer}` + +error[E0308]: mismatched types + --> $DIR/deref-suggestion.rs:46:20 + | +LL | let r = R { i: i }; + | ^ + | | + | expected u32, found &{integer} + | help: consider dereferencing the borrow: `*i` + | + = note: expected type `u32` + found type `&{integer}` + +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/derive-uninhabited-enum-38885.rs b/src/test/ui/derive-uninhabited-enum-38885.rs index c0279d60e24c9..b314eacc92e0e 100644 --- a/src/test/ui/derive-uninhabited-enum-38885.rs +++ b/src/test/ui/derive-uninhabited-enum-38885.rs @@ -14,4 +14,3 @@ enum Foo { //~ WARN never used } fn main() {} - diff --git a/src/test/ui/derive-uninhabited-enum-38885.stderr b/src/test/ui/derive-uninhabited-enum-38885.stderr index 8930b1f1974fc..941c98b5506b2 100644 --- a/src/test/ui/derive-uninhabited-enum-38885.stderr +++ b/src/test/ui/derive-uninhabited-enum-38885.stderr @@ -1,7 +1,7 @@ warning: enum is never used: `Void` --> $DIR/derive-uninhabited-enum-38885.rs:8:1 | -LL | enum Void {} //~ WARN never used +LL | enum Void {} | ^^^^^^^^^ | = note: `-W dead-code` implied by `-W unused` @@ -9,6 +9,6 @@ LL | enum Void {} //~ WARN never used warning: enum is never used: `Foo` --> $DIR/derive-uninhabited-enum-38885.rs:11:1 | -LL | enum Foo { //~ WARN never used +LL | enum Foo { | ^^^^^^^^ diff --git a/src/test/ui/derived-errors/issue-30580.stderr b/src/test/ui/derived-errors/issue-30580.stderr index d4829ad2a1af9..14c575f2699a6 100644 --- a/src/test/ui/derived-errors/issue-30580.stderr +++ b/src/test/ui/derived-errors/issue-30580.stderr @@ -1,7 +1,7 @@ error[E0609]: no field `c` on type `&Foo` --> $DIR/issue-30580.rs:12:11 | -LL | b.c; //~ ERROR no field `c` on type `&Foo` +LL | b.c; | ^ error: aborting due to previous error diff --git a/src/test/ui/derived-errors/issue-31997.rs b/src/test/ui/derived-errors/issue-31997.rs index 025e9100e2360..cfdee26c5599c 100644 --- a/src/test/ui/derived-errors/issue-31997.rs +++ b/src/test/ui/derived-errors/issue-31997.rs @@ -10,7 +10,7 @@ fn closure(x: F) -> Result } fn foo() -> Result<(), ()> { - try!(closure(|| bar(0 as *mut _))); //~ ERROR cannot find function `bar` in this scope + try!(closure(|| bar(core::ptr::null_mut()))); //~ ERROR cannot find function `bar` in this scope Ok(()) } diff --git a/src/test/ui/derived-errors/issue-31997.stderr b/src/test/ui/derived-errors/issue-31997.stderr index 246e6f6465cde..e9fe0d3971ee6 100644 --- a/src/test/ui/derived-errors/issue-31997.stderr +++ b/src/test/ui/derived-errors/issue-31997.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find function `bar` in this scope --> $DIR/issue-31997.rs:13:21 | -LL | try!(closure(|| bar(0 as *mut _))); //~ ERROR cannot find function `bar` in this scope +LL | try!(closure(|| bar(core::ptr::null_mut()))); | ^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/derives/derive-assoc-type-not-impl.stderr b/src/test/ui/derives/derive-assoc-type-not-impl.stderr index 1b25231677c7d..b9e175e43d1cf 100644 --- a/src/test/ui/derives/derive-assoc-type-not-impl.stderr +++ b/src/test/ui/derives/derive-assoc-type-not-impl.stderr @@ -4,7 +4,7 @@ error[E0599]: no method named `clone` found for type `Bar` in the curr LL | struct Bar { | ------------------ method `clone` not found for this ... -LL | Bar:: { x: 1 }.clone(); //~ ERROR +LL | Bar:: { x: 1 }.clone(); | ^^^^^ | = note: the method `clone` exists but the following trait bounds were not satisfied: diff --git a/src/test/ui/derives/derives-span-Clone-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Clone-enum-struct-variant.stderr index deb1cbd89b87b..7db5fbe3de402 100644 --- a/src/test/ui/derives/derives-span-Clone-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Clone-enum-struct-variant.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::clone::Clone` is not satisfied --> $DIR/derives-span-Clone-enum-struct-variant.rs:9:6 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ the trait `std::clone::Clone` is not implemented for `Error` | = note: required by `std::clone::Clone::clone` diff --git a/src/test/ui/derives/derives-span-Clone-enum.stderr b/src/test/ui/derives/derives-span-Clone-enum.stderr index de043cd28aa68..4371dc900ac10 100644 --- a/src/test/ui/derives/derives-span-Clone-enum.stderr +++ b/src/test/ui/derives/derives-span-Clone-enum.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::clone::Clone` is not satisfied --> $DIR/derives-span-Clone-enum.rs:9:6 | -LL | Error //~ ERROR +LL | Error | ^^^^^ the trait `std::clone::Clone` is not implemented for `Error` | = note: required by `std::clone::Clone::clone` diff --git a/src/test/ui/derives/derives-span-Clone-struct.stderr b/src/test/ui/derives/derives-span-Clone-struct.stderr index dd6fa9706c2cf..cc3b602c9c0b9 100644 --- a/src/test/ui/derives/derives-span-Clone-struct.stderr +++ b/src/test/ui/derives/derives-span-Clone-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::clone::Clone` is not satisfied --> $DIR/derives-span-Clone-struct.rs:8:5 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ the trait `std::clone::Clone` is not implemented for `Error` | = note: required by `std::clone::Clone::clone` diff --git a/src/test/ui/derives/derives-span-Clone-tuple-struct.stderr b/src/test/ui/derives/derives-span-Clone-tuple-struct.stderr index 5258240fc1f38..b2bf3527b0cc4 100644 --- a/src/test/ui/derives/derives-span-Clone-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Clone-tuple-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::clone::Clone` is not satisfied --> $DIR/derives-span-Clone-tuple-struct.rs:8:5 | -LL | Error //~ ERROR +LL | Error | ^^^^^ the trait `std::clone::Clone` is not implemented for `Error` | = note: required by `std::clone::Clone::clone` diff --git a/src/test/ui/derives/derives-span-Debug-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Debug-enum-struct-variant.stderr index c981c20b762e1..ca5bcfe930d61 100644 --- a/src/test/ui/derives/derives-span-Debug-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Debug-enum-struct-variant.stderr @@ -1,7 +1,7 @@ error[E0277]: `Error` doesn't implement `std::fmt::Debug` --> $DIR/derives-span-Debug-enum-struct-variant.rs:9:6 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ `Error` cannot be formatted using `{:?}` | = help: the trait `std::fmt::Debug` is not implemented for `Error` diff --git a/src/test/ui/derives/derives-span-Debug-enum.stderr b/src/test/ui/derives/derives-span-Debug-enum.stderr index 02cfe20616cd6..cd367a334fc60 100644 --- a/src/test/ui/derives/derives-span-Debug-enum.stderr +++ b/src/test/ui/derives/derives-span-Debug-enum.stderr @@ -1,7 +1,7 @@ error[E0277]: `Error` doesn't implement `std::fmt::Debug` --> $DIR/derives-span-Debug-enum.rs:9:6 | -LL | Error //~ ERROR +LL | Error | ^^^^^ `Error` cannot be formatted using `{:?}` | = help: the trait `std::fmt::Debug` is not implemented for `Error` diff --git a/src/test/ui/derives/derives-span-Debug-struct.stderr b/src/test/ui/derives/derives-span-Debug-struct.stderr index 5fe7d846b4c2f..e00695ec0ba62 100644 --- a/src/test/ui/derives/derives-span-Debug-struct.stderr +++ b/src/test/ui/derives/derives-span-Debug-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: `Error` doesn't implement `std::fmt::Debug` --> $DIR/derives-span-Debug-struct.rs:8:5 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ `Error` cannot be formatted using `{:?}` | = help: the trait `std::fmt::Debug` is not implemented for `Error` diff --git a/src/test/ui/derives/derives-span-Debug-tuple-struct.stderr b/src/test/ui/derives/derives-span-Debug-tuple-struct.stderr index 9088b9e83b0cb..37440b59ae704 100644 --- a/src/test/ui/derives/derives-span-Debug-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Debug-tuple-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: `Error` doesn't implement `std::fmt::Debug` --> $DIR/derives-span-Debug-tuple-struct.rs:8:5 | -LL | Error //~ ERROR +LL | Error | ^^^^^ `Error` cannot be formatted using `{:?}` | = help: the trait `std::fmt::Debug` is not implemented for `Error` diff --git a/src/test/ui/derives/derives-span-Default-struct.stderr b/src/test/ui/derives/derives-span-Default-struct.stderr index 1ad7cd4547731..413d4ec8c291a 100644 --- a/src/test/ui/derives/derives-span-Default-struct.stderr +++ b/src/test/ui/derives/derives-span-Default-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::default::Default` is not satisfied --> $DIR/derives-span-Default-struct.rs:8:5 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ the trait `std::default::Default` is not implemented for `Error` | = note: required by `std::default::Default::default` diff --git a/src/test/ui/derives/derives-span-Default-tuple-struct.stderr b/src/test/ui/derives/derives-span-Default-tuple-struct.stderr index 447bc73ceb403..8f4d43daa5191 100644 --- a/src/test/ui/derives/derives-span-Default-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Default-tuple-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::default::Default` is not satisfied --> $DIR/derives-span-Default-tuple-struct.rs:8:5 | -LL | Error //~ ERROR +LL | Error | ^^^^^ the trait `std::default::Default` is not implemented for `Error` | = note: required by `std::default::Default::default` diff --git a/src/test/ui/derives/derives-span-Eq-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Eq-enum-struct-variant.stderr index e8bcec4665500..52ecce4632d12 100644 --- a/src/test/ui/derives/derives-span-Eq-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Eq-enum-struct-variant.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::cmp::Eq` is not satisfied --> $DIR/derives-span-Eq-enum-struct-variant.rs:9:6 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Error` | = note: required by `std::cmp::AssertParamIsEq` diff --git a/src/test/ui/derives/derives-span-Eq-enum.stderr b/src/test/ui/derives/derives-span-Eq-enum.stderr index 95ff08a4332c5..bf91a0edc375b 100644 --- a/src/test/ui/derives/derives-span-Eq-enum.stderr +++ b/src/test/ui/derives/derives-span-Eq-enum.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::cmp::Eq` is not satisfied --> $DIR/derives-span-Eq-enum.rs:9:6 | -LL | Error //~ ERROR +LL | Error | ^^^^^ the trait `std::cmp::Eq` is not implemented for `Error` | = note: required by `std::cmp::AssertParamIsEq` diff --git a/src/test/ui/derives/derives-span-Eq-struct.stderr b/src/test/ui/derives/derives-span-Eq-struct.stderr index 44bbcf73dd778..531e8887cd2bc 100644 --- a/src/test/ui/derives/derives-span-Eq-struct.stderr +++ b/src/test/ui/derives/derives-span-Eq-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::cmp::Eq` is not satisfied --> $DIR/derives-span-Eq-struct.rs:8:5 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Error` | = note: required by `std::cmp::AssertParamIsEq` diff --git a/src/test/ui/derives/derives-span-Eq-tuple-struct.stderr b/src/test/ui/derives/derives-span-Eq-tuple-struct.stderr index 26228b3891312..9e21c6c67bfc7 100644 --- a/src/test/ui/derives/derives-span-Eq-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Eq-tuple-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::cmp::Eq` is not satisfied --> $DIR/derives-span-Eq-tuple-struct.rs:8:5 | -LL | Error //~ ERROR +LL | Error | ^^^^^ the trait `std::cmp::Eq` is not implemented for `Error` | = note: required by `std::cmp::AssertParamIsEq` diff --git a/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr index 324f2f1fd6d1c..417c720c63e99 100644 --- a/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied --> $DIR/derives-span-Hash-enum-struct-variant.rs:9:6 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ the trait `std::hash::Hash` is not implemented for `Error` | = note: required by `std::hash::Hash::hash` diff --git a/src/test/ui/derives/derives-span-Hash-enum.stderr b/src/test/ui/derives/derives-span-Hash-enum.stderr index da44a8f498ea4..25be8794889fc 100644 --- a/src/test/ui/derives/derives-span-Hash-enum.stderr +++ b/src/test/ui/derives/derives-span-Hash-enum.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied --> $DIR/derives-span-Hash-enum.rs:9:6 | -LL | Error //~ ERROR +LL | Error | ^^^^^ the trait `std::hash::Hash` is not implemented for `Error` | = note: required by `std::hash::Hash::hash` diff --git a/src/test/ui/derives/derives-span-Hash-struct.stderr b/src/test/ui/derives/derives-span-Hash-struct.stderr index 17d45e4b0dd21..c0574453a7a6b 100644 --- a/src/test/ui/derives/derives-span-Hash-struct.stderr +++ b/src/test/ui/derives/derives-span-Hash-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied --> $DIR/derives-span-Hash-struct.rs:8:5 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ the trait `std::hash::Hash` is not implemented for `Error` | = note: required by `std::hash::Hash::hash` diff --git a/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr b/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr index e0e5cce107f92..6339c38578eb8 100644 --- a/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied --> $DIR/derives-span-Hash-tuple-struct.rs:8:5 | -LL | Error //~ ERROR +LL | Error | ^^^^^ the trait `std::hash::Hash` is not implemented for `Error` | = note: required by `std::hash::Hash::hash` diff --git a/src/test/ui/derives/derives-span-Ord-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Ord-enum-struct-variant.stderr index 149a9475f103d..5c0d4e4ebe917 100644 --- a/src/test/ui/derives/derives-span-Ord-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Ord-enum-struct-variant.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::cmp::Ord` is not satisfied --> $DIR/derives-span-Ord-enum-struct-variant.rs:9:6 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `Error` | = note: required by `std::cmp::Ord::cmp` diff --git a/src/test/ui/derives/derives-span-Ord-enum.stderr b/src/test/ui/derives/derives-span-Ord-enum.stderr index 17ab75549e466..56268a237450a 100644 --- a/src/test/ui/derives/derives-span-Ord-enum.stderr +++ b/src/test/ui/derives/derives-span-Ord-enum.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::cmp::Ord` is not satisfied --> $DIR/derives-span-Ord-enum.rs:9:6 | -LL | Error //~ ERROR +LL | Error | ^^^^^ the trait `std::cmp::Ord` is not implemented for `Error` | = note: required by `std::cmp::Ord::cmp` diff --git a/src/test/ui/derives/derives-span-Ord-struct.stderr b/src/test/ui/derives/derives-span-Ord-struct.stderr index 7088f8fc89018..40dc3d09dad7e 100644 --- a/src/test/ui/derives/derives-span-Ord-struct.stderr +++ b/src/test/ui/derives/derives-span-Ord-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::cmp::Ord` is not satisfied --> $DIR/derives-span-Ord-struct.rs:8:5 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `Error` | = note: required by `std::cmp::Ord::cmp` diff --git a/src/test/ui/derives/derives-span-Ord-tuple-struct.stderr b/src/test/ui/derives/derives-span-Ord-tuple-struct.stderr index 5c046366993fc..4a9dea8c12e9a 100644 --- a/src/test/ui/derives/derives-span-Ord-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Ord-tuple-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Error: std::cmp::Ord` is not satisfied --> $DIR/derives-span-Ord-tuple-struct.rs:8:5 | -LL | Error //~ ERROR +LL | Error | ^^^^^ the trait `std::cmp::Ord` is not implemented for `Error` | = note: required by `std::cmp::Ord::cmp` diff --git a/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr index 7683402d8aaa1..ed5468cc4dac2 100644 --- a/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr @@ -1,7 +1,7 @@ error[E0369]: binary operation `==` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:9:6 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ | = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` @@ -9,7 +9,7 @@ LL | x: Error //~ ERROR error[E0369]: binary operation `!=` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:9:6 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ | = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` diff --git a/src/test/ui/derives/derives-span-PartialEq-enum.stderr b/src/test/ui/derives/derives-span-PartialEq-enum.stderr index 9fa1a2bf17a69..06a88c03f58af 100644 --- a/src/test/ui/derives/derives-span-PartialEq-enum.stderr +++ b/src/test/ui/derives/derives-span-PartialEq-enum.stderr @@ -1,7 +1,7 @@ error[E0369]: binary operation `==` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-enum.rs:9:6 | -LL | Error //~ ERROR +LL | Error | ^^^^^ | = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` @@ -9,7 +9,7 @@ LL | Error //~ ERROR error[E0369]: binary operation `!=` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-enum.rs:9:6 | -LL | Error //~ ERROR +LL | Error | ^^^^^ | = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` diff --git a/src/test/ui/derives/derives-span-PartialEq-struct.stderr b/src/test/ui/derives/derives-span-PartialEq-struct.stderr index 4a08c985b4a06..b8481048361e5 100644 --- a/src/test/ui/derives/derives-span-PartialEq-struct.stderr +++ b/src/test/ui/derives/derives-span-PartialEq-struct.stderr @@ -1,7 +1,7 @@ error[E0369]: binary operation `==` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-struct.rs:8:5 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ | = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` @@ -9,7 +9,7 @@ LL | x: Error //~ ERROR error[E0369]: binary operation `!=` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-struct.rs:8:5 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ | = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` diff --git a/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr b/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr index 850eab4f0880e..4398d25212550 100644 --- a/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr @@ -1,7 +1,7 @@ error[E0369]: binary operation `==` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-tuple-struct.rs:8:5 | -LL | Error //~ ERROR +LL | Error | ^^^^^ | = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` @@ -9,7 +9,7 @@ LL | Error //~ ERROR error[E0369]: binary operation `!=` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-tuple-struct.rs:8:5 | -LL | Error //~ ERROR +LL | Error | ^^^^^ | = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` diff --git a/src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr index 0c359629d7892..ac9f45046353a 100644 --- a/src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr @@ -1,7 +1,7 @@ error[E0277]: can't compare `Error` with `Error` --> $DIR/derives-span-PartialOrd-enum-struct-variant.rs:9:6 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` diff --git a/src/test/ui/derives/derives-span-PartialOrd-enum.stderr b/src/test/ui/derives/derives-span-PartialOrd-enum.stderr index e4036a540db2a..3e684aef39f24 100644 --- a/src/test/ui/derives/derives-span-PartialOrd-enum.stderr +++ b/src/test/ui/derives/derives-span-PartialOrd-enum.stderr @@ -1,7 +1,7 @@ error[E0277]: can't compare `Error` with `Error` --> $DIR/derives-span-PartialOrd-enum.rs:9:6 | -LL | Error //~ ERROR +LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` diff --git a/src/test/ui/derives/derives-span-PartialOrd-struct.stderr b/src/test/ui/derives/derives-span-PartialOrd-struct.stderr index 5c77a05e9d047..10659aac64217 100644 --- a/src/test/ui/derives/derives-span-PartialOrd-struct.stderr +++ b/src/test/ui/derives/derives-span-PartialOrd-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: can't compare `Error` with `Error` --> $DIR/derives-span-PartialOrd-struct.rs:8:5 | -LL | x: Error //~ ERROR +LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` diff --git a/src/test/ui/derives/derives-span-PartialOrd-tuple-struct.stderr b/src/test/ui/derives/derives-span-PartialOrd-tuple-struct.stderr index e38a0424b3d74..cbe05e3784057 100644 --- a/src/test/ui/derives/derives-span-PartialOrd-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-PartialOrd-tuple-struct.stderr @@ -1,7 +1,7 @@ error[E0277]: can't compare `Error` with `Error` --> $DIR/derives-span-PartialOrd-tuple-struct.rs:8:5 | -LL | Error //~ ERROR +LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` diff --git a/src/test/ui/derives/deriving-bounds.rs b/src/test/ui/derives/deriving-bounds.rs index 607cfa1bb2cd7..52659bd11e080 100644 --- a/src/test/ui/derives/deriving-bounds.rs +++ b/src/test/ui/derives/deriving-bounds.rs @@ -1,9 +1,9 @@ #[derive(Send)] -//~^ ERROR this unsafe trait should be implemented explicitly +//~^ ERROR cannot find derive macro `Send` in this scope struct Test; #[derive(Sync)] -//~^ ERROR this unsafe trait should be implemented explicitly +//~^ ERROR cannot find derive macro `Sync` in this scope struct Test1; pub fn main() {} diff --git a/src/test/ui/derives/deriving-bounds.stderr b/src/test/ui/derives/deriving-bounds.stderr index deb84fd99bd2a..99976da72da1d 100644 --- a/src/test/ui/derives/deriving-bounds.stderr +++ b/src/test/ui/derives/deriving-bounds.stderr @@ -1,10 +1,22 @@ -error: this unsafe trait should be implemented explicitly +error: cannot find derive macro `Send` in this scope + --> $DIR/deriving-bounds.rs:1:10 + | +LL | #[derive(Send)] + | ^^^^ + | +note: unsafe traits like `Send` should be implemented explicitly --> $DIR/deriving-bounds.rs:1:10 | LL | #[derive(Send)] | ^^^^ -error: this unsafe trait should be implemented explicitly +error: cannot find derive macro `Sync` in this scope + --> $DIR/deriving-bounds.rs:5:10 + | +LL | #[derive(Sync)] + | ^^^^ + | +note: unsafe traits like `Sync` should be implemented explicitly --> $DIR/deriving-bounds.rs:5:10 | LL | #[derive(Sync)] diff --git a/src/test/ui/derives/deriving-copyclone.rs b/src/test/ui/derives/deriving-copyclone.rs index afe619690711f..4565412bff7f3 100644 --- a/src/test/ui/derives/deriving-copyclone.rs +++ b/src/test/ui/derives/deriving-copyclone.rs @@ -35,4 +35,3 @@ fn main() { is_copy(B { a: 1, b: D }); //~ERROR Copy is_clone(B { a: 1, b: D }); } - diff --git a/src/test/ui/derives/deriving-copyclone.stderr b/src/test/ui/derives/deriving-copyclone.stderr index 0a9fdd34fe2e0..e6060c269e10a 100644 --- a/src/test/ui/derives/deriving-copyclone.stderr +++ b/src/test/ui/derives/deriving-copyclone.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `C: std::marker::Copy` is not satisfied --> $DIR/deriving-copyclone.rs:31:5 | -LL | is_copy(B { a: 1, b: C }); //~ERROR Copy +LL | is_copy(B { a: 1, b: C }); | ^^^^^^^ the trait `std::marker::Copy` is not implemented for `C` | = note: required because of the requirements on the impl of `std::marker::Copy` for `B` @@ -14,7 +14,7 @@ LL | fn is_copy(_: T) {} error[E0277]: the trait bound `C: std::clone::Clone` is not satisfied --> $DIR/deriving-copyclone.rs:32:5 | -LL | is_clone(B { a: 1, b: C }); //~ERROR Clone +LL | is_clone(B { a: 1, b: C }); | ^^^^^^^^ the trait `std::clone::Clone` is not implemented for `C` | = note: required because of the requirements on the impl of `std::clone::Clone` for `B` @@ -27,7 +27,7 @@ LL | fn is_clone(_: T) {} error[E0277]: the trait bound `D: std::marker::Copy` is not satisfied --> $DIR/deriving-copyclone.rs:35:5 | -LL | is_copy(B { a: 1, b: D }); //~ERROR Copy +LL | is_copy(B { a: 1, b: D }); | ^^^^^^^ the trait `std::marker::Copy` is not implemented for `D` | = note: required because of the requirements on the impl of `std::marker::Copy` for `B` diff --git a/src/test/ui/derives/deriving-meta-empty-trait-list.rs b/src/test/ui/derives/deriving-meta-empty-trait-list.rs index 882484146152d..4f2e31e8efb15 100644 --- a/src/test/ui/derives/deriving-meta-empty-trait-list.rs +++ b/src/test/ui/derives/deriving-meta-empty-trait-list.rs @@ -1,6 +1,6 @@ -// compile-pass +#![deny(unused)] -#[derive()] //~ WARNING empty trait list in `derive` -struct Bar; +#[derive()] //~ ERROR unused attribute +struct _Bar; pub fn main() {} diff --git a/src/test/ui/derives/deriving-meta-empty-trait-list.stderr b/src/test/ui/derives/deriving-meta-empty-trait-list.stderr index 191bb780f7e1f..95c94ded3eaf1 100644 --- a/src/test/ui/derives/deriving-meta-empty-trait-list.stderr +++ b/src/test/ui/derives/deriving-meta-empty-trait-list.stderr @@ -1,6 +1,15 @@ -warning: empty trait list in `derive` +error: unused attribute --> $DIR/deriving-meta-empty-trait-list.rs:3:1 | -LL | #[derive()] //~ WARNING empty trait list in `derive` +LL | #[derive()] | ^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/deriving-meta-empty-trait-list.rs:1:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: #[deny(unused_attributes)] implied by #[deny(unused)] + +error: aborting due to previous error diff --git a/src/test/ui/derives/deriving-meta-unknown-trait.rs b/src/test/ui/derives/deriving-meta-unknown-trait.rs index 2b29f10150b96..f4a6f3fd62a05 100644 --- a/src/test/ui/derives/deriving-meta-unknown-trait.rs +++ b/src/test/ui/derives/deriving-meta-unknown-trait.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - #[derive(Eqr)] //~^ ERROR cannot find derive macro `Eqr` in this scope struct Foo; diff --git a/src/test/ui/derives/deriving-meta-unknown-trait.stderr b/src/test/ui/derives/deriving-meta-unknown-trait.stderr index 2b121ac679ae0..cf0173dfad5cd 100644 --- a/src/test/ui/derives/deriving-meta-unknown-trait.stderr +++ b/src/test/ui/derives/deriving-meta-unknown-trait.stderr @@ -1,5 +1,5 @@ error: cannot find derive macro `Eqr` in this scope - --> $DIR/deriving-meta-unknown-trait.rs:3:10 + --> $DIR/deriving-meta-unknown-trait.rs:1:10 | LL | #[derive(Eqr)] | ^^^ help: try: `Eq` diff --git a/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr b/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr index 02ea6321eb8fc..3b480f00df6ea 100644 --- a/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr +++ b/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr @@ -1,7 +1,7 @@ error[E0369]: binary operation `==` cannot be applied to type `NoCloneOrEq` --> $DIR/deriving-no-inner-impl-error-message.rs:5:5 | -LL | x: NoCloneOrEq //~ ERROR binary operation `==` cannot be applied to type `NoCloneOrEq` +LL | x: NoCloneOrEq | ^^^^^^^^^^^^^^ | = note: an implementation of `std::cmp::PartialEq` might be missing for `NoCloneOrEq` @@ -9,7 +9,7 @@ LL | x: NoCloneOrEq //~ ERROR binary operation `==` cannot be applied to typ error[E0369]: binary operation `!=` cannot be applied to type `NoCloneOrEq` --> $DIR/deriving-no-inner-impl-error-message.rs:5:5 | -LL | x: NoCloneOrEq //~ ERROR binary operation `==` cannot be applied to type `NoCloneOrEq` +LL | x: NoCloneOrEq | ^^^^^^^^^^^^^^ | = note: an implementation of `std::cmp::PartialEq` might be missing for `NoCloneOrEq` @@ -24,5 +24,5 @@ LL | x: NoCloneOrEq error: aborting due to 3 previous errors -Some errors occurred: E0277, E0369. +Some errors have detailed explanations: E0277, E0369. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/derives/deriving-non-type.stderr b/src/test/ui/derives/deriving-non-type.stderr index 98594542653c7..563e76dc6094d 100644 --- a/src/test/ui/derives/deriving-non-type.stderr +++ b/src/test/ui/derives/deriving-non-type.stderr @@ -1,55 +1,55 @@ error: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:5:1 | -LL | #[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions +LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:8:1 | -LL | #[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions +LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:11:1 | -LL | #[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions +LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:14:1 | -LL | #[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions +LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:17:1 | -LL | #[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions +LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:20:1 | -LL | #[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions +LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:23:1 | -LL | #[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions +LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:26:1 | -LL | #[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions +LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:29:1 | -LL | #[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions +LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 9 previous errors diff --git a/src/test/ui/derives/deriving-primitive.rs b/src/test/ui/derives/deriving-primitive.rs index 53acf6164d9fe..c7098d4b563bb 100644 --- a/src/test/ui/derives/deriving-primitive.rs +++ b/src/test/ui/derives/deriving-primitive.rs @@ -2,4 +2,3 @@ enum Foo {} fn main() {} - diff --git a/src/test/ui/derives/deriving-primitive.stderr b/src/test/ui/derives/deriving-primitive.stderr index 377f4e870822d..d1b444976ddcc 100644 --- a/src/test/ui/derives/deriving-primitive.stderr +++ b/src/test/ui/derives/deriving-primitive.stderr @@ -1,7 +1,7 @@ error: cannot find derive macro `FromPrimitive` in this scope --> $DIR/deriving-primitive.rs:1:10 | -LL | #[derive(FromPrimitive)] //~ ERROR cannot find derive macro `FromPrimitive` in this scope +LL | #[derive(FromPrimitive)] | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/derives/deriving-with-repr-packed.stderr b/src/test/ui/derives/deriving-with-repr-packed.stderr index 4ab14a1df84db..9d96908a05620 100644 --- a/src/test/ui/derives/deriving-with-repr-packed.stderr +++ b/src/test/ui/derives/deriving-with-repr-packed.stderr @@ -1,4 +1,4 @@ -error: #[derive] can't be used on a #[repr(packed)] struct with type parameters (error E0133) +error: #[derive] can't be used on a #[repr(packed)] struct with type or const parameters (error E0133) --> $DIR/deriving-with-repr-packed.rs:8:16 | LL | #[derive(Copy, Clone, PartialEq, Eq)] @@ -12,7 +12,7 @@ LL | #![deny(safe_packed_borrows)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #46043 -error: #[derive] can't be used on a #[repr(packed)] struct with type parameters (error E0133) +error: #[derive] can't be used on a #[repr(packed)] struct with type or const parameters (error E0133) --> $DIR/deriving-with-repr-packed.rs:8:23 | LL | #[derive(Copy, Clone, PartialEq, Eq)] diff --git a/src/test/ui/destructure-trait-ref.rs b/src/test/ui/destructure-trait-ref.rs index 66be493cb1f97..71cf37ca84951 100644 --- a/src/test/ui/destructure-trait-ref.rs +++ b/src/test/ui/destructure-trait-ref.rs @@ -18,27 +18,28 @@ fn main() { // if n > m, it's a type mismatch error. // n < m - let &x = &(&1isize as &T); - let &x = &&(&1isize as &T); - let &&x = &&(&1isize as &T); + let &x = &(&1isize as &dyn T); + let &x = &&(&1isize as &dyn T); + let &&x = &&(&1isize as &dyn T); // n == m - let &x = &1isize as &T; //~ ERROR type `&dyn T` cannot be dereferenced - let &&x = &(&1isize as &T); //~ ERROR type `&dyn T` cannot be dereferenced - let box x = box 1isize as Box; //~ ERROR type `std::boxed::Box` cannot be dereferenced + let &x = &1isize as &dyn T; //~ ERROR type `&dyn T` cannot be dereferenced + let &&x = &(&1isize as &dyn T); //~ ERROR type `&dyn T` cannot be dereferenced + let box x = box 1isize as Box; + //~^ ERROR type `std::boxed::Box` cannot be dereferenced // n > m - let &&x = &1isize as &T; + let &&x = &1isize as &dyn T; //~^ ERROR mismatched types //~| expected type `dyn T` //~| found type `&_` //~| expected trait T, found reference - let &&&x = &(&1isize as &T); + let &&&x = &(&1isize as &dyn T); //~^ ERROR mismatched types //~| expected type `dyn T` //~| found type `&_` //~| expected trait T, found reference - let box box x = box 1isize as Box; + let box box x = box 1isize as Box; //~^ ERROR mismatched types //~| expected type `dyn T` //~| found type `std::boxed::Box<_>` diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr index 4c93a6781eab1..d3ad21eb24ffb 100644 --- a/src/test/ui/destructure-trait-ref.stderr +++ b/src/test/ui/destructure-trait-ref.stderr @@ -1,45 +1,49 @@ error[E0033]: type `&dyn T` cannot be dereferenced --> $DIR/destructure-trait-ref.rs:26:9 | -LL | let &x = &1isize as &T; //~ ERROR type `&dyn T` cannot be dereferenced +LL | let &x = &1isize as &dyn T; | ^^ type `&dyn T` cannot be dereferenced error[E0033]: type `&dyn T` cannot be dereferenced --> $DIR/destructure-trait-ref.rs:27:10 | -LL | let &&x = &(&1isize as &T); //~ ERROR type `&dyn T` cannot be dereferenced +LL | let &&x = &(&1isize as &dyn T); | ^^ type `&dyn T` cannot be dereferenced error[E0033]: type `std::boxed::Box` cannot be dereferenced --> $DIR/destructure-trait-ref.rs:28:9 | -LL | let box x = box 1isize as Box; //~ ERROR type `std::boxed::Box` cannot be dereferenced +LL | let box x = box 1isize as Box; | ^^^^^ type `std::boxed::Box` cannot be dereferenced error[E0308]: mismatched types - --> $DIR/destructure-trait-ref.rs:31:10 + --> $DIR/destructure-trait-ref.rs:32:10 | -LL | let &&x = &1isize as &T; - | ^^ expected trait T, found reference +LL | let &&x = &1isize as &dyn T; + | ^^ + | | + | expected trait T, found reference + | help: you can probably remove the explicit borrow: `x` | = note: expected type `dyn T` found type `&_` - = help: did you mean `x: &dyn T`? error[E0308]: mismatched types - --> $DIR/destructure-trait-ref.rs:36:11 + --> $DIR/destructure-trait-ref.rs:37:11 | -LL | let &&&x = &(&1isize as &T); - | ^^ expected trait T, found reference +LL | let &&&x = &(&1isize as &dyn T); + | ^^ + | | + | expected trait T, found reference + | help: you can probably remove the explicit borrow: `x` | = note: expected type `dyn T` found type `&_` - = help: did you mean `x: &dyn T`? error[E0308]: mismatched types - --> $DIR/destructure-trait-ref.rs:41:13 + --> $DIR/destructure-trait-ref.rs:42:13 | -LL | let box box x = box 1isize as Box; +LL | let box box x = box 1isize as Box; | ^^^^^ expected trait T, found struct `std::boxed::Box` | = note: expected type `dyn T` @@ -47,5 +51,5 @@ LL | let box box x = box 1isize as Box; error: aborting due to 6 previous errors -Some errors occurred: E0033, E0308. +Some errors have detailed explanations: E0033, E0308. For more information about an error, try `rustc --explain E0033`. diff --git a/src/test/ui/did_you_mean/E0178.rs b/src/test/ui/did_you_mean/E0178.rs index aad95dc2c20e0..095df640c38f2 100644 --- a/src/test/ui/did_you_mean/E0178.rs +++ b/src/test/ui/did_you_mean/E0178.rs @@ -1,3 +1,5 @@ +#![allow(bare_trait_objects)] + trait Foo {} struct Bar<'a> { diff --git a/src/test/ui/did_you_mean/E0178.stderr b/src/test/ui/did_you_mean/E0178.stderr index ad9bb57c922a3..58ac6e90823f6 100644 --- a/src/test/ui/did_you_mean/E0178.stderr +++ b/src/test/ui/did_you_mean/E0178.stderr @@ -1,25 +1,25 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` - --> $DIR/E0178.rs:4:8 + --> $DIR/E0178.rs:6:8 | -LL | w: &'a Foo + Copy, //~ ERROR expected a path +LL | w: &'a Foo + Copy, | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Copy)` error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` - --> $DIR/E0178.rs:5:8 + --> $DIR/E0178.rs:7:8 | -LL | x: &'a Foo + 'a, //~ ERROR expected a path +LL | x: &'a Foo + 'a, | ^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + 'a)` error[E0178]: expected a path on the left-hand side of `+`, not `&'a mut Foo` - --> $DIR/E0178.rs:6:8 + --> $DIR/E0178.rs:8:8 | -LL | y: &'a mut Foo + 'a, //~ ERROR expected a path +LL | y: &'a mut Foo + 'a, | ^^^^^^^^^^^^^^^^ help: try adding parentheses: `&'a mut (Foo + 'a)` error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> Foo` - --> $DIR/E0178.rs:7:8 + --> $DIR/E0178.rs:9:8 | -LL | z: fn() -> Foo + 'a, //~ ERROR expected a path +LL | z: fn() -> Foo + 'a, | ^^^^^^^^^^^^^^^^ perhaps you forgot parentheses? error: aborting due to 4 previous errors diff --git a/src/test/ui/did_you_mean/bad-assoc-expr.rs b/src/test/ui/did_you_mean/bad-assoc-expr.rs index 2e13db17d8271..1d584757f2faf 100644 --- a/src/test/ui/did_you_mean/bad-assoc-expr.rs +++ b/src/test/ui/did_you_mean/bad-assoc-expr.rs @@ -18,3 +18,19 @@ fn main() { 10 + (u8)::clone(&0); //~^ ERROR missing angle brackets in associated item path } + +macro_rules! expr { + ($ty: ty) => ($ty::clone(&0)) + //~^ ERROR missing angle brackets in associated item path +} +macro_rules! ty { + () => (u8) +} + +fn check_macros() { + expr!(u8); + let _ = ty!()::clone(&0); + //~^ ERROR missing angle brackets in associated item path + ty!()::clone(&0); + //~^ ERROR missing angle brackets in associated item path +} diff --git a/src/test/ui/did_you_mean/bad-assoc-expr.stderr b/src/test/ui/did_you_mean/bad-assoc-expr.stderr index e1eceabcc30af..2024564b911f6 100644 --- a/src/test/ui/did_you_mean/bad-assoc-expr.stderr +++ b/src/test/ui/did_you_mean/bad-assoc-expr.stderr @@ -34,5 +34,26 @@ error: missing angle brackets in associated item path LL | 10 + (u8)::clone(&0); | ^^^^^^^^^^^ help: try: `<(u8)>::clone` -error: aborting due to 6 previous errors +error: missing angle brackets in associated item path + --> $DIR/bad-assoc-expr.rs:32:13 + | +LL | let _ = ty!()::clone(&0); + | ^^^^^^^^^^^^ help: try: `::clone` + +error: missing angle brackets in associated item path + --> $DIR/bad-assoc-expr.rs:34:5 + | +LL | ty!()::clone(&0); + | ^^^^^^^^^^^^ help: try: `::clone` + +error: missing angle brackets in associated item path + --> $DIR/bad-assoc-expr.rs:23:19 + | +LL | ($ty: ty) => ($ty::clone(&0)) + | ^^^^^^^^^^ help: try: `<$ty>::clone` +... +LL | expr!(u8); + | ---------- in this macro invocation + +error: aborting due to 9 previous errors diff --git a/src/test/ui/did_you_mean/bad-assoc-pat.rs b/src/test/ui/did_you_mean/bad-assoc-pat.rs index 5bd2f1a894e82..7e7ba59dca816 100644 --- a/src/test/ui/did_you_mean/bad-assoc-pat.rs +++ b/src/test/ui/did_you_mean/bad-assoc-pat.rs @@ -16,3 +16,21 @@ fn main() { //~| ERROR no associated item named `AssocItem` found for type `(u8,)` in the current scope } } + +macro_rules! pat { + ($ty: ty) => ($ty::AssocItem) + //~^ ERROR missing angle brackets in associated item path + //~| ERROR no associated item named `AssocItem` found for type `u8` in the current scope +} +macro_rules! ty { + () => (u8) +} + +fn check_macros() { + match 0u8 { + pat!(u8) => {} + ty!()::AssocItem => {} + //~^ ERROR missing angle brackets in associated item path + //~| ERROR no associated item named `AssocItem` found for type `u8` in the current scope + } +} diff --git a/src/test/ui/did_you_mean/bad-assoc-pat.stderr b/src/test/ui/did_you_mean/bad-assoc-pat.stderr index 92fd9f26777f1..59b865437a2e0 100644 --- a/src/test/ui/did_you_mean/bad-assoc-pat.stderr +++ b/src/test/ui/did_you_mean/bad-assoc-pat.stderr @@ -22,38 +22,60 @@ error: missing angle brackets in associated item path LL | &(u8,)::AssocItem => {} | ^^^^^^^^^^^^^^^^ help: try: `<(u8,)>::AssocItem` +error: missing angle brackets in associated item path + --> $DIR/bad-assoc-pat.rs:32:9 + | +LL | ty!()::AssocItem => {} + | ^^^^^^^^^^^^^^^^ help: try: `::AssocItem` + +error: missing angle brackets in associated item path + --> $DIR/bad-assoc-pat.rs:21:19 + | +LL | ($ty: ty) => ($ty::AssocItem) + | ^^^^^^^^^^^^^^ help: try: `<$ty>::AssocItem` +... +LL | pat!(u8) => {} + | -------- in this macro invocation + error[E0599]: no associated item named `AssocItem` found for type `[u8]` in the current scope --> $DIR/bad-assoc-pat.rs:3:15 | LL | [u8]::AssocItem => {} - | ------^^^^^^^^^ - | | - | associated item not found in `[u8]` + | ^^^^^^^^^ associated item not found in `[u8]` error[E0599]: no associated item named `AssocItem` found for type `(u8, u8)` in the current scope --> $DIR/bad-assoc-pat.rs:6:19 | LL | (u8, u8)::AssocItem => {} - | ----------^^^^^^^^^ - | | - | associated item not found in `(u8, u8)` + | ^^^^^^^^^ associated item not found in `(u8, u8)` error[E0599]: no associated item named `AssocItem` found for type `_` in the current scope --> $DIR/bad-assoc-pat.rs:9:12 | LL | _::AssocItem => {} - | ---^^^^^^^^^ - | | - | associated item not found in `_` + | ^^^^^^^^^ associated item not found in `_` error[E0599]: no associated item named `AssocItem` found for type `(u8,)` in the current scope --> $DIR/bad-assoc-pat.rs:14:17 | LL | &(u8,)::AssocItem => {} - | -------^^^^^^^^^ - | | - | associated item not found in `(u8,)` + | ^^^^^^^^^ associated item not found in `(u8,)` + +error[E0599]: no associated item named `AssocItem` found for type `u8` in the current scope + --> $DIR/bad-assoc-pat.rs:21:24 + | +LL | ($ty: ty) => ($ty::AssocItem) + | ^^^^^^^^^ associated item not found in `u8` +... +LL | pat!(u8) => {} + | -------- in this macro invocation + +error[E0599]: no associated item named `AssocItem` found for type `u8` in the current scope + --> $DIR/bad-assoc-pat.rs:32:16 + | +LL | ty!()::AssocItem => {} + | ^^^^^^^^^ associated item not found in `u8` -error: aborting due to 8 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs index 436bda1547be9..fccfb7911cecf 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.rs +++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs @@ -24,7 +24,7 @@ type F = &'static (u8)::AssocTy; // Qualified paths cannot appear in bounds, so the recovery // should apply to the whole sum and not `(Send)`. -type G = 'static + (Send)::AssocTy; +type G = dyn 'static + (Send)::AssocTy; //~^ ERROR missing angle brackets in associated item path //~| ERROR ambiguous associated type @@ -33,4 +33,16 @@ type G = 'static + (Send)::AssocTy; type H = Fn(u8) -> (u8)::Output; //~^ ERROR ambiguous associated type +macro_rules! ty { + ($ty: ty) => ($ty::AssocTy); + //~^ ERROR missing angle brackets in associated item path + //~| ERROR ambiguous associated type + () => (u8); +} + +type J = ty!(u8); +type I = ty!()::AssocTy; +//~^ ERROR missing angle brackets in associated item path +//~| ERROR ambiguous associated type + fn main() {} diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr index a9dcc831ba7d5..0ae64edcc0546 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr +++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr @@ -37,8 +37,23 @@ LL | type F = &'static (u8)::AssocTy; error: missing angle brackets in associated item path --> $DIR/bad-assoc-ty.rs:27:10 | -LL | type G = 'static + (Send)::AssocTy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `<'static + Send>::AssocTy` +LL | type G = dyn 'static + (Send)::AssocTy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `::AssocTy` + +error: missing angle brackets in associated item path + --> $DIR/bad-assoc-ty.rs:44:10 + | +LL | type I = ty!()::AssocTy; + | ^^^^^^^^^^^^^^ help: try: `::AssocTy` + +error: missing angle brackets in associated item path + --> $DIR/bad-assoc-ty.rs:37:19 + | +LL | ($ty: ty) => ($ty::AssocTy); + | ^^^^^^^^^^^^ help: try: `<$ty>::AssocTy` +... +LL | type J = ty!(u8); + | ------- in this macro invocation error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:1:10 @@ -79,8 +94,8 @@ LL | type F = &'static (u8)::AssocTy; error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:27:10 | -LL | type G = 'static + (Send)::AssocTy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn std::marker::Send + 'static) as Trait>::AssocTy` +LL | type G = dyn 'static + (Send)::AssocTy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn std::marker::Send + 'static) as Trait>::AssocTy` error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:33:10 @@ -88,7 +103,22 @@ error[E0223]: ambiguous associated type LL | type H = Fn(u8) -> (u8)::Output; | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn std::ops::Fn(u8) -> u8 + 'static) as Trait>::Output` -error: aborting due to 15 previous errors +error[E0223]: ambiguous associated type + --> $DIR/bad-assoc-ty.rs:37:19 + | +LL | ($ty: ty) => ($ty::AssocTy); + | ^^^^^^^^^^^^ help: use fully-qualified syntax: `::AssocTy` +... +LL | type J = ty!(u8); + | ------- in this macro invocation + +error[E0223]: ambiguous associated type + --> $DIR/bad-assoc-ty.rs:44:10 + | +LL | type I = ty!()::AssocTy; + | ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::AssocTy` + +error: aborting due to 19 previous errors -Some errors occurred: E0121, E0223. +Some errors have detailed explanations: E0121, E0223. For more information about an error, try `rustc --explain E0121`. diff --git a/src/test/ui/did_you_mean/issue-31424.nll.stderr b/src/test/ui/did_you_mean/issue-31424.nll.stderr deleted file mode 100644 index 91368dded3758..0000000000000 --- a/src/test/ui/did_you_mean/issue-31424.nll.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable - --> $DIR/issue-31424.rs:7:9 - | -LL | (&mut self).bar(); //~ ERROR cannot borrow - | ^^^^^^^^^^^ - | | - | cannot borrow as mutable - | try removing `&mut` here - -warning: function cannot return without recursing - --> $DIR/issue-31424.rs:12:5 - | -LL | fn bar(self: &mut Self) { - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing -LL | //~^ WARN function cannot return without recursing -LL | (&mut self).bar(); //~ ERROR cannot borrow - | ----------------- recursive call site - | - = note: #[warn(unconditional_recursion)] on by default - = help: a `loop` may express intention better if this is on purpose - -error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable - --> $DIR/issue-31424.rs:14:9 - | -LL | (&mut self).bar(); //~ ERROR cannot borrow - | ^^^^^^^^^^^ - | | - | cannot borrow as mutable - | try removing `&mut` here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-31424.stderr b/src/test/ui/did_you_mean/issue-31424.stderr index 1442666ef66a5..147225f1be59e 100644 --- a/src/test/ui/did_you_mean/issue-31424.stderr +++ b/src/test/ui/did_you_mean/issue-31424.stderr @@ -1,33 +1,32 @@ -error[E0596]: cannot borrow immutable argument `self` as mutable - --> $DIR/issue-31424.rs:7:15 +error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable + --> $DIR/issue-31424.rs:7:9 | -LL | (&mut self).bar(); //~ ERROR cannot borrow - | ^^^^ - | | - | cannot reborrow mutably - | try removing `&mut` here +LL | (&mut self).bar(); + | ^^^^^^^^^^^ + | | + | cannot borrow as mutable + | try removing `&mut` here warning: function cannot return without recursing --> $DIR/issue-31424.rs:12:5 | LL | fn bar(self: &mut Self) { | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing -LL | //~^ WARN function cannot return without recursing -LL | (&mut self).bar(); //~ ERROR cannot borrow +LL | +LL | (&mut self).bar(); | ----------------- recursive call site | = note: #[warn(unconditional_recursion)] on by default = help: a `loop` may express intention better if this is on purpose -error[E0596]: cannot borrow immutable argument `self` as mutable - --> $DIR/issue-31424.rs:14:15 +error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable + --> $DIR/issue-31424.rs:14:9 | -LL | (&mut self).bar(); //~ ERROR cannot borrow - | ^^^^ cannot borrow mutably -help: consider removing the `&mut`, as it is an immutable binding to a mutable reference - | -LL | self.bar(); //~ ERROR cannot borrow - | ^^^^ +LL | (&mut self).bar(); + | ^^^^^^^^^^^ + | | + | cannot borrow as mutable + | try removing `&mut` here error: aborting due to 2 previous errors diff --git a/src/test/ui/did_you_mean/issue-34126.nll.stderr b/src/test/ui/did_you_mean/issue-34126.nll.stderr deleted file mode 100644 index ed73cca435fd0..0000000000000 --- a/src/test/ui/did_you_mean/issue-34126.nll.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable - --> $DIR/issue-34126.rs:6:18 - | -LL | self.run(&mut self); //~ ERROR cannot borrow - | ^^^^^^^^^ - | | - | cannot borrow as mutable - | try removing `&mut` here - -error[E0502]: cannot borrow `self` as mutable because it is also borrowed as immutable - --> $DIR/issue-34126.rs:6:18 - | -LL | self.run(&mut self); //~ ERROR cannot borrow - | ---- --- ^^^^^^^^^ mutable borrow occurs here - | | | - | | immutable borrow later used by call - | immutable borrow occurs here - -error: aborting due to 2 previous errors - -Some errors occurred: E0502, E0596. -For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/did_you_mean/issue-34126.rs b/src/test/ui/did_you_mean/issue-34126.rs index 15bef1ef815d6..4989577dbb68f 100644 --- a/src/test/ui/did_you_mean/issue-34126.rs +++ b/src/test/ui/did_you_mean/issue-34126.rs @@ -4,6 +4,7 @@ impl Z { fn run(&self, z: &mut Z) { } fn start(&mut self) { self.run(&mut self); //~ ERROR cannot borrow + //~| ERROR cannot borrow } } diff --git a/src/test/ui/did_you_mean/issue-34126.stderr b/src/test/ui/did_you_mean/issue-34126.stderr index 05ea4ef91ce49..0843df29b5c46 100644 --- a/src/test/ui/did_you_mean/issue-34126.stderr +++ b/src/test/ui/did_you_mean/issue-34126.stderr @@ -1,12 +1,22 @@ -error[E0596]: cannot borrow immutable argument `self` as mutable - --> $DIR/issue-34126.rs:6:23 +error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable + --> $DIR/issue-34126.rs:6:18 | -LL | self.run(&mut self); //~ ERROR cannot borrow - | ^^^^ - | | - | cannot reborrow mutably - | try removing `&mut` here +LL | self.run(&mut self); + | ^^^^^^^^^ + | | + | cannot borrow as mutable + | try removing `&mut` here -error: aborting due to previous error +error[E0502]: cannot borrow `self` as mutable because it is also borrowed as immutable + --> $DIR/issue-34126.rs:6:18 + | +LL | self.run(&mut self); + | ---- --- ^^^^^^^^^ mutable borrow occurs here + | | | + | | immutable borrow later used by call + | immutable borrow occurs here + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0502, E0596. +For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/did_you_mean/issue-34337.nll.stderr b/src/test/ui/did_you_mean/issue-34337.nll.stderr deleted file mode 100644 index 5e46889866d4d..0000000000000 --- a/src/test/ui/did_you_mean/issue-34337.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0596]: cannot borrow `key` as mutable, as it is not declared as mutable - --> $DIR/issue-34337.rs:6:9 - | -LL | get(&mut key); //~ ERROR cannot borrow - | ^^^^^^^^ - | | - | cannot borrow as mutable - | try removing `&mut` here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-34337.stderr b/src/test/ui/did_you_mean/issue-34337.stderr index 4bf988b72cd00..81f7b6dbf1b21 100644 --- a/src/test/ui/did_you_mean/issue-34337.stderr +++ b/src/test/ui/did_you_mean/issue-34337.stderr @@ -1,11 +1,11 @@ -error[E0596]: cannot borrow immutable local variable `key` as mutable - --> $DIR/issue-34337.rs:6:14 +error[E0596]: cannot borrow `key` as mutable, as it is not declared as mutable + --> $DIR/issue-34337.rs:6:9 | -LL | get(&mut key); //~ ERROR cannot borrow - | ^^^ - | | - | cannot reborrow mutably - | try removing `&mut` here +LL | get(&mut key); + | ^^^^^^^^ + | | + | cannot borrow as mutable + | try removing `&mut` here error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/issue-35937.nll.stderr b/src/test/ui/did_you_mean/issue-35937.nll.stderr deleted file mode 100644 index 76fb1e229536d..0000000000000 --- a/src/test/ui/did_you_mean/issue-35937.nll.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error[E0596]: cannot borrow `f.v` as mutable, as `f` is not declared as mutable - --> $DIR/issue-35937.rs:7:5 - | -LL | let f = Foo { v: Vec::new() }; - | - help: consider changing this to be mutable: `mut f` -LL | f.v.push("cat".to_string()); //~ ERROR cannot borrow - | ^^^ cannot borrow as mutable - -error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable - --> $DIR/issue-35937.rs:16:5 - | -LL | let s = S { x: 42 }; - | - help: consider changing this to be mutable: `mut s` -LL | s.x += 1; //~ ERROR cannot assign - | ^^^^^^^^ cannot assign - -error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable - --> $DIR/issue-35937.rs:20:5 - | -LL | fn bar(s: S) { - | - help: consider changing this to be mutable: `mut s` -LL | s.x += 1; //~ ERROR cannot assign - | ^^^^^^^^ cannot assign - -error: aborting due to 3 previous errors - -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/did_you_mean/issue-35937.stderr b/src/test/ui/did_you_mean/issue-35937.stderr index 7499a9475e889..4f9b6a6134dc8 100644 --- a/src/test/ui/did_you_mean/issue-35937.stderr +++ b/src/test/ui/did_you_mean/issue-35937.stderr @@ -1,28 +1,27 @@ -error[E0596]: cannot borrow field `f.v` of immutable binding as mutable +error[E0596]: cannot borrow `f.v` as mutable, as `f` is not declared as mutable --> $DIR/issue-35937.rs:7:5 | LL | let f = Foo { v: Vec::new() }; - | - help: make this binding mutable: `mut f` -LL | f.v.push("cat".to_string()); //~ ERROR cannot borrow - | ^^^ cannot mutably borrow field of immutable binding + | - help: consider changing this to be mutable: `mut f` +LL | f.v.push("cat".to_string()); + | ^^^ cannot borrow as mutable -error[E0594]: cannot assign to field `s.x` of immutable binding +error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable --> $DIR/issue-35937.rs:16:5 | LL | let s = S { x: 42 }; - | - help: make this binding mutable: `mut s` -LL | s.x += 1; //~ ERROR cannot assign - | ^^^^^^^^ cannot mutably borrow field of immutable binding + | - help: consider changing this to be mutable: `mut s` +LL | s.x += 1; + | ^^^^^^^^ cannot assign -error[E0594]: cannot assign to field `s.x` of immutable binding +error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable --> $DIR/issue-35937.rs:20:5 | LL | fn bar(s: S) { - | - help: make this binding mutable: `mut s` -LL | s.x += 1; //~ ERROR cannot assign - | ^^^^^^^^ cannot mutably borrow field of immutable binding + | - help: consider changing this to be mutable: `mut s` +LL | s.x += 1; + | ^^^^^^^^ cannot assign error: aborting due to 3 previous errors -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-36798.stderr b/src/test/ui/did_you_mean/issue-36798.stderr index 8273fad476462..98876e305ca09 100644 --- a/src/test/ui/did_you_mean/issue-36798.stderr +++ b/src/test/ui/did_you_mean/issue-36798.stderr @@ -1,7 +1,7 @@ error[E0609]: no field `baz` on type `Foo` --> $DIR/issue-36798.rs:7:7 | -LL | f.baz; //~ ERROR no field +LL | f.baz; | ^^^ help: a field with a similar name exists: `bar` error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr b/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr index b884d8a53d358..2ed0a09240062 100644 --- a/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr +++ b/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr @@ -1,7 +1,7 @@ error[E0609]: no field `zz` on type `Foo` --> $DIR/issue-36798_unknown_field.rs:7:7 | -LL | f.zz; //~ ERROR no field +LL | f.zz; | ^^ unknown field | = note: available fields are: `bar` diff --git a/src/test/ui/did_you_mean/issue-37139.nll.stderr b/src/test/ui/did_you_mean/issue-37139.nll.stderr deleted file mode 100644 index 4d1c8a6b0eb18..0000000000000 --- a/src/test/ui/did_you_mean/issue-37139.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/issue-37139.rs:12:18 - | -LL | test(&mut x); //~ ERROR cannot borrow immutable - | ^^^^^^ - | | - | cannot borrow as mutable - | try removing `&mut` here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-37139.rs b/src/test/ui/did_you_mean/issue-37139.rs index b7f419ae4a644..07d855d0969f3 100644 --- a/src/test/ui/did_you_mean/issue-37139.rs +++ b/src/test/ui/did_you_mean/issue-37139.rs @@ -9,7 +9,7 @@ fn main() { let mut x = TestEnum::Item(10); match x { TestEnum::Item(ref mut x) => { - test(&mut x); //~ ERROR cannot borrow immutable + test(&mut x); //~ ERROR cannot borrow `x` as mutable, as it is not declared as mutable } } } diff --git a/src/test/ui/did_you_mean/issue-37139.stderr b/src/test/ui/did_you_mean/issue-37139.stderr index 38617fda2afac..163817dd9bf58 100644 --- a/src/test/ui/did_you_mean/issue-37139.stderr +++ b/src/test/ui/did_you_mean/issue-37139.stderr @@ -1,11 +1,11 @@ -error[E0596]: cannot borrow immutable local variable `x` as mutable - --> $DIR/issue-37139.rs:12:23 +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/issue-37139.rs:12:18 | -LL | test(&mut x); //~ ERROR cannot borrow immutable - | ^ - | | - | cannot reborrow mutably - | try removing `&mut` here +LL | test(&mut x); + | ^^^^^^ + | | + | cannot borrow as mutable + | try removing `&mut` here error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/issue-38054-do-not-show-unresolved-names.stderr b/src/test/ui/did_you_mean/issue-38054-do-not-show-unresolved-names.stderr index 1f3f7c475707a..852abaed724dc 100644 --- a/src/test/ui/did_you_mean/issue-38054-do-not-show-unresolved-names.stderr +++ b/src/test/ui/did_you_mean/issue-38054-do-not-show-unresolved-names.stderr @@ -1,13 +1,13 @@ error[E0432]: unresolved import `Foo` --> $DIR/issue-38054-do-not-show-unresolved-names.rs:1:5 | -LL | use Foo; //~ ERROR unresolved +LL | use Foo; | ^^^ no `Foo` in the root error[E0432]: unresolved import `Foo1` --> $DIR/issue-38054-do-not-show-unresolved-names.rs:3:5 | -LL | use Foo1; //~ ERROR unresolved +LL | use Foo1; | ^^^^ no `Foo1` in the root error: aborting due to 2 previous errors diff --git a/src/test/ui/did_you_mean/issue-38147-1.nll.stderr b/src/test/ui/did_you_mean/issue-38147-1.nll.stderr deleted file mode 100644 index 838673b21d1ec..0000000000000 --- a/src/test/ui/did_you_mean/issue-38147-1.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference - --> $DIR/issue-38147-1.rs:17:9 - | -LL | fn f(&self) { - | ----- help: consider changing this to be a mutable reference: `&mut self` -LL | self.s.push('x'); //~ ERROR cannot borrow data mutably - | ^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-38147-1.rs b/src/test/ui/did_you_mean/issue-38147-1.rs index b67239619d979..c068a1834f350 100644 --- a/src/test/ui/did_you_mean/issue-38147-1.rs +++ b/src/test/ui/did_you_mean/issue-38147-1.rs @@ -14,7 +14,7 @@ struct Foo<'a> { impl<'a> Foo<'a> { fn f(&self) { - self.s.push('x'); //~ ERROR cannot borrow data mutably + self.s.push('x'); //~ cannot borrow `*self.s` as mutable, as it is behind a `&` reference } } diff --git a/src/test/ui/did_you_mean/issue-38147-1.stderr b/src/test/ui/did_you_mean/issue-38147-1.stderr index 74c72edd028b0..6efac371c028e 100644 --- a/src/test/ui/did_you_mean/issue-38147-1.stderr +++ b/src/test/ui/did_you_mean/issue-38147-1.stderr @@ -1,11 +1,11 @@ -error[E0389]: cannot borrow data mutably in a `&` reference +error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference --> $DIR/issue-38147-1.rs:17:9 | LL | fn f(&self) { - | ----- use `&mut self` here to make mutable -LL | self.s.push('x'); //~ ERROR cannot borrow data mutably - | ^^^^^^ assignment into an immutable reference + | ----- help: consider changing this to be a mutable reference: `&mut self` +LL | self.s.push('x'); + | ^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error -For more information about this error, try `rustc --explain E0389`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-38147-2.nll.stderr b/src/test/ui/did_you_mean/issue-38147-2.nll.stderr deleted file mode 100644 index cb4981089310a..0000000000000 --- a/src/test/ui/did_you_mean/issue-38147-2.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference - --> $DIR/issue-38147-2.rs:7:9 - | -LL | s: &'a String - | ---------- help: consider changing this to be mutable: `&'a mut String` -... -LL | self.s.push('x'); - | ^^^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-38147-2.rs b/src/test/ui/did_you_mean/issue-38147-2.rs index e43ebf9d26142..fe2634d88abf4 100644 --- a/src/test/ui/did_you_mean/issue-38147-2.rs +++ b/src/test/ui/did_you_mean/issue-38147-2.rs @@ -5,7 +5,7 @@ struct Bar<'a> { impl<'a> Bar<'a> { fn f(&mut self) { self.s.push('x'); - //~^ ERROR cannot borrow borrowed content `*self.s` of immutable binding as mutable + //~^ ERROR cannot borrow `*self.s` as mutable, as it is behind a `&` reference } } diff --git a/src/test/ui/did_you_mean/issue-38147-2.stderr b/src/test/ui/did_you_mean/issue-38147-2.stderr index fa4fccb8d2775..cb4981089310a 100644 --- a/src/test/ui/did_you_mean/issue-38147-2.stderr +++ b/src/test/ui/did_you_mean/issue-38147-2.stderr @@ -1,8 +1,8 @@ -error[E0596]: cannot borrow borrowed content `*self.s` of immutable binding as mutable +error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference --> $DIR/issue-38147-2.rs:7:9 | LL | s: &'a String - | ---------- use `&'a mut String` here to make mutable + | ---------- help: consider changing this to be mutable: `&'a mut String` ... LL | self.s.push('x'); | ^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/did_you_mean/issue-38147-3.nll.stderr b/src/test/ui/did_you_mean/issue-38147-3.nll.stderr deleted file mode 100644 index 67782578a2c64..0000000000000 --- a/src/test/ui/did_you_mean/issue-38147-3.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference - --> $DIR/issue-38147-3.rs:7:9 - | -LL | s: &'a String - | ---------- help: consider changing this to be mutable: `&'a mut String` -... -LL | self.s.push('x'); - | ^^^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-38147-3.rs b/src/test/ui/did_you_mean/issue-38147-3.rs index 4cd703f2f61f0..40b8e0dba26a3 100644 --- a/src/test/ui/did_you_mean/issue-38147-3.rs +++ b/src/test/ui/did_you_mean/issue-38147-3.rs @@ -5,7 +5,7 @@ struct Qux<'a> { impl<'a> Qux<'a> { fn f(&self) { self.s.push('x'); - //~^ ERROR cannot borrow borrowed content `*self.s` of immutable binding as mutable + //~^ ERROR cannot borrow `*self.s` as mutable, as it is behind a `&` reference } } diff --git a/src/test/ui/did_you_mean/issue-38147-3.stderr b/src/test/ui/did_you_mean/issue-38147-3.stderr index 2cb9835278db1..67782578a2c64 100644 --- a/src/test/ui/did_you_mean/issue-38147-3.stderr +++ b/src/test/ui/did_you_mean/issue-38147-3.stderr @@ -1,8 +1,8 @@ -error[E0596]: cannot borrow borrowed content `*self.s` of immutable binding as mutable +error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference --> $DIR/issue-38147-3.rs:7:9 | LL | s: &'a String - | ---------- use `&'a mut String` here to make mutable + | ---------- help: consider changing this to be mutable: `&'a mut String` ... LL | self.s.push('x'); | ^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/did_you_mean/issue-38147-4.nll.stderr b/src/test/ui/did_you_mean/issue-38147-4.nll.stderr deleted file mode 100644 index 458e41f6aae7c..0000000000000 --- a/src/test/ui/did_you_mean/issue-38147-4.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `*f.s` as mutable, as it is behind a `&` reference - --> $DIR/issue-38147-4.rs:6:5 - | -LL | fn f(x: usize, f: &Foo) { - | ---- help: consider changing this to be a mutable reference: `&mut Foo<'_>` -LL | f.s.push('x'); //~ ERROR cannot borrow data mutably - | ^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-38147-4.rs b/src/test/ui/did_you_mean/issue-38147-4.rs index 26573d4fddeb6..e2028a9e67bca 100644 --- a/src/test/ui/did_you_mean/issue-38147-4.rs +++ b/src/test/ui/did_you_mean/issue-38147-4.rs @@ -3,7 +3,7 @@ struct Foo<'a> { } fn f(x: usize, f: &Foo) { - f.s.push('x'); //~ ERROR cannot borrow data mutably + f.s.push('x'); //~ ERROR cannot borrow `*f.s` as mutable, as it is behind a `&` reference } fn main() {} diff --git a/src/test/ui/did_you_mean/issue-38147-4.stderr b/src/test/ui/did_you_mean/issue-38147-4.stderr index 6dc4f101084b5..db3e6b8942646 100644 --- a/src/test/ui/did_you_mean/issue-38147-4.stderr +++ b/src/test/ui/did_you_mean/issue-38147-4.stderr @@ -1,11 +1,11 @@ -error[E0389]: cannot borrow data mutably in a `&` reference +error[E0596]: cannot borrow `*f.s` as mutable, as it is behind a `&` reference --> $DIR/issue-38147-4.rs:6:5 | LL | fn f(x: usize, f: &Foo) { - | ---- use `&mut Foo` here to make mutable -LL | f.s.push('x'); //~ ERROR cannot borrow data mutably - | ^^^ assignment into an immutable reference + | ---- help: consider changing this to be a mutable reference: `&mut Foo<'_>` +LL | f.s.push('x'); + | ^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error -For more information about this error, try `rustc --explain E0389`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-39544.nll.stderr b/src/test/ui/did_you_mean/issue-39544.nll.stderr deleted file mode 100644 index 2fb8e3db68cbe..0000000000000 --- a/src/test/ui/did_you_mean/issue-39544.nll.stderr +++ /dev/null @@ -1,102 +0,0 @@ -error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable - --> $DIR/issue-39544.rs:11:13 - | -LL | let z = Z { x: X::Y }; - | - help: consider changing this to be mutable: `mut z` -LL | let _ = &mut z.x; //~ ERROR cannot borrow - | ^^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference - --> $DIR/issue-39544.rs:16:17 - | -LL | fn foo<'z>(&'z self) { - | -------- help: consider changing this to be a mutable reference: `&'z mut self` -LL | let _ = &mut self.x; //~ ERROR cannot borrow - | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference - --> $DIR/issue-39544.rs:20:17 - | -LL | fn foo1(&self, other: &Z) { - | ----- help: consider changing this to be a mutable reference: `&mut self` -LL | let _ = &mut self.x; //~ ERROR cannot borrow - | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference - --> $DIR/issue-39544.rs:21:17 - | -LL | fn foo1(&self, other: &Z) { - | -- help: consider changing this to be a mutable reference: `&mut Z` -LL | let _ = &mut self.x; //~ ERROR cannot borrow -LL | let _ = &mut other.x; //~ ERROR cannot borrow - | ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference - --> $DIR/issue-39544.rs:25:17 - | -LL | fn foo2<'a>(&'a self, other: &Z) { - | -------- help: consider changing this to be a mutable reference: `&'a mut self` -LL | let _ = &mut self.x; //~ ERROR cannot borrow - | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference - --> $DIR/issue-39544.rs:26:17 - | -LL | fn foo2<'a>(&'a self, other: &Z) { - | -- help: consider changing this to be a mutable reference: `&mut Z` -LL | let _ = &mut self.x; //~ ERROR cannot borrow -LL | let _ = &mut other.x; //~ ERROR cannot borrow - | ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference - --> $DIR/issue-39544.rs:30:17 - | -LL | fn foo3<'a>(self: &'a Self, other: &Z) { - | -------- help: consider changing this to be a mutable reference: `&'a mut Self` -LL | let _ = &mut self.x; //~ ERROR cannot borrow - | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference - --> $DIR/issue-39544.rs:31:17 - | -LL | fn foo3<'a>(self: &'a Self, other: &Z) { - | -- help: consider changing this to be a mutable reference: `&mut Z` -LL | let _ = &mut self.x; //~ ERROR cannot borrow -LL | let _ = &mut other.x; //~ ERROR cannot borrow - | ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference - --> $DIR/issue-39544.rs:35:17 - | -LL | fn foo4(other: &Z) { - | -- help: consider changing this to be a mutable reference: `&mut Z` -LL | let _ = &mut other.x; //~ ERROR cannot borrow - | ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable - --> $DIR/issue-39544.rs:41:13 - | -LL | pub fn with_arg(z: Z, w: &Z) { - | - help: consider changing this to be mutable: `mut z` -LL | let _ = &mut z.x; //~ ERROR cannot borrow - | ^^^^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `w.x` as mutable, as it is behind a `&` reference - --> $DIR/issue-39544.rs:42:13 - | -LL | pub fn with_arg(z: Z, w: &Z) { - | -- help: consider changing this to be a mutable reference: `&mut Z` -LL | let _ = &mut z.x; //~ ERROR cannot borrow -LL | let _ = &mut w.x; //~ ERROR cannot borrow - | ^^^^^^^^ `w` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0594]: cannot assign to `*x.0` which is behind a `&` reference - --> $DIR/issue-39544.rs:48:5 - | -LL | *x.0 = 1; - | ^^^^^^^^ cannot assign - -error: aborting due to 12 previous errors - -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs index 89696a06aaae8..3c86f29a89c30 100644 --- a/src/test/ui/did_you_mean/issue-39544.rs +++ b/src/test/ui/did_you_mean/issue-39544.rs @@ -46,5 +46,5 @@ pub fn with_tuple() { let mut y = 0; let x = (&y,); *x.0 = 1; - //~^ ERROR cannot assign to borrowed content `*x.0` of immutable binding + //~^ ERROR cannot assign to `*x.0` which is behind a `&` reference } diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index 7d6a672843a27..dfaaf6b17dc31 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -1,102 +1,101 @@ -error[E0596]: cannot borrow field `z.x` of immutable binding as mutable - --> $DIR/issue-39544.rs:11:18 +error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable + --> $DIR/issue-39544.rs:11:13 | LL | let z = Z { x: X::Y }; - | - help: make this binding mutable: `mut z` -LL | let _ = &mut z.x; //~ ERROR cannot borrow - | ^^^ cannot mutably borrow field of immutable binding + | - help: consider changing this to be mutable: `mut z` +LL | let _ = &mut z.x; + | ^^^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow field `self.x` of immutable binding as mutable - --> $DIR/issue-39544.rs:16:22 +error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference + --> $DIR/issue-39544.rs:16:17 | LL | fn foo<'z>(&'z self) { - | -------- use `&'z mut self` here to make mutable -LL | let _ = &mut self.x; //~ ERROR cannot borrow - | ^^^^^^ cannot mutably borrow field of immutable binding + | -------- help: consider changing this to be a mutable reference: `&'z mut self` +LL | let _ = &mut self.x; + | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow field `self.x` of immutable binding as mutable - --> $DIR/issue-39544.rs:20:22 +error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference + --> $DIR/issue-39544.rs:20:17 | LL | fn foo1(&self, other: &Z) { - | ----- use `&mut self` here to make mutable -LL | let _ = &mut self.x; //~ ERROR cannot borrow - | ^^^^^^ cannot mutably borrow field of immutable binding + | ----- help: consider changing this to be a mutable reference: `&mut self` +LL | let _ = &mut self.x; + | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow field `other.x` of immutable binding as mutable - --> $DIR/issue-39544.rs:21:22 +error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference + --> $DIR/issue-39544.rs:21:17 | LL | fn foo1(&self, other: &Z) { - | -- use `&mut Z` here to make mutable -LL | let _ = &mut self.x; //~ ERROR cannot borrow -LL | let _ = &mut other.x; //~ ERROR cannot borrow - | ^^^^^^^ cannot mutably borrow field of immutable binding + | -- help: consider changing this to be a mutable reference: `&mut Z` +LL | let _ = &mut self.x; +LL | let _ = &mut other.x; + | ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow field `self.x` of immutable binding as mutable - --> $DIR/issue-39544.rs:25:22 +error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference + --> $DIR/issue-39544.rs:25:17 | LL | fn foo2<'a>(&'a self, other: &Z) { - | -------- use `&'a mut self` here to make mutable -LL | let _ = &mut self.x; //~ ERROR cannot borrow - | ^^^^^^ cannot mutably borrow field of immutable binding + | -------- help: consider changing this to be a mutable reference: `&'a mut self` +LL | let _ = &mut self.x; + | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow field `other.x` of immutable binding as mutable - --> $DIR/issue-39544.rs:26:22 +error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference + --> $DIR/issue-39544.rs:26:17 | LL | fn foo2<'a>(&'a self, other: &Z) { - | -- use `&mut Z` here to make mutable -LL | let _ = &mut self.x; //~ ERROR cannot borrow -LL | let _ = &mut other.x; //~ ERROR cannot borrow - | ^^^^^^^ cannot mutably borrow field of immutable binding + | -- help: consider changing this to be a mutable reference: `&mut Z` +LL | let _ = &mut self.x; +LL | let _ = &mut other.x; + | ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow field `self.x` of immutable binding as mutable - --> $DIR/issue-39544.rs:30:22 +error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference + --> $DIR/issue-39544.rs:30:17 | LL | fn foo3<'a>(self: &'a Self, other: &Z) { - | -------- use `&'a mut Self` here to make mutable -LL | let _ = &mut self.x; //~ ERROR cannot borrow - | ^^^^^^ cannot mutably borrow field of immutable binding + | -------- help: consider changing this to be a mutable reference: `&'a mut Self` +LL | let _ = &mut self.x; + | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow field `other.x` of immutable binding as mutable - --> $DIR/issue-39544.rs:31:22 +error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference + --> $DIR/issue-39544.rs:31:17 | LL | fn foo3<'a>(self: &'a Self, other: &Z) { - | -- use `&mut Z` here to make mutable -LL | let _ = &mut self.x; //~ ERROR cannot borrow -LL | let _ = &mut other.x; //~ ERROR cannot borrow - | ^^^^^^^ cannot mutably borrow field of immutable binding + | -- help: consider changing this to be a mutable reference: `&mut Z` +LL | let _ = &mut self.x; +LL | let _ = &mut other.x; + | ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow field `other.x` of immutable binding as mutable - --> $DIR/issue-39544.rs:35:22 +error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference + --> $DIR/issue-39544.rs:35:17 | LL | fn foo4(other: &Z) { - | -- use `&mut Z` here to make mutable -LL | let _ = &mut other.x; //~ ERROR cannot borrow - | ^^^^^^^ cannot mutably borrow field of immutable binding + | -- help: consider changing this to be a mutable reference: `&mut Z` +LL | let _ = &mut other.x; + | ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow field `z.x` of immutable binding as mutable - --> $DIR/issue-39544.rs:41:18 +error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable + --> $DIR/issue-39544.rs:41:13 | LL | pub fn with_arg(z: Z, w: &Z) { - | - help: make this binding mutable: `mut z` -LL | let _ = &mut z.x; //~ ERROR cannot borrow - | ^^^ cannot mutably borrow field of immutable binding + | - help: consider changing this to be mutable: `mut z` +LL | let _ = &mut z.x; + | ^^^^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow field `w.x` of immutable binding as mutable - --> $DIR/issue-39544.rs:42:18 +error[E0596]: cannot borrow `w.x` as mutable, as it is behind a `&` reference + --> $DIR/issue-39544.rs:42:13 | LL | pub fn with_arg(z: Z, w: &Z) { - | -- use `&mut Z` here to make mutable -LL | let _ = &mut z.x; //~ ERROR cannot borrow -LL | let _ = &mut w.x; //~ ERROR cannot borrow - | ^^^ cannot mutably borrow field of immutable binding + | -- help: consider changing this to be a mutable reference: `&mut Z` +LL | let _ = &mut z.x; +LL | let _ = &mut w.x; + | ^^^^^^^^ `w` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0594]: cannot assign to borrowed content `*x.0` of immutable binding +error[E0594]: cannot assign to `*x.0` which is behind a `&` reference --> $DIR/issue-39544.rs:48:5 | LL | *x.0 = 1; - | ^^^^^^^^ cannot borrow as mutable + | ^^^^^^^^ cannot assign error: aborting due to 12 previous errors -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr index 3411958be62a9..cfb1da037dc07 100644 --- a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr +++ b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `i8: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:24:5 | -LL | Foo::::bar(&1i8); //~ ERROR is not satisfied +LL | Foo::::bar(&1i8); | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i8` | = help: the following implementations were found: @@ -19,7 +19,7 @@ LL | fn bar(&self){} error[E0277]: the trait bound `u8: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:25:5 | -LL | Foo::::bar(&1u8); //~ ERROR is not satisfied +LL | Foo::::bar(&1u8); | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u8` | = help: the following implementations were found: @@ -36,7 +36,7 @@ LL | fn bar(&self){} error[E0277]: the trait bound `bool: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:26:5 | -LL | Foo::::bar(&true); //~ ERROR is not satisfied +LL | Foo::::bar(&true); | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `bool` | = help: the following implementations were found: diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs index 75ea02b6a9d4a..a1184f757e2ab 100644 --- a/src/test/ui/did_you_mean/issue-40006.rs +++ b/src/test/ui/did_you_mean/issue-40006.rs @@ -1,4 +1,4 @@ -impl X { //~ ERROR cannot be made into an object +impl dyn X { //~ ERROR cannot be made into an object //~^ ERROR missing Y } diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 1b9eecb7769b3..87e48cd1e1cd9 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -1,16 +1,16 @@ error: missing `fn`, `type`, or `const` for impl-item declaration - --> $DIR/issue-40006.rs:1:9 + --> $DIR/issue-40006.rs:1:13 | -LL | impl X { //~ ERROR cannot be made into an object - | _________^ -LL | | //~^ ERROR missing +LL | impl dyn X { + | _____________^ +LL | | LL | | Y | |____^ missing `fn`, `type`, or `const` error: missing `fn`, `type`, or `const` for trait-item declaration --> $DIR/issue-40006.rs:8:10 | -LL | trait X { //~ ERROR missing +LL | trait X { | __________^ LL | | X() {} | |____^ missing `fn`, `type`, or `const` @@ -18,49 +18,49 @@ LL | | X() {} error: expected `[`, found `#` --> $DIR/issue-40006.rs:10:17 | -LL | fn xxx() { ### } //~ ERROR missing +LL | fn xxx() { ### } | ^ expected `[` error: missing `fn`, `type`, or `const` for trait-item declaration --> $DIR/issue-40006.rs:10:21 | -LL | fn xxx() { ### } //~ ERROR missing +LL | fn xxx() { ### } | _____________________^ -LL | | //~^ ERROR expected -LL | | L = M; //~ ERROR missing +LL | | +LL | | L = M; | |____^ missing `fn`, `type`, or `const` error: missing `fn`, `type`, or `const` for trait-item declaration --> $DIR/issue-40006.rs:12:11 | -LL | L = M; //~ ERROR missing +LL | L = M; | ___________^ -LL | | Z = { 2 + 3 }; //~ ERROR expected one of +LL | | Z = { 2 + 3 }; | |____^ missing `fn`, `type`, or `const` error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;` --> $DIR/issue-40006.rs:13:18 | -LL | Z = { 2 + 3 }; //~ ERROR expected one of +LL | Z = { 2 + 3 }; | ^ expected one of 7 possible tokens here error: expected one of `!` or `::`, found `(` --> $DIR/issue-40006.rs:14:9 | -LL | ::Y (); //~ ERROR expected one of +LL | ::Y (); | ^ expected one of `!` or `::` here error: missing `fn`, `type`, or `const` for impl-item declaration --> $DIR/issue-40006.rs:18:8 | -LL | pub hello_method(&self) { //~ ERROR missing +LL | pub hello_method(&self) { | ^ missing `fn`, `type`, or `const` error[E0038]: the trait `X` cannot be made into an object --> $DIR/issue-40006.rs:1:6 | -LL | impl X { //~ ERROR cannot be made into an object - | ^ the trait `X` cannot be made into an object +LL | impl dyn X { + | ^^^^^ the trait `X` cannot be made into an object | = note: method `xxx` has no receiver diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr index 86bbf2bf27ae6..fe517ee34949d 100644 --- a/src/test/ui/did_you_mean/issue-40396.stderr +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -99,5 +99,5 @@ LL | (0..13).collect(); error: aborting due to 14 previous errors -Some errors occurred: E0308, E0423, E0425, E0615. +Some errors have detailed explanations: E0308, E0423, E0425, E0615. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/did_you_mean/issue-40823.nll.stderr b/src/test/ui/did_you_mean/issue-40823.nll.stderr deleted file mode 100644 index 0389cf5499d9b..0000000000000 --- a/src/test/ui/did_you_mean/issue-40823.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `*buf` as mutable, as it is behind a `&` reference - --> $DIR/issue-40823.rs:3:5 - | -LL | let mut buf = &[1, 2, 3, 4]; - | ------------- help: consider changing this to be a mutable reference: `&mut [1, 2, 3, 4]` -LL | buf.iter_mut(); //~ ERROR cannot borrow immutable borrowed content - | ^^^ `buf` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-40823.rs b/src/test/ui/did_you_mean/issue-40823.rs index 7e456a354b390..0f8c745546778 100644 --- a/src/test/ui/did_you_mean/issue-40823.rs +++ b/src/test/ui/did_you_mean/issue-40823.rs @@ -1,4 +1,4 @@ fn main() { let mut buf = &[1, 2, 3, 4]; - buf.iter_mut(); //~ ERROR cannot borrow immutable borrowed content + buf.iter_mut(); //~ ERROR cannot borrow `*buf` as mutable, as it is behind a `&` reference } diff --git a/src/test/ui/did_you_mean/issue-40823.stderr b/src/test/ui/did_you_mean/issue-40823.stderr index ee64e79ead931..73473406a9ace 100644 --- a/src/test/ui/did_you_mean/issue-40823.stderr +++ b/src/test/ui/did_you_mean/issue-40823.stderr @@ -1,8 +1,10 @@ -error[E0596]: cannot borrow immutable borrowed content `*buf` as mutable +error[E0596]: cannot borrow `*buf` as mutable, as it is behind a `&` reference --> $DIR/issue-40823.rs:3:5 | -LL | buf.iter_mut(); //~ ERROR cannot borrow immutable borrowed content - | ^^^ cannot borrow as mutable +LL | let mut buf = &[1, 2, 3, 4]; + | ------------- help: consider changing this to be a mutable reference: `&mut [1, 2, 3, 4]` +LL | buf.iter_mut(); + | ^^^ `buf` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr b/src/test/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr index d2d9abee22cdc..84235ca4d6372 100644 --- a/src/test/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr +++ b/src/test/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr @@ -1,7 +1,7 @@ error: `~` cannot be used as a unary operator --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:2:13 | -LL | let x = ~1; //~ ERROR cannot be used as a unary operator +LL | let x = ~1; | ^ help: use `!` to perform bitwise negation error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr b/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr index e5dd61c45d662..143d7f695c970 100644 --- a/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr +++ b/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr @@ -28,5 +28,5 @@ LL | let egregious_field_misaccess = demo.egregiously_nonexistent_field; error: aborting due to 4 previous errors -Some errors occurred: E0560, E0609. +Some errors have detailed explanations: E0560, E0609. For more information about an error, try `rustc --explain E0560`. diff --git a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.rs b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.rs index f5dbab1ef3586..7d3aba364897f 100644 --- a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.rs +++ b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.rs @@ -1,5 +1,20 @@ enum Example { Ex(String), NotEx } +enum Void {} + +enum ManyVariants { + One, + Two, + Three, + Four, + Five, + Six, + Seven, + Eight, + Nine, + Ten, +} + fn result_test() { let x = Option(1); //~ ERROR expected function, found enum @@ -12,6 +27,10 @@ fn result_test() { if let Example(_) = y { //~ ERROR expected tuple struct/variant, found enum println!("It is OK."); } + + let y = Void(); //~ ERROR expected function, found enum + + let z = ManyVariants(); //~ ERROR expected function, found enum } fn main() {} diff --git a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr index e6d10ffaae935..d02f30152d687 100644 --- a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr +++ b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr @@ -1,34 +1,63 @@ error[E0423]: expected function, found enum `Option` - --> $DIR/issue-43871-enum-instead-of-variant.rs:4:13 + --> $DIR/issue-43871-enum-instead-of-variant.rs:19:13 | -LL | let x = Option(1); //~ ERROR expected function, found enum +LL | let x = Option(1); | ^^^^^^ +help: try using one of the enum's variants | - = note: did you mean to use one of the following variants? - - `std::prelude::v1::Option::None` - - `std::prelude::v1::Option::Some` +LL | let x = std::prelude::v1::Option::None(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = std::prelude::v1::Option::Some(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0532]: expected tuple struct/variant, found enum `Option` - --> $DIR/issue-43871-enum-instead-of-variant.rs:6:12 + --> $DIR/issue-43871-enum-instead-of-variant.rs:21:12 | -LL | if let Option(_) = x { //~ ERROR expected tuple struct/variant, found enum +LL | if let Option(_) = x { | ^^^^^^ +help: try using one of the enum's variants | - = note: did you mean to use one of the following variants? - - `std::prelude::v1::Option::None` - - `std::prelude::v1::Option::Some` +LL | if let std::prelude::v1::Option::None(_) = x { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | if let std::prelude::v1::Option::Some(_) = x { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0532]: expected tuple struct/variant, found enum `Example` - --> $DIR/issue-43871-enum-instead-of-variant.rs:12:12 + --> $DIR/issue-43871-enum-instead-of-variant.rs:27:12 | -LL | if let Example(_) = y { //~ ERROR expected tuple struct/variant, found enum +LL | if let Example(_) = y { | ^^^^^^^ +help: try using one of the enum's variants | - = note: did you mean to use one of the following variants? - - `Example::Ex` - - `Example::NotEx` +LL | if let Example::Ex(_) = y { + | ^^^^^^^^^^^ +LL | if let Example::NotEx(_) = y { + | ^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error[E0423]: expected function, found enum `Void` + --> $DIR/issue-43871-enum-instead-of-variant.rs:31:13 + | +LL | let y = Void(); + | ^^^^ + +error[E0423]: expected function, found enum `ManyVariants` + --> $DIR/issue-43871-enum-instead-of-variant.rs:33:13 + | +LL | let z = ManyVariants(); + | ^^^^^^^^^^^^ +help: try using one of the enum's variants + | +LL | let z = ManyVariants::Eight(); + | ^^^^^^^^^^^^^^^^^^^ +LL | let z = ManyVariants::Five(); + | ^^^^^^^^^^^^^^^^^^ +LL | let z = ManyVariants::Four(); + | ^^^^^^^^^^^^^^^^^^ +LL | let z = ManyVariants::Nine(); + | ^^^^^^^^^^^^^^^^^^ +and 6 other candidates + +error: aborting due to 5 previous errors -Some errors occurred: E0423, E0532. +Some errors have detailed explanations: E0423, E0532. For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr b/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr index 6107ca32a5d75..8d3a86df0233d 100644 --- a/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr +++ b/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr @@ -34,5 +34,5 @@ and 3 other candidates error: aborting due to 2 previous errors -Some errors occurred: E0412, E0425. +Some errors have detailed explanations: E0412, E0425. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/did_you_mean/multiple-pattern-typo.stderr b/src/test/ui/did_you_mean/multiple-pattern-typo.stderr index 2825ff46825a2..a29fa584b2924 100644 --- a/src/test/ui/did_you_mean/multiple-pattern-typo.stderr +++ b/src/test/ui/did_you_mean/multiple-pattern-typo.stderr @@ -1,7 +1,7 @@ error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:4:15 | -LL | 1 | 2 || 3 => (), //~ ERROR unexpected token `||` after pattern +LL | 1 | 2 || 3 => (), | ^^ help: use a single `|` to specify multiple patterns: `|` error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/pub-macro-rules.stderr b/src/test/ui/did_you_mean/pub-macro-rules.stderr index 7e62fc7c4fc0d..0bde5783b8cc6 100644 --- a/src/test/ui/did_you_mean/pub-macro-rules.stderr +++ b/src/test/ui/did_you_mean/pub-macro-rules.stderr @@ -1,7 +1,7 @@ error: can't qualify macro_rules invocation with `pub` --> $DIR/pub-macro-rules.rs:2:5 | -LL | pub macro_rules! foo { //~ ERROR can't qualify macro_rules invocation +LL | pub macro_rules! foo { | ^^^ help: try exporting the macro: `#[macro_export]` error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index 0738c3f65b95f..a646d98324e09 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -1,7 +1,7 @@ error[E0275]: overflow evaluating the requirement `J: std::marker::Send` --> $DIR/recursion_limit.rs:34:5 | -LL | is_send::(); //~ ERROR overflow evaluating the requirement +LL | is_send::(); | ^^^^^^^^^^^^ | = help: consider adding a `#![recursion_limit="20"]` attribute to your crate diff --git a/src/test/ui/did_you_mean/recursion_limit_deref.rs b/src/test/ui/did_you_mean/recursion_limit_deref.rs index 76e555e5aa6e6..613843801d461 100644 --- a/src/test/ui/did_you_mean/recursion_limit_deref.rs +++ b/src/test/ui/did_you_mean/recursion_limit_deref.rs @@ -50,4 +50,3 @@ fn main() { let x: &Bottom = &t; //~ ERROR mismatched types //~^ error recursion limit } - diff --git a/src/test/ui/did_you_mean/recursion_limit_deref.stderr b/src/test/ui/did_you_mean/recursion_limit_deref.stderr index f8672b20c7863..c76efb1d00920 100644 --- a/src/test/ui/did_you_mean/recursion_limit_deref.stderr +++ b/src/test/ui/did_you_mean/recursion_limit_deref.stderr @@ -1,7 +1,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `I` --> $DIR/recursion_limit_deref.rs:50:22 | -LL | let x: &Bottom = &t; //~ ERROR mismatched types +LL | let x: &Bottom = &t; | ^^ deref recursion limit reached | = help: consider adding a `#![recursion_limit="20"]` attribute to your crate @@ -9,7 +9,7 @@ LL | let x: &Bottom = &t; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/recursion_limit_deref.rs:50:22 | -LL | let x: &Bottom = &t; //~ ERROR mismatched types +LL | let x: &Bottom = &t; | ^^ expected struct `Bottom`, found struct `Top` | = note: expected type `&Bottom` @@ -17,5 +17,5 @@ LL | let x: &Bottom = &t; //~ ERROR mismatched types error: aborting due to 2 previous errors -Some errors occurred: E0055, E0308. +Some errors have detailed explanations: E0055, E0308. For more information about an error, try `rustc --explain E0055`. diff --git a/src/test/ui/did_you_mean/recursion_limit_macro.rs b/src/test/ui/did_you_mean/recursion_limit_macro.rs index c9415361cf826..a68a5ece7cf10 100644 --- a/src/test/ui/did_you_mean/recursion_limit_macro.rs +++ b/src/test/ui/did_you_mean/recursion_limit_macro.rs @@ -13,4 +13,3 @@ macro_rules! recurse { fn main() { recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9); } - diff --git a/src/test/ui/did_you_mean/recursion_limit_macro.stderr b/src/test/ui/did_you_mean/recursion_limit_macro.stderr index 5941d088f3aad..6640ced5c9ecb 100644 --- a/src/test/ui/did_you_mean/recursion_limit_macro.stderr +++ b/src/test/ui/did_you_mean/recursion_limit_macro.stderr @@ -1,7 +1,7 @@ error: recursion limit reached while expanding the macro `recurse` --> $DIR/recursion_limit_macro.rs:10:31 | -LL | ($t:tt $($tail:tt)*) => { recurse!($($tail)*) }; //~ ERROR recursion limit +LL | ($t:tt $($tail:tt)*) => { recurse!($($tail)*) }; | ^^^^^^^^^^^^^^^^^^^ ... LL | recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9); diff --git a/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs index a05227416cfd7..c9a097d3610a1 100644 --- a/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs +++ b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs @@ -1,3 +1,5 @@ +#![allow(bare_trait_objects)] + fn main() { let _: &Copy + 'static; //~ ERROR expected a path //~^ ERROR cannot be made into an object diff --git a/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr index 85c0527477350..8c6c33b11865b 100644 --- a/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr +++ b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr @@ -1,24 +1,24 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&Copy` - --> $DIR/trait-object-reference-without-parens-suggestion.rs:2:12 + --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12 | -LL | let _: &Copy + 'static; //~ ERROR expected a path +LL | let _: &Copy + 'static; | ^^^^^^^^^^^^^^^ help: try adding parentheses: `&(Copy + 'static)` error[E0178]: expected a path on the left-hand side of `+`, not `&'static Copy` - --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12 + --> $DIR/trait-object-reference-without-parens-suggestion.rs:6:12 | -LL | let _: &'static Copy + 'static; //~ ERROR expected a path +LL | let _: &'static Copy + 'static; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try adding parentheses: `&'static (Copy + 'static)` error[E0038]: the trait `std::marker::Copy` cannot be made into an object - --> $DIR/trait-object-reference-without-parens-suggestion.rs:2:12 + --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12 | -LL | let _: &Copy + 'static; //~ ERROR expected a path +LL | let _: &Copy + 'static; | ^^^^^ the trait `std::marker::Copy` cannot be made into an object | = note: the trait cannot require that `Self : Sized` error: aborting due to 3 previous errors -Some errors occurred: E0038, E0178. +Some errors have detailed explanations: E0038, E0178. For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr b/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr index 6ceaa2e346a07..46acc7e66d8b8 100644 --- a/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr +++ b/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr @@ -1,7 +1,7 @@ error: Cannot declare a non-inline module inside a block unless it has a path attribute --> $DIR/non-inline-mod-restriction.rs:4:9 | -LL | mod foo; //~ ERROR Cannot declare a non-inline module inside a block +LL | mod foo; | ^^^ error: aborting due to previous error diff --git a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.nll.stderr b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.nll.stderr deleted file mode 100644 index 59cb804a801fd..0000000000000 --- a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0509]: cannot move out of type `X`, which implements the `Drop` trait - --> $DIR/disallowed-deconstructing-destructing-struct-let.rs:12:22 - | -LL | let X { x: y } = x; //~ ERROR cannot move out of type - | - ^ cannot move out of here - | | - | data moved here - | -note: move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/disallowed-deconstructing-destructing-struct-let.rs:12:16 - | -LL | let X { x: y } = x; //~ ERROR cannot move out of type - | ^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr index cb32616d6e6fb..8c64149a0ff51 100644 --- a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr +++ b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr @@ -1,11 +1,11 @@ error[E0509]: cannot move out of type `X`, which implements the `Drop` trait - --> $DIR/disallowed-deconstructing-destructing-struct-let.rs:12:9 + --> $DIR/disallowed-deconstructing-destructing-struct-let.rs:12:22 | -LL | let X { x: y } = x; //~ ERROR cannot move out of type - | ^^^^^^^-^^ - | | | - | | hint: to prevent move, use `ref y` or `ref mut y` - | cannot move out of here +LL | let X { x: y } = x; + | - ^ cannot move out of here + | | + | data moved here + | move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.nll.stderr b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.nll.stderr deleted file mode 100644 index 2143c2f9b2244..0000000000000 --- a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0509]: cannot move out of type `X`, which implements the `Drop` trait - --> $DIR/disallowed-deconstructing-destructing-struct-match.rs:14:11 - | -LL | match x { - | ^ cannot move out of here -LL | X { x: y } => println!("contents: {}", y) - | - data moved here - | -note: move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/disallowed-deconstructing-destructing-struct-match.rs:15:16 - | -LL | X { x: y } => println!("contents: {}", y) - | ^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.rs b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.rs index 3a5ed6e3b3e53..9c996a93b9532 100644 --- a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.rs +++ b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.rs @@ -12,7 +12,7 @@ fn main() { let x = X { x: "hello".to_string() }; match x { + //~^ ERROR cannot move out of type `X`, which implements the `Drop` trait X { x: y } => println!("contents: {}", y) - //~^ ERROR cannot move out of type `X`, which implements the `Drop` trait } } diff --git a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr index 8be1b385afe6c..afc5170e1b84e 100644 --- a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr +++ b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr @@ -1,11 +1,14 @@ error[E0509]: cannot move out of type `X`, which implements the `Drop` trait - --> $DIR/disallowed-deconstructing-destructing-struct-match.rs:15:9 + --> $DIR/disallowed-deconstructing-destructing-struct-match.rs:14:11 | +LL | match x { + | ^ cannot move out of here +LL | LL | X { x: y } => println!("contents: {}", y) - | ^^^^^^^-^^ - | | | - | | hint: to prevent move, use `ref y` or `ref mut y` - | cannot move out of here + | - + | | + | data moved here + | move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/discrim/discrim-ill-typed.stderr b/src/test/ui/discrim/discrim-ill-typed.stderr index 14cdb9e07f902..543fecb249f98 100644 --- a/src/test/ui/discrim/discrim-ill-typed.stderr +++ b/src/test/ui/discrim/discrim-ill-typed.stderr @@ -3,48 +3,80 @@ error[E0308]: mismatched types | LL | OhNo = 0_u8, | ^^^^ expected i8, found u8 +help: change the type of the numeric literal from `u8` to `i8` + | +LL | OhNo = 0_i8, + | ^^^^ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:30:16 | LL | OhNo = 0_i8, | ^^^^ expected u8, found i8 +help: change the type of the numeric literal from `i8` to `u8` + | +LL | OhNo = 0_u8, + | ^^^^ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:43:16 | LL | OhNo = 0_u16, | ^^^^^ expected i16, found u16 +help: change the type of the numeric literal from `u16` to `i16` + | +LL | OhNo = 0_i16, + | ^^^^^ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:56:16 | LL | OhNo = 0_i16, | ^^^^^ expected u16, found i16 +help: change the type of the numeric literal from `i16` to `u16` + | +LL | OhNo = 0_u16, + | ^^^^^ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:69:16 | LL | OhNo = 0_u32, | ^^^^^ expected i32, found u32 +help: change the type of the numeric literal from `u32` to `i32` + | +LL | OhNo = 0_i32, + | ^^^^^ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:82:16 | LL | OhNo = 0_i32, | ^^^^^ expected u32, found i32 +help: change the type of the numeric literal from `i32` to `u32` + | +LL | OhNo = 0_u32, + | ^^^^^ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:95:16 | LL | OhNo = 0_u64, | ^^^^^ expected i64, found u64 +help: change the type of the numeric literal from `u64` to `i64` + | +LL | OhNo = 0_i64, + | ^^^^^ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:108:16 | LL | OhNo = 0_i64, | ^^^^^ expected u64, found i64 +help: change the type of the numeric literal from `i64` to `u64` + | +LL | OhNo = 0_u64, + | ^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/discrim/discrim-overflow-2.rs b/src/test/ui/discrim/discrim-overflow-2.rs index 9ff39cd048454..f8f565f4d9c14 100644 --- a/src/test/ui/discrim/discrim-overflow-2.rs +++ b/src/test/ui/discrim/discrim-overflow-2.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - // Issue 23030: Detect overflowing discriminant // // Check that we detect the overflow even if enum is not used. diff --git a/src/test/ui/discrim/discrim-overflow-2.stderr b/src/test/ui/discrim/discrim-overflow-2.stderr index c490509142ac6..198ebe9eb51f9 100644 --- a/src/test/ui/discrim/discrim-overflow-2.stderr +++ b/src/test/ui/discrim/discrim-overflow-2.stderr @@ -1,63 +1,63 @@ error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:17:9 + --> $DIR/discrim-overflow-2.rs:15:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 127 | = note: explicitly set `OhNo = -128` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:26:9 + --> $DIR/discrim-overflow-2.rs:24:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 255 | = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:35:9 + --> $DIR/discrim-overflow-2.rs:33:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 32767 | = note: explicitly set `OhNo = -32768` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:44:9 + --> $DIR/discrim-overflow-2.rs:42:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 65535 | = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:53:9 + --> $DIR/discrim-overflow-2.rs:51:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 2147483647 | = note: explicitly set `OhNo = -2147483648` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:62:9 + --> $DIR/discrim-overflow-2.rs:60:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 4294967295 | = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:71:9 + --> $DIR/discrim-overflow-2.rs:69:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 9223372036854775807 | = note: explicitly set `OhNo = -9223372036854775808` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:80:9 + --> $DIR/discrim-overflow-2.rs:78:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 18446744073709551615 | = note: explicitly set `OhNo = 0` if that is desired outcome diff --git a/src/test/ui/discrim/discrim-overflow.rs b/src/test/ui/discrim/discrim-overflow.rs index c612661178cf6..d8a9dacfa5180 100644 --- a/src/test/ui/discrim/discrim-overflow.rs +++ b/src/test/ui/discrim/discrim-overflow.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - // Issue 23030: Detect overflowing discriminant // See also run-pass/discrim-explicit-23030.rs where the suggested diff --git a/src/test/ui/discrim/discrim-overflow.stderr b/src/test/ui/discrim/discrim-overflow.stderr index e71df51e36d00..a2ae4863f9f79 100644 --- a/src/test/ui/discrim/discrim-overflow.stderr +++ b/src/test/ui/discrim/discrim-overflow.stderr @@ -1,63 +1,63 @@ error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:15:9 + --> $DIR/discrim-overflow.rs:13:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 127 | = note: explicitly set `OhNo = -128` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:26:9 + --> $DIR/discrim-overflow.rs:24:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 255 | = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:37:9 + --> $DIR/discrim-overflow.rs:35:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 32767 | = note: explicitly set `OhNo = -32768` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:48:9 + --> $DIR/discrim-overflow.rs:46:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 65535 | = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:60:9 + --> $DIR/discrim-overflow.rs:58:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 2147483647 | = note: explicitly set `OhNo = -2147483648` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:72:9 + --> $DIR/discrim-overflow.rs:70:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 4294967295 | = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:84:9 + --> $DIR/discrim-overflow.rs:82:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 9223372036854775807 | = note: explicitly set `OhNo = -9223372036854775808` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:96:9 + --> $DIR/discrim-overflow.rs:94:9 | -LL | OhNo, //~ ERROR enum discriminant overflowed [E0370] +LL | OhNo, | ^^^^ overflowed on value after 18446744073709551615 | = note: explicitly set `OhNo = 0` if that is desired outcome diff --git a/src/test/ui/diverging-tuple-parts-39485.stderr b/src/test/ui/diverging-tuple-parts-39485.stderr index c399650d3258b..70eefeb329db4 100644 --- a/src/test/ui/diverging-tuple-parts-39485.stderr +++ b/src/test/ui/diverging-tuple-parts-39485.stderr @@ -1,20 +1,26 @@ error[E0308]: mismatched types --> $DIR/diverging-tuple-parts-39485.rs:8:5 | -LL | fn g() { - | - help: try adding a return type: `-> &_` -LL | &panic!() //~ ERROR mismatched types +LL | &panic!() | ^^^^^^^^^ expected (), found reference | = note: expected type `()` found type `&_` +help: try adding a return type + | +LL | fn g() -> &_ { + | ^^^^^ +help: consider removing the borrow + | +LL | panic!() + | ^^^^^^^^ error[E0308]: mismatched types --> $DIR/diverging-tuple-parts-39485.rs:12:5 | LL | fn f() -> isize { | ----- expected `isize` because of return type -LL | (return 1, return 2) //~ ERROR mismatched types +LL | (return 1, return 2) | ^^^^^^^^^^^^^^^^^^^^ expected isize, found tuple | = note: expected type `isize` diff --git a/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr b/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr index 206af6757b225..55261a5e6aead 100644 --- a/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr +++ b/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: `$crate` in paths can only be used in start position --> $DIR/dollar-crate-is-keyword-2.rs:6:16 | -LL | use a::$crate::b; //~ ERROR `$crate` in paths can only be used in start position +LL | use a::$crate::b; | ^^^^^^ `$crate` in paths can only be used in start position ... LL | m!(); @@ -10,7 +10,7 @@ LL | m!(); error[E0432]: unresolved import `a::$crate` --> $DIR/dollar-crate-is-keyword-2.rs:5:13 | -LL | use a::$crate; //~ ERROR unresolved import `a::$crate` +LL | use a::$crate; | ^^^^^^^^^ no `$crate` in `a` ... LL | m!(); @@ -19,7 +19,7 @@ LL | m!(); error[E0433]: failed to resolve: `$crate` in paths can only be used in start position --> $DIR/dollar-crate-is-keyword-2.rs:7:21 | -LL | type A = a::$crate; //~ ERROR `$crate` in paths can only be used in start position +LL | type A = a::$crate; | ^^^^^^ `$crate` in paths can only be used in start position ... LL | m!(); @@ -27,5 +27,5 @@ LL | m!(); error: aborting due to 3 previous errors -Some errors occurred: E0432, E0433. +Some errors have detailed explanations: E0432, E0433. For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/dollar-crate/dollar-crate-is-keyword.stderr b/src/test/ui/dollar-crate/dollar-crate-is-keyword.stderr index e94a5fe96ffcd..5d4f39086cee6 100644 --- a/src/test/ui/dollar-crate/dollar-crate-is-keyword.stderr +++ b/src/test/ui/dollar-crate/dollar-crate-is-keyword.stderr @@ -1,7 +1,7 @@ error: expected identifier, found reserved identifier `$crate` --> $DIR/dollar-crate-is-keyword.rs:6:20 | -LL | struct $crate {} //~ ERROR expected identifier, found reserved identifier `$crate` +LL | struct $crate {} | ^^^^^^ expected identifier, found reserved identifier ... LL | m!(); @@ -10,7 +10,7 @@ LL | m!(); error: expected identifier, found reserved identifier `$crate` --> $DIR/dollar-crate-is-keyword.rs:11:23 | -LL | use $crate as $crate; //~ ERROR expected identifier, found reserved identifier `$crate` +LL | use $crate as $crate; | ^^^^^^ expected identifier, found reserved identifier ... LL | m!(); @@ -30,7 +30,7 @@ LL | m!(); warning: `$crate` may not be imported --> $DIR/dollar-crate-is-keyword.rs:11:9 | -LL | use $crate as $crate; //~ ERROR expected identifier, found reserved identifier `$crate` +LL | use $crate as $crate; | ^^^^^^^^^^^^^^^^^^^^^ ... LL | m!(); diff --git a/src/test/ui/dont-suggest-private-trait-method.stderr b/src/test/ui/dont-suggest-private-trait-method.stderr index af4253779a4f5..5189ffa62d1ba 100644 --- a/src/test/ui/dont-suggest-private-trait-method.stderr +++ b/src/test/ui/dont-suggest-private-trait-method.stderr @@ -5,9 +5,7 @@ LL | struct T; | --------- function or associated item `new` not found for this ... LL | T::new(); - | ---^^^ - | | - | function or associated item not found in `T` + | ^^^ function or associated item not found in `T` error: aborting due to previous error diff --git a/src/test/ui/double-import.stderr b/src/test/ui/double-import.stderr index 2fefdc49e9c4e..7a4e8e5d3b926 100644 --- a/src/test/ui/double-import.stderr +++ b/src/test/ui/double-import.stderr @@ -3,13 +3,13 @@ error[E0252]: the name `foo` is defined multiple times | LL | use sub1::foo; | --------- previous import of the value `foo` here -LL | use sub2::foo; //~ ERROR the name `foo` is defined multiple times +LL | use sub2::foo; | ^^^^^^^^^ `foo` reimported here | = note: `foo` must be defined only once in the value namespace of this module help: you can use `as` to change the binding name of the import | -LL | use sub2::foo as other_foo; //~ ERROR the name `foo` is defined multiple times +LL | use sub2::foo as other_foo; | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/double-type-import.stderr b/src/test/ui/double-type-import.stderr index c7288af13c278..a2f30d82ec38b 100644 --- a/src/test/ui/double-type-import.stderr +++ b/src/test/ui/double-type-import.stderr @@ -4,10 +4,7 @@ error[E0252]: the name `X` is defined multiple times LL | pub use self::bar::X; | ------------ previous import of the type `X` here LL | use self::bar::X; - | ----^^^^^^^^^^^^- - | | | - | | `X` reimported here - | help: remove unnecessary import + | ^^^^^^^^^^^^ `X` reimported here | = note: `X` must be defined only once in the type namespace of this module diff --git a/src/test/ui/dropck/drop-on-non-struct.stderr b/src/test/ui/dropck/drop-on-non-struct.stderr index 6b670d5d434e4..6ff16402b0e6e 100644 --- a/src/test/ui/dropck/drop-on-non-struct.stderr +++ b/src/test/ui/dropck/drop-on-non-struct.stderr @@ -15,5 +15,5 @@ LL | impl<'a> Drop for &'a mut isize { error: aborting due to 2 previous errors -Some errors occurred: E0117, E0120. +Some errors have detailed explanations: E0117, E0120. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/dropck/drop-with-active-borrows-1.nll.stderr b/src/test/ui/dropck/drop-with-active-borrows-1.nll.stderr deleted file mode 100644 index 9c6c9341be77a..0000000000000 --- a/src/test/ui/dropck/drop-with-active-borrows-1.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0505]: cannot move out of `a` because it is borrowed - --> $DIR/drop-with-active-borrows-1.rs:4:10 - | -LL | let b: Vec<&str> = a.lines().collect(); - | - borrow of `a` occurs here -LL | drop(a); //~ ERROR cannot move out of `a` because it is borrowed - | ^ move out of `a` occurs here -LL | for s in &b { - | -- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/dropck/drop-with-active-borrows-1.stderr b/src/test/ui/dropck/drop-with-active-borrows-1.stderr index a4295f96205ac..7fed27adaff2b 100644 --- a/src/test/ui/dropck/drop-with-active-borrows-1.stderr +++ b/src/test/ui/dropck/drop-with-active-borrows-1.stderr @@ -3,8 +3,10 @@ error[E0505]: cannot move out of `a` because it is borrowed | LL | let b: Vec<&str> = a.lines().collect(); | - borrow of `a` occurs here -LL | drop(a); //~ ERROR cannot move out of `a` because it is borrowed +LL | drop(a); | ^ move out of `a` occurs here +LL | for s in &b { + | -- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/dropck/drop-with-active-borrows-2.nll.stderr b/src/test/ui/dropck/drop-with-active-borrows-2.nll.stderr deleted file mode 100644 index ffec9306b7771..0000000000000 --- a/src/test/ui/dropck/drop-with-active-borrows-2.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0515]: cannot return value referencing local variable `raw_lines` - --> $DIR/drop-with-active-borrows-2.rs:3:5 - | -LL | raw_lines.iter().map(|l| l.trim()).collect() - | ---------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `raw_lines` is borrowed here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/dropck/drop-with-active-borrows-2.rs b/src/test/ui/dropck/drop-with-active-borrows-2.rs index 4e45633a281cb..cf4cb3dbe7aaf 100644 --- a/src/test/ui/dropck/drop-with-active-borrows-2.rs +++ b/src/test/ui/dropck/drop-with-active-borrows-2.rs @@ -1,7 +1,7 @@ fn read_lines_borrowed<'a>() -> Vec<&'a str> { let raw_lines: Vec = vec!["foo ".to_string(), " bar".to_string()]; raw_lines.iter().map(|l| l.trim()).collect() - //~^ ERROR `raw_lines` does not live long enough + //~^ ERROR cannot return value referencing local variable `raw_lines` } fn main() { diff --git a/src/test/ui/dropck/drop-with-active-borrows-2.stderr b/src/test/ui/dropck/drop-with-active-borrows-2.stderr index 347389cb59d70..ffec9306b7771 100644 --- a/src/test/ui/dropck/drop-with-active-borrows-2.stderr +++ b/src/test/ui/dropck/drop-with-active-borrows-2.stderr @@ -1,18 +1,12 @@ -error[E0597]: `raw_lines` does not live long enough +error[E0515]: cannot return value referencing local variable `raw_lines` --> $DIR/drop-with-active-borrows-2.rs:3:5 | LL | raw_lines.iter().map(|l| l.trim()).collect() - | ^^^^^^^^^ borrowed value does not live long enough -LL | //~^ ERROR `raw_lines` does not live long enough -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 1:24... - --> $DIR/drop-with-active-borrows-2.rs:1:24 - | -LL | fn read_lines_borrowed<'a>() -> Vec<&'a str> { - | ^^ + | ---------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `raw_lines` is borrowed here error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.ast.stderr b/src/test/ui/dropck/dropck-eyepatch-extern-crate.ast.stderr deleted file mode 100644 index 31adb2f3f1471..0000000000000 --- a/src/test/ui/dropck/dropck-eyepatch-extern-crate.ast.stderr +++ /dev/null @@ -1,69 +0,0 @@ -error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch-extern-crate.rs:41:20 - | -LL | dt = Dt("dt", &c); - | ^ borrowed value does not live long enough -... -LL | } - | - `c` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch-extern-crate.rs:43:20 - | -LL | dr = Dr("dr", &c); - | ^ borrowed value does not live long enough -... -LL | } - | - `c` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch-extern-crate.rs:47:20 - | -LL | dt = Dt("dt", &c_shortest); - | ^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `c_shortest` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch-extern-crate.rs:50:20 - | -LL | dr = Dr("dr", &c_shortest); - | ^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `c_shortest` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch-extern-crate.rs:57:29 - | -LL | pt = Pt("pt", &c_long, &c_shortest); - | ^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `c_shortest` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch-extern-crate.rs:59:29 - | -LL | pr = Pr("pr", &c_long, &c_shortest); - | ^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `c_shortest` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.nll.stderr b/src/test/ui/dropck/dropck-eyepatch-extern-crate.nll.stderr deleted file mode 100644 index e0b7fc4eb9054..0000000000000 --- a/src/test/ui/dropck/dropck-eyepatch-extern-crate.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch-extern-crate.rs:47:19 - | -LL | dt = Dt("dt", &c_shortest); - | ^^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `c_shortest` dropped here while still borrowed - | borrow might be used here, when `dt` is dropped and runs the `Drop` code for type `other::Dt` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs b/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs index 68065639398a5..b8f30355413e5 100644 --- a/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs +++ b/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs @@ -1,13 +1,3 @@ -// The behavior of AST-borrowck and NLL explcitly differ here due to -// NLL's increased precision; so we use revisions and do not worry -// about the --compare-mode=nll on this test. - -// revisions: ast nll -//[ast]compile-flags: -Z borrowck=ast -//[nll]compile-flags: -Z borrowck=migrate -Z two-phase-borrows - -// ignore-compare-mode-nll - // aux-build:dropck_eyepatch_extern_crate.rs // The point of this test is to illustrate that the `#[may_dangle]` @@ -19,52 +9,74 @@ // // See also dropck-eyepatch.rs for more information about the general // structure of the test. -#![feature(rustc_attrs)] extern crate dropck_eyepatch_extern_crate as other; use other::{Dt,Dr,Pt,Pr,St,Sr}; -fn main() { #![rustc_error] // rust-lang/rust#49855 +fn main() { use std::cell::Cell; - let c_long; - let (c, mut dt, mut dr, mut pt, mut pr, st, sr, c_shortest) - : (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>, Cell<_>); - c_long = Cell::new(1); - c = Cell::new(1); - c_shortest = Cell::new(1); - // No error: sufficiently long-lived state can be referenced in dtors - dt = Dt("dt", &c_long); - dr = Dr("dr", &c_long); + // We use separate blocks with separate variable to prevent the error + // messages from being deduplicated. + + { + let c_long; + let (mut dt, mut dr): (Dt<_>, Dr<_>); + c_long = Cell::new(1); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long); + dr = Dr("dr", &c_long); + } + + { + let (c, mut dt, mut dr): (Cell<_>, Dt<_>, Dr<_>); + c = Cell::new(1); + + // No Error: destructor order precisely modelled + dt = Dt("dt", &c); + dr = Dr("dr", &c); + } + + { + let (mut dt, mut dr, c_shortest): (Dt<_>, Dr<_>, Cell<_>); + c_shortest = Cell::new(1); - // Error: destructor order imprecisely modelled - dt = Dt("dt", &c); - //[ast]~^ ERROR `c` does not live long enough - dr = Dr("dr", &c); - //[ast]~^ ERROR `c` does not live long enough + // Error: `c_shortest` dies too soon for the references in dtors to be valid. + dt = Dt("dt", &c_shortest); + //~^ ERROR `c_shortest` does not live long enough + dr = Dr("dr", &c_shortest); + } - // Error: `c_shortest` dies too soon for the references in dtors to be valid. - dt = Dt("dt", &c_shortest); - //[ast]~^ ERROR `c_shortest` does not live long enough - //[nll]~^^ ERROR `c_shortest` does not live long enough - dr = Dr("dr", &c_shortest); - //[ast]~^ ERROR `c_shortest` does not live long enough - // No error: Drop impl asserts .1 (A and &'a _) are not accessed - pt = Pt("pt", &c_shortest, &c_long); - pr = Pr("pr", &c_shortest, &c_long); + { + let c_long; + let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>); + c_long = Cell::new(1); + c_shortest = Cell::new(1); - // Error: Drop impl's assertion does not apply to `B` nor `&'b _` - pt = Pt("pt", &c_long, &c_shortest); - //[ast]~^ ERROR `c_shortest` does not live long enough - pr = Pr("pr", &c_long, &c_shortest); - //[ast]~^ ERROR `c_shortest` does not live long enough + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c_shortest, &c_long); + pr = Pr("pr", &c_shortest, &c_long); + } - // No error: St and Sr have no destructor. - st = St("st", &c_shortest); - sr = Sr("sr", &c_shortest); + { + let c_long; + let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>); + c_long = Cell::new(1); + c_shortest = Cell::new(1); + // Error: Drop impl's assertion does not apply to `B` nor `&'b _` + pt = Pt("pt", &c_long, &c_shortest); + //~^ ERROR `c_shortest` does not live long enough + pr = Pr("pr", &c_long, &c_shortest); + } - println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); - use_imm(sr.1); use_imm(st.1); use_imm(pr.1); use_imm(pt.1); use_imm(dr.1); use_imm(dt.1); + { + let (st, sr, c_shortest): (St<_>, Sr<_>, Cell<_>); + c_shortest = Cell::new(1); + // No error: St and Sr have no destructor. + st = St("st", &c_shortest); + sr = Sr("sr", &c_shortest); + } } fn use_imm(_: &T) { } diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr b/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr new file mode 100644 index 0000000000000..c10232107e8c4 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr @@ -0,0 +1,31 @@ +error[E0597]: `c_shortest` does not live long enough + --> $DIR/dropck-eyepatch-extern-crate.rs:46:23 + | +LL | dt = Dt("dt", &c_shortest); + | ^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | `c_shortest` dropped here while still borrowed + | borrow might be used here, when `dt` is dropped and runs the `Drop` code for type `other::Dt` + | + = note: values in a scope are dropped in the opposite order they are defined + +error[E0597]: `c_shortest` does not live long enough + --> $DIR/dropck-eyepatch-extern-crate.rs:68:32 + | +LL | pt = Pt("pt", &c_long, &c_shortest); + | ^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | `c_shortest` dropped here while still borrowed + | borrow might be used here, when `pt` is dropped and runs the `Drop` code for type `other::Pt` + | + = note: values in a scope are dropped in the opposite order they are defined + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr index c3139948a07d4..49e55be1b49e4 100644 --- a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr +++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr @@ -2,7 +2,7 @@ error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attri --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:21:1 | LL | / impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { -LL | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute +LL | | LL | | LL | | // (unsafe to access self.1 due to #[may_dangle] on A) LL | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } @@ -13,7 +13,7 @@ error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attri --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:27:1 | LL | / impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { -LL | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute +LL | | LL | | LL | | // (unsafe to access self.1 due to #[may_dangle] on 'a) LL | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.ast.stderr b/src/test/ui/dropck/dropck-eyepatch-reorder.ast.stderr deleted file mode 100644 index ddd47e9743497..0000000000000 --- a/src/test/ui/dropck/dropck-eyepatch-reorder.ast.stderr +++ /dev/null @@ -1,69 +0,0 @@ -error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch-reorder.rs:58:20 - | -LL | dt = Dt("dt", &c); - | ^ borrowed value does not live long enough -... -LL | } - | - `c` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch-reorder.rs:60:20 - | -LL | dr = Dr("dr", &c); - | ^ borrowed value does not live long enough -... -LL | } - | - `c` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch-reorder.rs:64:20 - | -LL | dt = Dt("dt", &c_shortest); - | ^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `c_shortest` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch-reorder.rs:67:20 - | -LL | dr = Dr("dr", &c_shortest); - | ^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `c_shortest` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch-reorder.rs:74:29 - | -LL | pt = Pt("pt", &c_long, &c_shortest); - | ^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `c_shortest` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch-reorder.rs:76:29 - | -LL | pr = Pr("pr", &c_long, &c_shortest); - | ^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `c_shortest` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.nll.stderr b/src/test/ui/dropck/dropck-eyepatch-reorder.nll.stderr deleted file mode 100644 index 97c1caa87f5c5..0000000000000 --- a/src/test/ui/dropck/dropck-eyepatch-reorder.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch-reorder.rs:64:19 - | -LL | dt = Dt("dt", &c_shortest); - | ^^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `c_shortest` dropped here while still borrowed - | borrow might be used here, when `dt` is dropped and runs the `Drop` code for type `Dt` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.rs b/src/test/ui/dropck/dropck-eyepatch-reorder.rs index 16aaa26125768..44552b3fc1d9f 100644 --- a/src/test/ui/dropck/dropck-eyepatch-reorder.rs +++ b/src/test/ui/dropck/dropck-eyepatch-reorder.rs @@ -1,14 +1,4 @@ -// The behavior of AST-borrowck and NLL explcitly differ here due to -// NLL's increased precision; so we use revisions and do not worry -// about the --compare-mode=nll on this test. - -// revisions: ast nll -//[ast]compile-flags: -Z borrowck=ast -//[nll]compile-flags: -Z borrowck=migrate -Z two-phase-borrows - -// ignore-compare-mode-nll - -#![feature(dropck_eyepatch, rustc_attrs)] +#![feature(dropck_eyepatch)] // The point of this test is to test uses of `#[may_dangle]` attribute // where the formal declaration order (in the impl generics) does not @@ -41,47 +31,70 @@ unsafe impl<'b, #[may_dangle] 'a, B: fmt::Debug> Drop for Pr<'a, 'b, B> { fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } } -fn main() { #![rustc_error] // rust-lang/rust#49855 +fn main() { use std::cell::Cell; - let c_long; - let (c, mut dt, mut dr, mut pt, mut pr, st, sr, c_shortest) - : (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>, Cell<_>); - c_long = Cell::new(1); - c = Cell::new(1); - c_shortest = Cell::new(1); - - // No error: sufficiently long-lived state can be referenced in dtors - dt = Dt("dt", &c_long); - dr = Dr("dr", &c_long); - - // Error: destructor order imprecisely modelled - dt = Dt("dt", &c); - //[ast]~^ ERROR `c` does not live long enough - dr = Dr("dr", &c); - //[ast]~^ ERROR `c` does not live long enough - - // Error: `c_shortest` dies too soon for the references in dtors to be valid. - dt = Dt("dt", &c_shortest); - //[ast]~^ ERROR `c_shortest` does not live long enough - //[nll]~^^ ERROR `c_shortest` does not live long enough - dr = Dr("dr", &c_shortest); - //[ast]~^ ERROR `c_shortest` does not live long enough - // No error: Drop impl asserts .1 (A and &'a _) are not accessed - pt = Pt("pt", &c_shortest, &c_long); - pr = Pr("pr", &c_shortest, &c_long); - - // Error: Drop impl's assertion does not apply to `B` nor `&'b _` - pt = Pt("pt", &c_long, &c_shortest); - //[ast]~^ ERROR `c_shortest` does not live long enough - pr = Pr("pr", &c_long, &c_shortest); - //[ast]~^ ERROR `c_shortest` does not live long enough - - // No error: St and Sr have no destructor. - st = St("st", &c_shortest); - sr = Sr("sr", &c_shortest); - - println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); - use_imm(sr.1); use_imm(st.1); use_imm(pr.1); use_imm(pt.1); use_imm(dr.1); use_imm(dt.1); + + // We use separate blocks with separate variable to prevent the error + // messages from being deduplicated. + + { + let c_long; + let (mut dt, mut dr): (Dt<_>, Dr<_>); + c_long = Cell::new(1); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long); + dr = Dr("dr", &c_long); + } + + { + let (c, mut dt, mut dr): (Cell<_>, Dt<_>, Dr<_>); + c = Cell::new(1); + + // No Error: destructor order precisely modelled + dt = Dt("dt", &c); + dr = Dr("dr", &c); + } + + { + let (mut dt, mut dr, c_shortest): (Dt<_>, Dr<_>, Cell<_>); + c_shortest = Cell::new(1); + + // Error: `c_shortest` dies too soon for the references in dtors to be valid. + dt = Dt("dt", &c_shortest); + //~^ ERROR `c_shortest` does not live long enough + dr = Dr("dr", &c_shortest); + } + + { + let c_long; + let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>); + c_long = Cell::new(1); + c_shortest = Cell::new(1); + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c_shortest, &c_long); + pr = Pr("pr", &c_shortest, &c_long); + } + + { + let c_long; + let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>); + c_long = Cell::new(1); + c_shortest = Cell::new(1); + // Error: Drop impl's assertion does not apply to `B` nor `&'b _` + pt = Pt("pt", &c_long, &c_shortest); + //~^ ERROR `c_shortest` does not live long enough + pr = Pr("pr", &c_long, &c_shortest); + } + + { + let (st, sr, c_shortest): (St<_>, Sr<_>, Cell<_>); + c_shortest = Cell::new(1); + // No error: St and Sr have no destructor. + st = St("st", &c_shortest); + sr = Sr("sr", &c_shortest); + } } fn use_imm(_: &T) { } diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.stderr b/src/test/ui/dropck/dropck-eyepatch-reorder.stderr new file mode 100644 index 0000000000000..5055cdd8b2bf9 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-reorder.stderr @@ -0,0 +1,31 @@ +error[E0597]: `c_shortest` does not live long enough + --> $DIR/dropck-eyepatch-reorder.rs:64:23 + | +LL | dt = Dt("dt", &c_shortest); + | ^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | `c_shortest` dropped here while still borrowed + | borrow might be used here, when `dt` is dropped and runs the `Drop` code for type `Dt` + | + = note: values in a scope are dropped in the opposite order they are defined + +error[E0597]: `c_shortest` does not live long enough + --> $DIR/dropck-eyepatch-reorder.rs:86:32 + | +LL | pt = Pt("pt", &c_long, &c_shortest); + | ^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | `c_shortest` dropped here while still borrowed + | borrow might be used here, when `pt` is dropped and runs the `Drop` code for type `Pt` + | + = note: values in a scope are dropped in the opposite order they are defined + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/dropck/dropck-eyepatch.ast.stderr b/src/test/ui/dropck/dropck-eyepatch.ast.stderr deleted file mode 100644 index 0952ed0d6b793..0000000000000 --- a/src/test/ui/dropck/dropck-eyepatch.ast.stderr +++ /dev/null @@ -1,69 +0,0 @@ -error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch.rs:81:20 - | -LL | dt = Dt("dt", &c); - | ^ borrowed value does not live long enough -... -LL | } - | - `c` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch.rs:83:20 - | -LL | dr = Dr("dr", &c); - | ^ borrowed value does not live long enough -... -LL | } - | - `c` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch.rs:87:20 - | -LL | dt = Dt("dt", &c_shortest); - | ^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `c_shortest` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch.rs:90:20 - | -LL | dr = Dr("dr", &c_shortest); - | ^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `c_shortest` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch.rs:98:29 - | -LL | pt = Pt("pt", &c_long, &c_shortest); - | ^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `c_shortest` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch.rs:100:29 - | -LL | pr = Pr("pr", &c_long, &c_shortest); - | ^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `c_shortest` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/dropck/dropck-eyepatch.nll.stderr b/src/test/ui/dropck/dropck-eyepatch.nll.stderr deleted file mode 100644 index 4a6e42ef94a85..0000000000000 --- a/src/test/ui/dropck/dropck-eyepatch.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0597]: `c_shortest` does not live long enough - --> $DIR/dropck-eyepatch.rs:87:19 - | -LL | dt = Dt("dt", &c_shortest); - | ^^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `c_shortest` dropped here while still borrowed - | borrow might be used here, when `dt` is dropped and runs the `Drop` code for type `Dt` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/dropck/dropck-eyepatch.rs b/src/test/ui/dropck/dropck-eyepatch.rs index fb1c03b678632..ec1c685613832 100644 --- a/src/test/ui/dropck/dropck-eyepatch.rs +++ b/src/test/ui/dropck/dropck-eyepatch.rs @@ -1,14 +1,4 @@ -// The behavior of AST-borrowck and NLL explcitly differ here due to -// NLL's increased precision; so we use revisions and do not worry -// about the --compare-mode=nll on this test. - -// revisions: ast nll -//[ast]compile-flags: -Z borrowck=ast -//[nll]compile-flags: -Z borrowck=migrate -Z two-phase-borrows - -// ignore-compare-mode-nll - -#![feature(dropck_eyepatch, rustc_attrs)] +#![feature(dropck_eyepatch)] // The point of this test is to illustrate that the `#[may_dangle]` // attribute specifically allows, in the context of a type @@ -64,48 +54,70 @@ unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } } -fn main() { #![rustc_error] // rust-lang/rust#49855 + +fn main() { use std::cell::Cell; - let c_long; - let (c, mut dt, mut dr, mut pt, mut pr, st, sr, c_shortest) - : (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>, Cell<_>); - c_long = Cell::new(1); - c = Cell::new(1); - c_shortest = Cell::new(1); - - // No error: sufficiently long-lived state can be referenced in dtors - dt = Dt("dt", &c_long); - dr = Dr("dr", &c_long); - - // Error: destructor order imprecisely modelled - dt = Dt("dt", &c); - //[ast]~^ ERROR `c` does not live long enough - dr = Dr("dr", &c); - //[ast]~^ ERROR `c` does not live long enough - - // Error: `c_shortest` dies too soon for the references in dtors to be valid. - dt = Dt("dt", &c_shortest); - //[ast]~^ ERROR `c_shortest` does not live long enough - //[nll]~^^ ERROR `c_shortest` does not live long enough - dr = Dr("dr", &c_shortest); - //[ast]~^ ERROR `c_shortest` does not live long enough - - // No error: Drop impl asserts .1 (A and &'a _) are not accessed - pt = Pt("pt", &c_shortest, &c_long); - pr = Pr("pr", &c_shortest, &c_long); - - // Error: Drop impl's assertion does not apply to `B` nor `&'b _` - pt = Pt("pt", &c_long, &c_shortest); - //[ast]~^ ERROR `c_shortest` does not live long enough - pr = Pr("pr", &c_long, &c_shortest); - //[ast]~^ ERROR `c_shortest` does not live long enough - - // No error: St and Sr have no destructor. - st = St("st", &c_shortest); - sr = Sr("sr", &c_shortest); - - println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); - use_imm(sr.1); use_imm(st.1); use_imm(pr.1); use_imm(pt.1); use_imm(dr.1); use_imm(dt.1); -} + // We use separate blocks with separate variable to prevent the error + // messages from being deduplicated. + + { + let c_long; + let (mut dt, mut dr): (Dt<_>, Dr<_>); + c_long = Cell::new(1); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long); + dr = Dr("dr", &c_long); + } + + { + let (c, mut dt, mut dr): (Cell<_>, Dt<_>, Dr<_>); + c = Cell::new(1); + + // No Error: destructor order precisely modelled + dt = Dt("dt", &c); + dr = Dr("dr", &c); + } + + { + let (mut dt, mut dr, c_shortest): (Dt<_>, Dr<_>, Cell<_>); + c_shortest = Cell::new(1); + + // Error: `c_shortest` dies too soon for the references in dtors to be valid. + dt = Dt("dt", &c_shortest); + //~^ ERROR `c_shortest` does not live long enough + dr = Dr("dr", &c_shortest); + } + + { + let c_long; + let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>); + c_long = Cell::new(1); + c_shortest = Cell::new(1); + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c_shortest, &c_long); + pr = Pr("pr", &c_shortest, &c_long); + } + + { + let c_long; + let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>); + c_long = Cell::new(1); + c_shortest = Cell::new(1); + // Error: Drop impl's assertion does not apply to `B` nor `&'b _` + pt = Pt("pt", &c_long, &c_shortest); + //~^ ERROR `c_shortest` does not live long enough + pr = Pr("pr", &c_long, &c_shortest); + } + + { + let (st, sr, c_shortest): (St<_>, Sr<_>, Cell<_>); + c_shortest = Cell::new(1); + // No error: St and Sr have no destructor. + st = St("st", &c_shortest); + sr = Sr("sr", &c_shortest); + } +} fn use_imm(_: &T) { } diff --git a/src/test/ui/dropck/dropck-eyepatch.stderr b/src/test/ui/dropck/dropck-eyepatch.stderr new file mode 100644 index 0000000000000..21295e6c6019e --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch.stderr @@ -0,0 +1,31 @@ +error[E0597]: `c_shortest` does not live long enough + --> $DIR/dropck-eyepatch.rs:88:23 + | +LL | dt = Dt("dt", &c_shortest); + | ^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | `c_shortest` dropped here while still borrowed + | borrow might be used here, when `dt` is dropped and runs the `Drop` code for type `Dt` + | + = note: values in a scope are dropped in the opposite order they are defined + +error[E0597]: `c_shortest` does not live long enough + --> $DIR/dropck-eyepatch.rs:110:32 + | +LL | pt = Pt("pt", &c_long, &c_shortest); + | ^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | `c_shortest` dropped here while still borrowed + | borrow might be used here, when `pt` is dropped and runs the `Drop` code for type `Pt` + | + = note: values in a scope are dropped in the opposite order they are defined + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/dropck/dropck-union.nll.stderr b/src/test/ui/dropck/dropck-union.nll.stderr deleted file mode 100644 index 667bb7221aacd..0000000000000 --- a/src/test/ui/dropck/dropck-union.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0597]: `v` does not live long enough - --> $DIR/dropck-union.rs:39:18 - | -LL | v.0.set(Some(&v)); //~ ERROR: `v` does not live long enough - | ^^ borrowed value does not live long enough -LL | } - | - - | | - | `v` dropped here while still borrowed - | borrow might be used here, when `v` is dropped and runs the `Drop` code for type `Wrap` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/dropck/dropck-union.stderr b/src/test/ui/dropck/dropck-union.stderr index 6cb3c139132f3..228744326f947 100644 --- a/src/test/ui/dropck/dropck-union.stderr +++ b/src/test/ui/dropck/dropck-union.stderr @@ -1,12 +1,13 @@ error[E0597]: `v` does not live long enough - --> $DIR/dropck-union.rs:39:19 + --> $DIR/dropck-union.rs:39:18 | -LL | v.0.set(Some(&v)); //~ ERROR: `v` does not live long enough - | ^ borrowed value does not live long enough +LL | v.0.set(Some(&v)); + | ^^ borrowed value does not live long enough LL | } - | - `v` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created + | - + | | + | `v` dropped here while still borrowed + | borrow might be used here, when `v` is dropped and runs the `Drop` code for type `Wrap` error: aborting due to previous error diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr index 317ac7674311a..dd0c438f421c6 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr @@ -1,10 +1,10 @@ error[E0320]: overflow while adding drop-check rules for FingerTree --> $DIR/dropck_no_diverge_on_nonregular_1.rs:24:9 | -LL | let ft = //~ ERROR overflow while adding drop-check rules for FingerTree +LL | let ft = | ^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error[E0320]: overflow while adding drop-check rules for FingerTree --> $DIR/dropck_no_diverge_on_nonregular_1.rs:25:9 @@ -12,8 +12,7 @@ error[E0320]: overflow while adding drop-check rules for FingerTree LL | FingerTree::Single(1); | ^^^^^^^^^^^^^^^^^^^^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0320`. diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr index b87e7a111493e..769d5aed664f3 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr @@ -1,10 +1,10 @@ error[E0320]: overflow while adding drop-check rules for FingerTree --> $DIR/dropck_no_diverge_on_nonregular_2.rs:23:9 | -LL | let ft = //~ ERROR overflow while adding drop-check rules for FingerTree +LL | let ft = | ^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error[E0320]: overflow while adding drop-check rules for FingerTree --> $DIR/dropck_no_diverge_on_nonregular_2.rs:24:9 @@ -12,8 +12,7 @@ error[E0320]: overflow while adding drop-check rules for FingerTree LL | FingerTree::Single(1); | ^^^^^^^^^^^^^^^^^^^^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0320`. diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr index 799ee45a2022d..de8afdcc7cdab 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr @@ -1,10 +1,10 @@ error[E0320]: overflow while adding drop-check rules for std::option::Option> --> $DIR/dropck_no_diverge_on_nonregular_3.rs:32:9 | -LL | let w = //~ ERROR overflow while adding drop-check rules for std::option +LL | let w = | ^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error[E0320]: overflow while adding drop-check rules for std::option::Option> --> $DIR/dropck_no_diverge_on_nonregular_3.rs:33:9 @@ -12,7 +12,7 @@ error[E0320]: overflow while adding drop-check rules for std::option::Option); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error[E0320]: overflow while adding drop-check rules for Wrapper --> $DIR/dropck_no_diverge_on_nonregular_3.rs:33:14 @@ -20,8 +20,7 @@ error[E0320]: overflow while adding drop-check rules for Wrapper LL | Some(Wrapper::Simple::); | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0320`. diff --git a/src/test/ui/dropck/dropck_trait_cycle_checked.nll.stderr b/src/test/ui/dropck/dropck_trait_cycle_checked.nll.stderr deleted file mode 100644 index 28b9656c6fd17..0000000000000 --- a/src/test/ui/dropck/dropck_trait_cycle_checked.nll.stderr +++ /dev/null @@ -1,73 +0,0 @@ -error[E0597]: `o2` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:111:13 - | -LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` -LL | o1.set0(&o2); //~ ERROR `o2` does not live long enough - | ^^^ borrowed value does not live long enough -... -LL | } - | - `o2` dropped here while still borrowed - -error[E0597]: `o3` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:112:13 - | -LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o3` is borrowed for `'static` -LL | o1.set0(&o2); //~ ERROR `o2` does not live long enough -LL | o1.set1(&o3); //~ ERROR `o3` does not live long enough - | ^^^ borrowed value does not live long enough -... -LL | } - | - `o3` dropped here while still borrowed - -error[E0597]: `o2` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:113:13 - | -LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` -... -LL | o2.set0(&o2); //~ ERROR `o2` does not live long enough - | ^^^ borrowed value does not live long enough -... -LL | } - | - `o2` dropped here while still borrowed - -error[E0597]: `o3` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:114:13 - | -LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o3` is borrowed for `'static` -... -LL | o2.set1(&o3); //~ ERROR `o3` does not live long enough - | ^^^ borrowed value does not live long enough -... -LL | } - | - `o3` dropped here while still borrowed - -error[E0597]: `o1` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:115:13 - | -LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o1` is borrowed for `'static` -... -LL | o3.set0(&o1); //~ ERROR `o1` does not live long enough - | ^^^ borrowed value does not live long enough -LL | o3.set1(&o2); //~ ERROR `o2` does not live long enough -LL | } - | - `o1` dropped here while still borrowed - -error[E0597]: `o2` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:116:13 - | -LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` -... -LL | o3.set1(&o2); //~ ERROR `o2` does not live long enough - | ^^^ borrowed value does not live long enough -LL | } - | - `o2` dropped here while still borrowed - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/dropck/dropck_trait_cycle_checked.rs b/src/test/ui/dropck/dropck_trait_cycle_checked.rs index 128bbb04ee0ea..bea77dc9f5c4f 100644 --- a/src/test/ui/dropck/dropck_trait_cycle_checked.rs +++ b/src/test/ui/dropck/dropck_trait_cycle_checked.rs @@ -63,14 +63,14 @@ impl Drop for CheckId { } trait Obj<'a> : HasId { - fn set0(&self, b: &'a Box>); - fn set1(&self, b: &'a Box>); + fn set0(&self, b: &'a Box>); + fn set1(&self, b: &'a Box>); } struct O<'a> { id: Id, - obj0: CheckId>>>>, - obj1: CheckId>>>>, + obj0: CheckId>>>>, + obj1: CheckId>>>>, } impl<'a> HasId for O<'a> { @@ -87,7 +87,7 @@ impl<'a> O<'a> { } } -impl<'a> HasId for Cell>>> { +impl<'a> HasId for Cell>>> { fn count(&self) -> usize { match self.get() { None => 1, @@ -97,17 +97,17 @@ impl<'a> HasId for Cell>>> { } impl<'a> Obj<'a> for O<'a> { - fn set0(&self, b: &'a Box>) { + fn set0(&self, b: &'a Box>) { self.obj0.v.set(Some(b)) } - fn set1(&self, b: &'a Box>) { + fn set1(&self, b: &'a Box>) { self.obj1.v.set(Some(b)) } } fn f() { - let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); + let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); o1.set0(&o2); //~ ERROR `o2` does not live long enough o1.set1(&o3); //~ ERROR `o3` does not live long enough o2.set0(&o2); //~ ERROR `o2` does not live long enough diff --git a/src/test/ui/dropck/dropck_trait_cycle_checked.stderr b/src/test/ui/dropck/dropck_trait_cycle_checked.stderr index 0e4bd829a949d..1e779208e58a5 100644 --- a/src/test/ui/dropck/dropck_trait_cycle_checked.stderr +++ b/src/test/ui/dropck/dropck_trait_cycle_checked.stderr @@ -1,67 +1,72 @@ error[E0597]: `o2` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:111:14 + --> $DIR/dropck_trait_cycle_checked.rs:111:13 | -LL | o1.set0(&o2); //~ ERROR `o2` does not live long enough - | ^^ borrowed value does not live long enough +LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); + | -------- cast requires that `o2` is borrowed for `'static` +LL | o1.set0(&o2); + | ^^^ borrowed value does not live long enough ... LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - `o2` dropped here while still borrowed error[E0597]: `o3` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:112:14 + --> $DIR/dropck_trait_cycle_checked.rs:112:13 | -LL | o1.set1(&o3); //~ ERROR `o3` does not live long enough - | ^^ borrowed value does not live long enough +LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); + | -------- cast requires that `o3` is borrowed for `'static` +LL | o1.set0(&o2); +LL | o1.set1(&o3); + | ^^^ borrowed value does not live long enough ... LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - `o3` dropped here while still borrowed error[E0597]: `o2` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:113:14 + --> $DIR/dropck_trait_cycle_checked.rs:113:13 | -LL | o2.set0(&o2); //~ ERROR `o2` does not live long enough - | ^^ borrowed value does not live long enough +LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); + | -------- cast requires that `o2` is borrowed for `'static` +... +LL | o2.set0(&o2); + | ^^^ borrowed value does not live long enough ... LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - `o2` dropped here while still borrowed error[E0597]: `o3` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:114:14 + --> $DIR/dropck_trait_cycle_checked.rs:114:13 | -LL | o2.set1(&o3); //~ ERROR `o3` does not live long enough - | ^^ borrowed value does not live long enough +LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); + | -------- cast requires that `o3` is borrowed for `'static` +... +LL | o2.set1(&o3); + | ^^^ borrowed value does not live long enough ... LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - `o3` dropped here while still borrowed error[E0597]: `o1` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:115:14 + --> $DIR/dropck_trait_cycle_checked.rs:115:13 | -LL | o3.set0(&o1); //~ ERROR `o1` does not live long enough - | ^^ borrowed value does not live long enough -LL | o3.set1(&o2); //~ ERROR `o2` does not live long enough +LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); + | -------- cast requires that `o1` is borrowed for `'static` +... +LL | o3.set0(&o1); + | ^^^ borrowed value does not live long enough +LL | o3.set1(&o2); LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - `o1` dropped here while still borrowed error[E0597]: `o2` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:116:14 + --> $DIR/dropck_trait_cycle_checked.rs:116:13 | -LL | o3.set1(&o2); //~ ERROR `o2` does not live long enough - | ^^ borrowed value does not live long enough +LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); + | -------- cast requires that `o2` is borrowed for `'static` +... +LL | o3.set1(&o2); + | ^^^ borrowed value does not live long enough LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - `o2` dropped here while still borrowed error: aborting due to 6 previous errors diff --git a/src/test/ui/dst/dst-bad-assign-2.rs b/src/test/ui/dst/dst-bad-assign-2.rs index b4f72d034f5c5..7ba31bf2e5172 100644 --- a/src/test/ui/dst/dst-bad-assign-2.rs +++ b/src/test/ui/dst/dst-bad-assign-2.rs @@ -30,8 +30,8 @@ impl ToBar for Bar1 { pub fn main() { // Assignment. - let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; - let z: Box = Box::new(Bar1 {f: 36}); + let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + let z: Box = Box::new(Bar1 {f: 36}); f5.ptr = *z; //~^ ERROR the size for values of type diff --git a/src/test/ui/dst/dst-bad-assign-3.rs b/src/test/ui/dst/dst-bad-assign-3.rs index 5124abc7d8222..691909a231743 100644 --- a/src/test/ui/dst/dst-bad-assign-3.rs +++ b/src/test/ui/dst/dst-bad-assign-3.rs @@ -28,8 +28,8 @@ impl ToBar for Bar1 { pub fn main() { // Assignment. - let f5: &mut Fat = &mut (5, "some str", Bar1 {f :42}); - let z: Box = Box::new(Bar1 {f: 36}); + let f5: &mut Fat = &mut (5, "some str", Bar1 {f :42}); + let z: Box = Box::new(Bar1 {f: 36}); f5.2 = Bar1 {f: 36}; //~^ ERROR mismatched types //~| expected type `dyn ToBar` diff --git a/src/test/ui/dst/dst-bad-assign-3.stderr b/src/test/ui/dst/dst-bad-assign-3.stderr index 0c4f86613196d..8c80ec7aac1dd 100644 --- a/src/test/ui/dst/dst-bad-assign-3.stderr +++ b/src/test/ui/dst/dst-bad-assign-3.stderr @@ -19,5 +19,5 @@ LL | f5.2 = Bar1 {f: 36}; error: aborting due to 2 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/dst/dst-bad-assign.rs b/src/test/ui/dst/dst-bad-assign.rs index 003c80b4dc423..4f2648653f051 100644 --- a/src/test/ui/dst/dst-bad-assign.rs +++ b/src/test/ui/dst/dst-bad-assign.rs @@ -30,8 +30,8 @@ impl ToBar for Bar1 { pub fn main() { // Assignment. - let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; - let z: Box = Box::new(Bar1 {f: 36}); + let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + let z: Box = Box::new(Bar1 {f: 36}); f5.ptr = Bar1 {f: 36}; //~^ ERROR mismatched types //~| expected type `dyn ToBar` diff --git a/src/test/ui/dst/dst-bad-assign.stderr b/src/test/ui/dst/dst-bad-assign.stderr index a60d9d66f39e6..849b1a62a46f5 100644 --- a/src/test/ui/dst/dst-bad-assign.stderr +++ b/src/test/ui/dst/dst-bad-assign.stderr @@ -19,5 +19,5 @@ LL | f5.ptr = Bar1 {f: 36}; error: aborting due to 2 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/dst/dst-bad-coerce1.rs b/src/test/ui/dst/dst-bad-coerce1.rs index 8ca34234c0317..7ef237e39e36e 100644 --- a/src/test/ui/dst/dst-bad-coerce1.rs +++ b/src/test/ui/dst/dst-bad-coerce1.rs @@ -19,7 +19,7 @@ pub fn main() { // With a trait. let f1 = Fat { ptr: Foo }; let f2: &Fat = &f1; - let f3: &Fat = f2; + let f3: &Fat = f2; //~^ ERROR `Foo: Bar` is not satisfied // Tuple with a vec of isize. @@ -31,6 +31,6 @@ pub fn main() { // Tuple with a trait. let f1 = (Foo,); let f2: &(Foo,) = &f1; - let f3: &(Bar,) = f2; + let f3: &(dyn Bar,) = f2; //~^ ERROR `Foo: Bar` is not satisfied } diff --git a/src/test/ui/dst/dst-bad-coerce1.stderr b/src/test/ui/dst/dst-bad-coerce1.stderr index 34b2d6d3d8beb..a48f37b20be97 100644 --- a/src/test/ui/dst/dst-bad-coerce1.stderr +++ b/src/test/ui/dst/dst-bad-coerce1.stderr @@ -8,10 +8,10 @@ LL | let f3: &Fat<[usize]> = f2; found type `&Fat<[isize; 3]>` error[E0277]: the trait bound `Foo: Bar` is not satisfied - --> $DIR/dst-bad-coerce1.rs:22:25 + --> $DIR/dst-bad-coerce1.rs:22:29 | -LL | let f3: &Fat = f2; - | ^^ the trait `Bar` is not implemented for `Foo` +LL | let f3: &Fat = f2; + | ^^ the trait `Bar` is not implemented for `Foo` | = note: required for the cast to the object type `dyn Bar` @@ -25,14 +25,14 @@ LL | let f3: &([usize],) = f2; found type `&([isize; 3],)` error[E0277]: the trait bound `Foo: Bar` is not satisfied - --> $DIR/dst-bad-coerce1.rs:34:23 + --> $DIR/dst-bad-coerce1.rs:34:27 | -LL | let f3: &(Bar,) = f2; - | ^^ the trait `Bar` is not implemented for `Foo` +LL | let f3: &(dyn Bar,) = f2; + | ^^ the trait `Bar` is not implemented for `Foo` | = note: required for the cast to the object type `dyn Bar` error: aborting due to 4 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/dst/dst-bad-coerce2.rs b/src/test/ui/dst/dst-bad-coerce2.rs index 2bc7ecced0aab..e7ce20b895879 100644 --- a/src/test/ui/dst/dst-bad-coerce2.rs +++ b/src/test/ui/dst/dst-bad-coerce2.rs @@ -17,7 +17,7 @@ pub fn main() { // With a trait. let f1 = Fat { ptr: Foo }; let f2: &Fat = &f1; - let f3: &mut Fat = f2; //~ ERROR mismatched types + let f3: &mut Fat = f2; //~ ERROR mismatched types // Tuple with a vec of ints. let f1 = ([1, 2, 3],); @@ -27,5 +27,5 @@ pub fn main() { // Tuple with a trait. let f1 = (Foo,); let f2: &(Foo,) = &f1; - let f3: &mut (Bar,) = f2; //~ ERROR mismatched types + let f3: &mut (dyn Bar,) = f2; //~ ERROR mismatched types } diff --git a/src/test/ui/dst/dst-bad-coerce2.stderr b/src/test/ui/dst/dst-bad-coerce2.stderr index 6fb5c4b32ef12..d1da9b6ca0749 100644 --- a/src/test/ui/dst/dst-bad-coerce2.stderr +++ b/src/test/ui/dst/dst-bad-coerce2.stderr @@ -1,17 +1,17 @@ error[E0308]: mismatched types --> $DIR/dst-bad-coerce2.rs:15:33 | -LL | let f3: &mut Fat<[isize]> = f2; //~ ERROR mismatched types +LL | let f3: &mut Fat<[isize]> = f2; | ^^ types differ in mutability | = note: expected type `&mut Fat<[isize]>` found type `&Fat<[isize; 3]>` error[E0308]: mismatched types - --> $DIR/dst-bad-coerce2.rs:20:29 + --> $DIR/dst-bad-coerce2.rs:20:33 | -LL | let f3: &mut Fat = f2; //~ ERROR mismatched types - | ^^ types differ in mutability +LL | let f3: &mut Fat = f2; + | ^^ types differ in mutability | = note: expected type `&mut Fat` found type `&Fat` @@ -19,17 +19,17 @@ LL | let f3: &mut Fat = f2; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/dst-bad-coerce2.rs:25:31 | -LL | let f3: &mut ([isize],) = f2; //~ ERROR mismatched types +LL | let f3: &mut ([isize],) = f2; | ^^ types differ in mutability | = note: expected type `&mut ([isize],)` found type `&([isize; 3],)` error[E0308]: mismatched types - --> $DIR/dst-bad-coerce2.rs:30:27 + --> $DIR/dst-bad-coerce2.rs:30:31 | -LL | let f3: &mut (Bar,) = f2; //~ ERROR mismatched types - | ^^ types differ in mutability +LL | let f3: &mut (dyn Bar,) = f2; + | ^^ types differ in mutability | = note: expected type `&mut (dyn Bar,)` found type `&(Foo,)` diff --git a/src/test/ui/dst/dst-bad-coerce3.nll.stderr b/src/test/ui/dst/dst-bad-coerce3.nll.stderr deleted file mode 100644 index 8f1289845e37b..0000000000000 --- a/src/test/ui/dst/dst-bad-coerce3.nll.stderr +++ /dev/null @@ -1,58 +0,0 @@ -error[E0597]: `f1` does not live long enough - --> $DIR/dst-bad-coerce3.rs:16:32 - | -LL | fn baz<'a>() { - | -- lifetime `'a` defined here -... -LL | let f2: &Fat<[isize; 3]> = &f1; //~ ERROR `f1` does not live long enough - | ^^^ borrowed value does not live long enough -LL | let f3: &'a Fat<[isize]> = f2; - | ---------------- type annotation requires that `f1` is borrowed for `'a` -... -LL | } - | - `f1` dropped here while still borrowed - -error[E0597]: `f1` does not live long enough - --> $DIR/dst-bad-coerce3.rs:21:25 - | -LL | fn baz<'a>() { - | -- lifetime `'a` defined here -... -LL | let f2: &Fat = &f1; //~ ERROR `f1` does not live long enough - | ^^^ borrowed value does not live long enough -LL | let f3: &'a Fat = f2; - | ------------ type annotation requires that `f1` is borrowed for `'a` -... -LL | } - | - `f1` dropped here while still borrowed - -error[E0597]: `f1` does not live long enough - --> $DIR/dst-bad-coerce3.rs:26:30 - | -LL | fn baz<'a>() { - | -- lifetime `'a` defined here -... -LL | let f2: &([isize; 3],) = &f1; //~ ERROR `f1` does not live long enough - | ^^^ borrowed value does not live long enough -LL | let f3: &'a ([isize],) = f2; - | -------------- type annotation requires that `f1` is borrowed for `'a` -... -LL | } - | - `f1` dropped here while still borrowed - -error[E0597]: `f1` does not live long enough - --> $DIR/dst-bad-coerce3.rs:31:23 - | -LL | fn baz<'a>() { - | -- lifetime `'a` defined here -... -LL | let f2: &(Foo,) = &f1; //~ ERROR `f1` does not live long enough - | ^^^ borrowed value does not live long enough -LL | let f3: &'a (Bar,) = f2; - | ---------- type annotation requires that `f1` is borrowed for `'a` -LL | } - | - `f1` dropped here while still borrowed - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/dst/dst-bad-coerce3.rs b/src/test/ui/dst/dst-bad-coerce3.rs index 58c988520eb0d..fd5ee3b57bb42 100644 --- a/src/test/ui/dst/dst-bad-coerce3.rs +++ b/src/test/ui/dst/dst-bad-coerce3.rs @@ -19,7 +19,7 @@ fn baz<'a>() { // With a trait. let f1 = Fat { ptr: Foo }; let f2: &Fat = &f1; //~ ERROR `f1` does not live long enough - let f3: &'a Fat = f2; + let f3: &'a Fat = f2; // Tuple with a vec of ints. let f1 = ([1, 2, 3],); @@ -29,7 +29,7 @@ fn baz<'a>() { // Tuple with a trait. let f1 = (Foo,); let f2: &(Foo,) = &f1; //~ ERROR `f1` does not live long enough - let f3: &'a (Bar,) = f2; + let f3: &'a (dyn Bar,) = f2; } pub fn main() { diff --git a/src/test/ui/dst/dst-bad-coerce3.stderr b/src/test/ui/dst/dst-bad-coerce3.stderr index 701a869ee91e7..957e98bbeee96 100644 --- a/src/test/ui/dst/dst-bad-coerce3.stderr +++ b/src/test/ui/dst/dst-bad-coerce3.stderr @@ -1,62 +1,57 @@ error[E0597]: `f1` does not live long enough - --> $DIR/dst-bad-coerce3.rs:16:33 + --> $DIR/dst-bad-coerce3.rs:16:32 | -LL | let f2: &Fat<[isize; 3]> = &f1; //~ ERROR `f1` does not live long enough - | ^^ borrowed value does not live long enough +LL | fn baz<'a>() { + | -- lifetime `'a` defined here +... +LL | let f2: &Fat<[isize; 3]> = &f1; + | ^^^ borrowed value does not live long enough +LL | let f3: &'a Fat<[isize]> = f2; + | ---------------- type annotation requires that `f1` is borrowed for `'a` ... LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:8... - --> $DIR/dst-bad-coerce3.rs:13:8 - | -LL | fn baz<'a>() { - | ^^ + | - `f1` dropped here while still borrowed error[E0597]: `f1` does not live long enough - --> $DIR/dst-bad-coerce3.rs:21:26 + --> $DIR/dst-bad-coerce3.rs:21:25 | -LL | let f2: &Fat = &f1; //~ ERROR `f1` does not live long enough - | ^^ borrowed value does not live long enough +LL | fn baz<'a>() { + | -- lifetime `'a` defined here +... +LL | let f2: &Fat = &f1; + | ^^^ borrowed value does not live long enough +LL | let f3: &'a Fat = f2; + | ---------------- type annotation requires that `f1` is borrowed for `'a` ... LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:8... - --> $DIR/dst-bad-coerce3.rs:13:8 - | -LL | fn baz<'a>() { - | ^^ + | - `f1` dropped here while still borrowed error[E0597]: `f1` does not live long enough - --> $DIR/dst-bad-coerce3.rs:26:31 + --> $DIR/dst-bad-coerce3.rs:26:30 | -LL | let f2: &([isize; 3],) = &f1; //~ ERROR `f1` does not live long enough - | ^^ borrowed value does not live long enough +LL | fn baz<'a>() { + | -- lifetime `'a` defined here +... +LL | let f2: &([isize; 3],) = &f1; + | ^^^ borrowed value does not live long enough +LL | let f3: &'a ([isize],) = f2; + | -------------- type annotation requires that `f1` is borrowed for `'a` ... LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:8... - --> $DIR/dst-bad-coerce3.rs:13:8 - | -LL | fn baz<'a>() { - | ^^ + | - `f1` dropped here while still borrowed error[E0597]: `f1` does not live long enough - --> $DIR/dst-bad-coerce3.rs:31:24 - | -LL | let f2: &(Foo,) = &f1; //~ ERROR `f1` does not live long enough - | ^^ borrowed value does not live long enough -LL | let f3: &'a (Bar,) = f2; -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:8... - --> $DIR/dst-bad-coerce3.rs:13:8 + --> $DIR/dst-bad-coerce3.rs:31:23 | LL | fn baz<'a>() { - | ^^ + | -- lifetime `'a` defined here +... +LL | let f2: &(Foo,) = &f1; + | ^^^ borrowed value does not live long enough +LL | let f3: &'a (dyn Bar,) = f2; + | -------------- type annotation requires that `f1` is borrowed for `'a` +LL | } + | - `f1` dropped here while still borrowed error: aborting due to 4 previous errors diff --git a/src/test/ui/dst/dst-bad-coercions.rs b/src/test/ui/dst/dst-bad-coercions.rs index 9aa697225d5b6..bffef378c921c 100644 --- a/src/test/ui/dst/dst-bad-coercions.rs +++ b/src/test/ui/dst/dst-bad-coercions.rs @@ -12,15 +12,15 @@ pub fn main() { // Test that we cannot convert from *-ptr to &S and &T let x: *const S = &S; let y: &S = x; //~ ERROR mismatched types - let y: &T = x; //~ ERROR mismatched types + let y: &dyn T = x; //~ ERROR mismatched types // Test that we cannot convert from *-ptr to &S and &T (mut version) let x: *mut S = &mut S; let y: &S = x; //~ ERROR mismatched types - let y: &T = x; //~ ERROR mismatched types + let y: &dyn T = x; //~ ERROR mismatched types // Test that we cannot convert an immutable ptr to a mutable one using *-ptrs - let x: &mut T = &S; //~ ERROR mismatched types - let x: *mut T = &S; //~ ERROR mismatched types + let x: &mut dyn T = &S; //~ ERROR mismatched types + let x: *mut dyn T = &S; //~ ERROR mismatched types let x: *mut S = &S; //~ ERROR mismatched types } diff --git a/src/test/ui/dst/dst-bad-coercions.stderr b/src/test/ui/dst/dst-bad-coercions.stderr index df223b7cb96b2..e4bc6ee0010a2 100644 --- a/src/test/ui/dst/dst-bad-coercions.stderr +++ b/src/test/ui/dst/dst-bad-coercions.stderr @@ -1,20 +1,20 @@ error[E0308]: mismatched types --> $DIR/dst-bad-coercions.rs:14:17 | -LL | let y: &S = x; //~ ERROR mismatched types +LL | let y: &S = x; | ^ expected &S, found *-ptr | = note: expected type `&S` found type `*const S` error[E0308]: mismatched types - --> $DIR/dst-bad-coercions.rs:15:17 + --> $DIR/dst-bad-coercions.rs:15:21 | -LL | let y: &T = x; //~ ERROR mismatched types - | ^ - | | - | expected &dyn T, found *-ptr - | help: consider borrowing here: `&x` +LL | let y: &dyn T = x; + | ^ + | | + | expected &dyn T, found *-ptr + | help: consider borrowing here: `&x` | = note: expected type `&dyn T` found type `*const S` @@ -22,38 +22,38 @@ LL | let y: &T = x; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/dst-bad-coercions.rs:19:17 | -LL | let y: &S = x; //~ ERROR mismatched types +LL | let y: &S = x; | ^ expected &S, found *-ptr | = note: expected type `&S` found type `*mut S` error[E0308]: mismatched types - --> $DIR/dst-bad-coercions.rs:20:17 + --> $DIR/dst-bad-coercions.rs:20:21 | -LL | let y: &T = x; //~ ERROR mismatched types - | ^ - | | - | expected &dyn T, found *-ptr - | help: consider borrowing here: `&x` +LL | let y: &dyn T = x; + | ^ + | | + | expected &dyn T, found *-ptr + | help: consider borrowing here: `&x` | = note: expected type `&dyn T` found type `*mut S` error[E0308]: mismatched types - --> $DIR/dst-bad-coercions.rs:23:21 + --> $DIR/dst-bad-coercions.rs:23:25 | -LL | let x: &mut T = &S; //~ ERROR mismatched types - | ^^ types differ in mutability +LL | let x: &mut dyn T = &S; + | ^^ types differ in mutability | = note: expected type `&mut dyn T` found type `&S` error[E0308]: mismatched types - --> $DIR/dst-bad-coercions.rs:24:21 + --> $DIR/dst-bad-coercions.rs:24:25 | -LL | let x: *mut T = &S; //~ ERROR mismatched types - | ^^ types differ in mutability +LL | let x: *mut dyn T = &S; + | ^^ types differ in mutability | = note: expected type `*mut dyn T` found type `&S` @@ -61,7 +61,7 @@ LL | let x: *mut T = &S; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/dst-bad-coercions.rs:25:21 | -LL | let x: *mut S = &S; //~ ERROR mismatched types +LL | let x: *mut S = &S; | ^^ types differ in mutability | = note: expected type `*mut S` diff --git a/src/test/ui/dst/dst-index.nll.stderr b/src/test/ui/dst/dst-index.nll.stderr deleted file mode 100644 index 92e3d2b684a68..0000000000000 --- a/src/test/ui/dst/dst-index.nll.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error[E0161]: cannot move a value of type str: the size of str cannot be statically determined - --> $DIR/dst-index.rs:31:5 - | -LL | S[0]; - | ^^^^ - -error[E0161]: cannot move a value of type dyn std::fmt::Debug: the size of dyn std::fmt::Debug cannot be statically determined - --> $DIR/dst-index.rs:34:5 - | -LL | T[0]; - | ^^^^ - -error[E0507]: cannot move out of borrowed content - --> $DIR/dst-index.rs:31:5 - | -LL | S[0]; - | ^^^^ cannot move out of borrowed content - -error[E0507]: cannot move out of borrowed content - --> $DIR/dst-index.rs:34:5 - | -LL | T[0]; - | ^^^^ cannot move out of borrowed content - -error: aborting due to 4 previous errors - -Some errors occurred: E0161, E0507. -For more information about an error, try `rustc --explain E0161`. diff --git a/src/test/ui/dst/dst-index.rs b/src/test/ui/dst/dst-index.rs index 663c704ff39ac..2f2c5df462699 100644 --- a/src/test/ui/dst/dst-index.rs +++ b/src/test/ui/dst/dst-index.rs @@ -19,9 +19,9 @@ impl Index for S { struct T; impl Index for T { - type Output = Debug + 'static; + type Output = dyn Debug + 'static; - fn index<'a>(&'a self, idx: usize) -> &'a (Debug + 'static) { + fn index<'a>(&'a self, idx: usize) -> &'a (dyn Debug + 'static) { static x: usize = 42; &x } @@ -29,9 +29,9 @@ impl Index for T { fn main() { S[0]; - //~^ ERROR cannot move out of indexed content + //~^ ERROR cannot move out of index of `S` //~^^ ERROR E0161 T[0]; - //~^ ERROR cannot move out of indexed content + //~^ ERROR cannot move out of index of `T` //~^^ ERROR E0161 } diff --git a/src/test/ui/dst/dst-index.stderr b/src/test/ui/dst/dst-index.stderr index 05993f50fa1a5..6cdb0e76e90a2 100644 --- a/src/test/ui/dst/dst-index.stderr +++ b/src/test/ui/dst/dst-index.stderr @@ -4,25 +4,25 @@ error[E0161]: cannot move a value of type str: the size of str cannot be statica LL | S[0]; | ^^^^ -error[E0161]: cannot move a value of type (dyn std::fmt::Debug + 'static): the size of (dyn std::fmt::Debug + 'static) cannot be statically determined +error[E0161]: cannot move a value of type dyn std::fmt::Debug: the size of dyn std::fmt::Debug cannot be statically determined --> $DIR/dst-index.rs:34:5 | LL | T[0]; | ^^^^ -error[E0507]: cannot move out of indexed content +error[E0507]: cannot move out of index of `S` --> $DIR/dst-index.rs:31:5 | LL | S[0]; - | ^^^^ cannot move out of indexed content + | ^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait -error[E0507]: cannot move out of indexed content +error[E0507]: cannot move out of index of `T` --> $DIR/dst-index.rs:34:5 | LL | T[0]; - | ^^^^ cannot move out of indexed content + | ^^^^ move occurs because value has type `dyn std::fmt::Debug`, which does not implement the `Copy` trait error: aborting due to 4 previous errors -Some errors occurred: E0161, E0507. +Some errors have detailed explanations: E0161, E0507. For more information about an error, try `rustc --explain E0161`. diff --git a/src/test/ui/dst/dst-object-from-unsized-type.rs b/src/test/ui/dst/dst-object-from-unsized-type.rs index f4ee1783a2e34..3cd5b1ed6f462 100644 --- a/src/test/ui/dst/dst-object-from-unsized-type.rs +++ b/src/test/ui/dst/dst-object-from-unsized-type.rs @@ -5,22 +5,22 @@ impl Foo for str {} impl Foo for [u8] {} fn test1(t: &T) { - let u: &Foo = t; + let u: &dyn Foo = t; //~^ ERROR the size for values of type } fn test2(t: &T) { - let v: &Foo = t as &Foo; + let v: &dyn Foo = t as &dyn Foo; //~^ ERROR the size for values of type } fn test3() { - let _: &[&Foo] = &["hi"]; + let _: &[&dyn Foo] = &["hi"]; //~^ ERROR the size for values of type } fn test4(x: &[u8]) { - let _: &Foo = x as &Foo; + let _: &dyn Foo = x as &dyn Foo; //~^ ERROR the size for values of type } diff --git a/src/test/ui/dst/dst-object-from-unsized-type.stderr b/src/test/ui/dst/dst-object-from-unsized-type.stderr index 4851ca108285f..55ac625fc985b 100644 --- a/src/test/ui/dst/dst-object-from-unsized-type.stderr +++ b/src/test/ui/dst/dst-object-from-unsized-type.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/dst-object-from-unsized-type.rs:8:19 + --> $DIR/dst-object-from-unsized-type.rs:8:23 | -LL | let u: &Foo = t; - | ^ doesn't have a size known at compile-time +LL | let u: &dyn Foo = t; + | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit @@ -10,10 +10,10 @@ LL | let u: &Foo = t; = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/dst-object-from-unsized-type.rs:13:19 + --> $DIR/dst-object-from-unsized-type.rs:13:23 | -LL | let v: &Foo = t as &Foo; - | ^ doesn't have a size known at compile-time +LL | let v: &dyn Foo = t as &dyn Foo; + | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit @@ -21,20 +21,20 @@ LL | let v: &Foo = t as &Foo; = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/dst-object-from-unsized-type.rs:18:24 + --> $DIR/dst-object-from-unsized-type.rs:18:28 | -LL | let _: &[&Foo] = &["hi"]; - | ^^^^ doesn't have a size known at compile-time +LL | let _: &[&dyn Foo] = &["hi"]; + | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/dst-object-from-unsized-type.rs:23:19 + --> $DIR/dst-object-from-unsized-type.rs:23:23 | -LL | let _: &Foo = x as &Foo; - | ^ doesn't have a size known at compile-time +LL | let _: &dyn Foo = x as &dyn Foo; + | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` = note: to learn more, visit diff --git a/src/test/ui/dst/dst-rvalue.nll.stderr b/src/test/ui/dst/dst-rvalue.nll.stderr deleted file mode 100644 index d0d8f79395971..0000000000000 --- a/src/test/ui/dst/dst-rvalue.nll.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error[E0161]: cannot move a value of type str: the size of str cannot be statically determined - --> $DIR/dst-rvalue.rs:6:28 - | -LL | let _x: Box = box *"hello world"; - | ^^^^^^^^^^^^^^ - -error[E0161]: cannot move a value of type [isize]: the size of [isize] cannot be statically determined - --> $DIR/dst-rvalue.rs:11:32 - | -LL | let _x: Box<[isize]> = box *array; - | ^^^^^^ - -error[E0507]: cannot move out of borrowed content - --> $DIR/dst-rvalue.rs:6:28 - | -LL | let _x: Box = box *"hello world"; - | ^^^^^^^^^^^^^^ cannot move out of borrowed content - -error[E0508]: cannot move out of type `[isize]`, a non-copy slice - --> $DIR/dst-rvalue.rs:11:32 - | -LL | let _x: Box<[isize]> = box *array; - | ^^^^^^ cannot move out of here - -error: aborting due to 4 previous errors - -Some errors occurred: E0161, E0507, E0508. -For more information about an error, try `rustc --explain E0161`. diff --git a/src/test/ui/dst/dst-rvalue.rs b/src/test/ui/dst/dst-rvalue.rs index 86747dad00ddb..aa028396be4ad 100644 --- a/src/test/ui/dst/dst-rvalue.rs +++ b/src/test/ui/dst/dst-rvalue.rs @@ -5,10 +5,10 @@ pub fn main() { let _x: Box = box *"hello world"; //~^ ERROR E0161 - //~^^ ERROR cannot move out of borrowed content + //~^^ ERROR cannot move out of a shared reference let array: &[isize] = &[1, 2, 3]; let _x: Box<[isize]> = box *array; //~^ ERROR E0161 - //~^^ ERROR cannot move out of borrowed content + //~^^ ERROR cannot move out of type `[isize]`, a non-copy slice } diff --git a/src/test/ui/dst/dst-rvalue.stderr b/src/test/ui/dst/dst-rvalue.stderr index 2c92f5dcbf547..6a51c51755880 100644 --- a/src/test/ui/dst/dst-rvalue.stderr +++ b/src/test/ui/dst/dst-rvalue.stderr @@ -10,19 +10,22 @@ error[E0161]: cannot move a value of type [isize]: the size of [isize] cannot be LL | let _x: Box<[isize]> = box *array; | ^^^^^^ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of a shared reference --> $DIR/dst-rvalue.rs:6:28 | LL | let _x: Box = box *"hello world"; - | ^^^^^^^^^^^^^^ cannot move out of borrowed content + | ^^^^^^^^^^^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content +error[E0508]: cannot move out of type `[isize]`, a non-copy slice --> $DIR/dst-rvalue.rs:11:32 | LL | let _x: Box<[isize]> = box *array; - | ^^^^^^ cannot move out of borrowed content + | ^^^^^^ + | | + | cannot move out of here + | move occurs because `*array` has type `[isize]`, which does not implement the `Copy` trait error: aborting due to 4 previous errors -Some errors occurred: E0161, E0507. +Some errors have detailed explanations: E0161, E0507, E0508. For more information about an error, try `rustc --explain E0161`. diff --git a/src/test/ui/duplicate/dupe-symbols-1.stderr b/src/test/ui/duplicate/dupe-symbols-1.stderr index 58aa1e433d164..c46ac0c6ed4fc 100644 --- a/src/test/ui/duplicate/dupe-symbols-1.stderr +++ b/src/test/ui/duplicate/dupe-symbols-1.stderr @@ -2,7 +2,7 @@ error: symbol `fail` is already defined --> $DIR/dupe-symbols-1.rs:10:1 | LL | / pub fn b() { -LL | | //~^ symbol `fail` is already defined +LL | | LL | | } | |_^ diff --git a/src/test/ui/duplicate/dupe-symbols-2.stderr b/src/test/ui/duplicate/dupe-symbols-2.stderr index 65185cd54290c..821bdd03392ba 100644 --- a/src/test/ui/duplicate/dupe-symbols-2.stderr +++ b/src/test/ui/duplicate/dupe-symbols-2.stderr @@ -2,7 +2,7 @@ error: symbol `fail` is already defined --> $DIR/dupe-symbols-2.rs:13:5 | LL | / pub extern fn fail() { -LL | | //~^ symbol `fail` is already defined +LL | | LL | | } | |_____^ diff --git a/src/test/ui/duplicate/dupe-symbols-3.stderr b/src/test/ui/duplicate/dupe-symbols-3.stderr index 5cd618bc9f653..f30c88e4760ee 100644 --- a/src/test/ui/duplicate/dupe-symbols-3.stderr +++ b/src/test/ui/duplicate/dupe-symbols-3.stderr @@ -2,7 +2,7 @@ error: symbol `fail` is already defined --> $DIR/dupe-symbols-3.rs:10:1 | LL | / pub fn fail() { -LL | | //~^ symbol `fail` is already defined +LL | | LL | | } | |_^ diff --git a/src/test/ui/duplicate/dupe-symbols-5.stderr b/src/test/ui/duplicate/dupe-symbols-5.stderr index 3acfdd22a9a3b..cee72660e4ffe 100644 --- a/src/test/ui/duplicate/dupe-symbols-5.stderr +++ b/src/test/ui/duplicate/dupe-symbols-5.stderr @@ -2,7 +2,7 @@ error: symbol `fail` is already defined --> $DIR/dupe-symbols-5.rs:9:1 | LL | / pub fn b() { -LL | | //~^ symbol `fail` is already defined +LL | | LL | | } | |_^ diff --git a/src/test/ui/duplicate/dupe-symbols-7.rs b/src/test/ui/duplicate/dupe-symbols-7.rs index b28f1a40fe93b..b838aaa102ebb 100644 --- a/src/test/ui/duplicate/dupe-symbols-7.rs +++ b/src/test/ui/duplicate/dupe-symbols-7.rs @@ -1,5 +1,9 @@ // // error-pattern: entry symbol `main` defined multiple times + +// FIXME https://github.com/rust-lang/rust/issues/59774 +// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" #![allow(warnings)] #[no_mangle] diff --git a/src/test/ui/duplicate/dupe-symbols-7.stderr b/src/test/ui/duplicate/dupe-symbols-7.stderr index a1dbbb0c685fb..7d033ec3d85fa 100644 --- a/src/test/ui/duplicate/dupe-symbols-7.stderr +++ b/src/test/ui/duplicate/dupe-symbols-7.stderr @@ -1,5 +1,5 @@ error: entry symbol `main` defined multiple times - --> $DIR/dupe-symbols-7.rs:6:1 + --> $DIR/dupe-symbols-7.rs:10:1 | LL | fn main(){} | ^^^^^^^^^^^ diff --git a/src/test/ui/duplicate/duplicate-check-macro-exports.stderr b/src/test/ui/duplicate/duplicate-check-macro-exports.stderr index 97ee9b9b05f76..02f0206c443a2 100644 --- a/src/test/ui/duplicate/duplicate-check-macro-exports.stderr +++ b/src/test/ui/duplicate/duplicate-check-macro-exports.stderr @@ -4,7 +4,7 @@ error[E0255]: the name `panic` is defined multiple times LL | pub use std::panic; | ---------- previous import of the macro `panic` here ... -LL | macro_rules! panic { () => {} } //~ ERROR the name `panic` is defined multiple times +LL | macro_rules! panic { () => {} } | ^^^^^^^^^^^^^^^^^^ `panic` redefined here | = note: `panic` must be defined only once in the macro namespace of this module diff --git a/src/test/ui/duplicate/duplicate-type-parameter.stderr b/src/test/ui/duplicate/duplicate-type-parameter.stderr index 17d48edc35c91..8606479ff6863 100644 --- a/src/test/ui/duplicate/duplicate-type-parameter.stderr +++ b/src/test/ui/duplicate/duplicate-type-parameter.stderr @@ -62,5 +62,5 @@ LL | impl Qux for Option {} error: aborting due to 8 previous errors -Some errors occurred: E0207, E0403. +Some errors have detailed explanations: E0207, E0403. For more information about an error, try `rustc --explain E0207`. diff --git a/src/test/ui/duplicate_entry_error.stderr b/src/test/ui/duplicate_entry_error.stderr index ddb11e19c03de..1892ad38a594b 100644 --- a/src/test/ui/duplicate_entry_error.stderr +++ b/src/test/ui/duplicate_entry_error.stderr @@ -2,7 +2,7 @@ error[E0152]: duplicate lang item found: `panic_impl`. --> $DIR/duplicate_entry_error.rs:10:1 | LL | / fn panic_impl(info: &PanicInfo) -> ! { -LL | | //~^ ERROR: duplicate lang item found: `panic_impl`. +LL | | LL | | loop {} LL | | } | |_^ diff --git a/src/test/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.fixed b/src/test/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.fixed new file mode 100644 index 0000000000000..003736208ed38 --- /dev/null +++ b/src/test/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.fixed @@ -0,0 +1,81 @@ +// Under the 2015 edition with the keyword_idents lint, `dyn` is not +// entirely acceptable as an identifier. We currently do not attempt +// to detect or fix uses of `dyn` under a macro. Since we are testing +// this file via `rustfix`, we want the rustfix output to be +// compilable; so the macros here carefully use `dyn` "correctly." + +// run-rustfix + +#![allow(non_camel_case_types)] +#![deny(keyword_idents)] + +mod outer_mod { + pub mod r#dyn { +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted + pub struct r#dyn; +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted + } +} +use outer_mod::r#dyn::r#dyn; +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted +//~| ERROR `dyn` is a keyword +//~| WARN was previously accepted + +fn main() { + match r#dyn { r#dyn => {} } +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted +//~| ERROR `dyn` is a keyword +//~| WARN was previously accepted + macro_defn::r#dyn(); +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted + + macro_defn::boxed(); +} + +mod macro_defn { + use super::Trait; + + macro_rules! r#dyn { +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted + + // Note that we do not lint nor fix occurrences under macros + ($dyn:tt) => { (Box, Box<$dyn Trait>) } + } + + pub fn r#dyn() -> ::outer_mod::r#dyn::r#dyn { +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted +//~| ERROR `dyn` is a keyword +//~| WARN was previously accepted +//~| ERROR `dyn` is a keyword +//~| WARN was previously accepted + ::outer_mod::r#dyn::r#dyn +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted +//~| ERROR `dyn` is a keyword +//~| WARN was previously accepted + } + + + + pub fn boxed() -> r#dyn!( + //~^ ERROR `dyn` is a keyword + //~| WARN was previously accepted + + // Note that we do not lint nor fix occurrences under macros + dyn + ) + { + (Box::new(1), Box::new(2)) + } +} + +pub trait Trait { } + +impl Trait for u32 { } diff --git a/src/test/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.rs b/src/test/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.rs new file mode 100644 index 0000000000000..0e5c39fc501be --- /dev/null +++ b/src/test/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.rs @@ -0,0 +1,81 @@ +// Under the 2015 edition with the keyword_idents lint, `dyn` is not +// entirely acceptable as an identifier. We currently do not attempt +// to detect or fix uses of `dyn` under a macro. Since we are testing +// this file via `rustfix`, we want the rustfix output to be +// compilable; so the macros here carefully use `dyn` "correctly." + +// run-rustfix + +#![allow(non_camel_case_types)] +#![deny(keyword_idents)] + +mod outer_mod { + pub mod dyn { +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted + pub struct dyn; +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted + } +} +use outer_mod::dyn::dyn; +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted +//~| ERROR `dyn` is a keyword +//~| WARN was previously accepted + +fn main() { + match dyn { dyn => {} } +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted +//~| ERROR `dyn` is a keyword +//~| WARN was previously accepted + macro_defn::dyn(); +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted + + macro_defn::boxed(); +} + +mod macro_defn { + use super::Trait; + + macro_rules! dyn { +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted + + // Note that we do not lint nor fix occurrences under macros + ($dyn:tt) => { (Box, Box<$dyn Trait>) } + } + + pub fn dyn() -> ::outer_mod::dyn::dyn { +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted +//~| ERROR `dyn` is a keyword +//~| WARN was previously accepted +//~| ERROR `dyn` is a keyword +//~| WARN was previously accepted + ::outer_mod::dyn::dyn +//~^ ERROR `dyn` is a keyword +//~| WARN was previously accepted +//~| ERROR `dyn` is a keyword +//~| WARN was previously accepted + } + + + + pub fn boxed() -> dyn!( + //~^ ERROR `dyn` is a keyword + //~| WARN was previously accepted + + // Note that we do not lint nor fix occurrences under macros + dyn + ) + { + (Box::new(1), Box::new(2)) + } +} + +pub trait Trait { } + +impl Trait for u32 { } diff --git a/src/test/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr b/src/test/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr new file mode 100644 index 0000000000000..361727733bc57 --- /dev/null +++ b/src/test/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr @@ -0,0 +1,133 @@ +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:13:13 + | +LL | pub mod dyn { + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | +note: lint level defined here + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:10:9 + | +LL | #![deny(keyword_idents)] + | ^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:16:20 + | +LL | pub struct dyn; + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:21:16 + | +LL | use outer_mod::dyn::dyn; + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:21:21 + | +LL | use outer_mod::dyn::dyn; + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:28:11 + | +LL | match dyn { dyn => {} } + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:28:17 + | +LL | match dyn { dyn => {} } + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:33:17 + | +LL | macro_defn::dyn(); + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:43:18 + | +LL | macro_rules! dyn { + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:51:12 + | +LL | pub fn dyn() -> ::outer_mod::dyn::dyn { + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:51:34 + | +LL | pub fn dyn() -> ::outer_mod::dyn::dyn { + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:51:39 + | +LL | pub fn dyn() -> ::outer_mod::dyn::dyn { + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:58:22 + | +LL | ::outer_mod::dyn::dyn + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:58:27 + | +LL | ::outer_mod::dyn::dyn + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `dyn` is a keyword in the 2018 edition + --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:67:23 + | +LL | pub fn boxed() -> dyn!( + | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: aborting due to 14 previous errors + diff --git a/src/test/ui/dyn-keyword/dyn-2015-idents-in-decl-macros-unlinted.rs b/src/test/ui/dyn-keyword/dyn-2015-idents-in-decl-macros-unlinted.rs new file mode 100644 index 0000000000000..f535791d7fbe4 --- /dev/null +++ b/src/test/ui/dyn-keyword/dyn-2015-idents-in-decl-macros-unlinted.rs @@ -0,0 +1,51 @@ +// compile-pass + +// Under the 2015 edition with the keyword_idents lint, `dyn` is +// not entirely acceptable as an identifier. +// +// We currently do not attempt to detect or fix uses of `dyn` as an +// identifier under a macro, including under the declarative `macro` +// forms from macros 1.2 and macros 2.0. + +#![feature(decl_macro)] +#![allow(non_camel_case_types)] +#![deny(keyword_idents)] + +mod outer_mod { + pub mod r#dyn { + pub struct r#dyn; + } +} + +// Here we are illustrating that the current lint does not flag the +// occurrences of `dyn` in this macro definition; however, it +// certainly *could* (and it would be nice if it did), since these +// occurrences are not compatible with the 2018 edition's +// interpretation of `dyn` as a keyword. +macro defn_has_dyn_idents() { ::outer_mod::dyn::dyn } + +struct X; +trait Trait { fn hello(&self) { }} +impl Trait for X { } + +macro tt_trait($arg:tt) { & $arg Trait } +macro id_trait($id:ident) { & $id Trait } + +fn main() { + defn_has_dyn_idents!(); + + // Here we are illustrating that the current lint does not flag + // the occurrences of `dyn` in these macro invocations. It + // definitely should *not* flag the one in `tt_trait`, since that + // is expanding in a valid fashion to `&dyn Trait`. + // + // It is arguable whether it would be valid to flag the occurrence + // in `id_trait`, since that macro specifies that it takes an + // `ident` as its input. + fn f_tt(x: &X) -> tt_trait!(dyn) { x } + fn f_id(x: &X) -> id_trait!(dyn) { x } + + let x = X; + f_tt(&x).hello(); + f_id(&x).hello(); +} diff --git a/src/test/ui/dyn-keyword/dyn-2015-idents-in-macros-unlinted.rs b/src/test/ui/dyn-keyword/dyn-2015-idents-in-macros-unlinted.rs new file mode 100644 index 0000000000000..27e490558689f --- /dev/null +++ b/src/test/ui/dyn-keyword/dyn-2015-idents-in-macros-unlinted.rs @@ -0,0 +1,56 @@ +// compile-pass + +// Under the 2015 edition with the keyword_idents lint, `dyn` is +// not entirely acceptable as an identifier. +// +// We currently do not attempt to detect or fix uses of `dyn` as an +// identifier under a macro. + +#![allow(non_camel_case_types)] +#![deny(keyword_idents)] + +mod outer_mod { + pub mod r#dyn { + pub struct r#dyn; + } +} + +// Here we are illustrating that the current lint does not flag the +// occurrences of `dyn` in this macro definition; however, it +// certainly *could* (and it would be nice if it did), since these +// occurrences are not compatible with the 2018 edition's +// interpretation of `dyn` as a keyword. +macro_rules! defn_has_dyn_idents { + () => { ::outer_mod::dyn::dyn } +} + +struct X; +trait Trait { fn hello(&self) { }} +impl Trait for X { } + +macro_rules! tt_trait { + ($arg:tt) => { & $arg Trait } +} + +macro_rules! id_trait { + ($id:ident) => { & $id Trait } +} + +fn main() { + defn_has_dyn_idents!(); + + // Here we are illustrating that the current lint does not flag + // the occurrences of `dyn` in these macro invocations. It + // definitely should *not* flag the one in `tt_trait`, since that + // is expanding in a valid fashion to `&dyn Trait`. + // + // It is arguable whether it would be valid to flag the occurrence + // in `id_trait`, since that macro specifies that it takes an + // `ident` as its input. + fn f_tt(x: &X) -> tt_trait!(dyn) { x } + fn f_id(x: &X) -> id_trait!(dyn) { x } + + let x = X; + f_tt(&x).hello(); + f_id(&x).hello(); +} diff --git a/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs b/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs new file mode 100644 index 0000000000000..8cef5c2b34947 --- /dev/null +++ b/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs @@ -0,0 +1,27 @@ +// Under the 2015 edition without the keyword_idents lint, `dyn` is +// entirely acceptable as an identifier. + +// compile-pass + +#![allow(non_camel_case_types)] + +mod outer_mod { + pub mod dyn { + pub struct dyn; + } +} +use outer_mod::dyn::dyn; + +fn main() { + match dyn { dyn => {} } + macro_defn::dyn(); +} +mod macro_defn { + macro_rules! dyn { + () => { ::outer_mod::dyn::dyn } + } + + pub fn dyn() -> ::outer_mod::dyn::dyn { + dyn!() + } +} diff --git a/src/test/ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs b/src/test/ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs new file mode 100644 index 0000000000000..ff3830d61755a --- /dev/null +++ b/src/test/ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs @@ -0,0 +1,25 @@ +// compile-pass + +// rust-lang/rust#56327: Some occurrences of `dyn` within a macro are +// not instances of identifiers, and thus should *not* be caught by the +// keyword_ident lint. +// +// Otherwise, rustfix replaces the type `Box` with +// `Box`, which is injecting a bug rather than fixing +// anything. + +#![deny(rust_2018_compatibility)] + +macro_rules! foo { + () => { + fn generated_foo() { + let _x: Box; + } + } +} + +foo!(); + +fn main() { + generated_foo(); +} diff --git a/src/test/ui/dyn-trait-compatibility.stderr b/src/test/ui/dyn-trait-compatibility.stderr index aef785a75b912..7210a11f35070 100644 --- a/src/test/ui/dyn-trait-compatibility.stderr +++ b/src/test/ui/dyn-trait-compatibility.stderr @@ -48,5 +48,5 @@ LL | type A3 = dyn<::dyn>; error: aborting due to 8 previous errors -Some errors occurred: E0412, E0433. +Some errors have detailed explanations: E0412, E0433. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/e0119/conflict-with-std.stderr b/src/test/ui/e0119/conflict-with-std.stderr deleted file mode 100644 index 1cfb3c1dabae4..0000000000000 --- a/src/test/ui/e0119/conflict-with-std.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error[E0119]: conflicting implementations of trait `std::convert::AsRef` for type `std::boxed::Box`: - --> $DIR/conflict-with-std.rs:6:1 - | -LL | impl AsRef for Box { //~ ERROR conflicting implementations - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: conflicting implementation in crate `alloc`: - - impl std::convert::AsRef for std::boxed::Box - where T: ?Sized; - -error[E0119]: conflicting implementations of trait `std::convert::From` for type `S`: - --> $DIR/conflict-with-std.rs:13:1 - | -LL | impl From for S { //~ ERROR conflicting implementations - | ^^^^^^^^^^^^^^^^^^ - | - = note: conflicting implementation in crate `core`: - - impl std::convert::From for T; - -error[E0119]: conflicting implementations of trait `std::convert::TryFrom` for type `X`: - --> $DIR/conflict-with-std.rs:20:1 - | -LL | impl TryFrom for X { //~ ERROR conflicting implementations - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: conflicting implementation in crate `core`: - - impl std::convert::TryFrom for T - where U: std::convert::Into; - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/editions/edition-deny-async-fns-2015.stderr b/src/test/ui/editions/edition-deny-async-fns-2015.stderr deleted file mode 100644 index 1ad907aa7eb43..0000000000000 --- a/src/test/ui/editions/edition-deny-async-fns-2015.stderr +++ /dev/null @@ -1,58 +0,0 @@ -error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:5:1 - | -LL | async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition - | ^^^^^ - -error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:7:12 - | -LL | fn baz() { async fn foo() {} } //~ ERROR `async fn` is not permitted in the 2015 edition - | ^^^^^ - -error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:10:5 - | -LL | async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition - | ^^^^^ - -error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:9:1 - | -LL | async fn async_baz() { //~ ERROR `async fn` is not permitted in the 2015 edition - | ^^^^^ - -error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:32:9 - | -LL | async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition - | ^^^^^ - -error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:28:9 - | -LL | async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition - | ^^^^^ - -error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:16:5 - | -LL | async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition - | ^^^^^ - -error[E0706]: trait fns cannot be declared `async` - --> $DIR/edition-deny-async-fns-2015.rs:20:5 - | -LL | async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition - | ^^^^^^^^^^^^^^^^^ - -error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:20:5 - | -LL | async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition - | ^^^^^ - -error: aborting due to 9 previous errors - -Some errors occurred: E0670, E0706. -For more information about an error, try `rustc --explain E0670`. diff --git a/src/test/ui/editions/edition-imports-2015.stderr b/src/test/ui/editions/edition-imports-2015.stderr index 816ab21d81426..4aba5323cc575 100644 --- a/src/test/ui/editions/edition-imports-2015.stderr +++ b/src/test/ui/editions/edition-imports-2015.stderr @@ -1,7 +1,7 @@ error: cannot glob-import all possible crates --> $DIR/edition-imports-2015.rs:23:5 | -LL | gen_glob!(); //~ ERROR cannot glob-import all possible crates +LL | gen_glob!(); | ^^^^^^^^^^^^ | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/editions/edition-imports-2018.stderr b/src/test/ui/editions/edition-imports-2018.stderr index 944f42ee0451b..6ef49b6256058 100644 --- a/src/test/ui/editions/edition-imports-2018.stderr +++ b/src/test/ui/editions/edition-imports-2018.stderr @@ -1,7 +1,7 @@ error: cannot glob-import all possible crates --> $DIR/edition-imports-2018.rs:24:5 | -LL | gen_glob!(); //~ ERROR cannot glob-import all possible crates +LL | gen_glob!(); | ^^^^^^^^^^^^ | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/editions/edition-imports-virtual-2015-ambiguity.rs b/src/test/ui/editions/edition-imports-virtual-2015-ambiguity.rs index 53ec3867f0110..940b0c3c63db0 100644 --- a/src/test/ui/editions/edition-imports-virtual-2015-ambiguity.rs +++ b/src/test/ui/editions/edition-imports-virtual-2015-ambiguity.rs @@ -1,3 +1,4 @@ +// compile-pass // edition:2018 // compile-flags:--extern edition_imports_2015 // aux-build:edition-imports-2015.rs @@ -12,8 +13,7 @@ mod check { pub struct Ambiguous {} fn check() { - edition_imports_2015::gen_ambiguous!(); //~ ERROR `Ambiguous` is ambiguous - //~| ERROR `edition_imports_2015` is ambiguous + edition_imports_2015::gen_ambiguous!(); // OK } } diff --git a/src/test/ui/editions/edition-imports-virtual-2015-ambiguity.stderr b/src/test/ui/editions/edition-imports-virtual-2015-ambiguity.stderr deleted file mode 100644 index ac2bf21c5c0ba..0000000000000 --- a/src/test/ui/editions/edition-imports-virtual-2015-ambiguity.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error[E0659]: `Ambiguous` is ambiguous (name vs any other name during import resolution) - --> $DIR/edition-imports-virtual-2015-ambiguity.rs:15:9 - | -LL | edition_imports_2015::gen_ambiguous!(); //~ ERROR `Ambiguous` is ambiguous - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ambiguous name - | -note: `Ambiguous` could refer to the struct defined here - --> $DIR/edition-imports-virtual-2015-ambiguity.rs:9:1 - | -LL | pub struct Ambiguous {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - = help: use `crate::Ambiguous` to refer to this struct unambiguously -note: `Ambiguous` could also refer to the struct defined here - --> $DIR/edition-imports-virtual-2015-ambiguity.rs:12:5 - | -LL | pub struct Ambiguous {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - = help: use `self::Ambiguous` to refer to this struct unambiguously - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) - -error[E0659]: `edition_imports_2015` is ambiguous (name in the crate root vs extern crate during absolute path resolution) - --> $DIR/edition-imports-virtual-2015-ambiguity.rs:15:9 - | -LL | edition_imports_2015::gen_ambiguous!(); //~ ERROR `Ambiguous` is ambiguous - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ambiguous name - | - = note: `edition_imports_2015` could refer to an extern crate passed with `--extern` -note: `edition_imports_2015` could also refer to the module defined here - --> $DIR/edition-imports-virtual-2015-ambiguity.rs:5:1 - | -LL | / mod edition_imports_2015 { -LL | | pub struct Path; -LL | | } - | |_^ - = help: use `crate::edition_imports_2015` to refer to this module unambiguously - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0659`. diff --git a/src/test/ui/editions/edition-imports-virtual-2015-gated.rs b/src/test/ui/editions/edition-imports-virtual-2015-gated.rs index a1bf4f5eb51dc..634d3e9a443fa 100644 --- a/src/test/ui/editions/edition-imports-virtual-2015-gated.rs +++ b/src/test/ui/editions/edition-imports-virtual-2015-gated.rs @@ -1,12 +1,11 @@ // edition:2018 // aux-build:edition-imports-2015.rs -// error-pattern: imports can only refer to extern crate names passed with `--extern` #[macro_use] extern crate edition_imports_2015; mod check { - gen_gated!(); + gen_gated!(); //~ ERROR unresolved import `E` } fn main() {} diff --git a/src/test/ui/editions/edition-imports-virtual-2015-gated.stderr b/src/test/ui/editions/edition-imports-virtual-2015-gated.stderr index 7c78fbb26a1b8..e6d0f18a67722 100644 --- a/src/test/ui/editions/edition-imports-virtual-2015-gated.stderr +++ b/src/test/ui/editions/edition-imports-virtual-2015-gated.stderr @@ -1,20 +1,11 @@ -error: imports can only refer to extern crate names passed with `--extern` in macros originating from 2015 edition - --> <::edition_imports_2015::gen_gated macros>:1:50 - | -LL | ( ) => { fn check_gated ( ) { enum E { A } use E :: * ; } } - | ^ - | - ::: $DIR/edition-imports-virtual-2015-gated.rs:9:5 +error[E0432]: unresolved import `E` + --> $DIR/edition-imports-virtual-2015-gated.rs:8:5 | LL | gen_gated!(); - | ------------- not an extern crate passed with `--extern` - | -note: this import refers to the enum defined here - --> $DIR/edition-imports-virtual-2015-gated.rs:9:5 + | ^^^^^^^^^^^^^ could not find `E` in `{{root}}` | -LL | gen_gated!(); - | ^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error +For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/editions/edition-keywords-2015-2015-parsing.stderr b/src/test/ui/editions/edition-keywords-2015-2015-parsing.stderr index f2a9da71ca56b..3435fdfd72570 100644 --- a/src/test/ui/editions/edition-keywords-2015-2015-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2015-2015-parsing.stderr @@ -1,13 +1,13 @@ error: no rules expected the token `r#async` --> $DIR/edition-keywords-2015-2015-parsing.rs:16:31 | -LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` +LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call error: no rules expected the token `async` --> $DIR/edition-keywords-2015-2015-parsing.rs:17:35 | -LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` +LL | r#async = consumes_async_raw!(async); | ^^^^^ no rules expected this token in macro call error: aborting due to 2 previous errors diff --git a/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr b/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr index af1ac19c837d5..9724f78db6618 100644 --- a/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr +++ b/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr @@ -1,7 +1,7 @@ error: expected identifier, found reserved keyword `async` --> $DIR/edition-keywords-2015-2018-expansion.rs:8:5 | -LL | produces_async! {} //~ ERROR expected identifier, found reserved keyword +LL | produces_async! {} | ^^^^^^^^^^^^^^^^^^ expected identifier, found reserved keyword | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/editions/edition-keywords-2015-2018-parsing.stderr b/src/test/ui/editions/edition-keywords-2015-2018-parsing.stderr index fbb3b8bc75690..6e86d746f5442 100644 --- a/src/test/ui/editions/edition-keywords-2015-2018-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2015-2018-parsing.stderr @@ -1,13 +1,13 @@ error: no rules expected the token `r#async` --> $DIR/edition-keywords-2015-2018-parsing.rs:16:31 | -LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` +LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call error: no rules expected the token `async` --> $DIR/edition-keywords-2015-2018-parsing.rs:17:35 | -LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` +LL | r#async = consumes_async_raw!(async); | ^^^^^ no rules expected this token in macro call error: aborting due to 2 previous errors diff --git a/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr b/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr index 52399362482bc..0d8850c2397c6 100644 --- a/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -1,33 +1,33 @@ error: expected identifier, found reserved keyword `async` --> $DIR/edition-keywords-2018-2015-parsing.rs:8:13 | -LL | let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async` +LL | let mut async = 1; | ^^^^^ expected identifier, found reserved keyword help: you can escape reserved keywords to use them as identifiers | -LL | let mut r#async = 1; //~ ERROR expected identifier, found reserved keyword `async` +LL | let mut r#async = 1; | ^^^^^^^ error: expected identifier, found reserved keyword `async` --> $DIR/edition-keywords-2018-2015-parsing.rs:18:13 | -LL | module::async(); //~ ERROR expected identifier, found reserved keyword `async` +LL | module::async(); | ^^^^^ expected identifier, found reserved keyword help: you can escape reserved keywords to use them as identifiers | -LL | module::r#async(); //~ ERROR expected identifier, found reserved keyword `async` +LL | module::r#async(); | ^^^^^^^ error: no rules expected the token `r#async` --> $DIR/edition-keywords-2018-2015-parsing.rs:12:31 | -LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` +LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call error: no rules expected the token `async` --> $DIR/edition-keywords-2018-2015-parsing.rs:13:35 | -LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` +LL | r#async = consumes_async_raw!(async); | ^^^^^ no rules expected this token in macro call error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` diff --git a/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr b/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr index d997c3d8a421a..ab601c8d8a707 100644 --- a/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr @@ -1,7 +1,7 @@ error: expected identifier, found reserved keyword `async` --> $DIR/edition-keywords-2018-2018-expansion.rs:8:5 | -LL | produces_async! {} //~ ERROR expected identifier, found reserved keyword `async` +LL | produces_async! {} | ^^^^^^^^^^^^^^^^^^ expected identifier, found reserved keyword | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr b/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr index 1621368870a52..0604b600d23d0 100644 --- a/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -1,33 +1,33 @@ error: expected identifier, found reserved keyword `async` --> $DIR/edition-keywords-2018-2018-parsing.rs:8:13 | -LL | let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async` +LL | let mut async = 1; | ^^^^^ expected identifier, found reserved keyword help: you can escape reserved keywords to use them as identifiers | -LL | let mut r#async = 1; //~ ERROR expected identifier, found reserved keyword `async` +LL | let mut r#async = 1; | ^^^^^^^ error: expected identifier, found reserved keyword `async` --> $DIR/edition-keywords-2018-2018-parsing.rs:18:13 | -LL | module::async(); //~ ERROR expected identifier, found reserved keyword `async` +LL | module::async(); | ^^^^^ expected identifier, found reserved keyword help: you can escape reserved keywords to use them as identifiers | -LL | module::r#async(); //~ ERROR expected identifier, found reserved keyword `async` +LL | module::r#async(); | ^^^^^^^ error: no rules expected the token `r#async` --> $DIR/edition-keywords-2018-2018-parsing.rs:12:31 | -LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` +LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call error: no rules expected the token `async` --> $DIR/edition-keywords-2018-2018-parsing.rs:13:35 | -LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` +LL | r#async = consumes_async_raw!(async); | ^^^^^ no rules expected this token in macro call error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` diff --git a/src/test/ui/editions/edition-raw-pointer-method-2015.rs b/src/test/ui/editions/edition-raw-pointer-method-2015.rs index a538bca75f67d..3631415fc5f98 100644 --- a/src/test/ui/editions/edition-raw-pointer-method-2015.rs +++ b/src/test/ui/editions/edition-raw-pointer-method-2015.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // edition:2015 // tests that editions work with the tyvar warning-turned-error diff --git a/src/test/ui/editions/edition-raw-pointer-method-2015.stderr b/src/test/ui/editions/edition-raw-pointer-method-2015.stderr index deea6a71b24f3..508d5df2a7160 100644 --- a/src/test/ui/editions/edition-raw-pointer-method-2015.stderr +++ b/src/test/ui/editions/edition-raw-pointer-method-2015.stderr @@ -1,11 +1,11 @@ error: type annotations needed - --> $DIR/edition-raw-pointer-method-2015.rs:10:15 + --> $DIR/edition-raw-pointer-method-2015.rs:9:15 | LL | let _ = y.is_null(); | ^^^^^^^ | note: lint level defined here - --> $DIR/edition-raw-pointer-method-2015.rs:6:8 + --> $DIR/edition-raw-pointer-method-2015.rs:5:8 | LL | #[deny(warnings)] | ^^^^^^^^ diff --git a/src/test/ui/editions/edition-raw-pointer-method-2018.rs b/src/test/ui/editions/edition-raw-pointer-method-2018.rs index eabab5e4739ab..af0b2d6bd4aa6 100644 --- a/src/test/ui/editions/edition-raw-pointer-method-2018.rs +++ b/src/test/ui/editions/edition-raw-pointer-method-2018.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // edition:2018 // tests that editions work with the tyvar warning-turned-error diff --git a/src/test/ui/editions/edition-raw-pointer-method-2018.stderr b/src/test/ui/editions/edition-raw-pointer-method-2018.stderr index 03e7f3a9449d6..23452495b4bc6 100644 --- a/src/test/ui/editions/edition-raw-pointer-method-2018.stderr +++ b/src/test/ui/editions/edition-raw-pointer-method-2018.stderr @@ -1,5 +1,5 @@ error[E0699]: the type of this value must be known to call a method on a raw pointer on it - --> $DIR/edition-raw-pointer-method-2018.rs:10:15 + --> $DIR/edition-raw-pointer-method-2018.rs:9:15 | LL | let _ = y.is_null(); | ^^^^^^^ diff --git a/src/test/ui/elide-errors-on-mismatched-tuple.rs b/src/test/ui/elide-errors-on-mismatched-tuple.rs index e68358fd978bf..7d87b0a7756b1 100644 --- a/src/test/ui/elide-errors-on-mismatched-tuple.rs +++ b/src/test/ui/elide-errors-on-mismatched-tuple.rs @@ -13,6 +13,6 @@ impl A { fn main() { let (a, b, c) = (A::new(), A::new()); // This tuple is 2 elements, should be three //~^ ERROR mismatched types - let ts: Vec<&T> = vec![&a, &b, &c]; + let ts: Vec<&dyn T> = vec![&a, &b, &c]; // There is no E0277 error above, as `a`, `b` and `c` are `TyErr` } diff --git a/src/test/ui/emit-artifact-notifications.nll.stderr b/src/test/ui/emit-artifact-notifications.nll.stderr new file mode 100644 index 0000000000000..5547631a4b022 --- /dev/null +++ b/src/test/ui/emit-artifact-notifications.nll.stderr @@ -0,0 +1 @@ +{"artifact":"$TEST_BUILD_DIR/emit-artifact-notifications.nll/libemit_artifact_notifications.rmeta","emit":"metadata"} diff --git a/src/test/ui/emit-artifact-notifications.rs b/src/test/ui/emit-artifact-notifications.rs new file mode 100644 index 0000000000000..2f17f95b7a3be --- /dev/null +++ b/src/test/ui/emit-artifact-notifications.rs @@ -0,0 +1,8 @@ +// compile-flags:--emit=metadata --error-format=json -Z emit-artifact-notifications +// compile-pass +// ignore-pass +// ^-- needed because `--pass check` does not emit the output needed. + +// A very basic test for the emission of artifact notifications in JSON output. + +fn main() {} diff --git a/src/test/ui/emit-artifact-notifications.stderr b/src/test/ui/emit-artifact-notifications.stderr new file mode 100644 index 0000000000000..260d41b8f15cc --- /dev/null +++ b/src/test/ui/emit-artifact-notifications.stderr @@ -0,0 +1 @@ +{"artifact":"$TEST_BUILD_DIR/emit-artifact-notifications/libemit_artifact_notifications.rmeta","emit":"metadata"} diff --git a/src/test/ui/empty/empty-comment.stderr b/src/test/ui/empty/empty-comment.stderr index 908d5710c8a29..116cc83fa9ce5 100644 --- a/src/test/ui/empty/empty-comment.stderr +++ b/src/test/ui/empty/empty-comment.stderr @@ -4,7 +4,7 @@ error: unexpected end of macro invocation LL | macro_rules! one_arg_macro { | -------------------------- when calling this macro ... -LL | one_arg_macro!(/**/); //~ ERROR unexpected end +LL | one_arg_macro!(/**/); | ^^^^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments error: aborting due to previous error diff --git a/src/test/ui/empty/empty-linkname.stderr b/src/test/ui/empty/empty-linkname.stderr index a07a4f1c56746..df41cb894139c 100644 --- a/src/test/ui/empty/empty-linkname.stderr +++ b/src/test/ui/empty/empty-linkname.stderr @@ -1,7 +1,7 @@ error[E0454]: #[link(name = "")] given with empty name --> $DIR/empty-linkname.rs:1:1 | -LL | #[link(name = "")] //~ ERROR: given with empty name +LL | #[link(name = "")] | ^^^^^^^^^^^^^^^^^^ empty name given error: aborting due to previous error diff --git a/src/test/ui/empty/empty-never-array.nll.stderr b/src/test/ui/empty/empty-never-array.nll.stderr new file mode 100644 index 0000000000000..01ee1c3a4d7fa --- /dev/null +++ b/src/test/ui/empty/empty-never-array.nll.stderr @@ -0,0 +1,23 @@ +error[E0005]: refutable pattern in local binding: `T(_, _)` not covered + --> $DIR/empty-never-array.rs:10:9 + | +LL | / enum Helper { +LL | | T(T, [!; 0]), +LL | | #[allow(dead_code)] +LL | | U(U), +LL | | } + | |_- `Helper` defined here +... +LL | let Helper::U(u) = Helper::T(t, []); + | ^^^^^^^^^^^^ pattern `T(_, _)` not covered + +error[E0381]: use of possibly uninitialized variable: `u` + --> $DIR/empty-never-array.rs:12:5 + | +LL | u + | ^ use of possibly uninitialized `u` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0005, E0381. +For more information about an error, try `rustc --explain E0005`. diff --git a/src/test/ui/empty/empty-never-array.rs b/src/test/ui/empty/empty-never-array.rs index 01b99134a445f..ce781da7d47e1 100644 --- a/src/test/ui/empty/empty-never-array.rs +++ b/src/test/ui/empty/empty-never-array.rs @@ -10,6 +10,9 @@ fn transmute(t: T) -> U { let Helper::U(u) = Helper::T(t, []); //~^ ERROR refutable pattern in local binding: `T(_, _)` not covered u + //~^ WARN use of possibly uninitialized variable: `u` + //~| WARN this error has been downgraded to a warning for backwards compatibility + //~| WARN this represents potential undefined behavior in your code and this warning will } fn main() { diff --git a/src/test/ui/empty/empty-never-array.stderr b/src/test/ui/empty/empty-never-array.stderr index e409f14d6ce97..9911dd4683b66 100644 --- a/src/test/ui/empty/empty-never-array.stderr +++ b/src/test/ui/empty/empty-never-array.stderr @@ -1,9 +1,27 @@ error[E0005]: refutable pattern in local binding: `T(_, _)` not covered --> $DIR/empty-never-array.rs:10:9 | -LL | let Helper::U(u) = Helper::T(t, []); - | ^^^^^^^^^^^^ pattern `T(_, _)` not covered +LL | / enum Helper { +LL | | T(T, [!; 0]), +LL | | #[allow(dead_code)] +LL | | U(U), +LL | | } + | |_- `Helper` defined here +... +LL | let Helper::U(u) = Helper::T(t, []); + | ^^^^^^^^^^^^ pattern `T(_, _)` not covered + +warning[E0381]: use of possibly uninitialized variable: `u` + --> $DIR/empty-never-array.rs:12:5 + | +LL | u + | ^ use of possibly uninitialized `u` + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` error: aborting due to previous error -For more information about this error, try `rustc --explain E0005`. +Some errors have detailed explanations: E0005, E0381. +For more information about an error, try `rustc --explain E0005`. diff --git a/src/test/ui/empty/empty-struct-braces-expr.rs b/src/test/ui/empty/empty-struct-braces-expr.rs index 2f2f41ae8c1f0..e33fcb70db775 100644 --- a/src/test/ui/empty/empty-struct-braces-expr.rs +++ b/src/test/ui/empty/empty-struct-braces-expr.rs @@ -19,6 +19,8 @@ fn main() { let xe1 = XEmpty1; //~ ERROR expected value, found struct `XEmpty1` let xe1 = XEmpty1(); //~ ERROR expected function, found struct `XEmpty1` - let xe3 = XE::Empty3; //~ ERROR no variant named `Empty3` found for type - let xe3 = XE::Empty3(); //~ ERROR no variant named `Empty3` found for type + let xe3 = XE::Empty3; //~ ERROR no variant or associated item named `Empty3` found for type + let xe3 = XE::Empty3(); //~ ERROR no variant or associated item named `Empty3` found for type + + XE::Empty1 {}; //~ ERROR no variant `Empty1` in enum `empty_struct::XE` } diff --git a/src/test/ui/empty/empty-struct-braces-expr.stderr b/src/test/ui/empty/empty-struct-braces-expr.stderr index 19844503a4804..b9681db87b67e 100644 --- a/src/test/ui/empty/empty-struct-braces-expr.stderr +++ b/src/test/ui/empty/empty-struct-braces-expr.stderr @@ -1,7 +1,7 @@ error[E0423]: expected value, found struct `Empty1` --> $DIR/empty-struct-braces-expr.rs:15:14 | -LL | let e1 = Empty1; //~ ERROR expected value, found struct `Empty1` +LL | let e1 = Empty1; | ^^^^^^ | | | did you mean `Empty1 { /* fields */ }`? @@ -10,7 +10,7 @@ LL | let e1 = Empty1; //~ ERROR expected value, found struct `Empty1` error[E0423]: expected function, found struct `Empty1` --> $DIR/empty-struct-braces-expr.rs:16:14 | -LL | let e1 = Empty1(); //~ ERROR expected function, found struct `Empty1` +LL | let e1 = Empty1(); | ^^^^^^ | | | did you mean `Empty1 { /* fields */ }`? @@ -19,19 +19,19 @@ LL | let e1 = Empty1(); //~ ERROR expected function, found struct `Empty1` error[E0423]: expected value, found struct variant `E::Empty3` --> $DIR/empty-struct-braces-expr.rs:17:14 | -LL | let e3 = E::Empty3; //~ ERROR expected value, found struct variant `E::Empty3` +LL | let e3 = E::Empty3; | ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`? error[E0423]: expected function, found struct variant `E::Empty3` --> $DIR/empty-struct-braces-expr.rs:18:14 | -LL | let e3 = E::Empty3(); //~ ERROR expected function, found struct variant `E::Empty3` +LL | let e3 = E::Empty3(); | ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`? error[E0423]: expected value, found struct `XEmpty1` --> $DIR/empty-struct-braces-expr.rs:20:15 | -LL | let xe1 = XEmpty1; //~ ERROR expected value, found struct `XEmpty1` +LL | let xe1 = XEmpty1; | ^^^^^^^ | | | did you mean `XEmpty1 { /* fields */ }`? @@ -40,31 +40,37 @@ LL | let xe1 = XEmpty1; //~ ERROR expected value, found struct `XEmpty1` error[E0423]: expected function, found struct `XEmpty1` --> $DIR/empty-struct-braces-expr.rs:21:15 | -LL | let xe1 = XEmpty1(); //~ ERROR expected function, found struct `XEmpty1` +LL | let xe1 = XEmpty1(); | ^^^^^^^ | | | did you mean `XEmpty1 { /* fields */ }`? | help: a unit struct with a similar name exists: `XEmpty2` -error[E0599]: no variant named `Empty3` found for type `empty_struct::XE` in the current scope +error[E0599]: no variant or associated item named `Empty3` found for type `empty_struct::XE` in the current scope --> $DIR/empty-struct-braces-expr.rs:22:19 | -LL | let xe3 = XE::Empty3; //~ ERROR no variant named `Empty3` found for type - | ----^^^^^^ - | | | - | | help: did you mean: `XEmpty3` - | variant not found in `empty_struct::XE` +LL | let xe3 = XE::Empty3; + | ^^^^^^ + | | + | variant or associated item not found in `empty_struct::XE` + | help: there is a variant with a similar name: `XEmpty3` -error[E0599]: no variant named `Empty3` found for type `empty_struct::XE` in the current scope +error[E0599]: no variant or associated item named `Empty3` found for type `empty_struct::XE` in the current scope --> $DIR/empty-struct-braces-expr.rs:23:19 | -LL | let xe3 = XE::Empty3(); //~ ERROR no variant named `Empty3` found for type - | ----^^^^^^ - | | | - | | help: did you mean: `XEmpty3` - | variant not found in `empty_struct::XE` +LL | let xe3 = XE::Empty3(); + | ^^^^^^ + | | + | variant or associated item not found in `empty_struct::XE` + | help: there is a variant with a similar name: `XEmpty3` -error: aborting due to 8 previous errors +error: no variant `Empty1` in enum `empty_struct::XE` + --> $DIR/empty-struct-braces-expr.rs:25:9 + | +LL | XE::Empty1 {}; + | ^^^^^^ help: there is a variant with a similar name: `XEmpty3` + +error: aborting due to 9 previous errors -Some errors occurred: E0423, E0599. +Some errors have detailed explanations: E0423, E0599. For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/empty/empty-struct-braces-pat-2.stderr b/src/test/ui/empty/empty-struct-braces-pat-2.stderr index fc2ed79bb2e05..12047b5880c3e 100644 --- a/src/test/ui/empty/empty-struct-braces-pat-2.stderr +++ b/src/test/ui/empty/empty-struct-braces-pat-2.stderr @@ -1,7 +1,7 @@ error[E0532]: expected tuple struct/variant, found struct `Empty1` --> $DIR/empty-struct-braces-pat-2.rs:15:9 | -LL | Empty1() => () //~ ERROR expected tuple struct/variant, found struct `Empty1` +LL | Empty1() => () | ^^^^^^ | | | did you mean `Empty1 { /* fields */ }`? @@ -10,7 +10,7 @@ LL | Empty1() => () //~ ERROR expected tuple struct/variant, found struc error[E0532]: expected tuple struct/variant, found struct `XEmpty1` --> $DIR/empty-struct-braces-pat-2.rs:18:9 | -LL | XEmpty1() => () //~ ERROR expected tuple struct/variant, found struct `XEmpty1` +LL | XEmpty1() => () | ^^^^^^^ | | | did you mean `XEmpty1 { /* fields */ }`? @@ -19,7 +19,7 @@ LL | XEmpty1() => () //~ ERROR expected tuple struct/variant, found stru error[E0532]: expected tuple struct/variant, found struct `Empty1` --> $DIR/empty-struct-braces-pat-2.rs:21:9 | -LL | Empty1(..) => () //~ ERROR expected tuple struct/variant, found struct `Empty1` +LL | Empty1(..) => () | ^^^^^^ | | | did you mean `Empty1 { /* fields */ }`? @@ -28,7 +28,7 @@ LL | Empty1(..) => () //~ ERROR expected tuple struct/variant, found str error[E0532]: expected tuple struct/variant, found struct `XEmpty1` --> $DIR/empty-struct-braces-pat-2.rs:24:9 | -LL | XEmpty1(..) => () //~ ERROR expected tuple struct/variant, found struct `XEmpty1` +LL | XEmpty1(..) => () | ^^^^^^^ | | | did you mean `XEmpty1 { /* fields */ }`? diff --git a/src/test/ui/empty/empty-struct-tuple-pat.stderr b/src/test/ui/empty/empty-struct-tuple-pat.stderr index f92c4e5c46346..777b9d4a4acd0 100644 --- a/src/test/ui/empty/empty-struct-tuple-pat.stderr +++ b/src/test/ui/empty/empty-struct-tuple-pat.stderr @@ -4,7 +4,7 @@ error[E0530]: match bindings cannot shadow tuple structs LL | struct Empty2(); | ---------------- the tuple struct `Empty2` is defined here ... -LL | Empty2 => () //~ ERROR match bindings cannot shadow tuple structs +LL | Empty2 => () | ^^^^^^ cannot be named the same as a tuple struct error[E0530]: match bindings cannot shadow tuple structs @@ -13,7 +13,7 @@ error[E0530]: match bindings cannot shadow tuple structs LL | use empty_struct::*; | --------------- the tuple struct `XEmpty6` is imported here ... -LL | XEmpty6 => () //~ ERROR match bindings cannot shadow tuple structs +LL | XEmpty6 => () | ^^^^^^^ cannot be named the same as a tuple struct error[E0532]: expected unit struct/variant or constant, found tuple variant `E::Empty4` @@ -32,5 +32,5 @@ LL | XE::XEmpty5 => (), error: aborting due to 4 previous errors -Some errors occurred: E0530, E0532. +Some errors have detailed explanations: E0530, E0532. For more information about an error, try `rustc --explain E0530`. diff --git a/src/test/ui/empty/empty-struct-unit-expr.stderr b/src/test/ui/empty/empty-struct-unit-expr.stderr index b3519948f64dc..696eabe99cffb 100644 --- a/src/test/ui/empty/empty-struct-unit-expr.stderr +++ b/src/test/ui/empty/empty-struct-unit-expr.stderr @@ -4,7 +4,7 @@ error[E0618]: expected function, found `Empty2` LL | struct Empty2; | -------------- `Empty2` defined here ... -LL | let e2 = Empty2(); //~ ERROR expected function, found `Empty2` +LL | let e2 = Empty2(); | ^^^^^^-- | | | call expression requires function @@ -27,7 +27,7 @@ LL | let e4 = E::Empty4; error[E0618]: expected function, found `empty_struct::XEmpty2` --> $DIR/empty-struct-unit-expr.rs:18:15 | -LL | let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2` +LL | let xe2 = XEmpty2(); | ^^^^^^^-- | | | call expression requires function diff --git a/src/test/ui/empty/empty-struct-unit-pat.stderr b/src/test/ui/empty/empty-struct-unit-pat.stderr index e62246562be67..268fc7a6e0c19 100644 --- a/src/test/ui/empty/empty-struct-unit-pat.stderr +++ b/src/test/ui/empty/empty-struct-unit-pat.stderr @@ -1,31 +1,31 @@ error[E0532]: expected tuple struct/variant, found unit struct `Empty2` --> $DIR/empty-struct-unit-pat.rs:21:9 | -LL | Empty2() => () //~ ERROR expected tuple struct/variant, found unit struct `Empty2` +LL | Empty2() => () | ^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6` error[E0532]: expected tuple struct/variant, found unit struct `XEmpty2` --> $DIR/empty-struct-unit-pat.rs:24:9 | -LL | XEmpty2() => () //~ ERROR expected tuple struct/variant, found unit struct `XEmpty2` +LL | XEmpty2() => () | ^^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6` error[E0532]: expected tuple struct/variant, found unit struct `Empty2` --> $DIR/empty-struct-unit-pat.rs:27:9 | -LL | Empty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `Empty2` +LL | Empty2(..) => () | ^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6` error[E0532]: expected tuple struct/variant, found unit struct `XEmpty2` --> $DIR/empty-struct-unit-pat.rs:30:9 | -LL | XEmpty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `XEmpty2` +LL | XEmpty2(..) => () | ^^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6` error[E0532]: expected tuple struct/variant, found unit variant `E::Empty4` --> $DIR/empty-struct-unit-pat.rs:34:9 | -LL | E::Empty4() => () //~ ERROR expected tuple struct/variant, found unit variant `E::Empty4` +LL | E::Empty4() => () | ^^^^^^^^^ not a tuple struct/variant error[E0532]: expected tuple struct/variant, found unit variant `XE::XEmpty4` @@ -39,7 +39,7 @@ LL | XE::XEmpty4() => (), error[E0532]: expected tuple struct/variant, found unit variant `E::Empty4` --> $DIR/empty-struct-unit-pat.rs:42:9 | -LL | E::Empty4(..) => () //~ ERROR expected tuple struct/variant, found unit variant `E::Empty4` +LL | E::Empty4(..) => () | ^^^^^^^^^ not a tuple struct/variant error[E0532]: expected tuple struct/variant, found unit variant `XE::XEmpty4` diff --git a/src/test/ui/enable-unstable-lib-feature.rs b/src/test/ui/enable-unstable-lib-feature.rs index 2f248bf14c151..383c6868ce2fe 100644 --- a/src/test/ui/enable-unstable-lib-feature.rs +++ b/src/test/ui/enable-unstable-lib-feature.rs @@ -1,6 +1,6 @@ // Test that enabling an unstable feature disables warnings -// aux-build:stability_cfg2.rs +// aux-build:stability-cfg2.rs #![feature(unstable_test_feature)] #![deny(non_snake_case)] // To trigger a hard error diff --git a/src/test/ui/enable-unstable-lib-feature.stderr b/src/test/ui/enable-unstable-lib-feature.stderr index 51cfe7beade2d..5b6ebc4c0d990 100644 --- a/src/test/ui/enable-unstable-lib-feature.stderr +++ b/src/test/ui/enable-unstable-lib-feature.stderr @@ -1,7 +1,7 @@ error: function `BOGUS` should have a snake case name --> $DIR/enable-unstable-lib-feature.rs:12:8 | -LL | pub fn BOGUS() { } //~ ERROR +LL | pub fn BOGUS() { } | ^^^^^ help: convert the identifier to snake case: `bogus` | note: lint level defined here diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs new file mode 100644 index 0000000000000..4da7b5ab24b29 --- /dev/null +++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs @@ -0,0 +1,9 @@ +#![crate_type="lib"] +#![feature(arbitrary_enum_discriminant)] + +enum Enum { +//~^ ERROR `#[repr(inttype)]` must be specified + Unit = 1, + Tuple() = 2, + Struct{} = 3, +} diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr new file mode 100644 index 0000000000000..2db5372da0c6e --- /dev/null +++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr @@ -0,0 +1,14 @@ +error[E0732]: `#[repr(inttype)]` must be specified + --> $DIR/arbitrary_enum_discriminant-no-repr.rs:4:1 + | +LL | / enum Enum { +LL | | +LL | | Unit = 1, +LL | | Tuple() = 2, +LL | | Struct{} = 3, +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0732`. diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs new file mode 100644 index 0000000000000..f2270602d87eb --- /dev/null +++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs @@ -0,0 +1,56 @@ +// run-pass +#![feature(arbitrary_enum_discriminant, const_raw_ptr_deref, test)] + +extern crate test; + +use test::black_box; + +#[allow(dead_code)] +#[repr(u8)] +enum Enum { + Unit = 3, + Tuple(u16) = 2, + Struct { + a: u8, + b: u16, + } = 1, +} + +impl Enum { + const unsafe fn tag(&self) -> u8 { + *(self as *const Self as *const u8) + } +} + +#[allow(dead_code)] +#[repr(u8)] +enum FieldlessEnum { + Unit = 3, + Tuple() = 2, + Struct {} = 1, +} + +fn main() { + const UNIT: Enum = Enum::Unit; + const TUPLE: Enum = Enum::Tuple(5); + const STRUCT: Enum = Enum::Struct{a: 7, b: 11}; + + // Ensure discriminants are correct during runtime execution + assert_eq!(3, unsafe { black_box(UNIT).tag() }); + assert_eq!(2, unsafe { black_box(TUPLE).tag() }); + assert_eq!(1, unsafe { black_box(STRUCT).tag() }); + + // Ensure discriminants are correct during CTFE + const UNIT_TAG: u8 = unsafe { UNIT.tag() }; + const TUPLE_TAG: u8 = unsafe { TUPLE.tag() }; + const STRUCT_TAG: u8 = unsafe { STRUCT.tag() }; + + assert_eq!(3, UNIT_TAG); + assert_eq!(2, TUPLE_TAG); + assert_eq!(1, STRUCT_TAG); + + // Ensure `as` conversions are correct + assert_eq!(3, FieldlessEnum::Unit as u8); + assert_eq!(2, FieldlessEnum::Tuple() as u8); + assert_eq!(1, FieldlessEnum::Struct{} as u8); +} diff --git a/src/test/run-pass/discriminant_value-wrapper.rs b/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs similarity index 97% rename from src/test/run-pass/discriminant_value-wrapper.rs rename to src/test/ui/enum-discriminant/discriminant_value-wrapper.rs index f014cce9dddc6..daef2de87a9c2 100644 --- a/src/test/run-pass/discriminant_value-wrapper.rs +++ b/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs @@ -1,3 +1,4 @@ +// run-pass use std::mem; enum ADT { @@ -13,4 +14,3 @@ pub fn main() { let _ = mem::discriminant(&10); let _ = mem::discriminant(&"test"); } - diff --git a/src/test/run-pass/discriminant_value.rs b/src/test/ui/enum-discriminant/discriminant_value.rs similarity index 78% rename from src/test/run-pass/discriminant_value.rs rename to src/test/ui/enum-discriminant/discriminant_value.rs index 162ab27cdff25..b7000015c71db 100644 --- a/src/test/run-pass/discriminant_value.rs +++ b/src/test/ui/enum-discriminant/discriminant_value.rs @@ -1,5 +1,6 @@ +// run-pass #![allow(stable_features)] -#![feature(core, core_intrinsics)] +#![feature(arbitrary_enum_discriminant, core, core_intrinsics)] extern crate core; use core::intrinsics::discriminant_value; @@ -38,6 +39,17 @@ enum NullablePointer { static CONST : u32 = 0xBEEF; +#[allow(dead_code)] +#[repr(isize)] +enum Mixed { + Unit = 3, + Tuple(u16) = 2, + Struct { + a: u8, + b: u16, + } = 1, +} + pub fn main() { unsafe { @@ -64,5 +76,9 @@ pub fn main() { assert_eq!(discriminant_value(&10), 0); assert_eq!(discriminant_value(&"test"), 0); + + assert_eq!(3, discriminant_value(&Mixed::Unit)); + assert_eq!(2, discriminant_value(&Mixed::Tuple(5))); + assert_eq!(1, discriminant_value(&Mixed::Struct{a: 7, b: 11})); } } diff --git a/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.rs b/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.rs new file mode 100644 index 0000000000000..3e90af4d36af3 --- /dev/null +++ b/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.rs @@ -0,0 +1,10 @@ +#![crate_type="lib"] + +enum Enum { + Unit = 1, + //~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants + Tuple() = 2, + //~^ ERROR discriminants on non-unit variants are experimental + Struct{} = 3, + //~^ ERROR discriminants on non-unit variants are experimental +} diff --git a/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.stderr b/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.stderr new file mode 100644 index 0000000000000..f50ed2c184daf --- /dev/null +++ b/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.stderr @@ -0,0 +1,36 @@ +error[E0658]: discriminants on non-unit variants are experimental + --> $DIR/feature-gate-arbitrary_enum_discriminant.rs:6:13 + | +LL | Tuple() = 2, + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/60553 + = help: add #![feature(arbitrary_enum_discriminant)] to the crate attributes to enable + +error[E0658]: discriminants on non-unit variants are experimental + --> $DIR/feature-gate-arbitrary_enum_discriminant.rs:8:14 + | +LL | Struct{} = 3, + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/60553 + = help: add #![feature(arbitrary_enum_discriminant)] to the crate attributes to enable + +error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants + --> $DIR/feature-gate-arbitrary_enum_discriminant.rs:4:10 + | +LL | Unit = 1, + | ^ disallowed custom discriminant +LL | +LL | Tuple() = 2, + | ----------- tuple variant defined here +LL | +LL | Struct{} = 3, + | ------------ struct variant defined here + | + = note: for more information, see https://github.com/rust-lang/rust/issues/60553 + = help: add #![feature(arbitrary_enum_discriminant)] to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/enum-variant-generic-args.rs b/src/test/ui/enum-variant-generic-args.rs deleted file mode 100644 index 6eddd70964546..0000000000000 --- a/src/test/ui/enum-variant-generic-args.rs +++ /dev/null @@ -1,73 +0,0 @@ -#![feature(type_alias_enum_variants)] - -enum Enum { TSVariant(T), SVariant { v: T } } -type Alias = Enum; -type AliasFixed = Enum<()>; - -impl Enum { - fn ts_variant() { - Self::TSVariant(()); - //~^ ERROR mismatched types [E0308] - Self::TSVariant::<()>(()); - //~^ ERROR type arguments are not allowed on this entity [E0109] - Self::<()>::TSVariant(()); - //~^ ERROR type arguments are not allowed on this entity [E0109] - //~^^ ERROR mismatched types [E0308] - Self::<()>::TSVariant::<()>(()); - //~^ ERROR type arguments are not allowed on this entity [E0109] - //~^^ ERROR type arguments are not allowed on this entity [E0109] - } - - fn s_variant() { - Self::SVariant { v: () }; - //~^ ERROR mismatched types [E0308] - Self::SVariant::<()> { v: () }; - //~^ ERROR type arguments are not allowed on this entity [E0109] - //~^^ ERROR mismatched types [E0308] - Self::<()>::SVariant { v: () }; - //~^ ERROR type arguments are not allowed on this entity [E0109] - //~^^ ERROR mismatched types [E0308] - Self::<()>::SVariant::<()> { v: () }; - //~^ ERROR type arguments are not allowed on this entity [E0109] - //~^^ ERROR type arguments are not allowed on this entity [E0109] - //~^^^ ERROR mismatched types [E0308] - } -} - -fn main() { - // Tuple struct variant - - Enum::<()>::TSVariant::<()>(()); - //~^ ERROR type arguments are not allowed on this entity [E0109] - - Alias::TSVariant::<()>(()); - //~^ ERROR type arguments are not allowed on this entity [E0109] - Alias::<()>::TSVariant::<()>(()); - //~^ ERROR type arguments are not allowed on this entity [E0109] - - AliasFixed::TSVariant::<()>(()); - //~^ ERROR type arguments are not allowed on this entity [E0109] - AliasFixed::<()>::TSVariant(()); - //~^ ERROR wrong number of type arguments: expected 0, found 1 [E0107] - AliasFixed::<()>::TSVariant::<()>(()); - //~^ ERROR type arguments are not allowed on this entity [E0109] - //~^^ ERROR wrong number of type arguments: expected 0, found 1 [E0107] - - // Struct variant - - Enum::<()>::SVariant::<()> { v: () }; - //~^ ERROR type arguments are not allowed on this entity [E0109] - - Alias::SVariant::<()> { v: () }; - //~^ ERROR type arguments are not allowed on this entity [E0109] - Alias::<()>::SVariant::<()> { v: () }; - //~^ ERROR type arguments are not allowed on this entity [E0109] - - AliasFixed::SVariant::<()> { v: () }; - //~^ ERROR type arguments are not allowed on this entity [E0109] - AliasFixed::<()>::SVariant { v: () }; - //~^ ERROR wrong number of type arguments: expected 0, found 1 [E0107] - AliasFixed::<()>::SVariant::<()> { v: () }; - //~^ ERROR type arguments are not allowed on this entity [E0109] - //~^^ ERROR wrong number of type arguments: expected 0, found 1 [E0107] -} diff --git a/src/test/ui/enum-variant-generic-args.stderr b/src/test/ui/enum-variant-generic-args.stderr deleted file mode 100644 index 4d3b576734643..0000000000000 --- a/src/test/ui/enum-variant-generic-args.stderr +++ /dev/null @@ -1,190 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/enum-variant-generic-args.rs:9:25 - | -LL | Self::TSVariant(()); - | ^^ expected type parameter, found () - | - = note: expected type `T` - found type `()` - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:11:27 - | -LL | Self::TSVariant::<()>(()); - | ^^ type argument not allowed - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:13:16 - | -LL | Self::<()>::TSVariant(()); - | ^^ type argument not allowed - -error[E0308]: mismatched types - --> $DIR/enum-variant-generic-args.rs:13:31 - | -LL | Self::<()>::TSVariant(()); - | ^^ expected type parameter, found () - | - = note: expected type `T` - found type `()` - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:16:16 - | -LL | Self::<()>::TSVariant::<()>(()); - | ^^ type argument not allowed - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:16:33 - | -LL | Self::<()>::TSVariant::<()>(()); - | ^^ type argument not allowed - -error[E0308]: mismatched types - --> $DIR/enum-variant-generic-args.rs:22:29 - | -LL | Self::SVariant { v: () }; - | ^^ expected type parameter, found () - | - = note: expected type `T` - found type `()` - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:24:26 - | -LL | Self::SVariant::<()> { v: () }; - | ^^ type argument not allowed - -error[E0308]: mismatched types - --> $DIR/enum-variant-generic-args.rs:24:35 - | -LL | Self::SVariant::<()> { v: () }; - | ^^ expected type parameter, found () - | - = note: expected type `T` - found type `()` - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:27:16 - | -LL | Self::<()>::SVariant { v: () }; - | ^^ type argument not allowed - -error[E0308]: mismatched types - --> $DIR/enum-variant-generic-args.rs:27:35 - | -LL | Self::<()>::SVariant { v: () }; - | ^^ expected type parameter, found () - | - = note: expected type `T` - found type `()` - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:30:16 - | -LL | Self::<()>::SVariant::<()> { v: () }; - | ^^ type argument not allowed - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:30:32 - | -LL | Self::<()>::SVariant::<()> { v: () }; - | ^^ type argument not allowed - -error[E0308]: mismatched types - --> $DIR/enum-variant-generic-args.rs:30:41 - | -LL | Self::<()>::SVariant::<()> { v: () }; - | ^^ expected type parameter, found () - | - = note: expected type `T` - found type `()` - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:40:29 - | -LL | Enum::<()>::TSVariant::<()>(()); - | ^^ type argument not allowed - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:43:24 - | -LL | Alias::TSVariant::<()>(()); - | ^^ type argument not allowed - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:45:30 - | -LL | Alias::<()>::TSVariant::<()>(()); - | ^^ type argument not allowed - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:48:29 - | -LL | AliasFixed::TSVariant::<()>(()); - | ^^ type argument not allowed - -error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/enum-variant-generic-args.rs:50:18 - | -LL | AliasFixed::<()>::TSVariant(()); - | ^^ unexpected type argument - -error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/enum-variant-generic-args.rs:52:18 - | -LL | AliasFixed::<()>::TSVariant::<()>(()); - | ^^ unexpected type argument - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:52:35 - | -LL | AliasFixed::<()>::TSVariant::<()>(()); - | ^^ type argument not allowed - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:58:28 - | -LL | Enum::<()>::SVariant::<()> { v: () }; - | ^^ type argument not allowed - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:61:23 - | -LL | Alias::SVariant::<()> { v: () }; - | ^^ type argument not allowed - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:63:29 - | -LL | Alias::<()>::SVariant::<()> { v: () }; - | ^^ type argument not allowed - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:66:28 - | -LL | AliasFixed::SVariant::<()> { v: () }; - | ^^ type argument not allowed - -error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/enum-variant-generic-args.rs:68:18 - | -LL | AliasFixed::<()>::SVariant { v: () }; - | ^^ unexpected type argument - -error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/enum-variant-generic-args.rs:70:18 - | -LL | AliasFixed::<()>::SVariant::<()> { v: () }; - | ^^ unexpected type argument - -error[E0109]: type arguments are not allowed on this entity - --> $DIR/enum-variant-generic-args.rs:70:34 - | -LL | AliasFixed::<()>::SVariant::<()> { v: () }; - | ^^ type argument not allowed - -error: aborting due to 28 previous errors - -Some errors occurred: E0107, E0109, E0308. -For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/enum/enum-and-module-in-same-scope.stderr b/src/test/ui/enum/enum-and-module-in-same-scope.stderr index 5f42af8f260d3..538898c2f2a6f 100644 --- a/src/test/ui/enum/enum-and-module-in-same-scope.stderr +++ b/src/test/ui/enum/enum-and-module-in-same-scope.stderr @@ -4,7 +4,7 @@ error[E0428]: the name `Foo` is defined multiple times LL | enum Foo { | -------- previous definition of the type `Foo` here ... -LL | mod Foo { //~ ERROR the name `Foo` is defined multiple times +LL | mod Foo { | ^^^^^^^ `Foo` redefined here | = note: `Foo` must be defined only once in the type namespace of this module diff --git a/src/test/ui/enum/enum-discrim-autosizing.stderr b/src/test/ui/enum/enum-discrim-autosizing.stderr index 67b0d75d787cd..8848f984cfb7d 100644 --- a/src/test/ui/enum/enum-discrim-autosizing.stderr +++ b/src/test/ui/enum/enum-discrim-autosizing.stderr @@ -3,7 +3,7 @@ error[E0081]: discriminant value `0` already exists | LL | Au64 = 0, | - first use of `0` -LL | Bu64 = 0x8000_0000_0000_0000 //~ERROR already exists +LL | Bu64 = 0x8000_0000_0000_0000 | ^^^^^^^^^^^^^^^^^^^^^ enum already has `0` error: aborting due to previous error diff --git a/src/test/ui/enum/enum-discrim-too-small2.rs b/src/test/ui/enum/enum-discrim-too-small2.rs index af60564302599..85cd73d6f0855 100644 --- a/src/test/ui/enum/enum-discrim-too-small2.rs +++ b/src/test/ui/enum/enum-discrim-too-small2.rs @@ -5,28 +5,28 @@ enum Ei8 { Ai8 = 23, Bi8 = -23, - Ci8 = 223, //~ ERROR literal out of range for i8 + Ci8 = 223, //~ ERROR literal out of range for `i8` } #[repr(i16)] enum Ei16 { Ai16 = 23, Bi16 = -22333, - Ci16 = 55555, //~ ERROR literal out of range for i16 + Ci16 = 55555, //~ ERROR literal out of range for `i16` } #[repr(i32)] enum Ei32 { Ai32 = 23, Bi32 = -2_000_000_000, - Ci32 = 3_000_000_000, //~ ERROR literal out of range for i32 + Ci32 = 3_000_000_000, //~ ERROR literal out of range for `i32` } #[repr(i64)] enum Ei64 { Ai64 = 23, Bi64 = -9223372036854775808, - Ci64 = 9223372036854775809, //~ ERROR literal out of range for i64 + Ci64 = 9223372036854775809, //~ ERROR literal out of range for `i64` } // u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a diff --git a/src/test/ui/enum/enum-discrim-too-small2.stderr b/src/test/ui/enum/enum-discrim-too-small2.stderr index 31ca01b86bdb2..f7220044ba42d 100644 --- a/src/test/ui/enum/enum-discrim-too-small2.stderr +++ b/src/test/ui/enum/enum-discrim-too-small2.stderr @@ -1,7 +1,7 @@ -error: literal out of range for i8 +error: literal out of range for `i8` --> $DIR/enum-discrim-too-small2.rs:8:11 | -LL | Ci8 = 223, //~ ERROR literal out of range for i8 +LL | Ci8 = 223, | ^^^ | note: lint level defined here @@ -10,22 +10,22 @@ note: lint level defined here LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ -error: literal out of range for i16 +error: literal out of range for `i16` --> $DIR/enum-discrim-too-small2.rs:15:12 | -LL | Ci16 = 55555, //~ ERROR literal out of range for i16 +LL | Ci16 = 55555, | ^^^^^ -error: literal out of range for i32 +error: literal out of range for `i32` --> $DIR/enum-discrim-too-small2.rs:22:12 | -LL | Ci32 = 3_000_000_000, //~ ERROR literal out of range for i32 +LL | Ci32 = 3_000_000_000, | ^^^^^^^^^^^^^ -error: literal out of range for i64 +error: literal out of range for `i64` --> $DIR/enum-discrim-too-small2.rs:29:12 | -LL | Ci64 = 9223372036854775809, //~ ERROR literal out of range for i64 +LL | Ci64 = 9223372036854775809, | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/enum/enum-in-scope.stderr b/src/test/ui/enum/enum-in-scope.stderr index cd0100ec2fc47..49a01abcbd693 100644 --- a/src/test/ui/enum/enum-in-scope.stderr +++ b/src/test/ui/enum/enum-in-scope.stderr @@ -4,7 +4,7 @@ error[E0530]: let bindings cannot shadow tuple structs LL | struct hello(isize); | -------------------- the tuple struct `hello` is defined here ... -LL | let hello = 0; //~ERROR let bindings cannot shadow tuple structs +LL | let hello = 0; | ^^^^^ cannot be named the same as a tuple struct error: aborting due to previous error diff --git a/src/test/ui/enum/enum-size-variance.stderr b/src/test/ui/enum/enum-size-variance.stderr index 5cc0a0d7a8f88..1ebd9b6806f89 100644 --- a/src/test/ui/enum/enum-size-variance.stderr +++ b/src/test/ui/enum/enum-size-variance.stderr @@ -1,7 +1,7 @@ warning: enum variant is more than three times larger (32 bytes) than the next largest --> $DIR/enum-size-variance.rs:18:5 | -LL | L(i64, i64, i64, i64), //~ WARNING three times larger +LL | L(i64, i64, i64, i64), | ^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/enum/enum-to-float-cast-2.stderr b/src/test/ui/enum/enum-to-float-cast-2.stderr index 42d08a11ed1b6..2bc414098dcf8 100644 --- a/src/test/ui/enum/enum-to-float-cast-2.stderr +++ b/src/test/ui/enum/enum-to-float-cast-2.stderr @@ -1,7 +1,7 @@ error[E0606]: casting `E` as `f32` is invalid --> $DIR/enum-to-float-cast-2.rs:14:13 | -LL | let a = E::L0 as f32; //~ ERROR casting +LL | let a = E::L0 as f32; | ^^^^^^^^^^^^ | = help: cast through an integer first @@ -9,7 +9,7 @@ LL | let a = E::L0 as f32; //~ ERROR casting error[E0606]: casting `F` as `f32` is invalid --> $DIR/enum-to-float-cast-2.rs:15:13 | -LL | let c = F::H1 as f32; //~ ERROR casting +LL | let c = F::H1 as f32; | ^^^^^^^^^^^^ | = help: cast through an integer first diff --git a/src/test/ui/enum/enum-to-float-cast.stderr b/src/test/ui/enum/enum-to-float-cast.stderr index e6cd2ed4d0da4..191606d8dc531 100644 --- a/src/test/ui/enum/enum-to-float-cast.stderr +++ b/src/test/ui/enum/enum-to-float-cast.stderr @@ -1,7 +1,7 @@ error[E0606]: casting `E` as `f32` is invalid --> $DIR/enum-to-float-cast.rs:13:18 | -LL | static C0: f32 = E::L0 as f32; //~ ERROR casting +LL | static C0: f32 = E::L0 as f32; | ^^^^^^^^^^^^ | = help: cast through an integer first @@ -9,7 +9,7 @@ LL | static C0: f32 = E::L0 as f32; //~ ERROR casting error[E0606]: casting `F` as `f32` is invalid --> $DIR/enum-to-float-cast.rs:14:18 | -LL | static C1: f32 = F::H1 as f32; //~ ERROR casting +LL | static C1: f32 = F::H1 as f32; | ^^^^^^^^^^^^ | = help: cast through an integer first diff --git a/src/test/ui/enum/enum-variant-type-2.stderr b/src/test/ui/enum/enum-variant-type-2.stderr index 3e7a4edd66e68..65c45d9bad0dc 100644 --- a/src/test/ui/enum/enum-variant-type-2.stderr +++ b/src/test/ui/enum/enum-variant-type-2.stderr @@ -1,7 +1,7 @@ error[E0573]: expected type, found variant `Foo::Bar` --> $DIR/enum-variant-type-2.rs:7:11 | -LL | fn foo(x: Foo::Bar) {} //~ ERROR expected type, found variant `Foo::Bar` +LL | fn foo(x: Foo::Bar) {} | ^^^^^^^^ | | | not a type @@ -9,4 +9,3 @@ LL | fn foo(x: Foo::Bar) {} //~ ERROR expected type, found variant `Foo::Bar` error: aborting due to previous error -For more information about this error, try `rustc --explain E0573`. diff --git a/src/test/ui/enums-pats-not-idents.stderr b/src/test/ui/enums-pats-not-idents.stderr index 5e12f3b5eadf1..3891d1eac487b 100644 --- a/src/test/ui/enums-pats-not-idents.stderr +++ b/src/test/ui/enums-pats-not-idents.stderr @@ -1,9 +1,8 @@ error[E0531]: cannot find tuple struct/variant `a` in this scope --> $DIR/enums-pats-not-idents.rs:2:9 | -LL | let a(1) = 13; //~ ERROR cannot find tuple struct/variant `a` in this scope +LL | let a(1) = 13; | ^ not found in this scope error: aborting due to previous error -For more information about this error, try `rustc --explain E0531`. diff --git a/src/test/ui/error-codes/E0001.stderr b/src/test/ui/error-codes/E0001.stderr index 0b884c54a82f7..992345151827f 100644 --- a/src/test/ui/error-codes/E0001.stderr +++ b/src/test/ui/error-codes/E0001.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/E0001.rs:8:9 | -LL | _ => {/* ... */} //~ ERROR unreachable pattern +LL | _ => {/* ... */} | ^ | note: lint level defined here diff --git a/src/test/ui/error-codes/E0004-2.stderr b/src/test/ui/error-codes/E0004-2.stderr index 8b262cc6eb784..db0a2b5a08593 100644 --- a/src/test/ui/error-codes/E0004-2.stderr +++ b/src/test/ui/error-codes/E0004-2.stderr @@ -1,14 +1,10 @@ -error[E0004]: non-exhaustive patterns: type `std::option::Option` is non-empty +error[E0004]: non-exhaustive patterns: multiple patterns of type `std::option::Option` are not handled --> $DIR/E0004-2.rs:4:11 | -LL | match x { } //~ ERROR E0004 +LL | match x { } | ^ | -help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - --> $DIR/E0004-2.rs:4:11 - | -LL | match x { } //~ ERROR E0004 - | ^ + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0004.stderr b/src/test/ui/error-codes/E0004.stderr index a66dd92903200..2940ad4bb1e2d 100644 --- a/src/test/ui/error-codes/E0004.stderr +++ b/src/test/ui/error-codes/E0004.stderr @@ -1,8 +1,17 @@ error[E0004]: non-exhaustive patterns: `HastaLaVistaBaby` not covered --> $DIR/E0004.rs:9:11 | -LL | match x { //~ ERROR E0004 - | ^ pattern `HastaLaVistaBaby` not covered +LL | / enum Terminator { +LL | | HastaLaVistaBaby, + | | ---------------- not covered +LL | | TalkToMyHand, +LL | | } + | |_- `Terminator` defined here +... +LL | match x { + | ^ pattern `HastaLaVistaBaby` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0005.stderr b/src/test/ui/error-codes/E0005.stderr index 2a38aae0873ad..56a4bcffc81a2 100644 --- a/src/test/ui/error-codes/E0005.stderr +++ b/src/test/ui/error-codes/E0005.stderr @@ -1,7 +1,7 @@ error[E0005]: refutable pattern in local binding: `None` not covered --> $DIR/E0005.rs:3:9 | -LL | let Some(y) = x; //~ ERROR E0005 +LL | let Some(y) = x; | ^^^^^^^ pattern `None` not covered error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0007.rs b/src/test/ui/error-codes/E0007.rs index 8fc6342002bb2..cdda735ba4435 100644 --- a/src/test/ui/error-codes/E0007.rs +++ b/src/test/ui/error-codes/E0007.rs @@ -4,6 +4,7 @@ fn main() { op_string @ Some(s) => {}, //~^ ERROR E0007 //~| ERROR E0303 + //~| ERROR E0382 None => {}, } } diff --git a/src/test/ui/error-codes/E0007.stderr b/src/test/ui/error-codes/E0007.stderr index a5d694976cfbd..89a6298c8752f 100644 --- a/src/test/ui/error-codes/E0007.stderr +++ b/src/test/ui/error-codes/E0007.stderr @@ -10,7 +10,19 @@ error[E0303]: pattern bindings are not allowed after an `@` LL | op_string @ Some(s) => {}, | ^ not allowed after `@` -error: aborting due to 2 previous errors +error[E0382]: use of moved value + --> $DIR/E0007.rs:4:26 + | +LL | let x = Some("s".to_string()); + | - move occurs because `x` has type `std::option::Option`, which does not implement the `Copy` trait +LL | match x { +LL | op_string @ Some(s) => {}, + | -----------------^- + | | | + | | value used here after move + | value moved here + +error: aborting due to 3 previous errors -Some errors occurred: E0007, E0303. +Some errors have detailed explanations: E0007, E0303, E0382. For more information about an error, try `rustc --explain E0007`. diff --git a/src/test/ui/error-codes/E0008.nll.stderr b/src/test/ui/error-codes/E0008.nll.stderr deleted file mode 100644 index 2505c03a148af..0000000000000 --- a/src/test/ui/error-codes/E0008.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0008]: cannot bind by-move into a pattern guard - --> $DIR/E0008.rs:3:14 - | -LL | Some(s) if s.len() == 0 => {}, - | ^ moves value into pattern guard - | - = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0008`. diff --git a/src/test/ui/error-codes/E0008.stderr b/src/test/ui/error-codes/E0008.stderr index d5c44efd667ee..2505c03a148af 100644 --- a/src/test/ui/error-codes/E0008.stderr +++ b/src/test/ui/error-codes/E0008.stderr @@ -3,6 +3,8 @@ error[E0008]: cannot bind by-move into a pattern guard | LL | Some(s) if s.len() == 0 => {}, | ^ moves value into pattern guard + | + = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0010-teach.stderr b/src/test/ui/error-codes/E0010-teach.stderr index 77e7b5ec0e860..4c9d140692ad0 100644 --- a/src/test/ui/error-codes/E0010-teach.stderr +++ b/src/test/ui/error-codes/E0010-teach.stderr @@ -1,7 +1,7 @@ error[E0010]: allocations are not allowed in constants --> $DIR/E0010-teach.rs:6:24 | -LL | const CON : Box = box 0; //~ ERROR E0010 +LL | const CON : Box = box 0; | ^^^^^ allocation not allowed in constants | = note: The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. @@ -9,7 +9,7 @@ LL | const CON : Box = box 0; //~ ERROR E0010 error[E0019]: constant contains unimplemented expression type --> $DIR/E0010-teach.rs:6:28 | -LL | const CON : Box = box 0; //~ ERROR E0010 +LL | const CON : Box = box 0; | ^ | = note: A function call isn't allowed in the const's initialization expression because the expression's value must be known at compile-time. @@ -17,5 +17,5 @@ LL | const CON : Box = box 0; //~ ERROR E0010 error: aborting due to 2 previous errors -Some errors occurred: E0010, E0019. +Some errors have detailed explanations: E0010, E0019. For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/error-codes/E0010.stderr b/src/test/ui/error-codes/E0010.stderr index 1364693109e08..48472d8acda38 100644 --- a/src/test/ui/error-codes/E0010.stderr +++ b/src/test/ui/error-codes/E0010.stderr @@ -1,16 +1,16 @@ error[E0010]: allocations are not allowed in constants --> $DIR/E0010.rs:4:24 | -LL | const CON : Box = box 0; //~ ERROR E0010 +LL | const CON : Box = box 0; | ^^^^^ allocation not allowed in constants error[E0019]: constant contains unimplemented expression type --> $DIR/E0010.rs:4:28 | -LL | const CON : Box = box 0; //~ ERROR E0010 +LL | const CON : Box = box 0; | ^ error: aborting due to 2 previous errors -Some errors occurred: E0010, E0019. +Some errors have detailed explanations: E0010, E0019. For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/error-codes/E0017.nll.stderr b/src/test/ui/error-codes/E0017.nll.stderr deleted file mode 100644 index 0477f06010b02..0000000000000 --- a/src/test/ui/error-codes/E0017.nll.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0017]: references in constants may only refer to immutable values - --> $DIR/E0017.rs:4:30 - | -LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017 - | ^^^^^^ constants require immutable values - -error[E0017]: references in statics may only refer to immutable values - --> $DIR/E0017.rs:5:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 - | ^^^^^^ statics require immutable values - -error: cannot mutate statics in the initializer of another static - --> $DIR/E0017.rs:5:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 - | ^^^^^^ - -error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0017.rs:5:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 - | ^^^^^^ cannot borrow as mutable - -error[E0017]: references in statics may only refer to immutable values - --> $DIR/E0017.rs:8:38 - | -LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 - | ^^^^^^ statics require immutable values - -error: aborting due to 5 previous errors - -Some errors occurred: E0017, E0596. -For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr index cc202ec912e96..67ff7da611bb1 100644 --- a/src/test/ui/error-codes/E0017.stderr +++ b/src/test/ui/error-codes/E0017.stderr @@ -1,34 +1,34 @@ error[E0017]: references in constants may only refer to immutable values --> $DIR/E0017.rs:4:30 | -LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017 +LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ constants require immutable values error[E0017]: references in statics may only refer to immutable values --> $DIR/E0017.rs:5:39 | -LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 +LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ statics require immutable values error: cannot mutate statics in the initializer of another static --> $DIR/E0017.rs:5:39 | -LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 +LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ -error[E0596]: cannot borrow immutable static item as mutable - --> $DIR/E0017.rs:5:44 +error[E0596]: cannot borrow immutable static item `X` as mutable + --> $DIR/E0017.rs:5:39 | -LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 - | ^ +LL | static STATIC_REF: &'static mut i32 = &mut X; + | ^^^^^^ cannot borrow as mutable error[E0017]: references in statics may only refer to immutable values --> $DIR/E0017.rs:8:38 | -LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 +LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ statics require immutable values error: aborting due to 5 previous errors -Some errors occurred: E0017, E0596. +Some errors have detailed explanations: E0017, E0596. For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr index 37704fc3233ca..1bc90a995fe30 100644 --- a/src/test/ui/error-codes/E0023.stderr +++ b/src/test/ui/error-codes/E0023.stderr @@ -1,19 +1,19 @@ error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields --> $DIR/E0023.rs:10:9 | -LL | Fruit::Apple(a) => {}, //~ ERROR E0023 +LL | Fruit::Apple(a) => {}, | ^^^^^^^^^^^^^^^ expected 2 fields, found 1 error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/E0023.rs:11:9 | -LL | Fruit::Apple(a, b, c) => {}, //~ ERROR E0023 +LL | Fruit::Apple(a, b, c) => {}, | ^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3 error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 1 field --> $DIR/E0023.rs:12:9 | -LL | Fruit::Pear(1, 2) => {}, //~ ERROR E0023 +LL | Fruit::Pear(1, 2) => {}, | ^^^^^^^^^^^^^^^^^ expected 1 field, found 2 error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/E0030-teach.rs b/src/test/ui/error-codes/E0030-teach.rs index 388064fb0fae5..8caa4f0931d57 100644 --- a/src/test/ui/error-codes/E0030-teach.rs +++ b/src/test/ui/error-codes/E0030-teach.rs @@ -4,5 +4,6 @@ fn main() { match 5u32 { 1000 ..= 5 => {} //~^ ERROR lower range bound must be less than or equal to upper + //~| ERROR lower range bound must be less than or equal to upper } } diff --git a/src/test/ui/error-codes/E0030-teach.stderr b/src/test/ui/error-codes/E0030-teach.stderr index 3f1ad4af3a94e..800f66416a813 100644 --- a/src/test/ui/error-codes/E0030-teach.stderr +++ b/src/test/ui/error-codes/E0030-teach.stderr @@ -6,6 +6,12 @@ LL | 1000 ..= 5 => {} | = note: When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. -error: aborting due to previous error +error[E0030]: lower range bound must be less than or equal to upper + --> $DIR/E0030-teach.rs:5:9 + | +LL | 1000 ..= 5 => {} + | ^^^^ lower bound larger than upper bound + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0030`. diff --git a/src/test/ui/error-codes/E0033-teach.rs b/src/test/ui/error-codes/E0033-teach.rs index 0f0b8d864dc43..6a27b07fa8b77 100644 --- a/src/test/ui/error-codes/E0033-teach.rs +++ b/src/test/ui/error-codes/E0033-teach.rs @@ -5,7 +5,7 @@ trait SomeTrait { } fn main() { - let trait_obj: &SomeTrait = SomeTrait; + let trait_obj: &dyn SomeTrait = SomeTrait; //~^ ERROR expected value, found trait `SomeTrait` //~| ERROR E0038 //~| method `foo` has no receiver diff --git a/src/test/ui/error-codes/E0033-teach.stderr b/src/test/ui/error-codes/E0033-teach.stderr index 81a8f164b943c..fb630de7fc147 100644 --- a/src/test/ui/error-codes/E0033-teach.stderr +++ b/src/test/ui/error-codes/E0033-teach.stderr @@ -1,14 +1,14 @@ error[E0423]: expected value, found trait `SomeTrait` - --> $DIR/E0033-teach.rs:8:33 + --> $DIR/E0033-teach.rs:8:37 | -LL | let trait_obj: &SomeTrait = SomeTrait; - | ^^^^^^^^^ not a value +LL | let trait_obj: &dyn SomeTrait = SomeTrait; + | ^^^^^^^^^ not a value error[E0038]: the trait `SomeTrait` cannot be made into an object --> $DIR/E0033-teach.rs:8:20 | -LL | let trait_obj: &SomeTrait = SomeTrait; - | ^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object +LL | let trait_obj: &dyn SomeTrait = SomeTrait; + | ^^^^^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object | = note: method `foo` has no receiver @@ -24,5 +24,5 @@ LL | let &invalid = trait_obj; error: aborting due to 3 previous errors -Some errors occurred: E0033, E0038, E0423. +Some errors have detailed explanations: E0033, E0038, E0423. For more information about an error, try `rustc --explain E0033`. diff --git a/src/test/ui/error-codes/E0033.rs b/src/test/ui/error-codes/E0033.rs index 5a4f3cbce60e4..582600e110ba0 100644 --- a/src/test/ui/error-codes/E0033.rs +++ b/src/test/ui/error-codes/E0033.rs @@ -3,7 +3,7 @@ trait SomeTrait { } fn main() { - let trait_obj: &SomeTrait = SomeTrait; + let trait_obj: &dyn SomeTrait = SomeTrait; //~^ ERROR expected value, found trait `SomeTrait` //~| ERROR E0038 //~| method `foo` has no receiver diff --git a/src/test/ui/error-codes/E0033.stderr b/src/test/ui/error-codes/E0033.stderr index e250df81c14a0..fe9f45d86a6a0 100644 --- a/src/test/ui/error-codes/E0033.stderr +++ b/src/test/ui/error-codes/E0033.stderr @@ -1,14 +1,14 @@ error[E0423]: expected value, found trait `SomeTrait` - --> $DIR/E0033.rs:6:33 + --> $DIR/E0033.rs:6:37 | -LL | let trait_obj: &SomeTrait = SomeTrait; - | ^^^^^^^^^ not a value +LL | let trait_obj: &dyn SomeTrait = SomeTrait; + | ^^^^^^^^^ not a value error[E0038]: the trait `SomeTrait` cannot be made into an object --> $DIR/E0033.rs:6:20 | -LL | let trait_obj: &SomeTrait = SomeTrait; - | ^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object +LL | let trait_obj: &dyn SomeTrait = SomeTrait; + | ^^^^^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object | = note: method `foo` has no receiver @@ -20,5 +20,5 @@ LL | let &invalid = trait_obj; error: aborting due to 3 previous errors -Some errors occurred: E0033, E0038, E0423. +Some errors have detailed explanations: E0033, E0038, E0423. For more information about an error, try `rustc --explain E0033`. diff --git a/src/test/ui/error-codes/E0034.stderr b/src/test/ui/error-codes/E0034.stderr index 3c5569eb79f3f..816a48f102dce 100644 --- a/src/test/ui/error-codes/E0034.stderr +++ b/src/test/ui/error-codes/E0034.stderr @@ -1,7 +1,7 @@ error[E0034]: multiple applicable items in scope --> $DIR/E0034.rs:20:5 | -LL | Test::foo() //~ ERROR multiple applicable items in scope +LL | Test::foo() | ^^^^^^^^^ multiple `foo` found | note: candidate #1 is defined in an impl of the trait `Trait1` for the type `Test` diff --git a/src/test/ui/error-codes/E0038.rs b/src/test/ui/error-codes/E0038.rs index b2226803da7fa..9757e2ab10c7a 100644 --- a/src/test/ui/error-codes/E0038.rs +++ b/src/test/ui/error-codes/E0038.rs @@ -2,7 +2,7 @@ trait Trait { fn foo(&self) -> Self; } -fn call_foo(x: Box) { +fn call_foo(x: Box) { //~^ ERROR E0038 let y = x.foo(); } diff --git a/src/test/ui/error-codes/E0038.stderr b/src/test/ui/error-codes/E0038.stderr index 74b77338c85c0..e3d7593e42a71 100644 --- a/src/test/ui/error-codes/E0038.stderr +++ b/src/test/ui/error-codes/E0038.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/E0038.rs:5:1 | -LL | fn call_foo(x: Box) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` cannot be made into an object +LL | fn call_foo(x: Box) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` cannot be made into an object | = note: method `foo` references the `Self` type in its arguments or return type diff --git a/src/test/ui/error-codes/E0045.stderr b/src/test/ui/error-codes/E0045.stderr index 0ce91f0a40103..d163128bc8b6c 100644 --- a/src/test/ui/error-codes/E0045.stderr +++ b/src/test/ui/error-codes/E0045.stderr @@ -1,7 +1,7 @@ error[E0045]: C-variadic function must have C or cdecl calling convention --> $DIR/E0045.rs:1:17 | -LL | extern "Rust" { fn foo(x: u8, ...); } //~ ERROR E0045 +LL | extern "Rust" { fn foo(x: u8, ...); } | ^^^^^^^^^^^^^^^^^^^ C-variadics require C or cdecl calling convention error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0049.rs b/src/test/ui/error-codes/E0049.rs index c141f8a882820..3dd910019bfd0 100644 --- a/src/test/ui/error-codes/E0049.rs +++ b/src/test/ui/error-codes/E0049.rs @@ -8,5 +8,15 @@ impl Foo for Bar { fn foo(x: bool) -> Self { Bar } //~ ERROR E0049 } +trait Fuzz { + fn fuzz(x: A, y: B) -> Self; +} + +struct Baz; + +impl Fuzz for Baz { + fn fuzz(x: bool, y: bool) -> Self { Baz } //~ ERROR E0049 +} + fn main() { } diff --git a/src/test/ui/error-codes/E0049.stderr b/src/test/ui/error-codes/E0049.stderr index 0d132bdbbddaa..c0cd31faa90d6 100644 --- a/src/test/ui/error-codes/E0049.stderr +++ b/src/test/ui/error-codes/E0049.stderr @@ -1,12 +1,23 @@ error[E0049]: method `foo` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/E0049.rs:8:5 + --> $DIR/E0049.rs:8:11 | LL | fn foo(x: T) -> Self; - | --------------------------------- expected 1 type parameter + | - expected 1 type parameter ... -LL | fn foo(x: bool) -> Self { Bar } //~ ERROR E0049 - | ^^^^^^^^^^^^^^^^^^^^^^^ found 0 type parameters +LL | fn foo(x: bool) -> Self { Bar } + | ^ found 0 type parameters -error: aborting due to previous error +error[E0049]: method `fuzz` has 0 type parameters but its trait declaration has 2 type parameters + --> $DIR/E0049.rs:18:12 + | +LL | fn fuzz(x: A, y: B) -> Self; + | - - + | | + | expected 2 type parameters +... +LL | fn fuzz(x: bool, y: bool) -> Self { Baz } + | ^ found 0 type parameters + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0049`. diff --git a/src/test/ui/error-codes/E0050.stderr b/src/test/ui/error-codes/E0050.stderr index 2c1fd111d26fd..fe9ac5e8eb025 100644 --- a/src/test/ui/error-codes/E0050.stderr +++ b/src/test/ui/error-codes/E0050.stderr @@ -4,7 +4,7 @@ error[E0050]: method `foo` has 1 parameter but the declaration in trait `Foo::fo LL | fn foo(&self, x: u8) -> bool; | ------------ trait requires 2 parameters ... -LL | fn foo(&self) -> bool { true } //~ ERROR E0050 +LL | fn foo(&self) -> bool { true } | ^^^^^ expected 2 parameters, found 1 error[E0050]: method `bar` has 1 parameter but the declaration in trait `Foo::bar` has 4 @@ -13,7 +13,7 @@ error[E0050]: method `bar` has 1 parameter but the declaration in trait `Foo::ba LL | fn bar(&self, x: u8, y: u8, z: u8); | -------------------------- trait requires 4 parameters ... -LL | fn bar(&self) { } //~ ERROR E0050 +LL | fn bar(&self) { } | ^^^^^ expected 4 parameters, found 1 error[E0050]: method `less` has 4 parameters but the declaration in trait `Foo::less` has 1 @@ -22,7 +22,7 @@ error[E0050]: method `less` has 4 parameters but the declaration in trait `Foo:: LL | fn less(&self); | ----- trait requires 1 parameter ... -LL | fn less(&self, x: u8, y: u8, z: u8) { } //~ ERROR E0050 +LL | fn less(&self, x: u8, y: u8, z: u8) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 parameter, found 4 error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/E0054.stderr b/src/test/ui/error-codes/E0054.stderr index cce32fa294407..6b1092760fb49 100644 --- a/src/test/ui/error-codes/E0054.stderr +++ b/src/test/ui/error-codes/E0054.stderr @@ -1,7 +1,7 @@ error[E0054]: cannot cast as `bool` --> $DIR/E0054.rs:3:24 | -LL | let x_is_nonzero = x as bool; //~ ERROR E0054 +LL | let x_is_nonzero = x as bool; | ^^^^^^^^^ help: compare with zero instead: `x != 0` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0057.stderr b/src/test/ui/error-codes/E0057.stderr index 5906a05c32c97..6b5890cac36c5 100644 --- a/src/test/ui/error-codes/E0057.stderr +++ b/src/test/ui/error-codes/E0057.stderr @@ -1,13 +1,13 @@ error[E0057]: this function takes 1 parameter but 0 parameters were supplied --> $DIR/E0057.rs:3:13 | -LL | let a = f(); //~ ERROR E0057 +LL | let a = f(); | ^^^ expected 1 parameter error[E0057]: this function takes 1 parameter but 2 parameters were supplied --> $DIR/E0057.rs:5:13 | -LL | let c = f(2, 3); //~ ERROR E0057 +LL | let c = f(2, 3); | ^^^^^^^ expected 1 parameter error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0059.stderr b/src/test/ui/error-codes/E0059.stderr index a96e1a0beab32..a1b8aeaedbb8b 100644 --- a/src/test/ui/error-codes/E0059.stderr +++ b/src/test/ui/error-codes/E0059.stderr @@ -1,7 +1,7 @@ error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit --> $DIR/E0059.rs:3:41 | -LL | fn foo>(f: F) -> F::Output { f(3) } //~ ERROR E0059 +LL | fn foo>(f: F) -> F::Output { f(3) } | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0067.stderr b/src/test/ui/error-codes/E0067.stderr index fd4ca7c9f7075..0334565840f83 100644 --- a/src/test/ui/error-codes/E0067.stderr +++ b/src/test/ui/error-codes/E0067.stderr @@ -1,7 +1,7 @@ error[E0368]: binary assignment operation `+=` cannot be applied to type `std::collections::LinkedList<_>` --> $DIR/E0067.rs:4:5 | -LL | LinkedList::new() += 1; //~ ERROR E0368 +LL | LinkedList::new() += 1; | -----------------^^^^^ | | | cannot use `+=` on type `std::collections::LinkedList<_>` @@ -11,10 +11,10 @@ LL | LinkedList::new() += 1; //~ ERROR E0368 error[E0067]: invalid left-hand side expression --> $DIR/E0067.rs:4:5 | -LL | LinkedList::new() += 1; //~ ERROR E0368 +LL | LinkedList::new() += 1; | ^^^^^^^^^^^^^^^^^ invalid expression for left-hand side error: aborting due to 2 previous errors -Some errors occurred: E0067, E0368. +Some errors have detailed explanations: E0067, E0368. For more information about an error, try `rustc --explain E0067`. diff --git a/src/test/ui/error-codes/E0070.stderr b/src/test/ui/error-codes/E0070.stderr index 4c1cfd858e6c5..40186137b0aaf 100644 --- a/src/test/ui/error-codes/E0070.stderr +++ b/src/test/ui/error-codes/E0070.stderr @@ -1,19 +1,19 @@ error[E0070]: invalid left-hand side expression --> $DIR/E0070.rs:6:5 | -LL | SOME_CONST = 14; //~ ERROR E0070 +LL | SOME_CONST = 14; | ^^^^^^^^^^^^^^^ left-hand of expression not valid error[E0070]: invalid left-hand side expression --> $DIR/E0070.rs:7:5 | -LL | 1 = 3; //~ ERROR E0070 +LL | 1 = 3; | ^^^^^ left-hand of expression not valid error[E0308]: mismatched types --> $DIR/E0070.rs:8:25 | -LL | some_other_func() = 4; //~ ERROR E0070 +LL | some_other_func() = 4; | ^ expected (), found integer | = note: expected type `()` @@ -22,10 +22,10 @@ LL | some_other_func() = 4; //~ ERROR E0070 error[E0070]: invalid left-hand side expression --> $DIR/E0070.rs:8:5 | -LL | some_other_func() = 4; //~ ERROR E0070 +LL | some_other_func() = 4; | ^^^^^^^^^^^^^^^^^^^^^ left-hand of expression not valid error: aborting due to 4 previous errors -Some errors occurred: E0070, E0308. +Some errors have detailed explanations: E0070, E0308. For more information about an error, try `rustc --explain E0070`. diff --git a/src/test/ui/error-codes/E0075.stderr b/src/test/ui/error-codes/E0075.stderr index abf6889709694..d8b90d0691dad 100644 --- a/src/test/ui/error-codes/E0075.stderr +++ b/src/test/ui/error-codes/E0075.stderr @@ -1,7 +1,7 @@ error[E0075]: SIMD vector cannot be empty --> $DIR/E0075.rs:4:1 | -LL | struct Bad; //~ ERROR E0075 +LL | struct Bad; | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0077.stderr b/src/test/ui/error-codes/E0077.stderr index 9f3e1fa5c3581..4f85d175ce65d 100644 --- a/src/test/ui/error-codes/E0077.stderr +++ b/src/test/ui/error-codes/E0077.stderr @@ -1,7 +1,7 @@ error[E0077]: SIMD vector element type should be machine type --> $DIR/E0077.rs:4:1 | -LL | struct Bad(String); //~ ERROR E0077 +LL | struct Bad(String); | ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0080.stderr b/src/test/ui/error-codes/E0080.stderr index 4d37881c1e126..3113fd2189b4c 100644 --- a/src/test/ui/error-codes/E0080.stderr +++ b/src/test/ui/error-codes/E0080.stderr @@ -1,13 +1,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/E0080.rs:2:9 | -LL | X = (1 << 500), //~ ERROR E0080 +LL | X = (1 << 500), | ^^^^^^^^^^ attempt to shift left with overflow error[E0080]: evaluation of constant value failed --> $DIR/E0080.rs:4:9 | -LL | Y = (1 / 0) //~ ERROR E0080 +LL | Y = (1 / 0) | ^^^^^^^ attempt to divide by zero error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0084.stderr b/src/test/ui/error-codes/E0084.stderr index 353c825f5280e..1f818da25bb0f 100644 --- a/src/test/ui/error-codes/E0084.stderr +++ b/src/test/ui/error-codes/E0084.stderr @@ -1,7 +1,7 @@ error[E0084]: unsupported representation for zero-variant enum --> $DIR/E0084.rs:1:1 | -LL | #[repr(i32)] //~ ERROR: E0084 +LL | #[repr(i32)] | ^^^^^^^^^^^^ LL | enum Foo {} | ----------- zero-variant enum diff --git a/src/test/ui/error-codes/E0091.stderr b/src/test/ui/error-codes/E0091.stderr index d32960f82cbc1..a596b75e481de 100644 --- a/src/test/ui/error-codes/E0091.stderr +++ b/src/test/ui/error-codes/E0091.stderr @@ -1,13 +1,13 @@ error[E0091]: type parameter `T` is unused --> $DIR/E0091.rs:1:10 | -LL | type Foo = u32; //~ ERROR E0091 +LL | type Foo = u32; | ^ unused type parameter error[E0091]: type parameter `B` is unused --> $DIR/E0091.rs:2:14 | -LL | type Foo2 = Box; //~ ERROR E0091 +LL | type Foo2 = Box; | ^ unused type parameter error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0092.stderr b/src/test/ui/error-codes/E0092.stderr index a453517752691..2d590a8e1d706 100644 --- a/src/test/ui/error-codes/E0092.stderr +++ b/src/test/ui/error-codes/E0092.stderr @@ -1,7 +1,7 @@ error[E0092]: unrecognized atomic operation function: `foo` --> $DIR/E0092.rs:3:5 | -LL | fn atomic_foo(); //~ ERROR E0092 +LL | fn atomic_foo(); | ^^^^^^^^^^^^^^^^ unrecognized atomic operation error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0094.stderr b/src/test/ui/error-codes/E0094.stderr index 97bdbfbe5ab5a..da97f3a014b06 100644 --- a/src/test/ui/error-codes/E0094.stderr +++ b/src/test/ui/error-codes/E0094.stderr @@ -1,7 +1,7 @@ error[E0094]: intrinsic has wrong number of type parameters: found 2, expected 1 --> $DIR/E0094.rs:3:15 | -LL | fn size_of() -> usize; //~ ERROR E0094 +LL | fn size_of() -> usize; | ^^^^^^ expected 1 type parameter error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0109.stderr b/src/test/ui/error-codes/E0109.stderr index a5508f9808576..577e286fcc6ce 100644 --- a/src/test/ui/error-codes/E0109.stderr +++ b/src/test/ui/error-codes/E0109.stderr @@ -1,7 +1,7 @@ -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/E0109.rs:1:14 | -LL | type X = u32; //~ ERROR E0109 +LL | type X = u32; | ^^^ type argument not allowed error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0110.rs b/src/test/ui/error-codes/E0110.rs index 764b62b8dfecf..314c7f5af6036 100644 --- a/src/test/ui/error-codes/E0110.rs +++ b/src/test/ui/error-codes/E0110.rs @@ -1,3 +1,3 @@ -type X = u32<'static>; //~ ERROR E0110 +type X = u32<'static>; //~ ERROR E0109 fn main() {} diff --git a/src/test/ui/error-codes/E0110.stderr b/src/test/ui/error-codes/E0110.stderr index a644ac92cefbf..b022131808738 100644 --- a/src/test/ui/error-codes/E0110.stderr +++ b/src/test/ui/error-codes/E0110.stderr @@ -1,9 +1,9 @@ -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/E0110.rs:1:14 | -LL | type X = u32<'static>; //~ ERROR E0110 +LL | type X = u32<'static>; | ^^^^^^^ lifetime argument not allowed error: aborting due to previous error -For more information about this error, try `rustc --explain E0110`. +For more information about this error, try `rustc --explain E0109`. diff --git a/src/test/ui/error-codes/E0117.stderr b/src/test/ui/error-codes/E0117.stderr index b007ca05ab2cf..6c0bbc2b62801 100644 --- a/src/test/ui/error-codes/E0117.stderr +++ b/src/test/ui/error-codes/E0117.stderr @@ -1,13 +1,13 @@ error[E0120]: the Drop trait may only be implemented on structures --> $DIR/E0117.rs:1:15 | -LL | impl Drop for u32 {} //~ ERROR E0117 +LL | impl Drop for u32 {} | ^^^ implementing Drop requires a struct error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> $DIR/E0117.rs:1:1 | -LL | impl Drop for u32 {} //~ ERROR E0117 +LL | impl Drop for u32 {} | ^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate | = note: the impl does not reference only types defined in this crate @@ -15,5 +15,5 @@ LL | impl Drop for u32 {} //~ ERROR E0117 error: aborting due to 2 previous errors -Some errors occurred: E0117, E0120. +Some errors have detailed explanations: E0117, E0120. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/error-codes/E0118.stderr b/src/test/ui/error-codes/E0118.stderr index 787f8caec7f49..b0afaeb5c1fa9 100644 --- a/src/test/ui/error-codes/E0118.stderr +++ b/src/test/ui/error-codes/E0118.stderr @@ -1,7 +1,7 @@ error[E0118]: no base type found for inherent implementation --> $DIR/E0118.rs:1:6 | -LL | impl (u8, u8) { //~ ERROR E0118 +LL | impl (u8, u8) { | ^^^^^^^^ impl requires a base type | = note: either implement a trait on it or create a newtype to wrap it instead diff --git a/src/test/ui/error-codes/E0119.stderr b/src/test/ui/error-codes/E0119.stderr index af9acb294bcde..e7690aa30bd20 100644 --- a/src/test/ui/error-codes/E0119.stderr +++ b/src/test/ui/error-codes/E0119.stderr @@ -4,7 +4,7 @@ error[E0119]: conflicting implementations of trait `MyTrait` for type `Foo`: LL | impl MyTrait for T { | --------------------- first implementation here ... -LL | impl MyTrait for Foo { //~ ERROR E0119 +LL | impl MyTrait for Foo { | ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Foo` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0120.rs b/src/test/ui/error-codes/E0120.rs index 049707415e505..287a4088183f4 100644 --- a/src/test/ui/error-codes/E0120.rs +++ b/src/test/ui/error-codes/E0120.rs @@ -1,6 +1,6 @@ trait MyTrait { fn foo() {} } -impl Drop for MyTrait { +impl Drop for dyn MyTrait { //~^ ERROR E0120 fn drop(&mut self) {} } diff --git a/src/test/ui/error-codes/E0120.stderr b/src/test/ui/error-codes/E0120.stderr index 9b6603dbaca9c..68ca7d800d5ce 100644 --- a/src/test/ui/error-codes/E0120.stderr +++ b/src/test/ui/error-codes/E0120.stderr @@ -1,8 +1,8 @@ error[E0120]: the Drop trait may only be implemented on structures --> $DIR/E0120.rs:3:15 | -LL | impl Drop for MyTrait { - | ^^^^^^^ implementing Drop requires a struct +LL | impl Drop for dyn MyTrait { + | ^^^^^^^^^^^ implementing Drop requires a struct error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0121.stderr b/src/test/ui/error-codes/E0121.stderr index 75e03c659b77b..b7f4ce4d230ef 100644 --- a/src/test/ui/error-codes/E0121.stderr +++ b/src/test/ui/error-codes/E0121.stderr @@ -1,13 +1,13 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/E0121.rs:1:13 | -LL | fn foo() -> _ { 5 } //~ ERROR E0121 +LL | fn foo() -> _ { 5 } | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/E0121.rs:3:13 | -LL | static BAR: _ = "test"; //~ ERROR E0121 +LL | static BAR: _ = "test"; | ^ not allowed in type signatures error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0128.stderr b/src/test/ui/error-codes/E0128.stderr index 9ea3c09e63f53..253aa166bd371 100644 --- a/src/test/ui/error-codes/E0128.stderr +++ b/src/test/ui/error-codes/E0128.stderr @@ -1,7 +1,7 @@ error[E0128]: type parameters with a default cannot use forward declared identifiers --> $DIR/E0128.rs:1:14 | -LL | struct Foo { //~ ERROR E0128 +LL | struct Foo { | ^ defaulted type parameters cannot be forward declared error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0132.stderr b/src/test/ui/error-codes/E0132.stderr index e19b421bfdb9f..c21363756b3e6 100644 --- a/src/test/ui/error-codes/E0132.stderr +++ b/src/test/ui/error-codes/E0132.stderr @@ -1,7 +1,7 @@ error[E0132]: start function is not allowed to have type parameters --> $DIR/E0132.rs:4:5 | -LL | fn f< T >() {} //~ ERROR E0132 +LL | fn f< T >() {} | ^^^^^ start function cannot have type parameters error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0152.stderr b/src/test/ui/error-codes/E0152.stderr index 401c1755fa8be..26e6e2e1bce7e 100644 --- a/src/test/ui/error-codes/E0152.stderr +++ b/src/test/ui/error-codes/E0152.stderr @@ -1,7 +1,7 @@ error[E0152]: duplicate lang item found: `arc`. --> $DIR/E0152.rs:4:1 | -LL | struct Foo; //~ ERROR E0152 +LL | struct Foo; | ^^^^^^^^^^^ | = note: first defined in crate `alloc`. diff --git a/src/test/ui/error-codes/E0161.ast.stderr b/src/test/ui/error-codes/E0161.migrate.stderr similarity index 100% rename from src/test/ui/error-codes/E0161.ast.stderr rename to src/test/ui/error-codes/E0161.migrate.stderr diff --git a/src/test/ui/error-codes/E0161.astul.stderr b/src/test/ui/error-codes/E0161.migrateul.stderr similarity index 100% rename from src/test/ui/error-codes/E0161.astul.stderr rename to src/test/ui/error-codes/E0161.migrateul.stderr diff --git a/src/test/ui/error-codes/E0161.rs b/src/test/ui/error-codes/E0161.rs index a6d2b245eb184..2ca17050ae2a4 100644 --- a/src/test/ui/error-codes/E0161.rs +++ b/src/test/ui/error-codes/E0161.rs @@ -3,15 +3,15 @@ // Check that E0161 is a hard error in all possible configurations that might // affect it. -// revisions: ast nll zflags edition astul nllul zflagsul editionul -//[zflags]compile-flags: -Z borrowck=migrate -Z two-phase-borrows +// revisions: migrate nll zflags edition migrateul nllul zflagsul editionul +//[zflags]compile-flags: -Z borrowck=migrate //[edition]edition:2018 -//[zflagsul]compile-flags: -Z borrowck=migrate -Z two-phase-borrows +//[zflagsul]compile-flags: -Z borrowck=migrate //[editionul]edition:2018 #![cfg_attr(nll, feature(nll))] #![cfg_attr(nllul, feature(nll))] -#![cfg_attr(astul, feature(unsized_locals))] +#![cfg_attr(migrateul, feature(unsized_locals))] #![cfg_attr(zflagsul, feature(unsized_locals))] #![cfg_attr(nllul, feature(unsized_locals))] #![cfg_attr(editionul, feature(unsized_locals))] @@ -20,11 +20,11 @@ fn foo(x: Box<[i32]>) { box *x; - //[ast]~^ ERROR E0161 + //[migrate]~^ ERROR E0161 //[nll]~^^ ERROR E0161 //[zflags]~^^^ ERROR E0161 //[edition]~^^^^ ERROR E0161 - //[astul]~^^^^^ ERROR E0161 + //[migrateul]~^^^^^ ERROR E0161 //[nllul]~^^^^^^ ERROR E0161 //[zflagsul]~^^^^^^^ ERROR E0161 //[editionul]~^^^^^^^^ ERROR E0161 diff --git a/src/test/ui/error-codes/E0161.stderr b/src/test/ui/error-codes/E0161.stderr deleted file mode 100644 index 0135e495c16b5..0000000000000 --- a/src/test/ui/error-codes/E0161.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0161]: cannot move a value of type str: the size of str cannot be statically determined - --> $DIR/E0161.rs:14:28 - | -LL | let _x: Box = box *"hello"; //~ ERROR E0161 - | ^^^^^^^^ - -error[E0507]: cannot move out of borrowed content - --> $DIR/E0161.rs:14:28 - | -LL | let _x: Box = box *"hello"; //~ ERROR E0161 - | ^^^^^^^^ cannot move out of borrowed content - -error: aborting due to 2 previous errors - -Some errors occurred: E0161, E0507. -For more information about an error, try `rustc --explain E0161`. diff --git a/src/test/ui/error-codes/E0164.stderr b/src/test/ui/error-codes/E0164.stderr index 0debc8092e86d..0a153d85b4215 100644 --- a/src/test/ui/error-codes/E0164.stderr +++ b/src/test/ui/error-codes/E0164.stderr @@ -1,7 +1,7 @@ error[E0164]: expected tuple struct/variant, found associated constant `::B` --> $DIR/E0164.rs:9:9 | -LL | Foo::B(i) => i, //~ ERROR E0164 +LL | Foo::B(i) => i, | ^^^^^^^^^ not a tuple variant or struct error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0184.stderr b/src/test/ui/error-codes/E0184.stderr index 471ba3870e21d..b4128b9560664 100644 --- a/src/test/ui/error-codes/E0184.stderr +++ b/src/test/ui/error-codes/E0184.stderr @@ -1,7 +1,7 @@ error[E0184]: the trait `Copy` may not be implemented for this type; the type has a destructor --> $DIR/E0184.rs:1:10 | -LL | #[derive(Copy)] //~ ERROR E0184 +LL | #[derive(Copy)] | ^^^^ Copy not allowed on types with destructors error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0186.stderr b/src/test/ui/error-codes/E0186.stderr index 7fed0426ee874..8971d61fc758e 100644 --- a/src/test/ui/error-codes/E0186.stderr +++ b/src/test/ui/error-codes/E0186.stderr @@ -1,10 +1,10 @@ error[E0186]: method `foo` has a `&self` declaration in the trait, but not in the impl --> $DIR/E0186.rs:8:5 | -LL | fn foo(&self); //~ `&self` used in trait +LL | fn foo(&self); | -------------- `&self` used in trait ... -LL | fn foo() {} //~ ERROR E0186 +LL | fn foo() {} | ^^^^^^^^ expected `&self` in impl error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0191.rs b/src/test/ui/error-codes/E0191.rs index 356110671e715..22f739b9e76c2 100644 --- a/src/test/ui/error-codes/E0191.rs +++ b/src/test/ui/error-codes/E0191.rs @@ -2,6 +2,6 @@ trait Trait { type Bar; } -type Foo = Trait; //~ ERROR E0191 +type Foo = dyn Trait; //~ ERROR E0191 fn main() {} diff --git a/src/test/ui/error-codes/E0191.stderr b/src/test/ui/error-codes/E0191.stderr index 570b0ddc3131a..92fa85bca0eff 100644 --- a/src/test/ui/error-codes/E0191.stderr +++ b/src/test/ui/error-codes/E0191.stderr @@ -4,8 +4,8 @@ error[E0191]: the value of the associated type `Bar` (from the trait `Trait`) mu LL | type Bar; | --------- `Bar` defined here ... -LL | type Foo = Trait; //~ ERROR E0191 - | ^^^^^ associated type `Bar` must be specified +LL | type Foo = dyn Trait; + | ^^^^^^^^^ associated type `Bar` must be specified error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0192.stderr b/src/test/ui/error-codes/E0192.stderr index bdfe717afe279..8faa550a50935 100644 --- a/src/test/ui/error-codes/E0192.stderr +++ b/src/test/ui/error-codes/E0192.stderr @@ -1,7 +1,7 @@ error[E0192]: negative impls are only allowed for auto traits (e.g., `Send` and `Sync`) --> $DIR/E0192.rs:9:1 | -LL | impl !Trait for Foo { } //~ ERROR E0192 +LL | impl !Trait for Foo { } | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0195.stderr b/src/test/ui/error-codes/E0195.stderr index 57032c6b0c843..6eaa1750ee355 100644 --- a/src/test/ui/error-codes/E0195.stderr +++ b/src/test/ui/error-codes/E0195.stderr @@ -4,7 +4,7 @@ error[E0195]: lifetime parameters or bounds on method `bar` do not match the tra LL | fn bar<'a,'b:'a>(x: &'a str, y: &'b str); | ---------- lifetimes in impl do not match this method in trait ... -LL | fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195 +LL | fn bar<'a,'b>(x: &'a str, y: &'b str) { | ^^^^^^^ lifetimes do not match method in trait error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0197.stderr b/src/test/ui/error-codes/E0197.stderr index f58dcd791da1d..bb7b6474d3e38 100644 --- a/src/test/ui/error-codes/E0197.stderr +++ b/src/test/ui/error-codes/E0197.stderr @@ -1,7 +1,7 @@ error[E0197]: inherent impls cannot be unsafe --> $DIR/E0197.rs:3:1 | -LL | unsafe impl Foo { } //~ ERROR E0197 +LL | unsafe impl Foo { } | ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0198.stderr b/src/test/ui/error-codes/E0198.stderr index e182cbd2ec155..0d3706336a9ca 100644 --- a/src/test/ui/error-codes/E0198.stderr +++ b/src/test/ui/error-codes/E0198.stderr @@ -1,7 +1,7 @@ error[E0198]: negative impls cannot be unsafe --> $DIR/E0198.rs:5:1 | -LL | unsafe impl !Send for Foo { } //~ ERROR E0198 +LL | unsafe impl !Send for Foo { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0199.stderr b/src/test/ui/error-codes/E0199.stderr index ba55c4a58e476..3632d26cd32e5 100644 --- a/src/test/ui/error-codes/E0199.stderr +++ b/src/test/ui/error-codes/E0199.stderr @@ -1,7 +1,7 @@ error[E0199]: implementing the trait `Bar` is not unsafe --> $DIR/E0199.rs:6:1 | -LL | unsafe impl Bar for Foo { } //~ ERROR implementing the trait `Bar` is not unsafe [E0199] +LL | unsafe impl Bar for Foo { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0200.stderr b/src/test/ui/error-codes/E0200.stderr index f6a8f32d2384d..677271aad445e 100644 --- a/src/test/ui/error-codes/E0200.stderr +++ b/src/test/ui/error-codes/E0200.stderr @@ -1,7 +1,7 @@ error[E0200]: the trait `Bar` requires an `unsafe impl` declaration --> $DIR/E0200.rs:5:1 | -LL | impl Bar for Foo { } //~ ERROR E0200 +LL | impl Bar for Foo { } | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0201.stderr b/src/test/ui/error-codes/E0201.stderr index 5d2f9f3e362e4..89cfd4024230b 100644 --- a/src/test/ui/error-codes/E0201.stderr +++ b/src/test/ui/error-codes/E0201.stderr @@ -3,7 +3,7 @@ error[E0201]: duplicate definitions with name `bar`: | LL | fn bar(&self) -> bool { self.0 > 5 } | ------------------------------------ previous definition of `bar` here -LL | fn bar() {} //~ ERROR E0201 +LL | fn bar() {} | ^^^^^^^^^^^ duplicate definition error[E0201]: duplicate definitions with name `baz`: @@ -11,7 +11,7 @@ error[E0201]: duplicate definitions with name `baz`: | LL | fn baz(&self) -> bool { true } | ------------------------------ previous definition of `baz` here -LL | fn baz(&self) -> bool { self.0 > 5 } //~ ERROR E0201 +LL | fn baz(&self) -> bool { self.0 > 5 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition error[E0201]: duplicate definitions with name `Quux`: @@ -20,7 +20,7 @@ error[E0201]: duplicate definitions with name `Quux`: LL | type Quux = u32; | ---------------- previous definition of `Quux` here ... -LL | type Quux = u32; //~ ERROR E0201 +LL | type Quux = u32; | ^^^^^^^^^^^^^^^^ duplicate definition error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/E0206.stderr b/src/test/ui/error-codes/E0206.stderr index a0c4b0149a099..cd5d74854eff8 100644 --- a/src/test/ui/error-codes/E0206.stderr +++ b/src/test/ui/error-codes/E0206.stderr @@ -21,5 +21,5 @@ LL | impl Copy for Foo { } error: aborting due to 3 previous errors -Some errors occurred: E0117, E0206. +Some errors have detailed explanations: E0117, E0206. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/error-codes/E0207.stderr b/src/test/ui/error-codes/E0207.stderr index c82859a9867e6..5ef51ed86926a 100644 --- a/src/test/ui/error-codes/E0207.stderr +++ b/src/test/ui/error-codes/E0207.stderr @@ -1,7 +1,7 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates --> $DIR/E0207.rs:3:6 | -LL | impl Foo { //~ ERROR E0207 +LL | impl Foo { | ^ unconstrained type parameter error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0220.rs b/src/test/ui/error-codes/E0220.rs index f4798042538dd..e11a570df79d5 100644 --- a/src/test/ui/error-codes/E0220.rs +++ b/src/test/ui/error-codes/E0220.rs @@ -2,7 +2,7 @@ trait Trait { type Bar; } -type Foo = Trait; //~ ERROR E0220 - //~| ERROR E0191 +type Foo = dyn Trait; //~ ERROR E0220 + //~| ERROR E0191 fn main() { } diff --git a/src/test/ui/error-codes/E0220.stderr b/src/test/ui/error-codes/E0220.stderr index 0eb812a5ef071..5da302748cdaf 100644 --- a/src/test/ui/error-codes/E0220.stderr +++ b/src/test/ui/error-codes/E0220.stderr @@ -1,8 +1,8 @@ error[E0220]: associated type `F` not found for `Trait` - --> $DIR/E0220.rs:5:18 + --> $DIR/E0220.rs:5:22 | -LL | type Foo = Trait; //~ ERROR E0220 - | ^^^^^ associated type `F` not found +LL | type Foo = dyn Trait; + | ^^^^^ associated type `F` not found error[E0191]: the value of the associated type `Bar` (from the trait `Trait`) must be specified --> $DIR/E0220.rs:5:12 @@ -10,10 +10,10 @@ error[E0191]: the value of the associated type `Bar` (from the trait `Trait`) mu LL | type Bar; | --------- `Bar` defined here ... -LL | type Foo = Trait; //~ ERROR E0220 - | ^^^^^^^^^^^^ associated type `Bar` must be specified +LL | type Foo = dyn Trait; + | ^^^^^^^^^^^^^^^^ associated type `Bar` must be specified error: aborting due to 2 previous errors -Some errors occurred: E0191, E0220. +Some errors have detailed explanations: E0191, E0220. For more information about an error, try `rustc --explain E0191`. diff --git a/src/test/ui/error-codes/E0225.rs b/src/test/ui/error-codes/E0225.rs index 1789be1559d82..b50f68e64516f 100644 --- a/src/test/ui/error-codes/E0225.rs +++ b/src/test/ui/error-codes/E0225.rs @@ -1,4 +1,10 @@ +#![feature(trait_alias)] + +trait Foo = std::io::Read + std::io::Write; + fn main() { - let _: Box; + let _: Box; + //~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + let _: Box; //~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] } diff --git a/src/test/ui/error-codes/E0225.stderr b/src/test/ui/error-codes/E0225.stderr index 85a04708cb255..c7a66c327f1c1 100644 --- a/src/test/ui/error-codes/E0225.stderr +++ b/src/test/ui/error-codes/E0225.stderr @@ -1,9 +1,28 @@ error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/E0225.rs:2:32 + --> $DIR/E0225.rs:6:36 | -LL | let _: Box; - | ^^^^^^^^^^^^^^ non-auto additional trait +LL | let _: Box; + | ------------- ^^^^^^^^^^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) -error: aborting due to previous error +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/E0225.rs:8:20 + | +LL | trait Foo = std::io::Read + std::io::Write; + | ------------- -------------- additional non-auto trait + | | + | first non-auto trait +... +LL | let _: Box; + | ^^^ + | | + | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0225`. diff --git a/src/test/ui/error-codes/E0252.stderr b/src/test/ui/error-codes/E0252.stderr index bd06241fc76d1..8486806c6729c 100644 --- a/src/test/ui/error-codes/E0252.stderr +++ b/src/test/ui/error-codes/E0252.stderr @@ -3,13 +3,13 @@ error[E0252]: the name `baz` is defined multiple times | LL | use foo::baz; | -------- previous import of the type `baz` here -LL | use bar::baz; //~ ERROR E0252 +LL | use bar::baz; | ^^^^^^^^ `baz` reimported here | = note: `baz` must be defined only once in the type namespace of this module help: you can use `as` to change the binding name of the import | -LL | use bar::baz as other_baz; //~ ERROR E0252 +LL | use bar::baz as other_baz; | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0254.rs b/src/test/ui/error-codes/E0254.rs index 706cd347e134a..d166aff565792 100644 --- a/src/test/ui/error-codes/E0254.rs +++ b/src/test/ui/error-codes/E0254.rs @@ -1,4 +1,3 @@ -#![feature(alloc)] #![allow(unused_extern_crates, non_camel_case_types)] extern crate alloc; diff --git a/src/test/ui/error-codes/E0254.stderr b/src/test/ui/error-codes/E0254.stderr index c2d013da41747..10456fd5a5dc1 100644 --- a/src/test/ui/error-codes/E0254.stderr +++ b/src/test/ui/error-codes/E0254.stderr @@ -1,5 +1,5 @@ error[E0254]: the name `alloc` is defined multiple times - --> $DIR/E0254.rs:12:5 + --> $DIR/E0254.rs:11:5 | LL | extern crate alloc; | ------------------- previous import of the extern crate `alloc` here diff --git a/src/test/ui/error-codes/E0255.stderr b/src/test/ui/error-codes/E0255.stderr index a47aa7c6592dd..36e4eeeaeea76 100644 --- a/src/test/ui/error-codes/E0255.stderr +++ b/src/test/ui/error-codes/E0255.stderr @@ -4,7 +4,7 @@ error[E0255]: the name `foo` is defined multiple times LL | use bar::foo; | -------- previous import of the value `foo` here LL | -LL | fn foo() {} //~ ERROR E0255 +LL | fn foo() {} | ^^^^^^^^ `foo` redefined here | = note: `foo` must be defined only once in the value namespace of this module diff --git a/src/test/ui/error-codes/E0259.rs b/src/test/ui/error-codes/E0259.rs index cda3db34dfc41..c83561be9c6a5 100644 --- a/src/test/ui/error-codes/E0259.rs +++ b/src/test/ui/error-codes/E0259.rs @@ -1,4 +1,4 @@ -#![feature(alloc, rustc_private)] +#![feature(rustc_private)] #![allow(unused_extern_crates)] extern crate alloc; diff --git a/src/test/ui/error-codes/E0260.rs b/src/test/ui/error-codes/E0260.rs index 80382c0d2fcb5..73b8934159fcf 100644 --- a/src/test/ui/error-codes/E0260.rs +++ b/src/test/ui/error-codes/E0260.rs @@ -1,4 +1,3 @@ -#![feature(alloc)] #![allow(unused_extern_crates)] extern crate alloc; diff --git a/src/test/ui/error-codes/E0260.stderr b/src/test/ui/error-codes/E0260.stderr index bfe2ed0cfc778..7d0b3022914d8 100644 --- a/src/test/ui/error-codes/E0260.stderr +++ b/src/test/ui/error-codes/E0260.stderr @@ -1,5 +1,5 @@ error[E0260]: the name `alloc` is defined multiple times - --> $DIR/E0260.rs:6:1 + --> $DIR/E0260.rs:5:1 | LL | extern crate alloc; | ------------------- previous import of the extern crate `alloc` here diff --git a/src/test/ui/error-codes/E0261.stderr b/src/test/ui/error-codes/E0261.stderr index 9e64f6c3f1495..3bf5e9d815485 100644 --- a/src/test/ui/error-codes/E0261.stderr +++ b/src/test/ui/error-codes/E0261.stderr @@ -1,13 +1,13 @@ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/E0261.rs:1:12 | -LL | fn foo(x: &'a str) { } //~ ERROR E0261 +LL | fn foo(x: &'a str) { } | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/E0261.rs:5:9 | -LL | x: &'a str, //~ ERROR E0261 +LL | x: &'a str, | ^^ undeclared lifetime error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0262.stderr b/src/test/ui/error-codes/E0262.stderr index 8f01889a470b3..ad90b7171266e 100644 --- a/src/test/ui/error-codes/E0262.stderr +++ b/src/test/ui/error-codes/E0262.stderr @@ -1,7 +1,7 @@ error[E0262]: invalid lifetime parameter name: `'static` --> $DIR/E0262.rs:1:8 | -LL | fn foo<'static>(x: &'static str) { } //~ ERROR E0262 +LL | fn foo<'static>(x: &'static str) { } | ^^^^^^^ 'static is a reserved lifetime name error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0264.stderr b/src/test/ui/error-codes/E0264.stderr index bc6a0d9f96c3c..403c0aa4146c7 100644 --- a/src/test/ui/error-codes/E0264.stderr +++ b/src/test/ui/error-codes/E0264.stderr @@ -1,7 +1,7 @@ error[E0264]: unknown external lang item: `cake` --> $DIR/E0264.rs:5:5 | -LL | fn cake(); //~ ERROR E0264 +LL | fn cake(); | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0267.stderr b/src/test/ui/error-codes/E0267.stderr index 3506c1c0f165a..b14cfd1a52d47 100644 --- a/src/test/ui/error-codes/E0267.stderr +++ b/src/test/ui/error-codes/E0267.stderr @@ -1,7 +1,7 @@ error[E0267]: `break` inside of a closure --> $DIR/E0267.rs:2:18 | -LL | let w = || { break; }; //~ ERROR E0267 +LL | let w = || { break; }; | ^^^^^ cannot break inside of a closure error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0268.stderr b/src/test/ui/error-codes/E0268.stderr index 3e276bd1acb00..3c77e7f3df2be 100644 --- a/src/test/ui/error-codes/E0268.stderr +++ b/src/test/ui/error-codes/E0268.stderr @@ -1,7 +1,7 @@ error[E0268]: `break` outside of loop --> $DIR/E0268.rs:2:5 | -LL | break; //~ ERROR E0268 +LL | break; | ^^^^^ cannot break outside of a loop error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0271.stderr b/src/test/ui/error-codes/E0271.stderr index 8fcb68e434f80..16c3ab9d7425b 100644 --- a/src/test/ui/error-codes/E0271.stderr +++ b/src/test/ui/error-codes/E0271.stderr @@ -1,7 +1,7 @@ error[E0271]: type mismatch resolving `::AssociatedType == u32` --> $DIR/E0271.rs:10:5 | -LL | foo(3_i8); //~ ERROR E0271 +LL | foo(3_i8); | ^^^ expected reference, found u32 | = note: expected type `&'static str` diff --git a/src/test/ui/error-codes/E0275.stderr b/src/test/ui/error-codes/E0275.stderr index f2b0f392bc8bc..40991cb2297c9 100644 --- a/src/test/ui/error-codes/E0275.stderr +++ b/src/test/ui/error-codes/E0275.stderr @@ -1,10 +1,74 @@ -error[E0275]: overflow evaluating the requirement `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` +error[E0275]: overflow evaluating the requirement `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/E0275.rs:5:1 | -LL | impl Foo for T where Bar: Foo {} //~ ERROR E0275 +LL | impl Foo for T where Bar: Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding a `#![recursion_limit="128"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` diff --git a/src/test/ui/error-codes/E0276.stderr b/src/test/ui/error-codes/E0276.stderr index 393ad8c81a071..a8b016ebf52ae 100644 --- a/src/test/ui/error-codes/E0276.stderr +++ b/src/test/ui/error-codes/E0276.stderr @@ -4,7 +4,7 @@ error[E0276]: impl has stricter requirements than trait LL | fn foo(x: T); | ---------------- definition of `foo` from trait ... -LL | fn foo(x: T) where T: Copy {} //~ ERROR E0276 +LL | fn foo(x: T) where T: Copy {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::marker::Copy` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0282.stderr b/src/test/ui/error-codes/E0282.stderr index 49165d1e42bbb..3a5040eb6daa6 100644 --- a/src/test/ui/error-codes/E0282.stderr +++ b/src/test/ui/error-codes/E0282.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed --> $DIR/E0282.rs:2:9 | -LL | let x = "hello".chars().rev().collect(); //~ ERROR E0282 +LL | let x = "hello".chars().rev().collect(); | ^ | | | cannot infer type diff --git a/src/test/ui/error-codes/E0283.stderr b/src/test/ui/error-codes/E0283.stderr index 598ec672ce635..e1f53e592fc85 100644 --- a/src/test/ui/error-codes/E0283.stderr +++ b/src/test/ui/error-codes/E0283.stderr @@ -1,7 +1,7 @@ error[E0283]: type annotations required: cannot resolve `_: Generator` --> $DIR/E0283.rs:18:21 | -LL | let cont: u32 = Generator::create(); //~ ERROR E0283 +LL | let cont: u32 = Generator::create(); | ^^^^^^^^^^^^^^^^^ | note: required by `Generator::create` diff --git a/src/test/ui/error-codes/E0301.nll.stderr b/src/test/ui/error-codes/E0301.nll.stderr deleted file mode 100644 index 898c30a75b28d..0000000000000 --- a/src/test/ui/error-codes/E0301.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0301]: cannot mutably borrow in a pattern guard - --> $DIR/E0301.rs:4:19 - | -LL | option if option.take().is_none() => {}, //~ ERROR E0301 - | ^^^^^^ borrowed mutably in pattern guard - | - = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0301`. diff --git a/src/test/ui/error-codes/E0301.rs b/src/test/ui/error-codes/E0301.rs index 54372f8b6b4c5..3b451801c99df 100644 --- a/src/test/ui/error-codes/E0301.rs +++ b/src/test/ui/error-codes/E0301.rs @@ -2,6 +2,6 @@ fn main() { match Some(()) { None => { }, option if option.take().is_none() => {}, //~ ERROR E0301 - Some(_) => { } + Some(_) => { } //~^ ERROR E0596 } } diff --git a/src/test/ui/error-codes/E0301.stderr b/src/test/ui/error-codes/E0301.stderr index 3cfacd5983f0d..44e823631b592 100644 --- a/src/test/ui/error-codes/E0301.stderr +++ b/src/test/ui/error-codes/E0301.stderr @@ -1,9 +1,20 @@ error[E0301]: cannot mutably borrow in a pattern guard --> $DIR/E0301.rs:4:19 | -LL | option if option.take().is_none() => {}, //~ ERROR E0301 +LL | option if option.take().is_none() => {}, | ^^^^^^ borrowed mutably in pattern guard + | + = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable + +error[E0596]: cannot borrow `option` as mutable, as it is immutable for the pattern guard + --> $DIR/E0301.rs:4:19 + | +LL | option if option.take().is_none() => {}, + | ^^^^^^ cannot borrow as mutable + | + = note: variables bound in patterns are immutable until the end of the pattern guard -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0301`. +Some errors have detailed explanations: E0301, E0596. +For more information about an error, try `rustc --explain E0301`. diff --git a/src/test/ui/error-codes/E0302.rs b/src/test/ui/error-codes/E0302.rs index 7c76eb30c1d29..69f5953deb223 100644 --- a/src/test/ui/error-codes/E0302.rs +++ b/src/test/ui/error-codes/E0302.rs @@ -2,6 +2,7 @@ fn main() { match Some(()) { None => { }, option if { option = None; false } => { }, //~ ERROR E0302 + //~^ ERROR cannot assign to `option`, as it is immutable for the pattern guard Some(_) => { } } } diff --git a/src/test/ui/error-codes/E0302.stderr b/src/test/ui/error-codes/E0302.stderr index 66b31361762d2..a077fcaea4101 100644 --- a/src/test/ui/error-codes/E0302.stderr +++ b/src/test/ui/error-codes/E0302.stderr @@ -1,9 +1,17 @@ error[E0302]: cannot assign in a pattern guard --> $DIR/E0302.rs:4:21 | -LL | option if { option = None; false } => { }, //~ ERROR E0302 +LL | option if { option = None; false } => { }, | ^^^^^^^^^^^^^ assignment in pattern guard -error: aborting due to previous error +error[E0594]: cannot assign to `option`, as it is immutable for the pattern guard + --> $DIR/E0302.rs:4:21 + | +LL | option if { option = None; false } => { }, + | ^^^^^^^^^^^^^ cannot assign + | + = note: variables bound in patterns are immutable until the end of the pattern guard + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0302`. diff --git a/src/test/ui/error-codes/E0303.stderr b/src/test/ui/error-codes/E0303.stderr index d701b07de6b5e..af537ce5625ca 100644 --- a/src/test/ui/error-codes/E0303.stderr +++ b/src/test/ui/error-codes/E0303.stderr @@ -15,5 +15,5 @@ LL | ref op_string_ref @ Some(s) => {}, error: aborting due to 2 previous errors -Some errors occurred: E0009, E0303. +Some errors have detailed explanations: E0009, E0303. For more information about an error, try `rustc --explain E0009`. diff --git a/src/test/ui/error-codes/E0308-4.stderr b/src/test/ui/error-codes/E0308-4.stderr index f69a389336590..3c51106cae8c8 100644 --- a/src/test/ui/error-codes/E0308-4.stderr +++ b/src/test/ui/error-codes/E0308-4.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | match x { | - this match expression has type `u8` -LL | 0u8..=3i8 => (), //~ ERROR E0308 +LL | 0u8..=3i8 => (), | ^^^^^^^^^ expected u8, found i8 error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0308.stderr b/src/test/ui/error-codes/E0308.stderr index 8c71747fbcdf0..bd9834ceb9fef 100644 --- a/src/test/ui/error-codes/E0308.stderr +++ b/src/test/ui/error-codes/E0308.stderr @@ -1,7 +1,7 @@ error[E0308]: intrinsic has wrong type --> $DIR/E0308.rs:4:5 | -LL | fn size_of(); //~ ERROR E0308 +LL | fn size_of(); | ^^^^^^^^^^^^^^^^ expected (), found usize | = note: expected type `extern "rust-intrinsic" fn()` diff --git a/src/test/ui/error-codes/E0370.stderr b/src/test/ui/error-codes/E0370.stderr index cd1903bd7e26f..7fb622ee80bbf 100644 --- a/src/test/ui/error-codes/E0370.stderr +++ b/src/test/ui/error-codes/E0370.stderr @@ -1,7 +1,7 @@ error[E0370]: enum discriminant overflowed --> $DIR/E0370.rs:7:5 | -LL | Y, //~ ERROR E0370 +LL | Y, | ^ overflowed on value after 9223372036854775807 | = note: explicitly set `Y = -9223372036854775808` if that is desired outcome diff --git a/src/test/ui/error-codes/E0374.stderr b/src/test/ui/error-codes/E0374.stderr index 9226ca0e478d7..7ab0f82fc2360 100644 --- a/src/test/ui/error-codes/E0374.stderr +++ b/src/test/ui/error-codes/E0374.stderr @@ -1,7 +1,7 @@ error[E0374]: the trait `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced, none found --> $DIR/E0374.rs:8:1 | -LL | / impl CoerceUnsized> for Foo //~ ERROR E0374 +LL | / impl CoerceUnsized> for Foo LL | | where T: CoerceUnsized {} | |________________________________^ diff --git a/src/test/ui/error-codes/E0375.rs b/src/test/ui/error-codes/E0375.rs index 362854a53aa63..0c03a8761df01 100644 --- a/src/test/ui/error-codes/E0375.rs +++ b/src/test/ui/error-codes/E0375.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - #![feature(coerce_unsized)] use std::ops::CoerceUnsized; diff --git a/src/test/ui/error-codes/E0375.stderr b/src/test/ui/error-codes/E0375.stderr index 18416e9b7d8b9..a68b3af5aaf76 100644 --- a/src/test/ui/error-codes/E0375.stderr +++ b/src/test/ui/error-codes/E0375.stderr @@ -1,5 +1,5 @@ error[E0375]: implementing the trait `CoerceUnsized` requires multiple coercions - --> $DIR/E0375.rs:12:12 + --> $DIR/E0375.rs:10:12 | LL | impl CoerceUnsized> for Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions diff --git a/src/test/ui/error-codes/E0376.stderr b/src/test/ui/error-codes/E0376.stderr index 2894a91963200..015448c39eaaa 100644 --- a/src/test/ui/error-codes/E0376.stderr +++ b/src/test/ui/error-codes/E0376.stderr @@ -1,7 +1,7 @@ error[E0376]: the trait `CoerceUnsized` may only be implemented for a coercion between structures --> $DIR/E0376.rs:8:1 | -LL | impl CoerceUnsized for Foo {} //~ ERROR E0376 +LL | impl CoerceUnsized for Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0388.nll.stderr b/src/test/ui/error-codes/E0388.nll.stderr deleted file mode 100644 index a898d60a98595..0000000000000 --- a/src/test/ui/error-codes/E0388.nll.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0017]: references in constants may only refer to immutable values - --> $DIR/E0388.rs:4:30 - | -LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017 - | ^^^^^^ constants require immutable values - -error[E0017]: references in statics may only refer to immutable values - --> $DIR/E0388.rs:5:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 - | ^^^^^^ statics require immutable values - -error: cannot mutate statics in the initializer of another static - --> $DIR/E0388.rs:5:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 - | ^^^^^^ - -error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0388.rs:5:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 - | ^^^^^^ cannot borrow as mutable - -error[E0017]: references in statics may only refer to immutable values - --> $DIR/E0388.rs:8:38 - | -LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 - | ^^^^^^ statics require immutable values - -error: aborting due to 5 previous errors - -Some errors occurred: E0017, E0596. -For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr index f641830ae9ff2..e0ca431673240 100644 --- a/src/test/ui/error-codes/E0388.stderr +++ b/src/test/ui/error-codes/E0388.stderr @@ -1,34 +1,34 @@ error[E0017]: references in constants may only refer to immutable values --> $DIR/E0388.rs:4:30 | -LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017 +LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ constants require immutable values error[E0017]: references in statics may only refer to immutable values --> $DIR/E0388.rs:5:39 | -LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 +LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ statics require immutable values error: cannot mutate statics in the initializer of another static --> $DIR/E0388.rs:5:39 | -LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 +LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ -error[E0596]: cannot borrow immutable static item as mutable - --> $DIR/E0388.rs:5:44 +error[E0596]: cannot borrow immutable static item `X` as mutable + --> $DIR/E0388.rs:5:39 | -LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 - | ^ +LL | static STATIC_REF: &'static mut i32 = &mut X; + | ^^^^^^ cannot borrow as mutable error[E0017]: references in statics may only refer to immutable values --> $DIR/E0388.rs:8:38 | -LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 +LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ statics require immutable values error: aborting due to 5 previous errors -Some errors occurred: E0017, E0596. +Some errors have detailed explanations: E0017, E0596. For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/error-codes/E0389.nll.stderr b/src/test/ui/error-codes/E0389.nll.stderr deleted file mode 100644 index 13d2f8cfaa59c..0000000000000 --- a/src/test/ui/error-codes/E0389.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0594]: cannot assign to `fancy_ref.num` which is behind a `&` reference - --> $DIR/E0389.rs:8:5 - | -LL | let fancy_ref = &(&mut fancy); - | ------------- help: consider changing this to be a mutable reference: `&mut (&mut fancy)` -LL | fancy_ref.num = 6; //~ ERROR E0389 - | ^^^^^^^^^^^^^^^^^ `fancy_ref` is a `&` reference, so the data it refers to cannot be written - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/error-codes/E0389.rs b/src/test/ui/error-codes/E0389.rs index 8b821330ebec2..9dab2c3092434 100644 --- a/src/test/ui/error-codes/E0389.rs +++ b/src/test/ui/error-codes/E0389.rs @@ -5,6 +5,6 @@ struct FancyNum { fn main() { let mut fancy = FancyNum{ num: 5 }; let fancy_ref = &(&mut fancy); - fancy_ref.num = 6; //~ ERROR E0389 + fancy_ref.num = 6; //~ ERROR cannot assign to `fancy_ref.num` which is behind a `&` reference println!("{}", fancy_ref.num); } diff --git a/src/test/ui/error-codes/E0389.stderr b/src/test/ui/error-codes/E0389.stderr index cc8914ef3a6f7..5310367d51a55 100644 --- a/src/test/ui/error-codes/E0389.stderr +++ b/src/test/ui/error-codes/E0389.stderr @@ -1,9 +1,10 @@ -error[E0389]: cannot assign to data in a `&` reference +error[E0594]: cannot assign to `fancy_ref.num` which is behind a `&` reference --> $DIR/E0389.rs:8:5 | -LL | fancy_ref.num = 6; //~ ERROR E0389 - | ^^^^^^^^^^^^^^^^^ assignment into an immutable reference +LL | let fancy_ref = &(&mut fancy); + | ------------- help: consider changing this to be a mutable reference: `&mut (&mut fancy)` +LL | fancy_ref.num = 6; + | ^^^^^^^^^^^^^^^^^ `fancy_ref` is a `&` reference, so the data it refers to cannot be written error: aborting due to previous error -For more information about this error, try `rustc --explain E0389`. diff --git a/src/test/ui/error-codes/E0390.stderr b/src/test/ui/error-codes/E0390.stderr index 7632229360ee8..3ca3a77c74fb7 100644 --- a/src/test/ui/error-codes/E0390.stderr +++ b/src/test/ui/error-codes/E0390.stderr @@ -1,13 +1,13 @@ error[E0390]: only a single inherent implementation marked with `#[lang = "mut_ptr"]` is allowed for the `*mut T` primitive --> $DIR/E0390.rs:5:1 | -LL | impl *mut Foo {} //~ ERROR E0390 +LL | impl *mut Foo {} | ^^^^^^^^^^^^^^^^ | help: consider using a trait to implement these methods --> $DIR/E0390.rs:5:1 | -LL | impl *mut Foo {} //~ ERROR E0390 +LL | impl *mut Foo {} | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0392.stderr b/src/test/ui/error-codes/E0392.stderr index 4bb3b87bb4a27..d0b808df184c4 100644 --- a/src/test/ui/error-codes/E0392.stderr +++ b/src/test/ui/error-codes/E0392.stderr @@ -1,8 +1,8 @@ error[E0392]: parameter `T` is never used --> $DIR/E0392.rs:1:10 | -LL | enum Foo { Bar } //~ ERROR E0392 - | ^ unused type parameter +LL | enum Foo { Bar } + | ^ unused parameter | = help: consider removing `T` or using a marker such as `std::marker::PhantomData` diff --git a/src/test/ui/error-codes/E0393.rs b/src/test/ui/error-codes/E0393.rs index bdd4deafc838e..0c1a369806d8f 100644 --- a/src/test/ui/error-codes/E0393.rs +++ b/src/test/ui/error-codes/E0393.rs @@ -1,6 +1,6 @@ trait A {} -fn together_we_will_rule_the_galaxy(son: &A) {} +fn together_we_will_rule_the_galaxy(son: &dyn A) {} //~^ ERROR E0393 fn main() { diff --git a/src/test/ui/error-codes/E0393.stderr b/src/test/ui/error-codes/E0393.stderr index bf564ef10210a..543e3213633c8 100644 --- a/src/test/ui/error-codes/E0393.stderr +++ b/src/test/ui/error-codes/E0393.stderr @@ -1,8 +1,8 @@ error[E0393]: the type parameter `T` must be explicitly specified - --> $DIR/E0393.rs:3:43 + --> $DIR/E0393.rs:3:47 | -LL | fn together_we_will_rule_the_galaxy(son: &A) {} - | ^ missing reference to `T` +LL | fn together_we_will_rule_the_galaxy(son: &dyn A) {} + | ^ missing reference to `T` | = note: because of the default `Self` reference, type parameters must be specified on object types diff --git a/src/test/ui/error-codes/E0395.rs b/src/test/ui/error-codes/E0395.rs index 9657bbdeadc17..bbefff27d7f68 100644 --- a/src/test/ui/error-codes/E0395.rs +++ b/src/test/ui/error-codes/E0395.rs @@ -3,6 +3,8 @@ static FOO: i32 = 42; static BAR: i32 = 42; -static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; //~ ERROR issue #53020 +static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; +//~^ ERROR comparing raw pointers inside static + fn main() { } diff --git a/src/test/ui/error-codes/E0395.stderr b/src/test/ui/error-codes/E0395.stderr index cc7d94e22eb6b..30a4d4815ffba 100644 --- a/src/test/ui/error-codes/E0395.stderr +++ b/src/test/ui/error-codes/E0395.stderr @@ -1,9 +1,10 @@ -error[E0658]: comparing raw pointers inside static (see issue #53020) +error[E0658]: comparing raw pointers inside static --> $DIR/E0395.rs:6:29 | -LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; //~ ERROR issue #53020 +LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53020 = help: add #![feature(const_compare_raw_pointers)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0396-fixed.stderr b/src/test/ui/error-codes/E0396-fixed.stderr index 2923d97662868..4b7f1fa82c26c 100644 --- a/src/test/ui/error-codes/E0396-fixed.stderr +++ b/src/test/ui/error-codes/E0396-fixed.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error - --> $DIR/E0396-fixed.rs:5:1 + --> $DIR/E0396-fixed.rs:5:28 | LL | const VALUE: u8 = unsafe { *REG_ADDR }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^---------^^^ + | ---------------------------^^^^^^^^^--- | | | a memory access tried to interpret some bytes as a pointer | diff --git a/src/test/ui/error-codes/E0396.stderr b/src/test/ui/error-codes/E0396.stderr index 1006ff6dc5424..6d2d121e91c00 100644 --- a/src/test/ui/error-codes/E0396.stderr +++ b/src/test/ui/error-codes/E0396.stderr @@ -1,9 +1,10 @@ -error[E0658]: dereferencing raw pointers in constants is unstable (see issue #51911) +error[E0658]: dereferencing raw pointers in constants is unstable --> $DIR/E0396.rs:5:28 | LL | const VALUE: u8 = unsafe { *REG_ADDR }; | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr index 27f281ee43786..1d9dfe46722ec 100644 --- a/src/test/ui/error-codes/E0401.stderr +++ b/src/test/ui/error-codes/E0401.stderr @@ -2,8 +2,8 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/E0401.rs:4:39 | LL | fn foo(x: T) { - | - type variable from outer function -LL | fn bfnr, W: Fn()>(y: T) { //~ ERROR E0401 + | - type parameter from outer function +LL | fn bfnr, W: Fn()>(y: T) { | --------------------------- ^ use of generic parameter from outer function | | | help: try using a local generic parameter instead: `bfnr, W: Fn(), T>` @@ -12,12 +12,12 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/E0401.rs:9:16 | LL | fn foo(x: T) { - | - type variable from outer function + | - type parameter from outer function ... LL | fn baz Iterator for A { | ---- `Self` type implicitly declared here, by this `impl` ... -LL | fn helper(sel: &Self) -> u8 { //~ ERROR E0401 +LL | fn helper(sel: &Self) -> u8 { | ^^^^ | | | use of generic parameter from outer function diff --git a/src/test/ui/error-codes/E0403.stderr b/src/test/ui/error-codes/E0403.stderr index b924647502965..2bd7de6c24614 100644 --- a/src/test/ui/error-codes/E0403.stderr +++ b/src/test/ui/error-codes/E0403.stderr @@ -1,7 +1,7 @@ error[E0403]: the name `T` is already used for a generic parameter in this list of generic parameters --> $DIR/E0403.rs:1:11 | -LL | fn foo(s: T, u: T) {} //~ ERROR E0403 +LL | fn foo(s: T, u: T) {} | - ^ already used | | | first use of `T` diff --git a/src/test/ui/error-codes/E0404.stderr b/src/test/ui/error-codes/E0404.stderr index f84fd52c851a8..4ccb6c5728e83 100644 --- a/src/test/ui/error-codes/E0404.stderr +++ b/src/test/ui/error-codes/E0404.stderr @@ -1,13 +1,13 @@ error[E0404]: expected trait, found struct `Foo` --> $DIR/E0404.rs:4:6 | -LL | impl Foo for Bar {} //~ ERROR E0404 +LL | impl Foo for Bar {} | ^^^ not a trait error[E0404]: expected trait, found struct `Foo` --> $DIR/E0404.rs:8:11 | -LL | fn baz(_: T) {} //~ ERROR E0404 +LL | fn baz(_: T) {} | ^^^ not a trait error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0405.stderr b/src/test/ui/error-codes/E0405.stderr index 2f09a525e450b..a22afe6f3e8c3 100644 --- a/src/test/ui/error-codes/E0405.stderr +++ b/src/test/ui/error-codes/E0405.stderr @@ -1,7 +1,7 @@ error[E0405]: cannot find trait `SomeTrait` in this scope --> $DIR/E0405.rs:3:6 | -LL | impl SomeTrait for Foo {} //~ ERROR E0405 +LL | impl SomeTrait for Foo {} | ^^^^^^^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0408.stderr b/src/test/ui/error-codes/E0408.stderr index dc0a41e6eb0f8..132a9432254fc 100644 --- a/src/test/ui/error-codes/E0408.stderr +++ b/src/test/ui/error-codes/E0408.stderr @@ -1,7 +1,7 @@ error[E0408]: variable `y` is not bound in all patterns --> $DIR/E0408.rs:5:19 | -LL | Some(y) | None => {} //~ ERROR variable `y` is not bound in all patterns +LL | Some(y) | None => {} | - ^^^^ pattern doesn't bind `y` | | | variable not in all patterns diff --git a/src/test/ui/error-codes/E0411.stderr b/src/test/ui/error-codes/E0411.stderr index fe78d8d957ea0..c1c25e835c148 100644 --- a/src/test/ui/error-codes/E0411.stderr +++ b/src/test/ui/error-codes/E0411.stderr @@ -1,7 +1,7 @@ error[E0411]: cannot find type `Self` in this scope --> $DIR/E0411.rs:2:6 | -LL | ::foo; //~ ERROR E0411 +LL | ::foo; | ^^^^ `Self` is only available in impls, traits, and type definitions error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0412.stderr b/src/test/ui/error-codes/E0412.stderr index 68d636ffae0b2..7bdaa18073075 100644 --- a/src/test/ui/error-codes/E0412.stderr +++ b/src/test/ui/error-codes/E0412.stderr @@ -1,7 +1,7 @@ error[E0412]: cannot find type `Something` in this scope --> $DIR/E0412.rs:1:6 | -LL | impl Something {} //~ ERROR E0412 +LL | impl Something {} | ^^^^^^^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0415.stderr b/src/test/ui/error-codes/E0415.stderr index 6e848f9bfd39c..c2b8fdc7c558b 100644 --- a/src/test/ui/error-codes/E0415.stderr +++ b/src/test/ui/error-codes/E0415.stderr @@ -1,7 +1,7 @@ error[E0415]: identifier `f` is bound more than once in this parameter list --> $DIR/E0415.rs:1:16 | -LL | fn foo(f: i32, f: i32) {} //~ ERROR E0415 +LL | fn foo(f: i32, f: i32) {} | ^ used as parameter more than once error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0416.stderr b/src/test/ui/error-codes/E0416.stderr index 4baf5006cf40a..78acac5c6617e 100644 --- a/src/test/ui/error-codes/E0416.stderr +++ b/src/test/ui/error-codes/E0416.stderr @@ -1,7 +1,7 @@ error[E0416]: identifier `x` is bound more than once in the same pattern --> $DIR/E0416.rs:3:13 | -LL | (x, x) => {} //~ ERROR E0416 +LL | (x, x) => {} | ^ used in a pattern more than once error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0423.rs b/src/test/ui/error-codes/E0423.rs index 2b26808d4bde5..5080a5e059987 100644 --- a/src/test/ui/error-codes/E0423.rs +++ b/src/test/ui/error-codes/E0423.rs @@ -10,8 +10,7 @@ fn bar() { struct T {} if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); } - //~^ ERROR E0423 - //~| expected type, found `1` + //~^ ERROR struct literals are not allowed here if T {} == T {} { println!("Ok"); } //~^ ERROR E0423 //~| ERROR expected expression, found `==` @@ -19,6 +18,5 @@ fn bar() { fn foo() { for _ in std::ops::Range { start: 0, end: 10 } {} - //~^ ERROR E0423 - //~| ERROR expected type, found `0` + //~^ ERROR struct literals are not allowed here } diff --git a/src/test/ui/error-codes/E0423.stderr b/src/test/ui/error-codes/E0423.stderr index d0deb8ce7ea26..ec240003f9182 100644 --- a/src/test/ui/error-codes/E0423.stderr +++ b/src/test/ui/error-codes/E0423.stderr @@ -1,54 +1,46 @@ -error: expected type, found `1` - --> $DIR/E0423.rs:12:39 +error: struct literals are not allowed here + --> $DIR/E0423.rs:12:32 | LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); } - | ^ expecting a type here because of type ascription + | ^^^^^^^^^^^^^^^^ +help: surround the struct literal with parentheses + | +LL | if let S { x: _x, y: 2 } = (S { x: 1, y: 2 }) { println!("Ok"); } + | ^ ^ error: expected expression, found `==` - --> $DIR/E0423.rs:15:13 + --> $DIR/E0423.rs:14:13 | LL | if T {} == T {} { println!("Ok"); } | ^^ expected expression -error: expected type, found `0` - --> $DIR/E0423.rs:21:39 +error: struct literals are not allowed here + --> $DIR/E0423.rs:20:14 | LL | for _ in std::ops::Range { start: 0, end: 10 } {} - | ^ expecting a type here because of type ascription + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: surround the struct literal with parentheses + | +LL | for _ in (std::ops::Range { start: 0, end: 10 }) {} + | ^ ^ error[E0423]: expected function, found struct `Foo` --> $DIR/E0423.rs:4:13 | -LL | let f = Foo(); //~ ERROR E0423 +LL | let f = Foo(); | ^^^ | | | did you mean `Foo { /* fields */ }`? | help: a function with a similar name exists: `foo` -error[E0423]: expected value, found struct `S` - --> $DIR/E0423.rs:12:32 - | -LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); } - | ^--------------- - | | - | help: surround the struct literal with parenthesis: `(S { x: 1, y: 2 })` - error[E0423]: expected value, found struct `T` - --> $DIR/E0423.rs:15:8 + --> $DIR/E0423.rs:14:8 | LL | if T {} == T {} { println!("Ok"); } | ^--- | | | help: surround the struct literal with parenthesis: `(T {})` -error[E0423]: expected value, found struct `std::ops::Range` - --> $DIR/E0423.rs:21:14 - | -LL | for _ in std::ops::Range { start: 0, end: 10 } {} - | ^^^^^^^^^^^^^^^---------------------- - | | - | help: surround the struct literal with parenthesis: `(std::ops::Range { start: 0, end: 10 })` - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0423`. diff --git a/src/test/ui/error-codes/E0424.stderr b/src/test/ui/error-codes/E0424.stderr index b91f061db3455..d67a2660dac38 100644 --- a/src/test/ui/error-codes/E0424.stderr +++ b/src/test/ui/error-codes/E0424.stderr @@ -1,13 +1,13 @@ error[E0424]: expected value, found module `self` --> $DIR/E0424.rs:7:9 | -LL | self.bar(); //~ ERROR E0424 +LL | self.bar(); | ^^^^ `self` value is a keyword only available in methods with `self` parameter error[E0424]: expected unit struct/variant or constant, found module `self` --> $DIR/E0424.rs:12:9 | -LL | let self = "self"; //~ ERROR E0424 +LL | let self = "self"; | ^^^^ `self` value is a keyword and may not be bound to variables or shadowed error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0425.stderr b/src/test/ui/error-codes/E0425.stderr index 391027a518409..9ef4608da7dad 100644 --- a/src/test/ui/error-codes/E0425.stderr +++ b/src/test/ui/error-codes/E0425.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `elf` in this scope --> $DIR/E0425.rs:3:9 | -LL | elf; //~ ERROR E0425 +LL | elf; | ^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0428.stderr b/src/test/ui/error-codes/E0428.stderr index 2154cb0ead286..205bcf342f1ad 100644 --- a/src/test/ui/error-codes/E0428.stderr +++ b/src/test/ui/error-codes/E0428.stderr @@ -1,9 +1,9 @@ error[E0428]: the name `Bar` is defined multiple times --> $DIR/E0428.rs:2:1 | -LL | struct Bar; //~ previous definition of the type `Bar` here +LL | struct Bar; | ----------- previous definition of the type `Bar` here -LL | struct Bar; //~ ERROR E0428 +LL | struct Bar; | ^^^^^^^^^^^ `Bar` redefined here | = note: `Bar` must be defined only once in the type namespace of this module diff --git a/src/test/ui/error-codes/E0429.stderr b/src/test/ui/error-codes/E0429.stderr index 13cdb0d8861fa..b5f76a1fcd848 100644 --- a/src/test/ui/error-codes/E0429.stderr +++ b/src/test/ui/error-codes/E0429.stderr @@ -1,7 +1,7 @@ error[E0429]: `self` imports are only allowed within a { } list --> $DIR/E0429.rs:1:5 | -LL | use std::fmt::self; //~ ERROR E0429 +LL | use std::fmt::self; | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0430.stderr b/src/test/ui/error-codes/E0430.stderr index 78e4e43ac2f3d..69a0d6e11b29d 100644 --- a/src/test/ui/error-codes/E0430.stderr +++ b/src/test/ui/error-codes/E0430.stderr @@ -1,7 +1,7 @@ error[E0430]: `self` import can only appear once in an import list --> $DIR/E0430.rs:1:16 | -LL | use std::fmt::{self, self}; //~ ERROR E0430 +LL | use std::fmt::{self, self}; | ^^^^ ---- another `self` import appears here | | | can only appear once in an import list @@ -9,16 +9,14 @@ LL | use std::fmt::{self, self}; //~ ERROR E0430 error[E0252]: the name `fmt` is defined multiple times --> $DIR/E0430.rs:1:22 | -LL | use std::fmt::{self, self}; //~ ERROR E0430 - | ------^^^^ - | | | | - | | | `fmt` reimported here - | | help: remove unnecessary import +LL | use std::fmt::{self, self}; + | ---- ^^^^ `fmt` reimported here + | | | previous import of the module `fmt` here | = note: `fmt` must be defined only once in the type namespace of this module error: aborting due to 2 previous errors -Some errors occurred: E0252, E0430. +Some errors have detailed explanations: E0252, E0430. For more information about an error, try `rustc --explain E0252`. diff --git a/src/test/ui/error-codes/E0431.stderr b/src/test/ui/error-codes/E0431.stderr index 240e6bd4a829f..adfd2d923c78a 100644 --- a/src/test/ui/error-codes/E0431.stderr +++ b/src/test/ui/error-codes/E0431.stderr @@ -1,7 +1,7 @@ error[E0431]: `self` import can only appear in an import list with a non-empty prefix --> $DIR/E0431.rs:1:6 | -LL | use {self}; //~ ERROR E0431 +LL | use {self}; | ^^^^ can only appear in an import list with a non-empty prefix error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0432.stderr b/src/test/ui/error-codes/E0432.stderr index bb6b31242cb54..137a1af6f95b0 100644 --- a/src/test/ui/error-codes/E0432.stderr +++ b/src/test/ui/error-codes/E0432.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `something` --> $DIR/E0432.rs:1:5 | -LL | use something::Foo; //~ ERROR E0432 +LL | use something::Foo; | ^^^^^^^^^ maybe a missing `extern crate something;`? error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0433.stderr b/src/test/ui/error-codes/E0433.stderr index 7fbb7fa0413b6..d852e18838442 100644 --- a/src/test/ui/error-codes/E0433.stderr +++ b/src/test/ui/error-codes/E0433.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: use of undeclared type or module `HashMap` --> $DIR/E0433.rs:2:15 | -LL | let map = HashMap::new(); //~ ERROR E0433 +LL | let map = HashMap::new(); | ^^^^^^^ use of undeclared type or module `HashMap` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0434.stderr b/src/test/ui/error-codes/E0434.stderr index 0e2bc701b7fbf..14508ccbc9a7c 100644 --- a/src/test/ui/error-codes/E0434.stderr +++ b/src/test/ui/error-codes/E0434.stderr @@ -1,7 +1,7 @@ error[E0434]: can't capture dynamic environment in a fn item --> $DIR/E0434.rs:4:9 | -LL | y //~ ERROR E0434 +LL | y | ^ | = help: use the `|| { ... }` closure form instead diff --git a/src/test/ui/error-codes/E0435.stderr b/src/test/ui/error-codes/E0435.stderr index 09c9d19e11402..349aa0d07c5d8 100644 --- a/src/test/ui/error-codes/E0435.stderr +++ b/src/test/ui/error-codes/E0435.stderr @@ -1,7 +1,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/E0435.rs:3:17 | -LL | let _: [u8; foo]; //~ ERROR E0435 +LL | let _: [u8; foo]; | ^^^ non-constant value error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0437.stderr b/src/test/ui/error-codes/E0437.stderr index 9470cbf176aeb..217b164036f87 100644 --- a/src/test/ui/error-codes/E0437.stderr +++ b/src/test/ui/error-codes/E0437.stderr @@ -1,7 +1,7 @@ error[E0437]: type `Bar` is not a member of trait `Foo` --> $DIR/E0437.rs:4:5 | -LL | type Bar = bool; //~ ERROR E0437 +LL | type Bar = bool; | ^^^^^^^^^^^^^^^^ not a member of trait `Foo` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0438.stderr b/src/test/ui/error-codes/E0438.stderr index 6a11577bb0f33..853f0c3c2399d 100644 --- a/src/test/ui/error-codes/E0438.stderr +++ b/src/test/ui/error-codes/E0438.stderr @@ -1,7 +1,7 @@ error[E0438]: const `BAR` is not a member of trait `Bar` --> $DIR/E0438.rs:4:5 | -LL | const BAR: bool = true; //~ ERROR E0438 +LL | const BAR: bool = true; | ^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `Bar` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0439.stderr b/src/test/ui/error-codes/E0439.stderr index e3b8fbfb25362..8021f7d3951a8 100644 --- a/src/test/ui/error-codes/E0439.stderr +++ b/src/test/ui/error-codes/E0439.stderr @@ -1,7 +1,7 @@ error[E0439]: invalid `simd_shuffle`, needs length: `simd_shuffle` --> $DIR/E0439.rs:4:5 | -LL | fn simd_shuffle(a: A, b: A, c: [u32; 8]) -> B; //~ ERROR E0439 +LL | fn simd_shuffle(a: A, b: A, c: [u32; 8]) -> B; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0446.stderr b/src/test/ui/error-codes/E0446.stderr index 9c7399515f439..a0f5f7079b34c 100644 --- a/src/test/ui/error-codes/E0446.stderr +++ b/src/test/ui/error-codes/E0446.stderr @@ -4,7 +4,7 @@ error[E0446]: private type `foo::Bar` in public interface LL | struct Bar(u32); | - `foo::Bar` declared as private LL | -LL | / pub fn bar() -> Bar { //~ ERROR E0446 +LL | / pub fn bar() -> Bar { LL | | Bar(0) LL | | } | |_____^ can't leak private type diff --git a/src/test/ui/error-codes/E0449.stderr b/src/test/ui/error-codes/E0449.stderr index d623c8abbd923..8221a5e0ad677 100644 --- a/src/test/ui/error-codes/E0449.stderr +++ b/src/test/ui/error-codes/E0449.stderr @@ -1,7 +1,7 @@ error[E0449]: unnecessary visibility qualifier --> $DIR/E0449.rs:7:1 | -LL | pub impl Bar {} //~ ERROR E0449 +LL | pub impl Bar {} | ^^^ `pub` not permitted here because it's implied | = note: place qualifiers on individual impl items instead @@ -9,13 +9,13 @@ LL | pub impl Bar {} //~ ERROR E0449 error[E0449]: unnecessary visibility qualifier --> $DIR/E0449.rs:9:1 | -LL | pub impl Foo for Bar { //~ ERROR E0449 +LL | pub impl Foo for Bar { | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/E0449.rs:10:5 | -LL | pub fn foo() {} //~ ERROR E0449 +LL | pub fn foo() {} | ^^^ `pub` not permitted here because it's implied error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/E0451.stderr b/src/test/ui/error-codes/E0451.stderr index 11f0867724627..655f3a98d7f09 100644 --- a/src/test/ui/error-codes/E0451.stderr +++ b/src/test/ui/error-codes/E0451.stderr @@ -1,13 +1,13 @@ error[E0451]: field `b` of struct `bar::Foo` is private --> $DIR/E0451.rs:14:21 | -LL | let bar::Foo{a, b} = foo; //~ ERROR E0451 +LL | let bar::Foo{a, b} = foo; | ^ field `b` is private error[E0451]: field `b` of struct `bar::Foo` is private --> $DIR/E0451.rs:18:29 | -LL | let f = bar::Foo{ a: 0, b: 0 }; //~ ERROR E0451 +LL | let f = bar::Foo{ a: 0, b: 0 }; | ^^^^ field `b` is private error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0452.stderr b/src/test/ui/error-codes/E0452.stderr index 62f268cd432b6..7f074168f8e02 100644 --- a/src/test/ui/error-codes/E0452.stderr +++ b/src/test/ui/error-codes/E0452.stderr @@ -1,8 +1,8 @@ -error[E0452]: malformed lint attribute +error[E0452]: malformed lint attribute input --> $DIR/E0452.rs:1:10 | -LL | #![allow(foo = "")] //~ ERROR E0452 - | ^^^^^^^^ +LL | #![allow(foo = "")] + | ^^^^^^^^ bad attribute argument error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0458.stderr b/src/test/ui/error-codes/E0458.stderr index 8b071e0b315ed..d60fd96c77936 100644 --- a/src/test/ui/error-codes/E0458.stderr +++ b/src/test/ui/error-codes/E0458.stderr @@ -1,18 +1,18 @@ error[E0458]: unknown kind: `wonderful_unicorn` - --> $DIR/E0458.rs:1:1 + --> $DIR/E0458.rs:1:8 | -LL | #[link(kind = "wonderful_unicorn")] extern {} //~ ERROR E0458 - | ^^^^^^^--------------------------^^ +LL | #[link(kind = "wonderful_unicorn")] extern {} + | -------^^^^^^^^^^^^^^^^^^^^^^^^^^-- | | | unknown kind error[E0459]: #[link(...)] specified without `name = "foo"` --> $DIR/E0458.rs:1:1 | -LL | #[link(kind = "wonderful_unicorn")] extern {} //~ ERROR E0458 +LL | #[link(kind = "wonderful_unicorn")] extern {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `name` argument error: aborting due to 2 previous errors -Some errors occurred: E0458, E0459. +Some errors have detailed explanations: E0458, E0459. For more information about an error, try `rustc --explain E0458`. diff --git a/src/test/ui/error-codes/E0459.stderr b/src/test/ui/error-codes/E0459.stderr index d3591cd5f6062..da7069fbb477b 100644 --- a/src/test/ui/error-codes/E0459.stderr +++ b/src/test/ui/error-codes/E0459.stderr @@ -1,7 +1,7 @@ error[E0459]: #[link(...)] specified without `name = "foo"` --> $DIR/E0459.rs:1:1 | -LL | #[link(kind = "dylib")] extern {} //~ ERROR E0459 +LL | #[link(kind = "dylib")] extern {} | ^^^^^^^^^^^^^^^^^^^^^^^ missing `name` argument error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0478.rs b/src/test/ui/error-codes/E0478.rs index 1b5ca09d5a6c4..b1562dc0a8ba0 100644 --- a/src/test/ui/error-codes/E0478.rs +++ b/src/test/ui/error-codes/E0478.rs @@ -1,7 +1,7 @@ trait Wedding<'t>: 't { } struct Prince<'kiss, 'SnowWhite> { - child: Box + 'SnowWhite>, //~ ERROR E0478 + child: Box + 'SnowWhite>, //~ ERROR E0478 } fn main() { diff --git a/src/test/ui/error-codes/E0478.stderr b/src/test/ui/error-codes/E0478.stderr index 5147bf2455996..587125fdc336e 100644 --- a/src/test/ui/error-codes/E0478.stderr +++ b/src/test/ui/error-codes/E0478.stderr @@ -1,8 +1,8 @@ error[E0478]: lifetime bound not satisfied --> $DIR/E0478.rs:4:5 | -LL | child: Box + 'SnowWhite>, //~ ERROR E0478 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | child: Box + 'SnowWhite>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime 'SnowWhite as defined on the struct at 3:22 --> $DIR/E0478.rs:3:22 diff --git a/src/test/ui/error-codes/E0492.stderr b/src/test/ui/error-codes/E0492.stderr index b73db6c975ead..5f337dd7f422d 100644 --- a/src/test/ui/error-codes/E0492.stderr +++ b/src/test/ui/error-codes/E0492.stderr @@ -1,7 +1,7 @@ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead --> $DIR/E0492.rs:4:34 | -LL | static B: &'static AtomicUsize = &A; //~ ERROR E0492 +LL | static B: &'static AtomicUsize = &A; | ^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0496.stderr b/src/test/ui/error-codes/E0496.stderr index 515d71ba05ec5..b0294eef04ef7 100644 --- a/src/test/ui/error-codes/E0496.stderr +++ b/src/test/ui/error-codes/E0496.stderr @@ -3,7 +3,7 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scop | LL | impl<'a> Foo<'a> { | -- first declared here -LL | fn f<'a>(x: &'a i32) { //~ ERROR E0496 +LL | fn f<'a>(x: &'a i32) { | ^^ lifetime 'a already in scope error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0499.nll.stderr b/src/test/ui/error-codes/E0499.nll.stderr deleted file mode 100644 index c1acef10e6e6a..0000000000000 --- a/src/test/ui/error-codes/E0499.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0499]: cannot borrow `i` as mutable more than once at a time - --> $DIR/E0499.rs:4:17 - | -LL | let mut x = &mut i; - | ------ first mutable borrow occurs here -LL | let mut a = &mut i; //~ ERROR E0499 - | ^^^^^^ second mutable borrow occurs here -LL | a.use_mut(); -LL | x.use_mut(); - | - first borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/error-codes/E0499.stderr b/src/test/ui/error-codes/E0499.stderr index 92157e4eba6c4..d56baf7227201 100644 --- a/src/test/ui/error-codes/E0499.stderr +++ b/src/test/ui/error-codes/E0499.stderr @@ -1,13 +1,13 @@ error[E0499]: cannot borrow `i` as mutable more than once at a time - --> $DIR/E0499.rs:4:22 + --> $DIR/E0499.rs:4:17 | LL | let mut x = &mut i; - | - first mutable borrow occurs here -LL | let mut a = &mut i; //~ ERROR E0499 - | ^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here + | ------ first mutable borrow occurs here +LL | let mut a = &mut i; + | ^^^^^^ second mutable borrow occurs here +LL | a.use_mut(); +LL | x.use_mut(); + | - first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0501.rs b/src/test/ui/error-codes/E0501.rs new file mode 100644 index 0000000000000..3e39d9a63c59d --- /dev/null +++ b/src/test/ui/error-codes/E0501.rs @@ -0,0 +1,24 @@ +fn inside_closure(x: &mut i32) { +} + +fn outside_closure_1(x: &mut i32) { +} + +fn outside_closure_2(x: &i32) { +} + +fn foo(a: &mut i32) { + let bar = || { + inside_closure(a) + }; + outside_closure_1(a); + //~^ ERROR cannot borrow `*a` as mutable because previous closure requires unique access + + outside_closure_2(a); + //~^ ERROR cannot borrow `*a` as immutable because previous closure requires unique access + + drop(bar); +} + +fn main() { +} diff --git a/src/test/ui/error-codes/E0501.stderr b/src/test/ui/error-codes/E0501.stderr new file mode 100644 index 0000000000000..53d98d7e13fee --- /dev/null +++ b/src/test/ui/error-codes/E0501.stderr @@ -0,0 +1,31 @@ +error[E0501]: cannot borrow `*a` as mutable because previous closure requires unique access + --> $DIR/E0501.rs:14:23 + | +LL | let bar = || { + | -- closure construction occurs here +LL | inside_closure(a) + | - first borrow occurs due to use of `a` in closure +LL | }; +LL | outside_closure_1(a); + | ^ second borrow occurs here +... +LL | drop(bar); + | --- first borrow later used here + +error[E0501]: cannot borrow `*a` as immutable because previous closure requires unique access + --> $DIR/E0501.rs:17:23 + | +LL | let bar = || { + | -- closure construction occurs here +LL | inside_closure(a) + | - first borrow occurs due to use of `a` in closure +... +LL | outside_closure_2(a); + | ^ second borrow occurs here +... +LL | drop(bar); + | --- first borrow later used here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0501`. diff --git a/src/test/ui/error-codes/E0502.nll.stderr b/src/test/ui/error-codes/E0502.nll.stderr index 64ca8f0e6b9a4..e5671ee49e654 100644 --- a/src/test/ui/error-codes/E0502.nll.stderr +++ b/src/test/ui/error-codes/E0502.nll.stderr @@ -1,10 +1,10 @@ error[E0502]: cannot borrow `*a` as mutable because it is also borrowed as immutable - --> $DIR/E0502.rs:4:5 + --> $DIR/E0502.rs:4:9 | LL | let ref y = a; | ----- immutable borrow occurs here -LL | bar(a); //~ ERROR E0502 - | ^^^^^^ mutable borrow occurs here +LL | bar(a); + | ^ mutable borrow occurs here LL | y.use_ref(); | - immutable borrow later used here diff --git a/src/test/ui/error-codes/E0502.stderr b/src/test/ui/error-codes/E0502.stderr index 9193886b00969..cade6d71852f8 100644 --- a/src/test/ui/error-codes/E0502.stderr +++ b/src/test/ui/error-codes/E0502.stderr @@ -1,13 +1,12 @@ -error[E0502]: cannot borrow `*a` as mutable because `a` is also borrowed as immutable - --> $DIR/E0502.rs:4:9 +error[E0502]: cannot borrow `*a` as mutable because it is also borrowed as immutable + --> $DIR/E0502.rs:4:5 | LL | let ref y = a; | ----- immutable borrow occurs here -LL | bar(a); //~ ERROR E0502 - | ^ mutable borrow occurs here +LL | bar(a); + | ^^^^^^ mutable borrow occurs here LL | y.use_ref(); -LL | } - | - immutable borrow ends here + | - immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0503.nll.stderr b/src/test/ui/error-codes/E0503.nll.stderr deleted file mode 100644 index 7b483a5eaa585..0000000000000 --- a/src/test/ui/error-codes/E0503.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0503]: cannot use `value` because it was mutably borrowed - --> $DIR/E0503.rs:4:16 - | -LL | let _borrow = &mut value; - | ---------- borrow of `value` occurs here -LL | let _sum = value + 1; //~ ERROR E0503 - | ^^^^^ use of borrowed `value` -LL | _borrow.use_mut(); - | ------- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/error-codes/E0503.stderr b/src/test/ui/error-codes/E0503.stderr index 83391146b602d..106dda2bc2260 100644 --- a/src/test/ui/error-codes/E0503.stderr +++ b/src/test/ui/error-codes/E0503.stderr @@ -2,9 +2,11 @@ error[E0503]: cannot use `value` because it was mutably borrowed --> $DIR/E0503.rs:4:16 | LL | let _borrow = &mut value; - | ----- borrow of `value` occurs here -LL | let _sum = value + 1; //~ ERROR E0503 + | ---------- borrow of `value` occurs here +LL | let _sum = value + 1; | ^^^^^ use of borrowed `value` +LL | _borrow.use_mut(); + | ------- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0504.nll.stderr b/src/test/ui/error-codes/E0504.nll.stderr deleted file mode 100644 index 8d7387e86e524..0000000000000 --- a/src/test/ui/error-codes/E0504.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0505]: cannot move out of `fancy_num` because it is borrowed - --> $DIR/E0504.rs:9:13 - | -LL | let fancy_ref = &fancy_num; - | ---------- borrow of `fancy_num` occurs here -LL | -LL | let x = move || { - | ^^^^^^^ move out of `fancy_num` occurs here -LL | println!("child function: {}", fancy_num.num); //~ ERROR E0504 - | --------- move occurs due to use in closure -... -LL | println!("main function: {}", fancy_ref.num); - | ------------- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/error-codes/E0504.rs b/src/test/ui/error-codes/E0504.rs index 06ae0848b7c88..c2658bef61975 100644 --- a/src/test/ui/error-codes/E0504.rs +++ b/src/test/ui/error-codes/E0504.rs @@ -6,8 +6,8 @@ fn main() { let fancy_num = FancyNum { num: 5 }; let fancy_ref = &fancy_num; - let x = move || { - println!("child function: {}", fancy_num.num); //~ ERROR E0504 + let x = move || { //~ ERROR E0505 + println!("child function: {}", fancy_num.num); }; x(); diff --git a/src/test/ui/error-codes/E0504.stderr b/src/test/ui/error-codes/E0504.stderr index 7f4a611c5d53f..1f2a0407a3963 100644 --- a/src/test/ui/error-codes/E0504.stderr +++ b/src/test/ui/error-codes/E0504.stderr @@ -1,12 +1,17 @@ -error[E0504]: cannot move `fancy_num` into closure because it is borrowed - --> $DIR/E0504.rs:10:40 +error[E0505]: cannot move out of `fancy_num` because it is borrowed + --> $DIR/E0504.rs:9:13 | LL | let fancy_ref = &fancy_num; - | --------- borrow of `fancy_num` occurs here + | ---------- borrow of `fancy_num` occurs here +LL | +LL | let x = move || { + | ^^^^^^^ move out of `fancy_num` occurs here +LL | println!("child function: {}", fancy_num.num); + | --------- move occurs due to use in closure ... -LL | println!("child function: {}", fancy_num.num); //~ ERROR E0504 - | ^^^^^^^^^ move into closure occurs here +LL | println!("main function: {}", fancy_ref.num); + | ------------- borrow later used here error: aborting due to previous error -For more information about this error, try `rustc --explain E0504`. +For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/error-codes/E0505.nll.stderr b/src/test/ui/error-codes/E0505.nll.stderr deleted file mode 100644 index 181e5e33d29d7..0000000000000 --- a/src/test/ui/error-codes/E0505.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/E0505.rs:9:13 - | -LL | let _ref_to_val: &Value = &x; - | -- borrow of `x` occurs here -LL | eat(x); //~ ERROR E0505 - | ^ move out of `x` occurs here -LL | _ref_to_val.use_ref(); - | ----------- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/error-codes/E0505.stderr b/src/test/ui/error-codes/E0505.stderr index 268eb88019220..4d9d1ef121c69 100644 --- a/src/test/ui/error-codes/E0505.stderr +++ b/src/test/ui/error-codes/E0505.stderr @@ -2,9 +2,11 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/E0505.rs:9:13 | LL | let _ref_to_val: &Value = &x; - | - borrow of `x` occurs here -LL | eat(x); //~ ERROR E0505 + | -- borrow of `x` occurs here +LL | eat(x); | ^ move out of `x` occurs here +LL | _ref_to_val.use_ref(); + | ----------- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0506.rs b/src/test/ui/error-codes/E0506.rs new file mode 100644 index 0000000000000..062a44a52bb8b --- /dev/null +++ b/src/test/ui/error-codes/E0506.rs @@ -0,0 +1,11 @@ +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy_num = FancyNum { num: 5 }; + let fancy_ref = &fancy_num; + fancy_num = FancyNum { num: 6 }; //~ ERROR [E0506] + + println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num); +} diff --git a/src/test/ui/error-codes/E0506.stderr b/src/test/ui/error-codes/E0506.stderr new file mode 100644 index 0000000000000..17f883f84b8a2 --- /dev/null +++ b/src/test/ui/error-codes/E0506.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `fancy_num` because it is borrowed + --> $DIR/E0506.rs:8:5 + | +LL | let fancy_ref = &fancy_num; + | ---------- borrow of `fancy_num` occurs here +LL | fancy_num = FancyNum { num: 6 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `fancy_num` occurs here +LL | +LL | println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num); + | ------------- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/error-codes/E0507.stderr b/src/test/ui/error-codes/E0507.stderr index c24b8ecf61ac6..170b883191100 100644 --- a/src/test/ui/error-codes/E0507.stderr +++ b/src/test/ui/error-codes/E0507.stderr @@ -1,8 +1,8 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of dereference of `std::cell::Ref<'_, TheDarkKnight>` --> $DIR/E0507.rs:12:5 | -LL | x.borrow().nothing_is_true(); //~ ERROR E0507 - | ^^^^^^^^^^ cannot move out of borrowed content +LL | x.borrow().nothing_is_true(); + | ^^^^^^^^^^ move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/E0508.rs b/src/test/ui/error-codes/E0508-fail.rs similarity index 100% rename from src/test/ui/E0508.rs rename to src/test/ui/error-codes/E0508-fail.rs diff --git a/src/test/ui/error-codes/E0508-fail.stderr b/src/test/ui/error-codes/E0508-fail.stderr new file mode 100644 index 0000000000000..b69d7743b6c2c --- /dev/null +++ b/src/test/ui/error-codes/E0508-fail.stderr @@ -0,0 +1,13 @@ +error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array + --> $DIR/E0508-fail.rs:5:18 + | +LL | let _value = array[0]; + | ^^^^^^^^ + | | + | cannot move out of here + | move occurs because `array[_]` has type `NonCopy`, which does not implement the `Copy` trait + | help: consider borrowing here: `&array[0]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/error-codes/E0508.rs b/src/test/ui/error-codes/E0508.rs new file mode 100644 index 0000000000000..072c3d66183e3 --- /dev/null +++ b/src/test/ui/error-codes/E0508.rs @@ -0,0 +1,6 @@ +struct NonCopy; + +fn main() { + let array = [NonCopy; 1]; + let _value = array[0]; //~ ERROR [E0508] +} diff --git a/src/test/ui/error-codes/E0508.stderr b/src/test/ui/error-codes/E0508.stderr new file mode 100644 index 0000000000000..5e7b56dcd372a --- /dev/null +++ b/src/test/ui/error-codes/E0508.stderr @@ -0,0 +1,13 @@ +error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array + --> $DIR/E0508.rs:5:18 + | +LL | let _value = array[0]; + | ^^^^^^^^ + | | + | cannot move out of here + | move occurs because `array[_]` has type `NonCopy`, which does not implement the `Copy` trait + | help: consider borrowing here: `&array[0]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/error-codes/E0509.nll.stderr b/src/test/ui/error-codes/E0509.nll.stderr deleted file mode 100644 index 0233c7d6d1651..0000000000000 --- a/src/test/ui/error-codes/E0509.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0509]: cannot move out of type `DropStruct`, which implements the `Drop` trait - --> $DIR/E0509.rs:16:23 - | -LL | let fancy_field = drop_struct.fancy; //~ ERROR E0509 - | ^^^^^^^^^^^^^^^^^ - | | - | cannot move out of here - | help: consider borrowing here: `&drop_struct.fancy` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/error-codes/E0509.stderr b/src/test/ui/error-codes/E0509.stderr index b1f256d2d9e33..cbfbc3ccf6a87 100644 --- a/src/test/ui/error-codes/E0509.stderr +++ b/src/test/ui/error-codes/E0509.stderr @@ -1,11 +1,12 @@ error[E0509]: cannot move out of type `DropStruct`, which implements the `Drop` trait --> $DIR/E0509.rs:16:23 | -LL | let fancy_field = drop_struct.fancy; //~ ERROR E0509 +LL | let fancy_field = drop_struct.fancy; | ^^^^^^^^^^^^^^^^^ | | | cannot move out of here - | help: consider using a reference instead: `&drop_struct.fancy` + | move occurs because `drop_struct.fancy` has type `FancyNum`, which does not implement the `Copy` trait + | help: consider borrowing here: `&drop_struct.fancy` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0511.stderr b/src/test/ui/error-codes/E0511.stderr index f1e3c0135bfb2..5f8be0c61d304 100644 --- a/src/test/ui/error-codes/E0511.stderr +++ b/src/test/ui/error-codes/E0511.stderr @@ -1,9 +1,8 @@ error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `i32` --> $DIR/E0511.rs:8:14 | -LL | unsafe { simd_add(0, 1); } //~ ERROR E0511 +LL | unsafe { simd_add(0, 1); } | ^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/error-codes/E0512.stderr b/src/test/ui/error-codes/E0512.stderr index 998f6403f0b29..3fecce542ce9b 100644 --- a/src/test/ui/error-codes/E0512.stderr +++ b/src/test/ui/error-codes/E0512.stderr @@ -1,7 +1,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/E0512.rs:4:23 | -LL | unsafe { takes_u8(::std::mem::transmute(0u16)); } //~ ERROR E0512 +LL | unsafe { takes_u8(::std::mem::transmute(0u16)); } | ^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `u16` (16 bits) diff --git a/src/test/ui/error-codes/E0516.stderr b/src/test/ui/error-codes/E0516.stderr index 034c17933645c..2e6de5053d576 100644 --- a/src/test/ui/error-codes/E0516.stderr +++ b/src/test/ui/error-codes/E0516.stderr @@ -1,7 +1,7 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented --> $DIR/E0516.rs:2:12 | -LL | let x: typeof(92) = 92; //~ ERROR E0516 +LL | let x: typeof(92) = 92; | ^^^^^^^^^^ reserved keyword error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0517.stderr b/src/test/ui/error-codes/E0517.stderr index 366ab1bca63fa..2cfca1724c81b 100644 --- a/src/test/ui/error-codes/E0517.stderr +++ b/src/test/ui/error-codes/E0517.stderr @@ -1,15 +1,15 @@ -error[E0517]: attribute should be applied to struct, enum or union +error[E0517]: attribute should be applied to struct, enum, or union --> $DIR/E0517.rs:1:8 | -LL | #[repr(C)] //~ ERROR: E0517 +LL | #[repr(C)] | ^ LL | type Foo = u8; - | -------------- not a struct, enum or union + | -------------- not a struct, enum, or union error[E0517]: attribute should be applied to struct or union --> $DIR/E0517.rs:4:8 | -LL | #[repr(packed)] //~ ERROR: E0517 +LL | #[repr(packed)] | ^^^^^^ LL | enum Foo2 {Bar, Baz} | -------------------- not a struct or union @@ -17,19 +17,19 @@ LL | enum Foo2 {Bar, Baz} error[E0517]: attribute should be applied to enum --> $DIR/E0517.rs:7:8 | -LL | #[repr(u8)] //~ ERROR: E0517 +LL | #[repr(u8)] | ^^ LL | struct Foo3 {bar: bool, baz: bool} | ---------------------------------- not an enum -error[E0517]: attribute should be applied to struct, enum or union +error[E0517]: attribute should be applied to struct, enum, or union --> $DIR/E0517.rs:10:8 | -LL | #[repr(C)] //~ ERROR: E0517 +LL | #[repr(C)] | ^ LL | / impl Foo3 { LL | | } - | |_- not a struct, enum or union + | |_- not a struct, enum, or union error: aborting due to 4 previous errors diff --git a/src/test/ui/error-codes/E0518.stderr b/src/test/ui/error-codes/E0518.stderr index 6391a69c24e8f..561446f8175db 100644 --- a/src/test/ui/error-codes/E0518.stderr +++ b/src/test/ui/error-codes/E0518.stderr @@ -1,7 +1,7 @@ error[E0518]: attribute should be applied to function or closure --> $DIR/E0518.rs:1:1 | -LL | #[inline(always)] //~ ERROR: E0518 +LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ LL | struct Foo; | ----------- not a function or closure @@ -9,7 +9,7 @@ LL | struct Foo; error[E0518]: attribute should be applied to function or closure --> $DIR/E0518.rs:4:1 | -LL | #[inline(never)] //~ ERROR: E0518 +LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ LL | / impl Foo { LL | | } diff --git a/src/test/ui/error-codes/E0530.stderr b/src/test/ui/error-codes/E0530.stderr index 2ef80253eaf5b..c312144132d3b 100644 --- a/src/test/ui/error-codes/E0530.stderr +++ b/src/test/ui/error-codes/E0530.stderr @@ -4,7 +4,7 @@ error[E0530]: match bindings cannot shadow statics LL | static TEST: i32 = 0; | --------------------- the static `TEST` is defined here ... -LL | TEST => {} //~ ERROR E0530 +LL | TEST => {} | ^^^^ cannot be named the same as a static error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0534.stderr b/src/test/ui/error-codes/E0534.stderr index d2829e1643bbd..23f9cd7ce2db7 100644 --- a/src/test/ui/error-codes/E0534.stderr +++ b/src/test/ui/error-codes/E0534.stderr @@ -1,7 +1,7 @@ error[E0534]: expected one argument --> $DIR/E0534.rs:1:1 | -LL | #[inline()] //~ ERROR E0534 +LL | #[inline()] | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0565-1.stderr b/src/test/ui/error-codes/E0565-1.stderr index c320918a3bfdf..1283a9c5ef653 100644 --- a/src/test/ui/error-codes/E0565-1.stderr +++ b/src/test/ui/error-codes/E0565-1.stderr @@ -1,7 +1,7 @@ error[E0565]: item in `deprecated` must be a key/value pair --> $DIR/E0565-1.rs:2:14 | -LL | #[deprecated("since")] //~ ERROR E0565 +LL | #[deprecated("since")] | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0565-2.stderr b/src/test/ui/error-codes/E0565-2.stderr index 8e2ce09059a32..bb30bd7befb38 100644 --- a/src/test/ui/error-codes/E0565-2.stderr +++ b/src/test/ui/error-codes/E0565-2.stderr @@ -1,7 +1,7 @@ error[E0565]: literal in `deprecated` value must be a string --> $DIR/E0565-2.rs:2:22 | -LL | #[deprecated(since = b"1.29", note = "hi")] //~ ERROR E0565 +LL | #[deprecated(since = b"1.29", note = "hi")] | ^^^^^^^ help: consider removing the prefix: `"1.29"` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0565.stderr b/src/test/ui/error-codes/E0565.stderr index 2c172f8114962..6ed90c0ae4ffe 100644 --- a/src/test/ui/error-codes/E0565.stderr +++ b/src/test/ui/error-codes/E0565.stderr @@ -1,7 +1,7 @@ error[E0565]: meta item in `repr` must be an identifier --> $DIR/E0565.rs:2:8 | -LL | #[repr("C")] //~ ERROR E0565 +LL | #[repr("C")] | ^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0572.stderr b/src/test/ui/error-codes/E0572.stderr index 295a518c336dc..36619f8dee4cc 100644 --- a/src/test/ui/error-codes/E0572.stderr +++ b/src/test/ui/error-codes/E0572.stderr @@ -1,7 +1,7 @@ error[E0572]: return statement outside of function body --> $DIR/E0572.rs:1:18 | -LL | const FOO: u32 = return 0; //~ ERROR E0572 +LL | const FOO: u32 = return 0; | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/E0583.rs b/src/test/ui/error-codes/E0583.rs similarity index 100% rename from src/test/ui/E0583.rs rename to src/test/ui/error-codes/E0583.rs diff --git a/src/test/ui/E0583.stderr b/src/test/ui/error-codes/E0583.stderr similarity index 87% rename from src/test/ui/E0583.stderr rename to src/test/ui/error-codes/E0583.stderr index 33b584ccefeba..ef7a48bc8a48f 100644 --- a/src/test/ui/E0583.stderr +++ b/src/test/ui/error-codes/E0583.stderr @@ -1,7 +1,7 @@ error[E0583]: file not found for module `module_that_doesnt_exist` --> $DIR/E0583.rs:1:5 | -LL | mod module_that_doesnt_exist; //~ ERROR E0583 +LL | mod module_that_doesnt_exist; | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: name the file either module_that_doesnt_exist.rs or module_that_doesnt_exist/mod.rs inside the directory "$DIR" diff --git a/src/test/ui/error-codes/E0586.stderr b/src/test/ui/error-codes/E0586.stderr index 394b4be3340f5..d1e7e3f47442f 100644 --- a/src/test/ui/error-codes/E0586.stderr +++ b/src/test/ui/error-codes/E0586.stderr @@ -1,7 +1,7 @@ error[E0586]: inclusive range with no end --> $DIR/E0586.rs:3:22 | -LL | let x = &tmp[1..=]; //~ ERROR E0586 +LL | let x = &tmp[1..=]; | ^ | = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) diff --git a/src/test/ui/error-codes/E0594.rs b/src/test/ui/error-codes/E0594.rs new file mode 100644 index 0000000000000..8b0cae7e17b30 --- /dev/null +++ b/src/test/ui/error-codes/E0594.rs @@ -0,0 +1,5 @@ +static NUM: i32 = 18; + +fn main() { + NUM = 20; //~ ERROR cannot assign to immutable static item `NUM` +} diff --git a/src/test/ui/error-codes/E0594.stderr b/src/test/ui/error-codes/E0594.stderr new file mode 100644 index 0000000000000..c00ec4250a70b --- /dev/null +++ b/src/test/ui/error-codes/E0594.stderr @@ -0,0 +1,8 @@ +error[E0594]: cannot assign to immutable static item `NUM` + --> $DIR/E0594.rs:4:5 + | +LL | NUM = 20; + | ^^^^^^^^ cannot assign + +error: aborting due to previous error + diff --git a/src/test/ui/error-codes/E0596.rs b/src/test/ui/error-codes/E0596.rs new file mode 100644 index 0000000000000..9e2f5ee763639 --- /dev/null +++ b/src/test/ui/error-codes/E0596.rs @@ -0,0 +1,4 @@ +fn main() { + let x = 1; + let y = &mut x; //~ ERROR [E0596] +} diff --git a/src/test/ui/error-codes/E0596.stderr b/src/test/ui/error-codes/E0596.stderr new file mode 100644 index 0000000000000..79bc258f1fae7 --- /dev/null +++ b/src/test/ui/error-codes/E0596.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/E0596.rs:3:13 + | +LL | let x = 1; + | - help: consider changing this to be mutable: `mut x` +LL | let y = &mut x; + | ^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/error-codes/E0597.nll.stderr b/src/test/ui/error-codes/E0597.nll.stderr deleted file mode 100644 index 88a8a46930d2c..0000000000000 --- a/src/test/ui/error-codes/E0597.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0597]: `y` does not live long enough - --> $DIR/E0597.rs:8:16 - | -LL | x.x = Some(&y); - | ^^ borrowed value does not live long enough -LL | //~^ `y` does not live long enough [E0597] -LL | } - | - - | | - | `y` dropped here while still borrowed - | borrow might be used here, when `x` is dropped and runs the `Drop` code for type `Foo` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/error-codes/E0597.stderr b/src/test/ui/error-codes/E0597.stderr index a5b0cc49d0c83..b4a1180ad546c 100644 --- a/src/test/ui/error-codes/E0597.stderr +++ b/src/test/ui/error-codes/E0597.stderr @@ -1,13 +1,16 @@ error[E0597]: `y` does not live long enough - --> $DIR/E0597.rs:8:17 + --> $DIR/E0597.rs:8:16 | LL | x.x = Some(&y); - | ^ borrowed value does not live long enough -LL | //~^ `y` does not live long enough [E0597] + | ^^ borrowed value does not live long enough +LL | LL | } - | - `y` dropped here while still borrowed + | - + | | + | `y` dropped here while still borrowed + | borrow might be used here, when `x` is dropped and runs the `Drop` code for type `Foo` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0599.stderr b/src/test/ui/error-codes/E0599.stderr index 85110889e9a7b..89bfccf2fbc56 100644 --- a/src/test/ui/error-codes/E0599.stderr +++ b/src/test/ui/error-codes/E0599.stderr @@ -4,8 +4,8 @@ error[E0599]: no associated item named `NotEvenReal` found for type `Foo` in the LL | struct Foo; | ----------- associated item `NotEvenReal` not found for this ... -LL | || if let Foo::NotEvenReal() = Foo {}; //~ ERROR E0599 - | -----^^^^^^^^^^^-- associated item not found in `Foo` +LL | || if let Foo::NotEvenReal() = Foo {}; + | ^^^^^^^^^^^ associated item not found in `Foo` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0600.stderr b/src/test/ui/error-codes/E0600.stderr index 6c6d922290fc6..95ac4510ca885 100644 --- a/src/test/ui/error-codes/E0600.stderr +++ b/src/test/ui/error-codes/E0600.stderr @@ -1,7 +1,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str` --> $DIR/E0600.rs:2:5 | -LL | !"a"; //~ ERROR E0600 +LL | !"a"; | ^^^^ cannot apply unary operator `!` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0603.stderr b/src/test/ui/error-codes/E0603.stderr index ee8fd2809bc76..444005e086f1b 100644 --- a/src/test/ui/error-codes/E0603.stderr +++ b/src/test/ui/error-codes/E0603.stderr @@ -1,7 +1,7 @@ error[E0603]: constant `PRIVATE` is private --> $DIR/E0603.rs:6:17 | -LL | SomeModule::PRIVATE; //~ ERROR E0603 +LL | SomeModule::PRIVATE; | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0604.stderr b/src/test/ui/error-codes/E0604.stderr index 2bd92db86e363..5861bdcb7a953 100644 --- a/src/test/ui/error-codes/E0604.stderr +++ b/src/test/ui/error-codes/E0604.stderr @@ -1,7 +1,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/E0604.rs:2:5 | -LL | 1u32 as char; //~ ERROR E0604 +LL | 1u32 as char; | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0605.rs b/src/test/ui/error-codes/E0605.rs index 0e86e367e8328..cfbf1aa2bd765 100644 --- a/src/test/ui/error-codes/E0605.rs +++ b/src/test/ui/error-codes/E0605.rs @@ -2,6 +2,6 @@ fn main() { let x = 0u8; x as Vec; //~ ERROR E0605 - let v = 0 as *const u8; + let v = std::ptr::null::(); v as &u8; //~ ERROR E0605 } diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr index 4dc074b222ac8..95e899db8b7e9 100644 --- a/src/test/ui/error-codes/E0605.stderr +++ b/src/test/ui/error-codes/E0605.stderr @@ -1,7 +1,7 @@ error[E0605]: non-primitive cast: `u8` as `std::vec::Vec` --> $DIR/E0605.rs:3:5 | -LL | x as Vec; //~ ERROR E0605 +LL | x as Vec; | ^^^^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait @@ -9,7 +9,7 @@ LL | x as Vec; //~ ERROR E0605 error[E0605]: non-primitive cast: `*const u8` as `&u8` --> $DIR/E0605.rs:6:5 | -LL | v as &u8; //~ ERROR E0605 +LL | v as &u8; | ^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait diff --git a/src/test/ui/error-codes/E0606.stderr b/src/test/ui/error-codes/E0606.stderr index 89ec4896a2b43..fce24886eb0df 100644 --- a/src/test/ui/error-codes/E0606.stderr +++ b/src/test/ui/error-codes/E0606.stderr @@ -1,7 +1,7 @@ error[E0606]: casting `&u8` as `u8` is invalid --> $DIR/E0606.rs:2:5 | -LL | &0u8 as u8; //~ ERROR E0606 +LL | &0u8 as u8; | ----^^^^^^ | | | cannot cast `&u8` as `u8` diff --git a/src/test/ui/error-codes/E0607.rs b/src/test/ui/error-codes/E0607.rs index ad9f8709b07f2..65001c471cb4b 100644 --- a/src/test/ui/error-codes/E0607.rs +++ b/src/test/ui/error-codes/E0607.rs @@ -1,4 +1,4 @@ fn main() { - let v = 0 as *const u8; + let v = core::ptr::null::(); v as *const [u8]; //~ ERROR E0607 } diff --git a/src/test/ui/error-codes/E0607.stderr b/src/test/ui/error-codes/E0607.stderr index 1fbe4b9c5bccb..a0fe02c1c4d95 100644 --- a/src/test/ui/error-codes/E0607.stderr +++ b/src/test/ui/error-codes/E0607.stderr @@ -1,7 +1,7 @@ error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]` --> $DIR/E0607.rs:3:5 | -LL | v as *const [u8]; //~ ERROR E0607 +LL | v as *const [u8]; | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0608.stderr b/src/test/ui/error-codes/E0608.stderr index b228b2eddfd9e..3aec509934bc1 100644 --- a/src/test/ui/error-codes/E0608.stderr +++ b/src/test/ui/error-codes/E0608.stderr @@ -1,7 +1,7 @@ error[E0608]: cannot index into a value of type `u8` --> $DIR/E0608.rs:2:5 | -LL | 0u8[2]; //~ ERROR E0608 +LL | 0u8[2]; | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0609.stderr b/src/test/ui/error-codes/E0609.stderr index b5cf09b2201d0..797e95d02dda3 100644 --- a/src/test/ui/error-codes/E0609.stderr +++ b/src/test/ui/error-codes/E0609.stderr @@ -1,7 +1,7 @@ error[E0609]: no field `foo` on type `Foo` --> $DIR/E0609.rs:8:15 | -LL | let _ = x.foo; //~ ERROR E0609 +LL | let _ = x.foo; | ^^^ unknown field | = note: available fields are: `x` @@ -9,7 +9,7 @@ LL | let _ = x.foo; //~ ERROR E0609 error[E0609]: no field `1` on type `Bar` --> $DIR/E0609.rs:11:7 | -LL | y.1; //~ ERROR E0609 +LL | y.1; | ^ unknown field error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0610.stderr b/src/test/ui/error-codes/E0610.stderr index c46b1f2b2d562..a2966eea44c01 100644 --- a/src/test/ui/error-codes/E0610.stderr +++ b/src/test/ui/error-codes/E0610.stderr @@ -1,7 +1,7 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> $DIR/E0610.rs:3:15 | -LL | let _ = x.foo; //~ ERROR E0610 +LL | let _ = x.foo; | ^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0614.stderr b/src/test/ui/error-codes/E0614.stderr index 5b1a4a93c4c0d..598117c2b6058 100644 --- a/src/test/ui/error-codes/E0614.stderr +++ b/src/test/ui/error-codes/E0614.stderr @@ -1,7 +1,7 @@ error[E0614]: type `u32` cannot be dereferenced --> $DIR/E0614.rs:3:5 | -LL | *y; //~ ERROR E0614 +LL | *y; | ^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0615.stderr b/src/test/ui/error-codes/E0615.stderr index d86ee5b9b4b96..772058719ae04 100644 --- a/src/test/ui/error-codes/E0615.stderr +++ b/src/test/ui/error-codes/E0615.stderr @@ -1,7 +1,7 @@ error[E0615]: attempted to take value of method `method` on type `Foo` --> $DIR/E0615.rs:11:7 | -LL | f.method; //~ ERROR E0615 +LL | f.method; | ^^^^^^ help: use parentheses to call the method: `method()` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0616.stderr b/src/test/ui/error-codes/E0616.stderr index f600bfa8cd31f..556e5db10a944 100644 --- a/src/test/ui/error-codes/E0616.stderr +++ b/src/test/ui/error-codes/E0616.stderr @@ -1,7 +1,7 @@ error[E0616]: field `x` of struct `a::Foo` is private --> $DIR/E0616.rs:13:5 | -LL | f.x; //~ ERROR E0616 +LL | f.x; | ^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0617.rs b/src/test/ui/error-codes/E0617.rs index 51f13c7dbd540..439c3db576864 100644 --- a/src/test/ui/error-codes/E0617.rs +++ b/src/test/ui/error-codes/E0617.rs @@ -22,7 +22,7 @@ fn main() { //~^ ERROR can't pass `u16` to variadic function //~| HELP cast the value to `c_uint` printf(::std::ptr::null(), printf); - //~^ ERROR can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...) {printf}` to variadic function - //~| HELP cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...)` + //~^ ERROR can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...) {printf}` to variadic function + //~| HELP cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...)` } } diff --git a/src/test/ui/error-codes/E0617.stderr b/src/test/ui/error-codes/E0617.stderr index 8387d5c7e93a5..d866320bbcdf7 100644 --- a/src/test/ui/error-codes/E0617.stderr +++ b/src/test/ui/error-codes/E0617.stderr @@ -28,15 +28,15 @@ error[E0617]: can't pass `u16` to variadic function LL | printf(::std::ptr::null(), 0u16); | ^^^^ help: cast the value to `c_uint`: `0u16 as c_uint` -error[E0617]: can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...) {printf}` to variadic function +error[E0617]: can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...) {printf}` to variadic function --> $DIR/E0617.rs:24:36 | LL | printf(::std::ptr::null(), printf); | ^^^^^^ -help: cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...)` +help: cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...)` | -LL | printf(::std::ptr::null(), printf as for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | printf(::std::ptr::null(), printf as for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/error-codes/E0620.stderr b/src/test/ui/error-codes/E0620.stderr index f7319a878c27a..65152b2b74dd4 100644 --- a/src/test/ui/error-codes/E0620.stderr +++ b/src/test/ui/error-codes/E0620.stderr @@ -1,13 +1,13 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]` --> $DIR/E0620.rs:2:16 | -LL | let _foo = &[1_usize, 2] as [usize]; //~ ERROR E0620 +LL | let _foo = &[1_usize, 2] as [usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider using an implicit coercion to `&[usize]` instead --> $DIR/E0620.rs:2:16 | -LL | let _foo = &[1_usize, 2] as [usize]; //~ ERROR E0620 +LL | let _foo = &[1_usize, 2] as [usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr new file mode 100644 index 0000000000000..5140d1a9a7add --- /dev/null +++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/E0621-does-not-trigger-for-closures.rs:15:45 + | +LL | invoke(&x, |a, b| if a > b { a } else { b }); + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 i32 + | has type `&'1 i32` + +error: aborting due to previous error + diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr index f763c82eff80a..f50c64780118b 100644 --- a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr +++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr @@ -1,30 +1,29 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/E0621-does-not-trigger-for-closures.rs:15:5 | -LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495 +LL | invoke(&x, |a, b| if a > b { a } else { b }); | ^^^^^^ | note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 15:16... --> $DIR/E0621-does-not-trigger-for-closures.rs:15:16 | -LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495 +LL | invoke(&x, |a, b| if a > b { a } else { b }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...so that reference does not outlive borrowed content --> $DIR/E0621-does-not-trigger-for-closures.rs:15:45 | -LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495 +LL | invoke(&x, |a, b| if a > b { a } else { b }); | ^ note: but, the lifetime must be valid for the call at 15:5... --> $DIR/E0621-does-not-trigger-for-closures.rs:15:5 | -LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495 +LL | invoke(&x, |a, b| if a > b { a } else { b }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...so type `&i32` of expression is valid during the expression --> $DIR/E0621-does-not-trigger-for-closures.rs:15:5 | -LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495 +LL | invoke(&x, |a, b| if a > b { a } else { b }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/error-codes/E0624.stderr b/src/test/ui/error-codes/E0624.stderr index 31a2f607e582f..01ac24cfbbe12 100644 --- a/src/test/ui/error-codes/E0624.stderr +++ b/src/test/ui/error-codes/E0624.stderr @@ -1,7 +1,7 @@ error[E0624]: method `method` is private --> $DIR/E0624.rs:11:9 | -LL | foo.method(); //~ ERROR method `method` is private [E0624] +LL | foo.method(); | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0637.stderr b/src/test/ui/error-codes/E0637.stderr index f744520ef6ee5..9c3ca87ed7e64 100644 --- a/src/test/ui/error-codes/E0637.stderr +++ b/src/test/ui/error-codes/E0637.stderr @@ -1,21 +1,20 @@ error[E0637]: `'_` cannot be used here --> $DIR/E0637.rs:1:16 | -LL | struct Foo<'a: '_>(&'a u8); //~ ERROR cannot be used here +LL | struct Foo<'a: '_>(&'a u8); | ^^ `'_` is a reserved lifetime name error[E0637]: `'_` cannot be used here --> $DIR/E0637.rs:2:12 | -LL | fn foo<'a: '_>(_: &'a u8) {} //~ ERROR cannot be used here +LL | fn foo<'a: '_>(_: &'a u8) {} | ^^ `'_` is a reserved lifetime name error[E0637]: `'_` cannot be used here --> $DIR/E0637.rs:5:10 | -LL | impl<'a: '_> Bar<'a> { //~ ERROR cannot be used here +LL | impl<'a: '_> Bar<'a> { | ^^ `'_` is a reserved lifetime name error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/E0642.rs b/src/test/ui/error-codes/E0642.rs similarity index 100% rename from src/test/ui/E0642.rs rename to src/test/ui/error-codes/E0642.rs diff --git a/src/test/ui/error-codes/E0642.stderr b/src/test/ui/error-codes/E0642.stderr new file mode 100644 index 0000000000000..da255143494d6 --- /dev/null +++ b/src/test/ui/error-codes/E0642.stderr @@ -0,0 +1,33 @@ +error[E0642]: patterns aren't allowed in methods without bodies + --> $DIR/E0642.rs:5:12 + | +LL | fn foo((x, y): (i32, i32)); + | ^^^^^^ +help: give this argument a name or use an underscore to ignore it + | +LL | fn foo(_: (i32, i32)); + | ^ + +error[E0642]: patterns aren't allowed in methods without bodies + --> $DIR/E0642.rs:7:12 + | +LL | fn bar((x, y): (i32, i32)) {} + | ^^^^^^ +help: give this argument a name or use an underscore to ignore it + | +LL | fn bar(_: (i32, i32)) {} + | ^ + +error[E0642]: patterns aren't allowed in methods without bodies + --> $DIR/E0642.rs:9:15 + | +LL | fn method(S { .. }: S) {} + | ^^^^^^^^ +help: give this argument a name or use an underscore to ignore it + | +LL | fn method(_: S) {} + | ^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0642`. diff --git a/src/test/ui/error-codes/E0646.stderr b/src/test/ui/error-codes/E0646.stderr index 502200c1d008e..069401b3f1829 100644 --- a/src/test/ui/error-codes/E0646.stderr +++ b/src/test/ui/error-codes/E0646.stderr @@ -1,8 +1,8 @@ error[E0646]: `main` function is not allowed to have a `where` clause - --> $DIR/E0646.rs:1:17 + --> $DIR/E0646.rs:1:11 | -LL | fn main() where (): Copy {} //~ ERROR [E0646] - | ^^^^^^^^ `main` cannot have a `where` clause +LL | fn main() where (): Copy {} + | ^^^^^^^^^^^^^^ `main` cannot have a `where` clause error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0647.stderr b/src/test/ui/error-codes/E0647.stderr index da9ba5bf34bcf..08cedfaef04ce 100644 --- a/src/test/ui/error-codes/E0647.stderr +++ b/src/test/ui/error-codes/E0647.stderr @@ -1,8 +1,8 @@ error[E0647]: start function is not allowed to have a `where` clause - --> $DIR/E0647.rs:7:56 + --> $DIR/E0647.rs:7:50 | -LL | fn start(_: isize, _: *const *const u8) -> isize where (): Copy { //~ ERROR [E0647] - | ^^^^^^^^ start function cannot have a `where` clause +LL | fn start(_: isize, _: *const *const u8) -> isize where (): Copy { + | ^^^^^^^^^^^^^^ start function cannot have a `where` clause error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0648.stderr b/src/test/ui/error-codes/E0648.stderr index 090157fb0d778..1a65825c7b6c6 100644 --- a/src/test/ui/error-codes/E0648.stderr +++ b/src/test/ui/error-codes/E0648.stderr @@ -1,7 +1,7 @@ error[E0648]: `export_name` may not contain null characters --> $DIR/E0648.rs:1:1 | -LL | #[export_name="/0foo"] //~ ERROR E0648 +LL | #[export_name="\0foo"] | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0657.stderr b/src/test/ui/error-codes/E0657.stderr index df76b45a5891f..b24b413600c6c 100644 --- a/src/test/ui/error-codes/E0657.stderr +++ b/src/test/ui/error-codes/E0657.stderr @@ -12,4 +12,3 @@ LL | -> Box Id>> error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0657`. diff --git a/src/test/ui/error-codes/E0658.stderr b/src/test/ui/error-codes/E0658.stderr index 58802b23db382..ff3f74addd25b 100644 --- a/src/test/ui/error-codes/E0658.stderr +++ b/src/test/ui/error-codes/E0658.stderr @@ -1,11 +1,12 @@ -error[E0658]: repr with 128-bit type is unstable (see issue #35118) +error[E0658]: repr with 128-bit type is unstable --> $DIR/E0658.rs:2:1 | -LL | / enum Foo { //~ ERROR E0658 +LL | / enum Foo { LL | | Bar(u64), LL | | } | |_^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35118 = help: add #![feature(repr128)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0659.stderr b/src/test/ui/error-codes/E0659.stderr index b5aa1b21b0968..2f01f54c2d1ce 100644 --- a/src/test/ui/error-codes/E0659.stderr +++ b/src/test/ui/error-codes/E0659.stderr @@ -1,7 +1,7 @@ error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module) --> $DIR/E0659.rs:15:15 | -LL | collider::foo(); //~ ERROR E0659 +LL | collider::foo(); | ^^^ ambiguous name | note: `foo` could refer to the function imported here diff --git a/src/test/ui/E0660.rs b/src/test/ui/error-codes/E0660.rs similarity index 100% rename from src/test/ui/E0660.rs rename to src/test/ui/error-codes/E0660.rs diff --git a/src/test/ui/E0660.stderr b/src/test/ui/error-codes/E0660.stderr similarity index 82% rename from src/test/ui/E0660.stderr rename to src/test/ui/error-codes/E0660.stderr index d355531ef5d91..ce34a9b01d755 100644 --- a/src/test/ui/E0660.stderr +++ b/src/test/ui/error-codes/E0660.stderr @@ -12,4 +12,3 @@ LL | asm!("nop" "nop" : "=r"(a)); error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0660`. diff --git a/src/test/ui/E0661.rs b/src/test/ui/error-codes/E0661.rs similarity index 100% rename from src/test/ui/E0661.rs rename to src/test/ui/error-codes/E0661.rs diff --git a/src/test/ui/error-codes/E0661.stderr b/src/test/ui/error-codes/E0661.stderr new file mode 100644 index 0000000000000..30a23fd58c57c --- /dev/null +++ b/src/test/ui/error-codes/E0661.stderr @@ -0,0 +1,8 @@ +error[E0661]: output operand constraint lacks '=' or '+' + --> $DIR/E0661.rs:5:18 + | +LL | asm!("nop" : "r"(a)); + | ^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/E0662.rs b/src/test/ui/error-codes/E0662.rs similarity index 100% rename from src/test/ui/E0662.rs rename to src/test/ui/error-codes/E0662.rs diff --git a/src/test/ui/error-codes/E0662.stderr b/src/test/ui/error-codes/E0662.stderr new file mode 100644 index 0000000000000..0d3701aa955ec --- /dev/null +++ b/src/test/ui/error-codes/E0662.stderr @@ -0,0 +1,8 @@ +error[E0662]: input operand constraint contains '=' + --> $DIR/E0662.rs:6:12 + | +LL | : "=test"("a") + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/E0663.rs b/src/test/ui/error-codes/E0663.rs similarity index 100% rename from src/test/ui/E0663.rs rename to src/test/ui/error-codes/E0663.rs diff --git a/src/test/ui/error-codes/E0663.stderr b/src/test/ui/error-codes/E0663.stderr new file mode 100644 index 0000000000000..46a079af15252 --- /dev/null +++ b/src/test/ui/error-codes/E0663.stderr @@ -0,0 +1,8 @@ +error[E0663]: input operand constraint contains '+' + --> $DIR/E0663.rs:6:12 + | +LL | : "+test"("a") + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/E0664.rs b/src/test/ui/error-codes/E0664.rs similarity index 100% rename from src/test/ui/E0664.rs rename to src/test/ui/error-codes/E0664.rs diff --git a/src/test/ui/error-codes/E0664.stderr b/src/test/ui/error-codes/E0664.stderr new file mode 100644 index 0000000000000..3a99fce6eed0f --- /dev/null +++ b/src/test/ui/error-codes/E0664.stderr @@ -0,0 +1,8 @@ +error[E0664]: clobber should not be surrounded by braces + --> $DIR/E0664.rs:7:12 + | +LL | : "{eax}" + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/E0665.rs b/src/test/ui/error-codes/E0665.rs similarity index 100% rename from src/test/ui/E0665.rs rename to src/test/ui/error-codes/E0665.rs diff --git a/src/test/ui/error-codes/E0665.stderr b/src/test/ui/error-codes/E0665.stderr new file mode 100644 index 0000000000000..84fe3c013946a --- /dev/null +++ b/src/test/ui/error-codes/E0665.stderr @@ -0,0 +1,8 @@ +error[E0665]: `Default` cannot be derived for enums, only structs + --> $DIR/E0665.rs:1:10 + | +LL | #[derive(Default)] + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/E0705.rs b/src/test/ui/error-codes/E0705.rs similarity index 100% rename from src/test/ui/E0705.rs rename to src/test/ui/error-codes/E0705.rs diff --git a/src/test/ui/E0705.stderr b/src/test/ui/error-codes/E0705.stderr similarity index 100% rename from src/test/ui/E0705.stderr rename to src/test/ui/error-codes/E0705.stderr diff --git a/src/test/ui/error-codes/E0718.stderr b/src/test/ui/error-codes/E0718.stderr index 4f9734d1acff6..412c856ce065a 100644 --- a/src/test/ui/error-codes/E0718.stderr +++ b/src/test/ui/error-codes/E0718.stderr @@ -1,7 +1,7 @@ error[E0718]: `arc` language item must be applied to a struct --> $DIR/E0718.rs:4:1 | -LL | #[lang = "arc"] //~ ERROR language item must be applied to a struct +LL | #[lang = "arc"] | ^^^^^^^^^^^^^^^ attribute should be applied to a struct, not a static item error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0719.rs b/src/test/ui/error-codes/E0719.rs index 6b572f49cee8b..3311e190937cc 100644 --- a/src/test/ui/error-codes/E0719.rs +++ b/src/test/ui/error-codes/E0719.rs @@ -3,12 +3,12 @@ trait Foo: Iterator {} type Unit = (); -fn test() -> Box> { +fn test() -> Box> { //~^ ERROR is already specified Box::new(None.into_iter()) } fn main() { - let _: &Iterator; + let _: &dyn Iterator; test(); } diff --git a/src/test/ui/error-codes/E0719.stderr b/src/test/ui/error-codes/E0719.stderr index 209bfbae07fab..c5b9a71c65994 100644 --- a/src/test/ui/error-codes/E0719.stderr +++ b/src/test/ui/error-codes/E0719.stderr @@ -7,13 +7,12 @@ LL | trait Foo: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified - --> $DIR/E0719.rs:6:38 + --> $DIR/E0719.rs:6:42 | -LL | fn test() -> Box> { - | --------- ^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first +LL | fn test() -> Box> { + | --------- ^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0719`. diff --git a/src/test/ui/error-codes/E0730.rs b/src/test/ui/error-codes/E0730.rs new file mode 100644 index 0000000000000..e5048d6e6e320 --- /dev/null +++ b/src/test/ui/error-codes/E0730.rs @@ -0,0 +1,11 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn is_123(x: [u32; N]) -> bool { + match x { + [1, 2, 3] => true, //~ ERROR cannot pattern-match on an array without a fixed length + _ => false + } +} + +fn main() {} diff --git a/src/test/ui/error-codes/E0730.stderr b/src/test/ui/error-codes/E0730.stderr new file mode 100644 index 0000000000000..f9281262bb71b --- /dev/null +++ b/src/test/ui/error-codes/E0730.stderr @@ -0,0 +1,15 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/E0730.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0730]: cannot pattern-match on an array without a fixed length + --> $DIR/E0730.rs:6:9 + | +LL | [1, 2, 3] => true, + | ^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0730`. diff --git a/src/test/ui/e0119/auxiliary/complex_impl_support.rs b/src/test/ui/error-codes/e0119/auxiliary/complex_impl_support.rs similarity index 100% rename from src/test/ui/e0119/auxiliary/complex_impl_support.rs rename to src/test/ui/error-codes/e0119/auxiliary/complex_impl_support.rs diff --git a/src/test/ui/e0119/auxiliary/issue_23563_a.rs b/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs similarity index 100% rename from src/test/ui/e0119/auxiliary/issue_23563_a.rs rename to src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs diff --git a/src/test/ui/e0119/complex-impl.rs b/src/test/ui/error-codes/e0119/complex-impl.rs similarity index 100% rename from src/test/ui/e0119/complex-impl.rs rename to src/test/ui/error-codes/e0119/complex-impl.rs diff --git a/src/test/ui/e0119/complex-impl.stderr b/src/test/ui/error-codes/e0119/complex-impl.stderr similarity index 88% rename from src/test/ui/e0119/complex-impl.stderr rename to src/test/ui/error-codes/e0119/complex-impl.stderr index fb0c94dcc3df9..7ed89a5b1aeb1 100644 --- a/src/test/ui/e0119/complex-impl.stderr +++ b/src/test/ui/error-codes/e0119/complex-impl.stderr @@ -1,7 +1,7 @@ error[E0119]: conflicting implementations of trait `complex_impl_support::External` for type `(Q, complex_impl_support::M<'_, '_, '_, std::boxed::Box<_>, _, _>)`: --> $DIR/complex-impl.rs:9:1 | -LL | impl External for (Q, R) {} //~ ERROR must be used +LL | impl External for (Q, R) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `complex_impl_support`: @@ -11,12 +11,12 @@ LL | impl External for (Q, R) {} //~ ERROR must be used error[E0210]: type parameter `R` must be used as the type parameter for some local type (e.g., `MyStruct`) --> $DIR/complex-impl.rs:9:1 | -LL | impl External for (Q, R) {} //~ ERROR must be used +LL | impl External for (Q, R) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `R` must be used as the type parameter for some local type | = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to 2 previous errors -Some errors occurred: E0119, E0210. +Some errors have detailed explanations: E0119, E0210. For more information about an error, try `rustc --explain E0119`. diff --git a/src/test/ui/e0119/conflict-with-std.rs b/src/test/ui/error-codes/e0119/conflict-with-std.rs similarity index 99% rename from src/test/ui/e0119/conflict-with-std.rs rename to src/test/ui/error-codes/e0119/conflict-with-std.rs index 6dc81f33dfcc4..c9db2bab183b4 100644 --- a/src/test/ui/e0119/conflict-with-std.rs +++ b/src/test/ui/error-codes/e0119/conflict-with-std.rs @@ -1,4 +1,3 @@ - use std::marker::PhantomData; use std::convert::{TryFrom, AsRef}; diff --git a/src/test/ui/error-codes/e0119/conflict-with-std.stderr b/src/test/ui/error-codes/e0119/conflict-with-std.stderr new file mode 100644 index 0000000000000..3e0c71e907481 --- /dev/null +++ b/src/test/ui/error-codes/e0119/conflict-with-std.stderr @@ -0,0 +1,32 @@ +error[E0119]: conflicting implementations of trait `std::convert::AsRef` for type `std::boxed::Box`: + --> $DIR/conflict-with-std.rs:5:1 + | +LL | impl AsRef for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `alloc`: + - impl std::convert::AsRef for std::boxed::Box + where T: ?Sized; + +error[E0119]: conflicting implementations of trait `std::convert::From` for type `S`: + --> $DIR/conflict-with-std.rs:12:1 + | +LL | impl From for S { + | ^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl std::convert::From for T; + +error[E0119]: conflicting implementations of trait `std::convert::TryFrom` for type `X`: + --> $DIR/conflict-with-std.rs:19:1 + | +LL | impl TryFrom for X { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl std::convert::TryFrom for T + where U: std::convert::Into; + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/e0119/issue-23563.rs b/src/test/ui/error-codes/e0119/issue-23563.rs similarity index 95% rename from src/test/ui/e0119/issue-23563.rs rename to src/test/ui/error-codes/e0119/issue-23563.rs index a2804fcf1cc55..f578560c552a8 100644 --- a/src/test/ui/e0119/issue-23563.rs +++ b/src/test/ui/error-codes/e0119/issue-23563.rs @@ -1,4 +1,4 @@ -// aux-build:issue_23563_a.rs +// aux-build:issue-23563-a.rs // Ref: https://github.com/rust-lang/rust/issues/23563#issuecomment-260751672 diff --git a/src/test/ui/e0119/issue-23563.stderr b/src/test/ui/error-codes/e0119/issue-23563.stderr similarity index 81% rename from src/test/ui/e0119/issue-23563.stderr rename to src/test/ui/error-codes/e0119/issue-23563.stderr index 53f9a5e706444..8011689880dfb 100644 --- a/src/test/ui/e0119/issue-23563.stderr +++ b/src/test/ui/error-codes/e0119/issue-23563.stderr @@ -1,7 +1,7 @@ error[E0119]: conflicting implementations of trait `a::LolFrom<&[_]>` for type `LocalType<_>`: --> $DIR/issue-23563.rs:13:1 | -LL | impl<'a, T> LolFrom<&'a [T]> for LocalType { //~ ERROR conflicting implementations of trait +LL | impl<'a, T> LolFrom<&'a [T]> for LocalType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `issue_23563_a`: diff --git a/src/test/ui/e0119/issue-27403.rs b/src/test/ui/error-codes/e0119/issue-27403.rs similarity index 100% rename from src/test/ui/e0119/issue-27403.rs rename to src/test/ui/error-codes/e0119/issue-27403.rs diff --git a/src/test/ui/e0119/issue-27403.stderr b/src/test/ui/error-codes/e0119/issue-27403.stderr similarity index 85% rename from src/test/ui/e0119/issue-27403.stderr rename to src/test/ui/error-codes/e0119/issue-27403.stderr index 76c326fb20541..cba10432a9305 100644 --- a/src/test/ui/e0119/issue-27403.stderr +++ b/src/test/ui/error-codes/e0119/issue-27403.stderr @@ -1,7 +1,7 @@ error[E0119]: conflicting implementations of trait `std::convert::Into<_>` for type `GenX<_>`: --> $DIR/issue-27403.rs:5:1 | -LL | impl Into for GenX { //~ ERROR conflicting implementations +LL | impl Into for GenX { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: diff --git a/src/test/ui/e0119/issue-28981.rs b/src/test/ui/error-codes/e0119/issue-28981.rs similarity index 100% rename from src/test/ui/e0119/issue-28981.rs rename to src/test/ui/error-codes/e0119/issue-28981.rs diff --git a/src/test/ui/e0119/issue-28981.stderr b/src/test/ui/error-codes/e0119/issue-28981.stderr similarity index 83% rename from src/test/ui/e0119/issue-28981.stderr rename to src/test/ui/error-codes/e0119/issue-28981.stderr index 8b4cd9acac454..70c83e1412da6 100644 --- a/src/test/ui/e0119/issue-28981.stderr +++ b/src/test/ui/error-codes/e0119/issue-28981.stderr @@ -1,7 +1,7 @@ error[E0119]: conflicting implementations of trait `std::ops::Deref` for type `&_`: --> $DIR/issue-28981.rs:5:1 | -LL | impl Deref for Foo { } //~ ERROR must be used +LL | impl Deref for Foo { } | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: @@ -11,12 +11,12 @@ LL | impl Deref for Foo { } //~ ERROR must be used error[E0210]: type parameter `Foo` must be used as the type parameter for some local type (e.g., `MyStruct`) --> $DIR/issue-28981.rs:5:1 | -LL | impl Deref for Foo { } //~ ERROR must be used +LL | impl Deref for Foo { } | ^^^^^^^^^^^^^^^^^^^^^^^ type parameter `Foo` must be used as the type parameter for some local type | = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to 2 previous errors -Some errors occurred: E0119, E0210. +Some errors have detailed explanations: E0119, E0210. For more information about an error, try `rustc --explain E0119`. diff --git a/src/test/ui/e0119/so-37347311.rs b/src/test/ui/error-codes/e0119/so-37347311.rs similarity index 100% rename from src/test/ui/e0119/so-37347311.rs rename to src/test/ui/error-codes/e0119/so-37347311.rs diff --git a/src/test/ui/e0119/so-37347311.stderr b/src/test/ui/error-codes/e0119/so-37347311.stderr similarity index 81% rename from src/test/ui/e0119/so-37347311.stderr rename to src/test/ui/error-codes/e0119/so-37347311.stderr index eb321668d13f8..f2166de71f8d6 100644 --- a/src/test/ui/e0119/so-37347311.stderr +++ b/src/test/ui/error-codes/e0119/so-37347311.stderr @@ -1,7 +1,7 @@ error[E0119]: conflicting implementations of trait `std::convert::From>` for type `MyError<_>`: --> $DIR/so-37347311.rs:11:1 | -LL | impl From for MyError { //~ ERROR conflicting implementations +LL | impl From for MyError { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: diff --git a/src/test/ui/error-codes/ex-E0611.stderr b/src/test/ui/error-codes/ex-E0611.stderr index f8c7cd8c1464e..8bd00a392d4f8 100644 --- a/src/test/ui/error-codes/ex-E0611.stderr +++ b/src/test/ui/error-codes/ex-E0611.stderr @@ -1,7 +1,7 @@ error[E0616]: field `0` of struct `a::Foo` is private --> $DIR/ex-E0611.rs:11:4 | -LL | y.0; //~ ERROR field `0` of struct `a::Foo` is private +LL | y.0; | ^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/ex-E0612.stderr b/src/test/ui/error-codes/ex-E0612.stderr index 0f498d1643905..b21b6fdfcf1f2 100644 --- a/src/test/ui/error-codes/ex-E0612.stderr +++ b/src/test/ui/error-codes/ex-E0612.stderr @@ -1,7 +1,7 @@ error[E0609]: no field `1` on type `Foo` --> $DIR/ex-E0612.rs:5:6 | -LL | y.1; //~ ERROR no field `1` on type `Foo` +LL | y.1; | ^ help: a field with a similar name exists: `0` error: aborting due to previous error diff --git a/src/test/ui/error-festival.rs b/src/test/ui/error-festival.rs index e462824cded49..356564e54077a 100644 --- a/src/test/ui/error-festival.rs +++ b/src/test/ui/error-festival.rs @@ -37,7 +37,7 @@ fn main() { let y: u32 = x as u32; //~^ ERROR E0606 - let v = 0 as *const u8; + let v = core::ptr::null::(); v as *const [u8]; //~^ ERROR E0607 } diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr index ff6504e9688e5..8808e95d81b18 100644 --- a/src/test/ui/error-festival.stderr +++ b/src/test/ui/error-festival.stderr @@ -71,5 +71,5 @@ LL | v as *const [u8]; error: aborting due to 10 previous errors -Some errors occurred: E0054, E0368, E0425, E0599, E0600, E0603, E0604, E0605, E0606... +Some errors have detailed explanations: E0054, E0368, E0425, E0599, E0600, E0603, E0604, E0605, E0606... For more information about an error, try `rustc --explain E0054`. diff --git a/src/test/ui/error-should-say-copy-not-pod.stderr b/src/test/ui/error-should-say-copy-not-pod.stderr index d42fea7081280..7143f8c914dd0 100644 --- a/src/test/ui/error-should-say-copy-not-pod.stderr +++ b/src/test/ui/error-should-say-copy-not-pod.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/error-should-say-copy-not-pod.rs:6:5 | -LL | check_bound("nocopy".to_string()); //~ ERROR : std::marker::Copy` is not satisfied +LL | check_bound("nocopy".to_string()); | ^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | note: required by `check_bound` diff --git a/src/test/ui/estr-subtyping.stderr b/src/test/ui/estr-subtyping.stderr index 7a7dce98f2d18..29f210803dd1d 100644 --- a/src/test/ui/estr-subtyping.stderr +++ b/src/test/ui/estr-subtyping.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/estr-subtyping.rs:10:15 | -LL | wants_uniq(x); //~ ERROR mismatched types +LL | wants_uniq(x); | ^ | | | expected struct `std::string::String`, found &str diff --git a/src/test/ui/exclusive-drop-and-copy.stderr b/src/test/ui/exclusive-drop-and-copy.stderr index 2fbeaec23a798..9983aac4f9c06 100644 --- a/src/test/ui/exclusive-drop-and-copy.stderr +++ b/src/test/ui/exclusive-drop-and-copy.stderr @@ -1,13 +1,13 @@ error[E0184]: the trait `Copy` may not be implemented for this type; the type has a destructor --> $DIR/exclusive-drop-and-copy.rs:3:10 | -LL | #[derive(Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented +LL | #[derive(Copy, Clone)] | ^^^^ Copy not allowed on types with destructors error[E0184]: the trait `Copy` may not be implemented for this type; the type has a destructor --> $DIR/exclusive-drop-and-copy.rs:10:10 | -LL | #[derive(Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented +LL | #[derive(Copy, Clone)] | ^^^^ Copy not allowed on types with destructors error: aborting due to 2 previous errors diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr index 01c7e88175683..359725a41c105 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr @@ -1,8 +1,8 @@ error: unexpected token: `,` - --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:15 + --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:17 | -LL | [_, 99.., _] => {}, //~ ERROR unexpected token: `,` - | ^^ +LL | [_, 99.., _] => {}, + | ^ error: aborting due to previous error diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr index 91109a6456643..8f849d7b3f87c 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr @@ -1,8 +1,8 @@ error: unexpected token: `]` - --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:15 + --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:17 | -LL | [_, 99..] => {}, //~ ERROR unexpected token: `]` - | ^^ +LL | [_, 99..] => {}, + | ^ error: aborting due to previous error diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr index 9c76a66c265bb..a09ba3562e098 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr @@ -1,7 +1,7 @@ error: expected one of `,` or `]`, found `9` --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:12 | -LL | [..9, 99..100, _] => {}, //~ ERROR expected one of `,` or `]`, found `9` +LL | [..9, 99..100, _] => {}, | ^ expected one of `,` or `]` here error: aborting due to previous error diff --git a/src/test/ui/exhaustive_integer_patterns.stderr b/src/test/ui/exhaustive_integer_patterns.stderr index 7b873f7ba4259..82b0b48414464 100644 --- a/src/test/ui/exhaustive_integer_patterns.stderr +++ b/src/test/ui/exhaustive_integer_patterns.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/exhaustive_integer_patterns.rs:23:9 | -LL | 200 => {} //~ ERROR unreachable pattern +LL | 200 => {} | ^^^ | note: lint level defined here @@ -13,74 +13,96 @@ LL | #![deny(unreachable_patterns)] error[E0004]: non-exhaustive patterns: `128u8..=255u8` not covered --> $DIR/exhaustive_integer_patterns.rs:28:11 | -LL | match x { //~ ERROR non-exhaustive patterns +LL | match x { | ^ pattern `128u8..=255u8` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `11u8..=19u8`, `31u8..=34u8`, `36u8..=69u8` and 1 more not covered --> $DIR/exhaustive_integer_patterns.rs:33:11 | -LL | match x { //~ ERROR non-exhaustive patterns +LL | match x { | ^ patterns `11u8..=19u8`, `31u8..=34u8`, `36u8..=69u8` and 1 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: unreachable pattern --> $DIR/exhaustive_integer_patterns.rs:44:9 | -LL | -2..=20 => {} //~ ERROR unreachable pattern +LL | -2..=20 => {} | ^^^^^^^ error[E0004]: non-exhaustive patterns: `-128i8..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered --> $DIR/exhaustive_integer_patterns.rs:41:11 | -LL | match x { //~ ERROR non-exhaustive patterns +LL | match x { | ^ patterns `-128i8..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `-128i8` not covered --> $DIR/exhaustive_integer_patterns.rs:82:11 | -LL | match 0i8 { //~ ERROR non-exhaustive patterns +LL | match 0i8 { | ^^^ pattern `-128i8` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `0i16` not covered --> $DIR/exhaustive_integer_patterns.rs:90:11 | -LL | match 0i16 { //~ ERROR non-exhaustive patterns +LL | match 0i16 { | ^^^^ pattern `0i16` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `128u8..=255u8` not covered --> $DIR/exhaustive_integer_patterns.rs:108:11 | -LL | match 0u8 { //~ ERROR non-exhaustive patterns +LL | match 0u8 { | ^^^ pattern `128u8..=255u8` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `(0u8, Some(_))` and `(2u8..=255u8, Some(_))` not covered --> $DIR/exhaustive_integer_patterns.rs:120:11 | -LL | match (0u8, Some(())) { //~ ERROR non-exhaustive patterns +LL | match (0u8, Some(())) { | ^^^^^^^^^^^^^^^ patterns `(0u8, Some(_))` and `(2u8..=255u8, Some(_))` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `(126u8..=127u8, false)` not covered --> $DIR/exhaustive_integer_patterns.rs:125:11 | -LL | match (0u8, true) { //~ ERROR non-exhaustive patterns +LL | match (0u8, true) { | ^^^^^^^^^^^ pattern `(126u8..=127u8, false)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211455u128` not covered --> $DIR/exhaustive_integer_patterns.rs:145:11 | -LL | match 0u128 { //~ ERROR non-exhaustive patterns +LL | match 0u128 { | ^^^^^ pattern `340282366920938463463374607431768211455u128` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `5u128..=340282366920938463463374607431768211455u128` not covered --> $DIR/exhaustive_integer_patterns.rs:149:11 | -LL | match 0u128 { //~ ERROR non-exhaustive patterns +LL | match 0u128 { | ^^^^^ pattern `5u128..=340282366920938463463374607431768211455u128` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `0u128..=3u128` not covered --> $DIR/exhaustive_integer_patterns.rs:153:11 | -LL | match 0u128 { //~ ERROR non-exhaustive patterns +LL | match 0u128 { | ^^^^^ pattern `0u128..=3u128` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to 13 previous errors diff --git a/src/test/ui/existential-type/issue-60371.rs b/src/test/ui/existential-type/issue-60371.rs new file mode 100644 index 0000000000000..f9def11d1932d --- /dev/null +++ b/src/test/ui/existential-type/issue-60371.rs @@ -0,0 +1,15 @@ +trait Bug { + type Item: Bug; + + const FUN: fn() -> Self::Item; +} + +impl Bug for &() { + existential type Item: Bug; //~ ERROR existential types are unstable + //~^ ERROR the trait bound `(): Bug` is not satisfied + //~^^ ERROR could not find defining uses + + const FUN: fn() -> Self::Item = || (); +} + +fn main() {} diff --git a/src/test/ui/existential-type/issue-60371.stderr b/src/test/ui/existential-type/issue-60371.stderr new file mode 100644 index 0000000000000..2560e01047aad --- /dev/null +++ b/src/test/ui/existential-type/issue-60371.stderr @@ -0,0 +1,29 @@ +error[E0658]: existential types are unstable + --> $DIR/issue-60371.rs:8:5 + | +LL | existential type Item: Bug; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/34511 + = help: add #![feature(existential_type)] to the crate attributes to enable + +error[E0277]: the trait bound `(): Bug` is not satisfied + --> $DIR/issue-60371.rs:8:5 + | +LL | existential type Item: Bug; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bug` is not implemented for `()` + | + = help: the following implementations were found: + <&() as Bug> + = note: the return type of a function must have a statically known size + +error: could not find defining uses + --> $DIR/issue-60371.rs:8:5 + | +LL | existential type Item: Bug; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0658. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_types/auxiliary/cross_crate_ice.rs b/src/test/ui/existential_types/auxiliary/cross_crate_ice.rs index af2d209826e19..96ab476061d2a 100644 --- a/src/test/ui/existential_types/auxiliary/cross_crate_ice.rs +++ b/src/test/ui/existential_types/auxiliary/cross_crate_ice.rs @@ -9,4 +9,3 @@ pub existential type Foo: std::fmt::Debug; pub fn foo() -> Foo { 5 } - diff --git a/src/test/ui/existential_types/bound_reduction2.stderr b/src/test/ui/existential_types/bound_reduction2.stderr index f51f1c9a4e563..b8bad7db6b65e 100644 --- a/src/test/ui/existential_types/bound_reduction2.stderr +++ b/src/test/ui/existential_types/bound_reduction2.stderr @@ -1,7 +1,7 @@ error: defining existential type use does not fully define existential type --> $DIR/bound_reduction2.rs:17:1 | -LL | / fn foo_desugared(_: T) -> Foo { //~ ERROR does not fully define +LL | / fn foo_desugared(_: T) -> Foo { LL | | () LL | | } | |_^ diff --git a/src/test/ui/existential_types/declared_but_never_defined.stderr b/src/test/ui/existential_types/declared_but_never_defined.stderr index 681b1cf0fa7cf..7294a074db655 100644 --- a/src/test/ui/existential_types/declared_but_never_defined.stderr +++ b/src/test/ui/existential_types/declared_but_never_defined.stderr @@ -1,7 +1,7 @@ error: could not find defining uses --> $DIR/declared_but_never_defined.rs:6:1 | -LL | existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses +LL | existential type Bar: std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/existential_types/declared_but_not_defined_in_scope.stderr b/src/test/ui/existential_types/declared_but_not_defined_in_scope.stderr index e9cc92d78ea76..a72709f719437 100644 --- a/src/test/ui/existential_types/declared_but_not_defined_in_scope.stderr +++ b/src/test/ui/existential_types/declared_but_not_defined_in_scope.stderr @@ -1,7 +1,7 @@ error: could not find defining uses --> $DIR/declared_but_not_defined_in_scope.rs:7:5 | -LL | pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses +LL | pub existential type Boo: ::std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/existential_types/different_defining_uses.stderr b/src/test/ui/existential_types/different_defining_uses.stderr index 3f9ed96400b54..fddba584798b9 100644 --- a/src/test/ui/existential_types/different_defining_uses.stderr +++ b/src/test/ui/existential_types/different_defining_uses.stderr @@ -1,7 +1,7 @@ error: concrete type differs from previous defining existential type use --> $DIR/different_defining_uses.rs:12:1 | -LL | / fn bar() -> Foo { //~ ERROR concrete type differs from previous +LL | / fn bar() -> Foo { LL | | 42i32 LL | | } | |_^ expected `&'static str`, got `i32` diff --git a/src/test/ui/existential_types/different_defining_uses_never_type.stderr b/src/test/ui/existential_types/different_defining_uses_never_type.stderr index e29256a5014f9..14b7a810be2e3 100644 --- a/src/test/ui/existential_types/different_defining_uses_never_type.stderr +++ b/src/test/ui/existential_types/different_defining_uses_never_type.stderr @@ -1,7 +1,7 @@ error: concrete type differs from previous defining existential type use --> $DIR/different_defining_uses_never_type.rs:12:1 | -LL | / fn bar() -> Foo { //~ ERROR concrete type differs from previous +LL | / fn bar() -> Foo { LL | | panic!() LL | | } | |_^ expected `&'static str`, got `()` @@ -17,7 +17,7 @@ LL | | } error: concrete type differs from previous defining existential type use --> $DIR/different_defining_uses_never_type.rs:16:1 | -LL | / fn boo() -> Foo { //~ ERROR concrete type differs from previous +LL | / fn boo() -> Foo { LL | | loop {} LL | | } | |_^ expected `&'static str`, got `()` diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error.rs b/src/test/ui/existential_types/existential-types-with-cycle-error.rs new file mode 100644 index 0000000000000..3f0190892ebb3 --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-cycle-error.rs @@ -0,0 +1,12 @@ +#![feature(existential_type)] + +existential type Foo: Fn() -> Foo; +//~^ ERROR: cycle detected when processing `Foo` + +fn crash(x: Foo) -> Foo { + x +} + +fn main() { + +} diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error.stderr b/src/test/ui/existential_types/existential-types-with-cycle-error.stderr new file mode 100644 index 0000000000000..56057a9caa4a5 --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-cycle-error.stderr @@ -0,0 +1,30 @@ +error[E0391]: cycle detected when processing `Foo` + --> $DIR/existential-types-with-cycle-error.rs:3:1 + | +LL | existential type Foo: Fn() -> Foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires processing `crash`... + --> $DIR/existential-types-with-cycle-error.rs:6:25 + | +LL | fn crash(x: Foo) -> Foo { + | _________________________^ +LL | | x +LL | | } + | |_^ + = note: ...which again requires processing `Foo`, completing the cycle +note: cycle used when collecting item types in top-level module + --> $DIR/existential-types-with-cycle-error.rs:1:1 + | +LL | / #![feature(existential_type)] +LL | | +LL | | existential type Foo: Fn() -> Foo; +LL | | +... | +LL | | +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error2.rs b/src/test/ui/existential_types/existential-types-with-cycle-error2.rs new file mode 100644 index 0000000000000..29410309ef26e --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-cycle-error2.rs @@ -0,0 +1,16 @@ +#![feature(existential_type)] + +pub trait Bar { + type Item; +} + +existential type Foo: Bar; +//~^ ERROR: cycle detected when processing `Foo` + +fn crash(x: Foo) -> Foo { + x +} + +fn main() { + +} diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error2.stderr b/src/test/ui/existential_types/existential-types-with-cycle-error2.stderr new file mode 100644 index 0000000000000..8c7bf52470ab2 --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-cycle-error2.stderr @@ -0,0 +1,30 @@ +error[E0391]: cycle detected when processing `Foo` + --> $DIR/existential-types-with-cycle-error2.rs:7:1 + | +LL | existential type Foo: Bar; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires processing `crash`... + --> $DIR/existential-types-with-cycle-error2.rs:10:25 + | +LL | fn crash(x: Foo) -> Foo { + | _________________________^ +LL | | x +LL | | } + | |_^ + = note: ...which again requires processing `Foo`, completing the cycle +note: cycle used when collecting item types in top-level module + --> $DIR/existential-types-with-cycle-error2.rs:1:1 + | +LL | / #![feature(existential_type)] +LL | | +LL | | pub trait Bar { +LL | | type Item; +... | +LL | | +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/existential_types/existential-types-with-no-traits.rs b/src/test/ui/existential_types/existential-types-with-no-traits.rs new file mode 100644 index 0000000000000..46339c73b1f1d --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-no-traits.rs @@ -0,0 +1,14 @@ +#![feature(existential_type)] + +existential type Foo: 'static; +//~^ ERROR: at least one trait must be specified + +fn foo() -> Foo { + "foo" +} + +fn bar() -> impl 'static { //~ ERROR: at least one trait must be specified + "foo" +} + +fn main() {} diff --git a/src/test/ui/existential_types/existential-types-with-no-traits.stderr b/src/test/ui/existential_types/existential-types-with-no-traits.stderr new file mode 100644 index 0000000000000..4b2fbc79d3bc2 --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-no-traits.stderr @@ -0,0 +1,14 @@ +error: at least one trait must be specified + --> $DIR/existential-types-with-no-traits.rs:3:23 + | +LL | existential type Foo: 'static; + | ^^^^^^^ + +error: at least one trait must be specified + --> $DIR/existential-types-with-no-traits.rs:10:13 + | +LL | fn bar() -> impl 'static { + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/existential_types/generic_different_defining_uses.stderr b/src/test/ui/existential_types/generic_different_defining_uses.stderr index 3f129658b8fd0..e5b1539ccbb92 100644 --- a/src/test/ui/existential_types/generic_different_defining_uses.stderr +++ b/src/test/ui/existential_types/generic_different_defining_uses.stderr @@ -1,7 +1,7 @@ error: concrete type differs from previous defining existential type use --> $DIR/generic_different_defining_uses.rs:11:1 | -LL | / fn my_iter2(t: T) -> MyIter { //~ ERROR concrete type differs from previous +LL | / fn my_iter2(t: T) -> MyIter { LL | | Some(t).into_iter() LL | | } | |_^ expected `std::iter::Once`, got `std::option::IntoIter` diff --git a/src/test/ui/existential_types/generic_duplicate_lifetime_param.stderr b/src/test/ui/existential_types/generic_duplicate_lifetime_param.stderr index 7b09d3ceab0b9..29bd252babe52 100644 --- a/src/test/ui/existential_types/generic_duplicate_lifetime_param.stderr +++ b/src/test/ui/existential_types/generic_duplicate_lifetime_param.stderr @@ -1,7 +1,7 @@ error: non-defining existential type use in defining scope --> $DIR/generic_duplicate_lifetime_param.rs:7:1 | -LL | / fn one<'a>(t: &'a ()) -> Two<'a, 'a> { //~ ERROR non-defining existential type use +LL | / fn one<'a>(t: &'a ()) -> Two<'a, 'a> { LL | | t LL | | } | |_^ diff --git a/src/test/ui/existential_types/generic_duplicate_param_use.stderr b/src/test/ui/existential_types/generic_duplicate_param_use.stderr index d4deda999da16..a3827943b6dfc 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use.stderr @@ -2,7 +2,7 @@ error: defining existential type use restricts existential type by using the gen --> $DIR/generic_duplicate_param_use.rs:11:1 | LL | / fn one(t: T) -> Two { -LL | | //~^ ERROR defining existential type use restricts existential type +LL | | LL | | t LL | | } | |_^ diff --git a/src/test/ui/existential_types/generic_duplicate_param_use2.stderr b/src/test/ui/existential_types/generic_duplicate_param_use2.stderr index 0a8be3218c759..74f2802449a74 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use2.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use2.stderr @@ -2,7 +2,7 @@ error: defining existential type use restricts existential type by using the gen --> $DIR/generic_duplicate_param_use2.rs:10:1 | LL | / fn one(t: T) -> Two { -LL | | //~^ defining existential type use restricts existential type +LL | | LL | | t LL | | } | |_^ diff --git a/src/test/ui/existential_types/generic_duplicate_param_use3.stderr b/src/test/ui/existential_types/generic_duplicate_param_use3.stderr index 1c96c15a76919..22d5467c363fd 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use3.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use3.stderr @@ -2,7 +2,7 @@ error: defining existential type use restricts existential type by using the gen --> $DIR/generic_duplicate_param_use3.rs:10:1 | LL | / fn one(t: T) -> Two { -LL | | //~^ defining existential type use restricts existential type +LL | | LL | | t LL | | } | |_^ @@ -11,7 +11,7 @@ error: concrete type's generic parameters differ from previous defining use --> $DIR/generic_duplicate_param_use3.rs:19:1 | LL | / fn three(_: T, u: U) -> Two { -LL | | //~^ concrete type's generic parameters differ from previous defining use +LL | | LL | | u LL | | } | |_^ expected [`T`], got [`U`] diff --git a/src/test/ui/existential_types/generic_duplicate_param_use4.stderr b/src/test/ui/existential_types/generic_duplicate_param_use4.stderr index 24b1caf7c1bfe..d7e695578d399 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use4.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use4.stderr @@ -2,7 +2,7 @@ error: defining existential type use restricts existential type by using the gen --> $DIR/generic_duplicate_param_use4.rs:10:1 | LL | / fn one(t: T) -> Two { -LL | | //~^ ERROR defining existential type use restricts existential type +LL | | LL | | t LL | | } | |_^ diff --git a/src/test/ui/existential_types/generic_duplicate_param_use5.stderr b/src/test/ui/existential_types/generic_duplicate_param_use5.stderr index 166623801c246..cf4535d6c2c6a 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use5.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use5.stderr @@ -2,7 +2,7 @@ error: concrete type differs from previous defining existential type use --> $DIR/generic_duplicate_param_use5.rs:14:1 | LL | / fn three(t: T, u: U) -> Two { -LL | | //~^ concrete type differs from previous +LL | | LL | | (u, t) LL | | } | |_^ expected `(T, U)`, got `(U, T)` diff --git a/src/test/ui/existential_types/generic_duplicate_param_use6.stderr b/src/test/ui/existential_types/generic_duplicate_param_use6.stderr index da49a83be1f70..1f767dacea8de 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use6.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use6.stderr @@ -2,7 +2,7 @@ error: concrete type differs from previous defining existential type use --> $DIR/generic_duplicate_param_use6.rs:14:1 | LL | / fn three(t: T, u: U) -> Two { -LL | | //~^ concrete type differs from previous +LL | | LL | | (u, t) LL | | } | |_^ expected `(T, T)`, got `(U, T)` diff --git a/src/test/ui/existential_types/generic_duplicate_param_use7.rs b/src/test/ui/existential_types/generic_duplicate_param_use7.rs index 2bcac315f5a96..5d8d05c308780 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use7.rs +++ b/src/test/ui/existential_types/generic_duplicate_param_use7.rs @@ -22,4 +22,3 @@ fn four(t: T, t2: T, u: U, v: V) -> Two { fn five(x: X, y: Y, y2: Y) -> Two { (y, y2) } - diff --git a/src/test/ui/existential_types/generic_duplicate_param_use8.stderr b/src/test/ui/existential_types/generic_duplicate_param_use8.stderr index 80c7441c857d1..58f4f97b24118 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use8.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use8.stderr @@ -2,7 +2,7 @@ error: concrete type differs from previous defining existential type use --> $DIR/generic_duplicate_param_use8.rs:13:1 | LL | / fn three(_: T, u: U) -> Two { -LL | | //~^ concrete type differs from previous +LL | | LL | | (u, 4u32) LL | | } | |_^ expected `(T, u32)`, got `(U, u32)` diff --git a/src/test/ui/existential_types/generic_duplicate_param_use9.stderr b/src/test/ui/existential_types/generic_duplicate_param_use9.stderr index a3ce480d66dcd..fe4ae6cfdd078 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use9.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use9.stderr @@ -2,7 +2,7 @@ error: concrete type differs from previous defining existential type use --> $DIR/generic_duplicate_param_use9.rs:18:1 | LL | / fn three(t: T, u: U) -> Two { -LL | | (t, u, 42) //~^ ERROR concrete type differs from previous +LL | | (t, u, 42) LL | | } | |_^ expected `(A, B, ::Bar)`, got `(A, B, i32)` | diff --git a/src/test/ui/existential_types/generic_nondefining_use.rs b/src/test/ui/existential_types/generic_nondefining_use.rs index 75af5d9570ff2..ffc965aca47c9 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.rs +++ b/src/test/ui/existential_types/generic_nondefining_use.rs @@ -4,6 +4,8 @@ fn main() {} existential type Cmp: 'static; //~^ ERROR could not find defining uses +//~^^ ERROR: at least one trait must be specified + // not a defining use, because it doesn't define *all* possible generics fn cmp() -> Cmp { //~ ERROR defining existential type use does not fully define diff --git a/src/test/ui/existential_types/generic_nondefining_use.stderr b/src/test/ui/existential_types/generic_nondefining_use.stderr index 8dd88006be9c6..d205d44c68c71 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.stderr +++ b/src/test/ui/existential_types/generic_nondefining_use.stderr @@ -1,7 +1,13 @@ +error: at least one trait must be specified + --> $DIR/generic_nondefining_use.rs:5:26 + | +LL | existential type Cmp: 'static; + | ^^^^^^^ + error: defining existential type use does not fully define existential type - --> $DIR/generic_nondefining_use.rs:9:1 + --> $DIR/generic_nondefining_use.rs:11:1 | -LL | / fn cmp() -> Cmp { //~ ERROR defining existential type use does not fully define +LL | / fn cmp() -> Cmp { LL | | 5u32 LL | | } | |_^ @@ -12,5 +18,5 @@ error: could not find defining uses LL | existential type Cmp: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/existential_types/generic_not_used.rs b/src/test/ui/existential_types/generic_not_used.rs index bfe7b8c4a1d53..054e6f5f2ade9 100644 --- a/src/test/ui/existential_types/generic_not_used.rs +++ b/src/test/ui/existential_types/generic_not_used.rs @@ -3,6 +3,7 @@ fn main() {} existential type WrongGeneric: 'static; +//~^ ERROR: at least one trait must be specified fn wrong_generic(_: U, v: V) -> WrongGeneric { //~^ ERROR type parameter `V` is part of concrete type but not used in parameter list diff --git a/src/test/ui/existential_types/generic_not_used.stderr b/src/test/ui/existential_types/generic_not_used.stderr index b22cffeea2898..d243233992b02 100644 --- a/src/test/ui/existential_types/generic_not_used.stderr +++ b/src/test/ui/existential_types/generic_not_used.stderr @@ -1,12 +1,18 @@ +error: at least one trait must be specified + --> $DIR/generic_not_used.rs:5:44 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^ + error: type parameter `V` is part of concrete type but not used in parameter list for existential type - --> $DIR/generic_not_used.rs:7:73 + --> $DIR/generic_not_used.rs:8:73 | LL | fn wrong_generic(_: U, v: V) -> WrongGeneric { | _________________________________________________________________________^ -LL | | //~^ ERROR type parameter `V` is part of concrete type but not used in parameter list +LL | | LL | | v LL | | } | |_^ -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr new file mode 100644 index 0000000000000..f316644156dc5 --- /dev/null +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr @@ -0,0 +1,18 @@ +error: at least one trait must be specified + --> $DIR/generic_type_does_not_live_long_enough.rs:9:35 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/generic_type_does_not_live_long_enough.rs:6:18 + | +LL | let z: i32 = x; + | ^ expected i32, found opaque type + | + = note: expected type `i32` + found type `WrongGeneric::<&{integer}>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs index 02bb151ccb618..d9eedd6dca7c1 100644 --- a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs @@ -8,6 +8,7 @@ fn main() { existential type WrongGeneric: 'static; //~^ ERROR the parameter type `T` may not live long enough +//~^^ ERROR: at least one trait must be specified fn wrong_generic(t: T) -> WrongGeneric { t diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr index d9bb37328bd5b..2f76eea4460bd 100644 --- a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr @@ -1,7 +1,13 @@ +error: at least one trait must be specified + --> $DIR/generic_type_does_not_live_long_enough.rs:9:35 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^ + error[E0308]: mismatched types --> $DIR/generic_type_does_not_live_long_enough.rs:6:18 | -LL | let z: i32 = x; //~ ERROR mismatched types +LL | let z: i32 = x; | ^ expected i32, found opaque type | = note: expected type `i32` @@ -22,7 +28,7 @@ note: ...so that the type `T` will meet its required lifetime bounds LL | existential type WrongGeneric: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -Some errors occurred: E0308, E0310. +Some errors have detailed explanations: E0308, E0310. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/existential_types/generic_underconstrained.rs b/src/test/ui/existential_types/generic_underconstrained.rs index 967faca067c1e..cc0db893c6aa7 100644 --- a/src/test/ui/existential_types/generic_underconstrained.rs +++ b/src/test/ui/existential_types/generic_underconstrained.rs @@ -4,6 +4,7 @@ fn main() {} trait Trait {} existential type Underconstrained: 'static; //~ ERROR the trait bound `T: Trait` +//~^ ERROR: at least one trait must be specified // no `Trait` bound fn underconstrain(_: T) -> Underconstrained { diff --git a/src/test/ui/existential_types/generic_underconstrained.stderr b/src/test/ui/existential_types/generic_underconstrained.stderr index 57924e0ce2131..35083a53eb343 100644 --- a/src/test/ui/existential_types/generic_underconstrained.stderr +++ b/src/test/ui/existential_types/generic_underconstrained.stderr @@ -1,12 +1,18 @@ +error: at least one trait must be specified + --> $DIR/generic_underconstrained.rs:6:46 + | +LL | existential type Underconstrained: 'static; + | ^^^^^^^ + error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/generic_underconstrained.rs:6:1 | -LL | existential type Underconstrained: 'static; //~ ERROR the trait bound `T: Trait` +LL | existential type Underconstrained: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` | = help: consider adding a `where T: Trait` bound = note: the return type of a function must have a statically known size -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_types/generic_underconstrained2.rs b/src/test/ui/existential_types/generic_underconstrained2.rs index 98d9da832cfd3..c6263eacd53e3 100644 --- a/src/test/ui/existential_types/generic_underconstrained2.rs +++ b/src/test/ui/existential_types/generic_underconstrained2.rs @@ -4,6 +4,7 @@ fn main() {} existential type Underconstrained: 'static; //~^ ERROR `U` doesn't implement `std::fmt::Debug` +//~^^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained(_: U) -> Underconstrained { @@ -12,6 +13,7 @@ fn underconstrained(_: U) -> Underconstrained { existential type Underconstrained2: 'static; //~^ ERROR `V` doesn't implement `std::fmt::Debug` +//~^^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained2(_: U, _: V) -> Underconstrained2 { diff --git a/src/test/ui/existential_types/generic_underconstrained2.stderr b/src/test/ui/existential_types/generic_underconstrained2.stderr index c7b6d6ade557c..6ff783f33b96f 100644 --- a/src/test/ui/existential_types/generic_underconstrained2.stderr +++ b/src/test/ui/existential_types/generic_underconstrained2.stderr @@ -1,3 +1,15 @@ +error: at least one trait must be specified + --> $DIR/generic_underconstrained2.rs:5:56 + | +LL | existential type Underconstrained: 'static; + | ^^^^^^^ + +error: at least one trait must be specified + --> $DIR/generic_underconstrained2.rs:14:57 + | +LL | existential type Underconstrained2: 'static; + | ^^^^^^^ + error[E0277]: `U` doesn't implement `std::fmt::Debug` --> $DIR/generic_underconstrained2.rs:5:1 | @@ -9,7 +21,7 @@ LL | existential type Underconstrained: 'static; = note: the return type of a function must have a statically known size error[E0277]: `V` doesn't implement `std::fmt::Debug` - --> $DIR/generic_underconstrained2.rs:13:1 + --> $DIR/generic_underconstrained2.rs:14:1 | LL | existential type Underconstrained2: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` @@ -18,6 +30,6 @@ LL | existential type Underconstrained2: 'static; = help: consider adding a `where V: std::fmt::Debug` bound = note: the return type of a function must have a statically known size -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_types/nested_existential_types.rs b/src/test/ui/existential_types/nested_existential_types.rs index 62a4779991411..6d2a12da7e443 100644 --- a/src/test/ui/existential_types/nested_existential_types.rs +++ b/src/test/ui/existential_types/nested_existential_types.rs @@ -18,4 +18,3 @@ mod my_mod { fn main() { let _: my_mod::Foot = my_mod::get_foot(); } - diff --git a/src/test/ui/existential_types/never_reveal_concrete_type.stderr b/src/test/ui/existential_types/never_reveal_concrete_type.stderr index 33a71fc4356b5..7c195f1fad006 100644 --- a/src/test/ui/existential_types/never_reveal_concrete_type.stderr +++ b/src/test/ui/existential_types/never_reveal_concrete_type.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/never_reveal_concrete_type.rs:13:27 | -LL | let _: &'static str = x; //~ mismatched types +LL | let _: &'static str = x; | ^ expected reference, found opaque type | = note: expected type `&'static str` @@ -10,12 +10,12 @@ LL | let _: &'static str = x; //~ mismatched types error[E0605]: non-primitive cast: `NoReveal` as `&'static str` --> $DIR/never_reveal_concrete_type.rs:14:13 | -LL | let _ = x as &'static str; //~ non-primitive cast +LL | let _ = x as &'static str; | ^^^^^^^^^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait error: aborting due to 2 previous errors -Some errors occurred: E0308, E0605. +Some errors have detailed explanations: E0308, E0605. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/existential_types/no_inferrable_concrete_type.stderr b/src/test/ui/existential_types/no_inferrable_concrete_type.stderr index fab61bd9ed065..4605332ef5b35 100644 --- a/src/test/ui/existential_types/no_inferrable_concrete_type.stderr +++ b/src/test/ui/existential_types/no_inferrable_concrete_type.stderr @@ -1,7 +1,7 @@ error[E0391]: cycle detected when processing `Foo` --> $DIR/no_inferrable_concrete_type.rs:6:1 | -LL | existential type Foo: Copy; //~ cycle detected +LL | existential type Foo: Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...which requires processing `bar`... @@ -15,7 +15,7 @@ note: cycle used when collecting item types in top-level module | LL | / #![feature(existential_type)] LL | | -LL | | existential type Foo: Copy; //~ cycle detected +LL | | existential type Foo: Copy; LL | | ... | LL | | let _: Foo = std::mem::transmute(0u8); diff --git a/src/test/ui/existential_types/no_revealing_outside_defining_module.rs b/src/test/ui/existential_types/no_revealing_outside_defining_module.rs index 142f2f6d75169..04793c67b564d 100644 --- a/src/test/ui/existential_types/no_revealing_outside_defining_module.rs +++ b/src/test/ui/existential_types/no_revealing_outside_defining_module.rs @@ -9,7 +9,7 @@ mod boo { } } -// don't actually know the type here +// We don't actually know the type here. fn bomp2() { let _: &str = bomp(); //~ ERROR mismatched types diff --git a/src/test/ui/existential_types/no_revealing_outside_defining_module.stderr b/src/test/ui/existential_types/no_revealing_outside_defining_module.stderr index 4ffce58f8de75..5e5826978fc7e 100644 --- a/src/test/ui/existential_types/no_revealing_outside_defining_module.stderr +++ b/src/test/ui/existential_types/no_revealing_outside_defining_module.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/no_revealing_outside_defining_module.rs:15:19 | -LL | let _: &str = bomp(); //~ ERROR mismatched types +LL | let _: &str = bomp(); | ^^^^^^ expected &str, found opaque type | = note: expected type `&str` @@ -12,7 +12,7 @@ error[E0308]: mismatched types | LL | fn bomp() -> boo::Boo { | -------- expected `Boo` because of return type -LL | "" //~ ERROR mismatched types +LL | "" | ^^ expected opaque type, found reference | = note: expected type `Boo` diff --git a/src/test/ui/existential_types/not_a_defining_use.stderr b/src/test/ui/existential_types/not_a_defining_use.stderr index 288a32fc14edd..f315811cdb42e 100644 --- a/src/test/ui/existential_types/not_a_defining_use.stderr +++ b/src/test/ui/existential_types/not_a_defining_use.stderr @@ -2,7 +2,7 @@ error: defining existential type use does not fully define existential type --> $DIR/not_a_defining_use.rs:9:1 | LL | / fn two(t: T) -> Two { -LL | | //~^ ERROR defining existential type use does not fully define existential type +LL | | LL | | (t, 4i8) LL | | } | |_^ @@ -10,7 +10,7 @@ LL | | } error: concrete type differs from previous defining existential type use --> $DIR/not_a_defining_use.rs:30:1 | -LL | / fn four(t: T) -> Two { //~ concrete type differs from previous +LL | / fn four(t: T) -> Two { LL | | (t, ::FOO) LL | | } | |_^ expected `(T, i8)`, got `(T, ::Blub)` diff --git a/src/test/ui/existential_types/not_well_formed.stderr b/src/test/ui/existential_types/not_well_formed.stderr index 17ea57805d2b9..05f84d5762341 100644 --- a/src/test/ui/existential_types/not_well_formed.stderr +++ b/src/test/ui/existential_types/not_well_formed.stderr @@ -1,7 +1,7 @@ error[E0220]: associated type `Assoc` not found for `V` --> $DIR/not_well_formed.rs:10:32 | -LL | existential type Foo: Trait; //~ associated type `Assoc` not found for `V` +LL | existential type Foo: Trait; | ^^^^^^^^ associated type `Assoc` not found error: aborting due to previous error diff --git a/src/test/ui/existential_types/unused_generic_param.rs b/src/test/ui/existential_types/unused_generic_param.rs index 7af6508788129..5455b39f4cbe2 100644 --- a/src/test/ui/existential_types/unused_generic_param.rs +++ b/src/test/ui/existential_types/unused_generic_param.rs @@ -1,18 +1,17 @@ -// compile-pass #![feature(existential_type)] fn main() { } -// test that unused generic parameters are ok existential type PartiallyDefined: 'static; +//~^ ERROR: at least one trait must be specified fn partially_defined(_: T) -> PartiallyDefined { 4u32 } -// test that unused generic parameters are ok existential type PartiallyDefined2: 'static; +//~^ ERROR: at least one trait must be specified fn partially_defined2(_: T) -> PartiallyDefined2 { 4u32 diff --git a/src/test/ui/existential_types/unused_generic_param.stderr b/src/test/ui/existential_types/unused_generic_param.stderr new file mode 100644 index 0000000000000..9d628d069d36c --- /dev/null +++ b/src/test/ui/existential_types/unused_generic_param.stderr @@ -0,0 +1,14 @@ +error: at least one trait must be specified + --> $DIR/unused_generic_param.rs:6:39 + | +LL | existential type PartiallyDefined: 'static; + | ^^^^^^^ + +error: at least one trait must be specified + --> $DIR/unused_generic_param.rs:13:40 + | +LL | existential type PartiallyDefined2: 'static; + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/expanded-cfg.rs b/src/test/ui/expanded-cfg.rs index fbae093f2ac2d..baa161af76abc 100644 --- a/src/test/ui/expanded-cfg.rs +++ b/src/test/ui/expanded-cfg.rs @@ -1,6 +1,5 @@ -// skip-codegen -// compile-pass -#![feature(custom_attribute)] +// check-pass + macro_rules! mac { {} => { #[cfg(attr)] @@ -19,5 +18,4 @@ macro_rules! mac { mac! {} - fn main() {} diff --git a/src/test/ui/explain.stdout b/src/test/ui/explain.stdout index 411cdfb335b34..9ea56271f593f 100644 --- a/src/test/ui/explain.stdout +++ b/src/test/ui/explain.stdout @@ -53,7 +53,7 @@ This pattern should be rewritten. There are a few possible ways to do this: let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too ``` -The same applies to transmutes to `*mut fn()`, which were observedin practice. +The same applies to transmutes to `*mut fn()`, which were observed in practice. Note though that use of this type is generally incorrect. The intention is typically to describe a function pointer, but just `fn()` alone suffices for that. `*mut fn()` is a pointer to a fn pointer. diff --git a/src/test/ui/explicit/explicit-call-to-dtor.stderr b/src/test/ui/explicit/explicit-call-to-dtor.stderr index db09b23bf26e5..cbbe967179ef3 100644 --- a/src/test/ui/explicit/explicit-call-to-dtor.stderr +++ b/src/test/ui/explicit/explicit-call-to-dtor.stderr @@ -1,7 +1,7 @@ error[E0040]: explicit use of destructor method --> $DIR/explicit-call-to-dtor.rs:13:7 | -LL | x.drop(); //~ ERROR explicit use of destructor method +LL | x.drop(); | ^^^^ explicit destructor calls not allowed error: aborting due to previous error diff --git a/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr index dfd122b3ea405..0b302e30b64f3 100644 --- a/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr +++ b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr @@ -1,7 +1,7 @@ error[E0040]: explicit use of destructor method --> $DIR/explicit-call-to-supertrait-dtor.rs:17:14 | -LL | self.drop(); //~ ERROR explicit use of destructor method +LL | self.drop(); | ^^^^ explicit destructor calls not allowed error: aborting due to previous error diff --git a/src/test/ui/explore-issue-38412.rs b/src/test/ui/explore-issue-38412.rs index cd0a69b0d8b8e..e7bcd7c6bfe65 100644 --- a/src/test/ui/explore-issue-38412.rs +++ b/src/test/ui/explore-issue-38412.rs @@ -1,4 +1,4 @@ -// aux-build:pub_and_stability.rs +// aux-build:pub-and-stability.rs #![feature(unused_feature)] @@ -63,5 +63,4 @@ fn main() { t.pub_crate(); //~ ERROR `pub_crate` is private t.pub_mod(); //~ ERROR `pub_mod` is private t.private(); //~ ERROR `private` is private - } diff --git a/src/test/ui/explore-issue-38412.stderr b/src/test/ui/explore-issue-38412.stderr index e3ce6c1317f50..ceeaaafc2bc3f 100644 --- a/src/test/ui/explore-issue-38412.stderr +++ b/src/test/ui/explore-issue-38412.stderr @@ -1,132 +1,139 @@ -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:21:63 | LL | let Record { a_stable_pub: _, a_unstable_declared_pub: _, a_unstable_undeclared_pub: _, .. } = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:30:5 | -LL | r.a_unstable_undeclared_pub; //~ ERROR use of unstable library feature +LL | r.a_unstable_undeclared_pub; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable error[E0616]: field `b_crate` of struct `pub_and_stability::Record` is private --> $DIR/explore-issue-38412.rs:31:5 | -LL | r.b_crate; //~ ERROR is private +LL | r.b_crate; | ^^^^^^^^^ error[E0616]: field `c_mod` of struct `pub_and_stability::Record` is private --> $DIR/explore-issue-38412.rs:32:5 | -LL | r.c_mod; //~ ERROR is private +LL | r.c_mod; | ^^^^^^^ error[E0616]: field `d_priv` of struct `pub_and_stability::Record` is private --> $DIR/explore-issue-38412.rs:33:5 | -LL | r.d_priv; //~ ERROR is private +LL | r.d_priv; | ^^^^^^^^ -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:37:5 | -LL | t.2; //~ ERROR use of unstable library feature +LL | t.2; | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable error[E0616]: field `3` of struct `pub_and_stability::Tuple` is private --> $DIR/explore-issue-38412.rs:38:5 | -LL | t.3; //~ ERROR is private +LL | t.3; | ^^^ error[E0616]: field `4` of struct `pub_and_stability::Tuple` is private --> $DIR/explore-issue-38412.rs:39:5 | -LL | t.4; //~ ERROR is private +LL | t.4; | ^^^ error[E0616]: field `5` of struct `pub_and_stability::Tuple` is private --> $DIR/explore-issue-38412.rs:40:5 | -LL | t.5; //~ ERROR is private +LL | t.5; | ^^^ -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:44:7 | -LL | r.unstable_undeclared_trait_method(); //~ ERROR use of unstable library feature +LL | r.unstable_undeclared_trait_method(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:48:7 | -LL | r.unstable_undeclared(); //~ ERROR use of unstable library feature +LL | r.unstable_undeclared(); | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable error[E0624]: method `pub_crate` is private --> $DIR/explore-issue-38412.rs:50:7 | -LL | r.pub_crate(); //~ ERROR `pub_crate` is private +LL | r.pub_crate(); | ^^^^^^^^^ error[E0624]: method `pub_mod` is private --> $DIR/explore-issue-38412.rs:51:7 | -LL | r.pub_mod(); //~ ERROR `pub_mod` is private +LL | r.pub_mod(); | ^^^^^^^ error[E0624]: method `private` is private --> $DIR/explore-issue-38412.rs:52:7 | -LL | r.private(); //~ ERROR `private` is private +LL | r.private(); | ^^^^^^^ -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:57:7 | -LL | t.unstable_undeclared_trait_method(); //~ ERROR use of unstable library feature +LL | t.unstable_undeclared_trait_method(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:61:7 | -LL | t.unstable_undeclared(); //~ ERROR use of unstable library feature +LL | t.unstable_undeclared(); | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable error[E0624]: method `pub_crate` is private --> $DIR/explore-issue-38412.rs:63:7 | -LL | t.pub_crate(); //~ ERROR `pub_crate` is private +LL | t.pub_crate(); | ^^^^^^^^^ error[E0624]: method `pub_mod` is private --> $DIR/explore-issue-38412.rs:64:7 | -LL | t.pub_mod(); //~ ERROR `pub_mod` is private +LL | t.pub_mod(); | ^^^^^^^ error[E0624]: method `private` is private --> $DIR/explore-issue-38412.rs:65:7 | -LL | t.private(); //~ ERROR `private` is private +LL | t.private(); | ^^^^^^^ error: aborting due to 19 previous errors -Some errors occurred: E0616, E0624, E0658. +Some errors have detailed explanations: E0616, E0624, E0658. For more information about an error, try `rustc --explain E0616`. diff --git a/src/test/ui/export-fully-qualified.stderr b/src/test/ui/export-fully-qualified.stderr index dd7e3219c76a7..c2ec1600868ab 100644 --- a/src/test/ui/export-fully-qualified.stderr +++ b/src/test/ui/export-fully-qualified.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: use of undeclared type or module `foo` --> $DIR/export-fully-qualified.rs:6:20 | -LL | pub fn bar() { foo::baz(); } //~ ERROR failed to resolve: use of undeclared type or module `foo` +LL | pub fn bar() { foo::baz(); } | ^^^ use of undeclared type or module `foo` error: aborting due to previous error diff --git a/src/test/ui/export-tag-variant.stderr b/src/test/ui/export-tag-variant.stderr index eb202b3b31b08..b5a2c12c436d0 100644 --- a/src/test/ui/export-tag-variant.stderr +++ b/src/test/ui/export-tag-variant.stderr @@ -1,7 +1,7 @@ error[E0603]: enum `Y` is private --> $DIR/export-tag-variant.rs:7:26 | -LL | fn main() { let z = foo::Y::Y1; } //~ ERROR: enum `Y` is private +LL | fn main() { let z = foo::Y::Y1; } | ^ error: aborting due to previous error diff --git a/src/test/ui/export.stderr b/src/test/ui/export.stderr index ff7763bbd899b..a3668a502cdd4 100644 --- a/src/test/ui/export.stderr +++ b/src/test/ui/export.stderr @@ -25,10 +25,10 @@ LL | fn z(y: isize) { log(debug, y); } error[E0603]: function `z` is private --> $DIR/export.rs:10:18 | -LL | fn main() { foo::z(10); } //~ ERROR function `z` is private +LL | fn main() { foo::z(10); } | ^ error: aborting due to 5 previous errors -Some errors occurred: E0425, E0603. +Some errors have detailed explanations: E0425, E0603. For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/export2.stderr b/src/test/ui/export2.stderr index 6233c6d074e66..e0cd4404d3778 100644 --- a/src/test/ui/export2.stderr +++ b/src/test/ui/export2.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: use of undeclared type or module `bar` --> $DIR/export2.rs:2:18 | -LL | pub fn x() { bar::x(); } //~ ERROR failed to resolve: use of undeclared type or module `bar` +LL | pub fn x() { bar::x(); } | ^^^ use of undeclared type or module `bar` error: aborting due to previous error diff --git a/src/test/ui/expr_attr_paren_order.stderr b/src/test/ui/expr_attr_paren_order.stderr index 8155514191ce3..89f615f53ddd3 100644 --- a/src/test/ui/expr_attr_paren_order.stderr +++ b/src/test/ui/expr_attr_paren_order.stderr @@ -1,7 +1,7 @@ error: variable `X` should have a snake case name --> $DIR/expr_attr_paren_order.rs:19:17 | -LL | let X = 0; //~ ERROR snake case name +LL | let X = 0; | ^ help: convert the identifier to snake case: `x` | note: lint level defined here diff --git a/src/test/ui/extenv/extenv-arg-2-not-string-literal.stderr b/src/test/ui/extenv/extenv-arg-2-not-string-literal.stderr index 92c04f9fe8a51..258e2b347fba8 100644 --- a/src/test/ui/extenv/extenv-arg-2-not-string-literal.stderr +++ b/src/test/ui/extenv/extenv-arg-2-not-string-literal.stderr @@ -1,7 +1,7 @@ error: expected string literal --> $DIR/extenv-arg-2-not-string-literal.rs:1:25 | -LL | fn main() { env!("one", 10); } //~ ERROR: expected string literal +LL | fn main() { env!("one", 10); } | ^^ error: aborting due to previous error diff --git a/src/test/ui/extenv/extenv-no-args.stderr b/src/test/ui/extenv/extenv-no-args.stderr index 7ae8a6f1858a9..acdde84afa4d4 100644 --- a/src/test/ui/extenv/extenv-no-args.stderr +++ b/src/test/ui/extenv/extenv-no-args.stderr @@ -1,7 +1,7 @@ error: env! takes 1 or 2 arguments --> $DIR/extenv-no-args.rs:1:13 | -LL | fn main() { env!(); } //~ ERROR: env! takes 1 or 2 arguments +LL | fn main() { env!(); } | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/extenv/extenv-not-defined-custom.stderr b/src/test/ui/extenv/extenv-not-defined-custom.stderr index 34e5b7f9f2364..523982dd0196b 100644 --- a/src/test/ui/extenv/extenv-not-defined-custom.stderr +++ b/src/test/ui/extenv/extenv-not-defined-custom.stderr @@ -1,7 +1,7 @@ error: my error message --> $DIR/extenv-not-defined-custom.rs:1:13 | -LL | fn main() { env!("__HOPEFULLY_NOT_DEFINED__", "my error message"); } //~ ERROR: my error message +LL | fn main() { env!("__HOPEFULLY_NOT_DEFINED__", "my error message"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/extenv/extenv-not-string-literal.stderr b/src/test/ui/extenv/extenv-not-string-literal.stderr index 66645b24a49ad..342a9f7096e71 100644 --- a/src/test/ui/extenv/extenv-not-string-literal.stderr +++ b/src/test/ui/extenv/extenv-not-string-literal.stderr @@ -1,7 +1,7 @@ error: expected string literal --> $DIR/extenv-not-string-literal.rs:1:18 | -LL | fn main() { env!(10, "two"); } //~ ERROR: expected string literal +LL | fn main() { env!(10, "two"); } | ^^ error: aborting due to previous error diff --git a/src/test/ui/extenv/extenv-too-many-args.stderr b/src/test/ui/extenv/extenv-too-many-args.stderr index 43695d88eaf68..3351da0d54762 100644 --- a/src/test/ui/extenv/extenv-too-many-args.stderr +++ b/src/test/ui/extenv/extenv-too-many-args.stderr @@ -1,7 +1,7 @@ error: env! takes 1 or 2 arguments --> $DIR/extenv-too-many-args.rs:1:13 | -LL | fn main() { env!("one", "two", "three"); } //~ ERROR: env! takes 1 or 2 arguments +LL | fn main() { env!("one", "two", "three"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/extenv/issue-55897.rs b/src/test/ui/extenv/issue-55897.rs index bd151c8a4e4e7..c3975f6b9255e 100644 --- a/src/test/ui/extenv/issue-55897.rs +++ b/src/test/ui/extenv/issue-55897.rs @@ -12,4 +12,9 @@ mod nonexistent_env { //~^ ERROR environment variable `NON_EXISTENT` not defined } +mod erroneous_literal { + include!(concat!("NON_EXISTENT"suffix, "/data.rs")); + //~^ ERROR suffixes on a string literal are invalid +} + fn main() {} diff --git a/src/test/ui/extenv/issue-55897.stderr b/src/test/ui/extenv/issue-55897.stderr index 4d2e35dff4629..9d68131beabd7 100644 --- a/src/test/ui/extenv/issue-55897.stderr +++ b/src/test/ui/extenv/issue-55897.stderr @@ -4,11 +4,20 @@ error: environment variable `NON_EXISTENT` not defined LL | include!(concat!(env!("NON_EXISTENT"), "/data.rs")); | ^^^^^^^^^^^^^^^^^^^^ +error: suffixes on a string literal are invalid + --> $DIR/issue-55897.rs:16:22 + | +LL | include!(concat!("NON_EXISTENT"suffix, "/data.rs")); + | ^^^^^^^^^^^^^^^^^^^^ invalid suffix `suffix` + error[E0432]: unresolved import `prelude` --> $DIR/issue-55897.rs:1:5 | -LL | use prelude::*; //~ ERROR unresolved import `prelude` - | ^^^^^^^ did you mean `std::prelude`? +LL | use prelude::*; + | ^^^^^^^ + | | + | unresolved import + | help: a similar path exists: `std::prelude` error: cannot determine resolution for the macro `env` --> $DIR/issue-55897.rs:6:22 @@ -18,6 +27,6 @@ LL | include!(concat!(env!("NON_EXISTENT"), "/data.rs")); | = note: import resolution is stuck, try simplifying macro imports -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/extern-prelude-fail.rs b/src/test/ui/extern-prelude-fail.rs new file mode 100644 index 0000000000000..7d387025ad44d --- /dev/null +++ b/src/test/ui/extern-prelude-fail.rs @@ -0,0 +1,9 @@ +// compile-flags:--extern extern_prelude +// aux-build:extern-prelude.rs + +// Extern prelude names are not available by absolute paths + +fn main() { + use extern_prelude::S; //~ ERROR unresolved import `extern_prelude` + let s = ::extern_prelude::S; //~ ERROR failed to resolve +} diff --git a/src/test/ui/extern-prelude-fail.stderr b/src/test/ui/extern-prelude-fail.stderr new file mode 100644 index 0000000000000..9cd56ea7f5b66 --- /dev/null +++ b/src/test/ui/extern-prelude-fail.stderr @@ -0,0 +1,16 @@ +error[E0432]: unresolved import `extern_prelude` + --> $DIR/extern-prelude-fail.rs:7:9 + | +LL | use extern_prelude::S; + | ^^^^^^^^^^^^^^ maybe a missing `extern crate extern_prelude;`? + +error[E0433]: failed to resolve: maybe a missing `extern crate extern_prelude;`? + --> $DIR/extern-prelude-fail.rs:8:15 + | +LL | let s = ::extern_prelude::S; + | ^^^^^^^^^^^^^^ maybe a missing `extern crate extern_prelude;`? + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0432, E0433. +For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/extern-prelude.rs b/src/test/ui/extern-prelude.rs new file mode 100644 index 0000000000000..0e52f2c5158d4 --- /dev/null +++ b/src/test/ui/extern-prelude.rs @@ -0,0 +1,31 @@ +// compile-pass +// compile-flags:--extern extern_prelude --extern Vec +// aux-build:extern-prelude.rs +// aux-build:extern-prelude-vec.rs + +fn basic() { + // It works + let s = extern_prelude::S; + s.external(); +} + +fn shadow_mod() { + // Local module shadows `extern_prelude` from extern prelude + mod extern_prelude { + pub struct S; + + impl S { + pub fn internal(&self) {} + } + } + + let s = extern_prelude::S; + s.internal(); // OK +} + +fn shadow_prelude() { + // Extern prelude shadows standard library prelude + let x = Vec::new(0f32, ()); // OK +} + +fn main() {} diff --git a/src/test/ui/extern/extern-const.fixed b/src/test/ui/extern/extern-const.fixed index fb17934fa9b21..0eec9fb3ee647 100644 --- a/src/test/ui/extern/extern-const.fixed +++ b/src/test/ui/extern/extern-const.fixed @@ -6,7 +6,7 @@ // run-rustfix // ignore-wasm32 no external library to link to. -// compile-flags: -g -Z continue-parse-after-error +// compile-flags: -g #![feature(rustc_private)] extern crate libc; diff --git a/src/test/ui/extern/extern-const.rs b/src/test/ui/extern/extern-const.rs index f2585f5199ea6..ca5d7ddf27e3a 100644 --- a/src/test/ui/extern/extern-const.rs +++ b/src/test/ui/extern/extern-const.rs @@ -6,7 +6,7 @@ // run-rustfix // ignore-wasm32 no external library to link to. -// compile-flags: -g -Z continue-parse-after-error +// compile-flags: -g #![feature(rustc_private)] extern crate libc; diff --git a/src/test/ui/extern/extern-const.stderr b/src/test/ui/extern/extern-const.stderr index 7ebaec0368e3d..77406be2095cf 100644 --- a/src/test/ui/extern/extern-const.stderr +++ b/src/test/ui/extern/extern-const.stderr @@ -1,7 +1,7 @@ error: extern items cannot be `const` --> $DIR/extern-const.rs:15:5 | -LL | const rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const` +LL | const rust_dbg_static_mut: libc::c_int; | ^^^^^ help: try using a static value: `static` error: aborting due to previous error diff --git a/src/test/ui/extern/extern-crate-rename.stderr b/src/test/ui/extern/extern-crate-rename.stderr index 204e7dd64df42..787c11f2a81ab 100644 --- a/src/test/ui/extern/extern-crate-rename.stderr +++ b/src/test/ui/extern/extern-crate-rename.stderr @@ -3,13 +3,13 @@ error[E0259]: the name `m1` is defined multiple times | LL | extern crate m1; | ---------------- previous import of the extern crate `m1` here -LL | extern crate m2 as m1; //~ ERROR is defined multiple times +LL | extern crate m2 as m1; | ^^^^^^^^^^^^^^^^^^^^^^ `m1` reimported here | = note: `m1` must be defined only once in the type namespace of this module help: you can use `as` to change the binding name of the import | -LL | extern crate m2 as other_m1; //~ ERROR is defined multiple times +LL | extern crate m2 as other_m1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/extern/extern-crate-visibility.stderr b/src/test/ui/extern/extern-crate-visibility.stderr index 8baac1a902b87..8bc9f9a67e7ef 100644 --- a/src/test/ui/extern/extern-crate-visibility.stderr +++ b/src/test/ui/extern/extern-crate-visibility.stderr @@ -1,13 +1,13 @@ error[E0603]: extern crate `core` is private --> $DIR/extern-crate-visibility.rs:6:10 | -LL | use foo::core::cell; //~ ERROR extern crate `core` is private +LL | use foo::core::cell; | ^^^^ error[E0603]: extern crate `core` is private --> $DIR/extern-crate-visibility.rs:9:10 | -LL | foo::core::cell::Cell::new(0); //~ ERROR extern crate `core` is private +LL | foo::core::cell::Cell::new(0); | ^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/extern/extern-macro.stderr b/src/test/ui/extern/extern-macro.stderr index d70b6ef79ea8f..5b7a720736a1e 100644 --- a/src/test/ui/extern/extern-macro.stderr +++ b/src/test/ui/extern/extern-macro.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: partially resolved path in a macro --> $DIR/extern-macro.rs:5:13 | -LL | let _ = Foo::bar!(); //~ ERROR failed to resolve: partially resolved path in a macro +LL | let _ = Foo::bar!(); | ^^^^^^^^ partially resolved path in a macro error: aborting due to previous error diff --git a/src/test/ui/extern/extern-main-fn.stderr b/src/test/ui/extern/extern-main-fn.stderr index f2134701deeeb..14f064060a621 100644 --- a/src/test/ui/extern/extern-main-fn.stderr +++ b/src/test/ui/extern/extern-main-fn.stderr @@ -1,7 +1,7 @@ error[E0580]: main function has wrong type --> $DIR/extern-main-fn.rs:1:1 | -LL | extern fn main() {} //~ ERROR: main function has wrong type [E0580] +LL | extern fn main() {} | ^^^^^^^^^^^^^^^^ expected "Rust" fn, found "C" fn | = note: expected type `fn()` diff --git a/src/test/ui/extern/extern-types-distinct-types.stderr b/src/test/ui/extern/extern-types-distinct-types.stderr index b7b6f2cf04aeb..eb632ee395f22 100644 --- a/src/test/ui/extern/extern-types-distinct-types.stderr +++ b/src/test/ui/extern/extern-types-distinct-types.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/extern-types-distinct-types.rs:9:5 | -LL | r //~ ERROR mismatched types +LL | r | ^ expected extern type `B`, found extern type `A` | = note: expected type `&B` diff --git a/src/test/ui/extoption_env-no-args.stderr b/src/test/ui/extoption_env-no-args.stderr index 34fe289cd98a0..386d517a44603 100644 --- a/src/test/ui/extoption_env-no-args.stderr +++ b/src/test/ui/extoption_env-no-args.stderr @@ -1,7 +1,7 @@ error: option_env! takes 1 argument --> $DIR/extoption_env-no-args.rs:1:13 | -LL | fn main() { option_env!(); } //~ ERROR: option_env! takes 1 argument +LL | fn main() { option_env!(); } | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/extoption_env-not-string-literal.stderr b/src/test/ui/extoption_env-not-string-literal.stderr index 8c97b57e0ab99..272751916f5be 100644 --- a/src/test/ui/extoption_env-not-string-literal.stderr +++ b/src/test/ui/extoption_env-not-string-literal.stderr @@ -1,7 +1,7 @@ error: argument must be a string literal --> $DIR/extoption_env-not-string-literal.rs:1:25 | -LL | fn main() { option_env!(10); } //~ ERROR: argument must be a string literal +LL | fn main() { option_env!(10); } | ^^ error: aborting due to previous error diff --git a/src/test/ui/extoption_env-too-many-args.stderr b/src/test/ui/extoption_env-too-many-args.stderr index 6b5ade6daef2c..2ec5594703260 100644 --- a/src/test/ui/extoption_env-too-many-args.stderr +++ b/src/test/ui/extoption_env-too-many-args.stderr @@ -1,7 +1,7 @@ error: option_env! takes 1 argument --> $DIR/extoption_env-too-many-args.rs:1:13 | -LL | fn main() { option_env!("one", "two"); } //~ ERROR: option_env! takes 1 argument +LL | fn main() { option_env!("one", "two"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/fail-no-dead-code-core.stderr b/src/test/ui/fail-no-dead-code-core.stderr index b78aed4568306..2540242f9f68b 100644 --- a/src/test/ui/fail-no-dead-code-core.stderr +++ b/src/test/ui/fail-no-dead-code-core.stderr @@ -1,7 +1,7 @@ error: function is never used: `foo` --> $DIR/fail-no-dead-code-core.rs:7:1 | -LL | fn foo() { //~ ERROR function is never used +LL | fn foo() { | ^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/fail-no-dead-code.stderr b/src/test/ui/fail-no-dead-code.stderr index a435829593110..8babcffaa8dd7 100644 --- a/src/test/ui/fail-no-dead-code.stderr +++ b/src/test/ui/fail-no-dead-code.stderr @@ -1,7 +1,7 @@ error: function is never used: `foo` --> $DIR/fail-no-dead-code.rs:4:1 | -LL | fn foo() { //~ ERROR function is never used +LL | fn foo() { | ^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/fail-simple.stderr b/src/test/ui/fail-simple.stderr index 31be4e2c87a68..26ed918e94d91 100644 --- a/src/test/ui/fail-simple.stderr +++ b/src/test/ui/fail-simple.stderr @@ -1,7 +1,7 @@ error: no rules expected the token `@` --> $DIR/fail-simple.rs:2:12 | -LL | panic!(@); //~ ERROR no rules expected the token `@` +LL | panic!(@); | ^ no rules expected this token in macro call error: aborting due to previous error diff --git a/src/test/ui/fat-ptr-cast.rs b/src/test/ui/fat-ptr-cast.rs index eb419ba2036a4..a0fad583a1645 100644 --- a/src/test/ui/fat-ptr-cast.rs +++ b/src/test/ui/fat-ptr-cast.rs @@ -19,6 +19,6 @@ fn main() { q as *const [i32]; //~ ERROR cannot cast // #21397 - let t: *mut (Trait + 'static) = 0 as *mut _; //~ ERROR casting + let t: *mut (dyn Trait + 'static) = 0 as *mut _; //~ ERROR casting let mut fail: *const str = 0 as *const str; //~ ERROR casting } diff --git a/src/test/ui/fat-ptr-cast.stderr b/src/test/ui/fat-ptr-cast.stderr index 936cdc559bd14..93e1471838f72 100644 --- a/src/test/ui/fat-ptr-cast.stderr +++ b/src/test/ui/fat-ptr-cast.stderr @@ -1,7 +1,7 @@ error[E0606]: casting `&[i32]` as `usize` is invalid --> $DIR/fat-ptr-cast.rs:10:5 | -LL | a as usize; //~ ERROR casting +LL | a as usize; | ^^^^^^^^^^ | = help: cast through a raw pointer first @@ -9,7 +9,7 @@ LL | a as usize; //~ ERROR casting error[E0606]: casting `&[i32]` as `isize` is invalid --> $DIR/fat-ptr-cast.rs:11:5 | -LL | a as isize; //~ ERROR casting +LL | a as isize; | ^^^^^^^^^^ | = help: cast through a raw pointer first @@ -17,7 +17,7 @@ LL | a as isize; //~ ERROR casting error[E0606]: casting `&[i32]` as `i16` is invalid --> $DIR/fat-ptr-cast.rs:12:5 | -LL | a as i16; //~ ERROR casting `&[i32]` as `i16` is invalid +LL | a as i16; | ^^^^^^^^ | = help: cast through a raw pointer first @@ -25,7 +25,7 @@ LL | a as i16; //~ ERROR casting `&[i32]` as `i16` is invalid error[E0606]: casting `&[i32]` as `u32` is invalid --> $DIR/fat-ptr-cast.rs:13:5 | -LL | a as u32; //~ ERROR casting `&[i32]` as `u32` is invalid +LL | a as u32; | ^^^^^^^^ | = help: cast through a raw pointer first @@ -33,7 +33,7 @@ LL | a as u32; //~ ERROR casting `&[i32]` as `u32` is invalid error[E0605]: non-primitive cast: `std::boxed::Box<[i32]>` as `usize` --> $DIR/fat-ptr-cast.rs:14:5 | -LL | b as usize; //~ ERROR non-primitive cast +LL | b as usize; | ^^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait @@ -49,22 +49,22 @@ LL | p as usize; error[E0607]: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]` --> $DIR/fat-ptr-cast.rs:19:5 | -LL | q as *const [i32]; //~ ERROR cannot cast +LL | q as *const [i32]; | ^^^^^^^^^^^^^^^^^ error[E0606]: casting `usize` as `*mut (dyn Trait + 'static)` is invalid - --> $DIR/fat-ptr-cast.rs:22:37 + --> $DIR/fat-ptr-cast.rs:22:41 | -LL | let t: *mut (Trait + 'static) = 0 as *mut _; //~ ERROR casting - | ^^^^^^^^^^^ +LL | let t: *mut (dyn Trait + 'static) = 0 as *mut _; + | ^^^^^^^^^^^ error[E0606]: casting `usize` as `*const str` is invalid --> $DIR/fat-ptr-cast.rs:23:32 | -LL | let mut fail: *const str = 0 as *const str; //~ ERROR casting +LL | let mut fail: *const str = 0 as *const str; | ^^^^^^^^^^^^^^^ error: aborting due to 9 previous errors -Some errors occurred: E0605, E0606, E0607. +Some errors have detailed explanations: E0605, E0606, E0607. For more information about an error, try `rustc --explain E0605`. diff --git a/src/test/ui/feature-gate-optimize_attribute.rs b/src/test/ui/feature-gate-optimize_attribute.rs index c1f7510014187..f252a3c153d7f 100644 --- a/src/test/ui/feature-gate-optimize_attribute.rs +++ b/src/test/ui/feature-gate-optimize_attribute.rs @@ -1,17 +1,17 @@ #![crate_type="rlib"] -#![optimize(speed)] //~ ERROR #54882 +#![optimize(speed)] //~ ERROR #[optimize] attribute is an unstable feature -#[optimize(size)] //~ ERROR #54882 +#[optimize(size)] //~ ERROR #[optimize] attribute is an unstable feature mod module { -#[optimize(size)] //~ ERROR #54882 +#[optimize(size)] //~ ERROR #[optimize] attribute is an unstable feature fn size() {} -#[optimize(speed)] //~ ERROR #54882 +#[optimize(speed)] //~ ERROR #[optimize] attribute is an unstable feature fn speed() {} #[optimize(banana)] -//~^ ERROR #54882 +//~^ ERROR #[optimize] attribute is an unstable feature //~| ERROR E0722 fn not_known() {} diff --git a/src/test/ui/feature-gate-optimize_attribute.stderr b/src/test/ui/feature-gate-optimize_attribute.stderr index ddd4c457d731b..5e7c0a708c1da 100644 --- a/src/test/ui/feature-gate-optimize_attribute.stderr +++ b/src/test/ui/feature-gate-optimize_attribute.stderr @@ -1,41 +1,46 @@ -error[E0658]: #[optimize] attribute is an unstable feature (see issue #54882) +error[E0658]: #[optimize] attribute is an unstable feature --> $DIR/feature-gate-optimize_attribute.rs:7:1 | -LL | #[optimize(size)] //~ ERROR #54882 +LL | #[optimize(size)] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add #![feature(optimize_attribute)] to the crate attributes to enable -error[E0658]: #[optimize] attribute is an unstable feature (see issue #54882) +error[E0658]: #[optimize] attribute is an unstable feature --> $DIR/feature-gate-optimize_attribute.rs:10:1 | -LL | #[optimize(speed)] //~ ERROR #54882 +LL | #[optimize(speed)] | ^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add #![feature(optimize_attribute)] to the crate attributes to enable -error[E0658]: #[optimize] attribute is an unstable feature (see issue #54882) +error[E0658]: #[optimize] attribute is an unstable feature --> $DIR/feature-gate-optimize_attribute.rs:13:1 | LL | #[optimize(banana)] | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add #![feature(optimize_attribute)] to the crate attributes to enable -error[E0658]: #[optimize] attribute is an unstable feature (see issue #54882) +error[E0658]: #[optimize] attribute is an unstable feature --> $DIR/feature-gate-optimize_attribute.rs:4:1 | -LL | #[optimize(size)] //~ ERROR #54882 +LL | #[optimize(size)] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add #![feature(optimize_attribute)] to the crate attributes to enable -error[E0658]: #[optimize] attribute is an unstable feature (see issue #54882) +error[E0658]: #[optimize] attribute is an unstable feature --> $DIR/feature-gate-optimize_attribute.rs:2:1 | -LL | #![optimize(speed)] //~ ERROR #54882 +LL | #![optimize(speed)] | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add #![feature(optimize_attribute)] to the crate attributes to enable error[E0722]: invalid argument @@ -46,5 +51,4 @@ LL | #[optimize(banana)] error: aborting due to 6 previous errors -Some errors occurred: E0658, E0722. -For more information about an error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate/allow-features-empty.rs b/src/test/ui/feature-gate/allow-features-empty.rs new file mode 100644 index 0000000000000..784a1d2697d67 --- /dev/null +++ b/src/test/ui/feature-gate/allow-features-empty.rs @@ -0,0 +1,12 @@ +// compile-flags: -Z allow_features= +// Note: This test uses rustc internal flags because they will never stabilize. + +#![feature(rustc_diagnostic_macros)] //~ ERROR + +#![feature(rustc_const_unstable)] //~ ERROR + +#![feature(lang_items)] //~ ERROR + +#![feature(unknown_stdlib_feature)] //~ ERROR + +fn main() {} diff --git a/src/test/ui/feature-gate/allow-features-empty.stderr b/src/test/ui/feature-gate/allow-features-empty.stderr new file mode 100644 index 0000000000000..ab41422ed05b8 --- /dev/null +++ b/src/test/ui/feature-gate/allow-features-empty.stderr @@ -0,0 +1,27 @@ +error[E0725]: the feature `rustc_diagnostic_macros` is not in the list of allowed features + --> $DIR/allow-features-empty.rs:4:12 + | +LL | #![feature(rustc_diagnostic_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed features + --> $DIR/allow-features-empty.rs:6:12 + | +LL | #![feature(rustc_const_unstable)] + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0725]: the feature `lang_items` is not in the list of allowed features + --> $DIR/allow-features-empty.rs:8:12 + | +LL | #![feature(lang_items)] + | ^^^^^^^^^^ + +error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features + --> $DIR/allow-features-empty.rs:10:12 + | +LL | #![feature(unknown_stdlib_feature)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0725`. diff --git a/src/test/ui/feature-gate/allow-features.rs b/src/test/ui/feature-gate/allow-features.rs new file mode 100644 index 0000000000000..de3439a5b628f --- /dev/null +++ b/src/test/ui/feature-gate/allow-features.rs @@ -0,0 +1,12 @@ +// compile-flags: -Z allow_features=rustc_diagnostic_macros,lang_items +// Note: This test uses rustc internal flags because they will never stabilize. + +#![feature(rustc_diagnostic_macros)] + +#![feature(rustc_const_unstable)] //~ ERROR + +#![feature(lang_items)] + +#![feature(unknown_stdlib_feature)] //~ ERROR + +fn main() {} diff --git a/src/test/ui/feature-gate/allow-features.stderr b/src/test/ui/feature-gate/allow-features.stderr new file mode 100644 index 0000000000000..5b39a6f053bde --- /dev/null +++ b/src/test/ui/feature-gate/allow-features.stderr @@ -0,0 +1,15 @@ +error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed features + --> $DIR/allow-features.rs:6:12 + | +LL | #![feature(rustc_const_unstable)] + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features + --> $DIR/allow-features.rs:10:12 + | +LL | #![feature(unknown_stdlib_feature)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0725`. diff --git a/src/test/ui/feature-gate/await-macro.rs b/src/test/ui/feature-gate/await-macro.rs new file mode 100644 index 0000000000000..291db9ba41370 --- /dev/null +++ b/src/test/ui/feature-gate/await-macro.rs @@ -0,0 +1,12 @@ +// gate-test-await_macro +// edition:2018 + +#![feature(async_await)] + +async fn bar() {} + +async fn foo() { + await!(bar()); //~ ERROR `await!()` macro syntax is unstable, and will soon be removed +} + +fn main() {} diff --git a/src/test/ui/feature-gate/await-macro.stderr b/src/test/ui/feature-gate/await-macro.stderr new file mode 100644 index 0000000000000..699a7a8886e89 --- /dev/null +++ b/src/test/ui/feature-gate/await-macro.stderr @@ -0,0 +1,12 @@ +error[E0658]: `await!()` macro syntax is unstable, and will soon be removed in favor of `.await` syntax. + --> $DIR/await-macro.rs:9:5 + | +LL | await!(bar()); + | ^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/50547 + = help: add #![feature(await_macro)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate/duplicate-features.stderr b/src/test/ui/feature-gate/duplicate-features.stderr index 18adf3a880ace..dbde806f6cc44 100644 --- a/src/test/ui/feature-gate/duplicate-features.stderr +++ b/src/test/ui/feature-gate/duplicate-features.stderr @@ -1,13 +1,13 @@ error[E0636]: the feature `if_let` has already been declared --> $DIR/duplicate-features.rs:7:12 | -LL | #![feature(if_let)] //~ ERROR the feature `if_let` has already been declared +LL | #![feature(if_let)] | ^^^^^^ error[E0636]: the feature `rust1` has already been declared --> $DIR/duplicate-features.rs:4:12 | -LL | #![feature(rust1)] //~ ERROR the feature `rust1` has already been declared +LL | #![feature(rust1)] | ^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gate/feature-gate-c_variadic.rs b/src/test/ui/feature-gate/feature-gate-c_variadic.rs index 5801a2a89e2c1..8b40c36c7db5e 100644 --- a/src/test/ui/feature-gate/feature-gate-c_variadic.rs +++ b/src/test/ui/feature-gate/feature-gate-c_variadic.rs @@ -1,4 +1,4 @@ #![crate_type="lib"] pub unsafe extern "C" fn test(_: i32, ap: ...) { } -//~^ C-varaidic functions are unstable +//~^ C-variadic functions are unstable diff --git a/src/test/ui/feature-gate/feature-gate-c_variadic.stderr b/src/test/ui/feature-gate/feature-gate-c_variadic.stderr index a876e16fdea41..4367dee55a118 100644 --- a/src/test/ui/feature-gate/feature-gate-c_variadic.stderr +++ b/src/test/ui/feature-gate/feature-gate-c_variadic.stderr @@ -1,9 +1,10 @@ -error[E0658]: C-varaidic functions are unstable (see issue #44930) +error[E0658]: C-variadic functions are unstable --> $DIR/feature-gate-c_variadic.rs:3:1 | LL | pub unsafe extern "C" fn test(_: i32, ap: ...) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44930 = help: add #![feature(c_variadic)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr b/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr index 419c21901a02f..4a653265f165a 100644 --- a/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr +++ b/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr @@ -1,5 +1,6 @@ -error[E0658]: kind="static-nobundle" is feature gated (see issue #37403) +error[E0658]: kind="static-nobundle" is feature gated | + = note: for more information, see https://github.com/rust-lang/rust/issues/37403 = help: add #![feature(static_nobundle)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index b1a8cba1676bd..3187b4cae55ee 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -30,8 +30,9 @@ // inputs are handled by each, and (2.) to ease searching for related // occurrences in the source text. +// check-pass + #![warn(unused_attributes, unknown_lints)] -#![allow(stable_features)] // UNGATED WHITE-LISTED BUILT-IN ATTRIBUTES @@ -70,14 +71,12 @@ #![link()] #![link_name = "1900"] #![link_section = "1800"] -#![no_builtins] // Yikes, dupe'd on BUILTIN_ATTRIBUTES list (see "0300") -#![no_mangle] // Yikes, dupe'd on BUILTIN_ATTRIBUTES list (see "3500") // see issue-43106-gating-of-rustc_deprecated.rs #![must_use] // see issue-43106-gating-of-stable.rs // see issue-43106-gating-of-unstable.rs // see issue-43106-gating-of-deprecated.rs -#![windows_subsystem = "1000"] +#![windows_subsystem = "windows"] // UNGATED CRATE-LEVEL BUILT-IN ATTRIBUTES @@ -541,7 +540,7 @@ mod export_name { #[export_name = "2200"] impl S { } } -// Note that this test has a `skip-codegen`, so it +// Note that this is a `check-pass` test, so it // will never invoke the linker. These are here nonetheless to point // out that we allow them at non-crate-level (though I do not know // whether they have the same effect here as at crate-level). @@ -613,17 +612,17 @@ mod must_use { #[must_use] impl S { } } -#[windows_subsystem = "1000"] +#[windows_subsystem = "windows"] mod windows_subsystem { - mod inner { #![windows_subsystem="1000"] } + mod inner { #![windows_subsystem="windows"] } - #[windows_subsystem = "1000"] fn f() { } + #[windows_subsystem = "windows"] fn f() { } - #[windows_subsystem = "1000"] struct S; + #[windows_subsystem = "windows"] struct S; - #[windows_subsystem = "1000"] type T = S; + #[windows_subsystem = "windows"] type T = S; - #[windows_subsystem = "1000"] impl S { } + #[windows_subsystem = "windows"] impl S { } } // BROKEN USES OF CRATE-LEVEL BUILT-IN ATTRIBUTES diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index 4d15ccb300a87..e03b7124ac882 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -1,1182 +1,1186 @@ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:38:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:39:9 | -LL | #![warn(x5400)] //~ WARN unknown lint: `x5400` +LL | #![warn(x5400)] | ^^^^^ | note: lint level defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:33:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:35:28 | LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:39:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:10 | -LL | #![allow(x5300)] //~ WARN unknown lint: `x5300` +LL | #![allow(x5300)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:11 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:41:11 | -LL | #![forbid(x5200)] //~ WARN unknown lint: `x5200` +LL | #![forbid(x5200)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:41:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:42:9 | -LL | #![deny(x5100)] //~ WARN unknown lint: `x5100` +LL | #![deny(x5100)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:101:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:100:8 | LL | #[warn(x5400)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:104:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:103:25 | LL | mod inner { #![warn(x5400)] } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:107:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:106:12 | LL | #[warn(x5400)] fn f() { } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:110:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:109:12 | LL | #[warn(x5400)] struct S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:113:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:112:12 | LL | #[warn(x5400)] type T = S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:115:12 | LL | #[warn(x5400)] impl S { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:120:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:9 | LL | #[allow(x5300)] | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:123:26 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:26 | LL | mod inner { #![allow(x5300)] } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:126:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:13 | LL | #[allow(x5300)] fn f() { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:129:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:13 | LL | #[allow(x5300)] struct S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:132:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:13 | LL | #[allow(x5300)] type T = S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:134:13 | LL | #[allow(x5300)] impl S { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:139:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:10 | LL | #[forbid(x5200)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:142:27 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:27 | LL | mod inner { #![forbid(x5200)] } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:145:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:14 | LL | #[forbid(x5200)] fn f() { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:148:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:14 | LL | #[forbid(x5200)] struct S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:151:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:14 | LL | #[forbid(x5200)] type T = S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:153:14 | LL | #[forbid(x5200)] impl S { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:158:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:8 | LL | #[deny(x5100)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:161:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:25 | LL | mod inner { #![deny(x5100)] } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:164:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:12 | LL | #[deny(x5100)] fn f() { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:167:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:12 | LL | #[deny(x5100)] struct S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:170:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:12 | LL | #[deny(x5100)] type T = S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:172:12 | LL | #[deny(x5100)] impl S { } | ^^^^^ warning: macro_escape is a deprecated synonym for macro_use - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:457:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:456:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ warning: macro_escape is a deprecated synonym for macro_use - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:460:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ | = help: consider an outer attribute, #[macro_use] mod ... +warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:89:12 + | +LL | #![feature(rust1)] + | ^^^^^ + | + = note: #[warn(stable_features)] on by default + warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:181:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:180:5 | LL | #[macro_use] fn f() { } | ^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:33:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:35:9 | LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:184:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:183:5 | LL | #[macro_use] struct S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:187:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:186:5 | LL | #[macro_use] type T = S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:190:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:189:5 | LL | #[macro_use] impl S { } | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:197:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:196:17 | LL | mod inner { #![macro_export] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:200:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:199:5 | LL | #[macro_export] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:203:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:202:5 | LL | #[macro_export] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:206:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:205:5 | LL | #[macro_export] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:209:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:208:5 | LL | #[macro_export] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:194:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:193:1 | LL | #[macro_export] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:215:17 | LL | mod inner { #![plugin_registrar] } | ^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:220:5 | LL | #[plugin_registrar] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:224:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:223:5 | LL | #[plugin_registrar] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:226:5 | LL | #[plugin_registrar] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:213:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:212:1 | LL | #[plugin_registrar] | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:234:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:233:17 | LL | mod inner { #![main] } | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:239:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:238:5 | LL | #[main] struct S; | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:242:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:241:5 | LL | #[main] type T = S; | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:245:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:244:5 | LL | #[main] impl S { } | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:230:1 | LL | #[main] | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:252:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:17 | LL | mod inner { #![start] } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:257:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:256:5 | LL | #[start] struct S; | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:259:5 | LL | #[start] type T = S; | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:263:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:262:5 | LL | #[start] impl S { } | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:249:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:248:1 | LL | #[start] | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:316:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:315:5 | LL | #[path = "3800"] fn f() { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:319:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:318:5 | LL | #[path = "3800"] struct S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:322:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:321:5 | LL | #[path = "3800"] type T = S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:325:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:324:5 | LL | #[path = "3800"] impl S { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:331:17 | LL | mod inner { #![automatically_derived] } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:334:5 | LL | #[automatically_derived] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:337:5 | LL | #[automatically_derived] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:340:5 | LL | #[automatically_derived] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:343:5 | LL | #[automatically_derived] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:329:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:328:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:363:17 | LL | mod inner { #![no_link] } | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:366:5 | LL | #[no_link] fn f() { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:369:5 | LL | #[no_link] struct S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:372:5 | LL | #[no_link]type T = S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:375:5 | LL | #[no_link] impl S { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:360:1 | LL | #[no_link] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:382:17 | LL | mod inner { #![should_panic] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:385:5 | LL | #[should_panic] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:388:5 | LL | #[should_panic] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:391:5 | LL | #[should_panic] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:394:5 | LL | #[should_panic] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:17 | LL | mod inner { #![ignore] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:405:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5 | LL | #[ignore] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:407:5 | LL | #[ignore] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:410:5 | LL | #[ignore] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:413:5 | LL | #[ignore] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:399:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:1 | LL | #[ignore] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:17 | LL | mod inner { #![no_implicit_prelude] } | ^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:424:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 | LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5 | LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:429:5 | LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:432:5 | LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:418:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:1 | LL | #[no_implicit_prelude] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:440:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:443:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:442:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:446:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:445:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:448:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:451:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:437:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:463:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:465:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:468:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:472:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:480:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:480:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:484:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:484:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:491:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:491:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:1 | LL | #[no_std] | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:1 | LL | #[no_std] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:643:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:643:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:647:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:647:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:630:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:630:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:664:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:664:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:668:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:668:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:672:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:672:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:655:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:655:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:689:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:689:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:680:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:680:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:719:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:719:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:723:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:723:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:1 | LL | #[no_main] | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:1 | LL | #[no_main] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:778:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:778:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:769:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:769:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:1 | -LL | #![macro_export] //~ WARN unused attribute +LL | #![macro_export] | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:1 | -LL | #![plugin_registrar] //~ WARN unused attribute +LL | #![plugin_registrar] | ^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:47:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:1 | -LL | #![main] //~ WARN unused attribute +LL | #![main] | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:1 | -LL | #![start] //~ WARN unused attribute +LL | #![start] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:51:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:52:1 | LL | #![repr()] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1 | -LL | #![path = "3800"] //~ WARN unused attribute +LL | #![path = "3800"] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:1 | -LL | #![automatically_derived] //~ WARN unused attribute +LL | #![automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:56:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:57:1 | -LL | #![no_link] //~ WARN unused attribute +LL | #![no_link] | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:58:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1 | -LL | #![should_panic] //~ WARN unused attribute +LL | #![should_panic] | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1 | -LL | #![ignore] //~ WARN unused attribute +LL | #![ignore] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1 | -LL | #![proc_macro_derive()] //~ WARN unused attribute +LL | #![proc_macro_derive()] | ^^^^^^^^^^^^^^^^^^^^^^^ -error: invalid windows subsystem `1000`, only `windows` and `console` are allowed - -error: aborting due to previous error - diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-deprecated.rs b/src/test/ui/feature-gate/issue-43106-gating-of-deprecated.rs index 360d570b65061..5e1d08dd919d0 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-deprecated.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-deprecated.rs @@ -5,8 +5,7 @@ // // (For non-crate-level cases, see issue-43106-gating-of-builtin-attrs.rs) -// compile-pass -// skip-codegen +// check-pass #![deprecated] diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr index 71e8f11ff078d..ef89a887fd44d 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr @@ -13,13 +13,13 @@ error[E0518]: attribute should be applied to function or closure | LL | #[inline] | ^^^^^^^^^ -LL | //~^ ERROR attribute should be applied to function or closure +LL | LL | / mod inline { LL | | mod inner { #![inline] } -LL | | //~^ ERROR attribute should be applied to function or closure +LL | | LL | | ... | -LL | | //~^ ERROR attribute should be applied to function or closure +LL | | LL | | } | |_- not a function or closure diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-macro_use.rs b/src/test/ui/feature-gate/issue-43106-gating-of-macro_use.rs index 725f2e0b9d008..4ced941aad5d0 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-macro_use.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-macro_use.rs @@ -13,7 +13,7 @@ mod macro_escape { //~^ ERROR arguments to macro_use are not allowed here #[macro_use = "2700"] struct S; - //~^ ERROR attribute must be of the form + //~^ ERROR malformed `macro_use` attribute #[macro_use] fn f() { } diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-macro_use.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-macro_use.stderr index 8074528c0e060..665fe2880871e 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-macro_use.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-macro_use.stderr @@ -16,11 +16,17 @@ error: arguments to macro_use are not allowed here LL | mod inner { #![macro_use(my_macro)] } | ^^^^^^^^^^^^^^^^^^^^^^^ -error: attribute must be of the form `#[macro_use]` or `#[macro_use(name1, name2, ...)]` +error: malformed `macro_use` attribute input --> $DIR/issue-43106-gating-of-macro_use.rs:15:5 | LL | #[macro_use = "2700"] struct S; | ^^^^^^^^^^^^^^^^^^^^^ +help: the following are the possible correct uses + | +LL | #[macro_use] struct S; + | ^^^^^^^^^^^^ +LL | #[macro_use(name1, name2, ...)] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/feature-gate/issue-49983-see-issue-0.stderr b/src/test/ui/feature-gate/issue-49983-see-issue-0.stderr index 22ad8c8b77e90..83775322a270f 100644 --- a/src/test/ui/feature-gate/issue-49983-see-issue-0.stderr +++ b/src/test/ui/feature-gate/issue-49983-see-issue-0.stderr @@ -1,7 +1,7 @@ error[E0658]: use of unstable library feature 'ptr_internals': use NonNull instead and consider PhantomData (if you also use #[may_dangle]), Send, and/or Sync --> $DIR/issue-49983-see-issue-0.rs:4:30 | -LL | #[allow(unused_imports)] use core::ptr::Unique; //~ ERROR use of unstable library feature +LL | #[allow(unused_imports)] use core::ptr::Unique; | ^^^^^^^^^^^^^^^^^ | = help: add #![feature(ptr_internals)] to the crate attributes to enable diff --git a/src/test/ui/feature-gate/stability-attribute-consistency.stderr b/src/test/ui/feature-gate/stability-attribute-consistency.stderr index 191b25db3e0fe..9b4b28a3922cb 100644 --- a/src/test/ui/feature-gate/stability-attribute-consistency.stderr +++ b/src/test/ui/feature-gate/stability-attribute-consistency.stderr @@ -12,4 +12,3 @@ LL | #[unstable(feature = "foo", issue = "0")] error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0711`. diff --git a/src/test/ui/feature-gate/unknown-feature.stderr b/src/test/ui/feature-gate/unknown-feature.stderr index 2f8bf20ce4670..e5c05872dbf85 100644 --- a/src/test/ui/feature-gate/unknown-feature.stderr +++ b/src/test/ui/feature-gate/unknown-feature.stderr @@ -1,7 +1,7 @@ error[E0635]: unknown feature `unknown_rust_feature` --> $DIR/unknown-feature.rs:1:12 | -LL | #![feature(unknown_rust_feature)] //~ ERROR unknown feature +LL | #![feature(unknown_rust_feature)] | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/feature-gated-feature-in-macro-arg.stderr b/src/test/ui/feature-gated-feature-in-macro-arg.stderr index b262a6f7005ec..5cbd1023b3cc8 100644 --- a/src/test/ui/feature-gated-feature-in-macro-arg.stderr +++ b/src/test/ui/feature-gated-feature-in-macro-arg.stderr @@ -1,7 +1,7 @@ error[E0658]: intrinsics are subject to change --> $DIR/feature-gated-feature-in-macro-arg.rs:8:9 | -LL | / extern "rust-intrinsic" { //~ ERROR intrinsics are subject to change +LL | / extern "rust-intrinsic" { LL | | fn atomic_fence(); LL | | } | |_________^ diff --git a/src/test/ui/feature-gates/auxiliary/re_rebalance_coherence_lib.rs b/src/test/ui/feature-gates/auxiliary/re_rebalance_coherence_lib.rs index c8d027b25c748..41b9d64d5f71e 100644 --- a/src/test/ui/feature-gates/auxiliary/re_rebalance_coherence_lib.rs +++ b/src/test/ui/feature-gates/auxiliary/re_rebalance_coherence_lib.rs @@ -1,5 +1,4 @@ - -pub trait Backend{} +pub trait Backend {} pub trait SupportsDefaultKeyword {} impl SupportsDefaultKeyword for Postgres {} diff --git a/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr b/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr index 6b3c169c99de9..0eb26ec8291e5 100644 --- a/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr +++ b/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr @@ -1,9 +1,10 @@ -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi-msp430-interrupt.rs:4:1 | LL | extern "msp430-interrupt" fn foo() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-abi.stderr b/src/test/ui/feature-gates/feature-gate-abi.stderr index d528788f7c223..e20ab0cb2f521 100644 --- a/src/test/ui/feature-gates/feature-gate-abi.stderr +++ b/src/test/ui/feature-gates/feature-gate-abi.stderr @@ -1,505 +1,547 @@ error[E0658]: intrinsics are subject to change --> $DIR/feature-gate-abi.rs:12:1 | -LL | extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change +LL | extern "rust-intrinsic" fn f1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:13:1 | -LL | extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental +LL | extern "platform-intrinsic" fn f2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change --> $DIR/feature-gate-abi.rs:14:1 | -LL | extern "vectorcall" fn f3() {} //~ ERROR vectorcall is experimental and subject to change +LL | extern "vectorcall" fn f3() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:15:1 | -LL | extern "rust-call" fn f4() {} //~ ERROR rust-call ABI is subject to change +LL | extern "rust-call" fn f4() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:16:1 | -LL | extern "msp430-interrupt" fn f5() {} //~ ERROR msp430-interrupt ABI is experimental +LL | extern "msp430-interrupt" fn f5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:17:1 | -LL | extern "ptx-kernel" fn f6() {} //~ ERROR PTX ABIs are experimental and subject to change +LL | extern "ptx-kernel" fn f6() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:18:1 | -LL | extern "x86-interrupt" fn f7() {} //~ ERROR x86-interrupt ABI is experimental +LL | extern "x86-interrupt" fn f7() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change --> $DIR/feature-gate-abi.rs:19:1 | -LL | extern "thiscall" fn f8() {} //~ ERROR thiscall is experimental and subject to change +LL | extern "thiscall" fn f8() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:20:1 | -LL | extern "amdgpu-kernel" fn f9() {} //~ ERROR amdgpu-kernel ABI is experimental and subject to change +LL | extern "amdgpu-kernel" fn f9() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error[E0658]: intrinsics are subject to change --> $DIR/feature-gate-abi.rs:24:5 | -LL | extern "rust-intrinsic" fn m1(); //~ ERROR intrinsics are subject to change +LL | extern "rust-intrinsic" fn m1(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:25:5 | -LL | extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental +LL | extern "platform-intrinsic" fn m2(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change --> $DIR/feature-gate-abi.rs:26:5 | -LL | extern "vectorcall" fn m3(); //~ ERROR vectorcall is experimental and subject to change +LL | extern "vectorcall" fn m3(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:27:5 | -LL | extern "rust-call" fn m4(); //~ ERROR rust-call ABI is subject to change +LL | extern "rust-call" fn m4(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:28:5 | -LL | extern "msp430-interrupt" fn m5(); //~ ERROR msp430-interrupt ABI is experimental +LL | extern "msp430-interrupt" fn m5(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:29:5 | -LL | extern "ptx-kernel" fn m6(); //~ ERROR PTX ABIs are experimental and subject to change +LL | extern "ptx-kernel" fn m6(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:30:5 | -LL | extern "x86-interrupt" fn m7(); //~ ERROR x86-interrupt ABI is experimental +LL | extern "x86-interrupt" fn m7(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change --> $DIR/feature-gate-abi.rs:31:5 | -LL | extern "thiscall" fn m8(); //~ ERROR thiscall is experimental and subject to change +LL | extern "thiscall" fn m8(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:32:5 | -LL | extern "amdgpu-kernel" fn m9(); //~ ERROR amdgpu-kernel ABI is experimental and subject to change +LL | extern "amdgpu-kernel" fn m9(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error[E0658]: intrinsics are subject to change --> $DIR/feature-gate-abi.rs:34:5 | -LL | extern "rust-intrinsic" fn dm1() {} //~ ERROR intrinsics are subject to change +LL | extern "rust-intrinsic" fn dm1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:35:5 | -LL | extern "platform-intrinsic" fn dm2() {} //~ ERROR platform intrinsics are experimental +LL | extern "platform-intrinsic" fn dm2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change --> $DIR/feature-gate-abi.rs:36:5 | -LL | extern "vectorcall" fn dm3() {} //~ ERROR vectorcall is experimental and subject to change +LL | extern "vectorcall" fn dm3() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:37:5 | -LL | extern "rust-call" fn dm4() {} //~ ERROR rust-call ABI is subject to change +LL | extern "rust-call" fn dm4() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:38:5 | -LL | extern "msp430-interrupt" fn dm5() {} //~ ERROR msp430-interrupt ABI is experimental +LL | extern "msp430-interrupt" fn dm5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:39:5 | -LL | extern "ptx-kernel" fn dm6() {} //~ ERROR PTX ABIs are experimental and subject to change +LL | extern "ptx-kernel" fn dm6() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:40:5 | -LL | extern "x86-interrupt" fn dm7() {} //~ ERROR x86-interrupt ABI is experimental +LL | extern "x86-interrupt" fn dm7() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change --> $DIR/feature-gate-abi.rs:41:5 | -LL | extern "thiscall" fn dm8() {} //~ ERROR thiscall is experimental and subject to change +LL | extern "thiscall" fn dm8() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:42:5 | -LL | extern "amdgpu-kernel" fn dm9() {} //~ ERROR amdgpu-kernel ABI is experimental and subject to change +LL | extern "amdgpu-kernel" fn dm9() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error[E0658]: intrinsics are subject to change --> $DIR/feature-gate-abi.rs:49:5 | -LL | extern "rust-intrinsic" fn m1() {} //~ ERROR intrinsics are subject to change +LL | extern "rust-intrinsic" fn m1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:50:5 | -LL | extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental +LL | extern "platform-intrinsic" fn m2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change --> $DIR/feature-gate-abi.rs:51:5 | -LL | extern "vectorcall" fn m3() {} //~ ERROR vectorcall is experimental and subject to change +LL | extern "vectorcall" fn m3() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:52:5 | -LL | extern "rust-call" fn m4() {} //~ ERROR rust-call ABI is subject to change +LL | extern "rust-call" fn m4() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:53:5 | -LL | extern "msp430-interrupt" fn m5() {} //~ ERROR msp430-interrupt ABI is experimental +LL | extern "msp430-interrupt" fn m5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:54:5 | -LL | extern "ptx-kernel" fn m6() {} //~ ERROR PTX ABIs are experimental and subject to change +LL | extern "ptx-kernel" fn m6() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:55:5 | -LL | extern "x86-interrupt" fn m7() {} //~ ERROR x86-interrupt ABI is experimental +LL | extern "x86-interrupt" fn m7() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change --> $DIR/feature-gate-abi.rs:56:5 | -LL | extern "thiscall" fn m8() {} //~ ERROR thiscall is experimental and subject to change +LL | extern "thiscall" fn m8() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:57:5 | -LL | extern "amdgpu-kernel" fn m9() {} //~ ERROR amdgpu-kernel ABI is experimental and subject to change +LL | extern "amdgpu-kernel" fn m9() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error[E0658]: intrinsics are subject to change --> $DIR/feature-gate-abi.rs:62:5 | -LL | extern "rust-intrinsic" fn im1() {} //~ ERROR intrinsics are subject to change +LL | extern "rust-intrinsic" fn im1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:63:5 | -LL | extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental +LL | extern "platform-intrinsic" fn im2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change --> $DIR/feature-gate-abi.rs:64:5 | -LL | extern "vectorcall" fn im3() {} //~ ERROR vectorcall is experimental and subject to change +LL | extern "vectorcall" fn im3() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:65:5 | -LL | extern "rust-call" fn im4() {} //~ ERROR rust-call ABI is subject to change +LL | extern "rust-call" fn im4() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:66:5 | -LL | extern "msp430-interrupt" fn im5() {} //~ ERROR msp430-interrupt ABI is experimental +LL | extern "msp430-interrupt" fn im5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:67:5 | -LL | extern "ptx-kernel" fn im6() {} //~ ERROR PTX ABIs are experimental and subject to change +LL | extern "ptx-kernel" fn im6() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:68:5 | -LL | extern "x86-interrupt" fn im7() {} //~ ERROR x86-interrupt ABI is experimental +LL | extern "x86-interrupt" fn im7() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change --> $DIR/feature-gate-abi.rs:69:5 | -LL | extern "thiscall" fn im8() {} //~ ERROR thiscall is experimental and subject to change +LL | extern "thiscall" fn im8() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:70:5 | -LL | extern "amdgpu-kernel" fn im9() {} //~ ERROR amdgpu-kernel ABI is experimental and subject to change +LL | extern "amdgpu-kernel" fn im9() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error[E0658]: intrinsics are subject to change --> $DIR/feature-gate-abi.rs:74:11 | -LL | type A1 = extern "rust-intrinsic" fn(); //~ ERROR intrinsics are subject to change +LL | type A1 = extern "rust-intrinsic" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:75:11 | -LL | type A2 = extern "platform-intrinsic" fn(); //~ ERROR platform intrinsics are experimental +LL | type A2 = extern "platform-intrinsic" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change --> $DIR/feature-gate-abi.rs:76:11 | -LL | type A3 = extern "vectorcall" fn(); //~ ERROR vectorcall is experimental and subject to change +LL | type A3 = extern "vectorcall" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:77:11 | -LL | type A4 = extern "rust-call" fn(); //~ ERROR rust-call ABI is subject to change +LL | type A4 = extern "rust-call" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:78:11 | -LL | type A5 = extern "msp430-interrupt" fn(); //~ ERROR msp430-interrupt ABI is experimental +LL | type A5 = extern "msp430-interrupt" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:79:11 | -LL | type A6 = extern "ptx-kernel" fn (); //~ ERROR PTX ABIs are experimental and subject to change +LL | type A6 = extern "ptx-kernel" fn (); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:80:11 | -LL | type A7 = extern "x86-interrupt" fn(); //~ ERROR x86-interrupt ABI is experimental +LL | type A7 = extern "x86-interrupt" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change --> $DIR/feature-gate-abi.rs:81:11 | -LL | type A8 = extern "thiscall" fn(); //~ ERROR thiscall is experimental and subject to change +LL | type A8 = extern "thiscall" fn(); | ^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:82:11 | -LL | type A9 = extern "amdgpu-kernel" fn(); //~ ERROR amdgpu-kernel ABI is experimental and subject to change +LL | type A9 = extern "amdgpu-kernel" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error[E0658]: intrinsics are subject to change --> $DIR/feature-gate-abi.rs:85:1 | -LL | extern "rust-intrinsic" {} //~ ERROR intrinsics are subject to change +LL | extern "rust-intrinsic" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:86:1 | -LL | extern "platform-intrinsic" {} //~ ERROR platform intrinsics are experimental +LL | extern "platform-intrinsic" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change --> $DIR/feature-gate-abi.rs:87:1 | -LL | extern "vectorcall" {} //~ ERROR vectorcall is experimental and subject to change +LL | extern "vectorcall" {} | ^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:88:1 | -LL | extern "rust-call" {} //~ ERROR rust-call ABI is subject to change +LL | extern "rust-call" {} | ^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:89:1 | -LL | extern "msp430-interrupt" {} //~ ERROR msp430-interrupt ABI is experimental +LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:90:1 | -LL | extern "ptx-kernel" {} //~ ERROR PTX ABIs are experimental and subject to change +LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:91:1 | -LL | extern "x86-interrupt" {} //~ ERROR x86-interrupt ABI is experimental +LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change --> $DIR/feature-gate-abi.rs:92:1 | -LL | extern "thiscall" {} //~ ERROR thiscall is experimental and subject to change +LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:93:1 | -LL | extern "amdgpu-kernel" {} //~ ERROR amdgpu-kernel ABI is experimental and subject to change +LL | extern "amdgpu-kernel" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error: aborting due to 63 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-abi_unadjusted.stderr b/src/test/ui/feature-gates/feature-gate-abi_unadjusted.stderr index 707b6bc75b171..fb32ebb18882d 100644 --- a/src/test/ui/feature-gates/feature-gate-abi_unadjusted.stderr +++ b/src/test/ui/feature-gates/feature-gate-abi_unadjusted.stderr @@ -2,7 +2,7 @@ error[E0658]: unadjusted ABI is an implementation detail and perma-unstable --> $DIR/feature-gate-abi_unadjusted.rs:1:1 | LL | / extern "unadjusted" fn foo() { -LL | | //~^ ERROR: unadjusted ABI is an implementation detail and perma-unstable +LL | | LL | | } | |_^ | diff --git a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs index daa2bb5d6fafc..df7c3ad6b3dc0 100644 --- a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs +++ b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs @@ -5,7 +5,7 @@ use core::alloc::Layout; -#[alloc_error_handler] //~ ERROR #[alloc_error_handler] is an unstable feature (see issue #51540) +#[alloc_error_handler] //~ ERROR #[alloc_error_handler] is an unstable feature fn oom(info: Layout) -> ! { loop {} } diff --git a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr index c20b21fa43d68..cb01b5caf85a1 100644 --- a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr +++ b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[alloc_error_handler] is an unstable feature (see issue #51540) +error[E0658]: #[alloc_error_handler] is an unstable feature --> $DIR/feature-gate-alloc-error-handler.rs:8:1 | -LL | #[alloc_error_handler] //~ ERROR #[alloc_error_handler] is an unstable feature (see issue #51540) +LL | #[alloc_error_handler] | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51540 = help: add #![feature(alloc_error_handler)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-allocator_internals.rs b/src/test/ui/feature-gates/feature-gate-allocator_internals.rs index 2045857e4cb05..a17d17da60713 100644 --- a/src/test/ui/feature-gates/feature-gate-allocator_internals.rs +++ b/src/test/ui/feature-gates/feature-gate-allocator_internals.rs @@ -1,4 +1,3 @@ #![default_lib_allocator] //~ ERROR: attribute is an experimental feature fn main() {} - diff --git a/src/test/ui/feature-gates/feature-gate-allocator_internals.stderr b/src/test/ui/feature-gates/feature-gate-allocator_internals.stderr index 5103b7214f508..c41dca0ec4710 100644 --- a/src/test/ui/feature-gates/feature-gate-allocator_internals.stderr +++ b/src/test/ui/feature-gates/feature-gate-allocator_internals.stderr @@ -1,7 +1,7 @@ error[E0658]: the `#[default_lib_allocator]` attribute is an experimental feature --> $DIR/feature-gate-allocator_internals.rs:1:1 | -LL | #![default_lib_allocator] //~ ERROR: attribute is an experimental feature +LL | #![default_lib_allocator] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(allocator_internals)] to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-allow-internal-unsafe-nested-macro.stderr b/src/test/ui/feature-gates/feature-gate-allow-internal-unsafe-nested-macro.stderr index 1cadfb28214cb..27324d703a8fb 100644 --- a/src/test/ui/feature-gates/feature-gate-allow-internal-unsafe-nested-macro.stderr +++ b/src/test/ui/feature-gates/feature-gate-allow-internal-unsafe-nested-macro.stderr @@ -1,7 +1,7 @@ error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint --> $DIR/feature-gate-allow-internal-unsafe-nested-macro.rs:8:9 | -LL | #[allow_internal_unsafe] //~ ERROR allow_internal_unsafe side-steps +LL | #[allow_internal_unsafe] | ^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | bar!(); diff --git a/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-nested-macro.stderr b/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-nested-macro.stderr index 802c74239d719..76afd217b816f 100644 --- a/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-nested-macro.stderr +++ b/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-nested-macro.stderr @@ -1,7 +1,7 @@ error[E0658]: allow_internal_unstable side-steps feature gating and stability checks --> $DIR/feature-gate-allow-internal-unstable-nested-macro.rs:8:9 | -LL | #[allow_internal_unstable()] //~ ERROR allow_internal_unstable side-steps +LL | #[allow_internal_unstable()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | bar!(); diff --git a/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr b/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr index d619f1e3239ca..d512e56d0a841 100644 --- a/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr +++ b/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr @@ -1,7 +1,7 @@ error[E0658]: allow_internal_unstable side-steps feature gating and stability checks --> $DIR/feature-gate-allow-internal-unstable-struct.rs:4:1 | -LL | #[allow_internal_unstable()] //~ ERROR allow_internal_unstable side-steps +LL | #[allow_internal_unstable()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(allow_internal_unstable)] to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-allow-internal-unstable.stderr b/src/test/ui/feature-gates/feature-gate-allow-internal-unstable.stderr index aa4f6648c4fbd..baba7f4bfb5ae 100644 --- a/src/test/ui/feature-gates/feature-gate-allow-internal-unstable.stderr +++ b/src/test/ui/feature-gates/feature-gate-allow-internal-unstable.stderr @@ -1,7 +1,7 @@ error[E0658]: allow_internal_unstable side-steps feature gating and stability checks --> $DIR/feature-gate-allow-internal-unstable.rs:3:1 | -LL | #[allow_internal_unstable()] //~ ERROR allow_internal_unstable side-steps +LL | #[allow_internal_unstable()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(allow_internal_unstable)] to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-allow_fail.stderr b/src/test/ui/feature-gates/feature-gate-allow_fail.stderr index 18c7ac9c3c926..af7c8de61d5f9 100644 --- a/src/test/ui/feature-gates/feature-gate-allow_fail.stderr +++ b/src/test/ui/feature-gates/feature-gate-allow_fail.stderr @@ -1,9 +1,10 @@ -error[E0658]: allow_fail attribute is currently unstable (see issue #46488) +error[E0658]: allow_fail attribute is currently unstable --> $DIR/feature-gate-allow_fail.rs:3:1 | -LL | #[allow_fail] //~ ERROR allow_fail attribute is currently unstable +LL | #[allow_fail] | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/46488 = help: add #![feature(allow_fail)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr index 8ec3c682850da..8d061a95676fb 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr @@ -1,27 +1,30 @@ -error[E0658]: `Ptr` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) +error[E0658]: `Ptr` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary-self-types.rs:16:18 | -LL | fn foo(self: Ptr); //~ ERROR `Ptr` cannot be used as the type of `self` without +LL | fn foo(self: Ptr); | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44874 = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0658]: `Ptr` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) +error[E0658]: `Ptr` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary-self-types.rs:22:18 | -LL | fn foo(self: Ptr) {} //~ ERROR `Ptr` cannot be used as the type of `self` without +LL | fn foo(self: Ptr) {} | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44874 = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0658]: `std::boxed::Box>` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) +error[E0658]: `std::boxed::Box>` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary-self-types.rs:26:18 | -LL | fn bar(self: Box>) {} //~ ERROR `std::boxed::Box>` cannot be used as the +LL | fn bar(self: Box>) {} | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44874 = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr index f35438f42f403..eda2403e05706 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr @@ -1,27 +1,30 @@ -error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) +error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:9:18 | LL | fn bar(self: *const Self); | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44874 = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) +error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:4:18 | LL | fn foo(self: *const Self) {} | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44874 = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) +error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:14:18 | LL | fn bar(self: *const Self) {} | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44874 = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` diff --git a/src/test/ui/feature-gates/feature-gate-asm.stderr b/src/test/ui/feature-gates/feature-gate-asm.stderr index eee38e12c2aaa..ccaf34f0169fd 100644 --- a/src/test/ui/feature-gates/feature-gate-asm.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm.stderr @@ -1,9 +1,10 @@ -error[E0658]: inline assembly is not stable enough for use and is subject to change (see issue #29722) +error[E0658]: inline assembly is not stable enough for use and is subject to change --> $DIR/feature-gate-asm.rs:3:9 | -LL | asm!(""); //~ ERROR inline assembly is not stable enough +LL | asm!(""); | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29722 = help: add #![feature(asm)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-asm2.stderr b/src/test/ui/feature-gates/feature-gate-asm2.stderr index fc4aa57718ce3..cafe2be9d0bb0 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm2.stderr @@ -1,9 +1,10 @@ -error[E0658]: inline assembly is not stable enough for use and is subject to change (see issue #29722) +error[E0658]: inline assembly is not stable enough for use and is subject to change --> $DIR/feature-gate-asm2.rs:5:26 | -LL | println!("{:?}", asm!("")); //~ ERROR inline assembly is not stable +LL | println!("{:?}", asm!("")); | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29722 = help: add #![feature(asm)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-assoc-type-defaults.stderr b/src/test/ui/feature-gates/feature-gate-assoc-type-defaults.stderr index a23962fe31897..16b37cf29cadd 100644 --- a/src/test/ui/feature-gates/feature-gate-assoc-type-defaults.stderr +++ b/src/test/ui/feature-gates/feature-gate-assoc-type-defaults.stderr @@ -1,9 +1,10 @@ -error[E0658]: associated type defaults are unstable (see issue #29661) +error[E0658]: associated type defaults are unstable --> $DIR/feature-gate-assoc-type-defaults.rs:4:5 | -LL | type Bar = u8; //~ ERROR associated type defaults are unstable +LL | type Bar = u8; | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29661 = help: add #![feature(associated_type_defaults)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs new file mode 100644 index 0000000000000..3d75251e15616 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs @@ -0,0 +1,72 @@ +#![feature(untagged_unions)] + +trait Tr1 { type As1; } +trait Tr2 { type As2; } + +struct S1; +#[derive(Copy, Clone)] +struct S2; +impl Tr1 for S1 { type As1 = S2; } + +trait _Tr3 { + type A: Iterator; + //~^ ERROR associated type bounds are unstable + + type B: Iterator; + //~^ ERROR associated type bounds are unstable +} + +struct _St1> { +//~^ ERROR associated type bounds are unstable + outest: T, + outer: T::As1, + inner: ::As2, +} + +enum _En1> { +//~^ ERROR associated type bounds are unstable + Outest(T), + Outer(T::As1), + Inner(::As2), +} + +union _Un1> { +//~^ ERROR associated type bounds are unstable + outest: T, + outer: T::As1, + inner: ::As2, +} + +type _TaWhere1 where T: Iterator = T; +//~^ ERROR associated type bounds are unstable + +fn _apit(_: impl Tr1) {} +//~^ ERROR associated type bounds are unstable +fn _apit_dyn(_: &dyn Tr1) {} +//~^ ERROR associated type bounds are unstable + +fn _rpit() -> impl Tr1 { S1 } +//~^ ERROR associated type bounds are unstable + +fn _rpit_dyn() -> Box> { Box::new(S1) } +//~^ ERROR associated type bounds are unstable + +const _cdef: impl Tr1 = S1; +//~^ ERROR associated type bounds are unstable +//~| ERROR `impl Trait` not allowed outside of function and inherent method return types [E0562] +// FIXME: uncomment when `impl_trait_in_bindings` feature is fixed. +// const _cdef_dyn: &dyn Tr1 = &S1; + +static _sdef: impl Tr1 = S1; +//~^ ERROR associated type bounds are unstable +//~| ERROR `impl Trait` not allowed outside of function and inherent method return types [E0562] +// FIXME: uncomment when `impl_trait_in_bindings` feature is fixed. +// static _sdef_dyn: &dyn Tr1 = &S1; + +fn main() { + let _: impl Tr1 = S1; + //~^ ERROR associated type bounds are unstable + //~| ERROR `impl Trait` not allowed outside of function and inherent method return types [E0562] + // FIXME: uncomment when `impl_trait_in_bindings` feature is fixed. + // let _: &dyn Tr1 = &S1; +} diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr new file mode 100644 index 0000000000000..702f61262df69 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr @@ -0,0 +1,145 @@ +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:12:22 + | +LL | type A: Iterator; + | ^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add #![feature(associated_type_bounds)] to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:15:22 + | +LL | type B: Iterator; + | ^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add #![feature(associated_type_bounds)] to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:19:20 + | +LL | struct _St1> { + | ^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add #![feature(associated_type_bounds)] to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:26:18 + | +LL | enum _En1> { + | ^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add #![feature(associated_type_bounds)] to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:33:19 + | +LL | union _Un1> { + | ^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add #![feature(associated_type_bounds)] to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:40:37 + | +LL | type _TaWhere1 where T: Iterator = T; + | ^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add #![feature(associated_type_bounds)] to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:43:22 + | +LL | fn _apit(_: impl Tr1) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add #![feature(associated_type_bounds)] to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:45:26 + | +LL | fn _apit_dyn(_: &dyn Tr1) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add #![feature(associated_type_bounds)] to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:48:24 + | +LL | fn _rpit() -> impl Tr1 { S1 } + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add #![feature(associated_type_bounds)] to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:51:31 + | +LL | fn _rpit_dyn() -> Box> { Box::new(S1) } + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add #![feature(associated_type_bounds)] to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:54:23 + | +LL | const _cdef: impl Tr1 = S1; + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add #![feature(associated_type_bounds)] to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:60:24 + | +LL | static _sdef: impl Tr1 = S1; + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add #![feature(associated_type_bounds)] to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/feature-gate-associated_type_bounds.rs:67:21 + | +LL | let _: impl Tr1 = S1; + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52662 + = help: add #![feature(associated_type_bounds)] to the crate attributes to enable + +error[E0562]: `impl Trait` not allowed outside of function and inherent method return types + --> $DIR/feature-gate-associated_type_bounds.rs:54:14 + | +LL | const _cdef: impl Tr1 = S1; + | ^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable + +error[E0562]: `impl Trait` not allowed outside of function and inherent method return types + --> $DIR/feature-gate-associated_type_bounds.rs:60:15 + | +LL | static _sdef: impl Tr1 = S1; + | ^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable + +error[E0562]: `impl Trait` not allowed outside of function and inherent method return types + --> $DIR/feature-gate-associated_type_bounds.rs:67:12 + | +LL | let _: impl Tr1 = S1; + | ^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable + +error: aborting due to 16 previous errors + +Some errors have detailed explanations: E0562, E0658. +For more information about an error, try `rustc --explain E0562`. diff --git a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.rs b/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.rs index b6ab8ae0a9bc7..801aeb82aa266 100644 --- a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.rs +++ b/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.rs @@ -1,7 +1,5 @@ // edition:2015 -#![feature(futures_api)] - async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition //~^ ERROR async fn is unstable diff --git a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr b/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr index 58051153e1f0d..b419f1232dfab 100644 --- a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr +++ b/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr @@ -1,30 +1,31 @@ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/feature-gate-async-await-2015-edition.rs:5:1 + --> $DIR/feature-gate-async-await-2015-edition.rs:3:1 | -LL | async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition +LL | async fn foo() {} | ^^^^^ error[E0422]: cannot find struct, variant or union type `async` in this scope - --> $DIR/feature-gate-async-await-2015-edition.rs:9:13 + --> $DIR/feature-gate-async-await-2015-edition.rs:7:13 | -LL | let _ = async {}; //~ ERROR cannot find struct, variant or union type `async` +LL | let _ = async {}; | ^^^^^ not found in this scope error[E0425]: cannot find value `async` in this scope - --> $DIR/feature-gate-async-await-2015-edition.rs:10:13 + --> $DIR/feature-gate-async-await-2015-edition.rs:8:13 | -LL | let _ = async || { true }; //~ ERROR cannot find value `async` in this scope +LL | let _ = async || { true }; | ^^^^^ not found in this scope -error[E0658]: async fn is unstable (see issue #50547) - --> $DIR/feature-gate-async-await-2015-edition.rs:5:1 +error[E0658]: async fn is unstable + --> $DIR/feature-gate-async-await-2015-edition.rs:3:1 | -LL | async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition +LL | async fn foo() {} | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/50547 = help: add #![feature(async_await)] to the crate attributes to enable error: aborting due to 4 previous errors -Some errors occurred: E0422, E0425, E0658, E0670. +Some errors have detailed explanations: E0422, E0425, E0658, E0670. For more information about an error, try `rustc --explain E0422`. diff --git a/src/test/ui/feature-gates/feature-gate-async-await.rs b/src/test/ui/feature-gates/feature-gate-async-await.rs index 7ee035644bc95..9cfefef4129de 100644 --- a/src/test/ui/feature-gates/feature-gate-async-await.rs +++ b/src/test/ui/feature-gates/feature-gate-async-await.rs @@ -1,6 +1,15 @@ // edition:2018 -#![feature(futures_api)] +struct S; + +impl S { + async fn foo() {} //~ ERROR async fn is unstable +} + +trait T { + async fn foo(); //~ ERROR trait fns cannot be declared `async` + //~^ ERROR async fn is unstable +} async fn foo() {} //~ ERROR async fn is unstable diff --git a/src/test/ui/feature-gates/feature-gate-async-await.stderr b/src/test/ui/feature-gates/feature-gate-async-await.stderr index 3a3165ba3e696..43e41b4545869 100644 --- a/src/test/ui/feature-gates/feature-gate-async-await.stderr +++ b/src/test/ui/feature-gates/feature-gate-async-await.stderr @@ -1,27 +1,54 @@ -error[E0658]: async fn is unstable (see issue #50547) - --> $DIR/feature-gate-async-await.rs:5:1 +error[E0706]: trait fns cannot be declared `async` + --> $DIR/feature-gate-async-await.rs:10:5 | -LL | async fn foo() {} //~ ERROR async fn is unstable +LL | async fn foo(); + | ^^^^^^^^^^^^^^^ + +error[E0658]: async fn is unstable + --> $DIR/feature-gate-async-await.rs:6:5 + | +LL | async fn foo() {} + | ^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/50547 + = help: add #![feature(async_await)] to the crate attributes to enable + +error[E0658]: async fn is unstable + --> $DIR/feature-gate-async-await.rs:10:5 + | +LL | async fn foo(); + | ^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/50547 + = help: add #![feature(async_await)] to the crate attributes to enable + +error[E0658]: async fn is unstable + --> $DIR/feature-gate-async-await.rs:14:1 + | +LL | async fn foo() {} | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/50547 = help: add #![feature(async_await)] to the crate attributes to enable -error[E0658]: async blocks are unstable (see issue #50547) - --> $DIR/feature-gate-async-await.rs:8:13 +error[E0658]: async blocks are unstable + --> $DIR/feature-gate-async-await.rs:17:13 | -LL | let _ = async {}; //~ ERROR async blocks are unstable +LL | let _ = async {}; | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/50547 = help: add #![feature(async_await)] to the crate attributes to enable -error[E0658]: async closures are unstable (see issue #50547) - --> $DIR/feature-gate-async-await.rs:9:13 +error[E0658]: async closures are unstable + --> $DIR/feature-gate-async-await.rs:18:13 | -LL | let _ = async || {}; //~ ERROR async closures are unstable +LL | let _ = async || {}; | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/50547 = help: add #![feature(async_await)] to the crate attributes to enable -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-box-expr.stderr b/src/test/ui/feature-gates/feature-gate-box-expr.stderr index 9ebff2e044c95..9666793313ea4 100644 --- a/src/test/ui/feature-gates/feature-gate-box-expr.stderr +++ b/src/test/ui/feature-gates/feature-gate-box-expr.stderr @@ -1,9 +1,10 @@ -error[E0658]: box expression syntax is experimental; you can call `Box::new` instead. (see issue #49733) +error[E0658]: box expression syntax is experimental; you can call `Box::new` instead --> $DIR/feature-gate-box-expr.rs:12:13 | -LL | let x = box 'c'; //~ ERROR box expression syntax is experimental +LL | let x = box 'c'; | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49733 = help: add #![feature(box_syntax)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-box_patterns.stderr b/src/test/ui/feature-gates/feature-gate-box_patterns.stderr index 1379ba526f5d5..765b929de8a31 100644 --- a/src/test/ui/feature-gates/feature-gate-box_patterns.stderr +++ b/src/test/ui/feature-gates/feature-gate-box_patterns.stderr @@ -1,9 +1,10 @@ -error[E0658]: box pattern syntax is experimental (see issue #29641) +error[E0658]: box pattern syntax is experimental --> $DIR/feature-gate-box_patterns.rs:2:9 | -LL | let box x = Box::new('c'); //~ ERROR box pattern syntax is experimental +LL | let box x = Box::new('c'); | ^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29641 = help: add #![feature(box_patterns)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-box_syntax.rs b/src/test/ui/feature-gates/feature-gate-box_syntax.rs index df0c604b2a809..778660cc0b549 100644 --- a/src/test/ui/feature-gates/feature-gate-box_syntax.rs +++ b/src/test/ui/feature-gates/feature-gate-box_syntax.rs @@ -2,5 +2,5 @@ fn main() { let x = box 3; - //~^ ERROR box expression syntax is experimental; you can call `Box::new` instead. + //~^ ERROR box expression syntax is experimental; you can call `Box::new` instead } diff --git a/src/test/ui/feature-gates/feature-gate-box_syntax.stderr b/src/test/ui/feature-gates/feature-gate-box_syntax.stderr index f144d11d89b23..a9cac7686eace 100644 --- a/src/test/ui/feature-gates/feature-gate-box_syntax.stderr +++ b/src/test/ui/feature-gates/feature-gate-box_syntax.stderr @@ -1,9 +1,10 @@ -error[E0658]: box expression syntax is experimental; you can call `Box::new` instead. (see issue #49733) +error[E0658]: box expression syntax is experimental; you can call `Box::new` instead --> $DIR/feature-gate-box_syntax.rs:4:13 | LL | let x = box 3; | ^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49733 = help: add #![feature(box_syntax)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs index db1a7dad06bc3..827ac3af8f1fa 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs @@ -13,78 +13,78 @@ trait Sized {} trait Copy {} #[cfg(target_has_atomic = "8")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_u8(x: *mut u8) { atomic_xadd(x, 1); atomic_xadd(x, 1); } #[cfg(target_has_atomic = "8")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_i8(x: *mut i8) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "16")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_u16(x: *mut u16) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "16")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_i16(x: *mut i16) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "32")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_u32(x: *mut u32) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "32")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_i32(x: *mut i32) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "64")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_u64(x: *mut u64) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "64")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_i64(x: *mut i64) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "128")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_u128(x: *mut u128) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "128")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_i128(x: *mut i128) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "ptr")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_usize(x: *mut usize) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "ptr")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_isize(x: *mut isize) { atomic_xadd(x, 1); } fn main() { cfg!(target_has_atomic = "8"); - //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) + //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "16"); - //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) + //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "32"); - //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) + //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "64"); - //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) + //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "128"); - //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) + //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "ptr"); - //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) + //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change } diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr index a2d5669bcdcbe..995528efdd375 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr @@ -1,145 +1,163 @@ -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:15:7 | LL | #[cfg(target_has_atomic = "8")] | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:21:7 | LL | #[cfg(target_has_atomic = "8")] | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:26:7 | LL | #[cfg(target_has_atomic = "16")] | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:31:7 | LL | #[cfg(target_has_atomic = "16")] | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:36:7 | LL | #[cfg(target_has_atomic = "32")] | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:41:7 | LL | #[cfg(target_has_atomic = "32")] | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:46:7 | LL | #[cfg(target_has_atomic = "64")] | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:51:7 | LL | #[cfg(target_has_atomic = "64")] | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:56:7 | LL | #[cfg(target_has_atomic = "128")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:61:7 | LL | #[cfg(target_has_atomic = "128")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:66:7 | LL | #[cfg(target_has_atomic = "ptr")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:71:7 | LL | #[cfg(target_has_atomic = "ptr")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:78:10 | LL | cfg!(target_has_atomic = "8"); | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:80:10 | LL | cfg!(target_has_atomic = "16"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:82:10 | LL | cfg!(target_has_atomic = "32"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:84:10 | LL | cfg!(target_has_atomic = "64"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:86:10 | LL | cfg!(target_has_atomic = "128"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:88:10 | LL | cfg!(target_has_atomic = "ptr"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable error: aborting due to 18 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.rs b/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.rs index 54db7500583d1..d44f78d4fab27 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.rs +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.rs @@ -7,7 +7,7 @@ extern crate cfg_target_thread_local; extern { #[cfg_attr(target_thread_local, thread_local)] - //~^ `cfg(target_thread_local)` is experimental and subject to change (see issue #29594) + //~^ `cfg(target_thread_local)` is experimental and subject to change static FOO: u32; } diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.stderr b/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.stderr index 672fb14871a74..3d24b2182537e 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.stderr @@ -1,9 +1,10 @@ -error[E0658]: `cfg(target_thread_local)` is experimental and subject to change (see issue #29594) +error[E0658]: `cfg(target_thread_local)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-thread-local.rs:9:16 | LL | #[cfg_attr(target_thread_local, thread_local)] | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29594 = help: add #![feature(cfg_target_thread_local)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-compiler-builtins.rs b/src/test/ui/feature-gates/feature-gate-compiler-builtins.rs index 10a9749ee5cf8..0d64f1fdcf55e 100644 --- a/src/test/ui/feature-gates/feature-gate-compiler-builtins.rs +++ b/src/test/ui/feature-gates/feature-gate-compiler-builtins.rs @@ -1,4 +1,3 @@ #![compiler_builtins] //~ ERROR the `#[compiler_builtins]` attribute is fn main() {} - diff --git a/src/test/ui/feature-gates/feature-gate-compiler-builtins.stderr b/src/test/ui/feature-gates/feature-gate-compiler-builtins.stderr index 5bda76e2bfebc..278a184bae213 100644 --- a/src/test/ui/feature-gates/feature-gate-compiler-builtins.stderr +++ b/src/test/ui/feature-gates/feature-gate-compiler-builtins.stderr @@ -1,7 +1,7 @@ error[E0658]: the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate which contains compiler-rt intrinsics and will never be stable --> $DIR/feature-gate-compiler-builtins.rs:1:1 | -LL | #![compiler_builtins] //~ ERROR the `#[compiler_builtins]` attribute is +LL | #![compiler_builtins] | ^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(compiler_builtins)] to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents.stderr index d465512527a62..be8c727e2beec 100644 --- a/src/test/ui/feature-gates/feature-gate-concat_idents.stderr +++ b/src/test/ui/feature-gates/feature-gate-concat_idents.stderr @@ -1,17 +1,19 @@ -error[E0658]: `concat_idents` is not stable enough for use and is subject to change (see issue #29599) +error[E0658]: `concat_idents` is not stable enough for use and is subject to change --> $DIR/feature-gate-concat_idents.rs:5:13 | -LL | let a = concat_idents!(X, Y_1); //~ ERROR `concat_idents` is not stable +LL | let a = concat_idents!(X, Y_1); | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add #![feature(concat_idents)] to the crate attributes to enable -error[E0658]: `concat_idents` is not stable enough for use and is subject to change (see issue #29599) +error[E0658]: `concat_idents` is not stable enough for use and is subject to change --> $DIR/feature-gate-concat_idents.rs:6:13 | -LL | let b = concat_idents!(X, Y_2); //~ ERROR `concat_idents` is not stable +LL | let b = concat_idents!(X, Y_2); | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add #![feature(concat_idents)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr index cae409019f7a6..864ee63b201d6 100644 --- a/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr +++ b/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr @@ -1,18 +1,19 @@ -error[E0658]: `concat_idents` is not stable enough for use and is subject to change (see issue #29599) +error[E0658]: `concat_idents` is not stable enough for use and is subject to change --> $DIR/feature-gate-concat_idents2.rs:4:5 | -LL | concat_idents!(a, b); //~ ERROR `concat_idents` is not stable enough +LL | concat_idents!(a, b); | ^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add #![feature(concat_idents)] to the crate attributes to enable error[E0425]: cannot find value `ab` in this scope --> $DIR/feature-gate-concat_idents2.rs:4:5 | -LL | concat_idents!(a, b); //~ ERROR `concat_idents` is not stable enough +LL | concat_idents!(a, b); | ^^^^^^^^^^^^^^^^^^^^^ not found in this scope error: aborting due to 2 previous errors -Some errors occurred: E0425, E0658. +Some errors have detailed explanations: E0425, E0658. For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr index e9b9f240e8cd0..cb8725ab566a2 100644 --- a/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr +++ b/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr @@ -1,17 +1,19 @@ -error[E0658]: `concat_idents` is not stable enough for use and is subject to change (see issue #29599) +error[E0658]: `concat_idents` is not stable enough for use and is subject to change --> $DIR/feature-gate-concat_idents3.rs:7:20 | -LL | assert_eq!(10, concat_idents!(X, Y_1)); //~ ERROR `concat_idents` is not stable +LL | assert_eq!(10, concat_idents!(X, Y_1)); | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add #![feature(concat_idents)] to the crate attributes to enable -error[E0658]: `concat_idents` is not stable enough for use and is subject to change (see issue #29599) +error[E0658]: `concat_idents` is not stable enough for use and is subject to change --> $DIR/feature-gate-concat_idents3.rs:8:20 | -LL | assert_eq!(20, concat_idents!(X, Y_2)); //~ ERROR `concat_idents` is not stable +LL | assert_eq!(20, concat_idents!(X, Y_2)); | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add #![feature(concat_idents)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-const_fn.stderr b/src/test/ui/feature-gates/feature-gate-const_fn.stderr index be5237fbfcf3b..b4d64c2422162 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_fn.stderr @@ -1,38 +1,40 @@ error[E0379]: trait fns cannot be declared const --> $DIR/feature-gate-const_fn.rs:6:5 | -LL | const fn foo() -> u32; //~ ERROR const fn is unstable +LL | const fn foo() -> u32; | ^^^^^ trait fns cannot be const error[E0379]: trait fns cannot be declared const --> $DIR/feature-gate-const_fn.rs:8:5 | -LL | const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable +LL | const fn bar() -> u32 { 0 } | ^^^^^ trait fns cannot be const error[E0379]: trait fns cannot be declared const --> $DIR/feature-gate-const_fn.rs:13:5 | -LL | const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const +LL | const fn foo() -> u32 { 0 } | ^^^^^ trait fns cannot be const -error[E0658]: const fn is unstable (see issue #57563) +error[E0658]: const fn is unstable --> $DIR/feature-gate-const_fn.rs:6:5 | -LL | const fn foo() -> u32; //~ ERROR const fn is unstable +LL | const fn foo() -> u32; | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0658]: const fn is unstable (see issue #57563) +error[E0658]: const fn is unstable --> $DIR/feature-gate-const_fn.rs:8:5 | -LL | const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable +LL | const fn bar() -> u32 { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to 5 previous errors -Some errors occurred: E0379, E0658. +Some errors have detailed explanations: E0379, E0658. For more information about an error, try `rustc --explain E0379`. diff --git a/src/test/ui/feature-gates/feature-gate-const_generics.rs b/src/test/ui/feature-gates/feature-gate-const_generics.rs index 907e00b11e556..fe1ded1c4bbc4 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics.rs +++ b/src/test/ui/feature-gates/feature-gate-const_generics.rs @@ -1,7 +1,5 @@ fn foo() {} //~ ERROR const generics are unstable -//~^ const generics in any position are currently unsupported struct Foo([(); X]); //~ ERROR const generics are unstable -//~^ const generics in any position are currently unsupported fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_generics.stderr b/src/test/ui/feature-gates/feature-gate-const_generics.stderr index 3ab1aa2367f1c..9ea04a1e20435 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_generics.stderr @@ -1,31 +1,21 @@ -error[E0658]: const generics are unstable (see issue #44580) +error[E0658]: const generics are unstable --> $DIR/feature-gate-const_generics.rs:1:14 | -LL | fn foo() {} //~ ERROR const generics are unstable +LL | fn foo() {} | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 = help: add #![feature(const_generics)] to the crate attributes to enable -error[E0658]: const generics are unstable (see issue #44580) - --> $DIR/feature-gate-const_generics.rs:4:18 +error[E0658]: const generics are unstable + --> $DIR/feature-gate-const_generics.rs:3:18 | -LL | struct Foo([(); X]); //~ ERROR const generics are unstable +LL | struct Foo([(); X]); | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 = help: add #![feature(const_generics)] to the crate attributes to enable -error: const generics in any position are currently unsupported - --> $DIR/feature-gate-const_generics.rs:1:14 - | -LL | fn foo() {} //~ ERROR const generics are unstable - | ^ - -error: const generics in any position are currently unsupported - --> $DIR/feature-gate-const_generics.rs:4:18 - | -LL | struct Foo([(); X]); //~ ERROR const generics are unstable - | ^ - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-const_transmute.rs b/src/test/ui/feature-gates/feature-gate-const_transmute.rs index 3c4e6de0b1eaa..6a5bbec77fdb9 100644 --- a/src/test/ui/feature-gates/feature-gate-const_transmute.rs +++ b/src/test/ui/feature-gates/feature-gate-const_transmute.rs @@ -4,6 +4,6 @@ use std::mem; struct Foo(u32); const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) }; -//~^ ERROR The use of std::mem::transmute() is gated in constants (see issue #53605) +//~^ ERROR The use of std::mem::transmute() is gated in constants fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_transmute.stderr b/src/test/ui/feature-gates/feature-gate-const_transmute.stderr index 2e07a9e7ddb17..c3cd313134279 100644 --- a/src/test/ui/feature-gates/feature-gate-const_transmute.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_transmute.stderr @@ -1,9 +1,10 @@ -error[E0658]: The use of std::mem::transmute() is gated in constants (see issue #53605) +error[E0658]: The use of std::mem::transmute() is gated in constants --> $DIR/feature-gate-const_transmute.rs:6:38 | LL | const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) }; | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53605 = help: add #![feature(const_transmute)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.stderr b/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.stderr index 2b28bbca6454f..4e70870ae7222 100644 --- a/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.stderr +++ b/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.stderr @@ -1,9 +1,10 @@ -error[E0658]: `crate` visibility modifier is experimental (see issue #53120) +error[E0658]: `crate` visibility modifier is experimental --> $DIR/feature-gate-crate_visibility_modifier.rs:1:1 | -LL | crate struct Bender { //~ ERROR `crate` visibility modifier is experimental +LL | crate struct Bender { | ^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53120 = help: add #![feature(crate_visibility_modifier)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr index 51fefcfaff725..9b81c38f86b87 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr +++ b/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr @@ -1,105 +1,118 @@ -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:7:3 | -LL | #[fake_attr] //~ ERROR attribute `fake_attr` is currently unknown +LL | #[fake_attr] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:8:3 | -LL | #[fake_attr(100)] //~ ERROR attribute `fake_attr` is currently unknown +LL | #[fake_attr(100)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:9:3 | -LL | #[fake_attr(1, 2, 3)] //~ ERROR attribute `fake_attr` is currently unknown +LL | #[fake_attr(1, 2, 3)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:10:3 | -LL | #[fake_attr("hello")] //~ ERROR attribute `fake_attr` is currently unknown +LL | #[fake_attr("hello")] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:11:3 | -LL | #[fake_attr(name = "hello")] //~ ERROR attribute `fake_attr` is currently unknown +LL | #[fake_attr(name = "hello")] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:12:3 | -LL | #[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR attribute `fake_attr` is currently unknown +LL | #[fake_attr(1, "hi", key = 12, true, false)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:13:3 | -LL | #[fake_attr(key = "hello", val = 10)] //~ ERROR attribute `fake_attr` is currently unknown +LL | #[fake_attr(key = "hello", val = 10)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:14:3 | -LL | #[fake_attr(key("hello"), val(10))] //~ ERROR attribute `fake_attr` is currently unknown +LL | #[fake_attr(key("hello"), val(10))] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:15:3 | -LL | #[fake_attr(enabled = true, disabled = false)] //~ ERROR attribute `fake_attr` is currently unknown +LL | #[fake_attr(enabled = true, disabled = false)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:16:3 | -LL | #[fake_attr(true)] //~ ERROR attribute `fake_attr` is currently unknown +LL | #[fake_attr(true)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:17:3 | -LL | #[fake_attr(pi = 3.14159)] //~ ERROR attribute `fake_attr` is currently unknown +LL | #[fake_attr(pi = 3.14159)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:18:3 | -LL | #[fake_attr(b"hi")] //~ ERROR attribute `fake_attr` is currently unknown +LL | #[fake_attr(b"hi")] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_doc` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_doc` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:19:3 | -LL | #[fake_doc(r"doc")] //~ ERROR attribute `fake_doc` is currently unknown +LL | #[fake_doc(r"doc")] | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 13 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr index 560ceda3486dd..8c8ac1233a046 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr +++ b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr @@ -1,137 +1,154 @@ -error[E0658]: The attribute `lt_struct` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_struct` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:6:13 | LL | struct StLt<#[lt_struct] 'a>(&'a u32); | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_struct` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_struct` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:8:13 | LL | struct StTy<#[ty_struct] I>(I); | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_enum` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_enum` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:11:11 | LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_enum` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_enum` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:13:11 | LL | enum EnTy<#[ty_enum] J> { A(J), B } | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_trait` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_trait` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:16:12 | LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_trait` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_trait` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:18:12 | LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_type` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_type` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:21:11 | LL | type TyLt<#[lt_type] 'd> = &'d u32; | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_type` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_type` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:23:11 | LL | type TyTy<#[ty_type] L> = (L, ); | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_inherent` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_inherent` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:26:6 | LL | impl<#[lt_inherent] 'e> StLt<'e> { } | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_inherent` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_inherent` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:28:6 | LL | impl<#[ty_inherent] M> StTy { } | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_impl_for` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_impl_for` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:31:6 | LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_impl_for` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_impl_for` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:35:6 | LL | impl<#[ty_impl_for] N> TrTy for StTy { | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_fn` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_fn` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:40:9 | LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_fn` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_fn` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:42:9 | LL | fn f_ty<#[ty_fn] O>(_: O) { } | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_meth` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_meth` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:46:13 | LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_meth` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_meth` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:48:13 | LL | fn m_ty<#[ty_meth] P>(_: P) { } | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_hof` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_hof` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:53:19 | LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 17 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr b/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr index 1aec87f066966..e288af54cb270 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr +++ b/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr @@ -1,9 +1,10 @@ -error[E0658]: custom test frameworks are an unstable feature (see issue #50297) +error[E0658]: custom test frameworks are an unstable feature --> $DIR/feature-gate-custom_test_frameworks.rs:1:1 | -LL | #![test_runner(main)] //~ ERROR custom test frameworks are an unstable feature +LL | #![test_runner(main)] | ^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/50297 = help: add #![feature(custom_test_frameworks)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-decl_macro.rs b/src/test/ui/feature-gates/feature-gate-decl_macro.rs index ca0dafd0bf739..d002c5dbbd2db 100644 --- a/src/test/ui/feature-gates/feature-gate-decl_macro.rs +++ b/src/test/ui/feature-gates/feature-gate-decl_macro.rs @@ -1,5 +1,5 @@ #![allow(unused_macros)] -macro m() {} //~ ERROR `macro` is experimental (see issue #39412) +macro m() {} //~ ERROR `macro` is experimental fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-decl_macro.stderr b/src/test/ui/feature-gates/feature-gate-decl_macro.stderr index 01ec3d8b2e21f..808363a0048b7 100644 --- a/src/test/ui/feature-gates/feature-gate-decl_macro.stderr +++ b/src/test/ui/feature-gates/feature-gate-decl_macro.stderr @@ -1,9 +1,10 @@ -error[E0658]: `macro` is experimental (see issue #39412) +error[E0658]: `macro` is experimental --> $DIR/feature-gate-decl_macro.rs:3:1 | -LL | macro m() {} //~ ERROR `macro` is experimental (see issue #39412) +LL | macro m() {} | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/39412 = help: add #![feature(decl_macro)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr index 91845329534e7..be85ae4b13792 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[doc(alias = "...")] is experimental (see issue #50146) +error[E0658]: #[doc(alias = "...")] is experimental --> $DIR/feature-gate-doc_alias.rs:1:1 | -LL | #[doc(alias = "foo")] //~ ERROR: #[doc(alias = "...")] is experimental +LL | #[doc(alias = "foo")] | ^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/50146 = help: add #![feature(doc_alias)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-doc_cfg-cfg-rustdoc.stderr b/src/test/ui/feature-gates/feature-gate-doc_cfg-cfg-rustdoc.stderr index 5bc56adb8adfb..0f84a1b11f06f 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_cfg-cfg-rustdoc.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_cfg-cfg-rustdoc.stderr @@ -1,9 +1,10 @@ -error[E0658]: `cfg(rustdoc)` is experimental and subject to change (see issue #43781) +error[E0658]: `cfg(rustdoc)` is experimental and subject to change --> $DIR/feature-gate-doc_cfg-cfg-rustdoc.rs:1:7 | -LL | #[cfg(rustdoc)] //~ ERROR: `cfg(rustdoc)` is experimental and subject to change +LL | #[cfg(rustdoc)] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/43781 = help: add #![feature(doc_cfg)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr b/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr index 20e3a4dbbca45..9e4aa6c7a0717 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[doc(cfg(...))] is experimental (see issue #43781) +error[E0658]: #[doc(cfg(...))] is experimental --> $DIR/feature-gate-doc_cfg.rs:1:1 | -LL | #[doc(cfg(unix))] //~ ERROR: #[doc(cfg(...))] is experimental +LL | #[doc(cfg(unix))] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/43781 = help: add #![feature(doc_cfg)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr b/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr index 96f165d5a515a..6e4647817219e 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[doc(keyword = "...")] is experimental (see issue #51315) +error[E0658]: #[doc(keyword = "...")] is experimental --> $DIR/feature-gate-doc_keyword.rs:1:1 | -LL | #[doc(keyword = "match")] //~ ERROR: #[doc(keyword = "...")] is experimental +LL | #[doc(keyword = "match")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51315 = help: add #![feature(doc_keyword)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-doc_masked.stderr b/src/test/ui/feature-gates/feature-gate-doc_masked.stderr index 044f21a983365..d778d4d994c86 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_masked.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_masked.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[doc(masked)] is experimental (see issue #44027) +error[E0658]: #[doc(masked)] is experimental --> $DIR/feature-gate-doc_masked.rs:1:1 | -LL | #[doc(masked)] //~ ERROR: #[doc(masked)] is experimental +LL | #[doc(masked)] | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44027 = help: add #![feature(doc_masked)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr b/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr index c7101b436e26b..2bf201f4907ee 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[doc(spotlight)] is experimental (see issue #45040) +error[E0658]: #[doc(spotlight)] is experimental --> $DIR/feature-gate-doc_spotlight.rs:1:1 | -LL | #[doc(spotlight)] //~ ERROR: #[doc(spotlight)] is experimental +LL | #[doc(spotlight)] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/45040 = help: add #![feature(doc_spotlight)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-dropck-ugeh.stderr b/src/test/ui/feature-gates/feature-gate-dropck-ugeh.stderr index bc62fc01b4438..9c7f7b2178d17 100644 --- a/src/test/ui/feature-gates/feature-gate-dropck-ugeh.stderr +++ b/src/test/ui/feature-gates/feature-gate-dropck-ugeh.stderr @@ -1,9 +1,10 @@ -error[E0658]: unsafe_destructor_blind_to_params has been replaced by may_dangle and will be removed in the future (see issue #28498) +error[E0658]: unsafe_destructor_blind_to_params has been replaced by may_dangle and will be removed in the future --> $DIR/feature-gate-dropck-ugeh.rs:16:5 | LL | #[unsafe_destructor_blind_to_params] // This is the UGEH attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/28498 = help: add #![feature(dropck_parametricity)] to the crate attributes to enable warning: use of deprecated attribute `dropck_parametricity`: unsafe_destructor_blind_to_params has been replaced by may_dangle and will be removed in the future. See https://github.com/rust-lang/rust/issues/34761 diff --git a/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr b/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr index 2b43a480c6b94..0eb6da3b125ea 100644 --- a/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr +++ b/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr @@ -1,9 +1,10 @@ -error[E0658]: exclusive range pattern syntax is experimental (see issue #37854) +error[E0658]: exclusive range pattern syntax is experimental --> $DIR/feature-gate-exclusive-range-pattern.rs:3:9 | -LL | 0 .. 3 => {} //~ ERROR exclusive range pattern syntax is experimental +LL | 0 .. 3 => {} | ^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/37854 = help: add #![feature(exclusive_range_pattern)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs index dce8cf46ff9f3..27ff5ace25ddc 100644 --- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs +++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs @@ -6,4 +6,3 @@ fn foo() -> Result { fn main() { let Ok(_x) = foo(); //~ ERROR refutable pattern in local binding } - diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr index cbe6d56775594..dd4ca1f67e330 100644 --- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr +++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr @@ -1,7 +1,7 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered --> $DIR/feature-gate-exhaustive-patterns.rs:7:9 | -LL | let Ok(_x) = foo(); //~ ERROR refutable pattern in local binding +LL | let Ok(_x) = foo(); | ^^^^^^ pattern `Err(_)` not covered error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-existential-type.stderr b/src/test/ui/feature-gates/feature-gate-existential-type.stderr index e83d5cdbde1e6..efaf29c00daee 100644 --- a/src/test/ui/feature-gates/feature-gate-existential-type.stderr +++ b/src/test/ui/feature-gates/feature-gate-existential-type.stderr @@ -1,17 +1,19 @@ -error[E0658]: existential types are unstable (see issue #34511) +error[E0658]: existential types are unstable --> $DIR/feature-gate-existential-type.rs:3:1 | -LL | existential type Foo: std::fmt::Debug; //~ ERROR existential types are unstable +LL | existential type Foo: std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/34511 = help: add #![feature(existential_type)] to the crate attributes to enable -error[E0658]: existential types are unstable (see issue #34511) +error[E0658]: existential types are unstable --> $DIR/feature-gate-existential-type.rs:11:5 | -LL | existential type Baa: std::fmt::Debug; //~ ERROR existential types are unstable +LL | existential type Baa: std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/34511 = help: add #![feature(existential_type)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-extern_absolute_paths.stderr b/src/test/ui/feature-gates/feature-gate-extern_absolute_paths.stderr index 1629547acb1c0..59b28704ddb73 100644 --- a/src/test/ui/feature-gates/feature-gate-extern_absolute_paths.stderr +++ b/src/test/ui/feature-gates/feature-gate-extern_absolute_paths.stderr @@ -1,16 +1,16 @@ error[E0432]: unresolved import `core` --> $DIR/feature-gate-extern_absolute_paths.rs:1:5 | -LL | use core::default; //~ ERROR unresolved import `core` +LL | use core::default; | ^^^^ maybe a missing `extern crate core;`? error[E0433]: failed to resolve: maybe a missing `extern crate core;`? --> $DIR/feature-gate-extern_absolute_paths.rs:4:19 | -LL | let _: u8 = ::core::default::Default(); //~ ERROR failed to resolve +LL | let _: u8 = ::core::default::Default(); | ^^^^ maybe a missing `extern crate core;`? error: aborting due to 2 previous errors -Some errors occurred: E0432, E0433. +Some errors have detailed explanations: E0432, E0433. For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/feature-gates/feature-gate-extern_prelude.stderr b/src/test/ui/feature-gates/feature-gate-extern_prelude.stderr index 7a13f61a27ea7..c15a8b33037fc 100644 --- a/src/test/ui/feature-gates/feature-gate-extern_prelude.stderr +++ b/src/test/ui/feature-gates/feature-gate-extern_prelude.stderr @@ -1,7 +1,7 @@ error: expected one of `!` or `::`, found `-` --> $DIR/feature-gate-extern_prelude.rs:1:4 | -LL | can-only-test-this-in-run-make-fulldeps //~ ERROR expected one of `!` or `::`, found `-` +LL | can-only-test-this-in-run-make-fulldeps | ^ expected one of `!` or `::` here error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-extern_types.stderr b/src/test/ui/feature-gates/feature-gate-extern_types.stderr index 70ba06cde45ce..18c0bae2c4ba2 100644 --- a/src/test/ui/feature-gates/feature-gate-extern_types.stderr +++ b/src/test/ui/feature-gates/feature-gate-extern_types.stderr @@ -1,9 +1,10 @@ -error[E0658]: extern types are experimental (see issue #43467) +error[E0658]: extern types are experimental --> $DIR/feature-gate-extern_types.rs:2:5 | -LL | type T; //~ ERROR extern types are experimental +LL | type T; | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/43467 = help: add #![feature(extern_types)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-external_doc.stderr b/src/test/ui/feature-gates/feature-gate-external_doc.stderr index b5cb9f564a3b6..79e4f8e9b6263 100644 --- a/src/test/ui/feature-gates/feature-gate-external_doc.stderr +++ b/src/test/ui/feature-gates/feature-gate-external_doc.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[doc(include = "...")] is experimental (see issue #44732) +error[E0658]: #[doc(include = "...")] is experimental --> $DIR/feature-gate-external_doc.rs:1:1 | -LL | #[doc(include="asdf.md")] //~ ERROR: #[doc(include = "...")] is experimental +LL | #[doc(include="asdf.md")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44732 = help: add #![feature(external_doc)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-feature-gate.stderr b/src/test/ui/feature-gates/feature-gate-feature-gate.stderr index aee4f7ba47db9..d79404263e452 100644 --- a/src/test/ui/feature-gates/feature-gate-feature-gate.stderr +++ b/src/test/ui/feature-gates/feature-gate-feature-gate.stderr @@ -1,7 +1,7 @@ error: unstable feature --> $DIR/feature-gate-feature-gate.rs:2:12 | -LL | #![feature(intrinsics)] //~ ERROR unstable feature +LL | #![feature(intrinsics)] | ^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.rs b/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.rs index d3df6e5a852b5..d118b7f4ff2b2 100644 --- a/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.rs +++ b/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.rs @@ -1,7 +1,6 @@ -// ignore-tidy-linelength #![crate_type = "lib"] extern { - #[ffi_returns_twice] //~ ERROR the `#[ffi_returns_twice]` attribute is an experimental feature (see issue #58314) + #[ffi_returns_twice] //~ ERROR the `#[ffi_returns_twice]` attribute is an experimental feature pub fn foo(); } diff --git a/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.stderr b/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.stderr index 5c111fe78f48a..72e414eab9248 100644 --- a/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.stderr +++ b/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.stderr @@ -1,9 +1,10 @@ -error[E0658]: the `#[ffi_returns_twice]` attribute is an experimental feature (see issue #58314) - --> $DIR/feature-gate-ffi_returns_twice.rs:5:5 +error[E0658]: the `#[ffi_returns_twice]` attribute is an experimental feature + --> $DIR/feature-gate-ffi_returns_twice.rs:4:5 | -LL | #[ffi_returns_twice] //~ ERROR the `#[ffi_returns_twice]` attribute is an experimental feature (see issue #58314) +LL | #[ffi_returns_twice] | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/58314 = help: add #![feature(ffi_returns_twice)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-format_args_nl.stderr b/src/test/ui/feature-gates/feature-gate-format_args_nl.stderr index 135ec5eb0c094..58d2c790ffe87 100644 --- a/src/test/ui/feature-gates/feature-gate-format_args_nl.stderr +++ b/src/test/ui/feature-gates/feature-gate-format_args_nl.stderr @@ -1,7 +1,7 @@ error[E0658]: `format_args_nl` is only for internal language use and is subject to change --> $DIR/feature-gate-format_args_nl.rs:2:5 | -LL | format_args_nl!(""); //~ ERROR `format_args_nl` is only for internal language use +LL | format_args_nl!(""); | ^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(format_args_nl)] to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-fundamental.stderr b/src/test/ui/feature-gates/feature-gate-fundamental.stderr index 47cf241cc3f96..265b576bc79d3 100644 --- a/src/test/ui/feature-gates/feature-gate-fundamental.stderr +++ b/src/test/ui/feature-gates/feature-gate-fundamental.stderr @@ -1,9 +1,10 @@ -error[E0658]: the `#[fundamental]` attribute is an experimental feature (see issue #29635) +error[E0658]: the `#[fundamental]` attribute is an experimental feature --> $DIR/feature-gate-fundamental.rs:1:1 | -LL | #[fundamental] //~ ERROR the `#[fundamental]` attribute is an experimental feature +LL | #[fundamental] | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29635 = help: add #![feature(fundamental)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-generators.stderr b/src/test/ui/feature-gates/feature-gate-generators.stderr index aea1e00d698a6..d85dc18d03d18 100644 --- a/src/test/ui/feature-gates/feature-gate-generators.stderr +++ b/src/test/ui/feature-gates/feature-gate-generators.stderr @@ -1,18 +1,18 @@ -error[E0658]: yield syntax is experimental (see issue #43122) +error[E0658]: yield syntax is experimental --> $DIR/feature-gate-generators.rs:2:5 | -LL | yield true; //~ ERROR yield syntax is experimental +LL | yield true; | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/43122 = help: add #![feature(generators)] to the crate attributes to enable error[E0627]: yield statement outside of generator literal --> $DIR/feature-gate-generators.rs:2:5 | -LL | yield true; //~ ERROR yield syntax is experimental +LL | yield true; | ^^^^^^^^^^ error: aborting due to 2 previous errors -Some errors occurred: E0627, E0658. -For more information about an error, try `rustc --explain E0627`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr index 8a207c966cdab..d37dd93983c24 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr +++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr @@ -1,57 +1,64 @@ -error[E0658]: generic associated types are unstable (see issue #44265) +error[E0658]: generic associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:4:5 | LL | type Pointer: Deref; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable -error[E0658]: generic associated types are unstable (see issue #44265) +error[E0658]: generic associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:6:5 | LL | type Pointer2: Deref where T: Clone, U: Clone; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable -error[E0658]: where clauses on associated types are unstable (see issue #44265) +error[E0658]: where clauses on associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:6:5 | LL | type Pointer2: Deref where T: Clone, U: Clone; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable -error[E0658]: generic associated types are unstable (see issue #44265) +error[E0658]: generic associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:14:5 | LL | type Pointer = Box; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable -error[E0658]: generic associated types are unstable (see issue #44265) +error[E0658]: generic associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:16:5 | LL | type Pointer2 = Box; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable -error[E0658]: where clauses on associated types are unstable (see issue #44265) +error[E0658]: where clauses on associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:21:5 | LL | type Assoc where Self: Sized; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable -error[E0658]: where clauses on associated types are unstable (see issue #44265) +error[E0658]: where clauses on associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:26:5 | LL | type Assoc where Self: Sized = Foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable error: aborting due to 7 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-global_asm.stderr b/src/test/ui/feature-gates/feature-gate-global_asm.stderr index b698777f6234c..7d8abac399068 100644 --- a/src/test/ui/feature-gates/feature-gate-global_asm.stderr +++ b/src/test/ui/feature-gates/feature-gate-global_asm.stderr @@ -1,9 +1,10 @@ -error[E0658]: `global_asm!` is not stable enough for use and is subject to change (see issue #35119) +error[E0658]: `global_asm!` is not stable enough for use and is subject to change --> $DIR/feature-gate-global_asm.rs:1:1 | -LL | global_asm!(""); //~ ERROR `global_asm!` is not stable +LL | global_asm!(""); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35119 = help: add #![feature(global_asm)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr index 9f60a047cb47e..689a3757343b1 100644 --- a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr +++ b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr @@ -3,13 +3,13 @@ error[E0310]: the parameter type `U` may not live long enough | LL | struct Foo { | - help: consider adding an explicit lifetime bound `U: 'static`... -LL | bar: Bar //~ ERROR the parameter type `U` may not live long enough [E0310] +LL | bar: Bar | ^^^^^^^^^^^ | note: ...so that the type `U` will meet its required lifetime bounds --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:5 | -LL | bar: Bar //~ ERROR the parameter type `U` may not live long enough [E0310] +LL | bar: Bar | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-intrinsics.stderr b/src/test/ui/feature-gates/feature-gate-intrinsics.stderr index 092cb98a2f963..372af6ad92125 100644 --- a/src/test/ui/feature-gates/feature-gate-intrinsics.stderr +++ b/src/test/ui/feature-gates/feature-gate-intrinsics.stderr @@ -1,8 +1,8 @@ error[E0658]: intrinsics are subject to change --> $DIR/feature-gate-intrinsics.rs:1:1 | -LL | / extern "rust-intrinsic" { //~ ERROR intrinsics are subject to change -LL | | fn bar(); //~ ERROR unrecognized intrinsic function: `bar` +LL | / extern "rust-intrinsic" { +LL | | fn bar(); LL | | } | |_^ | @@ -11,7 +11,7 @@ LL | | } error[E0658]: intrinsics are subject to change --> $DIR/feature-gate-intrinsics.rs:5:1 | -LL | extern "rust-intrinsic" fn baz() {} //~ ERROR intrinsics are subject to change +LL | extern "rust-intrinsic" fn baz() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(intrinsics)] to the crate attributes to enable @@ -19,10 +19,10 @@ LL | extern "rust-intrinsic" fn baz() {} //~ ERROR intrinsics are subject to cha error[E0093]: unrecognized intrinsic function: `bar` --> $DIR/feature-gate-intrinsics.rs:2:5 | -LL | fn bar(); //~ ERROR unrecognized intrinsic function: `bar` +LL | fn bar(); | ^^^^^^^^^ unrecognized intrinsic error: aborting due to 3 previous errors -Some errors occurred: E0093, E0658. +Some errors have detailed explanations: E0093, E0658. For more information about an error, try `rustc --explain E0093`. diff --git a/src/test/ui/feature-gates/feature-gate-is_sorted.stderr b/src/test/ui/feature-gates/feature-gate-is_sorted.stderr index 8230c1e3a38dc..1d5998641be8e 100644 --- a/src/test/ui/feature-gates/feature-gate-is_sorted.stderr +++ b/src/test/ui/feature-gates/feature-gate-is_sorted.stderr @@ -1,33 +1,37 @@ -error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485) +error[E0658]: use of unstable library feature 'is_sorted': new API --> $DIR/feature-gate-is_sorted.rs:3:33 | LL | assert!([1, 2, 2, 9].iter().is_sorted()); | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53485 = help: add #![feature(is_sorted)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485) +error[E0658]: use of unstable library feature 'is_sorted': new API --> $DIR/feature-gate-is_sorted.rs:5:39 | LL | assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53485 = help: add #![feature(is_sorted)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485) +error[E0658]: use of unstable library feature 'is_sorted': new API --> $DIR/feature-gate-is_sorted.rs:9:26 | LL | assert!([1, 2, 2, 9].is_sorted()); | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53485 = help: add #![feature(is_sorted)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485) +error[E0658]: use of unstable library feature 'is_sorted': new API --> $DIR/feature-gate-is_sorted.rs:11:32 | LL | assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53485 = help: add #![feature(is_sorted)] to the crate attributes to enable error: aborting due to 4 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-label_break_value.stderr b/src/test/ui/feature-gates/feature-gate-label_break_value.stderr index 347b8a9710eec..40efc4dec4b49 100644 --- a/src/test/ui/feature-gates/feature-gate-label_break_value.stderr +++ b/src/test/ui/feature-gates/feature-gate-label_break_value.stderr @@ -1,9 +1,10 @@ -error[E0658]: labels on blocks are unstable (see issue #48594) +error[E0658]: labels on blocks are unstable --> $DIR/feature-gate-label_break_value.rs:2:5 | -LL | 'a: { //~ ERROR labels on blocks are unstable +LL | 'a: { | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/48594 = help: add #![feature(label_break_value)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-lang-items.stderr b/src/test/ui/feature-gates/feature-gate-lang-items.stderr index ccbb711fe6d43..8fc1197ddfe53 100644 --- a/src/test/ui/feature-gates/feature-gate-lang-items.stderr +++ b/src/test/ui/feature-gates/feature-gate-lang-items.stderr @@ -1,7 +1,7 @@ error[E0658]: language items are subject to change --> $DIR/feature-gate-lang-items.rs:1:1 | -LL | #[lang = "foo"] //~ ERROR language items are subject to change +LL | #[lang = "foo"] | ^^^^^^^^^^^^^^^ | = help: add #![feature(lang_items)] to the crate attributes to enable @@ -9,10 +9,10 @@ LL | #[lang = "foo"] //~ ERROR language items are subject to change error[E0522]: definition of an unknown language item: `foo` --> $DIR/feature-gate-lang-items.rs:1:1 | -LL | #[lang = "foo"] //~ ERROR language items are subject to change +LL | #[lang = "foo"] | ^^^^^^^^^^^^^^^ definition of unknown language item `foo` error: aborting due to 2 previous errors -Some errors occurred: E0522, E0658. +Some errors have detailed explanations: E0522, E0658. For more information about an error, try `rustc --explain E0522`. diff --git a/src/test/ui/feature-gates/feature-gate-link_args.stderr b/src/test/ui/feature-gates/feature-gate-link_args.stderr index c43377fe63081..5267b56253fb0 100644 --- a/src/test/ui/feature-gates/feature-gate-link_args.stderr +++ b/src/test/ui/feature-gates/feature-gate-link_args.stderr @@ -1,25 +1,28 @@ -error[E0658]: the `link_args` attribute is experimental and not portable across platforms, it is recommended to use `#[link(name = "foo")] instead (see issue #29596) +error[E0658]: the `link_args` attribute is experimental and not portable across platforms, it is recommended to use `#[link(name = "foo")] instead --> $DIR/feature-gate-link_args.rs:12:1 | LL | #[link_args = "-l expected_use_case"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29596 = help: add #![feature(link_args)] to the crate attributes to enable -error[E0658]: the `link_args` attribute is experimental and not portable across platforms, it is recommended to use `#[link(name = "foo")] instead (see issue #29596) +error[E0658]: the `link_args` attribute is experimental and not portable across platforms, it is recommended to use `#[link(name = "foo")] instead --> $DIR/feature-gate-link_args.rs:16:1 | LL | #[link_args = "-l unexected_use_on_non_extern_item"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29596 = help: add #![feature(link_args)] to the crate attributes to enable -error[E0658]: the `link_args` attribute is experimental and not portable across platforms, it is recommended to use `#[link(name = "foo")] instead (see issue #29596) +error[E0658]: the `link_args` attribute is experimental and not portable across platforms, it is recommended to use `#[link(name = "foo")] instead --> $DIR/feature-gate-link_args.rs:9:1 | LL | #![link_args = "-l unexpected_use_as_inner_attr_on_mod"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29596 = help: add #![feature(link_args)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-link_cfg.stderr b/src/test/ui/feature-gates/feature-gate-link_cfg.stderr index b5ac5fdb86a7d..1648245d0b812 100644 --- a/src/test/ui/feature-gates/feature-gate-link_cfg.stderr +++ b/src/test/ui/feature-gates/feature-gate-link_cfg.stderr @@ -1,9 +1,10 @@ -error[E0658]: is feature gated (see issue #37406) +error[E0658]: is feature gated --> $DIR/feature-gate-link_cfg.rs:1:1 | LL | #[link(name = "foo", cfg(foo))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/37406 = help: add #![feature(link_cfg)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-link_llvm_intrinsics.stderr b/src/test/ui/feature-gates/feature-gate-link_llvm_intrinsics.stderr index a6cfc99ecd238..903696dc7c2aa 100644 --- a/src/test/ui/feature-gates/feature-gate-link_llvm_intrinsics.stderr +++ b/src/test/ui/feature-gates/feature-gate-link_llvm_intrinsics.stderr @@ -1,9 +1,10 @@ -error[E0658]: linking to LLVM intrinsics is experimental (see issue #29602) +error[E0658]: linking to LLVM intrinsics is experimental --> $DIR/feature-gate-link_llvm_intrinsics.rs:3:5 | LL | fn sqrt(x: f32) -> f32; | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29602 = help: add #![feature(link_llvm_intrinsics)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-linkage.stderr b/src/test/ui/feature-gates/feature-gate-linkage.stderr index 1399a84faf6b2..872c695120a8f 100644 --- a/src/test/ui/feature-gates/feature-gate-linkage.stderr +++ b/src/test/ui/feature-gates/feature-gate-linkage.stderr @@ -1,9 +1,10 @@ -error[E0658]: the `linkage` attribute is experimental and not portable across platforms (see issue #29603) +error[E0658]: the `linkage` attribute is experimental and not portable across platforms --> $DIR/feature-gate-linkage.rs:2:5 | LL | #[linkage = "extern_weak"] static foo: isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29603 = help: add #![feature(linkage)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr b/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr index 6a36d9fd5a8e5..9e814a20d6db6 100644 --- a/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr +++ b/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr @@ -1,9 +1,10 @@ -error[E0658]: lint reasons are experimental (see issue #54503) +error[E0658]: lint reasons are experimental --> $DIR/feature-gate-lint-reasons.rs:1:28 | LL | #![warn(nonstandard_style, reason = "the standard should be respected")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54503 = help: add #![feature(lint_reasons)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-log_syntax.stderr b/src/test/ui/feature-gates/feature-gate-log_syntax.stderr index 33d1f07aa3625..67bd48d3bedf2 100644 --- a/src/test/ui/feature-gates/feature-gate-log_syntax.stderr +++ b/src/test/ui/feature-gates/feature-gate-log_syntax.stderr @@ -1,9 +1,10 @@ -error[E0658]: `log_syntax!` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `log_syntax!` is not stable enough for use and is subject to change --> $DIR/feature-gate-log_syntax.rs:2:5 | -LL | log_syntax!() //~ ERROR `log_syntax!` is not stable enough +LL | log_syntax!() | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(log_syntax)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr b/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr index bdcd922c6e1e4..ff0fa343c84d1 100644 --- a/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr +++ b/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr @@ -1,9 +1,10 @@ -error[E0658]: `log_syntax!` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `log_syntax!` is not stable enough for use and is subject to change --> $DIR/feature-gate-log_syntax2.rs:4:22 | -LL | println!("{:?}", log_syntax!()); //~ ERROR `log_syntax!` is not stable +LL | println!("{:?}", log_syntax!()); | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(log_syntax)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr b/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr index affef0fe7d37f..891ed81107f39 100644 --- a/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr +++ b/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr @@ -1,25 +1,28 @@ -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/feature-gate-macros_in_extern.rs:19:5 | LL | returns_isize!(rust_get_test_int); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/feature-gate-macros_in_extern.rs:21:5 | LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/feature-gate-macros_in_extern.rs:23:5 | LL | emits_nothing!(); | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-main.stderr b/src/test/ui/feature-gates/feature-gate-main.stderr index c92887eded640..4d2d01b49f365 100644 --- a/src/test/ui/feature-gates/feature-gate-main.stderr +++ b/src/test/ui/feature-gates/feature-gate-main.stderr @@ -1,9 +1,10 @@ -error[E0658]: declaration of a nonstandard #[main] function may change over time, for now a top-level `fn main()` is required (see issue #29634) +error[E0658]: declaration of a nonstandard #[main] function may change over time, for now a top-level `fn main()` is required --> $DIR/feature-gate-main.rs:2:1 | -LL | fn foo() {} //~ ERROR: declaration of a nonstandard #[main] function may change over time +LL | fn foo() {} | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29634 = help: add #![feature(main)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs index 2b1b5bba6e1c0..ea06c775b1a60 100644 --- a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs +++ b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs @@ -1,7 +1,7 @@ use std::fmt::{Debug, Display}; #[marker] trait ExplicitMarker {} -//~^ ERROR marker traits is an experimental feature (see issue #29864) +//~^ ERROR marker traits is an experimental feature impl ExplicitMarker for T {} impl ExplicitMarker for T {} diff --git a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr index e916df18b66ce..3ed43b52e5626 100644 --- a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr +++ b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr @@ -1,9 +1,10 @@ -error[E0658]: marker traits is an experimental feature (see issue #29864) +error[E0658]: marker traits is an experimental feature --> $DIR/feature-gate-marker_trait_attr.rs:3:1 | LL | #[marker] trait ExplicitMarker {} | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29864 = help: add #![feature(marker_trait_attr)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-may-dangle.stderr b/src/test/ui/feature-gates/feature-gate-may-dangle.stderr index 6d21147c9eeb3..f93be3ed4e71f 100644 --- a/src/test/ui/feature-gates/feature-gate-may-dangle.stderr +++ b/src/test/ui/feature-gates/feature-gate-may-dangle.stderr @@ -1,9 +1,10 @@ -error[E0658]: may_dangle has unstable semantics and may be removed in the future (see issue #34761) +error[E0658]: may_dangle has unstable semantics and may be removed in the future --> $DIR/feature-gate-may-dangle.rs:6:13 | LL | unsafe impl<#[may_dangle] A> Drop for Pt { | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/34761 = help: add #![feature(dropck_eyepatch)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.rs b/src/test/ui/feature-gates/feature-gate-member-constraints.rs new file mode 100644 index 0000000000000..293a93352e641 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-member-constraints.rs @@ -0,0 +1,9 @@ +trait Trait<'a, 'b> { } +impl Trait<'_, '_> for T {} + +fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> { + //~^ ERROR ambiguous lifetime bound + (x, y) +} + +fn main() { } diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.stderr b/src/test/ui/feature-gates/feature-gate-member-constraints.stderr new file mode 100644 index 0000000000000..3745d5e1c59d6 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-member-constraints.stderr @@ -0,0 +1,10 @@ +error: ambiguous lifetime bound in `impl Trait` + --> $DIR/feature-gate-member-constraints.rs:4:43 + | +LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> { + | ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other + | + = help: add #![feature(member_constraints)] to the crate attributes to enable + +error: aborting due to previous error + diff --git a/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr b/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr index 056e33111f0df..f5155b424b560 100644 --- a/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr +++ b/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr @@ -1,38 +1,40 @@ error[E0379]: trait fns cannot be declared const --> $DIR/feature-gate-min_const_fn.rs:6:5 | -LL | const fn foo() -> u32; //~ ERROR const fn is unstable +LL | const fn foo() -> u32; | ^^^^^ trait fns cannot be const error[E0379]: trait fns cannot be declared const --> $DIR/feature-gate-min_const_fn.rs:8:5 | -LL | const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable +LL | const fn bar() -> u32 { 0 } | ^^^^^ trait fns cannot be const error[E0379]: trait fns cannot be declared const --> $DIR/feature-gate-min_const_fn.rs:13:5 | -LL | const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const +LL | const fn foo() -> u32 { 0 } | ^^^^^ trait fns cannot be const -error[E0658]: const fn is unstable (see issue #57563) +error[E0658]: const fn is unstable --> $DIR/feature-gate-min_const_fn.rs:6:5 | -LL | const fn foo() -> u32; //~ ERROR const fn is unstable +LL | const fn foo() -> u32; | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0658]: const fn is unstable (see issue #57563) +error[E0658]: const fn is unstable --> $DIR/feature-gate-min_const_fn.rs:8:5 | -LL | const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable +LL | const fn bar() -> u32 { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to 5 previous errors -Some errors occurred: E0379, E0658. +Some errors have detailed explanations: E0379, E0658. For more information about an error, try `rustc --explain E0379`. diff --git a/src/test/ui/feature-gates/feature-gate-naked_functions.stderr b/src/test/ui/feature-gates/feature-gate-naked_functions.stderr index 2ff5ef101e062..0ba4d551a6d7d 100644 --- a/src/test/ui/feature-gates/feature-gate-naked_functions.stderr +++ b/src/test/ui/feature-gates/feature-gate-naked_functions.stderr @@ -1,17 +1,19 @@ -error[E0658]: the `#[naked]` attribute is an experimental feature (see issue #32408) +error[E0658]: the `#[naked]` attribute is an experimental feature --> $DIR/feature-gate-naked_functions.rs:1:1 | LL | #[naked] | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32408 = help: add #![feature(naked_functions)] to the crate attributes to enable -error[E0658]: the `#[naked]` attribute is an experimental feature (see issue #32408) +error[E0658]: the `#[naked]` attribute is an experimental feature --> $DIR/feature-gate-naked_functions.rs:5:1 | LL | #[naked] | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32408 = help: add #![feature(naked_functions)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-needs-allocator.rs b/src/test/ui/feature-gates/feature-gate-needs-allocator.rs index a3f91d02b3ee3..08954944bcde7 100644 --- a/src/test/ui/feature-gates/feature-gate-needs-allocator.rs +++ b/src/test/ui/feature-gates/feature-gate-needs-allocator.rs @@ -1,4 +1,3 @@ #![needs_allocator] //~ ERROR the `#[needs_allocator]` attribute is fn main() {} - diff --git a/src/test/ui/feature-gates/feature-gate-needs-allocator.stderr b/src/test/ui/feature-gates/feature-gate-needs-allocator.stderr index 8897f393dbd56..012664e9b6bf9 100644 --- a/src/test/ui/feature-gates/feature-gate-needs-allocator.stderr +++ b/src/test/ui/feature-gates/feature-gate-needs-allocator.stderr @@ -1,7 +1,7 @@ error[E0658]: the `#[needs_allocator]` attribute is an experimental feature --> $DIR/feature-gate-needs-allocator.rs:1:1 | -LL | #![needs_allocator] //~ ERROR the `#[needs_allocator]` attribute is +LL | #![needs_allocator] | ^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(allocator_internals)] to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-never_type.stderr b/src/test/ui/feature-gates/feature-gate-never_type.stderr index c4f8771171e8b..45a6e6de18b02 100644 --- a/src/test/ui/feature-gates/feature-gate-never_type.stderr +++ b/src/test/ui/feature-gates/feature-gate-never_type.stderr @@ -1,41 +1,46 @@ -error[E0658]: The `!` type is experimental (see issue #35121) +error[E0658]: The `!` type is experimental --> $DIR/feature-gate-never_type.rs:7:17 | -LL | type Ma = (u32, !, i32); //~ ERROR type is experimental +LL | type Ma = (u32, !, i32); | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35121 = help: add #![feature(never_type)] to the crate attributes to enable -error[E0658]: The `!` type is experimental (see issue #35121) +error[E0658]: The `!` type is experimental --> $DIR/feature-gate-never_type.rs:8:20 | -LL | type Meeshka = Vec; //~ ERROR type is experimental +LL | type Meeshka = Vec; | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35121 = help: add #![feature(never_type)] to the crate attributes to enable -error[E0658]: The `!` type is experimental (see issue #35121) +error[E0658]: The `!` type is experimental --> $DIR/feature-gate-never_type.rs:9:24 | -LL | type Mow = &'static fn(!) -> !; //~ ERROR type is experimental +LL | type Mow = &'static fn(!) -> !; | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35121 = help: add #![feature(never_type)] to the crate attributes to enable -error[E0658]: The `!` type is experimental (see issue #35121) +error[E0658]: The `!` type is experimental --> $DIR/feature-gate-never_type.rs:10:27 | -LL | type Skwoz = &'static mut !; //~ ERROR type is experimental +LL | type Skwoz = &'static mut !; | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35121 = help: add #![feature(never_type)] to the crate attributes to enable -error[E0658]: The `!` type is experimental (see issue #35121) +error[E0658]: The `!` type is experimental --> $DIR/feature-gate-never_type.rs:13:16 | -LL | type Wub = !; //~ ERROR type is experimental +LL | type Wub = !; | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35121 = help: add #![feature(never_type)] to the crate attributes to enable error: aborting due to 5 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-nll.rs b/src/test/ui/feature-gates/feature-gate-nll.rs index 14c48fb48a09b..ec5eacd162547 100644 --- a/src/test/ui/feature-gates/feature-gate-nll.rs +++ b/src/test/ui/feature-gates/feature-gate-nll.rs @@ -1,18 +1,19 @@ -// This is a test checking that if you do not opt into NLL then you -// should not get the effects of NLL applied to the test. - -// Don't use 2018 edition, since that turns on NLL (migration mode). -// edition:2015 +// There isn't a great way to test feature(nll), since it just disables migrate +// mode and changes some error messages. We just test for migrate mode. // Don't use compare-mode=nll, since that turns on NLL. // ignore-compare-mode-nll +#![feature(rustc_attrs)] -#![allow(dead_code)] - -fn main() { - let mut x = 33; +#[rustc_error] +fn main() { //~ ERROR compilation successful + let mut x = (33, &0); - let p = &x; - x = 22; //~ ERROR cannot assign to `x` because it is borrowed [E0506] + let m = &mut x; + let p = &*x.1; + //~^ WARNING cannot borrow + //~| WARNING this error has been downgraded to a warning + //~| WARNING this warning will become a hard error in the future + m; } diff --git a/src/test/ui/feature-gates/feature-gate-nll.stderr b/src/test/ui/feature-gates/feature-gate-nll.stderr index f7b431d19be7a..37542d52dc2ce 100644 --- a/src/test/ui/feature-gates/feature-gate-nll.stderr +++ b/src/test/ui/feature-gates/feature-gate-nll.stderr @@ -1,11 +1,30 @@ -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/feature-gate-nll.rs:17:5 +warning[E0502]: cannot borrow `*x.1` as immutable because it is also borrowed as mutable + --> $DIR/feature-gate-nll.rs:14:13 | -LL | let p = &x; - | - borrow of `x` occurs here -LL | x = 22; //~ ERROR cannot assign to `x` because it is borrowed [E0506] - | ^^^^^^ assignment to borrowed `x` occurs here +LL | let m = &mut x; + | ------ mutable borrow occurs here +LL | let p = &*x.1; + | ^^^^^ immutable borrow occurs here +... +LL | m; + | - mutable borrow later used here + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + +error: compilation successful + --> $DIR/feature-gate-nll.rs:10:1 + | +LL | / fn main() { +LL | | let mut x = (33, &0); +LL | | +LL | | let m = &mut x; +... | +LL | | m; +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0506`. +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/feature-gates/feature-gate-no-debug-2.stderr b/src/test/ui/feature-gates/feature-gate-no-debug-2.stderr index 9299ac739ce3c..1f8f114d7da53 100644 --- a/src/test/ui/feature-gates/feature-gate-no-debug-2.stderr +++ b/src/test/ui/feature-gates/feature-gate-no-debug-2.stderr @@ -1,7 +1,7 @@ error: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand. See https://github.com/rust-lang/rust/issues/29721 --> $DIR/feature-gate-no-debug-2.rs:4:1 | -LL | #[no_debug] //~ ERROR use of deprecated attribute `no_debug` +LL | #[no_debug] | ^^^^^^^^^^^ help: remove this attribute | note: lint level defined here diff --git a/src/test/ui/feature-gates/feature-gate-no-debug.stderr b/src/test/ui/feature-gates/feature-gate-no-debug.stderr index bdb732af7d2ed..a58a75b70c501 100644 --- a/src/test/ui/feature-gates/feature-gate-no-debug.stderr +++ b/src/test/ui/feature-gates/feature-gate-no-debug.stderr @@ -1,9 +1,10 @@ -error[E0658]: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand (see issue #29721) +error[E0658]: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand --> $DIR/feature-gate-no-debug.rs:3:1 | -LL | #[no_debug] //~ ERROR the `#[no_debug]` attribute was +LL | #[no_debug] | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29721 = help: add #![feature(no_debug)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-no_core.stderr b/src/test/ui/feature-gates/feature-gate-no_core.stderr index 7390051b95da2..e2f0fd68a7ccd 100644 --- a/src/test/ui/feature-gates/feature-gate-no_core.stderr +++ b/src/test/ui/feature-gates/feature-gate-no_core.stderr @@ -1,9 +1,10 @@ -error[E0658]: no_core is experimental (see issue #29639) +error[E0658]: no_core is experimental --> $DIR/feature-gate-no_core.rs:3:1 | -LL | #![no_core] //~ ERROR no_core is experimental +LL | #![no_core] | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29639 = help: add #![feature(no_core)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-non_ascii_idents.stderr b/src/test/ui/feature-gates/feature-gate-non_ascii_idents.stderr index 5c441189ea7cb..1d78b87a3e0cb 100644 --- a/src/test/ui/feature-gates/feature-gate-non_ascii_idents.stderr +++ b/src/test/ui/feature-gates/feature-gate-non_ascii_idents.stderr @@ -1,105 +1,118 @@ -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:1:22 | -LL | extern crate core as bäz; //~ ERROR non-ascii idents +LL | extern crate core as bäz; | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:3:5 | -LL | use föö::bar; //~ ERROR non-ascii idents +LL | use föö::bar; | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:5:5 | -LL | mod föö { //~ ERROR non-ascii idents +LL | mod föö { | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:9:4 | -LL | fn bär( //~ ERROR non-ascii idents +LL | fn bär( | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:10:5 | -LL | bäz: isize //~ ERROR non-ascii idents +LL | bäz: isize | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:12:9 | -LL | let _ö: isize; //~ ERROR non-ascii idents +LL | let _ö: isize; | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:15:10 | -LL | (_ä, _) => {} //~ ERROR non-ascii idents +LL | (_ä, _) => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:19:8 | -LL | struct Föö { //~ ERROR non-ascii idents +LL | struct Föö { | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:20:5 | -LL | föö: isize //~ ERROR non-ascii idents +LL | föö: isize | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:23:6 | -LL | enum Bär { //~ ERROR non-ascii idents +LL | enum Bär { | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:24:5 | -LL | Bäz { //~ ERROR non-ascii idents +LL | Bäz { | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:25:9 | -LL | qüx: isize //~ ERROR non-ascii idents +LL | qüx: isize | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:30:8 | -LL | fn qüx(); //~ ERROR non-ascii idents +LL | fn qüx(); | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable error: aborting due to 13 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs b/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs index b3e2e3d95f536..aca214d1935e2 100644 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs +++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs @@ -1,6 +1,6 @@ //#![feature(non_exhaustive)] -#[non_exhaustive] //~ERROR non exhaustive is an experimental feature (see issue #44109) +#[non_exhaustive] //~ERROR non exhaustive is an experimental feature pub enum NonExhaustiveEnum { Unit, Tuple(u32), diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr b/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr index 9b45e19c3a3c7..fdb1ffb0a9bff 100644 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr +++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr @@ -1,9 +1,10 @@ -error[E0658]: non exhaustive is an experimental feature (see issue #44109) +error[E0658]: non exhaustive is an experimental feature --> $DIR/feature-gate-non_exhaustive.rs:3:1 | -LL | #[non_exhaustive] //~ERROR non exhaustive is an experimental feature (see issue #44109) +LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44109 = help: add #![feature(non_exhaustive)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-omit-gdb-pretty-printer-section.stderr b/src/test/ui/feature-gates/feature-gate-omit-gdb-pretty-printer-section.stderr index de1f03cc170b1..683424899a2dd 100644 --- a/src/test/ui/feature-gates/feature-gate-omit-gdb-pretty-printer-section.stderr +++ b/src/test/ui/feature-gates/feature-gate-omit-gdb-pretty-printer-section.stderr @@ -1,7 +1,7 @@ error[E0658]: the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite --> $DIR/feature-gate-omit-gdb-pretty-printer-section.rs:1:1 | -LL | #[omit_gdb_pretty_printer_section] //~ ERROR the `#[omit_gdb_pretty_printer_section]` attribute is +LL | #[omit_gdb_pretty_printer_section] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(omit_gdb_pretty_printer_section)] to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-on-unimplemented.stderr b/src/test/ui/feature-gates/feature-gate-on-unimplemented.stderr index 32bfb20d5ed3e..044a9a398d681 100644 --- a/src/test/ui/feature-gates/feature-gate-on-unimplemented.stderr +++ b/src/test/ui/feature-gates/feature-gate-on-unimplemented.stderr @@ -1,9 +1,10 @@ -error[E0658]: the `#[rustc_on_unimplemented]` attribute is an experimental feature (see issue #29628) +error[E0658]: the `#[rustc_on_unimplemented]` attribute is an experimental feature --> $DIR/feature-gate-on-unimplemented.rs:4:1 | LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29628 = help: add #![feature(on_unimplemented)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr b/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr index e5d0a8681fb45..baad1627d9cb3 100644 --- a/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr +++ b/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr @@ -1,17 +1,19 @@ -error[E0658]: auto traits are experimental and possibly buggy (see issue #13231) +error[E0658]: auto traits are experimental and possibly buggy --> $DIR/feature-gate-optin-builtin-traits.rs:6:1 | LL | auto trait AutoDummyTrait {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/13231 = help: add #![feature(optin_builtin_traits)] to the crate attributes to enable -error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now (see issue #13231) +error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now --> $DIR/feature-gate-optin-builtin-traits.rs:9:1 | LL | impl !AutoDummyTrait for DummyStruct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/13231 = help: add #![feature(optin_builtin_traits)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-plugin.stderr b/src/test/ui/feature-gates/feature-gate-plugin.stderr index 0feebb6f0e0f7..5ac4120188847 100644 --- a/src/test/ui/feature-gates/feature-gate-plugin.stderr +++ b/src/test/ui/feature-gates/feature-gate-plugin.stderr @@ -1,9 +1,10 @@ -error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597) +error[E0658]: compiler plugins are experimental and possibly buggy --> $DIR/feature-gate-plugin.rs:3:1 | LL | #![plugin(foo)] | ^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29597 = help: add #![feature(plugin)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr b/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr index 6464d4087be08..941a6c49d156c 100644 --- a/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr +++ b/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr @@ -1,9 +1,10 @@ -error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597) +error[E0658]: compiler plugins are experimental and possibly buggy --> $DIR/feature-gate-plugin_registrar.rs:6:1 | LL | pub fn registrar() {} | ^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29597 = help: add #![feature(plugin_registrar)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr index 5806f6f039157..12b796d2e60a1 100644 --- a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr +++ b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr @@ -1,14 +1,18 @@ error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/feature-gate-precise_pointer_size_matching.rs:6:11 | -LL | match 0usize { //~ERROR non-exhaustive patterns: `_` not covered +LL | match 0usize { | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/feature-gate-precise_pointer_size_matching.rs:10:11 | -LL | match 0isize { //~ERROR non-exhaustive patterns: `_` not covered +LL | match 0isize { | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-prelude_import.stderr b/src/test/ui/feature-gates/feature-gate-prelude_import.stderr index c0016d24f35e1..7501954f904ec 100644 --- a/src/test/ui/feature-gates/feature-gate-prelude_import.stderr +++ b/src/test/ui/feature-gates/feature-gate-prelude_import.stderr @@ -1,7 +1,7 @@ error[E0658]: `#[prelude_import]` is for use by rustc only --> $DIR/feature-gate-prelude_import.rs:1:1 | -LL | #[prelude_import] //~ ERROR `#[prelude_import]` is for use by rustc only +LL | #[prelude_import] | ^^^^^^^^^^^^^^^^^ | = help: add #![feature(prelude_import)] to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-profiler-runtime.stderr b/src/test/ui/feature-gates/feature-gate-profiler-runtime.stderr index 2d6ef277572b9..1f335401f9962 100644 --- a/src/test/ui/feature-gates/feature-gate-profiler-runtime.stderr +++ b/src/test/ui/feature-gates/feature-gate-profiler-runtime.stderr @@ -1,7 +1,7 @@ error[E0658]: the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate which contains the profiler runtime and will never be stable --> $DIR/feature-gate-profiler-runtime.rs:1:1 | -LL | #![profiler_runtime] //~ ERROR the `#[profiler_runtime]` attribute is +LL | #![profiler_runtime] | ^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(profiler_runtime)] to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-repr-simd.stderr b/src/test/ui/feature-gates/feature-gate-repr-simd.stderr index 20cdbceeb689a..fd3176e573796 100644 --- a/src/test/ui/feature-gates/feature-gate-repr-simd.stderr +++ b/src/test/ui/feature-gates/feature-gate-repr-simd.stderr @@ -1,28 +1,29 @@ -error[E0658]: SIMD types are experimental and possibly buggy (see issue #27731) +error[E0658]: SIMD types are experimental and possibly buggy --> $DIR/feature-gate-repr-simd.rs:1:1 | -LL | #[repr(simd)] //~ error: SIMD types are experimental +LL | #[repr(simd)] | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(repr_simd)] to the crate attributes to enable -error[E0658]: SIMD types are experimental and possibly buggy (see issue #27731) +error[E0658]: SIMD types are experimental and possibly buggy --> $DIR/feature-gate-repr-simd.rs:5:1 | -LL | #[repr(simd)] //~ error: SIMD types are experimental +LL | #[repr(simd)] | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(repr_simd)] to the crate attributes to enable warning[E0566]: conflicting representation hints --> $DIR/feature-gate-repr-simd.rs:4:8 | -LL | #[repr(C)] //~ warn: conflicting representation hints +LL | #[repr(C)] | ^ -LL | #[repr(simd)] //~ error: SIMD types are experimental +LL | #[repr(simd)] | ^^^^ error: aborting due to 2 previous errors -Some errors occurred: E0566, E0658. -For more information about an error, try `rustc --explain E0566`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-repr128.stderr b/src/test/ui/feature-gates/feature-gate-repr128.stderr index ddd11f6daab94..30433447a2b40 100644 --- a/src/test/ui/feature-gates/feature-gate-repr128.stderr +++ b/src/test/ui/feature-gates/feature-gate-repr128.stderr @@ -1,11 +1,12 @@ -error[E0658]: repr with 128-bit type is unstable (see issue #35118) +error[E0658]: repr with 128-bit type is unstable --> $DIR/feature-gate-repr128.rs:2:1 | -LL | / enum A { //~ ERROR repr with 128-bit type is unstable +LL | / enum A { LL | | A(u64) LL | | } | |_^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35118 = help: add #![feature(repr128)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-repr_align_enum.rs b/src/test/ui/feature-gates/feature-gate-repr_align_enum.rs deleted file mode 100644 index f8e68a9de015b..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-repr_align_enum.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[repr(align(16))] -struct Foo(u64); - -#[repr(align(8))] //~ ERROR `#[repr(align(x))]` on enums is experimental (see issue #57996) -enum Bar { - Foo { foo: Foo }, - Baz, -} - -fn main() { } diff --git a/src/test/ui/feature-gates/feature-gate-repr_align_enum.stderr b/src/test/ui/feature-gates/feature-gate-repr_align_enum.stderr deleted file mode 100644 index 6def25f965118..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-repr_align_enum.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: `#[repr(align(x))]` on enums is experimental (see issue #57996) - --> $DIR/feature-gate-repr_align_enum.rs:4:1 - | -LL | #[repr(align(8))] //~ ERROR `#[repr(align(x))]` on enums is experimental (see issue #57996) - | ^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(repr_align_enum)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.rs b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.rs index f7ff3eb3ac9ff..9f5c92349e06f 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.rs +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.rs @@ -4,5 +4,6 @@ #[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable #[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable +#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and will never be stable fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr index 2b90699384b48..ed98484e13c4a 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr @@ -1,19 +1,30 @@ -error[E0658]: the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable (see issue #29642) +error[E0658]: the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable --> $DIR/feature-gate-rustc-attrs-1.rs:5:1 | -LL | #[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable +LL | #[rustc_variance] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(rustc_attrs)] to the crate attributes to enable -error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable (see issue #29642) +error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable --> $DIR/feature-gate-rustc-attrs-1.rs:6:1 | -LL | #[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable +LL | #[rustc_error] | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(rustc_attrs)] to the crate attributes to enable -error: aborting due to 2 previous errors +error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and will never be stable + --> $DIR/feature-gate-rustc-attrs-1.rs:7:1 + | +LL | #[rustc_nonnull_optimization_guaranteed] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(rustc_attrs)] to the crate attributes to enable + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr index 40e6d6d925679..3c823c8d4e25f 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr @@ -1,9 +1,10 @@ -error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics (see issue #29642) +error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics --> $DIR/feature-gate-rustc-attrs.rs:3:3 | LL | #[rustc_foo] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(rustc_attrs)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs b/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs index a85f2f4ad30ea..6961e68744ffe 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs +++ b/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs @@ -10,4 +10,3 @@ pub const fn bazinga() {} fn main() { } - diff --git a/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr b/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr index 52d9b8db2fbe7..8f584c333ac71 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr +++ b/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr @@ -1,7 +1,7 @@ error[E0658]: the `#[rustc_const_unstable]` attribute is an internal feature --> $DIR/feature-gate-rustc_const_unstable.rs:8:1 | -LL | #[rustc_const_unstable(feature="fzzzzzt")] //~ERROR internal feature +LL | #[rustc_const_unstable(feature="fzzzzzt")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(rustc_const_unstable)] to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-sanitizer-runtime.stderr b/src/test/ui/feature-gates/feature-gate-sanitizer-runtime.stderr index 37e9b35c0ba78..71d9890cb2c33 100644 --- a/src/test/ui/feature-gates/feature-gate-sanitizer-runtime.stderr +++ b/src/test/ui/feature-gates/feature-gate-sanitizer-runtime.stderr @@ -1,7 +1,7 @@ error[E0658]: the `#[sanitizer_runtime]` attribute is used to identify crates that contain the runtime of a sanitizer and will never be stable --> $DIR/feature-gate-sanitizer-runtime.rs:1:1 | -LL | #![sanitizer_runtime] //~ ERROR the `#[sanitizer_runtime]` attribute is +LL | #![sanitizer_runtime] | ^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(sanitizer_runtime)] to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-simd-ffi.stderr b/src/test/ui/feature-gates/feature-gate-simd-ffi.stderr index 01005138a6077..11e095fef3da9 100644 --- a/src/test/ui/feature-gates/feature-gate-simd-ffi.stderr +++ b/src/test/ui/feature-gates/feature-gate-simd-ffi.stderr @@ -1,7 +1,7 @@ error: use of SIMD type `LocalSimd` in FFI is highly experimental and may result in invalid code --> $DIR/feature-gate-simd-ffi.rs:9:17 | -LL | fn baz() -> LocalSimd; //~ ERROR use of SIMD type +LL | fn baz() -> LocalSimd; | ^^^^^^^^^ | = help: add #![feature(simd_ffi)] to the crate attributes to enable @@ -9,7 +9,7 @@ LL | fn baz() -> LocalSimd; //~ ERROR use of SIMD type error: use of SIMD type `LocalSimd` in FFI is highly experimental and may result in invalid code --> $DIR/feature-gate-simd-ffi.rs:10:15 | -LL | fn qux(x: LocalSimd); //~ ERROR use of SIMD type +LL | fn qux(x: LocalSimd); | ^^^^^^^^^ | = help: add #![feature(simd_ffi)] to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-simd.stderr b/src/test/ui/feature-gates/feature-gate-simd.stderr index ad5ffa5e7852b..1686a8530fe0e 100644 --- a/src/test/ui/feature-gates/feature-gate-simd.stderr +++ b/src/test/ui/feature-gates/feature-gate-simd.stderr @@ -1,9 +1,10 @@ -error[E0658]: SIMD types are experimental and possibly buggy (see issue #27731) +error[E0658]: SIMD types are experimental and possibly buggy --> $DIR/feature-gate-simd.rs:3:1 | -LL | #[repr(simd)] //~ ERROR SIMD types are experimental +LL | #[repr(simd)] | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(repr_simd)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-slice-patterns.stderr b/src/test/ui/feature-gates/feature-gate-slice-patterns.stderr index 65dec6e10990b..fe3c1e0afdd6b 100644 --- a/src/test/ui/feature-gates/feature-gate-slice-patterns.stderr +++ b/src/test/ui/feature-gates/feature-gate-slice-patterns.stderr @@ -1,49 +1,55 @@ -error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) +error[E0658]: syntax for subslices in slice patterns is not yet stabilized --> $DIR/feature-gate-slice-patterns.rs:6:16 | -LL | [1, 2, ..] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized +LL | [1, 2, ..] => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23121 = help: add #![feature(slice_patterns)] to the crate attributes to enable -error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) +error[E0658]: syntax for subslices in slice patterns is not yet stabilized --> $DIR/feature-gate-slice-patterns.rs:7:13 | -LL | [1, .., 5] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized +LL | [1, .., 5] => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23121 = help: add #![feature(slice_patterns)] to the crate attributes to enable -error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) +error[E0658]: syntax for subslices in slice patterns is not yet stabilized --> $DIR/feature-gate-slice-patterns.rs:8:10 | -LL | [.., 4, 5] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized +LL | [.., 4, 5] => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23121 = help: add #![feature(slice_patterns)] to the crate attributes to enable -error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) +error[E0658]: syntax for subslices in slice patterns is not yet stabilized --> $DIR/feature-gate-slice-patterns.rs:13:11 | -LL | [ xs.., 4, 5 ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized +LL | [ xs.., 4, 5 ] => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23121 = help: add #![feature(slice_patterns)] to the crate attributes to enable -error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) +error[E0658]: syntax for subslices in slice patterns is not yet stabilized --> $DIR/feature-gate-slice-patterns.rs:14:14 | -LL | [ 1, xs.., 5 ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized +LL | [ 1, xs.., 5 ] => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23121 = help: add #![feature(slice_patterns)] to the crate attributes to enable -error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) +error[E0658]: syntax for subslices in slice patterns is not yet stabilized --> $DIR/feature-gate-slice-patterns.rs:15:17 | -LL | [ 1, 2, xs.. ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized +LL | [ 1, 2, xs.. ] => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23121 = help: add #![feature(slice_patterns)] to the crate attributes to enable error: aborting due to 6 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-start.stderr b/src/test/ui/feature-gates/feature-gate-start.stderr index d39e5f3555537..fbe64ea130d96 100644 --- a/src/test/ui/feature-gates/feature-gate-start.stderr +++ b/src/test/ui/feature-gates/feature-gate-start.stderr @@ -1,9 +1,10 @@ -error[E0658]: a #[start] function is an experimental feature whose signature may change over time (see issue #29633) +error[E0658]: a #[start] function is an experimental feature whose signature may change over time --> $DIR/feature-gate-start.rs:2:1 | LL | fn foo(_: isize, _: *const *const u8) -> isize { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29633 = help: add #![feature(start)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr index 2e80275f3f7b3..7d5ed74abd102 100644 --- a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr +++ b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr @@ -1,9 +1,10 @@ -error[E0658]: kind="static-nobundle" is feature gated (see issue #37403) +error[E0658]: kind="static-nobundle" is feature gated --> $DIR/feature-gate-static-nobundle.rs:1:1 | LL | #[link(name="foo", kind="static-nobundle")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/37403 = help: add #![feature(static_nobundle)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.rs b/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.rs index 3e5b6260d74bc..f213e8933bf57 100644 --- a/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.rs +++ b/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.rs @@ -1,4 +1,4 @@ const X: i32 = #[allow(dead_code)] 8; -//~^ ERROR attributes on expressions are experimental. (see issue #15701) +//~^ ERROR attributes on expressions are experimental fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr b/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr index 4318edd9230a0..bbf0f66ca543a 100644 --- a/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr +++ b/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr @@ -1,9 +1,10 @@ -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/feature-gate-stmt_expr_attributes.rs:1:16 | LL | const X: i32 = #[allow(dead_code)] 8; | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-thread_local.stderr b/src/test/ui/feature-gates/feature-gate-thread_local.stderr index dc7d67a205379..95334d23d510b 100644 --- a/src/test/ui/feature-gates/feature-gate-thread_local.stderr +++ b/src/test/ui/feature-gates/feature-gate-thread_local.stderr @@ -1,9 +1,10 @@ -error[E0658]: `#[thread_local]` is an experimental feature, and does not currently handle destructors. (see issue #29594) +error[E0658]: `#[thread_local]` is an experimental feature, and does not currently handle destructors --> $DIR/feature-gate-thread_local.rs:8:1 | -LL | #[thread_local] //~ ERROR `#[thread_local]` is an experimental feature +LL | #[thread_local] | ^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29594 = help: add #![feature(thread_local)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-trace_macros.stderr b/src/test/ui/feature-gates/feature-gate-trace_macros.stderr index 9f4b01e45b6a6..bcce31d873b0a 100644 --- a/src/test/ui/feature-gates/feature-gate-trace_macros.stderr +++ b/src/test/ui/feature-gates/feature-gate-trace_macros.stderr @@ -1,9 +1,10 @@ -error[E0658]: `trace_macros` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `trace_macros` is not stable enough for use and is subject to change --> $DIR/feature-gate-trace_macros.rs:2:5 | -LL | trace_macros!(true); //~ ERROR: `trace_macros` is not stable +LL | trace_macros!(true); | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(trace_macros)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-trait-alias.stderr b/src/test/ui/feature-gates/feature-gate-trait-alias.stderr index bb833c4e732fd..1a9718a6ce4cc 100644 --- a/src/test/ui/feature-gates/feature-gate-trait-alias.stderr +++ b/src/test/ui/feature-gates/feature-gate-trait-alias.stderr @@ -1,9 +1,10 @@ -error[E0658]: trait aliases are experimental (see issue #41517) +error[E0658]: trait aliases are experimental --> $DIR/feature-gate-trait-alias.rs:1:1 | LL | trait Foo = Default; | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/41517 = help: add #![feature(trait_alias)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-transparent_enums.rs b/src/test/ui/feature-gates/feature-gate-transparent_enums.rs new file mode 100644 index 0000000000000..0a7a73a168ed5 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-transparent_enums.rs @@ -0,0 +1,6 @@ +#[repr(transparent)] +enum OkButUnstableEnum { //~ ERROR transparent enums are unstable + Foo((), String, ()), +} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-transparent_enums.stderr b/src/test/ui/feature-gates/feature-gate-transparent_enums.stderr new file mode 100644 index 0000000000000..8ba079b89f509 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-transparent_enums.stderr @@ -0,0 +1,12 @@ +error[E0658]: transparent enums are unstable + --> $DIR/feature-gate-transparent_enums.rs:2:1 + | +LL | enum OkButUnstableEnum { + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/60405 + = help: add #![feature(transparent_enums)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-transparent_unions.rs b/src/test/ui/feature-gates/feature-gate-transparent_unions.rs new file mode 100644 index 0000000000000..73cac0a49148b --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-transparent_unions.rs @@ -0,0 +1,7 @@ +#[repr(transparent)] +union OkButUnstableUnion { //~ ERROR transparent unions are unstable + field: u8, + zst: (), +} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-transparent_unions.stderr b/src/test/ui/feature-gates/feature-gate-transparent_unions.stderr new file mode 100644 index 0000000000000..341324c3d6764 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-transparent_unions.stderr @@ -0,0 +1,12 @@ +error[E0658]: transparent unions are unstable + --> $DIR/feature-gate-transparent_unions.rs:2:1 + | +LL | union OkButUnstableUnion { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/60405 + = help: add #![feature(transparent_unions)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs b/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs index e5028f2f8aa78..3dbaf5dea250e 100644 --- a/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs +++ b/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs @@ -52,8 +52,8 @@ struct Dst { struct TwoStrs(str, str) where str: Sized; //~ ERROR -fn unsized_local() where Dst: Sized { //~ ERROR - let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); +fn unsized_local() where Dst: Sized { //~ ERROR + let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); } fn return_str() -> str where str: Sized { //~ ERROR diff --git a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr index 1f35efa59b690..1d346fd42ffa4 100644 --- a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/feature-gate-trivial_bounds.rs:10:1 | -LL | enum E where i32: Foo { V } //~ ERROR +LL | enum E where i32: Foo { V } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32` | = help: see issue #48214 @@ -10,7 +10,7 @@ LL | enum E where i32: Foo { V } //~ ERROR error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/feature-gate-trivial_bounds.rs:12:1 | -LL | struct S where i32: Foo; //~ ERROR +LL | struct S where i32: Foo; | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32` | = help: see issue #48214 @@ -19,7 +19,7 @@ LL | struct S where i32: Foo; //~ ERROR error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/feature-gate-trivial_bounds.rs:14:1 | -LL | trait T where i32: Foo {} //~ ERROR +LL | trait T where i32: Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32` | = help: see issue #48214 @@ -28,7 +28,7 @@ LL | trait T where i32: Foo {} //~ ERROR error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/feature-gate-trivial_bounds.rs:16:1 | -LL | union U where i32: Foo { f: i32 } //~ ERROR +LL | union U where i32: Foo { f: i32 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32` | = help: see issue #48214 @@ -37,7 +37,7 @@ LL | union U where i32: Foo { f: i32 } //~ ERROR error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/feature-gate-trivial_bounds.rs:20:1 | -LL | / impl Foo for () where i32: Foo { //~ ERROR +LL | / impl Foo for () where i32: Foo { LL | | fn test(&self) { LL | | 3i32.test(); LL | | Foo::test(&4i32); @@ -52,7 +52,7 @@ LL | | } error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/feature-gate-trivial_bounds.rs:28:1 | -LL | / fn f() where i32: Foo //~ ERROR +LL | / fn f() where i32: Foo LL | | { LL | | let s = S; LL | | 3i32.test(); @@ -67,7 +67,7 @@ LL | | } error[E0277]: the trait bound `std::string::String: std::ops::Neg` is not satisfied --> $DIR/feature-gate-trivial_bounds.rs:36:1 | -LL | / fn use_op(s: String) -> String where String: ::std::ops::Neg { //~ ERROR +LL | / fn use_op(s: String) -> String where String: ::std::ops::Neg { LL | | -s LL | | } | |_^ the trait `std::ops::Neg` is not implemented for `std::string::String` @@ -78,7 +78,7 @@ LL | | } error[E0277]: `i32` is not an iterator --> $DIR/feature-gate-trivial_bounds.rs:40:1 | -LL | / fn use_for() where i32: Iterator { //~ ERROR +LL | / fn use_for() where i32: Iterator { LL | | for _ in 2i32 {} LL | | } | |_^ `i32` is not an iterator @@ -91,7 +91,7 @@ LL | | } error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/feature-gate-trivial_bounds.rs:52:1 | -LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR +LL | struct TwoStrs(str, str) where str: Sized; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` @@ -102,8 +102,8 @@ LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time --> $DIR/feature-gate-trivial_bounds.rs:55:1 | -LL | / fn unsized_local() where Dst: Sized { //~ ERROR -LL | | let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); +LL | / fn unsized_local() where Dst: Sized { +LL | | let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); LL | | } | |_^ doesn't have a size known at compile-time | @@ -116,7 +116,7 @@ LL | | } error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/feature-gate-trivial_bounds.rs:59:1 | -LL | / fn return_str() -> str where str: Sized { //~ ERROR +LL | / fn return_str() -> str where str: Sized { LL | | *"Sized".to_string().into_boxed_str() LL | | } | |_^ doesn't have a size known at compile-time diff --git a/src/test/ui/feature-gates/feature-gate-try_blocks.stderr b/src/test/ui/feature-gates/feature-gate-try_blocks.stderr index 209a445194da9..cb72b06733370 100644 --- a/src/test/ui/feature-gates/feature-gate-try_blocks.stderr +++ b/src/test/ui/feature-gates/feature-gate-try_blocks.stderr @@ -1,13 +1,14 @@ -error[E0658]: `try` expression is experimental (see issue #31436) +error[E0658]: `try` expression is experimental --> $DIR/feature-gate-try_blocks.rs:4:33 | -LL | let try_result: Option<_> = try { //~ ERROR `try` expression is experimental +LL | let try_result: Option<_> = try { | _________________________________^ LL | | let x = 5; LL | | x LL | | }; | |_____^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/31436 = help: add #![feature(try_blocks)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-try_reserve.stderr b/src/test/ui/feature-gates/feature-gate-try_reserve.stderr index 4ced5037f38ba..f1d82d94a521c 100644 --- a/src/test/ui/feature-gates/feature-gate-try_reserve.stderr +++ b/src/test/ui/feature-gates/feature-gate-try_reserve.stderr @@ -1,9 +1,10 @@ -error[E0658]: use of unstable library feature 'try_reserve': new API (see issue #48043) +error[E0658]: use of unstable library feature 'try_reserve': new API --> $DIR/feature-gate-try_reserve.rs:3:7 | -LL | v.try_reserve(10); //~ ERROR: use of unstable library feature 'try_reserve' +LL | v.try_reserve(10); | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/48043 = help: add #![feature(try_reserve)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-type_alias_enum_variants.rs b/src/test/ui/feature-gates/feature-gate-type_alias_enum_variants.rs deleted file mode 100644 index c7d3304a128dd..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-type_alias_enum_variants.rs +++ /dev/null @@ -1,19 +0,0 @@ -enum Foo { - Bar(i32), - Baz { i: i32 }, -} - -type Alias = Foo; - -fn main() { - let t = Alias::Bar(0); - //~^ ERROR enum variants on type aliases are experimental - let t = Alias::Baz { i: 0 }; - //~^ ERROR enum variants on type aliases are experimental - match t { - Alias::Bar(_i) => {} - //~^ ERROR enum variants on type aliases are experimental - Alias::Baz { i: _i } => {} - //~^ ERROR enum variants on type aliases are experimental - } -} diff --git a/src/test/ui/feature-gates/feature-gate-type_alias_enum_variants.stderr b/src/test/ui/feature-gates/feature-gate-type_alias_enum_variants.stderr deleted file mode 100644 index 43535af7c69d8..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-type_alias_enum_variants.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error: enum variants on type aliases are experimental - --> $DIR/feature-gate-type_alias_enum_variants.rs:9:13 - | -LL | let t = Alias::Bar(0); - | ^^^^^^^^^^ - | - = help: add `#![feature(type_alias_enum_variants)]` to the crate attributes to enable - -error: enum variants on type aliases are experimental - --> $DIR/feature-gate-type_alias_enum_variants.rs:11:13 - | -LL | let t = Alias::Baz { i: 0 }; - | ^^^^^^^^^^ - | - = help: add `#![feature(type_alias_enum_variants)]` to the crate attributes to enable - -error: enum variants on type aliases are experimental - --> $DIR/feature-gate-type_alias_enum_variants.rs:14:9 - | -LL | Alias::Bar(_i) => {} - | ^^^^^^^^^^^^^^ - | - = help: add `#![feature(type_alias_enum_variants)]` to the crate attributes to enable - -error: enum variants on type aliases are experimental - --> $DIR/feature-gate-type_alias_enum_variants.rs:16:9 - | -LL | Alias::Baz { i: _i } => {} - | ^^^^^^^^^^ - | - = help: add `#![feature(type_alias_enum_variants)]` to the crate attributes to enable - -error: aborting due to 4 previous errors - diff --git a/src/test/ui/feature-gates/feature-gate-type_ascription.stderr b/src/test/ui/feature-gates/feature-gate-type_ascription.stderr index 4cf1f29f1ab04..0e4e25882c8e3 100644 --- a/src/test/ui/feature-gates/feature-gate-type_ascription.stderr +++ b/src/test/ui/feature-gates/feature-gate-type_ascription.stderr @@ -1,9 +1,10 @@ -error[E0658]: type ascription is experimental (see issue #23416) +error[E0658]: type ascription is experimental --> $DIR/feature-gate-type_ascription.rs:4:13 | -LL | let a = 10: u8; //~ ERROR type ascription is experimental +LL | let a = 10: u8; | ^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23416 = help: add #![feature(type_ascription)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr index 865b87e7dd5d7..6b09daff0f9d1 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr @@ -1,41 +1,46 @@ -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:11:5 | LL | extern "rust-call" fn call(self, args: ()) -> () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:17:5 | LL | extern "rust-call" fn call_once(self, args: ()) -> () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:5 | LL | extern "rust-call" fn call_mut(&self, args: ()) -> () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:29:5 | LL | extern "rust-call" fn call_once(&self, args: ()) -> () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:6 | LL | impl Fn<()> for Foo { | ^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable error[E0229]: associated type bindings are not allowed here @@ -44,23 +49,25 @@ error[E0229]: associated type bindings are not allowed here LL | impl FnOnce() for Foo1 { | ^^ associated type not allowed here -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:21:6 | LL | impl FnMut<()> for Bar { | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:27:6 | LL | impl FnOnce<()> for Baz { | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable error: aborting due to 8 previous errors -Some errors occurred: E0229, E0658. +Some errors have detailed explanations: E0229, E0658. For more information about an error, try `rustc --explain E0229`. diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-method-calls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-method-calls.stderr index 8730bf678fd34..164368cd8ef79 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-method-calls.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-method-calls.stderr @@ -1,25 +1,28 @@ -error[E0658]: use of unstable library feature 'fn_traits' (see issue #29625) +error[E0658]: use of unstable library feature 'fn_traits' --> $DIR/feature-gate-unboxed-closures-method-calls.rs:4:7 | -LL | f.call(()); //~ ERROR use of unstable library feature 'fn_traits' +LL | f.call(()); | ^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(fn_traits)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'fn_traits' (see issue #29625) +error[E0658]: use of unstable library feature 'fn_traits' --> $DIR/feature-gate-unboxed-closures-method-calls.rs:5:7 | -LL | f.call_mut(()); //~ ERROR use of unstable library feature 'fn_traits' +LL | f.call_mut(()); | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(fn_traits)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'fn_traits' (see issue #29625) +error[E0658]: use of unstable library feature 'fn_traits' --> $DIR/feature-gate-unboxed-closures-method-calls.rs:6:7 | -LL | f.call_once(()); //~ ERROR use of unstable library feature 'fn_traits' +LL | f.call_once(()); | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(fn_traits)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-ufcs-calls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-ufcs-calls.stderr index 266775484a901..ff2629fe4216e 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-ufcs-calls.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-ufcs-calls.stderr @@ -1,25 +1,28 @@ -error[E0658]: use of unstable library feature 'fn_traits' (see issue #29625) +error[E0658]: use of unstable library feature 'fn_traits' --> $DIR/feature-gate-unboxed-closures-ufcs-calls.rs:4:5 | -LL | Fn::call(&f, ()); //~ ERROR use of unstable library feature 'fn_traits' +LL | Fn::call(&f, ()); | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(fn_traits)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'fn_traits' (see issue #29625) +error[E0658]: use of unstable library feature 'fn_traits' --> $DIR/feature-gate-unboxed-closures-ufcs-calls.rs:5:5 | -LL | FnMut::call_mut(&mut f, ()); //~ ERROR use of unstable library feature 'fn_traits' +LL | FnMut::call_mut(&mut f, ()); | ^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(fn_traits)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'fn_traits' (see issue #29625) +error[E0658]: use of unstable library feature 'fn_traits' --> $DIR/feature-gate-unboxed-closures-ufcs-calls.rs:6:5 | -LL | FnOnce::call_once(f, ()); //~ ERROR use of unstable library feature 'fn_traits' +LL | FnOnce::call_once(f, ()); | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(fn_traits)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures.rs b/src/test/ui/feature-gates/feature-gate-unboxed-closures.rs index c3f5c99dcb482..b8d3aa4a141df 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures.rs +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures.rs @@ -9,7 +9,7 @@ impl FnOnce<(u32, u32)> for Test { extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 { a + b } - //~^^^ ERROR rust-call ABI is subject to change (see issue #29625) + //~^^^ ERROR rust-call ABI is subject to change } fn main() { diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr index e7b1fc589bb4a..872a593f3e471 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr @@ -1,4 +1,4 @@ -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-unboxed-closures.rs:9:5 | LL | / extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 { @@ -6,14 +6,16 @@ LL | | a + b LL | | } | |_____^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead --> $DIR/feature-gate-unboxed-closures.rs:5:6 | LL | impl FnOnce<(u32, u32)> for Test { | ^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-underscore_const_names.rs b/src/test/ui/feature-gates/feature-gate-underscore_const_names.rs deleted file mode 100644 index 6b97c24a47ed2..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-underscore_const_names.rs +++ /dev/null @@ -1,14 +0,0 @@ -trait Trt {} -struct Str {} - -impl Trt for Str {} - -const _ : () = { -//~^ ERROR is unstable - use std::marker::PhantomData; - struct ImplementsTrait(PhantomData); - let _ = ImplementsTrait::(PhantomData); - () -}; - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-underscore_const_names.stderr b/src/test/ui/feature-gates/feature-gate-underscore_const_names.stderr deleted file mode 100644 index d608f3d37cf2a..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-underscore_const_names.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0658]: naming constants with `_` is unstable (see issue #54912) - --> $DIR/feature-gate-underscore_const_names.rs:6:1 - | -LL | / const _ : () = { -LL | | //~^ ERROR is unstable -LL | | use std::marker::PhantomData; -LL | | struct ImplementsTrait(PhantomData); -LL | | let _ = ImplementsTrait::(PhantomData); -LL | | () -LL | | }; - | |__^ - | - = help: add #![feature(underscore_const_names)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-unsized_locals.rs b/src/test/ui/feature-gates/feature-gate-unsized_locals.rs index a8f81f3f113c9..3686e7b37f4c4 100644 --- a/src/test/ui/feature-gates/feature-gate-unsized_locals.rs +++ b/src/test/ui/feature-gates/feature-gate-unsized_locals.rs @@ -1,4 +1,4 @@ -fn f(f: FnOnce()) {} +fn f(f: dyn FnOnce()) {} //~^ ERROR E0277 fn main() { diff --git a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr index bde39cbeaeb28..d20b9e2981e8c 100644 --- a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr +++ b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr @@ -1,7 +1,7 @@ error[E0277]: the size for values of type `(dyn std::ops::FnOnce() + 'static)` cannot be known at compilation time --> $DIR/feature-gate-unsized_locals.rs:1:6 | -LL | fn f(f: FnOnce()) {} +LL | fn f(f: dyn FnOnce()) {} | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::FnOnce() + 'static)` diff --git a/src/test/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs b/src/test/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs index f781bc9aeddd1..c3d62a231e5e4 100644 --- a/src/test/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs +++ b/src/test/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs @@ -1,4 +1,4 @@ fn main() { - let _ : &(Send,) = &((),); + let _ : &(dyn Send,) = &((),); //~^ ERROR unsized tuple coercion is not stable enough } diff --git a/src/test/ui/feature-gates/feature-gate-unsized_tuple_coercion.stderr b/src/test/ui/feature-gates/feature-gate-unsized_tuple_coercion.stderr index c2f5df48fed46..5b93c889db1c2 100644 --- a/src/test/ui/feature-gates/feature-gate-unsized_tuple_coercion.stderr +++ b/src/test/ui/feature-gates/feature-gate-unsized_tuple_coercion.stderr @@ -1,9 +1,10 @@ -error[E0658]: unsized tuple coercion is not stable enough for use and is subject to change (see issue #42877) - --> $DIR/feature-gate-unsized_tuple_coercion.rs:2:24 +error[E0658]: unsized tuple coercion is not stable enough for use and is subject to change + --> $DIR/feature-gate-unsized_tuple_coercion.rs:2:28 | -LL | let _ : &(Send,) = &((),); - | ^^^^^^ +LL | let _ : &(dyn Send,) = &((),); + | ^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/42877 = help: add #![feature(unsized_tuple_coercion)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr index f9f8cfe9171a9..5df3a1d699fe5 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr @@ -1,31 +1,34 @@ -error[E0658]: unions with non-`Copy` fields are unstable (see issue #32836) +error[E0658]: unions with non-`Copy` fields are unstable --> $DIR/feature-gate-untagged_unions.rs:9:1 | -LL | / union U3 { //~ ERROR unions with non-`Copy` fields are unstable +LL | / union U3 { LL | | a: String, LL | | } | |_^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32836 = help: add #![feature(untagged_unions)] to the crate attributes to enable -error[E0658]: unions with non-`Copy` fields are unstable (see issue #32836) +error[E0658]: unions with non-`Copy` fields are unstable --> $DIR/feature-gate-untagged_unions.rs:13:1 | -LL | / union U4 { //~ ERROR unions with non-`Copy` fields are unstable +LL | / union U4 { LL | | a: T, LL | | } | |_^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32836 = help: add #![feature(untagged_unions)] to the crate attributes to enable -error[E0658]: unions with `Drop` implementations are unstable (see issue #32836) +error[E0658]: unions with `Drop` implementations are unstable --> $DIR/feature-gate-untagged_unions.rs:17:1 | -LL | / union U5 { //~ ERROR unions with `Drop` implementations are unstable +LL | / union U5 { LL | | a: u8, LL | | } | |_^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32836 = help: add #![feature(untagged_unions)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr b/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr index 77f2f13c99ee8..bb55013d638cd 100644 --- a/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr +++ b/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[unwind] is experimental (see issue #58760) +error[E0658]: #[unwind] is experimental --> $DIR/feature-gate-unwind-attributes.rs:11:5 | -LL | #[unwind(allowed)] //~ ERROR #[unwind] is experimental +LL | #[unwind(allowed)] | ^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/58760 = help: add #![feature(unwind_attributes)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/underscore_const_names_feature_gate.rs b/src/test/ui/feature-gates/underscore_const_names_feature_gate.rs deleted file mode 100644 index e50bbf5b64909..0000000000000 --- a/src/test/ui/feature-gates/underscore_const_names_feature_gate.rs +++ /dev/null @@ -1,3 +0,0 @@ -const _: () = (); //~ ERROR is unstable - -fn main() {} diff --git a/src/test/ui/feature-gates/underscore_const_names_feature_gate.stderr b/src/test/ui/feature-gates/underscore_const_names_feature_gate.stderr deleted file mode 100644 index a42b8e579c9b2..0000000000000 --- a/src/test/ui/feature-gates/underscore_const_names_feature_gate.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: naming constants with `_` is unstable (see issue #54912) - --> $DIR/underscore_const_names_feature_gate.rs:1:1 - | -LL | const _: () = (); //~ ERROR is unstable - | ^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(underscore_const_names)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/ffi_returns_twice.rs b/src/test/ui/ffi_returns_twice.rs index 93c372e1d83dc..845e18df11b54 100644 --- a/src/test/ui/ffi_returns_twice.rs +++ b/src/test/ui/ffi_returns_twice.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength #![feature(ffi_returns_twice)] #![crate_type = "lib"] diff --git a/src/test/ui/ffi_returns_twice.stderr b/src/test/ui/ffi_returns_twice.stderr index c2105ae1dac7c..862892e27be98 100644 --- a/src/test/ui/ffi_returns_twice.stderr +++ b/src/test/ui/ffi_returns_twice.stderr @@ -1,9 +1,8 @@ error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions - --> $DIR/ffi_returns_twice.rs:5:1 + --> $DIR/ffi_returns_twice.rs:4:1 | -LL | #[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions +LL | #[ffi_returns_twice] | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0724`. diff --git a/src/test/ui/float-literal-inference-restrictions.stderr b/src/test/ui/float-literal-inference-restrictions.stderr index a69c13507e6b2..839ca57ce5562 100644 --- a/src/test/ui/float-literal-inference-restrictions.stderr +++ b/src/test/ui/float-literal-inference-restrictions.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/float-literal-inference-restrictions.rs:2:18 | -LL | let x: f32 = 1; //~ ERROR mismatched types +LL | let x: f32 = 1; | ^ | | | expected f32, found integer @@ -13,8 +13,12 @@ LL | let x: f32 = 1; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/float-literal-inference-restrictions.rs:3:18 | -LL | let y: f32 = 1f64; //~ ERROR mismatched types +LL | let y: f32 = 1f64; | ^^^^ expected f32, found f64 +help: change the type of the numeric literal from `f64` to `f32` + | +LL | let y: f32 = 1f32; + | ^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/fmt/format-string-error-2.rs b/src/test/ui/fmt/format-string-error-2.rs index 5c25ae502ff6d..69fed2cb69ad8 100644 --- a/src/test/ui/fmt/format-string-error-2.rs +++ b/src/test/ui/fmt/format-string-error-2.rs @@ -76,7 +76,6 @@ raw { \n println!("\x7B}\u8 {", 1); //~^ ERROR incorrect unicode escape sequence - //~| ERROR argument never used // note: raw strings don't escape `\xFF` and `\u{FF}` sequences println!(r#"\x7B}\u{8} {"#, 1); diff --git a/src/test/ui/fmt/format-string-error-2.stderr b/src/test/ui/fmt/format-string-error-2.stderr index baab8529940c5..d202044a2bb97 100644 --- a/src/test/ui/fmt/format-string-error-2.stderr +++ b/src/test/ui/fmt/format-string-error-2.stderr @@ -1,10 +1,10 @@ error: incorrect unicode escape sequence --> $DIR/format-string-error-2.rs:77:20 | -LL | println!("/x7B}/u8 {", 1); +LL | println!("\x7B}\u8 {", 1); | ^^- - | | - | help: format of unicode escape sequences uses braces: `/u{8}` + | | + | help: format of unicode escape sequences uses braces: `\u{8}` error: invalid format string: expected `'}'`, found `'a'` --> $DIR/format-string-error-2.rs:5:5 @@ -19,7 +19,7 @@ LL | a"); error: invalid format string: expected `'}'`, found `'b'` --> $DIR/format-string-error-2.rs:9:5 | -LL | format!("{ / +LL | format!("{ \ | - because of this opening brace LL | LL | b"); @@ -27,20 +27,20 @@ LL | b"); | = note: if you intended to print `{`, you can escape it using `{{` -error: invalid format string: expected `'}'`, found `'/'` +error: invalid format string: expected `'}'`, found `'\'` --> $DIR/format-string-error-2.rs:11:18 | -LL | format!(r#"{ / +LL | format!(r#"{ \ | - ^ expected `}` in format string | | | because of this opening brace | = note: if you intended to print `{`, you can escape it using `{{` -error: invalid format string: expected `'}'`, found `'/'` +error: invalid format string: expected `'}'`, found `'\'` --> $DIR/format-string-error-2.rs:15:18 | -LL | format!(r#"{ /n +LL | format!(r#"{ \n | - ^ expected `}` in format string | | | because of this opening brace @@ -50,9 +50,9 @@ LL | format!(r#"{ /n error: invalid format string: expected `'}'`, found `'e'` --> $DIR/format-string-error-2.rs:21:5 | -LL | format!("{ /n +LL | format!("{ \n | - because of this opening brace -LL | /n +LL | \n LL | e"); | ^ expected `}` in format string | @@ -81,9 +81,9 @@ LL | a error: invalid format string: expected `'}'`, found `'b'` --> $DIR/format-string-error-2.rs:35:5 | -LL | { / +LL | { \ | - because of this opening brace -LL | / +LL | \ LL | b"); | ^ expected `}` in format string | @@ -92,28 +92,28 @@ LL | b"); error: invalid format string: expected `'}'`, found `'b'` --> $DIR/format-string-error-2.rs:40:5 | -LL | { / +LL | { \ | - because of this opening brace -LL | / -LL | b / +LL | \ +LL | b \ | ^ expected `}` in format string | = note: if you intended to print `{`, you can escape it using `{{` -error: invalid format string: expected `'}'`, found `'/'` +error: invalid format string: expected `'}'`, found `'\'` --> $DIR/format-string-error-2.rs:45:8 | -LL | raw { / +LL | raw { \ | - ^ expected `}` in format string | | | because of this opening brace | = note: if you intended to print `{`, you can escape it using `{{` -error: invalid format string: expected `'}'`, found `'/'` +error: invalid format string: expected `'}'`, found `'\'` --> $DIR/format-string-error-2.rs:50:8 | -LL | raw { /n +LL | raw { \n | - ^ expected `}` in format string | | | because of this opening brace @@ -123,9 +123,9 @@ LL | raw { /n error: invalid format string: expected `'}'`, found `'e'` --> $DIR/format-string-error-2.rs:57:5 | -LL | { /n +LL | { \n | - because of this opening brace -LL | /n +LL | \n LL | e"); | ^ expected `}` in format string | @@ -144,42 +144,34 @@ LL | asdf} error: 1 positional argument in format string, but no arguments were given --> $DIR/format-string-error-2.rs:70:17 | -LL | println!("/t{}"); +LL | println!("\t{}"); | ^^ error: invalid format string: expected `'}'` but string was terminated --> $DIR/format-string-error-2.rs:74:27 | -LL | println!("/x7B}/u{8} {", 1); +LL | println!("\x7B}\u{8} {", 1); | -^ expected `'}'` in format string | | | because of this opening brace | = note: if you intended to print `{`, you can escape it using `{{` -error: argument never used - --> $DIR/format-string-error-2.rs:77:28 - | -LL | println!("/x7B}/u8 {", 1); - | ------------ ^ argument never used - | | - | formatting specifier missing - error: invalid format string: unmatched `}` found - --> $DIR/format-string-error-2.rs:82:21 + --> $DIR/format-string-error-2.rs:81:21 | -LL | println!(r#"/x7B}/u{8} {"#, 1); +LL | println!(r#"\x7B}\u{8} {"#, 1); | ^ unmatched `}` in format string | = note: if you intended to print `}`, you can escape it using `}}` error: invalid format string: unmatched `}` found - --> $DIR/format-string-error-2.rs:85:21 + --> $DIR/format-string-error-2.rs:84:21 | -LL | println!(r#"/x7B}/u8 {"#, 1); +LL | println!(r#"\x7B}\u8 {"#, 1); | ^ unmatched `}` in format string | = note: if you intended to print `}`, you can escape it using `}}` -error: aborting due to 19 previous errors +error: aborting due to 18 previous errors diff --git a/src/test/ui/fmt/format-string-error.stderr b/src/test/ui/fmt/format-string-error.stderr index 86ab163591e0d..3dc122a7399dd 100644 --- a/src/test/ui/fmt/format-string-error.stderr +++ b/src/test/ui/fmt/format-string-error.stderr @@ -50,10 +50,10 @@ LL | let _ = format!("}"); | = note: if you intended to print `}`, you can escape it using `}}` -error: invalid format string: expected `'}'`, found `'/'` +error: invalid format string: expected `'}'`, found `'\'` --> $DIR/format-string-error.rs:17:23 | -LL | let _ = format!("{/}"); +LL | let _ = format!("{\}"); | -^ expected `}` in format string | | | because of this opening brace @@ -63,7 +63,7 @@ LL | let _ = format!("{/}"); error: invalid format string: expected `'}'` but string was terminated --> $DIR/format-string-error.rs:19:35 | -LL | let _ = format!("/n/n/n{/n/n/n"); +LL | let _ = format!("\n\n\n{\n\n\n"); | - ^ expected `'}'` in format string | | | because of this opening brace diff --git a/src/test/ui/fmt/send-sync.stderr b/src/test/ui/fmt/send-sync.stderr index 5abe0d0c50b4f..1f698c90cb9a4 100644 --- a/src/test/ui/fmt/send-sync.stderr +++ b/src/test/ui/fmt/send-sync.stderr @@ -1,7 +1,7 @@ error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely --> $DIR/send-sync.rs:8:5 | -LL | send(format_args!("{:?}", c)); //~ ERROR E0277 +LL | send(format_args!("{:?}", c)); | ^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely | = help: within `[std::fmt::ArgumentV1<'_>]`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)` @@ -21,7 +21,7 @@ LL | fn send(_: T) {} error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely --> $DIR/send-sync.rs:9:5 | -LL | sync(format_args!("{:?}", c)); //~ ERROR E0277 +LL | sync(format_args!("{:?}", c)); | ^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely | = help: within `std::fmt::Arguments<'_>`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)` diff --git a/src/test/ui/fn-in-pat.rs b/src/test/ui/fn-in-pat.rs new file mode 100644 index 0000000000000..ed76b2c5db025 --- /dev/null +++ b/src/test/ui/fn-in-pat.rs @@ -0,0 +1,16 @@ +struct A {} + +impl A { + fn new() {} +} + +fn hof(_: F) where F: FnMut(()) {} + +fn ice() { + hof(|c| match c { + A::new() => (), //~ ERROR expected tuple struct/variant, found method + _ => () + }) +} + +fn main() {} diff --git a/src/test/ui/fn-in-pat.stderr b/src/test/ui/fn-in-pat.stderr new file mode 100644 index 0000000000000..0bb24365ef42b --- /dev/null +++ b/src/test/ui/fn-in-pat.stderr @@ -0,0 +1,11 @@ +error[E0164]: expected tuple struct/variant, found method `::new` + --> $DIR/fn-in-pat.rs:11:9 + | +LL | A::new() => (), + | ^^^^^^^^ `fn` calls are not allowed in patterns + | + = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0164`. diff --git a/src/test/ui/fn/fn-closure-mutable-capture.nll.stderr b/src/test/ui/fn/fn-closure-mutable-capture.nll.stderr deleted file mode 100644 index f7ab56da8de97..0000000000000 --- a/src/test/ui/fn/fn-closure-mutable-capture.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/fn-closure-mutable-capture.rs:5:17 - | -LL | bar(move || x = 1); - | ^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/fn-closure-mutable-capture.rs:5:9 - | -LL | bar(move || x = 1); - | ^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/fn/fn-closure-mutable-capture.rs b/src/test/ui/fn/fn-closure-mutable-capture.rs index a37eceffb9dae..81376af091b45 100644 --- a/src/test/ui/fn/fn-closure-mutable-capture.rs +++ b/src/test/ui/fn/fn-closure-mutable-capture.rs @@ -3,8 +3,9 @@ pub fn bar(_f: F) {} pub fn foo() { let mut x = 0; bar(move || x = 1); - //~^ ERROR cannot assign to captured outer variable in an `Fn` closure - //~| NOTE `Fn` closures cannot capture their enclosing environment for modifications + //~^ ERROR cannot assign to `x`, as it is a captured variable in a `Fn` closure + //~| NOTE cannot assign + //~| HELP consider changing this to accept closures that implement `FnMut` } fn main() {} diff --git a/src/test/ui/fn/fn-closure-mutable-capture.stderr b/src/test/ui/fn/fn-closure-mutable-capture.stderr index 84a5989c28c09..8dfae0cbdf294 100644 --- a/src/test/ui/fn/fn-closure-mutable-capture.stderr +++ b/src/test/ui/fn/fn-closure-mutable-capture.stderr @@ -1,11 +1,10 @@ -error[E0594]: cannot assign to captured outer variable in an `Fn` closure +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/fn-closure-mutable-capture.rs:5:17 | LL | bar(move || x = 1); - | ^^^^^ + | ^^^^^ cannot assign | - = note: `Fn` closures cannot capture their enclosing environment for modifications -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/fn-closure-mutable-capture.rs:5:9 | LL | bar(move || x = 1); @@ -13,4 +12,3 @@ LL | bar(move || x = 1); error: aborting due to previous error -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/fn/fn-compare-mismatch.stderr b/src/test/ui/fn/fn-compare-mismatch.stderr index 54dae525ffd0e..b2f6510d5a084 100644 --- a/src/test/ui/fn/fn-compare-mismatch.stderr +++ b/src/test/ui/fn/fn-compare-mismatch.stderr @@ -1,10 +1,18 @@ error[E0369]: binary operation `==` cannot be applied to type `fn() {main::f}` - --> $DIR/fn-compare-mismatch.rs:4:13 + --> $DIR/fn-compare-mismatch.rs:4:15 | LL | let x = f == g; - | ^^^^^^ + | - ^^ - fn() {main::g} + | | + | fn() {main::f} +help: you might have forgotten to call this function | - = note: an implementation of `std::cmp::PartialEq` might be missing for `fn() {main::f}` +LL | let x = f() == g; + | ^^^ +help: you might have forgotten to call this function + | +LL | let x = f == g(); + | ^^^ error[E0308]: mismatched types --> $DIR/fn-compare-mismatch.rs:4:18 @@ -17,5 +25,5 @@ LL | let x = f == g; error: aborting due to 2 previous errors -Some errors occurred: E0308, E0369. +Some errors have detailed explanations: E0308, E0369. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/fn/fn-trait-formatting.rs b/src/test/ui/fn/fn-trait-formatting.rs index 21da39dd4004f..5c16c1a7e88b7 100644 --- a/src/test/ui/fn/fn-trait-formatting.rs +++ b/src/test/ui/fn/fn-trait-formatting.rs @@ -3,15 +3,15 @@ fn needs_fn(x: F) where F: Fn(isize) -> isize {} fn main() { - let _: () = (box |_: isize| {}) as Box; + let _: () = (box |_: isize| {}) as Box; //~^ ERROR mismatched types //~| expected type `()` //~| found type `std::boxed::Box` - let _: () = (box |_: isize, isize| {}) as Box; + let _: () = (box |_: isize, isize| {}) as Box; //~^ ERROR mismatched types //~| expected type `()` //~| found type `std::boxed::Box` - let _: () = (box || -> isize { unimplemented!() }) as Box isize>; + let _: () = (box || -> isize { unimplemented!() }) as Box isize>; //~^ ERROR mismatched types //~| expected type `()` //~| found type `std::boxed::Box isize>` diff --git a/src/test/ui/fn/fn-trait-formatting.stderr b/src/test/ui/fn/fn-trait-formatting.stderr index bbccb57a1e218..504bc2605ec38 100644 --- a/src/test/ui/fn/fn-trait-formatting.stderr +++ b/src/test/ui/fn/fn-trait-formatting.stderr @@ -1,8 +1,8 @@ error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:6:17 | -LL | let _: () = (box |_: isize| {}) as Box; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found struct `std::boxed::Box` +LL | let _: () = (box |_: isize| {}) as Box; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found struct `std::boxed::Box` | = note: expected type `()` found type `std::boxed::Box` @@ -10,8 +10,8 @@ LL | let _: () = (box |_: isize| {}) as Box; error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:10:17 | -LL | let _: () = (box |_: isize, isize| {}) as Box; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found struct `std::boxed::Box` +LL | let _: () = (box |_: isize, isize| {}) as Box; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found struct `std::boxed::Box` | = note: expected type `()` found type `std::boxed::Box` @@ -19,8 +19,8 @@ LL | let _: () = (box |_: isize, isize| {}) as Box; error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:14:17 | -LL | let _: () = (box || -> isize { unimplemented!() }) as Box isize>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found struct `std::boxed::Box` +LL | let _: () = (box || -> isize { unimplemented!() }) as Box isize>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found struct `std::boxed::Box` | = note: expected type `()` found type `std::boxed::Box isize>` @@ -40,5 +40,5 @@ LL | fn needs_fn(x: F) where F: Fn(isize) -> isize {} error: aborting due to 4 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/fn_must_use.stderr b/src/test/ui/fn_must_use.stderr index 4bba638c4e9b0..5a1a4e36e06da 100644 --- a/src/test/ui/fn_must_use.stderr +++ b/src/test/ui/fn_must_use.stderr @@ -1,7 +1,7 @@ warning: unused return value of `need_to_use_this_value` that must be used --> $DIR/fn_must_use.rs:55:5 | -LL | need_to_use_this_value(); //~ WARN unused return value +LL | need_to_use_this_value(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -14,7 +14,7 @@ LL | #![warn(unused_must_use)] warning: unused return value of `MyStruct::need_to_use_this_method_value` that must be used --> $DIR/fn_must_use.rs:60:5 | -LL | m.need_to_use_this_method_value(); //~ WARN unused return value +LL | m.need_to_use_this_method_value(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused return value of `EvenNature::is_even` that must be used @@ -34,24 +34,24 @@ LL | MyStruct::need_to_use_this_associated_function_value(); warning: unused return value of `std::cmp::PartialEq::eq` that must be used --> $DIR/fn_must_use.rs:70:5 | -LL | 2.eq(&3); //~ WARN unused return value +LL | 2.eq(&3); | ^^^^^^^^^ warning: unused return value of `std::cmp::PartialEq::eq` that must be used --> $DIR/fn_must_use.rs:71:5 | -LL | m.eq(&n); //~ WARN unused return value +LL | m.eq(&n); | ^^^^^^^^^ warning: unused comparison that must be used --> $DIR/fn_must_use.rs:74:5 | -LL | 2 == 3; //~ WARN unused comparison +LL | 2 == 3; | ^^^^^^ warning: unused comparison that must be used --> $DIR/fn_must_use.rs:75:5 | -LL | m == n; //~ WARN unused comparison +LL | m == n; | ^^^^^^ diff --git a/src/test/ui/for/for-expn.stderr b/src/test/ui/for/for-expn.stderr index b598032e4c9b1..cdb2115552744 100644 --- a/src/test/ui/for/for-expn.stderr +++ b/src/test/ui/for/for-expn.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `foo` in this scope --> $DIR/for-expn.rs:6:7 | -LL | foo //~ ERROR cannot find value `foo` in this scope +LL | foo | ^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr index 88d82187716d9..da2b0dc234f40 100644 --- a/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr +++ b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr @@ -1,7 +1,7 @@ error[E0005]: refutable pattern in `for` loop binding: `&-2147483648i32..=0i32` not covered --> $DIR/for-loop-refutable-pattern-error-message.rs:2:9 | -LL | for &1 in [1].iter() {} //~ ERROR refutable pattern in `for` loop binding +LL | for &1 in [1].iter() {} | ^^ pattern `&-2147483648i32..=0i32` not covered error: aborting due to previous error diff --git a/src/test/ui/for/for-loop-type-error.stderr b/src/test/ui/for/for-loop-type-error.stderr index b5a4a5240d9d7..588e7a0ed339e 100644 --- a/src/test/ui/for/for-loop-type-error.stderr +++ b/src/test/ui/for/for-loop-type-error.stderr @@ -1,8 +1,10 @@ error[E0369]: binary operation `+` cannot be applied to type `()` - --> $DIR/for-loop-type-error.rs:2:13 + --> $DIR/for-loop-type-error.rs:2:16 | -LL | let x = () + (); //~ ERROR binary operation - | ^^^^^^^ +LL | let x = () + (); + | -- ^ -- () + | | + | () | = note: an implementation of `std::ops::Add` might be missing for `()` diff --git a/src/test/ui/for/for-loop-unconstrained-element-type.stderr b/src/test/ui/for/for-loop-unconstrained-element-type.stderr index aaaad658de7ba..02fdb808da449 100644 --- a/src/test/ui/for/for-loop-unconstrained-element-type.stderr +++ b/src/test/ui/for/for-loop-unconstrained-element-type.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed --> $DIR/for-loop-unconstrained-element-type.rs:8:14 | -LL | for i in Vec::new() { } //~ ERROR type annotations needed +LL | for i in Vec::new() { } | ^^^^^^^^^^ | | | cannot infer type diff --git a/src/test/ui/foreign-fn-return-lifetime.stderr b/src/test/ui/foreign-fn-return-lifetime.stderr index 00fda5dbd0c48..575da18f24043 100644 --- a/src/test/ui/foreign-fn-return-lifetime.stderr +++ b/src/test/ui/foreign-fn-return-lifetime.stderr @@ -1,7 +1,7 @@ error[E0106]: missing lifetime specifier --> $DIR/foreign-fn-return-lifetime.rs:5:19 | -LL | pub fn f() -> &u8; //~ ERROR missing lifetime specifier +LL | pub fn f() -> &u8; | ^ help: consider giving it a 'static lifetime: `&'static` | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from diff --git a/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.nll.stderr b/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.nll.stderr deleted file mode 100644 index 67cca25ac0cac..0000000000000 --- a/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0509]: cannot move out of type `A`, which implements the `Drop` trait - --> $DIR/functional-struct-update-noncopyable.rs:12:14 - | -LL | let _b = A { y: Arc::new(3), ..a }; //~ ERROR cannot move out of type `A` - | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.stderr b/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.stderr index a3497c59a52b1..635f83bbf480c 100644 --- a/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.stderr +++ b/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.stderr @@ -1,8 +1,11 @@ error[E0509]: cannot move out of type `A`, which implements the `Drop` trait - --> $DIR/functional-struct-update-noncopyable.rs:12:36 + --> $DIR/functional-struct-update-noncopyable.rs:12:14 | -LL | let _b = A { y: Arc::new(3), ..a }; //~ ERROR cannot move out of type `A` - | ^ cannot move out of here +LL | let _b = A { y: Arc::new(3), ..a }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `a.x` has type `std::sync::Arc`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/future-incompatible-lint-group.stderr b/src/test/ui/future-incompatible-lint-group.stderr index 79183fca9d3a3..65c37e01eaa93 100644 --- a/src/test/ui/future-incompatible-lint-group.stderr +++ b/src/test/ui/future-incompatible-lint-group.stderr @@ -1,7 +1,7 @@ error: anonymous parameters are deprecated and will be removed in the next edition. --> $DIR/future-incompatible-lint-group.rs:4:10 | -LL | fn f(u8) {} //~ ERROR anonymous parameters are deprecated +LL | fn f(u8) {} | ^^ help: Try naming the parameter or explicitly ignoring it: `_: u8` | note: lint level defined here diff --git a/src/test/ui/gated-bad-feature.rs b/src/test/ui/gated-bad-feature.rs index fb4cc94f779fe..f8aa23d95e5b6 100644 --- a/src/test/ui/gated-bad-feature.rs +++ b/src/test/ui/gated-bad-feature.rs @@ -1,13 +1,9 @@ -#![feature( - foo_bar_baz, - foo(bar), - foo = "baz" -)] -//~^^^ ERROR: malformed feature -//~^^^ ERROR: malformed feature +#![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] +//~^ ERROR malformed `feature` +//~| ERROR malformed `feature` -#![feature] //~ ERROR: attribute must be of the form -#![feature = "foo"] //~ ERROR: attribute must be of the form +#![feature] //~ ERROR malformed `feature` attribute +#![feature = "foo"] //~ ERROR malformed `feature` attribute #![feature(test_removed_feature)] //~ ERROR: feature has been removed diff --git a/src/test/ui/gated-bad-feature.stderr b/src/test/ui/gated-bad-feature.stderr index 141c51609b7c5..ff6780e66a8ce 100644 --- a/src/test/ui/gated-bad-feature.stderr +++ b/src/test/ui/gated-bad-feature.stderr @@ -1,34 +1,33 @@ -error[E0556]: malformed feature, expected just one word - --> $DIR/gated-bad-feature.rs:3:5 +error[E0556]: malformed `feature` attribute input + --> $DIR/gated-bad-feature.rs:1:25 | -LL | foo(bar), - | ^^^^^^^^ +LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] + | ^^^^^^^^ help: expected just one word: `foo` -error[E0556]: malformed feature, expected just one word - --> $DIR/gated-bad-feature.rs:4:5 +error[E0556]: malformed `feature` attribute input + --> $DIR/gated-bad-feature.rs:1:35 | -LL | foo = "baz" - | ^^^^^^^^^^^ +LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] + | ^^^^^^^^^^^ help: expected just one word: `foo` error[E0557]: feature has been removed - --> $DIR/gated-bad-feature.rs:12:12 + --> $DIR/gated-bad-feature.rs:8:12 | -LL | #![feature(test_removed_feature)] //~ ERROR: feature has been removed - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![feature(test_removed_feature)] + | ^^^^^^^^^^^^^^^^^^^^ feature has been removed -error: attribute must be of the form `#[feature(name1, name1, ...)]` - --> $DIR/gated-bad-feature.rs:9:1 +error: malformed `feature` attribute input + --> $DIR/gated-bad-feature.rs:5:1 | -LL | #![feature] //~ ERROR: attribute must be of the form - | ^^^^^^^^^^^ +LL | #![feature] + | ^^^^^^^^^^^ help: must be of the form: `#[feature(name1, name1, ...)]` -error: attribute must be of the form `#[feature(name1, name1, ...)]` - --> $DIR/gated-bad-feature.rs:10:1 +error: malformed `feature` attribute input + --> $DIR/gated-bad-feature.rs:6:1 | -LL | #![feature = "foo"] //~ ERROR: attribute must be of the form - | ^^^^^^^^^^^^^^^^^^^ +LL | #![feature = "foo"] + | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[feature(name1, name1, ...)]` error: aborting due to 5 previous errors -Some errors occurred: E0556, E0557. -For more information about an error, try `rustc --explain E0556`. +For more information about this error, try `rustc --explain E0557`. diff --git a/src/test/ui/generator-yielding-or-returning-itself.rs b/src/test/ui/generator-yielding-or-returning-itself.rs index 30788e3c1864b..fd52667981873 100644 --- a/src/test/ui/generator-yielding-or-returning-itself.rs +++ b/src/test/ui/generator-yielding-or-returning-itself.rs @@ -13,7 +13,7 @@ pub fn want_cyclic_generator_return(_: T) fn supply_cyclic_generator_return() { want_cyclic_generator_return(|| { - //~^ ERROR type mismatch + //~^ ERROR closure/generator type that references itself if false { yield None.unwrap(); } None.unwrap() }) diff --git a/src/test/ui/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator-yielding-or-returning-itself.stderr index 5834aed2450b1..42591683fe4e3 100644 --- a/src/test/ui/generator-yielding-or-returning-itself.stderr +++ b/src/test/ui/generator-yielding-or-returning-itself.stderr @@ -1,20 +1,17 @@ -error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _] as std::ops::Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _]` - --> $DIR/generator-yielding-or-returning-itself.rs:15:5 +error[E0644]: closure/generator type that references itself + --> $DIR/generator-yielding-or-returning-itself.rs:15:34 | -LL | want_cyclic_generator_return(|| { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size +LL | want_cyclic_generator_return(|| { + | __________________________________^ +LL | | +LL | | if false { yield None.unwrap(); } +LL | | None.unwrap() +LL | | }) + | |_____^ cyclic type of infinite size | = note: closures cannot capture themselves or take themselves as argument; this error may be the result of a recent compiler bug-fix, see https://github.com/rust-lang/rust/issues/46062 for more details -note: required by `want_cyclic_generator_return` - --> $DIR/generator-yielding-or-returning-itself.rs:9:1 - | -LL | / pub fn want_cyclic_generator_return(_: T) -LL | | where T: Generator -LL | | { -LL | | } - | |_^ error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as std::ops::Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]` --> $DIR/generator-yielding-or-returning-itself.rs:28:5 @@ -36,4 +33,5 @@ LL | | } error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0271`. +Some errors have detailed explanations: E0271, E0644. +For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/generator/auto-trait-regions.nll.stderr b/src/test/ui/generator/auto-trait-regions.nll.stderr new file mode 100644 index 0000000000000..4c157a05a5e05 --- /dev/null +++ b/src/test/ui/generator/auto-trait-regions.nll.stderr @@ -0,0 +1,41 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/auto-trait-regions.rs:44:24 + | +LL | let a = A(&mut true, &mut true, No); + | ^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use +LL | yield; +LL | assert_foo(a); + | - borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error[E0716]: temporary value dropped while borrowed + --> $DIR/auto-trait-regions.rs:44:35 + | +LL | let a = A(&mut true, &mut true, No); + | ^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use +LL | yield; +LL | assert_foo(a); + | - borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: higher-ranked subtype error + --> $DIR/auto-trait-regions.rs:30:5 + | +LL | assert_foo(gen); + | ^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/auto-trait-regions.rs:48:5 + | +LL | assert_foo(gen); + | ^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/generator/borrowing.nll.stderr b/src/test/ui/generator/borrowing.nll.stderr deleted file mode 100644 index 3c9221d28e74d..0000000000000 --- a/src/test/ui/generator/borrowing.nll.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0597]: `a` does not live long enough - --> $DIR/borrowing.rs:9:33 - | -LL | Pin::new(&mut || yield &a).resume() - | ----------^ - | | | - | | borrowed value does not live long enough - | value captured here by generator - | a temporary with access to the borrow is created here ... -LL | //~^ ERROR: `a` does not live long enough -LL | }; - | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for generator - | | - | `a` dropped here while still borrowed - | - = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. - -error[E0597]: `a` does not live long enough - --> $DIR/borrowing.rs:16:20 - | -LL | let _b = { - | -- borrow later stored here -LL | let a = 3; -LL | || { - | -- value captured here by generator -LL | yield &a - | ^ borrowed value does not live long enough -... -LL | }; - | - `a` dropped here while still borrowed - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/generator/borrowing.rs b/src/test/ui/generator/borrowing.rs index 9f8fc7483f64d..6234b73804878 100644 --- a/src/test/ui/generator/borrowing.rs +++ b/src/test/ui/generator/borrowing.rs @@ -18,4 +18,3 @@ fn main() { } }; } - diff --git a/src/test/ui/generator/borrowing.stderr b/src/test/ui/generator/borrowing.stderr index 169e4a8561c1d..3d58873f826da 100644 --- a/src/test/ui/generator/borrowing.stderr +++ b/src/test/ui/generator/borrowing.stderr @@ -2,28 +2,32 @@ error[E0597]: `a` does not live long enough --> $DIR/borrowing.rs:9:33 | LL | Pin::new(&mut || yield &a).resume() - | -- ^ borrowed value does not live long enough - | | - | capture occurs here -LL | //~^ ERROR: `a` does not live long enough + | ----------^ + | | | + | | borrowed value does not live long enough + | value captured here by generator + | a temporary with access to the borrow is created here ... +LL | LL | }; - | - borrowed value only lives until here -... -LL | } - | - borrowed value needs to live until here + | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for generator + | | + | `a` dropped here while still borrowed + | + = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. error[E0597]: `a` does not live long enough --> $DIR/borrowing.rs:16:20 | +LL | let _b = { + | -- borrow later stored here +LL | let a = 3; LL | || { - | -- capture occurs here + | -- value captured here by generator LL | yield &a | ^ borrowed value does not live long enough ... LL | }; - | - borrowed value only lives until here -LL | } - | - borrowed value needs to live until here + | - `a` dropped here while still borrowed error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/dropck.nll.stderr b/src/test/ui/generator/dropck.nll.stderr deleted file mode 100644 index a90a47fe9aa01..0000000000000 --- a/src/test/ui/generator/dropck.nll.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0597]: `*cell` does not live long enough - --> $DIR/dropck.rs:10:40 - | -LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); - | ^^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `*cell` dropped here while still borrowed - | borrow might be used here, when `gen` is dropped and runs the destructor for generator - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `ref_` does not live long enough - --> $DIR/dropck.rs:15:18 - | -LL | gen = || { - | -- value captured here by generator -LL | // but the generator can use it to drop a `Ref<'a, i32>`. -LL | let _d = ref_.take(); //~ ERROR `ref_` does not live long enough - | ^^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `ref_` dropped here while still borrowed - | borrow might be used here, when `gen` is dropped and runs the destructor for generator - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/generator/dropck.stderr b/src/test/ui/generator/dropck.stderr index fdaa5cfbae3e6..8bb860f288f10 100644 --- a/src/test/ui/generator/dropck.stderr +++ b/src/test/ui/generator/dropck.stderr @@ -5,23 +5,29 @@ LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); | ^^^^ borrowed value does not live long enough ... LL | } - | - `*cell` dropped here while still borrowed + | - + | | + | `*cell` dropped here while still borrowed + | borrow might be used here, when `gen` is dropped and runs the destructor for generator | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `ref_` does not live long enough --> $DIR/dropck.rs:15:18 | LL | gen = || { - | -- capture occurs here + | -- value captured here by generator LL | // but the generator can use it to drop a `Ref<'a, i32>`. -LL | let _d = ref_.take(); //~ ERROR `ref_` does not live long enough +LL | let _d = ref_.take(); | ^^^^ borrowed value does not live long enough ... LL | } - | - borrowed value dropped before borrower + | - + | | + | `ref_` dropped here while still borrowed + | borrow might be used here, when `gen` is dropped and runs the destructor for generator | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/generator-region-requirements.ast.stderr b/src/test/ui/generator/generator-region-requirements.migrate.stderr similarity index 100% rename from src/test/ui/generator/generator-region-requirements.ast.stderr rename to src/test/ui/generator/generator-region-requirements.migrate.stderr diff --git a/src/test/ui/generator/generator-region-requirements.nll.stderr b/src/test/ui/generator/generator-region-requirements.nll.stderr deleted file mode 100644 index 8a96d187f6b1c..0000000000000 --- a/src/test/ui/generator/generator-region-requirements.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/generator-region-requirements.rs:16:51 - | -LL | fn dangle(x: &mut i32) -> &'static mut i32 { - | -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32` -... -LL | GeneratorState::Complete(c) => return c, - | ^ lifetime `'static` required - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/generator/generator-region-requirements.rs b/src/test/ui/generator/generator-region-requirements.rs index 9738f6c3932ed..41cb339f45911 100644 --- a/src/test/ui/generator/generator-region-requirements.rs +++ b/src/test/ui/generator/generator-region-requirements.rs @@ -1,8 +1,4 @@ -// revisions: ast nll -// ignore-compare-mode-nll - #![feature(generators, generator_trait)] -#![cfg_attr(nll, feature(nll))] use std::ops::{Generator, GeneratorState}; use std::pin::Pin; @@ -14,8 +10,7 @@ fn dangle(x: &mut i32) -> &'static mut i32 { loop { match Pin::new(&mut g).resume() { GeneratorState::Complete(c) => return c, -//[nll]~^ ERROR explicit lifetime required -//[ast]~^^ ERROR explicit lifetime required + //~^ ERROR explicit lifetime required GeneratorState::Yielded(_) => (), } } diff --git a/src/test/ui/generator/generator-region-requirements.stderr b/src/test/ui/generator/generator-region-requirements.stderr new file mode 100644 index 0000000000000..53d48bc4f56ac --- /dev/null +++ b/src/test/ui/generator/generator-region-requirements.stderr @@ -0,0 +1,12 @@ +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/generator-region-requirements.rs:12:51 + | +LL | fn dangle(x: &mut i32) -> &'static mut i32 { + | -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32` +... +LL | GeneratorState::Complete(c) => return c, + | ^ lifetime `'static` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/generator/generator-with-nll.rs b/src/test/ui/generator/generator-with-nll.rs index 87afa57ab5198..cee3e6d226c12 100644 --- a/src/test/ui/generator/generator-with-nll.rs +++ b/src/test/ui/generator/generator-with-nll.rs @@ -1,5 +1,4 @@ #![feature(generators)] -#![feature(nll)] fn main() { || { diff --git a/src/test/ui/generator/generator-with-nll.stderr b/src/test/ui/generator/generator-with-nll.stderr index c683ea1a3094b..14199aeb93056 100644 --- a/src/test/ui/generator/generator-with-nll.stderr +++ b/src/test/ui/generator/generator-with-nll.stderr @@ -1,9 +1,9 @@ error[E0626]: borrow may still be in use when generator yields - --> $DIR/generator-with-nll.rs:8:17 + --> $DIR/generator-with-nll.rs:7:17 | LL | let b = &mut true; | ^^^^^^^^^ -LL | //~^ borrow may still be in use when generator yields +LL | LL | yield (); | -------- possible yield occurs here diff --git a/src/test/ui/generator/issue-48048.stderr b/src/test/ui/generator/issue-48048.stderr index aeea10225091f..234235839164c 100644 --- a/src/test/ui/generator/issue-48048.stderr +++ b/src/test/ui/generator/issue-48048.stderr @@ -1,7 +1,7 @@ error[E0626]: borrow may still be in use when generator yields --> $DIR/issue-48048.rs:9:9 | -LL | x.0({ //~ ERROR borrow may still be in use when generator yields +LL | x.0({ | ^^^ LL | yield; | ----- possible yield occurs here diff --git a/src/test/ui/generator/issue-53548-1.rs b/src/test/ui/generator/issue-53548-1.rs new file mode 100644 index 0000000000000..df11800731c72 --- /dev/null +++ b/src/test/ui/generator/issue-53548-1.rs @@ -0,0 +1,20 @@ +// A variant of #53548 that does not actually require generators, +// but which encountered the same ICE/error. See `issue-53548.rs` +// for details. +// +// compile-pass + +use std::cell::RefCell; +use std::rc::Rc; + +trait Trait: 'static {} + +struct Store { + inner: Rc>>, +} + +fn main() { + let store = Store:: fn(&(dyn Trait + 'a))>> { + inner: Default::default(), + }; +} diff --git a/src/test/ui/generator/issue-53548.rs b/src/test/ui/generator/issue-53548.rs new file mode 100644 index 0000000000000..73a2bcdd55538 --- /dev/null +++ b/src/test/ui/generator/issue-53548.rs @@ -0,0 +1,38 @@ +// Regression test for #53548. The `Box` type below is +// expanded to `Box`, but the generator "witness" +// that results is `for<'r> { Box }`. The WF code was +// encountering an ICE (when debug-assertions were enabled) and an +// unexpected compilation error (without debug-asserions) when trying +// to process this `'r` region bound. In particular, to be WF, the +// region bound must meet the requirements of the trait, and hence we +// got `for<'r> { 'r: 'static }`. This would ICE because the `Binder` +// constructor we were using was assering that no higher-ranked +// regions were involved (because the WF code is supposed to skip +// those). The error (if debug-asserions were disabled) came because +// we obviously cannot prove that `'r: 'static` for any region `'r`. +// Pursuant with our "lazy WF" strategy for higher-ranked regions, the +// fix is not to require that `for<'r> { 'r: 'static }` holds (this is +// also analogous to what we would do for higher-ranked regions +// appearing within the trait in other positions). +// +// compile-pass + +#![feature(generators)] + +use std::cell::RefCell; +use std::rc::Rc; + +trait Trait: 'static {} + +struct Store { + inner: Rc>>, +} + +fn main() { + Box::new(static move || { + let store = Store::> { + inner: Default::default(), + }; + yield (); + }); +} diff --git a/src/test/ui/generator/issue-61442-stmt-expr-with-drop.rs b/src/test/ui/generator/issue-61442-stmt-expr-with-drop.rs new file mode 100644 index 0000000000000..ce4642020f0f1 --- /dev/null +++ b/src/test/ui/generator/issue-61442-stmt-expr-with-drop.rs @@ -0,0 +1,32 @@ +// Test that we don't consider temporaries for statement expressions as live +// across yields + +// check-pass +// edition:2018 + +#![feature(async_await, generators, generator_trait)] + +use std::ops::Generator; + +async fn drop_and_await() { + async {}; + async {}.await; +} + +fn drop_and_yield() { + let x = || { + String::new(); + yield; + }; + Box::pin(x).as_mut().resume(); + let y = static || { + String::new(); + yield; + }; + Box::pin(y).as_mut().resume(); +} + +fn main() { + drop_and_await(); + drop_and_yield(); +} diff --git a/src/test/ui/generator/no-arguments-on-generators.stderr b/src/test/ui/generator/no-arguments-on-generators.stderr index 521001293afa1..23ae21585fd38 100644 --- a/src/test/ui/generator/no-arguments-on-generators.stderr +++ b/src/test/ui/generator/no-arguments-on-generators.stderr @@ -1,9 +1,8 @@ error[E0628]: generators cannot have explicit arguments --> $DIR/no-arguments-on-generators.rs:4:15 | -LL | let gen = |start| { //~ ERROR generators cannot have explicit arguments +LL | let gen = |start| { | ^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0628`. diff --git a/src/test/ui/generator/pattern-borrow.stderr b/src/test/ui/generator/pattern-borrow.stderr index 50442828d8df1..d78da51049150 100644 --- a/src/test/ui/generator/pattern-borrow.stderr +++ b/src/test/ui/generator/pattern-borrow.stderr @@ -1,7 +1,7 @@ error[E0626]: borrow may still be in use when generator yields --> $DIR/pattern-borrow.rs:9:24 | -LL | if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields +LL | if let Test::A(ref _a) = test { | ^^^^^^ LL | yield (); | -------- possible yield occurs here diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr b/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr deleted file mode 100644 index 01eea627351fb..0000000000000 --- a/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0521]: borrowed data escapes outside of generator - --> $DIR/ref-escapes-but-not-over-yield.rs:11:9 - | -LL | let mut a = &3; - | ----- `a` is declared here, outside of the generator body -... -LL | a = &b; - | ^^^^-- - | | | - | | borrow is only valid in the generator body - | reference to `b` escapes the generator body here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.rs b/src/test/ui/generator/ref-escapes-but-not-over-yield.rs index 8c576581ad8dd..3856d8233bcc0 100644 --- a/src/test/ui/generator/ref-escapes-but-not-over-yield.rs +++ b/src/test/ui/generator/ref-escapes-but-not-over-yield.rs @@ -9,7 +9,7 @@ fn foo(x: &i32) { yield(); let b = 5; a = &b; - //~^ ERROR `b` does not live long enough + //~^ ERROR borrowed data escapes outside of generator }; } diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr b/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr index 29299b2405a00..de533e4d5ff7b 100644 --- a/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr +++ b/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr @@ -1,14 +1,14 @@ -error[E0597]: `b` does not live long enough - --> $DIR/ref-escapes-but-not-over-yield.rs:11:14 +error[E0521]: borrowed data escapes outside of generator + --> $DIR/ref-escapes-but-not-over-yield.rs:11:9 | +LL | let mut a = &3; + | ----- `a` is declared here, outside of the generator body +... LL | a = &b; - | ^ borrowed value does not live long enough -LL | //~^ ERROR `b` does not live long enough -LL | }; - | - `b` dropped here while still borrowed -LL | } - | - borrowed value needs to live until here + | ^^^^-- + | | | + | | borrow is only valid in the generator body + | reference to `b` escapes the generator body here error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index c98f42e62168e..c2caac7ebe2e7 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -3,7 +3,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t | LL | let mut gen = move || { | __________________________^ -LL | | //~^ ERROR the size for values of type +LL | | LL | | yield s[..]; LL | | }; | |____^ doesn't have a size known at compile-time diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr index caf92f0ec693e..404d3069f79f3 100644 --- a/src/test/ui/generator/static-not-unpin.stderr +++ b/src/test/ui/generator/static-not-unpin.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]: std::marker::Unpin` is not satisfied --> $DIR/static-not-unpin.rs:14:5 | -LL | assert_unpin(generator); //~ ERROR std::marker::Unpin` is not satisfied +LL | assert_unpin(generator); | ^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` | note: required by `assert_unpin` diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.rs b/src/test/ui/generator/type-mismatch-signature-deduction.rs new file mode 100644 index 0000000000000..b9c6bc5d0796e --- /dev/null +++ b/src/test/ui/generator/type-mismatch-signature-deduction.rs @@ -0,0 +1,17 @@ +#![feature(generators, generator_trait)] + +use std::ops::Generator; + +fn foo() -> impl Generator { + || { + if false { + return Ok(6); //~ ERROR mismatched types [E0308] + } + + yield (); + + 5 + } +} + +fn main() {} diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr new file mode 100644 index 0000000000000..35d3f95c3e9e4 --- /dev/null +++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/type-mismatch-signature-deduction.rs:8:20 + | +LL | return Ok(6); + | ^^^^^ expected i32, found enum `std::result::Result` + | + = note: expected type `i32` + found type `std::result::Result<{integer}, _>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/generator/yield-in-args.nll.stderr b/src/test/ui/generator/yield-in-args.nll.stderr deleted file mode 100644 index f753daafa9741..0000000000000 --- a/src/test/ui/generator/yield-in-args.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0626]: borrow may still be in use when generator yields - --> $DIR/yield-in-args.rs:8:13 - | -LL | foo(&b, yield); //~ ERROR - | ^^ ----- possible yield occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0626`. diff --git a/src/test/ui/generator/yield-in-args.stderr b/src/test/ui/generator/yield-in-args.stderr index f53677b5312ed..ee6d22c27cde8 100644 --- a/src/test/ui/generator/yield-in-args.stderr +++ b/src/test/ui/generator/yield-in-args.stderr @@ -1,8 +1,8 @@ error[E0626]: borrow may still be in use when generator yields - --> $DIR/yield-in-args.rs:8:14 + --> $DIR/yield-in-args.rs:8:13 | -LL | foo(&b, yield); //~ ERROR - | ^ ----- possible yield occurs here +LL | foo(&b, yield); + | ^^ ----- possible yield occurs here error: aborting due to previous error diff --git a/src/test/ui/generator/yield-in-const.stderr b/src/test/ui/generator/yield-in-const.stderr index e531bd6ef9ff5..663bb70d7a07f 100644 --- a/src/test/ui/generator/yield-in-const.stderr +++ b/src/test/ui/generator/yield-in-const.stderr @@ -6,4 +6,3 @@ LL | const A: u8 = { yield 3u8; 3u8}; error: aborting due to previous error -For more information about this error, try `rustc --explain E0627`. diff --git a/src/test/ui/generator/yield-in-function.stderr b/src/test/ui/generator/yield-in-function.stderr index 981c9f8339f1f..e12b0e6843e41 100644 --- a/src/test/ui/generator/yield-in-function.stderr +++ b/src/test/ui/generator/yield-in-function.stderr @@ -6,4 +6,3 @@ LL | fn main() { yield; } error: aborting due to previous error -For more information about this error, try `rustc --explain E0627`. diff --git a/src/test/ui/generator/yield-in-static.stderr b/src/test/ui/generator/yield-in-static.stderr index 46d341f3dcfba..220520c3862ca 100644 --- a/src/test/ui/generator/yield-in-static.stderr +++ b/src/test/ui/generator/yield-in-static.stderr @@ -6,4 +6,3 @@ LL | static B: u8 = { yield 3u8; 3u8}; error: aborting due to previous error -For more information about this error, try `rustc --explain E0627`. diff --git a/src/test/ui/generator/yield-while-iterating.nll.stderr b/src/test/ui/generator/yield-while-iterating.nll.stderr deleted file mode 100644 index 2dc12f843b220..0000000000000 --- a/src/test/ui/generator/yield-while-iterating.nll.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0626]: borrow may still be in use when generator yields - --> $DIR/yield-while-iterating.rs:13:18 - | -LL | for p in &x { //~ ERROR - | ^^ -LL | yield(); - | ------- possible yield occurs here - -error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/yield-while-iterating.rs:58:20 - | -LL | let mut b = || { - | -- mutable borrow occurs here -LL | for p in &mut x { - | - first borrow occurs due to use of `x` in generator -... -LL | println!("{}", x[0]); //~ ERROR - | ^ immutable borrow occurs here -LL | Pin::new(&mut b).resume(); - | ------ mutable borrow later used here - -error: aborting due to 2 previous errors - -Some errors occurred: E0502, E0626. -For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/generator/yield-while-iterating.stderr b/src/test/ui/generator/yield-while-iterating.stderr index 1e3e31470e9d6..6a96b25b19fb4 100644 --- a/src/test/ui/generator/yield-while-iterating.stderr +++ b/src/test/ui/generator/yield-while-iterating.stderr @@ -1,8 +1,8 @@ error[E0626]: borrow may still be in use when generator yields - --> $DIR/yield-while-iterating.rs:13:19 + --> $DIR/yield-while-iterating.rs:13:18 | -LL | for p in &x { //~ ERROR - | ^ +LL | for p in &x { + | ^^ LL | yield(); | ------- possible yield occurs here @@ -12,15 +12,14 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as muta LL | let mut b = || { | -- mutable borrow occurs here LL | for p in &mut x { - | - previous borrow occurs due to use of `x` in closure + | - first borrow occurs due to use of `x` in generator ... -LL | println!("{}", x[0]); //~ ERROR +LL | println!("{}", x[0]); | ^ immutable borrow occurs here LL | Pin::new(&mut b).resume(); -LL | } - | - mutable borrow ends here + | ------ mutable borrow later used here error: aborting due to 2 previous errors -Some errors occurred: E0502, E0626. +Some errors have detailed explanations: E0502, E0626. For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/generator/yield-while-local-borrowed.rs b/src/test/ui/generator/yield-while-local-borrowed.rs index 38061e71358c4..b643bbf3376fb 100644 --- a/src/test/ui/generator/yield-while-local-borrowed.rs +++ b/src/test/ui/generator/yield-while-local-borrowed.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z borrowck=compare - #![feature(generators, generator_trait)] use std::ops::{GeneratorState, Generator}; @@ -13,8 +11,7 @@ fn borrow_local_inline() { // `b` and gets extended by region inference.) let mut b = move || { let a = &mut 3; - //~^ ERROR borrow may still be in use when generator yields (Ast) - //~| ERROR borrow may still be in use when generator yields (Mir) + //~^ ERROR borrow may still be in use when generator yields yield(); println!("{}", a); }; @@ -41,8 +38,7 @@ fn borrow_local() { let a = 3; { let b = &a; - //~^ ERROR borrow may still be in use when generator yields (Ast) - //~| ERROR borrow may still be in use when generator yields (Mir) + //~^ ERROR borrow may still be in use when generator yields yield(); println!("{}", b); } diff --git a/src/test/ui/generator/yield-while-local-borrowed.stderr b/src/test/ui/generator/yield-while-local-borrowed.stderr index 56f425b7e70a0..c1513ef9b7157 100644 --- a/src/test/ui/generator/yield-while-local-borrowed.stderr +++ b/src/test/ui/generator/yield-while-local-borrowed.stderr @@ -1,39 +1,21 @@ -error[E0626]: borrow may still be in use when generator yields (Ast) - --> $DIR/yield-while-local-borrowed.rs:15:22 - | -LL | let a = &mut 3; - | ^ -... -LL | yield(); - | ------- possible yield occurs here - -error[E0626]: borrow may still be in use when generator yields (Ast) - --> $DIR/yield-while-local-borrowed.rs:43:22 - | -LL | let b = &a; - | ^ -... -LL | yield(); - | ------- possible yield occurs here - -error[E0626]: borrow may still be in use when generator yields (Mir) - --> $DIR/yield-while-local-borrowed.rs:15:17 +error[E0626]: borrow may still be in use when generator yields + --> $DIR/yield-while-local-borrowed.rs:13:17 | LL | let a = &mut 3; | ^^^^^^ -... +LL | LL | yield(); | ------- possible yield occurs here -error[E0626]: borrow may still be in use when generator yields (Mir) - --> $DIR/yield-while-local-borrowed.rs:43:21 +error[E0626]: borrow may still be in use when generator yields + --> $DIR/yield-while-local-borrowed.rs:40:21 | LL | let b = &a; | ^^ -... +LL | LL | yield(); | ------- possible yield occurs here -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0626`. diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr b/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr deleted file mode 100644 index d0d6a98301e59..0000000000000 --- a/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access - --> $DIR/yield-while-ref-reborrowed.rs:36:20 - | -LL | let mut b = || { - | -- generator construction occurs here -LL | let a = &mut *x; - | - first borrow occurs due to use of `x` in generator -... -LL | println!("{}", x); //~ ERROR - | ^ second borrow occurs here -LL | Pin::new(&mut b).resume(); - | ------ first borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0501`. diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.stderr b/src/test/ui/generator/yield-while-ref-reborrowed.stderr index 5c9de279c02d8..4c37cd351732b 100644 --- a/src/test/ui/generator/yield-while-ref-reborrowed.stderr +++ b/src/test/ui/generator/yield-while-ref-reborrowed.stderr @@ -2,15 +2,14 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u --> $DIR/yield-while-ref-reborrowed.rs:36:20 | LL | let mut b = || { - | -- closure construction occurs here + | -- generator construction occurs here LL | let a = &mut *x; - | - previous borrow occurs due to use of `x` in closure + | - first borrow occurs due to use of `x` in generator ... -LL | println!("{}", x); //~ ERROR - | ^ borrow occurs here +LL | println!("{}", x); + | ^ second borrow occurs here LL | Pin::new(&mut b).resume(); -LL | } - | - borrow from closure ends here + | ------ first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/generic/generic-arg-mismatch-recover.stderr b/src/test/ui/generic/generic-arg-mismatch-recover.stderr index 37f6c61f06df3..fe36e807c777d 100644 --- a/src/test/ui/generic/generic-arg-mismatch-recover.stderr +++ b/src/test/ui/generic/generic-arg-mismatch-recover.stderr @@ -1,13 +1,13 @@ error[E0107]: wrong number of lifetime arguments: expected 1, found 2 --> $DIR/generic-arg-mismatch-recover.rs:6:20 | -LL | Foo::<'static, 'static, ()>(&0); //~ ERROR wrong number of lifetime arguments +LL | Foo::<'static, 'static, ()>(&0); | ^^^^^^^ unexpected lifetime argument error[E0308]: mismatched types --> $DIR/generic-arg-mismatch-recover.rs:6:33 | -LL | Foo::<'static, 'static, ()>(&0); //~ ERROR wrong number of lifetime arguments +LL | Foo::<'static, 'static, ()>(&0); | ^^ expected (), found integer | = note: expected type `&'static ()` @@ -16,16 +16,16 @@ LL | Foo::<'static, 'static, ()>(&0); //~ ERROR wrong number of lifetime arg error[E0107]: wrong number of lifetime arguments: expected 1, found 2 --> $DIR/generic-arg-mismatch-recover.rs:9:20 | -LL | Bar::<'static, 'static, ()>(&()); //~ ERROR wrong number of lifetime arguments +LL | Bar::<'static, 'static, ()>(&()); | ^^^^^^^ unexpected lifetime argument error[E0107]: wrong number of type arguments: expected 0, found 1 --> $DIR/generic-arg-mismatch-recover.rs:9:29 | -LL | Bar::<'static, 'static, ()>(&()); //~ ERROR wrong number of lifetime arguments +LL | Bar::<'static, 'static, ()>(&()); | ^^ unexpected type argument error: aborting due to 4 previous errors -Some errors occurred: E0107, E0308. +Some errors have detailed explanations: E0107, E0308. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/generic/generic-extern-lifetime.stderr b/src/test/ui/generic/generic-extern-lifetime.stderr index b31d2a88044c7..39372c9315831 100644 --- a/src/test/ui/generic/generic-extern-lifetime.stderr +++ b/src/test/ui/generic/generic-extern-lifetime.stderr @@ -1,19 +1,19 @@ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/generic-extern-lifetime.rs:6:24 | -LL | pub fn life2<'b>(x:&'a i32, y:&'b i32); //~ ERROR use of undeclared lifetime name `'a` +LL | pub fn life2<'b>(x:&'a i32, y:&'b i32); | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/generic-extern-lifetime.rs:8:36 | -LL | pub fn life4<'b>(x: for<'c> fn(&'a i32)); //~ ERROR use of undeclared lifetime name `'a` +LL | pub fn life4<'b>(x: for<'c> fn(&'a i32)); | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/generic-extern-lifetime.rs:11:38 | -LL | pub fn life7<'b>() -> for<'c> fn(&'a i32); //~ ERROR use of undeclared lifetime name `'a` +LL | pub fn life7<'b>() -> for<'c> fn(&'a i32); | ^^ undeclared lifetime error: aborting due to 3 previous errors diff --git a/src/test/ui/generic/generic-extern.stderr b/src/test/ui/generic/generic-extern.stderr index 1c978245f9c63..e7625abb1c831 100644 --- a/src/test/ui/generic/generic-extern.stderr +++ b/src/test/ui/generic/generic-extern.stderr @@ -1,7 +1,7 @@ error[E0044]: foreign items may not have type parameters --> $DIR/generic-extern.rs:2:5 | -LL | fn foo(); //~ ERROR foreign items may not have type parameters +LL | fn foo(); | ^^^^^^^^^^^^ can't have type parameters | = help: use specialization instead of type parameters by replacing them with concrete types like `u32` diff --git a/src/test/ui/generic/generic-lifetime-trait-impl.stderr b/src/test/ui/generic/generic-lifetime-trait-impl.stderr index 8f4a0f23670bf..4ae5098a121f5 100644 --- a/src/test/ui/generic/generic-lifetime-trait-impl.stderr +++ b/src/test/ui/generic/generic-lifetime-trait-impl.stderr @@ -4,7 +4,7 @@ error[E0195]: lifetime parameters or bounds on method `bar` do not match the tra LL | fn bar<'b, T: Bar<'b>>(self) -> &'b str; | ---------------- lifetimes in impl do not match this method in trait ... -LL | fn bar>(self) -> &'a str { panic!() } //~ ERROR lifetime +LL | fn bar>(self) -> &'a str { panic!() } | ^^^^^^^^^^^^ lifetimes do not match method in trait error: aborting due to previous error diff --git a/src/test/ui/generic/generic-no-mangle.stderr b/src/test/ui/generic/generic-no-mangle.stderr index 3da39f1dc17cb..f055a3ab83f76 100644 --- a/src/test/ui/generic/generic-no-mangle.stderr +++ b/src/test/ui/generic/generic-no-mangle.stderr @@ -3,7 +3,7 @@ error: functions generic over types or consts must be mangled | LL | #[no_mangle] | ------------ help: remove this attribute -LL | pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled +LL | pub fn foo() {} | ^^^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -17,7 +17,7 @@ error: functions generic over types or consts must be mangled | LL | #[no_mangle] | ------------ help: remove this attribute -LL | pub extern fn bar() {} //~ ERROR functions generic over types or consts must be mangled +LL | pub extern fn bar() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/glob-cycles.rs b/src/test/ui/glob-cycles.rs index 84f9e5d843608..f354cc885d00d 100644 --- a/src/test/ui/glob-cycles.rs +++ b/src/test/ui/glob-cycles.rs @@ -1,5 +1,5 @@ -// compile-pass -// skip-codegen +// check-pass + mod foo { pub use bar::*; pub use main as f; @@ -15,5 +15,4 @@ mod baz { pub use super::*; } - pub fn main() {} diff --git a/src/test/ui/glob-resolve1.stderr b/src/test/ui/glob-resolve1.stderr index 10a57aa6ca649..4958099ca7405 100644 --- a/src/test/ui/glob-resolve1.stderr +++ b/src/test/ui/glob-resolve1.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find function `fpriv` in this scope --> $DIR/glob-resolve1.rs:22:5 | -LL | fpriv(); //~ ERROR cannot find function `fpriv` in this scope +LL | fpriv(); | ^^^^^ not found in this scope help: possible candidate is found in another module, you can import it into scope | @@ -11,7 +11,7 @@ LL | use bar::fpriv; error[E0425]: cannot find function `epriv` in this scope --> $DIR/glob-resolve1.rs:23:5 | -LL | epriv(); //~ ERROR cannot find function `epriv` in this scope +LL | epriv(); | ^^^^^ not found in this scope help: possible candidate is found in another module, you can import it into scope | @@ -21,16 +21,13 @@ LL | use bar::epriv; error[E0423]: expected value, found enum `B` --> $DIR/glob-resolve1.rs:24:5 | -LL | B; //~ ERROR expected value, found enum `B` - | ^ - | - = note: did you mean to use one of the following variants? - - `B::B1` +LL | B; + | ^ help: try using the enum's variant: `B::B1` error[E0425]: cannot find value `C` in this scope --> $DIR/glob-resolve1.rs:25:5 | -LL | C; //~ ERROR cannot find value `C` in this scope +LL | C; | ^ not found in this scope help: possible candidate is found in another module, you can import it into scope | @@ -40,17 +37,17 @@ LL | use bar::C; error[E0425]: cannot find function `import` in this scope --> $DIR/glob-resolve1.rs:26:5 | -LL | import(); //~ ERROR: cannot find function `import` in this scope +LL | import(); | ^^^^^^ not found in this scope error[E0412]: cannot find type `A` in this scope --> $DIR/glob-resolve1.rs:28:11 | -LL | foo::(); //~ ERROR: cannot find type `A` in this scope +LL | foo::(); | ^ help: an enum with a similar name exists | -LL | foo::(); //~ ERROR: cannot find type `A` in this scope +LL | foo::(); | ^ help: possible candidate is found in another module, you can import it into scope | @@ -60,11 +57,11 @@ LL | use bar::A; error[E0412]: cannot find type `C` in this scope --> $DIR/glob-resolve1.rs:29:11 | -LL | foo::(); //~ ERROR: cannot find type `C` in this scope +LL | foo::(); | ^ help: an enum with a similar name exists | -LL | foo::(); //~ ERROR: cannot find type `C` in this scope +LL | foo::(); | ^ help: possible candidate is found in another module, you can import it into scope | @@ -74,11 +71,11 @@ LL | use bar::C; error[E0412]: cannot find type `D` in this scope --> $DIR/glob-resolve1.rs:30:11 | -LL | foo::(); //~ ERROR: cannot find type `D` in this scope +LL | foo::(); | ^ help: an enum with a similar name exists | -LL | foo::(); //~ ERROR: cannot find type `D` in this scope +LL | foo::(); | ^ help: possible candidate is found in another module, you can import it into scope | @@ -87,5 +84,5 @@ LL | use bar::D; error: aborting due to 8 previous errors -Some errors occurred: E0412, E0423, E0425. +Some errors have detailed explanations: E0412, E0423, E0425. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/hashmap-iter-value-lifetime.nll.stderr b/src/test/ui/hashmap-iter-value-lifetime.nll.stderr index cff58af3775c4..312a91adca678 100644 --- a/src/test/ui/hashmap-iter-value-lifetime.nll.stderr +++ b/src/test/ui/hashmap-iter-value-lifetime.nll.stderr @@ -4,8 +4,8 @@ error[E0502]: cannot borrow `my_stuff` as mutable because it is also borrowed as LL | let (_, thing) = my_stuff.iter().next().unwrap(); | -------- immutable borrow occurs here LL | -LL | my_stuff.clear(); //~ ERROR cannot borrow - | ^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | my_stuff.clear(); + | ^^^^^^^^ mutable borrow occurs here LL | LL | println!("{}", *thing); | ------ immutable borrow later used here diff --git a/src/test/ui/hashmap-iter-value-lifetime.stderr b/src/test/ui/hashmap-iter-value-lifetime.stderr index 99761dd1cd7f5..f7626b13bad36 100644 --- a/src/test/ui/hashmap-iter-value-lifetime.stderr +++ b/src/test/ui/hashmap-iter-value-lifetime.stderr @@ -4,11 +4,11 @@ error[E0502]: cannot borrow `my_stuff` as mutable because it is also borrowed as LL | let (_, thing) = my_stuff.iter().next().unwrap(); | -------- immutable borrow occurs here LL | -LL | my_stuff.clear(); //~ ERROR cannot borrow - | ^^^^^^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here +LL | my_stuff.clear(); + | ^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | +LL | println!("{}", *thing); + | ------ immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/hashmap-lifetimes.nll.stderr b/src/test/ui/hashmap-lifetimes.nll.stderr index 08b8e3e443a9b..aa8e890c168dc 100644 --- a/src/test/ui/hashmap-lifetimes.nll.stderr +++ b/src/test/ui/hashmap-lifetimes.nll.stderr @@ -3,8 +3,8 @@ error[E0502]: cannot borrow `my_stuff` as mutable because it is also borrowed as | LL | let mut it = my_stuff.iter(); | -------- immutable borrow occurs here -LL | my_stuff.insert(1, 43); //~ ERROR cannot borrow - | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | my_stuff.insert(1, 43); + | ^^^^^^^^ mutable borrow occurs here LL | it; | -- immutable borrow later used here diff --git a/src/test/ui/hashmap-lifetimes.stderr b/src/test/ui/hashmap-lifetimes.stderr index 81b2304f38102..497c7d1216cd9 100644 --- a/src/test/ui/hashmap-lifetimes.stderr +++ b/src/test/ui/hashmap-lifetimes.stderr @@ -3,11 +3,10 @@ error[E0502]: cannot borrow `my_stuff` as mutable because it is also borrowed as | LL | let mut it = my_stuff.iter(); | -------- immutable borrow occurs here -LL | my_stuff.insert(1, 43); //~ ERROR cannot borrow - | ^^^^^^^^ mutable borrow occurs here +LL | my_stuff.insert(1, 43); + | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | it; -LL | } - | - immutable borrow ends here + | -- immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/hidden-rt-injection.stderr b/src/test/ui/hidden-rt-injection.stderr index 6d63344882b22..3e288b72ec63d 100644 --- a/src/test/ui/hidden-rt-injection.stderr +++ b/src/test/ui/hidden-rt-injection.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `native` --> $DIR/hidden-rt-injection.rs:5:9 | -LL | use native; //~ ERROR unresolved import +LL | use native; | ^^^^^^ no `native` in the root error: aborting due to previous error diff --git a/src/test/ui/hidden-rt-injection2.stderr b/src/test/ui/hidden-rt-injection2.stderr index bbb45552f2c14..73f89b5856da5 100644 --- a/src/test/ui/hidden-rt-injection2.stderr +++ b/src/test/ui/hidden-rt-injection2.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `rt` --> $DIR/hidden-rt-injection2.rs:5:9 | -LL | use rt; //~ ERROR unresolved import +LL | use rt; | ^^ no `rt` in the root error: aborting due to previous error diff --git a/src/test/ui/higher-lifetime-bounds.rs b/src/test/ui/higher-lifetime-bounds.rs index 546f4d4366333..f3393347d90dc 100644 --- a/src/test/ui/higher-lifetime-bounds.rs +++ b/src/test/ui/higher-lifetime-bounds.rs @@ -58,12 +58,12 @@ struct S3(F) where for<'xa, 'xb: 'xa> F: Fn(&'xa i32, &'xb i32) -> &'xa i32; struct S_fnty(for<'xa, 'xb: 'xa> fn(&'xa i32, &'xb i32) -> &'xa i32); //~^ ERROR lifetime bounds cannot be used in this context -type T1 = Box Fn(&'xa i32, &'xb i32) -> &'xa i32>; +type T1 = Box Fn(&'xa i32, &'xb i32) -> &'xa i32>; //~^ ERROR lifetime bounds cannot be used in this context fn main() { let _ : Option fn(&'xa i32, &'xb i32) -> &'xa i32> = None; //~^ ERROR lifetime bounds cannot be used in this context - let _ : Option Fn(&'xa i32, &'xb i32) -> &'xa i32>> = None; + let _ : Option Fn(&'xa i32, &'xb i32) -> &'xa i32>> = None; //~^ ERROR lifetime bounds cannot be used in this context } diff --git a/src/test/ui/higher-lifetime-bounds.stderr b/src/test/ui/higher-lifetime-bounds.stderr index 431a89f5eb81b..bc6d2288cdfc4 100644 --- a/src/test/ui/higher-lifetime-bounds.stderr +++ b/src/test/ui/higher-lifetime-bounds.stderr @@ -47,10 +47,10 @@ LL | struct S_fnty(for<'xa, 'xb: 'xa> fn(&'xa i32, &'xb i32) -> &'xa i32); | ^^^ error: lifetime bounds cannot be used in this context - --> $DIR/higher-lifetime-bounds.rs:61:29 + --> $DIR/higher-lifetime-bounds.rs:61:33 | -LL | type T1 = Box Fn(&'xa i32, &'xb i32) -> &'xa i32>; - | ^^^ +LL | type T1 = Box Fn(&'xa i32, &'xb i32) -> &'xa i32>; + | ^^^ error: lifetime bounds cannot be used in this context --> $DIR/higher-lifetime-bounds.rs:65:34 @@ -59,10 +59,10 @@ LL | let _ : Option fn(&'xa i32, &'xb i32) -> &'xa i32> = | ^^^ error: lifetime bounds cannot be used in this context - --> $DIR/higher-lifetime-bounds.rs:67:38 + --> $DIR/higher-lifetime-bounds.rs:67:42 | -LL | let _ : Option Fn(&'xa i32, &'xb i32) -> &'xa i32>> = None; - | ^^^ +LL | let _ : Option Fn(&'xa i32, &'xb i32) -> &'xa i32>> = None; + | ^^^ error: aborting due to 11 previous errors diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr index 5fcb63e17bf31..9ec36f4c142e9 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr @@ -2,11 +2,11 @@ error: compilation successful --> $DIR/hr-subtype.rs:100:1 | LL | / fn main() { -LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful -LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful -LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful -LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful -LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful +LL | | +LL | | +LL | | +LL | | +LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr index 5fcb63e17bf31..9ec36f4c142e9 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr @@ -2,11 +2,11 @@ error: compilation successful --> $DIR/hr-subtype.rs:100:1 | LL | / fn main() { -LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful -LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful -LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful -LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful -LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful +LL | | +LL | | +LL | | +LL | | +LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr index 5fcb63e17bf31..9ec36f4c142e9 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr @@ -2,11 +2,11 @@ error: compilation successful --> $DIR/hr-subtype.rs:100:1 | LL | / fn main() { -LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful -LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful -LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful -LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful -LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful +LL | | +LL | | +LL | | +LL | | +LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr index 5fcb63e17bf31..9ec36f4c142e9 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr @@ -2,11 +2,11 @@ error: compilation successful --> $DIR/hr-subtype.rs:100:1 | LL | / fn main() { -LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful -LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful -LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful -LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful -LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful +LL | | +LL | | +LL | | +LL | | +LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr new file mode 100644 index 0000000000000..070fe12a2849f --- /dev/null +++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr @@ -0,0 +1,30 @@ +error: lifetime may not live long enough + --> $DIR/hr-subtype.rs:33:13 + | +LL | fn subtype<'x,'y:'x,'z:'y>() { + | -- -- lifetime `'y` defined here + | | + | lifetime `'x` defined here +LL | gimme::<$t2>(None::<$t1>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y` +... +LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), +LL | | fn(Inv<'y>)) } + | |__________________________________________________- in this macro invocation + +error: lifetime may not live long enough + --> $DIR/hr-subtype.rs:39:13 + | +LL | fn supertype<'x,'y:'x,'z:'y>() { + | -- -- lifetime `'y` defined here + | | + | lifetime `'x` defined here +LL | gimme::<$t1>(None::<$t2>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y` +... +LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), +LL | | fn(Inv<'y>)) } + | |__________________________________________________- in this macro invocation + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr index 5fcb63e17bf31..9ec36f4c142e9 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr @@ -2,11 +2,11 @@ error: compilation successful --> $DIR/hr-subtype.rs:100:1 | LL | / fn main() { -LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful -LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful -LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful -LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful -LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful +LL | | +LL | | +LL | | +LL | | +LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr new file mode 100644 index 0000000000000..e140eaadd48a5 --- /dev/null +++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr @@ -0,0 +1,16 @@ +error: lifetime may not live long enough + --> $DIR/hr-subtype.rs:39:13 + | +LL | fn supertype<'x,'y:'x,'z:'y>() { + | -- -- lifetime `'y` defined here + | | + | lifetime `'x` defined here +LL | gimme::<$t1>(None::<$t2>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y` +... +LL | / check! { free_x_vs_free_y: (fn(&'x u32), +LL | | fn(&'y u32)) } + | |__________________________________________- in this macro invocation + +error: aborting due to previous error + diff --git a/src/test/ui/hrtb/hrtb-cache-issue-54302.nll.stderr b/src/test/ui/hrtb/hrtb-cache-issue-54302.nll.stderr new file mode 100644 index 0000000000000..4de35d70c30a3 --- /dev/null +++ b/src/test/ui/hrtb/hrtb-cache-issue-54302.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/hrtb-cache-issue-54302.rs:19:5 + | +LL | assert_deserialize_owned::<&'static str>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr index 21d154eb2316c..77a5491cb63a7 100644 --- a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr +++ b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr @@ -1,7 +1,7 @@ error: implementation of `Deserialize` is not general enough --> $DIR/hrtb-cache-issue-54302.rs:19:5 | -LL | assert_deserialize_owned::<&'static str>(); //~ ERROR +LL | assert_deserialize_owned::<&'static str>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0` diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.stderr index 50e1af8f14231..3fb6baa35e144 100644 --- a/src/test/ui/hrtb/hrtb-conflate-regions.stderr +++ b/src/test/ui/hrtb/hrtb-conflate-regions.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `for<'a, 'b> SomeStruct: Foo<(&'a isize, &'b isize)>` is not satisfied --> $DIR/hrtb-conflate-regions.rs:28:10 | -LL | fn b() { want_foo2::(); } //~ ERROR +LL | fn b() { want_foo2::(); } | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a, 'b> Foo<(&'a isize, &'b isize)>` is not implemented for `SomeStruct` | = help: the following implementations were found: diff --git a/src/test/ui/hrtb/hrtb-debruijn-in-receiver.nll.stderr b/src/test/ui/hrtb/hrtb-debruijn-in-receiver.nll.stderr deleted file mode 100644 index 80ecc4741a2e8..0000000000000 --- a/src/test/ui/hrtb/hrtb-debruijn-in-receiver.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0499]: cannot borrow `foo` as mutable more than once at a time - --> $DIR/hrtb-debruijn-in-receiver.rs:17:5 - | -LL | foo.insert(); - | --- first mutable borrow occurs here -LL | foo.insert(); //~ ERROR cannot borrow - | ^^^ - | | - | second mutable borrow occurs here - | first borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr b/src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr index 85bff4ce7911f..70d5b3c2ec58c 100644 --- a/src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr +++ b/src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr @@ -3,10 +3,11 @@ error[E0499]: cannot borrow `foo` as mutable more than once at a time | LL | foo.insert(); | --- first mutable borrow occurs here -LL | foo.insert(); //~ ERROR cannot borrow - | ^^^ second mutable borrow occurs here -LL | } - | - first borrow ends here +LL | foo.insert(); + | ^^^ + | | + | second mutable borrow occurs here + | first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr index 8e8892552b701..d893cd606f1e4 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/hrtb-exists-forall-fn.rs:17:34 | -LL | let _: for<'b> fn(&'b u32) = foo(); //~ ERROR mismatched types +LL | let _: for<'b> fn(&'b u32) = foo(); | ^^^^^ expected concrete lifetime, found bound lifetime parameter 'b | = note: expected type `for<'b> fn(&'b u32)` diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr index f56b81759fede..f10e427a545fb 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `(): Trait fn(std::cell::Cell<&'b u32>)>` is not satisfied --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5 | -LL | foo::<()>(); //~ ERROR not satisfied +LL | foo::<()>(); | ^^^^^^^^^ the trait `Trait fn(std::cell::Cell<&'b u32>)>` is not implemented for `()` | = help: the following implementations were found: diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr index 77c1789852e52..b5d945fe15ca0 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5 | -LL | want_bar_for_any_ccx(b); //~ ERROR +LL | want_bar_for_any_ccx(b); | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` | = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr index 5914cb3eaa494..20a8fd459fa41 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied --> $DIR/hrtb-higher-ranker-supertraits.rs:18:5 | -LL | want_foo_for_any_tcx(f); //~ ERROR not satisfied +LL | want_foo_for_any_tcx(f); | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F` | = help: consider adding a `where for<'tcx> F: Foo<'tcx>` bound @@ -19,7 +19,7 @@ LL | | } error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied --> $DIR/hrtb-higher-ranker-supertraits.rs:35:5 | -LL | want_bar_for_any_ccx(b); //~ ERROR not satisfied +LL | want_bar_for_any_ccx(b); | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` | = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound diff --git a/src/test/ui/hrtb/hrtb-identity-fn-borrows.ast.nll.stderr b/src/test/ui/hrtb/hrtb-identity-fn-borrows.ast.nll.stderr deleted file mode 100644 index bbb95e8c8d440..0000000000000 --- a/src/test/ui/hrtb/hrtb-identity-fn-borrows.ast.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/hrtb-identity-fn-borrows.rs:17:5 - | -LL | let y = f.call(&x); - | -- borrow of `x` occurs here -LL | x = 5; //[ast]~ ERROR cannot assign - | ^^^^^ assignment to borrowed `x` occurs here -... -LL | drop(y); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/hrtb/hrtb-identity-fn-borrows.ast.stderr b/src/test/ui/hrtb/hrtb-identity-fn-borrows.ast.stderr deleted file mode 100644 index f6f9200a354d5..0000000000000 --- a/src/test/ui/hrtb/hrtb-identity-fn-borrows.ast.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/hrtb-identity-fn-borrows.rs:17:5 - | -LL | let y = f.call(&x); - | - borrow of `x` occurs here -LL | x = 5; //[ast]~ ERROR cannot assign - | ^^^^^ assignment to borrowed `x` occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/hrtb/hrtb-identity-fn-borrows.mir.stderr b/src/test/ui/hrtb/hrtb-identity-fn-borrows.mir.stderr deleted file mode 100644 index bbb95e8c8d440..0000000000000 --- a/src/test/ui/hrtb/hrtb-identity-fn-borrows.mir.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/hrtb-identity-fn-borrows.rs:17:5 - | -LL | let y = f.call(&x); - | -- borrow of `x` occurs here -LL | x = 5; //[ast]~ ERROR cannot assign - | ^^^^^ assignment to borrowed `x` occurs here -... -LL | drop(y); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/hrtb/hrtb-identity-fn-borrows.rs b/src/test/ui/hrtb/hrtb-identity-fn-borrows.rs index 35b39a9a69dd0..89fc4705a787f 100644 --- a/src/test/ui/hrtb/hrtb-identity-fn-borrows.rs +++ b/src/test/ui/hrtb/hrtb-identity-fn-borrows.rs @@ -1,9 +1,6 @@ // Test that the `'a` in the where clause correctly links the region // of the output to the region of the input. -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - trait FnLike { fn call(&self, arg: A) -> R; } @@ -14,8 +11,7 @@ fn call_repeatedly(f: F) // Result is stored: cannot re-assign `x` let mut x = 3; let y = f.call(&x); - x = 5; //[ast]~ ERROR cannot assign - //[mir]~^ ERROR cannot assign to `x` because it is borrowed + x = 5; //~ ERROR cannot assign to `x` because it is borrowed // Result is not stored: can re-assign `x` let mut x = 3; diff --git a/src/test/ui/hrtb/hrtb-identity-fn-borrows.stderr b/src/test/ui/hrtb/hrtb-identity-fn-borrows.stderr new file mode 100644 index 0000000000000..4886a3c8bad62 --- /dev/null +++ b/src/test/ui/hrtb/hrtb-identity-fn-borrows.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/hrtb-identity-fn-borrows.rs:14:5 + | +LL | let y = f.call(&x); + | -- borrow of `x` occurs here +LL | x = 5; + | ^^^^^ assignment to borrowed `x` occurs here +... +LL | drop(y); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr index fe2bc1f222504..115851ddf9385 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied --> $DIR/hrtb-just-for-static.rs:24:5 | -LL | want_hrtb::() //~ ERROR +LL | want_hrtb::() | ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt` | = help: the following implementations were found: @@ -18,7 +18,7 @@ LL | | } error[E0277]: the trait bound `for<'a> &'a u32: Foo<&'a isize>` is not satisfied --> $DIR/hrtb-just-for-static.rs:30:5 | -LL | want_hrtb::<&'a u32>() //~ ERROR +LL | want_hrtb::<&'a u32>() | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `&'a u32` | = help: the following implementations were found: diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr new file mode 100644 index 0000000000000..0522fc45d68f0 --- /dev/null +++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr @@ -0,0 +1,77 @@ +warning: function cannot return without recursing + --> $DIR/hrtb-perfect-forwarding.rs:22:1 + | +LL | / fn no_hrtb<'b,T>(mut t: T) +LL | | where T : Bar<&'b isize> +LL | | { +LL | | // OK -- `T : Bar<&'b isize>`, and thus the impl above ensures that +LL | | // `&mut T : Bar<&'b isize>`. +LL | | no_hrtb(&mut t); + | | --------------- recursive call site +LL | | } + | |_^ cannot return without recursing + | + = note: #[warn(unconditional_recursion)] on by default + = help: a `loop` may express intention better if this is on purpose + +warning: function cannot return without recursing + --> $DIR/hrtb-perfect-forwarding.rs:30:1 + | +LL | / fn bar_hrtb(mut t: T) +LL | | where T : for<'b> Bar<&'b isize> +LL | | { +LL | | // OK -- `T : for<'b> Bar<&'b isize>`, and thus the impl above +... | +LL | | bar_hrtb(&mut t); + | | ---------------- recursive call site +LL | | } + | |_^ cannot return without recursing + | + = help: a `loop` may express intention better if this is on purpose + +warning: function cannot return without recursing + --> $DIR/hrtb-perfect-forwarding.rs:39:1 + | +LL | / fn foo_hrtb_bar_not<'b,T>(mut t: T) +LL | | where T : for<'a> Foo<&'a isize> + Bar<&'b isize> +LL | | { +LL | | // Not OK -- The forwarding impl for `Foo` requires that `Bar` also +... | +LL | | foo_hrtb_bar_not(&mut t); + | | ------------------------ recursive call site +LL | | } + | |_^ cannot return without recursing + | + = help: a `loop` may express intention better if this is on purpose + +error: higher-ranked subtype error + --> $DIR/hrtb-perfect-forwarding.rs:46:5 + | +LL | foo_hrtb_bar_not(&mut t); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/hrtb-perfect-forwarding.rs:46:5 + | +LL | fn foo_hrtb_bar_not<'b,T>(mut t: T) + | -- lifetime `'b` defined here +... +LL | foo_hrtb_bar_not(&mut t); + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +warning: function cannot return without recursing + --> $DIR/hrtb-perfect-forwarding.rs:49:1 + | +LL | / fn foo_hrtb_bar_hrtb(mut t: T) +LL | | where T : for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize> +LL | | { +LL | | // OK -- now we have `T : for<'b> Bar&'b isize>`. +LL | | foo_hrtb_bar_hrtb(&mut t); + | | ------------------------- recursive call site +LL | | } + | |_^ cannot return without recursing + | + = help: a `loop` may express intention better if this is on purpose + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr index ea08af0164061..9bc8cd67a82af 100644 --- a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr +++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/hrtb-perfect-forwarding.rs:46:5 | -LL | foo_hrtb_bar_not(&mut t); //~ ERROR mismatched types +LL | foo_hrtb_bar_not(&mut t); | ^^^^^^^^^^^^^^^^ one type is more general than the other | = note: expected type `Bar<&'a isize>` diff --git a/src/test/ui/hrtb/issue-58451.stderr b/src/test/ui/hrtb/issue-58451.stderr index 79c24855dc96c..4648c0182b98e 100644 --- a/src/test/ui/hrtb/issue-58451.stderr +++ b/src/test/ui/hrtb/issue-58451.stderr @@ -8,7 +8,7 @@ LL | | I::Item: for<'a> Into<&'a ()>, LL | | {} | |__- defined here ... -LL | f(&[f()]); //~ ERROR this function takes 1 parameter +LL | f(&[f()]); | ^^^ expected 1 parameter error: aborting due to previous error diff --git a/src/test/ui/huge-array-simple.rs b/src/test/ui/huge-array-simple.rs index 8b244a47232fa..0ff27168a7d86 100644 --- a/src/test/ui/huge-array-simple.rs +++ b/src/test/ui/huge-array-simple.rs @@ -1,6 +1,10 @@ // error-pattern: too big for the current architecture // normalize-stderr-test "; \d+]" -> "; N]" + +// FIXME https://github.com/rust-lang/rust/issues/59774 +// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" #![allow(exceeding_bitshifts)] #[cfg(target_pointer_width = "64")] diff --git a/src/test/ui/huge-array.rs b/src/test/ui/huge-array.rs index 0608b23dac6b1..f58dcd5806761 100644 --- a/src/test/ui/huge-array.rs +++ b/src/test/ui/huge-array.rs @@ -1,5 +1,9 @@ // error-pattern:; 1518600000 +// FIXME https://github.com/rust-lang/rust/issues/59774 +// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" + fn generic(t: T) { let s: [T; 1518600000] = [t; 1518600000]; } diff --git a/src/test/ui/huge-enum.rs b/src/test/ui/huge-enum.rs index 71c8fd55b23f3..2492afbdc8f81 100644 --- a/src/test/ui/huge-enum.rs +++ b/src/test/ui/huge-enum.rs @@ -1,6 +1,10 @@ // normalize-stderr-test "std::option::Option<\[u32; \d+\]>" -> "TYPE" // normalize-stderr-test "\[u32; \d+\]" -> "TYPE" +// FIXME https://github.com/rust-lang/rust/issues/59774 +// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" + #[cfg(target_pointer_width = "32")] fn main() { let big: Option<[u32; (1<<29)-1]> = None; diff --git a/src/test/ui/huge-struct.rs b/src/test/ui/huge-struct.rs index 74e43cc6472be..dc7d75a6f028e 100644 --- a/src/test/ui/huge-struct.rs +++ b/src/test/ui/huge-struct.rs @@ -2,6 +2,10 @@ // normalize-stderr-test "S1M" -> "SXX" // error-pattern: too big for the current +// FIXME https://github.com/rust-lang/rust/issues/59774 +// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" + struct S32 { v0: T, v1: T, diff --git a/src/test/ui/hygiene/arguments.stderr b/src/test/ui/hygiene/arguments.stderr index 4cf35be22fad9..d072086e086d6 100644 --- a/src/test/ui/hygiene/arguments.stderr +++ b/src/test/ui/hygiene/arguments.stderr @@ -1,7 +1,7 @@ error[E0412]: cannot find type `S` in this scope --> $DIR/arguments.rs:16:8 | -LL | m!(S, S); //~ ERROR cannot find type `S` in this scope +LL | m!(S, S); | ^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/hygiene/assoc_item_ctxt.stderr b/src/test/ui/hygiene/assoc_item_ctxt.stderr index d89f395d8c170..0d1c73eef0e23 100644 --- a/src/test/ui/hygiene/assoc_item_ctxt.stderr +++ b/src/test/ui/hygiene/assoc_item_ctxt.stderr @@ -1,7 +1,7 @@ error[E0407]: method `method` is not a member of trait `Tr` --> $DIR/assoc_item_ctxt.rs:35:13 | -LL | fn method() {} //~ ERROR method `method` is not a member of trait `Tr` +LL | fn method() {} | ^^^^^^^^^^^^^^ not a member of trait `Tr` ... LL | mac_trait_impl!(); @@ -13,7 +13,7 @@ error[E0046]: not all trait items implemented, missing: `method` LL | fn method(); | ------------ `method` from trait ... -LL | impl Tr for u8 { //~ ERROR not all trait items implemented, missing: `method` +LL | impl Tr for u8 { | ^^^^^^^^^^^^^^ missing `method` in implementation ... LL | mac_trait_impl!(); @@ -21,5 +21,5 @@ LL | mac_trait_impl!(); error: aborting due to 2 previous errors -Some errors occurred: E0046, E0407. +Some errors have detailed explanations: E0046, E0407. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/hygiene/assoc_ty_bindings.rs b/src/test/ui/hygiene/assoc_ty_bindings.rs index eb0ca6a7d5f76..93cf7591a0db2 100644 --- a/src/test/ui/hygiene/assoc_ty_bindings.rs +++ b/src/test/ui/hygiene/assoc_ty_bindings.rs @@ -1,8 +1,8 @@ +// check-pass // ignore-pretty pretty-printing is unhygienic #![feature(decl_macro, associated_type_defaults)] -// compile-pass -// skip-codegen + trait Base { type AssocTy; fn f(); @@ -35,5 +35,4 @@ macro mac() { mac!(); - fn main() {} diff --git a/src/test/ui/hygiene/fields-definition.stderr b/src/test/ui/hygiene/fields-definition.stderr index d6d25d7fa0c2c..a30650d88e28d 100644 --- a/src/test/ui/hygiene/fields-definition.stderr +++ b/src/test/ui/hygiene/fields-definition.stderr @@ -3,7 +3,7 @@ error[E0124]: field `a` is already declared | LL | a: u8, | ----- `a` first declared here -LL | $a: u8, //~ ERROR field `a` is already declared +LL | $a: u8, | ^^ field already declared ... LL | legacy!(a); diff --git a/src/test/ui/hygiene/fields-move.nll.stderr b/src/test/ui/hygiene/fields-move.nll.stderr deleted file mode 100644 index f72a52e2535d2..0000000000000 --- a/src/test/ui/hygiene/fields-move.nll.stderr +++ /dev/null @@ -1,38 +0,0 @@ -error[E0382]: use of moved value: `foo.x` - --> $DIR/fields-move.rs:18:9 - | -LL | $foo.x //~ ERROR use of moved value: `foo.x` - | ^^^^^^ value used here after move -... -LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x` - | ----- value moved here -LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x` - | ----------------- in this macro invocation - | - = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `foo.x` - --> $DIR/fields-move.rs:28:42 - | -LL | $foo.x - | ------ value moved here -... -LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x` - | ^^^^^ value used here after move - | - = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `foo.x` - --> $DIR/fields-move.rs:29:42 - | -LL | $foo.x //~ ERROR use of moved value: `foo.x` - | ------ value moved here -... -LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x` - | ^^^^^ value used here after move - | - = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/hygiene/fields-move.stderr b/src/test/ui/hygiene/fields-move.stderr index a5eeadff4dc05..562f60e31b5d2 100644 --- a/src/test/ui/hygiene/fields-move.stderr +++ b/src/test/ui/hygiene/fields-move.stderr @@ -1,35 +1,34 @@ error[E0382]: use of moved value: `foo.x` - --> $DIR/fields-move.rs:28:42 + --> $DIR/fields-move.rs:18:9 | -LL | $foo.x - | ------ value moved here +LL | $foo.x + | ^^^^^^ value used here after move ... -LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x` - | ^^^^^ value used here after move +LL | assert_two_copies(copy_modern!(foo), foo.x); + | ----- value moved here +LL | assert_two_copies(copy_legacy!(foo), foo.x); + | ----------------- in this macro invocation | = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait error[E0382]: use of moved value: `foo.x` - --> $DIR/fields-move.rs:18:9 + --> $DIR/fields-move.rs:28:42 | LL | $foo.x | ------ value moved here ... -LL | $foo.x //~ ERROR use of moved value: `foo.x` - | ^^^^^^ value used here after move -... -LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x` - | ----------------- in this macro invocation +LL | assert_two_copies(copy_modern!(foo), foo.x); + | ^^^^^ value used here after move | = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait error[E0382]: use of moved value: `foo.x` --> $DIR/fields-move.rs:29:42 | -LL | $foo.x - | ------ value moved here +LL | $foo.x + | ------ value moved here ... -LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x` +LL | assert_two_copies(copy_legacy!(foo), foo.x); | ^^^^^ value used here after move | = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait diff --git a/src/test/ui/hygiene/fields-numeric-borrowck.nll.stderr b/src/test/ui/hygiene/fields-numeric-borrowck.nll.stderr deleted file mode 100644 index fb90825c0d93d..0000000000000 --- a/src/test/ui/hygiene/fields-numeric-borrowck.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0499]: cannot borrow `s.0` as mutable more than once at a time - --> $DIR/fields-numeric-borrowck.rs:6:16 - | -LL | let borrow1 = &mut s.0; - | -------- first mutable borrow occurs here -LL | let S { 0: ref mut borrow2 } = s; - | ^^^^^^^^^^^^^^^ second mutable borrow occurs here -... -LL | borrow1.use_mut(); - | ------- first borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/hygiene/fields-numeric-borrowck.stderr b/src/test/ui/hygiene/fields-numeric-borrowck.stderr index 11b5fd70aff9f..fb90825c0d93d 100644 --- a/src/test/ui/hygiene/fields-numeric-borrowck.stderr +++ b/src/test/ui/hygiene/fields-numeric-borrowck.stderr @@ -2,12 +2,12 @@ error[E0499]: cannot borrow `s.0` as mutable more than once at a time --> $DIR/fields-numeric-borrowck.rs:6:16 | LL | let borrow1 = &mut s.0; - | --- first mutable borrow occurs here + | -------- first mutable borrow occurs here LL | let S { 0: ref mut borrow2 } = s; | ^^^^^^^^^^^^^^^ second mutable borrow occurs here ... -LL | } - | - first borrow ends here +LL | borrow1.use_mut(); + | ------- first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/hygiene/fields.stderr b/src/test/ui/hygiene/fields.stderr index 6d5b60fcb5b7f..20ea4e91067be 100644 --- a/src/test/ui/hygiene/fields.stderr +++ b/src/test/ui/hygiene/fields.stderr @@ -1,7 +1,7 @@ error: type `foo::S` is private --> $DIR/fields.rs:15:17 | -LL | let s = S { x: 0 }; //~ ERROR type `foo::S` is private +LL | let s = S { x: 0 }; | ^^^^^^^^^^ ... LL | let s = foo::m!(S, x); @@ -10,7 +10,7 @@ LL | let s = foo::m!(S, x); error: type `foo::S` is private --> $DIR/fields.rs:16:17 | -LL | let _ = s.x; //~ ERROR type `foo::S` is private +LL | let _ = s.x; | ^ ... LL | let s = foo::m!(S, x); @@ -19,7 +19,7 @@ LL | let s = foo::m!(S, x); error: type `foo::T` is private --> $DIR/fields.rs:18:17 | -LL | let t = T(0); //~ ERROR type `foo::T` is private +LL | let t = T(0); | ^^^^ ... LL | let s = foo::m!(S, x); @@ -28,7 +28,7 @@ LL | let s = foo::m!(S, x); error: type `foo::T` is private --> $DIR/fields.rs:19:17 | -LL | let _ = t.0; //~ ERROR type `foo::T` is private +LL | let _ = t.0; | ^ ... LL | let s = foo::m!(S, x); diff --git a/src/test/ui/hygiene/for-loop.stderr b/src/test/ui/hygiene/for-loop.stderr index 755bf3e55f716..932c951e7a541 100644 --- a/src/test/ui/hygiene/for-loop.stderr +++ b/src/test/ui/hygiene/for-loop.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `iter` in this scope --> $DIR/for-loop.rs:6:9 | -LL | iter.next(); //~ ERROR cannot find value `iter` in this scope +LL | iter.next(); | ^^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/hygiene/generate-mod.stderr b/src/test/ui/hygiene/generate-mod.stderr index d9342d911592b..5e2c56d4bf4d4 100644 --- a/src/test/ui/hygiene/generate-mod.stderr +++ b/src/test/ui/hygiene/generate-mod.stderr @@ -1,19 +1,19 @@ error[E0412]: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:35:13 | -LL | genmod!(FromOutside, Outer); //~ ERROR cannot find type `FromOutside` in this scope +LL | genmod!(FromOutside, Outer); | ^^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `Outer` in this scope --> $DIR/generate-mod.rs:35:26 | -LL | genmod!(FromOutside, Outer); //~ ERROR cannot find type `FromOutside` in this scope +LL | genmod!(FromOutside, Outer); | ^^^^^ not found in this scope error[E0412]: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:19:18 | -LL | type A = FromOutside; //~ ERROR cannot find type `FromOutside` in this scope +LL | type A = FromOutside; | ^^^^^^^^^^^ not found in this scope ... LL | genmod_transparent!(); @@ -22,7 +22,7 @@ LL | genmod_transparent!(); error[E0412]: cannot find type `Outer` in this scope --> $DIR/generate-mod.rs:20:22 | -LL | type Inner = Outer; //~ ERROR cannot find type `Outer` in this scope +LL | type Inner = Outer; | ^^^^^ not found in this scope ... LL | genmod_transparent!(); @@ -31,7 +31,7 @@ LL | genmod_transparent!(); error[E0412]: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:28:18 | -LL | type A = FromOutside; //~ ERROR cannot find type `FromOutside` in this scope +LL | type A = FromOutside; | ^^^^^^^^^^^ not found in this scope ... LL | genmod_legacy!(); @@ -40,7 +40,7 @@ LL | genmod_legacy!(); error[E0412]: cannot find type `Outer` in this scope --> $DIR/generate-mod.rs:29:22 | -LL | type Inner = Outer; //~ ERROR cannot find type `Outer` in this scope +LL | type Inner = Outer; | ^^^^^ not found in this scope ... LL | genmod_legacy!(); diff --git a/src/test/ui/hygiene/globs.stderr b/src/test/ui/hygiene/globs.stderr index ad62b976251f0..7e0f4e4e0b8f3 100644 --- a/src/test/ui/hygiene/globs.stderr +++ b/src/test/ui/hygiene/globs.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find function `f` in this scope --> $DIR/globs.rs:22:9 | -LL | f(); //~ ERROR cannot find function `f` in this scope +LL | f(); | ^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -15,13 +15,13 @@ LL | use foo::f; error[E0425]: cannot find function `g` in this scope --> $DIR/globs.rs:15:5 | -LL | g(); //~ ERROR cannot find function `g` in this scope +LL | g(); | ^ not found in this scope ... LL | / m! { LL | | use bar::*; LL | | g(); -LL | | f(); //~ ERROR cannot find function `f` in this scope +LL | | f(); LL | | } | |_____- in this macro invocation help: possible candidates are found in other modules, you can import them into scope @@ -42,7 +42,7 @@ error[E0425]: cannot find function `f` in this scope LL | n!(f); | ------ in this macro invocation ... -LL | n!(f); //~ ERROR cannot find function `f` in this scope +LL | n!(f); | ^ not found in this scope error[E0425]: cannot find function `f` in this scope @@ -51,7 +51,7 @@ error[E0425]: cannot find function `f` in this scope LL | n!(f); | ------ in this macro invocation ... -LL | f //~ ERROR cannot find function `f` in this scope +LL | f | ^ not found in this scope error: aborting due to 4 previous errors diff --git a/src/test/ui/hygiene/hygienic-label-1.stderr b/src/test/ui/hygiene/hygienic-label-1.stderr index 9a55965d85fea..d61c0687c1665 100644 --- a/src/test/ui/hygiene/hygienic-label-1.stderr +++ b/src/test/ui/hygiene/hygienic-label-1.stderr @@ -1,8 +1,8 @@ error[E0426]: use of undeclared label `'x` --> $DIR/hygienic-label-1.rs:2:19 | -LL | () => { break 'x; } //~ ERROR use of undeclared label `'x` - | ^^ did you mean `'x`? +LL | () => { break 'x; } + | ^^ undeclared label `'x` ... LL | 'x: loop { foo!() } | ------ in this macro invocation diff --git a/src/test/ui/hygiene/hygienic-label-2.stderr b/src/test/ui/hygiene/hygienic-label-2.stderr index b7cb91d94f1b1..f23e741debe9d 100644 --- a/src/test/ui/hygiene/hygienic-label-2.stderr +++ b/src/test/ui/hygiene/hygienic-label-2.stderr @@ -1,8 +1,8 @@ error[E0426]: use of undeclared label `'x` --> $DIR/hygienic-label-2.rs:6:16 | -LL | foo!(break 'x); //~ ERROR use of undeclared label `'x` - | ^^ did you mean `'x`? +LL | foo!(break 'x); + | ^^ undeclared label `'x` error: aborting due to previous error diff --git a/src/test/ui/hygiene/hygienic-label-3.stderr b/src/test/ui/hygiene/hygienic-label-3.stderr index 227a39512b74f..0c4173a61aac4 100644 --- a/src/test/ui/hygiene/hygienic-label-3.stderr +++ b/src/test/ui/hygiene/hygienic-label-3.stderr @@ -1,8 +1,8 @@ error[E0426]: use of undeclared label `'x` --> $DIR/hygienic-label-3.rs:2:19 | -LL | () => { break 'x; } //~ ERROR use of undeclared label `'x` - | ^^ did you mean `'x`? +LL | () => { break 'x; } + | ^^ undeclared label `'x` ... LL | foo!() | ------ in this macro invocation diff --git a/src/test/ui/hygiene/hygienic-label-4.stderr b/src/test/ui/hygiene/hygienic-label-4.stderr index 4f9a68ca8311b..1c93da02f6142 100644 --- a/src/test/ui/hygiene/hygienic-label-4.stderr +++ b/src/test/ui/hygiene/hygienic-label-4.stderr @@ -1,8 +1,8 @@ error[E0426]: use of undeclared label `'x` --> $DIR/hygienic-label-4.rs:6:16 | -LL | foo!(break 'x); //~ ERROR use of undeclared label `'x` - | ^^ did you mean `'x`? +LL | foo!(break 'x); + | ^^ undeclared label `'x` error: aborting due to previous error diff --git a/src/test/ui/hygiene/impl_items.stderr b/src/test/ui/hygiene/impl_items.stderr index cb3705e5513cc..418c2c73ba157 100644 --- a/src/test/ui/hygiene/impl_items.stderr +++ b/src/test/ui/hygiene/impl_items.stderr @@ -1,7 +1,7 @@ error: type `for<'r> fn(&'r foo::S) {foo::S::f}` is private --> $DIR/impl_items.rs:12:23 | -LL | let _: () = S.f(); //~ ERROR type `for<'r> fn(&'r foo::S) {foo::S::f}` is private +LL | let _: () = S.f(); | ^ ... LL | foo::m!(); diff --git a/src/test/ui/hygiene/nested_macro_privacy.stderr b/src/test/ui/hygiene/nested_macro_privacy.stderr index 4fca86d521ba6..6e78cb86d80f4 100644 --- a/src/test/ui/hygiene/nested_macro_privacy.stderr +++ b/src/test/ui/hygiene/nested_macro_privacy.stderr @@ -1,7 +1,7 @@ error[E0616]: field `i` of struct `foo::S` is private --> $DIR/nested_macro_privacy.rs:15:5 | -LL | S::default().i; //~ ERROR field `i` of struct `foo::S` is private +LL | S::default().i; | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr index 370fc9784ad4d..e7ae7afa02aa6 100644 --- a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr @@ -1,7 +1,7 @@ error: cannot find macro `print!` in this scope --> $DIR/no_implicit_prelude-2018.rs:7:9 | -LL | print!(); //~ ERROR cannot find macro `print!` in this scope +LL | print!(); | ^^^^^ | = help: have you added the `#[macro_use]` on the module/import? diff --git a/src/test/ui/hygiene/no_implicit_prelude.rs b/src/test/ui/hygiene/no_implicit_prelude.rs index 1cd05f4d44c5e..890c8307543f3 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.rs +++ b/src/test/ui/hygiene/no_implicit_prelude.rs @@ -13,7 +13,7 @@ mod bar { } fn f() { ::foo::m!(); - println!(); //~ ERROR cannot find macro `print!` in this scope + assert_eq!(0, 0); //~ ERROR cannot find macro `panic!` in this scope } } diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr index b1de7700edb3c..737b375ed8971 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude.stderr @@ -4,14 +4,14 @@ error[E0433]: failed to resolve: use of undeclared type or module `Vec` LL | fn f() { ::bar::m!(); } | ------------ in this macro invocation ... -LL | Vec::new(); //~ ERROR failed to resolve +LL | Vec::new(); | ^^^ use of undeclared type or module `Vec` -error: cannot find macro `print!` in this scope +error: cannot find macro `panic!` in this scope --> $DIR/no_implicit_prelude.rs:16:9 | -LL | println!(); //~ ERROR cannot find macro `print!` in this scope - | ^^^^^^^^^^^ +LL | assert_eq!(0, 0); + | ^^^^^^^^^^^^^^^^^ | = help: have you added the `#[macro_use]` on the module/import? = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) @@ -22,7 +22,7 @@ error[E0599]: no method named `clone` found for type `()` in the current scope LL | fn f() { ::bar::m!(); } | ------------ in this macro invocation ... -LL | ().clone() //~ ERROR no method named `clone` found +LL | ().clone() | ^^^^^ | = help: items from traits can only be used if the trait is in scope @@ -31,5 +31,5 @@ LL | ().clone() //~ ERROR no method named `clone` found error: aborting due to 3 previous errors -Some errors occurred: E0433, E0599. +Some errors have detailed explanations: E0433, E0599. For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/ui/hygiene/pattern-macro.stderr b/src/test/ui/hygiene/pattern-macro.stderr index 8a170dccd5c42..edd05916ede2c 100644 --- a/src/test/ui/hygiene/pattern-macro.stderr +++ b/src/test/ui/hygiene/pattern-macro.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `x` in this scope --> $DIR/pattern-macro.rs:5:5 | -LL | x + 1; //~ ERROR cannot find value `x` in this scope +LL | x + 1; | ^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/hygiene/privacy.stderr b/src/test/ui/hygiene/privacy.stderr index bc056c7cf3cb5..80fb4dd0f314a 100644 --- a/src/test/ui/hygiene/privacy.stderr +++ b/src/test/ui/hygiene/privacy.stderr @@ -1,7 +1,7 @@ error[E0603]: function `f` is private --> $DIR/privacy.rs:16:14 | -LL | foo::f() //~ ERROR `f` is private +LL | foo::f() | ^ error: aborting due to previous error diff --git a/src/test/ui/hygiene/trait_items.stderr b/src/test/ui/hygiene/trait_items.stderr index 677bd08b6af57..4192b97e75069 100644 --- a/src/test/ui/hygiene/trait_items.stderr +++ b/src/test/ui/hygiene/trait_items.stderr @@ -4,7 +4,7 @@ error[E0599]: no method named `f` found for type `()` in the current scope LL | fn f() { ::baz::m!(); } | ------------ in this macro invocation ... -LL | pub macro m() { ().f() } //~ ERROR no method named `f` found for type `()` in the current scope +LL | pub macro m() { ().f() } | ^ | = help: items from traits can only be used if the trait is in scope diff --git a/src/test/ui/if/if-let-arm-types.rs b/src/test/ui/if/if-let-arm-types.rs index 819f5dd1cfc35..0f8815f0479f5 100644 --- a/src/test/ui/if/if-let-arm-types.rs +++ b/src/test/ui/if/if-let-arm-types.rs @@ -1,11 +1,12 @@ fn main() { if let Some(b) = None { - //~^ NOTE if let` arms have incompatible types + //~^ NOTE if and else have incompatible types () + //~^ NOTE expected because of this } else { 1 }; - //~^^ ERROR: `if let` arms have incompatible types + //~^^ ERROR: if and else have incompatible types //~| NOTE expected (), found integer //~| NOTE expected type `()` } diff --git a/src/test/ui/if/if-let-arm-types.stderr b/src/test/ui/if/if-let-arm-types.stderr index 6401a62c06ba2..ff88de20f76cc 100644 --- a/src/test/ui/if/if-let-arm-types.stderr +++ b/src/test/ui/if/if-let-arm-types.stderr @@ -1,14 +1,16 @@ -error[E0308]: `if let` arms have incompatible types - --> $DIR/if-let-arm-types.rs:6:9 +error[E0308]: if and else have incompatible types + --> $DIR/if-let-arm-types.rs:7:9 | LL | / if let Some(b) = None { -LL | | //~^ NOTE if let` arms have incompatible types +LL | | LL | | () + | | -- expected because of this +LL | | LL | | } else { LL | | 1 | | ^ expected (), found integer LL | | }; - | |_____- `if let` arms have incompatible types + | |_____- if and else have incompatible types | = note: expected type `()` found type `{integer}` diff --git a/src/test/ui/if/if-let.stderr b/src/test/ui/if/if-let.stderr index b2a104bfacffc..04bca1b76a097 100644 --- a/src/test/ui/if/if-let.stderr +++ b/src/test/ui/if/if-let.stderr @@ -4,7 +4,7 @@ warning: irrefutable if-let pattern LL | if let $p = $e $b | ^^ ... -LL | / foo!(a, 1, { //~ WARN irrefutable if-let +LL | / foo!(a, 1, { LL | | println!("irrefutable pattern"); LL | | }); | |_______- in this macro invocation @@ -17,7 +17,7 @@ warning: irrefutable if-let pattern LL | if let $p = $e $b | ^^ ... -LL | / bar!(a, 1, { //~ WARN irrefutable if-let +LL | / bar!(a, 1, { LL | | println!("irrefutable pattern"); LL | | }); | |_______- in this macro invocation @@ -25,7 +25,7 @@ LL | | }); warning: irrefutable if-let pattern --> $DIR/if-let.rs:24:5 | -LL | / if let a = 1 { //~ WARN irrefutable if-let +LL | / if let a = 1 { LL | | println!("irrefutable pattern"); LL | | } | |_____^ @@ -33,7 +33,7 @@ LL | | } warning: irrefutable if-let pattern --> $DIR/if-let.rs:28:5 | -LL | / if let a = 1 { //~ WARN irrefutable if-let +LL | / if let a = 1 { LL | | println!("irrefutable pattern"); LL | | } else if true { LL | | println!("else-if in irrefutable if-let"); @@ -45,7 +45,7 @@ LL | | } warning: irrefutable if-let pattern --> $DIR/if-let.rs:38:12 | -LL | } else if let a = 1 { //~ WARN irrefutable if-let +LL | } else if let a = 1 { | ____________^ LL | | println!("irrefutable pattern"); LL | | } @@ -54,7 +54,7 @@ LL | | } warning: irrefutable if-let pattern --> $DIR/if-let.rs:44:12 | -LL | } else if let a = 1 { //~ WARN irrefutable if-let +LL | } else if let a = 1 { | ____________^ LL | | println!("irrefutable pattern"); LL | | } diff --git a/src/test/ui/if/if-loop.rs b/src/test/ui/if/if-loop.rs index c799df2380013..06d0bdf456cdb 100644 --- a/src/test/ui/if/if-loop.rs +++ b/src/test/ui/if/if-loop.rs @@ -1,10 +1,8 @@ -// compile-pass -// skip-codegen -#![allow(warnings)] +// check-pass + // This used to ICE because the "if" being unreachable was not handled correctly fn err() { if loop {} {} } - fn main() {} diff --git a/src/test/ui/if/if-no-match-bindings.rs b/src/test/ui/if/if-no-match-bindings.rs new file mode 100644 index 0000000000000..581ce18c1d614 --- /dev/null +++ b/src/test/ui/if/if-no-match-bindings.rs @@ -0,0 +1,22 @@ +// Checks for `if` expressions with respect to default match bindings. +// Specifically, we do not accept `if cond { ... }` where `cond: &mut? bool`. +// Meanwhile, `match cond { true => ..., _ => ... }` does accept that. + +// FIXME(@rust-lang/lang-team): consider relaxing this? + +fn b_ref<'a>() -> &'a bool { &true } +fn b_mut_ref<'a>() -> &'a mut bool { &mut true } + +fn main() { + // This is OK: + match b_ref() { true => {}, _ => {} } + match b_mut_ref() { true => {}, _ => {} } + match &true { true => {}, _ => {} } + match &mut true { true => {}, _ => {} } + + // This is NOT: + if b_ref() {} //~ ERROR mismatched types [E0308] + if b_mut_ref() {} //~ ERROR mismatched types [E0308] + if &true {} //~ ERROR mismatched types [E0308] + if &mut true {} //~ ERROR mismatched types [E0308] +} diff --git a/src/test/ui/if/if-no-match-bindings.stderr b/src/test/ui/if/if-no-match-bindings.stderr new file mode 100644 index 0000000000000..7b0b472121fce --- /dev/null +++ b/src/test/ui/if/if-no-match-bindings.stderr @@ -0,0 +1,39 @@ +error[E0308]: mismatched types + --> $DIR/if-no-match-bindings.rs:18:8 + | +LL | if b_ref() {} + | ^^^^^^^ expected bool, found &bool + | + = note: expected type `bool` + found type `&bool` + +error[E0308]: mismatched types + --> $DIR/if-no-match-bindings.rs:19:8 + | +LL | if b_mut_ref() {} + | ^^^^^^^^^^^ expected bool, found &mut bool + | + = note: expected type `bool` + found type `&mut bool` + +error[E0308]: mismatched types + --> $DIR/if-no-match-bindings.rs:20:8 + | +LL | if &true {} + | ^^^^^ expected bool, found &bool + | + = note: expected type `bool` + found type `&bool` + +error[E0308]: mismatched types + --> $DIR/if-no-match-bindings.rs:21:8 + | +LL | if &mut true {} + | ^^^^^^^^^ expected bool, found &mut bool + | + = note: expected type `bool` + found type `&mut bool` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/if/if-without-else-as-fn-expr.rs b/src/test/ui/if/if-without-else-as-fn-expr.rs new file mode 100644 index 0000000000000..15892de83854c --- /dev/null +++ b/src/test/ui/if/if-without-else-as-fn-expr.rs @@ -0,0 +1,55 @@ +fn foo(bar: usize) -> usize { + if bar % 5 == 0 { + return 3; + } + //~^^^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] +} + +fn foo2(bar: usize) -> usize { + let x: usize = if bar % 5 == 0 { + return 3; + }; + //~^^^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] + x +} + +fn foo3(bar: usize) -> usize { + if bar % 5 == 0 { + 3 + } + //~^^^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] +} + +fn foo_let(bar: usize) -> usize { + if let 0 = 1 { + return 3; + } + //~^^^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] +} + +fn foo2_let(bar: usize) -> usize { + let x: usize = if let 0 = 1 { + return 3; + }; + //~^^^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] + x +} + +fn foo3_let(bar: usize) -> usize { + if let 0 = 1 { + 3 + } + //~^^^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] +} + +// FIXME(60254): deduplicate first error in favor of second. + +fn main() { + let _ = foo(1); +} diff --git a/src/test/ui/if/if-without-else-as-fn-expr.stderr b/src/test/ui/if/if-without-else-as-fn-expr.stderr new file mode 100644 index 0000000000000..06600b1cb9aea --- /dev/null +++ b/src/test/ui/if/if-without-else-as-fn-expr.stderr @@ -0,0 +1,164 @@ +error[E0308]: mismatched types + --> $DIR/if-without-else-as-fn-expr.rs:2:5 + | +LL | / if bar % 5 == 0 { +LL | | return 3; +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error[E0317]: if may be missing an else clause + --> $DIR/if-without-else-as-fn-expr.rs:2:5 + | +LL | fn foo(bar: usize) -> usize { + | ----- expected `usize` because of this return type +LL | / if bar % 5 == 0 { +LL | | return 3; +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + +error[E0308]: mismatched types + --> $DIR/if-without-else-as-fn-expr.rs:10:20 + | +LL | let x: usize = if bar % 5 == 0 { + | ____________________^ +LL | | return 3; +LL | | }; + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error[E0317]: if may be missing an else clause + --> $DIR/if-without-else-as-fn-expr.rs:10:20 + | +LL | let x: usize = if bar % 5 == 0 { + | _________-__________^ + | | | + | | expected because of this assignment +LL | | return 3; +LL | | }; + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + +error[E0308]: mismatched types + --> $DIR/if-without-else-as-fn-expr.rs:19:5 + | +LL | / if bar % 5 == 0 { +LL | | 3 +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error[E0317]: if may be missing an else clause + --> $DIR/if-without-else-as-fn-expr.rs:19:5 + | +LL | fn foo3(bar: usize) -> usize { + | ----- expected `usize` because of this return type +LL | / if bar % 5 == 0 { +LL | | 3 +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + +error[E0308]: mismatched types + --> $DIR/if-without-else-as-fn-expr.rs:27:5 + | +LL | / if let 0 = 1 { +LL | | return 3; +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error[E0317]: if may be missing an else clause + --> $DIR/if-without-else-as-fn-expr.rs:27:5 + | +LL | fn foo_let(bar: usize) -> usize { + | ----- expected `usize` because of this return type +LL | / if let 0 = 1 { +LL | | return 3; +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + +error[E0308]: mismatched types + --> $DIR/if-without-else-as-fn-expr.rs:35:20 + | +LL | let x: usize = if let 0 = 1 { + | ____________________^ +LL | | return 3; +LL | | }; + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error[E0317]: if may be missing an else clause + --> $DIR/if-without-else-as-fn-expr.rs:35:20 + | +LL | let x: usize = if let 0 = 1 { + | _________-__________^ + | | | + | | expected because of this assignment +LL | | return 3; +LL | | }; + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + +error[E0308]: mismatched types + --> $DIR/if-without-else-as-fn-expr.rs:44:5 + | +LL | / if let 0 = 1 { +LL | | 3 +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error[E0317]: if may be missing an else clause + --> $DIR/if-without-else-as-fn-expr.rs:44:5 + | +LL | fn foo3_let(bar: usize) -> usize { + | ----- expected `usize` because of this return type +LL | / if let 0 = 1 { +LL | | 3 +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0308, E0317. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/if/if-without-else-result.stderr b/src/test/ui/if/if-without-else-result.stderr index 2134781088c3d..ddb013ab711fa 100644 --- a/src/test/ui/if/if-without-else-result.stderr +++ b/src/test/ui/if/if-without-else-result.stderr @@ -2,10 +2,15 @@ error[E0317]: if may be missing an else clause --> $DIR/if-without-else-result.rs:2:13 | LL | let a = if true { true }; - | ^^^^^^^^^^^^^^^^ expected (), found bool + | ^^^^^^^^^^----^^ + | | | + | | found here + | expected (), found bool | = note: expected type `()` found type `bool` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type error: aborting due to previous error diff --git a/src/test/ui/if/ifmt-bad-arg.stderr b/src/test/ui/if/ifmt-bad-arg.stderr index d4153ac94acd1..65be86eaf2575 100644 --- a/src/test/ui/if/ifmt-bad-arg.stderr +++ b/src/test/ui/if/ifmt-bad-arg.stderr @@ -73,13 +73,13 @@ LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); error: there is no argument named `foo` --> $DIR/ifmt-bad-arg.rs:31:14 | -LL | format!("{foo}"); //~ ERROR: no argument named `foo` +LL | format!("{foo}"); | ^^^^^ error: multiple unused formatting arguments --> $DIR/ifmt-bad-arg.rs:32:17 | -LL | format!("", 1, 2); //~ ERROR: multiple unused formatting arguments +LL | format!("", 1, 2); | -- ^ ^ argument never used | | | | | argument never used @@ -88,7 +88,7 @@ LL | format!("", 1, 2); //~ ERROR: multiple unused formatting error: argument never used --> $DIR/ifmt-bad-arg.rs:33:22 | -LL | format!("{}", 1, 2); //~ ERROR: argument never used +LL | format!("{}", 1, 2); | ---- ^ argument never used | | | formatting specifier missing @@ -96,7 +96,7 @@ LL | format!("{}", 1, 2); //~ ERROR: argument never used error: argument never used --> $DIR/ifmt-bad-arg.rs:34:20 | -LL | format!("{1}", 1, 2); //~ ERROR: argument never used +LL | format!("{1}", 1, 2); | ----- ^ argument never used | | | formatting specifier missing @@ -104,7 +104,7 @@ LL | format!("{1}", 1, 2); //~ ERROR: argument never used error: named argument never used --> $DIR/ifmt-bad-arg.rs:35:26 | -LL | format!("{}", 1, foo=2); //~ ERROR: named argument never used +LL | format!("{}", 1, foo=2); | ---- ^ named argument never used | | | formatting specifier missing @@ -112,7 +112,7 @@ LL | format!("{}", 1, foo=2); //~ ERROR: named argument never used error: argument never used --> $DIR/ifmt-bad-arg.rs:36:22 | -LL | format!("{foo}", 1, foo=2); //~ ERROR: argument never used +LL | format!("{foo}", 1, foo=2); | ------- ^ argument never used | | | formatting specifier missing @@ -120,7 +120,7 @@ LL | format!("{foo}", 1, foo=2); //~ ERROR: argument never used error: named argument never used --> $DIR/ifmt-bad-arg.rs:37:21 | -LL | format!("", foo=2); //~ ERROR: named argument never used +LL | format!("", foo=2); | -- ^ named argument never used | | | formatting specifier missing @@ -128,7 +128,7 @@ LL | format!("", foo=2); //~ ERROR: named argument never used error: multiple unused formatting arguments --> $DIR/ifmt-bad-arg.rs:38:32 | -LL | format!("{} {}", 1, 2, foo=1, bar=2); //~ ERROR: multiple unused formatting arguments +LL | format!("{} {}", 1, 2, foo=1, bar=2); | ------- ^ ^ named argument never used | | | | | named argument never used @@ -137,19 +137,19 @@ LL | format!("{} {}", 1, 2, foo=1, bar=2); //~ ERROR: multiple unused forma error: duplicate argument named `foo` --> $DIR/ifmt-bad-arg.rs:40:33 | -LL | format!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument +LL | format!("{foo}", foo=1, foo=2); | ^ | note: previously here --> $DIR/ifmt-bad-arg.rs:40:26 | -LL | format!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument +LL | format!("{foo}", foo=1, foo=2); | ^ error: expected ident, positional arguments cannot follow named arguments --> $DIR/ifmt-bad-arg.rs:41:24 | -LL | format!("", foo=1, 2); //~ ERROR: positional arguments cannot follow +LL | format!("", foo=1, 2); | ^ error: there is no argument named `valueb` @@ -169,7 +169,7 @@ LL | format!("{valuea} {valueb}", valuea=5, valuec=7); error: invalid format string: expected `'}'` but string was terminated --> $DIR/ifmt-bad-arg.rs:51:15 | -LL | format!("{"); //~ ERROR: expected `'}'` but string was terminated +LL | format!("{"); | -^ expected `'}'` in format string | | | because of this opening brace @@ -179,7 +179,7 @@ LL | format!("{"); //~ ERROR: expected `'}'` but string was terminated error: invalid format string: unmatched `}` found --> $DIR/ifmt-bad-arg.rs:53:18 | -LL | format!("foo } bar"); //~ ERROR: unmatched `}` found +LL | format!("foo } bar"); | ^ unmatched `}` in format string | = note: if you intended to print `}`, you can escape it using `}}` @@ -187,7 +187,7 @@ LL | format!("foo } bar"); //~ ERROR: unmatched `}` found error: invalid format string: unmatched `}` found --> $DIR/ifmt-bad-arg.rs:54:18 | -LL | format!("foo }"); //~ ERROR: unmatched `}` found +LL | format!("foo }"); | ^ unmatched `}` in format string | = note: if you intended to print `}`, you can escape it using `}}` @@ -195,7 +195,7 @@ LL | format!("foo }"); //~ ERROR: unmatched `}` found error: argument never used --> $DIR/ifmt-bad-arg.rs:56:27 | -LL | format!("foo %s baz", "bar"); //~ ERROR: argument never used +LL | format!("foo %s baz", "bar"); | -- ^^^^^ argument never used | | | help: format specifiers use curly braces: `{}` diff --git a/src/test/ui/if/ifmt-bad-format-args.stderr b/src/test/ui/if/ifmt-bad-format-args.stderr index 966c8d916a3b5..9dc2b8f9a7397 100644 --- a/src/test/ui/if/ifmt-bad-format-args.stderr +++ b/src/test/ui/if/ifmt-bad-format-args.stderr @@ -1,17 +1,17 @@ error: requires at least a format string argument --> $DIR/ifmt-bad-format-args.rs:2:5 | -LL | format_args!(); //~ ERROR: requires at least a format string argument +LL | format_args!(); | ^^^^^^^^^^^^^^^ error: format argument must be a string literal --> $DIR/ifmt-bad-format-args.rs:3:18 | -LL | format_args!(|| {}); //~ ERROR: must be a string literal +LL | format_args!(|| {}); | ^^^^^ help: you might be missing a string literal to format with | -LL | format_args!("{}", || {}); //~ ERROR: must be a string literal +LL | format_args!("{}", || {}); | ^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/illegal-ufcs-drop.stderr b/src/test/ui/illegal-ufcs-drop.stderr index d8e2dc6e8700e..d35d376962c17 100644 --- a/src/test/ui/illegal-ufcs-drop.stderr +++ b/src/test/ui/illegal-ufcs-drop.stderr @@ -1,7 +1,7 @@ error[E0040]: explicit use of destructor method --> $DIR/illegal-ufcs-drop.rs:8:5 | -LL | Drop::drop(&mut Foo) //~ ERROR explicit use of destructor method +LL | Drop::drop(&mut Foo) | ^^^^^^^^^^ explicit destructor calls not allowed error: aborting due to previous error diff --git a/src/test/ui/immut-function-arguments.ast.nll.stderr b/src/test/ui/immut-function-arguments.ast.nll.stderr deleted file mode 100644 index f0163390ae000..0000000000000 --- a/src/test/ui/immut-function-arguments.ast.nll.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0594]: cannot assign to `*y`, as `y` is not declared as mutable - --> $DIR/immut-function-arguments.rs:5:5 - | -LL | fn f(y: Box) { - | - help: consider changing this to be mutable: `mut y` -LL | *y = 5; //[ast]~ ERROR cannot assign - | ^^^^^^ cannot assign - -error[E0594]: cannot assign to `*q`, as `q` is not declared as mutable - --> $DIR/immut-function-arguments.rs:10:35 - | -LL | let _frob = |q: Box| { *q = 2; }; //[ast]~ ERROR cannot assign - | - ^^^^^^ cannot assign - | | - | help: consider changing this to be mutable: `mut q` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/immut-function-arguments.ast.stderr b/src/test/ui/immut-function-arguments.ast.stderr deleted file mode 100644 index 1ffe569d8281a..0000000000000 --- a/src/test/ui/immut-function-arguments.ast.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0594]: cannot assign to immutable `Box` content `*y` - --> $DIR/immut-function-arguments.rs:5:5 - | -LL | fn f(y: Box) { - | - help: make this binding mutable: `mut y` -LL | *y = 5; //[ast]~ ERROR cannot assign - | ^^^^^^ cannot borrow as mutable - -error[E0594]: cannot assign to immutable `Box` content `*q` - --> $DIR/immut-function-arguments.rs:10:35 - | -LL | let _frob = |q: Box| { *q = 2; }; //[ast]~ ERROR cannot assign - | - ^^^^^^ cannot borrow as mutable - | | - | help: make this binding mutable: `mut q` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/immut-function-arguments.mir.stderr b/src/test/ui/immut-function-arguments.mir.stderr deleted file mode 100644 index f0163390ae000..0000000000000 --- a/src/test/ui/immut-function-arguments.mir.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0594]: cannot assign to `*y`, as `y` is not declared as mutable - --> $DIR/immut-function-arguments.rs:5:5 - | -LL | fn f(y: Box) { - | - help: consider changing this to be mutable: `mut y` -LL | *y = 5; //[ast]~ ERROR cannot assign - | ^^^^^^ cannot assign - -error[E0594]: cannot assign to `*q`, as `q` is not declared as mutable - --> $DIR/immut-function-arguments.rs:10:35 - | -LL | let _frob = |q: Box| { *q = 2; }; //[ast]~ ERROR cannot assign - | - ^^^^^^ cannot assign - | | - | help: consider changing this to be mutable: `mut q` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/immut-function-arguments.rs b/src/test/ui/immut-function-arguments.rs index 2cc9c694ef198..242a33e8216d8 100644 --- a/src/test/ui/immut-function-arguments.rs +++ b/src/test/ui/immut-function-arguments.rs @@ -1,14 +1,9 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - fn f(y: Box) { - *y = 5; //[ast]~ ERROR cannot assign - //[mir]~^ ERROR cannot assign + *y = 5; //~ ERROR cannot assign } fn g() { - let _frob = |q: Box| { *q = 2; }; //[ast]~ ERROR cannot assign - //[mir]~^ ERROR cannot assign + let _frob = |q: Box| { *q = 2; }; //~ ERROR cannot assign } fn main() {} diff --git a/src/test/ui/immut-function-arguments.stderr b/src/test/ui/immut-function-arguments.stderr new file mode 100644 index 0000000000000..7871ba52db9c9 --- /dev/null +++ b/src/test/ui/immut-function-arguments.stderr @@ -0,0 +1,18 @@ +error[E0594]: cannot assign to `*y`, as `y` is not declared as mutable + --> $DIR/immut-function-arguments.rs:2:5 + | +LL | fn f(y: Box) { + | - help: consider changing this to be mutable: `mut y` +LL | *y = 5; + | ^^^^^^ cannot assign + +error[E0594]: cannot assign to `*q`, as `q` is not declared as mutable + --> $DIR/immut-function-arguments.rs:6:35 + | +LL | let _frob = |q: Box| { *q = 2; }; + | - ^^^^^^ cannot assign + | | + | help: consider changing this to be mutable: `mut q` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/impl-bounds-checking.stderr b/src/test/ui/impl-bounds-checking.stderr index 618a9f94aa451..b52f3d6b839d4 100644 --- a/src/test/ui/impl-bounds-checking.stderr +++ b/src/test/ui/impl-bounds-checking.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `isize: Clone2` is not satisfied --> $DIR/impl-bounds-checking.rs:10:6 | -LL | impl Getter for isize { //~ ERROR `isize: Clone2` is not satisfied +LL | impl Getter for isize { | ^^^^^^^^^^^^^ the trait `Clone2` is not implemented for `isize` error: aborting due to previous error diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr new file mode 100644 index 0000000000000..da30997a23111 --- /dev/null +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr @@ -0,0 +1,10 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/dyn-trait.rs:20:5 + | +LL | fn with_dyn_debug_static<'a>(x: Box) { + | - `x` is a reference that is only valid in the function body +LL | static_val(x); + | ^^^^^^^^^^^^^ `x` escapes the function body here + +error: aborting due to previous error + diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr index 53cd2b1441187..eb824def24687 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr @@ -1,7 +1,7 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/dyn-trait.rs:20:16 | -LL | static_val(x); //~ ERROR cannot infer +LL | static_val(x); | ^ | note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 19:26... @@ -19,4 +19,3 @@ LL | fn with_dyn_debug_static<'a>(x: Box) { error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/impl-header-lifetime-elision/path-elided.rs b/src/test/ui/impl-header-lifetime-elision/path-elided.rs index 6532b0aebe74a..40a52efc7f9fc 100644 --- a/src/test/ui/impl-header-lifetime-elision/path-elided.rs +++ b/src/test/ui/impl-header-lifetime-elision/path-elided.rs @@ -5,7 +5,7 @@ trait MyTrait { } struct Foo<'a> { x: &'a u32 } impl MyTrait for Foo { - //~^ ERROR missing lifetime specifier + //~^ ERROR implicit elided lifetime not allowed here } fn main() {} diff --git a/src/test/ui/impl-header-lifetime-elision/path-elided.stderr b/src/test/ui/impl-header-lifetime-elision/path-elided.stderr index c9287ffba96d3..6500a2a55f667 100644 --- a/src/test/ui/impl-header-lifetime-elision/path-elided.stderr +++ b/src/test/ui/impl-header-lifetime-elision/path-elided.stderr @@ -1,9 +1,8 @@ -error[E0106]: missing lifetime specifier +error[E0726]: implicit elided lifetime not allowed here --> $DIR/path-elided.rs:7:18 | LL | impl MyTrait for Foo { - | ^^^ expected lifetime parameter + | ^^^- help: indicate the anonymous lifetime: `<'_>` error: aborting due to previous error -For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/impl-header-lifetime-elision/trait-elided.rs b/src/test/ui/impl-header-lifetime-elision/trait-elided.rs index 3979eda740a82..102d259b0c87a 100644 --- a/src/test/ui/impl-header-lifetime-elision/trait-elided.rs +++ b/src/test/ui/impl-header-lifetime-elision/trait-elided.rs @@ -3,7 +3,7 @@ trait MyTrait<'a> { } impl MyTrait for u32 { - //~^ ERROR missing lifetime specifier + //~^ ERROR implicit elided lifetime not allowed here } fn main() {} diff --git a/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr b/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr index b742db1c75c19..ad97cb0abd623 100644 --- a/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr +++ b/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr @@ -1,9 +1,8 @@ -error[E0106]: missing lifetime specifier +error[E0726]: implicit elided lifetime not allowed here --> $DIR/trait-elided.rs:5:6 | LL | impl MyTrait for u32 { - | ^^^^^^^ expected lifetime parameter + | ^^^^^^^- help: indicate the anonymous lifetime: `<'_>` error: aborting due to previous error -For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index ea0be0b346cbe..1c601bc3c34ea 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - use std::cell::Cell; use std::rc::Rc; diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index b936fed85f48e..61450d3203cd8 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -1,29 +1,29 @@ -error[E0391]: cycle detected when processing `cycle1::{{impl-Trait}}` - --> $DIR/auto-trait-leak.rs:14:16 +error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0` + --> $DIR/auto-trait-leak.rs:12:16 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ | note: ...which requires processing `cycle1`... - --> $DIR/auto-trait-leak.rs:14:1 + --> $DIR/auto-trait-leak.rs:12:1 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires processing `cycle2::{{impl-Trait}}`... - --> $DIR/auto-trait-leak.rs:23:16 +note: ...which requires processing `cycle2::{{opaque}}#0`... + --> $DIR/auto-trait-leak.rs:21:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:23:1 + --> $DIR/auto-trait-leak.rs:21:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... - = note: ...which again requires processing `cycle1::{{impl-Trait}}`, completing the cycle + = note: ...which again requires processing `cycle1::{{opaque}}#0`, completing the cycle note: cycle used when checking item types in top-level module - --> $DIR/auto-trait-leak.rs:3:1 + --> $DIR/auto-trait-leak.rs:1:1 | LL | / use std::cell::Cell; LL | | use std::rc::Rc; @@ -34,31 +34,31 @@ LL | | Rc::new(String::from("foo")) LL | | } | |_^ -error[E0391]: cycle detected when processing `cycle1::{{impl-Trait}}` - --> $DIR/auto-trait-leak.rs:14:16 +error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0` + --> $DIR/auto-trait-leak.rs:12:16 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ | note: ...which requires processing `cycle1`... - --> $DIR/auto-trait-leak.rs:14:1 + --> $DIR/auto-trait-leak.rs:12:1 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires processing `cycle2::{{impl-Trait}}`... - --> $DIR/auto-trait-leak.rs:23:16 +note: ...which requires processing `cycle2::{{opaque}}#0`... + --> $DIR/auto-trait-leak.rs:21:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:23:1 + --> $DIR/auto-trait-leak.rs:21:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires processing `cycle1::{{impl-Trait}}`, completing the cycle + = note: ...which again requires processing `cycle1::{{opaque}}#0`, completing the cycle note: cycle used when checking item types in top-level module - --> $DIR/auto-trait-leak.rs:3:1 + --> $DIR/auto-trait-leak.rs:1:1 | LL | / use std::cell::Cell; LL | | use std::rc::Rc; @@ -70,7 +70,7 @@ LL | | } | |_^ error[E0277]: `std::rc::Rc` cannot be sent between threads safely - --> $DIR/auto-trait-leak.rs:17:5 + --> $DIR/auto-trait-leak.rs:15:5 | LL | send(cycle2().clone()); | ^^^^ `std::rc::Rc` cannot be sent between threads safely @@ -78,12 +78,12 @@ LL | send(cycle2().clone()); = help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` = note: required because it appears within the type `impl std::clone::Clone` note: required by `send` - --> $DIR/auto-trait-leak.rs:6:1 + --> $DIR/auto-trait-leak.rs:4:1 | LL | fn send(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors -Some errors occurred: E0277, E0391. +Some errors have detailed explanations: E0277, E0391. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/auto-trait-leak2.rs b/src/test/ui/impl-trait/auto-trait-leak2.rs index a373edcfcf952..fb4b54051237c 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.rs +++ b/src/test/ui/impl-trait/auto-trait-leak2.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - use std::cell::Cell; use std::rc::Rc; @@ -25,4 +23,3 @@ fn after() -> impl Fn(i32) { let p = Rc::new(Cell::new(0)); move |x| p.set(x) } - diff --git a/src/test/ui/impl-trait/auto-trait-leak2.stderr b/src/test/ui/impl-trait/auto-trait-leak2.stderr index 4e427d3d6b388..19899ff83f7c3 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak2.stderr @@ -1,29 +1,29 @@ error[E0277]: `std::rc::Rc>` cannot be sent between threads safely - --> $DIR/auto-trait-leak2.rs:15:5 + --> $DIR/auto-trait-leak2.rs:13:5 | LL | send(before()); | ^^^^ `std::rc::Rc>` cannot be sent between threads safely | = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:9:5: 9:22 p:std::rc::Rc>]` + = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22 p:std::rc::Rc>]` = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` note: required by `send` - --> $DIR/auto-trait-leak2.rs:12:1 + --> $DIR/auto-trait-leak2.rs:10:1 | LL | fn send(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `std::rc::Rc>` cannot be sent between threads safely - --> $DIR/auto-trait-leak2.rs:18:5 + --> $DIR/auto-trait-leak2.rs:16:5 | LL | send(after()); | ^^^^ `std::rc::Rc>` cannot be sent between threads safely | = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:26:5: 26:22 p:std::rc::Rc>]` + = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22 p:std::rc::Rc>]` = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` note: required by `send` - --> $DIR/auto-trait-leak2.rs:12:1 + --> $DIR/auto-trait-leak2.rs:10:1 | LL | fn send(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/bindings-opaque.rs b/src/test/ui/impl-trait/bindings-opaque.rs index 5f623321943a3..d4eef29ed3207 100644 --- a/src/test/ui/impl-trait/bindings-opaque.rs +++ b/src/test/ui/impl-trait/bindings-opaque.rs @@ -1,4 +1,5 @@ #![feature(impl_trait_in_bindings)] +//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash const FOO: impl Copy = 42; diff --git a/src/test/ui/impl-trait/bindings-opaque.stderr b/src/test/ui/impl-trait/bindings-opaque.stderr index 8b2514c050142..d0a6a4ee578f7 100644 --- a/src/test/ui/impl-trait/bindings-opaque.stderr +++ b/src/test/ui/impl-trait/bindings-opaque.stderr @@ -1,17 +1,23 @@ +warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash + --> $DIR/bindings-opaque.rs:1:12 + | +LL | #![feature(impl_trait_in_bindings)] + | ^^^^^^^^^^^^^^^^^^^^^^ + error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope - --> $DIR/bindings-opaque.rs:10:17 + --> $DIR/bindings-opaque.rs:11:17 | LL | let _ = FOO.count_ones(); | ^^^^^^^^^^ error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope - --> $DIR/bindings-opaque.rs:12:17 + --> $DIR/bindings-opaque.rs:13:17 | LL | let _ = BAR.count_ones(); | ^^^^^^^^^^ error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope - --> $DIR/bindings-opaque.rs:14:17 + --> $DIR/bindings-opaque.rs:15:17 | LL | let _ = foo.count_ones(); | ^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/bindings.rs b/src/test/ui/impl-trait/bindings.rs index 91d092634a901..104a44d65662e 100644 --- a/src/test/ui/impl-trait/bindings.rs +++ b/src/test/ui/impl-trait/bindings.rs @@ -1,4 +1,5 @@ #![feature(impl_trait_in_bindings)] +//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash fn a(x: T) { const foo: impl Clone = x; diff --git a/src/test/ui/impl-trait/bindings.stderr b/src/test/ui/impl-trait/bindings.stderr index a5bf583afeaf6..c66836ab8e5af 100644 --- a/src/test/ui/impl-trait/bindings.stderr +++ b/src/test/ui/impl-trait/bindings.stderr @@ -1,23 +1,29 @@ +warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash + --> $DIR/bindings.rs:1:12 + | +LL | #![feature(impl_trait_in_bindings)] + | ^^^^^^^^^^^^^^^^^^^^^^ + error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/bindings.rs:4:29 + --> $DIR/bindings.rs:5:29 | LL | const foo: impl Clone = x; | ^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/bindings.rs:10:33 + --> $DIR/bindings.rs:11:33 | LL | const foo: impl Clone = x; | ^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/bindings.rs:17:33 + --> $DIR/bindings.rs:18:33 | LL | const foo: impl Clone = x; | ^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/bindings.rs:24:33 + --> $DIR/bindings.rs:25:33 | LL | const foo: impl Clone = x; | ^ non-constant value diff --git a/src/test/ui/impl-trait/can-return-unconstrained-closure.rs b/src/test/ui/impl-trait/can-return-unconstrained-closure.rs new file mode 100644 index 0000000000000..90a7519074b53 --- /dev/null +++ b/src/test/ui/impl-trait/can-return-unconstrained-closure.rs @@ -0,0 +1,23 @@ +// Test that we are special casing "outlives" for opaque types. +// +// The return type of a closure is not required to outlive the closure. As such +// the following code would not compile if we used a standard outlives check +// when checking the return type, because the return type of the closure would +// be `&ReEmpty i32`, and we don't allow `ReEmpty` to occur in the concrete +// type used for an opaque type. +// +// However, opaque types are special cased to include check all regions in the +// concrete type against the bound, which forces the return type to be +// `&'static i32` here. + +// compile-pass + +fn make_identity() -> impl Sized { + |x: &'static i32| x +} + +fn make_identity_static() -> impl Sized + 'static { + |x: &'static i32| x +} + +fn main() {} diff --git a/src/test/ui/impl-trait/closure-calling-parent-fn.rs b/src/test/ui/impl-trait/closure-calling-parent-fn.rs index cb5f78bd6fc0f..58d7875ccd034 100644 --- a/src/test/ui/impl-trait/closure-calling-parent-fn.rs +++ b/src/test/ui/impl-trait/closure-calling-parent-fn.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - // Regression test for #54593: the MIR type checker was going wrong // when a closure returns the `impl Copy` from its parent fn. It was // (incorrectly) replacing the `impl Copy` in its return type with the diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index 6cd9d07748c27..7bb2d7d47a51d 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -23,5 +23,5 @@ LL | n + sum_to(n - 1) error: aborting due to 2 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/extra-item.stderr b/src/test/ui/impl-trait/extra-item.stderr index de3c7ba5d3118..728bcc0aa865e 100644 --- a/src/test/ui/impl-trait/extra-item.stderr +++ b/src/test/ui/impl-trait/extra-item.stderr @@ -1,7 +1,7 @@ error[E0407]: method `extra` is not a member of trait `extra_item::MyTrait` --> $DIR/extra-item.rs:7:5 | -LL | fn extra() {} //~ ERROR method `extra` is not a member of trait `extra_item::MyTrait` +LL | fn extra() {} | ^^^^^^^^^^^^^ not a member of trait `extra_item::MyTrait` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/hidden-lifetimes.rs b/src/test/ui/impl-trait/hidden-lifetimes.rs new file mode 100644 index 0000000000000..2ee004a37a6fc --- /dev/null +++ b/src/test/ui/impl-trait/hidden-lifetimes.rs @@ -0,0 +1,63 @@ +// Test to show what happens if we were not careful and allowed invariant +// lifetimes to escape though an impl trait. +// +// Specifically we swap a long lived and short lived reference, giving us a +// dangling pointer. + +use std::cell::RefCell; +use std::rc::Rc; + +trait Swap: Sized { + fn swap(self, other: Self); +} + +impl Swap for &mut T { + fn swap(self, other: Self) { + std::mem::swap(self, other); + } +} + +impl Swap for Rc> { + fn swap(self, other: Self) { + >::swap(&self, &other); + } +} + +// Here we are hiding `'b` making the caller believe that `&'a mut &'s T` and +// `&'a mut &'l T` are the same type. +fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a { + //~^ ERROR hidden type + x +} + +fn dangle_ref() -> &'static [i32; 3] { + let mut res = &[4, 5, 6]; + let x = [1, 2, 3]; + hide_ref(&mut res).swap(hide_ref(&mut &x)); + res +} + +// Here we are hiding `'b` making the caller believe that `Rc>` +// and `Rc>` are the same type. +// +// This is different to the previous example because the concrete return type +// only has a single lifetime. +fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a { + //~^ ERROR hidden type + x +} + +fn dangle_rc_refcell() -> &'static [i32; 3] { + let long = Rc::new(RefCell::new(&[4, 5, 6])); + let x = [1, 2, 3]; + let short = Rc::new(RefCell::new(&x)); + hide_rc_refcell(long.clone()).swap(hide_rc_refcell(short)); + let res: &'static [i32; 3] = *long.borrow(); + res +} + +fn main() { + // both will print nonsense values. + println!("{:?}", dangle_ref()); + println!("{:?}", dangle_rc_refcell()) +} diff --git a/src/test/ui/impl-trait/hidden-lifetimes.stderr b/src/test/ui/impl-trait/hidden-lifetimes.stderr new file mode 100644 index 0000000000000..650161753d1e5 --- /dev/null +++ b/src/test/ui/impl-trait/hidden-lifetimes.stderr @@ -0,0 +1,27 @@ +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/hidden-lifetimes.rs:28:54 + | +LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a { + | ^^^^^^^^^^^^^^ + | +note: hidden type `&'a mut &'b T` captures the lifetime 'b as defined on the function body at 28:17 + --> $DIR/hidden-lifetimes.rs:28:17 + | +LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a { + | ^^ + +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/hidden-lifetimes.rs:45:70 + | +LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a { + | ^^^^^^^^^^^^^^ + | +note: hidden type `std::rc::Rc>` captures the lifetime 'b as defined on the function body at 45:24 + --> $DIR/hidden-lifetimes.rs:45:24 + | +LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a { + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/impl-trait/impl-trait-plus-priority.rs b/src/test/ui/impl-trait/impl-trait-plus-priority.rs index 2e4f048a4e406..dfac9c0f1ef86 100644 --- a/src/test/ui/impl-trait/impl-trait-plus-priority.rs +++ b/src/test/ui/impl-trait/impl-trait-plus-priority.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z parse-only -Z continue-parse-after-error +// compile-flags: -Z parse-only fn f() -> impl A + {} // OK fn f() -> impl A + B {} // OK diff --git a/src/test/ui/impl-trait/impl_trait_projections.stderr b/src/test/ui/impl-trait/impl_trait_projections.stderr index 4e9bcf32e1379..ff4382187aae4 100644 --- a/src/test/ui/impl-trait/impl_trait_projections.stderr +++ b/src/test/ui/impl-trait/impl_trait_projections.stderr @@ -30,5 +30,4 @@ LL | fn projection_is_disallowed(x: impl Iterator) -> ::Item { error: aborting due to 5 previous errors -Some errors occurred: E0223, E0667. -For more information about an error, try `rustc --explain E0223`. +For more information about this error, try `rustc --explain E0223`. diff --git a/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr b/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr deleted file mode 100644 index d1f147834d2ef..0000000000000 --- a/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/issue-55608-captures-empty-region.rs:6:16 - | -LL | fn server() -> impl FilterBase2 { //~ ERROR [E0700] - | ^^^^^^^^^^^^^^^^ - | - = note: hidden type `Map2<[closure@$DIR/issue-55608-captures-empty-region.rs:7:36: 7:41]>` captures an empty lifetime - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/impl-trait/infinite-impl-trait-issue-38064.rs b/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.rs similarity index 100% rename from src/test/ui/impl-trait/infinite-impl-trait-issue-38064.rs rename to src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.rs diff --git a/src/test/ui/impl-trait/infinite-impl-trait-issue-38064.stderr b/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr similarity index 79% rename from src/test/ui/impl-trait/infinite-impl-trait-issue-38064.stderr rename to src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr index 99c8fe35c66d0..fb48ecd12b6d1 100644 --- a/src/test/ui/impl-trait/infinite-impl-trait-issue-38064.stderr +++ b/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr @@ -1,7 +1,7 @@ error[E0720]: opaque type expands to a recursive type --> $DIR/infinite-impl-trait-issue-38064.rs:8:13 | -LL | fn foo() -> impl Quux { //~ opaque type expands to a recursive type +LL | fn foo() -> impl Quux { | ^^^^^^^^^ expands to self-referential type | = note: expanded type is `foo::Foo>` @@ -9,7 +9,7 @@ LL | fn foo() -> impl Quux { //~ opaque type expands to a recursive type error[E0720]: opaque type expands to a recursive type --> $DIR/infinite-impl-trait-issue-38064.rs:14:13 | -LL | fn bar() -> impl Quux { //~ opaque type expands to a recursive type +LL | fn bar() -> impl Quux { | ^^^^^^^^^ expands to self-referential type | = note: expanded type is `bar::Bar>` diff --git a/src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.rs b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs similarity index 100% rename from src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.rs rename to src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs diff --git a/src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.stderr b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr similarity index 100% rename from src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.stderr rename to src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr diff --git a/src/test/ui/impl-trait/issue-42479.rs b/src/test/ui/impl-trait/issues/issue-42479.rs similarity index 100% rename from src/test/ui/impl-trait/issue-42479.rs rename to src/test/ui/impl-trait/issues/issue-42479.rs diff --git a/src/test/ui/impl-trait/issue-49376.rs b/src/test/ui/impl-trait/issues/issue-49376.rs similarity index 100% rename from src/test/ui/impl-trait/issue-49376.rs rename to src/test/ui/impl-trait/issues/issue-49376.rs diff --git a/src/test/ui/impl-trait/issue-52128.rs b/src/test/ui/impl-trait/issues/issue-52128.rs similarity index 100% rename from src/test/ui/impl-trait/issue-52128.rs rename to src/test/ui/impl-trait/issues/issue-52128.rs diff --git a/src/test/ui/impl-trait/issues/issue-53457.rs b/src/test/ui/impl-trait/issues/issue-53457.rs new file mode 100644 index 0000000000000..3f6a4fb278715 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-53457.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(existential_type)] + +existential type X: Clone; + +fn bar(f: F) -> F { + f +} + +fn foo() -> X { + bar(|x| ()) +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs b/src/test/ui/impl-trait/issues/issue-55608-captures-empty-region.rs similarity index 82% rename from src/test/ui/impl-trait/issue-55608-captures-empty-region.rs rename to src/test/ui/impl-trait/issues/issue-55608-captures-empty-region.rs index 7ebc348996f5e..50646edd61a85 100644 --- a/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs +++ b/src/test/ui/impl-trait/issues/issue-55608-captures-empty-region.rs @@ -1,9 +1,9 @@ // This used to ICE because it creates an `impl Trait` that captures a // hidden empty region. -#![feature(conservative_impl_trait)] +// compile-pass -fn server() -> impl FilterBase2 { //~ ERROR [E0700] +fn server() -> impl FilterBase2 { segment2(|| { loop { } }).map2(|| "") } diff --git a/src/test/ui/impl-trait/issues/issue-57464-unexpected-regions.rs b/src/test/ui/impl-trait/issues/issue-57464-unexpected-regions.rs new file mode 100644 index 0000000000000..11f1a392239dc --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-57464-unexpected-regions.rs @@ -0,0 +1,29 @@ +// Regression test for issue 57464. +// +// Closure are (surprisingly) allowed to outlive their signature. As such it +// was possible to end up with `ReScope`s appearing in the concrete type of an +// opaque type. As all regions are now required to outlive the bound in an +// opaque type we avoid the issue here. + +// compile-pass + +struct A(F); + +unsafe impl <'a, 'b, F: Fn(&'a i32) -> &'b i32> Send for A {} + +fn wrapped_closure() -> impl Sized { + let f = |x| x; + f(&0); + A(f) +} + +fn wrapped_closure_with_bound() -> impl Sized + 'static { + let f = |x| x; + f(&0); + A(f) +} + +fn main() { + let x: Box = Box::new(wrapped_closure()); + let y: Box = Box::new(wrapped_closure_with_bound()); +} diff --git a/src/test/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs b/src/test/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs new file mode 100644 index 0000000000000..5eef6a39325fe --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs @@ -0,0 +1,42 @@ +// rust-lang/rust#57979 : the initial support for `impl Trait` didn't +// properly check syntax hidden behind an associated type projection, +// but it did catch *some cases*. This is checking that we continue to +// properly emit errors for those, even with the new +// future-incompatibility warnings. +// +// issue-57979-nested-impl-trait-in-assoc-proj.rs shows the main case +// that we were previously failing to catch. + +struct Deeper(T); + +mod allowed { + #![allow(nested_impl_trait)] + + pub trait Foo { } + pub trait Bar { } + pub trait Quux { type Assoc; } + pub fn demo(_: impl Quux>>) { } + //~^ ERROR nested `impl Trait` is not allowed +} + +mod warned { + #![warn(nested_impl_trait)] + + pub trait Foo { } + pub trait Bar { } + pub trait Quux { type Assoc; } + pub fn demo(_: impl Quux>>) { } + //~^ ERROR nested `impl Trait` is not allowed +} + +mod denied { + #![deny(nested_impl_trait)] + + pub trait Foo { } + pub trait Bar { } + pub trait Quux { type Assoc; } + pub fn demo(_: impl Quux>>) { } + //~^ ERROR nested `impl Trait` is not allowed +} + +fn main() { } diff --git a/src/test/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr b/src/test/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr new file mode 100644 index 0000000000000..b9a1a4fa80a2b --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr @@ -0,0 +1,29 @@ +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs:18:59 + | +LL | pub fn demo(_: impl Quux>>) { } + | ---------^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs:28:59 + | +LL | pub fn demo(_: impl Quux>>) { } + | ---------^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs:38:59 + | +LL | pub fn demo(_: impl Quux>>) { } + | ---------^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs b/src/test/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs new file mode 100644 index 0000000000000..84fcb5e2880a7 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs @@ -0,0 +1,37 @@ +// rust-lang/rust#57979 : the initial support for `impl Trait` didn't +// properly check syntax hidden behind an associated type projection. +// Here we test behavior of occurrences of `impl Trait` within a path +// component in that context. + +mod allowed { + #![allow(nested_impl_trait)] + + pub trait Bar { } + pub trait Quux { type Assoc; } + pub fn demo(_: impl Quux<(), Assoc=<() as Quux>::Assoc>) { } + impl Quux for () { type Assoc = u32; } +} + +mod warned { + #![warn(nested_impl_trait)] + + pub trait Bar { } + pub trait Quux { type Assoc; } + pub fn demo(_: impl Quux<(), Assoc=<() as Quux>::Assoc>) { } + //~^ WARN `impl Trait` is not allowed in path parameters + //~| WARN will become a hard error in a future release! + impl Quux for () { type Assoc = u32; } +} + +mod denied { + #![deny(nested_impl_trait)] + + pub trait Bar { } + pub trait Quux { type Assoc; } + pub fn demo(_: impl Quux<(), Assoc=<() as Quux>::Assoc>) { } + //~^ ERROR `impl Trait` is not allowed in path parameters + //~| WARN will become a hard error in a future release! + impl Quux for () { type Assoc = u32; } +} + +fn main() { } diff --git a/src/test/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr b/src/test/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr new file mode 100644 index 0000000000000..982ecba291f79 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr @@ -0,0 +1,30 @@ +warning: `impl Trait` is not allowed in path parameters + --> $DIR/issue-57979-impl-trait-in-path.rs:20:52 + | +LL | pub fn demo(_: impl Quux<(), Assoc=<() as Quux>::Assoc>) { } + | ^^^^^^^^ + | +note: lint level defined here + --> $DIR/issue-57979-impl-trait-in-path.rs:16:13 + | +LL | #![warn(nested_impl_trait)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #59014 + +error: `impl Trait` is not allowed in path parameters + --> $DIR/issue-57979-impl-trait-in-path.rs:31:52 + | +LL | pub fn demo(_: impl Quux<(), Assoc=<() as Quux>::Assoc>) { } + | ^^^^^^^^ + | +note: lint level defined here + --> $DIR/issue-57979-impl-trait-in-path.rs:27:13 + | +LL | #![deny(nested_impl_trait)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #59014 + +error: aborting due to previous error + diff --git a/src/test/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs b/src/test/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs new file mode 100644 index 0000000000000..5c20ffc7c6724 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs @@ -0,0 +1,37 @@ +// rust-lang/rust#57979 : the initial support for `impl Trait` didn't +// properly check syntax hidden behind an associated type projection. +// Here we test behavior of occurrences of `impl Trait` within an +// `impl Trait` in that context. + +mod allowed { + #![allow(nested_impl_trait)] + + pub trait Foo { } + pub trait Bar { } + pub trait Quux { type Assoc; } + pub fn demo(_: impl Quux>) { } +} + +mod warned { + #![warn(nested_impl_trait)] + + pub trait Foo { } + pub trait Bar { } + pub trait Quux { type Assoc; } + pub fn demo(_: impl Quux>) { } + //~^ WARN nested `impl Trait` is not allowed + //~| WARN will become a hard error in a future release! +} + +mod denied { + #![deny(nested_impl_trait)] + + pub trait Foo { } + pub trait Bar { } + pub trait Quux { type Assoc; } + pub fn demo(_: impl Quux>) { } + //~^ ERROR nested `impl Trait` is not allowed + //~| WARN will become a hard error in a future release! +} + +fn main() { } diff --git a/src/test/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr b/src/test/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr new file mode 100644 index 0000000000000..508aea2432132 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr @@ -0,0 +1,36 @@ +warning: nested `impl Trait` is not allowed + --> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:21:45 + | +LL | pub fn demo(_: impl Quux>) { } + | ---------^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + | +note: lint level defined here + --> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:16:13 + | +LL | #![warn(nested_impl_trait)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #59014 + +error: nested `impl Trait` is not allowed + --> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:32:45 + | +LL | pub fn demo(_: impl Quux>) { } + | ---------^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + | +note: lint level defined here + --> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:27:13 + | +LL | #![deny(nested_impl_trait)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #59014 + +error: aborting due to previous error + diff --git a/src/test/ui/impl-trait/universal-issue-48703.rs b/src/test/ui/impl-trait/issues/universal-issue-48703.rs similarity index 100% rename from src/test/ui/impl-trait/universal-issue-48703.rs rename to src/test/ui/impl-trait/issues/universal-issue-48703.rs diff --git a/src/test/ui/impl-trait/issues/universal-issue-48703.stderr b/src/test/ui/impl-trait/issues/universal-issue-48703.stderr new file mode 100644 index 0000000000000..527bbd5f30fef --- /dev/null +++ b/src/test/ui/impl-trait/issues/universal-issue-48703.stderr @@ -0,0 +1,8 @@ +error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position. + --> $DIR/universal-issue-48703.rs:8:5 + | +LL | foo::('a'); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.rs b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.rs similarity index 100% rename from src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.rs rename to src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.rs diff --git a/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.stderr b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr similarity index 81% rename from src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.stderr rename to src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr index b7fc4d149e3d2..e2e6581fcf915 100644 --- a/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.stderr +++ b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr @@ -6,4 +6,3 @@ LL | evt.handle_event::(|_evt| { error: aborting due to previous error -For more information about this error, try `rustc --explain E0632`. diff --git a/src/test/ui/impl-trait/method-suggestion-no-duplication.rs b/src/test/ui/impl-trait/method-suggestion-no-duplication.rs index 32f3517167349..c5c966a959ae9 100644 --- a/src/test/ui/impl-trait/method-suggestion-no-duplication.rs +++ b/src/test/ui/impl-trait/method-suggestion-no-duplication.rs @@ -1,6 +1,4 @@ // issue #21405 -// ignore-tidy-linelength - struct Foo; fn foo(f: F) where F: FnMut(Foo) {} diff --git a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr index 8da1ce41a0f94..afb3376638a96 100644 --- a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr +++ b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `is_empty` found for type `Foo` in the current scope - --> $DIR/method-suggestion-no-duplication.rs:9:15 + --> $DIR/method-suggestion-no-duplication.rs:7:15 | LL | struct Foo; | ----------- method `is_empty` not found for this diff --git a/src/test/ui/impl-trait/multiple-lifetimes.rs b/src/test/ui/impl-trait/multiple-lifetimes.rs new file mode 100644 index 0000000000000..8346542135bec --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes.rs @@ -0,0 +1,12 @@ +// Test that multiple liftimes are allowed in impl trait types. +// compile-pass + +trait X<'x>: Sized {} + +impl X<'_> for U {} + +fn multiple_lifeteimes<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl X<'b> + 'a { + x +} + +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs new file mode 100644 index 0000000000000..61e858ee02d44 --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs @@ -0,0 +1,22 @@ +// compile-flags:-Zborrowck=mir + +#![feature(member_constraints)] +#![feature(existential_type)] + +#[derive(Clone)] +struct CopyIfEq(T, U); + +impl Copy for CopyIfEq {} + +existential type E<'a, 'b>: Sized; + +fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { + //~^ ERROR lifetime may not live long enough + let v = CopyIfEq::<*mut _, *mut _>(&mut {x}, &mut y); + let u = v; + let _: *mut &'a i32 = u.1; + unsafe { let _: &'b i32 = *u.0; } + u.0 +} + +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr new file mode 100644 index 0000000000000..b59dfbe9f2ada --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/error-handling.rs:13:56 + | +LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { + | -- lifetime `'a` defined here ^^^^^^^^^ opaque type requires that `'a` must outlive `'static` +help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a constraint + | +LL | existential type E<'a, 'b>: Sized; + 'a + | + +error: aborting due to previous error + diff --git a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs new file mode 100644 index 0000000000000..2da3886bb552b --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs @@ -0,0 +1,54 @@ +// edition:2018 +// run-pass +// revisions: migrate mir +//[mir]compile-flags: -Z borrowck=mir + +#![feature(member_constraints)] + +trait Trait<'a, 'b> {} +impl Trait<'_, '_> for T {} + +// `Invert<'a> <: Invert<'b>` if `'b: 'a`, unlike most types. +// +// I am purposefully avoiding the terms co- and contra-variant because +// their application to regions depends on how you interpreted Rust +// regions. -nikomatsakis +struct Invert<'a>(fn(&'a u8)); + +fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Invert<'a>, b: Invert<'b>) -> impl Trait<'d, 'e> +where + 'c: 'a, + 'c: 'b, + 'd: 'c, +{ + // Representing the where clauses as a graph, where `A: B` is an + // edge `B -> A`: + // + // ``` + // 'a -> 'c -> 'd + // ^ + // | + // 'b + // ``` + // + // Meanwhile we return a value &'0 u8 where we have the constraints: + // + // ``` + // '0: 'a + // '0: 'b + // '0 in ['d, 'e] + // ``` + // + // Here, ignoring the "in" constraint, the minimal choice for `'0` + // is `'c`, but that is not in the "in set". Still, that reduces + // the range of options in the "in set" to just `'d` (`'e: 'c` + // does not hold). + let p = if condition() { a } else { b }; + p +} + +fn condition() -> bool { + true +} + +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.stderr b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.stderr new file mode 100644 index 0000000000000..4de872e8441ef --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.stderr @@ -0,0 +1,19 @@ +warning[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/inverse-bounds.rs:16:70 + | +LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Invert<'a>, b: Invert<'b>) -> impl Trait<'d, 'e> + | ^^^^^^^^^^^^^^^^^^ + | + = note: hidden type `Invert<'_>` captures lifetime '_#8r + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + +warning: the feature `pin` has been stable since 1.33.0 and no longer requires an attribute to enable + --> $DIR/inverse-bounds.rs:4:60 + | +LL | #![feature(arbitrary_self_types, async_await, await_macro, pin)] + | ^^^ + | + = note: #[warn(stable_features)] on by default + diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs new file mode 100644 index 0000000000000..5f484773405cd --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs @@ -0,0 +1,29 @@ +// edition:2018 +// compile-pass +// revisions: migrate mir +//[mir]compile-flags: -Z borrowck=mir + +#![feature(member_constraints)] + +trait Trait<'a, 'b> { } +impl Trait<'_, '_> for T { } + +// Test case where we have elision in the impl trait and we have to +// pick the right region. + +// Ultimately `Trait<'x, 'static>`. +fn upper_bounds1(a: &u8) -> impl Trait<'_, 'static> { + (a, a) +} + +// Ultimately `Trait<'x, 'x>`, so not really multiple bounds. +fn upper_bounds2(a: &u8) -> impl Trait<'_, '_> { + (a, a) +} + +// Kind of a weird annoying case. +fn upper_bounds3<'b>(a: &u8) -> impl Trait<'_, 'b> { + (a, a) +} + +fn main() { } diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-existential.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-existential.rs new file mode 100644 index 0000000000000..c17ae6f0519bf --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-existential.rs @@ -0,0 +1,32 @@ +// edition:2018 +// compile-pass +// revisions: migrate mir +//[mir]compile-flags: -Z borrowck=mir + +#![feature(member_constraints)] +#![feature(existential_type)] + +trait Trait<'a, 'b> { } +impl Trait<'_, '_> for T { } + +// Here we wind up selecting `'a` and `'b` in the hidden type because +// those are the types that appear in the original values. + +existential type Foo<'a, 'b>: Trait<'a, 'b>; + +fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> Foo<'a, 'b> { + // In this simple case, you have a hidden type `(&'0 u8, &'1 u8)` and constraints like + // + // ``` + // 'a: '0 + // 'b: '1 + // '0 in ['a, 'b] + // '1 in ['a, 'b] + // ``` + // + // We use the fact that `'a: 0'` must hold (combined with the in + // constraint) to determine that `'0 = 'a` must be the answer. + (a, b) +} + +fn main() { } diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs new file mode 100644 index 0000000000000..31891ef15c754 --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs @@ -0,0 +1,29 @@ +// edition:2018 +// compile-pass +// revisions: migrate mir +//[mir]compile-flags: -Z borrowck=mir + +#![feature(member_constraints)] + +trait Trait<'a, 'b> { } +impl Trait<'_, '_> for T { } + +// Here we wind up selecting `'a` and `'b` in the hidden type because +// those are the types that appear in the original values. + +fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { + // In this simple case, you have a hidden type `(&'0 u8, &'1 u8)` and constraints like + // + // ``` + // 'a: '0 + // 'b: '1 + // '0 in ['a, 'b] + // '1 in ['a, 'b] + // ``` + // + // We use the fact that `'a: 0'` must hold (combined with the in + // constraint) to determine that `'0 = 'a` must be the answer. + (a, b) +} + +fn main() { } diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs new file mode 100644 index 0000000000000..29c997085d8f4 --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs @@ -0,0 +1,46 @@ +// edition:2018 +// compile-pass +// revisions: migrate mir +//[mir]compile-flags: -Z borrowck=mir + +#![feature(member_constraints)] + +trait Trait<'a, 'b> {} +impl Trait<'_, '_> for T {} + +// `Ordinary<'a> <: Ordinary<'b>` if `'a: 'b`, as with most types. +// +// I am purposefully avoiding the terms co- and contra-variant because +// their application to regions depends on how you interpreted Rust +// regions. -nikomatsakis +struct Ordinary<'a>(&'a u8); + +// Here we wind up selecting `'e` in the hidden type because +// we need something outlived by both `'a` and `'b` and only `'e` applies. + +fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> +where + 'a: 'e, + 'b: 'e, + 'a: 'd, +{ + // We return a value: + // + // ``` + // 'a: '0 + // 'b: '1 + // '0 in ['d, 'e] + // ``` + // + // but we don't have it. + // + // We are forced to pick that '0 = 'e, because only 'e is outlived by *both* 'a and 'b. + let p = if condition() { a } else { b }; + p +} + +fn condition() -> bool { + true +} + +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr new file mode 100644 index 0000000000000..a255c48ec6ef1 --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr @@ -0,0 +1,9 @@ +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/ordinary-bounds-unrelated.rs:18:74 + | +LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs new file mode 100644 index 0000000000000..db1641b0140b9 --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs @@ -0,0 +1,38 @@ +// edition:2018 + +#![feature(member_constraints)] + +trait Trait<'a, 'b> {} +impl Trait<'_, '_> for T {} + +// `Ordinary<'a> <: Ordinary<'b>` if `'a: 'b`, as with most types. +// +// I am purposefully avoiding the terms co- and contra-variant because +// their application to regions depends on how you interpreted Rust +// regions. -nikomatsakis +struct Ordinary<'a>(&'a u8); + +// Here we get an error because none of our choices (either `'d` nor `'e`) are outlived +// by both `'a` and `'b`. + +fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> +//~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds +where + 'a: 'e, + 'b: 'd, +{ + // Hidden type `Ordinary<'0>` with constraints: + // + // ``` + // 'a: '0 + // 'b: '0 + // 'a in ['d, 'e] + // ``` + if condition() { a } else { b } +} + +fn condition() -> bool { + true +} + +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr new file mode 100644 index 0000000000000..cd2d46ac18218 --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr @@ -0,0 +1,21 @@ +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/ordinary-bounds-unrelated.rs:18:74 + | +LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + | ^^^^^^^^^^^^^^^^^^ + | +note: hidden type `Ordinary<'_>` captures the scope of call-site for function at 23:1 + --> $DIR/ordinary-bounds-unrelated.rs:23:1 + | +LL | / { +LL | | // Hidden type `Ordinary<'0>` with constraints: +LL | | // +LL | | // ``` +... | +LL | | if condition() { a } else { b } +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr new file mode 100644 index 0000000000000..af42ed1c5c15a --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr @@ -0,0 +1,9 @@ +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/ordinary-bounds-unsuited.rs:20:62 + | +LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs new file mode 100644 index 0000000000000..7f9c92f15a2f9 --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs @@ -0,0 +1,41 @@ +// edition:2018 + +#![feature(member_constraints)] + +trait Trait<'a, 'b> {} +impl Trait<'_, '_> for T {} + +// `Ordinary<'a> <: Ordinary<'b>` if `'a: 'b`, as with most types. +// +// I am purposefully avoiding the terms co- and contra-variant because +// their application to regions depends on how you interpreted Rust +// regions. -nikomatsakis +struct Ordinary<'a>(&'a u8); + +// Here we need something outlived by `'a` *and* outlived by `'b`, but +// we can only name `'a` and `'b` (and neither suits). So we get an +// error. Somewhat unfortunate, though, since the caller would have to +// consider the loans for both `'a` and `'b` alive. + +fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds +{ + // We return a value: + // + // ``` + // 'a: '0 + // 'b: '1 + // '0 in ['a, 'b] + // ``` + // + // but we don't have it. + // + // We are forced to pick that '0 = 'e, because only 'e is outlived by *both* 'a and 'b. + if condition() { a } else { b } +} + +fn condition() -> bool { + true +} + +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr new file mode 100644 index 0000000000000..59ce93fa78b6b --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr @@ -0,0 +1,21 @@ +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/ordinary-bounds-unsuited.rs:20:62 + | +LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + | ^^^^^^^^^^^^^^^^^^ + | +note: hidden type `Ordinary<'_>` captures the scope of call-site for function at 22:1 + --> $DIR/ordinary-bounds-unsuited.rs:22:1 + | +LL | / { +LL | | // We return a value: +LL | | // +LL | | // ``` +... | +LL | | if condition() { a } else { b } +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr new file mode 100644 index 0000000000000..b1e4edd998094 --- /dev/null +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr @@ -0,0 +1,51 @@ +error: lifetime may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:3:23 + | +LL | fn elided(x: &i32) -> impl Copy { x } + | - ^^^^^^^^^ opaque type requires that `'1` must outlive `'static` + | | + | let's call the lifetime of this reference `'1` +help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a constraint + | +LL | fn elided(x: &i32) -> impl Copy + '_ { x } + | ^^^^^^^^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:6:32 + | +LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } + | -- ^^^^^^^^^ opaque type requires that `'a` must outlive `'static` + | | + | lifetime `'a` defined here +help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a constraint + | +LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } + | ^^^^^^^^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:12:69 + | +LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } + | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` + | + = help: consider replacing `'a` with `'static` + +error: lifetime may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:17:61 + | +LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { + | -- -- lifetime `'b` defined here ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a` + | | + | lifetime `'a` defined here + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:22:51 + | +LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'static`... + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs index ef1b976ae333f..1c3b5ac76138f 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs @@ -1,7 +1,7 @@ use std::fmt::Debug; fn elided(x: &i32) -> impl Copy { x } -//~^ ERROR explicit lifetime required in the type of `x` [E0621] +//~^ ERROR cannot infer an appropriate lifetime fn explicit<'a>(x: &'a i32) -> impl Copy { x } //~^ ERROR cannot infer an appropriate lifetime diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 8a477e42a66ef..a6ea7837678ed 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -1,10 +1,20 @@ -error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/must_outlive_least_region_or_bound.rs:3:23 +error: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:3:35 | LL | fn elided(x: &i32) -> impl Copy { x } - | ---- ^^^^^^^^^ lifetime `'static` required - | | - | help: add explicit lifetime `'static` to the type of `x`: `&'static i32` + | --------- ^ ...but this borrow... + | | + | this return type evaluates to the `'static` lifetime... + | +note: ...can't outlive the anonymous lifetime #1 defined on the function body at 3:1 + --> $DIR/must_outlive_least_region_or_bound.rs:3:1 + | +LL | fn elided(x: &i32) -> impl Copy { x } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 3:1 + | +LL | fn elided(x: &i32) -> impl Copy + '_ { x } + | ^^^^^^^^^^^^^^ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:6:44 @@ -67,5 +77,4 @@ LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { error: aborting due to 5 previous errors -Some errors occurred: E0310, E0621, E0623. -For more information about an error, try `rustc --explain E0310`. +For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/impl-trait/needs_least_region_or_bound.rs b/src/test/ui/impl-trait/needs_least_region_or_bound.rs index 2a5b365559e77..52475f65a8353 100644 --- a/src/test/ui/impl-trait/needs_least_region_or_bound.rs +++ b/src/test/ui/impl-trait/needs_least_region_or_bound.rs @@ -1,10 +1,24 @@ +// run-pass + +#![feature(member_constraints)] + use std::fmt::Debug; trait MultiRegionTrait<'a, 'b> {} impl<'a, 'b> MultiRegionTrait<'a, 'b> for (&'a u32, &'b u32) {} fn no_least_region<'a, 'b>(x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> { -//~^ ERROR ambiguous lifetime bound + // Here we have a constraint that: + // + // (x, y) has type (&'0 u32, &'1 u32) + // + // where + // + // 'a: '0 + // + // then we require that `('0 u32, &'1 u32): MultiRegionTrait<'a, + // 'b>`, which winds up imposing a requirement that `'0 = 'a` and + // `'1 = 'b`. (x, y) } diff --git a/src/test/ui/impl-trait/needs_least_region_or_bound.stderr b/src/test/ui/impl-trait/needs_least_region_or_bound.stderr deleted file mode 100644 index f1b4d9c58f39f..0000000000000 --- a/src/test/ui/impl-trait/needs_least_region_or_bound.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: ambiguous lifetime bound in `impl Trait` - --> $DIR/needs_least_region_or_bound.rs:6:55 - | -LL | fn no_least_region<'a, 'b>(x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other - -error: aborting due to previous error - diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr index a3b118efa62c5..d980d7cccadd5 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -220,19 +220,19 @@ LL | std::rc::Rc::new(&mut Box::new(&Bar::X)).method3(); error[E0599]: no method named `method3` found for type `usize` in the current scope --> $DIR/no-method-suggested-traits.rs:69:13 | -LL | 1_usize.method3(); //~ ERROR no method named +LL | 1_usize.method3(); | ^^^^^^^ error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&usize>>` in the current scope --> $DIR/no-method-suggested-traits.rs:70:47 | -LL | std::rc::Rc::new(&mut Box::new(&1_usize)).method3(); //~ ERROR no method named +LL | std::rc::Rc::new(&mut Box::new(&1_usize)).method3(); | ^^^^^^^ error[E0599]: no method named `method3` found for type `no_method_suggested_traits::Foo` in the current scope --> $DIR/no-method-suggested-traits.rs:71:37 | -LL | no_method_suggested_traits::Foo.method3(); //~ ERROR no method named +LL | no_method_suggested_traits::Foo.method3(); | ^^^^^^^ error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope @@ -244,7 +244,7 @@ LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).metho error[E0599]: no method named `method3` found for type `no_method_suggested_traits::Bar` in the current scope --> $DIR/no-method-suggested-traits.rs:74:40 | -LL | no_method_suggested_traits::Bar::X.method3(); //~ ERROR no method named +LL | no_method_suggested_traits::Bar::X.method3(); | ^^^^^^^ error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope diff --git a/src/test/ui/impl-trait/no-trait.stderr b/src/test/ui/impl-trait/no-trait.stderr index 84ac1bd5ca4a3..3a636f2524fff 100644 --- a/src/test/ui/impl-trait/no-trait.stderr +++ b/src/test/ui/impl-trait/no-trait.stderr @@ -1,7 +1,7 @@ error: at least one trait must be specified --> $DIR/no-trait.rs:1:11 | -LL | fn f() -> impl 'static {} //~ ERROR at least one trait must be specified +LL | fn f() -> impl 'static {} | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type.rs b/src/test/ui/impl-trait/recursive-impl-trait-type.rs index 869876dc6a88a..2428b560b7001 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type.rs +++ b/src/test/ui/impl-trait/recursive-impl-trait-type.rs @@ -1,7 +1,7 @@ // Test that impl trait does not allow creating recursive types that are // otherwise forbidden. -#![feature(futures_api, generators)] +#![feature(generators)] fn option(i: i32) -> impl Sized { //~ ERROR if i < 0 { diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type.stderr index 96494229fd339..fce234eb87ced 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type.stderr @@ -1,7 +1,7 @@ error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:6:22 | -LL | fn option(i: i32) -> impl Sized { //~ ERROR +LL | fn option(i: i32) -> impl Sized { | ^^^^^^^^^^ expands to self-referential type | = note: expanded type is `std::option::Option<(impl Sized, i32)>` @@ -9,7 +9,7 @@ LL | fn option(i: i32) -> impl Sized { //~ ERROR error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:14:15 | -LL | fn tuple() -> impl Sized { //~ ERROR +LL | fn tuple() -> impl Sized { | ^^^^^^^^^^ expands to self-referential type | = note: expanded type is `(impl Sized,)` @@ -17,7 +17,7 @@ LL | fn tuple() -> impl Sized { //~ ERROR error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:18:15 | -LL | fn array() -> impl Sized { //~ ERROR +LL | fn array() -> impl Sized { | ^^^^^^^^^^ expands to self-referential type | = note: expanded type is `[impl Sized; 1]` @@ -25,7 +25,7 @@ LL | fn array() -> impl Sized { //~ ERROR error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:22:13 | -LL | fn ptr() -> impl Sized { //~ ERROR +LL | fn ptr() -> impl Sized { | ^^^^^^^^^^ expands to self-referential type | = note: expanded type is `*const impl Sized` @@ -33,7 +33,7 @@ LL | fn ptr() -> impl Sized { //~ ERROR error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:26:16 | -LL | fn fn_ptr() -> impl Sized { //~ ERROR +LL | fn fn_ptr() -> impl Sized { | ^^^^^^^^^^ expands to self-referential type | = note: expanded type is `fn() -> impl Sized` @@ -41,7 +41,7 @@ LL | fn fn_ptr() -> impl Sized { //~ ERROR error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:30:25 | -LL | fn closure_capture() -> impl Sized { //~ ERROR +LL | fn closure_capture() -> impl Sized { | ^^^^^^^^^^ expands to self-referential type | = note: expanded type is `[closure@$DIR/recursive-impl-trait-type.rs:32:5: 32:19 x:impl Sized]` @@ -49,7 +49,7 @@ LL | fn closure_capture() -> impl Sized { //~ ERROR error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:35:29 | -LL | fn closure_ref_capture() -> impl Sized { //~ ERROR +LL | fn closure_ref_capture() -> impl Sized { | ^^^^^^^^^^ expands to self-referential type | = note: expanded type is `[closure@$DIR/recursive-impl-trait-type.rs:37:5: 37:20 x:impl Sized]` @@ -57,7 +57,7 @@ LL | fn closure_ref_capture() -> impl Sized { //~ ERROR error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:40:21 | -LL | fn closure_sig() -> impl Sized { //~ ERROR +LL | fn closure_sig() -> impl Sized { | ^^^^^^^^^^ expands to self-referential type | = note: expanded type is `[closure@$DIR/recursive-impl-trait-type.rs:41:5: 41:21]` @@ -65,7 +65,7 @@ LL | fn closure_sig() -> impl Sized { //~ ERROR error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:44:23 | -LL | fn generator_sig() -> impl Sized { //~ ERROR +LL | fn generator_sig() -> impl Sized { | ^^^^^^^^^^ expands to self-referential type | = note: expanded type is `[closure@$DIR/recursive-impl-trait-type.rs:45:5: 45:23]` @@ -73,7 +73,7 @@ LL | fn generator_sig() -> impl Sized { //~ ERROR error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:48:27 | -LL | fn generator_capture() -> impl Sized { //~ ERROR +LL | fn generator_capture() -> impl Sized { | ^^^^^^^^^^ expands to self-referential type | = note: expanded type is `[generator@$DIR/recursive-impl-trait-type.rs:50:5: 50:26 x:impl Sized {()}]` @@ -81,7 +81,7 @@ LL | fn generator_capture() -> impl Sized { //~ ERROR error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:53:26 | -LL | fn substs_change() -> impl Sized { //~ ERROR +LL | fn substs_change() -> impl Sized { | ^^^^^^^^^^ expands to self-referential type | = note: expanded type is `(impl Sized,)` @@ -89,7 +89,7 @@ LL | fn substs_change() -> impl Sized { //~ ERROR error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:57:24 | -LL | fn generator_hold() -> impl Sized { //~ ERROR +LL | fn generator_hold() -> impl Sized { | ^^^^^^^^^^ expands to self-referential type | = note: expanded type is `[generator@$DIR/recursive-impl-trait-type.rs:58:5: 62:6 {impl Sized, ()}]` @@ -97,7 +97,7 @@ LL | fn generator_hold() -> impl Sized { //~ ERROR error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:69:26 | -LL | fn mutual_recursion() -> impl Sync { //~ ERROR +LL | fn mutual_recursion() -> impl Sync { | ^^^^^^^^^ expands to self-referential type | = note: type resolves to itself @@ -105,7 +105,7 @@ LL | fn mutual_recursion() -> impl Sync { //~ ERROR error[E0720]: opaque type expands to a recursive type --> $DIR/recursive-impl-trait-type.rs:73:28 | -LL | fn mutual_recursion_b() -> impl Sized { //~ ERROR +LL | fn mutual_recursion_b() -> impl Sized { | ^^^^^^^^^^ expands to self-referential type | = note: type resolves to itself diff --git a/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs b/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs index cb40d90ae551a..adaa474474f67 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs @@ -9,7 +9,6 @@ #![allow(dead_code)] #![feature(in_band_lifetimes)] -#![feature(nll)] fn foo(x: &'x u32) -> impl Fn() -> &'y u32 where 'x: 'y diff --git a/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs b/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs index e2310a3907f7e..204c2ff304114 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs @@ -9,7 +9,6 @@ #![allow(dead_code)] #![feature(in_band_lifetimes)] -#![feature(nll)] trait Trait<'a> { } diff --git a/src/test/ui/impl-trait/region-escape-via-bound.rs b/src/test/ui/impl-trait/region-escape-via-bound.rs index d62aec800e8ce..29243699e44fd 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound.rs @@ -5,7 +5,6 @@ #![allow(dead_code)] #![feature(in_band_lifetimes)] -#![feature(nll)] use std::cell::Cell; diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr index 81b44b7eba7fd..5c8e322f712d1 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.stderr +++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr @@ -1,11 +1,11 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/region-escape-via-bound.rs:16:29 + --> $DIR/region-escape-via-bound.rs:15:29 | LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y> | ^^^^^^^^^^^^^^ | -note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 18:7 - --> $DIR/region-escape-via-bound.rs:18:7 +note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 17:7 + --> $DIR/region-escape-via-bound.rs:17:7 | LL | where 'x: 'y | ^^ diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr new file mode 100644 index 0000000000000..0736f25cb51bd --- /dev/null +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr @@ -0,0 +1,26 @@ +error: lifetime may not live long enough + --> $DIR/static-return-lifetime-infered.rs:6:35 + | +LL | fn iter_values_anon(&self) -> impl Iterator { + | - ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static` + | | + | let's call the lifetime of this reference `'1` +help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a constraint + | +LL | fn iter_values_anon(&self) -> impl Iterator + '_ { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-return-lifetime-infered.rs:10:37 + | +LL | fn iter_values<'a>(&'a self) -> impl Iterator { + | -- ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static` + | | + | lifetime `'a` defined here +help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a constraint + | +LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/impl-trait/trait_type.stderr b/src/test/ui/impl-trait/trait_type.stderr index a1f6b73abff2d..129d7ef5783ce 100644 --- a/src/test/ui/impl-trait/trait_type.stderr +++ b/src/test/ui/impl-trait/trait_type.stderr @@ -33,5 +33,5 @@ LL | impl std::fmt::Display for MyType4 {} error: aborting due to 4 previous errors -Some errors occurred: E0046, E0050, E0053, E0186. +Some errors have detailed explanations: E0046, E0050, E0053, E0186. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/impl-trait/type_parameters_captured.nll.stderr b/src/test/ui/impl-trait/type_parameters_captured.nll.stderr new file mode 100644 index 0000000000000..039cb62f86656 --- /dev/null +++ b/src/test/ui/impl-trait/type_parameters_captured.nll.stderr @@ -0,0 +1,11 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/type_parameters_captured.rs:7:20 + | +LL | fn foo(x: T) -> impl Any + 'static { + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'static`... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/impl-trait/universal-issue-48703.stderr b/src/test/ui/impl-trait/universal-issue-48703.stderr deleted file mode 100644 index 920b44fc909ab..0000000000000 --- a/src/test/ui/impl-trait/universal-issue-48703.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position. - --> $DIR/universal-issue-48703.rs:8:5 - | -LL | foo::('a'); //~ ERROR cannot provide explicit type parameters - | ^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0632`. diff --git a/src/test/ui/impl-trait/universal-mismatched-type.stderr b/src/test/ui/impl-trait/universal-mismatched-type.stderr index 55e1216d3a8a0..d223b9672cfdc 100644 --- a/src/test/ui/impl-trait/universal-mismatched-type.stderr +++ b/src/test/ui/impl-trait/universal-mismatched-type.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | fn foo(x: impl Debug) -> String { | ------ expected `std::string::String` because of return type -LL | x //~ ERROR mismatched types +LL | x | ^ expected struct `std::string::String`, found type parameter | = note: expected type `std::string::String` diff --git a/src/test/ui/impl-trait/universal-two-impl-traits.stderr b/src/test/ui/impl-trait/universal-two-impl-traits.stderr index 43bf2862feea5..145d6a8431bf4 100644 --- a/src/test/ui/impl-trait/universal-two-impl-traits.stderr +++ b/src/test/ui/impl-trait/universal-two-impl-traits.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/universal-two-impl-traits.rs:5:9 | -LL | a = y; //~ ERROR mismatched +LL | a = y; | ^ expected type parameter, found a different type parameter | = note: expected type `impl Debug` (type parameter) diff --git a/src/test/ui/impl-trait/universal_wrong_bounds.stderr b/src/test/ui/impl-trait/universal_wrong_bounds.stderr index f0b685bd5ee91..1fd3ebff62a81 100644 --- a/src/test/ui/impl-trait/universal_wrong_bounds.stderr +++ b/src/test/ui/impl-trait/universal_wrong_bounds.stderr @@ -1,7 +1,7 @@ error[E0405]: cannot find trait `Debug` in this scope --> $DIR/universal_wrong_bounds.rs:9:24 | -LL | fn wants_debug(g: impl Debug) { } //~ ERROR cannot find +LL | fn wants_debug(g: impl Debug) { } | ^^^^^ not found in this scope help: possible candidate is found in another module, you can import it into scope | @@ -11,7 +11,7 @@ LL | use std::fmt::Debug; error[E0405]: cannot find trait `Debug` in this scope --> $DIR/universal_wrong_bounds.rs:10:26 | -LL | fn wants_display(g: impl Debug) { } //~ ERROR cannot find +LL | fn wants_display(g: impl Debug) { } | ^^^^^ not found in this scope help: possible candidate is found in another module, you can import it into scope | diff --git a/src/test/ui/impl-trait/where-allowed.stderr b/src/test/ui/impl-trait/where-allowed.stderr index 7218e82922975..e7a8430faeac5 100644 --- a/src/test/ui/impl-trait/where-allowed.stderr +++ b/src/test/ui/impl-trait/where-allowed.stderr @@ -242,5 +242,4 @@ LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; error: aborting due to 39 previous errors -Some errors occurred: E0562, E0666. -For more information about an error, try `rustc --explain E0562`. +For more information about this error, try `rustc --explain E0562`. diff --git a/src/test/ui/impl-unused-rps-in-assoc-type.stderr b/src/test/ui/impl-unused-rps-in-assoc-type.stderr index 80fc0504558f9..c7ad1b4e608fc 100644 --- a/src/test/ui/impl-unused-rps-in-assoc-type.stderr +++ b/src/test/ui/impl-unused-rps-in-assoc-type.stderr @@ -1,7 +1,7 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates --> $DIR/impl-unused-rps-in-assoc-type.rs:11:6 | -LL | impl<'a> Fun for Holder { //~ ERROR E0207 +LL | impl<'a> Fun for Holder { | ^^ unconstrained lifetime parameter error: aborting due to previous error diff --git a/src/test/ui/implicit-method-bind.stderr b/src/test/ui/implicit-method-bind.stderr index 7c70709c6b978..968272d4d2c19 100644 --- a/src/test/ui/implicit-method-bind.stderr +++ b/src/test/ui/implicit-method-bind.stderr @@ -1,7 +1,7 @@ error[E0615]: attempted to take value of method `abs` on type `i32` --> $DIR/implicit-method-bind.rs:2:20 | -LL | let _f = 10i32.abs; //~ ERROR attempted to take value of method +LL | let _f = 10i32.abs; | ^^^ help: use parentheses to call the method: `abs()` error: aborting due to previous error diff --git a/src/test/ui/import.rs b/src/test/ui/import.rs index 540258daaec82..3170dd2fae108 100644 --- a/src/test/ui/import.rs +++ b/src/test/ui/import.rs @@ -1,6 +1,8 @@ use zed::bar; use zed::baz; //~ ERROR unresolved import `zed::baz` [E0432] - //~^ no `baz` in `zed`. Did you mean to use `bar`? + //~| no `baz` in `zed` + //~| HELP a similar name exists in the module + //~| SUGGESTION bar mod zed { diff --git a/src/test/ui/import.stderr b/src/test/ui/import.stderr index 737d10cdecb23..6b320b198a0b1 100644 --- a/src/test/ui/import.stderr +++ b/src/test/ui/import.stderr @@ -1,22 +1,25 @@ error[E0432]: unresolved import `zed::baz` --> $DIR/import.rs:2:5 | -LL | use zed::baz; //~ ERROR unresolved import `zed::baz` [E0432] - | ^^^^^^^^ no `baz` in `zed`. Did you mean to use `bar`? +LL | use zed::baz; + | ^^^^^--- + | | | + | | help: a similar name exists in the module: `bar` + | no `baz` in `zed` error[E0432]: unresolved import `foo` - --> $DIR/import.rs:8:9 + --> $DIR/import.rs:10:9 | -LL | use foo; //~ ERROR unresolved import `foo` [E0432] +LL | use foo; | ^^^ no `foo` in the root error[E0603]: unresolved item `foo` is private - --> $DIR/import.rs:13:10 + --> $DIR/import.rs:15:10 | -LL | zed::foo(); //~ ERROR `foo` is private +LL | zed::foo(); | ^^^ error: aborting due to 3 previous errors -Some errors occurred: E0432, E0603. +Some errors have detailed explanations: E0432, E0603. For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/import2.stderr b/src/test/ui/import2.stderr index f0509204f2ce0..da888979c30f0 100644 --- a/src/test/ui/import2.stderr +++ b/src/test/ui/import2.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `baz::zed` --> $DIR/import2.rs:1:10 | -LL | use baz::zed::bar; //~ ERROR unresolved import `baz::zed` [E0432] +LL | use baz::zed::bar; | ^^^ could not find `zed` in `baz` error: aborting due to previous error diff --git a/src/test/ui/imports/auxiliary/gensymed.rs b/src/test/ui/imports/auxiliary/gensymed.rs new file mode 100644 index 0000000000000..bbb19f5ec6519 --- /dev/null +++ b/src/test/ui/imports/auxiliary/gensymed.rs @@ -0,0 +1,3 @@ +// edition:2018 + +mod std {} diff --git a/src/test/ui/imports/duplicate.stderr b/src/test/ui/imports/duplicate.stderr index 29660d908e485..0dbcb5f1de3f9 100644 --- a/src/test/ui/imports/duplicate.stderr +++ b/src/test/ui/imports/duplicate.stderr @@ -3,18 +3,15 @@ error[E0252]: the name `foo` is defined multiple times | LL | use a::foo; | ------ previous import of the value `foo` here -LL | use a::foo; //~ ERROR the name `foo` is defined multiple times - | ----^^^^^^- - | | | - | | `foo` reimported here - | help: remove unnecessary import +LL | use a::foo; + | ^^^^^^ `foo` reimported here | = note: `foo` must be defined only once in the value namespace of this module error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module) --> $DIR/duplicate.rs:46:15 | -LL | use self::foo::bar; //~ ERROR `foo` is ambiguous +LL | use self::foo::bar; | ^^^ ambiguous name | note: `foo` could refer to the module imported here @@ -33,7 +30,7 @@ LL | use self::m2::*; error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module) --> $DIR/duplicate.rs:35:8 | -LL | f::foo(); //~ ERROR `foo` is ambiguous +LL | f::foo(); | ^^^ ambiguous name | note: `foo` could refer to the function imported here @@ -52,7 +49,7 @@ LL | pub use b::*; error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module) --> $DIR/duplicate.rs:49:9 | -LL | foo::bar(); //~ ERROR `foo` is ambiguous +LL | foo::bar(); | ^^^ ambiguous name | note: `foo` could refer to the module imported here @@ -70,5 +67,5 @@ LL | use self::m2::*; error: aborting due to 4 previous errors -Some errors occurred: E0252, E0659. +Some errors have detailed explanations: E0252, E0659. For more information about an error, try `rustc --explain E0252`. diff --git a/src/test/ui/imports/extern-crate-self/extern-crate-self-fail.stderr b/src/test/ui/imports/extern-crate-self/extern-crate-self-fail.stderr index b47d10343f689..f26bb2f5a0ec4 100644 --- a/src/test/ui/imports/extern-crate-self/extern-crate-self-fail.stderr +++ b/src/test/ui/imports/extern-crate-self/extern-crate-self-fail.stderr @@ -1,13 +1,13 @@ error: `extern crate self;` requires renaming --> $DIR/extern-crate-self-fail.rs:1:1 | -LL | extern crate self; //~ ERROR `extern crate self;` requires renaming +LL | extern crate self; | ^^^^^^^^^^^^^^^^^^ help: try: `extern crate self as name;` error: `macro_use` is not supported on `extern crate self` --> $DIR/extern-crate-self-fail.rs:3:1 | -LL | #[macro_use] //~ ERROR `macro_use` is not supported on `extern crate self` +LL | #[macro_use] | ^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/imports/extern-crate-used.rs b/src/test/ui/imports/extern-crate-used.rs index 2d91cbc00f27d..8198c1816a141 100644 --- a/src/test/ui/imports/extern-crate-used.rs +++ b/src/test/ui/imports/extern-crate-used.rs @@ -5,10 +5,14 @@ #![deny(unused_extern_crates)] -extern crate core as iso1; //~ ERROR `extern crate` is not idiomatic in the new edition -extern crate core as iso2; //~ ERROR `extern crate` is not idiomatic in the new edition -extern crate core as iso3; //~ ERROR `extern crate` is not idiomatic in the new edition -extern crate core as iso4; //~ ERROR `extern crate` is not idiomatic in the new edition +// Shouldn't suggest changing to `use`, as new name +// would no longer be added to the prelude which could cause +// compilation errors for imports that use the new name in +// other modules. See #57672. +extern crate core as iso1; +extern crate core as iso2; +extern crate core as iso3; +extern crate core as iso4; // Doesn't introduce its extern prelude entry, so it's still considered unused. extern crate core; //~ ERROR unused extern crate @@ -16,13 +20,13 @@ extern crate core; //~ ERROR unused extern crate mod m { use iso1::any as are_you_okay1; use ::iso2::any as are_you_okay2; - type AreYouOkay1 = iso3::any::Any; - type AreYouOkay2 = ::iso4::any::Any; + type AreYouOkay1 = dyn iso3::any::Any; + type AreYouOkay2 = dyn (::iso4::any::Any); use core::any as are_you_okay3; use ::core::any as are_you_okay4; - type AreYouOkay3 = core::any::Any; - type AreYouOkay4 = ::core::any::Any; + type AreYouOkay3 = dyn core::any::Any; + type AreYouOkay4 = dyn (::core::any::Any); } fn main() {} diff --git a/src/test/ui/imports/extern-crate-used.stderr b/src/test/ui/imports/extern-crate-used.stderr index 3f9aab9dc79cb..397bfa02902c9 100644 --- a/src/test/ui/imports/extern-crate-used.stderr +++ b/src/test/ui/imports/extern-crate-used.stderr @@ -1,8 +1,8 @@ -error: `extern crate` is not idiomatic in the new edition - --> $DIR/extern-crate-used.rs:8:1 +error: unused extern crate + --> $DIR/extern-crate-used.rs:18:1 | -LL | extern crate core as iso1; //~ ERROR `extern crate` is not idiomatic in the new edition - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use` +LL | extern crate core; + | ^^^^^^^^^^^^^^^^^^ help: remove it | note: lint level defined here --> $DIR/extern-crate-used.rs:6:9 @@ -10,29 +10,5 @@ note: lint level defined here LL | #![deny(unused_extern_crates)] | ^^^^^^^^^^^^^^^^^^^^ -error: `extern crate` is not idiomatic in the new edition - --> $DIR/extern-crate-used.rs:9:1 - | -LL | extern crate core as iso2; //~ ERROR `extern crate` is not idiomatic in the new edition - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use` - -error: `extern crate` is not idiomatic in the new edition - --> $DIR/extern-crate-used.rs:10:1 - | -LL | extern crate core as iso3; //~ ERROR `extern crate` is not idiomatic in the new edition - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use` - -error: `extern crate` is not idiomatic in the new edition - --> $DIR/extern-crate-used.rs:11:1 - | -LL | extern crate core as iso4; //~ ERROR `extern crate` is not idiomatic in the new edition - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use` - -error: unused extern crate - --> $DIR/extern-crate-used.rs:14:1 - | -LL | extern crate core; //~ ERROR unused extern crate - | ^^^^^^^^^^^^^^^^^^ help: remove it - -error: aborting due to 5 previous errors +error: aborting due to previous error diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr index baeed02517d18..e067432b39237 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr +++ b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr @@ -10,7 +10,7 @@ LL | define_std_as_non_existent!(); error[E0433]: failed to resolve: use of undeclared type or module `two_macros` --> $DIR/extern-prelude-extern-crate-fail.rs:10:9 | -LL | two_macros::m!(); //~ ERROR failed to resolve: use of undeclared type or module `two_macros` +LL | two_macros::m!(); | ^^^^^^^^^^ use of undeclared type or module `two_macros` error: aborting due to 2 previous errors diff --git a/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr b/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr index 795e1761ccdb3..24b1b582d1ea3 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr +++ b/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr @@ -10,7 +10,7 @@ LL | define_other_core!(); error[E0659]: `Vec` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:13:9 | -LL | Vec::panic!(); //~ ERROR `Vec` is ambiguous +LL | Vec::panic!(); | ^^^ ambiguous name | = note: `Vec` could refer to a struct from prelude diff --git a/src/test/ui/imports/gensymed.rs b/src/test/ui/imports/gensymed.rs new file mode 100644 index 0000000000000..317441079ff87 --- /dev/null +++ b/src/test/ui/imports/gensymed.rs @@ -0,0 +1,7 @@ +// compile-pass +// edition:2018 +// aux-build:gensymed.rs + +extern crate gensymed; + +fn main() {} diff --git a/src/test/ui/imports/glob-conflict-cross-crate.stderr b/src/test/ui/imports/glob-conflict-cross-crate.stderr index f5a82ef1b3b01..ad70b7d5b91b0 100644 --- a/src/test/ui/imports/glob-conflict-cross-crate.stderr +++ b/src/test/ui/imports/glob-conflict-cross-crate.stderr @@ -1,13 +1,13 @@ error[E0425]: cannot find function `f` in module `glob_conflict` --> $DIR/glob-conflict-cross-crate.rs:6:20 | -LL | glob_conflict::f(); //~ ERROR cannot find function `f` in module `glob_conflict` +LL | glob_conflict::f(); | ^ not found in `glob_conflict` error[E0425]: cannot find function `f` in module `glob_conflict::glob` --> $DIR/glob-conflict-cross-crate.rs:7:26 | -LL | glob_conflict::glob::f(); //~ ERROR cannot find function `f` in module `glob_conflict::glob` +LL | glob_conflict::glob::f(); | ^ not found in `glob_conflict::glob` error: aborting due to 2 previous errors diff --git a/src/test/ui/imports/glob-shadowing.stderr b/src/test/ui/imports/glob-shadowing.stderr index c43ab00e718ad..7962fcb9aec1d 100644 --- a/src/test/ui/imports/glob-shadowing.stderr +++ b/src/test/ui/imports/glob-shadowing.stderr @@ -1,7 +1,7 @@ error[E0659]: `env` is ambiguous (glob import vs any other name from outer scope during import/macro resolution) --> $DIR/glob-shadowing.rs:11:17 | -LL | let x = env!("PATH"); //~ ERROR `env` is ambiguous +LL | let x = env!("PATH"); | ^^^ ambiguous name | = note: `env` could refer to a built-in macro @@ -16,7 +16,7 @@ LL | use m::*; error[E0659]: `env` is ambiguous (glob import vs any other name from outer scope during import/macro resolution) --> $DIR/glob-shadowing.rs:19:21 | -LL | let x = env!("PATH"); //~ ERROR `env` is ambiguous +LL | let x = env!("PATH"); | ^^^ ambiguous name | = note: `env` could refer to a built-in macro @@ -30,7 +30,7 @@ LL | use m::*; error[E0659]: `fenv` is ambiguous (glob import vs any other name from outer scope during import/macro resolution) --> $DIR/glob-shadowing.rs:29:21 | -LL | let x = fenv!(); //~ ERROR `fenv` is ambiguous +LL | let x = fenv!(); | ^^^^ ambiguous name | note: `fenv` could refer to the macro imported here diff --git a/src/test/ui/imports/import-crate-var.rs b/src/test/ui/imports/import-crate-var.rs index ab260500bb31f..b9d146d3735f2 100644 --- a/src/test/ui/imports/import-crate-var.rs +++ b/src/test/ui/imports/import-crate-var.rs @@ -1,10 +1,8 @@ +// check-pass // aux-build:import_crate_var.rs -// compile-pass -// skip-codegen #[macro_use] extern crate import_crate_var; - fn main() { m!(); //~^ WARN `$crate` may not be imported diff --git a/src/test/ui/imports/import-crate-var.stderr b/src/test/ui/imports/import-crate-var.stderr index 928256543bcb9..2f8c845156a82 100644 --- a/src/test/ui/imports/import-crate-var.stderr +++ b/src/test/ui/imports/import-crate-var.stderr @@ -1,9 +1,9 @@ warning: `$crate` may not be imported - --> $DIR/import-crate-var.rs:9:5 + --> $DIR/import-crate-var.rs:7:5 | LL | m!(); | ^^^^^ | = note: `use $crate;` was erroneously allowed and will become a hard error in a future release - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/imports/import-from-missing.stderr b/src/test/ui/imports/import-from-missing.stderr index 0524b1675645a..4254bfb5efb59 100644 --- a/src/test/ui/imports/import-from-missing.stderr +++ b/src/test/ui/imports/import-from-missing.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `spam::eggs` --> $DIR/import-from-missing.rs:1:17 | -LL | use spam::{ham, eggs}; //~ ERROR unresolved import `spam::eggs` [E0432] +LL | use spam::{ham, eggs}; | ^^^^ no `eggs` in `spam` error: aborting due to previous error diff --git a/src/test/ui/imports/import-glob-0.stderr b/src/test/ui/imports/import-glob-0.stderr index 4fecf80bff22b..820ff1bb536de 100644 --- a/src/test/ui/imports/import-glob-0.stderr +++ b/src/test/ui/imports/import-glob-0.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find function `f999` in this scope --> $DIR/import-glob-0.rs:14:5 | -LL | f999(); //~ ERROR cannot find function `f999` in this scope +LL | f999(); | ^^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/imports/import-glob-circular.stderr b/src/test/ui/imports/import-glob-circular.stderr index 30586132c3526..86bbea579ae23 100644 --- a/src/test/ui/imports/import-glob-circular.stderr +++ b/src/test/ui/imports/import-glob-circular.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find function `f1066` in this scope --> $DIR/import-glob-circular.rs:16:17 | -LL | fn test() { f1066(); } //~ ERROR cannot find function `f1066` in this scope +LL | fn test() { f1066(); } | ^^^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/imports/import-prefix-macro-1.stderr b/src/test/ui/imports/import-prefix-macro-1.stderr index 76e543a9f271b..577f12824716c 100644 --- a/src/test/ui/imports/import-prefix-macro-1.stderr +++ b/src/test/ui/imports/import-prefix-macro-1.stderr @@ -1,7 +1,7 @@ error: expected one of `::`, `;`, or `as`, found `{` --> $DIR/import-prefix-macro-1.rs:11:27 | -LL | ($p: path) => (use $p {S, Z}); //~ERROR expected one of `::`, `;`, or `as`, found `{` +LL | ($p: path) => (use $p {S, Z}); | ^ expected one of `::`, `;`, or `as` here ... LL | import! { a::b::c } diff --git a/src/test/ui/imports/import-prefix-macro-2.stderr b/src/test/ui/imports/import-prefix-macro-2.stderr index fa3c90d9ed29e..8428dce2728af 100644 --- a/src/test/ui/imports/import-prefix-macro-2.stderr +++ b/src/test/ui/imports/import-prefix-macro-2.stderr @@ -1,7 +1,7 @@ error: expected identifier, found `a::b::c` --> $DIR/import-prefix-macro-2.rs:11:26 | -LL | ($p: path) => (use ::$p {S, Z}); //~ERROR expected identifier, found `a::b::c` +LL | ($p: path) => (use ::$p {S, Z}); | ^^ expected identifier ... LL | import! { a::b::c } diff --git a/src/test/ui/imports/import-trait-method.stderr b/src/test/ui/imports/import-trait-method.stderr index 00cfb42ddd4fa..3c26907d3d06e 100644 --- a/src/test/ui/imports/import-trait-method.stderr +++ b/src/test/ui/imports/import-trait-method.stderr @@ -1,7 +1,7 @@ error[E0253]: `foo` is not directly importable --> $DIR/import-trait-method.rs:5:5 | -LL | use Foo::foo; //~ ERROR not directly importable +LL | use Foo::foo; | ^^^^^^^^ cannot be imported directly error: aborting due to previous error diff --git a/src/test/ui/imports/issue-53269.rs b/src/test/ui/imports/issue-53269.rs index 444a16f7e7a56..1031d507101de 100644 --- a/src/test/ui/imports/issue-53269.rs +++ b/src/test/ui/imports/issue-53269.rs @@ -1,4 +1,4 @@ -// Ambiguity between a `macro_rules` macro and a non-existent import recovered as `Def::Err` +// Ambiguity between a `macro_rules` macro and a non-existent import recovered as `Res::Err` macro_rules! mac { () => () } diff --git a/src/test/ui/imports/issue-53269.stderr b/src/test/ui/imports/issue-53269.stderr index 0163ee8bceb42..613c59867c989 100644 --- a/src/test/ui/imports/issue-53269.stderr +++ b/src/test/ui/imports/issue-53269.stderr @@ -1,13 +1,13 @@ error[E0432]: unresolved import `nonexistent_module` --> $DIR/issue-53269.rs:6:9 | -LL | use nonexistent_module::mac; //~ ERROR unresolved import `nonexistent_module` +LL | use nonexistent_module::mac; | ^^^^^^^^^^^^^^^^^^ maybe a missing `extern crate nonexistent_module;`? error[E0659]: `mac` is ambiguous (`macro_rules` vs non-`macro_rules` from other module) --> $DIR/issue-53269.rs:8:5 | -LL | mac!(); //~ ERROR `mac` is ambiguous +LL | mac!(); | ^^^ ambiguous name | note: `mac` could refer to the macro defined here @@ -18,11 +18,11 @@ LL | macro_rules! mac { () => () } note: `mac` could also refer to the unresolved item imported here --> $DIR/issue-53269.rs:6:9 | -LL | use nonexistent_module::mac; //~ ERROR unresolved import `nonexistent_module` +LL | use nonexistent_module::mac; | ^^^^^^^^^^^^^^^^^^^^^^^ = help: use `self::mac` to refer to this unresolved item unambiguously error: aborting due to 2 previous errors -Some errors occurred: E0432, E0659. +Some errors have detailed explanations: E0432, E0659. For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/imports/issue-53512.rs b/src/test/ui/imports/issue-53512.rs index 61d93531a15b3..615b36a0b21ec 100644 --- a/src/test/ui/imports/issue-53512.rs +++ b/src/test/ui/imports/issue-53512.rs @@ -1,4 +1,4 @@ -// Macro from prelude is shadowed by non-existent import recovered as `Def::Err`. +// Macro from prelude is shadowed by non-existent import recovered as `Res::Err`. use std::assert; //~ ERROR unresolved import `std::assert` diff --git a/src/test/ui/imports/issue-53512.stderr b/src/test/ui/imports/issue-53512.stderr index a733013be5f2e..f902fc488882f 100644 --- a/src/test/ui/imports/issue-53512.stderr +++ b/src/test/ui/imports/issue-53512.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `std::assert` --> $DIR/issue-53512.rs:3:5 | -LL | use std::assert; //~ ERROR unresolved import `std::assert` +LL | use std::assert; | ^^^^^^^^^^^ no `assert` in the root error: aborting due to previous error diff --git a/src/test/ui/imports/issue-55457.stderr b/src/test/ui/imports/issue-55457.stderr index 4ee0332d04bcd..86a76c1d89c70 100644 --- a/src/test/ui/imports/issue-55457.stderr +++ b/src/test/ui/imports/issue-55457.stderr @@ -1,19 +1,22 @@ error[E0432]: unresolved import `NonExistent` --> $DIR/issue-55457.rs:1:5 | -LL | use NonExistent; //~ ERROR unresolved import `NonExistent` - | ^^^^^^^^^^^ no `NonExistent` in the root. Did you mean to use `non_existent`? +LL | use NonExistent; + | ^^^^^^^^^^^ + | | + | no `NonExistent` in the root + | help: a similar name exists in the module: `non_existent` error[E0432]: unresolved import `non_existent` --> $DIR/issue-55457.rs:2:5 | -LL | use non_existent::non_existent; //~ ERROR unresolved import `non_existent` +LL | use non_existent::non_existent; | ^^^^^^^^^^^^ maybe a missing `extern crate non_existent;`? error: cannot determine resolution for the derive macro `NonExistent` --> $DIR/issue-55457.rs:5:10 | -LL | #[derive(NonExistent)] //~ ERROR cannot determine resolution for the derive macro `NonExistent` +LL | #[derive(NonExistent)] | ^^^^^^^^^^^ | = note: import resolution is stuck, try simplifying macro imports @@ -21,7 +24,7 @@ LL | #[derive(NonExistent)] //~ ERROR cannot determine resolution for the derive error: cannot determine resolution for the attribute macro `non_existent` --> $DIR/issue-55457.rs:4:3 | -LL | #[non_existent] //~ ERROR cannot determine resolution for the attribute macro `non_existent` +LL | #[non_existent] | ^^^^^^^^^^^^ | = note: import resolution is stuck, try simplifying macro imports diff --git a/src/test/ui/imports/issue-55884-1.stderr b/src/test/ui/imports/issue-55884-1.stderr index 477e859d0815e..a7a7cc8879e65 100644 --- a/src/test/ui/imports/issue-55884-1.stderr +++ b/src/test/ui/imports/issue-55884-1.stderr @@ -1,7 +1,7 @@ error[E0659]: `S` is ambiguous (glob import vs glob import in the same module) --> $DIR/issue-55884-1.rs:19:12 | -LL | use m::S; //~ ERROR `S` is ambiguous +LL | use m::S; | ^ ambiguous name | note: `S` could refer to the struct imported here diff --git a/src/test/ui/imports/issue-55884-2.stderr b/src/test/ui/imports/issue-55884-2.stderr index f8a6cb4a58090..d3b43783ee9c8 100644 --- a/src/test/ui/imports/issue-55884-2.stderr +++ b/src/test/ui/imports/issue-55884-2.stderr @@ -1,7 +1,7 @@ error[E0603]: struct `ParseOptions` is private --> $DIR/issue-55884-2.rs:12:17 | -LL | pub use parser::ParseOptions; //~ ERROR struct `ParseOptions` is private +LL | pub use parser::ParseOptions; | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/imports/issue-56125.stderr b/src/test/ui/imports/issue-56125.stderr index 844962b910a69..0ecedd50e03ec 100644 --- a/src/test/ui/imports/issue-56125.stderr +++ b/src/test/ui/imports/issue-56125.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `empty::issue_56125` --> $DIR/issue-56125.rs:17:9 | -LL | use empty::issue_56125; //~ ERROR unresolved import `empty::issue_56125` +LL | use empty::issue_56125; | ^^^^^^^^^^^^^^^^^^ no `issue_56125` in `m3::empty` error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution) @@ -37,7 +37,7 @@ LL | use issue_56125::non_last_segment::non_last_segment::*; error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution) --> $DIR/issue-56125.rs:18:9 | -LL | use issue_56125::*; //~ ERROR `issue_56125` is ambiguous +LL | use issue_56125::*; | ^^^^^^^^^^^ ambiguous name | = note: `issue_56125` could refer to an extern crate passed with `--extern` @@ -45,11 +45,11 @@ LL | use issue_56125::*; //~ ERROR `issue_56125` is ambiguous note: `issue_56125` could also refer to the module imported here --> $DIR/issue-56125.rs:18:9 | -LL | use issue_56125::*; //~ ERROR `issue_56125` is ambiguous +LL | use issue_56125::*; | ^^^^^^^^^^^^^^ = help: use `self::issue_56125` to refer to this module unambiguously error: aborting due to 4 previous errors -Some errors occurred: E0432, E0659. +Some errors have detailed explanations: E0432, E0659. For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/imports/issue-57015.stderr b/src/test/ui/imports/issue-57015.stderr index b0fcf5bec6a77..d200d23ab28ef 100644 --- a/src/test/ui/imports/issue-57015.stderr +++ b/src/test/ui/imports/issue-57015.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `single_err::something` --> $DIR/issue-57015.rs:10:5 | -LL | use single_err::something; //~ ERROR unresolved import `single_err::something` +LL | use single_err::something; | ^^^^^^^^^^^^^^^^^^^^^ no `something` in `single_err` error: aborting due to previous error diff --git a/src/test/ui/imports/issue-57539.stderr b/src/test/ui/imports/issue-57539.stderr index 3f745fd8204bf..ebf27ca54bc41 100644 --- a/src/test/ui/imports/issue-57539.stderr +++ b/src/test/ui/imports/issue-57539.stderr @@ -1,7 +1,7 @@ error[E0659]: `core` is ambiguous (name vs any other name during import resolution) --> $DIR/issue-57539.rs:4:9 | -LL | use core; //~ ERROR `core` is ambiguous +LL | use core; | ^^^^ ambiguous name | = note: `core` could refer to a built-in extern crate diff --git a/src/test/ui/imports/local-modularized-tricky-fail-1.rs b/src/test/ui/imports/local-modularized-tricky-fail-1.rs index d1cb6b07d750c..29e9b8ec841f5 100644 --- a/src/test/ui/imports/local-modularized-tricky-fail-1.rs +++ b/src/test/ui/imports/local-modularized-tricky-fail-1.rs @@ -33,7 +33,6 @@ mod inner2 { fn main() { panic!(); //~ ERROR `panic` is ambiguous - //~| ERROR `panic` is ambiguous } mod inner3 { diff --git a/src/test/ui/imports/local-modularized-tricky-fail-1.stderr b/src/test/ui/imports/local-modularized-tricky-fail-1.stderr index 21f75afb3f746..13d3227d8b38f 100644 --- a/src/test/ui/imports/local-modularized-tricky-fail-1.stderr +++ b/src/test/ui/imports/local-modularized-tricky-fail-1.stderr @@ -1,7 +1,7 @@ error[E0659]: `exported` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution) --> $DIR/local-modularized-tricky-fail-1.rs:28:1 | -LL | exported!(); //~ ERROR `exported` is ambiguous +LL | exported!(); | ^^^^^^^^ ambiguous name | note: `exported` could refer to the macro defined here @@ -22,9 +22,9 @@ LL | use inner1::*; = help: consider adding an explicit import of `exported` to disambiguate error[E0659]: `include` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) - --> $DIR/local-modularized-tricky-fail-1.rs:47:1 + --> $DIR/local-modularized-tricky-fail-1.rs:46:1 | -LL | include!(); //~ ERROR `include` is ambiguous +LL | include!(); | ^^^^^^^ ambiguous name | = note: `include` could refer to a built-in macro @@ -43,7 +43,7 @@ LL | define_include!(); error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/local-modularized-tricky-fail-1.rs:35:5 | -LL | panic!(); //~ ERROR `panic` is ambiguous +LL | panic!(); | ^^^^^ ambiguous name | = note: `panic` could refer to a macro from prelude @@ -59,26 +59,6 @@ LL | define_panic!(); | ---------------- in this macro invocation = help: use `crate::panic` to refer to this macro unambiguously -error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) - --> $DIR/local-modularized-tricky-fail-1.rs:35:5 - | -LL | panic!(); //~ ERROR `panic` is ambiguous - | ^^^^^^^^^ ambiguous name - | - = note: `panic` could refer to a macro from prelude -note: `panic` could also refer to the macro defined here - --> $DIR/local-modularized-tricky-fail-1.rs:11:5 - | -LL | / macro_rules! panic { -LL | | () => () -LL | | } - | |_____^ -... -LL | define_panic!(); - | ---------------- in this macro invocation - = help: use `crate::panic` to refer to this macro unambiguously - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0659`. diff --git a/src/test/ui/imports/local-modularized-tricky-fail-2.stderr b/src/test/ui/imports/local-modularized-tricky-fail-2.stderr index 40cb10ced16f5..70d197994f311 100644 --- a/src/test/ui/imports/local-modularized-tricky-fail-2.stderr +++ b/src/test/ui/imports/local-modularized-tricky-fail-2.stderr @@ -1,34 +1,37 @@ -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/local-modularized-tricky-fail-2.rs:20:32 | LL | exported!(); | ------------ in this macro invocation ... -LL | () => ( struct Б; ) //~ ERROR non-ascii idents are not fully supported +LL | () => ( struct Б; ) | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/local-modularized-tricky-fail-2.rs:36:24 | LL | panic!(); | --------- in this macro invocation ... -LL | () => ( struct Г; ) //~ ERROR non-ascii idents are not fully supported +LL | () => ( struct Г; ) | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/local-modularized-tricky-fail-2.rs:46:24 | LL | include!(); | ----------- in this macro invocation ... -LL | () => ( struct Д; ) //~ ERROR non-ascii idents are not fully supported +LL | () => ( struct Д; ) | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/imports/macro-paths.stderr b/src/test/ui/imports/macro-paths.stderr index 36290b2d93e64..a5b90008272cf 100644 --- a/src/test/ui/imports/macro-paths.stderr +++ b/src/test/ui/imports/macro-paths.stderr @@ -1,7 +1,7 @@ error[E0659]: `bar` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution) --> $DIR/macro-paths.rs:13:5 | -LL | bar::m! { //~ ERROR ambiguous +LL | bar::m! { | ^^^ ambiguous name | note: `bar` could refer to the module defined here @@ -19,7 +19,7 @@ LL | use foo::*; error[E0659]: `baz` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/macro-paths.rs:23:5 | -LL | baz::m! { //~ ERROR ambiguous +LL | baz::m! { | ^^^ ambiguous name | note: `baz` could refer to the module defined here diff --git a/src/test/ui/imports/macros.stderr b/src/test/ui/imports/macros.stderr index 5a15bf0ae71c6..3b9e6feebd7e3 100644 --- a/src/test/ui/imports/macros.stderr +++ b/src/test/ui/imports/macros.stderr @@ -1,7 +1,7 @@ error[E0659]: `m` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution) --> $DIR/macros.rs:16:5 | -LL | m! { //~ ERROR ambiguous +LL | m! { | ^ ambiguous name | note: `m` could refer to the macro imported here @@ -19,7 +19,7 @@ LL | use two_macros::*; error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/macros.rs:29:9 | -LL | m! { //~ ERROR ambiguous +LL | m! { | ^ ambiguous name | note: `m` could refer to the macro imported here diff --git a/src/test/ui/imports/reexports.stderr b/src/test/ui/imports/reexports.stderr index 964e847392afd..af2c97e77b9d7 100644 --- a/src/test/ui/imports/reexports.stderr +++ b/src/test/ui/imports/reexports.stderr @@ -1,34 +1,34 @@ error[E0364]: `foo` is private, and cannot be re-exported --> $DIR/reexports.rs:6:17 | -LL | pub use super::foo; //~ ERROR cannot be re-exported +LL | pub use super::foo; | ^^^^^^^^^^ | note: consider marking `foo` as `pub` in the imported module --> $DIR/reexports.rs:6:17 | -LL | pub use super::foo; //~ ERROR cannot be re-exported +LL | pub use super::foo; | ^^^^^^^^^^ error: A non-empty glob must import something with the glob's visibility --> $DIR/reexports.rs:7:17 | -LL | pub use super::*; //~ ERROR must import something with the glob's visibility +LL | pub use super::*; | ^^^^^^^^ error[E0603]: module `foo` is private --> $DIR/reexports.rs:28:15 | -LL | use b::a::foo::S; //~ ERROR `foo` +LL | use b::a::foo::S; | ^^^ error[E0603]: module `foo` is private --> $DIR/reexports.rs:29:15 | -LL | use b::b::foo::S as T; //~ ERROR `foo` +LL | use b::b::foo::S as T; | ^^^ error: aborting due to 4 previous errors -Some errors occurred: E0364, E0603. +Some errors have detailed explanations: E0364, E0603. For more information about an error, try `rustc --explain E0364`. diff --git a/src/test/ui/imports/rfc-1560-warning-cycle.stderr b/src/test/ui/imports/rfc-1560-warning-cycle.stderr index 16caf68e14fda..d79c719d82647 100644 --- a/src/test/ui/imports/rfc-1560-warning-cycle.stderr +++ b/src/test/ui/imports/rfc-1560-warning-cycle.stderr @@ -1,7 +1,7 @@ error[E0659]: `Foo` is ambiguous (glob import vs glob import in the same module) --> $DIR/rfc-1560-warning-cycle.rs:9:17 | -LL | fn f(_: Foo) {} //~ ERROR `Foo` is ambiguous +LL | fn f(_: Foo) {} | ^^^ ambiguous name | note: `Foo` could refer to the struct imported here diff --git a/src/test/ui/imports/shadow_builtin_macros.stderr b/src/test/ui/imports/shadow_builtin_macros.stderr index db4ee1128f421..c84226ef313c2 100644 --- a/src/test/ui/imports/shadow_builtin_macros.stderr +++ b/src/test/ui/imports/shadow_builtin_macros.stderr @@ -1,7 +1,7 @@ error[E0659]: `panic` is ambiguous (glob import vs any other name from outer scope during import/macro resolution) --> $DIR/shadow_builtin_macros.rs:15:14 | -LL | fn f() { panic!(); } //~ ERROR ambiguous +LL | fn f() { panic!(); } | ^^^^^ ambiguous name | = note: `panic` could refer to a macro from prelude @@ -16,7 +16,7 @@ LL | use foo::*; error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/shadow_builtin_macros.rs:20:14 | -LL | fn f() { panic!(); } //~ ERROR ambiguous +LL | fn f() { panic!(); } | ^^^^^ ambiguous name | = note: `panic` could refer to a macro from prelude @@ -30,7 +30,7 @@ LL | ::two_macros::m!(use foo::panic;); error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/shadow_builtin_macros.rs:33:5 | -LL | panic!(); //~ ERROR `panic` is ambiguous +LL | panic!(); | ^^^^^ ambiguous name | = note: `panic` could refer to a macro from prelude @@ -46,7 +46,7 @@ LL | m!(); error[E0659]: `n` is ambiguous (glob import vs any other name from outer scope during import/macro resolution) --> $DIR/shadow_builtin_macros.rs:49:5 | -LL | n!(); //~ ERROR ambiguous +LL | n!(); | ^ ambiguous name | note: `n` could refer to the macro imported here diff --git a/src/test/ui/imports/unresolved-imports-used.rs b/src/test/ui/imports/unresolved-imports-used.rs new file mode 100644 index 0000000000000..d1461e7b041c5 --- /dev/null +++ b/src/test/ui/imports/unresolved-imports-used.rs @@ -0,0 +1,12 @@ +// There should be *no* unused import errors. +#![deny(unused_imports)] + +mod qux { + fn quz() {} +} + +use qux::quz; //~ ERROR function `quz` is private +use qux::bar; //~ ERROR unresolved import `qux::bar` +use foo::bar; //~ ERROR unresolved import `foo` + +fn main() {} diff --git a/src/test/ui/imports/unresolved-imports-used.stderr b/src/test/ui/imports/unresolved-imports-used.stderr new file mode 100644 index 0000000000000..f20db881c8628 --- /dev/null +++ b/src/test/ui/imports/unresolved-imports-used.stderr @@ -0,0 +1,22 @@ +error[E0432]: unresolved import `qux::bar` + --> $DIR/unresolved-imports-used.rs:9:5 + | +LL | use qux::bar; + | ^^^^^^^^ no `bar` in `qux` + +error[E0432]: unresolved import `foo` + --> $DIR/unresolved-imports-used.rs:10:5 + | +LL | use foo::bar; + | ^^^ maybe a missing `extern crate foo;`? + +error[E0603]: function `quz` is private + --> $DIR/unresolved-imports-used.rs:8:10 + | +LL | use qux::quz; + | ^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0432, E0603. +For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/imports/unused-macro-use.stderr b/src/test/ui/imports/unused-macro-use.stderr index 2d20b3114426c..78683147f7ba6 100644 --- a/src/test/ui/imports/unused-macro-use.stderr +++ b/src/test/ui/imports/unused-macro-use.stderr @@ -1,7 +1,7 @@ error: unused `#[macro_use]` import --> $DIR/unused-macro-use.rs:3:1 | -LL | #[macro_use] //~ ERROR unused `#[macro_use]` import +LL | #[macro_use] | ^^^^^^^^^^^^ | note: lint level defined here @@ -14,7 +14,7 @@ LL | #![deny(unused)] error: unused `#[macro_use]` import --> $DIR/unused-macro-use.rs:7:5 | -LL | panic //~ ERROR unused `#[macro_use]` import +LL | panic | ^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/imports/unused.stderr b/src/test/ui/imports/unused.stderr index b56e930158cc1..259ed9586962c 100644 --- a/src/test/ui/imports/unused.stderr +++ b/src/test/ui/imports/unused.stderr @@ -1,7 +1,7 @@ error: unused import: `super::f` --> $DIR/unused.rs:7:24 | -LL | pub(super) use super::f; //~ ERROR unused +LL | pub(super) use super::f; | ^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/impossible_range.stderr b/src/test/ui/impossible_range.stderr index 1d26030625fc9..091fe37c7a1f7 100644 --- a/src/test/ui/impossible_range.stderr +++ b/src/test/ui/impossible_range.stderr @@ -1,7 +1,7 @@ error[E0586]: inclusive range with no end --> $DIR/impossible_range.rs:8:8 | -LL | ..=; //~ERROR inclusive range with no end +LL | ..=; | ^ | = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) @@ -9,7 +9,7 @@ LL | ..=; //~ERROR inclusive range with no end error[E0586]: inclusive range with no end --> $DIR/impossible_range.rs:15:9 | -LL | 0..=; //~ERROR inclusive range with no end +LL | 0..=; | ^ | = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) diff --git a/src/test/ui/in-band-lifetimes/E0687.stderr b/src/test/ui/in-band-lifetimes/E0687.stderr index 74245e16e7f2b..e8e5100e00e07 100644 --- a/src/test/ui/in-band-lifetimes/E0687.stderr +++ b/src/test/ui/in-band-lifetimes/E0687.stderr @@ -1,27 +1,26 @@ error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders --> $DIR/E0687.rs:4:15 | -LL | fn foo(x: fn(&'a u32)) {} //~ ERROR must be explicitly +LL | fn foo(x: fn(&'a u32)) {} | ^^ in-band lifetime definition error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders --> $DIR/E0687.rs:6:16 | -LL | fn bar(x: &Fn(&'a u32)) {} //~ ERROR must be explicitly +LL | fn bar(x: &Fn(&'a u32)) {} | ^^ in-band lifetime definition error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders --> $DIR/E0687.rs:8:15 | -LL | fn baz(x: fn(&'a u32), y: &'a u32) {} //~ ERROR must be explicitly +LL | fn baz(x: fn(&'a u32), y: &'a u32) {} | ^^ in-band lifetime definition error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders --> $DIR/E0687.rs:13:26 | -LL | fn bar(&self, x: fn(&'a u32)) {} //~ ERROR must be explicitly +LL | fn bar(&self, x: fn(&'a u32)) {} | ^^ in-band lifetime definition error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0687`. diff --git a/src/test/ui/in-band-lifetimes/E0687_where.stderr b/src/test/ui/in-band-lifetimes/E0687_where.stderr index 4533c3b10f797..b422869c4db89 100644 --- a/src/test/ui/in-band-lifetimes/E0687_where.stderr +++ b/src/test/ui/in-band-lifetimes/E0687_where.stderr @@ -1,15 +1,14 @@ error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders --> $DIR/E0687_where.rs:4:31 | -LL | fn bar(x: &F) where F: Fn(&'a u32) {} //~ ERROR must be explicitly +LL | fn bar(x: &F) where F: Fn(&'a u32) {} | ^^ in-band lifetime definition error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders --> $DIR/E0687_where.rs:6:21 | -LL | fn baz(x: &impl Fn(&'a u32)) {} //~ ERROR must be explicitly +LL | fn baz(x: &impl Fn(&'a u32)) {} | ^^ in-band lifetime definition error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0687`. diff --git a/src/test/ui/in-band-lifetimes/E0688.stderr b/src/test/ui/in-band-lifetimes/E0688.stderr index f02b8db4669e0..0078cd58001e3 100644 --- a/src/test/ui/in-band-lifetimes/E0688.stderr +++ b/src/test/ui/in-band-lifetimes/E0688.stderr @@ -1,7 +1,7 @@ error[E0688]: cannot mix in-band and explicit lifetime definitions --> $DIR/E0688.rs:4:28 | -LL | fn foo<'a>(x: &'a u32, y: &'b u32) {} //~ ERROR cannot mix +LL | fn foo<'a>(x: &'a u32, y: &'b u32) {} | -- ^^ in-band lifetime definition here | | | explicit lifetime definition here @@ -9,7 +9,7 @@ LL | fn foo<'a>(x: &'a u32, y: &'b u32) {} //~ ERROR cannot mix error[E0688]: cannot mix in-band and explicit lifetime definitions --> $DIR/E0688.rs:9:44 | -LL | fn bar<'b>(x: &'a u32, y: &'b u32, z: &'c u32) {} //~ ERROR cannot mix +LL | fn bar<'b>(x: &'a u32, y: &'b u32, z: &'c u32) {} | -- ^^ in-band lifetime definition here | | | explicit lifetime definition here @@ -17,11 +17,10 @@ LL | fn bar<'b>(x: &'a u32, y: &'b u32, z: &'c u32) {} //~ ERROR cannot mix error[E0688]: cannot mix in-band and explicit lifetime definitions --> $DIR/E0688.rs:12:14 | -LL | impl<'b> Foo<'a> { //~ ERROR cannot mix +LL | impl<'b> Foo<'a> { | -- ^^ in-band lifetime definition here | | | explicit lifetime definition here error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0688`. diff --git a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.rs b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.rs new file mode 100644 index 0000000000000..cf08cb7eeacd8 --- /dev/null +++ b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.rs @@ -0,0 +1,10 @@ +#![deny(elided_lifetimes_in_paths)] + +// Previously, the elided-lifetimes-in-path lint would fire, but we don't want +// that, because `'_` isn't legal in struct declarations. + +struct Betrayal<'a> { x: &'a u8 } + +struct Heartbreak(Betrayal); //~ ERROR missing lifetime specifier + +fn main() {} diff --git a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr new file mode 100644 index 0000000000000..9579abb76b32f --- /dev/null +++ b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr @@ -0,0 +1,9 @@ +error[E0106]: missing lifetime specifier + --> $DIR/issue-61124-anon-lifetime-in-struct-declaration.rs:8:19 + | +LL | struct Heartbreak(Betrayal); + | ^^^^^^^^ expected lifetime parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/in-band-lifetimes/mismatched.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched.nll.stderr new file mode 100644 index 0000000000000..f5aee2d2d7e5c --- /dev/null +++ b/src/test/ui/in-band-lifetimes/mismatched.nll.stderr @@ -0,0 +1,20 @@ +error[E0621]: explicit lifetime required in the type of `y` + --> $DIR/mismatched.rs:4:42 + | +LL | fn foo(x: &'a u32, y: &u32) -> &'a u32 { y } + | ---- ^ lifetime `'a` required + | | + | help: add explicit lifetime `'a` to the type of `y`: `&'a u32` + +error: lifetime may not live long enough + --> $DIR/mismatched.rs:6:46 + | +LL | fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y } + | -- -- ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | | | + | | lifetime `'b` defined here + | lifetime `'a` defined here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/in-band-lifetimes/mismatched.stderr b/src/test/ui/in-band-lifetimes/mismatched.stderr index abc6d42910fb3..ec1045d5fae37 100644 --- a/src/test/ui/in-band-lifetimes/mismatched.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched.stderr @@ -1,7 +1,7 @@ error[E0621]: explicit lifetime required in the type of `y` --> $DIR/mismatched.rs:4:42 | -LL | fn foo(x: &'a u32, y: &u32) -> &'a u32 { y } //~ ERROR explicit lifetime required +LL | fn foo(x: &'a u32, y: &u32) -> &'a u32 { y } | ---- ^ lifetime `'a` required | | | help: add explicit lifetime `'a` to the type of `y`: `&'a u32` @@ -9,12 +9,11 @@ LL | fn foo(x: &'a u32, y: &u32) -> &'a u32 { y } //~ ERROR explicit lifetime re error[E0623]: lifetime mismatch --> $DIR/mismatched.rs:6:46 | -LL | fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y } //~ ERROR lifetime mismatch +LL | fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y } | ------- ------- ^ ...but data from `y` is returned here | | | this parameter and the return type are declared with different lifetimes... error: aborting due to 2 previous errors -Some errors occurred: E0621, E0623. -For more information about an error, try `rustc --explain E0621`. +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait.stderr index dd28aa226b7fc..ac66daa21c7a9 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait.stderr @@ -3,7 +3,7 @@ error[E0621]: explicit lifetime required in the type of `y` | LL | fn baz(&self, x: &'a u32, y: &u32) -> &'a u32 { | ---- help: add explicit lifetime `'a` to the type of `y`: `&'a u32` -LL | y //~ ERROR explicit lifetime required +LL | y | ^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs index d4535ac442538..d131a944721d0 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs @@ -4,8 +4,8 @@ trait Trait {} struct Struct; impl Deref for Struct { - type Target = Trait; - fn deref(&self) -> &Trait { + type Target = dyn Trait; + fn deref(&self) -> &dyn Trait { unimplemented!(); } } diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index fbd312a632f07..b50a926c63795 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -1,13 +1,13 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements --> $DIR/mismatched_trait_impl-2.rs:8:5 | -LL | fn deref(&self) -> &Trait { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn deref(&self) -> &dyn Trait { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 8:5... --> $DIR/mismatched_trait_impl-2.rs:8:5 | -LL | / fn deref(&self) -> &Trait { +LL | / fn deref(&self) -> &dyn Trait { LL | | unimplemented!(); LL | | } | |_____^ @@ -18,4 +18,3 @@ LL | | } error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr new file mode 100644 index 0000000000000..cd65bab2d4668 --- /dev/null +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr @@ -0,0 +1,24 @@ +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements + --> $DIR/mismatched_trait_impl.rs:9:5 + | +LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 9:5... + --> $DIR/mismatched_trait_impl.rs:9:5 + | +LL | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { +LL | | x +LL | | } + | |_____^ +note: ...but the lifetime must also be valid for the lifetime 'a as defined on the method body at 9:32... + --> $DIR/mismatched_trait_impl.rs:9:32 + | +LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { + | ^^ + = note: ...so that the method type is compatible with trait: + expected fn(&i32, &'a u32, &u32) -> &'a u32 + found fn(&i32, &u32, &u32) -> &u32 + +error: aborting due to previous error + diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs index 654d2bddfd041..f2ba81af9b638 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs @@ -7,7 +7,7 @@ trait Get { impl Get for i32 { fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer - x + x //~ ERROR lifetime mismatch } } diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index 4af991cede436..80f15b7c5847f 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -1,25 +1,34 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements --> $DIR/mismatched_trait_impl.rs:9:5 | -LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer +LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 9:5... --> $DIR/mismatched_trait_impl.rs:9:5 | -LL | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer +LL | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { LL | | x LL | | } | |_____^ note: ...but the lifetime must also be valid for the lifetime 'a as defined on the method body at 9:32... --> $DIR/mismatched_trait_impl.rs:9:32 | -LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer +LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | ^^ = note: ...so that the method type is compatible with trait: expected fn(&i32, &'a u32, &u32) -> &'a u32 found fn(&i32, &u32, &u32) -> &u32 -error: aborting due to previous error +error[E0623]: lifetime mismatch + --> $DIR/mismatched_trait_impl.rs:10:9 + | +LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { + | ---- ------- + | | + | this parameter and the return type are declared with different lifetimes... +LL | x + | ^ ...but data from `x` is returned here + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/in-band-lifetimes/mut_while_borrow.nll.stderr b/src/test/ui/in-band-lifetimes/mut_while_borrow.nll.stderr deleted file mode 100644 index 3f5dbb850cc71..0000000000000 --- a/src/test/ui/in-band-lifetimes/mut_while_borrow.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0506]: cannot assign to `p` because it is borrowed - --> $DIR/mut_while_borrow.rs:9:5 - | -LL | let r = foo(&p); - | -- borrow of `p` occurs here -LL | p += 1; //~ ERROR cannot assign to `p` because it is borrowed - | ^^^^^^ assignment to borrowed `p` occurs here -LL | println!("{}", r); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/in-band-lifetimes/mut_while_borrow.stderr b/src/test/ui/in-band-lifetimes/mut_while_borrow.stderr index e710986c7217b..f96ff9dd4e674 100644 --- a/src/test/ui/in-band-lifetimes/mut_while_borrow.stderr +++ b/src/test/ui/in-band-lifetimes/mut_while_borrow.stderr @@ -2,9 +2,11 @@ error[E0506]: cannot assign to `p` because it is borrowed --> $DIR/mut_while_borrow.rs:9:5 | LL | let r = foo(&p); - | - borrow of `p` occurs here -LL | p += 1; //~ ERROR cannot assign to `p` because it is borrowed + | -- borrow of `p` occurs here +LL | p += 1; | ^^^^^^ assignment to borrowed `p` occurs here +LL | println!("{}", r); + | - borrow later used here error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr b/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr index 9076bdc946a39..a270dd03926dc 100644 --- a/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr +++ b/src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr @@ -1,13 +1,13 @@ error[E0261]: use of undeclared lifetime name `'test` --> $DIR/no_in_band_in_struct.rs:5:9 | -LL | x: &'test u32, //~ ERROR undeclared lifetime +LL | x: &'test u32, | ^^^^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'test` --> $DIR/no_in_band_in_struct.rs:9:10 | -LL | Baz(&'test u32), //~ ERROR undeclared lifetime +LL | Baz(&'test u32), | ^^^^^ undeclared lifetime error: aborting due to 2 previous errors diff --git a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr index 932dea5b2a953..c307066be6b46 100644 --- a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr +++ b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr @@ -1,13 +1,13 @@ error[E0261]: use of undeclared lifetime name `'test` --> $DIR/no_introducing_in_band_in_locals.rs:5:13 | -LL | let y: &'test u32 = x; //~ ERROR use of undeclared lifetime +LL | let y: &'test u32 = x; | ^^^^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'test` --> $DIR/no_introducing_in_band_in_locals.rs:10:16 | -LL | let y: fn(&'test u32) = foo2; //~ ERROR use of undeclared lifetime +LL | let y: fn(&'test u32) = foo2; | ^^^^^ undeclared lifetime error: aborting due to 2 previous errors diff --git a/src/test/ui/in-band-lifetimes/shadow.stderr b/src/test/ui/in-band-lifetimes/shadow.stderr index ac5bd5b5a3321..a0a15d3aa8886 100644 --- a/src/test/ui/in-band-lifetimes/shadow.stderr +++ b/src/test/ui/in-band-lifetimes/shadow.stderr @@ -3,7 +3,7 @@ error[E0496]: lifetime name `'s` shadows a lifetime name that is already in scop | LL | impl Foo<&'s u8> { | -- first declared here -LL | fn bar<'s>(&self, x: &'s u8) {} //~ ERROR shadows a lifetime name +LL | fn bar<'s>(&self, x: &'s u8) {} | ^^ lifetime 's already in scope error[E0496]: lifetime name `'s` shadows a lifetime name that is already in scope @@ -11,8 +11,8 @@ error[E0496]: lifetime name `'s` shadows a lifetime name that is already in scop | LL | impl Foo<&'s u8> { | -- first declared here -LL | fn bar<'s>(&self, x: &'s u8) {} //~ ERROR shadows a lifetime name -LL | fn baz(x: for<'s> fn(&'s u32)) {} //~ ERROR shadows a lifetime name +LL | fn bar<'s>(&self, x: &'s u8) {} +LL | fn baz(x: for<'s> fn(&'s u32)) {} | ^^ lifetime 's already in scope error: aborting due to 2 previous errors diff --git a/src/test/ui/inaccessible-test-modules.stderr b/src/test/ui/inaccessible-test-modules.stderr index 636ef8187059b..b6a817e6b1d30 100644 --- a/src/test/ui/inaccessible-test-modules.stderr +++ b/src/test/ui/inaccessible-test-modules.stderr @@ -1,14 +1,20 @@ error[E0432]: unresolved import `__test` --> $DIR/inaccessible-test-modules.rs:5:5 | -LL | use __test as x; //~ ERROR unresolved import `__test` - | ^^^^^^^^^^^ no `__test` in the root. Did you mean to use `test`? +LL | use __test as x; + | ------^^^^^ + | | + | no `__test` in the root + | help: a similar name exists in the module: `test` error[E0432]: unresolved import `__test_reexports` --> $DIR/inaccessible-test-modules.rs:6:5 | -LL | use __test_reexports as y; //~ ERROR unresolved import `__test_reexports` - | ^^^^^^^^^^^^^^^^^^^^^ no `__test_reexports` in the root. Did you mean to use `__test_reexports`? +LL | use __test_reexports as y; + | ----------------^^^^^ + | | + | no `__test_reexports` in the root + | help: a similar name exists in the module: `__test_reexports` error: aborting due to 2 previous errors diff --git a/src/test/ui/include-macros/mismatched-types.stderr b/src/test/ui/include-macros/mismatched-types.stderr index 1ee223b23f055..33204f1cfce9b 100644 --- a/src/test/ui/include-macros/mismatched-types.stderr +++ b/src/test/ui/include-macros/mismatched-types.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/mismatched-types.rs:2:20 | -LL | let b: &[u8] = include_str!("file.txt"); //~ ERROR mismatched types +LL | let b: &[u8] = include_str!("file.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^ expected slice, found str | = note: expected type `&[u8]` @@ -10,7 +10,7 @@ LL | let b: &[u8] = include_str!("file.txt"); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/mismatched-types.rs:3:19 | -LL | let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types +LL | let s: &str = include_bytes!("file.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected str, found array of 0 elements | = note: expected type `&str` diff --git a/src/test/ui/index-bot.stderr b/src/test/ui/index-bot.stderr index 2e2a98d1d80a7..b5d78297505d3 100644 --- a/src/test/ui/index-bot.stderr +++ b/src/test/ui/index-bot.stderr @@ -1,7 +1,7 @@ error[E0608]: cannot index into a value of type `!` --> $DIR/index-bot.rs:2:5 | -LL | (return)[0]; //~ ERROR cannot index into a value of type `!` +LL | (return)[0]; | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/index-help.stderr b/src/test/ui/index-help.stderr index 4c585a958c14b..cd4d8356749a5 100644 --- a/src/test/ui/index-help.stderr +++ b/src/test/ui/index-help.stderr @@ -1,7 +1,7 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `i32` --> $DIR/index-help.rs:3:5 | -LL | x[0i32]; //~ ERROR E0277 +LL | x[0i32]; | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `std::slice::SliceIndex<[{integer}]>` is not implemented for `i32` diff --git a/src/test/ui/index_message.stderr b/src/test/ui/index_message.stderr index 62a14523fe9ad..6c2b126734b05 100644 --- a/src/test/ui/index_message.stderr +++ b/src/test/ui/index_message.stderr @@ -1,7 +1,7 @@ error[E0608]: cannot index into a value of type `()` --> $DIR/index_message.rs:3:13 | -LL | let _ = z[0]; //~ ERROR cannot index into a value of type `()` +LL | let _ = z[0]; | ^^^^ help: to access tuple elements, use: `z.0` error: aborting due to previous error diff --git a/src/test/ui/indexing-requires-a-uint.stderr b/src/test/ui/indexing-requires-a-uint.stderr index 363c3d0d45853..3300db58d44c3 100644 --- a/src/test/ui/indexing-requires-a-uint.stderr +++ b/src/test/ui/indexing-requires-a-uint.stderr @@ -1,7 +1,7 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `u8` --> $DIR/indexing-requires-a-uint.rs:6:5 | -LL | [0][0u8]; //~ ERROR: the type `[{integer}]` cannot be indexed by `u8` +LL | [0][0u8]; | ^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `std::slice::SliceIndex<[{integer}]>` is not implemented for `u8` @@ -12,8 +12,12 @@ error[E0308]: mismatched types | LL | bar::(i); // i should not be re-coerced back to an isize | ^ expected isize, found usize +help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit + | +LL | bar::(i.try_into().unwrap()); // i should not be re-coerced back to an isize + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/inference/inference_unstable_featured.stderr b/src/test/ui/inference/inference_unstable_featured.stderr index 5f02578512712..08cdb8cc6883f 100644 --- a/src/test/ui/inference/inference_unstable_featured.stderr +++ b/src/test/ui/inference/inference_unstable_featured.stderr @@ -1,7 +1,7 @@ error[E0034]: multiple applicable items in scope --> $DIR/inference_unstable_featured.rs:16:20 | -LL | assert_eq!('x'.ipu_flatten(), 0); //~ ERROR E0034 +LL | assert_eq!('x'.ipu_flatten(), 0); | ^^^^^^^^^^^ multiple `ipu_flatten` found | = note: candidate #1 is defined in an impl of the trait `inference_unstable_iterator::IpuIterator` for the type `char` diff --git a/src/test/ui/inference/inference_unstable_forced.stderr b/src/test/ui/inference/inference_unstable_forced.stderr index 3c07085a648f6..83e27aaf2f855 100644 --- a/src/test/ui/inference/inference_unstable_forced.stderr +++ b/src/test/ui/inference/inference_unstable_forced.stderr @@ -1,9 +1,10 @@ -error[E0658]: use of unstable library feature 'ipu_flatten' (see issue #99999) +error[E0658]: use of unstable library feature 'ipu_flatten' --> $DIR/inference_unstable_forced.rs:11:20 | -LL | assert_eq!('x'.ipu_flatten(), 0); //~ ERROR E0658 +LL | assert_eq!('x'.ipu_flatten(), 0); | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/99999 = help: add #![feature(ipu_flatten)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/infinite/infinite-autoderef.stderr b/src/test/ui/infinite/infinite-autoderef.stderr index 9e4b0a029ab7c..3159a4b67dae5 100644 --- a/src/test/ui/infinite/infinite-autoderef.stderr +++ b/src/test/ui/infinite/infinite-autoderef.stderr @@ -13,7 +13,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | Foo.foo; | ^^^^^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="128"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate error[E0055]: reached the recursion limit while auto-dereferencing `Foo` --> $DIR/infinite-autoderef.rs:25:9 @@ -21,7 +21,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | Foo.foo; | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="128"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate error[E0609]: no field `foo` on type `Foo` --> $DIR/infinite-autoderef.rs:25:9 @@ -35,7 +35,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | Foo.bar(); | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="128"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate error[E0599]: no method named `bar` found for type `Foo` in the current scope --> $DIR/infinite-autoderef.rs:26:9 @@ -48,5 +48,5 @@ LL | Foo.bar(); error: aborting due to 6 previous errors -Some errors occurred: E0055, E0308, E0599, E0609. +Some errors have detailed explanations: E0055, E0308, E0599, E0609. For more information about an error, try `rustc --explain E0055`. diff --git a/src/test/ui/infinite/infinite-instantiation.stderr b/src/test/ui/infinite/infinite-instantiation.stderr index 42be1411b686a..d75dc0403a279 100644 --- a/src/test/ui/infinite/infinite-instantiation.stderr +++ b/src/test/ui/infinite/infinite-instantiation.stderr @@ -1,8 +1,8 @@ -error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/infinite-instantiation.rs:23:1 | LL | / fn function(counter: usize, t: T) { -LL | | //~^ ERROR reached the recursion limit while instantiating `function:: 0 { LL | | function(counter - 1, t.to_option()); ... | diff --git a/src/test/ui/infinite/infinite-macro-expansion.stderr b/src/test/ui/infinite/infinite-macro-expansion.stderr index 9b64fba8b94dd..0c0c6596760e2 100644 --- a/src/test/ui/infinite/infinite-macro-expansion.stderr +++ b/src/test/ui/infinite/infinite-macro-expansion.stderr @@ -1,13 +1,13 @@ error: recursion limit reached while expanding the macro `recursive` --> $DIR/infinite-macro-expansion.rs:2:12 | -LL | () => (recursive!()) //~ ERROR recursion limit reached while expanding the macro `recursive` +LL | () => (recursive!()) | ^^^^^^^^^^^^ ... LL | recursive!() | ------------ in this macro invocation | - = help: consider adding a `#![recursion_limit="128"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate error: aborting due to previous error diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.stderr b/src/test/ui/infinite/infinite-recursion-const-fn.stderr index 3ed7957d14d98..9e0530de425f8 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite/infinite-recursion-const-fn.stderr @@ -1,7 +1,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/infinite-recursion-const-fn.rs:3:25 | -LL | const fn a() -> usize { b() } //~ ERROR evaluation of constant value failed +LL | const fn a() -> usize { b() } | ^^^ | | | reached the configured maximum number of stack frames diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.rs b/src/test/ui/infinite/infinite-tag-type-recursion.rs index 87a9e08dd381a..bbfaaa62f0d32 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.rs +++ b/src/test/ui/infinite/infinite-tag-type-recursion.rs @@ -1,4 +1,5 @@ enum MList { Cons(isize, MList), Nil } //~^ ERROR recursive type `MList` has infinite size +//~| ERROR cycle detected when processing `MList` fn main() { let a = MList::Cons(10, MList::Cons(11, MList::Nil)); } diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index 88dad0033ddcf..8f6529db0bec5 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -8,6 +8,16 @@ LL | enum MList { Cons(isize, MList), Nil } | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `MList` representable -error: aborting due to previous error +error[E0391]: cycle detected when processing `MList` + --> $DIR/infinite-tag-type-recursion.rs:1:1 + | +LL | enum MList { Cons(isize, MList), Nil } + | ^^^^^^^^^^ + | + = note: ...which again requires processing `MList`, completing the cycle + = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, value: MList } }` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0072`. +Some errors have detailed explanations: E0072, E0391. +For more information about an error, try `rustc --explain E0072`. diff --git a/src/test/ui/infinite/infinite-vec-type-recursion.stderr b/src/test/ui/infinite/infinite-vec-type-recursion.stderr index daa18a7e9b1ce..be0db56f03449 100644 --- a/src/test/ui/infinite/infinite-vec-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-vec-type-recursion.stderr @@ -9,7 +9,7 @@ note: cycle used when collecting item types in top-level module --> $DIR/infinite-vec-type-recursion.rs:1:1 | LL | / type X = Vec; -LL | | //~^ ERROR cycle detected +LL | | LL | | LL | | fn main() { let b: X = Vec::new(); } | |____________________________________^ diff --git a/src/test/ui/init-unsafe.stderr b/src/test/ui/init-unsafe.stderr index dba8cc43ff223..857142dff64b7 100644 --- a/src/test/ui/init-unsafe.stderr +++ b/src/test/ui/init-unsafe.stderr @@ -1,7 +1,7 @@ error[E0133]: call to unsafe function is unsafe and requires unsafe function or block --> $DIR/init-unsafe.rs:7:17 | -LL | let stuff = init::(); //~ ERROR call to unsafe function is unsafe +LL | let stuff = init::(); | ^^^^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior diff --git a/src/test/ui/inline-asm-bad-constraint.stderr b/src/test/ui/inline-asm-bad-constraint.stderr index 1f63d4c2a48c9..37e71a94c1690 100644 --- a/src/test/ui/inline-asm-bad-constraint.stderr +++ b/src/test/ui/inline-asm-bad-constraint.stderr @@ -1,21 +1,20 @@ error[E0668]: malformed inline assembly --> $DIR/inline-asm-bad-constraint.rs:21:9 | -LL | asm!("" :"={rax"(rax)) //~ ERROR E0668 +LL | asm!("" :"={rax"(rax)) | ^^^^^^^^^^^^^^^^^^^^^^ error[E0668]: malformed inline assembly --> $DIR/inline-asm-bad-constraint.rs:29:9 | -LL | asm!("callq $0" : : "0"(foo)) //~ ERROR E0668 +LL | asm!("callq $0" : : "0"(foo)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0668]: malformed inline assembly --> $DIR/inline-asm-bad-constraint.rs:36:9 | -LL | asm!("addb $1, $0" : "={rax}"((0i32, rax))); //~ ERROR E0668 +LL | asm!("addb $1, $0" : "={rax}"((0i32, rax))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0668`. diff --git a/src/test/ui/inline-asm-bad-operand.stderr b/src/test/ui/inline-asm-bad-operand.stderr index f1de38efc036f..4554da7b798ea 100644 --- a/src/test/ui/inline-asm-bad-operand.stderr +++ b/src/test/ui/inline-asm-bad-operand.stderr @@ -1,45 +1,44 @@ error[E0669]: invalid value for constraint in inline assembly --> $DIR/inline-asm-bad-operand.rs:21:24 | -LL | asm!("" :: "r"("")); //~ ERROR E0669 +LL | asm!("" :: "r"("")); | ^^ error[E0669]: invalid value for constraint in inline assembly --> $DIR/inline-asm-bad-operand.rs:26:32 | -LL | asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669 +LL | asm!("ret" : : "{rdi}"(target)); | ^^^^^^ error[E0669]: invalid value for constraint in inline assembly --> $DIR/inline-asm-bad-operand.rs:33:29 | -LL | unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669 +LL | unsafe { asm!("" :: "i"(hello)) }; | ^^^^^ error[E0669]: invalid value for constraint in inline assembly --> $DIR/inline-asm-bad-operand.rs:41:38 | -LL | asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669 +LL | asm!("movups $1, %xmm0"::"m"(arr)); | ^^^ error[E0669]: invalid value for constraint in inline assembly --> $DIR/inline-asm-bad-operand.rs:48:32 | -LL | asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669 +LL | asm!("mov sp, $0"::"r"(addr)); | ^^^^ error[E0669]: invalid value for constraint in inline assembly --> $DIR/inline-asm-bad-operand.rs:55:32 | -LL | asm!("mov sp, $0"::"r"(addr), //~ ERROR E0669 +LL | asm!("mov sp, $0"::"r"(addr), | ^^^^ error[E0669]: invalid value for constraint in inline assembly --> $DIR/inline-asm-bad-operand.rs:56:32 | -LL | "r"("hello e0669")); //~ ERROR E0669 +LL | "r"("hello e0669")); | ^^^^^^^^^^^^^ error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0669`. diff --git a/src/test/ui/inner-static-type-parameter.stderr b/src/test/ui/inner-static-type-parameter.stderr index 87fb364954d96..083b4b67eb459 100644 --- a/src/test/ui/inner-static-type-parameter.stderr +++ b/src/test/ui/inner-static-type-parameter.stderr @@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/inner-static-type-parameter.rs:6:19 | LL | fn foo() { - | --- - type variable from outer function + | --- - type parameter from outer function | | | try adding a local generic parameter in this method instead LL | static a: Bar = Bar::What; @@ -11,12 +11,12 @@ LL | static a: Bar = Bar::What; error[E0392]: parameter `T` is never used --> $DIR/inner-static-type-parameter.rs:3:10 | -LL | enum Bar { What } //~ ERROR parameter `T` is never used - | ^ unused type parameter +LL | enum Bar { What } + | ^ unused parameter | = help: consider removing `T` or using a marker such as `std::marker::PhantomData` error: aborting due to 2 previous errors -Some errors occurred: E0392, E0401. +Some errors have detailed explanations: E0392, E0401. For more information about an error, try `rustc --explain E0392`. diff --git a/src/test/ui/integer-literal-suffix-inference.stderr b/src/test/ui/integer-literal-suffix-inference.stderr index 04c8633c8b5d8..80b601dc4394b 100644 --- a/src/test/ui/integer-literal-suffix-inference.stderr +++ b/src/test/ui/integer-literal-suffix-inference.stderr @@ -3,288 +3,342 @@ error[E0308]: mismatched types | LL | id_i8(a16); | ^^^ expected i8, found i16 +help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit + | +LL | id_i8(a16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:35:11 | LL | id_i8(a32); | ^^^ expected i8, found i32 +help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit + | +LL | id_i8(a32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:38:11 | LL | id_i8(a64); | ^^^ expected i8, found i64 +help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit + | +LL | id_i8(a64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:42:12 | LL | id_i16(a8); - | ^^ expected i16, found i8 -help: you can cast an `i8` to `i16`, which will sign-extend the source value - | -LL | id_i16(a8.into()); - | ^^^^^^^^^ + | ^^ + | | + | expected i16, found i8 + | help: you can convert an `i8` to `i16`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:46:12 | LL | id_i16(a32); | ^^^ expected i16, found i32 +help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit + | +LL | id_i16(a32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:49:12 | LL | id_i16(a64); | ^^^ expected i16, found i64 +help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit + | +LL | id_i16(a64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:53:12 | LL | id_i32(a8); - | ^^ expected i32, found i8 -help: you can cast an `i8` to `i32`, which will sign-extend the source value - | -LL | id_i32(a8.into()); - | ^^^^^^^^^ + | ^^ + | | + | expected i32, found i8 + | help: you can convert an `i8` to `i32`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:56:12 | LL | id_i32(a16); - | ^^^ expected i32, found i16 -help: you can cast an `i16` to `i32`, which will sign-extend the source value - | -LL | id_i32(a16.into()); - | ^^^^^^^^^^ + | ^^^ + | | + | expected i32, found i16 + | help: you can convert an `i16` to `i32`: `a16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:60:12 | LL | id_i32(a64); | ^^^ expected i32, found i64 +help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit + | +LL | id_i32(a64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:64:12 | LL | id_i64(a8); - | ^^ expected i64, found i8 -help: you can cast an `i8` to `i64`, which will sign-extend the source value - | -LL | id_i64(a8.into()); - | ^^^^^^^^^ + | ^^ + | | + | expected i64, found i8 + | help: you can convert an `i8` to `i64`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:67:12 | LL | id_i64(a16); - | ^^^ expected i64, found i16 -help: you can cast an `i16` to `i64`, which will sign-extend the source value - | -LL | id_i64(a16.into()); - | ^^^^^^^^^^ + | ^^^ + | | + | expected i64, found i16 + | help: you can convert an `i16` to `i64`: `a16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:70:12 | LL | id_i64(a32); - | ^^^ expected i64, found i32 -help: you can cast an `i32` to `i64`, which will sign-extend the source value - | -LL | id_i64(a32.into()); - | ^^^^^^^^^^ + | ^^^ + | | + | expected i64, found i32 + | help: you can convert an `i32` to `i64`: `a32.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:76:11 | LL | id_i8(c16); | ^^^ expected i8, found i16 +help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit + | +LL | id_i8(c16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:79:11 | LL | id_i8(c32); | ^^^ expected i8, found i32 +help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit + | +LL | id_i8(c32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:82:11 | LL | id_i8(c64); | ^^^ expected i8, found i64 +help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit + | +LL | id_i8(c64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:86:12 | LL | id_i16(c8); - | ^^ expected i16, found i8 -help: you can cast an `i8` to `i16`, which will sign-extend the source value - | -LL | id_i16(c8.into()); - | ^^^^^^^^^ + | ^^ + | | + | expected i16, found i8 + | help: you can convert an `i8` to `i16`: `c8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:90:12 | LL | id_i16(c32); | ^^^ expected i16, found i32 +help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit + | +LL | id_i16(c32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:93:12 | LL | id_i16(c64); | ^^^ expected i16, found i64 +help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit + | +LL | id_i16(c64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:97:12 | LL | id_i32(c8); - | ^^ expected i32, found i8 -help: you can cast an `i8` to `i32`, which will sign-extend the source value - | -LL | id_i32(c8.into()); - | ^^^^^^^^^ + | ^^ + | | + | expected i32, found i8 + | help: you can convert an `i8` to `i32`: `c8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:100:12 | LL | id_i32(c16); - | ^^^ expected i32, found i16 -help: you can cast an `i16` to `i32`, which will sign-extend the source value - | -LL | id_i32(c16.into()); - | ^^^^^^^^^^ + | ^^^ + | | + | expected i32, found i16 + | help: you can convert an `i16` to `i32`: `c16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:104:12 | LL | id_i32(c64); | ^^^ expected i32, found i64 +help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit + | +LL | id_i32(c64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:108:12 | LL | id_i64(a8); - | ^^ expected i64, found i8 -help: you can cast an `i8` to `i64`, which will sign-extend the source value - | -LL | id_i64(a8.into()); - | ^^^^^^^^^ + | ^^ + | | + | expected i64, found i8 + | help: you can convert an `i8` to `i64`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:111:12 | LL | id_i64(a16); - | ^^^ expected i64, found i16 -help: you can cast an `i16` to `i64`, which will sign-extend the source value - | -LL | id_i64(a16.into()); - | ^^^^^^^^^^ + | ^^^ + | | + | expected i64, found i16 + | help: you can convert an `i16` to `i64`: `a16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:114:12 | LL | id_i64(a32); - | ^^^ expected i64, found i32 -help: you can cast an `i32` to `i64`, which will sign-extend the source value - | -LL | id_i64(a32.into()); - | ^^^^^^^^^^ + | ^^^ + | | + | expected i64, found i32 + | help: you can convert an `i32` to `i64`: `a32.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:120:11 | LL | id_u8(b16); | ^^^ expected u8, found u16 +help: you can convert an `u16` to `u8` and panic if the converted value wouldn't fit + | +LL | id_u8(b16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:123:11 | LL | id_u8(b32); | ^^^ expected u8, found u32 +help: you can convert an `u32` to `u8` and panic if the converted value wouldn't fit + | +LL | id_u8(b32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:126:11 | LL | id_u8(b64); | ^^^ expected u8, found u64 +help: you can convert an `u64` to `u8` and panic if the converted value wouldn't fit + | +LL | id_u8(b64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:130:12 | LL | id_u16(b8); - | ^^ expected u16, found u8 -help: you can cast an `u8` to `u16`, which will zero-extend the source value - | -LL | id_u16(b8.into()); - | ^^^^^^^^^ + | ^^ + | | + | expected u16, found u8 + | help: you can convert an `u8` to `u16`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:134:12 | LL | id_u16(b32); | ^^^ expected u16, found u32 +help: you can convert an `u32` to `u16` and panic if the converted value wouldn't fit + | +LL | id_u16(b32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:137:12 | LL | id_u16(b64); | ^^^ expected u16, found u64 +help: you can convert an `u64` to `u16` and panic if the converted value wouldn't fit + | +LL | id_u16(b64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:141:12 | LL | id_u32(b8); - | ^^ expected u32, found u8 -help: you can cast an `u8` to `u32`, which will zero-extend the source value - | -LL | id_u32(b8.into()); - | ^^^^^^^^^ + | ^^ + | | + | expected u32, found u8 + | help: you can convert an `u8` to `u32`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:144:12 | LL | id_u32(b16); - | ^^^ expected u32, found u16 -help: you can cast an `u16` to `u32`, which will zero-extend the source value - | -LL | id_u32(b16.into()); - | ^^^^^^^^^^ + | ^^^ + | | + | expected u32, found u16 + | help: you can convert an `u16` to `u32`: `b16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:148:12 | LL | id_u32(b64); | ^^^ expected u32, found u64 +help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit + | +LL | id_u32(b64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:152:12 | LL | id_u64(b8); - | ^^ expected u64, found u8 -help: you can cast an `u8` to `u64`, which will zero-extend the source value - | -LL | id_u64(b8.into()); - | ^^^^^^^^^ + | ^^ + | | + | expected u64, found u8 + | help: you can convert an `u8` to `u64`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:155:12 | LL | id_u64(b16); - | ^^^ expected u64, found u16 -help: you can cast an `u16` to `u64`, which will zero-extend the source value - | -LL | id_u64(b16.into()); - | ^^^^^^^^^^ + | ^^^ + | | + | expected u64, found u16 + | help: you can convert an `u16` to `u64`: `b16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:158:12 | LL | id_u64(b32); - | ^^^ expected u64, found u32 -help: you can cast an `u32` to `u64`, which will zero-extend the source value - | -LL | id_u64(b32.into()); - | ^^^^^^^^^^ + | ^^^ + | | + | expected u64, found u32 + | help: you can convert an `u32` to `u64`: `b32.into()` error: aborting due to 36 previous errors diff --git a/src/test/ui/integral-indexing.stderr b/src/test/ui/integral-indexing.stderr index efbad86c4d31b..28ef5937eaa46 100644 --- a/src/test/ui/integral-indexing.stderr +++ b/src/test/ui/integral-indexing.stderr @@ -1,7 +1,7 @@ error[E0277]: the type `[isize]` cannot be indexed by `u8` --> $DIR/integral-indexing.rs:6:5 | -LL | v[3u8]; //~ERROR : the type `[isize]` cannot be indexed by `u8` +LL | v[3u8]; | ^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `u8` @@ -10,7 +10,7 @@ LL | v[3u8]; //~ERROR : the type `[isize]` cannot be indexed by `u8` error[E0277]: the type `[isize]` cannot be indexed by `i8` --> $DIR/integral-indexing.rs:7:5 | -LL | v[3i8]; //~ERROR : the type `[isize]` cannot be indexed by `i8` +LL | v[3i8]; | ^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `i8` @@ -19,7 +19,7 @@ LL | v[3i8]; //~ERROR : the type `[isize]` cannot be indexed by `i8` error[E0277]: the type `[isize]` cannot be indexed by `u32` --> $DIR/integral-indexing.rs:8:5 | -LL | v[3u32]; //~ERROR : the type `[isize]` cannot be indexed by `u32` +LL | v[3u32]; | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `u32` @@ -28,7 +28,7 @@ LL | v[3u32]; //~ERROR : the type `[isize]` cannot be indexed by `u32` error[E0277]: the type `[isize]` cannot be indexed by `i32` --> $DIR/integral-indexing.rs:9:5 | -LL | v[3i32]; //~ERROR : the type `[isize]` cannot be indexed by `i32` +LL | v[3i32]; | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `i32` @@ -37,7 +37,7 @@ LL | v[3i32]; //~ERROR : the type `[isize]` cannot be indexed by `i32` error[E0277]: the type `[u8]` cannot be indexed by `u8` --> $DIR/integral-indexing.rs:12:5 | -LL | s.as_bytes()[3u8]; //~ERROR : the type `[u8]` cannot be indexed by `u8` +LL | s.as_bytes()[3u8]; | ^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `u8` @@ -46,7 +46,7 @@ LL | s.as_bytes()[3u8]; //~ERROR : the type `[u8]` cannot be indexed by `u8 error[E0277]: the type `[u8]` cannot be indexed by `i8` --> $DIR/integral-indexing.rs:13:5 | -LL | s.as_bytes()[3i8]; //~ERROR : the type `[u8]` cannot be indexed by `i8` +LL | s.as_bytes()[3i8]; | ^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `i8` @@ -55,7 +55,7 @@ LL | s.as_bytes()[3i8]; //~ERROR : the type `[u8]` cannot be indexed by `i8 error[E0277]: the type `[u8]` cannot be indexed by `u32` --> $DIR/integral-indexing.rs:14:5 | -LL | s.as_bytes()[3u32]; //~ERROR : the type `[u8]` cannot be indexed by `u32` +LL | s.as_bytes()[3u32]; | ^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `u32` @@ -64,7 +64,7 @@ LL | s.as_bytes()[3u32]; //~ERROR : the type `[u8]` cannot be indexed by `u3 error[E0277]: the type `[u8]` cannot be indexed by `i32` --> $DIR/integral-indexing.rs:15:5 | -LL | s.as_bytes()[3i32]; //~ERROR : the type `[u8]` cannot be indexed by `i32` +LL | s.as_bytes()[3i32]; | ^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `i32` diff --git a/src/test/ui/internal/internal-unstable-thread-local.stderr b/src/test/ui/internal/internal-unstable-thread-local.stderr index 0e25592b103c3..603bdc39bdd0c 100644 --- a/src/test/ui/internal/internal-unstable-thread-local.stderr +++ b/src/test/ui/internal/internal-unstable-thread-local.stderr @@ -1,7 +1,7 @@ error[E0658]: use of unstable library feature 'function' --> $DIR/internal-unstable-thread-local.rs:9:32 | -LL | thread_local!(static BAR: () = internal_unstable::unstable()); //~ ERROR use of unstable +LL | thread_local!(static BAR: () = internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(function)] to the crate attributes to enable diff --git a/src/test/ui/internal/internal-unstable.stderr b/src/test/ui/internal/internal-unstable.stderr index 3e1a44f082ee7..5c14fed568f2a 100644 --- a/src/test/ui/internal/internal-unstable.stderr +++ b/src/test/ui/internal/internal-unstable.stderr @@ -1,7 +1,7 @@ error[E0658]: use of unstable library feature 'function' --> $DIR/internal-unstable.rs:33:25 | -LL | pass_through_allow!(internal_unstable::unstable()); //~ ERROR use of unstable +LL | pass_through_allow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(function)] to the crate attributes to enable @@ -9,7 +9,7 @@ LL | pass_through_allow!(internal_unstable::unstable()); //~ ERROR use of un error[E0658]: use of unstable library feature 'function' --> $DIR/internal-unstable.rs:35:27 | -LL | pass_through_noallow!(internal_unstable::unstable()); //~ ERROR use of unstable +LL | pass_through_noallow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(function)] to the crate attributes to enable @@ -17,7 +17,7 @@ LL | pass_through_noallow!(internal_unstable::unstable()); //~ ERROR use of error[E0658]: use of unstable library feature 'function' --> $DIR/internal-unstable.rs:39:22 | -LL | println!("{:?}", internal_unstable::unstable()); //~ ERROR use of unstable +LL | println!("{:?}", internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(function)] to the crate attributes to enable @@ -25,7 +25,7 @@ LL | println!("{:?}", internal_unstable::unstable()); //~ ERROR use of unsta error[E0658]: use of unstable library feature 'function' --> $DIR/internal-unstable.rs:41:10 | -LL | bar!(internal_unstable::unstable()); //~ ERROR use of unstable +LL | bar!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(function)] to the crate attributes to enable @@ -33,10 +33,10 @@ LL | bar!(internal_unstable::unstable()); //~ ERROR use of unstable error[E0658]: use of unstable library feature 'function' --> $DIR/internal-unstable.rs:12:9 | -LL | internal_unstable::unstable(); //~ ERROR use of unstable +LL | internal_unstable::unstable(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... -LL | bar!(internal_unstable::unstable()); //~ ERROR use of unstable +LL | bar!(internal_unstable::unstable()); | ------------------------------------ in this macro invocation | = help: add #![feature(function)] to the crate attributes to enable diff --git a/src/test/ui/intrinsics/unchecked_math_unsafe.rs b/src/test/ui/intrinsics/unchecked_math_unsafe.rs new file mode 100644 index 0000000000000..a034b45f5308c --- /dev/null +++ b/src/test/ui/intrinsics/unchecked_math_unsafe.rs @@ -0,0 +1,8 @@ +#![feature(core_intrinsics)] + +fn main() { + let (x, y) = (1u32, 2u32); + let add = std::intrinsics::unchecked_add(x, y); //~ ERROR call to unsafe function + let sub = std::intrinsics::unchecked_sub(x, y); //~ ERROR call to unsafe function + let mul = std::intrinsics::unchecked_mul(x, y); //~ ERROR call to unsafe function +} diff --git a/src/test/ui/intrinsics/unchecked_math_unsafe.stderr b/src/test/ui/intrinsics/unchecked_math_unsafe.stderr new file mode 100644 index 0000000000000..4066cf8efb8c1 --- /dev/null +++ b/src/test/ui/intrinsics/unchecked_math_unsafe.stderr @@ -0,0 +1,27 @@ +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/unchecked_math_unsafe.rs:5:15 + | +LL | let add = std::intrinsics::unchecked_add(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/unchecked_math_unsafe.rs:6:15 + | +LL | let sub = std::intrinsics::unchecked_sub(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/unchecked_math_unsafe.rs:7:15 + | +LL | let mul = std::intrinsics::unchecked_mul(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/intrinsics/unchecked_math_unstable.rs b/src/test/ui/intrinsics/unchecked_math_unstable.rs new file mode 100644 index 0000000000000..8869063d1cc3d --- /dev/null +++ b/src/test/ui/intrinsics/unchecked_math_unstable.rs @@ -0,0 +1,8 @@ +fn main() { + let (x, y) = (1u32, 2u32); + unsafe { + let add = std::intrinsics::unchecked_add(x, y); //~ ERROR use of unstable library feature + let sub = std::intrinsics::unchecked_sub(x, y); //~ ERROR use of unstable library feature + let mul = std::intrinsics::unchecked_mul(x, y); //~ ERROR use of unstable library feature + } +} diff --git a/src/test/ui/intrinsics/unchecked_math_unstable.stderr b/src/test/ui/intrinsics/unchecked_math_unstable.stderr new file mode 100644 index 0000000000000..6f5429127c690 --- /dev/null +++ b/src/test/ui/intrinsics/unchecked_math_unstable.stderr @@ -0,0 +1,27 @@ +error[E0658]: use of unstable library feature 'core_intrinsics': intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library + --> $DIR/unchecked_math_unstable.rs:4:19 + | +LL | let add = std::intrinsics::unchecked_add(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(core_intrinsics)] to the crate attributes to enable + +error[E0658]: use of unstable library feature 'core_intrinsics': intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library + --> $DIR/unchecked_math_unstable.rs:5:19 + | +LL | let sub = std::intrinsics::unchecked_sub(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(core_intrinsics)] to the crate attributes to enable + +error[E0658]: use of unstable library feature 'core_intrinsics': intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library + --> $DIR/unchecked_math_unstable.rs:6:19 + | +LL | let mul = std::intrinsics::unchecked_mul(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(core_intrinsics)] to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs b/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs index 3b1cd9fbdc80e..254d810d79dbc 100644 --- a/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs +++ b/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - mod auxiliary { mod foo; } diff --git a/src/test/ui/invalid-self-argument/bare-fn-start.rs b/src/test/ui/invalid-self-argument/bare-fn-start.rs index 741ba5f41ce16..a003a01941bde 100644 --- a/src/test/ui/invalid-self-argument/bare-fn-start.rs +++ b/src/test/ui/invalid-self-argument/bare-fn-start.rs @@ -1,5 +1,6 @@ fn a(&self) { } -//~^ ERROR unexpected `self` argument in function -//~| NOTE `self` is only valid as the first argument of an associated function +//~^ ERROR unexpected `self` parameter in function +//~| NOTE not valid as function parameter +//~| NOTE `self` is only valid as the first parameter of an associated function fn main() { } diff --git a/src/test/ui/invalid-self-argument/bare-fn-start.stderr b/src/test/ui/invalid-self-argument/bare-fn-start.stderr index 6a878b619d813..23de6502094f0 100644 --- a/src/test/ui/invalid-self-argument/bare-fn-start.stderr +++ b/src/test/ui/invalid-self-argument/bare-fn-start.stderr @@ -1,8 +1,10 @@ -error: unexpected `self` argument in function - --> $DIR/bare-fn-start.rs:1:7 +error: unexpected `self` parameter in function + --> $DIR/bare-fn-start.rs:1:6 | LL | fn a(&self) { } - | ^^^^ `self` is only valid as the first argument of an associated function + | ^^^^^ not valid as function parameter + | + = note: `self` is only valid as the first parameter of an associated function error: aborting due to previous error diff --git a/src/test/ui/invalid-self-argument/bare-fn.rs b/src/test/ui/invalid-self-argument/bare-fn.rs index 704fa996ca631..73d68e8b7a5ab 100644 --- a/src/test/ui/invalid-self-argument/bare-fn.rs +++ b/src/test/ui/invalid-self-argument/bare-fn.rs @@ -1,5 +1,6 @@ fn b(foo: u32, &mut self) { } -//~^ ERROR unexpected `self` argument in function -//~| NOTE `self` is only valid as the first argument of an associated function +//~^ ERROR unexpected `self` parameter in function +//~| NOTE not valid as function parameter +//~| NOTE `self` is only valid as the first parameter of an associated function fn main() { } diff --git a/src/test/ui/invalid-self-argument/bare-fn.stderr b/src/test/ui/invalid-self-argument/bare-fn.stderr index b13f746a4ec58..601a51bb4a96a 100644 --- a/src/test/ui/invalid-self-argument/bare-fn.stderr +++ b/src/test/ui/invalid-self-argument/bare-fn.stderr @@ -1,8 +1,10 @@ -error: unexpected `self` argument in function - --> $DIR/bare-fn.rs:1:21 +error: unexpected `self` parameter in function + --> $DIR/bare-fn.rs:1:16 | LL | fn b(foo: u32, &mut self) { } - | ^^^^ `self` is only valid as the first argument of an associated function + | ^^^^^^^^^ not valid as function parameter + | + = note: `self` is only valid as the first parameter of an associated function error: aborting due to previous error diff --git a/src/test/ui/invalid-self-argument/trait-fn.rs b/src/test/ui/invalid-self-argument/trait-fn.rs index 31e867bc7641f..1e8220d7b4a78 100644 --- a/src/test/ui/invalid-self-argument/trait-fn.rs +++ b/src/test/ui/invalid-self-argument/trait-fn.rs @@ -2,8 +2,8 @@ struct Foo {} impl Foo { fn c(foo: u32, self) {} - //~^ ERROR unexpected `self` argument in function - //~| NOTE `self` is only valid as the first argument of an associated function + //~^ ERROR unexpected `self` parameter in function + //~| NOTE must be the first associated function parameter fn good(&mut self, foo: u32) {} } diff --git a/src/test/ui/invalid-self-argument/trait-fn.stderr b/src/test/ui/invalid-self-argument/trait-fn.stderr index b3c2cc5b5ebe0..96a2251c036b1 100644 --- a/src/test/ui/invalid-self-argument/trait-fn.stderr +++ b/src/test/ui/invalid-self-argument/trait-fn.stderr @@ -1,8 +1,8 @@ -error: unexpected `self` argument in function +error: unexpected `self` parameter in function --> $DIR/trait-fn.rs:4:20 | LL | fn c(foo: u32, self) {} - | ^^^^ `self` is only valid as the first argument of an associated function + | ^^^^ must be the first associated function parameter error: aborting due to previous error diff --git a/src/test/ui/invalid/invalid-crate-type.stderr b/src/test/ui/invalid/invalid-crate-type.stderr index 63edd04650b21..030dc96c6d646 100644 --- a/src/test/ui/invalid/invalid-crate-type.stderr +++ b/src/test/ui/invalid/invalid-crate-type.stderr @@ -1,7 +1,7 @@ error: invalid `crate_type` value --> $DIR/invalid-crate-type.rs:2:15 | -LL | #![crate_type="foo"] //~ ERROR invalid `crate_type` value +LL | #![crate_type="foo"] | ^^^^^ | = note: #[deny(unknown_crate_types)] on by default diff --git a/src/test/ui/invalid/invalid-inline.stderr b/src/test/ui/invalid/invalid-inline.stderr index fdbd25070f7f8..f3d0426419729 100644 --- a/src/test/ui/invalid/invalid-inline.stderr +++ b/src/test/ui/invalid/invalid-inline.stderr @@ -1,22 +1,22 @@ error[E0535]: invalid argument --> $DIR/invalid-inline.rs:3:10 | -LL | #[inline(please_no)] //~ ERROR invalid argument +LL | #[inline(please_no)] | ^^^^^^^^^ error[E0534]: expected one argument --> $DIR/invalid-inline.rs:7:1 | -LL | #[inline(please,no)] //~ ERROR expected one argument +LL | #[inline(please,no)] | ^^^^^^^^^^^^^^^^^^^^ error[E0534]: expected one argument --> $DIR/invalid-inline.rs:11:1 | -LL | #[inline()] //~ ERROR expected one argument +LL | #[inline()] | ^^^^^^^^^^^ error: aborting due to 3 previous errors -Some errors occurred: E0534, E0535. +Some errors have detailed explanations: E0534, E0535. For more information about an error, try `rustc --explain E0534`. diff --git a/src/test/ui/invalid/invalid-macro-matcher.stderr b/src/test/ui/invalid/invalid-macro-matcher.stderr index 5d6c70fa30b88..dbe025b7330b0 100644 --- a/src/test/ui/invalid/invalid-macro-matcher.stderr +++ b/src/test/ui/invalid/invalid-macro-matcher.stderr @@ -1,7 +1,7 @@ error: invalid macro matcher; matchers must be contained in balanced delimiters --> $DIR/invalid-macro-matcher.rs:4:5 | -LL | _ => (); //~ ERROR invalid macro matcher +LL | _ => (); | ^ error: aborting due to previous error diff --git a/src/test/ui/invalid/invalid-path-in-const.stderr b/src/test/ui/invalid/invalid-path-in-const.stderr index 13176b8b8fb15..a14ab7d85e851 100644 --- a/src/test/ui/invalid/invalid-path-in-const.stderr +++ b/src/test/ui/invalid/invalid-path-in-const.stderr @@ -2,9 +2,7 @@ error[E0599]: no associated item named `DOESNOTEXIST` found for type `u32` in th --> $DIR/invalid-path-in-const.rs:2:23 | LL | fn f(a: [u8; u32::DOESNOTEXIST]) {} - | -----^^^^^^^^^^^^ - | | - | associated item not found in `u32` + | ^^^^^^^^^^^^ associated item not found in `u32` error: aborting due to previous error diff --git a/src/test/ui/invalid/invalid-plugin-attr.stderr b/src/test/ui/invalid/invalid-plugin-attr.stderr index 2d7ae1f5cfedc..c7b2ce47489a4 100644 --- a/src/test/ui/invalid/invalid-plugin-attr.stderr +++ b/src/test/ui/invalid/invalid-plugin-attr.stderr @@ -1,7 +1,7 @@ error: unused attribute --> $DIR/invalid-plugin-attr.rs:4:1 | -LL | #[plugin(bla)] //~ ERROR unused attribute +LL | #[plugin(bla)] | ^^^^^^^^^^^^^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unused_attributes)] error: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] --> $DIR/invalid-plugin-attr.rs:4:1 | -LL | #[plugin(bla)] //~ ERROR unused attribute +LL | #[plugin(bla)] | ^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/invalid_crate_type_syntax.rs b/src/test/ui/invalid_crate_type_syntax.rs index 8157ccdcbf0b9..621587af35ed7 100644 --- a/src/test/ui/invalid_crate_type_syntax.rs +++ b/src/test/ui/invalid_crate_type_syntax.rs @@ -1,5 +1,5 @@ // regression test for issue 16974 -#![crate_type(lib)] //~ ERROR attribute must be of the form +#![crate_type(lib)] //~ ERROR malformed `crate_type` attribute input fn my_lib_fn() {} diff --git a/src/test/ui/invalid_crate_type_syntax.stderr b/src/test/ui/invalid_crate_type_syntax.stderr index 8d6948b583c51..92bed231586f9 100644 --- a/src/test/ui/invalid_crate_type_syntax.stderr +++ b/src/test/ui/invalid_crate_type_syntax.stderr @@ -1,8 +1,8 @@ -error: attribute must be of the form `#[crate_type = "bin|lib|..."]` +error: malformed `crate_type` attribute input --> $DIR/invalid_crate_type_syntax.rs:2:1 | -LL | #![crate_type(lib)] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^^^^^^ +LL | #![crate_type(lib)] + | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[crate_type = "bin|lib|..."]` error: aborting due to previous error diff --git a/src/test/ui/invalid_dispatch_from_dyn_impls.rs b/src/test/ui/invalid_dispatch_from_dyn_impls.rs index c4716893fbc54..b7bc766fbe020 100644 --- a/src/test/ui/invalid_dispatch_from_dyn_impls.rs +++ b/src/test/ui/invalid_dispatch_from_dyn_impls.rs @@ -39,4 +39,13 @@ where T: Unsize, {} //~^^^ ERROR [E0378] +#[repr(align(64))] +struct OverAlignedZst; +struct OverAligned(Box, OverAlignedZst); + +impl DispatchFromDyn> for OverAligned + where + T: Unsize, +{} //~^^^ ERROR [E0378] + fn main() {} diff --git a/src/test/ui/invalid_dispatch_from_dyn_impls.stderr b/src/test/ui/invalid_dispatch_from_dyn_impls.stderr index 8ee0a40a529c0..6d62d4fd0711d 100644 --- a/src/test/ui/invalid_dispatch_from_dyn_impls.stderr +++ b/src/test/ui/invalid_dispatch_from_dyn_impls.stderr @@ -1,10 +1,10 @@ -error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, `PhantomData` fields, and nothing else +error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else --> $DIR/invalid_dispatch_from_dyn_impls.rs:10:1 | LL | / impl DispatchFromDyn> for WrapperWithExtraField LL | | where LL | | T: DispatchFromDyn, -LL | | {} //~^^^ ERROR [E0378] +LL | | {} | |__^ | = note: extra field `1` of type `i32` is not allowed @@ -15,7 +15,7 @@ error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercio LL | / impl DispatchFromDyn> for MultiplePointers LL | | where LL | | T: Unsize, -LL | | {} //~^^^ ERROR [E0378] +LL | | {} | |__^ | = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced @@ -33,9 +33,20 @@ error[E0378]: structs implementing `DispatchFromDyn` may not have `#[repr(packed LL | / impl DispatchFromDyn> for HasReprC LL | | where LL | | T: Unsize, -LL | | {} //~^^^ ERROR [E0378] +LL | | {} | |__^ -error: aborting due to 4 previous errors +error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else + --> $DIR/invalid_dispatch_from_dyn_impls.rs:46:1 + | +LL | / impl DispatchFromDyn> for OverAligned +LL | | where +LL | | T: Unsize, +LL | | {} + | |__^ + | + = note: extra field `1` of type `OverAlignedZst` is not allowed + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0378`. diff --git a/src/test/ui/issue-18986.stderr b/src/test/ui/issue-18986.stderr deleted file mode 100644 index 440782b0b1f2b..0000000000000 --- a/src/test/ui/issue-18986.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0574]: expected struct, variant or union type, found trait `Trait` - --> $DIR/issue-18986.rs:8:9 - | -LL | Trait { x: 42 } => () //~ ERROR expected struct, variant or union type, found trait `Trait` - | ^^^^^ not a struct, variant or union type - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/issue-42944.stderr b/src/test/ui/issue-42944.stderr deleted file mode 100644 index 43fd0ffb72439..0000000000000 --- a/src/test/ui/issue-42944.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0423]: expected function, found struct `B` - --> $DIR/issue-42944.rs:9:9 - | -LL | B(()); //~ ERROR expected function, found struct `B` [E0423] - | ^ constructor is not visible here due to private fields - -error[E0425]: cannot find function `B` in this scope - --> $DIR/issue-42944.rs:15:9 - | -LL | B(()); //~ ERROR cannot find function `B` in this scope [E0425] - | ^ not found in this scope -help: possible candidate is found in another module, you can import it into scope - | -LL | use foo::B; - | - -error: aborting due to 2 previous errors - -Some errors occurred: E0423, E0425. -For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/issue-53787-inline-assembler-macro.stderr b/src/test/ui/issue-53787-inline-assembler-macro.stderr deleted file mode 100644 index 69f380bdc9c03..0000000000000 --- a/src/test/ui/issue-53787-inline-assembler-macro.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0669]: invalid value for constraint in inline assembly - --> $DIR/issue-53787-inline-assembler-macro.rs:21:16 - | -LL | fake_jump!("FirstFunc"); //~ ERROR invalid value for constraint in inline assembly - | ^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0669`. diff --git a/src/test/ui/issue-53912.rs b/src/test/ui/issue-53912.rs new file mode 100644 index 0000000000000..d2347c3077cf3 --- /dev/null +++ b/src/test/ui/issue-53912.rs @@ -0,0 +1,37 @@ +// compile-pass + +// This test is the same code as in ui/symbol-names/issue-60925.rs but this checks that the +// reproduction compiles successfully and doesn't segfault, whereas that test just checks that the +// symbol mangling fix produces the correct result. + +fn dummy() {} + +mod llvm { + pub(crate) struct Foo; +} +mod foo { + pub(crate) struct Foo(T); + + impl Foo<::llvm::Foo> { + pub(crate) fn foo() { + for _ in 0..0 { + for _ in &[::dummy()] { + ::dummy(); + ::dummy(); + ::dummy(); + } + } + } + } + + pub(crate) fn foo() { + Foo::foo(); + Foo::foo(); + } +} + +pub fn foo() { + foo::foo(); +} + +fn main() {} diff --git a/src/test/ui/issue-54943.rs b/src/test/ui/issue-54943.rs deleted file mode 100644 index ce4e010674359..0000000000000 --- a/src/test/ui/issue-54943.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![feature(nll)] -#![allow(warnings)] - -fn foo() { } - -fn boo<'a>() { - return; - - let x = foo::<&'a u32>(); - //~^ ERROR lifetime may not live long enough -} - -fn main() {} diff --git a/src/test/ui/issue-54943.stderr b/src/test/ui/issue-54943.stderr deleted file mode 100644 index aa68177bcdb58..0000000000000 --- a/src/test/ui/issue-54943.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/issue-54943.rs:9:13 - | -LL | fn boo<'a>() { - | -- lifetime `'a` defined here -... -LL | let x = foo::<&'a u32>(); - | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - -error: aborting due to previous error - diff --git a/src/test/ui/issue-55511.stderr b/src/test/ui/issue-55511.stderr deleted file mode 100644 index 24668f045517a..0000000000000 --- a/src/test/ui/issue-55511.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0597]: `a` does not live long enough - --> $DIR/issue-55511.rs:13:29 - | -LL | let b = Some(Cell::new(&a)); - | ^ borrowed value does not live long enough -... -LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issues/auxiliary/issue-59764.rs b/src/test/ui/issues/auxiliary/issue-59764.rs new file mode 100644 index 0000000000000..a92eed968d060 --- /dev/null +++ b/src/test/ui/issues/auxiliary/issue-59764.rs @@ -0,0 +1,18 @@ +pub mod foo { + #[macro_export] + macro_rules! makro { + ($foo:ident) => { + fn $foo() { } + } + } + + pub fn baz() {} + + pub fn foobar() {} + + pub mod barbaz { + pub fn barfoo() {} + } +} + +pub fn foobaz() {} diff --git a/src/test/ui/issues/issue-10200.stderr b/src/test/ui/issues/issue-10200.stderr index ac1ad118a7152..544716e89b39d 100644 --- a/src/test/ui/issues/issue-10200.stderr +++ b/src/test/ui/issues/issue-10200.stderr @@ -1,7 +1,7 @@ error[E0532]: expected tuple struct/variant, found function `foo` --> $DIR/issue-10200.rs:6:9 | -LL | foo(x) //~ ERROR expected tuple struct/variant, found function `foo` +LL | foo(x) | ^^^ help: a tuple struct with a similar name exists: `Foo` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-10291.nll.stderr b/src/test/ui/issues/issue-10291.nll.stderr new file mode 100644 index 0000000000000..a7b827d27a87b --- /dev/null +++ b/src/test/ui/issues/issue-10291.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/issue-10291.rs:3:9 + | +LL | fn test<'x>(x: &'x isize) { + | -- lifetime `'x` defined here +LL | drop:: FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { +LL | x + | ^ returning this value requires that `'x` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-10291.rs b/src/test/ui/issues/issue-10291.rs index 877b0aba47392..559c5fcac954b 100644 --- a/src/test/ui/issues/issue-10291.rs +++ b/src/test/ui/issues/issue-10291.rs @@ -1,5 +1,5 @@ fn test<'x>(x: &'x isize) { - drop:: FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { + drop:: FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { x //~ ERROR E0312 })); } diff --git a/src/test/ui/issues/issue-10291.stderr b/src/test/ui/issues/issue-10291.stderr index 9bd428950179b..5e63469da59f5 100644 --- a/src/test/ui/issues/issue-10291.stderr +++ b/src/test/ui/issues/issue-10291.stderr @@ -1,15 +1,15 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/issue-10291.rs:3:9 | -LL | x //~ ERROR E0312 +LL | x | ^ | -note: ...the reference is valid for the anonymous lifetime #2 defined on the body at 2:65... - --> $DIR/issue-10291.rs:2:65 +note: ...the reference is valid for the anonymous lifetime #2 defined on the body at 2:69... + --> $DIR/issue-10291.rs:2:69 | -LL | drop:: FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { - | _________________________________________________________________^ -LL | | x //~ ERROR E0312 +LL | drop:: FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { + | _____________________________________________________________________^ +LL | | x LL | | })); | |_____^ note: ...but the borrowed content is only valid for the lifetime 'x as defined on the function body at 1:9 @@ -20,4 +20,3 @@ LL | fn test<'x>(x: &'x isize) { error: aborting due to previous error -For more information about this error, try `rustc --explain E0312`. diff --git a/src/test/ui/issues/issue-10398.nll.stderr b/src/test/ui/issues/issue-10398.nll.stderr deleted file mode 100644 index f5f4974265b9a..0000000000000 --- a/src/test/ui/issues/issue-10398.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: use of moved value: `x` - --> $DIR/issue-10398.rs:7:14 - | -LL | let _a = x; - | - value moved here -LL | drop(x); - | ^ value used here after move - | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/issues/issue-10398.stderr b/src/test/ui/issues/issue-10398.stderr index ceb2cfe2b75af..f5f4974265b9a 100644 --- a/src/test/ui/issues/issue-10398.stderr +++ b/src/test/ui/issues/issue-10398.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/issue-10398.rs:7:14 | LL | let _a = x; - | -- value moved here + | - value moved here LL | drop(x); | ^ value used here after move | diff --git a/src/test/ui/issues/issue-10412.rs b/src/test/ui/issues/issue-10412.rs index a0bc2fc2f3c79..020585136856b 100644 --- a/src/test/ui/issues/issue-10412.rs +++ b/src/test/ui/issues/issue-10412.rs @@ -5,7 +5,8 @@ trait Serializable<'self, T> { //~ ERROR lifetimes cannot use keyword names impl<'self> Serializable for &'self str { //~ ERROR lifetimes cannot use keyword names //~^ ERROR lifetimes cannot use keyword names - //~| ERROR missing lifetime specifier + //~| ERROR implicit elided lifetime not allowed here + //~| ERROR the size for values of type `str` cannot be known at compilation time fn serialize(val : &'self str) -> Vec { //~ ERROR lifetimes cannot use keyword names vec![1] } diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr index 8128ba22fdeb1..0793dd99b4d12 100644 --- a/src/test/ui/issues/issue-10412.stderr +++ b/src/test/ui/issues/issue-10412.stderr @@ -1,51 +1,60 @@ error: lifetimes cannot use keyword names --> $DIR/issue-10412.rs:1:20 | -LL | trait Serializable<'self, T> { //~ ERROR lifetimes cannot use keyword names +LL | trait Serializable<'self, T> { | ^^^^^ error: lifetimes cannot use keyword names --> $DIR/issue-10412.rs:2:25 | -LL | fn serialize(val : &'self T) -> Vec; //~ ERROR lifetimes cannot use keyword names +LL | fn serialize(val : &'self T) -> Vec; | ^^^^^ error: lifetimes cannot use keyword names --> $DIR/issue-10412.rs:3:38 | -LL | fn deserialize(repr : &[u8]) -> &'self T; //~ ERROR lifetimes cannot use keyword names +LL | fn deserialize(repr : &[u8]) -> &'self T; | ^^^^^ error: lifetimes cannot use keyword names --> $DIR/issue-10412.rs:6:6 | -LL | impl<'self> Serializable for &'self str { //~ ERROR lifetimes cannot use keyword names +LL | impl<'self> Serializable for &'self str { | ^^^^^ error: lifetimes cannot use keyword names --> $DIR/issue-10412.rs:6:36 | -LL | impl<'self> Serializable for &'self str { //~ ERROR lifetimes cannot use keyword names +LL | impl<'self> Serializable for &'self str { | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:9:25 + --> $DIR/issue-10412.rs:10:25 | -LL | fn serialize(val : &'self str) -> Vec { //~ ERROR lifetimes cannot use keyword names +LL | fn serialize(val : &'self str) -> Vec { | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:12:37 + --> $DIR/issue-10412.rs:13:37 | -LL | fn deserialize(repr: &[u8]) -> &'self str { //~ ERROR lifetimes cannot use keyword names +LL | fn deserialize(repr: &[u8]) -> &'self str { | ^^^^^ -error[E0106]: missing lifetime specifier +error[E0726]: implicit elided lifetime not allowed here --> $DIR/issue-10412.rs:6:13 | -LL | impl<'self> Serializable for &'self str { //~ ERROR lifetimes cannot use keyword names - | ^^^^^^^^^^^^^^^^^ expected lifetime parameter +LL | impl<'self> Serializable for &'self str { + | ^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Serializable<'_, str>` -error: aborting due to 8 previous errors +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/issue-10412.rs:6:13 + | +LL | impl<'self> Serializable for &'self str { + | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit + +error: aborting due to 9 previous errors -For more information about this error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-10465.stderr b/src/test/ui/issues/issue-10465.stderr index 41613cfa01058..6efbd8e40ef64 100644 --- a/src/test/ui/issues/issue-10465.stderr +++ b/src/test/ui/issues/issue-10465.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `foo` found for type `&b::B` in the current scope --> $DIR/issue-10465.rs:17:15 | -LL | b.foo(); //~ ERROR: no method named `foo` found +LL | b.foo(); | ^^^ | = help: items from traits can only be used if the trait is in scope diff --git a/src/test/ui/issues/issue-10536.rs b/src/test/ui/issues/issue-10536.rs index 95c8c2b0585b6..ceb44ecf7f583 100644 --- a/src/test/ui/issues/issue-10536.rs +++ b/src/test/ui/issues/issue-10536.rs @@ -12,7 +12,7 @@ pub fn main() { foo!(); assert!({one! two()}); - //~^ ERROR macros that expand to items must either be surrounded with braces or followed by a + //~^ ERROR macros that expand to items //~| ERROR cannot find macro `one!` in this scope //~| ERROR mismatched types diff --git a/src/test/ui/issues/issue-10536.stderr b/src/test/ui/issues/issue-10536.stderr index d5caf777cd45e..584cdf43a8f4b 100644 --- a/src/test/ui/issues/issue-10536.stderr +++ b/src/test/ui/issues/issue-10536.stderr @@ -1,8 +1,16 @@ -error: macros that expand to items must either be surrounded with braces or followed by a semicolon +error: macros that expand to items must be delimited with braces or followed by a semicolon --> $DIR/issue-10536.rs:14:22 | LL | assert!({one! two()}); | ^^ +help: change the delimiters to curly braces + | +LL | assert!({one! two {}}); + | ^^ +help: add a semicolon + | +LL | assert!({one! two();}); + | ^ error: expected `(` or `{`, found `}` --> $DIR/issue-10536.rs:21:22 diff --git a/src/test/ui/issues/issue-10545.stderr b/src/test/ui/issues/issue-10545.stderr index e486a17bda940..59d4fedcd2b40 100644 --- a/src/test/ui/issues/issue-10545.stderr +++ b/src/test/ui/issues/issue-10545.stderr @@ -1,7 +1,7 @@ error[E0603]: struct `S` is private --> $DIR/issue-10545.rs:6:14 | -LL | fn foo(_: a::S) { //~ ERROR: struct `S` is private +LL | fn foo(_: a::S) { | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-10902.rs b/src/test/ui/issues/issue-10902.rs index 672386bc8a6c2..5e7f8ed7fd5d2 100644 --- a/src/test/ui/issues/issue-10902.rs +++ b/src/test/ui/issues/issue-10902.rs @@ -4,16 +4,16 @@ pub mod two_tuple { pub trait T { fn dummy(&self) { } } - pub struct P<'a>(&'a (T + 'a), &'a (T + 'a)); - pub fn f<'a>(car: &'a T, cdr: &'a T) -> P<'a> { + pub struct P<'a>(&'a (dyn T + 'a), &'a (dyn T + 'a)); + pub fn f<'a>(car: &'a dyn T, cdr: &'a dyn T) -> P<'a> { P(car, cdr) } } pub mod two_fields { pub trait T { fn dummy(&self) { } } - pub struct P<'a> { car: &'a (T + 'a), cdr: &'a (T + 'a) } - pub fn f<'a>(car: &'a T, cdr: &'a T) -> P<'a> { + pub struct P<'a> { car: &'a (dyn T + 'a), cdr: &'a (dyn T + 'a) } + pub fn f<'a>(car: &'a dyn T, cdr: &'a dyn T) -> P<'a> { P{ car: car, cdr: cdr } } } diff --git a/src/test/ui/issues/issue-10969.stderr b/src/test/ui/issues/issue-10969.stderr index 0eaed9464b41a..9e28a665e30fb 100644 --- a/src/test/ui/issues/issue-10969.stderr +++ b/src/test/ui/issues/issue-10969.stderr @@ -3,7 +3,7 @@ error[E0618]: expected function, found `i32` | LL | fn func(i: i32) { | - `i32` defined here -LL | i(); //~ERROR expected function, found `i32` +LL | i(); | ^-- | | | call expression requires function @@ -13,7 +13,7 @@ error[E0618]: expected function, found `i32` | LL | let i = 0i32; | - `i32` defined here -LL | i(); //~ERROR expected function, found `i32` +LL | i(); | ^-- | | | call expression requires function diff --git a/src/test/ui/issues/issue-10991.stderr b/src/test/ui/issues/issue-10991.stderr index c91b15cb3fb33..f12539b47cf44 100644 --- a/src/test/ui/issues/issue-10991.stderr +++ b/src/test/ui/issues/issue-10991.stderr @@ -1,7 +1,7 @@ error[E0605]: non-primitive cast: `()` as `usize` --> $DIR/issue-10991.rs:3:14 | -LL | let _t = nil as usize; //~ ERROR: non-primitive cast: `()` as `usize` +LL | let _t = nil as usize; | ^^^^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait diff --git a/src/test/ui/issues/issue-11004.stderr b/src/test/ui/issues/issue-11004.stderr index a5c63e9c31d41..b5831e42e399f 100644 --- a/src/test/ui/issues/issue-11004.stderr +++ b/src/test/ui/issues/issue-11004.stderr @@ -1,7 +1,7 @@ error[E0609]: no field `x` on type `*mut A` --> $DIR/issue-11004.rs:7:21 | -LL | let x : i32 = n.x; //~ no field `x` on type `*mut A` +LL | let x : i32 = n.x; | --^ | | | help: `n` is a raw pointer; try dereferencing it: `(*n).x` @@ -9,7 +9,7 @@ LL | let x : i32 = n.x; //~ no field `x` on type `*mut A` error[E0609]: no field `y` on type `*mut A` --> $DIR/issue-11004.rs:8:21 | -LL | let y : f64 = n.y; //~ no field `y` on type `*mut A` +LL | let y : f64 = n.y; | --^ | | | help: `n` is a raw pointer; try dereferencing it: `(*n).y` diff --git a/src/test/ui/issues/issue-11192.nll.stderr b/src/test/ui/issues/issue-11192.nll.stderr deleted file mode 100644 index 2a9d913171c3e..0000000000000 --- a/src/test/ui/issues/issue-11192.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as mutable - --> $DIR/issue-11192.rs:20:10 - | -LL | let mut test = |foo: &Foo| { - | ----------- mutable borrow occurs here -LL | println!("access {}", foo.x); -LL | ptr = box Foo { x: ptr.x + 1 }; - | --- first borrow occurs due to use of `ptr` in closure -... -LL | test(&*ptr); - | ---- ^^^^^ immutable borrow occurs here - | | - | mutable borrow later used by call - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/issues/issue-11192.stderr b/src/test/ui/issues/issue-11192.stderr index 37ae73685b4f2..dfe7b3f6b5f9c 100644 --- a/src/test/ui/issues/issue-11192.stderr +++ b/src/test/ui/issues/issue-11192.stderr @@ -1,17 +1,16 @@ -error[E0502]: cannot borrow `*ptr` as immutable because `ptr` is also borrowed as mutable - --> $DIR/issue-11192.rs:20:11 +error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as mutable + --> $DIR/issue-11192.rs:20:10 | LL | let mut test = |foo: &Foo| { | ----------- mutable borrow occurs here LL | println!("access {}", foo.x); LL | ptr = box Foo { x: ptr.x + 1 }; - | --- previous borrow occurs due to use of `ptr` in closure + | --- first borrow occurs due to use of `ptr` in closure ... LL | test(&*ptr); - | ^^^^ immutable borrow occurs here -LL | //~^ ERROR: cannot borrow `*ptr` as immutable -LL | } - | - mutable borrow ends here + | ---- ^^^^^ immutable borrow occurs here + | | + | mutable borrow later used by call error: aborting due to previous error diff --git a/src/test/ui/issues/issue-11319.stderr b/src/test/ui/issues/issue-11319.stderr index 10db477b8ca7b..6179f9d3fe00f 100644 --- a/src/test/ui/issues/issue-11319.stderr +++ b/src/test/ui/issues/issue-11319.stderr @@ -2,13 +2,13 @@ error[E0308]: match arms have incompatible types --> $DIR/issue-11319.rs:8:20 | LL | / match Some(10) { -LL | | //~^ NOTE `match` arms have incompatible types +LL | | LL | | Some(5) => false, | | ----- this is found to be of type `bool` -LL | | //~^ NOTE this is found to be of type `bool` +LL | | LL | | Some(2) => true, | | ---- this is found to be of type `bool` -LL | | //~^ NOTE this is found to be of type `bool` +LL | | LL | | None => (), | | ^^ expected bool, found () ... | diff --git a/src/test/ui/issues/issue-11374.rs b/src/test/ui/issues/issue-11374.rs index f00da0acf8124..7519ba2826e7a 100644 --- a/src/test/ui/issues/issue-11374.rs +++ b/src/test/ui/issues/issue-11374.rs @@ -2,11 +2,11 @@ use std::io::{self, Read}; use std::vec; pub struct Container<'a> { - reader: &'a mut Read + reader: &'a mut dyn Read } impl<'a> Container<'a> { - pub fn wrap<'s>(reader: &'s mut io::Read) -> Container<'s> { + pub fn wrap<'s>(reader: &'s mut dyn io::Read) -> Container<'s> { Container { reader: reader } } @@ -17,7 +17,7 @@ impl<'a> Container<'a> { pub fn for_stdin<'a>() -> Container<'a> { let mut r = io::stdin(); - Container::wrap(&mut r as &mut io::Read) + Container::wrap(&mut r as &mut dyn io::Read) } fn main() { diff --git a/src/test/ui/issues/issue-11374.stderr b/src/test/ui/issues/issue-11374.stderr index 6cd552f86e158..8d7e6c81f4fce 100644 --- a/src/test/ui/issues/issue-11374.stderr +++ b/src/test/ui/issues/issue-11374.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-11374.rs:26:15 | -LL | c.read_to(v); //~ ERROR E0308 +LL | c.read_to(v); | ^ | | | expected &mut [u8], found struct `std::vec::Vec` diff --git a/src/test/ui/issues/issue-11493.ast.stderr b/src/test/ui/issues/issue-11493.ast.stderr deleted file mode 100644 index a5f8aefd194b0..0000000000000 --- a/src/test/ui/issues/issue-11493.ast.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0597]: borrowed value does not live long enough (Ast) - --> $DIR/issue-11493.rs:10:35 - | -LL | let y = x.as_ref().unwrap_or(&id(5)); - | ^^^^^ - temporary value dropped here while still borrowed - | | - | temporary value does not live long enough -... -LL | } - | - temporary value needs to live until here - | - = note: consider using a `let` binding to increase its lifetime - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issues/issue-11493.mir.stderr b/src/test/ui/issues/issue-11493.mir.stderr deleted file mode 100644 index a5f8aefd194b0..0000000000000 --- a/src/test/ui/issues/issue-11493.mir.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0597]: borrowed value does not live long enough (Ast) - --> $DIR/issue-11493.rs:10:35 - | -LL | let y = x.as_ref().unwrap_or(&id(5)); - | ^^^^^ - temporary value dropped here while still borrowed - | | - | temporary value does not live long enough -... -LL | } - | - temporary value needs to live until here - | - = note: consider using a `let` binding to increase its lifetime - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issues/issue-11493.rs b/src/test/ui/issues/issue-11493.rs index 4fdc32b42c2e9..b28c173b19b71 100644 --- a/src/test/ui/issues/issue-11493.rs +++ b/src/test/ui/issues/issue-11493.rs @@ -1,14 +1,7 @@ -// This file must never have a trailing newline -// -// revisions: ast mir -// compile-flags: -Z borrowck=compare - fn id(x: T) -> T { x } fn main() { let x = Some(3); - let y = x.as_ref().unwrap_or(&id(5)); - //[ast]~^ ERROR borrowed value does not live long enough (Ast) - //[mir]~^^ ERROR borrowed value does not live long enough (Ast) - // This actually passes in mir + let y = x.as_ref().unwrap_or(&id(5)); //~ ERROR + &y; } diff --git a/src/test/ui/issues/issue-11493.stderr b/src/test/ui/issues/issue-11493.stderr new file mode 100644 index 0000000000000..f954d64ac5bf4 --- /dev/null +++ b/src/test/ui/issues/issue-11493.stderr @@ -0,0 +1,15 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-11493.rs:5:35 + | +LL | let y = x.as_ref().unwrap_or(&id(5)); + | ^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use +LL | &y; + | -- borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/issues/issue-11515.rs b/src/test/ui/issues/issue-11515.rs index 7eab2a26178af..a7671b9282a99 100644 --- a/src/test/ui/issues/issue-11515.rs +++ b/src/test/ui/issues/issue-11515.rs @@ -1,10 +1,10 @@ #![feature(box_syntax)] struct Test { - func: Box + func: Box } fn main() { - let closure: Box = Box::new(|| ()); + let closure: Box = Box::new(|| ()); let test = box Test { func: closure }; //~ ERROR mismatched types } diff --git a/src/test/ui/issues/issue-11515.stderr b/src/test/ui/issues/issue-11515.stderr index d7d51a32414cc..0ab0c7dba0b76 100644 --- a/src/test/ui/issues/issue-11515.stderr +++ b/src/test/ui/issues/issue-11515.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-11515.rs:9:33 | -LL | let test = box Test { func: closure }; //~ ERROR mismatched types +LL | let test = box Test { func: closure }; | ^^^^^^^ expected trait `std::ops::FnMut`, found trait `std::ops::Fn` | = note: expected type `std::boxed::Box<(dyn std::ops::FnMut() + 'static)>` diff --git a/src/test/ui/issues/issue-11612.rs b/src/test/ui/issues/issue-11612.rs index 4d6f4656d589d..fd4fb2443cbe7 100644 --- a/src/test/ui/issues/issue-11612.rs +++ b/src/test/ui/issues/issue-11612.rs @@ -14,11 +14,11 @@ struct B<'a, T:'a> { impl<'a, T> A for B<'a, T> {} -fn foo(_: &A) {} +fn foo(_: &dyn A) {} fn bar(b: &B) { foo(b); // Coercion should work - foo(b as &A); // Explicit cast should work as well + foo(b as &dyn A); // Explicit cast should work as well } fn main() {} diff --git a/src/test/ui/issues/issue-11681.nll.stderr b/src/test/ui/issues/issue-11681.nll.stderr deleted file mode 100644 index a3c71ffe95a8a..0000000000000 --- a/src/test/ui/issues/issue-11681.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0515]: cannot return value referencing temporary value - --> $DIR/issue-11681.rs:13:10 - | -LL | let testValue = &Test; //~ ERROR borrowed value does not live long enough - | ---- temporary value created here -LL | return testValue; - | ^^^^^^^^^ returns a value referencing data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-11681.rs b/src/test/ui/issues/issue-11681.rs index 8294ca6b22e2e..6d8810d805200 100644 --- a/src/test/ui/issues/issue-11681.rs +++ b/src/test/ui/issues/issue-11681.rs @@ -9,8 +9,8 @@ impl Drop for Test { } fn createTest<'a>() -> &'a Test { - let testValue = &Test; //~ ERROR borrowed value does not live long enough - return testValue; + let testValue = &Test; + return testValue; //~ ERROR cannot return value referencing temporary value } diff --git a/src/test/ui/issues/issue-11681.stderr b/src/test/ui/issues/issue-11681.stderr index 210c6dc5a00b6..f2f9307667194 100644 --- a/src/test/ui/issues/issue-11681.stderr +++ b/src/test/ui/issues/issue-11681.stderr @@ -1,18 +1,11 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/issue-11681.rs:12:20 +error[E0515]: cannot return value referencing temporary value + --> $DIR/issue-11681.rs:13:10 | -LL | let testValue = &Test; //~ ERROR borrowed value does not live long enough - | ^^^^ temporary value does not live long enough +LL | let testValue = &Test; + | ---- temporary value created here LL | return testValue; -LL | } - | - temporary value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 11:15... - --> $DIR/issue-11681.rs:11:15 - | -LL | fn createTest<'a>() -> &'a Test { - | ^^ + | ^^^^^^^^^ returns a value referencing data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-11692-1.stderr b/src/test/ui/issues/issue-11692-1.stderr index 57a6a999544cf..bfd1647e8bee4 100644 --- a/src/test/ui/issues/issue-11692-1.stderr +++ b/src/test/ui/issues/issue-11692-1.stderr @@ -1,7 +1,7 @@ error: cannot find macro `testo!` in this scope --> $DIR/issue-11692-1.rs:2:12 | -LL | print!(testo!()); //~ ERROR cannot find macro `testo!` in this scope +LL | print!(testo!()); | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-11692-2.stderr b/src/test/ui/issues/issue-11692-2.stderr index 5d4467080f149..740c3555e52f0 100644 --- a/src/test/ui/issues/issue-11692-2.stderr +++ b/src/test/ui/issues/issue-11692-2.stderr @@ -1,7 +1,7 @@ error: cannot find macro `test!` in this scope --> $DIR/issue-11692-2.rs:2:13 | -LL | concat!(test!()); //~ ERROR cannot find macro `test!` in this scope +LL | concat!(test!()); | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-11740.rs b/src/test/ui/issues/issue-11740.rs index 47bdf085ee5db..dc10a205f2418 100644 --- a/src/test/ui/issues/issue-11740.rs +++ b/src/test/ui/issues/issue-11740.rs @@ -1,6 +1,5 @@ -// compile-pass -// skip-codegen -#![allow(warnings)] +// check-pass + struct Attr { name: String, value: String, @@ -21,7 +20,6 @@ impl Element { } } - fn main() { let element = Element { attrs: Vec::new() }; let _ = unsafe { element.get_attr("foo") }; diff --git a/src/test/ui/issues/issue-11844.stderr b/src/test/ui/issues/issue-11844.stderr index 683ad48ff52c0..1c4321f1b4ab0 100644 --- a/src/test/ui/issues/issue-11844.stderr +++ b/src/test/ui/issues/issue-11844.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | match a { | - this match expression has type `std::option::Option>` -LL | Ok(a) => //~ ERROR: mismatched types +LL | Ok(a) => | ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | = note: expected type `std::option::Option>` diff --git a/src/test/ui/issues/issue-11873.nll.stderr b/src/test/ui/issues/issue-11873.nll.stderr deleted file mode 100644 index e5abf07420233..0000000000000 --- a/src/test/ui/issues/issue-11873.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0505]: cannot move out of `v` because it is borrowed - --> $DIR/issue-11873.rs:4:14 - | -LL | let mut f = || v.push(2); - | -- - borrow occurs due to use in closure - | | - | borrow of `v` occurs here -LL | let _w = v; //~ ERROR: cannot move out of `v` - | ^ move out of `v` occurs here -LL | -LL | f(); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/issues/issue-11873.stderr b/src/test/ui/issues/issue-11873.stderr index 1e44754c707d7..4475bdf147402 100644 --- a/src/test/ui/issues/issue-11873.stderr +++ b/src/test/ui/issues/issue-11873.stderr @@ -1,10 +1,15 @@ error[E0505]: cannot move out of `v` because it is borrowed - --> $DIR/issue-11873.rs:4:9 + --> $DIR/issue-11873.rs:4:14 | LL | let mut f = || v.push(2); - | -- borrow of `v` occurs here -LL | let _w = v; //~ ERROR: cannot move out of `v` - | ^^ move out of `v` occurs here + | -- - borrow occurs due to use in closure + | | + | borrow of `v` occurs here +LL | let _w = v; + | ^ move out of `v` occurs here +LL | +LL | f(); + | - borrow later used here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-12028.stderr b/src/test/ui/issues/issue-12028.stderr index 7b0850581cecc..64694c7a8d0b6 100644 --- a/src/test/ui/issues/issue-12028.stderr +++ b/src/test/ui/issues/issue-12028.stderr @@ -1,7 +1,7 @@ error[E0284]: type annotations required: cannot resolve `<_ as StreamHasher>::S == ::S` --> $DIR/issue-12028.rs:29:14 | -LL | self.input_stream(&mut stream); //~ ERROR type annotations required +LL | self.input_stream(&mut stream); | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-12041.nll.stderr b/src/test/ui/issues/issue-12041.nll.stderr deleted file mode 100644 index d95cc89ce99ad..0000000000000 --- a/src/test/ui/issues/issue-12041.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0382]: use of moved value: `tx` - --> $DIR/issue-12041.rs:8:22 - | -LL | let tx = tx; - | ^^ value moved here, in previous iteration of loop - | - = note: move occurs because `tx` has type `std::sync::mpsc::Sender`, which does not implement the `Copy` trait - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/issues/issue-12041.stderr b/src/test/ui/issues/issue-12041.stderr index 48544c073efcf..d95cc89ce99ad 100644 --- a/src/test/ui/issues/issue-12041.stderr +++ b/src/test/ui/issues/issue-12041.stderr @@ -1,8 +1,8 @@ error[E0382]: use of moved value: `tx` - --> $DIR/issue-12041.rs:8:17 + --> $DIR/issue-12041.rs:8:22 | LL | let tx = tx; - | ^^ value moved here in previous iteration of loop + | ^^ value moved here, in previous iteration of loop | = note: move occurs because `tx` has type `std::sync::mpsc::Sender`, which does not implement the `Copy` trait diff --git a/src/test/ui/issues/issue-12187-1.rs b/src/test/ui/issues/issue-12187-1.rs index 37ff468e03205..86128ed94bd71 100644 --- a/src/test/ui/issues/issue-12187-1.rs +++ b/src/test/ui/issues/issue-12187-1.rs @@ -4,5 +4,5 @@ fn new() -> &'static T { fn main() { let &v = new(); - //~^ ERROR type annotations needed [E0282] + //~^ ERROR type annotations needed } diff --git a/src/test/ui/issues/issue-12187-1.stderr b/src/test/ui/issues/issue-12187-1.stderr index f8df4f82e7efd..3ea15439df25a 100644 --- a/src/test/ui/issues/issue-12187-1.stderr +++ b/src/test/ui/issues/issue-12187-1.stderr @@ -1,11 +1,11 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `&T` --> $DIR/issue-12187-1.rs:6:10 | LL | let &v = new(); | -^ | || | |cannot infer type - | consider giving the pattern a type + | consider giving this pattern the explicit type `&T`, with the type parameters specified error: aborting due to previous error diff --git a/src/test/ui/issues/issue-12187-2.rs b/src/test/ui/issues/issue-12187-2.rs index a1cdb84977907..080a6206be76d 100644 --- a/src/test/ui/issues/issue-12187-2.rs +++ b/src/test/ui/issues/issue-12187-2.rs @@ -4,5 +4,5 @@ fn new<'r, T>() -> &'r T { fn main() { let &v = new(); - //~^ ERROR type annotations needed [E0282] + //~^ ERROR type annotations needed } diff --git a/src/test/ui/issues/issue-12187-2.stderr b/src/test/ui/issues/issue-12187-2.stderr index c40ae0461ec03..a5e65c65beb2f 100644 --- a/src/test/ui/issues/issue-12187-2.stderr +++ b/src/test/ui/issues/issue-12187-2.stderr @@ -1,11 +1,11 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `&T` --> $DIR/issue-12187-2.rs:6:10 | LL | let &v = new(); | -^ | || | |cannot infer type - | consider giving the pattern a type + | consider giving this pattern the explicit type `&T`, with the type parameters specified error: aborting due to previous error diff --git a/src/test/ui/issues/issue-12369.stderr b/src/test/ui/issues/issue-12369.stderr index 6906c7b7920ca..fec9078dc4090 100644 --- a/src/test/ui/issues/issue-12369.stderr +++ b/src/test/ui/issues/issue-12369.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/issue-12369.rs:10:9 | -LL | &[10,a, ref rest..] => 10 //~ ERROR: unreachable pattern +LL | &[10,a, ref rest..] => 10 | ^^^^^^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/issues/issue-12470.nll.stderr b/src/test/ui/issues/issue-12470.nll.stderr deleted file mode 100644 index 27878e7718bef..0000000000000 --- a/src/test/ui/issues/issue-12470.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0515]: cannot return value referencing local data `*b` - --> $DIR/issue-12470.rs:29:5 - | -LL | let bb: &B = &*b; //~ ERROR does not live long enough - | --- `*b` is borrowed here -LL | make_a(bb) - | ^^^^^^^^^^ returns a value referencing data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-12470.rs b/src/test/ui/issues/issue-12470.rs index acf1b764fd92c..0ade359923a0e 100644 --- a/src/test/ui/issues/issue-12470.rs +++ b/src/test/ui/issues/issue-12470.rs @@ -16,17 +16,17 @@ impl X for B { } struct A<'a> { - p: &'a (X+'a) + p: &'a (dyn X + 'a) } -fn make_a<'a>(p: &'a X) -> A<'a> { +fn make_a<'a>(p: &'a dyn X) -> A<'a> { A { p: p } } fn make_make_a<'a>() -> A<'a> { let b: Box = box B {i:1}; - let bb: &B = &*b; //~ ERROR does not live long enough - make_a(bb) + let bb: &B = &*b; + make_a(bb) //~ ERROR cannot return value referencing local data `*b` } fn main() { diff --git a/src/test/ui/issues/issue-12470.stderr b/src/test/ui/issues/issue-12470.stderr index 59056aaca9022..c97e59195ed05 100644 --- a/src/test/ui/issues/issue-12470.stderr +++ b/src/test/ui/issues/issue-12470.stderr @@ -1,18 +1,11 @@ -error[E0597]: `*b` does not live long enough - --> $DIR/issue-12470.rs:28:19 +error[E0515]: cannot return value referencing local data `*b` + --> $DIR/issue-12470.rs:29:5 | -LL | let bb: &B = &*b; //~ ERROR does not live long enough - | ^^ borrowed value does not live long enough +LL | let bb: &B = &*b; + | --- `*b` is borrowed here LL | make_a(bb) -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 26:16... - --> $DIR/issue-12470.rs:26:16 - | -LL | fn make_make_a<'a>() -> A<'a> { - | ^^ + | ^^^^^^^^^^ returns a value referencing data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-12552.stderr b/src/test/ui/issues/issue-12552.stderr index 768d11bf899a1..6eaac1b35776f 100644 --- a/src/test/ui/issues/issue-12552.stderr +++ b/src/test/ui/issues/issue-12552.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | match t { | - this match expression has type `std::result::Result<_, {integer}>` -LL | Some(k) => match k { //~ ERROR mismatched types +LL | Some(k) => match k { | ^^^^^^^ expected enum `std::result::Result`, found enum `std::option::Option` | = note: expected type `std::result::Result<_, {integer}>` @@ -12,7 +12,7 @@ LL | Some(k) => match k { //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/issue-12552.rs:9:5 | -LL | None => () //~ ERROR mismatched types +LL | None => () | ^^^^ expected enum `std::result::Result`, found enum `std::option::Option` | = note: expected type `std::result::Result<_, {integer}>` diff --git a/src/test/ui/issues/issue-12567.nll.stderr b/src/test/ui/issues/issue-12567.nll.stderr deleted file mode 100644 index 17388df91d1f3..0000000000000 --- a/src/test/ui/issues/issue-12567.nll.stderr +++ /dev/null @@ -1,45 +0,0 @@ -error[E0508]: cannot move out of type `[T]`, a non-copy slice - --> $DIR/issue-12567.rs:4:11 - | -LL | match (l1, l2) { - | ^^^^^^^^ cannot move out of here -LL | (&[], &[]) => println!("both empty"), -LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) - | -- data moved here -... -LL | (&[hd1, ..], &[hd2, ..]) - | --- ...and here - | -note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/issue-12567.rs:6:17 - | -LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) - | ^^ -... -LL | (&[hd1, ..], &[hd2, ..]) - | ^^^ - -error[E0508]: cannot move out of type `[T]`, a non-copy slice - --> $DIR/issue-12567.rs:4:11 - | -LL | match (l1, l2) { - | ^^^^^^^^ cannot move out of here -LL | (&[], &[]) => println!("both empty"), -LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) - | -- data moved here -... -LL | (&[hd1, ..], &[hd2, ..]) - | --- ...and here - | -note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/issue-12567.rs:6:17 - | -LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) - | ^^ -... -LL | (&[hd1, ..], &[hd2, ..]) - | ^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/issues/issue-12567.rs b/src/test/ui/issues/issue-12567.rs index 1e1debe31ce6d..643d9a2fc69e9 100644 --- a/src/test/ui/issues/issue-12567.rs +++ b/src/test/ui/issues/issue-12567.rs @@ -2,15 +2,13 @@ fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) { match (l1, l2) { + //~^ ERROR: cannot move out of type `[T]`, a non-copy slice + //~| ERROR: cannot move out of type `[T]`, a non-copy slice (&[], &[]) => println!("both empty"), (&[], &[hd, ..]) | (&[hd, ..], &[]) => println!("one empty"), - //~^^ ERROR: cannot move out of type `[T]`, a non-copy slice - //~^^^ ERROR: cannot move out of type `[T]`, a non-copy slice (&[hd1, ..], &[hd2, ..]) => println!("both nonempty"), - //~^^ ERROR: cannot move out of type `[T]`, a non-copy slice - //~^^^ ERROR: cannot move out of type `[T]`, a non-copy slice } } diff --git a/src/test/ui/issues/issue-12567.stderr b/src/test/ui/issues/issue-12567.stderr index 15f723f1cee0f..1de29dc8c6108 100644 --- a/src/test/ui/issues/issue-12567.stderr +++ b/src/test/ui/issues/issue-12567.stderr @@ -1,39 +1,45 @@ error[E0508]: cannot move out of type `[T]`, a non-copy slice - --> $DIR/issue-12567.rs:6:16 + --> $DIR/issue-12567.rs:4:11 | +LL | match (l1, l2) { + | ^^^^^^^^ cannot move out of here +... LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) - | ^--^^^^^ - | || - | |hint: to prevent move, use `ref hd` or `ref mut hd` - | cannot move out of here - -error[E0508]: cannot move out of type `[T]`, a non-copy slice - --> $DIR/issue-12567.rs:6:30 + | -- data moved here +LL | => println!("one empty"), +LL | (&[hd1, ..], &[hd2, ..]) + | --- ...and here + | +note: move occurs because these variables have types that don't implement the `Copy` trait + --> $DIR/issue-12567.rs:8:17 | LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) - | ^--^^^^^ - | || - | |hint: to prevent move, use `ref hd` or `ref mut hd` - | cannot move out of here + | ^^ +LL | => println!("one empty"), +LL | (&[hd1, ..], &[hd2, ..]) + | ^^^ error[E0508]: cannot move out of type `[T]`, a non-copy slice - --> $DIR/issue-12567.rs:10:11 + --> $DIR/issue-12567.rs:4:11 | +LL | match (l1, l2) { + | ^^^^^^^^ cannot move out of here +... +LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) + | -- data moved here +LL | => println!("one empty"), LL | (&[hd1, ..], &[hd2, ..]) - | ^---^^^^^ - | || - | |hint: to prevent move, use `ref hd1` or `ref mut hd1` - | cannot move out of here - -error[E0508]: cannot move out of type `[T]`, a non-copy slice - --> $DIR/issue-12567.rs:10:23 + | --- ...and here | +note: move occurs because these variables have types that don't implement the `Copy` trait + --> $DIR/issue-12567.rs:8:17 + | +LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) + | ^^ +LL | => println!("one empty"), LL | (&[hd1, ..], &[hd2, ..]) - | ^---^^^^^ - | || - | |hint: to prevent move, use `ref hd2` or `ref mut hd2` - | cannot move out of here + | ^^^ -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/issues/issue-12863.stderr b/src/test/ui/issues/issue-12863.stderr index 3f1a6bf598de7..bec70a5fb95a2 100644 --- a/src/test/ui/issues/issue-12863.stderr +++ b/src/test/ui/issues/issue-12863.stderr @@ -1,7 +1,7 @@ error[E0532]: expected unit struct/variant or constant, found function `foo::bar` --> $DIR/issue-12863.rs:5:9 | -LL | foo::bar => {} //~ ERROR expected unit struct/variant or constant, found function `foo::bar` +LL | foo::bar => {} | ^^^^^^^^ not a unit struct/variant or constant error: aborting due to previous error diff --git a/src/test/ui/issues/issue-12997-1.stderr b/src/test/ui/issues/issue-12997-1.stderr index 050e753dd1a4c..e036896812ece 100644 --- a/src/test/ui/issues/issue-12997-1.stderr +++ b/src/test/ui/issues/issue-12997-1.stderr @@ -1,13 +1,13 @@ error: functions used as benches must have signature `fn(&mut Bencher) -> impl Termination` --> $DIR/issue-12997-1.rs:6:1 | -LL | fn foo() { } //~ ERROR functions used as benches +LL | fn foo() { } | ^^^^^^^^^^^^ error: functions used as benches must have signature `fn(&mut Bencher) -> impl Termination` --> $DIR/issue-12997-1.rs:9:1 | -LL | fn bar(x: isize, y: isize) { } //~ ERROR functions used as benches +LL | fn bar(x: isize, y: isize) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-13033.rs b/src/test/ui/issues/issue-13033.rs index a6c9e9712c050..e5274eb823d46 100644 --- a/src/test/ui/issues/issue-13033.rs +++ b/src/test/ui/issues/issue-13033.rs @@ -1,11 +1,11 @@ trait Foo { - fn bar(&mut self, other: &mut Foo); + fn bar(&mut self, other: &mut dyn Foo); } struct Baz; impl Foo for Baz { - fn bar(&mut self, other: &Foo) {} + fn bar(&mut self, other: &dyn Foo) {} //~^ ERROR method `bar` has an incompatible type for trait //~| expected type `fn(&mut Baz, &mut dyn Foo)` //~| found type `fn(&mut Baz, &dyn Foo)` diff --git a/src/test/ui/issues/issue-13033.stderr b/src/test/ui/issues/issue-13033.stderr index d1e8eb31c8834..195d0c39b2983 100644 --- a/src/test/ui/issues/issue-13033.stderr +++ b/src/test/ui/issues/issue-13033.stderr @@ -1,18 +1,18 @@ error[E0053]: method `bar` has an incompatible type for trait --> $DIR/issue-13033.rs:8:30 | -LL | fn bar(&mut self, other: &mut Foo); - | -------- type in trait +LL | fn bar(&mut self, other: &mut dyn Foo); + | ------------ type in trait ... -LL | fn bar(&mut self, other: &Foo) {} - | ^^^^ types differ in mutability +LL | fn bar(&mut self, other: &dyn Foo) {} + | ^^^^^^^^ types differ in mutability | = note: expected type `fn(&mut Baz, &mut dyn Foo)` found type `fn(&mut Baz, &dyn Foo)` help: consider change the type to match the mutability in trait | -LL | fn bar(&mut self, other: &mut Foo) {} - | ^^^^^^^^ +LL | fn bar(&mut self, other: &mut dyn Foo) {} + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-13058.nll.stderr b/src/test/ui/issues/issue-13058.nll.stderr new file mode 100644 index 0000000000000..8368978deab1a --- /dev/null +++ b/src/test/ui/issues/issue-13058.nll.stderr @@ -0,0 +1,12 @@ +error[E0621]: explicit lifetime required in the type of `cont` + --> $DIR/issue-13058.rs:14:21 + | +LL | fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool + | -- help: add explicit lifetime `'r` to the type of `cont`: `&'r T` +LL | { +LL | let cont_iter = cont.iter(); + | ^^^^^^^^^^^ lifetime `'r` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/issues/issue-13352.rs b/src/test/ui/issues/issue-13352.rs index c711e3b713f29..e6995be27d20e 100644 --- a/src/test/ui/issues/issue-13352.rs +++ b/src/test/ui/issues/issue-13352.rs @@ -1,6 +1,6 @@ // ignore-cloudabi no std::process -fn foo(_: Box) {} +fn foo(_: Box) {} fn main() { foo(loop { diff --git a/src/test/ui/issues/issue-13359.stderr b/src/test/ui/issues/issue-13359.stderr index 00b7fbd456490..7cfd754f72d8e 100644 --- a/src/test/ui/issues/issue-13359.stderr +++ b/src/test/ui/issues/issue-13359.stderr @@ -3,12 +3,20 @@ error[E0308]: mismatched types | LL | foo(1*(1 as isize)); | ^^^^^^^^^^^^^^ expected i16, found isize +help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit + | +LL | foo((1*(1 as isize)).try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/issue-13359.rs:10:9 | LL | bar(1*(1 as usize)); | ^^^^^^^^^^^^^^ expected u32, found usize +help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit + | +LL | bar((1*(1 as usize)).try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-13404.stderr b/src/test/ui/issues/issue-13404.stderr index 45cddffef710e..1f50debb07b11 100644 --- a/src/test/ui/issues/issue-13404.stderr +++ b/src/test/ui/issues/issue-13404.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `b::f` --> $DIR/issue-13404.rs:2:5 | -LL | use b::f; //~ ERROR: unresolved import `b::f` [E0432] +LL | use b::f; | ^^^^ no `f` in `b` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-13407.stderr b/src/test/ui/issues/issue-13407.stderr index 1f4c7dfb0da02..ddd99e6a3c9a8 100644 --- a/src/test/ui/issues/issue-13407.stderr +++ b/src/test/ui/issues/issue-13407.stderr @@ -21,5 +21,5 @@ LL | A::C = 1; error: aborting due to 3 previous errors -Some errors occurred: E0070, E0308, E0603. +Some errors have detailed explanations: E0070, E0308, E0603. For more information about an error, try `rustc --explain E0070`. diff --git a/src/test/ui/issues/issue-13482-2.stderr b/src/test/ui/issues/issue-13482-2.stderr index 0c036f1d0e68b..ccab95878b524 100644 --- a/src/test/ui/issues/issue-13482-2.stderr +++ b/src/test/ui/issues/issue-13482-2.stderr @@ -1,7 +1,7 @@ error[E0527]: pattern requires 0 elements but array has 2 --> $DIR/issue-13482-2.rs:6:9 | -LL | [] => None, //~ ERROR pattern requires 0 elements but array has 2 +LL | [] => None, | ^^ expected 2 elements error: aborting due to previous error diff --git a/src/test/ui/issues/issue-13482.stderr b/src/test/ui/issues/issue-13482.stderr index 5776dedf0a2cf..3eb05f504c23e 100644 --- a/src/test/ui/issues/issue-13482.stderr +++ b/src/test/ui/issues/issue-13482.stderr @@ -1,7 +1,7 @@ error[E0527]: pattern requires 0 elements but array has 2 --> $DIR/issue-13482.rs:4:5 | -LL | [] => None, //~ ERROR pattern requires 0 elements but array has 2 +LL | [] => None, | ^^ expected 2 elements error: aborting due to previous error diff --git a/src/test/ui/issues/issue-13483.stderr b/src/test/ui/issues/issue-13483.stderr index 1ab67d285c0de..739f061236697 100644 --- a/src/test/ui/issues/issue-13483.stderr +++ b/src/test/ui/issues/issue-13483.stderr @@ -1,13 +1,13 @@ error: missing condition for `if` statemement --> $DIR/issue-13483.rs:3:14 | -LL | } else if { //~ ERROR missing condition +LL | } else if { | ^ expected if condition here error: missing condition for `if` statemement --> $DIR/issue-13483.rs:10:14 | -LL | } else if { //~ ERROR missing condition +LL | } else if { | ^ expected if condition here error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-13497-2.nll.stderr b/src/test/ui/issues/issue-13497-2.nll.stderr deleted file mode 100644 index fb0d606690d04..0000000000000 --- a/src/test/ui/issues/issue-13497-2.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0515]: cannot return value referencing local variable `rawLines` - --> $DIR/issue-13497-2.rs:3:5 - | -LL | rawLines //~ ERROR `rawLines` does not live long enough - | ^------- - | | - | _____`rawLines` is borrowed here - | | -LL | | .iter().map(|l| l.trim()).collect() - | |___________________________________________^ returns a value referencing data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-13497-2.rs b/src/test/ui/issues/issue-13497-2.rs index a39ae4f1cf33b..c82da0f0096ad 100644 --- a/src/test/ui/issues/issue-13497-2.rs +++ b/src/test/ui/issues/issue-13497-2.rs @@ -1,6 +1,6 @@ fn read_lines_borrowed<'a>() -> Vec<&'a str> { let rawLines: Vec = vec!["foo ".to_string(), " bar".to_string()]; - rawLines //~ ERROR `rawLines` does not live long enough + rawLines //~ ERROR cannot return value referencing local variable `rawLines` .iter().map(|l| l.trim()).collect() } diff --git a/src/test/ui/issues/issue-13497-2.stderr b/src/test/ui/issues/issue-13497-2.stderr index c91ab789fe8a8..8ad921027e2e3 100644 --- a/src/test/ui/issues/issue-13497-2.stderr +++ b/src/test/ui/issues/issue-13497-2.stderr @@ -1,18 +1,14 @@ -error[E0597]: `rawLines` does not live long enough +error[E0515]: cannot return value referencing local variable `rawLines` --> $DIR/issue-13497-2.rs:3:5 | -LL | rawLines //~ ERROR `rawLines` does not live long enough - | ^^^^^^^^ borrowed value does not live long enough -LL | .iter().map(|l| l.trim()).collect() -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 1:24... - --> $DIR/issue-13497-2.rs:1:24 - | -LL | fn read_lines_borrowed<'a>() -> Vec<&'a str> { - | ^^ +LL | rawLines + | ^------- + | | + | _____`rawLines` is borrowed here + | | +LL | | .iter().map(|l| l.trim()).collect() + | |___________________________________________^ returns a value referencing data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-13497.stderr b/src/test/ui/issues/issue-13497.stderr index eb053c1003e38..b72f0277052b9 100644 --- a/src/test/ui/issues/issue-13497.stderr +++ b/src/test/ui/issues/issue-13497.stderr @@ -1,7 +1,7 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-13497.rs:2:5 | -LL | &str //~ ERROR missing lifetime specifier +LL | &str | ^ help: consider giving it a 'static lifetime: `&'static` | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from diff --git a/src/test/ui/issues/issue-1362.stderr b/src/test/ui/issues/issue-1362.stderr index dd97e0cf04a99..3f4fdee50fdde 100644 --- a/src/test/ui/issues/issue-1362.stderr +++ b/src/test/ui/issues/issue-1362.stderr @@ -1,8 +1,12 @@ error[E0308]: mismatched types --> $DIR/issue-1362.rs:4:16 | -LL | let x: u32 = 20i32; //~ ERROR mismatched types +LL | let x: u32 = 20i32; | ^^^^^ expected u32, found i32 +help: change the type of the numeric literal from `i32` to `u32` + | +LL | let x: u32 = 20u32; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-13727.stderr b/src/test/ui/issues/issue-13727.stderr index 0c2ce9f8b488e..4d1066516249b 100644 --- a/src/test/ui/issues/issue-13727.stderr +++ b/src/test/ui/issues/issue-13727.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/issue-13727.rs:7:5 | -LL | 512 => print!("0b1111/n"), +LL | 512 => print!("0b1111\n"), | ^^^ | note: lint level defined here diff --git a/src/test/ui/issues/issue-13847.stderr b/src/test/ui/issues/issue-13847.stderr index 9199199d7305a..52b8dc049702a 100644 --- a/src/test/ui/issues/issue-13847.stderr +++ b/src/test/ui/issues/issue-13847.stderr @@ -1,7 +1,7 @@ error[E0609]: no field `is_failure` on type `!` --> $DIR/issue-13847.rs:2:12 | -LL | return.is_failure //~ ERROR no field `is_failure` on type `!` +LL | return.is_failure | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-13853-2.rs b/src/test/ui/issues/issue-13853-2.rs index b58f2bd3b3b7c..27319c98d6e35 100644 --- a/src/test/ui/issues/issue-13853-2.rs +++ b/src/test/ui/issues/issue-13853-2.rs @@ -2,5 +2,5 @@ trait FromStructReader<'a> { } trait ResponseHook { fn get(&self); } -fn foo(res : Box) { res.get } //~ ERROR attempted to take value of method +fn foo(res : Box) { res.get } //~ ERROR attempted to take value of method fn main() {} diff --git a/src/test/ui/issues/issue-13853-2.stderr b/src/test/ui/issues/issue-13853-2.stderr index 3e711243b4e17..ea3b38940cf01 100644 --- a/src/test/ui/issues/issue-13853-2.stderr +++ b/src/test/ui/issues/issue-13853-2.stderr @@ -1,8 +1,8 @@ error[E0615]: attempted to take value of method `get` on type `std::boxed::Box<(dyn ResponseHook + 'static)>` - --> $DIR/issue-13853-2.rs:5:39 + --> $DIR/issue-13853-2.rs:5:43 | -LL | fn foo(res : Box) { res.get } //~ ERROR attempted to take value of method - | ^^^ help: use parentheses to call the method: `get()` +LL | fn foo(res : Box) { res.get } + | ^^^ help: use parentheses to call the method: `get()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-13853.stderr b/src/test/ui/issues/issue-13853.stderr index 6da5da04fb165..9026845b4ed86 100644 --- a/src/test/ui/issues/issue-13853.stderr +++ b/src/test/ui/issues/issue-13853.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn nodes<'a, I: Iterator>(&self) -> I | - expected `I` because of return type ... -LL | self.iter() //~ ERROR mismatched types +LL | self.iter() | ^^^^^^^^^^^ expected type parameter, found struct `std::slice::Iter` | = note: expected type `I` @@ -13,13 +13,13 @@ LL | self.iter() //~ ERROR mismatched types error[E0599]: no method named `iter` found for type `&G` in the current scope --> $DIR/issue-13853.rs:27:23 | -LL | for node in graph.iter() { //~ ERROR no method named `iter` found +LL | for node in graph.iter() { | ^^^^ error[E0308]: mismatched types --> $DIR/issue-13853.rs:37:13 | -LL | iterate(graph); //~ ERROR mismatched types +LL | iterate(graph); | ^^^^^ | | | expected reference, found struct `std::vec::Vec` @@ -30,5 +30,5 @@ LL | iterate(graph); //~ ERROR mismatched types error: aborting due to 3 previous errors -Some errors occurred: E0308, E0599. +Some errors have detailed explanations: E0308, E0599. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-14221.stderr b/src/test/ui/issues/issue-14221.stderr index bf12480a5d374..3e5e25a9f6d1f 100644 --- a/src/test/ui/issues/issue-14221.stderr +++ b/src/test/ui/issues/issue-14221.stderr @@ -7,7 +7,7 @@ LL | A => "A", warning[E0170]: pattern binding `B` is named the same as one of the variants of the type `E` --> $DIR/issue-14221.rs:15:13 | -LL | B => "B", //~ ERROR: unreachable pattern +LL | B => "B", | ^ help: to match on the variant, qualify the path: `E::B` error: unreachable pattern @@ -15,8 +15,8 @@ error: unreachable pattern | LL | A => "A", | - matches any value -LL | //~^ WARN pattern binding `A` is named the same as one of the variants of the type `E` -LL | B => "B", //~ ERROR: unreachable pattern +LL | +LL | B => "B", | ^ unreachable pattern | note: lint level defined here diff --git a/src/test/ui/issues/issue-14285.rs b/src/test/ui/issues/issue-14285.rs index 934d72a67ca19..2ba9ff717739c 100644 --- a/src/test/ui/issues/issue-14285.rs +++ b/src/test/ui/issues/issue-14285.rs @@ -6,9 +6,9 @@ struct A; impl Foo for A {} -struct B<'a>(&'a (Foo+'a)); +struct B<'a>(&'a (dyn Foo + 'a)); -fn foo<'a>(a: &Foo) -> B<'a> { +fn foo<'a>(a: &dyn Foo) -> B<'a> { B(a) //~ ERROR explicit lifetime required in the type of `a` [E0621] } diff --git a/src/test/ui/issues/issue-14285.stderr b/src/test/ui/issues/issue-14285.stderr index e5d0ab0684a0b..5c07066018e83 100644 --- a/src/test/ui/issues/issue-14285.stderr +++ b/src/test/ui/issues/issue-14285.stderr @@ -1,9 +1,9 @@ error[E0621]: explicit lifetime required in the type of `a` --> $DIR/issue-14285.rs:12:5 | -LL | fn foo<'a>(a: &Foo) -> B<'a> { - | ---- help: add explicit lifetime `'a` to the type of `a`: `&'a (dyn Foo + 'a)` -LL | B(a) //~ ERROR explicit lifetime required in the type of `a` [E0621] +LL | fn foo<'a>(a: &dyn Foo) -> B<'a> { + | -------- help: add explicit lifetime `'a` to the type of `a`: `&'a (dyn Foo + 'a)` +LL | B(a) | ^^^^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/issues/issue-14309.stderr b/src/test/ui/issues/issue-14309.stderr index b8d82aadd482f..e0491093a722a 100644 --- a/src/test/ui/issues/issue-14309.stderr +++ b/src/test/ui/issues/issue-14309.stderr @@ -1,7 +1,7 @@ error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout --> $DIR/issue-14309.rs:30:15 | -LL | fn foo(x: A); //~ ERROR type `A` which is not FFI-safe +LL | fn foo(x: A); | ^ | note: lint level defined here @@ -9,7 +9,7 @@ note: lint level defined here | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/issue-14309.rs:4:1 | @@ -21,10 +21,10 @@ LL | | } error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout --> $DIR/issue-14309.rs:31:15 | -LL | fn bar(x: B); //~ ERROR type `A` +LL | fn bar(x: B); | ^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/issue-14309.rs:4:1 | @@ -36,10 +36,10 @@ LL | | } error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout --> $DIR/issue-14309.rs:33:15 | -LL | fn qux(x: A2); //~ ERROR type `A` +LL | fn qux(x: A2); | ^^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/issue-14309.rs:4:1 | @@ -51,10 +51,10 @@ LL | | } error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout --> $DIR/issue-14309.rs:34:16 | -LL | fn quux(x: B2); //~ ERROR type `A` +LL | fn quux(x: B2); | ^^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/issue-14309.rs:4:1 | @@ -66,10 +66,10 @@ LL | | } error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout --> $DIR/issue-14309.rs:36:16 | -LL | fn fred(x: D); //~ ERROR type `A` +LL | fn fred(x: D); | ^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/issue-14309.rs:4:1 | diff --git a/src/test/ui/issues/issue-14366.rs b/src/test/ui/issues/issue-14366.rs index a6298f25d470b..bb338860d8b77 100644 --- a/src/test/ui/issues/issue-14366.rs +++ b/src/test/ui/issues/issue-14366.rs @@ -1,4 +1,4 @@ fn main() { - let _x = "test" as &::std::any::Any; + let _x = "test" as &dyn (::std::any::Any); //~^ ERROR the size for values of type } diff --git a/src/test/ui/issues/issue-14366.stderr b/src/test/ui/issues/issue-14366.stderr index a3588bb8ebe12..542d8a904c4e3 100644 --- a/src/test/ui/issues/issue-14366.stderr +++ b/src/test/ui/issues/issue-14366.stderr @@ -1,7 +1,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/issue-14366.rs:2:14 | -LL | let _x = "test" as &::std::any::Any; +LL | let _x = "test" as &dyn (::std::any::Any); | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` diff --git a/src/test/ui/issues/issue-1448-2.stderr b/src/test/ui/issues/issue-1448-2.stderr index b06a6162712fc..a9fabca50a683 100644 --- a/src/test/ui/issues/issue-1448-2.stderr +++ b/src/test/ui/issues/issue-1448-2.stderr @@ -1,8 +1,12 @@ error[E0308]: mismatched types --> $DIR/issue-1448-2.rs:6:24 | -LL | println!("{}", foo(10i32)); //~ ERROR mismatched types +LL | println!("{}", foo(10i32)); | ^^^^^ expected u32, found i32 +help: change the type of the numeric literal from `i32` to `u32` + | +LL | println!("{}", foo(10u32)); + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-14721.stderr b/src/test/ui/issues/issue-14721.stderr index 8029318419a62..49ebb2976e8ad 100644 --- a/src/test/ui/issues/issue-14721.stderr +++ b/src/test/ui/issues/issue-14721.stderr @@ -1,7 +1,7 @@ error[E0609]: no field `desc` on type `&str` --> $DIR/issue-14721.rs:3:24 | -LL | println!("{}", foo.desc); //~ no field `desc` on type `&str` +LL | println!("{}", foo.desc); | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-1476.stderr b/src/test/ui/issues/issue-1476.stderr index a0c0a8fb1f29e..670bd546335f4 100644 --- a/src/test/ui/issues/issue-1476.stderr +++ b/src/test/ui/issues/issue-1476.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `x` in this scope --> $DIR/issue-1476.rs:2:20 | -LL | println!("{}", x); //~ ERROR cannot find value `x` in this scope +LL | println!("{}", x); | ^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/issues/issue-14772.stderr b/src/test/ui/issues/issue-14772.stderr index a7448ad5b88d5..253fec5e57833 100644 --- a/src/test/ui/issues/issue-14772.stderr +++ b/src/test/ui/issues/issue-14772.stderr @@ -1,7 +1,7 @@ error: only functions may be used as tests --> $DIR/issue-14772.rs:4:1 | -LL | mod foo {} //~ ERROR only functions may be used as tests +LL | mod foo {} | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-14845.stderr b/src/test/ui/issues/issue-14845.stderr index 94e7ac74ff0ce..2fa9fbaa887bc 100644 --- a/src/test/ui/issues/issue-14845.stderr +++ b/src/test/ui/issues/issue-14845.stderr @@ -1,13 +1,13 @@ error[E0606]: casting `&[u8; 1]` as `*mut u8` is invalid --> $DIR/issue-14845.rs:7:14 | -LL | let _f = &x.a as *mut u8; //~ ERROR casting +LL | let _f = &x.a as *mut u8; | ^^^^^^^^^^^^^^^ error[E0606]: casting `&[u8; 1]` as `*mut u8` is invalid --> $DIR/issue-14845.rs:10:14 | -LL | let _v = &local as *mut u8; //~ ERROR casting +LL | let _v = &local as *mut u8; | ^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-14901.rs b/src/test/ui/issues/issue-14901.rs index 61b2b64ddf0c1..9b89c1631df15 100644 --- a/src/test/ui/issues/issue-14901.rs +++ b/src/test/ui/issues/issue-14901.rs @@ -2,7 +2,7 @@ pub trait Reader {} enum Wrapper<'a> { - WrapReader(&'a (Reader + 'a)) + WrapReader(&'a (dyn Reader + 'a)) } trait Wrap<'a> { @@ -11,7 +11,7 @@ trait Wrap<'a> { impl<'a, R: Reader> Wrap<'a> for &'a mut R { fn wrap(self) -> Wrapper<'a> { - Wrapper::WrapReader(self as &'a mut Reader) + Wrapper::WrapReader(self as &'a mut dyn Reader) } } diff --git a/src/test/ui/issues/issue-14915.stderr b/src/test/ui/issues/issue-14915.stderr index 411d7a3455238..e8de44320da9c 100644 --- a/src/test/ui/issues/issue-14915.stderr +++ b/src/test/ui/issues/issue-14915.stderr @@ -1,8 +1,10 @@ error[E0369]: binary operation `+` cannot be applied to type `std::boxed::Box` - --> $DIR/issue-14915.rs:6:20 + --> $DIR/issue-14915.rs:6:22 | LL | println!("{}", x + 1); - | ^^^^^ + | - ^ - {integer} + | | + | std::boxed::Box | = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box` diff --git a/src/test/ui/issues/issue-14959.rs b/src/test/ui/issues/issue-14959.rs index 78ae21e2837af..60daaafbcc8bd 100644 --- a/src/test/ui/issues/issue-14959.rs +++ b/src/test/ui/issues/issue-14959.rs @@ -26,20 +26,20 @@ impl Alloy { } } -impl<'b> Fn<(&'b mut (Response+'b),)> for SendFile { - extern "rust-call" fn call(&self, (_res,): (&'b mut (Response+'b),)) {} +impl<'b> Fn<(&'b mut (dyn Response + 'b),)> for SendFile { + extern "rust-call" fn call(&self, (_res,): (&'b mut (dyn Response + 'b),)) {} } -impl<'b> FnMut<(&'b mut (Response+'b),)> for SendFile { - extern "rust-call" fn call_mut(&mut self, (_res,): (&'b mut (Response+'b),)) { +impl<'b> FnMut<(&'b mut (dyn Response + 'b),)> for SendFile { + extern "rust-call" fn call_mut(&mut self, (_res,): (&'b mut (dyn Response+'b),)) { self.call((_res,)) } } -impl<'b> FnOnce<(&'b mut (Response+'b),)> for SendFile { +impl<'b> FnOnce<(&'b mut (dyn Response + 'b),)> for SendFile { type Output = (); - extern "rust-call" fn call_once(self, (_res,): (&'b mut (Response+'b),)) { + extern "rust-call" fn call_once(self, (_res,): (&'b mut (dyn Response+'b),)) { self.call((_res,)) } } diff --git a/src/test/ui/issues/issue-15034.nll.stderr b/src/test/ui/issues/issue-15034.nll.stderr new file mode 100644 index 0000000000000..f142e260a2313 --- /dev/null +++ b/src/test/ui/issues/issue-15034.nll.stderr @@ -0,0 +1,11 @@ +error[E0621]: explicit lifetime required in the type of `lexer` + --> $DIR/issue-15034.rs:17:9 + | +LL | pub fn new(lexer: &'a mut Lexer) -> Parser<'a> { + | ------------- help: add explicit lifetime `'a` to the type of `lexer`: `&'a mut Lexer<'a>` +LL | Parser { lexer: lexer } + | ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/issues/issue-15129.stderr b/src/test/ui/issues/issue-15129.stderr index 7ee369085202b..b93fa14db0387 100644 --- a/src/test/ui/issues/issue-15129.stderr +++ b/src/test/ui/issues/issue-15129.stderr @@ -3,6 +3,8 @@ error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` not covered | LL | match (T::T1(()), V::V2(true)) { | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `(T1(()), V2(_))` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/issues/issue-15207.stderr b/src/test/ui/issues/issue-15207.stderr index 7149444b56685..2d90eb80fc54c 100644 --- a/src/test/ui/issues/issue-15207.stderr +++ b/src/test/ui/issues/issue-15207.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `push` found for type `!` in the current scope --> $DIR/issue-15207.rs:3:15 | -LL | break.push(1) //~ ERROR no method named `push` found for type `!` +LL | break.push(1) | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-15381.nll.stderr b/src/test/ui/issues/issue-15381.nll.stderr new file mode 100644 index 0000000000000..a8495846b3610 --- /dev/null +++ b/src/test/ui/issues/issue-15381.nll.stderr @@ -0,0 +1,16 @@ +error[E0005]: refutable pattern in `for` loop binding: `&[]` not covered + --> $DIR/issue-15381.rs:4:9 + | +LL | for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) { + | ^^^^^^^^ pattern `&[]` not covered + +error[E0381]: borrow of possibly uninitialized variable: `y` + --> $DIR/issue-15381.rs:6:26 + | +LL | println!("y={}", y); + | ^ use of possibly uninitialized `y` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0005, E0381. +For more information about an error, try `rustc --explain E0005`. diff --git a/src/test/ui/issues/issue-15381.rs b/src/test/ui/issues/issue-15381.rs index e58c866119fbb..3dbd4e717a0db 100644 --- a/src/test/ui/issues/issue-15381.rs +++ b/src/test/ui/issues/issue-15381.rs @@ -4,5 +4,8 @@ fn main() { for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) { //~^ ERROR refutable pattern in `for` loop binding: `&[]` not covered println!("y={}", y); + //~^ WARN borrow of possibly uninitialized variable: `y` + //~| WARN this error has been downgraded to a warning for backwards compatibility + //~| WARN this represents potential undefined behavior in your code and this warning will } } diff --git a/src/test/ui/issues/issue-15381.stderr b/src/test/ui/issues/issue-15381.stderr index 8152737256c7f..7b11d85ead874 100644 --- a/src/test/ui/issues/issue-15381.stderr +++ b/src/test/ui/issues/issue-15381.stderr @@ -4,6 +4,17 @@ error[E0005]: refutable pattern in `for` loop binding: `&[]` not covered LL | for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) { | ^^^^^^^^ pattern `&[]` not covered +warning[E0381]: borrow of possibly uninitialized variable: `y` + --> $DIR/issue-15381.rs:6:26 + | +LL | println!("y={}", y); + | ^ use of possibly uninitialized `y` + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + error: aborting due to previous error -For more information about this error, try `rustc --explain E0005`. +Some errors have detailed explanations: E0005, E0381. +For more information about an error, try `rustc --explain E0005`. diff --git a/src/test/ui/issues/issue-15919.rs b/src/test/ui/issues/issue-15919.rs index 19ecf2f657e0a..a7ac4802a12d5 100644 --- a/src/test/ui/issues/issue-15919.rs +++ b/src/test/ui/issues/issue-15919.rs @@ -1,6 +1,10 @@ // error-pattern: too big for the current architecture // normalize-stderr-test "\[usize; \d+\]" -> "[usize; N]" +// FIXME https://github.com/rust-lang/rust/issues/59774 +// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" + #[cfg(target_pointer_width = "32")] fn main() { let x = [0usize; 0xffff_ffff]; diff --git a/src/test/ui/issues/issue-15965.stderr b/src/test/ui/issues/issue-15965.stderr index 904656cb3b1cf..90377c19dee02 100644 --- a/src/test/ui/issues/issue-15965.stderr +++ b/src/test/ui/issues/issue-15965.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/issue-15965.rs:3:9 | LL | / { return () } -LL | | //~^ ERROR type annotations needed [E0282] +LL | | LL | | () | |______^ cannot infer type | diff --git a/src/test/ui/issues/issue-16048.rs b/src/test/ui/issues/issue-16048.rs index 5910481bf7e0d..7d24f3a40a742 100644 --- a/src/test/ui/issues/issue-16048.rs +++ b/src/test/ui/issues/issue-16048.rs @@ -22,6 +22,8 @@ impl<'a> NoLifetime for Foo<'a> { //~^ ERROR E0195 //~| NOTE lifetimes do not match method in trait return *self as T; + //~^ ERROR non-primitive cast: `Foo<'a>` as `T` + //~| NOTE an `as` expression can only be used to convert between primitive types. } } diff --git a/src/test/ui/issues/issue-16048.stderr b/src/test/ui/issues/issue-16048.stderr index 18e59bd2410ff..a137bcdf1915e 100644 --- a/src/test/ui/issues/issue-16048.stderr +++ b/src/test/ui/issues/issue-16048.stderr @@ -7,6 +7,15 @@ LL | fn get<'p, T : Test<'p>>(&self) -> T; LL | fn get<'p, T : Test<'a>>(&self) -> T { | ^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait -error: aborting due to previous error +error[E0605]: non-primitive cast: `Foo<'a>` as `T` + --> $DIR/issue-16048.rs:24:16 + | +LL | return *self as T; + | ^^^^^^^^^^ + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0195`. +Some errors have detailed explanations: E0195, E0605. +For more information about an error, try `rustc --explain E0195`. diff --git a/src/test/ui/issues/issue-16098.stderr b/src/test/ui/issues/issue-16098.stderr index 4a62cea20b8a8..f890baf8eba04 100644 --- a/src/test/ui/issues/issue-16098.stderr +++ b/src/test/ui/issues/issue-16098.stderr @@ -1,13 +1,13 @@ error: recursion limit reached while expanding the macro `prob1` --> $DIR/issue-16098.rs:7:18 | -LL | $n + prob1!($n - 1); //~ ERROR recursion limit reached while expanding the macro `prob1` +LL | $n + prob1!($n - 1); | ^^^^^^^^^^^^^^ ... LL | println!("Problem 1: {}", prob1!(1000)); | ------------ in this macro invocation | - = help: consider adding a `#![recursion_limit="128"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16250.stderr b/src/test/ui/issues/issue-16250.stderr index fc6f26f043997..142d8e21532d8 100644 --- a/src/test/ui/issues/issue-16250.stderr +++ b/src/test/ui/issues/issue-16250.stderr @@ -1,7 +1,7 @@ error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout --> $DIR/issue-16250.rs:6:20 | -LL | pub fn foo(x: (Foo)); //~ ERROR unspecified layout +LL | pub fn foo(x: (Foo)); | ^^^ | note: lint level defined here @@ -10,7 +10,7 @@ note: lint level defined here LL | #![deny(warnings)] | ^^^^^^^^ = note: #[deny(improper_ctypes)] implied by #[deny(warnings)] - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/issue-16250.rs:3:1 | diff --git a/src/test/ui/issues/issue-16538.stderr b/src/test/ui/issues/issue-16538.stderr index 78c7d310ba2b2..2d8b5bf2f6fb8 100644 --- a/src/test/ui/issues/issue-16538.stderr +++ b/src/test/ui/issues/issue-16538.stderr @@ -15,5 +15,5 @@ LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); error: aborting due to 2 previous errors -Some errors occurred: E0015, E0277. +Some errors have detailed explanations: E0015, E0277. For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/issues/issue-16668.rs b/src/test/ui/issues/issue-16668.rs index f69ca4677c9c3..b570a2ced67bc 100644 --- a/src/test/ui/issues/issue-16668.rs +++ b/src/test/ui/issues/issue-16668.rs @@ -1,7 +1,7 @@ // compile-pass #![allow(dead_code)] struct Parser<'a, I, O> { - parse: Box Result + 'a> + parse: Box Result + 'a> } impl<'a, I: 'a, O: 'a> Parser<'a, I, O> { diff --git a/src/test/ui/issues/issue-16683.nll.stderr b/src/test/ui/issues/issue-16683.nll.stderr new file mode 100644 index 0000000000000..ea6b69d1a76c6 --- /dev/null +++ b/src/test/ui/issues/issue-16683.nll.stderr @@ -0,0 +1,10 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/issue-16683.rs:4:9 + | +LL | fn b(&self) { + | ----- `self` is a reference that is only valid in the function body +LL | self.a(); + | ^^^^^^^^ `self` escapes the function body here + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-16683.stderr b/src/test/ui/issues/issue-16683.stderr index 23e67bb2de9b7..771a2ddf240f5 100644 --- a/src/test/ui/issues/issue-16683.stderr +++ b/src/test/ui/issues/issue-16683.stderr @@ -1,20 +1,20 @@ error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements --> $DIR/issue-16683.rs:4:14 | -LL | self.a(); //~ ERROR cannot infer +LL | self.a(); | ^ | note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 3:5... --> $DIR/issue-16683.rs:3:5 | LL | / fn b(&self) { -LL | | self.a(); //~ ERROR cannot infer +LL | | self.a(); LL | | } | |_____^ note: ...so that reference does not outlive borrowed content --> $DIR/issue-16683.rs:4:9 | -LL | self.a(); //~ ERROR cannot infer +LL | self.a(); | ^^^^ note: but, the lifetime must be valid for the lifetime 'a as defined on the trait at 1:9... --> $DIR/issue-16683.rs:1:9 @@ -27,4 +27,3 @@ LL | trait T<'a> { error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/issues/issue-16922.rs b/src/test/ui/issues/issue-16922.rs index 1e865515c4b74..10a5cccbceef0 100644 --- a/src/test/ui/issues/issue-16922.rs +++ b/src/test/ui/issues/issue-16922.rs @@ -1,7 +1,7 @@ use std::any::Any; -fn foo(value: &T) -> Box { - Box::new(value) as Box +fn foo(value: &T) -> Box { + Box::new(value) as Box //~^ ERROR explicit lifetime required in the type of `value` [E0621] } diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 1f3b3fe739c44..4e3d3ecb9c03a 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -1,9 +1,9 @@ error[E0621]: explicit lifetime required in the type of `value` --> $DIR/issue-16922.rs:4:5 | -LL | fn foo(value: &T) -> Box { +LL | fn foo(value: &T) -> Box { | -- help: add explicit lifetime `'static` to the type of `value`: `&'static T` -LL | Box::new(value) as Box +LL | Box::new(value) as Box | ^^^^^^^^^^^^^^^ lifetime `'static` required error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16939.stderr b/src/test/ui/issues/issue-16939.stderr index 7281f6a735569..5df2119c14120 100644 --- a/src/test/ui/issues/issue-16939.stderr +++ b/src/test/ui/issues/issue-16939.stderr @@ -1,7 +1,7 @@ error[E0057]: this function takes 0 parameters but 1 parameter was supplied --> $DIR/issue-16939.rs:5:9 | -LL | |t| f(t); //~ ERROR E0057 +LL | |t| f(t); | ^^^^ expected 0 parameters error: aborting due to previous error diff --git a/src/test/ui/issues/issue-1697.stderr b/src/test/ui/issues/issue-1697.stderr index 00e136cb1ce86..6ae5bd1fc2649 100644 --- a/src/test/ui/issues/issue-1697.stderr +++ b/src/test/ui/issues/issue-1697.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `unresolved` --> $DIR/issue-1697.rs:3:5 | -LL | use unresolved::*; //~ ERROR unresolved import `unresolved` [E0432] +LL | use unresolved::*; | ^^^^^^^^^^ maybe a missing `extern crate unresolved;`? error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16994.rs b/src/test/ui/issues/issue-16994.rs index d356ce8a4da40..8d3074bcee9cc 100644 --- a/src/test/ui/issues/issue-16994.rs +++ b/src/test/ui/issues/issue-16994.rs @@ -1,10 +1,9 @@ -// compile-pass -// skip-codegen -fn cb<'a,T>(_x: Box, bool))) -> T>) -> T { +// check-pass + +fn cb<'a,T>(_x: Box, bool))) -> T>) -> T { panic!() } - fn main() { cb(Box::new(|(k, &(ref v, b))| (*k, v.clone(), b))); } diff --git a/src/test/ui/issues/issue-17001.stderr b/src/test/ui/issues/issue-17001.stderr index bdd0824963809..2374e829556ec 100644 --- a/src/test/ui/issues/issue-17001.stderr +++ b/src/test/ui/issues/issue-17001.stderr @@ -1,9 +1,8 @@ error[E0574]: expected struct, variant or union type, found module `foo` --> $DIR/issue-17001.rs:4:13 | -LL | let p = foo { x: () }; //~ ERROR expected struct, variant or union type, found module `foo` +LL | let p = foo { x: () }; | ^^^ not a struct, variant or union type error: aborting due to previous error -For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/issues/issue-17033.stderr b/src/test/ui/issues/issue-17033.stderr index 181a9992c6d82..ba78aa2bc6a50 100644 --- a/src/test/ui/issues/issue-17033.stderr +++ b/src/test/ui/issues/issue-17033.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-17033.rs:2:10 | -LL | (*p)(()) //~ ERROR mismatched types +LL | (*p)(()) | ^^ | | | expected &mut (), found () diff --git a/src/test/ui/issues/issue-17252.stderr b/src/test/ui/issues/issue-17252.stderr index e333e15065111..da3e2e763af58 100644 --- a/src/test/ui/issues/issue-17252.stderr +++ b/src/test/ui/issues/issue-17252.stderr @@ -1,11 +1,11 @@ error[E0391]: cycle detected when processing `FOO` --> $DIR/issue-17252.rs:1:20 | -LL | const FOO: usize = FOO; //~ ERROR E0391 +LL | const FOO: usize = FOO; | ^^^ | = note: ...which again requires processing `FOO`, completing the cycle -note: cycle used when processing `main::{{constant}}` +note: cycle used when processing `main::{{constant}}#0` --> $DIR/issue-17252.rs:4:18 | LL | let _x: [u8; FOO]; // caused stack overflow prior to fix diff --git a/src/test/ui/issues/issue-17263.ast.stderr b/src/test/ui/issues/issue-17263.ast.stderr deleted file mode 100644 index 823f2c747d686..0000000000000 --- a/src/test/ui/issues/issue-17263.ast.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0499]: cannot borrow `x` (via `x.b`) as mutable more than once at a time - --> $DIR/issue-17263.rs:17:34 - | -LL | let (a, b) = (&mut x.a, &mut x.b); - | --- ^^^ second mutable borrow occurs here (via `x.b`) - | | - | first mutable borrow occurs here (via `x.a`) -... -LL | } - | - first borrow ends here - -error[E0502]: cannot borrow `foo` (via `foo.b`) as immutable because `foo` is also borrowed as mutable (via `foo.a`) - --> $DIR/issue-17263.rs:21:32 - | -LL | let (c, d) = (&mut foo.a, &foo.b); - | ----- ^^^^^ immutable borrow of `foo.b` -- which overlaps with `foo.a` -- occurs here - | | - | mutable borrow occurs here (via `foo.a`) -... -LL | } - | - mutable borrow ends here - -error: aborting due to 2 previous errors - -Some errors occurred: E0499, E0502. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/issues/issue-17263.nll.stderr b/src/test/ui/issues/issue-17263.nll.stderr deleted file mode 100644 index cdb574b8b9f94..0000000000000 --- a/src/test/ui/issues/issue-17263.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: compilation successful - --> $DIR/issue-17263.rs:15:1 - | -LL | / fn main() { //[nll]~ ERROR compilation successful -LL | | let mut x: Box<_> = box Foo { a: 1, b: 2 }; -LL | | let (a, b) = (&mut x.a, &mut x.b); -LL | | //[ast]~^ ERROR cannot borrow `x` (via `x.b`) as mutable more than once at a time -... | -LL | | use_mut(a); -LL | | } - | |_^ - -error: aborting due to previous error - diff --git a/src/test/ui/issues/issue-17263.rs b/src/test/ui/issues/issue-17263.rs index 754f3b90aacf1..dce30275ff354 100644 --- a/src/test/ui/issues/issue-17263.rs +++ b/src/test/ui/issues/issue-17263.rs @@ -1,28 +1,18 @@ -// This checks diagnostic quality for cases where AST-borrowck treated -// `Box` as other types (see rust-lang/rfcs#130). NLL again treats -// `Box` specially. We capture the differences via revisions. +// compile-pass -// revisions: ast nll -//[ast]compile-flags: -Z borrowck=ast -//[nll]compile-flags: -Z borrowck=migrate -Z two-phase-borrows - -// don't worry about the --compare-mode=nll on this test. -// ignore-compare-mode-nll -#![feature(box_syntax, rustc_attrs)] +#![feature(box_syntax)] struct Foo { a: isize, b: isize } -#[rustc_error] // rust-lang/rust#49855 -fn main() { //[nll]~ ERROR compilation successful + +fn main() { let mut x: Box<_> = box Foo { a: 1, b: 2 }; let (a, b) = (&mut x.a, &mut x.b); - //[ast]~^ ERROR cannot borrow `x` (via `x.b`) as mutable more than once at a time let mut foo: Box<_> = box Foo { a: 1, b: 2 }; let (c, d) = (&mut foo.a, &foo.b); - //[ast]~^ ERROR cannot borrow `foo` (via `foo.b`) as immutable - // We explicitly use the references created above to illustrate - // that NLL is accepting this code *not* because of artificially + // We explicitly use the references created above to illustrate that the + // borrow checker is accepting this code *not* because of artificially // short lifetimes, but rather because it understands that all the // references are of disjoint parts of memory. use_imm(d); diff --git a/src/test/ui/issues/issue-17337.stderr b/src/test/ui/issues/issue-17337.stderr index 4c3ffe92cccdc..8973afb806817 100644 --- a/src/test/ui/issues/issue-17337.stderr +++ b/src/test/ui/issues/issue-17337.stderr @@ -1,7 +1,7 @@ error: use of deprecated item 'Foo::foo': text --> $DIR/issue-17337.rs:16:6 | -LL | .foo(); //~ ERROR use of deprecated item +LL | .foo(); | ^^^ | note: lint level defined here diff --git a/src/test/ui/issues/issue-17373.stderr b/src/test/ui/issues/issue-17373.stderr index e1a9f097b226c..5c429d1113df4 100644 --- a/src/test/ui/issues/issue-17373.stderr +++ b/src/test/ui/issues/issue-17373.stderr @@ -1,7 +1,7 @@ error[E0614]: type `!` cannot be dereferenced --> $DIR/issue-17373.rs:2:5 | -LL | *return //~ ERROR type `!` cannot be dereferenced +LL | *return | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17385.nll.stderr b/src/test/ui/issues/issue-17385.nll.stderr deleted file mode 100644 index 20198f19dd5f5..0000000000000 --- a/src/test/ui/issues/issue-17385.nll.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0382]: use of moved value: `foo` - --> $DIR/issue-17385.rs:19:11 - | -LL | let foo = X(1); - | --- move occurs because `foo` has type `X`, which does not implement the `Copy` trait -LL | drop(foo); - | --- value moved here -LL | match foo { //~ ERROR use of moved value -LL | X(1) => (), - | ^ value used here after move - -error[E0382]: use of moved value: `e` - --> $DIR/issue-17385.rs:25:11 - | -LL | let e = Enum::Variant2; - | - move occurs because `e` has type `Enum`, which does not implement the `Copy` trait -LL | drop(e); - | - value moved here -LL | match e { //~ ERROR use of moved value - | ^ value used here after move - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/issues/issue-17385.rs b/src/test/ui/issues/issue-17385.rs index 7400aadb059f7..93364d2f6259e 100644 --- a/src/test/ui/issues/issue-17385.rs +++ b/src/test/ui/issues/issue-17385.rs @@ -15,8 +15,8 @@ impl Drop for Enum { fn main() { let foo = X(1); drop(foo); - match foo { //~ ERROR use of moved value - X(1) => (), + match foo { + X(1) => (), //~ ERROR use of moved value _ => unreachable!() } diff --git a/src/test/ui/issues/issue-17385.stderr b/src/test/ui/issues/issue-17385.stderr index 5f28a3c2c2785..28c22260c3888 100644 --- a/src/test/ui/issues/issue-17385.stderr +++ b/src/test/ui/issues/issue-17385.stderr @@ -1,22 +1,23 @@ error[E0382]: use of moved value: `foo` - --> $DIR/issue-17385.rs:18:11 + --> $DIR/issue-17385.rs:19:11 | +LL | let foo = X(1); + | --- move occurs because `foo` has type `X`, which does not implement the `Copy` trait LL | drop(foo); | --- value moved here -LL | match foo { //~ ERROR use of moved value - | ^^^ value used here after move - | - = note: move occurs because `foo` has type `X`, which does not implement the `Copy` trait +LL | match foo { +LL | X(1) => (), + | ^ value used here after move error[E0382]: use of moved value: `e` --> $DIR/issue-17385.rs:25:11 | +LL | let e = Enum::Variant2; + | - move occurs because `e` has type `Enum`, which does not implement the `Copy` trait LL | drop(e); | - value moved here -LL | match e { //~ ERROR use of moved value +LL | match e { | ^ value used here after move - | - = note: move occurs because `e` has type `Enum`, which does not implement the `Copy` trait error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-17405.stderr b/src/test/ui/issues/issue-17405.stderr index 2bfc85cc7de8f..4b5678a88773b 100644 --- a/src/test/ui/issues/issue-17405.stderr +++ b/src/test/ui/issues/issue-17405.stderr @@ -1,9 +1,8 @@ error[E0574]: expected struct, variant or union type, found enum `Foo` --> $DIR/issue-17405.rs:7:9 | -LL | Foo { i } => () //~ ERROR expected struct, variant or union type, found enum `Foo` +LL | Foo { i } => () | ^^^ not a struct, variant or union type error: aborting due to previous error -For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/issues/issue-17441.rs b/src/test/ui/issues/issue-17441.rs index cfb2fe674edf7..b9813ef1eef77 100644 --- a/src/test/ui/issues/issue-17441.rs +++ b/src/test/ui/issues/issue-17441.rs @@ -2,10 +2,10 @@ fn main() { let _foo = &[1_usize, 2] as [usize]; //~^ ERROR cast to unsized type: `&[usize; 2]` as `[usize]` - let _bar = Box::new(1_usize) as std::fmt::Debug; + let _bar = Box::new(1_usize) as dyn std::fmt::Debug; //~^ ERROR cast to unsized type: `std::boxed::Box` as `dyn std::fmt::Debug` - let _baz = 1_usize as std::fmt::Debug; + let _baz = 1_usize as dyn std::fmt::Debug; //~^ ERROR cast to unsized type: `usize` as `dyn std::fmt::Debug` let _quux = [1_usize, 2] as [usize]; diff --git a/src/test/ui/issues/issue-17441.stderr b/src/test/ui/issues/issue-17441.stderr index 436ee7325f8e5..0ab035515a051 100644 --- a/src/test/ui/issues/issue-17441.stderr +++ b/src/test/ui/issues/issue-17441.stderr @@ -13,21 +13,21 @@ LL | let _foo = &[1_usize, 2] as [usize]; error[E0620]: cast to unsized type: `std::boxed::Box` as `dyn std::fmt::Debug` --> $DIR/issue-17441.rs:5:16 | -LL | let _bar = Box::new(1_usize) as std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^^--------------- +LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^^------------------- | | - | help: try casting to a `Box` instead: `Box` + | help: try casting to a `Box` instead: `Box` error[E0620]: cast to unsized type: `usize` as `dyn std::fmt::Debug` --> $DIR/issue-17441.rs:8:16 | -LL | let _baz = 1_usize as std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _baz = 1_usize as dyn std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider using a box or reference as appropriate --> $DIR/issue-17441.rs:8:16 | -LL | let _baz = 1_usize as std::fmt::Debug; +LL | let _baz = 1_usize as dyn std::fmt::Debug; | ^^^^^^^ error[E0620]: cast to unsized type: `[usize; 2]` as `[usize]` diff --git a/src/test/ui/issues/issue-17458.rs b/src/test/ui/issues/issue-17458.rs index 444e94d829bf8..d56ffebad7d5a 100644 --- a/src/test/ui/issues/issue-17458.rs +++ b/src/test/ui/issues/issue-17458.rs @@ -1,4 +1,4 @@ -static X: usize = unsafe { 0 as *const usize as usize }; +static X: usize = unsafe { core::ptr::null::() as usize }; //~^ ERROR: casting pointers to integers in statics is unstable fn main() { diff --git a/src/test/ui/issues/issue-17458.stderr b/src/test/ui/issues/issue-17458.stderr index a1a8ed9f0cdcb..d51d2f50d6faf 100644 --- a/src/test/ui/issues/issue-17458.stderr +++ b/src/test/ui/issues/issue-17458.stderr @@ -1,9 +1,10 @@ -error[E0658]: casting pointers to integers in statics is unstable (see issue #51910) +error[E0658]: casting pointers to integers in statics is unstable --> $DIR/issue-17458.rs:1:28 | -LL | static X: usize = unsafe { 0 as *const usize as usize }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | static X: usize = unsafe { core::ptr::null::() as usize }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51910 = help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17545.nll.stderr b/src/test/ui/issues/issue-17545.nll.stderr deleted file mode 100644 index 527f8df9ccbb8..0000000000000 --- a/src/test/ui/issues/issue-17545.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-17545.rs:7:10 - | -LL | pub fn foo<'a, F: Fn(&'a ())>(bar: F) { - | -- lifetime `'a` defined here -LL | / bar.call(( -LL | | &id(()), //~ ERROR borrowed value does not live long enough - | | ^^^^^^ creates a temporary which is freed while still in use -LL | | )); - | | -- temporary value is freed at the end of this statement - | |______| - | argument requires that borrow lasts for `'a` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/issues/issue-17545.rs b/src/test/ui/issues/issue-17545.rs index d62c0b9f32cb9..ced6fff315f4a 100644 --- a/src/test/ui/issues/issue-17545.rs +++ b/src/test/ui/issues/issue-17545.rs @@ -4,7 +4,7 @@ fn id(x: T) -> T { x } pub fn foo<'a, F: Fn(&'a ())>(bar: F) { bar.call(( - &id(()), //~ ERROR borrowed value does not live long enough + &id(()), //~ ERROR temporary value dropped while borrowed )); } fn main() {} diff --git a/src/test/ui/issues/issue-17545.stderr b/src/test/ui/issues/issue-17545.stderr index 62ec25e1d1a4f..79a1e09bd7cc6 100644 --- a/src/test/ui/issues/issue-17545.stderr +++ b/src/test/ui/issues/issue-17545.stderr @@ -1,18 +1,16 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/issue-17545.rs:7:10 | -LL | &id(()), //~ ERROR borrowed value does not live long enough - | ^^^^^^ temporary value does not live long enough -LL | )); - | - temporary value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 5:12... - --> $DIR/issue-17545.rs:5:12 - | -LL | pub fn foo<'a, F: Fn(&'a ())>(bar: F) { - | ^^ - = note: consider using a `let` binding to increase its lifetime +LL | pub fn foo<'a, F: Fn(&'a ())>(bar: F) { + | -- lifetime `'a` defined here +LL | / bar.call(( +LL | | &id(()), + | | ^^^^^^ creates a temporary which is freed while still in use +LL | | )); + | | -- temporary value is freed at the end of this statement + | |______| + | argument requires that borrow lasts for `'a` error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/issues/issue-17546.stderr b/src/test/ui/issues/issue-17546.stderr index 1fbb229ed98b4..e27f49b4a3f0a 100644 --- a/src/test/ui/issues/issue-17546.stderr +++ b/src/test/ui/issues/issue-17546.stderr @@ -62,4 +62,3 @@ LL | fn newer() -> Result { error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0573`. diff --git a/src/test/ui/issues/issue-17551.stderr b/src/test/ui/issues/issue-17551.stderr index df693591e7c25..ce16f0f58eaf0 100644 --- a/src/test/ui/issues/issue-17551.stderr +++ b/src/test/ui/issues/issue-17551.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `B` --> $DIR/issue-17551.rs:6:15 | -LL | let foo = B(marker::PhantomData); //~ ERROR type annotations needed +LL | let foo = B(marker::PhantomData); | --- ^ cannot infer type for `T` | | - | consider giving `foo` a type + | consider giving `foo` the explicit type `B`, where the type parameter `T` is specified error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17651.stderr b/src/test/ui/issues/issue-17651.stderr index 72c40ff4b3a0c..ce9af1524b087 100644 --- a/src/test/ui/issues/issue-17651.stderr +++ b/src/test/ui/issues/issue-17651.stderr @@ -6,7 +6,7 @@ LL | (|| Box::new(*(&[0][..])))(); | = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` = note: to learn more, visit - = note: required by `>::new` + = note: required by `std::boxed::Box::::new` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17718-const-bad-values.stderr b/src/test/ui/issues/issue-17718-const-bad-values.stderr index 95ef2b1b01008..7a49e89a1af70 100644 --- a/src/test/ui/issues/issue-17718-const-bad-values.stderr +++ b/src/test/ui/issues/issue-17718-const-bad-values.stderr @@ -18,5 +18,5 @@ LL | const C2: &'static mut usize = unsafe { &mut S }; error: aborting due to 3 previous errors -Some errors occurred: E0013, E0017. +Some errors have detailed explanations: E0013, E0017. For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/issues/issue-17718-const-privacy.stderr b/src/test/ui/issues/issue-17718-const-privacy.stderr index 5025aaca777d5..0b0de8a52590b 100644 --- a/src/test/ui/issues/issue-17718-const-privacy.stderr +++ b/src/test/ui/issues/issue-17718-const-privacy.stderr @@ -1,13 +1,13 @@ error[E0603]: constant `B` is private --> $DIR/issue-17718-const-privacy.rs:5:8 | -LL | use a::B; //~ ERROR: constant `B` is private +LL | use a::B; | ^ error[E0603]: constant `BAR` is private --> $DIR/issue-17718-const-privacy.rs:8:5 | -LL | BAR, //~ ERROR: constant `BAR` is private +LL | BAR, | ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-17718-constants-not-static.nll.stderr b/src/test/ui/issues/issue-17718-constants-not-static.nll.stderr deleted file mode 100644 index 8f3acae71391f..0000000000000 --- a/src/test/ui/issues/issue-17718-constants-not-static.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0515]: cannot return reference to temporary value - --> $DIR/issue-17718-constants-not-static.rs:5:30 - | -LL | fn foo() -> &'static usize { &id(FOO) } - | ^------- - | || - | |temporary value created here - | returns a reference to data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-17718-constants-not-static.rs b/src/test/ui/issues/issue-17718-constants-not-static.rs index e857b906efa7b..2e6aff1618bfb 100644 --- a/src/test/ui/issues/issue-17718-constants-not-static.rs +++ b/src/test/ui/issues/issue-17718-constants-not-static.rs @@ -3,7 +3,7 @@ fn id(x: T) -> T { x } const FOO: usize = 3; fn foo() -> &'static usize { &id(FOO) } -//~^ ERROR: borrowed value does not live long enough +//~^ ERROR: cannot return reference to temporary value fn main() { } diff --git a/src/test/ui/issues/issue-17718-constants-not-static.stderr b/src/test/ui/issues/issue-17718-constants-not-static.stderr index 2a5b9d7222345..8f3acae71391f 100644 --- a/src/test/ui/issues/issue-17718-constants-not-static.stderr +++ b/src/test/ui/issues/issue-17718-constants-not-static.stderr @@ -1,13 +1,12 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/issue-17718-constants-not-static.rs:5:31 +error[E0515]: cannot return reference to temporary value + --> $DIR/issue-17718-constants-not-static.rs:5:30 | LL | fn foo() -> &'static usize { &id(FOO) } - | ^^^^^^^ - temporary value only lives until here - | | - | temporary value does not live long enough - | - = note: borrowed value must be valid for the static lifetime... + | ^------- + | || + | |temporary value created here + | returns a reference to data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-17718-patterns.stderr b/src/test/ui/issues/issue-17718-patterns.stderr index 698bd857a5806..109091c2af0c7 100644 --- a/src/test/ui/issues/issue-17718-patterns.stderr +++ b/src/test/ui/issues/issue-17718-patterns.stderr @@ -4,7 +4,7 @@ error[E0530]: match bindings cannot shadow statics LL | static A1: usize = 1; | --------------------- the static `A1` is defined here ... -LL | A1 => {} //~ ERROR: match bindings cannot shadow statics +LL | A1 => {} | ^^ cannot be named the same as a static error[E0530]: match bindings cannot shadow statics @@ -13,7 +13,7 @@ error[E0530]: match bindings cannot shadow statics LL | static mut A2: usize = 1; | ------------------------- the static `A2` is defined here ... -LL | A2 => {} //~ ERROR: match bindings cannot shadow statics +LL | A2 => {} | ^^ cannot be named the same as a static error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-17718-references.stderr b/src/test/ui/issues/issue-17718-references.stderr index ef49dcfeef9f4..15c3e67f7a1a6 100644 --- a/src/test/ui/issues/issue-17718-references.stderr +++ b/src/test/ui/issues/issue-17718-references.stderr @@ -1,13 +1,13 @@ error[E0013]: constants cannot refer to statics, use a constant instead --> $DIR/issue-17718-references.rs:9:28 | -LL | const T2: &'static usize = &S; //~ ERROR: constants cannot refer to statics +LL | const T2: &'static usize = &S; | ^^ error[E0013]: constants cannot refer to statics, use a constant instead --> $DIR/issue-17718-references.rs:14:19 | -LL | const T6: usize = S; //~ ERROR: constants cannot refer to statics +LL | const T6: usize = S; | ^ error[E0013]: constants cannot refer to statics, use a constant instead diff --git a/src/test/ui/issues/issue-17718-static-move.nll.stderr b/src/test/ui/issues/issue-17718-static-move.nll.stderr deleted file mode 100644 index 86e7a18491041..0000000000000 --- a/src/test/ui/issues/issue-17718-static-move.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0507]: cannot move out of static item - --> $DIR/issue-17718-static-move.rs:6:14 - | -LL | let _a = FOO; //~ ERROR: cannot move out of static item - | ^^^ - | | - | cannot move out of static item - | help: consider borrowing here: `&FOO` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/issues/issue-17718-static-move.stderr b/src/test/ui/issues/issue-17718-static-move.stderr index dd473f0a4c457..984534bfb8b86 100644 --- a/src/test/ui/issues/issue-17718-static-move.stderr +++ b/src/test/ui/issues/issue-17718-static-move.stderr @@ -1,11 +1,11 @@ -error[E0507]: cannot move out of static item +error[E0507]: cannot move out of static item `FOO` --> $DIR/issue-17718-static-move.rs:6:14 | -LL | let _a = FOO; //~ ERROR: cannot move out of static item +LL | let _a = FOO; | ^^^ | | - | cannot move out of static item - | help: consider using a reference instead: `&FOO` + | move occurs because `FOO` has type `Foo`, which does not implement the `Copy` trait + | help: consider borrowing here: `&FOO` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17728.nll.stderr b/src/test/ui/issues/issue-17728.nll.stderr new file mode 100644 index 0000000000000..7436ebd920ee2 --- /dev/null +++ b/src/test/ui/issues/issue-17728.nll.stderr @@ -0,0 +1,21 @@ +error[E0308]: match arms have incompatible types + --> $DIR/issue-17728.rs:109:14 + | +LL | / match to_parse { +LL | | "w" | "west" => RoomDirection::West, +LL | | "e" | "east" => RoomDirection::East, +LL | | "n" | "north" => RoomDirection::North, +... | +LL | | "down" => RoomDirection::Down, + | | ------------------- this and all prior arms are found to be of type `RoomDirection` +LL | | _ => None + | | ^^^^ expected enum `RoomDirection`, found enum `std::option::Option` +LL | | } + | |_____- `match` arms have incompatible types + | + = note: expected type `RoomDirection` + found type `std::option::Option<_>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-17728.stderr b/src/test/ui/issues/issue-17728.stderr index 2c2efad19f569..56dfb89456fe5 100644 --- a/src/test/ui/issues/issue-17728.stderr +++ b/src/test/ui/issues/issue-17728.stderr @@ -29,5 +29,4 @@ LL | | } error: aborting due to 2 previous errors -Some errors occurred: E0308, E0623. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-17740.stderr b/src/test/ui/issues/issue-17740.stderr index c7a76c558ee8b..7ab0fa4d818b0 100644 --- a/src/test/ui/issues/issue-17740.stderr +++ b/src/test/ui/issues/issue-17740.stderr @@ -10,11 +10,11 @@ note: the anonymous lifetime #2 defined on the method body at 6:5... --> $DIR/issue-17740.rs:6:5 | LL | / fn bar(self: &mut Foo) { -LL | | //~^ mismatched method receiver -LL | | //~| expected type `Foo<'a>` -LL | | //~| found type `Foo<'_>` +LL | | +LL | | +LL | | ... | -LL | | //~| lifetime mismatch +LL | | LL | | } | |_____^ note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 5:7 @@ -40,11 +40,11 @@ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the m --> $DIR/issue-17740.rs:6:5 | LL | / fn bar(self: &mut Foo) { -LL | | //~^ mismatched method receiver -LL | | //~| expected type `Foo<'a>` -LL | | //~| found type `Foo<'_>` +LL | | +LL | | +LL | | ... | -LL | | //~| lifetime mismatch +LL | | LL | | } | |_____^ diff --git a/src/test/ui/issues/issue-17758.nll.stderr b/src/test/ui/issues/issue-17758.nll.stderr new file mode 100644 index 0000000000000..b9dc9da3683d6 --- /dev/null +++ b/src/test/ui/issues/issue-17758.nll.stderr @@ -0,0 +1,10 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/issue-17758.rs:7:9 + | +LL | fn bar(&self) { + | ----- `self` is a reference that is only valid in the function body +LL | self.foo(); + | ^^^^^^^^^^ `self` escapes the function body here + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-17758.stderr b/src/test/ui/issues/issue-17758.stderr index b376757091dd3..0ef3b98719d34 100644 --- a/src/test/ui/issues/issue-17758.stderr +++ b/src/test/ui/issues/issue-17758.stderr @@ -9,7 +9,7 @@ note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on th | LL | / fn bar(&self) { LL | | self.foo(); -LL | | //~^ ERROR cannot infer +LL | | LL | | } | |_____^ note: ...so that reference does not outlive borrowed content @@ -28,4 +28,3 @@ LL | trait Foo<'a> { error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/issues/issue-17800.stderr b/src/test/ui/issues/issue-17800.stderr index b4234245bfb38..6efc7f0c06e11 100644 --- a/src/test/ui/issues/issue-17800.stderr +++ b/src/test/ui/issues/issue-17800.stderr @@ -2,10 +2,10 @@ error[E0026]: variant `MyOption::MySome` does not have a field named `x` --> $DIR/issue-17800.rs:8:28 | LL | MyOption::MySome { x: 42 } => (), - | ^^^^^ + | ^ | | | variant `MyOption::MySome` does not have this field - | help: did you mean: `0` + | help: a field with a similar name exists: `0` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17904-2.stderr b/src/test/ui/issues/issue-17904-2.stderr index b4f9745257492..930409cc63727 100644 --- a/src/test/ui/issues/issue-17904-2.stderr +++ b/src/test/ui/issues/issue-17904-2.stderr @@ -1,8 +1,8 @@ error[E0392]: parameter `T` is never used --> $DIR/issue-17904-2.rs:4:12 | -LL | struct Foo where T: Copy; //~ ERROR parameter `T` is never used - | ^ unused type parameter +LL | struct Foo where T: Copy; + | ^ unused parameter | = help: consider removing `T` or using a marker such as `std::marker::PhantomData` diff --git a/src/test/ui/issues/issue-17905-2.stderr b/src/test/ui/issues/issue-17905-2.stderr index 39e5f8ffc9f99..e3909e0c1253f 100644 --- a/src/test/ui/issues/issue-17905-2.stderr +++ b/src/test/ui/issues/issue-17905-2.stderr @@ -4,14 +4,14 @@ error[E0308]: mismatched method receiver LL | fn say(self: &Pair<&str, isize>) { | ^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = note: expected type `Pair<&'_ str, _>` + = note: expected type `Pair<&str, _>` found type `Pair<&str, _>` note: the anonymous lifetime #2 defined on the method body at 8:5... --> $DIR/issue-17905-2.rs:8:5 | LL | / fn say(self: &Pair<&str, isize>) { -LL | | //~^ ERROR mismatched method receiver -LL | | //~| ERROR mismatched method receiver +LL | | +LL | | LL | | println!("{:?}", self); LL | | } | |_____^ @@ -27,7 +27,7 @@ error[E0308]: mismatched method receiver LL | fn say(self: &Pair<&str, isize>) { | ^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = note: expected type `Pair<&'_ str, _>` + = note: expected type `Pair<&str, _>` found type `Pair<&str, _>` note: the lifetime '_ as defined on the impl at 5:5... --> $DIR/issue-17905-2.rs:5:5 @@ -38,8 +38,8 @@ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the m --> $DIR/issue-17905-2.rs:8:5 | LL | / fn say(self: &Pair<&str, isize>) { -LL | | //~^ ERROR mismatched method receiver -LL | | //~| ERROR mismatched method receiver +LL | | +LL | | LL | | println!("{:?}", self); LL | | } | |_____^ diff --git a/src/test/ui/issues/issue-17913.rs b/src/test/ui/issues/issue-17913.rs index b0c4ef54b165d..48d8f407aa1e4 100644 --- a/src/test/ui/issues/issue-17913.rs +++ b/src/test/ui/issues/issue-17913.rs @@ -1,6 +1,10 @@ // normalize-stderr-test "\[&usize; \d+\]" -> "[&usize; N]" // error-pattern: too big for the current architecture +// FIXME https://github.com/rust-lang/rust/issues/59774 +// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" + #![feature(box_syntax)] #[cfg(target_pointer_width = "64")] diff --git a/src/test/ui/issues/issue-17954.nll.stderr b/src/test/ui/issues/issue-17954.nll.stderr deleted file mode 100644 index e08375fee1fe4..0000000000000 --- a/src/test/ui/issues/issue-17954.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0712]: thread-local variable borrowed past end of function - --> $DIR/issue-17954.rs:7:13 - | -LL | let a = &FOO; - | ^^^^ thread-local variables cannot be borrowed beyond the end of the function -... -LL | } - | - end of enclosing function is here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0712`. diff --git a/src/test/ui/issues/issue-17954.rs b/src/test/ui/issues/issue-17954.rs index a8fbf2372b06a..eb6a3d70f58e2 100644 --- a/src/test/ui/issues/issue-17954.rs +++ b/src/test/ui/issues/issue-17954.rs @@ -5,12 +5,11 @@ static FOO: u8 = 3; fn main() { let a = &FOO; - //~^ ERROR borrowed value does not live long enough - //~| does not live long enough - //~| NOTE borrowed value must be valid for the static lifetime + //~^ ERROR thread-local variable borrowed past end of function + //~| NOTE thread-local variables cannot be borrowed beyond the end of the function std::thread::spawn(move || { println!("{}", a); }); } -//~^ NOTE borrowed value only lives until here +//~^ NOTE end of enclosing function is here diff --git a/src/test/ui/issues/issue-17954.stderr b/src/test/ui/issues/issue-17954.stderr index 458bef5499236..e08375fee1fe4 100644 --- a/src/test/ui/issues/issue-17954.stderr +++ b/src/test/ui/issues/issue-17954.stderr @@ -1,14 +1,12 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/issue-17954.rs:7:14 +error[E0712]: thread-local variable borrowed past end of function + --> $DIR/issue-17954.rs:7:13 | LL | let a = &FOO; - | ^^^ borrowed value does not live long enough + | ^^^^ thread-local variables cannot be borrowed beyond the end of the function ... LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - end of enclosing function is here error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0712`. diff --git a/src/test/ui/issues/issue-17959.rs b/src/test/ui/issues/issue-17959.rs index d56f346ecd45a..73865ae2d2eb6 100644 --- a/src/test/ui/issues/issue-17959.rs +++ b/src/test/ui/issues/issue-17959.rs @@ -17,5 +17,5 @@ impl Drop for G { } fn main() { - let x:G; + let x:G; } diff --git a/src/test/ui/issues/issue-17959.stderr b/src/test/ui/issues/issue-17959.stderr index 790e8f7c79824..de742e48aea9d 100644 --- a/src/test/ui/issues/issue-17959.stderr +++ b/src/test/ui/issues/issue-17959.stderr @@ -2,7 +2,7 @@ error[E0367]: The requirement `T: std::marker::Sized` is added only by the Drop --> $DIR/issue-17959.rs:11:1 | LL | / impl Drop for G { -LL | | //~^ ERROR: The requirement `T: std::marker::Sized` is added only by the Drop impl. [E0367] +LL | | LL | | fn drop(&mut self) { LL | | if !self._ptr.is_null() { LL | | } diff --git a/src/test/ui/issues/issue-17994.stderr b/src/test/ui/issues/issue-17994.stderr index e22b2c0719736..61e1e496f7958 100644 --- a/src/test/ui/issues/issue-17994.stderr +++ b/src/test/ui/issues/issue-17994.stderr @@ -1,7 +1,7 @@ error[E0091]: type parameter `T` is unused --> $DIR/issue-17994.rs:2:10 | -LL | type Huh where T: Tr = isize; //~ ERROR type parameter `T` is unused +LL | type Huh where T: Tr = isize; | ^ unused type parameter error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17999.stderr b/src/test/ui/issues/issue-17999.stderr index 51c0c757a80c1..b9ae03356e9bc 100644 --- a/src/test/ui/issues/issue-17999.stderr +++ b/src/test/ui/issues/issue-17999.stderr @@ -1,7 +1,7 @@ error: unused variable: `x` --> $DIR/issue-17999.rs:5:13 | -LL | let x = (); //~ ERROR: unused variable: `x` +LL | let x = (); | ^ help: consider prefixing with an underscore: `_x` | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unused_variables)] error: unused variable: `a` --> $DIR/issue-17999.rs:7:13 | -LL | a => {} //~ ERROR: unused variable: `a` +LL | a => {} | ^ help: consider prefixing with an underscore: `_a` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-18107.rs b/src/test/ui/issues/issue-18107.rs index 184d122d5cd61..122940f1c1726 100644 --- a/src/test/ui/issues/issue-18107.rs +++ b/src/test/ui/issues/issue-18107.rs @@ -1,7 +1,7 @@ pub trait AbstractRenderer {} fn _create_render(_: &()) -> - AbstractRenderer + dyn AbstractRenderer //~^ ERROR the size for values of type { match 0 { diff --git a/src/test/ui/issues/issue-18107.stderr b/src/test/ui/issues/issue-18107.stderr index 23b58c3f6df3d..9bdf470413b1c 100644 --- a/src/test/ui/issues/issue-18107.stderr +++ b/src/test/ui/issues/issue-18107.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `(dyn AbstractRenderer + 'static)` cannot be known at compilation time --> $DIR/issue-18107.rs:4:5 | -LL | AbstractRenderer - | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time +LL | dyn AbstractRenderer + | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn AbstractRenderer + 'static)` = note: to learn more, visit diff --git a/src/test/ui/issues/issue-18118.nll.stderr b/src/test/ui/issues/issue-18118.nll.stderr deleted file mode 100644 index 1920e1637d149..0000000000000 --- a/src/test/ui/issues/issue-18118.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0597]: `p` does not live long enough - --> $DIR/issue-18118.rs:4:9 - | -LL | &p //~ ERROR `p` does not live long enough - | ^^ - | | - | borrowed value does not live long enough - | using this value as a constant requires that `p` is borrowed for `'static` -LL | }; - | - `p` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issues/issue-18118.stderr b/src/test/ui/issues/issue-18118.stderr index 9b21ece341a9f..49798a148dee1 100644 --- a/src/test/ui/issues/issue-18118.stderr +++ b/src/test/ui/issues/issue-18118.stderr @@ -1,12 +1,13 @@ error[E0597]: `p` does not live long enough - --> $DIR/issue-18118.rs:4:10 + --> $DIR/issue-18118.rs:4:9 | -LL | &p //~ ERROR `p` does not live long enough - | ^ borrowed value does not live long enough +LL | &p + | ^^ + | | + | borrowed value does not live long enough + | using this value as a constant requires that `p` is borrowed for `'static` LL | }; - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - `p` dropped here while still borrowed error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18119.stderr b/src/test/ui/issues/issue-18119.stderr index ddee5a9da7a42..4c5b940190ee6 100644 --- a/src/test/ui/issues/issue-18119.stderr +++ b/src/test/ui/issues/issue-18119.stderr @@ -18,4 +18,3 @@ LL | impl foo {} error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0573`. diff --git a/src/test/ui/issues/issue-18159.stderr b/src/test/ui/issues/issue-18159.stderr index 25b7051a88004..6048344125c5f 100644 --- a/src/test/ui/issues/issue-18159.stderr +++ b/src/test/ui/issues/issue-18159.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed --> $DIR/issue-18159.rs:2:9 | -LL | let x; //~ ERROR type annotations needed +LL | let x; | ^ | | | cannot infer type diff --git a/src/test/ui/issues/issue-18183.stderr b/src/test/ui/issues/issue-18183.stderr index cf33124bc950a..c8f8ac9296dc0 100644 --- a/src/test/ui/issues/issue-18183.stderr +++ b/src/test/ui/issues/issue-18183.stderr @@ -1,7 +1,7 @@ error[E0128]: type parameters with a default cannot use forward declared identifiers --> $DIR/issue-18183.rs:1:20 | -LL | pub struct Foo(Bar); //~ ERROR E0128 +LL | pub struct Foo(Bar); | ^^^ defaulted type parameters cannot be forward declared error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18188.rs b/src/test/ui/issues/issue-18188.rs index 8e39dc15597e7..4d0c4464759c6 100644 --- a/src/test/ui/issues/issue-18188.rs +++ b/src/test/ui/issues/issue-18188.rs @@ -5,7 +5,7 @@ pub trait Promisable: Send + Sync {} impl Promisable for T {} pub fn propagate<'a, T, E, F, G>(mut action: F) - -> Box) -> Result + 'a> + -> Box) -> Result + 'a> where T: Promisable + Clone + 'a, E: Promisable + Clone + 'a, diff --git a/src/test/ui/issues/issue-18294.stderr b/src/test/ui/issues/issue-18294.stderr index f3e8ab1a31307..d10242434b094 100644 --- a/src/test/ui/issues/issue-18294.stderr +++ b/src/test/ui/issues/issue-18294.stderr @@ -1,9 +1,10 @@ -error[E0658]: casting pointers to integers in constants is unstable (see issue #51910) +error[E0658]: casting pointers to integers in constants is unstable --> $DIR/issue-18294.rs:3:31 | -LL | const Y: usize = unsafe { &X as *const u32 as usize }; //~ ERROR is unstable +LL | const Y: usize = unsafe { &X as *const u32 as usize }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51910 = help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18389.stderr b/src/test/ui/issues/issue-18389.stderr index 02ff6b6d5bff4..090487ee8fdbf 100644 --- a/src/test/ui/issues/issue-18389.stderr +++ b/src/test/ui/issues/issue-18389.stderr @@ -5,7 +5,7 @@ LL | trait Private { | - `Private<::P, ::R>` declared as private ... LL | / pub trait Public: Private< -LL | | //~^ ERROR private trait `Private<::P, ::R>` in public interface +LL | | LL | | ::P, LL | | ::R ... | diff --git a/src/test/ui/issues/issue-18400.stderr b/src/test/ui/issues/issue-18400.stderr index 9c496cac88e7d..85cfa5663f13c 100644 --- a/src/test/ui/issues/issue-18400.stderr +++ b/src/test/ui/issues/issue-18400.stderr @@ -4,7 +4,7 @@ error[E0275]: overflow evaluating the requirement `_: std::marker::Sized` LL | 0.contains(bits); | ^^^^^^^^ | - = help: consider adding a `#![recursion_limit="128"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate = note: required because of the requirements on the impl of `Set<&[_]>` for `{integer}` = note: required because of the requirements on the impl of `Set<&[&[_]]>` for `{integer}` = note: required because of the requirements on the impl of `Set<&[&[&[_]]]>` for `{integer}` @@ -69,6 +69,70 @@ LL | 0.contains(bits); = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18423.stderr b/src/test/ui/issues/issue-18423.stderr index 96652767a05c3..141fd27be3649 100644 --- a/src/test/ui/issues/issue-18423.stderr +++ b/src/test/ui/issues/issue-18423.stderr @@ -1,7 +1,7 @@ error[E0107]: wrong number of lifetime arguments: expected 0, found 1 --> $DIR/issue-18423.rs:4:12 | -LL | x: Box<'a, isize> //~ ERROR wrong number of lifetime arguments +LL | x: Box<'a, isize> | ^^ unexpected lifetime argument error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18446-2.rs b/src/test/ui/issues/issue-18446-2.rs index 2f05ece31979f..3e04a914d4586 100644 --- a/src/test/ui/issues/issue-18446-2.rs +++ b/src/test/ui/issues/issue-18446-2.rs @@ -6,7 +6,7 @@ trait T { fn foo(&self) -> i32 { 0 } } -impl<'a> T + 'a { +impl<'a> dyn T + 'a { fn foo(&self) -> i32 { 1 } } diff --git a/src/test/ui/issues/issue-18446.rs b/src/test/ui/issues/issue-18446.rs index 64c89df3868cc..a2e238da03a3e 100644 --- a/src/test/ui/issues/issue-18446.rs +++ b/src/test/ui/issues/issue-18446.rs @@ -5,7 +5,7 @@ trait T { fn foo(&self); } -impl<'a> T + 'a { +impl<'a> dyn T + 'a { fn foo(&self) {} } @@ -14,6 +14,6 @@ impl T for i32 { } fn main() { - let x: &T = &0i32; + let x: &dyn T = &0i32; x.foo(); //~ ERROR multiple applicable items in scope [E0034] } diff --git a/src/test/ui/issues/issue-18446.stderr b/src/test/ui/issues/issue-18446.stderr index 8aff0309aa77f..e6afc4c13a912 100644 --- a/src/test/ui/issues/issue-18446.stderr +++ b/src/test/ui/issues/issue-18446.stderr @@ -1,7 +1,7 @@ error[E0034]: multiple applicable items in scope --> $DIR/issue-18446.rs:18:7 | -LL | x.foo(); //~ ERROR multiple applicable items in scope [E0034] +LL | x.foo(); | ^^^ multiple `foo` found | note: candidate #1 is defined in an impl for the type `dyn T` diff --git a/src/test/ui/issues/issue-18532.stderr b/src/test/ui/issues/issue-18532.stderr index 400890348a126..4c224eb2d2430 100644 --- a/src/test/ui/issues/issue-18532.stderr +++ b/src/test/ui/issues/issue-18532.stderr @@ -1,7 +1,7 @@ error[E0618]: expected function, found `!` --> $DIR/issue-18532.rs:6:5 | -LL | (return)((),()); //~ ERROR expected function, found `!` +LL | (return)((),()); | ^^^^^^^^------- | | | call expression requires function diff --git a/src/test/ui/issues/issue-18566.nll.stderr b/src/test/ui/issues/issue-18566.nll.stderr deleted file mode 100644 index 8db78935f839c..0000000000000 --- a/src/test/ui/issues/issue-18566.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0499]: cannot borrow `*s` as mutable more than once at a time - --> $DIR/issue-18566.rs:23:19 - | -LL | MyPtr(s).poke(s); - | - ---- ^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/issues/issue-18566.stderr b/src/test/ui/issues/issue-18566.stderr index 90c3af48eb482..8db78935f839c 100644 --- a/src/test/ui/issues/issue-18566.stderr +++ b/src/test/ui/issues/issue-18566.stderr @@ -2,9 +2,9 @@ error[E0499]: cannot borrow `*s` as mutable more than once at a time --> $DIR/issue-18566.rs:23:19 | LL | MyPtr(s).poke(s); - | - ^- first borrow ends here - | | | - | | second mutable borrow occurs here + | - ---- ^ second mutable borrow occurs here + | | | + | | first borrow later used by call | first mutable borrow occurs here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18611.stderr b/src/test/ui/issues/issue-18611.stderr index 8fa7694dc6c36..22c3470b61ede 100644 --- a/src/test/ui/issues/issue-18611.stderr +++ b/src/test/ui/issues/issue-18611.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `isize: HasState` is not satisfied --> $DIR/issue-18611.rs:1:1 | LL | / fn add_state(op: ::State) { -LL | | //~^ ERROR `isize: HasState` is not satisfied +LL | | LL | | } | |_^ the trait `HasState` is not implemented for `isize` diff --git a/src/test/ui/issues/issue-1871.stderr b/src/test/ui/issues/issue-1871.stderr index 10b0825c34e1b..fecd689251b32 100644 --- a/src/test/ui/issues/issue-1871.stderr +++ b/src/test/ui/issues/issue-1871.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `honk` found for type `{integer}` in the current scope --> $DIR/issue-1871.rs:7:9 | -LL | f.honk() //~ ERROR no method named `honk` found +LL | f.honk() | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18783.nll.stderr b/src/test/ui/issues/issue-18783.nll.stderr deleted file mode 100644 index f49a2d7a2b2fd..0000000000000 --- a/src/test/ui/issues/issue-18783.nll.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0499]: cannot borrow `y` as mutable more than once at a time - --> $DIR/issue-18783.rs:7:21 - | -LL | c.push(Box::new(|| y = 0)); - | -- - first borrow occurs due to use of `y` in closure - | | - | first mutable borrow occurs here -LL | c.push(Box::new(|| y = 0)); - | ^^ - second borrow occurs due to use of `y` in closure - | | - | second mutable borrow occurs here -LL | //~^ ERROR cannot borrow `y` as mutable more than once at a time -LL | } - | - first borrow might be used here, when `c` is dropped and runs the destructor for type `std::cell::RefCell>>` - -error[E0499]: cannot borrow `y` as mutable more than once at a time - --> $DIR/issue-18783.rs:16:29 - | -LL | Push::push(&c, Box::new(|| y = 0)); - | -- - first borrow occurs due to use of `y` in closure - | | - | first mutable borrow occurs here -LL | Push::push(&c, Box::new(|| y = 0)); - | ^^ - second borrow occurs due to use of `y` in closure - | | - | second mutable borrow occurs here -LL | //~^ ERROR cannot borrow `y` as mutable more than once at a time -LL | } - | - first borrow might be used here, when `c` is dropped and runs the destructor for type `std::cell::RefCell>>` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/issues/issue-18783.rs b/src/test/ui/issues/issue-18783.rs index b84a1adb42569..d4851ac14187e 100644 --- a/src/test/ui/issues/issue-18783.rs +++ b/src/test/ui/issues/issue-18783.rs @@ -18,11 +18,11 @@ fn ufcs() { } trait Push<'c> { - fn push<'f: 'c>(&self, push: Box); + fn push<'f: 'c>(&self, push: Box); } -impl<'c> Push<'c> for RefCell>> { - fn push<'f: 'c>(&self, fun: Box) { +impl<'c> Push<'c> for RefCell>> { + fn push<'f: 'c>(&self, fun: Box) { self.borrow_mut().push(fun) } } diff --git a/src/test/ui/issues/issue-18783.stderr b/src/test/ui/issues/issue-18783.stderr index 68eb5167ecbdc..047b42578a224 100644 --- a/src/test/ui/issues/issue-18783.stderr +++ b/src/test/ui/issues/issue-18783.stderr @@ -2,31 +2,31 @@ error[E0499]: cannot borrow `y` as mutable more than once at a time --> $DIR/issue-18783.rs:7:21 | LL | c.push(Box::new(|| y = 0)); - | -- - previous borrow occurs due to use of `y` in closure + | -- - first borrow occurs due to use of `y` in closure | | | first mutable borrow occurs here LL | c.push(Box::new(|| y = 0)); - | ^^ - borrow occurs due to use of `y` in closure + | ^^ - second borrow occurs due to use of `y` in closure | | | second mutable borrow occurs here -LL | //~^ ERROR cannot borrow `y` as mutable more than once at a time +LL | LL | } - | - first borrow ends here + | - first borrow might be used here, when `c` is dropped and runs the destructor for type `std::cell::RefCell>>` error[E0499]: cannot borrow `y` as mutable more than once at a time --> $DIR/issue-18783.rs:16:29 | LL | Push::push(&c, Box::new(|| y = 0)); - | -- - previous borrow occurs due to use of `y` in closure + | -- - first borrow occurs due to use of `y` in closure | | | first mutable borrow occurs here LL | Push::push(&c, Box::new(|| y = 0)); - | ^^ - borrow occurs due to use of `y` in closure + | ^^ - second borrow occurs due to use of `y` in closure | | | second mutable borrow occurs here -LL | //~^ ERROR cannot borrow `y` as mutable more than once at a time +LL | LL | } - | - first borrow ends here + | - first borrow might be used here, when `c` is dropped and runs the destructor for type `std::cell::RefCell>>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-18819.rs b/src/test/ui/issues/issue-18819.rs index 80db056e7dd3a..e634c55f824fd 100644 --- a/src/test/ui/issues/issue-18819.rs +++ b/src/test/ui/issues/issue-18819.rs @@ -8,7 +8,7 @@ impl Foo for X { type Item = bool; } -fn print_x(_: &Foo, extra: &str) { +fn print_x(_: &dyn Foo, extra: &str) { println!("{}", extra); } diff --git a/src/test/ui/issues/issue-18819.stderr b/src/test/ui/issues/issue-18819.stderr index eb7e4ad405fa1..41e8470ecd04f 100644 --- a/src/test/ui/issues/issue-18819.stderr +++ b/src/test/ui/issues/issue-18819.stderr @@ -1,8 +1,8 @@ error[E0061]: this function takes 2 parameters but 1 parameter was supplied --> $DIR/issue-18819.rs:16:5 | -LL | fn print_x(_: &Foo, extra: &str) { - | ------------------------------------------- defined here +LL | fn print_x(_: &dyn Foo, extra: &str) { + | ----------------------------------------------- defined here ... LL | print_x(X); | ^^^^^^^^^^ expected 2 parameters diff --git a/src/test/ui/issues/issue-18919.rs b/src/test/ui/issues/issue-18919.rs index 9db3084918239..91fbb13cd6988 100644 --- a/src/test/ui/issues/issue-18919.rs +++ b/src/test/ui/issues/issue-18919.rs @@ -1,4 +1,4 @@ -type FuncType<'f> = Fn(&isize) -> isize + 'f; +type FuncType<'f> = dyn Fn(&isize) -> isize + 'f; fn ho_func(f: Option) { //~^ ERROR the size for values of type diff --git a/src/test/ui/issues/issue-18919.stderr b/src/test/ui/issues/issue-18919.stderr index ca717a3c49b81..87528652bd482 100644 --- a/src/test/ui/issues/issue-18919.stderr +++ b/src/test/ui/issues/issue-18919.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `dyn for<'r> std::ops::Fn(&'r isize) - --> $DIR/issue-18919.rs:3:1 | LL | / fn ho_func(f: Option) { -LL | | //~^ ERROR the size for values of type +LL | | LL | | } | |_^ doesn't have a size known at compile-time | diff --git a/src/test/ui/issues/issue-18937.rs b/src/test/ui/issues/issue-18937.rs index f3824765f237a..ab4c9c736d896 100644 --- a/src/test/ui/issues/issue-18937.rs +++ b/src/test/ui/issues/issue-18937.rs @@ -6,7 +6,7 @@ use std::fmt; struct MyString<'a>(&'a String); struct B { - list: Vec>, + list: Vec>, } trait A<'a> { diff --git a/src/test/ui/issues/issue-18937.stderr b/src/test/ui/issues/issue-18937.stderr index 91182224ad0a6..ac302caecc335 100644 --- a/src/test/ui/issues/issue-18937.stderr +++ b/src/test/ui/issues/issue-18937.stderr @@ -6,7 +6,7 @@ LL | | where F: fmt::Debug + 'a, LL | | Self: Sized; | |__________________________- definition of `foo` from trait ... -LL | / fn foo(&mut self, f: F) //~ ERROR impl has stricter +LL | / fn foo(&mut self, f: F) LL | | where F: fmt::Debug + 'static, LL | | { LL | | self.list.push(Box::new(f)); diff --git a/src/test/ui/issues/issue-18959.rs b/src/test/ui/issues/issue-18959.rs index b07800928bc22..4b6f04e251b94 100644 --- a/src/test/ui/issues/issue-18959.rs +++ b/src/test/ui/issues/issue-18959.rs @@ -8,13 +8,13 @@ impl Foo for Thing { } #[inline(never)] -fn foo(b: &Bar) { +fn foo(b: &dyn Bar) { //~^ ERROR E0038 b.foo(&0) } fn main() { let mut thing = Thing; - let test: &Bar = &mut thing; + let test: &dyn Bar = &mut thing; foo(test); } diff --git a/src/test/ui/issues/issue-18959.stderr b/src/test/ui/issues/issue-18959.stderr index 939390102c387..63c33b7f4472d 100644 --- a/src/test/ui/issues/issue-18959.stderr +++ b/src/test/ui/issues/issue-18959.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/issue-18959.rs:11:1 | -LL | fn foo(b: &Bar) { - | ^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object +LL | fn foo(b: &dyn Bar) { + | ^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object | = note: method `foo` has generic type parameters diff --git a/src/test/ui/issues/issue-18988.rs b/src/test/ui/issues/issue-18988.rs index e03934866495b..7fe662e907d73 100644 --- a/src/test/ui/issues/issue-18988.rs +++ b/src/test/ui/issues/issue-18988.rs @@ -3,7 +3,7 @@ pub trait Foo : Send { } pub struct MyFoo { - children: Vec>, + children: Vec>, } impl Foo for MyFoo { } diff --git a/src/test/ui/issues/issue-19163.nll.stderr b/src/test/ui/issues/issue-19163.nll.stderr deleted file mode 100644 index af509aa59d481..0000000000000 --- a/src/test/ui/issues/issue-19163.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/issue-19163.rs:9:14 - | -LL | mywrite!(&v, "Hello world"); - | ^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/issues/issue-19163.rs b/src/test/ui/issues/issue-19163.rs index 20d3244027da1..d98c5912af2ee 100644 --- a/src/test/ui/issues/issue-19163.rs +++ b/src/test/ui/issues/issue-19163.rs @@ -7,5 +7,5 @@ use std::io::Write; fn main() { let mut v = vec![]; mywrite!(&v, "Hello world"); - //~^ error: cannot borrow immutable borrowed content as mutable + //~^ ERROR cannot borrow data in a `&` reference as mutable } diff --git a/src/test/ui/issues/issue-19163.stderr b/src/test/ui/issues/issue-19163.stderr index 242ceaedcb0b4..af509aa59d481 100644 --- a/src/test/ui/issues/issue-19163.stderr +++ b/src/test/ui/issues/issue-19163.stderr @@ -1,4 +1,4 @@ -error[E0596]: cannot borrow immutable borrowed content as mutable +error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/issue-19163.rs:9:14 | LL | mywrite!(&v, "Hello world"); diff --git a/src/test/ui/issues/issue-19380.rs b/src/test/ui/issues/issue-19380.rs index efbc5a0346ac5..5c10e2067e408 100644 --- a/src/test/ui/issues/issue-19380.rs +++ b/src/test/ui/issues/issue-19380.rs @@ -8,7 +8,7 @@ impl Qiz for Foo { } struct Bar { - foos: &'static [&'static (Qiz + 'static)] + foos: &'static [&'static (dyn Qiz + 'static)] //~^ ERROR E0038 } diff --git a/src/test/ui/issues/issue-19380.stderr b/src/test/ui/issues/issue-19380.stderr index 060e160f2e484..27e3ff57bf9ab 100644 --- a/src/test/ui/issues/issue-19380.stderr +++ b/src/test/ui/issues/issue-19380.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Qiz` cannot be made into an object --> $DIR/issue-19380.rs:11:3 | -LL | foos: &'static [&'static (Qiz + 'static)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object +LL | foos: &'static [&'static (dyn Qiz + 'static)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object | = note: method `qiz` has no receiver diff --git a/src/test/ui/issues/issue-19404.rs b/src/test/ui/issues/issue-19404.rs index cdec74fe9684d..59544393bae05 100644 --- a/src/test/ui/issues/issue-19404.rs +++ b/src/test/ui/issues/issue-19404.rs @@ -12,10 +12,10 @@ trait Component: 'static {} impl Component for Engine {} trait Env { - fn get_component_type_id(&self, type_id: TypeId) -> Option>; + fn get_component_type_id(&self, type_id: TypeId) -> Option>; } -impl<'a> Env+'a { +impl<'a> dyn Env + 'a { fn get_component(&self) -> Option> { let x = self.get_component_type_id(TypeId::of::()); None @@ -23,13 +23,13 @@ impl<'a> Env+'a { } trait Figment { - fn init(&mut self, env: &Env); + fn init(&mut self, env: &dyn Env); } struct MyFigment; impl Figment for MyFigment { - fn init(&mut self, env: &Env) { + fn init(&mut self, env: &dyn Env) { let engine = env.get_component::(); } } diff --git a/src/test/ui/issues/issue-19482.rs b/src/test/ui/issues/issue-19482.rs index 6ba334905499e..9e4b77d87f8b5 100644 --- a/src/test/ui/issues/issue-19482.rs +++ b/src/test/ui/issues/issue-19482.rs @@ -7,7 +7,7 @@ trait Foo { fn dummy(&self) { } } -fn bar(x: &Foo) {} +fn bar(x: &dyn Foo) {} //~^ ERROR the associated type `A` (from the trait `Foo`) must be specified pub fn main() {} diff --git a/src/test/ui/issues/issue-19482.stderr b/src/test/ui/issues/issue-19482.stderr index a8894f84e743d..f1e5419c71229 100644 --- a/src/test/ui/issues/issue-19482.stderr +++ b/src/test/ui/issues/issue-19482.stderr @@ -4,8 +4,8 @@ error[E0191]: the value of the associated type `A` (from the trait `Foo`) must b LL | type A; | ------- `A` defined here ... -LL | fn bar(x: &Foo) {} - | ^^^ associated type `A` must be specified +LL | fn bar(x: &dyn Foo) {} + | ^^^^^^^ associated type `A` must be specified error: aborting due to previous error diff --git a/src/test/ui/issues/issue-19498.stderr b/src/test/ui/issues/issue-19498.stderr index fd5e48bde160a..cc1d649d61093 100644 --- a/src/test/ui/issues/issue-19498.stderr +++ b/src/test/ui/issues/issue-19498.stderr @@ -4,7 +4,7 @@ error[E0255]: the name `A` is defined multiple times LL | use self::A; | ------- previous import of the module `A` here LL | use self::B; -LL | mod A {} //~ ERROR the name `A` is defined multiple times +LL | mod A {} | ^^^^^ `A` redefined here | = note: `A` must be defined only once in the type namespace of this module @@ -19,7 +19,7 @@ error[E0255]: the name `B` is defined multiple times LL | use self::B; | ------- previous import of the module `B` here ... -LL | pub mod B {} //~ ERROR the name `B` is defined multiple times +LL | pub mod B {} | ^^^^^^^^^ `B` redefined here | = note: `B` must be defined only once in the type namespace of this module @@ -33,7 +33,7 @@ error[E0255]: the name `D` is defined multiple times | LL | use C::D; | ---- previous import of the module `D` here -LL | mod D {} //~ ERROR the name `D` is defined multiple times +LL | mod D {} | ^^^^^ `D` redefined here | = note: `D` must be defined only once in the type namespace of this module diff --git a/src/test/ui/issues/issue-19521.stderr b/src/test/ui/issues/issue-19521.stderr index 9005317736a9a..a43368be58339 100644 --- a/src/test/ui/issues/issue-19521.stderr +++ b/src/test/ui/issues/issue-19521.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `homura` found for type `&'static str` in the current scope --> $DIR/issue-19521.rs:2:8 | -LL | "".homura()(); //~ ERROR no method named `homura` found +LL | "".homura()(); | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-19538.rs b/src/test/ui/issues/issue-19538.rs index 9f0b08d6c357c..7054ef41b1c82 100644 --- a/src/test/ui/issues/issue-19538.rs +++ b/src/test/ui/issues/issue-19538.rs @@ -14,7 +14,7 @@ impl Bar for Thing { } fn main() { let mut thing = Thing; - let test: &mut Bar = &mut thing; + let test: &mut dyn Bar = &mut thing; //~^ ERROR E0038 //~| ERROR E0038 } diff --git a/src/test/ui/issues/issue-19538.stderr b/src/test/ui/issues/issue-19538.stderr index d0f05a41d4d3a..e5da0a9b0dac3 100644 --- a/src/test/ui/issues/issue-19538.stderr +++ b/src/test/ui/issues/issue-19538.stderr @@ -1,16 +1,16 @@ error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/issue-19538.rs:17:15 | -LL | let test: &mut Bar = &mut thing; - | ^^^^^^^^ the trait `Bar` cannot be made into an object +LL | let test: &mut dyn Bar = &mut thing; + | ^^^^^^^^^^^^ the trait `Bar` cannot be made into an object | = note: method `foo` has generic type parameters error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/issue-19538.rs:17:26 + --> $DIR/issue-19538.rs:17:30 | -LL | let test: &mut Bar = &mut thing; - | ^^^^^^^^^^ the trait `Bar` cannot be made into an object +LL | let test: &mut dyn Bar = &mut thing; + | ^^^^^^^^^^ the trait `Bar` cannot be made into an object | = note: method `foo` has generic type parameters = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&mut dyn Bar>` for `&mut Thing` diff --git a/src/test/ui/issues/issue-19601.rs b/src/test/ui/issues/issue-19601.rs index faaa2db370eea..176e6ba410670 100644 --- a/src/test/ui/issues/issue-19601.rs +++ b/src/test/ui/issues/issue-19601.rs @@ -1,9 +1,6 @@ -// compile-pass -// skip-codegen -#![allow(warnings)] +// check-pass + trait A {} struct B where B: A> { t: T } - -fn main() { -} +fn main() {} diff --git a/src/test/ui/issues/issue-1962.stderr b/src/test/ui/issues/issue-1962.stderr index f2c540b74515c..afef59c52642f 100644 --- a/src/test/ui/issues/issue-1962.stderr +++ b/src/test/ui/issues/issue-1962.stderr @@ -1,7 +1,7 @@ error: denote infinite loops with `loop { ... }` --> $DIR/issue-1962.rs:4:3 | -LL | while true { //~ ERROR denote infinite loops with `loop +LL | while true { | ^^^^^^^^^^ help: use `loop` | = note: requested on the command line with `-D while-true` diff --git a/src/test/ui/issues/issue-19692.stderr b/src/test/ui/issues/issue-19692.stderr index 1ed1967667448..5e576f11583eb 100644 --- a/src/test/ui/issues/issue-19692.stderr +++ b/src/test/ui/issues/issue-19692.stderr @@ -4,7 +4,7 @@ error[E0599]: no method named `kaname` found for type `Homura` in the current sc LL | struct Homura; | -------------- method `kaname` not found for this ... -LL | let Some(ref madoka) = Some(homura.kaname()); //~ ERROR no method named `kaname` found +LL | let Some(ref madoka) = Some(homura.kaname()); | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index 7ba683a6891ba..c85ce0eb3a75e 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -1,7 +1,7 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:3:28 | -LL | type Foo = fn(&u8, &u8) -> &u8; //~ ERROR missing lifetime specifier +LL | type Foo = fn(&u8, &u8) -> &u8; | ^ expected lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 @@ -9,7 +9,7 @@ LL | type Foo = fn(&u8, &u8) -> &u8; //~ ERROR missing lifetime specifier error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:5:27 | -LL | fn bar &u8>(f: &F) {} //~ ERROR missing lifetime specifier +LL | fn bar &u8>(f: &F) {} | ^ expected lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 diff --git a/src/test/ui/issues/issue-19883.stderr b/src/test/ui/issues/issue-19883.stderr index e370b2ec1cb42..738add1684004 100644 --- a/src/test/ui/issues/issue-19883.stderr +++ b/src/test/ui/issues/issue-19883.stderr @@ -6,4 +6,3 @@ LL | >::Dst error: aborting due to previous error -For more information about this error, try `rustc --explain E0576`. diff --git a/src/test/ui/issues/issue-19991.stderr b/src/test/ui/issues/issue-19991.stderr index ee5d363c4bd2b..d9ea910adef50 100644 --- a/src/test/ui/issues/issue-19991.stderr +++ b/src/test/ui/issues/issue-19991.stderr @@ -1,16 +1,19 @@ error[E0317]: if may be missing an else clause --> $DIR/issue-19991.rs:5:5 | -LL | / if let Some(homura) = Some("madoka") { //~ ERROR missing an else clause -LL | | //~| expected type `()` -LL | | //~| found type `{integer}` -LL | | //~| expected (), found integer +LL | / if let Some(homura) = Some("madoka") { +LL | | +LL | | +LL | | LL | | 765 + | | --- found here LL | | }; | |_____^ expected (), found integer | = note: expected type `()` found type `{integer}` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20005.stderr b/src/test/ui/issues/issue-20005.stderr index 672d78f65e9f7..e271005e74d1d 100644 --- a/src/test/ui/issues/issue-20005.stderr +++ b/src/test/ui/issues/issue-20005.stderr @@ -1,7 +1,7 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation time --> $DIR/issue-20005.rs:8:5 | -LL | / fn to( //~ ERROR the size for values of type +LL | / fn to( LL | | self LL | | ) -> >::Result where Dst: From { LL | | From::from(self) diff --git a/src/test/ui/issues/issue-20091.rs b/src/test/ui/issues/issue-20091.rs index 4d86a17b6f1fb..4ea567d25ca53 100644 --- a/src/test/ui/issues/issue-20091.rs +++ b/src/test/ui/issues/issue-20091.rs @@ -3,6 +3,7 @@ // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes #![feature(os)] diff --git a/src/test/ui/issues/issue-20261.stderr b/src/test/ui/issues/issue-20261.stderr index 5665f5893f428..c6c3f32dfe7d8 100644 --- a/src/test/ui/issues/issue-20261.stderr +++ b/src/test/ui/issues/issue-20261.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `&(_,)` --> $DIR/issue-20261.rs:4:11 | LL | for (ref i,) in [].iter() { diff --git a/src/test/ui/issues/issue-20313.stderr b/src/test/ui/issues/issue-20313.stderr index 01673630cf189..405e717c358e6 100644 --- a/src/test/ui/issues/issue-20313.stderr +++ b/src/test/ui/issues/issue-20313.stderr @@ -1,9 +1,10 @@ -error[E0658]: linking to LLVM intrinsics is experimental (see issue #29602) +error[E0658]: linking to LLVM intrinsics is experimental --> $DIR/issue-20313.rs:3:5 | -LL | fn sqrt(x: f32) -> f32; //~ ERROR linking to LLVM intrinsics is experimental +LL | fn sqrt(x: f32) -> f32; | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29602 = help: add #![feature(link_llvm_intrinsics)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20396.rs b/src/test/ui/issues/issue-20396.rs index b6dfffbd69ebb..0e69b7f3d1e0c 100644 --- a/src/test/ui/issues/issue-20396.rs +++ b/src/test/ui/issues/issue-20396.rs @@ -10,7 +10,7 @@ trait Foo { enum Bar { Bla(T) } struct Baz<'a> { - inner: for<'b> Foo> + 'a, + inner: dyn for<'b> Foo> + 'a, } fn main() {} diff --git a/src/test/ui/issues/issue-20413.rs b/src/test/ui/issues/issue-20413.rs index 34094fe6a44e2..7eb6d5c0ecbaa 100644 --- a/src/test/ui/issues/issue-20413.rs +++ b/src/test/ui/issues/issue-20413.rs @@ -8,6 +8,7 @@ struct NoData; impl Foo for T where NoData: Foo { //~^ ERROR: overflow evaluating the requirement fn answer(self) { + //~^ ERROR: overflow evaluating the requirement let val: NoData = NoData; } } diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr index 1c353fec8aabf..762816c5a98c4 100644 --- a/src/test/ui/issues/issue-20413.stderr +++ b/src/test/ui/issues/issue-20413.stderr @@ -2,22 +2,87 @@ error[E0392]: parameter `T` is never used --> $DIR/issue-20413.rs:5:15 | LL | struct NoData; - | ^ unused type parameter + | ^ unused parameter | = help: consider removing `T` or using a marker such as `std::marker::PhantomData` -error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` +error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/issue-20413.rs:8:1 | LL | / impl Foo for T where NoData: Foo { -LL | | //~^ ERROR: overflow evaluating the requirement +LL | | LL | | fn answer(self) { +LL | | LL | | let val: NoData = NoData; LL | | } LL | | } | |_^ | - = help: consider adding a `#![recursion_limit="128"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` @@ -87,7 +152,150 @@ note: required by `Foo` LL | trait Foo { | ^^^^^^^^^ -error: aborting due to 2 previous errors +error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` + --> $DIR/issue-20413.rs:10:3 + | +LL | / fn answer(self) { +LL | | +LL | | let val: NoData = NoData; +LL | | } + | |___^ + | + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>` + = note: required because of the requirements on the impl of `Foo` for `NoData` +note: required by `Foo` + --> $DIR/issue-20413.rs:1:1 + | +LL | trait Foo { + | ^^^^^^^^^ + +error: aborting due to 3 previous errors -Some errors occurred: E0275, E0392. +Some errors have detailed explanations: E0275, E0392. For more information about an error, try `rustc --explain E0275`. diff --git a/src/test/ui/issues/issue-20605.rs b/src/test/ui/issues/issue-20605.rs index 11a2a573ea677..17b7d32ebf59b 100644 --- a/src/test/ui/issues/issue-20605.rs +++ b/src/test/ui/issues/issue-20605.rs @@ -1,4 +1,4 @@ -fn changer<'a>(mut things: Box>) { +fn changer<'a>(mut things: Box>) { for item in *things { *item = 0 } //~^ ERROR the size for values of type } diff --git a/src/test/ui/issues/issue-20605.stderr b/src/test/ui/issues/issue-20605.stderr index f779fe51bf2d1..89df58dd2dc1b 100644 --- a/src/test/ui/issues/issue-20605.stderr +++ b/src/test/ui/issues/issue-20605.stderr @@ -1,10 +1,10 @@ -error[E0277]: the size for values of type `dyn std::iter::Iterator` cannot be known at compilation time +error[E0277]: the size for values of type `dyn std::iter::Iterator` cannot be known at compilation time --> $DIR/issue-20605.rs:2:17 | LL | for item in *things { *item = 0 } | ^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn std::iter::Iterator` + = help: the trait `std::marker::Sized` is not implemented for `dyn std::iter::Iterator` = note: to learn more, visit = note: required by `std::iter::IntoIterator::into_iter` diff --git a/src/test/ui/issues/issue-20616-1.stderr b/src/test/ui/issues/issue-20616-1.stderr index 522db41241229..143486c8f5ad6 100644 --- a/src/test/ui/issues/issue-20616-1.stderr +++ b/src/test/ui/issues/issue-20616-1.stderr @@ -1,7 +1,7 @@ error: expected one of `,`, `:`, or `>`, found `T` --> $DIR/issue-20616-1.rs:9:16 | -LL | type Type_1<'a T> = &'a T; //~ error: expected one of `,`, `:`, or `>`, found `T` +LL | type Type_1<'a T> = &'a T; | ^ expected one of `,`, `:`, or `>` here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-2.stderr b/src/test/ui/issues/issue-20616-2.stderr index 544219eb6cfae..1152dec8bad1b 100644 --- a/src/test/ui/issues/issue-20616-2.stderr +++ b/src/test/ui/issues/issue-20616-2.stderr @@ -1,7 +1,7 @@ error: expected one of `,` or `>`, found `(` --> $DIR/issue-20616-2.rs:12:31 | -LL | type Type_2 = Type_1_<'static ()>; //~ error: expected one of `,` or `>`, found `(` +LL | type Type_2 = Type_1_<'static ()>; | ^ expected one of `,` or `>` here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20692.rs b/src/test/ui/issues/issue-20692.rs index ea89bca78d076..2a05bba7b1632 100644 --- a/src/test/ui/issues/issue-20692.rs +++ b/src/test/ui/issues/issue-20692.rs @@ -4,7 +4,7 @@ fn f(x: &T) { let _ = x //~^ ERROR `Array` cannot be made into an object as - &Array; + &dyn Array; //~^ ERROR `Array` cannot be made into an object } diff --git a/src/test/ui/issues/issue-20692.stderr b/src/test/ui/issues/issue-20692.stderr index acc223c0b2dfc..66309394a426d 100644 --- a/src/test/ui/issues/issue-20692.stderr +++ b/src/test/ui/issues/issue-20692.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Array` cannot be made into an object --> $DIR/issue-20692.rs:7:5 | -LL | &Array; - | ^^^^^^ the trait `Array` cannot be made into an object +LL | &dyn Array; + | ^^^^^^^^^^ the trait `Array` cannot be made into an object | = note: the trait cannot require that `Self : Sized` diff --git a/src/test/ui/issues/issue-20714.stderr b/src/test/ui/issues/issue-20714.stderr index 9cd6a27c12a28..456aff05750dd 100644 --- a/src/test/ui/issues/issue-20714.stderr +++ b/src/test/ui/issues/issue-20714.stderr @@ -4,7 +4,7 @@ error[E0618]: expected function, found `G` LL | struct G; | --------- `G` defined here ... -LL | let g = G(); //~ ERROR: expected function, found `G` +LL | let g = G(); | ^-- | | | call expression requires function diff --git a/src/test/ui/issues/issue-20772.rs b/src/test/ui/issues/issue-20772.rs index 36551e7014f10..1500bc831528a 100644 --- a/src/test/ui/issues/issue-20772.rs +++ b/src/test/ui/issues/issue-20772.rs @@ -1,6 +1,5 @@ trait T : Iterator //~^ ERROR cycle detected -//~| ERROR associated type `Item` not found for `Self` {} fn main() {} diff --git a/src/test/ui/issues/issue-20772.stderr b/src/test/ui/issues/issue-20772.stderr index 7dc4e43fd573d..d64636310a368 100644 --- a/src/test/ui/issues/issue-20772.stderr +++ b/src/test/ui/issues/issue-20772.stderr @@ -2,8 +2,7 @@ error[E0391]: cycle detected when computing the supertraits of `T` --> $DIR/issue-20772.rs:1:1 | LL | / trait T : Iterator -LL | | //~^ ERROR cycle detected -LL | | //~| ERROR associated type `Item` not found for `Self` +LL | | LL | | {} | |__^ | @@ -12,18 +11,10 @@ note: cycle used when collecting item types in top-level module --> $DIR/issue-20772.rs:1:1 | LL | / trait T : Iterator -LL | | //~^ ERROR cycle detected -LL | | //~| ERROR associated type `Item` not found for `Self` +LL | | LL | | {} | |__^ -error[E0220]: associated type `Item` not found for `Self` - --> $DIR/issue-20772.rs:1:25 - | -LL | trait T : Iterator - | ^^^^^^^^^^ associated type `Item` not found - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0220, E0391. -For more information about an error, try `rustc --explain E0220`. +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/issues/issue-20801.nll.stderr b/src/test/ui/issues/issue-20801.nll.stderr deleted file mode 100644 index adcbe55aa325f..0000000000000 --- a/src/test/ui/issues/issue-20801.nll.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/issue-20801.rs:26:22 - | -LL | let a = unsafe { *mut_ref() }; - | ^^^^^^^^^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `mut_ref()` - -error[E0507]: cannot move out of borrowed content - --> $DIR/issue-20801.rs:29:22 - | -LL | let b = unsafe { *imm_ref() }; - | ^^^^^^^^^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `imm_ref()` - -error[E0507]: cannot move out of dereference of raw pointer - --> $DIR/issue-20801.rs:32:22 - | -LL | let c = unsafe { *mut_ptr() }; - | ^^^^^^^^^^ - | | - | cannot move out of dereference of raw pointer - | help: consider removing the `*`: `mut_ptr()` - -error[E0507]: cannot move out of dereference of raw pointer - --> $DIR/issue-20801.rs:35:22 - | -LL | let d = unsafe { *const_ptr() }; - | ^^^^^^^^^^^^ - | | - | cannot move out of dereference of raw pointer - | help: consider removing the `*`: `const_ptr()` - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/issues/issue-20801.rs b/src/test/ui/issues/issue-20801.rs index 6f8ce66d8f288..c3f136f2876b6 100644 --- a/src/test/ui/issues/issue-20801.rs +++ b/src/test/ui/issues/issue-20801.rs @@ -15,23 +15,23 @@ fn mut_ref() -> &'static mut T { } fn mut_ptr() -> *mut T { - unsafe { 0 as *mut T } + unsafe { core::ptr::null_mut() } } fn const_ptr() -> *const T { - unsafe { 0 as *const T } + unsafe { core::ptr::null() } } pub fn main() { let a = unsafe { *mut_ref() }; - //~^ ERROR cannot move out of borrowed content + //~^ ERROR cannot move out of a mutable reference let b = unsafe { *imm_ref() }; - //~^ ERROR cannot move out of borrowed content + //~^ ERROR cannot move out of a shared reference let c = unsafe { *mut_ptr() }; - //~^ ERROR cannot move out of dereference of raw pointer + //~^ ERROR cannot move out of a raw pointer let d = unsafe { *const_ptr() }; - //~^ ERROR cannot move out of dereference of raw pointer + //~^ ERROR cannot move out of a raw pointer } diff --git a/src/test/ui/issues/issue-20801.stderr b/src/test/ui/issues/issue-20801.stderr index 3e273919bb9e2..d276231dc0c96 100644 --- a/src/test/ui/issues/issue-20801.stderr +++ b/src/test/ui/issues/issue-20801.stderr @@ -1,26 +1,38 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of a mutable reference --> $DIR/issue-20801.rs:26:22 | LL | let a = unsafe { *mut_ref() }; - | ^^^^^^^^^^ cannot move out of borrowed content + | ^^^^^^^^^^ + | | + | move occurs because value has type `T`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*mut_ref()` -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of a shared reference --> $DIR/issue-20801.rs:29:22 | LL | let b = unsafe { *imm_ref() }; - | ^^^^^^^^^^ cannot move out of borrowed content + | ^^^^^^^^^^ + | | + | move occurs because value has type `T`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*imm_ref()` -error[E0507]: cannot move out of dereference of raw pointer +error[E0507]: cannot move out of a raw pointer --> $DIR/issue-20801.rs:32:22 | LL | let c = unsafe { *mut_ptr() }; - | ^^^^^^^^^^ cannot move out of dereference of raw pointer + | ^^^^^^^^^^ + | | + | move occurs because value has type `T`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*mut_ptr()` -error[E0507]: cannot move out of dereference of raw pointer +error[E0507]: cannot move out of a raw pointer --> $DIR/issue-20801.rs:35:22 | LL | let d = unsafe { *const_ptr() }; - | ^^^^^^^^^^^^ cannot move out of dereference of raw pointer + | ^^^^^^^^^^^^ + | | + | move occurs because value has type `T`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*const_ptr()` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-20831-debruijn.rs b/src/test/ui/issues/issue-20831-debruijn.rs index 6d3c7331a4579..ef4b1581fd874 100644 --- a/src/test/ui/issues/issue-20831-debruijn.rs +++ b/src/test/ui/issues/issue-20831-debruijn.rs @@ -12,7 +12,7 @@ pub trait Subscriber { pub trait Publisher<'a> { type Output; - fn subscribe(&mut self, _: Box + 'a>); + fn subscribe(&mut self, _: Box + 'a>); } pub trait Processor<'a> : Subscriber + Publisher<'a> { } @@ -20,12 +20,12 @@ pub trait Processor<'a> : Subscriber + Publisher<'a> { } impl<'a, P> Processor<'a> for P where P : Subscriber + Publisher<'a> { } struct MyStruct<'a> { - sub: Box + 'a> + sub: Box + 'a> } impl<'a> Publisher<'a> for MyStruct<'a> { type Output = u64; - fn subscribe(&mut self, t : Box::Output> + 'a>) { + fn subscribe(&mut self, t : Box::Output> + 'a>) { // Not obvious, but there is an implicit lifetime here -------^ //~^^ ERROR cannot infer //~| ERROR mismatched types diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr index fa7704cf17e3f..64e3cdc64c112 100644 --- a/src/test/ui/issues/issue-20831-debruijn.stderr +++ b/src/test/ui/issues/issue-20831-debruijn.stderr @@ -1,24 +1,24 @@ error[E0308]: mismatched types --> $DIR/issue-20831-debruijn.rs:28:5 | -LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { +LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { LL | | // Not obvious, but there is an implicit lifetime here -------^ -LL | | //~^^ ERROR cannot infer -LL | | //~| ERROR mismatched types +LL | | +LL | | ... | LL | | self.sub = t; LL | | } | |_____^ lifetime mismatch | = note: expected type `'a` - found type `` + found type `'_` note: the anonymous lifetime #2 defined on the method body at 28:5... --> $DIR/issue-20831-debruijn.rs:28:5 | -LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { +LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { LL | | // Not obvious, but there is an implicit lifetime here -------^ -LL | | //~^^ ERROR cannot infer -LL | | //~| ERROR mismatched types +LL | | +LL | | ... | LL | | self.sub = t; LL | | } @@ -32,17 +32,17 @@ LL | impl<'a> Publisher<'a> for MyStruct<'a> { error[E0308]: mismatched types --> $DIR/issue-20831-debruijn.rs:28:5 | -LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { +LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { LL | | // Not obvious, but there is an implicit lifetime here -------^ -LL | | //~^^ ERROR cannot infer -LL | | //~| ERROR mismatched types +LL | | +LL | | ... | LL | | self.sub = t; LL | | } | |_____^ lifetime mismatch | = note: expected type `'a` - found type `` + found type `'_` note: the lifetime 'a as defined on the impl at 26:6... --> $DIR/issue-20831-debruijn.rs:26:6 | @@ -51,10 +51,10 @@ LL | impl<'a> Publisher<'a> for MyStruct<'a> { note: ...does not necessarily outlive the anonymous lifetime #2 defined on the method body at 28:5 --> $DIR/issue-20831-debruijn.rs:28:5 | -LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { +LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { LL | | // Not obvious, but there is an implicit lifetime here -------^ -LL | | //~^^ ERROR cannot infer -LL | | //~| ERROR mismatched types +LL | | +LL | | ... | LL | | self.sub = t; LL | | } @@ -63,10 +63,10 @@ LL | | } error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/issue-20831-debruijn.rs:28:5 | -LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { +LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { LL | | // Not obvious, but there is an implicit lifetime here -------^ -LL | | //~^^ ERROR cannot infer -LL | | //~| ERROR mismatched types +LL | | +LL | | ... | LL | | self.sub = t; LL | | } @@ -75,10 +75,10 @@ LL | | } note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 28:5... --> $DIR/issue-20831-debruijn.rs:28:5 | -LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { +LL | / fn subscribe(&mut self, t : Box::Output> + 'a>) { LL | | // Not obvious, but there is an implicit lifetime here -------^ -LL | | //~^^ ERROR cannot infer -LL | | //~| ERROR mismatched types +LL | | +LL | | ... | LL | | self.sub = t; LL | | } @@ -94,5 +94,4 @@ LL | impl<'a> Publisher<'a> for MyStruct<'a> { error: aborting due to 3 previous errors -Some errors occurred: E0308, E0495. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-20939.rs b/src/test/ui/issues/issue-20939.rs index 259fff2e6c2f8..c0c222978970d 100644 --- a/src/test/ui/issues/issue-20939.rs +++ b/src/test/ui/issues/issue-20939.rs @@ -1,6 +1,6 @@ trait Foo {} -impl<'a> Foo for Foo+'a {} +impl<'a> Foo for dyn Foo + 'a {} //~^ ERROR the object type `(dyn Foo + 'a)` automatically implements the trait `Foo` fn main() {} diff --git a/src/test/ui/issues/issue-20939.stderr b/src/test/ui/issues/issue-20939.stderr index d15a5196667f3..3819a21a2cfff 100644 --- a/src/test/ui/issues/issue-20939.stderr +++ b/src/test/ui/issues/issue-20939.stderr @@ -1,8 +1,8 @@ error[E0371]: the object type `(dyn Foo + 'a)` automatically implements the trait `Foo` --> $DIR/issue-20939.rs:3:1 | -LL | impl<'a> Foo for Foo+'a {} - | ^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Foo + 'a)` automatically implements trait `Foo` +LL | impl<'a> Foo for dyn Foo + 'a {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Foo + 'a)` automatically implements trait `Foo` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2111.stderr b/src/test/ui/issues/issue-2111.stderr index 348ad153c8099..90fdb48ea625d 100644 --- a/src/test/ui/issues/issue-2111.stderr +++ b/src/test/ui/issues/issue-2111.stderr @@ -3,6 +3,8 @@ error[E0004]: non-exhaustive patterns: `(None, None)` not covered | LL | match (a,b) { | ^^^^^ pattern `(None, None)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21177.rs b/src/test/ui/issues/issue-21177.rs index 9d153696b885e..258e362d1317c 100644 --- a/src/test/ui/issues/issue-21177.rs +++ b/src/test/ui/issues/issue-21177.rs @@ -5,6 +5,5 @@ trait Trait { fn foo>() { } //~^ ERROR cycle detected -//~| ERROR associated type `B` not found for `T` fn main() { } diff --git a/src/test/ui/issues/issue-21177.stderr b/src/test/ui/issues/issue-21177.stderr index c3d2c6f48af6c..00d9a3c46a723 100644 --- a/src/test/ui/issues/issue-21177.stderr +++ b/src/test/ui/issues/issue-21177.stderr @@ -11,13 +11,6 @@ note: cycle used when processing `foo` LL | fn foo>() { } | ^^^^ -error[E0220]: associated type `B` not found for `T` - --> $DIR/issue-21177.rs:6:21 - | -LL | fn foo>() { } - | ^^^^ associated type `B` not found - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0220, E0391. -For more information about an error, try `rustc --explain E0220`. +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/issues/issue-21363.rs b/src/test/ui/issues/issue-21363.rs index 5e30db17c6d18..12efce9496efa 100644 --- a/src/test/ui/issues/issue-21363.rs +++ b/src/test/ui/issues/issue-21363.rs @@ -8,7 +8,7 @@ trait Iterator { fn dummy(&self) { } } -impl<'a, T> Iterator for &'a mut (Iterator + 'a) { +impl<'a, T> Iterator for &'a mut (dyn Iterator + 'a) { type Item = T; } diff --git a/src/test/ui/issues/issue-21449.stderr b/src/test/ui/issues/issue-21449.stderr index ecaf6faba429e..21de1ea091568 100644 --- a/src/test/ui/issues/issue-21449.stderr +++ b/src/test/ui/issues/issue-21449.stderr @@ -6,4 +6,3 @@ LL | let myVar = MyMod { T: 0 }; error: aborting due to previous error -For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/issues/issue-2149.stderr b/src/test/ui/issues/issue-2149.stderr index 82dbf34cc882b..1df32aafa79c8 100644 --- a/src/test/ui/issues/issue-2149.stderr +++ b/src/test/ui/issues/issue-2149.stderr @@ -18,5 +18,5 @@ LL | ["hi"].bind(|x| [x] ); error: aborting due to 2 previous errors -Some errors occurred: E0277, E0599. +Some errors have detailed explanations: E0277, E0599. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-2151.stderr b/src/test/ui/issues/issue-2151.stderr index 23f3c58653e50..a2bcc8a8ceaf0 100644 --- a/src/test/ui/issues/issue-2151.stderr +++ b/src/test/ui/issues/issue-2151.stderr @@ -3,7 +3,7 @@ error[E0282]: type annotations needed | LL | let x = panic!(); | - consider giving `x` a type -LL | x.clone(); //~ ERROR type annotations needed +LL | x.clone(); | ^ cannot infer type | = note: type must be known at this point diff --git a/src/test/ui/issues/issue-21596.rs b/src/test/ui/issues/issue-21596.rs new file mode 100644 index 0000000000000..79f6c91d9ac97 --- /dev/null +++ b/src/test/ui/issues/issue-21596.rs @@ -0,0 +1,5 @@ +fn main() { + let x = 8u8; + let z: *const u8 = &x; + println!("{}", z.to_string()); //~ ERROR E0599 +} diff --git a/src/test/ui/issues/issue-21596.stderr b/src/test/ui/issues/issue-21596.stderr new file mode 100644 index 0000000000000..07d29f30e988a --- /dev/null +++ b/src/test/ui/issues/issue-21596.stderr @@ -0,0 +1,13 @@ +error[E0599]: no method named `to_string` found for type `*const u8` in the current scope + --> $DIR/issue-21596.rs:4:22 + | +LL | println!("{}", z.to_string()); + | ^^^^^^^^^ + | + = note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref + = note: the method `to_string` exists but the following trait bounds were not satisfied: + `*const u8 : std::string::ToString` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/issues/issue-21600.nll.stderr b/src/test/ui/issues/issue-21600.nll.stderr deleted file mode 100644 index 05837e92cdbc1..0000000000000 --- a/src/test/ui/issues/issue-21600.nll.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/issue-21600.rs:14:20 - | -LL | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer - | ^ cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/issue-21600.rs:14:17 - | -LL | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer - | ^^^^^^^^^^^^^^ - -error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/issue-21600.rs:14:17 - | -LL | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer - | ^^ - mutable borrow occurs due to use of `x` in closure - | | - | cannot borrow as mutable - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/issue-21600.rs:12:13 - | -LL | call_it(|| { - | _____________^ -LL | | call_it(|| x.gen()); -LL | | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer -LL | | //~^ ERROR cannot borrow data mutably in a captured outer -LL | | }); - | |_____^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/issues/issue-21600.rs b/src/test/ui/issues/issue-21600.rs index 1efc873bee266..2e22e5e6fa2e0 100644 --- a/src/test/ui/issues/issue-21600.rs +++ b/src/test/ui/issues/issue-21600.rs @@ -11,7 +11,8 @@ fn main() { let mut x = A; call_it(|| { call_it(|| x.gen()); - call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer - //~^ ERROR cannot borrow data mutably in a captured outer + call_it(|| x.gen_mut()); + //~^ ERROR cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + //~| ERROR cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure }); } diff --git a/src/test/ui/issues/issue-21600.stderr b/src/test/ui/issues/issue-21600.stderr index ccb75f4cc005c..9c534809dbee3 100644 --- a/src/test/ui/issues/issue-21600.stderr +++ b/src/test/ui/issues/issue-21600.stderr @@ -1,8 +1,22 @@ -error[E0387]: cannot borrow data mutably in a captured outer variable in an `Fn` closure +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/issue-21600.rs:14:20 + | +LL | call_it(|| x.gen_mut()); + | ^ cannot borrow as mutable + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/issue-21600.rs:14:17 + | +LL | call_it(|| x.gen_mut()); + | ^^^^^^^^^^^^^^ + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/issue-21600.rs:14:17 | -LL | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer - | ^^ +LL | call_it(|| x.gen_mut()); + | ^^ - mutable borrow occurs due to use of `x` in closure + | | + | cannot borrow as mutable | help: consider changing this to accept closures that implement `FnMut` --> $DIR/issue-21600.rs:12:13 @@ -10,23 +24,12 @@ help: consider changing this to accept closures that implement `FnMut` LL | call_it(|| { | _____________^ LL | | call_it(|| x.gen()); -LL | | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer -LL | | //~^ ERROR cannot borrow data mutably in a captured outer +LL | | call_it(|| x.gen_mut()); +LL | | +LL | | LL | | }); | |_____^ -error[E0387]: cannot borrow data mutably in a captured outer variable in an `Fn` closure - --> $DIR/issue-21600.rs:14:20 - | -LL | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer - | ^ - | -help: consider changing this closure to take self by mutable reference - --> $DIR/issue-21600.rs:14:17 - | -LL | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer - | ^^^^^^^^^^^^^^ - error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0387`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/issues/issue-21763.stderr b/src/test/ui/issues/issue-21763.stderr index 62cc88776882f..87c048fdf4c11 100644 --- a/src/test/ui/issues/issue-21763.stderr +++ b/src/test/ui/issues/issue-21763.stderr @@ -4,10 +4,10 @@ error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely LL | foo::, Rc<()>>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely | - = help: within `std::collections::HashMap, std::rc::Rc<()>>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + = help: within `(std::rc::Rc<()>, std::rc::Rc<()>)`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` = note: required because it appears within the type `(std::rc::Rc<()>, std::rc::Rc<()>)` - = note: required because it appears within the type `std::marker::PhantomData<(std::rc::Rc<()>, std::rc::Rc<()>)>` - = note: required because it appears within the type `std::collections::hash::table::RawTable, std::rc::Rc<()>>` + = note: required because of the requirements on the impl of `std::marker::Send` for `hashbrown::raw::RawTable<(std::rc::Rc<()>, std::rc::Rc<()>)>` + = note: required because it appears within the type `hashbrown::map::HashMap, std::rc::Rc<()>, std::collections::hash_map::RandomState>` = note: required because it appears within the type `std::collections::HashMap, std::rc::Rc<()>>` note: required by `foo` --> $DIR/issue-21763.rs:6:1 diff --git a/src/test/ui/issues/issue-21837.stderr b/src/test/ui/issues/issue-21837.stderr index 464a65fa695af..3111d3a47414b 100644 --- a/src/test/ui/issues/issue-21837.stderr +++ b/src/test/ui/issues/issue-21837.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `T: Bound` is not satisfied --> $DIR/issue-21837.rs:8:9 | -LL | impl Trait2 for Foo {} //~ ERROR the trait bound `T: Bound` is not satisfied +LL | impl Trait2 for Foo {} | ^^^^^^ the trait `Bound` is not implemented for `T` | = help: consider adding a `where T: Bound` bound diff --git a/src/test/ui/issues/issue-21946.rs b/src/test/ui/issues/issue-21946.rs index d7a6c656df98f..2d99769cfa31c 100644 --- a/src/test/ui/issues/issue-21946.rs +++ b/src/test/ui/issues/issue-21946.rs @@ -7,6 +7,7 @@ struct FooStruct; impl Foo for FooStruct { //~^ ERROR overflow evaluating the requirement `::A` type A = ::A; + //~^ ERROR overflow evaluating the requirement `::A` } fn main() {} diff --git a/src/test/ui/issues/issue-21946.stderr b/src/test/ui/issues/issue-21946.stderr index 7a178bee6ae03..5ac49f61543e4 100644 --- a/src/test/ui/issues/issue-21946.stderr +++ b/src/test/ui/issues/issue-21946.stderr @@ -4,6 +4,12 @@ error[E0275]: overflow evaluating the requirement `::A` LL | impl Foo for FooStruct { | ^^^ -error: aborting due to previous error +error[E0275]: overflow evaluating the requirement `::A` + --> $DIR/issue-21946.rs:9:5 + | +LL | type A = ::A; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/issues/issue-21950.rs b/src/test/ui/issues/issue-21950.rs index 0f78b37fedba3..0bc87824ccec3 100644 --- a/src/test/ui/issues/issue-21950.rs +++ b/src/test/ui/issues/issue-21950.rs @@ -1,10 +1,8 @@ -// ignore-tidy-linelength - use std::ops::Add; fn main() { let x = &10 as - &Add; + &dyn Add; //~^ ERROR E0393 //~| ERROR E0191 } diff --git a/src/test/ui/issues/issue-21950.stderr b/src/test/ui/issues/issue-21950.stderr index 5f401d13feb55..9be7b052da31c 100644 --- a/src/test/ui/issues/issue-21950.stderr +++ b/src/test/ui/issues/issue-21950.stderr @@ -1,18 +1,18 @@ -error[E0393]: the type parameter `RHS` must be explicitly specified - --> $DIR/issue-21950.rs:7:14 +error[E0393]: the type parameter `Rhs` must be explicitly specified + --> $DIR/issue-21950.rs:5:18 | -LL | &Add; - | ^^^ missing reference to `RHS` +LL | &dyn Add; + | ^^^ missing reference to `Rhs` | = note: because of the default `Self` reference, type parameters must be specified on object types error[E0191]: the value of the associated type `Output` (from the trait `std::ops::Add`) must be specified - --> $DIR/issue-21950.rs:7:14 + --> $DIR/issue-21950.rs:5:14 | -LL | &Add; - | ^^^ associated type `Output` must be specified +LL | &dyn Add; + | ^^^^^^^ associated type `Output` must be specified error: aborting due to 2 previous errors -Some errors occurred: E0191, E0393. +Some errors have detailed explanations: E0191, E0393. For more information about an error, try `rustc --explain E0191`. diff --git a/src/test/ui/issues/issue-21974.stderr b/src/test/ui/issues/issue-21974.stderr index d5c48db4500ea..85e59d7bede5f 100644 --- a/src/test/ui/issues/issue-21974.stderr +++ b/src/test/ui/issues/issue-21974.stderr @@ -1,7 +1,7 @@ error[E0283]: type annotations required: cannot resolve `&'a T: Foo` --> $DIR/issue-21974.rs:10:1 | -LL | / fn foo<'a,'b,T>(x: &'a T, y: &'b T) //~ ERROR type annotations required +LL | / fn foo<'a,'b,T>(x: &'a T, y: &'b T) LL | | where &'a T : Foo, LL | | &'b T : Foo LL | | { diff --git a/src/test/ui/issues/issue-22034.rs b/src/test/ui/issues/issue-22034.rs index 75ac78ad24fea..fab1cdadaf5e1 100644 --- a/src/test/ui/issues/issue-22034.rs +++ b/src/test/ui/issues/issue-22034.rs @@ -3,9 +3,9 @@ extern crate libc; fn main() { - let ptr: *mut () = 0 as *mut _; - let _: &mut Fn() = unsafe { - &mut *(ptr as *mut Fn()) + let ptr: *mut () = core::ptr::null_mut(); + let _: &mut dyn Fn() = unsafe { + &mut *(ptr as *mut dyn Fn()) //~^ ERROR expected a `std::ops::Fn<()>` closure, found `()` }; } diff --git a/src/test/ui/issues/issue-22034.stderr b/src/test/ui/issues/issue-22034.stderr index de2d315ff5c68..19fb080154a4a 100644 --- a/src/test/ui/issues/issue-22034.stderr +++ b/src/test/ui/issues/issue-22034.stderr @@ -1,7 +1,7 @@ error[E0277]: expected a `std::ops::Fn<()>` closure, found `()` --> $DIR/issue-22034.rs:8:16 | -LL | &mut *(ptr as *mut Fn()) +LL | &mut *(ptr as *mut dyn Fn()) | ^^^ expected an `Fn<()>` closure, found `()` | = help: the trait `std::ops::Fn<()>` is not implemented for `()` diff --git a/src/test/ui/issues/issue-22037.stderr b/src/test/ui/issues/issue-22037.stderr index 615628558f08b..40d4a5e3bc0c5 100644 --- a/src/test/ui/issues/issue-22037.stderr +++ b/src/test/ui/issues/issue-22037.stderr @@ -6,4 +6,3 @@ LL | fn a(&self) -> ::X; error: aborting due to previous error -For more information about this error, try `rustc --explain E0576`. diff --git a/src/test/ui/issues/issue-22289.rs b/src/test/ui/issues/issue-22289.rs index b683834de441b..e1b3dfe5b61bd 100644 --- a/src/test/ui/issues/issue-22289.rs +++ b/src/test/ui/issues/issue-22289.rs @@ -1,3 +1,3 @@ fn main() { - 0 as &std::any::Any; //~ ERROR non-primitive cast + 0 as &dyn std::any::Any; //~ ERROR non-primitive cast } diff --git a/src/test/ui/issues/issue-22289.stderr b/src/test/ui/issues/issue-22289.stderr index 5214ec1ad1638..cc7ace30cabef 100644 --- a/src/test/ui/issues/issue-22289.stderr +++ b/src/test/ui/issues/issue-22289.stderr @@ -1,8 +1,8 @@ error[E0605]: non-primitive cast: `i32` as `&(dyn std::any::Any + 'static)` --> $DIR/issue-22289.rs:2:5 | -LL | 0 as &std::any::Any; //~ ERROR non-primitive cast - | ^^^^^^^^^^^^^^^^^^^ +LL | 0 as &dyn std::any::Any; + | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait diff --git a/src/test/ui/issues/issue-22312.rs b/src/test/ui/issues/issue-22312.rs index f7ebdb0372ad8..250fec2588702 100644 --- a/src/test/ui/issues/issue-22312.rs +++ b/src/test/ui/issues/issue-22312.rs @@ -8,7 +8,7 @@ pub trait Array2D: Index { return None; } let i = y * self.columns() + x; - let indexer = &(*self as &Index>::Output>); + let indexer = &(*self as &dyn Index>::Output>); //~^ERROR non-primitive cast Some(indexer.index(i)) } diff --git a/src/test/ui/issues/issue-22312.stderr b/src/test/ui/issues/issue-22312.stderr index d8987a37f7e46..fc32fd376b75a 100644 --- a/src/test/ui/issues/issue-22312.stderr +++ b/src/test/ui/issues/issue-22312.stderr @@ -1,8 +1,8 @@ -error[E0605]: non-primitive cast: `Self` as `&dyn std::ops::Index>::Output>` +error[E0605]: non-primitive cast: `Self` as `&dyn std::ops::Index>::Output>` --> $DIR/issue-22312.rs:11:24 | -LL | let indexer = &(*self as &Index>::Output>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let indexer = &(*self as &dyn Index>::Output>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait diff --git a/src/test/ui/issues/issue-22370.rs b/src/test/ui/issues/issue-22370.rs index 44eef2da83ce3..bab0469c01193 100644 --- a/src/test/ui/issues/issue-22370.rs +++ b/src/test/ui/issues/issue-22370.rs @@ -1,8 +1,6 @@ -// ignore-tidy-linelength - trait A {} -fn f(a: &A) {} +fn f(a: &dyn A) {} //~^ ERROR E0393 fn main() {} diff --git a/src/test/ui/issues/issue-22370.stderr b/src/test/ui/issues/issue-22370.stderr index 5d76d84d11e6f..3ce164e9548b4 100644 --- a/src/test/ui/issues/issue-22370.stderr +++ b/src/test/ui/issues/issue-22370.stderr @@ -1,8 +1,8 @@ error[E0393]: the type parameter `T` must be explicitly specified - --> $DIR/issue-22370.rs:5:10 + --> $DIR/issue-22370.rs:3:14 | -LL | fn f(a: &A) {} - | ^ missing reference to `T` +LL | fn f(a: &dyn A) {} + | ^ missing reference to `T` | = note: because of the default `Self` reference, type parameters must be specified on object types diff --git a/src/test/ui/issues/issue-22384.stderr b/src/test/ui/issues/issue-22384.stderr index 1f767a443d0f0..130c3124b6f82 100644 --- a/src/test/ui/issues/issue-22384.stderr +++ b/src/test/ui/issues/issue-22384.stderr @@ -6,4 +6,3 @@ LL | <::foobar as Trait>::foo(); error: aborting due to previous error -For more information about this error, try `rustc --explain E0576`. diff --git a/src/test/ui/issues/issue-22434.rs b/src/test/ui/issues/issue-22434.rs index 0d7d67cbc1bc2..3e800a2b61db9 100644 --- a/src/test/ui/issues/issue-22434.rs +++ b/src/test/ui/issues/issue-22434.rs @@ -2,7 +2,7 @@ pub trait Foo { type A; } -type I<'a> = &'a (Foo + 'a); +type I<'a> = &'a (dyn Foo + 'a); //~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified fn main() {} diff --git a/src/test/ui/issues/issue-22434.stderr b/src/test/ui/issues/issue-22434.stderr index bbdbeb6ae9804..eb78c4fc311fc 100644 --- a/src/test/ui/issues/issue-22434.stderr +++ b/src/test/ui/issues/issue-22434.stderr @@ -4,8 +4,8 @@ error[E0191]: the value of the associated type `A` (from the trait `Foo`) must b LL | type A; | ------- `A` defined here ... -LL | type I<'a> = &'a (Foo + 'a); - | ^^^^^^^^ associated type `A` must be specified +LL | type I<'a> = &'a (dyn Foo + 'a); + | ^^^^^^^^^^^^ associated type `A` must be specified error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22560.rs b/src/test/ui/issues/issue-22560.rs index d91211e556b11..acee99dbedcc4 100644 --- a/src/test/ui/issues/issue-22560.rs +++ b/src/test/ui/issues/issue-22560.rs @@ -1,8 +1,6 @@ -// ignore-tidy-linelength - use std::ops::{Add, Sub}; -type Test = Add + +type Test = dyn Add + //~^ ERROR E0393 //~| ERROR E0191 Sub; diff --git a/src/test/ui/issues/issue-22560.stderr b/src/test/ui/issues/issue-22560.stderr index c6de479aac042..5b58adb197c69 100644 --- a/src/test/ui/issues/issue-22560.stderr +++ b/src/test/ui/issues/issue-22560.stderr @@ -1,36 +1,50 @@ -error[E0393]: the type parameter `RHS` must be explicitly specified - --> $DIR/issue-22560.rs:5:13 +error[E0393]: the type parameter `Rhs` must be explicitly specified + --> $DIR/issue-22560.rs:6:13 | -LL | type Test = Add + - | ^^^ missing reference to `RHS` +LL | Sub; + | ^^^ missing reference to `Rhs` | = note: because of the default `Self` reference, type parameters must be specified on object types -error[E0393]: the type parameter `RHS` must be explicitly specified - --> $DIR/issue-22560.rs:8:13 +error[E0393]: the type parameter `Rhs` must be explicitly specified + --> $DIR/issue-22560.rs:3:17 | -LL | Sub; - | ^^^ missing reference to `RHS` +LL | type Test = dyn Add + + | ^^^ missing reference to `Rhs` | = note: because of the default `Self` reference, type parameters must be specified on object types error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/issue-22560.rs:8:13 + --> $DIR/issue-22560.rs:6:13 | +LL | type Test = dyn Add + + | --- + | | + | first non-auto trait + | trait alias used in trait object type (first use) +... LL | Sub; - | ^^^ non-auto additional trait + | ^^^ + | | + | additional non-auto trait + | trait alias used in trait object type (additional use) -error[E0191]: the value of the associated type `Output` (from the trait `std::ops::Add`) must be specified - --> $DIR/issue-22560.rs:5:13 +error[E0191]: the value of the associated types `Output` (from the trait `std::ops::Add`), `Output` (from the trait `std::ops::Sub`) must be specified + --> $DIR/issue-22560.rs:3:13 | -LL | type Test = Add + +LL | type Test = dyn Add + | _____________^ -LL | | //~^ ERROR E0393 -LL | | //~| ERROR E0191 + | |_____________| + | | +LL | | +LL | | LL | | Sub; - | |_______________^ associated type `Output` must be specified + | | ^ + | |_______________| + | |_______________associated type `Output` must be specified + | associated type `Output` must be specified error: aborting due to 4 previous errors -Some errors occurred: E0191, E0225, E0393. +Some errors have detailed explanations: E0191, E0225, E0393. For more information about an error, try `rustc --explain E0191`. diff --git a/src/test/ui/issues/issue-22599.stderr b/src/test/ui/issues/issue-22599.stderr index bc4949da6f785..12234293ac995 100644 --- a/src/test/ui/issues/issue-22599.stderr +++ b/src/test/ui/issues/issue-22599.stderr @@ -1,7 +1,7 @@ error: unused variable: `a` --> $DIR/issue-22599.rs:8:19 | -LL | v = match 0 { a => 0 }; //~ ERROR: unused variable: `a` +LL | v = match 0 { a => 0 }; | ^ help: consider prefixing with an underscore: `_a` | note: lint level defined here diff --git a/src/test/ui/issues/issue-22603.rs b/src/test/ui/issues/issue-22603.rs index e298316f3b98e..a83e291f999ab 100644 --- a/src/test/ui/issues/issue-22603.rs +++ b/src/test/ui/issues/issue-22603.rs @@ -1,6 +1,7 @@ -// skip-codegen -// compile-pass +// check-pass + #![feature(unboxed_closures, fn_traits)] + struct Foo; impl FnOnce<(A,)> for Foo { diff --git a/src/test/ui/issues/issue-22638.stderr b/src/test/ui/issues/issue-22638.stderr index ba7d5f070170d..b60e1c29ec0ee 100644 --- a/src/test/ui/issues/issue-22638.stderr +++ b/src/test/ui/issues/issue-22638.stderr @@ -2,13 +2,13 @@ error: reached the type-length limit while instantiating `D::matches::$CLOSURE` --> $DIR/issue-22638.rs:52:5 | LL | / pub fn matches(&self, f: &F) { -LL | | //~^ ERROR reached the type-length limit while instantiating `D::matches::<[closure +LL | | LL | | let &D(ref a) = self; LL | | a.matches(f) LL | | } | |_____^ | - = note: consider adding a `#![type_length_limit="40000000"]` attribute to your crate + = note: consider adding a `#![type_length_limit="26214380"]` attribute to your crate error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22644.stderr b/src/test/ui/issues/issue-22644.stderr index de97b2271b10a..cf36953546549 100644 --- a/src/test/ui/issues/issue-22644.stderr +++ b/src/test/ui/issues/issue-22644.stderr @@ -1,7 +1,7 @@ error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:8:31 | -LL | println!("{}", a as usize < long_name); //~ ERROR `<` is interpreted as a start of generic +LL | println!("{}", a as usize < long_name); | ---------- ^ --------- interpreted as generic arguments | | | | | not interpreted as comparison @@ -19,7 +19,7 @@ LL | println!("{}{}", a as usize < long_name, long_name); error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:11:31 | -LL | println!("{}", a as usize < 4); //~ ERROR `<` is interpreted as a start of generic +LL | println!("{}", a as usize < 4); | ---------- ^ - interpreted as generic arguments | | | | | not interpreted as comparison @@ -37,7 +37,7 @@ LL | println!("{}{}", a: usize < long_name, long_name); error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:15:29 | -LL | println!("{}", a: usize < 4); //~ ERROR `<` is interpreted as a start of generic +LL | println!("{}", a: usize < 4); | -------- ^ - interpreted as generic arguments | | | | | not interpreted as comparison @@ -46,7 +46,7 @@ LL | println!("{}", a: usize < 4); //~ ERROR `<` is interpreted as a start o error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:20:20 | -LL | < //~ ERROR `<` is interpreted as a start of generic +LL | < | ^ not interpreted as comparison LL | 4); | - interpreted as generic arguments @@ -60,7 +60,7 @@ LL | usize) error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:29:20 | -LL | < //~ ERROR `<` is interpreted as a start of generic +LL | < | ^ not interpreted as comparison LL | 5); | - interpreted as generic arguments @@ -77,7 +77,7 @@ LL | error: `<` is interpreted as a start of generic arguments for `usize`, not a shift --> $DIR/issue-22644.rs:32:31 | -LL | println!("{}", a as usize << long_name); //~ ERROR `<` is interpreted as a start of generic +LL | println!("{}", a as usize << long_name); | ---------- ^^ --------- interpreted as generic arguments | | | | | not interpreted as shift @@ -86,8 +86,16 @@ LL | println!("{}", a as usize << long_name); //~ ERROR `<` is interpreted a error: expected type, found `4` --> $DIR/issue-22644.rs:34:28 | -LL | println!("{}", a: &mut 4); //~ ERROR expected type, found `4` +LL | println!("{}", a: &mut 4); | ^ expecting a type here because of type ascription + | + = note: #![feature(type_ascription)] lets you annotate an expression with a type: `: ` +note: this expression expects an ascribed type after the colon + --> $DIR/issue-22644.rs:34:20 + | +LL | println!("{}", a: &mut 4); + | ^ + = help: this might be indicative of a syntax error elsewhere error: aborting due to 9 previous errors diff --git a/src/test/ui/issues/issue-22684.stderr b/src/test/ui/issues/issue-22684.stderr index 6e2b2357a05de..738123ec4d41b 100644 --- a/src/test/ui/issues/issue-22684.stderr +++ b/src/test/ui/issues/issue-22684.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-22684.rs:17:17 | -LL | let _: () = foo::Foo.bar(); //~ ERROR mismatched types +LL | let _: () = foo::Foo.bar(); | ^^^^^^^^^^^^^^ expected (), found bool | = note: expected type `()` diff --git a/src/test/ui/issues/issue-22706.rs b/src/test/ui/issues/issue-22706.rs index 413a0d9a4943a..28e8a72280481 100644 --- a/src/test/ui/issues/issue-22706.rs +++ b/src/test/ui/issues/issue-22706.rs @@ -1,3 +1,3 @@ fn is_copy::Copy>() {} -//~^ ERROR type arguments are not allowed on this entity [E0109] +//~^ ERROR type arguments are not allowed for this type [E0109] fn main() {} diff --git a/src/test/ui/issues/issue-22706.stderr b/src/test/ui/issues/issue-22706.stderr index a3cf716903d20..c5929397f6501 100644 --- a/src/test/ui/issues/issue-22706.stderr +++ b/src/test/ui/issues/issue-22706.stderr @@ -1,4 +1,4 @@ -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/issue-22706.rs:1:29 | LL | fn is_copy::Copy>() {} diff --git a/src/test/ui/issues/issue-22781.rs b/src/test/ui/issues/issue-22781.rs index 5df3d88b168fa..a7b94c106a4c8 100644 --- a/src/test/ui/issues/issue-22781.rs +++ b/src/test/ui/issues/issue-22781.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use std::collections::hash_map::Entry::Vacant; pub fn foo() { - type F = Box; + type F = Box; let mut map: HashMap<(), F> = HashMap::new(); let x: &mut F = match map.entry(()) { Vacant(_) => unimplemented!(), diff --git a/src/test/ui/issues/issue-22789.rs b/src/test/ui/issues/issue-22789.rs index e6680124f85a8..cef4075376686 100644 --- a/src/test/ui/issues/issue-22789.rs +++ b/src/test/ui/issues/issue-22789.rs @@ -1,6 +1,7 @@ -// compile-pass -// skip-codegen +// check-pass + #![feature(unboxed_closures, fn_traits)] + fn main() { let k = |x: i32| { x + 1 }; Fn::call(&k, (0,)); diff --git a/src/test/ui/issues/issue-2281-part1.stderr b/src/test/ui/issues/issue-2281-part1.stderr index faf31c7bd4af5..c2391a7c0911f 100644 --- a/src/test/ui/issues/issue-2281-part1.stderr +++ b/src/test/ui/issues/issue-2281-part1.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `foobar` in this scope --> $DIR/issue-2281-part1.rs:1:28 | -LL | fn main() { println!("{}", foobar); } //~ ERROR cannot find value `foobar` in this scope +LL | fn main() { println!("{}", foobar); } | ^^^^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22814.rs b/src/test/ui/issues/issue-22814.rs index b008c75106492..bcc7a8a5ae0a3 100644 --- a/src/test/ui/issues/issue-22814.rs +++ b/src/test/ui/issues/issue-22814.rs @@ -3,7 +3,7 @@ trait Test {} macro_rules! test { ( $($name:ident)+) => ( - impl<$($name: Test),*> Test for ($($name,)*) { + impl<$($name: Test),+> Test for ($($name,)+) { } ) } diff --git a/src/test/ui/issues/issue-22872.rs b/src/test/ui/issues/issue-22872.rs index 8ef4af15bd462..5db2891e65e75 100644 --- a/src/test/ui/issues/issue-22872.rs +++ b/src/test/ui/issues/issue-22872.rs @@ -17,7 +17,7 @@ pub trait Process<'a> { } fn push_process

    (process: P) where P: Process<'static> { - let _: Box Wrap<'b>> = Box::new(Wrapper(process)); + let _: Box Wrap<'b>> = Box::new(Wrapper(process)); //~^ ERROR is not an iterator } diff --git a/src/test/ui/issues/issue-22872.stderr b/src/test/ui/issues/issue-22872.stderr index ebd096f1dde5a..fc5de23752b3e 100644 --- a/src/test/ui/issues/issue-22872.stderr +++ b/src/test/ui/issues/issue-22872.stderr @@ -1,8 +1,8 @@ error[E0277]: `

    >::Item` is not an iterator - --> $DIR/issue-22872.rs:20:36 + --> $DIR/issue-22872.rs:20:40 | -LL | let _: Box Wrap<'b>> = Box::new(Wrapper(process)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `

    >::Item` is not an iterator +LL | let _: Box Wrap<'b>> = Box::new(Wrapper(process)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `

    >::Item` is not an iterator | = help: the trait `std::iter::Iterator` is not implemented for `

    >::Item` = help: consider adding a `where

    >::Item: std::iter::Iterator` bound diff --git a/src/test/ui/issues/issue-22886.stderr b/src/test/ui/issues/issue-22886.stderr index ff206e8113e1e..c4b3965592411 100644 --- a/src/test/ui/issues/issue-22886.stderr +++ b/src/test/ui/issues/issue-22886.stderr @@ -1,7 +1,7 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates --> $DIR/issue-22886.rs:13:6 | -LL | impl<'a> Iterator for Newtype { //~ ERROR E0207 +LL | impl<'a> Iterator for Newtype { | ^^ unconstrained lifetime parameter error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22933-1.rs b/src/test/ui/issues/issue-22933-1.rs index 1bf8cb01cf7b5..3c9aa26697907 100644 --- a/src/test/ui/issues/issue-22933-1.rs +++ b/src/test/ui/issues/issue-22933-1.rs @@ -1,6 +1,5 @@ -// compile-pass -// skip-codegen -#![allow(warnings)] +// check-pass + struct CNFParser { token: char, } @@ -14,12 +13,11 @@ impl CNFParser { self.consume_while(&(CNFParser::is_whitespace)) } - fn consume_while(&mut self, p: &Fn(char) -> bool) { + fn consume_while(&mut self, p: &dyn Fn(char) -> bool) { while p(self.token) { return } } } - fn main() {} diff --git a/src/test/ui/issues/issue-22933-2.rs b/src/test/ui/issues/issue-22933-2.rs index 68d9ef2cfa809..98a354b1bd0fc 100644 --- a/src/test/ui/issues/issue-22933-2.rs +++ b/src/test/ui/issues/issue-22933-2.rs @@ -2,7 +2,7 @@ enum Delicious { Pie = 0x1, Apple = 0x2, ApplePie = Delicious::Apple as isize | Delicious::PIE as isize, - //~^ ERROR no variant named `PIE` found for type `Delicious` + //~^ ERROR no variant or associated item named `PIE` found for type `Delicious` } fn main() {} diff --git a/src/test/ui/issues/issue-22933-2.stderr b/src/test/ui/issues/issue-22933-2.stderr index 97962adc2d286..72038ea20a3fa 100644 --- a/src/test/ui/issues/issue-22933-2.stderr +++ b/src/test/ui/issues/issue-22933-2.stderr @@ -1,13 +1,11 @@ -error[E0599]: no variant named `PIE` found for type `Delicious` in the current scope +error[E0599]: no variant or associated item named `PIE` found for type `Delicious` in the current scope --> $DIR/issue-22933-2.rs:4:55 | LL | enum Delicious { - | -------------- variant `PIE` not found here + | -------------- variant or associated item `PIE` not found here ... LL | ApplePie = Delicious::Apple as isize | Delicious::PIE as isize, - | -----------^^^ - | | - | variant not found in `Delicious` + | ^^^ variant or associated item not found in `Delicious` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22933-3.stderr b/src/test/ui/issues/issue-22933-3.stderr index aa0052f97013e..e0e8b5e18a42d 100644 --- a/src/test/ui/issues/issue-22933-3.stderr +++ b/src/test/ui/issues/issue-22933-3.stderr @@ -2,9 +2,11 @@ error[E0599]: no associated item named `MIN` found for type `u8` in the current --> $DIR/issue-22933-3.rs:1:22 | LL | const FOO: [u32; u8::MIN as usize] = []; - | ----^^^ - | | - | associated item not found in `u8` + | ^^^ associated item not found in `u8` +help: you are looking for the module in `std`, not the primitive type + | +LL | const FOO: [u32; std::u8::MIN as usize] = []; + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23024.rs b/src/test/ui/issues/issue-23024.rs index 0639ce30aa0e8..2638e15f0eae5 100644 --- a/src/test/ui/issues/issue-23024.rs +++ b/src/test/ui/issues/issue-23024.rs @@ -4,9 +4,9 @@ use std::any::Any; fn main() { fn h(x:i32) -> i32 {3*x} - let mut vfnfer:Vec> = vec![]; + let mut vfnfer:Vec> = vec![]; vfnfer.push(box h); - println!("{:?}",(vfnfer[0] as Fn)(3)); + println!("{:?}",(vfnfer[0] as dyn Fn)(3)); //~^ ERROR the precise format of `Fn`-family traits' //~| ERROR wrong number of type arguments: expected 1, found 0 [E0107] //~| ERROR the value of the associated type `Output` (from the trait `std::ops::FnOnce`) diff --git a/src/test/ui/issues/issue-23024.stderr b/src/test/ui/issues/issue-23024.stderr index a972b36b8049d..e99854539de88 100644 --- a/src/test/ui/issues/issue-23024.stderr +++ b/src/test/ui/issues/issue-23024.stderr @@ -1,24 +1,25 @@ -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) - --> $DIR/issue-23024.rs:9:35 +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead + --> $DIR/issue-23024.rs:9:39 | -LL | println!("{:?}",(vfnfer[0] as Fn)(3)); - | ^^ +LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); + | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable error[E0107]: wrong number of type arguments: expected 1, found 0 - --> $DIR/issue-23024.rs:9:35 + --> $DIR/issue-23024.rs:9:39 | -LL | println!("{:?}",(vfnfer[0] as Fn)(3)); - | ^^ expected 1 type argument +LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); + | ^^ expected 1 type argument error[E0191]: the value of the associated type `Output` (from the trait `std::ops::FnOnce`) must be specified --> $DIR/issue-23024.rs:9:35 | -LL | println!("{:?}",(vfnfer[0] as Fn)(3)); - | ^^ associated type `Output` must be specified +LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); + | ^^^^^^ associated type `Output` must be specified error: aborting due to 3 previous errors -Some errors occurred: E0107, E0191, E0658. +Some errors have detailed explanations: E0107, E0191, E0658. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/issues/issue-23041.rs b/src/test/ui/issues/issue-23041.rs index a18e85806d918..a1371521a0aa0 100644 --- a/src/test/ui/issues/issue-23041.rs +++ b/src/test/ui/issues/issue-23041.rs @@ -2,6 +2,6 @@ use std::any::Any; fn main() { fn bar(x:i32) ->i32 { 3*x }; - let b:Box = Box::new(bar as fn(_)->_); + let b:Box = Box::new(bar as fn(_)->_); b.downcast_ref::_>(); //~ ERROR E0282 } diff --git a/src/test/ui/issues/issue-23041.stderr b/src/test/ui/issues/issue-23041.stderr index aa6ffdd2570f4..401086b204435 100644 --- a/src/test/ui/issues/issue-23041.stderr +++ b/src/test/ui/issues/issue-23041.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed --> $DIR/issue-23041.rs:6:22 | -LL | b.downcast_ref::_>(); //~ ERROR E0282 +LL | b.downcast_ref::_>(); | ^^^^^^^^ cannot infer type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23046.rs b/src/test/ui/issues/issue-23046.rs index 898654b7b5967..a68369616d8b6 100644 --- a/src/test/ui/issues/issue-23046.rs +++ b/src/test/ui/issues/issue-23046.rs @@ -1,6 +1,6 @@ pub enum Expr<'var, VAR> { Let(Box>, - Box Fn(Expr<'v, VAR>) -> Expr<'v, VAR> + 'var>) + Box Fn(Expr<'v, VAR>) -> Expr<'v, VAR> + 'var>) } pub fn add<'var, VAR> diff --git a/src/test/ui/issues/issue-23046.stderr b/src/test/ui/issues/issue-23046.stderr index 9b7599e1e35de..12b2eb48e7eaa 100644 --- a/src/test/ui/issues/issue-23046.stderr +++ b/src/test/ui/issues/issue-23046.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `Expr<'_, VAR>` --> $DIR/issue-23046.rs:17:15 | -LL | let ex = |x| { //~ ERROR type annotations needed - | ^ consider giving this closure parameter a type +LL | let ex = |x| { + | ^ consider giving this closure parameter the explicit type `Expr<'_, VAR>`, where the type parameter `VAR` is specified error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23073.stderr b/src/test/ui/issues/issue-23073.stderr index e3ddd190d4f81..3a10a1ab11ac5 100644 --- a/src/test/ui/issues/issue-23073.stderr +++ b/src/test/ui/issues/issue-23073.stderr @@ -1,7 +1,7 @@ error[E0223]: ambiguous associated type --> $DIR/issue-23073.rs:6:17 | -LL | type FooT = <::Foo>::T; //~ ERROR ambiguous associated type +LL | type FooT = <::Foo>::T; | ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<::Foo as Trait>::T` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23080-2.rs b/src/test/ui/issues/issue-23080-2.rs index 750b7e19d89df..319aa2a5cce9e 100644 --- a/src/test/ui/issues/issue-23080-2.rs +++ b/src/test/ui/issues/issue-23080-2.rs @@ -1,6 +1,4 @@ -// ignore-tidy-linelength - -//~^^ ERROR +//~ ERROR #![feature(optin_builtin_traits)] diff --git a/src/test/ui/issues/issue-23080-2.stderr b/src/test/ui/issues/issue-23080-2.stderr index db9a6488851a8..1103de0d91043 100644 --- a/src/test/ui/issues/issue-23080-2.stderr +++ b/src/test/ui/issues/issue-23080-2.stderr @@ -1,8 +1,8 @@ error[E0380]: auto traits cannot have methods or associated items - --> $DIR/issue-23080-2.rs:7:1 + --> $DIR/issue-23080-2.rs:5:1 | LL | / unsafe auto trait Trait { -LL | | //~^ ERROR E0380 +LL | | LL | | type Output; LL | | } | |_^ @@ -14,5 +14,5 @@ error[E0275]: overflow evaluating the requirement `<() as Trait>::Output` error: aborting due to 2 previous errors -Some errors occurred: E0275, E0380. +Some errors have detailed explanations: E0275, E0380. For more information about an error, try `rustc --explain E0275`. diff --git a/src/test/ui/issues/issue-23080.rs b/src/test/ui/issues/issue-23080.rs index e25a2d916f5f2..fdfee6981447d 100644 --- a/src/test/ui/issues/issue-23080.rs +++ b/src/test/ui/issues/issue-23080.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - #![feature(optin_builtin_traits)] unsafe auto trait Trait { diff --git a/src/test/ui/issues/issue-23080.stderr b/src/test/ui/issues/issue-23080.stderr index cace9a57507ff..91c2721732426 100644 --- a/src/test/ui/issues/issue-23080.stderr +++ b/src/test/ui/issues/issue-23080.stderr @@ -1,8 +1,8 @@ error[E0380]: auto traits cannot have methods or associated items - --> $DIR/issue-23080.rs:5:1 + --> $DIR/issue-23080.rs:3:1 | LL | / unsafe auto trait Trait { -LL | | //~^ ERROR E0380 +LL | | LL | | fn method(&self) { LL | | println!("Hello"); LL | | } diff --git a/src/test/ui/issues/issue-23122-1.rs b/src/test/ui/issues/issue-23122-1.rs index a882aa36af758..d6f64650f36bb 100644 --- a/src/test/ui/issues/issue-23122-1.rs +++ b/src/test/ui/issues/issue-23122-1.rs @@ -7,6 +7,7 @@ struct GetNext { t: T } impl Next for GetNext { //~^ ERROR overflow evaluating the requirement type Next = as Next>::Next; + //~^ ERROR overflow evaluating the requirement } fn main() {} diff --git a/src/test/ui/issues/issue-23122-1.stderr b/src/test/ui/issues/issue-23122-1.stderr index 39dd424a86ca0..1b752b7afe2e6 100644 --- a/src/test/ui/issues/issue-23122-1.stderr +++ b/src/test/ui/issues/issue-23122-1.stderr @@ -4,6 +4,12 @@ error[E0275]: overflow evaluating the requirement ` as Next>::Next` LL | impl Next for GetNext { | ^^^^ -error: aborting due to previous error +error[E0275]: overflow evaluating the requirement ` as Next>::Next` + --> $DIR/issue-23122-1.rs:9:5 + | +LL | type Next = as Next>::Next; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/issues/issue-23122-2.rs b/src/test/ui/issues/issue-23122-2.rs index b841120034301..695712d2cc929 100644 --- a/src/test/ui/issues/issue-23122-2.rs +++ b/src/test/ui/issues/issue-23122-2.rs @@ -7,6 +7,7 @@ struct GetNext { t: T } impl Next for GetNext { //~^ ERROR overflow evaluating the requirement type Next = as Next>::Next; + //~^ ERROR overflow evaluating the requirement } fn main() {} diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr index 8592877581103..d2c1421e29e0e 100644 --- a/src/test/ui/issues/issue-23122-2.stderr +++ b/src/test/ui/issues/issue-23122-2.stderr @@ -1,12 +1,21 @@ -error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` --> $DIR/issue-23122-2.rs:7:15 | LL | impl Next for GetNext { | ^^^^ | - = help: consider adding a `#![recursion_limit="128"]` attribute to your crate - = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` -error: aborting due to previous error +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` + --> $DIR/issue-23122-2.rs:9:5 + | +LL | type Next = as Next>::Next; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/issues/issue-23173.rs b/src/test/ui/issues/issue-23173.rs index 2922ebddf4c8a..7c15598448d7f 100644 --- a/src/test/ui/issues/issue-23173.rs +++ b/src/test/ui/issues/issue-23173.rs @@ -6,12 +6,8 @@ struct Struct { fn use_token(token: &Token) { unimplemented!() } fn main() { - use_token(&Token::Homura); - //~^ ERROR no variant named `Homura` - Struct::method(); - //~^ ERROR no function or associated item named `method` found for type - Struct::method; - //~^ ERROR no function or associated item named `method` found for type - Struct::Assoc; - //~^ ERROR no associated item named `Assoc` found for type `Struct` in + use_token(&Token::Homura); //~ ERROR no variant or associated item named `Homura` + Struct::method(); //~ ERROR no function or associated item named `method` found for type + Struct::method; //~ ERROR no function or associated item named `method` found for type + Struct::Assoc; //~ ERROR no associated item named `Assoc` found for type `Struct` in } diff --git a/src/test/ui/issues/issue-23173.stderr b/src/test/ui/issues/issue-23173.stderr index 98c4f867ad6a0..699e41156fa80 100644 --- a/src/test/ui/issues/issue-23173.stderr +++ b/src/test/ui/issues/issue-23173.stderr @@ -1,46 +1,38 @@ -error[E0599]: no variant named `Homura` found for type `Token` in the current scope +error[E0599]: no variant or associated item named `Homura` found for type `Token` in the current scope --> $DIR/issue-23173.rs:9:23 | LL | enum Token { LeftParen, RightParen, Plus, Minus, /* etc */ } - | ---------- variant `Homura` not found here + | ---------- variant or associated item `Homura` not found here ... LL | use_token(&Token::Homura); - | -------^^^^^^ - | | - | variant not found in `Token` + | ^^^^^^ variant or associated item not found in `Token` error[E0599]: no function or associated item named `method` found for type `Struct` in the current scope - --> $DIR/issue-23173.rs:11:13 + --> $DIR/issue-23173.rs:10:13 | LL | struct Struct { | ------------- function or associated item `method` not found for this ... LL | Struct::method(); - | --------^^^^^^ - | | - | function or associated item not found in `Struct` + | ^^^^^^ function or associated item not found in `Struct` error[E0599]: no function or associated item named `method` found for type `Struct` in the current scope - --> $DIR/issue-23173.rs:13:13 + --> $DIR/issue-23173.rs:11:13 | LL | struct Struct { | ------------- function or associated item `method` not found for this ... LL | Struct::method; - | --------^^^^^^ - | | - | function or associated item not found in `Struct` + | ^^^^^^ function or associated item not found in `Struct` error[E0599]: no associated item named `Assoc` found for type `Struct` in the current scope - --> $DIR/issue-23173.rs:15:13 + --> $DIR/issue-23173.rs:12:13 | LL | struct Struct { | ------------- associated item `Assoc` not found for this ... LL | Struct::Assoc; - | --------^^^^^ - | | - | associated item not found in `Struct` + | ^^^^^ associated item not found in `Struct` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-23189.stderr b/src/test/ui/issues/issue-23189.stderr index 82c6ed9c062b0..50c09f17486de 100644 --- a/src/test/ui/issues/issue-23189.stderr +++ b/src/test/ui/issues/issue-23189.stderr @@ -1,9 +1,8 @@ error[E0574]: expected struct, variant or union type, found module `module` --> $DIR/issue-23189.rs:4:13 | -LL | let _ = module { x: 0 }; //~ERROR expected struct +LL | let _ = module { x: 0 }; | ^^^^^^ not a struct, variant or union type error: aborting due to previous error -For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/issues/issue-23217.rs b/src/test/ui/issues/issue-23217.rs index 11426df6177ca..157f20d22d8ae 100644 --- a/src/test/ui/issues/issue-23217.rs +++ b/src/test/ui/issues/issue-23217.rs @@ -1,6 +1,5 @@ pub enum SomeEnum { - B = SomeEnum::A, - //~^ ERROR no variant named `A` found for type `SomeEnum` + B = SomeEnum::A, //~ ERROR no variant or associated item named `A` found for type `SomeEnum` } fn main() {} diff --git a/src/test/ui/issues/issue-23217.stderr b/src/test/ui/issues/issue-23217.stderr index 9cad002036fff..97100ed375374 100644 --- a/src/test/ui/issues/issue-23217.stderr +++ b/src/test/ui/issues/issue-23217.stderr @@ -1,13 +1,13 @@ -error[E0599]: no variant named `A` found for type `SomeEnum` in the current scope +error[E0599]: no variant or associated item named `A` found for type `SomeEnum` in the current scope --> $DIR/issue-23217.rs:2:19 | LL | pub enum SomeEnum { - | ----------------- variant `A` not found here + | ----------------- variant or associated item `A` not found here LL | B = SomeEnum::A, - | ----------^ - | | | - | | help: did you mean: `B` - | variant not found in `SomeEnum` + | ^ + | | + | variant or associated item not found in `SomeEnum` + | help: there is a variant with a similar name: `B` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23281.rs b/src/test/ui/issues/issue-23281.rs index 98a0495451d04..d5f7472886273 100644 --- a/src/test/ui/issues/issue-23281.rs +++ b/src/test/ui/issues/issue-23281.rs @@ -1,9 +1,7 @@ -// ignore-tidy-linelength - pub struct Struct; impl Struct { - pub fn function(funs: Vec ()>) {} + pub fn function(funs: Vec ()>) {} //~^ ERROR the size for values of type } diff --git a/src/test/ui/issues/issue-23281.stderr b/src/test/ui/issues/issue-23281.stderr index 1e57774afe55a..f1def47458368 100644 --- a/src/test/ui/issues/issue-23281.stderr +++ b/src/test/ui/issues/issue-23281.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `(dyn std::ops::Fn() + 'static)` cannot be known at compilation time - --> $DIR/issue-23281.rs:6:5 + --> $DIR/issue-23281.rs:4:5 | -LL | pub fn function(funs: Vec ()>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time +LL | pub fn function(funs: Vec ()>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)` = note: to learn more, visit diff --git a/src/test/ui/issues/issue-2330.stderr b/src/test/ui/issues/issue-2330.stderr index 472ad199a6393..877cf68b5866c 100644 --- a/src/test/ui/issues/issue-2330.stderr +++ b/src/test/ui/issues/issue-2330.stderr @@ -1,7 +1,7 @@ error[E0404]: expected trait, found enum `Chan` --> $DIR/issue-2330.rs:8:6 | -LL | impl Chan for isize { //~ ERROR expected trait, found enum `Chan` +LL | impl Chan for isize { | ^^^^ not a trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23302-1.stderr b/src/test/ui/issues/issue-23302-1.stderr index ed422e10c985e..bbdb13a95007b 100644 --- a/src/test/ui/issues/issue-23302-1.stderr +++ b/src/test/ui/issues/issue-23302-1.stderr @@ -1,14 +1,14 @@ -error[E0391]: cycle detected when processing `X::A::{{constant}}` +error[E0391]: cycle detected when processing `X::A::{{constant}}#0` --> $DIR/issue-23302-1.rs:4:9 | -LL | A = X::A as isize, //~ ERROR E0391 +LL | A = X::A as isize, | ^^^^^^^^^^^^^ | - = note: ...which again requires processing `X::A::{{constant}}`, completing the cycle -note: cycle used when const-evaluating `X::A::{{constant}}` + = note: ...which again requires processing `X::A::{{constant}}#0`, completing the cycle +note: cycle used when processing `X::A::{{constant}}#0` --> $DIR/issue-23302-1.rs:4:9 | -LL | A = X::A as isize, //~ ERROR E0391 +LL | A = X::A as isize, | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23302-2.stderr b/src/test/ui/issues/issue-23302-2.stderr index b6d44ceec9d75..03afd82211a7e 100644 --- a/src/test/ui/issues/issue-23302-2.stderr +++ b/src/test/ui/issues/issue-23302-2.stderr @@ -1,14 +1,14 @@ -error[E0391]: cycle detected when processing `Y::A::{{constant}}` +error[E0391]: cycle detected when processing `Y::A::{{constant}}#0` --> $DIR/issue-23302-2.rs:4:9 | -LL | A = Y::B as isize, //~ ERROR E0391 +LL | A = Y::B as isize, | ^^^^^^^^^^^^^ | - = note: ...which again requires processing `Y::A::{{constant}}`, completing the cycle -note: cycle used when const-evaluating `Y::A::{{constant}}` + = note: ...which again requires processing `Y::A::{{constant}}#0`, completing the cycle +note: cycle used when processing `Y::A::{{constant}}#0` --> $DIR/issue-23302-2.rs:4:9 | -LL | A = Y::B as isize, //~ ERROR E0391 +LL | A = Y::B as isize, | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23302-3.stderr b/src/test/ui/issues/issue-23302-3.stderr index b3ca736622a2a..a7d643987f710 100644 --- a/src/test/ui/issues/issue-23302-3.stderr +++ b/src/test/ui/issues/issue-23302-3.stderr @@ -1,13 +1,13 @@ error[E0391]: cycle detected when const checking if rvalue is promotable to static `A` --> $DIR/issue-23302-3.rs:1:1 | -LL | const A: i32 = B; //~ ERROR cycle detected +LL | const A: i32 = B; | ^^^^^^^^^^^^^^^^^ | note: ...which requires checking which parts of `A` are promotable to static... --> $DIR/issue-23302-3.rs:1:16 | -LL | const A: i32 = B; //~ ERROR cycle detected +LL | const A: i32 = B; | ^ note: ...which requires const checking if rvalue is promotable to static `B`... --> $DIR/issue-23302-3.rs:3:1 diff --git a/src/test/ui/issues/issue-23458.rs b/src/test/ui/issues/issue-23458.rs new file mode 100644 index 0000000000000..90b3f1f9714b2 --- /dev/null +++ b/src/test/ui/issues/issue-23458.rs @@ -0,0 +1,10 @@ +#![feature(asm)] + +// only-x86_64 + +fn main() { + unsafe { + asm!("int $3"); //~ ERROR too few operands for instruction + //~| ERROR invalid operand in inline asm + } +} diff --git a/src/test/ui/issues/issue-23458.stderr b/src/test/ui/issues/issue-23458.stderr new file mode 100644 index 0000000000000..aff0f82af6fdc --- /dev/null +++ b/src/test/ui/issues/issue-23458.stderr @@ -0,0 +1,17 @@ +error: invalid operand in inline asm: 'int $3' + --> $DIR/issue-23458.rs:7:9 + | +LL | asm!("int $3"); + | ^^^^^^^^^^^^^^^ + +error: :1:2: error: too few operands for instruction + int + ^ + + --> $DIR/issue-23458.rs:7:9 + | +LL | asm!("int $3"); + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/issues/issue-23589.stderr b/src/test/ui/issues/issue-23589.stderr index bc2007ba39cc6..d169fdfe2dddd 100644 --- a/src/test/ui/issues/issue-23589.stderr +++ b/src/test/ui/issues/issue-23589.stderr @@ -18,5 +18,5 @@ LL | let v: Vec(&str) = vec!['1', '2']; error: aborting due to 2 previous errors -Some errors occurred: E0214, E0308. +Some errors have detailed explanations: E0214, E0308. For more information about an error, try `rustc --explain E0214`. diff --git a/src/test/ui/issues/issue-24081.stderr b/src/test/ui/issues/issue-24081.stderr index 999ac0d5570e3..647048c7c2012 100644 --- a/src/test/ui/issues/issue-24081.stderr +++ b/src/test/ui/issues/issue-24081.stderr @@ -4,7 +4,7 @@ error[E0255]: the name `Add` is defined multiple times LL | use std::ops::Add; | ------------- previous import of the trait `Add` here ... -LL | type Add = bool; //~ ERROR the name `Add` is defined multiple times +LL | type Add = bool; | ^^^^^^^^^^^^^^^^ `Add` redefined here | = note: `Add` must be defined only once in the type namespace of this module @@ -19,7 +19,7 @@ error[E0255]: the name `Sub` is defined multiple times LL | use std::ops::Sub; | ------------- previous import of the trait `Sub` here ... -LL | struct Sub { x: f32 } //~ ERROR the name `Sub` is defined multiple times +LL | struct Sub { x: f32 } | ^^^^^^^^^^ `Sub` redefined here | = note: `Sub` must be defined only once in the type namespace of this module @@ -34,7 +34,7 @@ error[E0255]: the name `Mul` is defined multiple times LL | use std::ops::Mul; | ------------- previous import of the trait `Mul` here ... -LL | enum Mul { A, B } //~ ERROR the name `Mul` is defined multiple times +LL | enum Mul { A, B } | ^^^^^^^^ `Mul` redefined here | = note: `Mul` must be defined only once in the type namespace of this module @@ -49,7 +49,7 @@ error[E0255]: the name `Div` is defined multiple times LL | use std::ops::Div; | ------------- previous import of the trait `Div` here ... -LL | mod Div { } //~ ERROR the name `Div` is defined multiple times +LL | mod Div { } | ^^^^^^^ `Div` redefined here | = note: `Div` must be defined only once in the type namespace of this module @@ -64,7 +64,7 @@ error[E0255]: the name `Rem` is defined multiple times LL | use std::ops::Rem; | ------------- previous import of the trait `Rem` here ... -LL | trait Rem { } //~ ERROR the name `Rem` is defined multiple times +LL | trait Rem { } | ^^^^^^^^^ `Rem` redefined here | = note: `Rem` must be defined only once in the type namespace of this module diff --git a/src/test/ui/issues/issue-24267-flow-exit.nll.stderr b/src/test/ui/issues/issue-24267-flow-exit.nll.stderr deleted file mode 100644 index 52e637a3f0b0b..0000000000000 --- a/src/test/ui/issues/issue-24267-flow-exit.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/issue-24267-flow-exit.rs:12:20 - | -LL | println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` - | ^ use of possibly uninitialized `x` - -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/issue-24267-flow-exit.rs:18:20 - | -LL | println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` - | ^ use of possibly uninitialized `x` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/issues/issue-24267-flow-exit.rs b/src/test/ui/issues/issue-24267-flow-exit.rs index ce3a799fb3817..a1b4d75d4048f 100644 --- a/src/test/ui/issues/issue-24267-flow-exit.rs +++ b/src/test/ui/issues/issue-24267-flow-exit.rs @@ -9,11 +9,11 @@ pub fn main() { pub fn foo1() { let x: i32; loop { x = break; } - println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` + println!("{}", x); //~ ERROR borrow of possibly uninitialized variable: `x` } pub fn foo2() { let x: i32; for _ in 0..10 { x = continue; } - println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` + println!("{}", x); //~ ERROR borrow of possibly uninitialized variable: `x` } diff --git a/src/test/ui/issues/issue-24267-flow-exit.stderr b/src/test/ui/issues/issue-24267-flow-exit.stderr index 0d226e01809be..3b4f27621f696 100644 --- a/src/test/ui/issues/issue-24267-flow-exit.stderr +++ b/src/test/ui/issues/issue-24267-flow-exit.stderr @@ -1,13 +1,13 @@ -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly uninitialized variable: `x` --> $DIR/issue-24267-flow-exit.rs:12:20 | -LL | println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` +LL | println!("{}", x); | ^ use of possibly uninitialized `x` -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly uninitialized variable: `x` --> $DIR/issue-24267-flow-exit.rs:18:20 | -LL | println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` +LL | println!("{}", x); | ^ use of possibly uninitialized `x` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-24322.stderr b/src/test/ui/issues/issue-24322.stderr index b42854387518e..def373cf2c0a8 100644 --- a/src/test/ui/issues/issue-24322.stderr +++ b/src/test/ui/issues/issue-24322.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-24322.rs:8:29 | -LL | let x: &fn(&B) -> u32 = &B::func; //~ ERROR mismatched types +LL | let x: &fn(&B) -> u32 = &B::func; | ^^^^^^^^ expected fn pointer, found fn item | = note: expected type `&for<'r> fn(&'r B) -> u32` diff --git a/src/test/ui/issues/issue-24352.stderr b/src/test/ui/issues/issue-24352.stderr index 835706d015b5c..a315ca8b08f59 100644 --- a/src/test/ui/issues/issue-24352.stderr +++ b/src/test/ui/issues/issue-24352.stderr @@ -1,7 +1,7 @@ error[E0277]: cannot subtract `{integer}` from `f64` --> $DIR/issue-24352.rs:3:12 | -LL | 1.0f64 - 1 //~ ERROR E0277 +LL | 1.0f64 - 1 | ^ no implementation for `f64 - {integer}` | = help: the trait `std::ops::Sub<{integer}>` is not implemented for `f64` diff --git a/src/test/ui/issues/issue-24357.nll.stderr b/src/test/ui/issues/issue-24357.nll.stderr deleted file mode 100644 index 310535434cd08..0000000000000 --- a/src/test/ui/issues/issue-24357.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0382]: use of moved value: `x` - --> $DIR/issue-24357.rs:6:12 - | -LL | let x = NoCopy; - | - move occurs because `x` has type `NoCopy`, which does not implement the `Copy` trait -LL | let f = move || { let y = x; }; - | ------- - variable moved due to use in closure - | | - | value moved into closure here -LL | //~^ NOTE value moved (into closure) here -LL | let z = x; - | ^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/issues/issue-24357.rs b/src/test/ui/issues/issue-24357.rs index 84f263ff649c4..152e69ebc873f 100644 --- a/src/test/ui/issues/issue-24357.rs +++ b/src/test/ui/issues/issue-24357.rs @@ -1,10 +1,11 @@ struct NoCopy; fn main() { let x = NoCopy; + //~^ NOTE move occurs because `x` has type `NoCopy` let f = move || { let y = x; }; - //~^ NOTE value moved (into closure) here + //~^ NOTE value moved into closure here + //~| NOTE variable moved due to use in closure let z = x; //~^ ERROR use of moved value: `x` //~| NOTE value used here after move - //~| NOTE move occurs because `x` has type `NoCopy` } diff --git a/src/test/ui/issues/issue-24357.stderr b/src/test/ui/issues/issue-24357.stderr index 3bc84cba0f53f..b9e15f5e21bab 100644 --- a/src/test/ui/issues/issue-24357.stderr +++ b/src/test/ui/issues/issue-24357.stderr @@ -1,13 +1,16 @@ error[E0382]: use of moved value: `x` - --> $DIR/issue-24357.rs:6:8 + --> $DIR/issue-24357.rs:8:12 | +LL | let x = NoCopy; + | - move occurs because `x` has type `NoCopy`, which does not implement the `Copy` trait +LL | LL | let f = move || { let y = x; }; - | ------- value moved (into closure) here -LL | //~^ NOTE value moved (into closure) here + | ------- - variable moved due to use in closure + | | + | value moved into closure here +... LL | let z = x; - | ^ value used here after move - | - = note: move occurs because `x` has type `NoCopy`, which does not implement the `Copy` trait + | ^ value used here after move error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24363.stderr b/src/test/ui/issues/issue-24363.stderr index ff02887a15392..50d65e09bb1cc 100644 --- a/src/test/ui/issues/issue-24363.stderr +++ b/src/test/ui/issues/issue-24363.stderr @@ -1,18 +1,20 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> $DIR/issue-24363.rs:2:7 | -LL | 1.create_a_type_error[ //~ `{integer}` is a primitive type and therefore doesn't have fields +LL | 1.create_a_type_error[ | ^^^^^^^^^^^^^^^^^^^ error[E0369]: binary operation `+` cannot be applied to type `()` - --> $DIR/issue-24363.rs:3:9 + --> $DIR/issue-24363.rs:3:11 | -LL | ()+() //~ ERROR binary operation `+` cannot be applied - | ^^^^^ +LL | ()+() + | --^-- () + | | + | () | = note: an implementation of `std::ops::Add` might be missing for `()` error: aborting due to 2 previous errors -Some errors occurred: E0369, E0610. +Some errors have detailed explanations: E0369, E0610. For more information about an error, try `rustc --explain E0369`. diff --git a/src/test/ui/issues/issue-24365.stderr b/src/test/ui/issues/issue-24365.stderr index 7d02f117f9f55..f9eead8a4f213 100644 --- a/src/test/ui/issues/issue-24365.stderr +++ b/src/test/ui/issues/issue-24365.stderr @@ -1,19 +1,19 @@ error[E0609]: no field `b` on type `Foo` --> $DIR/issue-24365.rs:10:22 | -LL | println!("{}", a.b); //~ no field `b` on type `Foo` +LL | println!("{}", a.b); | ^ error[E0609]: no field `attr_name_idx` on type `&Attribute` --> $DIR/issue-24365.rs:17:18 | -LL | let z = (&x).attr_name_idx; //~ no field `attr_name_idx` on type `&Attribute` +LL | let z = (&x).attr_name_idx; | ^^^^^^^^^^^^^ error[E0609]: no field `attr_name_idx` on type `Attribute` --> $DIR/issue-24365.rs:18:15 | -LL | let y = x.attr_name_idx; //~ no field `attr_name_idx` on type `Attribute` +LL | let y = x.attr_name_idx; | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-24434.rs b/src/test/ui/issues/issue-24434.rs index 7b270ceb68814..2424a1c92cd64 100644 --- a/src/test/ui/issues/issue-24434.rs +++ b/src/test/ui/issues/issue-24434.rs @@ -1,8 +1,7 @@ // compile-pass -#![allow(unused_attributes)] // compile-flags:--cfg set1 -#![cfg_attr(set1, feature(custom_attribute))] +#![cfg_attr(set1, feature(rustc_attrs))] +#![rustc_dummy] -#![foobar] fn main() {} diff --git a/src/test/ui/issues/issue-24446.rs b/src/test/ui/issues/issue-24446.rs index c5e1b49e5ed1c..ffd6dfabc2890 100644 --- a/src/test/ui/issues/issue-24446.rs +++ b/src/test/ui/issues/issue-24446.rs @@ -1,5 +1,5 @@ fn main() { - static foo: Fn() -> u32 = || -> u32 { + static foo: dyn Fn() -> u32 = || -> u32 { //~^ ERROR the size for values of type 0 }; diff --git a/src/test/ui/issues/issue-24446.stderr b/src/test/ui/issues/issue-24446.stderr index ffec73b1ab4a8..344443e783038 100644 --- a/src/test/ui/issues/issue-24446.stderr +++ b/src/test/ui/issues/issue-24446.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `(dyn std::ops::Fn() -> u32 + 'static)` cannot be known at compilation time --> $DIR/issue-24446.rs:2:17 | -LL | static foo: Fn() -> u32 = || -> u32 { - | ^^^^^^^^^^^ doesn't have a size known at compile-time +LL | static foo: dyn Fn() -> u32 = || -> u32 { + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() -> u32 + 'static)` = note: to learn more, visit diff --git a/src/test/ui/issues/issue-24682.stderr b/src/test/ui/issues/issue-24682.stderr index f6d03f6c18fdc..e1943bf4d6837 100644 --- a/src/test/ui/issues/issue-24682.stderr +++ b/src/test/ui/issues/issue-24682.stderr @@ -1,20 +1,20 @@ error[E0229]: associated type bindings are not allowed here --> $DIR/issue-24682.rs:5:11 | -LL | / N= //~ ERROR associated type bindings are not allowed here +LL | / N= LL | | Self::N> { | |_________________^ associated type not allowed here error[E0229]: associated type bindings are not allowed here --> $DIR/issue-24682.rs:11:13 | -LL | //~ ERROR associated type bindings are not allowed here +LL | | ^^^^ associated type not allowed here error[E0229]: associated type bindings are not allowed here --> $DIR/issue-24682.rs:15:13 | -LL | u32 //~ ERROR associated type bindings are not allowed here +LL | u32 | ^^^^ associated type not allowed here error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-24883.rs b/src/test/ui/issues/issue-24883.rs index 1aa62d3a3b6ed..819a20ddbda92 100644 --- a/src/test/ui/issues/issue-24883.rs +++ b/src/test/ui/issues/issue-24883.rs @@ -1,5 +1,5 @@ -// compile-pass -// skip-codegen +// check-pass + mod a { pub mod b { pub struct Foo; } @@ -11,7 +11,6 @@ mod a { pub use self::c::*; } - fn main() { let _ = a::c::Bar(a::b::Foo); let _ = a::Bar(a::b::Foo); diff --git a/src/test/ui/issues/issue-25076.stderr b/src/test/ui/issues/issue-25076.stderr index 8793475e6d4ed..435ab13edada5 100644 --- a/src/test/ui/issues/issue-25076.stderr +++ b/src/test/ui/issues/issue-25076.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `(): InOut<_>` is not satisfied --> $DIR/issue-25076.rs:10:5 | -LL | do_fold(bot(), ()); //~ ERROR `(): InOut<_>` is not satisfied +LL | do_fold(bot(), ()); | ^^^^^^^ the trait `InOut<_>` is not implemented for `()` | note: required by `do_fold` diff --git a/src/test/ui/issues/issue-25180.rs b/src/test/ui/issues/issue-25180.rs index 739d571d7275f..297f403c05ee7 100644 --- a/src/test/ui/issues/issue-25180.rs +++ b/src/test/ui/issues/issue-25180.rs @@ -2,6 +2,6 @@ #![allow(dead_code)] #![allow(non_upper_case_globals)] -const x: &'static Fn() = &|| println!("ICE here"); +const x: &'static dyn Fn() = &|| println!("ICE here"); fn main() {} diff --git a/src/test/ui/issues/issue-25368.stderr b/src/test/ui/issues/issue-25368.stderr index 2e6a02e7389a7..0b890b573da13 100644 --- a/src/test/ui/issues/issue-25368.stderr +++ b/src/test/ui/issues/issue-25368.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `(std::sync::mpsc::Sender>, std::sync::mpsc::Receiver>)` --> $DIR/issue-25368.rs:11:17 | LL | let (tx, rx) = channel(); - | -------- consider giving the pattern a type + | -------- consider giving this pattern the explicit type `(std::sync::mpsc::Sender>, std::sync::mpsc::Receiver>)`, where the type parameter `T` is specified ... -LL | tx.send(Foo{ foo: PhantomData }); //~ ERROR E0282 +LL | tx.send(Foo{ foo: PhantomData }); | ^^^ cannot infer type for `T` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-25396.stderr b/src/test/ui/issues/issue-25396.stderr index aae62b688d4a7..38dc9ef103519 100644 --- a/src/test/ui/issues/issue-25396.stderr +++ b/src/test/ui/issues/issue-25396.stderr @@ -3,13 +3,13 @@ error[E0252]: the name `baz` is defined multiple times | LL | use foo::baz; | -------- previous import of the module `baz` here -LL | use bar::baz; //~ ERROR the name `baz` is defined multiple times +LL | use bar::baz; | ^^^^^^^^ `baz` reimported here | = note: `baz` must be defined only once in the type namespace of this module help: you can use `as` to change the binding name of the import | -LL | use bar::baz as other_baz; //~ ERROR the name `baz` is defined multiple times +LL | use bar::baz as other_baz; | ^^^^^^^^^^^^^^^^^^^^^ error[E0252]: the name `Quux` is defined multiple times @@ -17,13 +17,13 @@ error[E0252]: the name `Quux` is defined multiple times | LL | use foo::Quux; | --------- previous import of the trait `Quux` here -LL | use bar::Quux; //~ ERROR the name `Quux` is defined multiple times +LL | use bar::Quux; | ^^^^^^^^^ `Quux` reimported here | = note: `Quux` must be defined only once in the type namespace of this module help: you can use `as` to change the binding name of the import | -LL | use bar::Quux as OtherQuux; //~ ERROR the name `Quux` is defined multiple times +LL | use bar::Quux as OtherQuux; | ^^^^^^^^^^^^^^^^^^^^^^ error[E0252]: the name `blah` is defined multiple times @@ -31,13 +31,13 @@ error[E0252]: the name `blah` is defined multiple times | LL | use foo::blah; | --------- previous import of the type `blah` here -LL | use bar::blah; //~ ERROR the name `blah` is defined multiple times +LL | use bar::blah; | ^^^^^^^^^ `blah` reimported here | = note: `blah` must be defined only once in the type namespace of this module help: you can use `as` to change the binding name of the import | -LL | use bar::blah as other_blah; //~ ERROR the name `blah` is defined multiple times +LL | use bar::blah as other_blah; | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0252]: the name `WOMP` is defined multiple times @@ -45,13 +45,13 @@ error[E0252]: the name `WOMP` is defined multiple times | LL | use foo::WOMP; | --------- previous import of the value `WOMP` here -LL | use bar::WOMP; //~ ERROR the name `WOMP` is defined multiple times +LL | use bar::WOMP; | ^^^^^^^^^ `WOMP` reimported here | = note: `WOMP` must be defined only once in the value namespace of this module help: you can use `as` to change the binding name of the import | -LL | use bar::WOMP as OtherWOMP; //~ ERROR the name `WOMP` is defined multiple times +LL | use bar::WOMP as OtherWOMP; | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-25439.stderr b/src/test/ui/issues/issue-25439.stderr index 9e9ab4e39d34c..9b04148313256 100644 --- a/src/test/ui/issues/issue-25439.stderr +++ b/src/test/ui/issues/issue-25439.stderr @@ -1,7 +1,7 @@ error[E0644]: closure/generator type that references itself --> $DIR/issue-25439.rs:8:9 | -LL | fix(|_, x| x); //~ ERROR closure/generator type that references itself [E0644] +LL | fix(|_, x| x); | ^^^^^^^^ cyclic type of infinite size | = note: closures cannot capture themselves or take themselves as argument; diff --git a/src/test/ui/issues/issue-25579.ast.nll.stderr b/src/test/ui/issues/issue-25579.ast.nll.stderr deleted file mode 100644 index b791f600f50cb..0000000000000 --- a/src/test/ui/issues/issue-25579.ast.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error: compilation successful - --> $DIR/issue-25579.rs:21:1 - | -LL | / fn main() { //[mir]~ ERROR compilation successful -LL | | } - | |_^ - -error: aborting due to previous error - diff --git a/src/test/ui/issues/issue-25579.ast.stderr b/src/test/ui/issues/issue-25579.ast.stderr deleted file mode 100644 index 3de7f565b7b8a..0000000000000 --- a/src/test/ui/issues/issue-25579.ast.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0499]: cannot borrow `l.0` as mutable more than once at a time - --> $DIR/issue-25579.rs:14:32 - | -LL | &mut Sexpression::Cons(ref mut expr) => { //[ast]~ ERROR [E0499] - | ^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop -... -LL | } - | - mutable borrow ends here - -error[E0506]: cannot assign to `l` because it is borrowed - --> $DIR/issue-25579.rs:15:13 - | -LL | &mut Sexpression::Cons(ref mut expr) => { //[ast]~ ERROR [E0499] - | ------------ borrow of `l` occurs here -LL | l = &mut **expr; //[ast]~ ERROR [E0506] - | ^^^^^^^^^^^^^^^ assignment to borrowed `l` occurs here - -error: aborting due to 2 previous errors - -Some errors occurred: E0499, E0506. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/issues/issue-25579.mir.stderr b/src/test/ui/issues/issue-25579.mir.stderr deleted file mode 100644 index b791f600f50cb..0000000000000 --- a/src/test/ui/issues/issue-25579.mir.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error: compilation successful - --> $DIR/issue-25579.rs:21:1 - | -LL | / fn main() { //[mir]~ ERROR compilation successful -LL | | } - | |_^ - -error: aborting due to previous error - diff --git a/src/test/ui/issues/issue-25579.rs b/src/test/ui/issues/issue-25579.rs index 1813253332f98..31ba102746b34 100644 --- a/src/test/ui/issues/issue-25579.rs +++ b/src/test/ui/issues/issue-25579.rs @@ -1,7 +1,4 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - -#![feature(rustc_attrs)] +// compile-pass enum Sexpression { Num(()), @@ -11,12 +8,13 @@ enum Sexpression { fn causes_error_in_ast(mut l: &mut Sexpression) { loop { match l { &mut Sexpression::Num(ref mut n) => {}, - &mut Sexpression::Cons(ref mut expr) => { //[ast]~ ERROR [E0499] - l = &mut **expr; //[ast]~ ERROR [E0506] + &mut Sexpression::Cons(ref mut expr) => { + l = &mut **expr; } }} } -#[rustc_error] -fn main() { //[mir]~ ERROR compilation successful + +fn main() { + causes_error_in_ast(&mut Sexpression::Num(())); } diff --git a/src/test/ui/issues/issue-25700.nll.stderr b/src/test/ui/issues/issue-25700.nll.stderr deleted file mode 100644 index ba5403cca4d06..0000000000000 --- a/src/test/ui/issues/issue-25700.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: use of moved value: `t` - --> $DIR/issue-25700.rs:13:10 - | -LL | let t = S::<()>(None); - | - move occurs because `t` has type `S<()>`, which does not implement the `Copy` trait -LL | drop(t); - | - value moved here -LL | drop(t); //~ ERROR use of moved value - | ^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/issues/issue-25700.stderr b/src/test/ui/issues/issue-25700.stderr index d4cf89d0abd5f..fa309a55c3c22 100644 --- a/src/test/ui/issues/issue-25700.stderr +++ b/src/test/ui/issues/issue-25700.stderr @@ -1,12 +1,12 @@ error[E0382]: use of moved value: `t` --> $DIR/issue-25700.rs:13:10 | +LL | let t = S::<()>(None); + | - move occurs because `t` has type `S<()>`, which does not implement the `Copy` trait LL | drop(t); | - value moved here -LL | drop(t); //~ ERROR use of moved value +LL | drop(t); | ^ value used here after move - | - = note: move occurs because `t` has type `S<()>`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-25793.nll.stderr b/src/test/ui/issues/issue-25793.nll.stderr deleted file mode 100644 index daea9cd8cd717..0000000000000 --- a/src/test/ui/issues/issue-25793.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0503]: cannot use `self.width` because it was mutably borrowed - --> $DIR/issue-25793.rs:4:9 - | -LL | $this.width.unwrap() - | ^^^^^^^^^^^ use of borrowed `*self` -... -LL | let r = &mut *self; - | ---------- borrow of `*self` occurs here -LL | r.get_size(width!(self)) - | -------- ------------ in this macro invocation - | | - | borrow later used by call - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/issues/issue-25793.stderr b/src/test/ui/issues/issue-25793.stderr index e8d208c19aa37..daea9cd8cd717 100644 --- a/src/test/ui/issues/issue-25793.stderr +++ b/src/test/ui/issues/issue-25793.stderr @@ -5,9 +5,11 @@ LL | $this.width.unwrap() | ^^^^^^^^^^^ use of borrowed `*self` ... LL | let r = &mut *self; - | ----- borrow of `*self` occurs here + | ---------- borrow of `*self` occurs here LL | r.get_size(width!(self)) - | ------------ in this macro invocation + | -------- ------------ in this macro invocation + | | + | borrow later used by call error: aborting due to previous error diff --git a/src/test/ui/issues/issue-25826.stderr b/src/test/ui/issues/issue-25826.stderr index dc547f7c32c94..a800f787e38da 100644 --- a/src/test/ui/issues/issue-25826.stderr +++ b/src/test/ui/issues/issue-25826.stderr @@ -1,9 +1,10 @@ -error[E0658]: comparing raw pointers inside constant (see issue #53020) +error[E0658]: comparing raw pointers inside constant --> $DIR/issue-25826.rs:3:30 | LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53020 = help: add #![feature(const_compare_raw_pointers)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2590.nll.stderr b/src/test/ui/issues/issue-2590.nll.stderr deleted file mode 100644 index 1252578419a80..0000000000000 --- a/src/test/ui/issues/issue-2590.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/issue-2590.rs:11:9 - | -LL | self.tokens //~ ERROR cannot move out of borrowed content - | ^^^^^^^^^^^ cannot move out of borrowed content - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/issues/issue-2590.rs b/src/test/ui/issues/issue-2590.rs index 28d023db4f5b5..a9a0e5ca4ec16 100644 --- a/src/test/ui/issues/issue-2590.rs +++ b/src/test/ui/issues/issue-2590.rs @@ -8,7 +8,7 @@ trait Parse { impl Parse for Parser { fn parse(&self) -> Vec { - self.tokens //~ ERROR cannot move out of borrowed content + self.tokens //~ ERROR cannot move out } } diff --git a/src/test/ui/issues/issue-2590.stderr b/src/test/ui/issues/issue-2590.stderr index f93b5db3adfbc..3517d92403fbb 100644 --- a/src/test/ui/issues/issue-2590.stderr +++ b/src/test/ui/issues/issue-2590.stderr @@ -1,8 +1,8 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `self.tokens` which is behind a shared reference --> $DIR/issue-2590.rs:11:9 | -LL | self.tokens //~ ERROR cannot move out of borrowed content - | ^^^^ cannot move out of borrowed content +LL | self.tokens + | ^^^^^^^^^^^ move occurs because `self.tokens` has type `std::vec::Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-26056.rs b/src/test/ui/issues/issue-26056.rs index 0d9973b454843..99d43ec792b3c 100644 --- a/src/test/ui/issues/issue-26056.rs +++ b/src/test/ui/issues/issue-26056.rs @@ -17,6 +17,6 @@ impl Map for K { fn main() { let _ = &() - as &Map; + as &dyn Map; //~^ ERROR E0038 } diff --git a/src/test/ui/issues/issue-26056.stderr b/src/test/ui/issues/issue-26056.stderr index 44fabd0db195a..9c4cf0b18acfe 100644 --- a/src/test/ui/issues/issue-26056.stderr +++ b/src/test/ui/issues/issue-26056.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Map` cannot be made into an object --> $DIR/issue-26056.rs:20:13 | -LL | as &Map; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Map` cannot be made into an object +LL | as &dyn Map; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Map` cannot be made into an object | = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses diff --git a/src/test/ui/issues/issue-26158.stderr b/src/test/ui/issues/issue-26158.stderr index 868ffd191cba7..3a4dd79e81053 100644 --- a/src/test/ui/issues/issue-26158.stderr +++ b/src/test/ui/issues/issue-26158.stderr @@ -1,7 +1,7 @@ error[E0005]: refutable pattern in local binding: `&[]` not covered --> $DIR/issue-26158.rs:5:9 | -LL | let &[[ref _a, ref _b..]..] = x; //~ ERROR refutable pattern +LL | let &[[ref _a, ref _b..]..] = x; | ^^^^^^^^^^^^^^^^^^^^^^^ pattern `&[]` not covered error: aborting due to previous error diff --git a/src/test/ui/issues/issue-26217.nll.stderr b/src/test/ui/issues/issue-26217.nll.stderr new file mode 100644 index 0000000000000..c7601caacdca3 --- /dev/null +++ b/src/test/ui/issues/issue-26217.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/issue-26217.rs:4:5 + | +LL | fn bar<'a>() { + | -- lifetime `'a` defined here +LL | foo::<&'a i32>(); + | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-26217.rs b/src/test/ui/issues/issue-26217.rs index a700807d7f216..05e0462190906 100644 --- a/src/test/ui/issues/issue-26217.rs +++ b/src/test/ui/issues/issue-26217.rs @@ -1,6 +1,10 @@ fn foo() where for<'a> T: 'a {} -fn main<'a>() { +fn bar<'a>() { foo::<&'a i32>(); //~^ ERROR the type `&'a i32` does not fulfill the required lifetime } + +fn main() { + bar(); +} diff --git a/src/test/ui/issues/issue-26217.stderr b/src/test/ui/issues/issue-26217.stderr index be9da569f8be1..8bcc62ab2e73c 100644 --- a/src/test/ui/issues/issue-26217.stderr +++ b/src/test/ui/issues/issue-26217.stderr @@ -8,4 +8,3 @@ LL | foo::<&'a i32>(); error: aborting due to previous error -For more information about this error, try `rustc --explain E0477`. diff --git a/src/test/ui/issues/issue-26448-1.rs b/src/test/ui/issues/issue-26448-1.rs new file mode 100644 index 0000000000000..7d2d75bf2e878 --- /dev/null +++ b/src/test/ui/issues/issue-26448-1.rs @@ -0,0 +1,13 @@ +// run-pass + +pub trait Foo { + fn foo(self) -> T; +} + +impl<'a, T> Foo for &'a str where &'a str: Into { + fn foo(self) -> T { + panic!(); + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-26448-2.rs b/src/test/ui/issues/issue-26448-2.rs new file mode 100644 index 0000000000000..17e7c1f977a6d --- /dev/null +++ b/src/test/ui/issues/issue-26448-2.rs @@ -0,0 +1,21 @@ +// run-pass + +pub struct Bar { + items: Vec<&'static str>, + inner: T, +} + +pub trait IntoBar { + fn into_bar(self) -> Bar; +} + +impl<'a, T> IntoBar for &'a str where &'a str: Into { + fn into_bar(self) -> Bar { + Bar { + items: Vec::new(), + inner: self.into(), + } + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-26448-3.rs b/src/test/ui/issues/issue-26448-3.rs new file mode 100644 index 0000000000000..e57352e57f4fc --- /dev/null +++ b/src/test/ui/issues/issue-26448-3.rs @@ -0,0 +1,25 @@ +// run-pass + +pub struct Item { + _inner: &'static str, +} + +pub struct Bar { + items: Vec, + inner: T, +} + +pub trait IntoBar { + fn into_bar(self) -> Bar; +} + +impl<'a, T> IntoBar for &'a str where &'a str: Into { + fn into_bar(self) -> Bar { + Bar { + items: Vec::new(), + inner: self.into(), + } + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-26459.stderr b/src/test/ui/issues/issue-26459.stderr index 187369263a446..c7909a142bec4 100644 --- a/src/test/ui/issues/issue-26459.stderr +++ b/src/test/ui/issues/issue-26459.stderr @@ -6,4 +6,3 @@ LL | char{ch} => true error: aborting due to previous error -For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/issues/issue-26472.stderr b/src/test/ui/issues/issue-26472.stderr index 8c261d2a3f3eb..245ebeaf972ed 100644 --- a/src/test/ui/issues/issue-26472.stderr +++ b/src/test/ui/issues/issue-26472.stderr @@ -1,7 +1,7 @@ error[E0616]: field `len` of struct `sub::S` is private --> $DIR/issue-26472.rs:11:13 | -LL | let v = s.len; //~ ERROR field `len` of struct `sub::S` is private +LL | let v = s.len; | ^^--- | | | help: a method `len` also exists, call it with parentheses: `len()` @@ -9,7 +9,7 @@ LL | let v = s.len; //~ ERROR field `len` of struct `sub::S` is private error[E0616]: field `len` of struct `sub::S` is private --> $DIR/issue-26472.rs:12:5 | -LL | s.len = v; //~ ERROR field `len` of struct `sub::S` is private +LL | s.len = v; | ^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-26548.stderr b/src/test/ui/issues/issue-26548.stderr index ff197eeeb0fe9..7c1789cc1e993 100644 --- a/src/test/ui/issues/issue-26548.stderr +++ b/src/test/ui/issues/issue-26548.stderr @@ -5,7 +5,7 @@ error[E0391]: cycle detected when computing layout of `std::option::Option` note: cycle used when processing `main` --> $DIR/issue-26548.rs:9:1 | -LL | fn main() { //~ NOTE cycle used when processing `main` +LL | fn main() { | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-26614.rs b/src/test/ui/issues/issue-26614.rs index 11c22020733bb..b8ebbdc5abc3e 100644 --- a/src/test/ui/issues/issue-26614.rs +++ b/src/test/ui/issues/issue-26614.rs @@ -1,6 +1,5 @@ -// compile-pass -// skip-codegen -#![allow(warnings)] +// check-pass + trait Mirror { type It; } @@ -9,8 +8,6 @@ impl Mirror for T { type It = Self; } - - fn main() { let c: ::It = 5; const CCCC: ::It = 5; diff --git a/src/test/ui/issues/issue-26619.rs b/src/test/ui/issues/issue-26619.rs new file mode 100644 index 0000000000000..00e09f3f07764 --- /dev/null +++ b/src/test/ui/issues/issue-26619.rs @@ -0,0 +1,24 @@ +#![feature(slice_patterns)] + +pub struct History<'a> { pub _s: &'a str } + +impl<'a> History<'a> { + pub fn get_page(&self) { + for s in vec!["1|2".to_string()].into_iter().filter_map(|ref line| self.make_entry(line)) { + //~^ ERROR cannot return value referencing function parameter + println!("{:?}", s); + } + } + + fn make_entry(&self, s: &'a String) -> Option<&str> { + let parts: Vec<_> = s.split('|').collect(); + println!("{:?} -> {:?}", s, parts); + + if let [commit, ..] = &parts[..] { Some(commit) } else { None } + } +} + +fn main() { + let h = History{ _s: "" }; + h.get_page(); +} diff --git a/src/test/ui/issues/issue-26619.stderr b/src/test/ui/issues/issue-26619.stderr new file mode 100644 index 0000000000000..d1157cda92bf8 --- /dev/null +++ b/src/test/ui/issues/issue-26619.stderr @@ -0,0 +1,11 @@ +error[E0515]: cannot return value referencing function parameter + --> $DIR/issue-26619.rs:7:76 + | +LL | for s in vec!["1|2".to_string()].into_iter().filter_map(|ref line| self.make_entry(line)) { + | -------- ^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function + | | + | function parameter borrowed here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-26638.rs b/src/test/ui/issues/issue-26638.rs index 0f5ed5caa74cb..72fe4286a06b3 100644 --- a/src/test/ui/issues/issue-26638.rs +++ b/src/test/ui/issues/issue-26638.rs @@ -1,4 +1,4 @@ -fn parse_type(iter: Box+'static>) -> &str { iter.next() } +fn parse_type(iter: Box+'static>) -> &str { iter.next() } //~^ ERROR missing lifetime specifier [E0106] fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } diff --git a/src/test/ui/issues/issue-26638.stderr b/src/test/ui/issues/issue-26638.stderr index 64c2cd43264d0..6d7c1b0c43fce 100644 --- a/src/test/ui/issues/issue-26638.stderr +++ b/src/test/ui/issues/issue-26638.stderr @@ -1,8 +1,8 @@ error[E0106]: missing lifetime specifier - --> $DIR/issue-26638.rs:1:58 + --> $DIR/issue-26638.rs:1:62 | -LL | fn parse_type(iter: Box+'static>) -> &str { iter.next() } - | ^ expected lifetime parameter +LL | fn parse_type(iter: Box+'static>) -> &str { iter.next() } + | ^ expected lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from diff --git a/src/test/ui/issues/issue-26886.stderr b/src/test/ui/issues/issue-26886.stderr index 70dacb353fe07..e2b925ec5a705 100644 --- a/src/test/ui/issues/issue-26886.stderr +++ b/src/test/ui/issues/issue-26886.stderr @@ -3,11 +3,8 @@ error[E0252]: the name `Arc` is defined multiple times | LL | use std::sync::{self, Arc}; | --- previous import of the type `Arc` here -LL | use std::sync::Arc; //~ ERROR the name `Arc` is defined multiple times - | ----^^^^^^^^^^^^^^- - | | | - | | `Arc` reimported here - | help: remove unnecessary import +LL | use std::sync::Arc; + | ^^^^^^^^^^^^^^ `Arc` reimported here | = note: `Arc` must be defined only once in the type namespace of this module @@ -17,11 +14,8 @@ error[E0252]: the name `sync` is defined multiple times LL | use std::sync::{self, Arc}; | ---- previous import of the module `sync` here ... -LL | use std::sync; //~ ERROR the name `sync` is defined multiple times - | ----^^^^^^^^^- - | | | - | | `sync` reimported here - | help: remove unnecessary import +LL | use std::sync; + | ^^^^^^^^^ `sync` reimported here | = note: `sync` must be defined only once in the type namespace of this module diff --git a/src/test/ui/issues/issue-26905.rs b/src/test/ui/issues/issue-26905.rs index 0cd166f4ac694..4c5c67d58bc3d 100644 --- a/src/test/ui/issues/issue-26905.rs +++ b/src/test/ui/issues/issue-26905.rs @@ -19,6 +19,5 @@ fn main() { let data = [1, 2, 3]; let iter = data.iter(); let x = MyRc { _ptr: &iter, _boo: NotPhantomData(PhantomData) }; - let _y: MyRc> = x; + let _y: MyRc> = x; } - diff --git a/src/test/ui/issues/issue-26905.stderr b/src/test/ui/issues/issue-26905.stderr index 93b4d7e36e817..10dbb73258599 100644 --- a/src/test/ui/issues/issue-26905.stderr +++ b/src/test/ui/issues/issue-26905.stderr @@ -1,7 +1,7 @@ error[E0375]: implementing the trait `CoerceUnsized` requires multiple coercions --> $DIR/issue-26905.rs:16:40 | -LL | impl, U: ?Sized> CoerceUnsized> for MyRc{ } //~ERROR +LL | impl, U: ?Sized> CoerceUnsized> for MyRc{ } | ^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions | = note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced diff --git a/src/test/ui/issues/issue-26930.rs b/src/test/ui/issues/issue-26930.rs index abf6b933c3b5f..707e71b11249d 100644 --- a/src/test/ui/issues/issue-26930.rs +++ b/src/test/ui/issues/issue-26930.rs @@ -1,10 +1,8 @@ -// compile-pass -// skip-codegen -#![allow(unused)] +// check-pass + extern crate core; use core as core_export; use self::x::*; mod x {} - fn main() {} diff --git a/src/test/ui/issues/issue-27033.stderr b/src/test/ui/issues/issue-27033.stderr index b343924bb0245..ab95433228037 100644 --- a/src/test/ui/issues/issue-27033.stderr +++ b/src/test/ui/issues/issue-27033.stderr @@ -1,7 +1,7 @@ error[E0530]: match bindings cannot shadow unit variants --> $DIR/issue-27033.rs:3:9 | -LL | None @ _ => {} //~ ERROR match bindings cannot shadow unit variants +LL | None @ _ => {} | ^^^^ cannot be named the same as a unit variant error[E0530]: match bindings cannot shadow constants @@ -10,7 +10,7 @@ error[E0530]: match bindings cannot shadow constants LL | const C: u8 = 1; | ---------------- the constant `C` is defined here LL | match 1 { -LL | C @ 2 => { //~ ERROR match bindings cannot shadow constant +LL | C @ 2 => { | ^ cannot be named the same as a constant error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-27042.stderr b/src/test/ui/issues/issue-27042.stderr index bcefb29c18b05..cce7d24a5f602 100644 --- a/src/test/ui/issues/issue-27042.stderr +++ b/src/test/ui/issues/issue-27042.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-27042.rs:6:16 | -LL | loop { break }; //~ ERROR mismatched types +LL | loop { break }; | ^^^^^ expected (), found i32 | = note: expected type `()` @@ -10,7 +10,7 @@ LL | loop { break }; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/issue-27042.rs:8:9 | -LL | / 'b: //~ ERROR mismatched types +LL | / 'b: LL | | while true { break }; // but here we cite the whole loop | |____________________________^ expected i32, found () | @@ -20,7 +20,7 @@ LL | | while true { break }; // but here we cite the whole loop error[E0308]: mismatched types --> $DIR/issue-27042.rs:11:9 | -LL | / 'c: //~ ERROR mismatched types +LL | / 'c: LL | | for _ in None { break }; // but here we cite the whole loop | |_______________________________^ expected i32, found () | @@ -30,7 +30,7 @@ LL | | for _ in None { break }; // but here we cite the whole loop error[E0308]: mismatched types --> $DIR/issue-27042.rs:14:9 | -LL | / 'd: //~ ERROR mismatched types +LL | / 'd: LL | | while let Some(_) = None { break }; | |__________________________________________^ expected i32, found () | diff --git a/src/test/ui/issues/issue-27060-2.stderr b/src/test/ui/issues/issue-27060-2.stderr index b95c298b6e679..f7227c3410146 100644 --- a/src/test/ui/issues/issue-27060-2.stderr +++ b/src/test/ui/issues/issue-27060-2.stderr @@ -1,7 +1,7 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/issue-27060-2.rs:3:5 | -LL | data: T, //~ ERROR the size for values of type +LL | data: T, | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` diff --git a/src/test/ui/issues/issue-27060.stderr b/src/test/ui/issues/issue-27060.stderr index 023f90eb9fea3..bc44c1a4ac571 100644 --- a/src/test/ui/issues/issue-27060.stderr +++ b/src/test/ui/issues/issue-27060.stderr @@ -1,7 +1,7 @@ error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) --> $DIR/issue-27060.rs:26:13 | -LL | let _ = &good.data; //~ ERROR borrow of packed field is unsafe +LL | let _ = &good.data; | ^^^^^^^^^^ | note: lint level defined here @@ -16,7 +16,7 @@ LL | #[deny(safe_packed_borrows)] error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) --> $DIR/issue-27060.rs:28:13 | -LL | let _ = &good.data2[0]; //~ ERROR borrow of packed field is unsafe +LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/src/test/ui/issues/issue-27105.rs b/src/test/ui/issues/issue-27105.rs index 5f0dff12aec92..1aafa11768fd3 100644 --- a/src/test/ui/issues/issue-27105.rs +++ b/src/test/ui/issues/issue-27105.rs @@ -3,7 +3,7 @@ use std::cell::RefCell; use std::rc::Rc; pub struct Callbacks { - callbacks: Vec>>, + callbacks: Vec>>, } impl Callbacks { diff --git a/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.rs b/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.rs index 1312aff30fecf..e570b04a2bead 100644 --- a/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.rs +++ b/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.rs @@ -12,7 +12,7 @@ fn main() { None => {}, ref mut foo if { (|| { let bar = foo; bar.take() })(); false } => {}, - //~^ ERROR cannot move out of borrowed content [E0507] + //~^ ERROR cannot move out of `foo` in pattern guard [E0507] Some(s) => std::process::exit(*s), } } diff --git a/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr b/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr index b5973ba8bd56e..c5a9dd98a1596 100644 --- a/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr +++ b/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr @@ -1,8 +1,14 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/issue-27282-move-ref-mut-into-guard.rs:14:18 +error[E0507]: cannot move out of `foo` in pattern guard + --> $DIR/issue-27282-move-ref-mut-into-guard.rs:14:19 | LL | if { (|| { let bar = foo; bar.take() })(); false } => {}, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | ^^ --- + | | | + | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs due to use in closure + | move out of `foo` occurs here + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error: aborting due to previous error diff --git a/src/test/ui/issues/issue-27340.stderr b/src/test/ui/issues/issue-27340.stderr index 634a31a89d557..05b213b293cbf 100644 --- a/src/test/ui/issues/issue-27340.stderr +++ b/src/test/ui/issues/issue-27340.stderr @@ -3,7 +3,7 @@ error[E0204]: the trait `Copy` may not be implemented for this type | LL | #[derive(Copy, Clone)] | ^^^^ -LL | //~^ ERROR the trait `Copy` may not be implemented for this type +LL | LL | struct Bar(Foo); | --- this field does not implement `Copy` diff --git a/src/test/ui/issues/issue-27592.nll.stderr b/src/test/ui/issues/issue-27592.nll.stderr deleted file mode 100644 index 9d3eaa9705d44..0000000000000 --- a/src/test/ui/issues/issue-27592.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0515]: cannot return value referencing temporary value - --> $DIR/issue-27592.rs:16:14 - | -LL | write(|| format_args!("{}", String::from("Hello world"))); - | ^^^^^^^^^^^^^^^^^^^---------------------------^ - | | | - | | temporary value created here - | returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing temporary value - --> $DIR/issue-27592.rs:16:14 - | -LL | write(|| format_args!("{}", String::from("Hello world"))); - | ^^^^^^^^^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | temporary value created here - | returns a value referencing data owned by the current function - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-27592.rs b/src/test/ui/issues/issue-27592.rs index 6006f9a7c51d6..b023ea18ac9a9 100644 --- a/src/test/ui/issues/issue-27592.rs +++ b/src/test/ui/issues/issue-27592.rs @@ -14,6 +14,6 @@ impl ::std::fmt::Write for Stream { fn main() { write(|| format_args!("{}", String::from("Hello world"))); - //~^ ERROR borrowed value does not live long enough - //~| ERROR borrowed value does not live long enough + //~^ ERROR cannot return value referencing temporary value + //~| ERROR cannot return value referencing temporary value } diff --git a/src/test/ui/issues/issue-27592.stderr b/src/test/ui/issues/issue-27592.stderr index 0f62abee1ca88..9d3eaa9705d44 100644 --- a/src/test/ui/issues/issue-27592.stderr +++ b/src/test/ui/issues/issue-27592.stderr @@ -1,21 +1,21 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/issue-27592.rs:16:27 +error[E0515]: cannot return value referencing temporary value + --> $DIR/issue-27592.rs:16:14 | LL | write(|| format_args!("{}", String::from("Hello world"))); - | ^^^^ -- temporary value needs to live until here - | | | - | | temporary value dropped here while still borrowed - | temporary value does not live long enough + | ^^^^^^^^^^^^^^^^^^^---------------------------^ + | | | + | | temporary value created here + | returns a value referencing data owned by the current function -error[E0597]: borrowed value does not live long enough - --> $DIR/issue-27592.rs:16:33 +error[E0515]: cannot return value referencing temporary value + --> $DIR/issue-27592.rs:16:14 | LL | write(|| format_args!("{}", String::from("Hello world"))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value needs to live until here - | | | - | | temporary value dropped here while still borrowed - | temporary value does not live long enough + | ^^^^^^^^^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | temporary value created here + | returns a value referencing data owned by the current function error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-27697.rs b/src/test/ui/issues/issue-27697.rs new file mode 100644 index 0000000000000..83070012f5f04 --- /dev/null +++ b/src/test/ui/issues/issue-27697.rs @@ -0,0 +1,21 @@ +// run-pass + +use std::ops::Deref; + +trait MyTrait { + fn do_something(&self); + fn as_str(&self) -> &str; +} + +impl Deref for dyn MyTrait { + type Target = str; + fn deref(&self) -> &Self::Target { + self.as_str() + } +} + +fn trait_object_does_something(t: &dyn MyTrait) { + t.do_something() +} + +fn main() {} diff --git a/src/test/ui/issues/issue-27815.stderr b/src/test/ui/issues/issue-27815.stderr index fbddd3be9dcea..1d68e3bf558f3 100644 --- a/src/test/ui/issues/issue-27815.stderr +++ b/src/test/ui/issues/issue-27815.stderr @@ -1,13 +1,13 @@ error[E0574]: expected struct, variant or union type, found module `A` --> $DIR/issue-27815.rs:4:13 | -LL | let u = A { x: 1 }; //~ ERROR expected struct, variant or union type, found module `A` +LL | let u = A { x: 1 }; | ^ not a struct, variant or union type error[E0574]: expected struct, variant or union type, found builtin type `u32` --> $DIR/issue-27815.rs:5:13 | -LL | let v = u32 { x: 1 }; //~ ERROR expected struct, variant or union type, found builtin type `u32` +LL | let v = u32 { x: 1 }; | ^^^ not a struct, variant or union type error[E0574]: expected struct, variant or union type, found module `A` @@ -24,4 +24,3 @@ LL | u32 { x: 1 } => {} error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/issues/issue-28105.stderr b/src/test/ui/issues/issue-28105.stderr index 900bc43bfc8ad..0e1b90e65209b 100644 --- a/src/test/ui/issues/issue-28105.stderr +++ b/src/test/ui/issues/issue-28105.stderr @@ -1,13 +1,13 @@ error[E0268]: `continue` outside of loop --> $DIR/issue-28105.rs:4:5 | -LL | continue //~ ERROR `continue` outside of loop +LL | continue | ^^^^^^^^ cannot break outside of a loop error[E0268]: `break` outside of loop --> $DIR/issue-28105.rs:6:5 | -LL | break //~ ERROR `break` outside of loop +LL | break | ^^^^^ cannot break outside of a loop error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-28109.stderr b/src/test/ui/issues/issue-28109.stderr index 91a8297256435..0f918d3b6f702 100644 --- a/src/test/ui/issues/issue-28109.stderr +++ b/src/test/ui/issues/issue-28109.stderr @@ -1,13 +1,13 @@ error[E0426]: use of undeclared label `'b` --> $DIR/issue-28109.rs:6:9 | -LL | 'b //~ ERROR use of undeclared label +LL | 'b | ^^ undeclared label `'b` error[E0426]: use of undeclared label `'c` --> $DIR/issue-28109.rs:9:9 | -LL | 'c //~ ERROR use of undeclared label +LL | 'c | ^^ undeclared label `'c` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-28134.stderr b/src/test/ui/issues/issue-28134.stderr index 5b967b31c29e6..b9189480048d8 100644 --- a/src/test/ui/issues/issue-28134.stderr +++ b/src/test/ui/issues/issue-28134.stderr @@ -1,7 +1,7 @@ error: only functions may be used as tests --> $DIR/issue-28134.rs:3:1 | -LL | #![test] //~ ERROR only functions may be used as tests +LL | #![test] | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2823.stderr b/src/test/ui/issues/issue-2823.stderr index b51ff611dbd77..4c1dfb8501a91 100644 --- a/src/test/ui/issues/issue-2823.stderr +++ b/src/test/ui/issues/issue-2823.stderr @@ -4,7 +4,7 @@ error[E0599]: no method named `clone` found for type `C` in the current scope LL | struct C { | -------- method `clone` not found for this ... -LL | let _d = c.clone(); //~ ERROR no method named `clone` found +LL | let _d = c.clone(); | ^^^^^ | = help: items from traits can only be used if the trait is implemented and in scope diff --git a/src/test/ui/issues/issue-28279.rs b/src/test/ui/issues/issue-28279.rs index c770c50985959..fab91160a88be 100644 --- a/src/test/ui/issues/issue-28279.rs +++ b/src/test/ui/issues/issue-28279.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] use std::rc::Rc; -fn test1() -> Rc Fn(&'a usize) + 'static> { +fn test1() -> Rc Fn(&'a usize) + 'static> { if let Some(_) = Some(1) { loop{} } else { @@ -10,7 +10,7 @@ fn test1() -> Rc Fn(&'a usize) + 'static> { } } -fn test2() -> *mut (for<'a> Fn(&'a usize) + 'static) { +fn test2() -> *mut (dyn for<'a> Fn(&'a usize) + 'static) { if let Some(_) = Some(1) { loop{} } else { diff --git a/src/test/ui/issues/issue-28344.stderr b/src/test/ui/issues/issue-28344.stderr index b6f520c644b32..34ce2358a0a29 100644 --- a/src/test/ui/issues/issue-28344.stderr +++ b/src/test/ui/issues/issue-28344.stderr @@ -8,10 +8,10 @@ error[E0599]: no function or associated item named `bitor` found for type `dyn s --> $DIR/issue-28344.rs:4:25 | LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); - | --------^^^^^ - | | - | function or associated item not found in `dyn std::ops::BitXor<_>` - | help: did you mean: `bitxor` + | ^^^^^ + | | + | function or associated item not found in `dyn std::ops::BitXor<_>` + | help: there is a method with a similar name: `bitxor` error[E0191]: the value of the associated type `Output` (from the trait `std::ops::BitXor`) must be specified --> $DIR/issue-28344.rs:8:13 @@ -23,12 +23,12 @@ error[E0599]: no function or associated item named `bitor` found for type `dyn s --> $DIR/issue-28344.rs:8:21 | LL | let g = BitXor::bitor; - | --------^^^^^ - | | - | function or associated item not found in `dyn std::ops::BitXor<_>` - | help: did you mean: `bitxor` + | ^^^^^ + | | + | function or associated item not found in `dyn std::ops::BitXor<_>` + | help: there is a method with a similar name: `bitxor` error: aborting due to 4 previous errors -Some errors occurred: E0191, E0599. +Some errors have detailed explanations: E0191, E0599. For more information about an error, try `rustc --explain E0191`. diff --git a/src/test/ui/issues/issue-28388-1.stderr b/src/test/ui/issues/issue-28388-1.stderr index 6aabf65351200..7f5e47aa84fbe 100644 --- a/src/test/ui/issues/issue-28388-1.stderr +++ b/src/test/ui/issues/issue-28388-1.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `foo` --> $DIR/issue-28388-1.rs:3:5 | -LL | use foo::{}; //~ ERROR unresolved import `foo` +LL | use foo::{}; | ^^^^^^^ no `foo` in the root error: aborting due to previous error diff --git a/src/test/ui/issues/issue-28433.rs b/src/test/ui/issues/issue-28433.rs index a87ac63784fc6..8d05c32d5de91 100644 --- a/src/test/ui/issues/issue-28433.rs +++ b/src/test/ui/issues/issue-28433.rs @@ -1,13 +1,12 @@ -// compile-flags: -Z continue-parse-after-error - -enum bird { - pub duck, - //~^ ERROR: expected identifier, found keyword `pub` - //~| ERROR: expected - goose +enum Bird { + pub Duck, + //~^ ERROR unnecessary visibility qualifier + Goose, + pub(crate) Dove + //~^ ERROR unnecessary visibility qualifier } fn main() { - let y = bird::goose; + let y = Bird::Goose; } diff --git a/src/test/ui/issues/issue-28433.stderr b/src/test/ui/issues/issue-28433.stderr index d3cba3aae7101..851bc5dfbdd9e 100644 --- a/src/test/ui/issues/issue-28433.stderr +++ b/src/test/ui/issues/issue-28433.stderr @@ -1,18 +1,14 @@ -error: expected identifier, found keyword `pub` - --> $DIR/issue-28433.rs:4:5 +error: unnecessary visibility qualifier + --> $DIR/issue-28433.rs:2:5 | -LL | pub duck, - | ^^^ expected identifier, found keyword -help: you can escape reserved keywords to use them as identifiers - | -LL | r#pub duck, - | ^^^^^ +LL | pub Duck, + | ^^^ `pub` not permitted here -error: expected one of `(`, `,`, `=`, `{`, or `}`, found `duck` - --> $DIR/issue-28433.rs:4:9 +error: unnecessary visibility qualifier + --> $DIR/issue-28433.rs:5:5 | -LL | pub duck, - | ^^^^ expected one of `(`, `,`, `=`, `{`, or `}` here +LL | pub(crate) Dove + | ^^^^^^^^^^ `pub` not permitted here error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-28472.stderr b/src/test/ui/issues/issue-28472.stderr index 8288a1d9bb78f..92b598252bf7b 100644 --- a/src/test/ui/issues/issue-28472.stderr +++ b/src/test/ui/issues/issue-28472.stderr @@ -4,7 +4,7 @@ error[E0428]: the name `foo` is defined multiple times LL | fn foo(); | --------- previous definition of the value `foo` here LL | -LL | / pub //~ ERROR the name `foo` is defined multiple times +LL | / pub LL | | fn foo(); | |___________^ `foo` redefined here | @@ -16,7 +16,7 @@ error[E0428]: the name `foo` is defined multiple times LL | fn foo(); | --------- previous definition of the value `foo` here ... -LL | / pub //~ ERROR the name `foo` is defined multiple times +LL | / pub LL | | static mut foo: u32; | |______________________^ `foo` redefined here | diff --git a/src/test/ui/issues/issue-2848.stderr b/src/test/ui/issues/issue-2848.stderr index d9466405dd2aa..71ed7d70b5b81 100644 --- a/src/test/ui/issues/issue-2848.stderr +++ b/src/test/ui/issues/issue-2848.stderr @@ -1,7 +1,7 @@ error[E0408]: variable `beta` is not bound in all patterns --> $DIR/issue-2848.rs:14:7 | -LL | alpha | beta => {} //~ ERROR variable `beta` is not bound in all patterns +LL | alpha | beta => {} | ^^^^^ ---- variable not in all patterns | | | pattern doesn't bind `beta` diff --git a/src/test/ui/issues/issue-28576.rs b/src/test/ui/issues/issue-28576.rs index de665d5aa1680..972c839b64803 100644 --- a/src/test/ui/issues/issue-28576.rs +++ b/src/test/ui/issues/issue-28576.rs @@ -4,7 +4,7 @@ pub trait Foo { pub trait Bar: Foo { fn new(&self, b: & - Bar //~ ERROR the trait `Bar` cannot be made into an object + dyn Bar //~ ERROR the trait `Bar` cannot be made into an object ); } diff --git a/src/test/ui/issues/issue-28576.stderr b/src/test/ui/issues/issue-28576.stderr index b04715f23f49e..3249d76e69b57 100644 --- a/src/test/ui/issues/issue-28576.stderr +++ b/src/test/ui/issues/issue-28576.stderr @@ -1,7 +1,7 @@ error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/issue-28576.rs:7:12 | -LL | / Bar //~ ERROR the trait `Bar` cannot be made into an object +LL | / dyn Bar LL | | | |________________________^ the trait `Bar` cannot be made into an object | diff --git a/src/test/ui/issues/issue-28586.stderr b/src/test/ui/issues/issue-28586.stderr index eccb474c15eb6..d19c4af2df7c9 100644 --- a/src/test/ui/issues/issue-28586.stderr +++ b/src/test/ui/issues/issue-28586.stderr @@ -2,9 +2,7 @@ error[E0599]: no associated item named `BYTES` found for type `usize` in the cur --> $DIR/issue-28586.rs:4:26 | LL | impl Foo for [u8; usize::BYTES] {} - | -------^^^^^ - | | - | associated item not found in `usize` + | ^^^^^ associated item not found in `usize` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-28625.stderr b/src/test/ui/issues/issue-28625.stderr index 36cb47944f234..7ee0cd4867073 100644 --- a/src/test/ui/issues/issue-28625.stderr +++ b/src/test/ui/issues/issue-28625.stderr @@ -1,7 +1,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/issue-28625.rs:12:14 | -LL | unsafe { std::mem::transmute(a) } //~ ERROR cannot transmute between types of different sizes +LL | unsafe { std::mem::transmute(a) } | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `&ArrayPeano` (N bits) diff --git a/src/test/ui/issues/issue-28837.stderr b/src/test/ui/issues/issue-28837.stderr index 833493e5cda5e..ac2a9f2203d5a 100644 --- a/src/test/ui/issues/issue-28837.stderr +++ b/src/test/ui/issues/issue-28837.stderr @@ -1,120 +1,150 @@ error[E0369]: binary operation `+` cannot be applied to type `A` - --> $DIR/issue-28837.rs:6:5 + --> $DIR/issue-28837.rs:6:7 | -LL | a + a; //~ ERROR binary operation `+` cannot be applied to type `A` - | ^^^^^ +LL | a + a; + | - ^ - A + | | + | A | = note: an implementation of `std::ops::Add` might be missing for `A` error[E0369]: binary operation `-` cannot be applied to type `A` - --> $DIR/issue-28837.rs:8:5 + --> $DIR/issue-28837.rs:8:7 | -LL | a - a; //~ ERROR binary operation `-` cannot be applied to type `A` - | ^^^^^ +LL | a - a; + | - ^ - A + | | + | A | = note: an implementation of `std::ops::Sub` might be missing for `A` error[E0369]: binary operation `*` cannot be applied to type `A` - --> $DIR/issue-28837.rs:10:5 + --> $DIR/issue-28837.rs:10:7 | -LL | a * a; //~ ERROR binary operation `*` cannot be applied to type `A` - | ^^^^^ +LL | a * a; + | - ^ - A + | | + | A | = note: an implementation of `std::ops::Mul` might be missing for `A` error[E0369]: binary operation `/` cannot be applied to type `A` - --> $DIR/issue-28837.rs:12:5 + --> $DIR/issue-28837.rs:12:7 | -LL | a / a; //~ ERROR binary operation `/` cannot be applied to type `A` - | ^^^^^ +LL | a / a; + | - ^ - A + | | + | A | = note: an implementation of `std::ops::Div` might be missing for `A` error[E0369]: binary operation `%` cannot be applied to type `A` - --> $DIR/issue-28837.rs:14:5 + --> $DIR/issue-28837.rs:14:7 | -LL | a % a; //~ ERROR binary operation `%` cannot be applied to type `A` - | ^^^^^ +LL | a % a; + | - ^ - A + | | + | A | = note: an implementation of `std::ops::Rem` might be missing for `A` error[E0369]: binary operation `&` cannot be applied to type `A` - --> $DIR/issue-28837.rs:16:5 + --> $DIR/issue-28837.rs:16:7 | -LL | a & a; //~ ERROR binary operation `&` cannot be applied to type `A` - | ^^^^^ +LL | a & a; + | - ^ - A + | | + | A | = note: an implementation of `std::ops::BitAnd` might be missing for `A` error[E0369]: binary operation `|` cannot be applied to type `A` - --> $DIR/issue-28837.rs:18:5 + --> $DIR/issue-28837.rs:18:7 | -LL | a | a; //~ ERROR binary operation `|` cannot be applied to type `A` - | ^^^^^ +LL | a | a; + | - ^ - A + | | + | A | = note: an implementation of `std::ops::BitOr` might be missing for `A` error[E0369]: binary operation `<<` cannot be applied to type `A` - --> $DIR/issue-28837.rs:20:5 + --> $DIR/issue-28837.rs:20:7 | -LL | a << a; //~ ERROR binary operation `<<` cannot be applied to type `A` - | ^^^^^^ +LL | a << a; + | - ^^ - A + | | + | A | = note: an implementation of `std::ops::Shl` might be missing for `A` error[E0369]: binary operation `>>` cannot be applied to type `A` - --> $DIR/issue-28837.rs:22:5 + --> $DIR/issue-28837.rs:22:7 | -LL | a >> a; //~ ERROR binary operation `>>` cannot be applied to type `A` - | ^^^^^^ +LL | a >> a; + | - ^^ - A + | | + | A | = note: an implementation of `std::ops::Shr` might be missing for `A` error[E0369]: binary operation `==` cannot be applied to type `A` - --> $DIR/issue-28837.rs:24:5 + --> $DIR/issue-28837.rs:24:7 | -LL | a == a; //~ ERROR binary operation `==` cannot be applied to type `A` - | ^^^^^^ +LL | a == a; + | - ^^ - A + | | + | A | = note: an implementation of `std::cmp::PartialEq` might be missing for `A` error[E0369]: binary operation `!=` cannot be applied to type `A` - --> $DIR/issue-28837.rs:26:5 + --> $DIR/issue-28837.rs:26:7 | -LL | a != a; //~ ERROR binary operation `!=` cannot be applied to type `A` - | ^^^^^^ +LL | a != a; + | - ^^ - A + | | + | A | = note: an implementation of `std::cmp::PartialEq` might be missing for `A` error[E0369]: binary operation `<` cannot be applied to type `A` - --> $DIR/issue-28837.rs:28:5 + --> $DIR/issue-28837.rs:28:7 | -LL | a < a; //~ ERROR binary operation `<` cannot be applied to type `A` - | ^^^^^ +LL | a < a; + | - ^ - A + | | + | A | = note: an implementation of `std::cmp::PartialOrd` might be missing for `A` error[E0369]: binary operation `<=` cannot be applied to type `A` - --> $DIR/issue-28837.rs:30:5 + --> $DIR/issue-28837.rs:30:7 | -LL | a <= a; //~ ERROR binary operation `<=` cannot be applied to type `A` - | ^^^^^^ +LL | a <= a; + | - ^^ - A + | | + | A | = note: an implementation of `std::cmp::PartialOrd` might be missing for `A` error[E0369]: binary operation `>` cannot be applied to type `A` - --> $DIR/issue-28837.rs:32:5 + --> $DIR/issue-28837.rs:32:7 | -LL | a > a; //~ ERROR binary operation `>` cannot be applied to type `A` - | ^^^^^ +LL | a > a; + | - ^ - A + | | + | A | = note: an implementation of `std::cmp::PartialOrd` might be missing for `A` error[E0369]: binary operation `>=` cannot be applied to type `A` - --> $DIR/issue-28837.rs:34:5 + --> $DIR/issue-28837.rs:34:7 | -LL | a >= a; //~ ERROR binary operation `>=` cannot be applied to type `A` - | ^^^^^^ +LL | a >= a; + | - ^^ - A + | | + | A | = note: an implementation of `std::cmp::PartialOrd` might be missing for `A` diff --git a/src/test/ui/issues/issue-28848.nll.stderr b/src/test/ui/issues/issue-28848.nll.stderr new file mode 100644 index 0000000000000..5cf9856e4dc7e --- /dev/null +++ b/src/test/ui/issues/issue-28848.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/issue-28848.rs:10:5 + | +LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | Foo::<'a, 'b>::xmute(u) + | ^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-28848.stderr b/src/test/ui/issues/issue-28848.stderr index d9cdccac9fca3..5f0f202c0b27b 100644 --- a/src/test/ui/issues/issue-28848.stderr +++ b/src/test/ui/issues/issue-28848.stderr @@ -1,7 +1,7 @@ error[E0478]: lifetime bound not satisfied --> $DIR/issue-28848.rs:10:5 | -LL | Foo::<'a, 'b>::xmute(u) //~ ERROR lifetime bound not satisfied +LL | Foo::<'a, 'b>::xmute(u) | ^^^^^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime 'b as defined on the function body at 9:16 diff --git a/src/test/ui/issues/issue-28971.rs b/src/test/ui/issues/issue-28971.rs index 3f0d2fafb0478..6493565d21647 100644 --- a/src/test/ui/issues/issue-28971.rs +++ b/src/test/ui/issues/issue-28971.rs @@ -1,5 +1,3 @@ -// This should not cause an ICE - enum Foo { Bar(u8) } @@ -7,7 +5,7 @@ fn main(){ foo(|| { match Foo::Bar(1) { Foo::Baz(..) => (), - //~^ ERROR no variant named `Baz` found for type `Foo` + //~^ ERROR no variant or associated item named `Baz` found for type `Foo` _ => (), } }); diff --git a/src/test/ui/issues/issue-28971.stderr b/src/test/ui/issues/issue-28971.stderr index 77d0b53ad216b..7411896443dfe 100644 --- a/src/test/ui/issues/issue-28971.stderr +++ b/src/test/ui/issues/issue-28971.stderr @@ -1,14 +1,14 @@ -error[E0599]: no variant named `Baz` found for type `Foo` in the current scope - --> $DIR/issue-28971.rs:9:18 +error[E0599]: no variant or associated item named `Baz` found for type `Foo` in the current scope + --> $DIR/issue-28971.rs:7:18 | LL | enum Foo { - | -------- variant `Baz` not found here + | -------- variant or associated item `Baz` not found here ... LL | Foo::Baz(..) => (), - | -----^^^---- - | | | - | | help: did you mean: `Bar` - | variant not found in `Foo` + | ^^^ + | | + | variant or associated item not found in `Foo` + | help: there is a variant with a similar name: `Bar` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-28992-empty.stderr b/src/test/ui/issues/issue-28992-empty.stderr index 1eb1c67d106cf..9f9f574aa5dd4 100644 --- a/src/test/ui/issues/issue-28992-empty.stderr +++ b/src/test/ui/issues/issue-28992-empty.stderr @@ -1,7 +1,7 @@ error[E0532]: expected tuple struct/variant, found constant `C1` --> $DIR/issue-28992-empty.rs:13:12 | -LL | if let C1(..) = 0 {} //~ ERROR expected tuple struct/variant, found constant `C1` +LL | if let C1(..) = 0 {} | ^^ not a tuple struct/variant error[E0164]: expected tuple struct/variant, found associated constant `::C2` @@ -12,5 +12,5 @@ LL | if let S::C2(..) = 0 {} error: aborting due to 2 previous errors -Some errors occurred: E0164, E0532. +Some errors have detailed explanations: E0164, E0532. For more information about an error, try `rustc --explain E0164`. diff --git a/src/test/ui/issues/issue-2904.rs b/src/test/ui/issues/issue-2904.rs index 7755b7ecee307..42f71a1b09615 100644 --- a/src/test/ui/issues/issue-2904.rs +++ b/src/test/ui/issues/issue-2904.rs @@ -55,7 +55,7 @@ fn square_from_char(c: char) -> square { fn read_board_grid(mut input: rdr) -> Vec> { - let mut input: &mut Read = &mut input; + let mut input: &mut dyn Read = &mut input; let mut grid = Vec::new(); let mut line = [0; 10]; input.read(&mut line); diff --git a/src/test/ui/issues/issue-29147.stderr b/src/test/ui/issues/issue-29147.stderr index c6d850925ec64..3b42186b25138 100644 --- a/src/test/ui/issues/issue-29147.stderr +++ b/src/test/ui/issues/issue-29147.stderr @@ -1,7 +1,7 @@ error[E0283]: type annotations required: cannot resolve `S5<_>: Foo` --> $DIR/issue-29147.rs:21:13 | -LL | let _ = >::xxx; //~ ERROR cannot resolve `S5<_>: Foo` +LL | let _ = >::xxx; | ^^^^^^^^^^^^ | note: required by `Foo::xxx` diff --git a/src/test/ui/issues/issue-29161.stderr b/src/test/ui/issues/issue-29161.stderr index e0215157b3690..d30fd28a4a351 100644 --- a/src/test/ui/issues/issue-29161.stderr +++ b/src/test/ui/issues/issue-29161.stderr @@ -1,7 +1,7 @@ error[E0449]: unnecessary visibility qualifier --> $DIR/issue-29161.rs:5:9 | -LL | pub fn default() -> A { //~ ERROR unnecessary visibility qualifier +LL | pub fn default() -> A { | ^^^ `pub` not permitted here because it's implied error[E0603]: struct `A` is private @@ -12,5 +12,5 @@ LL | a::A::default(); error: aborting due to 2 previous errors -Some errors occurred: E0449, E0603. +Some errors have detailed explanations: E0449, E0603. For more information about an error, try `rustc --explain E0449`. diff --git a/src/test/ui/issues/issue-29181.stderr b/src/test/ui/issues/issue-29181.stderr index b277753608a16..092014281546f 100644 --- a/src/test/ui/issues/issue-29181.stderr +++ b/src/test/ui/issues/issue-29181.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `homura` found for type `{integer}` in the current scope --> $DIR/issue-29181.rs:6:7 | -LL | 0.homura(); //~ ERROR no method named `homura` found +LL | 0.homura(); | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-29184.stderr b/src/test/ui/issues/issue-29184.stderr index 6c1eeb9c0dc81..87d3632ee42e2 100644 --- a/src/test/ui/issues/issue-29184.stderr +++ b/src/test/ui/issues/issue-29184.stderr @@ -1,7 +1,7 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented --> $DIR/issue-29184.rs:2:12 | -LL | let x: typeof(92) = 92; //~ ERROR `typeof` is a reserved keyword +LL | let x: typeof(92) = 92; | ^^^^^^^^^^ reserved keyword error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2937.stderr b/src/test/ui/issues/issue-2937.stderr index e63ee42d99c0a..428634828f9be 100644 --- a/src/test/ui/issues/issue-2937.stderr +++ b/src/test/ui/issues/issue-2937.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `m::f` --> $DIR/issue-2937.rs:1:5 | -LL | use m::f as x; //~ ERROR unresolved import `m::f` [E0432] +LL | use m::f as x; | ^^^^^^^^^ no `f` in `m` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-29857.rs b/src/test/ui/issues/issue-29857.rs index 5aff968bb6a89..6f4c5f45d0d9c 100644 --- a/src/test/ui/issues/issue-29857.rs +++ b/src/test/ui/issues/issue-29857.rs @@ -1,5 +1,4 @@ -// compile-pass -// skip-codegen +// check-pass use std::marker::PhantomData; @@ -17,5 +16,4 @@ pub trait Bar { impl> Foo<*mut T> for W {} - fn main() {} diff --git a/src/test/ui/issues/issue-2995.stderr b/src/test/ui/issues/issue-2995.stderr index 68cb283e453d5..c316780d5f6a5 100644 --- a/src/test/ui/issues/issue-2995.stderr +++ b/src/test/ui/issues/issue-2995.stderr @@ -1,7 +1,7 @@ error[E0605]: non-primitive cast: `*const isize` as `&isize` --> $DIR/issue-2995.rs:2:22 | -LL | let _q: &isize = p as &isize; //~ ERROR non-primitive cast +LL | let _q: &isize = p as &isize; | ^^^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait diff --git a/src/test/ui/issues/issue-30007.stderr b/src/test/ui/issues/issue-30007.stderr index fb069e8ff9893..87e770e1543d5 100644 --- a/src/test/ui/issues/issue-30007.stderr +++ b/src/test/ui/issues/issue-30007.stderr @@ -1,7 +1,7 @@ error: macro expansion ignores token `;` and any following --> $DIR/issue-30007.rs:2:20 | -LL | () => ( String ; ); //~ ERROR macro expansion ignores token `;` +LL | () => ( String ; ); | ^ ... LL | let i: Vec; diff --git a/src/test/ui/issues/issue-30079.stderr b/src/test/ui/issues/issue-30079.stderr index b62482add304a..57ca572154484 100644 --- a/src/test/ui/issues/issue-30079.stderr +++ b/src/test/ui/issues/issue-30079.stderr @@ -1,7 +1,7 @@ warning: private type `m1::Priv` in public interface (error E0446) --> $DIR/issue-30079.rs:6:9 | -LL | pub fn f(_: Priv) {} //~ WARN private type `m1::Priv` in public interface +LL | pub fn f(_: Priv) {} | ^^^^^^^^^^^^^^^^^^^^ | = note: #[warn(private_in_public)] on by default @@ -14,7 +14,7 @@ error[E0446]: private type `m2::Priv` in public interface LL | struct Priv; | - `m2::Priv` declared as private LL | impl ::std::ops::Deref for ::SemiPriv { -LL | type Target = Priv; //~ ERROR private type `m2::Priv` in public interface +LL | type Target = Priv; | ^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `m3::Priv` in public interface @@ -23,7 +23,7 @@ error[E0446]: private type `m3::Priv` in public interface LL | struct Priv; | - `m3::Priv` declared as private LL | impl ::SemiPrivTrait for () { -LL | type Assoc = Priv; //~ ERROR private type `m3::Priv` in public interface +LL | type Assoc = Priv; | ^^^^^^^^^^^^^^^^^^ can't leak private type error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-30123.stderr b/src/test/ui/issues/issue-30123.stderr index 555bdb1236fe6..32bbd4d03d6d7 100644 --- a/src/test/ui/issues/issue-30123.stderr +++ b/src/test/ui/issues/issue-30123.stderr @@ -2,9 +2,7 @@ error[E0599]: no function or associated item named `new_undirected` found for ty --> $DIR/issue-30123.rs:7:33 | LL | let ug = Graph::::new_undirected(); - | -------------------^^^^^^^^^^^^^^ - | | - | function or associated item not found in `issue_30123_aux::Graph` + | ^^^^^^^^^^^^^^ function or associated item not found in `issue_30123_aux::Graph` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3021-b.stderr b/src/test/ui/issues/issue-3021-b.stderr index 375da43c1973e..72289c5f9c344 100644 --- a/src/test/ui/issues/issue-3021-b.stderr +++ b/src/test/ui/issues/issue-3021-b.stderr @@ -1,7 +1,7 @@ error[E0434]: can't capture dynamic environment in a fn item --> $DIR/issue-3021-b.rs:9:22 | -LL | self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR can't capture dynamic environment +LL | self.v0 = k0 ^ 0x736f6d6570736575; | ^^ | = help: use the `|| { ... }` closure form instead diff --git a/src/test/ui/issues/issue-3021-c.stderr b/src/test/ui/issues/issue-3021-c.stderr index 5eadf7837c7d0..8764ac8a8563c 100644 --- a/src/test/ui/issues/issue-3021-c.stderr +++ b/src/test/ui/issues/issue-3021-c.stderr @@ -2,9 +2,9 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-3021-c.rs:4:24 | LL | fn siphash() { - | - type variable from outer function + | - type parameter from outer function ... -LL | fn g(&self, x: T) -> T; //~ ERROR can't use generic parameters from outer function +LL | fn g(&self, x: T) -> T; | - ^ use of generic parameter from outer function | | | help: try using a local generic parameter instead: `g` @@ -13,9 +13,9 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-3021-c.rs:4:30 | LL | fn siphash() { - | - type variable from outer function + | - type parameter from outer function ... -LL | fn g(&self, x: T) -> T; //~ ERROR can't use generic parameters from outer function +LL | fn g(&self, x: T) -> T; | - ^ use of generic parameter from outer function | | | help: try using a local generic parameter instead: `g` diff --git a/src/test/ui/issues/issue-3021-d.stderr b/src/test/ui/issues/issue-3021-d.stderr index ffefab19725fb..39e6e8c43e944 100644 --- a/src/test/ui/issues/issue-3021-d.stderr +++ b/src/test/ui/issues/issue-3021-d.stderr @@ -1,7 +1,7 @@ error[E0434]: can't capture dynamic environment in a fn item --> $DIR/issue-3021-d.rs:21:23 | -LL | self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR can't capture dynamic environment +LL | self.v0 = k0 ^ 0x736f6d6570736575; | ^^ | = help: use the `|| { ... }` closure form instead @@ -9,7 +9,7 @@ LL | self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR can't capture dyna error[E0434]: can't capture dynamic environment in a fn item --> $DIR/issue-3021-d.rs:22:23 | -LL | self.v1 = k1 ^ 0x646f72616e646f6d; //~ ERROR can't capture dynamic environment +LL | self.v1 = k1 ^ 0x646f72616e646f6d; | ^^ | = help: use the `|| { ... }` closure form instead diff --git a/src/test/ui/issues/issue-3021.stderr b/src/test/ui/issues/issue-3021.stderr index 38c5bd2b94af7..d5b015eec3509 100644 --- a/src/test/ui/issues/issue-3021.stderr +++ b/src/test/ui/issues/issue-3021.stderr @@ -1,7 +1,7 @@ error[E0434]: can't capture dynamic environment in a fn item --> $DIR/issue-3021.rs:12:22 | -LL | self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR can't capture dynamic environment +LL | self.v0 = k0 ^ 0x736f6d6570736575; | ^^ | = help: use the `|| { ... }` closure form instead diff --git a/src/test/ui/issues/issue-30236.rs b/src/test/ui/issues/issue-30236.rs index 02f899be09ca1..9c2d855076d79 100644 --- a/src/test/ui/issues/issue-30236.rs +++ b/src/test/ui/issues/issue-30236.rs @@ -5,4 +5,3 @@ type Foo< fn main() { } - diff --git a/src/test/ui/issues/issue-30236.stderr b/src/test/ui/issues/issue-30236.stderr index e60babd9559e2..64cbd58d69547 100644 --- a/src/test/ui/issues/issue-30236.stderr +++ b/src/test/ui/issues/issue-30236.stderr @@ -1,7 +1,7 @@ error[E0091]: type parameter `Unused` is unused --> $DIR/issue-30236.rs:2:5 | -LL | Unused //~ ERROR type parameter `Unused` is unused +LL | Unused | ^^^^^^ unused type parameter error: aborting due to previous error diff --git a/src/test/ui/issues/issue-30240-b.rs b/src/test/ui/issues/issue-30240-b.rs index 2df06842e1818..01a6e7d8cb9a8 100644 --- a/src/test/ui/issues/issue-30240-b.rs +++ b/src/test/ui/issues/issue-30240-b.rs @@ -13,4 +13,3 @@ fn main() { _ => {}, } } - diff --git a/src/test/ui/issues/issue-30240-b.stderr b/src/test/ui/issues/issue-30240-b.stderr index 5613a18f404a0..e0dd4794db59a 100644 --- a/src/test/ui/issues/issue-30240-b.stderr +++ b/src/test/ui/issues/issue-30240-b.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/issue-30240-b.rs:12:9 | -LL | "hello" => {} //~ ERROR unreachable pattern +LL | "hello" => {} | ^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/issues/issue-30240.stderr b/src/test/ui/issues/issue-30240.stderr index 973c59c58526b..8b683b4af65cd 100644 --- a/src/test/ui/issues/issue-30240.stderr +++ b/src/test/ui/issues/issue-30240.stderr @@ -1,14 +1,18 @@ error[E0004]: non-exhaustive patterns: `&_` not covered --> $DIR/issue-30240.rs:2:11 | -LL | match "world" { //~ ERROR non-exhaustive patterns: `&_` +LL | match "world" { | ^^^^^^^ pattern `&_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `&_` not covered --> $DIR/issue-30240.rs:6:11 | -LL | match "world" { //~ ERROR non-exhaustive patterns: `&_` +LL | match "world" { | ^^^^^^^ pattern `&_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-30302.stderr b/src/test/ui/issues/issue-30302.stderr index 193a8c4916c66..d762d6f2b3d5e 100644 --- a/src/test/ui/issues/issue-30302.stderr +++ b/src/test/ui/issues/issue-30302.stderr @@ -9,7 +9,7 @@ error: unreachable pattern | LL | Nil => true, | --- matches any value -LL | //~^ WARN pattern binding `Nil` is named the same as one of the variants of the type `Stack` +LL | LL | _ => false | ^ unreachable pattern | diff --git a/src/test/ui/issues/issue-3038.stderr b/src/test/ui/issues/issue-3038.stderr index 8638c19652407..210da2ceff9bb 100644 --- a/src/test/ui/issues/issue-3038.stderr +++ b/src/test/ui/issues/issue-3038.stderr @@ -13,7 +13,7 @@ LL | H::I(J::L(x, _), K::M(_, x)) error[E0416]: identifier `x` is bound more than once in the same pattern --> $DIR/issue-3038.rs:23:13 | -LL | (x, x) => { x } //~ ERROR identifier `x` is bound more than once in the same pattern +LL | (x, x) => { x } | ^ used in a pattern more than once error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-30438-a.nll.stderr b/src/test/ui/issues/issue-30438-a.nll.stderr deleted file mode 100644 index 53845af82fb11..0000000000000 --- a/src/test/ui/issues/issue-30438-a.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0515]: cannot return reference to temporary value - --> $DIR/issue-30438-a.rs:12:16 - | -LL | return &Test { s: &self.s}; - | ^------------------ - | || - | |temporary value created here - | returns a reference to data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-30438-a.rs b/src/test/ui/issues/issue-30438-a.rs index 8900821090b1c..0d4eb796ad9b0 100644 --- a/src/test/ui/issues/issue-30438-a.rs +++ b/src/test/ui/issues/issue-30438-a.rs @@ -10,7 +10,7 @@ impl <'a> Index for Test<'a> { type Output = Test<'a>; fn index(&self, _: usize) -> &Self::Output { return &Test { s: &self.s}; - //~^ ERROR: borrowed value does not live long enough + //~^ ERROR: cannot return reference to temporary value } } diff --git a/src/test/ui/issues/issue-30438-a.stderr b/src/test/ui/issues/issue-30438-a.stderr index 94aca7f031999..53845af82fb11 100644 --- a/src/test/ui/issues/issue-30438-a.stderr +++ b/src/test/ui/issues/issue-30438-a.stderr @@ -1,21 +1,12 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/issue-30438-a.rs:12:17 +error[E0515]: cannot return reference to temporary value + --> $DIR/issue-30438-a.rs:12:16 | LL | return &Test { s: &self.s}; - | ^^^^^^^^^^^^^^^^^^- temporary value only lives until here - | | - | temporary value does not live long enough - | -note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 11:5... - --> $DIR/issue-30438-a.rs:11:5 - | -LL | / fn index(&self, _: usize) -> &Self::Output { -LL | | return &Test { s: &self.s}; -LL | | //~^ ERROR: borrowed value does not live long enough -LL | | } - | |_____^ - = note: consider using a `let` binding to increase its lifetime + | ^------------------ + | || + | |temporary value created here + | returns a reference to data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-30438-b.nll.stderr b/src/test/ui/issues/issue-30438-b.nll.stderr deleted file mode 100644 index fd6bd25b1da16..0000000000000 --- a/src/test/ui/issues/issue-30438-b.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0515]: cannot return reference to temporary value - --> $DIR/issue-30438-b.rs:13:9 - | -LL | &Test { s: &self.s} - | ^------------------ - | || - | |temporary value created here - | returns a reference to data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-30438-b.rs b/src/test/ui/issues/issue-30438-b.rs index b84211bec67d1..79510cdb66366 100644 --- a/src/test/ui/issues/issue-30438-b.rs +++ b/src/test/ui/issues/issue-30438-b.rs @@ -11,7 +11,7 @@ impl <'a> Index for Test<'a> { type Output = Test<'a>; fn index(&self, _: usize) -> &Self::Output { &Test { s: &self.s} - //~^ ERROR: borrowed value does not live long enough + //~^ ERROR: cannot return reference to temporary value } } diff --git a/src/test/ui/issues/issue-30438-b.stderr b/src/test/ui/issues/issue-30438-b.stderr index b99801dad81d5..fd6bd25b1da16 100644 --- a/src/test/ui/issues/issue-30438-b.stderr +++ b/src/test/ui/issues/issue-30438-b.stderr @@ -1,21 +1,12 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/issue-30438-b.rs:13:10 +error[E0515]: cannot return reference to temporary value + --> $DIR/issue-30438-b.rs:13:9 | LL | &Test { s: &self.s} - | ^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -LL | //~^ ERROR: borrowed value does not live long enough -LL | } - | - temporary value only lives until here - | -note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 12:5... - --> $DIR/issue-30438-b.rs:12:5 - | -LL | / fn index(&self, _: usize) -> &Self::Output { -LL | | &Test { s: &self.s} -LL | | //~^ ERROR: borrowed value does not live long enough -LL | | } - | |_____^ + | ^------------------ + | || + | |temporary value created here + | returns a reference to data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-30438-c.nll.stderr b/src/test/ui/issues/issue-30438-c.nll.stderr deleted file mode 100644 index 7c001088097ab..0000000000000 --- a/src/test/ui/issues/issue-30438-c.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0515]: cannot return reference to local variable `x` - --> $DIR/issue-30438-c.rs:9:5 - | -LL | &x - | ^^ returns a reference to data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-30438-c.rs b/src/test/ui/issues/issue-30438-c.rs index 75caf0a75dfb6..813c1d3e2cccd 100644 --- a/src/test/ui/issues/issue-30438-c.rs +++ b/src/test/ui/issues/issue-30438-c.rs @@ -7,7 +7,7 @@ struct Test<'a> { s: &'a str } fn silly<'y, 'z>(_s: &'y Test<'z>) -> &'y as Trait>::Out where 'z: 'static { let x = Test { s: "this cannot last" }; &x - //~^ ERROR: `x` does not live long enough + //~^ ERROR: cannot return reference to local variable `x` } impl<'b> Trait for Test<'b> { type Out = Test<'b>; } diff --git a/src/test/ui/issues/issue-30438-c.stderr b/src/test/ui/issues/issue-30438-c.stderr index 71c2ed9dfc935..7c001088097ab 100644 --- a/src/test/ui/issues/issue-30438-c.stderr +++ b/src/test/ui/issues/issue-30438-c.stderr @@ -1,18 +1,9 @@ -error[E0597]: `x` does not live long enough - --> $DIR/issue-30438-c.rs:9:6 +error[E0515]: cannot return reference to local variable `x` + --> $DIR/issue-30438-c.rs:9:5 | LL | &x - | ^ borrowed value does not live long enough -LL | //~^ ERROR: `x` does not live long enough -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'y as defined on the function body at 7:10... - --> $DIR/issue-30438-c.rs:7:10 - | -LL | fn silly<'y, 'z>(_s: &'y Test<'z>) -> &'y as Trait>::Out where 'z: 'static { - | ^^ + | ^^ returns a reference to data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-30535.stderr b/src/test/ui/issues/issue-30535.stderr index b93ed8d9c2aa5..5faf0374210d8 100644 --- a/src/test/ui/issues/issue-30535.stderr +++ b/src/test/ui/issues/issue-30535.stderr @@ -1,7 +1,7 @@ error[E0573]: expected type, found variant `foo::Foo::FooV` --> $DIR/issue-30535.rs:6:8 | -LL | _: foo::Foo::FooV //~ ERROR expected type, found variant `foo::Foo::FooV` +LL | _: foo::Foo::FooV | ^^^^^^^^^^^^^^ | | | not a type @@ -9,4 +9,3 @@ LL | _: foo::Foo::FooV //~ ERROR expected type, found variant `foo::Foo::Foo error: aborting due to previous error -For more information about this error, try `rustc --explain E0573`. diff --git a/src/test/ui/issues/issue-30560.rs b/src/test/ui/issues/issue-30560.rs index c848a1c51ca37..d8d4ca608f1c0 100644 --- a/src/test/ui/issues/issue-30560.rs +++ b/src/test/ui/issues/issue-30560.rs @@ -1,10 +1,7 @@ type Alias = (); -use Alias::*; -//~^ ERROR unresolved import `Alias` [E0432] -//~| not a module `Alias` -use std::io::Result::*; -//~^ ERROR unresolved import `std::io::Result` [E0432] -//~| not a module `Result` +use Alias::*; //~ ERROR unresolved import `Alias` [E0432] + +use std::io::Result::*; //~ ERROR unresolved import `std::io::Result` [E0432] trait T {} use T::*; //~ ERROR items in traits are not importable diff --git a/src/test/ui/issues/issue-30560.stderr b/src/test/ui/issues/issue-30560.stderr index 27fa9e16bf24f..b74134aaccc0d 100644 --- a/src/test/ui/issues/issue-30560.stderr +++ b/src/test/ui/issues/issue-30560.stderr @@ -1,20 +1,20 @@ error: items in traits are not importable. - --> $DIR/issue-30560.rs:10:5 + --> $DIR/issue-30560.rs:7:5 | -LL | use T::*; //~ ERROR items in traits are not importable +LL | use T::*; | ^^^^ error[E0432]: unresolved import `Alias` --> $DIR/issue-30560.rs:2:5 | LL | use Alias::*; - | ^^^^^ not a module `Alias` + | ^^^^^ `Alias` is a type alias, not a module error[E0432]: unresolved import `std::io::Result` - --> $DIR/issue-30560.rs:5:14 + --> $DIR/issue-30560.rs:4:14 | LL | use std::io::Result::*; - | ^^^^^^ not a module `Result` + | ^^^^^^ `Result` is a type alias, not a module error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-30589.stderr b/src/test/ui/issues/issue-30589.stderr index 17ba4051fb4e7..4b88547a1aff4 100644 --- a/src/test/ui/issues/issue-30589.stderr +++ b/src/test/ui/issues/issue-30589.stderr @@ -1,7 +1,7 @@ error[E0412]: cannot find type `DecoderError` in this scope --> $DIR/issue-30589.rs:3:23 | -LL | impl fmt::Display for DecoderError { //~ ERROR cannot find type `DecoderError` in this scope +LL | impl fmt::Display for DecoderError { | ^^^^^^^^^^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3080.stderr b/src/test/ui/issues/issue-3080.stderr index 44f16c708e0fa..138d6df679fc4 100644 --- a/src/test/ui/issues/issue-3080.stderr +++ b/src/test/ui/issues/issue-3080.stderr @@ -1,7 +1,7 @@ error[E0133]: call to unsafe function is unsafe and requires unsafe function or block --> $DIR/issue-3080.rs:7:5 | -LL | X(()).with(); //~ ERROR requires unsafe function or block +LL | X(()).with(); | ^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior diff --git a/src/test/ui/issues/issue-3096-1.stderr b/src/test/ui/issues/issue-3096-1.stderr index 7ced0d36805dd..c5a7fa7e0eb83 100644 --- a/src/test/ui/issues/issue-3096-1.stderr +++ b/src/test/ui/issues/issue-3096-1.stderr @@ -1,14 +1,10 @@ error[E0004]: non-exhaustive patterns: type `()` is non-empty --> $DIR/issue-3096-1.rs:2:11 | -LL | match () { } //~ ERROR non-exhaustive +LL | match () { } | ^^ | -help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - --> $DIR/issue-3096-1.rs:2:11 - | -LL | match () { } //~ ERROR non-exhaustive - | ^^ + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3096-2.stderr b/src/test/ui/issues/issue-3096-2.stderr index df87679448956..6f2e0e760d7f6 100644 --- a/src/test/ui/issues/issue-3096-2.stderr +++ b/src/test/ui/issues/issue-3096-2.stderr @@ -1,14 +1,10 @@ error[E0004]: non-exhaustive patterns: type `*const Bottom` is non-empty --> $DIR/issue-3096-2.rs:5:11 | -LL | match x { } //~ ERROR non-exhaustive patterns +LL | match x { } | ^ | -help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - --> $DIR/issue-3096-2.rs:5:11 - | -LL | match x { } //~ ERROR non-exhaustive patterns - | ^ + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3099-a.stderr b/src/test/ui/issues/issue-3099-a.stderr index d3da944cb5331..d6e0a799921f1 100644 --- a/src/test/ui/issues/issue-3099-a.stderr +++ b/src/test/ui/issues/issue-3099-a.stderr @@ -4,7 +4,7 @@ error[E0428]: the name `A` is defined multiple times LL | enum A { B, C } | ------ previous definition of the type `A` here LL | -LL | enum A { D, E } //~ ERROR the name `A` is defined multiple times +LL | enum A { D, E } | ^^^^^^ `A` redefined here | = note: `A` must be defined only once in the type namespace of this module diff --git a/src/test/ui/issues/issue-3099-b.stderr b/src/test/ui/issues/issue-3099-b.stderr index cc49325805e36..3ba8b189da670 100644 --- a/src/test/ui/issues/issue-3099-b.stderr +++ b/src/test/ui/issues/issue-3099-b.stderr @@ -4,7 +4,7 @@ error[E0428]: the name `a` is defined multiple times LL | pub mod a {} | --------- previous definition of the module `a` here LL | -LL | pub mod a {} //~ ERROR the name `a` is defined multiple times +LL | pub mod a {} | ^^^^^^^^^ `a` redefined here | = note: `a` must be defined only once in the type namespace of this module diff --git a/src/test/ui/issues/issue-3099.stderr b/src/test/ui/issues/issue-3099.stderr index a650d3caa6407..32ee2e1d20736 100644 --- a/src/test/ui/issues/issue-3099.stderr +++ b/src/test/ui/issues/issue-3099.stderr @@ -4,7 +4,7 @@ error[E0428]: the name `a` is defined multiple times LL | fn a(x: String) -> String { | ------------------------- previous definition of the value `a` here ... -LL | fn a(x: String, y: String) -> String { //~ ERROR the name `a` is defined multiple times +LL | fn a(x: String, y: String) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `a` redefined here | = note: `a` must be defined only once in the value namespace of this module diff --git a/src/test/ui/issues/issue-31076.stderr b/src/test/ui/issues/issue-31076.stderr index 3a13f02d9f45f..60a3be1c36b75 100644 --- a/src/test/ui/issues/issue-31076.stderr +++ b/src/test/ui/issues/issue-31076.stderr @@ -1,16 +1,20 @@ error[E0369]: binary operation `+` cannot be applied to type `{integer}` - --> $DIR/issue-31076.rs:13:13 + --> $DIR/issue-31076.rs:13:15 | LL | let x = 5 + 6; - | ^^^^^ + | - ^ - {integer} + | | + | {integer} | = note: an implementation of `std::ops::Add` might be missing for `{integer}` error[E0369]: binary operation `+` cannot be applied to type `i32` - --> $DIR/issue-31076.rs:15:13 + --> $DIR/issue-31076.rs:15:18 | LL | let y = 5i32 + 6i32; - | ^^^^^^^^^^^ + | ---- ^ ---- i32 + | | + | i32 | = note: an implementation of `std::ops::Add` might be missing for `i32` diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index 76f245a22cf89..3ca8338882681 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -10,7 +10,7 @@ LL | .cloned() error[E0599]: no method named `collect` found for type `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>` in the current scope --> $DIR/issue-31173.rs:14:10 | -LL | .collect(); //~ ERROR no method named `collect` +LL | .collect(); | ^^^^^^^ | = note: the method `collect` exists but the following trait bounds were not satisfied: @@ -19,5 +19,5 @@ LL | .collect(); //~ ERROR no method named `collect` error: aborting due to 2 previous errors -Some errors occurred: E0271, E0599. +Some errors have detailed explanations: E0271, E0599. For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/issues/issue-31212.stderr b/src/test/ui/issues/issue-31212.stderr index d964b702f221f..0bb56b361cbbf 100644 --- a/src/test/ui/issues/issue-31212.stderr +++ b/src/test/ui/issues/issue-31212.stderr @@ -1,16 +1,16 @@ error[E0432]: unresolved import `self::*` --> $DIR/issue-31212.rs:5:13 | -LL | pub use self::*; //~ ERROR unresolved - | ^^^^^^^ Cannot glob-import a module into itself. +LL | pub use self::*; + | ^^^^^^^ cannot glob-import a module into itself error[E0425]: cannot find function `f` in module `foo` --> $DIR/issue-31212.rs:9:10 | -LL | foo::f(); //~ ERROR cannot find function `f` in module `foo` +LL | foo::f(); | ^ not found in `foo` error: aborting due to 2 previous errors -Some errors occurred: E0425, E0432. +Some errors have detailed explanations: E0425, E0432. For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/issues/issue-3154.stderr b/src/test/ui/issues/issue-3154.stderr index 6f3b37a8a3fa1..da2af83ff03c3 100644 --- a/src/test/ui/issues/issue-3154.stderr +++ b/src/test/ui/issues/issue-3154.stderr @@ -3,7 +3,7 @@ error[E0621]: explicit lifetime required in the type of `x` | LL | fn thing<'a,Q>(x: &Q) -> Thing<'a,Q> { | -- help: add explicit lifetime `'a` to the type of `x`: `&'a Q` -LL | Thing { x: x } //~ ERROR explicit lifetime required in the type of `x` [E0621] +LL | Thing { x: x } | ^^^^^^^^^^^^^^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/issues/issue-31561.stderr b/src/test/ui/issues/issue-31561.stderr index c95fc36cea6e8..246137aeee05c 100644 --- a/src/test/ui/issues/issue-31561.stderr +++ b/src/test/ui/issues/issue-31561.stderr @@ -1,8 +1,15 @@ error[E0005]: refutable pattern in local binding: `Bar` not covered --> $DIR/issue-31561.rs:8:9 | -LL | let Thing::Foo(y) = Thing::Foo(1); - | ^^^^^^^^^^^^^ pattern `Bar` not covered +LL | / enum Thing { +LL | | Foo(u8), +LL | | Bar, +LL | | Baz +LL | | } + | |_- `Thing` defined here +... +LL | let Thing::Foo(y) = Thing::Foo(1); + | ^^^^^^^^^^^^^ pattern `Bar` not covered error: aborting due to previous error diff --git a/src/test/ui/issues/issue-31769.rs b/src/test/ui/issues/issue-31769.rs index 794c1d1989388..45eb5e4008089 100644 --- a/src/test/ui/issues/issue-31769.rs +++ b/src/test/ui/issues/issue-31769.rs @@ -1,4 +1,4 @@ fn main() { #[inline] struct Foo; //~ ERROR attribute should be applied to function or closure - #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum or union + #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum, or union } diff --git a/src/test/ui/issues/issue-31769.stderr b/src/test/ui/issues/issue-31769.stderr index 7e5e5673bafc6..20534e1ae82c5 100644 --- a/src/test/ui/issues/issue-31769.stderr +++ b/src/test/ui/issues/issue-31769.stderr @@ -1,16 +1,16 @@ error[E0518]: attribute should be applied to function or closure --> $DIR/issue-31769.rs:2:5 | -LL | #[inline] struct Foo; //~ ERROR attribute should be applied to function or closure +LL | #[inline] struct Foo; | ^^^^^^^^^ ----------- not a function or closure -error[E0517]: attribute should be applied to struct, enum or union +error[E0517]: attribute should be applied to struct, enum, or union --> $DIR/issue-31769.rs:3:12 | -LL | #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum or union - | ^ ----------- not a struct, enum or union +LL | #[repr(C)] fn foo() {} + | ^ ----------- not a struct, enum, or union error: aborting due to 2 previous errors -Some errors occurred: E0517, E0518. +Some errors have detailed explanations: E0517, E0518. For more information about an error, try `rustc --explain E0517`. diff --git a/src/test/ui/issues/issue-31804.stderr b/src/test/ui/issues/issue-31804.stderr index 67e2f2bf2ecf7..76e68b0b3524d 100644 --- a/src/test/ui/issues/issue-31804.stderr +++ b/src/test/ui/issues/issue-31804.stderr @@ -1,7 +1,7 @@ error: expected pattern, found `}` --> $DIR/issue-31804.rs:6:1 | -LL | } //~ ERROR expected pattern, found `}` +LL | } | ^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/issues/issue-31845.stderr b/src/test/ui/issues/issue-31845.stderr index 7ee1a41a3870d..10cb398cb24f1 100644 --- a/src/test/ui/issues/issue-31845.stderr +++ b/src/test/ui/issues/issue-31845.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find function `g` in this scope --> $DIR/issue-31845.rs:7:12 | -LL | g(); //~ ERROR cannot find function `g` in this scope +LL | g(); | ^ help: a function with a similar name exists: `h` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-31910.stderr b/src/test/ui/issues/issue-31910.stderr index c58702da97bc6..e7555b958a3d4 100644 --- a/src/test/ui/issues/issue-31910.stderr +++ b/src/test/ui/issues/issue-31910.stderr @@ -3,6 +3,10 @@ error[E0308]: mismatched types | LL | X = Trait::Number, | ^^^^^^^^^^^^^ expected isize, found i32 +help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit + | +LL | X = Trait::Number.try_into().unwrap(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-31924-non-snake-ffi.rs b/src/test/ui/issues/issue-31924-non-snake-ffi.rs index 5e2336cce2cc5..63e42b484427e 100644 --- a/src/test/ui/issues/issue-31924-non-snake-ffi.rs +++ b/src/test/ui/issues/issue-31924-non-snake-ffi.rs @@ -1,8 +1,8 @@ -// compile-pass -// skip-codegen +// check-pass + #![deny(non_snake_case)] -#[no_mangle] -pub extern "C" fn SparklingGenerationForeignFunctionInterface() {} +#[no_mangle] +pub extern "C" fn SparklingGenerationForeignFunctionInterface() {} // OK fn main() {} diff --git a/src/test/ui/issues/issue-32086.stderr b/src/test/ui/issues/issue-32086.stderr index bb2cc7c101b77..b5a120c4b9cee 100644 --- a/src/test/ui/issues/issue-32086.stderr +++ b/src/test/ui/issues/issue-32086.stderr @@ -1,13 +1,13 @@ error[E0532]: expected tuple struct/variant, found constant `C` --> $DIR/issue-32086.rs:5:9 | -LL | let C(a) = S(11); //~ ERROR expected tuple struct/variant, found constant `C` +LL | let C(a) = S(11); | ^ help: a tuple struct with a similar name exists: `S` error[E0532]: expected tuple struct/variant, found constant `C` --> $DIR/issue-32086.rs:6:9 | -LL | let C(..) = S(11); //~ ERROR expected tuple struct/variant, found constant `C` +LL | let C(..) = S(11); | ^ help: a tuple struct with a similar name exists: `S` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-32119.rs b/src/test/ui/issues/issue-32119.rs index ea8824b7966e8..36adb5289aca5 100644 --- a/src/test/ui/issues/issue-32119.rs +++ b/src/test/ui/issues/issue-32119.rs @@ -1,6 +1,5 @@ -// compile-pass -// skip-codegen -#![allow(dead_code)] +// check-pass + pub type T = (); mod foo { pub use super::T; } mod bar { pub use super::T; } @@ -15,5 +14,4 @@ mod baz { pub use self::bar::*; } - fn main() {} diff --git a/src/test/ui/issues/issue-3214.stderr b/src/test/ui/issues/issue-3214.stderr index e6526bad3e0d3..02c8da10bb4a3 100644 --- a/src/test/ui/issues/issue-3214.stderr +++ b/src/test/ui/issues/issue-3214.stderr @@ -2,11 +2,11 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-3214.rs:3:12 | LL | fn foo() { - | --- - type variable from outer function + | --- - type parameter from outer function | | | try adding a local generic parameter in this method instead LL | struct Foo { -LL | x: T, //~ ERROR can't use generic parameters from outer function +LL | x: T, | ^ use of generic parameter from outer function error[E0107]: wrong number of type arguments: expected 0, found 1 @@ -17,5 +17,5 @@ LL | impl Drop for Foo { error: aborting due to 2 previous errors -Some errors occurred: E0107, E0401. +Some errors have detailed explanations: E0107, E0401. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/issues/issue-32222.rs b/src/test/ui/issues/issue-32222.rs index 91f53ab2805a8..4ed06bff80341 100644 --- a/src/test/ui/issues/issue-32222.rs +++ b/src/test/ui/issues/issue-32222.rs @@ -1,6 +1,4 @@ -// compile-pass -// skip-codegen -#![allow(warnings)] +// check-pass mod foo { pub fn bar() {} @@ -21,5 +19,4 @@ mod b { pub use a::bar; } - fn main() {} diff --git a/src/test/ui/issues/issue-32326.stderr b/src/test/ui/issues/issue-32326.stderr index 0f56e94bd196c..5967627e51a4b 100644 --- a/src/test/ui/issues/issue-32326.stderr +++ b/src/test/ui/issues/issue-32326.stderr @@ -1,7 +1,7 @@ error[E0072]: recursive type `Expr` has infinite size --> $DIR/issue-32326.rs:5:1 | -LL | enum Expr { //~ ERROR E0072 +LL | enum Expr { | ^^^^^^^^^ recursive type has infinite size LL | Plus(Expr, Expr), | ---- ---- recursive without indirection diff --git a/src/test/ui/issues/issue-32354-suggest-import-rename.stderr b/src/test/ui/issues/issue-32354-suggest-import-rename.stderr index 9e115143fbd2a..96684309a008d 100644 --- a/src/test/ui/issues/issue-32354-suggest-import-rename.stderr +++ b/src/test/ui/issues/issue-32354-suggest-import-rename.stderr @@ -3,13 +3,13 @@ error[E0252]: the name `ConstructorExtension` is defined multiple times | LL | use extension1::ConstructorExtension; | -------------------------------- previous import of the trait `ConstructorExtension` here -LL | use extension2::ConstructorExtension; //~ ERROR is defined multiple times +LL | use extension2::ConstructorExtension; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ConstructorExtension` reimported here | = note: `ConstructorExtension` must be defined only once in the type namespace of this module help: you can use `as` to change the binding name of the import | -LL | use extension2::ConstructorExtension as OtherConstructorExtension; //~ ERROR is defined multiple times +LL | use extension2::ConstructorExtension as OtherConstructorExtension; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-32655.stderr b/src/test/ui/issues/issue-32655.stderr index ae0cf49a79110..3ab934f6ca58f 100644 --- a/src/test/ui/issues/issue-32655.stderr +++ b/src/test/ui/issues/issue-32655.stderr @@ -1,20 +1,22 @@ -error[E0658]: The attribute `derive_Clone` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `derive_Clone` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/issue-32655.rs:6:11 | -LL | #[derive_Clone] //~ ERROR attribute `derive_Clone` is currently unknown +LL | #[derive_Clone] | ^^^^^^^^^^^^ ... LL | foo!(); | ------- in this macro invocation | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `derive_Clone` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `derive_Clone` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/issue-32655.rs:18:7 | -LL | #[derive_Clone] //~ ERROR attribute `derive_Clone` is currently unknown +LL | #[derive_Clone] | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr index 9161e64ef0a8a..04b8c3aa35396 100644 --- a/src/test/ui/issues/issue-32709.stderr +++ b/src/test/ui/issues/issue-32709.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `(): std::convert::From<{integer}>` is not satisfied - --> $DIR/issue-32709.rs:4:5 +error[E0277]: `?` couldn't convert the error to `()` + --> $DIR/issue-32709.rs:4:11 | -LL | Err(5)?; //~ ERROR - | ^^^^^^^ the trait `std::convert::From<{integer}>` is not implemented for `()` +LL | Err(5)?; + | ^ the trait `std::convert::From<{integer}>` is not implemented for `()` | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = note: required by `std::convert::From::from` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-32782.stderr b/src/test/ui/issues/issue-32782.stderr index 5d583ee843f66..886f5297156f5 100644 --- a/src/test/ui/issues/issue-32782.stderr +++ b/src/test/ui/issues/issue-32782.stderr @@ -1,7 +1,7 @@ error[E0658]: allow_internal_unstable side-steps feature gating and stability checks --> $DIR/issue-32782.rs:7:9 | -LL | #[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps +LL | #[allow_internal_unstable] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | foo!(); diff --git a/src/test/ui/issues/issue-32797.rs b/src/test/ui/issues/issue-32797.rs index 5ceb7f49331e5..b12b929f8fcf8 100644 --- a/src/test/ui/issues/issue-32797.rs +++ b/src/test/ui/issues/issue-32797.rs @@ -1,5 +1,4 @@ -// compile-pass -// skip-codegen +// check-pass pub use bar::*; mod bar { @@ -11,5 +10,4 @@ mod baz { pub use main as f; } - pub fn main() {} diff --git a/src/test/ui/issues/issue-32829.stderr b/src/test/ui/issues/issue-32829.stderr index 037f5416fa583..157c8c85af0c8 100644 --- a/src/test/ui/issues/issue-32829.stderr +++ b/src/test/ui/issues/issue-32829.stderr @@ -1,9 +1,10 @@ -error[E0658]: panicking in statics is unstable (see issue #51999) +error[E0658]: panicking in statics is unstable --> $DIR/issue-32829.rs:1:22 | LL | static S : u64 = { { panic!("foo"); 0 } }; | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51999 = help: add #![feature(const_panic)] to the crate attributes to enable = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/issues/issue-32833.stderr b/src/test/ui/issues/issue-32833.stderr index c7f0eb1a43290..430cc0fda26da 100644 --- a/src/test/ui/issues/issue-32833.stderr +++ b/src/test/ui/issues/issue-32833.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `bar::Foo` --> $DIR/issue-32833.rs:1:5 | -LL | use bar::Foo; //~ ERROR unresolved import `bar::Foo` [E0432] +LL | use bar::Foo; | ^^^^^^^^ no `Foo` in `bar` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-32922.rs b/src/test/ui/issues/issue-32922.rs index b06b63cbdc3ff..54ec44a1cf4e5 100644 --- a/src/test/ui/issues/issue-32922.rs +++ b/src/test/ui/issues/issue-32922.rs @@ -1,6 +1,4 @@ -// compile-pass -// skip-codegen -#![allow(warnings)] +// check-pass macro_rules! foo { () => { let x = 1; @@ -22,7 +20,6 @@ macro_rules! baz { } } - fn main() { foo! {}; bar! {}; diff --git a/src/test/ui/issues/issue-32950.stderr b/src/test/ui/issues/issue-32950.stderr index 13aed4a1756b3..3cdf35af1d866 100644 --- a/src/test/ui/issues/issue-32950.stderr +++ b/src/test/ui/issues/issue-32950.stderr @@ -1,13 +1,13 @@ error: `derive` cannot be used on items with type macros --> $DIR/issue-32950.rs:5:5 | -LL | concat_idents!(Foo, Bar) //~ ERROR `derive` cannot be used on items with type macros +LL | concat_idents!(Foo, Bar) | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0412]: cannot find type `FooBar` in this scope --> $DIR/issue-32950.rs:5:5 | -LL | concat_idents!(Foo, Bar) //~ ERROR `derive` cannot be used on items with type macros +LL | concat_idents!(Foo, Bar) | ^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-32963.rs b/src/test/ui/issues/issue-32963.rs index be59d3522b865..ee099069f0241 100644 --- a/src/test/ui/issues/issue-32963.rs +++ b/src/test/ui/issues/issue-32963.rs @@ -5,7 +5,7 @@ trait Misc {} fn size_of_copy() -> usize { mem::size_of::() } fn main() { - size_of_copy::(); + size_of_copy::(); //~^ ERROR only auto traits can be used as additional traits in a trait object //~| ERROR the trait bound `dyn Misc: std::marker::Copy` is not satisfied } diff --git a/src/test/ui/issues/issue-32963.stderr b/src/test/ui/issues/issue-32963.stderr index 3e22ea7b2891b..a31a74a07f46e 100644 --- a/src/test/ui/issues/issue-32963.stderr +++ b/src/test/ui/issues/issue-32963.stderr @@ -1,14 +1,19 @@ error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/issue-32963.rs:8:25 + --> $DIR/issue-32963.rs:8:31 | -LL | size_of_copy::(); - | ^^^^ non-auto additional trait +LL | size_of_copy::(); + | ---- ^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) error[E0277]: the trait bound `dyn Misc: std::marker::Copy` is not satisfied --> $DIR/issue-32963.rs:8:5 | -LL | size_of_copy::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `dyn Misc` +LL | size_of_copy::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `dyn Misc` | note: required by `size_of_copy` --> $DIR/issue-32963.rs:5:1 @@ -18,5 +23,5 @@ LL | fn size_of_copy() -> usize { mem::size_of::() } error: aborting due to 2 previous errors -Some errors occurred: E0225, E0277. +Some errors have detailed explanations: E0225, E0277. For more information about an error, try `rustc --explain E0225`. diff --git a/src/test/ui/issues/issue-32995.rs b/src/test/ui/issues/issue-32995.rs index c32fb63f1e584..3526deffc79ab 100644 --- a/src/test/ui/issues/issue-32995.rs +++ b/src/test/ui/issues/issue-32995.rs @@ -17,11 +17,11 @@ fn main() { //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait //~| WARN previously accepted - let o : Box<::std::marker()::Send> = Box::new(1); + let o : Box = Box::new(1); //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait //~| WARN previously accepted - let o : Box = Box::new(1); + let o : Box = Box::new(1); //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait //~| WARN previously accepted } diff --git a/src/test/ui/issues/issue-32995.stderr b/src/test/ui/issues/issue-32995.stderr index 97b4b7fa76ca8..f97d86f6522ab 100644 --- a/src/test/ui/issues/issue-32995.stderr +++ b/src/test/ui/issues/issue-32995.stderr @@ -36,19 +36,19 @@ LL | let p = ::std::str::from_utf8::()(b"foo").unwrap(); = note: for more information, see issue #42238 error: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/issue-32995.rs:20:30 + --> $DIR/issue-32995.rs:20:35 | -LL | let o : Box<::std::marker()::Send> = Box::new(1); - | ^^ +LL | let o : Box = Box::new(1); + | ^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #42238 error: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/issue-32995.rs:24:37 + --> $DIR/issue-32995.rs:24:41 | -LL | let o : Box = Box::new(1); - | ^^ +LL | let o : Box = Box::new(1); + | ^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #42238 diff --git a/src/test/ui/issues/issue-33140-traitobject-crate.rs b/src/test/ui/issues/issue-33140-traitobject-crate.rs index 2b644817df115..078f3f3dd2cd2 100644 --- a/src/test/ui/issues/issue-33140-traitobject-crate.rs +++ b/src/test/ui/issues/issue-33140-traitobject-crate.rs @@ -13,85 +13,85 @@ /// Implementations for all traits in std are provided. pub unsafe trait Trait {} -unsafe impl Trait for ::std::any::Any + Send { } -unsafe impl Trait for ::std::any::Any + Sync { } -unsafe impl Trait for ::std::any::Any + Send + Sync { } -unsafe impl Trait for ::std::borrow::Borrow + Send { } -unsafe impl Trait for ::std::borrow::Borrow + Sync { } -unsafe impl Trait for ::std::borrow::Borrow + Send + Sync { } -unsafe impl Trait for ::std::borrow::BorrowMut + Send { } -unsafe impl Trait for ::std::borrow::BorrowMut + Sync { } -unsafe impl Trait for ::std::borrow::BorrowMut + Send + Sync { } -unsafe impl Trait for ::std::convert::AsMut + Send { } -unsafe impl Trait for ::std::convert::AsMut + Sync { } -unsafe impl Trait for ::std::convert::AsMut + Send + Sync { } -unsafe impl Trait for ::std::convert::AsRef + Send { } -unsafe impl Trait for ::std::convert::AsRef + Sync { } -unsafe impl Trait for ::std::convert::AsRef + Send + Sync { } -unsafe impl Trait for ::std::error::Error + Send { } -unsafe impl Trait for ::std::error::Error + Sync { } -unsafe impl Trait for ::std::error::Error + Send + Sync { } -unsafe impl Trait for ::std::fmt::Binary + Send { } -unsafe impl Trait for ::std::fmt::Binary + Sync { } -unsafe impl Trait for ::std::fmt::Binary + Send + Sync { } -unsafe impl Trait for ::std::fmt::Debug + Send { } -unsafe impl Trait for ::std::fmt::Debug + Sync { } -unsafe impl Trait for ::std::fmt::Debug + Send + Sync { } -unsafe impl Trait for ::std::fmt::Display + Send { } -unsafe impl Trait for ::std::fmt::Display + Sync { } -unsafe impl Trait for ::std::fmt::Display + Send + Sync { } -unsafe impl Trait for ::std::fmt::LowerExp + Send { } -unsafe impl Trait for ::std::fmt::LowerExp + Sync { } -unsafe impl Trait for ::std::fmt::LowerExp + Send + Sync { } -unsafe impl Trait for ::std::fmt::LowerHex + Send { } -unsafe impl Trait for ::std::fmt::LowerHex + Sync { } -unsafe impl Trait for ::std::fmt::LowerHex + Send + Sync { } -unsafe impl Trait for ::std::fmt::Octal + Send { } -unsafe impl Trait for ::std::fmt::Octal + Sync { } -unsafe impl Trait for ::std::fmt::Octal + Send + Sync { } -unsafe impl Trait for ::std::fmt::Pointer + Send { } -unsafe impl Trait for ::std::fmt::Pointer + Sync { } -unsafe impl Trait for ::std::fmt::Pointer + Send + Sync { } -unsafe impl Trait for ::std::fmt::UpperExp + Send { } -unsafe impl Trait for ::std::fmt::UpperExp + Sync { } -unsafe impl Trait for ::std::fmt::UpperExp + Send + Sync { } -unsafe impl Trait for ::std::fmt::UpperHex + Send { } -unsafe impl Trait for ::std::fmt::UpperHex + Sync { } -unsafe impl Trait for ::std::fmt::UpperHex + Send + Sync { } -unsafe impl Trait for ::std::fmt::Write + Send { } -unsafe impl Trait for ::std::fmt::Write + Sync { } -unsafe impl Trait for ::std::fmt::Write + Send + Sync { } -unsafe impl Trait for ::std::hash::Hasher + Send { } -unsafe impl Trait for ::std::hash::Hasher + Sync { } -unsafe impl Trait for ::std::hash::Hasher + Send + Sync { } -unsafe impl Trait for ::std::io::BufRead + Send { } -unsafe impl Trait for ::std::io::BufRead + Sync { } -unsafe impl Trait for ::std::io::BufRead + Send + Sync { } -unsafe impl Trait for ::std::io::Read + Send { } -unsafe impl Trait for ::std::io::Read + Sync { } -unsafe impl Trait for ::std::io::Read + Send + Sync { } -unsafe impl Trait for ::std::io::Seek + Send { } -unsafe impl Trait for ::std::io::Seek + Sync { } -unsafe impl Trait for ::std::io::Seek + Send + Sync { } -unsafe impl Trait for ::std::io::Write + Send { } -unsafe impl Trait for ::std::io::Write + Sync { } -unsafe impl Trait for ::std::io::Write + Send + Sync { } -unsafe impl Trait for ::std::iter::IntoIterator { } -unsafe impl Trait for ::std::iter::Iterator + Send { } -unsafe impl Trait for ::std::iter::Iterator + Sync { } -unsafe impl Trait for ::std::iter::Iterator + Send + Sync { } -unsafe impl Trait for ::std::marker::Send + Send { } -unsafe impl Trait for ::std::marker::Send + Sync { } -unsafe impl Trait for ::std::marker::Send + Send + Sync { } -unsafe impl Trait for ::std::marker::Sync + Send { } -unsafe impl Trait for ::std::marker::Sync + Sync { } -unsafe impl Trait for ::std::marker::Sync + Send + Sync { } -unsafe impl Trait for ::std::ops::Drop + Send { } -unsafe impl Trait for ::std::ops::Drop + Sync { } -unsafe impl Trait for ::std::ops::Drop + Send + Sync { } -unsafe impl Trait for ::std::string::ToString + Send { } -unsafe impl Trait for ::std::string::ToString + Sync { } -unsafe impl Trait for ::std::string::ToString + Send + Sync { } +unsafe impl Trait for dyn (::std::any::Any) + Send { } +unsafe impl Trait for dyn (::std::any::Any) + Sync { } +unsafe impl Trait for dyn (::std::any::Any) + Send + Sync { } +unsafe impl Trait for dyn (::std::borrow::Borrow) + Send { } +unsafe impl Trait for dyn (::std::borrow::Borrow) + Sync { } +unsafe impl Trait for dyn (::std::borrow::Borrow) + Send + Sync { } +unsafe impl Trait for dyn (::std::borrow::BorrowMut) + Send { } +unsafe impl Trait for dyn (::std::borrow::BorrowMut) + Sync { } +unsafe impl Trait for dyn (::std::borrow::BorrowMut) + Send + Sync { } +unsafe impl Trait for dyn (::std::convert::AsMut) + Send { } +unsafe impl Trait for dyn (::std::convert::AsMut) + Sync { } +unsafe impl Trait for dyn (::std::convert::AsMut) + Send + Sync { } +unsafe impl Trait for dyn (::std::convert::AsRef) + Send { } +unsafe impl Trait for dyn (::std::convert::AsRef) + Sync { } +unsafe impl Trait for dyn (::std::convert::AsRef) + Send + Sync { } +unsafe impl Trait for dyn (::std::error::Error) + Send { } +unsafe impl Trait for dyn (::std::error::Error) + Sync { } +unsafe impl Trait for dyn (::std::error::Error) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::Binary) + Send { } +unsafe impl Trait for dyn (::std::fmt::Binary) + Sync { } +unsafe impl Trait for dyn (::std::fmt::Binary) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::Debug) + Send { } +unsafe impl Trait for dyn (::std::fmt::Debug) + Sync { } +unsafe impl Trait for dyn (::std::fmt::Debug) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::Display) + Send { } +unsafe impl Trait for dyn (::std::fmt::Display) + Sync { } +unsafe impl Trait for dyn (::std::fmt::Display) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::LowerExp) + Send { } +unsafe impl Trait for dyn (::std::fmt::LowerExp) + Sync { } +unsafe impl Trait for dyn (::std::fmt::LowerExp) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::LowerHex) + Send { } +unsafe impl Trait for dyn (::std::fmt::LowerHex) + Sync { } +unsafe impl Trait for dyn (::std::fmt::LowerHex) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::Octal) + Send { } +unsafe impl Trait for dyn (::std::fmt::Octal) + Sync { } +unsafe impl Trait for dyn (::std::fmt::Octal) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::Pointer) + Send { } +unsafe impl Trait for dyn (::std::fmt::Pointer) + Sync { } +unsafe impl Trait for dyn (::std::fmt::Pointer) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::UpperExp) + Send { } +unsafe impl Trait for dyn (::std::fmt::UpperExp) + Sync { } +unsafe impl Trait for dyn (::std::fmt::UpperExp) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::UpperHex) + Send { } +unsafe impl Trait for dyn (::std::fmt::UpperHex) + Sync { } +unsafe impl Trait for dyn (::std::fmt::UpperHex) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::Write) + Send { } +unsafe impl Trait for dyn (::std::fmt::Write) + Sync { } +unsafe impl Trait for dyn (::std::fmt::Write) + Send + Sync { } +unsafe impl Trait for dyn (::std::hash::Hasher) + Send { } +unsafe impl Trait for dyn (::std::hash::Hasher) + Sync { } +unsafe impl Trait for dyn (::std::hash::Hasher) + Send + Sync { } +unsafe impl Trait for dyn (::std::io::BufRead) + Send { } +unsafe impl Trait for dyn (::std::io::BufRead) + Sync { } +unsafe impl Trait for dyn (::std::io::BufRead) + Send + Sync { } +unsafe impl Trait for dyn (::std::io::Read) + Send { } +unsafe impl Trait for dyn (::std::io::Read) + Sync { } +unsafe impl Trait for dyn (::std::io::Read) + Send + Sync { } +unsafe impl Trait for dyn (::std::io::Seek) + Send { } +unsafe impl Trait for dyn (::std::io::Seek) + Sync { } +unsafe impl Trait for dyn (::std::io::Seek) + Send + Sync { } +unsafe impl Trait for dyn (::std::io::Write) + Send { } +unsafe impl Trait for dyn (::std::io::Write) + Sync { } +unsafe impl Trait for dyn (::std::io::Write) + Send + Sync { } +unsafe impl Trait for dyn (::std::iter::IntoIterator) { } +unsafe impl Trait for dyn (::std::iter::Iterator) + Send { } +unsafe impl Trait for dyn (::std::iter::Iterator) + Sync { } +unsafe impl Trait for dyn (::std::iter::Iterator) + Send + Sync { } +unsafe impl Trait for dyn (::std::marker::Send) + Send { } +unsafe impl Trait for dyn (::std::marker::Send) + Sync { } +unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } +unsafe impl Trait for dyn (::std::marker::Sync) + Send { } +unsafe impl Trait for dyn (::std::marker::Sync) + Sync { } +unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { } +unsafe impl Trait for dyn (::std::ops::Drop) + Send { } +unsafe impl Trait for dyn (::std::ops::Drop) + Sync { } +unsafe impl Trait for dyn (::std::ops::Drop) + Send + Sync { } +unsafe impl Trait for dyn (::std::string::ToString) + Send { } +unsafe impl Trait for dyn (::std::string::ToString) + Sync { } +unsafe impl Trait for dyn (::std::string::ToString) + Send + Sync { } fn assert_trait() {} fn main() { diff --git a/src/test/ui/issues/issue-33140-traitobject-crate.stderr b/src/test/ui/issues/issue-33140-traitobject-crate.stderr index 6f71e79d0ee7a..76db98aa38bb4 100644 --- a/src/test/ui/issues/issue-33140-traitobject-crate.stderr +++ b/src/test/ui/issues/issue-33140-traitobject-crate.stderr @@ -1,10 +1,10 @@ warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) --> $DIR/issue-33140-traitobject-crate.rs:85:1 | -LL | unsafe impl Trait for ::std::marker::Send + Sync { } - | ------------------------------------------------ first implementation here -LL | unsafe impl Trait for ::std::marker::Send + Send + Sync { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)` +LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { } + | ------------------------------------------------------ first implementation here +LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)` | note: lint level defined here --> $DIR/issue-33140-traitobject-crate.rs:3:9 @@ -17,10 +17,10 @@ LL | #![warn(order_dependent_trait_objects)] warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) --> $DIR/issue-33140-traitobject-crate.rs:86:1 | -LL | unsafe impl Trait for ::std::marker::Send + Send + Sync { } - | ------------------------------------------------------- first implementation here -LL | unsafe impl Trait for ::std::marker::Sync + Send { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)` +LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } + | ------------------------------------------------------------- first implementation here +LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)` | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #56484 @@ -28,11 +28,11 @@ LL | unsafe impl Trait for ::std::marker::Sync + Send { } warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) --> $DIR/issue-33140-traitobject-crate.rs:88:1 | -LL | unsafe impl Trait for ::std::marker::Sync + Send { } - | ------------------------------------------------ first implementation here -LL | unsafe impl Trait for ::std::marker::Sync + Sync { } -LL | unsafe impl Trait for ::std::marker::Sync + Send + Sync { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)` +LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } + | ------------------------------------------------------ first implementation here +LL | unsafe impl Trait for dyn (::std::marker::Sync) + Sync { } +LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)` | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #56484 diff --git a/src/test/ui/issues/issue-33140.rs b/src/test/ui/issues/issue-33140.rs index 930e24218ac72..9bdac4b8375c2 100644 --- a/src/test/ui/issues/issue-33140.rs +++ b/src/test/ui/issues/issue-33140.rs @@ -38,10 +38,10 @@ impl Foo { } fn main() { - assert_eq!(::xyz(), false); - assert_eq!(::xyz(), true); - assert_eq!(::uvw(), false); - assert_eq!(::uvw(), true); - assert_eq!(>::abc(), false); - assert_eq!(>::abc(), true); + assert_eq!(::xyz(), false); + assert_eq!(::xyz(), true); + assert_eq!(::uvw(), false); + assert_eq!(::uvw(), true); + assert_eq!(>::abc(), false); + assert_eq!(>::abc(), true); } diff --git a/src/test/ui/issues/issue-33140.stderr b/src/test/ui/issues/issue-33140.stderr index e2631e971c516..6c3ba63e6f6f2 100644 --- a/src/test/ui/issues/issue-33140.stderr +++ b/src/test/ui/issues/issue-33140.stderr @@ -19,7 +19,7 @@ LL | impl Trait2 for dyn Sync + Send + Sync { error[E0592]: duplicate definitions with name `abc` --> $DIR/issue-33140.rs:29:5 | -LL | / fn abc() -> bool { //~ ERROR duplicate definitions with name `abc` +LL | / fn abc() -> bool { LL | | false LL | | } | |_____^ duplicate definitions for `abc` @@ -31,5 +31,5 @@ LL | | } error: aborting due to 3 previous errors -Some errors occurred: E0119, E0592. +Some errors have detailed explanations: E0119, E0592. For more information about an error, try `rustc --explain E0119`. diff --git a/src/test/ui/issues/issue-33241.rs b/src/test/ui/issues/issue-33241.rs index 4c5052a60d3f3..5f9f1e4a74211 100644 --- a/src/test/ui/issues/issue-33241.rs +++ b/src/test/ui/issues/issue-33241.rs @@ -1,5 +1,4 @@ -// compile-pass -// skip-codegen +// check-pass use std::fmt; @@ -7,8 +6,7 @@ use std::fmt; // an unsized tuple by transmuting a trait object. fn any() -> T { unreachable!() } - fn main() { - let t: &(u8, fmt::Debug) = any(); + let t: &(u8, dyn fmt::Debug) = any(); println!("{:?}", &t.1); } diff --git a/src/test/ui/issues/issue-33264.rs b/src/test/ui/issues/issue-33264.rs index 7cba4df7d82ae..51608b48be27c 100644 --- a/src/test/ui/issues/issue-33264.rs +++ b/src/test/ui/issues/issue-33264.rs @@ -27,4 +27,3 @@ impl D32x4 { } fn main() { } - diff --git a/src/test/ui/issues/issue-33287.rs b/src/test/ui/issues/issue-33287.rs index c6e1f4d1eb2f5..cc47e58fcdc15 100644 --- a/src/test/ui/issues/issue-33287.rs +++ b/src/test/ui/issues/issue-33287.rs @@ -8,4 +8,3 @@ fn test() { } fn main() { } - diff --git a/src/test/ui/issues/issue-3344.stderr b/src/test/ui/issues/issue-3344.stderr index 8e4a14fb4fae8..6593e07b18973 100644 --- a/src/test/ui/issues/issue-3344.stderr +++ b/src/test/ui/issues/issue-3344.stderr @@ -1,7 +1,7 @@ error[E0046]: not all trait items implemented, missing: `partial_cmp` --> $DIR/issue-3344.rs:3:1 | -LL | impl PartialOrd for Thing { //~ ERROR not all trait items implemented, missing: `partial_cmp` +LL | impl PartialOrd for Thing { | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing `partial_cmp` in implementation | = note: `partial_cmp` from trait: `fn(&Self, &Rhs) -> std::option::Option` diff --git a/src/test/ui/issues/issue-33504.stderr b/src/test/ui/issues/issue-33504.stderr index 716aa8a863292..7af555eaa2ce4 100644 --- a/src/test/ui/issues/issue-33504.stderr +++ b/src/test/ui/issues/issue-33504.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-33504.rs:7:13 | -LL | let Test = 1; //~ ERROR mismatched types +LL | let Test = 1; | ^^^^ expected integer, found struct `Test` | = note: expected type `{integer}` diff --git a/src/test/ui/issues/issue-33525.stderr b/src/test/ui/issues/issue-33525.stderr index 2c97a39a183f8..f8d703dc3b169 100644 --- a/src/test/ui/issues/issue-33525.stderr +++ b/src/test/ui/issues/issue-33525.stderr @@ -1,22 +1,22 @@ error[E0425]: cannot find value `a` in this scope --> $DIR/issue-33525.rs:2:5 | -LL | a; //~ ERROR cannot find value `a` +LL | a; | ^ not found in this scope error[E0609]: no field `lorem` on type `&'static str` --> $DIR/issue-33525.rs:3:8 | -LL | "".lorem; //~ ERROR no field +LL | "".lorem; | ^^^^^ error[E0609]: no field `ipsum` on type `&'static str` --> $DIR/issue-33525.rs:4:8 | -LL | "".ipsum; //~ ERROR no field +LL | "".ipsum; | ^^^^^ error: aborting due to 3 previous errors -Some errors occurred: E0425, E0609. +Some errors have detailed explanations: E0425, E0609. For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/issues/issue-33571.rs b/src/test/ui/issues/issue-33571.rs index 223bbc3ff5e21..147fb3fa8cf33 100644 --- a/src/test/ui/issues/issue-33571.rs +++ b/src/test/ui/issues/issue-33571.rs @@ -1,5 +1,5 @@ #[derive(Clone, - Sync, //~ ERROR this unsafe trait should be implemented explicitly + Sync, //~ ERROR cannot find derive macro `Sync` in this scope Copy)] enum Foo {} diff --git a/src/test/ui/issues/issue-33571.stderr b/src/test/ui/issues/issue-33571.stderr index 2fae447c5e8c5..78e7202077498 100644 --- a/src/test/ui/issues/issue-33571.stderr +++ b/src/test/ui/issues/issue-33571.stderr @@ -1,7 +1,13 @@ -error: this unsafe trait should be implemented explicitly +error: cannot find derive macro `Sync` in this scope --> $DIR/issue-33571.rs:2:10 | -LL | Sync, //~ ERROR this unsafe trait should be implemented explicitly +LL | Sync, + | ^^^^ + | +note: unsafe traits like `Sync` should be implemented explicitly + --> $DIR/issue-33571.rs:2:10 + | +LL | Sync, | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-33819.nll.stderr b/src/test/ui/issues/issue-33819.nll.stderr deleted file mode 100644 index 8bc2d82cd3f14..0000000000000 --- a/src/test/ui/issues/issue-33819.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable - --> $DIR/issue-33819.rs:4:34 - | -LL | Some(ref v) => { let a = &mut v; }, - | ^^^^^^ - | | - | cannot borrow as mutable - | try removing `&mut` here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/issues/issue-33819.rs b/src/test/ui/issues/issue-33819.rs index 7f25ebd18fffc..b73e85974a8e1 100644 --- a/src/test/ui/issues/issue-33819.rs +++ b/src/test/ui/issues/issue-33819.rs @@ -2,8 +2,7 @@ fn main() { let mut op = Some(2); match op { Some(ref v) => { let a = &mut v; }, - //~^ ERROR:cannot borrow immutable - //~| cannot borrow mutably + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable None => {}, } } diff --git a/src/test/ui/issues/issue-33819.stderr b/src/test/ui/issues/issue-33819.stderr index 09b8835a8a69c..8bc2d82cd3f14 100644 --- a/src/test/ui/issues/issue-33819.stderr +++ b/src/test/ui/issues/issue-33819.stderr @@ -1,8 +1,11 @@ -error[E0596]: cannot borrow immutable local variable `v` as mutable - --> $DIR/issue-33819.rs:4:39 +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/issue-33819.rs:4:34 | LL | Some(ref v) => { let a = &mut v; }, - | ^ cannot borrow mutably + | ^^^^^^ + | | + | cannot borrow as mutable + | try removing `&mut` here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-33903.rs b/src/test/ui/issues/issue-33903.rs index 98544aca5f9da..4fdc8dda8b42c 100644 --- a/src/test/ui/issues/issue-33903.rs +++ b/src/test/ui/issues/issue-33903.rs @@ -8,4 +8,3 @@ const FOO: i32 = [12, 34][0 + 1]; fn main() {} - diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index 43cd7af81d98a..596921e526d96 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -1,7 +1,7 @@ error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == &_` --> $DIR/issue-33941.rs:4:36 | -LL | for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch +LL | for _ in HashMap::new().iter().cloned() {} | ^^^^^^ expected tuple, found reference | = note: expected type `(&_, &_)` @@ -10,7 +10,7 @@ LL | for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == &_` --> $DIR/issue-33941.rs:4:14 | -LL | for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch +LL | for _ in HashMap::new().iter().cloned() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference | = note: expected type `(&_, &_)` diff --git a/src/test/ui/issues/issue-34028.rs b/src/test/ui/issues/issue-34028.rs index 8ebc730755faa..d761c0c823bcd 100644 --- a/src/test/ui/issues/issue-34028.rs +++ b/src/test/ui/issues/issue-34028.rs @@ -1,5 +1,4 @@ -// compile-pass -// skip-codegen +// check-pass macro_rules! m { () => { #[cfg(any())] fn f() {} } @@ -8,5 +7,4 @@ macro_rules! m { trait T {} impl T for () { m!(); } - fn main() {} diff --git a/src/test/ui/issues/issue-34047.stderr b/src/test/ui/issues/issue-34047.stderr index 8d552f24cd678..f770ded50d0fd 100644 --- a/src/test/ui/issues/issue-34047.stderr +++ b/src/test/ui/issues/issue-34047.stderr @@ -4,7 +4,7 @@ error[E0530]: match bindings cannot shadow constants LL | const C: u8 = 0; | ---------------- the constant `C` is defined here ... -LL | mut C => {} //~ ERROR match bindings cannot shadow constants +LL | mut C => {} | ^ cannot be named the same as a constant error: aborting due to previous error diff --git a/src/test/ui/issues/issue-34171.rs b/src/test/ui/issues/issue-34171.rs index 25a5f72e803ba..157c58c459d66 100644 --- a/src/test/ui/issues/issue-34171.rs +++ b/src/test/ui/issues/issue-34171.rs @@ -1,12 +1,10 @@ -// compile-pass -// skip-codegen +// check-pass macro_rules! null { ($i:tt) => {} } macro_rules! apply_null { ($i:item) => { null! { $i } } } - fn main() { apply_null!(#[cfg(all())] fn f() {}); } diff --git a/src/test/ui/issues/issue-34209.rs b/src/test/ui/issues/issue-34209.rs index 50095be7740ef..fc2c3679e13b8 100644 --- a/src/test/ui/issues/issue-34209.rs +++ b/src/test/ui/issues/issue-34209.rs @@ -4,8 +4,7 @@ enum S { fn bug(l: S) { match l { - S::B { } => { }, - //~^ ERROR no variant `B` on enum `S` + S::B {} => {}, //~ ERROR no variant `B` in enum `S` } } diff --git a/src/test/ui/issues/issue-34209.stderr b/src/test/ui/issues/issue-34209.stderr index 79aba89c1484e..194bb2bfab8ae 100644 --- a/src/test/ui/issues/issue-34209.stderr +++ b/src/test/ui/issues/issue-34209.stderr @@ -1,8 +1,11 @@ -error: no variant `B` on enum `S` - --> $DIR/issue-34209.rs:7:9 +error: no variant `B` in enum `S` + --> $DIR/issue-34209.rs:7:12 | -LL | S::B { } => { }, - | ^^^^ help: did you mean: `S::A` +LL | enum S { + | ------ variant `B` not found here +... +LL | S::B {} => {}, + | ^ help: there is a variant with a similar name: `A` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-34222-1.stderr b/src/test/ui/issues/issue-34222-1.stderr index beb6b589766b5..0799656b06bd2 100644 --- a/src/test/ui/issues/issue-34222-1.stderr +++ b/src/test/ui/issues/issue-34222-1.stderr @@ -1,7 +1,7 @@ error[E0585]: found a documentation comment that doesn't document anything --> $DIR/issue-34222-1.rs:2:5 | -LL | /// comment //~ ERROR found a documentation comment that doesn't document anything +LL | /// comment | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: doc comments must come before what they document, maybe a comment was intended with `//`? diff --git a/src/test/ui/issues/issue-3424.rs b/src/test/ui/issues/issue-3424.rs index a9ba5f5408bdb..19f9f13e14416 100644 --- a/src/test/ui/issues/issue-3424.rs +++ b/src/test/ui/issues/issue-3424.rs @@ -5,7 +5,7 @@ pub struct Path; -type rsrc_loader = Box Result>; +type rsrc_loader = Box Result>; fn tester() { diff --git a/src/test/ui/issues/issue-34255-1.rs b/src/test/ui/issues/issue-34255-1.rs new file mode 100644 index 0000000000000..b1071934bb2f3 --- /dev/null +++ b/src/test/ui/issues/issue-34255-1.rs @@ -0,0 +1,10 @@ +enum Test { + Drill { + field: i32, + } +} + +fn main() { + Test::Drill(field: 42); + //~^ ERROR expected type, found +} diff --git a/src/test/ui/issues/issue-34255-1.stderr b/src/test/ui/issues/issue-34255-1.stderr new file mode 100644 index 0000000000000..01f3953777017 --- /dev/null +++ b/src/test/ui/issues/issue-34255-1.stderr @@ -0,0 +1,16 @@ +error: expected type, found `42` + --> $DIR/issue-34255-1.rs:8:24 + | +LL | Test::Drill(field: 42); + | ^^ expecting a type here because of type ascription + | + = note: #![feature(type_ascription)] lets you annotate an expression with a type: `: ` +note: this expression expects an ascribed type after the colon + --> $DIR/issue-34255-1.rs:8:17 + | +LL | Test::Drill(field: 42); + | ^^^^^ + = help: this might be indicative of a syntax error elsewhere + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-34334.rs b/src/test/ui/issues/issue-34334.rs index 5c4f5c86a7fde..928d217441ef2 100644 --- a/src/test/ui/issues/issue-34334.rs +++ b/src/test/ui/issues/issue-34334.rs @@ -1,4 +1,10 @@ fn main () { - let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `,` or `>`, found `=` + let sr: Vec<(u32, _, _) = vec![]; + //~^ ERROR expected one of `,` or `>`, found `=` + //~| ERROR expected value, found struct `Vec` + //~| ERROR mismatched types + //~| ERROR invalid left-hand side expression + //~| ERROR expected expression, found reserved identifier `_` let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); + //~^ ERROR no method named `iter` found for type `()` in the current scope } diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index 9571d04363512..e8386fd8de9e5 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -1,10 +1,47 @@ +error: expected expression, found reserved identifier `_` + --> $DIR/issue-34334.rs:2:23 + | +LL | let sr: Vec<(u32, _, _) = vec![]; + | ^ expected expression + error: expected one of `,` or `>`, found `=` --> $DIR/issue-34334.rs:2:29 | -LL | let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `,` or `>`, found `=` - | -- ^ expected one of `,` or `>` here - | | +LL | let sr: Vec<(u32, _, _) = vec![]; + | --- ^ expected one of `,` or `>` here + | | | + | | help: use `=` if you meant to assign | while parsing the type for `sr` -error: aborting due to previous error +error[E0423]: expected value, found struct `Vec` + --> $DIR/issue-34334.rs:2:13 + | +LL | let sr: Vec<(u32, _, _) = vec![]; + | ^^^ did you mean `Vec { /* fields */ }`? + +error[E0308]: mismatched types + --> $DIR/issue-34334.rs:2:31 + | +LL | let sr: Vec<(u32, _, _) = vec![]; + | ^^^^^^ expected bool, found struct `std::vec::Vec` + | + = note: expected type `bool` + found type `std::vec::Vec<_>` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error[E0070]: invalid left-hand side expression + --> $DIR/issue-34334.rs:2:13 + | +LL | let sr: Vec<(u32, _, _) = vec![]; + | ^^^^^^^^^^^^^^^^^^^^^^^^ left-hand of expression not valid + +error[E0599]: no method named `iter` found for type `()` in the current scope + --> $DIR/issue-34334.rs:8:36 + | +LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); + | ^^^^ + +error: aborting due to 6 previous errors +Some errors have detailed explanations: E0070, E0308, E0423, E0599. +For more information about an error, try `rustc --explain E0070`. diff --git a/src/test/ui/issues/issue-34349.stderr b/src/test/ui/issues/issue-34349.stderr index f0cd8f9488157..d0b51961b44a7 100644 --- a/src/test/ui/issues/issue-34349.stderr +++ b/src/test/ui/issues/issue-34349.stderr @@ -1,7 +1,7 @@ error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` --> $DIR/issue-34349.rs:16:17 | -LL | let diary = || { //~ ERROR E0525 +LL | let diary = || { | ^^ this closure implements `FnMut`, not `Fn` LL | farewell.push_str("!!!"); | -------- closure is `FnMut` because it mutates the variable `farewell` here diff --git a/src/test/ui/issues/issue-34373.stderr b/src/test/ui/issues/issue-34373.stderr index 07ac421455cf6..f260a8477431b 100644 --- a/src/test/ui/issues/issue-34373.stderr +++ b/src/test/ui/issues/issue-34373.stderr @@ -1,7 +1,7 @@ error[E0391]: cycle detected when processing `Foo::T` --> $DIR/issue-34373.rs:7:30 | -LL | pub struct Foo>>; //~ ERROR cycle detected +LL | pub struct Foo>>; | ^^^^^^^^^^ | note: ...which requires processing `DefaultFoo`... diff --git a/src/test/ui/issues/issue-34418.rs b/src/test/ui/issues/issue-34418.rs index 6a86c277eafa6..6132f744b50a9 100644 --- a/src/test/ui/issues/issue-34418.rs +++ b/src/test/ui/issues/issue-34418.rs @@ -1,6 +1,4 @@ -// compile-pass -// skip-codegen -#![allow(unused)] +// check-pass macro_rules! make_item { () => { fn f() {} } @@ -18,5 +16,4 @@ fn g() { make_stmt! {} } - fn main() {} diff --git a/src/test/ui/issues/issue-34721.rs b/src/test/ui/issues/issue-34721.rs index 226c21446b1ed..bdc9fe43a8bd9 100644 --- a/src/test/ui/issues/issue-34721.rs +++ b/src/test/ui/issues/issue-34721.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - pub trait Foo { fn zero(self) -> Self; } diff --git a/src/test/ui/issues/issue-34721.stderr b/src/test/ui/issues/issue-34721.stderr index 2ed7b543e713c..d5cede990a335 100644 --- a/src/test/ui/issues/issue-34721.stderr +++ b/src/test/ui/issues/issue-34721.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `x` - --> $DIR/issue-34721.rs:27:9 + --> $DIR/issue-34721.rs:25:9 | LL | pub fn baz(x: T) -> T { | - - move occurs because `x` has type `T`, which does not implement the `Copy` trait diff --git a/src/test/ui/issues/issue-34839.rs b/src/test/ui/issues/issue-34839.rs index 01669f01e2ff4..8ffed827e9087 100644 --- a/src/test/ui/issues/issue-34839.rs +++ b/src/test/ui/issues/issue-34839.rs @@ -1,6 +1,4 @@ -// compile-pass -// skip-codegen -#![allow(dead_code)] +// check-pass trait RegularExpression: Sized { type Text; @@ -18,5 +16,4 @@ enum FindCapturesInner<'r, 't> { Dynamic(FindCaptures<'t, ExecNoSyncStr<'r>>), } - fn main() {} diff --git a/src/test/ui/issues/issue-35075.stderr b/src/test/ui/issues/issue-35075.stderr index 5372996d1cbbe..2aeb6b1522424 100644 --- a/src/test/ui/issues/issue-35075.stderr +++ b/src/test/ui/issues/issue-35075.stderr @@ -1,21 +1,21 @@ error[E0412]: cannot find type `Foo` in this scope --> $DIR/issue-35075.rs:2:12 | -LL | inner: Foo //~ ERROR cannot find type `Foo` in this scope +LL | inner: Foo | ^^^ not found in this scope help: there is an enum variant `Baz::Foo`; try using the variant's enum | -LL | inner: Baz //~ ERROR cannot find type `Foo` in this scope +LL | inner: Baz | ^^^ error[E0412]: cannot find type `Foo` in this scope --> $DIR/issue-35075.rs:6:9 | -LL | Foo(Foo) //~ ERROR cannot find type `Foo` in this scope +LL | Foo(Foo) | ^^^ not found in this scope help: there is an enum variant `Baz::Foo`; try using the variant's enum | -LL | Foo(Baz) //~ ERROR cannot find type `Foo` in this scope +LL | Foo(Baz) | ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-35139.rs b/src/test/ui/issues/issue-35139.rs index 1ee00fc7ec2d9..e462f35437358 100644 --- a/src/test/ui/issues/issue-35139.rs +++ b/src/test/ui/issues/issue-35139.rs @@ -7,14 +7,14 @@ pub trait MethodType { pub struct MTFn; impl<'a> MethodType for MTFn { //~ ERROR E0207 - type GetProp = fmt::Debug + 'a; + type GetProp = dyn fmt::Debug + 'a; } -fn bad(a: Box<::GetProp>) -> Box { +fn bad(a: Box<::GetProp>) -> Box { a } -fn dangling(a: &str) -> Box { +fn dangling(a: &str) -> Box { bad(Box::new(a)) } diff --git a/src/test/ui/issues/issue-35139.stderr b/src/test/ui/issues/issue-35139.stderr index 1e3d24fa514c3..79e889b7e599e 100644 --- a/src/test/ui/issues/issue-35139.stderr +++ b/src/test/ui/issues/issue-35139.stderr @@ -1,7 +1,7 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates --> $DIR/issue-35139.rs:9:6 | -LL | impl<'a> MethodType for MTFn { //~ ERROR E0207 +LL | impl<'a> MethodType for MTFn { | ^^ unconstrained lifetime parameter error: aborting due to previous error diff --git a/src/test/ui/issues/issue-35241.stderr b/src/test/ui/issues/issue-35241.stderr index 022bc7baa34cc..8fda58abadb6e 100644 --- a/src/test/ui/issues/issue-35241.stderr +++ b/src/test/ui/issues/issue-35241.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-35241.rs:3:20 | -LL | fn test() -> Foo { Foo } //~ ERROR mismatched types +LL | fn test() -> Foo { Foo } | --- ^^^ | | | | | expected struct `Foo`, found fn item diff --git a/src/test/ui/issues/issue-35450.stderr b/src/test/ui/issues/issue-35450.stderr index 7edee5c41e626..f2065689f444e 100644 --- a/src/test/ui/issues/issue-35450.stderr +++ b/src/test/ui/issues/issue-35450.stderr @@ -1,7 +1,7 @@ error: expected expression, found `$` --> $DIR/issue-35450.rs:4:8 | -LL | m!($t); //~ ERROR expected expression +LL | m!($t); | ^ expected expression error: aborting due to previous error diff --git a/src/test/ui/issues/issue-35546.rs b/src/test/ui/issues/issue-35546.rs index 19c0491e4bc29..500ba48e0b71c 100644 --- a/src/test/ui/issues/issue-35546.rs +++ b/src/test/ui/issues/issue-35546.rs @@ -6,11 +6,11 @@ // `value` field of `Node`). struct Node { - next: Option>>, + next: Option>>, value: T, } -fn clear(head: &mut Option>>) { +fn clear(head: &mut Option>>) { match head.take() { Some(node) => *head = node.next, None => (), diff --git a/src/test/ui/issues/issue-35570.rs b/src/test/ui/issues/issue-35570.rs index e809b46bcdca5..fafef79ea5b86 100644 --- a/src/test/ui/issues/issue-35570.rs +++ b/src/test/ui/issues/issue-35570.rs @@ -1,5 +1,4 @@ -// compile-pass -// skip-codegen +// check-pass use std::mem; @@ -8,7 +7,7 @@ trait Trait2<'a> { type Ty; } -fn _ice(param: Box Trait1<<() as Trait2<'a>>::Ty>>) { +fn _ice(param: Box Trait1<<() as Trait2<'a>>::Ty>>) { let _e: (usize, usize) = unsafe{mem::transmute(param)}; } @@ -25,7 +24,6 @@ fn foo<'a>(x: &'a ()) -> <() as Lifetime<'a>>::Out { fn takes_lifetime(_f: for<'a> fn(&'a ()) -> <() as Lifetime<'a>>::Out) { } - fn main() { takes_lifetime(foo); } diff --git a/src/test/ui/issues/issue-35668.stderr b/src/test/ui/issues/issue-35668.stderr index 08ce2faff10ab..59ca874bd2018 100644 --- a/src/test/ui/issues/issue-35668.stderr +++ b/src/test/ui/issues/issue-35668.stderr @@ -1,8 +1,10 @@ error[E0369]: binary operation `*` cannot be applied to type `&T` - --> $DIR/issue-35668.rs:2:22 + --> $DIR/issue-35668.rs:2:23 | LL | a.iter().map(|a| a*a) - | ^^^ + | -^- &T + | | + | &T | = note: an implementation of `std::ops::Mul` might be missing for `&T` diff --git a/src/test/ui/issues/issue-35675.stderr b/src/test/ui/issues/issue-35675.stderr index 3e4fd5593caae..28555a15afae1 100644 --- a/src/test/ui/issues/issue-35675.stderr +++ b/src/test/ui/issues/issue-35675.stderr @@ -67,5 +67,5 @@ LL | fn qux() -> Some { error: aborting due to 7 previous errors -Some errors occurred: E0412, E0425, E0573. +Some errors have detailed explanations: E0412, E0425. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/issues/issue-35976.rs b/src/test/ui/issues/issue-35976.rs index 95c0cc95bb2ba..d075794d9946f 100644 --- a/src/test/ui/issues/issue-35976.rs +++ b/src/test/ui/issues/issue-35976.rs @@ -3,14 +3,14 @@ mod private { fn wait(&self) where Self: Sized; } - impl Future for Box { + impl Future for Box { fn wait(&self) { } } } //use private::Future; -fn bar(arg: Box) { +fn bar(arg: Box) { arg.wait(); //~^ ERROR the `wait` method cannot be invoked on a trait object } diff --git a/src/test/ui/issues/issue-3601.stderr b/src/test/ui/issues/issue-3601.stderr index 0b5242ee528dd..fa0fa3345f5ee 100644 --- a/src/test/ui/issues/issue-3601.stderr +++ b/src/test/ui/issues/issue-3601.stderr @@ -1,8 +1,10 @@ error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/issue-3601.rs:30:44 | -LL | box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns +LL | box NodeKind::Element(ed) => match ed.kind { | ^^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/issues/issue-36082.ast.nll.stderr b/src/test/ui/issues/issue-36082.ast.nll.stderr deleted file mode 100644 index 6b3b13aa291d8..0000000000000 --- a/src/test/ui/issues/issue-36082.ast.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-36082.rs:11:19 - | -LL | let val: &_ = x.borrow().0; - | ^^^^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary which is freed while still in use -... -LL | println!("{}", val); - | --- borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/issues/issue-36082.ast.stderr b/src/test/ui/issues/issue-36082.ast.stderr deleted file mode 100644 index 56e50e55ed3ef..0000000000000 --- a/src/test/ui/issues/issue-36082.ast.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/issue-36082.rs:11:19 - | -LL | let val: &_ = x.borrow().0; - | ^^^^^^^^^^ - temporary value dropped here while still borrowed - | | - | temporary value does not live long enough -... -LL | } - | - temporary value needs to live until here - | - = note: consider using a `let` binding to increase its lifetime - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issues/issue-36082.mir.stderr b/src/test/ui/issues/issue-36082.mir.stderr deleted file mode 100644 index 6b3b13aa291d8..0000000000000 --- a/src/test/ui/issues/issue-36082.mir.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-36082.rs:11:19 - | -LL | let val: &_ = x.borrow().0; - | ^^^^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary which is freed while still in use -... -LL | println!("{}", val); - | --- borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/issues/issue-36082.rs b/src/test/ui/issues/issue-36082.rs index 2658ef0ddaaec..a2ff477eb816a 100644 --- a/src/test/ui/issues/issue-36082.rs +++ b/src/test/ui/issues/issue-36082.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - use std::cell::RefCell; fn main() { @@ -9,15 +6,10 @@ fn main() { let x = RefCell::new((&mut r,s)); let val: &_ = x.borrow().0; - //[ast]~^ ERROR borrowed value does not live long enough [E0597] - //[ast]~| NOTE temporary value dropped here while still borrowed - //[ast]~| NOTE temporary value does not live long enough - //[ast]~| NOTE consider using a `let` binding to increase its lifetime - //[mir]~^^^^^ ERROR temporary value dropped while borrowed [E0716] - //[mir]~| NOTE temporary value is freed at the end of this statement - //[mir]~| NOTE creates a temporary which is freed while still in use - //[mir]~| NOTE consider using a `let` binding to create a longer lived value + //~^ ERROR temporary value dropped while borrowed [E0716] + //~| NOTE temporary value is freed at the end of this statement + //~| NOTE creates a temporary which is freed while still in use + //~| NOTE consider using a `let` binding to create a longer lived value println!("{}", val); - //[mir]~^ borrow later used here + //~^ borrow later used here } -//[ast]~^ NOTE temporary value needs to live until here diff --git a/src/test/ui/issues/issue-36082.stderr b/src/test/ui/issues/issue-36082.stderr new file mode 100644 index 0000000000000..26bf4cb1be8be --- /dev/null +++ b/src/test/ui/issues/issue-36082.stderr @@ -0,0 +1,16 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-36082.rs:8:19 + | +LL | let val: &_ = x.borrow().0; + | ^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use +... +LL | println!("{}", val); + | --- borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/issues/issue-3609.rs b/src/test/ui/issues/issue-3609.rs index c76c183821e52..9bccb2a21e33c 100644 --- a/src/test/ui/issues/issue-3609.rs +++ b/src/test/ui/issues/issue-3609.rs @@ -6,7 +6,7 @@ use std::thread; use std::sync::mpsc::Sender; type RingBuffer = Vec ; -type SamplesFn = Box; +type SamplesFn = Box; enum Msg { diff --git a/src/test/ui/issues/issue-36116.rs b/src/test/ui/issues/issue-36116.rs index f4fe96cf75b55..c7c70c7afe743 100644 --- a/src/test/ui/issues/issue-36116.rs +++ b/src/test/ui/issues/issue-36116.rs @@ -1,8 +1,7 @@ // Unnecessary path disambiguator is ok -// compile-pass -// skip-codegen -#![allow(unused)] +// check-pass + macro_rules! m { ($p: path) => { let _ = $p(0); @@ -17,11 +16,10 @@ struct Foo { struct S(T); fn f() { - let f = Some(Foo { _a: 42 }).map(|a| a as Foo::); //~ WARN unnecessary path disambiguator - let g: Foo:: = Foo { _a: 42 }; //~ WARN unnecessary path disambiguator + let f = Some(Foo { _a: 42 }).map(|a| a as Foo::); + let g: Foo:: = Foo { _a: 42 }; - m!(S::); // OK, no warning + m!(S::); } - fn main() {} diff --git a/src/test/ui/issues/issue-36116.stderr b/src/test/ui/issues/issue-36116.stderr deleted file mode 100644 index e8f9a472b07b6..0000000000000 --- a/src/test/ui/issues/issue-36116.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: unnecessary path disambiguator - --> $DIR/issue-36116.rs:20:50 - | -LL | let f = Some(Foo { _a: 42 }).map(|a| a as Foo::); //~ WARN unnecessary path disambiguator - | ^^ try removing `::` - -warning: unnecessary path disambiguator - --> $DIR/issue-36116.rs:21:15 - | -LL | let g: Foo:: = Foo { _a: 42 }; //~ WARN unnecessary path disambiguator - | ^^ try removing `::` - diff --git a/src/test/ui/issues/issue-36163.stderr b/src/test/ui/issues/issue-36163.stderr index c114e58e4d943..50e8cf6e88c58 100644 --- a/src/test/ui/issues/issue-36163.stderr +++ b/src/test/ui/issues/issue-36163.stderr @@ -1,7 +1,7 @@ -error[E0391]: cycle detected when processing `Foo::B::{{constant}}` +error[E0391]: cycle detected when processing `Foo::B::{{constant}}#0` --> $DIR/issue-36163.rs:4:9 | -LL | B = A, //~ ERROR E0391 +LL | B = A, | ^ | note: ...which requires processing `A`... @@ -9,11 +9,11 @@ note: ...which requires processing `A`... | LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^ - = note: ...which again requires processing `Foo::B::{{constant}}`, completing the cycle -note: cycle used when const-evaluating `Foo::B::{{constant}}` + = note: ...which again requires processing `Foo::B::{{constant}}#0`, completing the cycle +note: cycle used when processing `Foo::B::{{constant}}#0` --> $DIR/issue-36163.rs:4:9 | -LL | B = A, //~ ERROR E0391 +LL | B = A, | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-36299.stderr b/src/test/ui/issues/issue-36299.stderr index dce4bd31ca305..edbe790a0c9f6 100644 --- a/src/test/ui/issues/issue-36299.stderr +++ b/src/test/ui/issues/issue-36299.stderr @@ -2,7 +2,7 @@ error[E0392]: parameter `'a` is never used --> $DIR/issue-36299.rs:1:12 | LL | struct Foo<'a, A> {} - | ^^ unused type parameter + | ^^ unused parameter | = help: consider removing `'a` or using a marker such as `std::marker::PhantomData` @@ -10,7 +10,7 @@ error[E0392]: parameter `A` is never used --> $DIR/issue-36299.rs:1:16 | LL | struct Foo<'a, A> {} - | ^ unused type parameter + | ^ unused parameter | = help: consider removing `A` or using a marker such as `std::marker::PhantomData` diff --git a/src/test/ui/issues/issue-36379.rs b/src/test/ui/issues/issue-36379.rs index b2da65131fb17..3a3e6f47067d9 100644 --- a/src/test/ui/issues/issue-36379.rs +++ b/src/test/ui/issues/issue-36379.rs @@ -1,7 +1,5 @@ -// compile-pass -// skip-codegen +// check-pass fn _test() -> impl Default { } - -fn main() { } +fn main() {} diff --git a/src/test/ui/issues/issue-36400.nll.stderr b/src/test/ui/issues/issue-36400.nll.stderr deleted file mode 100644 index e260fab779112..0000000000000 --- a/src/test/ui/issues/issue-36400.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable - --> $DIR/issue-36400.rs:5:7 - | -LL | let x = Box::new(3); - | - help: consider changing this to be mutable: `mut x` -LL | f(&mut *x); //~ ERROR cannot borrow immutable - | ^^^^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/issues/issue-36400.rs b/src/test/ui/issues/issue-36400.rs index 5ba9eb2333bbd..a405f9b113525 100644 --- a/src/test/ui/issues/issue-36400.rs +++ b/src/test/ui/issues/issue-36400.rs @@ -2,5 +2,5 @@ fn f(x: &mut u32) {} fn main() { let x = Box::new(3); - f(&mut *x); //~ ERROR cannot borrow immutable + f(&mut *x); //~ ERROR cannot borrow `*x` as mutable, as `x` is not declared as mutable } diff --git a/src/test/ui/issues/issue-36400.stderr b/src/test/ui/issues/issue-36400.stderr index d9394277050de..3b37578f3c455 100644 --- a/src/test/ui/issues/issue-36400.stderr +++ b/src/test/ui/issues/issue-36400.stderr @@ -1,10 +1,10 @@ -error[E0596]: cannot borrow immutable `Box` content `*x` as mutable - --> $DIR/issue-36400.rs:5:12 +error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable + --> $DIR/issue-36400.rs:5:7 | LL | let x = Box::new(3); - | - help: make this binding mutable: `mut x` -LL | f(&mut *x); //~ ERROR cannot borrow immutable - | ^^ cannot borrow as mutable + | - help: consider changing this to be mutable: `mut x` +LL | f(&mut *x); + | ^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/issues/issue-36617.stderr b/src/test/ui/issues/issue-36617.stderr index 7685b84bea7bf..296fec46d80a6 100644 --- a/src/test/ui/issues/issue-36617.stderr +++ b/src/test/ui/issues/issue-36617.stderr @@ -1,7 +1,7 @@ error: `derive` may only be applied to structs, enums and unions --> $DIR/issue-36617.rs:1:1 | -LL | #![derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions +LL | #![derive(Copy)] | ^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Copy)]` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-36638.rs b/src/test/ui/issues/issue-36638.rs index 1d006fbdee4b5..2e64853697a1b 100644 --- a/src/test/ui/issues/issue-36638.rs +++ b/src/test/ui/issues/issue-36638.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - struct Foo(Self); //~^ ERROR expected identifier, found keyword `Self` //~^^ ERROR E0392 diff --git a/src/test/ui/issues/issue-36638.stderr b/src/test/ui/issues/issue-36638.stderr index 171343090142f..f3f94198465d8 100644 --- a/src/test/ui/issues/issue-36638.stderr +++ b/src/test/ui/issues/issue-36638.stderr @@ -1,20 +1,20 @@ error: expected identifier, found keyword `Self` - --> $DIR/issue-36638.rs:3:12 + --> $DIR/issue-36638.rs:1:12 | LL | struct Foo(Self); | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/issue-36638.rs:7:11 + --> $DIR/issue-36638.rs:5:11 | LL | trait Bar {} | ^^^^ expected identifier, found keyword error[E0392]: parameter `Self` is never used - --> $DIR/issue-36638.rs:3:12 + --> $DIR/issue-36638.rs:1:12 | LL | struct Foo(Self); - | ^^^^ unused type parameter + | ^^^^ unused parameter | = help: consider removing `Self` or using a marker such as `std::marker::PhantomData` diff --git a/src/test/ui/issues/issue-36708.stderr b/src/test/ui/issues/issue-36708.stderr index 835094c4fdc5e..140f19f1ff774 100644 --- a/src/test/ui/issues/issue-36708.stderr +++ b/src/test/ui/issues/issue-36708.stderr @@ -1,8 +1,8 @@ error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/issue-36708.rs:8:11 + --> $DIR/issue-36708.rs:8:12 | LL | fn foo() {} - | ^^^ found 1 type parameter, expected 0 + | ^ found 1 type parameter, expected 0 error: aborting due to previous error diff --git a/src/test/ui/issues/issue-36839.rs b/src/test/ui/issues/issue-36839.rs index 0944d07896e57..ca3d66b1c8eb7 100644 --- a/src/test/ui/issues/issue-36839.rs +++ b/src/test/ui/issues/issue-36839.rs @@ -1,5 +1,4 @@ -// compile-pass -// skip-codegen +// check-pass pub trait Foo { type Bar; @@ -17,7 +16,6 @@ impl Broken for T { } } - fn main() { - let _m: &Broken = &(); + let _m: &dyn Broken = &(); } diff --git a/src/test/ui/issues/issue-36881.stderr b/src/test/ui/issues/issue-36881.stderr index b08b229384d08..2ec636fde60bf 100644 --- a/src/test/ui/issues/issue-36881.stderr +++ b/src/test/ui/issues/issue-36881.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `issue_36881_aux` --> $DIR/issue-36881.rs:6:9 | -LL | use issue_36881_aux::Foo; //~ ERROR unresolved import +LL | use issue_36881_aux::Foo; | ^^^^^^^^^^^^^^^ maybe a missing `extern crate issue_36881_aux;`? error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3702-2.rs b/src/test/ui/issues/issue-3702-2.rs index c3a92a23cef50..d47f6d248f708 100644 --- a/src/test/ui/issues/issue-3702-2.rs +++ b/src/test/ui/issues/issue-3702-2.rs @@ -7,12 +7,12 @@ impl ToPrimitive for isize {} trait Add { fn to_int(&self) -> isize; - fn add_dynamic(&self, other: &Add) -> isize; + fn add_dynamic(&self, other: &dyn Add) -> isize; } impl Add for isize { fn to_int(&self) -> isize { *self } - fn add_dynamic(&self, other: &Add) -> isize { + fn add_dynamic(&self, other: &dyn Add) -> isize { self.to_int() + other.to_int() //~ ERROR multiple applicable items in scope } } diff --git a/src/test/ui/issues/issue-3702-2.stderr b/src/test/ui/issues/issue-3702-2.stderr index 11d24b38061e8..347a19b687fbb 100644 --- a/src/test/ui/issues/issue-3702-2.stderr +++ b/src/test/ui/issues/issue-3702-2.stderr @@ -1,7 +1,7 @@ error[E0034]: multiple applicable items in scope --> $DIR/issue-3702-2.rs:16:14 | -LL | self.to_int() + other.to_int() //~ ERROR multiple applicable items in scope +LL | self.to_int() + other.to_int() | ^^^^^^ multiple `to_int` found | note: candidate #1 is defined in an impl of the trait `ToPrimitive` for the type `isize` diff --git a/src/test/ui/issues/issue-37026.stderr b/src/test/ui/issues/issue-37026.stderr index 39a500cf5653b..1f81264ffdb49 100644 --- a/src/test/ui/issues/issue-37026.stderr +++ b/src/test/ui/issues/issue-37026.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-37026.rs:6:9 | -LL | let empty_struct::XEmpty2 = (); //~ ERROR mismatched types +LL | let empty_struct::XEmpty2 = (); | ^^^^^^^^^^^^^^^^^^^^^ expected (), found struct `empty_struct::XEmpty2` | = note: expected type `()` @@ -10,7 +10,7 @@ LL | let empty_struct::XEmpty2 = (); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/issue-37026.rs:7:9 | -LL | let empty_struct::XEmpty6(..) = (); //~ ERROR mismatched types +LL | let empty_struct::XEmpty6(..) = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found struct `empty_struct::XEmpty6` | = note: expected type `()` diff --git a/src/test/ui/issues/issue-37051.rs b/src/test/ui/issues/issue-37051.rs index 1ccf5b9780190..9cae6cf5e7665 100644 --- a/src/test/ui/issues/issue-37051.rs +++ b/src/test/ui/issues/issue-37051.rs @@ -1,7 +1,7 @@ -// compile-pass -// skip-codegen +// check-pass + #![feature(associated_type_defaults)] -#![allow(warnings)] + trait State: Sized { type NextState: State = StateMachineEnded; fn execute(self) -> Option; @@ -15,6 +15,4 @@ impl State for StateMachineEnded { } } - -fn main() { -} +fn main() {} diff --git a/src/test/ui/issues/issue-3707.stderr b/src/test/ui/issues/issue-3707.stderr index 436dcbee862a7..05c8ce4c3f11e 100644 --- a/src/test/ui/issues/issue-3707.stderr +++ b/src/test/ui/issues/issue-3707.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `boom` found for type `&Obj` in the current scope --> $DIR/issue-3707.rs:10:14 | -LL | self.boom(); //~ ERROR no method named `boom` found for type `&Obj` in the current scope +LL | self.boom(); | -----^^^^ | | | | | this is an associated function, not a method diff --git a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr index fa1ee227f0bf2..aead415d23f84 100644 --- a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr +++ b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr @@ -1,12 +1,12 @@ -error: reached the type-length limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(), &()), &(&()...` +error: reached the type-length limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(...))))))))))))))) as Foo>::recurse` --> $DIR/issue-37311.rs:13:5 | -LL | / fn recurse(&self) { //~ ERROR reached the type-length limit +LL | / fn recurse(&self) { LL | | (self, self).recurse(); LL | | } | |_____^ | - = note: consider adding a `#![type_length_limit="2097152"]` attribute to your crate + = note: consider adding a `#![type_length_limit="2097149"]` attribute to your crate error: aborting due to previous error diff --git a/src/test/ui/issues/issue-37366.rs b/src/test/ui/issues/issue-37366.rs index 1c27960e9afb2..6bf3a276ce138 100644 --- a/src/test/ui/issues/issue-37366.rs +++ b/src/test/ui/issues/issue-37366.rs @@ -1,6 +1,6 @@ +// check-pass // ignore-emscripten -// compile-pass -// skip-codegen + #![feature(asm)] macro_rules! interrupt_handler { @@ -12,6 +12,4 @@ macro_rules! interrupt_handler { } interrupt_handler!{} - -fn main() { -} +fn main() {} diff --git a/src/test/ui/issues/issue-37510.rs b/src/test/ui/issues/issue-37510.rs index 465e680995704..2081c9f7e26ec 100644 --- a/src/test/ui/issues/issue-37510.rs +++ b/src/test/ui/issues/issue-37510.rs @@ -1,9 +1,7 @@ -// compile-pass -// skip-codegen +// check-pass fn foo(_: &mut i32) -> bool { true } - fn main() { let opt = Some(92); let mut x = 62; diff --git a/src/test/ui/issues/issue-37515.rs b/src/test/ui/issues/issue-37515.rs index 090b9bbf1ec49..caff507c91833 100644 --- a/src/test/ui/issues/issue-37515.rs +++ b/src/test/ui/issues/issue-37515.rs @@ -1,10 +1,8 @@ -// skip-codegen -// compile-pass +// check-pass + #![warn(unused)] -type Z = for<'x> Send; +type Z = dyn for<'x> Send; //~^ WARN type alias is never used - -fn main() { -} +fn main() {} diff --git a/src/test/ui/issues/issue-37515.stderr b/src/test/ui/issues/issue-37515.stderr index 1b4965594848b..1476d17cdc642 100644 --- a/src/test/ui/issues/issue-37515.stderr +++ b/src/test/ui/issues/issue-37515.stderr @@ -1,8 +1,8 @@ warning: type alias is never used: `Z` --> $DIR/issue-37515.rs:5:1 | -LL | type Z = for<'x> Send; - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | type Z = dyn for<'x> Send; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here --> $DIR/issue-37515.rs:3:9 diff --git a/src/test/ui/issues/issue-37534.stderr b/src/test/ui/issues/issue-37534.stderr index fe143540b735f..741e93561bc54 100644 --- a/src/test/ui/issues/issue-37534.stderr +++ b/src/test/ui/issues/issue-37534.stderr @@ -18,11 +18,11 @@ error[E0392]: parameter `T` is never used --> $DIR/issue-37534.rs:1:12 | LL | struct Foo { } - | ^ unused type parameter + | ^ unused parameter | = help: consider removing `T` or using a marker such as `std::marker::PhantomData` error: aborting due to 2 previous errors -Some errors occurred: E0392, E0405. +Some errors have detailed explanations: E0392, E0405. For more information about an error, try `rustc --explain E0392`. diff --git a/src/test/ui/issues/issue-37550.stderr b/src/test/ui/issues/issue-37550.stderr index 97160af43bee4..609043942b7d9 100644 --- a/src/test/ui/issues/issue-37550.stderr +++ b/src/test/ui/issues/issue-37550.stderr @@ -1,9 +1,10 @@ -error[E0723]: function pointers in const fn are unstable (see issue #57563) +error[E0723]: function pointers in const fn are unstable --> $DIR/issue-37550.rs:3:9 | -LL | let x = || t; //~ ERROR function pointers in const fn are unstable +LL | let x = || t; | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3763.stderr b/src/test/ui/issues/issue-3763.stderr index f37b923d5dcfb..50169286b1ceb 100644 --- a/src/test/ui/issues/issue-3763.stderr +++ b/src/test/ui/issues/issue-3763.stderr @@ -13,13 +13,13 @@ LL | let _woohoo = (Box::new(my_struct)).priv_field; error[E0624]: method `happyfun` is private --> $DIR/issue-3763.rs:21:18 | -LL | (&my_struct).happyfun(); //~ ERROR method `happyfun` is private +LL | (&my_struct).happyfun(); | ^^^^^^^^ error[E0624]: method `happyfun` is private --> $DIR/issue-3763.rs:23:27 | -LL | (Box::new(my_struct)).happyfun(); //~ ERROR method `happyfun` is private +LL | (Box::new(my_struct)).happyfun(); | ^^^^^^^^ error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private @@ -30,5 +30,5 @@ LL | let nope = my_struct.priv_field; error: aborting due to 5 previous errors -Some errors occurred: E0616, E0624. +Some errors have detailed explanations: E0616, E0624. For more information about an error, try `rustc --explain E0616`. diff --git a/src/test/ui/issues/issue-37665.stderr b/src/test/ui/issues/issue-37665.stderr index c3599fab68507..c27494699515b 100644 --- a/src/test/ui/issues/issue-37665.stderr +++ b/src/test/ui/issues/issue-37665.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-37665.rs:10:17 | -LL | let x: () = 0; //~ ERROR: mismatched types +LL | let x: () = 0; | ^ expected (), found integer | = note: expected type `()` diff --git a/src/test/ui/issues/issue-3779.stderr b/src/test/ui/issues/issue-3779.stderr index 3538cb199c3e0..ba1e842c610ba 100644 --- a/src/test/ui/issues/issue-3779.stderr +++ b/src/test/ui/issues/issue-3779.stderr @@ -3,7 +3,7 @@ error[E0072]: recursive type `S` has infinite size | LL | struct S { | ^^^^^^^^ recursive type has infinite size -LL | //~^ ERROR E0072 +LL | LL | element: Option | ------------------ recursive without indirection | diff --git a/src/test/ui/issues/issue-37884.stderr b/src/test/ui/issues/issue-37884.stderr index f791c6df72f2e..9a5f659da1604 100644 --- a/src/test/ui/issues/issue-37884.stderr +++ b/src/test/ui/issues/issue-37884.stderr @@ -2,8 +2,8 @@ error[E0308]: method not compatible with trait --> $DIR/issue-37884.rs:6:5 | LL | / fn next(&'a mut self) -> Option -LL | | //~^ ERROR method not compatible with trait -LL | | //~| lifetime mismatch +LL | | +LL | | LL | | { LL | | Some(&mut self.0) LL | | } @@ -15,8 +15,8 @@ note: the anonymous lifetime #1 defined on the method body at 6:5... --> $DIR/issue-37884.rs:6:5 | LL | / fn next(&'a mut self) -> Option -LL | | //~^ ERROR method not compatible with trait -LL | | //~| lifetime mismatch +LL | | +LL | | LL | | { LL | | Some(&mut self.0) LL | | } diff --git a/src/test/ui/issues/issue-37887.stderr b/src/test/ui/issues/issue-37887.stderr index 3b3ce8b39bc94..81ec3a5956bc6 100644 --- a/src/test/ui/issues/issue-37887.stderr +++ b/src/test/ui/issues/issue-37887.stderr @@ -1,18 +1,19 @@ error[E0432]: unresolved import `libc` --> $DIR/issue-37887.rs:3:9 | -LL | use libc::*; //~ ERROR unresolved import +LL | use libc::*; | ^^^^ maybe a missing `extern crate libc;`? -error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? (see issue #27812) +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? --> $DIR/issue-37887.rs:2:5 | -LL | extern crate libc; //~ ERROR use of unstable +LL | extern crate libc; | ^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27812 = help: add #![feature(rustc_private)] to the crate attributes to enable error: aborting due to 2 previous errors -Some errors occurred: E0432, E0658. +Some errors have detailed explanations: E0432, E0658. For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/issues/issue-38160.rs b/src/test/ui/issues/issue-38160.rs index a454211c4df87..0da8b7900a8a5 100644 --- a/src/test/ui/issues/issue-38160.rs +++ b/src/test/ui/issues/issue-38160.rs @@ -1,7 +1,5 @@ -// compile-pass -// skip-codegen -#![feature(associated_consts)] -#![allow(warnings)] +// check-pass + trait MyTrait { const MY_CONST: &'static str; } @@ -18,5 +16,4 @@ macro_rules! my_macro { my_macro!(); - fn main() {} diff --git a/src/test/ui/issues/issue-3820.stderr b/src/test/ui/issues/issue-3820.stderr index 0a36ac7616bb3..35eceb3b3c637 100644 --- a/src/test/ui/issues/issue-3820.stderr +++ b/src/test/ui/issues/issue-3820.stderr @@ -1,8 +1,10 @@ error[E0369]: binary operation `*` cannot be applied to type `Thing` - --> $DIR/issue-3820.rs:14:13 + --> $DIR/issue-3820.rs:14:15 | -LL | let w = u * 3; //~ ERROR binary operation `*` cannot be applied to type `Thing` - | ^^^^^ +LL | let w = u * 3; + | - ^ - {integer} + | | + | Thing | = note: an implementation of `std::ops::Mul` might be missing for `Thing` diff --git a/src/test/ui/issues/issue-38293.stderr b/src/test/ui/issues/issue-38293.stderr index 409670074d9f3..d16d45277c038 100644 --- a/src/test/ui/issues/issue-38293.stderr +++ b/src/test/ui/issues/issue-38293.stderr @@ -1,13 +1,13 @@ error[E0432]: unresolved import `foo::f` --> $DIR/issue-38293.rs:6:14 | -LL | use foo::f::{self}; //~ ERROR unresolved import `foo::f` +LL | use foo::f::{self}; | ^^^^ no `f` in `foo` error[E0423]: expected function, found module `baz` --> $DIR/issue-38293.rs:15:5 | -LL | baz(); //~ ERROR expected function, found module `baz` +LL | baz(); | ^^^ not a function help: possible better candidate is found in another module, you can import it into scope | @@ -16,5 +16,5 @@ LL | use bar::baz; error: aborting due to 2 previous errors -Some errors occurred: E0423, E0432. +Some errors have detailed explanations: E0423, E0432. For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/issues/issue-38381.rs b/src/test/ui/issues/issue-38381.rs index 135137690e577..82d4a4e325ac0 100644 --- a/src/test/ui/issues/issue-38381.rs +++ b/src/test/ui/issues/issue-38381.rs @@ -1,9 +1,7 @@ -// compile-pass -// skip-codegen +// check-pass use std::ops::Deref; - fn main() { let _x: fn(&i32) -> <&i32 as Deref>::Target = unimplemented!(); } diff --git a/src/test/ui/issues/issue-38404.rs b/src/test/ui/issues/issue-38404.rs index cddd75e267c42..1a92acc34042b 100644 --- a/src/test/ui/issues/issue-38404.rs +++ b/src/test/ui/issues/issue-38404.rs @@ -1,6 +1,6 @@ trait A: std::ops::Add + Sized {} trait B: A {} -trait C: A> {} +trait C: A> {} //~^ ERROR the trait `B` cannot be made into an object fn main() {} diff --git a/src/test/ui/issues/issue-38404.stderr b/src/test/ui/issues/issue-38404.stderr index 06bcf220f1836..d18a26b3a7638 100644 --- a/src/test/ui/issues/issue-38404.stderr +++ b/src/test/ui/issues/issue-38404.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `B` cannot be made into an object --> $DIR/issue-38404.rs:3:15 | -LL | trait C: A> {} - | ^^^^^^^^^^^^^^^^^^ the trait `B` cannot be made into an object +LL | trait C: A> {} + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `B` cannot be made into an object | = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses diff --git a/src/test/ui/issues/issue-38458.stderr b/src/test/ui/issues/issue-38458.stderr index 541a36233ca26..c04a01118a441 100644 --- a/src/test/ui/issues/issue-38458.stderr +++ b/src/test/ui/issues/issue-38458.stderr @@ -1,7 +1,7 @@ error[E0572]: return statement outside of function body --> $DIR/issue-38458.rs:2:5 | -LL | return; //~ ERROR return statement outside of function body +LL | return; | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-38591.rs b/src/test/ui/issues/issue-38591.rs new file mode 100644 index 0000000000000..7aa71f8b9eb9b --- /dev/null +++ b/src/test/ui/issues/issue-38591.rs @@ -0,0 +1,10 @@ +// run-pass + +struct S { + t : T, + s : Box> +} + +fn f(x : S) {} + +fn main () {} diff --git a/src/test/ui/issues/issue-38604.rs b/src/test/ui/issues/issue-38604.rs index c172595a245cd..002a3c43fcba6 100644 --- a/src/test/ui/issues/issue-38604.rs +++ b/src/test/ui/issues/issue-38604.rs @@ -11,6 +11,6 @@ impl Foo for () { } fn main() { - let _f: Box = //~ ERROR `Foo` cannot be made into an object + let _f: Box = //~ ERROR `Foo` cannot be made into an object Box::new(()); //~ ERROR `Foo` cannot be made into an object } diff --git a/src/test/ui/issues/issue-38604.stderr b/src/test/ui/issues/issue-38604.stderr index 30b4d2b53ff30..8ef7d346cb331 100644 --- a/src/test/ui/issues/issue-38604.stderr +++ b/src/test/ui/issues/issue-38604.stderr @@ -1,15 +1,15 @@ error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/issue-38604.rs:14:13 | -LL | let _f: Box = //~ ERROR `Foo` cannot be made into an object - | ^^^^^^^^ the trait `Foo` cannot be made into an object +LL | let _f: Box = + | ^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/issue-38604.rs:15:9 | -LL | Box::new(()); //~ ERROR `Foo` cannot be made into an object +LL | Box::new(()); | ^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses diff --git a/src/test/ui/issues/issue-38715.stderr b/src/test/ui/issues/issue-38715.stderr index 21d96d36e2741..34e08bfc93aaf 100644 --- a/src/test/ui/issues/issue-38715.stderr +++ b/src/test/ui/issues/issue-38715.stderr @@ -1,7 +1,7 @@ error: a macro named `foo` has already been exported --> $DIR/issue-38715.rs:5:1 | -LL | macro_rules! foo { () => {} } //~ ERROR a macro named `foo` has already been exported +LL | macro_rules! foo { () => {} } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `foo` already exported | = note: #[deny(duplicate_macro_exports)] on by default diff --git a/src/test/ui/issues/issue-38857.stderr b/src/test/ui/issues/issue-38857.stderr index 9385dc56af9db..5762e3d6ac00a 100644 --- a/src/test/ui/issues/issue-38857.stderr +++ b/src/test/ui/issues/issue-38857.stderr @@ -12,5 +12,5 @@ LL | let a = std::sys::imp::process::process_common::StdioPipes { ..panic!() error: aborting due to 2 previous errors -Some errors occurred: E0433, E0603. +Some errors have detailed explanations: E0433, E0603. For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/ui/issues/issue-38868.stderr b/src/test/ui/issues/issue-38868.stderr index ae975ca78c11b..fe932c744bf78 100644 --- a/src/test/ui/issues/issue-38868.stderr +++ b/src/test/ui/issues/issue-38868.stderr @@ -1,7 +1,7 @@ error[E0366]: Implementations of Drop cannot be specialized --> $DIR/issue-38868.rs:5:1 | -LL | / impl Drop for List { //~ ERROR E0366 +LL | / impl Drop for List { LL | | fn drop(&mut self) { LL | | panic!() LL | | } diff --git a/src/test/ui/issues/issue-38919.stderr b/src/test/ui/issues/issue-38919.stderr index 8c09436479564..603d42ca35e0b 100644 --- a/src/test/ui/issues/issue-38919.stderr +++ b/src/test/ui/issues/issue-38919.stderr @@ -1,10 +1,8 @@ error[E0599]: no associated item named `Item` found for type `T` in the current scope --> $DIR/issue-38919.rs:2:8 | -LL | T::Item; //~ ERROR no associated item named `Item` found for type `T` in the current scope - | ---^^^^ - | | - | associated item not found in `T` +LL | T::Item; + | ^^^^ associated item not found in `T` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-38940.stderr b/src/test/ui/issues/issue-38940.stderr index d94a7101c0a38..4851c01a347b6 100644 --- a/src/test/ui/issues/issue-38940.stderr +++ b/src/test/ui/issues/issue-38940.stderr @@ -17,5 +17,5 @@ LL | let x: &Bottom = &t; error: aborting due to 2 previous errors -Some errors occurred: E0055, E0308. +Some errors have detailed explanations: E0055, E0308. For more information about an error, try `rustc --explain E0055`. diff --git a/src/test/ui/issues/issue-39175.rs b/src/test/ui/issues/issue-39175.rs index 25225ca6e7c3a..3ba2a9d40bec4 100644 --- a/src/test/ui/issues/issue-39175.rs +++ b/src/test/ui/issues/issue-39175.rs @@ -6,6 +6,7 @@ // ignore-windows // ignore-cloudabi // ignore-emscripten +// ignore-sgx no processes use std::process::Command; // use std::os::unix::process::CommandExt; diff --git a/src/test/ui/issues/issue-39175.stderr b/src/test/ui/issues/issue-39175.stderr index 6aee474fe7435..108c969cdadde 100644 --- a/src/test/ui/issues/issue-39175.stderr +++ b/src/test/ui/issues/issue-39175.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `exec` found for type `&mut std::process::Command` in the current scope - --> $DIR/issue-39175.rs:14:39 + --> $DIR/issue-39175.rs:15:39 | LL | Command::new("echo").arg("hello").exec(); | ^^^^ diff --git a/src/test/ui/issues/issue-39211.stderr b/src/test/ui/issues/issue-39211.stderr index b9134445455af..ea850ea57d5b6 100644 --- a/src/test/ui/issues/issue-39211.stderr +++ b/src/test/ui/issues/issue-39211.stderr @@ -1,7 +1,7 @@ error[E0220]: associated type `Row` not found for `M` --> $DIR/issue-39211.rs:11:17 | -LL | let a = [3; M::Row::DIM]; //~ ERROR associated type `Row` not found for `M` +LL | let a = [3; M::Row::DIM]; | ^^^^^^^^^^^ associated type `Row` not found error: aborting due to previous error diff --git a/src/test/ui/issues/issue-39362.stderr b/src/test/ui/issues/issue-39362.stderr index 06385127e94fe..55cd14a5c1e08 100644 --- a/src/test/ui/issues/issue-39362.stderr +++ b/src/test/ui/issues/issue-39362.stderr @@ -1,8 +1,15 @@ error[E0004]: non-exhaustive patterns: `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered --> $DIR/issue-39362.rs:10:11 | -LL | match f { - | ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered +LL | / enum Foo { +LL | | Bar { bar: Bar, id: usize } +LL | | } + | |_- `Foo` defined here +... +LL | match f { + | ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/issues/issue-39388.rs b/src/test/ui/issues/issue-39388.rs index e5b1cd93614bb..a8e31a648c9ed 100644 --- a/src/test/ui/issues/issue-39388.rs +++ b/src/test/ui/issues/issue-39388.rs @@ -1,7 +1,7 @@ #![allow(unused_macros)] macro_rules! assign { - (($($a:tt)*) = ($($b:tt))*) => { //~ ERROR expected `*` or `+` + (($($a:tt)*) = ($($b:tt))*) => { //~ ERROR expected one of: `*`, `+`, or `?` $($a)* = $($b)* } } diff --git a/src/test/ui/issues/issue-39388.stderr b/src/test/ui/issues/issue-39388.stderr index 00d6598aeaf2a..62e7dff547692 100644 --- a/src/test/ui/issues/issue-39388.stderr +++ b/src/test/ui/issues/issue-39388.stderr @@ -1,7 +1,7 @@ -error: expected `*` or `+` +error: expected one of: `*`, `+`, or `?` --> $DIR/issue-39388.rs:4:22 | -LL | (($($a:tt)*) = ($($b:tt))*) => { //~ ERROR expected `*` or `+` +LL | (($($a:tt)*) = ($($b:tt))*) => { | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-39559-2.stderr b/src/test/ui/issues/issue-39559-2.stderr index 700dbe3647497..586debbbe5353 100644 --- a/src/test/ui/issues/issue-39559-2.stderr +++ b/src/test/ui/issues/issue-39559-2.stderr @@ -24,5 +24,5 @@ LL | = [0; Dim3::dim()]; error: aborting due to 4 previous errors -Some errors occurred: E0015, E0080. +Some errors have detailed explanations: E0015, E0080. For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/issues/issue-39559.stderr b/src/test/ui/issues/issue-39559.stderr index e851e79faee06..aded0c2de45e4 100644 --- a/src/test/ui/issues/issue-39559.stderr +++ b/src/test/ui/issues/issue-39559.stderr @@ -2,9 +2,7 @@ error[E0599]: no function or associated item named `dim` found for type `D` in t --> $DIR/issue-39559.rs:14:21 | LL | entries: [T; D::dim()], - | ---^^^ - | | - | function or associated item not found in `D` + | ^^^ function or associated item not found in `D` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `dim`, perhaps you need to implement it: diff --git a/src/test/ui/issues/issue-39616.stderr b/src/test/ui/issues/issue-39616.stderr index 082c3a6853a14..e24ffcdb0d990 100644 --- a/src/test/ui/issues/issue-39616.stderr +++ b/src/test/ui/issues/issue-39616.stderr @@ -1,13 +1,13 @@ error: expected type, found `0` --> $DIR/issue-39616.rs:1:12 | -LL | fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0` +LL | fn foo(a: [0; 1]) {} | ^ error: expected one of `)`, `,`, `->`, `where`, or `{`, found `]` --> $DIR/issue-39616.rs:1:16 | -LL | fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0` +LL | fn foo(a: [0; 1]) {} | ^ expected one of `)`, `,`, `->`, `where`, or `{` here error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-3973.stderr b/src/test/ui/issues/issue-3973.stderr index 8e46d88018112..ee07a410a9c86 100644 --- a/src/test/ui/issues/issue-3973.stderr +++ b/src/test/ui/issues/issue-3973.stderr @@ -2,7 +2,7 @@ error[E0407]: method `new` is not a member of trait `ToString_` --> $DIR/issue-3973.rs:11:5 | LL | / fn new(x: f64, y: f64) -> Point { -LL | | //~^ ERROR method `new` is not a member of trait `ToString_` +LL | | LL | | Point { x: x, y: y } LL | | } | |_____^ not a member of trait `ToString_` @@ -14,11 +14,9 @@ LL | struct Point { | ------------ function or associated item `new` not found for this ... LL | let p = Point::new(0.0, 0.0); - | -------^^^ - | | - | function or associated item not found in `Point` + | ^^^ function or associated item not found in `Point` error: aborting due to 2 previous errors -Some errors occurred: E0407, E0599. +Some errors have detailed explanations: E0407, E0599. For more information about an error, try `rustc --explain E0407`. diff --git a/src/test/ui/issues/issue-3993.stderr b/src/test/ui/issues/issue-3993.stderr index 090bca3a759cf..ce594a3f9bb27 100644 --- a/src/test/ui/issues/issue-3993.stderr +++ b/src/test/ui/issues/issue-3993.stderr @@ -1,7 +1,7 @@ error[E0603]: function `fly` is private --> $DIR/issue-3993.rs:1:10 | -LL | use zoo::fly; //~ ERROR: function `fly` is private +LL | use zoo::fly; | ^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40000.rs b/src/test/ui/issues/issue-40000.rs index 320992c0764cf..9d5ef481afc37 100644 --- a/src/test/ui/issues/issue-40000.rs +++ b/src/test/ui/issues/issue-40000.rs @@ -1,7 +1,7 @@ fn main() { let bar: fn(&mut u32) = |_| {}; - fn foo(x: Box) {} - let bar = Box::new(|x: &i32| {}) as Box; + fn foo(x: Box) {} + let bar = Box::new(|x: &i32| {}) as Box; foo(bar); //~ ERROR E0308 } diff --git a/src/test/ui/issues/issue-40000.stderr b/src/test/ui/issues/issue-40000.stderr index ce0c44c147563..c48fb24ea17dc 100644 --- a/src/test/ui/issues/issue-40000.stderr +++ b/src/test/ui/issues/issue-40000.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-40000.rs:6:9 | -LL | foo(bar); //~ ERROR E0308 +LL | foo(bar); | ^^^ expected concrete lifetime, found bound lifetime parameter | = note: expected type `std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r i32) + 'static)>` diff --git a/src/test/ui/issues/issue-40288.nll.stderr b/src/test/ui/issues/issue-40288.nll.stderr deleted file mode 100644 index bb4110948d54f..0000000000000 --- a/src/test/ui/issues/issue-40288.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0506]: cannot assign to `*refr` because it is borrowed - --> $DIR/issue-40288.rs:16:5 - | -LL | save_ref(&*refr, &mut out); - | ------ borrow of `*refr` occurs here -... -LL | *refr = 3; //~ ERROR cannot assign to `*refr` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `*refr` occurs here -... -LL | println!("{:?}", out[0]); - | ------ borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/issues/issue-40288.stderr b/src/test/ui/issues/issue-40288.stderr index 2ac5964f5da7f..fb4ecab362db1 100644 --- a/src/test/ui/issues/issue-40288.stderr +++ b/src/test/ui/issues/issue-40288.stderr @@ -2,10 +2,13 @@ error[E0506]: cannot assign to `*refr` because it is borrowed --> $DIR/issue-40288.rs:16:5 | LL | save_ref(&*refr, &mut out); - | ----- borrow of `*refr` occurs here + | ------ borrow of `*refr` occurs here ... -LL | *refr = 3; //~ ERROR cannot assign to `*refr` because it is borrowed +LL | *refr = 3; | ^^^^^^^^^ assignment to borrowed `*refr` occurs here +... +LL | println!("{:?}", out[0]); + | ------ borrow later used here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40350.rs b/src/test/ui/issues/issue-40350.rs index b2cc0047bb885..a39a8519aa986 100644 --- a/src/test/ui/issues/issue-40350.rs +++ b/src/test/ui/issues/issue-40350.rs @@ -1,6 +1,4 @@ -// compile-pass -// skip-codegen -#![allow(warnings)] +// check-pass enum E { A = { @@ -9,5 +7,4 @@ enum E { } } - fn main() {} diff --git a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.nll.stderr b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.nll.stderr deleted file mode 100644 index a4847568ba0cb..0000000000000 --- a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/issue-40402-1.rs:9:13 - | -LL | let e = f.v[0]; //~ ERROR cannot move out of indexed content - | ^^^^^^ - | | - | cannot move out of borrowed content - | help: consider borrowing here: `&f.v[0]` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.rs b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.rs index 6bb0b6f1cfb04..254956ae30692 100644 --- a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.rs +++ b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.rs @@ -6,5 +6,5 @@ struct Foo { fn main() { let mut f = Foo { v: Vec::new() }; f.v.push("hello".to_string()); - let e = f.v[0]; //~ ERROR cannot move out of indexed content + let e = f.v[0]; //~ ERROR cannot move out of index } diff --git a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr index 87b98bbcedb6a..8a9d9aab81a6a 100644 --- a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr +++ b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr @@ -1,11 +1,11 @@ -error[E0507]: cannot move out of indexed content +error[E0507]: cannot move out of index of `std::vec::Vec` --> $DIR/issue-40402-1.rs:9:13 | -LL | let e = f.v[0]; //~ ERROR cannot move out of indexed content +LL | let e = f.v[0]; | ^^^^^^ | | - | cannot move out of indexed content - | help: consider using a reference instead: `&f.v[0]` + | move occurs because value has type `std::string::String`, which does not implement the `Copy` trait + | help: consider borrowing here: `&f.v[0]` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.nll.stderr b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.nll.stderr deleted file mode 100644 index 5c23021ee2c87..0000000000000 --- a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.nll.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/issue-40402-2.rs:5:18 - | -LL | let (a, b) = x[0]; //~ ERROR cannot move out of indexed content - | - - ^^^^ - | | | | - | | | cannot move out of borrowed content - | | | help: consider borrowing here: `&x[0]` - | | ...and here - | data moved here - | -note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/issue-40402-2.rs:5:10 - | -LL | let (a, b) = x[0]; //~ ERROR cannot move out of indexed content - | ^ ^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.rs b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.rs index 0b8f40c5eff7f..1fb6e31e964ee 100644 --- a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.rs +++ b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.rs @@ -2,5 +2,5 @@ // are nested within a pattern fn main() { let x = vec![(String::new(), String::new())]; - let (a, b) = x[0]; //~ ERROR cannot move out of indexed content + let (a, b) = x[0]; //~ ERROR cannot move out of index } diff --git a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.stderr b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.stderr index d64cd96e959ff..e547ec7e4754c 100644 --- a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.stderr +++ b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.stderr @@ -1,11 +1,17 @@ -error[E0507]: cannot move out of indexed content +error[E0507]: cannot move out of index of `std::vec::Vec<(std::string::String, std::string::String)>` --> $DIR/issue-40402-2.rs:5:18 | -LL | let (a, b) = x[0]; //~ ERROR cannot move out of indexed content - | - - ^^^^ cannot move out of indexed content +LL | let (a, b) = x[0]; + | - - ^^^^ help: consider borrowing here: `&x[0]` | | | - | | ...and here (use `ref b` or `ref mut b`) - | hint: to prevent move, use `ref a` or `ref mut a` + | | ...and here + | data moved here + | +note: move occurs because these variables have types that don't implement the `Copy` trait + --> $DIR/issue-40402-2.rs:5:10 + | +LL | let (a, b) = x[0]; + | ^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40510-1.migrate.nll.stderr b/src/test/ui/issues/issue-40510-1.migrate.nll.stderr new file mode 100644 index 0000000000000..776a724d3106a --- /dev/null +++ b/src/test/ui/issues/issue-40510-1.migrate.nll.stderr @@ -0,0 +1,13 @@ +error: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-40510-1.rs:11:9 + | +LL | || { + | - inferred to be a `FnMut` closure +LL | &mut x + | ^^^^^^ returns a reference to a captured variable which escapes the closure body + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-40510-1.migrate.stderr b/src/test/ui/issues/issue-40510-1.migrate.stderr new file mode 100644 index 0000000000000..28aaa2a797e05 --- /dev/null +++ b/src/test/ui/issues/issue-40510-1.migrate.stderr @@ -0,0 +1,22 @@ +warning: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-40510-1.rs:11:9 + | +LL | || { + | - inferred to be a `FnMut` closure +LL | &mut x + | ^^^^^^ returns a reference to a captured variable which escapes the closure body + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + +error: compilation successful + --> $DIR/issue-40510-1.rs:20:1 + | +LL | fn main() {} + | ^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-40510-1.nll.stderr b/src/test/ui/issues/issue-40510-1.nll.stderr index 44234cbc8816e..776a724d3106a 100644 --- a/src/test/ui/issues/issue-40510-1.nll.stderr +++ b/src/test/ui/issues/issue-40510-1.nll.stderr @@ -1,5 +1,5 @@ -warning: captured variable cannot escape `FnMut` closure body - --> $DIR/issue-40510-1.rs:8:9 +error: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-40510-1.rs:11:9 | LL | || { | - inferred to be a `FnMut` closure @@ -8,6 +8,6 @@ LL | &mut x | = note: `FnMut` closures only have access to their captured variables while they are executing... = note: ...therefore, they cannot allow references to captured variables to escape - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + +error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40510-1.rs b/src/test/ui/issues/issue-40510-1.rs index dd8a6bc5ab2bd..6ecbeefd88115 100644 --- a/src/test/ui/issues/issue-40510-1.rs +++ b/src/test/ui/issues/issue-40510-1.rs @@ -1,13 +1,21 @@ -// compile-pass +#![feature(rustc_attrs)] #![allow(unused)] +// revisions: migrate nll +#![cfg_attr(nll, feature(nll))] + fn f() { let mut x: Box<()> = Box::new(()); || { &mut x }; + //[migrate]~^^ WARNING captured variable cannot escape `FnMut` closure body + //[migrate]~| WARNING this error has been downgraded to a warning + //[migrate]~| WARNING this warning will become a hard error in the future + //[nll]~^^^^^ ERROR captured variable cannot escape `FnMut` closure body } - +#[rustc_error] fn main() {} +//[migrate]~^ ERROR diff --git a/src/test/ui/issues/issue-40510-3.migrate.nll.stderr b/src/test/ui/issues/issue-40510-3.migrate.nll.stderr new file mode 100644 index 0000000000000..a49475a8570a1 --- /dev/null +++ b/src/test/ui/issues/issue-40510-3.migrate.nll.stderr @@ -0,0 +1,15 @@ +error: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-40510-3.rs:11:9 + | +LL | || { + | - inferred to be a `FnMut` closure +LL | / || { +LL | | x.push(()) +LL | | } + | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-40510-3.migrate.stderr b/src/test/ui/issues/issue-40510-3.migrate.stderr new file mode 100644 index 0000000000000..f00690efc312c --- /dev/null +++ b/src/test/ui/issues/issue-40510-3.migrate.stderr @@ -0,0 +1,24 @@ +warning: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-40510-3.rs:11:9 + | +LL | || { + | - inferred to be a `FnMut` closure +LL | / || { +LL | | x.push(()) +LL | | } + | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + +error: compilation successful + --> $DIR/issue-40510-3.rs:22:1 + | +LL | fn main() {} + | ^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-40510-3.nll.stderr b/src/test/ui/issues/issue-40510-3.nll.stderr index 1297e1418981f..a49475a8570a1 100644 --- a/src/test/ui/issues/issue-40510-3.nll.stderr +++ b/src/test/ui/issues/issue-40510-3.nll.stderr @@ -1,5 +1,5 @@ -warning: captured variable cannot escape `FnMut` closure body - --> $DIR/issue-40510-3.rs:8:9 +error: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-40510-3.rs:11:9 | LL | || { | - inferred to be a `FnMut` closure @@ -10,6 +10,6 @@ LL | | } | = note: `FnMut` closures only have access to their captured variables while they are executing... = note: ...therefore, they cannot allow references to captured variables to escape - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + +error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40510-3.rs b/src/test/ui/issues/issue-40510-3.rs index bc95c461d1e1e..205d982363128 100644 --- a/src/test/ui/issues/issue-40510-3.rs +++ b/src/test/ui/issues/issue-40510-3.rs @@ -1,6 +1,9 @@ -// compile-pass +#![feature(rustc_attrs)] #![allow(unused)] +// revisions: migrate nll +#![cfg_attr(nll, feature(nll))] + fn f() { let mut x: Vec<()> = Vec::new(); @@ -8,8 +11,13 @@ fn f() { || { x.push(()) } + //[migrate]~^^^ WARNING captured variable cannot escape `FnMut` closure body + //[migrate]~| WARNING this error has been downgraded to a warning + //[migrate]~| WARNING this warning will become a hard error in the future + //[nll]~^^^^^^ ERROR captured variable cannot escape `FnMut` closure body }; } - +#[rustc_error] fn main() {} +//[migrate]~^ ERROR diff --git a/src/test/ui/issues/issue-40610.stderr b/src/test/ui/issues/issue-40610.stderr index f441d65b91e43..9d5775919296d 100644 --- a/src/test/ui/issues/issue-40610.stderr +++ b/src/test/ui/issues/issue-40610.stderr @@ -1,8 +1,10 @@ error[E0369]: binary operation `+` cannot be applied to type `()` - --> $DIR/issue-40610.rs:4:5 + --> $DIR/issue-40610.rs:4:8 | LL | () + f(&[1.0]); - | ^^^^^^^^^^^^^^ + | -- ^ --------- () + | | + | () | = note: an implementation of `std::ops::Add` might be missing for `()` diff --git a/src/test/ui/issues/issue-40782.rs b/src/test/ui/issues/issue-40782.rs index 55fec04e0e01a..60db19ef9151f 100644 --- a/src/test/ui/issues/issue-40782.rs +++ b/src/test/ui/issues/issue-40782.rs @@ -2,4 +2,3 @@ fn main() { for i 0..2 { //~ ERROR missing `in` } } - diff --git a/src/test/ui/issues/issue-40782.stderr b/src/test/ui/issues/issue-40782.stderr index 03f051adc6e32..fdc57466f3cac 100644 --- a/src/test/ui/issues/issue-40782.stderr +++ b/src/test/ui/issues/issue-40782.stderr @@ -1,7 +1,7 @@ error: missing `in` in `for` loop --> $DIR/issue-40782.rs:2:10 | -LL | for i 0..2 { //~ ERROR missing `in` +LL | for i 0..2 { | ^ help: try adding `in` here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40845.stderr b/src/test/ui/issues/issue-40845.stderr index a8d75025279de..a8be38ebf0657 100644 --- a/src/test/ui/issues/issue-40845.stderr +++ b/src/test/ui/issues/issue-40845.stderr @@ -1,13 +1,13 @@ error: cannot find macro `m!` in this scope --> $DIR/issue-40845.rs:4:10 | -LL | impl S { m!(); } //~ ERROR cannot find macro `m!` in this scope +LL | impl S { m!(); } | ^ error: cannot find macro `m!` in this scope --> $DIR/issue-40845.rs:1:11 | -LL | trait T { m!(); } //~ ERROR cannot find macro `m!` in this scope +LL | trait T { m!(); } | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-41139.nll.stderr b/src/test/ui/issues/issue-41139.nll.stderr deleted file mode 100644 index 4dd017b0a9191..0000000000000 --- a/src/test/ui/issues/issue-41139.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0161]: cannot move a value of type dyn Trait: the size of dyn Trait cannot be statically determined - --> $DIR/issue-41139.rs:6:23 - | -LL | let t : &Trait = &get_function()(); - | ^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0161`. diff --git a/src/test/ui/issues/issue-41139.rs b/src/test/ui/issues/issue-41139.rs index 0bfbea11b0e08..4814232607cf8 100644 --- a/src/test/ui/issues/issue-41139.rs +++ b/src/test/ui/issues/issue-41139.rs @@ -1,8 +1,8 @@ trait Trait {} -fn get_function<'a>() -> &'a Fn() -> Trait { panic!("") } +fn get_function<'a>() -> &'a dyn Fn() -> dyn Trait { panic!("") } fn main() { - let t : &Trait = &get_function()(); - //~^ ERROR cannot move a value of type (dyn Trait + 'static) + let t : &dyn Trait = &get_function()(); + //~^ ERROR cannot move a value of type dyn Trait } diff --git a/src/test/ui/issues/issue-41139.stderr b/src/test/ui/issues/issue-41139.stderr index 3e3de7b7cf12d..829d0cfa72ca7 100644 --- a/src/test/ui/issues/issue-41139.stderr +++ b/src/test/ui/issues/issue-41139.stderr @@ -1,8 +1,8 @@ -error[E0161]: cannot move a value of type (dyn Trait + 'static): the size of (dyn Trait + 'static) cannot be statically determined - --> $DIR/issue-41139.rs:6:23 +error[E0161]: cannot move a value of type dyn Trait: the size of dyn Trait cannot be statically determined + --> $DIR/issue-41139.rs:6:27 | -LL | let t : &Trait = &get_function()(); - | ^^^^^^^^^^^^^^^^ +LL | let t : &dyn Trait = &get_function()(); + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-41255.rs b/src/test/ui/issues/issue-41255.rs index 395ab8601bcc5..60fdf7c3e8a47 100644 --- a/src/test/ui/issues/issue-41255.rs +++ b/src/test/ui/issues/issue-41255.rs @@ -9,6 +9,8 @@ fn main() { match x { 5.0 => {}, //~ ERROR floating-point types cannot be used in patterns //~| WARNING hard error + //~| ERROR floating-point types cannot be used in patterns + //~| WARNING this was previously accepted by the compiler but is being 5.0f32 => {}, //~ ERROR floating-point types cannot be used in patterns //~| WARNING hard error -5.0 => {}, //~ ERROR floating-point types cannot be used in patterns diff --git a/src/test/ui/issues/issue-41255.stderr b/src/test/ui/issues/issue-41255.stderr index 05e930de27af8..c334742cfc4a4 100644 --- a/src/test/ui/issues/issue-41255.stderr +++ b/src/test/ui/issues/issue-41255.stderr @@ -1,7 +1,7 @@ error: floating-point types cannot be used in patterns --> $DIR/issue-41255.rs:10:9 | -LL | 5.0 => {}, //~ ERROR floating-point types cannot be used in patterns +LL | 5.0 => {}, | ^^^ | note: lint level defined here @@ -13,76 +13,85 @@ LL | #![forbid(illegal_floating_point_literal_pattern)] = note: for more information, see issue #41620 error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:12:9 + --> $DIR/issue-41255.rs:14:9 | -LL | 5.0f32 => {}, //~ ERROR floating-point types cannot be used in patterns +LL | 5.0f32 => {}, | ^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:14:10 + --> $DIR/issue-41255.rs:16:10 | -LL | -5.0 => {}, //~ ERROR floating-point types cannot be used in patterns +LL | -5.0 => {}, | ^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:16:9 + --> $DIR/issue-41255.rs:18:9 | -LL | 1.0 .. 33.0 => {}, //~ ERROR floating-point types cannot be used in patterns +LL | 1.0 .. 33.0 => {}, | ^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:16:16 + --> $DIR/issue-41255.rs:18:16 | -LL | 1.0 .. 33.0 => {}, //~ ERROR floating-point types cannot be used in patterns +LL | 1.0 .. 33.0 => {}, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:20:9 + --> $DIR/issue-41255.rs:22:9 | -LL | 39.0 ..= 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns +LL | 39.0 ..= 70.0 => {}, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:20:18 + --> $DIR/issue-41255.rs:22:18 | -LL | 39.0 ..= 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns +LL | 39.0 ..= 70.0 => {}, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:29:10 + --> $DIR/issue-41255.rs:31:10 | -LL | (3.14, 1) => {}, //~ ERROR floating-point types cannot be used +LL | (3.14, 1) => {}, | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:36:18 + --> $DIR/issue-41255.rs:38:18 | -LL | Foo { x: 2.0 } => {}, //~ ERROR floating-point types cannot be used +LL | Foo { x: 2.0 } => {}, | ^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 -error: aborting due to 9 previous errors +error: floating-point types cannot be used in patterns + --> $DIR/issue-41255.rs:10:9 + | +LL | 5.0 => {}, + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: aborting due to 10 previous errors diff --git a/src/test/ui/issues/issue-41394.stderr b/src/test/ui/issues/issue-41394.stderr index bc5c6e798e868..c8437ab189d8d 100644 --- a/src/test/ui/issues/issue-41394.stderr +++ b/src/test/ui/issues/issue-41394.stderr @@ -1,8 +1,10 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` - --> $DIR/issue-41394.rs:2:9 + --> $DIR/issue-41394.rs:2:12 | LL | A = "" + 1 - | ^^^^^^ + | -- ^ - {integer} + | | + | &str | = note: an implementation of `std::ops::Add` might be missing for `&str` @@ -14,5 +16,5 @@ LL | A = Foo::A as isize error: aborting due to 2 previous errors -Some errors occurred: E0080, E0369. +Some errors have detailed explanations: E0080, E0369. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/issues/issue-41549.stderr b/src/test/ui/issues/issue-41549.stderr index b144387ac44bc..5e102dcbf4115 100644 --- a/src/test/ui/issues/issue-41549.stderr +++ b/src/test/ui/issues/issue-41549.stderr @@ -1,7 +1,7 @@ error[E0326]: implemented const `CONST` has an incompatible type for trait --> $DIR/issue-41549.rs:9:18 | -LL | const CONST: () = (); //~ ERROR incompatible type for trait +LL | const CONST: () = (); | ^^ expected u32, found () | = note: expected type `u32` diff --git a/src/test/ui/issues/issue-41726.nll.stderr b/src/test/ui/issues/issue-41726.nll.stderr deleted file mode 100644 index 087f557a0d4fc..0000000000000 --- a/src/test/ui/issues/issue-41726.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/issue-41726.rs:5:9 - | -LL | things[src.as_str()].sort(); //~ ERROR cannot borrow immutable - | ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable - | - = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap>` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/issues/issue-41726.rs b/src/test/ui/issues/issue-41726.rs index 41dcaa8e280b8..ed05629389005 100644 --- a/src/test/ui/issues/issue-41726.rs +++ b/src/test/ui/issues/issue-41726.rs @@ -2,6 +2,6 @@ use std::collections::HashMap; fn main() { let things: HashMap> = HashMap::new(); for src in things.keys() { - things[src.as_str()].sort(); //~ ERROR cannot borrow immutable + things[src.as_str()].sort(); //~ ERROR cannot borrow data in a `&` reference as mutable } } diff --git a/src/test/ui/issues/issue-41726.stderr b/src/test/ui/issues/issue-41726.stderr index e6b92dc9dfeaf..c92753d6e3dbf 100644 --- a/src/test/ui/issues/issue-41726.stderr +++ b/src/test/ui/issues/issue-41726.stderr @@ -1,7 +1,7 @@ -error[E0596]: cannot borrow immutable indexed content as mutable +error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/issue-41726.rs:5:9 | -LL | things[src.as_str()].sort(); //~ ERROR cannot borrow immutable +LL | things[src.as_str()].sort(); | ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap>` diff --git a/src/test/ui/issues/issue-41742.stderr b/src/test/ui/issues/issue-41742.stderr index 03a9710f67975..f205abf55768c 100644 --- a/src/test/ui/issues/issue-41742.stderr +++ b/src/test/ui/issues/issue-41742.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-41742.rs:24:7 | -LL | H["?"].f(); //~ ERROR mismatched types +LL | H["?"].f(); | ^^^ expected u32, found reference | = note: expected type `u32` diff --git a/src/test/ui/issues/issue-41776.stderr b/src/test/ui/issues/issue-41776.stderr index 1806f68f14aee..e06873b50265d 100644 --- a/src/test/ui/issues/issue-41776.stderr +++ b/src/test/ui/issues/issue-41776.stderr @@ -1,7 +1,7 @@ error: argument must be a string literal --> $DIR/issue-41776.rs:2:14 | -LL | include!(line!()); //~ ERROR argument must be a string literal +LL | include!(line!()); | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-41974.stderr b/src/test/ui/issues/issue-41974.stderr index 68712e0f0549c..20121878a0754 100644 --- a/src/test/ui/issues/issue-41974.stderr +++ b/src/test/ui/issues/issue-41974.stderr @@ -1,7 +1,7 @@ error[E0119]: conflicting implementations of trait `std::ops::Drop` for type `std::boxed::Box<_>`: --> $DIR/issue-41974.rs:7:1 | -LL | impl Drop for T where T: A { //~ ERROR E0119 +LL | impl Drop for T where T: A { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `alloc`: @@ -12,18 +12,18 @@ LL | impl Drop for T where T: A { //~ ERROR E0119 error[E0120]: the Drop trait may only be implemented on structures --> $DIR/issue-41974.rs:7:18 | -LL | impl Drop for T where T: A { //~ ERROR E0119 +LL | impl Drop for T where T: A { | ^ implementing Drop requires a struct error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) --> $DIR/issue-41974.rs:7:1 | -LL | impl Drop for T where T: A { //~ ERROR E0119 +LL | impl Drop for T where T: A { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type | = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to 3 previous errors -Some errors occurred: E0119, E0120, E0210. +Some errors have detailed explanations: E0119, E0120, E0210. For more information about an error, try `rustc --explain E0119`. diff --git a/src/test/ui/issues/issue-4201.stderr b/src/test/ui/issues/issue-4201.stderr index 4f8ec96d53151..dd76faef5c7a6 100644 --- a/src/test/ui/issues/issue-4201.stderr +++ b/src/test/ui/issues/issue-4201.stderr @@ -3,16 +3,19 @@ error[E0317]: if may be missing an else clause | LL | } else if false { | ____________^ -LL | | //~^ ERROR if may be missing an else clause -LL | | //~| expected type `()` -LL | | //~| found type `{integer}` -LL | | //~| expected (), found integer +LL | | +LL | | +LL | | +LL | | LL | | 1 + | | - found here LL | | }; | |_____^ expected (), found integer | = note: expected type `()` found type `{integer}` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-42060.rs b/src/test/ui/issues/issue-42060.rs index da7c03032eb87..1740b238343c8 100644 --- a/src/test/ui/issues/issue-42060.rs +++ b/src/test/ui/issues/issue-42060.rs @@ -9,4 +9,3 @@ fn f(){ ::N //~ ERROR attempt to use a non-constant value in a constant //~^ ERROR `typeof` is a reserved keyword but unimplemented [E0516] } - diff --git a/src/test/ui/issues/issue-42060.stderr b/src/test/ui/issues/issue-42060.stderr index cad2bb2a67be5..72408c7919456 100644 --- a/src/test/ui/issues/issue-42060.stderr +++ b/src/test/ui/issues/issue-42060.stderr @@ -1,28 +1,28 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-42060.rs:3:23 | -LL | let other: typeof(thing) = thing; //~ ERROR attempt to use a non-constant value in a constant +LL | let other: typeof(thing) = thing; | ^^^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-42060.rs:9:13 | -LL | ::N //~ ERROR attempt to use a non-constant value in a constant +LL | ::N | ^ non-constant value error[E0516]: `typeof` is a reserved keyword but unimplemented --> $DIR/issue-42060.rs:3:16 | -LL | let other: typeof(thing) = thing; //~ ERROR attempt to use a non-constant value in a constant +LL | let other: typeof(thing) = thing; | ^^^^^^^^^^^^^ reserved keyword error[E0516]: `typeof` is a reserved keyword but unimplemented --> $DIR/issue-42060.rs:9:6 | -LL | ::N //~ ERROR attempt to use a non-constant value in a constant +LL | ::N | ^^^^^^^^^ reserved keyword error: aborting due to 4 previous errors -Some errors occurred: E0435, E0516. +Some errors have detailed explanations: E0435, E0516. For more information about an error, try `rustc --explain E0435`. diff --git a/src/test/ui/issues/issue-42106.nll.stderr b/src/test/ui/issues/issue-42106.nll.stderr deleted file mode 100644 index 3a31e439c078a..0000000000000 --- a/src/test/ui/issues/issue-42106.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0502]: cannot borrow `*collection` as mutable because it is also borrowed as immutable - --> $DIR/issue-42106.rs:3:5 - | -LL | let _a = &collection; - | ----------- immutable borrow occurs here -LL | collection.swap(1, 2); //~ ERROR also borrowed as immutable - | ^^^^^^^^^^ mutable borrow occurs here -LL | _a.use_ref(); - | -- immutable borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/issues/issue-42106.stderr b/src/test/ui/issues/issue-42106.stderr index e1018a89d2091..d5a9d233bc969 100644 --- a/src/test/ui/issues/issue-42106.stderr +++ b/src/test/ui/issues/issue-42106.stderr @@ -1,13 +1,12 @@ -error[E0502]: cannot borrow `*collection` as mutable because `collection` is also borrowed as immutable +error[E0502]: cannot borrow `*collection` as mutable because it is also borrowed as immutable --> $DIR/issue-42106.rs:3:5 | LL | let _a = &collection; - | ---------- immutable borrow occurs here -LL | collection.swap(1, 2); //~ ERROR also borrowed as immutable + | ----------- immutable borrow occurs here +LL | collection.swap(1, 2); | ^^^^^^^^^^ mutable borrow occurs here LL | _a.use_ref(); -LL | } - | - immutable borrow ends here + | -- immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-42312.rs b/src/test/ui/issues/issue-42312.rs index b1c651f665b72..426efcbf9b16f 100644 --- a/src/test/ui/issues/issue-42312.rs +++ b/src/test/ui/issues/issue-42312.rs @@ -5,7 +5,7 @@ pub trait Foo { //~^ ERROR the size for values of type } -pub fn f(_: ToString) {} +pub fn f(_: dyn ToString) {} //~^ ERROR the size for values of type fn main() { } diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr index 20c8d085cbc62..bfdc4272fb308 100644 --- a/src/test/ui/issues/issue-42312.stderr +++ b/src/test/ui/issues/issue-42312.stderr @@ -11,10 +11,10 @@ LL | fn baz(_: Self::Target) where Self: Deref {} = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `(dyn std::string::ToString + 'static)` cannot be known at compilation time - --> $DIR/issue-42312.rs:8:23 + --> $DIR/issue-42312.rs:8:27 | -LL | pub fn f(_: ToString) {} - | ^ doesn't have a size known at compile-time +LL | pub fn f(_: dyn ToString) {} + | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::string::ToString + 'static)` = note: to learn more, visit diff --git a/src/test/ui/issues/issue-42344.nll.stderr b/src/test/ui/issues/issue-42344.nll.stderr deleted file mode 100644 index 9770d26fb12d8..0000000000000 --- a/src/test/ui/issues/issue-42344.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0596]: cannot borrow `*TAB[_]` as mutable, as `TAB` is an immutable static item - --> $DIR/issue-42344.rs:4:5 - | -LL | TAB[0].iter_mut(); //~ ERROR cannot borrow data mutably in a `&` reference [E0389] - | ^^^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/issues/issue-42344.rs b/src/test/ui/issues/issue-42344.rs index 5f1bb4f91bb84..a7636edf2f8db 100644 --- a/src/test/ui/issues/issue-42344.rs +++ b/src/test/ui/issues/issue-42344.rs @@ -1,7 +1,8 @@ static TAB: [&mut [u8]; 0] = []; pub unsafe fn test() { - TAB[0].iter_mut(); //~ ERROR cannot borrow data mutably in a `&` reference [E0389] + TAB[0].iter_mut(); + //~^ ERROR cannot borrow `*TAB[_]` as mutable, as `TAB` is an immutable static item [E0596] } pub fn main() {} diff --git a/src/test/ui/issues/issue-42344.stderr b/src/test/ui/issues/issue-42344.stderr index cb0fe78d10205..5cffa1b51219f 100644 --- a/src/test/ui/issues/issue-42344.stderr +++ b/src/test/ui/issues/issue-42344.stderr @@ -1,9 +1,9 @@ -error[E0389]: cannot borrow data mutably in a `&` reference +error[E0596]: cannot borrow `*TAB[_]` as mutable, as `TAB` is an immutable static item --> $DIR/issue-42344.rs:4:5 | -LL | TAB[0].iter_mut(); //~ ERROR cannot borrow data mutably in a `&` reference [E0389] - | ^^^^^^ assignment into an immutable reference +LL | TAB[0].iter_mut(); + | ^^^^^^ cannot borrow as mutable error: aborting due to previous error -For more information about this error, try `rustc --explain E0389`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/issues/issue-4265.stderr b/src/test/ui/issues/issue-4265.stderr index b5fce14914d65..4faf5d3a92302 100644 --- a/src/test/ui/issues/issue-4265.stderr +++ b/src/test/ui/issues/issue-4265.stderr @@ -6,7 +6,7 @@ LL | | Foo { baz: 0 }.bar(); LL | | } | |_____- previous definition of `bar` here LL | -LL | / fn bar() { //~ ERROR duplicate definitions +LL | / fn bar() { LL | | } | |_____^ duplicate definition diff --git a/src/test/ui/issues/issue-42755.stderr b/src/test/ui/issues/issue-42755.stderr index 4b490f8e87f9c..12047e22f1b02 100644 --- a/src/test/ui/issues/issue-42755.stderr +++ b/src/test/ui/issues/issue-42755.stderr @@ -1,7 +1,7 @@ error: repetition matches empty token tree --> $DIR/issue-42755.rs:2:7 | -LL | ($($p:vis)*) => {} //~ ERROR repetition matches empty token tree +LL | ($($p:vis)*) => {} | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-42796.nll.stderr b/src/test/ui/issues/issue-42796.nll.stderr deleted file mode 100644 index 23cc88bab52d5..0000000000000 --- a/src/test/ui/issues/issue-42796.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0382]: borrow of moved value: `s` - --> $DIR/issue-42796.rs:18:20 - | -LL | let s = "Hello!".to_owned(); - | - move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait -LL | let mut s_copy = s; - | - value moved here -... -LL | println!("{}", s); //~ ERROR use of moved value - | ^ value borrowed here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/issues/issue-42796.rs b/src/test/ui/issues/issue-42796.rs index 98b91270b7d30..5e83a1cd67785 100644 --- a/src/test/ui/issues/issue-42796.rs +++ b/src/test/ui/issues/issue-42796.rs @@ -15,5 +15,5 @@ fn main() { let mut s_copy = s; s_copy.push_str("World!"); "0wned!".to_owned(); - println!("{}", s); //~ ERROR use of moved value + println!("{}", s); //~ ERROR borrow of moved value } diff --git a/src/test/ui/issues/issue-42796.stderr b/src/test/ui/issues/issue-42796.stderr index 530eedd68e6a1..d9dfbc999f360 100644 --- a/src/test/ui/issues/issue-42796.stderr +++ b/src/test/ui/issues/issue-42796.stderr @@ -1,13 +1,13 @@ -error[E0382]: use of moved value: `s` +error[E0382]: borrow of moved value: `s` --> $DIR/issue-42796.rs:18:20 | +LL | let s = "Hello!".to_owned(); + | - move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait LL | let mut s_copy = s; - | ---------- value moved here + | - value moved here ... -LL | println!("{}", s); //~ ERROR use of moved value - | ^ value used here after move - | - = note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait +LL | println!("{}", s); + | ^ value borrowed here after move error: aborting due to previous error diff --git a/src/test/ui/issues/issue-42880.stderr b/src/test/ui/issues/issue-42880.stderr index 36b9e8a1e8afa..763bb9ae0ea9c 100644 --- a/src/test/ui/issues/issue-42880.stderr +++ b/src/test/ui/issues/issue-42880.stderr @@ -1,8 +1,8 @@ error[E0599]: no associated item named `String` found for type `std::string::String` in the current scope --> $DIR/issue-42880.rs:4:22 | -LL | let f = |&Value::String(_)| (); //~ ERROR no associated item named - | -------^^^^^^--- associated item not found in `std::string::String` +LL | let f = |&Value::String(_)| (); + | ^^^^^^ associated item not found in `std::string::String` error: aborting due to previous error diff --git a/src/test/ui/issue-42944.rs b/src/test/ui/issues/issue-42944.rs similarity index 100% rename from src/test/ui/issue-42944.rs rename to src/test/ui/issues/issue-42944.rs diff --git a/src/test/ui/issues/issue-42944.stderr b/src/test/ui/issues/issue-42944.stderr new file mode 100644 index 0000000000000..ba285953dbdbd --- /dev/null +++ b/src/test/ui/issues/issue-42944.stderr @@ -0,0 +1,20 @@ +error[E0423]: expected function, found struct `B` + --> $DIR/issue-42944.rs:9:9 + | +LL | B(()); + | ^ constructor is not visible here due to private fields + +error[E0425]: cannot find function `B` in this scope + --> $DIR/issue-42944.rs:15:9 + | +LL | B(()); + | ^ not found in this scope +help: possible candidate is found in another module, you can import it into scope + | +LL | use foo::B; + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0423, E0425. +For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/issues/issue-42954.stderr b/src/test/ui/issues/issue-42954.stderr index 6a89724de5f70..8c35088a1bbeb 100644 --- a/src/test/ui/issues/issue-42954.stderr +++ b/src/test/ui/issues/issue-42954.stderr @@ -1,7 +1,7 @@ error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison --> $DIR/issue-42954.rs:7:19 | -LL | $i as u32 < 0 //~ `<` is interpreted as a start of generic arguments +LL | $i as u32 < 0 | --------- ^ - interpreted as generic arguments | | | | | not interpreted as comparison diff --git a/src/test/ui/issues/issue-43023.stderr b/src/test/ui/issues/issue-43023.stderr index b620cc5d74e8b..206a51645fe68 100644 --- a/src/test/ui/issues/issue-43023.stderr +++ b/src/test/ui/issues/issue-43023.stderr @@ -1,19 +1,19 @@ error: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43023.rs:4:5 | -LL | #[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions +LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43023.rs:11:5 | -LL | #[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions +LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43023.rs:16:5 | -LL | #[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions +LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-43105.stderr b/src/test/ui/issues/issue-43105.stderr index 3cc0440d2c77a..378fbe6d5c430 100644 --- a/src/test/ui/issues/issue-43105.stderr +++ b/src/test/ui/issues/issue-43105.stderr @@ -5,10 +5,10 @@ LL | const NUM: u8 = xyz(); | ^^^^^ error: any use of this value will cause an error - --> $DIR/issue-43105.rs:3:1 + --> $DIR/issue-43105.rs:3:17 | LL | const NUM: u8 = xyz(); - | ^^^^^^^^^^^^^^^^-----^ + | ----------------^^^^^- | | | calling non-const function `xyz` | diff --git a/src/test/ui/issues/issue-43162.stderr b/src/test/ui/issues/issue-43162.stderr index 3fc5317830e48..cd11959ede6cb 100644 --- a/src/test/ui/issues/issue-43162.stderr +++ b/src/test/ui/issues/issue-43162.stderr @@ -1,13 +1,13 @@ error[E0268]: `break` outside of loop --> $DIR/issue-43162.rs:3:5 | -LL | break true; //~ ERROR E0268 +LL | break true; | ^^^^^^^^^^ cannot break outside of a loop error[E0268]: `break` outside of loop --> $DIR/issue-43162.rs:7:5 | -LL | break {}; //~ ERROR E0268 +LL | break {}; | ^^^^^^^^ cannot break outside of a loop error[E0308]: mismatched types @@ -17,8 +17,8 @@ LL | fn foo() -> bool { | --- ^^^^ expected bool, found () | | | this function's body doesn't return -LL | //~^ ERROR E0308 -LL | break true; //~ ERROR E0268 +LL | +LL | break true; | - help: consider removing this semicolon | = note: expected type `bool` @@ -26,5 +26,5 @@ LL | break true; //~ ERROR E0268 error: aborting due to 3 previous errors -Some errors occurred: E0268, E0308. +Some errors have detailed explanations: E0268, E0308. For more information about an error, try `rustc --explain E0268`. diff --git a/src/test/ui/issues/issue-43196.rs b/src/test/ui/issues/issue-43196.rs index 81e5205ce330d..0eefa01ce6de3 100644 --- a/src/test/ui/issues/issue-43196.rs +++ b/src/test/ui/issues/issue-43196.rs @@ -4,4 +4,3 @@ fn main() { //~^ ERROR expected `|`, found `}` | //~^ ERROR expected item, found `|` - diff --git a/src/test/ui/issues/issue-4321.stderr b/src/test/ui/issues/issue-4321.stderr index 7817fdcbce99c..afb4fe775d58c 100644 --- a/src/test/ui/issues/issue-4321.stderr +++ b/src/test/ui/issues/issue-4321.stderr @@ -1,8 +1,10 @@ error[E0004]: non-exhaustive patterns: `(true, false)` not covered --> $DIR/issue-4321.rs:3:31 | -LL | println!("foo {:}", match tup { //~ ERROR non-exhaustive patterns: `(true, false)` not covered +LL | println!("foo {:}", match tup { | ^^^ pattern `(true, false)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/issues/issue-4335.nll.stderr b/src/test/ui/issues/issue-4335.nll.stderr deleted file mode 100644 index 5ac3bdb805cb8..0000000000000 --- a/src/test/ui/issues/issue-4335.nll.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/issue-4335.rs:6:20 - | -LL | fn f<'r, T>(v: &'r T) -> Box T + 'r> { - | - captured outer variable -LL | id(Box::new(|| *v)) - | ^^ cannot move out of captured variable in an `FnMut` closure - -error[E0373]: closure may outlive the current function, but it borrows `v`, which is owned by the current function - --> $DIR/issue-4335.rs:6:17 - | -LL | id(Box::new(|| *v)) - | ^^ - `v` is borrowed here - | | - | may outlive borrowed value `v` - | -note: closure is returned here - --> $DIR/issue-4335.rs:6:5 - | -LL | id(Box::new(|| *v)) - | ^^^^^^^^^^^^^^^^^^^ -help: to force the closure to take ownership of `v` (and any other referenced variables), use the `move` keyword - | -LL | id(Box::new(move || *v)) - | ^^^^^^^ - -error: aborting due to 2 previous errors - -Some errors occurred: E0373, E0507. -For more information about an error, try `rustc --explain E0373`. diff --git a/src/test/ui/issues/issue-4335.rs b/src/test/ui/issues/issue-4335.rs index d3c9954cdb051..a10ae9a1243a2 100644 --- a/src/test/ui/issues/issue-4335.rs +++ b/src/test/ui/issues/issue-4335.rs @@ -2,7 +2,7 @@ fn id(t: T) -> T { t } -fn f<'r, T>(v: &'r T) -> Box T + 'r> { +fn f<'r, T>(v: &'r T) -> Box T + 'r> { id(Box::new(|| *v)) //~^ ERROR E0373 //~| ERROR E0507 diff --git a/src/test/ui/issues/issue-4335.stderr b/src/test/ui/issues/issue-4335.stderr index 9ef8e16bbd3c9..ca1c0b68d2a5f 100644 --- a/src/test/ui/issues/issue-4335.stderr +++ b/src/test/ui/issues/issue-4335.stderr @@ -1,3 +1,11 @@ +error[E0507]: cannot move out of `*v`, as `v` is a captured variable in an `FnMut` closure + --> $DIR/issue-4335.rs:6:20 + | +LL | fn f<'r, T>(v: &'r T) -> Box T + 'r> { + | - captured outer variable +LL | id(Box::new(|| *v)) + | ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait + error[E0373]: closure may outlive the current function, but it borrows `v`, which is owned by the current function --> $DIR/issue-4335.rs:6:17 | @@ -5,18 +13,18 @@ LL | id(Box::new(|| *v)) | ^^ - `v` is borrowed here | | | may outlive borrowed value `v` + | +note: closure is returned here + --> $DIR/issue-4335.rs:6:5 + | +LL | id(Box::new(|| *v)) + | ^^^^^^^^^^^^^^^^^^^ help: to force the closure to take ownership of `v` (and any other referenced variables), use the `move` keyword | LL | id(Box::new(move || *v)) | ^^^^^^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/issue-4335.rs:6:20 - | -LL | id(Box::new(|| *v)) - | ^^ cannot move out of borrowed content - error: aborting due to 2 previous errors -Some errors occurred: E0373, E0507. +Some errors have detailed explanations: E0373, E0507. For more information about an error, try `rustc --explain E0373`. diff --git a/src/test/ui/issues/issue-43355.rs b/src/test/ui/issues/issue-43355.rs index 809300d6d1968..bf819af79625f 100644 --- a/src/test/ui/issues/issue-43355.rs +++ b/src/test/ui/issues/issue-43355.rs @@ -12,7 +12,6 @@ impl Trait1 for T where T: Trait2 { impl Trait1> for A { //~^ ERROR conflicting implementations of trait -//~| hard error //~| downstream crates may implement trait `Trait2>` for type `A` type Output = i32; } diff --git a/src/test/ui/issues/issue-43355.stderr b/src/test/ui/issues/issue-43355.stderr index 039f10447c072..75c69e5b3e3f5 100644 --- a/src/test/ui/issues/issue-43355.stderr +++ b/src/test/ui/issues/issue-43355.stderr @@ -1,4 +1,4 @@ -error: conflicting implementations of trait `Trait1>` for type `A`: (E0119) +error[E0119]: conflicting implementations of trait `Trait1>` for type `A`: --> $DIR/issue-43355.rs:13:1 | LL | impl Trait1 for T where T: Trait2 { @@ -7,10 +7,8 @@ LL | impl Trait1 for T where T: Trait2 { LL | impl Trait1> for A { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A` | - = note: #[deny(incoherent_fundamental_impls)] on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46205 = note: downstream crates may implement trait `Trait2>` for type `A` error: aborting due to previous error +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/issues/issue-43420-no-over-suggest.stderr b/src/test/ui/issues/issue-43420-no-over-suggest.stderr index bd51d7e116953..7a3722e4bd727 100644 --- a/src/test/ui/issues/issue-43420-no-over-suggest.stderr +++ b/src/test/ui/issues/issue-43420-no-over-suggest.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-43420-no-over-suggest.rs:8:9 | -LL | foo(&a); //~ ERROR mismatched types +LL | foo(&a); | ^^ expected slice, found struct `std::vec::Vec` | = note: expected type `&[u16]` diff --git a/src/test/ui/issues/issue-43424.stderr b/src/test/ui/issues/issue-43424.stderr index c81ea20170c71..6274a7928ba04 100644 --- a/src/test/ui/issues/issue-43424.stderr +++ b/src/test/ui/issues/issue-43424.stderr @@ -1,7 +1,7 @@ error: unexpected generic arguments in path --> $DIR/issue-43424.rs:10:4 | -LL | m!(inline); //~ ERROR: unexpected generic arguments in path +LL | m!(inline); | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-4366-2.stderr b/src/test/ui/issues/issue-4366-2.stderr index 8cf0e3bd520d5..63013a6523ab0 100644 --- a/src/test/ui/issues/issue-4366-2.stderr +++ b/src/test/ui/issues/issue-4366-2.stderr @@ -11,7 +11,7 @@ LL | use a::b::Bar; error[E0423]: expected function, found module `foo` --> $DIR/issue-4366-2.rs:25:5 | -LL | foo(); //~ ERROR expected function, found module `foo` +LL | foo(); | ^^^ not a function help: possible better candidates are found in other modules, you can import them into scope | @@ -22,5 +22,5 @@ LL | use m1::foo; error: aborting due to 2 previous errors -Some errors occurred: E0412, E0423. +Some errors have detailed explanations: E0412, E0423. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/issues/issue-4366.stderr b/src/test/ui/issues/issue-4366.stderr index 2bad7b17d642e..c59ab00455709 100644 --- a/src/test/ui/issues/issue-4366.stderr +++ b/src/test/ui/issues/issue-4366.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find function `foo` in this scope --> $DIR/issue-4366.rs:18:29 | -LL | fn sub() -> isize { foo(); 1 } //~ ERROR cannot find function `foo` in this scope +LL | fn sub() -> isize { foo(); 1 } | ^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | diff --git a/src/test/ui/issues/issue-43733.rs b/src/test/ui/issues/issue-43733.rs index 91192e3360c2c..a602d7667c48d 100644 --- a/src/test/ui/issues/issue-43733.rs +++ b/src/test/ui/issues/issue-43733.rs @@ -13,15 +13,13 @@ static __KEY: std::thread::__FastLocalKeyInner = static __KEY: std::thread::__OsLocalKeyInner = std::thread::__OsLocalKeyInner::new(); -fn __getit() -> std::option::Option< - &'static std::cell::UnsafeCell< - std::option::Option>> +fn __getit() -> std::option::Option<&'static Foo> { - __KEY.get() //~ ERROR call to unsafe function is unsafe + __KEY.get(Default::default) //~ ERROR call to unsafe function is unsafe } static FOO: std::thread::LocalKey = - std::thread::LocalKey::new(__getit, Default::default); + std::thread::LocalKey::new(__getit); //~^ ERROR call to unsafe function is unsafe fn main() { diff --git a/src/test/ui/issues/issue-43733.stderr b/src/test/ui/issues/issue-43733.stderr index 38fa93d446188..ee6a3b065d6ee 100644 --- a/src/test/ui/issues/issue-43733.stderr +++ b/src/test/ui/issues/issue-43733.stderr @@ -1,16 +1,16 @@ error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/issue-43733.rs:20:5 + --> $DIR/issue-43733.rs:18:5 | -LL | __KEY.get() //~ ERROR call to unsafe function is unsafe - | ^^^^^^^^^^^ call to unsafe function +LL | __KEY.get(Default::default) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/issue-43733.rs:24:5 + --> $DIR/issue-43733.rs:22:5 | -LL | std::thread::LocalKey::new(__getit, Default::default); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function +LL | std::thread::LocalKey::new(__getit); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior diff --git a/src/test/ui/issues/issue-43784-associated-type.stderr b/src/test/ui/issues/issue-43784-associated-type.stderr index 4beb854b0f319..fc05d280693b8 100644 --- a/src/test/ui/issues/issue-43784-associated-type.stderr +++ b/src/test/ui/issues/issue-43784-associated-type.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/issue-43784-associated-type.rs:13:9 | -LL | impl Complete for T { //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied +LL | impl Complete for T { | ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound diff --git a/src/test/ui/issues/issue-43784-supertrait.stderr b/src/test/ui/issues/issue-43784-supertrait.stderr index 7771f9abfb8af..4c423f2e77fe8 100644 --- a/src/test/ui/issues/issue-43784-supertrait.stderr +++ b/src/test/ui/issues/issue-43784-supertrait.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/issue-43784-supertrait.rs:8:9 | -LL | impl Complete for T {} //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied +LL | impl Complete for T {} | ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound diff --git a/src/test/ui/issues/issue-43925.stderr b/src/test/ui/issues/issue-43925.stderr index e73c2122a03fc..739ace10aa6ab 100644 --- a/src/test/ui/issues/issue-43925.stderr +++ b/src/test/ui/issues/issue-43925.stderr @@ -1,7 +1,7 @@ error: invalid argument for `cfg(..)` --> $DIR/issue-43925.rs:1:24 | -LL | #[link(name="foo", cfg("rlib"))] //~ ERROR invalid argument for `cfg(..)` +LL | #[link(name="foo", cfg("rlib"))] | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-43926.stderr b/src/test/ui/issues/issue-43926.stderr index 9dc9cfe5db2ac..d9d6b3a34fe2e 100644 --- a/src/test/ui/issues/issue-43926.stderr +++ b/src/test/ui/issues/issue-43926.stderr @@ -1,7 +1,7 @@ error: `cfg()` must have an argument --> $DIR/issue-43926.rs:1:20 | -LL | #[link(name="foo", cfg())] //~ ERROR `cfg()` must have an argument +LL | #[link(name="foo", cfg())] | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-43988.rs b/src/test/ui/issues/issue-43988.rs index 74667d74334cc..b80907560c385 100644 --- a/src/test/ui/issues/issue-43988.rs +++ b/src/test/ui/issues/issue-43988.rs @@ -24,7 +24,7 @@ fn main() { #[repr] let _y = "123"; //~^^ ERROR attribute should not be applied to a statement - //~| ERROR attribute must be of the form + //~| ERROR malformed `repr` attribute fn foo() {} @@ -34,5 +34,5 @@ fn main() { let _z = #[repr] 1; //~^ ERROR attribute should not be applied to an expression - //~| ERROR attribute must be of the form + //~| ERROR malformed `repr` attribute } diff --git a/src/test/ui/issues/issue-43988.stderr b/src/test/ui/issues/issue-43988.stderr index 6fe41a3de29b4..339c1a3b8f617 100644 --- a/src/test/ui/issues/issue-43988.stderr +++ b/src/test/ui/issues/issue-43988.stderr @@ -1,14 +1,14 @@ -error: attribute must be of the form `#[repr(C, packed, ...)]` +error: malformed `repr` attribute input --> $DIR/issue-43988.rs:24:5 | LL | #[repr] - | ^^^^^^^ + | ^^^^^^^ help: must be of the form: `#[repr(C, packed, ...)]` -error: attribute must be of the form `#[repr(C, packed, ...)]` +error: malformed `repr` attribute input --> $DIR/issue-43988.rs:35:14 | LL | let _z = #[repr] 1; - | ^^^^^^^ + | ^^^^^^^ help: must be of the form: `#[repr(C, packed, ...)]` error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43988.rs:5:5 @@ -32,7 +32,7 @@ error[E0517]: attribute should not be applied to a statement LL | #[repr(nothing)] | ^^^^^^^^^^^^^^^^ LL | let _x = 0; - | ----------- not a struct, enum or union + | ----------- not a struct, enum, or union error[E0517]: attribute should not be applied to an expression --> $DIR/issue-43988.rs:18:5 @@ -42,7 +42,7 @@ LL | #[repr(something_not_real)] LL | / loop { LL | | () LL | | }; - | |_____- not defining a struct, enum or union + | |_____- not defining a struct, enum, or union error[E0517]: attribute should not be applied to a statement --> $DIR/issue-43988.rs:24:5 @@ -50,7 +50,7 @@ error[E0517]: attribute should not be applied to a statement LL | #[repr] | ^^^^^^^ LL | let _y = "123"; - | --------------- not a struct, enum or union + | --------------- not a struct, enum, or union error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43988.rs:31:5 @@ -64,9 +64,9 @@ error[E0517]: attribute should not be applied to an expression --> $DIR/issue-43988.rs:35:14 | LL | let _z = #[repr] 1; - | ^^^^^^^ - not defining a struct, enum or union + | ^^^^^^^ - not defining a struct, enum, or union error: aborting due to 9 previous errors -Some errors occurred: E0517, E0518. +Some errors have detailed explanations: E0517, E0518. For more information about an error, try `rustc --explain E0517`. diff --git a/src/test/ui/issues/issue-44005.rs b/src/test/ui/issues/issue-44005.rs index e2625fd937908..f6d1b7073a2b3 100644 --- a/src/test/ui/issues/issue-44005.rs +++ b/src/test/ui/issues/issue-44005.rs @@ -27,4 +27,3 @@ pub fn broken(x: &i32, f: F) { } fn main() { } - diff --git a/src/test/ui/issues/issue-44021.stderr b/src/test/ui/issues/issue-44021.stderr index 03f11312d4655..94500087e5536 100644 --- a/src/test/ui/issues/issue-44021.stderr +++ b/src/test/ui/issues/issue-44021.stderr @@ -1,7 +1,7 @@ error: expected one of `:`, `@`, or `|`, found `}` --> $DIR/issue-44021.rs:3:18 | -LL | fn f() {|x, y} //~ ERROR expected one of `:`, `@`, or `|`, found `}` +LL | fn f() {|x, y} | ^ expected one of `:`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-44023.stderr b/src/test/ui/issues/issue-44023.stderr index f1962a86ee03a..153be363c1dea 100644 --- a/src/test/ui/issues/issue-44023.stderr +++ b/src/test/ui/issues/issue-44023.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-44023.rs:5:36 | -LL | fn საჭმელად_გემრიელი_სადილი ( ) -> isize { //~ ERROR mismatched types +LL | fn საჭმელად_გემრიელი_სადილი ( ) -> isize { | ------------------------ ^^^^^ expected isize, found () | | | this function's body doesn't return diff --git a/src/test/ui/issues/issue-44078.stderr b/src/test/ui/issues/issue-44078.stderr index e7f46130f112f..43b49e463128f 100644 --- a/src/test/ui/issues/issue-44078.stderr +++ b/src/test/ui/issues/issue-44078.stderr @@ -1,7 +1,7 @@ error: unterminated double quote string --> $DIR/issue-44078.rs:2:8 | -LL | "😊""; //~ ERROR unterminated double quote +LL | "😊""; | _________^ LL | | } | |__^ diff --git a/src/test/ui/issues/issue-44127.rs b/src/test/ui/issues/issue-44127.rs new file mode 100644 index 0000000000000..21b2e68264a14 --- /dev/null +++ b/src/test/ui/issues/issue-44127.rs @@ -0,0 +1,17 @@ +// run-pass + +#![feature(decl_macro)] + +pub struct Foo { + bar: u32, +} +pub macro pattern($a:pat) { + Foo { bar: $a } +} + +fn main() { + match (Foo { bar: 3 }) { + pattern!(3) => println!("Test OK"), + _ => unreachable!(), + } +} diff --git a/src/test/ui/issues/issue-44255.rs b/src/test/ui/issues/issue-44255.rs new file mode 100644 index 0000000000000..2245032043257 --- /dev/null +++ b/src/test/ui/issues/issue-44255.rs @@ -0,0 +1,29 @@ +// run-pass + +use std::marker::PhantomData; + +fn main() { + let _arr = [1; >::VAL]; +} + +trait TypeVal { + const VAL: T; +} + +struct Five; + +impl TypeVal for Five { + const VAL: usize = 5; +} + +struct Multiply { + _n: PhantomData, + _m: PhantomData, +} + +impl TypeVal for Multiply + where N: TypeVal, + M: TypeVal, +{ + const VAL: usize = N::VAL * M::VAL; +} diff --git a/src/test/ui/issues/issue-44373-2.rs b/src/test/ui/issues/issue-44373-2.rs index ab92bf458fb60..18b2ce85125f2 100644 --- a/src/test/ui/issues/issue-44373-2.rs +++ b/src/test/ui/issues/issue-44373-2.rs @@ -1,6 +1,5 @@ // compile-pass #![allow(dead_code)] -// compile-flags: -Z borrowck=compare struct Foo(bool); diff --git a/src/test/ui/issues/issue-44373.nll.stderr b/src/test/ui/issues/issue-44373.nll.stderr deleted file mode 100644 index 8359e5af2b8de..0000000000000 --- a/src/test/ui/issues/issue-44373.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-44373.rs:4:42 - | -LL | let _val: &'static [&'static u32] = &[&FOO]; //~ ERROR borrowed value does not live long enough - | ----------------------- ^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/issues/issue-44373.rs b/src/test/ui/issues/issue-44373.rs index 13e9fa9ea6743..0d011d096bd1f 100644 --- a/src/test/ui/issues/issue-44373.rs +++ b/src/test/ui/issues/issue-44373.rs @@ -1,5 +1,5 @@ static FOO: u32 = 50; fn main() { - let _val: &'static [&'static u32] = &[&FOO]; //~ ERROR borrowed value does not live long enough + let _val: &'static [&'static u32] = &[&FOO]; //~ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/issues/issue-44373.stderr b/src/test/ui/issues/issue-44373.stderr index 5a4bf18f3d5aa..6f92fbb1eb689 100644 --- a/src/test/ui/issues/issue-44373.stderr +++ b/src/test/ui/issues/issue-44373.stderr @@ -1,13 +1,13 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/issue-44373.rs:4:42 | -LL | let _val: &'static [&'static u32] = &[&FOO]; //~ ERROR borrowed value does not live long enough - | ^^^^^^ temporary value does not live long enough +LL | let _val: &'static [&'static u32] = &[&FOO]; + | ----------------------- ^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/issues/issue-44406.stderr b/src/test/ui/issues/issue-44406.stderr index 105dbb677dc02..14b3b8cc5c85d 100644 --- a/src/test/ui/issues/issue-44406.stderr +++ b/src/test/ui/issues/issue-44406.stderr @@ -1,11 +1,11 @@ error: expected identifier, found keyword `true` --> $DIR/issue-44406.rs:8:10 | -LL | foo!(true); //~ ERROR expected type, found keyword +LL | foo!(true); | ^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | -LL | foo!(r#true); //~ ERROR expected type, found keyword +LL | foo!(r#true); | ^^^^^^ error: expected type, found keyword `true` @@ -14,7 +14,7 @@ error: expected type, found keyword `true` LL | bar(baz: $rest) | - help: try using a semicolon: `;` ... -LL | foo!(true); //~ ERROR expected type, found keyword +LL | foo!(true); | ^^^^ expecting a type here because of type ascription error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-44415.stderr b/src/test/ui/issues/issue-44415.stderr index 3f377fd27e7db..df8e804c87a3f 100644 --- a/src/test/ui/issues/issue-44415.stderr +++ b/src/test/ui/issues/issue-44415.stderr @@ -1,22 +1,22 @@ -error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{constant}}` +error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{constant}}#0` --> $DIR/issue-44415.rs:6:17 | LL | bytes: [u8; unsafe { intrinsics::size_of::() }], | ^^^^^^ | -note: ...which requires const-evaluating `Foo::bytes::{{constant}}`... +note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`... --> $DIR/issue-44415.rs:6:26 | LL | bytes: [u8; unsafe { intrinsics::size_of::() }], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`... -note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}`... +note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... --> $DIR/issue-44415.rs:6:17 | LL | bytes: [u8; unsafe { intrinsics::size_of::() }], | ^^^^^^ - = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}`, completing the cycle + = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle note: cycle used when processing `Foo` --> $DIR/issue-44415.rs:5:1 | diff --git a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr index 3510112daf0a5..71fbba562cae1 100644 --- a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr +++ b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr @@ -4,7 +4,7 @@ error: unnecessary `unsafe` block LL | unsafe { | ------ because it's nested under this `unsafe` block LL | let f = |v: &mut Vec<_>| { -LL | unsafe { //~ ERROR unnecessary `unsafe` +LL | unsafe { | ^^^^^^ unnecessary `unsafe` block | note: lint level defined here @@ -19,7 +19,7 @@ error: unnecessary `unsafe` block LL | unsafe { | ------ because it's nested under this `unsafe` block ... -LL | |w: &mut Vec| { unsafe { //~ ERROR unnecessary `unsafe` +LL | |w: &mut Vec| { unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block @@ -28,7 +28,7 @@ error: unnecessary `unsafe` block LL | unsafe { | ------ because it's nested under this `unsafe` block ... -LL | |x: &mut Vec| { unsafe { //~ ERROR unnecessary `unsafe` +LL | |x: &mut Vec| { unsafe { | ^^^^^^ unnecessary `unsafe` block error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-45157.stderr b/src/test/ui/issues/issue-45157.stderr index 3b15a8dbd9ef8..fbfa1d199566e 100644 --- a/src/test/ui/issues/issue-45157.stderr +++ b/src/test/ui/issues/issue-45157.stderr @@ -6,7 +6,7 @@ LL | let mref = &mut u.s.a; ... LL | let nref = &u.z.c; | ^^^^^^ immutable borrow of `u.z.c` -- which overlaps with `u.s.a` -- occurs here -LL | //~^ ERROR cannot borrow `u` (via `u.z.c`) as immutable because it is also borrowed as mutable (via `u.s.a`) [E0502] +LL | LL | println!("{} {}", mref, nref) | ---- mutable borrow later used here | diff --git a/src/test/ui/issues/issue-45199.ast.nll.stderr b/src/test/ui/issues/issue-45199.ast.nll.stderr deleted file mode 100644 index 6d6af83598226..0000000000000 --- a/src/test/ui/issues/issue-45199.ast.nll.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/issue-45199.rs:10:5 - | -LL | let b: Box; - | - help: make this binding mutable: `mut b` -... -LL | b = Box::new(1); //[ast]~ NOTE first assignment - | - first assignment to `b` -LL | //[mir]~^ NOTE first assignment -LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - | ^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/issue-45199.rs:21:5 - | -LL | let b = Box::new(1); //[ast]~ NOTE first assignment - | - - | | - | first assignment to `b` - | help: make this binding mutable: `mut b` -... -LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - | ^ cannot assign twice to immutable variable - -error[E0384]: cannot assign to immutable argument `b` - --> $DIR/issue-45199.rs:30:5 - | -LL | fn test_args(b: Box) { //[ast]~ NOTE first assignment - | - help: make this binding mutable: `mut b` -... -LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - | ^ cannot assign to immutable argument - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/issues/issue-45199.ast.stderr b/src/test/ui/issues/issue-45199.ast.stderr deleted file mode 100644 index fa9d8e09af5a1..0000000000000 --- a/src/test/ui/issues/issue-45199.ast.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/issue-45199.rs:10:5 - | -LL | b = Box::new(1); //[ast]~ NOTE first assignment - | --------------- first assignment to `b` -LL | //[mir]~^ NOTE first assignment -LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^^^^^^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/issue-45199.rs:21:5 - | -LL | let b = Box::new(1); //[ast]~ NOTE first assignment - | - first assignment to `b` -... -LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^^^^^^^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/issue-45199.rs:30:5 - | -LL | fn test_args(b: Box) { //[ast]~ NOTE first assignment - | - first assignment to `b` -... -LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^^^^^^^^^^^ cannot assign twice to immutable variable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/issues/issue-45199.mir.stderr b/src/test/ui/issues/issue-45199.mir.stderr deleted file mode 100644 index 6d6af83598226..0000000000000 --- a/src/test/ui/issues/issue-45199.mir.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/issue-45199.rs:10:5 - | -LL | let b: Box; - | - help: make this binding mutable: `mut b` -... -LL | b = Box::new(1); //[ast]~ NOTE first assignment - | - first assignment to `b` -LL | //[mir]~^ NOTE first assignment -LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - | ^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/issue-45199.rs:21:5 - | -LL | let b = Box::new(1); //[ast]~ NOTE first assignment - | - - | | - | first assignment to `b` - | help: make this binding mutable: `mut b` -... -LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - | ^ cannot assign twice to immutable variable - -error[E0384]: cannot assign to immutable argument `b` - --> $DIR/issue-45199.rs:30:5 - | -LL | fn test_args(b: Box) { //[ast]~ NOTE first assignment - | - help: make this binding mutable: `mut b` -... -LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - | ^ cannot assign to immutable argument - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/issues/issue-45199.rs b/src/test/ui/issues/issue-45199.rs index bb55534c13218..cbd45cbb61990 100644 --- a/src/test/ui/issues/issue-45199.rs +++ b/src/test/ui/issues/issue-45199.rs @@ -1,36 +1,24 @@ -// revisions: ast mir -//[mir]compile-flags: -Zborrowck=mir - fn test_drop_replace() { let b: Box; - //[mir]~^ HELP make this binding mutable - //[mir]~| SUGGESTION mut b - b = Box::new(1); //[ast]~ NOTE first assignment - //[mir]~^ NOTE first assignment - b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - //[mir]~^ ERROR cannot assign twice to immutable variable `b` - //[ast]~| NOTE cannot assign twice to immutable - //[mir]~| NOTE cannot assign twice to immutable + //~^ HELP make this binding mutable + //~| SUGGESTION mut b + b = Box::new(1); //~ NOTE first assignment + b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` + //~| NOTE cannot assign twice to immutable } fn test_call() { - let b = Box::new(1); //[ast]~ NOTE first assignment - //[mir]~^ NOTE first assignment - //[mir]~| HELP make this binding mutable - //[mir]~| SUGGESTION mut b - b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - //[mir]~^ ERROR cannot assign twice to immutable variable `b` - //[ast]~| NOTE cannot assign twice to immutable - //[mir]~| NOTE cannot assign twice to immutable + let b = Box::new(1); //~ NOTE first assignment + //~| HELP make this binding mutable + //~| SUGGESTION mut b + b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` + //~| NOTE cannot assign twice to immutable } -fn test_args(b: Box) { //[ast]~ NOTE first assignment - //[mir]~^ HELP make this binding mutable - //[mir]~| SUGGESTION mut b - b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - //[mir]~^ ERROR cannot assign to immutable argument `b` - //[ast]~| NOTE cannot assign twice to immutable - //[mir]~| NOTE cannot assign to immutable argument +fn test_args(b: Box) { //~ HELP make this binding mutable + //~| SUGGESTION mut b + b = Box::new(2); //~ ERROR cannot assign to immutable argument `b` + //~| NOTE cannot assign to immutable argument } fn main() {} diff --git a/src/test/ui/issues/issue-45199.stderr b/src/test/ui/issues/issue-45199.stderr new file mode 100644 index 0000000000000..83b634051bb00 --- /dev/null +++ b/src/test/ui/issues/issue-45199.stderr @@ -0,0 +1,35 @@ +error[E0384]: cannot assign twice to immutable variable `b` + --> $DIR/issue-45199.rs:6:5 + | +LL | let b: Box; + | - help: make this binding mutable: `mut b` +... +LL | b = Box::new(1); + | - first assignment to `b` +LL | b = Box::new(2); + | ^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `b` + --> $DIR/issue-45199.rs:14:5 + | +LL | let b = Box::new(1); + | - + | | + | first assignment to `b` + | help: make this binding mutable: `mut b` +... +LL | b = Box::new(2); + | ^ cannot assign twice to immutable variable + +error[E0384]: cannot assign to immutable argument `b` + --> $DIR/issue-45199.rs:20:5 + | +LL | fn test_args(b: Box) { + | - help: make this binding mutable: `mut b` +LL | +LL | b = Box::new(2); + | ^ cannot assign to immutable argument + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/issues/issue-45296.stderr b/src/test/ui/issues/issue-45296.stderr index afea28fb7aaf8..bc14d20b62388 100644 --- a/src/test/ui/issues/issue-45296.stderr +++ b/src/test/ui/issues/issue-45296.stderr @@ -1,7 +1,7 @@ error: an inner attribute is not permitted in this context --> $DIR/issue-45296.rs:4:7 | -LL | #![allow(unused_variables)] //~ ERROR not permitted in this context +LL | #![allow(unused_variables)] | ^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. diff --git a/src/test/ui/issues/issue-45696-long-live-borrows-in-boxes.rs b/src/test/ui/issues/issue-45696-long-live-borrows-in-boxes.rs index 9f86caeaea9e9..b3f655628ba94 100644 --- a/src/test/ui/issues/issue-45696-long-live-borrows-in-boxes.rs +++ b/src/test/ui/issues/issue-45696-long-live-borrows-in-boxes.rs @@ -1,14 +1,5 @@ // rust-lang/rust#45696: This test is checking that we can return // mutable borrows owned by boxes even when the boxes are dropped. -// -// We will explicitly test AST-borrowck, NLL, and migration modes; -// thus we will also skip the automated compare-mode=nll. - -// revisions: ast nll migrate -// ignore-compare-mode-nll - -#![cfg_attr(nll, feature(nll))] -//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows // run-pass diff --git a/src/test/ui/issues/issue-45696-no-variant-box-recur.rs b/src/test/ui/issues/issue-45696-no-variant-box-recur.rs index 867da22221aee..c688261fa1cb1 100644 --- a/src/test/ui/issues/issue-45696-no-variant-box-recur.rs +++ b/src/test/ui/issues/issue-45696-no-variant-box-recur.rs @@ -1,16 +1,10 @@ -// rust-lang/rust#45696: This test checks the compiler won't infinite -// loop when you declare a variable of type `struct A(Box, ...);` -// (which is impossible to construct but *is* possible to declare; see -// also issues #4287, #44933, and #52852). +// rust-lang/rust#45696: This test checks the compiler won't infinite loop when +// you declare a variable of type `struct A(Box, ...);` (which is impossible +// to construct but *is* possible to declare; see also issues #4287, #44933, +// and #52852). // -// We will explicitly test AST-borrowck, NLL, and migration modes; -// thus we will also skip the automated compare-mode=nll. - -// revisions: ast nll migrate -// ignore-compare-mode-nll - -#![cfg_attr(nll, feature(nll))] -//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows +// We will explicitly test NLL, and migration modes; thus we will also skip the +// automated compare-mode=nll. // run-pass diff --git a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.ast.stderr b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.ast.stderr deleted file mode 100644 index 1992e32bf8406..0000000000000 --- a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.ast.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: compilation successful - --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:1 - | -LL | / fn main() { //[ast]~ ERROR compilation successful -LL | | //[migrate]~^ ERROR compilation successful -LL | | let mut x = 1; -LL | | { -... | -LL | | *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10; -LL | | } - | |_^ - -error: aborting due to previous error - diff --git a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.migrate.stderr b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.migrate.stderr index 129c6292b15a1..479b724ad18f1 100644 --- a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.migrate.stderr +++ b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.migrate.stderr @@ -1,9 +1,9 @@ warning[E0713]: borrow may still be in use when destructor runs - --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:53:5 + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:51:5 | LL | fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 { | -- lifetime `'a` defined here -LL | &mut *s.0 //[nll]~ ERROR borrow may still be in use when destructor runs [E0713] +LL | &mut *s.0 | ^^^^^^^^^ returning this value requires that `*s.0` is borrowed for `'a` ... LL | } @@ -11,13 +11,14 @@ LL | } | = warning: this error has been downgraded to a warning for backwards compatibility with previous releases = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` warning[E0713]: borrow may still be in use when destructor runs - --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:64:5 + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:62:5 | LL | fn boxed_scribbled<'a>(s: Box>) -> &'a mut u32 { | -- lifetime `'a` defined here -LL | &mut *(*s).0 //[nll]~ ERROR borrow may still be in use when destructor runs [E0713] +LL | &mut *(*s).0 | ^^^^^^^^^^^^ returning this value requires that `*s.0` is borrowed for `'a` ... LL | } @@ -25,13 +26,14 @@ LL | } | = warning: this error has been downgraded to a warning for backwards compatibility with previous releases = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` warning[E0713]: borrow may still be in use when destructor runs - --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:75:5 + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:73:5 | LL | fn boxed_boxed_scribbled<'a>(s: Box>>) -> &'a mut u32 { | -- lifetime `'a` defined here -LL | &mut *(**s).0 //[nll]~ ERROR borrow may still be in use when destructor runs [E0713] +LL | &mut *(**s).0 | ^^^^^^^^^^^^^ returning this value requires that `*s.0` is borrowed for `'a` ... LL | } @@ -39,14 +41,15 @@ LL | } | = warning: this error has been downgraded to a warning for backwards compatibility with previous releases = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` error: compilation successful - --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:1 + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:80:1 | -LL | / fn main() { //[ast]~ ERROR compilation successful -LL | | //[migrate]~^ ERROR compilation successful +LL | / fn main() { LL | | let mut x = 1; LL | | { +LL | | let mut long_lived = Scribble(&mut x); ... | LL | | *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10; LL | | } diff --git a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.nll.stderr b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.nll.stderr index 2cb07f0ad0013..1b9fb0499260c 100644 --- a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.nll.stderr +++ b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.nll.stderr @@ -1,31 +1,31 @@ error[E0713]: borrow may still be in use when destructor runs - --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:53:5 + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:51:5 | LL | fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 { | -- lifetime `'a` defined here -LL | &mut *s.0 //[nll]~ ERROR borrow may still be in use when destructor runs [E0713] +LL | &mut *s.0 | ^^^^^^^^^ returning this value requires that `*s.0` is borrowed for `'a` ... LL | } | - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait error[E0713]: borrow may still be in use when destructor runs - --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:64:5 + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:62:5 | LL | fn boxed_scribbled<'a>(s: Box>) -> &'a mut u32 { | -- lifetime `'a` defined here -LL | &mut *(*s).0 //[nll]~ ERROR borrow may still be in use when destructor runs [E0713] +LL | &mut *(*s).0 | ^^^^^^^^^^^^ returning this value requires that `*s.0` is borrowed for `'a` ... LL | } | - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait error[E0713]: borrow may still be in use when destructor runs - --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:75:5 + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:73:5 | LL | fn boxed_boxed_scribbled<'a>(s: Box>>) -> &'a mut u32 { | -- lifetime `'a` defined here -LL | &mut *(**s).0 //[nll]~ ERROR borrow may still be in use when destructor runs [E0713] +LL | &mut *(**s).0 | ^^^^^^^^^^^^^ returning this value requires that `*s.0` is borrowed for `'a` ... LL | } diff --git a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.rs b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.rs index fc56a2a8b70ad..f568efa487cd7 100644 --- a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.rs +++ b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.rs @@ -2,21 +2,19 @@ // mutable borrows that would be scribbled over by destructors before // the return occurs. // -// We will explicitly test AST-borrowck, NLL, and migration modes; +// We will explicitly test NLL, and migration modes; // thus we will also skip the automated compare-mode=nll. -// revisions: ast nll migrate +// revisions: nll migrate // ignore-compare-mode-nll -// This test is going to pass in the ast and migrate revisions, -// because the AST-borrowck accepted this code in the past (see notes -// below). So we use `#[rustc_error]` to keep the outcome as an error -// in all scenarios, and rely on the stderr files to show what the -// actual behavior is. (See rust-lang/rust#49855.) +// This test is going to pass in the migrate revision, because the AST-borrowck +// accepted this code in the past (see notes below). So we use `#[rustc_error]` +// to keep the outcome as an error in all scenarios, and rely on the stderr +// files to show what the actual behavior is. (See rust-lang/rust#49855.) #![feature(rustc_attrs)] #![cfg_attr(nll, feature(nll))] -//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows struct Scribble<'a>(&'a mut u32); @@ -79,8 +77,7 @@ fn boxed_boxed_scribbled<'a>(s: Box>>) -> &'a mut u32 { } #[rustc_error] -fn main() { //[ast]~ ERROR compilation successful - //[migrate]~^ ERROR compilation successful +fn main() { //[migrate]~ ERROR compilation successful let mut x = 1; { let mut long_lived = Scribble(&mut x); diff --git a/src/test/ui/issues/issue-45697-1.rs b/src/test/ui/issues/issue-45697-1.rs index c9b267ca5a10a..b45f1170b86c5 100644 --- a/src/test/ui/issues/issue-45697-1.rs +++ b/src/test/ui/issues/issue-45697-1.rs @@ -1,7 +1,7 @@ // Test that assignments to an `&mut` pointer which is found in a // borrowed (but otherwise non-aliasable) location is illegal. -// compile-flags: -Z borrowck=compare -C overflow-checks=on +// compile-flags: -C overflow-checks=on struct S<'a> { pointer: &'a mut isize @@ -18,9 +18,8 @@ fn main() { let mut y = S { pointer: &mut x }; let z = copy_borrowed_ptr(&mut y); *y.pointer += 1; - //~^ ERROR cannot assign to `*y.pointer` because it is borrowed (Ast) [E0506] - //~| ERROR cannot use `*y.pointer` because it was mutably borrowed (Mir) [E0503] - //~| ERROR cannot assign to `*y.pointer` because it is borrowed (Mir) [E0506] + //~^ ERROR cannot use `*y.pointer` because it was mutably borrowed [E0503] + //~| ERROR cannot assign to `*y.pointer` because it is borrowed [E0506] *z.pointer += 1; } } diff --git a/src/test/ui/issues/issue-45697-1.stderr b/src/test/ui/issues/issue-45697-1.stderr index 8d3907206081f..30c69f19658c8 100644 --- a/src/test/ui/issues/issue-45697-1.stderr +++ b/src/test/ui/issues/issue-45697-1.stderr @@ -1,12 +1,4 @@ -error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast) - --> $DIR/issue-45697-1.rs:20:9 - | -LL | let z = copy_borrowed_ptr(&mut y); - | - borrow of `*y.pointer` occurs here -LL | *y.pointer += 1; - | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here - -error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir) +error[E0503]: cannot use `*y.pointer` because it was mutably borrowed --> $DIR/issue-45697-1.rs:20:9 | LL | let z = copy_borrowed_ptr(&mut y); @@ -17,7 +9,7 @@ LL | *y.pointer += 1; LL | *z.pointer += 1; | --------------- borrow later used here -error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir) +error[E0506]: cannot assign to `*y.pointer` because it is borrowed --> $DIR/issue-45697-1.rs:20:9 | LL | let z = copy_borrowed_ptr(&mut y); @@ -28,7 +20,7 @@ LL | *y.pointer += 1; LL | *z.pointer += 1; | --------------- borrow later used here -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0503, E0506. +Some errors have detailed explanations: E0503, E0506. For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/issues/issue-45697.rs b/src/test/ui/issues/issue-45697.rs index 5bb30432fede4..db6d1d8fa2a92 100644 --- a/src/test/ui/issues/issue-45697.rs +++ b/src/test/ui/issues/issue-45697.rs @@ -1,7 +1,7 @@ // Test that assignments to an `&mut` pointer which is found in a // borrowed (but otherwise non-aliasable) location is illegal. -// compile-flags: -Z borrowck=compare -C overflow-checks=off +// compile-flags: -C overflow-checks=off struct S<'a> { pointer: &'a mut isize @@ -18,9 +18,8 @@ fn main() { let mut y = S { pointer: &mut x }; let z = copy_borrowed_ptr(&mut y); *y.pointer += 1; - //~^ ERROR cannot assign to `*y.pointer` because it is borrowed (Ast) [E0506] - //~| ERROR cannot use `*y.pointer` because it was mutably borrowed (Mir) [E0503] - //~| ERROR cannot assign to `*y.pointer` because it is borrowed (Mir) [E0506] + //~^ ERROR cannot use `*y.pointer` because it was mutably borrowed [E0503] + //~| ERROR cannot assign to `*y.pointer` because it is borrowed [E0506] *z.pointer += 1; } } diff --git a/src/test/ui/issues/issue-45697.stderr b/src/test/ui/issues/issue-45697.stderr index 5085d36febac3..26749d36f0b7b 100644 --- a/src/test/ui/issues/issue-45697.stderr +++ b/src/test/ui/issues/issue-45697.stderr @@ -1,12 +1,4 @@ -error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast) - --> $DIR/issue-45697.rs:20:9 - | -LL | let z = copy_borrowed_ptr(&mut y); - | - borrow of `*y.pointer` occurs here -LL | *y.pointer += 1; - | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here - -error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir) +error[E0503]: cannot use `*y.pointer` because it was mutably borrowed --> $DIR/issue-45697.rs:20:9 | LL | let z = copy_borrowed_ptr(&mut y); @@ -17,7 +9,7 @@ LL | *y.pointer += 1; LL | *z.pointer += 1; | --------------- borrow later used here -error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir) +error[E0506]: cannot assign to `*y.pointer` because it is borrowed --> $DIR/issue-45697.rs:20:9 | LL | let z = copy_borrowed_ptr(&mut y); @@ -28,7 +20,7 @@ LL | *y.pointer += 1; LL | *z.pointer += 1; | --------------- borrow later used here -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0503, E0506. +Some errors have detailed explanations: E0503, E0506. For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/issues/issue-45730.rs b/src/test/ui/issues/issue-45730.rs index 5709125e5f01b..3776759fe07a5 100644 --- a/src/test/ui/issues/issue-45730.rs +++ b/src/test/ui/issues/issue-45730.rs @@ -3,7 +3,7 @@ fn main() { let x: *const _ = 0 as _; //~ ERROR cannot cast let x: *const _ = 0 as *const _; //~ ERROR cannot cast - let y: Option<*const fmt::Debug> = Some(x) as _; + let y: Option<*const dyn fmt::Debug> = Some(x) as _; let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast } diff --git a/src/test/ui/issues/issue-45730.stderr b/src/test/ui/issues/issue-45730.stderr index 4f2784c6c362b..4fc1e3835f7ad 100644 --- a/src/test/ui/issues/issue-45730.stderr +++ b/src/test/ui/issues/issue-45730.stderr @@ -1,7 +1,7 @@ error[E0641]: cannot cast to a pointer of an unknown kind --> $DIR/issue-45730.rs:3:23 | -LL | let x: *const _ = 0 as _; //~ ERROR cannot cast +LL | let x: *const _ = 0 as _; | ^^^^^- | | | help: consider giving more type information @@ -11,7 +11,7 @@ LL | let x: *const _ = 0 as _; //~ ERROR cannot cast error[E0641]: cannot cast to a pointer of an unknown kind --> $DIR/issue-45730.rs:5:23 | -LL | let x: *const _ = 0 as *const _; //~ ERROR cannot cast +LL | let x: *const _ = 0 as *const _; | ^^^^^-------- | | | help: consider giving more type information @@ -21,7 +21,7 @@ LL | let x: *const _ = 0 as *const _; //~ ERROR cannot cast error[E0641]: cannot cast to a pointer of an unknown kind --> $DIR/issue-45730.rs:8:13 | -LL | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast +LL | let x = 0 as *const i32 as *const _ as *mut _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------ | | | help: consider giving more type information @@ -30,4 +30,3 @@ LL | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0641`. diff --git a/src/test/ui/issues/issue-45829/import-self.stderr b/src/test/ui/issues/issue-45829/import-self.stderr index 2a7277bd1e936..39522cd818392 100644 --- a/src/test/ui/issues/issue-45829/import-self.stderr +++ b/src/test/ui/issues/issue-45829/import-self.stderr @@ -41,5 +41,5 @@ LL | use foo::{self as OtherA}; error: aborting due to 4 previous errors -Some errors occurred: E0252, E0255, E0429. +Some errors have detailed explanations: E0252, E0255, E0429. For more information about an error, try `rustc --explain E0252`. diff --git a/src/test/ui/issues/issue-45829/import-twice.stderr b/src/test/ui/issues/issue-45829/import-twice.stderr index 2a1ac57651138..656b011bc3be8 100644 --- a/src/test/ui/issues/issue-45829/import-twice.stderr +++ b/src/test/ui/issues/issue-45829/import-twice.stderr @@ -2,10 +2,8 @@ error[E0252]: the name `A` is defined multiple times --> $DIR/import-twice.rs:6:14 | LL | use foo::{A, A}; - | ---^ - | || | - | || `A` reimported here - | |help: remove unnecessary import + | - ^ `A` reimported here + | | | previous import of the type `A` here | = note: `A` must be defined only once in the type namespace of this module diff --git a/src/test/ui/issues/issue-46023.ast.nll.stderr b/src/test/ui/issues/issue-46023.ast.nll.stderr deleted file mode 100644 index 05dbe42732b62..0000000000000 --- a/src/test/ui/issues/issue-46023.ast.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-46023.rs:8:9 - | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... -LL | x = 1; - | ^^^^^ cannot assign - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-46023.ast.stderr b/src/test/ui/issues/issue-46023.ast.stderr deleted file mode 100644 index ace48f8be6b29..0000000000000 --- a/src/test/ui/issues/issue-46023.ast.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0594]: cannot assign to captured outer variable in an `FnMut` closure - --> $DIR/issue-46023.rs:8:9 - | -LL | let x = 0; - | - help: consider making `x` mutable: `mut x` -... -LL | x = 1; - | ^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-46023.mir.stderr b/src/test/ui/issues/issue-46023.mir.stderr deleted file mode 100644 index 05dbe42732b62..0000000000000 --- a/src/test/ui/issues/issue-46023.mir.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-46023.rs:8:9 - | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... -LL | x = 1; - | ^^^^^ cannot assign - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-46023.rs b/src/test/ui/issues/issue-46023.rs index a9ecbbeea4751..a923eb2442101 100644 --- a/src/test/ui/issues/issue-46023.rs +++ b/src/test/ui/issues/issue-46023.rs @@ -1,12 +1,8 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - fn main() { let x = 0; (move || { x = 1; - //[mir]~^ ERROR cannot assign to `x`, as it is not declared as mutable [E0594] - //[ast]~^^ ERROR cannot assign to captured outer variable in an `FnMut` closure [E0594] + //~^ ERROR cannot assign to `x`, as it is not declared as mutable [E0594] })() } diff --git a/src/test/ui/issues/issue-46023.stderr b/src/test/ui/issues/issue-46023.stderr new file mode 100644 index 0000000000000..fac696c6fdcbf --- /dev/null +++ b/src/test/ui/issues/issue-46023.stderr @@ -0,0 +1,11 @@ +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/issue-46023.rs:5:9 + | +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +... +LL | x = 1; + | ^^^^^ cannot assign + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-46036.rs b/src/test/ui/issues/issue-46036.rs index c517bbe57e82b..18af33c1821c0 100644 --- a/src/test/ui/issues/issue-46036.rs +++ b/src/test/ui/issues/issue-46036.rs @@ -1,6 +1,5 @@ // Issue 46036: [NLL] false edges on infinite loops // Infinite loops should create false edges to the cleanup block. -#![feature(nll)] struct Foo { x: &'static u32 } diff --git a/src/test/ui/issues/issue-46036.stderr b/src/test/ui/issues/issue-46036.stderr index 40a77f925b94e..49dd0e267b8ea 100644 --- a/src/test/ui/issues/issue-46036.stderr +++ b/src/test/ui/issues/issue-46036.stderr @@ -1,7 +1,7 @@ error[E0597]: `a` does not live long enough - --> $DIR/issue-46036.rs:9:24 + --> $DIR/issue-46036.rs:8:24 | -LL | let foo = Foo { x: &a }; //~ ERROR E0597 +LL | let foo = Foo { x: &a }; | ^^ | | | borrowed value does not live long enough diff --git a/src/test/ui/issues/issue-46101.rs b/src/test/ui/issues/issue-46101.rs new file mode 100644 index 0000000000000..2d9111e9b3a98 --- /dev/null +++ b/src/test/ui/issues/issue-46101.rs @@ -0,0 +1,4 @@ +#![feature(use_extern_macros)] +trait Foo {} +#[derive(Foo::Anything)] //~ ERROR failed to resolve: partially resolved path in a derive macro +struct S; diff --git a/src/test/ui/issues/issue-46101.stderr b/src/test/ui/issues/issue-46101.stderr new file mode 100644 index 0000000000000..772d4bfeb30a7 --- /dev/null +++ b/src/test/ui/issues/issue-46101.stderr @@ -0,0 +1,14 @@ +error[E0433]: failed to resolve: partially resolved path in a derive macro + --> $DIR/issue-46101.rs:3:10 + | +LL | #[derive(Foo::Anything)] + | ^^^^^^^^^^^^^ partially resolved path in a derive macro + +error[E0601]: `main` function not found in crate `issue_46101` + | + = note: consider adding a `main` function to `$DIR/issue-46101.rs` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0433, E0601. +For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/ui/issues/issue-46311.stderr b/src/test/ui/issues/issue-46311.stderr index 8ceb1d62c25c7..d72d6477db649 100644 --- a/src/test/ui/issues/issue-46311.stderr +++ b/src/test/ui/issues/issue-46311.stderr @@ -1,7 +1,7 @@ error: invalid label name `'break` --> $DIR/issue-46311.rs:2:5 | -LL | 'break: loop { //~ ERROR invalid label name `'break` +LL | 'break: loop { | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-46438.stderr b/src/test/ui/issues/issue-46438.stderr index c670459c78166..c1fad44b885f1 100644 --- a/src/test/ui/issues/issue-46438.stderr +++ b/src/test/ui/issues/issue-46438.stderr @@ -1,7 +1,7 @@ error: expected a trait, found type --> $DIR/issue-46438.rs:11:4 | -LL | m!(&'static u8); //~ ERROR expected a trait, found type +LL | m!(&'static u8); | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-46471-1.rs b/src/test/ui/issues/issue-46471-1.rs index 3cf3f35284951..aa161d40f702d 100644 --- a/src/test/ui/issues/issue-46471-1.rs +++ b/src/test/ui/issues/issue-46471-1.rs @@ -1,11 +1,8 @@ -// compile-flags: -Z borrowck=compare - fn main() { let y = { let mut z = 0; &mut z }; - //~^^ ERROR `z` does not live long enough (Ast) [E0597] - //~| ERROR `z` does not live long enough (Mir) [E0597] + //~^^ ERROR `z` does not live long enough [E0597] println!("{}", y); } diff --git a/src/test/ui/issues/issue-46471-1.stderr b/src/test/ui/issues/issue-46471-1.stderr index 51026c9f2d834..b09f31729a5fd 100644 --- a/src/test/ui/issues/issue-46471-1.stderr +++ b/src/test/ui/issues/issue-46471-1.stderr @@ -1,16 +1,5 @@ -error[E0597]: `z` does not live long enough (Ast) - --> $DIR/issue-46471-1.rs:6:14 - | -LL | &mut z - | ^ borrowed value does not live long enough -LL | }; - | - `z` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here - -error[E0597]: `z` does not live long enough (Mir) - --> $DIR/issue-46471-1.rs:6:9 +error[E0597]: `z` does not live long enough + --> $DIR/issue-46471-1.rs:4:9 | LL | &mut z | ^^^^^^ @@ -20,6 +9,6 @@ LL | &mut z LL | }; | - `z` dropped here while still borrowed -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issues/issue-46471.rs b/src/test/ui/issues/issue-46471.rs index 0905c8bb1eb12..8922005d2f82c 100644 --- a/src/test/ui/issues/issue-46471.rs +++ b/src/test/ui/issues/issue-46471.rs @@ -1,10 +1,7 @@ -// compile-flags: -Z borrowck=compare - fn foo() -> &'static u32 { let x = 0; &x - //~^ ERROR `x` does not live long enough (Ast) [E0597] - //~| ERROR cannot return reference to local variable `x` (Mir) [E0515] + //~^ ERROR cannot return reference to local variable `x` [E0515] } fn main() { } diff --git a/src/test/ui/issues/issue-46471.stderr b/src/test/ui/issues/issue-46471.stderr index 903b6585e8a4c..935414c1f3f9d 100644 --- a/src/test/ui/issues/issue-46471.stderr +++ b/src/test/ui/issues/issue-46471.stderr @@ -1,21 +1,9 @@ -error[E0597]: `x` does not live long enough (Ast) - --> $DIR/issue-46471.rs:5:6 - | -LL | &x - | ^ borrowed value does not live long enough -... -LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... - -error[E0515]: cannot return reference to local variable `x` (Mir) - --> $DIR/issue-46471.rs:5:5 +error[E0515]: cannot return reference to local variable `x` + --> $DIR/issue-46471.rs:3:5 | LL | &x | ^^ returns a reference to data owned by the current function -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0515, E0597. -For more information about an error, try `rustc --explain E0515`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-46472.rs b/src/test/ui/issues/issue-46472.rs index 88f97e99aeaff..b9e20e8dbcb5f 100644 --- a/src/test/ui/issues/issue-46472.rs +++ b/src/test/ui/issues/issue-46472.rs @@ -1,9 +1,6 @@ -// compile-flags: -Z borrowck=compare - fn bar<'a>() -> &'a mut u32 { &mut 4 - //~^ ERROR borrowed value does not live long enough (Ast) [E0597] - //~| ERROR cannot return reference to temporary value (Mir) [E0515] + //~^ ERROR cannot return reference to temporary value [E0515] } fn main() { } diff --git a/src/test/ui/issues/issue-46472.stderr b/src/test/ui/issues/issue-46472.stderr index 2d81fa09cc278..6e561e03a8b7a 100644 --- a/src/test/ui/issues/issue-46472.stderr +++ b/src/test/ui/issues/issue-46472.stderr @@ -1,20 +1,5 @@ -error[E0597]: borrowed value does not live long enough (Ast) - --> $DIR/issue-46472.rs:4:10 - | -LL | &mut 4 - | ^ temporary value does not live long enough -... -LL | } - | - temporary value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 3:8... - --> $DIR/issue-46472.rs:3:8 - | -LL | fn bar<'a>() -> &'a mut u32 { - | ^^ - -error[E0515]: cannot return reference to temporary value (Mir) - --> $DIR/issue-46472.rs:4:5 +error[E0515]: cannot return reference to temporary value + --> $DIR/issue-46472.rs:2:5 | LL | &mut 4 | ^^^^^- @@ -22,7 +7,6 @@ LL | &mut 4 | | temporary value created here | returns a reference to data owned by the current function -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0515, E0597. -For more information about an error, try `rustc --explain E0515`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/issues/issue-46604.ast.nll.stderr b/src/test/ui/issues/issue-46604.ast.nll.stderr deleted file mode 100644 index 4f73a0f9d541d..0000000000000 --- a/src/test/ui/issues/issue-46604.ast.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0017]: references in statics may only refer to immutable values - --> $DIR/issue-46604.rs:4:25 - | -LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //[ast]~ ERROR E0017 - | ^^^^^^^^^^^^^^^^^^^^ statics require immutable values - -error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item - --> $DIR/issue-46604.rs:10:5 - | -LL | buf[0]=2; //[ast]~ ERROR E0389 - | ^^^^^^^^ cannot assign - -error: aborting due to 2 previous errors - -Some errors occurred: E0017, E0594. -For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/issues/issue-46604.ast.stderr b/src/test/ui/issues/issue-46604.ast.stderr deleted file mode 100644 index 14b9242ba0c3d..0000000000000 --- a/src/test/ui/issues/issue-46604.ast.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0017]: references in statics may only refer to immutable values - --> $DIR/issue-46604.rs:4:25 - | -LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //[ast]~ ERROR E0017 - | ^^^^^^^^^^^^^^^^^^^^ statics require immutable values - -error[E0389]: cannot assign to data in a `&` reference - --> $DIR/issue-46604.rs:10:5 - | -LL | buf[0]=2; //[ast]~ ERROR E0389 - | ^^^^^^^^ assignment into an immutable reference - -error: aborting due to 2 previous errors - -Some errors occurred: E0017, E0389. -For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/issues/issue-46604.mir.stderr b/src/test/ui/issues/issue-46604.mir.stderr deleted file mode 100644 index 4f73a0f9d541d..0000000000000 --- a/src/test/ui/issues/issue-46604.mir.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0017]: references in statics may only refer to immutable values - --> $DIR/issue-46604.rs:4:25 - | -LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //[ast]~ ERROR E0017 - | ^^^^^^^^^^^^^^^^^^^^ statics require immutable values - -error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item - --> $DIR/issue-46604.rs:10:5 - | -LL | buf[0]=2; //[ast]~ ERROR E0389 - | ^^^^^^^^ cannot assign - -error: aborting due to 2 previous errors - -Some errors occurred: E0017, E0594. -For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/issues/issue-46604.rs b/src/test/ui/issues/issue-46604.rs index 34fe3af3ab6ca..4f1ad38dbdd94 100644 --- a/src/test/ui/issues/issue-46604.rs +++ b/src/test/ui/issues/issue-46604.rs @@ -1,12 +1,7 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - -static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //[ast]~ ERROR E0017 - //[mir]~^ ERROR E0017 +static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0017 fn write>(buffer: T) { } fn main() { write(&buf); - buf[0]=2; //[ast]~ ERROR E0389 - //[mir]~^ ERROR E0594 + buf[0]=2; //~ ERROR E0594 } diff --git a/src/test/ui/issues/issue-46604.stderr b/src/test/ui/issues/issue-46604.stderr new file mode 100644 index 0000000000000..961b249daeb0c --- /dev/null +++ b/src/test/ui/issues/issue-46604.stderr @@ -0,0 +1,15 @@ +error[E0017]: references in statics may only refer to immutable values + --> $DIR/issue-46604.rs:1:25 + | +LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; + | ^^^^^^^^^^^^^^^^^^^^ statics require immutable values + +error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item + --> $DIR/issue-46604.rs:6:5 + | +LL | buf[0]=2; + | ^^^^^^^^ cannot assign + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0017`. diff --git a/src/test/ui/issues/issue-46771.stderr b/src/test/ui/issues/issue-46771.stderr index 3c9c679ece437..76c86d7aa907d 100644 --- a/src/test/ui/issues/issue-46771.stderr +++ b/src/test/ui/issues/issue-46771.stderr @@ -3,7 +3,7 @@ error[E0618]: expected function, found `main::Foo` | LL | struct Foo; | ----------- `main::Foo` defined here -LL | (1 .. 2).find(|_| Foo(0) == 0); //~ ERROR expected function, found `main::Foo` +LL | (1 .. 2).find(|_| Foo(0) == 0); | ^^^--- | | | call expression requires function diff --git a/src/test/ui/issues/issue-46843.rs b/src/test/ui/issues/issue-46843.rs index a310de624d271..aa252efea464b 100644 --- a/src/test/ui/issues/issue-46843.rs +++ b/src/test/ui/issues/issue-46843.rs @@ -4,7 +4,9 @@ fn non_const() -> Thing { Thing::This } -pub const Q: i32 = match non_const() { //~ ERROR E0015 +pub const Q: i32 = match non_const() { + //~^ ERROR E0015 + //~^^ ERROR unimplemented expression type Thing::This => 1, //~ ERROR unimplemented expression type Thing::That => 0 }; diff --git a/src/test/ui/issues/issue-46843.stderr b/src/test/ui/issues/issue-46843.stderr index d02561e4a2727..92ee154552c68 100644 --- a/src/test/ui/issues/issue-46843.stderr +++ b/src/test/ui/issues/issue-46843.stderr @@ -1,16 +1,22 @@ error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants --> $DIR/issue-46843.rs:7:26 | -LL | pub const Q: i32 = match non_const() { //~ ERROR E0015 +LL | pub const Q: i32 = match non_const() { | ^^^^^^^^^^^ error[E0019]: constant contains unimplemented expression type - --> $DIR/issue-46843.rs:8:5 + --> $DIR/issue-46843.rs:7:26 + | +LL | pub const Q: i32 = match non_const() { + | ^^^^^^^^^^^ + +error[E0019]: constant contains unimplemented expression type + --> $DIR/issue-46843.rs:10:5 | -LL | Thing::This => 1, //~ ERROR unimplemented expression type +LL | Thing::This => 1, | ^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -Some errors occurred: E0015, E0019. +Some errors have detailed explanations: E0015, E0019. For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/issues/issue-46983.rs b/src/test/ui/issues/issue-46983.rs index a5c1e17a58c3b..c1fd7729bdefb 100644 --- a/src/test/ui/issues/issue-46983.rs +++ b/src/test/ui/issues/issue-46983.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - fn foo(x: &u32) -> &'static u32 { &*x //~^ ERROR explicit lifetime required in the type of `x` [E0621] diff --git a/src/test/ui/issues/issue-46983.stderr b/src/test/ui/issues/issue-46983.stderr index 43d351ec905e3..8a4a6bdb39fa4 100644 --- a/src/test/ui/issues/issue-46983.stderr +++ b/src/test/ui/issues/issue-46983.stderr @@ -1,5 +1,5 @@ error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/issue-46983.rs:4:5 + --> $DIR/issue-46983.rs:2:5 | LL | fn foo(x: &u32) -> &'static u32 { | ---- help: add explicit lifetime `'static` to the type of `x`: `&'static u32` diff --git a/src/test/ui/issues/issue-47184.rs b/src/test/ui/issues/issue-47184.rs index 04f1146a8f8ff..2f78ce0002ba3 100644 --- a/src/test/ui/issues/issue-47184.rs +++ b/src/test/ui/issues/issue-47184.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - fn main() { let _vec: Vec<&'static String> = vec![&String::new()]; //~^ ERROR temporary value dropped while borrowed [E0716] diff --git a/src/test/ui/issues/issue-47184.stderr b/src/test/ui/issues/issue-47184.stderr index 2b4d576e726f8..f97713b4ac438 100644 --- a/src/test/ui/issues/issue-47184.stderr +++ b/src/test/ui/issues/issue-47184.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-47184.rs:4:44 + --> $DIR/issue-47184.rs:2:44 | LL | let _vec: Vec<&'static String> = vec![&String::new()]; | -------------------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement diff --git a/src/test/ui/issues/issue-4736.stderr b/src/test/ui/issues/issue-4736.stderr index 39c649ba3e0e7..257ec914a61ca 100644 --- a/src/test/ui/issues/issue-4736.stderr +++ b/src/test/ui/issues/issue-4736.stderr @@ -1,8 +1,13 @@ error[E0560]: struct `NonCopyable` has no field named `p` --> $DIR/issue-4736.rs:4:26 | -LL | let z = NonCopyable{ p: () }; //~ ERROR struct `NonCopyable` has no field named `p` - | ^ help: a field with a similar name exists: `0` +LL | struct NonCopyable(()); + | ----------- `NonCopyable` defined here +... +LL | let z = NonCopyable{ p: () }; + | ----------- ^ field does not exist + | | + | `NonCopyable` is a tuple struct, use the appropriate syntax: `NonCopyable(/* fields */)` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-47377.stderr b/src/test/ui/issues/issue-47377.stderr index 1e945727746e9..7d11a8c802128 100644 --- a/src/test/ui/issues/issue-47377.stderr +++ b/src/test/ui/issues/issue-47377.stderr @@ -1,8 +1,11 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` - --> $DIR/issue-47377.rs:4:12 + --> $DIR/issue-47377.rs:4:14 | LL | let _a = b + ", World!"; - | ^^^^^^^^^^^^^^ `+` can't be used to concatenate two `&str` strings + | - ^ ---------- &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let _a = b.to_owned() + ", World!"; diff --git a/src/test/ui/issues/issue-47380.stderr b/src/test/ui/issues/issue-47380.stderr index 84c5df3ca897b..89a154c5109d8 100644 --- a/src/test/ui/issues/issue-47380.stderr +++ b/src/test/ui/issues/issue-47380.stderr @@ -1,8 +1,11 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` - --> $DIR/issue-47380.rs:3:33 + --> $DIR/issue-47380.rs:3:35 | LL | println!("🦀🦀🦀🦀🦀"); let _a = b + ", World!"; - | ^^^^^^^^^^^^^^ `+` can't be used to concatenate two `&str` strings + | - ^ ---------- &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | println!("🦀🦀🦀🦀🦀"); let _a = b.to_owned() + ", World!"; diff --git a/src/test/ui/issues/issue-47623.stderr b/src/test/ui/issues/issue-47623.stderr index eb160ff86aec9..53968a2960ccd 100644 --- a/src/test/ui/issues/issue-47623.stderr +++ b/src/test/ui/issues/issue-47623.stderr @@ -1,7 +1,7 @@ error[E0429]: `self` imports are only allowed within a { } list --> $DIR/issue-47623.rs:1:5 | -LL | use self; //~ERROR `self` imports are only allowed within a { } list +LL | use self; | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-47646.rs b/src/test/ui/issues/issue-47646.rs index c3c07bf641161..ace6cdce841a7 100644 --- a/src/test/ui/issues/issue-47646.rs +++ b/src/test/ui/issues/issue-47646.rs @@ -1,6 +1,3 @@ -#![allow(warnings)] -#![feature(nll)] - use std::collections::BinaryHeap; fn main() { diff --git a/src/test/ui/issues/issue-47646.stderr b/src/test/ui/issues/issue-47646.stderr index c30fedeea73d8..c0b8763684806 100644 --- a/src/test/ui/issues/issue-47646.stderr +++ b/src/test/ui/issues/issue-47646.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `heap` as immutable because it is also borrowed as mutable - --> $DIR/issue-47646.rs:12:30 + --> $DIR/issue-47646.rs:9:30 | LL | let borrow = heap.peek_mut(); | ---- mutable borrow occurs here @@ -7,7 +7,7 @@ LL | LL | match (borrow, ()) { | ------------ a temporary with access to the mutable borrow is created here ... LL | (Some(_), ()) => { -LL | println!("{:?}", heap); //~ ERROR cannot borrow `heap` as immutable +LL | println!("{:?}", heap); | ^^^^ immutable borrow occurs here ... LL | }; diff --git a/src/test/ui/issues/issue-47703-1.rs b/src/test/ui/issues/issue-47703-1.rs index 9add314fdaf09..74323317f1956 100644 --- a/src/test/ui/issues/issue-47703-1.rs +++ b/src/test/ui/issues/issue-47703-1.rs @@ -1,6 +1,4 @@ // compile-pass -#![allow(dead_code)] -#![feature(nll)] struct AtomicRefMut<'a> { value: &'a mut i32, diff --git a/src/test/ui/issues/issue-47703-tuple.rs b/src/test/ui/issues/issue-47703-tuple.rs index 850771cffd0cf..377eeb67ae1b9 100644 --- a/src/test/ui/issues/issue-47703-tuple.rs +++ b/src/test/ui/issues/issue-47703-tuple.rs @@ -1,6 +1,4 @@ // compile-pass -#![allow(dead_code)] -#![feature(nll)] struct WithDrop; diff --git a/src/test/ui/issues/issue-47703.rs b/src/test/ui/issues/issue-47703.rs index 06b17e931a974..22f2a1f364d1d 100644 --- a/src/test/ui/issues/issue-47703.rs +++ b/src/test/ui/issues/issue-47703.rs @@ -1,6 +1,4 @@ // compile-pass -#![allow(dead_code)] -#![feature(nll)] struct MyStruct<'a> { field: &'a mut (), diff --git a/src/test/ui/issues/issue-47722.rs b/src/test/ui/issues/issue-47722.rs index c9bc6147aa9ca..cefc872668ceb 100644 --- a/src/test/ui/issues/issue-47722.rs +++ b/src/test/ui/issues/issue-47722.rs @@ -1,10 +1,8 @@ // compile-pass -#![allow(dead_code)] // Tests that automatic coercions from &mut T to *mut T // allow borrows of T to expire immediately - essentially, that // they work identically to 'foo as *mut T' -#![feature(nll)] struct SelfReference { self_reference: *mut SelfReference, diff --git a/src/test/ui/issues/issue-47789.rs b/src/test/ui/issues/issue-47789.rs index d15a27a2a2e65..334bd608add15 100644 --- a/src/test/ui/issues/issue-47789.rs +++ b/src/test/ui/issues/issue-47789.rs @@ -1,9 +1,6 @@ // compile-pass -#![allow(dead_code)] #![allow(non_upper_case_globals)] -#![feature(nll)] - static mut x: &'static u32 = &0; fn foo() { diff --git a/src/test/ui/issues/issue-48131.stderr b/src/test/ui/issues/issue-48131.stderr index 6e454173f8bc0..adc36e266c271 100644 --- a/src/test/ui/issues/issue-48131.stderr +++ b/src/test/ui/issues/issue-48131.stderr @@ -1,19 +1,19 @@ error: unnecessary `unsafe` block --> $DIR/issue-48131.rs:8:9 | -LL | unsafe { /* unnecessary */ } //~ ERROR unnecessary `unsafe` +LL | unsafe { /* unnecessary */ } | ^^^^^^ unnecessary `unsafe` block | note: lint level defined here --> $DIR/issue-48131.rs:3:9 | -LL | #![deny(unused_unsafe)] //~ NOTE +LL | #![deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block --> $DIR/issue-48131.rs:19:13 | -LL | unsafe { /* unnecessary */ } //~ ERROR unnecessary `unsafe` +LL | unsafe { /* unnecessary */ } | ^^^^^^ unnecessary `unsafe` block error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-48132.rs b/src/test/ui/issues/issue-48132.rs index b3cef78f3e6b4..ea325ea695f66 100644 --- a/src/test/ui/issues/issue-48132.rs +++ b/src/test/ui/issues/issue-48132.rs @@ -3,9 +3,6 @@ // run-pass -#![feature(nll)] -#![allow(warnings)] - struct Inner { iterator: I, item: V, diff --git a/src/test/ui/issues/issue-48179.rs b/src/test/ui/issues/issue-48179.rs index 245f13b2b609d..90e9858d74197 100644 --- a/src/test/ui/issues/issue-48179.rs +++ b/src/test/ui/issues/issue-48179.rs @@ -3,9 +3,6 @@ // run-pass -#![feature(nll)] -#![allow(warnings)] - pub struct Container { value: Option, } diff --git a/src/test/ui/issues/issue-48728.stderr b/src/test/ui/issues/issue-48728.stderr index e2f549ac4256c..99a9bf9903e25 100644 --- a/src/test/ui/issues/issue-48728.stderr +++ b/src/test/ui/issues/issue-48728.stderr @@ -1,7 +1,7 @@ error[E0119]: conflicting implementations of trait `std::clone::Clone` for type `Node<[_]>`: --> $DIR/issue-48728.rs:4:10 | -LL | #[derive(Clone)] //~ ERROR conflicting implementations of trait `std::clone::Clone` +LL | #[derive(Clone)] | ^^^^^ conflicting implementation for `Node<[_]>` ... LL | impl Clone for Node<[T]> { diff --git a/src/test/ui/issues/issue-48803.rs b/src/test/ui/issues/issue-48803.rs index bc1bc29c98f2e..f7fd04179f26e 100644 --- a/src/test/ui/issues/issue-48803.rs +++ b/src/test/ui/issues/issue-48803.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - fn flatten<'a, 'b, T>(x: &'a &'b T) -> &'a T { x } diff --git a/src/test/ui/issues/issue-48803.stderr b/src/test/ui/issues/issue-48803.stderr index 2635520ef0786..2f94039c0c3a9 100644 --- a/src/test/ui/issues/issue-48803.stderr +++ b/src/test/ui/issues/issue-48803.stderr @@ -1,12 +1,12 @@ error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/issue-48803.rs:12:5 + --> $DIR/issue-48803.rs:10:5 | LL | let y = &x; | -- borrow of `x` occurs here ... LL | x = "modified"; | ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here -LL | //~^ ERROR cannot assign to `x` because it is borrowed [E0506] +LL | LL | println!("{}", w); // prints "modified" | - borrow later used here diff --git a/src/test/ui/issues/issue-48838.stderr b/src/test/ui/issues/issue-48838.stderr index 32eea5e5fbb8f..3007d67336b50 100644 --- a/src/test/ui/issues/issue-48838.stderr +++ b/src/test/ui/issues/issue-48838.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-48838.rs:2:14 | -LL | Square = |x| x, //~ ERROR mismatched types +LL | Square = |x| x, | ^^^^^ expected isize, found closure | = note: expected type `isize` diff --git a/src/test/ui/issues/issue-49040.stderr b/src/test/ui/issues/issue-49040.stderr index 12e78e2f3bc95..de78b8d3c14af 100644 --- a/src/test/ui/issues/issue-49040.stderr +++ b/src/test/ui/issues/issue-49040.stderr @@ -1,7 +1,7 @@ error: expected item, found `;` --> $DIR/issue-49040.rs:1:28 | -LL | #![allow(unused_variables)]; //~ ERROR expected item, found `;` +LL | #![allow(unused_variables)]; | ^ help: remove this semicolon error[E0601]: `main` function not found in crate `issue_49040` diff --git a/src/test/ui/issues/issue-49074.stderr b/src/test/ui/issues/issue-49074.stderr index a25d8ee352686..29e10f1bf41c7 100644 --- a/src/test/ui/issues/issue-49074.stderr +++ b/src/test/ui/issues/issue-49074.stderr @@ -1,15 +1,16 @@ -error[E0658]: The attribute `marco_use` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `marco_use` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/issue-49074.rs:3:3 | LL | #[marco_use] // typo | ^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_use` | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: cannot find macro `bar!` in this scope --> $DIR/issue-49074.rs:12:4 | -LL | bar!(); //~ ERROR cannot find macro `bar!` in this scope +LL | bar!(); | ^^^ | = help: have you added the `#[macro_use]` on the module/import? diff --git a/src/test/ui/issues/issue-49257.stderr b/src/test/ui/issues/issue-49257.stderr index 0bccfbbf7e5a2..43a505cfe85f8 100644 --- a/src/test/ui/issues/issue-49257.stderr +++ b/src/test/ui/issues/issue-49257.stderr @@ -1,33 +1,33 @@ error: expected `}`, found `,` --> $DIR/issue-49257.rs:10:19 | -LL | let Point { .., y, } = p; //~ ERROR expected `}`, found `,` +LL | let Point { .., y, } = p; | --^ | | | | | expected `}` | `..` must be at the end and cannot have a trailing comma help: move the `..` to the end of the field list | -LL | let Point { y, .. } = p; //~ ERROR expected `}`, found `,` +LL | let Point { y, .. } = p; | -- ^^^^ error: expected `}`, found `,` --> $DIR/issue-49257.rs:11:19 | -LL | let Point { .., y } = p; //~ ERROR expected `}`, found `,` +LL | let Point { .., y } = p; | --^ | | | | | expected `}` | `..` must be at the end and cannot have a trailing comma help: move the `..` to the end of the field list | -LL | let Point { y , .. } = p; //~ ERROR expected `}`, found `,` +LL | let Point { y , .. } = p; | -- ^^^^^^ error: expected `}`, found `,` --> $DIR/issue-49257.rs:12:19 | -LL | let Point { .., } = p; //~ ERROR expected `}`, found `,` +LL | let Point { .., } = p; | --^ | | | | | expected `}` diff --git a/src/test/ui/issues/issue-4935.stderr b/src/test/ui/issues/issue-4935.stderr index 42869ab483180..a99581fdca18f 100644 --- a/src/test/ui/issues/issue-4935.stderr +++ b/src/test/ui/issues/issue-4935.stderr @@ -3,7 +3,7 @@ error[E0061]: this function takes 1 parameter but 2 parameters were supplied | LL | fn foo(a: usize) {} | ---------------- defined here -LL | //~^ defined here +LL | LL | fn main() { foo(5, 6) } | ^^^^^^^^^ expected 1 parameter diff --git a/src/test/ui/issues/issue-49556.rs b/src/test/ui/issues/issue-49556.rs index b8fcc645a59d3..46d9e749aae23 100644 --- a/src/test/ui/issues/issue-49556.rs +++ b/src/test/ui/issues/issue-49556.rs @@ -2,10 +2,10 @@ fn iter<'a>(data: &'a [usize]) -> impl Iterator + 'a { data.iter() .map( - |x| x // fn(&'a usize) -> &'(ReScope) usize + |x| x // fn(&'a usize) -> &'a usize ) .map( - |x| *x // fn(&'(ReScope) usize) -> usize + |x| *x // fn(&'a usize) -> usize ) } diff --git a/src/test/ui/issues/issue-49579.rs b/src/test/ui/issues/issue-49579.rs index 34f277af01e97..dd7b9eeb8d54e 100644 --- a/src/test/ui/issues/issue-49579.rs +++ b/src/test/ui/issues/issue-49579.rs @@ -1,8 +1,6 @@ // compile-pass // ignore-emscripten no i128 support -#![feature(nll)] - fn fibs(n: u32) -> impl Iterator { (0 .. n) .scan((0, 1), |st, _| { diff --git a/src/test/ui/issues/issue-4972.rs b/src/test/ui/issues/issue-4972.rs index 9c95a9794766b..fab258f137e68 100644 --- a/src/test/ui/issues/issue-4972.rs +++ b/src/test/ui/issues/issue-4972.rs @@ -6,10 +6,10 @@ trait MyTrait { } pub enum TraitWrapper { - A(Box), + A(Box), } -fn get_tw_map(tw: &TraitWrapper) -> &MyTrait { +fn get_tw_map(tw: &TraitWrapper) -> &dyn MyTrait { match *tw { TraitWrapper::A(box ref map) => map, //~ ERROR cannot be dereferenced } diff --git a/src/test/ui/issues/issue-4972.stderr b/src/test/ui/issues/issue-4972.stderr index 30664c90ce811..b1947e2a9dfff 100644 --- a/src/test/ui/issues/issue-4972.stderr +++ b/src/test/ui/issues/issue-4972.stderr @@ -1,7 +1,7 @@ error[E0033]: type `std::boxed::Box<(dyn MyTrait + 'static)>` cannot be dereferenced --> $DIR/issue-4972.rs:14:25 | -LL | TraitWrapper::A(box ref map) => map, //~ ERROR cannot be dereferenced +LL | TraitWrapper::A(box ref map) => map, | ^^^^^^^^^^^ type `std::boxed::Box<(dyn MyTrait + 'static)>` cannot be dereferenced error: aborting due to previous error diff --git a/src/test/ui/issues/issue-49824.nll.stderr b/src/test/ui/issues/issue-49824.nll.stderr index 4e2f3f59a6445..9c6f8d4532a70 100644 --- a/src/test/ui/issues/issue-49824.nll.stderr +++ b/src/test/ui/issues/issue-49824.nll.stderr @@ -1,29 +1,18 @@ -warning: captured variable cannot escape `FnMut` closure body - --> $DIR/issue-49824.rs:12:9 +error: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-49824.rs:10:9 | LL | || { | - inferred to be a `FnMut` closure LL | / || { +LL | | +LL | | +LL | | LL | | let _y = &mut x; LL | | } | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body | = note: `FnMut` closures only have access to their captured variables while they are executing... = note: ...therefore, they cannot allow references to captured variables to escape - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - -error: compilation successful - --> $DIR/issue-49824.rs:8:1 - | -LL | / fn main() { -LL | | //~^ compilation successful -LL | | let mut x = 0; -LL | | || { -... | -LL | | }; -LL | | } - | |_^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-49824.rs b/src/test/ui/issues/issue-49824.rs index 58cada5d31ea0..b0d01b3d98d51 100644 --- a/src/test/ui/issues/issue-49824.rs +++ b/src/test/ui/issues/issue-49824.rs @@ -1,15 +1,16 @@ #![feature(rustc_attrs)] -// This test checks that a failure occurs with NLL but does not fail with the -// legacy AST output. Check issue-49824.nll.stderr for expected compilation error -// output under NLL and #49824 for more information. +// This test checks that a warning occurs with migrate mode. #[rustc_error] fn main() { - //~^ compilation successful + //~^ ERROR compilation successful let mut x = 0; || { || { + //~^ WARNING captured variable cannot escape `FnMut` closure body + //~| WARNING this error has been downgraded to a warning + //~| WARNING this warning will become a hard error in the future let _y = &mut x; } }; diff --git a/src/test/ui/issues/issue-49824.stderr b/src/test/ui/issues/issue-49824.stderr index f487c363ea674..d5f1af88e133a 100644 --- a/src/test/ui/issues/issue-49824.stderr +++ b/src/test/ui/issues/issue-49824.stderr @@ -1,8 +1,27 @@ +warning: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-49824.rs:10:9 + | +LL | || { + | - inferred to be a `FnMut` closure +LL | / || { +LL | | +LL | | +LL | | +LL | | let _y = &mut x; +LL | | } + | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + error: compilation successful - --> $DIR/issue-49824.rs:8:1 + --> $DIR/issue-49824.rs:6:1 | LL | / fn main() { -LL | | //~^ compilation successful +LL | | LL | | let mut x = 0; LL | | || { ... | diff --git a/src/test/ui/issues/issue-49851/compiler-builtins-error.rs b/src/test/ui/issues/issue-49851/compiler-builtins-error.rs index 0163da0771e9b..3484ff3b87432 100644 --- a/src/test/ui/issues/issue-49851/compiler-builtins-error.rs +++ b/src/test/ui/issues/issue-49851/compiler-builtins-error.rs @@ -8,4 +8,3 @@ #![no_std] extern crate cortex_m; - diff --git a/src/test/ui/issues/issue-49934.stderr b/src/test/ui/issues/issue-49934.stderr index 295f4f1b559a7..6ca751a47c47d 100644 --- a/src/test/ui/issues/issue-49934.stderr +++ b/src/test/ui/issues/issue-49934.stderr @@ -9,31 +9,31 @@ LL | #[derive(Debug)] warning: unused attribute --> $DIR/issue-49934.rs:6:8 | -LL | fn foo<#[derive(Debug)] T>() { //~ WARN unused attribute +LL | fn foo<#[derive(Debug)] T>() { | ^^^^^^^^^^^^^^^^ | note: lint level defined here --> $DIR/issue-49934.rs:4:9 | -LL | #![warn(unused_attributes)] //~ NOTE lint level defined here +LL | #![warn(unused_attributes)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute --> $DIR/issue-49934.rs:8:9 | -LL | #[derive(Debug)] //~ WARN unused attribute +LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ warning: unused attribute --> $DIR/issue-49934.rs:26:5 | -LL | #[derive(Debug)] //~ WARN unused attribute +LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ warning: unused attribute --> $DIR/issue-49934.rs:30:5 | -LL | #[derive(Debug)] //~ WARN unused attribute +LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ warning: unused attribute @@ -45,6 +45,6 @@ LL | let _ = #[derive(Debug)] "Hello, world!"; warning: unused attribute --> $DIR/issue-49934.rs:39:9 | -LL | #[derive(Debug)] //~ WARN unused attribute +LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-deref-err.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-deref-err.stderr index 96d6814b0fe93..333036127eadb 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-deref-err.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-deref-err.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `deref_err` found for type `std::result::Result<_, --> $DIR/result-deref-err.rs:4:28 | LL | let _result = &Err(41).deref_err(); - | ^^^^^^^^^ help: did you mean: `deref_ok` + | ^^^^^^^^^ help: there is a method with a similar name: `deref_ok` | = note: the method `deref_err` exists but the following trait bounds were not satisfied: `{integer} : std::ops::Deref` diff --git a/src/test/ui/issues/issue-50403.stderr b/src/test/ui/issues/issue-50403.stderr index f84d9d7769daf..d20a98ecc6ad5 100644 --- a/src/test/ui/issues/issue-50403.stderr +++ b/src/test/ui/issues/issue-50403.stderr @@ -1,7 +1,7 @@ error: concat_idents! takes 1 or more arguments. --> $DIR/issue-50403.rs:4:13 | -LL | let x = concat_idents!(); //~ ERROR concat_idents! takes 1 or more arguments +LL | let x = concat_idents!(); | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50480.stderr b/src/test/ui/issues/issue-50480.stderr index 240a0f2228648..9022bfae509f5 100644 --- a/src/test/ui/issues/issue-50480.stderr +++ b/src/test/ui/issues/issue-50480.stderr @@ -18,7 +18,7 @@ error[E0204]: the trait `Copy` may not be implemented for this type | LL | #[derive(Clone, Copy)] | ^^^^ -LL | //~^ ERROR the trait `Copy` may not be implemented for this type +LL | LL | struct Foo(NotDefined, ::Item, Vec, String); | -------- ------ this field does not implement `Copy` | | @@ -26,5 +26,5 @@ LL | struct Foo(NotDefined, ::Item, Vec, String); error: aborting due to 3 previous errors -Some errors occurred: E0204, E0277, E0412. +Some errors have detailed explanations: E0204, E0277, E0412. For more information about an error, try `rustc --explain E0204`. diff --git a/src/test/ui/issues/issue-50518.rs b/src/test/ui/issues/issue-50518.rs new file mode 100644 index 0000000000000..d776d181b6268 --- /dev/null +++ b/src/test/ui/issues/issue-50518.rs @@ -0,0 +1,40 @@ +// compile-pass +use std::marker::PhantomData; + +struct Meta { + value: i32, + type_: PhantomData +} + +trait MetaTrait { + fn get_value(&self) -> i32; +} + +impl MetaTrait for Meta { + fn get_value(&self) -> i32 { self.value } +} + +trait Bar { + fn get_const(&self) -> &dyn MetaTrait; +} + +struct Foo { + _value: A +} + +impl Foo { + const CONST: &'static dyn MetaTrait = &Meta:: { + value: 10, + type_: PhantomData + }; +} + +impl Bar for Foo { + fn get_const(&self) -> &dyn MetaTrait { Self::CONST } +} + +fn main() { + let foo = Foo:: { _value: 10 }; + let bar: &dyn Bar = &foo; + println!("const {}", bar.get_const().get_value()); +} diff --git a/src/test/ui/issues/issue-50576.stderr b/src/test/ui/issues/issue-50576.stderr index 98624d141a616..95619eeed9a46 100644 --- a/src/test/ui/issues/issue-50576.stderr +++ b/src/test/ui/issues/issue-50576.stderr @@ -13,10 +13,10 @@ LL | |bool: [u8; break 'L]| 0; error[E0268]: `break` outside of loop --> $DIR/issue-50576.rs:5:16 | -LL | Vec::<[u8; break]>::new(); //~ ERROR [E0268] +LL | Vec::<[u8; break]>::new(); | ^^^^^ cannot break outside of a loop error: aborting due to 3 previous errors -Some errors occurred: E0268, E0426. +Some errors have detailed explanations: E0268, E0426. For more information about an error, try `rustc --explain E0268`. diff --git a/src/test/ui/issues/issue-50577.rs b/src/test/ui/issues/issue-50577.rs index f0f1dc6c28667..bf892a8daa27f 100644 --- a/src/test/ui/issues/issue-50577.rs +++ b/src/test/ui/issues/issue-50577.rs @@ -2,5 +2,6 @@ fn main() { enum Foo { Drop = assert_eq!(1, 1) //~^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] } } diff --git a/src/test/ui/issues/issue-50577.stderr b/src/test/ui/issues/issue-50577.stderr index f26f5a9a9ba22..413c8c5c80b52 100644 --- a/src/test/ui/issues/issue-50577.stderr +++ b/src/test/ui/issues/issue-50577.stderr @@ -1,13 +1,29 @@ +error[E0308]: mismatched types + --> $DIR/issue-50577.rs:3:16 + | +LL | Drop = assert_eq!(1, 1) + | ^^^^^^^^^^^^^^^^ expected isize, found () + | + = note: expected type `isize` + found type `()` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + error[E0317]: if may be missing an else clause --> $DIR/issue-50577.rs:3:16 | LL | Drop = assert_eq!(1, 1) - | ^^^^^^^^^^^^^^^^ expected (), found isize + | ^^^^^^^^^^^^^^^^ + | | + | expected (), found isize + | found here | = note: expected type `()` found type `isize` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0317`. +Some errors have detailed explanations: E0308, E0317. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-50581.stderr b/src/test/ui/issues/issue-50581.stderr index 70ac9ecc9edf5..01a5f9b3c4432 100644 --- a/src/test/ui/issues/issue-50581.stderr +++ b/src/test/ui/issues/issue-50581.stderr @@ -1,7 +1,7 @@ error[E0268]: `break` outside of loop --> $DIR/issue-50581.rs:2:14 | -LL | |_: [u8; break]| (); //~ ERROR [E0268] +LL | |_: [u8; break]| (); | ^^^^^ cannot break outside of a loop error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50582.rs b/src/test/ui/issues/issue-50582.rs new file mode 100644 index 0000000000000..1358e0bde4c82 --- /dev/null +++ b/src/test/ui/issues/issue-50582.rs @@ -0,0 +1,4 @@ +fn main() { + Vec::<[(); 1 + for x in 0..1 {}]>::new(); + //~^ ERROR cannot add +} diff --git a/src/test/ui/issues/issue-50582.stderr b/src/test/ui/issues/issue-50582.stderr new file mode 100644 index 0000000000000..226f5a3f0fed2 --- /dev/null +++ b/src/test/ui/issues/issue-50582.stderr @@ -0,0 +1,11 @@ +error[E0277]: cannot add `()` to `{integer}` + --> $DIR/issue-50582.rs:2:18 + | +LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); + | ^ no implementation for `{integer} + ()` + | + = help: the trait `std::ops::Add<()>` is not implemented for `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-50599.stderr b/src/test/ui/issues/issue-50599.stderr index cf2f309340de7..4bd74c3c785fe 100644 --- a/src/test/ui/issues/issue-50599.stderr +++ b/src/test/ui/issues/issue-50599.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `LOG10_2` in module `std::f64` --> $DIR/issue-50599.rs:3:48 | -LL | const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize; //~ ERROR cannot find value +LL | const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize; | ^^^^^^^ not found in `std::f64` help: possible candidates are found in other modules, you can import them into scope | @@ -18,5 +18,5 @@ LL | let mut digits = [0u32; M]; error: aborting due to 2 previous errors -Some errors occurred: E0080, E0425. +Some errors have detailed explanations: E0080, E0425. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/issues/issue-50600.stderr b/src/test/ui/issues/issue-50600.stderr index 36219390c519e..2d97c2781c2d1 100644 --- a/src/test/ui/issues/issue-50600.stderr +++ b/src/test/ui/issues/issue-50600.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-50600.rs:2:13 | -LL | fn([u8; |x: u8| {}]), //~ ERROR mismatched types +LL | fn([u8; |x: u8| {}]), | ^^^^^^^^^^ expected usize, found closure | = note: expected type `usize` diff --git a/src/test/ui/issues/issue-50688.stderr b/src/test/ui/issues/issue-50688.stderr index 2a1315c9a015d..13eec8361ba8a 100644 --- a/src/test/ui/issues/issue-50688.stderr +++ b/src/test/ui/issues/issue-50688.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-50688.rs:2:9 | -LL | [1; || {}]; //~ ERROR mismatched types +LL | [1; || {}]; | ^^^^^ expected usize, found closure | = note: expected type `usize` diff --git a/src/test/ui/issues/issue-50714-1.rs b/src/test/ui/issues/issue-50714-1.rs index 31de3f3c0a1b8..a25940ce1cbef 100644 --- a/src/test/ui/issues/issue-50714-1.rs +++ b/src/test/ui/issues/issue-50714-1.rs @@ -9,4 +9,3 @@ extern crate std; fn start(_: isize, _: *const *const u8) -> isize where fn(&()): Eq { //~ ERROR [E0647] 0 } - diff --git a/src/test/ui/issues/issue-50714-1.stderr b/src/test/ui/issues/issue-50714-1.stderr index e5fdd18d3328e..28469bee01714 100644 --- a/src/test/ui/issues/issue-50714-1.stderr +++ b/src/test/ui/issues/issue-50714-1.stderr @@ -1,8 +1,8 @@ error[E0647]: start function is not allowed to have a `where` clause - --> $DIR/issue-50714-1.rs:9:56 + --> $DIR/issue-50714-1.rs:9:50 | -LL | fn start(_: isize, _: *const *const u8) -> isize where fn(&()): Eq { //~ ERROR [E0647] - | ^^^^^^^^^^^ start function cannot have a `where` clause +LL | fn start(_: isize, _: *const *const u8) -> isize where fn(&()): Eq { + | ^^^^^^^^^^^^^^^^^ start function cannot have a `where` clause error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50714.rs b/src/test/ui/issues/issue-50714.rs index 3683d4bdaccd5..c571a470cee1c 100644 --- a/src/test/ui/issues/issue-50714.rs +++ b/src/test/ui/issues/issue-50714.rs @@ -1,4 +1,3 @@ // Regression test for issue 50714, make sure that this isn't a linker error. fn main() where fn(&()): Eq {} //~ ERROR [E0646] - diff --git a/src/test/ui/issues/issue-50714.stderr b/src/test/ui/issues/issue-50714.stderr index d7631adc7b26f..a11aceb6211c5 100644 --- a/src/test/ui/issues/issue-50714.stderr +++ b/src/test/ui/issues/issue-50714.stderr @@ -1,8 +1,8 @@ error[E0646]: `main` function is not allowed to have a `where` clause - --> $DIR/issue-50714.rs:3:17 + --> $DIR/issue-50714.rs:3:11 | -LL | fn main() where fn(&()): Eq {} //~ ERROR [E0646] - | ^^^^^^^^^^^ `main` cannot have a `where` clause +LL | fn main() where fn(&()): Eq {} + | ^^^^^^^^^^^^^^^^^ `main` cannot have a `where` clause error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50761.rs b/src/test/ui/issues/issue-50761.rs index bcf3ebcd60a5e..70b4bc8b755aa 100644 --- a/src/test/ui/issues/issue-50761.rs +++ b/src/test/ui/issues/issue-50761.rs @@ -14,7 +14,7 @@ mod b { } impl Builder { - pub fn with_a(&mut self, _a: fn() -> ::a::A) {} + pub fn with_a(&mut self, _a: fn() -> dyn (::a::A)) {} } } diff --git a/src/test/ui/issues/issue-50781.rs b/src/test/ui/issues/issue-50781.rs index edf8d82b48050..3c5e5a9f69af0 100644 --- a/src/test/ui/issues/issue-50781.rs +++ b/src/test/ui/issues/issue-50781.rs @@ -15,5 +15,5 @@ impl Trait for dyn X {} pub fn main() { // Check that this does not segfault. - ::foo(&()); + ::foo(&()); } diff --git a/src/test/ui/issues/issue-50781.stderr b/src/test/ui/issues/issue-50781.stderr index 11de59f9f0095..c98f78c51ee5f 100644 --- a/src/test/ui/issues/issue-50781.stderr +++ b/src/test/ui/issues/issue-50781.stderr @@ -1,7 +1,7 @@ error: the trait `X` cannot be made into an object --> $DIR/issue-50781.rs:6:5 | -LL | fn foo(&self) where Self: Trait; //~ ERROR the trait `X` cannot be made into an object +LL | fn foo(&self) where Self: Trait; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/issues/issue-50802.stderr b/src/test/ui/issues/issue-50802.stderr index 9a2ae79429397..e064fabccd045 100644 --- a/src/test/ui/issues/issue-50802.stderr +++ b/src/test/ui/issues/issue-50802.stderr @@ -1,7 +1,7 @@ error[E0590]: `break` or `continue` with no label in the condition of a `while` loop --> $DIR/issue-50802.rs:5:21 | -LL | break while continue { //~ ERROR E0590 +LL | break while continue { | ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5099.stderr b/src/test/ui/issues/issue-5099.stderr index d103c968979a1..cc11db9c5eca6 100644 --- a/src/test/ui/issues/issue-5099.stderr +++ b/src/test/ui/issues/issue-5099.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `this` in this scope --> $DIR/issue-5099.rs:1:31 | -LL | trait B < A > { fn a() -> A { this.a } } //~ ERROR cannot find value `this` in this scope +LL | trait B < A > { fn a() -> A { this.a } } | ^^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5100.stderr b/src/test/ui/issues/issue-5100.stderr index 0a918a789703e..b50d24671a850 100644 --- a/src/test/ui/issues/issue-5100.stderr +++ b/src/test/ui/issues/issue-5100.stderr @@ -48,7 +48,7 @@ LL | &(true, false) => () error[E0618]: expected function, found `(char, char)` --> $DIR/issue-5100.rs:48:14 | -LL | let v = [('a', 'b') //~ ERROR expected function, found `(char, char)` +LL | let v = [('a', 'b') | ______________-^^^^^^^^^ LL | | ('c', 'd'), | |_______________________- call expression requires function @@ -56,10 +56,10 @@ LL | | ('c', 'd'), error[E0308]: mismatched types --> $DIR/issue-5100.rs:55:19 | -LL | let x: char = true; //~ ERROR mismatched types +LL | let x: char = true; | ^^^^ expected char, found bool error: aborting due to 7 previous errors -Some errors occurred: E0308, E0618. +Some errors have detailed explanations: E0308, E0618. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-51102.stderr b/src/test/ui/issues/issue-51102.stderr index 1b2948db2d6c3..eb9eb68020067 100644 --- a/src/test/ui/issues/issue-51102.stderr +++ b/src/test/ui/issues/issue-51102.stderr @@ -2,7 +2,7 @@ error[E0026]: struct `SimpleStruct` does not have a field named `state` --> $DIR/issue-51102.rs:13:17 | LL | state: 0, - | ^^^^^^^^ struct `SimpleStruct` does not have this field + | ^^^^^ struct `SimpleStruct` does not have this field error[E0025]: field `no_state_here` bound multiple times in the pattern --> $DIR/issue-51102.rs:24:17 @@ -16,9 +16,9 @@ error[E0026]: variant `SimpleEnum::NoState` does not have a field named `state` --> $DIR/issue-51102.rs:33:17 | LL | state: 0 - | ^^^^^^^^ variant `SimpleEnum::NoState` does not have this field + | ^^^^^ variant `SimpleEnum::NoState` does not have this field error: aborting due to 3 previous errors -Some errors occurred: E0025, E0026. +Some errors have detailed explanations: E0025, E0026. For more information about an error, try `rustc --explain E0025`. diff --git a/src/test/ui/issues/issue-51116.stderr b/src/test/ui/issues/issue-51116.stderr index 4c1870eb8c9f3..8501ae6a1d029 100644 --- a/src/test/ui/issues/issue-51116.stderr +++ b/src/test/ui/issues/issue-51116.stderr @@ -3,7 +3,7 @@ error[E0282]: type annotations needed | LL | for tile in row { | --- the element type for this iterator is not specified -LL | //~^ NOTE the element type for this iterator is not specified +LL | LL | *tile = 0; | ^^^^^ cannot infer type | diff --git a/src/test/ui/issues/issue-51244.nll.stderr b/src/test/ui/issues/issue-51244.nll.stderr deleted file mode 100644 index 7a4935fafc6e9..0000000000000 --- a/src/test/ui/issues/issue-51244.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0594]: cannot assign to `*my_ref` which is behind a `&` reference - --> $DIR/issue-51244.rs:3:5 - | -LL | let ref my_ref @ _ = 0; - | -------------- help: consider changing this to be a mutable reference: `ref mut my_ref @ _` -LL | *my_ref = 0; //~ ERROR cannot assign to immutable borrowed content `*my_ref` [E0594] - | ^^^^^^^^^^^ `my_ref` is a `&` reference, so the data it refers to cannot be written - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-51244.rs b/src/test/ui/issues/issue-51244.rs index d365181013172..509060e1ad81b 100644 --- a/src/test/ui/issues/issue-51244.rs +++ b/src/test/ui/issues/issue-51244.rs @@ -1,4 +1,4 @@ fn main() { let ref my_ref @ _ = 0; - *my_ref = 0; //~ ERROR cannot assign to immutable borrowed content `*my_ref` [E0594] + *my_ref = 0; //~ ERROR cannot assign to `*my_ref` which is behind a `&` reference [E0594] } diff --git a/src/test/ui/issues/issue-51244.stderr b/src/test/ui/issues/issue-51244.stderr index a5b06aa228290..8a7e71e0326a0 100644 --- a/src/test/ui/issues/issue-51244.stderr +++ b/src/test/ui/issues/issue-51244.stderr @@ -1,11 +1,10 @@ -error[E0594]: cannot assign to immutable borrowed content `*my_ref` +error[E0594]: cannot assign to `*my_ref` which is behind a `&` reference --> $DIR/issue-51244.rs:3:5 | LL | let ref my_ref @ _ = 0; - | -------------- help: use a mutable reference instead: `ref mut my_ref @ _` -LL | *my_ref = 0; //~ ERROR cannot assign to immutable borrowed content `*my_ref` [E0594] - | ^^^^^^^^^^^ cannot borrow as mutable + | -------------- help: consider changing this to be a mutable reference: `ref mut my_ref @ _` +LL | *my_ref = 0; + | ^^^^^^^^^^^ `my_ref` is a `&` reference, so the data it refers to cannot be written error: aborting due to previous error -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-51279.rs b/src/test/ui/issues/issue-51279.rs deleted file mode 100644 index f8f3626caabe7..0000000000000 --- a/src/test/ui/issues/issue-51279.rs +++ /dev/null @@ -1,27 +0,0 @@ -pub struct X<#[cfg(none)] 'a, #[cfg(none)] T>(&'a T); -//~^ ERROR #[cfg] cannot be applied on a generic parameter -//~^^ ERROR #[cfg] cannot be applied on a generic parameter - -impl<#[cfg(none)] 'a, #[cfg(none)] T> X<'a, T> {} -//~^ ERROR #[cfg] cannot be applied on a generic parameter -//~^^ ERROR #[cfg] cannot be applied on a generic parameter - -pub fn f<#[cfg(none)] 'a, #[cfg(none)] T>(_: &'a T) {} -//~^ ERROR #[cfg] cannot be applied on a generic parameter -//~^^ ERROR #[cfg] cannot be applied on a generic parameter - -#[cfg(none)] -pub struct Y<#[cfg(none)] T>(T); // shouldn't care when the entire item is stripped out - -struct M(*const T); - -impl<#[cfg_attr(none, may_dangle)] T> Drop for M { - //~^ ERROR #[cfg_attr] cannot be applied on a generic parameter - fn drop(&mut self) {} -} - -type Z<#[ignored] 'a, #[cfg(none)] T> = X<'a, T>; -//~^ ERROR #[cfg] cannot be applied on a generic parameter -//~| ERROR attribute `ignored` is currently unknown to the compiler - -fn main() {} diff --git a/src/test/ui/issues/issue-51279.stderr b/src/test/ui/issues/issue-51279.stderr deleted file mode 100644 index bc33eacac9994..0000000000000 --- a/src/test/ui/issues/issue-51279.stderr +++ /dev/null @@ -1,59 +0,0 @@ -error: #[cfg] cannot be applied on a generic parameter - --> $DIR/issue-51279.rs:1:14 - | -LL | pub struct X<#[cfg(none)] 'a, #[cfg(none)] T>(&'a T); - | ^^^^^^^^^^^^ - -error: #[cfg] cannot be applied on a generic parameter - --> $DIR/issue-51279.rs:1:31 - | -LL | pub struct X<#[cfg(none)] 'a, #[cfg(none)] T>(&'a T); - | ^^^^^^^^^^^^ - -error: #[cfg] cannot be applied on a generic parameter - --> $DIR/issue-51279.rs:5:6 - | -LL | impl<#[cfg(none)] 'a, #[cfg(none)] T> X<'a, T> {} - | ^^^^^^^^^^^^ - -error: #[cfg] cannot be applied on a generic parameter - --> $DIR/issue-51279.rs:5:23 - | -LL | impl<#[cfg(none)] 'a, #[cfg(none)] T> X<'a, T> {} - | ^^^^^^^^^^^^ - -error: #[cfg] cannot be applied on a generic parameter - --> $DIR/issue-51279.rs:9:10 - | -LL | pub fn f<#[cfg(none)] 'a, #[cfg(none)] T>(_: &'a T) {} - | ^^^^^^^^^^^^ - -error: #[cfg] cannot be applied on a generic parameter - --> $DIR/issue-51279.rs:9:27 - | -LL | pub fn f<#[cfg(none)] 'a, #[cfg(none)] T>(_: &'a T) {} - | ^^^^^^^^^^^^ - -error: #[cfg_attr] cannot be applied on a generic parameter - --> $DIR/issue-51279.rs:18:6 - | -LL | impl<#[cfg_attr(none, may_dangle)] T> Drop for M { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: #[cfg] cannot be applied on a generic parameter - --> $DIR/issue-51279.rs:23:23 - | -LL | type Z<#[ignored] 'a, #[cfg(none)] T> = X<'a, T>; - | ^^^^^^^^^^^^ - -error[E0658]: The attribute `ignored` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/issue-51279.rs:23:8 - | -LL | type Z<#[ignored] 'a, #[cfg(none)] T> = X<'a, T>; - | ^^^^^^^^^^ - | - = help: add #![feature(custom_attribute)] to the crate attributes to enable - -error: aborting due to 9 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/issues/issue-51301.rs b/src/test/ui/issues/issue-51301.rs new file mode 100644 index 0000000000000..7e0a5190fcd8a --- /dev/null +++ b/src/test/ui/issues/issue-51301.rs @@ -0,0 +1,35 @@ +use std::any::TypeId; +use std::collections::HashMap; +use std::hash::Hash; + +trait State { + type EventType; + fn get_type_id_of_state(&self) -> TypeId; +} + +struct StateMachine { + current_state: Box>, + transition_table: + HashMap Box>>>, +} + +impl StateMachine { + fn inner_process_event(&mut self, event: EventType) -> Result<(), i8> { + let new_state_creation_function = self + .transition_table + .iter() + .find(|(&event_typeid, _)| event_typeid == self.current_state.get_type_id_of_state()) + .ok_or(1)? + .1 + .iter() + .find(|(&event_type, _)| event == event_type) + //~^ ERROR cannot move out of a shared reference + .ok_or(2)? + .1; + + self.current_state = new_state_creation_function(); + Ok(()) + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-51301.stderr b/src/test/ui/issues/issue-51301.stderr new file mode 100644 index 0000000000000..f3decf7a9913c --- /dev/null +++ b/src/test/ui/issues/issue-51301.stderr @@ -0,0 +1,12 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/issue-51301.rs:25:20 + | +LL | .find(|(&event_type, _)| event == event_type) + | ^^----------^^^^ + | | + | data moved here + | move occurs because `event_type` has type `EventType`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/issues/issue-51515.rs b/src/test/ui/issues/issue-51515.rs index 64d9822bab4da..8eab7b2fa3ae9 100644 --- a/src/test/ui/issues/issue-51515.rs +++ b/src/test/ui/issues/issue-51515.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - fn main() { let foo = &16; //~^ HELP consider changing this to be a mutable reference diff --git a/src/test/ui/issues/issue-51515.stderr b/src/test/ui/issues/issue-51515.stderr index bcfed6d3bf88f..827bb8fe2b892 100644 --- a/src/test/ui/issues/issue-51515.stderr +++ b/src/test/ui/issues/issue-51515.stderr @@ -1,5 +1,5 @@ error[E0594]: cannot assign to `*foo` which is behind a `&` reference - --> $DIR/issue-51515.rs:7:5 + --> $DIR/issue-51515.rs:5:5 | LL | let foo = &16; | --- help: consider changing this to be a mutable reference: `&mut 16` @@ -8,7 +8,7 @@ LL | *foo = 32; | ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*bar` which is behind a `&` reference - --> $DIR/issue-51515.rs:12:5 + --> $DIR/issue-51515.rs:10:5 | LL | let bar = foo; | --- help: consider changing this to be a mutable reference: `&mut i32` @@ -18,4 +18,3 @@ LL | *bar = 64; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-5153.rs b/src/test/ui/issues/issue-5153.rs index 551880ae009fb..e6737662088f2 100644 --- a/src/test/ui/issues/issue-5153.rs +++ b/src/test/ui/issues/issue-5153.rs @@ -7,6 +7,6 @@ impl Foo for isize { } fn main() { - (&5isize as &Foo).foo(); + (&5isize as &dyn Foo).foo(); //~^ ERROR: no method named `foo` found for type `&dyn Foo` in the current scope } diff --git a/src/test/ui/issues/issue-5153.stderr b/src/test/ui/issues/issue-5153.stderr index 48adfee0dec03..97214fbdc52d4 100644 --- a/src/test/ui/issues/issue-5153.stderr +++ b/src/test/ui/issues/issue-5153.stderr @@ -1,8 +1,8 @@ error[E0599]: no method named `foo` found for type `&dyn Foo` in the current scope - --> $DIR/issue-5153.rs:10:23 + --> $DIR/issue-5153.rs:10:27 | -LL | (&5isize as &Foo).foo(); - | ^^^ +LL | (&5isize as &dyn Foo).foo(); + | ^^^ | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `foo`, perhaps you need to implement it: diff --git a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr index 8f36a3f961813..bf45357147916 100644 --- a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr +++ b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr @@ -2,7 +2,10 @@ error[E0308]: try expression alternatives have incompatible types --> $DIR/issue-51632-try-desugar-incompatible-types.rs:8:5 | LL | missing_discourses()? - | ^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found isize + | ^^^^^^^^^^^^^^^^^^^^- + | | | + | | help: try removing this `?` + | expected enum `std::result::Result`, found isize | = note: expected type `std::result::Result` found type `isize` diff --git a/src/test/ui/issues/issue-51714.rs b/src/test/ui/issues/issue-51714.rs index 4885e4a2db7d5..0dc588d75c654 100644 --- a/src/test/ui/issues/issue-51714.rs +++ b/src/test/ui/issues/issue-51714.rs @@ -10,5 +10,4 @@ fn main() { [(); return while let Some(n) = Some(0) {}]; //~^ ERROR return statement outside of function body - //~^^ WARN irrefutable while-let pattern } diff --git a/src/test/ui/issues/issue-51714.stderr b/src/test/ui/issues/issue-51714.stderr index df11f6b7f5a53..023d9013ab4ed 100644 --- a/src/test/ui/issues/issue-51714.stderr +++ b/src/test/ui/issues/issue-51714.stderr @@ -22,14 +22,6 @@ error[E0572]: return statement outside of function body LL | [(); return while let Some(n) = Some(0) {}]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: irrefutable while-let pattern - --> $DIR/issue-51714.rs:11:17 - | -LL | [(); return while let Some(n) = Some(0) {}]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: #[warn(irrefutable_let_patterns)] on by default - error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0572`. diff --git a/src/test/ui/issues/issue-51848.stderr b/src/test/ui/issues/issue-51848.stderr index 1bb6f3c1f1fff..31faaab6141c5 100644 --- a/src/test/ui/issues/issue-51848.stderr +++ b/src/test/ui/issues/issue-51848.stderr @@ -1,7 +1,7 @@ error: invalid format string: expected `'}'` but string was terminated --> $DIR/issue-51848.rs:6:20 | -LL | println!("{"); //~ ERROR invalid +LL | println!("{"); | -^ expected `'}'` in format string | | | because of this opening brace @@ -14,7 +14,7 @@ LL | macro_with_error!(); error: invalid format string: unmatched `}` found --> $DIR/issue-51848.rs:18:15 | -LL | println!("}"); //~ ERROR invalid +LL | println!("}"); | ^ unmatched `}` in format string | = note: if you intended to print `}`, you can escape it using `}}` diff --git a/src/test/ui/issues/issue-51874.stderr b/src/test/ui/issues/issue-51874.stderr index 38c380c4bab80..9b1a6bf2e12d6 100644 --- a/src/test/ui/issues/issue-51874.stderr +++ b/src/test/ui/issues/issue-51874.stderr @@ -1,11 +1,11 @@ error[E0689]: can't call method `pow` on ambiguous numeric type `{float}` --> $DIR/issue-51874.rs:2:19 | -LL | let a = (1.0).pow(1.0); //~ ERROR can't call method `pow` on ambiguous numeric type +LL | let a = (1.0).pow(1.0); | ^^^ help: you must specify a concrete type for this numeric value, like `f32` | -LL | let a = (1.0_f32).pow(1.0); //~ ERROR can't call method `pow` on ambiguous numeric type +LL | let a = (1.0_f32).pow(1.0); | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr b/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr index f687be5edb091..f8c3016e3a74a 100644 --- a/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr +++ b/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr @@ -1,20 +1,21 @@ -error[E0658]: casting pointers to integers in constants is unstable (see issue #51910) +error[E0658]: casting pointers to integers in constants is unstable --> $DIR/issue-52023-array-size-pointer-cast.rs:2:17 | -LL | let _ = [0; (&0 as *const i32) as usize]; //~ ERROR casting pointers to integers in constants +LL | let _ = [0; (&0 as *const i32) as usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51910 = help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable error[E0080]: it is undefined behavior to use this value --> $DIR/issue-52023-array-size-pointer-cast.rs:2:17 | -LL | let _ = [0; (&0 as *const i32) as usize]; //~ ERROR casting pointers to integers in constants +LL | let _ = [0; (&0 as *const i32) as usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: aborting due to 2 previous errors -Some errors occurred: E0080, E0658. +Some errors have detailed explanations: E0080, E0658. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/issues/issue-52049.nll.stderr b/src/test/ui/issues/issue-52049.nll.stderr deleted file mode 100644 index 55929d85da457..0000000000000 --- a/src/test/ui/issues/issue-52049.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-52049.rs:6:10 - | -LL | foo(&unpromotable(5u32)); - | -----^^^^^^^^^^^^^^^^^^- - | | | - | | creates a temporary which is freed while still in use - | argument requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/issues/issue-52049.rs b/src/test/ui/issues/issue-52049.rs index 23b21cf4e615d..efdcc44930567 100644 --- a/src/test/ui/issues/issue-52049.rs +++ b/src/test/ui/issues/issue-52049.rs @@ -5,4 +5,4 @@ fn unpromotable(t: T) -> T { t } fn main() { foo(&unpromotable(5u32)); } -//~^^ ERROR borrowed value does not live long enough +//~^^ ERROR temporary value dropped while borrowed diff --git a/src/test/ui/issues/issue-52049.stderr b/src/test/ui/issues/issue-52049.stderr index 45381765f8c09..55929d85da457 100644 --- a/src/test/ui/issues/issue-52049.stderr +++ b/src/test/ui/issues/issue-52049.stderr @@ -1,13 +1,14 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/issue-52049.rs:6:10 | LL | foo(&unpromotable(5u32)); - | ^^^^^^^^^^^^^^^^^^ - temporary value only lives until here - | | - | temporary value does not live long enough - | - = note: borrowed value must be valid for the static lifetime... + | -----^^^^^^^^^^^^^^^^^^- + | | | + | | creates a temporary which is freed while still in use + | argument requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/issues/issue-52057.rs b/src/test/ui/issues/issue-52057.rs index 356efd5dfedba..911983445e6d6 100644 --- a/src/test/ui/issues/issue-52057.rs +++ b/src/test/ui/issues/issue-52057.rs @@ -4,8 +4,6 @@ // // run-pass -#![feature(nll)] - pub trait Parser { type Input; diff --git a/src/test/ui/issues/issue-52126-assign-op-invariance.nll.stderr b/src/test/ui/issues/issue-52126-assign-op-invariance.nll.stderr deleted file mode 100644 index d231f621e59c7..0000000000000 --- a/src/test/ui/issues/issue-52126-assign-op-invariance.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0597]: `line` does not live long enough - --> $DIR/issue-52126-assign-op-invariance.rs:34:28 - | -LL | let v: Vec<&str> = line.split_whitespace().collect(); - | ^^^^ borrowed value does not live long enough -... -LL | acc += cnt2; - | --- borrow later used here -... -LL | } - | - `line` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issues/issue-52126-assign-op-invariance.stderr b/src/test/ui/issues/issue-52126-assign-op-invariance.stderr index b07b8d5281e8f..d231f621e59c7 100644 --- a/src/test/ui/issues/issue-52126-assign-op-invariance.stderr +++ b/src/test/ui/issues/issue-52126-assign-op-invariance.stderr @@ -4,10 +4,11 @@ error[E0597]: `line` does not live long enough LL | let v: Vec<&str> = line.split_whitespace().collect(); | ^^^^ borrowed value does not live long enough ... +LL | acc += cnt2; + | --- borrow later used here +... LL | } | - `line` dropped here while still borrowed -LL | } - | - borrowed value needs to live until here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5216.rs b/src/test/ui/issues/issue-5216.rs index fd490884fa1fc..35b343edfbdbe 100644 --- a/src/test/ui/issues/issue-5216.rs +++ b/src/test/ui/issues/issue-5216.rs @@ -1,10 +1,10 @@ fn f() { } -struct S(Box); +struct S(Box); pub static C: S = S(f); //~ ERROR mismatched types fn g() { } -type T = Box; +type T = Box; pub static D: T = g; //~ ERROR mismatched types fn main() {} diff --git a/src/test/ui/issues/issue-5216.stderr b/src/test/ui/issues/issue-5216.stderr index 5afea5873d568..ccfe7e04a2cf9 100644 --- a/src/test/ui/issues/issue-5216.stderr +++ b/src/test/ui/issues/issue-5216.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-5216.rs:3:21 | -LL | pub static C: S = S(f); //~ ERROR mismatched types +LL | pub static C: S = S(f); | ^ expected struct `std::boxed::Box`, found fn item | = note: expected type `std::boxed::Box<(dyn std::ops::FnMut() + 'static)>` @@ -10,7 +10,7 @@ LL | pub static C: S = S(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/issue-5216.rs:8:19 | -LL | pub static D: T = g; //~ ERROR mismatched types +LL | pub static D: T = g; | ^ expected struct `std::boxed::Box`, found fn item | = note: expected type `std::boxed::Box<(dyn std::ops::FnMut() + 'static)>` diff --git a/src/test/ui/issues/issue-52213.nll.stderr b/src/test/ui/issues/issue-52213.nll.stderr new file mode 100644 index 0000000000000..eba875de2152b --- /dev/null +++ b/src/test/ui/issues/issue-52213.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/issue-52213.rs:3:20 + | +LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | match (&t,) { +LL | ((u,),) => u, + | ^ returning this value requires that `'a` must outlive `'b` + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-52213.stderr b/src/test/ui/issues/issue-52213.stderr index 4d3346f325ddf..b4df10efc5d8d 100644 --- a/src/test/ui/issues/issue-52213.stderr +++ b/src/test/ui/issues/issue-52213.stderr @@ -1,7 +1,7 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/issue-52213.rs:2:11 | -LL | match (&t,) { //~ ERROR cannot infer an appropriate lifetime +LL | match (&t,) { | ^^^^^ | note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 1:23... @@ -25,4 +25,3 @@ LL | ((u,),) => u, error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/issues/issue-52240.nll.stderr b/src/test/ui/issues/issue-52240.nll.stderr deleted file mode 100644 index 69b663b17d340..0000000000000 --- a/src/test/ui/issues/issue-52240.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/issue-52240.rs:9:27 - | -LL | if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) { - | ^^^^^^^^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/issues/issue-52240.rs b/src/test/ui/issues/issue-52240.rs index 9ac7e9905da3a..5def557789f0f 100644 --- a/src/test/ui/issues/issue-52240.rs +++ b/src/test/ui/issues/issue-52240.rs @@ -7,7 +7,7 @@ enum Foo { fn main() { let arr = vec!(Foo::Bar(0)); if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) { - //~^ ERROR cannot borrow field of immutable binding as mutable + //~^ ERROR cannot borrow data in a `&` reference as mutable *val = 9001; } match arr[0] { diff --git a/src/test/ui/issues/issue-52240.stderr b/src/test/ui/issues/issue-52240.stderr index c2c2524816dc1..69b663b17d340 100644 --- a/src/test/ui/issues/issue-52240.stderr +++ b/src/test/ui/issues/issue-52240.stderr @@ -1,8 +1,8 @@ -error[E0596]: cannot borrow field of immutable binding as mutable +error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/issue-52240.rs:9:27 | LL | if let (Some(Foo::Bar(ref mut val)), _) = (&arr.get(0), 0) { - | ^^^^^^^^^^^ cannot mutably borrow field of immutable binding + | ^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/issues/issue-52533-1.nll.stderr b/src/test/ui/issues/issue-52533-1.nll.stderr new file mode 100644 index 0000000000000..20f19b2596716 --- /dev/null +++ b/src/test/ui/issues/issue-52533-1.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/issue-52533-1.rs:9:18 + | +LL | gimme(|x, y| y) + | - - ^ closure was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | | | + | | has type `&Foo<'_, '1, u32>` + | has type `&Foo<'_, '2, u32>` + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-52533.nll.stderr b/src/test/ui/issues/issue-52533.nll.stderr new file mode 100644 index 0000000000000..c764736d79878 --- /dev/null +++ b/src/test/ui/issues/issue-52533.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/issue-52533.rs:5:16 + | +LL | foo(|a, b| b) + | - - ^ closure was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | | | + | | has type `&'1 u32` + | has type `&'2 u32` + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-52533.stderr b/src/test/ui/issues/issue-52533.stderr index 586548002072e..1ed740c421e0f 100644 --- a/src/test/ui/issues/issue-52533.stderr +++ b/src/test/ui/issues/issue-52533.stderr @@ -17,4 +17,3 @@ LL | foo(|a, b| b) error: aborting due to previous error -For more information about this error, try `rustc --explain E0312`. diff --git a/src/test/ui/issues/issue-52717.stderr b/src/test/ui/issues/issue-52717.stderr index 408819813b075..468cdf2dcf921 100644 --- a/src/test/ui/issues/issue-52717.stderr +++ b/src/test/ui/issues/issue-52717.stderr @@ -5,7 +5,7 @@ LL | A::A { fob } => { println!("{}", fob); } | ^^^ | | | variant `A::A` does not have this field - | help: did you mean: `foo` + | help: a field with a similar name exists: `foo` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-52891.stderr b/src/test/ui/issues/issue-52891.stderr index 65b2b9460bc94..6e6e42ddc2d09 100644 --- a/src/test/ui/issues/issue-52891.stderr +++ b/src/test/ui/issues/issue-52891.stderr @@ -3,11 +3,8 @@ error[E0252]: the name `a` is defined multiple times | LL | use issue_52891::a; | -------------- previous import of the module `a` here -LL | use issue_52891::a; //~ ERROR `a` is defined multiple times - | ----^^^^^^^^^^^^^^- - | | | - | | `a` reimported here - | help: remove unnecessary import +LL | use issue_52891::a; + | ^^^^^^^^^^^^^^ `a` reimported here | = note: `a` must be defined only once in the type namespace of this module @@ -17,7 +14,7 @@ error[E0252]: the name `a` is defined multiple times LL | use issue_52891::a; | -------------- previous import of the module `a` here ... -LL | use issue_52891::{a, b, c}; //~ ERROR `a` is defined multiple times +LL | use issue_52891::{a, b, c}; | ^-- | | | `a` reimported here @@ -31,7 +28,7 @@ error[E0252]: the name `a` is defined multiple times LL | use issue_52891::a; | -------------- previous import of the module `a` here ... -LL | use issue_52891::{d, a, e}; //~ ERROR `a` is defined multiple times +LL | use issue_52891::{d, a, e}; | ^-- | | | `a` reimported here @@ -45,11 +42,8 @@ error[E0252]: the name `a` is defined multiple times LL | use issue_52891::a; | -------------- previous import of the module `a` here ... -LL | use issue_52891::{f, g, a}; //~ ERROR `a` is defined multiple times - | --^ - | | | - | | `a` reimported here - | help: remove unnecessary import +LL | use issue_52891::{f, g, a}; + | ^ `a` reimported here | = note: `a` must be defined only once in the type namespace of this module @@ -59,7 +53,7 @@ error[E0252]: the name `a` is defined multiple times LL | use issue_52891::a; | -------------- previous import of the module `a` here ... -LL | use issue_52891::{a, //~ ERROR `a` is defined multiple times +LL | use issue_52891::{a, | ^-- | | | `a` reimported here @@ -73,7 +67,7 @@ error[E0252]: the name `a` is defined multiple times LL | use issue_52891::a; | -------------- previous import of the module `a` here ... -LL | a, //~ ERROR `a` is defined multiple times +LL | a, | ^-- | | | `a` reimported here @@ -84,16 +78,11 @@ LL | a, //~ ERROR `a` is defined multiple times error[E0252]: the name `a` is defined multiple times --> $DIR/issue-52891.rs:26:5 | -LL | use issue_52891::a; - | -------------- previous import of the module `a` here +LL | use issue_52891::a; + | -------------- previous import of the module `a` here ... -LL | m, - | ______- -LL | | a}; //~ ERROR `a` is defined multiple times - | | ^ - | | | - | |_____`a` reimported here - | help: remove unnecessary import +LL | a}; + | ^ `a` reimported here | = note: `a` must be defined only once in the type namespace of this module @@ -102,13 +91,13 @@ error[E0252]: the name `inner` is defined multiple times | LL | use issue_52891::a::inner; | --------------------- previous import of the module `inner` here -LL | use issue_52891::b::inner; //~ ERROR `inner` is defined multiple times +LL | use issue_52891::b::inner; | ^^^^^^^^^^^^^^^^^^^^^ `inner` reimported here | = note: `inner` must be defined only once in the type namespace of this module help: you can use `as` to change the binding name of the import | -LL | use issue_52891::b::inner as other_inner; //~ ERROR `inner` is defined multiple times +LL | use issue_52891::b::inner as other_inner; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0254]: the name `issue_52891` is defined multiple times @@ -129,17 +118,14 @@ error[E0252]: the name `n` is defined multiple times --> $DIR/issue-52891.rs:36:5 | LL | use issue_52891::n; - | ------------------- - | | | - | | previous import of the module `n` here - | help: remove unnecessary import + | -------------- previous import of the module `n` here LL | #[macro_use] -LL | use issue_52891::n; //~ ERROR `n` is defined multiple times +LL | use issue_52891::n; | ^^^^^^^^^^^^^^ `n` reimported here | = note: `n` must be defined only once in the type namespace of this module error: aborting due to 10 previous errors -Some errors occurred: E0252, E0254. +Some errors have detailed explanations: E0252, E0254. For more information about an error, try `rustc --explain E0252`. diff --git a/src/test/ui/issues/issue-52992.rs b/src/test/ui/issues/issue-52992.rs index 0fdf077d2fc15..c58656330e12b 100644 --- a/src/test/ui/issues/issue-52992.rs +++ b/src/test/ui/issues/issue-52992.rs @@ -4,8 +4,6 @@ // // compile-pass -#![feature(nll)] - fn main() {} fn fail<'a>() -> Struct<'a, Generic<()>> { diff --git a/src/test/ui/issues/issue-53419.rs b/src/test/ui/issues/issue-53419.rs index fc2a926f90ff6..bf6791734d4e2 100644 --- a/src/test/ui/issues/issue-53419.rs +++ b/src/test/ui/issues/issue-53419.rs @@ -1,9 +1,8 @@ //compile-pass struct Foo { - bar: for<'r> Fn(usize, &'r FnMut()) + bar: dyn for<'r> Fn(usize, &'r dyn FnMut()) } fn main() { } - diff --git a/src/test/ui/issues/issue-53498.rs b/src/test/ui/issues/issue-53498.rs new file mode 100644 index 0000000000000..c87d423649233 --- /dev/null +++ b/src/test/ui/issues/issue-53498.rs @@ -0,0 +1,17 @@ +pub mod test { + pub struct A; + pub struct B; + pub struct Foo(T); + + impl Foo { + fn foo() {} + } + + impl Foo { + fn foo() {} + } +} + +fn main() { + test::Foo::::foo(); //~ ERROR method `foo` is private +} diff --git a/src/test/ui/issues/issue-53498.stderr b/src/test/ui/issues/issue-53498.stderr new file mode 100644 index 0000000000000..3fd48233daeb4 --- /dev/null +++ b/src/test/ui/issues/issue-53498.stderr @@ -0,0 +1,9 @@ +error[E0624]: method `foo` is private + --> $DIR/issue-53498.rs:16:5 + | +LL | test::Foo::::foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0624`. diff --git a/src/test/ui/issues/issue-53568.rs b/src/test/ui/issues/issue-53568.rs index 60a6e16492c41..4d3b3f80a97e5 100644 --- a/src/test/ui/issues/issue-53568.rs +++ b/src/test/ui/issues/issue-53568.rs @@ -3,9 +3,6 @@ // // compile-pass -#![feature(nll)] -#![allow(dead_code)] - trait Future { type Item; } @@ -48,4 +45,3 @@ where H: Fn() + Copy } fn main() { } - diff --git a/src/test/ui/issue-53787-inline-assembler-macro.rs b/src/test/ui/issues/issue-53787-inline-assembler-macro.rs similarity index 100% rename from src/test/ui/issue-53787-inline-assembler-macro.rs rename to src/test/ui/issues/issue-53787-inline-assembler-macro.rs diff --git a/src/test/ui/issues/issue-53787-inline-assembler-macro.stderr b/src/test/ui/issues/issue-53787-inline-assembler-macro.stderr new file mode 100644 index 0000000000000..7edf235652f3a --- /dev/null +++ b/src/test/ui/issues/issue-53787-inline-assembler-macro.stderr @@ -0,0 +1,8 @@ +error[E0669]: invalid value for constraint in inline assembly + --> $DIR/issue-53787-inline-assembler-macro.rs:21:16 + | +LL | fake_jump!("FirstFunc"); + | ^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-54189.rs b/src/test/ui/issues/issue-54189.rs new file mode 100644 index 0000000000000..70aecc384effe --- /dev/null +++ b/src/test/ui/issues/issue-54189.rs @@ -0,0 +1,6 @@ +fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } } +//~^ ERROR binding for associated type `Output` references lifetime `'r` + +fn main() { + let f = bug(); +} diff --git a/src/test/ui/issues/issue-54189.stderr b/src/test/ui/issues/issue-54189.stderr new file mode 100644 index 0000000000000..4787abd49d178 --- /dev/null +++ b/src/test/ui/issues/issue-54189.stderr @@ -0,0 +1,9 @@ +error[E0582]: binding for associated type `Output` references lifetime `'r`, which does not appear in the trait input types + --> $DIR/issue-54189.rs:1:35 + | +LL | fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } } + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0582`. diff --git a/src/test/ui/issues/issue-54302-cases.nll.stderr b/src/test/ui/issues/issue-54302-cases.nll.stderr new file mode 100644 index 0000000000000..7463a3f286f4c --- /dev/null +++ b/src/test/ui/issues/issue-54302-cases.nll.stderr @@ -0,0 +1,26 @@ +error: higher-ranked subtype error + --> $DIR/issue-54302-cases.rs:63:5 + | +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/issue-54302-cases.rs:69:5 + | +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/issue-54302-cases.rs:75:5 + | +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/issue-54302-cases.rs:81:5 + | +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/issues/issue-54302.nll.stderr b/src/test/ui/issues/issue-54302.nll.stderr new file mode 100644 index 0000000000000..e68de0312824d --- /dev/null +++ b/src/test/ui/issues/issue-54302.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/issue-54302.rs:13:5 + | +LL | assert_deserialize_owned::<&'static str>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-54348.stderr b/src/test/ui/issues/issue-54348.stderr index d4ee94aa411b7..e39a1cb20cff3 100644 --- a/src/test/ui/issues/issue-54348.stderr +++ b/src/test/ui/issues/issue-54348.stderr @@ -1,7 +1,7 @@ error: index out of bounds: the len is 1 but the index is 1 --> $DIR/issue-54348.rs:3:5 | -LL | [1][1.5 as usize]; //~ ERROR index out of bounds +LL | [1][1.5 as usize]; | ^^^^^^^^^^^^^^^^^ | = note: #[deny(const_err)] on by default @@ -9,7 +9,7 @@ LL | [1][1.5 as usize]; //~ ERROR index out of bounds error: index out of bounds: the len is 1 but the index is 1 --> $DIR/issue-54348.rs:4:5 | -LL | [1][1u64 as usize]; //~ ERROR index out of bounds +LL | [1][1u64 as usize]; | ^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-5439.stderr b/src/test/ui/issues/issue-5439.stderr index 847bc7695807b..bd0cb670bc210 100644 --- a/src/test/ui/issues/issue-5439.stderr +++ b/src/test/ui/issues/issue-5439.stderr @@ -1,7 +1,7 @@ error[E0560]: struct `Foo` has no field named `nonexistent` --> $DIR/issue-5439.rs:13:26 | -LL | return box Foo { nonexistent: self, foo: i }; //~ ERROR: no field named +LL | return box Foo { nonexistent: self, foo: i }; | ^^^^^^^^^^^ `Foo` does not have this field | = note: available fields are: `foo` diff --git a/src/test/ui/issues/issue-54582.rs b/src/test/ui/issues/issue-54582.rs index c2dbf361911b5..8c50cac67f8fc 100644 --- a/src/test/ui/issues/issue-54582.rs +++ b/src/test/ui/issues/issue-54582.rs @@ -9,7 +9,7 @@ pub enum Enum { impl Stage for Enum {} -pub static ARRAY: [(&Stage, &str); 1] = [ +pub static ARRAY: [(&dyn Stage, &str); 1] = [ (&Enum::A, ""), ]; diff --git a/src/test/ui/issue-54943-1.rs b/src/test/ui/issues/issue-54943-1.rs similarity index 93% rename from src/test/ui/issue-54943-1.rs rename to src/test/ui/issues/issue-54943-1.rs index 7750e34036192..8d3a4e72de411 100644 --- a/src/test/ui/issue-54943-1.rs +++ b/src/test/ui/issues/issue-54943-1.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - // This test is a minimal version of an ICE in the dropck-eyepatch tests // found in the fix for #54943. diff --git a/src/test/ui/issue-54943-2.rs b/src/test/ui/issues/issue-54943-2.rs similarity index 95% rename from src/test/ui/issue-54943-2.rs rename to src/test/ui/issues/issue-54943-2.rs index f829c38c35d23..41ca7c1498265 100644 --- a/src/test/ui/issue-54943-2.rs +++ b/src/test/ui/issues/issue-54943-2.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - // This test is a minimal version of an ICE in the dropck-eyepatch tests // found in the fix for #54943. In particular, this test is in unreachable // code as the initial fix for this ICE only worked if the code was reachable. diff --git a/src/test/ui/issue-54943-3.rs b/src/test/ui/issues/issue-54943-3.rs similarity index 100% rename from src/test/ui/issue-54943-3.rs rename to src/test/ui/issues/issue-54943-3.rs diff --git a/src/test/ui/issues/issue-54943.nll.stderr b/src/test/ui/issues/issue-54943.nll.stderr new file mode 100644 index 0000000000000..59be0f983b907 --- /dev/null +++ b/src/test/ui/issues/issue-54943.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/issue-54943.rs:6:13 + | +LL | fn boo<'a>() { + | -- lifetime `'a` defined here +... +LL | let x = foo::<&'a u32>(); + | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-54943.rs b/src/test/ui/issues/issue-54943.rs new file mode 100644 index 0000000000000..85722300bf006 --- /dev/null +++ b/src/test/ui/issues/issue-54943.rs @@ -0,0 +1,10 @@ +fn foo() { } + +fn boo<'a>() { + return; + + let x = foo::<&'a u32>(); + //~^ ERROR +} + +fn main() {} diff --git a/src/test/ui/issues/issue-54943.stderr b/src/test/ui/issues/issue-54943.stderr new file mode 100644 index 0000000000000..d0f03f90c8330 --- /dev/null +++ b/src/test/ui/issues/issue-54943.stderr @@ -0,0 +1,10 @@ +error[E0477]: the type `&'a u32` does not fulfill the required lifetime + --> $DIR/issue-54943.rs:6:13 + | +LL | let x = foo::<&'a u32>(); + | ^^^^^^^^^^^^^^ + | + = note: type must satisfy the static lifetime + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-54954.rs b/src/test/ui/issues/issue-54954.rs new file mode 100644 index 0000000000000..40045bc758cff --- /dev/null +++ b/src/test/ui/issues/issue-54954.rs @@ -0,0 +1,19 @@ +#![feature(const_fn)] + +const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); +//~^ ERROR constant contains unimplemented expression type + +trait Tt { + const fn const_val() -> usize { + //~^ ERROR trait fns cannot be declared const + core::mem::size_of::() + } +} + +fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] { + z +} + +fn main() { + let _ = f([1f32; ARR_LEN]); +} diff --git a/src/test/ui/issues/issue-54954.stderr b/src/test/ui/issues/issue-54954.stderr new file mode 100644 index 0000000000000..29edb506c4b1c --- /dev/null +++ b/src/test/ui/issues/issue-54954.stderr @@ -0,0 +1,16 @@ +error[E0379]: trait fns cannot be declared const + --> $DIR/issue-54954.rs:7:5 + | +LL | const fn const_val() -> usize { + | ^^^^^ trait fns cannot be const + +error[E0019]: constant contains unimplemented expression type + --> $DIR/issue-54954.rs:3:24 + | +LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0019, E0379. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/issues/issue-5500-1.ast.stderr b/src/test/ui/issues/issue-5500-1.ast.stderr deleted file mode 100644 index 681ccbc4276a1..0000000000000 --- a/src/test/ui/issues/issue-5500-1.ast.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0594]: cannot assign to field `_iter.node` of immutable binding - --> $DIR/issue-5500-1.rs:12:5 - | -LL | let _iter = TrieMapIterator{node: &a}; - | ----- help: make this binding mutable: `mut _iter` -LL | / _iter.node = & //[ast]~ ERROR cannot assign to field `_iter.node` of immutable binding -LL | | //[mir]~^ ERROR cannot assign to field `_iter.node` of immutable binding (Ast) -LL | | // MIR doesn't generate an error because the code isn't reachable. This is OK -LL | | // because the test is here to check that the compiler doesn't ICE (cf. #5500). -LL | | panic!() - | |____________^ cannot mutably borrow field of immutable binding - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-5500-1.mir.stderr b/src/test/ui/issues/issue-5500-1.mir.stderr deleted file mode 100644 index 67ca23ca2974b..0000000000000 --- a/src/test/ui/issues/issue-5500-1.mir.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0594]: cannot assign to field `_iter.node` of immutable binding (Ast) - --> $DIR/issue-5500-1.rs:12:5 - | -LL | let _iter = TrieMapIterator{node: &a}; - | ----- help: make this binding mutable: `mut _iter` -LL | / _iter.node = & //[ast]~ ERROR cannot assign to field `_iter.node` of immutable binding -LL | | //[mir]~^ ERROR cannot assign to field `_iter.node` of immutable binding (Ast) -LL | | // MIR doesn't generate an error because the code isn't reachable. This is OK -LL | | // because the test is here to check that the compiler doesn't ICE (cf. #5500). -LL | | panic!() - | |____________^ cannot mutably borrow field of immutable binding - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-5500-1.rs b/src/test/ui/issues/issue-5500-1.rs index e8043563c7359..56f5ce9901e68 100644 --- a/src/test/ui/issues/issue-5500-1.rs +++ b/src/test/ui/issues/issue-5500-1.rs @@ -1,6 +1,8 @@ -// ignore-compare-mode-nll -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=compare +// MIR doesn't generate an error because the assignment isn't reachable. This +// is OK because the test is here to check that the compiler doesn't ICE (cf. +// #5500). + +// compile-pass struct TrieMapIterator<'a> { node: &'a usize @@ -9,9 +11,5 @@ struct TrieMapIterator<'a> { fn main() { let a = 5; let _iter = TrieMapIterator{node: &a}; - _iter.node = & //[ast]~ ERROR cannot assign to field `_iter.node` of immutable binding - //[mir]~^ ERROR cannot assign to field `_iter.node` of immutable binding (Ast) - // MIR doesn't generate an error because the code isn't reachable. This is OK - // because the test is here to check that the compiler doesn't ICE (cf. #5500). - panic!() + _iter.node = &panic!() } diff --git a/src/test/ui/issue-55511.rs b/src/test/ui/issues/issue-55511.rs similarity index 100% rename from src/test/ui/issue-55511.rs rename to src/test/ui/issues/issue-55511.rs diff --git a/src/test/ui/issue-55511.nll.stderr b/src/test/ui/issues/issue-55511.stderr similarity index 100% rename from src/test/ui/issue-55511.nll.stderr rename to src/test/ui/issues/issue-55511.stderr diff --git a/src/test/ui/issues/issue-55587.stderr b/src/test/ui/issues/issue-55587.stderr index 876fb4391b1bc..3928a3cd53201 100644 --- a/src/test/ui/issues/issue-55587.stderr +++ b/src/test/ui/issues/issue-55587.stderr @@ -1,8 +1,10 @@ error[E0164]: expected tuple struct/variant, found method `::new` --> $DIR/issue-55587.rs:4:9 | -LL | let Path::new(); //~ ERROR expected tuple struct/variant - | ^^^^^^^^^^^ not a tuple variant or struct +LL | let Path::new(); + | ^^^^^^^^^^^ `fn` calls are not allowed in patterns + | + = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html error: aborting due to previous error diff --git a/src/test/ui/issues/issue-55731.nll.stderr b/src/test/ui/issues/issue-55731.nll.stderr new file mode 100644 index 0000000000000..dd38bb6291251 --- /dev/null +++ b/src/test/ui/issues/issue-55731.nll.stderr @@ -0,0 +1,11 @@ +error: higher-ranked subtype error + --> $DIR/issue-55731.rs:48:5 + | +LL | / multi(Map { +LL | | i: Cloned(PhantomData), +LL | | f: X, +LL | | }); + | |______^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-55731.rs b/src/test/ui/issues/issue-55731.rs new file mode 100644 index 0000000000000..7b4f4e2cd3b40 --- /dev/null +++ b/src/test/ui/issues/issue-55731.rs @@ -0,0 +1,52 @@ +use std::marker::PhantomData; + +trait DistributedIterator { + fn reduce(self) + where + Self: Sized, + { + unreachable!() + } +} + +trait DistributedIteratorMulti { + type Item; +} + +struct Connect(PhantomData); +impl DistributedIteratorMulti<&'a ()>> DistributedIterator for Connect where {} + +struct Cloned(PhantomData); +impl<'a, Source> DistributedIteratorMulti<&'a Source> for Cloned<&'a Source> { + type Item = (); +} + +struct Map { + i: I, + f: F, +} +impl, F, Source> DistributedIteratorMulti for Map +where + F: A<>::Item>, +{ + type Item = (); +} + +trait A {} + +struct X; +impl A<()> for X {} + +fn multi(_reducer: I) +where + I: for<'a> DistributedIteratorMulti<&'a ()>, +{ + DistributedIterator::reduce(Connect::(PhantomData)) +} + +fn main() { + multi(Map { //~ ERROR implementation of `DistributedIteratorMulti` is not general enough + i: Cloned(PhantomData), + f: X, + }); +} diff --git a/src/test/ui/issues/issue-55731.stderr b/src/test/ui/issues/issue-55731.stderr new file mode 100644 index 0000000000000..f25e18e5d90cb --- /dev/null +++ b/src/test/ui/issues/issue-55731.stderr @@ -0,0 +1,11 @@ +error: implementation of `DistributedIteratorMulti` is not general enough + --> $DIR/issue-55731.rs:48:5 + | +LL | multi(Map { + | ^^^^^ + | + = note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0` + = note: but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1` + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-55796.nll.stderr b/src/test/ui/issues/issue-55796.nll.stderr new file mode 100644 index 0000000000000..5809a56cd4b6b --- /dev/null +++ b/src/test/ui/issues/issue-55796.nll.stderr @@ -0,0 +1,20 @@ +error: lifetime may not live long enough + --> $DIR/issue-55796.rs:16:9 + | +LL | pub trait Graph<'a> { + | -- lifetime `'a` defined here +... +LL | Box::new(self.out_edges(u).map(|e| e.target())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/issue-55796.rs:21:9 + | +LL | pub trait Graph<'a> { + | -- lifetime `'a` defined here +... +LL | Box::new(self.in_edges(u).map(|e| e.target())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/issues/issue-55796.rs b/src/test/ui/issues/issue-55796.rs index efdea5c9b1e16..088d4301c51b1 100644 --- a/src/test/ui/issues/issue-55796.rs +++ b/src/test/ui/issues/issue-55796.rs @@ -12,12 +12,12 @@ pub trait Graph<'a> { fn out_edges(&'a self, u: &Self::Node) -> Self::EdgesIter; fn in_edges(&'a self, u: &Self::Node) -> Self::EdgesIter; - fn out_neighbors(&'a self, u: &Self::Node) -> Box> { + fn out_neighbors(&'a self, u: &Self::Node) -> Box> { Box::new(self.out_edges(u).map(|e| e.target())) //~^ ERROR cannot infer } - fn in_neighbors(&'a self, u: &Self::Node) -> Box> { + fn in_neighbors(&'a self, u: &Self::Node) -> Box> { Box::new(self.in_edges(u).map(|e| e.target())) //~^ ERROR cannot infer } diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr index c05f8b85d0e98..9e67e5e125f62 100644 --- a/src/test/ui/issues/issue-55796.stderr +++ b/src/test/ui/issues/issue-55796.stderr @@ -16,8 +16,8 @@ LL | Box::new(self.out_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: but, the lifetime must be valid for the static lifetime... = note: ...so that the expression is assignable: - expected std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)> - found std::boxed::Box>::Node>> + expected std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)> + found std::boxed::Box>::Node>> error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/issue-55796.rs:21:9 @@ -37,9 +37,8 @@ LL | Box::new(self.in_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: but, the lifetime must be valid for the static lifetime... = note: ...so that the expression is assignable: - expected std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)> - found std::boxed::Box>::Node>> + expected std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)> + found std::boxed::Box>::Node>> error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/issue-55846.rs b/src/test/ui/issues/issue-55846.rs similarity index 100% rename from src/test/ui/issue-55846.rs rename to src/test/ui/issues/issue-55846.rs diff --git a/src/test/ui/issues/issue-56031.rs b/src/test/ui/issues/issue-56031.rs new file mode 100644 index 0000000000000..b68f56814678c --- /dev/null +++ b/src/test/ui/issues/issue-56031.rs @@ -0,0 +1,6 @@ +struct T; + +impl for T {} +//~^ ERROR missing trait in a trait impl + +fn main() {} diff --git a/src/test/ui/issues/issue-56031.stderr b/src/test/ui/issues/issue-56031.stderr new file mode 100644 index 0000000000000..3d7acee0a56eb --- /dev/null +++ b/src/test/ui/issues/issue-56031.stderr @@ -0,0 +1,8 @@ +error: missing trait in a trait impl + --> $DIR/issue-56031.rs:3:5 + | +LL | impl for T {} + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue_56411_aux.rs b/src/test/ui/issues/issue-56411-aux.rs similarity index 100% rename from src/test/ui/issues/issue_56411_aux.rs rename to src/test/ui/issues/issue-56411-aux.rs diff --git a/src/test/ui/issues/issue-56411.rs b/src/test/ui/issues/issue-56411.rs index 3561c21cc7ee3..163651a7ef607 100644 --- a/src/test/ui/issues/issue-56411.rs +++ b/src/test/ui/issues/issue-56411.rs @@ -1,6 +1,7 @@ macro_rules! import { - ( $($name:ident),* ) => { + ( $(($path:expr, $name:ident)),* ) => { $( + #[path = $path] mod $name; pub use self::$name; //~^ ERROR the name `issue_56411_aux` is defined multiple times @@ -10,7 +11,7 @@ macro_rules! import { } } -import!(issue_56411_aux); +import!(("issue-56411-aux.rs", issue_56411_aux)); fn main() { println!("Hello, world!"); diff --git a/src/test/ui/issues/issue-56411.stderr b/src/test/ui/issues/issue-56411.stderr index dd05852c09159..1f38c70a11938 100644 --- a/src/test/ui/issues/issue-56411.stderr +++ b/src/test/ui/issues/issue-56411.stderr @@ -1,5 +1,5 @@ error[E0255]: the name `issue_56411_aux` is defined multiple times - --> $DIR/issue-56411.rs:5:21 + --> $DIR/issue-56411.rs:6:21 | LL | mod $name; | ---------- previous definition of the module `issue_56411_aux` here @@ -9,23 +9,23 @@ LL | pub use self::$name; | `issue_56411_aux` reimported here | you can use `as` to change the binding name of the import ... -LL | import!(issue_56411_aux); - | ------------------------- in this macro invocation +LL | import!(("issue-56411-aux.rs", issue_56411_aux)); + | ------------------------------------------------- in this macro invocation | = note: `issue_56411_aux` must be defined only once in the type namespace of this module error[E0365]: `issue_56411_aux` is private, and cannot be re-exported - --> $DIR/issue-56411.rs:5:21 + --> $DIR/issue-56411.rs:6:21 | LL | pub use self::$name; | ^^^^^^^^^^^ re-export of private `issue_56411_aux` ... -LL | import!(issue_56411_aux); - | ------------------------- in this macro invocation +LL | import!(("issue-56411-aux.rs", issue_56411_aux)); + | ------------------------------------------------- in this macro invocation | = note: consider declaring type or module `issue_56411_aux` with `pub` error: aborting due to 2 previous errors -Some errors occurred: E0255, E0365. +Some errors have detailed explanations: E0255, E0365. For more information about an error, try `rustc --explain E0255`. diff --git a/src/test/ui/issues/issue-56762.rs b/src/test/ui/issues/issue-56762.rs index 97b66b2c7c923..8bb81b907c9a4 100644 --- a/src/test/ui/issues/issue-56762.rs +++ b/src/test/ui/issues/issue-56762.rs @@ -1,4 +1,8 @@ // only-x86_64 + +// FIXME https://github.com/rust-lang/rust/issues/59774 +// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" const HUGE_SIZE: usize = !0usize / 8; diff --git a/src/test/ui/issues/issue-56806.stderr b/src/test/ui/issues/issue-56806.stderr index 2dd3add8f60e6..96979b9dc1eec 100644 --- a/src/test/ui/issues/issue-56806.stderr +++ b/src/test/ui/issues/issue-56806.stderr @@ -9,4 +9,3 @@ LL | fn dyn_instead_of_self(self: Box); error: aborting due to previous error -For more information about this error, try `rustc --explain E0307`. diff --git a/src/test/ui/issues/issue-57362-1.stderr b/src/test/ui/issues/issue-57362-1.stderr index b21b35849b172..1d2ff7669c093 100644 --- a/src/test/ui/issues/issue-57362-1.stderr +++ b/src/test/ui/issues/issue-57362-1.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `f` found for type `fn(&u8)` in the current scope --> $DIR/issue-57362-1.rs:20:7 | -LL | a.f(); //~ ERROR no method named `f` +LL | a.f(); | ^ | = note: a is a function, perhaps you wish to call it diff --git a/src/test/ui/issues/issue-57362-2.stderr b/src/test/ui/issues/issue-57362-2.stderr index b8211691f7be6..2e713cc0ab508 100644 --- a/src/test/ui/issues/issue-57362-2.stderr +++ b/src/test/ui/issues/issue-57362-2.stderr @@ -1,10 +1,8 @@ error[E0599]: no function or associated item named `make_g` found for type `for<'r> fn(&'r ())` in the current scope --> $DIR/issue-57362-2.rs:22:25 | -LL | let x = ::make_g(); //~ ERROR no function or associated item - | ------------^^^^^^ - | | - | function or associated item not found in `for<'r> fn(&'r ())` +LL | let x = ::make_g(); + | ^^^^^^ function or associated item not found in `for<'r> fn(&'r ())` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `make_g`, perhaps you need to implement it: diff --git a/src/test/ui/issues/issue-57781.rs b/src/test/ui/issues/issue-57781.rs new file mode 100644 index 0000000000000..f5015aaf5d81f --- /dev/null +++ b/src/test/ui/issues/issue-57781.rs @@ -0,0 +1,20 @@ +// run-pass + +use std::cell::UnsafeCell; +use std::collections::HashMap; + +struct OnceCell { + _value: UnsafeCell>, +} + +impl OnceCell { + const INIT: OnceCell = OnceCell { + _value: UnsafeCell::new(None), + }; +} + +pub fn crash() { + let _ = OnceCell::>::INIT; +} + +fn main() {} diff --git a/src/test/ui/issues/issue-57843.nll.stderr b/src/test/ui/issues/issue-57843.nll.stderr new file mode 100644 index 0000000000000..70310780b4330 --- /dev/null +++ b/src/test/ui/issues/issue-57843.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/issue-57843.rs:23:9 + | +LL | Foo(Box::new(|_| ())); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-57843.stderr b/src/test/ui/issues/issue-57843.stderr index 4ef884cb3f589..57b206d7bff69 100644 --- a/src/test/ui/issues/issue-57843.stderr +++ b/src/test/ui/issues/issue-57843.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-57843.rs:23:9 | -LL | Foo(Box::new(|_| ())); //~ ERROR mismatched types +LL | Foo(Box::new(|_| ())); | ^^^^^^^^^^^^^^^^ one type is more general than the other | = note: expected type `std::ops::FnOnce<(&'a bool,)>` diff --git a/src/test/ui/issues/issue-57924.rs b/src/test/ui/issues/issue-57924.rs new file mode 100644 index 0000000000000..dc2942225e3de --- /dev/null +++ b/src/test/ui/issues/issue-57924.rs @@ -0,0 +1,10 @@ +pub struct Gcm(E); + +impl Gcm { + pub fn crash(e: E) -> Self { + Self::(e) + //~^ ERROR type arguments are not allowed for this type + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-57924.stderr b/src/test/ui/issues/issue-57924.stderr new file mode 100644 index 0000000000000..2f184b1aae171 --- /dev/null +++ b/src/test/ui/issues/issue-57924.stderr @@ -0,0 +1,9 @@ +error[E0109]: type arguments are not allowed for this type + --> $DIR/issue-57924.rs:5:16 + | +LL | Self::(e) + | ^ type argument not allowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0109`. diff --git a/src/test/ui/issues/issue-57979.rs b/src/test/ui/issues/issue-57979.rs deleted file mode 100644 index abd46b60ab194..0000000000000 --- a/src/test/ui/issues/issue-57979.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Regression test for #57979. This situation is meant to be an error. -// As noted in the issue thread, we decided to forbid nested impl -// trait of this kind: -// -// ```rust -// fn foo() -> impl Foo { .. } -// ``` -// -// Basically there are two hidden variables here, let's call them `X` -// and `Y`, and we must prove that: -// -// ``` -// X: Foo -// Y: Bar -// ``` -// -// However, the user is only giving us the return type `X`. It's true -// that in some cases, we can infer `Y` from `X`, because `X` only -// implements `Foo` for one type (and indeed the compiler does -// inference of this kind), but I do recall that we intended to forbid -// this -- in part because such inference is fragile, and there is not -// necessarily a way for the user to be more explicit should the -// inference fail (so you could get stuck with no way to port your -// code forward if, for example, more impls are added to an existing -// type). -// -// The same seems to apply in this situation. Here there are three impl traits, so we have -// -// ``` -// X: IntoIterator -// Y: Borrow> -// Z: AsRef<[u8]> -// ``` - -use std::borrow::Borrow; - -pub struct Data(TBody); - -pub fn collect(_: impl IntoIterator>>>) { - //~^ ERROR - unimplemented!() -} diff --git a/src/test/ui/issues/issue-57979.stderr b/src/test/ui/issues/issue-57979.stderr deleted file mode 100644 index 488f30ab7c5a7..0000000000000 --- a/src/test/ui/issues/issue-57979.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0666]: nested `impl Trait` is not allowed - --> $DIR/issue-57979.rs:39:61 - | -LL | pub fn collect(_: impl IntoIterator>>>) { - | -----------------^^^^^^^^^^^^^^^^-- - | | | - | | nested `impl Trait` here - | outer `impl Trait` - -error[E0601]: `main` function not found in crate `issue_57979` - | - = note: consider adding a `main` function to `$DIR/issue-57979.rs` - -error: aborting due to 2 previous errors - -Some errors occurred: E0601, E0666. -For more information about an error, try `rustc --explain E0601`. diff --git a/src/test/ui/issues/issue-58006.rs b/src/test/ui/issues/issue-58006.rs deleted file mode 100644 index 1fb5fefa7596d..0000000000000 --- a/src/test/ui/issues/issue-58006.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(type_alias_enum_variants)] -pub enum Enum { - A(usize), -} - -impl Enum { - fn foo(&self) -> () { - match self { - Self::A => (), - //~^ ERROR expected unit struct/variant or constant, found tuple variant - } - } -} - -fn main() {} diff --git a/src/test/ui/issues/issue-58006.stderr b/src/test/ui/issues/issue-58006.stderr deleted file mode 100644 index c65e3e2777fae..0000000000000 --- a/src/test/ui/issues/issue-58006.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0533]: expected unit struct/variant or constant, found tuple variant `::A` - --> $DIR/issue-58006.rs:9:13 - | -LL | Self::A => (), - | ^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0533`. diff --git a/src/test/ui/issues/issue-5844.stderr b/src/test/ui/issues/issue-5844.stderr index 876151fb25cb4..ed5a3dc6b1e1e 100644 --- a/src/test/ui/issues/issue-5844.stderr +++ b/src/test/ui/issues/issue-5844.stderr @@ -1,7 +1,7 @@ error[E0133]: call to unsafe function is unsafe and requires unsafe function or block --> $DIR/issue-5844.rs:6:5 | -LL | issue_5844_aux::rand(); //~ ERROR: requires unsafe +LL | issue_5844_aux::rand(); | ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior diff --git a/src/test/ui/issues/issue-58712.rs b/src/test/ui/issues/issue-58712.rs new file mode 100644 index 0000000000000..930bec6889bce --- /dev/null +++ b/src/test/ui/issues/issue-58712.rs @@ -0,0 +1,14 @@ +struct AddrVec { + h: H, + a: A, +} + +impl AddrVec { + //~^ ERROR cannot find type `DeviceId` in this scope + pub fn device(&self) -> DeviceId { + //~^ ERROR cannot find type `DeviceId` in this scope + self.tail() + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-58712.stderr b/src/test/ui/issues/issue-58712.stderr new file mode 100644 index 0000000000000..6164ad7ee19b2 --- /dev/null +++ b/src/test/ui/issues/issue-58712.stderr @@ -0,0 +1,15 @@ +error[E0412]: cannot find type `DeviceId` in this scope + --> $DIR/issue-58712.rs:6:20 + | +LL | impl AddrVec { + | ^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `DeviceId` in this scope + --> $DIR/issue-58712.rs:8:29 + | +LL | pub fn device(&self) -> DeviceId { + | ^^^^^^^^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/issues/issue-58734.rs b/src/test/ui/issues/issue-58734.rs new file mode 100644 index 0000000000000..bbdfebe1577c7 --- /dev/null +++ b/src/test/ui/issues/issue-58734.rs @@ -0,0 +1,22 @@ +trait Trait { + fn exists(self) -> (); + + fn not_object_safe() -> Self; +} + +impl Trait for () { + fn exists(self) -> () { + } + + fn not_object_safe() -> Self { + () + } +} + +fn main() { + // object-safe or not, this call is OK + Trait::exists(()); + // no object safety error + Trait::nonexistent(()); + //~^ ERROR no function or associated item named `nonexistent` found for type `dyn Trait` +} diff --git a/src/test/ui/issues/issue-58734.stderr b/src/test/ui/issues/issue-58734.stderr new file mode 100644 index 0000000000000..07f2a046b2dbb --- /dev/null +++ b/src/test/ui/issues/issue-58734.stderr @@ -0,0 +1,9 @@ +error[E0599]: no function or associated item named `nonexistent` found for type `dyn Trait` in the current scope + --> $DIR/issue-58734.rs:20:12 + | +LL | Trait::nonexistent(()); + | ^^^^^^^^^^^ function or associated item not found in `dyn Trait` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/issues/issue-5883.rs b/src/test/ui/issues/issue-5883.rs index b4a73ba99c574..0de535023972e 100644 --- a/src/test/ui/issues/issue-5883.rs +++ b/src/test/ui/issues/issue-5883.rs @@ -1,10 +1,10 @@ trait A {} struct Struct { - r: A+'static + r: dyn A + 'static } -fn new_struct(r: A+'static) +fn new_struct(r: dyn A + 'static) -> Struct { //~^ ERROR the size for values of type //~^ ERROR the size for values of type Struct { r: r } diff --git a/src/test/ui/issues/issue-5883.stderr b/src/test/ui/issues/issue-5883.stderr index ad463d4c478ca..c2de1d095505a 100644 --- a/src/test/ui/issues/issue-5883.stderr +++ b/src/test/ui/issues/issue-5883.stderr @@ -1,7 +1,7 @@ error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time --> $DIR/issue-5883.rs:7:15 | -LL | fn new_struct(r: A+'static) +LL | fn new_struct(r: dyn A + 'static) | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` @@ -12,7 +12,7 @@ LL | fn new_struct(r: A+'static) error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time --> $DIR/issue-5883.rs:8:8 | -LL | -> Struct { //~^ ERROR the size for values of type +LL | -> Struct { | ^^^^^^ doesn't have a size known at compile-time | = help: within `Struct`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` diff --git a/src/test/ui/issues/issue-58856-1.rs b/src/test/ui/issues/issue-58856-1.rs new file mode 100644 index 0000000000000..db3984cd18987 --- /dev/null +++ b/src/test/ui/issues/issue-58856-1.rs @@ -0,0 +1,6 @@ +impl A { + fn b(self> + //~^ ERROR expected one of `)`, `,`, or `:`, found `>` +} + +fn main() {} diff --git a/src/test/ui/issues/issue-58856-1.stderr b/src/test/ui/issues/issue-58856-1.stderr new file mode 100644 index 0000000000000..58ab0a142d6f1 --- /dev/null +++ b/src/test/ui/issues/issue-58856-1.stderr @@ -0,0 +1,10 @@ +error: expected one of `)`, `,`, or `:`, found `>` + --> $DIR/issue-58856-1.rs:2:14 + | +LL | fn b(self> + | - ^ help: `)` may belong here + | | + | unclosed delimiter + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-58856-2.rs b/src/test/ui/issues/issue-58856-2.rs new file mode 100644 index 0000000000000..acc38e4c20163 --- /dev/null +++ b/src/test/ui/issues/issue-58856-2.rs @@ -0,0 +1,14 @@ +struct Empty; + +trait Howness {} + +impl Howness for () { + fn how_are_you(&self -> Empty { + //~^ ERROR expected one of `)` or `,`, found `->` + //~| ERROR method `how_are_you` is not a member of trait `Howness` + Empty + } +} +//~^ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, + +fn main() {} diff --git a/src/test/ui/issues/issue-58856-2.stderr b/src/test/ui/issues/issue-58856-2.stderr new file mode 100644 index 0000000000000..b760fd6768afb --- /dev/null +++ b/src/test/ui/issues/issue-58856-2.stderr @@ -0,0 +1,30 @@ +error: expected one of `)` or `,`, found `->` + --> $DIR/issue-58856-2.rs:6:26 + | +LL | fn how_are_you(&self -> Empty { + | - -^^ + | | | + | | help: `)` may belong here + | unclosed delimiter + +error: expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `)` + --> $DIR/issue-58856-2.rs:11:1 + | +LL | } + | - expected one of 11 possible tokens here +LL | } + | ^ unexpected token + +error[E0407]: method `how_are_you` is not a member of trait `Howness` + --> $DIR/issue-58856-2.rs:6:5 + | +LL | / fn how_are_you(&self -> Empty { +LL | | +LL | | +LL | | Empty +LL | | } + | |_____^ not a member of trait `Howness` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0407`. diff --git a/src/test/ui/issues/issue-58857.rs b/src/test/ui/issues/issue-58857.rs new file mode 100644 index 0000000000000..392e4ea0c2ecc --- /dev/null +++ b/src/test/ui/issues/issue-58857.rs @@ -0,0 +1,7 @@ +struct Conj {a : A} +trait Valid {} + +impl Conj{} +//~^ ERROR negative trait bounds are not supported + +fn main() {} diff --git a/src/test/ui/issues/issue-58857.stderr b/src/test/ui/issues/issue-58857.stderr new file mode 100644 index 0000000000000..56e87215a800c --- /dev/null +++ b/src/test/ui/issues/issue-58857.stderr @@ -0,0 +1,9 @@ +error: negative trait bounds are not supported + --> $DIR/issue-58857.rs:4:7 + | +LL | impl Conj{} + | ^^^^^^^^ negative trait bounds are not supported + = help: remove the trait bound + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-59029-1.rs b/src/test/ui/issues/issue-59029-1.rs new file mode 100644 index 0000000000000..e98a4d0e491a3 --- /dev/null +++ b/src/test/ui/issues/issue-59029-1.rs @@ -0,0 +1,8 @@ +#![feature(trait_alias)] + +trait Svc { type Res; } + +trait MkSvc = Svc where Self::Res: Svc; +//~^ ERROR associated type `Res` not found for `Self` + +fn main() {} diff --git a/src/test/ui/issues/issue-59029-1.stderr b/src/test/ui/issues/issue-59029-1.stderr new file mode 100644 index 0000000000000..ed1d98c40d18a --- /dev/null +++ b/src/test/ui/issues/issue-59029-1.stderr @@ -0,0 +1,9 @@ +error[E0220]: associated type `Res` not found for `Self` + --> $DIR/issue-59029-1.rs:5:46 + | +LL | trait MkSvc = Svc where Self::Res: Svc; + | ^^^^^^^^^ associated type `Res` not found + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0220`. diff --git a/src/test/ui/issues/issue-59029-2.rs b/src/test/ui/issues/issue-59029-2.rs new file mode 100644 index 0000000000000..2bdb128d8c4c8 --- /dev/null +++ b/src/test/ui/issues/issue-59029-2.rs @@ -0,0 +1,8 @@ +// run-pass +#![feature(trait_alias)] + +trait Svc { type Res; } + +trait MkSvc = Svc where >::Res: Svc; + +fn main() {} diff --git a/src/test/ui/issues/issue-5927.stderr b/src/test/ui/issues/issue-5927.stderr index 189eefe51b914..89f5e399ae689 100644 --- a/src/test/ui/issues/issue-5927.stderr +++ b/src/test/ui/issues/issue-5927.stderr @@ -1,16 +1,15 @@ error[E0531]: cannot find tuple struct/variant `x` in this scope --> $DIR/issue-5927.rs:3:9 | -LL | x(1) => x(1) //~ ERROR cannot find tuple struct/variant `x` in this scope +LL | x(1) => x(1) | ^ not found in this scope error[E0425]: cannot find function `x` in this scope --> $DIR/issue-5927.rs:3:17 | -LL | x(1) => x(1) //~ ERROR cannot find tuple struct/variant `x` in this scope +LL | x(1) => x(1) | ^ not found in this scope error: aborting due to 2 previous errors -Some errors occurred: E0425, E0531. -For more information about an error, try `rustc --explain E0425`. +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/issues/issue-59488.rs b/src/test/ui/issues/issue-59488.rs new file mode 100644 index 0000000000000..6fa9961f26cc8 --- /dev/null +++ b/src/test/ui/issues/issue-59488.rs @@ -0,0 +1,34 @@ +fn foo() -> i32 { + 42 +} + +fn bar(a: i64) -> i64 { + 43 +} + +enum Foo { + Bar(usize), +} + +fn main() { + foo > 12; + //~^ ERROR binary operation `>` cannot be applied to type `fn() -> i32 {foo}` [E0369] + //~| ERROR mismatched types [E0308] + + bar > 13; + //~^ ERROR binary operation `>` cannot be applied to type `fn(i64) -> i64 {bar}` [E0369] + //~| ERROR mismatched types [E0308] + + foo > foo; + //~^ ERROR binary operation `>` cannot be applied to type `fn() -> i32 {foo}` [E0369] + + foo > bar; + //~^ ERROR binary operation `>` cannot be applied to type `fn() -> i32 {foo}` [E0369] + //~| ERROR mismatched types [E0308] + + let i = Foo::Bar; + assert_eq!(Foo::Bar, i); + //~^ ERROR binary operation `==` cannot be applied to type `fn(usize) -> Foo {Foo::Bar}` [E0369] + //~| ERROR `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` [E0277] + //~| ERROR `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` [E0277] +} diff --git a/src/test/ui/issues/issue-59488.stderr b/src/test/ui/issues/issue-59488.stderr new file mode 100644 index 0000000000000..e0cb1f7b96df8 --- /dev/null +++ b/src/test/ui/issues/issue-59488.stderr @@ -0,0 +1,109 @@ +error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` + --> $DIR/issue-59488.rs:14:9 + | +LL | foo > 12; + | --- ^ -- {integer} + | | + | fn() -> i32 {foo} + | help: you might have forgotten to call this function: `foo()` + +error[E0308]: mismatched types + --> $DIR/issue-59488.rs:14:11 + | +LL | foo > 12; + | ^^ expected fn item, found integer + | + = note: expected type `fn() -> i32 {foo}` + found type `i32` + +error[E0369]: binary operation `>` cannot be applied to type `fn(i64) -> i64 {bar}` + --> $DIR/issue-59488.rs:18:9 + | +LL | bar > 13; + | --- ^ -- {integer} + | | + | fn(i64) -> i64 {bar} + | help: you might have forgotten to call this function: `bar( /* arguments */ )` + +error[E0308]: mismatched types + --> $DIR/issue-59488.rs:18:11 + | +LL | bar > 13; + | ^^ expected fn item, found integer + | + = note: expected type `fn(i64) -> i64 {bar}` + found type `i64` + +error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` + --> $DIR/issue-59488.rs:22:9 + | +LL | foo > foo; + | --- ^ --- fn() -> i32 {foo} + | | + | fn() -> i32 {foo} +help: you might have forgotten to call this function + | +LL | foo() > foo; + | ^^^^^ +help: you might have forgotten to call this function + | +LL | foo > foo(); + | ^^^^^ + +error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` + --> $DIR/issue-59488.rs:25:9 + | +LL | foo > bar; + | --- ^ --- fn(i64) -> i64 {bar} + | | + | fn() -> i32 {foo} + | + = note: an implementation of `std::cmp::PartialOrd` might be missing for `fn() -> i32 {foo}` + +error[E0308]: mismatched types + --> $DIR/issue-59488.rs:25:11 + | +LL | foo > bar; + | ^^^ expected fn item, found a different fn item + | + = note: expected type `fn() -> i32 {foo}` + found type `fn(i64) -> i64 {bar}` + +error[E0369]: binary operation `==` cannot be applied to type `fn(usize) -> Foo {Foo::Bar}` + --> $DIR/issue-59488.rs:30:5 + | +LL | assert_eq!(Foo::Bar, i); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | fn(usize) -> Foo {Foo::Bar} + | fn(usize) -> Foo {Foo::Bar} + | + = note: an implementation of `std::cmp::PartialEq` might be missing for `fn(usize) -> Foo {Foo::Bar}` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` + --> $DIR/issue-59488.rs:30:5 + | +LL | assert_eq!(Foo::Bar, i); + | ^^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | + = help: the trait `std::fmt::Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}` + = note: required because of the requirements on the impl of `std::fmt::Debug` for `&fn(usize) -> Foo {Foo::Bar}` + = note: required by `std::fmt::Debug::fmt` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` + --> $DIR/issue-59488.rs:30:5 + | +LL | assert_eq!(Foo::Bar, i); + | ^^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | + = help: the trait `std::fmt::Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}` + = note: required because of the requirements on the impl of `std::fmt::Debug` for `&fn(usize) -> Foo {Foo::Bar}` + = note: required by `std::fmt::Debug::fmt` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0277, E0308, E0369. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-59508-1.rs b/src/test/ui/issues/issue-59508-1.rs new file mode 100644 index 0000000000000..4fbed9b08f215 --- /dev/null +++ b/src/test/ui/issues/issue-59508-1.rs @@ -0,0 +1,18 @@ +#![allow(dead_code)] +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +// This test checks that generic parameter re-ordering diagnostic suggestions mention that +// consts come after types and lifetimes when the `const_generics` feature is enabled. +// We cannot run rustfix on this test because of the above const generics warning. + +struct A; + +impl A { + pub fn do_things() { + //~^ ERROR lifetime parameters must be declared prior to type parameters + println!("panic"); + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-59508-1.stderr b/src/test/ui/issues/issue-59508-1.stderr new file mode 100644 index 0000000000000..8fb7d7c3c84dc --- /dev/null +++ b/src/test/ui/issues/issue-59508-1.stderr @@ -0,0 +1,14 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-59508-1.rs:2:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error: lifetime parameters must be declared prior to type parameters + --> $DIR/issue-59508-1.rs:12:25 + | +LL | pub fn do_things() { + | ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>` + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-59508.fixed b/src/test/ui/issues/issue-59508.fixed new file mode 100644 index 0000000000000..b5c60a1626f53 --- /dev/null +++ b/src/test/ui/issues/issue-59508.fixed @@ -0,0 +1,16 @@ +// run-rustfix + +#![allow(dead_code)] + +// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds. + +struct A; + +impl A { + pub fn do_things<'a, 'b: 'a, T>() { + //~^ ERROR lifetime parameters must be declared prior to type parameters + println!("panic"); + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-59508.rs b/src/test/ui/issues/issue-59508.rs new file mode 100644 index 0000000000000..0b39c5d8f2aec --- /dev/null +++ b/src/test/ui/issues/issue-59508.rs @@ -0,0 +1,16 @@ +// run-rustfix + +#![allow(dead_code)] + +// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds. + +struct A; + +impl A { + pub fn do_things() { + //~^ ERROR lifetime parameters must be declared prior to type parameters + println!("panic"); + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-59508.stderr b/src/test/ui/issues/issue-59508.stderr new file mode 100644 index 0000000000000..c0fdb2ef34ac4 --- /dev/null +++ b/src/test/ui/issues/issue-59508.stderr @@ -0,0 +1,8 @@ +error: lifetime parameters must be declared prior to type parameters + --> $DIR/issue-59508.rs:10:25 + | +LL | pub fn do_things() { + | ----^^--^^----- help: reorder the parameters: lifetimes, then types: `<'a, 'b: 'a, T>` + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-59756.fixed b/src/test/ui/issues/issue-59756.fixed new file mode 100644 index 0000000000000..7b55d0f17e690 --- /dev/null +++ b/src/test/ui/issues/issue-59756.fixed @@ -0,0 +1,17 @@ +// run-rustfix + +#![allow(warnings)] + +struct A; +struct B; + +fn foo() -> Result { + Ok(A) +} + +fn bar() -> Result { + foo() + //~^ ERROR try expression alternatives have incompatible types [E0308] +} + +fn main() {} diff --git a/src/test/ui/issues/issue-59756.rs b/src/test/ui/issues/issue-59756.rs new file mode 100644 index 0000000000000..cccae396b7210 --- /dev/null +++ b/src/test/ui/issues/issue-59756.rs @@ -0,0 +1,17 @@ +// run-rustfix + +#![allow(warnings)] + +struct A; +struct B; + +fn foo() -> Result { + Ok(A) +} + +fn bar() -> Result { + foo()? + //~^ ERROR try expression alternatives have incompatible types [E0308] +} + +fn main() {} diff --git a/src/test/ui/issues/issue-59756.stderr b/src/test/ui/issues/issue-59756.stderr new file mode 100644 index 0000000000000..d46232874fd2a --- /dev/null +++ b/src/test/ui/issues/issue-59756.stderr @@ -0,0 +1,15 @@ +error[E0308]: try expression alternatives have incompatible types + --> $DIR/issue-59756.rs:13:5 + | +LL | foo()? + | ^^^^^- + | | | + | | help: try removing this `?` + | expected enum `std::result::Result`, found struct `A` + | + = note: expected type `std::result::Result` + found type `A` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-59764.rs b/src/test/ui/issues/issue-59764.rs new file mode 100644 index 0000000000000..09dee8c273268 --- /dev/null +++ b/src/test/ui/issues/issue-59764.rs @@ -0,0 +1,136 @@ +// aux-build:issue-59764.rs +// compile-flags:--extern issue_59764 +// edition:2018 + +#![allow(warnings)] + +// This tests the suggestion to import macros from the root of a crate. This aims to capture +// the case where a user attempts to import a macro from the definition location instead of the +// root of the crate and the macro is annotated with `#![macro_export]`. + +// Edge cases.. + +mod multiple_imports_same_line_at_end { + use issue_59764::foo::{baz, makro}; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod multiple_imports_multiline_at_end_trailing_comma { + use issue_59764::foo::{ + baz, + makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + }; +} + +mod multiple_imports_multiline_at_end { + use issue_59764::foo::{ + baz, + makro //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + }; +} + +mod multiple_imports_same_line_in_middle { + use issue_59764::foo::{baz, makro, foobar}; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod multiple_imports_multiline_in_middle_trailing_comma { + use issue_59764::foo::{ + baz, + makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + foobar, + }; +} + +mod multiple_imports_multiline_in_middle { + use issue_59764::foo::{ + baz, + makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + foobar + }; +} + +mod nested_imports { + use issue_59764::{foobaz, foo::makro}; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod nested_multiple_imports { + use issue_59764::{foobaz, foo::{baz, makro}}; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod nested_multiline_multiple_imports_trailing_comma { + use issue_59764::{ + foobaz, + foo::{ + baz, + makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + }, + }; +} + +mod nested_multiline_multiple_imports { + use issue_59764::{ + foobaz, + foo::{ + baz, + makro //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + } + }; +} + +mod doubly_nested_multiple_imports { + use issue_59764::{foobaz, foo::{baz, makro, barbaz::{barfoo}}}; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod doubly_multiline_nested_multiple_imports { + use issue_59764::{ + foobaz, + foo::{ + baz, + makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + barbaz::{ + barfoo, + } + } + }; +} + +mod renamed_import { + use issue_59764::foo::makro as baz; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod renamed_multiple_imports { + use issue_59764::foo::{baz, makro as foobar}; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod lots_of_whitespace { + use + issue_59764::{ + + foobaz, + + + foo::{baz, + + makro as foobar} //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + + }; +} + +// Simple case.. + +use issue_59764::foo::makro; +//~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] + +makro!(bar); +//~^ ERROR cannot determine resolution for the macro `makro` + +fn main() { + bar(); + //~^ ERROR cannot find function `bar` in this scope [E0425] +} diff --git a/src/test/ui/issues/issue-59764.stderr b/src/test/ui/issues/issue-59764.stderr new file mode 100644 index 0000000000000..f266e908ecc3f --- /dev/null +++ b/src/test/ui/issues/issue-59764.stderr @@ -0,0 +1,241 @@ +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:14:33 + | +LL | use issue_59764::foo::{baz, makro}; + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foo::{baz}}; + | ^^^^^^^^^ --^^ + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:21:9 + | +LL | makro, + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foo::{ +LL | baz, +LL | +LL | }}; + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:28:9 + | +LL | makro + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foo::{ +LL | baz, +LL | +LL | }}; + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:33:33 + | +LL | use issue_59764::foo::{baz, makro, foobar}; + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foo::{baz, foobar}}; + | ^^^^^^^^^ -- ^^ + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:40:9 + | +LL | makro, + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foo::{ +LL | baz, +LL | +LL | foobar, +LL | }}; + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:48:9 + | +LL | makro, + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foo::{ +LL | baz, +LL | +LL | foobar +LL | }}; + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:54:31 + | +LL | use issue_59764::{foobaz, foo::makro}; + | ^^^^^^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foobaz}; + | ^^^^^^^ -- + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:59:42 + | +LL | use issue_59764::{foobaz, foo::{baz, makro}}; + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foobaz, foo::{baz}}; + | ^^^^^^^ -- + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:68:13 + | +LL | makro, + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, +LL | foobaz, +LL | foo::{ +LL | baz, +LL | + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:78:13 + | +LL | makro + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, +LL | foobaz, +LL | foo::{ +LL | baz, +LL | + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:84:42 + | +LL | use issue_59764::{foobaz, foo::{baz, makro, barbaz::{barfoo}}}; + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foobaz, foo::{baz, barbaz::{barfoo}}}; + | ^^^^^^^ -- + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:93:13 + | +LL | makro, + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, +LL | foobaz, +LL | foo::{ +LL | baz, +LL | + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:102:9 + | +LL | use issue_59764::foo::makro as baz; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::makro as baz; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:107:33 + | +LL | use issue_59764::foo::{baz, makro as foobar}; + | ^^^^^^^^^^^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro as foobar, foo::{baz}}; + | ^^^^^^^^^^^^^^^^^^^ --^^ + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:120:17 + | +LL | makro as foobar} + | ^^^^^^^^^^^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | issue_59764::{makro as foobar, +LL | +LL | foobaz, +LL | +LL | +LL | foo::{baz} + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:127:5 + | +LL | use issue_59764::foo::makro; + | ^^^^^^^^^^^^^^^^^^^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::makro; + | ^^^^^^^^^^^^^^^^^^ + +error: cannot determine resolution for the macro `makro` + --> $DIR/issue-59764.rs:130:1 + | +LL | makro!(bar); + | ^^^^^ + | + = note: import resolution is stuck, try simplifying macro imports + +error[E0425]: cannot find function `bar` in this scope + --> $DIR/issue-59764.rs:134:5 + | +LL | bar(); + | ^^^ not found in this scope + +error: aborting due to 18 previous errors + +Some errors have detailed explanations: E0425, E0432. +For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/issues/issue-59896.rs b/src/test/ui/issues/issue-59896.rs new file mode 100644 index 0000000000000..ff9f19acf8471 --- /dev/null +++ b/src/test/ui/issues/issue-59896.rs @@ -0,0 +1,9 @@ +#![deny(unused_imports)] + +struct S; + +fn main() { + use S; //~ ERROR the item `S` is imported redundantly + + let _s = S; +} diff --git a/src/test/ui/issues/issue-59896.stderr b/src/test/ui/issues/issue-59896.stderr new file mode 100644 index 0000000000000..ef78f27fa69a3 --- /dev/null +++ b/src/test/ui/issues/issue-59896.stderr @@ -0,0 +1,17 @@ +error: the item `S` is imported redundantly + --> $DIR/issue-59896.rs:6:9 + | +LL | struct S; + | --------- the item `S` is already defined here +... +LL | use S; + | ^ + | +note: lint level defined here + --> $DIR/issue-59896.rs:1:9 + | +LL | #![deny(unused_imports)] + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-5997-enum.stderr b/src/test/ui/issues/issue-5997-enum.stderr index 5c778143e13dd..1c58b9c391104 100644 --- a/src/test/ui/issues/issue-5997-enum.stderr +++ b/src/test/ui/issues/issue-5997-enum.stderr @@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-5997-enum.rs:2:16 | LL | fn f() -> bool { - | - - type variable from outer function + | - - type parameter from outer function | | | try adding a local generic parameter in this method instead LL | enum E { V(Z) } diff --git a/src/test/ui/issues/issue-5997-struct.stderr b/src/test/ui/issues/issue-5997-struct.stderr index a60987b3f98ba..5b388d16d7553 100644 --- a/src/test/ui/issues/issue-5997-struct.stderr +++ b/src/test/ui/issues/issue-5997-struct.stderr @@ -2,10 +2,10 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-5997-struct.rs:2:14 | LL | fn f() -> bool { - | - - type variable from outer function + | - - type parameter from outer function | | | try adding a local generic parameter in this method instead -LL | struct S(T); //~ ERROR can't use generic parameters from outer function +LL | struct S(T); | ^ use of generic parameter from outer function error: aborting due to previous error diff --git a/src/test/ui/issues/issue-60057.rs b/src/test/ui/issues/issue-60057.rs new file mode 100644 index 0000000000000..3027d01c5325b --- /dev/null +++ b/src/test/ui/issues/issue-60057.rs @@ -0,0 +1,17 @@ +struct A { + banana: u8, +} + +impl A { + fn new(peach: u8) -> A { + A { + banana: banana //~ ERROR cannot find value `banana` in this scope + } + } + + fn foo(&self, peach: u8) -> A { + A { + banana: banana //~ ERROR cannot find value `banana` in this scope + } + } +} diff --git a/src/test/ui/issues/issue-60057.stderr b/src/test/ui/issues/issue-60057.stderr new file mode 100644 index 0000000000000..6b967204ce6fb --- /dev/null +++ b/src/test/ui/issues/issue-60057.stderr @@ -0,0 +1,20 @@ +error[E0425]: cannot find value `banana` in this scope + --> $DIR/issue-60057.rs:8:21 + | +LL | banana: banana + | ^^^^^^ a field by this name exists in `Self` + +error[E0425]: cannot find value `banana` in this scope + --> $DIR/issue-60057.rs:14:21 + | +LL | banana: banana + | ^^^^^^ help: you might have meant to use the available field: `self.banana` + +error[E0601]: `main` function not found in crate `issue_60057` + | + = note: consider adding a `main` function to `$DIR/issue-60057.rs` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0425, E0601. +For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/issues/issue-60075.rs b/src/test/ui/issues/issue-60075.rs new file mode 100644 index 0000000000000..5788716a52629 --- /dev/null +++ b/src/test/ui/issues/issue-60075.rs @@ -0,0 +1,12 @@ +fn main() {} + +trait T { + fn qux() -> Option { + let _ = if true { + }); +//~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;` +//~^^ ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `}` +//~^^^ ERROR 6:11: 6:12: expected identifier, found `;` +//~^^^^ ERROR missing `fn`, `type`, or `const` for trait-item declaration + Some(4) + } diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr new file mode 100644 index 0000000000000..ac97d32a6e15b --- /dev/null +++ b/src/test/ui/issues/issue-60075.stderr @@ -0,0 +1,35 @@ +error: expected one of `.`, `;`, `?`, `else`, or an operator, found `}` + --> $DIR/issue-60075.rs:6:10 + | +LL | }); + | ^ expected one of `.`, `;`, `?`, `else`, or an operator here + +error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;` + --> $DIR/issue-60075.rs:6:11 + | +LL | fn qux() -> Option { + | - unclosed delimiter +LL | let _ = if true { +LL | }); + | ^ help: `}` may belong here + +error: expected identifier, found `;` + --> $DIR/issue-60075.rs:6:11 + | +LL | }); + | ^ expected identifier + +error: missing `fn`, `type`, or `const` for trait-item declaration + --> $DIR/issue-60075.rs:6:12 + | +LL | }); + | ____________^ +LL | | +LL | | +LL | | +LL | | +LL | | Some(4) + | |________^ missing `fn`, `type`, or `const` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/issues/issue-60283.rs b/src/test/ui/issues/issue-60283.rs new file mode 100644 index 0000000000000..e5a9caa32fae7 --- /dev/null +++ b/src/test/ui/issues/issue-60283.rs @@ -0,0 +1,17 @@ +pub trait Trait<'a> { + type Item; +} + +impl<'a> Trait<'a> for () { + type Item = (); +} + +pub fn foo(_: T, _: F) +where T: for<'a> Trait<'a>, + F: for<'a> FnMut(>::Item) {} + +fn main() { + foo((), drop) + //~^ ERROR type mismatch in function arguments + //~| ERROR type mismatch resolving +} diff --git a/src/test/ui/issues/issue-60283.stderr b/src/test/ui/issues/issue-60283.stderr new file mode 100644 index 0000000000000..a79b1959dca2f --- /dev/null +++ b/src/test/ui/issues/issue-60283.stderr @@ -0,0 +1,34 @@ +error[E0631]: type mismatch in function arguments + --> $DIR/issue-60283.rs:14:5 + | +LL | foo((), drop) + | ^^^ + | | + | expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _` + | found signature of `fn(_) -> _` + | +note: required by `foo` + --> $DIR/issue-60283.rs:9:1 + | +LL | / pub fn foo(_: T, _: F) +LL | | where T: for<'a> Trait<'a>, +LL | | F: for<'a> FnMut(>::Item) {} + | |_________________________________________________^ + +error[E0271]: type mismatch resolving `for<'a> } as std::ops::FnOnce<(<() as Trait<'a>>::Item,)>>::Output == ()` + --> $DIR/issue-60283.rs:14:5 + | +LL | foo((), drop) + | ^^^ expected bound lifetime parameter 'a, found concrete lifetime + | +note: required by `foo` + --> $DIR/issue-60283.rs:9:1 + | +LL | / pub fn foo(_: T, _: F) +LL | | where T: for<'a> Trait<'a>, +LL | | F: for<'a> FnMut(>::Item) {} + | |_________________________________________________^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/issues/issue-60622.rs b/src/test/ui/issues/issue-60622.rs new file mode 100644 index 0000000000000..d6a0189c3e042 --- /dev/null +++ b/src/test/ui/issues/issue-60622.rs @@ -0,0 +1,18 @@ +// ignore-tidy-linelength + +#![deny(warnings)] + +struct Borked {} + +impl Borked { + fn a(&self) {} +} + +fn run_wild(b: &Borked) { + b.a::<'_, T>(); + //~^ ERROR cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + //~^^ ERROR wrong number of type arguments: expected 0, found 1 + //~^^^ WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +} + +fn main() {} diff --git a/src/test/ui/issues/issue-60622.stderr b/src/test/ui/issues/issue-60622.stderr new file mode 100644 index 0000000000000..0c337c315f161 --- /dev/null +++ b/src/test/ui/issues/issue-60622.stderr @@ -0,0 +1,27 @@ +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/issue-60622.rs:12:11 + | +LL | fn a(&self) {} + | - the late bound lifetime parameter is introduced here +... +LL | b.a::<'_, T>(); + | ^^ + | +note: lint level defined here + --> $DIR/issue-60622.rs:3:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: #[deny(late_bound_lifetime_arguments)] implied by #[deny(warnings)] + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 + +error[E0107]: wrong number of type arguments: expected 0, found 1 + --> $DIR/issue-60622.rs:12:15 + | +LL | b.a::<'_, T>(); + | ^ unexpected type argument + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/issues/issue-60662.rs b/src/test/ui/issues/issue-60662.rs new file mode 100644 index 0000000000000..fe4eaff742d62 --- /dev/null +++ b/src/test/ui/issues/issue-60662.rs @@ -0,0 +1,11 @@ +// compile-pass +// compile-flags: -Z unpretty=hir + +#![feature(existential_type)] + +trait Animal { +} + +fn main() { + pub existential type ServeFut: Animal; +} diff --git a/src/test/ui/issues/issue-60662.stdout b/src/test/ui/issues/issue-60662.stdout new file mode 100644 index 0000000000000..5acfdf9ed5342 --- /dev/null +++ b/src/test/ui/issues/issue-60662.stdout @@ -0,0 +1,14 @@ +// compile-pass +// compile-flags: -Z unpretty=hir + +#![feature(existential_type)] +#[prelude_import] +use ::std::prelude::v1::*; +#[macro_use] +extern crate std; + +trait Animal { } + +fn main() { + pub existential type ServeFut : Animal; + } diff --git a/src/test/ui/issues/issue-60989.rs b/src/test/ui/issues/issue-60989.rs new file mode 100644 index 0000000000000..6dae1e1347b7a --- /dev/null +++ b/src/test/ui/issues/issue-60989.rs @@ -0,0 +1,18 @@ +struct A {} +struct B {} + +impl From for B { + fn from(a: A) -> B { + B{} + } +} + +fn main() { + let c1 = (); + c1::<()>; + //~^ ERROR type arguments are not allowed for this type + + let c1 = A {}; + c1::>; + //~^ ERROR type arguments are not allowed for this type +} diff --git a/src/test/ui/issues/issue-60989.stderr b/src/test/ui/issues/issue-60989.stderr new file mode 100644 index 0000000000000..5d2d9e83c9b9c --- /dev/null +++ b/src/test/ui/issues/issue-60989.stderr @@ -0,0 +1,15 @@ +error[E0109]: type arguments are not allowed for this type + --> $DIR/issue-60989.rs:12:10 + | +LL | c1::<()>; + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/issue-60989.rs:16:10 + | +LL | c1::>; + | ^^^^^^^^^^^ type argument not allowed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0109`. diff --git a/src/test/ui/issues/issue-61106.rs b/src/test/ui/issues/issue-61106.rs new file mode 100644 index 0000000000000..308ef1de3ccc3 --- /dev/null +++ b/src/test/ui/issues/issue-61106.rs @@ -0,0 +1,6 @@ +fn main() { + let x = String::new(); + foo(x.clone()); //~ ERROR mismatched types +} + +fn foo(_: &str) {} diff --git a/src/test/ui/issues/issue-61106.stderr b/src/test/ui/issues/issue-61106.stderr new file mode 100644 index 0000000000000..ca67d51492845 --- /dev/null +++ b/src/test/ui/issues/issue-61106.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-61106.rs:3:9 + | +LL | foo(x.clone()); + | ^^^^^^^^^ + | | + | expected &str, found struct `std::string::String` + | help: consider borrowing here: `&x` + | + = note: expected type `&str` + found type `std::string::String` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-61108.rs b/src/test/ui/issues/issue-61108.rs new file mode 100644 index 0000000000000..0a883b9581835 --- /dev/null +++ b/src/test/ui/issues/issue-61108.rs @@ -0,0 +1,7 @@ +fn main() { + let mut bad_letters = vec!['e', 't', 'o', 'i']; + for l in bad_letters { + // something here + } + bad_letters.push('s'); //~ ERROR borrow of moved value: `bad_letters` +} diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr new file mode 100644 index 0000000000000..8523a6f6548a6 --- /dev/null +++ b/src/test/ui/issues/issue-61108.stderr @@ -0,0 +1,17 @@ +error[E0382]: borrow of moved value: `bad_letters` + --> $DIR/issue-61108.rs:6:5 + | +LL | let mut bad_letters = vec!['e', 't', 'o', 'i']; + | --------------- move occurs because `bad_letters` has type `std::vec::Vec`, which does not implement the `Copy` trait +LL | for l in bad_letters { + | ----------- + | | + | value moved here + | help: consider borrowing to avoid moving into the for loop: `&bad_letters` +... +LL | bad_letters.push('s'); + | ^^^^^^^^^^^ value borrowed here after move + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/issues/issue-61475.rs b/src/test/ui/issues/issue-61475.rs new file mode 100644 index 0000000000000..680449c9ef3e6 --- /dev/null +++ b/src/test/ui/issues/issue-61475.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(dead_code)] + +enum E { + A, B +} + +fn main() { + match &&E::A { + &&E::A => { + } + &&E::B => { + } + }; +} diff --git a/src/test/ui/issues/issue-61623.rs b/src/test/ui/issues/issue-61623.rs new file mode 100644 index 0000000000000..e5b8747bd8047 --- /dev/null +++ b/src/test/ui/issues/issue-61623.rs @@ -0,0 +1,11 @@ +fn f1<'a>(_: &'a mut ()) {} + +fn f2

    (_: P, _: ()) {} + +fn f3<'a>(x: &'a ((), &'a mut ())) { + f2(|| x.0, f1(x.1)) +//~^ ERROR cannot borrow `*x.1` as mutable, as it is behind a `&` reference +//~| ERROR cannot borrow `*x.1` as mutable because it is also borrowed as immutable +} + +fn main() {} diff --git a/src/test/ui/issues/issue-61623.stderr b/src/test/ui/issues/issue-61623.stderr new file mode 100644 index 0000000000000..883a1c441d6bb --- /dev/null +++ b/src/test/ui/issues/issue-61623.stderr @@ -0,0 +1,22 @@ +error[E0596]: cannot borrow `*x.1` as mutable, as it is behind a `&` reference + --> $DIR/issue-61623.rs:6:19 + | +LL | fn f3<'a>(x: &'a ((), &'a mut ())) { + | -------------------- help: consider changing this to be a mutable reference: `&'a mut ((), &'a mut ())` +LL | f2(|| x.0, f1(x.1)) + | ^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + +error[E0502]: cannot borrow `*x.1` as mutable because it is also borrowed as immutable + --> $DIR/issue-61623.rs:6:19 + | +LL | f2(|| x.0, f1(x.1)) + | -- -- - ^^^ mutable borrow occurs here + | | | | + | | | first borrow occurs due to use of `x` in closure + | | immutable borrow occurs here + | immutable borrow later used by call + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0502, E0596. +For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/issues/issue-61858.rs b/src/test/ui/issues/issue-61858.rs new file mode 100644 index 0000000000000..6c3b56586c4ec --- /dev/null +++ b/src/test/ui/issues/issue-61858.rs @@ -0,0 +1,3 @@ +fn main() { + (if foobar) //~ ERROR expected `{`, found `)` +} diff --git a/src/test/ui/issues/issue-61858.stderr b/src/test/ui/issues/issue-61858.stderr new file mode 100644 index 0000000000000..ea2ec3d013f59 --- /dev/null +++ b/src/test/ui/issues/issue-61858.stderr @@ -0,0 +1,10 @@ +error: expected `{`, found `)` + --> $DIR/issue-61858.rs:2:15 + | +LL | (if foobar) + | -- ^ expected `{` + | | + | this `if` statement has a condition, but no block + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-61882-2.rs b/src/test/ui/issues/issue-61882-2.rs new file mode 100644 index 0000000000000..1209b54bc410e --- /dev/null +++ b/src/test/ui/issues/issue-61882-2.rs @@ -0,0 +1,11 @@ +struct A(T); + +impl A<&'static u8> { + fn f() { + let x = 0; + Self(&x); + //~^ ERROR `x` does not live long enough + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-61882-2.stderr b/src/test/ui/issues/issue-61882-2.stderr new file mode 100644 index 0000000000000..03a65540ced04 --- /dev/null +++ b/src/test/ui/issues/issue-61882-2.stderr @@ -0,0 +1,15 @@ +error[E0597]: `x` does not live long enough + --> $DIR/issue-61882-2.rs:6:14 + | +LL | Self(&x); + | ^^ + | | + | borrowed value does not live long enough + | requires that `x` is borrowed for `'static` +LL | +LL | } + | - `x` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issues/issue-61882.rs b/src/test/ui/issues/issue-61882.rs new file mode 100644 index 0000000000000..013398b4598a8 --- /dev/null +++ b/src/test/ui/issues/issue-61882.rs @@ -0,0 +1,9 @@ +struct A(T); + +impl A { + const B: A = Self(0); + //~^ ERROR mismatched types + //~| ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/issues/issue-61882.stderr b/src/test/ui/issues/issue-61882.stderr new file mode 100644 index 0000000000000..a14e1a4dd4d44 --- /dev/null +++ b/src/test/ui/issues/issue-61882.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/issue-61882.rs:4:27 + | +LL | const B: A = Self(0); + | ^ expected bool, found integer + | + = note: expected type `bool` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/issue-61882.rs:4:22 + | +LL | const B: A = Self(0); + | ^^^^^^^ expected u8, found bool + | + = note: expected type `A` + found type `A` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-6458-4.stderr b/src/test/ui/issues/issue-6458-4.stderr index c087292e978c2..90b493e1634c4 100644 --- a/src/test/ui/issues/issue-6458-4.stderr +++ b/src/test/ui/issues/issue-6458-4.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-6458-4.rs:1:20 | -LL | fn foo(b: bool) -> Result { //~ ERROR mismatched types +LL | fn foo(b: bool) -> Result { | --- ^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found () | | | this function's body doesn't return diff --git a/src/test/ui/issues/issue-6642.stderr b/src/test/ui/issues/issue-6642.stderr index a99d9b3cd77c3..6668108d0245e 100644 --- a/src/test/ui/issues/issue-6642.stderr +++ b/src/test/ui/issues/issue-6642.stderr @@ -1,7 +1,7 @@ error[E0434]: can't capture dynamic environment in a fn item --> $DIR/issue-6642.rs:5:13 | -LL | self.m() //~ ERROR can't capture dynamic environment in a fn item +LL | self.m() | ^^^^ | = help: use the `|| { ... }` closure form instead diff --git a/src/test/ui/issues/issue-6801.nll.stderr b/src/test/ui/issues/issue-6801.nll.stderr deleted file mode 100644 index 2c0fedf351a23..0000000000000 --- a/src/test/ui/issues/issue-6801.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/issue-6801.rs:19:13 - | -LL | let sq = || { *x * *x }; - | -- - borrow occurs due to use in closure - | | - | borrow of `x` occurs here -LL | -LL | twice(x); //~ ERROR: cannot move out of - | ^ move out of `x` occurs here -LL | invoke(sq); - | -- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/issues/issue-6801.stderr b/src/test/ui/issues/issue-6801.stderr index fa0e1928ba4bd..dbb8e6530c053 100644 --- a/src/test/ui/issues/issue-6801.stderr +++ b/src/test/ui/issues/issue-6801.stderr @@ -2,10 +2,14 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/issue-6801.rs:19:13 | LL | let sq = || { *x * *x }; - | -- borrow of `x` occurs here + | -- - borrow occurs due to use in closure + | | + | borrow of `x` occurs here LL | -LL | twice(x); //~ ERROR: cannot move out of +LL | twice(x); | ^ move out of `x` occurs here +LL | invoke(sq); + | -- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-6804.rs b/src/test/ui/issues/issue-6804.rs index da73e2bd397d6..b4af3581a0de0 100644 --- a/src/test/ui/issues/issue-6804.rs +++ b/src/test/ui/issues/issue-6804.rs @@ -10,6 +10,8 @@ fn main() { match x { NAN => {}, //~ ERROR floating-point types cannot be used //~^ WARN this was previously accepted by the compiler but is being phased out + //~| ERROR floating-point types cannot be used in patterns + //~| WARN this was previously accepted by the compiler but is being phased out _ => {}, }; diff --git a/src/test/ui/issues/issue-6804.stderr b/src/test/ui/issues/issue-6804.stderr index 965148d478e00..ab4467e5135ed 100644 --- a/src/test/ui/issues/issue-6804.stderr +++ b/src/test/ui/issues/issue-6804.stderr @@ -1,7 +1,7 @@ error: floating-point types cannot be used in patterns --> $DIR/issue-6804.rs:11:9 | -LL | NAN => {}, //~ ERROR floating-point types cannot be used +LL | NAN => {}, | ^^^ | note: lint level defined here @@ -13,13 +13,22 @@ LL | #![deny(illegal_floating_point_literal_pattern)] = note: for more information, see issue #41620 error: floating-point types cannot be used in patterns - --> $DIR/issue-6804.rs:17:10 + --> $DIR/issue-6804.rs:19:10 | -LL | [NAN, _] => {}, //~ ERROR floating-point types cannot be used +LL | [NAN, _] => {}, | ^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 -error: aborting due to 2 previous errors +error: floating-point types cannot be used in patterns + --> $DIR/issue-6804.rs:11:9 + | +LL | NAN => {}, + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-6936.stderr b/src/test/ui/issues/issue-6936.stderr index b3fe1ddc48348..9292d60ca68f7 100644 --- a/src/test/ui/issues/issue-6936.stderr +++ b/src/test/ui/issues/issue-6936.stderr @@ -3,7 +3,7 @@ error[E0428]: the name `Foo` is defined multiple times | LL | type Foo = ::T; | --------------- previous definition of the type `Foo` here -LL | mod Foo {} //~ ERROR the name `Foo` is defined multiple times +LL | mod Foo {} | ^^^^^^^ `Foo` redefined here | = note: `Foo` must be defined only once in the type namespace of this module @@ -13,7 +13,7 @@ error[E0428]: the name `Foo` is defined multiple times | LL | type Foo = ::T; | --------------- previous definition of the type `Foo` here -LL | struct Foo; //~ ERROR the name `Foo` is defined multiple times +LL | struct Foo; | ^^^^^^^^^^^ `Foo` redefined here | = note: `Foo` must be defined only once in the type namespace of this module @@ -23,7 +23,7 @@ error[E0428]: the name `Foo` is defined multiple times | LL | type Foo = ::T; | --------------- previous definition of the type `Foo` here -LL | enum Foo {} //~ ERROR the name `Foo` is defined multiple times +LL | enum Foo {} | ^^^^^^^^ `Foo` redefined here | = note: `Foo` must be defined only once in the type namespace of this module @@ -33,7 +33,7 @@ error[E0428]: the name `Bar` is defined multiple times | LL | type Bar = T; | ---------------- previous definition of the type `Bar` here -LL | mod Bar {} //~ ERROR the name `Bar` is defined multiple times +LL | mod Bar {} | ^^^^^^^ `Bar` redefined here | = note: `Bar` must be defined only once in the type namespace of this module diff --git a/src/test/ui/issues/issue-7013.rs b/src/test/ui/issues/issue-7013.rs index ee68aa8623b37..3d72b67e391c9 100644 --- a/src/test/ui/issues/issue-7013.rs +++ b/src/test/ui/issues/issue-7013.rs @@ -19,10 +19,10 @@ impl Foo for B { } struct A { - v: Box, + v: Box, } fn main() { - let a = A {v: box B{v: None} as Box}; + let a = A {v: box B{v: None} as Box}; //~^ ERROR `std::rc::Rc>` cannot be sent between threads safely } diff --git a/src/test/ui/issues/issue-7013.stderr b/src/test/ui/issues/issue-7013.stderr index 22185c7da344b..f2668d3312289 100644 --- a/src/test/ui/issues/issue-7013.stderr +++ b/src/test/ui/issues/issue-7013.stderr @@ -1,7 +1,7 @@ error[E0277]: `std::rc::Rc>` cannot be sent between threads safely --> $DIR/issue-7013.rs:26:19 | -LL | let a = A {v: box B{v: None} as Box}; +LL | let a = A {v: box B{v: None} as Box}; | ^^^^^^^^^^^^^^ `std::rc::Rc>` cannot be sent between threads safely | = help: within `B`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` diff --git a/src/test/ui/issues/issue-7044.stderr b/src/test/ui/issues/issue-7044.stderr index 46c5d164e42c7..2ad67ec23be87 100644 --- a/src/test/ui/issues/issue-7044.stderr +++ b/src/test/ui/issues/issue-7044.stderr @@ -3,7 +3,7 @@ error[E0428]: the name `X` is defined multiple times | LL | static X: isize = 0; | -------------------- previous definition of the value `X` here -LL | struct X; //~ ERROR the name `X` is defined multiple times +LL | struct X; | ^^^^^^^^^ `X` redefined here | = note: `X` must be defined only once in the value namespace of this module diff --git a/src/test/ui/issues/issue-7246.stderr b/src/test/ui/issues/issue-7246.stderr index 5b8652597d3f7..e049295e9136f 100644 --- a/src/test/ui/issues/issue-7246.stderr +++ b/src/test/ui/issues/issue-7246.stderr @@ -1,7 +1,7 @@ error: unreachable statement --> $DIR/issue-7246.rs:7:5 | -LL | if *ptr::null() {}; //~ ERROR unreachable +LL | if *ptr::null() {}; | ^^^^^^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/issues/issue-7364.stderr b/src/test/ui/issues/issue-7364.stderr index 52a99ce36b870..1f1079555a91f 100644 --- a/src/test/ui/issues/issue-7364.stderr +++ b/src/test/ui/issues/issue-7364.stderr @@ -23,5 +23,5 @@ LL | static boxed: Box> = box RefCell::new(0); error: aborting due to 3 previous errors -Some errors occurred: E0010, E0019, E0277. +Some errors have detailed explanations: E0010, E0019, E0277. For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/issues/issue-7607-1.stderr b/src/test/ui/issues/issue-7607-1.stderr index aa0a6c761bf07..9320943a82766 100644 --- a/src/test/ui/issues/issue-7607-1.stderr +++ b/src/test/ui/issues/issue-7607-1.stderr @@ -1,7 +1,7 @@ error[E0412]: cannot find type `Fo` in this scope --> $DIR/issue-7607-1.rs:5:6 | -LL | impl Fo { //~ ERROR cannot find type `Fo` in this scope +LL | impl Fo { | ^^ help: a trait with a similar name exists: `Fn` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-7673-cast-generically-implemented-trait.rs b/src/test/ui/issues/issue-7673-cast-generically-implemented-trait.rs index 7dd6b07177f93..619256c787193 100644 --- a/src/test/ui/issues/issue-7673-cast-generically-implemented-trait.rs +++ b/src/test/ui/issues/issue-7673-cast-generically-implemented-trait.rs @@ -18,5 +18,5 @@ trait A { impl A for T {} -fn owned2(a: Box) { a as Box; } -fn owned3(a: Box) { box a as Box; } +fn owned2(a: Box) { a as Box; } +fn owned3(a: Box) { box a as Box; } diff --git a/src/test/ui/issues/issue-7813.stderr b/src/test/ui/issues/issue-7813.stderr index da5fc6357a66a..59be0f3be11e6 100644 --- a/src/test/ui/issues/issue-7813.stderr +++ b/src/test/ui/issues/issue-7813.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `&[_; 0]` --> $DIR/issue-7813.rs:2:13 | -LL | let v = &[]; //~ ERROR type annotations needed +LL | let v = &[]; | - ^^^ cannot infer type | | - | consider giving `v` a type + | consider giving `v` the explicit type `&[_; 0]`, with the type parameters specified error: aborting due to previous error diff --git a/src/test/ui/issues/issue-7950.stderr b/src/test/ui/issues/issue-7950.stderr index e30f04753762e..bbeab405e2935 100644 --- a/src/test/ui/issues/issue-7950.stderr +++ b/src/test/ui/issues/issue-7950.stderr @@ -5,9 +5,7 @@ LL | struct Foo; | ----------- function or associated item `bar` not found for this ... LL | Foo::bar(); - | -----^^^ - | | - | function or associated item not found in `Foo` + | ^^^ function or associated item not found in `Foo` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-8153.stderr b/src/test/ui/issues/issue-8153.stderr index 800b0277c9ac8..4389c3dc288f6 100644 --- a/src/test/ui/issues/issue-8153.stderr +++ b/src/test/ui/issues/issue-8153.stderr @@ -3,7 +3,7 @@ error[E0201]: duplicate definitions with name `bar`: | LL | fn bar(&self) -> isize {1} | -------------------------- previous definition of `bar` here -LL | fn bar(&self) -> isize {2} //~ ERROR duplicate definitions +LL | fn bar(&self) -> isize {2} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition error: aborting due to previous error diff --git a/src/test/ui/issues/issue-8208.rs b/src/test/ui/issues/issue-8208.rs index ad94f99098db8..1c566938f9d0e 100644 --- a/src/test/ui/issues/issue-8208.rs +++ b/src/test/ui/issues/issue-8208.rs @@ -1,14 +1,14 @@ use self::*; //~ ERROR: unresolved import `self::*` [E0432] - //~^ Cannot glob-import a module into itself. + //~^ cannot glob-import a module into itself mod foo { use foo::*; //~ ERROR: unresolved import `foo::*` [E0432] - //~^ Cannot glob-import a module into itself. + //~^ cannot glob-import a module into itself mod bar { use super::bar::*; //~^ ERROR: unresolved import `super::bar::*` [E0432] - //~| Cannot glob-import a module into itself. + //~| cannot glob-import a module into itself } } diff --git a/src/test/ui/issues/issue-8208.stderr b/src/test/ui/issues/issue-8208.stderr index 6de95fb953a9f..e59aea12cda20 100644 --- a/src/test/ui/issues/issue-8208.stderr +++ b/src/test/ui/issues/issue-8208.stderr @@ -1,20 +1,20 @@ error[E0432]: unresolved import `self::*` --> $DIR/issue-8208.rs:1:5 | -LL | use self::*; //~ ERROR: unresolved import `self::*` [E0432] - | ^^^^^^^ Cannot glob-import a module into itself. +LL | use self::*; + | ^^^^^^^ cannot glob-import a module into itself error[E0432]: unresolved import `foo::*` --> $DIR/issue-8208.rs:5:9 | -LL | use foo::*; //~ ERROR: unresolved import `foo::*` [E0432] - | ^^^^^^ Cannot glob-import a module into itself. +LL | use foo::*; + | ^^^^^^ cannot glob-import a module into itself error[E0432]: unresolved import `super::bar::*` --> $DIR/issue-8208.rs:9:13 | LL | use super::bar::*; - | ^^^^^^^^^^^^^ Cannot glob-import a module into itself. + | ^^^^^^^^^^^^^ cannot glob-import a module into itself error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-8398.rs b/src/test/ui/issues/issue-8398.rs index bd37b8582b204..a65c667b08e45 100644 --- a/src/test/ui/issues/issue-8398.rs +++ b/src/test/ui/issues/issue-8398.rs @@ -6,7 +6,7 @@ pub trait Writer { fn write(&mut self, b: &[u8]) -> Result<(), ()>; } -fn foo(a: &mut Writer) { +fn foo(a: &mut dyn Writer) { a.write(&[]).unwrap(); } diff --git a/src/test/ui/issues/issue-8727.stderr b/src/test/ui/issues/issue-8727.stderr index dd23830ea35a4..a7d020cb6756e 100644 --- a/src/test/ui/issues/issue-8727.stderr +++ b/src/test/ui/issues/issue-8727.stderr @@ -9,7 +9,7 @@ LL | generic::>(); = note: #[warn(unconditional_recursion)] on by default = help: a `loop` may express intention better if this is on purpose -error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-8727.rs:4:1 | LL | / fn generic() { diff --git a/src/test/ui/issues/issue-8761.stderr b/src/test/ui/issues/issue-8761.stderr index fc0c14076019f..28847c5a82a07 100644 --- a/src/test/ui/issues/issue-8761.stderr +++ b/src/test/ui/issues/issue-8761.stderr @@ -3,12 +3,20 @@ error[E0308]: mismatched types | LL | A = 1i64, | ^^^^ expected isize, found i64 +help: change the type of the numeric literal from `i64` to `isize` + | +LL | A = 1isize, + | ^^^^^^ error[E0308]: mismatched types --> $DIR/issue-8761.rs:5:9 | LL | B = 2u8 | ^^^ expected isize, found u8 +help: change the type of the numeric literal from `u8` to `isize` + | +LL | B = 2isize + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-8767.stderr b/src/test/ui/issues/issue-8767.stderr index 80280f8c53589..91d99f393b61a 100644 --- a/src/test/ui/issues/issue-8767.stderr +++ b/src/test/ui/issues/issue-8767.stderr @@ -1,7 +1,7 @@ error[E0412]: cannot find type `B` in this scope --> $DIR/issue-8767.rs:1:6 | -LL | impl B { //~ ERROR cannot find type `B` in this scope +LL | impl B { | ^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/issues/issue-9719.rs b/src/test/ui/issues/issue-9719.rs index 96865344e7464..1e38ab9c6c2a4 100644 --- a/src/test/ui/issues/issue-9719.rs +++ b/src/test/ui/issues/issue-9719.rs @@ -12,8 +12,8 @@ mod a { } impl X for isize {} - pub struct Z<'a>(Enum<&'a (X+'a)>); - fn foo() { let x: isize = 42; let z = Z(Enum::A(&x as &X)); let _ = z; } + pub struct Z<'a>(Enum<&'a (dyn X + 'a)>); + fn foo() { let x: isize = 42; let z = Z(Enum::A(&x as &dyn X)); let _ = z; } } mod b { @@ -22,20 +22,20 @@ mod b { } impl X for isize {} struct Y<'a>{ - x:Option<&'a (X+'a)>, + x:Option<&'a (dyn X + 'a)>, } fn bar() { let x: isize = 42; - let _y = Y { x: Some(&x as &X) }; + let _y = Y { x: Some(&x as &dyn X) }; } } mod c { pub trait X { fn f(&self); } impl X for isize { fn f(&self) {} } - pub struct Z<'a>(Option<&'a (X+'a)>); - fn main() { let x: isize = 42; let z = Z(Some(&x as &X)); let _ = z; } + pub struct Z<'a>(Option<&'a (dyn X + 'a)>); + fn main() { let x: isize = 42; let z = Z(Some(&x as &dyn X)); let _ = z; } } pub fn main() {} diff --git a/src/test/ui/issues/issue-9725.stderr b/src/test/ui/issues/issue-9725.stderr index eafe92e4688a8..687e0cc0f3ef1 100644 --- a/src/test/ui/issues/issue-9725.stderr +++ b/src/test/ui/issues/issue-9725.stderr @@ -14,5 +14,5 @@ LL | let A { foo, foo } = A { foo: 3 }; error: aborting due to 2 previous errors -Some errors occurred: E0025, E0416. +Some errors have detailed explanations: E0025, E0416. For more information about an error, try `rustc --explain E0025`. diff --git a/src/test/ui/issues/issue-9814.stderr b/src/test/ui/issues/issue-9814.stderr index fe105a9c3cef3..bd9e7df4991ba 100644 --- a/src/test/ui/issues/issue-9814.stderr +++ b/src/test/ui/issues/issue-9814.stderr @@ -1,7 +1,7 @@ error[E0614]: type `Foo` cannot be dereferenced --> $DIR/issue-9814.rs:7:13 | -LL | let _ = *Foo::Bar(2); //~ ERROR type `Foo` cannot be dereferenced +LL | let _ = *Foo::Bar(2); | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-pr29383.stderr b/src/test/ui/issues/issue-pr29383.stderr index 1fe49f8fb14a6..9695e1e3c07f5 100644 --- a/src/test/ui/issues/issue-pr29383.stderr +++ b/src/test/ui/issues/issue-pr29383.stderr @@ -1,13 +1,13 @@ error[E0532]: expected tuple struct/variant, found unit variant `E::A` --> $DIR/issue-pr29383.rs:9:14 | -LL | Some(E::A(..)) => {} //~ ERROR expected tuple struct/variant, found unit variant `E::A` +LL | Some(E::A(..)) => {} | ^^^^ not a tuple struct/variant error[E0532]: expected tuple struct/variant, found unit variant `E::B` --> $DIR/issue-pr29383.rs:10:14 | -LL | Some(E::B(..)) => {} //~ ERROR expected tuple struct/variant, found unit variant `E::B` +LL | Some(E::B(..)) => {} | ^^^^ not a tuple struct/variant error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs index 4a71932d1df18..ecfa5c69e2f03 100644 --- a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs +++ b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs @@ -10,6 +10,7 @@ impl Foo for u32 { fn foo(&self, t: impl Clone) {} //~^ ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters //~| NOTE found 1 type parameter +//~| NOTE `impl Trait` introduces an implicit type parameter } fn main() {} diff --git a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr index af7fdde9a8ed1..30322f88cca42 100644 --- a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr +++ b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr @@ -1,11 +1,14 @@ error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:5 + --> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:22 | LL | fn foo(&self, t: Self::T); - | -------------------------- expected 0 type parameters + | - expected 0 type parameters ... LL | fn foo(&self, t: impl Clone) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found 1 type parameter + | ^^^^^^^^^^ + | | + | found 1 type parameter + | `impl Trait` introduces an implicit type parameter error: aborting due to previous error diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-expr.stderr b/src/test/ui/keyword/extern/keyword-extern-as-identifier-expr.stderr index 150fc88e7efc2..8bb89d2ee215e 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-expr.stderr +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-expr.stderr @@ -1,7 +1,7 @@ error: expected expression, found keyword `extern` --> $DIR/keyword-extern-as-identifier-expr.rs:2:13 | -LL | let s = extern::foo::Bar; //~ ERROR expected expression, found keyword `extern` +LL | let s = extern::foo::Bar; | ^^^^^^ expected expression error: aborting due to previous error diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr index 426b4eef0569c..d7b9ad2abe97a 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `extern` --> $DIR/keyword-extern-as-identifier-pat.rs:2:9 | -LL | let extern = 0; //~ ERROR expected pattern, found keyword `extern` +LL | let extern = 0; | ^^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.stderr b/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.stderr index 97b641fbea557..447c76a5bbceb 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.stderr +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.stderr @@ -1,7 +1,7 @@ error: expected `fn`, found `::` --> $DIR/keyword-extern-as-identifier-type.rs:1:16 | -LL | type A = extern::foo::bar; //~ ERROR expected `fn`, found `::` +LL | type A = extern::foo::bar; | ^^ expected `fn` here error: aborting due to previous error diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr b/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr index 31b575a92e0c8..4b833f8068195 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr @@ -1,11 +1,11 @@ error: expected identifier, found keyword `extern` --> $DIR/keyword-extern-as-identifier-use.rs:1:5 | -LL | use extern::foo; //~ ERROR expected identifier, found keyword `extern` +LL | use extern::foo; | ^^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | -LL | use r#extern::foo; //~ ERROR expected identifier, found keyword `extern` +LL | use r#extern::foo; | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/keyword/keyword-false-as-identifier.stderr b/src/test/ui/keyword/keyword-false-as-identifier.stderr index 6c8dffa7e22c6..9544604599835 100644 --- a/src/test/ui/keyword/keyword-false-as-identifier.stderr +++ b/src/test/ui/keyword/keyword-false-as-identifier.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/keyword-false-as-identifier.rs:2:9 | -LL | let false = 22; //~ error: mismatched types +LL | let false = 22; | ^^^^^ expected integer, found bool | = note: expected type `{integer}` diff --git a/src/test/ui/keyword/keyword-self-as-identifier.stderr b/src/test/ui/keyword/keyword-self-as-identifier.stderr index 6ea19620a6609..5f567910ed81b 100644 --- a/src/test/ui/keyword/keyword-self-as-identifier.stderr +++ b/src/test/ui/keyword/keyword-self-as-identifier.stderr @@ -1,9 +1,8 @@ error[E0531]: cannot find unit struct/variant or constant `Self` in this scope --> $DIR/keyword-self-as-identifier.rs:2:9 | -LL | let Self = 22; //~ ERROR cannot find unit struct/variant or constant `Self` in this scope +LL | let Self = 22; | ^^^^ not found in this scope error: aborting due to previous error -For more information about this error, try `rustc --explain E0531`. diff --git a/src/test/ui/keyword/keyword-super-as-identifier.stderr b/src/test/ui/keyword/keyword-super-as-identifier.stderr index b0973bd170e58..bbeaed9428795 100644 --- a/src/test/ui/keyword/keyword-super-as-identifier.stderr +++ b/src/test/ui/keyword/keyword-super-as-identifier.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: there are too many initial `super`s. --> $DIR/keyword-super-as-identifier.rs:2:9 | -LL | let super = 22; //~ ERROR failed to resolve: there are too many initial `super`s +LL | let super = 22; | ^^^^^ there are too many initial `super`s. error: aborting due to previous error diff --git a/src/test/ui/keyword/keyword-super.stderr b/src/test/ui/keyword/keyword-super.stderr index 5ec33ae30a698..63394c7852a5d 100644 --- a/src/test/ui/keyword/keyword-super.stderr +++ b/src/test/ui/keyword/keyword-super.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: there are too many initial `super`s. --> $DIR/keyword-super.rs:2:9 | -LL | let super: isize; //~ ERROR failed to resolve: there are too many initial `super`s +LL | let super: isize; | ^^^^^ there are too many initial `super`s. error: aborting due to previous error diff --git a/src/test/ui/keyword/keyword-true-as-identifier.stderr b/src/test/ui/keyword/keyword-true-as-identifier.stderr index e5d3938e54ac2..36b1d882a347f 100644 --- a/src/test/ui/keyword/keyword-true-as-identifier.stderr +++ b/src/test/ui/keyword/keyword-true-as-identifier.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/keyword-true-as-identifier.rs:2:9 | -LL | let true = 22; //~ error: mismatched types +LL | let true = 22; | ^^^^ expected integer, found bool | = note: expected type `{integer}` diff --git a/src/test/ui/kindck/kindck-copy.rs b/src/test/ui/kindck/kindck-copy.rs index dadeb9569644c..eb18613682f65 100644 --- a/src/test/ui/kindck/kindck-copy.rs +++ b/src/test/ui/kindck/kindck-copy.rs @@ -34,16 +34,16 @@ fn test<'a,T,U:Copy>(_: &'a isize) { assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied // borrowed object types are generally ok - assert_copy::<&'a Dummy>(); - assert_copy::<&'a (Dummy+Send)>(); - assert_copy::<&'static (Dummy+Send)>(); + assert_copy::<&'a dyn Dummy>(); + assert_copy::<&'a (dyn Dummy + Send)>(); + assert_copy::<&'static (dyn Dummy + Send)>(); // owned object types are not ok - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied // mutable object types are not ok - assert_copy::<&'a mut (Dummy+Send)>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::<&'a mut (dyn Dummy + Send)>(); //~ ERROR : std::marker::Copy` is not satisfied // unsafe ptrs are ok assert_copy::<*const isize>(); diff --git a/src/test/ui/kindck/kindck-copy.stderr b/src/test/ui/kindck/kindck-copy.stderr index 65c06b8308c9b..929a807656209 100644 --- a/src/test/ui/kindck/kindck-copy.stderr +++ b/src/test/ui/kindck/kindck-copy.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `&'static mut isize: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:27:5 | -LL | assert_copy::<&'static mut isize>(); //~ ERROR : std::marker::Copy` is not satisfied +LL | assert_copy::<&'static mut isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `&'static mut isize` | = help: the following implementations were found: @@ -15,7 +15,7 @@ LL | fn assert_copy() { } error[E0277]: the trait bound `&'a mut isize: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:28:5 | -LL | assert_copy::<&'a mut isize>(); //~ ERROR : std::marker::Copy` is not satisfied +LL | assert_copy::<&'a mut isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `&'a mut isize` | = help: the following implementations were found: @@ -29,7 +29,7 @@ LL | fn assert_copy() { } error[E0277]: the trait bound `std::boxed::Box: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:31:5 | -LL | assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied +LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` | note: required by `assert_copy` @@ -41,7 +41,7 @@ LL | fn assert_copy() { } error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:32:5 | -LL | assert_copy::(); //~ ERROR : std::marker::Copy` is not satisfied +LL | assert_copy::(); | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` | note: required by `assert_copy` @@ -53,7 +53,7 @@ LL | fn assert_copy() { } error[E0277]: the trait bound `std::vec::Vec: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:33:5 | -LL | assert_copy:: >(); //~ ERROR : std::marker::Copy` is not satisfied +LL | assert_copy:: >(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::vec::Vec` | note: required by `assert_copy` @@ -65,7 +65,7 @@ LL | fn assert_copy() { } error[E0277]: the trait bound `std::boxed::Box<&'a mut isize>: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:34:5 | -LL | assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied +LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<&'a mut isize>` | note: required by `assert_copy` @@ -77,8 +77,8 @@ LL | fn assert_copy() { } error[E0277]: the trait bound `std::boxed::Box: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:42:5 | -LL | assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied - | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` +LL | assert_copy::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` | note: required by `assert_copy` --> $DIR/kindck-copy.rs:5:1 @@ -89,8 +89,8 @@ LL | fn assert_copy() { } error[E0277]: the trait bound `std::boxed::Box: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:43:5 | -LL | assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` +LL | assert_copy::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` | note: required by `assert_copy` --> $DIR/kindck-copy.rs:5:1 @@ -101,8 +101,8 @@ LL | fn assert_copy() { } error[E0277]: the trait bound `&'a mut (dyn Dummy + std::marker::Send + 'a): std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:46:5 | -LL | assert_copy::<&'a mut (Dummy+Send)>(); //~ ERROR : std::marker::Copy` is not satisfied - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `&'a mut (dyn Dummy + std::marker::Send + 'a)` +LL | assert_copy::<&'a mut (dyn Dummy + Send)>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `&'a mut (dyn Dummy + std::marker::Send + 'a)` | note: required by `assert_copy` --> $DIR/kindck-copy.rs:5:1 @@ -113,7 +113,7 @@ LL | fn assert_copy() { } error[E0277]: the trait bound `MyNoncopyStruct: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:64:5 | -LL | assert_copy::(); //~ ERROR : std::marker::Copy` is not satisfied +LL | assert_copy::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `MyNoncopyStruct` | note: required by `assert_copy` @@ -125,7 +125,7 @@ LL | fn assert_copy() { } error[E0277]: the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:67:5 | -LL | assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied +LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::rc::Rc` | note: required by `assert_copy` diff --git a/src/test/ui/kindck/kindck-impl-type-params.nll.stderr b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr new file mode 100644 index 0000000000000..25d0e74187f75 --- /dev/null +++ b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr @@ -0,0 +1,63 @@ +error[E0277]: `T` cannot be sent between threads safely + --> $DIR/kindck-impl-type-params.rs:18:13 + | +LL | let a = &t as &dyn Gettable; + | ^^ `T` cannot be sent between threads safely + | + = help: the trait `std::marker::Send` is not implemented for `T` + = help: consider adding a `where T: std::marker::Send` bound + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` + +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/kindck-impl-type-params.rs:18:13 + | +LL | let a = &t as &dyn Gettable; + | ^^ the trait `std::marker::Copy` is not implemented for `T` + | + = help: consider adding a `where T: std::marker::Copy` bound + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` + +error[E0277]: `T` cannot be sent between threads safely + --> $DIR/kindck-impl-type-params.rs:25:31 + | +LL | let a: &dyn Gettable = &t; + | ^^ `T` cannot be sent between threads safely + | + = help: the trait `std::marker::Send` is not implemented for `T` + = help: consider adding a `where T: std::marker::Send` bound + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` + +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/kindck-impl-type-params.rs:25:31 + | +LL | let a: &dyn Gettable = &t; + | ^^ the trait `std::marker::Copy` is not implemented for `T` + | + = help: consider adding a `where T: std::marker::Copy` bound + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` + +error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied + --> $DIR/kindck-impl-type-params.rs:38:13 + | +LL | let a = t as Box>; + | ^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` + +error[E0277]: the trait bound `foo3::Foo: std::marker::Copy` is not satisfied + --> $DIR/kindck-impl-type-params.rs:46:37 + | +LL | let a: Box> = t; + | ^ the trait `std::marker::Copy` is not implemented for `foo3::Foo` + | + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/kindck/kindck-impl-type-params.rs b/src/test/ui/kindck/kindck-impl-type-params.rs index a47e418709dcd..c4f90f36acfc2 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.rs +++ b/src/test/ui/kindck/kindck-impl-type-params.rs @@ -15,27 +15,27 @@ impl Gettable for S {} fn f(val: T) { let t: S = S(marker::PhantomData); - let a = &t as &Gettable; + let a = &t as &dyn Gettable; //~^ ERROR `T` cannot be sent between threads safely //~| ERROR : std::marker::Copy` is not satisfied } fn g(val: T) { let t: S = S(marker::PhantomData); - let a: &Gettable = &t; + let a: &dyn Gettable = &t; //~^ ERROR `T` cannot be sent between threads safely //~| ERROR : std::marker::Copy` is not satisfied } fn foo<'a>() { let t: S<&'a isize> = S(marker::PhantomData); - let a = &t as &Gettable<&'a isize>; + let a = &t as &dyn Gettable<&'a isize>; //~^ ERROR does not fulfill } fn foo2<'a>() { let t: Box> = box S(marker::PhantomData); - let a = t as Box>; + let a = t as Box>; //~^ ERROR : std::marker::Copy` is not satisfied } @@ -43,7 +43,7 @@ fn foo3<'a>() { struct Foo; // does not impl Copy let t: Box> = box S(marker::PhantomData); - let a: Box> = t; + let a: Box> = t; //~^ ERROR : std::marker::Copy` is not satisfied } diff --git a/src/test/ui/kindck/kindck-impl-type-params.stderr b/src/test/ui/kindck/kindck-impl-type-params.stderr index 03cd480babead..e6f7088bd4635 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params.stderr @@ -1,7 +1,7 @@ error[E0277]: `T` cannot be sent between threads safely --> $DIR/kindck-impl-type-params.rs:18:13 | -LL | let a = &t as &Gettable; +LL | let a = &t as &dyn Gettable; | ^^ `T` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `T` @@ -12,7 +12,7 @@ LL | let a = &t as &Gettable; error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:18:13 | -LL | let a = &t as &Gettable; +LL | let a = &t as &dyn Gettable; | ^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound @@ -20,10 +20,10 @@ LL | let a = &t as &Gettable; = note: required for the cast to the object type `dyn Gettable` error[E0277]: `T` cannot be sent between threads safely - --> $DIR/kindck-impl-type-params.rs:25:27 + --> $DIR/kindck-impl-type-params.rs:25:31 | -LL | let a: &Gettable = &t; - | ^^ `T` cannot be sent between threads safely +LL | let a: &dyn Gettable = &t; + | ^^ `T` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `T` = help: consider adding a `where T: std::marker::Send` bound @@ -31,10 +31,10 @@ LL | let a: &Gettable = &t; = note: required for the cast to the object type `dyn Gettable` error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:25:27 + --> $DIR/kindck-impl-type-params.rs:25:31 | -LL | let a: &Gettable = &t; - | ^^ the trait `std::marker::Copy` is not implemented for `T` +LL | let a: &dyn Gettable = &t; + | ^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound = note: required because of the requirements on the impl of `Gettable` for `S` @@ -43,7 +43,7 @@ LL | let a: &Gettable = &t; error[E0477]: the type `&'a isize` does not fulfill the required lifetime --> $DIR/kindck-impl-type-params.rs:32:13 | -LL | let a = &t as &Gettable<&'a isize>; +LL | let a = &t as &dyn Gettable<&'a isize>; | ^^ | = note: type must satisfy the static lifetime @@ -51,22 +51,21 @@ LL | let a = &t as &Gettable<&'a isize>; error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:38:13 | -LL | let a = t as Box>; +LL | let a = t as Box>; | ^ the trait `std::marker::Copy` is not implemented for `std::string::String` | = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` error[E0277]: the trait bound `foo3::Foo: std::marker::Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:46:33 + --> $DIR/kindck-impl-type-params.rs:46:37 | -LL | let a: Box> = t; - | ^ the trait `std::marker::Copy` is not implemented for `foo3::Foo` +LL | let a: Box> = t; + | ^ the trait `std::marker::Copy` is not implemented for `foo3::Foo` | = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` error: aborting due to 7 previous errors -Some errors occurred: E0277, E0477. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.rs b/src/test/ui/kindck/kindck-inherited-copy-bound.rs index 0134636fa0d3c..61e72908248df 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.rs +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.rs @@ -21,7 +21,7 @@ fn a() { fn b() { let x: Box<_> = box 3; let y = &x; - let z = &x as &Foo; + let z = &x as &dyn Foo; //~^ ERROR E0038 //~| ERROR E0038 } diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.stderr index fe8e02e354776..1e719e2608425 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.stderr +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied --> $DIR/kindck-inherited-copy-bound.rs:18:5 | -LL | take_param(&x); //~ ERROR E0277 +LL | take_param(&x); | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<{integer}>` | = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>` @@ -14,15 +14,15 @@ LL | fn take_param(foo: &T) { } error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/kindck-inherited-copy-bound.rs:24:19 | -LL | let z = &x as &Foo; - | ^^^^ the trait `Foo` cannot be made into an object +LL | let z = &x as &dyn Foo; + | ^^^^^^^^ the trait `Foo` cannot be made into an object | = note: the trait cannot require that `Self : Sized` error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/kindck-inherited-copy-bound.rs:24:13 | -LL | let z = &x as &Foo; +LL | let z = &x as &dyn Foo; | ^^ the trait `Foo` cannot be made into an object | = note: the trait cannot require that `Self : Sized` @@ -30,5 +30,5 @@ LL | let z = &x as &Foo; error: aborting due to 3 previous errors -Some errors occurred: E0038, E0277. +Some errors have detailed explanations: E0038, E0277. For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/kindck/kindck-send-object.rs b/src/test/ui/kindck/kindck-send-object.rs index 97f46c3953d51..6411e688b4aa6 100644 --- a/src/test/ui/kindck/kindck-send-object.rs +++ b/src/test/ui/kindck/kindck-send-object.rs @@ -9,18 +9,18 @@ trait Message : Send { } // careful with object types, who knows what they close over... fn object_ref_with_static_bound_not_ok() { - assert_send::<&'static (Dummy+'static)>(); + assert_send::<&'static (dyn Dummy + 'static)>(); //~^ ERROR `(dyn Dummy + 'static)` cannot be shared between threads safely [E0277] } fn box_object_with_no_bound_not_ok<'a>() { - assert_send::>(); + assert_send::>(); //~^ ERROR `dyn Dummy` cannot be sent between threads safely } fn object_with_send_bound_ok() { - assert_send::<&'static (Dummy+Sync)>(); - assert_send::>(); + assert_send::<&'static (dyn Dummy + Sync)>(); + assert_send::>(); } fn main() { } diff --git a/src/test/ui/kindck/kindck-send-object.stderr b/src/test/ui/kindck/kindck-send-object.stderr index 8d9935660292f..c9aadd85a53f2 100644 --- a/src/test/ui/kindck/kindck-send-object.stderr +++ b/src/test/ui/kindck/kindck-send-object.stderr @@ -1,8 +1,8 @@ error[E0277]: `(dyn Dummy + 'static)` cannot be shared between threads safely --> $DIR/kindck-send-object.rs:12:5 | -LL | assert_send::<&'static (Dummy+'static)>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'static)` cannot be shared between threads safely +LL | assert_send::<&'static (dyn Dummy + 'static)>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'static)` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'static)` = note: required because of the requirements on the impl of `std::marker::Send` for `&'static (dyn Dummy + 'static)` @@ -15,8 +15,8 @@ LL | fn assert_send() { } error[E0277]: `dyn Dummy` cannot be sent between threads safely --> $DIR/kindck-send-object.rs:17:5 | -LL | assert_send::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely +LL | assert_send::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `dyn Dummy` = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique` diff --git a/src/test/ui/kindck/kindck-send-object1.nll.stderr b/src/test/ui/kindck/kindck-send-object1.nll.stderr new file mode 100644 index 0000000000000..998dc90456f14 --- /dev/null +++ b/src/test/ui/kindck/kindck-send-object1.nll.stderr @@ -0,0 +1,32 @@ +error[E0277]: `(dyn Dummy + 'a)` cannot be shared between threads safely + --> $DIR/kindck-send-object1.rs:10:5 + | +LL | assert_send::<&'a dyn Dummy>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be shared between threads safely + | + = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'a)` + = note: required because of the requirements on the impl of `std::marker::Send` for `&'a (dyn Dummy + 'a)` +note: required by `assert_send` + --> $DIR/kindck-send-object1.rs:5:1 + | +LL | fn assert_send() { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely + --> $DIR/kindck-send-object1.rs:29:5 + | +LL | assert_send::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely + | + = help: the trait `std::marker::Send` is not implemented for `(dyn Dummy + 'a)` + = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn Dummy + 'a)>` + = note: required because it appears within the type `std::boxed::Box<(dyn Dummy + 'a)>` +note: required by `assert_send` + --> $DIR/kindck-send-object1.rs:5:1 + | +LL | fn assert_send() { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/kindck/kindck-send-object1.rs b/src/test/ui/kindck/kindck-send-object1.rs index 341985467de6c..0e198395c26fb 100644 --- a/src/test/ui/kindck/kindck-send-object1.rs +++ b/src/test/ui/kindck/kindck-send-object1.rs @@ -7,26 +7,26 @@ trait Dummy { } // careful with object types, who knows what they close over... fn test51<'a>() { - assert_send::<&'a Dummy>(); + assert_send::<&'a dyn Dummy>(); //~^ ERROR `(dyn Dummy + 'a)` cannot be shared between threads safely [E0277] } fn test52<'a>() { - assert_send::<&'a (Dummy+Sync)>(); + assert_send::<&'a (dyn Dummy + Sync)>(); //~^ ERROR does not fulfill the required lifetime } // ...unless they are properly bounded fn test60() { - assert_send::<&'static (Dummy+Sync)>(); + assert_send::<&'static (dyn Dummy + Sync)>(); } fn test61() { - assert_send::>(); + assert_send::>(); } // closure and object types can have lifetime bounds which make // them not ok fn test_71<'a>() { - assert_send::>(); + assert_send::>(); //~^ ERROR `(dyn Dummy + 'a)` cannot be sent between threads safely } diff --git a/src/test/ui/kindck/kindck-send-object1.stderr b/src/test/ui/kindck/kindck-send-object1.stderr index 4f2d09a60f564..757b41ab6cb7e 100644 --- a/src/test/ui/kindck/kindck-send-object1.stderr +++ b/src/test/ui/kindck/kindck-send-object1.stderr @@ -1,8 +1,8 @@ error[E0277]: `(dyn Dummy + 'a)` cannot be shared between threads safely --> $DIR/kindck-send-object1.rs:10:5 | -LL | assert_send::<&'a Dummy>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be shared between threads safely +LL | assert_send::<&'a dyn Dummy>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'a)` = note: required because of the requirements on the impl of `std::marker::Send` for `&'a (dyn Dummy + 'a)` @@ -15,16 +15,16 @@ LL | fn assert_send() { } error[E0477]: the type `&'a (dyn Dummy + std::marker::Sync + 'a)` does not fulfill the required lifetime --> $DIR/kindck-send-object1.rs:14:5 | -LL | assert_send::<&'a (Dummy+Sync)>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | assert_send::<&'a (dyn Dummy + Sync)>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: type must satisfy the static lifetime error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely --> $DIR/kindck-send-object1.rs:29:5 | -LL | assert_send::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely +LL | assert_send::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `(dyn Dummy + 'a)` = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn Dummy + 'a)>` @@ -37,5 +37,4 @@ LL | fn assert_send() { } error: aborting due to 3 previous errors -Some errors occurred: E0277, E0477. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/kindck/kindck-send-object2.rs b/src/test/ui/kindck/kindck-send-object2.rs index 911ad988081f5..b797588e446d6 100644 --- a/src/test/ui/kindck/kindck-send-object2.rs +++ b/src/test/ui/kindck/kindck-send-object2.rs @@ -4,21 +4,21 @@ fn assert_send() { } trait Dummy { } fn test50() { - assert_send::<&'static Dummy>(); + assert_send::<&'static dyn Dummy>(); //~^ ERROR `(dyn Dummy + 'static)` cannot be shared between threads safely [E0277] } fn test53() { - assert_send::>(); + assert_send::>(); //~^ ERROR `dyn Dummy` cannot be sent between threads safely } // ...unless they are properly bounded fn test60() { - assert_send::<&'static (Dummy+Sync)>(); + assert_send::<&'static (dyn Dummy + Sync)>(); } fn test61() { - assert_send::>(); + assert_send::>(); } fn main() { } diff --git a/src/test/ui/kindck/kindck-send-object2.stderr b/src/test/ui/kindck/kindck-send-object2.stderr index db79989dc5f6c..c1c9db9da839a 100644 --- a/src/test/ui/kindck/kindck-send-object2.stderr +++ b/src/test/ui/kindck/kindck-send-object2.stderr @@ -1,8 +1,8 @@ error[E0277]: `(dyn Dummy + 'static)` cannot be shared between threads safely --> $DIR/kindck-send-object2.rs:7:5 | -LL | assert_send::<&'static Dummy>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'static)` cannot be shared between threads safely +LL | assert_send::<&'static dyn Dummy>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'static)` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'static)` = note: required because of the requirements on the impl of `std::marker::Send` for `&'static (dyn Dummy + 'static)` @@ -15,8 +15,8 @@ LL | fn assert_send() { } error[E0277]: `dyn Dummy` cannot be sent between threads safely --> $DIR/kindck-send-object2.rs:12:5 | -LL | assert_send::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely +LL | assert_send::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `dyn Dummy` = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique` diff --git a/src/test/ui/label/label-static.stderr b/src/test/ui/label/label-static.stderr index 52ab547aa7bb0..1d3251d1b5f45 100644 --- a/src/test/ui/label/label-static.stderr +++ b/src/test/ui/label/label-static.stderr @@ -1,13 +1,13 @@ error: invalid label name `'static` --> $DIR/label-static.rs:2:5 | -LL | 'static: loop { //~ ERROR invalid label name `'static` +LL | 'static: loop { | ^^^^^^^ error: invalid label name `'static` --> $DIR/label-static.rs:3:15 | -LL | break 'static //~ ERROR invalid label name `'static` +LL | break 'static | ^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/label/label-underscore.stderr b/src/test/ui/label/label-underscore.stderr index a4925c8619edc..4558ec4cb41f6 100644 --- a/src/test/ui/label/label-underscore.stderr +++ b/src/test/ui/label/label-underscore.stderr @@ -1,13 +1,13 @@ error: invalid label name `'_` --> $DIR/label-underscore.rs:2:5 | -LL | '_: loop { //~ ERROR invalid label name `'_` +LL | '_: loop { | ^^ error: invalid label name `'_` --> $DIR/label-underscore.rs:3:15 | -LL | break '_ //~ ERROR invalid label name `'_` +LL | break '_ | ^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/label/label_break_value_continue.stderr b/src/test/ui/label/label_break_value_continue.stderr index c0decc8255244..b3c0b421023ac 100644 --- a/src/test/ui/label/label_break_value_continue.stderr +++ b/src/test/ui/label/label_break_value_continue.stderr @@ -1,30 +1,29 @@ error[E0695]: unlabeled `continue` inside of a labeled block --> $DIR/label_break_value_continue.rs:7:9 | -LL | continue; //~ ERROR unlabeled `continue` inside of a labeled block +LL | continue; | ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label error[E0696]: `continue` pointing to a labeled block --> $DIR/label_break_value_continue.rs:14:9 | -LL | continue 'b; //~ ERROR `continue` pointing to a labeled block +LL | continue 'b; | ^^^^^^^^^^^ labeled blocks cannot be `continue`'d | note: labeled block the continue points to --> $DIR/label_break_value_continue.rs:13:5 | LL | / 'b: { -LL | | continue 'b; //~ ERROR `continue` pointing to a labeled block +LL | | continue 'b; LL | | } | |_____^ error[E0695]: unlabeled `continue` inside of a labeled block --> $DIR/label_break_value_continue.rs:22:13 | -LL | continue; //~ ERROR unlabeled `continue` inside of a labeled block +LL | continue; | ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label error: aborting due to 3 previous errors -Some errors occurred: E0695, E0696. -For more information about an error, try `rustc --explain E0695`. +For more information about this error, try `rustc --explain E0695`. diff --git a/src/test/ui/label/label_break_value_illegal_uses.stderr b/src/test/ui/label/label_break_value_illegal_uses.stderr index 889df17de44d5..0b9754c3c70e3 100644 --- a/src/test/ui/label/label_break_value_illegal_uses.stderr +++ b/src/test/ui/label/label_break_value_illegal_uses.stderr @@ -1,13 +1,13 @@ error: expected one of `extern`, `fn`, or `{`, found `'b` --> $DIR/label_break_value_illegal_uses.rs:6:12 | -LL | unsafe 'b: {} //~ ERROR expected one of `extern`, `fn`, or `{` +LL | unsafe 'b: {} | ^^ expected one of `extern`, `fn`, or `{` here error: expected `{`, found `'b` --> $DIR/label_break_value_illegal_uses.rs:10:13 | -LL | if true 'b: {} //~ ERROR expected `{`, found `'b` +LL | if true 'b: {} | -- ^^---- | | | | | expected `{` @@ -17,7 +17,7 @@ LL | if true 'b: {} //~ ERROR expected `{`, found `'b` error: expected `{`, found `'b` --> $DIR/label_break_value_illegal_uses.rs:14:21 | -LL | if true {} else 'b: {} //~ ERROR expected `{`, found `'b` +LL | if true {} else 'b: {} | ^^---- | | | expected `{` @@ -26,7 +26,7 @@ LL | if true {} else 'b: {} //~ ERROR expected `{`, found `'b` error: expected one of `.`, `?`, `{`, or an operator, found `'b` --> $DIR/label_break_value_illegal_uses.rs:18:17 | -LL | match false 'b: {} //~ ERROR expected one of `.`, `?`, `{`, or an operator +LL | match false 'b: {} | ----- ^^ expected one of `.`, `?`, `{`, or an operator here | | | while parsing this match expression diff --git a/src/test/ui/label/label_break_value_unlabeled_break.stderr b/src/test/ui/label/label_break_value_unlabeled_break.stderr index 1d6e27d4c3d0f..0c4f573d27db5 100644 --- a/src/test/ui/label/label_break_value_unlabeled_break.stderr +++ b/src/test/ui/label/label_break_value_unlabeled_break.stderr @@ -1,13 +1,13 @@ error[E0695]: unlabeled `break` inside of a labeled block --> $DIR/label_break_value_unlabeled_break.rs:7:9 | -LL | break; //~ ERROR unlabeled `break` inside of a labeled block +LL | break; | ^^^^^ `break` statements that would diverge to or through a labeled block need to bear a label error[E0695]: unlabeled `break` inside of a labeled block --> $DIR/label_break_value_unlabeled_break.rs:15:13 | -LL | break; //~ ERROR unlabeled `break` inside of a labeled block +LL | break; | ^^^^^ `break` statements that would diverge to or through a labeled block need to bear a label error: aborting due to 2 previous errors diff --git a/src/test/ui/lexical-scopes.stderr b/src/test/ui/lexical-scopes.stderr index 51313033a02dd..e990f705af3f9 100644 --- a/src/test/ui/lexical-scopes.stderr +++ b/src/test/ui/lexical-scopes.stderr @@ -1,7 +1,7 @@ error[E0574]: expected struct, variant or union type, found type parameter `T` --> $DIR/lexical-scopes.rs:3:13 | -LL | let t = T { i: 0 }; //~ ERROR expected struct, variant or union type, found type parameter `T` +LL | let t = T { i: 0 }; | ^ not a struct, variant or union type help: possible better candidate is found in another module, you can import it into scope | @@ -11,12 +11,9 @@ LL | use T; error[E0599]: no function or associated item named `f` found for type `Foo` in the current scope --> $DIR/lexical-scopes.rs:10:10 | -LL | Foo::f(); //~ ERROR no function or associated item named `f` - | -----^ - | | - | function or associated item not found in `Foo` +LL | Foo::f(); + | ^ function or associated item not found in `Foo` error: aborting due to 2 previous errors -Some errors occurred: E0574, E0599. -For more information about an error, try `rustc --explain E0574`. +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/lifetime-before-type-params.stderr b/src/test/ui/lifetime-before-type-params.stderr index 3cef5db66c66f..ffc6784bafed8 100644 --- a/src/test/ui/lifetime-before-type-params.stderr +++ b/src/test/ui/lifetime-before-type-params.stderr @@ -2,25 +2,25 @@ error: lifetime parameters must be declared prior to type parameters --> $DIR/lifetime-before-type-params.rs:2:13 | LL | fn first() {} - | ----^^--^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>` + | ----^^--^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>` error: lifetime parameters must be declared prior to type parameters --> $DIR/lifetime-before-type-params.rs:4:18 | LL | fn second<'a, T, 'b>() {} - | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>` + | --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>` error: lifetime parameters must be declared prior to type parameters --> $DIR/lifetime-before-type-params.rs:6:16 | LL | fn third() {} - | -------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, U>` + | -------^^- help: reorder the parameters: lifetimes, then types: `<'a, T, U>` error: lifetime parameters must be declared prior to type parameters --> $DIR/lifetime-before-type-params.rs:8:18 | LL | fn fourth<'a, T, 'b, U, 'c, V>() {} - | --------^^-----^^---- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, 'c, T, U, V>` + | --------^^-----^^---- help: reorder the parameters: lifetimes, then types: `<'a, 'b, 'c, T, U, V>` error[E0601]: `main` function not found in crate `lifetime_before_type_params` | diff --git a/src/test/ui/lifetime_starts_expressions.stderr b/src/test/ui/lifetime_starts_expressions.stderr index fa0a7ac002b2f..8ae8018c2ff25 100644 --- a/src/test/ui/lifetime_starts_expressions.stderr +++ b/src/test/ui/lifetime_starts_expressions.stderr @@ -13,6 +13,14 @@ error: expected type, found keyword `loop` | LL | loop { break 'label: loop { break 'label 42; }; } | ^^^^ expecting a type here because of type ascription + | + = note: #![feature(type_ascription)] lets you annotate an expression with a type: `: ` +note: this expression expects an ascribed type after the colon + --> $DIR/lifetime_starts_expressions.rs:6:12 + | +LL | loop { break 'label: loop { break 'label 42; }; } + | ^^^^^^^^^^^^ + = help: this might be indicative of a syntax error elsewhere error: aborting due to 2 previous errors diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr b/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr deleted file mode 100644 index d70524b2387fd..0000000000000 --- a/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-let-suggestion.rs:2:17 - | -LL | let mut x = vec![1].iter(); - | ^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary which is freed while still in use -LL | //~^ ERROR borrowed value does not live long enough -LL | x.use_mut(); - | - borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.rs b/src/test/ui/lifetimes/borrowck-let-suggestion.rs index 1deb0457e95af..3d591a506d59e 100644 --- a/src/test/ui/lifetimes/borrowck-let-suggestion.rs +++ b/src/test/ui/lifetimes/borrowck-let-suggestion.rs @@ -1,6 +1,6 @@ fn f() { let mut x = vec![1].iter(); - //~^ ERROR borrowed value does not live long enough + //~^ ERROR temporary value dropped while borrowed x.use_mut(); } diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr index 7a95137ac9274..0e2fc0a0fe97e 100644 --- a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr +++ b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr @@ -1,17 +1,17 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion.rs:2:17 | LL | let mut x = vec![1].iter(); - | ^^^^^^^ - temporary value dropped here while still borrowed + | ^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough -... -LL | } - | - temporary value needs to live until here + | creates a temporary which is freed while still in use +LL | +LL | x.use_mut(); + | - borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr new file mode 100644 index 0000000000000..f2cf19abdac31 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr @@ -0,0 +1,20 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/lifetime-bound-will-change-warning.rs:34:5 + | +LL | fn test2<'a>(x: &'a Box) { + | - `x` is a reference that is only valid in the function body +LL | // but ref_obj will not, so warn. +LL | ref_obj(x) + | ^^^^^^^^^^ `x` escapes the function body here + +error[E0521]: borrowed data escapes outside of function + --> $DIR/lifetime-bound-will-change-warning.rs:39:5 + | +LL | fn test2cc<'a>(x: &'a Box) { + | - `x` is a reference that is only valid in the function body +LL | // same as test2, but cross crate +LL | lib::ref_obj(x) + | ^^^^^^^^^^^^^^^ `x` escapes the function body here + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.rs b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.rs index 5461f875af6c5..3c6d92234c4fa 100644 --- a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.rs +++ b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.rs @@ -9,42 +9,42 @@ extern crate lifetime_bound_will_change_warning_lib as lib; -fn just_ref(x: &Fn()) { +fn just_ref(x: &dyn Fn()) { } -fn ref_obj(x: &Box) { +fn ref_obj(x: &Box) { // this will change to &Box... // Note: no warning is issued here, because the type of `x` will change to 'static if false { ref_obj(x); } } -fn test1<'a>(x: &'a Box) { +fn test1<'a>(x: &'a Box) { // just_ref will stay the same. just_ref(&**x) } -fn test1cc<'a>(x: &'a Box) { +fn test1cc<'a>(x: &'a Box) { // same as test1, but cross-crate lib::just_ref(&**x) } -fn test2<'a>(x: &'a Box) { +fn test2<'a>(x: &'a Box) { // but ref_obj will not, so warn. ref_obj(x) //~ ERROR mismatched types } -fn test2cc<'a>(x: &'a Box) { +fn test2cc<'a>(x: &'a Box) { // same as test2, but cross crate lib::ref_obj(x) //~ ERROR mismatched types } -fn test3<'a>(x: &'a Box) { +fn test3<'a>(x: &'a Box) { // here, we have a 'static bound, so even when ref_obj changes, no error results ref_obj(x) } -fn test3cc<'a>(x: &'a Box) { +fn test3cc<'a>(x: &'a Box) { // same as test3, but cross crate lib::ref_obj(x) } diff --git a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr index a283a0b29e6c4..35d63c1727651 100644 --- a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr +++ b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/lifetime-bound-will-change-warning.rs:34:13 | -LL | ref_obj(x) //~ ERROR mismatched types +LL | ref_obj(x) | ^ lifetime mismatch | = note: expected type `&std::boxed::Box<(dyn std::ops::Fn() + 'static)>` @@ -9,14 +9,14 @@ LL | ref_obj(x) //~ ERROR mismatched types note: the lifetime 'a as defined on the function body at 32:10... --> $DIR/lifetime-bound-will-change-warning.rs:32:10 | -LL | fn test2<'a>(x: &'a Box) { +LL | fn test2<'a>(x: &'a Box) { | ^^ = note: ...does not necessarily outlive the static lifetime error[E0308]: mismatched types --> $DIR/lifetime-bound-will-change-warning.rs:39:18 | -LL | lib::ref_obj(x) //~ ERROR mismatched types +LL | lib::ref_obj(x) | ^ lifetime mismatch | = note: expected type `&std::boxed::Box<(dyn std::ops::Fn() + 'static)>` @@ -24,7 +24,7 @@ LL | lib::ref_obj(x) //~ ERROR mismatched types note: the lifetime 'a as defined on the function body at 37:12... --> $DIR/lifetime-bound-will-change-warning.rs:37:12 | -LL | fn test2cc<'a>(x: &'a Box) { +LL | fn test2cc<'a>(x: &'a Box) { | ^^ = note: ...does not necessarily outlive the static lifetime diff --git a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr index d4ca1aec6978b..7b823f012b9f9 100644 --- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr +++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr @@ -46,7 +46,7 @@ LL | fn baz<'a, L, M: X<&'a Nested>>() { | ^ - help: consider adding an explicit lifetime bound `L: 'a`... | _____| | | -LL | | //~^ ERROR may not live long enough +LL | | LL | | } | |_____^ | @@ -54,7 +54,7 @@ note: ...so that the reference type `&'a Nested` does not outlive the data it --> $DIR/lifetime-doesnt-live-long-enough.rs:32:5 | LL | / fn baz<'a, L, M: X<&'a Nested>>() { -LL | | //~^ ERROR may not live long enough +LL | | LL | | } | |_____^ @@ -64,7 +64,7 @@ error[E0309]: the parameter type `K` may not live long enough LL | impl Nested { | - help: consider adding an explicit lifetime bound `K: 'a`... LL | / fn generic_in_parent<'a, L: X<&'a Nested>>() { -LL | | //~^ ERROR may not live long enough +LL | | LL | | } | |_____^ | @@ -72,7 +72,7 @@ note: ...so that the reference type `&'a Nested` does not outlive the data it --> $DIR/lifetime-doesnt-live-long-enough.rs:41:5 | LL | / fn generic_in_parent<'a, L: X<&'a Nested>>() { -LL | | //~^ ERROR may not live long enough +LL | | LL | | } | |_____^ @@ -83,7 +83,7 @@ LL | fn generic_in_child<'a, 'b, L: X<&'a Nested>, M: 'b>() { | ^ -- help: consider adding an explicit lifetime bound `M: 'a`... | _____| | | -LL | | //~^ ERROR may not live long enough +LL | | LL | | } | |_____^ | @@ -91,11 +91,11 @@ note: ...so that the reference type `&'a Nested` does not outlive the data it --> $DIR/lifetime-doesnt-live-long-enough.rs:44:5 | LL | / fn generic_in_child<'a, 'b, L: X<&'a Nested>, M: 'b>() { -LL | | //~^ ERROR may not live long enough +LL | | LL | | } | |_____^ error: aborting due to 6 previous errors -Some errors occurred: E0309, E0310. +Some errors have detailed explanations: E0309, E0310. For more information about an error, try `rustc --explain E0309`. diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr index cf825c52f569e..3f7c3934a0ba2 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr @@ -1,7 +1,7 @@ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:2:11 | -LL | fn f() -> &isize { //~ ERROR missing lifetime specifier +LL | fn f() -> &isize { | ^ help: consider giving it a 'static lifetime: `&'static` | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from @@ -9,7 +9,7 @@ LL | fn f() -> &isize { //~ ERROR missing lifetime specifier error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33 | -LL | fn g(_x: &isize, _y: &isize) -> &isize { //~ ERROR missing lifetime specifier +LL | fn g(_x: &isize, _y: &isize) -> &isize { | ^ expected lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_x` or `_y` @@ -17,7 +17,7 @@ LL | fn g(_x: &isize, _y: &isize) -> &isize { //~ ERROR missing lifetime spec error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:19 | -LL | fn h(_x: &Foo) -> &isize { //~ ERROR missing lifetime specifier +LL | fn h(_x: &Foo) -> &isize { | ^ expected lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from @@ -25,7 +25,7 @@ LL | fn h(_x: &Foo) -> &isize { //~ ERROR missing lifetime specifier error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20 | -LL | fn i(_x: isize) -> &isize { //~ ERROR missing lifetime specifier +LL | fn i(_x: isize) -> &isize { | ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static` | = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments @@ -33,7 +33,7 @@ LL | fn i(_x: isize) -> &isize { //~ ERROR missing lifetime specifier error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:34:24 | -LL | fn j(_x: StaticStr) -> &isize { //~ ERROR missing lifetime specifier +LL | fn j(_x: StaticStr) -> &isize { | ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static` | = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs index 1c288a7e44f37..2370084b072c7 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs @@ -5,7 +5,7 @@ trait Future { use std::error::Error; -fn foo() -> impl Future> { +fn foo() -> impl Future> { //~^ ERROR missing lifetime Ok(()) } diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr index b2a3d9a94361f..06b317ce95278 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr @@ -1,8 +1,8 @@ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-trait.rs:8:44 | -LL | fn foo() -> impl Future> { - | ^^^^^ help: consider giving it a 'static lifetime: `Error + 'static` +LL | fn foo() -> impl Future> { + | ^^^^^^^^^ help: consider giving it a 'static lifetime: `dyn Error + 'static` | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from diff --git a/src/test/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr b/src/test/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr index 6211a9a114176..63d00875dd330 100644 --- a/src/test/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr @@ -4,7 +4,7 @@ error[E0621]: explicit lifetime required in the type of `x` LL | fn foo2<'a>(a: &'a Foo, x: &i32) -> &'a i32 { | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` ... -LL | &*x //~ ERROR explicit lifetime +LL | &*x | ^^^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr index 9fe1679936d87..64aa8361cd5ea 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr @@ -4,7 +4,7 @@ error[E0621]: explicit lifetime required in the type of `other` LL | fn bar(&self, other: Foo) -> Foo<'a> { | --- help: add explicit lifetime `'a` to the type of `other`: `Foo<'a>` ... -LL | other //~ ERROR explicit lifetime +LL | other | ^^^^^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr index 94ec5248eb00e..b40481ecdc401 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr @@ -3,7 +3,7 @@ error[E0621]: explicit lifetime required in the type of `x` | LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` -LL | if x > y { x } else { y } //~ ERROR explicit lifetime +LL | if x > y { x } else { y } | ^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr index 4be638bf4c210..194fd95891eb0 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr @@ -3,7 +3,7 @@ error[E0621]: explicit lifetime required in parameter type | LL | fn foo<'a>((x, y): (&'a i32, &i32)) -> &'a i32 { | --------------- help: add explicit lifetime `'a` to type: `(&'a i32, &'a i32)` -LL | if x > y { x } else { y } //~ ERROR explicit lifetime +LL | if x > y { x } else { y } | ^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr index d61271b81ac1d..64f4bd0fc7061 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr @@ -3,7 +3,7 @@ error[E0621]: explicit lifetime required in the type of `x` | LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` -LL | if x > y { x } else { y } //~ ERROR explicit lifetime +LL | if x > y { x } else { y } | ^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr index 15642be44b7ed..f764ec43ad1cd 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr @@ -4,7 +4,7 @@ error[E0621]: explicit lifetime required in the type of `x` LL | fn foo<'a>(&'a self, x: &i32) -> &i32 { | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` LL | -LL | if true { &self.field } else { x } //~ ERROR explicit lifetime +LL | if true { &self.field } else { x } | ^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr new file mode 100644 index 0000000000000..fc9093bb2e4b8 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/ex1-return-one-existing-name-if-else-using-impl.rs:11:20 + | +LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { + | -- - let's call the lifetime of this reference `'1` + | | + | lifetime `'a` defined here +LL | +LL | if x > y { x } else { y } + | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr index 1eaa9c8339f7a..56ca610019c4c 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr @@ -6,9 +6,8 @@ LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { | | | this parameter and the return type are declared with different lifetimes... LL | -LL | if x > y { x } else { y } //~ ERROR lifetime mismatch +LL | if x > y { x } else { y } | ^ ...but data from `x` is returned here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr index d48adf1680806..29a70695710f7 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr @@ -3,7 +3,7 @@ error[E0621]: explicit lifetime required in the type of `y` | LL | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { | ---- help: add explicit lifetime `'a` to the type of `y`: `&'a i32` -LL | if x > y { x } else { y } //~ ERROR explicit lifetime +LL | if x > y { x } else { y } | ^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr new file mode 100644 index 0000000000000..3384c24da8fbe --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:8:5 + | +LL | fn foo<'a>(&self, x: &'a i32) -> &i32 { + | -- - let's call the lifetime of this reference `'1` + | | + | lifetime `'a` defined here +LL | +LL | x + | ^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr index f4b2efa8438c6..df34d18ee83a4 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr @@ -6,9 +6,8 @@ LL | fn foo<'a>(&self, x: &'a i32) -> &i32 { | | | this parameter and the return type are declared with different lifetimes... LL | -LL | x //~ ERROR lifetime mismatch +LL | x | ^ ...but data from `x` is returned here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr new file mode 100644 index 0000000000000..5ef29076e07bf --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/ex1-return-one-existing-name-self-is-anon.rs:8:30 + | +LL | fn foo<'a>(&self, x: &'a Foo) -> &'a Foo { + | -- - let's call the lifetime of this reference `'1` + | | + | lifetime `'a` defined here +LL | +LL | if true { x } else { self } + | ^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr index 328c69bb65868..22e14df9edc03 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr @@ -6,9 +6,8 @@ LL | fn foo<'a>(&self, x: &'a Foo) -> &'a Foo { | | | this parameter and the return type are declared with different lifetimes... LL | -LL | if true { x } else { self } //~ ERROR lifetime mismatch +LL | if true { x } else { self } | ^^^^ ...but data from `self` is returned here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr index 9fc1124685c59..a4e0d71a3fa6b 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr @@ -1,7 +1,7 @@ error[E0106]: missing lifetime specifier --> $DIR/ex1b-return-no-names-if-else.rs:1:29 | -LL | fn foo(x: &i32, y: &i32) -> &i32 { //~ ERROR missing lifetime +LL | fn foo(x: &i32, y: &i32) -> &i32 { | ^ expected lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr new file mode 100644 index 0000000000000..90d4754ebab82 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr @@ -0,0 +1,11 @@ +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/ex2a-push-one-existing-name-2.rs:6:5 + | +LL | fn foo<'a>(x: Ref, y: &mut Vec>) { + | -------- help: add explicit lifetime `'a` to the type of `x`: `Ref<'a, i32>` +LL | y.push(x); + | ^^^^^^^^^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr index 3df29e62a283b..412cac4356368 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr @@ -3,7 +3,7 @@ error[E0621]: explicit lifetime required in the type of `x` | LL | fn foo<'a>(x: Ref, y: &mut Vec>) { | -------- help: add explicit lifetime `'a` to the type of `x`: `Ref<'a, i32>` -LL | y.push(x); //~ ERROR explicit lifetime +LL | y.push(x); | ^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr new file mode 100644 index 0000000000000..a03e16b3b7919 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr @@ -0,0 +1,12 @@ +error[E0621]: explicit lifetime required in the type of `y` + --> $DIR/ex2a-push-one-existing-name-early-bound.rs:8:5 + | +LL | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T) + | -- help: add explicit lifetime `'a` to the type of `y`: `&'a T` +... +LL | x.push(y); + | ^^^^^^^^^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr index 0fd085c39f282..30826c3613c58 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr @@ -4,7 +4,7 @@ error[E0621]: explicit lifetime required in the type of `y` LL | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T) | -- help: add explicit lifetime `'a` to the type of `y`: `&'a T` ... -LL | x.push(y); //~ ERROR explicit lifetime required +LL | x.push(y); | ^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.nll.stderr new file mode 100644 index 0000000000000..487b34e3d18f4 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.nll.stderr @@ -0,0 +1,11 @@ +error[E0621]: explicit lifetime required in the type of `y` + --> $DIR/ex2a-push-one-existing-name.rs:6:5 + | +LL | fn foo<'a>(x: &mut Vec>, y: Ref) { + | -------- help: add explicit lifetime `'a` to the type of `y`: `Ref<'a, i32>` +LL | x.push(y); + | ^^^^^^^^^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr index a669e33ab098e..13d0835287d04 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr @@ -3,7 +3,7 @@ error[E0621]: explicit lifetime required in the type of `y` | LL | fn foo<'a>(x: &mut Vec>, y: Ref) { | -------- help: add explicit lifetime `'a` to the type of `y`: `Ref<'a, i32>` -LL | x.push(y); //~ ERROR explicit lifetime +LL | x.push(y); | ^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr new file mode 100644 index 0000000000000..735f7a0dfc633 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/ex2b-push-no-existing-names.rs:6:5 + | +LL | fn foo(x: &mut Vec>, y: Ref) { + | - - has type `Ref<'1, i32>` + | | + | has type `&mut std::vec::Vec>` +LL | x.push(y); + | ^^^^^^^^^ argument requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr index 7ac61df495486..c0c75c7453d24 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo(x: &mut Vec>, y: Ref) { | -------- -------- these two types are declared with different lifetimes... -LL | x.push(y); //~ ERROR lifetime mismatch +LL | x.push(y); | ^ ...but data from `y` flows into `x` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.nll.stderr new file mode 100644 index 0000000000000..fbefa1f5667c7 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/ex2c-push-inference-variable.rs:7:5 + | +LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { + | -- -- lifetime `'c` defined here + | | + | lifetime `'b` defined here +LL | let z = Ref { data: y.data }; +LL | x.push(z); + | ^^^^^^^^^ argument requires that `'c` must outlive `'b` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.stderr index bfa9c0d15f0f9..57101cffe9b92 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.stderr @@ -4,9 +4,8 @@ error[E0623]: lifetime mismatch LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { | ------------ ------------ these two types are declared with different lifetimes... LL | let z = Ref { data: y.data }; -LL | x.push(z); //~ ERROR lifetime mismatch +LL | x.push(z); | ^ ...but data from `y` flows into `x` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr new file mode 100644 index 0000000000000..d889eb4afdbe5 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/ex2d-push-inference-variable-2.rs:8:5 + | +LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { + | -- -- lifetime `'c` defined here + | | + | lifetime `'b` defined here +... +LL | a.push(b); + | ^^^^^^^^^ argument requires that `'c` must outlive `'b` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.stderr index 2db81f8aba6e8..cab30636280a9 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { | ------------ ------------ these two types are declared with different lifetimes... -LL | let a: &mut Vec> = x; //~ ERROR lifetime mismatch +LL | let a: &mut Vec> = x; | ^ ...but data from `y` flows into `x` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr new file mode 100644 index 0000000000000..39eb4079352c3 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/ex2e-push-inference-variable-3.rs:8:5 + | +LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { + | -- -- lifetime `'c` defined here + | | + | lifetime `'b` defined here +... +LL | Vec::push(a, b); + | ^^^^^^^^^^^^^^^ argument requires that `'c` must outlive `'b` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.stderr index 85a6dba928932..384caca824892 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { | ------------ ------------ these two types are declared with different lifetimes... -LL | let a: &mut Vec> = x; //~ ERROR lifetime mismatch +LL | let a: &mut Vec> = x; | ^ ...but data from `y` flows into `x` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.nll.stderr new file mode 100644 index 0000000000000..a94f9a799061a --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-2.rs:2:5 + | +LL | fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | *v = x; + | ^^^^^^ assignment requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr index b8f97d145772b..9251c5e2446f3 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) { | --- --- these two types are declared with different lifetimes... -LL | *v = x; //~ ERROR lifetime mismatch +LL | *v = x; | ^ ...but data from `x` flows here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr new file mode 100644 index 0000000000000..779e2eb8b9205 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr @@ -0,0 +1,22 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-3.rs:2:5 + | +LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | z.push((x,y)); + | ^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-3.rs:2:5 + | +LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | z.push((x,y)); + | ^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.rs b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.rs index c04b5d3a3eb71..c483f59f9d98c 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.rs +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.rs @@ -4,4 +4,3 @@ fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { } fn main() { } - diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr index acfe809b6785b..adda66899cbf0 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr @@ -3,7 +3,7 @@ error[E0623]: lifetime mismatch | LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { | --- --- these two types are declared with different lifetimes... -LL | z.push((x,y)); //~ ERROR lifetime mismatch +LL | z.push((x,y)); | ^ ...but data flows into `z` here error[E0623]: lifetime mismatch @@ -11,9 +11,8 @@ error[E0623]: lifetime mismatch | LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { | --- --- these two types are declared with different lifetimes... -LL | z.push((x,y)); //~ ERROR lifetime mismatch +LL | z.push((x,y)); | ^ ...but data flows into `z` here error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr new file mode 100644 index 0000000000000..4c0ffe5c0901a --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-both-are-structs-2.rs:7:5 + | +LL | fn foo(mut x: Ref, y: Ref) { + | ----- - has type `Ref<'_, '1>` + | | + | has type `Ref<'_, '2>` +LL | x.b = y.b; + | ^^^^^^^^^ assignment requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr index cb1ca5e1485b0..4341e8e663e19 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo(mut x: Ref, y: Ref) { | --- --- these two types are declared with different lifetimes... -LL | x.b = y.b; //~ ERROR lifetime mismatch +LL | x.b = y.b; | ^^^ ...but data from `y` flows into `x` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr new file mode 100644 index 0000000000000..97c665347f6ec --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-both-are-structs-3.rs:7:5 + | +LL | fn foo(mut x: Ref) { + | ----- + | | + | has type `Ref<'_, '1>` + | has type `Ref<'2, '_>` +LL | x.a = x.b; + | ^^^^^^^^^ assignment requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr index 863ec9806fca1..b49ee0cfc7033 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr @@ -2,12 +2,9 @@ error[E0623]: lifetime mismatch --> $DIR/ex3-both-anon-regions-both-are-structs-3.rs:7:11 | LL | fn foo(mut x: Ref) { - | --- - | | - | this type is declared with multiple lifetimes... -LL | x.a = x.b; //~ ERROR lifetime mismatch + | --- this type is declared with multiple lifetimes... +LL | x.a = x.b; | ^^^ ...but data with one lifetime flows into the other here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr new file mode 100644 index 0000000000000..a39bb165806f2 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-both-are-structs-earlybound-regions.rs:9:5 + | +LL | fn foo<'a, 'b>(mut x: Vec>, y: Ref<'b>) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | x.push(y); + | ^^^^^^^^^ argument requires that `'b` must outlive `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.stderr index 57174385b4dd8..a13c7e63cd6d9 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.stderr @@ -4,9 +4,8 @@ error[E0623]: lifetime mismatch LL | fn foo<'a, 'b>(mut x: Vec>, y: Ref<'b>) | ------- ------- these two types are declared with different lifetimes... ... -LL | x.push(y); //~ ERROR lifetime mismatch +LL | x.push(y); | ^ ...but data from `y` flows into `x` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr new file mode 100644 index 0000000000000..48ce5301adef3 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-both-are-structs-latebound-regions.rs:6:5 + | +LL | fn foo<'a, 'b>(mut x: Vec>, y: Ref<'b>) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x.push(y); + | ^^^^^^^^^ argument requires that `'b` must outlive `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.stderr index caa7397979bce..14faf6f460f52 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo<'a, 'b>(mut x: Vec>, y: Ref<'b>) { | ------- ------- these two types are declared with different lifetimes... -LL | x.push(y); //~ ERROR lifetime mismatch +LL | x.push(y); | ^ ...but data from `y` flows into `x` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr new file mode 100644 index 0000000000000..f9c33c2480693 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-both-are-structs.rs:6:5 + | +LL | fn foo(mut x: Vec, y: Ref) { + | ----- - has type `Ref<'1>` + | | + | has type `std::vec::Vec>` +LL | x.push(y); + | ^^^^^^^^^ argument requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr index 27d5f5da7e537..e5696b74da9ec 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo(mut x: Vec, y: Ref) { | --- --- these two types are declared with different lifetimes... -LL | x.push(y); //~ ERROR lifetime mismatch +LL | x.push(y); | ^ ...but data from `y` flows into `x` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr new file mode 100644 index 0000000000000..0996068398009 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-latebound-regions.rs:2:5 + | +LL | fn foo<'a,'b>(x: &mut Vec<&'a u8>, y: &'b u8) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x.push(y); + | ^^^^^^^^^ argument requires that `'b` must outlive `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.stderr index 97da7f8ac6df8..bbf5d2452bfb9 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo<'a,'b>(x: &mut Vec<&'a u8>, y: &'b u8) { | ------ ------ these two types are declared with different lifetimes... -LL | x.push(y); //~ ERROR lifetime mismatch +LL | x.push(y); | ^ ...but data from `y` flows into `x` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr new file mode 100644 index 0000000000000..5751c3194894e --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr @@ -0,0 +1,21 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:4:5 + | +LL | fn foo(mut x: Ref, y: &u32) { + | ----- - let's call the lifetime of this reference `'2` + | | + | has type `Ref<'_, '1>` +LL | y = x.b; + | ^^^^^^^ assignment requires that `'1` must outlive `'2` + +error[E0384]: cannot assign to immutable argument `y` + --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:4:5 + | +LL | fn foo(mut x: Ref, y: &u32) { + | - help: make this binding mutable: `mut y` +LL | y = x.b; + | ^^^^^^^ cannot assign to immutable argument + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr index 8c4e3daed4cae..f1bc1ca3aab01 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr @@ -5,9 +5,8 @@ LL | fn foo(mut x: Ref, y: &u32) { | --- ---- | | | these two types are declared with different lifetimes... -LL | y = x.b; //~ ERROR lifetime mismatch +LL | y = x.b; | ^^^ ...but data from `x` flows into `y` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr new file mode 100644 index 0000000000000..79e7e8e157d95 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-one-is-struct-3.rs:4:5 + | +LL | fn foo(mut y: Ref, x: &u32) { + | ----- - let's call the lifetime of this reference `'1` + | | + | has type `Ref<'_, '2>` +LL | y.b = x; + | ^^^^^^^ assignment requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr index b443707bbae4c..d8f6b8c49d30d 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo(mut y: Ref, x: &u32) { | --- ---- these two types are declared with different lifetimes... -LL | y.b = x; //~ ERROR lifetime mismatch +LL | y.b = x; | ^ ...but data from `x` flows into `y` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr new file mode 100644 index 0000000000000..53615fd1aba69 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-one-is-struct-4.rs:4:5 + | +LL | fn foo(mut y: Ref, x: &u32) { + | ----- - let's call the lifetime of this reference `'1` + | | + | has type `Ref<'_, '2>` +LL | y.b = x; + | ^^^^^^^ assignment requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr index 77d43cd17c8fd..08ae2c9db52e7 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo(mut y: Ref, x: &u32) { | --- ---- these two types are declared with different lifetimes... -LL | y.b = x; //~ ERROR lifetime mismatch +LL | y.b = x; | ^ ...but data from `x` flows into `y` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr new file mode 100644 index 0000000000000..6ff4411673756 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-one-is-struct.rs:7:5 + | +LL | fn foo(mut x: Ref, y: &u32) { + | ----- - let's call the lifetime of this reference `'1` + | | + | has type `Ref<'_, '2>` +LL | x.b = y; + | ^^^^^^^ assignment requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr index eef3aa50e0f2e..ff286d722aacd 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo(mut x: Ref, y: &u32) { | --- ---- these two types are declared with different lifetimes... -LL | x.b = y; //~ ERROR lifetime mismatch +LL | x.b = y; | ^ ...but data from `y` flows into `x` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr new file mode 100644 index 0000000000000..1c258ad98ba10 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:7:5 + | +LL | fn foo<'a>(&self, x: &i32) -> &i32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | x + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs index 09852403d934a..286cb6dc90e1b 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs @@ -9,4 +9,3 @@ impl Foo { } fn main() { } - diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr index 917b90fd47f90..3d16c26568353 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr @@ -5,9 +5,8 @@ LL | fn foo<'a>(&self, x: &i32) -> &i32 { | ---- ---- | | | this parameter and the return type are declared with different lifetimes... -LL | x //~ ERROR lifetime mismatch +LL | x | ^ ...but data from `x` is returned here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr new file mode 100644 index 0000000000000..ffe39fdd8c9f5 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-self-is-anon.rs:7:19 + | +LL | fn foo<'a>(&self, x: &Foo) -> &Foo { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | if true { x } else { self } + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.rs b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.rs index 33aa199938f83..79d7d63c8bb1e 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.rs +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.rs @@ -9,4 +9,3 @@ impl Foo { } fn main() {} - diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr index a2ba41ef4f09a..10872d31ef206 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr @@ -5,9 +5,8 @@ LL | fn foo<'a>(&self, x: &Foo) -> &Foo { | ---- ---- | | | this parameter and the return type are declared with different lifetimes... -LL | if true { x } else { self } //~ ERROR lifetime mismatch +LL | if true { x } else { self } | ^ ...but data from `x` is returned here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr new file mode 100644 index 0000000000000..33be98c64910d --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr @@ -0,0 +1,21 @@ +error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable + --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3 + | +LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { + | - help: consider changing this to be mutable: `mut y` +LL | y.push(z); + | ^ cannot borrow as mutable + +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3 + | +LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | y.push(z); + | ^^^^^^^^^ argument requires that `'1` must outlive `'2` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr index 43e54d640859d..99e6e8bc5aa9b 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { | --- --- these two types are declared with different lifetimes... -LL | y.push(z); //~ ERROR lifetime mismatch +LL | y.push(z); | ^ ...but data from `z` flows into `y` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr new file mode 100644 index 0000000000000..f3502674849ef --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-using-impl-items.rs:6:9 + | +LL | fn foo(x: &mut Vec<&u8>, y: &u8) { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | x.push(y); + | ^^^^^^^^^ argument requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr index 39896a3c8a059..8ac221e333ad7 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo(x: &mut Vec<&u8>, y: &u8) { | --- --- these two types are declared with different lifetimes... -LL | x.push(y); //~ ERROR lifetime mismatch +LL | x.push(y); | ^ ...but data from `y` flows into `x` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr new file mode 100644 index 0000000000000..3c95be95db080 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr @@ -0,0 +1,21 @@ +error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable + --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3 + | +LL | fn foo(x:Box , y: Vec<&u8>, z: &u8) { + | - help: consider changing this to be mutable: `mut y` +LL | y.push(z); + | ^ cannot borrow as mutable + +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3 + | +LL | fn foo(x:Box , y: Vec<&u8>, z: &u8) { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | y.push(z); + | ^^^^^^^^^ argument requires that `'1` must outlive `'2` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.rs b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.rs index 324a5846c94ae..6625d41c7de2a 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.rs +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.rs @@ -1,4 +1,4 @@ -fn foo(x:Box , y: Vec<&u8>, z: &u8) { +fn foo(x:Box , y: Vec<&u8>, z: &u8) { y.push(z); //~ ERROR lifetime mismatch } diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr index 46eca5ea64f6c..bfecb4d33931b 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr @@ -1,11 +1,10 @@ error[E0623]: lifetime mismatch --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:10 | -LL | fn foo(x:Box , y: Vec<&u8>, z: &u8) { - | --- --- these two types are declared with different lifetimes... -LL | y.push(z); //~ ERROR lifetime mismatch +LL | fn foo(x:Box , y: Vec<&u8>, z: &u8) { + | --- --- these two types are declared with different lifetimes... +LL | y.push(z); | ^ ...but data from `z` flows into `y` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.nll.stderr new file mode 100644 index 0000000000000..6989acfa1963b --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/ex3-both-anon-regions.rs:2:5 + | +LL | fn foo(x: &mut Vec<&u8>, y: &u8) { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | x.push(y); + | ^^^^^^^^^ argument requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr index 07d6cafd63395..053d577fa01ed 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr @@ -3,9 +3,8 @@ error[E0623]: lifetime mismatch | LL | fn foo(x: &mut Vec<&u8>, y: &u8) { | --- --- these two types are declared with different lifetimes... -LL | x.push(y); //~ ERROR lifetime mismatch +LL | x.push(y); | ^ ...but data from `y` flows into `x` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.rs b/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.rs index 99949e17b6f4a..81a20c58776c8 100644 --- a/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.rs +++ b/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.rs @@ -1,17 +1,13 @@ -// FIXME: Change to UI Test // Check notes are placed on an assignment that can actually precede the current assignment // Don't emit a first assignment for assignment in a loop. -// compile-flags: -Zborrowck=compare - fn test() { let x; if true { x = 1; } else { x = 2; - x = 3; //~ ERROR (Ast) [E0384] - //~^ ERROR (Mir) [E0384] + x = 3; //~ ERROR [E0384] } } @@ -22,8 +18,7 @@ fn test_in_loop() { x = 1; } else { x = 2; - x = 3; //~ ERROR (Ast) [E0384] - //~^ ERROR (Mir) [E0384] + x = 3; //~ ERROR [E0384] } } } @@ -32,11 +27,9 @@ fn test_using_loop() { let x; loop { if true { - x = 1; //~ ERROR (Ast) [E0384] - //~^ ERROR (Mir) [E0384] + x = 1; //~ ERROR [E0384] } else { - x = 2; //~ ERROR (Ast) [E0384] - //~^ ERROR (Mir) [E0384] + x = 2; //~ ERROR [E0384] } } } diff --git a/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr b/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr index f66bd3b35f789..13b6a7bbef321 100644 --- a/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr @@ -1,77 +1,46 @@ -error[E0384]: cannot assign twice to immutable variable `x` (Ast) - --> $DIR/liveness-assign-imm-local-notes.rs:13:9 - | -LL | x = 2; - | ----- first assignment to `x` -LL | x = 3; //~ ERROR (Ast) [E0384] - | ^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` (Ast) - --> $DIR/liveness-assign-imm-local-notes.rs:25:13 - | -LL | x = 2; - | ----- first assignment to `x` -LL | x = 3; //~ ERROR (Ast) [E0384] - | ^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` (Ast) - --> $DIR/liveness-assign-imm-local-notes.rs:35:13 - | -LL | x = 1; //~ ERROR (Ast) [E0384] - | ^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` (Ast) - --> $DIR/liveness-assign-imm-local-notes.rs:38:13 - | -LL | x = 1; //~ ERROR (Ast) [E0384] - | ----- first assignment to `x` -... -LL | x = 2; //~ ERROR (Ast) [E0384] - | ^^^^^ cannot assign twice to immutable variable - -error[E0384]: cannot assign twice to immutable variable `x` (Mir) - --> $DIR/liveness-assign-imm-local-notes.rs:13:9 +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/liveness-assign-imm-local-notes.rs:10:9 | LL | let x; | - help: make this binding mutable: `mut x` ... LL | x = 2; | ----- first assignment to `x` -LL | x = 3; //~ ERROR (Ast) [E0384] +LL | x = 3; | ^^^^^ cannot assign twice to immutable variable -error[E0384]: cannot assign twice to immutable variable `x` (Mir) - --> $DIR/liveness-assign-imm-local-notes.rs:25:13 +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/liveness-assign-imm-local-notes.rs:21:13 | LL | let x; | - help: make this binding mutable: `mut x` ... LL | x = 2; | ----- first assignment to `x` -LL | x = 3; //~ ERROR (Ast) [E0384] +LL | x = 3; | ^^^^^ cannot assign twice to immutable variable -error[E0384]: cannot assign twice to immutable variable `x` (Mir) - --> $DIR/liveness-assign-imm-local-notes.rs:35:13 +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/liveness-assign-imm-local-notes.rs:30:13 | LL | let x; | - help: make this binding mutable: `mut x` ... -LL | x = 1; //~ ERROR (Ast) [E0384] +LL | x = 1; | ^^^^^ cannot assign twice to immutable variable +LL | } else { +LL | x = 2; + | ----- first assignment to `x` -error[E0384]: cannot assign twice to immutable variable `x` (Mir) - --> $DIR/liveness-assign-imm-local-notes.rs:38:13 +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/liveness-assign-imm-local-notes.rs:32:13 | LL | let x; | - help: make this binding mutable: `mut x` ... -LL | x = 1; //~ ERROR (Ast) [E0384] - | ----- first assignment to `x` -... -LL | x = 2; //~ ERROR (Ast) [E0384] +LL | x = 2; | ^^^^^ cannot assign twice to immutable variable -error: aborting due to 8 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/lifetimes/lifetime-no-keyword.stderr b/src/test/ui/lifetimes/lifetime-no-keyword.stderr index 912befff01cc0..ba8ceb80fe0f0 100644 --- a/src/test/ui/lifetimes/lifetime-no-keyword.stderr +++ b/src/test/ui/lifetimes/lifetime-no-keyword.stderr @@ -1,25 +1,25 @@ error: lifetimes cannot use keyword names --> $DIR/lifetime-no-keyword.rs:3:8 | -LL | fn baz<'let>(a: &'let isize) { } //~ ERROR lifetimes cannot use keyword names +LL | fn baz<'let>(a: &'let isize) { } | ^^^^ error: lifetimes cannot use keyword names --> $DIR/lifetime-no-keyword.rs:3:18 | -LL | fn baz<'let>(a: &'let isize) { } //~ ERROR lifetimes cannot use keyword names +LL | fn baz<'let>(a: &'let isize) { } | ^^^^ error: lifetimes cannot use keyword names --> $DIR/lifetime-no-keyword.rs:5:8 | -LL | fn zab<'self>(a: &'self isize) { } //~ ERROR lifetimes cannot use keyword names +LL | fn zab<'self>(a: &'self isize) { } | ^^^^^ error: lifetimes cannot use keyword names --> $DIR/lifetime-no-keyword.rs:5:19 | -LL | fn zab<'self>(a: &'self isize) { } //~ ERROR lifetimes cannot use keyword names +LL | fn zab<'self>(a: &'self isize) { } | ^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/linkage-attr/auxiliary/def_colliding_external.rs b/src/test/ui/linkage-attr/auxiliary/def_colliding_external.rs new file mode 100644 index 0000000000000..bbbfc4857918d --- /dev/null +++ b/src/test/ui/linkage-attr/auxiliary/def_colliding_external.rs @@ -0,0 +1,7 @@ +#![feature(linkage)] +#![crate_type = "lib"] + +extern { + #[linkage="external"] + pub static collision: *const i32; +} diff --git a/src/test/ui/linkage-attr/auxiliary/def_illtyped_external.rs b/src/test/ui/linkage-attr/auxiliary/def_illtyped_external.rs new file mode 100644 index 0000000000000..2300930e513af --- /dev/null +++ b/src/test/ui/linkage-attr/auxiliary/def_illtyped_external.rs @@ -0,0 +1,5 @@ +#![feature(linkage)] +#![crate_type = "lib"] + +#[linkage="external"] +pub static EXTERN: u32 = 0; diff --git a/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs b/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs new file mode 100644 index 0000000000000..85a9a336b0d64 --- /dev/null +++ b/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs @@ -0,0 +1,21 @@ +// rust-lang/rust#61232: We used to ICE when trying to detect a +// collision on the symbol generated for the external linkage item in +// an extern crate. + +// aux-build:def_colliding_external.rs + +extern crate def_colliding_external as dep1; + +#[no_mangle] +pub static _rust_extern_with_linkage_collision: i32 = 0; + +mod dep2 { + #[no_mangle] + pub static collision: usize = 0; +} + +fn main() { + unsafe { + println!("{:p}", &dep1::collision); + } +} diff --git a/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.stderr b/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.stderr new file mode 100644 index 0000000000000..dcb954a4bc0c1 --- /dev/null +++ b/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.stderr @@ -0,0 +1,8 @@ +error: symbol `collision` is already defined + --> $DIR/auxiliary/def_colliding_external.rs:6:5 + | +LL | pub static collision: *const i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.rs b/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.rs new file mode 100644 index 0000000000000..dc15798e16a6a --- /dev/null +++ b/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.rs @@ -0,0 +1,23 @@ +#![feature(linkage)] + +mod dep1 { + extern { + #[linkage="external"] + #[no_mangle] + pub static collision: *const i32; //~ ERROR symbol `collision` is already defined + } +} + +#[no_mangle] +pub static _rust_extern_with_linkage_collision: i32 = 0; + +mod dep2 { + #[no_mangle] + pub static collision: usize = 0; +} + +fn main() { + unsafe { + println!("{:p}", &dep1::collision); + } +} diff --git a/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.stderr b/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.stderr new file mode 100644 index 0000000000000..117c76f7f26c7 --- /dev/null +++ b/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.stderr @@ -0,0 +1,8 @@ +error: symbol `collision` is already defined + --> $DIR/linkage-detect-local-generated-name-collision.rs:7:9 + | +LL | pub static collision: *const i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/linkage-attr/linkage-requires-raw-ptr.rs b/src/test/ui/linkage-attr/linkage-requires-raw-ptr.rs new file mode 100644 index 0000000000000..014c715be0d3b --- /dev/null +++ b/src/test/ui/linkage-attr/linkage-requires-raw-ptr.rs @@ -0,0 +1,10 @@ +// rust-lang/rust#59548: We used to ICE when trying to use a static +// with a type that violated its own `#[linkage]`. + +// aux-build:def_illtyped_external.rs + +extern crate def_illtyped_external as dep; + +fn main() { + println!("{:p}", &dep::EXTERN); +} diff --git a/src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr b/src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr new file mode 100644 index 0000000000000..a80b495f97fa3 --- /dev/null +++ b/src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr @@ -0,0 +1,8 @@ +error: must have type `*const T` or `*mut T` due to `#[linkage]` attribute + --> $DIR/auxiliary/def_illtyped_external.rs:5:1 + | +LL | pub static EXTERN: u32 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/linkage-attr/linkage2.rs b/src/test/ui/linkage-attr/linkage2.rs new file mode 100644 index 0000000000000..c8af1a69979a0 --- /dev/null +++ b/src/test/ui/linkage-attr/linkage2.rs @@ -0,0 +1,15 @@ +// FIXME https://github.com/rust-lang/rust/issues/59774 +// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" +// ignore-sgx no weak linkages permitted + +#![feature(linkage)] + +extern { + #[linkage = "extern_weak"] static foo: i32; + //~^ ERROR: must have type `*const T` or `*mut T` due to `#[linkage]` attribute +} + +fn main() { + println!("{}", unsafe { foo }); +} diff --git a/src/test/ui/linkage-attr/linkage2.stderr b/src/test/ui/linkage-attr/linkage2.stderr new file mode 100644 index 0000000000000..2654ffd67b678 --- /dev/null +++ b/src/test/ui/linkage-attr/linkage2.stderr @@ -0,0 +1,8 @@ +error: must have type `*const T` or `*mut T` due to `#[linkage]` attribute + --> $DIR/linkage2.rs:9:32 + | +LL | #[linkage = "extern_weak"] static foo: i32; + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/linkage-attr/linkage3.rs b/src/test/ui/linkage-attr/linkage3.rs new file mode 100644 index 0000000000000..1462079acf7e7 --- /dev/null +++ b/src/test/ui/linkage-attr/linkage3.rs @@ -0,0 +1,14 @@ +// FIXME https://github.com/rust-lang/rust/issues/59774 +// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" + +#![feature(linkage)] + +extern { + #[linkage = "foo"] static foo: *const i32; + //~^ ERROR: invalid linkage specified +} + +fn main() { + println!("{:?}", unsafe { foo }); +} diff --git a/src/test/ui/linkage3.stderr b/src/test/ui/linkage-attr/linkage3.stderr similarity index 86% rename from src/test/ui/linkage3.stderr rename to src/test/ui/linkage-attr/linkage3.stderr index a03593ff2c68e..b74fdc91429e2 100644 --- a/src/test/ui/linkage3.stderr +++ b/src/test/ui/linkage-attr/linkage3.stderr @@ -1,5 +1,5 @@ error: invalid linkage specified - --> $DIR/linkage3.rs:4:24 + --> $DIR/linkage3.rs:8:24 | LL | #[linkage = "foo"] static foo: *const i32; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/linkage4.rs b/src/test/ui/linkage-attr/linkage4.rs similarity index 100% rename from src/test/ui/linkage4.rs rename to src/test/ui/linkage-attr/linkage4.rs diff --git a/src/test/ui/linkage4.stderr b/src/test/ui/linkage-attr/linkage4.stderr similarity index 75% rename from src/test/ui/linkage4.stderr rename to src/test/ui/linkage-attr/linkage4.stderr index fd86671204e52..f2aab164bd7fa 100644 --- a/src/test/ui/linkage4.stderr +++ b/src/test/ui/linkage-attr/linkage4.stderr @@ -1,9 +1,10 @@ -error[E0658]: the `linkage` attribute is experimental and not portable across platforms (see issue #29603) +error[E0658]: the `linkage` attribute is experimental and not portable across platforms --> $DIR/linkage4.rs:1:1 | LL | #[linkage = "external"] | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29603 = help: add #![feature(linkage)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/linkage2.rs b/src/test/ui/linkage2.rs deleted file mode 100644 index 6d1410a90bd21..0000000000000 --- a/src/test/ui/linkage2.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(linkage)] - -extern { - #[linkage = "extern_weak"] static foo: i32; - //~^ ERROR: must have type `*const T` or `*mut T` -} - -fn main() { - println!("{}", unsafe { foo }); -} diff --git a/src/test/ui/linkage2.stderr b/src/test/ui/linkage2.stderr deleted file mode 100644 index 64213f1270adb..0000000000000 --- a/src/test/ui/linkage2.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: must have type `*const T` or `*mut T` - --> $DIR/linkage2.rs:4:32 - | -LL | #[linkage = "extern_weak"] static foo: i32; - | ^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/linkage3.rs b/src/test/ui/linkage3.rs deleted file mode 100644 index f094a0d53e941..0000000000000 --- a/src/test/ui/linkage3.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(linkage)] - -extern { - #[linkage = "foo"] static foo: *const i32; - //~^ ERROR: invalid linkage specified -} - -fn main() { - println!("{:?}", unsafe { foo }); -} diff --git a/src/test/ui/lint/auxiliary/stability-cfg2.rs b/src/test/ui/lint/auxiliary/stability-cfg2.rs new file mode 100644 index 0000000000000..8a2899584b903 --- /dev/null +++ b/src/test/ui/lint/auxiliary/stability-cfg2.rs @@ -0,0 +1,5 @@ +// compile-flags:--cfg foo + +#![cfg_attr(foo, unstable(feature = "unstable_test_feature", issue = "0"))] +#![cfg_attr(not(foo), stable(feature = "test_feature", since = "1.0.0"))] +#![feature(staged_api)] diff --git a/src/test/ui/lint/command-line-lint-group-deny.stderr b/src/test/ui/lint/command-line-lint-group-deny.stderr index 3250a41ee0ecd..04c3f6f263790 100644 --- a/src/test/ui/lint/command-line-lint-group-deny.stderr +++ b/src/test/ui/lint/command-line-lint-group-deny.stderr @@ -1,7 +1,7 @@ error: variable `_InappropriateCamelCasing` should have a snake case name --> $DIR/command-line-lint-group-deny.rs:4:9 | -LL | let _InappropriateCamelCasing = true; //~ ERROR should have a snake +LL | let _InappropriateCamelCasing = true; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `_inappropriate_camel_casing` | = note: `-D non-snake-case` implied by `-D bad-style` diff --git a/src/test/ui/lint/command-line-lint-group-forbid.stderr b/src/test/ui/lint/command-line-lint-group-forbid.stderr index 39f6da400c493..736782140639a 100644 --- a/src/test/ui/lint/command-line-lint-group-forbid.stderr +++ b/src/test/ui/lint/command-line-lint-group-forbid.stderr @@ -1,7 +1,7 @@ error: variable `_InappropriateCamelCasing` should have a snake case name --> $DIR/command-line-lint-group-forbid.rs:4:9 | -LL | let _InappropriateCamelCasing = true; //~ ERROR should have a snake +LL | let _InappropriateCamelCasing = true; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `_inappropriate_camel_casing` | = note: `-F non-snake-case` implied by `-F bad-style` diff --git a/src/test/ui/lint/deny-overflowing-literals.rs b/src/test/ui/lint/deny-overflowing-literals.rs index ebd6654d39b1f..21c8ba7d6ce4e 100644 --- a/src/test/ui/lint/deny-overflowing-literals.rs +++ b/src/test/ui/lint/deny-overflowing-literals.rs @@ -1,4 +1,7 @@ fn main() { let x: u8 = 256; - //~^ error: literal out of range for u8 + //~^ error: literal out of range for `u8` + + for _ in 0..256u8 {} + //~^ error: range endpoint is out of range for `u8` } diff --git a/src/test/ui/lint/deny-overflowing-literals.stderr b/src/test/ui/lint/deny-overflowing-literals.stderr index 7313dd0bfb5a7..c97872b5222e8 100644 --- a/src/test/ui/lint/deny-overflowing-literals.stderr +++ b/src/test/ui/lint/deny-overflowing-literals.stderr @@ -1,4 +1,4 @@ -error: literal out of range for u8 +error: literal out of range for `u8` --> $DIR/deny-overflowing-literals.rs:2:17 | LL | let x: u8 = 256; @@ -6,5 +6,11 @@ LL | let x: u8 = 256; | = note: #[deny(overflowing_literals)] on by default -error: aborting due to previous error +error: range endpoint is out of range for `u8` + --> $DIR/deny-overflowing-literals.rs:5:14 + | +LL | for _ in 0..256u8 {} + | ^^^^^^^^ help: use an inclusive range instead: `0..=255u8` + +error: aborting due to 2 previous errors diff --git a/src/test/ui/lint/issue-54180-unused-ref-field.fixed b/src/test/ui/lint/issue-54180-unused-ref-field.fixed new file mode 100644 index 0000000000000..1350b7ca6996c --- /dev/null +++ b/src/test/ui/lint/issue-54180-unused-ref-field.fixed @@ -0,0 +1,34 @@ +// run-rustfix + +#![deny(unused)] + +pub struct S { + pub f1: i32, +} + +pub struct Point { + pub x: i32, + pub y: i32, +} + +pub enum E { + Variant { field: String } +} + +pub fn foo(arg: &E) { + match arg { + E::Variant { field: _ } => (), //~ ERROR unused variable + } +} + +fn main() { + let s = S { f1: 123 }; + let S { f1: _ } = s; //~ ERROR unused variable + + let points = vec![Point { x: 1, y: 2 }]; + let _: i32 = points.iter().map(|Point { x: _, y }| y).sum(); //~ ERROR unused variable + + match (Point { x: 1, y: 2 }) { + Point { y, x: _ } => y, //~ ERROR unused variable + }; +} diff --git a/src/test/ui/lint/issue-54180-unused-ref-field.rs b/src/test/ui/lint/issue-54180-unused-ref-field.rs new file mode 100644 index 0000000000000..7b3392b609a0a --- /dev/null +++ b/src/test/ui/lint/issue-54180-unused-ref-field.rs @@ -0,0 +1,34 @@ +// run-rustfix + +#![deny(unused)] + +pub struct S { + pub f1: i32, +} + +pub struct Point { + pub x: i32, + pub y: i32, +} + +pub enum E { + Variant { field: String } +} + +pub fn foo(arg: &E) { + match arg { + E::Variant { ref field } => (), //~ ERROR unused variable + } +} + +fn main() { + let s = S { f1: 123 }; + let S { ref f1 } = s; //~ ERROR unused variable + + let points = vec![Point { x: 1, y: 2 }]; + let _: i32 = points.iter().map(|Point { x, y }| y).sum(); //~ ERROR unused variable + + match (Point { x: 1, y: 2 }) { + Point { y, ref mut x } => y, //~ ERROR unused variable + }; +} diff --git a/src/test/ui/lint/issue-54180-unused-ref-field.stderr b/src/test/ui/lint/issue-54180-unused-ref-field.stderr new file mode 100644 index 0000000000000..9f47554a1a65e --- /dev/null +++ b/src/test/ui/lint/issue-54180-unused-ref-field.stderr @@ -0,0 +1,39 @@ +error: unused variable: `field` + --> $DIR/issue-54180-unused-ref-field.rs:20:26 + | +LL | E::Variant { ref field } => (), + | ----^^^^^ + | | + | help: try ignoring the field: `field: _` + | +note: lint level defined here + --> $DIR/issue-54180-unused-ref-field.rs:3:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: #[deny(unused_variables)] implied by #[deny(unused)] + +error: unused variable: `x` + --> $DIR/issue-54180-unused-ref-field.rs:29:45 + | +LL | let _: i32 = points.iter().map(|Point { x, y }| y).sum(); + | ^ help: try ignoring the field: `x: _` + +error: unused variable: `f1` + --> $DIR/issue-54180-unused-ref-field.rs:26:17 + | +LL | let S { ref f1 } = s; + | ----^^ + | | + | help: try ignoring the field: `f1: _` + +error: unused variable: `x` + --> $DIR/issue-54180-unused-ref-field.rs:32:28 + | +LL | Point { y, ref mut x } => y, + | --------^ + | | + | help: try ignoring the field: `x: _` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/lint/issue-54538-unused-parens-lint.rs b/src/test/ui/lint/issue-54538-unused-parens-lint.rs index 6ca53816e3c6b..3a52996195c0d 100644 --- a/src/test/ui/lint/issue-54538-unused-parens-lint.rs +++ b/src/test/ui/lint/issue-54538-unused-parens-lint.rs @@ -1,10 +1,32 @@ // compile-pass +#![allow(ellipsis_inclusive_range_patterns)] #![allow(unreachable_patterns)] #![allow(unused_variables)] #![warn(unused_parens)] fn main() { + match 1 { + (_) => {} //~ WARNING: unnecessary parentheses around pattern + (y) => {} //~ WARNING: unnecessary parentheses around pattern + (ref r) => {} //~ WARNING: unnecessary parentheses around pattern + (e @ 1...2) => {} //~ WARNING: unnecessary parentheses around outer pattern + (1...2) => {} // Non ambiguous range pattern should not warn + e @ (3...4) => {} // Non ambiguous range pattern should not warn + } + + match &1 { + (e @ &(1...2)) => {} //~ WARNING: unnecessary parentheses around outer pattern + &(_) => {} //~ WARNING: unnecessary parentheses around pattern + e @ &(1...2) => {} // Ambiguous range pattern should not warn + &(1...2) => {} // Ambiguous range pattern should not warn + } + + match &1 { + e @ &(1...2) | e @ &(3...4) => {} // Complex ambiguous pattern should not warn + &_ => {} + } + match 1 { (_) => {} //~ WARNING: unnecessary parentheses around pattern (y) => {} //~ WARNING: unnecessary parentheses around pattern @@ -15,14 +37,14 @@ fn main() { } match &1 { - (e @ &(1...2)) => {} //~ WARNING: unnecessary parentheses around outer pattern + (e @ &(1..=2)) => {} //~ WARNING: unnecessary parentheses around outer pattern &(_) => {} //~ WARNING: unnecessary parentheses around pattern - e @ &(1...2) => {} // Ambiguous range pattern should not warn + e @ &(1..=2) => {} // Ambiguous range pattern should not warn &(1..=2) => {} // Ambiguous range pattern should not warn } match &1 { - e @ &(1...2) | e @ &(3..=4) => {} // Complex ambiguous pattern should not warn + e @ &(1..=2) | e @ &(3..=4) => {} // Complex ambiguous pattern should not warn &_ => {} } } diff --git a/src/test/ui/lint/issue-54538-unused-parens-lint.stderr b/src/test/ui/lint/issue-54538-unused-parens-lint.stderr index fd55ffbdf4374..3b312198952a5 100644 --- a/src/test/ui/lint/issue-54538-unused-parens-lint.stderr +++ b/src/test/ui/lint/issue-54538-unused-parens-lint.stderr @@ -1,42 +1,78 @@ warning: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:9:9 + --> $DIR/issue-54538-unused-parens-lint.rs:10:9 | -LL | (_) => {} //~ WARNING: unnecessary parentheses around pattern +LL | (_) => {} | ^^^ help: remove these parentheses | note: lint level defined here - --> $DIR/issue-54538-unused-parens-lint.rs:5:9 + --> $DIR/issue-54538-unused-parens-lint.rs:6:9 | LL | #![warn(unused_parens)] | ^^^^^^^^^^^^^ warning: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:10:9 + --> $DIR/issue-54538-unused-parens-lint.rs:11:9 | -LL | (y) => {} //~ WARNING: unnecessary parentheses around pattern +LL | (y) => {} | ^^^ help: remove these parentheses warning: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:11:9 + --> $DIR/issue-54538-unused-parens-lint.rs:12:9 | -LL | (ref r) => {} //~ WARNING: unnecessary parentheses around pattern +LL | (ref r) => {} | ^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:12:9 + --> $DIR/issue-54538-unused-parens-lint.rs:13:9 + | +LL | (e @ 1...2) => {} + | ^^^^^^^^^^^ help: remove these parentheses + +warning: unnecessary parentheses around pattern + --> $DIR/issue-54538-unused-parens-lint.rs:19:9 + | +LL | (e @ &(1...2)) => {} + | ^^^^^^^^^^^^^^ help: remove these parentheses + +warning: unnecessary parentheses around pattern + --> $DIR/issue-54538-unused-parens-lint.rs:20:10 + | +LL | &(_) => {} + | ^^^ help: remove these parentheses + +warning: unnecessary parentheses around pattern + --> $DIR/issue-54538-unused-parens-lint.rs:31:9 + | +LL | (_) => {} + | ^^^ help: remove these parentheses + +warning: unnecessary parentheses around pattern + --> $DIR/issue-54538-unused-parens-lint.rs:32:9 + | +LL | (y) => {} + | ^^^ help: remove these parentheses + +warning: unnecessary parentheses around pattern + --> $DIR/issue-54538-unused-parens-lint.rs:33:9 + | +LL | (ref r) => {} + | ^^^^^^^ help: remove these parentheses + +warning: unnecessary parentheses around pattern + --> $DIR/issue-54538-unused-parens-lint.rs:34:9 | -LL | (e @ 1..=2) => {} //~ WARNING: unnecessary parentheses around outer pattern +LL | (e @ 1..=2) => {} | ^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:18:9 + --> $DIR/issue-54538-unused-parens-lint.rs:40:9 | -LL | (e @ &(1...2)) => {} //~ WARNING: unnecessary parentheses around outer pattern +LL | (e @ &(1..=2)) => {} | ^^^^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:19:10 + --> $DIR/issue-54538-unused-parens-lint.rs:41:10 | -LL | &(_) => {} //~ WARNING: unnecessary parentheses around pattern +LL | &(_) => {} | ^^^ help: remove these parentheses diff --git a/src/test/ui/lint/lint-attr-non-item-node.stderr b/src/test/ui/lint/lint-attr-non-item-node.stderr index 2c95831f3759f..6eb72c098df5c 100644 --- a/src/test/ui/lint/lint-attr-non-item-node.stderr +++ b/src/test/ui/lint/lint-attr-non-item-node.stderr @@ -1,7 +1,7 @@ error: unreachable statement --> $DIR/lint-attr-non-item-node.rs:7:9 | -LL | "unreachable"; //~ ERROR unreachable statement +LL | "unreachable"; | ^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/lint/lint-change-warnings.stderr b/src/test/ui/lint/lint-change-warnings.stderr index 7d7a066613ace..c4b8ab5fc1858 100644 --- a/src/test/ui/lint/lint-change-warnings.stderr +++ b/src/test/ui/lint/lint-change-warnings.stderr @@ -1,7 +1,7 @@ error: denote infinite loops with `loop { ... }` --> $DIR/lint-change-warnings.rs:5:5 | -LL | while true {} //~ ERROR: infinite +LL | while true {} | ^^^^^^^^^^ help: use `loop` | note: lint level defined here @@ -14,7 +14,7 @@ LL | #![deny(warnings)] warning: denote infinite loops with `loop { ... }` --> $DIR/lint-change-warnings.rs:15:5 | -LL | while true {} //~ WARNING: infinite +LL | while true {} | ^^^^^^^^^^ help: use `loop` | = note: #[warn(while_true)] on by default @@ -22,7 +22,7 @@ LL | while true {} //~ WARNING: infinite error: denote infinite loops with `loop { ... }` --> $DIR/lint-change-warnings.rs:20:5 | -LL | while true {} //~ ERROR: infinite +LL | while true {} | ^^^^^^^^^^ help: use `loop` | note: lint level defined here diff --git a/src/test/ui/lint/lint-ctypes-enum.rs b/src/test/ui/lint/lint-ctypes-enum.rs index f347c2761c322..45eeffff7a6ac 100644 --- a/src/test/ui/lint/lint-ctypes-enum.rs +++ b/src/test/ui/lint/lint-ctypes-enum.rs @@ -1,6 +1,9 @@ +#![feature(transparent_enums, transparent_unions)] #![deny(improper_ctypes)] #![allow(dead_code)] +use std::num; + enum Z { } enum U { A } enum B { C, D } @@ -15,14 +18,52 @@ enum U8 { A, B, C } #[repr(isize)] enum Isize { A, B, C } +#[repr(transparent)] +struct TransparentStruct(T, std::marker::PhantomData); + +#[repr(transparent)] +enum TransparentEnum { + Variant(T, std::marker::PhantomData), +} + +#[repr(transparent)] +union TransparentUnion { + field: T, +} + +struct Rust(T); + extern { fn zf(x: Z); fn uf(x: U); //~ ERROR enum has no representation hint fn bf(x: B); //~ ERROR enum has no representation hint fn tf(x: T); //~ ERROR enum has no representation hint - fn reprc(x: ReprC); - fn u8(x: U8); - fn isize(x: Isize); + fn repr_c(x: ReprC); + fn repr_u8(x: U8); + fn repr_isize(x: Isize); + fn option_ref(x: Option<&'static u8>); + fn option_fn(x: Option); + fn nonnull(x: Option>); + fn nonzero_u8(x: Option); + fn nonzero_u16(x: Option); + fn nonzero_u32(x: Option); + fn nonzero_u64(x: Option); + fn nonzero_u128(x: Option); + //~^ ERROR 128-bit integers don't currently have a known stable ABI + fn nonzero_usize(x: Option); + fn nonzero_i8(x: Option); + fn nonzero_i16(x: Option); + fn nonzero_i32(x: Option); + fn nonzero_i64(x: Option); + fn nonzero_i128(x: Option); + //~^ ERROR 128-bit integers don't currently have a known stable ABI + fn nonzero_isize(x: Option); + fn transparent_struct(x: Option>); + fn transparent_enum(x: Option>); + fn transparent_union(x: Option>); + //~^ ERROR enum has no representation hint + fn repr_rust(x: Option>); //~ ERROR enum has no representation hint + fn no_result(x: Result<(), num::NonZeroI32>); //~ ERROR enum has no representation hint } pub fn main() { } diff --git a/src/test/ui/lint/lint-ctypes-enum.stderr b/src/test/ui/lint/lint-ctypes-enum.stderr index dd33cc77458d7..2a60cd12d9936 100644 --- a/src/test/ui/lint/lint-ctypes-enum.stderr +++ b/src/test/ui/lint/lint-ctypes-enum.stderr @@ -1,46 +1,82 @@ error: `extern` block uses type `U` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:20:13 + --> $DIR/lint-ctypes-enum.rs:38:13 | -LL | fn uf(x: U); //~ ERROR enum has no representation hint +LL | fn uf(x: U); | ^ | note: lint level defined here - --> $DIR/lint-ctypes-enum.rs:1:9 + --> $DIR/lint-ctypes-enum.rs:2:9 | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ - = help: consider adding a #[repr(...)] attribute to this enum + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum note: type defined here - --> $DIR/lint-ctypes-enum.rs:5:1 + --> $DIR/lint-ctypes-enum.rs:8:1 | LL | enum U { A } | ^^^^^^^^^^^^ error: `extern` block uses type `B` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:21:13 + --> $DIR/lint-ctypes-enum.rs:39:13 | -LL | fn bf(x: B); //~ ERROR enum has no representation hint +LL | fn bf(x: B); | ^ | - = help: consider adding a #[repr(...)] attribute to this enum + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum note: type defined here - --> $DIR/lint-ctypes-enum.rs:6:1 + --> $DIR/lint-ctypes-enum.rs:9:1 | LL | enum B { C, D } | ^^^^^^^^^^^^^^^ error: `extern` block uses type `T` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:22:13 + --> $DIR/lint-ctypes-enum.rs:40:13 | -LL | fn tf(x: T); //~ ERROR enum has no representation hint +LL | fn tf(x: T); | ^ | - = help: consider adding a #[repr(...)] attribute to this enum + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum note: type defined here - --> $DIR/lint-ctypes-enum.rs:7:1 + --> $DIR/lint-ctypes-enum.rs:10:1 | LL | enum T { E, F, G } | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: `extern` block uses type `u128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI + --> $DIR/lint-ctypes-enum.rs:51:23 + | +LL | fn nonzero_u128(x: Option); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI + --> $DIR/lint-ctypes-enum.rs:58:23 + | +LL | fn nonzero_i128(x: Option); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `extern` block uses type `std::option::Option>` which is not FFI-safe: enum has no representation hint + --> $DIR/lint-ctypes-enum.rs:63:28 + | +LL | fn transparent_union(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + +error: `extern` block uses type `std::option::Option>` which is not FFI-safe: enum has no representation hint + --> $DIR/lint-ctypes-enum.rs:65:20 + | +LL | fn repr_rust(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + +error: `extern` block uses type `std::result::Result<(), std::num::NonZeroI32>` which is not FFI-safe: enum has no representation hint + --> $DIR/lint-ctypes-enum.rs:66:20 + | +LL | fn no_result(x: Result<(), num::NonZeroI32>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + +error: aborting due to 8 previous errors diff --git a/src/test/ui/lint/lint-ctypes.rs b/src/test/ui/lint/lint-ctypes.rs index 816177abdeaf1..a3d9b6febdbb7 100644 --- a/src/test/ui/lint/lint-ctypes.rs +++ b/src/test/ui/lint/lint-ctypes.rs @@ -51,7 +51,7 @@ extern { pub fn char_type(p: char); //~ ERROR uses type `char` pub fn i128_type(p: i128); //~ ERROR uses type `i128` pub fn u128_type(p: u128); //~ ERROR uses type `u128` - pub fn trait_type(p: &Clone); //~ ERROR uses type `dyn std::clone::Clone` + pub fn trait_type(p: &dyn Clone); //~ ERROR uses type `dyn std::clone::Clone` pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)` pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)` pub fn zero_size(p: ZeroSize); //~ ERROR struct has no fields diff --git a/src/test/ui/lint/lint-ctypes.stderr b/src/test/ui/lint/lint-ctypes.stderr index 51211c8763179..c78463beb6559 100644 --- a/src/test/ui/lint/lint-ctypes.stderr +++ b/src/test/ui/lint/lint-ctypes.stderr @@ -1,7 +1,7 @@ error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout --> $DIR/lint-ctypes.rs:46:28 | -LL | pub fn ptr_type1(size: *const Foo); //~ ERROR: uses type `Foo` +LL | pub fn ptr_type1(size: *const Foo); | ^^^^^^^^^^ | note: lint level defined here @@ -9,7 +9,7 @@ note: lint level defined here | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/lint-ctypes.rs:24:1 | @@ -19,10 +19,10 @@ LL | pub struct Foo; error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout --> $DIR/lint-ctypes.rs:47:28 | -LL | pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo` +LL | pub fn ptr_type2(size: *const Foo); | ^^^^^^^^^^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/lint-ctypes.rs:24:1 | @@ -32,7 +32,7 @@ LL | pub struct Foo; error: `extern` block uses type `[u32]` which is not FFI-safe: slices have no C equivalent --> $DIR/lint-ctypes.rs:48:26 | -LL | pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]` +LL | pub fn slice_type(p: &[u32]); | ^^^^^^ | = help: consider using a raw pointer instead @@ -40,7 +40,7 @@ LL | pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]` error: `extern` block uses type `str` which is not FFI-safe: string slices have no C equivalent --> $DIR/lint-ctypes.rs:49:24 | -LL | pub fn str_type(p: &str); //~ ERROR: uses type `str` +LL | pub fn str_type(p: &str); | ^^^^ | = help: consider using `*const u8` and a length instead @@ -48,15 +48,15 @@ LL | pub fn str_type(p: &str); //~ ERROR: uses type `str` error: `extern` block uses type `std::boxed::Box` which is not FFI-safe: this struct has unspecified layout --> $DIR/lint-ctypes.rs:50:24 | -LL | pub fn box_type(p: Box); //~ ERROR uses type `std::boxed::Box` +LL | pub fn box_type(p: Box); | ^^^^^^^^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct error: `extern` block uses type `char` which is not FFI-safe: the `char` type has no C equivalent --> $DIR/lint-ctypes.rs:51:25 | -LL | pub fn char_type(p: char); //~ ERROR uses type `char` +LL | pub fn char_type(p: char); | ^^^^ | = help: consider using `u32` or `libc::wchar_t` instead @@ -64,25 +64,25 @@ LL | pub fn char_type(p: char); //~ ERROR uses type `char` error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI --> $DIR/lint-ctypes.rs:52:25 | -LL | pub fn i128_type(p: i128); //~ ERROR uses type `i128` +LL | pub fn i128_type(p: i128); | ^^^^ error: `extern` block uses type `u128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI --> $DIR/lint-ctypes.rs:53:25 | -LL | pub fn u128_type(p: u128); //~ ERROR uses type `u128` +LL | pub fn u128_type(p: u128); | ^^^^ error: `extern` block uses type `dyn std::clone::Clone` which is not FFI-safe: trait objects have no C equivalent --> $DIR/lint-ctypes.rs:54:26 | -LL | pub fn trait_type(p: &Clone); //~ ERROR uses type `dyn std::clone::Clone` - | ^^^^^^ +LL | pub fn trait_type(p: &dyn Clone); + | ^^^^^^^^^^ error: `extern` block uses type `(i32, i32)` which is not FFI-safe: tuples have unspecified layout --> $DIR/lint-ctypes.rs:55:26 | -LL | pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)` +LL | pub fn tuple_type(p: (i32, i32)); | ^^^^^^^^^^ | = help: consider using a struct instead @@ -90,7 +90,7 @@ LL | pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)` error: `extern` block uses type `(i32, i32)` which is not FFI-safe: tuples have unspecified layout --> $DIR/lint-ctypes.rs:56:27 | -LL | pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)` +LL | pub fn tuple_type2(p: I32Pair); | ^^^^^^^ | = help: consider using a struct instead @@ -98,7 +98,7 @@ LL | pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)` error: `extern` block uses type `ZeroSize` which is not FFI-safe: this struct has no fields --> $DIR/lint-ctypes.rs:57:25 | -LL | pub fn zero_size(p: ZeroSize); //~ ERROR struct has no fields +LL | pub fn zero_size(p: ZeroSize); | ^^^^^^^^ | = help: consider adding a member to this struct @@ -111,19 +111,19 @@ LL | pub struct ZeroSize; error: `extern` block uses type `ZeroSizeWithPhantomData` which is not FFI-safe: composed only of PhantomData --> $DIR/lint-ctypes.rs:58:33 | -LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR composed only of PhantomData +LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `std::marker::PhantomData` which is not FFI-safe: composed only of PhantomData --> $DIR/lint-ctypes.rs:60:12 | -LL | -> ::std::marker::PhantomData; //~ ERROR: composed only of PhantomData +LL | -> ::std::marker::PhantomData; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `fn()` which is not FFI-safe: this function pointer has Rust-specific calling convention --> $DIR/lint-ctypes.rs:61:23 | -LL | pub fn fn_type(p: RustFn); //~ ERROR function pointer has Rust-specific +LL | pub fn fn_type(p: RustFn); | ^^^^^^ | = help: consider using an `extern fn(...) -> ...` function pointer instead @@ -131,7 +131,7 @@ LL | pub fn fn_type(p: RustFn); //~ ERROR function pointer has Rust-specific error: `extern` block uses type `fn()` which is not FFI-safe: this function pointer has Rust-specific calling convention --> $DIR/lint-ctypes.rs:62:24 | -LL | pub fn fn_type2(p: fn()); //~ ERROR function pointer has Rust-specific +LL | pub fn fn_type2(p: fn()); | ^^^^ | = help: consider using an `extern fn(...) -> ...` function pointer instead @@ -139,21 +139,21 @@ LL | pub fn fn_type2(p: fn()); //~ ERROR function pointer has Rust-specific error: `extern` block uses type `std::boxed::Box` which is not FFI-safe: this struct has unspecified layout --> $DIR/lint-ctypes.rs:63:28 | -LL | pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `std::boxed::Box` +LL | pub fn fn_contained(p: RustBadRet); | ^^^^^^^^^^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI --> $DIR/lint-ctypes.rs:64:32 | -LL | pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128` +LL | pub fn transparent_i128(p: TransparentI128); | ^^^^^^^^^^^^^^^ error: `extern` block uses type `str` which is not FFI-safe: string slices have no C equivalent --> $DIR/lint-ctypes.rs:65:31 | -LL | pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str` +LL | pub fn transparent_str(p: TransparentStr); | ^^^^^^^^^^^^^^ | = help: consider using `*const u8` and a length instead @@ -161,10 +161,10 @@ LL | pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str` error: `extern` block uses type `std::boxed::Box` which is not FFI-safe: this struct has unspecified layout --> $DIR/lint-ctypes.rs:66:30 | -LL | pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `std::boxed::Box` +LL | pub fn transparent_fn(p: TransparentBadFn); | ^^^^^^^^^^^^^^^^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct error: aborting due to 20 previous errors diff --git a/src/test/ui/lint/lint-dead-code-1.stderr b/src/test/ui/lint/lint-dead-code-1.stderr index 6d0295002f1ca..be96c697d9944 100644 --- a/src/test/ui/lint/lint-dead-code-1.stderr +++ b/src/test/ui/lint/lint-dead-code-1.stderr @@ -1,7 +1,7 @@ error: struct is never constructed: `Bar` --> $DIR/lint-dead-code-1.rs:12:5 | -LL | pub struct Bar; //~ ERROR: struct is never constructed +LL | pub struct Bar; | ^^^^^^^^^^^^^^^ | note: lint level defined here @@ -13,55 +13,55 @@ LL | #![deny(dead_code)] error: static item is never used: `priv_static` --> $DIR/lint-dead-code-1.rs:20:1 | -LL | static priv_static: isize = 0; //~ ERROR: static item is never used +LL | static priv_static: isize = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant item is never used: `priv_const` --> $DIR/lint-dead-code-1.rs:27:1 | -LL | const priv_const: isize = 0; //~ ERROR: constant item is never used +LL | const priv_const: isize = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: struct is never constructed: `PrivStruct` --> $DIR/lint-dead-code-1.rs:35:1 | -LL | struct PrivStruct; //~ ERROR: struct is never constructed +LL | struct PrivStruct; | ^^^^^^^^^^^^^^^^^^ error: enum is never used: `priv_enum` --> $DIR/lint-dead-code-1.rs:64:1 | -LL | enum priv_enum { foo2, bar2 } //~ ERROR: enum is never used +LL | enum priv_enum { foo2, bar2 } | ^^^^^^^^^^^^^^ error: variant is never constructed: `bar3` --> $DIR/lint-dead-code-1.rs:67:5 | -LL | bar3 //~ ERROR variant is never constructed +LL | bar3 | ^^^^ error: function is never used: `priv_fn` --> $DIR/lint-dead-code-1.rs:88:1 | -LL | fn priv_fn() { //~ ERROR: function is never used +LL | fn priv_fn() { | ^^^^^^^^^^^^ error: function is never used: `foo` --> $DIR/lint-dead-code-1.rs:93:1 | -LL | fn foo() { //~ ERROR: function is never used +LL | fn foo() { | ^^^^^^^^ error: function is never used: `bar` --> $DIR/lint-dead-code-1.rs:98:1 | -LL | fn bar() { //~ ERROR: function is never used +LL | fn bar() { | ^^^^^^^^ error: function is never used: `baz` --> $DIR/lint-dead-code-1.rs:102:1 | -LL | fn baz() -> impl Copy { //~ ERROR: function is never used +LL | fn baz() -> impl Copy { | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 10 previous errors diff --git a/src/test/ui/lint/lint-dead-code-2.stderr b/src/test/ui/lint/lint-dead-code-2.stderr index d17149104dbaa..1226f9823ac54 100644 --- a/src/test/ui/lint/lint-dead-code-2.stderr +++ b/src/test/ui/lint/lint-dead-code-2.stderr @@ -1,7 +1,7 @@ error: function is never used: `dead_fn` --> $DIR/lint-dead-code-2.rs:22:1 | -LL | fn dead_fn() {} //~ ERROR: function is never used +LL | fn dead_fn() {} | ^^^^^^^^^^^^ | note: lint level defined here @@ -13,13 +13,13 @@ LL | #![deny(dead_code)] error: function is never used: `dead_fn2` --> $DIR/lint-dead-code-2.rs:25:1 | -LL | fn dead_fn2() {} //~ ERROR: function is never used +LL | fn dead_fn2() {} | ^^^^^^^^^^^^^ error: function is never used: `main` --> $DIR/lint-dead-code-2.rs:38:1 | -LL | fn main() { //~ ERROR: function is never used +LL | fn main() { | ^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/lint/lint-dead-code-3.rs b/src/test/ui/lint/lint-dead-code-3.rs index 00b250f83dd6f..4397522f3f32f 100644 --- a/src/test/ui/lint/lint-dead-code-3.rs +++ b/src/test/ui/lint/lint-dead-code-3.rs @@ -73,6 +73,6 @@ mod inner { } pub fn foo() { - let a: &inner::Trait = &1_isize; + let a: &dyn inner::Trait = &1_isize; a.f(); } diff --git a/src/test/ui/lint/lint-dead-code-3.stderr b/src/test/ui/lint/lint-dead-code-3.stderr index 72bcac22de8cb..2408da0af89ea 100644 --- a/src/test/ui/lint/lint-dead-code-3.stderr +++ b/src/test/ui/lint/lint-dead-code-3.stderr @@ -1,7 +1,7 @@ error: struct is never constructed: `Foo` --> $DIR/lint-dead-code-3.rs:13:1 | -LL | struct Foo; //~ ERROR: struct is never constructed +LL | struct Foo; | ^^^^^^^^^^^ | note: lint level defined here @@ -13,25 +13,25 @@ LL | #![deny(dead_code)] error: method is never used: `foo` --> $DIR/lint-dead-code-3.rs:15:5 | -LL | fn foo(&self) { //~ ERROR: method is never used +LL | fn foo(&self) { | ^^^^^^^^^^^^^ error: function is never used: `bar` --> $DIR/lint-dead-code-3.rs:20:1 | -LL | fn bar() { //~ ERROR: function is never used +LL | fn bar() { | ^^^^^^^^ error: enum is never used: `c_void` --> $DIR/lint-dead-code-3.rs:59:1 | -LL | enum c_void {} //~ ERROR: enum is never used +LL | enum c_void {} | ^^^^^^^^^^^ error: foreign function is never used: `free` --> $DIR/lint-dead-code-3.rs:61:5 | -LL | fn free(p: *const c_void); //~ ERROR: foreign function is never used +LL | fn free(p: *const c_void); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/lint/lint-dead-code-4.stderr b/src/test/ui/lint/lint-dead-code-4.stderr index 62de048d5e919..b7ceee99998d7 100644 --- a/src/test/ui/lint/lint-dead-code-4.stderr +++ b/src/test/ui/lint/lint-dead-code-4.stderr @@ -1,7 +1,7 @@ error: field is never used: `b` --> $DIR/lint-dead-code-4.rs:7:5 | -LL | b: bool, //~ ERROR: field is never used +LL | b: bool, | ^^^^^^^ | note: lint level defined here @@ -13,13 +13,13 @@ LL | #![deny(dead_code)] error: variant is never constructed: `X` --> $DIR/lint-dead-code-4.rs:15:5 | -LL | X, //~ ERROR variant is never constructed +LL | X, | ^ error: variant is never constructed: `Y` --> $DIR/lint-dead-code-4.rs:16:5 | -LL | / Y { //~ ERROR variant is never constructed +LL | / Y { LL | | a: String, LL | | b: i32, LL | | c: i32, @@ -29,43 +29,43 @@ LL | | }, error: enum is never used: `ABC` --> $DIR/lint-dead-code-4.rs:24:1 | -LL | enum ABC { //~ ERROR enum is never used +LL | enum ABC { | ^^^^^^^^ error: variant is never constructed: `I` --> $DIR/lint-dead-code-4.rs:36:5 | -LL | I, //~ ERROR variant is never constructed +LL | I, | ^ error: field is never used: `b` --> $DIR/lint-dead-code-4.rs:39:9 | -LL | b: i32, //~ ERROR field is never used +LL | b: i32, | ^^^^^^ error: field is never used: `c` --> $DIR/lint-dead-code-4.rs:40:9 | -LL | c: i32, //~ ERROR field is never used +LL | c: i32, | ^^^^^^ error: variant is never constructed: `K` --> $DIR/lint-dead-code-4.rs:42:5 | -LL | K //~ ERROR variant is never constructed +LL | K | ^ error: field is never used: `x` --> $DIR/lint-dead-code-4.rs:61:5 | -LL | x: usize, //~ ERROR: field is never used +LL | x: usize, | ^^^^^^^^ error: field is never used: `c` --> $DIR/lint-dead-code-4.rs:63:5 | -LL | c: bool, //~ ERROR: field is never used +LL | c: bool, | ^^^^^^^ error: aborting due to 10 previous errors diff --git a/src/test/ui/lint/lint-dead-code-5.stderr b/src/test/ui/lint/lint-dead-code-5.stderr index e6c2354783a21..740cfde2c069f 100644 --- a/src/test/ui/lint/lint-dead-code-5.stderr +++ b/src/test/ui/lint/lint-dead-code-5.stderr @@ -1,7 +1,7 @@ error: variant is never constructed: `Variant2` --> $DIR/lint-dead-code-5.rs:6:5 | -LL | Variant2 //~ ERROR: variant is never constructed +LL | Variant2 | ^^^^^^^^ | note: lint level defined here @@ -13,19 +13,19 @@ LL | #![deny(dead_code)] error: variant is never constructed: `Variant5` --> $DIR/lint-dead-code-5.rs:13:5 | -LL | Variant5 { _x: isize }, //~ ERROR: variant is never constructed: `Variant5` +LL | Variant5 { _x: isize }, | ^^^^^^^^^^^^^^^^^^^^^^ error: variant is never constructed: `Variant6` --> $DIR/lint-dead-code-5.rs:14:5 | -LL | Variant6(isize), //~ ERROR: variant is never constructed: `Variant6` +LL | Variant6(isize), | ^^^^^^^^^^^^^^^ error: enum is never used: `Enum3` --> $DIR/lint-dead-code-5.rs:18:1 | -LL | enum Enum3 { //~ ERROR: enum is never used +LL | enum Enum3 { | ^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/lint/lint-dead-code-impl-trait.rs b/src/test/ui/lint/lint-dead-code-impl-trait.rs new file mode 100644 index 0000000000000..a2736d97308af --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-impl-trait.rs @@ -0,0 +1,18 @@ +#![deny(dead_code)] + +trait Trait { + type Type; +} + +impl Trait for () { + type Type = (); +} + +type Used = (); +type Unused = (); //~ ERROR type alias is never used + +fn foo() -> impl Trait {} + +fn main() { + foo(); +} diff --git a/src/test/ui/lint/lint-dead-code-impl-trait.stderr b/src/test/ui/lint/lint-dead-code-impl-trait.stderr new file mode 100644 index 0000000000000..61d0954bf3146 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-impl-trait.stderr @@ -0,0 +1,14 @@ +error: type alias is never used: `Unused` + --> $DIR/lint-dead-code-impl-trait.rs:12:1 + | +LL | type Unused = (); + | ^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-dead-code-impl-trait.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-dead-code-type-alias.stderr b/src/test/ui/lint/lint-dead-code-type-alias.stderr index a4d4727be7ca4..4198ddfb6cb03 100644 --- a/src/test/ui/lint/lint-dead-code-type-alias.stderr +++ b/src/test/ui/lint/lint-dead-code-type-alias.stderr @@ -1,7 +1,7 @@ error: type alias is never used: `Unused` --> $DIR/lint-dead-code-type-alias.rs:4:1 | -LL | type Unused = u8; //~ ERROR type alias is never used +LL | type Unused = u8; | ^^^^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/lint/lint-dead-code-variant.stderr b/src/test/ui/lint/lint-dead-code-variant.stderr index b9465e73b0d79..a79432dc68d6a 100644 --- a/src/test/ui/lint/lint-dead-code-variant.stderr +++ b/src/test/ui/lint/lint-dead-code-variant.stderr @@ -1,7 +1,7 @@ error: variant is never constructed: `Variant1` --> $DIR/lint-dead-code-variant.rs:5:5 | -LL | Variant1, //~ ERROR: variant is never constructed +LL | Variant1, | ^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/lint/lint-directives-on-use-items-issue-10534.stderr b/src/test/ui/lint/lint-directives-on-use-items-issue-10534.stderr index 170b98a12a848..020591ccff74d 100644 --- a/src/test/ui/lint/lint-directives-on-use-items-issue-10534.stderr +++ b/src/test/ui/lint/lint-directives-on-use-items-issue-10534.stderr @@ -1,7 +1,7 @@ error: unused import: `a::x` --> $DIR/lint-directives-on-use-items-issue-10534.rs:12:9 | -LL | use a::x; //~ ERROR: unused import +LL | use a::x; | ^^^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unused_imports)] error: unused import: `a::y` --> $DIR/lint-directives-on-use-items-issue-10534.rs:21:9 | -LL | use a::y; //~ ERROR: unused import +LL | use a::y; | ^^^^ | note: lint level defined here diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.stderr index be739eb41bd34..f9f168c14dee3 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.stderr +++ b/src/test/ui/lint/lint-exceeding-bitshifts.stderr @@ -1,7 +1,7 @@ error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts.rs:7:15 | -LL | let n = 1u8 << 8; //~ ERROR: attempt to shift left with overflow +LL | let n = 1u8 << 8; | ^^^^^^^^ | note: lint level defined here @@ -13,103 +13,103 @@ LL | #![deny(exceeding_bitshifts, const_err)] error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts.rs:9:15 | -LL | let n = 1u16 << 16; //~ ERROR: attempt to shift left with overflow +LL | let n = 1u16 << 16; | ^^^^^^^^^^ error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts.rs:11:15 | -LL | let n = 1u32 << 32; //~ ERROR: attempt to shift left with overflow +LL | let n = 1u32 << 32; | ^^^^^^^^^^ error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts.rs:13:15 | -LL | let n = 1u64 << 64; //~ ERROR: attempt to shift left with overflow +LL | let n = 1u64 << 64; | ^^^^^^^^^^ error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts.rs:15:15 | -LL | let n = 1i8 << 8; //~ ERROR: attempt to shift left with overflow +LL | let n = 1i8 << 8; | ^^^^^^^^ error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts.rs:17:15 | -LL | let n = 1i16 << 16; //~ ERROR: attempt to shift left with overflow +LL | let n = 1i16 << 16; | ^^^^^^^^^^ error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts.rs:19:15 | -LL | let n = 1i32 << 32; //~ ERROR: attempt to shift left with overflow +LL | let n = 1i32 << 32; | ^^^^^^^^^^ error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts.rs:21:15 | -LL | let n = 1i64 << 64; //~ ERROR: attempt to shift left with overflow +LL | let n = 1i64 << 64; | ^^^^^^^^^^ error: attempt to shift right with overflow --> $DIR/lint-exceeding-bitshifts.rs:24:15 | -LL | let n = 1u8 >> 8; //~ ERROR: attempt to shift right with overflow +LL | let n = 1u8 >> 8; | ^^^^^^^^ error: attempt to shift right with overflow --> $DIR/lint-exceeding-bitshifts.rs:26:15 | -LL | let n = 1u16 >> 16; //~ ERROR: attempt to shift right with overflow +LL | let n = 1u16 >> 16; | ^^^^^^^^^^ error: attempt to shift right with overflow --> $DIR/lint-exceeding-bitshifts.rs:28:15 | -LL | let n = 1u32 >> 32; //~ ERROR: attempt to shift right with overflow +LL | let n = 1u32 >> 32; | ^^^^^^^^^^ error: attempt to shift right with overflow --> $DIR/lint-exceeding-bitshifts.rs:30:15 | -LL | let n = 1u64 >> 64; //~ ERROR: attempt to shift right with overflow +LL | let n = 1u64 >> 64; | ^^^^^^^^^^ error: attempt to shift right with overflow --> $DIR/lint-exceeding-bitshifts.rs:32:15 | -LL | let n = 1i8 >> 8; //~ ERROR: attempt to shift right with overflow +LL | let n = 1i8 >> 8; | ^^^^^^^^ error: attempt to shift right with overflow --> $DIR/lint-exceeding-bitshifts.rs:34:15 | -LL | let n = 1i16 >> 16; //~ ERROR: attempt to shift right with overflow +LL | let n = 1i16 >> 16; | ^^^^^^^^^^ error: attempt to shift right with overflow --> $DIR/lint-exceeding-bitshifts.rs:36:15 | -LL | let n = 1i32 >> 32; //~ ERROR: attempt to shift right with overflow +LL | let n = 1i32 >> 32; | ^^^^^^^^^^ error: attempt to shift right with overflow --> $DIR/lint-exceeding-bitshifts.rs:38:15 | -LL | let n = 1i64 >> 64; //~ ERROR: attempt to shift right with overflow +LL | let n = 1i64 >> 64; | ^^^^^^^^^^ error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts.rs:42:15 | -LL | let n = n << 8; //~ ERROR: attempt to shift left with overflow +LL | let n = n << 8; | ^^^^^^ error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts.rs:44:15 | -LL | let n = 1u8 << -8; //~ ERROR: attempt to shift left with overflow +LL | let n = 1u8 << -8; | ^^^^^^^^^ error: aborting due to 18 previous errors diff --git a/src/test/ui/lint/lint-exceeding-bitshifts2.stderr b/src/test/ui/lint/lint-exceeding-bitshifts2.stderr index 0adcde02acb7b..8a6d2a89c7063 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts2.stderr +++ b/src/test/ui/lint/lint-exceeding-bitshifts2.stderr @@ -1,7 +1,7 @@ error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts2.rs:7:15 | -LL | let n = 1u8 << (4+4); //~ ERROR: attempt to shift left with overflow +LL | let n = 1u8 << (4+4); | ^^^^^^^^^^^^ | note: lint level defined here @@ -13,13 +13,13 @@ LL | #![deny(exceeding_bitshifts, const_err)] error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts2.rs:15:15 | -LL | let n = 1_isize << BITS; //~ ERROR: attempt to shift left with overflow +LL | let n = 1_isize << BITS; | ^^^^^^^^^^^^^^^ error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts2.rs:16:15 | -LL | let n = 1_usize << BITS; //~ ERROR: attempt to shift left with overflow +LL | let n = 1_usize << BITS; | ^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/lint/lint-forbid-cmdline.stderr b/src/test/ui/lint/lint-forbid-cmdline.stderr index 35539f0e87770..bece4775abb93 100644 --- a/src/test/ui/lint/lint-forbid-cmdline.stderr +++ b/src/test/ui/lint/lint-forbid-cmdline.stderr @@ -1,7 +1,7 @@ error[E0453]: allow(deprecated) overruled by outer forbid(deprecated) --> $DIR/lint-forbid-cmdline.rs:3:9 | -LL | #[allow(deprecated)] //~ ERROR allow(deprecated) overruled by outer forbid(deprecated) +LL | #[allow(deprecated)] | ^^^^^^^^^^ overruled by previous forbid | = note: `forbid` lint level was set on command line diff --git a/src/test/ui/lint/lint-group-nonstandard-style.stderr b/src/test/ui/lint/lint-group-nonstandard-style.stderr index ab36cda57ec80..a365204f12adf 100644 --- a/src/test/ui/lint/lint-group-nonstandard-style.stderr +++ b/src/test/ui/lint/lint-group-nonstandard-style.stderr @@ -1,7 +1,7 @@ warning: type `snake_case` should have an upper camel case name --> $DIR/lint-group-nonstandard-style.rs:22:16 | -LL | struct snake_case; //~ WARN should have an upper camel +LL | struct snake_case; | ^^^^^^^^^^ help: convert the identifier to upper camel case: `SnakeCase` | note: lint level defined here @@ -14,7 +14,7 @@ LL | #![warn(nonstandard_style)] error: function `CamelCase` should have a snake case name --> $DIR/lint-group-nonstandard-style.rs:4:4 | -LL | fn CamelCase() {} //~ ERROR should have a snake +LL | fn CamelCase() {} | ^^^^^^^^^ help: convert the identifier to snake case: `camel_case` | note: lint level defined here @@ -27,7 +27,7 @@ LL | #![deny(nonstandard_style)] error: function `CamelCase` should have a snake case name --> $DIR/lint-group-nonstandard-style.rs:12:12 | -LL | fn CamelCase() {} //~ ERROR should have a snake +LL | fn CamelCase() {} | ^^^^^^^^^ help: convert the identifier to snake case: `camel_case` | note: lint level defined here @@ -40,7 +40,7 @@ LL | #[forbid(nonstandard_style)] error: static variable `bad` should have an upper case name --> $DIR/lint-group-nonstandard-style.rs:14:16 | -LL | static bad: isize = 1; //~ ERROR should have an upper +LL | static bad: isize = 1; | ^^^ help: convert the identifier to upper case: `BAD` | note: lint level defined here @@ -53,7 +53,7 @@ LL | #[forbid(nonstandard_style)] warning: function `CamelCase` should have a snake case name --> $DIR/lint-group-nonstandard-style.rs:20:12 | -LL | fn CamelCase() {} //~ WARN should have a snake +LL | fn CamelCase() {} | ^^^^^^^^^ help: convert the identifier to snake case: `camel_case` | note: lint level defined here diff --git a/src/test/ui/lint/lint-impl-fn.stderr b/src/test/ui/lint/lint-impl-fn.stderr index b0a3f61978435..56f85111d428f 100644 --- a/src/test/ui/lint/lint-impl-fn.stderr +++ b/src/test/ui/lint/lint-impl-fn.stderr @@ -1,7 +1,7 @@ error: denote infinite loops with `loop { ... }` --> $DIR/lint-impl-fn.rs:10:21 | -LL | fn bar(&self) { while true {} } //~ ERROR: infinite loops +LL | fn bar(&self) { while true {} } | ^^^^^^^^^^ help: use `loop` | note: lint level defined here @@ -11,25 +11,25 @@ LL | #[deny(while_true)] | ^^^^^^^^^^ error: denote infinite loops with `loop { ... }` - --> $DIR/lint-impl-fn.rs:18:25 + --> $DIR/lint-impl-fn.rs:27:5 | -LL | fn foo(&self) { while true {} } //~ ERROR: infinite loops - | ^^^^^^^^^^ help: use `loop` +LL | while true {} + | ^^^^^^^^^^ help: use `loop` | note: lint level defined here - --> $DIR/lint-impl-fn.rs:13:8 + --> $DIR/lint-impl-fn.rs:25:8 | LL | #[deny(while_true)] | ^^^^^^^^^^ error: denote infinite loops with `loop { ... }` - --> $DIR/lint-impl-fn.rs:27:5 + --> $DIR/lint-impl-fn.rs:18:25 | -LL | while true {} //~ ERROR: infinite loops - | ^^^^^^^^^^ help: use `loop` +LL | fn foo(&self) { while true {} } + | ^^^^^^^^^^ help: use `loop` | note: lint level defined here - --> $DIR/lint-impl-fn.rs:25:8 + --> $DIR/lint-impl-fn.rs:13:8 | LL | #[deny(while_true)] | ^^^^^^^^^^ diff --git a/src/test/ui/lint/lint-incoherent-auto-trait-objects.rs b/src/test/ui/lint/lint-incoherent-auto-trait-objects.rs index 0d18965ee7338..d53b514476025 100644 --- a/src/test/ui/lint/lint-incoherent-auto-trait-objects.rs +++ b/src/test/ui/lint/lint-incoherent-auto-trait-objects.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - trait Foo {} impl Foo for dyn Send {} diff --git a/src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr b/src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr index 928c92ef91655..448cc953d40ad 100644 --- a/src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr +++ b/src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr @@ -1,5 +1,5 @@ error: conflicting implementations of trait `Foo` for type `(dyn std::marker::Send + 'static)`: (E0119) - --> $DIR/lint-incoherent-auto-trait-objects.rs:7:1 + --> $DIR/lint-incoherent-auto-trait-objects.rs:5:1 | LL | impl Foo for dyn Send {} | --------------------- first implementation here @@ -12,7 +12,7 @@ LL | impl Foo for dyn Send + Send {} = note: for more information, see issue #56484 error: conflicting implementations of trait `Foo` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) - --> $DIR/lint-incoherent-auto-trait-objects.rs:13:1 + --> $DIR/lint-incoherent-auto-trait-objects.rs:11:1 | LL | impl Foo for dyn Send + Sync {} | ---------------------------- first implementation here @@ -24,7 +24,7 @@ LL | impl Foo for dyn Sync + Send {} = note: for more information, see issue #56484 error: conflicting implementations of trait `Foo` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) - --> $DIR/lint-incoherent-auto-trait-objects.rs:17:1 + --> $DIR/lint-incoherent-auto-trait-objects.rs:15:1 | LL | impl Foo for dyn Sync + Send {} | ---------------------------- first implementation here diff --git a/src/test/ui/lint/lint-malformed.rs b/src/test/ui/lint/lint-malformed.rs index c97a4320f1d20..0d327677d5469 100644 --- a/src/test/ui/lint/lint-malformed.rs +++ b/src/test/ui/lint/lint-malformed.rs @@ -1,4 +1,4 @@ -#![deny = "foo"] //~ ERROR attribute must be of the form +#![deny = "foo"] //~ ERROR malformed `deny` attribute input #![allow(bar = "baz")] //~ ERROR malformed lint attribute fn main() { } diff --git a/src/test/ui/lint/lint-malformed.stderr b/src/test/ui/lint/lint-malformed.stderr index 98a7cecc2bb2d..f4876290ddb5d 100644 --- a/src/test/ui/lint/lint-malformed.stderr +++ b/src/test/ui/lint/lint-malformed.stderr @@ -1,14 +1,14 @@ -error[E0452]: malformed lint attribute +error[E0452]: malformed lint attribute input --> $DIR/lint-malformed.rs:2:10 | -LL | #![allow(bar = "baz")] //~ ERROR malformed lint attribute - | ^^^^^^^^^^^ +LL | #![allow(bar = "baz")] + | ^^^^^^^^^^^ bad attribute argument -error: attribute must be of the form `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]` +error: malformed `deny` attribute input --> $DIR/lint-malformed.rs:1:1 | -LL | #![deny = "foo"] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^^^ +LL | #![deny = "foo"] + | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]` error: aborting due to 2 previous errors diff --git a/src/test/ui/lint/lint-match-arms.rs b/src/test/ui/lint/lint-match-arms.rs new file mode 100644 index 0000000000000..2c471a61054b2 --- /dev/null +++ b/src/test/ui/lint/lint-match-arms.rs @@ -0,0 +1,18 @@ +fn deny_on_arm() { + match 0 { + #[deny(unused_variables)] + //~^ NOTE lint level defined here + y => (), + //~^ ERROR unused variable + } +} + +#[deny(unused_variables)] +fn allow_on_arm() { + match 0 { + #[allow(unused_variables)] + y => (), // OK + } +} + +fn main() {} diff --git a/src/test/ui/lint/lint-match-arms.stderr b/src/test/ui/lint/lint-match-arms.stderr new file mode 100644 index 0000000000000..e4e3adab0a9b2 --- /dev/null +++ b/src/test/ui/lint/lint-match-arms.stderr @@ -0,0 +1,14 @@ +error: unused variable: `y` + --> $DIR/lint-match-arms.rs:5:9 + | +LL | y => (), + | ^ help: consider prefixing with an underscore: `_y` + | +note: lint level defined here + --> $DIR/lint-match-arms.rs:3:16 + | +LL | #[deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-misplaced-attr.stderr b/src/test/ui/lint/lint-misplaced-attr.stderr index 2a28d54619c6d..1419f858f8e78 100644 --- a/src/test/ui/lint/lint-misplaced-attr.stderr +++ b/src/test/ui/lint/lint-misplaced-attr.stderr @@ -1,7 +1,7 @@ error: unused attribute --> $DIR/lint-misplaced-attr.rs:7:5 | -LL | #![crate_type = "bin"] //~ ERROR unused attribute +LL | #![crate_type = "bin"] | ^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -13,19 +13,19 @@ LL | #![deny(unused_attributes)] error: crate-level attribute should be in the root module --> $DIR/lint-misplaced-attr.rs:7:5 | -LL | #![crate_type = "bin"] //~ ERROR unused attribute +LL | #![crate_type = "bin"] | ^^^^^^^^^^^^^^^^^^^^^^ error: unused attribute --> $DIR/lint-misplaced-attr.rs:11:1 | -LL | #[crate_type = "bin"] fn main() {} //~ ERROR unused attribute +LL | #[crate_type = "bin"] fn main() {} | ^^^^^^^^^^^^^^^^^^^^^ error: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] --> $DIR/lint-misplaced-attr.rs:11:1 | -LL | #[crate_type = "bin"] fn main() {} //~ ERROR unused attribute +LL | #[crate_type = "bin"] fn main() {} | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/lint/lint-missing-copy-implementations.stderr b/src/test/ui/lint/lint-missing-copy-implementations.stderr index 30da3ac879ea8..7b6674e71bf19 100644 --- a/src/test/ui/lint/lint-missing-copy-implementations.stderr +++ b/src/test/ui/lint/lint-missing-copy-implementations.stderr @@ -1,7 +1,7 @@ error: type could implement `Copy`; consider adding `impl Copy` --> $DIR/lint-missing-copy-implementations.rs:6:5 | -LL | / pub struct Foo { //~ ERROR type could implement `Copy`; consider adding `impl Copy` +LL | / pub struct Foo { LL | | pub field: i32 LL | | } | |_____^ diff --git a/src/test/ui/lint/lint-missing-doc.stderr b/src/test/ui/lint/lint-missing-doc.stderr index ea5a14bca7cf3..3532c9315d8dc 100644 --- a/src/test/ui/lint/lint-missing-doc.stderr +++ b/src/test/ui/lint/lint-missing-doc.stderr @@ -1,7 +1,7 @@ error: missing documentation for a type alias --> $DIR/lint-missing-doc.rs:11:1 | -LL | pub type PubTypedef = String; //~ ERROR: missing documentation for a type alias +LL | pub type PubTypedef = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -13,109 +13,109 @@ LL | #![deny(missing_docs)] error: missing documentation for a struct --> $DIR/lint-missing-doc.rs:18:1 | -LL | pub struct PubFoo { //~ ERROR: missing documentation for a struct +LL | pub struct PubFoo { | ^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field --> $DIR/lint-missing-doc.rs:19:5 | -LL | pub a: isize, //~ ERROR: missing documentation for a struct field +LL | pub a: isize, | ^^^^^^^^^^^^ error: missing documentation for a module --> $DIR/lint-missing-doc.rs:30:1 | -LL | pub mod pub_module_no_dox {} //~ ERROR: missing documentation for a module +LL | pub mod pub_module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function --> $DIR/lint-missing-doc.rs:34:1 | -LL | pub fn foo2() {} //~ ERROR: missing documentation for a function +LL | pub fn foo2() {} | ^^^^^^^^^^^^^ error: missing documentation for a trait --> $DIR/lint-missing-doc.rs:52:1 | -LL | pub trait C { //~ ERROR: missing documentation for a trait +LL | pub trait C { | ^^^^^^^^^^^ error: missing documentation for a trait method --> $DIR/lint-missing-doc.rs:53:5 | -LL | fn foo(&self); //~ ERROR: missing documentation for a trait method +LL | fn foo(&self); | ^^^^^^^^^^^^^^ error: missing documentation for a trait method --> $DIR/lint-missing-doc.rs:54:5 | -LL | fn foo_with_impl(&self) {} //~ ERROR: missing documentation for a trait method +LL | fn foo_with_impl(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated type --> $DIR/lint-missing-doc.rs:64:5 | -LL | type AssociatedType; //~ ERROR: missing documentation for an associated type +LL | type AssociatedType; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated type --> $DIR/lint-missing-doc.rs:65:5 | -LL | type AssociatedTypeDef = Self; //~ ERROR: missing documentation for an associated type +LL | type AssociatedTypeDef = Self; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a method --> $DIR/lint-missing-doc.rs:81:5 | -LL | pub fn foo() {} //~ ERROR: missing documentation for a method +LL | pub fn foo() {} | ^^^^^^^^^^^^ error: missing documentation for an enum --> $DIR/lint-missing-doc.rs:118:1 | -LL | pub enum PubBaz { //~ ERROR: missing documentation for an enum +LL | pub enum PubBaz { | ^^^^^^^^^^^^^^^ error: missing documentation for a variant --> $DIR/lint-missing-doc.rs:119:5 | -LL | PubBazA { //~ ERROR: missing documentation for a variant +LL | PubBazA { | ^^^^^^^ error: missing documentation for a struct field --> $DIR/lint-missing-doc.rs:120:9 | -LL | a: isize, //~ ERROR: missing documentation for a struct field +LL | a: isize, | ^^^^^^^^ error: missing documentation for a constant --> $DIR/lint-missing-doc.rs:151:1 | -LL | pub const FOO4: u32 = 0; //~ ERROR: missing documentation for a const +LL | pub const FOO4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static --> $DIR/lint-missing-doc.rs:161:1 | -LL | pub static BAR4: u32 = 0; //~ ERROR: missing documentation for a static +LL | pub static BAR4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function --> $DIR/lint-missing-doc.rs:167:5 | -LL | pub fn undocumented1() {} //~ ERROR: missing documentation for a function +LL | pub fn undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function --> $DIR/lint-missing-doc.rs:168:5 | -LL | pub fn undocumented2() {} //~ ERROR: missing documentation for a function +LL | pub fn undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function --> $DIR/lint-missing-doc.rs:174:9 | -LL | pub fn also_undocumented1() {} //~ ERROR: missing documentation for a function +LL | pub fn also_undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 19 previous errors diff --git a/src/test/ui/lint/lint-non-camel-case-types.stderr b/src/test/ui/lint/lint-non-camel-case-types.stderr index 7afacf64d8778..432a16debc698 100644 --- a/src/test/ui/lint/lint-non-camel-case-types.stderr +++ b/src/test/ui/lint/lint-non-camel-case-types.stderr @@ -13,43 +13,43 @@ LL | #![forbid(non_camel_case_types)] error: type `foo` should have an upper camel case name --> $DIR/lint-non-camel-case-types.rs:7:8 | -LL | struct foo { //~ ERROR type `foo` should have an upper camel case name +LL | struct foo { | ^^^ help: convert the identifier to upper camel case: `Foo` error: type `foo2` should have an upper camel case name --> $DIR/lint-non-camel-case-types.rs:11:6 | -LL | enum foo2 { //~ ERROR type `foo2` should have an upper camel case name +LL | enum foo2 { | ^^^^ help: convert the identifier to upper camel case: `Foo2` error: type `foo3` should have an upper camel case name --> $DIR/lint-non-camel-case-types.rs:15:8 | -LL | struct foo3 { //~ ERROR type `foo3` should have an upper camel case name +LL | struct foo3 { | ^^^^ help: convert the identifier to upper camel case: `Foo3` error: type `foo4` should have an upper camel case name --> $DIR/lint-non-camel-case-types.rs:19:6 | -LL | type foo4 = isize; //~ ERROR type `foo4` should have an upper camel case name +LL | type foo4 = isize; | ^^^^ help: convert the identifier to upper camel case: `Foo4` error: variant `bar` should have an upper camel case name --> $DIR/lint-non-camel-case-types.rs:22:5 | -LL | bar //~ ERROR variant `bar` should have an upper camel case name +LL | bar | ^^^ help: convert the identifier to upper camel case: `Bar` error: trait `foo6` should have an upper camel case name --> $DIR/lint-non-camel-case-types.rs:25:7 | -LL | trait foo6 { //~ ERROR trait `foo6` should have an upper camel case name +LL | trait foo6 { | ^^^^ help: convert the identifier to upper camel case: `Foo6` error: type parameter `ty` should have an upper camel case name --> $DIR/lint-non-camel-case-types.rs:29:6 | -LL | fn f(_: ty) {} //~ ERROR type parameter `ty` should have an upper camel case name +LL | fn f(_: ty) {} | ^^ help: convert the identifier to upper camel case: `Ty` error: aborting due to 8 previous errors diff --git a/src/test/ui/lint/lint-non-snake-case-lifetimes.stderr b/src/test/ui/lint/lint-non-snake-case-lifetimes.stderr index 970666ebcfdc3..d638626495ace 100644 --- a/src/test/ui/lint/lint-non-snake-case-lifetimes.stderr +++ b/src/test/ui/lint/lint-non-snake-case-lifetimes.stderr @@ -1,7 +1,7 @@ error: lifetime `'FooBar` should have a snake case name --> $DIR/lint-non-snake-case-lifetimes.rs:4:6 | -LL | fn f<'FooBar>( //~ ERROR lifetime `'FooBar` should have a snake case name +LL | fn f<'FooBar>( | ^^^^^^^ help: convert the identifier to snake case: `'foo_bar` | note: lint level defined here diff --git a/src/test/ui/lint/lint-non-snake-case-modules.stderr b/src/test/ui/lint/lint-non-snake-case-modules.stderr index 651132e49d914..847c43e1b04e4 100644 --- a/src/test/ui/lint/lint-non-snake-case-modules.stderr +++ b/src/test/ui/lint/lint-non-snake-case-modules.stderr @@ -1,7 +1,7 @@ error: module `FooBar` should have a snake case name --> $DIR/lint-non-snake-case-modules.rs:4:5 | -LL | mod FooBar { //~ ERROR module `FooBar` should have a snake case name +LL | mod FooBar { | ^^^^^^ help: convert the identifier to snake case: `foo_bar` | note: lint level defined here diff --git a/src/test/ui/lint/lint-non-uppercase-statics.stderr b/src/test/ui/lint/lint-non-uppercase-statics.stderr index f5bba5f145de4..8b477276efc93 100644 --- a/src/test/ui/lint/lint-non-uppercase-statics.stderr +++ b/src/test/ui/lint/lint-non-uppercase-statics.stderr @@ -1,7 +1,7 @@ error: static variable `foo` should have an upper case name --> $DIR/lint-non-uppercase-statics.rs:4:8 | -LL | static foo: isize = 1; //~ ERROR static variable `foo` should have an upper case name +LL | static foo: isize = 1; | ^^^ help: convert the identifier to upper case: `FOO` | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![forbid(non_upper_case_globals)] error: static variable `bar` should have an upper case name --> $DIR/lint-non-uppercase-statics.rs:6:12 | -LL | static mut bar: isize = 1; //~ ERROR static variable `bar` should have an upper case name +LL | static mut bar: isize = 1; | ^^^ help: convert the identifier to upper case: `BAR` error: aborting due to 2 previous errors diff --git a/src/test/ui/lint/lint-obsolete-attr.rs b/src/test/ui/lint/lint-obsolete-attr.rs deleted file mode 100644 index 149948b5a6da2..0000000000000 --- a/src/test/ui/lint/lint-obsolete-attr.rs +++ /dev/null @@ -1,12 +0,0 @@ -// When denying at the crate level, be sure to not get random warnings from the -// injected intrinsics by the compiler. - -#![deny(unused_attributes)] -#![allow(dead_code)] -#![feature(custom_attribute)] - -#[ab_isize="stdcall"] extern {} //~ ERROR unused attribute - -#[fixed_stack_segment] fn f() {} //~ ERROR unused attribute - -fn main() {} diff --git a/src/test/ui/lint/lint-obsolete-attr.stderr b/src/test/ui/lint/lint-obsolete-attr.stderr deleted file mode 100644 index c71bde54acfbc..0000000000000 --- a/src/test/ui/lint/lint-obsolete-attr.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: unused attribute - --> $DIR/lint-obsolete-attr.rs:8:1 - | -LL | #[ab_isize="stdcall"] extern {} //~ ERROR unused attribute - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: lint level defined here - --> $DIR/lint-obsolete-attr.rs:4:9 - | -LL | #![deny(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ - -error: unused attribute - --> $DIR/lint-obsolete-attr.rs:10:1 - | -LL | #[fixed_stack_segment] fn f() {} //~ ERROR unused attribute - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/lint/lint-output-format.stderr b/src/test/ui/lint/lint-output-format.stderr index 4dcd8c2316439..21b12301e2c7a 100644 --- a/src/test/ui/lint/lint-output-format.stderr +++ b/src/test/ui/lint/lint-output-format.stderr @@ -1,7 +1,7 @@ error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-output-format.rs:6:1 | -LL | extern crate lint_output_format; //~ ERROR use of unstable library feature +LL | extern crate lint_output_format; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -9,7 +9,7 @@ LL | extern crate lint_output_format; //~ ERROR use of unstable library feature error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-output-format.rs:7:31 | -LL | use lint_output_format::{foo, bar}; //~ ERROR use of unstable library feature +LL | use lint_output_format::{foo, bar}; | ^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -17,7 +17,7 @@ LL | use lint_output_format::{foo, bar}; //~ ERROR use of unstable library featu error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-output-format.rs:11:14 | -LL | let _y = bar(); //~ ERROR use of unstable library feature +LL | let _y = bar(); | ^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable diff --git a/src/test/ui/lint/lint-owned-heap-memory.stderr b/src/test/ui/lint/lint-owned-heap-memory.stderr index 572b82b3366ba..c61b3d31558cb 100644 --- a/src/test/ui/lint/lint-owned-heap-memory.stderr +++ b/src/test/ui/lint/lint-owned-heap-memory.stderr @@ -1,7 +1,7 @@ error: type uses owned (Box type) pointers: std::boxed::Box --> $DIR/lint-owned-heap-memory.rs:6:5 | -LL | x: Box //~ ERROR type uses owned +LL | x: Box | ^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/lint/lint-qualification.stderr b/src/test/ui/lint/lint-qualification.stderr index 953ff0f5f652d..78f7e32a30cd1 100644 --- a/src/test/ui/lint/lint-qualification.stderr +++ b/src/test/ui/lint/lint-qualification.stderr @@ -1,7 +1,7 @@ error: unnecessary qualification --> $DIR/lint-qualification.rs:9:5 | -LL | foo::bar(); //~ ERROR: unnecessary qualification +LL | foo::bar(); | ^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/lint/lint-range-endpoint-overflow.rs b/src/test/ui/lint/lint-range-endpoint-overflow.rs new file mode 100644 index 0000000000000..7034d56aa5d83 --- /dev/null +++ b/src/test/ui/lint/lint-range-endpoint-overflow.rs @@ -0,0 +1,17 @@ +#![deny(overflowing_literals)] + +fn main() { + let range_a = 0..256; //~ ERROR range endpoint is out of range for `u8` + let range_b = 0..=255; // ok + let range_c = 0..=256; //~ ERROR literal out of range for `u8` + let range_d = 256..5; //~ ERROR literal out of range for `u8` + let range_e = 0..257; //~ ERROR literal out of range for `u8` + let _range_f = 0..256u8; //~ ERROR range endpoint is out of range for `u8` + let _range_g = 0..128i8; //~ ERROR range endpoint is out of range for `i8` + + range_a.collect::>(); + range_b.collect::>(); + range_c.collect::>(); + range_d.collect::>(); + range_e.collect::>(); +} diff --git a/src/test/ui/lint/lint-range-endpoint-overflow.stderr b/src/test/ui/lint/lint-range-endpoint-overflow.stderr new file mode 100644 index 0000000000000..939451d6bc022 --- /dev/null +++ b/src/test/ui/lint/lint-range-endpoint-overflow.stderr @@ -0,0 +1,44 @@ +error: range endpoint is out of range for `u8` + --> $DIR/lint-range-endpoint-overflow.rs:4:19 + | +LL | let range_a = 0..256; + | ^^^^^^ help: use an inclusive range instead: `0..=255` + | +note: lint level defined here + --> $DIR/lint-range-endpoint-overflow.rs:1:9 + | +LL | #![deny(overflowing_literals)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: literal out of range for `u8` + --> $DIR/lint-range-endpoint-overflow.rs:6:23 + | +LL | let range_c = 0..=256; + | ^^^ + +error: literal out of range for `u8` + --> $DIR/lint-range-endpoint-overflow.rs:7:19 + | +LL | let range_d = 256..5; + | ^^^ + +error: literal out of range for `u8` + --> $DIR/lint-range-endpoint-overflow.rs:8:22 + | +LL | let range_e = 0..257; + | ^^^ + +error: range endpoint is out of range for `u8` + --> $DIR/lint-range-endpoint-overflow.rs:9:20 + | +LL | let _range_f = 0..256u8; + | ^^^^^^^^ help: use an inclusive range instead: `0..=255u8` + +error: range endpoint is out of range for `i8` + --> $DIR/lint-range-endpoint-overflow.rs:10:20 + | +LL | let _range_g = 0..128i8; + | ^^^^^^^^ help: use an inclusive range instead: `0..=127i8` + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/lint/lint-removed-allow.stderr b/src/test/ui/lint/lint-removed-allow.stderr index f796a14d63796..32af7389b6c7e 100644 --- a/src/test/ui/lint/lint-removed-allow.stderr +++ b/src/test/ui/lint/lint-removed-allow.stderr @@ -1,7 +1,7 @@ error: unused variable: `unused` --> $DIR/lint-removed-allow.rs:8:17 | -LL | fn main() { let unused = (); } //~ ERROR unused +LL | fn main() { let unused = (); } | ^^^^^^ help: consider prefixing with an underscore: `_unused` | note: lint level defined here diff --git a/src/test/ui/lint/lint-removed.stderr b/src/test/ui/lint/lint-removed.stderr index 55f010348fe1e..cde494f22f091 100644 --- a/src/test/ui/lint/lint-removed.stderr +++ b/src/test/ui/lint/lint-removed.stderr @@ -1,7 +1,7 @@ warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok` --> $DIR/lint-removed.rs:6:8 | -LL | #[deny(raw_pointer_derive)] //~ WARN `raw_pointer_derive` has been removed +LL | #[deny(raw_pointer_derive)] | ^^^^^^^^^^^^^^^^^^ | = note: #[warn(renamed_and_removed_lints)] on by default @@ -9,7 +9,7 @@ LL | #[deny(raw_pointer_derive)] //~ WARN `raw_pointer_derive` has been removed error: unused variable: `unused` --> $DIR/lint-removed.rs:8:17 | -LL | fn main() { let unused = (); } //~ ERROR unused +LL | fn main() { let unused = (); } | ^^^^^^ help: consider prefixing with an underscore: `_unused` | note: lint level defined here diff --git a/src/test/ui/lint/lint-renamed-allow.stderr b/src/test/ui/lint/lint-renamed-allow.stderr index b2eeeae8f8e6d..383a800b54a86 100644 --- a/src/test/ui/lint/lint-renamed-allow.stderr +++ b/src/test/ui/lint/lint-renamed-allow.stderr @@ -1,7 +1,7 @@ error: unused variable: `unused` --> $DIR/lint-renamed-allow.rs:8:17 | -LL | fn main() { let unused = (); } //~ ERROR unused +LL | fn main() { let unused = (); } | ^^^^^^ help: consider prefixing with an underscore: `_unused` | note: lint level defined here diff --git a/src/test/ui/lint/lint-renamed.stderr b/src/test/ui/lint/lint-renamed.stderr index b140a93ab38bd..2174b22ffb9db 100644 --- a/src/test/ui/lint/lint-renamed.stderr +++ b/src/test/ui/lint/lint-renamed.stderr @@ -9,7 +9,7 @@ LL | #[deny(bare_trait_object)] error: unused variable: `unused` --> $DIR/lint-renamed.rs:4:17 | -LL | fn main() { let unused = (); } //~ ERROR unused +LL | fn main() { let unused = (); } | ^^^^^^ help: consider prefixing with an underscore: `_unused` | note: lint level defined here diff --git a/src/test/ui/lint/lint-shorthand-field.stderr b/src/test/ui/lint/lint-shorthand-field.stderr index 32c69fdddcbf4..366ab55d7d4df 100644 --- a/src/test/ui/lint/lint-shorthand-field.stderr +++ b/src/test/ui/lint/lint-shorthand-field.stderr @@ -1,7 +1,7 @@ error: the `x:` in this pattern is redundant --> $DIR/lint-shorthand-field.rs:12:13 | -LL | x: x, //~ ERROR the `x:` in this pattern is redundant +LL | x: x, | --^^ | | | help: remove this @@ -15,7 +15,7 @@ LL | #![deny(non_shorthand_field_patterns)] error: the `y:` in this pattern is redundant --> $DIR/lint-shorthand-field.rs:13:13 | -LL | y: ref y, //~ ERROR the `y:` in this pattern is redundant +LL | y: ref y, | --^^^^^^ | | | help: remove this diff --git a/src/test/ui/lint/lint-stability-2.rs b/src/test/ui/lint/lint-stability-2.rs index 12e7b086d35d1..53eee35a9ca24 100644 --- a/src/test/ui/lint/lint-stability-2.rs +++ b/src/test/ui/lint/lint-stability-2.rs @@ -148,7 +148,7 @@ mod cross_crate { ::trait_stable(&foo); } - fn test_method_object(foo: &Trait) { + fn test_method_object(foo: &dyn Trait) { foo.trait_deprecated(); foo.trait_deprecated_text(); foo.trait_deprecated_unstable(); @@ -373,7 +373,7 @@ mod this_crate { ::trait_stable(&foo); } - fn test_method_object(foo: &Trait) { + fn test_method_object(foo: &dyn Trait) { foo.trait_deprecated(); foo.trait_deprecated_text(); foo.trait_unstable(); diff --git a/src/test/ui/lint/lint-stability-2.stderr b/src/test/ui/lint/lint-stability-2.stderr index 4142ce5af7932..808c16c95a498 100644 --- a/src/test/ui/lint/lint-stability-2.stderr +++ b/src/test/ui/lint/lint-stability-2.stderr @@ -81,7 +81,7 @@ LL | ::trait_deprecated_unstable_text(&foo); error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-2.rs:62:13 | -LL | foo.method_unstable(); //~ ERROR use of unstable library feature +LL | foo.method_unstable(); | ^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -89,7 +89,7 @@ LL | foo.method_unstable(); //~ ERROR use of unstable library feature error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-2.rs:63:9 | -LL | Foo::method_unstable(&foo); //~ ERROR use of unstable library feature +LL | Foo::method_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -97,7 +97,7 @@ LL | Foo::method_unstable(&foo); //~ ERROR use of unstable library featu error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-2.rs:64:9 | -LL | ::method_unstable(&foo); //~ ERROR use of unstable library feature +LL | ::method_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -105,7 +105,7 @@ LL | ::method_unstable(&foo); //~ ERROR use of unstable library fea error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-2.rs:65:13 | -LL | foo.trait_unstable(); //~ ERROR use of unstable library feature +LL | foo.trait_unstable(); | ^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -113,7 +113,7 @@ LL | foo.trait_unstable(); //~ ERROR use of unstable library feature error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-2.rs:66:9 | -LL | ::trait_unstable(&foo); //~ ERROR use of unstable library feature +LL | ::trait_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -193,7 +193,7 @@ LL | ::trait_deprecated_unstable_text(&foo); error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-2.rs:139:13 | -LL | foo.trait_unstable(); //~ ERROR use of unstable library feature +LL | foo.trait_unstable(); | ^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -201,7 +201,7 @@ LL | foo.trait_unstable(); //~ ERROR use of unstable library feature error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-2.rs:140:9 | -LL | ::trait_unstable(&foo); //~ ERROR use of unstable library feature +LL | ::trait_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -241,7 +241,7 @@ LL | foo.trait_deprecated_unstable_text(); error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-2.rs:158:13 | -LL | foo.trait_unstable(); //~ ERROR use of unstable library feature +LL | foo.trait_unstable(); | ^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable diff --git a/src/test/ui/lint/lint-stability-deprecated.rs b/src/test/ui/lint/lint-stability-deprecated.rs index 8f6425bcc77f6..a2031c2189ae1 100644 --- a/src/test/ui/lint/lint-stability-deprecated.rs +++ b/src/test/ui/lint/lint-stability-deprecated.rs @@ -2,7 +2,7 @@ // aux-build:lint_stability.rs // aux-build:inherited_stability.rs // aux-build:stability_cfg1.rs -// aux-build:stability_cfg2.rs +// aux-build:stability-cfg2.rs // ignore-tidy-linelength #![warn(deprecated)] #![allow(dead_code, unused_extern_crates)] @@ -98,7 +98,7 @@ mod cross_crate { struct S1(T::TypeUnstable); struct S2(T::TypeDeprecated); //~^ WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text - type A = TraitWithAssociatedTypes< + type A = dyn TraitWithAssociatedTypes< TypeUnstable = u8, TypeDeprecated = u16, //~^ WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated' @@ -170,7 +170,7 @@ mod cross_crate { ::trait_stable(&foo); } - fn test_method_object(foo: &Trait) { + fn test_method_object(foo: &dyn Trait) { foo.trait_deprecated(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated' foo.trait_deprecated_text(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text foo.trait_deprecated_unstable(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable' @@ -423,7 +423,7 @@ mod this_crate { ::trait_stable(&foo); } - fn test_method_object(foo: &Trait) { + fn test_method_object(foo: &dyn Trait) { foo.trait_deprecated(); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated' foo.trait_deprecated_text(); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated_text': text foo.trait_unstable(); diff --git a/src/test/ui/lint/lint-stability-deprecated.stderr b/src/test/ui/lint/lint-stability-deprecated.stderr index a1748ac59fb45..811004ee12ccb 100644 --- a/src/test/ui/lint/lint-stability-deprecated.stderr +++ b/src/test/ui/lint/lint-stability-deprecated.stderr @@ -1,7 +1,7 @@ warning: use of deprecated item 'lint_stability::deprecated': text --> $DIR/lint-stability-deprecated.rs:26:9 | -LL | deprecated(); //~ WARN use of deprecated item 'lint_stability::deprecated' +LL | deprecated(); | ^^^^^^^^^^ | note: lint level defined here @@ -13,73 +13,73 @@ LL | #![warn(deprecated)] warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:31:9 | -LL | Trait::trait_deprecated(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated' +LL | Trait::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:33:9 | -LL | ::trait_deprecated(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::deprecated_text': text --> $DIR/lint-stability-deprecated.rs:35:9 | -LL | deprecated_text(); //~ WARN use of deprecated item 'lint_stability::deprecated_text': text +LL | deprecated_text(); | ^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:40:9 | -LL | Trait::trait_deprecated_text(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text +LL | Trait::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:42:9 | -LL | ::trait_deprecated_text(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::deprecated_unstable': text --> $DIR/lint-stability-deprecated.rs:44:9 | -LL | deprecated_unstable(); //~ WARN use of deprecated item 'lint_stability::deprecated_unstable' +LL | deprecated_unstable(); | ^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text --> $DIR/lint-stability-deprecated.rs:49:9 | -LL | Trait::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable' +LL | Trait::trait_deprecated_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text --> $DIR/lint-stability-deprecated.rs:51:9 | -LL | ::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable' +LL | ::trait_deprecated_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:53:9 | -LL | deprecated_unstable_text(); //~ WARN use of deprecated item 'lint_stability::deprecated_unstable_text': text +LL | deprecated_unstable_text(); | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:58:9 | -LL | Trait::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text +LL | Trait::trait_deprecated_unstable_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:60:9 | -LL | ::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text +LL | ::trait_deprecated_unstable_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedStruct': text --> $DIR/lint-stability-deprecated.rs:107:17 | -LL | let _ = DeprecatedStruct { //~ WARN use of deprecated item 'lint_stability::DeprecatedStruct' +LL | let _ = DeprecatedStruct { | ^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedUnstableStruct': text @@ -91,157 +91,157 @@ LL | let _ = DeprecatedUnstableStruct { warning: use of deprecated item 'lint_stability::DeprecatedUnitStruct': text --> $DIR/lint-stability-deprecated.rs:117:17 | -LL | let _ = DeprecatedUnitStruct; //~ WARN use of deprecated item 'lint_stability::DeprecatedUnitStruct' +LL | let _ = DeprecatedUnitStruct; | ^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedUnstableUnitStruct': text --> $DIR/lint-stability-deprecated.rs:118:17 | -LL | let _ = DeprecatedUnstableUnitStruct; //~ WARN use of deprecated item 'lint_stability::DeprecatedUnstableUnitStruct' +LL | let _ = DeprecatedUnstableUnitStruct; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Enum::DeprecatedVariant': text --> $DIR/lint-stability-deprecated.rs:122:17 | -LL | let _ = Enum::DeprecatedVariant; //~ WARN use of deprecated item 'lint_stability::Enum::DeprecatedVariant' +LL | let _ = Enum::DeprecatedVariant; | ^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Enum::DeprecatedUnstableVariant': text --> $DIR/lint-stability-deprecated.rs:123:17 | -LL | let _ = Enum::DeprecatedUnstableVariant; //~ WARN use of deprecated item 'lint_stability::Enum::DeprecatedUnstableVariant' +LL | let _ = Enum::DeprecatedUnstableVariant; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedTupleStruct': text --> $DIR/lint-stability-deprecated.rs:127:17 | -LL | let _ = DeprecatedTupleStruct (1); //~ WARN use of deprecated item 'lint_stability::DeprecatedTupleStruct' +LL | let _ = DeprecatedTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedUnstableTupleStruct': text --> $DIR/lint-stability-deprecated.rs:128:17 | -LL | let _ = DeprecatedUnstableTupleStruct (1); //~ WARN use of deprecated item 'lint_stability::DeprecatedUnstableTupleStruct' +LL | let _ = DeprecatedUnstableTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::deprecated_text': text --> $DIR/lint-stability-deprecated.rs:137:25 | -LL | macro_test_arg!(deprecated_text()); //~ WARN use of deprecated item 'lint_stability::deprecated_text': text +LL | macro_test_arg!(deprecated_text()); | ^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:138:25 | -LL | macro_test_arg!(deprecated_unstable_text()); //~ WARN use of deprecated item 'lint_stability::deprecated_unstable_text': text +LL | macro_test_arg!(deprecated_unstable_text()); | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::deprecated_text': text --> $DIR/lint-stability-deprecated.rs:139:41 | -LL | macro_test_arg!(macro_test_arg!(deprecated_text())); //~ WARN use of deprecated item 'lint_stability::deprecated_text': text +LL | macro_test_arg!(macro_test_arg!(deprecated_text())); | ^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:144:9 | -LL | Trait::trait_deprecated(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated' +LL | Trait::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:146:9 | -LL | ::trait_deprecated(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:148:9 | -LL | Trait::trait_deprecated_text(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text +LL | Trait::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:150:9 | -LL | ::trait_deprecated_text(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text --> $DIR/lint-stability-deprecated.rs:152:9 | -LL | Trait::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable' +LL | Trait::trait_deprecated_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text --> $DIR/lint-stability-deprecated.rs:154:9 | -LL | ::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable' +LL | ::trait_deprecated_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:156:9 | -LL | Trait::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text +LL | Trait::trait_deprecated_unstable_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:158:9 | -LL | ::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text +LL | ::trait_deprecated_unstable_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedTrait': text --> $DIR/lint-stability-deprecated.rs:186:10 | -LL | impl DeprecatedTrait for S {} //~ WARN use of deprecated item 'lint_stability::DeprecatedTrait': text +LL | impl DeprecatedTrait for S {} | ^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedTrait': text --> $DIR/lint-stability-deprecated.rs:188:25 | -LL | trait LocalTrait2 : DeprecatedTrait { } //~ WARN use of deprecated item 'lint_stability::DeprecatedTrait': text +LL | trait LocalTrait2 : DeprecatedTrait { } | ^^^^^^^^^^^^^^^ warning: use of deprecated item 'inheritance::inherited_stability::unstable_mod::deprecated': text --> $DIR/lint-stability-deprecated.rs:207:9 | -LL | unstable_mod::deprecated(); //~ WARN use of deprecated item 'inheritance::inherited_stability::unstable_mod::deprecated': text +LL | unstable_mod::deprecated(); | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::deprecated': text --> $DIR/lint-stability-deprecated.rs:329:9 | -LL | deprecated(); //~ WARN use of deprecated item 'this_crate::deprecated' +LL | deprecated(); | ^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:334:9 | -LL | Trait::trait_deprecated(&foo); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | Trait::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:336:9 | -LL | ::trait_deprecated(&foo); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::deprecated_text': text --> $DIR/lint-stability-deprecated.rs:338:9 | -LL | deprecated_text(); //~ WARN use of deprecated item 'this_crate::deprecated_text': text +LL | deprecated_text(); | ^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:343:9 | -LL | Trait::trait_deprecated_text(&foo); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | Trait::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:345:9 | -LL | ::trait_deprecated_text(&foo); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::DeprecatedStruct': text @@ -253,67 +253,67 @@ LL | let _ = DeprecatedStruct { warning: use of deprecated item 'this_crate::DeprecatedUnitStruct': text --> $DIR/lint-stability-deprecated.rs:390:17 | -LL | let _ = DeprecatedUnitStruct; //~ WARN use of deprecated item 'this_crate::DeprecatedUnitStruct' +LL | let _ = DeprecatedUnitStruct; | ^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Enum::DeprecatedVariant': text --> $DIR/lint-stability-deprecated.rs:394:17 | -LL | let _ = Enum::DeprecatedVariant; //~ WARN use of deprecated item 'this_crate::Enum::DeprecatedVariant' +LL | let _ = Enum::DeprecatedVariant; | ^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::DeprecatedTupleStruct': text --> $DIR/lint-stability-deprecated.rs:398:17 | -LL | let _ = DeprecatedTupleStruct (1); //~ WARN use of deprecated item 'this_crate::DeprecatedTupleStruct' +LL | let _ = DeprecatedTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:405:9 | -LL | Trait::trait_deprecated(&foo); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | Trait::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:407:9 | -LL | ::trait_deprecated(&foo); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:409:9 | -LL | Trait::trait_deprecated_text(&foo); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | Trait::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:411:9 | -LL | ::trait_deprecated_text(&foo); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::test_fn_body::fn_in_body': text --> $DIR/lint-stability-deprecated.rs:438:9 | -LL | fn_in_body(); //~ WARN use of deprecated item 'this_crate::test_fn_body::fn_in_body': text +LL | fn_in_body(); | ^^^^^^^^^^ warning: use of deprecated item 'this_crate::DeprecatedTrait': text --> $DIR/lint-stability-deprecated.rs:458:10 | -LL | impl DeprecatedTrait for S { } //~ WARN use of deprecated item 'this_crate::DeprecatedTrait' +LL | impl DeprecatedTrait for S { } | ^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::DeprecatedTrait': text --> $DIR/lint-stability-deprecated.rs:460:24 | -LL | trait LocalTrait : DeprecatedTrait { } //~ WARN use of deprecated item 'this_crate::DeprecatedTrait' +LL | trait LocalTrait : DeprecatedTrait { } | ^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::MethodTester::test_method_body::fn_in_body': text --> $DIR/lint-stability-deprecated.rs:446:13 | -LL | fn_in_body(); //~ WARN use of deprecated item 'this_crate::MethodTester::test_method_body::fn_in_body': text +LL | fn_in_body(); | ^^^^^^^^^^ warning: use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text @@ -331,306 +331,306 @@ LL | TypeDeprecated = u16, warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated': text --> $DIR/lint-stability-deprecated.rs:27:13 | -LL | foo.method_deprecated(); //~ WARN use of deprecated item 'lint_stability::MethodTester::method_deprecated' +LL | foo.method_deprecated(); | ^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated': text --> $DIR/lint-stability-deprecated.rs:28:9 | -LL | Foo::method_deprecated(&foo); //~ WARN use of deprecated item 'lint_stability::MethodTester::method_deprecated' +LL | Foo::method_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated': text --> $DIR/lint-stability-deprecated.rs:29:9 | -LL | ::method_deprecated(&foo); //~ WARN use of deprecated item 'lint_stability::MethodTester::method_deprecated' +LL | ::method_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:30:13 | -LL | foo.trait_deprecated(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated' +LL | foo.trait_deprecated(); | ^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:32:9 | -LL | ::trait_deprecated(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:36:13 | -LL | foo.method_deprecated_text(); //~ WARN use of deprecated item 'lint_stability::MethodTester::method_deprecated_text': text +LL | foo.method_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:37:9 | -LL | Foo::method_deprecated_text(&foo); //~ WARN use of deprecated item 'lint_stability::MethodTester::method_deprecated_text': text +LL | Foo::method_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:38:9 | -LL | ::method_deprecated_text(&foo); //~ WARN use of deprecated item 'lint_stability::MethodTester::method_deprecated_text': text +LL | ::method_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:39:13 | -LL | foo.trait_deprecated_text(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text +LL | foo.trait_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:41:9 | -LL | ::trait_deprecated_text(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable': text --> $DIR/lint-stability-deprecated.rs:45:13 | -LL | foo.method_deprecated_unstable(); //~ WARN use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable' +LL | foo.method_deprecated_unstable(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable': text --> $DIR/lint-stability-deprecated.rs:46:9 | -LL | Foo::method_deprecated_unstable(&foo); //~ WARN use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable' +LL | Foo::method_deprecated_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable': text --> $DIR/lint-stability-deprecated.rs:47:9 | -LL | ::method_deprecated_unstable(&foo); //~ WARN use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable' +LL | ::method_deprecated_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text --> $DIR/lint-stability-deprecated.rs:48:13 | -LL | foo.trait_deprecated_unstable(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable' +LL | foo.trait_deprecated_unstable(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text --> $DIR/lint-stability-deprecated.rs:50:9 | -LL | ::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable' +LL | ::trait_deprecated_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:54:13 | -LL | foo.method_deprecated_unstable_text(); //~ WARN use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text +LL | foo.method_deprecated_unstable_text(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:55:9 | -LL | Foo::method_deprecated_unstable_text(&foo); //~ WARN use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text +LL | Foo::method_deprecated_unstable_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:56:9 | -LL | ::method_deprecated_unstable_text(&foo); //~ WARN use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text +LL | ::method_deprecated_unstable_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:57:13 | -LL | foo.trait_deprecated_unstable_text(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text +LL | foo.trait_deprecated_unstable_text(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:59:9 | -LL | ::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text +LL | ::trait_deprecated_unstable_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedStruct::i': text --> $DIR/lint-stability-deprecated.rs:108:13 | -LL | i: 0 //~ WARN use of deprecated item 'lint_stability::DeprecatedStruct::i' +LL | i: 0 | ^^^^ warning: use of deprecated item 'lint_stability::DeprecatedUnstableStruct::i': text --> $DIR/lint-stability-deprecated.rs:112:13 | -LL | i: 0 //~ WARN use of deprecated item 'lint_stability::DeprecatedUnstableStruct::i' +LL | i: 0 | ^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:143:13 | -LL | foo.trait_deprecated(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated' +LL | foo.trait_deprecated(); | ^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:145:9 | -LL | ::trait_deprecated(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:147:13 | -LL | foo.trait_deprecated_text(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text +LL | foo.trait_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:149:9 | -LL | ::trait_deprecated_text(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text --> $DIR/lint-stability-deprecated.rs:151:13 | -LL | foo.trait_deprecated_unstable(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable' +LL | foo.trait_deprecated_unstable(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text --> $DIR/lint-stability-deprecated.rs:153:9 | -LL | ::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable' +LL | ::trait_deprecated_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:155:13 | -LL | foo.trait_deprecated_unstable_text(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text +LL | foo.trait_deprecated_unstable_text(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:157:9 | -LL | ::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text +LL | ::trait_deprecated_unstable_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:174:13 | -LL | foo.trait_deprecated(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated' +LL | foo.trait_deprecated(); | ^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:175:13 | -LL | foo.trait_deprecated_text(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text +LL | foo.trait_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text --> $DIR/lint-stability-deprecated.rs:176:13 | -LL | foo.trait_deprecated_unstable(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable' +LL | foo.trait_deprecated_unstable(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:177:13 | -LL | foo.trait_deprecated_unstable_text(); //~ WARN use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text +LL | foo.trait_deprecated_unstable_text(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::MethodTester::method_deprecated': text --> $DIR/lint-stability-deprecated.rs:330:13 | -LL | foo.method_deprecated(); //~ WARN use of deprecated item 'this_crate::MethodTester::method_deprecated' +LL | foo.method_deprecated(); | ^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::MethodTester::method_deprecated': text --> $DIR/lint-stability-deprecated.rs:331:9 | -LL | Foo::method_deprecated(&foo); //~ WARN use of deprecated item 'this_crate::MethodTester::method_deprecated' +LL | Foo::method_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::MethodTester::method_deprecated': text --> $DIR/lint-stability-deprecated.rs:332:9 | -LL | ::method_deprecated(&foo); //~ WARN use of deprecated item 'this_crate::MethodTester::method_deprecated' +LL | ::method_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:333:13 | -LL | foo.trait_deprecated(); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | foo.trait_deprecated(); | ^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:335:9 | -LL | ::trait_deprecated(&foo); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:339:13 | -LL | foo.method_deprecated_text(); //~ WARN use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text +LL | foo.method_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:340:9 | -LL | Foo::method_deprecated_text(&foo); //~ WARN use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text +LL | Foo::method_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:341:9 | -LL | ::method_deprecated_text(&foo); //~ WARN use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text +LL | ::method_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:342:13 | -LL | foo.trait_deprecated_text(); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | foo.trait_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:344:9 | -LL | ::trait_deprecated_text(&foo); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::DeprecatedStruct::i': text --> $DIR/lint-stability-deprecated.rs:385:13 | -LL | i: 0 //~ WARN use of deprecated item 'this_crate::DeprecatedStruct::i' +LL | i: 0 | ^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:404:13 | -LL | foo.trait_deprecated(); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | foo.trait_deprecated(); | ^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:406:9 | -LL | ::trait_deprecated(&foo); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | ::trait_deprecated(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:408:13 | -LL | foo.trait_deprecated_text(); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | foo.trait_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:410:9 | -LL | ::trait_deprecated_text(&foo); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:427:13 | -LL | foo.trait_deprecated(); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated' +LL | foo.trait_deprecated(); | ^^^^^^^^^^^^^^^^ warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text --> $DIR/lint-stability-deprecated.rs:428:13 | -LL | foo.trait_deprecated_text(); //~ WARN use of deprecated item 'this_crate::Trait::trait_deprecated_text': text +LL | foo.trait_deprecated_text(); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/lint/lint-stability-fields.stderr b/src/test/ui/lint/lint-stability-fields.stderr index 93f8075b2b273..e80e745922de6 100644 --- a/src/test/ui/lint/lint-stability-fields.stderr +++ b/src/test/ui/lint/lint-stability-fields.stderr @@ -1,7 +1,7 @@ error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:51:17 | -LL | let x = Unstable { //~ ERROR use of unstable +LL | let x = Unstable { | ^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -9,7 +9,7 @@ LL | let x = Unstable { //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:61:13 | -LL | let Unstable { //~ ERROR use of unstable +LL | let Unstable { | ^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -17,7 +17,7 @@ LL | let Unstable { //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:67:13 | -LL | let Unstable //~ ERROR use of unstable +LL | let Unstable | ^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -25,7 +25,7 @@ LL | let Unstable //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:72:17 | -LL | let x = reexport::Unstable2(1, 2, 3); //~ ERROR use of unstable +LL | let x = reexport::Unstable2(1, 2, 3); | ^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -33,7 +33,7 @@ LL | let x = reexport::Unstable2(1, 2, 3); //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:74:17 | -LL | let x = Unstable2(1, 2, 3); //~ ERROR use of unstable +LL | let x = Unstable2(1, 2, 3); | ^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -41,7 +41,7 @@ LL | let x = Unstable2(1, 2, 3); //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:80:13 | -LL | let Unstable2 //~ ERROR use of unstable +LL | let Unstable2 | ^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -49,7 +49,7 @@ LL | let Unstable2 //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:85:13 | -LL | let Unstable2 //~ ERROR use of unstable +LL | let Unstable2 | ^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -57,7 +57,7 @@ LL | let Unstable2 //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:90:17 | -LL | let x = Deprecated { //~ ERROR use of unstable +LL | let x = Deprecated { | ^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -65,7 +65,7 @@ LL | let x = Deprecated { //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:100:13 | -LL | let Deprecated { //~ ERROR use of unstable +LL | let Deprecated { | ^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -73,7 +73,7 @@ LL | let Deprecated { //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:106:13 | -LL | let Deprecated //~ ERROR use of unstable +LL | let Deprecated | ^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -81,7 +81,7 @@ LL | let Deprecated //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:110:17 | -LL | let x = Deprecated2(1, 2, 3); //~ ERROR use of unstable +LL | let x = Deprecated2(1, 2, 3); | ^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -89,7 +89,7 @@ LL | let x = Deprecated2(1, 2, 3); //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:116:13 | -LL | let Deprecated2 //~ ERROR use of unstable +LL | let Deprecated2 | ^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -97,7 +97,7 @@ LL | let Deprecated2 //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:121:13 | -LL | let Deprecated2 //~ ERROR use of unstable +LL | let Deprecated2 | ^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -105,7 +105,7 @@ LL | let Deprecated2 //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:21:13 | -LL | override1: 2, //~ ERROR use of unstable +LL | override1: 2, | ^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -113,7 +113,7 @@ LL | override1: 2, //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:22:13 | -LL | override2: 3, //~ ERROR use of unstable +LL | override2: 3, | ^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -121,7 +121,7 @@ LL | override2: 3, //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:26:17 | -LL | let _ = x.override1; //~ ERROR use of unstable +LL | let _ = x.override1; | ^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -129,7 +129,7 @@ LL | let _ = x.override1; //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:27:17 | -LL | let _ = x.override2; //~ ERROR use of unstable +LL | let _ = x.override2; | ^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -137,7 +137,7 @@ LL | let _ = x.override2; //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:31:13 | -LL | override1: _, //~ ERROR use of unstable +LL | override1: _, | ^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -145,7 +145,7 @@ LL | override1: _, //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:32:13 | -LL | override2: _ //~ ERROR use of unstable +LL | override2: _ | ^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -153,7 +153,7 @@ LL | override2: _ //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:40:17 | -LL | let _ = x.1; //~ ERROR use of unstable +LL | let _ = x.1; | ^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -161,7 +161,7 @@ LL | let _ = x.1; //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:41:17 | -LL | let _ = x.2; //~ ERROR use of unstable +LL | let _ = x.2; | ^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -169,7 +169,7 @@ LL | let _ = x.2; //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:44:20 | -LL | _, //~ ERROR use of unstable +LL | _, | ^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -177,7 +177,7 @@ LL | _, //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:45:20 | -LL | _) //~ ERROR use of unstable +LL | _) | ^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -185,7 +185,7 @@ LL | _) //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:52:13 | -LL | inherit: 1, //~ ERROR use of unstable +LL | inherit: 1, | ^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -193,7 +193,7 @@ LL | inherit: 1, //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:54:13 | -LL | override2: 3, //~ ERROR use of unstable +LL | override2: 3, | ^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -201,7 +201,7 @@ LL | override2: 3, //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:57:17 | -LL | let _ = x.inherit; //~ ERROR use of unstable +LL | let _ = x.inherit; | ^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -209,7 +209,7 @@ LL | let _ = x.inherit; //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:59:17 | -LL | let _ = x.override2; //~ ERROR use of unstable +LL | let _ = x.override2; | ^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -217,7 +217,7 @@ LL | let _ = x.override2; //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:62:13 | -LL | inherit: _, //~ ERROR use of unstable +LL | inherit: _, | ^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -225,7 +225,7 @@ LL | inherit: _, //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:64:13 | -LL | override2: _ //~ ERROR use of unstable +LL | override2: _ | ^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -233,7 +233,7 @@ LL | override2: _ //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:76:17 | -LL | let _ = x.0; //~ ERROR use of unstable +LL | let _ = x.0; | ^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -241,7 +241,7 @@ LL | let _ = x.0; //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:78:17 | -LL | let _ = x.2; //~ ERROR use of unstable +LL | let _ = x.2; | ^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -249,7 +249,7 @@ LL | let _ = x.2; //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:81:14 | -LL | (_, //~ ERROR use of unstable +LL | (_, | ^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -257,7 +257,7 @@ LL | (_, //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:83:14 | -LL | _) //~ ERROR use of unstable +LL | _) | ^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -265,7 +265,7 @@ LL | _) //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:91:13 | -LL | inherit: 1, //~ ERROR use of unstable +LL | inherit: 1, | ^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -273,7 +273,7 @@ LL | inherit: 1, //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:93:13 | -LL | override2: 3, //~ ERROR use of unstable +LL | override2: 3, | ^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -281,7 +281,7 @@ LL | override2: 3, //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:96:17 | -LL | let _ = x.inherit; //~ ERROR use of unstable +LL | let _ = x.inherit; | ^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -289,7 +289,7 @@ LL | let _ = x.inherit; //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:98:17 | -LL | let _ = x.override2; //~ ERROR use of unstable +LL | let _ = x.override2; | ^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -297,7 +297,7 @@ LL | let _ = x.override2; //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:101:13 | -LL | inherit: _, //~ ERROR use of unstable +LL | inherit: _, | ^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -305,7 +305,7 @@ LL | inherit: _, //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:103:13 | -LL | override2: _ //~ ERROR use of unstable +LL | override2: _ | ^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -313,7 +313,7 @@ LL | override2: _ //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:112:17 | -LL | let _ = x.0; //~ ERROR use of unstable +LL | let _ = x.0; | ^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -321,7 +321,7 @@ LL | let _ = x.0; //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:114:17 | -LL | let _ = x.2; //~ ERROR use of unstable +LL | let _ = x.2; | ^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -329,7 +329,7 @@ LL | let _ = x.2; //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:117:14 | -LL | (_, //~ ERROR use of unstable +LL | (_, | ^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -337,7 +337,7 @@ LL | (_, //~ ERROR use of unstable error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability-fields.rs:119:14 | -LL | _) //~ ERROR use of unstable +LL | _) | ^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable diff --git a/src/test/ui/lint/lint-stability.rs b/src/test/ui/lint/lint-stability.rs index 6ff79083f46ff..fde27eec7d3e8 100644 --- a/src/test/ui/lint/lint-stability.rs +++ b/src/test/ui/lint/lint-stability.rs @@ -1,7 +1,7 @@ // aux-build:lint_stability.rs // aux-build:inherited_stability.rs // aux-build:stability_cfg1.rs -// aux-build:stability_cfg2.rs +// aux-build:stability-cfg2.rs #![allow(deprecated)] #![allow(dead_code)] @@ -88,7 +88,7 @@ mod cross_crate { struct S1(T::TypeUnstable); //~^ ERROR use of unstable library feature struct S2(T::TypeDeprecated); - type A = TraitWithAssociatedTypes< + type A = dyn TraitWithAssociatedTypes< TypeUnstable = u8, //~ ERROR use of unstable library feature TypeDeprecated = u16, >; @@ -161,7 +161,7 @@ mod cross_crate { ::trait_stable(&foo); } - fn test_method_object(foo: &Trait) { + fn test_method_object(foo: &dyn Trait) { foo.trait_deprecated(); foo.trait_deprecated_text(); foo.trait_stable(); @@ -414,7 +414,7 @@ mod this_crate { ::trait_stable(&foo); } - fn test_method_object(foo: &Trait) { + fn test_method_object(foo: &dyn Trait) { foo.trait_deprecated(); foo.trait_deprecated_text(); foo.trait_unstable(); diff --git a/src/test/ui/lint/lint-stability.stderr b/src/test/ui/lint/lint-stability.stderr index 03c42e59c679a..dd7f7182530b9 100644 --- a/src/test/ui/lint/lint-stability.stderr +++ b/src/test/ui/lint/lint-stability.stderr @@ -1,7 +1,7 @@ error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:17:5 | -LL | extern crate stability_cfg2; //~ ERROR use of unstable library feature +LL | extern crate stability_cfg2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -57,7 +57,7 @@ LL | ::trait_deprecated_unstable_text(&foo); error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:59:9 | -LL | unstable(); //~ ERROR use of unstable library feature +LL | unstable(); | ^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -65,7 +65,7 @@ LL | unstable(); //~ ERROR use of unstable library feature error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:60:9 | -LL | Trait::trait_unstable(&foo); //~ ERROR use of unstable library feature +LL | Trait::trait_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -73,7 +73,7 @@ LL | Trait::trait_unstable(&foo); //~ ERROR use of unstable library feat error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:61:9 | -LL | ::trait_unstable(&foo); //~ ERROR use of unstable library feature +LL | ::trait_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -113,7 +113,7 @@ LL | let _ = DeprecatedUnstableStruct { error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:103:17 | -LL | let _ = UnstableStruct { i: 0 }; //~ ERROR use of unstable library feature +LL | let _ = UnstableStruct { i: 0 }; | ^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -129,7 +129,7 @@ LL | let _ = DeprecatedUnstableUnitStruct; error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:109:17 | -LL | let _ = UnstableUnitStruct; //~ ERROR use of unstable library feature +LL | let _ = UnstableUnitStruct; | ^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -145,7 +145,7 @@ LL | let _ = Enum::DeprecatedUnstableVariant; error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:115:17 | -LL | let _ = Enum::UnstableVariant; //~ ERROR use of unstable library feature +LL | let _ = Enum::UnstableVariant; | ^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -161,7 +161,7 @@ LL | let _ = DeprecatedUnstableTupleStruct (1); error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:121:17 | -LL | let _ = UnstableTupleStruct (1); //~ ERROR use of unstable library feature +LL | let _ = UnstableTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -209,7 +209,7 @@ LL | ::trait_deprecated_unstable_text(&foo); error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:152:9 | -LL | Trait::trait_unstable(&foo); //~ ERROR use of unstable library feature +LL | Trait::trait_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -217,7 +217,7 @@ LL | Trait::trait_unstable(&foo); //~ ERROR use of unstable library feat error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:153:9 | -LL | ::trait_unstable(&foo); //~ ERROR use of unstable library feature +LL | ::trait_unstable(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -241,7 +241,7 @@ LL | ::trait_unstable_text(&foo); error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:172:10 | -LL | impl UnstableTrait for S { } //~ ERROR use of unstable library feature +LL | impl UnstableTrait for S { } | ^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -249,7 +249,7 @@ LL | impl UnstableTrait for S { } //~ ERROR use of unstable library feature error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:174:24 | -LL | trait LocalTrait : UnstableTrait { } //~ ERROR use of unstable library feature +LL | trait LocalTrait : UnstableTrait { } | ^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -257,7 +257,7 @@ LL | trait LocalTrait : UnstableTrait { } //~ ERROR use of unstable library error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:179:9 | -LL | fn trait_unstable(&self) {} //~ ERROR use of unstable library feature +LL | fn trait_unstable(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -265,7 +265,7 @@ LL | fn trait_unstable(&self) {} //~ ERROR use of unstable library featu error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:184:5 | -LL | extern crate inherited_stability; //~ ERROR use of unstable library feature +LL | extern crate inherited_stability; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -273,7 +273,7 @@ LL | extern crate inherited_stability; //~ ERROR use of unstable library fea error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:185:9 | -LL | use self::inherited_stability::*; //~ ERROR use of unstable library feature +LL | use self::inherited_stability::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -281,7 +281,7 @@ LL | use self::inherited_stability::*; //~ ERROR use of unstable library fea error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:188:9 | -LL | unstable(); //~ ERROR use of unstable library feature +LL | unstable(); | ^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -289,7 +289,7 @@ LL | unstable(); //~ ERROR use of unstable library feature error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:191:9 | -LL | stable_mod::unstable(); //~ ERROR use of unstable library feature +LL | stable_mod::unstable(); | ^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -297,7 +297,7 @@ LL | stable_mod::unstable(); //~ ERROR use of unstable library feature error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:195:9 | -LL | unstable_mod::unstable(); //~ ERROR use of unstable library feature +LL | unstable_mod::unstable(); | ^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -305,7 +305,7 @@ LL | unstable_mod::unstable(); //~ ERROR use of unstable library feature error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:197:17 | -LL | let _ = Unstable::UnstableVariant; //~ ERROR use of unstable library feature +LL | let _ = Unstable::UnstableVariant; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable @@ -321,7 +321,7 @@ LL | struct S1(T::TypeUnstable); error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:92:13 | -LL | TypeUnstable = u8, //~ ERROR use of unstable library feature +LL | TypeUnstable = u8, | ^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_test_feature)] to the crate attributes to enable diff --git a/src/test/ui/lint/lint-type-limits.stderr b/src/test/ui/lint/lint-type-limits.stderr index 14ef953d294e0..71a2b3bfda8c4 100644 --- a/src/test/ui/lint/lint-type-limits.stderr +++ b/src/test/ui/lint/lint-type-limits.stderr @@ -1,7 +1,7 @@ error: comparison is useless due to type limits --> $DIR/lint-type-limits.rs:8:11 | -LL | while i >= 0 { //~ ERROR comparison is useless due to type limits +LL | while i >= 0 { | ^^^^^^ | = note: requested on the command line with `-D unused-comparisons` @@ -9,49 +9,49 @@ LL | while i >= 0 { //~ ERROR comparison is useless due to type limits error: comparison is useless due to type limits --> $DIR/lint-type-limits.rs:19:13 | -LL | let _ = u > 255; //~ ERROR comparison is useless due to type limits +LL | let _ = u > 255; | ^^^^^^^ error: comparison is useless due to type limits --> $DIR/lint-type-limits.rs:20:13 | -LL | let _ = 255 < u; //~ ERROR comparison is useless due to type limits +LL | let _ = 255 < u; | ^^^^^^^ error: comparison is useless due to type limits --> $DIR/lint-type-limits.rs:21:13 | -LL | let _ = u < 0; //~ ERROR comparison is useless due to type limits +LL | let _ = u < 0; | ^^^^^ error: comparison is useless due to type limits --> $DIR/lint-type-limits.rs:22:13 | -LL | let _ = 0 > u; //~ ERROR comparison is useless due to type limits +LL | let _ = 0 > u; | ^^^^^ error: comparison is useless due to type limits --> $DIR/lint-type-limits.rs:23:13 | -LL | let _ = u <= 255; //~ ERROR comparison is useless due to type limits +LL | let _ = u <= 255; | ^^^^^^^^ error: comparison is useless due to type limits --> $DIR/lint-type-limits.rs:24:13 | -LL | let _ = 255 >= u; //~ ERROR comparison is useless due to type limits +LL | let _ = 255 >= u; | ^^^^^^^^ error: comparison is useless due to type limits --> $DIR/lint-type-limits.rs:25:13 | -LL | let _ = u >= 0; //~ ERROR comparison is useless due to type limits +LL | let _ = u >= 0; | ^^^^^^ error: comparison is useless due to type limits --> $DIR/lint-type-limits.rs:26:13 | -LL | let _ = 0 <= u; //~ ERROR comparison is useless due to type limits +LL | let _ = 0 <= u; | ^^^^^^ error: aborting due to 9 previous errors diff --git a/src/test/ui/lint/lint-type-limits2.rs b/src/test/ui/lint/lint-type-limits2.rs index c4486e0676887..3f90119cd8954 100644 --- a/src/test/ui/lint/lint-type-limits2.rs +++ b/src/test/ui/lint/lint-type-limits2.rs @@ -11,5 +11,5 @@ fn bar() -> i8 { fn baz() -> bool { 128 > bar() //~ ERROR comparison is useless due to type limits - //~| WARN literal out of range for i8 + //~| WARN literal out of range for `i8` } diff --git a/src/test/ui/lint/lint-type-limits2.stderr b/src/test/ui/lint/lint-type-limits2.stderr index f88fff62e21fc..0b3d292856707 100644 --- a/src/test/ui/lint/lint-type-limits2.stderr +++ b/src/test/ui/lint/lint-type-limits2.stderr @@ -1,15 +1,15 @@ error: comparison is useless due to type limits --> $DIR/lint-type-limits2.rs:13:5 | -LL | 128 > bar() //~ ERROR comparison is useless due to type limits +LL | 128 > bar() | ^^^^^^^^^^^ | = note: requested on the command line with `-D unused-comparisons` -warning: literal out of range for i8 +warning: literal out of range for `i8` --> $DIR/lint-type-limits2.rs:13:5 | -LL | 128 > bar() //~ ERROR comparison is useless due to type limits +LL | 128 > bar() | ^^^ | note: lint level defined here diff --git a/src/test/ui/lint/lint-type-limits3.rs b/src/test/ui/lint/lint-type-limits3.rs index a715c69f7849e..ceecf9ab30bb8 100644 --- a/src/test/ui/lint/lint-type-limits3.rs +++ b/src/test/ui/lint/lint-type-limits3.rs @@ -7,7 +7,7 @@ fn main() { } fn qux() { let mut i = 1i8; while 200 != i { //~ ERROR comparison is useless due to type limits - //~| WARN literal out of range for i8 + //~| WARN literal out of range for `i8` i += 1; } } diff --git a/src/test/ui/lint/lint-type-limits3.stderr b/src/test/ui/lint/lint-type-limits3.stderr index 4f47a7ce31665..70cd9c859ecf3 100644 --- a/src/test/ui/lint/lint-type-limits3.stderr +++ b/src/test/ui/lint/lint-type-limits3.stderr @@ -1,15 +1,15 @@ error: comparison is useless due to type limits --> $DIR/lint-type-limits3.rs:9:11 | -LL | while 200 != i { //~ ERROR comparison is useless due to type limits +LL | while 200 != i { | ^^^^^^^^ | = note: requested on the command line with `-D unused-comparisons` -warning: literal out of range for i8 +warning: literal out of range for `i8` --> $DIR/lint-type-limits3.rs:9:11 | -LL | while 200 != i { //~ ERROR comparison is useless due to type limits +LL | while 200 != i { | ^^^ | note: lint level defined here diff --git a/src/test/ui/lint/lint-type-overflow.rs b/src/test/ui/lint/lint-type-overflow.rs index 847cdf31dc788..9672da6d3586c 100644 --- a/src/test/ui/lint/lint-type-overflow.rs +++ b/src/test/ui/lint/lint-type-overflow.rs @@ -1,5 +1,3 @@ -// - #![deny(overflowing_literals)] fn test(x: i8) { @@ -9,39 +7,39 @@ fn test(x: i8) { #[allow(unused_variables)] fn main() { let x1: u8 = 255; // should be OK - let x1: u8 = 256; //~ error: literal out of range for u8 + let x1: u8 = 256; //~ error: literal out of range for `u8` let x1 = 255_u8; // should be OK - let x1 = 256_u8; //~ error: literal out of range for u8 + let x1 = 256_u8; //~ error: literal out of range for `u8` let x2: i8 = -128; // should be OK - let x1: i8 = 128; //~ error: literal out of range for i8 + let x1: i8 = 128; //~ error: literal out of range for `i8` - let x3: i8 = -129; //~ error: literal out of range for i8 - let x3: i8 = -(129); //~ error: literal out of range for i8 - let x3: i8 = -{129}; //~ error: literal out of range for i8 + let x3: i8 = -129; //~ error: literal out of range for `i8` + let x3: i8 = -(129); //~ error: literal out of range for `i8` + let x3: i8 = -{129}; //~ error: literal out of range for `i8` - test(1000); //~ error: literal out of range for i8 + test(1000); //~ error: literal out of range for `i8` - let x = 128_i8; //~ error: literal out of range for i8 + let x = 128_i8; //~ error: literal out of range for `i8` let x = 127_i8; let x = -128_i8; let x = -(128_i8); - let x = -129_i8; //~ error: literal out of range for i8 + let x = -129_i8; //~ error: literal out of range for `i8` let x: i32 = 2147483647; // should be OK let x = 2147483647_i32; // should be OK - let x: i32 = 2147483648; //~ error: literal out of range for i32 - let x = 2147483648_i32; //~ error: literal out of range for i32 + let x: i32 = 2147483648; //~ error: literal out of range for `i32` + let x = 2147483648_i32; //~ error: literal out of range for `i32` let x: i32 = -2147483648; // should be OK let x = -2147483648_i32; // should be OK - let x: i32 = -2147483649; //~ error: literal out of range for i32 - let x = -2147483649_i32; //~ error: literal out of range for i32 - let x = 2147483648; //~ error: literal out of range for i32 + let x: i32 = -2147483649; //~ error: literal out of range for `i32` + let x = -2147483649_i32; //~ error: literal out of range for `i32` + let x = 2147483648; //~ error: literal out of range for `i32` - let x = 9223372036854775808_i64; //~ error: literal out of range for i64 + let x = 9223372036854775808_i64; //~ error: literal out of range for `i64` let x = -9223372036854775808_i64; // should be OK - let x = 18446744073709551615_i64; //~ error: literal out of range for i64 - let x: i64 = -9223372036854775809; //~ error: literal out of range for i64 - let x = -9223372036854775809_i64; //~ error: literal out of range for i64 + let x = 18446744073709551615_i64; //~ error: literal out of range for `i64` + let x: i64 = -9223372036854775809; //~ error: literal out of range for `i64` + let x = -9223372036854775809_i64; //~ error: literal out of range for `i64` } diff --git a/src/test/ui/lint/lint-type-overflow.stderr b/src/test/ui/lint/lint-type-overflow.stderr index 987ee8a640c9c..6fcd9b58b2dc7 100644 --- a/src/test/ui/lint/lint-type-overflow.stderr +++ b/src/test/ui/lint/lint-type-overflow.stderr @@ -1,115 +1,115 @@ -error: literal out of range for u8 - --> $DIR/lint-type-overflow.rs:12:18 +error: literal out of range for `u8` + --> $DIR/lint-type-overflow.rs:10:18 | -LL | let x1: u8 = 256; //~ error: literal out of range for u8 +LL | let x1: u8 = 256; | ^^^ | note: lint level defined here - --> $DIR/lint-type-overflow.rs:3:9 + --> $DIR/lint-type-overflow.rs:1:9 | LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ -error: literal out of range for u8 - --> $DIR/lint-type-overflow.rs:15:14 +error: literal out of range for `u8` + --> $DIR/lint-type-overflow.rs:13:14 | -LL | let x1 = 256_u8; //~ error: literal out of range for u8 +LL | let x1 = 256_u8; | ^^^^^^ -error: literal out of range for i8 - --> $DIR/lint-type-overflow.rs:18:18 +error: literal out of range for `i8` + --> $DIR/lint-type-overflow.rs:16:18 | -LL | let x1: i8 = 128; //~ error: literal out of range for i8 +LL | let x1: i8 = 128; | ^^^ -error: literal out of range for i8 - --> $DIR/lint-type-overflow.rs:20:19 +error: literal out of range for `i8` + --> $DIR/lint-type-overflow.rs:18:19 | -LL | let x3: i8 = -129; //~ error: literal out of range for i8 +LL | let x3: i8 = -129; | ^^^ -error: literal out of range for i8 - --> $DIR/lint-type-overflow.rs:21:19 +error: literal out of range for `i8` + --> $DIR/lint-type-overflow.rs:19:19 | -LL | let x3: i8 = -(129); //~ error: literal out of range for i8 +LL | let x3: i8 = -(129); | ^^^^^ -error: literal out of range for i8 - --> $DIR/lint-type-overflow.rs:22:20 +error: literal out of range for `i8` + --> $DIR/lint-type-overflow.rs:20:20 | -LL | let x3: i8 = -{129}; //~ error: literal out of range for i8 +LL | let x3: i8 = -{129}; | ^^^ -error: literal out of range for i8 - --> $DIR/lint-type-overflow.rs:24:10 +error: literal out of range for `i8` + --> $DIR/lint-type-overflow.rs:22:10 | -LL | test(1000); //~ error: literal out of range for i8 +LL | test(1000); | ^^^^ -error: literal out of range for i8 - --> $DIR/lint-type-overflow.rs:26:13 +error: literal out of range for `i8` + --> $DIR/lint-type-overflow.rs:24:13 | -LL | let x = 128_i8; //~ error: literal out of range for i8 +LL | let x = 128_i8; | ^^^^^^ -error: literal out of range for i8 - --> $DIR/lint-type-overflow.rs:30:14 +error: literal out of range for `i8` + --> $DIR/lint-type-overflow.rs:28:14 | -LL | let x = -129_i8; //~ error: literal out of range for i8 +LL | let x = -129_i8; | ^^^^^^ -error: literal out of range for i32 - --> $DIR/lint-type-overflow.rs:34:18 +error: literal out of range for `i32` + --> $DIR/lint-type-overflow.rs:32:18 | -LL | let x: i32 = 2147483648; //~ error: literal out of range for i32 +LL | let x: i32 = 2147483648; | ^^^^^^^^^^ -error: literal out of range for i32 - --> $DIR/lint-type-overflow.rs:35:13 +error: literal out of range for `i32` + --> $DIR/lint-type-overflow.rs:33:13 | -LL | let x = 2147483648_i32; //~ error: literal out of range for i32 +LL | let x = 2147483648_i32; | ^^^^^^^^^^^^^^ -error: literal out of range for i32 - --> $DIR/lint-type-overflow.rs:38:19 +error: literal out of range for `i32` + --> $DIR/lint-type-overflow.rs:36:19 | -LL | let x: i32 = -2147483649; //~ error: literal out of range for i32 +LL | let x: i32 = -2147483649; | ^^^^^^^^^^ -error: literal out of range for i32 - --> $DIR/lint-type-overflow.rs:39:14 +error: literal out of range for `i32` + --> $DIR/lint-type-overflow.rs:37:14 | -LL | let x = -2147483649_i32; //~ error: literal out of range for i32 +LL | let x = -2147483649_i32; | ^^^^^^^^^^^^^^ -error: literal out of range for i32 - --> $DIR/lint-type-overflow.rs:40:13 +error: literal out of range for `i32` + --> $DIR/lint-type-overflow.rs:38:13 | -LL | let x = 2147483648; //~ error: literal out of range for i32 +LL | let x = 2147483648; | ^^^^^^^^^^ -error: literal out of range for i64 - --> $DIR/lint-type-overflow.rs:42:13 +error: literal out of range for `i64` + --> $DIR/lint-type-overflow.rs:40:13 | -LL | let x = 9223372036854775808_i64; //~ error: literal out of range for i64 +LL | let x = 9223372036854775808_i64; | ^^^^^^^^^^^^^^^^^^^^^^^ -error: literal out of range for i64 - --> $DIR/lint-type-overflow.rs:44:13 +error: literal out of range for `i64` + --> $DIR/lint-type-overflow.rs:42:13 | -LL | let x = 18446744073709551615_i64; //~ error: literal out of range for i64 +LL | let x = 18446744073709551615_i64; | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: literal out of range for i64 - --> $DIR/lint-type-overflow.rs:45:19 +error: literal out of range for `i64` + --> $DIR/lint-type-overflow.rs:43:19 | -LL | let x: i64 = -9223372036854775809; //~ error: literal out of range for i64 +LL | let x: i64 = -9223372036854775809; | ^^^^^^^^^^^^^^^^^^^ -error: literal out of range for i64 - --> $DIR/lint-type-overflow.rs:46:14 +error: literal out of range for `i64` + --> $DIR/lint-type-overflow.rs:44:14 | -LL | let x = -9223372036854775809_i64; //~ error: literal out of range for i64 +LL | let x = -9223372036854775809_i64; | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 18 previous errors diff --git a/src/test/ui/lint/lint-type-overflow2.rs b/src/test/ui/lint/lint-type-overflow2.rs index 507e8d0734970..c1f874c079cb5 100644 --- a/src/test/ui/lint/lint-type-overflow2.rs +++ b/src/test/ui/lint/lint-type-overflow2.rs @@ -1,15 +1,13 @@ // compile-flags: -O -#![warn(overflowing_literals)] -#![warn(const_err)] -// compile-pass -#[allow(unused_variables)] +#![deny(overflowing_literals)] +#![deny(const_err)] fn main() { - let x2: i8 = --128; //~ warn: literal out of range for i8 + let x2: i8 = --128; //~ ERROR literal out of range for `i8` - let x = -3.40282357e+38_f32; //~ warn: literal out of range for f32 - let x = 3.40282357e+38_f32; //~ warn: literal out of range for f32 - let x = -1.7976931348623159e+308_f64; //~ warn: literal out of range for f64 - let x = 1.7976931348623159e+308_f64; //~ warn: literal out of range for f64 + let x = -3.40282357e+38_f32; //~ ERROR literal out of range for `f32` + let x = 3.40282357e+38_f32; //~ ERROR literal out of range for `f32` + let x = -1.7976931348623159e+308_f64; //~ ERROR literal out of range for `f64` + let x = 1.7976931348623159e+308_f64; //~ ERROR literal out of range for `f64` } diff --git a/src/test/ui/lint/lint-type-overflow2.stderr b/src/test/ui/lint/lint-type-overflow2.stderr index 5f63ce49680b3..761b095464fe8 100644 --- a/src/test/ui/lint/lint-type-overflow2.stderr +++ b/src/test/ui/lint/lint-type-overflow2.stderr @@ -1,48 +1,38 @@ -warning: literal out of range for i8 - --> $DIR/lint-type-overflow2.rs:9:20 +error: literal out of range for `i8` + --> $DIR/lint-type-overflow2.rs:7:20 | -LL | let x2: i8 = --128; //~ warn: literal out of range for i8 +LL | let x2: i8 = --128; | ^^^ | note: lint level defined here - --> $DIR/lint-type-overflow2.rs:2:9 + --> $DIR/lint-type-overflow2.rs:3:9 | -LL | #![warn(overflowing_literals)] +LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ -warning: literal out of range for f32 - --> $DIR/lint-type-overflow2.rs:11:14 +error: literal out of range for `f32` + --> $DIR/lint-type-overflow2.rs:9:14 | -LL | let x = -3.40282357e+38_f32; //~ warn: literal out of range for f32 +LL | let x = -3.40282357e+38_f32; | ^^^^^^^^^^^^^^^^^^ -warning: literal out of range for f32 - --> $DIR/lint-type-overflow2.rs:12:14 +error: literal out of range for `f32` + --> $DIR/lint-type-overflow2.rs:10:14 | -LL | let x = 3.40282357e+38_f32; //~ warn: literal out of range for f32 +LL | let x = 3.40282357e+38_f32; | ^^^^^^^^^^^^^^^^^^ -warning: literal out of range for f64 - --> $DIR/lint-type-overflow2.rs:13:14 +error: literal out of range for `f64` + --> $DIR/lint-type-overflow2.rs:11:14 | -LL | let x = -1.7976931348623159e+308_f64; //~ warn: literal out of range for f64 +LL | let x = -1.7976931348623159e+308_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: literal out of range for f64 - --> $DIR/lint-type-overflow2.rs:14:14 +error: literal out of range for `f64` + --> $DIR/lint-type-overflow2.rs:12:14 | -LL | let x = 1.7976931348623159e+308_f64; //~ warn: literal out of range for f64 +LL | let x = 1.7976931348623159e+308_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: this expression will panic at runtime - --> $DIR/lint-type-overflow2.rs:9:18 - | -LL | let x2: i8 = --128; //~ warn: literal out of range for i8 - | ^^^^^ attempt to negate with overflow - | -note: lint level defined here - --> $DIR/lint-type-overflow2.rs:3:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ +error: aborting due to 5 previous errors diff --git a/src/test/ui/lint/lint-unconditional-recursion.rs b/src/test/ui/lint/lint-unconditional-recursion.rs index 44af1179097ed..ab60a326cd220 100644 --- a/src/test/ui/lint/lint-unconditional-recursion.rs +++ b/src/test/ui/lint/lint-unconditional-recursion.rs @@ -39,7 +39,7 @@ trait Foo { } } -impl Foo for Box { +impl Foo for Box { fn bar(&self) { //~ ERROR function cannot return without recursing loop { self.bar() @@ -67,7 +67,7 @@ trait Foo2 { } } -impl Foo2 for Box { +impl Foo2 for Box { fn bar(&self) { //~ ERROR function cannot return without recursing loop { Foo2::bar(self) diff --git a/src/test/ui/lint/lint-unconditional-recursion.stderr b/src/test/ui/lint/lint-unconditional-recursion.stderr index 50daa537591b3..5d2e8201b142d 100644 --- a/src/test/ui/lint/lint-unconditional-recursion.stderr +++ b/src/test/ui/lint/lint-unconditional-recursion.stderr @@ -1,7 +1,7 @@ error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:4:1 | -LL | fn foo() { //~ ERROR function cannot return without recursing +LL | fn foo() { | ^^^^^^^^ cannot return without recursing LL | foo(); | ----- recursive call site @@ -16,7 +16,7 @@ LL | #![deny(unconditional_recursion)] error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:14:1 | -LL | fn baz() { //~ ERROR function cannot return without recursing +LL | fn baz() { | ^^^^^^^^ cannot return without recursing LL | if true { LL | baz() @@ -30,7 +30,7 @@ LL | baz() error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:26:1 | -LL | fn quz() -> bool { //~ ERROR function cannot return without recursing +LL | fn quz() -> bool { | ^^^^^^^^^^^^^^^^ cannot return without recursing LL | if true { LL | while quz() {} @@ -44,7 +44,7 @@ LL | loop { quz(); } error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:37:5 | -LL | fn bar(&self) { //~ ERROR function cannot return without recursing +LL | fn bar(&self) { | ^^^^^^^^^^^^^ cannot return without recursing LL | self.bar() | ---------- recursive call site @@ -54,7 +54,7 @@ LL | self.bar() error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:43:5 | -LL | fn bar(&self) { //~ ERROR function cannot return without recursing +LL | fn bar(&self) { | ^^^^^^^^^^^^^ cannot return without recursing LL | loop { LL | self.bar() @@ -65,7 +65,7 @@ LL | self.bar() error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:52:5 | -LL | fn bar(&self) { //~ ERROR function cannot return without recursing +LL | fn bar(&self) { | ^^^^^^^^^^^^^ cannot return without recursing LL | 0.bar() | ------- recursive call site @@ -75,7 +75,7 @@ LL | 0.bar() error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:65:5 | -LL | fn bar(&self) { //~ ERROR function cannot return without recursing +LL | fn bar(&self) { | ^^^^^^^^^^^^^ cannot return without recursing LL | Foo2::bar(self) | --------------- recursive call site @@ -85,7 +85,7 @@ LL | Foo2::bar(self) error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:71:5 | -LL | fn bar(&self) { //~ ERROR function cannot return without recursing +LL | fn bar(&self) { | ^^^^^^^^^^^^^ cannot return without recursing LL | loop { LL | Foo2::bar(self) @@ -96,7 +96,7 @@ LL | Foo2::bar(self) error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:81:5 | -LL | fn qux(&self) { //~ ERROR function cannot return without recursing +LL | fn qux(&self) { | ^^^^^^^^^^^^^ cannot return without recursing LL | self.qux(); | ---------- recursive call site @@ -106,7 +106,7 @@ LL | self.qux(); error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:86:5 | -LL | fn as_ref(&self) -> &Self { //~ ERROR function cannot return without recursing +LL | fn as_ref(&self) -> &Self { | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing LL | Baz::as_ref(self) | ----------------- recursive call site @@ -116,7 +116,7 @@ LL | Baz::as_ref(self) error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:93:5 | -LL | fn default() -> Baz { //~ ERROR function cannot return without recursing +LL | fn default() -> Baz { | ^^^^^^^^^^^^^^^^^^^ cannot return without recursing LL | let x = Default::default(); | ------------------ recursive call site @@ -126,7 +126,7 @@ LL | let x = Default::default(); error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:102:5 | -LL | fn deref(&self) -> &() { //~ ERROR function cannot return without recursing +LL | fn deref(&self) -> &() { | ^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing LL | &**self | ------ recursive call site @@ -136,7 +136,7 @@ LL | &**self error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:109:5 | -LL | fn index(&self, x: usize) -> &Baz { //~ ERROR function cannot return without recursing +LL | fn index(&self, x: usize) -> &Baz { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing LL | &self[x] | ------- recursive call site @@ -146,7 +146,7 @@ LL | &self[x] error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:118:5 | -LL | fn deref(&self) -> &Baz { //~ ERROR function cannot return without recursing +LL | fn deref(&self) -> &Baz { | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing LL | self.as_ref() | ---- recursive call site diff --git a/src/test/ui/lint/lint-unexported-no-mangle.stderr b/src/test/ui/lint/lint-unexported-no-mangle.stderr index f6a1087635afd..586ee8ed411c0 100644 --- a/src/test/ui/lint/lint-unexported-no-mangle.stderr +++ b/src/test/ui/lint/lint-unexported-no-mangle.stderr @@ -9,7 +9,7 @@ warning: lint `private_no_mangle_statics` has been removed: `no longer a warning error: const items should never be #[no_mangle] --> $DIR/lint-unexported-no-mangle.rs:9:1 | -LL | const FOO: u64 = 1; //~ ERROR const items should never be #[no_mangle] +LL | const FOO: u64 = 1; | -----^^^^^^^^^^^^^^ | | | help: try a static value: `pub static` @@ -19,7 +19,7 @@ LL | const FOO: u64 = 1; //~ ERROR const items should never be #[no_mangle] error: const items should never be #[no_mangle] --> $DIR/lint-unexported-no-mangle.rs:12:1 | -LL | pub const PUB_FOO: u64 = 1; //~ ERROR const items should never be #[no_mangle] +LL | pub const PUB_FOO: u64 = 1; | ---------^^^^^^^^^^^^^^^^^^ | | | help: try a static value: `pub static` diff --git a/src/test/ui/lint/lint-unknown-attr.rs b/src/test/ui/lint/lint-unknown-attr.rs deleted file mode 100644 index 828b869c12e23..0000000000000 --- a/src/test/ui/lint/lint-unknown-attr.rs +++ /dev/null @@ -1,11 +0,0 @@ -// When denying at the crate level, be sure to not get random warnings from the -// injected intrinsics by the compiler. - -#![feature(custom_attribute)] -#![deny(unused_attributes)] - -#![mutable_doc] //~ ERROR unused attribute - -#[dance] mod a {} //~ ERROR unused attribute - -#[dance] fn main() {} //~ ERROR unused attribute diff --git a/src/test/ui/lint/lint-unknown-attr.stderr b/src/test/ui/lint/lint-unknown-attr.stderr deleted file mode 100644 index 435b03b1f658d..0000000000000 --- a/src/test/ui/lint/lint-unknown-attr.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: unused attribute - --> $DIR/lint-unknown-attr.rs:9:1 - | -LL | #[dance] mod a {} //~ ERROR unused attribute - | ^^^^^^^^ - | -note: lint level defined here - --> $DIR/lint-unknown-attr.rs:5:9 - | -LL | #![deny(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ - -error: unused attribute - --> $DIR/lint-unknown-attr.rs:11:1 - | -LL | #[dance] fn main() {} //~ ERROR unused attribute - | ^^^^^^^^ - -error: unused attribute - --> $DIR/lint-unknown-attr.rs:7:1 - | -LL | #![mutable_doc] //~ ERROR unused attribute - | ^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/src/test/ui/lint/lint-unknown-lint.stderr b/src/test/ui/lint/lint-unknown-lint.stderr index 976c88c11d0c9..b3ba6e31bc1ea 100644 --- a/src/test/ui/lint/lint-unknown-lint.stderr +++ b/src/test/ui/lint/lint-unknown-lint.stderr @@ -1,7 +1,7 @@ error: unknown lint: `not_a_real_lint` --> $DIR/lint-unknown-lint.rs:3:10 | -LL | #![allow(not_a_real_lint)] //~ ERROR unknown lint +LL | #![allow(not_a_real_lint)] | ^^^^^^^^^^^^^^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unknown_lints)] error: unknown lint: `dead_cod` --> $DIR/lint-unknown-lint.rs:5:9 | -LL | #![deny(dead_cod)] //~ ERROR unknown lint +LL | #![deny(dead_cod)] | ^^^^^^^^ help: did you mean: `dead_code` error: aborting due to 2 previous errors diff --git a/src/test/ui/lint/lint-unnecessary-import-braces.stderr b/src/test/ui/lint/lint-unnecessary-import-braces.stderr index 40e7ab4dd1392..41e274bc54508 100644 --- a/src/test/ui/lint/lint-unnecessary-import-braces.stderr +++ b/src/test/ui/lint/lint-unnecessary-import-braces.stderr @@ -1,7 +1,7 @@ error: braces around A is unnecessary --> $DIR/lint-unnecessary-import-braces.rs:3:1 | -LL | use test::{A}; //~ ERROR braces around A is unnecessary +LL | use test::{A}; | ^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/lint/lint-unnecessary-parens.rs b/src/test/ui/lint/lint-unnecessary-parens.rs index dc74d69bd8d54..c36101043a7f7 100644 --- a/src/test/ui/lint/lint-unnecessary-parens.rs +++ b/src/test/ui/lint/lint-unnecessary-parens.rs @@ -22,8 +22,8 @@ fn main() { match (true) { //~ ERROR unnecessary parentheses around `match` head expression _ => {} } - if let 1 = (1) {} //~ ERROR unnecessary parentheses around `if let` head expression - while let 1 = (2) {} //~ ERROR unnecessary parentheses around `while let` head expression + if let 1 = (1) {} //~ ERROR unnecessary parentheses around `let` head expression + while let 1 = (2) {} //~ ERROR unnecessary parentheses around `let` head expression let v = X { y: false }; // struct lits needs parens, so these shouldn't warn. if (v == X { y: true }) {} diff --git a/src/test/ui/lint/lint-unnecessary-parens.stderr b/src/test/ui/lint/lint-unnecessary-parens.stderr index c14ebb6be9761..dfbefd7b03ee5 100644 --- a/src/test/ui/lint/lint-unnecessary-parens.stderr +++ b/src/test/ui/lint/lint-unnecessary-parens.stderr @@ -1,7 +1,7 @@ error: unnecessary parentheses around `return` value --> $DIR/lint-unnecessary-parens.rs:10:12 | -LL | return (1); //~ ERROR unnecessary parentheses around `return` value +LL | return (1); | ^^^ help: remove these parentheses | note: lint level defined here @@ -13,67 +13,67 @@ LL | #![deny(unused_parens)] error: unnecessary parentheses around `return` value --> $DIR/lint-unnecessary-parens.rs:13:12 | -LL | return (X { y }); //~ ERROR unnecessary parentheses around `return` value +LL | return (X { y }); | ^^^^^^^^^ help: remove these parentheses error: unnecessary parentheses around function argument --> $DIR/lint-unnecessary-parens.rs:18:9 | -LL | bar((true)); //~ ERROR unnecessary parentheses around function argument +LL | bar((true)); | ^^^^^^ help: remove these parentheses error: unnecessary parentheses around `if` condition --> $DIR/lint-unnecessary-parens.rs:20:8 | -LL | if (true) {} //~ ERROR unnecessary parentheses around `if` condition +LL | if (true) {} | ^^^^^^ help: remove these parentheses error: unnecessary parentheses around `while` condition --> $DIR/lint-unnecessary-parens.rs:21:11 | -LL | while (true) {} //~ ERROR unnecessary parentheses around `while` condition +LL | while (true) {} | ^^^^^^ help: remove these parentheses error: unnecessary parentheses around `match` head expression --> $DIR/lint-unnecessary-parens.rs:22:11 | -LL | match (true) { //~ ERROR unnecessary parentheses around `match` head expression +LL | match (true) { | ^^^^^^ help: remove these parentheses -error: unnecessary parentheses around `if let` head expression +error: unnecessary parentheses around `let` head expression --> $DIR/lint-unnecessary-parens.rs:25:16 | -LL | if let 1 = (1) {} //~ ERROR unnecessary parentheses around `if let` head expression +LL | if let 1 = (1) {} | ^^^ help: remove these parentheses -error: unnecessary parentheses around `while let` head expression +error: unnecessary parentheses around `let` head expression --> $DIR/lint-unnecessary-parens.rs:26:19 | -LL | while let 1 = (2) {} //~ ERROR unnecessary parentheses around `while let` head expression +LL | while let 1 = (2) {} | ^^^ help: remove these parentheses error: unnecessary parentheses around method argument --> $DIR/lint-unnecessary-parens.rs:40:24 | -LL | X { y: false }.foo((true)); //~ ERROR unnecessary parentheses around method argument +LL | X { y: false }.foo((true)); | ^^^^^^ help: remove these parentheses error: unnecessary parentheses around assigned value --> $DIR/lint-unnecessary-parens.rs:42:18 | -LL | let mut _a = (0); //~ ERROR unnecessary parentheses around assigned value +LL | let mut _a = (0); | ^^^ help: remove these parentheses error: unnecessary parentheses around assigned value --> $DIR/lint-unnecessary-parens.rs:43:10 | -LL | _a = (0); //~ ERROR unnecessary parentheses around assigned value +LL | _a = (0); | ^^^ help: remove these parentheses error: unnecessary parentheses around assigned value --> $DIR/lint-unnecessary-parens.rs:44:11 | -LL | _a += (1); //~ ERROR unnecessary parentheses around assigned value +LL | _a += (1); | ^^^ help: remove these parentheses error: aborting due to 12 previous errors diff --git a/src/test/ui/lint/lint-unsafe-code.stderr b/src/test/ui/lint/lint-unsafe-code.stderr index e2dd45e2c8a31..96ad0c33691db 100644 --- a/src/test/ui/lint/lint-unsafe-code.stderr +++ b/src/test/ui/lint/lint-unsafe-code.stderr @@ -1,7 +1,7 @@ error: declaration of an `unsafe` function --> $DIR/lint-unsafe-code.rs:23:1 | -LL | unsafe fn baz() {} //~ ERROR: declaration of an `unsafe` function +LL | unsafe fn baz() {} | ^^^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -13,79 +13,79 @@ LL | #![deny(unsafe_code)] error: declaration of an `unsafe` trait --> $DIR/lint-unsafe-code.rs:24:1 | -LL | unsafe trait Foo {} //~ ERROR: declaration of an `unsafe` trait +LL | unsafe trait Foo {} | ^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` trait --> $DIR/lint-unsafe-code.rs:25:1 | -LL | unsafe impl Foo for Bar {} //~ ERROR: implementation of an `unsafe` trait +LL | unsafe impl Foo for Bar {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: declaration of an `unsafe` method --> $DIR/lint-unsafe-code.rs:28:5 | -LL | unsafe fn baz(&self); //~ ERROR: declaration of an `unsafe` method +LL | unsafe fn baz(&self); | ^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method --> $DIR/lint-unsafe-code.rs:29:5 | -LL | unsafe fn provided(&self) {} //~ ERROR: implementation of an `unsafe` method +LL | unsafe fn provided(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method --> $DIR/lint-unsafe-code.rs:30:5 | -LL | unsafe fn provided_override(&self) {} //~ ERROR: implementation of an `unsafe` method +LL | unsafe fn provided_override(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method --> $DIR/lint-unsafe-code.rs:34:5 | -LL | unsafe fn baz(&self) {} //~ ERROR: implementation of an `unsafe` method +LL | unsafe fn baz(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method --> $DIR/lint-unsafe-code.rs:35:5 | -LL | unsafe fn provided_override(&self) {} //~ ERROR: implementation of an `unsafe` method +LL | unsafe fn provided_override(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method --> $DIR/lint-unsafe-code.rs:54:5 | -LL | unsafe fn provided_override(&self) {} //~ ERROR: implementation of an `unsafe` method +LL | unsafe fn provided_override(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method --> $DIR/lint-unsafe-code.rs:65:5 | -LL | unsafe fn provided(&self) {} //~ ERROR: implementation of an `unsafe` method +LL | unsafe fn provided(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method --> $DIR/lint-unsafe-code.rs:71:5 | -LL | unsafe fn provided(&self) {} //~ ERROR: implementation of an `unsafe` method +LL | unsafe fn provided(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method --> $DIR/lint-unsafe-code.rs:75:5 | -LL | unsafe fn baz(&self) {} //~ ERROR: implementation of an `unsafe` method +LL | unsafe fn baz(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^ error: usage of an `unsafe` block --> $DIR/lint-unsafe-code.rs:86:5 | -LL | unsafe {} //~ ERROR: usage of an `unsafe` block +LL | unsafe {} | ^^^^^^^^^ error: usage of an `unsafe` block --> $DIR/lint-unsafe-code.rs:19:9 | -LL | unsafe {} //~ ERROR: usage of an `unsafe` block +LL | unsafe {} | ^^^^^^^^^ ... LL | unsafe_in_macro!() diff --git a/src/test/ui/lint/lint-unused-extern-crate.stderr b/src/test/ui/lint/lint-unused-extern-crate.stderr index 46499515fa751..aa4a8dad24c94 100644 --- a/src/test/ui/lint/lint-unused-extern-crate.stderr +++ b/src/test/ui/lint/lint-unused-extern-crate.stderr @@ -1,7 +1,7 @@ error: unused extern crate --> $DIR/lint-unused-extern-crate.rs:11:1 | -LL | extern crate lint_unused_extern_crate5; //~ ERROR: unused extern crate +LL | extern crate lint_unused_extern_crate5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unused_extern_crates)] error: unused extern crate --> $DIR/lint-unused-extern-crate.rs:29:5 | -LL | extern crate lint_unused_extern_crate2; //~ ERROR unused extern crate +LL | extern crate lint_unused_extern_crate2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it error: aborting due to 2 previous errors diff --git a/src/test/ui/lint/lint-unused-imports.rs b/src/test/ui/lint/lint-unused-imports.rs index 9c5b206203c1d..4754d8880763a 100644 --- a/src/test/ui/lint/lint-unused-imports.rs +++ b/src/test/ui/lint/lint-unused-imports.rs @@ -66,6 +66,7 @@ mod bar { fn g() { use self::g; //~ ERROR unused import: `self::g` + //~^ ERROR the item `g` is imported redundantly fn f() { self::g(); } @@ -75,6 +76,7 @@ fn g() { #[allow(unused_variables)] fn h() { use test2::foo; //~ ERROR unused import: `test2::foo` + //~^ ERROR the item `foo` is imported redundantly let foo = 0; } diff --git a/src/test/ui/lint/lint-unused-imports.stderr b/src/test/ui/lint/lint-unused-imports.stderr index 18f2fae0067eb..96d71a228a5f2 100644 --- a/src/test/ui/lint/lint-unused-imports.stderr +++ b/src/test/ui/lint/lint-unused-imports.stderr @@ -19,38 +19,60 @@ LL | use std::option::Option::{Some, None}; error: unused import: `test::A` --> $DIR/lint-unused-imports.rs:15:5 | -LL | use test::A; //~ ERROR unused import: `test::A` +LL | use test::A; | ^^^^^^^ error: unused import: `bar` --> $DIR/lint-unused-imports.rs:24:18 | -LL | use test2::{foo, bar}; //~ ERROR unused import: `bar` +LL | use test2::{foo, bar}; | ^^^ error: unused import: `foo::Square` --> $DIR/lint-unused-imports.rs:52:13 | -LL | use foo::Square; //~ ERROR unused import: `foo::Square` +LL | use foo::Square; | ^^^^^^^^^^^ +error: the item `g` is imported redundantly + --> $DIR/lint-unused-imports.rs:68:9 + | +LL | / fn g() { +LL | | use self::g; + | | ^^^^^^^ +LL | | +LL | | fn f() { +LL | | self::g(); +LL | | } +LL | | } + | |_- the item `g` is already defined here + error: unused import: `self::g` --> $DIR/lint-unused-imports.rs:68:9 | -LL | use self::g; //~ ERROR unused import: `self::g` +LL | use self::g; | ^^^^^^^ +error: the item `foo` is imported redundantly + --> $DIR/lint-unused-imports.rs:78:9 + | +LL | use test2::{foo, bar}; + | --- the item `foo` is already imported here +... +LL | use test2::foo; + | ^^^^^^^^^^ + error: unused import: `test2::foo` - --> $DIR/lint-unused-imports.rs:77:9 + --> $DIR/lint-unused-imports.rs:78:9 | -LL | use test2::foo; //~ ERROR unused import: `test2::foo` +LL | use test2::foo; | ^^^^^^^^^^ error: unused import: `test::B2` --> $DIR/lint-unused-imports.rs:20:5 | -LL | use test::B2; //~ ERROR unused import: `test::B2` +LL | use test::B2; | ^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors diff --git a/src/test/ui/lint/lint-unused-mut-self.stderr b/src/test/ui/lint/lint-unused-mut-self.stderr index 62be0c8f159c6..b5f6b717dc39c 100644 --- a/src/test/ui/lint/lint-unused-mut-self.stderr +++ b/src/test/ui/lint/lint-unused-mut-self.stderr @@ -1,7 +1,7 @@ error: variable does not need to be mutable --> $DIR/lint-unused-mut-self.rs:8:12 | -LL | fn foo(mut self) {} //~ ERROR: variable does not need to be mutable +LL | fn foo(mut self) {} | ----^^^^ | | | help: remove this `mut` @@ -15,7 +15,7 @@ LL | #![deny(unused_mut)] error: variable does not need to be mutable --> $DIR/lint-unused-mut-self.rs:9:12 | -LL | fn bar(mut self: Box) {} //~ ERROR: variable does not need to be mutable +LL | fn bar(mut self: Box) {} | ----^^^^ | | | help: remove this `mut` diff --git a/src/test/ui/lint/lint-unused-mut-variables.rs b/src/test/ui/lint/lint-unused-mut-variables.rs index da0236ac45070..78609a6e24b5e 100644 --- a/src/test/ui/lint/lint-unused-mut-variables.rs +++ b/src/test/ui/lint/lint-unused-mut-variables.rs @@ -105,6 +105,14 @@ fn main() { _ => {} } + // Attribute should be respected on match arms + match 0 { + #[allow(unused_mut)] + mut x => { + let mut y = 1; + }, + } + let x = |mut y: isize| y = 32; fn nothing(mut foo: isize) { foo = 37; } diff --git a/src/test/ui/lint/lint-unused-mut-variables.stderr b/src/test/ui/lint/lint-unused-mut-variables.stderr index a90cc964a84dd..1a175c9683ec7 100644 --- a/src/test/ui/lint/lint-unused-mut-variables.stderr +++ b/src/test/ui/lint/lint-unused-mut-variables.stderr @@ -1,7 +1,7 @@ error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:46:14 | -LL | let x = |mut y: isize| 10; //~ ERROR: variable does not need to be mutable +LL | let x = |mut y: isize| 10; | ----^ | | | help: remove this `mut` @@ -15,7 +15,7 @@ LL | #![deny(unused_mut)] error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:11:9 | -LL | let mut a = 3; //~ ERROR: variable does not need to be mutable +LL | let mut a = 3; | ----^ | | | help: remove this `mut` @@ -23,7 +23,7 @@ LL | let mut a = 3; //~ ERROR: variable does not need to be mutable error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:13:9 | -LL | let mut a = 2; //~ ERROR: variable does not need to be mutable +LL | let mut a = 2; | ----^ | | | help: remove this `mut` @@ -31,7 +31,7 @@ LL | let mut a = 2; //~ ERROR: variable does not need to be mutable error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:15:9 | -LL | let mut b = 3; //~ ERROR: variable does not need to be mutable +LL | let mut b = 3; | ----^ | | | help: remove this `mut` @@ -39,7 +39,7 @@ LL | let mut b = 3; //~ ERROR: variable does not need to be mutable error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:17:9 | -LL | let mut a = vec![3]; //~ ERROR: variable does not need to be mutable +LL | let mut a = vec![3]; | ----^ | | | help: remove this `mut` @@ -47,7 +47,7 @@ LL | let mut a = vec![3]; //~ ERROR: variable does not need to be mutable error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:19:10 | -LL | let (mut a, b) = (1, 2); //~ ERROR: variable does not need to be mutable +LL | let (mut a, b) = (1, 2); | ----^ | | | help: remove this `mut` @@ -55,7 +55,7 @@ LL | let (mut a, b) = (1, 2); //~ ERROR: variable does not need to be mutabl error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:21:9 | -LL | let mut a; //~ ERROR: variable does not need to be mutable +LL | let mut a; | ----^ | | | help: remove this `mut` @@ -63,7 +63,7 @@ LL | let mut a; //~ ERROR: variable does not need to be mutable error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:25:9 | -LL | let mut b; //~ ERROR: variable does not need to be mutable +LL | let mut b; | ----^ | | | help: remove this `mut` @@ -71,7 +71,7 @@ LL | let mut b; //~ ERROR: variable does not need to be mutable error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:34:9 | -LL | mut x => {} //~ ERROR: variable does not need to be mutable +LL | mut x => {} | ----^ | | | help: remove this `mut` @@ -79,7 +79,7 @@ LL | mut x => {} //~ ERROR: variable does not need to be mutable error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:38:8 | -LL | (mut x, 1) | //~ ERROR: variable does not need to be mutable +LL | (mut x, 1) | | ----^ | | | help: remove this `mut` @@ -87,7 +87,7 @@ LL | (mut x, 1) | //~ ERROR: variable does not need to be mutable error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:51:9 | -LL | let mut a = &mut 5; //~ ERROR: variable does not need to be mutable +LL | let mut a = &mut 5; | ----^ | | | help: remove this `mut` @@ -95,7 +95,7 @@ LL | let mut a = &mut 5; //~ ERROR: variable does not need to be mutable error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:56:9 | -LL | let mut b = (&mut a,); //~ ERROR: variable does not need to be mutable +LL | let mut b = (&mut a,); | ----^ | | | help: remove this `mut` @@ -103,7 +103,7 @@ LL | let mut b = (&mut a,); //~ ERROR: variable does not need to be mutable error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:59:9 | -LL | let mut x = &mut 1; //~ ERROR: variable does not need to be mutable +LL | let mut x = &mut 1; | ----^ | | | help: remove this `mut` @@ -111,7 +111,7 @@ LL | let mut x = &mut 1; //~ ERROR: variable does not need to be mutable error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:71:9 | -LL | let mut v : &mut Vec<()> = &mut vec![]; //~ ERROR: variable does not need to be mutable +LL | let mut v : &mut Vec<()> = &mut vec![]; | ----^ | | | help: remove this `mut` @@ -119,7 +119,7 @@ LL | let mut v : &mut Vec<()> = &mut vec![]; //~ ERROR: variable does not ne error: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:48:13 | -LL | fn what(mut foo: isize) {} //~ ERROR: variable does not need to be mutable +LL | fn what(mut foo: isize) {} | ----^^^ | | | help: remove this `mut` @@ -133,15 +133,15 @@ LL | fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] { | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:130:9 + --> $DIR/lint-unused-mut-variables.rs:138:9 | -LL | let mut b = vec![2]; //~ ERROR: variable does not need to be mutable +LL | let mut b = vec![2]; | ----^ | | | help: remove this `mut` | note: lint level defined here - --> $DIR/lint-unused-mut-variables.rs:126:8 + --> $DIR/lint-unused-mut-variables.rs:134:8 | LL | #[deny(unused_mut)] | ^^^^^^^^^^ diff --git a/src/test/ui/lint/lint-uppercase-variables.stderr b/src/test/ui/lint/lint-uppercase-variables.stderr index f2267f351ddda..40c13231c1823 100644 --- a/src/test/ui/lint/lint-uppercase-variables.stderr +++ b/src/test/ui/lint/lint-uppercase-variables.stderr @@ -20,7 +20,7 @@ LL | #![warn(unused)] error: structure field `X` should have a snake case name --> $DIR/lint-uppercase-variables.rs:10:5 | -LL | X: usize //~ ERROR structure field `X` should have a snake case name +LL | X: usize | ^ help: convert the identifier to snake case: `x` | note: lint level defined here @@ -32,13 +32,13 @@ LL | #![deny(non_snake_case)] error: variable `Xx` should have a snake case name --> $DIR/lint-uppercase-variables.rs:13:9 | -LL | fn test(Xx: usize) { //~ ERROR variable `Xx` should have a snake case name +LL | fn test(Xx: usize) { | ^^ help: convert the identifier to snake case: `xx` error: variable `Test` should have a snake case name --> $DIR/lint-uppercase-variables.rs:18:9 | -LL | let Test: usize = 0; //~ ERROR variable `Test` should have a snake case name +LL | let Test: usize = 0; | ^^^^ help: convert the identifier to snake case: `test` error: variable `Foo` should have a snake case name diff --git a/src/test/ui/lint/lints-in-foreign-macros.stderr b/src/test/ui/lint/lints-in-foreign-macros.stderr index 8287ca5692bd9..3fc3c2281f2e3 100644 --- a/src/test/ui/lint/lints-in-foreign-macros.stderr +++ b/src/test/ui/lint/lints-in-foreign-macros.stderr @@ -1,7 +1,7 @@ warning: unused import: `std::string::ToString` --> $DIR/lints-in-foreign-macros.rs:11:16 | -LL | () => {use std::string::ToString;} //~ WARN: unused import +LL | () => {use std::string::ToString;} | ^^^^^^^^^^^^^^^^^^^^^ ... LL | mod a { foo!(); } @@ -10,25 +10,25 @@ LL | mod a { foo!(); } note: lint level defined here --> $DIR/lints-in-foreign-macros.rs:4:9 | -LL | #![warn(unused_imports)] //~ missing documentation for crate [missing_docs] +LL | #![warn(unused_imports)] | ^^^^^^^^^^^^^^ warning: unused import: `std::string::ToString` --> $DIR/lints-in-foreign-macros.rs:16:18 | -LL | mod c { baz!(use std::string::ToString;); } //~ WARN: unused import +LL | mod c { baz!(use std::string::ToString;); } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused import: `std::string::ToString` --> $DIR/lints-in-foreign-macros.rs:17:19 | -LL | mod d { baz2!(use std::string::ToString;); } //~ WARN: unused import +LL | mod d { baz2!(use std::string::ToString;); } | ^^^^^^^^^^^^^^^^^^^^^ warning: missing documentation for crate --> $DIR/lints-in-foreign-macros.rs:4:1 | -LL | / #![warn(unused_imports)] //~ missing documentation for crate [missing_docs] +LL | / #![warn(unused_imports)] LL | | #![warn(missing_docs)] LL | | LL | | #[macro_use] @@ -46,12 +46,12 @@ LL | #![warn(missing_docs)] warning: missing documentation for a function --> $DIR/lints-in-foreign-macros.rs:18:6 | -LL | baz!(pub fn undocumented() {}); //~ WARN: missing documentation for a function +LL | baz!(pub fn undocumented() {}); | ^^^^^^^^^^^^^^^^^^^^^ warning: missing documentation for a function --> $DIR/lints-in-foreign-macros.rs:19:7 | -LL | baz2!(pub fn undocumented2() {}); //~ WARN: missing documentation for a function +LL | baz2!(pub fn undocumented2() {}); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/lint/must_use-array.rs b/src/test/ui/lint/must_use-array.rs new file mode 100644 index 0000000000000..97825dd2f6c43 --- /dev/null +++ b/src/test/ui/lint/must_use-array.rs @@ -0,0 +1,47 @@ +#![deny(unused_must_use)] + +#[must_use] +struct S; + +struct A; + +#[must_use] +trait T {} + +impl T for A {} + +fn empty() -> [S; 0] { + [] +} + +fn singleton() -> [S; 1] { + [S] +} + +fn many() -> [S; 4] { + [S, S, S, S] +} + +fn array_of_impl_trait() -> [impl T; 2] { + [A, A] +} + +fn impl_array() -> [(u8, Box); 2] { + [(0, Box::new(A)), (0, Box::new(A))] +} + +fn array_of_arrays_of_arrays() -> [[[S; 1]; 2]; 1] { + [[[S], [S]]] +} + +fn main() { + empty(); // ok + singleton(); //~ ERROR unused array of `S` that must be used + many(); //~ ERROR unused array of `S` that must be used + ([S], 0, ()); //~ ERROR unused array of `S` in tuple element 0 that must be used + array_of_impl_trait(); //~ ERROR unused array of implementers of `T` that must be used + impl_array(); + //~^ ERROR unused array of boxed `T` trait objects in tuple element 1 that must be used + array_of_arrays_of_arrays(); + //~^ ERROR unused array of arrays of arrays of `S` that must be used +} diff --git a/src/test/ui/lint/must_use-array.stderr b/src/test/ui/lint/must_use-array.stderr new file mode 100644 index 0000000000000..a6dbd8e93d4d3 --- /dev/null +++ b/src/test/ui/lint/must_use-array.stderr @@ -0,0 +1,44 @@ +error: unused array of `S` that must be used + --> $DIR/must_use-array.rs:39:5 + | +LL | singleton(); + | ^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/must_use-array.rs:1:9 + | +LL | #![deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ + +error: unused array of `S` that must be used + --> $DIR/must_use-array.rs:40:5 + | +LL | many(); + | ^^^^^^^ + +error: unused array of `S` in tuple element 0 that must be used + --> $DIR/must_use-array.rs:41:6 + | +LL | ([S], 0, ()); + | ^^^ + +error: unused array of implementers of `T` that must be used + --> $DIR/must_use-array.rs:42:5 + | +LL | array_of_impl_trait(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: unused array of boxed `T` trait objects in tuple element 1 that must be used + --> $DIR/must_use-array.rs:43:5 + | +LL | impl_array(); + | ^^^^^^^^^^^^^ + +error: unused array of arrays of arrays of `S` that must be used + --> $DIR/must_use-array.rs:45:5 + | +LL | array_of_arrays_of_arrays(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/lint/must_use-trait.rs b/src/test/ui/lint/must_use-trait.rs index 23df4fa6132d3..0aa751443a080 100644 --- a/src/test/ui/lint/must_use-trait.rs +++ b/src/test/ui/lint/must_use-trait.rs @@ -17,6 +17,23 @@ fn get_critical() -> impl NotSoCritical + Critical + DecidedlyUnimportant { Anon {} } +fn get_boxed_critical() -> Box { + Box::new(Anon {}) +} + +fn get_nested_boxed_critical() -> Box> { + Box::new(Box::new(Anon {})) +} + +fn get_critical_tuple() -> (u32, Box, impl Critical, ()) { + (0, get_boxed_critical(), get_critical(), ()) +} + fn main() { get_critical(); //~ ERROR unused implementer of `Critical` that must be used + get_boxed_critical(); //~ ERROR unused boxed `Critical` trait object that must be used + get_nested_boxed_critical(); + //~^ ERROR unused boxed boxed `Critical` trait object that must be used + get_critical_tuple(); //~ ERROR unused boxed `Critical` trait object in tuple element 1 + //~^ ERROR unused implementer of `Critical` in tuple element 2 } diff --git a/src/test/ui/lint/must_use-trait.stderr b/src/test/ui/lint/must_use-trait.stderr index 94f5f4f40d2d5..be74362e29d62 100644 --- a/src/test/ui/lint/must_use-trait.stderr +++ b/src/test/ui/lint/must_use-trait.stderr @@ -1,7 +1,7 @@ error: unused implementer of `Critical` that must be used - --> $DIR/must_use-trait.rs:21:5 + --> $DIR/must_use-trait.rs:33:5 | -LL | get_critical(); //~ ERROR unused implementer of `Critical` that must be used +LL | get_critical(); | ^^^^^^^^^^^^^^^ | note: lint level defined here @@ -10,5 +10,29 @@ note: lint level defined here LL | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: unused boxed `Critical` trait object that must be used + --> $DIR/must_use-trait.rs:34:5 + | +LL | get_boxed_critical(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: unused boxed boxed `Critical` trait object that must be used + --> $DIR/must_use-trait.rs:35:5 + | +LL | get_nested_boxed_critical(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unused boxed `Critical` trait object in tuple element 1 that must be used + --> $DIR/must_use-trait.rs:37:5 + | +LL | get_critical_tuple(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: unused implementer of `Critical` in tuple element 2 that must be used + --> $DIR/must_use-trait.rs:37:5 + | +LL | get_critical_tuple(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors diff --git a/src/test/ui/lint/must_use-tuple.rs b/src/test/ui/lint/must_use-tuple.rs new file mode 100644 index 0000000000000..f6b579a7f35cf --- /dev/null +++ b/src/test/ui/lint/must_use-tuple.rs @@ -0,0 +1,17 @@ +#![deny(unused_must_use)] + +fn foo() -> (Result<(), ()>, ()) { + (Ok::<(), ()>(()), ()) +} + +fn main() { + (Ok::<(), ()>(()),); //~ ERROR unused `std::result::Result` + + (Ok::<(), ()>(()), 0, Ok::<(), ()>(()), 5); + //~^ ERROR unused `std::result::Result` + //~^^ ERROR unused `std::result::Result` + + foo(); //~ ERROR unused `std::result::Result` + + ((Err::<(), ()>(()), ()), ()); //~ ERROR unused `std::result::Result` +} diff --git a/src/test/ui/lint/must_use-tuple.stderr b/src/test/ui/lint/must_use-tuple.stderr new file mode 100644 index 0000000000000..45d2a439e52b0 --- /dev/null +++ b/src/test/ui/lint/must_use-tuple.stderr @@ -0,0 +1,47 @@ +error: unused `std::result::Result` in tuple element 0 that must be used + --> $DIR/must_use-tuple.rs:8:6 + | +LL | (Ok::<(), ()>(()),); + | ^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/must_use-tuple.rs:1:9 + | +LL | #![deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ + = note: this `Result` may be an `Err` variant, which should be handled + +error: unused `std::result::Result` in tuple element 0 that must be used + --> $DIR/must_use-tuple.rs:10:6 + | +LL | (Ok::<(), ()>(()), 0, Ok::<(), ()>(()), 5); + | ^^^^^^^^^^^^^^^^ + | + = note: this `Result` may be an `Err` variant, which should be handled + +error: unused `std::result::Result` in tuple element 2 that must be used + --> $DIR/must_use-tuple.rs:10:27 + | +LL | (Ok::<(), ()>(()), 0, Ok::<(), ()>(()), 5); + | ^^^^^^^^^^^^^^^^ + | + = note: this `Result` may be an `Err` variant, which should be handled + +error: unused `std::result::Result` in tuple element 0 that must be used + --> $DIR/must_use-tuple.rs:14:5 + | +LL | foo(); + | ^^^^^^ + | + = note: this `Result` may be an `Err` variant, which should be handled + +error: unused `std::result::Result` in tuple element 0 that must be used + --> $DIR/must_use-tuple.rs:16:6 + | +LL | ((Err::<(), ()>(()), ()), ()); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this `Result` may be an `Err` variant, which should be handled + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/lint/must_use-unit.stderr b/src/test/ui/lint/must_use-unit.stderr index ee61c2d1dbc52..f6229c0442f99 100644 --- a/src/test/ui/lint/must_use-unit.stderr +++ b/src/test/ui/lint/must_use-unit.stderr @@ -1,7 +1,7 @@ error: unused return value of `foo` that must be used --> $DIR/must_use-unit.rs:14:5 | -LL | foo(); //~ unused return value of `foo` +LL | foo(); | ^^^^^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unused_must_use)] error: unused return value of `bar` that must be used --> $DIR/must_use-unit.rs:16:5 | -LL | bar(); //~ unused return value of `bar` +LL | bar(); | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/lint/outer-forbid.stderr b/src/test/ui/lint/outer-forbid.stderr index 57ad55a37f050..310a5d88f8c1c 100644 --- a/src/test/ui/lint/outer-forbid.stderr +++ b/src/test/ui/lint/outer-forbid.stderr @@ -4,7 +4,7 @@ error[E0453]: allow(unused_variables) overruled by outer forbid(unused) LL | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here LL | -LL | #[allow(unused_variables)] //~ ERROR overruled +LL | #[allow(unused_variables)] | ^^^^^^^^^^^^^^^^ overruled by previous forbid error[E0453]: allow(unused) overruled by outer forbid(unused) @@ -13,7 +13,7 @@ error[E0453]: allow(unused) overruled by outer forbid(unused) LL | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here ... -LL | #[allow(unused)] //~ ERROR overruled +LL | #[allow(unused)] | ^^^^^^ overruled by previous forbid error[E0453]: allow(nonstandard_style) overruled by outer forbid(non_snake_case) @@ -22,7 +22,7 @@ error[E0453]: allow(nonstandard_style) overruled by outer forbid(non_snake_case) LL | #![forbid(unused, non_snake_case)] | -------------- `forbid` level set here ... -LL | #[allow(nonstandard_style)] //~ ERROR overruled +LL | #[allow(nonstandard_style)] | ^^^^^^^^^^^^^^^^^ overruled by previous forbid error: aborting due to 3 previous errors diff --git a/src/test/ui/lint/reasons-erroneous.rs b/src/test/ui/lint/reasons-erroneous.rs index e42b329338b5a..84db885ac0949 100644 --- a/src/test/ui/lint/reasons-erroneous.rs +++ b/src/test/ui/lint/reasons-erroneous.rs @@ -2,23 +2,27 @@ #![warn(absolute_paths_not_starting_with_crate, reason = 0)] //~^ ERROR malformed lint attribute -//~| HELP reason must be a string literal +//~| NOTE reason must be a string literal #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")] //~^ ERROR malformed lint attribute -//~| HELP reason must be a string literal +//~| NOTE reason must be a string literal #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] //~^ ERROR malformed lint attribute +//~| NOTE bad attribute argument #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")] //~^ ERROR malformed lint attribute +//~| NOTE bad attribute argument #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] //~^ ERROR malformed lint attribute +//~| NOTE bad attribute argument #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] //~^ ERROR malformed lint attribute -//~| HELP reason in lint attribute must come last +//~| NOTE reason in lint attribute must come last #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)] //~^ ERROR malformed lint attribute -//~| HELP reason in lint attribute must come last +//~| NOTE reason in lint attribute must come last #![warn(missing_copy_implementations, reason)] //~^ WARN unknown lint +//~| NOTE #[warn(unknown_lints)] on by default fn main() {} diff --git a/src/test/ui/lint/reasons-erroneous.stderr b/src/test/ui/lint/reasons-erroneous.stderr index 6842686ecbab5..ff4a0f36bbda4 100644 --- a/src/test/ui/lint/reasons-erroneous.stderr +++ b/src/test/ui/lint/reasons-erroneous.stderr @@ -1,55 +1,47 @@ -error[E0452]: malformed lint attribute +error[E0452]: malformed lint attribute input --> $DIR/reasons-erroneous.rs:3:58 | LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)] - | ^ - | - = help: reason must be a string literal + | ^ reason must be a string literal -error[E0452]: malformed lint attribute +error[E0452]: malformed lint attribute input --> $DIR/reasons-erroneous.rs:6:40 | LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: reason must be a string literal + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal -error[E0452]: malformed lint attribute +error[E0452]: malformed lint attribute input --> $DIR/reasons-erroneous.rs:9:29 | LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument -error[E0452]: malformed lint attribute - --> $DIR/reasons-erroneous.rs:11:23 +error[E0452]: malformed lint attribute input + --> $DIR/reasons-erroneous.rs:12:23 | LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument -error[E0452]: malformed lint attribute - --> $DIR/reasons-erroneous.rs:13:36 +error[E0452]: malformed lint attribute input + --> $DIR/reasons-erroneous.rs:15:36 | LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument -error[E0452]: malformed lint attribute - --> $DIR/reasons-erroneous.rs:15:44 +error[E0452]: malformed lint attribute input + --> $DIR/reasons-erroneous.rs:18:44 | LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = help: reason in lint attribute must come last + | ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last -error[E0452]: malformed lint attribute - --> $DIR/reasons-erroneous.rs:18:25 +error[E0452]: malformed lint attribute input + --> $DIR/reasons-erroneous.rs:21:25 | LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: reason in lint attribute must come last + | ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last warning: unknown lint: `reason` - --> $DIR/reasons-erroneous.rs:21:39 + --> $DIR/reasons-erroneous.rs:24:39 | LL | #![warn(missing_copy_implementations, reason)] | ^^^^^^ diff --git a/src/test/ui/lint/suggestions.stderr b/src/test/ui/lint/suggestions.stderr index 1e4eabc9db0f7..5aaa9947f998a 100644 --- a/src/test/ui/lint/suggestions.stderr +++ b/src/test/ui/lint/suggestions.stderr @@ -59,12 +59,30 @@ warning: functions generic over types or consts must be mangled | LL | #[no_mangle] | ------------ help: remove this attribute -LL | //~^ HELP remove this attribute +LL | LL | pub fn defiant(_t: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: #[warn(no_mangle_generic_items)] on by default +warning: denote infinite loops with `loop { ... }` + --> $DIR/suggestions.rs:46:5 + | +LL | while true { + | ^^^^^^^^^^ help: use `loop` + | + = note: #[warn(while_true)] on by default + +warning: the `warp_factor:` in this pattern is redundant + --> $DIR/suggestions.rs:61:23 + | +LL | Equinox { warp_factor: warp_factor } => {} + | ------------^^^^^^^^^^^^ + | | + | help: remove this + | + = note: #[warn(non_shorthand_field_patterns)] on by default + error: const items should never be #[no_mangle] --> $DIR/suggestions.rs:22:18 | @@ -97,23 +115,5 @@ LL | #[no_mangle] pub(crate) fn crossfield() {} | | | help: remove this attribute -warning: denote infinite loops with `loop { ... }` - --> $DIR/suggestions.rs:46:5 - | -LL | while true { - | ^^^^^^^^^^ help: use `loop` - | - = note: #[warn(while_true)] on by default - -warning: the `warp_factor:` in this pattern is redundant - --> $DIR/suggestions.rs:61:23 - | -LL | Equinox { warp_factor: warp_factor } => {} - | ------------^^^^^^^^^^^^ - | | - | help: remove this - | - = note: #[warn(non_shorthand_field_patterns)] on by default - error: aborting due to 3 previous errors diff --git a/src/test/ui/lint/test-inner-fn.stderr b/src/test/ui/lint/test-inner-fn.stderr index 12838cec02478..bf476a45f772c 100644 --- a/src/test/ui/lint/test-inner-fn.stderr +++ b/src/test/ui/lint/test-inner-fn.stderr @@ -1,7 +1,7 @@ error: cannot test inner items --> $DIR/test-inner-fn.rs:5:5 | -LL | #[test] //~ ERROR cannot test inner items [unnameable_test_items] +LL | #[test] | ^^^^^^^ | = note: requested on the command line with `-D unnameable-test-items` @@ -9,7 +9,7 @@ LL | #[test] //~ ERROR cannot test inner items [unnameable_test_items] error: cannot test inner items --> $DIR/test-inner-fn.rs:13:9 | -LL | #[test] //~ ERROR cannot test inner items [unnameable_test_items] +LL | #[test] | ^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/lint/type-overflow.stderr b/src/test/ui/lint/type-overflow.stderr index 349d0be016497..dabfb876fbb92 100644 --- a/src/test/ui/lint/type-overflow.stderr +++ b/src/test/ui/lint/type-overflow.stderr @@ -1,7 +1,7 @@ -warning: literal out of range for i8 +warning: literal out of range for `i8` --> $DIR/type-overflow.rs:5:17 | -LL | let error = 255i8; //~WARNING literal out of range for i8 +LL | let error = 255i8; | ^^^^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![warn(overflowing_literals)] warning: literal out of range for i8 --> $DIR/type-overflow.rs:10:16 | -LL | let fail = 0b1000_0001i8; //~WARNING literal out of range for i8 +LL | let fail = 0b1000_0001i8; | ^^^^^^^^^^^^^ help: consider using `u8` instead: `0b1000_0001u8` | = note: the literal `0b1000_0001i8` (decimal `129`) does not fit into an `i8` and will become `-127i8` @@ -21,7 +21,7 @@ LL | let fail = 0b1000_0001i8; //~WARNING literal out of range for i8 warning: literal out of range for i64 --> $DIR/type-overflow.rs:12:16 | -LL | let fail = 0x8000_0000_0000_0000i64; //~WARNING literal out of range for i64 +LL | let fail = 0x8000_0000_0000_0000i64; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `u64` instead: `0x8000_0000_0000_0000u64` | = note: the literal `0x8000_0000_0000_0000i64` (decimal `9223372036854775808`) does not fit into an `i64` and will become `-9223372036854775808i64` @@ -29,7 +29,7 @@ LL | let fail = 0x8000_0000_0000_0000i64; //~WARNING literal out of range fo warning: literal out of range for u32 --> $DIR/type-overflow.rs:14:16 | -LL | let fail = 0x1_FFFF_FFFFu32; //~WARNING literal out of range for u32 +LL | let fail = 0x1_FFFF_FFFFu32; | ^^^^^^^^^^^^^^^^ help: consider using `u64` instead: `0x1_FFFF_FFFFu64` | = note: the literal `0x1_FFFF_FFFFu32` (decimal `8589934591`) does not fit into an `u32` and will become `4294967295u32` @@ -46,7 +46,7 @@ LL | let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; warning: literal out of range for i32 --> $DIR/type-overflow.rs:19:16 | -LL | let fail = 0x8FFF_FFFF_FFFF_FFFE; //~WARNING literal out of range for i32 +LL | let fail = 0x8FFF_FFFF_FFFF_FFFE; | ^^^^^^^^^^^^^^^^^^^^^ | = note: the literal `0x8FFF_FFFF_FFFF_FFFE` (decimal `10376293541461622782`) does not fit into an `i32` and will become `-2i32` @@ -55,7 +55,7 @@ LL | let fail = 0x8FFF_FFFF_FFFF_FFFE; //~WARNING literal out of range for i warning: literal out of range for i8 --> $DIR/type-overflow.rs:21:17 | -LL | let fail = -0b1111_1111i8; //~WARNING literal out of range for i8 +LL | let fail = -0b1111_1111i8; | ^^^^^^^^^^^^^ help: consider using `i16` instead: `0b1111_1111i16` | = note: the literal `0b1111_1111i8` (decimal `255`) does not fit into an `i8` and will become `-1i8` diff --git a/src/test/ui/lint/unused_import_warning_issue_45268.rs b/src/test/ui/lint/unused_import_warning_issue_45268.rs new file mode 100644 index 0000000000000..0bd7751113593 --- /dev/null +++ b/src/test/ui/lint/unused_import_warning_issue_45268.rs @@ -0,0 +1,48 @@ +// compile-pass + +#![warn(unused_imports)] // Warning explanation here, it's OK + +mod test { + pub trait A { + fn a(); + } + + impl A for () { + fn a() { } + } + + pub trait B { + fn b(self); + } + + impl B for () { + fn b(self) { } + } + + pub trait Unused { + } +} + +use test::Unused; // This is really unused, so warning is OK +use test::A; // This is used by the test2::func() through import of super::* +use test::B; // This is used by the test2::func() through import of super::* + +mod test2 { + use super::*; + pub fn func() { + let _ = <()>::a(); + let _ = ().b(); + test3::inner_func(); + } + mod test3 { + use super::*; + pub fn inner_func() { + let _ = <()>::a(); + let _ = ().b(); + } + } +} + +fn main() { + test2::func(); +} diff --git a/src/test/ui/lint/unused_import_warning_issue_45268.stderr b/src/test/ui/lint/unused_import_warning_issue_45268.stderr new file mode 100644 index 0000000000000..7392e99f7aef3 --- /dev/null +++ b/src/test/ui/lint/unused_import_warning_issue_45268.stderr @@ -0,0 +1,12 @@ +warning: unused import: `test::Unused` + --> $DIR/unused_import_warning_issue_45268.rs:26:5 + | +LL | use test::Unused; // This is really unused, so warning is OK + | ^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/unused_import_warning_issue_45268.rs:3:9 + | +LL | #![warn(unused_imports)] // Warning explanation here, it's OK + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/lint/unused_labels.stderr b/src/test/ui/lint/unused_labels.stderr index 39d0a7850efad..08f8548e0493d 100644 --- a/src/test/ui/lint/unused_labels.stderr +++ b/src/test/ui/lint/unused_labels.stderr @@ -57,7 +57,7 @@ warning: label name `'many_used_shadowed` shadows a label name that is already i | LL | 'many_used_shadowed: for _ in 0..10 { | ------------------- first declared here -LL | //~^ WARN unused label +LL | LL | 'many_used_shadowed: for _ in 0..10 { | ^^^^^^^^^^^^^^^^^^^ lifetime 'many_used_shadowed already in scope diff --git a/src/test/ui/lint/use-redundant.rs b/src/test/ui/lint/use-redundant.rs new file mode 100644 index 0000000000000..328f8232bafa8 --- /dev/null +++ b/src/test/ui/lint/use-redundant.rs @@ -0,0 +1,27 @@ +// compile-pass +#![warn(unused_imports)] + +use crate::foo::Bar; //~ WARNING first import + +mod foo { + pub type Bar = i32; +} + +fn baz() -> Bar { + 3 +} + +mod m1 { pub struct S {} } +mod m2 { pub struct S {} } + +use m1::*; +use m2::*; + +fn main() { + use crate::foo::Bar; //~ WARNING redundant import + let _a: Bar = 3; + baz(); + + use m1::S; //~ WARNING redundant import + let _s = S {}; +} diff --git a/src/test/ui/lint/use-redundant.stderr b/src/test/ui/lint/use-redundant.stderr new file mode 100644 index 0000000000000..fbd9f81f18f8a --- /dev/null +++ b/src/test/ui/lint/use-redundant.stderr @@ -0,0 +1,27 @@ +warning: unused import: `m1::*` + --> $DIR/use-redundant.rs:17:5 + | +LL | use m1::*; + | ^^^^^ + | +note: lint level defined here + --> $DIR/use-redundant.rs:2:9 + | +LL | #![warn(unused_imports)] + | ^^^^^^^^^^^^^^ + +warning: unused import: `m2::*` + --> $DIR/use-redundant.rs:18:5 + | +LL | use m2::*; + | ^^^^^ + +warning: the item `Bar` is imported redundantly + --> $DIR/use-redundant.rs:21:9 + | +LL | use crate::foo::Bar; + | --------------- the item `Bar` is already imported here +... +LL | use crate::foo::Bar; + | ^^^^^^^^^^^^^^^ + diff --git a/src/test/ui/lint/use_suggestion_json.rs b/src/test/ui/lint/use_suggestion_json.rs index 3bdbaa55f2df8..9679ce4a2ae1d 100644 --- a/src/test/ui/lint/use_suggestion_json.rs +++ b/src/test/ui/lint/use_suggestion_json.rs @@ -1,5 +1,6 @@ // ignore-cloudabi -// compile-flags: --error-format pretty-json -Zunstable-options +// ignore-windows +// compile-flags: --error-format pretty-json -Zunstable-options --json-rendered=termcolor // The output for humans should just highlight the whole span without showing // the suggested replacement, but we also want to test that suggested diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr index dee7f2f9b160b..632666db75b66 100644 --- a/src/test/ui/lint/use_suggestion_json.stderr +++ b/src/test/ui/lint/use_suggestion_json.stderr @@ -73,10 +73,10 @@ mod foo { "spans": [ { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 440, - "byte_end": 444, - "line_start": 11, - "line_end": 11, + "byte_start": 484, + "byte_end": 488, + "line_start": 12, + "line_end": 12, "column_start": 12, "column_end": 16, "is_primary": true, @@ -101,10 +101,10 @@ mod foo { "spans": [ { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 417, - "byte_end": 417, - "line_start": 10, - "line_end": 10, + "byte_start": 461, + "byte_end": 461, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -124,10 +124,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 417, - "byte_end": 417, - "line_start": 10, - "line_end": 10, + "byte_start": 461, + "byte_end": 461, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -147,10 +147,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 417, - "byte_end": 417, - "line_start": 10, - "line_end": 10, + "byte_start": 461, + "byte_end": 461, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -170,10 +170,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 417, - "byte_end": 417, - "line_start": 10, - "line_end": 10, + "byte_start": 461, + "byte_end": 461, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -193,10 +193,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 417, - "byte_end": 417, - "line_start": 10, - "line_end": 10, + "byte_start": 461, + "byte_end": 461, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -216,10 +216,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 417, - "byte_end": 417, - "line_start": 10, - "line_end": 10, + "byte_start": 461, + "byte_end": 461, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -239,10 +239,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 417, - "byte_end": 417, - "line_start": 10, - "line_end": 10, + "byte_start": 461, + "byte_end": 461, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -262,10 +262,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 417, - "byte_end": 417, - "line_start": 10, - "line_end": 10, + "byte_start": 461, + "byte_end": 461, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -285,10 +285,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 417, - "byte_end": 417, - "line_start": 10, - "line_end": 10, + "byte_start": 461, + "byte_end": 461, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -308,10 +308,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 417, - "byte_end": 417, - "line_start": 10, - "line_end": 10, + "byte_start": 461, + "byte_end": 461, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -331,10 +331,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 417, - "byte_end": 417, - "line_start": 10, - "line_end": 10, + "byte_start": 461, + "byte_end": 461, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -354,10 +354,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 417, - "byte_end": 417, - "line_start": 10, - "line_end": 10, + "byte_start": 461, + "byte_end": 461, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -380,22 +380,22 @@ mod foo { "rendered": null } ], - "rendered": "error[E0412]: cannot find type `Iter` in this scope - --> $DIR/use_suggestion_json.rs:11:12 - | -LL | let x: Iter; - | ^^^^ not found in this scope -help: possible candidates are found in other modules, you can import them into scope - | -LL | use std::collections::binary_heap::Iter; - | -LL | use std::collections::btree_map::Iter; - | -LL | use std::collections::btree_set::Iter; - | -LL | use std::collections::hash_map::Iter; - | -and 8 other candidates + "rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror[E0412]\u001b[0m\u001b[0m\u001b[1m: cannot find type `Iter` in this scope\u001b[0m +\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0m$DIR/use_suggestion_json.rs:12:12\u001b[0m +\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m +\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m let x: Iter;\u001b[0m +\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m +\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: possible candidates are found in other modules, you can import them into scope\u001b[0m +\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m +\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::binary_heap::Iter;\u001b[0m +\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m +\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::btree_map::Iter;\u001b[0m +\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m +\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::btree_set::Iter;\u001b[0m +\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m +\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::hash_map::Iter;\u001b[0m +\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m +\u001b[0mand 8 other candidates\u001b[0m " } @@ -405,7 +405,7 @@ and 8 other candidates "level": "error", "spans": [], "children": [], - "rendered": "error: aborting due to previous error + "rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror\u001b[0m\u001b[0m\u001b[1m: aborting due to previous error\u001b[0m " } @@ -415,6 +415,6 @@ and 8 other candidates "level": "", "spans": [], "children": [], - "rendered": "For more information about this error, try `rustc --explain E0412`. + "rendered": "\u001b[0m\u001b[1mFor more information about this error, try `rustc --explain E0412`.\u001b[0m " } diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.ast.nll.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.ast.nll.stderr deleted file mode 100644 index 9d24570057375..0000000000000 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.ast.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `v` - --> $DIR/liveness-assign-imm-local-in-loop.rs:9:9 - | -LL | let v: isize; - | - help: make this binding mutable: `mut v` -... -LL | v = 1; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.ast.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.ast.stderr deleted file mode 100644 index 20003b73d3999..0000000000000 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.ast.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `v` - --> $DIR/liveness-assign-imm-local-in-loop.rs:9:9 - | -LL | v = 1; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.mir.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.mir.stderr deleted file mode 100644 index 9d24570057375..0000000000000 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.mir.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `v` - --> $DIR/liveness-assign-imm-local-in-loop.rs:9:9 - | -LL | let v: isize; - | - help: make this binding mutable: `mut v` -... -LL | v = 1; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs index 59447ba3d755a..c9e1851b9a980 100644 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs +++ b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs @@ -1,16 +1,10 @@ -// revisions: ast mir -//[mir]compile-flags: -Zborrowck=mir - fn test() { let v: isize; - //[mir]~^ HELP make this binding mutable - //[mir]~| SUGGESTION mut v + //~^ HELP make this binding mutable + //~| SUGGESTION mut v loop { - v = 1; //[ast]~ ERROR cannot assign twice to immutable variable - //[mir]~^ ERROR cannot assign twice to immutable variable `v` - //[ast]~| NOTE cannot assign twice to immutable variable - //[mir]~| NOTE cannot assign twice to immutable variable - v.clone(); // just to prevent liveness warnings + v = 1; //~ ERROR cannot assign twice to immutable variable `v` + //~| NOTE cannot assign twice to immutable variable } } diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr new file mode 100644 index 0000000000000..69dff734ee4be --- /dev/null +++ b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr @@ -0,0 +1,12 @@ +error[E0384]: cannot assign twice to immutable variable `v` + --> $DIR/liveness-assign-imm-local-in-loop.rs:6:9 + | +LL | let v: isize; + | - help: make this binding mutable: `mut v` +... +LL | v = 1; + | ^^^^^ cannot assign twice to immutable variable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.ast.nll.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.ast.nll.stderr deleted file mode 100644 index 47b9b029d3171..0000000000000 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.ast.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `v` - --> $DIR/liveness-assign-imm-local-in-op-eq.rs:10:5 - | -LL | let v: isize; - | - help: make this binding mutable: `mut v` -... -LL | v = 2; //[ast]~ NOTE first assignment - | ----- first assignment to `v` -LL | //[mir]~^ NOTE first assignment -LL | v += 1; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.ast.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.ast.stderr deleted file mode 100644 index 4ab254beb2d86..0000000000000 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.ast.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `v` - --> $DIR/liveness-assign-imm-local-in-op-eq.rs:10:5 - | -LL | v = 2; //[ast]~ NOTE first assignment - | ----- first assignment to `v` -LL | //[mir]~^ NOTE first assignment -LL | v += 1; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.mir.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.mir.stderr deleted file mode 100644 index 47b9b029d3171..0000000000000 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.mir.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `v` - --> $DIR/liveness-assign-imm-local-in-op-eq.rs:10:5 - | -LL | let v: isize; - | - help: make this binding mutable: `mut v` -... -LL | v = 2; //[ast]~ NOTE first assignment - | ----- first assignment to `v` -LL | //[mir]~^ NOTE first assignment -LL | v += 1; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs index a2677f4e22351..f24f7d2bcfc52 100644 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs +++ b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs @@ -1,16 +1,10 @@ -// revisions: ast mir -//[mir]compile-flags: -Zborrowck=mir - fn test() { let v: isize; - //[mir]~^ HELP make this binding mutable - //[mir]~| SUGGESTION mut v - v = 2; //[ast]~ NOTE first assignment - //[mir]~^ NOTE first assignment - v += 1; //[ast]~ ERROR cannot assign twice to immutable variable - //[mir]~^ ERROR cannot assign twice to immutable variable `v` - //[ast]~| NOTE cannot assign twice to immutable - //[mir]~| NOTE cannot assign twice to immutable + //~^ HELP make this binding mutable + //~| SUGGESTION mut v + v = 2; //~ NOTE first assignment + v += 1; //~ ERROR cannot assign twice to immutable variable `v` + //~| NOTE cannot assign twice to immutable v.clone(); } diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr new file mode 100644 index 0000000000000..182958dd49244 --- /dev/null +++ b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr @@ -0,0 +1,14 @@ +error[E0384]: cannot assign twice to immutable variable `v` + --> $DIR/liveness-assign-imm-local-in-op-eq.rs:6:5 + | +LL | let v: isize; + | - help: make this binding mutable: `mut v` +... +LL | v = 2; + | ----- first assignment to `v` +LL | v += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.ast.nll.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.ast.nll.stderr deleted file mode 100644 index 08a1e9d2bb4ca..0000000000000 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.ast.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/liveness-assign-imm-local-with-drop.rs:10:5 - | -LL | let b = Box::new(1); //[ast]~ NOTE first assignment - | - - | | - | first assignment to `b` - | help: make this binding mutable: `mut b` -... -LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - | ^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.ast.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.ast.stderr deleted file mode 100644 index d543fb9ac6bd7..0000000000000 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.ast.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/liveness-assign-imm-local-with-drop.rs:10:5 - | -LL | let b = Box::new(1); //[ast]~ NOTE first assignment - | - first assignment to `b` -... -LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^^^^^^^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.mir.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.mir.stderr deleted file mode 100644 index 08a1e9d2bb4ca..0000000000000 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.mir.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/liveness-assign-imm-local-with-drop.rs:10:5 - | -LL | let b = Box::new(1); //[ast]~ NOTE first assignment - | - - | | - | first assignment to `b` - | help: make this binding mutable: `mut b` -... -LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - | ^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs index 4a81dcd3cfb54..8963e32717e22 100644 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs +++ b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs @@ -1,16 +1,10 @@ -// revisions: ast mir -//[mir]compile-flags: -Zborrowck=mir - fn test() { - let b = Box::new(1); //[ast]~ NOTE first assignment - //[mir]~^ NOTE first assignment - //[mir]~| HELP make this binding mutable - //[mir]~| SUGGESTION mut b + let b = Box::new(1); //~ NOTE first assignment + //~| HELP make this binding mutable + //~| SUGGESTION mut b drop(b); - b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable - //[mir]~^ ERROR cannot assign twice to immutable variable `b` - //[ast]~| NOTE cannot assign twice to immutable - //[mir]~| NOTE cannot assign twice to immutable + b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` + //~| NOTE cannot assign twice to immutable drop(b); } diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr new file mode 100644 index 0000000000000..7c4af624b2735 --- /dev/null +++ b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr @@ -0,0 +1,15 @@ +error[E0384]: cannot assign twice to immutable variable `b` + --> $DIR/liveness-assign-imm-local-with-drop.rs:6:5 + | +LL | let b = Box::new(1); + | - + | | + | first assignment to `b` + | help: make this binding mutable: `mut b` +... +LL | b = Box::new(2); + | ^ cannot assign twice to immutable variable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.ast.nll.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.ast.nll.stderr deleted file mode 100644 index 3c1a5692fece7..0000000000000 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.ast.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `v` - --> $DIR/liveness-assign-imm-local-with-init.rs:10:5 - | -LL | let v: isize = 1; //[ast]~ NOTE first assignment - | - - | | - | first assignment to `v` - | help: make this binding mutable: `mut v` -... -LL | v = 2; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.ast.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.ast.stderr deleted file mode 100644 index cf293ae9f2f70..0000000000000 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.ast.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `v` - --> $DIR/liveness-assign-imm-local-with-init.rs:10:5 - | -LL | let v: isize = 1; //[ast]~ NOTE first assignment - | - first assignment to `v` -... -LL | v = 2; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.mir.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.mir.stderr deleted file mode 100644 index 3c1a5692fece7..0000000000000 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.mir.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `v` - --> $DIR/liveness-assign-imm-local-with-init.rs:10:5 - | -LL | let v: isize = 1; //[ast]~ NOTE first assignment - | - - | | - | first assignment to `v` - | help: make this binding mutable: `mut v` -... -LL | v = 2; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^ cannot assign twice to immutable variable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs index 2c59aaf4f92d5..4ab222af8d088 100644 --- a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs +++ b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs @@ -1,16 +1,10 @@ -// revisions: ast mir -//[mir]compile-flags: -Zborrowck=mir - fn test() { - let v: isize = 1; //[ast]~ NOTE first assignment - //[mir]~^ NOTE first assignment - //[mir]~| HELP make this binding mutable - //[mir]~| SUGGESTION mut v + let v: isize = 1; //~ NOTE first assignment + //~| HELP make this binding mutable + //~| SUGGESTION mut v v.clone(); - v = 2; //[ast]~ ERROR cannot assign twice to immutable variable - //[mir]~^ ERROR cannot assign twice to immutable variable `v` - //[ast]~| NOTE cannot assign twice to immutable - //[mir]~| NOTE cannot assign twice to immutable + v = 2; //~ ERROR cannot assign twice to immutable variable `v` + //~| NOTE cannot assign twice to immutable v.clone(); } diff --git a/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr new file mode 100644 index 0000000000000..6f5d5574877c9 --- /dev/null +++ b/src/test/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr @@ -0,0 +1,15 @@ +error[E0384]: cannot assign twice to immutable variable `v` + --> $DIR/liveness-assign-imm-local-with-init.rs:6:5 + | +LL | let v: isize = 1; + | - + | | + | first assignment to `v` + | help: make this binding mutable: `mut v` +... +LL | v = 2; + | ^^^^^ cannot assign twice to immutable variable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/liveness/liveness-closure-require-ret.stderr b/src/test/ui/liveness/liveness-closure-require-ret.stderr index 3133efdedd762..e8f185a5cb27c 100644 --- a/src/test/ui/liveness/liveness-closure-require-ret.stderr +++ b/src/test/ui/liveness/liveness-closure-require-ret.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/liveness-closure-require-ret.rs:2:37 | -LL | fn main() { println!("{}", force(|| {})); } //~ ERROR mismatched types +LL | fn main() { println!("{}", force(|| {})); } | ^^ expected isize, found () | = note: expected type `isize` diff --git a/src/test/ui/liveness/liveness-dead.stderr b/src/test/ui/liveness/liveness-dead.stderr index c89135e5135f0..d054b1d497e5b 100644 --- a/src/test/ui/liveness/liveness-dead.stderr +++ b/src/test/ui/liveness/liveness-dead.stderr @@ -1,7 +1,7 @@ error: value assigned to `x` is never read --> $DIR/liveness-dead.rs:9:13 | -LL | let mut x: isize = 3; //~ ERROR: value assigned to `x` is never read +LL | let mut x: isize = 3; | ^ | note: lint level defined here @@ -14,7 +14,7 @@ LL | #![deny(unused_assignments)] error: value assigned to `x` is never read --> $DIR/liveness-dead.rs:17:5 | -LL | x = 4; //~ ERROR: value assigned to `x` is never read +LL | x = 4; | ^ | = help: maybe it is overwritten before being read? @@ -22,7 +22,7 @@ LL | x = 4; //~ ERROR: value assigned to `x` is never read error: value passed to `x` is never read --> $DIR/liveness-dead.rs:20:11 | -LL | fn f4(mut x: i32) { //~ ERROR: value passed to `x` is never read +LL | fn f4(mut x: i32) { | ^ | = help: maybe it is overwritten before being read? @@ -30,7 +30,7 @@ LL | fn f4(mut x: i32) { //~ ERROR: value passed to `x` is never read error: value assigned to `x` is never read --> $DIR/liveness-dead.rs:27:5 | -LL | x = 4; //~ ERROR: value assigned to `x` is never read +LL | x = 4; | ^ | = help: maybe it is overwritten before being read? diff --git a/src/test/ui/liveness/liveness-issue-2163.stderr b/src/test/ui/liveness/liveness-issue-2163.stderr index e91994d9a2299..780a2548f1f86 100644 --- a/src/test/ui/liveness/liveness-issue-2163.stderr +++ b/src/test/ui/liveness/liveness-issue-2163.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | a.iter().all(|_| -> bool { | ______________________________^ -LL | | //~^ ERROR mismatched types +LL | | LL | | }); | |_____^ expected bool, found () | diff --git a/src/test/ui/liveness/liveness-missing-ret2.stderr b/src/test/ui/liveness/liveness-missing-ret2.stderr index 58d0249ee3b24..ab7d411880bba 100644 --- a/src/test/ui/liveness/liveness-missing-ret2.stderr +++ b/src/test/ui/liveness/liveness-missing-ret2.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/liveness-missing-ret2.rs:1:11 | -LL | fn f() -> isize { //~ ERROR mismatched types +LL | fn f() -> isize { | - ^^^^^ expected isize, found () | | | this function's body doesn't return diff --git a/src/test/ui/liveness/liveness-move-call-arg.nll.stderr b/src/test/ui/liveness/liveness-move-call-arg.nll.stderr deleted file mode 100644 index 521304d560554..0000000000000 --- a/src/test/ui/liveness/liveness-move-call-arg.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0382]: use of moved value: `x` - --> $DIR/liveness-move-call-arg.rs:9:14 - | -LL | let x: Box = box 25; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait -LL | loop { -LL | take(x); //~ ERROR use of moved value: `x` - | ^ value moved here, in previous iteration of loop - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/liveness/liveness-move-call-arg.stderr b/src/test/ui/liveness/liveness-move-call-arg.stderr index 21d285463e384..ab4460a32684f 100644 --- a/src/test/ui/liveness/liveness-move-call-arg.stderr +++ b/src/test/ui/liveness/liveness-move-call-arg.stderr @@ -1,10 +1,11 @@ error[E0382]: use of moved value: `x` --> $DIR/liveness-move-call-arg.rs:9:14 | -LL | take(x); //~ ERROR use of moved value: `x` - | ^ value moved here in previous iteration of loop - | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait +LL | let x: Box = box 25; + | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait +LL | loop { +LL | take(x); + | ^ value moved here, in previous iteration of loop error: aborting due to previous error diff --git a/src/test/ui/liveness/liveness-move-in-loop.nll.stderr b/src/test/ui/liveness/liveness-move-in-loop.nll.stderr deleted file mode 100644 index b7e973bc9140d..0000000000000 --- a/src/test/ui/liveness/liveness-move-in-loop.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0382]: use of moved value: `y` - --> $DIR/liveness-move-in-loop.rs:11:25 - | -LL | let y: Box = box 42; - | - move occurs because `y` has type `std::boxed::Box`, which does not implement the `Copy` trait -... -LL | x = y; //~ ERROR use of moved value - | ^ value moved here, in previous iteration of loop - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/liveness/liveness-move-in-loop.stderr b/src/test/ui/liveness/liveness-move-in-loop.stderr index d00c2d6ac35ec..150c1ec82b83d 100644 --- a/src/test/ui/liveness/liveness-move-in-loop.stderr +++ b/src/test/ui/liveness/liveness-move-in-loop.stderr @@ -1,10 +1,11 @@ error[E0382]: use of moved value: `y` --> $DIR/liveness-move-in-loop.rs:11:25 | -LL | x = y; //~ ERROR use of moved value - | ^ value moved here in previous iteration of loop - | - = note: move occurs because `y` has type `std::boxed::Box`, which does not implement the `Copy` trait +LL | let y: Box = box 42; + | - move occurs because `y` has type `std::boxed::Box`, which does not implement the `Copy` trait +... +LL | x = y; + | ^ value moved here, in previous iteration of loop error: aborting due to previous error diff --git a/src/test/ui/liveness/liveness-move-in-while.nll.stderr b/src/test/ui/liveness/liveness-move-in-while.nll.stderr deleted file mode 100644 index 167dcc6b64372..0000000000000 --- a/src/test/ui/liveness/liveness-move-in-while.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0382]: borrow of moved value: `y` - --> $DIR/liveness-move-in-while.rs:7:24 - | -LL | let y: Box = box 42; - | - move occurs because `y` has type `std::boxed::Box`, which does not implement the `Copy` trait -... -LL | println!("{}", y); //~ ERROR use of moved value: `y` - | ^ value borrowed here after move -LL | while true { while true { while true { x = y; x.clone(); } } } - | - value moved here, in previous iteration of loop - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/liveness/liveness-move-in-while.rs b/src/test/ui/liveness/liveness-move-in-while.rs index a43e75982a1d1..420d1311f8b1f 100644 --- a/src/test/ui/liveness/liveness-move-in-while.rs +++ b/src/test/ui/liveness/liveness-move-in-while.rs @@ -4,8 +4,7 @@ fn main() { let y: Box = box 42; let mut x: Box; loop { - println!("{}", y); //~ ERROR use of moved value: `y` + println!("{}", y); //~ ERROR borrow of moved value: `y` while true { while true { while true { x = y; x.clone(); } } } - //~^ ERROR use of moved value: `y` } } diff --git a/src/test/ui/liveness/liveness-move-in-while.stderr b/src/test/ui/liveness/liveness-move-in-while.stderr index 91f722cb42288..e1eed1b59f470 100644 --- a/src/test/ui/liveness/liveness-move-in-while.stderr +++ b/src/test/ui/liveness/liveness-move-in-while.stderr @@ -1,21 +1,14 @@ -error[E0382]: use of moved value: `y` +error[E0382]: borrow of moved value: `y` --> $DIR/liveness-move-in-while.rs:7:24 | -LL | println!("{}", y); //~ ERROR use of moved value: `y` - | ^ value used here after move +LL | let y: Box = box 42; + | - move occurs because `y` has type `std::boxed::Box`, which does not implement the `Copy` trait +... +LL | println!("{}", y); + | ^ value borrowed here after move LL | while true { while true { while true { x = y; x.clone(); } } } - | - value moved here - | - = note: move occurs because `y` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `y` - --> $DIR/liveness-move-in-while.rs:8:52 - | -LL | while true { while true { while true { x = y; x.clone(); } } } - | ^ value moved here in previous iteration of loop - | - = note: move occurs because `y` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - value moved here, in previous iteration of loop -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr b/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr index c6d166d8b31a0..a5d9734c069ec 100644 --- a/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr +++ b/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr @@ -16,7 +16,7 @@ LL | test!(); error[E0308]: mismatched types --> $DIR/liveness-return-last-stmt-semi.rs:7:19 | -LL | fn no_return() -> i32 {} //~ ERROR mismatched types +LL | fn no_return() -> i32 {} | --------- ^^^ expected i32, found () | | | this function's body doesn't return @@ -27,7 +27,7 @@ LL | fn no_return() -> i32 {} //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/liveness-return-last-stmt-semi.rs:9:19 | -LL | fn bar(x: u32) -> u32 { //~ ERROR mismatched types +LL | fn bar(x: u32) -> u32 { | --- ^^^ expected u32, found () | | | this function's body doesn't return @@ -40,7 +40,7 @@ LL | x * 2; error[E0308]: mismatched types --> $DIR/liveness-return-last-stmt-semi.rs:13:19 | -LL | fn baz(x: u64) -> u32 { //~ ERROR mismatched types +LL | fn baz(x: u64) -> u32 { | --- ^^^ expected u32, found () | | | this function's body doesn't return diff --git a/src/test/ui/liveness/liveness-unused.stderr b/src/test/ui/liveness/liveness-unused.stderr index 49795faa59c8d..d6077111f71b4 100644 --- a/src/test/ui/liveness/liveness-unused.stderr +++ b/src/test/ui/liveness/liveness-unused.stderr @@ -1,7 +1,7 @@ warning: unreachable statement --> $DIR/liveness-unused.rs:92:9 | -LL | drop(*x as i32); //~ WARNING unreachable statement +LL | drop(*x as i32); | ^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -105,7 +105,7 @@ LL | let x; error: value assigned to `x` is never read --> $DIR/liveness-unused.rs:116:9 | -LL | x = 0; //~ ERROR value assigned to `x` is never read +LL | x = 0; | ^ | = help: maybe it is overwritten before being read? diff --git a/src/test/ui/liveness/liveness-use-after-move.nll.stderr b/src/test/ui/liveness/liveness-use-after-move.nll.stderr deleted file mode 100644 index 36c25882ccd4f..0000000000000 --- a/src/test/ui/liveness/liveness-use-after-move.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: borrow of moved value: `x` - --> $DIR/liveness-use-after-move.rs:6:20 - | -LL | let x: Box<_> = box 5; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait -LL | let y = x; - | - value moved here -LL | println!("{}", *x); //~ ERROR use of moved value: `*x` - | ^^ value borrowed here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/liveness/liveness-use-after-move.rs b/src/test/ui/liveness/liveness-use-after-move.rs index 157587c7a7b54..5263e293603cd 100644 --- a/src/test/ui/liveness/liveness-use-after-move.rs +++ b/src/test/ui/liveness/liveness-use-after-move.rs @@ -3,6 +3,6 @@ fn main() { let x: Box<_> = box 5; let y = x; - println!("{}", *x); //~ ERROR use of moved value: `*x` + println!("{}", *x); //~ ERROR borrow of moved value: `x` y.clone(); } diff --git a/src/test/ui/liveness/liveness-use-after-move.stderr b/src/test/ui/liveness/liveness-use-after-move.stderr index 62475943d0e3d..383b89afaa75e 100644 --- a/src/test/ui/liveness/liveness-use-after-move.stderr +++ b/src/test/ui/liveness/liveness-use-after-move.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `*x` +error[E0382]: borrow of moved value: `x` --> $DIR/liveness-use-after-move.rs:6:20 | +LL | let x: Box<_> = box 5; + | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait LL | let y = x; - | - value moved here -LL | println!("{}", *x); //~ ERROR use of moved value: `*x` - | ^^ value used here after move - | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - value moved here +LL | println!("{}", *x); + | ^^ value borrowed here after move error: aborting due to previous error diff --git a/src/test/ui/liveness/liveness-use-after-send.nll.stderr b/src/test/ui/liveness/liveness-use-after-send.nll.stderr deleted file mode 100644 index d9367c871165a..0000000000000 --- a/src/test/ui/liveness/liveness-use-after-send.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: borrow of moved value: `message` - --> $DIR/liveness-use-after-send.rs:16:20 - | -LL | fn test00_start(ch: Chan>, message: Box, _count: Box) { - | ------- move occurs because `message` has type `std::boxed::Box`, which does not implement the `Copy` trait -LL | send(ch, message); - | ------- value moved here -LL | println!("{}", message); //~ ERROR use of moved value: `message` - | ^^^^^^^ value borrowed here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/liveness/liveness-use-after-send.rs b/src/test/ui/liveness/liveness-use-after-send.rs index 7f2cc3c00f459..6fcd91a9d9b2e 100644 --- a/src/test/ui/liveness/liveness-use-after-send.rs +++ b/src/test/ui/liveness/liveness-use-after-send.rs @@ -13,7 +13,7 @@ struct Chan(isize, marker::PhantomData); // message after the send deinitializes it fn test00_start(ch: Chan>, message: Box, _count: Box) { send(ch, message); - println!("{}", message); //~ ERROR use of moved value: `message` + println!("{}", message); //~ ERROR borrow of moved value: `message` } fn main() { panic!(); } diff --git a/src/test/ui/liveness/liveness-use-after-send.stderr b/src/test/ui/liveness/liveness-use-after-send.stderr index 1fdb1d3ec39bc..ccf9499f64407 100644 --- a/src/test/ui/liveness/liveness-use-after-send.stderr +++ b/src/test/ui/liveness/liveness-use-after-send.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `message` +error[E0382]: borrow of moved value: `message` --> $DIR/liveness-use-after-send.rs:16:20 | +LL | fn test00_start(ch: Chan>, message: Box, _count: Box) { + | ------- move occurs because `message` has type `std::boxed::Box`, which does not implement the `Copy` trait LL | send(ch, message); | ------- value moved here -LL | println!("{}", message); //~ ERROR use of moved value: `message` - | ^^^^^^^ value used here after move - | - = note: move occurs because `message` has type `std::boxed::Box`, which does not implement the `Copy` trait +LL | println!("{}", message); + | ^^^^^^^ value borrowed here after move error: aborting due to previous error diff --git a/src/test/ui/loops/loop-break-value-no-repeat.stderr b/src/test/ui/loops/loop-break-value-no-repeat.stderr index f5c6544a815ab..066dce531a54f 100644 --- a/src/test/ui/loops/loop-break-value-no-repeat.stderr +++ b/src/test/ui/loops/loop-break-value-no-repeat.stderr @@ -1,11 +1,11 @@ error[E0571]: `break` with value from a `for` loop --> $DIR/loop-break-value-no-repeat.rs:12:9 | -LL | break 22 //~ ERROR `break` with value from a `for` loop +LL | break 22 | ^^^^^^^^ can only break with a value inside `loop` or breakable block help: instead, use `break` on its own without a value inside this `for` loop | -LL | break //~ ERROR `break` with value from a `for` loop +LL | break | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/loops/loop-break-value.stderr b/src/test/ui/loops/loop-break-value.stderr index 3e009c007e08d..13fe50855408b 100644 --- a/src/test/ui/loops/loop-break-value.stderr +++ b/src/test/ui/loops/loop-break-value.stderr @@ -1,11 +1,11 @@ error[E0571]: `break` with value from a `while` loop --> $DIR/loop-break-value.rs:28:9 | -LL | break (); //~ ERROR `break` with value from a `while` loop +LL | break (); | ^^^^^^^^ can only break with a value inside `loop` or breakable block help: instead, use `break` on its own without a value inside this `while` loop | -LL | break; //~ ERROR `break` with value from a `while` loop +LL | break; | ^^^^^ error[E0571]: `break` with value from a `while` loop @@ -21,11 +21,11 @@ LL | break; error[E0571]: `break` with value from a `while let` loop --> $DIR/loop-break-value.rs:38:12 | -LL | if break () { //~ ERROR `break` with value from a `while let` loop +LL | if break () { | ^^^^^^^^ can only break with a value inside `loop` or breakable block help: instead, use `break` on its own without a value inside this `while let` loop | -LL | if break { //~ ERROR `break` with value from a `while let` loop +LL | if break { | ^^^^^ error[E0571]: `break` with value from a `while let` loop @@ -51,11 +51,11 @@ LL | break; error[E0571]: `break` with value from a `for` loop --> $DIR/loop-break-value.rs:56:9 | -LL | break (); //~ ERROR `break` with value from a `for` loop +LL | break (); | ^^^^^^^^ can only break with a value inside `loop` or breakable block help: instead, use `break` on its own without a value inside this `for` loop | -LL | break; //~ ERROR `break` with value from a `for` loop +LL | break; | ^^^^^ error[E0571]: `break` with value from a `for` loop @@ -90,7 +90,7 @@ LL | let val: ! = loop { break break; }; error[E0308]: mismatched types --> $DIR/loop-break-value.rs:11:19 | -LL | break 123; //~ ERROR mismatched types +LL | break 123; | ^^^ expected &str, found integer | = note: expected type `&str` @@ -99,7 +99,7 @@ LL | break 123; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/loop-break-value.rs:16:15 | -LL | break "asdf"; //~ ERROR mismatched types +LL | break "asdf"; | ^^^^^^ expected i32, found reference | = note: expected type `i32` @@ -108,7 +108,7 @@ LL | break "asdf"; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/loop-break-value.rs:21:31 | -LL | break 'outer_loop "nope"; //~ ERROR mismatched types +LL | break 'outer_loop "nope"; | ^^^^^^ expected i32, found reference | = note: expected type `i32` @@ -117,7 +117,7 @@ LL | break 'outer_loop "nope"; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/loop-break-value.rs:73:26 | -LL | break 'c 123; //~ ERROR mismatched types +LL | break 'c 123; | ^^^ expected (), found integer | = note: expected type `()` @@ -126,7 +126,7 @@ LL | break 'c 123; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/loop-break-value.rs:80:15 | -LL | break (break, break); //~ ERROR mismatched types +LL | break (break, break); | ^^^^^^^^^^^^^^ expected (), found tuple | = note: expected type `()` @@ -135,7 +135,7 @@ LL | break (break, break); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/loop-break-value.rs:85:15 | -LL | break 2; //~ ERROR mismatched types +LL | break 2; | ^ expected (), found integer | = note: expected type `()` @@ -144,7 +144,7 @@ LL | break 2; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/loop-break-value.rs:90:9 | -LL | break; //~ ERROR mismatched types +LL | break; | ^^^^^ expected (), found integer | = note: expected type `()` @@ -152,5 +152,5 @@ LL | break; //~ ERROR mismatched types error: aborting due to 16 previous errors -Some errors occurred: E0308, E0571. +Some errors have detailed explanations: E0308, E0571. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/loops/loop-labeled-break-value.stderr b/src/test/ui/loops/loop-labeled-break-value.stderr index 5cfd86ea50478..ad7cb4b0c2e5f 100644 --- a/src/test/ui/loops/loop-labeled-break-value.stderr +++ b/src/test/ui/loops/loop-labeled-break-value.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/loop-labeled-break-value.rs:3:29 | -LL | let _: i32 = loop { break }; //~ ERROR mismatched types +LL | let _: i32 = loop { break }; | ^^^^^ expected (), found i32 | = note: expected type `()` @@ -10,7 +10,7 @@ LL | let _: i32 = loop { break }; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/loop-labeled-break-value.rs:6:37 | -LL | let _: i32 = 'inner: loop { break 'inner }; //~ ERROR mismatched types +LL | let _: i32 = 'inner: loop { break 'inner }; | ^^^^^^^^^^^^ expected (), found i32 | = note: expected type `()` @@ -19,7 +19,7 @@ LL | let _: i32 = 'inner: loop { break 'inner }; //~ ERROR mismatched ty error[E0308]: mismatched types --> $DIR/loop-labeled-break-value.rs:9:45 | -LL | let _: i32 = 'inner2: loop { loop { break 'inner2 } }; //~ ERROR mismatched types +LL | let _: i32 = 'inner2: loop { loop { break 'inner2 } }; | ^^^^^^^^^^^^^ expected (), found i32 | = note: expected type `()` diff --git a/src/test/ui/loops/loop-proper-liveness.nll.stderr b/src/test/ui/loops/loop-proper-liveness.nll.stderr deleted file mode 100644 index 745f0876b404d..0000000000000 --- a/src/test/ui/loops/loop-proper-liveness.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: borrow of possibly uninitialized variable: `x` - --> $DIR/loop-proper-liveness.rs:9:22 - | -LL | println!("{:?}", x); //~ ERROR use of possibly uninitialized variable - | ^ use of possibly uninitialized `x` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/loops/loop-proper-liveness.rs b/src/test/ui/loops/loop-proper-liveness.rs index fd9d6612220c7..b8f76fbe57ba3 100644 --- a/src/test/ui/loops/loop-proper-liveness.rs +++ b/src/test/ui/loops/loop-proper-liveness.rs @@ -6,7 +6,7 @@ fn test1() { 'a: loop { x = loop { break 'a }; } - println!("{:?}", x); //~ ERROR use of possibly uninitialized variable + println!("{:?}", x); //~ ERROR borrow of possibly uninitialized variable } // test2 and test3 should not fail. diff --git a/src/test/ui/loops/loop-proper-liveness.stderr b/src/test/ui/loops/loop-proper-liveness.stderr index b8fb3fe00ee54..c87720659fd78 100644 --- a/src/test/ui/loops/loop-proper-liveness.stderr +++ b/src/test/ui/loops/loop-proper-liveness.stderr @@ -1,7 +1,7 @@ -error[E0381]: use of possibly uninitialized variable: `x` +error[E0381]: borrow of possibly uninitialized variable: `x` --> $DIR/loop-proper-liveness.rs:9:22 | -LL | println!("{:?}", x); //~ ERROR use of possibly uninitialized variable +LL | println!("{:?}", x); | ^ use of possibly uninitialized `x` error: aborting due to previous error diff --git a/src/test/ui/loops/loop-properly-diverging-2.stderr b/src/test/ui/loops/loop-properly-diverging-2.stderr index 5bd088fa0114c..6293fdb058a0f 100644 --- a/src/test/ui/loops/loop-properly-diverging-2.stderr +++ b/src/test/ui/loops/loop-properly-diverging-2.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/loop-properly-diverging-2.rs:2:23 | -LL | let x: i32 = loop { break }; //~ ERROR mismatched types +LL | let x: i32 = loop { break }; | ^^^^^ expected (), found i32 | = note: expected type `()` diff --git a/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr b/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr index 4d1a29f71658c..fc42449aa58bc 100644 --- a/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr +++ b/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr @@ -3,7 +3,7 @@ warning: label name `'fl` shadows a label name that is already in scope | LL | { 'fl: for _ in 0..10 { break; } } | --- first declared here -LL | { 'fl: loop { break; } } //~ WARN label name `'fl` shadows a label name that is already in scope +LL | { 'fl: loop { break; } } | ^^^ lifetime 'fl already in scope warning: label name `'lf` shadows a label name that is already in scope @@ -11,7 +11,7 @@ warning: label name `'lf` shadows a label name that is already in scope | LL | { 'lf: loop { break; } } | --- first declared here -LL | { 'lf: for _ in 0..10 { break; } } //~ WARN label name `'lf` shadows a label name that is already in scope +LL | { 'lf: for _ in 0..10 { break; } } | ^^^ lifetime 'lf already in scope warning: label name `'wl` shadows a label name that is already in scope @@ -19,7 +19,7 @@ warning: label name `'wl` shadows a label name that is already in scope | LL | { 'wl: while 2 > 1 { break; } } | --- first declared here -LL | { 'wl: loop { break; } } //~ WARN label name `'wl` shadows a label name that is already in scope +LL | { 'wl: loop { break; } } | ^^^ lifetime 'wl already in scope warning: label name `'lw` shadows a label name that is already in scope @@ -27,7 +27,7 @@ warning: label name `'lw` shadows a label name that is already in scope | LL | { 'lw: loop { break; } } | --- first declared here -LL | { 'lw: while 2 > 1 { break; } } //~ WARN label name `'lw` shadows a label name that is already in scope +LL | { 'lw: while 2 > 1 { break; } } | ^^^ lifetime 'lw already in scope warning: label name `'fw` shadows a label name that is already in scope @@ -35,7 +35,7 @@ warning: label name `'fw` shadows a label name that is already in scope | LL | { 'fw: for _ in 0..10 { break; } } | --- first declared here -LL | { 'fw: while 2 > 1 { break; } } //~ WARN label name `'fw` shadows a label name that is already in scope +LL | { 'fw: while 2 > 1 { break; } } | ^^^ lifetime 'fw already in scope warning: label name `'wf` shadows a label name that is already in scope @@ -43,7 +43,7 @@ warning: label name `'wf` shadows a label name that is already in scope | LL | { 'wf: while 2 > 1 { break; } } | --- first declared here -LL | { 'wf: for _ in 0..10 { break; } } //~ WARN label name `'wf` shadows a label name that is already in scope +LL | { 'wf: for _ in 0..10 { break; } } | ^^^ lifetime 'wf already in scope warning: label name `'tl` shadows a label name that is already in scope @@ -51,7 +51,7 @@ warning: label name `'tl` shadows a label name that is already in scope | LL | { 'tl: while let Some(_) = None:: { break; } } | --- first declared here -LL | { 'tl: loop { break; } } //~ WARN label name `'tl` shadows a label name that is already in scope +LL | { 'tl: loop { break; } } | ^^^ lifetime 'tl already in scope warning: label name `'lt` shadows a label name that is already in scope diff --git a/src/test/ui/loops/loops-reject-duplicate-labels.stderr b/src/test/ui/loops/loops-reject-duplicate-labels.stderr index f9a19ad57f04f..4574c5ca0bd51 100644 --- a/src/test/ui/loops/loops-reject-duplicate-labels.stderr +++ b/src/test/ui/loops/loops-reject-duplicate-labels.stderr @@ -3,7 +3,7 @@ warning: label name `'fl` shadows a label name that is already in scope | LL | 'fl: for _ in 0..10 { break; } | --- first declared here -LL | 'fl: loop { break; } //~ WARN label name `'fl` shadows a label name that is already in scope +LL | 'fl: loop { break; } | ^^^ lifetime 'fl already in scope warning: label name `'lf` shadows a label name that is already in scope @@ -11,7 +11,7 @@ warning: label name `'lf` shadows a label name that is already in scope | LL | 'lf: loop { break; } | --- first declared here -LL | 'lf: for _ in 0..10 { break; } //~ WARN label name `'lf` shadows a label name that is already in scope +LL | 'lf: for _ in 0..10 { break; } | ^^^ lifetime 'lf already in scope warning: label name `'wl` shadows a label name that is already in scope @@ -19,7 +19,7 @@ warning: label name `'wl` shadows a label name that is already in scope | LL | 'wl: while 2 > 1 { break; } | --- first declared here -LL | 'wl: loop { break; } //~ WARN label name `'wl` shadows a label name that is already in scope +LL | 'wl: loop { break; } | ^^^ lifetime 'wl already in scope warning: label name `'lw` shadows a label name that is already in scope @@ -27,7 +27,7 @@ warning: label name `'lw` shadows a label name that is already in scope | LL | 'lw: loop { break; } | --- first declared here -LL | 'lw: while 2 > 1 { break; } //~ WARN label name `'lw` shadows a label name that is already in scope +LL | 'lw: while 2 > 1 { break; } | ^^^ lifetime 'lw already in scope warning: label name `'fw` shadows a label name that is already in scope @@ -35,7 +35,7 @@ warning: label name `'fw` shadows a label name that is already in scope | LL | 'fw: for _ in 0..10 { break; } | --- first declared here -LL | 'fw: while 2 > 1 { break; } //~ WARN label name `'fw` shadows a label name that is already in scope +LL | 'fw: while 2 > 1 { break; } | ^^^ lifetime 'fw already in scope warning: label name `'wf` shadows a label name that is already in scope @@ -43,7 +43,7 @@ warning: label name `'wf` shadows a label name that is already in scope | LL | 'wf: while 2 > 1 { break; } | --- first declared here -LL | 'wf: for _ in 0..10 { break; } //~ WARN label name `'wf` shadows a label name that is already in scope +LL | 'wf: for _ in 0..10 { break; } | ^^^ lifetime 'wf already in scope warning: label name `'tl` shadows a label name that is already in scope @@ -51,7 +51,7 @@ warning: label name `'tl` shadows a label name that is already in scope | LL | 'tl: while let Some(_) = None:: { break; } | --- first declared here -LL | 'tl: loop { break; } //~ WARN label name `'tl` shadows a label name that is already in scope +LL | 'tl: loop { break; } | ^^^ lifetime 'tl already in scope warning: label name `'lt` shadows a label name that is already in scope diff --git a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs index f48e984845665..656ed6576e269 100644 --- a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs +++ b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs @@ -18,7 +18,7 @@ fn foo() { let z = 3_i8; 'a: loop { - let b = Box::new(|x: &i8| *x) as Box Fn(&'a i8) -> i8>; + let b = Box::new(|x: &i8| *x) as Box Fn(&'a i8) -> i8>; //~^ WARN lifetime name `'a` shadows a label name that is already in scope assert_eq!((*b)(&z), z); break 'a; diff --git a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr index 4c4d9218ec9e9..e5d376675c62a 100644 --- a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr +++ b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr @@ -1,8 +1,8 @@ warning: lifetime name `'a` shadows a label name that is already in scope - --> $DIR/loops-reject-lifetime-shadowing-label.rs:21:51 + --> $DIR/loops-reject-lifetime-shadowing-label.rs:21:55 | LL | 'a: loop { | -- first declared here -LL | let b = Box::new(|x: &i8| *x) as Box Fn(&'a i8) -> i8>; - | ^^ lifetime 'a already in scope +LL | let b = Box::new(|x: &i8| *x) as Box Fn(&'a i8) -> i8>; + | ^^ lifetime 'a already in scope diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr.stderr index 8f228ea4cad41..475c1801ca129 100644 --- a/src/test/ui/lub-glb/old-lub-glb-hr.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-hr.stderr @@ -5,7 +5,7 @@ LL | let z = match 22 { | _____________- LL | | 0 => x, | | - this is found to be of type `for<'r, 's> fn(&'r u8, &'s u8)` -LL | | _ => y, //~ ERROR match arms have incompatible types +LL | | _ => y, | | ^ expected bound lifetime parameter, found concrete lifetime LL | | }; | |_____- `match` arms have incompatible types diff --git a/src/test/ui/lub-glb/old-lub-glb-object.rs b/src/test/ui/lub-glb/old-lub-glb-object.rs index dcd604a5157e2..f303c07e6d79c 100644 --- a/src/test/ui/lub-glb/old-lub-glb-object.rs +++ b/src/test/ui/lub-glb/old-lub-glb-object.rs @@ -4,8 +4,8 @@ trait Foo { } fn foo( - x: &for<'a, 'b> Foo<&'a u8, &'b u8>, - y: &for<'a> Foo<&'a u8, &'a u8>, + x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, + y: &dyn for<'a> Foo<&'a u8, &'a u8>, ) { let z = match 22 { 0 => x, @@ -14,12 +14,12 @@ fn foo( } fn bar( - x: &for<'a, 'b> Foo<&'a u8, &'b u8>, - y: &for<'a> Foo<&'a u8, &'a u8>, + x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, + y: &dyn for<'a> Foo<&'a u8, &'a u8>, ) { // Accepted with explicit case: let z = match 22 { - 0 => x as &for<'a> Foo<&'a u8, &'a u8>, + 0 => x as &dyn for<'a> Foo<&'a u8, &'a u8>, _ => y, }; } diff --git a/src/test/ui/lub-glb/old-lub-glb-object.stderr b/src/test/ui/lub-glb/old-lub-glb-object.stderr index 056f9131dd21c..e02ede399e6af 100644 --- a/src/test/ui/lub-glb/old-lub-glb-object.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr @@ -5,7 +5,7 @@ LL | let z = match 22 { | _____________- LL | | 0 => x, | | - this is found to be of type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>` -LL | | _ => y, //~ ERROR match arms have incompatible types +LL | | _ => y, | | ^ expected bound lifetime parameter 'a, found concrete lifetime LL | | }; | |_____- `match` arms have incompatible types diff --git a/src/test/ui/lub-if.nll.stderr b/src/test/ui/lub-if.nll.stderr new file mode 100644 index 0000000000000..832688f5162b3 --- /dev/null +++ b/src/test/ui/lub-if.nll.stderr @@ -0,0 +1,20 @@ +error: lifetime may not live long enough + --> $DIR/lub-if.rs:28:9 + | +LL | pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { + | -- lifetime `'a` defined here +... +LL | s + | ^ returning this value requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/lub-if.rs:35:9 + | +LL | pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { + | -- lifetime `'a` defined here +... +LL | s + | ^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lub-if.stderr b/src/test/ui/lub-if.stderr index 2cf12ba60414d..bb772d4c6c695 100644 --- a/src/test/ui/lub-if.stderr +++ b/src/test/ui/lub-if.stderr @@ -1,7 +1,7 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/lub-if.rs:28:9 | -LL | s //~ ERROR E0312 +LL | s | ^ | = note: ...the reference is valid for the static lifetime... @@ -14,7 +14,7 @@ LL | pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/lub-if.rs:35:9 | -LL | s //~ ERROR E0312 +LL | s | ^ | = note: ...the reference is valid for the static lifetime... @@ -26,4 +26,3 @@ LL | pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0312`. diff --git a/src/test/ui/lub-match.nll.stderr b/src/test/ui/lub-match.nll.stderr new file mode 100644 index 0000000000000..3a344a77d2c2d --- /dev/null +++ b/src/test/ui/lub-match.nll.stderr @@ -0,0 +1,20 @@ +error: lifetime may not live long enough + --> $DIR/lub-match.rs:30:13 + | +LL | pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { + | -- lifetime `'a` defined here +... +LL | s + | ^ returning this value requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/lub-match.rs:39:13 + | +LL | pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { + | -- lifetime `'a` defined here +... +LL | s + | ^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lub-match.stderr b/src/test/ui/lub-match.stderr index 0db27f91717b0..090af25143670 100644 --- a/src/test/ui/lub-match.stderr +++ b/src/test/ui/lub-match.stderr @@ -1,7 +1,7 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/lub-match.rs:30:13 | -LL | s //~ ERROR E0312 +LL | s | ^ | = note: ...the reference is valid for the static lifetime... @@ -14,7 +14,7 @@ LL | pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/lub-match.rs:39:13 | -LL | s //~ ERROR E0312 +LL | s | ^ | = note: ...the reference is valid for the static lifetime... @@ -26,4 +26,3 @@ LL | pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0312`. diff --git a/src/test/ui/macro_backtrace/auxiliary/ping.rs b/src/test/ui/macro_backtrace/auxiliary/ping.rs index efddb209cdaa0..25b9efbc93ac9 100644 --- a/src/test/ui/macro_backtrace/auxiliary/ping.rs +++ b/src/test/ui/macro_backtrace/auxiliary/ping.rs @@ -28,4 +28,3 @@ macro_rules! bar { ping!(); } } - diff --git a/src/test/ui/macros/ambiguity-legacy-vs-modern.stderr b/src/test/ui/macros/ambiguity-legacy-vs-modern.stderr index 2785594585dd8..d9a0a9f005432 100644 --- a/src/test/ui/macros/ambiguity-legacy-vs-modern.stderr +++ b/src/test/ui/macros/ambiguity-legacy-vs-modern.stderr @@ -1,7 +1,7 @@ error[E0659]: `m` is ambiguous (`macro_rules` vs non-`macro_rules` from other module) --> $DIR/ambiguity-legacy-vs-modern.rs:31:9 | -LL | m!() //~ ERROR `m` is ambiguous +LL | m!() | ^ ambiguous name | note: `m` could refer to the macro defined here @@ -18,7 +18,7 @@ LL | macro m() { 0 } error[E0659]: `m` is ambiguous (`macro_rules` vs non-`macro_rules` from other module) --> $DIR/ambiguity-legacy-vs-modern.rs:43:5 | -LL | m!() //~ ERROR `m` is ambiguous +LL | m!() | ^ ambiguous name | note: `m` could refer to the macro defined here diff --git a/src/test/ui/macros/assert-trailing-junk.rs b/src/test/ui/macros/assert-trailing-junk.rs new file mode 100644 index 0000000000000..676ae05bf0fa6 --- /dev/null +++ b/src/test/ui/macros/assert-trailing-junk.rs @@ -0,0 +1,24 @@ +// Ensure assert macro does not ignore trailing garbage. +// +// See https://github.com/rust-lang/rust/issues/60024 for details. + +fn main() { + assert!(true some extra junk, "whatever"); + //~^ ERROR expected one of + + assert!(true some extra junk); + //~^ ERROR expected one of + + assert!(true, "whatever" blah); + //~^ ERROR no rules expected + + assert!(true "whatever" blah); + //~^ WARN unexpected string literal + //~^^ ERROR no rules expected + + assert!(true;); + //~^ WARN macro requires an expression + + assert!(false || true "error message"); + //~^ WARN unexpected string literal +} diff --git a/src/test/ui/macros/assert-trailing-junk.stderr b/src/test/ui/macros/assert-trailing-junk.stderr new file mode 100644 index 0000000000000..6fc0a27846109 --- /dev/null +++ b/src/test/ui/macros/assert-trailing-junk.stderr @@ -0,0 +1,60 @@ +error: expected one of `,`, `.`, `?`, or an operator, found `some` + --> $DIR/assert-trailing-junk.rs:6:18 + | +LL | assert!(true some extra junk, "whatever"); + | ^^^^ expected one of `,`, `.`, `?`, or an operator here + +error: expected one of `,`, `.`, `?`, or an operator, found `some` + --> $DIR/assert-trailing-junk.rs:9:18 + | +LL | assert!(true some extra junk); + | ^^^^ expected one of `,`, `.`, `?`, or an operator here + +error: no rules expected the token `blah` + --> $DIR/assert-trailing-junk.rs:12:30 + | +LL | assert!(true, "whatever" blah); + | -^^^^ no rules expected this token in macro call + | | + | help: missing comma here + +warning: unexpected string literal + --> $DIR/assert-trailing-junk.rs:15:18 + | +LL | assert!(true "whatever" blah); + | -^^^^^^^^^^ + | | + | help: try adding a comma + | + = note: this is going to be an error in the future + +error: no rules expected the token `blah` + --> $DIR/assert-trailing-junk.rs:15:29 + | +LL | assert!(true "whatever" blah); + | -^^^^ no rules expected this token in macro call + | | + | help: missing comma here + +warning: macro requires an expression as an argument + --> $DIR/assert-trailing-junk.rs:19:5 + | +LL | assert!(true;); + | ^^^^^^^^^^^^-^^ + | | + | help: try removing semicolon + | + = note: this is going to be an error in the future + +warning: unexpected string literal + --> $DIR/assert-trailing-junk.rs:22:27 + | +LL | assert!(false || true "error message"); + | -^^^^^^^^^^^^^^^ + | | + | help: try adding a comma + | + = note: this is going to be an error in the future + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/macros/assert.stderr b/src/test/ui/macros/assert.stderr index 2cfcebabcb931..fa604506b9464 100644 --- a/src/test/ui/macros/assert.stderr +++ b/src/test/ui/macros/assert.stderr @@ -1,19 +1,19 @@ error: macro requires a boolean expression as an argument --> $DIR/assert.rs:2:5 | -LL | assert!(); //~ ERROR requires a boolean expression +LL | assert!(); | ^^^^^^^^^^ boolean expression required error: expected expression, found keyword `struct` --> $DIR/assert.rs:3:13 | -LL | assert!(struct); //~ ERROR expected expression +LL | assert!(struct); | ^^^^^^ expected expression error: macro requires a boolean expression as an argument --> $DIR/assert.rs:4:5 | -LL | debug_assert!(); //~ ERROR requires a boolean expression +LL | debug_assert!(); | ^^^^^^^^^^^^^^^^ boolean expression required | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) @@ -21,7 +21,7 @@ LL | debug_assert!(); //~ ERROR requires a boolean expression error: expected expression, found keyword `struct` --> $DIR/assert.rs:5:19 | -LL | debug_assert!(struct); //~ ERROR expected expression +LL | debug_assert!(struct); | ^^^^^^ expected expression error: aborting due to 4 previous errors diff --git a/src/test/ui/macros/cfg.stderr b/src/test/ui/macros/cfg.stderr index a7aca88f3e56e..0fdb62922a751 100644 --- a/src/test/ui/macros/cfg.stderr +++ b/src/test/ui/macros/cfg.stderr @@ -1,19 +1,19 @@ error: macro requires a cfg-pattern as an argument --> $DIR/cfg.rs:2:5 | -LL | cfg!(); //~ ERROR macro requires a cfg-pattern +LL | cfg!(); | ^^^^^^^ cfg-pattern required error: expected identifier, found `123` --> $DIR/cfg.rs:3:10 | -LL | cfg!(123); //~ ERROR expected identifier +LL | cfg!(123); | ^^^ expected identifier error[E0565]: literal in `cfg` predicate value must be a string --> $DIR/cfg.rs:4:16 | -LL | cfg!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string +LL | cfg!(foo = 123); | ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/macros/format-foreign.stderr b/src/test/ui/macros/format-foreign.stderr index 0b8bfcbdc17ba..e2f2f14dce319 100644 --- a/src/test/ui/macros/format-foreign.stderr +++ b/src/test/ui/macros/format-foreign.stderr @@ -1,7 +1,7 @@ error: multiple unused formatting arguments --> $DIR/format-foreign.rs:2:30 | -LL | println!("%.*3$s %s!/n", "Hello,", "World", 4); //~ ERROR multiple unused formatting arguments +LL | println!("%.*3$s %s!\n", "Hello,", "World", 4); | -------------- ^^^^^^^^ ^^^^^^^ ^ argument never used | | | | | | | argument never used @@ -11,13 +11,13 @@ LL | println!("%.*3$s %s!/n", "Hello,", "World", 4); //~ ERROR multiple unus = note: printf formatting not supported; see the documentation for `std::fmt` help: format specifiers use curly braces | -LL | println!("{:.2$} {}!/n", "Hello,", "World", 4); //~ ERROR multiple unused formatting arguments +LL | println!("{:.2$} {}!\n", "Hello,", "World", 4); | ^^^^^^ ^^ error: argument never used --> $DIR/format-foreign.rs:3:29 | -LL | println!("%1$*2$.*3$f", 123.456); //~ ERROR never used +LL | println!("%1$*2$.*3$f", 123.456); | ----------- ^^^^^^^ argument never used | | | help: format specifiers use curly braces: `{0:1$.2$}` @@ -29,7 +29,7 @@ error: multiple unused formatting arguments | LL | println!(r###"%.*3$s | ______________- -LL | | %s!/n +LL | | %s!\n LL | | "###, "Hello,", "World", 4); | | - ^^^^^^^^ ^^^^^^^ ^ argument never used | | | | | @@ -41,13 +41,13 @@ LL | | "###, "Hello,", "World", 4); help: format specifiers use curly braces | LL | println!(r###"{:.2$} -LL | {}!/n +LL | {}!\n | error: argument never used --> $DIR/format-foreign.rs:12:30 | -LL | println!("{} %f", "one", 2.0); //~ ERROR never used +LL | println!("{} %f", "one", 2.0); | ------- ^^^ argument never used | | | formatting specifier missing @@ -55,7 +55,7 @@ LL | println!("{} %f", "one", 2.0); //~ ERROR never used error: named argument never used --> $DIR/format-foreign.rs:14:39 | -LL | println!("Hi there, $NAME.", NAME="Tim"); //~ ERROR never used +LL | println!("Hi there, $NAME.", NAME="Tim"); | ----- ^^^^^ named argument never used | | | help: format specifiers use curly braces: `{NAME}` diff --git a/src/test/ui/macros/format-parse-errors.stderr b/src/test/ui/macros/format-parse-errors.stderr index a3d2786bce111..fd4f93091944c 100644 --- a/src/test/ui/macros/format-parse-errors.stderr +++ b/src/test/ui/macros/format-parse-errors.stderr @@ -1,7 +1,7 @@ error: requires at least a format string argument --> $DIR/format-parse-errors.rs:2:5 | -LL | format!(); //~ ERROR requires at least a format string argument +LL | format!(); | ^^^^^^^^^^ | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) @@ -9,41 +9,41 @@ LL | format!(); //~ ERROR requires at least a format string argument error: expected expression, found keyword `struct` --> $DIR/format-parse-errors.rs:3:13 | -LL | format!(struct); //~ ERROR expected expression +LL | format!(struct); | ^^^^^^ expected expression -error: expected expression, found `` - --> $DIR/format-parse-errors.rs:4:23 +error: expected expression, found end of macro arguments + --> $DIR/format-parse-errors.rs:4:24 | -LL | format!("s", name =); //~ ERROR expected expression - | ^ expected expression +LL | format!("s", name =); + | ^ expected expression -error: expected `=`, found `` - --> $DIR/format-parse-errors.rs:5:29 +error: expected `=`, found end of macro arguments + --> $DIR/format-parse-errors.rs:5:32 | -LL | format!("s", foo = foo, bar); //~ ERROR expected `=` - | ^^^ expected `=` +LL | format!("s", foo = foo, bar); + | ^ expected `=` error: expected expression, found keyword `struct` --> $DIR/format-parse-errors.rs:6:24 | -LL | format!("s", foo = struct); //~ ERROR expected expression +LL | format!("s", foo = struct); | ^^^^^^ expected expression error: expected expression, found keyword `struct` --> $DIR/format-parse-errors.rs:7:18 | -LL | format!("s", struct); //~ ERROR expected expression +LL | format!("s", struct); | ^^^^^^ expected expression error: format argument must be a string literal --> $DIR/format-parse-errors.rs:10:13 | -LL | format!(123); //~ ERROR format argument must be a string literal +LL | format!(123); | ^^^ help: you might be missing a string literal to format with | -LL | format!("{}", 123); //~ ERROR format argument must be a string literal +LL | format!("{}", 123); | ^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/macros/format-unused-lables.stderr b/src/test/ui/macros/format-unused-lables.stderr index 0a5e379a4adb4..7423c7b7c8b47 100644 --- a/src/test/ui/macros/format-unused-lables.stderr +++ b/src/test/ui/macros/format-unused-lables.stderr @@ -13,7 +13,7 @@ error: multiple unused formatting arguments | LL | println!("Test2", | ------- multiple missing formatting specifiers -LL | 123, //~ ERROR multiple unused formatting arguments +LL | 123, | ^^^ argument never used LL | 456, | ^^^ argument never used @@ -23,7 +23,7 @@ LL | 789 error: named argument never used --> $DIR/format-unused-lables.rs:11:35 | -LL | println!("Some stuff", UNUSED="args"); //~ ERROR named argument never used +LL | println!("Some stuff", UNUSED="args"); | ------------ ^^^^^^ named argument never used | | | formatting specifier missing @@ -36,7 +36,7 @@ LL | println!("Some more $STUFF", | | | | | help: format specifiers use curly braces: `{STUFF}` | multiple missing formatting specifiers -LL | "woo!", //~ ERROR multiple unused formatting arguments +LL | "woo!", | ^^^^^^ argument never used LL | STUFF= LL | "things" diff --git a/src/test/ui/macros/global-asm.stderr b/src/test/ui/macros/global-asm.stderr index 94664c96db391..c43bf83fe1912 100644 --- a/src/test/ui/macros/global-asm.stderr +++ b/src/test/ui/macros/global-asm.stderr @@ -1,19 +1,19 @@ error: macro requires a string literal as an argument --> $DIR/global-asm.rs:4:5 | -LL | global_asm!(); //~ ERROR requires a string literal as an argument +LL | global_asm!(); | ^^^^^^^^^^^^^^ string literal required error: expected expression, found keyword `struct` --> $DIR/global-asm.rs:5:17 | -LL | global_asm!(struct); //~ ERROR expected expression +LL | global_asm!(struct); | ^^^^^^ expected expression error: inline assembly must be a string literal --> $DIR/global-asm.rs:6:17 | -LL | global_asm!(123); //~ ERROR inline assembly must be a string literal +LL | global_asm!(123); | ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr index e27056b412a0f..b0fafdc3b6326 100644 --- a/src/test/ui/macros/issue-54441.stderr +++ b/src/test/ui/macros/issue-54441.stderr @@ -1,7 +1,7 @@ error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found `let` --> $DIR/issue-54441.rs:5:9 | -LL | let //~ ERROR expected +LL | let | ^^^ unexpected token ... LL | m!(); diff --git a/src/test/ui/macros/issue-61033-1.rs b/src/test/ui/macros/issue-61033-1.rs new file mode 100644 index 0000000000000..8f85dec017f2a --- /dev/null +++ b/src/test/ui/macros/issue-61033-1.rs @@ -0,0 +1,9 @@ +// Regression test for issue #61033. + +macro_rules! test1 { + ($x:ident, $($tt:tt)*) => { $($tt)+ } //~ERROR this must repeat at least once +} + +fn main() { + test1!(x,); +} diff --git a/src/test/ui/macros/issue-61033-1.stderr b/src/test/ui/macros/issue-61033-1.stderr new file mode 100644 index 0000000000000..f3c68f4928dbb --- /dev/null +++ b/src/test/ui/macros/issue-61033-1.stderr @@ -0,0 +1,8 @@ +error: this must repeat at least once + --> $DIR/issue-61033-1.rs:4:34 + | +LL | ($x:ident, $($tt:tt)*) => { $($tt)+ } + | ^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/macros/issue-61033-2.rs b/src/test/ui/macros/issue-61033-2.rs new file mode 100644 index 0000000000000..0799be10b96c7 --- /dev/null +++ b/src/test/ui/macros/issue-61033-2.rs @@ -0,0 +1,19 @@ +// Regression test for issue #61033. + +macro_rules! test2 { + ( + $(* $id1:ident)* + $(+ $id2:ident)* + ) => { + $( //~ERROR meta-variable `id1` repeats 2 times + $id1 + $id2 // $id1 and $id2 may repeat different numbers of times + )* + } +} + +fn main() { + test2! { + * a * b + + a + b + c + } +} diff --git a/src/test/ui/macros/issue-61033-2.stderr b/src/test/ui/macros/issue-61033-2.stderr new file mode 100644 index 0000000000000..bf502919cf794 --- /dev/null +++ b/src/test/ui/macros/issue-61033-2.stderr @@ -0,0 +1,11 @@ +error: meta-variable `id1` repeats 2 times, but `id2` repeats 3 times + --> $DIR/issue-61033-2.rs:8:10 + | +LL | $( + | __________^ +LL | | $id1 + $id2 // $id1 and $id2 may repeat different numbers of times +LL | | )* + | |_________^ + +error: aborting due to previous error + diff --git a/src/test/ui/macros/macro-at-most-once-rep-2015-ques-rep.rs b/src/test/ui/macros/macro-at-most-once-rep-2015-ques-rep.rs deleted file mode 100644 index 2d8d2ecf9d7b4..0000000000000 --- a/src/test/ui/macros/macro-at-most-once-rep-2015-ques-rep.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Test behavior of `?` macro _kleene op_ under the 2015 edition. Namely, it doesn't exist. - -// edition:2015 - -macro_rules! bar { - ($(a)?) => {} //~ERROR expected `*` or `+` -} - -macro_rules! baz { - ($(a),?) => {} //~ERROR expected `*` or `+` -} - -fn main() {} diff --git a/src/test/ui/macros/macro-at-most-once-rep-2015-ques-rep.stderr b/src/test/ui/macros/macro-at-most-once-rep-2015-ques-rep.stderr deleted file mode 100644 index cb0a9163b7470..0000000000000 --- a/src/test/ui/macros/macro-at-most-once-rep-2015-ques-rep.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: expected `*` or `+` - --> $DIR/macro-at-most-once-rep-2015-ques-rep.rs:6:10 - | -LL | ($(a)?) => {} //~ERROR expected `*` or `+` - | ^ - | - = note: `?` is not a macro repetition operator in the 2015 edition, but is accepted in the 2018 edition - -error: expected `*` or `+` - --> $DIR/macro-at-most-once-rep-2015-ques-rep.rs:10:11 - | -LL | ($(a),?) => {} //~ERROR expected `*` or `+` - | ^ - | - = note: `?` is not a macro repetition operator in the 2015 edition, but is accepted in the 2018 edition - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/macros/macro-at-most-once-rep-2015-ques-sep.rs b/src/test/ui/macros/macro-at-most-once-rep-2015-ques-sep.rs deleted file mode 100644 index c8c920ff3f87a..0000000000000 --- a/src/test/ui/macros/macro-at-most-once-rep-2015-ques-sep.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Test behavior of `?` macro _separator_ under the 2015 edition. Namely, `?` can be used as a -// separator, but you get a migration warning for the edition. - -// edition:2015 -// compile-pass - -#![warn(rust_2018_compatibility)] - -macro_rules! bar { - ($(a)?*) => {} //~WARN using `?` as a separator - //~^WARN this was previously accepted -} - -macro_rules! baz { - ($(a)?+) => {} //~WARN using `?` as a separator - //~^WARN this was previously accepted -} - -fn main() { - bar!(); - bar!(a); - bar!(a?a); - bar!(a?a?a?a?a); - - baz!(a); - baz!(a?a); - baz!(a?a?a?a?a); -} diff --git a/src/test/ui/macros/macro-at-most-once-rep-2015-ques-sep.stderr b/src/test/ui/macros/macro-at-most-once-rep-2015-ques-sep.stderr deleted file mode 100644 index b171cf8b34df7..0000000000000 --- a/src/test/ui/macros/macro-at-most-once-rep-2015-ques-sep.stderr +++ /dev/null @@ -1,24 +0,0 @@ -warning: using `?` as a separator is deprecated and will be a hard error in an upcoming edition - --> $DIR/macro-at-most-once-rep-2015-ques-sep.rs:10:10 - | -LL | ($(a)?*) => {} //~WARN using `?` as a separator - | ^ - | -note: lint level defined here - --> $DIR/macro-at-most-once-rep-2015-ques-sep.rs:7:9 - | -LL | #![warn(rust_2018_compatibility)] - | ^^^^^^^^^^^^^^^^^^^^^^^ - = note: #[warn(question_mark_macro_sep)] implied by #[warn(rust_2018_compatibility)] - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! - = note: for more information, see issue #48075 - -warning: using `?` as a separator is deprecated and will be a hard error in an upcoming edition - --> $DIR/macro-at-most-once-rep-2015-ques-sep.rs:15:10 - | -LL | ($(a)?+) => {} //~WARN using `?` as a separator - | ^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! - = note: for more information, see issue #48075 - diff --git a/src/test/ui/macros/macro-at-most-once-rep-2015.rs b/src/test/ui/macros/macro-at-most-once-rep-2015.rs new file mode 100644 index 0000000000000..f68100d4557d6 --- /dev/null +++ b/src/test/ui/macros/macro-at-most-once-rep-2015.rs @@ -0,0 +1,42 @@ +// Tests that `?` is a Kleene op and not a macro separator in the 2015 edition. + +// edition:2015 + +macro_rules! foo { + ($(a)?) => {}; +} + +// The Kleene op `?` does not admit a separator before it. +macro_rules! baz { + ($(a),?) => {}; //~ERROR the `?` macro repetition operator +} + +macro_rules! barplus { + ($(a)?+) => {}; // ok. matches "a+" and "+" +} + +macro_rules! barstar { + ($(a)?*) => {}; // ok. matches "a*" and "*" +} + +pub fn main() { + foo!(); + foo!(a); + foo!(a?); //~ ERROR no rules expected the token `?` + foo!(a?a); //~ ERROR no rules expected the token `?` + foo!(a?a?a); //~ ERROR no rules expected the token `?` + + barplus!(); //~ERROR unexpected end of macro invocation + barplus!(a); //~ERROR unexpected end of macro invocation + barplus!(a?); //~ ERROR no rules expected the token `?` + barplus!(a?a); //~ ERROR no rules expected the token `?` + barplus!(a+); + barplus!(+); + + barstar!(); //~ERROR unexpected end of macro invocation + barstar!(a); //~ERROR unexpected end of macro invocation + barstar!(a?); //~ ERROR no rules expected the token `?` + barstar!(a?a); //~ ERROR no rules expected the token `?` + barstar!(a*); + barstar!(*); +} diff --git a/src/test/ui/macros/macro-at-most-once-rep-2015.stderr b/src/test/ui/macros/macro-at-most-once-rep-2015.stderr new file mode 100644 index 0000000000000..f9871ab8ffe0c --- /dev/null +++ b/src/test/ui/macros/macro-at-most-once-rep-2015.stderr @@ -0,0 +1,107 @@ +error: the `?` macro repetition operator does not take a separator + --> $DIR/macro-at-most-once-rep-2015.rs:11:10 + | +LL | ($(a),?) => {}; + | ^ + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:25:11 + | +LL | macro_rules! foo { + | ---------------- when calling this macro +... +LL | foo!(a?); + | ^ no rules expected this token in macro call + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:26:11 + | +LL | macro_rules! foo { + | ---------------- when calling this macro +... +LL | foo!(a?a); + | ^ no rules expected this token in macro call + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:27:11 + | +LL | macro_rules! foo { + | ---------------- when calling this macro +... +LL | foo!(a?a?a); + | ^ no rules expected this token in macro call + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-2015.rs:29:5 + | +LL | macro_rules! barplus { + | -------------------- when calling this macro +... +LL | barplus!(); + | ^^^^^^^^^^^ missing tokens in macro arguments + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-2015.rs:30:15 + | +LL | macro_rules! barplus { + | -------------------- when calling this macro +... +LL | barplus!(a); + | ^ missing tokens in macro arguments + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:31:15 + | +LL | macro_rules! barplus { + | -------------------- when calling this macro +... +LL | barplus!(a?); + | ^ no rules expected this token in macro call + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:32:15 + | +LL | macro_rules! barplus { + | -------------------- when calling this macro +... +LL | barplus!(a?a); + | ^ no rules expected this token in macro call + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-2015.rs:36:5 + | +LL | macro_rules! barstar { + | -------------------- when calling this macro +... +LL | barstar!(); + | ^^^^^^^^^^^ missing tokens in macro arguments + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-2015.rs:37:15 + | +LL | macro_rules! barstar { + | -------------------- when calling this macro +... +LL | barstar!(a); + | ^ missing tokens in macro arguments + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:38:15 + | +LL | macro_rules! barstar { + | -------------------- when calling this macro +... +LL | barstar!(a?); + | ^ no rules expected this token in macro call + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:39:15 + | +LL | macro_rules! barstar { + | -------------------- when calling this macro +... +LL | barstar!(a?a); + | ^ no rules expected this token in macro call + +error: aborting due to 12 previous errors + diff --git a/src/test/ui/macros/macro-at-most-once-rep-2018.rs b/src/test/ui/macros/macro-at-most-once-rep-2018.rs index da072adec1516..886a25bbcbcb2 100644 --- a/src/test/ui/macros/macro-at-most-once-rep-2018.rs +++ b/src/test/ui/macros/macro-at-most-once-rep-2018.rs @@ -6,6 +6,7 @@ macro_rules! foo { ($(a)?) => {}; } +// The Kleene op `?` does not admit a separator before it. macro_rules! baz { ($(a),?) => {}; //~ERROR the `?` macro repetition operator } diff --git a/src/test/ui/macros/macro-at-most-once-rep-2018.stderr b/src/test/ui/macros/macro-at-most-once-rep-2018.stderr index 657c7e54d9768..bfe5883b03fa0 100644 --- a/src/test/ui/macros/macro-at-most-once-rep-2018.stderr +++ b/src/test/ui/macros/macro-at-most-once-rep-2018.stderr @@ -1,106 +1,106 @@ error: the `?` macro repetition operator does not take a separator - --> $DIR/macro-at-most-once-rep-2018.rs:10:10 + --> $DIR/macro-at-most-once-rep-2018.rs:11:10 | -LL | ($(a),?) => {}; //~ERROR the `?` macro repetition operator +LL | ($(a),?) => {}; | ^ error: no rules expected the token `?` - --> $DIR/macro-at-most-once-rep-2018.rs:24:11 + --> $DIR/macro-at-most-once-rep-2018.rs:25:11 | LL | macro_rules! foo { | ---------------- when calling this macro ... -LL | foo!(a?); //~ ERROR no rules expected the token `?` +LL | foo!(a?); | ^ no rules expected this token in macro call error: no rules expected the token `?` - --> $DIR/macro-at-most-once-rep-2018.rs:25:11 + --> $DIR/macro-at-most-once-rep-2018.rs:26:11 | LL | macro_rules! foo { | ---------------- when calling this macro ... -LL | foo!(a?a); //~ ERROR no rules expected the token `?` +LL | foo!(a?a); | ^ no rules expected this token in macro call error: no rules expected the token `?` - --> $DIR/macro-at-most-once-rep-2018.rs:26:11 + --> $DIR/macro-at-most-once-rep-2018.rs:27:11 | LL | macro_rules! foo { | ---------------- when calling this macro ... -LL | foo!(a?a?a); //~ ERROR no rules expected the token `?` +LL | foo!(a?a?a); | ^ no rules expected this token in macro call error: unexpected end of macro invocation - --> $DIR/macro-at-most-once-rep-2018.rs:28:5 + --> $DIR/macro-at-most-once-rep-2018.rs:29:5 | LL | macro_rules! barplus { | -------------------- when calling this macro ... -LL | barplus!(); //~ERROR unexpected end of macro invocation +LL | barplus!(); | ^^^^^^^^^^^ missing tokens in macro arguments error: unexpected end of macro invocation - --> $DIR/macro-at-most-once-rep-2018.rs:29:15 + --> $DIR/macro-at-most-once-rep-2018.rs:30:15 | LL | macro_rules! barplus { | -------------------- when calling this macro ... -LL | barplus!(a); //~ERROR unexpected end of macro invocation +LL | barplus!(a); | ^ missing tokens in macro arguments error: no rules expected the token `?` - --> $DIR/macro-at-most-once-rep-2018.rs:30:15 + --> $DIR/macro-at-most-once-rep-2018.rs:31:15 | LL | macro_rules! barplus { | -------------------- when calling this macro ... -LL | barplus!(a?); //~ ERROR no rules expected the token `?` +LL | barplus!(a?); | ^ no rules expected this token in macro call error: no rules expected the token `?` - --> $DIR/macro-at-most-once-rep-2018.rs:31:15 + --> $DIR/macro-at-most-once-rep-2018.rs:32:15 | LL | macro_rules! barplus { | -------------------- when calling this macro ... -LL | barplus!(a?a); //~ ERROR no rules expected the token `?` +LL | barplus!(a?a); | ^ no rules expected this token in macro call error: unexpected end of macro invocation - --> $DIR/macro-at-most-once-rep-2018.rs:35:5 + --> $DIR/macro-at-most-once-rep-2018.rs:36:5 | LL | macro_rules! barstar { | -------------------- when calling this macro ... -LL | barstar!(); //~ERROR unexpected end of macro invocation +LL | barstar!(); | ^^^^^^^^^^^ missing tokens in macro arguments error: unexpected end of macro invocation - --> $DIR/macro-at-most-once-rep-2018.rs:36:15 + --> $DIR/macro-at-most-once-rep-2018.rs:37:15 | LL | macro_rules! barstar { | -------------------- when calling this macro ... -LL | barstar!(a); //~ERROR unexpected end of macro invocation +LL | barstar!(a); | ^ missing tokens in macro arguments error: no rules expected the token `?` - --> $DIR/macro-at-most-once-rep-2018.rs:37:15 + --> $DIR/macro-at-most-once-rep-2018.rs:38:15 | LL | macro_rules! barstar { | -------------------- when calling this macro ... -LL | barstar!(a?); //~ ERROR no rules expected the token `?` +LL | barstar!(a?); | ^ no rules expected this token in macro call error: no rules expected the token `?` - --> $DIR/macro-at-most-once-rep-2018.rs:38:15 + --> $DIR/macro-at-most-once-rep-2018.rs:39:15 | LL | macro_rules! barstar { | -------------------- when calling this macro ... -LL | barstar!(a?a); //~ ERROR no rules expected the token `?` +LL | barstar!(a?a); | ^ no rules expected this token in macro call error: aborting due to 12 previous errors diff --git a/src/test/ui/macros/macro-attribute.stderr b/src/test/ui/macros/macro-attribute.stderr index 7314e48334893..d28ce25341d3a 100644 --- a/src/test/ui/macros/macro-attribute.stderr +++ b/src/test/ui/macros/macro-attribute.stderr @@ -1,8 +1,8 @@ error: unexpected token: `$` - --> $DIR/macro-attribute.rs:1:7 + --> $DIR/macro-attribute.rs:1:9 | -LL | #[doc = $not_there] //~ ERROR unexpected token: `$` - | ^ +LL | #[doc = $not_there] + | ^ error: aborting due to previous error diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr index 353ae1d0ea698..015e05ed9bf61 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `fake` found for type `{integer}` in the current scope --> $DIR/macro-backtrace-invalid-internals.rs:5:13 | -LL | 1.fake() //~ ERROR no method +LL | 1.fake() | ^^^^ ... LL | fake_method_stmt!(); @@ -10,7 +10,7 @@ LL | fake_method_stmt!(); error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> $DIR/macro-backtrace-invalid-internals.rs:11:13 | -LL | 1.fake //~ ERROR doesn't have fields +LL | 1.fake | ^^^^ ... LL | fake_field_stmt!(); @@ -19,7 +19,7 @@ LL | fake_field_stmt!(); error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> $DIR/macro-backtrace-invalid-internals.rs:17:15 | -LL | (1).0 //~ ERROR doesn't have fields +LL | (1).0 | ^ ... LL | fake_anon_field_stmt!(); @@ -28,20 +28,20 @@ LL | fake_anon_field_stmt!(); error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` --> $DIR/macro-backtrace-invalid-internals.rs:41:15 | -LL | 2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` +LL | 2.0.neg() | ^^^ ... LL | real_method_stmt!(); | -------------------- in this macro invocation help: you must specify a concrete type for this numeric value, like `f32` | -LL | 2.0_f32.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` +LL | 2.0_f32.neg() | ^^^^^^^ error[E0599]: no method named `fake` found for type `{integer}` in the current scope --> $DIR/macro-backtrace-invalid-internals.rs:23:13 | -LL | 1.fake() //~ ERROR no method +LL | 1.fake() | ^^^^ ... LL | let _ = fake_method_expr!(); @@ -50,7 +50,7 @@ LL | let _ = fake_method_expr!(); error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> $DIR/macro-backtrace-invalid-internals.rs:29:13 | -LL | 1.fake //~ ERROR doesn't have fields +LL | 1.fake | ^^^^ ... LL | let _ = fake_field_expr!(); @@ -59,7 +59,7 @@ LL | let _ = fake_field_expr!(); error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> $DIR/macro-backtrace-invalid-internals.rs:35:15 | -LL | (1).0 //~ ERROR doesn't have fields +LL | (1).0 | ^ ... LL | let _ = fake_anon_field_expr!(); @@ -68,17 +68,17 @@ LL | let _ = fake_anon_field_expr!(); error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` --> $DIR/macro-backtrace-invalid-internals.rs:47:15 | -LL | 2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` +LL | 2.0.neg() | ^^^ ... LL | let _ = real_method_expr!(); | ------------------- in this macro invocation help: you must specify a concrete type for this numeric value, like `f32` | -LL | 2.0_f32.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` +LL | 2.0_f32.neg() | ^^^^^^^ error: aborting due to 8 previous errors -Some errors occurred: E0599, E0610, E0689. +Some errors have detailed explanations: E0599, E0610, E0689. For more information about an error, try `rustc --explain E0599`. diff --git a/src/test/ui/macros/macro-backtrace-nested.stderr b/src/test/ui/macros/macro-backtrace-nested.stderr index 61a11231efef5..501f525a05f77 100644 --- a/src/test/ui/macros/macro-backtrace-nested.stderr +++ b/src/test/ui/macros/macro-backtrace-nested.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `fake` in this scope --> $DIR/macro-backtrace-nested.rs:5:12 | -LL | () => (fake) //~ ERROR cannot find +LL | () => (fake) | ^^^^ not found in this scope ... LL | 1 + call_nested_expr!(); @@ -10,7 +10,7 @@ LL | 1 + call_nested_expr!(); error[E0425]: cannot find value `fake` in this scope --> $DIR/macro-backtrace-nested.rs:5:12 | -LL | () => (fake) //~ ERROR cannot find +LL | () => (fake) | ^^^^ not found in this scope ... LL | call_nested_expr_sum!(); diff --git a/src/test/ui/macros/macro-backtrace-println.stderr b/src/test/ui/macros/macro-backtrace-println.stderr index c24a88c4159fd..209ff09aea41b 100644 --- a/src/test/ui/macros/macro-backtrace-println.stderr +++ b/src/test/ui/macros/macro-backtrace-println.stderr @@ -1,7 +1,7 @@ error: 1 positional argument in format string, but no arguments were given --> $DIR/macro-backtrace-println.rs:14:30 | -LL | ($fmt:expr) => (myprint!(concat!($fmt, "/n"))); //~ ERROR no arguments were given +LL | ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); | ^^^^^^^^^^^^^^^^^^^ ... LL | myprintln!("{}"); diff --git a/src/test/ui/macros/macro-comma-support.stderr b/src/test/ui/macros/macro-comma-support.stderr index a4bb8a9b32fb2..28d064f7f5bd2 100644 --- a/src/test/ui/macros/macro-comma-support.stderr +++ b/src/test/ui/macros/macro-comma-support.stderr @@ -1,13 +1,13 @@ error: lel --> $DIR/macro-comma-support.rs:6:5 | -LL | compile_error!("lel"); //~ ERROR lel +LL | compile_error!("lel"); | ^^^^^^^^^^^^^^^^^^^^^^ error: lel --> $DIR/macro-comma-support.rs:7:5 | -LL | compile_error!("lel",); //~ ERROR lel +LL | compile_error!("lel",); | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/macros/macro-context.stderr b/src/test/ui/macros/macro-context.stderr index 9a4a8e31985fb..2a0779190f573 100644 --- a/src/test/ui/macros/macro-context.stderr +++ b/src/test/ui/macros/macro-context.stderr @@ -1,7 +1,7 @@ error: macro expansion ignores token `;` and any following --> $DIR/macro-context.rs:3:15 | -LL | () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof` +LL | () => ( i ; typeof ); | ^ ... LL | let a: m!(); @@ -12,7 +12,7 @@ LL | let a: m!(); error: macro expansion ignores token `typeof` and any following --> $DIR/macro-context.rs:3:17 | -LL | () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof` +LL | () => ( i ; typeof ); | ^^^^^^ ... LL | let i = m!(); @@ -23,7 +23,7 @@ LL | let i = m!(); error: macro expansion ignores token `;` and any following --> $DIR/macro-context.rs:3:15 | -LL | () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof` +LL | () => ( i ; typeof ); | ^ ... LL | m!() => {} @@ -34,7 +34,7 @@ LL | m!() => {} error: expected expression, found reserved keyword `typeof` --> $DIR/macro-context.rs:3:17 | -LL | () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof` +LL | () => ( i ; typeof ); | ^^^^^^ expected expression ... LL | m!(); diff --git a/src/test/ui/macros/macro-crate-nonterminal-non-root.stderr b/src/test/ui/macros/macro-crate-nonterminal-non-root.stderr index a1af9ba175845..1eca0186da955 100644 --- a/src/test/ui/macros/macro-crate-nonterminal-non-root.stderr +++ b/src/test/ui/macros/macro-crate-nonterminal-non-root.stderr @@ -1,7 +1,7 @@ error[E0468]: an `extern crate` loading macros must be at the crate root --> $DIR/macro-crate-nonterminal-non-root.rs:5:5 | -LL | extern crate macro_crate_nonterminal; //~ ERROR must be at the crate root +LL | extern crate macro_crate_nonterminal; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/macros/macro-error.stderr b/src/test/ui/macros/macro-error.stderr index f56b67e7cd06a..b3aed8c2cef24 100644 --- a/src/test/ui/macros/macro-error.stderr +++ b/src/test/ui/macros/macro-error.stderr @@ -1,13 +1,13 @@ error: macro rhs must be delimited --> $DIR/macro-error.rs:2:18 | -LL | ($a:expr) => a; //~ ERROR macro rhs must be delimited +LL | ($a:expr) => a; | ^ error: non-type macro in type position: cfg --> $DIR/macro-error.rs:8:12 | -LL | let _: cfg!(foo) = (); //~ ERROR non-type macro in type position +LL | let _: cfg!(foo) = (); | ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/macros/macro-follow.rs b/src/test/ui/macros/macro-follow.rs index 10b44e0017532..8054418d9b893 100644 --- a/src/test/ui/macros/macro-follow.rs +++ b/src/test/ui/macros/macro-follow.rs @@ -112,4 +112,3 @@ macro_rules! follow_path { // FOLLOW(ident) = any token fn main() {} - diff --git a/src/test/ui/macros/macro-follow.stderr b/src/test/ui/macros/macro-follow.stderr index e3302eac4ac08..d3f081bb4a28f 100644 --- a/src/test/ui/macros/macro-follow.stderr +++ b/src/test/ui/macros/macro-follow.stderr @@ -1,7 +1,7 @@ error: `$p:pat` is followed by `(`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:8:14 | -LL | ($p:pat ()) => {}; //~ERROR `$p:pat` is followed by `(` +LL | ($p:pat ()) => {}; | ^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -9,7 +9,7 @@ LL | ($p:pat ()) => {}; //~ERROR `$p:pat` is followed by `(` error: `$p:pat` is followed by `[`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:9:14 | -LL | ($p:pat []) => {}; //~ERROR `$p:pat` is followed by `[` +LL | ($p:pat []) => {}; | ^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -17,7 +17,7 @@ LL | ($p:pat []) => {}; //~ERROR `$p:pat` is followed by `[` error: `$p:pat` is followed by `{`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:10:14 | -LL | ($p:pat {}) => {}; //~ERROR `$p:pat` is followed by `{` +LL | ($p:pat {}) => {}; | ^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -25,7 +25,7 @@ LL | ($p:pat {}) => {}; //~ERROR `$p:pat` is followed by `{` error: `$p:pat` is followed by `:`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:11:13 | -LL | ($p:pat :) => {}; //~ERROR `$p:pat` is followed by `:` +LL | ($p:pat :) => {}; | ^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -33,7 +33,7 @@ LL | ($p:pat :) => {}; //~ERROR `$p:pat` is followed by `:` error: `$p:pat` is followed by `>`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:12:13 | -LL | ($p:pat >) => {}; //~ERROR `$p:pat` is followed by `>` +LL | ($p:pat >) => {}; | ^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -41,7 +41,7 @@ LL | ($p:pat >) => {}; //~ERROR `$p:pat` is followed by `>` error: `$p:pat` is followed by `+`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:13:13 | -LL | ($p:pat +) => {}; //~ERROR `$p:pat` is followed by `+` +LL | ($p:pat +) => {}; | ^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -49,7 +49,7 @@ LL | ($p:pat +) => {}; //~ERROR `$p:pat` is followed by `+` error: `$p:pat` is followed by `ident`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:14:13 | -LL | ($p:pat ident) => {}; //~ERROR `$p:pat` is followed by `ident` +LL | ($p:pat ident) => {}; | ^^^^^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -57,7 +57,7 @@ LL | ($p:pat ident) => {}; //~ERROR `$p:pat` is followed by `ident` error: `$p:pat` is followed by `$q:pat`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:15:13 | -LL | ($p:pat $q:pat) => {}; //~ERROR `$p:pat` is followed by `$q:pat` +LL | ($p:pat $q:pat) => {}; | ^^^^^^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -65,7 +65,7 @@ LL | ($p:pat $q:pat) => {}; //~ERROR `$p:pat` is followed by `$q:pat` error: `$p:pat` is followed by `$e:expr`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:16:13 | -LL | ($p:pat $e:expr) => {}; //~ERROR `$p:pat` is followed by `$e:expr` +LL | ($p:pat $e:expr) => {}; | ^^^^^^^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -73,7 +73,7 @@ LL | ($p:pat $e:expr) => {}; //~ERROR `$p:pat` is followed by `$e:expr` error: `$p:pat` is followed by `$t:ty`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:17:13 | -LL | ($p:pat $t:ty) => {}; //~ERROR `$p:pat` is followed by `$t:ty` +LL | ($p:pat $t:ty) => {}; | ^^^^^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -81,7 +81,7 @@ LL | ($p:pat $t:ty) => {}; //~ERROR `$p:pat` is followed by `$t:ty` error: `$p:pat` is followed by `$s:stmt`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:18:13 | -LL | ($p:pat $s:stmt) => {}; //~ERROR `$p:pat` is followed by `$s:stmt` +LL | ($p:pat $s:stmt) => {}; | ^^^^^^^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -89,7 +89,7 @@ LL | ($p:pat $s:stmt) => {}; //~ERROR `$p:pat` is followed by `$s:stmt` error: `$p:pat` is followed by `$q:path`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:19:13 | -LL | ($p:pat $q:path) => {}; //~ERROR `$p:pat` is followed by `$q:path` +LL | ($p:pat $q:path) => {}; | ^^^^^^^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -97,7 +97,7 @@ LL | ($p:pat $q:path) => {}; //~ERROR `$p:pat` is followed by `$q:path` error: `$p:pat` is followed by `$b:block`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:20:13 | -LL | ($p:pat $b:block) => {}; //~ERROR `$p:pat` is followed by `$b:block` +LL | ($p:pat $b:block) => {}; | ^^^^^^^^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -105,7 +105,7 @@ LL | ($p:pat $b:block) => {}; //~ERROR `$p:pat` is followed by `$b:block` error: `$p:pat` is followed by `$i:ident`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:21:13 | -LL | ($p:pat $i:ident) => {}; //~ERROR `$p:pat` is followed by `$i:ident` +LL | ($p:pat $i:ident) => {}; | ^^^^^^^^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -113,7 +113,7 @@ LL | ($p:pat $i:ident) => {}; //~ERROR `$p:pat` is followed by `$i:ident` error: `$p:pat` is followed by `$t:tt`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:22:13 | -LL | ($p:pat $t:tt) => {}; //~ERROR `$p:pat` is followed by `$t:tt` +LL | ($p:pat $t:tt) => {}; | ^^^^^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -121,7 +121,7 @@ LL | ($p:pat $t:tt) => {}; //~ERROR `$p:pat` is followed by `$t:tt` error: `$p:pat` is followed by `$i:item`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:23:13 | -LL | ($p:pat $i:item) => {}; //~ERROR `$p:pat` is followed by `$i:item` +LL | ($p:pat $i:item) => {}; | ^^^^^^^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -129,7 +129,7 @@ LL | ($p:pat $i:item) => {}; //~ERROR `$p:pat` is followed by `$i:item` error: `$p:pat` is followed by `$m:meta`, which is not allowed for `pat` fragments --> $DIR/macro-follow.rs:24:13 | -LL | ($p:pat $m:meta) => {}; //~ERROR `$p:pat` is followed by `$m:meta` +LL | ($p:pat $m:meta) => {}; | ^^^^^^^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -137,7 +137,7 @@ LL | ($p:pat $m:meta) => {}; //~ERROR `$p:pat` is followed by `$m:meta` error: `$e:expr` is followed by `(`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:28:15 | -LL | ($e:expr ()) => {}; //~ERROR `$e:expr` is followed by `(` +LL | ($e:expr ()) => {}; | ^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -145,7 +145,7 @@ LL | ($e:expr ()) => {}; //~ERROR `$e:expr` is followed by `(` error: `$e:expr` is followed by `[`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:29:15 | -LL | ($e:expr []) => {}; //~ERROR `$e:expr` is followed by `[` +LL | ($e:expr []) => {}; | ^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -153,7 +153,7 @@ LL | ($e:expr []) => {}; //~ERROR `$e:expr` is followed by `[` error: `$e:expr` is followed by `{`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:30:15 | -LL | ($e:expr {}) => {}; //~ERROR `$e:expr` is followed by `{` +LL | ($e:expr {}) => {}; | ^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -161,7 +161,7 @@ LL | ($e:expr {}) => {}; //~ERROR `$e:expr` is followed by `{` error: `$e:expr` is followed by `=`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:31:14 | -LL | ($e:expr =) => {}; //~ERROR `$e:expr` is followed by `=` +LL | ($e:expr =) => {}; | ^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -169,7 +169,7 @@ LL | ($e:expr =) => {}; //~ERROR `$e:expr` is followed by `=` error: `$e:expr` is followed by `|`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:32:14 | -LL | ($e:expr |) => {}; //~ERROR `$e:expr` is followed by `|` +LL | ($e:expr |) => {}; | ^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -177,7 +177,7 @@ LL | ($e:expr |) => {}; //~ERROR `$e:expr` is followed by `|` error: `$e:expr` is followed by `:`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:33:14 | -LL | ($e:expr :) => {}; //~ERROR `$e:expr` is followed by `:` +LL | ($e:expr :) => {}; | ^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -185,7 +185,7 @@ LL | ($e:expr :) => {}; //~ERROR `$e:expr` is followed by `:` error: `$e:expr` is followed by `>`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:34:14 | -LL | ($e:expr >) => {}; //~ERROR `$e:expr` is followed by `>` +LL | ($e:expr >) => {}; | ^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -193,7 +193,7 @@ LL | ($e:expr >) => {}; //~ERROR `$e:expr` is followed by `>` error: `$e:expr` is followed by `+`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:35:14 | -LL | ($e:expr +) => {}; //~ERROR `$e:expr` is followed by `+` +LL | ($e:expr +) => {}; | ^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -201,7 +201,7 @@ LL | ($e:expr +) => {}; //~ERROR `$e:expr` is followed by `+` error: `$e:expr` is followed by `ident`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:36:14 | -LL | ($e:expr ident) => {}; //~ERROR `$e:expr` is followed by `ident` +LL | ($e:expr ident) => {}; | ^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -209,7 +209,7 @@ LL | ($e:expr ident) => {}; //~ERROR `$e:expr` is followed by `ident` error: `$e:expr` is followed by `if`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:37:14 | -LL | ($e:expr if) => {}; //~ERROR `$e:expr` is followed by `if` +LL | ($e:expr if) => {}; | ^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -217,7 +217,7 @@ LL | ($e:expr if) => {}; //~ERROR `$e:expr` is followed by `if` error: `$e:expr` is followed by `in`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:38:14 | -LL | ($e:expr in) => {}; //~ERROR `$e:expr` is followed by `in` +LL | ($e:expr in) => {}; | ^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -225,7 +225,7 @@ LL | ($e:expr in) => {}; //~ERROR `$e:expr` is followed by `in` error: `$e:expr` is followed by `$p:pat`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:39:14 | -LL | ($e:expr $p:pat) => {}; //~ERROR `$e:expr` is followed by `$p:pat` +LL | ($e:expr $p:pat) => {}; | ^^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -233,7 +233,7 @@ LL | ($e:expr $p:pat) => {}; //~ERROR `$e:expr` is followed by `$p:pat` error: `$e:expr` is followed by `$f:expr`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:40:14 | -LL | ($e:expr $f:expr) => {}; //~ERROR `$e:expr` is followed by `$f:expr` +LL | ($e:expr $f:expr) => {}; | ^^^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -241,7 +241,7 @@ LL | ($e:expr $f:expr) => {}; //~ERROR `$e:expr` is followed by `$f:expr` error: `$e:expr` is followed by `$t:ty`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:41:14 | -LL | ($e:expr $t:ty) => {}; //~ERROR `$e:expr` is followed by `$t:ty` +LL | ($e:expr $t:ty) => {}; | ^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -249,7 +249,7 @@ LL | ($e:expr $t:ty) => {}; //~ERROR `$e:expr` is followed by `$t:ty` error: `$e:expr` is followed by `$s:stmt`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:42:14 | -LL | ($e:expr $s:stmt) => {}; //~ERROR `$e:expr` is followed by `$s:stmt` +LL | ($e:expr $s:stmt) => {}; | ^^^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -257,7 +257,7 @@ LL | ($e:expr $s:stmt) => {}; //~ERROR `$e:expr` is followed by `$s:stmt` error: `$e:expr` is followed by `$p:path`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:43:14 | -LL | ($e:expr $p:path) => {}; //~ERROR `$e:expr` is followed by `$p:path` +LL | ($e:expr $p:path) => {}; | ^^^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -265,7 +265,7 @@ LL | ($e:expr $p:path) => {}; //~ERROR `$e:expr` is followed by `$p:path` error: `$e:expr` is followed by `$b:block`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:44:14 | -LL | ($e:expr $b:block) => {}; //~ERROR `$e:expr` is followed by `$b:block` +LL | ($e:expr $b:block) => {}; | ^^^^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -273,7 +273,7 @@ LL | ($e:expr $b:block) => {}; //~ERROR `$e:expr` is followed by `$b:block` error: `$e:expr` is followed by `$i:ident`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:45:14 | -LL | ($e:expr $i:ident) => {}; //~ERROR `$e:expr` is followed by `$i:ident` +LL | ($e:expr $i:ident) => {}; | ^^^^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -281,7 +281,7 @@ LL | ($e:expr $i:ident) => {}; //~ERROR `$e:expr` is followed by `$i:ident` error: `$e:expr` is followed by `$t:tt`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:46:14 | -LL | ($e:expr $t:tt) => {}; //~ERROR `$e:expr` is followed by `$t:tt` +LL | ($e:expr $t:tt) => {}; | ^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -289,7 +289,7 @@ LL | ($e:expr $t:tt) => {}; //~ERROR `$e:expr` is followed by `$t:tt` error: `$e:expr` is followed by `$i:item`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:47:14 | -LL | ($e:expr $i:item) => {}; //~ERROR `$e:expr` is followed by `$i:item` +LL | ($e:expr $i:item) => {}; | ^^^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -297,7 +297,7 @@ LL | ($e:expr $i:item) => {}; //~ERROR `$e:expr` is followed by `$i:item` error: `$e:expr` is followed by `$m:meta`, which is not allowed for `expr` fragments --> $DIR/macro-follow.rs:48:14 | -LL | ($e:expr $m:meta) => {}; //~ERROR `$e:expr` is followed by `$m:meta` +LL | ($e:expr $m:meta) => {}; | ^^^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -305,7 +305,7 @@ LL | ($e:expr $m:meta) => {}; //~ERROR `$e:expr` is followed by `$m:meta` error: `$t:ty` is followed by `(`, which is not allowed for `ty` fragments --> $DIR/macro-follow.rs:53:13 | -LL | ($t:ty ()) => {}; //~ERROR `$t:ty` is followed by `(` +LL | ($t:ty ()) => {}; | ^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -313,7 +313,7 @@ LL | ($t:ty ()) => {}; //~ERROR `$t:ty` is followed by `(` error: `$t:ty` is followed by `+`, which is not allowed for `ty` fragments --> $DIR/macro-follow.rs:55:12 | -LL | ($t:ty +) => {}; //~ERROR `$t:ty` is followed by `+` +LL | ($t:ty +) => {}; | ^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -321,7 +321,7 @@ LL | ($t:ty +) => {}; //~ERROR `$t:ty` is followed by `+` error: `$t:ty` is followed by `ident`, which is not allowed for `ty` fragments --> $DIR/macro-follow.rs:56:12 | -LL | ($t:ty ident) => {}; //~ERROR `$t:ty` is followed by `ident` +LL | ($t:ty ident) => {}; | ^^^^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -329,7 +329,7 @@ LL | ($t:ty ident) => {}; //~ERROR `$t:ty` is followed by `ident` error: `$t:ty` is followed by `if`, which is not allowed for `ty` fragments --> $DIR/macro-follow.rs:57:12 | -LL | ($t:ty if) => {}; //~ERROR `$t:ty` is followed by `if` +LL | ($t:ty if) => {}; | ^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -337,7 +337,7 @@ LL | ($t:ty if) => {}; //~ERROR `$t:ty` is followed by `if` error: `$t:ty` is followed by `$p:pat`, which is not allowed for `ty` fragments --> $DIR/macro-follow.rs:58:12 | -LL | ($t:ty $p:pat) => {}; //~ERROR `$t:ty` is followed by `$p:pat` +LL | ($t:ty $p:pat) => {}; | ^^^^^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -345,7 +345,7 @@ LL | ($t:ty $p:pat) => {}; //~ERROR `$t:ty` is followed by `$p:pat` error: `$t:ty` is followed by `$e:expr`, which is not allowed for `ty` fragments --> $DIR/macro-follow.rs:59:12 | -LL | ($t:ty $e:expr) => {}; //~ERROR `$t:ty` is followed by `$e:expr` +LL | ($t:ty $e:expr) => {}; | ^^^^^^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -353,7 +353,7 @@ LL | ($t:ty $e:expr) => {}; //~ERROR `$t:ty` is followed by `$e:expr` error: `$t:ty` is followed by `$r:ty`, which is not allowed for `ty` fragments --> $DIR/macro-follow.rs:60:12 | -LL | ($t:ty $r:ty) => {}; //~ERROR `$t:ty` is followed by `$r:ty` +LL | ($t:ty $r:ty) => {}; | ^^^^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -361,7 +361,7 @@ LL | ($t:ty $r:ty) => {}; //~ERROR `$t:ty` is followed by `$r:ty` error: `$t:ty` is followed by `$s:stmt`, which is not allowed for `ty` fragments --> $DIR/macro-follow.rs:61:12 | -LL | ($t:ty $s:stmt) => {}; //~ERROR `$t:ty` is followed by `$s:stmt` +LL | ($t:ty $s:stmt) => {}; | ^^^^^^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -369,7 +369,7 @@ LL | ($t:ty $s:stmt) => {}; //~ERROR `$t:ty` is followed by `$s:stmt` error: `$t:ty` is followed by `$p:path`, which is not allowed for `ty` fragments --> $DIR/macro-follow.rs:62:12 | -LL | ($t:ty $p:path) => {}; //~ERROR `$t:ty` is followed by `$p:path` +LL | ($t:ty $p:path) => {}; | ^^^^^^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -377,7 +377,7 @@ LL | ($t:ty $p:path) => {}; //~ERROR `$t:ty` is followed by `$p:path` error: `$t:ty` is followed by `$i:ident`, which is not allowed for `ty` fragments --> $DIR/macro-follow.rs:64:12 | -LL | ($t:ty $i:ident) => {}; //~ERROR `$t:ty` is followed by `$i:ident` +LL | ($t:ty $i:ident) => {}; | ^^^^^^^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -385,7 +385,7 @@ LL | ($t:ty $i:ident) => {}; //~ERROR `$t:ty` is followed by `$i:ident` error: `$t:ty` is followed by `$r:tt`, which is not allowed for `ty` fragments --> $DIR/macro-follow.rs:65:12 | -LL | ($t:ty $r:tt) => {}; //~ERROR `$t:ty` is followed by `$r:tt` +LL | ($t:ty $r:tt) => {}; | ^^^^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -393,7 +393,7 @@ LL | ($t:ty $r:tt) => {}; //~ERROR `$t:ty` is followed by `$r:tt` error: `$t:ty` is followed by `$i:item`, which is not allowed for `ty` fragments --> $DIR/macro-follow.rs:66:12 | -LL | ($t:ty $i:item) => {}; //~ERROR `$t:ty` is followed by `$i:item` +LL | ($t:ty $i:item) => {}; | ^^^^^^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -401,7 +401,7 @@ LL | ($t:ty $i:item) => {}; //~ERROR `$t:ty` is followed by `$i:item` error: `$t:ty` is followed by `$m:meta`, which is not allowed for `ty` fragments --> $DIR/macro-follow.rs:67:12 | -LL | ($t:ty $m:meta) => {}; //~ERROR `$t:ty` is followed by `$m:meta` +LL | ($t:ty $m:meta) => {}; | ^^^^^^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -409,7 +409,7 @@ LL | ($t:ty $m:meta) => {}; //~ERROR `$t:ty` is followed by `$m:meta` error: `$s:stmt` is followed by `(`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:71:15 | -LL | ($s:stmt ()) => {}; //~ERROR `$s:stmt` is followed by `(` +LL | ($s:stmt ()) => {}; | ^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -417,7 +417,7 @@ LL | ($s:stmt ()) => {}; //~ERROR `$s:stmt` is followed by `(` error: `$s:stmt` is followed by `[`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:72:15 | -LL | ($s:stmt []) => {}; //~ERROR `$s:stmt` is followed by `[` +LL | ($s:stmt []) => {}; | ^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -425,7 +425,7 @@ LL | ($s:stmt []) => {}; //~ERROR `$s:stmt` is followed by `[` error: `$s:stmt` is followed by `{`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:73:15 | -LL | ($s:stmt {}) => {}; //~ERROR `$s:stmt` is followed by `{` +LL | ($s:stmt {}) => {}; | ^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -433,7 +433,7 @@ LL | ($s:stmt {}) => {}; //~ERROR `$s:stmt` is followed by `{` error: `$s:stmt` is followed by `=`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:74:14 | -LL | ($s:stmt =) => {}; //~ERROR `$s:stmt` is followed by `=` +LL | ($s:stmt =) => {}; | ^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -441,7 +441,7 @@ LL | ($s:stmt =) => {}; //~ERROR `$s:stmt` is followed by `=` error: `$s:stmt` is followed by `|`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:75:14 | -LL | ($s:stmt |) => {}; //~ERROR `$s:stmt` is followed by `|` +LL | ($s:stmt |) => {}; | ^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -449,7 +449,7 @@ LL | ($s:stmt |) => {}; //~ERROR `$s:stmt` is followed by `|` error: `$s:stmt` is followed by `:`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:76:14 | -LL | ($s:stmt :) => {}; //~ERROR `$s:stmt` is followed by `:` +LL | ($s:stmt :) => {}; | ^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -457,7 +457,7 @@ LL | ($s:stmt :) => {}; //~ERROR `$s:stmt` is followed by `:` error: `$s:stmt` is followed by `>`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:77:14 | -LL | ($s:stmt >) => {}; //~ERROR `$s:stmt` is followed by `>` +LL | ($s:stmt >) => {}; | ^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -465,7 +465,7 @@ LL | ($s:stmt >) => {}; //~ERROR `$s:stmt` is followed by `>` error: `$s:stmt` is followed by `+`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:78:14 | -LL | ($s:stmt +) => {}; //~ERROR `$s:stmt` is followed by `+` +LL | ($s:stmt +) => {}; | ^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -473,7 +473,7 @@ LL | ($s:stmt +) => {}; //~ERROR `$s:stmt` is followed by `+` error: `$s:stmt` is followed by `ident`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:79:14 | -LL | ($s:stmt ident) => {}; //~ERROR `$s:stmt` is followed by `ident` +LL | ($s:stmt ident) => {}; | ^^^^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -481,7 +481,7 @@ LL | ($s:stmt ident) => {}; //~ERROR `$s:stmt` is followed by `ident` error: `$s:stmt` is followed by `if`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:80:14 | -LL | ($s:stmt if) => {}; //~ERROR `$s:stmt` is followed by `if` +LL | ($s:stmt if) => {}; | ^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -489,7 +489,7 @@ LL | ($s:stmt if) => {}; //~ERROR `$s:stmt` is followed by `if` error: `$s:stmt` is followed by `in`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:81:14 | -LL | ($s:stmt in) => {}; //~ERROR `$s:stmt` is followed by `in` +LL | ($s:stmt in) => {}; | ^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -497,7 +497,7 @@ LL | ($s:stmt in) => {}; //~ERROR `$s:stmt` is followed by `in` error: `$s:stmt` is followed by `$p:pat`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:82:14 | -LL | ($s:stmt $p:pat) => {}; //~ERROR `$s:stmt` is followed by `$p:pat` +LL | ($s:stmt $p:pat) => {}; | ^^^^^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -505,7 +505,7 @@ LL | ($s:stmt $p:pat) => {}; //~ERROR `$s:stmt` is followed by `$p:pat` error: `$s:stmt` is followed by `$e:expr`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:83:14 | -LL | ($s:stmt $e:expr) => {}; //~ERROR `$s:stmt` is followed by `$e:expr` +LL | ($s:stmt $e:expr) => {}; | ^^^^^^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -513,7 +513,7 @@ LL | ($s:stmt $e:expr) => {}; //~ERROR `$s:stmt` is followed by `$e:expr` error: `$s:stmt` is followed by `$t:ty`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:84:14 | -LL | ($s:stmt $t:ty) => {}; //~ERROR `$s:stmt` is followed by `$t:ty` +LL | ($s:stmt $t:ty) => {}; | ^^^^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -521,7 +521,7 @@ LL | ($s:stmt $t:ty) => {}; //~ERROR `$s:stmt` is followed by `$t:ty` error: `$s:stmt` is followed by `$t:stmt`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:85:14 | -LL | ($s:stmt $t:stmt) => {}; //~ERROR `$s:stmt` is followed by `$t:stmt` +LL | ($s:stmt $t:stmt) => {}; | ^^^^^^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -529,7 +529,7 @@ LL | ($s:stmt $t:stmt) => {}; //~ERROR `$s:stmt` is followed by `$t:stmt` error: `$s:stmt` is followed by `$p:path`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:86:14 | -LL | ($s:stmt $p:path) => {}; //~ERROR `$s:stmt` is followed by `$p:path` +LL | ($s:stmt $p:path) => {}; | ^^^^^^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -537,7 +537,7 @@ LL | ($s:stmt $p:path) => {}; //~ERROR `$s:stmt` is followed by `$p:path` error: `$s:stmt` is followed by `$b:block`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:87:14 | -LL | ($s:stmt $b:block) => {}; //~ERROR `$s:stmt` is followed by `$b:block` +LL | ($s:stmt $b:block) => {}; | ^^^^^^^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -545,7 +545,7 @@ LL | ($s:stmt $b:block) => {}; //~ERROR `$s:stmt` is followed by `$b:block` error: `$s:stmt` is followed by `$i:ident`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:88:14 | -LL | ($s:stmt $i:ident) => {}; //~ERROR `$s:stmt` is followed by `$i:ident` +LL | ($s:stmt $i:ident) => {}; | ^^^^^^^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -553,7 +553,7 @@ LL | ($s:stmt $i:ident) => {}; //~ERROR `$s:stmt` is followed by `$i:ident` error: `$s:stmt` is followed by `$t:tt`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:89:14 | -LL | ($s:stmt $t:tt) => {}; //~ERROR `$s:stmt` is followed by `$t:tt` +LL | ($s:stmt $t:tt) => {}; | ^^^^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -561,7 +561,7 @@ LL | ($s:stmt $t:tt) => {}; //~ERROR `$s:stmt` is followed by `$t:tt` error: `$s:stmt` is followed by `$i:item`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:90:14 | -LL | ($s:stmt $i:item) => {}; //~ERROR `$s:stmt` is followed by `$i:item` +LL | ($s:stmt $i:item) => {}; | ^^^^^^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -569,7 +569,7 @@ LL | ($s:stmt $i:item) => {}; //~ERROR `$s:stmt` is followed by `$i:item` error: `$s:stmt` is followed by `$m:meta`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:91:14 | -LL | ($s:stmt $m:meta) => {}; //~ERROR `$s:stmt` is followed by `$m:meta` +LL | ($s:stmt $m:meta) => {}; | ^^^^^^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -577,7 +577,7 @@ LL | ($s:stmt $m:meta) => {}; //~ERROR `$s:stmt` is followed by `$m:meta` error: `$p:path` is followed by `(`, which is not allowed for `path` fragments --> $DIR/macro-follow.rs:95:15 | -LL | ($p:path ()) => {}; //~ERROR `$p:path` is followed by `(` +LL | ($p:path ()) => {}; | ^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -585,7 +585,7 @@ LL | ($p:path ()) => {}; //~ERROR `$p:path` is followed by `(` error: `$p:path` is followed by `+`, which is not allowed for `path` fragments --> $DIR/macro-follow.rs:97:14 | -LL | ($p:path +) => {}; //~ERROR `$p:path` is followed by `+` +LL | ($p:path +) => {}; | ^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -593,7 +593,7 @@ LL | ($p:path +) => {}; //~ERROR `$p:path` is followed by `+` error: `$p:path` is followed by `ident`, which is not allowed for `path` fragments --> $DIR/macro-follow.rs:98:14 | -LL | ($p:path ident) => {}; //~ERROR `$p:path` is followed by `ident` +LL | ($p:path ident) => {}; | ^^^^^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -601,7 +601,7 @@ LL | ($p:path ident) => {}; //~ERROR `$p:path` is followed by `ident` error: `$p:path` is followed by `if`, which is not allowed for `path` fragments --> $DIR/macro-follow.rs:99:14 | -LL | ($p:path if) => {}; //~ERROR `$p:path` is followed by `if` +LL | ($p:path if) => {}; | ^^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -609,7 +609,7 @@ LL | ($p:path if) => {}; //~ERROR `$p:path` is followed by `if` error: `$p:path` is followed by `$q:pat`, which is not allowed for `path` fragments --> $DIR/macro-follow.rs:100:14 | -LL | ($p:path $q:pat) => {}; //~ERROR `$p:path` is followed by `$q:pat` +LL | ($p:path $q:pat) => {}; | ^^^^^^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -617,7 +617,7 @@ LL | ($p:path $q:pat) => {}; //~ERROR `$p:path` is followed by `$q:pat` error: `$p:path` is followed by `$e:expr`, which is not allowed for `path` fragments --> $DIR/macro-follow.rs:101:14 | -LL | ($p:path $e:expr) => {}; //~ERROR `$p:path` is followed by `$e:expr` +LL | ($p:path $e:expr) => {}; | ^^^^^^^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -625,7 +625,7 @@ LL | ($p:path $e:expr) => {}; //~ERROR `$p:path` is followed by `$e:expr` error: `$p:path` is followed by `$t:ty`, which is not allowed for `path` fragments --> $DIR/macro-follow.rs:102:14 | -LL | ($p:path $t:ty) => {}; //~ERROR `$p:path` is followed by `$t:ty` +LL | ($p:path $t:ty) => {}; | ^^^^^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -633,7 +633,7 @@ LL | ($p:path $t:ty) => {}; //~ERROR `$p:path` is followed by `$t:ty` error: `$p:path` is followed by `$s:stmt`, which is not allowed for `path` fragments --> $DIR/macro-follow.rs:103:14 | -LL | ($p:path $s:stmt) => {}; //~ERROR `$p:path` is followed by `$s:stmt` +LL | ($p:path $s:stmt) => {}; | ^^^^^^^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -641,7 +641,7 @@ LL | ($p:path $s:stmt) => {}; //~ERROR `$p:path` is followed by `$s:stmt` error: `$p:path` is followed by `$q:path`, which is not allowed for `path` fragments --> $DIR/macro-follow.rs:104:14 | -LL | ($p:path $q:path) => {}; //~ERROR `$p:path` is followed by `$q:path` +LL | ($p:path $q:path) => {}; | ^^^^^^^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -649,7 +649,7 @@ LL | ($p:path $q:path) => {}; //~ERROR `$p:path` is followed by `$q:path` error: `$p:path` is followed by `$i:ident`, which is not allowed for `path` fragments --> $DIR/macro-follow.rs:106:14 | -LL | ($p:path $i:ident) => {}; //~ERROR `$p:path` is followed by `$i:ident` +LL | ($p:path $i:ident) => {}; | ^^^^^^^^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -657,7 +657,7 @@ LL | ($p:path $i:ident) => {}; //~ERROR `$p:path` is followed by `$i:ident` error: `$p:path` is followed by `$t:tt`, which is not allowed for `path` fragments --> $DIR/macro-follow.rs:107:14 | -LL | ($p:path $t:tt) => {}; //~ERROR `$p:path` is followed by `$t:tt` +LL | ($p:path $t:tt) => {}; | ^^^^^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -665,7 +665,7 @@ LL | ($p:path $t:tt) => {}; //~ERROR `$p:path` is followed by `$t:tt` error: `$p:path` is followed by `$i:item`, which is not allowed for `path` fragments --> $DIR/macro-follow.rs:108:14 | -LL | ($p:path $i:item) => {}; //~ERROR `$p:path` is followed by `$i:item` +LL | ($p:path $i:item) => {}; | ^^^^^^^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -673,7 +673,7 @@ LL | ($p:path $i:item) => {}; //~ERROR `$p:path` is followed by `$i:item` error: `$p:path` is followed by `$m:meta`, which is not allowed for `path` fragments --> $DIR/macro-follow.rs:109:14 | -LL | ($p:path $m:meta) => {}; //~ERROR `$p:path` is followed by `$m:meta` +LL | ($p:path $m:meta) => {}; | ^^^^^^^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` diff --git a/src/test/ui/macros/macro-followed-by-seq-bad.stderr b/src/test/ui/macros/macro-followed-by-seq-bad.stderr index 18403fd248d84..7097979aeddf3 100644 --- a/src/test/ui/macros/macro-followed-by-seq-bad.stderr +++ b/src/test/ui/macros/macro-followed-by-seq-bad.stderr @@ -1,7 +1,7 @@ error: `$a:expr` is followed by `$b:tt`, which is not allowed for `expr` fragments --> $DIR/macro-followed-by-seq-bad.rs:7:15 | -LL | ( $a:expr $($b:tt)* ) => { }; //~ ERROR not allowed for `expr` fragments +LL | ( $a:expr $($b:tt)* ) => { }; | ^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` @@ -9,7 +9,7 @@ LL | ( $a:expr $($b:tt)* ) => { }; //~ ERROR not allowed for `expr` fragments error: `$a:ty` is followed by `$b:tt`, which is not allowed for `ty` fragments --> $DIR/macro-followed-by-seq-bad.rs:8:13 | -LL | ( $a:ty $($b:tt)* ) => { }; //~ ERROR not allowed for `ty` fragments +LL | ( $a:ty $($b:tt)* ) => { }; | ^^^^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` diff --git a/src/test/ui/macros/macro-inner-attributes.rs b/src/test/ui/macros/macro-inner-attributes.rs index 268ddda1b3c25..56a9023156612 100644 --- a/src/test/ui/macros/macro-inner-attributes.rs +++ b/src/test/ui/macros/macro-inner-attributes.rs @@ -1,4 +1,4 @@ -#![feature(custom_attribute)] +#![feature(rustc_attrs)] macro_rules! test { ($nm:ident, #[$a:meta], @@ -12,7 +12,7 @@ test!(b, #[cfg(not(qux))], pub fn bar() { }); -#[qux] +#[rustc_dummy] fn main() { a::bar(); //~^ ERROR failed to resolve: use of undeclared type or module `a` diff --git a/src/test/ui/macros/macro-input-future-proofing.stderr b/src/test/ui/macros/macro-input-future-proofing.stderr index fa39fc6a2125f..542486927dfd1 100644 --- a/src/test/ui/macros/macro-input-future-proofing.stderr +++ b/src/test/ui/macros/macro-input-future-proofing.stderr @@ -1,7 +1,7 @@ error: `$ty:ty` is followed by `<`, which is not allowed for `ty` fragments --> $DIR/macro-input-future-proofing.rs:4:13 | -LL | ($ty:ty <) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty` +LL | ($ty:ty <) => (); | ^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -9,7 +9,7 @@ LL | ($ty:ty <) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not a error: `$ty:ty` is followed by `<`, which is not allowed for `ty` fragments --> $DIR/macro-input-future-proofing.rs:5:13 | -LL | ($ty:ty < foo ,) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty` +LL | ($ty:ty < foo ,) => (); | ^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -17,7 +17,7 @@ LL | ($ty:ty < foo ,) => (); //~ ERROR `$ty:ty` is followed by `<`, which is error: `$pa:pat` is followed by `>`, which is not allowed for `pat` fragments --> $DIR/macro-input-future-proofing.rs:11:14 | -LL | ($pa:pat >) => (); //~ ERROR `$pa:pat` is followed by `>`, which is not allowed for `pat` +LL | ($pa:pat >) => (); | ^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` @@ -41,7 +41,7 @@ LL | ($pa:pat $pb:pat $ty:ty ,) => (); error: `$ty:ty` is followed by `-`, which is not allowed for `ty` fragments --> $DIR/macro-input-future-proofing.rs:16:17 | -LL | ($($ty:ty)* -) => (); //~ ERROR `$ty:ty` is followed by `-` +LL | ($($ty:ty)* -) => (); | ^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` @@ -49,16 +49,16 @@ LL | ($($ty:ty)* -) => (); //~ ERROR `$ty:ty` is followed by `-` error: `$b:ty` is followed by `-`, which is not allowed for `ty` fragments --> $DIR/macro-input-future-proofing.rs:17:23 | -LL | ($($a:ty, $b:ty)* -) => (); //~ ERROR `$b:ty` is followed by `-` +LL | ($($a:ty, $b:ty)* -) => (); | ^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$ty:ty` is followed by `-`, which is not allowed for `ty` fragments - --> $DIR/macro-input-future-proofing.rs:18:7 + --> $DIR/macro-input-future-proofing.rs:18:15 | -LL | ($($ty:ty)-+) => (); //~ ERROR `$ty:ty` is followed by `-`, which is not allowed for `ty` - | ^^^^^^^^ not allowed after `ty` fragments +LL | ($($ty:ty)-+) => (); + | ^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` diff --git a/src/test/ui/macros/macro-match-nonterminal.stderr b/src/test/ui/macros/macro-match-nonterminal.stderr index 15eafbde0a23d..1de8c5bd4b472 100644 --- a/src/test/ui/macros/macro-match-nonterminal.stderr +++ b/src/test/ui/macros/macro-match-nonterminal.stderr @@ -1,7 +1,7 @@ error: missing fragment specifier --> $DIR/macro-match-nonterminal.rs:1:24 | -LL | macro_rules! test { ($a, $b) => (()); } //~ ERROR missing fragment +LL | macro_rules! test { ($a, $b) => (()); } | ^ error: aborting due to previous error diff --git a/src/test/ui/macros/macro-missing-delimiters.stderr b/src/test/ui/macros/macro-missing-delimiters.stderr index 63cf1826f7721..e7c37c8ddbebd 100644 --- a/src/test/ui/macros/macro-missing-delimiters.stderr +++ b/src/test/ui/macros/macro-missing-delimiters.stderr @@ -1,7 +1,7 @@ error: invalid macro matcher; matchers must be contained in balanced delimiters --> $DIR/macro-missing-delimiters.rs:2:5 | -LL | baz => () //~ ERROR invalid macro matcher; +LL | baz => () | ^^^ error: aborting due to previous error diff --git a/src/test/ui/macros/macro-missing-fragment.stderr b/src/test/ui/macros/macro-missing-fragment.stderr index 8c4026760ca1c..b7871c0ec3a6f 100644 --- a/src/test/ui/macros/macro-missing-fragment.stderr +++ b/src/test/ui/macros/macro-missing-fragment.stderr @@ -1,7 +1,7 @@ error: missing fragment specifier --> $DIR/macro-missing-fragment.rs:2:20 | -LL | ( $( any_token $field_rust_type )* ) => {}; //~ ERROR missing fragment +LL | ( $( any_token $field_rust_type )* ) => {}; | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/macros/macro-multiple-matcher-bindings.rs b/src/test/ui/macros/macro-multiple-matcher-bindings.rs index 9e0fa3887163d..7d39dc0a52f2e 100644 --- a/src/test/ui/macros/macro-multiple-matcher-bindings.rs +++ b/src/test/ui/macros/macro-multiple-matcher-bindings.rs @@ -1,15 +1,11 @@ // Test that duplicate matcher binding names are caught at declaration time, rather than at macro // invocation time. -// -// FIXME(mark-i-m): Update this when it becomes a hard error. - -// compile-pass #![allow(unused_macros)] macro_rules! foo1 { - ($a:ident, $a:ident) => {}; //~WARNING duplicate matcher binding - ($a:ident, $a:path) => {}; //~WARNING duplicate matcher binding + ($a:ident, $a:ident) => {}; //~ERROR duplicate matcher binding + ($a:ident, $a:path) => {}; //~ERROR duplicate matcher binding } macro_rules! foo2 { @@ -18,8 +14,8 @@ macro_rules! foo2 { } macro_rules! foo3 { - ($a:ident, $($a:ident),*) => {}; //~WARNING duplicate matcher binding - ($($a:ident)+ # $($($a:path),+);*) => {}; //~WARNING duplicate matcher binding + ($a:ident, $($a:ident),*) => {}; //~ERROR duplicate matcher binding + ($($a:ident)+ # $($($a:path),+);*) => {}; //~ERROR duplicate matcher binding } fn main() {} diff --git a/src/test/ui/macros/macro-multiple-matcher-bindings.stderr b/src/test/ui/macros/macro-multiple-matcher-bindings.stderr index bc78b471a2d1e..65362388d7de1 100644 --- a/src/test/ui/macros/macro-multiple-matcher-bindings.stderr +++ b/src/test/ui/macros/macro-multiple-matcher-bindings.stderr @@ -1,37 +1,50 @@ -warning: duplicate matcher binding - --> $DIR/macro-multiple-matcher-bindings.rs:11:6 +error: duplicate matcher binding + --> $DIR/macro-multiple-matcher-bindings.rs:7:16 | -LL | ($a:ident, $a:ident) => {}; //~WARNING duplicate matcher binding - | ^^^^^^^^ ^^^^^^^^ +LL | ($a:ident, $a:ident) => {}; + | ^^^^^^^^ | - = note: #[warn(duplicate_matcher_binding_name)] on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57593 +note: previous declaration was here + --> $DIR/macro-multiple-matcher-bindings.rs:7:6 + | +LL | ($a:ident, $a:ident) => {}; + | ^^^^^^^^ -warning: duplicate matcher binding - --> $DIR/macro-multiple-matcher-bindings.rs:12:6 +error: duplicate matcher binding + --> $DIR/macro-multiple-matcher-bindings.rs:8:16 + | +LL | ($a:ident, $a:path) => {}; + | ^^^^^^^ | -LL | ($a:ident, $a:path) => {}; //~WARNING duplicate matcher binding - | ^^^^^^^^ ^^^^^^^ +note: previous declaration was here + --> $DIR/macro-multiple-matcher-bindings.rs:8:6 | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57593 +LL | ($a:ident, $a:path) => {}; + | ^^^^^^^^ -warning: duplicate matcher binding - --> $DIR/macro-multiple-matcher-bindings.rs:21:6 +error: duplicate matcher binding + --> $DIR/macro-multiple-matcher-bindings.rs:17:18 + | +LL | ($a:ident, $($a:ident),*) => {}; + | ^^^^^^^^ | -LL | ($a:ident, $($a:ident),*) => {}; //~WARNING duplicate matcher binding - | ^^^^^^^^ ^^^^^^^^ +note: previous declaration was here + --> $DIR/macro-multiple-matcher-bindings.rs:17:6 | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57593 +LL | ($a:ident, $($a:ident),*) => {}; + | ^^^^^^^^ -warning: duplicate matcher binding - --> $DIR/macro-multiple-matcher-bindings.rs:22:8 +error: duplicate matcher binding + --> $DIR/macro-multiple-matcher-bindings.rs:18:25 | -LL | ($($a:ident)+ # $($($a:path),+);*) => {}; //~WARNING duplicate matcher binding - | ^^^^^^^^ ^^^^^^^ +LL | ($($a:ident)+ # $($($a:path),+);*) => {}; + | ^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57593 +note: previous declaration was here + --> $DIR/macro-multiple-matcher-bindings.rs:18:8 + | +LL | ($($a:ident)+ # $($($a:path),+);*) => {}; + | ^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/src/test/ui/macros/macro-name-typo.stderr b/src/test/ui/macros/macro-name-typo.stderr index 5af9828fd9820..a8930f243f8fa 100644 --- a/src/test/ui/macros/macro-name-typo.stderr +++ b/src/test/ui/macros/macro-name-typo.stderr @@ -1,7 +1,7 @@ error: cannot find macro `printlx!` in this scope --> $DIR/macro-name-typo.rs:2:5 | -LL | printlx!("oh noes!"); //~ ERROR cannot find +LL | printlx!("oh noes!"); | ^^^^^^^ help: you could try the macro: `println` error: aborting due to previous error diff --git a/src/test/ui/macros/macro-outer-attributes.rs b/src/test/ui/macros/macro-outer-attributes.rs index aa70060425f65..0752f7e3153c1 100644 --- a/src/test/ui/macros/macro-outer-attributes.rs +++ b/src/test/ui/macros/macro-outer-attributes.rs @@ -1,4 +1,4 @@ -#![feature(custom_attribute)] +#![feature(rustc_attrs)] macro_rules! test { ($nm:ident, #[$a:meta], @@ -13,7 +13,7 @@ test!(b, pub fn bar() { }); // test1!(#[bar]) -#[qux] +#[rustc_dummy] fn main() { a::bar(); //~ ERROR cannot find function `bar` in module `a` b::bar(); diff --git a/src/test/ui/macros/macro-outer-attributes.stderr b/src/test/ui/macros/macro-outer-attributes.stderr index f9413250076b2..838333b95c0d5 100644 --- a/src/test/ui/macros/macro-outer-attributes.stderr +++ b/src/test/ui/macros/macro-outer-attributes.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find function `bar` in module `a` --> $DIR/macro-outer-attributes.rs:18:8 | -LL | a::bar(); //~ ERROR cannot find function `bar` in module `a` +LL | a::bar(); | ^^^ not found in `a` help: possible candidate is found in another module, you can import it into scope | diff --git a/src/test/ui/macros/macro-parameter-span.stderr b/src/test/ui/macros/macro-parameter-span.stderr index c7dcb12d3d109..24e3e89ea9bf3 100644 --- a/src/test/ui/macros/macro-parameter-span.stderr +++ b/src/test/ui/macros/macro-parameter-span.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `x` in this scope --> $DIR/macro-parameter-span.rs:11:9 | -LL | x //~ ERROR cannot find value `x` in this scope +LL | x | ^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/macros/macro-path-prelude-fail-1.rs b/src/test/ui/macros/macro-path-prelude-fail-1.rs index 354c2bf8571d9..cd695ca916ea9 100644 --- a/src/test/ui/macros/macro-path-prelude-fail-1.rs +++ b/src/test/ui/macros/macro-path-prelude-fail-1.rs @@ -2,8 +2,8 @@ mod m { fn check() { - Vec::clone!(); //~ ERROR failed to resolve: not a module `Vec` - u8::clone!(); //~ ERROR failed to resolve: not a module `u8` + Vec::clone!(); //~ ERROR failed to resolve: `Vec` is a struct, not a module + u8::clone!(); //~ ERROR failed to resolve: `u8` is a builtin type, not a module } } diff --git a/src/test/ui/macros/macro-path-prelude-fail-1.stderr b/src/test/ui/macros/macro-path-prelude-fail-1.stderr index 4bf51bd893a88..b68e89f07f676 100644 --- a/src/test/ui/macros/macro-path-prelude-fail-1.stderr +++ b/src/test/ui/macros/macro-path-prelude-fail-1.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: not a module `Vec` +error[E0433]: failed to resolve: `Vec` is a struct, not a module --> $DIR/macro-path-prelude-fail-1.rs:5:9 | -LL | Vec::clone!(); //~ ERROR failed to resolve: not a module `Vec` - | ^^^ not a module `Vec` +LL | Vec::clone!(); + | ^^^ `Vec` is a struct, not a module -error[E0433]: failed to resolve: not a module `u8` +error[E0433]: failed to resolve: `u8` is a builtin type, not a module --> $DIR/macro-path-prelude-fail-1.rs:6:9 | -LL | u8::clone!(); //~ ERROR failed to resolve: not a module `u8` - | ^^ not a module `u8` +LL | u8::clone!(); + | ^^ `u8` is a builtin type, not a module error: aborting due to 2 previous errors diff --git a/src/test/ui/macros/macro-path-prelude-fail-2.stderr b/src/test/ui/macros/macro-path-prelude-fail-2.stderr index 6b1a5b3741a3b..9574b7a1e25f1 100644 --- a/src/test/ui/macros/macro-path-prelude-fail-2.stderr +++ b/src/test/ui/macros/macro-path-prelude-fail-2.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: partially resolved path in a macro --> $DIR/macro-path-prelude-fail-2.rs:3:9 | -LL | Result::Ok!(); //~ ERROR failed to resolve: partially resolved path in a macro +LL | Result::Ok!(); | ^^^^^^^^^^ partially resolved path in a macro error: aborting due to previous error diff --git a/src/test/ui/macros/macro-path-prelude-fail-3.stderr b/src/test/ui/macros/macro-path-prelude-fail-3.stderr index 1772325118174..7eeddb885479a 100644 --- a/src/test/ui/macros/macro-path-prelude-fail-3.stderr +++ b/src/test/ui/macros/macro-path-prelude-fail-3.stderr @@ -1,7 +1,7 @@ error: cannot find macro `inline!` in this scope --> $DIR/macro-path-prelude-fail-3.rs:2:5 | -LL | inline!(); //~ ERROR cannot find macro `inline!` in this scope +LL | inline!(); | ^^^^^^ help: you could try the macro: `line` error: aborting due to previous error diff --git a/src/test/ui/macros/macro-path-prelude-fail-4.stderr b/src/test/ui/macros/macro-path-prelude-fail-4.stderr index e354f345a4c2f..f08445e1f775e 100644 --- a/src/test/ui/macros/macro-path-prelude-fail-4.stderr +++ b/src/test/ui/macros/macro-path-prelude-fail-4.stderr @@ -1,7 +1,7 @@ error: expected a macro, found built-in attribute --> $DIR/macro-path-prelude-fail-4.rs:1:10 | -LL | #[derive(inline)] //~ ERROR expected a macro, found built-in attribute +LL | #[derive(inline)] | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/macros/macro-path-prelude-shadowing.stderr b/src/test/ui/macros/macro-path-prelude-shadowing.stderr index 9c0214346a6a0..e7b381daf9346 100644 --- a/src/test/ui/macros/macro-path-prelude-shadowing.stderr +++ b/src/test/ui/macros/macro-path-prelude-shadowing.stderr @@ -1,7 +1,7 @@ error[E0659]: `std` is ambiguous (glob import vs any other name from outer scope during import/macro resolution) --> $DIR/macro-path-prelude-shadowing.rs:29:9 | -LL | std::panic!(); //~ ERROR `std` is ambiguous +LL | std::panic!(); | ^^^ ambiguous name | = note: `std` could refer to a built-in extern crate diff --git a/src/test/ui/macros/macro-reexport-removed.stderr b/src/test/ui/macros/macro-reexport-removed.stderr index 6cfec3ee762dd..742a72964db01 100644 --- a/src/test/ui/macros/macro-reexport-removed.stderr +++ b/src/test/ui/macros/macro-reexport-removed.stderr @@ -1,24 +1,25 @@ error[E0557]: feature has been removed --> $DIR/macro-reexport-removed.rs:3:12 | -LL | #![feature(macro_reexport)] //~ ERROR feature has been removed +LL | #![feature(macro_reexport)] | ^^^^^^^^^^^^^^ | note: subsumed by `pub use` --> $DIR/macro-reexport-removed.rs:3:12 | -LL | #![feature(macro_reexport)] //~ ERROR feature has been removed +LL | #![feature(macro_reexport)] | ^^^^^^^^^^^^^^ -error[E0658]: The attribute `macro_reexport` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `macro_reexport` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/macro-reexport-removed.rs:5:3 | -LL | #[macro_reexport(macro_one)] //~ ERROR attribute `macro_reexport` is currently unknown +LL | #[macro_reexport(macro_one)] | ^^^^^^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_export` | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 2 previous errors -Some errors occurred: E0557, E0658. +Some errors have detailed explanations: E0557, E0658. For more information about an error, try `rustc --explain E0557`. diff --git a/src/test/ui/macros/macro-shadowing.stderr b/src/test/ui/macros/macro-shadowing.stderr index c297f0ef52d77..033e12a31ae00 100644 --- a/src/test/ui/macros/macro-shadowing.stderr +++ b/src/test/ui/macros/macro-shadowing.stderr @@ -1,7 +1,7 @@ error: `macro_two` is already in scope --> $DIR/macro-shadowing.rs:12:5 | -LL | #[macro_use] //~ ERROR `macro_two` is already in scope +LL | #[macro_use] | ^^^^^^^^^^^^ ... LL | m1!(); @@ -12,7 +12,7 @@ LL | m1!(); error[E0659]: `foo` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/macro-shadowing.rs:17:1 | -LL | foo!(); //~ ERROR `foo` is ambiguous +LL | foo!(); | ^^^ ambiguous name | note: `foo` could refer to the macro defined here diff --git a/src/test/ui/macros/macro-stability.stderr b/src/test/ui/macros/macro-stability.stderr index e5c535a08e1c3..a0e0c351a4834 100644 --- a/src/test/ui/macros/macro-stability.stderr +++ b/src/test/ui/macros/macro-stability.stderr @@ -1,7 +1,7 @@ error[E0658]: macro unstable_macro! is unstable --> $DIR/macro-stability.rs:11:5 | -LL | unstable_macro!(); //~ ERROR: macro unstable_macro! is unstable +LL | unstable_macro!(); | ^^^^^^^^^^^^^^^^^^ | = help: add #![feature(unstable_macros)] to the crate attributes to enable diff --git a/src/test/ui/macros/macro-use-bad-args-1.stderr b/src/test/ui/macros/macro-use-bad-args-1.stderr index 1eb8cc3f4c493..f403c8a366084 100644 --- a/src/test/ui/macros/macro-use-bad-args-1.stderr +++ b/src/test/ui/macros/macro-use-bad-args-1.stderr @@ -1,7 +1,7 @@ error[E0466]: bad macro import --> $DIR/macro-use-bad-args-1.rs:4:13 | -LL | #[macro_use(foo(bar))] //~ ERROR bad macro import +LL | #[macro_use(foo(bar))] | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/macros/macro-use-bad-args-2.stderr b/src/test/ui/macros/macro-use-bad-args-2.stderr index 7ed6b26b1b778..93617edeeaea4 100644 --- a/src/test/ui/macros/macro-use-bad-args-2.stderr +++ b/src/test/ui/macros/macro-use-bad-args-2.stderr @@ -1,7 +1,7 @@ error[E0466]: bad macro import --> $DIR/macro-use-bad-args-2.rs:4:13 | -LL | #[macro_use(foo="bar")] //~ ERROR bad macro import +LL | #[macro_use(foo="bar")] | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/macros/macro-use-undef.stderr b/src/test/ui/macros/macro-use-undef.stderr index 4d9fa3aeb137d..85b86e2211f2d 100644 --- a/src/test/ui/macros/macro-use-undef.stderr +++ b/src/test/ui/macros/macro-use-undef.stderr @@ -1,7 +1,7 @@ error[E0469]: imported macro not found --> $DIR/macro-use-undef.rs:3:24 | -LL | #[macro_use(macro_two, no_way)] //~ ERROR imported macro not found +LL | #[macro_use(macro_two, no_way)] | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/macros/macro_path_as_generic_bound.stderr b/src/test/ui/macros/macro_path_as_generic_bound.stderr index 2f0e67c1ba8a0..48c33575ad2a9 100644 --- a/src/test/ui/macros/macro_path_as_generic_bound.stderr +++ b/src/test/ui/macros/macro_path_as_generic_bound.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: use of undeclared type or module `m` --> $DIR/macro_path_as_generic_bound.rs:7:6 | -LL | foo!(m::m2::A); //~ ERROR failed to resolve +LL | foo!(m::m2::A); | ^ use of undeclared type or module `m` error: aborting due to previous error diff --git a/src/test/ui/macros/macro_undefined.stderr b/src/test/ui/macros/macro_undefined.stderr index b9a76e07a007b..b516f91c67d1b 100644 --- a/src/test/ui/macros/macro_undefined.stderr +++ b/src/test/ui/macros/macro_undefined.stderr @@ -1,7 +1,7 @@ error: cannot find macro `k!` in this scope --> $DIR/macro_undefined.rs:11:5 | -LL | k!(); //~ ERROR cannot find +LL | k!(); | ^ help: you could try the macro: `kl` error: aborting due to previous error diff --git a/src/test/ui/macros/macros-in-extern.stderr b/src/test/ui/macros/macros-in-extern.stderr index 1d0c28752bcaa..ec7c37402d495 100644 --- a/src/test/ui/macros/macros-in-extern.stderr +++ b/src/test/ui/macros/macros-in-extern.stderr @@ -1,25 +1,28 @@ -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/macros-in-extern.rs:26:5 | LL | returns_isize!(rust_get_test_int); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/macros-in-extern.rs:28:5 | LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/macros-in-extern.rs:30:5 | LL | emits_nothing!(); | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/macros/macros-nonfatal-errors.stderr b/src/test/ui/macros/macros-nonfatal-errors.stderr index ce7035ee27461..f0ea5761bc8db 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.stderr +++ b/src/test/ui/macros/macros-nonfatal-errors.stderr @@ -1,91 +1,90 @@ error[E0665]: `Default` cannot be derived for enums, only structs --> $DIR/macros-nonfatal-errors.rs:9:10 | -LL | #[derive(Default)] //~ ERROR +LL | #[derive(Default)] | ^^^^^^^ error: inline assembly must be a string literal --> $DIR/macros-nonfatal-errors.rs:13:10 | -LL | asm!(invalid); //~ ERROR +LL | asm!(invalid); | ^^^^^^^ error: concat_idents! requires ident args. --> $DIR/macros-nonfatal-errors.rs:15:5 | -LL | concat_idents!("not", "idents"); //~ ERROR +LL | concat_idents!("not", "idents"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: argument must be a string literal --> $DIR/macros-nonfatal-errors.rs:17:17 | -LL | option_env!(invalid); //~ ERROR +LL | option_env!(invalid); | ^^^^^^^ error: expected string literal --> $DIR/macros-nonfatal-errors.rs:18:10 | -LL | env!(invalid); //~ ERROR +LL | env!(invalid); | ^^^^^^^ error: expected string literal --> $DIR/macros-nonfatal-errors.rs:19:10 | -LL | env!(foo, abr, baz); //~ ERROR +LL | env!(foo, abr, baz); | ^^^ error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined --> $DIR/macros-nonfatal-errors.rs:20:5 | -LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); //~ ERROR +LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: format argument must be a string literal --> $DIR/macros-nonfatal-errors.rs:22:13 | -LL | format!(invalid); //~ ERROR +LL | format!(invalid); | ^^^^^^^ help: you might be missing a string literal to format with | -LL | format!("{}", invalid); //~ ERROR +LL | format!("{}", invalid); | ^^^^^ error: argument must be a string literal --> $DIR/macros-nonfatal-errors.rs:24:14 | -LL | include!(invalid); //~ ERROR +LL | include!(invalid); | ^^^^^^^ error: argument must be a string literal --> $DIR/macros-nonfatal-errors.rs:26:18 | -LL | include_str!(invalid); //~ ERROR +LL | include_str!(invalid); | ^^^^^^^ error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) --> $DIR/macros-nonfatal-errors.rs:27:5 | -LL | include_str!("i'd be quite surprised if a file with this name existed"); //~ ERROR +LL | include_str!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: argument must be a string literal --> $DIR/macros-nonfatal-errors.rs:28:20 | -LL | include_bytes!(invalid); //~ ERROR +LL | include_bytes!(invalid); | ^^^^^^^ error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) --> $DIR/macros-nonfatal-errors.rs:29:5 | -LL | include_bytes!("i'd be quite surprised if a file with this name existed"); //~ ERROR +LL | include_bytes!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: trace_macros! accepts only `true` or `false` --> $DIR/macros-nonfatal-errors.rs:31:5 | -LL | trace_macros!(invalid); //~ ERROR +LL | trace_macros!(invalid); | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0665`. diff --git a/src/test/ui/macros/meta-item-absolute-path.stderr b/src/test/ui/macros/meta-item-absolute-path.stderr index 31b0a27bbc8da..23933f730aae9 100644 --- a/src/test/ui/macros/meta-item-absolute-path.stderr +++ b/src/test/ui/macros/meta-item-absolute-path.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: maybe a missing `extern crate Absolute;`? --> $DIR/meta-item-absolute-path.rs:1:12 | -LL | #[derive(::Absolute)] //~ ERROR failed to resolve +LL | #[derive(::Absolute)] | ^^^^^^^^ maybe a missing `extern crate Absolute;`? error: aborting due to previous error diff --git a/src/test/ui/macros/missing-comma.rs b/src/test/ui/macros/missing-comma.rs index 1e146875bcc76..2002fed6c93aa 100644 --- a/src/test/ui/macros/missing-comma.rs +++ b/src/test/ui/macros/missing-comma.rs @@ -6,6 +6,15 @@ macro_rules! foo { ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident) => (); } +macro_rules! bar { + ($lvl:expr, $($arg:tt)+) => {} +} + +macro_rules! check { + ($ty:ty, $expected:expr) => {}; + ($ty_of:expr, $expected:expr) => {}; +} + fn main() { println!("{}" a); //~^ ERROR expected token: `,` @@ -17,4 +26,9 @@ fn main() { //~^ ERROR no rules expected the token `d` foo!(a, b, c d e); //~^ ERROR no rules expected the token `d` + bar!(Level::Error, ); + //~^ ERROR unexpected end of macro invocation + check!(::fmt, "fmt"); + check!(::fmt, "fmt",); + //~^ ERROR no rules expected the token `,` } diff --git a/src/test/ui/macros/missing-comma.stderr b/src/test/ui/macros/missing-comma.stderr index 5881e0b7b68c6..d5b6d86b20ff1 100644 --- a/src/test/ui/macros/missing-comma.stderr +++ b/src/test/ui/macros/missing-comma.stderr @@ -1,11 +1,11 @@ error: expected token: `,` - --> $DIR/missing-comma.rs:10:19 + --> $DIR/missing-comma.rs:19:19 | LL | println!("{}" a); | ^ error: no rules expected the token `b` - --> $DIR/missing-comma.rs:12:12 + --> $DIR/missing-comma.rs:21:12 | LL | macro_rules! foo { | ---------------- when calling this macro @@ -16,7 +16,7 @@ LL | foo!(a b); | help: missing comma here error: no rules expected the token `e` - --> $DIR/missing-comma.rs:14:21 + --> $DIR/missing-comma.rs:23:21 | LL | macro_rules! foo { | ---------------- when calling this macro @@ -27,7 +27,7 @@ LL | foo!(a, b, c, d e); | help: missing comma here error: no rules expected the token `d` - --> $DIR/missing-comma.rs:16:18 + --> $DIR/missing-comma.rs:25:18 | LL | macro_rules! foo { | ---------------- when calling this macro @@ -38,7 +38,7 @@ LL | foo!(a, b, c d, e); | help: missing comma here error: no rules expected the token `d` - --> $DIR/missing-comma.rs:18:18 + --> $DIR/missing-comma.rs:27:18 | LL | macro_rules! foo { | ---------------- when calling this macro @@ -46,5 +46,23 @@ LL | macro_rules! foo { LL | foo!(a, b, c d e); | ^ no rules expected this token in macro call -error: aborting due to 5 previous errors +error: unexpected end of macro invocation + --> $DIR/missing-comma.rs:29:23 + | +LL | macro_rules! bar { + | ---------------- when calling this macro +... +LL | bar!(Level::Error, ); + | ^ missing tokens in macro arguments + +error: no rules expected the token `,` + --> $DIR/missing-comma.rs:32:38 + | +LL | macro_rules! check { + | ------------------ when calling this macro +... +LL | check!(::fmt, "fmt",); + | ^ no rules expected this token in macro call + +error: aborting due to 7 previous errors diff --git a/src/test/ui/macros/must-use-in-macro-55516.rs b/src/test/ui/macros/must-use-in-macro-55516.rs index 10e5646dc3d94..a5de32e5d2a8b 100644 --- a/src/test/ui/macros/must-use-in-macro-55516.rs +++ b/src/test/ui/macros/must-use-in-macro-55516.rs @@ -8,4 +8,3 @@ fn main() { let mut example = String::new(); write!(&mut example, "{}", 42); //~WARN must be used } - diff --git a/src/test/ui/macros/must-use-in-macro-55516.stderr b/src/test/ui/macros/must-use-in-macro-55516.stderr index 47874b8097278..302c8aa7e6a55 100644 --- a/src/test/ui/macros/must-use-in-macro-55516.stderr +++ b/src/test/ui/macros/must-use-in-macro-55516.stderr @@ -1,10 +1,10 @@ warning: unused `std::result::Result` that must be used --> $DIR/must-use-in-macro-55516.rs:9:5 | -LL | write!(&mut example, "{}", 42); //~WARN must be used +LL | write!(&mut example, "{}", 42); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-W unused-must-use` implied by `-W unused` = note: this `Result` may be an `Err` variant, which should be handled - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/macros/nonterminal-matching.stderr b/src/test/ui/macros/nonterminal-matching.stderr index f2a191ae149c0..93cc97d45830b 100644 --- a/src/test/ui/macros/nonterminal-matching.stderr +++ b/src/test/ui/macros/nonterminal-matching.stderr @@ -1,7 +1,10 @@ error: no rules expected the token `enum E { }` --> $DIR/nonterminal-matching.rs:19:10 | -LL | n!(a $nt_item b); //~ ERROR no rules expected the token `enum E { }` +LL | macro n(a $nt_item b) { + | --------------------- when calling this macro +... +LL | n!(a $nt_item b); | ^^^^^^^^ no rules expected this token in macro call ... LL | complex_nonterminal!(enum E {}); diff --git a/src/test/ui/macros/restricted-shadowing-legacy.stderr b/src/test/ui/macros/restricted-shadowing-legacy.stderr index 9d61799713b04..8378286bdadf5 100644 --- a/src/test/ui/macros/restricted-shadowing-legacy.stderr +++ b/src/test/ui/macros/restricted-shadowing-legacy.stderr @@ -1,7 +1,7 @@ error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-legacy.rs:101:13 | -LL | m!(); //~ ERROR `m` is ambiguous +LL | m!(); | ^ ambiguous name ... LL | include!(); @@ -27,7 +27,7 @@ LL | include!(); error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-legacy.rs:139:42 | -LL | macro_rules! gen_invoc { () => { m!() } } //~ ERROR `m` is ambiguous +LL | macro_rules! gen_invoc { () => { m!() } } | ^ ambiguous name ... LL | include!(); @@ -53,7 +53,7 @@ LL | include!(); error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-legacy.rs:148:9 | -LL | m!(); //~ ERROR `m` is ambiguous +LL | m!(); | ^ ambiguous name ... LL | include!(); @@ -79,7 +79,7 @@ LL | include!(); error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-legacy.rs:164:9 | -LL | m!(); //~ ERROR `m` is ambiguous +LL | m!(); | ^ ambiguous name ... LL | include!(); @@ -105,7 +105,7 @@ LL | include!(); error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-legacy.rs:180:13 | -LL | m!(); //~ ERROR `m` is ambiguous +LL | m!(); | ^ ambiguous name ... LL | include!(); @@ -131,7 +131,7 @@ LL | include!(); error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-legacy.rs:218:42 | -LL | macro_rules! gen_invoc { () => { m!() } } //~ ERROR `m` is ambiguous +LL | macro_rules! gen_invoc { () => { m!() } } | ^ ambiguous name ... LL | include!(); @@ -157,7 +157,7 @@ LL | include!(); error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-legacy.rs:232:9 | -LL | m!(); //~ ERROR `m` is ambiguous +LL | m!(); | ^ ambiguous name ... LL | include!(); @@ -183,7 +183,7 @@ LL | include!(); error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-legacy.rs:262:42 | -LL | macro_rules! gen_invoc { () => { m!() } } //~ ERROR `m` is ambiguous +LL | macro_rules! gen_invoc { () => { m!() } } | ^ ambiguous name ... LL | include!(); diff --git a/src/test/ui/macros/restricted-shadowing-modern.stderr b/src/test/ui/macros/restricted-shadowing-modern.stderr index 398a7660d3093..d147debeb51b8 100644 --- a/src/test/ui/macros/restricted-shadowing-modern.stderr +++ b/src/test/ui/macros/restricted-shadowing-modern.stderr @@ -1,7 +1,7 @@ error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-modern.rs:106:17 | -LL | m!(); //~ ERROR `m` is ambiguous +LL | m!(); | ^ ambiguous name ... LL | include!(); @@ -27,7 +27,7 @@ LL | include!(); error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-modern.rs:149:33 | -LL | macro gen_invoc() { m!() } //~ ERROR `m` is ambiguous +LL | macro gen_invoc() { m!() } | ^ ambiguous name ... LL | include!(); @@ -53,7 +53,7 @@ LL | include!(); error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-modern.rs:158:13 | -LL | m!(); //~ ERROR `m` is ambiguous +LL | m!(); | ^ ambiguous name ... LL | include!(); @@ -79,7 +79,7 @@ LL | include!(); error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-modern.rs:174:13 | -LL | m!(); //~ ERROR `m` is ambiguous +LL | m!(); | ^ ambiguous name ... LL | include!(); @@ -105,7 +105,7 @@ LL | include!(); error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-modern.rs:192:17 | -LL | m!(); //~ ERROR `m` is ambiguous +LL | m!(); | ^ ambiguous name ... LL | include!(); @@ -131,7 +131,7 @@ LL | include!(); error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/restricted-shadowing-modern.rs:235:33 | -LL | macro gen_invoc() { m!() } //~ ERROR `m` is ambiguous +LL | macro gen_invoc() { m!() } | ^ ambiguous name ... LL | include!(); diff --git a/src/test/ui/macros/span-covering-argument-1.nll.stderr b/src/test/ui/macros/span-covering-argument-1.nll.stderr deleted file mode 100644 index 2ac881107b96a..0000000000000 --- a/src/test/ui/macros/span-covering-argument-1.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable - --> $DIR/span-covering-argument-1.rs:5:14 - | -LL | let $s = 0; - | -- help: consider changing this to be mutable: `mut foo` -LL | *&mut $s = 0; - | ^^^^^^^ cannot borrow as mutable -... -LL | bad!(foo whatever); - | ------------------- in this macro invocation - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/macros/span-covering-argument-1.rs b/src/test/ui/macros/span-covering-argument-1.rs index 0256aaf901e3a..9b9506c80b150 100644 --- a/src/test/ui/macros/span-covering-argument-1.rs +++ b/src/test/ui/macros/span-covering-argument-1.rs @@ -3,7 +3,7 @@ macro_rules! bad { { let $s = 0; *&mut $s = 0; - //~^ ERROR cannot borrow immutable local variable `foo` as mutable [E0596] + //~^ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable [E0596] } } } diff --git a/src/test/ui/macros/span-covering-argument-1.stderr b/src/test/ui/macros/span-covering-argument-1.stderr index 345b880ccad9b..2ac881107b96a 100644 --- a/src/test/ui/macros/span-covering-argument-1.stderr +++ b/src/test/ui/macros/span-covering-argument-1.stderr @@ -1,10 +1,10 @@ -error[E0596]: cannot borrow immutable local variable `foo` as mutable - --> $DIR/span-covering-argument-1.rs:5:19 +error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable + --> $DIR/span-covering-argument-1.rs:5:14 | LL | let $s = 0; - | -- help: make this binding mutable: `mut $s` + | -- help: consider changing this to be mutable: `mut foo` LL | *&mut $s = 0; - | ^^ cannot borrow mutably + | ^^^^^^^ cannot borrow as mutable ... LL | bad!(foo whatever); | ------------------- in this macro invocation diff --git a/src/test/ui/macros/trace_faulty_macros.stderr b/src/test/ui/macros/trace_faulty_macros.stderr index a645590f005ad..233d3dcfcb6db 100644 --- a/src/test/ui/macros/trace_faulty_macros.stderr +++ b/src/test/ui/macros/trace_faulty_macros.stderr @@ -4,7 +4,7 @@ error: no rules expected the token `bcd` LL | macro_rules! my_faulty_macro { | ---------------------------- when calling this macro LL | () => { -LL | my_faulty_macro!(bcd); //~ ERROR no rules +LL | my_faulty_macro!(bcd); | ^^^ no rules expected this token in macro call ... LL | my_faulty_macro!(); @@ -23,7 +23,7 @@ LL | my_faulty_macro!(); error: recursion limit reached while expanding the macro `my_recursive_macro` --> $DIR/trace_faulty_macros.rs:22:9 | -LL | my_recursive_macro!(); //~ ERROR recursion limit +LL | my_recursive_macro!(); | ^^^^^^^^^^^^^^^^^^^^^^ ... LL | my_recursive_macro!(); diff --git a/src/test/ui/malformed/malformed-derive-entry.rs b/src/test/ui/malformed/malformed-derive-entry.rs index 74d22102c664d..a6d886318e820 100644 --- a/src/test/ui/malformed/malformed-derive-entry.rs +++ b/src/test/ui/malformed/malformed-derive-entry.rs @@ -1,17 +1,10 @@ -#[derive(Copy(Bad))] -//~^ ERROR expected one of `)`, `,`, or `::`, found `(` +#[derive(Copy(Bad))] //~ ERROR expected one of `)`, `,`, or `::`, found `(` struct Test1; -#[derive(Copy="bad")] -//~^ ERROR expected one of `)`, `,`, or `::`, found `=` +#[derive(Copy="bad")] //~ ERROR expected one of `)`, `,`, or `::`, found `=` struct Test2; -#[derive()] -//~^ WARNING empty trait list -struct Test3; - -#[derive] -//~^ ERROR attribute must be of the form +#[derive] //~ ERROR malformed `derive` attribute input struct Test4; fn main() {} diff --git a/src/test/ui/malformed/malformed-derive-entry.stderr b/src/test/ui/malformed/malformed-derive-entry.stderr index f546f74220a1c..f7500febe9719 100644 --- a/src/test/ui/malformed/malformed-derive-entry.stderr +++ b/src/test/ui/malformed/malformed-derive-entry.stderr @@ -5,22 +5,16 @@ LL | #[derive(Copy(Bad))] | ^ expected one of `)`, `,`, or `::` here error: expected one of `)`, `,`, or `::`, found `=` - --> $DIR/malformed-derive-entry.rs:5:14 + --> $DIR/malformed-derive-entry.rs:4:14 | LL | #[derive(Copy="bad")] | ^ expected one of `)`, `,`, or `::` here -warning: empty trait list in `derive` - --> $DIR/malformed-derive-entry.rs:9:1 - | -LL | #[derive()] - | ^^^^^^^^^^^ - -error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]` - --> $DIR/malformed-derive-entry.rs:13:1 +error: malformed `derive` attribute input + --> $DIR/malformed-derive-entry.rs:7:1 | LL | #[derive] - | ^^^^^^^^^ + | ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]` error: aborting due to 3 previous errors diff --git a/src/test/ui/malformed/malformed-interpolated.rs b/src/test/ui/malformed/malformed-interpolated.rs index e452435968bac..5101b5caeea09 100644 --- a/src/test/ui/malformed/malformed-interpolated.rs +++ b/src/test/ui/malformed/malformed-interpolated.rs @@ -1,17 +1,16 @@ -#![feature(custom_attribute)] +#![feature(rustc_attrs)] macro_rules! check { ($expr: expr) => ( - #[my_attr = $expr] //~ ERROR suffixed literals are not allowed in attributes - //~| ERROR unexpected token: `-0` - //~| ERROR unexpected token: `0 + 0` + #[rustc_dummy = $expr] //~ ERROR unexpected token: `-0` + //~| ERROR unexpected token: `0 + 0` use main as _; ); } check!("0"); // OK check!(0); // OK -check!(0u8); // ERROR, see above +check!(0u8); //~ ERROR suffixed literals are not allowed in attributes check!(-0); // ERROR, see above check!(0 + 0); // ERROR, see above diff --git a/src/test/ui/malformed/malformed-interpolated.stderr b/src/test/ui/malformed/malformed-interpolated.stderr index 24aa590c4d903..bcd2ef545d815 100644 --- a/src/test/ui/malformed/malformed-interpolated.stderr +++ b/src/test/ui/malformed/malformed-interpolated.stderr @@ -1,28 +1,25 @@ error: suffixed literals are not allowed in attributes - --> $DIR/malformed-interpolated.rs:5:21 + --> $DIR/malformed-interpolated.rs:13:8 | -LL | #[my_attr = $expr] //~ ERROR suffixed literals are not allowed in attributes - | ^^^^^ -... -LL | check!(0u8); // ERROR, see above - | ------------ in this macro invocation +LL | check!(0u8); + | ^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). error: unexpected token: `-0` - --> $DIR/malformed-interpolated.rs:5:19 + --> $DIR/malformed-interpolated.rs:5:25 | -LL | #[my_attr = $expr] //~ ERROR suffixed literals are not allowed in attributes - | ^ +LL | #[rustc_dummy = $expr] + | ^^^^^ ... LL | check!(-0); // ERROR, see above | ----------- in this macro invocation error: unexpected token: `0 + 0` - --> $DIR/malformed-interpolated.rs:5:19 + --> $DIR/malformed-interpolated.rs:5:25 | -LL | #[my_attr = $expr] //~ ERROR suffixed literals are not allowed in attributes - | ^ +LL | #[rustc_dummy = $expr] + | ^^^^^ ... LL | check!(0 + 0); // ERROR, see above | -------------- in this macro invocation diff --git a/src/test/ui/malformed/malformed-plugin-1.rs b/src/test/ui/malformed/malformed-plugin-1.rs index 16e7a952ef2d0..28f6c8e7a6f67 100644 --- a/src/test/ui/malformed/malformed-plugin-1.rs +++ b/src/test/ui/malformed/malformed-plugin-1.rs @@ -1,4 +1,4 @@ #![feature(plugin)] -#![plugin] //~ ERROR attribute must be of the form +#![plugin] //~ ERROR malformed `plugin` attribute fn main() {} diff --git a/src/test/ui/malformed/malformed-plugin-1.stderr b/src/test/ui/malformed/malformed-plugin-1.stderr index f42e66e2b32f3..a863cd4859656 100644 --- a/src/test/ui/malformed/malformed-plugin-1.stderr +++ b/src/test/ui/malformed/malformed-plugin-1.stderr @@ -1,8 +1,8 @@ -error: attribute must be of the form `#[plugin(name|name(args))]` +error: malformed `plugin` attribute input --> $DIR/malformed-plugin-1.rs:2:1 | -LL | #![plugin] //~ ERROR attribute must be of the form - | ^^^^^^^^^^ +LL | #![plugin] + | ^^^^^^^^^^ help: must be of the form: `#[plugin(name|name(args))]` error: aborting due to previous error diff --git a/src/test/ui/malformed/malformed-plugin-2.rs b/src/test/ui/malformed/malformed-plugin-2.rs index 70a1d7f85e8b6..8ec7a71da29b3 100644 --- a/src/test/ui/malformed/malformed-plugin-2.rs +++ b/src/test/ui/malformed/malformed-plugin-2.rs @@ -1,4 +1,4 @@ #![feature(plugin)] -#![plugin="bleh"] //~ ERROR attribute must be of the form +#![plugin="bleh"] //~ ERROR malformed `plugin` attribute fn main() {} diff --git a/src/test/ui/malformed/malformed-plugin-2.stderr b/src/test/ui/malformed/malformed-plugin-2.stderr index 923cbc188607e..6eb0c50ca9398 100644 --- a/src/test/ui/malformed/malformed-plugin-2.stderr +++ b/src/test/ui/malformed/malformed-plugin-2.stderr @@ -1,8 +1,8 @@ -error: attribute must be of the form `#[plugin(name|name(args))]` +error: malformed `plugin` attribute input --> $DIR/malformed-plugin-2.rs:2:1 | -LL | #![plugin="bleh"] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^^^^ +LL | #![plugin="bleh"] + | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[plugin(name|name(args))]` error: aborting due to previous error diff --git a/src/test/ui/malformed/malformed-plugin-3.rs b/src/test/ui/malformed/malformed-plugin-3.rs index 1b70ff3bdb7c1..c4713616b6258 100644 --- a/src/test/ui/malformed/malformed-plugin-3.rs +++ b/src/test/ui/malformed/malformed-plugin-3.rs @@ -1,4 +1,4 @@ #![feature(plugin)] -#![plugin(foo="bleh")] //~ ERROR malformed plugin attribute +#![plugin(foo="bleh")] //~ ERROR malformed `plugin` attribute fn main() {} diff --git a/src/test/ui/malformed/malformed-plugin-3.stderr b/src/test/ui/malformed/malformed-plugin-3.stderr index 6f19a11714901..f93fa0f65e85a 100644 --- a/src/test/ui/malformed/malformed-plugin-3.stderr +++ b/src/test/ui/malformed/malformed-plugin-3.stderr @@ -1,9 +1,8 @@ -error[E0498]: malformed plugin attribute +error[E0498]: malformed `plugin` attribute --> $DIR/malformed-plugin-3.rs:2:1 | -LL | #![plugin(foo="bleh")] //~ ERROR malformed plugin attribute - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![plugin(foo="bleh")] + | ^^^^^^^^^^^^^^^^^^^^^^ malformed attribute error: aborting due to previous error -For more information about this error, try `rustc --explain E0498`. diff --git a/src/test/ui/malformed/malformed-regressions.stderr b/src/test/ui/malformed/malformed-regressions.stderr index a3b2bda07f625..99a87f0c3aa0f 100644 --- a/src/test/ui/malformed/malformed-regressions.stderr +++ b/src/test/ui/malformed/malformed-regressions.stderr @@ -1,7 +1,7 @@ warning: attribute must be of the form `#[doc(hidden|inline|...)]` or `#[doc = "string"]` --> $DIR/malformed-regressions.rs:3:1 | -LL | #[doc] //~ WARN attribute must be of the form +LL | #[doc] | ^^^^^^ | = note: #[warn(ill_formed_attribute_input)] on by default @@ -11,7 +11,7 @@ LL | #[doc] //~ WARN attribute must be of the form warning: attribute must be of the form `#[ignore]` or `#[ignore = "reason"]` --> $DIR/malformed-regressions.rs:4:1 | -LL | #[ignore()] //~ WARN attribute must be of the form +LL | #[ignore()] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -20,27 +20,27 @@ LL | #[ignore()] //~ WARN attribute must be of the form warning: attribute must be of the form `#[inline]` or `#[inline(always|never)]` --> $DIR/malformed-regressions.rs:5:1 | -LL | #[inline = ""] //~ WARN attribute must be of the form +LL | #[inline = ""] | ^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 warning: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", - /*opt*/ cfg = "...")]` + /*opt*/ cfg = "...")]` --> $DIR/malformed-regressions.rs:6:1 | -LL | #[link] //~ WARN attribute must be of the form +LL | #[link] | ^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 warning: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", - /*opt*/ cfg = "...")]` + /*opt*/ cfg = "...")]` --> $DIR/malformed-regressions.rs:7:1 | -LL | #[link = ""] //~ WARN attribute must be of the form +LL | #[link = ""] | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/src/test/ui/malformed/malformed-special-attrs.rs b/src/test/ui/malformed/malformed-special-attrs.rs index f91c6bedb2b21..e67fbdd5ddd32 100644 --- a/src/test/ui/malformed/malformed-special-attrs.rs +++ b/src/test/ui/malformed/malformed-special-attrs.rs @@ -1,13 +1,13 @@ -#[cfg_attr] //~ ERROR expected `(`, found `` +#[cfg_attr] //~ ERROR malformed `cfg_attr` attribute struct S1; #[cfg_attr = ""] //~ ERROR expected `(`, found `=` struct S2; -#[derive] //~ ERROR attribute must be of the form +#[derive] //~ ERROR malformed `derive` attribute struct S3; -#[derive = ""] //~ ERROR attribute must be of the form +#[derive = ""] //~ ERROR malformed `derive` attribute struct S4; fn main() {} diff --git a/src/test/ui/malformed/malformed-special-attrs.stderr b/src/test/ui/malformed/malformed-special-attrs.stderr index 1653aa150d578..319c05eadbf1d 100644 --- a/src/test/ui/malformed/malformed-special-attrs.stderr +++ b/src/test/ui/malformed/malformed-special-attrs.stderr @@ -1,25 +1,28 @@ -error: expected `(`, found `` +error: malformed `cfg_attr` attribute input + --> $DIR/malformed-special-attrs.rs:1:1 + | +LL | #[cfg_attr] + | ^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]` + | + = note: for more information, visit error: expected `(`, found `=` --> $DIR/malformed-special-attrs.rs:4:12 | -LL | #[cfg_attr] //~ ERROR expected `(`, found `` - | - expected `(` -... -LL | #[cfg_attr = ""] //~ ERROR expected `(`, found `=` - | ^ unexpected token +LL | #[cfg_attr = ""] + | ^ expected `(` -error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]` +error: malformed `derive` attribute input --> $DIR/malformed-special-attrs.rs:7:1 | -LL | #[derive] //~ ERROR attribute must be of the form - | ^^^^^^^^^ +LL | #[derive] + | ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]` -error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]` +error: malformed `derive` attribute input --> $DIR/malformed-special-attrs.rs:10:1 | -LL | #[derive = ""] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^ +LL | #[derive = ""] + | ^^^^^^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]` error: aborting due to 4 previous errors diff --git a/src/test/ui/malformed/malformed-unwind-1.rs b/src/test/ui/malformed/malformed-unwind-1.rs new file mode 100644 index 0000000000000..009695b177f96 --- /dev/null +++ b/src/test/ui/malformed/malformed-unwind-1.rs @@ -0,0 +1,9 @@ +#![feature(unwind_attributes)] + +#[unwind] //~ ERROR malformed `unwind` attribute +extern "C" fn f1() {} + +#[unwind = ""] //~ ERROR malformed `unwind` attribute +extern "C" fn f2() {} + +fn main() {} diff --git a/src/test/ui/malformed/malformed-unwind-1.stderr b/src/test/ui/malformed/malformed-unwind-1.stderr new file mode 100644 index 0000000000000..0a553e8a245f6 --- /dev/null +++ b/src/test/ui/malformed/malformed-unwind-1.stderr @@ -0,0 +1,14 @@ +error: malformed `unwind` attribute input + --> $DIR/malformed-unwind-1.rs:3:1 + | +LL | #[unwind] + | ^^^^^^^^^ help: must be of the form: `#[unwind(allowed|aborts)]` + +error: malformed `unwind` attribute input + --> $DIR/malformed-unwind-1.rs:6:1 + | +LL | #[unwind = ""] + | ^^^^^^^^^^^^^^ help: must be of the form: `#[unwind(allowed|aborts)]` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/malformed/malformed-unwind-2.rs b/src/test/ui/malformed/malformed-unwind-2.rs new file mode 100644 index 0000000000000..9aafc7ca9b851 --- /dev/null +++ b/src/test/ui/malformed/malformed-unwind-2.rs @@ -0,0 +1,11 @@ +#![feature(unwind_attributes)] + +#[unwind(allowed, aborts)] +//~^ ERROR malformed `unwind` attribute +extern "C" fn f1() {} + +#[unwind(unsupported)] +//~^ ERROR malformed `unwind` attribute +extern "C" fn f2() {} + +fn main() {} diff --git a/src/test/ui/malformed/malformed-unwind-2.stderr b/src/test/ui/malformed/malformed-unwind-2.stderr new file mode 100644 index 0000000000000..ed88b9afd8758 --- /dev/null +++ b/src/test/ui/malformed/malformed-unwind-2.stderr @@ -0,0 +1,27 @@ +error[E0633]: malformed `unwind` attribute input + --> $DIR/malformed-unwind-2.rs:3:1 + | +LL | #[unwind(allowed, aborts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid argument +help: the allowed arguments are `allowed` and `aborts` + | +LL | #[unwind(allowed)] + | +LL | #[unwind(aborts)] + | + +error[E0633]: malformed `unwind` attribute input + --> $DIR/malformed-unwind-2.rs:7:1 + | +LL | #[unwind(unsupported)] + | ^^^^^^^^^^^^^^^^^^^^^^ invalid argument +help: the allowed arguments are `allowed` and `aborts` + | +LL | #[unwind(allowed)] + | +LL | #[unwind(aborts)] + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0633`. diff --git a/src/test/ui/malformed_macro_lhs.stderr b/src/test/ui/malformed_macro_lhs.stderr index ab09bc10b86f0..adf64b089350d 100644 --- a/src/test/ui/malformed_macro_lhs.stderr +++ b/src/test/ui/malformed_macro_lhs.stderr @@ -1,7 +1,7 @@ error: invalid macro matcher; matchers must be contained in balanced delimiters --> $DIR/malformed_macro_lhs.rs:2:5 | -LL | t => (1); //~ ERROR invalid macro matcher +LL | t => (1); | ^ error: aborting due to previous error diff --git a/src/test/ui/map-types.rs b/src/test/ui/map-types.rs index dab7863415f6e..c355a0e420f8f 100644 --- a/src/test/ui/map-types.rs +++ b/src/test/ui/map-types.rs @@ -13,7 +13,7 @@ impl Map for HashMap {} fn main() { let x: Box> = box HashMap::new(); - let x: Box> = x; - let y: Box> = Box::new(x); + let x: Box> = x; + let y: Box> = Box::new(x); //~^ ERROR `std::boxed::Box>: Map` is not satisfied } diff --git a/src/test/ui/map-types.stderr b/src/test/ui/map-types.stderr index 9aa9804424214..21dac1ab1edfb 100644 --- a/src/test/ui/map-types.stderr +++ b/src/test/ui/map-types.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `std::boxed::Box>: Map` is not satisfied - --> $DIR/map-types.rs:17:37 + --> $DIR/map-types.rs:17:41 | -LL | let y: Box> = Box::new(x); - | ^^^^^^^^^^^ the trait `Map` is not implemented for `std::boxed::Box>` +LL | let y: Box> = Box::new(x); + | ^^^^^^^^^^^ the trait `Map` is not implemented for `std::boxed::Box>` | = note: required for the cast to the object type `dyn Map` diff --git a/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr b/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr index b88c125d968db..d30b990caac2b 100644 --- a/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr +++ b/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr @@ -1,7 +1,7 @@ error: attribute can only be applied to a trait --> $DIR/marker-attribute-on-non-trait.rs:3:1 | -LL | #[marker] //~ ERROR attribute can only be applied to a trait +LL | #[marker] | ^^^^^^^^^ LL | struct Struct {} | ---------------- not a trait @@ -9,7 +9,7 @@ LL | struct Struct {} error: attribute can only be applied to a trait --> $DIR/marker-attribute-on-non-trait.rs:6:1 | -LL | #[marker] //~ ERROR attribute can only be applied to a trait +LL | #[marker] | ^^^^^^^^^ LL | impl Struct {} | -------------- not a trait @@ -17,7 +17,7 @@ LL | impl Struct {} error: attribute can only be applied to a trait --> $DIR/marker-attribute-on-non-trait.rs:9:1 | -LL | #[marker] //~ ERROR attribute can only be applied to a trait +LL | #[marker] | ^^^^^^^^^ LL | / union Union { LL | | x: i32, @@ -27,7 +27,7 @@ LL | | } error: attribute can only be applied to a trait --> $DIR/marker-attribute-on-non-trait.rs:14:1 | -LL | #[marker] //~ ERROR attribute can only be applied to a trait +LL | #[marker] | ^^^^^^^^^ LL | const CONST: usize = 10; | ------------------------ not a trait @@ -35,7 +35,7 @@ LL | const CONST: usize = 10; error: attribute can only be applied to a trait --> $DIR/marker-attribute-on-non-trait.rs:17:1 | -LL | #[marker] //~ ERROR attribute can only be applied to a trait +LL | #[marker] | ^^^^^^^^^ LL | fn function() {} | ---------------- not a trait @@ -43,7 +43,7 @@ LL | fn function() {} error: attribute can only be applied to a trait --> $DIR/marker-attribute-on-non-trait.rs:20:1 | -LL | #[marker] //~ ERROR attribute can only be applied to a trait +LL | #[marker] | ^^^^^^^^^ LL | type Type = (); | --------------- not a trait diff --git a/src/test/ui/marker_trait_attr/marker-attribute-with-values.rs b/src/test/ui/marker_trait_attr/marker-attribute-with-values.rs index f8bcec78650e8..9e07f0eaeea7f 100644 --- a/src/test/ui/marker_trait_attr/marker-attribute-with-values.rs +++ b/src/test/ui/marker_trait_attr/marker-attribute-with-values.rs @@ -1,15 +1,12 @@ #![feature(marker_trait_attr)] -#[marker(always)] +#[marker(always)] //~ ERROR malformed `marker` attribute trait Marker1 {} -//~^^ ERROR attribute must be of the form -#[marker("never")] +#[marker("never")] //~ ERROR malformed `marker` attribute trait Marker2 {} -//~^^ ERROR attribute must be of the form -#[marker(key = "value")] +#[marker(key = "value")] //~ ERROR malformed `marker` attribute trait Marker3 {} -//~^^ ERROR attribute must be of the form `#[marker]` fn main() {} diff --git a/src/test/ui/marker_trait_attr/marker-attribute-with-values.stderr b/src/test/ui/marker_trait_attr/marker-attribute-with-values.stderr index 2b31dcb4760a0..6f9c9508e7e55 100644 --- a/src/test/ui/marker_trait_attr/marker-attribute-with-values.stderr +++ b/src/test/ui/marker_trait_attr/marker-attribute-with-values.stderr @@ -1,20 +1,20 @@ -error: attribute must be of the form `#[marker]` +error: malformed `marker` attribute input --> $DIR/marker-attribute-with-values.rs:3:1 | LL | #[marker(always)] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[marker]` -error: attribute must be of the form `#[marker]` - --> $DIR/marker-attribute-with-values.rs:7:1 +error: malformed `marker` attribute input + --> $DIR/marker-attribute-with-values.rs:6:1 | LL | #[marker("never")] - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[marker]` -error: attribute must be of the form `#[marker]` - --> $DIR/marker-attribute-with-values.rs:11:1 +error: malformed `marker` attribute input + --> $DIR/marker-attribute-with-values.rs:9:1 | LL | #[marker(key = "value")] - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[marker]` error: aborting due to 3 previous errors diff --git a/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr b/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr index 4579ec261164a..f4a52a65af6aa 100644 --- a/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr +++ b/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `NotDebugOrDisplay: Marker` is not satisfied --> $DIR/overlap-marker-trait.rs:27:5 | -LL | is_marker::(); //~ ERROR +LL | is_marker::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Marker` is not implemented for `NotDebugOrDisplay` | note: required by `is_marker` diff --git a/src/test/ui/match/match-argm-statics-2.rs b/src/test/ui/match/match-argm-statics-2.rs index ad220d2f4319a..4c5f2d356491b 100644 --- a/src/test/ui/match/match-argm-statics-2.rs +++ b/src/test/ui/match/match-argm-statics-2.rs @@ -60,4 +60,3 @@ fn main() { nonexhaustive_2(); nonexhaustive_3(); } - diff --git a/src/test/ui/match/match-argm-statics-2.stderr b/src/test/ui/match/match-argm-statics-2.stderr index 3e6f22ab87513..8c54e030823af 100644 --- a/src/test/ui/match/match-argm-statics-2.stderr +++ b/src/test/ui/match/match-argm-statics-2.stderr @@ -3,18 +3,30 @@ error[E0004]: non-exhaustive patterns: `(true, false)` not covered | LL | match (true, false) { | ^^^^^^^^^^^^^ pattern `(true, false)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `Some(Some(West))` not covered --> $DIR/match-argm-statics-2.rs:29:11 | LL | match Some(Some(North)) { | ^^^^^^^^^^^^^^^^^ pattern `Some(Some(West))` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` not covered --> $DIR/match-argm-statics-2.rs:48:11 | -LL | match (Foo { bar: Some(North), baz: NewBool(true) }) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered +LL | / struct Foo { +LL | | bar: Option, +LL | | baz: NewBool +LL | | } + | |_- `Foo` defined here +... +LL | match (Foo { bar: Some(North), baz: NewBool(true) }) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to 3 previous errors diff --git a/src/test/ui/match/match-byte-array-patterns-2.rs b/src/test/ui/match/match-byte-array-patterns-2.rs index a3a47d23bef4c..33468d03fae40 100644 --- a/src/test/ui/match/match-byte-array-patterns-2.rs +++ b/src/test/ui/match/match-byte-array-patterns-2.rs @@ -11,4 +11,3 @@ fn main() { b"AAAA" => {} } } - diff --git a/src/test/ui/match/match-byte-array-patterns-2.stderr b/src/test/ui/match/match-byte-array-patterns-2.stderr index 4030cd39448a0..d53e2e25b3dbd 100644 --- a/src/test/ui/match/match-byte-array-patterns-2.stderr +++ b/src/test/ui/match/match-byte-array-patterns-2.stderr @@ -1,14 +1,18 @@ error[E0004]: non-exhaustive patterns: `&[_, _, _, _]` not covered --> $DIR/match-byte-array-patterns-2.rs:4:11 | -LL | match buf { //~ ERROR non-exhaustive +LL | match buf { | ^^^ pattern `&[_, _, _, _]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 3 more not covered --> $DIR/match-byte-array-patterns-2.rs:10:11 | -LL | match buf { //~ ERROR non-exhaustive +LL | match buf { | ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 3 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to 2 previous errors diff --git a/src/test/ui/match/match-byte-array-patterns.stderr b/src/test/ui/match/match-byte-array-patterns.stderr index a23f185366664..b28646b50cf01 100644 --- a/src/test/ui/match/match-byte-array-patterns.stderr +++ b/src/test/ui/match/match-byte-array-patterns.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:9:9 | -LL | &[0x41, 0x41, 0x41, 0x41] => {} //~ ERROR unreachable pattern +LL | &[0x41, 0x41, 0x41, 0x41] => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -13,43 +13,43 @@ LL | #![deny(unreachable_patterns)] error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:15:9 | -LL | b"AAAA" => {}, //~ ERROR unreachable pattern +LL | b"AAAA" => {}, | ^^^^^^^ error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:21:9 | -LL | b"AAAA" => {}, //~ ERROR unreachable pattern +LL | b"AAAA" => {}, | ^^^^^^^ error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:27:9 | -LL | b"AAAA" => {}, //~ ERROR unreachable pattern +LL | b"AAAA" => {}, | ^^^^^^^ error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:35:9 | -LL | &[0x41, 0x41, 0x41, 0x41] => {} //~ ERROR unreachable pattern +LL | &[0x41, 0x41, 0x41, 0x41] => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:41:9 | -LL | b"AAAA" => {}, //~ ERROR unreachable pattern +LL | b"AAAA" => {}, | ^^^^^^^ error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:47:9 | -LL | b"AAAA" => {}, //~ ERROR unreachable pattern +LL | b"AAAA" => {}, | ^^^^^^^ error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:53:9 | -LL | b"AAAA" => {}, //~ ERROR unreachable pattern +LL | b"AAAA" => {}, | ^^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/match/match-fn-call.stderr b/src/test/ui/match/match-fn-call.stderr index 4e24621706bdb..bd918428351b9 100644 --- a/src/test/ui/match/match-fn-call.stderr +++ b/src/test/ui/match/match-fn-call.stderr @@ -2,13 +2,17 @@ error[E0164]: expected tuple struct/variant, found method `::new` --> $DIR/match-fn-call.rs:6:9 | LL | Path::new("foo") => println!("foo"), - | ^^^^^^^^^^^^^^^^ not a tuple variant or struct + | ^^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns + | + = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html error[E0164]: expected tuple struct/variant, found method `::new` --> $DIR/match-fn-call.rs:8:9 | LL | Path::new("bar") => println!("bar"), - | ^^^^^^^^^^^^^^^^ not a tuple variant or struct + | ^^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns + | + = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html error: aborting due to 2 previous errors diff --git a/src/test/ui/match/match-ill-type2.stderr b/src/test/ui/match/match-ill-type2.stderr index 116d26ac71210..83fae10d4cb4e 100644 --- a/src/test/ui/match/match-ill-type2.stderr +++ b/src/test/ui/match/match-ill-type2.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/match-ill-type2.rs:4:9 | -LL | 2u32 => 1, //~ ERROR mismatched types +LL | 2u32 => 1, | ^^^^ expected i32, found u32 error: aborting due to previous error diff --git a/src/test/ui/match/match-join.stderr b/src/test/ui/match/match-join.stderr index 6e08c92bedb54..27a82c1242cc7 100644 --- a/src/test/ui/match/match-join.stderr +++ b/src/test/ui/match/match-join.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `x` in this scope --> $DIR/match-join.rs:9:20 | -LL | println!("{}", x); //~ ERROR cannot find value `x` in this scope +LL | println!("{}", x); | ^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/match/match-no-arms-unreachable-after.stderr b/src/test/ui/match/match-no-arms-unreachable-after.stderr index bd136245c1ae9..65dcc6ee46554 100644 --- a/src/test/ui/match/match-no-arms-unreachable-after.stderr +++ b/src/test/ui/match/match-no-arms-unreachable-after.stderr @@ -1,7 +1,7 @@ error: unreachable statement --> $DIR/match-no-arms-unreachable-after.rs:8:5 | -LL | let x = 2; //~ ERROR unreachable +LL | let x = 2; | ^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/match/match-non-exhaustive.stderr b/src/test/ui/match/match-non-exhaustive.stderr index ab5ab18c3283a..00c2bfff7eb45 100644 --- a/src/test/ui/match/match-non-exhaustive.stderr +++ b/src/test/ui/match/match-non-exhaustive.stderr @@ -1,14 +1,18 @@ error[E0004]: non-exhaustive patterns: `-2147483648i32..=0i32` and `2i32..=2147483647i32` not covered --> $DIR/match-non-exhaustive.rs:2:11 | -LL | match 0 { 1 => () } //~ ERROR non-exhaustive patterns +LL | match 0 { 1 => () } | ^ patterns `-2147483648i32..=0i32` and `2i32..=2147483647i32` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/match-non-exhaustive.rs:3:11 | -LL | match 0 { 0 if false => () } //~ ERROR non-exhaustive patterns +LL | match 0 { 0 if false => () } | ^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to 2 previous errors diff --git a/src/test/ui/match/match-privately-empty.stderr b/src/test/ui/match/match-privately-empty.stderr index 23ca64e50af78..f79d180a1b8b5 100644 --- a/src/test/ui/match/match-privately-empty.stderr +++ b/src/test/ui/match/match-privately-empty.stderr @@ -3,6 +3,8 @@ error[E0004]: non-exhaustive patterns: `Some(Private { misc: true, .. })` not co | LL | match private::DATA { | ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/match/match-range-fail-2.stderr b/src/test/ui/match/match-range-fail-2.stderr index b9e4534fdf5de..52a2bf2b34aa6 100644 --- a/src/test/ui/match/match-range-fail-2.stderr +++ b/src/test/ui/match/match-range-fail-2.stderr @@ -18,5 +18,5 @@ LL | 0xFFFF_FFFF_FFFF_FFFF ..= 1 => { } error: aborting due to 3 previous errors -Some errors occurred: E0030, E0579. +Some errors have detailed explanations: E0030, E0579. For more information about an error, try `rustc --explain E0030`. diff --git a/src/test/ui/match/match-range-fail-dominate.rs b/src/test/ui/match/match-range-fail-dominate.rs index 99069183e4eda..a0cc773d20edd 100644 --- a/src/test/ui/match/match-range-fail-dominate.rs +++ b/src/test/ui/match/match-range-fail-dominate.rs @@ -8,31 +8,31 @@ fn main() { match 5 { - 1 ... 10 => { } - 5 ... 6 => { } + 1 ..= 10 => { } + 5 ..= 6 => { } _ => {} }; match 5 { - 3 ... 6 => { } - 4 ... 6 => { } + 3 ..= 6 => { } + 4 ..= 6 => { } _ => {} }; match 5 { - 4 ... 6 => { } - 4 ... 6 => { } + 4 ..= 6 => { } + 4 ..= 6 => { } _ => {} }; match 'c' { - 'A' ... 'z' => {} - 'a' ... 'z' => {} + 'A' ..= 'z' => {} + 'a' ..= 'z' => {} _ => {} }; match 1.0f64 { - 0.01f64 ... 6.5f64 => {} + 0.01f64 ..= 6.5f64 => {} 0.02f64 => {} _ => {} }; diff --git a/src/test/ui/match/match-range-fail-dominate.stderr b/src/test/ui/match/match-range-fail-dominate.stderr index d35394aa38ba0..f481e56c85e56 100644 --- a/src/test/ui/match/match-range-fail-dominate.stderr +++ b/src/test/ui/match/match-range-fail-dominate.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/match-range-fail-dominate.rs:12:7 | -LL | 5 ... 6 => { } +LL | 5 ..= 6 => { } | ^^^^^^^ | note: lint level defined here @@ -13,25 +13,25 @@ LL | #![deny(unreachable_patterns)] error: unreachable pattern --> $DIR/match-range-fail-dominate.rs:18:7 | -LL | 4 ... 6 => { } +LL | 4 ..= 6 => { } | ^^^^^^^ error: unreachable pattern --> $DIR/match-range-fail-dominate.rs:24:7 | -LL | 4 ... 6 => { } +LL | 4 ..= 6 => { } | ^^^^^^^ error: unreachable pattern --> $DIR/match-range-fail-dominate.rs:30:7 | -LL | 'a' ... 'z' => {} +LL | 'a' ..= 'z' => {} | ^^^^^^^^^^^ warning: floating-point types cannot be used in patterns --> $DIR/match-range-fail-dominate.rs:35:7 | -LL | 0.01f64 ... 6.5f64 => {} +LL | 0.01f64 ..= 6.5f64 => {} | ^^^^^^^ | = note: #[warn(illegal_floating_point_literal_pattern)] on by default @@ -41,7 +41,7 @@ LL | 0.01f64 ... 6.5f64 => {} warning: floating-point types cannot be used in patterns --> $DIR/match-range-fail-dominate.rs:35:19 | -LL | 0.01f64 ... 6.5f64 => {} +LL | 0.01f64 ..= 6.5f64 => {} | ^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -62,5 +62,14 @@ error: unreachable pattern LL | 0.02f64 => {} | ^^^^^^^ +warning: floating-point types cannot be used in patterns + --> $DIR/match-range-fail-dominate.rs:35:7 + | +LL | 0.01f64 ..= 6.5f64 => {} + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + error: aborting due to 5 previous errors diff --git a/src/test/ui/match/match-range-fail.stderr b/src/test/ui/match/match-range-fail.stderr index 54969927433a4..3fd2a499e2bc3 100644 --- a/src/test/ui/match/match-range-fail.stderr +++ b/src/test/ui/match/match-range-fail.stderr @@ -27,5 +27,5 @@ LL | 'c' ..= 100 => { } error: aborting due to 3 previous errors -Some errors occurred: E0029, E0308. +Some errors have detailed explanations: E0029, E0308. For more information about an error, try `rustc --explain E0029`. diff --git a/src/test/ui/match/match-ref-ice.stderr b/src/test/ui/match/match-ref-ice.stderr index faefd9f212904..c4bfa0afcc278 100644 --- a/src/test/ui/match/match-ref-ice.stderr +++ b/src/test/ui/match/match-ref-ice.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/match-ref-ice.rs:13:9 | -LL | [1, 2, 3] => (), //~ ERROR unreachable pattern +LL | [1, 2, 3] => (), | ^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/match/match-ref-mut-invariance.nll.stderr b/src/test/ui/match/match-ref-mut-invariance.nll.stderr new file mode 100644 index 0000000000000..505b8db6a3332 --- /dev/null +++ b/src/test/ui/match/match-ref-mut-invariance.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/match-ref-mut-invariance.rs:10:9 + | +LL | impl<'b> S<'b> { + | -- lifetime `'b` defined here +LL | fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { + | -- lifetime `'a` defined here +LL | match self.0 { ref mut x => x } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b` + +error: aborting due to previous error + diff --git a/src/test/ui/match/match-ref-mut-invariance.stderr b/src/test/ui/match/match-ref-mut-invariance.stderr index 61552b44c2757..30bbb8d7800f9 100644 --- a/src/test/ui/match/match-ref-mut-invariance.stderr +++ b/src/test/ui/match/match-ref-mut-invariance.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/match-ref-mut-invariance.rs:10:37 | -LL | match self.0 { ref mut x => x } //~ ERROR mismatched types +LL | match self.0 { ref mut x => x } | ^ lifetime mismatch | = note: expected type `&'a mut &'a i32` diff --git a/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr b/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr new file mode 100644 index 0000000000000..ab5f43d022281 --- /dev/null +++ b/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/match-ref-mut-let-invariance.rs:11:9 + | +LL | impl<'b> S<'b> { + | -- lifetime `'b` defined here +LL | fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { + | -- lifetime `'a` defined here +LL | let ref mut x = self.0; +LL | x + | ^ returning this value requires that `'a` must outlive `'b` + +error: aborting due to previous error + diff --git a/src/test/ui/match/match-ref-mut-let-invariance.stderr b/src/test/ui/match/match-ref-mut-let-invariance.stderr index 26ec0697f410e..6ca222d9c2ffc 100644 --- a/src/test/ui/match/match-ref-mut-let-invariance.stderr +++ b/src/test/ui/match/match-ref-mut-let-invariance.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/match-ref-mut-let-invariance.rs:11:9 | -LL | x //~ ERROR mismatched types +LL | x | ^ lifetime mismatch | = note: expected type `&'a mut &'a i32` diff --git a/src/test/ui/match/match-slice-patterns.stderr b/src/test/ui/match/match-slice-patterns.stderr index 2b817498aba9f..24769db34c932 100644 --- a/src/test/ui/match/match-slice-patterns.stderr +++ b/src/test/ui/match/match-slice-patterns.stderr @@ -3,6 +3,8 @@ error[E0004]: non-exhaustive patterns: `&[_, Some(_), None, _]` not covered | LL | match list { | ^^^^ pattern `&[_, Some(_), None, _]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/match/match-tag-nullary.stderr b/src/test/ui/match/match-tag-nullary.stderr index 014581ea4bd05..902ccc94dde23 100644 --- a/src/test/ui/match/match-tag-nullary.stderr +++ b/src/test/ui/match/match-tag-nullary.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/match-tag-nullary.rs:4:40 | -LL | fn main() { let x: A = A::A; match x { B::B => { } } } //~ ERROR mismatched types +LL | fn main() { let x: A = A::A; match x { B::B => { } } } | ^^^^ expected enum `A`, found enum `B` | = note: expected type `A` diff --git a/src/test/ui/match/match-tag-unary.stderr b/src/test/ui/match/match-tag-unary.stderr index 53b6635136966..da599c3740740 100644 --- a/src/test/ui/match/match-tag-unary.stderr +++ b/src/test/ui/match/match-tag-unary.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/match-tag-unary.rs:4:43 | -LL | fn main() { let x: A = A::A(0); match x { B::B(y) => { } } } //~ ERROR mismatched types +LL | fn main() { let x: A = A::A(0); match x { B::B(y) => { } } } | - ^^^^^^^ expected enum `A`, found enum `B` | | | this match expression has type `A` diff --git a/src/test/ui/match/match-type-err-first-arm.rs b/src/test/ui/match/match-type-err-first-arm.rs index b4b84ef8f1cec..8dfbf1019e9a4 100644 --- a/src/test/ui/match/match-type-err-first-arm.rs +++ b/src/test/ui/match/match-type-err-first-arm.rs @@ -3,8 +3,7 @@ fn main() { let _ = test_func2(1); } -fn test_func1(n: i32) -> i32 { - //~^ NOTE expected `i32` because of return type +fn test_func1(n: i32) -> i32 { //~ NOTE expected `i32` because of return type match n { 12 => 'b', //~^ ERROR mismatched types @@ -14,10 +13,8 @@ fn test_func1(n: i32) -> i32 { } fn test_func2(n: i32) -> i32 { - let x = match n { - //~^ NOTE `match` arms have incompatible types - 12 => 'b', - //~^ NOTE this is found to be of type `char` + let x = match n { //~ NOTE `match` arms have incompatible types + 12 => 'b', //~ NOTE this is found to be of type `char` _ => 42, //~^ ERROR match arms have incompatible types //~| NOTE expected char, found integer @@ -27,8 +24,7 @@ fn test_func2(n: i32) -> i32 { } fn test_func3(n: i32) -> i32 { - let x = match n { - //~^ NOTE `match` arms have incompatible types + let x = match n { //~ NOTE `match` arms have incompatible types 1 => 'b', 2 => 'b', 3 => 'b', @@ -43,3 +39,15 @@ fn test_func3(n: i32) -> i32 { }; x } + +fn test_func4() { + match Some(0u32) { //~ NOTE `match` arms have incompatible types + Some(x) => { + x //~ NOTE this is found to be of type `u32` + }, + None => {} + //~^ ERROR match arms have incompatible types + //~| NOTE expected u32, found () + //~| NOTE expected type `u32` + }; +} diff --git a/src/test/ui/match/match-type-err-first-arm.stderr b/src/test/ui/match/match-type-err-first-arm.stderr index db8bef8dc7755..e0553fca683a5 100644 --- a/src/test/ui/match/match-type-err-first-arm.stderr +++ b/src/test/ui/match/match-type-err-first-arm.stderr @@ -1,25 +1,24 @@ error[E0308]: mismatched types - --> $DIR/match-type-err-first-arm.rs:9:15 + --> $DIR/match-type-err-first-arm.rs:8:15 | LL | fn test_func1(n: i32) -> i32 { | --- expected `i32` because of return type -... +LL | match n { LL | 12 => 'b', | ^^^ expected i32, found char error[E0308]: match arms have incompatible types - --> $DIR/match-type-err-first-arm.rs:21:14 + --> $DIR/match-type-err-first-arm.rs:18:14 | LL | let x = match n { | _____________- -LL | | //~^ NOTE `match` arms have incompatible types LL | | 12 => 'b', | | --- this is found to be of type `char` -LL | | //~^ NOTE this is found to be of type `char` LL | | _ => 42, | | ^^ expected char, found integer -... | -LL | | //~| NOTE expected type `char` +LL | | +LL | | +LL | | LL | | }; | |_____- `match` arms have incompatible types | @@ -27,27 +26,45 @@ LL | | }; found type `{integer}` error[E0308]: match arms have incompatible types - --> $DIR/match-type-err-first-arm.rs:39:14 + --> $DIR/match-type-err-first-arm.rs:35:14 | LL | let x = match n { | _____________- -LL | | //~^ NOTE `match` arms have incompatible types LL | | 1 => 'b', LL | | 2 => 'b', +LL | | 3 => 'b', ... | LL | | 6 => 'b', | | --- this and all prior arms are found to be of type `char` -LL | | //~^ NOTE this and all prior arms are found to be of type `char` +LL | | LL | | _ => 42, | | ^^ expected char, found integer ... | -LL | | //~| NOTE expected type `char` +LL | | LL | | }; | |_____- `match` arms have incompatible types | = note: expected type `char` found type `{integer}` -error: aborting due to 3 previous errors +error[E0308]: match arms have incompatible types + --> $DIR/match-type-err-first-arm.rs:48:17 + | +LL | / match Some(0u32) { +LL | | Some(x) => { +LL | | x + | | - this is found to be of type `u32` +LL | | }, +LL | | None => {} + | | ^^ expected u32, found () +... | +LL | | +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected type `u32` + found type `()` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/match/match-unresolved-one-arm.stderr b/src/test/ui/match/match-unresolved-one-arm.stderr index b013933eaae6a..ad8569b4802fb 100644 --- a/src/test/ui/match/match-unresolved-one-arm.stderr +++ b/src/test/ui/match/match-unresolved-one-arm.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed --> $DIR/match-unresolved-one-arm.rs:4:9 | -LL | let x = match () { //~ ERROR type annotations needed +LL | let x = match () { | ^ | | | cannot infer type diff --git a/src/test/ui/match/match-vec-fixed.stderr b/src/test/ui/match/match-vec-fixed.stderr index f4b426bea325c..ae2dd87b6954b 100644 --- a/src/test/ui/match/match-vec-fixed.stderr +++ b/src/test/ui/match/match-vec-fixed.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/match-vec-fixed.rs:7:9 | -LL | [_, _, _] => {} //~ ERROR unreachable pattern +LL | [_, _, _] => {} | ^^^^^^^^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unreachable_patterns)] error: unreachable pattern --> $DIR/match-vec-fixed.rs:11:9 | -LL | [_, 1, _] => {} //~ ERROR unreachable pattern +LL | [_, 1, _] => {} | ^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/match/match-vec-mismatch.stderr b/src/test/ui/match/match-vec-mismatch.stderr index 93a407760a517..47f9d48e26290 100644 --- a/src/test/ui/match/match-vec-mismatch.stderr +++ b/src/test/ui/match/match-vec-mismatch.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `does_not_exist` in this scope --> $DIR/match-vec-mismatch.rs:28:11 | -LL | match does_not_exist { //~ ERROR cannot find value `does_not_exist` in this scope +LL | match does_not_exist { | ^^^^^^^^^^^^^^ not found in this scope error[E0529]: expected an array or slice, found `std::string::String` @@ -13,24 +13,24 @@ LL | ['f', 'o', ..] => {} error[E0527]: pattern requires 1 elements but array has 3 --> $DIR/match-vec-mismatch.rs:20:9 | -LL | [0] => {}, //~ ERROR pattern requires +LL | [0] => {}, | ^^^ expected 3 elements error[E0528]: pattern requires at least 4 elements but array has 3 --> $DIR/match-vec-mismatch.rs:25:9 | -LL | [0, 1, 2, 3, x..] => {} //~ ERROR pattern requires +LL | [0, 1, 2, 3, x..] => {} | ^^^^^^^^^^^^^^^^^ pattern cannot match array of 3 elements error[E0282]: type annotations needed --> $DIR/match-vec-mismatch.rs:36:9 | -LL | [] => {} //~ ERROR type annotations needed +LL | [] => {} | ^^ cannot infer type | = note: type must be known at this point error: aborting due to 5 previous errors -Some errors occurred: E0282, E0425, E0527, E0528, E0529. +Some errors have detailed explanations: E0282, E0425, E0527, E0528, E0529. For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/match/match-vec-unreachable.stderr b/src/test/ui/match/match-vec-unreachable.stderr index 71e3d8c5e31cd..415c24ae77ef5 100644 --- a/src/test/ui/match/match-vec-unreachable.stderr +++ b/src/test/ui/match/match-vec-unreachable.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/match-vec-unreachable.rs:9:9 | -LL | [(1, 2), (2, 3), b] => (), //~ ERROR unreachable pattern +LL | [(1, 2), (2, 3), b] => (), | ^^^^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -13,13 +13,13 @@ LL | #![deny(unreachable_patterns)] error: unreachable pattern --> $DIR/match-vec-unreachable.rs:19:9 | -LL | [_, _, _, _, _] => { } //~ ERROR unreachable pattern +LL | [_, _, _, _, _] => { } | ^^^^^^^^^^^^^^^ error: unreachable pattern --> $DIR/match-vec-unreachable.rs:27:9 | -LL | ['a', 'b', 'c'] => {} //~ ERROR unreachable pattern +LL | ['a', 'b', 'c'] => {} | ^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/maybe-bounds-where.stderr b/src/test/ui/maybe-bounds-where.stderr index 562e597728ebd..78524cbabecd7 100644 --- a/src/test/ui/maybe-bounds-where.stderr +++ b/src/test/ui/maybe-bounds-where.stderr @@ -42,4 +42,3 @@ LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0203`. diff --git a/src/test/ui/maybe-bounds.rs b/src/test/ui/maybe-bounds.rs index 3e07026fb7d71..02ed45c656f1c 100644 --- a/src/test/ui/maybe-bounds.rs +++ b/src/test/ui/maybe-bounds.rs @@ -1,6 +1,9 @@ -trait Tr: ?Sized {} //~ ERROR `?Trait` is not permitted in supertraits +trait Tr: ?Sized {} +//~^ ERROR `?Trait` is not permitted in supertraits -type A1 = Tr + (?Sized); //~ ERROR `?Trait` is not permitted in trait object types -type A2 = for<'a> Tr + (?Sized); //~ ERROR `?Trait` is not permitted in trait object types +type A1 = dyn Tr + (?Sized); +//~^ ERROR `?Trait` is not permitted in trait object types +type A2 = dyn for<'a> Tr + (?Sized); +//~^ ERROR `?Trait` is not permitted in trait object types fn main() {} diff --git a/src/test/ui/maybe-bounds.stderr b/src/test/ui/maybe-bounds.stderr index 58f5b790c097c..1d823b6acb283 100644 --- a/src/test/ui/maybe-bounds.stderr +++ b/src/test/ui/maybe-bounds.stderr @@ -1,22 +1,22 @@ error: `?Trait` is not permitted in supertraits --> $DIR/maybe-bounds.rs:1:11 | -LL | trait Tr: ?Sized {} //~ ERROR `?Trait` is not permitted in supertraits +LL | trait Tr: ?Sized {} | ^^^^^^ | = note: traits are `?Sized` by default error: `?Trait` is not permitted in trait object types - --> $DIR/maybe-bounds.rs:3:16 + --> $DIR/maybe-bounds.rs:4:20 | -LL | type A1 = Tr + (?Sized); //~ ERROR `?Trait` is not permitted in trait object types - | ^^^^^^^^ +LL | type A1 = dyn Tr + (?Sized); + | ^^^^^^^^ error: `?Trait` is not permitted in trait object types - --> $DIR/maybe-bounds.rs:4:24 + --> $DIR/maybe-bounds.rs:6:28 | -LL | type A2 = for<'a> Tr + (?Sized); //~ ERROR `?Trait` is not permitted in trait object types - | ^^^^^^^^ +LL | type A2 = dyn for<'a> Tr + (?Sized); + | ^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/meta-expected-error-correct-rev.a.stderr b/src/test/ui/meta-expected-error-correct-rev.a.stderr index b561a9e5b3afc..db1d5070e7fa1 100644 --- a/src/test/ui/meta-expected-error-correct-rev.a.stderr +++ b/src/test/ui/meta-expected-error-correct-rev.a.stderr @@ -1,8 +1,12 @@ error[E0308]: mismatched types --> $DIR/meta-expected-error-correct-rev.rs:7:18 | -LL | let x: u32 = 22_usize; //[a]~ ERROR mismatched types +LL | let x: u32 = 22_usize; | ^^^^^^^^ expected u32, found usize +help: change the type of the numeric literal from `usize` to `u32` + | +LL | let x: u32 = 22_u32; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs index 590e98dc35365..e33f23c64dbe1 100644 --- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs @@ -22,7 +22,7 @@ impl Foo for Vec { fn m1() { // we couldn't infer the type of the vector just based on calling foo()... let mut x = Vec::new(); - //~^ ERROR type annotations needed [E0282] + //~^ ERROR type annotations needed x.foo(); } diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr index 53a07f5196e4b..b1bd749bef4a2 100644 --- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr @@ -1,18 +1,22 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `std::vec::Vec` --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17 | LL | let mut x = Vec::new(); | ----- ^^^^^^^^ cannot infer type for `T` | | - | consider giving `x` a type + | consider giving `x` the explicit type `std::vec::Vec`, where the type parameter `T` is specified error[E0308]: mismatched types --> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20 | -LL | let y: usize = x.foo(); //~ ERROR mismatched types +LL | let y: usize = x.foo(); | ^^^^^^^ expected usize, found isize +help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit + | +LL | let y: usize = x.foo().try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors -Some errors occurred: E0282, E0308. +Some errors have detailed explanations: E0282, E0308. For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr index 15379194777c9..2b87ddfdf98e5 100644 --- a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr @@ -1,7 +1,7 @@ error[E0034]: multiple applicable items in scope --> $DIR/method-ambig-two-traits-cross-crate.rs:11:21 | -LL | fn main() { 1_usize.me(); } //~ ERROR E0034 +LL | fn main() { 1_usize.me(); } | ^^ multiple `me` found | note: candidate #1 is defined in an impl of the trait `Me2` for the type `usize` diff --git a/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr b/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr index a805ca3ca56b2..6c493c67e29d9 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr @@ -1,7 +1,7 @@ error[E0034]: multiple applicable items in scope --> $DIR/method-ambig-two-traits-from-bounds.rs:5:7 | -LL | t.foo(); //~ ERROR E0034 +LL | t.foo(); | ^^^ multiple `foo` found | note: candidate #1 is defined in the trait `A` diff --git a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr index cbb1754935a97..5d508d5702258 100644 --- a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr @@ -1,7 +1,7 @@ error[E0034]: multiple applicable items in scope --> $DIR/method-ambig-two-traits-with-default-method.rs:12:13 | -LL | 1_usize.method(); //~ ERROR E0034 +LL | 1_usize.method(); | ^^^^^^ multiple `method` found | note: candidate #1 is defined in an impl of the trait `Foo` for the type `usize` diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr index 2113add63d61d..b8ae4c34dc155 100644 --- a/src/test/ui/methods/method-call-err-msg.stderr +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -4,7 +4,7 @@ error[E0061]: this function takes 0 parameters but 1 parameter was supplied LL | fn zero(self) -> Foo { self } | -------------------- defined here ... -LL | x.zero(0) //~ ERROR this function takes 0 parameters but 1 parameter was supplied +LL | x.zero(0) | ^^^^ expected 0 parameters error[E0061]: this function takes 1 parameter but 0 parameters were supplied @@ -13,7 +13,7 @@ error[E0061]: this function takes 1 parameter but 0 parameters were supplied LL | fn one(self, _: isize) -> Foo { self } | ----------------------------- defined here ... -LL | .one() //~ ERROR this function takes 1 parameter but 0 parameters were supplied +LL | .one() | ^^^ expected 1 parameter error[E0061]: this function takes 2 parameters but 1 parameter was supplied @@ -22,7 +22,7 @@ error[E0061]: this function takes 2 parameters but 1 parameter was supplied LL | fn two(self, _: isize, _: isize) -> Foo { self } | --------------------------------------- defined here ... -LL | .two(0); //~ ERROR this function takes 2 parameters but 1 parameter was supplied +LL | .two(0); | ^^^ expected 2 parameters error[E0599]: no method named `take` found for type `Foo` in the current scope @@ -31,7 +31,7 @@ error[E0599]: no method named `take` found for type `Foo` in the current scope LL | pub struct Foo; | --------------- method `take` not found for this ... -LL | .take() //~ ERROR no method named `take` found for type `Foo` in the current scope +LL | .take() | ^^^^ | = note: the method `take` exists but the following trait bounds were not satisfied: @@ -43,5 +43,5 @@ LL | .take() //~ ERROR no method named `take` found for type `Foo` in th error: aborting due to 4 previous errors -Some errors occurred: E0061, E0599. +Some errors have detailed explanations: E0061, E0599. For more information about an error, try `rustc --explain E0061`. diff --git a/src/test/ui/methods/method-call-lifetime-args-lint-fail.rs b/src/test/ui/methods/method-call-lifetime-args-lint-fail.rs index 36a1a2fda6995..23893911eabd9 100644 --- a/src/test/ui/methods/method-call-lifetime-args-lint-fail.rs +++ b/src/test/ui/methods/method-call-lifetime-args-lint-fail.rs @@ -11,10 +11,10 @@ impl S { // 'late lifetimes here belong to nested types not to the tested functions. fn early_tricky_explicit<'a>(_: for<'late> fn(&'late u8), - _: Box Fn(&'late u8)>) + _: Box Fn(&'late u8)>) -> &'a u8 { loop {} } fn early_tricky_implicit<'a>(_: fn(&u8), - _: Box) + _: Box) -> &'a u8 { loop {} } } diff --git a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr index 25432177a8598..67fd8d7a13eb1 100644 --- a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr +++ b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr @@ -1,7 +1,7 @@ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/method-call-lifetime-args-unresolved.rs:2:15 | -LL | 0.clone::<'a>(); //~ ERROR use of undeclared lifetime name `'a` +LL | 0.clone::<'a>(); | ^^ undeclared lifetime error: aborting due to previous error diff --git a/src/test/ui/methods/method-call-type-binding.stderr b/src/test/ui/methods/method-call-type-binding.stderr index 27d6f93490bb8..4b93082ace575 100644 --- a/src/test/ui/methods/method-call-type-binding.stderr +++ b/src/test/ui/methods/method-call-type-binding.stderr @@ -1,7 +1,7 @@ error[E0229]: associated type bindings are not allowed here --> $DIR/method-call-type-binding.rs:2:15 | -LL | 0.clone::(); //~ ERROR associated type bindings are not allowed here +LL | 0.clone::(); | ^^^^^^ associated type not allowed here error: aborting due to previous error diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr index 2d8449b96de41..d6fac7025a479 100644 --- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:85:24 | -LL | let _seetype: () = z; //~ ERROR mismatched types +LL | let _seetype: () = z; | ^ expected (), found u32 | = note: expected type `()` @@ -10,7 +10,7 @@ LL | let _seetype: () = z; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:102:24 | -LL | let _seetype: () = z; //~ ERROR mismatched types +LL | let _seetype: () = z; | ^ expected (), found u64 | = note: expected type `()` @@ -19,7 +19,7 @@ LL | let _seetype: () = z; //~ ERROR mismatched types error[E0034]: multiple applicable items in scope --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:120:15 | -LL | let z = x.foo(); //~ ERROR multiple applicable items in scope +LL | let z = x.foo(); | ^^^ multiple `foo` found | note: candidate #1 is defined in an impl of the trait `internal::X` for the type `_` @@ -42,7 +42,7 @@ LL | fn foo(&self) -> u8; error[E0308]: mismatched types --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:137:24 | -LL | let _seetype: () = z; //~ ERROR mismatched types +LL | let _seetype: () = z; | ^ expected (), found u8 | = note: expected type `()` @@ -51,7 +51,7 @@ LL | let _seetype: () = z; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:155:24 | -LL | let _seetype: () = z; //~ ERROR mismatched types +LL | let _seetype: () = z; | ^ expected (), found u32 | = note: expected type `()` @@ -60,7 +60,7 @@ LL | let _seetype: () = z; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:172:24 | -LL | let _seetype: () = z; //~ ERROR mismatched types +LL | let _seetype: () = z; | ^ expected (), found u32 | = note: expected type `()` @@ -68,5 +68,5 @@ LL | let _seetype: () = z; //~ ERROR mismatched types error: aborting due to 6 previous errors -Some errors occurred: E0034, E0308. +Some errors have detailed explanations: E0034, E0308. For more information about an error, try `rustc --explain E0034`. diff --git a/src/test/ui/methods/method-macro-backtrace.stderr b/src/test/ui/methods/method-macro-backtrace.stderr index 81098bbceb052..7860365476a31 100644 --- a/src/test/ui/methods/method-macro-backtrace.stderr +++ b/src/test/ui/methods/method-macro-backtrace.stderr @@ -3,7 +3,7 @@ error[E0201]: duplicate definitions with name `bar`: | LL | fn bar(&self) { } | ----------------- previous definition of `bar` here -LL | fn bar(&self) { } //~ ERROR duplicate definitions +LL | fn bar(&self) { } | ^^^^^^^^^^^^^^^^^ duplicate definition error: aborting due to previous error diff --git a/src/test/ui/methods/method-missing-call.stderr b/src/test/ui/methods/method-missing-call.stderr index 886d92aa9253d..3ab5f66a0c3f6 100644 --- a/src/test/ui/methods/method-missing-call.stderr +++ b/src/test/ui/methods/method-missing-call.stderr @@ -1,13 +1,13 @@ error[E0615]: attempted to take value of method `get_x` on type `Point` --> $DIR/method-missing-call.rs:22:26 | -LL | .get_x;//~ ERROR attempted to take value of method `get_x` on type `Point` +LL | .get_x; | ^^^^^ help: use parentheses to call the method: `get_x()` error[E0615]: attempted to take value of method `filter_map` on type `std::iter::Filter, [closure@$DIR/method-missing-call.rs:27:20: 27:25]>, [closure@$DIR/method-missing-call.rs:28:23: 28:35]>` --> $DIR/method-missing-call.rs:29:16 | -LL | .filter_map; //~ ERROR attempted to take value of method `filter_map` on type +LL | .filter_map; | ^^^^^^^^^^ help: use parentheses to call the method: `filter_map(...)` error: aborting due to 2 previous errors diff --git a/src/test/ui/methods/method-path-in-pattern.stderr b/src/test/ui/methods/method-path-in-pattern.stderr index 03d6509c915d5..3f53ad768825b 100644 --- a/src/test/ui/methods/method-path-in-pattern.stderr +++ b/src/test/ui/methods/method-path-in-pattern.stderr @@ -18,4 +18,3 @@ LL | ::trait_bar => {} error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0533`. diff --git a/src/test/ui/methods/method-self-arg-1.stderr b/src/test/ui/methods/method-self-arg-1.stderr index 8c80d01b18cb9..8485a5403ff85 100644 --- a/src/test/ui/methods/method-self-arg-1.stderr +++ b/src/test/ui/methods/method-self-arg-1.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/method-self-arg-1.rs:11:14 | -LL | Foo::bar(x); //~ ERROR mismatched types +LL | Foo::bar(x); | ^ | | | expected &Foo, found struct `Foo` @@ -13,7 +13,7 @@ LL | Foo::bar(x); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/method-self-arg-1.rs:15:14 | -LL | Foo::bar(&42); //~ ERROR mismatched types +LL | Foo::bar(&42); | ^^^ expected struct `Foo`, found integer | = note: expected type `&Foo` diff --git a/src/test/ui/methods/method-self-arg-2.nll.stderr b/src/test/ui/methods/method-self-arg-2.nll.stderr deleted file mode 100644 index 8cfecdba41c0a..0000000000000 --- a/src/test/ui/methods/method-self-arg-2.nll.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/method-self-arg-2.rs:15:14 - | -LL | let y = &mut x; - | ------ mutable borrow occurs here -LL | Foo::bar(&x); //~ERROR cannot borrow `x` - | ^^ immutable borrow occurs here -LL | y.use_mut(); - | - mutable borrow later used here - -error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/method-self-arg-2.rs:20:14 - | -LL | let y = &mut x; - | ------ first mutable borrow occurs here -LL | Foo::baz(&mut x); //~ERROR cannot borrow `x` - | ^^^^^^ second mutable borrow occurs here -LL | y.use_mut(); - | - first borrow later used here - -error: aborting due to 2 previous errors - -Some errors occurred: E0499, E0502. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/methods/method-self-arg-2.stderr b/src/test/ui/methods/method-self-arg-2.stderr index 9746ac316d92f..946e71ee5b9c0 100644 --- a/src/test/ui/methods/method-self-arg-2.stderr +++ b/src/test/ui/methods/method-self-arg-2.stderr @@ -1,26 +1,24 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/method-self-arg-2.rs:15:15 + --> $DIR/method-self-arg-2.rs:15:14 | LL | let y = &mut x; - | - mutable borrow occurs here -LL | Foo::bar(&x); //~ERROR cannot borrow `x` - | ^ immutable borrow occurs here -... -LL | } - | - mutable borrow ends here + | ------ mutable borrow occurs here +LL | Foo::bar(&x); + | ^^ immutable borrow occurs here +LL | y.use_mut(); + | - mutable borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/method-self-arg-2.rs:20:19 + --> $DIR/method-self-arg-2.rs:20:14 | LL | let y = &mut x; - | - first mutable borrow occurs here -LL | Foo::baz(&mut x); //~ERROR cannot borrow `x` - | ^ second mutable borrow occurs here + | ------ first mutable borrow occurs here +LL | Foo::baz(&mut x); + | ^^^^^^ second mutable borrow occurs here LL | y.use_mut(); -LL | } - | - first borrow ends here + | - first borrow later used here error: aborting due to 2 previous errors -Some errors occurred: E0499, E0502. +Some errors have detailed explanations: E0499, E0502. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/mir-dataflow/def-inits-1.rs b/src/test/ui/mir-dataflow/def-inits-1.rs index 07ac1900bc71c..91d41e9b5794e 100644 --- a/src/test/ui/mir-dataflow/def-inits-1.rs +++ b/src/test/ui/mir-dataflow/def-inits-1.rs @@ -1,6 +1,5 @@ // General test of maybe_uninits state computed by MIR dataflow. -#![feature(nll)] #![feature(core_intrinsics, rustc_attrs)] use std::intrinsics::rustc_peek; diff --git a/src/test/ui/mir-dataflow/def-inits-1.stderr b/src/test/ui/mir-dataflow/def-inits-1.stderr index 93debd6c15d5a..48d8450489488 100644 --- a/src/test/ui/mir-dataflow/def-inits-1.stderr +++ b/src/test/ui/mir-dataflow/def-inits-1.stderr @@ -1,25 +1,25 @@ error: rustc_peek: bit not set - --> $DIR/def-inits-1.rs:15:14 + --> $DIR/def-inits-1.rs:14:14 | -LL | unsafe { rustc_peek(&ret); } //~ ERROR rustc_peek: bit not set +LL | unsafe { rustc_peek(&ret); } | ^^^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/def-inits-1.rs:31:14 + --> $DIR/def-inits-1.rs:30:14 | -LL | unsafe { rustc_peek(&z); } //~ ERROR rustc_peek: bit not set +LL | unsafe { rustc_peek(&z); } | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/def-inits-1.rs:34:14 + --> $DIR/def-inits-1.rs:33:14 | -LL | unsafe { rustc_peek(&y); } //~ ERROR rustc_peek: bit not set +LL | unsafe { rustc_peek(&y); } | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/def-inits-1.rs:42:14 + --> $DIR/def-inits-1.rs:41:14 | -LL | unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set +LL | unsafe { rustc_peek(&x); } | ^^^^^^^^^^^^^^ error: stop_after_dataflow ended compilation diff --git a/src/test/ui/mir-dataflow/inits-1.rs b/src/test/ui/mir-dataflow/inits-1.rs index 13f900e4a75ee..4a4786a2a7378 100644 --- a/src/test/ui/mir-dataflow/inits-1.rs +++ b/src/test/ui/mir-dataflow/inits-1.rs @@ -1,6 +1,5 @@ // General test of maybe_inits state computed by MIR dataflow. -#![feature(nll)] #![feature(core_intrinsics, rustc_attrs)] use std::intrinsics::rustc_peek; diff --git a/src/test/ui/mir-dataflow/inits-1.stderr b/src/test/ui/mir-dataflow/inits-1.stderr index 7ee61e6be2c8c..23d0679cb1ac1 100644 --- a/src/test/ui/mir-dataflow/inits-1.stderr +++ b/src/test/ui/mir-dataflow/inits-1.stderr @@ -1,19 +1,19 @@ error: rustc_peek: bit not set - --> $DIR/inits-1.rs:15:14 + --> $DIR/inits-1.rs:14:14 | -LL | unsafe { rustc_peek(&ret); } //~ ERROR rustc_peek: bit not set +LL | unsafe { rustc_peek(&ret); } | ^^^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/inits-1.rs:35:14 + --> $DIR/inits-1.rs:34:14 | -LL | unsafe { rustc_peek(&y); } //~ ERROR rustc_peek: bit not set +LL | unsafe { rustc_peek(&y); } | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/inits-1.rs:43:14 + --> $DIR/inits-1.rs:42:14 | -LL | unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set +LL | unsafe { rustc_peek(&x); } | ^^^^^^^^^^^^^^ error: stop_after_dataflow ended compilation diff --git a/src/test/ui/mir-dataflow/uninits-1.rs b/src/test/ui/mir-dataflow/uninits-1.rs index 4c64359693296..66b3f458a5159 100644 --- a/src/test/ui/mir-dataflow/uninits-1.rs +++ b/src/test/ui/mir-dataflow/uninits-1.rs @@ -1,6 +1,5 @@ // General test of maybe_uninits state computed by MIR dataflow. -#![feature(nll)] #![feature(core_intrinsics, rustc_attrs)] use std::intrinsics::rustc_peek; diff --git a/src/test/ui/mir-dataflow/uninits-1.stderr b/src/test/ui/mir-dataflow/uninits-1.stderr index 21ad0b3c2c16e..5f6dbde212d0a 100644 --- a/src/test/ui/mir-dataflow/uninits-1.stderr +++ b/src/test/ui/mir-dataflow/uninits-1.stderr @@ -1,31 +1,31 @@ error: rustc_peek: bit not set - --> $DIR/uninits-1.rs:19:14 + --> $DIR/uninits-1.rs:18:14 | -LL | unsafe { rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set +LL | unsafe { rustc_peek(&x) }; | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/uninits-1.rs:20:14 + --> $DIR/uninits-1.rs:19:14 | -LL | unsafe { rustc_peek(&y) }; //~ ERROR rustc_peek: bit not set +LL | unsafe { rustc_peek(&y) }; | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/uninits-1.rs:21:14 + --> $DIR/uninits-1.rs:20:14 | -LL | unsafe { rustc_peek(&z) }; //~ ERROR rustc_peek: bit not set +LL | unsafe { rustc_peek(&z) }; | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/uninits-1.rs:37:14 + --> $DIR/uninits-1.rs:36:14 | -LL | unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set +LL | unsafe { rustc_peek(&x); } | ^^^^^^^^^^^^^^ error: rustc_peek: bit not set - --> $DIR/uninits-1.rs:45:14 + --> $DIR/uninits-1.rs:44:14 | -LL | unsafe { rustc_peek(&ret); } //~ ERROR rustc_peek: bit not set +LL | unsafe { rustc_peek(&ret); } | ^^^^^^^^^^^^^^^^ error: stop_after_dataflow ended compilation diff --git a/src/test/ui/mir-dataflow/uninits-2.rs b/src/test/ui/mir-dataflow/uninits-2.rs index 2247e68d097fc..2ccf1c7f9d6c6 100644 --- a/src/test/ui/mir-dataflow/uninits-2.rs +++ b/src/test/ui/mir-dataflow/uninits-2.rs @@ -1,6 +1,5 @@ // General test of maybe_uninits state computed by MIR dataflow. -#![feature(nll)] #![feature(core_intrinsics, rustc_attrs)] use std::intrinsics::rustc_peek; diff --git a/src/test/ui/mir-dataflow/uninits-2.stderr b/src/test/ui/mir-dataflow/uninits-2.stderr index 08959ce3b1329..dcb61371994db 100644 --- a/src/test/ui/mir-dataflow/uninits-2.stderr +++ b/src/test/ui/mir-dataflow/uninits-2.stderr @@ -1,7 +1,7 @@ error: rustc_peek: bit not set - --> $DIR/uninits-2.rs:15:14 + --> $DIR/uninits-2.rs:14:14 | -LL | unsafe { rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set +LL | unsafe { rustc_peek(&x) }; | ^^^^^^^^^^^^^^ error: stop_after_dataflow ended compilation diff --git a/src/test/ui/mir-unpretty.stderr b/src/test/ui/mir-unpretty.stderr index 59e8c0bf09029..6e5dac226692a 100644 --- a/src/test/ui/mir-unpretty.stderr +++ b/src/test/ui/mir-unpretty.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/mir-unpretty.rs:4:17 | -LL | let x: () = 0; //~ ERROR: mismatched types +LL | let x: () = 0; | ^ expected (), found integer | = note: expected type `()` diff --git a/src/test/ui/mismatched_types/E0409.stderr b/src/test/ui/mismatched_types/E0409.stderr index 08f132efd0526..e3919bf260264 100644 --- a/src/test/ui/mismatched_types/E0409.stderr +++ b/src/test/ui/mismatched_types/E0409.stderr @@ -1,7 +1,7 @@ error[E0409]: variable `y` is bound in inconsistent ways within the same match arm --> $DIR/E0409.rs:5:23 | -LL | (0, ref y) | (y, 0) => {} //~ ERROR E0409 +LL | (0, ref y) | (y, 0) => {} | - ^ bound in different ways | | | first binding @@ -9,7 +9,7 @@ LL | (0, ref y) | (y, 0) => {} //~ ERROR E0409 error[E0308]: mismatched types --> $DIR/E0409.rs:5:23 | -LL | (0, ref y) | (y, 0) => {} //~ ERROR E0409 +LL | (0, ref y) | (y, 0) => {} | ^ expected &{integer}, found integer | = note: expected type `&{integer}` @@ -17,5 +17,5 @@ LL | (0, ref y) | (y, 0) => {} //~ ERROR E0409 error: aborting due to 2 previous errors -Some errors occurred: E0308, E0409. +Some errors have detailed explanations: E0308, E0409. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/mismatched_types/E0631.stderr b/src/test/ui/mismatched_types/E0631.stderr index df320a2059b85..8662bb7795382 100644 --- a/src/test/ui/mismatched_types/E0631.stderr +++ b/src/test/ui/mismatched_types/E0631.stderr @@ -1,7 +1,7 @@ error[E0631]: type mismatch in closure arguments --> $DIR/E0631.rs:7:5 | -LL | foo(|_: isize| {}); //~ ERROR type mismatch +LL | foo(|_: isize| {}); | ^^^ ---------- found signature of `fn(isize) -> _` | | | expected signature of `fn(usize) -> _` @@ -15,7 +15,7 @@ LL | fn foo(_: F) {} error[E0631]: type mismatch in closure arguments --> $DIR/E0631.rs:8:5 | -LL | bar(|_: isize| {}); //~ ERROR type mismatch +LL | bar(|_: isize| {}); | ^^^ ---------- found signature of `fn(isize) -> _` | | | expected signature of `fn(usize) -> _` @@ -32,7 +32,7 @@ error[E0631]: type mismatch in function arguments LL | fn f(_: u64) {} | ------------ found signature of `fn(u64) -> _` ... -LL | foo(f); //~ ERROR type mismatch +LL | foo(f); | ^^^ expected signature of `fn(usize) -> _` | note: required by `foo` @@ -47,7 +47,7 @@ error[E0631]: type mismatch in function arguments LL | fn f(_: u64) {} | ------------ found signature of `fn(u64) -> _` ... -LL | bar(f); //~ ERROR type mismatch +LL | bar(f); | ^^^ expected signature of `fn(usize) -> _` | note: required by `bar` @@ -58,4 +58,3 @@ LL | fn bar>(_: F) {} error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr index 6a5cf7db4eed9..b7f3b3dde8a93 100644 --- a/src/test/ui/mismatched_types/abridged.stderr +++ b/src/test/ui/mismatched_types/abridged.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | fn a() -> Foo { | --- expected `Foo` because of return type -LL | Some(Foo { bar: 1 }) //~ ERROR mismatched types +LL | Some(Foo { bar: 1 }) | ^^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::option::Option` | = note: expected type `Foo` @@ -14,7 +14,7 @@ error[E0308]: mismatched types | LL | fn a2() -> Foo { | --- expected `Foo` because of return type -LL | Ok(Foo { bar: 1}) //~ ERROR mismatched types +LL | Ok(Foo { bar: 1}) | ^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::result::Result` | = note: expected type `Foo` @@ -25,7 +25,7 @@ error[E0308]: mismatched types | LL | fn b() -> Option { | ----------- expected `std::option::Option` because of return type -LL | Foo { bar: 1 } //~ ERROR mismatched types +LL | Foo { bar: 1 } | ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo` | = note: expected type `std::option::Option` @@ -36,7 +36,7 @@ error[E0308]: mismatched types | LL | fn c() -> Result { | ---------------- expected `std::result::Result` because of return type -LL | Foo { bar: 1 } //~ ERROR mismatched types +LL | Foo { bar: 1 } | ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo` | = note: expected type `std::result::Result` @@ -48,7 +48,7 @@ error[E0308]: mismatched types LL | fn d() -> X, String> { | ---------------------------- expected `X, std::string::String>` because of return type ... -LL | x //~ ERROR mismatched types +LL | x | ^ expected struct `std::string::String`, found integer | = note: expected type `X, std::string::String>` @@ -60,7 +60,7 @@ error[E0308]: mismatched types LL | fn e() -> X, String> { | ---------------------------- expected `X, std::string::String>` because of return type ... -LL | x //~ ERROR mismatched types +LL | x | ^ expected struct `std::string::String`, found integer | = note: expected type `X, _>` diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 76ea0ab54c3dc..9dda44a85686f 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -1,7 +1,7 @@ error[E0277]: cannot add `std::option::Option<{integer}>` to `{integer}` --> $DIR/binops.rs:2:7 | -LL | 1 + Some(1); //~ ERROR cannot add `std::option::Option<{integer}>` to `{integer}` +LL | 1 + Some(1); | ^ no implementation for `{integer} + std::option::Option<{integer}>` | = help: the trait `std::ops::Add>` is not implemented for `{integer}` @@ -9,7 +9,7 @@ LL | 1 + Some(1); //~ ERROR cannot add `std::option::Option<{integer}>` to ` error[E0277]: cannot subtract `std::option::Option<{integer}>` from `usize` --> $DIR/binops.rs:3:16 | -LL | 2 as usize - Some(1); //~ ERROR cannot subtract `std::option::Option<{integer}>` from `usize` +LL | 2 as usize - Some(1); | ^ no implementation for `usize - std::option::Option<{integer}>` | = help: the trait `std::ops::Sub>` is not implemented for `usize` @@ -17,7 +17,7 @@ LL | 2 as usize - Some(1); //~ ERROR cannot subtract `std::option::Option<{i error[E0277]: cannot multiply `()` to `{integer}` --> $DIR/binops.rs:4:7 | -LL | 3 * (); //~ ERROR cannot multiply `()` to `{integer}` +LL | 3 * (); | ^ no implementation for `{integer} * ()` | = help: the trait `std::ops::Mul<()>` is not implemented for `{integer}` @@ -25,7 +25,7 @@ LL | 3 * (); //~ ERROR cannot multiply `()` to `{integer}` error[E0277]: cannot divide `{integer}` by `&str` --> $DIR/binops.rs:5:7 | -LL | 4 / ""; //~ ERROR cannot divide `{integer}` by `&str` +LL | 4 / ""; | ^ no implementation for `{integer} / &str` | = help: the trait `std::ops::Div<&str>` is not implemented for `{integer}` @@ -33,7 +33,7 @@ LL | 4 / ""; //~ ERROR cannot divide `{integer}` by `&str` error[E0277]: can't compare `{integer}` with `std::string::String` --> $DIR/binops.rs:6:7 | -LL | 5 < String::new(); //~ ERROR can't compare `{integer}` with `std::string::String` +LL | 5 < String::new(); | ^ no implementation for `{integer} < std::string::String` and `{integer} > std::string::String` | = help: the trait `std::cmp::PartialOrd` is not implemented for `{integer}` @@ -41,7 +41,7 @@ LL | 5 < String::new(); //~ ERROR can't compare `{integer}` with `std::strin error[E0277]: can't compare `{integer}` with `std::result::Result<{integer}, _>` --> $DIR/binops.rs:7:7 | -LL | 6 == Ok(1); //~ ERROR can't compare `{integer}` with `std::result::Result<{integer}, _>` +LL | 6 == Ok(1); | ^^ no implementation for `{integer} == std::result::Result<{integer}, _>` | = help: the trait `std::cmp::PartialEq>` is not implemented for `{integer}` diff --git a/src/test/ui/mismatched_types/cast-rfc0401.rs b/src/test/ui/mismatched_types/cast-rfc0401.rs index a5e03a18e6af2..b8d12fb9809ce 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.rs +++ b/src/test/ui/mismatched_types/cast-rfc0401.rs @@ -21,10 +21,10 @@ enum E { fn main() { let f: f32 = 1.2; - let v = 0 as *const u8; - let fat_v : *const [u8] = unsafe { &*(0 as *const [u8; 1])}; - let fat_sv : *const [i8] = unsafe { &*(0 as *const [i8; 1])}; - let foo: &Foo = &f; + let v = core::ptr::null::(); + let fat_v : *const [u8] = unsafe { &*core::ptr::null::<[u8; 1]>()}; + let fat_sv : *const [i8] = unsafe { &*core::ptr::null::<[i8; 1]>()}; + let foo: &dyn Foo = &f; let _ = v as &u8; //~ ERROR non-primitive cast let _ = v as E; //~ ERROR non-primitive cast @@ -50,7 +50,7 @@ fn main() let _ = 42usize as *const [u8]; //~ ERROR is invalid let _ = v as *const [u8]; //~ ERROR cannot cast - let _ = fat_v as *const Foo; //~ ERROR the size for values of type + let _ = fat_v as *const dyn Foo; //~ ERROR the size for values of type let _ = foo as *const str; //~ ERROR is invalid let _ = foo as *mut str; //~ ERROR is invalid let _ = main as *mut str; //~ ERROR is invalid @@ -59,14 +59,14 @@ fn main() let _ = fat_sv as usize; //~ ERROR is invalid let a : *const str = "hello"; - let _ = a as *const Foo; //~ ERROR the size for values of type + let _ = a as *const dyn Foo; //~ ERROR the size for values of type // check no error cascade let _ = main.f as *const u32; //~ ERROR no field - let cf: *const Foo = &0; + let cf: *const dyn Foo = &0; let _ = cf as *const [u16]; //~ ERROR is invalid - let _ = cf as *const Bar; //~ ERROR is invalid + let _ = cf as *const dyn Bar; //~ ERROR is invalid vec![0.0].iter().map(|s| s as f32).collect::>(); //~ ERROR is invalid } diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 76091f2d09ed4..f94dfd100a6f4 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -1,7 +1,7 @@ error[E0606]: casting `*const U` as `*const V` is invalid --> $DIR/cast-rfc0401.rs:3:5 | -LL | u as *const V //~ ERROR is invalid +LL | u as *const V | ^^^^^^^^^^^^^ | = note: vtable kinds may not match @@ -9,7 +9,7 @@ LL | u as *const V //~ ERROR is invalid error[E0606]: casting `*const U` as `*const str` is invalid --> $DIR/cast-rfc0401.rs:8:5 | -LL | u as *const str //~ ERROR is invalid +LL | u as *const str | ^^^^^^^^^^^^^^^ | = note: vtable kinds may not match @@ -17,13 +17,13 @@ LL | u as *const str //~ ERROR is invalid error[E0609]: no field `f` on type `fn() {main}` --> $DIR/cast-rfc0401.rs:65:18 | -LL | let _ = main.f as *const u32; //~ ERROR no field +LL | let _ = main.f as *const u32; | ^ error[E0605]: non-primitive cast: `*const u8` as `&u8` --> $DIR/cast-rfc0401.rs:29:13 | -LL | let _ = v as &u8; //~ ERROR non-primitive cast +LL | let _ = v as &u8; | ^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait @@ -31,7 +31,7 @@ LL | let _ = v as &u8; //~ ERROR non-primitive cast error[E0605]: non-primitive cast: `*const u8` as `E` --> $DIR/cast-rfc0401.rs:30:13 | -LL | let _ = v as E; //~ ERROR non-primitive cast +LL | let _ = v as E; | ^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait @@ -39,7 +39,7 @@ LL | let _ = v as E; //~ ERROR non-primitive cast error[E0605]: non-primitive cast: `*const u8` as `fn()` --> $DIR/cast-rfc0401.rs:31:13 | -LL | let _ = v as fn(); //~ ERROR non-primitive cast +LL | let _ = v as fn(); | ^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait @@ -47,7 +47,7 @@ LL | let _ = v as fn(); //~ ERROR non-primitive cast error[E0605]: non-primitive cast: `*const u8` as `(u32,)` --> $DIR/cast-rfc0401.rs:32:13 | -LL | let _ = v as (u32,); //~ ERROR non-primitive cast +LL | let _ = v as (u32,); | ^^^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait @@ -55,7 +55,7 @@ LL | let _ = v as (u32,); //~ ERROR non-primitive cast error[E0605]: non-primitive cast: `std::option::Option<&*const u8>` as `*const u8` --> $DIR/cast-rfc0401.rs:33:13 | -LL | let _ = Some(&v) as *const u8; //~ ERROR non-primitive cast +LL | let _ = Some(&v) as *const u8; | ^^^^^^^^^^^^^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait @@ -63,19 +63,19 @@ LL | let _ = Some(&v) as *const u8; //~ ERROR non-primitive cast error[E0606]: casting `*const u8` as `f32` is invalid --> $DIR/cast-rfc0401.rs:35:13 | -LL | let _ = v as f32; //~ ERROR is invalid +LL | let _ = v as f32; | ^^^^^^^^ error[E0606]: casting `fn() {main}` as `f64` is invalid --> $DIR/cast-rfc0401.rs:36:13 | -LL | let _ = main as f64; //~ ERROR is invalid +LL | let _ = main as f64; | ^^^^^^^^^^^ error[E0606]: casting `&*const u8` as `usize` is invalid --> $DIR/cast-rfc0401.rs:37:13 | -LL | let _ = &v as usize; //~ ERROR is invalid +LL | let _ = &v as usize; | ^^^^^^^^^^^ | = help: cast through a raw pointer first @@ -83,31 +83,31 @@ LL | let _ = &v as usize; //~ ERROR is invalid error[E0606]: casting `f32` as `*const u8` is invalid --> $DIR/cast-rfc0401.rs:38:13 | -LL | let _ = f as *const u8; //~ ERROR is invalid +LL | let _ = f as *const u8; | ^^^^^^^^^^^^^^ error[E0054]: cannot cast as `bool` --> $DIR/cast-rfc0401.rs:39:13 | -LL | let _ = 3_i32 as bool; //~ ERROR cannot cast +LL | let _ = 3_i32 as bool; | ^^^^^^^^^^^^^ help: compare with zero instead: `3_i32 != 0` error[E0054]: cannot cast as `bool` --> $DIR/cast-rfc0401.rs:40:13 | -LL | let _ = E::A as bool; //~ ERROR cannot cast +LL | let _ = E::A as bool; | ^^^^^^^^^^^^ unsupported cast error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/cast-rfc0401.rs:41:13 | -LL | let _ = 0x61u32 as char; //~ ERROR can be cast as +LL | let _ = 0x61u32 as char; | ^^^^^^^^^^^^^^^ error[E0606]: casting `bool` as `f32` is invalid --> $DIR/cast-rfc0401.rs:43:13 | -LL | let _ = false as f32; //~ ERROR is invalid +LL | let _ = false as f32; | ^^^^^^^^^^^^ | = help: cast through an integer first @@ -115,7 +115,7 @@ LL | let _ = false as f32; //~ ERROR is invalid error[E0606]: casting `E` as `f32` is invalid --> $DIR/cast-rfc0401.rs:44:13 | -LL | let _ = E::A as f32; //~ ERROR is invalid +LL | let _ = E::A as f32; | ^^^^^^^^^^^ | = help: cast through an integer first @@ -123,7 +123,7 @@ LL | let _ = E::A as f32; //~ ERROR is invalid error[E0606]: casting `char` as `f32` is invalid --> $DIR/cast-rfc0401.rs:45:13 | -LL | let _ = 'a' as f32; //~ ERROR is invalid +LL | let _ = 'a' as f32; | ^^^^^^^^^^ | = help: cast through an integer first @@ -131,67 +131,67 @@ LL | let _ = 'a' as f32; //~ ERROR is invalid error[E0606]: casting `bool` as `*const u8` is invalid --> $DIR/cast-rfc0401.rs:47:13 | -LL | let _ = false as *const u8; //~ ERROR is invalid +LL | let _ = false as *const u8; | ^^^^^^^^^^^^^^^^^^ error[E0606]: casting `E` as `*const u8` is invalid --> $DIR/cast-rfc0401.rs:48:13 | -LL | let _ = E::A as *const u8; //~ ERROR is invalid +LL | let _ = E::A as *const u8; | ^^^^^^^^^^^^^^^^^ error[E0606]: casting `char` as `*const u8` is invalid --> $DIR/cast-rfc0401.rs:49:13 | -LL | let _ = 'a' as *const u8; //~ ERROR is invalid +LL | let _ = 'a' as *const u8; | ^^^^^^^^^^^^^^^^ error[E0606]: casting `usize` as `*const [u8]` is invalid --> $DIR/cast-rfc0401.rs:51:13 | -LL | let _ = 42usize as *const [u8]; //~ ERROR is invalid +LL | let _ = 42usize as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^ error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]` --> $DIR/cast-rfc0401.rs:52:13 | -LL | let _ = v as *const [u8]; //~ ERROR cannot cast +LL | let _ = v as *const [u8]; | ^^^^^^^^^^^^^^^^ error[E0606]: casting `&dyn Foo` as `*const str` is invalid --> $DIR/cast-rfc0401.rs:54:13 | -LL | let _ = foo as *const str; //~ ERROR is invalid +LL | let _ = foo as *const str; | ^^^^^^^^^^^^^^^^^ error[E0606]: casting `&dyn Foo` as `*mut str` is invalid --> $DIR/cast-rfc0401.rs:55:13 | -LL | let _ = foo as *mut str; //~ ERROR is invalid +LL | let _ = foo as *mut str; | ^^^^^^^^^^^^^^^ error[E0606]: casting `fn() {main}` as `*mut str` is invalid --> $DIR/cast-rfc0401.rs:56:13 | -LL | let _ = main as *mut str; //~ ERROR is invalid +LL | let _ = main as *mut str; | ^^^^^^^^^^^^^^^^ error[E0606]: casting `&f32` as `*mut f32` is invalid --> $DIR/cast-rfc0401.rs:57:13 | -LL | let _ = &f as *mut f32; //~ ERROR is invalid +LL | let _ = &f as *mut f32; | ^^^^^^^^^^^^^^ error[E0606]: casting `&f32` as `*const f64` is invalid --> $DIR/cast-rfc0401.rs:58:13 | -LL | let _ = &f as *const f64; //~ ERROR is invalid +LL | let _ = &f as *const f64; | ^^^^^^^^^^^^^^^^ error[E0606]: casting `*const [i8]` as `usize` is invalid --> $DIR/cast-rfc0401.rs:59:13 | -LL | let _ = fat_sv as usize; //~ ERROR is invalid +LL | let _ = fat_sv as usize; | ^^^^^^^^^^^^^^^ | = help: cast through a thin pointer first @@ -199,7 +199,7 @@ LL | let _ = fat_sv as usize; //~ ERROR is invalid error[E0606]: casting `*const dyn Foo` as `*const [u16]` is invalid --> $DIR/cast-rfc0401.rs:68:13 | -LL | let _ = cf as *const [u16]; //~ ERROR is invalid +LL | let _ = cf as *const [u16]; | ^^^^^^^^^^^^^^^^^^ | = note: vtable kinds may not match @@ -207,15 +207,15 @@ LL | let _ = cf as *const [u16]; //~ ERROR is invalid error[E0606]: casting `*const dyn Foo` as `*const dyn Bar` is invalid --> $DIR/cast-rfc0401.rs:69:13 | -LL | let _ = cf as *const Bar; //~ ERROR is invalid - | ^^^^^^^^^^^^^^^^ +LL | let _ = cf as *const dyn Bar; + | ^^^^^^^^^^^^^^^^^^^^ | = note: vtable kinds may not match error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/cast-rfc0401.rs:53:13 | -LL | let _ = fat_v as *const Foo; //~ ERROR the size for values of type +LL | let _ = fat_v as *const dyn Foo; | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` @@ -225,7 +225,7 @@ LL | let _ = fat_v as *const Foo; //~ ERROR the size for values of type error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/cast-rfc0401.rs:62:13 | -LL | let _ = a as *const Foo; //~ ERROR the size for values of type +LL | let _ = a as *const dyn Foo; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` @@ -235,7 +235,7 @@ LL | let _ = a as *const Foo; //~ ERROR the size for values of type error[E0606]: casting `&{float}` as `f32` is invalid --> $DIR/cast-rfc0401.rs:71:30 | -LL | vec![0.0].iter().map(|s| s as f32).collect::>(); //~ ERROR is invalid +LL | vec![0.0].iter().map(|s| s as f32).collect::>(); | -^^^^^^^ | | | cannot cast `&{float}` as `f32` @@ -243,5 +243,5 @@ LL | vec![0.0].iter().map(|s| s as f32).collect::>(); //~ ERROR is error: aborting due to 34 previous errors -Some errors occurred: E0054, E0277, E0604, E0605, E0606, E0607, E0609. +Some errors have detailed explanations: E0054, E0277, E0604, E0605, E0606, E0607, E0609. For more information about an error, try `rustc --explain E0054`. diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr index 5dd6887005e83..d4ccf8d451c12 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -1,7 +1,7 @@ error[E0631]: type mismatch in closure arguments --> $DIR/closure-arg-type-mismatch.rs:3:14 | -LL | a.iter().map(|_: (u32, u32)| 45); //~ ERROR type mismatch +LL | a.iter().map(|_: (u32, u32)| 45); | ^^^ ------------------ found signature of `fn((u32, u32)) -> _` | | | expected signature of `fn(&(u32, u32)) -> _` @@ -9,7 +9,7 @@ LL | a.iter().map(|_: (u32, u32)| 45); //~ ERROR type mismatch error[E0631]: type mismatch in closure arguments --> $DIR/closure-arg-type-mismatch.rs:4:14 | -LL | a.iter().map(|_: &(u16, u16)| 45); //~ ERROR type mismatch +LL | a.iter().map(|_: &(u16, u16)| 45); | ^^^ ------------------- found signature of `for<'r> fn(&'r (u16, u16)) -> _` | | | expected signature of `fn(&(u32, u32)) -> _` @@ -17,7 +17,7 @@ LL | a.iter().map(|_: &(u16, u16)| 45); //~ ERROR type mismatch error[E0631]: type mismatch in closure arguments --> $DIR/closure-arg-type-mismatch.rs:5:14 | -LL | a.iter().map(|_: (u16, u16)| 45); //~ ERROR type mismatch +LL | a.iter().map(|_: (u16, u16)| 45); | ^^^ ------------------ found signature of `fn((u16, u16)) -> _` | | | expected signature of `fn(&(u32, u32)) -> _` @@ -25,7 +25,7 @@ LL | a.iter().map(|_: (u16, u16)| 45); //~ ERROR type mismatch error[E0631]: type mismatch in function arguments --> $DIR/closure-arg-type-mismatch.rs:10:5 | -LL | baz(f); //~ ERROR type mismatch +LL | baz(f); | ^^^ | | | expected signature of `for<'r> fn(*mut &'r u32) -> _` @@ -40,7 +40,7 @@ LL | fn baz(_: F) {} error[E0271]: type mismatch resolving `for<'r> >::Output == ()` --> $DIR/closure-arg-type-mismatch.rs:10:5 | -LL | baz(f); //~ ERROR type mismatch +LL | baz(f); | ^^^ expected bound lifetime parameter, found concrete lifetime | note: required by `baz` @@ -51,5 +51,4 @@ LL | fn baz(_: F) {} error: aborting due to 5 previous errors -Some errors occurred: E0271, E0631. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index e55047e96c297..7161f6979087a 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -1,7 +1,7 @@ error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.rs:8:9: 8:15] as std::ops::FnOnce<(&'r (),)>>::Output == ()` --> $DIR/closure-mismatch.rs:8:5 | -LL | baz(|_| ()); //~ ERROR type mismatch +LL | baz(|_| ()); | ^^^ expected bound lifetime parameter, found concrete lifetime | = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]` @@ -14,7 +14,7 @@ LL | fn baz(_: T) {} error[E0631]: type mismatch in closure arguments --> $DIR/closure-mismatch.rs:8:5 | -LL | baz(|_| ()); //~ ERROR type mismatch +LL | baz(|_| ()); | ^^^ ------ found signature of `fn(_) -> _` | | | expected signature of `for<'r> fn(&'r ()) -> _` @@ -28,5 +28,4 @@ LL | fn baz(_: T) {} error: aborting due to 2 previous errors -Some errors occurred: E0271, E0631. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/mismatched_types/const-fn-in-trait.stderr b/src/test/ui/mismatched_types/const-fn-in-trait.stderr index e1482d7c45079..ec1f36bf08774 100644 --- a/src/test/ui/mismatched_types/const-fn-in-trait.stderr +++ b/src/test/ui/mismatched_types/const-fn-in-trait.stderr @@ -1,13 +1,13 @@ error[E0379]: trait fns cannot be declared const --> $DIR/const-fn-in-trait.rs:7:5 | -LL | const fn g(); //~ ERROR cannot be declared const +LL | const fn g(); | ^^^^^ trait fns cannot be const error[E0379]: trait fns cannot be declared const --> $DIR/const-fn-in-trait.rs:11:5 | -LL | const fn f() -> u32 { 22 } //~ ERROR cannot be declared const +LL | const fn f() -> u32 { 22 } | ^^^^^ trait fns cannot be const error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/fn-variance-1.stderr b/src/test/ui/mismatched_types/fn-variance-1.stderr index 0fb1a5346f322..c15d6620e18da 100644 --- a/src/test/ui/mismatched_types/fn-variance-1.stderr +++ b/src/test/ui/mismatched_types/fn-variance-1.stderr @@ -30,4 +30,3 @@ LL | fn apply(t: T, f: F) where F: FnOnce(T) { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/mismatched_types/for-loop-has-unit-body.stderr b/src/test/ui/mismatched_types/for-loop-has-unit-body.stderr index 25203d6f35d28..3c8ba8057c55a 100644 --- a/src/test/ui/mismatched_types/for-loop-has-unit-body.stderr +++ b/src/test/ui/mismatched_types/for-loop-has-unit-body.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/for-loop-has-unit-body.rs:3:9 | -LL | x //~ ERROR mismatched types +LL | x | ^ expected (), found integer | = note: expected type `()` diff --git a/src/test/ui/mismatched_types/issue-19109.rs b/src/test/ui/mismatched_types/issue-19109.rs index 030b7a40ca6fe..eae6a87905b33 100644 --- a/src/test/ui/mismatched_types/issue-19109.rs +++ b/src/test/ui/mismatched_types/issue-19109.rs @@ -1,7 +1,7 @@ trait Trait { } -fn function(t: &mut Trait) { - t as *mut Trait +fn function(t: &mut dyn Trait) { + t as *mut dyn Trait //~^ ERROR: mismatched types } diff --git a/src/test/ui/mismatched_types/issue-19109.stderr b/src/test/ui/mismatched_types/issue-19109.stderr index db2d484edff07..b826ca66c683a 100644 --- a/src/test/ui/mismatched_types/issue-19109.stderr +++ b/src/test/ui/mismatched_types/issue-19109.stderr @@ -1,10 +1,10 @@ error[E0308]: mismatched types --> $DIR/issue-19109.rs:4:5 | -LL | fn function(t: &mut Trait) { - | - help: try adding a return type: `-> *mut dyn Trait` -LL | t as *mut Trait - | ^^^^^^^^^^^^^^^ expected (), found *-ptr +LL | fn function(t: &mut dyn Trait) { + | - help: try adding a return type: `-> *mut dyn Trait` +LL | t as *mut dyn Trait + | ^^^^^^^^^^^^^^^^^^^ expected (), found *-ptr | = note: expected type `()` found type `*mut dyn Trait` diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 11aa6cd7c1ba8..881d9fd32029e 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -1,16 +1,20 @@ error[E0308]: mismatched types --> $DIR/issue-26480.rs:16:19 | -LL | $arr.len() * size_of($arr[0])); //~ ERROR mismatched types +LL | $arr.len() * size_of($arr[0])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize ... LL | write!(hello); | -------------- in this macro invocation +help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit + | +LL | ($arr.len() * size_of($arr[0])).try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0605]: non-primitive cast: `{integer}` as `()` --> $DIR/issue-26480.rs:22:19 | -LL | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast +LL | ($x:expr) => ($x as ()) | ^^^^^^^^ ... LL | cast!(2); @@ -20,5 +24,5 @@ LL | cast!(2); error: aborting due to 2 previous errors -Some errors occurred: E0308, E0605. +Some errors have detailed explanations: E0308, E0605. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/mismatched_types/issue-35030.stderr b/src/test/ui/mismatched_types/issue-35030.stderr index 6a3e7d930cf29..f030670161343 100644 --- a/src/test/ui/mismatched_types/issue-35030.stderr +++ b/src/test/ui/mismatched_types/issue-35030.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-35030.rs:9:14 | -LL | Some(true) //~ ERROR mismatched types +LL | Some(true) | ^^^^ expected type parameter, found bool | = note: expected type `bool` (type parameter) diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index c5c67e6bd9bd9..3f87ef74b8ea3 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -26,5 +26,4 @@ LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); error: aborting due to 3 previous errors -Some errors occurred: E0599, E0631. -For more information about an error, try `rustc --explain E0599`. +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr index f702a4f47f10c..a9347926bda0a 100644 --- a/src/test/ui/mismatched_types/issue-38371.stderr +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/issue-38371.rs:4:8 | -LL | fn foo(&foo: Foo) { //~ ERROR mismatched types +LL | fn foo(&foo: Foo) { | ^^^^ expected struct `Foo`, found reference | = note: expected type `Foo` @@ -11,17 +11,19 @@ LL | fn foo(&foo: Foo) { //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/issue-38371.rs:18:9 | -LL | fn agh(&&bar: &u32) { //~ ERROR mismatched types - | ^^^^ expected u32, found reference +LL | fn agh(&&bar: &u32) { + | ^^^^ + | | + | expected u32, found reference + | help: you can probably remove the explicit borrow: `bar` | = note: expected type `u32` found type `&_` - = help: did you mean `bar: &u32`? error[E0308]: mismatched types --> $DIR/issue-38371.rs:21:8 | -LL | fn bgh(&&bar: u32) { //~ ERROR mismatched types +LL | fn bgh(&&bar: u32) { | ^^^^^ expected u32, found reference | = note: expected type `u32` @@ -30,10 +32,10 @@ LL | fn bgh(&&bar: u32) { //~ ERROR mismatched types error[E0529]: expected an array or slice, found `u32` --> $DIR/issue-38371.rs:24:9 | -LL | fn ugh(&[bar]: &u32) { //~ ERROR expected an array or slice +LL | fn ugh(&[bar]: &u32) { | ^^^^^ pattern cannot match with input type `u32` error: aborting due to 4 previous errors -Some errors occurred: E0308, E0529. +Some errors have detailed explanations: E0308, E0529. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/mismatched_types/main.rs b/src/test/ui/mismatched_types/main.rs index 16c18ddda291a..e2d09dc219922 100644 --- a/src/test/ui/mismatched_types/main.rs +++ b/src/test/ui/mismatched_types/main.rs @@ -2,4 +2,3 @@ fn main() { let x: u32 = ( //~ ERROR mismatched types ); } - diff --git a/src/test/ui/mismatched_types/main.stderr b/src/test/ui/mismatched_types/main.stderr index 57e95e4133376..1d53cfdd2527c 100644 --- a/src/test/ui/mismatched_types/main.stderr +++ b/src/test/ui/mismatched_types/main.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/main.rs:2:18 | -LL | let x: u32 = ( //~ ERROR mismatched types +LL | let x: u32 = ( | __________________^ LL | | ); | |_____^ expected u32, found () diff --git a/src/test/ui/mismatched_types/numeric-literal-cast.rs b/src/test/ui/mismatched_types/numeric-literal-cast.rs index 74a2211709971..69cfe262fdf42 100644 --- a/src/test/ui/mismatched_types/numeric-literal-cast.rs +++ b/src/test/ui/mismatched_types/numeric-literal-cast.rs @@ -10,4 +10,3 @@ fn main() { foo2(3i16); //~^ ERROR mismatched types } - diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr index 51975abd720fd..bcb316e2bfb3f 100644 --- a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr +++ b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/overloaded-calls-bad.rs:28:17 | -LL | let ans = s("what"); //~ ERROR mismatched types +LL | let ans = s("what"); | ^^^^^^ expected isize, found reference | = note: expected type `isize` @@ -21,5 +21,5 @@ LL | let ans = s("burma", "shave"); error: aborting due to 3 previous errors -Some errors occurred: E0057, E0308. +Some errors have detailed explanations: E0057, E0308. For more information about an error, try `rustc --explain E0057`. diff --git a/src/test/ui/mismatched_types/trait-bounds-cant-coerce.rs b/src/test/ui/mismatched_types/trait-bounds-cant-coerce.rs index be5fab871b42f..882533992bd3c 100644 --- a/src/test/ui/mismatched_types/trait-bounds-cant-coerce.rs +++ b/src/test/ui/mismatched_types/trait-bounds-cant-coerce.rs @@ -2,14 +2,14 @@ trait Foo { fn dummy(&self) { } } -fn a(_x: Box) { +fn a(_x: Box) { } -fn c(x: Box) { +fn c(x: Box) { a(x); } -fn d(x: Box) { +fn d(x: Box) { a(x); //~ ERROR mismatched types [E0308] } diff --git a/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr b/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr index a9b637c81a78f..6475cce5aa62f 100644 --- a/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr +++ b/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/trait-bounds-cant-coerce.rs:13:7 | -LL | a(x); //~ ERROR mismatched types [E0308] +LL | a(x); | ^ expected trait `Foo + std::marker::Send`, found trait `Foo` | = note: expected type `std::boxed::Box<(dyn Foo + std::marker::Send + 'static)>` diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs index 3547272e51b51..949f5683c8a20 100644 --- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs @@ -14,4 +14,3 @@ impl Foo for Bar { fn main() { } - diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr index 4e54b35029a5f..8ea3567b948ce 100644 --- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr @@ -4,7 +4,7 @@ error[E0053]: method `foo` has an incompatible type for trait LL | fn foo(x: u16); | --- type in trait ... -LL | fn foo(x: i16) { } //~ ERROR incompatible type +LL | fn foo(x: i16) { } | ^^^ expected u16, found i16 | = note: expected type `fn(u16)` @@ -16,14 +16,14 @@ error[E0053]: method `bar` has an incompatible type for trait LL | fn bar(&mut self, bar: &mut Bar); | -------- type in trait ... -LL | fn bar(&mut self, bar: &Bar) { } //~ ERROR incompatible type +LL | fn bar(&mut self, bar: &Bar) { } | ^^^^ types differ in mutability | = note: expected type `fn(&mut Bar, &mut Bar)` found type `fn(&mut Bar, &Bar)` help: consider change the type to match the mutability in trait | -LL | fn bar(&mut self, bar: &mut Bar) { } //~ ERROR incompatible type +LL | fn bar(&mut self, bar: &mut Bar) { } | ^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr index 8db81a8c6835c..47aa3c21f5301 100644 --- a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr +++ b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr @@ -3,7 +3,7 @@ error[E0631]: type mismatch in closure arguments | LL | let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y }); | ----------------------------- found signature of `fn(usize, isize) -> _` -LL | //~^ NOTE found signature of `fn(usize, isize) -> _` +LL | LL | let z = call_it(3, f); | ^^^^^^^ expected signature of `fn(isize, isize) -> _` | @@ -15,4 +15,3 @@ LL | fn call_itisize>(y: isize, mut f: F) -> isize { error: aborting due to previous error -For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/missing/missing-alloc_error_handler.rs b/src/test/ui/missing/missing-alloc_error_handler.rs index 1a9e8688e8a42..ae0c067bb5f3e 100644 --- a/src/test/ui/missing/missing-alloc_error_handler.rs +++ b/src/test/ui/missing/missing-alloc_error_handler.rs @@ -3,7 +3,7 @@ #![no_std] #![crate_type = "staticlib"] -#![feature(panic_handler, alloc_error_handler, alloc)] +#![feature(panic_handler, alloc_error_handler)] #[panic_handler] fn panic(_: &core::panic::PanicInfo) -> ! { diff --git a/src/test/ui/missing/missing-allocator.rs b/src/test/ui/missing/missing-allocator.rs index dbb10d1e7b97e..6d867e2e8b48e 100644 --- a/src/test/ui/missing/missing-allocator.rs +++ b/src/test/ui/missing/missing-allocator.rs @@ -3,7 +3,7 @@ #![no_std] #![crate_type = "staticlib"] -#![feature(panic_handler, alloc_error_handler, alloc)] +#![feature(panic_handler, alloc_error_handler)] #[panic_handler] fn panic(_: &core::panic::PanicInfo) -> ! { diff --git a/src/test/ui/missing/missing-block-hint.stderr b/src/test/ui/missing/missing-block-hint.stderr index 576a6268a99df..ee86a3241e822 100644 --- a/src/test/ui/missing/missing-block-hint.stderr +++ b/src/test/ui/missing/missing-block-hint.stderr @@ -1,7 +1,7 @@ error: expected `{`, found `=>` --> $DIR/missing-block-hint.rs:3:18 | -LL | if (foo) => {} //~ ERROR expected `{`, found `=>` +LL | if (foo) => {} | -- ^^ expected `{` | | | this `if` statement has a condition, but no block @@ -11,7 +11,7 @@ error: expected `{`, found `bar` | LL | if (foo) | -- this `if` statement has a condition, but no block -LL | bar; //~ ERROR expected `{`, found `bar` +LL | bar; | ^^^- | | | expected `{` diff --git a/src/test/ui/missing/missing-derivable-attr.stderr b/src/test/ui/missing/missing-derivable-attr.stderr index e3e61bcb391eb..9b8c0c583a1c1 100644 --- a/src/test/ui/missing/missing-derivable-attr.stderr +++ b/src/test/ui/missing/missing-derivable-attr.stderr @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `eq` LL | fn eq(&self, other: &Self) -> bool; | ----------------------------------- `eq` from trait ... -LL | impl MyEq for A {} //~ ERROR not all trait items implemented, missing: `eq` +LL | impl MyEq for A {} | ^^^^^^^^^^^^^^^ missing `eq` in implementation error: aborting due to previous error diff --git a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr index 5d88a5d03e23b..f7037468996f4 100644 --- a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr +++ b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr @@ -14,5 +14,5 @@ LL | if let S { a, b, c, d } = S(1, 2, 3, 4) { error: aborting due to 2 previous errors -Some errors occurred: E0026, E0027. +Some errors have detailed explanations: E0026, E0027. For more information about an error, try `rustc --explain E0026`. diff --git a/src/test/ui/missing/missing-items/issue-40221.stderr b/src/test/ui/missing/missing-items/issue-40221.stderr index 437fb7bbc3131..8e5286f210013 100644 --- a/src/test/ui/missing/missing-items/issue-40221.stderr +++ b/src/test/ui/missing/missing-items/issue-40221.stderr @@ -1,8 +1,16 @@ error[E0004]: non-exhaustive patterns: `C(QA)` not covered --> $DIR/issue-40221.rs:11:11 | -LL | match proto { //~ ERROR non-exhaustive patterns - | ^^^^^ pattern `C(QA)` not covered +LL | / enum P { +LL | | C(PC), + | | - not covered +LL | | } + | |_- `P` defined here +... +LL | match proto { + | ^^^^^ pattern `C(QA)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/missing/missing-items/m2.stderr b/src/test/ui/missing/missing-items/m2.stderr index b2245750518b1..d2dac4ca6454a 100644 --- a/src/test/ui/missing/missing-items/m2.stderr +++ b/src/test/ui/missing/missing-items/m2.stderr @@ -1,7 +1,7 @@ error[E0046]: not all trait items implemented, missing: `CONSTANT`, `Type`, `method` --> $DIR/m2.rs:9:1 | -LL | impl m1::X for X { //~ ERROR not all trait items implemented +LL | impl m1::X for X { | ^^^^^^^^^^^^^^^^ missing `CONSTANT`, `Type`, `method` in implementation | = note: `CONSTANT` from trait: `const CONSTANT: u32;` diff --git a/src/test/ui/missing/missing-items/missing-type-parameter.stderr b/src/test/ui/missing/missing-items/missing-type-parameter.stderr index 619377198e1fc..dbb467d60f9ec 100644 --- a/src/test/ui/missing/missing-items/missing-type-parameter.stderr +++ b/src/test/ui/missing/missing-items/missing-type-parameter.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed --> $DIR/missing-type-parameter.rs:4:5 | -LL | foo(); //~ ERROR type annotations needed +LL | foo(); | ^^^ cannot infer type for `X` error: aborting due to previous error diff --git a/src/test/ui/missing/missing-semicolon-warning.stderr b/src/test/ui/missing/missing-semicolon-warning.stderr index 50627c3252dd6..b3f3ebc855daa 100644 --- a/src/test/ui/missing/missing-semicolon-warning.stderr +++ b/src/test/ui/missing/missing-semicolon-warning.stderr @@ -1,7 +1,7 @@ warning: expected `;`, found keyword `let` --> $DIR/missing-semicolon-warning.rs:6:12 | -LL | $( let x = $e1 )*; //~ WARN expected `;` +LL | $( let x = $e1 )*; | ^^^ ... LL | fn main() { m!(0, 0; 0, 0); } @@ -12,7 +12,7 @@ LL | fn main() { m!(0, 0; 0, 0); } warning: expected `;`, found `println` --> $DIR/missing-semicolon-warning.rs:7:12 | -LL | $( println!("{}", $e2) )*; //~ WARN expected `;` +LL | $( println!("{}", $e2) )*; | ^^^^^^^ ... LL | fn main() { m!(0, 0; 0, 0); } diff --git a/src/test/ui/missing/missing-stability.stderr b/src/test/ui/missing/missing-stability.stderr index 6c81f2bac5788..659f8c78cae6d 100644 --- a/src/test/ui/missing/missing-stability.stderr +++ b/src/test/ui/missing/missing-stability.stderr @@ -2,7 +2,7 @@ error: function has missing stability attribute --> $DIR/missing-stability.rs:8:1 | LL | / pub fn unmarked() { -LL | | //~^ ERROR function has missing stability attribute +LL | | LL | | () LL | | } | |_^ diff --git a/src/test/ui/missing_debug_impls.stderr b/src/test/ui/missing_debug_impls.stderr index cceab4b4c0bf8..bb8390a8f313c 100644 --- a/src/test/ui/missing_debug_impls.stderr +++ b/src/test/ui/missing_debug_impls.stderr @@ -1,7 +1,7 @@ error: type does not implement `fmt::Debug`; consider adding #[derive(Debug)] or a manual implementation --> $DIR/missing_debug_impls.rs:7:1 | -LL | pub enum A {} //~ ERROR type does not implement `fmt::Debug` +LL | pub enum A {} | ^^^^^^^^^^^^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(missing_debug_implementations)] error: type does not implement `fmt::Debug`; consider adding #[derive(Debug)] or a manual implementation --> $DIR/missing_debug_impls.rs:20:1 | -LL | pub struct Foo; //~ ERROR type does not implement `fmt::Debug` +LL | pub struct Foo; | ^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/mod-subitem-as-enum-variant.rs b/src/test/ui/mod-subitem-as-enum-variant.rs index ec809d44e942a..9328d1a9045e5 100644 --- a/src/test/ui/mod-subitem-as-enum-variant.rs +++ b/src/test/ui/mod-subitem-as-enum-variant.rs @@ -1,4 +1,3 @@ - mod Mod { pub struct FakeVariant(pub T); } @@ -6,5 +5,5 @@ mod Mod { fn main() { Mod::FakeVariant::(0); Mod::::FakeVariant(0); - //~^ ERROR type arguments are not allowed on this entity [E0109] + //~^ ERROR type arguments are not allowed for this type [E0109] } diff --git a/src/test/ui/mod-subitem-as-enum-variant.stderr b/src/test/ui/mod-subitem-as-enum-variant.stderr index d62bad81c3d8d..d6815c91e5e9e 100644 --- a/src/test/ui/mod-subitem-as-enum-variant.stderr +++ b/src/test/ui/mod-subitem-as-enum-variant.stderr @@ -1,5 +1,5 @@ -error[E0109]: type arguments are not allowed on this entity - --> $DIR/mod-subitem-as-enum-variant.rs:8:11 +error[E0109]: type arguments are not allowed for this type + --> $DIR/mod-subitem-as-enum-variant.rs:7:11 | LL | Mod::::FakeVariant(0); | ^^^ type argument not allowed diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/mod/mod_file_disambig.stderr index 1720ca420ca29..27df0241aa21f 100644 --- a/src/test/ui/mod/mod_file_disambig.stderr +++ b/src/test/ui/mod/mod_file_disambig.stderr @@ -1,11 +1,10 @@ error[E0584]: file for module `mod_file_disambig_aux` found at both mod_file_disambig_aux.rs and mod_file_disambig_aux/mod.rs --> $DIR/mod_file_disambig.rs:1:5 | -LL | mod mod_file_disambig_aux; //~ ERROR file for module `mod_file_disambig_aux` found at both +LL | mod mod_file_disambig_aux; | ^^^^^^^^^^^^^^^^^^^^^ | = help: delete or rename one of them to remove the ambiguity error: aborting due to previous error -For more information about this error, try `rustc --explain E0584`. diff --git a/src/test/ui/module-macro_use-arguments.stderr b/src/test/ui/module-macro_use-arguments.stderr index 4dc6df39a4797..2a75736a2c69f 100644 --- a/src/test/ui/module-macro_use-arguments.stderr +++ b/src/test/ui/module-macro_use-arguments.stderr @@ -1,7 +1,7 @@ error: arguments to macro_use are not allowed here --> $DIR/module-macro_use-arguments.rs:1:1 | -LL | #[macro_use(foo, bar)] //~ ERROR arguments to macro_use are not allowed here +LL | #[macro_use(foo, bar)] | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/moves/move-guard-same-consts.nll.stderr b/src/test/ui/moves/move-guard-same-consts.nll.stderr deleted file mode 100644 index 43f99cabcae94..0000000000000 --- a/src/test/ui/moves/move-guard-same-consts.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0382]: use of moved value: `x` - --> $DIR/move-guard-same-consts.rs:20:24 - | -LL | let x: Box<_> = box 1; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait -... -LL | (1, 2) if take(x) => (), - | - value moved here -LL | (1, 2) if take(x) => (), //~ ERROR use of moved value: `x` - | ^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-guard-same-consts.stderr b/src/test/ui/moves/move-guard-same-consts.stderr index 78a76a47b8a52..0945fbe68a0f2 100644 --- a/src/test/ui/moves/move-guard-same-consts.stderr +++ b/src/test/ui/moves/move-guard-same-consts.stderr @@ -1,12 +1,13 @@ error[E0382]: use of moved value: `x` --> $DIR/move-guard-same-consts.rs:20:24 | +LL | let x: Box<_> = box 1; + | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait +... LL | (1, 2) if take(x) => (), | - value moved here -LL | (1, 2) if take(x) => (), //~ ERROR use of moved value: `x` +LL | (1, 2) if take(x) => (), | ^ value used here after move - | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/moves/move-in-guard-1.nll.stderr b/src/test/ui/moves/move-in-guard-1.nll.stderr deleted file mode 100644 index 41abe6fa72a57..0000000000000 --- a/src/test/ui/moves/move-in-guard-1.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0382]: use of moved value: `x` - --> $DIR/move-in-guard-1.rs:10:24 - | -LL | let x: Box<_> = box 1; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait -... -LL | (1, _) if take(x) => (), - | - value moved here -LL | (_, 2) if take(x) => (), //~ ERROR use of moved value: `x` - | ^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-in-guard-1.stderr b/src/test/ui/moves/move-in-guard-1.stderr index d4cb538e05d1c..542fd1698637d 100644 --- a/src/test/ui/moves/move-in-guard-1.stderr +++ b/src/test/ui/moves/move-in-guard-1.stderr @@ -1,12 +1,13 @@ error[E0382]: use of moved value: `x` --> $DIR/move-in-guard-1.rs:10:24 | +LL | let x: Box<_> = box 1; + | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait +... LL | (1, _) if take(x) => (), | - value moved here -LL | (_, 2) if take(x) => (), //~ ERROR use of moved value: `x` +LL | (_, 2) if take(x) => (), | ^ value used here after move - | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/moves/move-in-guard-2.nll.stderr b/src/test/ui/moves/move-in-guard-2.nll.stderr deleted file mode 100644 index 0b14c1620d3cf..0000000000000 --- a/src/test/ui/moves/move-in-guard-2.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0382]: use of moved value: `x` - --> $DIR/move-in-guard-2.rs:10:24 - | -LL | let x: Box<_> = box 1; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait -... -LL | (_, 2) if take(x) => (), //~ ERROR use of moved value: `x` - | ^ value moved here, in previous iteration of loop - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-in-guard-2.stderr b/src/test/ui/moves/move-in-guard-2.stderr index d4e747c9f61d0..8bd405279c526 100644 --- a/src/test/ui/moves/move-in-guard-2.stderr +++ b/src/test/ui/moves/move-in-guard-2.stderr @@ -1,10 +1,11 @@ error[E0382]: use of moved value: `x` --> $DIR/move-in-guard-2.rs:10:24 | -LL | (_, 2) if take(x) => (), //~ ERROR use of moved value: `x` - | ^ value moved here in previous iteration of loop - | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait +LL | let x: Box<_> = box 1; + | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait +... +LL | (_, 2) if take(x) => (), + | ^ value moved here, in previous iteration of loop error: aborting due to previous error diff --git a/src/test/ui/moves/move-into-dead-array-1.nll.stderr b/src/test/ui/moves/move-into-dead-array-1.nll.stderr deleted file mode 100644 index e3a2a601246d4..0000000000000 --- a/src/test/ui/moves/move-into-dead-array-1.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0381]: use of possibly uninitialized variable: `a` - --> $DIR/move-into-dead-array-1.rs:14:5 - | -LL | a[i] = d(); //~ ERROR use of possibly uninitialized variable: `a` - | ^^^^ use of possibly uninitialized `a` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/moves/move-into-dead-array-1.stderr b/src/test/ui/moves/move-into-dead-array-1.stderr index 36f98a76b5473..33da0e54a1e4c 100644 --- a/src/test/ui/moves/move-into-dead-array-1.stderr +++ b/src/test/ui/moves/move-into-dead-array-1.stderr @@ -1,8 +1,8 @@ error[E0381]: use of possibly uninitialized variable: `a` --> $DIR/move-into-dead-array-1.rs:14:5 | -LL | a[i] = d(); //~ ERROR use of possibly uninitialized variable: `a` - | ^^^^^^^^^^ use of possibly uninitialized `a` +LL | a[i] = d(); + | ^^^^ use of possibly uninitialized `a` error: aborting due to previous error diff --git a/src/test/ui/moves/move-into-dead-array-2.nll.stderr b/src/test/ui/moves/move-into-dead-array-2.nll.stderr deleted file mode 100644 index 20bfdc2bbac72..0000000000000 --- a/src/test/ui/moves/move-into-dead-array-2.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: use of moved value: `a` - --> $DIR/move-into-dead-array-2.rs:14:5 - | -LL | fn foo(mut a: [D; 4], i: usize) { - | ----- move occurs because `a` has type `[D; 4]`, which does not implement the `Copy` trait -LL | drop(a); - | - value moved here -LL | a[i] = d(); //~ ERROR use of moved value: `a` - | ^^^^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-into-dead-array-2.stderr b/src/test/ui/moves/move-into-dead-array-2.stderr index 417b1ab205407..19e476c04ea07 100644 --- a/src/test/ui/moves/move-into-dead-array-2.stderr +++ b/src/test/ui/moves/move-into-dead-array-2.stderr @@ -1,12 +1,12 @@ error[E0382]: use of moved value: `a` --> $DIR/move-into-dead-array-2.rs:14:5 | +LL | fn foo(mut a: [D; 4], i: usize) { + | ----- move occurs because `a` has type `[D; 4]`, which does not implement the `Copy` trait LL | drop(a); | - value moved here -LL | a[i] = d(); //~ ERROR use of moved value: `a` - | ^^^^^^^^^^ value used here after move - | - = note: move occurs because `a` has type `[D; 4]`, which does not implement the `Copy` trait +LL | a[i] = d(); + | ^^^^ value used here after move error: aborting due to previous error diff --git a/src/test/ui/moves/move-out-of-array-1.stderr b/src/test/ui/moves/move-out-of-array-1.stderr index 677f0b42f5a27..0af083e5b5233 100644 --- a/src/test/ui/moves/move-out-of-array-1.stderr +++ b/src/test/ui/moves/move-out-of-array-1.stderr @@ -1,8 +1,11 @@ error[E0508]: cannot move out of type `[D; 4]`, a non-copy array --> $DIR/move-out-of-array-1.rs:17:5 | -LL | a[i] //~ ERROR cannot move out of type `[D; 4]`, a non-copy array - | ^^^^ cannot move out of here +LL | a[i] + | ^^^^ + | | + | cannot move out of here + | move occurs because `a[_]` has type `D`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/moves/move-out-of-slice-1.nll.stderr b/src/test/ui/moves/move-out-of-slice-1.nll.stderr deleted file mode 100644 index c8c09b31d36b8..0000000000000 --- a/src/test/ui/moves/move-out-of-slice-1.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0508]: cannot move out of type `[A]`, a non-copy slice - --> $DIR/move-out-of-slice-1.rs:7:11 - | -LL | match a { - | ^ cannot move out of here -LL | box [a] => {}, //~ ERROR cannot move out of type `[A]`, a non-copy slice - | - data moved here - | -note: move occurs because `a` has type `A`, which does not implement the `Copy` trait - --> $DIR/move-out-of-slice-1.rs:8:14 - | -LL | box [a] => {}, //~ ERROR cannot move out of type `[A]`, a non-copy slice - | ^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/moves/move-out-of-slice-1.rs b/src/test/ui/moves/move-out-of-slice-1.rs index 3e0906060e601..982648f5b237c 100644 --- a/src/test/ui/moves/move-out-of-slice-1.rs +++ b/src/test/ui/moves/move-out-of-slice-1.rs @@ -4,8 +4,8 @@ struct A; fn main() { let a: Box<[A]> = Box::new([A]); - match a { - box [a] => {}, //~ ERROR cannot move out of type `[A]`, a non-copy slice + match a { //~ ERROR cannot move out of type `[A]`, a non-copy slice + box [a] => {}, _ => {} } } diff --git a/src/test/ui/moves/move-out-of-slice-1.stderr b/src/test/ui/moves/move-out-of-slice-1.stderr index bfdf641986908..ce5ddb3e183b1 100644 --- a/src/test/ui/moves/move-out-of-slice-1.stderr +++ b/src/test/ui/moves/move-out-of-slice-1.stderr @@ -1,11 +1,13 @@ error[E0508]: cannot move out of type `[A]`, a non-copy slice - --> $DIR/move-out-of-slice-1.rs:8:13 + --> $DIR/move-out-of-slice-1.rs:7:11 | -LL | box [a] => {}, //~ ERROR cannot move out of type `[A]`, a non-copy slice - | ^-^ - | || - | |hint: to prevent move, use `ref a` or `ref mut a` - | cannot move out of here +LL | match a { + | ^ cannot move out of here +LL | box [a] => {}, + | - + | | + | data moved here + | move occurs because `a` has type `A`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/moves/move-out-of-tuple-field.nll.stderr b/src/test/ui/moves/move-out-of-tuple-field.nll.stderr deleted file mode 100644 index 2efdc84ca37d1..0000000000000 --- a/src/test/ui/moves/move-out-of-tuple-field.nll.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0382]: use of moved value: `x.0` - --> $DIR/move-out-of-tuple-field.rs:8:13 - | -LL | let y = x.0; - | --- value moved here -LL | let z = x.0; //~ ERROR use of moved value: `x.0` - | ^^^ value used here after move - | - = note: move occurs because `x.0` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `x.0` - --> $DIR/move-out-of-tuple-field.rs:12:13 - | -LL | let y = x.0; - | --- value moved here -LL | let z = x.0; //~ ERROR use of moved value: `x.0` - | ^^^ value used here after move - | - = note: move occurs because `x.0` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-out-of-tuple-field.stderr b/src/test/ui/moves/move-out-of-tuple-field.stderr index 6839c49c82963..888ef3352e26d 100644 --- a/src/test/ui/moves/move-out-of-tuple-field.stderr +++ b/src/test/ui/moves/move-out-of-tuple-field.stderr @@ -1,20 +1,20 @@ error[E0382]: use of moved value: `x.0` - --> $DIR/move-out-of-tuple-field.rs:8:9 + --> $DIR/move-out-of-tuple-field.rs:8:13 | LL | let y = x.0; - | - value moved here -LL | let z = x.0; //~ ERROR use of moved value: `x.0` - | ^ value used here after move + | --- value moved here +LL | let z = x.0; + | ^^^ value used here after move | = note: move occurs because `x.0` has type `std::boxed::Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x.0` - --> $DIR/move-out-of-tuple-field.rs:12:9 + --> $DIR/move-out-of-tuple-field.rs:12:13 | LL | let y = x.0; - | - value moved here -LL | let z = x.0; //~ ERROR use of moved value: `x.0` - | ^ value used here after move + | --- value moved here +LL | let z = x.0; + | ^^^ value used here after move | = note: move occurs because `x.0` has type `std::boxed::Box`, which does not implement the `Copy` trait diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.nll.stderr b/src/test/ui/moves/moves-based-on-type-access-to-field.nll.stderr deleted file mode 100644 index 6ad9a2d414c77..0000000000000 --- a/src/test/ui/moves/moves-based-on-type-access-to-field.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-access-to-field.rs:11:12 - | -LL | let x = vec!["hi".to_string()]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait -LL | consume(x.into_iter().next().unwrap()); - | - value moved here -LL | touch(&x[0]); //~ ERROR use of moved value: `x` - | ^ value borrowed here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.rs b/src/test/ui/moves/moves-based-on-type-access-to-field.rs index c7ea357a5d9a0..e2003ed6e4716 100644 --- a/src/test/ui/moves/moves-based-on-type-access-to-field.rs +++ b/src/test/ui/moves/moves-based-on-type-access-to-field.rs @@ -8,7 +8,7 @@ fn touch(_a: &A) {} fn f20() { let x = vec!["hi".to_string()]; consume(x.into_iter().next().unwrap()); - touch(&x[0]); //~ ERROR use of moved value: `x` + touch(&x[0]); //~ ERROR borrow of moved value: `x` } fn main() {} diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr index 882c1fe1706d2..71a3c4506eaf2 100644 --- a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr +++ b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `x` +error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-access-to-field.rs:11:12 | +LL | let x = vec!["hi".to_string()]; + | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait LL | consume(x.into_iter().next().unwrap()); | - value moved here -LL | touch(&x[0]); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait +LL | touch(&x[0]); + | ^ value borrowed here after move error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-block-bad.nll.stderr b/src/test/ui/moves/moves-based-on-type-block-bad.nll.stderr deleted file mode 100644 index 6950a56a5335a..0000000000000 --- a/src/test/ui/moves/moves-based-on-type-block-bad.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/moves-based-on-type-block-bad.rs:24:19 - | -LL | match hellothere.x { //~ ERROR cannot move out - | ^^^^^^^^^^^^ - | | - | cannot move out of borrowed content - | help: consider borrowing here: `&hellothere.x` -... -LL | box E::Bar(x) => println!("{}", x.to_string()), - | - data moved here - | -note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait - --> $DIR/moves-based-on-type-block-bad.rs:27:28 - | -LL | box E::Bar(x) => println!("{}", x.to_string()), - | ^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/moves/moves-based-on-type-block-bad.rs b/src/test/ui/moves/moves-based-on-type-block-bad.rs index 99928caa926a4..085e249c0fb07 100644 --- a/src/test/ui/moves/moves-based-on-type-block-bad.rs +++ b/src/test/ui/moves/moves-based-on-type-block-bad.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - #![feature(box_patterns)] #![feature(box_syntax)] @@ -22,7 +20,6 @@ fn main() { loop { f(&s, |hellothere| { match hellothere.x { //~ ERROR cannot move out - //~| cannot move out of borrowed content box E::Foo(_) => {} box E::Bar(x) => println!("{}", x.to_string()), box E::Baz => {} diff --git a/src/test/ui/moves/moves-based-on-type-block-bad.stderr b/src/test/ui/moves/moves-based-on-type-block-bad.stderr index 4ecaed3b69b54..12b87c54b9c73 100644 --- a/src/test/ui/moves/moves-based-on-type-block-bad.stderr +++ b/src/test/ui/moves/moves-based-on-type-block-bad.stderr @@ -1,11 +1,14 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/moves-based-on-type-block-bad.rs:24:19 +error[E0507]: cannot move out of `hellothere.x.0` which is behind a shared reference + --> $DIR/moves-based-on-type-block-bad.rs:22:19 | -LL | match hellothere.x { //~ ERROR cannot move out - | ^^^^^^^^^^ cannot move out of borrowed content -... +LL | match hellothere.x { + | ^^^^^^^^^^^^ help: consider borrowing here: `&hellothere.x` +LL | box E::Foo(_) => {} LL | box E::Bar(x) => println!("{}", x.to_string()), - | - hint: to prevent move, use `ref x` or `ref mut x` + | - + | | + | data moved here + | move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.nll.stderr b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.nll.stderr deleted file mode 100644 index bed0ae7275cc5..0000000000000 --- a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-capture-clause-bad.rs:8:20 - | -LL | let x = "Hello world!".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait -LL | thread::spawn(move|| { - | ------ value moved into closure here -LL | println!("{}", x); - | - variable moved due to use in closure -LL | }); -LL | println!("{}", x); //~ ERROR use of moved value - | ^ value borrowed here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.rs b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.rs index d5f44a0b3f75d..b2f68352f896c 100644 --- a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.rs +++ b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.rs @@ -5,5 +5,5 @@ fn main() { thread::spawn(move|| { println!("{}", x); }); - println!("{}", x); //~ ERROR use of moved value + println!("{}", x); //~ ERROR borrow of moved value } diff --git a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr index 88e58fdf58bcd..3a05a1305beed 100644 --- a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr +++ b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr @@ -1,13 +1,15 @@ -error[E0382]: use of moved value: `x` +error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-capture-clause-bad.rs:8:20 | +LL | let x = "Hello world!".to_string(); + | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait LL | thread::spawn(move|| { - | ------ value moved (into closure) here -... -LL | println!("{}", x); //~ ERROR use of moved value - | ^ value used here after move - | - = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | ------ value moved into closure here +LL | println!("{}", x); + | - variable moved due to use in closure +LL | }); +LL | println!("{}", x); + | ^ value borrowed here after move error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.nll.stderr b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.nll.stderr deleted file mode 100644 index 5f0d2b42671de..0000000000000 --- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0382]: use of moved value: `node` - --> $DIR/moves-based-on-type-cyclic-types-issue-4821.rs:13:13 - | -LL | Some(right) => consume(right), - | ----- value moved here -... -LL | consume(node) + r //~ ERROR use of partially moved value: `node` - | ^^^^ value used here after partial move - | - = note: move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs index 4417fb926d96d..b070671cb250e 100644 --- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs +++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs @@ -10,7 +10,7 @@ fn foo(node: Box) -> isize { Some(right) => consume(right), None => 0 }; - consume(node) + r //~ ERROR use of partially moved value: `node` + consume(node) + r //~ ERROR use of moved value: `node` } fn consume(v: Box) -> isize { diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr index 7624ba5fe28d9..fb8562d00ead1 100644 --- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr +++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr @@ -1,13 +1,13 @@ -error[E0382]: use of partially moved value: `node` +error[E0382]: use of moved value: `node` --> $DIR/moves-based-on-type-cyclic-types-issue-4821.rs:13:13 | LL | Some(right) => consume(right), | ----- value moved here ... -LL | consume(node) + r //~ ERROR use of partially moved value: `node` - | ^^^^ value used here after move +LL | consume(node) + r + | ^^^^ value used here after partial move | - = note: move occurs because the value has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.nll.stderr b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.nll.stderr deleted file mode 100644 index 07f40274f9e31..0000000000000 --- a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.nll.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:11:11 - | -LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait -LL | let _y = Foo { f:x }; - | - value moved here -LL | //~^ NOTE value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^^ value borrowed here after move - -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:20:11 - | -LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait -LL | let _y = Foo { f:(((x))) }; - | ------- value moved here -LL | //~^ NOTE value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^^ value borrowed here after move - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs index 7c7ca0044e29c..0b44ca56ced47 100644 --- a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs +++ b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs @@ -6,20 +6,20 @@ fn touch(_a: &A) {} fn f00() { let x = "hi".to_string(); + //~^ NOTE move occurs because `x` has type `std::string::String` let _y = Foo { f:x }; //~^ NOTE value moved here - touch(&x); //~ ERROR use of moved value: `x` - //~^ NOTE value used here after move - //~| NOTE move occurs because `x` has type `std::string::String` + touch(&x); //~ ERROR borrow of moved value: `x` + //~^ NOTE value borrowed here after move } fn f05() { let x = "hi".to_string(); + //~^ NOTE move occurs because `x` has type `std::string::String` let _y = Foo { f:(((x))) }; //~^ NOTE value moved here - touch(&x); //~ ERROR use of moved value: `x` - //~^ NOTE value used here after move - //~| NOTE move occurs because `x` has type `std::string::String` + touch(&x); //~ ERROR borrow of moved value: `x` + //~^ NOTE value borrowed here after move } fn f10() { diff --git a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr index 374ac61e7f5e9..d7a7ceabf8505 100644 --- a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr +++ b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr @@ -1,24 +1,26 @@ -error[E0382]: use of moved value: `x` - --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:11:12 +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:12:11 | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +LL | LL | let _y = Foo { f:x }; | - value moved here -LL | //~^ NOTE value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +LL | +LL | touch(&x); + | ^^ value borrowed here after move -error[E0382]: use of moved value: `x` - --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:20:12 +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:21:11 | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +LL | LL | let _y = Foo { f:(((x))) }; | ------- value moved here -LL | //~^ NOTE value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +LL | +LL | touch(&x); + | ^^ value borrowed here after move error: aborting due to 2 previous errors diff --git a/src/test/ui/moves/moves-based-on-type-exprs.nll.stderr b/src/test/ui/moves/moves-based-on-type-exprs.nll.stderr deleted file mode 100644 index 162aec45f5f57..0000000000000 --- a/src/test/ui/moves/moves-based-on-type-exprs.nll.stderr +++ /dev/null @@ -1,123 +0,0 @@ -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:12:11 - | -LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait -LL | let _y = Foo { f:x }; - | - value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^^ value borrowed here after move - -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:18:11 - | -LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait -LL | let _y = (x, 3); - | - value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^^ value borrowed here after move - -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:35:11 - | -LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait -... -LL | x - | - value moved here -... -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^^ value borrowed here after move - -error[E0382]: borrow of moved value: `y` - --> $DIR/moves-based-on-type-exprs.rs:36:11 - | -LL | let y = "ho".to_string(); - | - move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait -... -LL | y - | - value moved here -... -LL | touch(&y); //~ ERROR use of moved value: `y` - | ^^ value borrowed here after move - -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:46:11 - | -LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait -... -LL | true => x, - | - value moved here -... -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^^ value borrowed here after move - -error[E0382]: borrow of moved value: `y` - --> $DIR/moves-based-on-type-exprs.rs:47:11 - | -LL | let y = "ho".to_string(); - | - move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait -... -LL | false => y - | - value moved here -... -LL | touch(&y); //~ ERROR use of moved value: `y` - | ^^ value borrowed here after move - -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:58:11 - | -LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait -... -LL | _ if guard(x) => 10, - | - value moved here -... -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^^ value borrowed here after move - -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:65:11 - | -LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait -LL | let _y = [x]; - | - value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^^ value borrowed here after move - -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:71:11 - | -LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait -LL | let _y = vec![x]; - | - value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^^ value borrowed here after move - -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:77:11 - | -LL | let x = vec!["hi".to_string()]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait -LL | let _y = x.into_iter().next().unwrap(); - | - value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^^ value borrowed here after move - -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:83:11 - | -LL | let x = vec!["hi".to_string()]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait -LL | let _y = [x.into_iter().next().unwrap(); 1]; - | - value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^^ value borrowed here after move - -error: aborting due to 11 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-exprs.rs b/src/test/ui/moves/moves-based-on-type-exprs.rs index b058f83291b10..4a52d8d32064f 100644 --- a/src/test/ui/moves/moves-based-on-type-exprs.rs +++ b/src/test/ui/moves/moves-based-on-type-exprs.rs @@ -9,13 +9,13 @@ fn touch(_a: &A) {} fn f10() { let x = "hi".to_string(); let _y = Foo { f:x }; - touch(&x); //~ ERROR use of moved value: `x` + touch(&x); //~ ERROR borrow of moved value: `x` } fn f20() { let x = "hi".to_string(); let _y = (x, 3); - touch(&x); //~ ERROR use of moved value: `x` + touch(&x); //~ ERROR borrow of moved value: `x` } fn f21() { @@ -32,8 +32,8 @@ fn f30(cond: bool) { } else { y }; - touch(&x); //~ ERROR use of moved value: `x` - touch(&y); //~ ERROR use of moved value: `y` + touch(&x); //~ ERROR borrow of moved value: `x` + touch(&y); //~ ERROR borrow of moved value: `y` } fn f40(cond: bool) { @@ -43,8 +43,8 @@ fn f40(cond: bool) { true => x, false => y }; - touch(&x); //~ ERROR use of moved value: `x` - touch(&y); //~ ERROR use of moved value: `y` + touch(&x); //~ ERROR borrow of moved value: `x` + touch(&y); //~ ERROR borrow of moved value: `y` } fn f50(cond: bool) { @@ -55,32 +55,32 @@ fn f50(cond: bool) { true => 10, false => 20, }; - touch(&x); //~ ERROR use of moved value: `x` + touch(&x); //~ ERROR borrow of moved value: `x` touch(&y); } fn f70() { let x = "hi".to_string(); let _y = [x]; - touch(&x); //~ ERROR use of moved value: `x` + touch(&x); //~ ERROR borrow of moved value: `x` } fn f80() { let x = "hi".to_string(); let _y = vec![x]; - touch(&x); //~ ERROR use of moved value: `x` + touch(&x); //~ ERROR borrow of moved value: `x` } fn f100() { let x = vec!["hi".to_string()]; let _y = x.into_iter().next().unwrap(); - touch(&x); //~ ERROR use of moved value: `x` + touch(&x); //~ ERROR borrow of moved value: `x` } fn f110() { let x = vec!["hi".to_string()]; let _y = [x.into_iter().next().unwrap(); 1]; - touch(&x); //~ ERROR use of moved value: `x` + touch(&x); //~ ERROR borrow of moved value: `x` } fn f120() { diff --git a/src/test/ui/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr index e6177c6b6c836..67fae606c4e43 100644 --- a/src/test/ui/moves/moves-based-on-type-exprs.stderr +++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr @@ -1,117 +1,122 @@ -error[E0382]: use of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:12:12 +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:12:11 | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait LL | let _y = Foo { f:x }; | - value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +LL | touch(&x); + | ^^ value borrowed here after move -error[E0382]: use of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:18:12 +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:18:11 | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait LL | let _y = (x, 3); | - value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +LL | touch(&x); + | ^^ value borrowed here after move -error[E0382]: use of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:35:12 +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:35:11 | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +... LL | x | - value moved here ... -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +LL | touch(&x); + | ^^ value borrowed here after move -error[E0382]: use of moved value: `y` - --> $DIR/moves-based-on-type-exprs.rs:36:12 +error[E0382]: borrow of moved value: `y` + --> $DIR/moves-based-on-type-exprs.rs:36:11 | +LL | let y = "ho".to_string(); + | - move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait +... LL | y | - value moved here ... -LL | touch(&y); //~ ERROR use of moved value: `y` - | ^ value used here after move - | - = note: move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait +LL | touch(&y); + | ^^ value borrowed here after move -error[E0382]: use of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:46:12 +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:46:11 | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +... LL | true => x, | - value moved here ... -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +LL | touch(&x); + | ^^ value borrowed here after move -error[E0382]: use of moved value: `y` - --> $DIR/moves-based-on-type-exprs.rs:47:12 +error[E0382]: borrow of moved value: `y` + --> $DIR/moves-based-on-type-exprs.rs:47:11 | +LL | let y = "ho".to_string(); + | - move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait +... LL | false => y | - value moved here ... -LL | touch(&y); //~ ERROR use of moved value: `y` - | ^ value used here after move - | - = note: move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait +LL | touch(&y); + | ^^ value borrowed here after move -error[E0382]: use of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:58:12 +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:58:11 | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +... LL | _ if guard(x) => 10, | - value moved here ... -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +LL | touch(&x); + | ^^ value borrowed here after move -error[E0382]: use of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:65:12 +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:65:11 | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait LL | let _y = [x]; | - value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +LL | touch(&x); + | ^^ value borrowed here after move -error[E0382]: use of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:71:12 +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:71:11 | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait LL | let _y = vec![x]; | - value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait +LL | touch(&x); + | ^^ value borrowed here after move -error[E0382]: use of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:77:12 +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:77:11 | +LL | let x = vec!["hi".to_string()]; + | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait LL | let _y = x.into_iter().next().unwrap(); | - value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait +LL | touch(&x); + | ^^ value borrowed here after move -error[E0382]: use of moved value: `x` - --> $DIR/moves-based-on-type-exprs.rs:83:12 +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:83:11 | +LL | let x = vec!["hi".to_string()]; + | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait LL | let _y = [x.into_iter().next().unwrap(); 1]; | - value moved here -LL | touch(&x); //~ ERROR use of moved value: `x` - | ^ value used here after move - | - = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait +LL | touch(&x); + | ^^ value borrowed here after move error: aborting due to 11 previous errors diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.nll.stderr b/src/test/ui/moves/moves-based-on-type-match-bindings.nll.stderr deleted file mode 100644 index 6d523fc09c08b..0000000000000 --- a/src/test/ui/moves/moves-based-on-type-match-bindings.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0382]: borrow of moved value: `x` - --> $DIR/moves-based-on-type-match-bindings.rs:16:11 - | -LL | Foo {f} => {} - | - value moved here -... -LL | touch(&x); //~ ERROR use of partially moved value: `x` - | ^^ value borrowed here after partial move - | - = note: move occurs because `x.f` has type `std::string::String`, which does not implement the `Copy` trait - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.rs b/src/test/ui/moves/moves-based-on-type-match-bindings.rs index 59e5a8f684e9a..1290d4a25abc4 100644 --- a/src/test/ui/moves/moves-based-on-type-match-bindings.rs +++ b/src/test/ui/moves/moves-based-on-type-match-bindings.rs @@ -13,8 +13,8 @@ fn f10() { Foo {f} => {} }; - touch(&x); //~ ERROR use of partially moved value: `x` - //~^ value used here after move + touch(&x); //~ ERROR borrow of moved value: `x` + //~^ value borrowed here after partial move //~| move occurs because `x.f` has type `std::string::String` } diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr index 41ced9dfd935b..322999a1f0ff9 100644 --- a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr +++ b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr @@ -1,11 +1,11 @@ -error[E0382]: use of partially moved value: `x` - --> $DIR/moves-based-on-type-match-bindings.rs:16:12 +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-match-bindings.rs:16:11 | LL | Foo {f} => {} | - value moved here ... -LL | touch(&x); //~ ERROR use of partially moved value: `x` - | ^ value used here after move +LL | touch(&x); + | ^^ value borrowed here after partial move | = note: move occurs because `x.f` has type `std::string::String`, which does not implement the `Copy` trait diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.nll.stderr b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.nll.stderr deleted file mode 100644 index 7d410f6cabc83..0000000000000 --- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:11:28 - | -LL | let i = box 3; - | - captured outer variable -LL | let _f = to_fn(|| test(i)); //~ ERROR cannot move out - | ^ cannot move out of captured variable in an `Fn` closure - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr index 49113a57d2fa5..fafd377c12b9d 100644 --- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr +++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr @@ -1,10 +1,10 @@ -error[E0507]: cannot move out of captured outer variable in an `Fn` closure +error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure --> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:11:28 | LL | let i = box 3; | - captured outer variable -LL | let _f = to_fn(|| test(i)); //~ ERROR cannot move out - | ^ cannot move out of captured outer variable in an `Fn` closure +LL | let _f = to_fn(|| test(i)); + | ^ move occurs because `i` has type `std::boxed::Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.nll.stderr b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.nll.stderr deleted file mode 100644 index 391dd67dbf60a..0000000000000 --- a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.nll.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0499]: cannot borrow `*f` as mutable more than once at a time - --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:20:27 - | -LL | (f.c)(f, true); - | ----- ^ second mutable borrow occurs here - | | - | first mutable borrow occurs here - | first borrow later used by call - -error[E0382]: borrow of moved value: `f` - --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:32:5 - | -LL | fn conspirator(mut f: F) where F: FnMut(&mut R, bool) { - | - ----- move occurs because `f` has type `F`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | let mut r = R {c: Box::new(f)}; - | - value moved here -LL | f(&mut r, false) //~ ERROR use of moved value - | ^ value borrowed here after move - -error: aborting due to 2 previous errors - -Some errors occurred: E0382, E0499. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.rs b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.rs index 737a131c9bf6a..0385a120ce213 100644 --- a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.rs +++ b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.rs @@ -6,7 +6,7 @@ struct R<'a> { // This struct is needed to create the // otherwise infinite type of a fn that // accepts itself as argument: - c: Box + c: Box } fn innocent_looking_victim() { @@ -29,7 +29,7 @@ fn innocent_looking_victim() { fn conspirator(mut f: F) where F: FnMut(&mut R, bool) { let mut r = R {c: Box::new(f)}; - f(&mut r, false) //~ ERROR use of moved value + f(&mut r, false) //~ ERROR borrow of moved value } fn main() { innocent_looking_victim() } diff --git a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr index 05ced7f0107ae..483c364752b7b 100644 --- a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr +++ b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr @@ -2,22 +2,24 @@ error[E0499]: cannot borrow `*f` as mutable more than once at a time --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:20:27 | LL | (f.c)(f, true); - | ----- ^ - first borrow ends here - | | | - | | second mutable borrow occurs here + | ----- ^ second mutable borrow occurs here + | | | first mutable borrow occurs here + | first borrow later used by call -error[E0382]: use of moved value: `f` +error[E0382]: borrow of moved value: `f` --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:32:5 | +LL | fn conspirator(mut f: F) where F: FnMut(&mut R, bool) { + | - ----- move occurs because `f` has type `F`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | let mut r = R {c: Box::new(f)}; | - value moved here -LL | f(&mut r, false) //~ ERROR use of moved value - | ^ value used here after move - | - = note: move occurs because `f` has type `F`, which does not implement the `Copy` trait +LL | f(&mut r, false) + | ^ value borrowed here after move error: aborting due to 2 previous errors -Some errors occurred: E0382, E0499. +Some errors have detailed explanations: E0382, E0499. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-tuple.rs b/src/test/ui/moves/moves-based-on-type-tuple.rs index d99fe51931a1f..828d90cd7ac7f 100644 --- a/src/test/ui/moves/moves-based-on-type-tuple.rs +++ b/src/test/ui/moves/moves-based-on-type-tuple.rs @@ -1,11 +1,8 @@ #![feature(box_syntax)] -// compile-flags: -Z borrowck=compare - fn dup(x: Box) -> Box<(Box,Box)> { box (x, x) - //~^ use of moved value: `x` (Ast) [E0382] - //~| use of moved value: `x` (Mir) [E0382] + //~^ use of moved value: `x` [E0382] } fn main() { diff --git a/src/test/ui/moves/moves-based-on-type-tuple.stderr b/src/test/ui/moves/moves-based-on-type-tuple.stderr index c49dbdab40210..2e1ddbdf57f98 100644 --- a/src/test/ui/moves/moves-based-on-type-tuple.stderr +++ b/src/test/ui/moves/moves-based-on-type-tuple.stderr @@ -1,15 +1,5 @@ -error[E0382]: use of moved value: `x` (Ast) - --> $DIR/moves-based-on-type-tuple.rs:6:13 - | -LL | box (x, x) - | - ^ value used here after move - | | - | value moved here - | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `x` (Mir) - --> $DIR/moves-based-on-type-tuple.rs:6:13 +error[E0382]: use of moved value: `x` + --> $DIR/moves-based-on-type-tuple.rs:4:13 | LL | fn dup(x: Box) -> Box<(Box,Box)> { | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait @@ -18,6 +8,6 @@ LL | box (x, x) | | | value moved here -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-sru-moved-field.nll.stderr b/src/test/ui/moves/moves-sru-moved-field.nll.stderr deleted file mode 100644 index e5daab36f6ee7..0000000000000 --- a/src/test/ui/moves/moves-sru-moved-field.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: use of moved value: `f.moved` - --> $DIR/moves-sru-moved-field.rs:20:14 - | -LL | let _b = Foo {noncopyable: g, ..f}; - | ------------------------- value moved here -LL | let _c = Foo {noncopyable: h, ..f}; //~ ERROR use of moved value: `f.moved` - | ^^^^^^^^^^^^^^^^^^^^^^^^^ value used here after move - | - = note: move occurs because `f.moved` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-sru-moved-field.stderr b/src/test/ui/moves/moves-sru-moved-field.stderr index 3d38faa20a1e4..a012c2d9b7b74 100644 --- a/src/test/ui/moves/moves-sru-moved-field.stderr +++ b/src/test/ui/moves/moves-sru-moved-field.stderr @@ -1,10 +1,10 @@ error[E0382]: use of moved value: `f.moved` - --> $DIR/moves-sru-moved-field.rs:20:37 + --> $DIR/moves-sru-moved-field.rs:20:14 | LL | let _b = Foo {noncopyable: g, ..f}; - | - value moved here -LL | let _c = Foo {noncopyable: h, ..f}; //~ ERROR use of moved value: `f.moved` - | ^ value used here after move + | ------------------------- value moved here +LL | let _c = Foo {noncopyable: h, ..f}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ value used here after move | = note: move occurs because `f.moved` has type `std::boxed::Box`, which does not implement the `Copy` trait diff --git a/src/test/ui/multiple-main-2.stderr b/src/test/ui/multiple-main-2.stderr index c761e74bb8723..ae33e01cd26eb 100644 --- a/src/test/ui/multiple-main-2.stderr +++ b/src/test/ui/multiple-main-2.stderr @@ -5,7 +5,7 @@ LL | / fn bar() { LL | | } | |_- first #[main] function ... -LL | / fn foo() { //~ ERROR multiple functions with a #[main] attribute +LL | / fn foo() { LL | | } | |_^ additional #[main] function diff --git a/src/test/ui/multiple-main-3.stderr b/src/test/ui/multiple-main-3.stderr index 2574f0ef6d81c..b85637b8a56e2 100644 --- a/src/test/ui/multiple-main-3.stderr +++ b/src/test/ui/multiple-main-3.stderr @@ -5,7 +5,7 @@ LL | / fn main1() { LL | | } | |_- first #[main] function ... -LL | / fn main2() { //~ ERROR multiple functions with a #[main] attribute +LL | / fn main2() { LL | | } | |_____^ additional #[main] function diff --git a/src/test/ui/mut/mut-cant-alias.nll.stderr b/src/test/ui/mut/mut-cant-alias.nll.stderr deleted file mode 100644 index 2d7104b39c4b2..0000000000000 --- a/src/test/ui/mut/mut-cant-alias.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0499]: cannot borrow `b` as mutable more than once at a time - --> $DIR/mut-cant-alias.rs:9:20 - | -LL | let b1 = &mut *b; - | - first mutable borrow occurs here -LL | let b2 = &mut *b; //~ ERROR cannot borrow - | ^ second mutable borrow occurs here -LL | b1.use_mut(); - | -- first borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/mut/mut-cant-alias.stderr b/src/test/ui/mut/mut-cant-alias.stderr index ce942677bed61..d56e45db13d0e 100644 --- a/src/test/ui/mut/mut-cant-alias.stderr +++ b/src/test/ui/mut/mut-cant-alias.stderr @@ -3,11 +3,10 @@ error[E0499]: cannot borrow `b` as mutable more than once at a time | LL | let b1 = &mut *b; | - first mutable borrow occurs here -LL | let b2 = &mut *b; //~ ERROR cannot borrow +LL | let b2 = &mut *b; | ^ second mutable borrow occurs here LL | b1.use_mut(); -LL | } - | - first borrow ends here + | -- first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/mut/mut-cross-borrowing.stderr b/src/test/ui/mut/mut-cross-borrowing.stderr index 8708a135360b7..e2eea195dafb8 100644 --- a/src/test/ui/mut/mut-cross-borrowing.stderr +++ b/src/test/ui/mut/mut-cross-borrowing.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/mut-cross-borrowing.rs:7:7 | -LL | f(x) //~ ERROR mismatched types +LL | f(x) | ^ | | | expected &mut isize, found struct `std::boxed::Box` diff --git a/src/test/ui/mut/mut-pattern-internal-mutability.ast.nll.stderr b/src/test/ui/mut/mut-pattern-internal-mutability.ast.nll.stderr deleted file mode 100644 index 82a4628a0e6b7..0000000000000 --- a/src/test/ui/mut/mut-pattern-internal-mutability.ast.nll.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/mut-pattern-internal-mutability.rs:8:5 - | -LL | let &mut x = foo; - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^^ cannot assign twice to immutable variable - -error[E0506]: cannot assign to `*foo` because it is borrowed - --> $DIR/mut-pattern-internal-mutability.rs:17:5 - | -LL | let &mut ref x = foo; - | ----- borrow of `*foo` occurs here -LL | *foo += 1; //[ast]~ ERROR cannot assign to `*foo` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `*foo` occurs here -LL | //[mir]~^ ERROR cannot assign to `*foo` because it is borrowed -LL | drop(x); - | - borrow later used here - -error: aborting due to 2 previous errors - -Some errors occurred: E0384, E0506. -For more information about an error, try `rustc --explain E0384`. diff --git a/src/test/ui/mut/mut-pattern-internal-mutability.ast.stderr b/src/test/ui/mut/mut-pattern-internal-mutability.ast.stderr deleted file mode 100644 index e3423d5388e43..0000000000000 --- a/src/test/ui/mut/mut-pattern-internal-mutability.ast.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/mut-pattern-internal-mutability.rs:8:5 - | -LL | let &mut x = foo; - | - first assignment to `x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^^ cannot assign twice to immutable variable - -error[E0506]: cannot assign to `*foo` because it is borrowed - --> $DIR/mut-pattern-internal-mutability.rs:17:5 - | -LL | let &mut ref x = foo; - | ----- borrow of `*foo` occurs here -LL | *foo += 1; //[ast]~ ERROR cannot assign to `*foo` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `*foo` occurs here - -error: aborting due to 2 previous errors - -Some errors occurred: E0384, E0506. -For more information about an error, try `rustc --explain E0384`. diff --git a/src/test/ui/mut/mut-pattern-internal-mutability.mir.stderr b/src/test/ui/mut/mut-pattern-internal-mutability.mir.stderr deleted file mode 100644 index 82a4628a0e6b7..0000000000000 --- a/src/test/ui/mut/mut-pattern-internal-mutability.mir.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/mut-pattern-internal-mutability.rs:8:5 - | -LL | let &mut x = foo; - | - - | | - | first assignment to `x` - | help: make this binding mutable: `mut x` -LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable - | ^^^^^^ cannot assign twice to immutable variable - -error[E0506]: cannot assign to `*foo` because it is borrowed - --> $DIR/mut-pattern-internal-mutability.rs:17:5 - | -LL | let &mut ref x = foo; - | ----- borrow of `*foo` occurs here -LL | *foo += 1; //[ast]~ ERROR cannot assign to `*foo` because it is borrowed - | ^^^^^^^^^ assignment to borrowed `*foo` occurs here -LL | //[mir]~^ ERROR cannot assign to `*foo` because it is borrowed -LL | drop(x); - | - borrow later used here - -error: aborting due to 2 previous errors - -Some errors occurred: E0384, E0506. -For more information about an error, try `rustc --explain E0384`. diff --git a/src/test/ui/mut/mut-pattern-internal-mutability.rs b/src/test/ui/mut/mut-pattern-internal-mutability.rs index ffad623e572a7..bcee878e3894b 100644 --- a/src/test/ui/mut/mut-pattern-internal-mutability.rs +++ b/src/test/ui/mut/mut-pattern-internal-mutability.rs @@ -1,12 +1,8 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - fn main() { let foo = &mut 1; let &mut x = foo; - x += 1; //[ast]~ ERROR cannot assign twice to immutable variable - //[mir]~^ ERROR cannot assign twice to immutable variable `x` + x += 1; //~ ERROR cannot assign twice to immutable variable `x` // explicitly mut-ify internals let &mut mut x = foo; @@ -14,7 +10,6 @@ fn main() { // check borrowing is detected successfully let &mut ref x = foo; - *foo += 1; //[ast]~ ERROR cannot assign to `*foo` because it is borrowed - //[mir]~^ ERROR cannot assign to `*foo` because it is borrowed + *foo += 1; //~ ERROR cannot assign to `*foo` because it is borrowed drop(x); } diff --git a/src/test/ui/mut/mut-pattern-internal-mutability.stderr b/src/test/ui/mut/mut-pattern-internal-mutability.stderr new file mode 100644 index 0000000000000..eaa33453a7507 --- /dev/null +++ b/src/test/ui/mut/mut-pattern-internal-mutability.stderr @@ -0,0 +1,25 @@ +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/mut-pattern-internal-mutability.rs:5:5 + | +LL | let &mut x = foo; + | - + | | + | first assignment to `x` + | help: make this binding mutable: `mut x` +LL | x += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error[E0506]: cannot assign to `*foo` because it is borrowed + --> $DIR/mut-pattern-internal-mutability.rs:13:5 + | +LL | let &mut ref x = foo; + | ----- borrow of `*foo` occurs here +LL | *foo += 1; + | ^^^^^^^^^ assignment to borrowed `*foo` occurs here +LL | drop(x); + | - borrow later used here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0384, E0506. +For more information about an error, try `rustc --explain E0384`. diff --git a/src/test/ui/mut/mut-pattern-mismatched.stderr b/src/test/ui/mut/mut-pattern-mismatched.stderr index d50a1a8f273bd..d1adc9915196d 100644 --- a/src/test/ui/mut/mut-pattern-mismatched.stderr +++ b/src/test/ui/mut/mut-pattern-mismatched.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/mut-pattern-mismatched.rs:6:10 | -LL | let &_ //~ ERROR mismatched types +LL | let &_ | ^^ types differ in mutability | = note: expected type `&mut {integer}` @@ -10,7 +10,7 @@ LL | let &_ //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/mut-pattern-mismatched.rs:15:9 | -LL | let &mut _ //~ ERROR mismatched types +LL | let &mut _ | ^^^^^^ types differ in mutability | = note: expected type `&{integer}` diff --git a/src/test/ui/mut/mut-ref.stderr b/src/test/ui/mut/mut-ref.stderr index 339da7f8a020c..e6d4901aafb17 100644 --- a/src/test/ui/mut/mut-ref.stderr +++ b/src/test/ui/mut/mut-ref.stderr @@ -1,7 +1,7 @@ error: the order of `mut` and `ref` is incorrect --> $DIR/mut-ref.rs:2:9 | -LL | let mut ref x = 10; //~ ERROR the order of `mut` and `ref` is incorrect +LL | let mut ref x = 10; | ^^^^^^^ help: try switching the order: `ref mut` error: aborting due to previous error diff --git a/src/test/ui/mut/mut-suggestion.nll.stderr b/src/test/ui/mut/mut-suggestion.nll.stderr deleted file mode 100644 index 61656db5ec295..0000000000000 --- a/src/test/ui/mut/mut-suggestion.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable - --> $DIR/mut-suggestion.rs:12:5 - | -LL | fn func(arg: S) { - | --- help: consider changing this to be mutable: `mut arg` -... -LL | arg.mutate(); - | ^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `local` as mutable, as it is not declared as mutable - --> $DIR/mut-suggestion.rs:21:5 - | -LL | let local = S; - | ----- help: consider changing this to be mutable: `mut local` -... -LL | local.mutate(); - | ^^^^^ cannot borrow as mutable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/mut/mut-suggestion.rs b/src/test/ui/mut/mut-suggestion.rs index 0d95a8bc12a9f..3104b20aca4e6 100644 --- a/src/test/ui/mut/mut-suggestion.rs +++ b/src/test/ui/mut/mut-suggestion.rs @@ -7,18 +7,16 @@ impl S { } fn func(arg: S) { - //~^ HELP make this binding mutable + //~^ HELP consider changing this to be mutable //~| SUGGESTION mut arg arg.mutate(); - //~^ ERROR cannot borrow immutable argument - //~| cannot borrow mutably + //~^ ERROR cannot borrow `arg` as mutable, as it is not declared as mutable } fn main() { let local = S; - //~^ HELP make this binding mutable + //~^ HELP consider changing this to be mutable //~| SUGGESTION mut local local.mutate(); - //~^ ERROR cannot borrow immutable local variable - //~| cannot borrow mutably + //~^ ERROR cannot borrow `local` as mutable, as it is not declared as mutable } diff --git a/src/test/ui/mut/mut-suggestion.stderr b/src/test/ui/mut/mut-suggestion.stderr index 1998ec1eca9e3..245eaff4bb4ec 100644 --- a/src/test/ui/mut/mut-suggestion.stderr +++ b/src/test/ui/mut/mut-suggestion.stderr @@ -1,20 +1,20 @@ -error[E0596]: cannot borrow immutable argument `arg` as mutable +error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable --> $DIR/mut-suggestion.rs:12:5 | LL | fn func(arg: S) { - | --- help: make this binding mutable: `mut arg` + | --- help: consider changing this to be mutable: `mut arg` ... LL | arg.mutate(); - | ^^^ cannot borrow mutably + | ^^^ cannot borrow as mutable -error[E0596]: cannot borrow immutable local variable `local` as mutable - --> $DIR/mut-suggestion.rs:21:5 +error[E0596]: cannot borrow `local` as mutable, as it is not declared as mutable + --> $DIR/mut-suggestion.rs:20:5 | LL | let local = S; - | ----- help: make this binding mutable: `mut local` + | ----- help: consider changing this to be mutable: `mut local` ... LL | local.mutate(); - | ^^^^^ cannot borrow mutably + | ^^^^^ cannot borrow as mutable error: aborting due to 2 previous errors diff --git a/src/test/ui/mut/mutable-class-fields-2.nll.stderr b/src/test/ui/mut/mutable-class-fields-2.nll.stderr deleted file mode 100644 index 53127922263cd..0000000000000 --- a/src/test/ui/mut/mutable-class-fields-2.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0594]: cannot assign to `self.how_hungry` which is behind a `&` reference - --> $DIR/mutable-class-fields-2.rs:9:5 - | -LL | pub fn eat(&self) { - | ----- help: consider changing this to be a mutable reference: `&mut self` -LL | self.how_hungry -= 5; //~ ERROR cannot assign - | ^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/mut/mutable-class-fields-2.stderr b/src/test/ui/mut/mutable-class-fields-2.stderr index daeee1117bcc3..a27a82ffe4642 100644 --- a/src/test/ui/mut/mutable-class-fields-2.stderr +++ b/src/test/ui/mut/mutable-class-fields-2.stderr @@ -1,11 +1,10 @@ -error[E0594]: cannot assign to field `self.how_hungry` of immutable binding +error[E0594]: cannot assign to `self.how_hungry` which is behind a `&` reference --> $DIR/mutable-class-fields-2.rs:9:5 | LL | pub fn eat(&self) { - | ----- use `&mut self` here to make mutable -LL | self.how_hungry -= 5; //~ ERROR cannot assign - | ^^^^^^^^^^^^^^^^^^^^ cannot mutably borrow field of immutable binding + | ----- help: consider changing this to be a mutable reference: `&mut self` +LL | self.how_hungry -= 5; + | ^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written error: aborting due to previous error -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/mut/mutable-class-fields.ast.nll.stderr b/src/test/ui/mut/mutable-class-fields.ast.nll.stderr deleted file mode 100644 index 6b36b29d46028..0000000000000 --- a/src/test/ui/mut/mutable-class-fields.ast.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0594]: cannot assign to `nyan.how_hungry`, as `nyan` is not declared as mutable - --> $DIR/mutable-class-fields.rs:18:3 - | -LL | let nyan : Cat = cat(52, 99); - | ---- help: consider changing this to be mutable: `mut nyan` -LL | nyan.how_hungry = 0; //[ast]~ ERROR cannot assign - | ^^^^^^^^^^^^^^^^^^^ cannot assign - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/mut/mutable-class-fields.ast.stderr b/src/test/ui/mut/mutable-class-fields.ast.stderr deleted file mode 100644 index 80185703a9e02..0000000000000 --- a/src/test/ui/mut/mutable-class-fields.ast.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0594]: cannot assign to field `nyan.how_hungry` of immutable binding - --> $DIR/mutable-class-fields.rs:18:3 - | -LL | let nyan : Cat = cat(52, 99); - | ---- help: make this binding mutable: `mut nyan` -LL | nyan.how_hungry = 0; //[ast]~ ERROR cannot assign - | ^^^^^^^^^^^^^^^^^^^ cannot mutably borrow field of immutable binding - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/mut/mutable-class-fields.mir.stderr b/src/test/ui/mut/mutable-class-fields.mir.stderr deleted file mode 100644 index 6b36b29d46028..0000000000000 --- a/src/test/ui/mut/mutable-class-fields.mir.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0594]: cannot assign to `nyan.how_hungry`, as `nyan` is not declared as mutable - --> $DIR/mutable-class-fields.rs:18:3 - | -LL | let nyan : Cat = cat(52, 99); - | ---- help: consider changing this to be mutable: `mut nyan` -LL | nyan.how_hungry = 0; //[ast]~ ERROR cannot assign - | ^^^^^^^^^^^^^^^^^^^ cannot assign - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/mut/mutable-class-fields.rs b/src/test/ui/mut/mutable-class-fields.rs index 2a729a5f6e626..30768a1ec9bcd 100644 --- a/src/test/ui/mut/mutable-class-fields.rs +++ b/src/test/ui/mut/mutable-class-fields.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - struct Cat { meows : usize, how_hungry : isize, @@ -15,6 +12,5 @@ fn cat(in_x : usize, in_y : isize) -> Cat { fn main() { let nyan : Cat = cat(52, 99); - nyan.how_hungry = 0; //[ast]~ ERROR cannot assign - //[mir]~^ ERROR cannot assign + nyan.how_hungry = 0; //~ ERROR cannot assign } diff --git a/src/test/ui/mut/mutable-class-fields.stderr b/src/test/ui/mut/mutable-class-fields.stderr new file mode 100644 index 0000000000000..5391ccc80c5f9 --- /dev/null +++ b/src/test/ui/mut/mutable-class-fields.stderr @@ -0,0 +1,10 @@ +error[E0594]: cannot assign to `nyan.how_hungry`, as `nyan` is not declared as mutable + --> $DIR/mutable-class-fields.rs:15:3 + | +LL | let nyan : Cat = cat(52, 99); + | ---- help: consider changing this to be mutable: `mut nyan` +LL | nyan.how_hungry = 0; + | ^^^^^^^^^^^^^^^^^^^ cannot assign + +error: aborting due to previous error + diff --git a/src/test/ui/namespace/namespace-mix.stderr b/src/test/ui/namespace/namespace-mix.stderr index 5ebb40e75b395..ef2d0d87f09d5 100644 --- a/src/test/ui/namespace/namespace-mix.stderr +++ b/src/test/ui/namespace/namespace-mix.stderr @@ -1,13 +1,13 @@ error[E0423]: expected value, found type alias `m1::S` --> $DIR/namespace-mix.rs:34:11 | -LL | check(m1::S); //~ ERROR expected value, found type alias `m1::S` +LL | check(m1::S); | ^^^^^ | = note: can't use a type alias as a constructor help: a tuple struct with a similar name exists | -LL | check(m1::TS); //~ ERROR expected value, found type alias `m1::S` +LL | check(m1::TS); | ^^ help: possible better candidates are found in other modules, you can import them into scope | @@ -19,13 +19,13 @@ LL | use namespace_mix::xm2::S; error[E0423]: expected value, found type alias `xm1::S` --> $DIR/namespace-mix.rs:40:11 | -LL | check(xm1::S); //~ ERROR expected value, found type alias `xm1::S` +LL | check(xm1::S); | ^^^^^^ | = note: can't use a type alias as a constructor help: a tuple struct with a similar name exists | -LL | check(xm1::TS); //~ ERROR expected value, found type alias `xm1::S` +LL | check(xm1::TS); | ^^ help: possible better candidates are found in other modules, you can import them into scope | @@ -37,11 +37,11 @@ LL | use namespace_mix::xm2::S; error[E0423]: expected value, found struct variant `m7::V` --> $DIR/namespace-mix.rs:100:11 | -LL | check(m7::V); //~ ERROR expected value, found struct variant `m7::V` +LL | check(m7::V); | ^^^^^ did you mean `m7::V { /* fields */ }`? help: a tuple variant with a similar name exists | -LL | check(m7::TV); //~ ERROR expected value, found struct variant `m7::V` +LL | check(m7::TV); | ^^ help: possible better candidates are found in other modules, you can import them into scope | @@ -53,11 +53,11 @@ LL | use namespace_mix::xm8::V; error[E0423]: expected value, found struct variant `xm7::V` --> $DIR/namespace-mix.rs:106:11 | -LL | check(xm7::V); //~ ERROR expected value, found struct variant `xm7::V` +LL | check(xm7::V); | ^^^^^^ did you mean `xm7::V { /* fields */ }`? help: a tuple variant with a similar name exists | -LL | check(xm7::TV); //~ ERROR expected value, found struct variant `xm7::V` +LL | check(xm7::TV); | ^^ help: possible better candidates are found in other modules, you can import them into scope | @@ -69,7 +69,7 @@ LL | use namespace_mix::xm8::V; error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:33:5 | -LL | check(m1::S{}); //~ ERROR c::Item +LL | check(m1::S{}); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` | note: required by `check` @@ -81,7 +81,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::S: Impossible` is not satisfied --> $DIR/namespace-mix.rs:35:5 | -LL | check(m2::S{}); //~ ERROR c::S +LL | check(m2::S{}); | ^^^^^ the trait `Impossible` is not implemented for `c::S` | note: required by `check` @@ -93,7 +93,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:36:5 | -LL | check(m2::S); //~ ERROR c::Item +LL | check(m2::S); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` | note: required by `check` @@ -105,7 +105,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:39:5 | -LL | check(xm1::S{}); //~ ERROR c::Item +LL | check(xm1::S{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` | note: required by `check` @@ -117,7 +117,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::S: Impossible` is not satisfied --> $DIR/namespace-mix.rs:41:5 | -LL | check(xm2::S{}); //~ ERROR c::S +LL | check(xm2::S{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::S` | note: required by `check` @@ -129,7 +129,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:42:5 | -LL | check(xm2::S); //~ ERROR c::Item +LL | check(xm2::S); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` | note: required by `check` @@ -141,7 +141,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:55:5 | -LL | check(m3::TS{}); //~ ERROR c::Item +LL | check(m3::TS{}); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` | note: required by `check` @@ -153,7 +153,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `fn() -> c::TS {c::TS}: Impossible` is not satisfied --> $DIR/namespace-mix.rs:56:5 | -LL | check(m3::TS); //~ ERROR c::TS +LL | check(m3::TS); | ^^^^^ the trait `Impossible` is not implemented for `fn() -> c::TS {c::TS}` | note: required by `check` @@ -165,7 +165,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::TS: Impossible` is not satisfied --> $DIR/namespace-mix.rs:57:5 | -LL | check(m4::TS{}); //~ ERROR c::TS +LL | check(m4::TS{}); | ^^^^^ the trait `Impossible` is not implemented for `c::TS` | note: required by `check` @@ -177,7 +177,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:58:5 | -LL | check(m4::TS); //~ ERROR c::Item +LL | check(m4::TS); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` | note: required by `check` @@ -189,7 +189,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:61:5 | -LL | check(xm3::TS{}); //~ ERROR c::Item +LL | check(xm3::TS{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` | note: required by `check` @@ -201,7 +201,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `fn() -> namespace_mix::c::TS {namespace_mix::c::TS}: Impossible` is not satisfied --> $DIR/namespace-mix.rs:62:5 | -LL | check(xm3::TS); //~ ERROR c::TS +LL | check(xm3::TS); | ^^^^^ the trait `Impossible` is not implemented for `fn() -> namespace_mix::c::TS {namespace_mix::c::TS}` | note: required by `check` @@ -213,7 +213,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::TS: Impossible` is not satisfied --> $DIR/namespace-mix.rs:63:5 | -LL | check(xm4::TS{}); //~ ERROR c::TS +LL | check(xm4::TS{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::TS` | note: required by `check` @@ -225,7 +225,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:64:5 | -LL | check(xm4::TS); //~ ERROR c::Item +LL | check(xm4::TS); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` | note: required by `check` @@ -237,7 +237,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:77:5 | -LL | check(m5::US{}); //~ ERROR c::Item +LL | check(m5::US{}); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` | note: required by `check` @@ -249,7 +249,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::US: Impossible` is not satisfied --> $DIR/namespace-mix.rs:78:5 | -LL | check(m5::US); //~ ERROR c::US +LL | check(m5::US); | ^^^^^ the trait `Impossible` is not implemented for `c::US` | note: required by `check` @@ -261,7 +261,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::US: Impossible` is not satisfied --> $DIR/namespace-mix.rs:79:5 | -LL | check(m6::US{}); //~ ERROR c::US +LL | check(m6::US{}); | ^^^^^ the trait `Impossible` is not implemented for `c::US` | note: required by `check` @@ -273,7 +273,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:80:5 | -LL | check(m6::US); //~ ERROR c::Item +LL | check(m6::US); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` | note: required by `check` @@ -285,7 +285,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:83:5 | -LL | check(xm5::US{}); //~ ERROR c::Item +LL | check(xm5::US{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` | note: required by `check` @@ -297,7 +297,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::US: Impossible` is not satisfied --> $DIR/namespace-mix.rs:84:5 | -LL | check(xm5::US); //~ ERROR c::US +LL | check(xm5::US); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::US` | note: required by `check` @@ -309,7 +309,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::US: Impossible` is not satisfied --> $DIR/namespace-mix.rs:85:5 | -LL | check(xm6::US{}); //~ ERROR c::US +LL | check(xm6::US{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::US` | note: required by `check` @@ -321,7 +321,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:86:5 | -LL | check(xm6::US); //~ ERROR c::Item +LL | check(xm6::US); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` | note: required by `check` @@ -333,7 +333,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:99:5 | -LL | check(m7::V{}); //~ ERROR c::Item +LL | check(m7::V{}); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` | note: required by `check` @@ -345,7 +345,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:101:5 | -LL | check(m8::V{}); //~ ERROR c::E +LL | check(m8::V{}); | ^^^^^ the trait `Impossible` is not implemented for `c::E` | note: required by `check` @@ -357,7 +357,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:102:5 | -LL | check(m8::V); //~ ERROR c::Item +LL | check(m8::V); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` | note: required by `check` @@ -369,7 +369,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:105:5 | -LL | check(xm7::V{}); //~ ERROR c::Item +LL | check(xm7::V{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` | note: required by `check` @@ -381,7 +381,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:107:5 | -LL | check(xm8::V{}); //~ ERROR c::E +LL | check(xm8::V{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` | note: required by `check` @@ -393,7 +393,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:108:5 | -LL | check(xm8::V); //~ ERROR c::Item +LL | check(xm8::V); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` | note: required by `check` @@ -405,7 +405,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:121:5 | -LL | check(m9::TV{}); //~ ERROR c::Item +LL | check(m9::TV{}); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` | note: required by `check` @@ -417,7 +417,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `fn() -> c::E {c::E::TV}: Impossible` is not satisfied --> $DIR/namespace-mix.rs:122:5 | -LL | check(m9::TV); //~ ERROR c::E +LL | check(m9::TV); | ^^^^^ the trait `Impossible` is not implemented for `fn() -> c::E {c::E::TV}` | note: required by `check` @@ -429,7 +429,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:123:5 | -LL | check(mA::TV{}); //~ ERROR c::E +LL | check(mA::TV{}); | ^^^^^ the trait `Impossible` is not implemented for `c::E` | note: required by `check` @@ -441,7 +441,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:124:5 | -LL | check(mA::TV); //~ ERROR c::Item +LL | check(mA::TV); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` | note: required by `check` @@ -453,7 +453,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:127:5 | -LL | check(xm9::TV{}); //~ ERROR c::Item +LL | check(xm9::TV{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` | note: required by `check` @@ -462,11 +462,11 @@ note: required by `check` LL | fn check(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `fn() -> namespace_mix::c::E {namespace_mix::c::E::TV}: Impossible` is not satisfied +error[E0277]: the trait bound `fn() -> namespace_mix::c::E {namespace_mix::xm7::TV}: Impossible` is not satisfied --> $DIR/namespace-mix.rs:128:5 | -LL | check(xm9::TV); //~ ERROR c::E - | ^^^^^ the trait `Impossible` is not implemented for `fn() -> namespace_mix::c::E {namespace_mix::c::E::TV}` +LL | check(xm9::TV); + | ^^^^^ the trait `Impossible` is not implemented for `fn() -> namespace_mix::c::E {namespace_mix::xm7::TV}` | note: required by `check` --> $DIR/namespace-mix.rs:21:1 @@ -477,7 +477,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:129:5 | -LL | check(xmA::TV{}); //~ ERROR c::E +LL | check(xmA::TV{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` | note: required by `check` @@ -489,7 +489,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:130:5 | -LL | check(xmA::TV); //~ ERROR c::Item +LL | check(xmA::TV); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` | note: required by `check` @@ -501,7 +501,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:143:5 | -LL | check(mB::UV{}); //~ ERROR c::Item +LL | check(mB::UV{}); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` | note: required by `check` @@ -513,7 +513,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:144:5 | -LL | check(mB::UV); //~ ERROR c::E +LL | check(mB::UV); | ^^^^^ the trait `Impossible` is not implemented for `c::E` | note: required by `check` @@ -525,7 +525,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:145:5 | -LL | check(mC::UV{}); //~ ERROR c::E +LL | check(mC::UV{}); | ^^^^^ the trait `Impossible` is not implemented for `c::E` | note: required by `check` @@ -537,7 +537,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:146:5 | -LL | check(mC::UV); //~ ERROR c::Item +LL | check(mC::UV); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` | note: required by `check` @@ -549,7 +549,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:149:5 | -LL | check(xmB::UV{}); //~ ERROR c::Item +LL | check(xmB::UV{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` | note: required by `check` @@ -561,7 +561,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:150:5 | -LL | check(xmB::UV); //~ ERROR c::E +LL | check(xmB::UV); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` | note: required by `check` @@ -573,7 +573,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:151:5 | -LL | check(xmC::UV{}); //~ ERROR c::E +LL | check(xmC::UV{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` | note: required by `check` @@ -585,7 +585,7 @@ LL | fn check(_: T) {} error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:152:5 | -LL | check(xmC::UV); //~ ERROR c::Item +LL | check(xmC::UV); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` | note: required by `check` @@ -596,5 +596,5 @@ LL | fn check(_: T) {} error: aborting due to 48 previous errors -Some errors occurred: E0277, E0423. +Some errors have detailed explanations: E0277, E0423. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/namespace/namespaced-enum-glob-import-no-impls-xcrate.stderr b/src/test/ui/namespace/namespaced-enum-glob-import-no-impls-xcrate.stderr index 691061f051083..f3dbcc2d7b243 100644 --- a/src/test/ui/namespace/namespaced-enum-glob-import-no-impls-xcrate.stderr +++ b/src/test/ui/namespace/namespaced-enum-glob-import-no-impls-xcrate.stderr @@ -1,25 +1,25 @@ error[E0425]: cannot find function `foo` in this scope --> $DIR/namespaced-enum-glob-import-no-impls-xcrate.rs:11:5 | -LL | foo(); //~ ERROR cannot find function `foo` in this scope +LL | foo(); | ^^^ not found in this scope error[E0425]: cannot find function `foo` in module `m` --> $DIR/namespaced-enum-glob-import-no-impls-xcrate.rs:12:8 | -LL | m::foo(); //~ ERROR cannot find function `foo` in module `m` +LL | m::foo(); | ^^^ not found in `m` error[E0425]: cannot find function `bar` in this scope --> $DIR/namespaced-enum-glob-import-no-impls-xcrate.rs:13:5 | -LL | bar(); //~ ERROR cannot find function `bar` in this scope +LL | bar(); | ^^^ not found in this scope error[E0425]: cannot find function `bar` in module `m` --> $DIR/namespaced-enum-glob-import-no-impls-xcrate.rs:14:8 | -LL | m::bar(); //~ ERROR cannot find function `bar` in module `m` +LL | m::bar(); | ^^^ not found in `m` error: aborting due to 4 previous errors diff --git a/src/test/ui/namespace/namespaced-enum-glob-import-no-impls.stderr b/src/test/ui/namespace/namespaced-enum-glob-import-no-impls.stderr index f53f299fe4dca..98784de8e593c 100644 --- a/src/test/ui/namespace/namespaced-enum-glob-import-no-impls.stderr +++ b/src/test/ui/namespace/namespaced-enum-glob-import-no-impls.stderr @@ -1,25 +1,25 @@ error[E0425]: cannot find function `foo` in this scope --> $DIR/namespaced-enum-glob-import-no-impls.rs:21:5 | -LL | foo(); //~ ERROR cannot find function `foo` in this scope +LL | foo(); | ^^^ not found in this scope error[E0425]: cannot find function `foo` in module `m` --> $DIR/namespaced-enum-glob-import-no-impls.rs:22:8 | -LL | m::foo(); //~ ERROR cannot find function `foo` in module `m` +LL | m::foo(); | ^^^ not found in `m` error[E0425]: cannot find function `bar` in this scope --> $DIR/namespaced-enum-glob-import-no-impls.rs:23:5 | -LL | bar(); //~ ERROR cannot find function `bar` in this scope +LL | bar(); | ^^^ not found in this scope error[E0425]: cannot find function `bar` in module `m` --> $DIR/namespaced-enum-glob-import-no-impls.rs:24:8 | -LL | m::bar(); //~ ERROR cannot find function `bar` in module `m` +LL | m::bar(); | ^^^ not found in `m` error: aborting due to 4 previous errors diff --git a/src/test/ui/nested-cfg-attrs.stderr b/src/test/ui/nested-cfg-attrs.stderr index e7cd39114eda0..f63888b2f8ad0 100644 --- a/src/test/ui/nested-cfg-attrs.stderr +++ b/src/test/ui/nested-cfg-attrs.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find function `f` in this scope --> $DIR/nested-cfg-attrs.rs:4:13 | -LL | fn main() { f() } //~ ERROR cannot find function `f` in this scope +LL | fn main() { f() } | ^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/nested-ty-params.stderr b/src/test/ui/nested-ty-params.stderr index 37adeffb9b07a..f6741b5e5e82a 100644 --- a/src/test/ui/nested-ty-params.stderr +++ b/src/test/ui/nested-ty-params.stderr @@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/nested-ty-params.rs:3:16 | LL | fn hd(v: Vec ) -> U { - | - type variable from outer function + | - type parameter from outer function LL | fn hd1(w: [U]) -> U { return w[0]; } | --- ^ use of generic parameter from outer function | | @@ -12,7 +12,7 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/nested-ty-params.rs:3:23 | LL | fn hd(v: Vec ) -> U { - | - type variable from outer function + | - type parameter from outer function LL | fn hd1(w: [U]) -> U { return w[0]; } | --- ^ use of generic parameter from outer function | | diff --git a/src/test/ui/nested_impl_trait.stderr b/src/test/ui/nested_impl_trait.stderr index 60f57e56ba118..bf853d30fab46 100644 --- a/src/test/ui/nested_impl_trait.stderr +++ b/src/test/ui/nested_impl_trait.stderr @@ -48,5 +48,4 @@ LL | fn allowed_in_ret_type() -> impl Fn() -> impl Into { error: aborting due to 6 previous errors -Some errors occurred: E0562, E0666. -For more information about an error, try `rustc --explain E0562`. +For more information about this error, try `rustc --explain E0562`. diff --git a/src/test/ui/never-assign-dead-code.stderr b/src/test/ui/never-assign-dead-code.stderr index bcc20a0d703c0..6735310da8b95 100644 --- a/src/test/ui/never-assign-dead-code.stderr +++ b/src/test/ui/never-assign-dead-code.stderr @@ -1,7 +1,7 @@ warning: unreachable statement --> $DIR/never-assign-dead-code.rs:10:5 | -LL | drop(x); //~ WARN unreachable +LL | drop(x); | ^^^^^^^^ | note: lint level defined here @@ -14,13 +14,13 @@ LL | #![warn(unused)] warning: unreachable expression --> $DIR/never-assign-dead-code.rs:10:5 | -LL | drop(x); //~ WARN unreachable +LL | drop(x); | ^^^^^^^ warning: unused variable: `x` --> $DIR/never-assign-dead-code.rs:9:9 | -LL | let x: ! = panic!("aah"); //~ WARN unused +LL | let x: ! = panic!("aah"); | ^ help: consider prefixing with an underscore: `_x` | note: lint level defined here diff --git a/src/test/ui/never-assign-wrong-type.stderr b/src/test/ui/never-assign-wrong-type.stderr index bc61996db99bb..da2e77d023d19 100644 --- a/src/test/ui/never-assign-wrong-type.stderr +++ b/src/test/ui/never-assign-wrong-type.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/never-assign-wrong-type.rs:7:16 | -LL | let x: ! = "hello"; //~ ERROR mismatched types +LL | let x: ! = "hello"; | ^^^^^^^ expected !, found reference | = note: expected type `!` diff --git a/src/test/ui/nll/assign-while-to-immutable.rs b/src/test/ui/nll/assign-while-to-immutable.rs new file mode 100644 index 0000000000000..c803321b5087a --- /dev/null +++ b/src/test/ui/nll/assign-while-to-immutable.rs @@ -0,0 +1,11 @@ +// We used to incorrectly assign to `x` twice when generating MIR for this +// function, preventing this from compiling. + +// check-pass + +fn main() { + let x = while false { + break; + }; + let y = 'l: while break 'l {}; +} diff --git a/src/test/ui/nll/borrow-use-issue-46875.rs b/src/test/ui/nll/borrow-use-issue-46875.rs index 03db28fc508b1..42e28b9674b30 100644 --- a/src/test/ui/nll/borrow-use-issue-46875.rs +++ b/src/test/ui/nll/borrow-use-issue-46875.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - // run-pass fn vec() { diff --git a/src/test/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs b/src/test/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs index 59936a8092534..7d3b00dfc7163 100644 --- a/src/test/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs +++ b/src/test/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs @@ -3,7 +3,6 @@ // // FIXME(#54366) - We probably shouldn't allow #[thread_local] static mut to get a 'static lifetime. -#![feature(nll)] #![feature(thread_local)] #[thread_local] diff --git a/src/test/ui/nll/borrowed-local-error.rs b/src/test/ui/nll/borrowed-local-error.rs index d37e61b63a814..d333356d964ce 100644 --- a/src/test/ui/nll/borrowed-local-error.rs +++ b/src/test/ui/nll/borrowed-local-error.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - fn gimme(x: &(u32,)) -> &u32 { &x.0 } diff --git a/src/test/ui/nll/borrowed-local-error.stderr b/src/test/ui/nll/borrowed-local-error.stderr index 318b62a0fdb15..d629caa435319 100644 --- a/src/test/ui/nll/borrowed-local-error.stderr +++ b/src/test/ui/nll/borrowed-local-error.stderr @@ -1,12 +1,12 @@ error[E0597]: `v` does not live long enough - --> $DIR/borrowed-local-error.rs:10:9 + --> $DIR/borrowed-local-error.rs:8:9 | LL | let x = gimme({ | ----- borrow later used by call LL | let v = (22,); LL | &v | ^^ borrowed value does not live long enough -LL | //~^ ERROR `v` does not live long enough [E0597] +LL | LL | }); | - `v` dropped here while still borrowed diff --git a/src/test/ui/nll/borrowed-referent-issue-38899.rs b/src/test/ui/nll/borrowed-referent-issue-38899.rs index 7bad6dc2cd335..d4b05fb793160 100644 --- a/src/test/ui/nll/borrowed-referent-issue-38899.rs +++ b/src/test/ui/nll/borrowed-referent-issue-38899.rs @@ -1,7 +1,6 @@ // Regression test for issue #38899 #![feature(nll)] -#![allow(dead_code)] pub struct Block<'a> { current: &'a u8, diff --git a/src/test/ui/nll/borrowed-referent-issue-38899.stderr b/src/test/ui/nll/borrowed-referent-issue-38899.stderr index 1b58b21fff05a..38a6e27a0e560 100644 --- a/src/test/ui/nll/borrowed-referent-issue-38899.stderr +++ b/src/test/ui/nll/borrowed-referent-issue-38899.stderr @@ -1,12 +1,12 @@ error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable - --> $DIR/borrowed-referent-issue-38899.rs:14:21 + --> $DIR/borrowed-referent-issue-38899.rs:13:21 | LL | let x = &mut block; | ---------- mutable borrow occurs here LL | println!("{}", x.current); LL | let p: &'a u8 = &*block.current; | ^^^^^^^^^^^^^^^ immutable borrow occurs here -LL | //~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable +LL | LL | drop(x); | - mutable borrow later used here diff --git a/src/test/ui/nll/borrowed-temporary-error.rs b/src/test/ui/nll/borrowed-temporary-error.rs index 5ad987c721470..37d0e670d350d 100644 --- a/src/test/ui/nll/borrowed-temporary-error.rs +++ b/src/test/ui/nll/borrowed-temporary-error.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - fn gimme(x: &(u32,)) -> &u32 { &x.0 } diff --git a/src/test/ui/nll/borrowed-temporary-error.stderr b/src/test/ui/nll/borrowed-temporary-error.stderr index 31d1dfde1ce8c..2c6bd92641f60 100644 --- a/src/test/ui/nll/borrowed-temporary-error.stderr +++ b/src/test/ui/nll/borrowed-temporary-error.stderr @@ -1,9 +1,9 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowed-temporary-error.rs:10:10 + --> $DIR/borrowed-temporary-error.rs:8:10 | LL | &(v,) | ^^^^ creates a temporary which is freed while still in use -LL | //~^ ERROR temporary value dropped while borrowed [E0716] +LL | LL | }); | - temporary value is freed at the end of this statement LL | println!("{:?}", x); diff --git a/src/test/ui/nll/borrowed-universal-error-2.rs b/src/test/ui/nll/borrowed-universal-error-2.rs index a10a62b470d76..3f9b2f2924c2c 100644 --- a/src/test/ui/nll/borrowed-universal-error-2.rs +++ b/src/test/ui/nll/borrowed-universal-error-2.rs @@ -1,6 +1,3 @@ -#![feature(nll)] -#![allow(warnings)] - fn foo<'a>(x: &'a (u32,)) -> &'a u32 { let v = 22; &v diff --git a/src/test/ui/nll/borrowed-universal-error-2.stderr b/src/test/ui/nll/borrowed-universal-error-2.stderr index e89a77a2d360f..7213ed3bafb37 100644 --- a/src/test/ui/nll/borrowed-universal-error-2.stderr +++ b/src/test/ui/nll/borrowed-universal-error-2.stderr @@ -1,5 +1,5 @@ error[E0515]: cannot return reference to local variable `v` - --> $DIR/borrowed-universal-error-2.rs:6:5 + --> $DIR/borrowed-universal-error-2.rs:3:5 | LL | &v | ^^ returns a reference to data owned by the current function diff --git a/src/test/ui/nll/borrowed-universal-error.rs b/src/test/ui/nll/borrowed-universal-error.rs index 18a0a72c4bb83..fc9ffd47061b4 100644 --- a/src/test/ui/nll/borrowed-universal-error.rs +++ b/src/test/ui/nll/borrowed-universal-error.rs @@ -1,6 +1,3 @@ -#![feature(nll)] -#![allow(warnings)] - fn gimme(x: &(u32,)) -> &u32 { &x.0 } diff --git a/src/test/ui/nll/borrowed-universal-error.stderr b/src/test/ui/nll/borrowed-universal-error.stderr index 4b76795943e64..88a2d8fcf8cc0 100644 --- a/src/test/ui/nll/borrowed-universal-error.stderr +++ b/src/test/ui/nll/borrowed-universal-error.stderr @@ -1,5 +1,5 @@ error[E0515]: cannot return value referencing temporary value - --> $DIR/borrowed-universal-error.rs:10:5 + --> $DIR/borrowed-universal-error.rs:7:5 | LL | gimme(&(v,)) | ^^^^^^^----^ diff --git a/src/test/ui/nll/cannot-move-block-spans.nll.stderr b/src/test/ui/nll/cannot-move-block-spans.nll.stderr deleted file mode 100644 index 30b4bf75af693..0000000000000 --- a/src/test/ui/nll/cannot-move-block-spans.nll.stderr +++ /dev/null @@ -1,85 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/cannot-move-block-spans.rs:5:15 - | -LL | let x = { *r }; //~ ERROR - | ^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `r` - -error[E0507]: cannot move out of borrowed content - --> $DIR/cannot-move-block-spans.rs:6:22 - | -LL | let y = unsafe { *r }; //~ ERROR - | ^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `r` - -error[E0507]: cannot move out of borrowed content - --> $DIR/cannot-move-block-spans.rs:7:26 - | -LL | let z = loop { break *r; }; //~ ERROR - | ^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `r` - -error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array - --> $DIR/cannot-move-block-spans.rs:11:15 - | -LL | let x = { arr[0] }; //~ ERROR - | ^^^^^^ - | | - | cannot move out of here - | help: consider borrowing here: `&arr[0]` - -error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array - --> $DIR/cannot-move-block-spans.rs:12:22 - | -LL | let y = unsafe { arr[0] }; //~ ERROR - | ^^^^^^ - | | - | cannot move out of here - | help: consider borrowing here: `&arr[0]` - -error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array - --> $DIR/cannot-move-block-spans.rs:13:26 - | -LL | let z = loop { break arr[0]; }; //~ ERROR - | ^^^^^^ - | | - | cannot move out of here - | help: consider borrowing here: `&arr[0]` - -error[E0507]: cannot move out of borrowed content - --> $DIR/cannot-move-block-spans.rs:17:38 - | -LL | let x = { let mut u = 0; u += 1; *r }; //~ ERROR - | ^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `r` - -error[E0507]: cannot move out of borrowed content - --> $DIR/cannot-move-block-spans.rs:18:45 - | -LL | let y = unsafe { let mut u = 0; u += 1; *r }; //~ ERROR - | ^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `r` - -error[E0507]: cannot move out of borrowed content - --> $DIR/cannot-move-block-spans.rs:19:49 - | -LL | let z = loop { let mut u = 0; u += 1; break *r; u += 2; }; //~ ERROR - | ^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `r` - -error: aborting due to 9 previous errors - -Some errors occurred: E0507, E0508. -For more information about an error, try `rustc --explain E0507`. diff --git a/src/test/ui/nll/cannot-move-block-spans.stderr b/src/test/ui/nll/cannot-move-block-spans.stderr index e37c6ff06f7e8..7db5d731acd17 100644 --- a/src/test/ui/nll/cannot-move-block-spans.stderr +++ b/src/test/ui/nll/cannot-move-block-spans.stderr @@ -1,58 +1,88 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:5:15 | -LL | let x = { *r }; //~ ERROR - | ^^ cannot move out of borrowed content +LL | let x = { *r }; + | ^^ + | | + | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*r` -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:6:22 | -LL | let y = unsafe { *r }; //~ ERROR - | ^^ cannot move out of borrowed content +LL | let y = unsafe { *r }; + | ^^ + | | + | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*r` -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:7:26 | -LL | let z = loop { break *r; }; //~ ERROR - | ^^ cannot move out of borrowed content +LL | let z = loop { break *r; }; + | ^^ + | | + | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*r` error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array --> $DIR/cannot-move-block-spans.rs:11:15 | -LL | let x = { arr[0] }; //~ ERROR - | ^^^^^^ cannot move out of here +LL | let x = { arr[0] }; + | ^^^^^^ + | | + | cannot move out of here + | move occurs because `arr[_]` has type `std::string::String`, which does not implement the `Copy` trait + | help: consider borrowing here: `&arr[0]` error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array --> $DIR/cannot-move-block-spans.rs:12:22 | -LL | let y = unsafe { arr[0] }; //~ ERROR - | ^^^^^^ cannot move out of here +LL | let y = unsafe { arr[0] }; + | ^^^^^^ + | | + | cannot move out of here + | move occurs because `arr[_]` has type `std::string::String`, which does not implement the `Copy` trait + | help: consider borrowing here: `&arr[0]` error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array --> $DIR/cannot-move-block-spans.rs:13:26 | -LL | let z = loop { break arr[0]; }; //~ ERROR - | ^^^^^^ cannot move out of here +LL | let z = loop { break arr[0]; }; + | ^^^^^^ + | | + | cannot move out of here + | move occurs because `arr[_]` has type `std::string::String`, which does not implement the `Copy` trait + | help: consider borrowing here: `&arr[0]` -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:17:38 | -LL | let x = { let mut u = 0; u += 1; *r }; //~ ERROR - | ^^ cannot move out of borrowed content +LL | let x = { let mut u = 0; u += 1; *r }; + | ^^ + | | + | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*r` -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:18:45 | -LL | let y = unsafe { let mut u = 0; u += 1; *r }; //~ ERROR - | ^^ cannot move out of borrowed content +LL | let y = unsafe { let mut u = 0; u += 1; *r }; + | ^^ + | | + | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*r` -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:19:49 | -LL | let z = loop { let mut u = 0; u += 1; break *r; u += 2; }; //~ ERROR - | ^^ cannot move out of borrowed content +LL | let z = loop { let mut u = 0; u += 1; break *r; u += 2; }; + | ^^ + | | + | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*r` error: aborting due to 9 previous errors -Some errors occurred: E0507, E0508. +Some errors have detailed explanations: E0507, E0508. For more information about an error, try `rustc --explain E0507`. diff --git a/src/test/ui/nll/capture-mut-ref.rs b/src/test/ui/nll/capture-mut-ref.rs index 222f4e71c52fe..9d2624a9d6fa6 100644 --- a/src/test/ui/nll/capture-mut-ref.rs +++ b/src/test/ui/nll/capture-mut-ref.rs @@ -1,7 +1,6 @@ // Check that capturing a mutable reference by move and assigning to its // referent doesn't make the unused mut lint think that it is mutable. -#![feature(nll)] #![deny(unused_mut)] fn mutable_upvar() { diff --git a/src/test/ui/nll/capture-mut-ref.stderr b/src/test/ui/nll/capture-mut-ref.stderr index 327ce0c6e81f0..883b2d05a7f51 100644 --- a/src/test/ui/nll/capture-mut-ref.stderr +++ b/src/test/ui/nll/capture-mut-ref.stderr @@ -1,5 +1,5 @@ error: variable does not need to be mutable - --> $DIR/capture-mut-ref.rs:8:9 + --> $DIR/capture-mut-ref.rs:7:9 | LL | let mut x = &mut 0; | ----^ @@ -7,7 +7,7 @@ LL | let mut x = &mut 0; | help: remove this `mut` | note: lint level defined here - --> $DIR/capture-mut-ref.rs:5:9 + --> $DIR/capture-mut-ref.rs:4:9 | LL | #![deny(unused_mut)] | ^^^^^^^^^^ diff --git a/src/test/ui/nll/capture-ref-in-struct.rs b/src/test/ui/nll/capture-ref-in-struct.rs index bf2db32901e68..db6ac7d66ccc4 100644 --- a/src/test/ui/nll/capture-ref-in-struct.rs +++ b/src/test/ui/nll/capture-ref-in-struct.rs @@ -1,9 +1,6 @@ // Test that a structure which tries to store a pointer to `y` into // `p` (indirectly) fails to compile. -#![feature(rustc_attrs)] -#![feature(nll)] - struct SomeStruct<'a, 'b: 'a> { p: &'a mut &'b i32, y: &'b i32, diff --git a/src/test/ui/nll/capture-ref-in-struct.stderr b/src/test/ui/nll/capture-ref-in-struct.stderr index 7fafb4474fdb3..521e543bd2693 100644 --- a/src/test/ui/nll/capture-ref-in-struct.stderr +++ b/src/test/ui/nll/capture-ref-in-struct.stderr @@ -1,5 +1,5 @@ error[E0597]: `y` does not live long enough - --> $DIR/capture-ref-in-struct.rs:21:16 + --> $DIR/capture-ref-in-struct.rs:18:16 | LL | y: &y, | ^^ borrowed value does not live long enough diff --git a/src/test/ui/nll/closure-access-spans.rs b/src/test/ui/nll/closure-access-spans.rs index 1e11b4818183b..2a59e80b25cd9 100644 --- a/src/test/ui/nll/closure-access-spans.rs +++ b/src/test/ui/nll/closure-access-spans.rs @@ -1,7 +1,5 @@ // check that accesses due to a closure capture give a special note -#![feature(nll)] - fn closure_imm_capture_conflict(mut x: i32) { let r = &mut x; || x; //~ ERROR diff --git a/src/test/ui/nll/closure-access-spans.stderr b/src/test/ui/nll/closure-access-spans.stderr index 3ca0aefb592e0..4a8086905b7df 100644 --- a/src/test/ui/nll/closure-access-spans.stderr +++ b/src/test/ui/nll/closure-access-spans.stderr @@ -1,9 +1,9 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/closure-access-spans.rs:7:5 + --> $DIR/closure-access-spans.rs:5:5 | LL | let r = &mut x; | ------ mutable borrow occurs here -LL | || x; //~ ERROR +LL | || x; | ^^ - second borrow occurs due to use of `x` in closure | | | immutable borrow occurs here @@ -11,11 +11,11 @@ LL | r.use_mut(); | - mutable borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/closure-access-spans.rs:13:5 + --> $DIR/closure-access-spans.rs:11:5 | LL | let r = &mut x; | ------ first mutable borrow occurs here -LL | || x = 2; //~ ERROR +LL | || x = 2; | ^^ - second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here @@ -23,11 +23,11 @@ LL | r.use_mut(); | - first borrow later used here error[E0500]: closure requires unique access to `x` but it is already borrowed - --> $DIR/closure-access-spans.rs:19:5 + --> $DIR/closure-access-spans.rs:17:5 | LL | let r = &mut x; | ------ borrow occurs here -LL | || *x = 2; //~ ERROR +LL | || *x = 2; | ^^ - second borrow occurs due to use of `x` in closure | | | closure construction occurs here @@ -35,21 +35,21 @@ LL | r.use_mut(); | - first borrow later used here error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/closure-access-spans.rs:25:13 + --> $DIR/closure-access-spans.rs:23:13 | LL | let r = &mut x; | ------ borrow of `x` occurs here -LL | move || x; //~ ERROR +LL | move || x; | ^ use of borrowed `x` LL | r.use_ref(); | - borrow later used here error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/closure-access-spans.rs:31:5 + --> $DIR/closure-access-spans.rs:29:5 | LL | let r = &x; | -- borrow of `x` occurs here -LL | || x; //~ ERROR +LL | || x; | ^^ - move occurs due to use in closure | | | move out of `x` occurs here @@ -57,54 +57,54 @@ LL | r.use_ref(); | - borrow later used here error[E0382]: borrow of moved value: `x` - --> $DIR/closure-access-spans.rs:37:5 + --> $DIR/closure-access-spans.rs:35:5 | LL | fn closure_imm_capture_moved(mut x: String) { | ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait LL | let r = x; | - value moved here -LL | || x.len(); //~ ERROR +LL | || x.len(); | ^^ - borrow occurs due to use in closure | | | value borrowed here after move error[E0382]: borrow of moved value: `x` - --> $DIR/closure-access-spans.rs:42:5 + --> $DIR/closure-access-spans.rs:40:5 | LL | fn closure_mut_capture_moved(mut x: String) { | ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait LL | let r = x; | - value moved here -LL | || x = String::new(); //~ ERROR +LL | || x = String::new(); | ^^ - borrow occurs due to use in closure | | | value borrowed here after move error[E0382]: borrow of moved value: `x` - --> $DIR/closure-access-spans.rs:47:5 + --> $DIR/closure-access-spans.rs:45:5 | LL | fn closure_unique_capture_moved(x: &mut String) { | - move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait LL | let r = x; | - value moved here -LL | || *x = String::new(); //~ ERROR +LL | || *x = String::new(); | ^^ - borrow occurs due to use in closure | | | value borrowed here after move error[E0382]: use of moved value: `x` - --> $DIR/closure-access-spans.rs:52:5 + --> $DIR/closure-access-spans.rs:50:5 | LL | fn closure_move_capture_moved(x: &mut String) { | - move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait LL | let r = x; | - value moved here -LL | || x; //~ ERROR +LL | || x; | ^^ - use occurs due to use in closure | | | value used here after move error: aborting due to 9 previous errors -Some errors occurred: E0382, E0499, E0500, E0502, E0503, E0505. +Some errors have detailed explanations: E0382, E0499, E0500, E0502, E0503, E0505. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/nll/closure-borrow-spans.rs b/src/test/ui/nll/closure-borrow-spans.rs index 7fc301b70380b..b38f7900e8e5e 100644 --- a/src/test/ui/nll/closure-borrow-spans.rs +++ b/src/test/ui/nll/closure-borrow-spans.rs @@ -1,7 +1,5 @@ // check that existing borrows due to a closure capture give a special note -#![feature(nll)] - fn move_while_borrowed(x: String) { let f = || x.len(); let y = x; //~ ERROR diff --git a/src/test/ui/nll/closure-borrow-spans.stderr b/src/test/ui/nll/closure-borrow-spans.stderr index cf88b309f74d6..a3bcbbab3ec69 100644 --- a/src/test/ui/nll/closure-borrow-spans.stderr +++ b/src/test/ui/nll/closure-borrow-spans.stderr @@ -1,31 +1,31 @@ error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/closure-borrow-spans.rs:7:13 + --> $DIR/closure-borrow-spans.rs:5:13 | LL | let f = || x.len(); | -- - borrow occurs due to use in closure | | | borrow of `x` occurs here -LL | let y = x; //~ ERROR +LL | let y = x; | ^ move out of `x` occurs here LL | f.use_ref(); | - borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/closure-borrow-spans.rs:13:13 + --> $DIR/closure-borrow-spans.rs:11:13 | LL | let f = || x; | -- - first borrow occurs due to use of `x` in closure | | | immutable borrow occurs here -LL | let y = &mut x; //~ ERROR +LL | let y = &mut x; | ^^^^^^ mutable borrow occurs here LL | f.use_ref(); | - immutable borrow later used here error[E0597]: `x` does not live long enough - --> $DIR/closure-borrow-spans.rs:21:16 + --> $DIR/closure-borrow-spans.rs:19:16 | -LL | f = || x; //~ ERROR +LL | f = || x; | -- ^ borrowed value does not live long enough | | | value captured here @@ -35,57 +35,57 @@ LL | f.use_ref(); | - borrow later used here error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/closure-borrow-spans.rs:28:5 + --> $DIR/closure-borrow-spans.rs:26:5 | LL | let f = || x; | -- - borrow occurs due to use in closure | | | borrow of `x` occurs here -LL | x = 1; //~ ERROR +LL | x = 1; | ^^^^^ assignment to borrowed `x` occurs here LL | f.use_ref(); | - borrow later used here error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/closure-borrow-spans.rs:34:13 + --> $DIR/closure-borrow-spans.rs:32:13 | LL | let f = || x = 0; | -- - borrow occurs due to use of `x` in closure | | | borrow of `x` occurs here -LL | let y = x; //~ ERROR +LL | let y = x; | ^ use of borrowed `x` LL | f.use_ref(); | - borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/closure-borrow-spans.rs:40:13 + --> $DIR/closure-borrow-spans.rs:38:13 | LL | let f = || x = 0; | -- - first borrow occurs due to use of `x` in closure | | | mutable borrow occurs here -LL | let y = &x; //~ ERROR +LL | let y = &x; | ^^ immutable borrow occurs here LL | f.use_ref(); | - mutable borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/closure-borrow-spans.rs:46:13 + --> $DIR/closure-borrow-spans.rs:44:13 | LL | let f = || x = 0; | -- - first borrow occurs due to use of `x` in closure | | | first mutable borrow occurs here -LL | let y = &mut x; //~ ERROR +LL | let y = &mut x; | ^^^^^^ second mutable borrow occurs here LL | f.use_ref(); | - first borrow later used here error[E0597]: `x` does not live long enough - --> $DIR/closure-borrow-spans.rs:54:16 + --> $DIR/closure-borrow-spans.rs:52:16 | -LL | f = || x = 0; //~ ERROR +LL | f = || x = 0; | -- ^ borrowed value does not live long enough | | | value captured here @@ -95,57 +95,57 @@ LL | f.use_ref(); | - borrow later used here error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/closure-borrow-spans.rs:61:5 + --> $DIR/closure-borrow-spans.rs:59:5 | LL | let f = || x = 0; | -- - borrow occurs due to use in closure | | | borrow of `x` occurs here -LL | x = 1; //~ ERROR +LL | x = 1; | ^^^^^ assignment to borrowed `x` occurs here LL | f.use_ref(); | - borrow later used here error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/closure-borrow-spans.rs:67:13 + --> $DIR/closure-borrow-spans.rs:65:13 | LL | let f = || *x = 0; | -- - borrow occurs due to use in closure | | | borrow of `x` occurs here -LL | let y = x; //~ ERROR +LL | let y = x; | ^ move out of `x` occurs here LL | f.use_ref(); | - borrow later used here error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access - --> $DIR/closure-borrow-spans.rs:73:13 + --> $DIR/closure-borrow-spans.rs:71:13 | LL | let f = || *x = 0; | -- - first borrow occurs due to use of `x` in closure | | | closure construction occurs here -LL | let y = &x; //~ ERROR +LL | let y = &x; | ^^ second borrow occurs here LL | f.use_ref(); | - first borrow later used here error[E0501]: cannot borrow `x` as mutable because previous closure requires unique access - --> $DIR/closure-borrow-spans.rs:79:13 + --> $DIR/closure-borrow-spans.rs:77:13 | LL | let f = || *x = 0; | -- - first borrow occurs due to use of `x` in closure | | | closure construction occurs here -LL | let y = &mut x; //~ ERROR +LL | let y = &mut x; | ^^^^^^ second borrow occurs here LL | f.use_ref(); | - first borrow later used here error[E0597]: `x` does not live long enough - --> $DIR/closure-borrow-spans.rs:88:17 + --> $DIR/closure-borrow-spans.rs:86:17 | -LL | f = || *x = 0; //~ ERROR +LL | f = || *x = 0; | -- ^ borrowed value does not live long enough | | | value captured here @@ -155,18 +155,18 @@ LL | f.use_ref(); | - borrow later used here error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/closure-borrow-spans.rs:95:5 + --> $DIR/closure-borrow-spans.rs:93:5 | LL | let f = || *x = 0; | -- - borrow occurs due to use in closure | | | borrow of `*x` occurs here -LL | *x = 1; //~ ERROR +LL | *x = 1; | ^^^^^^ assignment to borrowed `*x` occurs here LL | f.use_ref(); | - borrow later used here error: aborting due to 14 previous errors -Some errors occurred: E0499, E0501, E0502, E0503, E0505, E0506, E0597. +Some errors have detailed explanations: E0499, E0501, E0502, E0503, E0505, E0506, E0597. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/nll/closure-captures.rs b/src/test/ui/nll/closure-captures.rs index 3a01f86cad890..16d90b971745a 100644 --- a/src/test/ui/nll/closure-captures.rs +++ b/src/test/ui/nll/closure-captures.rs @@ -1,8 +1,5 @@ // Some cases with closures that might be problems -#![allow(unused)] -#![feature(nll)] - // Should have one error per assignment fn one_closure(x: i32) { diff --git a/src/test/ui/nll/closure-captures.stderr b/src/test/ui/nll/closure-captures.stderr index cdc055f2a37a0..77f7d815eeb4c 100644 --- a/src/test/ui/nll/closure-captures.stderr +++ b/src/test/ui/nll/closure-captures.stderr @@ -1,160 +1,159 @@ error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/closure-captures.rs:10:5 + --> $DIR/closure-captures.rs:7:5 | LL | fn one_closure(x: i32) { | - help: consider changing this to be mutable: `mut x` LL | || -LL | x = 1; //~ ERROR +LL | x = 1; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/closure-captures.rs:12:5 + --> $DIR/closure-captures.rs:9:5 | LL | fn one_closure(x: i32) { | - help: consider changing this to be mutable: `mut x` ... -LL | x = 1; //~ ERROR +LL | x = 1; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/closure-captures.rs:18:9 + --> $DIR/closure-captures.rs:15:9 | LL | fn two_closures(x: i32) { | - help: consider changing this to be mutable: `mut x` ... -LL | x = 1; //~ ERROR +LL | x = 1; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/closure-captures.rs:22:9 + --> $DIR/closure-captures.rs:19:9 | LL | fn two_closures(x: i32) { | - help: consider changing this to be mutable: `mut x` ... -LL | x = 1; //~ ERROR +LL | x = 1; | ^^^^^ cannot assign error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/closure-captures.rs:30:9 + --> $DIR/closure-captures.rs:27:9 | -LL | || //~ ERROR +LL | || | ^^ cannot borrow as mutable LL | x = 1;} | - mutable borrow occurs due to use of `x` in closure | help: consider changing this to accept closures that implement `FnMut` - --> $DIR/closure-captures.rs:29:12 + --> $DIR/closure-captures.rs:26:12 | LL | fn_ref(|| { | ____________^ -LL | | || //~ ERROR +LL | | || LL | | x = 1;} | |________________^ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/closure-captures.rs:34:9 + --> $DIR/closure-captures.rs:31:9 | -LL | || //~ ERROR +LL | || | ^^ cannot borrow as mutable LL | x = 1;}); | - mutable borrow occurs due to use of `x` in closure | help: consider changing this to accept closures that implement `FnMut` - --> $DIR/closure-captures.rs:33:12 + --> $DIR/closure-captures.rs:30:12 | LL | fn_ref(move || { | ____________^ -LL | | || //~ ERROR +LL | | || LL | | x = 1;}); | |___________^ error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/closure-captures.rs:42:10 + --> $DIR/closure-captures.rs:39:10 | LL | fn two_closures_ref(x: i32) { | - help: consider changing this to be mutable: `mut x` ... -LL | x = 1;} //~ ERROR +LL | x = 1;} | ^^^^^ cannot assign error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/closure-captures.rs:41:9 + --> $DIR/closure-captures.rs:38:9 | -LL | || //~ ERROR +LL | || | ^^ cannot borrow as mutable -LL | x = 1;} //~ ERROR +LL | x = 1;} | - mutable borrow occurs due to use of `x` in closure | help: consider changing this to accept closures that implement `FnMut` - --> $DIR/closure-captures.rs:40:12 + --> $DIR/closure-captures.rs:37:12 | LL | fn_ref(|| { | ____________^ -LL | | || //~ ERROR -LL | | x = 1;} //~ ERROR +LL | | || +LL | | x = 1;} | |________________^ error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/closure-captures.rs:46:5 + --> $DIR/closure-captures.rs:43:5 | LL | fn two_closures_ref(x: i32) { | - help: consider changing this to be mutable: `mut x` ... -LL | x = 1;}); //~ ERROR +LL | x = 1;}); | ^^^^^ cannot assign error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/closure-captures.rs:45:9 + --> $DIR/closure-captures.rs:42:9 | -LL | || //~ ERROR +LL | || | ^^ cannot borrow as mutable -LL | x = 1;}); //~ ERROR +LL | x = 1;}); | - mutable borrow occurs due to use of `x` in closure | help: consider changing this to accept closures that implement `FnMut` - --> $DIR/closure-captures.rs:44:12 + --> $DIR/closure-captures.rs:41:12 | LL | fn_ref(move || { | ____________^ -LL | | || //~ ERROR -LL | | x = 1;}); //~ ERROR +LL | | || +LL | | x = 1;}); | |___________^ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/closure-captures.rs:51:9 + --> $DIR/closure-captures.rs:48:9 | -LL | || //~ ERROR +LL | || | ^^ cannot borrow as mutable LL | *x = 1;}); | - mutable borrow occurs due to use of `x` in closure | help: consider changing this to accept closures that implement `FnMut` - --> $DIR/closure-captures.rs:50:12 + --> $DIR/closure-captures.rs:47:12 | LL | fn_ref(|| { | ____________^ -LL | | || //~ ERROR +LL | | || LL | | *x = 1;}); | |________________^ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/closure-captures.rs:54:9 + --> $DIR/closure-captures.rs:51:9 | -LL | || //~ ERROR +LL | || | ^^ cannot borrow as mutable LL | *x = 1;}); | - mutable borrow occurs due to use of `x` in closure | help: consider changing this to accept closures that implement `FnMut` - --> $DIR/closure-captures.rs:53:12 + --> $DIR/closure-captures.rs:50:12 | LL | fn_ref(move || { | ____________^ -LL | | || //~ ERROR +LL | | || LL | | *x = 1;}); | |________________^ error: aborting due to 12 previous errors -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/nll/closure-move-spans.rs b/src/test/ui/nll/closure-move-spans.rs index ffbfa9f8ae483..bf2431870a942 100644 --- a/src/test/ui/nll/closure-move-spans.rs +++ b/src/test/ui/nll/closure-move-spans.rs @@ -1,7 +1,5 @@ // check that moves due to a closure capture give a special note -#![feature(nll)] - fn move_after_move(x: String) { || x; let y = x; //~ ERROR diff --git a/src/test/ui/nll/closure-move-spans.stderr b/src/test/ui/nll/closure-move-spans.stderr index 6750c4047601a..972dbc6a61d08 100644 --- a/src/test/ui/nll/closure-move-spans.stderr +++ b/src/test/ui/nll/closure-move-spans.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `x` - --> $DIR/closure-move-spans.rs:7:13 + --> $DIR/closure-move-spans.rs:5:13 | LL | fn move_after_move(x: String) { | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait @@ -7,11 +7,11 @@ LL | || x; | -- - variable moved due to use in closure | | | value moved into closure here -LL | let y = x; //~ ERROR +LL | let y = x; | ^ value used here after move error[E0382]: borrow of moved value: `x` - --> $DIR/closure-move-spans.rs:12:13 + --> $DIR/closure-move-spans.rs:10:13 | LL | fn borrow_after_move(x: String) { | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait @@ -19,11 +19,11 @@ LL | || x; | -- - variable moved due to use in closure | | | value moved into closure here -LL | let y = &x; //~ ERROR +LL | let y = &x; | ^^ value borrowed here after move error[E0382]: borrow of moved value: `x` - --> $DIR/closure-move-spans.rs:17:13 + --> $DIR/closure-move-spans.rs:15:13 | LL | fn borrow_mut_after_move(mut x: String) { | ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait @@ -31,7 +31,7 @@ LL | || x; | -- - variable moved due to use in closure | | | value moved into closure here -LL | let y = &mut x; //~ ERROR +LL | let y = &mut x; | ^^^^^^ value borrowed here after move error: aborting due to 3 previous errors diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr index 8e407070342cf..cc5ffca10475e 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -4,9 +4,9 @@ note: No external requirements LL | let mut closure = expect_sig(|p, y| *p = y); | ^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:9 ~ escape_argument_callee[317d]::test[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:13 ~ escape_argument_callee[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) i32)) + for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) i32)), ] error: lifetime may not live long enough @@ -16,7 +16,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | - - ^^^^^^ assignment requires that `'1` must outlive `'2` | | | | | has type `&'1 i32` - | has type `&mut &'2 i32` + | has type `&'_#2r mut &'2 i32` note: No external requirements --> $DIR/escape-argument-callee.rs:20:1 @@ -30,7 +30,7 @@ LL | | deref(p); LL | | } | |_^ | - = note: defining type: DefId(0/0:3 ~ escape_argument_callee[317d]::test[0]) with substs [] + = note: defining type: DefId(0:12 ~ escape_argument_callee[317d]::test[0]) with substs [] error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index 9b66abc40f07d..fdf95b8acebfc 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -4,9 +4,9 @@ note: No external requirements LL | let mut closure = expect_sig(|p, y| *p = y); | ^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:9 ~ escape_argument[317d]::test[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:13 ~ escape_argument[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32)) + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) i32)), ] note: No external requirements @@ -21,14 +21,14 @@ LL | | deref(p); LL | | } | |_^ | - = note: defining type: DefId(0/0:3 ~ escape_argument[317d]::test[0]) with substs [] + = note: defining type: DefId(0:12 ~ escape_argument[317d]::test[0]) with substs [] error[E0597]: `y` does not live long enough --> $DIR/escape-argument.rs:27:25 | LL | closure(&mut p, &y); | ^^ borrowed value does not live long enough -LL | //~^ ERROR `y` does not live long enough [E0597] +LL | LL | } | - `y` dropped here while still borrowed LL | diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr index 8214ff1fcec18..186f25a3c89db 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -1,36 +1,36 @@ note: External requirements --> $DIR/escape-upvar-nested.rs:21:32 | -LL | let mut closure1 = || p = &y; //~ ERROR `y` does not live long enough [E0597] +LL | let mut closure1 = || p = &y; | ^^^^^^^^^ | - = note: defining type: DefId(0/1:10 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:14 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]::{{closure}}[0]) with closure substs [ i16, extern "rust-call" fn(()), - &'_#1r mut &'_#2r i32, - &'_#3r i32 + &'_#1r i32, + &'_#2r mut &'_#3r i32, ] = note: number of external vids: 4 - = note: where '_#3r: '_#2r + = note: where '_#1r: '_#3r note: External requirements --> $DIR/escape-upvar-nested.rs:20:27 | LL | let mut closure = || { | ___________________________^ -LL | | let mut closure1 = || p = &y; //~ ERROR `y` does not live long enough [E0597] +LL | | let mut closure1 = || p = &y; LL | | closure1(); LL | | }; | |_________^ | - = note: defining type: DefId(0/1:9 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:13 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, extern "rust-call" fn(()), - &'_#1r mut &'_#2r i32, - &'_#3r i32 + &'_#1r i32, + &'_#2r mut &'_#3r i32, ] = note: number of external vids: 4 - = note: where '_#3r: '_#2r + = note: where '_#1r: '_#3r note: No external requirements --> $DIR/escape-upvar-nested.rs:13:1 @@ -44,14 +44,14 @@ LL | | deref(p); LL | | } | |_^ | - = note: defining type: DefId(0/0:3 ~ escape_upvar_nested[317d]::test[0]) with substs [] + = note: defining type: DefId(0:12 ~ escape_upvar_nested[317d]::test[0]) with substs [] error[E0597]: `y` does not live long enough --> $DIR/escape-upvar-nested.rs:21:40 | LL | let mut closure = || { | -- value captured here -LL | let mut closure1 = || p = &y; //~ ERROR `y` does not live long enough [E0597] +LL | let mut closure1 = || p = &y; | ^ borrowed value does not live long enough ... LL | } diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr index 55ede6ed4aae9..0df2c0f69a71b 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -4,14 +4,14 @@ note: External requirements LL | let mut closure = || p = &y; | ^^^^^^^^^ | - = note: defining type: DefId(0/1:9 ~ escape_upvar_ref[317d]::test[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:13 ~ escape_upvar_ref[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, extern "rust-call" fn(()), - &'_#1r mut &'_#2r i32, - &'_#3r i32 + &'_#1r i32, + &'_#2r mut &'_#3r i32, ] = note: number of external vids: 4 - = note: where '_#3r: '_#2r + = note: where '_#1r: '_#3r note: No external requirements --> $DIR/escape-upvar-ref.rs:17:1 @@ -25,7 +25,7 @@ LL | | deref(p); LL | | } | |_^ | - = note: defining type: DefId(0/0:3 ~ escape_upvar_ref[317d]::test[0]) with substs [] + = note: defining type: DefId(0:12 ~ escape_upvar_ref[317d]::test[0]) with substs [] error[E0597]: `y` does not live long enough --> $DIR/escape-upvar-ref.rs:23:35 diff --git a/src/test/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs b/src/test/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs index 71d5d4053ee25..8ed6554877eae 100644 --- a/src/test/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs +++ b/src/test/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs @@ -1,7 +1,3 @@ -// revisions: migrate nll -//[migrate]compile-flags: -Z borrowck=migrate -#![cfg_attr(nll, feature(nll))] - // compile-pass // Test that we propagate region relations from closures precisely when there is diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index 55e4573e60bbb..8916fdcfc88f1 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -4,13 +4,13 @@ note: No external requirements LL | / |_outlives1, _outlives2, _outlives3, x, y| { LL | | // Only works if 'x: 'y: LL | | let p = x.get(); -LL | | demand_y(x, y, p) //~ ERROR +LL | | demand_y(x, y, p) LL | | }, | |_________^ | - = note: defining type: DefId(0/1:20 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:27 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)) + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>)), ] = note: late-bound region is '_#4r = note: late-bound region is '_#5r @@ -20,11 +20,11 @@ error: lifetime may not live long enough --> $DIR/propagate-approximated-fail-no-postdom.rs:46:13 | LL | |_outlives1, _outlives2, _outlives3, x, y| { - | ---------- ---------- has type `std::cell::Cell<&'2 &u32>` + | ---------- ---------- has type `std::cell::Cell<&'2 &'_#3r u32>` | | - | has type `std::cell::Cell<&&'1 u32>` + | has type `std::cell::Cell<&'_#1r &'1 u32>` ... -LL | demand_y(x, y, p) //~ ERROR +LL | demand_y(x, y, p) | ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` note: No external requirements @@ -39,7 +39,7 @@ LL | | ); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:23 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]) with substs [] error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr index 5863b9bc84094..fa8384311ea57 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -5,13 +5,13 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, | _______________________________________________^ LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) -LL | | //~^ ERROR lifetime may not live long enough +LL | | LL | | }); | |_____^ | - = note: defining type: DefId(0/1:18 ~ propagate_approximated_ref[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:25 ~ propagate_approximated_ref[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>)) + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r @@ -25,12 +25,12 @@ LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { LL | | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) -LL | | //~^ ERROR lifetime may not live long enough +LL | | LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_approximated_ref[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:22 ~ propagate_approximated_ref[317d]::supply[0]) with substs [] error: lifetime may not live long enough --> $DIR/propagate-approximated-ref.rs:45:9 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index a9aeee8a3190c..cfaa75b8ef861 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -4,13 +4,13 @@ note: No external requirements LL | foo(cell, |cell_a, cell_x| { | _______________^ LL | | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure -LL | | //~^ ERROR +LL | | LL | | }) | |_____^ | - = note: defining type: DefId(0/1:12 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:18 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]::{{closure}}[0]) with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>)) + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>)), ] error[E0521]: borrowed data escapes outside of closure @@ -35,7 +35,7 @@ LL | | }) LL | | } | |_^ | - = note: defining type: DefId(0/0:5 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]) with substs [] + = note: defining type: DefId(0:17 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]) with substs [] note: External requirements --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:35:15 @@ -46,9 +46,9 @@ LL | | cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static LL | | }) | |_____^ | - = note: defining type: DefId(0/1:13 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:20 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]::{{closure}}[0]) with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>)) + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>)), ] = note: number of external vids: 2 = note: where '_#1r: '_#0r @@ -59,13 +59,13 @@ note: No external requirements LL | / fn case2() { LL | | let a = 0; LL | | let cell = Cell::new(&a); -LL | | //~^ ERROR `a` does not live long enough +LL | | ... | LL | | }) LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]) with substs [] + = note: defining type: DefId(0:19 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]) with substs [] error[E0597]: `a` does not live long enough --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:30:26 @@ -81,5 +81,4 @@ LL | } error: aborting due to 2 previous errors -Some errors occurred: E0521, E0597. -For more information about an error, try `rustc --explain E0521`. +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index daeb3b9ab5c55..601b3577e0eec 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -3,16 +3,16 @@ note: External requirements | LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { | _______________________________________________^ -LL | | //~^ ERROR borrowed data escapes outside of function +LL | | LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | }); | |_____^ | - = note: defining type: DefId(0/1:18 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:25 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) u32>)) + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) u32>)), ] = note: late-bound region is '_#2r = note: late-bound region is '_#3r @@ -24,14 +24,14 @@ note: No external requirements | LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { LL | | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { -LL | | //~^ ERROR borrowed data escapes outside of function +LL | | LL | | ... | LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:22 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]) with substs [] error[E0521]: borrowed data escapes outside of function --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:5 @@ -39,7 +39,7 @@ error[E0521]: borrowed data escapes outside of function LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { | ------ `cell_a` is a reference that is only valid in the function body LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { -LL | | //~^ ERROR borrowed data escapes outside of function +LL | | LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) @@ -48,4 +48,3 @@ LL | | }); error: aborting due to previous error -For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 95e5ce0ae74cd..5b5440e7a9641 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -3,16 +3,16 @@ note: External requirements | LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { | _______________________________________________^ -LL | | //~^ ERROR borrowed data escapes outside of function +LL | | LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | }); | |_____^ | - = note: defining type: DefId(0/1:18 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:25 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>)) + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r @@ -24,14 +24,14 @@ note: No external requirements | LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { LL | | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { -LL | | //~^ ERROR borrowed data escapes outside of function +LL | | LL | | ... | LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:22 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]) with substs [] error[E0521]: borrowed data escapes outside of function --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:5 @@ -39,7 +39,7 @@ error[E0521]: borrowed data escapes outside of function LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { | ------ `cell_a` is a reference that is only valid in the function body LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { -LL | | //~^ ERROR borrowed data escapes outside of function +LL | | LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) @@ -48,4 +48,3 @@ LL | | }); error: aborting due to previous error -For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr index b6d9d8529cf5c..a08cde2c9c635 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -5,13 +5,13 @@ LL | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| | _____________________________________________^ LL | | // Only works if 'x: 'y: LL | | demand_y(outlives1, outlives2, x.get()) -LL | | //~^ ERROR lifetime may not live long enough +LL | | LL | | }); | |_____^ | - = note: defining type: DefId(0/1:18 ~ propagate_approximated_val[317d]::test[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:25 ~ propagate_approximated_val[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)) + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r @@ -25,12 +25,12 @@ LL | / fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { LL | | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| { LL | | // Only works if 'x: 'y: LL | | demand_y(outlives1, outlives2, x.get()) -LL | | //~^ ERROR lifetime may not live long enough +LL | | LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_approximated_val[317d]::test[0]) with substs [] + = note: defining type: DefId(0:22 ~ propagate_approximated_val[317d]::test[0]) with substs [] error: lifetime may not live long enough --> $DIR/propagate-approximated-val.rs:38:9 diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr index 79f0df9a6888e..60847bb2e9290 100644 --- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr @@ -8,9 +8,9 @@ LL | | demand_y(x, y, p) LL | | }, | |_________^ | - = note: defining type: DefId(0/1:16 ~ propagate_despite_same_free_region[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:23 ~ propagate_despite_same_free_region[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)) + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>)), ] = note: late-bound region is '_#3r = note: number of external vids: 4 @@ -28,5 +28,5 @@ LL | | ); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_despite_same_free_region[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:21 ~ propagate_despite_same_free_region[317d]::supply[0]) with substs [] diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 93eb93bdc0638..a660c763bff78 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -5,13 +5,13 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { | _______________________________________________^ LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) -LL | | //~^ ERROR +LL | | LL | | }); | |_____^ | - = note: defining type: DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:25 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)) + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>)), ] = note: late-bound region is '_#2r = note: late-bound region is '_#3r @@ -20,9 +20,9 @@ error: lifetime may not live long enough --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:37:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { - | --------- - has type `&std::cell::Cell<&'1 u32>` + | --------- - has type `&'_#7r std::cell::Cell<&'1 u32>` | | - | has type `&std::cell::Cell<&'2 &u32>` + | has type `&'_#5r std::cell::Cell<&'2 &'_#1r u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` @@ -34,12 +34,12 @@ LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { LL | | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) -LL | | //~^ ERROR +LL | | LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:22 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]) with substs [] error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index c7809de88b922..9671b8ebff3a4 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -5,13 +5,13 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, | _______________________________________________^ LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) -LL | | //~^ ERROR +LL | | LL | | }); | |_____^ | - = note: defining type: DefId(0/1:18 ~ propagate_fail_to_approximate_longer_wrong_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:25 ~ propagate_fail_to_approximate_longer_wrong_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>)) + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r @@ -20,9 +20,9 @@ error: lifetime may not live long enough --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:41:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - | ---------- ---------- has type `&std::cell::Cell<&'2 &u32>` + | ---------- ---------- has type `&'_#8r std::cell::Cell<&'2 &'_#2r u32>` | | - | has type `&std::cell::Cell<&'1 &u32>` + | has type `&'_#6r std::cell::Cell<&'1 &'_#1r u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` @@ -34,12 +34,12 @@ LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { LL | | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) -LL | | //~^ ERROR +LL | | LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_fail_to_approximate_longer_wrong_bounds[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:22 ~ propagate_fail_to_approximate_longer_wrong_bounds[317d]::supply[0]) with substs [] error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr index 3bcd8e1e2568c..457b5950b7ff0 100644 --- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr @@ -3,7 +3,7 @@ note: External requirements | LL | establish_relationships(value, |value| { | ____________________________________^ -LL | | //~^ ERROR the parameter type `T` may not live long enough +LL | | LL | | LL | | // This function call requires that ... | @@ -11,11 +11,11 @@ LL | | require(value); LL | | }); | |_____^ | - = note: defining type: DefId(0/1:16 ~ propagate_from_trait_match[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:23 ~ propagate_from_trait_match[317d]::supply[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, - extern "rust-call" fn((T,)) + extern "rust-call" fn((T,)), ] = note: number of external vids: 2 = note: where T: '_#1r @@ -32,9 +32,9 @@ LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_from_trait_match[317d]::supply[0]) with substs [ + = note: defining type: DefId(0:20 ~ propagate_from_trait_match[317d]::supply[0]) with substs [ '_#1r, - T + T, ] error[E0309]: the parameter type `T` may not live long enough @@ -42,7 +42,7 @@ error[E0309]: the parameter type `T` may not live long enough | LL | establish_relationships(value, |value| { | ____________________________________^ -LL | | //~^ ERROR the parameter type `T` may not live long enough +LL | | LL | | LL | | // This function call requires that ... | diff --git a/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.rs b/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.rs index dbc659b4aeef9..a9d2a07715d49 100644 --- a/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.rs +++ b/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.rs @@ -1,8 +1,6 @@ // Test that we propagate *all* requirements to the caller, not just the first // one. -#![feature(nll)] - fn once U>(f: F, s: S, t: T) -> U { f(s, t) } diff --git a/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.stderr b/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.stderr index 2ad4577869a55..2fec9bc62d1c7 100644 --- a/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.stderr @@ -1,12 +1,12 @@ error[E0597]: `local_arr` does not live long enough - --> $DIR/propagate-multiple-requirements.rs:17:14 + --> $DIR/propagate-multiple-requirements.rs:15:14 | LL | let mut out: &mut &'static [i32] = &mut (&[1] as _); | ------------------- type annotation requires that `local_arr` is borrowed for `'static` LL | once(|mut z: &[i32], mut out_val: &mut &[i32]| { | ----------------------------------------- value captured here ... -LL | z = &local_arr; //~ ERROR +LL | z = &local_arr; | ^^^^^^^^^ borrowed value does not live long enough ... LL | } diff --git a/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs b/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs index 66290f2ff230a..a558e8a1813fd 100644 --- a/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs +++ b/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs @@ -1,13 +1,11 @@ // Basic test for free regions in the NLL code. This test does not // report an error because of the (implied) bound that `'b: 'a`. +// check-pass // compile-flags:-Zborrowck=mir -Zverbose -// compile-pass - -#![allow(warnings)] fn foo<'a, 'b>(x: &'a &'b u32) -> &'a u32 { &**x } -fn main() { } +fn main() {} diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr index 4a035d0c9cd83..8aff6d5b89279 100644 --- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr @@ -4,9 +4,9 @@ note: No external requirements LL | expect_sig(|a, b| b); // ought to return `a` | ^^^^^^^^ | - = note: defining type: DefId(0/1:9 ~ return_wrong_bound_region[317d]::test[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:13 ~ return_wrong_bound_region[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) i32 + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) i32, ] error: lifetime may not live long enough @@ -23,11 +23,11 @@ note: No external requirements | LL | / fn test() { LL | | expect_sig(|a, b| b); // ought to return `a` -LL | | //~^ ERROR +LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:3 ~ return_wrong_bound_region[317d]::test[0]) with substs [] + = note: defining type: DefId(0:12 ~ return_wrong_bound_region[317d]::test[0]) with substs [] error: aborting due to previous error diff --git a/src/test/ui/nll/closure-use-spans.rs b/src/test/ui/nll/closure-use-spans.rs index c7cd519cffbce..6768250dcbc0a 100644 --- a/src/test/ui/nll/closure-use-spans.rs +++ b/src/test/ui/nll/closure-use-spans.rs @@ -1,7 +1,5 @@ // check that liveness due to a closure capture gives a special note -#![feature(nll)] - fn use_as_borrow_capture(mut x: i32) { let y = &x; x = 0; //~ ERROR diff --git a/src/test/ui/nll/closure-use-spans.stderr b/src/test/ui/nll/closure-use-spans.stderr index b2abfcacd0ea4..ec7e0f308557d 100644 --- a/src/test/ui/nll/closure-use-spans.stderr +++ b/src/test/ui/nll/closure-use-spans.stderr @@ -1,29 +1,29 @@ error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/closure-use-spans.rs:7:5 + --> $DIR/closure-use-spans.rs:5:5 | LL | let y = &x; | -- borrow of `x` occurs here -LL | x = 0; //~ ERROR +LL | x = 0; | ^^^^^ assignment to borrowed `x` occurs here LL | || *y; | - borrow later captured here by closure error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/closure-use-spans.rs:13:5 + --> $DIR/closure-use-spans.rs:11:5 | LL | let y = &mut x; | ------ borrow of `x` occurs here -LL | x = 0; //~ ERROR +LL | x = 0; | ^^^^^ assignment to borrowed `x` occurs here LL | || *y = 1; | - borrow later captured here by closure error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/closure-use-spans.rs:19:5 + --> $DIR/closure-use-spans.rs:17:5 | LL | let y = &x; | -- borrow of `x` occurs here -LL | x = 0; //~ ERROR +LL | x = 0; | ^^^^^ assignment to borrowed `x` occurs here LL | move || *y; | - borrow later captured here by closure diff --git a/src/test/ui/nll/closures-in-loops.rs b/src/test/ui/nll/closures-in-loops.rs index d2afa564734c8..491c186ecb5a0 100644 --- a/src/test/ui/nll/closures-in-loops.rs +++ b/src/test/ui/nll/closures-in-loops.rs @@ -1,8 +1,6 @@ // Test messages where a closure capture conflicts with itself because it's in // a loop. -#![feature(nll)] - fn repreated_move(x: String) { for i in 0..10 { || x; //~ ERROR diff --git a/src/test/ui/nll/closures-in-loops.stderr b/src/test/ui/nll/closures-in-loops.stderr index 6c9e1639f88dd..7603f9650b54a 100644 --- a/src/test/ui/nll/closures-in-loops.stderr +++ b/src/test/ui/nll/closures-in-loops.stderr @@ -1,31 +1,31 @@ error[E0382]: use of moved value: `x` - --> $DIR/closures-in-loops.rs:8:9 + --> $DIR/closures-in-loops.rs:6:9 | LL | fn repreated_move(x: String) { | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait LL | for i in 0..10 { -LL | || x; //~ ERROR +LL | || x; | ^^ - use occurs due to use in closure | | | value moved into closure here, in previous iteration of loop error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/closures-in-loops.rs:15:16 + --> $DIR/closures-in-loops.rs:13:16 | -LL | v.push(|| x = String::new()); //~ ERROR +LL | v.push(|| x = String::new()); | ^^ - borrows occur due to use of `x` in closure | | | mutable borrow starts here in previous iteration of loop error[E0524]: two closures require unique access to `x` at the same time - --> $DIR/closures-in-loops.rs:22:16 + --> $DIR/closures-in-loops.rs:20:16 | -LL | v.push(|| *x = String::new()); //~ ERROR +LL | v.push(|| *x = String::new()); | ^^ - borrows occur due to use of `x` in closure | | | closures are constructed here in different iterations of loop error: aborting due to 3 previous errors -Some errors occurred: E0382, E0499, E0524. +Some errors have detailed explanations: E0382, E0499. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/nll/constant-thread-locals-issue-47053.rs b/src/test/ui/nll/constant-thread-locals-issue-47053.rs index 4dd01410c5e4d..dde0ef7a5bb83 100644 --- a/src/test/ui/nll/constant-thread-locals-issue-47053.rs +++ b/src/test/ui/nll/constant-thread-locals-issue-47053.rs @@ -1,6 +1,5 @@ // Regression test for issue #47053 -#![feature(nll)] #![feature(thread_local)] #[thread_local] diff --git a/src/test/ui/nll/constant-thread-locals-issue-47053.stderr b/src/test/ui/nll/constant-thread-locals-issue-47053.stderr index 77cffbfa72d26..8afb42d66a61a 100644 --- a/src/test/ui/nll/constant-thread-locals-issue-47053.stderr +++ b/src/test/ui/nll/constant-thread-locals-issue-47053.stderr @@ -1,9 +1,8 @@ error[E0594]: cannot assign to immutable static item `FOO` - --> $DIR/constant-thread-locals-issue-47053.rs:10:5 + --> $DIR/constant-thread-locals-issue-47053.rs:9:5 | -LL | FOO = 6; //~ ERROR cannot assign to immutable static item `FOO` [E0594] +LL | FOO = 6; | ^^^^^^^ cannot assign error: aborting due to previous error -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/nll/decl-macro-illegal-copy.rs b/src/test/ui/nll/decl-macro-illegal-copy.rs index 38bdb7dd270f8..f7243294669a6 100644 --- a/src/test/ui/nll/decl-macro-illegal-copy.rs +++ b/src/test/ui/nll/decl-macro-illegal-copy.rs @@ -1,6 +1,5 @@ // Regression test for #46314 -#![feature(nll)] #![feature(decl_macro)] struct NonCopy(String); diff --git a/src/test/ui/nll/decl-macro-illegal-copy.stderr b/src/test/ui/nll/decl-macro-illegal-copy.stderr index 9232ff52393e1..7948485bd6866 100644 --- a/src/test/ui/nll/decl-macro-illegal-copy.stderr +++ b/src/test/ui/nll/decl-macro-illegal-copy.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `wrapper.inner` - --> $DIR/decl-macro-illegal-copy.rs:22:9 + --> $DIR/decl-macro-illegal-copy.rs:21:9 | LL | $wrapper.inner | -------------- value moved here diff --git a/src/test/ui/nll/do-not-ignore-lifetime-bounds-in-copy.stderr b/src/test/ui/nll/do-not-ignore-lifetime-bounds-in-copy.stderr index db5a549106bf2..bf5c571b455b3 100644 --- a/src/test/ui/nll/do-not-ignore-lifetime-bounds-in-copy.stderr +++ b/src/test/ui/nll/do-not-ignore-lifetime-bounds-in-copy.stderr @@ -1,7 +1,7 @@ error[E0597]: `s` does not live long enough --> $DIR/do-not-ignore-lifetime-bounds-in-copy.rs:10:17 | -LL | let a = Foo(&s); //~ ERROR `s` does not live long enough [E0597] +LL | let a = Foo(&s); | ^^ borrowed value does not live long enough LL | drop(a); | - copying this value requires that `s` is borrowed for `'static` diff --git a/src/test/ui/nll/dont-print-desugared.rs b/src/test/ui/nll/dont-print-desugared.rs new file mode 100644 index 0000000000000..829d78ed4c3ba --- /dev/null +++ b/src/test/ui/nll/dont-print-desugared.rs @@ -0,0 +1,21 @@ +// Test that we don't show variables with from for loop desugaring + +fn for_loop(s: &[i32]) { + for &ref mut x in s {} + //~^ ERROR cannot borrow data in a `&` reference as mutable [E0596] +} + +struct D<'a>(&'a ()); + +impl Drop for D<'_> { + fn drop(&mut self) {} +} + +fn for_loop_dropck(v: Vec>) { + for ref mut d in v { + let y = (); + *d = D(&y); //~ ERROR `y` does not live long enough + } +} + +fn main() {} diff --git a/src/test/ui/nll/dont-print-desugared.stderr b/src/test/ui/nll/dont-print-desugared.stderr new file mode 100644 index 0000000000000..45d7cbcdfbe7f --- /dev/null +++ b/src/test/ui/nll/dont-print-desugared.stderr @@ -0,0 +1,27 @@ +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/dont-print-desugared.rs:4:10 + | +LL | for &ref mut x in s {} + | -^^^^^^^^^ + | || + | |cannot borrow as mutable through `&` reference + | help: consider changing this to be a mutable reference: `&mut ref mut x` + +error[E0597]: `y` does not live long enough + --> $DIR/dont-print-desugared.rs:17:16 + | +LL | for ref mut d in v { + | - a temporary with access to the borrow is created here ... +LL | let y = (); +LL | *d = D(&y); + | ^^ borrowed value does not live long enough +LL | } + | - + | | + | `y` dropped here while still borrowed + | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0596, E0597. +For more information about an error, try `rustc --explain E0596`. diff --git a/src/test/ui/nll/drop-no-may-dangle.stderr b/src/test/ui/nll/drop-no-may-dangle.stderr index efa825be295f2..e1d2b038ec8be 100644 --- a/src/test/ui/nll/drop-no-may-dangle.stderr +++ b/src/test/ui/nll/drop-no-may-dangle.stderr @@ -4,7 +4,7 @@ error[E0506]: cannot assign to `v[_]` because it is borrowed LL | let p: WrapMayNotDangle<&usize> = WrapMayNotDangle { value: &v[0] }; | ----- borrow of `v[_]` occurs here ... -LL | v[0] += 1; //~ ERROR cannot assign to `v[_]` because it is borrowed +LL | v[0] += 1; | ^^^^^^^^^ assignment to borrowed `v[_]` occurs here ... LL | } @@ -16,7 +16,7 @@ error[E0506]: cannot assign to `v[_]` because it is borrowed LL | let p: WrapMayNotDangle<&usize> = WrapMayNotDangle { value: &v[0] }; | ----- borrow of `v[_]` occurs here ... -LL | v[0] += 1; //~ ERROR cannot assign to `v[_]` because it is borrowed +LL | v[0] += 1; | ^^^^^^^^^ assignment to borrowed `v[_]` occurs here LL | } | - borrow might be used here, when `p` is dropped and runs the `Drop` code for type `WrapMayNotDangle` diff --git a/src/test/ui/nll/empty-type-predicate.rs b/src/test/ui/nll/empty-type-predicate.rs new file mode 100644 index 0000000000000..75431d40ce542 --- /dev/null +++ b/src/test/ui/nll/empty-type-predicate.rs @@ -0,0 +1,11 @@ +// Regression test for #61315 +// +// `dyn T:` is lowered to `dyn T: ReEmpty` - check that we don't ICE in NLL for +// the unexpected region. + +// compile-pass + +trait T {} +fn f() where dyn T: {} + +fn main() {} diff --git a/src/test/ui/nll/enum-drop-access.stderr b/src/test/ui/nll/enum-drop-access.stderr index da9c96f7bc2e8..699179fd52fd4 100644 --- a/src/test/ui/nll/enum-drop-access.stderr +++ b/src/test/ui/nll/enum-drop-access.stderr @@ -4,7 +4,7 @@ error[E0713]: borrow may still be in use when destructor runs LL | fn drop_enum(opt: DropOption<&mut i32>) -> Option<&mut i32> { | - let's call the lifetime of this reference `'1` LL | match opt { -LL | DropOption::Some(&mut ref mut r) => { //~ ERROR +LL | DropOption::Some(&mut ref mut r) => { | ^^^^^^^^^ LL | Some(r) | ------- returning this value requires that `*opt.0` is borrowed for `'1` @@ -18,7 +18,7 @@ error[E0713]: borrow may still be in use when destructor runs LL | fn optional_drop_enum(opt: Option>) -> Option<&mut i32> { | - let's call the lifetime of this reference `'1` LL | match opt { -LL | Some(DropOption::Some(&mut ref mut r)) => { //~ ERROR +LL | Some(DropOption::Some(&mut ref mut r)) => { | ^^^^^^^^^ LL | Some(r) | ------- returning this value requires that `*opt.0.0` is borrowed for `'1` diff --git a/src/test/ui/nll/extra-unused-mut.rs b/src/test/ui/nll/extra-unused-mut.rs index d5f0b0ddf18bf..6d0d6e16a6775 100644 --- a/src/test/ui/nll/extra-unused-mut.rs +++ b/src/test/ui/nll/extra-unused-mut.rs @@ -1,6 +1,6 @@ // extra unused mut lint tests for #51918 -// run-pass +// compile-pass #![feature(generators, nll)] #![deny(unused_mut)] @@ -53,11 +53,14 @@ fn if_guard(x: Result) { } } -fn main() { - ref_argument(0); - mutable_upvar(); - generator_mutable_upvar(); - ref_closure_argument(); - parse_dot_or_call_expr_with(Vec::new()); - if_guard(Ok(0)); +// #59620 +fn nested_closures() { + let mut i = 0; + [].iter().for_each(|_: &i32| { + [].iter().for_each(move |_: &i32| { + i += 1; + }); + }); } + +fn main() {} diff --git a/src/test/ui/nll/generator-upvar-mutability.stderr b/src/test/ui/nll/generator-upvar-mutability.stderr index 31b061b61d19d..1b4e5b89984e7 100644 --- a/src/test/ui/nll/generator-upvar-mutability.stderr +++ b/src/test/ui/nll/generator-upvar-mutability.stderr @@ -9,4 +9,3 @@ LL | x = 1; error: aborting due to previous error -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/nll/get_default.nll.stderr b/src/test/ui/nll/get_default.nll.stderr index 0f71452805db0..279123069877f 100644 --- a/src/test/ui/nll/get_default.nll.stderr +++ b/src/test/ui/nll/get_default.nll.stderr @@ -1,41 +1,5 @@ -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:23:17 - | -LL | match map.get() { - | --- immutable borrow occurs here -... -LL | map.set(String::new()); // Ideally, this would not error. - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:35:17 - | -LL | match map.get() { - | --- immutable borrow occurs here -LL | Some(v) => { -LL | map.set(String::new()); // Both AST and MIR error here - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:41:17 - | -LL | match map.get() { - | --- immutable borrow occurs here -... -LL | map.set(String::new()); // Ideally, just AST would error here - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/get_default.rs:23:17 +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable + --> $DIR/get_default.rs:21:17 | LL | fn ok(map: &mut Map) -> &String { | - let's call the lifetime of this reference `'1` @@ -47,10 +11,10 @@ LL | return v; | - returning this value requires that `*map` is borrowed for `'1` ... LL | map.set(String::new()); // Ideally, this would not error. - | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^^^ mutable borrow occurs here -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/get_default.rs:35:17 +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable + --> $DIR/get_default.rs:32:17 | LL | fn err(map: &mut Map) -> &String { | - let's call the lifetime of this reference `'1` @@ -59,13 +23,13 @@ LL | match map.get() { | --- immutable borrow occurs here LL | Some(v) => { LL | map.set(String::new()); // Both AST and MIR error here - | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here -... + | ^^^ mutable borrow occurs here +LL | LL | return v; | - returning this value requires that `*map` is borrowed for `'1` -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/get_default.rs:41:17 +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable + --> $DIR/get_default.rs:37:17 | LL | fn err(map: &mut Map) -> &String { | - let's call the lifetime of this reference `'1` @@ -77,8 +41,8 @@ LL | return v; | - returning this value requires that `*map` is borrowed for `'1` ... LL | map.set(String::new()); // Ideally, just AST would error here - | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^^^ mutable borrow occurs here -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/nll/get_default.rs b/src/test/ui/nll/get_default.rs index 89f693bfb654e..ffac8a33da104 100644 --- a/src/test/ui/nll/get_default.rs +++ b/src/test/ui/nll/get_default.rs @@ -3,8 +3,6 @@ // a variety of errors from the older, AST-based machinery (notably // borrowck), and then we get the NLL error at the end. -// compile-flags:-Zborrowck=compare - struct Map { } @@ -21,8 +19,7 @@ fn ok(map: &mut Map) -> &String { } None => { map.set(String::new()); // Ideally, this would not error. - //~^ ERROR borrowed as immutable (Ast) - //~| ERROR borrowed as immutable (Mir) + //~^ ERROR borrowed as immutable } } } @@ -33,14 +30,12 @@ fn err(map: &mut Map) -> &String { match map.get() { Some(v) => { map.set(String::new()); // Both AST and MIR error here - //~^ ERROR borrowed as immutable (Mir) - //~| ERROR borrowed as immutable (Ast) + //~^ ERROR borrowed as immutable return v; } None => { map.set(String::new()); // Ideally, just AST would error here - //~^ ERROR borrowed as immutable (Ast) - //~| ERROR borrowed as immutable (Mir) + //~^ ERROR borrowed as immutable } } } diff --git a/src/test/ui/nll/get_default.stderr b/src/test/ui/nll/get_default.stderr index abb5343845b57..af79771e7e1b9 100644 --- a/src/test/ui/nll/get_default.stderr +++ b/src/test/ui/nll/get_default.stderr @@ -1,41 +1,5 @@ -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:23:17 - | -LL | match map.get() { - | --- immutable borrow occurs here -... -LL | map.set(String::new()); // Ideally, this would not error. - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:35:17 - | -LL | match map.get() { - | --- immutable borrow occurs here -LL | Some(v) => { -LL | map.set(String::new()); // Both AST and MIR error here - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:41:17 - | -LL | match map.get() { - | --- immutable borrow occurs here -... -LL | map.set(String::new()); // Ideally, just AST would error here - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/get_default.rs:23:17 +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable + --> $DIR/get_default.rs:21:17 | LL | fn ok(map: &mut Map) -> &String { | - let's call the lifetime of this reference `'1` @@ -47,10 +11,10 @@ LL | return v; | - returning this value requires that `*map` is borrowed for `'1` ... LL | map.set(String::new()); // Ideally, this would not error. - | ^^^ mutable borrow occurs here + | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/get_default.rs:35:17 +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable + --> $DIR/get_default.rs:32:17 | LL | fn err(map: &mut Map) -> &String { | - let's call the lifetime of this reference `'1` @@ -59,13 +23,13 @@ LL | match map.get() { | --- immutable borrow occurs here LL | Some(v) => { LL | map.set(String::new()); // Both AST and MIR error here - | ^^^ mutable borrow occurs here -... + | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | LL | return v; | - returning this value requires that `*map` is borrowed for `'1` -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/get_default.rs:41:17 +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable + --> $DIR/get_default.rs:37:17 | LL | fn err(map: &mut Map) -> &String { | - let's call the lifetime of this reference `'1` @@ -77,8 +41,8 @@ LL | return v; | - returning this value requires that `*map` is borrowed for `'1` ... LL | map.set(String::new()); // Ideally, just AST would error here - | ^^^ mutable borrow occurs here + | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/nll/guarantor-issue-46974.stderr b/src/test/ui/nll/guarantor-issue-46974.stderr index b2ed4c8fcab7f..80df393598775 100644 --- a/src/test/ui/nll/guarantor-issue-46974.stderr +++ b/src/test/ui/nll/guarantor-issue-46974.stderr @@ -4,7 +4,7 @@ error[E0506]: cannot assign to `*s` because it is borrowed LL | let t = &mut *s; // this borrow should last for the entire function | ------- borrow of `*s` occurs here LL | let x = &t.0; -LL | *s = (2,); //~ ERROR cannot assign to `*s` +LL | *s = (2,); | ^^^^^^^^^ assignment to borrowed `*s` occurs here LL | *x | -- borrow later used here @@ -15,10 +15,10 @@ error[E0621]: explicit lifetime required in the type of `s` LL | fn bar(s: &Box<(i32,)>) -> &'static i32 { | ------------ help: add explicit lifetime `'static` to the type of `s`: `&'static std::boxed::Box<(i32,)>` LL | // FIXME(#46983): error message should be better -LL | &s.0 //~ ERROR explicit lifetime required in the type of `s` [E0621] +LL | &s.0 | ^^^^ lifetime `'static` required error: aborting due to 2 previous errors -Some errors occurred: E0506, E0621. +Some errors have detailed explanations: E0506, E0621. For more information about an error, try `rustc --explain E0506`. diff --git a/src/test/ui/nll/issue-16223.rs b/src/test/ui/nll/issue-16223.rs index 881e202acf8d3..e75362750645c 100644 --- a/src/test/ui/nll/issue-16223.rs +++ b/src/test/ui/nll/issue-16223.rs @@ -15,7 +15,6 @@ // compile-pass -#![feature(nll)] #![feature(box_patterns)] struct Root { diff --git a/src/test/ui/nll/issue-21114-ebfull.rs b/src/test/ui/nll/issue-21114-ebfull.rs index f5738968746ee..1fe4fffa324a6 100644 --- a/src/test/ui/nll/issue-21114-ebfull.rs +++ b/src/test/ui/nll/issue-21114-ebfull.rs @@ -1,6 +1,4 @@ -// (this works, but only in NLL) // compile-pass -#![feature(nll)] use std::collections::HashMap; use std::sync::Mutex; diff --git a/src/test/ui/nll/issue-21114-kixunil.rs b/src/test/ui/nll/issue-21114-kixunil.rs index 2add951b70bc0..80a85293e5a5c 100644 --- a/src/test/ui/nll/issue-21114-kixunil.rs +++ b/src/test/ui/nll/issue-21114-kixunil.rs @@ -1,6 +1,4 @@ -// (this works, but only in NLL) // compile-pass -#![feature(nll)] fn from_stdin(min: u64) -> Vec { use std::io::BufRead; diff --git a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs index abafd330573ee..906ea32b9c42d 100644 --- a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs +++ b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs @@ -8,8 +8,6 @@ // meant to compile and run successfully once rust-lang/rust#54987 is // implemented. -#![feature(nll)] - struct D { x: u32, s: S, diff --git a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr index 54c728e3d2783..153d9bdf3215d 100644 --- a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr +++ b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr @@ -1,17 +1,17 @@ error[E0381]: assign of possibly uninitialized variable: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:30:5 + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:28:5 | LL | d.x = 10; | ^^^^^^^^ use of possibly uninitialized `d` error[E0381]: assign of possibly uninitialized variable: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:36:5 + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:34:5 | LL | d.x = 10; | ^^^^^^^^ use of possibly uninitialized `d` error[E0382]: assign of moved value: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:43:5 + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:41:5 | LL | let mut d = D { x: 0, s: S{ y: 0, z: 0 } }; | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait @@ -21,19 +21,19 @@ LL | d.x = 10; | ^^^^^^^^ value assigned here after move error[E0381]: assign to part of possibly uninitialized variable: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:49:5 + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:47:5 | LL | d.s.y = 20; | ^^^^^^^^^^ use of possibly uninitialized `d.s` error[E0381]: assign to part of possibly uninitialized variable: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:55:5 + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:53:5 | LL | d.s.y = 20; | ^^^^^^^^^^ use of possibly uninitialized `d.s` error[E0382]: assign to part of moved value: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:62:5 + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:60:5 | LL | let mut d = D { x: 0, s: S{ y: 0, z: 0} }; | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait @@ -44,5 +44,5 @@ LL | d.s.y = 20; error: aborting due to 6 previous errors -Some errors occurred: E0381, E0382. +Some errors have detailed explanations: E0381, E0382. For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr index 23da533252cb9..1cdf728a5e604 100644 --- a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr +++ b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr @@ -158,7 +158,7 @@ LL | let mut c = (1, "".to_owned()); LL | match c { LL | c2 => { | -- value moved here -LL | c.0 = 2; //~ ERROR assign to part of moved value +LL | c.0 = 2; | ^^^^^^^ value partially assigned here after move error[E0382]: assign to part of moved value: `c` @@ -169,7 +169,7 @@ LL | let mut c = (1, (1, "".to_owned())); LL | match c { LL | c2 => { | -- value moved here -LL | (c.1).0 = 2; //~ ERROR assign to part of moved value +LL | (c.1).0 = 2; | ^^^^^^^^^^^ value partially assigned here after move error[E0382]: assign to part of moved value: `c.1` @@ -177,12 +177,12 @@ error[E0382]: assign to part of moved value: `c.1` | LL | c2 => { | -- value moved here -LL | ((c.1).1).0 = 3; //~ ERROR assign to part of moved value +LL | ((c.1).1).0 = 3; | ^^^^^^^^^^^^^^^ value partially assigned here after move | = note: move occurs because `c.1` has type `(i32, (i32, std::string::String))`, which does not implement the `Copy` trait error: aborting due to 23 previous errors -Some errors occurred: E0381, E0382. +Some errors have detailed explanations: E0381, E0382. For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/nll/issue-22323-temp-destruction.rs b/src/test/ui/nll/issue-22323-temp-destruction.rs index 2c547fb7c7da7..6357c3ccef1f8 100644 --- a/src/test/ui/nll/issue-22323-temp-destruction.rs +++ b/src/test/ui/nll/issue-22323-temp-destruction.rs @@ -3,8 +3,6 @@ // compile-pass -#![feature(nll)] - fn main() { let _s = construct().borrow().consume_borrowed(); } diff --git a/src/test/ui/nll/issue-27868.stderr b/src/test/ui/nll/issue-27868.stderr index 4cbd74fe272d4..c83cb0b300b25 100644 --- a/src/test/ui/nll/issue-27868.stderr +++ b/src/test/ui/nll/issue-27868.stderr @@ -8,7 +8,7 @@ LL | vecvec[0] += { | | LL | | vecvec = vec![]; | | ^^^^^^ assignment to borrowed `vecvec` occurs here -LL | | //~^ ERROR cannot assign to `vecvec` because it is borrowed [E0506] +LL | | LL | | 0 LL | | }; | |_____- borrow later used here diff --git a/src/test/ui/nll/issue-30104.rs b/src/test/ui/nll/issue-30104.rs index 88e49bf8df70d..27e519005f62b 100644 --- a/src/test/ui/nll/issue-30104.rs +++ b/src/test/ui/nll/issue-30104.rs @@ -2,8 +2,6 @@ // compile-pass -#![feature(nll)] - use std::ops::{Deref, DerefMut}; fn box_two_field(v: &mut Box<(i32, i32)>) { diff --git a/src/test/ui/nll/issue-31567.stderr b/src/test/ui/nll/issue-31567.stderr index c76365095df39..d098ff82d34f0 100644 --- a/src/test/ui/nll/issue-31567.stderr +++ b/src/test/ui/nll/issue-31567.stderr @@ -3,7 +3,7 @@ error[E0713]: borrow may still be in use when destructor runs | LL | fn get_dangling<'a>(v: VecWrapper<'a>) -> &'a u32 { | -- lifetime `'a` defined here -LL | let s_inner: &'a S = &*v.0; //~ ERROR borrow may still be in use when destructor runs [E0713] +LL | let s_inner: &'a S = &*v.0; | ----- ^^^^^ | | | type annotation requires that `*v.0` is borrowed for `'a` diff --git a/src/test/ui/nll/issue-32382-index-assoc-type-with-lifetime.rs b/src/test/ui/nll/issue-32382-index-assoc-type-with-lifetime.rs index a114d7092ecf9..7e0ffd6cf3644 100644 --- a/src/test/ui/nll/issue-32382-index-assoc-type-with-lifetime.rs +++ b/src/test/ui/nll/issue-32382-index-assoc-type-with-lifetime.rs @@ -1,4 +1,3 @@ -#![feature(nll)] // compile-pass // rust-lang/rust#32382: Borrow checker used to complain about diff --git a/src/test/ui/nll/issue-43058.rs b/src/test/ui/nll/issue-43058.rs index c5bae7a12d7e7..c50473511f116 100644 --- a/src/test/ui/nll/issue-43058.rs +++ b/src/test/ui/nll/issue-43058.rs @@ -1,7 +1,5 @@ // compile-pass -#![feature(nll)] - use std::borrow::Cow; #[derive(Clone, Debug)] diff --git a/src/test/ui/nll/issue-46589.rs b/src/test/ui/nll/issue-46589.rs index 690f6f269ebcd..8c0c356e96721 100644 --- a/src/test/ui/nll/issue-46589.rs +++ b/src/test/ui/nll/issue-46589.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - struct Foo; impl Foo { diff --git a/src/test/ui/nll/issue-46589.stderr b/src/test/ui/nll/issue-46589.stderr index 7b02b905303f1..397909a436610 100644 --- a/src/test/ui/nll/issue-46589.stderr +++ b/src/test/ui/nll/issue-46589.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `**other` as mutable more than once at a time - --> $DIR/issue-46589.rs:19:21 + --> $DIR/issue-46589.rs:17:21 | LL | *other = match (*other).get_self() { | -------- first mutable borrow occurs here diff --git a/src/test/ui/nll/issue-47022.rs b/src/test/ui/nll/issue-47022.rs index c0f8efa24981c..3f8e0f5ad3d7a 100644 --- a/src/test/ui/nll/issue-47022.rs +++ b/src/test/ui/nll/issue-47022.rs @@ -1,8 +1,5 @@ // compile-pass -#![allow(warnings)] -#![feature(nll)] - struct LoadedObject { bodies: Vec, color: Color, @@ -34,4 +31,3 @@ fn convert(objects: Vec) -> (Vec, Vec) { } fn main() {} - diff --git a/src/test/ui/nll/issue-47388.rs b/src/test/ui/nll/issue-47388.rs index df47baa3c17f0..207af380e62dd 100644 --- a/src/test/ui/nll/issue-47388.rs +++ b/src/test/ui/nll/issue-47388.rs @@ -1,4 +1,3 @@ -#![feature(nll)] struct FancyNum { num: u8, } diff --git a/src/test/ui/nll/issue-47388.stderr b/src/test/ui/nll/issue-47388.stderr index dda324c2e9890..d4064b3f50a34 100644 --- a/src/test/ui/nll/issue-47388.stderr +++ b/src/test/ui/nll/issue-47388.stderr @@ -1,11 +1,10 @@ error[E0594]: cannot assign to `fancy_ref.num` which is behind a `&` reference - --> $DIR/issue-47388.rs:9:5 + --> $DIR/issue-47388.rs:8:5 | LL | let fancy_ref = &(&mut fancy); | ------------- help: consider changing this to be a mutable reference: `&mut (&mut fancy)` -LL | fancy_ref.num = 6; //~ ERROR E0594 +LL | fancy_ref.num = 6; | ^^^^^^^^^^^^^^^^^ `fancy_ref` is a `&` reference, so the data it refers to cannot be written error: aborting due to previous error -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/nll/issue-47470.rs b/src/test/ui/nll/issue-47470.rs index 67150b46c3599..72ee7f88650e1 100644 --- a/src/test/ui/nll/issue-47470.rs +++ b/src/test/ui/nll/issue-47470.rs @@ -2,8 +2,6 @@ // causing region relations not to be enforced at all the places where // they have to be enforced. -#![feature(nll)] - struct Foo<'a>(&'a ()); trait Bar { type Assoc; diff --git a/src/test/ui/nll/issue-47470.stderr b/src/test/ui/nll/issue-47470.stderr index ff1f1e2c1f19a..0b1247d60ec67 100644 --- a/src/test/ui/nll/issue-47470.stderr +++ b/src/test/ui/nll/issue-47470.stderr @@ -1,7 +1,7 @@ error[E0515]: cannot return reference to local variable `local` - --> $DIR/issue-47470.rs:17:9 + --> $DIR/issue-47470.rs:15:9 | -LL | &local //~ ERROR cannot return reference to local variable `local` +LL | &local | ^^^^^^ returns a reference to data owned by the current function error: aborting due to previous error diff --git a/src/test/ui/nll/issue-48070.rs b/src/test/ui/nll/issue-48070.rs index c69bd3dbe90a5..47426cdfa57ef 100644 --- a/src/test/ui/nll/issue-48070.rs +++ b/src/test/ui/nll/issue-48070.rs @@ -1,8 +1,6 @@ // run-pass // revisions: lxl nll -#![cfg_attr(nll, feature(nll))] - struct Foo { x: u32 } diff --git a/src/test/ui/nll/issue-48238.stderr b/src/test/ui/nll/issue-48238.stderr index 7cb5eb736c0e3..05a90eec05c3f 100644 --- a/src/test/ui/nll/issue-48238.stderr +++ b/src/test/ui/nll/issue-48238.stderr @@ -1,7 +1,7 @@ error: lifetime may not live long enough --> $DIR/issue-48238.rs:11:13 | -LL | move || use_val(&orig); //~ ERROR +LL | move || use_val(&orig); | ------- ^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` | | | | | return type of closure is &'2 u8 diff --git a/src/test/ui/nll/issue-48697.rs b/src/test/ui/nll/issue-48697.rs index ececd6fccd84b..16e29ab2a8ad2 100644 --- a/src/test/ui/nll/issue-48697.rs +++ b/src/test/ui/nll/issue-48697.rs @@ -1,7 +1,5 @@ // Regression test for #48697 -#![feature(nll)] - fn foo(x: &i32) -> &i32 { let z = 4; let f = &|y| y; diff --git a/src/test/ui/nll/issue-48697.stderr b/src/test/ui/nll/issue-48697.stderr index 16b46c15b90b6..f0c29b72b4298 100644 --- a/src/test/ui/nll/issue-48697.stderr +++ b/src/test/ui/nll/issue-48697.stderr @@ -1,9 +1,9 @@ error[E0515]: cannot return value referencing local variable `z` - --> $DIR/issue-48697.rs:9:5 + --> $DIR/issue-48697.rs:7:5 | LL | let k = f(&z); | -- `z` is borrowed here -LL | f(x) //~ cannot return value referencing local variable +LL | f(x) | ^^^^ returns a value referencing data owned by the current function error: aborting due to previous error diff --git a/src/test/ui/nll/issue-50716-1.rs b/src/test/ui/nll/issue-50716-1.rs index db7e6b30f2718..ec992959a66ca 100644 --- a/src/test/ui/nll/issue-50716-1.rs +++ b/src/test/ui/nll/issue-50716-1.rs @@ -3,12 +3,8 @@ // bounds derived from `Sized` requirements” that checks that the fixed compiler // accepts this code fragment with both AST and MIR borrow checkers. // -// revisions: ast mir -// // compile-pass -#![cfg_attr(mir, feature(nll))] - struct Qey(Q); fn main() {} diff --git a/src/test/ui/nll/issue-50716.nll.stderr b/src/test/ui/nll/issue-50716.nll.stderr new file mode 100644 index 0000000000000..38dd1b5f6fe73 --- /dev/null +++ b/src/test/ui/nll/issue-50716.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/issue-50716.rs:14:14 + | +LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) + | -- lifetime `'a` defined here +... +LL | let _x = *s; + | ^^ proving this value is `Sized` requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/issue-50716.rs b/src/test/ui/nll/issue-50716.rs index ce4bee366567c..c2fc345fa2ba2 100644 --- a/src/test/ui/nll/issue-50716.rs +++ b/src/test/ui/nll/issue-50716.rs @@ -2,8 +2,6 @@ // Regression test for the issue #50716: NLL ignores lifetimes bounds // derived from `Sized` requirements -#![feature(nll)] - trait A { type X: ?Sized; } diff --git a/src/test/ui/nll/issue-50716.stderr b/src/test/ui/nll/issue-50716.stderr index 229bb1777cc5e..b19e3a9dfb345 100644 --- a/src/test/ui/nll/issue-50716.stderr +++ b/src/test/ui/nll/issue-50716.stderr @@ -1,11 +1,18 @@ -error: lifetime may not live long enough - --> $DIR/issue-50716.rs:16:14 +error[E0308]: mismatched types + --> $DIR/issue-50716.rs:14:9 + | +LL | let _x = *s; + | ^^ lifetime mismatch + | + = note: expected type `std::marker::Sized` + found type `std::marker::Sized` +note: the lifetime 'a as defined on the function body at 9:8... + --> $DIR/issue-50716.rs:9:8 | LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) - | -- lifetime `'a` defined here -... -LL | let _x = *s; //~ ERROR - | ^^ proving this value is `Sized` requires that `'a` must outlive `'static` + | ^^ + = note: ...does not necessarily outlive the static lifetime error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/nll/issue-51191.rs b/src/test/ui/nll/issue-51191.rs index 6704b64869914..747bfe3a8a575 100644 --- a/src/test/ui/nll/issue-51191.rs +++ b/src/test/ui/nll/issue-51191.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - struct Struct; impl Struct { diff --git a/src/test/ui/nll/issue-51191.stderr b/src/test/ui/nll/issue-51191.stderr index e2348d36d33ee..e226de15dc2f0 100644 --- a/src/test/ui/nll/issue-51191.stderr +++ b/src/test/ui/nll/issue-51191.stderr @@ -1,9 +1,9 @@ warning: function cannot return without recursing - --> $DIR/issue-51191.rs:6:5 + --> $DIR/issue-51191.rs:4:5 | LL | fn bar(self: &mut Self) { | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing -LL | //~^ WARN function cannot return without recursing +LL | LL | (&mut self).bar(); | ----------------- recursive call site | @@ -11,7 +11,7 @@ LL | (&mut self).bar(); = help: a `loop` may express intention better if this is on purpose error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable - --> $DIR/issue-51191.rs:8:9 + --> $DIR/issue-51191.rs:6:9 | LL | (&mut self).bar(); | ^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | (&mut self).bar(); | try removing `&mut` here error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable - --> $DIR/issue-51191.rs:13:9 + --> $DIR/issue-51191.rs:11:9 | LL | fn imm(self) { | ---- help: consider changing this to be mutable: `mut self` @@ -28,19 +28,19 @@ LL | (&mut self).bar(); | ^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable - --> $DIR/issue-51191.rs:22:9 + --> $DIR/issue-51191.rs:20:9 | LL | (&mut self).bar(); | ^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/issue-51191.rs:22:9 + --> $DIR/issue-51191.rs:20:9 | LL | (&mut self).bar(); | ^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable - --> $DIR/issue-51191.rs:28:9 + --> $DIR/issue-51191.rs:26:9 | LL | (&mut self).bar(); | ^^^^^^^^^^^ diff --git a/src/test/ui/nll/issue-51244.rs b/src/test/ui/nll/issue-51244.rs index aaf98ddfa2777..743415d58afad 100644 --- a/src/test/ui/nll/issue-51244.rs +++ b/src/test/ui/nll/issue-51244.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - fn main() { let ref my_ref @ _ = 0; *my_ref = 0; diff --git a/src/test/ui/nll/issue-51244.stderr b/src/test/ui/nll/issue-51244.stderr index 69efb2ca84751..8a7e71e0326a0 100644 --- a/src/test/ui/nll/issue-51244.stderr +++ b/src/test/ui/nll/issue-51244.stderr @@ -1,5 +1,5 @@ error[E0594]: cannot assign to `*my_ref` which is behind a `&` reference - --> $DIR/issue-51244.rs:5:5 + --> $DIR/issue-51244.rs:3:5 | LL | let ref my_ref @ _ = 0; | -------------- help: consider changing this to be a mutable reference: `ref mut my_ref @ _` @@ -8,4 +8,3 @@ LL | *my_ref = 0; error: aborting due to previous error -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/nll/issue-51268.rs b/src/test/ui/nll/issue-51268.rs index c14146a3de2a1..12d0449abb19b 100644 --- a/src/test/ui/nll/issue-51268.rs +++ b/src/test/ui/nll/issue-51268.rs @@ -1,7 +1,5 @@ // ignore-tidy-linelength -#![feature(nll)] - struct Bar; impl Bar { diff --git a/src/test/ui/nll/issue-51268.stderr b/src/test/ui/nll/issue-51268.stderr index ce93d3787ef26..420c94f8e1bd2 100644 --- a/src/test/ui/nll/issue-51268.stderr +++ b/src/test/ui/nll/issue-51268.stderr @@ -1,12 +1,12 @@ error[E0502]: cannot borrow `self.thing` as mutable because it is also borrowed as immutable - --> $DIR/issue-51268.rs:18:9 + --> $DIR/issue-51268.rs:16:9 | LL | self.thing.bar(|| { | ^ --- -- immutable borrow occurs here | | | | _________| immutable borrow later used by call | | -LL | | //~^ ERROR cannot borrow `self.thing` as mutable because it is also borrowed as immutable [E0502] +LL | | LL | | &self.number; | | ---- first borrow occurs due to use of `self` in closure LL | | }); diff --git a/src/test/ui/nll/issue-51351.rs b/src/test/ui/nll/issue-51351.rs index 939993f154f8f..b45477c7fb10d 100644 --- a/src/test/ui/nll/issue-51351.rs +++ b/src/test/ui/nll/issue-51351.rs @@ -8,8 +8,6 @@ // // compile-pass -#![feature(nll)] - fn creash<'a>() { let x: &'a () = &(); } diff --git a/src/test/ui/nll/issue-51512.rs b/src/test/ui/nll/issue-51512.rs index 7e2e6e0a16cc0..691760eb91e52 100644 --- a/src/test/ui/nll/issue-51512.rs +++ b/src/test/ui/nll/issue-51512.rs @@ -1,6 +1,3 @@ -#![allow(warnings)] -#![feature(nll)] - fn main() { let range = 0..1; let r = range; diff --git a/src/test/ui/nll/issue-51512.stderr b/src/test/ui/nll/issue-51512.stderr index a84a236ca7772..e591ca08290eb 100644 --- a/src/test/ui/nll/issue-51512.stderr +++ b/src/test/ui/nll/issue-51512.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `range` - --> $DIR/issue-51512.rs:7:13 + --> $DIR/issue-51512.rs:4:13 | LL | let range = 0..1; | ----- move occurs because `range` has type `std::ops::Range`, which does not implement the `Copy` trait diff --git a/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs b/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs index eaa809d2b3706..58416c31edde7 100644 --- a/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs +++ b/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs @@ -4,7 +4,6 @@ // of the fact that the type implements Drop. #![feature(nll)] -#![allow(dead_code)] pub struct S<'a> { url: &'a mut String } diff --git a/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr b/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr index e2036ee4ac0c1..ce48457abe7ec 100644 --- a/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr +++ b/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr @@ -1,5 +1,5 @@ error[E0713]: borrow may still be in use when destructor runs - --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:14:5 + --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:13:5 | LL | fn finish_1(s: S) -> &mut String { | - has type `S<'1>` @@ -9,7 +9,7 @@ LL | } | - here, drop of `s` needs exclusive access to `*s.url`, because the type `S<'_>` implements the `Drop` trait error[E0713]: borrow may still be in use when destructor runs - --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:19:13 + --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:18:13 | LL | fn finish_2(s: S) -> &mut String { | - has type `S<'1>` @@ -19,7 +19,7 @@ LL | } | - here, drop of `s` needs exclusive access to `*s.url`, because the type `S<'_>` implements the `Drop` trait error[E0713]: borrow may still be in use when destructor runs - --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:24:21 + --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:23:21 | LL | fn finish_3(s: S) -> &mut String { | - has type `S<'1>` @@ -29,15 +29,16 @@ LL | } | - here, drop of `s` needs exclusive access to `*s.url`, because the type `S<'_>` implements the `Drop` trait error[E0509]: cannot move out of type `S<'_>`, which implements the `Drop` trait - --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:29:13 + --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:28:13 | LL | let p = s.url; p | ^^^^^ | | | cannot move out of here + | move occurs because `s.url` has type `&mut std::string::String`, which does not implement the `Copy` trait | help: consider borrowing here: `&s.url` error: aborting due to 4 previous errors -Some errors occurred: E0509, E0713. +Some errors have detailed explanations: E0509, E0713. For more information about an error, try `rustc --explain E0509`. diff --git a/src/test/ui/nll/issue-52078.rs b/src/test/ui/nll/issue-52078.rs index ebe442adbd945..4b8e6c6807530 100644 --- a/src/test/ui/nll/issue-52078.rs +++ b/src/test/ui/nll/issue-52078.rs @@ -1,6 +1,3 @@ -#![feature(nll)] -#![allow(unused_variables)] - // Regression test for #52078: we were failing to infer a relationship // between `'a` and `'b` below due to inference variables introduced // during the normalization process. diff --git a/src/test/ui/nll/issue-52086.rs b/src/test/ui/nll/issue-52086.rs index 78765283ec29e..0414428e48150 100644 --- a/src/test/ui/nll/issue-52086.rs +++ b/src/test/ui/nll/issue-52086.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - use std::rc::Rc; use std::sync::Arc; diff --git a/src/test/ui/nll/issue-52086.stderr b/src/test/ui/nll/issue-52086.stderr index ed4171ff14261..e9aa7939f7778 100644 --- a/src/test/ui/nll/issue-52086.stderr +++ b/src/test/ui/nll/issue-52086.stderr @@ -1,14 +1,14 @@ error[E0507]: cannot move out of an `Rc` - --> $DIR/issue-52086.rs:10:10 + --> $DIR/issue-52086.rs:8:10 | LL | drop(x.field); - | ^^^^^^^ cannot move out of an `Rc` + | ^^^^^^^ move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait error[E0507]: cannot move out of an `Arc` - --> $DIR/issue-52086.rs:14:10 + --> $DIR/issue-52086.rs:12:10 | LL | drop(y.field); - | ^^^^^^^ cannot move out of an `Arc` + | ^^^^^^^ move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/issue-52113.rs b/src/test/ui/nll/issue-52113.rs index 795f4f426ffff..0d7ee0376924d 100644 --- a/src/test/ui/nll/issue-52113.rs +++ b/src/test/ui/nll/issue-52113.rs @@ -1,6 +1,3 @@ -// - -#![allow(warnings)] #![feature(nll)] trait Bazinga {} diff --git a/src/test/ui/nll/issue-52113.stderr b/src/test/ui/nll/issue-52113.stderr index ceae16185bbb1..590963ded78bc 100644 --- a/src/test/ui/nll/issue-52113.stderr +++ b/src/test/ui/nll/issue-52113.stderr @@ -1,12 +1,12 @@ error: lifetime may not live long enough - --> $DIR/issue-52113.rs:37:5 + --> $DIR/issue-52113.rs:34:5 | LL | fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here ... -LL | x //~ ERROR lifetime may not live long enough +LL | x | ^ returning this value requires that `'a` must outlive `'b` error: aborting due to previous error diff --git a/src/test/ui/nll/issue-52534-1.rs b/src/test/ui/nll/issue-52534-1.rs index 7ab3593c89f7e..d9ea3ae42c49e 100644 --- a/src/test/ui/nll/issue-52534-1.rs +++ b/src/test/ui/nll/issue-52534-1.rs @@ -1,6 +1,3 @@ -#![feature(nll)] -#![allow(warnings)] - struct Test; impl Test { diff --git a/src/test/ui/nll/issue-52534-1.stderr b/src/test/ui/nll/issue-52534-1.stderr index 7d82f5e710fb1..743179f05c1af 100644 --- a/src/test/ui/nll/issue-52534-1.stderr +++ b/src/test/ui/nll/issue-52534-1.stderr @@ -1,17 +1,17 @@ error[E0515]: cannot return reference to local variable `x` - --> $DIR/issue-52534-1.rs:9:9 + --> $DIR/issue-52534-1.rs:6:9 | LL | &x | ^^ returns a reference to data owned by the current function error[E0515]: cannot return reference to local variable `x` - --> $DIR/issue-52534-1.rs:16:5 + --> $DIR/issue-52534-1.rs:13:5 | LL | &x | ^^ returns a reference to data owned by the current function error[E0515]: cannot return value referencing local variable `x` - --> $DIR/issue-52534-1.rs:22:5 + --> $DIR/issue-52534-1.rs:19:5 | LL | &&x | ^-- @@ -20,7 +20,7 @@ LL | &&x | returns a value referencing data owned by the current function error[E0515]: cannot return reference to temporary value - --> $DIR/issue-52534-1.rs:22:5 + --> $DIR/issue-52534-1.rs:19:5 | LL | &&x | ^-- @@ -29,25 +29,25 @@ LL | &&x | returns a reference to data owned by the current function error[E0515]: cannot return reference to local variable `x` - --> $DIR/issue-52534-1.rs:29:5 + --> $DIR/issue-52534-1.rs:26:5 | LL | &x | ^^ returns a reference to data owned by the current function error[E0515]: cannot return reference to local variable `x` - --> $DIR/issue-52534-1.rs:35:5 + --> $DIR/issue-52534-1.rs:32:5 | LL | &x | ^^ returns a reference to data owned by the current function error[E0515]: cannot return reference to local variable `x` - --> $DIR/issue-52534-1.rs:41:5 + --> $DIR/issue-52534-1.rs:38:5 | LL | &x | ^^ returns a reference to data owned by the current function error[E0515]: cannot return reference to local variable `x` - --> $DIR/issue-52534-1.rs:47:5 + --> $DIR/issue-52534-1.rs:44:5 | LL | &x | ^^ returns a reference to data owned by the current function diff --git a/src/test/ui/nll/issue-52534-2.rs b/src/test/ui/nll/issue-52534-2.rs index 6e84869dd6d3b..e416264ed09fd 100644 --- a/src/test/ui/nll/issue-52534-2.rs +++ b/src/test/ui/nll/issue-52534-2.rs @@ -1,6 +1,3 @@ -#![feature(nll)] -#![allow(warnings)] - fn foo(x: &u32) -> &u32 { let y; diff --git a/src/test/ui/nll/issue-52534-2.stderr b/src/test/ui/nll/issue-52534-2.stderr index a4396ae386dc5..dd8a87f7e29aa 100644 --- a/src/test/ui/nll/issue-52534-2.stderr +++ b/src/test/ui/nll/issue-52534-2.stderr @@ -1,9 +1,9 @@ error[E0597]: `x` does not live long enough - --> $DIR/issue-52534-2.rs:9:9 + --> $DIR/issue-52534-2.rs:6:9 | LL | y = &x | ^^^^^^ borrowed value does not live long enough -LL | //~^ ERROR does not live long enough +LL | LL | } | - `x` dropped here while still borrowed LL | diff --git a/src/test/ui/nll/issue-52534.rs b/src/test/ui/nll/issue-52534.rs index 1394560df19ba..559d4c8591b34 100644 --- a/src/test/ui/nll/issue-52534.rs +++ b/src/test/ui/nll/issue-52534.rs @@ -1,6 +1,3 @@ -#![feature(nll)] -#![allow(warnings)] - fn foo(_: impl FnOnce(&u32) -> &u32) { } diff --git a/src/test/ui/nll/issue-52534.stderr b/src/test/ui/nll/issue-52534.stderr index e83374af3b066..b2b727fd43893 100644 --- a/src/test/ui/nll/issue-52534.stderr +++ b/src/test/ui/nll/issue-52534.stderr @@ -1,11 +1,11 @@ error[E0597]: `x` does not live long enough - --> $DIR/issue-52534.rs:12:14 + --> $DIR/issue-52534.rs:9:14 | LL | foo(|a| &x) | - ^ `x` would have to be valid for `'0`... | | | has type `&'0 u32` -LL | //~^ ERROR does not live long enough +LL | LL | } | - ...but `x` will be dropped here, when the function `bar` returns | @@ -13,13 +13,13 @@ LL | } = note: to learn more, visit error[E0597]: `y` does not live long enough - --> $DIR/issue-52534.rs:18:26 + --> $DIR/issue-52534.rs:15:26 | LL | baz(|first, second| &y) | ----- ^ `y` would have to be valid for `'0`... | | | has type `&'0 u32` -LL | //~^ ERROR does not live long enough +LL | LL | } | - ...but `y` will be dropped here, when the function `foobar` returns | diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs b/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs index 3e57d26745a95..cd1f457a13064 100644 --- a/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs +++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - fn expect_fn(f: F) where F : Fn() { f(); } @@ -8,6 +6,6 @@ fn main() { { let x = (vec![22], vec![44]); expect_fn(|| drop(x.0)); - //~^ ERROR cannot move out of captured variable in an `Fn` closure [E0507] + //~^ ERROR cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure [E0507] } } diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr index 0162c6bcbd1ec..57b9dc1f0be57 100644 --- a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr +++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr @@ -1,10 +1,10 @@ -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/issue-52663-span-decl-captured-variable.rs:10:26 +error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure + --> $DIR/issue-52663-span-decl-captured-variable.rs:8:26 | LL | let x = (vec![22], vec![44]); | - captured outer variable LL | expect_fn(|| drop(x.0)); - | ^^^ cannot move out of captured variable in an `Fn` closure + | ^^^ move occurs because `x.0` has type `std::vec::Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/nll/issue-52663-trait-object.rs b/src/test/ui/nll/issue-52663-trait-object.rs index 121c3ef4e6109..a7be365bde4bd 100644 --- a/src/test/ui/nll/issue-52663-trait-object.rs +++ b/src/test/ui/nll/issue-52663-trait-object.rs @@ -1,5 +1,4 @@ #![feature(box_syntax)] -#![feature(nll)] trait Foo { fn get(&self); } @@ -11,7 +10,7 @@ fn main() { let _ = { let tmp0 = 3; let tmp1 = &tmp0; - box tmp1 as Box + box tmp1 as Box }; //~^^^ ERROR `tmp0` does not live long enough } diff --git a/src/test/ui/nll/issue-52663-trait-object.stderr b/src/test/ui/nll/issue-52663-trait-object.stderr index b9437d88ff674..b71893de7f8bd 100644 --- a/src/test/ui/nll/issue-52663-trait-object.stderr +++ b/src/test/ui/nll/issue-52663-trait-object.stderr @@ -1,10 +1,10 @@ error[E0597]: `tmp0` does not live long enough - --> $DIR/issue-52663-trait-object.rs:13:20 + --> $DIR/issue-52663-trait-object.rs:12:20 | LL | let tmp1 = &tmp0; | ^^^^^ borrowed value does not live long enough -LL | box tmp1 as Box - | ------------------------- borrow later captured here by trait object +LL | box tmp1 as Box + | ----------------------------- borrow later captured here by trait object LL | }; | - `tmp0` dropped here while still borrowed diff --git a/src/test/ui/nll/issue-52669.rs b/src/test/ui/nll/issue-52669.rs index 6027e98814128..e33528ac59e68 100644 --- a/src/test/ui/nll/issue-52669.rs +++ b/src/test/ui/nll/issue-52669.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - struct A { b: B, } diff --git a/src/test/ui/nll/issue-52669.stderr b/src/test/ui/nll/issue-52669.stderr index f51768c3859e4..db53e444b9e4a 100644 --- a/src/test/ui/nll/issue-52669.stderr +++ b/src/test/ui/nll/issue-52669.stderr @@ -1,5 +1,5 @@ error[E0382]: borrow of moved value: `a.b` - --> $DIR/issue-52669.rs:15:5 + --> $DIR/issue-52669.rs:13:5 | LL | fn bar(mut a: A) -> B { | ----- move occurs because `a` has type `A`, which does not implement the `Copy` trait diff --git a/src/test/ui/nll/issue-52742.nll.stderr b/src/test/ui/nll/issue-52742.nll.stderr new file mode 100644 index 0000000000000..e8b7b3333eb6b --- /dev/null +++ b/src/test/ui/nll/issue-52742.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/issue-52742.rs:14:9 + | +LL | fn take_bar(&mut self, b: Bar<'_>) { + | --------- -- let's call this `'1` + | | + | has type `&mut Foo<'_, '2>` +LL | self.y = b.z + | ^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/issue-52742.rs b/src/test/ui/nll/issue-52742.rs index 150e67fe09481..db9ddfff285b3 100644 --- a/src/test/ui/nll/issue-52742.rs +++ b/src/test/ui/nll/issue-52742.rs @@ -1,4 +1,3 @@ -#![feature(nll)] #![feature(in_band_lifetimes)] struct Foo<'a, 'b> { @@ -13,7 +12,7 @@ struct Bar<'b> { impl Foo<'_, '_> { fn take_bar(&mut self, b: Bar<'_>) { self.y = b.z - //~^ ERROR lifetime may not live long enough + //~^ ERROR } } diff --git a/src/test/ui/nll/issue-52742.stderr b/src/test/ui/nll/issue-52742.stderr index 6b25296c4bda1..b982915800294 100644 --- a/src/test/ui/nll/issue-52742.stderr +++ b/src/test/ui/nll/issue-52742.stderr @@ -1,12 +1,22 @@ -error: lifetime may not live long enough - --> $DIR/issue-52742.rs:15:9 +error[E0312]: lifetime of reference outlives lifetime of borrowed content... + --> $DIR/issue-52742.rs:14:18 | -LL | fn take_bar(&mut self, b: Bar<'_>) { - | --------- -- let's call this `'1` - | | - | has type `&mut Foo<'_, '2>` LL | self.y = b.z - | ^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` + | ^^^ + | +note: ...the reference is valid for the lifetime '_ as defined on the impl at 12:10... + --> $DIR/issue-52742.rs:12:10 + | +LL | impl Foo<'_, '_> { + | ^^ +note: ...but the borrowed content is only valid for the anonymous lifetime #2 defined on the method body at 13:5 + --> $DIR/issue-52742.rs:13:5 + | +LL | / fn take_bar(&mut self, b: Bar<'_>) { +LL | | self.y = b.z +LL | | +LL | | } + | |_____^ error: aborting due to previous error diff --git a/src/test/ui/nll/issue-53119.rs b/src/test/ui/nll/issue-53119.rs index 97e05c8810d09..7a47a77f6bb4c 100644 --- a/src/test/ui/nll/issue-53119.rs +++ b/src/test/ui/nll/issue-53119.rs @@ -1,7 +1,5 @@ // compile-pass -#![feature(nll)] - use std::ops::Deref; pub struct TypeFieldIterator<'a, T: 'a> { diff --git a/src/test/ui/nll/issue-53570.rs b/src/test/ui/nll/issue-53570.rs index d0baffa2702c3..81c50edfed1a4 100644 --- a/src/test/ui/nll/issue-53570.rs +++ b/src/test/ui/nll/issue-53570.rs @@ -8,21 +8,17 @@ // // compile-pass -#![feature(nll)] -#![feature(rustc_attrs)] -#![allow(dead_code)] - use std::cell::{RefCell, Ref}; trait AnyVec<'a> { } trait GenericVec { - fn unwrap<'a, 'b>(vec: &'b AnyVec<'a>) -> &'b [T] where T: 'a; + fn unwrap<'a, 'b>(vec: &'b dyn AnyVec<'a>) -> &'b [T] where T: 'a; } struct Scratchpad<'a> { - buffers: RefCell>>, + buffers: RefCell>>, } impl<'a> Scratchpad<'a> { diff --git a/src/test/ui/nll/issue-53773.stderr b/src/test/ui/nll/issue-53773.stderr index 92a9946068cfe..1933ef7a2dbc7 100644 --- a/src/test/ui/nll/issue-53773.stderr +++ b/src/test/ui/nll/issue-53773.stderr @@ -3,7 +3,7 @@ error[E0713]: borrow may still be in use when destructor runs | LL | members.push(child.raw); | ^^^^^^^^^ -LL | //~^ ERROR borrow may still be in use when destructor runs [E0713] +LL | LL | } | - here, drop of `child` needs exclusive access to `*child.raw`, because the type `C<'_>` implements the `Drop` trait LL | members.len(); diff --git a/src/test/ui/nll/issue-53807.nll.stderr b/src/test/ui/nll/issue-53807.nll.stderr deleted file mode 100644 index 2b15da3710e62..0000000000000 --- a/src/test/ui/nll/issue-53807.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0382]: use of moved value - --> $DIR/issue-53807.rs:4:21 - | -LL | if let Some(thing) = maybe { - | ^^^^^ value moved here, in previous iteration of loop - | - = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/nll/issue-53807.rs b/src/test/ui/nll/issue-53807.rs index f69d8c14935f9..d494f7e151dfb 100644 --- a/src/test/ui/nll/issue-53807.rs +++ b/src/test/ui/nll/issue-53807.rs @@ -2,8 +2,7 @@ pub fn main(){ let maybe = Some(vec![true, true]); loop { if let Some(thing) = maybe { -//~^ ERROR use of partially moved value -//~| ERROR use of moved value +//~^ ERROR use of moved value } } } diff --git a/src/test/ui/nll/issue-53807.stderr b/src/test/ui/nll/issue-53807.stderr index fb6701452cb6c..2b15da3710e62 100644 --- a/src/test/ui/nll/issue-53807.stderr +++ b/src/test/ui/nll/issue-53807.stderr @@ -1,21 +1,11 @@ -error[E0382]: use of partially moved value: `maybe` - --> $DIR/issue-53807.rs:4:30 - | -LL | if let Some(thing) = maybe { - | ----- ^^^^^ value used here after move - | | - | value moved here - | - = note: move occurs because the value has type `std::vec::Vec`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `(maybe as std::prelude::v1::Some).0` +error[E0382]: use of moved value --> $DIR/issue-53807.rs:4:21 | LL | if let Some(thing) = maybe { - | ^^^^^ value moved here in previous iteration of loop + | ^^^^^ value moved here, in previous iteration of loop | - = note: move occurs because the value has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr deleted file mode 100644 index 8412cbdc54b3b..0000000000000 --- a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0597]: `_thing1` does not live long enough - --> $DIR/issue-54382-use-span-of-tail-of-block.rs:7:29 - | -LL | D("other").next(&_thing1) - | ----------------^^^^^^^^- - | | | - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... -... -LL | } - | - `_thing1` dropped here while still borrowed -LL | -LL | ; - | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | - = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr index 8d23891e1ba79..8412cbdc54b3b 100644 --- a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr +++ b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr @@ -1,14 +1,19 @@ error[E0597]: `_thing1` does not live long enough - --> $DIR/issue-54382-use-span-of-tail-of-block.rs:7:30 + --> $DIR/issue-54382-use-span-of-tail-of-block.rs:7:29 | LL | D("other").next(&_thing1) - | ^^^^^^^ borrowed value does not live long enough + | ----------------^^^^^^^^- + | | | + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... ... LL | } | - `_thing1` dropped here while still borrowed LL | LL | ; - | - borrowed value needs to live until here + | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | + = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. error: aborting due to previous error diff --git a/src/test/ui/nll/issue-54556-niconii.nll.stderr b/src/test/ui/nll/issue-54556-niconii.nll.stderr deleted file mode 100644 index 58239fe6e888d..0000000000000 --- a/src/test/ui/nll/issue-54556-niconii.nll.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0597]: `counter` does not live long enough - --> $DIR/issue-54556-niconii.rs:22:20 - | -LL | if let Ok(_) = counter.lock() { } //~ ERROR does not live long enough - | ^^^^^^^------- - | | - | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... -... -LL | } - | - - | | - | `counter` dropped here while still borrowed - | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::result::Result, ()>` - | - = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/issue-54556-niconii.stderr b/src/test/ui/nll/issue-54556-niconii.stderr index 03a7b94d181ba..40cd04de5ecc1 100644 --- a/src/test/ui/nll/issue-54556-niconii.stderr +++ b/src/test/ui/nll/issue-54556-niconii.stderr @@ -1,13 +1,19 @@ error[E0597]: `counter` does not live long enough --> $DIR/issue-54556-niconii.rs:22:20 | -LL | if let Ok(_) = counter.lock() { } //~ ERROR does not live long enough - | ^^^^^^^ borrowed value does not live long enough +LL | if let Ok(_) = counter.lock() { } + | ^^^^^^^------- + | | + | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... ... LL | } - | - `counter` dropped here while still borrowed + | - + | | + | `counter` dropped here while still borrowed + | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::result::Result, ()>` | - = note: values in a scope are dropped in the opposite order they are created + = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. error: aborting due to previous error diff --git a/src/test/ui/nll/issue-54556-stephaneyfx.nll.stderr b/src/test/ui/nll/issue-54556-stephaneyfx.nll.stderr deleted file mode 100644 index b58454427af84..0000000000000 --- a/src/test/ui/nll/issue-54556-stephaneyfx.nll.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0597]: `stmt` does not live long enough - --> $DIR/issue-54556-stephaneyfx.rs:27:21 - | -LL | let rows = Rows(&stmt); //~ ERROR does not live long enough - | ^^^^^ borrowed value does not live long enough -LL | rows.map(|row| row).next() - | ------------------- a temporary with access to the borrow is created here ... -... -LL | } - | - - | | - | `stmt` dropped here while still borrowed - | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::iter::Map, [closure@$DIR/issue-54556-stephaneyfx.rs:28:14: 28:23]>` - | - = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/issue-54556-stephaneyfx.stderr b/src/test/ui/nll/issue-54556-stephaneyfx.stderr index bf3285a73c7c5..0bf76485eef2a 100644 --- a/src/test/ui/nll/issue-54556-stephaneyfx.stderr +++ b/src/test/ui/nll/issue-54556-stephaneyfx.stderr @@ -1,13 +1,18 @@ error[E0597]: `stmt` does not live long enough - --> $DIR/issue-54556-stephaneyfx.rs:27:22 + --> $DIR/issue-54556-stephaneyfx.rs:27:21 | -LL | let rows = Rows(&stmt); //~ ERROR does not live long enough - | ^^^^ borrowed value does not live long enough +LL | let rows = Rows(&stmt); + | ^^^^^ borrowed value does not live long enough +LL | rows.map(|row| row).next() + | ------------------- a temporary with access to the borrow is created here ... ... LL | } - | - `stmt` dropped here while still borrowed + | - + | | + | `stmt` dropped here while still borrowed + | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::iter::Map, [closure@$DIR/issue-54556-stephaneyfx.rs:28:14: 28:23]>` | - = note: values in a scope are dropped in the opposite order they are created + = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. error: aborting due to previous error diff --git a/src/test/ui/nll/issue-54556-temps-in-tail-diagnostic.nll.stderr b/src/test/ui/nll/issue-54556-temps-in-tail-diagnostic.nll.stderr deleted file mode 100644 index 1bc43017bc675..0000000000000 --- a/src/test/ui/nll/issue-54556-temps-in-tail-diagnostic.nll.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0597]: `_thing1` does not live long enough - --> $DIR/issue-54556-temps-in-tail-diagnostic.rs:5:11 - | -LL | D(&_thing1).end() //~ ERROR does not live long enough - | --^^^^^^^^- - | | | - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... -LL | } - | - `_thing1` dropped here while still borrowed -LL | -LL | ; - | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | - = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/issue-54556-temps-in-tail-diagnostic.stderr b/src/test/ui/nll/issue-54556-temps-in-tail-diagnostic.stderr index ca636e7613265..513dca7950af9 100644 --- a/src/test/ui/nll/issue-54556-temps-in-tail-diagnostic.stderr +++ b/src/test/ui/nll/issue-54556-temps-in-tail-diagnostic.stderr @@ -1,13 +1,18 @@ error[E0597]: `_thing1` does not live long enough - --> $DIR/issue-54556-temps-in-tail-diagnostic.rs:5:12 + --> $DIR/issue-54556-temps-in-tail-diagnostic.rs:5:11 | -LL | D(&_thing1).end() //~ ERROR does not live long enough - | ^^^^^^^ borrowed value does not live long enough +LL | D(&_thing1).end() + | --^^^^^^^^- + | | | + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... LL | } | - `_thing1` dropped here while still borrowed LL | LL | ; - | - borrowed value needs to live until here + | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | + = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. error: aborting due to previous error diff --git a/src/test/ui/nll/issue-54556-used-vs-unused-tails.nll.stderr b/src/test/ui/nll/issue-54556-used-vs-unused-tails.nll.stderr deleted file mode 100644 index 52d0870b78f95..0000000000000 --- a/src/test/ui/nll/issue-54556-used-vs-unused-tails.nll.stderr +++ /dev/null @@ -1,113 +0,0 @@ -error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:10:55 - | -LL | { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // suggest `;` - | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... - | - = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. - -error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:13:55 - | -LL | { { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } } ; // suggest `;` - | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... - | - = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. - -error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:16:55 - | -LL | { { let mut _t1 = D(Box::new("t1")); D(&_t1).end() }; } // suggest `;` - | --^^^^- -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... - | - = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. - -error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:19:55 - | -LL | let _ = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // suggest `;` - | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... - | - = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. - -error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:22:55 - | -LL | let _u = { let mut _t1 = D(Box::new("t1")); D(&_t1).unit() } ; // suggest `;` - | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... - | - = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. - -error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:25:55 - | -LL | let _x = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // `let x = ...; x` - | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... - | - = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. - -error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:30:55 - | -LL | _y = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // `let x = ...; x` - | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... - | - = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. - -error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:37:55 - | -LL | fn f_local_ref() { let mut _t1 = D(Box::new("t1")); D(&_t1).unit() } // suggest `;` - | --^^^^- - - | | | | - | | | `_t1` dropped here while still borrowed - | | | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... - | - = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. - -error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:40:55 - | -LL | fn f() -> String { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } // `let x = ...; x` - | --^^^^- - - | | | | - | | | `_t1` dropped here while still borrowed - | | | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... - | - = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. - -error: aborting due to 9 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/issue-54556-used-vs-unused-tails.stderr b/src/test/ui/nll/issue-54556-used-vs-unused-tails.stderr index e9e4e51136d0a..52d0870b78f95 100644 --- a/src/test/ui/nll/issue-54556-used-vs-unused-tails.stderr +++ b/src/test/ui/nll/issue-54556-used-vs-unused-tails.stderr @@ -1,85 +1,112 @@ error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:10:56 + --> $DIR/issue-54556-used-vs-unused-tails.rs:10:55 | LL | { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // suggest `;` - | ^^^ - - borrowed value needs to live until here - | | | - | | `_t1` dropped here while still borrowed - | borrowed value does not live long enough + | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | + | | | `_t1` dropped here while still borrowed + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... + | + = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:13:56 + --> $DIR/issue-54556-used-vs-unused-tails.rs:13:55 | LL | { { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } } ; // suggest `;` - | ^^^ - - borrowed value needs to live until here - | | | - | | `_t1` dropped here while still borrowed - | borrowed value does not live long enough + | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | + | | | `_t1` dropped here while still borrowed + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... + | + = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:16:56 + --> $DIR/issue-54556-used-vs-unused-tails.rs:16:55 | LL | { { let mut _t1 = D(Box::new("t1")); D(&_t1).end() }; } // suggest `;` - | ^^^ -- borrowed value needs to live until here - | | | - | | `_t1` dropped here while still borrowed - | borrowed value does not live long enough + | --^^^^- -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | + | | | `_t1` dropped here while still borrowed + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... + | + = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:19:56 + --> $DIR/issue-54556-used-vs-unused-tails.rs:19:55 | LL | let _ = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // suggest `;` - | ^^^ - - borrowed value needs to live until here - | | | - | | `_t1` dropped here while still borrowed - | borrowed value does not live long enough + | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | + | | | `_t1` dropped here while still borrowed + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... + | + = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:22:56 + --> $DIR/issue-54556-used-vs-unused-tails.rs:22:55 | LL | let _u = { let mut _t1 = D(Box::new("t1")); D(&_t1).unit() } ; // suggest `;` - | ^^^ - - borrowed value needs to live until here - | | | - | | `_t1` dropped here while still borrowed - | borrowed value does not live long enough + | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | + | | | `_t1` dropped here while still borrowed + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... + | + = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:25:56 + --> $DIR/issue-54556-used-vs-unused-tails.rs:25:55 | LL | let _x = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // `let x = ...; x` - | ^^^ - - borrowed value needs to live until here - | | | - | | `_t1` dropped here while still borrowed - | borrowed value does not live long enough + | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | + | | | `_t1` dropped here while still borrowed + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... + | + = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:30:56 + --> $DIR/issue-54556-used-vs-unused-tails.rs:30:55 | LL | _y = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // `let x = ...; x` - | ^^^ - - borrowed value needs to live until here - | | | - | | `_t1` dropped here while still borrowed - | borrowed value does not live long enough + | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | + | | | `_t1` dropped here while still borrowed + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... + | + = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:37:56 + --> $DIR/issue-54556-used-vs-unused-tails.rs:37:55 | LL | fn f_local_ref() { let mut _t1 = D(Box::new("t1")); D(&_t1).unit() } // suggest `;` - | ^^^ - `_t1` dropped here while still borrowed - | | - | borrowed value does not live long enough + | --^^^^- - + | | | | + | | | `_t1` dropped here while still borrowed + | | | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... | - = note: values in a scope are dropped in the opposite order they are created + = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. error[E0597]: `_t1` does not live long enough - --> $DIR/issue-54556-used-vs-unused-tails.rs:40:56 + --> $DIR/issue-54556-used-vs-unused-tails.rs:40:55 | LL | fn f() -> String { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } // `let x = ...; x` - | ^^^ - `_t1` dropped here while still borrowed - | | - | borrowed value does not live long enough + | --^^^^- - + | | | | + | | | `_t1` dropped here while still borrowed + | | | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... | - = note: values in a scope are dropped in the opposite order they are created + = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. error: aborting due to 9 previous errors diff --git a/src/test/ui/nll/issue-54556-wrap-it-up.nll.stderr b/src/test/ui/nll/issue-54556-wrap-it-up.nll.stderr deleted file mode 100644 index a13e59fa48b5c..0000000000000 --- a/src/test/ui/nll/issue-54556-wrap-it-up.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/issue-54556-wrap-it-up.rs:27:5 - | -LL | let wrap = Wrap { p: &mut x }; - | ------ borrow of `x` occurs here -... -LL | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506] - | ^^^^^ assignment to borrowed `x` occurs here -LL | } - | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/nll/issue-54556-wrap-it-up.stderr b/src/test/ui/nll/issue-54556-wrap-it-up.stderr index a0c19b9638798..9f27fac15a7f6 100644 --- a/src/test/ui/nll/issue-54556-wrap-it-up.stderr +++ b/src/test/ui/nll/issue-54556-wrap-it-up.stderr @@ -2,10 +2,12 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/issue-54556-wrap-it-up.rs:27:5 | LL | let wrap = Wrap { p: &mut x }; - | - borrow of `x` occurs here + | ------ borrow of `x` occurs here ... -LL | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506] +LL | x = 1; | ^^^^^ assignment to borrowed `x` occurs here +LL | } + | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>` error: aborting due to previous error diff --git a/src/test/ui/nll/issue-55288.rs b/src/test/ui/nll/issue-55288.rs index 9b3eb7f05ded4..c7b6ac5924837 100644 --- a/src/test/ui/nll/issue-55288.rs +++ b/src/test/ui/nll/issue-55288.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - // run-pass struct Slice(&'static [&'static [u8]]); diff --git a/src/test/ui/nll/issue-55344.rs b/src/test/ui/nll/issue-55344.rs index b900acfa1599e..521d4d33d8633 100644 --- a/src/test/ui/nll/issue-55344.rs +++ b/src/test/ui/nll/issue-55344.rs @@ -1,7 +1,5 @@ // compile-pass -#![feature(nll)] -#![allow(unreachable_code)] #![deny(unused_mut)] pub fn foo() { diff --git a/src/test/ui/nll/issue-55394.nll.stderr b/src/test/ui/nll/issue-55394.nll.stderr new file mode 100644 index 0000000000000..d0723047ac08c --- /dev/null +++ b/src/test/ui/nll/issue-55394.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/issue-55394.rs:9:9 + | +LL | fn new(bar: &mut Bar) -> Self { + | - ---- return type is Foo<'2> + | | + | let's call the lifetime of this reference `'1` +LL | Foo { bar } + | ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/issue-55394.rs b/src/test/ui/nll/issue-55394.rs index deb1034525edb..f813d1c915cf6 100644 --- a/src/test/ui/nll/issue-55394.rs +++ b/src/test/ui/nll/issue-55394.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - struct Bar; struct Foo<'s> { @@ -8,7 +6,7 @@ struct Foo<'s> { impl Foo<'_> { fn new(bar: &mut Bar) -> Self { - Foo { bar } //~ERROR lifetime may not live long enough + Foo { bar } //~ERROR } } diff --git a/src/test/ui/nll/issue-55394.stderr b/src/test/ui/nll/issue-55394.stderr index bcdd78248eb4b..ffb94ed7dd7c0 100644 --- a/src/test/ui/nll/issue-55394.stderr +++ b/src/test/ui/nll/issue-55394.stderr @@ -1,12 +1,29 @@ -error: lifetime may not live long enough - --> $DIR/issue-55394.rs:11:9 - | -LL | fn new(bar: &mut Bar) -> Self { - | - ---- return type is Foo<'2> - | | - | let's call the lifetime of this reference `'1` -LL | Foo { bar } //~ERROR lifetime may not live long enough - | ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'s` due to conflicting requirements + --> $DIR/issue-55394.rs:9:9 + | +LL | Foo { bar } + | ^^^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 8:5... + --> $DIR/issue-55394.rs:8:5 + | +LL | / fn new(bar: &mut Bar) -> Self { +LL | | Foo { bar } +LL | | } + | |_____^ +note: ...so that reference does not outlive borrowed content + --> $DIR/issue-55394.rs:9:15 + | +LL | Foo { bar } + | ^^^ +note: but, the lifetime must be valid for the lifetime '_ as defined on the impl at 7:10... + --> $DIR/issue-55394.rs:7:10 + | +LL | impl Foo<'_> { + | ^^ + = note: ...so that the expression is assignable: + expected Foo<'_> + found Foo<'_> error: aborting due to previous error diff --git a/src/test/ui/nll/issue-55401.nll.stderr b/src/test/ui/nll/issue-55401.nll.stderr new file mode 100644 index 0000000000000..4f797f26a1a7c --- /dev/null +++ b/src/test/ui/nll/issue-55401.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/issue-55401.rs:3:5 + | +LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | let (ref y, _z): (&'a u32, u32) = (&22, 44); +LL | *y + | ^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/issue-55401.rs b/src/test/ui/nll/issue-55401.rs index 2fa234491087d..fc45824e903c8 100644 --- a/src/test/ui/nll/issue-55401.rs +++ b/src/test/ui/nll/issue-55401.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 { let (ref y, _z): (&'a u32, u32) = (&22, 44); *y //~ ERROR diff --git a/src/test/ui/nll/issue-55401.stderr b/src/test/ui/nll/issue-55401.stderr index 952b5441f86ff..50debc6386f6a 100644 --- a/src/test/ui/nll/issue-55401.stderr +++ b/src/test/ui/nll/issue-55401.stderr @@ -1,11 +1,15 @@ -error: lifetime may not live long enough - --> $DIR/issue-55401.rs:5:5 +error[E0312]: lifetime of reference outlives lifetime of borrowed content... + --> $DIR/issue-55401.rs:3:5 + | +LL | *y + | ^^ + | + = note: ...the reference is valid for the static lifetime... +note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 1:47 + --> $DIR/issue-55401.rs:1:47 | LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 { - | -- lifetime `'a` defined here -LL | let (ref y, _z): (&'a u32, u32) = (&22, 44); -LL | *y //~ ERROR - | ^^ returning this value requires that `'a` must outlive `'static` + | ^^ error: aborting due to previous error diff --git a/src/test/ui/nll/issue-55850.nll.stderr b/src/test/ui/nll/issue-55850.nll.stderr deleted file mode 100644 index e09711f74fd72..0000000000000 --- a/src/test/ui/nll/issue-55850.nll.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0597]: `s` does not live long enough - --> $DIR/issue-55850.rs:28:16 - | -LL | yield &s[..] //~ ERROR `s` does not live long enough [E0597] - | ^ borrowed value does not live long enough -LL | }) - | - `s` dropped here while still borrowed - -error[E0626]: borrow may still be in use when generator yields - --> $DIR/issue-55850.rs:28:16 - | -LL | yield &s[..] //~ ERROR `s` does not live long enough [E0597] - | -------^---- possible yield occurs here - -error: aborting due to 2 previous errors - -Some errors occurred: E0597, E0626. -For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/issue-55850.rs b/src/test/ui/nll/issue-55850.rs index 8b5887224d19a..a8f7299f89937 100644 --- a/src/test/ui/nll/issue-55850.rs +++ b/src/test/ui/nll/issue-55850.rs @@ -25,7 +25,8 @@ where fn bug<'a>() -> impl Iterator { GenIter(move || { let mut s = String::new(); - yield &s[..] //~ ERROR `s` does not live long enough [E0597] + yield &s[..] //~ ERROR cannot yield value referencing local variable `s` [E0515] + //~| ERROR borrow may still be in use when generator yields }) } diff --git a/src/test/ui/nll/issue-55850.stderr b/src/test/ui/nll/issue-55850.stderr index 2a24cba1a6846..86a8cdc42ff9f 100644 --- a/src/test/ui/nll/issue-55850.stderr +++ b/src/test/ui/nll/issue-55850.stderr @@ -1,17 +1,19 @@ -error[E0597]: `s` does not live long enough - --> $DIR/issue-55850.rs:28:16 - | -LL | yield &s[..] //~ ERROR `s` does not live long enough [E0597] - | ^ borrowed value does not live long enough -LL | }) - | - borrowed value only lives until here +error[E0515]: cannot yield value referencing local variable `s` + --> $DIR/issue-55850.rs:28:9 | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 25:8... - --> $DIR/issue-55850.rs:25:8 +LL | yield &s[..] + | ^^^^^^^-^^^^ + | | | + | | `s` is borrowed here + | yields a value referencing data owned by the current function + +error[E0626]: borrow may still be in use when generator yields + --> $DIR/issue-55850.rs:28:16 | -LL | fn bug<'a>() -> impl Iterator { - | ^^ +LL | yield &s[..] + | -------^---- possible yield occurs here -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors have detailed explanations: E0515, E0626. +For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/nll/issue-57265-return-type-wf-check.rs b/src/test/ui/nll/issue-57265-return-type-wf-check.rs index 24c61a4926f0c..8fb8351cee260 100644 --- a/src/test/ui/nll/issue-57265-return-type-wf-check.rs +++ b/src/test/ui/nll/issue-57265-return-type-wf-check.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - use std::any::Any; #[derive(Debug, Clone)] diff --git a/src/test/ui/nll/issue-57265-return-type-wf-check.stderr b/src/test/ui/nll/issue-57265-return-type-wf-check.stderr index db01212597f5b..20add62b91ddf 100644 --- a/src/test/ui/nll/issue-57265-return-type-wf-check.stderr +++ b/src/test/ui/nll/issue-57265-return-type-wf-check.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-57265-return-type-wf-check.rs:22:23 + --> $DIR/issue-57265-return-type-wf-check.rs:20:23 | LL | let (_, z) = foo(&"hello".to_string()); | -----^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement diff --git a/src/test/ui/nll/issue-57280-1.rs b/src/test/ui/nll/issue-57280-1.rs index 356c477f1ba36..e02d6a0cb5a39 100644 --- a/src/test/ui/nll/issue-57280-1.rs +++ b/src/test/ui/nll/issue-57280-1.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - // compile-pass trait Foo<'a> { diff --git a/src/test/ui/nll/issue-57280.rs b/src/test/ui/nll/issue-57280.rs index 4fe6a96f5dcc8..776a0d359cda6 100644 --- a/src/test/ui/nll/issue-57280.rs +++ b/src/test/ui/nll/issue-57280.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - // compile-pass trait Foo { diff --git a/src/test/ui/nll/issue-57960.rs b/src/test/ui/nll/issue-57960.rs index 0b52e46c45989..1399694a79b6a 100644 --- a/src/test/ui/nll/issue-57960.rs +++ b/src/test/ui/nll/issue-57960.rs @@ -27,9 +27,9 @@ impl Range for ThreeDigits { fn digits(x: u8) -> u32 { match x { - OneDigit::FIRST...OneDigit::LAST => 1, - TwoDigits::FIRST...TwoDigits::LAST => 2, - ThreeDigits::FIRST...ThreeDigits::LAST => 3, + OneDigit::FIRST..=OneDigit::LAST => 1, + TwoDigits::FIRST..=TwoDigits::LAST => 2, + ThreeDigits::FIRST..=ThreeDigits::LAST => 3, _ => unreachable!(), } } diff --git a/src/test/ui/nll/issue-57989.rs b/src/test/ui/nll/issue-57989.rs index 4f21cca97cc09..c410f0b0bfb4d 100644 --- a/src/test/ui/nll/issue-57989.rs +++ b/src/test/ui/nll/issue-57989.rs @@ -1,7 +1,5 @@ // Test for ICE from issue 57989 -#![feature(nll)] - fn f(x: &i32) { let g = &x; *x = 0; //~ ERROR cannot assign to `*x` which is behind a `&` reference diff --git a/src/test/ui/nll/issue-57989.stderr b/src/test/ui/nll/issue-57989.stderr index 4561c99096f14..00a9bab486855 100644 --- a/src/test/ui/nll/issue-57989.stderr +++ b/src/test/ui/nll/issue-57989.stderr @@ -1,24 +1,23 @@ error[E0594]: cannot assign to `*x` which is behind a `&` reference - --> $DIR/issue-57989.rs:7:5 + --> $DIR/issue-57989.rs:5:5 | LL | fn f(x: &i32) { | ---- help: consider changing this to be a mutable reference: `&mut i32` LL | let g = &x; -LL | *x = 0; //~ ERROR cannot assign to `*x` which is behind a `&` reference +LL | *x = 0; | ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written error[E0506]: cannot assign to `*x` because it is borrowed - --> $DIR/issue-57989.rs:7:5 + --> $DIR/issue-57989.rs:5:5 | LL | let g = &x; | -- borrow of `*x` occurs here -LL | *x = 0; //~ ERROR cannot assign to `*x` which is behind a `&` reference +LL | *x = 0; | ^^^^^^ assignment to borrowed `*x` occurs here -LL | //~| ERROR cannot assign to `*x` because it is borrowed +LL | LL | g; | - borrow later used here error: aborting due to 2 previous errors -Some errors occurred: E0506, E0594. -For more information about an error, try `rustc --explain E0506`. +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/nll/issue-58053.rs b/src/test/ui/nll/issue-58053.rs index d4338905ed2df..0992e3a85ae94 100644 --- a/src/test/ui/nll/issue-58053.rs +++ b/src/test/ui/nll/issue-58053.rs @@ -1,4 +1,3 @@ -#![allow(warnings)] #![feature(nll)] fn main() { diff --git a/src/test/ui/nll/issue-58053.stderr b/src/test/ui/nll/issue-58053.stderr index 9048983318b36..297681ff4038a 100644 --- a/src/test/ui/nll/issue-58053.stderr +++ b/src/test/ui/nll/issue-58053.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/issue-58053.rs:7:33 + --> $DIR/issue-58053.rs:6:33 | LL | let f = |x: &i32| -> &i32 { x }; | - ---- ^ returning this value requires that `'1` must outlive `'2` @@ -8,7 +8,7 @@ LL | let f = |x: &i32| -> &i32 { x }; | let's call the lifetime of this reference `'1` error: lifetime may not live long enough - --> $DIR/issue-58053.rs:11:25 + --> $DIR/issue-58053.rs:10:25 | LL | let g = |x: &i32| { x }; | - - ^ returning this value requires that `'1` must outlive `'2` diff --git a/src/test/ui/nll/issue-58299.rs b/src/test/ui/nll/issue-58299.rs index 9267cac5dd3d7..3277a9db8ec46 100644 --- a/src/test/ui/nll/issue-58299.rs +++ b/src/test/ui/nll/issue-58299.rs @@ -1,4 +1,3 @@ -#![allow(dead_code)] #![feature(nll)] struct A<'a>(&'a ()); diff --git a/src/test/ui/nll/issue-58299.stderr b/src/test/ui/nll/issue-58299.stderr index b87d0de51a37e..aba07542d026e 100644 --- a/src/test/ui/nll/issue-58299.stderr +++ b/src/test/ui/nll/issue-58299.stderr @@ -1,19 +1,19 @@ error: lifetime may not live long enough - --> $DIR/issue-58299.rs:17:9 + --> $DIR/issue-58299.rs:16:9 | LL | fn foo<'a>(x: i32) { | -- lifetime `'a` defined here ... -LL | A::<'a>::X..=A::<'static>::X => (), //~ ERROR lifetime may not live long enough +LL | A::<'a>::X..=A::<'static>::X => (), | ^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/issue-58299.rs:25:27 + --> $DIR/issue-58299.rs:24:27 | LL | fn bar<'a>(x: i32) { | -- lifetime `'a` defined here ... -LL | A::<'static>::X..=A::<'a>::X => (), //~ ERROR lifetime may not live long enough +LL | A::<'static>::X..=A::<'a>::X => (), | ^^^^^^^^^^ requires that `'a` must outlive `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/issue-61311-normalize.rs b/src/test/ui/nll/issue-61311-normalize.rs new file mode 100644 index 0000000000000..1164e9ef2d62f --- /dev/null +++ b/src/test/ui/nll/issue-61311-normalize.rs @@ -0,0 +1,34 @@ +// Regression test for #61311 +// We would ICE after failing to normalize `Self::Proj` in the `impl` below. + +// compile-pass + +pub struct Unit; +trait Obj {} + +trait Bound {} +impl Bound for Unit {} + +pub trait HasProj { + type Proj; +} + +impl HasProj for T { + type Proj = Unit; +} + +trait HasProjFn { + type Proj; + fn the_fn(_: Self::Proj); +} + +impl HasProjFn for Unit +where + Box: HasProj, + as HasProj>::Proj: Bound, +{ + type Proj = Unit; + fn the_fn(_: Self::Proj) {} +} + +fn main() {} diff --git a/src/test/ui/nll/issue-61320-normalize.rs b/src/test/ui/nll/issue-61320-normalize.rs new file mode 100644 index 0000000000000..a36ccd36113b5 --- /dev/null +++ b/src/test/ui/nll/issue-61320-normalize.rs @@ -0,0 +1,160 @@ +// Regression test for #61320 +// This is the same issue as #61311, just a larger test case. + +// compile-pass + +pub struct AndThen +where + A: Future, + B: IntoFuture, +{ + state: (A, B::Future, F), +} + +pub struct FutureResult { + inner: Option>, +} + +impl Future for FutureResult { + type Item = T; + type Error = E; + + fn poll(&mut self) -> Poll { + unimplemented!() + } +} + +pub type Poll = Result; + +impl Future for AndThen +where + A: Future, + B: IntoFuture, + F: FnOnce(A::Item) -> B, +{ + type Item = B::Item; + type Error = B::Error; + + fn poll(&mut self) -> Poll { + unimplemented!() + } +} + +pub trait Future { + type Item; + + type Error; + + fn poll(&mut self) -> Poll; + + fn and_then(self, f: F) -> AndThen + where + F: FnOnce(Self::Item) -> B, + B: IntoFuture, + Self: Sized, + { + unimplemented!() + } +} + +pub trait IntoFuture { + /// The future that this type can be converted into. + type Future: Future; + + /// The item that the future may resolve with. + type Item; + /// The error that the future may resolve with. + type Error; + + /// Consumes this object and produces a future. + fn into_future(self) -> Self::Future; +} + +impl IntoFuture for F { + type Future = F; + type Item = F::Item; + type Error = F::Error; + + fn into_future(self) -> F { + self + } +} + +impl Future for ::std::boxed::Box { + type Item = F::Item; + type Error = F::Error; + + fn poll(&mut self) -> Poll { + (**self).poll() + } +} + +impl IntoFuture for Result { + type Future = FutureResult; + type Item = T; + type Error = E; + + fn into_future(self) -> FutureResult { + unimplemented!() + } +} + +struct Request(T); + +trait RequestContext {} +impl RequestContext for T {} +struct NoContext; +impl AsRef for NoContext { + fn as_ref(&self) -> &Self { + &NoContext + } +} + +type BoxedError = Box; +type DefaultFuture = Box + Send>; + +trait Guard: Sized { + type Result: IntoFuture; + fn from_request(request: &Request<()>) -> Self::Result; +} + +trait FromRequest: Sized { + type Context; + type Future: Future + Send; + fn from_request(request: Request<()>) -> Self::Future; +} + +struct MyGuard; +impl Guard for MyGuard { + type Result = Result; + fn from_request(_request: &Request<()>) -> Self::Result { + Ok(MyGuard) + } +} + +struct Generic { + _inner: I, +} + +impl FromRequest for Generic +where + MyGuard: Guard, + ::Result: IntoFuture, + <::Result as IntoFuture>::Future: Send, + I: FromRequest, +{ + type Future = DefaultFuture; + type Context = NoContext; + fn from_request(headers: Request<()>) -> DefaultFuture { + let _future = ::from_request(&headers) + .into_future() + .and_then(move |_| { + ::from_request(headers) + .into_future() + .and_then(move |fld_inner| Ok(Generic { _inner: fld_inner }).into_future()) + }); + panic!(); + } +} + +fn main() {} diff --git a/src/test/ui/nll/issue-61424.rs b/src/test/ui/nll/issue-61424.rs new file mode 100644 index 0000000000000..44c8e9f7256f5 --- /dev/null +++ b/src/test/ui/nll/issue-61424.rs @@ -0,0 +1,7 @@ +#![deny(unused_mut)] + +fn main() { + let mut x; //~ ERROR: variable does not need to be mutable + x = String::new(); + dbg!(x); +} diff --git a/src/test/ui/nll/issue-61424.stderr b/src/test/ui/nll/issue-61424.stderr new file mode 100644 index 0000000000000..ae336b2fe1c03 --- /dev/null +++ b/src/test/ui/nll/issue-61424.stderr @@ -0,0 +1,16 @@ +error: variable does not need to be mutable + --> $DIR/issue-61424.rs:4:9 + | +LL | let mut x; + | ----^ + | | + | help: remove this `mut` + | +note: lint level defined here + --> $DIR/issue-61424.rs:1:9 + | +LL | #![deny(unused_mut)] + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/nll/issue-62007-assign-const-index.rs b/src/test/ui/nll/issue-62007-assign-const-index.rs new file mode 100644 index 0000000000000..3ea5d3a7ad007 --- /dev/null +++ b/src/test/ui/nll/issue-62007-assign-const-index.rs @@ -0,0 +1,32 @@ +// Issue #62007: assigning over a const-index projection of an array +// (in this case, `list[I] = n;`) should in theory be able to kill all borrows +// of `list[0]`, so that `list[0]` could be borrowed on the next +// iteration through the loop. +// +// Currently the compiler does not allow this. We may want to consider +// loosening that restriction in the future. (However, doing so would +// at *least* require T-lang team approval, and probably an RFC; e.g. +// such loosening might make complicate the user's mental mode; it +// also would make code more brittle in the face of refactorings that +// replace constants with variables. + +#![allow(dead_code)] + +struct List { + value: T, + next: Option>>, +} + +fn to_refs(mut list: [&mut List; 2]) -> Vec<&mut T> { + let mut result = vec![]; + loop { + result.push(&mut list[0].value); //~ ERROR cannot borrow `list[_].value` as mutable + if let Some(n) = list[0].next.as_mut() { //~ ERROR cannot borrow `list[_].next` as mutable + list[0] = n; + } else { + return result; + } + } +} + +fn main() {} diff --git a/src/test/ui/nll/issue-62007-assign-const-index.stderr b/src/test/ui/nll/issue-62007-assign-const-index.stderr new file mode 100644 index 0000000000000..758a14d017705 --- /dev/null +++ b/src/test/ui/nll/issue-62007-assign-const-index.stderr @@ -0,0 +1,27 @@ +error[E0499]: cannot borrow `list[_].value` as mutable more than once at a time + --> $DIR/issue-62007-assign-const-index.rs:23:21 + | +LL | fn to_refs(mut list: [&mut List; 2]) -> Vec<&mut T> { + | - let's call the lifetime of this reference `'1` +... +LL | result.push(&mut list[0].value); + | ^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop +... +LL | return result; + | ------ returning this value requires that `list[_].value` is borrowed for `'1` + +error[E0499]: cannot borrow `list[_].next` as mutable more than once at a time + --> $DIR/issue-62007-assign-const-index.rs:24:26 + | +LL | fn to_refs(mut list: [&mut List; 2]) -> Vec<&mut T> { + | - let's call the lifetime of this reference `'1` +... +LL | if let Some(n) = list[0].next.as_mut() { + | ^^^^^^^^^^^^--------- + | | + | mutable borrow starts here in previous iteration of loop + | argument requires that `list[_].next` is borrowed for `'1` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/nll/issue-62007-assign-differing-fields.rs b/src/test/ui/nll/issue-62007-assign-differing-fields.rs new file mode 100644 index 0000000000000..29d92b7b85c12 --- /dev/null +++ b/src/test/ui/nll/issue-62007-assign-differing-fields.rs @@ -0,0 +1,25 @@ +// Double-check we didn't go too far with our resolution to issue +// #62007: assigning over a field projection (`list.1 = n;` in this +// case) should kill only borrows of `list.1`; `list.0` can *not* +// necessarily be borrowed on the next iteration through the loop. + +#![allow(dead_code)] + +struct List { + value: T, + next: Option>>, +} + +fn to_refs<'a, T>(mut list: (&'a mut List, &'a mut List)) -> Vec<&'a mut T> { + let mut result = vec![]; + loop { + result.push(&mut (list.0).value); //~ ERROR cannot borrow `list.0.value` as mutable + if let Some(n) = (list.0).next.as_mut() { //~ ERROR cannot borrow `list.0.next` as mutable + list.1 = n; + } else { + return result; + } + } +} + +fn main() {} diff --git a/src/test/ui/nll/issue-62007-assign-differing-fields.stderr b/src/test/ui/nll/issue-62007-assign-differing-fields.stderr new file mode 100644 index 0000000000000..f942d7628b507 --- /dev/null +++ b/src/test/ui/nll/issue-62007-assign-differing-fields.stderr @@ -0,0 +1,27 @@ +error[E0499]: cannot borrow `list.0.value` as mutable more than once at a time + --> $DIR/issue-62007-assign-differing-fields.rs:16:21 + | +LL | fn to_refs<'a, T>(mut list: (&'a mut List, &'a mut List)) -> Vec<&'a mut T> { + | -- lifetime `'a` defined here +... +LL | result.push(&mut (list.0).value); + | ^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop +... +LL | return result; + | ------ returning this value requires that `list.0.value` is borrowed for `'a` + +error[E0499]: cannot borrow `list.0.next` as mutable more than once at a time + --> $DIR/issue-62007-assign-differing-fields.rs:17:26 + | +LL | fn to_refs<'a, T>(mut list: (&'a mut List, &'a mut List)) -> Vec<&'a mut T> { + | -- lifetime `'a` defined here +... +LL | if let Some(n) = (list.0).next.as_mut() { + | ^^^^^^^^^^^^^--------- + | | + | mutable borrow starts here in previous iteration of loop + | argument requires that `list.0.next` is borrowed for `'a` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/nll/loan_ends_mid_block_pair.rs b/src/test/ui/nll/loan_ends_mid_block_pair.rs index bad214deac129..acd6ec706080d 100644 --- a/src/test/ui/nll/loan_ends_mid_block_pair.rs +++ b/src/test/ui/nll/loan_ends_mid_block_pair.rs @@ -1,5 +1,3 @@ -// compile-flags:-Zborrowck=compare - #![allow(warnings)] #![feature(rustc_attrs)] @@ -12,12 +10,9 @@ fn nll_fail() { let c = &mut data.0; capitalize(c); data.0 = 'e'; - //~^ ERROR (Ast) [E0506] - //~| ERROR (Mir) [E0506] + //~^ ERROR [E0506] data.0 = 'f'; - //~^ ERROR (Ast) [E0506] data.0 = 'g'; - //~^ ERROR (Ast) [E0506] capitalize(c); } @@ -26,11 +21,8 @@ fn nll_ok() { let c = &mut data.0; capitalize(c); data.0 = 'e'; - //~^ ERROR (Ast) [E0506] data.0 = 'f'; - //~^ ERROR (Ast) [E0506] data.0 = 'g'; - //~^ ERROR (Ast) [E0506] } fn capitalize(_: &mut char) { diff --git a/src/test/ui/nll/loan_ends_mid_block_pair.stderr b/src/test/ui/nll/loan_ends_mid_block_pair.stderr index 85703bda31c4e..eb8442b31d7c7 100644 --- a/src/test/ui/nll/loan_ends_mid_block_pair.stderr +++ b/src/test/ui/nll/loan_ends_mid_block_pair.stderr @@ -1,59 +1,5 @@ -error[E0506]: cannot assign to `data.0` because it is borrowed (Ast) - --> $DIR/loan_ends_mid_block_pair.rs:14:5 - | -LL | let c = &mut data.0; - | ------ borrow of `data.0` occurs here -LL | capitalize(c); -LL | data.0 = 'e'; - | ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here - -error[E0506]: cannot assign to `data.0` because it is borrowed (Ast) - --> $DIR/loan_ends_mid_block_pair.rs:17:5 - | -LL | let c = &mut data.0; - | ------ borrow of `data.0` occurs here -... -LL | data.0 = 'f'; - | ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here - -error[E0506]: cannot assign to `data.0` because it is borrowed (Ast) - --> $DIR/loan_ends_mid_block_pair.rs:19:5 - | -LL | let c = &mut data.0; - | ------ borrow of `data.0` occurs here -... -LL | data.0 = 'g'; - | ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here - -error[E0506]: cannot assign to `data.0` because it is borrowed (Ast) - --> $DIR/loan_ends_mid_block_pair.rs:28:5 - | -LL | let c = &mut data.0; - | ------ borrow of `data.0` occurs here -LL | capitalize(c); -LL | data.0 = 'e'; - | ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here - -error[E0506]: cannot assign to `data.0` because it is borrowed (Ast) - --> $DIR/loan_ends_mid_block_pair.rs:30:5 - | -LL | let c = &mut data.0; - | ------ borrow of `data.0` occurs here -... -LL | data.0 = 'f'; - | ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here - -error[E0506]: cannot assign to `data.0` because it is borrowed (Ast) - --> $DIR/loan_ends_mid_block_pair.rs:32:5 - | -LL | let c = &mut data.0; - | ------ borrow of `data.0` occurs here -... -LL | data.0 = 'g'; - | ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here - -error[E0506]: cannot assign to `data.0` because it is borrowed (Mir) - --> $DIR/loan_ends_mid_block_pair.rs:14:5 +error[E0506]: cannot assign to `data.0` because it is borrowed + --> $DIR/loan_ends_mid_block_pair.rs:12:5 | LL | let c = &mut data.0; | ----------- borrow of `data.0` occurs here @@ -64,6 +10,6 @@ LL | data.0 = 'e'; LL | capitalize(c); | - borrow later used here -error: aborting due to 7 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/nll/loan_ends_mid_block_vec.rs b/src/test/ui/nll/loan_ends_mid_block_vec.rs index 682e7e3e96fee..2edcdef0af86c 100644 --- a/src/test/ui/nll/loan_ends_mid_block_vec.rs +++ b/src/test/ui/nll/loan_ends_mid_block_vec.rs @@ -1,5 +1,3 @@ -// compile-flags:-Zborrowck=compare - #![allow(warnings)] #![feature(rustc_attrs)] @@ -11,14 +9,11 @@ fn nll_fail() { let slice = &mut data; capitalize(slice); data.push('d'); - //~^ ERROR (Ast) [E0499] - //~| ERROR (Mir) [E0499] + //~^ ERROR [E0499] data.push('e'); - //~^ ERROR (Ast) [E0499] - //~| ERROR (Mir) [E0499] + //~^ ERROR [E0499] data.push('f'); - //~^ ERROR (Ast) [E0499] - //~| ERROR (Mir) [E0499] + //~^ ERROR [E0499] capitalize(slice); } @@ -27,11 +22,8 @@ fn nll_ok() { let slice = &mut data; capitalize(slice); data.push('d'); - //~^ ERROR (Ast) [E0499] data.push('e'); - //~^ ERROR (Ast) [E0499] data.push('f'); - //~^ ERROR (Ast) [E0499] } fn capitalize(_: &mut [char]) { diff --git a/src/test/ui/nll/loan_ends_mid_block_vec.stderr b/src/test/ui/nll/loan_ends_mid_block_vec.stderr index 18d4e010946bb..c0b97bea348c4 100644 --- a/src/test/ui/nll/loan_ends_mid_block_vec.stderr +++ b/src/test/ui/nll/loan_ends_mid_block_vec.stderr @@ -1,77 +1,5 @@ -error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast) - --> $DIR/loan_ends_mid_block_vec.rs:13:5 - | -LL | let slice = &mut data; - | ---- first mutable borrow occurs here -LL | capitalize(slice); -LL | data.push('d'); - | ^^^^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast) - --> $DIR/loan_ends_mid_block_vec.rs:16:5 - | -LL | let slice = &mut data; - | ---- first mutable borrow occurs here -... -LL | data.push('e'); - | ^^^^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast) - --> $DIR/loan_ends_mid_block_vec.rs:19:5 - | -LL | let slice = &mut data; - | ---- first mutable borrow occurs here -... -LL | data.push('f'); - | ^^^^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast) - --> $DIR/loan_ends_mid_block_vec.rs:29:5 - | -LL | let slice = &mut data; - | ---- first mutable borrow occurs here -LL | capitalize(slice); -LL | data.push('d'); - | ^^^^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast) - --> $DIR/loan_ends_mid_block_vec.rs:31:5 - | -LL | let slice = &mut data; - | ---- first mutable borrow occurs here -... -LL | data.push('e'); - | ^^^^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast) - --> $DIR/loan_ends_mid_block_vec.rs:33:5 - | -LL | let slice = &mut data; - | ---- first mutable borrow occurs here -... -LL | data.push('f'); - | ^^^^ second mutable borrow occurs here -LL | //~^ ERROR (Ast) [E0499] -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `data` as mutable more than once at a time (Mir) - --> $DIR/loan_ends_mid_block_vec.rs:13:5 +error[E0499]: cannot borrow `data` as mutable more than once at a time + --> $DIR/loan_ends_mid_block_vec.rs:11:5 | LL | let slice = &mut data; | --------- first mutable borrow occurs here @@ -82,8 +10,8 @@ LL | data.push('d'); LL | capitalize(slice); | ----- first borrow later used here -error[E0499]: cannot borrow `data` as mutable more than once at a time (Mir) - --> $DIR/loan_ends_mid_block_vec.rs:16:5 +error[E0499]: cannot borrow `data` as mutable more than once at a time + --> $DIR/loan_ends_mid_block_vec.rs:13:5 | LL | let slice = &mut data; | --------- first mutable borrow occurs here @@ -94,18 +22,18 @@ LL | data.push('e'); LL | capitalize(slice); | ----- first borrow later used here -error[E0499]: cannot borrow `data` as mutable more than once at a time (Mir) - --> $DIR/loan_ends_mid_block_vec.rs:19:5 +error[E0499]: cannot borrow `data` as mutable more than once at a time + --> $DIR/loan_ends_mid_block_vec.rs:15:5 | LL | let slice = &mut data; | --------- first mutable borrow occurs here ... LL | data.push('f'); | ^^^^ second mutable borrow occurs here -... +LL | LL | capitalize(slice); | ----- first borrow later used here -error: aborting due to 9 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/nll/local-outlives-static-via-hrtb.rs b/src/test/ui/nll/local-outlives-static-via-hrtb.rs new file mode 100644 index 0000000000000..5f1f9b3a7f229 --- /dev/null +++ b/src/test/ui/nll/local-outlives-static-via-hrtb.rs @@ -0,0 +1,26 @@ +// Test that we handle the case when a local variable is borrowed for `'static` +// due to an outlives constraint involving a region in an incompatible universe + +pub trait Outlives<'this> {} + +impl<'this, T> Outlives<'this> for T where T: 'this {} +trait Reference { + type AssociatedType; +} + +impl<'a, T: 'a> Reference for &'a T { + type AssociatedType = &'a (); +} + +fn assert_static_via_hrtb(_: G) where for<'a> G: Outlives<'a> {} + +fn assert_static_via_hrtb_with_assoc_type(_: &'_ T) +where + for<'a> &'a T: Reference, +{} + +fn main() { + let local = 0; + assert_static_via_hrtb(&local); //~ ERROR `local` does not live long enough + assert_static_via_hrtb_with_assoc_type(&&local); //~ ERROR `local` does not live long enough +} diff --git a/src/test/ui/nll/local-outlives-static-via-hrtb.stderr b/src/test/ui/nll/local-outlives-static-via-hrtb.stderr new file mode 100644 index 0000000000000..61009da49ffed --- /dev/null +++ b/src/test/ui/nll/local-outlives-static-via-hrtb.stderr @@ -0,0 +1,26 @@ +error[E0597]: `local` does not live long enough + --> $DIR/local-outlives-static-via-hrtb.rs:24:28 + | +LL | assert_static_via_hrtb(&local); + | -----------------------^^^^^^- + | | | + | | borrowed value does not live long enough + | argument requires that `local` is borrowed for `'static` +LL | assert_static_via_hrtb_with_assoc_type(&&local); +LL | } + | - `local` dropped here while still borrowed + +error[E0597]: `local` does not live long enough + --> $DIR/local-outlives-static-via-hrtb.rs:25:45 + | +LL | assert_static_via_hrtb_with_assoc_type(&&local); + | ----------------------------------------^^^^^^- + | | | + | | borrowed value does not live long enough + | argument requires that `local` is borrowed for `'static` +LL | } + | - `local` dropped here while still borrowed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr index a855b28a978dd..d37c52444ac0d 100644 --- a/src/test/ui/nll/match-cfg-fake-edges.stderr +++ b/src/test/ui/nll/match-cfg-fake-edges.stderr @@ -1,7 +1,7 @@ error[E0381]: use of possibly uninitialized variable: `x` --> $DIR/match-cfg-fake-edges.rs:23:13 | -LL | x; //~ ERROR use of possibly uninitialized variable: `x` +LL | x; | ^ use of possibly uninitialized `x` error[E0382]: use of moved value: `x` @@ -13,7 +13,7 @@ LL | let x = String::new(); LL | false if { drop(x); true } => 1, | - value moved here LL | true => { -LL | x; //~ ERROR use of moved value: `x` +LL | x; | ^ value used here after move error[E0503]: cannot use `y.1` because it was mutably borrowed @@ -22,7 +22,7 @@ error[E0503]: cannot use `y.1` because it was mutably borrowed LL | let r = &mut y.1; | -------- borrow of `y.1` occurs here ... -LL | (false, true) => 1, //~ ERROR cannot use `y.1` because it was mutably borrowed +LL | (false, true) => 1, | ^^^^ use of borrowed `y.1` LL | (true, _) => { LL | r; @@ -30,5 +30,5 @@ LL | r; error: aborting due to 3 previous errors -Some errors occurred: E0381, E0382, E0503. +Some errors have detailed explanations: E0381, E0382, E0503. For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/nll/match-guards-always-borrow.ast.nll.stderr b/src/test/ui/nll/match-guards-always-borrow.ast.nll.stderr deleted file mode 100644 index 4d647949038ac..0000000000000 --- a/src/test/ui/nll/match-guards-always-borrow.ast.nll.stderr +++ /dev/null @@ -1,22 +0,0 @@ -warning[E0507]: cannot move out of borrowed content - --> $DIR/match-guards-always-borrow.rs:13:13 - | -LL | (|| { let bar = foo; bar.take() })(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - -error: compilation successful - --> $DIR/match-guards-always-borrow.rs:47:1 - | -LL | / fn main() { //[ast]~ ERROR compilation successful -LL | | should_reject_destructive_mutate_in_guard(); -LL | | allow_mutate_in_arm_body(); -LL | | allow_move_into_arm_body(); -LL | | } - | |_^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/nll/match-guards-always-borrow.ast.stderr b/src/test/ui/nll/match-guards-always-borrow.ast.stderr deleted file mode 100644 index 92d76d577d55f..0000000000000 --- a/src/test/ui/nll/match-guards-always-borrow.ast.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error: compilation successful - --> $DIR/match-guards-always-borrow.rs:47:1 - | -LL | / fn main() { //[ast]~ ERROR compilation successful -LL | | should_reject_destructive_mutate_in_guard(); -LL | | allow_mutate_in_arm_body(); -LL | | allow_move_into_arm_body(); -LL | | } - | |_^ - -error: aborting due to previous error - diff --git a/src/test/ui/nll/match-guards-always-borrow.mir.stderr b/src/test/ui/nll/match-guards-always-borrow.mir.stderr deleted file mode 100644 index 3e90c5a154259..0000000000000 --- a/src/test/ui/nll/match-guards-always-borrow.mir.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/match-guards-always-borrow.rs:13:13 - | -LL | (|| { let bar = foo; bar.take() })(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/nll/match-guards-always-borrow.rs b/src/test/ui/nll/match-guards-always-borrow.rs index ec4eed6797600..d423730bdbc35 100644 --- a/src/test/ui/nll/match-guards-always-borrow.rs +++ b/src/test/ui/nll/match-guards-always-borrow.rs @@ -1,7 +1,4 @@ -//revisions: ast mir -//[mir] compile-flags: -Z borrowck=mir - -#![feature(rustc_attrs)] +#![feature(nll)] // Here is arielb1's basic example from rust-lang/rust#27282 // that AST borrowck is flummoxed by: @@ -11,7 +8,7 @@ fn should_reject_destructive_mutate_in_guard() { None => {}, ref mut foo if { (|| { let bar = foo; bar.take() })(); - //[mir]~^ ERROR cannot move out of borrowed content [E0507] + //~^ ERROR cannot move out of `foo` in pattern guard [E0507] false } => { }, Some(s) => std::process::exit(*s), } @@ -39,12 +36,7 @@ fn allow_move_into_arm_body() { } } -// Since this is a compile-fail test that is explicitly encoding the -// different behavior of AST- vs MIR-borrowck where AST-borrowck does -// not error, we need to use rustc_error to placate the test harness -// that wants *some* error to occur. -#[rustc_error] -fn main() { //[ast]~ ERROR compilation successful +fn main() { should_reject_destructive_mutate_in_guard(); allow_mutate_in_arm_body(); allow_move_into_arm_body(); diff --git a/src/test/ui/nll/match-guards-always-borrow.stderr b/src/test/ui/nll/match-guards-always-borrow.stderr new file mode 100644 index 0000000000000..5b49db45a52ec --- /dev/null +++ b/src/test/ui/nll/match-guards-always-borrow.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of `foo` in pattern guard + --> $DIR/match-guards-always-borrow.rs:10:14 + | +LL | (|| { let bar = foo; bar.take() })(); + | ^^ --- + | | | + | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs due to use in closure + | move out of `foo` occurs here + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/nll/match-guards-partially-borrow.stderr b/src/test/ui/nll/match-guards-partially-borrow.stderr index baff2fda9f5d1..3d9b67b4ea660 100644 --- a/src/test/ui/nll/match-guards-partially-borrow.stderr +++ b/src/test/ui/nll/match-guards-partially-borrow.stderr @@ -4,7 +4,7 @@ error[E0510]: cannot assign `q` in match guard LL | match q { | - value is immutable in match guard ... -LL | q = true; //~ ERROR +LL | q = true; | ^^^^^^^^ cannot assign error[E0510]: cannot assign `r` in match guard @@ -13,7 +13,7 @@ error[E0510]: cannot assign `r` in match guard LL | match r { | - value is immutable in match guard ... -LL | r = true; //~ ERROR +LL | r = true; | ^^^^^^^^ cannot assign error[E0510]: cannot assign `t` in match guard @@ -22,7 +22,7 @@ error[E0510]: cannot assign `t` in match guard LL | match t { | - value is immutable in match guard ... -LL | t = true; //~ ERROR +LL | t = true; | ^^^^^^^^ cannot assign error[E0510]: cannot mutably borrow `x.0` in match guard @@ -31,7 +31,7 @@ error[E0510]: cannot mutably borrow `x.0` in match guard LL | match x { | - value is immutable in match guard ... -LL | Some(ref mut r) => *r = None, //~ ERROR +LL | Some(ref mut r) => *r = None, | ^^^^^^^^^ cannot mutably borrow error[E0506]: cannot assign to `t` because it is borrowed @@ -39,7 +39,7 @@ error[E0506]: cannot assign to `t` because it is borrowed | LL | s if { | - borrow of `t` occurs here -LL | t = !t; //~ ERROR +LL | t = !t; | ^^^^^^ assignment to borrowed `t` occurs here LL | false LL | } => (), // What value should `s` have in the arm? @@ -51,7 +51,7 @@ error[E0510]: cannot assign `y` in match guard LL | match *y { | -- value is immutable in match guard ... -LL | y = &true; //~ ERROR +LL | y = &true; | ^^^^^^^^^ cannot assign error[E0510]: cannot assign `z` in match guard @@ -60,7 +60,7 @@ error[E0510]: cannot assign `z` in match guard LL | match z { | - value is immutable in match guard ... -LL | z = &true; //~ ERROR +LL | z = &true; | ^^^^^^^^^ cannot assign error[E0510]: cannot assign `a` in match guard @@ -69,7 +69,7 @@ error[E0510]: cannot assign `a` in match guard LL | match a { | - value is immutable in match guard ... -LL | a = &true; //~ ERROR +LL | a = &true; | ^^^^^^^^^ cannot assign error[E0510]: cannot assign `b` in match guard @@ -78,10 +78,10 @@ error[E0510]: cannot assign `b` in match guard LL | match b { | - value is immutable in match guard ... -LL | b = &true; //~ ERROR +LL | b = &true; | ^^^^^^^^^ cannot assign error: aborting due to 9 previous errors -Some errors occurred: E0506, E0510. +Some errors have detailed explanations: E0506, E0510. For more information about an error, try `rustc --explain E0506`. diff --git a/src/test/ui/nll/match-on-borrowed.stderr b/src/test/ui/nll/match-on-borrowed.stderr index 2d34dd7805dbf..9f804dfb3d7be 100644 --- a/src/test/ui/nll/match-on-borrowed.stderr +++ b/src/test/ui/nll/match-on-borrowed.stderr @@ -4,7 +4,7 @@ error[E0503]: cannot use `e` because it was mutably borrowed LL | E::V(ref mut x, _) => x, | --------- borrow of `e.0` occurs here ... -LL | E::V(_, r) => (), //~ ERROR +LL | E::V(_, r) => (), | ^^^^^^^^^^ use of borrowed `e.0` ... LL | x; @@ -16,7 +16,7 @@ error[E0503]: cannot use `*f` because it was mutably borrowed LL | E::V(ref mut x, _) => x, | --------- borrow of `f.0` occurs here ... -LL | E::V(_, r) => (), //~ ERROR +LL | E::V(_, r) => (), | ^^^^^^^^^^ use of borrowed `f.0` ... LL | x; @@ -28,7 +28,7 @@ error[E0503]: cannot use `t` because it was mutably borrowed LL | let x = &mut t; | ------ borrow of `t` occurs here LL | match t { -LL | true => (), //~ ERROR +LL | true => (), | ^^^^ use of borrowed `t` ... LL | x; @@ -37,10 +37,10 @@ LL | x; error[E0381]: use of possibly uninitialized variable: `n` --> $DIR/match-on-borrowed.rs:92:11 | -LL | match n {} //~ ERROR +LL | match n {} | ^ use of possibly uninitialized `n` error: aborting due to 4 previous errors -Some errors occurred: E0381, E0503. +Some errors have detailed explanations: E0381, E0503. For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs index 5b609820a237f..1de32ddf531c8 100644 --- a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs +++ b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs @@ -1,6 +1,3 @@ -#![allow(warnings)] -#![feature(nll)] - struct Wrap<'p> { p: &'p mut i32 } impl<'p> Drop for Wrap<'p> { diff --git a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr index 3ff778675bcf4..80e297807465d 100644 --- a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr +++ b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr @@ -1,10 +1,10 @@ error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/maybe-initialized-drop-implicit-fragment-drop.rs:20:5 + --> $DIR/maybe-initialized-drop-implicit-fragment-drop.rs:17:5 | LL | let wrap = Wrap { p: &mut x }; | ------ borrow of `x` occurs here ... -LL | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506] +LL | x = 1; | ^^^^^ assignment to borrowed `x` occurs here LL | // FIXME ^ Should not error in the future with implicit dtors, only manually implemented ones LL | } diff --git a/src/test/ui/nll/maybe-initialized-drop-with-fragment.stderr b/src/test/ui/nll/maybe-initialized-drop-with-fragment.stderr index 5585e69f090a8..e4efd98253c0d 100644 --- a/src/test/ui/nll/maybe-initialized-drop-with-fragment.stderr +++ b/src/test/ui/nll/maybe-initialized-drop-with-fragment.stderr @@ -4,7 +4,7 @@ error[E0506]: cannot assign to `x` because it is borrowed LL | let wrap = Wrap { p: &mut x }; | ------ borrow of `x` occurs here ... -LL | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506] +LL | x = 1; | ^^^^^ assignment to borrowed `x` occurs here LL | } | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>` diff --git a/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr b/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr index aa9544927f899..0e2be68c6d3ab 100644 --- a/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr +++ b/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr @@ -4,7 +4,7 @@ error[E0506]: cannot assign to `x` because it is borrowed LL | let wrap = Wrap { p: &mut x }; | ------ borrow of `x` occurs here ... -LL | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506] +LL | x = 1; | ^^^^^ assignment to borrowed `x` occurs here LL | // FIXME ^ This currently errors and it should not. LL | } diff --git a/src/test/ui/nll/maybe-initialized-drop.stderr b/src/test/ui/nll/maybe-initialized-drop.stderr index 331f846dfd095..10b9a6dcf5a0b 100644 --- a/src/test/ui/nll/maybe-initialized-drop.stderr +++ b/src/test/ui/nll/maybe-initialized-drop.stderr @@ -3,7 +3,7 @@ error[E0506]: cannot assign to `x` because it is borrowed | LL | let wrap = Wrap { p: &mut x }; | ------ borrow of `x` occurs here -LL | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506] +LL | x = 1; | ^^^^^ assignment to borrowed `x` occurs here LL | } | - borrow might be used here, when `wrap` is dropped and runs the `Drop` code for type `Wrap` diff --git a/src/test/ui/nll/move-errors.rs b/src/test/ui/nll/move-errors.rs index a34163737096c..e0fcd6250322d 100644 --- a/src/test/ui/nll/move-errors.rs +++ b/src/test/ui/nll/move-errors.rs @@ -1,6 +1,3 @@ -#![allow(unused)] -#![feature(nll)] - struct A(String); struct C(D); diff --git a/src/test/ui/nll/move-errors.stderr b/src/test/ui/nll/move-errors.stderr index 86bb8e3a4b33b..7139617a97a4f 100644 --- a/src/test/ui/nll/move-errors.stderr +++ b/src/test/ui/nll/move-errors.stderr @@ -1,100 +1,90 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/move-errors.rs:9:13 +error[E0507]: cannot move out of `*a` which is behind a shared reference + --> $DIR/move-errors.rs:6:13 | LL | let b = *a; | ^^ | | - | cannot move out of borrowed content - | help: consider removing the `*`: `a` + | move occurs because `*a` has type `A`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*a` error[E0508]: cannot move out of type `[A; 1]`, a non-copy array - --> $DIR/move-errors.rs:15:13 + --> $DIR/move-errors.rs:12:13 | LL | let b = a[0]; | ^^^^ | | | cannot move out of here + | move occurs because `a[_]` has type `A`, which does not implement the `Copy` trait | help: consider borrowing here: `&a[0]` -error[E0507]: cannot move out of borrowed content - --> $DIR/move-errors.rs:22:13 +error[E0507]: cannot move out of `**r` which is behind a shared reference + --> $DIR/move-errors.rs:19:13 | LL | let s = **r; | ^^^ | | - | cannot move out of borrowed content - | help: consider removing the `*`: `*r` + | move occurs because `**r` has type `A`, which does not implement the `Copy` trait + | help: consider borrowing here: `&**r` error[E0507]: cannot move out of an `Rc` - --> $DIR/move-errors.rs:30:13 + --> $DIR/move-errors.rs:27:13 | LL | let s = *r; | ^^ | | - | cannot move out of an `Rc` - | help: consider removing the `*`: `r` + | move occurs because value has type `A`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*r` error[E0508]: cannot move out of type `[A; 1]`, a non-copy array - --> $DIR/move-errors.rs:35:13 + --> $DIR/move-errors.rs:32:13 | LL | let a = [A("".to_string())][0]; | ^^^^^^^^^^^^^^^^^^^^^^ | | | cannot move out of here + | move occurs because value has type `A`, which does not implement the `Copy` trait | help: consider borrowing here: `&[A("".to_string())][0]` -error[E0507]: cannot move out of borrowed content - --> $DIR/move-errors.rs:41:16 +error[E0507]: cannot move out of `a.0` which is behind a shared reference + --> $DIR/move-errors.rs:38:16 | LL | let A(s) = *a; - | - ^^ - | | | - | | cannot move out of borrowed content - | | help: consider removing the `*`: `a` + | - ^^ help: consider borrowing here: `&*a` + | | | data moved here - | -note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/move-errors.rs:41:11 - | -LL | let A(s) = *a; - | ^ + | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `D`, which implements the `Drop` trait - --> $DIR/move-errors.rs:47:19 + --> $DIR/move-errors.rs:44:19 | LL | let C(D(s)) = c; | - ^ cannot move out of here | | | data moved here - | -note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/move-errors.rs:47:13 - | -LL | let C(D(s)) = c; - | ^ + | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/move-errors.rs:54:9 +error[E0507]: cannot move out of `*a` which is behind a shared reference + --> $DIR/move-errors.rs:51:9 | LL | b = *a; - | ^^ cannot move out of borrowed content + | ^^ move occurs because `*a` has type `A`, which does not implement the `Copy` trait error[E0508]: cannot move out of type `[B; 1]`, a non-copy array - --> $DIR/move-errors.rs:77:11 + --> $DIR/move-errors.rs:74:11 | LL | match x[0] { | ^^^^ | | | cannot move out of here | help: consider borrowing here: `&x[0]` -LL | //~^ ERROR +LL | LL | B::U(d) => (), | - data moved here LL | B::V(s) => (), | - ...and here | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/move-errors.rs:79:14 + --> $DIR/move-errors.rs:76:14 | LL | B::U(d) => (), | ^ @@ -102,86 +92,71 @@ LL | B::V(s) => (), | ^ error[E0509]: cannot move out of type `D`, which implements the `Drop` trait - --> $DIR/move-errors.rs:86:11 + --> $DIR/move-errors.rs:83:11 | LL | match x { | ^ cannot move out of here ... LL | B::U(D(s)) => (), - | - data moved here - | -note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/move-errors.rs:89:16 - | -LL | B::U(D(s)) => (), - | ^ + | - + | | + | data moved here + | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `D`, which implements the `Drop` trait - --> $DIR/move-errors.rs:95:11 + --> $DIR/move-errors.rs:92:11 | LL | match x { | ^ cannot move out of here ... LL | (D(s), &t) => (), - | - data moved here - | -note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/move-errors.rs:98:12 - | -LL | (D(s), &t) => (), - | ^ + | - + | | + | data moved here + | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/move-errors.rs:95:11 +error[E0507]: cannot move out of `*x.1` which is behind a shared reference + --> $DIR/move-errors.rs:92:11 | LL | match x { - | ^ cannot move out of borrowed content + | ^ ... LL | (D(s), &t) => (), - | - data moved here - | -note: move occurs because `t` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/move-errors.rs:98:17 - | -LL | (D(s), &t) => (), - | ^ + | - + | | + | data moved here + | move occurs because `t` has type `std::string::String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `F`, which implements the `Drop` trait - --> $DIR/move-errors.rs:105:11 + --> $DIR/move-errors.rs:102:11 | LL | match x { | ^ cannot move out of here -LL | //~^ ERROR +LL | LL | F(s, mut t) => (), | - ----- ...and here | | | data moved here | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/move-errors.rs:107:11 + --> $DIR/move-errors.rs:104:11 | LL | F(s, mut t) => (), | ^ ^^^^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/move-errors.rs:113:11 +error[E0507]: cannot move out of `x.0` which is behind a shared reference + --> $DIR/move-errors.rs:110:11 | LL | match *x { - | ^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `x` -LL | //~^ ERROR -LL | Ok(s) | Err(s) => (), - | - data moved here - | -note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait - --> $DIR/move-errors.rs:115:12 - | + | ^^ help: consider borrowing here: `&*x` +LL | LL | Ok(s) | Err(s) => (), - | ^ + | - + | | + | data moved here + | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait error: aborting due to 14 previous errors -Some errors occurred: E0507, E0508, E0509. +Some errors have detailed explanations: E0507, E0508, E0509. For more information about an error, try `rustc --explain E0507`. diff --git a/src/test/ui/nll/move-subpaths-moves-root.rs b/src/test/ui/nll/move-subpaths-moves-root.rs index 72a36ef22dff7..e7caf89e78391 100644 --- a/src/test/ui/nll/move-subpaths-moves-root.rs +++ b/src/test/ui/nll/move-subpaths-moves-root.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - fn main() { let x = (vec![1, 2, 3], ); drop(x.0); diff --git a/src/test/ui/nll/move-subpaths-moves-root.stderr b/src/test/ui/nll/move-subpaths-moves-root.stderr index 8b52cc113ccc5..7030d5b3305f1 100644 --- a/src/test/ui/nll/move-subpaths-moves-root.stderr +++ b/src/test/ui/nll/move-subpaths-moves-root.stderr @@ -1,9 +1,9 @@ error[E0382]: use of moved value: `x` - --> $DIR/move-subpaths-moves-root.rs:6:10 + --> $DIR/move-subpaths-moves-root.rs:4:10 | LL | drop(x.0); | --- value moved here -LL | drop(x); //~ ERROR use of moved value +LL | drop(x); | ^ value used here after partial move | = note: move occurs because `x.0` has type `std::vec::Vec`, which does not implement the `Copy` trait diff --git a/src/test/ui/nll/normalization-bounds-error.rs b/src/test/ui/nll/normalization-bounds-error.rs index d6610e158236c..b6cfcd98732b4 100644 --- a/src/test/ui/nll/normalization-bounds-error.rs +++ b/src/test/ui/nll/normalization-bounds-error.rs @@ -1,7 +1,6 @@ // Check that we error when a bound from the impl is not satisfied when // normalizing an associated type. -#![feature(nll)] trait Visitor<'d> { type Value; } diff --git a/src/test/ui/nll/normalization-bounds-error.stderr b/src/test/ui/nll/normalization-bounds-error.stderr index cd88ceb16d05a..951e73e7fd765 100644 --- a/src/test/ui/nll/normalization-bounds-error.stderr +++ b/src/test/ui/nll/normalization-bounds-error.stderr @@ -1,16 +1,16 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'d` due to conflicting requirements - --> $DIR/normalization-bounds-error.rs:13:1 + --> $DIR/normalization-bounds-error.rs:12:1 | LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime 'd as defined on the function body at 13:14... - --> $DIR/normalization-bounds-error.rs:13:14 +note: first, the lifetime cannot outlive the lifetime 'd as defined on the function body at 12:14... + --> $DIR/normalization-bounds-error.rs:12:14 | LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {} | ^^ -note: ...but the lifetime must also be valid for the lifetime 'a as defined on the function body at 13:18... - --> $DIR/normalization-bounds-error.rs:13:18 +note: ...but the lifetime must also be valid for the lifetime 'a as defined on the function body at 12:18... + --> $DIR/normalization-bounds-error.rs:12:18 | LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {} | ^^ @@ -20,4 +20,3 @@ LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {} error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/nll/normalization-bounds.rs b/src/test/ui/nll/normalization-bounds.rs index ebc19d7cc8350..5d2825ef2d670 100644 --- a/src/test/ui/nll/normalization-bounds.rs +++ b/src/test/ui/nll/normalization-bounds.rs @@ -2,7 +2,6 @@ //run-pass -#![feature(nll)] trait Visitor<'d> { type Value; } diff --git a/src/test/ui/nll/polonius-smoke-test.stderr b/src/test/ui/nll/polonius-smoke-test.stderr index c4aab0b8b1d6a..dbc5b7a019a69 100644 --- a/src/test/ui/nll/polonius-smoke-test.stderr +++ b/src/test/ui/nll/polonius-smoke-test.stderr @@ -1,7 +1,7 @@ error[E0515]: cannot return reference to local variable `x` --> $DIR/polonius-smoke-test.rs:7:5 | -LL | &x //~ ERROR +LL | &x | ^^ returns a reference to data owned by the current function error[E0503]: cannot use `x` because it was mutably borrowed @@ -9,7 +9,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed | LL | let y = &mut x; | ------ borrow of `x` occurs here -LL | let z = x; //~ ERROR +LL | let z = x; | ^ use of borrowed `x` LL | let w = y; | - borrow later used here @@ -19,7 +19,7 @@ error[E0505]: cannot move out of `x` because it is borrowed | LL | let y = &mut *x; | ------- borrow of `*x` occurs here -LL | let z = x; //~ ERROR +LL | let z = x; | ^ move out of `x` occurs here LL | y | - borrow later used here @@ -30,12 +30,12 @@ error[E0505]: cannot move out of `s` because it is borrowed LL | let r = &mut *s; | ------- borrow of `*s` occurs here LL | let tmp = foo(&r); -LL | s; //~ ERROR +LL | s; | ^ move out of `s` occurs here LL | tmp; | --- borrow later used here error: aborting due to 4 previous errors -Some errors occurred: E0503, E0505, E0515. +Some errors have detailed explanations: E0503, E0505, E0515. For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/nll/projection-return.rs b/src/test/ui/nll/projection-return.rs index b2c9a087e0e02..fdf3f59484172 100644 --- a/src/test/ui/nll/projection-return.rs +++ b/src/test/ui/nll/projection-return.rs @@ -16,4 +16,3 @@ fn foo() -> <() as Foo>::Bar { } fn main() { } - diff --git a/src/test/ui/nll/promotable-mutable-zst-doesnt-conflict.rs b/src/test/ui/nll/promotable-mutable-zst-doesnt-conflict.rs index 061d0d69d099e..6d5bdfa4da2f0 100644 --- a/src/test/ui/nll/promotable-mutable-zst-doesnt-conflict.rs +++ b/src/test/ui/nll/promotable-mutable-zst-doesnt-conflict.rs @@ -3,8 +3,6 @@ // run-pass -#![feature(nll)] - pub fn main() { let mut x: Vec<&[i32; 0]> = Vec::new(); for i in 0..10 { diff --git a/src/test/ui/nll/promoted-bounds.rs b/src/test/ui/nll/promoted-bounds.rs index 59b21cf9ac2a9..5f95ae13c58af 100644 --- a/src/test/ui/nll/promoted-bounds.rs +++ b/src/test/ui/nll/promoted-bounds.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - fn shorten_lifetime<'a, 'b, 'min>(a: &'a i32, b: &'b i32) -> &'min i32 where 'a: 'min, diff --git a/src/test/ui/nll/promoted-bounds.stderr b/src/test/ui/nll/promoted-bounds.stderr index 9798f238fc4d0..df347f4e7f0fe 100644 --- a/src/test/ui/nll/promoted-bounds.stderr +++ b/src/test/ui/nll/promoted-bounds.stderr @@ -1,10 +1,10 @@ error[E0597]: `l` does not live long enough - --> $DIR/promoted-bounds.rs:21:17 + --> $DIR/promoted-bounds.rs:19:17 | LL | let ptr = { | --- borrow later stored here LL | let l = 3; -LL | let b = &l; //~ ERROR does not live long enough +LL | let b = &l; | ^^ borrowed value does not live long enough ... LL | }; diff --git a/src/test/ui/nll/promoted-closure-pair.rs b/src/test/ui/nll/promoted-closure-pair.rs index 7b3bbad4c1e0c..cc9f17fd4e6bc 100644 --- a/src/test/ui/nll/promoted-closure-pair.rs +++ b/src/test/ui/nll/promoted-closure-pair.rs @@ -1,7 +1,5 @@ // Check that we handle multiple closures in the same promoted constant. -#![feature(nll)] - fn foo() -> &'static i32 { let z = 0; let p = &(|y| y, |y| y); diff --git a/src/test/ui/nll/promoted-closure-pair.stderr b/src/test/ui/nll/promoted-closure-pair.stderr index 5f4a6037668b5..000bdf85804d8 100644 --- a/src/test/ui/nll/promoted-closure-pair.stderr +++ b/src/test/ui/nll/promoted-closure-pair.stderr @@ -1,7 +1,7 @@ error[E0515]: cannot return value referencing local variable `z` - --> $DIR/promoted-closure-pair.rs:9:5 + --> $DIR/promoted-closure-pair.rs:7:5 | -LL | p.1(&z) //~ ERROR cannot return +LL | p.1(&z) | ^^^^--^ | | | | | `z` is borrowed here diff --git a/src/test/ui/nll/reference-carried-through-struct-field.ast.nll.stderr b/src/test/ui/nll/reference-carried-through-struct-field.ast.nll.stderr deleted file mode 100644 index f28e552901530..0000000000000 --- a/src/test/ui/nll/reference-carried-through-struct-field.ast.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/reference-carried-through-struct-field.rs:11:5 - | -LL | let wrapper = Wrap { w: &mut x }; - | ------ borrow of `x` occurs here -LL | x += 1; //[ast]~ ERROR cannot assign to `x` because it is borrowed [E0506] - | ^^^^^^ use of borrowed `x` -LL | //[mir]~^ ERROR cannot use `x` because it was mutably borrowed [E0503] -LL | *wrapper.w += 1; - | --------------- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/nll/reference-carried-through-struct-field.ast.stderr b/src/test/ui/nll/reference-carried-through-struct-field.ast.stderr deleted file mode 100644 index b19d0b5277cea..0000000000000 --- a/src/test/ui/nll/reference-carried-through-struct-field.ast.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0506]: cannot assign to `x` because it is borrowed - --> $DIR/reference-carried-through-struct-field.rs:11:5 - | -LL | let wrapper = Wrap { w: &mut x }; - | - borrow of `x` occurs here -LL | x += 1; //[ast]~ ERROR cannot assign to `x` because it is borrowed [E0506] - | ^^^^^^ assignment to borrowed `x` occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/nll/reference-carried-through-struct-field.mir.stderr b/src/test/ui/nll/reference-carried-through-struct-field.mir.stderr deleted file mode 100644 index f28e552901530..0000000000000 --- a/src/test/ui/nll/reference-carried-through-struct-field.mir.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/reference-carried-through-struct-field.rs:11:5 - | -LL | let wrapper = Wrap { w: &mut x }; - | ------ borrow of `x` occurs here -LL | x += 1; //[ast]~ ERROR cannot assign to `x` because it is borrowed [E0506] - | ^^^^^^ use of borrowed `x` -LL | //[mir]~^ ERROR cannot use `x` because it was mutably borrowed [E0503] -LL | *wrapper.w += 1; - | --------------- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/nll/reference-carried-through-struct-field.rs b/src/test/ui/nll/reference-carried-through-struct-field.rs index f7903cba6a22c..effd610849940 100644 --- a/src/test/ui/nll/reference-carried-through-struct-field.rs +++ b/src/test/ui/nll/reference-carried-through-struct-field.rs @@ -1,15 +1,9 @@ -//revisions: ast mir -//[mir] compile-flags: -Z borrowck=mir - -#![allow(unused_assignments)] - struct Wrap<'a> { w: &'a mut u32 } fn foo() { let mut x = 22; let wrapper = Wrap { w: &mut x }; - x += 1; //[ast]~ ERROR cannot assign to `x` because it is borrowed [E0506] - //[mir]~^ ERROR cannot use `x` because it was mutably borrowed [E0503] + x += 1; //~ ERROR cannot use `x` because it was mutably borrowed [E0503] *wrapper.w += 1; } diff --git a/src/test/ui/nll/reference-carried-through-struct-field.stderr b/src/test/ui/nll/reference-carried-through-struct-field.stderr new file mode 100644 index 0000000000000..56d878e43033b --- /dev/null +++ b/src/test/ui/nll/reference-carried-through-struct-field.stderr @@ -0,0 +1,13 @@ +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/reference-carried-through-struct-field.rs:6:5 + | +LL | let wrapper = Wrap { w: &mut x }; + | ------ borrow of `x` occurs here +LL | x += 1; + | ^^^^^^ use of borrowed `x` +LL | *wrapper.w += 1; + | --------------- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/nll/region-ends-after-if-condition.nll.stderr b/src/test/ui/nll/region-ends-after-if-condition.nll.stderr index ab8d96d4e9916..322930984a545 100644 --- a/src/test/ui/nll/region-ends-after-if-condition.nll.stderr +++ b/src/test/ui/nll/region-ends-after-if-condition.nll.stderr @@ -1,39 +1,15 @@ -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/region-ends-after-if-condition.rs:19:9 - | -LL | let value = &my_struct.field; - | --------------- immutable borrow occurs here -LL | if value.is_empty() { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/region-ends-after-if-condition.rs:29:9 - | -LL | let value = &my_struct.field; - | --------------- immutable borrow occurs here -LL | if value.is_empty() { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/region-ends-after-if-condition.rs:29:9 +error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable + --> $DIR/region-ends-after-if-condition.rs:26:9 | LL | let value = &my_struct.field; | ---------------- immutable borrow occurs here LL | if value.is_empty() { LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^^^^^^^^^^^^^^^ mutable borrow occurs here ... LL | drop(value); | ----- immutable borrow later used here -error: aborting due to 3 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/nll/region-ends-after-if-condition.rs b/src/test/ui/nll/region-ends-after-if-condition.rs index 1bf13a91b9116..f67de03caf225 100644 --- a/src/test/ui/nll/region-ends-after-if-condition.rs +++ b/src/test/ui/nll/region-ends-after-if-condition.rs @@ -2,8 +2,6 @@ // in the type of `p` includes the points after `&v[0]` up to (but not // including) the call to `use_x`. The `else` branch is not included. -// compile-flags:-Zborrowck=compare - #![allow(warnings)] #![feature(rustc_attrs)] @@ -17,7 +15,6 @@ fn foo1() { let value = &my_struct.field; if value.is_empty() { my_struct.field.push_str("Hello, world!"); - //~^ ERROR (Ast) [E0502] } } @@ -27,8 +24,7 @@ fn foo2() { let value = &my_struct.field; if value.is_empty() { my_struct.field.push_str("Hello, world!"); - //~^ ERROR (Ast) [E0502] - //~| ERROR (Mir) [E0502] + //~^ ERROR [E0502] } drop(value); } diff --git a/src/test/ui/nll/region-ends-after-if-condition.stderr b/src/test/ui/nll/region-ends-after-if-condition.stderr index aa876a0bcb3bf..c03e385790616 100644 --- a/src/test/ui/nll/region-ends-after-if-condition.stderr +++ b/src/test/ui/nll/region-ends-after-if-condition.stderr @@ -1,39 +1,15 @@ -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/region-ends-after-if-condition.rs:19:9 - | -LL | let value = &my_struct.field; - | --------------- immutable borrow occurs here -LL | if value.is_empty() { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/region-ends-after-if-condition.rs:29:9 - | -LL | let value = &my_struct.field; - | --------------- immutable borrow occurs here -LL | if value.is_empty() { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/region-ends-after-if-condition.rs:29:9 +error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable + --> $DIR/region-ends-after-if-condition.rs:26:9 | LL | let value = &my_struct.field; | ---------------- immutable borrow occurs here LL | if value.is_empty() { LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here ... LL | drop(value); | ----- immutable borrow later used here -error: aborting due to 3 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/nll/relate_tys/issue-48071.rs b/src/test/ui/nll/relate_tys/issue-48071.rs index 9b8ac167466f7..72987629848c8 100644 --- a/src/test/ui/nll/relate_tys/issue-48071.rs +++ b/src/test/ui/nll/relate_tys/issue-48071.rs @@ -6,10 +6,6 @@ // // compile-pass -#![allow(warnings)] -#![feature(dyn_trait)] -#![feature(nll)] - trait Foo { fn foo(&self) { } } diff --git a/src/test/ui/nll/relate_tys/universe-violation.stderr b/src/test/ui/nll/relate_tys/universe-violation.stderr index 0a2e0ed7b2db2..6dc78789564c7 100644 --- a/src/test/ui/nll/relate_tys/universe-violation.stderr +++ b/src/test/ui/nll/relate_tys/universe-violation.stderr @@ -1,7 +1,7 @@ error: higher-ranked subtype error --> $DIR/universe-violation.rs:15:31 | -LL | let b: fn(&u32) -> &u32 = a; //~ ERROR higher-ranked subtype error +LL | let b: fn(&u32) -> &u32 = a; | ^ error: aborting due to previous error diff --git a/src/test/ui/nll/relate_tys/var-appears-twice.rs b/src/test/ui/nll/relate_tys/var-appears-twice.rs index 2f227c872598f..77129f4468f04 100644 --- a/src/test/ui/nll/relate_tys/var-appears-twice.rs +++ b/src/test/ui/nll/relate_tys/var-appears-twice.rs @@ -2,9 +2,6 @@ // function returning always its first argument can be upcast to one // that returns either first or second argument. -#![feature(nll)] -#![allow(warnings)] - use std::cell::Cell; type DoubleCell = Cell<(A, A)>; diff --git a/src/test/ui/nll/relate_tys/var-appears-twice.stderr b/src/test/ui/nll/relate_tys/var-appears-twice.stderr index da6930455760d..d032ce6f2132c 100644 --- a/src/test/ui/nll/relate_tys/var-appears-twice.stderr +++ b/src/test/ui/nll/relate_tys/var-appears-twice.stderr @@ -1,7 +1,7 @@ error[E0597]: `b` does not live long enough - --> $DIR/var-appears-twice.rs:23:38 + --> $DIR/var-appears-twice.rs:20:38 | -LL | let x: DoubleCell<_> = make_cell(&b); //~ ERROR +LL | let x: DoubleCell<_> = make_cell(&b); | ------------- ^^ borrowed value does not live long enough | | | type annotation requires that `b` is borrowed for `'static` diff --git a/src/test/ui/nll/return-ref-mut-issue-46557.rs b/src/test/ui/nll/return-ref-mut-issue-46557.rs index b535ab1f5e139..dca61d39dfe81 100644 --- a/src/test/ui/nll/return-ref-mut-issue-46557.rs +++ b/src/test/ui/nll/return-ref-mut-issue-46557.rs @@ -1,8 +1,5 @@ // Regression test for issue #46557 -#![feature(nll)] -#![allow(dead_code)] - fn gimme_static_mut() -> &'static mut u32 { let ref mut x = 1234543; x //~ ERROR cannot return value referencing temporary value [E0515] diff --git a/src/test/ui/nll/return-ref-mut-issue-46557.stderr b/src/test/ui/nll/return-ref-mut-issue-46557.stderr index 7603d8b5bb5c8..720440a0ae5f8 100644 --- a/src/test/ui/nll/return-ref-mut-issue-46557.stderr +++ b/src/test/ui/nll/return-ref-mut-issue-46557.stderr @@ -1,9 +1,9 @@ error[E0515]: cannot return value referencing temporary value - --> $DIR/return-ref-mut-issue-46557.rs:8:5 + --> $DIR/return-ref-mut-issue-46557.rs:5:5 | LL | let ref mut x = 1234543; | ------- temporary value created here -LL | x //~ ERROR cannot return value referencing temporary value [E0515] +LL | x | ^ returns a value referencing data owned by the current function error: aborting due to previous error diff --git a/src/test/ui/nll/return_from_loop.rs b/src/test/ui/nll/return_from_loop.rs index 23a1e0b816cbd..49541089405f2 100644 --- a/src/test/ui/nll/return_from_loop.rs +++ b/src/test/ui/nll/return_from_loop.rs @@ -2,8 +2,6 @@ // in the type of `p` includes the points after `&v[0]` up to (but not // including) the call to `use_x`. The `else` branch is not included. -// compile-flags:-Zborrowck=compare - #![allow(warnings)] #![feature(rustc_attrs)] @@ -20,8 +18,7 @@ fn nll_fail() { let value = &mut my_struct.field; loop { my_struct.field.push_str("Hello, world!"); - //~^ ERROR (Ast) [E0499] - //~| ERROR (Mir) [E0499] + //~^ ERROR [E0499] value.len(); return; } @@ -33,7 +30,6 @@ fn nll_ok() { let value = &mut my_struct.field; loop { my_struct.field.push_str("Hello, world!"); - //~^ ERROR (Ast) [E0499] return; } } diff --git a/src/test/ui/nll/return_from_loop.stderr b/src/test/ui/nll/return_from_loop.stderr index 09882d55cb70e..efd56ea2dd542 100644 --- a/src/test/ui/nll/return_from_loop.stderr +++ b/src/test/ui/nll/return_from_loop.stderr @@ -1,39 +1,15 @@ -error[E0499]: cannot borrow `my_struct.field` as mutable more than once at a time (Ast) - --> $DIR/return_from_loop.rs:22:9 - | -LL | let value = &mut my_struct.field; - | --------------- first mutable borrow occurs here -LL | loop { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `my_struct.field` as mutable more than once at a time (Ast) - --> $DIR/return_from_loop.rs:35:9 - | -LL | let value = &mut my_struct.field; - | --------------- first mutable borrow occurs here -LL | loop { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `my_struct.field` as mutable more than once at a time (Mir) - --> $DIR/return_from_loop.rs:22:9 +error[E0499]: cannot borrow `my_struct.field` as mutable more than once at a time + --> $DIR/return_from_loop.rs:20:9 | LL | let value = &mut my_struct.field; | -------------------- first mutable borrow occurs here LL | loop { LL | my_struct.field.push_str("Hello, world!"); | ^^^^^^^^^^^^^^^ second mutable borrow occurs here -... +LL | LL | value.len(); | ----- first borrow later used here -error: aborting due to 3 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/nll/trait-associated-constant.rs b/src/test/ui/nll/trait-associated-constant.rs index 9d3e1a690f001..31dc58185e90a 100644 --- a/src/test/ui/nll/trait-associated-constant.rs +++ b/src/test/ui/nll/trait-associated-constant.rs @@ -9,24 +9,23 @@ trait Anything<'a: 'b, 'b> { const AC: Option<&'b str>; } -struct OKStruct { } +struct OKStruct1 { } -impl<'a: 'b, 'b> Anything<'a, 'b> for OKStruct { +impl<'a: 'b, 'b> Anything<'a, 'b> for OKStruct1 { const AC: Option<&'b str> = None; } -struct FailStruct1 { } +struct FailStruct { } -impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct1 { +impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct { const AC: Option<&'c str> = None; //~^ ERROR: mismatched types } -struct FailStruct2 { } +struct OKStruct2 { } -impl<'a: 'b, 'b> Anything<'a, 'b> for FailStruct2 { +impl<'a: 'b, 'b> Anything<'a, 'b> for OKStruct2 { const AC: Option<&'a str> = None; - //~^ ERROR: mismatched types } fn main() {} diff --git a/src/test/ui/nll/trait-associated-constant.stderr b/src/test/ui/nll/trait-associated-constant.stderr index 78ef513f3eecb..f39f668e2329a 100644 --- a/src/test/ui/nll/trait-associated-constant.stderr +++ b/src/test/ui/nll/trait-associated-constant.stderr @@ -9,33 +9,14 @@ LL | const AC: Option<&'c str> = None; note: the lifetime 'c as defined on the impl at 20:18... --> $DIR/trait-associated-constant.rs:20:18 | -LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct1 { +LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct { | ^^ note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 20:14 --> $DIR/trait-associated-constant.rs:20:14 | -LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct1 { +LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct { | ^^ -error[E0308]: mismatched types - --> $DIR/trait-associated-constant.rs:28:5 - | -LL | const AC: Option<&'a str> = None; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch - | - = note: expected type `std::option::Option<&'b str>` - found type `std::option::Option<&'a str>` -note: the lifetime 'a as defined on the impl at 27:6... - --> $DIR/trait-associated-constant.rs:27:6 - | -LL | impl<'a: 'b, 'b> Anything<'a, 'b> for FailStruct2 { - | ^^ -note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 27:14 - --> $DIR/trait-associated-constant.rs:27:14 - | -LL | impl<'a: 'b, 'b> Anything<'a, 'b> for FailStruct2 { - | ^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.rs b/src/test/ui/nll/ty-outlives/impl-trait-captures.rs index 7405505d5d6f8..bcdf643c0b9d1 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-captures.rs +++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.rs @@ -8,8 +8,8 @@ trait Foo<'a> { impl<'a, T> Foo<'a> for T { } fn foo<'a, T>(x: &T) -> impl Foo<'a> { +//~^ ERROR explicit lifetime required in the type of `x` [E0621] x - //~^ ERROR explicit lifetime required in the type of `x` [E0621] } fn main() {} diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr index d9481b6156ca0..3a1e3ce3ad1a0 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -1,8 +1,8 @@ error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/impl-trait-captures.rs:11:5 + --> $DIR/impl-trait-captures.rs:10:25 | -LL | x - | ^ lifetime `ReEarlyBound(0, 'a)` required +LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { + | ^^^^^^^^^^^^ lifetime `ReEarlyBound(0, 'a)` required help: add explicit lifetime `ReEarlyBound(0, 'a)` to the type of `x` | LL | fn foo<'a, T>(x: &ReEarlyBound(0, 'a) T) -> impl Foo<'a> { diff --git a/src/test/ui/nll/ty-outlives/issue-53789-1.rs b/src/test/ui/nll/ty-outlives/issue-53789-1.rs index 593cdfdbf711a..dc67c1a68aaf6 100644 --- a/src/test/ui/nll/ty-outlives/issue-53789-1.rs +++ b/src/test/ui/nll/ty-outlives/issue-53789-1.rs @@ -2,9 +2,6 @@ // // compile-pass -#![feature(nll)] -#![allow(unused_variables)] - use std::collections::BTreeMap; trait ValueTree { @@ -88,4 +85,3 @@ fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters) -> StrategyType<'a, A> { } fn main() { } - diff --git a/src/test/ui/nll/ty-outlives/issue-53789-2.rs b/src/test/ui/nll/ty-outlives/issue-53789-2.rs index 62e2833aa1b1a..1b80be2eaff99 100644 --- a/src/test/ui/nll/ty-outlives/issue-53789-2.rs +++ b/src/test/ui/nll/ty-outlives/issue-53789-2.rs @@ -2,9 +2,6 @@ // // compile-pass -#![feature(nll)] -#![allow(unused_variables)] - use std::collections::BTreeMap; use std::ops::Range; use std::cmp::Ord; @@ -248,4 +245,3 @@ mod statics { } fn main() { } - diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr index fc7a4570a1802..9fa54e83812f7 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -4,11 +4,11 @@ note: External requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:15 ~ projection_no_regions_closure[317d]::no_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:22 ~ projection_no_regions_closure[317d]::no_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r)> + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, ] = note: number of external vids: 3 = note: where ::Item: '_#2r @@ -21,13 +21,13 @@ LL | | where LL | | T: Iterator, LL | | { LL | | with_signature(x, |mut y| Box::new(y.next())) -LL | | //~^ ERROR the associated type `::Item` may not live long enough +LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ projection_no_regions_closure[317d]::no_region[0]) with substs [ + = note: defining type: DefId(0:19 ~ projection_no_regions_closure[317d]::no_region[0]) with substs [ '_#1r, - T + T, ] error[E0309]: the associated type `::Item` may not live long enough @@ -44,11 +44,11 @@ note: External requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:18 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:26 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r)> + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, ] = note: number of external vids: 3 = note: where ::Item: '_#2r @@ -64,9 +64,9 @@ LL | | with_signature(x, |mut y| Box::new(y.next())) LL | | } | |_^ | - = note: defining type: DefId(0/0:7 ~ projection_no_regions_closure[317d]::correct_region[0]) with substs [ + = note: defining type: DefId(0:23 ~ projection_no_regions_closure[317d]::correct_region[0]) with substs [ '_#1r, - T + T, ] note: External requirements @@ -75,12 +75,12 @@ note: External requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:22 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:31 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r)> + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, ] = note: number of external vids: 4 = note: where ::Item: '_#3r @@ -93,14 +93,14 @@ LL | | where LL | | T: 'b + Iterator, LL | | { LL | | with_signature(x, |mut y| Box::new(y.next())) -LL | | //~^ ERROR the associated type `::Item` may not live long enough +LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:8 ~ projection_no_regions_closure[317d]::wrong_region[0]) with substs [ + = note: defining type: DefId(0:27 ~ projection_no_regions_closure[317d]::wrong_region[0]) with substs [ '_#1r, '_#2r, - T + T, ] error[E0309]: the associated type `::Item` may not live long enough @@ -117,12 +117,12 @@ note: External requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:26 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:36 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r)> + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, ] = note: number of external vids: 4 = note: where ::Item: '_#3r @@ -139,10 +139,10 @@ LL | | with_signature(x, |mut y| Box::new(y.next())) LL | | } | |_^ | - = note: defining type: DefId(0/0:9 ~ projection_no_regions_closure[317d]::outlives_region[0]) with substs [ + = note: defining type: DefId(0:32 ~ projection_no_regions_closure[317d]::outlives_region[0]) with substs [ '_#1r, '_#2r, - T + T, ] error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index e8283d1ab5da2..10b2bd1af4702 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -4,11 +4,11 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:19 ~ projection_one_region_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:28 ~ projection_one_region_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: late-bound region is '_#3r = note: number of external vids: 4 @@ -23,13 +23,13 @@ LL | | where LL | | T: Anything<'b>, LL | | { ... | -LL | | //~| ERROR +LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]) with substs [ + = note: defining type: DefId(0:24 ~ projection_one_region_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, - T + T, ] error[E0309]: the parameter type `T` may not live long enough @@ -38,7 +38,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`... + = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:24 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(25), 'a))`... error: lifetime may not live long enough --> $DIR/projection-one-region-closure.rs:45:39 @@ -57,12 +57,12 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:23 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:33 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where T: '_#3r @@ -76,14 +76,14 @@ LL | | where LL | | T: Anything<'b>, LL | | 'a: 'a, ... | -LL | | //~| ERROR +LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:9 ~ projection_one_region_closure[317d]::no_relationships_early[0]) with substs [ + = note: defining type: DefId(0:29 ~ projection_one_region_closure[317d]::no_relationships_early[0]) with substs [ '_#1r, '_#2r, - T + T, ] error[E0309]: the parameter type `T` may not live long enough @@ -111,12 +111,12 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:27 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:38 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where >::AssocType: '_#3r @@ -133,10 +133,10 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:10 ~ projection_one_region_closure[317d]::projection_outlives[0]) with substs [ + = note: defining type: DefId(0:34 ~ projection_one_region_closure[317d]::projection_outlives[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: External requirements @@ -145,12 +145,12 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:31 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:43 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where T: '_#3r @@ -168,10 +168,10 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:11 ~ projection_one_region_closure[317d]::elements_outlive[0]) with substs [ + = note: defining type: DefId(0:39 ~ projection_one_region_closure[317d]::elements_outlive[0]) with substs [ '_#1r, '_#2r, - T + T, ] error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 78a8c803dd972..b4b74bfc1284f 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -4,11 +4,11 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:19 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:28 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: late-bound region is '_#3r = note: number of external vids: 4 @@ -22,13 +22,13 @@ LL | | where LL | | T: Anything<'b>, LL | | { LL | | with_signature(cell, t, |cell, t| require(cell, t)); -LL | | //~^ ERROR +LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [ + = note: defining type: DefId(0:24 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, - T + T, ] error: lifetime may not live long enough @@ -48,12 +48,12 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:33 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where '_#2r: '_#3r @@ -66,14 +66,14 @@ LL | | where LL | | T: Anything<'b>, LL | | 'a: 'a, ... | -LL | | //~^ ERROR +LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [ + = note: defining type: DefId(0:29 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [ '_#1r, '_#2r, - T + T, ] error: lifetime may not live long enough @@ -93,12 +93,12 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:38 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where >::AssocType: '_#3r @@ -115,10 +115,10 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [ + = note: defining type: DefId(0:34 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: External requirements @@ -127,12 +127,12 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:43 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where '_#2r: '_#3r @@ -149,10 +149,10 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]) with substs [ + = note: defining type: DefId(0:39 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: External requirements @@ -161,11 +161,11 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:47 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: number of external vids: 3 = note: where '_#1r: '_#2r @@ -182,9 +182,9 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]) with substs [ + = note: defining type: DefId(0:44 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]) with substs [ '_#1r, - T + T, ] error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr index 61f8132cf490c..a757a43499f4b 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr @@ -4,11 +4,11 @@ note: No external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:19 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:28 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: late-bound region is '_#3r @@ -23,9 +23,9 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [ + = note: defining type: DefId(0:24 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, - T + T, ] note: No external requirements @@ -34,12 +34,12 @@ note: No external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:33 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] note: No external requirements @@ -54,10 +54,10 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]) with substs [ + = note: defining type: DefId(0:29 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: No external requirements @@ -66,12 +66,12 @@ note: No external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:38 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] note: No external requirements @@ -86,10 +86,10 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]) with substs [ + = note: defining type: DefId(0:34 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: No external requirements @@ -98,12 +98,12 @@ note: No external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:43 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] note: No external requirements @@ -118,10 +118,10 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]) with substs [ + = note: defining type: DefId(0:39 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: No external requirements @@ -130,11 +130,11 @@ note: No external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:47 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] note: No external requirements @@ -149,8 +149,8 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]) with substs [ + = note: defining type: DefId(0:44 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]) with substs [ '_#1r, - T + T, ] diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index d8725dc4284f3..a48766cd7340b 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -4,12 +4,12 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:22 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:31 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: late-bound region is '_#4r = note: number of external vids: 5 @@ -23,14 +23,14 @@ LL | | where LL | | T: Anything<'b, 'c>, LL | | { LL | | with_signature(cell, t, |cell, t| require(cell, t)); -LL | | //~^ ERROR associated type `>::AssocType` may not live long enough +LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [ + = note: defining type: DefId(0:26 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, '_#2r, - T + T, ] error[E0309]: the associated type `>::AssocType` may not live long enough @@ -39,7 +39,7 @@ error[E0309]: the associated type `>::AssocType` may LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `>::AssocType: ReFree(DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:18), 'a))`... + = help: consider adding an explicit lifetime bound `>::AssocType: ReFree(DefId(0:26 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(27), 'a))`... note: External requirements --> $DIR/projection-two-region-trait-bound-closure.rs:48:29 @@ -47,13 +47,13 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:27 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:37 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, '_#3r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), ] = note: number of external vids: 5 = note: where >::AssocType: '_#4r @@ -66,15 +66,15 @@ LL | | where LL | | T: Anything<'b, 'c>, LL | | 'a: 'a, ... | -LL | | //~^ ERROR associated type `>::AssocType` may not live long enough +LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:9 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [ + = note: defining type: DefId(0:32 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [ '_#1r, '_#2r, '_#3r, - T + T, ] error[E0309]: the associated type `>::AssocType` may not live long enough @@ -91,13 +91,13 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:32 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:43 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, '_#3r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), ] = note: number of external vids: 5 = note: where >::AssocType: '_#4r @@ -114,11 +114,11 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:10 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [ + = note: defining type: DefId(0:38 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [ '_#1r, '_#2r, '_#3r, - T + T, ] note: External requirements @@ -127,13 +127,13 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:37 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:49 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, '_#3r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), ] = note: number of external vids: 5 = note: where >::AssocType: '_#4r @@ -150,11 +150,11 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:11 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]) with substs [ + = note: defining type: DefId(0:44 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]) with substs [ '_#1r, '_#2r, '_#3r, - T + T, ] note: External requirements @@ -163,13 +163,13 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:42 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:55 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, '_#3r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), ] = note: number of external vids: 5 = note: where >::AssocType: '_#4r @@ -186,11 +186,11 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:12 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]) with substs [ + = note: defining type: DefId(0:50 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]) with substs [ '_#1r, '_#2r, '_#3r, - T + T, ] note: External requirements @@ -199,11 +199,11 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:46 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:60 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: late-bound region is '_#3r = note: number of external vids: 4 @@ -217,13 +217,13 @@ LL | | where LL | | T: Anything<'b, 'b>, LL | | { LL | | with_signature(cell, t, |cell, t| require(cell, t)); -LL | | //~^ ERROR lifetime may not live long enough +LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]) with substs [ + = note: defining type: DefId(0:56 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]) with substs [ '_#1r, - T + T, ] error: lifetime may not live long enough @@ -243,12 +243,12 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:50 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:65 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where >::AssocType: '_#3r @@ -265,10 +265,10 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:14 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]) with substs [ + = note: defining type: DefId(0:61 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: External requirements @@ -277,11 +277,11 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:53 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:69 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: number of external vids: 3 = note: where >::AssocType: '_#2r @@ -298,9 +298,9 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:15 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]) with substs [ + = note: defining type: DefId(0:66 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]) with substs [ '_#1r, - T + T, ] error: aborting due to 3 previous errors diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.nll.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.nll.stderr new file mode 100644 index 0000000000000..3a84cbfbedc09 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.nll.stderr @@ -0,0 +1,11 @@ +error[E0309]: the associated type `>::Output` may not live long enough + --> $DIR/projection-where-clause-env-wrong-bound.rs:15:5 + | +LL | bar::() + | ^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `>::Output: 'a`... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs index 9c2cbfd4a4530..dce88b88c7530 100644 --- a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs +++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - // Test that we are able to establish that `>::Output` outlives `'b` here. We need to prove however // that `>::Output` outlives `'a`, so we also have to diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr index 597b096dbe607..1a5a3719fd86d 100644 --- a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr +++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr @@ -1,10 +1,15 @@ -error[E0309]: the associated type `>::Output` may not live long enough - --> $DIR/projection-where-clause-env-wrong-bound.rs:17:5 +error[E0309]: the associated type `>::Output` may not live long enough + --> $DIR/projection-where-clause-env-wrong-bound.rs:15:5 | -LL | bar::() //~ ERROR may not live long enough +LL | bar::() | ^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `>::Output: 'a`... + = help: consider adding an explicit lifetime bound `>::Output: 'a`... +note: ...so that the type `>::Output` will meet its required lifetime bounds + --> $DIR/projection-where-clause-env-wrong-bound.rs:15:5 + | +LL | bar::() + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.nll.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.nll.stderr new file mode 100644 index 0000000000000..58bfb600452e0 --- /dev/null +++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.nll.stderr @@ -0,0 +1,11 @@ +error[E0309]: the associated type `>::Output` may not live long enough + --> $DIR/projection-where-clause-env-wrong-lifetime.rs:14:5 + | +LL | bar::<>::Output>() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `>::Output: 'a`... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env.rs b/src/test/ui/nll/ty-outlives/projection-where-clause-env.rs index c6935badf54b2..7314766611121 100644 --- a/src/test/ui/nll/ty-outlives/projection-where-clause-env.rs +++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - // Test that when we have a `>::Output: 'a` // relationship in the environment we take advantage of it. In this // case, that means we **don't** have to prove that `T: 'a`. diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr index 3c2ac474778f9..8175c302155a5 100644 --- a/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr +++ b/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr @@ -1,7 +1,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-where-clause-none.rs:16:5 | -LL | bar::() //~ ERROR the parameter type `T` may not live long enough +LL | bar::() | ^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `T: 'a`... diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index 24bd97f046913..2ed94df1f3478 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -4,10 +4,10 @@ note: External requirements LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:14 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:20 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]::{{closure}}[0]) with closure substs [ T, i16, - for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) T)) + for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) T)), ] = note: number of external vids: 2 = note: where T: '_#1r @@ -21,8 +21,8 @@ LL | | twice(cell, value, |a, b| invoke(a, b)); LL | | } | |_^ | - = note: defining type: DefId(0/0:5 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]) with substs [ - T + = note: defining type: DefId(0:18 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]) with substs [ + T, ] note: External requirements @@ -31,10 +31,10 @@ note: External requirements LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:17 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:24 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [ T, i16, - for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) T)) + for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) T)), ] = note: late-bound region is '_#2r = note: number of external vids: 3 @@ -45,12 +45,12 @@ note: No external requirements | LL | / fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) { LL | | twice(cell, value, |a, b| invoke(a, b)); -LL | | //~^ ERROR the parameter type `T` may not live long enough +LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]) with substs [ - T + = note: defining type: DefId(0:21 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]) with substs [ + T, ] error[E0309]: the parameter type `T` may not live long enough @@ -59,7 +59,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]), BrNamed(crate0:DefIndex(1:15), 'a))`... + = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:21 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]), BrNamed(crate0:DefIndex(22), 'a))`... error: aborting due to previous error diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr index 30c1dbc9027b4..d689949969d7e 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -4,11 +4,11 @@ note: External requirements LL | with_signature(x, |y| y) | ^^^^^ | - = note: defining type: DefId(0/1:14 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:20 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)> + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>, ] = note: number of external vids: 3 = note: where T: '_#2r @@ -21,13 +21,13 @@ LL | | where LL | | T: Debug, LL | | { ... | -LL | | //~^ ERROR the parameter type `T` may not live long enough +LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:5 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]) with substs [ + = note: defining type: DefId(0:17 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]) with substs [ '_#1r, - T + T, ] error[E0309]: the parameter type `T` may not live long enough diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index a76a9463cc801..11444c9f72bef 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -3,7 +3,7 @@ note: External requirements | LL | with_signature(a, b, |x, y| { | __________________________^ -LL | | //~^ ERROR the parameter type `T` may not live long enough +LL | | LL | | // LL | | // See `correct_region`, which explains the point of this ... | @@ -11,10 +11,10 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: DefId(0/1:16 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:23 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]::{{closure}}[0]) with closure substs [ T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)), ] = note: late-bound region is '_#2r = note: number of external vids: 3 @@ -25,15 +25,15 @@ note: No external requirements | LL | / fn no_region<'a, T>(a: Cell<&'a ()>, b: T) { LL | | with_signature(a, b, |x, y| { -LL | | //~^ ERROR the parameter type `T` may not live long enough +LL | | LL | | // ... | LL | | }) LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]) with substs [ - T + = note: defining type: DefId(0:20 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]) with substs [ + T, ] error[E0309]: the parameter type `T` may not live long enough @@ -41,7 +41,7 @@ error[E0309]: the parameter type `T` may not live long enough | LL | with_signature(a, b, |x, y| { | __________________________^ -LL | | //~^ ERROR the parameter type `T` may not live long enough +LL | | LL | | // LL | | // See `correct_region`, which explains the point of this ... | @@ -49,7 +49,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]), BrNamed(crate0:DefIndex(1:14), 'a))`... + = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:20 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]), BrNamed(crate0:DefIndex(21), 'a))`... note: External requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:43:26 @@ -64,11 +64,11 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: DefId(0/1:19 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:27 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: number of external vids: 3 = note: where T: '_#2r @@ -85,9 +85,9 @@ LL | | }) LL | | } | |_^ | - = note: defining type: DefId(0/0:7 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]) with substs [ + = note: defining type: DefId(0:24 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]) with substs [ '_#1r, - T + T, ] note: External requirements @@ -95,17 +95,17 @@ note: External requirements | LL | with_signature(a, b, |x, y| { | __________________________^ -LL | | //~^ ERROR the parameter type `T` may not live long enough +LL | | LL | | // See `correct_region` LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: DefId(0/1:23 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:32 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: late-bound region is '_#3r = note: number of external vids: 4 @@ -123,9 +123,9 @@ LL | | }) LL | | } | |_^ | - = note: defining type: DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]) with substs [ + = note: defining type: DefId(0:28 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]) with substs [ '_#1r, - T + T, ] error[E0309]: the parameter type `T` may not live long enough @@ -133,13 +133,13 @@ error[E0309]: the parameter type `T` may not live long enough | LL | with_signature(a, b, |x, y| { | __________________________^ -LL | | //~^ ERROR the parameter type `T` may not live long enough +LL | | LL | | // See `correct_region` LL | | require(&x, &y) LL | | }) | |_____^ | - = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]), BrNamed(crate0:DefIndex(1:20), 'a))`... + = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:28 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]), BrNamed(crate0:DefIndex(29), 'a))`... note: External requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:77:26 @@ -151,12 +151,12 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: DefId(0/1:27 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:37 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where T: '_#3r @@ -173,10 +173,10 @@ LL | | }) LL | | } | |_^ | - = note: defining type: DefId(0/0:9 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]) with substs [ + = note: defining type: DefId(0:33 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]) with substs [ '_#1r, '_#2r, - T + T, ] error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs b/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs deleted file mode 100644 index ec5594375709b..0000000000000 --- a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Test that we assume that universal types like `T` outlive the -// function body. Same as ty-param-fn-body, but uses `feature(nll)`, -// which affects error reporting. - -#![feature(nll)] - -#![allow(warnings)] - -use std::cell::Cell; - -// No errors here, because `'a` is local to the body. -fn region_within_body(t: T) { - let some_int = 22; - let cell = Cell::new(&some_int); - outlives(cell, t) -} - -// Error here, because T: 'a is not satisfied. -fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) { - outlives(cell, t) - //~^ ERROR the parameter type `T` may not live long enough -} - -fn outlives<'a, T>(x: Cell<&'a usize>, y: T) -where - T: 'a, -{ -} - -fn main() {} diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr deleted file mode 100644 index b3c02f7f42919..0000000000000 --- a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-fn-body-nll-feature.rs:20:5 - | -LL | outlives(cell, t) - | ^^^^^^^^^^^^^^^^^ - | - = help: consider adding an explicit lifetime bound `T: 'a`... - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/nll/ty-outlives/wf-unreachable.stderr b/src/test/ui/nll/ty-outlives/wf-unreachable.stderr index 14642a1e615df..9128fd1647959 100644 --- a/src/test/ui/nll/ty-outlives/wf-unreachable.stderr +++ b/src/test/ui/nll/ty-outlives/wf-unreachable.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | fn uninit<'a>() { | -- lifetime `'a` defined here LL | return; -LL | let x: &'static &'a (); //~ ERROR lifetime may not live long enough +LL | let x: &'static &'a (); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -13,7 +13,7 @@ error: lifetime may not live long enough LL | fn var_type<'a>() { | -- lifetime `'a` defined here LL | return; -LL | let x: &'static &'a () = &&(); //~ ERROR lifetime may not live long enough +LL | let x: &'static &'a () = &&(); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -21,7 +21,7 @@ error: lifetime may not live long enough | LL | fn uninit_infer<'a>() { | -- lifetime `'a` defined here -LL | let x: &'static &'a _; //~ ERROR lifetime may not live long enough +LL | let x: &'static &'a _; | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -30,7 +30,7 @@ error: lifetime may not live long enough LL | fn infer<'a>() { | -- lifetime `'a` defined here LL | return; -LL | let x: &'static &'a _ = &&(); //~ ERROR lifetime may not live long enough +LL | let x: &'static &'a _ = &&(); | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -39,7 +39,7 @@ error: lifetime may not live long enough LL | fn uninit_no_var<'a>() { | -- lifetime `'a` defined here LL | return; -LL | let _: &'static &'a (); //~ ERROR lifetime may not live long enough +LL | let _: &'static &'a (); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -48,7 +48,7 @@ error: lifetime may not live long enough LL | fn no_var<'a>() { | -- lifetime `'a` defined here LL | return; -LL | let _: &'static &'a () = &&(); //~ ERROR lifetime may not live long enough +LL | let _: &'static &'a () = &&(); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -57,7 +57,7 @@ error: lifetime may not live long enough LL | fn infer_no_var<'a>() { | -- lifetime `'a` defined here LL | return; -LL | let _: &'static &'a _ = &&(); //~ ERROR lifetime may not live long enough +LL | let _: &'static &'a _ = &&(); | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -66,7 +66,7 @@ error: lifetime may not live long enough LL | fn required_substs<'a>() { | -- lifetime `'a` defined here LL | return; -LL | let _: C<'static, 'a, _> = C((), &(), &()); //~ ERROR lifetime may not live long enough +LL | let _: C<'static, 'a, _> = C((), &(), &()); | ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: aborting due to 8 previous errors diff --git a/src/test/ui/nll/type-alias-free-regions.nll.stderr b/src/test/ui/nll/type-alias-free-regions.nll.stderr new file mode 100644 index 0000000000000..235bf4167d521 --- /dev/null +++ b/src/test/ui/nll/type-alias-free-regions.nll.stderr @@ -0,0 +1,22 @@ +error: lifetime may not live long enough + --> $DIR/type-alias-free-regions.rs:17:9 + | +LL | impl<'a> FromBox<'a> for C<'a> { + | -- lifetime `'a` defined here +LL | fn from_box(b: Box) -> Self { + | - has type `std::boxed::Box>` +LL | C { f: b } + | ^^^^^^^^^^ returning this value requires that `'1` must outlive `'a` + +error: lifetime may not live long enough + --> $DIR/type-alias-free-regions.rs:27:9 + | +LL | impl<'a> FromTuple<'a> for C<'a> { + | -- lifetime `'a` defined here +LL | fn from_tuple(b: (B,)) -> Self { + | - has type `(std::boxed::Box<&'1 isize>,)` +LL | C { f: Box::new(b.0) } + | ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'a` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/nll/type-alias-free-regions.rs b/src/test/ui/nll/type-alias-free-regions.rs index ebe6b9d20739a..fd5566f35d514 100644 --- a/src/test/ui/nll/type-alias-free-regions.rs +++ b/src/test/ui/nll/type-alias-free-regions.rs @@ -1,8 +1,6 @@ // Test that we don't assume that type aliases have the same type parameters // as the type they alias and then panic when we see this. -#![feature(nll)] - type A<'a> = &'a isize; type B<'a> = Box>; diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr index bcd141bb406b1..00d58d34362e6 100644 --- a/src/test/ui/nll/type-alias-free-regions.stderr +++ b/src/test/ui/nll/type-alias-free-regions.stderr @@ -1,22 +1,52 @@ -error: lifetime may not live long enough - --> $DIR/type-alias-free-regions.rs:19:9 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/type-alias-free-regions.rs:17:9 + | +LL | C { f: b } + | ^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 16:5... + --> $DIR/type-alias-free-regions.rs:16:5 + | +LL | / fn from_box(b: Box) -> Self { +LL | | C { f: b } +LL | | } + | |_____^ + = note: ...so that the expression is assignable: + expected std::boxed::Box> + found std::boxed::Box> +note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 15:6... + --> $DIR/type-alias-free-regions.rs:15:6 | LL | impl<'a> FromBox<'a> for C<'a> { - | -- lifetime `'a` defined here -LL | fn from_box(b: Box) -> Self { - | - has type `std::boxed::Box>` -LL | C { f: b } //~ ERROR - | ^^^^^^^^^^ returning this value requires that `'1` must outlive `'a` + | ^^ + = note: ...so that the expression is assignable: + expected C<'a> + found C<'_> -error: lifetime may not live long enough - --> $DIR/type-alias-free-regions.rs:29:9 +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements + --> $DIR/type-alias-free-regions.rs:27:16 + | +LL | C { f: Box::new(b.0) } + | ^^^^^^^^^^^^^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 26:5... + --> $DIR/type-alias-free-regions.rs:26:5 + | +LL | / fn from_tuple(b: (B,)) -> Self { +LL | | C { f: Box::new(b.0) } +LL | | } + | |_____^ + = note: ...so that the expression is assignable: + expected std::boxed::Box<&isize> + found std::boxed::Box<&isize> +note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 25:6... + --> $DIR/type-alias-free-regions.rs:25:6 | LL | impl<'a> FromTuple<'a> for C<'a> { - | -- lifetime `'a` defined here -LL | fn from_tuple(b: (B,)) -> Self { - | - has type `(std::boxed::Box<&'1 isize>,)` -LL | C { f: Box::new(b.0) } //~ ERROR - | ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'a` + | ^^ + = note: ...so that the expression is assignable: + expected C<'a> + found C<'_> error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/type-check-pointer-coercions.rs b/src/test/ui/nll/type-check-pointer-coercions.rs new file mode 100644 index 0000000000000..b6a25eddb866d --- /dev/null +++ b/src/test/ui/nll/type-check-pointer-coercions.rs @@ -0,0 +1,39 @@ +#![feature(nll)] + +fn shared_to_const<'a, 'b>(x: &&'a i32) -> *const &'b i32 { + x //~ ERROR +} + +fn unique_to_const<'a, 'b>(x: &mut &'a i32) -> *const &'b i32 { + x //~ ERROR +} + +fn unique_to_mut<'a, 'b>(x: &mut &'a i32) -> *mut &'b i32 { + // Two errors because *mut is invariant + x //~ ERROR + //~| ERROR +} + +fn mut_to_const<'a, 'b>(x: *mut &'a i32) -> *const &'b i32 { + x //~ ERROR +} + +fn array_elem<'a, 'b>(x: &'a i32) -> *const &'b i32 { + let z = &[x; 3]; + let y = z as *const &i32; + y //~ ERROR +} + +fn array_coerce<'a, 'b>(x: &'a i32) -> *const [&'b i32; 3] { + let z = &[x; 3]; + let y = z as *const [&i32; 3]; + y //~ ERROR +} + +fn nested_array<'a, 'b>(x: &'a i32) -> *const [&'b i32; 2] { + let z = &[[x; 2]; 3]; + let y = z as *const [&i32; 2]; + y //~ ERROR +} + +fn main() {} diff --git a/src/test/ui/nll/type-check-pointer-coercions.stderr b/src/test/ui/nll/type-check-pointer-coercions.stderr new file mode 100644 index 0000000000000..9aa78dfbd4acd --- /dev/null +++ b/src/test/ui/nll/type-check-pointer-coercions.stderr @@ -0,0 +1,87 @@ +error: lifetime may not live long enough + --> $DIR/type-check-pointer-coercions.rs:4:5 + | +LL | fn shared_to_const<'a, 'b>(x: &&'a i32) -> *const &'b i32 { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x + | ^ returning this value requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/type-check-pointer-coercions.rs:8:5 + | +LL | fn unique_to_const<'a, 'b>(x: &mut &'a i32) -> *const &'b i32 { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x + | ^ returning this value requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/type-check-pointer-coercions.rs:13:5 + | +LL | fn unique_to_mut<'a, 'b>(x: &mut &'a i32) -> *mut &'b i32 { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // Two errors because *mut is invariant +LL | x + | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + +error: lifetime may not live long enough + --> $DIR/type-check-pointer-coercions.rs:13:5 + | +LL | fn unique_to_mut<'a, 'b>(x: &mut &'a i32) -> *mut &'b i32 { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // Two errors because *mut is invariant +LL | x + | ^ returning this value requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/type-check-pointer-coercions.rs:18:5 + | +LL | fn mut_to_const<'a, 'b>(x: *mut &'a i32) -> *const &'b i32 { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x + | ^ returning this value requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/type-check-pointer-coercions.rs:24:5 + | +LL | fn array_elem<'a, 'b>(x: &'a i32) -> *const &'b i32 { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | y + | ^ returning this value requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/type-check-pointer-coercions.rs:30:5 + | +LL | fn array_coerce<'a, 'b>(x: &'a i32) -> *const [&'b i32; 3] { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | y + | ^ returning this value requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/type-check-pointer-coercions.rs:36:5 + | +LL | fn nested_array<'a, 'b>(x: &'a i32) -> *const [&'b i32; 2] { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | y + | ^ returning this value requires that `'a` must outlive `'b` + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/nll/type-check-pointer-comparisons.rs b/src/test/ui/nll/type-check-pointer-comparisons.rs new file mode 100644 index 0000000000000..3c900356fab3b --- /dev/null +++ b/src/test/ui/nll/type-check-pointer-comparisons.rs @@ -0,0 +1,33 @@ +#![feature(nll)] + +// Check that we assert that pointers have a common subtype for comparisons + +fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) { + x == y; + //~^ ERROR lifetime may not live long enough + //~| ERROR lifetime may not live long enough +} + +fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) { + x == y; + //~^ ERROR lifetime may not live long enough + //~| ERROR lifetime may not live long enough +} + +fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32)) { + f == g; + //~^ ERROR lifetime may not live long enough + //~| ERROR lifetime may not live long enough +} + +fn compare_hr_fn_ptr<'a>(f: fn(&'a i32), g: fn(&i32)) { + // Ideally this should compile with the operands swapped as well, but HIR + // type checking prevents it (and stops compilation) for now. + f == g; // OK +} + +fn compare_const_fn_ptr<'a>(f: *const fn(&'a i32), g: *const fn(&i32)) { + f == g; // OK +} + +fn main() {} diff --git a/src/test/ui/nll/type-check-pointer-comparisons.stderr b/src/test/ui/nll/type-check-pointer-comparisons.stderr new file mode 100644 index 0000000000000..c0a994cfb6381 --- /dev/null +++ b/src/test/ui/nll/type-check-pointer-comparisons.stderr @@ -0,0 +1,62 @@ +error: lifetime may not live long enough + --> $DIR/type-check-pointer-comparisons.rs:6:5 + | +LL | fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x == y; + | ^ requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/type-check-pointer-comparisons.rs:6:10 + | +LL | fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x == y; + | ^ requires that `'b` must outlive `'a` + +error: lifetime may not live long enough + --> $DIR/type-check-pointer-comparisons.rs:12:5 + | +LL | fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x == y; + | ^ requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/type-check-pointer-comparisons.rs:12:10 + | +LL | fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x == y; + | ^ requires that `'b` must outlive `'a` + +error: lifetime may not live long enough + --> $DIR/type-check-pointer-comparisons.rs:18:5 + | +LL | fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32)) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | f == g; + | ^ requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/type-check-pointer-comparisons.rs:18:10 + | +LL | fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32)) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | f == g; + | ^ requires that `'b` must outlive `'a` + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/nll/unused-mut-issue-50343.rs b/src/test/ui/nll/unused-mut-issue-50343.rs index 06dbc47355739..da0d9229c1262 100644 --- a/src/test/ui/nll/unused-mut-issue-50343.rs +++ b/src/test/ui/nll/unused-mut-issue-50343.rs @@ -1,4 +1,3 @@ -#![feature(nll)] #![deny(unused_mut)] fn main() { diff --git a/src/test/ui/nll/unused-mut-issue-50343.stderr b/src/test/ui/nll/unused-mut-issue-50343.stderr index ef31dd7b29a40..261d678db6758 100644 --- a/src/test/ui/nll/unused-mut-issue-50343.stderr +++ b/src/test/ui/nll/unused-mut-issue-50343.stderr @@ -1,5 +1,5 @@ error: variable does not need to be mutable - --> $DIR/unused-mut-issue-50343.rs:5:33 + --> $DIR/unused-mut-issue-50343.rs:4:33 | LL | vec![(42, 22)].iter().map(|(mut x, _y)| ()).count(); | ----^ @@ -7,7 +7,7 @@ LL | vec![(42, 22)].iter().map(|(mut x, _y)| ()).count(); | help: remove this `mut` | note: lint level defined here - --> $DIR/unused-mut-issue-50343.rs:2:9 + --> $DIR/unused-mut-issue-50343.rs:1:9 | LL | #![deny(unused_mut)] | ^^^^^^^^^^ diff --git a/src/test/ui/nll/user-annotations/adt-brace-enums.rs b/src/test/ui/nll/user-annotations/adt-brace-enums.rs index 842ebae261819..0d9828342d8cb 100644 --- a/src/test/ui/nll/user-annotations/adt-brace-enums.rs +++ b/src/test/ui/nll/user-annotations/adt-brace-enums.rs @@ -1,8 +1,6 @@ // Unit test for the "user substitutions" that are annotated on each // node. -#![feature(nll)] - enum SomeEnum { SomeVariant { t: T } } diff --git a/src/test/ui/nll/user-annotations/adt-brace-enums.stderr b/src/test/ui/nll/user-annotations/adt-brace-enums.stderr index fd1a4b96fe347..e38b77fdcea01 100644 --- a/src/test/ui/nll/user-annotations/adt-brace-enums.stderr +++ b/src/test/ui/nll/user-annotations/adt-brace-enums.stderr @@ -1,7 +1,7 @@ error[E0597]: `c` does not live long enough - --> $DIR/adt-brace-enums.rs:27:48 + --> $DIR/adt-brace-enums.rs:25:48 | -LL | SomeEnum::SomeVariant::<&'static u32> { t: &c }; //~ ERROR +LL | SomeEnum::SomeVariant::<&'static u32> { t: &c }; | ^^ | | | borrowed value does not live long enough @@ -10,12 +10,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/adt-brace-enums.rs:32:43 + --> $DIR/adt-brace-enums.rs:30:43 | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here LL | let c = 66; -LL | SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR +LL | SomeEnum::SomeVariant::<&'a u32> { t: &c }; | ^^ | | | borrowed value does not live long enough @@ -24,12 +24,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/adt-brace-enums.rs:42:47 + --> $DIR/adt-brace-enums.rs:40:47 | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here ... -LL | SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR +LL | SomeEnum::SomeVariant::<&'a u32> { t: &c }; | ^^ | | | borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/adt-brace-structs.rs b/src/test/ui/nll/user-annotations/adt-brace-structs.rs index d7ebbe8eb5fc0..bdbfd87d584d9 100644 --- a/src/test/ui/nll/user-annotations/adt-brace-structs.rs +++ b/src/test/ui/nll/user-annotations/adt-brace-structs.rs @@ -1,8 +1,6 @@ // Unit test for the "user substitutions" that are annotated on each // node. -#![feature(nll)] - struct SomeStruct { t: T } fn no_annot() { diff --git a/src/test/ui/nll/user-annotations/adt-brace-structs.stderr b/src/test/ui/nll/user-annotations/adt-brace-structs.stderr index e614e00ac00cd..3c3003477c2d6 100644 --- a/src/test/ui/nll/user-annotations/adt-brace-structs.stderr +++ b/src/test/ui/nll/user-annotations/adt-brace-structs.stderr @@ -1,7 +1,7 @@ error[E0597]: `c` does not live long enough - --> $DIR/adt-brace-structs.rs:25:37 + --> $DIR/adt-brace-structs.rs:23:37 | -LL | SomeStruct::<&'static u32> { t: &c }; //~ ERROR +LL | SomeStruct::<&'static u32> { t: &c }; | ^^ | | | borrowed value does not live long enough @@ -10,12 +10,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/adt-brace-structs.rs:30:32 + --> $DIR/adt-brace-structs.rs:28:32 | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here LL | let c = 66; -LL | SomeStruct::<&'a u32> { t: &c }; //~ ERROR +LL | SomeStruct::<&'a u32> { t: &c }; | ^^ | | | borrowed value does not live long enough @@ -24,12 +24,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/adt-brace-structs.rs:40:36 + --> $DIR/adt-brace-structs.rs:38:36 | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here ... -LL | SomeStruct::<&'a u32> { t: &c }; //~ ERROR +LL | SomeStruct::<&'a u32> { t: &c }; | ^^ | | | borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/adt-nullary-enums.rs b/src/test/ui/nll/user-annotations/adt-nullary-enums.rs index 7a8f55a800b92..53853668d1978 100644 --- a/src/test/ui/nll/user-annotations/adt-nullary-enums.rs +++ b/src/test/ui/nll/user-annotations/adt-nullary-enums.rs @@ -1,7 +1,6 @@ // Unit test for the "user substitutions" that are annotated on each // node. -#![feature(nll)] #![allow(warnings)] use std::cell::Cell; diff --git a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr index c72e56c619f32..bb70341222880 100644 --- a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr +++ b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr @@ -1,7 +1,7 @@ error[E0597]: `c` does not live long enough - --> $DIR/adt-nullary-enums.rs:34:41 + --> $DIR/adt-nullary-enums.rs:33:41 | -LL | SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR +LL | SomeEnum::SomeVariant(Cell::new(&c)), | ----------^^- | | | | | borrowed value does not live long enough @@ -11,12 +11,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/adt-nullary-enums.rs:42:41 + --> $DIR/adt-nullary-enums.rs:41:41 | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here ... -LL | SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR +LL | SomeEnum::SomeVariant(Cell::new(&c)), | ----------^^- | | | | | borrowed value does not live long enough @@ -26,12 +26,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/adt-nullary-enums.rs:55:45 + --> $DIR/adt-nullary-enums.rs:54:45 | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here ... -LL | SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR +LL | SomeEnum::SomeVariant(Cell::new(&c)), | ----------^^- | | | | | borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/adt-tuple-enums.rs b/src/test/ui/nll/user-annotations/adt-tuple-enums.rs index 085596ecc53ee..efe8dfda1910a 100644 --- a/src/test/ui/nll/user-annotations/adt-tuple-enums.rs +++ b/src/test/ui/nll/user-annotations/adt-tuple-enums.rs @@ -1,7 +1,6 @@ // Unit test for the "user substitutions" that are annotated on each // node. -#![feature(nll)] #![allow(warnings)] enum SomeEnum { diff --git a/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr b/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr index dc5b5a0dd7fd1..810912bf88618 100644 --- a/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr +++ b/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr @@ -1,7 +1,7 @@ error[E0597]: `c` does not live long enough - --> $DIR/adt-tuple-enums.rs:29:43 + --> $DIR/adt-tuple-enums.rs:28:43 | -LL | SomeEnum::SomeVariant::<&'static u32>(&c); //~ ERROR +LL | SomeEnum::SomeVariant::<&'static u32>(&c); | ^^ | | | borrowed value does not live long enough @@ -10,12 +10,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/adt-tuple-enums.rs:34:38 + --> $DIR/adt-tuple-enums.rs:33:38 | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here LL | let c = 66; -LL | SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR +LL | SomeEnum::SomeVariant::<&'a u32>(&c); | ^^ | | | borrowed value does not live long enough @@ -24,12 +24,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/adt-tuple-enums.rs:44:42 + --> $DIR/adt-tuple-enums.rs:43:42 | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here ... -LL | SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR +LL | SomeEnum::SomeVariant::<&'a u32>(&c); | ^^ | | | borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.rs b/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.rs new file mode 100644 index 0000000000000..116583223925a --- /dev/null +++ b/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.rs @@ -0,0 +1,71 @@ +// Unit test for the "user substitutions" that are annotated on each +// node. + +struct SomeStruct(T); + +fn no_annot() { + let c = 66; + let f = SomeStruct; + f(&c); +} + +fn annot_underscore() { + let c = 66; + let f = SomeStruct::<_>; + f(&c); +} + +fn annot_reference_any_lifetime() { + let c = 66; + let f = SomeStruct::<&u32>; + f(&c); +} + +fn annot_reference_static_lifetime() { + let c = 66; + let f = SomeStruct::<&'static u32>; + f(&c); //~ ERROR +} + +fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + let c = 66; + let f = SomeStruct::<&'a u32>; + f(&c); //~ ERROR +} + +fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) { + let f = SomeStruct::<&'a u32>; + f(c); +} + +fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + let _closure = || { + let c = 66; + let f = SomeStruct::<&'a u32>; + f(&c); //~ ERROR + }; +} + +fn annot_reference_named_lifetime_across_closure<'a>(_: &'a u32) { + let f = SomeStruct::<&'a u32>; + let _closure = || { + let c = 66; + f(&c); //~ ERROR + }; +} + +fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) { + let _closure = || { + let f = SomeStruct::<&'a u32>; + f(c); + }; +} + +fn annot_reference_named_lifetime_across_closure_ok<'a>(c: &'a u32) { + let f = SomeStruct::<&'a u32>; + let _closure = || { + f(c); + }; +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr b/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr new file mode 100644 index 0000000000000..9664fb9f54831 --- /dev/null +++ b/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr @@ -0,0 +1,56 @@ +error[E0597]: `c` does not live long enough + --> $DIR/adt-tuple-struct-calls.rs:27:7 + | +LL | f(&c); + | --^^- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'static` +LL | } + | - `c` dropped here while still borrowed + +error[E0597]: `c` does not live long enough + --> $DIR/adt-tuple-struct-calls.rs:33:7 + | +LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + | -- lifetime `'a` defined here +... +LL | f(&c); + | --^^- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'a` +LL | } + | - `c` dropped here while still borrowed + +error[E0597]: `c` does not live long enough + --> $DIR/adt-tuple-struct-calls.rs:45:11 + | +LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + | -- lifetime `'a` defined here +... +LL | f(&c); + | --^^- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'a` +LL | }; + | - `c` dropped here while still borrowed + +error[E0597]: `c` does not live long enough + --> $DIR/adt-tuple-struct-calls.rs:53:11 + | +LL | let f = SomeStruct::<&'a u32>; + | - lifetime `'1` appears in the type of `f` +... +LL | f(&c); + | --^^- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'1` +LL | }; + | - `c` dropped here while still borrowed + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct.rs b/src/test/ui/nll/user-annotations/adt-tuple-struct.rs index ebbe3cd2c8988..37284e1fda82b 100644 --- a/src/test/ui/nll/user-annotations/adt-tuple-struct.rs +++ b/src/test/ui/nll/user-annotations/adt-tuple-struct.rs @@ -1,8 +1,6 @@ // Unit test for the "user substitutions" that are annotated on each // node. -#![feature(nll)] - struct SomeStruct(T); fn no_annot() { diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr b/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr index 38acfcb4b6136..4d2140eca1b02 100644 --- a/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr +++ b/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr @@ -1,7 +1,7 @@ error[E0597]: `c` does not live long enough - --> $DIR/adt-tuple-struct.rs:25:32 + --> $DIR/adt-tuple-struct.rs:23:32 | -LL | SomeStruct::<&'static u32>(&c); //~ ERROR +LL | SomeStruct::<&'static u32>(&c); | ^^ | | | borrowed value does not live long enough @@ -10,12 +10,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/adt-tuple-struct.rs:30:27 + --> $DIR/adt-tuple-struct.rs:28:27 | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here LL | let c = 66; -LL | SomeStruct::<&'a u32>(&c); //~ ERROR +LL | SomeStruct::<&'a u32>(&c); | ^^ | | | borrowed value does not live long enough @@ -24,12 +24,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/adt-tuple-struct.rs:40:31 + --> $DIR/adt-tuple-struct.rs:38:31 | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here ... -LL | SomeStruct::<&'a u32>(&c); //~ ERROR +LL | SomeStruct::<&'a u32>(&c); | ^^ | | | borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/cast_static_lifetime.rs b/src/test/ui/nll/user-annotations/cast_static_lifetime.rs index 4756c771f6eaa..bb6129dacda8d 100644 --- a/src/test/ui/nll/user-annotations/cast_static_lifetime.rs +++ b/src/test/ui/nll/user-annotations/cast_static_lifetime.rs @@ -1,5 +1,4 @@ #![allow(warnings)] -#![feature(nll)] fn main() { let x = 22_u32; diff --git a/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr b/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr index 7e795ce17a8dd..4599d04e7e230 100644 --- a/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr +++ b/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr @@ -1,7 +1,7 @@ error[E0597]: `x` does not live long enough - --> $DIR/cast_static_lifetime.rs:6:19 + --> $DIR/cast_static_lifetime.rs:5:19 | -LL | let y: &u32 = (&x) as &'static u32; //~ ERROR `x` does not live long enough +LL | let y: &u32 = (&x) as &'static u32; | ^^^^---------------- | | | borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/closure-substs.stderr b/src/test/ui/nll/user-annotations/closure-substs.stderr index a46ab61418efb..384d53f0e4b0a 100644 --- a/src/test/ui/nll/user-annotations/closure-substs.stderr +++ b/src/test/ui/nll/user-annotations/closure-substs.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | fn foo<'a>() { | -- lifetime `'a` defined here ... -LL | return x; //~ ERROR lifetime may not live long enough +LL | return x; | ^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -12,7 +12,7 @@ error: lifetime may not live long enough | LL | |x: &i32| -> &'static i32 { | - let's call the lifetime of this reference `'1` -LL | return x; //~ ERROR lifetime may not live long enough +LL | return x; | ^ returning this value requires that `'1` must outlive `'static` error: lifetime may not live long enough @@ -21,7 +21,7 @@ error: lifetime may not live long enough LL | fn bar<'a>() { | -- lifetime `'a` defined here ... -LL | b(x); //~ ERROR lifetime may not live long enough +LL | b(x); | ^^^^ argument requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of closure @@ -29,9 +29,8 @@ error[E0521]: borrowed data escapes outside of closure | LL | |x: &i32, b: fn(&'static i32)| { | - `x` is a reference that is only valid in the closure body -LL | b(x); //~ ERROR borrowed data escapes outside of closure +LL | b(x); | ^^^^ `x` escapes the closure body here error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr new file mode 100644 index 0000000000000..c39301588acfa --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/constant-in-expr-inherent-1.rs:8:5 + | +LL | fn foo<'a>(_: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | >::C + | ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs index 058ebaee9e512..e3a8a5f58dfda 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - struct Foo<'a> { x: &'a u32 } impl<'a> Foo<'a> { @@ -12,4 +10,3 @@ fn foo<'a>(_: &'a u32) -> &'static u32 { fn main() { } - diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr index 541a7113ec740..77e1339dc161d 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr @@ -1,10 +1,23 @@ -error: lifetime may not live long enough - --> $DIR/constant-in-expr-inherent-1.rs:10:5 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/constant-in-expr-inherent-1.rs:8:5 + | +LL | >::C + | ^^^^^^^^^^^^ + | +note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 7:8... + --> $DIR/constant-in-expr-inherent-1.rs:7:8 | LL | fn foo<'a>(_: &'a u32) -> &'static u32 { - | -- lifetime `'a` defined here -LL | >::C //~ ERROR - | ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + | ^^ + = note: ...so that the types are compatible: + expected Foo<'_> + found Foo<'a> + = note: but, the lifetime must be valid for the static lifetime... +note: ...so that reference does not outlive borrowed content + --> $DIR/constant-in-expr-inherent-1.rs:8:5 + | +LL | >::C + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs index 123be6b3e4098..90696d4b17d8d 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs @@ -1,8 +1,6 @@ // Test that we still check constants are well-formed, even when we there's no // type annotation to check. -#![feature(nll)] - const FUN: fn(&'static ()) = |_| {}; struct A; impl A { diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr index 57cfaa2db0432..12065a85aa4a0 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr @@ -1,7 +1,7 @@ error[E0597]: `x` does not live long enough - --> $DIR/constant-in-expr-inherent-2.rs:25:9 + --> $DIR/constant-in-expr-inherent-2.rs:23:9 | -LL | FUN(&x); //~ ERROR `x` does not live long enough +LL | FUN(&x); | ----^^- | | | | | borrowed value does not live long enough @@ -11,9 +11,9 @@ LL | } | - `x` dropped here while still borrowed error[E0597]: `x` does not live long enough - --> $DIR/constant-in-expr-inherent-2.rs:26:23 + --> $DIR/constant-in-expr-inherent-2.rs:24:23 | -LL | A::ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough +LL | A::ASSOCIATED_FUN(&x); | ------------------^^- | | | | | borrowed value does not live long enough @@ -23,21 +23,21 @@ LL | } | - `x` dropped here while still borrowed error[E0597]: `x` does not live long enough - --> $DIR/constant-in-expr-inherent-2.rs:27:28 + --> $DIR/constant-in-expr-inherent-2.rs:25:28 | -LL | B::ALSO_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough +LL | B::ALSO_ASSOCIATED_FUN(&x); | -----------------------^^- | | | | | borrowed value does not live long enough | argument requires that `x` is borrowed for `'static` -LL | <_>::TRAIT_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough +LL | <_>::TRAIT_ASSOCIATED_FUN(&x); LL | } | - `x` dropped here while still borrowed error[E0597]: `x` does not live long enough - --> $DIR/constant-in-expr-inherent-2.rs:28:31 + --> $DIR/constant-in-expr-inherent-2.rs:26:31 | -LL | <_>::TRAIT_ASSOCIATED_FUN(&x); //~ ERROR `x` does not live long enough +LL | <_>::TRAIT_ASSOCIATED_FUN(&x); | --------------------------^^- | | | | | borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr new file mode 100644 index 0000000000000..541a2cfaf299a --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/constant-in-expr-normalize.rs:18:5 + | +LL | fn foo<'a>(_: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | <() as Foo<'a>>::C + | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs index 4292fc710e98b..b7095430d8bd2 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs +++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - trait Mirror { type Me; } diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr index 5b97c12b626b3..f49d68458bea5 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr @@ -1,10 +1,15 @@ -error: lifetime may not live long enough - --> $DIR/constant-in-expr-normalize.rs:20:5 +error[E0312]: lifetime of reference outlives lifetime of borrowed content... + --> $DIR/constant-in-expr-normalize.rs:18:5 + | +LL | <() as Foo<'a>>::C + | ^^^^^^^^^^^^^^^^^^ + | + = note: ...the reference is valid for the static lifetime... +note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 17:8 + --> $DIR/constant-in-expr-normalize.rs:17:8 | LL | fn foo<'a>(_: &'a u32) -> &'static u32 { - | -- lifetime `'a` defined here -LL | <() as Foo<'a>>::C //~ ERROR - | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + | ^^ error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr new file mode 100644 index 0000000000000..ea0fcb6d634cd --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/constant-in-expr-trait-item-1.rs:10:5 + | +LL | fn foo<'a>(_: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | <() as Foo<'a>>::C + | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs index daa0d7bc24140..e0400b2cc0267 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - trait Foo<'a> { const C: &'a u32; } diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr index 10e48b5bc348b..451bcf41e42a9 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr @@ -1,10 +1,15 @@ -error: lifetime may not live long enough - --> $DIR/constant-in-expr-trait-item-1.rs:12:5 +error[E0312]: lifetime of reference outlives lifetime of borrowed content... + --> $DIR/constant-in-expr-trait-item-1.rs:10:5 + | +LL | <() as Foo<'a>>::C + | ^^^^^^^^^^^^^^^^^^ + | + = note: ...the reference is valid for the static lifetime... +note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 9:8 + --> $DIR/constant-in-expr-trait-item-1.rs:9:8 | LL | fn foo<'a>(_: &'a u32) -> &'static u32 { - | -- lifetime `'a` defined here -LL | <() as Foo<'a>>::C //~ ERROR - | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + | ^^ error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr new file mode 100644 index 0000000000000..ff549f1d88bd4 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/constant-in-expr-trait-item-2.rs:10:5 + | +LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 { + | -- lifetime `'a` defined here +LL | >::C + | ^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs index cd66e7a49cb83..73c4e577b05c0 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - trait Foo<'a> { const C: &'a u32; } diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr index 5bfa32ec64492..d129e55e1e6f6 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr @@ -1,10 +1,15 @@ -error: lifetime may not live long enough - --> $DIR/constant-in-expr-trait-item-2.rs:12:5 +error[E0312]: lifetime of reference outlives lifetime of borrowed content... + --> $DIR/constant-in-expr-trait-item-2.rs:10:5 + | +LL | >::C + | ^^^^^^^^^^^^^^^^^ + | + = note: ...the reference is valid for the static lifetime... +note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 9:8 + --> $DIR/constant-in-expr-trait-item-2.rs:9:8 | LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 { - | -- lifetime `'a` defined here -LL | >::C //~ ERROR - | ^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + | ^^ error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr new file mode 100644 index 0000000000000..7f160d8e398b9 --- /dev/null +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/constant-in-expr-trait-item-3.rs:10:5 + | +LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 { + | -- lifetime `'a` defined here +LL | T::C + | ^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs index f83ae2438e6d5..567e31ef93632 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - trait Foo<'a> { const C: &'a u32; } diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr index a1e60db05d08f..77655fe091b62 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr @@ -1,10 +1,23 @@ -error: lifetime may not live long enough - --> $DIR/constant-in-expr-trait-item-3.rs:12:5 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/constant-in-expr-trait-item-3.rs:10:5 + | +LL | T::C + | ^^^^ + | +note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 9:8... + --> $DIR/constant-in-expr-trait-item-3.rs:9:8 | LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 { - | -- lifetime `'a` defined here -LL | T::C //~ ERROR - | ^^^^ returning this value requires that `'a` must outlive `'static` + | ^^ + = note: ...so that the types are compatible: + expected Foo<'_> + found Foo<'a> + = note: but, the lifetime must be valid for the static lifetime... +note: ...so that reference does not outlive borrowed content + --> $DIR/constant-in-expr-trait-item-3.rs:10:5 + | +LL | T::C + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr index 6e24da094e0d2..ae123b8ab5451 100644 --- a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr +++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr @@ -1,7 +1,7 @@ error: user substs: UserSubsts { substs: [&ReStatic u32], user_self_ty: None } --> $DIR/dump-adt-brace-struct.rs:20:5 | -LL | SomeStruct::<&'static u32> { t: &22 }; //~ ERROR [&ReStatic u32] +LL | SomeStruct::<&'static u32> { t: &22 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.stderr b/src/test/ui/nll/user-annotations/dump-fn-method.stderr index 04ceb8e5f8495..631bcde4ee877 100644 --- a/src/test/ui/nll/user-annotations/dump-fn-method.stderr +++ b/src/test/ui/nll/user-annotations/dump-fn-method.stderr @@ -1,25 +1,25 @@ error: user substs: UserSubsts { substs: [&ReStatic u32], user_self_ty: None } --> $DIR/dump-fn-method.rs:30:13 | -LL | let x = foo::<&'static u32>; //~ ERROR [&ReStatic u32] +LL | let x = foo::<&'static u32>; | ^^^^^^^^^^^^^^^^^^^ error: user substs: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None } --> $DIR/dump-fn-method.rs:36:13 | -LL | let x = <_ as Bazoom>::method::<_>; //~ ERROR [^0, u32, ^1] +LL | let x = <_ as Bazoom>::method::<_>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: user substs: UserSubsts { substs: [u8, &ReStatic u16, u32], user_self_ty: None } --> $DIR/dump-fn-method.rs:45:13 | -LL | let x = >::method::; //~ ERROR [u8, &ReStatic u16, u32] +LL | let x = >::method::; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: user substs: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } --> $DIR/dump-fn-method.rs:53:5 | -LL | y.method::(44, 66); //~ ERROR [^0, ^1, u32] +LL | y.method::(44, 66); | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/user-annotations/fns.rs b/src/test/ui/nll/user-annotations/fns.rs index 1e5e9340bef51..38db6d1c4c56f 100644 --- a/src/test/ui/nll/user-annotations/fns.rs +++ b/src/test/ui/nll/user-annotations/fns.rs @@ -1,8 +1,6 @@ // Unit test for the "user substitutions" that are annotated on each // node. -#![feature(nll)] - fn some_fn(arg: T) { } fn no_annot() { diff --git a/src/test/ui/nll/user-annotations/fns.stderr b/src/test/ui/nll/user-annotations/fns.stderr index 65af2f68bcf8c..e0640da39e2b6 100644 --- a/src/test/ui/nll/user-annotations/fns.stderr +++ b/src/test/ui/nll/user-annotations/fns.stderr @@ -1,7 +1,7 @@ error[E0597]: `c` does not live long enough - --> $DIR/fns.rs:25:29 + --> $DIR/fns.rs:23:29 | -LL | some_fn::<&'static u32>(&c); //~ ERROR +LL | some_fn::<&'static u32>(&c); | ------------------------^^- | | | | | borrowed value does not live long enough @@ -10,12 +10,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/fns.rs:30:24 + --> $DIR/fns.rs:28:24 | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here LL | let c = 66; -LL | some_fn::<&'a u32>(&c); //~ ERROR +LL | some_fn::<&'a u32>(&c); | -------------------^^- | | | | | borrowed value does not live long enough @@ -24,12 +24,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/fns.rs:40:28 + --> $DIR/fns.rs:38:28 | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here ... -LL | some_fn::<&'a u32>(&c); //~ ERROR +LL | some_fn::<&'a u32>(&c); | -------------------^^- | | | | | borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr b/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr index 785b39ec887a0..768454698987e 100644 --- a/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr +++ b/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr @@ -3,7 +3,7 @@ error: lifetime may not live long enough | LL | fn non_wf_associated_const<'a>(x: i32) { | -- lifetime `'a` defined here -LL | A::<'a>::IC; //~ ERROR lifetime may not live long enough +LL | A::<'a>::IC; | ^^^^^^^^^^^ requires that `'a` must outlive `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/issue-54124.stderr b/src/test/ui/nll/user-annotations/issue-54124.stderr index b1c2411e46c01..6cfccf7cb69ce 100644 --- a/src/test/ui/nll/user-annotations/issue-54124.stderr +++ b/src/test/ui/nll/user-annotations/issue-54124.stderr @@ -3,7 +3,7 @@ error: lifetime may not live long enough | LL | fn test<'a>() { | -- lifetime `'a` defined here -LL | let _:fn(&()) = |_:&'a ()| {}; //~ ERROR lifetime may not live long enough +LL | let _:fn(&()) = |_:&'a ()| {}; | ^ - let's call the lifetime of this reference `'1` | | | requires that `'1` must outlive `'a` @@ -13,7 +13,7 @@ error: lifetime may not live long enough | LL | fn test<'a>() { | -- lifetime `'a` defined here -LL | let _:fn(&()) = |_:&'a ()| {}; //~ ERROR lifetime may not live long enough +LL | let _:fn(&()) = |_:&'a ()| {}; | ^ requires that `'a` must outlive `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/user-annotations/issue-54570-bootstrapping.rs b/src/test/ui/nll/user-annotations/issue-54570-bootstrapping.rs index 0a8a6793dc782..6b9d30f5ab425 100644 --- a/src/test/ui/nll/user-annotations/issue-54570-bootstrapping.rs +++ b/src/test/ui/nll/user-annotations/issue-54570-bootstrapping.rs @@ -1,5 +1,4 @@ // compile-pass -#![feature(nll)] // This test is reduced from a scenario pnkfelix encountered while // bootstrapping the compiler. diff --git a/src/test/ui/nll/user-annotations/issue-55219.rs b/src/test/ui/nll/user-annotations/issue-55219.rs index 7daa5a59b9977..4d18e96cc1543 100644 --- a/src/test/ui/nll/user-annotations/issue-55219.rs +++ b/src/test/ui/nll/user-annotations/issue-55219.rs @@ -5,8 +5,6 @@ // // run-pass -#![feature(nll)] - pub struct Foo(T); impl Foo { diff --git a/src/test/ui/nll/user-annotations/issue-55241.rs b/src/test/ui/nll/user-annotations/issue-55241.rs index d7686b9dc9411..29969c7b4c6c8 100644 --- a/src/test/ui/nll/user-annotations/issue-55241.rs +++ b/src/test/ui/nll/user-annotations/issue-55241.rs @@ -7,8 +7,6 @@ // // run-pass -#![feature(nll)] - pub trait Hasher { type Out: Eq; } diff --git a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs new file mode 100644 index 0000000000000..3d042d442d531 --- /dev/null +++ b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs @@ -0,0 +1,70 @@ +// This test is ensuring that type ascriptions on let bindings +// constrain both: +// +// 1. the input expression on the right-hand side (after any potential +// coercion, and allowing for covariance), *and* +// +// 2. the bindings (if any) nested within the pattern on the left-hand +// side (and here, the type-constraint is *invariant*). + +#![feature(nll)] + +#![allow(dead_code, unused_mut)] +type PairUncoupled<'a, 'b, T> = (&'a T, &'b T); +type PairCoupledRegions<'a, T> = (&'a T, &'a T); +type PairCoupledTypes = (T, T); + +fn uncoupled_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((mut y, mut _z),): (PairUncoupled,) = ((s, &_x),); // ok + // Above compiling does *not* imply below would compile. + // ::std::mem::swap(&mut y, &mut _z); + y +} + +fn swap_regions((mut y, mut _z): PairCoupledRegions) { + ::std::mem::swap(&mut y, &mut _z); +} + +fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((y, _z),): (PairCoupledRegions,) = ((s, &_x),); + // If above line compiled, so should line below ... + + // swap_regions((y, _z)); + + // ... but the ascribed type also invalidates this use of `y` + y //~ ERROR lifetime may not live long enough +} + +fn swap_types((mut y, mut _z): PairCoupledTypes<&u32>) { + ::std::mem::swap(&mut y, &mut _z); +} + +fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((y, _z),): (PairCoupledTypes<&u32>,) = ((s, &_x),); + // If above line compiled, so should line below ... + + // swap_types((y, _z)); + + // ... but the ascribed type also invalidates this use of `y` + y //~ ERROR lifetime may not live long enough +} + +fn swap_wilds((mut y, mut _z): PairCoupledTypes<&u32>) { + ::std::mem::swap(&mut y, &mut _z); +} + +fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((y, _z),): (PairCoupledTypes<_>,) = ((s, &_x),); + // If above line compiled, so should line below + // swap_wilds((y, _z)); + + // ... but the ascribed type also invalidates this use of `y` + y //~ ERROR lifetime may not live long enough +} + +fn main() { + uncoupled_lhs(&3, &4); + coupled_regions_lhs(&3, &4); + coupled_types_lhs(&3, &4); + coupled_wilds_lhs(&3, &4); +} diff --git a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr new file mode 100644 index 0000000000000..5929707e41e10 --- /dev/null +++ b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr @@ -0,0 +1,29 @@ +error: lifetime may not live long enough + --> $DIR/issue-55748-pat-types-constrain-bindings.rs:35:5 + | +LL | fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y + | ^ returning this value requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/issue-55748-pat-types-constrain-bindings.rs:49:5 + | +LL | fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y + | ^ returning this value requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/issue-55748-pat-types-constrain-bindings.rs:62:5 + | +LL | fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y + | ^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr b/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr index 76be637220a15..c99f53c5aa4c5 100644 --- a/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr +++ b/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | fn coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { | -- lifetime `'a` defined here LL | let ((y, _z),) = ((s, _x),): (PairCoupledTypes<_>,); -LL | y //~ ERROR lifetime may not live long enough +LL | y | ^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -13,7 +13,7 @@ error: lifetime may not live long enough LL | fn coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { | -- lifetime `'a` defined here LL | let ((y, _z),) = ((s, _x),): (PairCoupledRegions<_>,); -LL | y //~ ERROR lifetime may not live long enough +LL | y | ^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -22,7 +22,7 @@ error: lifetime may not live long enough LL | fn cast_coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { | -- lifetime `'a` defined here LL | let ((y, _z),) = ((s, _x),) as (PairCoupledTypes<_>,); -LL | y //~ ERROR lifetime may not live long enough +LL | y | ^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -31,7 +31,7 @@ error: lifetime may not live long enough LL | fn cast_coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { | -- lifetime `'a` defined here LL | let ((y, _z),) = ((s, _x),) as (PairCoupledRegions<_>,); -LL | y //~ ERROR lifetime may not live long enough +LL | y | ^ returning this value requires that `'a` must outlive `'static` error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/user-annotations/method-call.rs b/src/test/ui/nll/user-annotations/method-call.rs index 59d1513c4c38e..beafc597ac113 100644 --- a/src/test/ui/nll/user-annotations/method-call.rs +++ b/src/test/ui/nll/user-annotations/method-call.rs @@ -1,8 +1,6 @@ // Unit test for the "user substitutions" that are annotated on each // node. -#![feature(nll)] - trait Bazoom { fn method(&self, arg: T, arg2: U) { } } diff --git a/src/test/ui/nll/user-annotations/method-call.stderr b/src/test/ui/nll/user-annotations/method-call.stderr index 2e23e6e2a650a..10447e45a6d42 100644 --- a/src/test/ui/nll/user-annotations/method-call.stderr +++ b/src/test/ui/nll/user-annotations/method-call.stderr @@ -1,7 +1,7 @@ error[E0597]: `c` does not live long enough - --> $DIR/method-call.rs:38:34 + --> $DIR/method-call.rs:36:34 | -LL | a.method::<&'static u32>(b, &c); //~ ERROR +LL | a.method::<&'static u32>(b, &c); | -----------------------------^^- | | | | | borrowed value does not live long enough @@ -10,12 +10,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/method-call.rs:45:29 + --> $DIR/method-call.rs:43:29 | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here ... -LL | a.method::<&'a u32>(b, &c); //~ ERROR +LL | a.method::<&'a u32>(b, &c); | ------------------------^^- | | | | | borrowed value does not live long enough @@ -24,12 +24,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/method-call.rs:59:33 + --> $DIR/method-call.rs:57:33 | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here ... -LL | a.method::<&'a u32>(b, &c); //~ ERROR +LL | a.method::<&'a u32>(b, &c); | ------------------------^^- | | | | | borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/method-ufcs-1.rs b/src/test/ui/nll/user-annotations/method-ufcs-1.rs index 7968a9f6c4fd5..950771f35e49c 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-1.rs +++ b/src/test/ui/nll/user-annotations/method-ufcs-1.rs @@ -1,8 +1,6 @@ // Unit test for the "user substitutions" that are annotated on each // node. -#![feature(nll)] - trait Bazoom: Sized { fn method(self, arg: T, arg2: U) { } } diff --git a/src/test/ui/nll/user-annotations/method-ufcs-1.stderr b/src/test/ui/nll/user-annotations/method-ufcs-1.stderr index 30cf01f54bd14..962ddfd2bd151 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-1.stderr +++ b/src/test/ui/nll/user-annotations/method-ufcs-1.stderr @@ -1,7 +1,7 @@ error[E0597]: `a` does not live long enough - --> $DIR/method-ufcs-1.rs:32:7 + --> $DIR/method-ufcs-1.rs:30:7 | -LL | x(&a, b, c); //~ ERROR +LL | x(&a, b, c); | --^^------- | | | | | borrowed value does not live long enough @@ -10,12 +10,12 @@ LL | } | - `a` dropped here while still borrowed error[E0597]: `a` does not live long enough - --> $DIR/method-ufcs-1.rs:39:36 + --> $DIR/method-ufcs-1.rs:37:36 | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here ... -LL | <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR +LL | <&'a u32 as Bazoom<_>>::method(&a, b, c); | -------------------------------^^------- | | | | | borrowed value does not live long enough @@ -24,7 +24,7 @@ LL | } | - `a` dropped here while still borrowed error[E0597]: `a` does not live long enough - --> $DIR/method-ufcs-1.rs:53:41 + --> $DIR/method-ufcs-1.rs:51:41 | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here @@ -32,7 +32,7 @@ LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { LL | let _closure = || { | -- value captured here LL | let c = 66; -LL | <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR +LL | <&'a u32 as Bazoom<_>>::method(&a, b, c); | --------------------------------^------- | | | | | borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/method-ufcs-2.rs b/src/test/ui/nll/user-annotations/method-ufcs-2.rs index a1d0e7b4c9208..7dc0f0c12a43e 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-2.rs +++ b/src/test/ui/nll/user-annotations/method-ufcs-2.rs @@ -1,8 +1,6 @@ // Unit test for the "user substitutions" that are annotated on each // node. -#![feature(nll)] - trait Bazoom: Sized { fn method(self, arg: T, arg2: U) { } } diff --git a/src/test/ui/nll/user-annotations/method-ufcs-2.stderr b/src/test/ui/nll/user-annotations/method-ufcs-2.stderr index 140bb750469b8..63d59905e1c38 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-2.stderr +++ b/src/test/ui/nll/user-annotations/method-ufcs-2.stderr @@ -1,7 +1,7 @@ error[E0597]: `a` does not live long enough - --> $DIR/method-ufcs-2.rs:32:7 + --> $DIR/method-ufcs-2.rs:30:7 | -LL | x(&a, b, c); //~ ERROR +LL | x(&a, b, c); | --^^------- | | | | | borrowed value does not live long enough @@ -10,12 +10,12 @@ LL | } | - `a` dropped here while still borrowed error[E0597]: `b` does not live long enough - --> $DIR/method-ufcs-2.rs:39:39 + --> $DIR/method-ufcs-2.rs:37:39 | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here ... -LL | <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR +LL | <_ as Bazoom<&'a u32>>::method(a, &b, c); | ----------------------------------^^---- | | | | | borrowed value does not live long enough @@ -24,7 +24,7 @@ LL | } | - `b` dropped here while still borrowed error[E0597]: `b` does not live long enough - --> $DIR/method-ufcs-2.rs:53:44 + --> $DIR/method-ufcs-2.rs:51:44 | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here @@ -32,7 +32,7 @@ LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { LL | let _closure = || { | -- value captured here LL | let c = 66; -LL | <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR +LL | <_ as Bazoom<&'a u32>>::method(a, &b, c); | -----------------------------------^---- | | | | | borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/method-ufcs-3.rs b/src/test/ui/nll/user-annotations/method-ufcs-3.rs index ea480c03c3503..59d2009d14bdf 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-3.rs +++ b/src/test/ui/nll/user-annotations/method-ufcs-3.rs @@ -1,8 +1,6 @@ // Unit test for the "user substitutions" that are annotated on each // node. -#![feature(nll)] - trait Bazoom { fn method(&self, arg: T, arg2: U) { } } diff --git a/src/test/ui/nll/user-annotations/method-ufcs-3.stderr b/src/test/ui/nll/user-annotations/method-ufcs-3.stderr index 12b9685bdb87c..e7851833e93b2 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-3.stderr +++ b/src/test/ui/nll/user-annotations/method-ufcs-3.stderr @@ -1,7 +1,7 @@ error[E0597]: `c` does not live long enough - --> $DIR/method-ufcs-3.rs:38:53 + --> $DIR/method-ufcs-3.rs:36:53 | -LL | <_ as Bazoom<_>>::method::<&'static u32>(&a, b, &c); //~ ERROR +LL | <_ as Bazoom<_>>::method::<&'static u32>(&a, b, &c); | ------------------------------------------------^^- | | | | | borrowed value does not live long enough @@ -10,12 +10,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/method-ufcs-3.rs:45:48 + --> $DIR/method-ufcs-3.rs:43:48 | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here ... -LL | <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR +LL | <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); | -------------------------------------------^^- | | | | | borrowed value does not live long enough @@ -24,12 +24,12 @@ LL | } | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough - --> $DIR/method-ufcs-3.rs:59:52 + --> $DIR/method-ufcs-3.rs:57:52 | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here ... -LL | <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR +LL | <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); | -------------------------------------------^^- | | | | | borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr index cb6cc64796461..70e1cda004b09 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr @@ -9,7 +9,7 @@ LL | let x = A::<'a>::new(&v, 22); | | | | | borrowed value does not live long enough | argument requires that `v` is borrowed for `'a` -LL | //~^ ERROR +LL | LL | } | - `v` dropped here while still borrowed diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs index a77d6af5323c2..cfbc0bcf6b0fc 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - // Check that substitutions given on the self type (here, `A`) can be // used in combination with annotations given for method arguments. diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr index 4dc534b2e77ac..06f20d9b23559 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr @@ -1,5 +1,5 @@ error[E0597]: `v` does not live long enough - --> $DIR/method-ufcs-inherent-2.rs:16:37 + --> $DIR/method-ufcs-inherent-2.rs:14:37 | LL | fn foo<'a>() { | -- lifetime `'a` defined here @@ -14,7 +14,7 @@ LL | } | - `v` dropped here while still borrowed error[E0597]: `v` does not live long enough - --> $DIR/method-ufcs-inherent-2.rs:16:41 + --> $DIR/method-ufcs-inherent-2.rs:14:41 | LL | fn foo<'a>() { | -- lifetime `'a` defined here diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr index 2f83283ef9122..50e4fb259918f 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr @@ -9,7 +9,7 @@ LL | let x = >::new(&v, 22); | | | | | borrowed value does not live long enough | argument requires that `v` is borrowed for `'a` -LL | //~^ ERROR +LL | LL | } | - `v` dropped here while still borrowed diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs index 3f88c3df48e00..85e7597390d5c 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - // Check that inherent methods invoked with `::new` style // carry their annotations through to NLL in connection with // method type parameters. diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr index a41cf50465e87..0f83e99cdfb92 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr @@ -1,5 +1,5 @@ error[E0597]: `v` does not live long enough - --> $DIR/method-ufcs-inherent-4.rs:17:37 + --> $DIR/method-ufcs-inherent-4.rs:15:37 | LL | fn foo<'a>() { | -- lifetime `'a` defined here @@ -14,7 +14,7 @@ LL | } | - `v` dropped here while still borrowed error[E0597]: `v` does not live long enough - --> $DIR/method-ufcs-inherent-4.rs:17:41 + --> $DIR/method-ufcs-inherent-4.rs:15:41 | LL | fn foo<'a>() { | -- lifetime `'a` defined here diff --git a/src/test/ui/nll/user-annotations/normalization.rs b/src/test/ui/nll/user-annotations/normalization.rs index e0af2e67e1836..870e3d8110cd5 100644 --- a/src/test/ui/nll/user-annotations/normalization.rs +++ b/src/test/ui/nll/user-annotations/normalization.rs @@ -1,8 +1,6 @@ // Test that we enforce a `&'static` requirement that is only visible // after normalization. -#![feature(nll)] - trait Foo { type Out; } impl Foo for () { type Out = &'static u32; } diff --git a/src/test/ui/nll/user-annotations/normalization.stderr b/src/test/ui/nll/user-annotations/normalization.stderr index 71bf8507a735f..4c7893789a535 100644 --- a/src/test/ui/nll/user-annotations/normalization.stderr +++ b/src/test/ui/nll/user-annotations/normalization.stderr @@ -1,7 +1,7 @@ error[E0597]: `a` does not live long enough - --> $DIR/normalization.rs:11:31 + --> $DIR/normalization.rs:9:31 | -LL | let b: <() as Foo>::Out = &a; //~ ERROR +LL | let b: <() as Foo>::Out = &a; | ---------------- ^^ borrowed value does not live long enough | | | type annotation requires that `a` is borrowed for `'static` diff --git a/src/test/ui/nll/user-annotations/normalize-self-ty.rs b/src/test/ui/nll/user-annotations/normalize-self-ty.rs index d97cc88dd9af4..a06229a02032a 100644 --- a/src/test/ui/nll/user-annotations/normalize-self-ty.rs +++ b/src/test/ui/nll/user-annotations/normalize-self-ty.rs @@ -4,8 +4,6 @@ // // run-pass -#![feature(nll)] - trait Mirror { type Me; } diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs index 526134b6e4b3c..59cd69c0ca55d 100644 --- a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - enum Foo<'a> { Bar { field: &'a u32 } } diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr index 800c822058d0a..a97e7a9fd46fc 100644 --- a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr @@ -1,16 +1,16 @@ error[E0597]: `y` does not live long enough - --> $DIR/pattern_substs_on_brace_enum_variant.rs:9:33 + --> $DIR/pattern_substs_on_brace_enum_variant.rs:7:33 | LL | let foo = Foo::Bar { field: &y }; | ^^ borrowed value does not live long enough -LL | //~^ ERROR `y` does not live long enough +LL | LL | let Foo::Bar::<'static> { field: _z } = foo; | --------------------------------- type annotation requires that `y` is borrowed for `'static` LL | } | - `y` dropped here while still borrowed error[E0597]: `y` does not live long enough - --> $DIR/pattern_substs_on_brace_enum_variant.rs:16:33 + --> $DIR/pattern_substs_on_brace_enum_variant.rs:14:33 | LL | let foo = Foo::Bar { field: &y }; | ^^ borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs index 1c92858eb3a08..1586c4ea30c62 100644 --- a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - struct Foo<'a> { field: &'a u32 } fn in_let() { diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr index 8adadfb8b6796..408d7c2a5e2a5 100644 --- a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr @@ -1,16 +1,16 @@ error[E0597]: `y` does not live long enough - --> $DIR/pattern_substs_on_brace_struct.rs:7:28 + --> $DIR/pattern_substs_on_brace_struct.rs:5:28 | LL | let foo = Foo { field: &y }; | ^^ borrowed value does not live long enough -LL | //~^ ERROR `y` does not live long enough +LL | LL | let Foo::<'static> { field: _z } = foo; | ---------------------------- type annotation requires that `y` is borrowed for `'static` LL | } | - `y` dropped here while still borrowed error[E0597]: `y` does not live long enough - --> $DIR/pattern_substs_on_brace_struct.rs:14:28 + --> $DIR/pattern_substs_on_brace_struct.rs:12:28 | LL | let foo = Foo { field: &y }; | ^^ borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs index d6c364f8e3f0c..6fa59fdd8d899 100644 --- a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - enum Foo<'a> { Bar(&'a u32) } diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr index 0fd5fc3578d57..920c906f63a58 100644 --- a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr @@ -1,16 +1,16 @@ error[E0597]: `y` does not live long enough - --> $DIR/pattern_substs_on_tuple_enum_variant.rs:9:24 + --> $DIR/pattern_substs_on_tuple_enum_variant.rs:7:24 | LL | let foo = Foo::Bar(&y); | ^^ borrowed value does not live long enough -LL | //~^ ERROR `y` does not live long enough +LL | LL | let Foo::Bar::<'static>(_z) = foo; | ----------------------- type annotation requires that `y` is borrowed for `'static` LL | } | - `y` dropped here while still borrowed error[E0597]: `y` does not live long enough - --> $DIR/pattern_substs_on_tuple_enum_variant.rs:16:24 + --> $DIR/pattern_substs_on_tuple_enum_variant.rs:14:24 | LL | let foo = Foo::Bar(&y); | ^^ borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs index 626ca90879787..7486aab0e0883 100644 --- a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - struct Foo<'a>(&'a u32); fn in_let() { diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr index 3d114fa5d7535..3f01638d84757 100644 --- a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr +++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr @@ -1,16 +1,16 @@ error[E0597]: `y` does not live long enough - --> $DIR/pattern_substs_on_tuple_struct.rs:7:19 + --> $DIR/pattern_substs_on_tuple_struct.rs:5:19 | LL | let foo = Foo(&y); | ^^ borrowed value does not live long enough -LL | //~^ ERROR `y` does not live long enough +LL | LL | let Foo::<'static>(_z) = foo; | ------------------ type annotation requires that `y` is borrowed for `'static` LL | } | - `y` dropped here while still borrowed error[E0597]: `y` does not live long enough - --> $DIR/pattern_substs_on_tuple_struct.rs:14:19 + --> $DIR/pattern_substs_on_tuple_struct.rs:12:19 | LL | let foo = Foo(&y); | ^^ borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/patterns.stderr b/src/test/ui/nll/user-annotations/patterns.stderr index 476578e074dac..7ebd0ae227a80 100644 --- a/src/test/ui/nll/user-annotations/patterns.stderr +++ b/src/test/ui/nll/user-annotations/patterns.stderr @@ -3,7 +3,7 @@ error[E0597]: `x` does not live long enough | LL | let y: &'static u32; | ------------ type annotation requires that `x` is borrowed for `'static` -LL | y = &x; //~ ERROR +LL | y = &x; | ^^ borrowed value does not live long enough LL | } | - `x` dropped here while still borrowed @@ -13,7 +13,7 @@ error[E0597]: `x` does not live long enough | LL | let (y, z): (&'static u32, &'static u32); | ---------------------------- type annotation requires that `x` is borrowed for `'static` -LL | y = &x; //~ ERROR +LL | y = &x; | ^^ borrowed value does not live long enough LL | } | - `x` dropped here while still borrowed @@ -21,7 +21,7 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:22:13 | -LL | let y = &x; //~ ERROR +LL | let y = &x; | ^^ borrowed value does not live long enough LL | let ref z: &'static u32 = y; | ------------ type annotation requires that `x` is borrowed for `'static` @@ -34,7 +34,7 @@ error[E0597]: `x` does not live long enough | LL | let Single { value: y }: Single<&'static u32>; | -------------------- type annotation requires that `x` is borrowed for `'static` -LL | y = &x; //~ ERROR +LL | y = &x; | ^^ borrowed value does not live long enough LL | } | - `x` dropped here while still borrowed @@ -44,7 +44,7 @@ error[E0597]: `x` does not live long enough | LL | let Single2 { value: mut _y }: Single2; | ------------------ type annotation requires that `x` is borrowed for `'static` -LL | _y = &x; //~ ERROR +LL | _y = &x; | ^^ borrowed value does not live long enough LL | } | - `x` dropped here while still borrowed @@ -52,7 +52,7 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:58:27 | -LL | let y: &'static u32 = &x; //~ ERROR +LL | let y: &'static u32 = &x; | ------------ ^^ borrowed value does not live long enough | | | type annotation requires that `x` is borrowed for `'static` @@ -62,7 +62,7 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:63:27 | -LL | let _: &'static u32 = &x; //~ ERROR +LL | let _: &'static u32 = &x; | ------------ ^^ borrowed value does not live long enough | | | type annotation requires that `x` is borrowed for `'static` @@ -100,7 +100,7 @@ LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44); error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:77:40 | -LL | let (_, _): (&'static u32, u32) = (&x, 44); //~ ERROR +LL | let (_, _): (&'static u32, u32) = (&x, 44); | ------------------- ^^ borrowed value does not live long enough | | | type annotation requires that `x` is borrowed for `'static` @@ -110,7 +110,7 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:82:40 | -LL | let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR +LL | let (y, _): (&'static u32, u32) = (&x, 44); | ------------------- ^^ borrowed value does not live long enough | | | type annotation requires that `x` is borrowed for `'static` @@ -120,7 +120,7 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:87:69 | -LL | let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR +LL | let Single { value: y }: Single<&'static u32> = Single { value: &x }; | -------------------- ^^ borrowed value does not live long enough | | | type annotation requires that `x` is borrowed for `'static` @@ -130,7 +130,7 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:92:69 | -LL | let Single { value: _ }: Single<&'static u32> = Single { value: &x }; //~ ERROR +LL | let Single { value: _ }: Single<&'static u32> = Single { value: &x }; | -------------------- ^^ borrowed value does not live long enough | | | type annotation requires that `x` is borrowed for `'static` @@ -142,7 +142,7 @@ error[E0597]: `x` does not live long enough | LL | let Double { value1: _, value2: _ }: Double<&'static u32> = Double { | -------------------- type annotation requires that `x` is borrowed for `'static` -LL | value1: &x, //~ ERROR +LL | value1: &x, | ^^ borrowed value does not live long enough ... LL | } @@ -154,7 +154,7 @@ error: lifetime may not live long enough LL | fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here ... -LL | y //~ ERROR +LL | y | ^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -163,7 +163,7 @@ error: lifetime may not live long enough LL | fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here ... -LL | y //~ ERROR +LL | y | ^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -172,7 +172,7 @@ error: lifetime may not live long enough LL | fn static_to_a_to_static_through_struct<'a>(_x: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here LL | let Single { value: y }: Single<&'a u32> = Single { value: &22 }; -LL | y //~ ERROR +LL | y | ^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough @@ -180,10 +180,10 @@ error: lifetime may not live long enough | LL | fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here -LL | let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR +LL | let (y, _z): (&'static u32, u32) = (x, 44); | ^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: aborting due to 19 previous errors -Some errors occurred: E0597, E0716. +Some errors have detailed explanations: E0597, E0716. For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/promoted-annotation.rs b/src/test/ui/nll/user-annotations/promoted-annotation.rs index fa2d2fb81183d..b92f8bfd23b23 100644 --- a/src/test/ui/nll/user-annotations/promoted-annotation.rs +++ b/src/test/ui/nll/user-annotations/promoted-annotation.rs @@ -1,7 +1,5 @@ // Test that type annotations are checked in promoted constants correctly. -#![feature(nll)] - fn foo<'a>() { let x = 0; let f = &drop::<&'a i32>; diff --git a/src/test/ui/nll/user-annotations/promoted-annotation.stderr b/src/test/ui/nll/user-annotations/promoted-annotation.stderr index 144af1e0ec120..cb99a6a369d0b 100644 --- a/src/test/ui/nll/user-annotations/promoted-annotation.stderr +++ b/src/test/ui/nll/user-annotations/promoted-annotation.stderr @@ -1,5 +1,5 @@ error[E0597]: `x` does not live long enough - --> $DIR/promoted-annotation.rs:8:7 + --> $DIR/promoted-annotation.rs:6:7 | LL | fn foo<'a>() { | -- lifetime `'a` defined here @@ -8,7 +8,7 @@ LL | let f = &drop::<&'a i32>; | ---------------- assignment requires that `x` is borrowed for `'a` LL | f(&x); | ^^ borrowed value does not live long enough -LL | //~^ ERROR `x` does not live long enough +LL | LL | } | - `x` dropped here while still borrowed diff --git a/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs b/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs index 362fe51c3ea37..101b5cfabb3d0 100644 --- a/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs +++ b/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs @@ -1,5 +1,4 @@ #![allow(warnings)] -#![feature(nll)] #![feature(type_ascription)] fn main() { diff --git a/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr b/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr index a88ff6df3d791..133bbef52311d 100644 --- a/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr +++ b/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr @@ -1,7 +1,7 @@ error[E0597]: `x` does not live long enough - --> $DIR/type_ascription_static_lifetime.rs:7:19 + --> $DIR/type_ascription_static_lifetime.rs:6:19 | -LL | let y: &u32 = &x: &'static u32; //~ ERROR E0597 +LL | let y: &u32 = &x: &'static u32; | ^^-------------- | | | borrowed value does not live long enough diff --git a/src/test/ui/nll/user-annotations/wf-self-type.stderr b/src/test/ui/nll/user-annotations/wf-self-type.stderr index 00500c8d6541f..8f8e1bc28f6fa 100644 --- a/src/test/ui/nll/user-annotations/wf-self-type.stderr +++ b/src/test/ui/nll/user-annotations/wf-self-type.stderr @@ -5,7 +5,7 @@ LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here -LL | Foo::xmute(u) //~ ERROR lifetime may not live long enough +LL | Foo::xmute(u) | ^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a` error: aborting due to previous error diff --git a/src/test/ui/no-args-non-move-async-closure.rs b/src/test/ui/no-args-non-move-async-closure.rs deleted file mode 100644 index 4f5b2ea3783aa..0000000000000 --- a/src/test/ui/no-args-non-move-async-closure.rs +++ /dev/null @@ -1,8 +0,0 @@ -// edition:2018 - -#![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)] - -fn main() { - let _ = async |x: u8| {}; - //~^ ERROR `async` non-`move` closures with arguments are not currently supported -} diff --git a/src/test/ui/no-capture-arc.nll.stderr b/src/test/ui/no-capture-arc.nll.stderr deleted file mode 100644 index 476b6f75abb46..0000000000000 --- a/src/test/ui/no-capture-arc.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0382]: borrow of moved value: `arc_v` - --> $DIR/no-capture-arc.rs:14:18 - | -LL | let arc_v = Arc::new(v); - | ----- move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait -LL | -LL | thread::spawn(move|| { - | ------ value moved into closure here -LL | assert_eq!((*arc_v)[3], 4); - | ----- variable moved due to use in closure -... -LL | assert_eq!((*arc_v)[2], 3); - | ^^^^^ value borrowed here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/no-capture-arc.rs b/src/test/ui/no-capture-arc.rs index 06f5fb3da3c0b..3f0b075778bd9 100644 --- a/src/test/ui/no-capture-arc.rs +++ b/src/test/ui/no-capture-arc.rs @@ -1,4 +1,4 @@ -// error-pattern: use of moved value +// error-pattern: borrow of moved value use std::sync::Arc; use std::thread; diff --git a/src/test/ui/no-capture-arc.stderr b/src/test/ui/no-capture-arc.stderr index 0dfa5cdbe9ef3..476b6f75abb46 100644 --- a/src/test/ui/no-capture-arc.stderr +++ b/src/test/ui/no-capture-arc.stderr @@ -1,25 +1,17 @@ -error[E0382]: use of moved value: `arc_v` +error[E0382]: borrow of moved value: `arc_v` --> $DIR/no-capture-arc.rs:14:18 | +LL | let arc_v = Arc::new(v); + | ----- move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait +LL | LL | thread::spawn(move|| { - | ------ value moved (into closure) here + | ------ value moved into closure here +LL | assert_eq!((*arc_v)[3], 4); + | ----- variable moved due to use in closure ... LL | assert_eq!((*arc_v)[2], 3); - | ^^^^^ value used here after move - | - = note: move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `arc_v` - --> $DIR/no-capture-arc.rs:16:23 - | -LL | thread::spawn(move|| { - | ------ value moved (into closure) here -... -LL | println!("{:?}", *arc_v); - | ^^^^^ value used here after move - | - = note: move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait + | ^^^^^ value borrowed here after move -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/no-implicit-prelude-nested.stderr b/src/test/ui/no-implicit-prelude-nested.stderr index 7ef4bfbaf9920..79b9396d41cc9 100644 --- a/src/test/ui/no-implicit-prelude-nested.stderr +++ b/src/test/ui/no-implicit-prelude-nested.stderr @@ -1,7 +1,7 @@ error[E0405]: cannot find trait `Add` in this scope --> $DIR/no-implicit-prelude-nested.rs:11:14 | -LL | impl Add for Test {} //~ ERROR cannot find trait `Add` in this scope +LL | impl Add for Test {} | ^^^ not found in this scope help: possible candidate is found in another module, you can import it into scope | @@ -11,7 +11,7 @@ LL | use std::ops::Add; error[E0405]: cannot find trait `Clone` in this scope --> $DIR/no-implicit-prelude-nested.rs:12:14 | -LL | impl Clone for Test {} //~ ERROR cannot find trait `Clone` in this scope +LL | impl Clone for Test {} | ^^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -23,7 +23,7 @@ LL | use std::prelude::v1::Clone; error[E0405]: cannot find trait `Iterator` in this scope --> $DIR/no-implicit-prelude-nested.rs:13:14 | -LL | impl Iterator for Test {} //~ ERROR cannot find trait `Iterator` in this scope +LL | impl Iterator for Test {} | ^^^^^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -35,7 +35,7 @@ LL | use std::prelude::v1::Iterator; error[E0405]: cannot find trait `ToString` in this scope --> $DIR/no-implicit-prelude-nested.rs:14:14 | -LL | impl ToString for Test {} //~ ERROR cannot find trait `ToString` in this scope +LL | impl ToString for Test {} | ^^^^^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -47,13 +47,13 @@ LL | use std::string::ToString; error[E0405]: cannot find trait `Writer` in this scope --> $DIR/no-implicit-prelude-nested.rs:15:14 | -LL | impl Writer for Test {} //~ ERROR cannot find trait `Writer` in this scope +LL | impl Writer for Test {} | ^^^^^^ not found in this scope error[E0425]: cannot find function `drop` in this scope --> $DIR/no-implicit-prelude-nested.rs:18:13 | -LL | drop(2) //~ ERROR cannot find function `drop` in this scope +LL | drop(2) | ^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -65,7 +65,7 @@ LL | use std::prelude::v1::drop; error[E0405]: cannot find trait `Add` in this scope --> $DIR/no-implicit-prelude-nested.rs:23:10 | -LL | impl Add for Test {} //~ ERROR cannot find trait `Add` in this scope +LL | impl Add for Test {} | ^^^ not found in this scope help: possible candidate is found in another module, you can import it into scope | @@ -75,7 +75,7 @@ LL | use std::ops::Add; error[E0405]: cannot find trait `Clone` in this scope --> $DIR/no-implicit-prelude-nested.rs:24:10 | -LL | impl Clone for Test {} //~ ERROR cannot find trait `Clone` in this scope +LL | impl Clone for Test {} | ^^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -87,7 +87,7 @@ LL | use std::prelude::v1::Clone; error[E0405]: cannot find trait `Iterator` in this scope --> $DIR/no-implicit-prelude-nested.rs:25:10 | -LL | impl Iterator for Test {} //~ ERROR cannot find trait `Iterator` in this scope +LL | impl Iterator for Test {} | ^^^^^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -99,7 +99,7 @@ LL | use std::prelude::v1::Iterator; error[E0405]: cannot find trait `ToString` in this scope --> $DIR/no-implicit-prelude-nested.rs:26:10 | -LL | impl ToString for Test {} //~ ERROR cannot find trait `ToString` in this scope +LL | impl ToString for Test {} | ^^^^^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -111,13 +111,13 @@ LL | use std::string::ToString; error[E0405]: cannot find trait `Writer` in this scope --> $DIR/no-implicit-prelude-nested.rs:27:10 | -LL | impl Writer for Test {} //~ ERROR cannot find trait `Writer` in this scope +LL | impl Writer for Test {} | ^^^^^^ not found in this scope error[E0425]: cannot find function `drop` in this scope --> $DIR/no-implicit-prelude-nested.rs:30:9 | -LL | drop(2) //~ ERROR cannot find function `drop` in this scope +LL | drop(2) | ^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -129,7 +129,7 @@ LL | use std::prelude::v1::drop; error[E0405]: cannot find trait `Add` in this scope --> $DIR/no-implicit-prelude-nested.rs:38:14 | -LL | impl Add for Test {} //~ ERROR cannot find trait `Add` in this scope +LL | impl Add for Test {} | ^^^ not found in this scope help: possible candidate is found in another module, you can import it into scope | @@ -139,7 +139,7 @@ LL | use std::ops::Add; error[E0405]: cannot find trait `Clone` in this scope --> $DIR/no-implicit-prelude-nested.rs:39:14 | -LL | impl Clone for Test {} //~ ERROR cannot find trait `Clone` in this scope +LL | impl Clone for Test {} | ^^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -151,7 +151,7 @@ LL | use std::prelude::v1::Clone; error[E0405]: cannot find trait `Iterator` in this scope --> $DIR/no-implicit-prelude-nested.rs:40:14 | -LL | impl Iterator for Test {} //~ ERROR cannot find trait `Iterator` in this scope +LL | impl Iterator for Test {} | ^^^^^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -163,7 +163,7 @@ LL | use std::prelude::v1::Iterator; error[E0405]: cannot find trait `ToString` in this scope --> $DIR/no-implicit-prelude-nested.rs:41:14 | -LL | impl ToString for Test {} //~ ERROR cannot find trait `ToString` in this scope +LL | impl ToString for Test {} | ^^^^^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -175,13 +175,13 @@ LL | use std::string::ToString; error[E0405]: cannot find trait `Writer` in this scope --> $DIR/no-implicit-prelude-nested.rs:42:14 | -LL | impl Writer for Test {} //~ ERROR cannot find trait `Writer` in this scope +LL | impl Writer for Test {} | ^^^^^^ not found in this scope error[E0425]: cannot find function `drop` in this scope --> $DIR/no-implicit-prelude-nested.rs:45:13 | -LL | drop(2) //~ ERROR cannot find function `drop` in this scope +LL | drop(2) | ^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -192,5 +192,5 @@ LL | use std::prelude::v1::drop; error: aborting due to 18 previous errors -Some errors occurred: E0405, E0425. +Some errors have detailed explanations: E0405, E0425. For more information about an error, try `rustc --explain E0405`. diff --git a/src/test/ui/no-implicit-prelude.stderr b/src/test/ui/no-implicit-prelude.stderr index fa82ac6cbe72c..eac1fcb7b67c1 100644 --- a/src/test/ui/no-implicit-prelude.stderr +++ b/src/test/ui/no-implicit-prelude.stderr @@ -1,7 +1,7 @@ error[E0405]: cannot find trait `Add` in this scope --> $DIR/no-implicit-prelude.rs:10:6 | -LL | impl Add for Test {} //~ ERROR cannot find trait `Add` in this scope +LL | impl Add for Test {} | ^^^ not found in this scope help: possible candidate is found in another module, you can import it into scope | @@ -11,7 +11,7 @@ LL | use std::ops::Add; error[E0405]: cannot find trait `Clone` in this scope --> $DIR/no-implicit-prelude.rs:11:6 | -LL | impl Clone for Test {} //~ ERROR cannot find trait `Clone` in this scope +LL | impl Clone for Test {} | ^^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -23,7 +23,7 @@ LL | use std::prelude::v1::Clone; error[E0405]: cannot find trait `Iterator` in this scope --> $DIR/no-implicit-prelude.rs:12:6 | -LL | impl Iterator for Test {} //~ ERROR cannot find trait `Iterator` in this scope +LL | impl Iterator for Test {} | ^^^^^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -35,7 +35,7 @@ LL | use std::prelude::v1::Iterator; error[E0405]: cannot find trait `ToString` in this scope --> $DIR/no-implicit-prelude.rs:13:6 | -LL | impl ToString for Test {} //~ ERROR cannot find trait `ToString` in this scope +LL | impl ToString for Test {} | ^^^^^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -47,13 +47,13 @@ LL | use std::string::ToString; error[E0405]: cannot find trait `Writer` in this scope --> $DIR/no-implicit-prelude.rs:14:6 | -LL | impl Writer for Test {} //~ ERROR cannot find trait `Writer` in this scope +LL | impl Writer for Test {} | ^^^^^^ not found in this scope error[E0425]: cannot find function `drop` in this scope --> $DIR/no-implicit-prelude.rs:17:5 | -LL | drop(2) //~ ERROR cannot find function `drop` in this scope +LL | drop(2) | ^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -64,5 +64,5 @@ LL | use std::prelude::v1::drop; error: aborting due to 6 previous errors -Some errors occurred: E0405, E0425. +Some errors have detailed explanations: E0405, E0425. For more information about an error, try `rustc --explain E0405`. diff --git a/src/test/ui/no-link-unknown-crate.stderr b/src/test/ui/no-link-unknown-crate.stderr index db76b74fdad0a..068c7139ed9e2 100644 --- a/src/test/ui/no-link-unknown-crate.stderr +++ b/src/test/ui/no-link-unknown-crate.stderr @@ -1,7 +1,7 @@ error[E0463]: can't find crate for `doesnt_exist` --> $DIR/no-link-unknown-crate.rs:2:1 | -LL | extern crate doesnt_exist; //~ ERROR can't find crate +LL | extern crate doesnt_exist; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate error: aborting due to previous error diff --git a/src/test/ui/no-link.stderr b/src/test/ui/no-link.stderr index 928ad4232024e..c9c8468eba432 100644 --- a/src/test/ui/no-link.stderr +++ b/src/test/ui/no-link.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `XEmpty1` in module `empty_struct` --> $DIR/no-link.rs:7:19 | -LL | empty_struct::XEmpty1; //~ ERROR cannot find value `XEmpty1` in module `empty_struct` +LL | empty_struct::XEmpty1; | ^^^^^^^ not found in `empty_struct` error: aborting due to previous error diff --git a/src/test/ui/no-patterns-in-args-2.stderr b/src/test/ui/no-patterns-in-args-2.stderr index 161e7bb4b005f..ec7d2d9f0d114 100644 --- a/src/test/ui/no-patterns-in-args-2.stderr +++ b/src/test/ui/no-patterns-in-args-2.stderr @@ -1,13 +1,13 @@ error[E0642]: patterns aren't allowed in methods without bodies --> $DIR/no-patterns-in-args-2.rs:6:11 | -LL | fn f2(&arg: u8); //~ ERROR patterns aren't allowed in methods without bodies +LL | fn f2(&arg: u8); | ^^^^ error: patterns aren't allowed in methods without bodies --> $DIR/no-patterns-in-args-2.rs:4:11 | -LL | fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in methods without bodies +LL | fn f1(mut arg: u8); | ^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/no-patterns-in-args-macro.stderr b/src/test/ui/no-patterns-in-args-macro.stderr index 28a48bf6a89c4..680430a05ee8a 100644 --- a/src/test/ui/no-patterns-in-args-macro.stderr +++ b/src/test/ui/no-patterns-in-args-macro.stderr @@ -18,5 +18,5 @@ LL | m!((bad, pat)); error: aborting due to 3 previous errors -Some errors occurred: E0130, E0561, E0642. +Some errors have detailed explanations: E0130, E0642. For more information about an error, try `rustc --explain E0130`. diff --git a/src/test/ui/no-patterns-in-args.stderr b/src/test/ui/no-patterns-in-args.stderr index 3fd476c4d720e..b65e0ecd253e6 100644 --- a/src/test/ui/no-patterns-in-args.stderr +++ b/src/test/ui/no-patterns-in-args.stderr @@ -1,34 +1,33 @@ error[E0130]: patterns aren't allowed in foreign function declarations --> $DIR/no-patterns-in-args.rs:2:11 | -LL | fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in foreign function declarations +LL | fn f1(mut arg: u8); | ^^^^^^^ pattern not allowed in foreign function error[E0130]: patterns aren't allowed in foreign function declarations --> $DIR/no-patterns-in-args.rs:3:11 | -LL | fn f2(&arg: u8); //~ ERROR patterns aren't allowed in foreign function declarations +LL | fn f2(&arg: u8); | ^^^^ pattern not allowed in foreign function error[E0130]: patterns aren't allowed in foreign function declarations --> $DIR/no-patterns-in-args.rs:4:11 | -LL | fn f3(arg @ _: u8); //~ ERROR patterns aren't allowed in foreign function declarations +LL | fn f3(arg @ _: u8); | ^^^^^^^ pattern not allowed in foreign function error[E0561]: patterns aren't allowed in function pointer types --> $DIR/no-patterns-in-args.rs:10:14 | -LL | type A1 = fn(mut arg: u8); //~ ERROR patterns aren't allowed in function pointer types +LL | type A1 = fn(mut arg: u8); | ^^^^^^^ error[E0561]: patterns aren't allowed in function pointer types --> $DIR/no-patterns-in-args.rs:11:14 | -LL | type A2 = fn(&arg: u8); //~ ERROR patterns aren't allowed in function pointer types +LL | type A2 = fn(&arg: u8); | ^^^^ error: aborting due to 5 previous errors -Some errors occurred: E0130, E0561. -For more information about an error, try `rustc --explain E0130`. +For more information about this error, try `rustc --explain E0130`. diff --git a/src/test/ui/no-reuse-move-arc.nll.stderr b/src/test/ui/no-reuse-move-arc.nll.stderr deleted file mode 100644 index 0b14f65a77073..0000000000000 --- a/src/test/ui/no-reuse-move-arc.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0382]: borrow of moved value: `arc_v` - --> $DIR/no-reuse-move-arc.rs:12:18 - | -LL | let arc_v = Arc::new(v); - | ----- move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait -LL | -LL | thread::spawn(move|| { - | ------ value moved into closure here -LL | assert_eq!((*arc_v)[3], 4); - | ----- variable moved due to use in closure -... -LL | assert_eq!((*arc_v)[2], 3); //~ ERROR use of moved value: `arc_v` - | ^^^^^ value borrowed here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/no-reuse-move-arc.rs b/src/test/ui/no-reuse-move-arc.rs index b60a7f24999af..9c957a4e01b41 100644 --- a/src/test/ui/no-reuse-move-arc.rs +++ b/src/test/ui/no-reuse-move-arc.rs @@ -9,7 +9,7 @@ fn main() { assert_eq!((*arc_v)[3], 4); }); - assert_eq!((*arc_v)[2], 3); //~ ERROR use of moved value: `arc_v` + assert_eq!((*arc_v)[2], 3); //~ ERROR borrow of moved value: `arc_v` - println!("{:?}", *arc_v); //~ ERROR use of moved value: `arc_v` + println!("{:?}", *arc_v); } diff --git a/src/test/ui/no-reuse-move-arc.stderr b/src/test/ui/no-reuse-move-arc.stderr index d8ab314e7625e..3f7169e6fcbb9 100644 --- a/src/test/ui/no-reuse-move-arc.stderr +++ b/src/test/ui/no-reuse-move-arc.stderr @@ -1,25 +1,17 @@ -error[E0382]: use of moved value: `arc_v` +error[E0382]: borrow of moved value: `arc_v` --> $DIR/no-reuse-move-arc.rs:12:18 | +LL | let arc_v = Arc::new(v); + | ----- move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait +LL | LL | thread::spawn(move|| { - | ------ value moved (into closure) here + | ------ value moved into closure here +LL | assert_eq!((*arc_v)[3], 4); + | ----- variable moved due to use in closure ... -LL | assert_eq!((*arc_v)[2], 3); //~ ERROR use of moved value: `arc_v` - | ^^^^^ value used here after move - | - = note: move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `arc_v` - --> $DIR/no-reuse-move-arc.rs:14:23 - | -LL | thread::spawn(move|| { - | ------ value moved (into closure) here -... -LL | println!("{:?}", *arc_v); //~ ERROR use of moved value: `arc_v` - | ^^^^^ value used here after move - | - = note: move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait +LL | assert_eq!((*arc_v)[2], 3); + | ^^^^^ value borrowed here after move -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/no-std-inject.stderr b/src/test/ui/no-std-inject.stderr index 0ccd567e7a950..975f5c2f50c5d 100644 --- a/src/test/ui/no-std-inject.stderr +++ b/src/test/ui/no-std-inject.stderr @@ -1,13 +1,13 @@ error[E0259]: the name `core` is defined multiple times --> $DIR/no-std-inject.rs:4:1 | -LL | extern crate core; //~ ERROR: the name `core` is defined multiple times +LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ `core` reimported here | = note: `core` must be defined only once in the type namespace of this module help: you can use `as` to change the binding name of the import | -LL | extern crate core as other_core; //~ ERROR: the name `core` is defined multiple times +LL | extern crate core as other_core; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no-type-for-node-ice.stderr b/src/test/ui/no-type-for-node-ice.stderr index cd1a7ee6fe532..b50241fb1a059 100644 --- a/src/test/ui/no-type-for-node-ice.stderr +++ b/src/test/ui/no-type-for-node-ice.stderr @@ -1,7 +1,7 @@ error[E0609]: no field `homura` on type `&'static str` --> $DIR/no-type-for-node-ice.rs:4:8 | -LL | "".homura[""]; //~ no field `homura` on type `&'static str` +LL | "".homura[""]; | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no_crate_type.rs b/src/test/ui/no_crate_type.rs index 392c6fd0dfa13..d8e687e04a76d 100644 --- a/src/test/ui/no_crate_type.rs +++ b/src/test/ui/no_crate_type.rs @@ -1,5 +1,5 @@ // regression test for issue 11256 -#![crate_type] //~ ERROR attribute must be of the form +#![crate_type] //~ ERROR malformed `crate_type` attribute fn main() { return diff --git a/src/test/ui/no_crate_type.stderr b/src/test/ui/no_crate_type.stderr index 6b76ab68658cd..f34df4e2dd143 100644 --- a/src/test/ui/no_crate_type.stderr +++ b/src/test/ui/no_crate_type.stderr @@ -1,8 +1,8 @@ -error: attribute must be of the form `#[crate_type = "bin|lib|..."]` +error: malformed `crate_type` attribute input --> $DIR/no_crate_type.rs:2:1 | -LL | #![crate_type] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^ +LL | #![crate_type] + | ^^^^^^^^^^^^^^ help: must be of the form: `#[crate_type = "bin|lib|..."]` error: aborting due to previous error diff --git a/src/test/ui/non-exhaustive/non-exhaustive-float-range-match.stderr b/src/test/ui/non-exhaustive/non-exhaustive-float-range-match.stderr index 2e285afb3804e..6de615c3de4fd 100644 --- a/src/test/ui/non-exhaustive/non-exhaustive-float-range-match.stderr +++ b/src/test/ui/non-exhaustive/non-exhaustive-float-range-match.stderr @@ -1,8 +1,10 @@ error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/non-exhaustive-float-range-match.rs:10:11 | -LL | match 0.0 { //~ ERROR non-exhaustive patterns +LL | match 0.0 { | ^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/non-exhaustive/non-exhaustive-match-nested.stderr b/src/test/ui/non-exhaustive/non-exhaustive-match-nested.stderr index b2551c8dcf2ae..67c818e19cbda 100644 --- a/src/test/ui/non-exhaustive/non-exhaustive-match-nested.stderr +++ b/src/test/ui/non-exhaustive/non-exhaustive-match-nested.stderr @@ -1,14 +1,24 @@ error[E0004]: non-exhaustive patterns: `(Some(&[]), Err(_))` not covered --> $DIR/non-exhaustive-match-nested.rs:7:11 | -LL | match (l1, l2) { //~ ERROR non-exhaustive patterns: `(Some(&[]), Err(_))` not covered +LL | match (l1, l2) { | ^^^^^^^^ pattern `(Some(&[]), Err(_))` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `A(C)` not covered --> $DIR/non-exhaustive-match-nested.rs:17:11 | -LL | match x { //~ ERROR non-exhaustive patterns: `A(C)` not covered +LL | enum T { A(U), B } + | ------------------ + | | | + | | not covered + | `T` defined here +... +LL | match x { | ^ pattern `A(C)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to 2 previous errors diff --git a/src/test/ui/non-exhaustive/non-exhaustive-match.stderr b/src/test/ui/non-exhaustive/non-exhaustive-match.stderr index 8d2a73b2c6dcc..58e3309fd267a 100644 --- a/src/test/ui/non-exhaustive/non-exhaustive-match.stderr +++ b/src/test/ui/non-exhaustive/non-exhaustive-match.stderr @@ -1,50 +1,78 @@ error[E0004]: non-exhaustive patterns: `A` not covered --> $DIR/non-exhaustive-match.rs:8:11 | -LL | match x { T::B => { } } //~ ERROR non-exhaustive patterns: `A` not covered +LL | enum T { A, B } + | --------------- + | | | + | | not covered + | `T` defined here +... +LL | match x { T::B => { } } | ^ pattern `A` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `false` not covered --> $DIR/non-exhaustive-match.rs:9:11 | -LL | match true { //~ ERROR non-exhaustive patterns: `false` not covered +LL | match true { | ^^^^ pattern `false` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `Some(_)` not covered --> $DIR/non-exhaustive-match.rs:12:11 | -LL | match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered +LL | match Some(10) { | ^^^^^^^^ pattern `Some(_)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `(_, _, -2147483648i32..=3i32)` and `(_, _, 5i32..=2147483647i32)` not covered --> $DIR/non-exhaustive-match.rs:15:11 | -LL | match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, -2147483648i32..=3i32)` +LL | match (2, 3, 4) { | ^^^^^^^^^ patterns `(_, _, -2147483648i32..=3i32)` and `(_, _, 5i32..=2147483647i32)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `(A, A)` not covered --> $DIR/non-exhaustive-match.rs:19:11 | -LL | match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` not covered +LL | match (T::A, T::A) { | ^^^^^^^^^^^^ pattern `(A, A)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `B` not covered --> $DIR/non-exhaustive-match.rs:23:11 | -LL | match T::A { //~ ERROR non-exhaustive patterns: `B` not covered +LL | enum T { A, B } + | --------------- + | | | + | | not covered + | `T` defined here +... +LL | match T::A { | ^^^^ pattern `B` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `[]` not covered --> $DIR/non-exhaustive-match.rs:34:11 | -LL | match *vec { //~ ERROR non-exhaustive patterns: `[]` not covered +LL | match *vec { | ^^^^ pattern `[]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `[_, _, _, _]` not covered --> $DIR/non-exhaustive-match.rs:47:11 | -LL | match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered +LL | match *vec { | ^^^^ pattern `[_, _, _, _]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to 8 previous errors diff --git a/src/test/ui/non-exhaustive/non-exhaustive-pattern-witness.stderr b/src/test/ui/non-exhaustive/non-exhaustive-pattern-witness.stderr index d3a06e7b4b6f8..a0b497dd4c0ba 100644 --- a/src/test/ui/non-exhaustive/non-exhaustive-pattern-witness.stderr +++ b/src/test/ui/non-exhaustive/non-exhaustive-pattern-witness.stderr @@ -1,44 +1,94 @@ error[E0004]: non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered --> $DIR/non-exhaustive-pattern-witness.rs:9:11 | -LL | match (Foo { first: true, second: None }) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered +LL | / struct Foo { +LL | | first: bool, +LL | | second: Option<[usize; 4]> +LL | | } + | |_- `Foo` defined here +... +LL | match (Foo { first: true, second: None }) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `Red` not covered --> $DIR/non-exhaustive-pattern-witness.rs:25:11 | -LL | match Color::Red { - | ^^^^^^^^^^ pattern `Red` not covered +LL | / enum Color { +LL | | Red, + | | --- not covered +LL | | Green, +LL | | CustomRGBA { a: bool, r: u8, g: u8, b: u8 } +LL | | } + | |_- `Color` defined here +... +LL | match Color::Red { + | ^^^^^^^^^^ pattern `Red` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `East`, `South` and `West` not covered --> $DIR/non-exhaustive-pattern-witness.rs:37:11 | -LL | match Direction::North { - | ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered +LL | / enum Direction { +LL | | North, East, South, West + | | ---- ----- ---- not covered + | | | | + | | | not covered + | | not covered +LL | | } + | |_- `Direction` defined here +... +LL | match Direction::North { + | ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `Second`, `Third`, `Fourth` and 8 more not covered --> $DIR/non-exhaustive-pattern-witness.rs:48:11 | -LL | match ExcessiveEnum::First { - | ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered +LL | / enum ExcessiveEnum { +LL | | First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth, Tenth, Eleventh, Twelfth +LL | | } + | |_- `ExcessiveEnum` defined here +... +LL | match ExcessiveEnum::First { + | ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `CustomRGBA { a: true, .. }` not covered --> $DIR/non-exhaustive-pattern-witness.rs:56:11 | -LL | match Color::Red { - | ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered +LL | / enum Color { +LL | | Red, +LL | | Green, +LL | | CustomRGBA { a: bool, r: u8, g: u8, b: u8 } + | | ---------- not covered +LL | | } + | |_- `Color` defined here +... +LL | match Color::Red { + | ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `[Second(true), Second(false)]` not covered --> $DIR/non-exhaustive-pattern-witness.rs:72:11 | LL | match *x { | ^^ pattern `[Second(true), Second(false)]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `((), false)` not covered --> $DIR/non-exhaustive-pattern-witness.rs:85:11 | LL | match ((), false) { | ^^^^^^^^^^^ pattern `((), false)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to 7 previous errors diff --git a/src/test/ui/non-interger-atomic.stderr b/src/test/ui/non-interger-atomic.stderr index 9a49ee88d00cc..7d1130d238e2c 100644 --- a/src/test/ui/non-interger-atomic.stderr +++ b/src/test/ui/non-interger-atomic.stderr @@ -96,4 +96,3 @@ LL | intrinsics::atomic_cxchg(p, v, v); error: aborting due to 16 previous errors -For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/noncopyable-class.stderr b/src/test/ui/noncopyable-class.stderr index 1876de8736275..eb47a33a7292b 100644 --- a/src/test/ui/noncopyable-class.stderr +++ b/src/test/ui/noncopyable-class.stderr @@ -4,7 +4,7 @@ error[E0599]: no method named `clone` found for type `Foo` in the current scope LL | struct Foo { | ---------- method `clone` not found for this ... -LL | let _y = x.clone(); //~ ERROR no method named `clone` found +LL | let _y = x.clone(); | ^^^^^ | = help: items from traits can only be used if the trait is implemented and in scope diff --git a/src/test/ui/nonscalar-cast.stderr b/src/test/ui/nonscalar-cast.stderr index eb482b337e647..9338688b037ff 100644 --- a/src/test/ui/nonscalar-cast.stderr +++ b/src/test/ui/nonscalar-cast.stderr @@ -1,7 +1,7 @@ error[E0605]: non-primitive cast: `Foo` as `isize` --> $DIR/nonscalar-cast.rs:7:20 | -LL | println!("{}", Foo { x: 1 } as isize); //~ non-primitive cast: `Foo` as `isize` [E0605] +LL | println!("{}", Foo { x: 1 } as isize); | ^^^^^^^^^^^^^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait diff --git a/src/test/ui/not-clone-closure.stderr b/src/test/ui/not-clone-closure.stderr index b583db1e4ba2e..b66391b83b8db 100644 --- a/src/test/ui/not-clone-closure.stderr +++ b/src/test/ui/not-clone-closure.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `S: std::clone::Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` --> $DIR/not-clone-closure.rs:11:23 | -LL | let hello = hello.clone(); //~ ERROR the trait bound `S: std::clone::Clone` is not satisfied +LL | let hello = hello.clone(); | ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`, the trait `std::clone::Clone` is not implemented for `S` | = note: required because it appears within the type `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` diff --git a/src/test/ui/not-copy-closure.nll.stderr b/src/test/ui/not-copy-closure.nll.stderr deleted file mode 100644 index 1a65bcf447317..0000000000000 --- a/src/test/ui/not-copy-closure.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0382]: use of moved value: `hello` - --> $DIR/not-copy-closure.rs:10:13 - | -LL | let b = hello; - | ----- value moved here -LL | let c = hello; //~ ERROR use of moved value: `hello` [E0382] - | ^^^^^ value used here after move - | -note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `a` out of its environment - --> $DIR/not-copy-closure.rs:6:9 - | -LL | a += 1; - | ^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/not-copy-closure.stderr b/src/test/ui/not-copy-closure.stderr index bdae06d3a66c4..10bf570727fa0 100644 --- a/src/test/ui/not-copy-closure.stderr +++ b/src/test/ui/not-copy-closure.stderr @@ -1,12 +1,12 @@ error[E0382]: use of moved value: `hello` - --> $DIR/not-copy-closure.rs:10:9 + --> $DIR/not-copy-closure.rs:10:13 | LL | let b = hello; - | - value moved here -LL | let c = hello; //~ ERROR use of moved value: `hello` [E0382] - | ^ value used here after move + | ----- value moved here +LL | let c = hello; + | ^^^^^ value used here after move | -note: closure cannot be invoked more than once because it moves the variable `a` out of its environment +note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `a` out of its environment --> $DIR/not-copy-closure.rs:6:9 | LL | a += 1; diff --git a/src/test/ui/not-panic/not-panic-safe-5.stderr b/src/test/ui/not-panic/not-panic-safe-5.stderr index 46400a4b03c12..a603acb2f1fed 100644 --- a/src/test/ui/not-panic/not-panic-safe-5.stderr +++ b/src/test/ui/not-panic/not-panic-safe-5.stderr @@ -1,7 +1,7 @@ error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-5.rs:9:5 | -LL | assert::<*const UnsafeCell>(); //~ ERROR E0277 +LL | assert::<*const UnsafeCell>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | = help: the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` diff --git a/src/test/ui/numeric/const-scope.rs b/src/test/ui/numeric/const-scope.rs new file mode 100644 index 0000000000000..053599a9bb9f1 --- /dev/null +++ b/src/test/ui/numeric/const-scope.rs @@ -0,0 +1,12 @@ +const C: i32 = 1i8; //~ ERROR mismatched types +const D: i8 = C; //~ ERROR mismatched types + +const fn foo() { + let c: i32 = 1i8; //~ ERROR mismatched types + let d: i8 = c; //~ ERROR mismatched types +} + +fn main() { + let c: i32 = 1i8; //~ ERROR mismatched types + let d: i8 = c; //~ ERROR mismatched types +} diff --git a/src/test/ui/numeric/const-scope.stderr b/src/test/ui/numeric/const-scope.stderr new file mode 100644 index 0000000000000..3f69bcc7d4a2f --- /dev/null +++ b/src/test/ui/numeric/const-scope.stderr @@ -0,0 +1,47 @@ +error[E0308]: mismatched types + --> $DIR/const-scope.rs:1:16 + | +LL | const C: i32 = 1i8; + | ^^^ expected i32, found i8 + +error[E0308]: mismatched types + --> $DIR/const-scope.rs:2:15 + | +LL | const D: i8 = C; + | ^ expected i8, found i32 + +error[E0308]: mismatched types + --> $DIR/const-scope.rs:5:18 + | +LL | let c: i32 = 1i8; + | ^^^ expected i32, found i8 + +error[E0308]: mismatched types + --> $DIR/const-scope.rs:6:17 + | +LL | let d: i8 = c; + | ^ expected i8, found i32 + +error[E0308]: mismatched types + --> $DIR/const-scope.rs:10:18 + | +LL | let c: i32 = 1i8; + | ^^^ expected i32, found i8 +help: change the type of the numeric literal from `i8` to `i32` + | +LL | let c: i32 = 1i32; + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/const-scope.rs:11:17 + | +LL | let d: i8 = c; + | ^ expected i8, found i32 +help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit + | +LL | let d: i8 = c.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/numeric/len.rs b/src/test/ui/numeric/len.rs new file mode 100644 index 0000000000000..a725409882059 --- /dev/null +++ b/src/test/ui/numeric/len.rs @@ -0,0 +1,8 @@ +fn main() { + let array = [1, 2, 3]; + test(array.len()); //~ ERROR mismatched types +} + +fn test(length: u32) { + println!("{}", length); +} diff --git a/src/test/ui/numeric/len.stderr b/src/test/ui/numeric/len.stderr new file mode 100644 index 0000000000000..c767bdd9bd5a5 --- /dev/null +++ b/src/test/ui/numeric/len.stderr @@ -0,0 +1,13 @@ +error[E0308]: mismatched types + --> $DIR/len.rs:3:10 + | +LL | test(array.len()); + | ^^^^^^^^^^^ expected u32, found usize +help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit + | +LL | test(array.len().try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/numeric/numeric-cast-2.stderr b/src/test/ui/numeric/numeric-cast-2.stderr index 79088f0e2ca2f..f58389ce96c3b 100644 --- a/src/test/ui/numeric/numeric-cast-2.stderr +++ b/src/test/ui/numeric/numeric-cast-2.stderr @@ -3,18 +3,30 @@ error[E0308]: mismatched types | LL | let x: u16 = foo(); | ^^^^^ expected u16, found i32 +help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit + | +LL | let x: u16 = foo().try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/numeric-cast-2.rs:7:18 | LL | let y: i64 = x + x; | ^^^^^ expected i64, found u16 +help: you can convert an `u16` to `i64` and panic if the converted value wouldn't fit + | +LL | let y: i64 = (x + x).try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/numeric-cast-2.rs:9:18 | LL | let z: i32 = x + x; | ^^^^^ expected i32, found u16 +help: you can convert an `u16` to `i32` and panic if the converted value wouldn't fit + | +LL | let z: i32 = (x + x).try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/numeric/numeric-cast-without-suggestion.rs b/src/test/ui/numeric/numeric-cast-without-suggestion.rs new file mode 100644 index 0000000000000..faf24a8c18efd --- /dev/null +++ b/src/test/ui/numeric/numeric-cast-without-suggestion.rs @@ -0,0 +1,38 @@ +fn foo(_x: N) {} + +fn main() { + let x_usize: usize = 1; + let x_u64: u64 = 2; + let x_u32: u32 = 3; + let x_u16: u16 = 4; + let x_u8: u8 = 5; + let x_isize: isize = 6; + let x_i64: i64 = 7; + let x_i32: i32 = 8; + let x_i16: i16 = 9; + let x_i8: i8 = 10; + let x_f64: f64 = 11.0; + let x_f32: f32 = 12.0; + + foo::(x_f64); //~ ERROR mismatched types + foo::(x_f32); //~ ERROR mismatched types + foo::(x_f64); //~ ERROR mismatched types + foo::(x_f32); //~ ERROR mismatched types + foo::(x_f64); //~ ERROR mismatched types + foo::(x_f32); //~ ERROR mismatched types + foo::(x_f64); //~ ERROR mismatched types + foo::(x_f32); //~ ERROR mismatched types + foo::(x_f64); //~ ERROR mismatched types + foo::(x_f32); //~ ERROR mismatched types + foo::(x_f64); //~ ERROR mismatched types + foo::(x_f32); //~ ERROR mismatched types + foo::(x_f64); //~ ERROR mismatched types + foo::(x_f32); //~ ERROR mismatched types + foo::(x_f64); //~ ERROR mismatched types + foo::(x_f32); //~ ERROR mismatched types + foo::(x_f64); //~ ERROR mismatched types + foo::(x_f32); //~ ERROR mismatched types + foo::(x_f64); //~ ERROR mismatched types + foo::(x_f32); //~ ERROR mismatched types + foo::(x_f64); //~ ERROR mismatched types +} diff --git a/src/test/ui/numeric/numeric-cast-without-suggestion.stderr b/src/test/ui/numeric/numeric-cast-without-suggestion.stderr new file mode 100644 index 0000000000000..a79eaea16ebb0 --- /dev/null +++ b/src/test/ui/numeric/numeric-cast-without-suggestion.stderr @@ -0,0 +1,129 @@ +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:17:18 + | +LL | foo::(x_f64); + | ^^^^^ expected usize, found f64 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:18:18 + | +LL | foo::(x_f32); + | ^^^^^ expected usize, found f32 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:19:18 + | +LL | foo::(x_f64); + | ^^^^^ expected isize, found f64 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:20:18 + | +LL | foo::(x_f32); + | ^^^^^ expected isize, found f32 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:21:16 + | +LL | foo::(x_f64); + | ^^^^^ expected u64, found f64 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:22:16 + | +LL | foo::(x_f32); + | ^^^^^ expected u64, found f32 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:23:16 + | +LL | foo::(x_f64); + | ^^^^^ expected i64, found f64 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:24:16 + | +LL | foo::(x_f32); + | ^^^^^ expected i64, found f32 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:25:16 + | +LL | foo::(x_f64); + | ^^^^^ expected u32, found f64 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:26:16 + | +LL | foo::(x_f32); + | ^^^^^ expected u32, found f32 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:27:16 + | +LL | foo::(x_f64); + | ^^^^^ expected i32, found f64 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:28:16 + | +LL | foo::(x_f32); + | ^^^^^ expected i32, found f32 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:29:16 + | +LL | foo::(x_f64); + | ^^^^^ expected u16, found f64 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:30:16 + | +LL | foo::(x_f32); + | ^^^^^ expected u16, found f32 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:31:16 + | +LL | foo::(x_f64); + | ^^^^^ expected i16, found f64 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:32:16 + | +LL | foo::(x_f32); + | ^^^^^ expected i16, found f32 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:33:15 + | +LL | foo::(x_f64); + | ^^^^^ expected u8, found f64 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:34:15 + | +LL | foo::(x_f32); + | ^^^^^ expected u8, found f32 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:35:15 + | +LL | foo::(x_f64); + | ^^^^^ expected i8, found f64 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:36:15 + | +LL | foo::(x_f32); + | ^^^^^ expected i8, found f32 + +error[E0308]: mismatched types + --> $DIR/numeric-cast-without-suggestion.rs:37:16 + | +LL | foo::(x_f64); + | ^^^^^ expected f32, found f64 + +error: aborting due to 21 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/numeric/numeric-cast.fixed b/src/test/ui/numeric/numeric-cast.fixed new file mode 100644 index 0000000000000..6f78228a85d44 --- /dev/null +++ b/src/test/ui/numeric/numeric-cast.fixed @@ -0,0 +1,293 @@ +// run-rustfix + +// The `try_into` suggestion doesn't include this, but we do suggest it after applying it +use std::convert::TryInto; + +fn foo(_x: N) {} + +fn main() { + let x_usize: usize = 1; + let x_u64: u64 = 2; + let x_u32: u32 = 3; + let x_u16: u16 = 4; + let x_u8: u8 = 5; + let x_isize: isize = 6; + let x_i64: i64 = 7; + let x_i32: i32 = 8; + let x_i16: i16 = 9; + let x_i8: i8 = 10; + let x_f64: f64 = 11.0; + let x_f32: f32 = 12.0; + + foo::(x_usize); + foo::(x_u64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u8.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_isize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i8.try_into().unwrap()); + //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); + + foo::(x_usize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u8.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_isize); + foo::(x_i64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i8.try_into().unwrap()); + //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); + + foo::(x_usize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u64); + foo::(x_u32.into()); + //~^ ERROR mismatched types + foo::(x_u16.into()); + //~^ ERROR mismatched types + foo::(x_u8.into()); + //~^ ERROR mismatched types + foo::(x_isize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i8.try_into().unwrap()); + //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); + + foo::(x_usize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u8.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_isize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i64); + foo::(x_i32.into()); + //~^ ERROR mismatched types + foo::(x_i16.into()); + //~^ ERROR mismatched types + foo::(x_i8.into()); + //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); + + foo::(x_usize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u32); + foo::(x_u16.into()); + //~^ ERROR mismatched types + foo::(x_u8.into()); + //~^ ERROR mismatched types + foo::(x_isize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i8.try_into().unwrap()); + //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); + + foo::(x_usize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u8.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_isize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i32); + foo::(x_i16.into()); + //~^ ERROR mismatched types + foo::(x_i8.into()); + //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); + + foo::(x_usize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u16); + foo::(x_u8.into()); + //~^ ERROR mismatched types + foo::(x_isize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i8.try_into().unwrap()); + //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); + + foo::(x_usize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u8.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_isize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i16); + foo::(x_i8.into()); + //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); + + foo::(x_usize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u8); + foo::(x_isize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i8.try_into().unwrap()); + //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); + + foo::(x_usize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_u8.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_isize.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i64.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i32.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i16.try_into().unwrap()); + //~^ ERROR mismatched types + foo::(x_i8); + // foo::(x_f64); + // foo::(x_f32); + + foo::(x_usize as f64); + //~^ ERROR mismatched types + foo::(x_u64 as f64); + //~^ ERROR mismatched types + foo::(x_u32.into()); + //~^ ERROR mismatched types + foo::(x_u16.into()); + //~^ ERROR mismatched types + foo::(x_u8.into()); + //~^ ERROR mismatched types + foo::(x_isize as f64); + //~^ ERROR mismatched types + foo::(x_i64 as f64); + //~^ ERROR mismatched types + foo::(x_i32.into()); + //~^ ERROR mismatched types + foo::(x_i16.into()); + //~^ ERROR mismatched types + foo::(x_i8.into()); + //~^ ERROR mismatched types + foo::(x_f64); + foo::(x_f32.into()); + //~^ ERROR mismatched types + + foo::(x_usize as f32); + //~^ ERROR mismatched types + foo::(x_u64 as f32); + //~^ ERROR mismatched types + foo::(x_u32 as f32); + //~^ ERROR mismatched types + foo::(x_u16.into()); + //~^ ERROR mismatched types + foo::(x_u8.into()); + //~^ ERROR mismatched types + foo::(x_isize as f32); + //~^ ERROR mismatched types + foo::(x_i64 as f32); + //~^ ERROR mismatched types + foo::(x_i32 as f32); + //~^ ERROR mismatched types + foo::(x_i16.into()); + //~^ ERROR mismatched types + foo::(x_i8.into()); + //~^ ERROR mismatched types + // foo::(x_f64); + foo::(x_f32); + + foo::((x_u8 as u16).into()); + //~^ ERROR mismatched types + foo::((-x_i8).into()); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/numeric/numeric-cast.rs b/src/test/ui/numeric/numeric-cast.rs index 39378c288fe56..7bddfc5090535 100644 --- a/src/test/ui/numeric/numeric-cast.rs +++ b/src/test/ui/numeric/numeric-cast.rs @@ -1,3 +1,8 @@ +// run-rustfix + +// The `try_into` suggestion doesn't include this, but we do suggest it after applying it +use std::convert::TryInto; + fn foo(_x: N) {} fn main() { @@ -33,10 +38,8 @@ fn main() { //~^ ERROR mismatched types foo::(x_i8); //~^ ERROR mismatched types - foo::(x_f64); - //~^ ERROR mismatched types - foo::(x_f32); - //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); foo::(x_usize); //~^ ERROR mismatched types @@ -57,10 +60,8 @@ fn main() { //~^ ERROR mismatched types foo::(x_i8); //~^ ERROR mismatched types - foo::(x_f64); - //~^ ERROR mismatched types - foo::(x_f32); - //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); foo::(x_usize); //~^ ERROR mismatched types @@ -81,10 +82,8 @@ fn main() { //~^ ERROR mismatched types foo::(x_i8); //~^ ERROR mismatched types - foo::(x_f64); - //~^ ERROR mismatched types - foo::(x_f32); - //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); foo::(x_usize); //~^ ERROR mismatched types @@ -105,10 +104,8 @@ fn main() { //~^ ERROR mismatched types foo::(x_i8); //~^ ERROR mismatched types - foo::(x_f64); - //~^ ERROR mismatched types - foo::(x_f32); - //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); foo::(x_usize); //~^ ERROR mismatched types @@ -129,10 +126,8 @@ fn main() { //~^ ERROR mismatched types foo::(x_i8); //~^ ERROR mismatched types - foo::(x_f64); - //~^ ERROR mismatched types - foo::(x_f32); - //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); foo::(x_usize); //~^ ERROR mismatched types @@ -153,10 +148,8 @@ fn main() { //~^ ERROR mismatched types foo::(x_i8); //~^ ERROR mismatched types - foo::(x_f64); - //~^ ERROR mismatched types - foo::(x_f32); - //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); foo::(x_usize); //~^ ERROR mismatched types @@ -177,10 +170,8 @@ fn main() { //~^ ERROR mismatched types foo::(x_i8); //~^ ERROR mismatched types - foo::(x_f64); - //~^ ERROR mismatched types - foo::(x_f32); - //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); foo::(x_usize); //~^ ERROR mismatched types @@ -201,10 +192,8 @@ fn main() { foo::(x_i16); foo::(x_i8); //~^ ERROR mismatched types - foo::(x_f64); - //~^ ERROR mismatched types - foo::(x_f32); - //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); foo::(x_usize); //~^ ERROR mismatched types @@ -225,10 +214,8 @@ fn main() { //~^ ERROR mismatched types foo::(x_i8); //~^ ERROR mismatched types - foo::(x_f64); - //~^ ERROR mismatched types - foo::(x_f32); - //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); foo::(x_usize); //~^ ERROR mismatched types @@ -249,10 +236,8 @@ fn main() { foo::(x_i16); //~^ ERROR mismatched types foo::(x_i8); - foo::(x_f64); - //~^ ERROR mismatched types - foo::(x_f32); - //~^ ERROR mismatched types + // foo::(x_f64); + // foo::(x_f32); foo::(x_usize); //~^ ERROR mismatched types @@ -298,8 +283,7 @@ fn main() { //~^ ERROR mismatched types foo::(x_i8); //~^ ERROR mismatched types - foo::(x_f64); - //~^ ERROR mismatched types + // foo::(x_f64); foo::(x_f32); foo::(x_u8 as u16); diff --git a/src/test/ui/numeric/numeric-cast.stderr b/src/test/ui/numeric/numeric-cast.stderr index 2c4f6e20f1f0a..e66b83f2b39f5 100644 --- a/src/test/ui/numeric/numeric-cast.stderr +++ b/src/test/ui/numeric/numeric-cast.stderr @@ -1,907 +1,1118 @@ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:18:18 + --> $DIR/numeric-cast.rs:23:18 | LL | foo::(x_u64); | ^^^^^ expected usize, found u64 +help: you can convert an `u64` to `usize` and panic if the converted value wouldn't fit + | +LL | foo::(x_u64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:20:18 + --> $DIR/numeric-cast.rs:25:18 | LL | foo::(x_u32); | ^^^^^ expected usize, found u32 +help: you can convert an `u32` to `usize` and panic if the converted value wouldn't fit + | +LL | foo::(x_u32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:22:18 + --> $DIR/numeric-cast.rs:27:18 | LL | foo::(x_u16); | ^^^^^ expected usize, found u16 +help: you can convert an `u16` to `usize` and panic if the converted value wouldn't fit + | +LL | foo::(x_u16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:24:18 + --> $DIR/numeric-cast.rs:29:18 | LL | foo::(x_u8); | ^^^^ expected usize, found u8 +help: you can convert an `u8` to `usize` and panic if the converted value wouldn't fit + | +LL | foo::(x_u8.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:26:18 + --> $DIR/numeric-cast.rs:31:18 | LL | foo::(x_isize); | ^^^^^^^ expected usize, found isize +help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit + | +LL | foo::(x_isize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:28:18 + --> $DIR/numeric-cast.rs:33:18 | LL | foo::(x_i64); | ^^^^^ expected usize, found i64 +help: you can convert an `i64` to `usize` and panic if the converted value wouldn't fit + | +LL | foo::(x_i64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:30:18 + --> $DIR/numeric-cast.rs:35:18 | LL | foo::(x_i32); | ^^^^^ expected usize, found i32 +help: you can convert an `i32` to `usize` and panic if the converted value wouldn't fit + | +LL | foo::(x_i32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:32:18 + --> $DIR/numeric-cast.rs:37:18 | LL | foo::(x_i16); | ^^^^^ expected usize, found i16 +help: you can convert an `i16` to `usize` and panic if the converted value wouldn't fit + | +LL | foo::(x_i16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:34:18 + --> $DIR/numeric-cast.rs:39:18 | LL | foo::(x_i8); | ^^^^ expected usize, found i8 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:36:18 +help: you can convert an `i8` to `usize` and panic if the converted value wouldn't fit | -LL | foo::(x_f64); - | ^^^^^ expected usize, found f64 +LL | foo::(x_i8.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:38:18 - | -LL | foo::(x_f32); - | ^^^^^ expected usize, found f32 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:41:18 + --> $DIR/numeric-cast.rs:44:18 | LL | foo::(x_usize); | ^^^^^^^ expected isize, found usize +help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit + | +LL | foo::(x_usize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:43:18 + --> $DIR/numeric-cast.rs:46:18 | LL | foo::(x_u64); | ^^^^^ expected isize, found u64 +help: you can convert an `u64` to `isize` and panic if the converted value wouldn't fit + | +LL | foo::(x_u64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:45:18 + --> $DIR/numeric-cast.rs:48:18 | LL | foo::(x_u32); | ^^^^^ expected isize, found u32 +help: you can convert an `u32` to `isize` and panic if the converted value wouldn't fit + | +LL | foo::(x_u32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:47:18 + --> $DIR/numeric-cast.rs:50:18 | LL | foo::(x_u16); | ^^^^^ expected isize, found u16 +help: you can convert an `u16` to `isize` and panic if the converted value wouldn't fit + | +LL | foo::(x_u16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:49:18 + --> $DIR/numeric-cast.rs:52:18 | LL | foo::(x_u8); | ^^^^ expected isize, found u8 +help: you can convert an `u8` to `isize` and panic if the converted value wouldn't fit + | +LL | foo::(x_u8.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:52:18 + --> $DIR/numeric-cast.rs:55:18 | LL | foo::(x_i64); | ^^^^^ expected isize, found i64 +help: you can convert an `i64` to `isize` and panic if the converted value wouldn't fit + | +LL | foo::(x_i64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:54:18 + --> $DIR/numeric-cast.rs:57:18 | LL | foo::(x_i32); | ^^^^^ expected isize, found i32 +help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit + | +LL | foo::(x_i32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:56:18 + --> $DIR/numeric-cast.rs:59:18 | LL | foo::(x_i16); | ^^^^^ expected isize, found i16 +help: you can convert an `i16` to `isize` and panic if the converted value wouldn't fit + | +LL | foo::(x_i16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:58:18 + --> $DIR/numeric-cast.rs:61:18 | LL | foo::(x_i8); | ^^^^ expected isize, found i8 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:60:18 +help: you can convert an `i8` to `isize` and panic if the converted value wouldn't fit | -LL | foo::(x_f64); - | ^^^^^ expected isize, found f64 +LL | foo::(x_i8.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:62:18 - | -LL | foo::(x_f32); - | ^^^^^ expected isize, found f32 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:65:16 + --> $DIR/numeric-cast.rs:66:16 | LL | foo::(x_usize); | ^^^^^^^ expected u64, found usize +help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit + | +LL | foo::(x_usize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:68:16 + --> $DIR/numeric-cast.rs:69:16 | LL | foo::(x_u32); - | ^^^^^ expected u64, found u32 -help: you can cast an `u32` to `u64`, which will zero-extend the source value - | -LL | foo::(x_u32.into()); - | ^^^^^^^^^^^^ + | ^^^^^ + | | + | expected u64, found u32 + | help: you can convert an `u32` to `u64`: `x_u32.into()` error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:70:16 + --> $DIR/numeric-cast.rs:71:16 | LL | foo::(x_u16); - | ^^^^^ expected u64, found u16 -help: you can cast an `u16` to `u64`, which will zero-extend the source value - | -LL | foo::(x_u16.into()); - | ^^^^^^^^^^^^ + | ^^^^^ + | | + | expected u64, found u16 + | help: you can convert an `u16` to `u64`: `x_u16.into()` error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:72:16 + --> $DIR/numeric-cast.rs:73:16 | LL | foo::(x_u8); - | ^^^^ expected u64, found u8 -help: you can cast an `u8` to `u64`, which will zero-extend the source value - | -LL | foo::(x_u8.into()); - | ^^^^^^^^^^^ + | ^^^^ + | | + | expected u64, found u8 + | help: you can convert an `u8` to `u64`: `x_u8.into()` error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:74:16 + --> $DIR/numeric-cast.rs:75:16 | LL | foo::(x_isize); | ^^^^^^^ expected u64, found isize +help: you can convert an `isize` to `u64` and panic if the converted value wouldn't fit + | +LL | foo::(x_isize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:76:16 + --> $DIR/numeric-cast.rs:77:16 | LL | foo::(x_i64); | ^^^^^ expected u64, found i64 +help: you can convert an `i64` to `u64` and panic if the converted value wouldn't fit + | +LL | foo::(x_i64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:78:16 + --> $DIR/numeric-cast.rs:79:16 | LL | foo::(x_i32); | ^^^^^ expected u64, found i32 +help: you can convert an `i32` to `u64` and panic if the converted value wouldn't fit + | +LL | foo::(x_i32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:80:16 + --> $DIR/numeric-cast.rs:81:16 | LL | foo::(x_i16); | ^^^^^ expected u64, found i16 +help: you can convert an `i16` to `u64` and panic if the converted value wouldn't fit + | +LL | foo::(x_i16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:82:16 + --> $DIR/numeric-cast.rs:83:16 | LL | foo::(x_i8); | ^^^^ expected u64, found i8 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:84:16 +help: you can convert an `i8` to `u64` and panic if the converted value wouldn't fit | -LL | foo::(x_f64); - | ^^^^^ expected u64, found f64 +LL | foo::(x_i8.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:86:16 - | -LL | foo::(x_f32); - | ^^^^^ expected u64, found f32 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:89:16 + --> $DIR/numeric-cast.rs:88:16 | LL | foo::(x_usize); | ^^^^^^^ expected i64, found usize +help: you can convert an `usize` to `i64` and panic if the converted value wouldn't fit + | +LL | foo::(x_usize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:91:16 + --> $DIR/numeric-cast.rs:90:16 | LL | foo::(x_u64); | ^^^^^ expected i64, found u64 +help: you can convert an `u64` to `i64` and panic if the converted value wouldn't fit + | +LL | foo::(x_u64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:93:16 + --> $DIR/numeric-cast.rs:92:16 | LL | foo::(x_u32); | ^^^^^ expected i64, found u32 +help: you can convert an `u32` to `i64` and panic if the converted value wouldn't fit + | +LL | foo::(x_u32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:95:16 + --> $DIR/numeric-cast.rs:94:16 | LL | foo::(x_u16); | ^^^^^ expected i64, found u16 +help: you can convert an `u16` to `i64` and panic if the converted value wouldn't fit + | +LL | foo::(x_u16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:97:16 + --> $DIR/numeric-cast.rs:96:16 | LL | foo::(x_u8); | ^^^^ expected i64, found u8 +help: you can convert an `u8` to `i64` and panic if the converted value wouldn't fit + | +LL | foo::(x_u8.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:99:16 + --> $DIR/numeric-cast.rs:98:16 | LL | foo::(x_isize); | ^^^^^^^ expected i64, found isize +help: you can convert an `isize` to `i64` and panic if the converted value wouldn't fit + | +LL | foo::(x_isize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:102:16 + --> $DIR/numeric-cast.rs:101:16 | LL | foo::(x_i32); - | ^^^^^ expected i64, found i32 -help: you can cast an `i32` to `i64`, which will sign-extend the source value - | -LL | foo::(x_i32.into()); - | ^^^^^^^^^^^^ + | ^^^^^ + | | + | expected i64, found i32 + | help: you can convert an `i32` to `i64`: `x_i32.into()` error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:104:16 + --> $DIR/numeric-cast.rs:103:16 | LL | foo::(x_i16); - | ^^^^^ expected i64, found i16 -help: you can cast an `i16` to `i64`, which will sign-extend the source value - | -LL | foo::(x_i16.into()); - | ^^^^^^^^^^^^ + | ^^^^^ + | | + | expected i64, found i16 + | help: you can convert an `i16` to `i64`: `x_i16.into()` error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:106:16 + --> $DIR/numeric-cast.rs:105:16 | LL | foo::(x_i8); - | ^^^^ expected i64, found i8 -help: you can cast an `i8` to `i64`, which will sign-extend the source value - | -LL | foo::(x_i8.into()); - | ^^^^^^^^^^^ - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:108:16 - | -LL | foo::(x_f64); - | ^^^^^ expected i64, found f64 + | ^^^^ + | | + | expected i64, found i8 + | help: you can convert an `i8` to `i64`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:110:16 | -LL | foo::(x_f32); - | ^^^^^ expected i64, found f32 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:113:16 - | LL | foo::(x_usize); | ^^^^^^^ expected u32, found usize +help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit + | +LL | foo::(x_usize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:115:16 + --> $DIR/numeric-cast.rs:112:16 | LL | foo::(x_u64); | ^^^^^ expected u32, found u64 +help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit + | +LL | foo::(x_u64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:118:16 + --> $DIR/numeric-cast.rs:115:16 | LL | foo::(x_u16); - | ^^^^^ expected u32, found u16 -help: you can cast an `u16` to `u32`, which will zero-extend the source value - | -LL | foo::(x_u16.into()); - | ^^^^^^^^^^^^ + | ^^^^^ + | | + | expected u32, found u16 + | help: you can convert an `u16` to `u32`: `x_u16.into()` error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:120:16 + --> $DIR/numeric-cast.rs:117:16 | LL | foo::(x_u8); - | ^^^^ expected u32, found u8 -help: you can cast an `u8` to `u32`, which will zero-extend the source value - | -LL | foo::(x_u8.into()); - | ^^^^^^^^^^^ + | ^^^^ + | | + | expected u32, found u8 + | help: you can convert an `u8` to `u32`: `x_u8.into()` error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:122:16 + --> $DIR/numeric-cast.rs:119:16 | LL | foo::(x_isize); | ^^^^^^^ expected u32, found isize +help: you can convert an `isize` to `u32` and panic if the converted value wouldn't fit + | +LL | foo::(x_isize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:124:16 + --> $DIR/numeric-cast.rs:121:16 | LL | foo::(x_i64); | ^^^^^ expected u32, found i64 +help: you can convert an `i64` to `u32` and panic if the converted value wouldn't fit + | +LL | foo::(x_i64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:126:16 + --> $DIR/numeric-cast.rs:123:16 | LL | foo::(x_i32); | ^^^^^ expected u32, found i32 +help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit + | +LL | foo::(x_i32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:128:16 + --> $DIR/numeric-cast.rs:125:16 | LL | foo::(x_i16); | ^^^^^ expected u32, found i16 +help: you can convert an `i16` to `u32` and panic if the converted value wouldn't fit + | +LL | foo::(x_i16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:130:16 + --> $DIR/numeric-cast.rs:127:16 | LL | foo::(x_i8); | ^^^^ expected u32, found i8 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:132:16 - | -LL | foo::(x_f64); - | ^^^^^ expected u32, found f64 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:134:16 +help: you can convert an `i8` to `u32` and panic if the converted value wouldn't fit | -LL | foo::(x_f32); - | ^^^^^ expected u32, found f32 +LL | foo::(x_i8.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:137:16 + --> $DIR/numeric-cast.rs:132:16 | LL | foo::(x_usize); | ^^^^^^^ expected i32, found usize +help: you can convert an `usize` to `i32` and panic if the converted value wouldn't fit + | +LL | foo::(x_usize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:139:16 + --> $DIR/numeric-cast.rs:134:16 | LL | foo::(x_u64); | ^^^^^ expected i32, found u64 +help: you can convert an `u64` to `i32` and panic if the converted value wouldn't fit + | +LL | foo::(x_u64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:141:16 + --> $DIR/numeric-cast.rs:136:16 | LL | foo::(x_u32); | ^^^^^ expected i32, found u32 +help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit + | +LL | foo::(x_u32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:143:16 + --> $DIR/numeric-cast.rs:138:16 | LL | foo::(x_u16); | ^^^^^ expected i32, found u16 +help: you can convert an `u16` to `i32` and panic if the converted value wouldn't fit + | +LL | foo::(x_u16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:145:16 + --> $DIR/numeric-cast.rs:140:16 | LL | foo::(x_u8); | ^^^^ expected i32, found u8 +help: you can convert an `u8` to `i32` and panic if the converted value wouldn't fit + | +LL | foo::(x_u8.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:147:16 + --> $DIR/numeric-cast.rs:142:16 | LL | foo::(x_isize); | ^^^^^^^ expected i32, found isize +help: you can convert an `isize` to `i32` and panic if the converted value wouldn't fit + | +LL | foo::(x_isize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:149:16 + --> $DIR/numeric-cast.rs:144:16 | LL | foo::(x_i64); | ^^^^^ expected i32, found i64 +help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit + | +LL | foo::(x_i64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:152:16 + --> $DIR/numeric-cast.rs:147:16 | LL | foo::(x_i16); - | ^^^^^ expected i32, found i16 -help: you can cast an `i16` to `i32`, which will sign-extend the source value - | -LL | foo::(x_i16.into()); - | ^^^^^^^^^^^^ + | ^^^^^ + | | + | expected i32, found i16 + | help: you can convert an `i16` to `i32`: `x_i16.into()` error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:154:16 + --> $DIR/numeric-cast.rs:149:16 | LL | foo::(x_i8); - | ^^^^ expected i32, found i8 -help: you can cast an `i8` to `i32`, which will sign-extend the source value - | -LL | foo::(x_i8.into()); - | ^^^^^^^^^^^ - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:156:16 - | -LL | foo::(x_f64); - | ^^^^^ expected i32, found f64 + | ^^^^ + | | + | expected i32, found i8 + | help: you can convert an `i8` to `i32`: `x_i8.into()` error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:158:16 - | -LL | foo::(x_f32); - | ^^^^^ expected i32, found f32 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:161:16 + --> $DIR/numeric-cast.rs:154:16 | LL | foo::(x_usize); | ^^^^^^^ expected u16, found usize +help: you can convert an `usize` to `u16` and panic if the converted value wouldn't fit + | +LL | foo::(x_usize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:163:16 + --> $DIR/numeric-cast.rs:156:16 | LL | foo::(x_u64); | ^^^^^ expected u16, found u64 +help: you can convert an `u64` to `u16` and panic if the converted value wouldn't fit + | +LL | foo::(x_u64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:165:16 + --> $DIR/numeric-cast.rs:158:16 | LL | foo::(x_u32); | ^^^^^ expected u16, found u32 +help: you can convert an `u32` to `u16` and panic if the converted value wouldn't fit + | +LL | foo::(x_u32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:168:16 + --> $DIR/numeric-cast.rs:161:16 | LL | foo::(x_u8); - | ^^^^ expected u16, found u8 -help: you can cast an `u8` to `u16`, which will zero-extend the source value - | -LL | foo::(x_u8.into()); - | ^^^^^^^^^^^ + | ^^^^ + | | + | expected u16, found u8 + | help: you can convert an `u8` to `u16`: `x_u8.into()` error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:170:16 + --> $DIR/numeric-cast.rs:163:16 | LL | foo::(x_isize); | ^^^^^^^ expected u16, found isize +help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit + | +LL | foo::(x_isize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:172:16 + --> $DIR/numeric-cast.rs:165:16 | LL | foo::(x_i64); | ^^^^^ expected u16, found i64 +help: you can convert an `i64` to `u16` and panic if the converted value wouldn't fit + | +LL | foo::(x_i64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:174:16 + --> $DIR/numeric-cast.rs:167:16 | LL | foo::(x_i32); | ^^^^^ expected u16, found i32 +help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit + | +LL | foo::(x_i32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:176:16 + --> $DIR/numeric-cast.rs:169:16 | LL | foo::(x_i16); | ^^^^^ expected u16, found i16 +help: you can convert an `i16` to `u16` and panic if the converted value wouldn't fit + | +LL | foo::(x_i16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:178:16 + --> $DIR/numeric-cast.rs:171:16 | LL | foo::(x_i8); | ^^^^ expected u16, found i8 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:180:16 - | -LL | foo::(x_f64); - | ^^^^^ expected u16, found f64 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:182:16 +help: you can convert an `i8` to `u16` and panic if the converted value wouldn't fit | -LL | foo::(x_f32); - | ^^^^^ expected u16, found f32 +LL | foo::(x_i8.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:185:16 + --> $DIR/numeric-cast.rs:176:16 | LL | foo::(x_usize); | ^^^^^^^ expected i16, found usize +help: you can convert an `usize` to `i16` and panic if the converted value wouldn't fit + | +LL | foo::(x_usize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:187:16 + --> $DIR/numeric-cast.rs:178:16 | LL | foo::(x_u64); | ^^^^^ expected i16, found u64 +help: you can convert an `u64` to `i16` and panic if the converted value wouldn't fit + | +LL | foo::(x_u64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:189:16 + --> $DIR/numeric-cast.rs:180:16 | LL | foo::(x_u32); | ^^^^^ expected i16, found u32 +help: you can convert an `u32` to `i16` and panic if the converted value wouldn't fit + | +LL | foo::(x_u32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:191:16 + --> $DIR/numeric-cast.rs:182:16 | LL | foo::(x_u16); | ^^^^^ expected i16, found u16 +help: you can convert an `u16` to `i16` and panic if the converted value wouldn't fit + | +LL | foo::(x_u16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:193:16 + --> $DIR/numeric-cast.rs:184:16 | LL | foo::(x_u8); | ^^^^ expected i16, found u8 +help: you can convert an `u8` to `i16` and panic if the converted value wouldn't fit + | +LL | foo::(x_u8.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:195:16 + --> $DIR/numeric-cast.rs:186:16 | LL | foo::(x_isize); | ^^^^^^^ expected i16, found isize +help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit + | +LL | foo::(x_isize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:197:16 + --> $DIR/numeric-cast.rs:188:16 | LL | foo::(x_i64); | ^^^^^ expected i16, found i64 +help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit + | +LL | foo::(x_i64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:199:16 + --> $DIR/numeric-cast.rs:190:16 | LL | foo::(x_i32); | ^^^^^ expected i16, found i32 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:202:16 - | -LL | foo::(x_i8); - | ^^^^ expected i16, found i8 -help: you can cast an `i8` to `i16`, which will sign-extend the source value - | -LL | foo::(x_i8.into()); - | ^^^^^^^^^^^ - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:204:16 +help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit | -LL | foo::(x_f64); - | ^^^^^ expected i16, found f64 +LL | foo::(x_i32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:206:16 + --> $DIR/numeric-cast.rs:193:16 | -LL | foo::(x_f32); - | ^^^^^ expected i16, found f32 +LL | foo::(x_i8); + | ^^^^ + | | + | expected i16, found i8 + | help: you can convert an `i8` to `i16`: `x_i8.into()` error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:209:15 + --> $DIR/numeric-cast.rs:198:15 | LL | foo::(x_usize); | ^^^^^^^ expected u8, found usize +help: you can convert an `usize` to `u8` and panic if the converted value wouldn't fit + | +LL | foo::(x_usize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:211:15 + --> $DIR/numeric-cast.rs:200:15 | LL | foo::(x_u64); | ^^^^^ expected u8, found u64 +help: you can convert an `u64` to `u8` and panic if the converted value wouldn't fit + | +LL | foo::(x_u64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:213:15 + --> $DIR/numeric-cast.rs:202:15 | LL | foo::(x_u32); | ^^^^^ expected u8, found u32 +help: you can convert an `u32` to `u8` and panic if the converted value wouldn't fit + | +LL | foo::(x_u32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:215:15 + --> $DIR/numeric-cast.rs:204:15 | LL | foo::(x_u16); | ^^^^^ expected u8, found u16 +help: you can convert an `u16` to `u8` and panic if the converted value wouldn't fit + | +LL | foo::(x_u16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:218:15 + --> $DIR/numeric-cast.rs:207:15 | LL | foo::(x_isize); | ^^^^^^^ expected u8, found isize +help: you can convert an `isize` to `u8` and panic if the converted value wouldn't fit + | +LL | foo::(x_isize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:220:15 + --> $DIR/numeric-cast.rs:209:15 | LL | foo::(x_i64); | ^^^^^ expected u8, found i64 +help: you can convert an `i64` to `u8` and panic if the converted value wouldn't fit + | +LL | foo::(x_i64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:222:15 + --> $DIR/numeric-cast.rs:211:15 | LL | foo::(x_i32); | ^^^^^ expected u8, found i32 +help: you can convert an `i32` to `u8` and panic if the converted value wouldn't fit + | +LL | foo::(x_i32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:224:15 + --> $DIR/numeric-cast.rs:213:15 | LL | foo::(x_i16); | ^^^^^ expected u8, found i16 +help: you can convert an `i16` to `u8` and panic if the converted value wouldn't fit + | +LL | foo::(x_i16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:226:15 + --> $DIR/numeric-cast.rs:215:15 | LL | foo::(x_i8); | ^^^^ expected u8, found i8 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:228:15 - | -LL | foo::(x_f64); - | ^^^^^ expected u8, found f64 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:230:15 +help: you can convert an `i8` to `u8` and panic if the converted value wouldn't fit | -LL | foo::(x_f32); - | ^^^^^ expected u8, found f32 +LL | foo::(x_i8.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:233:15 + --> $DIR/numeric-cast.rs:220:15 | LL | foo::(x_usize); | ^^^^^^^ expected i8, found usize +help: you can convert an `usize` to `i8` and panic if the converted value wouldn't fit + | +LL | foo::(x_usize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:235:15 + --> $DIR/numeric-cast.rs:222:15 | LL | foo::(x_u64); | ^^^^^ expected i8, found u64 +help: you can convert an `u64` to `i8` and panic if the converted value wouldn't fit + | +LL | foo::(x_u64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:237:15 + --> $DIR/numeric-cast.rs:224:15 | LL | foo::(x_u32); | ^^^^^ expected i8, found u32 +help: you can convert an `u32` to `i8` and panic if the converted value wouldn't fit + | +LL | foo::(x_u32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:239:15 + --> $DIR/numeric-cast.rs:226:15 | LL | foo::(x_u16); | ^^^^^ expected i8, found u16 +help: you can convert an `u16` to `i8` and panic if the converted value wouldn't fit + | +LL | foo::(x_u16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:241:15 + --> $DIR/numeric-cast.rs:228:15 | LL | foo::(x_u8); | ^^^^ expected i8, found u8 +help: you can convert an `u8` to `i8` and panic if the converted value wouldn't fit + | +LL | foo::(x_u8.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:243:15 + --> $DIR/numeric-cast.rs:230:15 | LL | foo::(x_isize); | ^^^^^^^ expected i8, found isize +help: you can convert an `isize` to `i8` and panic if the converted value wouldn't fit + | +LL | foo::(x_isize.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:245:15 + --> $DIR/numeric-cast.rs:232:15 | LL | foo::(x_i64); | ^^^^^ expected i8, found i64 +help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit + | +LL | foo::(x_i64.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:247:15 + --> $DIR/numeric-cast.rs:234:15 | LL | foo::(x_i32); | ^^^^^ expected i8, found i32 +help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit + | +LL | foo::(x_i32.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:249:15 + --> $DIR/numeric-cast.rs:236:15 | LL | foo::(x_i16); | ^^^^^ expected i8, found i16 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:252:15 - | -LL | foo::(x_f64); - | ^^^^^ expected i8, found f64 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:254:15 +help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit | -LL | foo::(x_f32); - | ^^^^^ expected i8, found f32 +LL | foo::(x_i16.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:257:16 + --> $DIR/numeric-cast.rs:242:16 | LL | foo::(x_usize); | ^^^^^^^ expected f64, found usize +help: you can cast an `usize to `f64`, producing the floating point representation of the integer, + | rounded if necessary +LL | foo::(x_usize as f64); + | ^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:259:16 + --> $DIR/numeric-cast.rs:244:16 | LL | foo::(x_u64); | ^^^^^ expected f64, found u64 +help: you can cast an `u64 to `f64`, producing the floating point representation of the integer, + | rounded if necessary +LL | foo::(x_u64 as f64); + | ^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:261:16 + --> $DIR/numeric-cast.rs:246:16 | LL | foo::(x_u32); | ^^^^^ expected f64, found u32 -help: you can cast an `u32` to `f64`, producing the floating point representation of the integer +help: you can convert an `u32` to `f64`, producing the floating point representation of the integer | LL | foo::(x_u32.into()); | ^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:263:16 + --> $DIR/numeric-cast.rs:248:16 | LL | foo::(x_u16); | ^^^^^ expected f64, found u16 -help: you can cast an `u16` to `f64`, producing the floating point representation of the integer +help: you can convert an `u16` to `f64`, producing the floating point representation of the integer | LL | foo::(x_u16.into()); | ^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:265:16 + --> $DIR/numeric-cast.rs:250:16 | LL | foo::(x_u8); | ^^^^ expected f64, found u8 -help: you can cast an `u8` to `f64`, producing the floating point representation of the integer +help: you can convert an `u8` to `f64`, producing the floating point representation of the integer | LL | foo::(x_u8.into()); | ^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:267:16 + --> $DIR/numeric-cast.rs:252:16 | LL | foo::(x_isize); | ^^^^^^^ expected f64, found isize +help: you can convert an `isize` to `f64`, producing the floating point representation of the integer, rounded if necessary + | +LL | foo::(x_isize as f64); + | ^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:269:16 + --> $DIR/numeric-cast.rs:254:16 | LL | foo::(x_i64); | ^^^^^ expected f64, found i64 +help: you can convert an `i64` to `f64`, producing the floating point representation of the integer, rounded if necessary + | +LL | foo::(x_i64 as f64); + | ^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:271:16 + --> $DIR/numeric-cast.rs:256:16 | LL | foo::(x_i32); | ^^^^^ expected f64, found i32 -help: you can cast an `i32` to `f64`, producing the floating point representation of the integer +help: you can convert an `i32` to `f64`, producing the floating point representation of the integer | LL | foo::(x_i32.into()); | ^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:273:16 + --> $DIR/numeric-cast.rs:258:16 | LL | foo::(x_i16); | ^^^^^ expected f64, found i16 -help: you can cast an `i16` to `f64`, producing the floating point representation of the integer +help: you can convert an `i16` to `f64`, producing the floating point representation of the integer | LL | foo::(x_i16.into()); | ^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:275:16 + --> $DIR/numeric-cast.rs:260:16 | LL | foo::(x_i8); | ^^^^ expected f64, found i8 -help: you can cast an `i8` to `f64`, producing the floating point representation of the integer +help: you can convert an `i8` to `f64`, producing the floating point representation of the integer | LL | foo::(x_i8.into()); | ^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:278:16 + --> $DIR/numeric-cast.rs:263:16 | LL | foo::(x_f32); - | ^^^^^ expected f64, found f32 -help: you can cast an `f32` to `f64` in a lossless way - | -LL | foo::(x_f32.into()); - | ^^^^^^^^^^^^ + | ^^^^^ + | | + | expected f64, found f32 + | help: you can convert an `f32` to `f64`: `x_f32.into()` error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:281:16 + --> $DIR/numeric-cast.rs:266:16 | LL | foo::(x_usize); | ^^^^^^^ expected f32, found usize +help: you can cast an `usize to `f32`, producing the floating point representation of the integer, + | rounded if necessary +LL | foo::(x_usize as f32); + | ^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:283:16 + --> $DIR/numeric-cast.rs:268:16 | LL | foo::(x_u64); | ^^^^^ expected f32, found u64 +help: you can cast an `u64 to `f32`, producing the floating point representation of the integer, + | rounded if necessary +LL | foo::(x_u64 as f32); + | ^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:285:16 + --> $DIR/numeric-cast.rs:270:16 | LL | foo::(x_u32); | ^^^^^ expected f32, found u32 +help: you can cast an `u32 to `f32`, producing the floating point representation of the integer, + | rounded if necessary +LL | foo::(x_u32 as f32); + | ^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:287:16 + --> $DIR/numeric-cast.rs:272:16 | LL | foo::(x_u16); | ^^^^^ expected f32, found u16 -help: you can cast an `u16` to `f32`, producing the floating point representation of the integer +help: you can convert an `u16` to `f32`, producing the floating point representation of the integer | LL | foo::(x_u16.into()); | ^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:289:16 + --> $DIR/numeric-cast.rs:274:16 | LL | foo::(x_u8); | ^^^^ expected f32, found u8 -help: you can cast an `u8` to `f32`, producing the floating point representation of the integer +help: you can convert an `u8` to `f32`, producing the floating point representation of the integer | LL | foo::(x_u8.into()); | ^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:291:16 + --> $DIR/numeric-cast.rs:276:16 | LL | foo::(x_isize); | ^^^^^^^ expected f32, found isize +help: you can convert an `isize` to `f32`, producing the floating point representation of the integer, rounded if necessary + | +LL | foo::(x_isize as f32); + | ^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:293:16 + --> $DIR/numeric-cast.rs:278:16 | LL | foo::(x_i64); | ^^^^^ expected f32, found i64 +help: you can convert an `i64` to `f32`, producing the floating point representation of the integer, rounded if necessary + | +LL | foo::(x_i64 as f32); + | ^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:295:16 + --> $DIR/numeric-cast.rs:280:16 | LL | foo::(x_i32); | ^^^^^ expected f32, found i32 +help: you can convert an `i32` to `f32`, producing the floating point representation of the integer, rounded if necessary + | +LL | foo::(x_i32 as f32); + | ^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:297:16 + --> $DIR/numeric-cast.rs:282:16 | LL | foo::(x_i16); | ^^^^^ expected f32, found i16 -help: you can cast an `i16` to `f32`, producing the floating point representation of the integer +help: you can convert an `i16` to `f32`, producing the floating point representation of the integer | LL | foo::(x_i16.into()); | ^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:299:16 + --> $DIR/numeric-cast.rs:284:16 | LL | foo::(x_i8); | ^^^^ expected f32, found i8 -help: you can cast an `i8` to `f32`, producing the floating point representation of the integer +help: you can convert an `i8` to `f32`, producing the floating point representation of the integer | LL | foo::(x_i8.into()); | ^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:301:16 - | -LL | foo::(x_f64); - | ^^^^^ expected f32, found f64 - -error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:305:16 + --> $DIR/numeric-cast.rs:289:16 | LL | foo::(x_u8 as u16); - | ^^^^^^^^^^^ expected u32, found u16 -help: you can cast an `u16` to `u32`, which will zero-extend the source value - | -LL | foo::((x_u8 as u16).into()); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ + | | + | expected u32, found u16 + | help: you can convert an `u16` to `u32`: `(x_u8 as u16).into()` error[E0308]: mismatched types - --> $DIR/numeric-cast.rs:307:16 + --> $DIR/numeric-cast.rs:291:16 | LL | foo::(-x_i8); - | ^^^^^ expected i32, found i8 -help: you can cast an `i8` to `i32`, which will sign-extend the source value - | -LL | foo::((-x_i8).into()); - | ^^^^^^^^^^^^^^ + | ^^^^^ + | | + | expected i32, found i8 + | help: you can convert an `i8` to `i32`: `(-x_i8).into()` -error: aborting due to 134 previous errors +error: aborting due to 113 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/numeric/numeric-fields.stderr b/src/test/ui/numeric/numeric-fields.stderr index 1a2ad4a0c0945..5202393f559c9 100644 --- a/src/test/ui/numeric/numeric-fields.stderr +++ b/src/test/ui/numeric/numeric-fields.stderr @@ -1,18 +1,21 @@ error[E0560]: struct `S` has no field named `0b1` --> $DIR/numeric-fields.rs:4:15 | +LL | struct S(u8, u16); + | - `S` defined here +... LL | let s = S{0b1: 10, 0: 11}; - | ^^^ `S` does not have this field - | - = note: available fields are: `0`, `1` + | - ^^^ field does not exist + | | + | `S` is a tuple struct, use the appropriate syntax: `S(/* fields */)` error[E0026]: struct `S` does not have a field named `0x1` --> $DIR/numeric-fields.rs:7:17 | LL | S{0: a, 0x1: b, ..} => {} - | ^^^^^^ struct `S` does not have this field + | ^^^ struct `S` does not have this field error: aborting due to 2 previous errors -Some errors occurred: E0026, E0560. +Some errors have detailed explanations: E0026, E0560. For more information about an error, try `rustc --explain E0026`. diff --git a/src/test/ui/numeric/numeric-suffix.fixed b/src/test/ui/numeric/numeric-suffix.fixed new file mode 100644 index 0000000000000..53c5fe0f435f9 --- /dev/null +++ b/src/test/ui/numeric/numeric-suffix.fixed @@ -0,0 +1,298 @@ +// run-rustfix + +fn foo(_x: N) {} + +fn main() { + foo::(42_usize); + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42usize); + //~^ ERROR mismatched types + foo::(42usize); + //~^ ERROR mismatched types + + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_isize); + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42isize); + //~^ ERROR mismatched types + foo::(42isize); + //~^ ERROR mismatched types + + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u64); + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42u64); + //~^ ERROR mismatched types + foo::(42u64); + //~^ ERROR mismatched types + + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i64); + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42i64); + //~^ ERROR mismatched types + foo::(42i64); + //~^ ERROR mismatched types + + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u32); + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42u32); + //~^ ERROR mismatched types + foo::(42u32); + //~^ ERROR mismatched types + + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i32); + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42i32); + //~^ ERROR mismatched types + foo::(42i32); + //~^ ERROR mismatched types + + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u16); + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42u16); + //~^ ERROR mismatched types + foo::(42u16); + //~^ ERROR mismatched types + + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i16); + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42i16); + //~^ ERROR mismatched types + foo::(42i16); + //~^ ERROR mismatched types + + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_u8); + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42u8); + //~^ ERROR mismatched types + foo::(42u8); + //~^ ERROR mismatched types + + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42_i8); + foo::(42i8); + //~^ ERROR mismatched types + foo::(42i8); + //~^ ERROR mismatched types + + foo::(42_f64); + //~^ ERROR mismatched types + foo::(42_f64); + //~^ ERROR mismatched types + foo::(42_u32.into()); + //~^ ERROR mismatched types + foo::(42_u16.into()); + //~^ ERROR mismatched types + foo::(42_u8.into()); + //~^ ERROR mismatched types + foo::(42_f64); + //~^ ERROR mismatched types + foo::(42_f64); + //~^ ERROR mismatched types + foo::(42_i32.into()); + //~^ ERROR mismatched types + foo::(42_i16.into()); + //~^ ERROR mismatched types + foo::(42_i8.into()); + //~^ ERROR mismatched types + foo::(42.0_f64); + foo::(42.0_f64); + //~^ ERROR mismatched types + + foo::(42_f32); + //~^ ERROR mismatched types + foo::(42_f32); + //~^ ERROR mismatched types + foo::(42_f32); + //~^ ERROR mismatched types + foo::(42_u16.into()); + //~^ ERROR mismatched types + foo::(42_u8.into()); + //~^ ERROR mismatched types + foo::(42_f32); + //~^ ERROR mismatched types + foo::(42_f32); + //~^ ERROR mismatched types + foo::(42_f32); + //~^ ERROR mismatched types + foo::(42_i16.into()); + //~^ ERROR mismatched types + foo::(42_i8.into()); + //~^ ERROR mismatched types + foo::(42.0_f32); + //~^ ERROR mismatched types + foo::(42.0_f32); + + foo::((42_u8 as u16).into()); + //~^ ERROR mismatched types + foo::((-42_i8).into()); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/numeric/numeric-suffix.rs b/src/test/ui/numeric/numeric-suffix.rs new file mode 100644 index 0000000000000..ca38ed82220b2 --- /dev/null +++ b/src/test/ui/numeric/numeric-suffix.rs @@ -0,0 +1,298 @@ +// run-rustfix + +fn foo(_x: N) {} + +fn main() { + foo::(42_usize); + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42.0_f64); + //~^ ERROR mismatched types + foo::(42.0_f32); + //~^ ERROR mismatched types + + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_isize); + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42.0_f64); + //~^ ERROR mismatched types + foo::(42.0_f32); + //~^ ERROR mismatched types + + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_u64); + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42.0_f64); + //~^ ERROR mismatched types + foo::(42.0_f32); + //~^ ERROR mismatched types + + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_i64); + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42.0_f64); + //~^ ERROR mismatched types + foo::(42.0_f32); + //~^ ERROR mismatched types + + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u32); + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42.0_f64); + //~^ ERROR mismatched types + foo::(42.0_f32); + //~^ ERROR mismatched types + + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i32); + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42.0_f64); + //~^ ERROR mismatched types + foo::(42.0_f32); + //~^ ERROR mismatched types + + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u16); + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42.0_f64); + //~^ ERROR mismatched types + foo::(42.0_f32); + //~^ ERROR mismatched types + + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i16); + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42.0_f64); + //~^ ERROR mismatched types + foo::(42.0_f32); + //~^ ERROR mismatched types + + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u8); + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42.0_f64); + //~^ ERROR mismatched types + foo::(42.0_f32); + //~^ ERROR mismatched types + + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i8); + foo::(42.0_f64); + //~^ ERROR mismatched types + foo::(42.0_f32); + //~^ ERROR mismatched types + + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42.0_f64); + foo::(42.0_f32); + //~^ ERROR mismatched types + + foo::(42_usize); + //~^ ERROR mismatched types + foo::(42_u64); + //~^ ERROR mismatched types + foo::(42_u32); + //~^ ERROR mismatched types + foo::(42_u16); + //~^ ERROR mismatched types + foo::(42_u8); + //~^ ERROR mismatched types + foo::(42_isize); + //~^ ERROR mismatched types + foo::(42_i64); + //~^ ERROR mismatched types + foo::(42_i32); + //~^ ERROR mismatched types + foo::(42_i16); + //~^ ERROR mismatched types + foo::(42_i8); + //~^ ERROR mismatched types + foo::(42.0_f64); + //~^ ERROR mismatched types + foo::(42.0_f32); + + foo::(42_u8 as u16); + //~^ ERROR mismatched types + foo::(-42_i8); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/numeric/numeric-suffix.stderr b/src/test/ui/numeric/numeric-suffix.stderr new file mode 100644 index 0000000000000..c88eeeb9f70b2 --- /dev/null +++ b/src/test/ui/numeric/numeric-suffix.stderr @@ -0,0 +1,1341 @@ +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:7:18 + | +LL | foo::(42_u64); + | ^^^^^^ expected usize, found u64 +help: change the type of the numeric literal from `u64` to `usize` + | +LL | foo::(42_usize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:9:18 + | +LL | foo::(42_u32); + | ^^^^^^ expected usize, found u32 +help: change the type of the numeric literal from `u32` to `usize` + | +LL | foo::(42_usize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:11:18 + | +LL | foo::(42_u16); + | ^^^^^^ expected usize, found u16 +help: change the type of the numeric literal from `u16` to `usize` + | +LL | foo::(42_usize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:13:18 + | +LL | foo::(42_u8); + | ^^^^^ expected usize, found u8 +help: change the type of the numeric literal from `u8` to `usize` + | +LL | foo::(42_usize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:15:18 + | +LL | foo::(42_isize); + | ^^^^^^^^ expected usize, found isize +help: change the type of the numeric literal from `isize` to `usize` + | +LL | foo::(42_usize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:17:18 + | +LL | foo::(42_i64); + | ^^^^^^ expected usize, found i64 +help: change the type of the numeric literal from `i64` to `usize` + | +LL | foo::(42_usize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:19:18 + | +LL | foo::(42_i32); + | ^^^^^^ expected usize, found i32 +help: change the type of the numeric literal from `i32` to `usize` + | +LL | foo::(42_usize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:21:18 + | +LL | foo::(42_i16); + | ^^^^^^ expected usize, found i16 +help: change the type of the numeric literal from `i16` to `usize` + | +LL | foo::(42_usize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:23:18 + | +LL | foo::(42_i8); + | ^^^^^ expected usize, found i8 +help: change the type of the numeric literal from `i8` to `usize` + | +LL | foo::(42_usize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:25:18 + | +LL | foo::(42.0_f64); + | ^^^^^^^^ expected usize, found f64 +help: change the type of the numeric literal from `f64` to `usize` + | +LL | foo::(42usize); + | ^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:27:18 + | +LL | foo::(42.0_f32); + | ^^^^^^^^ expected usize, found f32 +help: change the type of the numeric literal from `f32` to `usize` + | +LL | foo::(42usize); + | ^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:30:18 + | +LL | foo::(42_usize); + | ^^^^^^^^ expected isize, found usize +help: change the type of the numeric literal from `usize` to `isize` + | +LL | foo::(42_isize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:32:18 + | +LL | foo::(42_u64); + | ^^^^^^ expected isize, found u64 +help: change the type of the numeric literal from `u64` to `isize` + | +LL | foo::(42_isize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:34:18 + | +LL | foo::(42_u32); + | ^^^^^^ expected isize, found u32 +help: change the type of the numeric literal from `u32` to `isize` + | +LL | foo::(42_isize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:36:18 + | +LL | foo::(42_u16); + | ^^^^^^ expected isize, found u16 +help: change the type of the numeric literal from `u16` to `isize` + | +LL | foo::(42_isize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:38:18 + | +LL | foo::(42_u8); + | ^^^^^ expected isize, found u8 +help: change the type of the numeric literal from `u8` to `isize` + | +LL | foo::(42_isize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:41:18 + | +LL | foo::(42_i64); + | ^^^^^^ expected isize, found i64 +help: change the type of the numeric literal from `i64` to `isize` + | +LL | foo::(42_isize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:43:18 + | +LL | foo::(42_i32); + | ^^^^^^ expected isize, found i32 +help: change the type of the numeric literal from `i32` to `isize` + | +LL | foo::(42_isize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:45:18 + | +LL | foo::(42_i16); + | ^^^^^^ expected isize, found i16 +help: change the type of the numeric literal from `i16` to `isize` + | +LL | foo::(42_isize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:47:18 + | +LL | foo::(42_i8); + | ^^^^^ expected isize, found i8 +help: change the type of the numeric literal from `i8` to `isize` + | +LL | foo::(42_isize); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:49:18 + | +LL | foo::(42.0_f64); + | ^^^^^^^^ expected isize, found f64 +help: change the type of the numeric literal from `f64` to `isize` + | +LL | foo::(42isize); + | ^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:51:18 + | +LL | foo::(42.0_f32); + | ^^^^^^^^ expected isize, found f32 +help: change the type of the numeric literal from `f32` to `isize` + | +LL | foo::(42isize); + | ^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:54:16 + | +LL | foo::(42_usize); + | ^^^^^^^^ expected u64, found usize +help: change the type of the numeric literal from `usize` to `u64` + | +LL | foo::(42_u64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:57:16 + | +LL | foo::(42_u32); + | ^^^^^^ expected u64, found u32 +help: change the type of the numeric literal from `u32` to `u64` + | +LL | foo::(42_u64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:59:16 + | +LL | foo::(42_u16); + | ^^^^^^ expected u64, found u16 +help: change the type of the numeric literal from `u16` to `u64` + | +LL | foo::(42_u64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:61:16 + | +LL | foo::(42_u8); + | ^^^^^ expected u64, found u8 +help: change the type of the numeric literal from `u8` to `u64` + | +LL | foo::(42_u64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:63:16 + | +LL | foo::(42_isize); + | ^^^^^^^^ expected u64, found isize +help: change the type of the numeric literal from `isize` to `u64` + | +LL | foo::(42_u64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:65:16 + | +LL | foo::(42_i64); + | ^^^^^^ expected u64, found i64 +help: change the type of the numeric literal from `i64` to `u64` + | +LL | foo::(42_u64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:67:16 + | +LL | foo::(42_i32); + | ^^^^^^ expected u64, found i32 +help: change the type of the numeric literal from `i32` to `u64` + | +LL | foo::(42_u64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:69:16 + | +LL | foo::(42_i16); + | ^^^^^^ expected u64, found i16 +help: change the type of the numeric literal from `i16` to `u64` + | +LL | foo::(42_u64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:71:16 + | +LL | foo::(42_i8); + | ^^^^^ expected u64, found i8 +help: change the type of the numeric literal from `i8` to `u64` + | +LL | foo::(42_u64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:73:16 + | +LL | foo::(42.0_f64); + | ^^^^^^^^ expected u64, found f64 +help: change the type of the numeric literal from `f64` to `u64` + | +LL | foo::(42u64); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:75:16 + | +LL | foo::(42.0_f32); + | ^^^^^^^^ expected u64, found f32 +help: change the type of the numeric literal from `f32` to `u64` + | +LL | foo::(42u64); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:78:16 + | +LL | foo::(42_usize); + | ^^^^^^^^ expected i64, found usize +help: change the type of the numeric literal from `usize` to `i64` + | +LL | foo::(42_i64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:80:16 + | +LL | foo::(42_u64); + | ^^^^^^ expected i64, found u64 +help: change the type of the numeric literal from `u64` to `i64` + | +LL | foo::(42_i64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:82:16 + | +LL | foo::(42_u32); + | ^^^^^^ expected i64, found u32 +help: change the type of the numeric literal from `u32` to `i64` + | +LL | foo::(42_i64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:84:16 + | +LL | foo::(42_u16); + | ^^^^^^ expected i64, found u16 +help: change the type of the numeric literal from `u16` to `i64` + | +LL | foo::(42_i64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:86:16 + | +LL | foo::(42_u8); + | ^^^^^ expected i64, found u8 +help: change the type of the numeric literal from `u8` to `i64` + | +LL | foo::(42_i64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:88:16 + | +LL | foo::(42_isize); + | ^^^^^^^^ expected i64, found isize +help: change the type of the numeric literal from `isize` to `i64` + | +LL | foo::(42_i64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:91:16 + | +LL | foo::(42_i32); + | ^^^^^^ expected i64, found i32 +help: change the type of the numeric literal from `i32` to `i64` + | +LL | foo::(42_i64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:93:16 + | +LL | foo::(42_i16); + | ^^^^^^ expected i64, found i16 +help: change the type of the numeric literal from `i16` to `i64` + | +LL | foo::(42_i64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:95:16 + | +LL | foo::(42_i8); + | ^^^^^ expected i64, found i8 +help: change the type of the numeric literal from `i8` to `i64` + | +LL | foo::(42_i64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:97:16 + | +LL | foo::(42.0_f64); + | ^^^^^^^^ expected i64, found f64 +help: change the type of the numeric literal from `f64` to `i64` + | +LL | foo::(42i64); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:99:16 + | +LL | foo::(42.0_f32); + | ^^^^^^^^ expected i64, found f32 +help: change the type of the numeric literal from `f32` to `i64` + | +LL | foo::(42i64); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:102:16 + | +LL | foo::(42_usize); + | ^^^^^^^^ expected u32, found usize +help: change the type of the numeric literal from `usize` to `u32` + | +LL | foo::(42_u32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:104:16 + | +LL | foo::(42_u64); + | ^^^^^^ expected u32, found u64 +help: change the type of the numeric literal from `u64` to `u32` + | +LL | foo::(42_u32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:107:16 + | +LL | foo::(42_u16); + | ^^^^^^ expected u32, found u16 +help: change the type of the numeric literal from `u16` to `u32` + | +LL | foo::(42_u32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:109:16 + | +LL | foo::(42_u8); + | ^^^^^ expected u32, found u8 +help: change the type of the numeric literal from `u8` to `u32` + | +LL | foo::(42_u32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:111:16 + | +LL | foo::(42_isize); + | ^^^^^^^^ expected u32, found isize +help: change the type of the numeric literal from `isize` to `u32` + | +LL | foo::(42_u32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:113:16 + | +LL | foo::(42_i64); + | ^^^^^^ expected u32, found i64 +help: change the type of the numeric literal from `i64` to `u32` + | +LL | foo::(42_u32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:115:16 + | +LL | foo::(42_i32); + | ^^^^^^ expected u32, found i32 +help: change the type of the numeric literal from `i32` to `u32` + | +LL | foo::(42_u32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:117:16 + | +LL | foo::(42_i16); + | ^^^^^^ expected u32, found i16 +help: change the type of the numeric literal from `i16` to `u32` + | +LL | foo::(42_u32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:119:16 + | +LL | foo::(42_i8); + | ^^^^^ expected u32, found i8 +help: change the type of the numeric literal from `i8` to `u32` + | +LL | foo::(42_u32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:121:16 + | +LL | foo::(42.0_f64); + | ^^^^^^^^ expected u32, found f64 +help: change the type of the numeric literal from `f64` to `u32` + | +LL | foo::(42u32); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:123:16 + | +LL | foo::(42.0_f32); + | ^^^^^^^^ expected u32, found f32 +help: change the type of the numeric literal from `f32` to `u32` + | +LL | foo::(42u32); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:126:16 + | +LL | foo::(42_usize); + | ^^^^^^^^ expected i32, found usize +help: change the type of the numeric literal from `usize` to `i32` + | +LL | foo::(42_i32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:128:16 + | +LL | foo::(42_u64); + | ^^^^^^ expected i32, found u64 +help: change the type of the numeric literal from `u64` to `i32` + | +LL | foo::(42_i32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:130:16 + | +LL | foo::(42_u32); + | ^^^^^^ expected i32, found u32 +help: change the type of the numeric literal from `u32` to `i32` + | +LL | foo::(42_i32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:132:16 + | +LL | foo::(42_u16); + | ^^^^^^ expected i32, found u16 +help: change the type of the numeric literal from `u16` to `i32` + | +LL | foo::(42_i32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:134:16 + | +LL | foo::(42_u8); + | ^^^^^ expected i32, found u8 +help: change the type of the numeric literal from `u8` to `i32` + | +LL | foo::(42_i32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:136:16 + | +LL | foo::(42_isize); + | ^^^^^^^^ expected i32, found isize +help: change the type of the numeric literal from `isize` to `i32` + | +LL | foo::(42_i32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:138:16 + | +LL | foo::(42_i64); + | ^^^^^^ expected i32, found i64 +help: change the type of the numeric literal from `i64` to `i32` + | +LL | foo::(42_i32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:141:16 + | +LL | foo::(42_i16); + | ^^^^^^ expected i32, found i16 +help: change the type of the numeric literal from `i16` to `i32` + | +LL | foo::(42_i32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:143:16 + | +LL | foo::(42_i8); + | ^^^^^ expected i32, found i8 +help: change the type of the numeric literal from `i8` to `i32` + | +LL | foo::(42_i32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:145:16 + | +LL | foo::(42.0_f64); + | ^^^^^^^^ expected i32, found f64 +help: change the type of the numeric literal from `f64` to `i32` + | +LL | foo::(42i32); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:147:16 + | +LL | foo::(42.0_f32); + | ^^^^^^^^ expected i32, found f32 +help: change the type of the numeric literal from `f32` to `i32` + | +LL | foo::(42i32); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:150:16 + | +LL | foo::(42_usize); + | ^^^^^^^^ expected u16, found usize +help: change the type of the numeric literal from `usize` to `u16` + | +LL | foo::(42_u16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:152:16 + | +LL | foo::(42_u64); + | ^^^^^^ expected u16, found u64 +help: change the type of the numeric literal from `u64` to `u16` + | +LL | foo::(42_u16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:154:16 + | +LL | foo::(42_u32); + | ^^^^^^ expected u16, found u32 +help: change the type of the numeric literal from `u32` to `u16` + | +LL | foo::(42_u16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:157:16 + | +LL | foo::(42_u8); + | ^^^^^ expected u16, found u8 +help: change the type of the numeric literal from `u8` to `u16` + | +LL | foo::(42_u16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:159:16 + | +LL | foo::(42_isize); + | ^^^^^^^^ expected u16, found isize +help: change the type of the numeric literal from `isize` to `u16` + | +LL | foo::(42_u16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:161:16 + | +LL | foo::(42_i64); + | ^^^^^^ expected u16, found i64 +help: change the type of the numeric literal from `i64` to `u16` + | +LL | foo::(42_u16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:163:16 + | +LL | foo::(42_i32); + | ^^^^^^ expected u16, found i32 +help: change the type of the numeric literal from `i32` to `u16` + | +LL | foo::(42_u16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:165:16 + | +LL | foo::(42_i16); + | ^^^^^^ expected u16, found i16 +help: change the type of the numeric literal from `i16` to `u16` + | +LL | foo::(42_u16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:167:16 + | +LL | foo::(42_i8); + | ^^^^^ expected u16, found i8 +help: change the type of the numeric literal from `i8` to `u16` + | +LL | foo::(42_u16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:169:16 + | +LL | foo::(42.0_f64); + | ^^^^^^^^ expected u16, found f64 +help: change the type of the numeric literal from `f64` to `u16` + | +LL | foo::(42u16); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:171:16 + | +LL | foo::(42.0_f32); + | ^^^^^^^^ expected u16, found f32 +help: change the type of the numeric literal from `f32` to `u16` + | +LL | foo::(42u16); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:174:16 + | +LL | foo::(42_usize); + | ^^^^^^^^ expected i16, found usize +help: change the type of the numeric literal from `usize` to `i16` + | +LL | foo::(42_i16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:176:16 + | +LL | foo::(42_u64); + | ^^^^^^ expected i16, found u64 +help: change the type of the numeric literal from `u64` to `i16` + | +LL | foo::(42_i16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:178:16 + | +LL | foo::(42_u32); + | ^^^^^^ expected i16, found u32 +help: change the type of the numeric literal from `u32` to `i16` + | +LL | foo::(42_i16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:180:16 + | +LL | foo::(42_u16); + | ^^^^^^ expected i16, found u16 +help: change the type of the numeric literal from `u16` to `i16` + | +LL | foo::(42_i16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:182:16 + | +LL | foo::(42_u8); + | ^^^^^ expected i16, found u8 +help: change the type of the numeric literal from `u8` to `i16` + | +LL | foo::(42_i16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:184:16 + | +LL | foo::(42_isize); + | ^^^^^^^^ expected i16, found isize +help: change the type of the numeric literal from `isize` to `i16` + | +LL | foo::(42_i16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:186:16 + | +LL | foo::(42_i64); + | ^^^^^^ expected i16, found i64 +help: change the type of the numeric literal from `i64` to `i16` + | +LL | foo::(42_i16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:188:16 + | +LL | foo::(42_i32); + | ^^^^^^ expected i16, found i32 +help: change the type of the numeric literal from `i32` to `i16` + | +LL | foo::(42_i16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:191:16 + | +LL | foo::(42_i8); + | ^^^^^ expected i16, found i8 +help: change the type of the numeric literal from `i8` to `i16` + | +LL | foo::(42_i16); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:193:16 + | +LL | foo::(42.0_f64); + | ^^^^^^^^ expected i16, found f64 +help: change the type of the numeric literal from `f64` to `i16` + | +LL | foo::(42i16); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:195:16 + | +LL | foo::(42.0_f32); + | ^^^^^^^^ expected i16, found f32 +help: change the type of the numeric literal from `f32` to `i16` + | +LL | foo::(42i16); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:198:15 + | +LL | foo::(42_usize); + | ^^^^^^^^ expected u8, found usize +help: change the type of the numeric literal from `usize` to `u8` + | +LL | foo::(42_u8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:200:15 + | +LL | foo::(42_u64); + | ^^^^^^ expected u8, found u64 +help: change the type of the numeric literal from `u64` to `u8` + | +LL | foo::(42_u8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:202:15 + | +LL | foo::(42_u32); + | ^^^^^^ expected u8, found u32 +help: change the type of the numeric literal from `u32` to `u8` + | +LL | foo::(42_u8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:204:15 + | +LL | foo::(42_u16); + | ^^^^^^ expected u8, found u16 +help: change the type of the numeric literal from `u16` to `u8` + | +LL | foo::(42_u8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:207:15 + | +LL | foo::(42_isize); + | ^^^^^^^^ expected u8, found isize +help: change the type of the numeric literal from `isize` to `u8` + | +LL | foo::(42_u8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:209:15 + | +LL | foo::(42_i64); + | ^^^^^^ expected u8, found i64 +help: change the type of the numeric literal from `i64` to `u8` + | +LL | foo::(42_u8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:211:15 + | +LL | foo::(42_i32); + | ^^^^^^ expected u8, found i32 +help: change the type of the numeric literal from `i32` to `u8` + | +LL | foo::(42_u8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:213:15 + | +LL | foo::(42_i16); + | ^^^^^^ expected u8, found i16 +help: change the type of the numeric literal from `i16` to `u8` + | +LL | foo::(42_u8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:215:15 + | +LL | foo::(42_i8); + | ^^^^^ expected u8, found i8 +help: change the type of the numeric literal from `i8` to `u8` + | +LL | foo::(42_u8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:217:15 + | +LL | foo::(42.0_f64); + | ^^^^^^^^ expected u8, found f64 +help: change the type of the numeric literal from `f64` to `u8` + | +LL | foo::(42u8); + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:219:15 + | +LL | foo::(42.0_f32); + | ^^^^^^^^ expected u8, found f32 +help: change the type of the numeric literal from `f32` to `u8` + | +LL | foo::(42u8); + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:222:15 + | +LL | foo::(42_usize); + | ^^^^^^^^ expected i8, found usize +help: change the type of the numeric literal from `usize` to `i8` + | +LL | foo::(42_i8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:224:15 + | +LL | foo::(42_u64); + | ^^^^^^ expected i8, found u64 +help: change the type of the numeric literal from `u64` to `i8` + | +LL | foo::(42_i8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:226:15 + | +LL | foo::(42_u32); + | ^^^^^^ expected i8, found u32 +help: change the type of the numeric literal from `u32` to `i8` + | +LL | foo::(42_i8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:228:15 + | +LL | foo::(42_u16); + | ^^^^^^ expected i8, found u16 +help: change the type of the numeric literal from `u16` to `i8` + | +LL | foo::(42_i8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:230:15 + | +LL | foo::(42_u8); + | ^^^^^ expected i8, found u8 +help: change the type of the numeric literal from `u8` to `i8` + | +LL | foo::(42_i8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:232:15 + | +LL | foo::(42_isize); + | ^^^^^^^^ expected i8, found isize +help: change the type of the numeric literal from `isize` to `i8` + | +LL | foo::(42_i8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:234:15 + | +LL | foo::(42_i64); + | ^^^^^^ expected i8, found i64 +help: change the type of the numeric literal from `i64` to `i8` + | +LL | foo::(42_i8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:236:15 + | +LL | foo::(42_i32); + | ^^^^^^ expected i8, found i32 +help: change the type of the numeric literal from `i32` to `i8` + | +LL | foo::(42_i8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:238:15 + | +LL | foo::(42_i16); + | ^^^^^^ expected i8, found i16 +help: change the type of the numeric literal from `i16` to `i8` + | +LL | foo::(42_i8); + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:241:15 + | +LL | foo::(42.0_f64); + | ^^^^^^^^ expected i8, found f64 +help: change the type of the numeric literal from `f64` to `i8` + | +LL | foo::(42i8); + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:243:15 + | +LL | foo::(42.0_f32); + | ^^^^^^^^ expected i8, found f32 +help: change the type of the numeric literal from `f32` to `i8` + | +LL | foo::(42i8); + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:246:16 + | +LL | foo::(42_usize); + | ^^^^^^^^ expected f64, found usize +help: change the type of the numeric literal from `usize` to `f64` + | +LL | foo::(42_f64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:248:16 + | +LL | foo::(42_u64); + | ^^^^^^ expected f64, found u64 +help: change the type of the numeric literal from `u64` to `f64` + | +LL | foo::(42_f64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:250:16 + | +LL | foo::(42_u32); + | ^^^^^^ expected f64, found u32 +help: you can convert an `u32` to `f64`, producing the floating point representation of the integer + | +LL | foo::(42_u32.into()); + | ^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:252:16 + | +LL | foo::(42_u16); + | ^^^^^^ expected f64, found u16 +help: you can convert an `u16` to `f64`, producing the floating point representation of the integer + | +LL | foo::(42_u16.into()); + | ^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:254:16 + | +LL | foo::(42_u8); + | ^^^^^ expected f64, found u8 +help: you can convert an `u8` to `f64`, producing the floating point representation of the integer + | +LL | foo::(42_u8.into()); + | ^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:256:16 + | +LL | foo::(42_isize); + | ^^^^^^^^ expected f64, found isize +help: change the type of the numeric literal from `isize` to `f64` + | +LL | foo::(42_f64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:258:16 + | +LL | foo::(42_i64); + | ^^^^^^ expected f64, found i64 +help: change the type of the numeric literal from `i64` to `f64` + | +LL | foo::(42_f64); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:260:16 + | +LL | foo::(42_i32); + | ^^^^^^ expected f64, found i32 +help: you can convert an `i32` to `f64`, producing the floating point representation of the integer + | +LL | foo::(42_i32.into()); + | ^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:262:16 + | +LL | foo::(42_i16); + | ^^^^^^ expected f64, found i16 +help: you can convert an `i16` to `f64`, producing the floating point representation of the integer + | +LL | foo::(42_i16.into()); + | ^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:264:16 + | +LL | foo::(42_i8); + | ^^^^^ expected f64, found i8 +help: you can convert an `i8` to `f64`, producing the floating point representation of the integer + | +LL | foo::(42_i8.into()); + | ^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:267:16 + | +LL | foo::(42.0_f32); + | ^^^^^^^^ expected f64, found f32 +help: change the type of the numeric literal from `f32` to `f64` + | +LL | foo::(42.0_f64); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:270:16 + | +LL | foo::(42_usize); + | ^^^^^^^^ expected f32, found usize +help: change the type of the numeric literal from `usize` to `f32` + | +LL | foo::(42_f32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:272:16 + | +LL | foo::(42_u64); + | ^^^^^^ expected f32, found u64 +help: change the type of the numeric literal from `u64` to `f32` + | +LL | foo::(42_f32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:274:16 + | +LL | foo::(42_u32); + | ^^^^^^ expected f32, found u32 +help: change the type of the numeric literal from `u32` to `f32` + | +LL | foo::(42_f32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:276:16 + | +LL | foo::(42_u16); + | ^^^^^^ expected f32, found u16 +help: you can convert an `u16` to `f32`, producing the floating point representation of the integer + | +LL | foo::(42_u16.into()); + | ^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:278:16 + | +LL | foo::(42_u8); + | ^^^^^ expected f32, found u8 +help: you can convert an `u8` to `f32`, producing the floating point representation of the integer + | +LL | foo::(42_u8.into()); + | ^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:280:16 + | +LL | foo::(42_isize); + | ^^^^^^^^ expected f32, found isize +help: change the type of the numeric literal from `isize` to `f32` + | +LL | foo::(42_f32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:282:16 + | +LL | foo::(42_i64); + | ^^^^^^ expected f32, found i64 +help: change the type of the numeric literal from `i64` to `f32` + | +LL | foo::(42_f32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:284:16 + | +LL | foo::(42_i32); + | ^^^^^^ expected f32, found i32 +help: change the type of the numeric literal from `i32` to `f32` + | +LL | foo::(42_f32); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:286:16 + | +LL | foo::(42_i16); + | ^^^^^^ expected f32, found i16 +help: you can convert an `i16` to `f32`, producing the floating point representation of the integer + | +LL | foo::(42_i16.into()); + | ^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:288:16 + | +LL | foo::(42_i8); + | ^^^^^ expected f32, found i8 +help: you can convert an `i8` to `f32`, producing the floating point representation of the integer + | +LL | foo::(42_i8.into()); + | ^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:290:16 + | +LL | foo::(42.0_f64); + | ^^^^^^^^ expected f32, found f64 +help: change the type of the numeric literal from `f64` to `f32` + | +LL | foo::(42.0_f32); + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:294:16 + | +LL | foo::(42_u8 as u16); + | ^^^^^^^^^^^^ + | | + | expected u32, found u16 + | help: you can convert an `u16` to `u32`: `(42_u8 as u16).into()` + +error[E0308]: mismatched types + --> $DIR/numeric-suffix.rs:296:16 + | +LL | foo::(-42_i8); + | ^^^^^^ + | | + | expected i32, found i8 + | help: you can convert an `i8` to `i32`: `(-42_i8).into()` + +error: aborting due to 134 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/object-does-not-impl-trait.rs b/src/test/ui/object-does-not-impl-trait.rs index 2d72b4588f754..104e7b2e21559 100644 --- a/src/test/ui/object-does-not-impl-trait.rs +++ b/src/test/ui/object-does-not-impl-trait.rs @@ -3,6 +3,6 @@ trait Foo {} fn take_foo(f: F) {} -fn take_object(f: Box) { take_foo(f); } +fn take_object(f: Box) { take_foo(f); } //~^ ERROR `std::boxed::Box: Foo` is not satisfied fn main() {} diff --git a/src/test/ui/object-does-not-impl-trait.stderr b/src/test/ui/object-does-not-impl-trait.stderr index 0e28875ced63a..288ce9682c209 100644 --- a/src/test/ui/object-does-not-impl-trait.stderr +++ b/src/test/ui/object-does-not-impl-trait.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `std::boxed::Box: Foo` is not satisfied - --> $DIR/object-does-not-impl-trait.rs:6:31 + --> $DIR/object-does-not-impl-trait.rs:6:35 | -LL | fn take_object(f: Box) { take_foo(f); } - | ^^^^^^^^ the trait `Foo` is not implemented for `std::boxed::Box` +LL | fn take_object(f: Box) { take_foo(f); } + | ^^^^^^^^ the trait `Foo` is not implemented for `std::boxed::Box` | note: required by `take_foo` --> $DIR/object-does-not-impl-trait.rs:5:1 diff --git a/src/test/ui/object-lifetime/object-lifetime-default-ambiguous.rs b/src/test/ui/object-lifetime/object-lifetime-default-ambiguous.rs index d14351aef9a48..5dae92fee5f90 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-ambiguous.rs +++ b/src/test/ui/object-lifetime/object-lifetime-default-ambiguous.rs @@ -20,27 +20,27 @@ struct Ref2<'a,'b:'a,T:'a+'b+?Sized> { r: &'a &'b T } -fn a<'a,'b>(t: Ref2<'a,'b,Test>) { +fn a<'a,'b>(t: Ref2<'a,'b, dyn Test>) { //~^ ERROR lifetime bound for this object type cannot be deduced from context } -fn b(t: Ref2) { +fn b(t: Ref2) { //~^ ERROR lifetime bound for this object type cannot be deduced from context } -fn c(t: Ref2<&Test>) { +fn c(t: Ref2<&dyn Test>) { // In this case, the &'a overrides. } -fn d(t: Ref2>) { +fn d(t: Ref2>) { // In this case, the lifetime parameter from the Ref1 overrides. } -fn e(t: Ref2>) { +fn e(t: Ref2>) { // In this case, Ref2 is ambiguous, but Ref0 overrides with 'static. } -fn f(t: &Ref2) { +fn f(t: &Ref2) { //~^ ERROR lifetime bound for this object type cannot be deduced from context } diff --git a/src/test/ui/object-lifetime/object-lifetime-default-ambiguous.stderr b/src/test/ui/object-lifetime/object-lifetime-default-ambiguous.stderr index f079803c901b4..0c3dbffeea638 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-ambiguous.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-ambiguous.stderr @@ -1,21 +1,20 @@ error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound - --> $DIR/object-lifetime-default-ambiguous.rs:23:27 + --> $DIR/object-lifetime-default-ambiguous.rs:23:28 | -LL | fn a<'a,'b>(t: Ref2<'a,'b,Test>) { - | ^^^^ +LL | fn a<'a,'b>(t: Ref2<'a,'b, dyn Test>) { + | ^^^^^^^^ error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound --> $DIR/object-lifetime-default-ambiguous.rs:27:14 | -LL | fn b(t: Ref2) { - | ^^^^ +LL | fn b(t: Ref2) { + | ^^^^^^^^ error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound --> $DIR/object-lifetime-default-ambiguous.rs:43:15 | -LL | fn f(t: &Ref2) { - | ^^^^ +LL | fn f(t: &Ref2) { + | ^^^^^^^^ error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0228`. diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr new file mode 100644 index 0000000000000..e94f2a92125cd --- /dev/null +++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/object-lifetime-default-elision.rs:71:5 + | +LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | ss + | ^^ returning this value requires that `'a` must outlive `'b` + +error: aborting due to previous error + diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.rs b/src/test/ui/object-lifetime/object-lifetime-default-elision.rs index cf15a4e8676bd..dc42edfba2cc1 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-elision.rs +++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.rs @@ -8,7 +8,7 @@ trait SomeTrait { } struct SomeStruct<'a> { - r: Box + r: Box } fn deref(ss: &T) -> T { @@ -17,7 +17,7 @@ fn deref(ss: &T) -> T { loop { } } -fn load0<'a>(ss: &'a Box) -> Box { +fn load0<'a>(ss: &'a Box) -> Box { // Under old rules, the fully elaborated types of input/output were: // // for<'a,'b> fn(&'a Box) -> Box @@ -31,7 +31,7 @@ fn load0<'a>(ss: &'a Box) -> Box { deref(ss) } -fn load1(ss: &SomeTrait) -> &SomeTrait { +fn load1(ss: &dyn SomeTrait) -> &dyn SomeTrait { // Under old rules, the fully elaborated types of input/output were: // // for<'a,'b> fn(&'a (SomeTrait+'b)) -> &'a (SomeTrait+'a) @@ -45,13 +45,13 @@ fn load1(ss: &SomeTrait) -> &SomeTrait { ss } -fn load2<'a>(ss: &'a SomeTrait) -> &SomeTrait { +fn load2<'a>(ss: &'a dyn SomeTrait) -> &dyn SomeTrait { // Same as `load1` but with an explicit name thrown in for fun. ss } -fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { +fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { // Under old rules, the fully elaborated types of input/output were: // // for<'a,'b,'c>fn(&'a (SomeTrait+'c)) -> &'b (SomeTrait+'a) diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr index ed734c20f38ba..2cdd6c5d890f2 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr @@ -7,7 +7,7 @@ LL | ss note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 54:10... --> $DIR/object-lifetime-default-elision.rs:54:10 | -LL | fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { +LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { | ^^ note: ...so that reference does not outlive borrowed content --> $DIR/object-lifetime-default-elision.rs:71:5 @@ -17,7 +17,7 @@ LL | ss note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 54:13... --> $DIR/object-lifetime-default-elision.rs:54:13 | -LL | fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { +LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { | ^^ = note: ...so that the expression is assignable: expected &'b (dyn SomeTrait + 'b) @@ -32,7 +32,7 @@ LL | ss note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 54:10... --> $DIR/object-lifetime-default-elision.rs:54:10 | -LL | fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { +LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { | ^^ note: ...so that the declared lifetime parameter bounds are satisfied --> $DIR/object-lifetime-default-elision.rs:71:5 @@ -42,7 +42,7 @@ LL | ss note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 54:13... --> $DIR/object-lifetime-default-elision.rs:54:13 | -LL | fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { +LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { | ^^ = note: ...so that the expression is assignable: expected &'b (dyn SomeTrait + 'b) @@ -50,4 +50,3 @@ LL | fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr new file mode 100644 index 0000000000000..f6252f4ed7977 --- /dev/null +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr @@ -0,0 +1,28 @@ +error[E0621]: explicit lifetime required in the type of `ss` + --> $DIR/object-lifetime-default-from-box-error.rs:18:5 + | +LL | fn load(ss: &mut SomeStruct) -> Box { + | --------------- help: add explicit lifetime `'static` to the type of `ss`: `&mut SomeStruct<'static>` +... +LL | ss.r + | ^^^^ lifetime `'static` required + +error[E0507]: cannot move out of `ss.r` which is behind a mutable reference + --> $DIR/object-lifetime-default-from-box-error.rs:18:5 + | +LL | ss.r + | ^^^^ move occurs because `ss.r` has type `std::boxed::Box`, which does not implement the `Copy` trait + +error[E0621]: explicit lifetime required in the type of `ss` + --> $DIR/object-lifetime-default-from-box-error.rs:31:5 + | +LL | fn store1<'b>(ss: &mut SomeStruct, b: Box) { + | --------------- help: add explicit lifetime `'b` to the type of `ss`: `&mut SomeStruct<'b>` +... +LL | ss.r = b; + | ^^^^ lifetime `'b` required + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0507, E0621. +For more information about an error, try `rustc --explain E0507`. diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs index b6d72f1fce3ff..587aab1edce38 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs @@ -8,24 +8,24 @@ trait SomeTrait { } struct SomeStruct<'a> { - r: Box + r: Box } -fn load(ss: &mut SomeStruct) -> Box { +fn load(ss: &mut SomeStruct) -> Box { // `Box` defaults to a `'static` bound, so this return // is illegal. ss.r //~ ERROR explicit lifetime required in the type of `ss` [E0621] } -fn store(ss: &mut SomeStruct, b: Box) { +fn store(ss: &mut SomeStruct, b: Box) { // No error: b is bounded by 'static which outlives the // (anonymous) lifetime on the struct. ss.r = b; } -fn store1<'b>(ss: &mut SomeStruct, b: Box) { +fn store1<'b>(ss: &mut SomeStruct, b: Box) { // Here we override the lifetimes explicitly, and so naturally we get an error. ss.r = b; //~ ERROR explicit lifetime required in the type of `ss` [E0621] diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index a7cb32ec7b8b4..78e4bdd374da9 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -1,19 +1,19 @@ error[E0621]: explicit lifetime required in the type of `ss` --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | -LL | fn load(ss: &mut SomeStruct) -> Box { +LL | fn load(ss: &mut SomeStruct) -> Box { | --------------- help: add explicit lifetime `'static` to the type of `ss`: `&mut SomeStruct<'static>` ... -LL | ss.r //~ ERROR explicit lifetime required in the type of `ss` [E0621] +LL | ss.r | ^^^^ lifetime `'static` required error[E0621]: explicit lifetime required in the type of `ss` --> $DIR/object-lifetime-default-from-box-error.rs:31:12 | -LL | fn store1<'b>(ss: &mut SomeStruct, b: Box) { +LL | fn store1<'b>(ss: &mut SomeStruct, b: Box) { | --------------- help: add explicit lifetime `'b` to the type of `ss`: `&mut SomeStruct<'b>` ... -LL | ss.r = b; //~ ERROR explicit lifetime required in the type of `ss` [E0621] +LL | ss.r = b; | ^ lifetime `'b` required error: aborting due to 2 previous errors diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr new file mode 100644 index 0000000000000..7d6f9f39d13ed --- /dev/null +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/object-lifetime-default-from-rptr-box-error.rs:15:5 + | +LL | fn c<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { + | -- lifetime `'a` defined here +LL | ss.t = t; + | ^^^^^^^^ assignment requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs index 91b384e00713b..bf9e0beb57cdf 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs @@ -8,10 +8,10 @@ trait Test { } struct SomeStruct<'a> { - t: &'a Box, + t: &'a Box, } -fn c<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { +fn c<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { ss.t = t; //~ ERROR mismatched types } diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr index 165f6311ffdfe..4f9cef12c5ef2 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/object-lifetime-default-from-rptr-box-error.rs:15:12 | -LL | ss.t = t; //~ ERROR mismatched types +LL | ss.t = t; | ^ lifetime mismatch | = note: expected type `&'a std::boxed::Box<(dyn Test + 'static)>` @@ -9,7 +9,7 @@ LL | ss.t = t; //~ ERROR mismatched types note: the lifetime 'a as defined on the function body at 14:6... --> $DIR/object-lifetime-default-from-rptr-box-error.rs:14:6 | -LL | fn c<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { +LL | fn c<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { | ^^ = note: ...does not necessarily outlive the static lifetime diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr new file mode 100644 index 0000000000000..6df54638ce004 --- /dev/null +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:21:5 + | +LL | fn c<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { + | -- lifetime `'a` defined here +LL | ss.t = t; + | ^^^^^^^^ assignment requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.rs b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.rs index 6a84621f59e44..ae2878539cfd1 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.rs +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.rs @@ -9,15 +9,15 @@ trait Test { } struct SomeStruct<'a> { - t: &'a MyBox, - u: &'a MyBox, + t: &'a MyBox, + u: &'a MyBox, } struct MyBox { b: Box } -fn c<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { +fn c<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { ss.t = t; //~ ERROR mismatched types } diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr index 2f042c05f25bc..3b7faee68aaba 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:21:12 | -LL | ss.t = t; //~ ERROR mismatched types +LL | ss.t = t; | ^ lifetime mismatch | = note: expected type `&'a MyBox<(dyn Test + 'static)>` @@ -9,7 +9,7 @@ LL | ss.t = t; //~ ERROR mismatched types note: the lifetime 'a as defined on the function body at 20:6... --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:20:6 | -LL | fn c<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { +LL | fn c<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { | ^^ = note: ...does not necessarily outlive the static lifetime diff --git a/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr new file mode 100644 index 0000000000000..cdfbf0fc878cf --- /dev/null +++ b/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr @@ -0,0 +1,21 @@ +error: lifetime may not live long enough + --> $DIR/object-lifetime-default-mybox.rs:27:5 + | +LL | fn load1<'a,'b>(a: &'a MyBox, + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | a + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/object-lifetime-default-mybox.rs:31:5 + | +LL | fn load2<'a>(ss: &MyBox) -> MyBox { + | -- `ss` is a reference that is only valid in the function body +LL | load0(ss) + | ^^^^^^^^^ `ss` escapes the function body here + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/object-lifetime/object-lifetime-default-mybox.rs b/src/test/ui/object-lifetime/object-lifetime-default-mybox.rs index c94df82a17759..eb27fe90f47ce 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-mybox.rs +++ b/src/test/ui/object-lifetime/object-lifetime-default-mybox.rs @@ -16,18 +16,18 @@ fn deref(ss: &T) -> T { loop { } } -fn load0(ss: &MyBox) -> MyBox { +fn load0(ss: &MyBox) -> MyBox { deref(ss) } -fn load1<'a,'b>(a: &'a MyBox, - b: &'b MyBox) - -> &'b MyBox +fn load1<'a,'b>(a: &'a MyBox, + b: &'b MyBox) + -> &'b MyBox { a //~ ERROR lifetime mismatch } -fn load2<'a>(ss: &MyBox) -> MyBox { +fn load2<'a>(ss: &MyBox) -> MyBox { load0(ss) //~ ERROR mismatched types } diff --git a/src/test/ui/object-lifetime/object-lifetime-default-mybox.stderr b/src/test/ui/object-lifetime/object-lifetime-default-mybox.stderr index 1a21096741cb9..928b920198232 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-mybox.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-mybox.stderr @@ -1,19 +1,19 @@ error[E0623]: lifetime mismatch --> $DIR/object-lifetime-default-mybox.rs:27:5 | -LL | fn load1<'a,'b>(a: &'a MyBox, - | -------------------- this parameter and the return type are declared with different lifetimes... -LL | b: &'b MyBox) -LL | -> &'b MyBox - | -------------------- +LL | fn load1<'a,'b>(a: &'a MyBox, + | ------------------------ this parameter and the return type are declared with different lifetimes... +LL | b: &'b MyBox) +LL | -> &'b MyBox + | ------------------------ LL | { -LL | a //~ ERROR lifetime mismatch +LL | a | ^ ...but data from `a` is returned here error[E0308]: mismatched types --> $DIR/object-lifetime-default-mybox.rs:31:11 | -LL | load0(ss) //~ ERROR mismatched types +LL | load0(ss) | ^^ lifetime mismatch | = note: expected type `&MyBox<(dyn SomeTrait + 'static)>` @@ -21,11 +21,10 @@ LL | load0(ss) //~ ERROR mismatched types note: the lifetime 'a as defined on the function body at 30:10... --> $DIR/object-lifetime-default-mybox.rs:30:10 | -LL | fn load2<'a>(ss: &MyBox) -> MyBox { +LL | fn load2<'a>(ss: &MyBox) -> MyBox { | ^^ = note: ...does not necessarily outlive the static lifetime error: aborting due to 2 previous errors -Some errors occurred: E0308, E0623. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/object-lifetime/object-lifetime-default.stderr b/src/test/ui/object-lifetime/object-lifetime-default.stderr index 443d4ff6537e3..2642cdff2bf6a 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default.stderr @@ -1,43 +1,43 @@ error: 'a,Ambiguous --> $DIR/object-lifetime-default.rs:24:1 | -LL | struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U); //~ ERROR 'a,Ambiguous +LL | struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: 'a,'b --> $DIR/object-lifetime-default.rs:21:1 | -LL | struct F<'a,'b,T:'a,U:'b>(&'a T, &'b U); //~ ERROR 'a,'b +LL | struct F<'a,'b,T:'a,U:'b>(&'a T, &'b U); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: 'b --> $DIR/object-lifetime-default.rs:18:1 | -LL | struct E<'a,'b:'a,T:'b>(&'a T, &'b T); //~ ERROR 'b +LL | struct E<'a,'b:'a,T:'b>(&'a T, &'b T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Ambiguous --> $DIR/object-lifetime-default.rs:15:1 | -LL | struct D<'a,'b,T:'a+'b>(&'a T, &'b T); //~ ERROR Ambiguous +LL | struct D<'a,'b,T:'a+'b>(&'a T, &'b T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: 'a --> $DIR/object-lifetime-default.rs:12:1 | -LL | struct C<'a,T:'a>(&'a T); //~ ERROR 'a +LL | struct C<'a,T:'a>(&'a T); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: BaseDefault --> $DIR/object-lifetime-default.rs:9:1 | -LL | struct B<'a,T>(&'a (), T); //~ ERROR BaseDefault +LL | struct B<'a,T>(&'a (), T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: BaseDefault --> $DIR/object-lifetime-default.rs:6:1 | -LL | struct A(T); //~ ERROR BaseDefault +LL | struct A(T); | ^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/object-pointer-types.rs b/src/test/ui/object-pointer-types.rs index a8a482fb5a6c3..760a50e5b7972 100644 --- a/src/test/ui/object-pointer-types.rs +++ b/src/test/ui/object-pointer-types.rs @@ -5,19 +5,19 @@ trait Foo { fn owned(self: Box); } -fn borrowed_receiver(x: &Foo) { +fn borrowed_receiver(x: &dyn Foo) { x.borrowed(); x.borrowed_mut(); // See [1] x.owned(); //~ ERROR no method named `owned` found } -fn borrowed_mut_receiver(x: &mut Foo) { +fn borrowed_mut_receiver(x: &mut dyn Foo) { x.borrowed(); x.borrowed_mut(); x.owned(); //~ ERROR no method named `owned` found } -fn owned_receiver(x: Box) { +fn owned_receiver(x: Box) { x.borrowed(); x.borrowed_mut(); // See [1] x.managed(); //~ ERROR no method named `managed` found diff --git a/src/test/ui/object-pointer-types.stderr b/src/test/ui/object-pointer-types.stderr index c5738edb6cf09..0c7e4e991a51d 100644 --- a/src/test/ui/object-pointer-types.stderr +++ b/src/test/ui/object-pointer-types.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `owned` found for type `&dyn Foo` in the current scope --> $DIR/object-pointer-types.rs:11:7 | -LL | x.owned(); //~ ERROR no method named `owned` found +LL | x.owned(); | ^^^^^ | = help: items from traits can only be used if the trait is implemented and in scope @@ -11,7 +11,7 @@ LL | x.owned(); //~ ERROR no method named `owned` found error[E0599]: no method named `owned` found for type `&mut dyn Foo` in the current scope --> $DIR/object-pointer-types.rs:17:7 | -LL | x.owned(); //~ ERROR no method named `owned` found +LL | x.owned(); | ^^^^^ | = help: items from traits can only be used if the trait is implemented and in scope @@ -21,7 +21,7 @@ LL | x.owned(); //~ ERROR no method named `owned` found error[E0599]: no method named `managed` found for type `std::boxed::Box<(dyn Foo + 'static)>` in the current scope --> $DIR/object-pointer-types.rs:23:7 | -LL | x.managed(); //~ ERROR no method named `managed` found +LL | x.managed(); | ^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/object-safety/object-safety-associated-consts.rs b/src/test/ui/object-safety/object-safety-associated-consts.rs index 79b7e541af82a..5900019ea915a 100644 --- a/src/test/ui/object-safety/object-safety-associated-consts.rs +++ b/src/test/ui/object-safety/object-safety-associated-consts.rs @@ -6,7 +6,7 @@ trait Bar { const X: usize; } -fn make_bar(t: &T) -> &Bar { +fn make_bar(t: &T) -> &dyn Bar { //~^ ERROR E0038 t } diff --git a/src/test/ui/object-safety/object-safety-associated-consts.stderr b/src/test/ui/object-safety/object-safety-associated-consts.stderr index 96962c10720a2..55f9e3f9f138b 100644 --- a/src/test/ui/object-safety/object-safety-associated-consts.stderr +++ b/src/test/ui/object-safety/object-safety-associated-consts.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/object-safety-associated-consts.rs:9:1 | -LL | fn make_bar(t: &T) -> &Bar { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object +LL | fn make_bar(t: &T) -> &dyn Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object | = note: the trait cannot contain associated consts like `X` diff --git a/src/test/ui/object-safety/object-safety-by-value-self-use.nll.stderr b/src/test/ui/object-safety/object-safety-by-value-self-use.nll.stderr deleted file mode 100644 index 0dd50b2802678..0000000000000 --- a/src/test/ui/object-safety/object-safety-by-value-self-use.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined - --> $DIR/object-safety-by-value-self-use.rs:15:5 - | -LL | t.bar() //~ ERROR cannot move a value of type (dyn Bar + 'static) - | ^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0161`. diff --git a/src/test/ui/object-safety/object-safety-by-value-self-use.rs b/src/test/ui/object-safety/object-safety-by-value-self-use.rs index dc8ea64ec9ce2..f903f26c0901d 100644 --- a/src/test/ui/object-safety/object-safety-by-value-self-use.rs +++ b/src/test/ui/object-safety/object-safety-by-value-self-use.rs @@ -11,8 +11,8 @@ trait Baz { fn baz(self: Self); } -fn use_bar(t: Box) { - t.bar() //~ ERROR cannot move a value of type (dyn Bar + 'static) +fn use_bar(t: Box) { + t.bar() //~ ERROR cannot move a value of type dyn Bar } fn main() { } diff --git a/src/test/ui/object-safety/object-safety-by-value-self-use.stderr b/src/test/ui/object-safety/object-safety-by-value-self-use.stderr index 0711981a5215d..1497aa42082d1 100644 --- a/src/test/ui/object-safety/object-safety-by-value-self-use.stderr +++ b/src/test/ui/object-safety/object-safety-by-value-self-use.stderr @@ -1,7 +1,7 @@ -error[E0161]: cannot move a value of type (dyn Bar + 'static): the size of (dyn Bar + 'static) cannot be statically determined +error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined --> $DIR/object-safety-by-value-self-use.rs:15:5 | -LL | t.bar() //~ ERROR cannot move a value of type (dyn Bar + 'static) +LL | t.bar() | ^ error: aborting due to previous error diff --git a/src/test/ui/object-safety/object-safety-by-value-self.rs b/src/test/ui/object-safety/object-safety-by-value-self.rs index dee31f6e370f9..a8b1ddfaba7f1 100644 --- a/src/test/ui/object-safety/object-safety-by-value-self.rs +++ b/src/test/ui/object-safety/object-safety-by-value-self.rs @@ -17,28 +17,28 @@ trait Quux { fn baz(self: Self) where Self : Sized; } -fn make_bar(t: &T) -> &Bar { +fn make_bar(t: &T) -> &dyn Bar { t // legal } -fn make_bar_explicit(t: &T) -> &Bar { - t as &Bar // legal +fn make_bar_explicit(t: &T) -> &dyn Bar { + t as &dyn Bar // legal } -fn make_baz(t: &T) -> &Baz { +fn make_baz(t: &T) -> &dyn Baz { t // legal } -fn make_baz_explicit(t: &T) -> &Baz { - t as &Baz // legal +fn make_baz_explicit(t: &T) -> &dyn Baz { + t as &dyn Baz // legal } -fn make_quux(t: &T) -> &Quux { +fn make_quux(t: &T) -> &dyn Quux { t } -fn make_quux_explicit(t: &T) -> &Quux { - t as &Quux +fn make_quux_explicit(t: &T) -> &dyn Quux { + t as &dyn Quux } diff --git a/src/test/ui/object-safety/object-safety-generics.rs b/src/test/ui/object-safety/object-safety-generics.rs index 5f4aabf5469cb..d63ea28c8f227 100644 --- a/src/test/ui/object-safety/object-safety-generics.rs +++ b/src/test/ui/object-safety/object-safety-generics.rs @@ -11,22 +11,22 @@ trait Quux { where Self : Sized; } -fn make_bar(t: &T) -> &Bar { +fn make_bar(t: &T) -> &dyn Bar { //~^ ERROR E0038 t } -fn make_bar_explicit(t: &T) -> &Bar { +fn make_bar_explicit(t: &T) -> &dyn Bar { //~^ ERROR E0038 - t as &Bar + t as &dyn Bar } -fn make_quux(t: &T) -> &Quux { +fn make_quux(t: &T) -> &dyn Quux { t } -fn make_quux_explicit(t: &T) -> &Quux { - t as &Quux +fn make_quux_explicit(t: &T) -> &dyn Quux { + t as &dyn Quux } fn main() { diff --git a/src/test/ui/object-safety/object-safety-generics.stderr b/src/test/ui/object-safety/object-safety-generics.stderr index 7ae44794ceba9..d66cdb98448d4 100644 --- a/src/test/ui/object-safety/object-safety-generics.stderr +++ b/src/test/ui/object-safety/object-safety-generics.stderr @@ -1,16 +1,16 @@ error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/object-safety-generics.rs:14:1 | -LL | fn make_bar(t: &T) -> &Bar { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object +LL | fn make_bar(t: &T) -> &dyn Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object | = note: method `bar` has generic type parameters error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/object-safety-generics.rs:19:1 | -LL | fn make_bar_explicit(t: &T) -> &Bar { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object +LL | fn make_bar_explicit(t: &T) -> &dyn Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object | = note: method `bar` has generic type parameters diff --git a/src/test/ui/object-safety/object-safety-issue-22040.rs b/src/test/ui/object-safety/object-safety-issue-22040.rs index eb28fcf0d5af2..1fc5c5442c21b 100644 --- a/src/test/ui/object-safety/object-safety-issue-22040.rs +++ b/src/test/ui/object-safety/object-safety-issue-22040.rs @@ -9,7 +9,7 @@ trait Expr: Debug + PartialEq { //#[derive(PartialEq)] #[derive(Debug)] struct SExpr<'x> { - elements: Vec>, + elements: Vec>, //~^ ERROR E0038 } @@ -35,8 +35,8 @@ impl <'x> Expr for SExpr<'x> { } fn main() { - let a: Box = Box::new(SExpr::new()); - let b: Box = Box::new(SExpr::new()); + let a: Box = Box::new(SExpr::new()); + let b: Box = Box::new(SExpr::new()); // assert_eq!(a , b); } diff --git a/src/test/ui/object-safety/object-safety-issue-22040.stderr b/src/test/ui/object-safety/object-safety-issue-22040.stderr index 85721f1a5f81c..1f5c472ddc25a 100644 --- a/src/test/ui/object-safety/object-safety-issue-22040.stderr +++ b/src/test/ui/object-safety/object-safety-issue-22040.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Expr` cannot be made into an object --> $DIR/object-safety-issue-22040.rs:12:23 | -LL | elements: Vec>, - | ^^^^^^^^ the trait `Expr` cannot be made into an object +LL | elements: Vec>, + | ^^^^^^^^^^^^^ the trait `Expr` cannot be made into an object | = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.rs b/src/test/ui/object-safety/object-safety-mentions-Self.rs index 8e1bd83cec00a..f13ffe5362670 100644 --- a/src/test/ui/object-safety/object-safety-mentions-Self.rs +++ b/src/test/ui/object-safety/object-safety-mentions-Self.rs @@ -14,22 +14,22 @@ trait Quux { fn get(&self, s: &Self) -> Self where Self : Sized; } -fn make_bar(t: &T) -> &Bar { +fn make_bar(t: &T) -> &dyn Bar { //~^ ERROR E0038 loop { } } -fn make_baz(t: &T) -> &Baz { +fn make_baz(t: &T) -> &dyn Baz { //~^ ERROR E0038 t } -fn make_quux(t: &T) -> &Quux { +fn make_quux(t: &T) -> &dyn Quux { t } -fn make_quux_explicit(t: &T) -> &Quux { - t as &Quux +fn make_quux_explicit(t: &T) -> &dyn Quux { + t as &dyn Quux } fn main() { diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.stderr b/src/test/ui/object-safety/object-safety-mentions-Self.stderr index ed3aed983cf7a..c0c471c2b1e72 100644 --- a/src/test/ui/object-safety/object-safety-mentions-Self.stderr +++ b/src/test/ui/object-safety/object-safety-mentions-Self.stderr @@ -1,16 +1,16 @@ error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/object-safety-mentions-Self.rs:17:1 | -LL | fn make_bar(t: &T) -> &Bar { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object +LL | fn make_bar(t: &T) -> &dyn Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object | = note: method `bar` references the `Self` type in its arguments or return type error[E0038]: the trait `Baz` cannot be made into an object --> $DIR/object-safety-mentions-Self.rs:22:1 | -LL | fn make_baz(t: &T) -> &Baz { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Baz` cannot be made into an object +LL | fn make_baz(t: &T) -> &dyn Baz { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Baz` cannot be made into an object | = note: method `bar` references the `Self` type in its arguments or return type diff --git a/src/test/ui/object-safety/object-safety-no-static.rs b/src/test/ui/object-safety/object-safety-no-static.rs index 4faf9386f9a8b..55d31ce808769 100644 --- a/src/test/ui/object-safety/object-safety-no-static.rs +++ b/src/test/ui/object-safety/object-safety-no-static.rs @@ -5,7 +5,7 @@ trait Foo { fn foo(); } -fn foo_implicit(b: Box) -> Box { +fn foo_implicit(b: Box) -> Box { //~^ ERROR E0038 loop { } } diff --git a/src/test/ui/object-safety/object-safety-no-static.stderr b/src/test/ui/object-safety/object-safety-no-static.stderr index 3b8ccb594c181..da8dd657c2a9d 100644 --- a/src/test/ui/object-safety/object-safety-no-static.stderr +++ b/src/test/ui/object-safety/object-safety-no-static.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/object-safety-no-static.rs:8:1 | -LL | fn foo_implicit(b: Box) -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object +LL | fn foo_implicit(b: Box) -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | = note: method `foo` has no receiver diff --git a/src/test/ui/object-safety/object-safety-phantom-fn.rs b/src/test/ui/object-safety/object-safety-phantom-fn.rs index f8875e4995b44..59ed12c78f026 100644 --- a/src/test/ui/object-safety/object-safety-phantom-fn.rs +++ b/src/test/ui/object-safety/object-safety-phantom-fn.rs @@ -9,11 +9,11 @@ trait Baz { trait Bar { } -fn make_bar>(t: &T) -> &Bar { +fn make_bar>(t: &T) -> &dyn Bar { t } -fn make_baz(t: &T) -> &Baz { +fn make_baz(t: &T) -> &dyn Baz { t } diff --git a/src/test/ui/object-safety/object-safety-sized-2.rs b/src/test/ui/object-safety/object-safety-sized-2.rs index baeb3734677fb..7235b22404e29 100644 --- a/src/test/ui/object-safety/object-safety-sized-2.rs +++ b/src/test/ui/object-safety/object-safety-sized-2.rs @@ -7,7 +7,7 @@ trait Bar fn bar(&self, t: T); } -fn make_bar(t: &T) -> &Bar { +fn make_bar(t: &T) -> &dyn Bar { //~^ ERROR E0038 loop { } } diff --git a/src/test/ui/object-safety/object-safety-sized-2.stderr b/src/test/ui/object-safety/object-safety-sized-2.stderr index 2b8bfa341d796..dcaf2ff0bc294 100644 --- a/src/test/ui/object-safety/object-safety-sized-2.stderr +++ b/src/test/ui/object-safety/object-safety-sized-2.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/object-safety-sized-2.rs:10:1 | -LL | fn make_bar(t: &T) -> &Bar { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object +LL | fn make_bar(t: &T) -> &dyn Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object | = note: the trait cannot require that `Self : Sized` diff --git a/src/test/ui/object-safety/object-safety-sized.rs b/src/test/ui/object-safety/object-safety-sized.rs index 77dc7390aff01..1312bb34717ee 100644 --- a/src/test/ui/object-safety/object-safety-sized.rs +++ b/src/test/ui/object-safety/object-safety-sized.rs @@ -5,7 +5,7 @@ trait Bar : Sized { fn bar(&self, t: T); } -fn make_bar(t: &T) -> &Bar { +fn make_bar(t: &T) -> &dyn Bar { //~^ ERROR E0038 t } diff --git a/src/test/ui/object-safety/object-safety-sized.stderr b/src/test/ui/object-safety/object-safety-sized.stderr index ba98e2f1ef655..98bc73e38d4cc 100644 --- a/src/test/ui/object-safety/object-safety-sized.stderr +++ b/src/test/ui/object-safety/object-safety-sized.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/object-safety-sized.rs:8:1 | -LL | fn make_bar(t: &T) -> &Bar { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object +LL | fn make_bar(t: &T) -> &dyn Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object | = note: the trait cannot require that `Self : Sized` diff --git a/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.rs b/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.rs index 9d0da4e327c7c..2445b33c81447 100644 --- a/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.rs +++ b/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.rs @@ -8,11 +8,11 @@ trait Bar { trait Baz : Bar { } -fn make_bar>(t: &T) -> &Bar { +fn make_bar>(t: &T) -> &dyn Bar { t } -fn make_baz(t: &T) -> &Baz { +fn make_baz(t: &T) -> &dyn Baz { //~^ ERROR E0038 t } diff --git a/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr b/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr index 5db34a23fff64..8ae89832703d1 100644 --- a/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr +++ b/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Baz` cannot be made into an object --> $DIR/object-safety-supertrait-mentions-Self.rs:15:31 | -LL | fn make_baz(t: &T) -> &Baz { - | ^^^ the trait `Baz` cannot be made into an object +LL | fn make_baz(t: &T) -> &dyn Baz { + | ^^^^^^^ the trait `Baz` cannot be made into an object | = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses diff --git a/src/test/ui/obsolete-in-place/bad.bad.stderr b/src/test/ui/obsolete-in-place/bad.bad.stderr index 245ecb4ed1cb4..d895981050ae9 100644 --- a/src/test/ui/obsolete-in-place/bad.bad.stderr +++ b/src/test/ui/obsolete-in-place/bad.bad.stderr @@ -1,18 +1,19 @@ -error: emplacement syntax is obsolete (for now, anyway) - --> $DIR/bad.rs:9:5 - | -LL | x <- y; //[bad]~ ERROR emplacement syntax is obsolete - | ^^^^^^ +error: expected expression, found keyword `in` + --> $DIR/bad.rs:10:5 | - = note: for more information, see +LL | in(foo) { bar }; + | ^^ expected expression -error: emplacement syntax is obsolete (for now, anyway) - --> $DIR/bad.rs:10:5 +error[E0282]: type annotations needed + --> $DIR/bad.rs:9:8 | -LL | in(foo) { bar }; //[bad]~ ERROR emplacement syntax is obsolete - | ^^^^^^^^^^^^^^^ +LL | let (x, y, foo, bar); + | ---------------- consider giving the pattern a type +LL | x <- y; + | ^^^ cannot infer type | - = note: for more information, see + = note: type must be known at this point error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/obsolete-in-place/bad.rs b/src/test/ui/obsolete-in-place/bad.rs index f35d297e552ee..67676857e8da0 100644 --- a/src/test/ui/obsolete-in-place/bad.rs +++ b/src/test/ui/obsolete-in-place/bad.rs @@ -1,15 +1,12 @@ // Check that `<-` and `in` syntax gets a hard error. -// revisions: good bad -//[good] run-pass - -#[cfg(bad)] -fn main() { - let (x, y, foo, bar); - x <- y; //[bad]~ ERROR emplacement syntax is obsolete - in(foo) { bar }; //[bad]~ ERROR emplacement syntax is obsolete +fn foo() { + let (x, y) = (0, 0); + x <- y; //~ ERROR expected one of + //~^ ERROR mismatched types } -#[cfg(good)] fn main() { + let (foo, bar) = (0, 0); + in(foo) { bar }; //~ ERROR expected expression, found keyword `in` } diff --git a/src/test/ui/obsolete-in-place/bad.stderr b/src/test/ui/obsolete-in-place/bad.stderr new file mode 100644 index 0000000000000..91ea82a657dc3 --- /dev/null +++ b/src/test/ui/obsolete-in-place/bad.stderr @@ -0,0 +1,27 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `<-` + --> $DIR/bad.rs:5:7 + | +LL | x <- y; + | ^^ expected one of 8 possible tokens here + +error: expected expression, found keyword `in` + --> $DIR/bad.rs:11:5 + | +LL | in(foo) { bar }; + | ^^ expected expression + +error[E0308]: mismatched types + --> $DIR/bad.rs:5:5 + | +LL | fn foo() { + | - possibly return type missing here? +LL | let (x, y) = (0, 0); +LL | x <- y; + | ^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/obsolete-syntax-impl-for-dotdot.stderr b/src/test/ui/obsolete-syntax-impl-for-dotdot.stderr index 793ed26ca6885..b7108ced0d763 100644 --- a/src/test/ui/obsolete-syntax-impl-for-dotdot.stderr +++ b/src/test/ui/obsolete-syntax-impl-for-dotdot.stderr @@ -1,7 +1,7 @@ error: `impl Trait for .. {}` is an obsolete syntax --> $DIR/obsolete-syntax-impl-for-dotdot.rs:7:1 | -LL | impl Trait2 for .. {} //~ ERROR `impl Trait for .. {}` is an obsolete syntax +LL | impl Trait2 for .. {} | ^^^^^^^^^^^^^^^^^^^^^ | = help: use `auto trait Trait {}` instead diff --git a/src/test/ui/old-suffixes-are-really-forbidden.stderr b/src/test/ui/old-suffixes-are-really-forbidden.stderr index c54b72a3585d1..ccfe60e964b2e 100644 --- a/src/test/ui/old-suffixes-are-really-forbidden.stderr +++ b/src/test/ui/old-suffixes-are-really-forbidden.stderr @@ -1,15 +1,15 @@ -error: invalid suffix `is` for numeric literal +error: invalid suffix `is` for integer literal --> $DIR/old-suffixes-are-really-forbidden.rs:2:13 | -LL | let a = 1_is; //~ ERROR invalid suffix +LL | let a = 1_is; | ^^^^ invalid suffix `is` | = help: the suffix must be one of the integral types (`u32`, `isize`, etc) -error: invalid suffix `us` for numeric literal +error: invalid suffix `us` for integer literal --> $DIR/old-suffixes-are-really-forbidden.rs:3:13 | -LL | let b = 2_us; //~ ERROR invalid suffix +LL | let b = 2_us; | ^^^^ invalid suffix `us` | = help: the suffix must be one of the integral types (`u32`, `isize`, etc) diff --git a/src/test/ui/on-unimplemented/auxiliary/no_debug.rs b/src/test/ui/on-unimplemented/auxiliary/no_debug.rs index f240d0e1f1fab..fd3dc0abdc8fc 100644 --- a/src/test/ui/on-unimplemented/auxiliary/no_debug.rs +++ b/src/test/ui/on-unimplemented/auxiliary/no_debug.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - #![crate_type = "lib"] pub struct Bar; diff --git a/src/test/ui/on-unimplemented/bad-annotation.rs b/src/test/ui/on-unimplemented/bad-annotation.rs index 846db63024cfb..5357c3bff9a8a 100644 --- a/src/test/ui/on-unimplemented/bad-annotation.rs +++ b/src/test/ui/on-unimplemented/bad-annotation.rs @@ -15,7 +15,7 @@ trait MyFromIterator { } #[rustc_on_unimplemented] -//~^ ERROR attribute must be of the form +//~^ ERROR malformed `rustc_on_unimplemented` attribute trait BadAnnotation1 {} diff --git a/src/test/ui/on-unimplemented/bad-annotation.stderr b/src/test/ui/on-unimplemented/bad-annotation.stderr index 31b626e0ff4c5..20b2169f45824 100644 --- a/src/test/ui/on-unimplemented/bad-annotation.stderr +++ b/src/test/ui/on-unimplemented/bad-annotation.stderr @@ -1,8 +1,14 @@ -error: attribute must be of the form `#[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")]` or `#[rustc_on_unimplemented = "message"]` +error: malformed `rustc_on_unimplemented` attribute input --> $DIR/bad-annotation.rs:17:1 | LL | #[rustc_on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: the following are the possible correct uses + | +LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")] + | +LL | #[rustc_on_unimplemented = "message"] + | error[E0230]: there is no parameter `C` on trait `BadAnnotation2` --> $DIR/bad-annotation.rs:22:1 @@ -72,5 +78,5 @@ LL | #[rustc_on_unimplemented(on(desugared, on(desugared, message="x")), message error: aborting due to 10 previous errors -Some errors occurred: E0230, E0231, E0232. +Some errors have detailed explanations: E0230, E0231, E0232. For more information about an error, try `rustc --explain E0230`. diff --git a/src/test/ui/on-unimplemented/expected-comma-found-token.stderr b/src/test/ui/on-unimplemented/expected-comma-found-token.stderr index 1e0808e1d8408..5bbdbe29416c1 100644 --- a/src/test/ui/on-unimplemented/expected-comma-found-token.stderr +++ b/src/test/ui/on-unimplemented/expected-comma-found-token.stderr @@ -3,7 +3,7 @@ error: expected one of `)` or `,`, found `label` | LL | message="the message" | - expected one of `)` or `,` here -LL | label="the label" //~ ERROR expected one of `)` or `,`, found `label` +LL | label="the label" | ^^^^^ unexpected token error: aborting due to previous error diff --git a/src/test/ui/on-unimplemented/no-debug.rs b/src/test/ui/on-unimplemented/no-debug.rs index 858df17ffda0f..45c9ea46fa29d 100644 --- a/src/test/ui/on-unimplemented/no-debug.rs +++ b/src/test/ui/on-unimplemented/no-debug.rs @@ -14,4 +14,3 @@ fn main() { //~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Debug` //~^^^^ ERROR `Foo` doesn't implement `std::fmt::Display` //~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Display` - diff --git a/src/test/ui/on-unimplemented/on-trait.stderr b/src/test/ui/on-unimplemented/on-trait.stderr index 939c2725cc472..ece8dee0afe97 100644 --- a/src/test/ui/on-unimplemented/on-trait.stderr +++ b/src/test/ui/on-unimplemented/on-trait.stderr @@ -14,7 +14,7 @@ LL | fn collect, B: MyFromIterator>(it: I) -> B { error[E0277]: the trait bound `std::string::String: Bar::Foo` is not satisfied --> $DIR/on-trait.rs:31:21 | -LL | let x: String = foobar(); //~ ERROR +LL | let x: String = foobar(); | ^^^^^^ test error `std::string::String` with `u8` `_` `u32` in `Bar::Foo` | = help: the trait `Bar::Foo` is not implemented for `std::string::String` diff --git a/src/test/ui/on-unimplemented/slice-index.rs b/src/test/ui/on-unimplemented/slice-index.rs index b5e18e2397e00..758220d3c4ecd 100644 --- a/src/test/ui/on-unimplemented/slice-index.rs +++ b/src/test/ui/on-unimplemented/slice-index.rs @@ -1,7 +1,4 @@ // Test new Index error message for slices -// ignore-tidy-linelength - - use std::ops::Index; diff --git a/src/test/ui/on-unimplemented/slice-index.stderr b/src/test/ui/on-unimplemented/slice-index.stderr index 7b45d848c97b7..25a65460071da 100644 --- a/src/test/ui/on-unimplemented/slice-index.stderr +++ b/src/test/ui/on-unimplemented/slice-index.stderr @@ -1,16 +1,16 @@ error[E0277]: the type `[i32]` cannot be indexed by `i32` - --> $DIR/slice-index.rs:11:5 + --> $DIR/slice-index.rs:8:5 | -LL | x[1i32]; //~ ERROR E0277 +LL | x[1i32]; | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `std::slice::SliceIndex<[i32]>` is not implemented for `i32` = note: required because of the requirements on the impl of `std::ops::Index` for `[i32]` error[E0277]: the type `[i32]` cannot be indexed by `std::ops::RangeTo` - --> $DIR/slice-index.rs:12:5 + --> $DIR/slice-index.rs:9:5 | -LL | x[..1i32]; //~ ERROR E0277 +LL | x[..1i32]; | ^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `std::slice::SliceIndex<[i32]>` is not implemented for `std::ops::RangeTo` diff --git a/src/test/ui/once-cant-call-twice-on-heap.nll.stderr b/src/test/ui/once-cant-call-twice-on-heap.nll.stderr deleted file mode 100644 index ea53abc1b0f2d..0000000000000 --- a/src/test/ui/once-cant-call-twice-on-heap.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0382]: use of moved value: `blk` - --> $DIR/once-cant-call-twice-on-heap.rs:9:5 - | -LL | fn foo(blk: F) { - | - --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | blk(); - | --- value moved here -LL | blk(); //~ ERROR use of moved value - | ^^^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/once-cant-call-twice-on-heap.stderr b/src/test/ui/once-cant-call-twice-on-heap.stderr index 4559425e5be0d..f98d3d8384537 100644 --- a/src/test/ui/once-cant-call-twice-on-heap.stderr +++ b/src/test/ui/once-cant-call-twice-on-heap.stderr @@ -1,12 +1,14 @@ error[E0382]: use of moved value: `blk` --> $DIR/once-cant-call-twice-on-heap.rs:9:5 | +LL | fn foo(blk: F) { + | - --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | blk(); | --- value moved here -LL | blk(); //~ ERROR use of moved value +LL | blk(); | ^^^ value used here after move - | - = note: move occurs because `blk` has type `F`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/order-dependent-cast-inference.stderr b/src/test/ui/order-dependent-cast-inference.stderr index 081038c573acf..01e59f8f022fd 100644 --- a/src/test/ui/order-dependent-cast-inference.stderr +++ b/src/test/ui/order-dependent-cast-inference.stderr @@ -10,4 +10,3 @@ LL | let mut y = 0 as *const _; error: aborting due to previous error -For more information about this error, try `rustc --explain E0641`. diff --git a/src/test/ui/orphan-check-diagnostics.rs b/src/test/ui/orphan-check-diagnostics.rs index 9a29620ae6532..c8803b9ae5d82 100644 --- a/src/test/ui/orphan-check-diagnostics.rs +++ b/src/test/ui/orphan-check-diagnostics.rs @@ -1,5 +1,6 @@ -// aux-build:orphan_check_diagnostics.rs -// see #22388 +// aux-build:orphan-check-diagnostics.rs + +// See issue #22388. extern crate orphan_check_diagnostics; diff --git a/src/test/ui/orphan-check-diagnostics.stderr b/src/test/ui/orphan-check-diagnostics.stderr index 4bd6aa2c154bd..3f868422c7fcb 100644 --- a/src/test/ui/orphan-check-diagnostics.stderr +++ b/src/test/ui/orphan-check-diagnostics.stderr @@ -1,5 +1,5 @@ error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) - --> $DIR/orphan-check-diagnostics.rs:10:1 + --> $DIR/orphan-check-diagnostics.rs:11:1 | LL | impl RemoteTrait for T where T: LocalTrait {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type diff --git a/src/test/ui/out-of-order-shadowing.rs b/src/test/ui/out-of-order-shadowing.rs index b4cb6a2383013..a0d1a973764ad 100644 --- a/src/test/ui/out-of-order-shadowing.rs +++ b/src/test/ui/out-of-order-shadowing.rs @@ -1,4 +1,4 @@ -// aux-build:define_macro.rs +// aux-build:define-macro.rs macro_rules! bar { () => {} } define_macro!(bar); diff --git a/src/test/ui/out-of-order-shadowing.stderr b/src/test/ui/out-of-order-shadowing.stderr index 17bda18f8f63b..2a120dee482df 100644 --- a/src/test/ui/out-of-order-shadowing.stderr +++ b/src/test/ui/out-of-order-shadowing.stderr @@ -1,7 +1,7 @@ error[E0659]: `bar` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) --> $DIR/out-of-order-shadowing.rs:5:1 | -LL | bar!(); //~ ERROR `bar` is ambiguous +LL | bar!(); | ^^^ ambiguous name | note: `bar` could refer to the macro defined here diff --git a/src/test/ui/overlap-marker-trait.stderr b/src/test/ui/overlap-marker-trait.stderr index 21ba2367901cd..a59af8dcdbcf7 100644 --- a/src/test/ui/overlap-marker-trait.stderr +++ b/src/test/ui/overlap-marker-trait.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `NotDebugOrDisplay: Marker` is not satisfied --> $DIR/overlap-marker-trait.rs:30:5 | -LL | is_marker::(); //~ ERROR +LL | is_marker::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Marker` is not implemented for `NotDebugOrDisplay` | note: required by `is_marker` diff --git a/src/test/ui/overloaded-calls-nontuple.stderr b/src/test/ui/overloaded-calls-nontuple.stderr index 31b5697addaf8..82c12c4b6e19c 100644 --- a/src/test/ui/overloaded-calls-nontuple.stderr +++ b/src/test/ui/overloaded-calls-nontuple.stderr @@ -1,7 +1,7 @@ error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit --> $DIR/overloaded-calls-nontuple.rs:26:10 | -LL | drop(s(3)) //~ ERROR cannot use call notation +LL | drop(s(3)) | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/panic-handler/panic-handler-bad-signature-1.stderr b/src/test/ui/panic-handler/panic-handler-bad-signature-1.stderr index e36644895492f..8b044f7669c72 100644 --- a/src/test/ui/panic-handler/panic-handler-bad-signature-1.stderr +++ b/src/test/ui/panic-handler/panic-handler-bad-signature-1.stderr @@ -1,13 +1,13 @@ error: return type should be `!` --> $DIR/panic-handler-bad-signature-1.rs:11:6 | -LL | ) -> () //~ ERROR return type should be `!` +LL | ) -> () | ^^ error: argument should be `&PanicInfo` --> $DIR/panic-handler-bad-signature-1.rs:10:11 | -LL | info: PanicInfo, //~ ERROR argument should be `&PanicInfo` +LL | info: PanicInfo, | ^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/panic-handler/panic-handler-bad-signature-2.stderr b/src/test/ui/panic-handler/panic-handler-bad-signature-2.stderr index 737ff313d0bef..5ab6934202e94 100644 --- a/src/test/ui/panic-handler/panic-handler-bad-signature-2.stderr +++ b/src/test/ui/panic-handler/panic-handler-bad-signature-2.stderr @@ -1,7 +1,7 @@ error: argument should be `&PanicInfo` --> $DIR/panic-handler-bad-signature-2.rs:10:11 | -LL | info: &'static PanicInfo, //~ ERROR argument should be `&PanicInfo` +LL | info: &'static PanicInfo, | ^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/panic-handler/panic-handler-bad-signature-3.stderr b/src/test/ui/panic-handler/panic-handler-bad-signature-3.stderr index c0b39769a49b5..0a70181fdace9 100644 --- a/src/test/ui/panic-handler/panic-handler-bad-signature-3.stderr +++ b/src/test/ui/panic-handler/panic-handler-bad-signature-3.stderr @@ -1,7 +1,7 @@ error: function should have one argument --> $DIR/panic-handler-bad-signature-3.rs:9:1 | -LL | fn panic() -> ! { //~ ERROR function should have one argument +LL | fn panic() -> ! { | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/panic-handler/panic-handler-bad-signature-4.stderr b/src/test/ui/panic-handler/panic-handler-bad-signature-4.stderr index bd25c8b02f805..3a5fc76efbbd4 100644 --- a/src/test/ui/panic-handler/panic-handler-bad-signature-4.stderr +++ b/src/test/ui/panic-handler/panic-handler-bad-signature-4.stderr @@ -2,7 +2,7 @@ error: should have no type parameters --> $DIR/panic-handler-bad-signature-4.rs:9:1 | LL | / fn panic(pi: &PanicInfo) -> ! { -LL | | //~^ ERROR should have no type parameters +LL | | LL | | loop {} LL | | } | |_^ diff --git a/src/test/ui/panic-handler/panic-handler-duplicate.stderr b/src/test/ui/panic-handler/panic-handler-duplicate.stderr index 80deff23a87d1..e9b1945364372 100644 --- a/src/test/ui/panic-handler/panic-handler-duplicate.stderr +++ b/src/test/ui/panic-handler/panic-handler-duplicate.stderr @@ -1,7 +1,7 @@ error[E0152]: duplicate lang item found: `panic_impl`. --> $DIR/panic-handler-duplicate.rs:15:1 | -LL | / fn panic2(info: &PanicInfo) -> ! { //~ ERROR duplicate lang item found: `panic_impl`. +LL | / fn panic2(info: &PanicInfo) -> ! { LL | | loop {} LL | | } | |_^ diff --git a/src/test/ui/panic-handler/panic-handler-wrong-location.stderr b/src/test/ui/panic-handler/panic-handler-wrong-location.stderr index cab45d8bfad62..ae3ed5ab12b4c 100644 --- a/src/test/ui/panic-handler/panic-handler-wrong-location.stderr +++ b/src/test/ui/panic-handler/panic-handler-wrong-location.stderr @@ -1,7 +1,7 @@ error[E0718]: `panic_impl` language item must be applied to a function --> $DIR/panic-handler-wrong-location.rs:6:1 | -LL | #[panic_handler] //~ ERROR `panic_impl` language item must be applied to a function +LL | #[panic_handler] | ^^^^^^^^^^^^^^^^ attribute should be applied to a function, not a static item error: `#[panic_handler]` function required, but not found diff --git a/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs b/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs index 7e1174a273438..c2deeb7dfd48b 100644 --- a/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs +++ b/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs @@ -2,6 +2,7 @@ // ignore-musl - no dylibs here // ignore-cloudabi // ignore-emscripten +// ignore-sgx no dynamic lib support // error-pattern:`panic_unwind` is not compiled with this crate's panic strategy // This is a test where the local crate, compiled with `panic=abort`, links to diff --git a/src/test/ui/panic-runtime/libtest-unwinds.rs b/src/test/ui/panic-runtime/libtest-unwinds.rs index 47dd8c3efe58e..bc13072612a29 100644 --- a/src/test/ui/panic-runtime/libtest-unwinds.rs +++ b/src/test/ui/panic-runtime/libtest-unwinds.rs @@ -8,4 +8,3 @@ extern crate test; fn main() { } - diff --git a/src/test/ui/panic-runtime/needs-gate.stderr b/src/test/ui/panic-runtime/needs-gate.stderr index 75ddda79b2d0e..72999a0de89eb 100644 --- a/src/test/ui/panic-runtime/needs-gate.stderr +++ b/src/test/ui/panic-runtime/needs-gate.stderr @@ -1,17 +1,19 @@ -error[E0658]: the `#[panic_runtime]` attribute is an experimental feature (see issue #32837) +error[E0658]: the `#[panic_runtime]` attribute is an experimental feature --> $DIR/needs-gate.rs:4:1 | -LL | #![panic_runtime] //~ ERROR: is an experimental feature +LL | #![panic_runtime] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32837 = help: add #![feature(panic_runtime)] to the crate attributes to enable -error[E0658]: the `#[needs_panic_runtime]` attribute is an experimental feature (see issue #32837) +error[E0658]: the `#[needs_panic_runtime]` attribute is an experimental feature --> $DIR/needs-gate.rs:5:1 | -LL | #![needs_panic_runtime] //~ ERROR: is an experimental feature +LL | #![needs_panic_runtime] | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32837 = help: add #![feature(needs_panic_runtime)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/paren-span.stderr b/src/test/ui/paren-span.stderr index 23e6ade046957..141378752d6f4 100644 --- a/src/test/ui/paren-span.stderr +++ b/src/test/ui/paren-span.stderr @@ -1,7 +1,7 @@ error[E0616]: field `x` of struct `m::S` is private --> $DIR/paren-span.rs:19:12 | -LL | paren!(s.x); //~ ERROR field `x` of struct `m::S` is private +LL | paren!(s.x); | ^^^ error: aborting due to previous error diff --git a/src/test/ui/parenthesized-deref-suggestion.stderr b/src/test/ui/parenthesized-deref-suggestion.stderr index fd9b0e8216b41..a16510055f548 100644 --- a/src/test/ui/parenthesized-deref-suggestion.stderr +++ b/src/test/ui/parenthesized-deref-suggestion.stderr @@ -1,17 +1,17 @@ error[E0609]: no field `opts` on type `*const Session` --> $DIR/parenthesized-deref-suggestion.rs:7:30 | -LL | (sess as *const Session).opts; //~ ERROR no field `opts` on type `*const Session` +LL | (sess as *const Session).opts; | ^^^^ help: `(sess as *const Session)` is a raw pointer; try dereferencing it | -LL | (*(sess as *const Session)).opts; //~ ERROR no field `opts` on type `*const Session` +LL | (*(sess as *const Session)).opts; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0609]: no field `0` on type `[u32; 1]` --> $DIR/parenthesized-deref-suggestion.rs:10:21 | -LL | (x as [u32; 1]).0; //~ ERROR no field `0` on type `[u32; 1]` +LL | (x as [u32; 1]).0; | ----------------^ | | | help: instead of using tuple indexing, use array indexing: `(x as [u32; 1])[0]` diff --git a/src/test/ui/parse-error-correct.stderr b/src/test/ui/parse-error-correct.stderr index 529a93cf3042b..d593431d9781d 100644 --- a/src/test/ui/parse-error-correct.stderr +++ b/src/test/ui/parse-error-correct.stderr @@ -1,13 +1,13 @@ error: unexpected token: `;` --> $DIR/parse-error-correct.rs:8:15 | -LL | let x = y.; //~ ERROR unexpected token +LL | let x = y.; | ^ error: unexpected token: `(` --> $DIR/parse-error-correct.rs:9:15 | -LL | let x = y.(); //~ ERROR unexpected token +LL | let x = y.(); | ^ error[E0618]: expected function, found `{integer}` @@ -15,8 +15,8 @@ error[E0618]: expected function, found `{integer}` | LL | let y = 42; | - `{integer}` defined here -LL | let x = y.; //~ ERROR unexpected token -LL | let x = y.(); //~ ERROR unexpected token +LL | let x = y.; +LL | let x = y.(); | ^--- | | | call expression requires function @@ -24,10 +24,10 @@ LL | let x = y.(); //~ ERROR unexpected token error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> $DIR/parse-error-correct.rs:11:15 | -LL | let x = y.foo; //~ ERROR `{integer}` is a primitive type and therefore doesn't have fields [E061 +LL | let x = y.foo; | ^^^ error: aborting due to 4 previous errors -Some errors occurred: E0610, E0618. +Some errors have detailed explanations: E0610, E0618. For more information about an error, try `rustc --explain E0610`. diff --git a/src/test/ui/parser-recovery-1.stderr b/src/test/ui/parser-recovery-1.stderr index 28505a8a0565f..c29f42759178e 100644 --- a/src/test/ui/parser-recovery-1.stderr +++ b/src/test/ui/parser-recovery-1.stderr @@ -9,7 +9,7 @@ LL | fn bar() { LL | } | - ...as it matches this but it has different indentation ... -LL | } //~ ERROR this file contains an un-closed delimiter +LL | } | ^ error: unexpected token: `;` @@ -36,5 +36,5 @@ error[E0601]: `main` function not found in crate `parser_recovery_1` error: aborting due to 5 previous errors -Some errors occurred: E0425, E0601. +Some errors have detailed explanations: E0425, E0601. For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/parser-recovery-2.stderr b/src/test/ui/parser-recovery-2.stderr index 76f7af38e776d..c246fa80b0a05 100644 --- a/src/test/ui/parser-recovery-2.stderr +++ b/src/test/ui/parser-recovery-2.stderr @@ -1,7 +1,7 @@ error: unexpected token: `;` --> $DIR/parser-recovery-2.rs:12:15 | -LL | let x = y.; //~ ERROR unexpected token +LL | let x = y.; | ^ error: incorrect close delimiter: `)` @@ -9,20 +9,20 @@ error: incorrect close delimiter: `)` | LL | fn bar() { | - un-closed delimiter -LL | let x = foo(); //~ ERROR cannot find function `foo` in this scope -LL | ) //~ ERROR incorrect close delimiter: `)` +LL | let x = foo(); +LL | ) | ^ incorrect close delimiter error[E0425]: cannot find function `foo` in this scope --> $DIR/parser-recovery-2.rs:7:17 | -LL | let x = foo(); //~ ERROR cannot find function `foo` in this scope +LL | let x = foo(); | ^^^ not found in this scope error[E0425]: cannot find value `y` in this scope --> $DIR/parser-recovery-2.rs:12:13 | -LL | let x = y.; //~ ERROR unexpected token +LL | let x = y.; | ^ not found in this scope error: aborting due to 4 previous errors diff --git a/src/test/ui/parser/ascii-only-character-escape.stderr b/src/test/ui/parser/ascii-only-character-escape.stderr index d3330a405c06b..391677917580b 100644 --- a/src/test/ui/parser/ascii-only-character-escape.stderr +++ b/src/test/ui/parser/ascii-only-character-escape.stderr @@ -1,20 +1,20 @@ -error: this form of character escape may only be used with characters in the range [/x00-/x7f] - --> $DIR/ascii-only-character-escape.rs:4:16 +error: this form of character escape may only be used with characters in the range [\x00-\x7f] + --> $DIR/ascii-only-character-escape.rs:4:14 | -LL | let x = "/x80"; //~ ERROR may only be used - | ^^ +LL | let x = "\x80"; + | ^^^^ -error: this form of character escape may only be used with characters in the range [/x00-/x7f] - --> $DIR/ascii-only-character-escape.rs:5:16 +error: this form of character escape may only be used with characters in the range [\x00-\x7f] + --> $DIR/ascii-only-character-escape.rs:5:14 | -LL | let y = "/xff"; //~ ERROR may only be used - | ^^ +LL | let y = "\xff"; + | ^^^^ -error: this form of character escape may only be used with characters in the range [/x00-/x7f] - --> $DIR/ascii-only-character-escape.rs:6:16 +error: this form of character escape may only be used with characters in the range [\x00-\x7f] + --> $DIR/ascii-only-character-escape.rs:6:14 | -LL | let z = "/xe2"; //~ ERROR may only be used - | ^^ +LL | let z = "\xe2"; + | ^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/assoc-oddities-1.stderr b/src/test/ui/parser/assoc-oddities-1.stderr index 076bca0fc3a2d..376ddf4d68b74 100644 --- a/src/test/ui/parser/assoc-oddities-1.stderr +++ b/src/test/ui/parser/assoc-oddities-1.stderr @@ -1,7 +1,7 @@ error: expected one of `.`, `;`, `?`, or `}`, found `[` --> $DIR/assoc-oddities-1.rs:10:28 | -LL | ..if c { a } else { b }[n]; //~ ERROR expected one of +LL | ..if c { a } else { b }[n]; | ^ expected one of `.`, `;`, `?`, or `}` here error: aborting due to previous error diff --git a/src/test/ui/parser/assoc-oddities-2.stderr b/src/test/ui/parser/assoc-oddities-2.stderr index 5681029125213..4b3893d2c17da 100644 --- a/src/test/ui/parser/assoc-oddities-2.stderr +++ b/src/test/ui/parser/assoc-oddities-2.stderr @@ -1,7 +1,7 @@ error: expected one of `.`, `;`, `?`, or `}`, found `[` --> $DIR/assoc-oddities-2.rs:5:29 | -LL | x..if c { a } else { b }[n]; //~ ERROR expected one of +LL | x..if c { a } else { b }[n]; | ^ expected one of `.`, `;`, `?`, or `}` here error: aborting due to previous error diff --git a/src/test/ui/parser/associated-types-project-from-hrtb-explicit.rs b/src/test/ui/parser/associated-types-project-from-hrtb-explicit.rs index ed9c996d4ccef..b238a9ca22674 100644 --- a/src/test/ui/parser/associated-types-project-from-hrtb-explicit.rs +++ b/src/test/ui/parser/associated-types-project-from-hrtb-explicit.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - // Test you can't use a higher-ranked trait bound inside of a qualified // path (just won't parse). diff --git a/src/test/ui/parser/associated-types-project-from-hrtb-explicit.stderr b/src/test/ui/parser/associated-types-project-from-hrtb-explicit.stderr index ceea4625e3eb3..ada0f268a8d6b 100644 --- a/src/test/ui/parser/associated-types-project-from-hrtb-explicit.stderr +++ b/src/test/ui/parser/associated-types-project-from-hrtb-explicit.stderr @@ -1,5 +1,5 @@ error: expected identifier, found keyword `for` - --> $DIR/associated-types-project-from-hrtb-explicit.rs:12:21 + --> $DIR/associated-types-project-from-hrtb-explicit.rs:10:21 | LL | fn foo2(x: Foo<&'x isize>>::A) | ^^^ expected identifier, found keyword @@ -9,7 +9,7 @@ LL | fn foo2(x: Foo<&'x isize>>::A) | ^^^^^ error: expected one of `::` or `>`, found `Foo` - --> $DIR/associated-types-project-from-hrtb-explicit.rs:12:29 + --> $DIR/associated-types-project-from-hrtb-explicit.rs:10:29 | LL | fn foo2(x: Foo<&'x isize>>::A) | ^^^ expected one of `::` or `>` here diff --git a/src/test/ui/parser/attr-bad-meta-2.stderr b/src/test/ui/parser/attr-bad-meta-2.stderr index 36e566b5aa41a..2d772dae69125 100644 --- a/src/test/ui/parser/attr-bad-meta-2.stderr +++ b/src/test/ui/parser/attr-bad-meta-2.stderr @@ -1,8 +1,8 @@ error: unexpected token: `]` - --> $DIR/attr-bad-meta-2.rs:1:8 + --> $DIR/attr-bad-meta-2.rs:1:9 | -LL | #[path =] //~ ERROR unexpected token: `]` - | ^ +LL | #[path =] + | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/attr-bad-meta-3.stderr b/src/test/ui/parser/attr-bad-meta-3.stderr index 863a2d2069fce..4fa420c79fcc8 100644 --- a/src/test/ui/parser/attr-bad-meta-3.stderr +++ b/src/test/ui/parser/attr-bad-meta-3.stderr @@ -1,7 +1,7 @@ error: expected `]`, found `token` --> $DIR/attr-bad-meta-3.rs:1:10 | -LL | #[path() token] //~ ERROR expected `]`, found `token` +LL | #[path() token] | ^^^^^ expected `]` error: aborting due to previous error diff --git a/src/test/ui/parser/attr-bad-meta.stderr b/src/test/ui/parser/attr-bad-meta.stderr index 693da95017d2e..a452df5e90cb7 100644 --- a/src/test/ui/parser/attr-bad-meta.stderr +++ b/src/test/ui/parser/attr-bad-meta.stderr @@ -1,7 +1,7 @@ error: expected one of `(`, `::`, `=`, `[`, `]`, or `{`, found `*` --> $DIR/attr-bad-meta.rs:1:7 | -LL | #[path*] //~ ERROR expected one of `(`, `::`, `=`, `[`, `]`, or `{`, found `*` +LL | #[path*] | ^ expected one of `(`, `::`, `=`, `[`, `]`, or `{` here error: aborting due to previous error diff --git a/src/test/ui/parser/attr-before-eof.stderr b/src/test/ui/parser/attr-before-eof.stderr index a81dc52417a4a..eb5daf849811c 100644 --- a/src/test/ui/parser/attr-before-eof.stderr +++ b/src/test/ui/parser/attr-before-eof.stderr @@ -1,7 +1,7 @@ error: expected item after attributes --> $DIR/attr-before-eof.rs:3:16 | -LL | #[derive(Debug)] //~ERROR expected item after attributes +LL | #[derive(Debug)] | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/attr.stderr b/src/test/ui/parser/attr.stderr index 8151bd7cdd7b1..5111b40603c49 100644 --- a/src/test/ui/parser/attr.stderr +++ b/src/test/ui/parser/attr.stderr @@ -1,7 +1,7 @@ error: an inner attribute is not permitted in this context --> $DIR/attr.rs:5:3 | -LL | #![lang = "foo"] //~ ERROR an inner attribute is not permitted in this context +LL | #![lang = "foo"] | ^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. @@ -9,7 +9,7 @@ LL | #![lang = "foo"] //~ ERROR an inner attribute is not permitted in this cont error[E0522]: definition of an unknown language item: `foo` --> $DIR/attr.rs:5:1 | -LL | #![lang = "foo"] //~ ERROR an inner attribute is not permitted in this context +LL | #![lang = "foo"] | ^^^^^^^^^^^^^^^^ definition of unknown language item `foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/attrs-after-extern-mod.stderr b/src/test/ui/parser/attrs-after-extern-mod.stderr index 067c4192ce6af..cecdab4d63197 100644 --- a/src/test/ui/parser/attrs-after-extern-mod.stderr +++ b/src/test/ui/parser/attrs-after-extern-mod.stderr @@ -1,7 +1,7 @@ error: expected item after attributes --> $DIR/attrs-after-extern-mod.rs:10:19 | -LL | #[cfg(stage37)] //~ ERROR expected item after attributes +LL | #[cfg(stage37)] | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/bad-char-literals.stderr b/src/test/ui/parser/bad-char-literals.stderr index 0335a4b83eab1..8e96ea22771b8 100644 --- a/src/test/ui/parser/bad-char-literals.stderr +++ b/src/test/ui/parser/bad-char-literals.stderr @@ -4,7 +4,7 @@ error: character constant must be escaped: ' LL | '''; | ^ -error: character constant must be escaped: /n +error: character constant must be escaped: \n --> $DIR/bad-char-literals.rs:11:6 | LL | ' @@ -12,13 +12,13 @@ LL | ' LL | | '; | |_ -error: character constant must be escaped: /r +error: character constant must be escaped: \r --> $DIR/bad-char-literals.rs:16:6 | -LL | ' '; //~ ERROR: character constant must be escaped: /r +LL | ' '; | ^ -error: character constant must be escaped: /t +error: character constant must be escaped: \t --> $DIR/bad-char-literals.rs:19:6 | LL | ' '; diff --git a/src/test/ui/parser/bad-lit-suffixes.rs b/src/test/ui/parser/bad-lit-suffixes.rs index 391e7f0acf979..9f301db09956e 100644 --- a/src/test/ui/parser/bad-lit-suffixes.rs +++ b/src/test/ui/parser/bad-lit-suffixes.rs @@ -1,29 +1,26 @@ -// compile-flags: -Z continue-parse-after-error - - extern - "C"suffix //~ ERROR ABI spec with a suffix is invalid + "C"suffix //~ ERROR suffixes on an ABI spec are invalid fn foo() {} extern - "C"suffix //~ ERROR ABI spec with a suffix is invalid + "C"suffix //~ ERROR suffixes on an ABI spec are invalid {} fn main() { - ""suffix; //~ ERROR string literal with a suffix is invalid - b""suffix; //~ ERROR byte string literal with a suffix is invalid - r#""#suffix; //~ ERROR string literal with a suffix is invalid - br#""#suffix; //~ ERROR byte string literal with a suffix is invalid - 'a'suffix; //~ ERROR char literal with a suffix is invalid - b'a'suffix; //~ ERROR byte literal with a suffix is invalid + ""suffix; //~ ERROR suffixes on a string literal are invalid + b""suffix; //~ ERROR suffixes on a byte string literal are invalid + r#""#suffix; //~ ERROR suffixes on a string literal are invalid + br#""#suffix; //~ ERROR suffixes on a byte string literal are invalid + 'a'suffix; //~ ERROR suffixes on a char literal are invalid + b'a'suffix; //~ ERROR suffixes on a byte literal are invalid 1234u1024; //~ ERROR invalid width `1024` for integer literal 1234i1024; //~ ERROR invalid width `1024` for integer literal 1234f1024; //~ ERROR invalid width `1024` for float literal 1234.5f1024; //~ ERROR invalid width `1024` for float literal - 1234suffix; //~ ERROR invalid suffix `suffix` for numeric literal - 0b101suffix; //~ ERROR invalid suffix `suffix` for numeric literal + 1234suffix; //~ ERROR invalid suffix `suffix` for integer literal + 0b101suffix; //~ ERROR invalid suffix `suffix` for integer literal 1.0suffix; //~ ERROR invalid suffix `suffix` for float literal 1.0e10suffix; //~ ERROR invalid suffix `suffix` for float literal } diff --git a/src/test/ui/parser/bad-lit-suffixes.stderr b/src/test/ui/parser/bad-lit-suffixes.stderr index 608c5fda2482a..208fcf43d9177 100644 --- a/src/test/ui/parser/bad-lit-suffixes.stderr +++ b/src/test/ui/parser/bad-lit-suffixes.stderr @@ -1,111 +1,111 @@ -error: ABI spec with a suffix is invalid - --> $DIR/bad-lit-suffixes.rs:5:5 +error: suffixes on an ABI spec are invalid + --> $DIR/bad-lit-suffixes.rs:2:5 | -LL | "C"suffix //~ ERROR ABI spec with a suffix is invalid - | ^^^^^^^^^ ABI spec with a suffix is invalid +LL | "C"suffix + | ^^^^^^^^^ invalid suffix `suffix` -error: ABI spec with a suffix is invalid - --> $DIR/bad-lit-suffixes.rs:9:5 +error: suffixes on an ABI spec are invalid + --> $DIR/bad-lit-suffixes.rs:6:5 | -LL | "C"suffix //~ ERROR ABI spec with a suffix is invalid - | ^^^^^^^^^ ABI spec with a suffix is invalid +LL | "C"suffix + | ^^^^^^^^^ invalid suffix `suffix` -error: string literal with a suffix is invalid - --> $DIR/bad-lit-suffixes.rs:13:5 +error: suffixes on a string literal are invalid + --> $DIR/bad-lit-suffixes.rs:10:5 | -LL | ""suffix; //~ ERROR string literal with a suffix is invalid - | ^^^^^^^^ string literal with a suffix is invalid +LL | ""suffix; + | ^^^^^^^^ invalid suffix `suffix` -error: byte string literal with a suffix is invalid - --> $DIR/bad-lit-suffixes.rs:14:5 +error: suffixes on a byte string literal are invalid + --> $DIR/bad-lit-suffixes.rs:11:5 | -LL | b""suffix; //~ ERROR byte string literal with a suffix is invalid - | ^^^^^^^^^ byte string literal with a suffix is invalid +LL | b""suffix; + | ^^^^^^^^^ invalid suffix `suffix` -error: string literal with a suffix is invalid - --> $DIR/bad-lit-suffixes.rs:15:5 +error: suffixes on a string literal are invalid + --> $DIR/bad-lit-suffixes.rs:12:5 | -LL | r#""#suffix; //~ ERROR string literal with a suffix is invalid - | ^^^^^^^^^^^ string literal with a suffix is invalid +LL | r#""#suffix; + | ^^^^^^^^^^^ invalid suffix `suffix` -error: byte string literal with a suffix is invalid - --> $DIR/bad-lit-suffixes.rs:16:5 +error: suffixes on a byte string literal are invalid + --> $DIR/bad-lit-suffixes.rs:13:5 | -LL | br#""#suffix; //~ ERROR byte string literal with a suffix is invalid - | ^^^^^^^^^^^^ byte string literal with a suffix is invalid +LL | br#""#suffix; + | ^^^^^^^^^^^^ invalid suffix `suffix` -error: char literal with a suffix is invalid - --> $DIR/bad-lit-suffixes.rs:17:5 +error: suffixes on a char literal are invalid + --> $DIR/bad-lit-suffixes.rs:14:5 | -LL | 'a'suffix; //~ ERROR char literal with a suffix is invalid - | ^^^^^^^^^ char literal with a suffix is invalid +LL | 'a'suffix; + | ^^^^^^^^^ invalid suffix `suffix` -error: byte literal with a suffix is invalid - --> $DIR/bad-lit-suffixes.rs:18:5 +error: suffixes on a byte literal are invalid + --> $DIR/bad-lit-suffixes.rs:15:5 | -LL | b'a'suffix; //~ ERROR byte literal with a suffix is invalid - | ^^^^^^^^^^ byte literal with a suffix is invalid +LL | b'a'suffix; + | ^^^^^^^^^^ invalid suffix `suffix` error: invalid width `1024` for integer literal - --> $DIR/bad-lit-suffixes.rs:20:5 + --> $DIR/bad-lit-suffixes.rs:17:5 | -LL | 1234u1024; //~ ERROR invalid width `1024` for integer literal +LL | 1234u1024; | ^^^^^^^^^ | = help: valid widths are 8, 16, 32, 64 and 128 error: invalid width `1024` for integer literal - --> $DIR/bad-lit-suffixes.rs:21:5 + --> $DIR/bad-lit-suffixes.rs:18:5 | -LL | 1234i1024; //~ ERROR invalid width `1024` for integer literal +LL | 1234i1024; | ^^^^^^^^^ | = help: valid widths are 8, 16, 32, 64 and 128 error: invalid width `1024` for float literal - --> $DIR/bad-lit-suffixes.rs:22:5 + --> $DIR/bad-lit-suffixes.rs:19:5 | -LL | 1234f1024; //~ ERROR invalid width `1024` for float literal +LL | 1234f1024; | ^^^^^^^^^ | = help: valid widths are 32 and 64 error: invalid width `1024` for float literal - --> $DIR/bad-lit-suffixes.rs:23:5 + --> $DIR/bad-lit-suffixes.rs:20:5 | -LL | 1234.5f1024; //~ ERROR invalid width `1024` for float literal +LL | 1234.5f1024; | ^^^^^^^^^^^ | = help: valid widths are 32 and 64 -error: invalid suffix `suffix` for numeric literal - --> $DIR/bad-lit-suffixes.rs:25:5 +error: invalid suffix `suffix` for integer literal + --> $DIR/bad-lit-suffixes.rs:22:5 | -LL | 1234suffix; //~ ERROR invalid suffix `suffix` for numeric literal +LL | 1234suffix; | ^^^^^^^^^^ invalid suffix `suffix` | = help: the suffix must be one of the integral types (`u32`, `isize`, etc) -error: invalid suffix `suffix` for numeric literal - --> $DIR/bad-lit-suffixes.rs:26:5 +error: invalid suffix `suffix` for integer literal + --> $DIR/bad-lit-suffixes.rs:23:5 | -LL | 0b101suffix; //~ ERROR invalid suffix `suffix` for numeric literal +LL | 0b101suffix; | ^^^^^^^^^^^ invalid suffix `suffix` | = help: the suffix must be one of the integral types (`u32`, `isize`, etc) error: invalid suffix `suffix` for float literal - --> $DIR/bad-lit-suffixes.rs:27:5 + --> $DIR/bad-lit-suffixes.rs:24:5 | -LL | 1.0suffix; //~ ERROR invalid suffix `suffix` for float literal +LL | 1.0suffix; | ^^^^^^^^^ invalid suffix `suffix` | = help: valid suffixes are `f32` and `f64` error: invalid suffix `suffix` for float literal - --> $DIR/bad-lit-suffixes.rs:28:5 + --> $DIR/bad-lit-suffixes.rs:25:5 | -LL | 1.0e10suffix; //~ ERROR invalid suffix `suffix` for float literal +LL | 1.0e10suffix; | ^^^^^^^^^^^^ invalid suffix `suffix` | = help: valid suffixes are `f32` and `f64` diff --git a/src/test/ui/parser/bad-match.stderr b/src/test/ui/parser/bad-match.stderr index dd3a2d2a27a0a..2f29b978e9c91 100644 --- a/src/test/ui/parser/bad-match.stderr +++ b/src/test/ui/parser/bad-match.stderr @@ -1,7 +1,7 @@ error: expected one of `:`, `;`, `=`, or `@`, found `x` --> $DIR/bad-match.rs:2:13 | -LL | let isize x = 5; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `x` +LL | let isize x = 5; | ^ expected one of `:`, `;`, `=`, or `@` here error: aborting due to previous error diff --git a/src/test/ui/parser/bad-value-ident-false.stderr b/src/test/ui/parser/bad-value-ident-false.stderr index 69a496f3a0c39..9ddca101567ff 100644 --- a/src/test/ui/parser/bad-value-ident-false.stderr +++ b/src/test/ui/parser/bad-value-ident-false.stderr @@ -1,11 +1,11 @@ error: expected identifier, found keyword `false` --> $DIR/bad-value-ident-false.rs:1:4 | -LL | fn false() { } //~ ERROR expected identifier, found keyword `false` +LL | fn false() { } | ^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | -LL | fn r#false() { } //~ ERROR expected identifier, found keyword `false` +LL | fn r#false() { } | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/bad-value-ident-true.stderr b/src/test/ui/parser/bad-value-ident-true.stderr index 2606b7450aef9..ec497dbe40730 100644 --- a/src/test/ui/parser/bad-value-ident-true.stderr +++ b/src/test/ui/parser/bad-value-ident-true.stderr @@ -1,11 +1,11 @@ error: expected identifier, found keyword `true` --> $DIR/bad-value-ident-true.rs:1:4 | -LL | fn true() { } //~ ERROR expected identifier, found keyword `true` +LL | fn true() { } | ^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | -LL | fn r#true() { } //~ ERROR expected identifier, found keyword `true` +LL | fn r#true() { } | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/better-expected.stderr b/src/test/ui/parser/better-expected.stderr index 3495353c6f905..d100d01e78ff2 100644 --- a/src/test/ui/parser/better-expected.stderr +++ b/src/test/ui/parser/better-expected.stderr @@ -1,7 +1,7 @@ error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3` --> $DIR/better-expected.rs:2:19 | -LL | let x: [isize 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3` +LL | let x: [isize 3]; | - ^ expected one of 7 possible tokens here | | | while parsing the type for `x` diff --git a/src/test/ui/parser/bind-struct-early-modifiers.rs b/src/test/ui/parser/bind-struct-early-modifiers.rs index c1de0df54e278..c4b1937de104f 100644 --- a/src/test/ui/parser/bind-struct-early-modifiers.rs +++ b/src/test/ui/parser/bind-struct-early-modifiers.rs @@ -2,7 +2,6 @@ fn main() { struct Foo { x: isize } match (Foo { x: 10 }) { Foo { ref x: ref x } => {}, //~ ERROR expected `,` - //~| ERROR pattern does not mention field `x` _ => {} } } diff --git a/src/test/ui/parser/bind-struct-early-modifiers.stderr b/src/test/ui/parser/bind-struct-early-modifiers.stderr index 618e577e4e229..03482a41f5465 100644 --- a/src/test/ui/parser/bind-struct-early-modifiers.stderr +++ b/src/test/ui/parser/bind-struct-early-modifiers.stderr @@ -1,15 +1,8 @@ error: expected `,` --> $DIR/bind-struct-early-modifiers.rs:4:19 | -LL | Foo { ref x: ref x } => {}, //~ ERROR expected `,` +LL | Foo { ref x: ref x } => {}, | ^ -error[E0027]: pattern does not mention field `x` - --> $DIR/bind-struct-early-modifiers.rs:4:9 - | -LL | Foo { ref x: ref x } => {}, //~ ERROR expected `,` - | ^^^^^^^^^^^^^^^^^^^^ missing field `x` - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/parser/bound-single-question-mark.stderr b/src/test/ui/parser/bound-single-question-mark.stderr index e30b32f41b413..82937a517b5e9 100644 --- a/src/test/ui/parser/bound-single-question-mark.stderr +++ b/src/test/ui/parser/bound-single-question-mark.stderr @@ -1,7 +1,7 @@ error: expected identifier, found `>` --> $DIR/bound-single-question-mark.rs:1:10 | -LL | fn f() {} //~ ERROR expected identifier, found `>` +LL | fn f() {} | ^ expected identifier error: aborting due to previous error diff --git a/src/test/ui/parser/bounds-lifetime-1.stderr b/src/test/ui/parser/bounds-lifetime-1.stderr index 33bba35f692dd..17d65314d9625 100644 --- a/src/test/ui/parser/bounds-lifetime-1.stderr +++ b/src/test/ui/parser/bounds-lifetime-1.stderr @@ -1,7 +1,7 @@ error: expected one of `,`, `:`, or `>`, found `'b` --> $DIR/bounds-lifetime-1.rs:1:17 | -LL | type A = for<'a 'b> fn(); //~ ERROR expected one of `,`, `:`, or `>`, found `'b` +LL | type A = for<'a 'b> fn(); | ^^ expected one of `,`, `:`, or `>` here error: aborting due to previous error diff --git a/src/test/ui/parser/bounds-lifetime-2.stderr b/src/test/ui/parser/bounds-lifetime-2.stderr index a8a22aaafce33..587e527f0a85b 100644 --- a/src/test/ui/parser/bounds-lifetime-2.stderr +++ b/src/test/ui/parser/bounds-lifetime-2.stderr @@ -1,7 +1,7 @@ error: expected one of `,`, `:`, or `>`, found `+` --> $DIR/bounds-lifetime-2.rs:1:17 | -LL | type A = for<'a + 'b> fn(); //~ ERROR expected one of `,`, `:`, or `>`, found `+` +LL | type A = for<'a + 'b> fn(); | ^ expected one of `,`, `:`, or `>` here error: aborting due to previous error diff --git a/src/test/ui/parser/bounds-lifetime-where-1.stderr b/src/test/ui/parser/bounds-lifetime-where-1.stderr index 0300fe9891016..b6bd866938bed 100644 --- a/src/test/ui/parser/bounds-lifetime-where-1.stderr +++ b/src/test/ui/parser/bounds-lifetime-where-1.stderr @@ -1,7 +1,7 @@ error: expected `:`, found `;` --> $DIR/bounds-lifetime-where-1.rs:1:16 | -LL | type A where 'a; //~ ERROR expected `:`, found `;` +LL | type A where 'a; | ^ expected `:` error: aborting due to previous error diff --git a/src/test/ui/parser/bounds-lifetime-where.stderr b/src/test/ui/parser/bounds-lifetime-where.stderr index 6a8d7e9d4a165..9507a4598581a 100644 --- a/src/test/ui/parser/bounds-lifetime-where.stderr +++ b/src/test/ui/parser/bounds-lifetime-where.stderr @@ -1,7 +1,7 @@ error: expected one of `=`, lifetime, or type, found `,` --> $DIR/bounds-lifetime-where.rs:8:14 | -LL | type A where , = u8; //~ ERROR expected one of `=`, lifetime, or type, found `,` +LL | type A where , = u8; | ^ expected one of `=`, lifetime, or type here error: aborting due to previous error diff --git a/src/test/ui/parser/bounds-lifetime.stderr b/src/test/ui/parser/bounds-lifetime.stderr index 191ea3ebd070a..facbd2800709d 100644 --- a/src/test/ui/parser/bounds-lifetime.stderr +++ b/src/test/ui/parser/bounds-lifetime.stderr @@ -1,7 +1,7 @@ error: expected one of `>`, `const`, identifier, or lifetime, found `,` --> $DIR/bounds-lifetime.rs:9:14 | -LL | type A = for<,> fn(); //~ ERROR expected one of `>`, `const`, identifier, or lifetime, found `,` +LL | type A = for<,> fn(); | ^ expected one of `>`, `const`, identifier, or lifetime here error: aborting due to previous error diff --git a/src/test/ui/parser/bounds-obj-parens.rs b/src/test/ui/parser/bounds-obj-parens.rs index cc86879bf461a..1e0f9e40cdca6 100644 --- a/src/test/ui/parser/bounds-obj-parens.rs +++ b/src/test/ui/parser/bounds-obj-parens.rs @@ -1,5 +1,7 @@ // compile-pass +#![allow(bare_trait_objects)] + type A = Box<(Fn(u8) -> u8) + 'static + Send + Sync>; // OK (but see #39318) fn main() {} diff --git a/src/test/ui/parser/bounds-type.rs b/src/test/ui/parser/bounds-type.rs index 360e7939c9556..9122cb49ebc1a 100644 --- a/src/test/ui/parser/bounds-type.rs +++ b/src/test/ui/parser/bounds-type.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z parse-only -Z continue-parse-after-error +// compile-flags: -Z parse-only struct S< T: 'a + Tr, // OK diff --git a/src/test/ui/parser/bounds-type.stderr b/src/test/ui/parser/bounds-type.stderr index 046e0ce8c7ab7..0b714e40a1012 100644 --- a/src/test/ui/parser/bounds-type.stderr +++ b/src/test/ui/parser/bounds-type.stderr @@ -1,7 +1,7 @@ error: `?` may only modify trait bounds, not lifetime bounds --> $DIR/bounds-type.rs:10:8 | -LL | T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds +LL | T: ?'a, | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/byte-literals.stderr b/src/test/ui/parser/byte-literals.stderr index ab14eeede663e..58a5797b90776 100644 --- a/src/test/ui/parser/byte-literals.stderr +++ b/src/test/ui/parser/byte-literals.stderr @@ -1,44 +1,44 @@ error: unknown byte escape: f --> $DIR/byte-literals.rs:6:21 | -LL | static FOO: u8 = b'/f'; //~ ERROR unknown byte escape - | ^ +LL | static FOO: u8 = b'\f'; + | ^ unknown byte escape error: unknown byte escape: f --> $DIR/byte-literals.rs:9:8 | -LL | b'/f'; //~ ERROR unknown byte escape - | ^ +LL | b'\f'; + | ^ unknown byte escape error: invalid character in numeric character escape: Z --> $DIR/byte-literals.rs:10:10 | -LL | b'/x0Z'; //~ ERROR invalid character in numeric character escape: Z +LL | b'\x0Z'; | ^ -error: byte constant must be escaped: /t +error: byte constant must be escaped: \t --> $DIR/byte-literals.rs:11:7 | -LL | b' '; //~ ERROR byte constant must be escaped +LL | b' '; | ^^^^ error: byte constant must be escaped: ' --> $DIR/byte-literals.rs:12:7 | -LL | b'''; //~ ERROR byte constant must be escaped +LL | b'''; | ^ -error: byte constant must be ASCII. Use a /xHH escape for a non-ASCII byte +error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte --> $DIR/byte-literals.rs:13:7 | -LL | b'é'; //~ ERROR byte constant must be ASCII +LL | b'é'; | ^ -error: unterminated byte constant: b'a - --> $DIR/byte-literals.rs:14:5 +error: unterminated byte constant + --> $DIR/byte-literals.rs:14:6 | -LL | b'a //~ ERROR unterminated byte constant - | ^^^ +LL | b'a + | ^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/parser/byte-string-literals.rs b/src/test/ui/parser/byte-string-literals.rs index d028f28655b8e..8d8ee4da98717 100644 --- a/src/test/ui/parser/byte-string-literals.rs +++ b/src/test/ui/parser/byte-string-literals.rs @@ -1,8 +1,5 @@ // compile-flags: -Z continue-parse-after-error - -// ignore-tidy-tab - static FOO: &'static [u8] = b"\f"; //~ ERROR unknown byte escape pub fn main() { diff --git a/src/test/ui/parser/byte-string-literals.stderr b/src/test/ui/parser/byte-string-literals.stderr index 669f5585cb242..eeb2fcd12320b 100644 --- a/src/test/ui/parser/byte-string-literals.stderr +++ b/src/test/ui/parser/byte-string-literals.stderr @@ -1,32 +1,32 @@ error: unknown byte escape: f - --> $DIR/byte-string-literals.rs:6:32 + --> $DIR/byte-string-literals.rs:3:32 | -LL | static FOO: &'static [u8] = b"/f"; //~ ERROR unknown byte escape - | ^ +LL | static FOO: &'static [u8] = b"\f"; + | ^ unknown byte escape error: unknown byte escape: f - --> $DIR/byte-string-literals.rs:9:8 + --> $DIR/byte-string-literals.rs:6:8 | -LL | b"/f"; //~ ERROR unknown byte escape - | ^ +LL | b"\f"; + | ^ unknown byte escape error: invalid character in numeric character escape: Z - --> $DIR/byte-string-literals.rs:10:10 + --> $DIR/byte-string-literals.rs:7:10 | -LL | b"/x0Z"; //~ ERROR invalid character in numeric character escape: Z +LL | b"\x0Z"; | ^ -error: byte constant must be ASCII. Use a /xHH escape for a non-ASCII byte - --> $DIR/byte-string-literals.rs:11:7 +error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte + --> $DIR/byte-string-literals.rs:8:7 | -LL | b"é"; //~ ERROR byte constant must be ASCII +LL | b"é"; | ^ error: unterminated double quote byte string - --> $DIR/byte-string-literals.rs:12:7 + --> $DIR/byte-string-literals.rs:9:6 | -LL | b"a //~ ERROR unterminated double quote byte string - | _______^ +LL | b"a + | ______^ LL | | } | |__^ diff --git a/src/test/ui/parser/circular_modules_main.stderr b/src/test/ui/parser/circular_modules_main.stderr index 7751a8c0f38a1..33865fb7bca95 100644 --- a/src/test/ui/parser/circular_modules_main.stderr +++ b/src/test/ui/parser/circular_modules_main.stderr @@ -1,7 +1,7 @@ error: circular modules: $DIR/circular_modules_hello.rs -> $DIR/circular_modules_main.rs -> $DIR/circular_modules_hello.rs --> $DIR/circular_modules_main.rs:2:5 | -LL | mod circular_modules_hello; //~ ERROR: circular modules +LL | mod circular_modules_hello; | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/column-offset-1-based.stderr b/src/test/ui/parser/column-offset-1-based.stderr index b12b47b67ce10..5cbf3d3e95965 100644 --- a/src/test/ui/parser/column-offset-1-based.stderr +++ b/src/test/ui/parser/column-offset-1-based.stderr @@ -1,7 +1,7 @@ error: expected `[`, found `` --> $DIR/column-offset-1-based.rs:1:1 | -LL | # //~ ERROR expected `[`, found `` +LL | # | ^ expected `[` error: aborting due to previous error diff --git a/src/test/ui/parser/default.stderr b/src/test/ui/parser/default.stderr index 27193672903ac..ded088acfc42e 100644 --- a/src/test/ui/parser/default.stderr +++ b/src/test/ui/parser/default.stderr @@ -1,13 +1,13 @@ error: expected one of `async`, `const`, `existential`, `extern`, `fn`, `type`, or `unsafe`, found `pub` --> $DIR/default.rs:22:13 | -LL | default pub fn foo() -> T { T::default() } //~ ERROR expected one of +LL | default pub fn foo() -> T { T::default() } | ^^^ expected one of 7 possible tokens here error[E0449]: unnecessary visibility qualifier --> $DIR/default.rs:16:5 | -LL | pub default fn foo() -> T { //~ ERROR unnecessary visibility qualifier +LL | pub default fn foo() -> T { | ^^^ `pub` not permitted here because it's implied error[E0046]: not all trait items implemented, missing: `foo` @@ -16,10 +16,10 @@ error[E0046]: not all trait items implemented, missing: `foo` LL | fn foo() -> T; | -------------------------- `foo` from trait ... -LL | impl Foo for u32 { //~ ERROR not all trait items implemented, missing: `foo` +LL | impl Foo for u32 { | ^^^^^^^^^^^^^^^^ missing `foo` in implementation error: aborting due to 3 previous errors -Some errors occurred: E0046, E0449. +Some errors have detailed explanations: E0046, E0449. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/parser/doc-after-struct-field.rs b/src/test/ui/parser/doc-after-struct-field.rs index 7870555aebb23..5b6f080360336 100644 --- a/src/test/ui/parser/doc-after-struct-field.rs +++ b/src/test/ui/parser/doc-after-struct-field.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - struct X { a: u8 /** document a */, //~^ ERROR found a documentation comment that doesn't document anything diff --git a/src/test/ui/parser/doc-after-struct-field.stderr b/src/test/ui/parser/doc-after-struct-field.stderr index b84f353b8f1a4..e3b32a7f03543 100644 --- a/src/test/ui/parser/doc-after-struct-field.stderr +++ b/src/test/ui/parser/doc-after-struct-field.stderr @@ -1,5 +1,5 @@ error[E0585]: found a documentation comment that doesn't document anything - --> $DIR/doc-after-struct-field.rs:4:11 + --> $DIR/doc-after-struct-field.rs:2:11 | LL | a: u8 /** document a */, | ^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | a: u8 /** document a */, = help: doc comments must come before what they document, maybe a comment was intended with `//`? error[E0585]: found a documentation comment that doesn't document anything - --> $DIR/doc-after-struct-field.rs:10:11 + --> $DIR/doc-after-struct-field.rs:8:11 | LL | a: u8 /// document a | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/parser/doc-before-attr.stderr b/src/test/ui/parser/doc-before-attr.stderr index 0cd6aa81ec5f4..0fae44ce5c806 100644 --- a/src/test/ui/parser/doc-before-attr.stderr +++ b/src/test/ui/parser/doc-before-attr.stderr @@ -1,7 +1,7 @@ error: expected item after attributes --> $DIR/doc-before-attr.rs:4:16 | -LL | #[derive(Debug)] //~ERROR expected item after attributes +LL | #[derive(Debug)] | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/doc-before-eof.stderr b/src/test/ui/parser/doc-before-eof.stderr index 5809d64e80678..82756626765b0 100644 --- a/src/test/ui/parser/doc-before-eof.stderr +++ b/src/test/ui/parser/doc-before-eof.stderr @@ -1,7 +1,7 @@ error: expected item after doc comment --> $DIR/doc-before-eof.rs:3:1 | -LL | /// hi //~ERROR expected item after doc comment +LL | /// hi | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this doc comment doesn't document anything error: aborting due to previous error diff --git a/src/test/ui/parser/doc-before-fn-rbrace.rs b/src/test/ui/parser/doc-before-fn-rbrace.rs index d33520baebe07..eb355136f1e66 100644 --- a/src/test/ui/parser/doc-before-fn-rbrace.rs +++ b/src/test/ui/parser/doc-before-fn-rbrace.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - fn main() { /// document //~^ ERROR found a documentation comment that doesn't document anything diff --git a/src/test/ui/parser/doc-before-fn-rbrace.stderr b/src/test/ui/parser/doc-before-fn-rbrace.stderr index a1ca88cf31487..56241de709247 100644 --- a/src/test/ui/parser/doc-before-fn-rbrace.stderr +++ b/src/test/ui/parser/doc-before-fn-rbrace.stderr @@ -1,5 +1,5 @@ error[E0585]: found a documentation comment that doesn't document anything - --> $DIR/doc-before-fn-rbrace.rs:4:5 + --> $DIR/doc-before-fn-rbrace.rs:2:5 | LL | /// document | ^^^^^^^^^^^^ diff --git a/src/test/ui/parser/doc-before-identifier.rs b/src/test/ui/parser/doc-before-identifier.rs index d9777be63d280..76263ad92885d 100644 --- a/src/test/ui/parser/doc-before-identifier.rs +++ b/src/test/ui/parser/doc-before-identifier.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - fn /// document foo() {} //~^^ ERROR expected identifier, found doc comment `/// document` diff --git a/src/test/ui/parser/doc-before-identifier.stderr b/src/test/ui/parser/doc-before-identifier.stderr index 4bc5e6f65d804..940d293b6786c 100644 --- a/src/test/ui/parser/doc-before-identifier.stderr +++ b/src/test/ui/parser/doc-before-identifier.stderr @@ -1,5 +1,5 @@ error: expected identifier, found doc comment `/// document` - --> $DIR/doc-before-identifier.rs:3:4 + --> $DIR/doc-before-identifier.rs:1:4 | LL | fn /// document | ^^^^^^^^^^^^ expected identifier, found doc comment diff --git a/src/test/ui/parser/doc-before-mod-rbrace.rs b/src/test/ui/parser/doc-before-mod-rbrace.rs index 4e0b65ef496db..c65a0a93184c0 100644 --- a/src/test/ui/parser/doc-before-mod-rbrace.rs +++ b/src/test/ui/parser/doc-before-mod-rbrace.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - mod Foo { /// document //~^ ERROR expected item after doc comment diff --git a/src/test/ui/parser/doc-before-mod-rbrace.stderr b/src/test/ui/parser/doc-before-mod-rbrace.stderr index 4eaf351f676c8..d5749c66cd290 100644 --- a/src/test/ui/parser/doc-before-mod-rbrace.stderr +++ b/src/test/ui/parser/doc-before-mod-rbrace.stderr @@ -1,5 +1,5 @@ error: expected item after doc comment - --> $DIR/doc-before-mod-rbrace.rs:4:5 + --> $DIR/doc-before-mod-rbrace.rs:2:5 | LL | /// document | ^^^^^^^^^^^^ this doc comment doesn't document anything diff --git a/src/test/ui/parser/doc-before-struct-rbrace-1.rs b/src/test/ui/parser/doc-before-struct-rbrace-1.rs index e7055f6a5fcb4..3866a3105c25a 100644 --- a/src/test/ui/parser/doc-before-struct-rbrace-1.rs +++ b/src/test/ui/parser/doc-before-struct-rbrace-1.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - struct X { a: u8, /// document diff --git a/src/test/ui/parser/doc-before-struct-rbrace-1.stderr b/src/test/ui/parser/doc-before-struct-rbrace-1.stderr index f2824f85ca98a..19f90677398ea 100644 --- a/src/test/ui/parser/doc-before-struct-rbrace-1.stderr +++ b/src/test/ui/parser/doc-before-struct-rbrace-1.stderr @@ -1,5 +1,5 @@ error[E0585]: found a documentation comment that doesn't document anything - --> $DIR/doc-before-struct-rbrace-1.rs:5:5 + --> $DIR/doc-before-struct-rbrace-1.rs:3:5 | LL | /// document | ^^^^^^^^^^^^ diff --git a/src/test/ui/parser/doc-before-struct-rbrace-2.rs b/src/test/ui/parser/doc-before-struct-rbrace-2.rs index d5c2a314cbbf8..dda138f1a8835 100644 --- a/src/test/ui/parser/doc-before-struct-rbrace-2.rs +++ b/src/test/ui/parser/doc-before-struct-rbrace-2.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - struct X { a: u8 /// document //~^ ERROR found a documentation comment that doesn't document anything diff --git a/src/test/ui/parser/doc-before-struct-rbrace-2.stderr b/src/test/ui/parser/doc-before-struct-rbrace-2.stderr index ba3e884263ca3..b25ccab79f94a 100644 --- a/src/test/ui/parser/doc-before-struct-rbrace-2.stderr +++ b/src/test/ui/parser/doc-before-struct-rbrace-2.stderr @@ -1,5 +1,5 @@ error[E0585]: found a documentation comment that doesn't document anything - --> $DIR/doc-before-struct-rbrace-2.rs:4:11 + --> $DIR/doc-before-struct-rbrace-2.rs:2:11 | LL | a: u8 /// document | ^^^^^^^^^^^^ diff --git a/src/test/ui/parser/doc-inside-trait-item.rs b/src/test/ui/parser/doc-inside-trait-item.rs new file mode 100644 index 0000000000000..87b501bd2a2df --- /dev/null +++ b/src/test/ui/parser/doc-inside-trait-item.rs @@ -0,0 +1,6 @@ +trait User{ + fn test(); + /// empty doc + //~^ ERROR found a documentation comment that doesn't document anything +} +fn main() {} diff --git a/src/test/ui/parser/doc-inside-trait-item.stderr b/src/test/ui/parser/doc-inside-trait-item.stderr new file mode 100644 index 0000000000000..3287ece9ae644 --- /dev/null +++ b/src/test/ui/parser/doc-inside-trait-item.stderr @@ -0,0 +1,10 @@ +error[E0584]: found a documentation comment that doesn't document anything + --> $DIR/doc-inside-trait-item.rs:3:5 + | +LL | /// empty doc + | ^^^^^^^^^^^^^ + | + = help: doc comments must come before what they document, maybe a comment was intended with `//`? + +error: aborting due to previous error + diff --git a/src/test/ui/parser/empty-impl-semicolon.stderr b/src/test/ui/parser/empty-impl-semicolon.stderr index 965a8a45aedea..46f2393cd832e 100644 --- a/src/test/ui/parser/empty-impl-semicolon.stderr +++ b/src/test/ui/parser/empty-impl-semicolon.stderr @@ -1,7 +1,7 @@ error: expected one of `!`, `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `;` --> $DIR/empty-impl-semicolon.rs:1:9 | -LL | impl Foo; //~ ERROR expected one of `!`, `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `;` +LL | impl Foo; | ^ expected one of 8 possible tokens here error: aborting due to previous error diff --git a/src/test/ui/parser/expr-as-stmt.fixed b/src/test/ui/parser/expr-as-stmt.fixed new file mode 100644 index 0000000000000..1ce6f9c25034f --- /dev/null +++ b/src/test/ui/parser/expr-as-stmt.fixed @@ -0,0 +1,40 @@ +// run-rustfix +#![allow(unused_variables)] +#![allow(dead_code)] +#![allow(unused_must_use)] + +fn foo() -> i32 { + ({2}) + {2} //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types +} + +fn bar() -> i32 { + ({2}) + 2 //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types +} + +fn zul() -> u32 { + let foo = 3; + ({ 42 }) + foo; //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types + 32 +} + +fn baz() -> i32 { + ({ 3 }) * 3 //~ ERROR type `{integer}` cannot be dereferenced + //~^ ERROR mismatched types +} + +fn qux(a: Option, b: Option) -> bool { + (if let Some(x) = a { true } else { false }) + && //~ ERROR expected expression + if let Some(y) = a { true } else { false } +} + +fn moo(x: u32) -> bool { + (match x { + _ => 1, + }) > 0 //~ ERROR expected expression +} + +fn main() {} diff --git a/src/test/ui/parser/expr-as-stmt.rs b/src/test/ui/parser/expr-as-stmt.rs new file mode 100644 index 0000000000000..b526c17488eaf --- /dev/null +++ b/src/test/ui/parser/expr-as-stmt.rs @@ -0,0 +1,40 @@ +// run-rustfix +#![allow(unused_variables)] +#![allow(dead_code)] +#![allow(unused_must_use)] + +fn foo() -> i32 { + {2} + {2} //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types +} + +fn bar() -> i32 { + {2} + 2 //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types +} + +fn zul() -> u32 { + let foo = 3; + { 42 } + foo; //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types + 32 +} + +fn baz() -> i32 { + { 3 } * 3 //~ ERROR type `{integer}` cannot be dereferenced + //~^ ERROR mismatched types +} + +fn qux(a: Option, b: Option) -> bool { + if let Some(x) = a { true } else { false } + && //~ ERROR expected expression + if let Some(y) = a { true } else { false } +} + +fn moo(x: u32) -> bool { + match x { + _ => 1, + } > 0 //~ ERROR expected expression +} + +fn main() {} diff --git a/src/test/ui/parser/expr-as-stmt.stderr b/src/test/ui/parser/expr-as-stmt.stderr new file mode 100644 index 0000000000000..a11209998a7d5 --- /dev/null +++ b/src/test/ui/parser/expr-as-stmt.stderr @@ -0,0 +1,92 @@ +error: expected expression, found `+` + --> $DIR/expr-as-stmt.rs:7:9 + | +LL | {2} + {2} + | --- ^ expected expression + | | + | help: parentheses are required to parse this as an expression: `({2})` + +error: expected expression, found `+` + --> $DIR/expr-as-stmt.rs:12:9 + | +LL | {2} + 2 + | --- ^ expected expression + | | + | help: parentheses are required to parse this as an expression: `({2})` + +error: expected expression, found `+` + --> $DIR/expr-as-stmt.rs:18:12 + | +LL | { 42 } + foo; + | ------ ^ expected expression + | | + | help: parentheses are required to parse this as an expression: `({ 42 })` + +error: expected expression, found `&&` + --> $DIR/expr-as-stmt.rs:30:5 + | +LL | if let Some(x) = a { true } else { false } + | ------------------------------------------ help: parentheses are required to parse this as an expression: `(if let Some(x) = a { true } else { false })` +LL | && + | ^^ expected expression + +error: expected expression, found `>` + --> $DIR/expr-as-stmt.rs:37:7 + | +LL | } > 0 + | ^ expected expression +help: parentheses are required to parse this as an expression + | +LL | (match x { +LL | _ => 1, +LL | }) > 0 + | + +error[E0308]: mismatched types + --> $DIR/expr-as-stmt.rs:7:6 + | +LL | {2} + {2} + | ^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/expr-as-stmt.rs:12:6 + | +LL | {2} + 2 + | ^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/expr-as-stmt.rs:18:7 + | +LL | { 42 } + foo; + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/expr-as-stmt.rs:24:7 + | +LL | { 3 } * 3 + | ^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error[E0614]: type `{integer}` cannot be dereferenced + --> $DIR/expr-as-stmt.rs:24:11 + | +LL | { 3 } * 3 + | ----- ^^^ + | | + | help: parentheses are required to parse this as an expression: `({ 3 })` + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0308, E0614. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/extern-crate-unexpected-token.stderr b/src/test/ui/parser/extern-crate-unexpected-token.stderr index ed888eb1a8ea8..04edd46936a61 100644 --- a/src/test/ui/parser/extern-crate-unexpected-token.stderr +++ b/src/test/ui/parser/extern-crate-unexpected-token.stderr @@ -1,7 +1,7 @@ error: expected one of `crate`, `fn`, or `{`, found `crte` --> $DIR/extern-crate-unexpected-token.rs:1:8 | -LL | extern crte foo; //~ ERROR expected one of `crate`, `fn`, or `{`, found `crte` +LL | extern crte foo; | ^^^^ expected one of `crate`, `fn`, or `{` here error: aborting due to previous error diff --git a/src/test/ui/parser/extern-expected-fn-or-brace.stderr b/src/test/ui/parser/extern-expected-fn-or-brace.stderr index 94b2d1d7b7e86..0fb993553417d 100644 --- a/src/test/ui/parser/extern-expected-fn-or-brace.stderr +++ b/src/test/ui/parser/extern-expected-fn-or-brace.stderr @@ -1,7 +1,7 @@ error: expected one of `fn` or `{`, found `mod` --> $DIR/extern-expected-fn-or-brace.rs:4:12 | -LL | extern "C" mod foo; //~ERROR expected one of `fn` or `{`, found `mod` +LL | extern "C" mod foo; | ^^^ expected one of `fn` or `{` here error: aborting due to previous error diff --git a/src/test/ui/parser/extern-foreign-crate.stderr b/src/test/ui/parser/extern-foreign-crate.stderr index d2fe8b77ce668..de9f0c932327d 100644 --- a/src/test/ui/parser/extern-foreign-crate.stderr +++ b/src/test/ui/parser/extern-foreign-crate.stderr @@ -1,7 +1,7 @@ error: expected one of `;` or `as`, found `{` --> $DIR/extern-foreign-crate.rs:4:18 | -LL | extern crate foo {} //~ERROR expected one of `;` or `as`, found `{` +LL | extern crate foo {} | ^ expected one of `;` or `as` here error: aborting due to previous error diff --git a/src/test/ui/parser/extern-no-fn.stderr b/src/test/ui/parser/extern-no-fn.stderr index e764cd0840196..d2d5e3c46874a 100644 --- a/src/test/ui/parser/extern-no-fn.stderr +++ b/src/test/ui/parser/extern-no-fn.stderr @@ -1,7 +1,7 @@ error: missing `fn`, `type`, or `static` for extern-item declaration --> $DIR/extern-no-fn.rs:1:9 | -LL | extern { //~ ERROR missing `fn`, `type`, or `static` for extern-item declaration +LL | extern { | _________^ LL | | f(); | |____^ missing `fn`, `type`, or `static` diff --git a/src/test/ui/parser/fn-arg-doc-comment.rs b/src/test/ui/parser/fn-arg-doc-comment.rs index 22af94b628452..4a4f959e21353 100644 --- a/src/test/ui/parser/fn-arg-doc-comment.rs +++ b/src/test/ui/parser/fn-arg-doc-comment.rs @@ -1,20 +1,20 @@ pub fn f( /// Comment - //~^ ERROR documentation comments cannot be applied to method arguments + //~^ ERROR documentation comments cannot be applied to function parameters //~| NOTE doc comments are not allowed here + //~| ERROR attributes on function parameters are unstable + //~| NOTE https://github.com/rust-lang/rust/issues/60406 id: u8, /// Other - //~^ ERROR documentation comments cannot be applied to method arguments + //~^ ERROR documentation comments cannot be applied to function parameters //~| NOTE doc comments are not allowed here + //~| ERROR attributes on function parameters are unstable + //~| NOTE https://github.com/rust-lang/rust/issues/60406 a: u8, ) {} -fn foo(#[allow(dead_code)] id: i32) {} -//~^ ERROR attributes cannot be applied to method arguments -//~| NOTE attributes are not allowed here - fn bar(id: #[allow(dead_code)] i32) {} -//~^ ERROR attributes cannot be applied to a method argument's type +//~^ ERROR attributes cannot be applied to a function parameter's type //~| NOTE attributes are not allowed here fn main() { @@ -26,10 +26,6 @@ fn main() { //~| ERROR mismatched types //~| NOTE expected u8, found reference //~| NOTE expected - foo(""); - //~^ ERROR mismatched types - //~| NOTE expected i32, found reference - //~| NOTE expected bar(""); //~^ ERROR mismatched types //~| NOTE expected i32, found reference diff --git a/src/test/ui/parser/fn-arg-doc-comment.stderr b/src/test/ui/parser/fn-arg-doc-comment.stderr index 73a24eebb3f12..9058e88d1d7b7 100644 --- a/src/test/ui/parser/fn-arg-doc-comment.stderr +++ b/src/test/ui/parser/fn-arg-doc-comment.stderr @@ -1,26 +1,38 @@ -error: documentation comments cannot be applied to method arguments +error: attributes cannot be applied to a function parameter's type + --> $DIR/fn-arg-doc-comment.rs:16:12 + | +LL | fn bar(id: #[allow(dead_code)] i32) {} + | ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here + +error: documentation comments cannot be applied to function parameters --> $DIR/fn-arg-doc-comment.rs:2:5 | LL | /// Comment | ^^^^^^^^^^^ doc comments are not allowed here -error: documentation comments cannot be applied to method arguments - --> $DIR/fn-arg-doc-comment.rs:6:5 +error: documentation comments cannot be applied to function parameters + --> $DIR/fn-arg-doc-comment.rs:8:5 | LL | /// Other | ^^^^^^^^^ doc comments are not allowed here -error: attributes cannot be applied to method arguments - --> $DIR/fn-arg-doc-comment.rs:12:8 +error[E0658]: attributes on function parameters are unstable + --> $DIR/fn-arg-doc-comment.rs:2:5 + | +LL | /// Comment + | ^^^^^^^^^^^ | -LL | fn foo(#[allow(dead_code)] id: i32) {} - | ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here + = note: for more information, see https://github.com/rust-lang/rust/issues/60406 + = help: add #![feature(param_attrs)] to the crate attributes to enable -error: attributes cannot be applied to a method argument's type - --> $DIR/fn-arg-doc-comment.rs:16:12 +error[E0658]: attributes on function parameters are unstable + --> $DIR/fn-arg-doc-comment.rs:8:5 | -LL | fn bar(id: #[allow(dead_code)] i32) {} - | ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here +LL | /// Other + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/60406 + = help: add #![feature(param_attrs)] to the crate attributes to enable error[E0308]: mismatched types --> $DIR/fn-arg-doc-comment.rs:22:7 @@ -43,15 +55,6 @@ LL | f("", ""); error[E0308]: mismatched types --> $DIR/fn-arg-doc-comment.rs:29:9 | -LL | foo(""); - | ^^ expected i32, found reference - | - = note: expected type `i32` - found type `&'static str` - -error[E0308]: mismatched types - --> $DIR/fn-arg-doc-comment.rs:33:9 - | LL | bar(""); | ^^ expected i32, found reference | @@ -60,4 +63,5 @@ LL | bar(""); error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/if-in-in.stderr b/src/test/ui/parser/if-in-in.stderr index 2938bba77d717..1adb4429ec7d0 100644 --- a/src/test/ui/parser/if-in-in.stderr +++ b/src/test/ui/parser/if-in-in.stderr @@ -1,13 +1,10 @@ error: expected iterable, found keyword `in` --> $DIR/if-in-in.rs:2:14 | -LL | for i in in 1..2 { //~ ERROR expected iterable, found keyword `in` +LL | for i in in 1..2 { | ---^^ | | | help: remove the duplicated `in` - | - = note: if you meant to use emplacement syntax, it is obsolete (for now, anyway) - = note: for more information on the status of emplacement syntax, see error: aborting due to previous error diff --git a/src/test/ui/parser/impl-parsing.stderr b/src/test/ui/parser/impl-parsing.stderr index 353f5e21ee641..935e93963e1e6 100644 --- a/src/test/ui/parser/impl-parsing.stderr +++ b/src/test/ui/parser/impl-parsing.stderr @@ -1,31 +1,31 @@ error: missing `for` in a trait impl --> $DIR/impl-parsing.rs:6:11 | -LL | impl Trait Type {} //~ ERROR missing `for` in a trait impl +LL | impl Trait Type {} | ^ help: add `for` here error: missing `for` in a trait impl --> $DIR/impl-parsing.rs:7:11 | -LL | impl Trait .. {} //~ ERROR missing `for` in a trait impl +LL | impl Trait .. {} | ^ help: add `for` here error: expected a trait, found type --> $DIR/impl-parsing.rs:8:6 | -LL | impl ?Sized for Type {} //~ ERROR expected a trait, found type +LL | impl ?Sized for Type {} | ^^^^^^ error: expected a trait, found type --> $DIR/impl-parsing.rs:9:6 | -LL | impl ?Sized for .. {} //~ ERROR expected a trait, found type +LL | impl ?Sized for .. {} | ^^^^^^ error: expected `impl`, found `FAIL` --> $DIR/impl-parsing.rs:11:16 | -LL | default unsafe FAIL //~ ERROR expected `impl`, found `FAIL` +LL | default unsafe FAIL | ^^^^ expected `impl` here error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/inner-attr.stderr b/src/test/ui/parser/inner-attr.stderr index 001eab226dc21..11a37bc139b3c 100644 --- a/src/test/ui/parser/inner-attr.stderr +++ b/src/test/ui/parser/inner-attr.stderr @@ -1,7 +1,7 @@ error: an inner attribute is not permitted following an outer attribute --> $DIR/inner-attr.rs:3:3 | -LL | #![recursion_limit="100"] //~ ERROR an inner attribute is not permitted following an outer attribute +LL | #![recursion_limit="100"] | ^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. diff --git a/src/test/ui/parser/int-literal-too-large-span.rs b/src/test/ui/parser/int-literal-too-large-span.rs index 206242c3c7fa6..666ca93505976 100644 --- a/src/test/ui/parser/int-literal-too-large-span.rs +++ b/src/test/ui/parser/int-literal-too-large-span.rs @@ -2,6 +2,6 @@ fn main() { 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 - //~^ ERROR int literal is too large + //~^ ERROR integer literal is too large ; // the span shouldn't point to this. } diff --git a/src/test/ui/parser/int-literal-too-large-span.stderr b/src/test/ui/parser/int-literal-too-large-span.stderr index d7774c333c29a..7cae85fc9fe6d 100644 --- a/src/test/ui/parser/int-literal-too-large-span.stderr +++ b/src/test/ui/parser/int-literal-too-large-span.stderr @@ -1,4 +1,4 @@ -error: int literal is too large +error: integer literal is too large --> $DIR/int-literal-too-large-span.rs:4:5 | LL | 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 diff --git a/src/test/ui/parser/inverted-parameters.rs b/src/test/ui/parser/inverted-parameters.rs index 42430278c7267..f06b951041731 100644 --- a/src/test/ui/parser/inverted-parameters.rs +++ b/src/test/ui/parser/inverted-parameters.rs @@ -20,6 +20,8 @@ fn pattern((i32, i32) (a, b)) {} fn fizz(i32) {} //~^ ERROR expected one of `:` or `@` +//~| HELP if this was a parameter name, give it a type +//~| HELP if this is a type, explicitly ignore the parameter name fn missing_colon(quux S) {} //~^ ERROR expected one of `:` or `@` diff --git a/src/test/ui/parser/inverted-parameters.stderr b/src/test/ui/parser/inverted-parameters.stderr index bdb8faa6c6593..fb48bd1fe9383 100644 --- a/src/test/ui/parser/inverted-parameters.stderr +++ b/src/test/ui/parser/inverted-parameters.stderr @@ -33,9 +33,19 @@ error: expected one of `:` or `@`, found `)` | LL | fn fizz(i32) {} | ^ expected one of `:` or `@` here + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this was a parameter name, give it a type + | +LL | fn fizz(i32: TypeName) {} + | ^^^^^^^^^^^^^ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn fizz(_: i32) {} + | ^^^^^^ error: expected one of `:` or `@`, found `S` - --> $DIR/inverted-parameters.rs:24:23 + --> $DIR/inverted-parameters.rs:26:23 | LL | fn missing_colon(quux S) {} | -----^ diff --git a/src/test/ui/parser/issue-10392-2.stderr b/src/test/ui/parser/issue-10392-2.stderr index 47e1f7adf25ec..ccc5dd938b5fd 100644 --- a/src/test/ui/parser/issue-10392-2.stderr +++ b/src/test/ui/parser/issue-10392-2.stderr @@ -1,7 +1,7 @@ error: expected `}`, found `,` --> $DIR/issue-10392-2.rs:6:15 | -LL | let A { .., } = a(); //~ ERROR: expected `}` +LL | let A { .., } = a(); | --^ | | | | | expected `}` diff --git a/src/test/ui/parser/issue-10392.rs b/src/test/ui/parser/issue-10392.rs index dd84af393003c..5b0c2fc2be407 100644 --- a/src/test/ui/parser/issue-10392.rs +++ b/src/test/ui/parser/issue-10392.rs @@ -4,5 +4,4 @@ fn a() -> A { panic!() } fn main() { let A { , } = a(); //~ ERROR expected ident - //~| ERROR pattern does not mention field `foo` } diff --git a/src/test/ui/parser/issue-10392.stderr b/src/test/ui/parser/issue-10392.stderr index 9c9858aa26cb4..34991151c1eb6 100644 --- a/src/test/ui/parser/issue-10392.stderr +++ b/src/test/ui/parser/issue-10392.stderr @@ -1,15 +1,8 @@ error: expected identifier, found `,` --> $DIR/issue-10392.rs:6:13 | -LL | let A { , } = a(); //~ ERROR expected ident +LL | let A { , } = a(); | ^ expected identifier -error[E0027]: pattern does not mention field `foo` - --> $DIR/issue-10392.rs:6:9 - | -LL | let A { , } = a(); //~ ERROR expected ident - | ^^^^^^^ missing field `foo` - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/parser/issue-10636-2.stderr b/src/test/ui/parser/issue-10636-2.stderr index 38d57ce572365..5b9a9b7f06c39 100644 --- a/src/test/ui/parser/issue-10636-2.stderr +++ b/src/test/ui/parser/issue-10636-2.stderr @@ -2,9 +2,8 @@ error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;` --> $DIR/issue-10636-2.rs:5:25 | LL | option.map(|some| 42; - | - ^ - | | | - | | help: `)` may belong here + | - ^ help: `)` may belong here + | | | unclosed delimiter error: expected expression, found `)` diff --git a/src/test/ui/parser/issue-14303-enum.stderr b/src/test/ui/parser/issue-14303-enum.stderr index bcecd75b1abba..46f16ea0cc41c 100644 --- a/src/test/ui/parser/issue-14303-enum.stderr +++ b/src/test/ui/parser/issue-14303-enum.stderr @@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters --> $DIR/issue-14303-enum.rs:1:15 | LL | enum X<'a, T, 'b> { - | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>` + | --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-14303-fn-def.stderr b/src/test/ui/parser/issue-14303-fn-def.stderr index 082c37e0be795..8cbab4b9653a0 100644 --- a/src/test/ui/parser/issue-14303-fn-def.stderr +++ b/src/test/ui/parser/issue-14303-fn-def.stderr @@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters --> $DIR/issue-14303-fn-def.rs:1:15 | LL | fn foo<'a, T, 'b>(x: &'a T) {} - | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>` + | --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-14303-impl.stderr b/src/test/ui/parser/issue-14303-impl.stderr index 3b5615d2a9eca..56cd4fb381038 100644 --- a/src/test/ui/parser/issue-14303-impl.stderr +++ b/src/test/ui/parser/issue-14303-impl.stderr @@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters --> $DIR/issue-14303-impl.rs:3:13 | LL | impl<'a, T, 'b> X {} - | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>` + | --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-14303-struct.stderr b/src/test/ui/parser/issue-14303-struct.stderr index dbd0b987dd190..f31cb92ad66ce 100644 --- a/src/test/ui/parser/issue-14303-struct.stderr +++ b/src/test/ui/parser/issue-14303-struct.stderr @@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters --> $DIR/issue-14303-struct.rs:1:17 | LL | struct X<'a, T, 'b> { - | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>` + | --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-14303-trait.stderr b/src/test/ui/parser/issue-14303-trait.stderr index 7dfa62d823fd8..0e7399102bf17 100644 --- a/src/test/ui/parser/issue-14303-trait.stderr +++ b/src/test/ui/parser/issue-14303-trait.stderr @@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters --> $DIR/issue-14303-trait.rs:1:18 | LL | trait Foo<'a, T, 'b> {} - | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>` + | --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-15914.stderr b/src/test/ui/parser/issue-15914.stderr index 3a886c4c481f1..ea26453f80897 100644 --- a/src/test/ui/parser/issue-15914.stderr +++ b/src/test/ui/parser/issue-15914.stderr @@ -1,7 +1,7 @@ error: expected identifier, found `(` --> $DIR/issue-15914.rs:3:9 | -LL | (); //~ ERROR expected identifier, found `(` +LL | (); | ^ expected identifier error: aborting due to previous error diff --git a/src/test/ui/parser/issue-15980.stderr b/src/test/ui/parser/issue-15980.stderr index c91595208c864..879bcb2b4a1f7 100644 --- a/src/test/ui/parser/issue-15980.stderr +++ b/src/test/ui/parser/issue-15980.stderr @@ -3,7 +3,7 @@ error: expected identifier, found keyword `return` | LL | Err(ref e) if e.kind == io::EndOfFile { | ------------- while parsing this struct -LL | //~^ NOTE while parsing this struct +LL | LL | return | ^^^^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers @@ -16,7 +16,7 @@ error: expected one of `.`, `=>`, `?`, or an operator, found `_` | LL | } | - expected one of `.`, `=>`, `?`, or an operator here -LL | //~^ NOTE expected one of `.`, `=>`, `?`, or an operator here +LL | LL | _ => {} | ^ unexpected token diff --git a/src/test/ui/parser/issue-17383.rs b/src/test/ui/parser/issue-17383.rs index 04cd43d0b1071..7bf0e64f2c0a3 100644 --- a/src/test/ui/parser/issue-17383.rs +++ b/src/test/ui/parser/issue-17383.rs @@ -1,6 +1,6 @@ enum X { A = 3, - //~^ ERROR discriminator values can only be used with a field-less enum + //~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants B(usize) } diff --git a/src/test/ui/parser/issue-17383.stderr b/src/test/ui/parser/issue-17383.stderr index 57caa3372a629..486c4055807c9 100644 --- a/src/test/ui/parser/issue-17383.stderr +++ b/src/test/ui/parser/issue-17383.stderr @@ -1,8 +1,15 @@ -error: discriminator values can only be used with a field-less enum +error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants --> $DIR/issue-17383.rs:2:9 | LL | A = 3, - | ^ only valid in field-less enums + | ^ disallowed custom discriminant +LL | +LL | B(usize) + | -------- tuple variant defined here + | + = note: for more information, see https://github.com/rust-lang/rust/issues/60553 + = help: add #![feature(arbitrary_enum_discriminant)] to the crate attributes to enable error: aborting due to previous error +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/parser/issue-17718-const-mut.stderr b/src/test/ui/parser/issue-17718-const-mut.stderr index 19f9fe19ef5ab..8251ce9993fa9 100644 --- a/src/test/ui/parser/issue-17718-const-mut.stderr +++ b/src/test/ui/parser/issue-17718-const-mut.stderr @@ -3,7 +3,7 @@ error: const globals cannot be mutable | LL | const | ----- help: you might want to declare a static instead: `static` -LL | mut //~ ERROR: const globals cannot be mutable +LL | mut | ^^^ cannot be mutable error: aborting due to previous error diff --git a/src/test/ui/parser/issue-17904-2.rs b/src/test/ui/parser/issue-17904-2.rs index d3f32255c31d7..186a955c3135b 100644 --- a/src/test/ui/parser/issue-17904-2.rs +++ b/src/test/ui/parser/issue-17904-2.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - struct Bar { x: T } where T: Copy //~ ERROR expected item, found keyword `where` fn main() {} diff --git a/src/test/ui/parser/issue-17904-2.stderr b/src/test/ui/parser/issue-17904-2.stderr index 8322dc00cade0..9c7fdf6ccb416 100644 --- a/src/test/ui/parser/issue-17904-2.stderr +++ b/src/test/ui/parser/issue-17904-2.stderr @@ -1,7 +1,7 @@ error: expected item, found keyword `where` - --> $DIR/issue-17904-2.rs:3:24 + --> $DIR/issue-17904-2.rs:1:24 | -LL | struct Bar { x: T } where T: Copy //~ ERROR expected item, found keyword `where` +LL | struct Bar { x: T } where T: Copy | ^^^^^ expected item error: aborting due to previous error diff --git a/src/test/ui/parser/issue-17904.rs b/src/test/ui/parser/issue-17904.rs index 6112623041a7d..7d6a54f4be12e 100644 --- a/src/test/ui/parser/issue-17904.rs +++ b/src/test/ui/parser/issue-17904.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - struct Baz where U: Eq(U); //This is parsed as the new Fn* style parenthesis syntax. struct Baz where U: Eq(U) -> R; // Notice this parses as well. struct Baz(U) where U: Eq; // This rightfully signals no error as well. diff --git a/src/test/ui/parser/issue-17904.stderr b/src/test/ui/parser/issue-17904.stderr index f2f0b411e9ada..38f30099ed59c 100644 --- a/src/test/ui/parser/issue-17904.stderr +++ b/src/test/ui/parser/issue-17904.stderr @@ -1,7 +1,7 @@ error: expected one of `:`, `==`, or `=`, found `;` - --> $DIR/issue-17904.rs:6:33 + --> $DIR/issue-17904.rs:4:33 | -LL | struct Foo where T: Copy, (T); //~ ERROR expected one of `:`, `==`, or `=`, found `;` +LL | struct Foo where T: Copy, (T); | ^ expected one of `:`, `==`, or `=` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-19096.stderr b/src/test/ui/parser/issue-19096.stderr index f92604d0067c3..6aa97add7b0f4 100644 --- a/src/test/ui/parser/issue-19096.stderr +++ b/src/test/ui/parser/issue-19096.stderr @@ -1,7 +1,7 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `::` --> $DIR/issue-19096.rs:3:8 | -LL | t.0::; //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `::` +LL | t.0::; | ^^ expected one of `.`, `;`, `?`, `}`, or an operator here error[E0308]: mismatched types @@ -10,7 +10,7 @@ error[E0308]: mismatched types LL | fn main() { | - expected `()` because of default return type LL | let t = (42, 42); -LL | t.0::; //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `::` +LL | t.0::; | ^^^ expected (), found integer | = note: expected type `()` diff --git a/src/test/ui/parser/issue-19398.stderr b/src/test/ui/parser/issue-19398.stderr index 627b74ff8f7bd..d5f1f972d553d 100644 --- a/src/test/ui/parser/issue-19398.stderr +++ b/src/test/ui/parser/issue-19398.stderr @@ -1,7 +1,7 @@ error: expected `fn`, found `unsafe` --> $DIR/issue-19398.rs:2:19 | -LL | extern "Rust" unsafe fn foo(); //~ ERROR expected `fn`, found `unsafe` +LL | extern "Rust" unsafe fn foo(); | ^^^^^^ expected `fn` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-20711-2.stderr b/src/test/ui/parser/issue-20711-2.stderr index e06eb7a9846e1..f67dfa09aca8b 100644 --- a/src/test/ui/parser/issue-20711-2.stderr +++ b/src/test/ui/parser/issue-20711-2.stderr @@ -3,7 +3,7 @@ error: expected one of `async`, `const`, `crate`, `default`, `existential`, `ext | LL | #[stable(feature = "rust1", since = "1.0.0")] | - expected one of 10 possible tokens here -LL | } //~ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, or +LL | } | ^ unexpected token error: aborting due to previous error diff --git a/src/test/ui/parser/issue-20711.stderr b/src/test/ui/parser/issue-20711.stderr index 6cf39608fcc9b..26b819fa2984f 100644 --- a/src/test/ui/parser/issue-20711.stderr +++ b/src/test/ui/parser/issue-20711.stderr @@ -3,7 +3,7 @@ error: expected one of `async`, `const`, `crate`, `default`, `existential`, `ext | LL | #[stable(feature = "rust1", since = "1.0.0")] | - expected one of 10 possible tokens here -LL | } //~ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, or +LL | } | ^ unexpected token error: aborting due to previous error diff --git a/src/test/ui/parser/issue-21153.stderr b/src/test/ui/parser/issue-21153.stderr index 1e0244c2e1d32..70f55f0aeb9ff 100644 --- a/src/test/ui/parser/issue-21153.stderr +++ b/src/test/ui/parser/issue-21153.stderr @@ -1,7 +1,7 @@ error: missing `fn`, `type`, or `const` for trait-item declaration --> $DIR/issue-21153.rs:1:29 | -LL | trait MyTrait: Iterator { //~ ERROR missing `fn`, `type`, or `const` +LL | trait MyTrait: Iterator { | _____________________________^ LL | | Item = T; | |____^ missing `fn`, `type`, or `const` diff --git a/src/test/ui/parser/issue-22647.stderr b/src/test/ui/parser/issue-22647.stderr index 8935ea9c6c125..2dc56a5eca3a6 100644 --- a/src/test/ui/parser/issue-22647.stderr +++ b/src/test/ui/parser/issue-22647.stderr @@ -1,7 +1,7 @@ error: expected one of `:`, `;`, `=`, or `@`, found `<` --> $DIR/issue-22647.rs:2:15 | -LL | let caller = |f: F| //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` +LL | let caller = |f: F| | ^ expected one of `:`, `;`, `=`, or `@` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-22712.stderr b/src/test/ui/parser/issue-22712.stderr index 3a4fa9a5e7ba7..167eaf962e0f4 100644 --- a/src/test/ui/parser/issue-22712.stderr +++ b/src/test/ui/parser/issue-22712.stderr @@ -1,7 +1,7 @@ error: expected one of `:`, `;`, `=`, or `@`, found `<` --> $DIR/issue-22712.rs:6:12 | -LL | let Foo> //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` +LL | let Foo> | ^ expected one of `:`, `;`, `=`, or `@` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-2354-1.stderr b/src/test/ui/parser/issue-2354-1.stderr index da25aac486e35..7c083751228b6 100644 --- a/src/test/ui/parser/issue-2354-1.stderr +++ b/src/test/ui/parser/issue-2354-1.stderr @@ -1,7 +1,7 @@ error: unexpected close delimiter: `}` --> $DIR/issue-2354-1.rs:1:24 | -LL | static foo: isize = 2; } //~ ERROR unexpected close delimiter: +LL | static foo: isize = 2; } | ^ unexpected close delimiter error: aborting due to previous error diff --git a/src/test/ui/parser/issue-2354.stderr b/src/test/ui/parser/issue-2354.stderr index 0f4cd5724ce1e..7098da738b8df 100644 --- a/src/test/ui/parser/issue-2354.stderr +++ b/src/test/ui/parser/issue-2354.stderr @@ -1,7 +1,7 @@ error: this file contains an un-closed delimiter --> $DIR/issue-2354.rs:15:66 | -LL | fn foo() { //~ NOTE un-closed delimiter +LL | fn foo() { | - un-closed delimiter LL | match Some(10) { | - this delimiter might not be properly closed... @@ -9,7 +9,7 @@ LL | match Some(10) { LL | } | - ...as it matches this but it has different indentation ... -LL | //~ ERROR this file contains an un-closed delimiter +LL | | ^ error[E0601]: `main` function not found in crate `issue_2354` @@ -18,7 +18,7 @@ error[E0601]: `main` function not found in crate `issue_2354` note: here is a function named 'main' --> $DIR/issue-2354.rs:14:1 | -LL | fn main() {} //~ NOTE here is a function named 'main' +LL | fn main() {} | ^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/issue-23620-invalid-escapes.rs b/src/test/ui/parser/issue-23620-invalid-escapes.rs index b4b8f1fc0b0ab..53629973a1b5f 100644 --- a/src/test/ui/parser/issue-23620-invalid-escapes.rs +++ b/src/test/ui/parser/issue-23620-invalid-escapes.rs @@ -9,32 +9,27 @@ fn main() { let _ = b'\u'; //~^ ERROR incorrect unicode escape sequence - //~^^ ERROR unicode escape sequences cannot be used as a byte or in a byte string let _ = b'\x5'; //~^ ERROR numeric character escape is too short let _ = b'\xxy'; //~^ ERROR invalid character in numeric character escape: x - //~^^ ERROR invalid character in numeric character escape: y let _ = '\x5'; //~^ ERROR numeric character escape is too short let _ = '\xxy'; //~^ ERROR invalid character in numeric character escape: x - //~^^ ERROR invalid character in numeric character escape: y let _ = b"\u{a4a4} \xf \u"; //~^ ERROR unicode escape sequences cannot be used as a byte or in a byte string //~^^ ERROR invalid character in numeric character escape: //~^^^ ERROR incorrect unicode escape sequence - //~^^^^ ERROR unicode escape sequences cannot be used as a byte or in a byte string let _ = "\xf \u"; //~^ ERROR invalid character in numeric character escape: - //~^^ ERROR form of character escape may only be used with characters in the range [\x00-\x7f] - //~^^^ ERROR incorrect unicode escape sequence + //~^^ ERROR incorrect unicode escape sequence let _ = "\u8f"; //~^ ERROR incorrect unicode escape sequence diff --git a/src/test/ui/parser/issue-23620-invalid-escapes.stderr b/src/test/ui/parser/issue-23620-invalid-escapes.stderr index f6e476ab0cd1d..5fabc1d7e4326 100644 --- a/src/test/ui/parser/issue-23620-invalid-escapes.stderr +++ b/src/test/ui/parser/issue-23620-invalid-escapes.stderr @@ -1,130 +1,88 @@ error: unicode escape sequences cannot be used as a byte or in a byte string --> $DIR/issue-23620-invalid-escapes.rs:4:15 | -LL | let _ = b"/u{a66e}"; +LL | let _ = b"\u{a66e}"; | ^^^^^^^^ error: unicode escape sequences cannot be used as a byte or in a byte string --> $DIR/issue-23620-invalid-escapes.rs:7:15 | -LL | let _ = b'/u{a66e}'; +LL | let _ = b'\u{a66e}'; | ^^^^^^^^ error: incorrect unicode escape sequence --> $DIR/issue-23620-invalid-escapes.rs:10:15 | -LL | let _ = b'/u'; - | ^^ +LL | let _ = b'\u'; + | ^^ incorrect unicode escape sequence | -help: format of unicode escape sequences is `/u{...}` - --> $DIR/issue-23620-invalid-escapes.rs:10:15 - | -LL | let _ = b'/u'; - | ^^ - -error: unicode escape sequences cannot be used as a byte or in a byte string - --> $DIR/issue-23620-invalid-escapes.rs:10:15 - | -LL | let _ = b'/u'; - | ^^ + = help: format of unicode escape sequences is `\u{...}` error: numeric character escape is too short - --> $DIR/issue-23620-invalid-escapes.rs:14:17 + --> $DIR/issue-23620-invalid-escapes.rs:13:15 | -LL | let _ = b'/x5'; - | ^ +LL | let _ = b'\x5'; + | ^^^ error: invalid character in numeric character escape: x - --> $DIR/issue-23620-invalid-escapes.rs:17:17 + --> $DIR/issue-23620-invalid-escapes.rs:16:17 | -LL | let _ = b'/xxy'; +LL | let _ = b'\xxy'; | ^ -error: invalid character in numeric character escape: y - --> $DIR/issue-23620-invalid-escapes.rs:17:18 - | -LL | let _ = b'/xxy'; - | ^ - error: numeric character escape is too short - --> $DIR/issue-23620-invalid-escapes.rs:21:16 + --> $DIR/issue-23620-invalid-escapes.rs:19:14 | -LL | let _ = '/x5'; - | ^ +LL | let _ = '\x5'; + | ^^^ error: invalid character in numeric character escape: x - --> $DIR/issue-23620-invalid-escapes.rs:24:16 + --> $DIR/issue-23620-invalid-escapes.rs:22:16 | -LL | let _ = '/xxy'; +LL | let _ = '\xxy'; | ^ -error: invalid character in numeric character escape: y - --> $DIR/issue-23620-invalid-escapes.rs:24:17 - | -LL | let _ = '/xxy'; - | ^ - error: unicode escape sequences cannot be used as a byte or in a byte string - --> $DIR/issue-23620-invalid-escapes.rs:28:15 + --> $DIR/issue-23620-invalid-escapes.rs:25:15 | -LL | let _ = b"/u{a4a4} /xf /u"; +LL | let _ = b"\u{a4a4} \xf \u"; | ^^^^^^^^ error: invalid character in numeric character escape: - --> $DIR/issue-23620-invalid-escapes.rs:28:27 + --> $DIR/issue-23620-invalid-escapes.rs:25:27 | -LL | let _ = b"/u{a4a4} /xf /u"; +LL | let _ = b"\u{a4a4} \xf \u"; | ^ error: incorrect unicode escape sequence - --> $DIR/issue-23620-invalid-escapes.rs:28:28 - | -LL | let _ = b"/u{a4a4} /xf /u"; - | ^^ - | -help: format of unicode escape sequences is `/u{...}` - --> $DIR/issue-23620-invalid-escapes.rs:28:28 + --> $DIR/issue-23620-invalid-escapes.rs:25:28 | -LL | let _ = b"/u{a4a4} /xf /u"; - | ^^ - -error: unicode escape sequences cannot be used as a byte or in a byte string - --> $DIR/issue-23620-invalid-escapes.rs:28:28 +LL | let _ = b"\u{a4a4} \xf \u"; + | ^^ incorrect unicode escape sequence | -LL | let _ = b"/u{a4a4} /xf /u"; - | ^^ + = help: format of unicode escape sequences is `\u{...}` error: invalid character in numeric character escape: - --> $DIR/issue-23620-invalid-escapes.rs:34:17 + --> $DIR/issue-23620-invalid-escapes.rs:30:17 | -LL | let _ = "/xf /u"; +LL | let _ = "\xf \u"; | ^ -error: this form of character escape may only be used with characters in the range [/x00-/x7f] - --> $DIR/issue-23620-invalid-escapes.rs:34:16 - | -LL | let _ = "/xf /u"; - | ^^ - error: incorrect unicode escape sequence - --> $DIR/issue-23620-invalid-escapes.rs:34:18 - | -LL | let _ = "/xf /u"; - | ^^ + --> $DIR/issue-23620-invalid-escapes.rs:30:18 | -help: format of unicode escape sequences is `/u{...}` - --> $DIR/issue-23620-invalid-escapes.rs:34:18 +LL | let _ = "\xf \u"; + | ^^ incorrect unicode escape sequence | -LL | let _ = "/xf /u"; - | ^^ + = help: format of unicode escape sequences is `\u{...}` error: incorrect unicode escape sequence - --> $DIR/issue-23620-invalid-escapes.rs:39:14 + --> $DIR/issue-23620-invalid-escapes.rs:34:14 | -LL | let _ = "/u8f"; +LL | let _ = "\u8f"; | ^^-- - | | - | help: format of unicode escape sequences uses braces: `/u{8f}` + | | + | help: format of unicode escape sequences uses braces: `\u{8f}` -error: aborting due to 18 previous errors +error: aborting due to 13 previous errors diff --git a/src/test/ui/parser/issue-24197.stderr b/src/test/ui/parser/issue-24197.stderr index 4e073d8c58aaa..2dfb31432bc99 100644 --- a/src/test/ui/parser/issue-24197.stderr +++ b/src/test/ui/parser/issue-24197.stderr @@ -1,7 +1,7 @@ error: expected one of `:`, `;`, `=`, or `@`, found `[` --> $DIR/issue-24197.rs:2:12 | -LL | let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` +LL | let buf[0] = 0; | ^ expected one of `:`, `;`, `=`, or `@` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-24375.stderr b/src/test/ui/parser/issue-24375.stderr index f773a7df4fedd..e45b08be9ab6a 100644 --- a/src/test/ui/parser/issue-24375.stderr +++ b/src/test/ui/parser/issue-24375.stderr @@ -1,7 +1,7 @@ error: expected one of `=>`, `@`, `if`, or `|`, found `[` --> $DIR/issue-24375.rs:6:12 | -LL | tmp[0] => {} //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `[` +LL | tmp[0] => {} | ^ expected one of `=>`, `@`, `if`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-3036.stderr b/src/test/ui/parser/issue-3036.stderr index eadf5546d8505..18947b8fa401e 100644 --- a/src/test/ui/parser/issue-3036.stderr +++ b/src/test/ui/parser/issue-3036.stderr @@ -3,7 +3,7 @@ error: expected one of `.`, `;`, `?`, or an operator, found `}` | LL | let x = 3 | - expected one of `.`, `;`, `?`, or an operator here -LL | } //~ ERROR: expected one of `.`, `;`, `?`, or an operator, found `}` +LL | } | ^ unexpected token error: aborting due to previous error diff --git a/src/test/ui/parser/issue-32214.rs b/src/test/ui/parser/issue-32214.rs index 7191a3234c083..82f7ce62b9457 100644 --- a/src/test/ui/parser/issue-32214.rs +++ b/src/test/ui/parser/issue-32214.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - trait Trait { type Item; } pub fn test >() {} diff --git a/src/test/ui/parser/issue-32214.stderr b/src/test/ui/parser/issue-32214.stderr index 7022019a22f26..08b230a14f50e 100644 --- a/src/test/ui/parser/issue-32214.stderr +++ b/src/test/ui/parser/issue-32214.stderr @@ -1,5 +1,5 @@ error: associated type bindings must be declared after generic parameters - --> $DIR/issue-32214.rs:5:25 + --> $DIR/issue-32214.rs:3:25 | LL | pub fn test >() {} | -------^^^ diff --git a/src/test/ui/parser/issue-32446.stderr b/src/test/ui/parser/issue-32446.stderr index 07eafdde9071a..b0c18f4ec5a41 100644 --- a/src/test/ui/parser/issue-32446.stderr +++ b/src/test/ui/parser/issue-32446.stderr @@ -1,7 +1,7 @@ error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `...` --> $DIR/issue-32446.rs:4:11 | -LL | trait T { ... } //~ ERROR +LL | trait T { ... } | ^^^ expected one of 7 possible tokens here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-32501.stderr b/src/test/ui/parser/issue-32501.stderr index d74c539abfe54..97efb89593579 100644 --- a/src/test/ui/parser/issue-32501.stderr +++ b/src/test/ui/parser/issue-32501.stderr @@ -1,7 +1,7 @@ error: expected identifier, found reserved identifier `_` --> $DIR/issue-32501.rs:7:13 | -LL | let mut _ = 0; //~ ERROR expected identifier, found reserved identifier `_` +LL | let mut _ = 0; | ^ expected identifier, found reserved identifier error: aborting due to previous error diff --git a/src/test/ui/parser/issue-32505.rs b/src/test/ui/parser/issue-32505.rs index 49e7a2f536f2a..f31c00e5cc3fb 100644 --- a/src/test/ui/parser/issue-32505.rs +++ b/src/test/ui/parser/issue-32505.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - pub fn test() { foo(|_|) //~ ERROR expected expression, found `)` } diff --git a/src/test/ui/parser/issue-32505.stderr b/src/test/ui/parser/issue-32505.stderr index 1ea4c36a5255c..cdd779a93ef91 100644 --- a/src/test/ui/parser/issue-32505.stderr +++ b/src/test/ui/parser/issue-32505.stderr @@ -1,7 +1,7 @@ error: expected expression, found `)` - --> $DIR/issue-32505.rs:4:12 + --> $DIR/issue-32505.rs:2:12 | -LL | foo(|_|) //~ ERROR expected expression, found `)` +LL | foo(|_|) | ^ expected expression error: aborting due to previous error diff --git a/src/test/ui/parser/issue-33418.fixed b/src/test/ui/parser/issue-33418.fixed index df11f2d855ce0..2aaa3b5b1ea50 100644 --- a/src/test/ui/parser/issue-33418.fixed +++ b/src/test/ui/parser/issue-33418.fixed @@ -1,10 +1,15 @@ // run-rustfix -trait Tr {} //~ ERROR negative trait bounds are not supported -trait Tr2: SuperA {} //~ ERROR negative trait bounds are not supported -trait Tr3: SuperB {} //~ ERROR negative trait bounds are not supported +trait Tr {} +//~^ ERROR negative trait bounds are not supported +trait Tr2: SuperA {} +//~^ ERROR negative trait bounds are not supported +trait Tr3: SuperB {} +//~^ ERROR negative trait bounds are not supported trait Tr4: SuperB + SuperD {} +//~^ ERROR negative trait bounds are not supported trait Tr5 {} +//~^ ERROR negative trait bounds are not supported trait SuperA {} trait SuperB {} diff --git a/src/test/ui/parser/issue-33418.rs b/src/test/ui/parser/issue-33418.rs index 5bb5f2afca377..5533152092719 100644 --- a/src/test/ui/parser/issue-33418.rs +++ b/src/test/ui/parser/issue-33418.rs @@ -1,12 +1,17 @@ // run-rustfix -trait Tr: !SuperA {} //~ ERROR negative trait bounds are not supported -trait Tr2: SuperA + !SuperB {} //~ ERROR negative trait bounds are not supported -trait Tr3: !SuperA + SuperB {} //~ ERROR negative trait bounds are not supported -trait Tr4: !SuperA + SuperB //~ ERROR negative trait bounds are not supported +trait Tr: !SuperA {} +//~^ ERROR negative trait bounds are not supported +trait Tr2: SuperA + !SuperB {} +//~^ ERROR negative trait bounds are not supported +trait Tr3: !SuperA + SuperB {} +//~^ ERROR negative trait bounds are not supported +trait Tr4: !SuperA + SuperB + !SuperC + SuperD {} -trait Tr5: !SuperA //~ ERROR negative trait bounds are not supported +//~^ ERROR negative trait bounds are not supported +trait Tr5: !SuperA + !SuperB {} +//~^ ERROR negative trait bounds are not supported trait SuperA {} trait SuperB {} diff --git a/src/test/ui/parser/issue-33418.stderr b/src/test/ui/parser/issue-33418.stderr index bfe44588a5b0b..660d9fd30c82e 100644 --- a/src/test/ui/parser/issue-33418.stderr +++ b/src/test/ui/parser/issue-33418.stderr @@ -1,42 +1,41 @@ error: negative trait bounds are not supported --> $DIR/issue-33418.rs:3:9 | -LL | trait Tr: !SuperA {} //~ ERROR negative trait bounds are not supported - | ^^^^^^^^^ help: remove the trait bound +LL | trait Tr: !SuperA {} + | ^^^^^^^^^ negative trait bounds are not supported + = help: remove the trait bound error: negative trait bounds are not supported - --> $DIR/issue-33418.rs:4:19 + --> $DIR/issue-33418.rs:5:19 | -LL | trait Tr2: SuperA + !SuperB {} //~ ERROR negative trait bounds are not supported - | ---------^^^^^^^^^ - | | - | help: remove the trait bound +LL | trait Tr2: SuperA + !SuperB {} + | ^^^^^^^^^ negative trait bounds are not supported + = help: remove the trait bound error: negative trait bounds are not supported - --> $DIR/issue-33418.rs:5:10 + --> $DIR/issue-33418.rs:7:10 | -LL | trait Tr3: !SuperA + SuperB {} //~ ERROR negative trait bounds are not supported - | ^^^^^^^^^--------- - | | - | help: remove the trait bound +LL | trait Tr3: !SuperA + SuperB {} + | ^^^^^^^^^ negative trait bounds are not supported + = help: remove the trait bound error: negative trait bounds are not supported - --> $DIR/issue-33418.rs:6:10 + --> $DIR/issue-33418.rs:9:10 | -LL | trait Tr4: !SuperA + SuperB //~ ERROR negative trait bounds are not supported - | __________-^^^^^^^^ -LL | | + !SuperC + SuperD {} - | |_____^^^^^^^^^________- help: remove the trait bounds +LL | trait Tr4: !SuperA + SuperB + | ^^^^^^^^^ +LL | + !SuperC + SuperD {} + | ^^^^^^^^^ negative trait bounds are not supported + = help: remove the trait bounds error: negative trait bounds are not supported - --> $DIR/issue-33418.rs:8:10 + --> $DIR/issue-33418.rs:12:10 | -LL | trait Tr5: !SuperA //~ ERROR negative trait bounds are not supported - | __________-^^^^^^^^ -LL | | + !SuperB {} - | | ^^^^^^^^- - | |_____________| - | help: remove the trait bounds +LL | trait Tr5: !SuperA + | ^^^^^^^^^ +LL | + !SuperB {} + | ^^^^^^^^^ negative trait bounds are not supported + = help: remove the trait bounds error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/issue-33455.stderr b/src/test/ui/parser/issue-33455.stderr index 38d00a0ea0b4c..4516c388afcb0 100644 --- a/src/test/ui/parser/issue-33455.stderr +++ b/src/test/ui/parser/issue-33455.stderr @@ -1,7 +1,7 @@ error: expected one of `::`, `;`, or `as`, found `.` --> $DIR/issue-33455.rs:1:8 | -LL | use foo.bar; //~ ERROR expected one of `::`, `;`, or `as`, found `.` +LL | use foo.bar; | ^ expected one of `::`, `;`, or `as` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-41155.stderr b/src/test/ui/parser/issue-41155.stderr index ac75829f2e355..719845e699939 100644 --- a/src/test/ui/parser/issue-41155.stderr +++ b/src/test/ui/parser/issue-41155.stderr @@ -3,7 +3,7 @@ error: expected one of `(`, `async`, `const`, `default`, `existential`, `extern` | LL | pub | - expected one of 9 possible tokens here -LL | } //~ ERROR expected one of +LL | } | ^ unexpected token error: aborting due to previous error diff --git a/src/test/ui/parser/issue-43692.stderr b/src/test/ui/parser/issue-43692.stderr index 780f63a663860..69a54af3d82ed 100644 --- a/src/test/ui/parser/issue-43692.stderr +++ b/src/test/ui/parser/issue-43692.stderr @@ -1,7 +1,7 @@ error: invalid start of unicode escape --> $DIR/issue-43692.rs:2:9 | -LL | '/u{_10FFFF}'; //~ ERROR invalid start of unicode escape +LL | '\u{_10FFFF}'; | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/issue-5544-a.rs b/src/test/ui/parser/issue-5544-a.rs index 303b902c49904..3c239c73b9d70 100644 --- a/src/test/ui/parser/issue-5544-a.rs +++ b/src/test/ui/parser/issue-5544-a.rs @@ -1,4 +1,4 @@ fn main() { let __isize = 340282366920938463463374607431768211456; // 2^128 - //~^ ERROR int literal is too large + //~^ ERROR integer literal is too large } diff --git a/src/test/ui/parser/issue-5544-a.stderr b/src/test/ui/parser/issue-5544-a.stderr index bc48853b380e6..de579c3c134e5 100644 --- a/src/test/ui/parser/issue-5544-a.stderr +++ b/src/test/ui/parser/issue-5544-a.stderr @@ -1,4 +1,4 @@ -error: int literal is too large +error: integer literal is too large --> $DIR/issue-5544-a.rs:2:19 | LL | let __isize = 340282366920938463463374607431768211456; // 2^128 diff --git a/src/test/ui/parser/issue-5544-b.rs b/src/test/ui/parser/issue-5544-b.rs index fa40f15dedb5c..93f2ff271364e 100644 --- a/src/test/ui/parser/issue-5544-b.rs +++ b/src/test/ui/parser/issue-5544-b.rs @@ -1,4 +1,4 @@ fn main() { let __isize = 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ff; - //~^ ERROR int literal is too large + //~^ ERROR integer literal is too large } diff --git a/src/test/ui/parser/issue-5544-b.stderr b/src/test/ui/parser/issue-5544-b.stderr index 3f15c0c0d755c..7df212dedfede 100644 --- a/src/test/ui/parser/issue-5544-b.stderr +++ b/src/test/ui/parser/issue-5544-b.stderr @@ -1,4 +1,4 @@ -error: int literal is too large +error: integer literal is too large --> $DIR/issue-5544-b.rs:2:19 | LL | let __isize = 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ff; diff --git a/src/test/ui/parser/issue-5806.stderr b/src/test/ui/parser/issue-5806.stderr index f9f00f70f0b90..6cf902ca86e79 100644 --- a/src/test/ui/parser/issue-5806.stderr +++ b/src/test/ui/parser/issue-5806.stderr @@ -1,7 +1,7 @@ error: couldn't read $DIR/../parser: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE) --> $DIR/issue-5806.rs:5:5 | -LL | mod foo; //~ ERROR couldn't read +LL | mod foo; | ^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/issue-59418.rs b/src/test/ui/parser/issue-59418.rs new file mode 100644 index 0000000000000..0fa191d4a7ef4 --- /dev/null +++ b/src/test/ui/parser/issue-59418.rs @@ -0,0 +1,18 @@ +struct X(i32,i32,i32); + +fn main() { + let a = X(1, 2, 3); + let b = a.1suffix; + //~^ ERROR suffixes on a tuple index are invalid + println!("{}", b); + let c = (1, 2, 3); + let d = c.1suffix; + //~^ ERROR suffixes on a tuple index are invalid + println!("{}", d); + let s = X { 0suffix: 0, 1: 1, 2: 2 }; + //~^ ERROR suffixes on a tuple index are invalid + match s { + X { 0suffix: _, .. } => {} + //~^ ERROR suffixes on a tuple index are invalid + } +} diff --git a/src/test/ui/parser/issue-59418.stderr b/src/test/ui/parser/issue-59418.stderr new file mode 100644 index 0000000000000..347051e9f921c --- /dev/null +++ b/src/test/ui/parser/issue-59418.stderr @@ -0,0 +1,26 @@ +error: suffixes on a tuple index are invalid + --> $DIR/issue-59418.rs:5:15 + | +LL | let b = a.1suffix; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/issue-59418.rs:9:15 + | +LL | let d = c.1suffix; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/issue-59418.rs:12:17 + | +LL | let s = X { 0suffix: 0, 1: 1, 2: 2 }; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/issue-59418.rs:15:13 + | +LL | X { 0suffix: _, .. } => {} + | ^^^^^^^ invalid suffix `suffix` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/parser/issue-62546.rs b/src/test/ui/parser/issue-62546.rs new file mode 100644 index 0000000000000..75b95e7407302 --- /dev/null +++ b/src/test/ui/parser/issue-62546.rs @@ -0,0 +1,3 @@ +pub t(# +//~^ ERROR missing `fn` or `struct` for function or struct definition +//~ ERROR this file contains an un-closed delimiter diff --git a/src/test/ui/parser/issue-62546.stderr b/src/test/ui/parser/issue-62546.stderr new file mode 100644 index 0000000000000..631aac9550585 --- /dev/null +++ b/src/test/ui/parser/issue-62546.stderr @@ -0,0 +1,17 @@ +error: this file contains an un-closed delimiter + --> $DIR/issue-62546.rs:3:53 + | +LL | pub t(# + | - un-closed delimiter +LL | +LL | + | ^ + +error: missing `fn` or `struct` for function or struct definition + --> $DIR/issue-62546.rs:1:4 + | +LL | pub t(# + | ---^- help: if you meant to call a macro, try: `t!` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/issue-62660.rs b/src/test/ui/parser/issue-62660.rs new file mode 100644 index 0000000000000..33c8a9fa328ca --- /dev/null +++ b/src/test/ui/parser/issue-62660.rs @@ -0,0 +1,11 @@ +// Regression test for issue #62660: if a receiver's type does not +// successfully parse, emit the correct error instead of ICE-ing the compiler. + +struct Foo; + +impl Foo { + pub fn foo(_: i32, self: Box`, found `)` +} + +fn main() {} diff --git a/src/test/ui/parser/issue-62660.stderr b/src/test/ui/parser/issue-62660.stderr new file mode 100644 index 0000000000000..3a8f6797b82fb --- /dev/null +++ b/src/test/ui/parser/issue-62660.stderr @@ -0,0 +1,8 @@ +error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)` + --> $DIR/issue-62660.rs:7:38 + | +LL | pub fn foo(_: i32, self: Box isize { fn f() -> isize {} pub f< +//~^ ERROR missing `fn` or `struct` for function or struct definition +//~| ERROR mismatched types +//~ ERROR this file contains an un-closed delimiter diff --git a/src/test/ui/parser/issue-62881.stderr b/src/test/ui/parser/issue-62881.stderr new file mode 100644 index 0000000000000..85c3575fd9288 --- /dev/null +++ b/src/test/ui/parser/issue-62881.stderr @@ -0,0 +1,29 @@ +error: this file contains an un-closed delimiter + --> $DIR/issue-62881.rs:6:53 + | +LL | fn f() -> isize { fn f() -> isize {} pub f< + | - un-closed delimiter +... +LL | + | ^ + +error: missing `fn` or `struct` for function or struct definition + --> $DIR/issue-62881.rs:3:41 + | +LL | fn f() -> isize { fn f() -> isize {} pub f< + | ^ + +error[E0308]: mismatched types + --> $DIR/issue-62881.rs:3:29 + | +LL | fn f() -> isize { fn f() -> isize {} pub f< + | - ^^^^^ expected isize, found () + | | + | this function's body doesn't return + | + = note: expected type `isize` + found type `()` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/issue-62895.rs b/src/test/ui/parser/issue-62895.rs new file mode 100644 index 0000000000000..53f17405d79f4 --- /dev/null +++ b/src/test/ui/parser/issue-62895.rs @@ -0,0 +1,11 @@ +fn main() {} + +fn v() -> isize { //~ ERROR mismatched types +mod _ { //~ ERROR expected identifier +pub fn g() -> isizee { //~ ERROR cannot find type `isizee` in this scope +mod _ { //~ ERROR expected identifier +pub g() -> is //~ ERROR missing `fn` for function definition +(), w20); +} +(), w20); //~ ERROR expected item, found `;` +} diff --git a/src/test/ui/parser/issue-62895.stderr b/src/test/ui/parser/issue-62895.stderr new file mode 100644 index 0000000000000..882764cb94678 --- /dev/null +++ b/src/test/ui/parser/issue-62895.stderr @@ -0,0 +1,49 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-62895.rs:4:5 + | +LL | mod _ { + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-62895.rs:6:5 + | +LL | mod _ { + | ^ expected identifier, found reserved identifier + +error: missing `fn` for function definition + --> $DIR/issue-62895.rs:7:4 + | +LL | pub g() -> is + | ^^^^ +help: add `fn` here to parse `g` as a public function + | +LL | pub fn g() -> is + | ^^ + +error: expected item, found `;` + --> $DIR/issue-62895.rs:10:9 + | +LL | (), w20); + | ^ help: remove this semicolon + +error[E0412]: cannot find type `isizee` in this scope + --> $DIR/issue-62895.rs:5:15 + | +LL | pub fn g() -> isizee { + | ^^^^^^ help: a primitive type with a similar name exists: `isize` + +error[E0308]: mismatched types + --> $DIR/issue-62895.rs:3:11 + | +LL | fn v() -> isize { + | - ^^^^^ expected isize, found () + | | + | this function's body doesn't return + | + = note: expected type `isize` + found type `()` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0308, E0412. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/issue-6610.stderr b/src/test/ui/parser/issue-6610.stderr index b4760161a62a5..22d93bffeaded 100644 --- a/src/test/ui/parser/issue-6610.stderr +++ b/src/test/ui/parser/issue-6610.stderr @@ -1,7 +1,7 @@ error: expected `;` or `{`, found `}` --> $DIR/issue-6610.rs:1:20 | -LL | trait Foo { fn a() } //~ ERROR expected `;` or `{`, found `}` +LL | trait Foo { fn a() } | ^ expected `;` or `{` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-8537.stderr b/src/test/ui/parser/issue-8537.stderr index 4442cd0ff011c..29a68c9e1c375 100644 --- a/src/test/ui/parser/issue-8537.stderr +++ b/src/test/ui/parser/issue-8537.stderr @@ -1,11 +1,10 @@ error[E0703]: invalid ABI: found `invalid-ab_isize` --> $DIR/issue-8537.rs:2:3 | -LL | "invalid-ab_isize" //~ ERROR invalid ABI +LL | "invalid-ab_isize" | ^^^^^^^^^^^^^^^^^^ invalid ABI | = help: valid ABIs: cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted error: aborting due to previous error -For more information about this error, try `rustc --explain E0703`. diff --git a/src/test/ui/parser/keyword-abstract.stderr b/src/test/ui/parser/keyword-abstract.stderr index 4185ae034b504..2c79598a81b18 100644 --- a/src/test/ui/parser/keyword-abstract.stderr +++ b/src/test/ui/parser/keyword-abstract.stderr @@ -1,7 +1,7 @@ error: expected pattern, found reserved keyword `abstract` --> $DIR/keyword-abstract.rs:2:9 | -LL | let abstract = (); //~ ERROR expected pattern, found reserved keyword `abstract` +LL | let abstract = (); | ^^^^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-as-as-identifier.stderr b/src/test/ui/parser/keyword-as-as-identifier.stderr index 6eaf5e2ed93ee..ef466488ad061 100644 --- a/src/test/ui/parser/keyword-as-as-identifier.stderr +++ b/src/test/ui/parser/keyword-as-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `as` --> $DIR/keyword-as-as-identifier.rs:4:9 | -LL | let as = "foo"; //~ error: expected pattern, found keyword `as` +LL | let as = "foo"; | ^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-box-as-identifier.stderr b/src/test/ui/parser/keyword-box-as-identifier.stderr index 07a134442b8de..8b185948498d8 100644 --- a/src/test/ui/parser/keyword-box-as-identifier.stderr +++ b/src/test/ui/parser/keyword-box-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found `=` --> $DIR/keyword-box-as-identifier.rs:2:13 | -LL | let box = "foo"; //~ error: expected pattern, found `=` +LL | let box = "foo"; | ^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-break-as-identifier.stderr b/src/test/ui/parser/keyword-break-as-identifier.stderr index 69af97374455a..690bd84221a94 100644 --- a/src/test/ui/parser/keyword-break-as-identifier.stderr +++ b/src/test/ui/parser/keyword-break-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `break` --> $DIR/keyword-break-as-identifier.rs:4:9 | -LL | let break = "foo"; //~ error: expected pattern, found keyword `break` +LL | let break = "foo"; | ^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-const-as-identifier.stderr b/src/test/ui/parser/keyword-const-as-identifier.stderr index c727f1754c77e..6da47f88d04e3 100644 --- a/src/test/ui/parser/keyword-const-as-identifier.stderr +++ b/src/test/ui/parser/keyword-const-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `const` --> $DIR/keyword-const-as-identifier.rs:4:9 | -LL | let const = "foo"; //~ error: expected pattern, found keyword `const` +LL | let const = "foo"; | ^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-continue-as-identifier.stderr b/src/test/ui/parser/keyword-continue-as-identifier.stderr index 7fd2761884f79..4b0a659f9ad7e 100644 --- a/src/test/ui/parser/keyword-continue-as-identifier.stderr +++ b/src/test/ui/parser/keyword-continue-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `continue` --> $DIR/keyword-continue-as-identifier.rs:4:9 | -LL | let continue = "foo"; //~ error: expected pattern, found keyword `continue` +LL | let continue = "foo"; | ^^^^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-else-as-identifier.stderr b/src/test/ui/parser/keyword-else-as-identifier.stderr index 6d180bb56da5d..bec7b7ba01e12 100644 --- a/src/test/ui/parser/keyword-else-as-identifier.stderr +++ b/src/test/ui/parser/keyword-else-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `else` --> $DIR/keyword-else-as-identifier.rs:4:9 | -LL | let else = "foo"; //~ error: expected pattern, found keyword `else` +LL | let else = "foo"; | ^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-enum-as-identifier.stderr b/src/test/ui/parser/keyword-enum-as-identifier.stderr index dc7e37824dc68..51a834f797c32 100644 --- a/src/test/ui/parser/keyword-enum-as-identifier.stderr +++ b/src/test/ui/parser/keyword-enum-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `enum` --> $DIR/keyword-enum-as-identifier.rs:4:9 | -LL | let enum = "foo"; //~ error: expected pattern, found keyword `enum` +LL | let enum = "foo"; | ^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-final.stderr b/src/test/ui/parser/keyword-final.stderr index 897624279e5e8..e8372643be6b7 100644 --- a/src/test/ui/parser/keyword-final.stderr +++ b/src/test/ui/parser/keyword-final.stderr @@ -1,7 +1,7 @@ error: expected pattern, found reserved keyword `final` --> $DIR/keyword-final.rs:2:9 | -LL | let final = (); //~ ERROR expected pattern, found reserved keyword `final` +LL | let final = (); | ^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-fn-as-identifier.stderr b/src/test/ui/parser/keyword-fn-as-identifier.stderr index 945fc77c3102f..a071a40a70e0d 100644 --- a/src/test/ui/parser/keyword-fn-as-identifier.stderr +++ b/src/test/ui/parser/keyword-fn-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `fn` --> $DIR/keyword-fn-as-identifier.rs:4:9 | -LL | let fn = "foo"; //~ error: expected pattern, found keyword `fn` +LL | let fn = "foo"; | ^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-for-as-identifier.stderr b/src/test/ui/parser/keyword-for-as-identifier.stderr index 32263e9f6e20e..090046cebdc56 100644 --- a/src/test/ui/parser/keyword-for-as-identifier.stderr +++ b/src/test/ui/parser/keyword-for-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `for` --> $DIR/keyword-for-as-identifier.rs:4:9 | -LL | let for = "foo"; //~ error: expected pattern, found keyword `for` +LL | let for = "foo"; | ^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-if-as-identifier.stderr b/src/test/ui/parser/keyword-if-as-identifier.stderr index 11ba41015cbd2..98bfdb46e9770 100644 --- a/src/test/ui/parser/keyword-if-as-identifier.stderr +++ b/src/test/ui/parser/keyword-if-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `if` --> $DIR/keyword-if-as-identifier.rs:4:9 | -LL | let if = "foo"; //~ error: expected pattern, found keyword `if` +LL | let if = "foo"; | ^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-impl-as-identifier.stderr b/src/test/ui/parser/keyword-impl-as-identifier.stderr index 960a42df429e9..2672959b7c68e 100644 --- a/src/test/ui/parser/keyword-impl-as-identifier.stderr +++ b/src/test/ui/parser/keyword-impl-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `impl` --> $DIR/keyword-impl-as-identifier.rs:4:9 | -LL | let impl = "foo"; //~ error: expected pattern, found keyword `impl` +LL | let impl = "foo"; | ^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-in-as-identifier.stderr b/src/test/ui/parser/keyword-in-as-identifier.stderr index 2300a257a02b5..98332b723f277 100644 --- a/src/test/ui/parser/keyword-in-as-identifier.stderr +++ b/src/test/ui/parser/keyword-in-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `in` --> $DIR/keyword-in-as-identifier.rs:4:9 | -LL | let in = "foo"; //~ error: expected pattern, found keyword `in` +LL | let in = "foo"; | ^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-let-as-identifier.stderr b/src/test/ui/parser/keyword-let-as-identifier.stderr index ed2c8a4eb9c4c..99dbc0530f3fe 100644 --- a/src/test/ui/parser/keyword-let-as-identifier.stderr +++ b/src/test/ui/parser/keyword-let-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `let` --> $DIR/keyword-let-as-identifier.rs:4:9 | -LL | let let = "foo"; //~ error: expected pattern, found keyword `let` +LL | let let = "foo"; | ^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-loop-as-identifier.stderr b/src/test/ui/parser/keyword-loop-as-identifier.stderr index f91cab029533c..783507eb35cd7 100644 --- a/src/test/ui/parser/keyword-loop-as-identifier.stderr +++ b/src/test/ui/parser/keyword-loop-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `loop` --> $DIR/keyword-loop-as-identifier.rs:4:9 | -LL | let loop = "foo"; //~ error: expected pattern, found keyword `loop` +LL | let loop = "foo"; | ^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-match-as-identifier.stderr b/src/test/ui/parser/keyword-match-as-identifier.stderr index 4c8e76695bc8f..e56a115c91636 100644 --- a/src/test/ui/parser/keyword-match-as-identifier.stderr +++ b/src/test/ui/parser/keyword-match-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `match` --> $DIR/keyword-match-as-identifier.rs:4:9 | -LL | let match = "foo"; //~ error: expected pattern, found keyword `match` +LL | let match = "foo"; | ^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-mod-as-identifier.stderr b/src/test/ui/parser/keyword-mod-as-identifier.stderr index 8aeebcebec959..a8be2ceb037d6 100644 --- a/src/test/ui/parser/keyword-mod-as-identifier.stderr +++ b/src/test/ui/parser/keyword-mod-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `mod` --> $DIR/keyword-mod-as-identifier.rs:4:9 | -LL | let mod = "foo"; //~ error: expected pattern, found keyword `mod` +LL | let mod = "foo"; | ^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-move-as-identifier.stderr b/src/test/ui/parser/keyword-move-as-identifier.stderr index 37e06708e25fd..e0687e27eb585 100644 --- a/src/test/ui/parser/keyword-move-as-identifier.stderr +++ b/src/test/ui/parser/keyword-move-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `move` --> $DIR/keyword-move-as-identifier.rs:4:9 | -LL | let move = "foo"; //~ error: expected pattern, found keyword `move` +LL | let move = "foo"; | ^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-mut-as-identifier.stderr b/src/test/ui/parser/keyword-mut-as-identifier.stderr index b0266060903ca..040960835d811 100644 --- a/src/test/ui/parser/keyword-mut-as-identifier.stderr +++ b/src/test/ui/parser/keyword-mut-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected identifier, found `=` --> $DIR/keyword-mut-as-identifier.rs:2:13 | -LL | let mut = "foo"; //~ error: expected identifier, found `=` +LL | let mut = "foo"; | ^ expected identifier error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-override.stderr b/src/test/ui/parser/keyword-override.stderr index 69a6415908c2c..1bfc6c9b3858d 100644 --- a/src/test/ui/parser/keyword-override.stderr +++ b/src/test/ui/parser/keyword-override.stderr @@ -1,7 +1,7 @@ error: expected pattern, found reserved keyword `override` --> $DIR/keyword-override.rs:2:9 | -LL | let override = (); //~ ERROR expected pattern, found reserved keyword `override` +LL | let override = (); | ^^^^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-pub-as-identifier.stderr b/src/test/ui/parser/keyword-pub-as-identifier.stderr index 8b595673ec4cd..526ddcd6ee0ff 100644 --- a/src/test/ui/parser/keyword-pub-as-identifier.stderr +++ b/src/test/ui/parser/keyword-pub-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `pub` --> $DIR/keyword-pub-as-identifier.rs:4:9 | -LL | let pub = "foo"; //~ error: expected pattern, found keyword `pub` +LL | let pub = "foo"; | ^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-ref-as-identifier.stderr b/src/test/ui/parser/keyword-ref-as-identifier.stderr index 656df196f09b1..618043d89ffaa 100644 --- a/src/test/ui/parser/keyword-ref-as-identifier.stderr +++ b/src/test/ui/parser/keyword-ref-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected identifier, found `=` --> $DIR/keyword-ref-as-identifier.rs:2:13 | -LL | let ref = "foo"; //~ error: expected identifier, found `=` +LL | let ref = "foo"; | ^ expected identifier error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-return-as-identifier.stderr b/src/test/ui/parser/keyword-return-as-identifier.stderr index 903137542d6f8..c0156a63fa9d1 100644 --- a/src/test/ui/parser/keyword-return-as-identifier.stderr +++ b/src/test/ui/parser/keyword-return-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `return` --> $DIR/keyword-return-as-identifier.rs:4:9 | -LL | let return = "foo"; //~ error: expected pattern, found keyword `return` +LL | let return = "foo"; | ^^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-static-as-identifier.stderr b/src/test/ui/parser/keyword-static-as-identifier.stderr index 4830e6f1bef40..00a65977732f8 100644 --- a/src/test/ui/parser/keyword-static-as-identifier.stderr +++ b/src/test/ui/parser/keyword-static-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `static` --> $DIR/keyword-static-as-identifier.rs:4:9 | -LL | let static = "foo"; //~ error: expected pattern, found keyword `static` +LL | let static = "foo"; | ^^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-struct-as-identifier.stderr b/src/test/ui/parser/keyword-struct-as-identifier.stderr index 50ac690e425ad..b2d6639e72ecb 100644 --- a/src/test/ui/parser/keyword-struct-as-identifier.stderr +++ b/src/test/ui/parser/keyword-struct-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `struct` --> $DIR/keyword-struct-as-identifier.rs:4:9 | -LL | let struct = "foo"; //~ error: expected pattern, found keyword `struct` +LL | let struct = "foo"; | ^^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-trait-as-identifier.stderr b/src/test/ui/parser/keyword-trait-as-identifier.stderr index 3736f366cbd49..b31c0df28c008 100644 --- a/src/test/ui/parser/keyword-trait-as-identifier.stderr +++ b/src/test/ui/parser/keyword-trait-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `trait` --> $DIR/keyword-trait-as-identifier.rs:4:9 | -LL | let trait = "foo"; //~ error: expected pattern, found keyword `trait` +LL | let trait = "foo"; | ^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr b/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr index 73e8d64b56c1f..c342e3a76fbb4 100644 --- a/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr +++ b/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr @@ -1,7 +1,7 @@ error: expected pattern, found reserved keyword `try` --> $DIR/keyword-try-as-identifier-edition2018.rs:4:9 | -LL | let try = "foo"; //~ error: expected pattern, found reserved keyword `try` +LL | let try = "foo"; | ^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-type-as-identifier.stderr b/src/test/ui/parser/keyword-type-as-identifier.stderr index f7db20034a10d..b749c708d441d 100644 --- a/src/test/ui/parser/keyword-type-as-identifier.stderr +++ b/src/test/ui/parser/keyword-type-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `type` --> $DIR/keyword-type-as-identifier.rs:4:9 | -LL | let type = "foo"; //~ error: expected pattern, found keyword `type` +LL | let type = "foo"; | ^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-typeof.stderr b/src/test/ui/parser/keyword-typeof.stderr index 07c9f883b60fb..e7b18023e61a9 100644 --- a/src/test/ui/parser/keyword-typeof.stderr +++ b/src/test/ui/parser/keyword-typeof.stderr @@ -1,7 +1,7 @@ error: expected pattern, found reserved keyword `typeof` --> $DIR/keyword-typeof.rs:2:9 | -LL | let typeof = (); //~ ERROR expected pattern, found reserved keyword `typeof` +LL | let typeof = (); | ^^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-unsafe-as-identifier.stderr b/src/test/ui/parser/keyword-unsafe-as-identifier.stderr index ddd5e4d7b115f..67935ce43ba04 100644 --- a/src/test/ui/parser/keyword-unsafe-as-identifier.stderr +++ b/src/test/ui/parser/keyword-unsafe-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `unsafe` --> $DIR/keyword-unsafe-as-identifier.rs:4:9 | -LL | let unsafe = "foo"; //~ error: expected pattern, found keyword `unsafe` +LL | let unsafe = "foo"; | ^^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-use-as-identifier.stderr b/src/test/ui/parser/keyword-use-as-identifier.stderr index 7e798a3f0b9d9..2c69d0a8744a0 100644 --- a/src/test/ui/parser/keyword-use-as-identifier.stderr +++ b/src/test/ui/parser/keyword-use-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `use` --> $DIR/keyword-use-as-identifier.rs:4:9 | -LL | let use = "foo"; //~ error: expected pattern, found keyword `use` +LL | let use = "foo"; | ^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-where-as-identifier.stderr b/src/test/ui/parser/keyword-where-as-identifier.stderr index 5285520cc20c4..fc01183ca046b 100644 --- a/src/test/ui/parser/keyword-where-as-identifier.stderr +++ b/src/test/ui/parser/keyword-where-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `where` --> $DIR/keyword-where-as-identifier.rs:4:9 | -LL | let where = "foo"; //~ error: expected pattern, found keyword `where` +LL | let where = "foo"; | ^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-while-as-identifier.stderr b/src/test/ui/parser/keyword-while-as-identifier.stderr index b84a652dc5c81..f72ac87742099 100644 --- a/src/test/ui/parser/keyword-while-as-identifier.stderr +++ b/src/test/ui/parser/keyword-while-as-identifier.stderr @@ -1,7 +1,7 @@ error: expected pattern, found keyword `while` --> $DIR/keyword-while-as-identifier.rs:4:9 | -LL | let while = "foo"; //~ error: expected pattern, found keyword `while` +LL | let while = "foo"; | ^^^^^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/lex-bad-binary-literal.rs b/src/test/ui/parser/lex-bad-binary-literal.rs index da36537f0f307..7df98073e3570 100644 --- a/src/test/ui/parser/lex-bad-binary-literal.rs +++ b/src/test/ui/parser/lex-bad-binary-literal.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - fn main() { 0b121; //~ ERROR invalid digit for a base 2 literal 0b10_10301; //~ ERROR invalid digit for a base 2 literal diff --git a/src/test/ui/parser/lex-bad-binary-literal.stderr b/src/test/ui/parser/lex-bad-binary-literal.stderr index 9750906aaf212..992b3d2487e53 100644 --- a/src/test/ui/parser/lex-bad-binary-literal.stderr +++ b/src/test/ui/parser/lex-bad-binary-literal.stderr @@ -1,55 +1,55 @@ error: invalid digit for a base 2 literal - --> $DIR/lex-bad-binary-literal.rs:4:8 + --> $DIR/lex-bad-binary-literal.rs:2:8 | -LL | 0b121; //~ ERROR invalid digit for a base 2 literal +LL | 0b121; | ^ error: invalid digit for a base 2 literal - --> $DIR/lex-bad-binary-literal.rs:5:12 + --> $DIR/lex-bad-binary-literal.rs:3:12 | -LL | 0b10_10301; //~ ERROR invalid digit for a base 2 literal +LL | 0b10_10301; | ^ error: invalid digit for a base 2 literal - --> $DIR/lex-bad-binary-literal.rs:6:7 + --> $DIR/lex-bad-binary-literal.rs:4:7 | -LL | 0b30; //~ ERROR invalid digit for a base 2 literal +LL | 0b30; | ^ error: invalid digit for a base 2 literal - --> $DIR/lex-bad-binary-literal.rs:7:7 + --> $DIR/lex-bad-binary-literal.rs:5:7 | -LL | 0b41; //~ ERROR invalid digit for a base 2 literal +LL | 0b41; | ^ error: invalid digit for a base 2 literal - --> $DIR/lex-bad-binary-literal.rs:8:7 + --> $DIR/lex-bad-binary-literal.rs:6:7 | -LL | 0b5; //~ ERROR invalid digit for a base 2 literal +LL | 0b5; | ^ error: invalid digit for a base 2 literal - --> $DIR/lex-bad-binary-literal.rs:9:7 + --> $DIR/lex-bad-binary-literal.rs:7:7 | -LL | 0b6; //~ ERROR invalid digit for a base 2 literal +LL | 0b6; | ^ error: invalid digit for a base 2 literal - --> $DIR/lex-bad-binary-literal.rs:10:7 + --> $DIR/lex-bad-binary-literal.rs:8:7 | -LL | 0b7; //~ ERROR invalid digit for a base 2 literal +LL | 0b7; | ^ error: invalid digit for a base 2 literal - --> $DIR/lex-bad-binary-literal.rs:11:7 + --> $DIR/lex-bad-binary-literal.rs:9:7 | -LL | 0b8; //~ ERROR invalid digit for a base 2 literal +LL | 0b8; | ^ error: invalid digit for a base 2 literal - --> $DIR/lex-bad-binary-literal.rs:12:7 + --> $DIR/lex-bad-binary-literal.rs:10:7 | -LL | 0b9; //~ ERROR invalid digit for a base 2 literal +LL | 0b9; | ^ error: aborting due to 9 previous errors diff --git a/src/test/ui/parser/lex-bad-char-literals-1.stderr b/src/test/ui/parser/lex-bad-char-literals-1.stderr index c22bf7d001090..000d155c26833 100644 --- a/src/test/ui/parser/lex-bad-char-literals-1.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-1.stderr @@ -1,26 +1,26 @@ error: numeric character escape is too short - --> $DIR/lex-bad-char-literals-1.rs:3:8 + --> $DIR/lex-bad-char-literals-1.rs:3:6 | -LL | '/x1' //~ ERROR: numeric character escape is too short - | ^ +LL | '\x1' + | ^^^ error: numeric character escape is too short - --> $DIR/lex-bad-char-literals-1.rs:7:8 + --> $DIR/lex-bad-char-literals-1.rs:7:6 | -LL | "/x1" //~ ERROR: numeric character escape is too short - | ^ +LL | "\x1" + | ^^^ -error: unknown character escape: /u{25cf} +error: unknown character escape: \u{25cf} --> $DIR/lex-bad-char-literals-1.rs:11:7 | -LL | '/●' //~ ERROR: unknown character escape - | ^ +LL | '\●' + | ^ unknown character escape -error: unknown character escape: /u{25cf} +error: unknown character escape: \u{25cf} --> $DIR/lex-bad-char-literals-1.rs:15:7 | -LL | "/●" //~ ERROR: unknown character escape - | ^ +LL | "\●" + | ^ unknown character escape error: aborting due to 4 previous errors diff --git a/src/test/ui/parser/lex-bad-char-literals-2.stderr b/src/test/ui/parser/lex-bad-char-literals-2.stderr index 7eadb8ebfe06d..b0a4ed02434b4 100644 --- a/src/test/ui/parser/lex-bad-char-literals-2.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-2.stderr @@ -1,7 +1,11 @@ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-2.rs:3:5 | -LL | 'nope' //~ ERROR: character literal may only contain one codepoint +LL | 'nope' + | ^^^^^^ +help: if you meant to write a `str` literal, use double quotes + | +LL | "nope" | ^^^^^^ error[E0601]: `main` function not found in crate `lex_bad_char_literals_2` diff --git a/src/test/ui/parser/lex-bad-char-literals-4.rs b/src/test/ui/parser/lex-bad-char-literals-4.rs index e13f11f36df48..de0a19df99360 100644 --- a/src/test/ui/parser/lex-bad-char-literals-4.rs +++ b/src/test/ui/parser/lex-bad-char-literals-4.rs @@ -1,5 +1,5 @@ // // This test needs to the last one appearing in this file as it kills the parser static c: char = - '● //~ ERROR: character literal may only contain one codepoint + '● //~ ERROR: unterminated character literal ; diff --git a/src/test/ui/parser/lex-bad-char-literals-4.stderr b/src/test/ui/parser/lex-bad-char-literals-4.stderr index 881e3d5276bb1..8f8f806f6cf61 100644 --- a/src/test/ui/parser/lex-bad-char-literals-4.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-4.stderr @@ -1,8 +1,8 @@ -error: character literal may only contain one codepoint: '● +error: unterminated character literal --> $DIR/lex-bad-char-literals-4.rs:4:5 | -LL | '● //~ ERROR: character literal may only contain one codepoint - | ^^ +LL | '● + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/lex-bad-char-literals-5.stderr b/src/test/ui/parser/lex-bad-char-literals-5.stderr index ef02973310153..97c6338820d73 100644 --- a/src/test/ui/parser/lex-bad-char-literals-5.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-5.stderr @@ -1,21 +1,21 @@ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-5.rs:1:18 | -LL | static c: char = '/x10/x10'; +LL | static c: char = '\x10\x10'; | ^^^^^^^^^^ help: if you meant to write a `str` literal, use double quotes | -LL | static c: char = "/x10/x10"; +LL | static c: char = "\x10\x10"; | ^^^^^^^^^^ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-5.rs:5:20 | -LL | let ch: &str = '/x10/x10'; +LL | let ch: &str = '\x10\x10'; | ^^^^^^^^^^ help: if you meant to write a `str` literal, use double quotes | -LL | let ch: &str = "/x10/x10"; +LL | let ch: &str = "\x10\x10"; | ^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/lex-bad-char-literals-6.stderr b/src/test/ui/parser/lex-bad-char-literals-6.stderr index df99726034878..a7bbe05e94b7b 100644 --- a/src/test/ui/parser/lex-bad-char-literals-6.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-6.stderr @@ -3,18 +3,30 @@ error: character literal may only contain one codepoint | LL | let x: &str = 'ab'; | ^^^^ +help: if you meant to write a `str` literal, use double quotes + | +LL | let x: &str = "ab"; + | ^^^^ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-6.rs:4:19 | LL | let y: char = 'cd'; | ^^^^ +help: if you meant to write a `str` literal, use double quotes + | +LL | let y: char = "cd"; + | ^^^^ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-6.rs:6:13 | LL | let z = 'ef'; | ^^^^ +help: if you meant to write a `str` literal, use double quotes + | +LL | let z = "ef"; + | ^^^^ error[E0277]: can't compare `&str` with `char` --> $DIR/lex-bad-char-literals-6.rs:9:10 @@ -43,5 +55,5 @@ LL | if x == z {} error: aborting due to 6 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/parser/lex-bad-char-literals-7.rs b/src/test/ui/parser/lex-bad-char-literals-7.rs new file mode 100644 index 0000000000000..70eafcb91dacb --- /dev/null +++ b/src/test/ui/parser/lex-bad-char-literals-7.rs @@ -0,0 +1,14 @@ +// compile-flags: -Z continue-parse-after-error +fn main() { + let _: char = ''; + //~^ ERROR: empty character literal + let _: char = '\u{}'; + //~^ ERROR: empty unicode escape (must have at least 1 hex digit) + + // Next two are OK, but may befool error recovery + let _ = '/'; + let _ = b'/'; + + let _ = ' hello // here's a comment + //~^ ERROR: unterminated character literal +} diff --git a/src/test/ui/parser/lex-bad-char-literals-7.stderr b/src/test/ui/parser/lex-bad-char-literals-7.stderr new file mode 100644 index 0000000000000..e1ba3c3ee0f17 --- /dev/null +++ b/src/test/ui/parser/lex-bad-char-literals-7.stderr @@ -0,0 +1,20 @@ +error: empty character literal + --> $DIR/lex-bad-char-literals-7.rs:3:20 + | +LL | let _: char = ''; + | ^ + +error: empty unicode escape (must have at least 1 hex digit) + --> $DIR/lex-bad-char-literals-7.rs:5:20 + | +LL | let _: char = '\u{}'; + | ^^^^ + +error: unterminated character literal + --> $DIR/lex-bad-char-literals-7.rs:12:13 + | +LL | let _ = ' hello // here's a comment + | ^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/lex-bad-numeric-literals.rs b/src/test/ui/parser/lex-bad-numeric-literals.rs index 9496ad305fc2c..cf8440ca488cc 100644 --- a/src/test/ui/parser/lex-bad-numeric-literals.rs +++ b/src/test/ui/parser/lex-bad-numeric-literals.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - fn main() { 0o1.0; //~ ERROR: octal float literal is not supported 0o2f32; //~ ERROR: octal float literal is not supported @@ -13,8 +11,10 @@ fn main() { 0o; //~ ERROR: no valid digits 1e+; //~ ERROR: expected at least one digit in exponent 0x539.0; //~ ERROR: hexadecimal float literal is not supported - 9900000000000000000000000000999999999999999999999999999999; //~ ERROR: int literal is too large - 9900000000000000000000000000999999999999999999999999999999; //~ ERROR: int literal is too large + 9900000000000000000000000000999999999999999999999999999999; + //~^ ERROR: integer literal is too large + 9900000000000000000000000000999999999999999999999999999999; + //~^ ERROR: integer literal is too large 0x; //~ ERROR: no valid digits 0xu32; //~ ERROR: no valid digits 0ou32; //~ ERROR: no valid digits diff --git a/src/test/ui/parser/lex-bad-numeric-literals.stderr b/src/test/ui/parser/lex-bad-numeric-literals.stderr index 1fa23b8b73c9e..84e27f7366d0c 100644 --- a/src/test/ui/parser/lex-bad-numeric-literals.stderr +++ b/src/test/ui/parser/lex-bad-numeric-literals.stderr @@ -1,139 +1,139 @@ error: octal float literal is not supported - --> $DIR/lex-bad-numeric-literals.rs:4:5 + --> $DIR/lex-bad-numeric-literals.rs:2:5 | -LL | 0o1.0; //~ ERROR: octal float literal is not supported +LL | 0o1.0; | ^^^^^ error: octal float literal is not supported - --> $DIR/lex-bad-numeric-literals.rs:6:5 + --> $DIR/lex-bad-numeric-literals.rs:4:5 | -LL | 0o3.0f32; //~ ERROR: octal float literal is not supported +LL | 0o3.0f32; | ^^^^^ error: octal float literal is not supported - --> $DIR/lex-bad-numeric-literals.rs:7:5 + --> $DIR/lex-bad-numeric-literals.rs:5:5 | -LL | 0o4e4; //~ ERROR: octal float literal is not supported +LL | 0o4e4; | ^^^^^ error: octal float literal is not supported - --> $DIR/lex-bad-numeric-literals.rs:8:5 + --> $DIR/lex-bad-numeric-literals.rs:6:5 | -LL | 0o5.0e5; //~ ERROR: octal float literal is not supported +LL | 0o5.0e5; | ^^^^^^^ error: octal float literal is not supported - --> $DIR/lex-bad-numeric-literals.rs:9:5 + --> $DIR/lex-bad-numeric-literals.rs:7:5 | -LL | 0o6e6f32; //~ ERROR: octal float literal is not supported +LL | 0o6e6f32; | ^^^^^ error: octal float literal is not supported - --> $DIR/lex-bad-numeric-literals.rs:10:5 + --> $DIR/lex-bad-numeric-literals.rs:8:5 | -LL | 0o7.0e7f64; //~ ERROR: octal float literal is not supported +LL | 0o7.0e7f64; | ^^^^^^^ error: hexadecimal float literal is not supported - --> $DIR/lex-bad-numeric-literals.rs:11:5 + --> $DIR/lex-bad-numeric-literals.rs:9:5 | -LL | 0x8.0e+9; //~ ERROR: hexadecimal float literal is not supported +LL | 0x8.0e+9; | ^^^^^^^^ error: hexadecimal float literal is not supported - --> $DIR/lex-bad-numeric-literals.rs:12:5 + --> $DIR/lex-bad-numeric-literals.rs:10:5 | -LL | 0x9.0e-9; //~ ERROR: hexadecimal float literal is not supported +LL | 0x9.0e-9; | ^^^^^^^^ error: no valid digits found for number - --> $DIR/lex-bad-numeric-literals.rs:13:5 + --> $DIR/lex-bad-numeric-literals.rs:11:5 | -LL | 0o; //~ ERROR: no valid digits +LL | 0o; | ^^ error: expected at least one digit in exponent - --> $DIR/lex-bad-numeric-literals.rs:14:8 + --> $DIR/lex-bad-numeric-literals.rs:12:8 | -LL | 1e+; //~ ERROR: expected at least one digit in exponent +LL | 1e+; | ^ error: hexadecimal float literal is not supported - --> $DIR/lex-bad-numeric-literals.rs:15:5 + --> $DIR/lex-bad-numeric-literals.rs:13:5 | -LL | 0x539.0; //~ ERROR: hexadecimal float literal is not supported +LL | 0x539.0; | ^^^^^^^ error: no valid digits found for number --> $DIR/lex-bad-numeric-literals.rs:18:5 | -LL | 0x; //~ ERROR: no valid digits +LL | 0x; | ^^ error: no valid digits found for number --> $DIR/lex-bad-numeric-literals.rs:19:5 | -LL | 0xu32; //~ ERROR: no valid digits +LL | 0xu32; | ^^ error: no valid digits found for number --> $DIR/lex-bad-numeric-literals.rs:20:5 | -LL | 0ou32; //~ ERROR: no valid digits +LL | 0ou32; | ^^ error: no valid digits found for number --> $DIR/lex-bad-numeric-literals.rs:21:5 | -LL | 0bu32; //~ ERROR: no valid digits +LL | 0bu32; | ^^ error: no valid digits found for number --> $DIR/lex-bad-numeric-literals.rs:22:5 | -LL | 0b; //~ ERROR: no valid digits +LL | 0b; | ^^ error: octal float literal is not supported --> $DIR/lex-bad-numeric-literals.rs:24:5 | -LL | 0o123.456; //~ ERROR: octal float literal is not supported +LL | 0o123.456; | ^^^^^^^^^ error: binary float literal is not supported --> $DIR/lex-bad-numeric-literals.rs:26:5 | -LL | 0b111.101; //~ ERROR: binary float literal is not supported +LL | 0b111.101; | ^^^^^^^^^ error: octal float literal is not supported - --> $DIR/lex-bad-numeric-literals.rs:5:5 + --> $DIR/lex-bad-numeric-literals.rs:3:5 | -LL | 0o2f32; //~ ERROR: octal float literal is not supported +LL | 0o2f32; | ^^^^^^ not supported -error: int literal is too large - --> $DIR/lex-bad-numeric-literals.rs:16:5 +error: integer literal is too large + --> $DIR/lex-bad-numeric-literals.rs:14:5 | -LL | 9900000000000000000000000000999999999999999999999999999999; //~ ERROR: int literal is too large +LL | 9900000000000000000000000000999999999999999999999999999999; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: int literal is too large - --> $DIR/lex-bad-numeric-literals.rs:17:5 +error: integer literal is too large + --> $DIR/lex-bad-numeric-literals.rs:16:5 | -LL | 9900000000000000000000000000999999999999999999999999999999; //~ ERROR: int literal is too large +LL | 9900000000000000000000000000999999999999999999999999999999; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: octal float literal is not supported --> $DIR/lex-bad-numeric-literals.rs:23:5 | -LL | 0o123f64; //~ ERROR: octal float literal is not supported +LL | 0o123f64; | ^^^^^^^^ not supported error: binary float literal is not supported --> $DIR/lex-bad-numeric-literals.rs:25:5 | -LL | 0b101f64; //~ ERROR: binary float literal is not supported +LL | 0b101f64; | ^^^^^^^^ not supported error: aborting due to 23 previous errors diff --git a/src/test/ui/parser/lex-bad-octal-literal.rs b/src/test/ui/parser/lex-bad-octal-literal.rs index f4cc2c5c420fa..49631f16bdbd7 100644 --- a/src/test/ui/parser/lex-bad-octal-literal.rs +++ b/src/test/ui/parser/lex-bad-octal-literal.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - fn main() { 0o18; //~ ERROR invalid digit for a base 8 literal 0o1234_9_5670; //~ ERROR invalid digit for a base 8 literal diff --git a/src/test/ui/parser/lex-bad-octal-literal.stderr b/src/test/ui/parser/lex-bad-octal-literal.stderr index 542247d69df6e..2cb8ca5ded0ad 100644 --- a/src/test/ui/parser/lex-bad-octal-literal.stderr +++ b/src/test/ui/parser/lex-bad-octal-literal.stderr @@ -1,13 +1,13 @@ error: invalid digit for a base 8 literal - --> $DIR/lex-bad-octal-literal.rs:4:8 + --> $DIR/lex-bad-octal-literal.rs:2:8 | -LL | 0o18; //~ ERROR invalid digit for a base 8 literal +LL | 0o18; | ^ error: invalid digit for a base 8 literal - --> $DIR/lex-bad-octal-literal.rs:5:12 + --> $DIR/lex-bad-octal-literal.rs:3:12 | -LL | 0o1234_9_5670; //~ ERROR invalid digit for a base 8 literal +LL | 0o1234_9_5670; | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/lex-bad-token.stderr b/src/test/ui/parser/lex-bad-token.stderr index 284ffde9efbe7..43c43721b19f2 100644 --- a/src/test/ui/parser/lex-bad-token.stderr +++ b/src/test/ui/parser/lex-bad-token.stderr @@ -1,7 +1,7 @@ -error: unknown start of token: /u{25cf} +error: unknown start of token: \u{25cf} --> $DIR/lex-bad-token.rs:1:1 | -LL | ● //~ ERROR: unknown start of token +LL | ● | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/lex-bare-cr-string-literal-doc-comment.stderr b/src/test/ui/parser/lex-bare-cr-string-literal-doc-comment.stderr index e9f3537ab7431..b0fe4b6acd484 100644 --- a/src/test/ui/parser/lex-bare-cr-string-literal-doc-comment.stderr +++ b/src/test/ui/parser/lex-bare-cr-string-literal-doc-comment.stderr @@ -22,29 +22,25 @@ error: bare CR not allowed in block doc-comment LL | /*! block doc comment with bare CR: ' ' */ | ^ -error: bare CR not allowed in string, use /r instead +error: bare CR not allowed in string, use \r instead --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:21:18 | -LL | let _s = "foo bar"; //~ ERROR: bare CR not allowed in string +LL | let _s = "foo bar"; | ^ -error: bare CR not allowed in raw string, use /r instead - --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:24:14 +error: bare CR not allowed in raw string + --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:24:19 | -LL | let _s = r"bar foo"; //~ ERROR: bare CR not allowed in raw string - | ^^^^^ +LL | let _s = r"bar foo"; + | ^ -error: unknown character escape: /r +error: unknown character escape: \r --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:27:19 | -LL | let _s = "foo/ bar"; //~ ERROR: unknown character escape: /r - | ^ +LL | let _s = "foo\ bar"; + | ^ unknown character escape | -help: this is an isolated carriage return; consider checking your editor and version control settings - --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:27:19 - | -LL | let _s = "foo/ bar"; //~ ERROR: unknown character escape: /r - | ^ + = help: this is an isolated carriage return; consider checking your editor and version control settings error: aborting due to 7 previous errors diff --git a/src/test/ui/parser/lex-stray-backslash.stderr b/src/test/ui/parser/lex-stray-backslash.stderr index 40e0cc1d786d1..06dc0f2b537ba 100644 --- a/src/test/ui/parser/lex-stray-backslash.stderr +++ b/src/test/ui/parser/lex-stray-backslash.stderr @@ -1,7 +1,7 @@ -error: unknown start of token: / +error: unknown start of token: \ --> $DIR/lex-stray-backslash.rs:1:1 | -LL | / //~ ERROR: unknown start of token: / +LL | \ | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/macro-bad-delimiter-ident.stderr b/src/test/ui/parser/macro-bad-delimiter-ident.stderr index 59762e021652c..6a17d39e8bfec 100644 --- a/src/test/ui/parser/macro-bad-delimiter-ident.stderr +++ b/src/test/ui/parser/macro-bad-delimiter-ident.stderr @@ -1,7 +1,7 @@ error: expected `(` or `{`, found `<` --> $DIR/macro-bad-delimiter-ident.rs:2:14 | -LL | foo! bar < //~ ERROR expected `(` or `{`, found `<` +LL | foo! bar < | ^ expected `(` or `{` error: aborting due to previous error diff --git a/src/test/ui/parser/macro-keyword.stderr b/src/test/ui/parser/macro-keyword.stderr index 4a10dd50b2340..f74c8aa57e705 100644 --- a/src/test/ui/parser/macro-keyword.stderr +++ b/src/test/ui/parser/macro-keyword.stderr @@ -1,11 +1,11 @@ error: expected identifier, found reserved keyword `macro` --> $DIR/macro-keyword.rs:1:4 | -LL | fn macro() { //~ ERROR expected identifier, found reserved keyword `macro` +LL | fn macro() { | ^^^^^ expected identifier, found reserved keyword help: you can escape reserved keywords to use them as identifiers | -LL | fn r#macro() { //~ ERROR expected identifier, found reserved keyword `macro` +LL | fn r#macro() { | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/macro-mismatched-delim-brace-paren.stderr b/src/test/ui/parser/macro-mismatched-delim-brace-paren.stderr index 21c3d1771aade..f411ee8ce2ccc 100644 --- a/src/test/ui/parser/macro-mismatched-delim-brace-paren.stderr +++ b/src/test/ui/parser/macro-mismatched-delim-brace-paren.stderr @@ -4,7 +4,7 @@ error: incorrect close delimiter: `)` LL | foo! { | - un-closed delimiter LL | bar, "baz", 1, 2.0 -LL | ) //~ ERROR incorrect close delimiter +LL | ) | ^ incorrect close delimiter error: aborting due to previous error diff --git a/src/test/ui/parser/macro-mismatched-delim-paren-brace.stderr b/src/test/ui/parser/macro-mismatched-delim-paren-brace.stderr index abb0820979532..b68433936117a 100644 --- a/src/test/ui/parser/macro-mismatched-delim-paren-brace.stderr +++ b/src/test/ui/parser/macro-mismatched-delim-paren-brace.stderr @@ -1,7 +1,7 @@ error: unexpected close delimiter: `}` --> $DIR/macro-mismatched-delim-paren-brace.rs:5:1 | -LL | } //~ ERROR unexpected close delimiter: `}` +LL | } | ^ unexpected close delimiter error: incorrect close delimiter: `}` @@ -10,7 +10,7 @@ error: incorrect close delimiter: `}` LL | foo! ( | - un-closed delimiter LL | bar, "baz", 1, 2.0 -LL | } //~ ERROR incorrect close delimiter +LL | } | ^ incorrect close delimiter error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/macro/bad-macro-argument.rs b/src/test/ui/parser/macro/bad-macro-argument.rs new file mode 100644 index 0000000000000..4b6d23890653d --- /dev/null +++ b/src/test/ui/parser/macro/bad-macro-argument.rs @@ -0,0 +1,4 @@ +fn main() { + let message = "world"; + println!("Hello, {}", message/); //~ ERROR expected expression +} diff --git a/src/test/ui/parser/macro/bad-macro-argument.stderr b/src/test/ui/parser/macro/bad-macro-argument.stderr new file mode 100644 index 0000000000000..3cd8accb66294 --- /dev/null +++ b/src/test/ui/parser/macro/bad-macro-argument.stderr @@ -0,0 +1,8 @@ +error: expected expression, found end of macro arguments + --> $DIR/bad-macro-argument.rs:3:35 + | +LL | println!("Hello, {}", message/); + | ^ expected expression + +error: aborting due to previous error + diff --git a/src/test/ui/parser/macro/issue-33569.rs b/src/test/ui/parser/macro/issue-33569.rs index 83f8a562a03ad..9ed53519ceb31 100644 --- a/src/test/ui/parser/macro/issue-33569.rs +++ b/src/test/ui/parser/macro/issue-33569.rs @@ -1,7 +1,7 @@ macro_rules! foo { { $+ } => { //~ ERROR expected identifier, found `+` //~^ ERROR missing fragment specifier - $(x)(y) //~ ERROR expected `*` or `+` + $(x)(y) //~ ERROR expected one of: `*`, `+`, or `?` } } diff --git a/src/test/ui/parser/macro/issue-33569.stderr b/src/test/ui/parser/macro/issue-33569.stderr index 213d72363f59c..b4d38d3ce4806 100644 --- a/src/test/ui/parser/macro/issue-33569.stderr +++ b/src/test/ui/parser/macro/issue-33569.stderr @@ -1,19 +1,19 @@ error: expected identifier, found `+` --> $DIR/issue-33569.rs:2:8 | -LL | { $+ } => { //~ ERROR expected identifier, found `+` +LL | { $+ } => { | ^ -error: expected `*` or `+` +error: expected one of: `*`, `+`, or `?` --> $DIR/issue-33569.rs:4:13 | -LL | $(x)(y) //~ ERROR expected `*` or `+` +LL | $(x)(y) | ^^^ error: missing fragment specifier --> $DIR/issue-33569.rs:2:8 | -LL | { $+ } => { //~ ERROR expected identifier, found `+` +LL | { $+ } => { | ^ error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/macro/issue-37113.stderr b/src/test/ui/parser/macro/issue-37113.stderr index 36589667c4bcb..7aadc0aa4b5c1 100644 --- a/src/test/ui/parser/macro/issue-37113.stderr +++ b/src/test/ui/parser/macro/issue-37113.stderr @@ -1,7 +1,7 @@ error: expected identifier, found `String` --> $DIR/issue-37113.rs:4:16 | -LL | $( $t, )* //~ ERROR expected identifier, found `String` +LL | $( $t, )* | ^^ expected identifier ... LL | test_macro!(String,); diff --git a/src/test/ui/parser/macro/issue-37234.stderr b/src/test/ui/parser/macro/issue-37234.stderr index dcc24fca5cc4c..004de9d905f15 100644 --- a/src/test/ui/parser/macro/issue-37234.stderr +++ b/src/test/ui/parser/macro/issue-37234.stderr @@ -1,7 +1,7 @@ error: expected one of `.`, `;`, `?`, or an operator, found `""` --> $DIR/issue-37234.rs:3:19 | -LL | let x = 5 ""; //~ ERROR found `""` +LL | let x = 5 ""; | ^^ expected one of `.`, `;`, `?`, or an operator here ... LL | failed!(); diff --git a/src/test/ui/parser/macro/literals-are-validated-before-expansion.rs b/src/test/ui/parser/macro/literals-are-validated-before-expansion.rs new file mode 100644 index 0000000000000..c3fc754b5567f --- /dev/null +++ b/src/test/ui/parser/macro/literals-are-validated-before-expansion.rs @@ -0,0 +1,10 @@ +macro_rules! black_hole { + ($($tt:tt)*) => {} +} + +fn main() { + black_hole! { '\u{FFFFFF}' } + //~^ ERROR: invalid unicode character escape + black_hole! { "this is surrogate: \u{DAAA}" } + //~^ ERROR: invalid unicode character escape +} diff --git a/src/test/ui/parser/macro/literals-are-validated-before-expansion.stderr b/src/test/ui/parser/macro/literals-are-validated-before-expansion.stderr new file mode 100644 index 0000000000000..d20eb0fb30a49 --- /dev/null +++ b/src/test/ui/parser/macro/literals-are-validated-before-expansion.stderr @@ -0,0 +1,18 @@ +error: invalid unicode character escape + --> $DIR/literals-are-validated-before-expansion.rs:6:20 + | +LL | black_hole! { '\u{FFFFFF}' } + | ^^^^^^^^^^ + | + = help: unicode escape must be at most 10FFFF + +error: invalid unicode character escape + --> $DIR/literals-are-validated-before-expansion.rs:8:39 + | +LL | black_hole! { "this is surrogate: \u{DAAA}" } + | ^^^^^^^^ + | + = help: unicode escape must not be a surrogate + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/macro/macro-incomplete-parse.rs b/src/test/ui/parser/macro/macro-incomplete-parse.rs index 9294bebc5148c..544e4aa7b1b09 100644 --- a/src/test/ui/parser/macro/macro-incomplete-parse.rs +++ b/src/test/ui/parser/macro/macro-incomplete-parse.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - macro_rules! ignored_item { () => { fn foo() {} diff --git a/src/test/ui/parser/macro/macro-incomplete-parse.stderr b/src/test/ui/parser/macro/macro-incomplete-parse.stderr index 3fcc8e08520db..e40919cda945f 100644 --- a/src/test/ui/parser/macro/macro-incomplete-parse.stderr +++ b/src/test/ui/parser/macro/macro-incomplete-parse.stderr @@ -1,7 +1,7 @@ error: macro expansion ignores token `,` and any following - --> $DIR/macro-incomplete-parse.rs:7:9 + --> $DIR/macro-incomplete-parse.rs:5:9 | -LL | , //~ ERROR macro expansion ignores token `,` +LL | , | ^ ... LL | ignored_item!(); @@ -10,18 +10,18 @@ LL | ignored_item!(); = note: the usage of `ignored_item!` is likely invalid in item context error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` - --> $DIR/macro-incomplete-parse.rs:12:14 + --> $DIR/macro-incomplete-parse.rs:10:14 | -LL | () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` +LL | () => ( 1, | ^ expected one of `.`, `;`, `?`, `}`, or an operator here ... LL | ignored_expr!(); | ---------------- in this macro invocation error: macro expansion ignores token `,` and any following - --> $DIR/macro-incomplete-parse.rs:18:14 + --> $DIR/macro-incomplete-parse.rs:16:14 | -LL | () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,` +LL | () => ( 1, 2 ) | ^ ... LL | ignored_pat!() => (), diff --git a/src/test/ui/parser/macro/macro-repeat.stderr b/src/test/ui/parser/macro/macro-repeat.stderr index 310d60c8dbda0..c86684de74432 100644 --- a/src/test/ui/parser/macro/macro-repeat.stderr +++ b/src/test/ui/parser/macro/macro-repeat.stderr @@ -1,7 +1,7 @@ error: variable 'v' is still repeating at this depth --> $DIR/macro-repeat.rs:3:9 | -LL | $v //~ ERROR still repeating at this depth +LL | $v | ^^ error: aborting due to previous error diff --git a/src/test/ui/parser/macro/pub-item-macro.stderr b/src/test/ui/parser/macro/pub-item-macro.stderr index a624d574c456f..fa25161ab50b2 100644 --- a/src/test/ui/parser/macro/pub-item-macro.stderr +++ b/src/test/ui/parser/macro/pub-item-macro.stderr @@ -1,7 +1,7 @@ error: can't qualify macro invocation with `pub` --> $DIR/pub-item-macro.rs:8:5 | -LL | pub priv_x!(); //~ ERROR can't qualify macro invocation with `pub` +LL | pub priv_x!(); | ^^^ ... LL | pub_x!(); @@ -12,7 +12,7 @@ LL | pub_x!(); error[E0603]: static `x` is private --> $DIR/pub-item-macro.rs:17:23 | -LL | let y: u32 = foo::x; //~ ERROR static `x` is private +LL | let y: u32 = foo::x; | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/macro/trait-object-macro-matcher.stderr b/src/test/ui/parser/macro/trait-object-macro-matcher.stderr index 185a9e718098a..19c5c82f82cd2 100644 --- a/src/test/ui/parser/macro/trait-object-macro-matcher.stderr +++ b/src/test/ui/parser/macro/trait-object-macro-matcher.stderr @@ -1,7 +1,7 @@ error: expected type, found `'static` --> $DIR/trait-object-macro-matcher.rs:9:8 | -LL | m!('static); //~ ERROR expected type, found `'static` +LL | m!('static); | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/macros-no-semicolon-items.rs b/src/test/ui/parser/macros-no-semicolon-items.rs index a727cafcab023..3afc275d61a2b 100644 --- a/src/test/ui/parser/macros-no-semicolon-items.rs +++ b/src/test/ui/parser/macros-no-semicolon-items.rs @@ -1,4 +1,15 @@ macro_rules! foo() //~ ERROR semicolon + //~| ERROR unexpected end of macro + +macro_rules! bar { + ($($tokens:tt)*) => {} +} + +bar!( //~ ERROR semicolon + blah + blah + blah +) fn main() { } diff --git a/src/test/ui/parser/macros-no-semicolon-items.stderr b/src/test/ui/parser/macros-no-semicolon-items.stderr index 84dd302b4a8e1..5276aa6f5e9e9 100644 --- a/src/test/ui/parser/macros-no-semicolon-items.stderr +++ b/src/test/ui/parser/macros-no-semicolon-items.stderr @@ -1,8 +1,45 @@ -error: macros that expand to items must either be surrounded with braces or followed by a semicolon +error: macros that expand to items must be delimited with braces or followed by a semicolon --> $DIR/macros-no-semicolon-items.rs:1:17 | -LL | macro_rules! foo() //~ ERROR semicolon +LL | macro_rules! foo() | ^^ +help: change the delimiters to curly braces + | +LL | macro_rules! foo {} + | ^^ +help: add a semicolon + | +LL | macro_rules! foo(); + | ^ + +error: macros that expand to items must be delimited with braces or followed by a semicolon + --> $DIR/macros-no-semicolon-items.rs:8:5 + | +LL | bar!( + | _____^ +LL | | blah +LL | | blah +LL | | blah +LL | | ) + | |_^ +help: change the delimiters to curly braces + | +LL | bar! { +LL | blah +LL | blah +LL | blah +LL | } + | +help: add a semicolon + | +LL | ); + | ^ + +error: unexpected end of macro invocation + --> $DIR/macros-no-semicolon-items.rs:1:1 + | +LL | macro_rules! foo() + | ^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments -error: aborting due to previous error +error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/macros-no-semicolon.stderr b/src/test/ui/parser/macros-no-semicolon.stderr index 4f9e7fb5de85a..09925eae51d27 100644 --- a/src/test/ui/parser/macros-no-semicolon.stderr +++ b/src/test/ui/parser/macros-no-semicolon.stderr @@ -3,7 +3,7 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `assert_eq` | LL | assert_eq!(1, 2) | - expected one of `.`, `;`, `?`, `}`, or an operator here -LL | assert_eq!(3, 4) //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `assert_eq` +LL | assert_eq!(3, 4) | ^^^^^^^^^ unexpected token error: aborting due to previous error diff --git a/src/test/ui/parser/match-arrows-block-then-binop.rs b/src/test/ui/parser/match-arrows-block-then-binop.rs index 1a40d67492990..56c917c7462f2 100644 --- a/src/test/ui/parser/match-arrows-block-then-binop.rs +++ b/src/test/ui/parser/match-arrows-block-then-binop.rs @@ -1,7 +1,7 @@ fn main() { - - match 0 { + let _ = match 0 { 0 => { + 0 } + 5 //~ ERROR expected pattern, found `+` - } + }; } diff --git a/src/test/ui/parser/match-arrows-block-then-binop.stderr b/src/test/ui/parser/match-arrows-block-then-binop.stderr index 2782af49e66b1..bb7df30783acd 100644 --- a/src/test/ui/parser/match-arrows-block-then-binop.stderr +++ b/src/test/ui/parser/match-arrows-block-then-binop.stderr @@ -1,8 +1,14 @@ error: expected pattern, found `+` --> $DIR/match-arrows-block-then-binop.rs:5:9 | -LL | } + 5 //~ ERROR expected pattern, found `+` +LL | } + 5 | ^ expected pattern +help: parentheses are required to parse this as an expression + | +LL | 0 => ({ +LL | 0 +LL | }) + 5 + | error: aborting due to previous error diff --git a/src/test/ui/parser/match-refactor-to-expr.stderr b/src/test/ui/parser/match-refactor-to-expr.stderr index 692b116123a60..bf20bc9350021 100644 --- a/src/test/ui/parser/match-refactor-to-expr.stderr +++ b/src/test/ui/parser/match-refactor-to-expr.stderr @@ -1,15 +1,15 @@ error: expected one of `.`, `?`, `{`, or an operator, found `;` --> $DIR/match-refactor-to-expr.rs:6:9 | -LL | match //~ NOTE while parsing this match expression +LL | match | ----- | | | while parsing this match expression | help: try removing this `match` LL | Some(4).unwrap_or_else(5) | - expected one of `.`, `?`, `{`, or an operator here -LL | //~^ NOTE expected one of `.`, `?`, `{`, or an operator here -LL | ; //~ NOTE unexpected token +LL | +LL | ; | ^ unexpected token error: aborting due to previous error diff --git a/src/test/ui/parser/match-vec-invalid.stderr b/src/test/ui/parser/match-vec-invalid.stderr index 5a5fc9c450989..fee8d248dcf07 100644 --- a/src/test/ui/parser/match-vec-invalid.stderr +++ b/src/test/ui/parser/match-vec-invalid.stderr @@ -1,7 +1,7 @@ error: expected one of `,` or `@`, found `..` --> $DIR/match-vec-invalid.rs:4:25 | -LL | [1, tail.., tail..] => {}, //~ ERROR: expected one of `,` or `@`, found `..` +LL | [1, tail.., tail..] => {}, | ^^ expected one of `,` or `@` here error: aborting due to previous error diff --git a/src/test/ui/parser/mod_file_not_exist.stderr b/src/test/ui/parser/mod_file_not_exist.stderr index f7f0e2d2d1168..dadf4b29dcf39 100644 --- a/src/test/ui/parser/mod_file_not_exist.stderr +++ b/src/test/ui/parser/mod_file_not_exist.stderr @@ -1,7 +1,7 @@ error[E0583]: file not found for module `not_a_real_file` --> $DIR/mod_file_not_exist.rs:3:5 | -LL | mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` +LL | mod not_a_real_file; | ^^^^^^^^^^^^^^^ | = help: name the file either not_a_real_file.rs or not_a_real_file/mod.rs inside the directory "$DIR" diff --git a/src/test/ui/parser/mod_file_not_exist_windows.stderr b/src/test/ui/parser/mod_file_not_exist_windows.stderr index 67abd6304d515..60ae00abab1ed 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.stderr +++ b/src/test/ui/parser/mod_file_not_exist_windows.stderr @@ -1,7 +1,7 @@ error[E0583]: file not found for module `not_a_real_file` --> $DIR/mod_file_not_exist_windows.rs:3:5 | -LL | mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` +LL | mod not_a_real_file; | ^^^^^^^^^^^^^^^ | = help: name the file either not_a_real_file.rs or not_a_real_file/mod.rs inside the directory "$DIR" diff --git a/src/test/ui/parser/mod_file_with_path_attr.stderr b/src/test/ui/parser/mod_file_with_path_attr.stderr index a3a3486dd9e36..004b5d7963a1d 100644 --- a/src/test/ui/parser/mod_file_with_path_attr.stderr +++ b/src/test/ui/parser/mod_file_with_path_attr.stderr @@ -1,7 +1,7 @@ error: couldn't read $DIR/not_a_real_file.rs: $FILE_NOT_FOUND_MSG (os error 2) --> $DIR/mod_file_with_path_attr.rs:4:5 | -LL | mod m; //~ ERROR not_a_real_file.rs +LL | mod m; | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/multiline-comment-line-tracking.stderr b/src/test/ui/parser/multiline-comment-line-tracking.stderr index c9404d8b9e4d3..cac0c801a5998 100644 --- a/src/test/ui/parser/multiline-comment-line-tracking.stderr +++ b/src/test/ui/parser/multiline-comment-line-tracking.stderr @@ -1,7 +1,7 @@ error: expected expression, found `%` --> $DIR/multiline-comment-line-tracking.rs:8:3 | -LL | %; //~ ERROR expected expression, found `%` +LL | %; | ^ expected expression error: aborting due to previous error diff --git a/src/test/ui/parser/mut-patterns.stderr b/src/test/ui/parser/mut-patterns.stderr index 5bbb4ce569f0b..286956440ec34 100644 --- a/src/test/ui/parser/mut-patterns.stderr +++ b/src/test/ui/parser/mut-patterns.stderr @@ -1,7 +1,7 @@ error: expected one of `:`, `;`, `=`, or `@`, found `{` --> $DIR/mut-patterns.rs:5:17 | -LL | let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected one of `:`, `;`, `=`, or `@`, found `{` +LL | let mut Foo { x: x } = Foo { x: 3 }; | ^ expected one of `:`, `;`, `=`, or `@` here error: aborting due to previous error diff --git a/src/test/ui/parser/new-unicode-escapes-1.stderr b/src/test/ui/parser/new-unicode-escapes-1.stderr index 828e72e56eac8..22d6a0981ffd6 100644 --- a/src/test/ui/parser/new-unicode-escapes-1.stderr +++ b/src/test/ui/parser/new-unicode-escapes-1.stderr @@ -1,8 +1,8 @@ error: unterminated unicode escape (needed a `}`) - --> $DIR/new-unicode-escapes-1.rs:2:21 + --> $DIR/new-unicode-escapes-1.rs:2:14 | -LL | let s = "/u{2603"; //~ ERROR unterminated unicode escape (needed a `}`) - | ^ +LL | let s = "\u{2603"; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/new-unicode-escapes-2.stderr b/src/test/ui/parser/new-unicode-escapes-2.stderr index 97ba3fb2cb666..b5148279c7450 100644 --- a/src/test/ui/parser/new-unicode-escapes-2.stderr +++ b/src/test/ui/parser/new-unicode-escapes-2.stderr @@ -1,8 +1,8 @@ error: overlong unicode escape (must have at most 6 hex digits) - --> $DIR/new-unicode-escapes-2.rs:2:17 + --> $DIR/new-unicode-escapes-2.rs:2:14 | -LL | let s = "/u{260311111111}"; //~ ERROR overlong unicode escape (must have at most 6 hex digits) - | ^^^^^^^^^^^^ +LL | let s = "\u{260311111111}"; + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/new-unicode-escapes-3.stderr b/src/test/ui/parser/new-unicode-escapes-3.stderr index 038002ae05e56..361698467f97d 100644 --- a/src/test/ui/parser/new-unicode-escapes-3.stderr +++ b/src/test/ui/parser/new-unicode-escapes-3.stderr @@ -1,16 +1,16 @@ error: invalid unicode character escape - --> $DIR/new-unicode-escapes-3.rs:2:14 + --> $DIR/new-unicode-escapes-3.rs:2:15 | -LL | let s1 = "/u{d805}"; //~ ERROR invalid unicode character escape - | ^^^^^^^^^^ +LL | let s1 = "\u{d805}"; + | ^^^^^^^^ | = help: unicode escape must not be a surrogate error: invalid unicode character escape - --> $DIR/new-unicode-escapes-3.rs:3:14 + --> $DIR/new-unicode-escapes-3.rs:3:15 | -LL | let s2 = "/u{ffffff}"; //~ ERROR invalid unicode character escape - | ^^^^^^^^^^^^ +LL | let s2 = "\u{ffffff}"; + | ^^^^^^^^^^ | = help: unicode escape must be at most 10FFFF diff --git a/src/test/ui/parser/new-unicode-escapes-4.rs b/src/test/ui/parser/new-unicode-escapes-4.rs index b871000ac1284..9ac03cedc3f3e 100644 --- a/src/test/ui/parser/new-unicode-escapes-4.rs +++ b/src/test/ui/parser/new-unicode-escapes-4.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - pub fn main() { let s = "\u{lol}"; //~^ ERROR invalid character in unicode escape: l diff --git a/src/test/ui/parser/new-unicode-escapes-4.stderr b/src/test/ui/parser/new-unicode-escapes-4.stderr index c8dbe027184de..a35c5f0f21658 100644 --- a/src/test/ui/parser/new-unicode-escapes-4.stderr +++ b/src/test/ui/parser/new-unicode-escapes-4.stderr @@ -1,7 +1,7 @@ error: invalid character in unicode escape: l - --> $DIR/new-unicode-escapes-4.rs:4:17 + --> $DIR/new-unicode-escapes-4.rs:2:17 | -LL | let s = "/u{lol}"; +LL | let s = "\u{lol}"; | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/no-binary-float-literal.rs b/src/test/ui/parser/no-binary-float-literal.rs index a42d2cbc442f0..052cb4934f503 100644 --- a/src/test/ui/parser/no-binary-float-literal.rs +++ b/src/test/ui/parser/no-binary-float-literal.rs @@ -4,5 +4,5 @@ fn main() { 0b101.010; //~^ ERROR binary float literal is not supported 0b101p4f64; - //~^ ERROR invalid suffix `p4f64` for numeric literal + //~^ ERROR invalid suffix `p4f64` for integer literal } diff --git a/src/test/ui/parser/no-binary-float-literal.stderr b/src/test/ui/parser/no-binary-float-literal.stderr index 21f415bcfb000..65b129b5827ce 100644 --- a/src/test/ui/parser/no-binary-float-literal.stderr +++ b/src/test/ui/parser/no-binary-float-literal.stderr @@ -10,7 +10,7 @@ error: binary float literal is not supported LL | 0b101010f64; | ^^^^^^^^^^^ not supported -error: invalid suffix `p4f64` for numeric literal +error: invalid suffix `p4f64` for integer literal --> $DIR/no-binary-float-literal.rs:6:5 | LL | 0b101p4f64; diff --git a/src/test/ui/parser/no-unsafe-self.rs b/src/test/ui/parser/no-unsafe-self.rs index 57201f2d91afd..d1cd8ad53114b 100644 --- a/src/test/ui/parser/no-unsafe-self.rs +++ b/src/test/ui/parser/no-unsafe-self.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - trait A { fn foo(*mut self); //~ ERROR cannot pass `self` by raw pointer fn baz(*const self); //~ ERROR cannot pass `self` by raw pointer diff --git a/src/test/ui/parser/no-unsafe-self.stderr b/src/test/ui/parser/no-unsafe-self.stderr index 84779b09dc7c6..23323945ee4b6 100644 --- a/src/test/ui/parser/no-unsafe-self.stderr +++ b/src/test/ui/parser/no-unsafe-self.stderr @@ -1,37 +1,37 @@ error: cannot pass `self` by raw pointer - --> $DIR/no-unsafe-self.rs:4:17 + --> $DIR/no-unsafe-self.rs:2:17 | -LL | fn foo(*mut self); //~ ERROR cannot pass `self` by raw pointer +LL | fn foo(*mut self); | ^^^^ cannot pass `self` by raw pointer error: cannot pass `self` by raw pointer - --> $DIR/no-unsafe-self.rs:5:19 + --> $DIR/no-unsafe-self.rs:3:19 | -LL | fn baz(*const self); //~ ERROR cannot pass `self` by raw pointer +LL | fn baz(*const self); | ^^^^ cannot pass `self` by raw pointer error: cannot pass `self` by raw pointer - --> $DIR/no-unsafe-self.rs:6:13 + --> $DIR/no-unsafe-self.rs:4:13 | -LL | fn bar(*self); //~ ERROR cannot pass `self` by raw pointer +LL | fn bar(*self); | ^^^^ cannot pass `self` by raw pointer error: cannot pass `self` by raw pointer - --> $DIR/no-unsafe-self.rs:11:17 + --> $DIR/no-unsafe-self.rs:9:17 | -LL | fn foo(*mut self) { } //~ ERROR cannot pass `self` by raw pointer +LL | fn foo(*mut self) { } | ^^^^ cannot pass `self` by raw pointer error: cannot pass `self` by raw pointer - --> $DIR/no-unsafe-self.rs:12:19 + --> $DIR/no-unsafe-self.rs:10:19 | -LL | fn baz(*const self) { } //~ ERROR cannot pass `self` by raw pointer +LL | fn baz(*const self) { } | ^^^^ cannot pass `self` by raw pointer error: cannot pass `self` by raw pointer - --> $DIR/no-unsafe-self.rs:13:13 + --> $DIR/no-unsafe-self.rs:11:13 | -LL | fn bar(*self) { } //~ ERROR cannot pass `self` by raw pointer +LL | fn bar(*self) { } | ^^^^ cannot pass `self` by raw pointer error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/numeric-lifetime.rs b/src/test/ui/parser/numeric-lifetime.rs new file mode 100644 index 0000000000000..2d82354c62cca --- /dev/null +++ b/src/test/ui/parser/numeric-lifetime.rs @@ -0,0 +1,8 @@ +struct S<'1> { s: &'1 usize } +//~^ ERROR lifetimes cannot start with a number +//~| ERROR lifetimes cannot start with a number +fn main() { + // verify that the parse error doesn't stop type checking + let x: usize = ""; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/parser/numeric-lifetime.stderr b/src/test/ui/parser/numeric-lifetime.stderr new file mode 100644 index 0000000000000..4018b24aac175 --- /dev/null +++ b/src/test/ui/parser/numeric-lifetime.stderr @@ -0,0 +1,24 @@ +error: lifetimes cannot start with a number + --> $DIR/numeric-lifetime.rs:1:10 + | +LL | struct S<'1> { s: &'1 usize } + | ^^ + +error: lifetimes cannot start with a number + --> $DIR/numeric-lifetime.rs:1:20 + | +LL | struct S<'1> { s: &'1 usize } + | ^^ + +error[E0308]: mismatched types + --> $DIR/numeric-lifetime.rs:6:20 + | +LL | let x: usize = ""; + | ^^ expected usize, found reference + | + = note: expected type `usize` + found type `&'static str` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/omitted-arg-in-item-fn.stderr b/src/test/ui/parser/omitted-arg-in-item-fn.stderr index b21a1bd08315c..e501f235d6d3b 100644 --- a/src/test/ui/parser/omitted-arg-in-item-fn.stderr +++ b/src/test/ui/parser/omitted-arg-in-item-fn.stderr @@ -1,8 +1,18 @@ error: expected one of `:` or `@`, found `)` --> $DIR/omitted-arg-in-item-fn.rs:1:9 | -LL | fn foo(x) { //~ ERROR expected one of `:` or `@`, found `)` +LL | fn foo(x) { | ^ expected one of `:` or `@` here + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this was a parameter name, give it a type + | +LL | fn foo(x: TypeName) { + | ^^^^^^^^^^^ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn foo(_: x) { + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/paamayim-nekudotayim.stderr b/src/test/ui/parser/paamayim-nekudotayim.stderr index 6423aa2dc2fd1..6ceba07f46918 100644 --- a/src/test/ui/parser/paamayim-nekudotayim.stderr +++ b/src/test/ui/parser/paamayim-nekudotayim.stderr @@ -1,7 +1,7 @@ error: expected identifier, found `;` --> $DIR/paamayim-nekudotayim.rs:4:7 | -LL | ::; //~ ERROR expected identifier, found `;` +LL | ::; | ^ expected identifier error: aborting due to previous error diff --git a/src/test/ui/parser/pat-lt-bracket-4.stderr b/src/test/ui/parser/pat-lt-bracket-4.stderr index 18e0e9e8f0c45..d14702acee6e5 100644 --- a/src/test/ui/parser/pat-lt-bracket-4.stderr +++ b/src/test/ui/parser/pat-lt-bracket-4.stderr @@ -1,7 +1,7 @@ error: expected one of `=>`, `@`, `if`, or `|`, found `<` --> $DIR/pat-lt-bracket-4.rs:8:12 | -LL | Foo::A(value) => value, //~ error: expected one of `=>`, `@`, `if`, or `|`, found `<` +LL | Foo::A(value) => value, | ^ expected one of `=>`, `@`, `if`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-lt-bracket-5.stderr b/src/test/ui/parser/pat-lt-bracket-5.stderr index 7e76a04ce6f5d..ce4cc05db19b2 100644 --- a/src/test/ui/parser/pat-lt-bracket-5.stderr +++ b/src/test/ui/parser/pat-lt-bracket-5.stderr @@ -1,7 +1,7 @@ error: expected one of `:`, `;`, `=`, or `@`, found `[` --> $DIR/pat-lt-bracket-5.rs:2:10 | -LL | let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` +LL | let v[0] = v[1]; | ^ expected one of `:`, `;`, `=`, or `@` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-lt-bracket-6.stderr b/src/test/ui/parser/pat-lt-bracket-6.stderr index bf5b61907614c..2ee4bdb20fe88 100644 --- a/src/test/ui/parser/pat-lt-bracket-6.stderr +++ b/src/test/ui/parser/pat-lt-bracket-6.stderr @@ -1,7 +1,7 @@ error: expected one of `)`, `,`, or `@`, found `[` --> $DIR/pat-lt-bracket-6.rs:2:19 | -LL | let Test(&desc[..]) = x; //~ ERROR: expected one of `)`, `,`, or `@`, found `[` +LL | let Test(&desc[..]) = x; | ^ expected one of `)`, `,`, or `@` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-lt-bracket-7.stderr b/src/test/ui/parser/pat-lt-bracket-7.stderr index 44394c3002157..5552ea46d9b9d 100644 --- a/src/test/ui/parser/pat-lt-bracket-7.stderr +++ b/src/test/ui/parser/pat-lt-bracket-7.stderr @@ -1,7 +1,7 @@ error: expected one of `)`, `,`, or `@`, found `[` --> $DIR/pat-lt-bracket-7.rs:2:16 | -LL | for thing(x[]) in foo {} //~ ERROR: expected one of `)`, `,`, or `@`, found `[` +LL | for thing(x[]) in foo {} | ^ expected one of `)`, `,`, or `@` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-1.stderr b/src/test/ui/parser/pat-ranges-1.stderr index 378caf6300057..6e0deccab8ca2 100644 --- a/src/test/ui/parser/pat-ranges-1.stderr +++ b/src/test/ui/parser/pat-ranges-1.stderr @@ -1,7 +1,7 @@ error: expected one of `:`, `;`, or `=`, found `..=` --> $DIR/pat-ranges-1.rs:4:21 | -LL | let macropus!() ..= 11 = 12; //~ error: expected one of `:`, `;`, or `=`, found `..=` +LL | let macropus!() ..= 11 = 12; | ^^^ expected one of `:`, `;`, or `=` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-2.stderr b/src/test/ui/parser/pat-ranges-2.stderr index ef8b4f94ef49d..d180bb429110a 100644 --- a/src/test/ui/parser/pat-ranges-2.stderr +++ b/src/test/ui/parser/pat-ranges-2.stderr @@ -1,7 +1,7 @@ error: expected one of `::`, `:`, `;`, or `=`, found `!` --> $DIR/pat-ranges-2.rs:4:26 | -LL | let 10 ..= makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, or `=`, found `!` +LL | let 10 ..= makropulos!() = 12; | ^ expected one of `::`, `:`, `;`, or `=` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-3.stderr b/src/test/ui/parser/pat-ranges-3.stderr index f923228710bf3..aaa85e3c2ddd8 100644 --- a/src/test/ui/parser/pat-ranges-3.stderr +++ b/src/test/ui/parser/pat-ranges-3.stderr @@ -1,7 +1,7 @@ error: expected one of `:`, `;`, or `=`, found `+` --> $DIR/pat-ranges-3.rs:4:19 | -LL | let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, or `=`, found `+` +LL | let 10 ..= 10 + 3 = 12; | ^ expected one of `:`, `;`, or `=` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ref-enum.stderr b/src/test/ui/parser/pat-ref-enum.stderr index 8729e8c5854f7..a3bce3372646f 100644 --- a/src/test/ui/parser/pat-ref-enum.stderr +++ b/src/test/ui/parser/pat-ref-enum.stderr @@ -1,7 +1,7 @@ error: expected identifier, found enum pattern --> $DIR/pat-ref-enum.rs:3:11 | -LL | ref Some(i) => {} //~ ERROR expected identifier, found enum pattern +LL | ref Some(i) => {} | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/pat-tuple-1.rs b/src/test/ui/parser/pat-tuple-1.rs index 213fbe371d435..0e49b547f7d0f 100644 --- a/src/test/ui/parser/pat-tuple-1.rs +++ b/src/test/ui/parser/pat-tuple-1.rs @@ -1,5 +1,5 @@ fn main() { - match 0 { + match (0, 1) { (, ..) => {} //~ ERROR expected pattern, found `,` } } diff --git a/src/test/ui/parser/pat-tuple-1.stderr b/src/test/ui/parser/pat-tuple-1.stderr index 33c69deda42ca..391f2c428bf2e 100644 --- a/src/test/ui/parser/pat-tuple-1.stderr +++ b/src/test/ui/parser/pat-tuple-1.stderr @@ -1,7 +1,7 @@ error: expected pattern, found `,` --> $DIR/pat-tuple-1.rs:3:10 | -LL | (, ..) => {} //~ ERROR expected pattern, found `,` +LL | (, ..) => {} | ^ expected pattern error: aborting due to previous error diff --git a/src/test/ui/parser/pat-tuple-3.stderr b/src/test/ui/parser/pat-tuple-3.stderr index 0ad7d27b94e54..c9f14bb90429b 100644 --- a/src/test/ui/parser/pat-tuple-3.stderr +++ b/src/test/ui/parser/pat-tuple-3.stderr @@ -2,7 +2,9 @@ error: `..` can only be used once per tuple or tuple struct pattern --> $DIR/pat-tuple-3.rs:3:19 | LL | (.., pat, ..) => {} - | ^^ can only be used once per pattern + | -- ^^ can only be used once per pattern + | | + | previously present here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-tuple-4.stderr b/src/test/ui/parser/pat-tuple-4.stderr index fe4b4deaa60d9..26b92fae31391 100644 --- a/src/test/ui/parser/pat-tuple-4.stderr +++ b/src/test/ui/parser/pat-tuple-4.stderr @@ -1,7 +1,7 @@ error: expected one of `)` or `,`, found `pat` --> $DIR/pat-tuple-4.rs:3:13 | -LL | (.. pat) => {} //~ ERROR expected one of `)` or `,`, found `pat` +LL | (.. pat) => {} | ^^^ expected one of `)` or `,` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-tuple-5.rs b/src/test/ui/parser/pat-tuple-5.rs index 03176abaf49a8..d4f05a5eb523e 100644 --- a/src/test/ui/parser/pat-tuple-5.rs +++ b/src/test/ui/parser/pat-tuple-5.rs @@ -1,5 +1,5 @@ fn main() { - match 0 { + match (0, 1) { (pat ..) => {} //~ ERROR unexpected token: `)` } } diff --git a/src/test/ui/parser/pat-tuple-5.stderr b/src/test/ui/parser/pat-tuple-5.stderr index 2ca10f697604d..f9832214c6800 100644 --- a/src/test/ui/parser/pat-tuple-5.stderr +++ b/src/test/ui/parser/pat-tuple-5.stderr @@ -1,8 +1,8 @@ error: unexpected token: `)` - --> $DIR/pat-tuple-5.rs:3:14 + --> $DIR/pat-tuple-5.rs:3:16 | -LL | (pat ..) => {} //~ ERROR unexpected token: `)` - | ^^ +LL | (pat ..) => {} + | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/pub-method-macro.stderr b/src/test/ui/parser/pub-method-macro.stderr index 2b4920a792f09..7b0fe4934610d 100644 --- a/src/test/ui/parser/pub-method-macro.stderr +++ b/src/test/ui/parser/pub-method-macro.stderr @@ -1,7 +1,7 @@ error: can't qualify macro invocation with `pub` --> $DIR/pub-method-macro.rs:17:9 | -LL | pub defn!(f); //~ ERROR can't qualify macro invocation with `pub` +LL | pub defn!(f); | ^^^ | = help: try adjusting the macro to put `pub` inside the invocation diff --git a/src/test/ui/parser/range_inclusive.stderr b/src/test/ui/parser/range_inclusive.stderr index f50b2fa49fb0c..12b7edae79f52 100644 --- a/src/test/ui/parser/range_inclusive.stderr +++ b/src/test/ui/parser/range_inclusive.stderr @@ -1,7 +1,7 @@ error[E0586]: inclusive range with no end --> $DIR/range_inclusive.rs:4:19 | -LL | for _ in 1..= {} //~ERROR inclusive range with no end +LL | for _ in 1..= {} | ^ | = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) diff --git a/src/test/ui/parser/range_inclusive_dotdotdot.rs b/src/test/ui/parser/range_inclusive_dotdotdot.rs index a780304c2d51e..c3e600e771bdf 100644 --- a/src/test/ui/parser/range_inclusive_dotdotdot.rs +++ b/src/test/ui/parser/range_inclusive_dotdotdot.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - // Make sure that inclusive ranges with `...` syntax don't parse. use std::ops::RangeToInclusive; diff --git a/src/test/ui/parser/range_inclusive_dotdotdot.stderr b/src/test/ui/parser/range_inclusive_dotdotdot.stderr index 9fad20848a636..f877c5c6f79de 100644 --- a/src/test/ui/parser/range_inclusive_dotdotdot.stderr +++ b/src/test/ui/parser/range_inclusive_dotdotdot.stderr @@ -1,57 +1,57 @@ error: unexpected token: `...` - --> $DIR/range_inclusive_dotdotdot.rs:8:12 + --> $DIR/range_inclusive_dotdotdot.rs:6:12 | -LL | return ...1; //~ERROR unexpected token: `...` +LL | return ...1; | ^^^ help: use `..` for an exclusive range | -LL | return ..1; //~ERROR unexpected token: `...` +LL | return ..1; | ^^ help: or `..=` for an inclusive range | -LL | return ..=1; //~ERROR unexpected token: `...` +LL | return ..=1; | ^^^ error: unexpected token: `...` - --> $DIR/range_inclusive_dotdotdot.rs:14:13 + --> $DIR/range_inclusive_dotdotdot.rs:12:13 | -LL | let x = ...0; //~ERROR unexpected token: `...` +LL | let x = ...0; | ^^^ help: use `..` for an exclusive range | -LL | let x = ..0; //~ERROR unexpected token: `...` +LL | let x = ..0; | ^^ help: or `..=` for an inclusive range | -LL | let x = ..=0; //~ERROR unexpected token: `...` +LL | let x = ..=0; | ^^^ error: unexpected token: `...` - --> $DIR/range_inclusive_dotdotdot.rs:18:14 + --> $DIR/range_inclusive_dotdotdot.rs:16:14 | -LL | let x = 5...5; //~ERROR unexpected token: `...` +LL | let x = 5...5; | ^^^ help: use `..` for an exclusive range | -LL | let x = 5..5; //~ERROR unexpected token: `...` +LL | let x = 5..5; | ^^ help: or `..=` for an inclusive range | -LL | let x = 5..=5; //~ERROR unexpected token: `...` +LL | let x = 5..=5; | ^^^ error: unexpected token: `...` - --> $DIR/range_inclusive_dotdotdot.rs:22:15 + --> $DIR/range_inclusive_dotdotdot.rs:20:15 | -LL | for _ in 0...1 {} //~ERROR unexpected token: `...` +LL | for _ in 0...1 {} | ^^^ help: use `..` for an exclusive range | -LL | for _ in 0..1 {} //~ERROR unexpected token: `...` +LL | for _ in 0..1 {} | ^^ help: or `..=` for an inclusive range | -LL | for _ in 0..=1 {} //~ERROR unexpected token: `...` +LL | for _ in 0..=1 {} | ^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/parser/raw-byte-string-eof.stderr b/src/test/ui/parser/raw-byte-string-eof.stderr index 071cd6241da20..2ba50e8fb2a34 100644 --- a/src/test/ui/parser/raw-byte-string-eof.stderr +++ b/src/test/ui/parser/raw-byte-string-eof.stderr @@ -1,7 +1,7 @@ error: unterminated raw string --> $DIR/raw-byte-string-eof.rs:2:6 | -LL | br##"a"#; //~ unterminated raw string +LL | br##"a"#; | ^ unterminated raw string | = note: this raw string should be terminated with `"##` diff --git a/src/test/ui/parser/raw-byte-string-literals.rs b/src/test/ui/parser/raw-byte-string-literals.rs index 2800e4090cf79..534afabdf777e 100644 --- a/src/test/ui/parser/raw-byte-string-literals.rs +++ b/src/test/ui/parser/raw-byte-string-literals.rs @@ -1,7 +1,7 @@ +// ignore-tidy-cr // compile-flags: -Z continue-parse-after-error - - pub fn main() { + br"a "; //~ ERROR bare CR not allowed in raw string br"é"; //~ ERROR raw byte string must be ASCII br##~"a"~##; //~ ERROR only `#` is allowed in raw string delimitation } diff --git a/src/test/ui/parser/raw-byte-string-literals.stderr b/src/test/ui/parser/raw-byte-string-literals.stderr index 1131e0015bb53..4880d1fdbe8a7 100644 --- a/src/test/ui/parser/raw-byte-string-literals.stderr +++ b/src/test/ui/parser/raw-byte-string-literals.stderr @@ -1,14 +1,20 @@ -error: raw byte string must be ASCII: /u{e9} +error: bare CR not allowed in raw string + --> $DIR/raw-byte-string-literals.rs:4:9 + | +LL | br"a "; + | ^ + +error: raw byte string must be ASCII --> $DIR/raw-byte-string-literals.rs:5:8 | -LL | br"é"; //~ ERROR raw byte string must be ASCII +LL | br"é"; | ^ error: found invalid character; only `#` is allowed in raw string delimitation: ~ --> $DIR/raw-byte-string-literals.rs:6:6 | -LL | br##~"a"~##; //~ ERROR only `#` is allowed in raw string delimitation +LL | br##~"a"~##; | ^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/raw-str-delim.stderr b/src/test/ui/parser/raw-str-delim.stderr index 47fd331969dfe..b86b9e90e73ad 100644 --- a/src/test/ui/parser/raw-str-delim.stderr +++ b/src/test/ui/parser/raw-str-delim.stderr @@ -1,7 +1,7 @@ error: found invalid character; only `#` is allowed in raw string delimitation: ~ --> $DIR/raw-str-delim.rs:2:5 | -LL | r#~"#"~# //~ ERROR found invalid character; only `#` is allowed in raw string delimitation +LL | r#~"#"~# | ^^ error: aborting due to previous error diff --git a/src/test/ui/parser/raw-str-unbalanced.stderr b/src/test/ui/parser/raw-str-unbalanced.stderr index 6dedcfb6a0aab..26910ff64f578 100644 --- a/src/test/ui/parser/raw-str-unbalanced.stderr +++ b/src/test/ui/parser/raw-str-unbalanced.stderr @@ -1,7 +1,7 @@ error: expected one of `.`, `;`, `?`, or an operator, found `#` --> $DIR/raw-str-unbalanced.rs:3:9 | -LL | "## //~ ERROR expected one of `.`, `;`, `?`, or an operator, found `#` +LL | "## | ^ expected one of `.`, `;`, `?`, or an operator here error: aborting due to previous error diff --git a/src/test/ui/parser/raw/raw-literal-keywords.stderr b/src/test/ui/parser/raw/raw-literal-keywords.stderr index 8465b6a6e8495..8b8b71373b504 100644 --- a/src/test/ui/parser/raw/raw-literal-keywords.stderr +++ b/src/test/ui/parser/raw/raw-literal-keywords.stderr @@ -1,37 +1,37 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `true` --> $DIR/raw-literal-keywords.rs:2:10 | -LL | r#if true { } //~ ERROR found `true` +LL | r#if true { } | ^^^^ expected one of 8 possible tokens here error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `Test` --> $DIR/raw-literal-keywords.rs:7:14 | -LL | r#struct Test; //~ ERROR found `Test` +LL | r#struct Test; | ^^^^ expected one of 8 possible tokens here error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `Test` --> $DIR/raw-literal-keywords.rs:12:13 | -LL | r#union Test; //~ ERROR found `Test` +LL | r#union Test; | ^^^^ expected one of 8 possible tokens here error[E0425]: cannot find value `if` in this scope --> $DIR/raw-literal-keywords.rs:2:5 | -LL | r#if true { } //~ ERROR found `true` +LL | r#if true { } | ^^^^ not found in this scope error[E0425]: cannot find value `struct` in this scope --> $DIR/raw-literal-keywords.rs:7:5 | -LL | r#struct Test; //~ ERROR found `Test` +LL | r#struct Test; | ^^^^^^^^ not found in this scope error[E0425]: cannot find value `union` in this scope --> $DIR/raw-literal-keywords.rs:12:5 | -LL | r#union Test; //~ ERROR found `Test` +LL | r#union Test; | ^^^^^^^ not found in this scope error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/raw/raw-literal-self.rs b/src/test/ui/parser/raw/raw-literal-self.rs index d7b9553d032d3..123a11b6f8543 100644 --- a/src/test/ui/parser/raw/raw-literal-self.rs +++ b/src/test/ui/parser/raw/raw-literal-self.rs @@ -1,3 +1,4 @@ -fn self_test(r#self: u32) { - //~^ ERROR `r#self` is not currently supported. +fn main() { + let r#self; + //~^ ERROR `self` cannot be a raw identifier } diff --git a/src/test/ui/parser/raw/raw-literal-self.stderr b/src/test/ui/parser/raw/raw-literal-self.stderr index e64332785cc51..9a330fcdf2aae 100644 --- a/src/test/ui/parser/raw/raw-literal-self.stderr +++ b/src/test/ui/parser/raw/raw-literal-self.stderr @@ -1,8 +1,8 @@ -error: `r#self` is not currently supported. - --> $DIR/raw-literal-self.rs:1:14 +error: `self` cannot be a raw identifier + --> $DIR/raw-literal-self.rs:2:9 | -LL | fn self_test(r#self: u32) { - | ^^^^^^ +LL | let r#self; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/raw/raw-literal-underscore.rs b/src/test/ui/parser/raw/raw-literal-underscore.rs index bbedd395202cf..6d15f1e7f0afd 100644 --- a/src/test/ui/parser/raw/raw-literal-underscore.rs +++ b/src/test/ui/parser/raw/raw-literal-underscore.rs @@ -1,3 +1,4 @@ -fn underscore_test(r#_: u32) { - //~^ ERROR `r#_` is not currently supported. +fn main() { + let r#_; + //~^ ERROR `_` cannot be a raw identifier } diff --git a/src/test/ui/parser/raw/raw-literal-underscore.stderr b/src/test/ui/parser/raw/raw-literal-underscore.stderr index 9427b33afd8d4..d96b14f55a39b 100644 --- a/src/test/ui/parser/raw/raw-literal-underscore.stderr +++ b/src/test/ui/parser/raw/raw-literal-underscore.stderr @@ -1,8 +1,8 @@ -error: `r#_` is not currently supported. - --> $DIR/raw-literal-underscore.rs:1:20 +error: `_` cannot be a raw identifier + --> $DIR/raw-literal-underscore.rs:2:9 | -LL | fn underscore_test(r#_: u32) { - | ^^^ +LL | let r#_; + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/recover-enum.rs b/src/test/ui/parser/recover-enum.rs index 204ad85716564..331bfff84f106 100644 --- a/src/test/ui/parser/recover-enum.rs +++ b/src/test/ui/parser/recover-enum.rs @@ -1,9 +1,11 @@ -// compile-flags: -Z continue-parse-after-error - fn main() { enum Test { Very - Bad //~ ERROR found `Bad` - Stuff + //~^ ERROR missing comma + Bad(usize) + //~^ ERROR missing comma + Stuff { a: usize } + //~^ ERROR missing comma + Here } } diff --git a/src/test/ui/parser/recover-enum.stderr b/src/test/ui/parser/recover-enum.stderr index 81e292939b020..81c7ae337dbeb 100644 --- a/src/test/ui/parser/recover-enum.stderr +++ b/src/test/ui/parser/recover-enum.stderr @@ -1,10 +1,20 @@ -error: expected one of `(`, `,`, `=`, `{`, or `}`, found `Bad` - --> $DIR/recover-enum.rs:6:9 +error: missing comma + --> $DIR/recover-enum.rs:3:13 | LL | Very - | - expected one of `(`, `,`, `=`, `{`, or `}` here -LL | Bad //~ ERROR found `Bad` - | ^^^ unexpected token + | ^ help: missing comma -error: aborting due to previous error +error: missing comma + --> $DIR/recover-enum.rs:5:19 + | +LL | Bad(usize) + | ^ help: missing comma + +error: missing comma + --> $DIR/recover-enum.rs:7:27 + | +LL | Stuff { a: usize } + | ^ help: missing comma + +error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/recover-enum2.rs b/src/test/ui/parser/recover-enum2.rs index 65a187737879d..0c9420889553b 100644 --- a/src/test/ui/parser/recover-enum2.rs +++ b/src/test/ui/parser/recover-enum2.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - fn main() { enum Test { Var1, @@ -25,9 +23,6 @@ fn main() { // fail again enum Test4 { Nope(i32 {}) //~ ERROR: found `{` - //~^ ERROR: found `{` } } - // still recover later - let bad_syntax = _; //~ ERROR: expected expression, found reserved identifier `_` } diff --git a/src/test/ui/parser/recover-enum2.stderr b/src/test/ui/parser/recover-enum2.stderr index b308e644ad9f8..9ed2e6f5eb6c4 100644 --- a/src/test/ui/parser/recover-enum2.stderr +++ b/src/test/ui/parser/recover-enum2.stderr @@ -1,26 +1,14 @@ error: expected type, found `{` - --> $DIR/recover-enum2.rs:8:18 + --> $DIR/recover-enum2.rs:6:18 | -LL | abc: {}, //~ ERROR: expected type, found `{` +LL | abc: {}, | ^ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{` - --> $DIR/recover-enum2.rs:27:22 + --> $DIR/recover-enum2.rs:25:22 | -LL | Nope(i32 {}) //~ ERROR: found `{` +LL | Nope(i32 {}) | ^ expected one of 7 possible tokens here -error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `...`, `::`, `<`, `?`, `[`, `_`, `crate`, `dyn`, `extern`, `fn`, `for`, `impl`, `pub`, `unsafe`, `}`, or lifetime, found `{` - --> $DIR/recover-enum2.rs:27:22 - | -LL | Nope(i32 {}) //~ ERROR: found `{` - | ^ expected one of 24 possible tokens here - -error: expected expression, found reserved identifier `_` - --> $DIR/recover-enum2.rs:32:22 - | -LL | let bad_syntax = _; //~ ERROR: expected expression, found reserved identifier `_` - | ^ expected expression - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/recover-from-bad-variant.rs b/src/test/ui/parser/recover-from-bad-variant.rs new file mode 100644 index 0000000000000..35088fb306882 --- /dev/null +++ b/src/test/ui/parser/recover-from-bad-variant.rs @@ -0,0 +1,14 @@ +enum Enum { + Foo { a: usize, b: usize }, + Bar(usize, usize), +} + +fn main() { + let x = Enum::Foo(a: 3, b: 4); + //~^ ERROR expected type, found `3` + match x { + Enum::Foo(a, b) => {} + //~^ ERROR expected tuple struct/variant, found struct variant `Enum::Foo` + Enum::Bar(a, b) => {} + } +} diff --git a/src/test/ui/parser/recover-from-bad-variant.stderr b/src/test/ui/parser/recover-from-bad-variant.stderr new file mode 100644 index 0000000000000..150d74f07428d --- /dev/null +++ b/src/test/ui/parser/recover-from-bad-variant.stderr @@ -0,0 +1,23 @@ +error: expected type, found `3` + --> $DIR/recover-from-bad-variant.rs:7:26 + | +LL | let x = Enum::Foo(a: 3, b: 4); + | ^ expecting a type here because of type ascription + | + = note: #![feature(type_ascription)] lets you annotate an expression with a type: `: ` +note: this expression expects an ascribed type after the colon + --> $DIR/recover-from-bad-variant.rs:7:23 + | +LL | let x = Enum::Foo(a: 3, b: 4); + | ^ + = help: this might be indicative of a syntax error elsewhere + +error[E0532]: expected tuple struct/variant, found struct variant `Enum::Foo` + --> $DIR/recover-from-bad-variant.rs:10:9 + | +LL | Enum::Foo(a, b) => {} + | ^^^^^^^^^ did you mean `Enum::Foo { /* fields */ }`? + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0532`. diff --git a/src/test/ui/parser/recover-missing-semi.rs b/src/test/ui/parser/recover-missing-semi.rs new file mode 100644 index 0000000000000..1893dc716bedc --- /dev/null +++ b/src/test/ui/parser/recover-missing-semi.rs @@ -0,0 +1,13 @@ +fn main() { + let _: usize = () + //~^ ERROR mismatched types + let _ = 3; + //~^ ERROR expected one of +} + +fn foo() -> usize { + let _: usize = () + //~^ ERROR mismatched types + return 3; + //~^ ERROR expected one of +} diff --git a/src/test/ui/parser/recover-missing-semi.stderr b/src/test/ui/parser/recover-missing-semi.stderr new file mode 100644 index 0000000000000..99339e4dd5025 --- /dev/null +++ b/src/test/ui/parser/recover-missing-semi.stderr @@ -0,0 +1,39 @@ +error: expected one of `.`, `;`, `?`, or an operator, found `let` + --> $DIR/recover-missing-semi.rs:4:5 + | +LL | let _: usize = () + | - help: a semicolon may be missing here +LL | +LL | let _ = 3; + | ^^^ + +error: expected one of `.`, `;`, `?`, or an operator, found `return` + --> $DIR/recover-missing-semi.rs:11:5 + | +LL | let _: usize = () + | - help: a semicolon may be missing here +LL | +LL | return 3; + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/recover-missing-semi.rs:2:20 + | +LL | let _: usize = () + | ^^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error[E0308]: mismatched types + --> $DIR/recover-missing-semi.rs:9:20 + | +LL | let _: usize = () + | ^^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/recover-struct.rs b/src/test/ui/parser/recover-struct.rs index 500591b2ad138..bfa5b454c0a8b 100644 --- a/src/test/ui/parser/recover-struct.rs +++ b/src/test/ui/parser/recover-struct.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - fn main() { struct Test { Very diff --git a/src/test/ui/parser/recover-struct.stderr b/src/test/ui/parser/recover-struct.stderr index edb3cb95cab2f..1b72184b0c886 100644 --- a/src/test/ui/parser/recover-struct.stderr +++ b/src/test/ui/parser/recover-struct.stderr @@ -1,9 +1,9 @@ error: expected `:`, found `Bad` - --> $DIR/recover-struct.rs:6:9 + --> $DIR/recover-struct.rs:4:9 | LL | Very | - expected `:` -LL | Bad //~ ERROR found `Bad` +LL | Bad | ^^^ unexpected token error: aborting due to previous error diff --git a/src/test/ui/parser/recover-tuple-pat.rs b/src/test/ui/parser/recover-tuple-pat.rs new file mode 100644 index 0000000000000..488e8db6b8789 --- /dev/null +++ b/src/test/ui/parser/recover-tuple-pat.rs @@ -0,0 +1,12 @@ +fn main() { + let x = (1, 2, 3, 4); + match x { + (1, .., 4) => {} + (1, .=., 4) => { let _: usize = ""; } + //~^ ERROR expected pattern, found `.` + //~| ERROR mismatched types + (.=., 4) => {} + //~^ ERROR expected pattern, found `.` + (1, 2, 3, 4) => {} + } +} diff --git a/src/test/ui/parser/recover-tuple-pat.stderr b/src/test/ui/parser/recover-tuple-pat.stderr new file mode 100644 index 0000000000000..5919aa72355ac --- /dev/null +++ b/src/test/ui/parser/recover-tuple-pat.stderr @@ -0,0 +1,24 @@ +error: expected pattern, found `.` + --> $DIR/recover-tuple-pat.rs:5:13 + | +LL | (1, .=., 4) => { let _: usize = ""; } + | ^ expected pattern + +error: expected pattern, found `.` + --> $DIR/recover-tuple-pat.rs:8:10 + | +LL | (.=., 4) => {} + | ^ expected pattern + +error[E0308]: mismatched types + --> $DIR/recover-tuple-pat.rs:5:41 + | +LL | (1, .=., 4) => { let _: usize = ""; } + | ^^ expected usize, found reference + | + = note: expected type `usize` + found type `&'static str` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/recover-tuple.rs b/src/test/ui/parser/recover-tuple.rs new file mode 100644 index 0000000000000..59e2695dec6dc --- /dev/null +++ b/src/test/ui/parser/recover-tuple.rs @@ -0,0 +1,11 @@ +fn main() { + // no complaints about the tuple not matching the expected type + let x: (usize, usize, usize) = (3, .=.); + //~^ ERROR expected expression, found `.` + // verify that the parser recovers: + let y: usize = ""; //~ ERROR mismatched types + // no complaints about the type + foo(x); +} + +fn foo(_: (usize, usize, usize)) {} diff --git a/src/test/ui/parser/recover-tuple.stderr b/src/test/ui/parser/recover-tuple.stderr new file mode 100644 index 0000000000000..4252fc1fd1e1b --- /dev/null +++ b/src/test/ui/parser/recover-tuple.stderr @@ -0,0 +1,18 @@ +error: expected expression, found `.` + --> $DIR/recover-tuple.rs:3:40 + | +LL | let x: (usize, usize, usize) = (3, .=.); + | ^ expected expression + +error[E0308]: mismatched types + --> $DIR/recover-tuple.rs:6:20 + | +LL | let y: usize = ""; + | ^^ expected usize, found reference + | + = note: expected type `usize` + found type `&'static str` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/recovered-struct-variant.rs b/src/test/ui/parser/recovered-struct-variant.rs new file mode 100644 index 0000000000000..5b195dcc37878 --- /dev/null +++ b/src/test/ui/parser/recovered-struct-variant.rs @@ -0,0 +1,13 @@ +enum Foo { + A { a, b: usize } + //~^ ERROR expected `:`, found `,` +} + +fn main() { + // no complaints about non-existing fields + let f = Foo::A { a:3, b: 4}; + match f { + // no complaints about non-existing fields + Foo::A {a, b} => {} + } +} diff --git a/src/test/ui/parser/recovered-struct-variant.stderr b/src/test/ui/parser/recovered-struct-variant.stderr new file mode 100644 index 0000000000000..51aaf8bb3cfbe --- /dev/null +++ b/src/test/ui/parser/recovered-struct-variant.stderr @@ -0,0 +1,8 @@ +error: expected `:`, found `,` + --> $DIR/recovered-struct-variant.rs:2:10 + | +LL | A { a, b: usize } + | ^ expected `:` + +error: aborting due to previous error + diff --git a/src/test/ui/parser/regions-out-of-scope-slice.stderr b/src/test/ui/parser/regions-out-of-scope-slice.stderr index cd56dfa6aeb7b..8d9bf0b7a0445 100644 --- a/src/test/ui/parser/regions-out-of-scope-slice.stderr +++ b/src/test/ui/parser/regions-out-of-scope-slice.stderr @@ -1,7 +1,7 @@ error: expected `:`, found `[` --> $DIR/regions-out-of-scope-slice.rs:7:19 | -LL | x = &'blk [1,2,3]; //~ ERROR expected `:`, found `[` +LL | x = &'blk [1,2,3]; | ^ expected `:` error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-enum-newtype.stderr b/src/test/ui/parser/removed-syntax-enum-newtype.stderr index 4c710dec5ba3d..a6d0ff4eaf2aa 100644 --- a/src/test/ui/parser/removed-syntax-enum-newtype.stderr +++ b/src/test/ui/parser/removed-syntax-enum-newtype.stderr @@ -1,7 +1,7 @@ error: expected one of `<`, `where`, or `{`, found `=` --> $DIR/removed-syntax-enum-newtype.rs:1:8 | -LL | enum e = isize; //~ ERROR expected one of `<`, `where`, or `{`, found `=` +LL | enum e = isize; | ^ expected one of `<`, `where`, or `{` here error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-field-let.rs b/src/test/ui/parser/removed-syntax-field-let.rs index 3412788668ac2..9fe4a148a56aa 100644 --- a/src/test/ui/parser/removed-syntax-field-let.rs +++ b/src/test/ui/parser/removed-syntax-field-let.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - struct S { let foo: (), //~^ ERROR expected identifier, found keyword `let` diff --git a/src/test/ui/parser/removed-syntax-field-let.stderr b/src/test/ui/parser/removed-syntax-field-let.stderr index 0d489beae123a..d6e38be4869eb 100644 --- a/src/test/ui/parser/removed-syntax-field-let.stderr +++ b/src/test/ui/parser/removed-syntax-field-let.stderr @@ -1,5 +1,5 @@ error: expected identifier, found keyword `let` - --> $DIR/removed-syntax-field-let.rs:4:5 + --> $DIR/removed-syntax-field-let.rs:2:5 | LL | let foo: (), | ^^^ expected identifier, found keyword @@ -9,7 +9,7 @@ LL | r#let foo: (), | ^^^^^ error: expected `:`, found `foo` - --> $DIR/removed-syntax-field-let.rs:4:9 + --> $DIR/removed-syntax-field-let.rs:2:9 | LL | let foo: (), | ^^^ expected `:` diff --git a/src/test/ui/parser/removed-syntax-fixed-vec.stderr b/src/test/ui/parser/removed-syntax-fixed-vec.stderr index 318591e5cc0a4..ca6969d1e8733 100644 --- a/src/test/ui/parser/removed-syntax-fixed-vec.stderr +++ b/src/test/ui/parser/removed-syntax-fixed-vec.stderr @@ -1,7 +1,7 @@ error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*` --> $DIR/removed-syntax-fixed-vec.rs:1:17 | -LL | type v = [isize * 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*` +LL | type v = [isize * 3]; | ^ expected one of 7 possible tokens here error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-fn-sigil.stderr b/src/test/ui/parser/removed-syntax-fn-sigil.stderr index 9303a67a8cc7b..196a5af472938 100644 --- a/src/test/ui/parser/removed-syntax-fn-sigil.stderr +++ b/src/test/ui/parser/removed-syntax-fn-sigil.stderr @@ -1,7 +1,7 @@ error: expected `(`, found `~` --> $DIR/removed-syntax-fn-sigil.rs:2:14 | -LL | let x: fn~() = || (); //~ ERROR expected `(`, found `~` +LL | let x: fn~() = || (); | - ^ expected `(` | | | while parsing the type for `x` diff --git a/src/test/ui/parser/removed-syntax-mut-vec-expr.stderr b/src/test/ui/parser/removed-syntax-mut-vec-expr.stderr index 8164645b01b7f..313420fb9a4fd 100644 --- a/src/test/ui/parser/removed-syntax-mut-vec-expr.stderr +++ b/src/test/ui/parser/removed-syntax-mut-vec-expr.stderr @@ -1,7 +1,7 @@ error: expected expression, found keyword `mut` --> $DIR/removed-syntax-mut-vec-expr.rs:2:14 | -LL | let v = [mut 1, 2, 3, 4]; //~ ERROR expected expression, found keyword `mut` +LL | let v = [mut 1, 2, 3, 4]; | ^^^ expected expression error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-mut-vec-ty.stderr b/src/test/ui/parser/removed-syntax-mut-vec-ty.stderr index f0eafa3d00a6f..a759716b5a963 100644 --- a/src/test/ui/parser/removed-syntax-mut-vec-ty.stderr +++ b/src/test/ui/parser/removed-syntax-mut-vec-ty.stderr @@ -1,7 +1,7 @@ error: expected type, found keyword `mut` --> $DIR/removed-syntax-mut-vec-ty.rs:1:11 | -LL | type v = [mut isize]; //~ ERROR expected type, found keyword `mut` +LL | type v = [mut isize]; | ^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-ptr-lifetime.stderr b/src/test/ui/parser/removed-syntax-ptr-lifetime.stderr index 689ed35668ec9..7beef9883bd7d 100644 --- a/src/test/ui/parser/removed-syntax-ptr-lifetime.stderr +++ b/src/test/ui/parser/removed-syntax-ptr-lifetime.stderr @@ -1,7 +1,7 @@ error: expected one of `!`, `(`, `::`, `;`, or `<`, found `/` --> $DIR/removed-syntax-ptr-lifetime.rs:1:22 | -LL | type bptr = &lifetime/isize; //~ ERROR expected one of `!`, `(`, `::`, `;`, or `<`, found `/` +LL | type bptr = &lifetime/isize; | ^ expected one of `!`, `(`, `::`, `;`, or `<` here error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-record.stderr b/src/test/ui/parser/removed-syntax-record.stderr index f9b98596ae399..730d5e2712b96 100644 --- a/src/test/ui/parser/removed-syntax-record.stderr +++ b/src/test/ui/parser/removed-syntax-record.stderr @@ -1,7 +1,7 @@ error: expected type, found `{` --> $DIR/removed-syntax-record.rs:1:10 | -LL | type t = { f: () }; //~ ERROR expected type, found `{` +LL | type t = { f: () }; | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-uniq-mut-expr.stderr b/src/test/ui/parser/removed-syntax-uniq-mut-expr.stderr index 90d0764def0bc..63d2fdb8cd4a9 100644 --- a/src/test/ui/parser/removed-syntax-uniq-mut-expr.stderr +++ b/src/test/ui/parser/removed-syntax-uniq-mut-expr.stderr @@ -1,7 +1,7 @@ error: expected expression, found keyword `mut` --> $DIR/removed-syntax-uniq-mut-expr.rs:2:21 | -LL | let a_box = box mut 42; //~ ERROR expected expression, found keyword `mut` +LL | let a_box = box mut 42; | ^^^ expected expression error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr b/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr index b2759778d0313..b6c5749c031e0 100644 --- a/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr +++ b/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr @@ -1,7 +1,7 @@ error: expected one of `>`, const, lifetime, or type, found `mut` --> $DIR/removed-syntax-uniq-mut-ty.rs:1:20 | -LL | type mut_box = Box; //~ ERROR expected one of `>`, const, lifetime, or type, found `mut` +LL | type mut_box = Box; | ^^^ expected one of `>`, const, lifetime, or type here error: aborting due to previous error diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.stderr b/src/test/ui/parser/require-parens-for-chained-comparison.stderr index 4597b14321513..76e548de045aa 100644 --- a/src/test/ui/parser/require-parens-for-chained-comparison.stderr +++ b/src/test/ui/parser/require-parens-for-chained-comparison.stderr @@ -38,14 +38,16 @@ LL | false == 0 < 2; found type `{integer}` error[E0369]: binary operation `<` cannot be applied to type `fn() {f::<_>}` - --> $DIR/require-parens-for-chained-comparison.rs:13:5 + --> $DIR/require-parens-for-chained-comparison.rs:13:6 | LL | f(); - | ^^^ + | -^- X + | | + | fn() {f::<_>} | = note: an implementation of `std::cmp::PartialOrd` might be missing for `fn() {f::<_>}` error: aborting due to 6 previous errors -Some errors occurred: E0308, E0369. +Some errors have detailed explanations: E0308, E0369. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/self-in-function-arg.rs b/src/test/ui/parser/self-in-function-arg.rs new file mode 100644 index 0000000000000..6172ffe1b0347 --- /dev/null +++ b/src/test/ui/parser/self-in-function-arg.rs @@ -0,0 +1,3 @@ +fn foo(x:i32, self: i32) -> i32 { self } //~ ERROR unexpected `self` parameter in function + +fn main() {} diff --git a/src/test/ui/parser/self-in-function-arg.stderr b/src/test/ui/parser/self-in-function-arg.stderr new file mode 100644 index 0000000000000..f58df9b9e79b3 --- /dev/null +++ b/src/test/ui/parser/self-in-function-arg.stderr @@ -0,0 +1,10 @@ +error: unexpected `self` parameter in function + --> $DIR/self-in-function-arg.rs:1:15 + | +LL | fn foo(x:i32, self: i32) -> i32 { self } + | ^^^^ not valid as function parameter + | + = note: `self` is only valid as the first parameter of an associated function + +error: aborting due to previous error + diff --git a/src/test/ui/parser/struct-literal-in-for.rs b/src/test/ui/parser/struct-literal-in-for.rs index 526b5e75c4574..3227ae37bfd05 100644 --- a/src/test/ui/parser/struct-literal-in-for.rs +++ b/src/test/ui/parser/struct-literal-in-for.rs @@ -9,9 +9,9 @@ impl Foo { } fn main() { - for x in Foo { //~ ERROR expected value, found struct `Foo` - x: 3 //~ ERROR expected type, found `3` - }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` + for x in Foo { //~ ERROR struct literals are not allowed here + x: 3 //~^ ERROR `bool` is not an iterator + }.hi() { println!("yo"); } } diff --git a/src/test/ui/parser/struct-literal-in-for.stderr b/src/test/ui/parser/struct-literal-in-for.stderr index 38a5e22e3f7b6..29af72a5d23d0 100644 --- a/src/test/ui/parser/struct-literal-in-for.stderr +++ b/src/test/ui/parser/struct-literal-in-for.stderr @@ -1,21 +1,30 @@ -error: expected type, found `3` - --> $DIR/struct-literal-in-for.rs:13:12 +error: struct literals are not allowed here + --> $DIR/struct-literal-in-for.rs:12:14 | -LL | x: 3 //~ ERROR expected type, found `3` - | ^ expecting a type here because of type ascription - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - --> $DIR/struct-literal-in-for.rs:14:12 +LL | for x in Foo { + | ______________^ +LL | | x: 3 +LL | | }.hi() { + | |_____^ +help: surround the struct literal with parentheses + | +LL | for x in (Foo { +LL | x: 3 +LL | }).hi() { | -LL | }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - | ^ expected one of `.`, `;`, `?`, `}`, or an operator here -error[E0423]: expected value, found struct `Foo` +error[E0277]: `bool` is not an iterator --> $DIR/struct-literal-in-for.rs:12:14 | -LL | for x in Foo { //~ ERROR expected value, found struct `Foo` - | ^^^ did you mean `(Foo { /* fields */ })`? +LL | for x in Foo { + | ______________^ +LL | | x: 3 +LL | | }.hi() { + | |__________^ `bool` is not an iterator + | + = help: the trait `std::iter::Iterator` is not implemented for `bool` + = note: required by `std::iter::IntoIterator::into_iter` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0423`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/parser/struct-literal-in-if.rs b/src/test/ui/parser/struct-literal-in-if.rs index 362a71c577fc9..2ce2c8f189944 100644 --- a/src/test/ui/parser/struct-literal-in-if.rs +++ b/src/test/ui/parser/struct-literal-in-if.rs @@ -9,9 +9,9 @@ impl Foo { } fn main() { - if Foo { //~ ERROR expected value, found struct `Foo` - x: 3 //~ ERROR expected type, found `3` - }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` + if Foo { //~ ERROR struct literals are not allowed here + x: 3 + }.hi() { println!("yo"); } } diff --git a/src/test/ui/parser/struct-literal-in-if.stderr b/src/test/ui/parser/struct-literal-in-if.stderr index 49b9a52aff918..e76c1cb45dd4e 100644 --- a/src/test/ui/parser/struct-literal-in-if.stderr +++ b/src/test/ui/parser/struct-literal-in-if.stderr @@ -1,21 +1,17 @@ -error: expected type, found `3` - --> $DIR/struct-literal-in-if.rs:13:12 +error: struct literals are not allowed here + --> $DIR/struct-literal-in-if.rs:12:8 | -LL | x: 3 //~ ERROR expected type, found `3` - | ^ expecting a type here because of type ascription - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - --> $DIR/struct-literal-in-if.rs:14:12 +LL | if Foo { + | ________^ +LL | | x: 3 +LL | | }.hi() { + | |_____^ +help: surround the struct literal with parentheses | -LL | }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - | ^ expected one of `.`, `;`, `?`, `}`, or an operator here - -error[E0423]: expected value, found struct `Foo` - --> $DIR/struct-literal-in-if.rs:12:8 +LL | if (Foo { +LL | x: 3 +LL | }).hi() { | -LL | if Foo { //~ ERROR expected value, found struct `Foo` - | ^^^ did you mean `(Foo { /* fields */ })`? -error: aborting due to 3 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0423`. diff --git a/src/test/ui/parser/struct-literal-in-match-discriminant.rs b/src/test/ui/parser/struct-literal-in-match-discriminant.rs index 35a1109035146..ce132df5a888b 100644 --- a/src/test/ui/parser/struct-literal-in-match-discriminant.rs +++ b/src/test/ui/parser/struct-literal-in-match-discriminant.rs @@ -3,11 +3,11 @@ struct Foo { } fn main() { - match Foo { //~ ERROR expected value, found struct `Foo` - x: 3 //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `:` + match Foo { //~ ERROR struct literals are not allowed here + x: 3 } { - Foo { //~ ERROR mismatched types - x: x //~ ERROR cannot find value `x` in this scope - } => {} //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `=>` + Foo { + x: x + } => {} } } diff --git a/src/test/ui/parser/struct-literal-in-match-discriminant.stderr b/src/test/ui/parser/struct-literal-in-match-discriminant.stderr index 64ddde0e9e97f..95b0882b7aeb5 100644 --- a/src/test/ui/parser/struct-literal-in-match-discriminant.stderr +++ b/src/test/ui/parser/struct-literal-in-match-discriminant.stderr @@ -1,42 +1,17 @@ -error: expected one of `=>`, `@`, `if`, or `|`, found `:` - --> $DIR/struct-literal-in-match-discriminant.rs:7:10 - | -LL | x: 3 //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `:` - | ^ expected one of `=>`, `@`, `if`, or `|` here - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `=>` - --> $DIR/struct-literal-in-match-discriminant.rs:11:11 - | -LL | } => {} //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `=>` - | ^^ expected one of `.`, `;`, `?`, `}`, or an operator here - -error[E0423]: expected value, found struct `Foo` +error: struct literals are not allowed here --> $DIR/struct-literal-in-match-discriminant.rs:6:11 | -LL | match Foo { //~ ERROR expected value, found struct `Foo` - | ^^^ did you mean `(Foo { /* fields */ })`? - -error[E0425]: cannot find value `x` in this scope - --> $DIR/struct-literal-in-match-discriminant.rs:10:16 - | -LL | x: x //~ ERROR cannot find value `x` in this scope - | ^ not found in this scope - -error[E0308]: mismatched types - --> $DIR/struct-literal-in-match-discriminant.rs:9:9 +LL | match Foo { + | ___________^ +LL | | x: 3 +LL | | } { + | |_____^ +help: surround the struct literal with parentheses | -LL | fn main() { - | - expected `()` because of default return type -... -LL | / Foo { //~ ERROR mismatched types -LL | | x: x //~ ERROR cannot find value `x` in this scope -LL | | } => {} //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `=>` - | |_________^ expected (), found struct `Foo` +LL | match (Foo { +LL | x: 3 +LL | }) { | - = note: expected type `()` - found type `Foo` -error: aborting due to 5 previous errors +error: aborting due to previous error -Some errors occurred: E0308, E0423, E0425. -For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/struct-literal-in-while.rs b/src/test/ui/parser/struct-literal-in-while.rs index 561cdcea089a5..5000ce85b7f71 100644 --- a/src/test/ui/parser/struct-literal-in-while.rs +++ b/src/test/ui/parser/struct-literal-in-while.rs @@ -9,10 +9,9 @@ impl Foo { } fn main() { - while Foo { //~ ERROR expected value, found struct `Foo` - x: 3 //~ ERROR expected type, found `3` - }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - //~| ERROR no method named `hi` found for type `()` in the current scope + while Foo { //~ ERROR struct literals are not allowed here + x: 3 + }.hi() { println!("yo"); } } diff --git a/src/test/ui/parser/struct-literal-in-while.stderr b/src/test/ui/parser/struct-literal-in-while.stderr index 9a6ab81e7c02f..acd31b477dc27 100644 --- a/src/test/ui/parser/struct-literal-in-while.stderr +++ b/src/test/ui/parser/struct-literal-in-while.stderr @@ -1,28 +1,17 @@ -error: expected type, found `3` - --> $DIR/struct-literal-in-while.rs:13:12 - | -LL | x: 3 //~ ERROR expected type, found `3` - | ^ expecting a type here because of type ascription - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - --> $DIR/struct-literal-in-while.rs:14:12 - | -LL | }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - | ^ expected one of `.`, `;`, `?`, `}`, or an operator here - -error[E0423]: expected value, found struct `Foo` +error: struct literals are not allowed here --> $DIR/struct-literal-in-while.rs:12:11 | -LL | while Foo { //~ ERROR expected value, found struct `Foo` - | ^^^ did you mean `(Foo { /* fields */ })`? - -error[E0599]: no method named `hi` found for type `()` in the current scope - --> $DIR/struct-literal-in-while.rs:14:7 +LL | while Foo { + | ___________^ +LL | | x: 3 +LL | | }.hi() { + | |_____^ +help: surround the struct literal with parentheses + | +LL | while (Foo { +LL | x: 3 +LL | }).hi() { | -LL | }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - | ^^ -error: aborting due to 4 previous errors +error: aborting due to previous error -Some errors occurred: E0423, E0599. -For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/parser/struct-literal-restrictions-in-lamda.rs b/src/test/ui/parser/struct-literal-restrictions-in-lamda.rs index e5049082ab016..e185153dcf62a 100644 --- a/src/test/ui/parser/struct-literal-restrictions-in-lamda.rs +++ b/src/test/ui/parser/struct-literal-restrictions-in-lamda.rs @@ -9,10 +9,9 @@ impl Foo { } fn main() { - while || Foo { //~ ERROR expected value, found struct `Foo` - x: 3 //~ ERROR expected type, found `3` - }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - //~| ERROR no method named `hi` found for type `()` in the current scope + while || Foo { //~ ERROR struct literals are not allowed here + x: 3 //~^ ERROR mismatched types + }.hi() { println!("yo"); } } diff --git a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr index 2303df93810cd..24078074161e6 100644 --- a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr +++ b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr @@ -1,28 +1,30 @@ -error: expected type, found `3` - --> $DIR/struct-literal-restrictions-in-lamda.rs:13:12 +error: struct literals are not allowed here + --> $DIR/struct-literal-restrictions-in-lamda.rs:12:14 | -LL | x: 3 //~ ERROR expected type, found `3` - | ^ expecting a type here because of type ascription - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - --> $DIR/struct-literal-restrictions-in-lamda.rs:14:12 +LL | while || Foo { + | ______________^ +LL | | x: 3 +LL | | }.hi() { + | |_____^ +help: surround the struct literal with parentheses | -LL | }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - | ^ expected one of `.`, `;`, `?`, `}`, or an operator here - -error[E0423]: expected value, found struct `Foo` - --> $DIR/struct-literal-restrictions-in-lamda.rs:12:14 +LL | while || (Foo { +LL | x: 3 +LL | }).hi() { | -LL | while || Foo { //~ ERROR expected value, found struct `Foo` - | ^^^ did you mean `(Foo { /* fields */ })`? -error[E0599]: no method named `hi` found for type `()` in the current scope - --> $DIR/struct-literal-restrictions-in-lamda.rs:14:7 +error[E0308]: mismatched types + --> $DIR/struct-literal-restrictions-in-lamda.rs:12:11 + | +LL | while || Foo { + | ___________^ +LL | | x: 3 +LL | | }.hi() { + | |__________^ expected bool, found closure | -LL | }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - | ^^ + = note: expected type `bool` + found type `[closure@$DIR/struct-literal-restrictions-in-lamda.rs:12:11: 14:11]` -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0423, E0599. -For more information about an error, try `rustc --explain E0423`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/tag-variant-disr-non-nullary.rs b/src/test/ui/parser/tag-variant-disr-non-nullary.rs index 83a3b727982b5..a9cfdd549c752 100644 --- a/src/test/ui/parser/tag-variant-disr-non-nullary.rs +++ b/src/test/ui/parser/tag-variant-disr-non-nullary.rs @@ -1,11 +1,12 @@ enum Color { Red = 0xff0000, - //~^ ERROR discriminator values can only be used with a field-less enum + //~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants Green = 0x00ff00, Blue = 0x0000ff, Black = 0x000000, White = 0xffffff, Other(usize), + Other2(usize, usize), } fn main() {} diff --git a/src/test/ui/parser/tag-variant-disr-non-nullary.stderr b/src/test/ui/parser/tag-variant-disr-non-nullary.stderr index cc6312b454551..13b46c6e8b3e5 100644 --- a/src/test/ui/parser/tag-variant-disr-non-nullary.stderr +++ b/src/test/ui/parser/tag-variant-disr-non-nullary.stderr @@ -1,17 +1,25 @@ -error: discriminator values can only be used with a field-less enum +error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants --> $DIR/tag-variant-disr-non-nullary.rs:2:11 | LL | Red = 0xff0000, - | ^^^^^^^^ only valid in field-less enums -LL | //~^ ERROR discriminator values can only be used with a field-less enum + | ^^^^^^^^ disallowed custom discriminant +LL | LL | Green = 0x00ff00, - | ^^^^^^^^ only valid in field-less enums + | ^^^^^^^^ disallowed custom discriminant LL | Blue = 0x0000ff, - | ^^^^^^^^ only valid in field-less enums + | ^^^^^^^^ disallowed custom discriminant LL | Black = 0x000000, - | ^^^^^^^^ only valid in field-less enums + | ^^^^^^^^ disallowed custom discriminant LL | White = 0xffffff, - | ^^^^^^^^ only valid in field-less enums + | ^^^^^^^^ disallowed custom discriminant +LL | Other(usize), + | ------------ tuple variant defined here +LL | Other2(usize, usize), + | -------------------- tuple variant defined here + | + = note: for more information, see https://github.com/rust-lang/rust/issues/60553 + = help: add #![feature(arbitrary_enum_discriminant)] to the crate attributes to enable error: aborting due to previous error +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/parser/trailing-carriage-return-in-string.stderr b/src/test/ui/parser/trailing-carriage-return-in-string.stderr index 972e4296da358..3687b9dd282d1 100644 --- a/src/test/ui/parser/trailing-carriage-return-in-string.stderr +++ b/src/test/ui/parser/trailing-carriage-return-in-string.stderr @@ -1,14 +1,10 @@ -error: unknown character escape: /r +error: unknown character escape: \r --> $DIR/trailing-carriage-return-in-string.rs:10:25 | -LL | let bad = "This is / a test"; - | ^ +LL | let bad = "This is \ a test"; + | ^ unknown character escape | -help: this is an isolated carriage return; consider checking your editor and version control settings - --> $DIR/trailing-carriage-return-in-string.rs:10:25 - | -LL | let bad = "This is / a test"; - | ^ + = help: this is an isolated carriage return; consider checking your editor and version control settings error: aborting due to previous error diff --git a/src/test/ui/parser/trailing-plus-in-bounds.rs b/src/test/ui/parser/trailing-plus-in-bounds.rs index 153f942b978a8..3213e06805371 100644 --- a/src/test/ui/parser/trailing-plus-in-bounds.rs +++ b/src/test/ui/parser/trailing-plus-in-bounds.rs @@ -1,7 +1,7 @@ // compile-pass -// compile-flags: -Z continue-parse-after-error #![feature(box_syntax)] +#![allow(bare_trait_objects)] use std::fmt::Debug; diff --git a/src/test/ui/parser/trait-bounds-not-on-impl.rs b/src/test/ui/parser/trait-bounds-not-on-impl.rs index d77ff80ca2597..02563847ef326 100644 --- a/src/test/ui/parser/trait-bounds-not-on-impl.rs +++ b/src/test/ui/parser/trait-bounds-not-on-impl.rs @@ -1,11 +1,7 @@ -// compile-flags: -Z continue-parse-after-error - -trait Foo { -} +trait Foo {} struct Bar; -impl Foo + Owned for Bar { //~ ERROR expected a trait, found type -} +impl Foo + Owned for Bar {} //~ ERROR expected a trait, found type fn main() { } diff --git a/src/test/ui/parser/trait-bounds-not-on-impl.stderr b/src/test/ui/parser/trait-bounds-not-on-impl.stderr index 3c0346c96b282..8d2d5e3d7ddd2 100644 --- a/src/test/ui/parser/trait-bounds-not-on-impl.stderr +++ b/src/test/ui/parser/trait-bounds-not-on-impl.stderr @@ -1,7 +1,7 @@ error: expected a trait, found type - --> $DIR/trait-bounds-not-on-impl.rs:8:6 + --> $DIR/trait-bounds-not-on-impl.rs:5:6 | -LL | impl Foo + Owned for Bar { //~ ERROR expected a trait, found type +LL | impl Foo + Owned for Bar {} | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/trait-object-bad-parens.rs b/src/test/ui/parser/trait-object-bad-parens.rs index 0f1f49a521bd6..048e028be1ca1 100644 --- a/src/test/ui/parser/trait-object-bad-parens.rs +++ b/src/test/ui/parser/trait-object-bad-parens.rs @@ -1,6 +1,5 @@ -// compile-flags: -Z continue-parse-after-error - #![feature(optin_builtin_traits)] +#![allow(bare_trait_objects)] auto trait Auto {} diff --git a/src/test/ui/parser/trait-object-bad-parens.stderr b/src/test/ui/parser/trait-object-bad-parens.stderr index 74e484eebee1f..f53afdff5e7c2 100644 --- a/src/test/ui/parser/trait-object-bad-parens.stderr +++ b/src/test/ui/parser/trait-object-bad-parens.stderr @@ -1,23 +1,23 @@ error[E0178]: expected a path on the left-hand side of `+`, not `((Auto))` - --> $DIR/trait-object-bad-parens.rs:8:16 + --> $DIR/trait-object-bad-parens.rs:7:16 | LL | let _: Box<((Auto)) + Auto>; | ^^^^^^^^^^^^^^^ expected a path error[E0178]: expected a path on the left-hand side of `+`, not `(Auto + Auto)` - --> $DIR/trait-object-bad-parens.rs:10:16 + --> $DIR/trait-object-bad-parens.rs:9:16 | LL | let _: Box<(Auto + Auto) + Auto>; | ^^^^^^^^^^^^^^^^^^^^ expected a path error[E0178]: expected a path on the left-hand side of `+`, not `(Auto)` - --> $DIR/trait-object-bad-parens.rs:12:16 + --> $DIR/trait-object-bad-parens.rs:11:16 | LL | let _: Box<(Auto +) + Auto>; | ^^^^^^^^^^^^^^^ expected a path error[E0178]: expected a path on the left-hand side of `+`, not `(dyn Auto)` - --> $DIR/trait-object-bad-parens.rs:14:16 + --> $DIR/trait-object-bad-parens.rs:13:16 | LL | let _: Box<(dyn Auto) + Auto>; | ^^^^^^^^^^^^^^^^^ expected a path diff --git a/src/test/ui/parser/trait-object-lifetime-parens.rs b/src/test/ui/parser/trait-object-lifetime-parens.rs index b188e14778be5..5bbda4296ca7e 100644 --- a/src/test/ui/parser/trait-object-lifetime-parens.rs +++ b/src/test/ui/parser/trait-object-lifetime-parens.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z continue-parse-after-error +#![allow(bare_trait_objects)] trait Trait {} @@ -6,7 +6,10 @@ fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not s fn check<'a>() { let _: Box; //~ ERROR parenthesized lifetime bounds are not supported - let _: Box<('a) + Trait>; //~ ERROR expected type, found `'a` + let _: Box<('a) + Trait>; + //~^ ERROR expected type, found `'a` + //~| ERROR expected `:`, found `)` + //~| ERROR chained comparison operators require parentheses } fn main() {} diff --git a/src/test/ui/parser/trait-object-lifetime-parens.stderr b/src/test/ui/parser/trait-object-lifetime-parens.stderr index 94ca66aef729b..a31b7aea8fee6 100644 --- a/src/test/ui/parser/trait-object-lifetime-parens.stderr +++ b/src/test/ui/parser/trait-object-lifetime-parens.stderr @@ -1,22 +1,37 @@ error: parenthesized lifetime bounds are not supported --> $DIR/trait-object-lifetime-parens.rs:5:21 | -LL | fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not supported +LL | fn f<'a, T: Trait + ('a)>() {} | ^^^^ help: remove the parentheses error: parenthesized lifetime bounds are not supported --> $DIR/trait-object-lifetime-parens.rs:8:24 | -LL | let _: Box; //~ ERROR parenthesized lifetime bounds are not supported +LL | let _: Box; | ^^^^ help: remove the parentheses +error: expected `:`, found `)` + --> $DIR/trait-object-lifetime-parens.rs:9:19 + | +LL | let _: Box<('a) + Trait>; + | ^ expected `:` + +error: chained comparison operators require parentheses + --> $DIR/trait-object-lifetime-parens.rs:9:15 + | +LL | let _: Box<('a) + Trait>; + | ^^^^^^^^^^^^^^^ + | + = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + = help: or use `(...)` if you meant to specify fn arguments + error: expected type, found `'a` --> $DIR/trait-object-lifetime-parens.rs:9:17 | -LL | let _: Box<('a) + Trait>; //~ ERROR expected type, found `'a` +LL | let _: Box<('a) + Trait>; | - ^^ | | | while parsing the type for `_` -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/trait-object-polytrait-priority.rs b/src/test/ui/parser/trait-object-polytrait-priority.rs index 40d2ad52c3574..63425f3e20186 100644 --- a/src/test/ui/parser/trait-object-polytrait-priority.rs +++ b/src/test/ui/parser/trait-object-polytrait-priority.rs @@ -1,3 +1,5 @@ +#![allow(bare_trait_objects)] + trait Trait<'a> {} fn main() { diff --git a/src/test/ui/parser/trait-object-polytrait-priority.stderr b/src/test/ui/parser/trait-object-polytrait-priority.stderr index 5e2a35ea60cb0..a6add6079cece 100644 --- a/src/test/ui/parser/trait-object-polytrait-priority.stderr +++ b/src/test/ui/parser/trait-object-polytrait-priority.stderr @@ -1,5 +1,5 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>` - --> $DIR/trait-object-polytrait-priority.rs:4:12 + --> $DIR/trait-object-polytrait-priority.rs:6:12 | LL | let _: &for<'a> Trait<'a> + 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try adding parentheses: `&(for<'a> Trait<'a> + 'static)` diff --git a/src/test/ui/parser/trait-object-trait-parens.rs b/src/test/ui/parser/trait-object-trait-parens.rs index 2bbc5800015bd..a113de14b6fbc 100644 --- a/src/test/ui/parser/trait-object-trait-parens.rs +++ b/src/test/ui/parser/trait-object-trait-parens.rs @@ -5,8 +5,11 @@ fn f Trait<'a>)>() {} fn main() { let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; //~^ ERROR `?Trait` is not permitted in trait object types + //~| WARN trait objects without an explicit `dyn` are deprecated let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>; + //~^ WARN trait objects without an explicit `dyn` are deprecated let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; - //~^ ERROR `?Trait` is not permitted in trait object types - //~| ERROR use of undeclared lifetime name `'a` + //~^ ERROR use of undeclared lifetime name `'a` + //~| ERROR `?Trait` is not permitted in trait object types + //~| WARN trait objects without an explicit `dyn` are deprecated } diff --git a/src/test/ui/parser/trait-object-trait-parens.stderr b/src/test/ui/parser/trait-object-trait-parens.stderr index 36494b765394c..e3fb8a0113a66 100644 --- a/src/test/ui/parser/trait-object-trait-parens.stderr +++ b/src/test/ui/parser/trait-object-trait-parens.stderr @@ -5,13 +5,33 @@ LL | let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; | ^^^^^^^^ error: `?Trait` is not permitted in trait object types - --> $DIR/trait-object-trait-parens.rs:9:47 + --> $DIR/trait-object-trait-parens.rs:11:47 | LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; | ^^^^^^^^ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/trait-object-trait-parens.rs:6:16 + | +LL | let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (Copy) + (?Sized) + (for<'a> Trait<'a>)` + | + = note: #[warn(bare_trait_objects)] on by default + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/trait-object-trait-parens.rs:9:16 + | +LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (?Sized) + (for<'a> Trait<'a>) + (Copy)` + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/trait-object-trait-parens.rs:11:16 + | +LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (for<'a> Trait<'a>) + (Copy) + (?Sized)` + error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/trait-object-trait-parens.rs:9:31 + --> $DIR/trait-object-trait-parens.rs:11:31 | LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; | ^^ undeclared lifetime diff --git a/src/test/ui/parser/trait-pub-assoc-const.rs b/src/test/ui/parser/trait-pub-assoc-const.rs index 3ee2dc1ae18fb..219ffa309c254 100644 --- a/src/test/ui/parser/trait-pub-assoc-const.rs +++ b/src/test/ui/parser/trait-pub-assoc-const.rs @@ -1,6 +1,6 @@ trait Foo { pub const Foo: u32; - //~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found + //~^ ERROR unnecessary visibility qualifier } fn main() {} diff --git a/src/test/ui/parser/trait-pub-assoc-const.stderr b/src/test/ui/parser/trait-pub-assoc-const.stderr index 8fc9ae4cf28b4..817692cc82c86 100644 --- a/src/test/ui/parser/trait-pub-assoc-const.stderr +++ b/src/test/ui/parser/trait-pub-assoc-const.stderr @@ -1,10 +1,8 @@ -error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub` +error: unnecessary visibility qualifier --> $DIR/trait-pub-assoc-const.rs:2:5 | -LL | trait Foo { - | - expected one of 7 possible tokens here LL | pub const Foo: u32; - | ^^^ unexpected token + | ^^^ `pub` not permitted here error: aborting due to previous error diff --git a/src/test/ui/parser/trait-pub-assoc-ty.rs b/src/test/ui/parser/trait-pub-assoc-ty.rs index 042addfd1a434..a78dfbdcddaad 100644 --- a/src/test/ui/parser/trait-pub-assoc-ty.rs +++ b/src/test/ui/parser/trait-pub-assoc-ty.rs @@ -1,6 +1,6 @@ trait Foo { pub type Foo; - //~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found + //~^ ERROR unnecessary visibility qualifier } fn main() {} diff --git a/src/test/ui/parser/trait-pub-assoc-ty.stderr b/src/test/ui/parser/trait-pub-assoc-ty.stderr index b8eab4e87bf0b..400be6af22a82 100644 --- a/src/test/ui/parser/trait-pub-assoc-ty.stderr +++ b/src/test/ui/parser/trait-pub-assoc-ty.stderr @@ -1,10 +1,8 @@ -error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub` +error: unnecessary visibility qualifier --> $DIR/trait-pub-assoc-ty.rs:2:5 | -LL | trait Foo { - | - expected one of 7 possible tokens here LL | pub type Foo; - | ^^^ unexpected token + | ^^^ `pub` not permitted here error: aborting due to previous error diff --git a/src/test/ui/parser/trait-pub-method.rs b/src/test/ui/parser/trait-pub-method.rs index 9675182c1561e..1f6ee028a174b 100644 --- a/src/test/ui/parser/trait-pub-method.rs +++ b/src/test/ui/parser/trait-pub-method.rs @@ -1,6 +1,6 @@ trait Foo { pub fn foo(); - //~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found + //~^ ERROR unnecessary visibility qualifier } fn main() {} diff --git a/src/test/ui/parser/trait-pub-method.stderr b/src/test/ui/parser/trait-pub-method.stderr index d4db961c3fa9c..b3617a4aa9b01 100644 --- a/src/test/ui/parser/trait-pub-method.stderr +++ b/src/test/ui/parser/trait-pub-method.stderr @@ -1,10 +1,8 @@ -error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub` +error: unnecessary visibility qualifier --> $DIR/trait-pub-method.rs:2:5 | -LL | trait Foo { - | - expected one of 7 possible tokens here LL | pub fn foo(); - | ^^^ unexpected token + | ^^^ `pub` not permitted here error: aborting due to previous error diff --git a/src/test/ui/parser/unclosed-braces.stderr b/src/test/ui/parser/unclosed-braces.stderr index 3ab366446d86e..44c7e930a3a43 100644 --- a/src/test/ui/parser/unclosed-braces.stderr +++ b/src/test/ui/parser/unclosed-braces.stderr @@ -10,7 +10,7 @@ LL | { LL | } | - ...as it matches this but it has different indentation ... -LL | //~ ERROR this file contains an un-closed delimiter +LL | | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/unclosed-delimiter-in-dep.rs b/src/test/ui/parser/unclosed-delimiter-in-dep.rs new file mode 100644 index 0000000000000..6db1b66e9f785 --- /dev/null +++ b/src/test/ui/parser/unclosed-delimiter-in-dep.rs @@ -0,0 +1,6 @@ +mod unclosed_delim_mod; + +fn main() { + let _: usize = unclosed_delim_mod::new(); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/parser/unclosed-delimiter-in-dep.stderr b/src/test/ui/parser/unclosed-delimiter-in-dep.stderr new file mode 100644 index 0000000000000..633c63bea9105 --- /dev/null +++ b/src/test/ui/parser/unclosed-delimiter-in-dep.stderr @@ -0,0 +1,23 @@ +error: incorrect close delimiter: `}` + --> $DIR/unclosed_delim_mod.rs:5:1 + | +LL | pub fn new() -> Result { + | - close delimiter possibly meant for this +LL | Ok(Value { + | - un-closed delimiter +LL | } +LL | } + | ^ incorrect close delimiter + +error[E0308]: mismatched types + --> $DIR/unclosed-delimiter-in-dep.rs:4:20 + | +LL | let _: usize = unclosed_delim_mod::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected usize, found enum `std::result::Result` + | + = note: expected type `usize` + found type `std::result::Result` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/unclosed_delim_mod.rs b/src/test/ui/parser/unclosed_delim_mod.rs new file mode 100644 index 0000000000000..b1664f49dc591 --- /dev/null +++ b/src/test/ui/parser/unclosed_delim_mod.rs @@ -0,0 +1,6 @@ +pub struct Value {} +pub fn new() -> Result { + Ok(Value { + } +} +//~^ ERROR incorrect close delimiter diff --git a/src/test/ui/parser/unclosed_delim_mod.stderr b/src/test/ui/parser/unclosed_delim_mod.stderr new file mode 100644 index 0000000000000..cc04eb531cbea --- /dev/null +++ b/src/test/ui/parser/unclosed_delim_mod.stderr @@ -0,0 +1,18 @@ +error: incorrect close delimiter: `}` + --> $DIR/unclosed_delim_mod.rs:5:1 + | +LL | pub fn new() -> Result { + | - close delimiter possibly meant for this +LL | Ok(Value { + | - un-closed delimiter +LL | } +LL | } + | ^ incorrect close delimiter + +error[E0601]: `main` function not found in crate `unclosed_delim_mod` + | + = note: consider adding a `main` function to `$DIR/unclosed_delim_mod.rs` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/parser/underscore-suffix-for-float.stderr b/src/test/ui/parser/underscore-suffix-for-float.stderr index 58adcbbba76ba..a5f3b6551aa27 100644 --- a/src/test/ui/parser/underscore-suffix-for-float.stderr +++ b/src/test/ui/parser/underscore-suffix-for-float.stderr @@ -1,13 +1,13 @@ error: expected identifier, found reserved identifier `_` --> $DIR/underscore-suffix-for-float.rs:2:16 | -LL | let a = 42._; //~ ERROR expected identifier, found reserved identifier `_` +LL | let a = 42._; | ^ expected identifier, found reserved identifier error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> $DIR/underscore-suffix-for-float.rs:2:16 | -LL | let a = 42._; //~ ERROR expected identifier, found reserved identifier `_` +LL | let a = 42._; | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/underscore_item_not_const.rs b/src/test/ui/parser/underscore_item_not_const.rs new file mode 100644 index 0000000000000..375bdc3a46369 --- /dev/null +++ b/src/test/ui/parser/underscore_item_not_const.rs @@ -0,0 +1,30 @@ +// Test that various non-const items and associated consts do not permit `_` as a name. + +// Associated `const`s: + +pub trait A { + const _: () = (); //~ ERROR expected identifier, found reserved identifier `_` +} +impl A for () { + const _: () = (); //~ ERROR expected identifier, found reserved identifier `_` +} +impl dyn A { + const _: () = (); //~ ERROR expected identifier, found reserved identifier `_` +} + +// Other kinds of items: + +static _: () = (); //~ ERROR expected identifier, found reserved identifier `_` +struct _(); //~ ERROR expected identifier, found reserved identifier `_` +enum _ {} //~ ERROR expected identifier, found reserved identifier `_` +fn _() {} //~ ERROR expected identifier, found reserved identifier `_` +mod _ {} //~ ERROR expected identifier, found reserved identifier `_` +type _ = (); //~ ERROR expected identifier, found reserved identifier `_` +use _; //~ ERROR expected identifier, found reserved identifier `_` +use _ as g; //~ ERROR expected identifier, found reserved identifier `_` +trait _ {} //~ ERROR expected identifier, found reserved identifier `_` +trait _ = Copy; //~ ERROR expected identifier, found reserved identifier `_` +macro_rules! _ { () => {} } //~ ERROR expected identifier, found reserved identifier `_` +union _ { f: u8 } //~ ERROR expected one of `!` or `::`, found `_` + +fn main() {} diff --git a/src/test/ui/parser/underscore_item_not_const.stderr b/src/test/ui/parser/underscore_item_not_const.stderr new file mode 100644 index 0000000000000..deb4a012e32ab --- /dev/null +++ b/src/test/ui/parser/underscore_item_not_const.stderr @@ -0,0 +1,92 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:6:11 + | +LL | const _: () = (); + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:9:11 + | +LL | const _: () = (); + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:12:11 + | +LL | const _: () = (); + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:17:8 + | +LL | static _: () = (); + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:18:8 + | +LL | struct _(); + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:19:6 + | +LL | enum _ {} + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:20:4 + | +LL | fn _() {} + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:21:5 + | +LL | mod _ {} + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:22:6 + | +LL | type _ = (); + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:23:5 + | +LL | use _; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:24:5 + | +LL | use _ as g; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:25:7 + | +LL | trait _ {} + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:26:7 + | +LL | trait _ = Copy; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_item_not_const.rs:27:14 + | +LL | macro_rules! _ { () => {} } + | ^ expected identifier, found reserved identifier + +error: expected one of `!` or `::`, found `_` + --> $DIR/underscore_item_not_const.rs:28:7 + | +LL | union _ { f: u8 } + | ^ expected one of `!` or `::` here + +error: aborting due to 15 previous errors + diff --git a/src/test/ui/parser/underscore_static.rs b/src/test/ui/parser/underscore_static.rs deleted file mode 100644 index 21d6a1bc1b360..0000000000000 --- a/src/test/ui/parser/underscore_static.rs +++ /dev/null @@ -1,3 +0,0 @@ -static _: () = (); //~ ERROR expected identifier, found reserved identifier `_` - -fn main() {} diff --git a/src/test/ui/parser/underscore_static.stderr b/src/test/ui/parser/underscore_static.stderr deleted file mode 100644 index 3bf3ce88a63c2..0000000000000 --- a/src/test/ui/parser/underscore_static.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_static.rs:1:8 - | -LL | static _: () = (); //~ ERROR expected identifier, found reserved identifier `_` - | ^ expected identifier, found reserved identifier - -error: aborting due to previous error - diff --git a/src/test/ui/parser/unicode-chars.stderr b/src/test/ui/parser/unicode-chars.stderr index 3a360d8f4681f..76bf6627a4bc4 100644 --- a/src/test/ui/parser/unicode-chars.stderr +++ b/src/test/ui/parser/unicode-chars.stderr @@ -1,4 +1,4 @@ -error: unknown start of token: /u{37e} +error: unknown start of token: \u{37e} --> $DIR/unicode-chars.rs:2:14 | LL | let y = 0; diff --git a/src/test/ui/parser/unicode-quote-chars.stderr b/src/test/ui/parser/unicode-quote-chars.stderr index 315e20cf854cd..4a09ed75605e4 100644 --- a/src/test/ui/parser/unicode-quote-chars.stderr +++ b/src/test/ui/parser/unicode-quote-chars.stderr @@ -1,4 +1,4 @@ -error: unknown start of token: /u{201c} +error: unknown start of token: \u{201c} --> $DIR/unicode-quote-chars.rs:4:14 | LL | println!(“hello world”); diff --git a/src/test/ui/parser/unmatched-delimiter-at-end-of-file.stderr b/src/test/ui/parser/unmatched-delimiter-at-end-of-file.stderr index 442837e580802..bfbdb0363ef68 100644 --- a/src/test/ui/parser/unmatched-delimiter-at-end-of-file.stderr +++ b/src/test/ui/parser/unmatched-delimiter-at-end-of-file.stderr @@ -1,7 +1,7 @@ error: this file contains an un-closed delimiter --> $DIR/unmatched-delimiter-at-end-of-file.rs:11:64 | -LL | fn foo() { //~ ERROR this file contains an un-closed delimiter +LL | fn foo() { | - un-closed delimiter ^ error: aborting due to previous error diff --git a/src/test/ui/parser/unsized2.stderr b/src/test/ui/parser/unsized2.stderr index fd12d86144c9c..17e39b292005a 100644 --- a/src/test/ui/parser/unsized2.stderr +++ b/src/test/ui/parser/unsized2.stderr @@ -1,7 +1,7 @@ error: expected expression, found keyword `type` --> $DIR/unsized2.rs:6:7 | -LL | f(); //~ ERROR expected expression, found keyword `type` +LL | f(); | ^^^^ expected expression error: aborting due to previous error diff --git a/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.rs b/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.rs index d322e9ffe68cd..b4bb484182466 100644 --- a/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.rs +++ b/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.rs @@ -1,4 +1,2 @@ -// compile-flags: -Z continue-parse-after-error - use std::any:: as foo; //~ ERROR expected identifier, found keyword `as` //~^ ERROR: expected one of `::`, `;`, or `as`, found `foo` diff --git a/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.stderr b/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.stderr index 51e1a02cbd763..0764400254350 100644 --- a/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.stderr +++ b/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.stderr @@ -1,17 +1,17 @@ error: expected identifier, found keyword `as` - --> $DIR/use-as-where-use-ends-with-mod-sep.rs:3:16 + --> $DIR/use-as-where-use-ends-with-mod-sep.rs:1:16 | -LL | use std::any:: as foo; //~ ERROR expected identifier, found keyword `as` +LL | use std::any:: as foo; | ^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | -LL | use std::any:: r#as foo; //~ ERROR expected identifier, found keyword `as` +LL | use std::any:: r#as foo; | ^^^^ error: expected one of `::`, `;`, or `as`, found `foo` - --> $DIR/use-as-where-use-ends-with-mod-sep.rs:3:19 + --> $DIR/use-as-where-use-ends-with-mod-sep.rs:1:19 | -LL | use std::any:: as foo; //~ ERROR expected identifier, found keyword `as` +LL | use std::any:: as foo; | ^^^ expected one of `::`, `;`, or `as` here error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/use-ends-with-mod-sep.stderr b/src/test/ui/parser/use-ends-with-mod-sep.stderr index 4a2b95ada6d21..bd0d881a06c35 100644 --- a/src/test/ui/parser/use-ends-with-mod-sep.stderr +++ b/src/test/ui/parser/use-ends-with-mod-sep.stderr @@ -1,7 +1,7 @@ error: expected identifier, found `;` --> $DIR/use-ends-with-mod-sep.rs:1:15 | -LL | use std::any::; //~ ERROR expected identifier, found `;` +LL | use std::any::; | ^ expected identifier error: aborting due to previous error diff --git a/src/test/ui/parser/where-clauses-no-bounds-or-predicates.rs b/src/test/ui/parser/where-clauses-no-bounds-or-predicates.rs index 45dacf22cfa3a..e80db5372b609 100644 --- a/src/test/ui/parser/where-clauses-no-bounds-or-predicates.rs +++ b/src/test/ui/parser/where-clauses-no-bounds-or-predicates.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - // Empty predicate list is OK fn equal1(_: &T, _: &T) -> bool where { true diff --git a/src/test/ui/parser/where-clauses-no-bounds-or-predicates.stderr b/src/test/ui/parser/where-clauses-no-bounds-or-predicates.stderr index 7e82522872eed..b80b0a409065b 100644 --- a/src/test/ui/parser/where-clauses-no-bounds-or-predicates.stderr +++ b/src/test/ui/parser/where-clauses-no-bounds-or-predicates.stderr @@ -1,5 +1,5 @@ error: expected `:`, found `{` - --> $DIR/where-clauses-no-bounds-or-predicates.rs:13:23 + --> $DIR/where-clauses-no-bounds-or-predicates.rs:11:23 | LL | fn foo<'a>() where 'a {} | ^ expected `:` diff --git a/src/test/ui/parser/wrong-escape-of-curly-braces.stderr b/src/test/ui/parser/wrong-escape-of-curly-braces.stderr index 90debfc337d83..1406b795ba8c3 100644 --- a/src/test/ui/parser/wrong-escape-of-curly-braces.stderr +++ b/src/test/ui/parser/wrong-escape-of-curly-braces.stderr @@ -1,26 +1,18 @@ error: unknown character escape: { --> $DIR/wrong-escape-of-curly-braces.rs:3:17 | -LL | let bad = "/{it is wrong/}"; - | ^ +LL | let bad = "\{it is wrong\}"; + | ^ unknown character escape | -help: if used in a formatting string, curly braces are escaped with `{{` and `}}` - --> $DIR/wrong-escape-of-curly-braces.rs:3:17 - | -LL | let bad = "/{it is wrong/}"; - | ^ + = help: if used in a formatting string, curly braces are escaped with `{{` and `}}` error: unknown character escape: } --> $DIR/wrong-escape-of-curly-braces.rs:3:30 | -LL | let bad = "/{it is wrong/}"; - | ^ - | -help: if used in a formatting string, curly braces are escaped with `{{` and `}}` - --> $DIR/wrong-escape-of-curly-braces.rs:3:30 +LL | let bad = "\{it is wrong\}"; + | ^ unknown character escape | -LL | let bad = "/{it is wrong/}"; - | ^ + = help: if used in a formatting string, curly braces are escaped with `{{` and `}}` error: aborting due to 2 previous errors diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/partialeq_help.stderr index 04eb9770c468d..9021bd30a7781 100644 --- a/src/test/ui/partialeq_help.stderr +++ b/src/test/ui/partialeq_help.stderr @@ -1,7 +1,7 @@ error[E0277]: can't compare `&T` with `T` --> $DIR/partialeq_help.rs:2:7 | -LL | a == b; //~ ERROR E0277 +LL | a == b; | ^^ no implementation for `&T == T` | = help: the trait `std::cmp::PartialEq` is not implemented for `&T` diff --git a/src/test/ui/path-lookahead.stderr b/src/test/ui/path-lookahead.stderr index 73c6884679dde..50593e45230ba 100644 --- a/src/test/ui/path-lookahead.stderr +++ b/src/test/ui/path-lookahead.stderr @@ -1,7 +1,7 @@ warning: unnecessary parentheses around `return` value --> $DIR/path-lookahead.rs:8:10 | -LL | return (::to_string(&arg)); //~WARN unnecessary parentheses around `return` value +LL | return (::to_string(&arg)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses | note: lint level defined here @@ -14,7 +14,7 @@ LL | #![warn(unused)] warning: function is never used: `with_parens` --> $DIR/path-lookahead.rs:7:1 | -LL | fn with_parens(arg: T) -> String { //~WARN function is never used: `with_parens` +LL | fn with_parens(arg: T) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -27,6 +27,6 @@ LL | #![warn(unused)] warning: function is never used: `no_parens` --> $DIR/path-lookahead.rs:11:1 | -LL | fn no_parens(arg: T) -> String { //~WARN function is never used: `no_parens` +LL | fn no_parens(arg: T) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/pattern/const-pat-ice.rs b/src/test/ui/pattern/const-pat-ice.rs index 865c54be1ad7b..0655876788214 100644 --- a/src/test/ui/pattern/const-pat-ice.rs +++ b/src/test/ui/pattern/const-pat-ice.rs @@ -1,5 +1,8 @@ // failure-status: 101 // rustc-env:RUST_BACKTRACE=0 +// normalize-stderr-test "note: rustc 1.* running on .*" -> "note: rustc VERSION running on TARGET" +// normalize-stderr-test "note: compiler flags: .*" -> "note: compiler flags: FLAGS" +// normalize-stderr-test "/_match.rs:[0-9]+:[0-9]+" -> "/_match.rs:LL:CC" // This is a repro test for an ICE in our pattern handling of constants. diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr new file mode 100644 index 0000000000000..7a0f14425b746 --- /dev/null +++ b/src/test/ui/pattern/const-pat-ice.stderr @@ -0,0 +1,13 @@ +thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. + +error: internal compiler error: unexpected panic + +note: the compiler unexpectedly panicked. this is a bug. + +note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports + +note: rustc VERSION running on TARGET + +note: compiler flags: FLAGS + diff --git a/src/test/ui/pattern/deny-irrefutable-let-patterns.stderr b/src/test/ui/pattern/deny-irrefutable-let-patterns.stderr index ad8cc2ef8973b..b32cf8cbb0efc 100644 --- a/src/test/ui/pattern/deny-irrefutable-let-patterns.stderr +++ b/src/test/ui/pattern/deny-irrefutable-let-patterns.stderr @@ -1,7 +1,7 @@ error: irrefutable if-let pattern --> $DIR/deny-irrefutable-let-patterns.rs:4:5 | -LL | if let _ = 5 {} //~ ERROR irrefutable if-let pattern +LL | if let _ = 5 {} | ^^^^^^^^^^^^^^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(irrefutable_let_patterns)] error: irrefutable while-let pattern --> $DIR/deny-irrefutable-let-patterns.rs:6:5 | -LL | / while let _ = 5 { //~ ERROR irrefutable while-let pattern +LL | / while let _ = 5 { LL | | break; LL | | } | |_____^ diff --git a/src/test/ui/pattern/enum-variant-generic-args.rs b/src/test/ui/pattern/enum-variant-generic-args.rs deleted file mode 100644 index 85599530ea6a4..0000000000000 --- a/src/test/ui/pattern/enum-variant-generic-args.rs +++ /dev/null @@ -1,43 +0,0 @@ -// run-pass - -#![feature(type_alias_enum_variants)] - -#![allow(irrefutable_let_patterns)] - -#[allow(dead_code)] -enum Enum { TSVariant(T), SVariant { v: T } } -type Alias = Enum; -type AliasFixed = Enum<()>; - -macro_rules! is_variant { - (TSVariant, $expr:expr) => (is_variant!(@check TSVariant, (_), $expr)); - (SVariant, $expr:expr) => (is_variant!(@check SVariant, { v: _ }, $expr)); - (@check $variant:ident, $matcher:tt, $expr:expr) => ( - assert!(if let Enum::$variant::<()> $matcher = $expr { true } else { false }, - "expr does not have correct type"); - ); -} - -fn main() { - // Tuple struct variant - - is_variant!(TSVariant, Enum::TSVariant(())); - is_variant!(TSVariant, Enum::TSVariant::<()>(())); - is_variant!(TSVariant, Enum::<()>::TSVariant(())); - - is_variant!(TSVariant, Alias::TSVariant(())); - is_variant!(TSVariant, Alias::<()>::TSVariant(())); - - is_variant!(TSVariant, AliasFixed::TSVariant(())); - - // Struct variant - - is_variant!(SVariant, Enum::SVariant { v: () }); - is_variant!(SVariant, Enum::SVariant::<()> { v: () }); - is_variant!(SVariant, Enum::<()>::SVariant { v: () }); - - is_variant!(SVariant, Alias::SVariant { v: () }); - is_variant!(SVariant, Alias::<()>::SVariant { v: () }); - - is_variant!(SVariant, AliasFixed::SVariant { v: () }); -} diff --git a/src/test/ui/pattern/pat-shadow-in-nested-binding.stderr b/src/test/ui/pattern/pat-shadow-in-nested-binding.stderr index 7dbe23a8f283c..0c5824be95df1 100644 --- a/src/test/ui/pattern/pat-shadow-in-nested-binding.stderr +++ b/src/test/ui/pattern/pat-shadow-in-nested-binding.stderr @@ -4,7 +4,7 @@ error[E0530]: let bindings cannot shadow tuple structs LL | struct foo(usize); | ------------------ the tuple struct `foo` is defined here ... -LL | let (foo, _) = (2, 3); //~ ERROR let bindings cannot shadow tuple structs +LL | let (foo, _) = (2, 3); | ^^^ cannot be named the same as a tuple struct error: aborting due to previous error diff --git a/src/test/ui/pattern/pat-tuple-bad-type.stderr b/src/test/ui/pattern/pat-tuple-bad-type.stderr index 28aa52856c55d..3da3bcb635f19 100644 --- a/src/test/ui/pattern/pat-tuple-bad-type.stderr +++ b/src/test/ui/pattern/pat-tuple-bad-type.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | let x; | - consider giving `x` a type ... -LL | (..) => {} //~ ERROR type annotations needed +LL | (..) => {} | ^^^^ cannot infer type | = note: type must be known at this point @@ -12,7 +12,7 @@ LL | (..) => {} //~ ERROR type annotations needed error[E0308]: mismatched types --> $DIR/pat-tuple-bad-type.rs:10:9 | -LL | (..) => {} //~ ERROR mismatched types +LL | (..) => {} | ^^^^ expected u8, found () | = note: expected type `u8` @@ -20,5 +20,5 @@ LL | (..) => {} //~ ERROR mismatched types error: aborting due to 2 previous errors -Some errors occurred: E0282, E0308. +Some errors have detailed explanations: E0282, E0308. For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/pattern/pat-tuple-overfield.stderr b/src/test/ui/pattern/pat-tuple-overfield.stderr index 4bd374affb366..0430897510b85 100644 --- a/src/test/ui/pattern/pat-tuple-overfield.stderr +++ b/src/test/ui/pattern/pat-tuple-overfield.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/pat-tuple-overfield.rs:5:9 | -LL | (1, 2, 3, 4) => {} //~ ERROR mismatched types +LL | (1, 2, 3, 4) => {} | ^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 4 elements | = note: expected type `({integer}, {integer}, {integer})` @@ -10,7 +10,7 @@ LL | (1, 2, 3, 4) => {} //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/pat-tuple-overfield.rs:6:9 | -LL | (1, 2, .., 3, 4) => {} //~ ERROR mismatched types +LL | (1, 2, .., 3, 4) => {} | ^^^^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 4 elements | = note: expected type `({integer}, {integer}, {integer})` @@ -30,5 +30,5 @@ LL | S(1, 2, .., 3, 4) => {} error: aborting due to 4 previous errors -Some errors occurred: E0023, E0308. +Some errors have detailed explanations: E0023, E0308. For more information about an error, try `rustc --explain E0023`. diff --git a/src/test/ui/pattern/patkind-litrange-no-expr.stderr b/src/test/ui/pattern/patkind-litrange-no-expr.stderr index 4caafa7d3e84b..7474d32679366 100644 --- a/src/test/ui/pattern/patkind-litrange-no-expr.stderr +++ b/src/test/ui/pattern/patkind-litrange-no-expr.stderr @@ -1,13 +1,13 @@ error: arbitrary expressions aren't allowed in patterns --> $DIR/patkind-litrange-no-expr.rs:20:13 | -LL | Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns +LL | Arith = 1 + 1, | ^^^^^ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/patkind-litrange-no-expr.rs:20:13 | -LL | Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns +LL | Arith = 1 + 1, | ^^^^^ ranges require char or numeric types | = note: start type: {integer} diff --git a/src/test/ui/pattern/pattern-binding-disambiguation.stderr b/src/test/ui/pattern/pattern-binding-disambiguation.stderr index 958934c301ff4..faa0d7c30743b 100644 --- a/src/test/ui/pattern/pattern-binding-disambiguation.stderr +++ b/src/test/ui/pattern/pattern-binding-disambiguation.stderr @@ -4,7 +4,7 @@ error[E0530]: match bindings cannot shadow tuple structs LL | struct TupleStruct(); | --------------------- the tuple struct `TupleStruct` is defined here ... -LL | TupleStruct => {} //~ ERROR match bindings cannot shadow tuple structs +LL | TupleStruct => {} | ^^^^^^^^^^^ cannot be named the same as a tuple struct error[E0530]: match bindings cannot shadow tuple variants @@ -13,7 +13,7 @@ error[E0530]: match bindings cannot shadow tuple variants LL | use E::*; | ---- the tuple variant `TupleVariant` is imported here ... -LL | TupleVariant => {} //~ ERROR match bindings cannot shadow tuple variants +LL | TupleVariant => {} | ^^^^^^^^^^^^ cannot be named the same as a tuple variant error[E0530]: match bindings cannot shadow struct variants @@ -22,7 +22,7 @@ error[E0530]: match bindings cannot shadow struct variants LL | use E::*; | ---- the struct variant `BracedVariant` is imported here ... -LL | BracedVariant => {} //~ ERROR match bindings cannot shadow struct variants +LL | BracedVariant => {} | ^^^^^^^^^^^^^ cannot be named the same as a struct variant error[E0530]: match bindings cannot shadow statics @@ -31,7 +31,7 @@ error[E0530]: match bindings cannot shadow statics LL | static STATIC: () = (); | ----------------------- the static `STATIC` is defined here ... -LL | STATIC => {} //~ ERROR match bindings cannot shadow statics +LL | STATIC => {} | ^^^^^^ cannot be named the same as a static error[E0530]: let bindings cannot shadow tuple structs @@ -40,7 +40,7 @@ error[E0530]: let bindings cannot shadow tuple structs LL | struct TupleStruct(); | --------------------- the tuple struct `TupleStruct` is defined here ... -LL | let TupleStruct = doesnt_matter; //~ ERROR let bindings cannot shadow tuple structs +LL | let TupleStruct = doesnt_matter; | ^^^^^^^^^^^ cannot be named the same as a tuple struct error[E0530]: let bindings cannot shadow tuple variants @@ -49,7 +49,7 @@ error[E0530]: let bindings cannot shadow tuple variants LL | use E::*; | ---- the tuple variant `TupleVariant` is imported here ... -LL | let TupleVariant = doesnt_matter; //~ ERROR let bindings cannot shadow tuple variants +LL | let TupleVariant = doesnt_matter; | ^^^^^^^^^^^^ cannot be named the same as a tuple variant error[E0530]: let bindings cannot shadow struct variants @@ -58,7 +58,7 @@ error[E0530]: let bindings cannot shadow struct variants LL | use E::*; | ---- the struct variant `BracedVariant` is imported here ... -LL | let BracedVariant = doesnt_matter; //~ ERROR let bindings cannot shadow struct variants +LL | let BracedVariant = doesnt_matter; | ^^^^^^^^^^^^^ cannot be named the same as a struct variant error[E0530]: let bindings cannot shadow statics @@ -67,7 +67,7 @@ error[E0530]: let bindings cannot shadow statics LL | static STATIC: () = (); | ----------------------- the static `STATIC` is defined here ... -LL | let STATIC = doesnt_matter; //~ ERROR let bindings cannot shadow statics +LL | let STATIC = doesnt_matter; | ^^^^^^ cannot be named the same as a static error: aborting due to 8 previous errors diff --git a/src/test/ui/pattern/pattern-bindings-after-at.nll.stderr b/src/test/ui/pattern/pattern-bindings-after-at.nll.stderr new file mode 100644 index 0000000000000..35ee7877f2f78 --- /dev/null +++ b/src/test/ui/pattern/pattern-bindings-after-at.nll.stderr @@ -0,0 +1,22 @@ +error[E0303]: pattern bindings are not allowed after an `@` + --> $DIR/pattern-bindings-after-at.rs:8:31 + | +LL | ref mut z @ &mut Some(ref a) => { + | ^^^^^ not allowed after `@` + +error[E0502]: cannot borrow `_` as immutable because it is also borrowed as mutable + --> $DIR/pattern-bindings-after-at.rs:8:31 + | +LL | ref mut z @ &mut Some(ref a) => { + | ----------------------^^^^^- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here +... +LL | **z = None; + | ---------- mutable borrow later used here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0303, E0502. +For more information about an error, try `rustc --explain E0303`. diff --git a/src/test/ui/pattern/pattern-bindings-after-at.rs b/src/test/ui/pattern/pattern-bindings-after-at.rs index 4a24a496857ba..20a1d017cdd18 100644 --- a/src/test/ui/pattern/pattern-bindings-after-at.rs +++ b/src/test/ui/pattern/pattern-bindings-after-at.rs @@ -7,6 +7,9 @@ fn main() { match &mut Some(1) { ref mut z @ &mut Some(ref a) => { //~^ ERROR pattern bindings are not allowed after an `@` + //~| WARN cannot borrow `_` as immutable because it is also borrowed as mutable + //~| WARN this error has been downgraded to a warning for backwards compatibility + //~| WARN this represents potential undefined behavior in your code and this warning will **z = None; println!("{}", *a); } diff --git a/src/test/ui/pattern/pattern-bindings-after-at.stderr b/src/test/ui/pattern/pattern-bindings-after-at.stderr index 7a3883c585450..70452a930ee70 100644 --- a/src/test/ui/pattern/pattern-bindings-after-at.stderr +++ b/src/test/ui/pattern/pattern-bindings-after-at.stderr @@ -4,6 +4,23 @@ error[E0303]: pattern bindings are not allowed after an `@` LL | ref mut z @ &mut Some(ref a) => { | ^^^^^ not allowed after `@` +warning[E0502]: cannot borrow `_` as immutable because it is also borrowed as mutable + --> $DIR/pattern-bindings-after-at.rs:8:31 + | +LL | ref mut z @ &mut Some(ref a) => { + | ----------------------^^^^^- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here +... +LL | **z = None; + | ---------- mutable borrow later used here + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + error: aborting due to previous error -For more information about this error, try `rustc --explain E0303`. +Some errors have detailed explanations: E0303, E0502. +For more information about an error, try `rustc --explain E0303`. diff --git a/src/test/ui/pattern/pattern-error-continue.stderr b/src/test/ui/pattern/pattern-error-continue.stderr index 654814afcfe17..a581f07496e6c 100644 --- a/src/test/ui/pattern/pattern-error-continue.stderr +++ b/src/test/ui/pattern/pattern-error-continue.stderr @@ -1,13 +1,13 @@ error[E0433]: failed to resolve: use of undeclared type or module `E` --> $DIR/pattern-error-continue.rs:35:9 | -LL | E::V => {} //~ ERROR failed to resolve: use of undeclared type or module `E` +LL | E::V => {} | ^ use of undeclared type or module `E` error[E0532]: expected tuple struct/variant, found unit variant `A::D` --> $DIR/pattern-error-continue.rs:18:9 | -LL | A::D(_) => (), //~ ERROR expected tuple struct/variant, found unit variant `A::D` +LL | A::D(_) => (), | ^^^- | | | help: a tuple variant with a similar name exists: `B` @@ -15,7 +15,7 @@ LL | A::D(_) => (), //~ ERROR expected tuple struct/variant, found error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/pattern-error-continue.rs:17:9 | -LL | A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but +LL | A::B(_, _, _) => (), | ^^^^^^^^^^^^^ expected 2 fields, found 3 error[E0308]: mismatched types @@ -37,5 +37,5 @@ LL | f(true); error: aborting due to 5 previous errors -Some errors occurred: E0023, E0308, E0433, E0532. +Some errors have detailed explanations: E0023, E0308, E0433, E0532. For more information about an error, try `rustc --explain E0023`. diff --git a/src/test/ui/pattern/pattern-ident-path-generics.stderr b/src/test/ui/pattern/pattern-ident-path-generics.stderr index 278b3d19d8bc7..bfc10c5f86652 100644 --- a/src/test/ui/pattern/pattern-ident-path-generics.stderr +++ b/src/test/ui/pattern/pattern-ident-path-generics.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/pattern-ident-path-generics.rs:3:9 | -LL | None:: => {} //~ ERROR mismatched types +LL | None:: => {} | ^^^^^^^^^^^^^ expected &str, found isize | = note: expected type `std::option::Option<&str>` diff --git a/src/test/ui/pattern/pattern-tyvar-2.stderr b/src/test/ui/pattern/pattern-tyvar-2.stderr index 5218dd916a575..7c6ae499cbb07 100644 --- a/src/test/ui/pattern/pattern-tyvar-2.stderr +++ b/src/test/ui/pattern/pattern-tyvar-2.stderr @@ -1,8 +1,10 @@ error[E0369]: binary operation `*` cannot be applied to type `std::vec::Vec` - --> $DIR/pattern-tyvar-2.rs:3:69 + --> $DIR/pattern-tyvar-2.rs:3:71 | LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; } _ => { panic!(); } } } - | ^^^^^ + | - ^ - {integer} + | | + | std::vec::Vec | = note: an implementation of `std::ops::Mul` might be missing for `std::vec::Vec` diff --git a/src/test/ui/pattern/pattern-tyvar.stderr b/src/test/ui/pattern/pattern-tyvar.stderr index 69cd552aabd1b..548347034671c 100644 --- a/src/test/ui/pattern/pattern-tyvar.stderr +++ b/src/test/ui/pattern/pattern-tyvar.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | match t { | - this match expression has type `std::option::Option>` -LL | Bar::T1(_, Some::(x)) => { //~ ERROR mismatched types +LL | Bar::T1(_, Some::(x)) => { | ^^^^^^^^^^^^^^^^ expected struct `std::vec::Vec`, found isize | = note: expected type `std::option::Option>` diff --git a/src/test/ui/pattern/slice-pattern-const-2.rs b/src/test/ui/pattern/slice-pattern-const-2.rs index 6cfef115d08dc..a36c550f530a9 100644 --- a/src/test/ui/pattern/slice-pattern-const-2.rs +++ b/src/test/ui/pattern/slice-pattern-const-2.rs @@ -6,13 +6,13 @@ fn main() { match s { MAGIC_TEST => (), [0x00, 0x00, 0x00, 0x00] => (), - [4, 5, 6, 7] => (), //~ ERROR unreachable pattern + [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not _ => (), } match s { [0x00, 0x00, 0x00, 0x00] => (), MAGIC_TEST => (), - [4, 5, 6, 7] => (), //~ ERROR unreachable pattern + [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not _ => (), } match s { diff --git a/src/test/ui/pattern/slice-pattern-const-2.stderr b/src/test/ui/pattern/slice-pattern-const-2.stderr index 95651ccc401e0..0c7401269dfc7 100644 --- a/src/test/ui/pattern/slice-pattern-const-2.stderr +++ b/src/test/ui/pattern/slice-pattern-const-2.stderr @@ -1,8 +1,8 @@ error: unreachable pattern - --> $DIR/slice-pattern-const-2.rs:9:9 + --> $DIR/slice-pattern-const-2.rs:28:9 | -LL | [4, 5, 6, 7] => (), //~ ERROR unreachable pattern - | ^^^^^^^^^^^^ +LL | FOO => (), + | ^^^ | note: lint level defined here --> $DIR/slice-pattern-const-2.rs:1:9 @@ -10,17 +10,5 @@ note: lint level defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: unreachable pattern - --> $DIR/slice-pattern-const-2.rs:15:9 - | -LL | [4, 5, 6, 7] => (), //~ ERROR unreachable pattern - | ^^^^^^^^^^^^ - -error: unreachable pattern - --> $DIR/slice-pattern-const-2.rs:28:9 - | -LL | FOO => (), //~ ERROR unreachable pattern - | ^^^ - -error: aborting due to 3 previous errors +error: aborting due to previous error diff --git a/src/test/ui/pattern/slice-pattern-const-3.stderr b/src/test/ui/pattern/slice-pattern-const-3.stderr index 531bbbc84d038..eab4fc3f086da 100644 --- a/src/test/ui/pattern/slice-pattern-const-3.stderr +++ b/src/test/ui/pattern/slice-pattern-const-3.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/slice-pattern-const-3.rs:28:9 | -LL | FOO => (), //~ ERROR unreachable pattern +LL | FOO => (), | ^^^ | note: lint level defined here diff --git a/src/test/ui/pattern/slice-pattern-const.stderr b/src/test/ui/pattern/slice-pattern-const.stderr index 412e0158c01c7..2dd10a0478ab9 100644 --- a/src/test/ui/pattern/slice-pattern-const.stderr +++ b/src/test/ui/pattern/slice-pattern-const.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/slice-pattern-const.rs:9:9 | -LL | [84, 69, 83, 84] => (), //~ ERROR unreachable pattern +LL | [84, 69, 83, 84] => (), | ^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -13,43 +13,43 @@ LL | #![deny(unreachable_patterns)] error: unreachable pattern --> $DIR/slice-pattern-const.rs:15:9 | -LL | [84, 69, 83, 84] => (), //~ ERROR unreachable pattern +LL | [84, 69, 83, 84] => (), | ^^^^^^^^^^^^^^^^ error: unreachable pattern --> $DIR/slice-pattern-const.rs:21:9 | -LL | MAGIC_TEST => (), //~ ERROR unreachable pattern +LL | MAGIC_TEST => (), | ^^^^^^^^^^ error: unreachable pattern --> $DIR/slice-pattern-const.rs:28:9 | -LL | FOO => (), //~ ERROR unreachable pattern +LL | FOO => (), | ^^^ error: unreachable pattern --> $DIR/slice-pattern-const.rs:35:9 | -LL | BAR => (), //~ ERROR unreachable pattern +LL | BAR => (), | ^^^ error: unreachable pattern --> $DIR/slice-pattern-const.rs:43:9 | -LL | BOO => (), //~ ERROR unreachable pattern +LL | BOO => (), | ^^^ error: unreachable pattern --> $DIR/slice-pattern-const.rs:44:9 | -LL | b"" => (), //~ ERROR unreachable pattern +LL | b"" => (), | ^^^ error: unreachable pattern --> $DIR/slice-pattern-const.rs:45:9 | -LL | _ => (), //~ ERROR unreachable pattern +LL | _ => (), | ^ error: aborting due to 8 previous errors diff --git a/src/test/ui/placement-syntax.rs b/src/test/ui/placement-syntax.rs index ac6fed1558f53..2edd78ec8ab3d 100644 --- a/src/test/ui/placement-syntax.rs +++ b/src/test/ui/placement-syntax.rs @@ -1,7 +1,6 @@ fn main() { let x = -5; - if x<-1 { - //~^ ERROR emplacement syntax is obsolete + if x<-1 { //~ ERROR expected `{`, found `<-` println!("ok"); } } diff --git a/src/test/ui/placement-syntax.stderr b/src/test/ui/placement-syntax.stderr index 350aaa9bdddc1..e90acce168e47 100644 --- a/src/test/ui/placement-syntax.stderr +++ b/src/test/ui/placement-syntax.stderr @@ -1,14 +1,10 @@ -error: emplacement syntax is obsolete (for now, anyway) - --> $DIR/placement-syntax.rs:3:8 +error: expected `{`, found `<-` + --> $DIR/placement-syntax.rs:3:9 | LL | if x<-1 { - | ^^^^ - | - = note: for more information, see -help: if you meant to write a comparison against a negative value, add a space in between `<` and `-` - | -LL | if x< -1 { - | ^^^ + | -- ^^ expected `{` + | | + | this `if` statement has a condition, but no block error: aborting due to previous error diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr index 5ebe00e624fc1..ee1e36081e778 100644 --- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr +++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr @@ -34,7 +34,7 @@ error[E0308]: mismatched types LL | fn baz() -> impl std::fmt::Display { | ---------------------- expected because this return type... LL | / if false { -LL | | //~^ ERROR mismatched types +LL | | LL | | return 0i32; | | ---- ...is found to be `i32` here LL | | } else { @@ -54,7 +54,7 @@ LL | | 0i32 LL | | } else { LL | | 1u32 | | ^^^^ expected i32, found u32 -LL | | //~^ ERROR if and else have incompatible types +LL | | LL | | } | |_____- if and else have incompatible types | diff --git a/src/test/ui/pptypedef.stderr b/src/test/ui/pptypedef.stderr index 32ee1a6aae99d..dc4b3ce370cb1 100644 --- a/src/test/ui/pptypedef.stderr +++ b/src/test/ui/pptypedef.stderr @@ -3,12 +3,20 @@ error[E0308]: mismatched types | LL | let_in(3u32, |i| { assert!(i == 3i32); }); | ^^^^ expected u32, found i32 +help: change the type of the numeric literal from `i32` to `u32` + | +LL | let_in(3u32, |i| { assert!(i == 3u32); }); + | ^^^^ error[E0308]: mismatched types --> $DIR/pptypedef.rs:8:37 | LL | let_in(3i32, |i| { assert!(i == 3u32); }); | ^^^^ expected i32, found u32 +help: change the type of the numeric literal from `u32` to `i32` + | +LL | let_in(3i32, |i| { assert!(i == 3i32); }); + | ^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/precise_pointer_size_matching.stderr b/src/test/ui/precise_pointer_size_matching.stderr index 4acbec6c7ff1a..6f0322fd9b953 100644 --- a/src/test/ui/precise_pointer_size_matching.stderr +++ b/src/test/ui/precise_pointer_size_matching.stderr @@ -1,14 +1,18 @@ error[E0004]: non-exhaustive patterns: `$ISIZE_MIN..=-6isize` and `21isize..=$ISIZE_MAX` not covered --> $DIR/precise_pointer_size_matching.rs:24:11 | -LL | match 0isize { //~ ERROR non-exhaustive patterns +LL | match 0isize { | ^^^^^^ patterns `$ISIZE_MIN..=-6isize` and `21isize..=$ISIZE_MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `0usize` and `21usize..=$USIZE_MAX` not covered --> $DIR/precise_pointer_size_matching.rs:29:11 | -LL | match 0usize { //~ ERROR non-exhaustive patterns +LL | match 0usize { | ^^^^^^ patterns `0usize` and `21usize..=$USIZE_MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to 2 previous errors diff --git a/src/test/ui/prim-with-args.rs b/src/test/ui/prim-with-args.rs index b5df0fb76ca6a..e5beaca6abb8c 100644 --- a/src/test/ui/prim-with-args.rs +++ b/src/test/ui/prim-with-args.rs @@ -1,27 +1,27 @@ fn main() { -let x: isize; //~ ERROR type arguments are not allowed on this entity -let x: i8; //~ ERROR type arguments are not allowed on this entity -let x: i16; //~ ERROR type arguments are not allowed on this entity -let x: i32; //~ ERROR type arguments are not allowed on this entity -let x: i64; //~ ERROR type arguments are not allowed on this entity -let x: usize; //~ ERROR type arguments are not allowed on this entity -let x: u8; //~ ERROR type arguments are not allowed on this entity -let x: u16; //~ ERROR type arguments are not allowed on this entity -let x: u32; //~ ERROR type arguments are not allowed on this entity -let x: u64; //~ ERROR type arguments are not allowed on this entity -let x: char; //~ ERROR type arguments are not allowed on this entity +let x: isize; //~ ERROR type arguments are not allowed for this type +let x: i8; //~ ERROR type arguments are not allowed for this type +let x: i16; //~ ERROR type arguments are not allowed for this type +let x: i32; //~ ERROR type arguments are not allowed for this type +let x: i64; //~ ERROR type arguments are not allowed for this type +let x: usize; //~ ERROR type arguments are not allowed for this type +let x: u8; //~ ERROR type arguments are not allowed for this type +let x: u16; //~ ERROR type arguments are not allowed for this type +let x: u32; //~ ERROR type arguments are not allowed for this type +let x: u64; //~ ERROR type arguments are not allowed for this type +let x: char; //~ ERROR type arguments are not allowed for this type -let x: isize<'static>; //~ ERROR lifetime arguments are not allowed on this entity -let x: i8<'static>; //~ ERROR lifetime arguments are not allowed on this entity -let x: i16<'static>; //~ ERROR lifetime arguments are not allowed on this entity -let x: i32<'static>; //~ ERROR lifetime arguments are not allowed on this entity -let x: i64<'static>; //~ ERROR lifetime arguments are not allowed on this entity -let x: usize<'static>; //~ ERROR lifetime arguments are not allowed on this entity -let x: u8<'static>; //~ ERROR lifetime arguments are not allowed on this entity -let x: u16<'static>; //~ ERROR lifetime arguments are not allowed on this entity -let x: u32<'static>; //~ ERROR lifetime arguments are not allowed on this entity -let x: u64<'static>; //~ ERROR lifetime arguments are not allowed on this entity -let x: char<'static>; //~ ERROR lifetime arguments are not allowed on this entity +let x: isize<'static>; //~ ERROR lifetime arguments are not allowed for this type +let x: i8<'static>; //~ ERROR lifetime arguments are not allowed for this type +let x: i16<'static>; //~ ERROR lifetime arguments are not allowed for this type +let x: i32<'static>; //~ ERROR lifetime arguments are not allowed for this type +let x: i64<'static>; //~ ERROR lifetime arguments are not allowed for this type +let x: usize<'static>; //~ ERROR lifetime arguments are not allowed for this type +let x: u8<'static>; //~ ERROR lifetime arguments are not allowed for this type +let x: u16<'static>; //~ ERROR lifetime arguments are not allowed for this type +let x: u32<'static>; //~ ERROR lifetime arguments are not allowed for this type +let x: u64<'static>; //~ ERROR lifetime arguments are not allowed for this type +let x: char<'static>; //~ ERROR lifetime arguments are not allowed for this type } diff --git a/src/test/ui/prim-with-args.stderr b/src/test/ui/prim-with-args.stderr index 91259e87efc02..4bde981e7f2d4 100644 --- a/src/test/ui/prim-with-args.stderr +++ b/src/test/ui/prim-with-args.stderr @@ -1,136 +1,135 @@ -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/prim-with-args.rs:3:14 | -LL | let x: isize; //~ ERROR type arguments are not allowed on this entity +LL | let x: isize; | ^^^^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/prim-with-args.rs:4:11 | -LL | let x: i8; //~ ERROR type arguments are not allowed on this entity +LL | let x: i8; | ^^^^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/prim-with-args.rs:5:12 | -LL | let x: i16; //~ ERROR type arguments are not allowed on this entity +LL | let x: i16; | ^^^^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/prim-with-args.rs:6:12 | -LL | let x: i32; //~ ERROR type arguments are not allowed on this entity +LL | let x: i32; | ^^^^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/prim-with-args.rs:7:12 | -LL | let x: i64; //~ ERROR type arguments are not allowed on this entity +LL | let x: i64; | ^^^^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/prim-with-args.rs:8:14 | -LL | let x: usize; //~ ERROR type arguments are not allowed on this entity +LL | let x: usize; | ^^^^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/prim-with-args.rs:9:11 | -LL | let x: u8; //~ ERROR type arguments are not allowed on this entity +LL | let x: u8; | ^^^^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/prim-with-args.rs:10:12 | -LL | let x: u16; //~ ERROR type arguments are not allowed on this entity +LL | let x: u16; | ^^^^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/prim-with-args.rs:11:12 | -LL | let x: u32; //~ ERROR type arguments are not allowed on this entity +LL | let x: u32; | ^^^^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/prim-with-args.rs:12:12 | -LL | let x: u64; //~ ERROR type arguments are not allowed on this entity +LL | let x: u64; | ^^^^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/prim-with-args.rs:13:13 | -LL | let x: char; //~ ERROR type arguments are not allowed on this entity +LL | let x: char; | ^^^^^ type argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/prim-with-args.rs:15:14 | -LL | let x: isize<'static>; //~ ERROR lifetime arguments are not allowed on this entity +LL | let x: isize<'static>; | ^^^^^^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/prim-with-args.rs:16:11 | -LL | let x: i8<'static>; //~ ERROR lifetime arguments are not allowed on this entity +LL | let x: i8<'static>; | ^^^^^^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/prim-with-args.rs:17:12 | -LL | let x: i16<'static>; //~ ERROR lifetime arguments are not allowed on this entity +LL | let x: i16<'static>; | ^^^^^^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/prim-with-args.rs:18:12 | -LL | let x: i32<'static>; //~ ERROR lifetime arguments are not allowed on this entity +LL | let x: i32<'static>; | ^^^^^^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/prim-with-args.rs:19:12 | -LL | let x: i64<'static>; //~ ERROR lifetime arguments are not allowed on this entity +LL | let x: i64<'static>; | ^^^^^^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/prim-with-args.rs:20:14 | -LL | let x: usize<'static>; //~ ERROR lifetime arguments are not allowed on this entity +LL | let x: usize<'static>; | ^^^^^^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/prim-with-args.rs:21:11 | -LL | let x: u8<'static>; //~ ERROR lifetime arguments are not allowed on this entity +LL | let x: u8<'static>; | ^^^^^^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/prim-with-args.rs:22:12 | -LL | let x: u16<'static>; //~ ERROR lifetime arguments are not allowed on this entity +LL | let x: u16<'static>; | ^^^^^^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/prim-with-args.rs:23:12 | -LL | let x: u32<'static>; //~ ERROR lifetime arguments are not allowed on this entity +LL | let x: u32<'static>; | ^^^^^^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/prim-with-args.rs:24:12 | -LL | let x: u64<'static>; //~ ERROR lifetime arguments are not allowed on this entity +LL | let x: u64<'static>; | ^^^^^^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/prim-with-args.rs:25:13 | -LL | let x: char<'static>; //~ ERROR lifetime arguments are not allowed on this entity +LL | let x: char<'static>; | ^^^^^^^ lifetime argument not allowed error: aborting due to 22 previous errors -Some errors occurred: E0109, E0110. -For more information about an error, try `rustc --explain E0109`. +For more information about this error, try `rustc --explain E0109`. diff --git a/src/test/ui/primitive-binop-lhs-mut.rs b/src/test/ui/primitive-binop-lhs-mut.rs new file mode 100644 index 0000000000000..4f1c456ace354 --- /dev/null +++ b/src/test/ui/primitive-binop-lhs-mut.rs @@ -0,0 +1,6 @@ +// run-pass + +fn main() { + let x = Box::new(0); + assert_eq!(0, *x + { drop(x); let _ = Box::new(main); 0 }); +} diff --git a/src/test/ui/print_type_sizes/generics.rs b/src/test/ui/print_type_sizes/generics.rs index 360c995868654..ecfc03717db46 100644 --- a/src/test/ui/print_type_sizes/generics.rs +++ b/src/test/ui/print_type_sizes/generics.rs @@ -1,5 +1,8 @@ // compile-flags: -Z print-type-sizes // compile-pass +// ignore-pass +// ^-- needed because `--pass check` does not emit the output needed. +// FIXME: consider using an attribute instead of side-effects. // This file illustrates how generics are handled: types have to be // monomorphized, in the MIR of the original function in which they diff --git a/src/test/ui/print_type_sizes/multiple_types.stdout b/src/test/ui/print_type_sizes/multiple_types.stdout index eed9af26987b4..6411881545843 100644 --- a/src/test/ui/print_type_sizes/multiple_types.stdout +++ b/src/test/ui/print_type_sizes/multiple_types.stdout @@ -1,9 +1,9 @@ print-type-size type: `Enum`: 51 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes -print-type-size variant `Small`: 7 bytes -print-type-size field `.0`: 7 bytes print-type-size variant `Large`: 50 bytes print-type-size field `.0`: 50 bytes +print-type-size variant `Small`: 7 bytes +print-type-size field `.0`: 7 bytes print-type-size type: `FiftyBytes`: 50 bytes, alignment: 1 bytes print-type-size field `.0`: 50 bytes print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs index bed1e32a60158..98b506b1f0db1 100644 --- a/src/test/ui/print_type_sizes/niche-filling.rs +++ b/src/test/ui/print_type_sizes/niche-filling.rs @@ -1,5 +1,8 @@ // compile-flags: -Z print-type-sizes // compile-pass +// ignore-pass +// ^-- needed because `--pass check` does not emit the output needed. +// FIXME: consider using an attribute instead of side-effects. // This file illustrates how niche-filling enums are handled, // modelled after cases like `Option<&u32>`, `Option` and such. @@ -57,6 +60,15 @@ pub enum Enum4 { Four(D) } +pub union Union1 { + a: A, +} + +pub union Union2 { + a: A, + b: B, +} + #[start] fn start(_: isize, _: *const *const u8) -> isize { let _x: MyOption = Default::default(); @@ -69,5 +81,13 @@ fn start(_: isize, _: *const *const u8) -> isize { let _e: Enum4<(), char, (), ()> = Enum4::One(()); let _f: Enum4<(), (), bool, ()> = Enum4::One(()); let _g: Enum4<(), (), (), MyOption> = Enum4::One(()); + + // Unions do not currently participate in niche filling. + let _h: MyOption> = Default::default(); + + // ...even when theoretically possible. + let _i: MyOption> = Default::default(); + let _j: MyOption> = Default::default(); + 0 } diff --git a/src/test/ui/print_type_sizes/niche-filling.stdout b/src/test/ui/print_type_sizes/niche-filling.stdout index 0789c6d7f3486..301edc0d086b1 100644 --- a/src/test/ui/print_type_sizes/niche-filling.stdout +++ b/src/test/ui/print_type_sizes/niche-filling.stdout @@ -4,75 +4,101 @@ print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes print-type-size end padding: 1 bytes print-type-size type: `MyOption`: 12 bytes, alignment: 4 bytes -print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 12 bytes print-type-size field `.0`: 12 bytes -print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes print-type-size variant `None`: 0 bytes +print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes print-type-size variant `Record`: 7 bytes print-type-size field `.val`: 4 bytes print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes +print-type-size variant `None`: 0 bytes print-type-size end padding: 1 bytes +print-type-size type: `MyOption>`: 8 bytes, alignment: 4 bytes +print-type-size discriminant: 4 bytes +print-type-size variant `Some`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `MyOption>`: 8 bytes, alignment: 4 bytes +print-type-size discriminant: 4 bytes +print-type-size variant `Some`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `MyOption>`: 8 bytes, alignment: 4 bytes +print-type-size discriminant: 4 bytes +print-type-size variant `Some`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes print-type-size field `.val`: 4 bytes print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes print-type-size end padding: 1 bytes print-type-size type: `Enum4<(), char, (), ()>`: 4 bytes, alignment: 4 bytes -print-type-size variant `One`: 0 bytes -print-type-size field `.0`: 0 bytes print-type-size variant `Two`: 4 bytes print-type-size field `.0`: 4 bytes +print-type-size variant `One`: 0 bytes +print-type-size field `.0`: 0 bytes print-type-size variant `Three`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Four`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size type: `MyOption`: 4 bytes, alignment: 4 bytes -print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes -print-type-size type: `MyOption`: 4 bytes, alignment: 4 bytes print-type-size variant `None`: 0 bytes +print-type-size type: `MyOption`: 4 bytes, alignment: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `Union1`: 4 bytes, alignment: 4 bytes +print-type-size variant `Union1`: 4 bytes +print-type-size field `.a`: 4 bytes +print-type-size type: `Union2`: 4 bytes, alignment: 4 bytes +print-type-size variant `Union2`: 4 bytes +print-type-size field `.a`: 4 bytes +print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes +print-type-size type: `Union2`: 4 bytes, alignment: 4 bytes +print-type-size variant `Union2`: 4 bytes +print-type-size field `.a`: 4 bytes +print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes print-type-size type: `std::num::NonZeroU32`: 4 bytes, alignment: 4 bytes print-type-size field `.0`: 4 bytes print-type-size type: `Enum4<(), (), (), MyOption>`: 2 bytes, alignment: 1 bytes +print-type-size variant `Four`: 2 bytes +print-type-size field `.0`: 2 bytes print-type-size variant `One`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Two`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Three`: 0 bytes print-type-size field `.0`: 0 bytes -print-type-size variant `Four`: 2 bytes -print-type-size field `.0`: 2 bytes print-type-size type: `MyOption>`: 2 bytes, alignment: 1 bytes -print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 2 bytes print-type-size field `.0`: 2 bytes +print-type-size variant `None`: 0 bytes print-type-size type: `MyOption`: 2 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes -print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 1 bytes print-type-size field `.0`: 1 bytes +print-type-size variant `None`: 0 bytes print-type-size type: `Enum4<(), (), bool, ()>`: 1 bytes, alignment: 1 bytes +print-type-size variant `Three`: 1 bytes +print-type-size field `.0`: 1 bytes print-type-size variant `One`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Two`: 0 bytes print-type-size field `.0`: 0 bytes -print-type-size variant `Three`: 1 bytes -print-type-size field `.0`: 1 bytes print-type-size variant `Four`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size type: `MyOption`: 1 bytes, alignment: 1 bytes -print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 1 bytes print-type-size field `.0`: 1 bytes -print-type-size type: `MyOption`: 1 bytes, alignment: 1 bytes print-type-size variant `None`: 0 bytes +print-type-size type: `MyOption`: 1 bytes, alignment: 1 bytes print-type-size variant `Some`: 1 bytes print-type-size field `.0`: 1 bytes +print-type-size variant `None`: 0 bytes print-type-size type: `std::cmp::Ordering`: 1 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Less`: 0 bytes diff --git a/src/test/ui/print_type_sizes/no_duplicates.rs b/src/test/ui/print_type_sizes/no_duplicates.rs index 7307c0fd8b406..f1b8a28ae304b 100644 --- a/src/test/ui/print_type_sizes/no_duplicates.rs +++ b/src/test/ui/print_type_sizes/no_duplicates.rs @@ -1,5 +1,8 @@ // compile-flags: -Z print-type-sizes // compile-pass +// ignore-pass +// ^-- needed because `--pass check` does not emit the output needed. +// FIXME: consider using an attribute instead of side-effects. // This file illustrates that when the same type occurs repeatedly // (even if multiple functions), it is only printed once in the diff --git a/src/test/ui/print_type_sizes/packed.rs b/src/test/ui/print_type_sizes/packed.rs index ec3efd6923aef..a8d409a91a240 100644 --- a/src/test/ui/print_type_sizes/packed.rs +++ b/src/test/ui/print_type_sizes/packed.rs @@ -1,5 +1,8 @@ // compile-flags: -Z print-type-sizes // compile-pass +// ignore-pass +// ^-- needed because `--pass check` does not emit the output needed. +// FIXME: consider using an attribute instead of side-effects. // This file illustrates how packing is handled; it should cause // the elimination of padding that would normally be introduced diff --git a/src/test/ui/print_type_sizes/padding.stdout b/src/test/ui/print_type_sizes/padding.stdout index 0eaff7118b35c..9afdf76245df7 100644 --- a/src/test/ui/print_type_sizes/padding.stdout +++ b/src/test/ui/print_type_sizes/padding.stdout @@ -1,21 +1,21 @@ print-type-size type: `E1`: 12 bytes, alignment: 4 bytes print-type-size discriminant: 1 bytes +print-type-size variant `B`: 11 bytes +print-type-size padding: 3 bytes +print-type-size field `.0`: 8 bytes, alignment: 4 bytes print-type-size variant `A`: 7 bytes print-type-size field `.1`: 1 bytes print-type-size padding: 2 bytes print-type-size field `.0`: 4 bytes, alignment: 4 bytes +print-type-size type: `E2`: 12 bytes, alignment: 4 bytes +print-type-size discriminant: 1 bytes print-type-size variant `B`: 11 bytes print-type-size padding: 3 bytes print-type-size field `.0`: 8 bytes, alignment: 4 bytes -print-type-size type: `E2`: 12 bytes, alignment: 4 bytes -print-type-size discriminant: 1 bytes print-type-size variant `A`: 7 bytes print-type-size field `.0`: 1 bytes print-type-size padding: 2 bytes print-type-size field `.1`: 4 bytes, alignment: 4 bytes -print-type-size variant `B`: 11 bytes -print-type-size padding: 3 bytes -print-type-size field `.0`: 8 bytes, alignment: 4 bytes print-type-size type: `S`: 8 bytes, alignment: 4 bytes print-type-size field `.g`: 4 bytes print-type-size field `.a`: 1 bytes diff --git a/src/test/ui/print_type_sizes/repr-align.rs b/src/test/ui/print_type_sizes/repr-align.rs index fd452f411c51e..3b5248b6f7ebb 100644 --- a/src/test/ui/print_type_sizes/repr-align.rs +++ b/src/test/ui/print_type_sizes/repr-align.rs @@ -1,5 +1,8 @@ // compile-flags: -Z print-type-sizes // compile-pass +// ignore-pass +// ^-- needed because `--pass check` does not emit the output needed. +// FIXME: consider using an attribute instead of side-effects. // This file illustrates how padding is handled: alignment // requirements can lead to the introduction of padding, either before diff --git a/src/test/ui/print_type_sizes/repr-align.stdout b/src/test/ui/print_type_sizes/repr-align.stdout index 7df12f040b15d..33671bd8e14bc 100644 --- a/src/test/ui/print_type_sizes/repr-align.stdout +++ b/src/test/ui/print_type_sizes/repr-align.stdout @@ -1,10 +1,10 @@ print-type-size type: `E`: 32 bytes, alignment: 16 bytes print-type-size discriminant: 4 bytes -print-type-size variant `A`: 4 bytes -print-type-size field `.0`: 4 bytes print-type-size variant `B`: 28 bytes print-type-size padding: 12 bytes print-type-size field `.0`: 16 bytes, alignment: 16 bytes +print-type-size variant `A`: 4 bytes +print-type-size field `.0`: 4 bytes print-type-size type: `S`: 32 bytes, alignment: 16 bytes print-type-size field `.c`: 16 bytes print-type-size field `.a`: 4 bytes diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs index 14245d0dc9a28..c33965c4f53ea 100644 --- a/src/test/ui/print_type_sizes/uninhabited.rs +++ b/src/test/ui/print_type_sizes/uninhabited.rs @@ -1,5 +1,8 @@ // compile-flags: -Z print-type-sizes // compile-pass +// ignore-pass +// ^-- needed because `--pass check` does not emit the output needed. +// FIXME: consider using an attribute instead of side-effects. #![feature(never_type)] #![feature(start)] diff --git a/src/test/ui/print_type_sizes/variants.stdout b/src/test/ui/print_type_sizes/variants.stdout index eed9af26987b4..6411881545843 100644 --- a/src/test/ui/print_type_sizes/variants.stdout +++ b/src/test/ui/print_type_sizes/variants.stdout @@ -1,9 +1,9 @@ print-type-size type: `Enum`: 51 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes -print-type-size variant `Small`: 7 bytes -print-type-size field `.0`: 7 bytes print-type-size variant `Large`: 50 bytes print-type-size field `.0`: 50 bytes +print-type-size variant `Small`: 7 bytes +print-type-size field `.0`: 7 bytes print-type-size type: `FiftyBytes`: 50 bytes, alignment: 1 bytes print-type-size field `.0`: 50 bytes print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes diff --git a/src/test/ui/priv-in-bad-locations.stderr b/src/test/ui/priv-in-bad-locations.stderr index 09706a6d255b4..713568f879dad 100644 --- a/src/test/ui/priv-in-bad-locations.stderr +++ b/src/test/ui/priv-in-bad-locations.stderr @@ -1,7 +1,7 @@ error[E0449]: unnecessary visibility qualifier --> $DIR/priv-in-bad-locations.rs:1:1 | -LL | pub extern { //~ ERROR unnecessary visibility qualifier +LL | pub extern { | ^^^ `pub` not permitted here because it's implied | = note: place qualifiers on individual foreign items instead @@ -9,7 +9,7 @@ LL | pub extern { //~ ERROR unnecessary visibility qualifier error[E0449]: unnecessary visibility qualifier --> $DIR/priv-in-bad-locations.rs:11:1 | -LL | pub impl B {} //~ ERROR unnecessary visibility qualifier +LL | pub impl B {} | ^^^ `pub` not permitted here because it's implied | = note: place qualifiers on individual impl items instead @@ -17,13 +17,13 @@ LL | pub impl B {} //~ ERROR unnecessary visibility qualifier error[E0449]: unnecessary visibility qualifier --> $DIR/priv-in-bad-locations.rs:13:1 | -LL | pub impl A for B { //~ ERROR unnecessary visibility qualifier +LL | pub impl A for B { | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/priv-in-bad-locations.rs:14:5 | -LL | pub fn foo(&self) {} //~ ERROR unnecessary visibility qualifier +LL | pub fn foo(&self) {} | ^^^ `pub` not permitted here because it's implied error: aborting due to 4 previous errors diff --git a/src/test/ui/privacy/decl-macro.stderr b/src/test/ui/privacy/decl-macro.stderr index c8b043d1b5f31..230cf95de6206 100644 --- a/src/test/ui/privacy/decl-macro.stderr +++ b/src/test/ui/privacy/decl-macro.stderr @@ -1,7 +1,7 @@ error[E0603]: macro `mac` is private --> $DIR/decl-macro.rs:8:8 | -LL | m::mac!(); //~ ERROR macro `mac` is private +LL | m::mac!(); | ^^^ error: aborting due to previous error diff --git a/src/test/ui/privacy/privacy-in-paths.stderr b/src/test/ui/privacy/privacy-in-paths.stderr index 563aaec89aa34..4b9faca045709 100644 --- a/src/test/ui/privacy/privacy-in-paths.stderr +++ b/src/test/ui/privacy/privacy-in-paths.stderr @@ -1,19 +1,19 @@ error[E0603]: module `bar` is private --> $DIR/privacy-in-paths.rs:24:16 | -LL | ::foo::bar::baz::f(); //~ERROR module `bar` is private +LL | ::foo::bar::baz::f(); | ^^^ error[E0603]: module `bar` is private --> $DIR/privacy-in-paths.rs:25:16 | -LL | ::foo::bar::S::f(); //~ERROR module `bar` is private +LL | ::foo::bar::S::f(); | ^^^ error[E0603]: trait `T` is private --> $DIR/privacy-in-paths.rs:26:23 | -LL | <() as ::foo::T>::Assoc::f(); //~ERROR trait `T` is private +LL | <() as ::foo::T>::Assoc::f(); | ^ error: aborting due to 3 previous errors diff --git a/src/test/ui/privacy/privacy-ns1.stderr b/src/test/ui/privacy/privacy-ns1.stderr index 6ba2dbe41a2b4..09148f9d0e6e1 100644 --- a/src/test/ui/privacy/privacy-ns1.stderr +++ b/src/test/ui/privacy/privacy-ns1.stderr @@ -1,11 +1,11 @@ error[E0423]: expected function, found trait `Bar` --> $DIR/privacy-ns1.rs:20:5 | -LL | Bar(); //~ ERROR expected function, found trait `Bar` +LL | Bar(); | ^^^ help: a unit struct with a similar name exists | -LL | Baz(); //~ ERROR expected function, found trait `Bar` +LL | Baz(); | ^^^ help: possible better candidates are found in other modules, you can import them into scope | @@ -19,11 +19,11 @@ LL | use foo3::Bar; error[E0573]: expected type, found function `Bar` --> $DIR/privacy-ns1.rs:35:17 | -LL | let _x: Box; //~ ERROR expected type, found function `Bar` +LL | let _x: Box; | ^^^ help: a struct with a similar name exists | -LL | let _x: Box; //~ ERROR expected type, found function `Bar` +LL | let _x: Box; | ^^^ help: possible better candidates are found in other modules, you can import them into scope | @@ -37,11 +37,11 @@ LL | use foo3::Bar; error[E0425]: cannot find function `Bar` in this scope --> $DIR/privacy-ns1.rs:50:5 | -LL | Bar(); //~ ERROR cannot find function `Bar` in this scope +LL | Bar(); | ^^^ help: a unit struct with a similar name exists | -LL | Baz(); //~ ERROR cannot find function `Bar` in this scope +LL | Baz(); | ^^^ help: possible candidates are found in other modules, you can import them into scope | @@ -55,11 +55,11 @@ LL | use foo3::Bar; error[E0412]: cannot find type `Bar` in this scope --> $DIR/privacy-ns1.rs:51:17 | -LL | let _x: Box; //~ ERROR cannot find type `Bar` in this scope +LL | let _x: Box; | ^^^ help: a struct with a similar name exists | -LL | let _x: Box; //~ ERROR cannot find type `Bar` in this scope +LL | let _x: Box; | ^^^ help: possible candidates are found in other modules, you can import them into scope | @@ -72,5 +72,5 @@ LL | use foo3::Bar; error: aborting due to 4 previous errors -Some errors occurred: E0412, E0423, E0425, E0573. +Some errors have detailed explanations: E0412, E0423, E0425. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/privacy/privacy-ns2.stderr b/src/test/ui/privacy/privacy-ns2.stderr index 0012072ed1138..8ea32f36f9e7a 100644 --- a/src/test/ui/privacy/privacy-ns2.stderr +++ b/src/test/ui/privacy/privacy-ns2.stderr @@ -1,7 +1,7 @@ error[E0423]: expected function, found trait `Bar` --> $DIR/privacy-ns2.rs:20:5 | -LL | Bar(); //~ ERROR expected function, found trait `Bar` +LL | Bar(); | ^^^ not a function help: possible better candidates are found in other modules, you can import them into scope | @@ -15,11 +15,11 @@ LL | use foo3::Bar; error[E0423]: expected function, found trait `Bar` --> $DIR/privacy-ns2.rs:26:5 | -LL | Bar(); //~ ERROR expected function, found trait `Bar` +LL | Bar(); | ^^^ help: a unit struct with a similar name exists | -LL | Baz(); //~ ERROR expected function, found trait `Bar` +LL | Baz(); | ^^^ help: possible better candidates are found in other modules, you can import them into scope | @@ -33,7 +33,7 @@ LL | use foo3::Bar; error[E0573]: expected type, found function `Bar` --> $DIR/privacy-ns2.rs:41:18 | -LL | let _x : Box; //~ ERROR expected type, found function `Bar` +LL | let _x : Box; | ^^^ not a type help: possible better candidates are found in other modules, you can import them into scope | @@ -47,11 +47,11 @@ LL | use foo3::Bar; error[E0573]: expected type, found function `Bar` --> $DIR/privacy-ns2.rs:47:17 | -LL | let _x: Box; //~ ERROR expected type, found function `Bar` +LL | let _x: Box; | ^^^ help: a struct with a similar name exists | -LL | let _x: Box; //~ ERROR expected type, found function `Bar` +LL | let _x: Box; | ^^^ help: possible better candidates are found in other modules, you can import them into scope | @@ -65,22 +65,22 @@ LL | use foo3::Bar; error[E0603]: trait `Bar` is private --> $DIR/privacy-ns2.rs:60:15 | -LL | use foo3::Bar; //~ ERROR `Bar` is private +LL | use foo3::Bar; | ^^^ error[E0603]: trait `Bar` is private --> $DIR/privacy-ns2.rs:64:15 | -LL | use foo3::Bar; //~ ERROR `Bar` is private +LL | use foo3::Bar; | ^^^ error[E0603]: trait `Bar` is private --> $DIR/privacy-ns2.rs:71:16 | -LL | use foo3::{Bar,Baz}; //~ ERROR `Bar` is private +LL | use foo3::{Bar,Baz}; | ^^^ error: aborting due to 7 previous errors -Some errors occurred: E0423, E0573, E0603. +Some errors have detailed explanations: E0423, E0603. For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/privacy/privacy-sanity.stderr b/src/test/ui/privacy/privacy-sanity.stderr index b1e3127645e0b..c92553fd1a16a 100644 --- a/src/test/ui/privacy/privacy-sanity.stderr +++ b/src/test/ui/privacy/privacy-sanity.stderr @@ -1,31 +1,31 @@ error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:13:1 | -LL | pub impl Tr for S { //~ ERROR unnecessary visibility qualifier +LL | pub impl Tr for S { | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:14:5 | -LL | pub fn f() {} //~ ERROR unnecessary visibility qualifier +LL | pub fn f() {} | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:15:5 | -LL | pub const C: u8 = 0; //~ ERROR unnecessary visibility qualifier +LL | pub const C: u8 = 0; | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:16:5 | -LL | pub type T = u8; //~ ERROR unnecessary visibility qualifier +LL | pub type T = u8; | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:18:1 | -LL | pub impl S { //~ ERROR unnecessary visibility qualifier +LL | pub impl S { | ^^^ `pub` not permitted here because it's implied | = note: place qualifiers on individual impl items instead @@ -33,7 +33,7 @@ LL | pub impl S { //~ ERROR unnecessary visibility qualifier error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:23:1 | -LL | pub extern "C" { //~ ERROR unnecessary visibility qualifier +LL | pub extern "C" { | ^^^ `pub` not permitted here because it's implied | = note: place qualifiers on individual foreign items instead @@ -41,31 +41,31 @@ LL | pub extern "C" { //~ ERROR unnecessary visibility qualifier error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:39:5 | -LL | pub impl Tr for S { //~ ERROR unnecessary visibility qualifier +LL | pub impl Tr for S { | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:40:9 | -LL | pub fn f() {} //~ ERROR unnecessary visibility qualifier +LL | pub fn f() {} | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:41:9 | -LL | pub const C: u8 = 0; //~ ERROR unnecessary visibility qualifier +LL | pub const C: u8 = 0; | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:42:9 | -LL | pub type T = u8; //~ ERROR unnecessary visibility qualifier +LL | pub type T = u8; | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:44:5 | -LL | pub impl S { //~ ERROR unnecessary visibility qualifier +LL | pub impl S { | ^^^ `pub` not permitted here because it's implied | = note: place qualifiers on individual impl items instead @@ -73,7 +73,7 @@ LL | pub impl S { //~ ERROR unnecessary visibility qualifier error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:49:5 | -LL | pub extern "C" { //~ ERROR unnecessary visibility qualifier +LL | pub extern "C" { | ^^^ `pub` not permitted here because it's implied | = note: place qualifiers on individual foreign items instead @@ -81,31 +81,31 @@ LL | pub extern "C" { //~ ERROR unnecessary visibility qualifier error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:68:5 | -LL | pub impl Tr for S { //~ ERROR unnecessary visibility qualifier +LL | pub impl Tr for S { | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:69:9 | -LL | pub fn f() {} //~ ERROR unnecessary visibility qualifier +LL | pub fn f() {} | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:70:9 | -LL | pub const C: u8 = 0; //~ ERROR unnecessary visibility qualifier +LL | pub const C: u8 = 0; | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:71:9 | -LL | pub type T = u8; //~ ERROR unnecessary visibility qualifier +LL | pub type T = u8; | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:73:5 | -LL | pub impl S { //~ ERROR unnecessary visibility qualifier +LL | pub impl S { | ^^^ `pub` not permitted here because it's implied | = note: place qualifiers on individual impl items instead @@ -113,7 +113,7 @@ LL | pub impl S { //~ ERROR unnecessary visibility qualifier error[E0449]: unnecessary visibility qualifier --> $DIR/privacy-sanity.rs:78:5 | -LL | pub extern "C" { //~ ERROR unnecessary visibility qualifier +LL | pub extern "C" { | ^^^ `pub` not permitted here because it's implied | = note: place qualifiers on individual foreign items instead diff --git a/src/test/ui/privacy/privacy-ufcs.stderr b/src/test/ui/privacy/privacy-ufcs.stderr index c70afe5061d39..6be14df89d20a 100644 --- a/src/test/ui/privacy/privacy-ufcs.stderr +++ b/src/test/ui/privacy/privacy-ufcs.stderr @@ -1,7 +1,7 @@ error[E0603]: trait `Bar` is private --> $DIR/privacy-ufcs.rs:12:20 | -LL | ::baz(); //~ERROR trait `Bar` is private +LL | ::baz(); | ^^^ error: aborting due to previous error diff --git a/src/test/ui/privacy/privacy1.stderr b/src/test/ui/privacy/privacy1.stderr index 7feebabe781ac..b647cc8ab8a83 100644 --- a/src/test/ui/privacy/privacy1.stderr +++ b/src/test/ui/privacy/privacy1.stderr @@ -13,55 +13,55 @@ LL | use bar::baz; error[E0603]: module `i` is private --> $DIR/privacy1.rs:164:20 | -LL | use self::foo::i::A; //~ ERROR: module `i` is private +LL | use self::foo::i::A; | ^ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:104:16 | -LL | ::bar::baz::A::foo(); //~ ERROR: module `baz` is private +LL | ::bar::baz::A::foo(); | ^^^ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:105:16 | -LL | ::bar::baz::A::bar(); //~ ERROR: module `baz` is private +LL | ::bar::baz::A::bar(); | ^^^ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:107:16 | -LL | ::bar::baz::A.foo2(); //~ ERROR: module `baz` is private +LL | ::bar::baz::A.foo2(); | ^^^ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:108:16 | -LL | ::bar::baz::A.bar2(); //~ ERROR: module `baz` is private +LL | ::bar::baz::A.bar2(); | ^^^ error[E0603]: trait `B` is private --> $DIR/privacy1.rs:112:16 | -LL | ::bar::B::foo(); //~ ERROR: trait `B` is private +LL | ::bar::B::foo(); | ^ error[E0603]: function `epriv` is private --> $DIR/privacy1.rs:118:20 | -LL | ::bar::epriv(); //~ ERROR: function `epriv` is private +LL | ::bar::epriv(); | ^^^^^ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:127:16 | -LL | ::bar::baz::foo(); //~ ERROR: module `baz` is private +LL | ::bar::baz::foo(); | ^^^ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:128:16 | -LL | ::bar::baz::bar(); //~ ERROR: module `baz` is private +LL | ::bar::baz::bar(); | ^^^ error[E0603]: trait `B` is private @@ -73,34 +73,34 @@ LL | impl ::bar::B for f32 { fn foo() -> f32 { 1.0 } } error[E0624]: method `bar` is private --> $DIR/privacy1.rs:77:9 | -LL | self::baz::A::bar(); //~ ERROR: method `bar` is private +LL | self::baz::A::bar(); | ^^^^^^^^^^^^^^^^^ error[E0624]: method `bar` is private --> $DIR/privacy1.rs:95:5 | -LL | bar::A::bar(); //~ ERROR: method `bar` is private +LL | bar::A::bar(); | ^^^^^^^^^^^ error[E0624]: method `bar` is private --> $DIR/privacy1.rs:102:9 | -LL | ::bar::A::bar(); //~ ERROR: method `bar` is private +LL | ::bar::A::bar(); | ^^^^^^^^^^^^^ error[E0624]: method `bar` is private --> $DIR/privacy1.rs:105:9 | -LL | ::bar::baz::A::bar(); //~ ERROR: module `baz` is private +LL | ::bar::baz::A::bar(); | ^^^^^^^^^^^^^^^^^^ error[E0624]: method `bar2` is private --> $DIR/privacy1.rs:108:23 | -LL | ::bar::baz::A.bar2(); //~ ERROR: module `baz` is private +LL | ::bar::baz::A.bar2(); | ^^^^ error: aborting due to 17 previous errors -Some errors occurred: E0603, E0624. +Some errors have detailed explanations: E0603, E0624. For more information about an error, try `rustc --explain E0603`. diff --git a/src/test/ui/privacy/privacy2.stderr b/src/test/ui/privacy/privacy2.stderr index 2e6bb99f43664..9f2359657bd7c 100644 --- a/src/test/ui/privacy/privacy2.stderr +++ b/src/test/ui/privacy/privacy2.stderr @@ -14,5 +14,5 @@ error: requires `sized` lang_item error: aborting due to 3 previous errors -Some errors occurred: E0432, E0603. +Some errors have detailed explanations: E0432, E0603. For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/privacy/privacy4.stderr b/src/test/ui/privacy/privacy4.stderr index 9e3e48272f90a..e4a20f920a062 100644 --- a/src/test/ui/privacy/privacy4.stderr +++ b/src/test/ui/privacy/privacy4.stderr @@ -1,7 +1,7 @@ error[E0603]: module `glob` is private --> $DIR/privacy4.rs:21:14 | -LL | use bar::glob::gpriv; //~ ERROR: module `glob` is private +LL | use bar::glob::gpriv; | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/privacy/privacy5.stderr b/src/test/ui/privacy/privacy5.stderr index cdd9b2cefbba7..7568c346b2489 100644 --- a/src/test/ui/privacy/privacy5.stderr +++ b/src/test/ui/privacy/privacy5.stderr @@ -1,289 +1,289 @@ error[E0603]: tuple struct `A` is private --> $DIR/privacy5.rs:51:16 | -LL | let a = a::A(()); //~ ERROR tuple struct `A` is private +LL | let a = a::A(()); | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:52:16 | -LL | let b = a::B(2); //~ ERROR tuple struct `B` is private +LL | let b = a::B(2); | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:53:16 | -LL | let c = a::C(2, 3); //~ ERROR tuple struct `C` is private +LL | let c = a::C(2, 3); | ^ error[E0603]: tuple struct `A` is private --> $DIR/privacy5.rs:56:12 | -LL | let a::A(()) = a; //~ ERROR tuple struct `A` is private +LL | let a::A(()) = a; | ^ error[E0603]: tuple struct `A` is private --> $DIR/privacy5.rs:57:12 | -LL | let a::A(_) = a; //~ ERROR tuple struct `A` is private +LL | let a::A(_) = a; | ^ error[E0603]: tuple struct `A` is private --> $DIR/privacy5.rs:58:18 | -LL | match a { a::A(()) => {} } //~ ERROR tuple struct `A` is private +LL | match a { a::A(()) => {} } | ^ error[E0603]: tuple struct `A` is private --> $DIR/privacy5.rs:59:18 | -LL | match a { a::A(_) => {} } //~ ERROR tuple struct `A` is private +LL | match a { a::A(_) => {} } | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:61:12 | -LL | let a::B(_) = b; //~ ERROR tuple struct `B` is private +LL | let a::B(_) = b; | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:62:12 | -LL | let a::B(_b) = b; //~ ERROR tuple struct `B` is private +LL | let a::B(_b) = b; | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:63:18 | -LL | match b { a::B(_) => {} } //~ ERROR tuple struct `B` is private +LL | match b { a::B(_) => {} } | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:64:18 | -LL | match b { a::B(_b) => {} } //~ ERROR tuple struct `B` is private +LL | match b { a::B(_b) => {} } | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:65:18 | -LL | match b { a::B(1) => {} a::B(_) => {} } //~ ERROR tuple struct `B` is private +LL | match b { a::B(1) => {} a::B(_) => {} } | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:65:32 | -LL | match b { a::B(1) => {} a::B(_) => {} } //~ ERROR tuple struct `B` is private +LL | match b { a::B(1) => {} a::B(_) => {} } | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:68:12 | -LL | let a::C(_, _) = c; //~ ERROR tuple struct `C` is private +LL | let a::C(_, _) = c; | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:69:12 | -LL | let a::C(_a, _) = c; //~ ERROR tuple struct `C` is private +LL | let a::C(_a, _) = c; | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:70:12 | -LL | let a::C(_, _b) = c; //~ ERROR tuple struct `C` is private +LL | let a::C(_, _b) = c; | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:71:12 | -LL | let a::C(_a, _b) = c; //~ ERROR tuple struct `C` is private +LL | let a::C(_a, _b) = c; | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:72:18 | -LL | match c { a::C(_, _) => {} } //~ ERROR tuple struct `C` is private +LL | match c { a::C(_, _) => {} } | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:73:18 | -LL | match c { a::C(_a, _) => {} } //~ ERROR tuple struct `C` is private +LL | match c { a::C(_a, _) => {} } | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:74:18 | -LL | match c { a::C(_, _b) => {} } //~ ERROR tuple struct `C` is private +LL | match c { a::C(_, _b) => {} } | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:75:18 | -LL | match c { a::C(_a, _b) => {} } //~ ERROR tuple struct `C` is private +LL | match c { a::C(_a, _b) => {} } | ^ error[E0603]: tuple struct `A` is private --> $DIR/privacy5.rs:83:17 | -LL | let a2 = a::A; //~ ERROR tuple struct `A` is private +LL | let a2 = a::A; | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:84:17 | -LL | let b2 = a::B; //~ ERROR tuple struct `B` is private +LL | let b2 = a::B; | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:85:17 | -LL | let c2 = a::C; //~ ERROR tuple struct `C` is private +LL | let c2 = a::C; | ^ error[E0603]: tuple struct `A` is private --> $DIR/privacy5.rs:90:20 | -LL | let a = other::A(()); //~ ERROR tuple struct `A` is private +LL | let a = other::A(()); | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:91:20 | -LL | let b = other::B(2); //~ ERROR tuple struct `B` is private +LL | let b = other::B(2); | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:92:20 | -LL | let c = other::C(2, 3); //~ ERROR tuple struct `C` is private +LL | let c = other::C(2, 3); | ^ error[E0603]: tuple struct `A` is private --> $DIR/privacy5.rs:95:16 | -LL | let other::A(()) = a; //~ ERROR tuple struct `A` is private +LL | let other::A(()) = a; | ^ error[E0603]: tuple struct `A` is private --> $DIR/privacy5.rs:96:16 | -LL | let other::A(_) = a; //~ ERROR tuple struct `A` is private +LL | let other::A(_) = a; | ^ error[E0603]: tuple struct `A` is private --> $DIR/privacy5.rs:97:22 | -LL | match a { other::A(()) => {} } //~ ERROR tuple struct `A` is private +LL | match a { other::A(()) => {} } | ^ error[E0603]: tuple struct `A` is private --> $DIR/privacy5.rs:98:22 | -LL | match a { other::A(_) => {} } //~ ERROR tuple struct `A` is private +LL | match a { other::A(_) => {} } | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:100:16 | -LL | let other::B(_) = b; //~ ERROR tuple struct `B` is private +LL | let other::B(_) = b; | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:101:16 | -LL | let other::B(_b) = b; //~ ERROR tuple struct `B` is private +LL | let other::B(_b) = b; | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:102:22 | -LL | match b { other::B(_) => {} } //~ ERROR tuple struct `B` is private +LL | match b { other::B(_) => {} } | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:103:22 | -LL | match b { other::B(_b) => {} } //~ ERROR tuple struct `B` is private +LL | match b { other::B(_b) => {} } | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:104:22 | -LL | match b { other::B(1) => {} other::B(_) => {} } //~ ERROR tuple struct `B` is private +LL | match b { other::B(1) => {} other::B(_) => {} } | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:104:40 | -LL | match b { other::B(1) => {} other::B(_) => {} } //~ ERROR tuple struct `B` is private +LL | match b { other::B(1) => {} other::B(_) => {} } | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:107:16 | -LL | let other::C(_, _) = c; //~ ERROR tuple struct `C` is private +LL | let other::C(_, _) = c; | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:108:16 | -LL | let other::C(_a, _) = c; //~ ERROR tuple struct `C` is private +LL | let other::C(_a, _) = c; | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:109:16 | -LL | let other::C(_, _b) = c; //~ ERROR tuple struct `C` is private +LL | let other::C(_, _b) = c; | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:110:16 | -LL | let other::C(_a, _b) = c; //~ ERROR tuple struct `C` is private +LL | let other::C(_a, _b) = c; | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:111:22 | -LL | match c { other::C(_, _) => {} } //~ ERROR tuple struct `C` is private +LL | match c { other::C(_, _) => {} } | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:112:22 | -LL | match c { other::C(_a, _) => {} } //~ ERROR tuple struct `C` is private +LL | match c { other::C(_a, _) => {} } | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:113:22 | -LL | match c { other::C(_, _b) => {} } //~ ERROR tuple struct `C` is private +LL | match c { other::C(_, _b) => {} } | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:114:22 | -LL | match c { other::C(_a, _b) => {} } //~ ERROR tuple struct `C` is private +LL | match c { other::C(_a, _b) => {} } | ^ error[E0603]: tuple struct `A` is private --> $DIR/privacy5.rs:122:21 | -LL | let a2 = other::A; //~ ERROR tuple struct `A` is private +LL | let a2 = other::A; | ^ error[E0603]: tuple struct `B` is private --> $DIR/privacy5.rs:123:21 | -LL | let b2 = other::B; //~ ERROR tuple struct `B` is private +LL | let b2 = other::B; | ^ error[E0603]: tuple struct `C` is private --> $DIR/privacy5.rs:124:21 | -LL | let c2 = other::C; //~ ERROR tuple struct `C` is private +LL | let c2 = other::C; | ^ error: aborting due to 48 previous errors diff --git a/src/test/ui/privacy/private-impl-method.stderr b/src/test/ui/privacy/private-impl-method.stderr index 8e254b15c7895..e1da3f47a4ef7 100644 --- a/src/test/ui/privacy/private-impl-method.stderr +++ b/src/test/ui/privacy/private-impl-method.stderr @@ -1,7 +1,7 @@ error[E0624]: method `foo` is private --> $DIR/private-impl-method.rs:20:7 | -LL | s.foo(); //~ ERROR method `foo` is private +LL | s.foo(); | ^^^ error: aborting due to previous error diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.stderr b/src/test/ui/privacy/private-in-public-assoc-ty.stderr index 0e5dab1a08c37..81d70ee770857 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.stderr +++ b/src/test/ui/privacy/private-in-public-assoc-ty.stderr @@ -2,9 +2,9 @@ warning: private trait `m::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-assoc-ty.rs:15:5 | LL | / pub trait PubTr { -LL | | //~^ WARN private trait `m::PrivTr` in public interface -LL | | //~| WARN this was previously accepted -LL | | //~| WARN private type `m::Priv` in public interface +LL | | +LL | | +LL | | ... | LL | | fn infer_exist() -> Self::Exist; LL | | } @@ -18,9 +18,9 @@ warning: private type `m::Priv` in public interface (error E0446) --> $DIR/private-in-public-assoc-ty.rs:15:5 | LL | / pub trait PubTr { -LL | | //~^ WARN private trait `m::PrivTr` in public interface -LL | | //~| WARN this was previously accepted -LL | | //~| WARN private type `m::Priv` in public interface +LL | | +LL | | +LL | | ... | LL | | fn infer_exist() -> Self::Exist; LL | | } @@ -58,5 +58,5 @@ LL | existential type Exist: PrivTr; error: aborting due to 3 previous errors -Some errors occurred: E0445, E0446. +Some errors have detailed explanations: E0445, E0446. For more information about an error, try `rustc --explain E0445`. diff --git a/src/test/ui/privacy/private-in-public-ill-formed.stderr b/src/test/ui/privacy/private-in-public-ill-formed.stderr index ab6531cc748ed..a1a326f2873e1 100644 --- a/src/test/ui/privacy/private-in-public-ill-formed.stderr +++ b/src/test/ui/privacy/private-in-public-ill-formed.stderr @@ -1,7 +1,7 @@ error[E0118]: no base type found for inherent implementation --> $DIR/private-in-public-ill-formed.rs:14:10 | -LL | impl ::AssocAlias { //~ ERROR no base type found for inherent implementation +LL | impl ::AssocAlias { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a base type | = note: either implement a trait on it or create a newtype to wrap it instead @@ -9,7 +9,7 @@ LL | impl ::AssocAlias { //~ ERROR no base type found for in error[E0118]: no base type found for inherent implementation --> $DIR/private-in-public-ill-formed.rs:30:10 | -LL | impl ::AssocAlias { //~ ERROR no base type found for inherent implementation +LL | impl ::AssocAlias { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a base type | = note: either implement a trait on it or create a newtype to wrap it instead diff --git a/src/test/ui/privacy/private-in-public-lint.stderr b/src/test/ui/privacy/private-in-public-lint.stderr index 730ac24d5e54f..441a4d5cffd49 100644 --- a/src/test/ui/privacy/private-in-public-lint.stderr +++ b/src/test/ui/privacy/private-in-public-lint.stderr @@ -4,7 +4,7 @@ error[E0446]: private type `m1::Priv` in public interface LL | struct Priv; | - `m1::Priv` declared as private ... -LL | pub fn f() -> Priv {Priv} //~ ERROR private type `m1::Priv` in public interface +LL | pub fn f() -> Priv {Priv} | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `m2::Priv` in public interface @@ -13,7 +13,7 @@ error[E0446]: private type `m2::Priv` in public interface LL | struct Priv; | - `m2::Priv` declared as private ... -LL | pub fn f() -> Priv {Priv} //~ ERROR private type `m2::Priv` in public interface +LL | pub fn f() -> Priv {Priv} | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error: aborting due to 2 previous errors diff --git a/src/test/ui/privacy/private-in-public-non-principal-2.rs b/src/test/ui/privacy/private-in-public-non-principal-2.rs index 02fd92aa7a4ef..8a59073fa6c7e 100644 --- a/src/test/ui/privacy/private-in-public-non-principal-2.rs +++ b/src/test/ui/privacy/private-in-public-non-principal-2.rs @@ -4,7 +4,7 @@ mod m { pub trait PubPrincipal {} auto trait PrivNonPrincipal {} - pub fn leak_dyn_nonprincipal() -> Box { loop {} } + pub fn leak_dyn_nonprincipal() -> Box { loop {} } } fn main() { diff --git a/src/test/ui/privacy/private-in-public-non-principal.rs b/src/test/ui/privacy/private-in-public-non-principal.rs index 5de5a685208cd..5d89d8105b119 100644 --- a/src/test/ui/privacy/private-in-public-non-principal.rs +++ b/src/test/ui/privacy/private-in-public-non-principal.rs @@ -3,7 +3,7 @@ pub trait PubPrincipal {} auto trait PrivNonPrincipal {} -pub fn leak_dyn_nonprincipal() -> Box { loop {} } +pub fn leak_dyn_nonprincipal() -> Box { loop {} } //~^ WARN private trait `PrivNonPrincipal` in public interface //~| WARN this was previously accepted diff --git a/src/test/ui/privacy/private-in-public-non-principal.stderr b/src/test/ui/privacy/private-in-public-non-principal.stderr index 9967405589777..578f4380b4225 100644 --- a/src/test/ui/privacy/private-in-public-non-principal.stderr +++ b/src/test/ui/privacy/private-in-public-non-principal.stderr @@ -1,8 +1,8 @@ warning: private trait `PrivNonPrincipal` in public interface (error E0445) --> $DIR/private-in-public-non-principal.rs:6:1 | -LL | pub fn leak_dyn_nonprincipal() -> Box { loop {} } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub fn leak_dyn_nonprincipal() -> Box { loop {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: #[warn(private_in_public)] on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -11,7 +11,7 @@ LL | pub fn leak_dyn_nonprincipal() -> Box { lo error: missing documentation for a method --> $DIR/private-in-public-non-principal.rs:13:9 | -LL | pub fn check_doc_lint() {} //~ ERROR missing documentation for a method +LL | pub fn check_doc_lint() {} | ^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/privacy/private-in-public-warn.stderr b/src/test/ui/privacy/private-in-public-warn.stderr index 621d9a57fa076..16b7e5103283f 100644 --- a/src/test/ui/privacy/private-in-public-warn.stderr +++ b/src/test/ui/privacy/private-in-public-warn.stderr @@ -1,7 +1,7 @@ error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:15:5 | -LL | pub type Alias = Priv; //~ ERROR private type `types::Priv` in public interface +LL | pub type Alias = Priv; | ^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -15,7 +15,7 @@ LL | #![deny(private_in_public)] error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:18:12 | -LL | V1(Priv), //~ ERROR private type `types::Priv` in public interface +LL | V1(Priv), | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -24,7 +24,7 @@ LL | V1(Priv), //~ ERROR private type `types::Priv` in public interface error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:20:14 | -LL | V2 { field: Priv }, //~ ERROR private type `types::Priv` in public interface +LL | V2 { field: Priv }, | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -33,7 +33,7 @@ LL | V2 { field: Priv }, //~ ERROR private type `types::Priv` in public error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:24:9 | -LL | const C: Priv = Priv; //~ ERROR private type `types::Priv` in public interface +LL | const C: Priv = Priv; | ^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -45,13 +45,13 @@ error[E0446]: private type `types::Priv` in public interface LL | struct Priv; | - `types::Priv` declared as private ... -LL | type Alias = Priv; //~ ERROR private type `types::Priv` in public interface +LL | type Alias = Priv; | ^^^^^^^^^^^^^^^^^^ can't leak private type error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:27:9 | -LL | fn f1(arg: Priv) {} //~ ERROR private type `types::Priv` in public interface +LL | fn f1(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -60,7 +60,7 @@ LL | fn f1(arg: Priv) {} //~ ERROR private type `types::Priv` in public error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:29:9 | -LL | fn f2() -> Priv { panic!() } //~ ERROR private type `types::Priv` in public interface +LL | fn f2() -> Priv { panic!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -69,7 +69,7 @@ LL | fn f2() -> Priv { panic!() } //~ ERROR private type `types::Priv` i error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:33:9 | -LL | pub static ES: Priv; //~ ERROR private type `types::Priv` in public interface +LL | pub static ES: Priv; | ^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -78,7 +78,7 @@ LL | pub static ES: Priv; //~ ERROR private type `types::Priv` in public error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:35:9 | -LL | pub fn ef1(arg: Priv); //~ ERROR private type `types::Priv` in public interface +LL | pub fn ef1(arg: Priv); | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -87,7 +87,7 @@ LL | pub fn ef1(arg: Priv); //~ ERROR private type `types::Priv` in publ error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:37:9 | -LL | pub fn ef2() -> Priv; //~ ERROR private type `types::Priv` in public interface +LL | pub fn ef2() -> Priv; | ^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -99,13 +99,13 @@ error[E0446]: private type `types::Priv` in public interface LL | struct Priv; | - `types::Priv` declared as private ... -LL | type Alias = Priv; //~ ERROR private type `types::Priv` in public interface +LL | type Alias = Priv; | ^^^^^^^^^^^^^^^^^^ can't leak private type error: private trait `traits::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:50:5 | -LL | pub type Alias = T; //~ ERROR private trait `traits::PrivTr` in public interface +LL | pub type Alias = T; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -114,7 +114,7 @@ LL | pub type Alias = T; //~ ERROR private trait `traits::PrivTr` error: private trait `traits::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:53:5 | -LL | pub trait Tr1: PrivTr {} //~ ERROR private trait `traits::PrivTr` in public interface +LL | pub trait Tr1: PrivTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -123,7 +123,7 @@ LL | pub trait Tr1: PrivTr {} //~ ERROR private trait `traits::PrivTr` in pu error: private trait `traits::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:55:5 | -LL | pub trait Tr2 {} //~ ERROR private trait `traits::PrivTr` in public interface +LL | pub trait Tr2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -133,11 +133,11 @@ error: private trait `traits::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:57:5 | LL | / pub trait Tr3 { -LL | | //~^ ERROR private trait `traits::PrivTr` in public interface -LL | | //~| WARNING hard error +LL | | +LL | | LL | | type Alias: PrivTr; -LL | | fn f(arg: T) {} //~ ERROR private trait `traits::PrivTr` in public interface -LL | | //~^ WARNING hard error +LL | | fn f(arg: T) {} +LL | | LL | | } | |_____^ | @@ -147,7 +147,7 @@ LL | | } error: private trait `traits::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:61:9 | -LL | fn f(arg: T) {} //~ ERROR private trait `traits::PrivTr` in public interface +LL | fn f(arg: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -156,7 +156,7 @@ LL | fn f(arg: T) {} //~ ERROR private trait `traits::PrivTr` error: private trait `traits::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:64:5 | -LL | impl Pub {} //~ ERROR private trait `traits::PrivTr` in public interface +LL | impl Pub {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -165,7 +165,7 @@ LL | impl Pub {} //~ ERROR private trait `traits::PrivTr` in p error: private trait `traits::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:66:5 | -LL | impl PubTr for Pub {} //~ ERROR private trait `traits::PrivTr` in public interface +LL | impl PubTr for Pub {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -228,7 +228,7 @@ LL | pub trait Tr1: PrivTr {} error: private type `generics::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:104:5 | -LL | pub trait Tr2: PubTr {} //~ ERROR private type `generics::Priv` in public interface +LL | pub trait Tr2: PubTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -237,7 +237,7 @@ LL | pub trait Tr2: PubTr {} //~ ERROR private type `generics::Priv` i error: private type `generics::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:106:5 | -LL | pub trait Tr3: PubTr<[Priv; 1]> {} //~ ERROR private type `generics::Priv` in public interface +LL | pub trait Tr3: PubTr<[Priv; 1]> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -246,7 +246,7 @@ LL | pub trait Tr3: PubTr<[Priv; 1]> {} //~ ERROR private type `generics::Pr error: private type `generics::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:108:5 | -LL | pub trait Tr4: PubTr> {} //~ ERROR private type `generics::Priv` in public interface +LL | pub trait Tr4: PubTr> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -258,13 +258,13 @@ error[E0446]: private type `impls::Priv` in public interface LL | struct Priv; | - `impls::Priv` declared as private ... -LL | type Alias = Priv; //~ ERROR private type `impls::Priv` in public interface +LL | type Alias = Priv; | ^^^^^^^^^^^^^^^^^^ can't leak private type error: private type `aliases_pub::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:206:9 | -LL | pub fn f(arg: Priv) {} //~ ERROR private type `aliases_pub::Priv` in public interface +LL | pub fn f(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -276,7 +276,7 @@ error[E0446]: private type `aliases_pub::Priv` in public interface LL | struct Priv; | - `aliases_pub::Priv` declared as private ... -LL | type Check = Priv; //~ ERROR private type `aliases_pub::Priv` in public interface +LL | type Check = Priv; | ^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_pub::Priv` in public interface @@ -285,7 +285,7 @@ error[E0446]: private type `aliases_pub::Priv` in public interface LL | struct Priv; | - `aliases_pub::Priv` declared as private ... -LL | type Check = Priv; //~ ERROR private type `aliases_pub::Priv` in public interface +LL | type Check = Priv; | ^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_pub::Priv` in public interface @@ -294,7 +294,7 @@ error[E0446]: private type `aliases_pub::Priv` in public interface LL | struct Priv; | - `aliases_pub::Priv` declared as private ... -LL | type Check = Priv; //~ ERROR private type `aliases_pub::Priv` in public interface +LL | type Check = Priv; | ^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_pub::Priv` in public interface @@ -303,7 +303,7 @@ error[E0446]: private type `aliases_pub::Priv` in public interface LL | struct Priv; | - `aliases_pub::Priv` declared as private ... -LL | type Check = Priv; //~ ERROR private type `aliases_pub::Priv` in public interface +LL | type Check = Priv; | ^^^^^^^^^^^^^^^^^^ can't leak private type error: private trait `aliases_priv::PrivTr1` in public interface (error E0445) @@ -336,7 +336,7 @@ LL | pub trait Tr2: PrivUseAliasTr {} warning: bounds on generic parameters are not enforced in type aliases --> $DIR/private-in-public-warn.rs:50:23 | -LL | pub type Alias = T; //~ ERROR private trait `traits::PrivTr` in public interface +LL | pub type Alias = T; | ^^^^^^ | = note: #[warn(type_alias_bounds)] on by default diff --git a/src/test/ui/privacy/private-in-public.stderr b/src/test/ui/privacy/private-in-public.stderr index bf88a83e633cc..e3fa4c145c3dd 100644 --- a/src/test/ui/privacy/private-in-public.stderr +++ b/src/test/ui/privacy/private-in-public.stderr @@ -4,7 +4,7 @@ error[E0446]: private type `types::Priv` in public interface LL | struct Priv; | - `types::Priv` declared as private ... -LL | pub const C: Priv = Priv; //~ ERROR private type `types::Priv` in public interface +LL | pub const C: Priv = Priv; | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface @@ -13,7 +13,7 @@ error[E0446]: private type `types::Priv` in public interface LL | struct Priv; | - `types::Priv` declared as private ... -LL | pub static S: Priv = Priv; //~ ERROR private type `types::Priv` in public interface +LL | pub static S: Priv = Priv; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface @@ -22,7 +22,7 @@ error[E0446]: private type `types::Priv` in public interface LL | struct Priv; | - `types::Priv` declared as private ... -LL | pub fn f1(arg: Priv) {} //~ ERROR private type `types::Priv` in public interface +LL | pub fn f1(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface @@ -31,7 +31,7 @@ error[E0446]: private type `types::Priv` in public interface LL | struct Priv; | - `types::Priv` declared as private ... -LL | pub fn f2() -> Priv { panic!() } //~ ERROR private type `types::Priv` in public interface +LL | pub fn f2() -> Priv { panic!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface @@ -40,7 +40,7 @@ error[E0446]: private type `types::Priv` in public interface LL | struct Priv; | - `types::Priv` declared as private ... -LL | pub struct S1(pub Priv); //~ ERROR private type `types::Priv` in public interface +LL | pub struct S1(pub Priv); | ^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface @@ -49,7 +49,7 @@ error[E0446]: private type `types::Priv` in public interface LL | struct Priv; | - `types::Priv` declared as private ... -LL | pub struct S2 { pub field: Priv } //~ ERROR private type `types::Priv` in public interface +LL | pub struct S2 { pub field: Priv } | ^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface @@ -58,7 +58,7 @@ error[E0446]: private type `types::Priv` in public interface LL | struct Priv; | - `types::Priv` declared as private ... -LL | pub const C: Priv = Priv; //~ ERROR private type `types::Priv` in public interface +LL | pub const C: Priv = Priv; | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface @@ -67,7 +67,7 @@ error[E0446]: private type `types::Priv` in public interface LL | struct Priv; | - `types::Priv` declared as private ... -LL | pub fn f1(arg: Priv) {} //~ ERROR private type `types::Priv` in public interface +LL | pub fn f1(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface @@ -76,7 +76,7 @@ error[E0446]: private type `types::Priv` in public interface LL | struct Priv; | - `types::Priv` declared as private ... -LL | pub fn f2() -> Priv { panic!() } //~ ERROR private type `types::Priv` in public interface +LL | pub fn f2() -> Priv { panic!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0445]: private trait `traits::PrivTr` in public interface @@ -85,7 +85,7 @@ error[E0445]: private trait `traits::PrivTr` in public interface LL | trait PrivTr {} | - `traits::PrivTr` declared as private ... -LL | pub enum E { V(T) } //~ ERROR private trait `traits::PrivTr` in public interface +LL | pub enum E { V(T) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `traits::PrivTr` in public interface @@ -94,7 +94,7 @@ error[E0445]: private trait `traits::PrivTr` in public interface LL | trait PrivTr {} | - `traits::PrivTr` declared as private ... -LL | pub fn f(arg: T) {} //~ ERROR private trait `traits::PrivTr` in public interface +LL | pub fn f(arg: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `traits::PrivTr` in public interface @@ -103,7 +103,7 @@ error[E0445]: private trait `traits::PrivTr` in public interface LL | trait PrivTr {} | - `traits::PrivTr` declared as private ... -LL | pub struct S1(T); //~ ERROR private trait `traits::PrivTr` in public interface +LL | pub struct S1(T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `traits::PrivTr` in public interface @@ -112,8 +112,8 @@ error[E0445]: private trait `traits::PrivTr` in public interface LL | trait PrivTr {} | - `traits::PrivTr` declared as private ... -LL | / impl Pub { //~ ERROR private trait `traits::PrivTr` in public interface -LL | | pub fn f(arg: U) {} //~ ERROR private trait `traits::PrivTr` in public interface +LL | / impl Pub { +LL | | pub fn f(arg: U) {} LL | | } | |_____^ can't leak private trait @@ -123,7 +123,7 @@ error[E0445]: private trait `traits::PrivTr` in public interface LL | trait PrivTr {} | - `traits::PrivTr` declared as private ... -LL | pub fn f(arg: U) {} //~ ERROR private trait `traits::PrivTr` in public interface +LL | pub fn f(arg: U) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `traits_where::PrivTr` in public interface @@ -160,9 +160,9 @@ LL | trait PrivTr {} | - `traits_where::PrivTr` declared as private ... LL | / impl Pub where T: PrivTr { -LL | | //~^ ERROR private trait `traits_where::PrivTr` in public interface +LL | | LL | | pub fn f(arg: U) where U: PrivTr {} -LL | | //~^ ERROR private trait `traits_where::PrivTr` in public interface +LL | | LL | | } | |_____^ can't leak private trait @@ -181,7 +181,7 @@ error[E0446]: private type `generics::Priv` in public interface LL | struct Priv(T); | - `generics::Priv` declared as private ... -LL | pub fn f1(arg: [Priv; 1]) {} //~ ERROR private type `generics::Priv` in public interface +LL | pub fn f1(arg: [Priv; 1]) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `generics::Priv` in public interface @@ -190,7 +190,7 @@ error[E0446]: private type `generics::Priv` in public interface LL | struct Priv(T); | - `generics::Priv` declared as private ... -LL | pub fn f2(arg: Pub) {} //~ ERROR private type `generics::Priv` in public interface +LL | pub fn f2(arg: Pub) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `generics::Priv` in public interface @@ -208,7 +208,7 @@ error[E0446]: private type `impls::Priv` in public interface LL | struct Priv; | - `impls::Priv` declared as private ... -LL | pub fn f(arg: Priv) {} //~ ERROR private type `impls::Priv` in public interface +LL | pub fn f(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0445]: private trait `aliases_pub::PrivTr` in public interface @@ -235,7 +235,7 @@ error[E0446]: private type `aliases_pub::Priv` in public interface LL | struct Priv; | - `aliases_pub::Priv` declared as private ... -LL | pub fn f(arg: Priv) {} //~ ERROR private type `aliases_pub::Priv` in public interface +LL | pub fn f(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_priv::Priv1` in public interface @@ -244,7 +244,7 @@ error[E0446]: private type `aliases_priv::Priv1` in public interface LL | struct Priv1; | - `aliases_priv::Priv1` declared as private ... -LL | pub fn f1(arg: PrivUseAlias) {} //~ ERROR private type `aliases_priv::Priv1` in public interface +LL | pub fn f1(arg: PrivUseAlias) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_priv::Priv2` in public interface @@ -253,7 +253,7 @@ error[E0446]: private type `aliases_priv::Priv2` in public interface LL | struct Priv2; | - `aliases_priv::Priv2` declared as private ... -LL | pub fn f2(arg: PrivAlias) {} //~ ERROR private type `aliases_priv::Priv2` in public interface +LL | pub fn f2(arg: PrivAlias) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0445]: private trait `aliases_priv::PrivTr` in public interface @@ -289,10 +289,10 @@ error[E0446]: private type `aliases_params::Priv` in public interface LL | struct Priv; | - `aliases_params::Priv` declared as private ... -LL | pub fn f3(arg: Result) {} //~ ERROR private type `aliases_params::Priv` in public interface +LL | pub fn f3(arg: Result) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error: aborting due to 32 previous errors -Some errors occurred: E0445, E0446. +Some errors have detailed explanations: E0445, E0446. For more information about an error, try `rustc --explain E0445`. diff --git a/src/test/ui/privacy/private-inferred-type-1.stderr b/src/test/ui/privacy/private-inferred-type-1.stderr index 06df7e8478370..097b8b9a61eff 100644 --- a/src/test/ui/privacy/private-inferred-type-1.stderr +++ b/src/test/ui/privacy/private-inferred-type-1.stderr @@ -1,13 +1,13 @@ error: type `m::Priv` is private --> $DIR/private-inferred-type-1.rs:16:5 | -LL | [].arr0_secret(); //~ ERROR type `m::Priv` is private +LL | [].arr0_secret(); | ^^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type-1.rs:17:5 | -LL | None.ty_param_secret(); //~ ERROR type `m::Priv` is private +LL | None.ty_param_secret(); | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/privacy/private-inferred-type-2.stderr b/src/test/ui/privacy/private-inferred-type-2.stderr index 7a3f52fa05df7..da95cc49241ae 100644 --- a/src/test/ui/privacy/private-inferred-type-2.stderr +++ b/src/test/ui/privacy/private-inferred-type-2.stderr @@ -1,19 +1,19 @@ error: type `m::Priv` is private --> $DIR/private-inferred-type-2.rs:16:5 | -LL | m::Pub::get_priv; //~ ERROR type `m::Priv` is private +LL | m::Pub::get_priv; | ^^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type-2.rs:17:5 | -LL | m::Pub::static_method; //~ ERROR type `m::Priv` is private +LL | m::Pub::static_method; | ^^^^^^^^^^^^^^^^^^^^^ error: type `ext::Priv` is private --> $DIR/private-inferred-type-2.rs:18:5 | -LL | ext::Pub::static_method; //~ ERROR type `ext::Priv` is private +LL | ext::Pub::static_method; | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/privacy/private-inferred-type-3.rs b/src/test/ui/privacy/private-inferred-type-3.rs index d885407a1cd37..39f2e5d4af2aa 100644 --- a/src/test/ui/privacy/private-inferred-type-3.rs +++ b/src/test/ui/privacy/private-inferred-type-3.rs @@ -6,7 +6,7 @@ // error-pattern:type `fn() {::method}` is private // error-pattern:type `fn(u8) -> ext::PrivTupleStruct {ext::PrivTupleStruct}` is private // error-pattern:type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct}` is private -// error-pattern:type `for<'r> fn(&'r ext::Pub) {>::priv_method}` is private +// error-pattern:type `for<'r> fn(&'r ext::Pub) {ext::Pub::::priv_method}` is private #![feature(decl_macro)] diff --git a/src/test/ui/privacy/private-inferred-type-3.stderr b/src/test/ui/privacy/private-inferred-type-3.stderr index f8b757ea09820..61cd84762978c 100644 --- a/src/test/ui/privacy/private-inferred-type-3.stderr +++ b/src/test/ui/privacy/private-inferred-type-3.stderr @@ -46,7 +46,7 @@ LL | ext::m!(); | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error: type `for<'r> fn(&'r ext::Pub) {>::priv_method}` is private +error: type `for<'r> fn(&'r ext::Pub) {ext::Pub::::priv_method}` is private --> $DIR/private-inferred-type-3.rs:16:5 | LL | ext::m!(); diff --git a/src/test/ui/privacy/private-inferred-type.rs b/src/test/ui/privacy/private-inferred-type.rs index d98cf5991efeb..dab440b2d9910 100644 --- a/src/test/ui/privacy/private-inferred-type.rs +++ b/src/test/ui/privacy/private-inferred-type.rs @@ -47,7 +47,7 @@ mod m { PubTupleStruct; //~^ ERROR type `fn(u8) -> m::PubTupleStruct {m::PubTupleStruct}` is private Pub(0u8).priv_method(); - //~^ ERROR type `for<'r> fn(&'r m::Pub) {>::priv_method}` is private + //~^ ERROR type `for<'r> fn(&'r m::Pub) {m::Pub::::priv_method}` is private } trait Trait {} @@ -65,9 +65,9 @@ mod m { pub fn leak_anon2() -> impl TraitWithTyParam { 0 } pub fn leak_anon3() -> impl TraitWithAssocTy { 0 } - pub fn leak_dyn1() -> Box { Box::new(0) } - pub fn leak_dyn2() -> Box> { Box::new(0) } - pub fn leak_dyn3() -> Box> { Box::new(0) } + pub fn leak_dyn1() -> Box { Box::new(0) } + pub fn leak_dyn2() -> Box> { Box::new(0) } + pub fn leak_dyn3() -> Box> { Box::new(0) } } mod adjust { diff --git a/src/test/ui/privacy/private-inferred-type.stderr b/src/test/ui/privacy/private-inferred-type.stderr index 80a475f7dceea..4d40b6b7cab32 100644 --- a/src/test/ui/privacy/private-inferred-type.stderr +++ b/src/test/ui/privacy/private-inferred-type.stderr @@ -1,97 +1,115 @@ +error[E0446]: private type `m::Priv` in public interface + --> $DIR/private-inferred-type.rs:61:36 + | +LL | struct Priv; + | - `m::Priv` declared as private +... +LL | impl TraitWithAssocTy for u8 { type AssocTy = Priv; } + | ^^^^^^^^^^^^^^^^^^^^ can't leak private type + +error[E0446]: private type `adjust::S2` in public interface + --> $DIR/private-inferred-type.rs:83:9 + | +LL | struct S2; + | - `adjust::S2` declared as private +... +LL | type Target = S2Alias; + | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:97:9 | -LL | let _: m::Alias; //~ ERROR type `m::Priv` is private +LL | let _: m::Alias; | ^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:97:12 | -LL | let _: m::Alias; //~ ERROR type `m::Priv` is private +LL | let _: m::Alias; | ^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:99:13 | -LL | let _: ::AssocTy; //~ ERROR type `m::Priv` is private +LL | let _: ::AssocTy; | ^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:100:5 | -LL | m::Alias {}; //~ ERROR type `m::Priv` is private +LL | m::Alias {}; | ^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:101:5 | -LL | m::Pub { 0: m::Alias {} }; //~ ERROR type `m::Priv` is private +LL | m::Pub { 0: m::Alias {} }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:103:5 | -LL | m::Pub::static_method; //~ ERROR type `m::Priv` is private +LL | m::Pub::static_method; | ^^^^^^^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:104:5 | -LL | m::Pub::INHERENT_ASSOC_CONST; //~ ERROR type `m::Priv` is private +LL | m::Pub::INHERENT_ASSOC_CONST; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:105:5 | -LL | m::Pub(0u8).method_with_substs::(); //~ ERROR type `m::Priv` is private +LL | m::Pub(0u8).method_with_substs::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:106:17 | -LL | m::Pub(0u8).method_with_priv_params(loop{}); //~ ERROR type `m::Priv` is private +LL | m::Pub(0u8).method_with_priv_params(loop{}); | ^^^^^^^^^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:107:5 | -LL | ::TRAIT_ASSOC_CONST; //~ ERROR type `m::Priv` is private +LL | ::TRAIT_ASSOC_CONST; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:108:6 | -LL | >::INHERENT_ASSOC_CONST; //~ ERROR type `m::Priv` is private +LL | >::INHERENT_ASSOC_CONST; | ^^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:109:5 | -LL | >::INHERENT_ASSOC_CONST_GENERIC_SELF; //~ ERROR type `m::Priv` is private +LL | >::INHERENT_ASSOC_CONST_GENERIC_SELF; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:110:5 | -LL | >::static_method_generic_self; //~ ERROR type `m::Priv` is private +LL | >::static_method_generic_self; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:112:5 | -LL | u8::pub_method; //~ ERROR type `m::Priv` is private +LL | u8::pub_method; | ^^^^^^^^^^^^^^ error: type `adjust::S2` is private --> $DIR/private-inferred-type.rs:114:5 | -LL | adjust::S1.method_s3(); //~ ERROR type `adjust::S2` is private +LL | adjust::S1.method_s3(); | ^^^^^^^^^^ error: type `fn() {m::priv_fn}` is private --> $DIR/private-inferred-type.rs:39:9 | -LL | priv_fn; //~ ERROR type `fn() {m::priv_fn}` is private +LL | priv_fn; | ^^^^^^^ ... LL | m::m!(); @@ -100,7 +118,7 @@ LL | m::m!(); error: type `m::PrivEnum` is private --> $DIR/private-inferred-type.rs:41:9 | -LL | PrivEnum::Variant; //~ ERROR type `m::PrivEnum` is private +LL | PrivEnum::Variant; | ^^^^^^^^^^^^^^^^^ ... LL | m::m!(); @@ -109,7 +127,7 @@ LL | m::m!(); error: type `fn() {::method}` is private --> $DIR/private-inferred-type.rs:43:9 | -LL | ::method; //~ ERROR type `fn() {::method}` is private +LL | ::method; | ^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | m::m!(); @@ -133,7 +151,7 @@ LL | PubTupleStruct; LL | m::m!(); | -------- in this macro invocation -error: type `for<'r> fn(&'r m::Pub) {>::priv_method}` is private +error: type `for<'r> fn(&'r m::Pub) {m::Pub::::priv_method}` is private --> $DIR/private-inferred-type.rs:49:18 | LL | Pub(0u8).priv_method(); @@ -145,81 +163,63 @@ LL | m::m!(); error: trait `m::Trait` is private --> $DIR/private-inferred-type.rs:118:5 | -LL | m::leak_anon1(); //~ ERROR trait `m::Trait` is private +LL | m::leak_anon1(); | ^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:119:5 | -LL | m::leak_anon2(); //~ ERROR type `m::Priv` is private +LL | m::leak_anon2(); | ^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:120:5 | -LL | m::leak_anon3(); //~ ERROR type `m::Priv` is private +LL | m::leak_anon3(); | ^^^^^^^^^^^^^^^ error: trait `m::Trait` is private --> $DIR/private-inferred-type.rs:122:5 | -LL | m::leak_dyn1(); //~ ERROR trait `m::Trait` is private +LL | m::leak_dyn1(); | ^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:123:5 | -LL | m::leak_dyn2(); //~ ERROR type `m::Priv` is private +LL | m::leak_dyn2(); | ^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:124:5 | -LL | m::leak_dyn3(); //~ ERROR type `m::Priv` is private +LL | m::leak_dyn3(); | ^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:127:13 | -LL | let a = m::Alias {}; //~ ERROR type `m::Priv` is private +LL | let a = m::Alias {}; | ^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:128:17 | -LL | let mut b = a; //~ ERROR type `m::Priv` is private +LL | let mut b = a; | ^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:129:9 | -LL | b = a; //~ ERROR type `m::Priv` is private +LL | b = a; | ^ error: type `m::Priv` is private --> $DIR/private-inferred-type.rs:130:11 | -LL | match a { //~ ERROR type `m::Priv` is private +LL | match a { | ^ -error[E0446]: private type `m::Priv` in public interface - --> $DIR/private-inferred-type.rs:61:36 - | -LL | struct Priv; - | - `m::Priv` declared as private -... -LL | impl TraitWithAssocTy for u8 { type AssocTy = Priv; } - | ^^^^^^^^^^^^^^^^^^^^ can't leak private type - -error[E0446]: private type `adjust::S2` in public interface - --> $DIR/private-inferred-type.rs:83:9 - | -LL | struct S2; - | - `adjust::S2` declared as private -... -LL | type Target = S2Alias; //~ ERROR private type `adjust::S2` in public interface - | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type - error: aborting due to 33 previous errors For more information about this error, try `rustc --explain E0446`. diff --git a/src/test/ui/privacy/private-item-simple.stderr b/src/test/ui/privacy/private-item-simple.stderr index 2ac694f35d464..0d5435e1c504b 100644 --- a/src/test/ui/privacy/private-item-simple.stderr +++ b/src/test/ui/privacy/private-item-simple.stderr @@ -1,7 +1,7 @@ error[E0603]: function `f` is private --> $DIR/private-item-simple.rs:6:8 | -LL | a::f(); //~ ERROR function `f` is private +LL | a::f(); | ^ error: aborting due to previous error diff --git a/src/test/ui/privacy/private-method-cross-crate.stderr b/src/test/ui/privacy/private-method-cross-crate.stderr index bd28f2e5a8ba8..10e0bfe5b1367 100644 --- a/src/test/ui/privacy/private-method-cross-crate.stderr +++ b/src/test/ui/privacy/private-method-cross-crate.stderr @@ -1,7 +1,7 @@ error[E0624]: method `nap` is private --> $DIR/private-method-cross-crate.rs:7:8 | -LL | nyan.nap(); //~ ERROR method `nap` is private +LL | nyan.nap(); | ^^^ error: aborting due to previous error diff --git a/src/test/ui/privacy/private-method-inherited.stderr b/src/test/ui/privacy/private-method-inherited.stderr index 30c1e99ceddb4..d2ba591ef0cc1 100644 --- a/src/test/ui/privacy/private-method-inherited.stderr +++ b/src/test/ui/privacy/private-method-inherited.stderr @@ -1,7 +1,7 @@ error[E0624]: method `f` is private --> $DIR/private-method-inherited.rs:13:7 | -LL | x.f(); //~ ERROR method `f` is private +LL | x.f(); | ^ error: aborting due to previous error diff --git a/src/test/ui/privacy/private-method.stderr b/src/test/ui/privacy/private-method.stderr index 64820e5ea8c70..61fc122e318ee 100644 --- a/src/test/ui/privacy/private-method.stderr +++ b/src/test/ui/privacy/private-method.stderr @@ -1,7 +1,7 @@ error[E0624]: method `nap` is private --> $DIR/private-method.rs:22:8 | -LL | nyan.nap(); //~ ERROR method `nap` is private +LL | nyan.nap(); | ^^^ error: aborting due to previous error diff --git a/src/test/ui/privacy/private-struct-field-ctor.stderr b/src/test/ui/privacy/private-struct-field-ctor.stderr index 943abeed114c8..97585c1d8805b 100644 --- a/src/test/ui/privacy/private-struct-field-ctor.stderr +++ b/src/test/ui/privacy/private-struct-field-ctor.stderr @@ -1,7 +1,7 @@ error[E0451]: field `x` of struct `a::Foo` is private --> $DIR/private-struct-field-ctor.rs:8:22 | -LL | let s = a::Foo { x: 1 }; //~ ERROR field `x` of struct `a::Foo` is private +LL | let s = a::Foo { x: 1 }; | ^^^^ field `x` is private error: aborting due to previous error diff --git a/src/test/ui/privacy/private-struct-field-pattern.stderr b/src/test/ui/privacy/private-struct-field-pattern.stderr index 05e6d3d724313..69bd58aacfc54 100644 --- a/src/test/ui/privacy/private-struct-field-pattern.stderr +++ b/src/test/ui/privacy/private-struct-field-pattern.stderr @@ -1,7 +1,7 @@ error[E0451]: field `x` of struct `a::Foo` is private --> $DIR/private-struct-field-pattern.rs:15:15 | -LL | Foo { x: _ } => {} //~ ERROR field `x` of struct `a::Foo` is private +LL | Foo { x: _ } => {} | ^^^^ field `x` is private error: aborting due to previous error diff --git a/src/test/ui/privacy/private-struct-field.stderr b/src/test/ui/privacy/private-struct-field.stderr index 7cb6d6ab4d7e8..da53c73b4311c 100644 --- a/src/test/ui/privacy/private-struct-field.stderr +++ b/src/test/ui/privacy/private-struct-field.stderr @@ -1,7 +1,7 @@ error[E0616]: field `meows` of struct `cat::Cat` is private --> $DIR/private-struct-field.rs:13:16 | -LL | assert_eq!(nyan.meows, 52); //~ ERROR field `meows` of struct `cat::Cat` is private +LL | assert_eq!(nyan.meows, 52); | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/privacy/private-type-in-interface.stderr b/src/test/ui/privacy/private-type-in-interface.stderr index b436f20fce981..aa4bfb7fc9a19 100644 --- a/src/test/ui/privacy/private-type-in-interface.stderr +++ b/src/test/ui/privacy/private-type-in-interface.stderr @@ -1,55 +1,55 @@ error: type `m::Priv` is private --> $DIR/private-type-in-interface.rs:15:9 | -LL | fn f(_: m::Alias) {} //~ ERROR type `m::Priv` is private +LL | fn f(_: m::Alias) {} | ^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-type-in-interface.rs:15:6 | -LL | fn f(_: m::Alias) {} //~ ERROR type `m::Priv` is private +LL | fn f(_: m::Alias) {} | ^ error: type `ext::Priv` is private --> $DIR/private-type-in-interface.rs:17:13 | -LL | fn f_ext(_: ext::Alias) {} //~ ERROR type `ext::Priv` is private +LL | fn f_ext(_: ext::Alias) {} | ^^^^^^^^^^ error: type `ext::Priv` is private --> $DIR/private-type-in-interface.rs:17:10 | -LL | fn f_ext(_: ext::Alias) {} //~ ERROR type `ext::Priv` is private +LL | fn f_ext(_: ext::Alias) {} | ^ error: type `m::Priv` is private --> $DIR/private-type-in-interface.rs:21:6 | -LL | impl m::Alias {} //~ ERROR type `m::Priv` is private +LL | impl m::Alias {} | ^^^^^^^^ error: type `ext::Priv` is private --> $DIR/private-type-in-interface.rs:22:14 | -LL | impl Tr1 for ext::Alias {} //~ ERROR type `ext::Priv` is private +LL | impl Tr1 for ext::Alias {} | ^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-type-in-interface.rs:23:10 | -LL | type A = ::X; //~ ERROR type `m::Priv` is private +LL | type A = ::X; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `m::Priv` is private --> $DIR/private-type-in-interface.rs:27:11 | -LL | fn g() -> impl Tr2 { 0 } //~ ERROR type `m::Priv` is private +LL | fn g() -> impl Tr2 { 0 } | ^^^^^^^^^^^^^^^^^^ error: type `ext::Priv` is private --> $DIR/private-type-in-interface.rs:28:15 | -LL | fn g_ext() -> impl Tr2 { 0 } //~ ERROR type `ext::Priv` is private +LL | fn g_ext() -> impl Tr2 { 0 } | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 9 previous errors diff --git a/src/test/ui/privacy/private-variant-reexport.stderr b/src/test/ui/privacy/private-variant-reexport.stderr index 99f4a41272cd0..8e4c345286247 100644 --- a/src/test/ui/privacy/private-variant-reexport.stderr +++ b/src/test/ui/privacy/private-variant-reexport.stderr @@ -1,7 +1,7 @@ error: variant `V` is private and cannot be re-exported --> $DIR/private-variant-reexport.rs:2:13 | -LL | pub use ::E::V; //~ ERROR variant `V` is private and cannot be re-exported +LL | pub use ::E::V; | ^^^^^^ ... LL | enum E { V } @@ -10,19 +10,19 @@ LL | enum E { V } error: variant `V` is private and cannot be re-exported --> $DIR/private-variant-reexport.rs:6:19 | -LL | pub use ::E::{V}; //~ ERROR variant `V` is private and cannot be re-exported +LL | pub use ::E::{V}; | ^ error: variant `V` is private and cannot be re-exported --> $DIR/private-variant-reexport.rs:10:22 | -LL | pub use ::E::V::{self}; //~ ERROR variant `V` is private and cannot be re-exported +LL | pub use ::E::V::{self}; | ^^^^ error: enum is private and its variants cannot be re-exported --> $DIR/private-variant-reexport.rs:14:13 | -LL | pub use ::E::*; //~ ERROR enum is private and its variants cannot be re-exported +LL | pub use ::E::*; | ^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs index 9ebc96017fe9c..784615354a95c 100644 --- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs +++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs @@ -1,6 +1,6 @@ // aux-build:priv_dep.rs // aux-build:pub_dep.rs - // compile-flags: --extern-private priv_dep + // extern-private:priv_dep #![deny(exported_private_dependencies)] // This crate is a private dependency diff --git a/src/test/ui/privacy/restricted/private-in-public.stderr b/src/test/ui/privacy/restricted/private-in-public.stderr index 2fb7059e0d40d..87c96d31f0929 100644 --- a/src/test/ui/privacy/restricted/private-in-public.stderr +++ b/src/test/ui/privacy/restricted/private-in-public.stderr @@ -4,7 +4,7 @@ error[E0446]: private type `foo::Priv` in public interface LL | struct Priv; | - `foo::Priv` declared as private ... -LL | pub(crate) fn g(_: Priv) {} //~ ERROR E0446 +LL | pub(crate) fn g(_: Priv) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `foo::Priv` in public interface @@ -13,7 +13,7 @@ error[E0446]: private type `foo::Priv` in public interface LL | struct Priv; | - `foo::Priv` declared as private ... -LL | crate fn h(_: Priv) {} //~ ERROR E0446 +LL | crate fn h(_: Priv) {} | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error: aborting due to 2 previous errors diff --git a/src/test/ui/privacy/restricted/struct-literal-field.stderr b/src/test/ui/privacy/restricted/struct-literal-field.stderr index 0109cae91a0c8..dd609944a4b3f 100644 --- a/src/test/ui/privacy/restricted/struct-literal-field.stderr +++ b/src/test/ui/privacy/restricted/struct-literal-field.stderr @@ -1,7 +1,7 @@ error[E0451]: field `x` of struct `foo::bar::S` is private --> $DIR/struct-literal-field.rs:18:9 | -LL | S { x: 0 }; //~ ERROR private +LL | S { x: 0 }; | ^^^^ field `x` is private error: aborting due to previous error diff --git a/src/test/ui/privacy/restricted/test.stderr b/src/test/ui/privacy/restricted/test.stderr index 7539b0e1af4c9..fa78ae759c737 100644 --- a/src/test/ui/privacy/restricted/test.stderr +++ b/src/test/ui/privacy/restricted/test.stderr @@ -1,82 +1,82 @@ error[E0433]: failed to resolve: maybe a missing `extern crate bad;`? --> $DIR/test.rs:50:12 | -LL | pub(in bad::path) mod m1 {} //~ ERROR failed to resolve: maybe a missing `extern crate bad;`? +LL | pub(in bad::path) mod m1 {} | ^^^ maybe a missing `extern crate bad;`? error: visibilities can only be restricted to ancestor modules --> $DIR/test.rs:51:12 | -LL | pub(in foo) mod m2 {} //~ ERROR visibilities can only be restricted to ancestor modules +LL | pub(in foo) mod m2 {} | ^^^ error[E0364]: `f` is private, and cannot be re-exported --> $DIR/test.rs:21:24 | -LL | pub(super) use foo::bar::f as g; //~ ERROR cannot be re-exported +LL | pub(super) use foo::bar::f as g; | ^^^^^^^^^^^^^^^^ | note: consider marking `f` as `pub` in the imported module --> $DIR/test.rs:21:24 | -LL | pub(super) use foo::bar::f as g; //~ ERROR cannot be re-exported +LL | pub(super) use foo::bar::f as g; | ^^^^^^^^^^^^^^^^ error[E0603]: struct `Crate` is private --> $DIR/test.rs:38:25 | -LL | use pub_restricted::Crate; //~ ERROR private +LL | use pub_restricted::Crate; | ^^^^^ error[E0603]: function `f` is private --> $DIR/test.rs:30:19 | -LL | use foo::bar::f; //~ ERROR private +LL | use foo::bar::f; | ^ error[E0616]: field `x` of struct `foo::bar::S` is private --> $DIR/test.rs:31:5 | -LL | S::default().x; //~ ERROR private +LL | S::default().x; | ^^^^^^^^^^^^^^ error[E0624]: method `f` is private --> $DIR/test.rs:32:18 | -LL | S::default().f(); //~ ERROR private +LL | S::default().f(); | ^ error[E0624]: method `g` is private --> $DIR/test.rs:33:5 | -LL | S::g(); //~ ERROR private +LL | S::g(); | ^^^^ error[E0616]: field `y` of struct `pub_restricted::Universe` is private --> $DIR/test.rs:42:13 | -LL | let _ = u.y; //~ ERROR private +LL | let _ = u.y; | ^^^ error[E0616]: field `z` of struct `pub_restricted::Universe` is private --> $DIR/test.rs:43:13 | -LL | let _ = u.z; //~ ERROR private +LL | let _ = u.z; | ^^^ error[E0624]: method `g` is private --> $DIR/test.rs:45:7 | -LL | u.g(); //~ ERROR private +LL | u.g(); | ^ error[E0624]: method `h` is private --> $DIR/test.rs:46:7 | -LL | u.h(); //~ ERROR private +LL | u.h(); | ^ error: aborting due to 12 previous errors -Some errors occurred: E0364, E0433, E0603, E0616, E0624. +Some errors have detailed explanations: E0364, E0433, E0603, E0616, E0624. For more information about an error, try `rustc --explain E0364`. diff --git a/src/test/ui/privacy/union-field-privacy-1.stderr b/src/test/ui/privacy/union-field-privacy-1.stderr index d31360dbe6511..96a1d7ed5090a 100644 --- a/src/test/ui/privacy/union-field-privacy-1.stderr +++ b/src/test/ui/privacy/union-field-privacy-1.stderr @@ -1,13 +1,13 @@ error[E0451]: field `c` of union `m::U` is private --> $DIR/union-field-privacy-1.rs:12:20 | -LL | let u = m::U { c: 0 }; //~ ERROR field `c` of union `m::U` is private +LL | let u = m::U { c: 0 }; | ^^^^ field `c` is private error[E0451]: field `c` of union `m::U` is private --> $DIR/union-field-privacy-1.rs:16:16 | -LL | let m::U { c } = u; //~ ERROR field `c` of union `m::U` is private +LL | let m::U { c } = u; | ^ field `c` is private error: aborting due to 2 previous errors diff --git a/src/test/ui/privacy/union-field-privacy-2.stderr b/src/test/ui/privacy/union-field-privacy-2.stderr index bd2c834c966d1..df054b8cff8a6 100644 --- a/src/test/ui/privacy/union-field-privacy-2.stderr +++ b/src/test/ui/privacy/union-field-privacy-2.stderr @@ -1,7 +1,7 @@ error[E0616]: field `c` of struct `m::U` is private --> $DIR/union-field-privacy-2.rs:14:13 | -LL | let c = u.c; //~ ERROR field `c` of struct `m::U` is private +LL | let c = u.c; | ^^^ error: aborting due to previous error diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs-test.stderr b/src/test/ui/proc-macro/ambiguous-builtin-attrs-test.stderr index db07055b6a109..316eb636ba825 100644 --- a/src/test/ui/proc-macro/ambiguous-builtin-attrs-test.stderr +++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs-test.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `NonExistent` in this scope --> $DIR/ambiguous-builtin-attrs-test.rs:19:5 | -LL | NonExistent; //~ ERROR cannot find value `NonExistent` in this scope +LL | NonExistent; | ^^^^^^^^^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr index 79dc922b9db2c..23310f6c6f528 100644 --- a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr +++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr @@ -1,13 +1,13 @@ error[E0425]: cannot find value `NonExistent` in this scope --> $DIR/ambiguous-builtin-attrs.rs:30:5 | -LL | NonExistent; //~ ERROR cannot find value `NonExistent` in this scope +LL | NonExistent; | ^^^^^^^^^^^ not found in this scope error[E0659]: `repr` is ambiguous (built-in attribute vs any other name) --> $DIR/ambiguous-builtin-attrs.rs:9:3 | -LL | #[repr(C)] //~ ERROR `repr` is ambiguous +LL | #[repr(C)] | ^^^^ ambiguous name | = note: `repr` could refer to a built-in attribute @@ -21,7 +21,7 @@ LL | use builtin_attrs::*; error[E0659]: `repr` is ambiguous (built-in attribute vs any other name) --> $DIR/ambiguous-builtin-attrs.rs:11:19 | -LL | #[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous +LL | #[cfg_attr(all(), repr(C))] | ^^^^ ambiguous name | = note: `repr` could refer to a built-in attribute @@ -35,7 +35,7 @@ LL | use builtin_attrs::*; error[E0659]: `repr` is ambiguous (built-in attribute vs any other name) --> $DIR/ambiguous-builtin-attrs.rs:20:34 | -LL | fn non_macro_expanded_location<#[repr(C)] T>() { //~ ERROR `repr` is ambiguous +LL | fn non_macro_expanded_location<#[repr(C)] T>() { | ^^^^ ambiguous name | = note: `repr` could refer to a built-in attribute @@ -49,7 +49,7 @@ LL | use builtin_attrs::*; error[E0659]: `repr` is ambiguous (built-in attribute vs any other name) --> $DIR/ambiguous-builtin-attrs.rs:22:11 | -LL | #[repr(C)] //~ ERROR `repr` is ambiguous +LL | #[repr(C)] | ^^^^ ambiguous name | = note: `repr` could refer to a built-in attribute @@ -63,7 +63,7 @@ LL | use builtin_attrs::*; error[E0659]: `feature` is ambiguous (built-in attribute vs any other name) --> $DIR/ambiguous-builtin-attrs.rs:3:4 | -LL | #![feature(decl_macro)] //~ ERROR `feature` is ambiguous +LL | #![feature(decl_macro)] | ^^^^^^^ ambiguous name | = note: `feature` could refer to a built-in attribute @@ -76,5 +76,5 @@ LL | use builtin_attrs::*; error: aborting due to 6 previous errors -Some errors occurred: E0425, E0659. +Some errors have detailed explanations: E0425, E0659. For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/proc-macro/attr-invalid-exprs.rs b/src/test/ui/proc-macro/attr-invalid-exprs.rs index c609cae90240c..fab98f0ce5ebe 100644 --- a/src/test/ui/proc-macro/attr-invalid-exprs.rs +++ b/src/test/ui/proc-macro/attr-invalid-exprs.rs @@ -9,7 +9,7 @@ use attr_stmt_expr::{duplicate, no_output}; fn main() { let _ = #[no_output] "Hello, world!"; - //~^ ERROR expected expression, found `` + //~^ ERROR expected expression, found end of macro arguments let _ = #[duplicate] "Hello, world!"; //~^ ERROR macro expansion ignores token `,` and any following diff --git a/src/test/ui/proc-macro/attr-invalid-exprs.stderr b/src/test/ui/proc-macro/attr-invalid-exprs.stderr index 5d2fb59ff1f66..49fe0bd0fcfe2 100644 --- a/src/test/ui/proc-macro/attr-invalid-exprs.stderr +++ b/src/test/ui/proc-macro/attr-invalid-exprs.stderr @@ -1,4 +1,4 @@ -error: expected expression, found `` +error: expected expression, found end of macro arguments --> $DIR/attr-invalid-exprs.rs:11:13 | LL | let _ = #[no_output] "Hello, world!"; diff --git a/src/test/ui/proc-macro/attr-stmt-expr.stderr b/src/test/ui/proc-macro/attr-stmt-expr.stderr index 34ee012ab3107..3928a973eab57 100644 --- a/src/test/ui/proc-macro/attr-stmt-expr.stderr +++ b/src/test/ui/proc-macro/attr-stmt-expr.stderr @@ -1,17 +1,19 @@ -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/attr-stmt-expr.rs:10:5 | LL | #[expect_print_expr] | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/attr-stmt-expr.rs:23:5 | LL | #[expect_expr] | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/proc-macro/attribute-order-restricted.rs b/src/test/ui/proc-macro/attribute-order-restricted.rs index 7b1eecd155865..a3d4d23450ca6 100644 --- a/src/test/ui/proc-macro/attribute-order-restricted.rs +++ b/src/test/ui/proc-macro/attribute-order-restricted.rs @@ -1,14 +1,14 @@ -// aux-build:attr_proc_macro.rs +// aux-build:test-macros.rs -extern crate attr_proc_macro; -use attr_proc_macro::*; +#[macro_use] +extern crate test_macros; -#[attr_proc_macro] // OK +#[identity_attr] // OK #[derive(Clone)] struct Before; #[derive(Clone)] -#[attr_proc_macro] //~ ERROR macro attributes must be placed before `#[derive]` +#[identity_attr] //~ ERROR macro attributes must be placed before `#[derive]` struct After; fn main() {} diff --git a/src/test/ui/proc-macro/attribute-order-restricted.stderr b/src/test/ui/proc-macro/attribute-order-restricted.stderr index a4f165cd1b52c..9ca8a443e40fb 100644 --- a/src/test/ui/proc-macro/attribute-order-restricted.stderr +++ b/src/test/ui/proc-macro/attribute-order-restricted.stderr @@ -1,8 +1,8 @@ error: macro attributes must be placed before `#[derive]` --> $DIR/attribute-order-restricted.rs:11:1 | -LL | #[attr_proc_macro] //~ ERROR macro attributes must be placed before `#[derive]` - | ^^^^^^^^^^^^^^^^^^ +LL | #[identity_attr] + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/proc-macro/attribute-spans-preserved.stderr b/src/test/ui/proc-macro/attribute-spans-preserved.stderr index 8371088c4c209..6c571dbdb4769 100644 --- a/src/test/ui/proc-macro/attribute-spans-preserved.stderr +++ b/src/test/ui/proc-macro/attribute-spans-preserved.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/attribute-spans-preserved.rs:7:23 | -LL | #[ foo ( let y: u32 = "z"; ) ] //~ ERROR: mismatched types +LL | #[ foo ( let y: u32 = "z"; ) ] | ^^^ expected u32, found reference | = note: expected type `u32` @@ -10,7 +10,7 @@ LL | #[ foo ( let y: u32 = "z"; ) ] //~ ERROR: mismatched types error[E0308]: mismatched types --> $DIR/attribute-spans-preserved.rs:8:23 | -LL | #[ bar { let x: u32 = "y"; } ] //~ ERROR: mismatched types +LL | #[ bar { let x: u32 = "y"; } ] | ^^^ expected u32, found reference | = note: expected type `u32` diff --git a/src/test/ui/proc-macro/attribute-with-error.rs b/src/test/ui/proc-macro/attribute-with-error.rs index 2cced40830a74..aaa6c07dddbbd 100644 --- a/src/test/ui/proc-macro/attribute-with-error.rs +++ b/src/test/ui/proc-macro/attribute-with-error.rs @@ -1,12 +1,11 @@ -// aux-build:attribute-with-error.rs +// aux-build:test-macros.rs #![feature(custom_inner_attributes)] -extern crate attribute_with_error; +#[macro_use] +extern crate test_macros; -use attribute_with_error::foo; - -#[foo] +#[recollect_attr] fn test1() { let a: i32 = "foo"; //~^ ERROR: mismatched types @@ -15,13 +14,13 @@ fn test1() { } fn test2() { - #![foo] + #![recollect_attr] // FIXME: should have a type error here and assert it works but it doesn't } trait A { - // FIXME: should have a #[foo] attribute here and assert that it works + // FIXME: should have a #[recollect_attr] attribute here and assert that it works fn foo(&self) { let a: i32 = "foo"; //~^ ERROR: mismatched types @@ -31,13 +30,13 @@ trait A { struct B; impl A for B { - #[foo] + #[recollect_attr] fn foo(&self) { let a: i32 = "foo"; //~^ ERROR: mismatched types } } -#[foo] +#[recollect_attr] fn main() { } diff --git a/src/test/ui/proc-macro/attribute-with-error.stderr b/src/test/ui/proc-macro/attribute-with-error.stderr index c5970ab6baaf8..937d47ff08979 100644 --- a/src/test/ui/proc-macro/attribute-with-error.stderr +++ b/src/test/ui/proc-macro/attribute-with-error.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/attribute-with-error.rs:11:18 + --> $DIR/attribute-with-error.rs:10:18 | LL | let a: i32 = "foo"; | ^^^^^ expected i32, found reference @@ -8,7 +8,7 @@ LL | let a: i32 = "foo"; found type `&'static str` error[E0308]: mismatched types - --> $DIR/attribute-with-error.rs:13:18 + --> $DIR/attribute-with-error.rs:12:18 | LL | let b: i32 = "f'oo"; | ^^^^^^ expected i32, found reference @@ -17,7 +17,7 @@ LL | let b: i32 = "f'oo"; found type `&'static str` error[E0308]: mismatched types - --> $DIR/attribute-with-error.rs:26:22 + --> $DIR/attribute-with-error.rs:25:22 | LL | let a: i32 = "foo"; | ^^^^^ expected i32, found reference @@ -26,7 +26,7 @@ LL | let a: i32 = "foo"; found type `&'static str` error[E0308]: mismatched types - --> $DIR/attribute-with-error.rs:36:22 + --> $DIR/attribute-with-error.rs:35:22 | LL | let a: i32 = "foo"; | ^^^^^ expected i32, found reference diff --git a/src/test/ui/proc-macro/attribute.rs b/src/test/ui/proc-macro/attribute.rs index a0b982d75f519..04c88dcef50ac 100644 --- a/src/test/ui/proc-macro/attribute.rs +++ b/src/test/ui/proc-macro/attribute.rs @@ -4,53 +4,71 @@ #![crate_type = "proc-macro"] extern crate proc_macro; +use proc_macro::*; -#[proc_macro_derive] -//~^ ERROR: attribute must be of the form -pub fn foo1(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} - -#[proc_macro_derive = "foo"] -//~^ ERROR: attribute must be of the form -pub fn foo2(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} - -#[proc_macro_derive( - a = "b" -)] -//~^^ ERROR: must only be one word -pub fn foo3(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} - -#[proc_macro_derive(b, c, d)] -//~^ ERROR: attribute must have either one or two arguments -pub fn foo4(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} - -#[proc_macro_derive(d(e))] +#[proc_macro_derive] //~ ERROR malformed `proc_macro_derive` attribute +pub fn foo1(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive = ""] //~ ERROR malformed `proc_macro_derive` attribute +pub fn foo2(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d3, a, b)] +//~^ ERROR attribute must have either one or two arguments +pub fn foo3(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d4, attributes(a), b)] +//~^ ERROR attribute must have either one or two arguments +pub fn foo4(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive("a")] +//~^ ERROR: not a meta item +pub fn foo5(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d6 = "")] //~^ ERROR: must only be one word -pub fn foo5(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} +pub fn foo6(input: TokenStream) -> TokenStream { input } -#[proc_macro_derive(f, attributes(g = "h"))] +#[proc_macro_derive(m::d7)] //~^ ERROR: must only be one word -pub fn foo6(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} +pub fn foo7(input: TokenStream) -> TokenStream { input } -#[proc_macro_derive(i, attributes(j(k)))] +#[proc_macro_derive(d8(a))] //~^ ERROR: must only be one word -pub fn foo7(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} - -#[proc_macro_derive(l, attributes(m), n)] -//~^ ERROR: attribute must have either one or two arguments -pub fn foo8(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} +pub fn foo8(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(self)] +//~^ ERROR: `self` cannot be a name of derive macro +pub fn foo9(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(PartialEq)] +//~^ ERROR: cannot override a built-in derive macro +pub fn foo10(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d11, a)] +//~^ ERROR: second argument must be `attributes` +//~| ERROR: attribute must be of form: `attributes(foo, bar)` +pub fn foo11(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d12, attributes)] +//~^ ERROR: attribute must be of form: `attributes(foo, bar)` +pub fn foo12(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d13, attributes("a"))] +//~^ ERROR: not a meta item +pub fn foo13(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d14, attributes(a = ""))] +//~^ ERROR: must only be one word +pub fn foo14(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d15, attributes(m::a))] +//~^ ERROR: must only be one word +pub fn foo15(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d16, attributes(a(b)))] +//~^ ERROR: must only be one word +pub fn foo16(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d17, attributes(self))] +//~^ ERROR: `self` cannot be a name of derive helper attribute +pub fn foo17(input: TokenStream) -> TokenStream { input } diff --git a/src/test/ui/proc-macro/attribute.stderr b/src/test/ui/proc-macro/attribute.stderr index 231eb1f106898..e632875cb16e5 100644 --- a/src/test/ui/proc-macro/attribute.stderr +++ b/src/test/ui/proc-macro/attribute.stderr @@ -1,50 +1,110 @@ -error: must only be one word - --> $DIR/attribute.rs:21:5 +error: attribute must have either one or two arguments + --> $DIR/attribute.rs:15:1 | -LL | a = "b" - | ^^^^^^^ +LL | #[proc_macro_derive(d3, a, b)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: attribute must have either one or two arguments - --> $DIR/attribute.rs:28:1 + --> $DIR/attribute.rs:19:1 + | +LL | #[proc_macro_derive(d4, attributes(a), b)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: not a meta item + --> $DIR/attribute.rs:23:21 + | +LL | #[proc_macro_derive("a")] + | ^^^ + +error: must only be one word + --> $DIR/attribute.rs:27:21 | -LL | #[proc_macro_derive(b, c, d)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_derive(d6 = "")] + | ^^^^^^^ error: must only be one word - --> $DIR/attribute.rs:34:21 + --> $DIR/attribute.rs:31:21 | -LL | #[proc_macro_derive(d(e))] +LL | #[proc_macro_derive(m::d7)] + | ^^^^^ + +error: must only be one word + --> $DIR/attribute.rs:35:21 + | +LL | #[proc_macro_derive(d8(a))] + | ^^^^^ + +error: `self` cannot be a name of derive macro + --> $DIR/attribute.rs:39:21 + | +LL | #[proc_macro_derive(self)] | ^^^^ +error: cannot override a built-in derive macro + --> $DIR/attribute.rs:43:21 + | +LL | #[proc_macro_derive(PartialEq)] + | ^^^^^^^^^ + +error: second argument must be `attributes` + --> $DIR/attribute.rs:47:26 + | +LL | #[proc_macro_derive(d11, a)] + | ^ + +error: attribute must be of form: `attributes(foo, bar)` + --> $DIR/attribute.rs:47:26 + | +LL | #[proc_macro_derive(d11, a)] + | ^ + +error: attribute must be of form: `attributes(foo, bar)` + --> $DIR/attribute.rs:52:26 + | +LL | #[proc_macro_derive(d12, attributes)] + | ^^^^^^^^^^ + +error: not a meta item + --> $DIR/attribute.rs:56:37 + | +LL | #[proc_macro_derive(d13, attributes("a"))] + | ^^^ + error: must only be one word - --> $DIR/attribute.rs:40:35 + --> $DIR/attribute.rs:60:37 | -LL | #[proc_macro_derive(f, attributes(g = "h"))] - | ^^^^^^^ +LL | #[proc_macro_derive(d14, attributes(a = ""))] + | ^^^^^^ error: must only be one word - --> $DIR/attribute.rs:46:35 + --> $DIR/attribute.rs:64:37 | -LL | #[proc_macro_derive(i, attributes(j(k)))] - | ^^^^ +LL | #[proc_macro_derive(d15, attributes(m::a))] + | ^^^^ -error: attribute must have either one or two arguments - --> $DIR/attribute.rs:52:1 +error: must only be one word + --> $DIR/attribute.rs:68:37 + | +LL | #[proc_macro_derive(d16, attributes(a(b)))] + | ^^^^ + +error: `self` cannot be a name of derive helper attribute + --> $DIR/attribute.rs:72:37 | -LL | #[proc_macro_derive(l, attributes(m), n)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_derive(d17, attributes(self))] + | ^^^^ -error: attribute must be of the form `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` - --> $DIR/attribute.rs:8:1 +error: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:9:1 | LL | #[proc_macro_derive] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: attribute must be of the form `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` - --> $DIR/attribute.rs:14:1 +error: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:12:1 | -LL | #[proc_macro_derive = "foo"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_derive = ""] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` -error: aborting due to 8 previous errors +error: aborting due to 18 previous errors diff --git a/src/test/ui/proc-macro/attributes-included.stderr b/src/test/ui/proc-macro/attributes-included.stderr index 87b6fb9539fb4..fcd77b2d383da 100644 --- a/src/test/ui/proc-macro/attributes-included.stderr +++ b/src/test/ui/proc-macro/attributes-included.stderr @@ -1,7 +1,7 @@ warning: unused variable: `a` --> $DIR/attributes-included.rs:17:9 | -LL | let a: i32 = "foo"; //~ WARN: unused variable +LL | let a: i32 = "foo"; | ^ help: consider prefixing with an underscore: `_a` | note: lint level defined here diff --git a/src/test/ui/proc-macro/auxiliary/attr_proc_macro.rs b/src/test/ui/proc-macro/auxiliary/attr_proc_macro.rs deleted file mode 100644 index b1f54be6bac4b..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/attr_proc_macro.rs +++ /dev/null @@ -1,13 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::TokenStream; - -#[proc_macro_attribute] -pub fn attr_proc_macro(_: TokenStream, input: TokenStream) -> TokenStream { - input -} diff --git a/src/test/ui/proc-macro/auxiliary/attribute-with-error.rs b/src/test/ui/proc-macro/auxiliary/attribute-with-error.rs deleted file mode 100644 index c073be0031019..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/attribute-with-error.rs +++ /dev/null @@ -1,13 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::TokenStream; - -#[proc_macro_attribute] -pub fn foo(_attr: TokenStream, input: TokenStream) -> TokenStream { - input.into_iter().collect() -} diff --git a/src/test/ui/proc-macro/auxiliary/bang_proc_macro.rs b/src/test/ui/proc-macro/auxiliary/bang_proc_macro.rs deleted file mode 100644 index 16f3b7640290d..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/bang_proc_macro.rs +++ /dev/null @@ -1,13 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::TokenStream; - -#[proc_macro] -pub fn bang_proc_macro(input: TokenStream) -> TokenStream { - input -} diff --git a/src/test/ui/proc-macro/auxiliary/derive-a-b.rs b/src/test/ui/proc-macro/auxiliary/derive-a-b.rs deleted file mode 100644 index 64d4e0f7b7ae5..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/derive-a-b.rs +++ /dev/null @@ -1,17 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; -use proc_macro::TokenStream; - -#[proc_macro_derive(A)] -pub fn derive_a(_: TokenStream) -> TokenStream { - "".parse().unwrap() -} - -#[proc_macro_derive(B)] -pub fn derive_b(_: TokenStream) -> TokenStream { - "".parse().unwrap() -} diff --git a/src/test/ui/proc-macro/auxiliary/derive-a.rs b/src/test/ui/proc-macro/auxiliary/derive-a.rs deleted file mode 100644 index c9d94aba9f756..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/derive-a.rs +++ /dev/null @@ -1,13 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::TokenStream; - -#[proc_macro_derive(A)] -pub fn derive_a(input: TokenStream) -> TokenStream { - "".parse().unwrap() -} diff --git a/src/test/ui/proc-macro/auxiliary/derive-bad.rs b/src/test/ui/proc-macro/auxiliary/derive-bad.rs index 468410972fb7c..90bb9b1baf2b7 100644 --- a/src/test/ui/proc-macro/auxiliary/derive-bad.rs +++ b/src/test/ui/proc-macro/auxiliary/derive-bad.rs @@ -11,4 +11,3 @@ use proc_macro::TokenStream; pub fn derive_a(_input: TokenStream) -> TokenStream { "struct A { inner }".parse().unwrap() } - diff --git a/src/test/ui/proc-macro/auxiliary/derive-helper-shadowed-2.rs b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowed-2.rs index 9912a89dafb3f..ab532da299224 100644 --- a/src/test/ui/proc-macro/auxiliary/derive-helper-shadowed-2.rs +++ b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowed-2.rs @@ -1,2 +1,2 @@ #[macro_export] -macro_rules! my_attr { () => () } +macro_rules! empty_helper { () => () } diff --git a/src/test/ui/proc-macro/auxiliary/derive-helper-shadowed.rs b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowed.rs deleted file mode 100644 index 5b5243dd60ee3..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/derive-helper-shadowed.rs +++ /dev/null @@ -1,12 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; -use proc_macro::*; - -#[proc_macro_derive(MyTrait, attributes(my_attr))] -pub fn foo(_: TokenStream) -> TokenStream { - TokenStream::new() -} diff --git a/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing.rs b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing.rs deleted file mode 100644 index 6e0bdcba9c50f..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing.rs +++ /dev/null @@ -1,17 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; -use proc_macro::*; - -#[proc_macro_attribute] -pub fn my_attr(_: TokenStream, input: TokenStream) -> TokenStream { - input -} - -#[proc_macro_derive(MyTrait, attributes(my_attr))] -pub fn derive(input: TokenStream) -> TokenStream { - TokenStream::new() -} diff --git a/src/test/ui/proc-macro/auxiliary/derive-panic.rs b/src/test/ui/proc-macro/auxiliary/derive-panic.rs deleted file mode 100644 index e2afa7affa302..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/derive-panic.rs +++ /dev/null @@ -1,13 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::TokenStream; - -#[proc_macro_derive(A)] -pub fn derive_a(_input: TokenStream) -> TokenStream { - panic!("nope!"); -} diff --git a/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs b/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs index 8f15a2b975bf3..d5d393b5a6457 100644 --- a/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs +++ b/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs @@ -3,14 +3,14 @@ pub type S = u8; #[macro_export] macro_rules! external { () => { - dollar_crate::m! { + print_bang! { struct M($crate::S); } - #[dollar_crate::a] + #[print_attr] struct A($crate::S); - #[derive(dollar_crate::d)] + #[derive(Print)] struct D($crate::S); }; } diff --git a/src/test/ui/proc-macro/auxiliary/dollar-crate.rs b/src/test/ui/proc-macro/auxiliary/dollar-crate.rs deleted file mode 100644 index c5347d2e81a6b..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/dollar-crate.rs +++ /dev/null @@ -1,35 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; -use proc_macro::TokenStream; - -#[proc_macro] -pub fn m_empty(input: TokenStream) -> TokenStream { - println!("PROC MACRO INPUT (PRETTY-PRINTED): {}", input); - println!("PROC MACRO INPUT: {:#?}", input); - TokenStream::new() -} - -#[proc_macro] -pub fn m(input: TokenStream) -> TokenStream { - println!("PROC MACRO INPUT (PRETTY-PRINTED): {}", input); - println!("PROC MACRO INPUT: {:#?}", input); - input.into_iter().collect() -} - -#[proc_macro_attribute] -pub fn a(_args: TokenStream, input: TokenStream) -> TokenStream { - println!("ATTRIBUTE INPUT (PRETTY-PRINTED): {}", input); - println!("ATTRIBUTE INPUT: {:#?}", input); - input.into_iter().collect() -} - -#[proc_macro_derive(d)] -pub fn d(input: TokenStream) -> TokenStream { - println!("DERIVE INPUT (PRETTY-PRINTED): {}", input); - println!("DERIVE INPUT: {:#?}", input); - input.into_iter().collect() -} diff --git a/src/test/ui/proc-macro/auxiliary/generate-mod.rs b/src/test/ui/proc-macro/auxiliary/generate-mod.rs index 8b41e8b3b3eb8..e950f7d62d645 100644 --- a/src/test/ui/proc-macro/auxiliary/generate-mod.rs +++ b/src/test/ui/proc-macro/auxiliary/generate-mod.rs @@ -1,6 +1,7 @@ // run-pass // force-host // no-prefer-dynamic +// ignore-pass #![crate_type = "proc-macro"] diff --git a/src/test/ui/proc-macro/auxiliary/issue_38586.rs b/src/test/ui/proc-macro/auxiliary/issue-38586.rs similarity index 100% rename from src/test/ui/proc-macro/auxiliary/issue_38586.rs rename to src/test/ui/proc-macro/auxiliary/issue-38586.rs diff --git a/src/test/ui/proc-macro/auxiliary/issue-41211.rs b/src/test/ui/proc-macro/auxiliary/issue-41211.rs deleted file mode 100644 index db946e7f331ca..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/issue-41211.rs +++ /dev/null @@ -1,12 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; -use proc_macro::TokenStream; - -#[proc_macro_attribute] -pub fn emit_unchanged(_args: TokenStream, input: TokenStream) -> TokenStream { - input -} diff --git a/src/test/ui/proc-macro/auxiliary/issue_50493.rs b/src/test/ui/proc-macro/auxiliary/issue-50493.rs similarity index 100% rename from src/test/ui/proc-macro/auxiliary/issue_50493.rs rename to src/test/ui/proc-macro/auxiliary/issue-50493.rs diff --git a/src/test/ui/proc-macro/auxiliary/issue-53481.rs b/src/test/ui/proc-macro/auxiliary/issue-53481.rs deleted file mode 100644 index d9f290dec7ef9..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/issue-53481.rs +++ /dev/null @@ -1,13 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::*; - -#[proc_macro_derive(MyTrait, attributes(my_attr))] -pub fn foo(_: TokenStream) -> TokenStream { - TokenStream::new() -} diff --git a/src/test/ui/proc-macro/auxiliary/macro-brackets.rs b/src/test/ui/proc-macro/auxiliary/macro-brackets.rs deleted file mode 100644 index f2c62ab1b5ef0..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/macro-brackets.rs +++ /dev/null @@ -1,12 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; -use proc_macro::*; - -#[proc_macro_attribute] -pub fn doit(_: TokenStream, input: TokenStream) -> TokenStream { - input.into_iter().collect() -} diff --git a/src/test/ui/proc-macro/auxiliary/nested-item-spans.rs b/src/test/ui/proc-macro/auxiliary/nested-item-spans.rs deleted file mode 100644 index 8f720b4574dde..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/nested-item-spans.rs +++ /dev/null @@ -1,13 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::*; - -#[proc_macro_attribute] -pub fn foo(_: TokenStream, item: TokenStream) -> TokenStream { - item.into_iter().collect() -} diff --git a/src/test/ui/proc-macro/auxiliary/proc-macro-gates.rs b/src/test/ui/proc-macro/auxiliary/proc-macro-gates.rs deleted file mode 100644 index c7c7167eca0d5..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/proc-macro-gates.rs +++ /dev/null @@ -1,18 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::*; - -#[proc_macro] -pub fn m(a: TokenStream) -> TokenStream { - a -} - -#[proc_macro_attribute] -pub fn a(_a: TokenStream, b: TokenStream) -> TokenStream { - b -} diff --git a/src/test/ui/proc-macro/auxiliary/span-preservation.rs b/src/test/ui/proc-macro/auxiliary/span-preservation.rs deleted file mode 100644 index 33c7968104b72..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/span-preservation.rs +++ /dev/null @@ -1,13 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::TokenStream; - -#[proc_macro_attribute] -pub fn foo(_: TokenStream, input: TokenStream) -> TokenStream { - input.into_iter().collect() -} diff --git a/src/test/ui/proc-macro/auxiliary/test-macros.rs b/src/test/ui/proc-macro/auxiliary/test-macros.rs index 15fe3804f9b4f..27efa44f98032 100644 --- a/src/test/ui/proc-macro/auxiliary/test-macros.rs +++ b/src/test/ui/proc-macro/auxiliary/test-macros.rs @@ -1,26 +1,112 @@ // force-host // no-prefer-dynamic +// Proc macros commonly used by tests. +// `panic`/`print` -> `panic_bang`/`print_bang` to avoid conflicts with standard macros. + #![crate_type = "proc-macro"] extern crate proc_macro; - use proc_macro::TokenStream; +// Macro that return empty token stream. + +#[proc_macro] +pub fn empty(_: TokenStream) -> TokenStream { + TokenStream::new() +} + #[proc_macro_attribute] -pub fn nop_attr(_attr: TokenStream, input: TokenStream) -> TokenStream { - assert!(_attr.to_string().is_empty()); - input +pub fn empty_attr(_: TokenStream, _: TokenStream) -> TokenStream { + TokenStream::new() +} + +#[proc_macro_derive(Empty, attributes(empty_helper))] +pub fn empty_derive(_: TokenStream) -> TokenStream { + TokenStream::new() +} + +// Macro that panics. + +#[proc_macro] +pub fn panic_bang(_: TokenStream) -> TokenStream { + panic!("panic-bang"); } #[proc_macro_attribute] -pub fn no_output(_attr: TokenStream, _input: TokenStream) -> TokenStream { - assert!(_attr.to_string().is_empty()); - assert!(!_input.to_string().is_empty()); - "".parse().unwrap() +pub fn panic_attr(_: TokenStream, _: TokenStream) -> TokenStream { + panic!("panic-attr"); +} + +#[proc_macro_derive(Panic, attributes(panic_helper))] +pub fn panic_derive(_: TokenStream) -> TokenStream { + panic!("panic-derive"); } +// Macros that return the input stream. + #[proc_macro] -pub fn emit_input(input: TokenStream) -> TokenStream { +pub fn identity(input: TokenStream) -> TokenStream { input } + +#[proc_macro_attribute] +pub fn identity_attr(_: TokenStream, input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_derive(Identity, attributes(identity_helper))] +pub fn identity_derive(input: TokenStream) -> TokenStream { + input +} + +// Macros that iterate and re-collect the input stream. + +#[proc_macro] +pub fn recollect(input: TokenStream) -> TokenStream { + input.into_iter().collect() +} + +#[proc_macro_attribute] +pub fn recollect_attr(_: TokenStream, input: TokenStream) -> TokenStream { + input.into_iter().collect() +} + +#[proc_macro_derive(Recollect, attributes(recollect_helper))] +pub fn recollect_derive(input: TokenStream) -> TokenStream { + input.into_iter().collect() +} + +// Macros that print their input in the original and re-collected forms (if they differ). + +fn print_helper(input: TokenStream, kind: &str) -> TokenStream { + let input_display = format!("{}", input); + let input_debug = format!("{:#?}", input); + let recollected = input.into_iter().collect(); + let recollected_display = format!("{}", recollected); + let recollected_debug = format!("{:#?}", recollected); + println!("PRINT-{} INPUT (DISPLAY): {}", kind, input_display); + if recollected_display != input_display { + println!("PRINT-{} RE-COLLECTED (DISPLAY): {}", kind, recollected_display); + } + println!("PRINT-{} INPUT (DEBUG): {}", kind, input_debug); + if recollected_debug != input_debug { + println!("PRINT-{} RE-COLLECTED (DEBUG): {}", kind, recollected_debug); + } + recollected +} + +#[proc_macro] +pub fn print_bang(input: TokenStream) -> TokenStream { + print_helper(input, "BANG") +} + +#[proc_macro_attribute] +pub fn print_attr(_: TokenStream, input: TokenStream) -> TokenStream { + print_helper(input, "ATTR") +} + +#[proc_macro_derive(Print, attributes(print_helper))] +pub fn print_derive(input: TokenStream) -> TokenStream { + print_helper(input, "DERIVE") +} diff --git a/src/test/ui/proc-macro/define-two.stderr b/src/test/ui/proc-macro/define-two.stderr index c74215f415e0e..bf1bd8427c833 100644 --- a/src/test/ui/proc-macro/define-two.stderr +++ b/src/test/ui/proc-macro/define-two.stderr @@ -4,7 +4,7 @@ error[E0428]: the name `A` is defined multiple times LL | #[proc_macro_derive(A)] | - previous definition of the macro `A` here ... -LL | #[proc_macro_derive(A)] //~ ERROR the name `A` is defined multiple times +LL | #[proc_macro_derive(A)] | ^ `A` redefined here | = note: `A` must be defined only once in the macro namespace of this module diff --git a/src/test/ui/proc-macro/derive-helper-shadowed.rs b/src/test/ui/proc-macro/derive-helper-shadowed.rs index 792b54b3b945a..0388e647b58aa 100644 --- a/src/test/ui/proc-macro/derive-helper-shadowed.rs +++ b/src/test/ui/proc-macro/derive-helper-shadowed.rs @@ -1,16 +1,16 @@ // compile-pass -// aux-build:derive-helper-shadowed.rs +// aux-build:test-macros.rs // aux-build:derive-helper-shadowed-2.rs #[macro_use] -extern crate derive_helper_shadowed; -#[macro_use(my_attr)] +extern crate test_macros; +#[macro_use(empty_helper)] extern crate derive_helper_shadowed_2; -macro_rules! my_attr { () => () } +macro_rules! empty_helper { () => () } -#[derive(MyTrait)] -#[my_attr] // OK +#[derive(Empty)] +#[empty_helper] // OK struct S; fn main() {} diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.rs b/src/test/ui/proc-macro/derive-helper-shadowing.rs index f6fe9f9fd8b30..cdc0d6da94695 100644 --- a/src/test/ui/proc-macro/derive-helper-shadowing.rs +++ b/src/test/ui/proc-macro/derive-helper-shadowing.rs @@ -1,23 +1,25 @@ -// aux-build:derive-helper-shadowing.rs +// aux-build:test-macros.rs -extern crate derive_helper_shadowing; -use derive_helper_shadowing::*; +#[macro_use] +extern crate test_macros; -#[my_attr] //~ ERROR `my_attr` is ambiguous -#[derive(MyTrait)] +use test_macros::empty_attr as empty_helper; + +#[empty_helper] //~ ERROR `empty_helper` is ambiguous +#[derive(Empty)] struct S { // FIXME No ambiguity, attributes in non-macro positions are not resolved properly - #[my_attr] + #[empty_helper] field: [u8; { // FIXME No ambiguity, derive helpers are not put into scope for non-attributes - use my_attr; + use empty_helper; // FIXME No ambiguity, derive helpers are not put into scope for inner items - #[my_attr] + #[empty_helper] struct U; mod inner { - #[my_attr] //~ ERROR attribute `my_attr` is currently unknown + #[empty_helper] //~ ERROR attribute `empty_helper` is currently unknown struct V; } diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.stderr b/src/test/ui/proc-macro/derive-helper-shadowing.stderr index 8180c84d3f6eb..ed6d30516562d 100644 --- a/src/test/ui/proc-macro/derive-helper-shadowing.stderr +++ b/src/test/ui/proc-macro/derive-helper-shadowing.stderr @@ -1,30 +1,31 @@ -error[E0658]: The attribute `my_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/derive-helper-shadowing.rs:20:15 +error[E0658]: The attribute `empty_helper` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/derive-helper-shadowing.rs:22:15 | -LL | #[my_attr] //~ ERROR attribute `my_attr` is currently unknown - | ^^^^^^^ +LL | #[empty_helper] + | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0659]: `my_attr` is ambiguous (derive helper attribute vs any other name) - --> $DIR/derive-helper-shadowing.rs:6:3 +error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name) + --> $DIR/derive-helper-shadowing.rs:8:3 | -LL | #[my_attr] //~ ERROR `my_attr` is ambiguous - | ^^^^^^^ ambiguous name +LL | #[empty_helper] + | ^^^^^^^^^^^^ ambiguous name | -note: `my_attr` could refer to the derive helper attribute defined here - --> $DIR/derive-helper-shadowing.rs:7:10 +note: `empty_helper` could refer to the derive helper attribute defined here + --> $DIR/derive-helper-shadowing.rs:9:10 | -LL | #[derive(MyTrait)] - | ^^^^^^^ -note: `my_attr` could also refer to the attribute macro imported here - --> $DIR/derive-helper-shadowing.rs:4:5 +LL | #[derive(Empty)] + | ^^^^^ +note: `empty_helper` could also refer to the attribute macro imported here + --> $DIR/derive-helper-shadowing.rs:6:5 | -LL | use derive_helper_shadowing::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: use `crate::my_attr` to refer to this attribute macro unambiguously +LL | use test_macros::empty_attr as empty_helper; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use `crate::empty_helper` to refer to this attribute macro unambiguously error: aborting due to 2 previous errors -Some errors occurred: E0658, E0659. +Some errors have detailed explanations: E0658, E0659. For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/proc-macro/derive-in-mod.rs b/src/test/ui/proc-macro/derive-in-mod.rs new file mode 100644 index 0000000000000..e6b91324f95d0 --- /dev/null +++ b/src/test/ui/proc-macro/derive-in-mod.rs @@ -0,0 +1,13 @@ +// compile-pass +// aux-build:test-macros.rs + +extern crate test_macros; + +mod inner { + use test_macros::Empty; + + #[derive(Empty)] + struct S; +} + +fn main() {} diff --git a/src/test/ui/proc-macro/derive-still-gated.rs b/src/test/ui/proc-macro/derive-still-gated.rs index 526eff39891ae..d895d26f26763 100644 --- a/src/test/ui/proc-macro/derive-still-gated.rs +++ b/src/test/ui/proc-macro/derive-still-gated.rs @@ -1,11 +1,9 @@ -// aux-build:derive-a.rs - -#![allow(warnings)] +// aux-build:test-macros.rs #[macro_use] -extern crate derive_a; +extern crate test_macros; -#[derive_A] //~ ERROR attribute `derive_A` is currently unknown +#[derive_Empty] //~ ERROR attribute `derive_Empty` is currently unknown struct A; fn main() {} diff --git a/src/test/ui/proc-macro/derive-still-gated.stderr b/src/test/ui/proc-macro/derive-still-gated.stderr index ece1b6212914d..f299b5abdbc6b 100644 --- a/src/test/ui/proc-macro/derive-still-gated.stderr +++ b/src/test/ui/proc-macro/derive-still-gated.stderr @@ -1,9 +1,10 @@ -error[E0658]: The attribute `derive_A` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/derive-still-gated.rs:8:3 +error[E0658]: The attribute `derive_Empty` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/derive-still-gated.rs:6:3 | -LL | #[derive_A] //~ ERROR attribute `derive_A` is currently unknown - | ^^^^^^^^ help: a built-in attribute with a similar name exists: `derive` +LL | #[derive_Empty] + | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/proc-macro/dollar-crate-issue-57089.rs b/src/test/ui/proc-macro/dollar-crate-issue-57089.rs index 2d54c07ff9530..2615db3e119f1 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-57089.rs +++ b/src/test/ui/proc-macro/dollar-crate-issue-57089.rs @@ -1,22 +1,23 @@ // compile-pass // edition:2018 -// aux-build:dollar-crate.rs +// aux-build:test-macros.rs // Anonymize unstable non-dummy spans while still showing dummy spans `0..0`. // normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)" // normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)" -extern crate dollar_crate; +#[macro_use] +extern crate test_macros; type S = u8; macro_rules! m { () => { - dollar_crate::m_empty! { + print_bang! { struct M($crate::S); } - #[dollar_crate::a] + #[print_attr] struct A($crate::S); }; } diff --git a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout index 09340988c8968..0611fcb13f267 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout @@ -1,80 +1,81 @@ -PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ; -PROC MACRO INPUT: TokenStream [ +PRINT-BANG INPUT (DISPLAY): struct M ( $crate :: S ) ; +PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "M", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ], - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ] -ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(crate::S); -ATTRIBUTE INPUT: TokenStream [ +PRINT-ATTR INPUT (DISPLAY): struct A(crate::S); +PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( $crate :: S ) ; +PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "A", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ], - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ] diff --git a/src/test/ui/proc-macro/dollar-crate.rs b/src/test/ui/proc-macro/dollar-crate.rs index 1460e9a3b2d55..aadd87ffaf203 100644 --- a/src/test/ui/proc-macro/dollar-crate.rs +++ b/src/test/ui/proc-macro/dollar-crate.rs @@ -1,29 +1,28 @@ // edition:2018 -// aux-build:dollar-crate.rs +// aux-build:test-macros.rs // aux-build:dollar-crate-external.rs // Anonymize unstable non-dummy spans while still showing dummy spans `0..0`. // normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)" // normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)" -extern crate dollar_crate; +#[macro_use] +extern crate test_macros; extern crate dollar_crate_external; type S = u8; mod local { - use crate::dollar_crate; - macro_rules! local { () => { - dollar_crate::m! { + print_bang! { struct M($crate::S); } - #[dollar_crate::a] + #[print_attr] struct A($crate::S); - #[derive(dollar_crate::d)] + #[derive(Print)] struct D($crate::S); //~ ERROR the name `D` is defined multiple times }; } diff --git a/src/test/ui/proc-macro/dollar-crate.stderr b/src/test/ui/proc-macro/dollar-crate.stderr index 08de3c7d1a666..5d78a8e198729 100644 --- a/src/test/ui/proc-macro/dollar-crate.stderr +++ b/src/test/ui/proc-macro/dollar-crate.stderr @@ -1,7 +1,7 @@ error[E0428]: the name `D` is defined multiple times - --> $DIR/dollar-crate.rs:27:13 + --> $DIR/dollar-crate.rs:26:13 | -LL | struct D($crate::S); //~ ERROR the name `D` is defined multiple times +LL | struct D($crate::S); | ^^^^^^^^^^^^^^^^^^^^ | | | `D` redefined here @@ -13,9 +13,9 @@ LL | local!(); = note: `D` must be defined only once in the type namespace of this module error[E0428]: the name `D` is defined multiple times - --> $DIR/dollar-crate.rs:37:5 + --> $DIR/dollar-crate.rs:36:5 | -LL | dollar_crate_external::external!(); //~ ERROR the name `D` is defined multiple times +LL | dollar_crate_external::external!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | `D` redefined here diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout index c47b3603f41c0..3c88ee99842a2 100644 --- a/src/test/ui/proc-macro/dollar-crate.stdout +++ b/src/test/ui/proc-macro/dollar-crate.stdout @@ -1,240 +1,244 @@ -PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ; -PROC MACRO INPUT: TokenStream [ +PRINT-BANG INPUT (DISPLAY): struct M ( $crate :: S ) ; +PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "M", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ], - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ] -ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(crate::S); -ATTRIBUTE INPUT: TokenStream [ +PRINT-ATTR INPUT (DISPLAY): struct A(crate::S); +PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( $crate :: S ) ; +PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "A", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ], - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ] -DERIVE INPUT (PRETTY-PRINTED): struct D(crate::S); -DERIVE INPUT: TokenStream [ +PRINT-DERIVE INPUT (DISPLAY): struct D(crate::S); +PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ( $crate :: S ) ; +PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "D", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ], - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ] -PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ; -PROC MACRO INPUT: TokenStream [ +PRINT-BANG INPUT (DISPLAY): struct M ( $crate :: S ) ; +PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Ident { ident: "M", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Ident { ident: "S", - span: #10 bytes(LO..HI) - } + span: #10 bytes(LO..HI), + }, ], - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #10 bytes(LO..HI) - } + span: #10 bytes(LO..HI), + }, ] -ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(::dollar_crate_external::S); -ATTRIBUTE INPUT: TokenStream [ +PRINT-ATTR INPUT (DISPLAY): struct A(::dollar_crate_external::S); +PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( $crate :: S ) ; +PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Ident { ident: "A", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Ident { ident: "S", - span: #10 bytes(LO..HI) - } + span: #10 bytes(LO..HI), + }, ], - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #10 bytes(LO..HI) - } + span: #10 bytes(LO..HI), + }, ] -DERIVE INPUT (PRETTY-PRINTED): struct D(::dollar_crate_external::S); -DERIVE INPUT: TokenStream [ +PRINT-DERIVE INPUT (DISPLAY): struct D(::dollar_crate_external::S); +PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ( $crate :: S ) ; +PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Ident { ident: "D", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Ident { ident: "S", - span: #10 bytes(LO..HI) - } + span: #10 bytes(LO..HI), + }, ], - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #10 bytes(LO..HI) - } + span: #10 bytes(LO..HI), + }, ] diff --git a/src/test/ui/proc-macro/expand-to-unstable-2.stderr b/src/test/ui/proc-macro/expand-to-unstable-2.stderr index b322f8e9d5610..e2f51dd3d5dd2 100644 --- a/src/test/ui/proc-macro/expand-to-unstable-2.stderr +++ b/src/test/ui/proc-macro/expand-to-unstable-2.stderr @@ -1,9 +1,10 @@ -error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics (see issue #29642) +error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics --> $DIR/expand-to-unstable-2.rs:8:10 | LL | #[derive(Unstable)] | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(rustc_attrs)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/proc-macro/exports.stderr b/src/test/ui/proc-macro/exports.stderr index 6cf5c63d2da4b..2f81921358dfe 100644 --- a/src/test/ui/proc-macro/exports.stderr +++ b/src/test/ui/proc-macro/exports.stderr @@ -1,25 +1,25 @@ error: `proc-macro` crate types cannot export any items other than functions tagged with `#[proc_macro_derive]` currently --> $DIR/exports.rs:7:1 | -LL | pub fn a() {} //~ ERROR: cannot export any items +LL | pub fn a() {} | ^^^^^^^^^^^^^ error: `proc-macro` crate types cannot export any items other than functions tagged with `#[proc_macro_derive]` currently --> $DIR/exports.rs:8:1 | -LL | pub struct B; //~ ERROR: cannot export any items +LL | pub struct B; | ^^^^^^^^^^^^^ error: `proc-macro` crate types cannot export any items other than functions tagged with `#[proc_macro_derive]` currently --> $DIR/exports.rs:9:1 | -LL | pub enum C {} //~ ERROR: cannot export any items +LL | pub enum C {} | ^^^^^^^^^^^^^ error: `proc-macro` crate types cannot export any items other than functions tagged with `#[proc_macro_derive]` currently --> $DIR/exports.rs:10:1 | -LL | pub mod d {} //~ ERROR: cannot export any items +LL | pub mod d {} | ^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/proc-macro/generate-mod.stderr b/src/test/ui/proc-macro/generate-mod.stderr index 1177fc6e575a7..1b828b4f03f2c 100644 --- a/src/test/ui/proc-macro/generate-mod.stderr +++ b/src/test/ui/proc-macro/generate-mod.stderr @@ -1,31 +1,31 @@ error[E0412]: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:9:1 | -LL | generate_mod::check!(); //~ ERROR cannot find type `FromOutside` in this scope +LL | generate_mod::check!(); | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `Outer` in this scope --> $DIR/generate-mod.rs:9:1 | -LL | generate_mod::check!(); //~ ERROR cannot find type `FromOutside` in this scope +LL | generate_mod::check!(); | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:12:1 | -LL | #[generate_mod::check_attr] //~ ERROR cannot find type `FromOutside` in this scope +LL | #[generate_mod::check_attr] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `OuterAttr` in this scope --> $DIR/generate-mod.rs:12:1 | -LL | #[generate_mod::check_attr] //~ ERROR cannot find type `FromOutside` in this scope +LL | #[generate_mod::check_attr] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope warning: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:16:10 | -LL | #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope +LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | = note: #[warn(proc_macro_derive_resolution_fallback)] on by default @@ -35,7 +35,7 @@ LL | #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside warning: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:16:10 | -LL | #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope +LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -44,7 +44,7 @@ LL | #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside warning: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:23:14 | -LL | #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope +LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -53,7 +53,7 @@ LL | #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOut warning: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:23:14 | -LL | #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope +LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.rs b/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.rs new file mode 100644 index 0000000000000..3a1c56efce8c2 --- /dev/null +++ b/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.rs @@ -0,0 +1,11 @@ +// aux-build:test-macros.rs + +#[macro_use(Empty)] +extern crate test_macros; +use test_macros::empty_attr as empty_helper; + +#[derive(Empty)] +#[empty_helper] //~ ERROR `empty_helper` is ambiguous +struct S; + +fn main() {} diff --git a/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr b/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr new file mode 100644 index 0000000000000..012fb105b128d --- /dev/null +++ b/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr @@ -0,0 +1,21 @@ +error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name) + --> $DIR/helper-attr-blocked-by-import-ambig.rs:8:3 + | +LL | #[empty_helper] + | ^^^^^^^^^^^^ ambiguous name + | +note: `empty_helper` could refer to the derive helper attribute defined here + --> $DIR/helper-attr-blocked-by-import-ambig.rs:7:10 + | +LL | #[derive(Empty)] + | ^^^^^ +note: `empty_helper` could also refer to the attribute macro imported here + --> $DIR/helper-attr-blocked-by-import-ambig.rs:5:5 + | +LL | use test_macros::empty_attr as empty_helper; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use `crate::empty_helper` to refer to this attribute macro unambiguously + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/src/test/ui/proc-macro/helper-attr-blocked-by-import.rs b/src/test/ui/proc-macro/helper-attr-blocked-by-import.rs new file mode 100644 index 0000000000000..6d3e5ec198d85 --- /dev/null +++ b/src/test/ui/proc-macro/helper-attr-blocked-by-import.rs @@ -0,0 +1,28 @@ +// compile-pass +// aux-build:test-macros.rs + +#[macro_use(Empty)] +extern crate test_macros; + +use self::one::*; +use self::two::*; + +mod empty_helper {} + +mod one { + use empty_helper; + + #[derive(Empty)] + #[empty_helper] + struct One; +} + +mod two { + use empty_helper; + + #[derive(Empty)] + #[empty_helper] + struct Two; +} + +fn main() {} diff --git a/src/test/ui/proc-macro/import.rs b/src/test/ui/proc-macro/import.rs index 8fbccdf1aed14..d1b1ff350695f 100644 --- a/src/test/ui/proc-macro/import.rs +++ b/src/test/ui/proc-macro/import.rs @@ -1,11 +1,8 @@ -// aux-build:derive-a.rs +// aux-build:test-macros.rs -#![allow(warnings)] +extern crate test_macros; -#[macro_use] -extern crate derive_a; - -use derive_a::derive_a; -//~^ ERROR: unresolved import `derive_a::derive_a` +use test_macros::empty_derive; +//~^ ERROR: unresolved import `test_macros::empty_derive` fn main() {} diff --git a/src/test/ui/proc-macro/import.stderr b/src/test/ui/proc-macro/import.stderr index 813a8ac260460..aae621193ab9f 100644 --- a/src/test/ui/proc-macro/import.stderr +++ b/src/test/ui/proc-macro/import.stderr @@ -1,8 +1,8 @@ -error[E0432]: unresolved import `derive_a::derive_a` - --> $DIR/import.rs:8:5 +error[E0432]: unresolved import `test_macros::empty_derive` + --> $DIR/import.rs:5:5 | -LL | use derive_a::derive_a; - | ^^^^^^^^^^^^^^^^^^ no `derive_a` in the root +LL | use test_macros::empty_derive; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ no `empty_derive` in the root error: aborting due to previous error diff --git a/src/test/ui/proc-macro/invalid-attributes.rs b/src/test/ui/proc-macro/invalid-attributes.rs index c5ec4925e4310..6bbe022c690fe 100644 --- a/src/test/ui/proc-macro/invalid-attributes.rs +++ b/src/test/ui/proc-macro/invalid-attributes.rs @@ -7,20 +7,20 @@ extern crate proc_macro; use proc_macro::TokenStream; -#[proc_macro = "test"] //~ ERROR attribute must be of the form +#[proc_macro = "test"] //~ ERROR malformed `proc_macro` attribute pub fn a(a: TokenStream) -> TokenStream { a } -#[proc_macro()] //~ ERROR attribute must be of the form +#[proc_macro()] //~ ERROR malformed `proc_macro` attribute pub fn c(a: TokenStream) -> TokenStream { a } -#[proc_macro(x)] //~ ERROR attribute must be of the form +#[proc_macro(x)] //~ ERROR malformed `proc_macro` attribute pub fn d(a: TokenStream) -> TokenStream { a } -#[proc_macro_attribute = "test"] //~ ERROR attribute must be of the form +#[proc_macro_attribute = "test"] //~ ERROR malformed `proc_macro_attribute` attribute pub fn e(_: TokenStream, a: TokenStream) -> TokenStream { a } -#[proc_macro_attribute()] //~ ERROR attribute must be of the form +#[proc_macro_attribute()] //~ ERROR malformed `proc_macro_attribute` attribute pub fn g(_: TokenStream, a: TokenStream) -> TokenStream { a } -#[proc_macro_attribute(x)] //~ ERROR attribute must be of the form +#[proc_macro_attribute(x)] //~ ERROR malformed `proc_macro_attribute` attribute pub fn h(_: TokenStream, a: TokenStream) -> TokenStream { a } diff --git a/src/test/ui/proc-macro/invalid-attributes.stderr b/src/test/ui/proc-macro/invalid-attributes.stderr index 06a7ef2b206c7..fe411fa5e1f8e 100644 --- a/src/test/ui/proc-macro/invalid-attributes.stderr +++ b/src/test/ui/proc-macro/invalid-attributes.stderr @@ -1,38 +1,38 @@ -error: attribute must be of the form `#[proc_macro]` +error: malformed `proc_macro` attribute input --> $DIR/invalid-attributes.rs:10:1 | -LL | #[proc_macro = "test"] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro = "test"] + | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]` -error: attribute must be of the form `#[proc_macro]` +error: malformed `proc_macro` attribute input --> $DIR/invalid-attributes.rs:13:1 | -LL | #[proc_macro()] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^^ +LL | #[proc_macro()] + | ^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]` -error: attribute must be of the form `#[proc_macro]` +error: malformed `proc_macro` attribute input --> $DIR/invalid-attributes.rs:16:1 | -LL | #[proc_macro(x)] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^^^ +LL | #[proc_macro(x)] + | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]` -error: attribute must be of the form `#[proc_macro_attribute]` +error: malformed `proc_macro_attribute` attribute input --> $DIR/invalid-attributes.rs:19:1 | -LL | #[proc_macro_attribute = "test"] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_attribute = "test"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]` -error: attribute must be of the form `#[proc_macro_attribute]` +error: malformed `proc_macro_attribute` attribute input --> $DIR/invalid-attributes.rs:22:1 | -LL | #[proc_macro_attribute()] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_attribute()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]` -error: attribute must be of the form `#[proc_macro_attribute]` +error: malformed `proc_macro_attribute` attribute input --> $DIR/invalid-attributes.rs:25:1 | -LL | #[proc_macro_attribute(x)] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_attribute(x)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]` error: aborting due to 6 previous errors diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.rs b/src/test/ui/proc-macro/invalid-punct-ident-1.rs index 2360b1fe8c0fc..c9881ad2c38af 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.rs @@ -1,5 +1,9 @@ // aux-build:invalid-punct-ident.rs +// FIXME https://github.com/rust-lang/rust/issues/59998 +// normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" + #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr index 875941303787c..40333a3f4c211 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr @@ -1,7 +1,7 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-1.rs:6:1 + --> $DIR/invalid-punct-ident-1.rs:10:1 | -LL | invalid_punct!(); //~ ERROR proc macro panicked +LL | invalid_punct!(); | ^^^^^^^^^^^^^^^^^ | = help: message: unsupported character `'`'` diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.rs b/src/test/ui/proc-macro/invalid-punct-ident-2.rs index 9593d47bb13b0..15e2286a65049 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-2.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-2.rs @@ -1,5 +1,9 @@ // aux-build:invalid-punct-ident.rs +// FIXME https://github.com/rust-lang/rust/issues/59998 +// normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" + #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr index 384d30650f10c..ec97e265c3fcd 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr @@ -1,7 +1,7 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-2.rs:6:1 + --> $DIR/invalid-punct-ident-2.rs:10:1 | -LL | invalid_ident!(); //~ ERROR proc macro panicked +LL | invalid_ident!(); | ^^^^^^^^^^^^^^^^^ | = help: message: `"*"` is not a valid identifier diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.rs b/src/test/ui/proc-macro/invalid-punct-ident-3.rs index 75e3e06f881f3..629bbaa9e3888 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-3.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-3.rs @@ -1,5 +1,9 @@ // aux-build:invalid-punct-ident.rs +// FIXME https://github.com/rust-lang/rust/issues/59998 +// normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" + #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr index fd34459e89766..a5e5ded65333a 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr @@ -1,10 +1,10 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-3.rs:6:1 + --> $DIR/invalid-punct-ident-3.rs:10:1 | -LL | invalid_raw_ident!(); //~ ERROR proc macro panicked +LL | invalid_raw_ident!(); | ^^^^^^^^^^^^^^^^^^^^^ | - = help: message: `"self"` is not a valid raw identifier + = help: message: `self` cannot be a raw identifier error: aborting due to previous error diff --git a/src/test/ui/proc-macro/invalid-punct-ident-4.stderr b/src/test/ui/proc-macro/invalid-punct-ident-4.stderr index 39eb64e555c14..da2bf07a1a3ad 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-4.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-4.stderr @@ -1,13 +1,13 @@ error: unexpected close delimiter: `)` --> $DIR/invalid-punct-ident-4.rs:6:1 | -LL | lexer_failure!(); //~ ERROR proc macro panicked +LL | lexer_failure!(); | ^^^^^^^^^^^^^^^^^ unexpected close delimiter error: proc macro panicked --> $DIR/invalid-punct-ident-4.rs:6:1 | -LL | lexer_failure!(); //~ ERROR proc macro panicked +LL | lexer_failure!(); | ^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/proc-macro/issue-36935.rs b/src/test/ui/proc-macro/issue-36935.rs new file mode 100644 index 0000000000000..f809592d5f449 --- /dev/null +++ b/src/test/ui/proc-macro/issue-36935.rs @@ -0,0 +1,12 @@ +// aux-build:test-macros.rs + +#[macro_use] +extern crate test_macros; + +#[derive(Identity, Panic)] //~ ERROR proc-macro derive panicked +struct Baz { + a: i32, + b: i32, +} + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-36935.stderr b/src/test/ui/proc-macro/issue-36935.stderr new file mode 100644 index 0000000000000..da4366eb668d6 --- /dev/null +++ b/src/test/ui/proc-macro/issue-36935.stderr @@ -0,0 +1,10 @@ +error: proc-macro derive panicked + --> $DIR/issue-36935.rs:6:20 + | +LL | #[derive(Identity, Panic)] + | ^^^^^ + | + = help: message: panic-derive + +error: aborting due to previous error + diff --git a/src/test/ui/proc-macro/issue-37788.rs b/src/test/ui/proc-macro/issue-37788.rs index 75fcd24d85f6f..73b1f0d58c837 100644 --- a/src/test/ui/proc-macro/issue-37788.rs +++ b/src/test/ui/proc-macro/issue-37788.rs @@ -1,7 +1,7 @@ -// aux-build:derive-a-b.rs +// aux-build:test-macros.rs #[macro_use] -extern crate derive_a_b; +extern crate test_macros; fn main() { // Test that constructing the `visible_parent_map` (in `cstore_impl.rs`) does not ICE. diff --git a/src/test/ui/proc-macro/issue-37788.stderr b/src/test/ui/proc-macro/issue-37788.stderr index 40f28460b1631..0727e8c8ed168 100644 --- a/src/test/ui/proc-macro/issue-37788.stderr +++ b/src/test/ui/proc-macro/issue-37788.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn main() { | - expected `()` because of default return type LL | // Test that constructing the `visible_parent_map` (in `cstore_impl.rs`) does not ICE. -LL | std::cell::Cell::new(0) //~ ERROR mismatched types +LL | std::cell::Cell::new(0) | ^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;` | | | expected (), found struct `std::cell::Cell` diff --git a/src/test/ui/proc-macro/issue-38586.rs b/src/test/ui/proc-macro/issue-38586.rs index 4f291ba990ab7..24e88ed93caaf 100644 --- a/src/test/ui/proc-macro/issue-38586.rs +++ b/src/test/ui/proc-macro/issue-38586.rs @@ -1,4 +1,4 @@ -// aux-build:issue_38586.rs +// aux-build:issue-38586.rs #[macro_use] extern crate issue_38586; diff --git a/src/test/ui/proc-macro/issue-38586.stderr b/src/test/ui/proc-macro/issue-38586.stderr index 9657914f49bb7..2584e0c62eece 100644 --- a/src/test/ui/proc-macro/issue-38586.stderr +++ b/src/test/ui/proc-macro/issue-38586.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `foo` in this scope --> $DIR/issue-38586.rs:6:10 | -LL | #[derive(A)] //~ ERROR `foo` +LL | #[derive(A)] | ^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/proc-macro/issue-41211.rs b/src/test/ui/proc-macro/issue-41211.rs index 0b082f4818f1b..ee9246e1c9b5c 100644 --- a/src/test/ui/proc-macro/issue-41211.rs +++ b/src/test/ui/proc-macro/issue-41211.rs @@ -1,14 +1,14 @@ -// aux-build:issue-41211.rs +// aux-build:test-macros.rs // FIXME: https://github.com/rust-lang/rust/issues/41430 // This is a temporary regression test for the ICE reported in #41211 #![feature(custom_inner_attributes)] -#![emit_unchanged] -//~^ ERROR attribute `emit_unchanged` is currently unknown to the compiler +#![identity_attr] +//~^ ERROR attribute `identity_attr` is currently unknown to the compiler //~| ERROR inconsistent resolution for a macro: first custom attribute, then attribute macro -extern crate issue_41211; -use issue_41211::emit_unchanged; +extern crate test_macros; +use test_macros::identity_attr; fn main() {} diff --git a/src/test/ui/proc-macro/issue-41211.stderr b/src/test/ui/proc-macro/issue-41211.stderr index f75481e4829bf..1de6b293ecfb8 100644 --- a/src/test/ui/proc-macro/issue-41211.stderr +++ b/src/test/ui/proc-macro/issue-41211.stderr @@ -1,16 +1,17 @@ -error[E0658]: The attribute `emit_unchanged` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `identity_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/issue-41211.rs:8:4 | -LL | #![emit_unchanged] - | ^^^^^^^^^^^^^^ +LL | #![identity_attr] + | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: inconsistent resolution for a macro: first custom attribute, then attribute macro --> $DIR/issue-41211.rs:8:4 | -LL | #![emit_unchanged] - | ^^^^^^^^^^^^^^ +LL | #![identity_attr] + | ^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/proc-macro/issue-50493.rs b/src/test/ui/proc-macro/issue-50493.rs index f504dbdfce247..5d1a9f25baffd 100644 --- a/src/test/ui/proc-macro/issue-50493.rs +++ b/src/test/ui/proc-macro/issue-50493.rs @@ -1,4 +1,4 @@ -// aux-build:issue_50493.rs +// aux-build:issue-50493.rs #[macro_use] extern crate issue_50493; @@ -11,4 +11,3 @@ struct Restricted { mod restricted {} fn main() {} - diff --git a/src/test/ui/proc-macro/issue-50493.stderr b/src/test/ui/proc-macro/issue-50493.stderr index 559e8f0f2225b..28c61a2f52fed 100644 --- a/src/test/ui/proc-macro/issue-50493.stderr +++ b/src/test/ui/proc-macro/issue-50493.stderr @@ -1,13 +1,13 @@ error: visibilities can only be restricted to ancestor modules --> $DIR/issue-50493.rs:8:12 | -LL | pub(in restricted) field: usize, //~ visibilities can only be restricted to ancestor modules +LL | pub(in restricted) field: usize, | ^^^^^^^^^^ error[E0616]: field `field` of struct `Restricted` is private --> $DIR/issue-50493.rs:6:10 | -LL | #[derive(Derive)] //~ ERROR field `field` of struct `Restricted` is private +LL | #[derive(Derive)] | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/proc-macro/issue-53481.rs b/src/test/ui/proc-macro/issue-53481.rs index 479fd1db630a3..2fbde5fedb95b 100644 --- a/src/test/ui/proc-macro/issue-53481.rs +++ b/src/test/ui/proc-macro/issue-53481.rs @@ -1,21 +1,21 @@ // compile-pass -// aux-build:issue-53481.rs +// aux-build:test-macros.rs #[macro_use] -extern crate issue_53481; +extern crate test_macros; mod m1 { - use m2::MyTrait; + use m2::Empty; - #[derive(MyTrait)] + #[derive(Empty)] struct A {} } mod m2 { - pub type MyTrait = u8; + pub type Empty = u8; - #[derive(MyTrait)] - #[my_attr] + #[derive(Empty)] + #[empty_helper] struct B {} } diff --git a/src/test/ui/proc-macro/lifetimes.stderr b/src/test/ui/proc-macro/lifetimes.stderr index c873ab68654b8..2356a119530bb 100644 --- a/src/test/ui/proc-macro/lifetimes.stderr +++ b/src/test/ui/proc-macro/lifetimes.stderr @@ -1,7 +1,7 @@ error: expected type, found `'` --> $DIR/lifetimes.rs:9:10 | -LL | type A = single_quote_alone!(); //~ ERROR expected type, found `'` +LL | type A = single_quote_alone!(); | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/proc-macro/load-panic.rs b/src/test/ui/proc-macro/load-panic.rs index fa279c559fbf1..2e9a311d882bd 100644 --- a/src/test/ui/proc-macro/load-panic.rs +++ b/src/test/ui/proc-macro/load-panic.rs @@ -1,10 +1,9 @@ -// aux-build:derive-panic.rs -// compile-flags:--error-format human +// aux-build:test-macros.rs #[macro_use] -extern crate derive_panic; +extern crate test_macros; -#[derive(A)] +#[derive(Panic)] //~^ ERROR: proc-macro derive panicked struct Foo; diff --git a/src/test/ui/proc-macro/load-panic.stderr b/src/test/ui/proc-macro/load-panic.stderr index b448c804bff59..40cc4ee0e3d37 100644 --- a/src/test/ui/proc-macro/load-panic.stderr +++ b/src/test/ui/proc-macro/load-panic.stderr @@ -1,10 +1,10 @@ error: proc-macro derive panicked - --> $DIR/load-panic.rs:7:10 + --> $DIR/load-panic.rs:6:10 | -LL | #[derive(A)] - | ^ +LL | #[derive(Panic)] + | ^^^^^ | - = help: message: nope! + = help: message: panic-derive error: aborting due to previous error diff --git a/src/test/ui/proc-macro/macro-brackets.rs b/src/test/ui/proc-macro/macro-brackets.rs index c46abf03654ce..aa0046f458229 100644 --- a/src/test/ui/proc-macro/macro-brackets.rs +++ b/src/test/ui/proc-macro/macro-brackets.rs @@ -1,13 +1,13 @@ -// aux-build:macro-brackets.rs +// aux-build:test-macros.rs -extern crate macro_brackets as bar; -use bar::doit; +#[macro_use] +extern crate test_macros; macro_rules! id { ($($t:tt)*) => ($($t)*) } -#[doit] +#[identity_attr] id![static X: u32 = 'a';]; //~ ERROR: mismatched types diff --git a/src/test/ui/proc-macro/macro-brackets.stderr b/src/test/ui/proc-macro/macro-brackets.stderr index a3cc7d485cd39..7447b5c15eef0 100644 --- a/src/test/ui/proc-macro/macro-brackets.stderr +++ b/src/test/ui/proc-macro/macro-brackets.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/macro-brackets.rs:11:21 | -LL | id![static X: u32 = 'a';]; //~ ERROR: mismatched types +LL | id![static X: u32 = 'a';]; | ^^^ expected u32, found char error: aborting due to previous error diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr index c1821199e30b1..548f9e3051dd3 100644 --- a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -1,55 +1,55 @@ error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:25:5 | -LL | my_macro!(); //~ ERROR can't use a procedural macro from the same crate that defines it +LL | my_macro!(); | ^^^^^^^^ error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:28:5 | -LL | my_macro_attr!(); //~ ERROR can't use a procedural macro from the same crate that defines it +LL | my_macro_attr!(); | ^^^^^^^^^^^^^ error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:31:5 | -LL | MyTrait!(); //~ ERROR can't use a procedural macro from the same crate that defines it +LL | MyTrait!(); | ^^^^^^^ error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:34:3 | -LL | #[my_macro] //~ ERROR can't use a procedural macro from the same crate that defines it +LL | #[my_macro] | ^^^^^^^^ error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:36:3 | -LL | #[my_macro_attr] //~ ERROR can't use a procedural macro from the same crate that defines it +LL | #[my_macro_attr] | ^^^^^^^^^^^^^ error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:38:3 | -LL | #[MyTrait] //~ ERROR can't use a procedural macro from the same crate that defines it +LL | #[MyTrait] | ^^^^^^^ error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:41:10 | -LL | #[derive(my_macro)] //~ ERROR can't use a procedural macro from the same crate that defines it +LL | #[derive(my_macro)] | ^^^^^^^^ error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:43:10 | -LL | #[derive(my_macro_attr)] //~ ERROR can't use a procedural macro from the same crate that defines it +LL | #[derive(my_macro_attr)] | ^^^^^^^^^^^^^ error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:45:10 | -LL | #[derive(MyTrait)] //~ ERROR can't use a procedural macro from the same crate that defines it +LL | #[derive(MyTrait)] | ^^^^^^^ error: aborting due to 9 previous errors diff --git a/src/test/ui/proc-macro/macro-namespace-reserved.stderr b/src/test/ui/proc-macro/macro-namespace-reserved.stderr index 2192e6d2b17aa..f5d589c3ac6ef 100644 --- a/src/test/ui/proc-macro/macro-namespace-reserved.stderr +++ b/src/test/ui/proc-macro/macro-namespace-reserved.stderr @@ -4,7 +4,7 @@ error[E0428]: the name `my_macro` is defined multiple times LL | pub fn my_macro(input: TokenStream) -> TokenStream { | -------------------------------------------------- previous definition of the macro `my_macro` here ... -LL | macro my_macro() {} //~ ERROR the name `my_macro` is defined multiple times +LL | macro my_macro() {} | ^^^^^^^^^^^^^^^^ `my_macro` redefined here | = note: `my_macro` must be defined only once in the macro namespace of this module @@ -15,7 +15,7 @@ error[E0428]: the name `my_macro_attr` is defined multiple times LL | pub fn my_macro_attr(input: TokenStream, _: TokenStream) -> TokenStream { | ----------------------------------------------------------------------- previous definition of the macro `my_macro_attr` here ... -LL | macro my_macro_attr() {} //~ ERROR the name `my_macro_attr` is defined multiple times +LL | macro my_macro_attr() {} | ^^^^^^^^^^^^^^^^^^^^^ `my_macro_attr` redefined here | = note: `my_macro_attr` must be defined only once in the macro namespace of this module @@ -26,7 +26,7 @@ error[E0428]: the name `MyTrait` is defined multiple times LL | #[proc_macro_derive(MyTrait)] | ------- previous definition of the macro `MyTrait` here ... -LL | macro MyTrait() {} //~ ERROR the name `MyTrait` is defined multiple times +LL | macro MyTrait() {} | ^^^^^^^^^^^^^^^ `MyTrait` redefined here | = note: `MyTrait` must be defined only once in the macro namespace of this module diff --git a/src/test/ui/proc-macro/macro-use-attr.rs b/src/test/ui/proc-macro/macro-use-attr.rs index 13db0725a388b..d1b1430fb5d03 100644 --- a/src/test/ui/proc-macro/macro-use-attr.rs +++ b/src/test/ui/proc-macro/macro-use-attr.rs @@ -1,9 +1,10 @@ // compile-pass -// aux-build:attr_proc_macro.rs +// aux-build:test-macros.rs -#[macro_use] extern crate attr_proc_macro; +#[macro_use] +extern crate test_macros; -#[attr_proc_macro] +#[identity_attr] struct Foo; fn main() { diff --git a/src/test/ui/proc-macro/macro-use-bang.rs b/src/test/ui/proc-macro/macro-use-bang.rs index 4bf3bcd6f3aae..d39c42267fb96 100644 --- a/src/test/ui/proc-macro/macro-use-bang.rs +++ b/src/test/ui/proc-macro/macro-use-bang.rs @@ -1,11 +1,11 @@ // compile-pass -// aux-build:bang_proc_macro.rs +// aux-build:test-macros.rs #![feature(proc_macro_hygiene)] #[macro_use] -extern crate bang_proc_macro; +extern crate test_macros; fn main() { - bang_proc_macro!(println!("Hello, world!")); + identity!(println!("Hello, world!")); } diff --git a/src/test/ui/proc-macro/macros-in-extern.rs b/src/test/ui/proc-macro/macros-in-extern.rs index 5c5603b6c06b0..0477b5c48ecc9 100644 --- a/src/test/ui/proc-macro/macros-in-extern.rs +++ b/src/test/ui/proc-macro/macros-in-extern.rs @@ -1,10 +1,9 @@ // aux-build:test-macros.rs // ignore-wasm32 +#[macro_use] extern crate test_macros; -use test_macros::{nop_attr, no_output, emit_input}; - fn main() { assert_eq!(unsafe { rust_get_test_int() }, 0isize); assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF); @@ -12,14 +11,14 @@ fn main() { #[link(name = "rust_test_helpers", kind = "static")] extern { - #[no_output] + #[empty_attr] //~^ ERROR macro invocations in `extern {}` blocks are experimental fn some_definitely_unknown_symbol_which_should_be_removed(); - #[nop_attr] + #[identity_attr] //~^ ERROR macro invocations in `extern {}` blocks are experimental fn rust_get_test_int() -> isize; - emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); + identity!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); //~^ ERROR macro invocations in `extern {}` blocks are experimental } diff --git a/src/test/ui/proc-macro/macros-in-extern.stderr b/src/test/ui/proc-macro/macros-in-extern.stderr index 8a48656d08790..592c91553aa8c 100644 --- a/src/test/ui/proc-macro/macros-in-extern.stderr +++ b/src/test/ui/proc-macro/macros-in-extern.stderr @@ -1,25 +1,28 @@ -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) - --> $DIR/macros-in-extern.rs:15:5 +error[E0658]: macro invocations in `extern {}` blocks are experimental + --> $DIR/macros-in-extern.rs:14:5 | -LL | #[no_output] - | ^^^^^^^^^^^^ +LL | #[empty_attr] + | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) - --> $DIR/macros-in-extern.rs:19:5 +error[E0658]: macro invocations in `extern {}` blocks are experimental + --> $DIR/macros-in-extern.rs:18:5 | -LL | #[nop_attr] - | ^^^^^^^^^^^ +LL | #[identity_attr] + | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) - --> $DIR/macros-in-extern.rs:23:5 +error[E0658]: macro invocations in `extern {}` blocks are experimental + --> $DIR/macros-in-extern.rs:22:5 | -LL | emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | identity!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/proc-macro/more-gates.stderr b/src/test/ui/proc-macro/more-gates.stderr index 21e75027e4879..80985ce752353 100644 --- a/src/test/ui/proc-macro/more-gates.stderr +++ b/src/test/ui/proc-macro/more-gates.stderr @@ -1,41 +1,46 @@ -error[E0658]: procedural macros cannot expand to macro definitions (see issue #54727) +error[E0658]: procedural macros cannot expand to macro definitions --> $DIR/more-gates.rs:9:1 | LL | #[attr2mac1] | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot expand to macro definitions (see issue #54727) +error[E0658]: procedural macros cannot expand to macro definitions --> $DIR/more-gates.rs:12:1 | LL | #[attr2mac2] | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot expand to macro definitions (see issue #54727) +error[E0658]: procedural macros cannot expand to macro definitions --> $DIR/more-gates.rs:16:1 | -LL | mac2mac1!(); //~ ERROR: cannot expand to macro definitions +LL | mac2mac1!(); | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot expand to macro definitions (see issue #54727) +error[E0658]: procedural macros cannot expand to macro definitions --> $DIR/more-gates.rs:17:1 | -LL | mac2mac2!(); //~ ERROR: cannot expand to macro definitions +LL | mac2mac2!(); | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot expand to macro definitions (see issue #54727) +error[E0658]: procedural macros cannot expand to macro definitions --> $DIR/more-gates.rs:19:1 | LL | tricky!(); | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable error: aborting due to 5 previous errors diff --git a/src/test/ui/proc-macro/multispan.stderr b/src/test/ui/proc-macro/multispan.stderr index 7519f778e9e75..44af07a794234 100644 --- a/src/test/ui/proc-macro/multispan.stderr +++ b/src/test/ui/proc-macro/multispan.stderr @@ -1,85 +1,85 @@ error: hello to you, too! --> $DIR/multispan.rs:14:5 | -LL | hello!(hi); //~ ERROR hello to you, too! +LL | hello!(hi); | ^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:14:12 | -LL | hello!(hi); //~ ERROR hello to you, too! +LL | hello!(hi); | ^^ error: hello to you, too! --> $DIR/multispan.rs:17:5 | -LL | hello!(hi hi); //~ ERROR hello to you, too! +LL | hello!(hi hi); | ^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:17:12 | -LL | hello!(hi hi); //~ ERROR hello to you, too! +LL | hello!(hi hi); | ^^ ^^ error: hello to you, too! --> $DIR/multispan.rs:20:5 | -LL | hello!(hi hi hi); //~ ERROR hello to you, too! +LL | hello!(hi hi hi); | ^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:20:12 | -LL | hello!(hi hi hi); //~ ERROR hello to you, too! +LL | hello!(hi hi hi); | ^^ ^^ ^^ error: hello to you, too! --> $DIR/multispan.rs:23:5 | -LL | hello!(hi hey hi yo hi beep beep hi hi); //~ ERROR hello to you, too! +LL | hello!(hi hey hi yo hi beep beep hi hi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:23:12 | -LL | hello!(hi hey hi yo hi beep beep hi hi); //~ ERROR hello to you, too! +LL | hello!(hi hey hi yo hi beep beep hi hi); | ^^ ^^ ^^ ^^ ^^ error: hello to you, too! --> $DIR/multispan.rs:24:5 | -LL | hello!(hi there, hi how are you? hi... hi.); //~ ERROR hello to you, too! +LL | hello!(hi there, hi how are you? hi... hi.); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:24:12 | -LL | hello!(hi there, hi how are you? hi... hi.); //~ ERROR hello to you, too! +LL | hello!(hi there, hi how are you? hi... hi.); | ^^ ^^ ^^ ^^ error: hello to you, too! --> $DIR/multispan.rs:25:5 | -LL | hello!(whoah. hi di hi di ho); //~ ERROR hello to you, too! +LL | hello!(whoah. hi di hi di ho); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:25:19 | -LL | hello!(whoah. hi di hi di ho); //~ ERROR hello to you, too! +LL | hello!(whoah. hi di hi di ho); | ^^ ^^ error: hello to you, too! --> $DIR/multispan.rs:26:5 | -LL | hello!(hi good hi and good bye); //~ ERROR hello to you, too! +LL | hello!(hi good hi and good bye); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:26:12 | -LL | hello!(hi good hi and good bye); //~ ERROR hello to you, too! +LL | hello!(hi good hi and good bye); | ^^ ^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/proc-macro/nested-item-spans.rs b/src/test/ui/proc-macro/nested-item-spans.rs index e365b74b3be8f..63da170d0bbb2 100644 --- a/src/test/ui/proc-macro/nested-item-spans.rs +++ b/src/test/ui/proc-macro/nested-item-spans.rs @@ -1,10 +1,9 @@ -// aux-build:nested-item-spans.rs +// aux-build:test-macros.rs -extern crate nested_item_spans; +#[macro_use] +extern crate test_macros; -use nested_item_spans::foo; - -#[foo] +#[recollect_attr] fn another() { fn bar() { let x: u32 = "x"; //~ ERROR: mismatched types @@ -14,7 +13,7 @@ fn another() { } fn main() { - #[foo] + #[recollect_attr] fn bar() { let x: u32 = "x"; //~ ERROR: mismatched types } diff --git a/src/test/ui/proc-macro/nested-item-spans.stderr b/src/test/ui/proc-macro/nested-item-spans.stderr index cba4b73486c13..bef80311f38e5 100644 --- a/src/test/ui/proc-macro/nested-item-spans.stderr +++ b/src/test/ui/proc-macro/nested-item-spans.stderr @@ -1,16 +1,16 @@ error[E0308]: mismatched types - --> $DIR/nested-item-spans.rs:10:22 + --> $DIR/nested-item-spans.rs:9:22 | -LL | let x: u32 = "x"; //~ ERROR: mismatched types +LL | let x: u32 = "x"; | ^^^ expected u32, found reference | = note: expected type `u32` found type `&'static str` error[E0308]: mismatched types - --> $DIR/nested-item-spans.rs:19:22 + --> $DIR/nested-item-spans.rs:18:22 | -LL | let x: u32 = "x"; //~ ERROR: mismatched types +LL | let x: u32 = "x"; | ^^^ expected u32, found reference | = note: expected type `u32` diff --git a/src/test/ui/proc-macro/no-macro-use-attr.rs b/src/test/ui/proc-macro/no-macro-use-attr.rs index 62a501ded1006..15ab431fe754a 100644 --- a/src/test/ui/proc-macro/no-macro-use-attr.rs +++ b/src/test/ui/proc-macro/no-macro-use-attr.rs @@ -1,9 +1,9 @@ -// aux-build:derive-a.rs +// aux-build:test-macros.rs #![feature(rustc_attrs)] #![warn(unused_extern_crates)] -extern crate derive_a; +extern crate test_macros; //~^ WARN unused extern crate #[rustc_error] diff --git a/src/test/ui/proc-macro/no-macro-use-attr.stderr b/src/test/ui/proc-macro/no-macro-use-attr.stderr index fe5107e17cb95..87487bcc7d662 100644 --- a/src/test/ui/proc-macro/no-macro-use-attr.stderr +++ b/src/test/ui/proc-macro/no-macro-use-attr.stderr @@ -1,8 +1,8 @@ warning: unused extern crate --> $DIR/no-macro-use-attr.rs:6:1 | -LL | extern crate derive_a; - | ^^^^^^^^^^^^^^^^^^^^^^ help: remove it +LL | extern crate test_macros; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it | note: lint level defined here --> $DIR/no-macro-use-attr.rs:4:9 @@ -13,7 +13,7 @@ LL | #![warn(unused_extern_crates)] error: compilation successful --> $DIR/no-macro-use-attr.rs:10:1 | -LL | fn main() {} //~ ERROR compilation successful +LL | fn main() {} | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/proc-macro/no-missing-docs.rs b/src/test/ui/proc-macro/no-missing-docs.rs new file mode 100644 index 0000000000000..e5a5f8beb4585 --- /dev/null +++ b/src/test/ui/proc-macro/no-missing-docs.rs @@ -0,0 +1,16 @@ +//! Verify that the `decls` module implicitly added by the compiler does not cause `missing_docs` +//! warnings. + +// compile-pass +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![deny(missing_docs)] + +extern crate proc_macro; +use proc_macro::*; + +/// Foo1. +#[proc_macro] +pub fn foo1(input: TokenStream) -> TokenStream { input } diff --git a/src/test/ui/proc-macro/proc-macro-attributes.stderr b/src/test/ui/proc-macro/proc-macro-attributes.stderr index a5ec787ac67e6..5117c7e155952 100644 --- a/src/test/ui/proc-macro/proc-macro-attributes.stderr +++ b/src/test/ui/proc-macro/proc-macro-attributes.stderr @@ -1,15 +1,16 @@ -error[E0658]: The attribute `C` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `C` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/proc-macro-attributes.rs:7:3 | -LL | #[C] //~ ERROR attribute `C` is currently unknown to the compiler +LL | #[C] | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0659]: `B` is ambiguous (derive helper attribute vs any other name) --> $DIR/proc-macro-attributes.rs:6:3 | -LL | #[B] //~ ERROR `B` is ambiguous +LL | #[B] | ^ ambiguous name | note: `B` could refer to the derive helper attribute defined here @@ -26,7 +27,7 @@ LL | #[macro_use] error[E0659]: `B` is ambiguous (derive helper attribute vs any other name) --> $DIR/proc-macro-attributes.rs:8:3 | -LL | #[B(D)] //~ ERROR `B` is ambiguous +LL | #[B(D)] | ^ ambiguous name | note: `B` could refer to the derive helper attribute defined here @@ -43,7 +44,7 @@ LL | #[macro_use] error[E0659]: `B` is ambiguous (derive helper attribute vs any other name) --> $DIR/proc-macro-attributes.rs:9:3 | -LL | #[B(E = "foo")] //~ ERROR `B` is ambiguous +LL | #[B(E = "foo")] | ^ ambiguous name | note: `B` could refer to the derive helper attribute defined here @@ -60,7 +61,7 @@ LL | #[macro_use] error[E0659]: `B` is ambiguous (derive helper attribute vs any other name) --> $DIR/proc-macro-attributes.rs:10:3 | -LL | #[B(arbitrary tokens)] //~ ERROR `B` is ambiguous +LL | #[B(arbitrary tokens)] | ^ ambiguous name | note: `B` could refer to the derive helper attribute defined here @@ -76,5 +77,5 @@ LL | #[macro_use] error: aborting due to 5 previous errors -Some errors occurred: E0658, E0659. +Some errors have detailed explanations: E0658, E0659. For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/proc-macro/proc-macro-gates.rs b/src/test/ui/proc-macro/proc-macro-gates.rs index af6bfa08aaa94..678dc83b753b5 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.rs +++ b/src/test/ui/proc-macro/proc-macro-gates.rs @@ -1,61 +1,62 @@ -// aux-build:proc-macro-gates.rs +// aux-build:test-macros.rs // gate-test-proc_macro_hygiene #![feature(stmt_expr_attributes)] -extern crate proc_macro_gates as foo; - -use foo::*; +#[macro_use] +extern crate test_macros; fn _test_inner() { - #![a] //~ ERROR: non-builtin inner attributes are unstable + #![empty_attr] //~ ERROR: non-builtin inner attributes are unstable } -#[a] //~ ERROR: custom attributes cannot be applied to modules +#[empty_attr] //~ ERROR: custom attributes cannot be applied to modules mod _test2 {} mod _test2_inner { - #![a] //~ ERROR: custom attributes cannot be applied to modules + #![empty_attr] //~ ERROR: custom attributes cannot be applied to modules //~| ERROR: non-builtin inner attributes are unstable } -#[a = "y"] //~ ERROR: must only be followed by a delimiter token +#[empty_attr = "y"] //~ ERROR: must only be followed by a delimiter token fn _test3() {} fn attrs() { // Statement, item - #[a] // OK + #[empty_attr] // OK struct S; // Statement, macro - #[a] //~ ERROR: custom attributes cannot be applied to statements + #[empty_attr] //~ ERROR: custom attributes cannot be applied to statements println!(); // Statement, semi - #[a] //~ ERROR: custom attributes cannot be applied to statements + #[empty_attr] //~ ERROR: custom attributes cannot be applied to statements S; // Statement, local - #[a] //~ ERROR: custom attributes cannot be applied to statements + #[empty_attr] //~ ERROR: custom attributes cannot be applied to statements let _x = 2; // Expr - let _x = #[a] 2; //~ ERROR: custom attributes cannot be applied to expressions + let _x = #[identity_attr] 2; //~ ERROR: custom attributes cannot be applied to expressions // Opt expr - let _x = [#[a] 2]; //~ ERROR: custom attributes cannot be applied to expressions + let _x = [#[identity_attr] 2]; //~ ERROR: custom attributes cannot be applied to expressions // Expr macro - let _x = #[a] println!(); //~ ERROR: custom attributes cannot be applied to expressions + let _x = #[identity_attr] println!(); + //~^ ERROR: custom attributes cannot be applied to expressions } fn main() { - let _x: m!(u32) = 3; //~ ERROR: procedural macros cannot be expanded to types - if let m!(Some(_x)) = Some(3) {} //~ ERROR: procedural macros cannot be expanded to patterns + let _x: identity!(u32) = 3; //~ ERROR: procedural macros cannot be expanded to types + if let identity!(Some(_x)) = Some(3) {} + //~^ ERROR: procedural macros cannot be expanded to patterns - m!(struct S;); //~ ERROR: procedural macros cannot be expanded to statements - m!(let _x = 3;); //~ ERROR: procedural macros cannot be expanded to statements + empty!(struct S;); //~ ERROR: procedural macros cannot be expanded to statements + empty!(let _x = 3;); //~ ERROR: procedural macros cannot be expanded to statements - let _x = m!(3); //~ ERROR: procedural macros cannot be expanded to expressions - let _x = [m!(3)]; //~ ERROR: procedural macros cannot be expanded to expressions + let _x = identity!(3); //~ ERROR: procedural macros cannot be expanded to expressions + let _x = [empty!(3)]; //~ ERROR: procedural macros cannot be expanded to expressions } diff --git a/src/test/ui/proc-macro/proc-macro-gates.stderr b/src/test/ui/proc-macro/proc-macro-gates.stderr index abfcf09bfaf6c..f53ad222a0368 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.stderr +++ b/src/test/ui/proc-macro/proc-macro-gates.stderr @@ -1,135 +1,151 @@ -error[E0658]: non-builtin inner attributes are unstable (see issue #54726) - --> $DIR/proc-macro-gates.rs:11:5 +error[E0658]: non-builtin inner attributes are unstable + --> $DIR/proc-macro-gates.rs:10:5 | -LL | #![a] //~ ERROR: non-builtin inner attributes are unstable - | ^^^^^ +LL | #![empty_attr] + | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54726 = help: add #![feature(custom_inner_attributes)] to the crate attributes to enable -error[E0658]: non-builtin inner attributes are unstable (see issue #54726) - --> $DIR/proc-macro-gates.rs:18:5 +error[E0658]: non-builtin inner attributes are unstable + --> $DIR/proc-macro-gates.rs:17:5 | -LL | #![a] //~ ERROR: custom attributes cannot be applied to modules - | ^^^^^ +LL | #![empty_attr] + | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54726 = help: add #![feature(custom_inner_attributes)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to modules (see issue #54727) - --> $DIR/proc-macro-gates.rs:14:1 +error[E0658]: custom attributes cannot be applied to modules + --> $DIR/proc-macro-gates.rs:13:1 | -LL | #[a] //~ ERROR: custom attributes cannot be applied to modules - | ^^^^ +LL | #[empty_attr] + | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to modules (see issue #54727) - --> $DIR/proc-macro-gates.rs:18:5 +error[E0658]: custom attributes cannot be applied to modules + --> $DIR/proc-macro-gates.rs:17:5 | -LL | #![a] //~ ERROR: custom attributes cannot be applied to modules - | ^^^^^ +LL | #![empty_attr] + | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable error: custom attribute invocations must be of the form #[foo] or #[foo(..)], the macro name must only be followed by a delimiter token - --> $DIR/proc-macro-gates.rs:22:1 + --> $DIR/proc-macro-gates.rs:21:1 | -LL | #[a = "y"] //~ ERROR: must only be followed by a delimiter token - | ^^^^^^^^^^ +LL | #[empty_attr = "y"] + | ^^^^^^^^^^^^^^^^^^^ -error[E0658]: custom attributes cannot be applied to statements (see issue #54727) - --> $DIR/proc-macro-gates.rs:31:5 +error[E0658]: custom attributes cannot be applied to statements + --> $DIR/proc-macro-gates.rs:30:5 | -LL | #[a] //~ ERROR: custom attributes cannot be applied to statements - | ^^^^ +LL | #[empty_attr] + | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to statements (see issue #54727) - --> $DIR/proc-macro-gates.rs:35:5 +error[E0658]: custom attributes cannot be applied to statements + --> $DIR/proc-macro-gates.rs:34:5 | -LL | #[a] //~ ERROR: custom attributes cannot be applied to statements - | ^^^^ +LL | #[empty_attr] + | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to statements (see issue #54727) - --> $DIR/proc-macro-gates.rs:39:5 +error[E0658]: custom attributes cannot be applied to statements + --> $DIR/proc-macro-gates.rs:38:5 | -LL | #[a] //~ ERROR: custom attributes cannot be applied to statements - | ^^^^ +LL | #[empty_attr] + | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to expressions (see issue #54727) - --> $DIR/proc-macro-gates.rs:43:14 +error[E0658]: custom attributes cannot be applied to expressions + --> $DIR/proc-macro-gates.rs:42:14 | -LL | let _x = #[a] 2; //~ ERROR: custom attributes cannot be applied to expressions - | ^^^^ +LL | let _x = #[identity_attr] 2; + | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to expressions (see issue #54727) - --> $DIR/proc-macro-gates.rs:46:15 +error[E0658]: custom attributes cannot be applied to expressions + --> $DIR/proc-macro-gates.rs:45:15 | -LL | let _x = [#[a] 2]; //~ ERROR: custom attributes cannot be applied to expressions - | ^^^^ +LL | let _x = [#[identity_attr] 2]; + | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to expressions (see issue #54727) - --> $DIR/proc-macro-gates.rs:49:14 +error[E0658]: custom attributes cannot be applied to expressions + --> $DIR/proc-macro-gates.rs:48:14 | -LL | let _x = #[a] println!(); //~ ERROR: custom attributes cannot be applied to expressions - | ^^^^ +LL | let _x = #[identity_attr] println!(); + | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to types (see issue #54727) +error[E0658]: procedural macros cannot be expanded to types --> $DIR/proc-macro-gates.rs:53:13 | -LL | let _x: m!(u32) = 3; //~ ERROR: procedural macros cannot be expanded to types - | ^^^^^^^ +LL | let _x: identity!(u32) = 3; + | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to patterns (see issue #54727) +error[E0658]: procedural macros cannot be expanded to patterns --> $DIR/proc-macro-gates.rs:54:12 | -LL | if let m!(Some(_x)) = Some(3) {} //~ ERROR: procedural macros cannot be expanded to patterns - | ^^^^^^^^^^^^ +LL | if let identity!(Some(_x)) = Some(3) {} + | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to statements (see issue #54727) - --> $DIR/proc-macro-gates.rs:56:5 +error[E0658]: procedural macros cannot be expanded to statements + --> $DIR/proc-macro-gates.rs:57:5 | -LL | m!(struct S;); //~ ERROR: procedural macros cannot be expanded to statements - | ^^^^^^^^^^^^^^ +LL | empty!(struct S;); + | ^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to statements (see issue #54727) - --> $DIR/proc-macro-gates.rs:57:5 +error[E0658]: procedural macros cannot be expanded to statements + --> $DIR/proc-macro-gates.rs:58:5 | -LL | m!(let _x = 3;); //~ ERROR: procedural macros cannot be expanded to statements - | ^^^^^^^^^^^^^^^^ +LL | empty!(let _x = 3;); + | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to expressions (see issue #54727) - --> $DIR/proc-macro-gates.rs:59:14 +error[E0658]: procedural macros cannot be expanded to expressions + --> $DIR/proc-macro-gates.rs:60:14 | -LL | let _x = m!(3); //~ ERROR: procedural macros cannot be expanded to expressions - | ^^^^^ +LL | let _x = identity!(3); + | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to expressions (see issue #54727) - --> $DIR/proc-macro-gates.rs:60:15 +error[E0658]: procedural macros cannot be expanded to expressions + --> $DIR/proc-macro-gates.rs:61:15 | -LL | let _x = [m!(3)]; //~ ERROR: procedural macros cannot be expanded to expressions - | ^^^^^ +LL | let _x = [empty!(3)]; + | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable error: aborting due to 17 previous errors diff --git a/src/test/ui/proc-macro/proc-macro-gates2.rs b/src/test/ui/proc-macro/proc-macro-gates2.rs index 46b543a397cc7..35d7fc8042a3d 100644 --- a/src/test/ui/proc-macro/proc-macro-gates2.rs +++ b/src/test/ui/proc-macro/proc-macro-gates2.rs @@ -1,21 +1,20 @@ -// aux-build:proc-macro-gates.rs +// aux-build:test-macros.rs #![feature(stmt_expr_attributes)] -extern crate proc_macro_gates as foo; - -use foo::*; +#[macro_use] +extern crate test_macros; // NB. these errors aren't the best errors right now, but they're definitely // intended to be errors. Somehow using a custom attribute in these positions // should either require a feature gate or not be allowed on stable. -fn _test6<#[a] T>() {} +fn _test6<#[empty_attr] T>() {} //~^ ERROR: unknown to the compiler fn _test7() { match 1 { - #[a] //~ ERROR: unknown to the compiler + #[empty_attr] //~ ERROR: unknown to the compiler 0 => {} _ => {} } diff --git a/src/test/ui/proc-macro/proc-macro-gates2.stderr b/src/test/ui/proc-macro/proc-macro-gates2.stderr index 262482aea3457..8eeca99ab3984 100644 --- a/src/test/ui/proc-macro/proc-macro-gates2.stderr +++ b/src/test/ui/proc-macro/proc-macro-gates2.stderr @@ -1,17 +1,19 @@ -error[E0658]: The attribute `a` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/proc-macro-gates2.rs:13:11 +error[E0658]: The attribute `empty_attr` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/proc-macro-gates2.rs:12:11 | -LL | fn _test6<#[a] T>() {} - | ^^^^ +LL | fn _test6<#[empty_attr] T>() {} + | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `a` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/proc-macro-gates2.rs:18:9 +error[E0658]: The attribute `empty_attr` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/proc-macro-gates2.rs:17:9 | -LL | #[a] //~ ERROR: unknown to the compiler - | ^^^^ +LL | #[empty_attr] + | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/proc-macro/pub-at-crate-root.stderr b/src/test/ui/proc-macro/pub-at-crate-root.stderr index 47be1c44d2d8c..66fa499d33bb2 100644 --- a/src/test/ui/proc-macro/pub-at-crate-root.stderr +++ b/src/test/ui/proc-macro/pub-at-crate-root.stderr @@ -1,7 +1,7 @@ error: `proc-macro` crate types cannot export any items other than functions tagged with `#[proc_macro_derive]` currently --> $DIR/pub-at-crate-root.rs:8:1 | -LL | / pub mod a { //~ `proc-macro` crate types cannot export any items +LL | / pub mod a { LL | | use proc_macro::TokenStream; LL | | LL | | #[proc_macro_derive(B)] @@ -14,7 +14,7 @@ error: functions tagged with `#[proc_macro_derive]` must currently reside in the --> $DIR/pub-at-crate-root.rs:12:5 | LL | / pub fn bar(a: TokenStream) -> TokenStream { -LL | | //~^ ERROR: must currently reside in the root of the crate +LL | | LL | | a LL | | } | |_____^ @@ -23,7 +23,7 @@ error: functions tagged with `#[proc_macro_derive]` must be `pub` --> $DIR/pub-at-crate-root.rs:19:1 | LL | / fn bar(a: proc_macro::TokenStream) -> proc_macro::TokenStream { -LL | | //~^ ERROR: functions tagged with `#[proc_macro_derive]` must be `pub` +LL | | LL | | a LL | | } | |_^ diff --git a/src/test/ui/proc-macro/resolve-error.rs b/src/test/ui/proc-macro/resolve-error.rs index bb242f302496e..1298c08df846d 100644 --- a/src/test/ui/proc-macro/resolve-error.rs +++ b/src/test/ui/proc-macro/resolve-error.rs @@ -1,19 +1,15 @@ // aux-build:derive-foo.rs // aux-build:derive-clona.rs -// aux-build:attr_proc_macro.rs -// aux-build:bang_proc_macro.rs - -#![feature(custom_attribute)] +// aux-build:test-macros.rs #[macro_use] extern crate derive_foo; #[macro_use] extern crate derive_clona; -extern crate attr_proc_macro; -extern crate bang_proc_macro; +extern crate test_macros; -use attr_proc_macro::attr_proc_macro; -use bang_proc_macro::bang_proc_macro; +use test_macros::empty as bang_proc_macro; +use test_macros::empty_attr as attr_proc_macro; macro_rules! FooWithLongNam { () => {} @@ -27,10 +23,12 @@ macro_rules! attr_proc_mac { //~^ ERROR cannot find struct Foo; -#[attr_proc_macra] // OK, interpreted as a custom attribute +// Interpreted as a feature gated custom attribute +#[attr_proc_macra] //~ ERROR attribute `attr_proc_macra` is currently unknown struct Bar; -#[FooWithLongNan] // OK, interpreted as a custom attribute +// Interpreted as a feature gated custom attribute +#[FooWithLongNan] //~ ERROR attribute `FooWithLongNan` is currently unknown struct Asdf; #[derive(Dlone)] diff --git a/src/test/ui/proc-macro/resolve-error.stderr b/src/test/ui/proc-macro/resolve-error.stderr index 1e7fd25d0da42..f9f116c15dcc7 100644 --- a/src/test/ui/proc-macro/resolve-error.stderr +++ b/src/test/ui/proc-macro/resolve-error.stderr @@ -1,50 +1,69 @@ +error[E0658]: The attribute `attr_proc_macra` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/resolve-error.rs:27:3 + | +LL | #[attr_proc_macra] + | ^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `FooWithLongNan` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/resolve-error.rs:31:3 + | +LL | #[FooWithLongNan] + | ^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + error: cannot find derive macro `FooWithLongNan` in this scope - --> $DIR/resolve-error.rs:26:10 + --> $DIR/resolve-error.rs:22:10 | LL | #[derive(FooWithLongNan)] | ^^^^^^^^^^^^^^ help: try: `FooWithLongName` error: cannot find derive macro `Dlone` in this scope - --> $DIR/resolve-error.rs:36:10 + --> $DIR/resolve-error.rs:34:10 | LL | #[derive(Dlone)] | ^^^^^ help: try: `Clone` error: cannot find derive macro `Dlona` in this scope - --> $DIR/resolve-error.rs:40:10 + --> $DIR/resolve-error.rs:38:10 | LL | #[derive(Dlona)] | ^^^^^ help: try: `Clona` error: cannot find derive macro `attr_proc_macra` in this scope - --> $DIR/resolve-error.rs:44:10 + --> $DIR/resolve-error.rs:42:10 | LL | #[derive(attr_proc_macra)] - | ^^^^^^^^^^^^^^^ help: try: `attr_proc_macro` + | ^^^^^^^^^^^^^^^ error: cannot find macro `FooWithLongNama!` in this scope - --> $DIR/resolve-error.rs:49:5 + --> $DIR/resolve-error.rs:47:5 | LL | FooWithLongNama!(); | ^^^^^^^^^^^^^^^ help: you could try the macro: `FooWithLongNam` error: cannot find macro `attr_proc_macra!` in this scope - --> $DIR/resolve-error.rs:52:5 + --> $DIR/resolve-error.rs:50:5 | LL | attr_proc_macra!(); | ^^^^^^^^^^^^^^^ help: you could try the macro: `attr_proc_mac` error: cannot find macro `Dlona!` in this scope - --> $DIR/resolve-error.rs:55:5 + --> $DIR/resolve-error.rs:53:5 | LL | Dlona!(); | ^^^^^ error: cannot find macro `bang_proc_macrp!` in this scope - --> $DIR/resolve-error.rs:58:5 + --> $DIR/resolve-error.rs:56:5 | LL | bang_proc_macrp!(); | ^^^^^^^^^^^^^^^ help: you could try the macro: `bang_proc_macro` -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/proc-macro/shadow-builtin.rs b/src/test/ui/proc-macro/shadow-builtin.rs deleted file mode 100644 index afcc0ebc3464c..0000000000000 --- a/src/test/ui/proc-macro/shadow-builtin.rs +++ /dev/null @@ -1,14 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::TokenStream; - -#[proc_macro_derive(PartialEq)] -//~^ ERROR: cannot override a built-in #[derive] mode -pub fn foo(input: TokenStream) -> TokenStream { - input -} diff --git a/src/test/ui/proc-macro/shadow-builtin.stderr b/src/test/ui/proc-macro/shadow-builtin.stderr deleted file mode 100644 index 668579509dc3b..0000000000000 --- a/src/test/ui/proc-macro/shadow-builtin.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: cannot override a built-in #[derive] mode - --> $DIR/shadow-builtin.rs:10:21 - | -LL | #[proc_macro_derive(PartialEq)] - | ^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/proc-macro/shadow.rs b/src/test/ui/proc-macro/shadow.rs index 9c49bae28a3bc..61959594c7981 100644 --- a/src/test/ui/proc-macro/shadow.rs +++ b/src/test/ui/proc-macro/shadow.rs @@ -1,8 +1,8 @@ -// aux-build:derive-a.rs +// aux-build:test-macros.rs #[macro_use] -extern crate derive_a; +extern crate test_macros; #[macro_use] -extern crate derive_a; //~ ERROR the name `derive_a` is defined multiple times +extern crate test_macros; //~ ERROR the name `test_macros` is defined multiple times fn main() {} diff --git a/src/test/ui/proc-macro/shadow.stderr b/src/test/ui/proc-macro/shadow.stderr index 2dfe2a94c88e1..e7d95cc835811 100644 --- a/src/test/ui/proc-macro/shadow.stderr +++ b/src/test/ui/proc-macro/shadow.stderr @@ -1,16 +1,13 @@ -error[E0259]: the name `derive_a` is defined multiple times +error[E0259]: the name `test_macros` is defined multiple times --> $DIR/shadow.rs:6:1 | -LL | extern crate derive_a; - | ---------------------- previous import of the extern crate `derive_a` here -LL | / #[macro_use] -LL | | extern crate derive_a; //~ ERROR the name `derive_a` is defined multiple times - | | ^^^^^^^^^^^^^^^^^^^^^- - | |_|____________________| - | | help: remove unnecessary import - | `derive_a` reimported here +LL | extern crate test_macros; + | ------------------------- previous import of the extern crate `test_macros` here +LL | #[macro_use] +LL | extern crate test_macros; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `test_macros` reimported here | - = note: `derive_a` must be defined only once in the type namespace of this module + = note: `test_macros` must be defined only once in the type namespace of this module error: aborting due to previous error diff --git a/src/test/ui/proc-macro/signature.stderr b/src/test/ui/proc-macro/signature.stderr index 99cb3316533a1..4743e3031a34c 100644 --- a/src/test/ui/proc-macro/signature.stderr +++ b/src/test/ui/proc-macro/signature.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/signature.rs:10:1 | LL | / pub unsafe extern fn foo(a: i32, b: u32) -> u32 { -LL | | //~^ ERROR: mismatched types +LL | | LL | | loop {} LL | | } | |_^ expected normal fn, found unsafe fn diff --git a/src/test/ui/proc-macro/span-preservation.rs b/src/test/ui/proc-macro/span-preservation.rs index 64f675ecc1c4d..0a82d28e9e544 100644 --- a/src/test/ui/proc-macro/span-preservation.rs +++ b/src/test/ui/proc-macro/span-preservation.rs @@ -1,19 +1,18 @@ //~ ERROR mismatched types -// aux-build:span-preservation.rs +// aux-build:test-macros.rs // For each of these, we should get the appropriate type mismatch error message, // and the function should be echoed. -extern crate span_preservation as foo; +#[macro_use] +extern crate test_macros; -use foo::foo; - -#[foo] +#[recollect_attr] fn a() { let x: usize = "hello";;;;; //~ ERROR mismatched types } -#[foo] +#[recollect_attr] fn b(x: Option) -> usize { match x { Some(x) => { return x }, //~ ERROR mismatched types @@ -21,7 +20,7 @@ fn b(x: Option) -> usize { } } -#[foo] +#[recollect_attr] fn c() { struct Foo { a: usize @@ -39,12 +38,12 @@ fn c() { // FIXME: This doesn't work at the moment. See the one below. The pretty-printer // injects a "C" between `extern` and `fn` which causes a "probably_eq" // `TokenStream` mismatch. The lack of `"C"` should be preserved in the AST. -#[foo] +#[recollect_attr] extern fn bar() { 0 } -#[foo] +#[recollect_attr] extern "C" fn baz() { 0 //~ ERROR mismatched types } diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr index db524907b656f..cf03deee7e445 100644 --- a/src/test/ui/proc-macro/span-preservation.stderr +++ b/src/test/ui/proc-macro/span-preservation.stderr @@ -4,43 +4,43 @@ error[E0308]: mismatched types found type `{integer}` error[E0308]: mismatched types - --> $DIR/span-preservation.rs:13:20 + --> $DIR/span-preservation.rs:12:20 | -LL | let x: usize = "hello";;;;; //~ ERROR mismatched types +LL | let x: usize = "hello";;;;; | ^^^^^^^ expected usize, found reference | = note: expected type `usize` found type `&'static str` error[E0308]: mismatched types - --> $DIR/span-preservation.rs:19:29 + --> $DIR/span-preservation.rs:18:29 | LL | fn b(x: Option) -> usize { | ----- expected `usize` because of return type LL | match x { -LL | Some(x) => { return x }, //~ ERROR mismatched types +LL | Some(x) => { return x }, | ^ expected usize, found isize error[E0308]: mismatched types - --> $DIR/span-preservation.rs:35:22 + --> $DIR/span-preservation.rs:34:22 | -LL | let x = Foo { a: 10isize }; //~ ERROR mismatched types +LL | let x = Foo { a: 10isize }; | ^^^^^^^ expected usize, found isize error[E0560]: struct `c::Foo` has no field named `b` - --> $DIR/span-preservation.rs:36:26 + --> $DIR/span-preservation.rs:35:26 | -LL | let y = Foo { a: 10, b: 10isize }; //~ ERROR has no field named `b` +LL | let y = Foo { a: 10, b: 10isize }; | ^ `c::Foo` does not have this field | = note: available fields are: `a` error[E0308]: mismatched types - --> $DIR/span-preservation.rs:49:5 + --> $DIR/span-preservation.rs:48:5 | LL | extern "C" fn baz() { | - possibly return type missing here? -LL | 0 //~ ERROR mismatched types +LL | 0 | ^ expected (), found integer | = note: expected type `()` @@ -48,5 +48,5 @@ LL | 0 //~ ERROR mismatched types error: aborting due to 6 previous errors -Some errors occurred: E0308, E0560. +Some errors have detailed explanations: E0308, E0560. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/proc-macro/subspan.stderr b/src/test/ui/proc-macro/subspan.stderr index 94f1be6021faa..5117dd6d32d49 100644 --- a/src/test/ui/proc-macro/subspan.stderr +++ b/src/test/ui/proc-macro/subspan.stderr @@ -1,97 +1,97 @@ error: found 'hi's --> $DIR/subspan.rs:11:1 | -LL | subspan!("hi"); //~ ERROR found 'hi's +LL | subspan!("hi"); | ^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:11:11 | -LL | subspan!("hi"); //~ ERROR found 'hi's +LL | subspan!("hi"); | ^^ error: found 'hi's --> $DIR/subspan.rs:14:1 | -LL | subspan!("hihi"); //~ ERROR found 'hi's +LL | subspan!("hihi"); | ^^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:14:11 | -LL | subspan!("hihi"); //~ ERROR found 'hi's +LL | subspan!("hihi"); | ^^^^ error: found 'hi's --> $DIR/subspan.rs:17:1 | -LL | subspan!("hihihi"); //~ ERROR found 'hi's +LL | subspan!("hihihi"); | ^^^^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:17:11 | -LL | subspan!("hihihi"); //~ ERROR found 'hi's +LL | subspan!("hihihi"); | ^^^^^^ error: found 'hi's --> $DIR/subspan.rs:20:1 | -LL | subspan!("why I hide? hi!"); //~ ERROR found 'hi's +LL | subspan!("why I hide? hi!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:20:17 | -LL | subspan!("why I hide? hi!"); //~ ERROR found 'hi's +LL | subspan!("why I hide? hi!"); | ^^ ^^ error: found 'hi's --> $DIR/subspan.rs:21:1 | -LL | subspan!("hey, hi, hidy, hidy, hi hi"); //~ ERROR found 'hi's +LL | subspan!("hey, hi, hidy, hidy, hi hi"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:21:16 | -LL | subspan!("hey, hi, hidy, hidy, hi hi"); //~ ERROR found 'hi's +LL | subspan!("hey, hi, hidy, hidy, hi hi"); | ^^ ^^ ^^ ^^ ^^ error: found 'hi's --> $DIR/subspan.rs:22:1 | -LL | subspan!("this is a hi, and this is another hi"); //~ ERROR found 'hi's +LL | subspan!("this is a hi, and this is another hi"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:22:12 | -LL | subspan!("this is a hi, and this is another hi"); //~ ERROR found 'hi's +LL | subspan!("this is a hi, and this is another hi"); | ^^ ^^ ^^ ^^ error: found 'hi's --> $DIR/subspan.rs:23:1 | -LL | subspan!("how are you this evening"); //~ ERROR found 'hi's +LL | subspan!("how are you this evening"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:23:24 | -LL | subspan!("how are you this evening"); //~ ERROR found 'hi's +LL | subspan!("how are you this evening"); | ^^ error: found 'hi's --> $DIR/subspan.rs:24:1 | -LL | subspan!("this is highly eradic"); //~ ERROR found 'hi's +LL | subspan!("this is highly eradic"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:24:12 | -LL | subspan!("this is highly eradic"); //~ ERROR found 'hi's +LL | subspan!("this is highly eradic"); | ^^ ^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/proc-macro/three-equals.stderr b/src/test/ui/proc-macro/three-equals.stderr index e38343348dd94..f8dfa841d4f3b 100644 --- a/src/test/ui/proc-macro/three-equals.stderr +++ b/src/test/ui/proc-macro/three-equals.stderr @@ -1,7 +1,7 @@ error: found 2 equal signs, need exactly 3 --> $DIR/three-equals.rs:15:5 | -LL | three_equals!(==); //~ ERROR found 2 equal signs, need exactly 3 +LL | three_equals!(==); | ^^^^^^^^^^^^^^^^^^ | = help: input must be: `===` @@ -9,38 +9,38 @@ LL | three_equals!(==); //~ ERROR found 2 equal signs, need exactly 3 error: expected EOF, found `=`. --> $DIR/three-equals.rs:18:21 | -LL | three_equals!(=====); //~ ERROR expected EOF +LL | three_equals!(=====); | ^^ | note: last good input was here --> $DIR/three-equals.rs:18:21 | -LL | three_equals!(=====); //~ ERROR expected EOF +LL | three_equals!(=====); | ^^ = help: input must be: `===` error: expected `=`, found `abc`. --> $DIR/three-equals.rs:21:19 | -LL | three_equals!(abc); //~ ERROR expected `=` +LL | three_equals!(abc); | ^^^ error: expected `=`, found `!`. --> $DIR/three-equals.rs:24:19 | -LL | three_equals!(!!); //~ ERROR expected `=` +LL | three_equals!(!!); | ^ error: expected EOF, found `a`. --> $DIR/three-equals.rs:27:22 | -LL | three_equals!(===a); //~ ERROR expected EOF +LL | three_equals!(===a); | ^ | note: last good input was here --> $DIR/three-equals.rs:27:21 | -LL | three_equals!(===a); //~ ERROR expected EOF +LL | three_equals!(===a); | ^ = help: input must be: `===` diff --git a/src/test/ui/ptr-coercion.stderr b/src/test/ui/ptr-coercion.stderr index 2499e90db7d91..019241d6874aa 100644 --- a/src/test/ui/ptr-coercion.stderr +++ b/src/test/ui/ptr-coercion.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/ptr-coercion.rs:7:25 | -LL | let x: *mut isize = x; //~ ERROR mismatched types +LL | let x: *mut isize = x; | ^ types differ in mutability | = note: expected type `*mut isize` @@ -10,7 +10,7 @@ LL | let x: *mut isize = x; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/ptr-coercion.rs:13:25 | -LL | let x: *mut isize = &42; //~ ERROR mismatched types +LL | let x: *mut isize = &42; | ^^^ types differ in mutability | = note: expected type `*mut isize` @@ -19,7 +19,7 @@ LL | let x: *mut isize = &42; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/ptr-coercion.rs:19:25 | -LL | let x: *mut isize = x; //~ ERROR mismatched types +LL | let x: *mut isize = x; | ^ types differ in mutability | = note: expected type `*mut isize` diff --git a/src/test/ui/pub/pub-ident-fn-3.rs b/src/test/ui/pub/pub-ident-fn-3.rs new file mode 100644 index 0000000000000..fdbea7cf487eb --- /dev/null +++ b/src/test/ui/pub/pub-ident-fn-3.rs @@ -0,0 +1,8 @@ +// #60115 + +mod foo { + pub bar(); + //~^ ERROR missing `fn` or `struct` for function or struct definition +} + +fn main() {} diff --git a/src/test/ui/pub/pub-ident-fn-3.stderr b/src/test/ui/pub/pub-ident-fn-3.stderr new file mode 100644 index 0000000000000..6d3d4e592c8ed --- /dev/null +++ b/src/test/ui/pub/pub-ident-fn-3.stderr @@ -0,0 +1,8 @@ +error: missing `fn` or `struct` for function or struct definition + --> $DIR/pub-ident-fn-3.rs:4:8 + | +LL | pub bar(); + | ---^--- help: if you meant to call a macro, try: `bar!` + +error: aborting due to previous error + diff --git a/src/test/ui/pub/pub-reexport-priv-extern-crate.stderr b/src/test/ui/pub/pub-reexport-priv-extern-crate.stderr index e895d51a848b3..61c148bf2df27 100644 --- a/src/test/ui/pub/pub-reexport-priv-extern-crate.stderr +++ b/src/test/ui/pub/pub-reexport-priv-extern-crate.stderr @@ -1,7 +1,7 @@ error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub` --> $DIR/pub-reexport-priv-extern-crate.rs:4:9 | -LL | pub use core as reexported_core; //~ ERROR `core` is private, and cannot be re-exported +LL | pub use core as reexported_core; | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: #[deny(pub_use_of_private_extern_crate)] on by default @@ -11,7 +11,7 @@ LL | pub use core as reexported_core; //~ ERROR `core` is private, and cannot be error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub` --> $DIR/pub-reexport-priv-extern-crate.rs:12:9 | -LL | use foo1::core; //~ ERROR `core` is private, and cannot be re-exported +LL | use foo1::core; | ^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -20,7 +20,7 @@ LL | use foo1::core; //~ ERROR `core` is private, and cannot be re-exported error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub` --> $DIR/pub-reexport-priv-extern-crate.rs:20:13 | -LL | pub use foo2::bar::core; //~ ERROR `core` is private, and cannot be re-exported +LL | pub use foo2::bar::core; | ^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/src/test/ui/pub/pub-restricted-error-fn.stderr b/src/test/ui/pub/pub-restricted-error-fn.stderr index 86fe1b2186f40..fcff5334890eb 100644 --- a/src/test/ui/pub/pub-restricted-error-fn.stderr +++ b/src/test/ui/pub/pub-restricted-error-fn.stderr @@ -1,7 +1,7 @@ error: unmatched visibility `pub` --> $DIR/pub-restricted-error-fn.rs:3:10 | -LL | pub(crate) () fn foo() {} //~ unmatched visibility +LL | pub(crate) () fn foo() {} | ^ error: aborting due to previous error diff --git a/src/test/ui/pub/pub-restricted-error.stderr b/src/test/ui/pub/pub-restricted-error.stderr index ca720279946f0..d856833d04fb1 100644 --- a/src/test/ui/pub/pub-restricted-error.stderr +++ b/src/test/ui/pub/pub-restricted-error.stderr @@ -1,7 +1,7 @@ error: expected identifier, found `(` --> $DIR/pub-restricted-error.rs:6:16 | -LL | pub(crate) () foo: usize, //~ ERROR expected identifier +LL | pub(crate) () foo: usize, | ^ expected identifier error: aborting due to previous error diff --git a/src/test/ui/pub/pub-restricted-non-path.stderr b/src/test/ui/pub/pub-restricted-non-path.stderr index 526e964f8ee35..e0ea50621f752 100644 --- a/src/test/ui/pub/pub-restricted-non-path.stderr +++ b/src/test/ui/pub/pub-restricted-non-path.stderr @@ -1,7 +1,7 @@ error: expected identifier, found `.` --> $DIR/pub-restricted-non-path.rs:3:6 | -LL | pub (.) fn afn() {} //~ ERROR expected identifier +LL | pub (.) fn afn() {} | ^ expected identifier error: aborting due to previous error diff --git a/src/test/ui/pub/pub-restricted.rs b/src/test/ui/pub/pub-restricted.rs index 8793cb9d3357f..b4bc4a08c7b6d 100644 --- a/src/test/ui/pub/pub-restricted.rs +++ b/src/test/ui/pub/pub-restricted.rs @@ -4,6 +4,8 @@ mod a {} pub (a) fn afn() {} //~ incorrect visibility restriction pub (b) fn bfn() {} //~ incorrect visibility restriction +pub (crate::a) fn cfn() {} //~ incorrect visibility restriction + pub fn privfn() {} mod x { mod y { diff --git a/src/test/ui/pub/pub-restricted.stderr b/src/test/ui/pub/pub-restricted.stderr index 40cf398023b28..596264ba16b42 100644 --- a/src/test/ui/pub/pub-restricted.stderr +++ b/src/test/ui/pub/pub-restricted.stderr @@ -1,7 +1,7 @@ error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:5:6 | -LL | pub (a) fn afn() {} //~ incorrect visibility restriction +LL | pub (a) fn afn() {} | ^ help: make this visible only to module `a` with `in`: `in a` | = help: some possible visibility restrictions are: @@ -12,7 +12,7 @@ LL | pub (a) fn afn() {} //~ incorrect visibility restriction error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:6:6 | -LL | pub (b) fn bfn() {} //~ incorrect visibility restriction +LL | pub (b) fn bfn() {} | ^ help: make this visible only to module `b` with `in`: `in b` | = help: some possible visibility restrictions are: @@ -21,9 +21,20 @@ LL | pub (b) fn bfn() {} //~ incorrect visibility restriction `pub(in path::to::module)`: visible only on the specified path error[E0704]: incorrect visibility restriction - --> $DIR/pub-restricted.rs:22:14 + --> $DIR/pub-restricted.rs:7:6 | -LL | pub (a) invalid: usize, //~ incorrect visibility restriction +LL | pub (crate::a) fn cfn() {} + | ^^^^^^^^ help: make this visible only to module `crate::a` with `in`: `in crate::a` + | + = help: some possible visibility restrictions are: + `pub(crate)`: visible only on the current crate + `pub(super)`: visible only in the current module's parent + `pub(in path::to::module)`: visible only on the specified path + +error[E0704]: incorrect visibility restriction + --> $DIR/pub-restricted.rs:24:14 + | +LL | pub (a) invalid: usize, | ^ help: make this visible only to module `a` with `in`: `in a` | = help: some possible visibility restrictions are: @@ -32,9 +43,9 @@ LL | pub (a) invalid: usize, //~ incorrect visibility restriction `pub(in path::to::module)`: visible only on the specified path error[E0704]: incorrect visibility restriction - --> $DIR/pub-restricted.rs:31:6 + --> $DIR/pub-restricted.rs:33:6 | -LL | pub (xyz) fn xyz() {} //~ incorrect visibility restriction +LL | pub (xyz) fn xyz() {} | ^^^ help: make this visible only to module `xyz` with `in`: `in xyz` | = help: some possible visibility restrictions are: @@ -43,11 +54,11 @@ LL | pub (xyz) fn xyz() {} //~ incorrect visibility restriction `pub(in path::to::module)`: visible only on the specified path error: visibilities can only be restricted to ancestor modules - --> $DIR/pub-restricted.rs:23:17 + --> $DIR/pub-restricted.rs:25:17 | -LL | pub (in x) non_parent_invalid: usize, //~ ERROR visibilities can only be restricted +LL | pub (in x) non_parent_invalid: usize, | ^ -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0704`. diff --git a/src/test/ui/qualified/qualified-path-params-2.rs b/src/test/ui/qualified/qualified-path-params-2.rs index 8412983fda549..ebdd749046239 100644 --- a/src/test/ui/qualified/qualified-path-params-2.rs +++ b/src/test/ui/qualified/qualified-path-params-2.rs @@ -16,7 +16,7 @@ impl S { } type A = ::A::f; -//~^ ERROR type arguments are not allowed on this entity +//~^ ERROR type arguments are not allowed for this type //~| ERROR ambiguous associated type fn main() {} diff --git a/src/test/ui/qualified/qualified-path-params-2.stderr b/src/test/ui/qualified/qualified-path-params-2.stderr index 4e073841b9740..15da5193e8834 100644 --- a/src/test/ui/qualified/qualified-path-params-2.stderr +++ b/src/test/ui/qualified/qualified-path-params-2.stderr @@ -1,4 +1,4 @@ -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/qualified-path-params-2.rs:18:26 | LL | type A = ::A::f; @@ -12,5 +12,5 @@ LL | type A = ::A::f; error: aborting due to 2 previous errors -Some errors occurred: E0109, E0223. +Some errors have detailed explanations: E0109, E0223. For more information about an error, try `rustc --explain E0109`. diff --git a/src/test/ui/qualified/qualified-path-params.stderr b/src/test/ui/qualified/qualified-path-params.stderr index 18fca2e304696..b8d3b744e837c 100644 --- a/src/test/ui/qualified/qualified-path-params.stderr +++ b/src/test/ui/qualified/qualified-path-params.stderr @@ -7,7 +7,7 @@ LL | ::A::f:: => {} error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/qualified-path-params.rs:22:15 | -LL | 0 ..= ::A::f:: => {} //~ ERROR only char and numeric types are allowed in range +LL | 0 ..= ::A::f:: => {} | ^^^^^^^^^^^^^^^^^^^^^ ranges require char or numeric types | = note: start type: {integer} @@ -15,5 +15,4 @@ LL | 0 ..= ::A::f:: => {} //~ ERROR only char and numeric t error: aborting due to 2 previous errors -Some errors occurred: E0029, E0533. -For more information about an error, try `rustc --explain E0029`. +For more information about this error, try `rustc --explain E0029`. diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr index c998bdc086f10..f62a540572c93 100644 --- a/src/test/ui/question-mark-type-infer.stderr +++ b/src/test/ui/question-mark-type-infer.stderr @@ -1,7 +1,7 @@ error[E0284]: type annotations required: cannot resolve `<_ as std::ops::Try>::Ok == _` --> $DIR/question-mark-type-infer.rs:12:5 | -LL | l.iter().map(f).collect()? //~ ERROR type annotations required: cannot resolve +LL | l.iter().map(f).collect()? | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/range/range-1.stderr b/src/test/ui/range/range-1.stderr index 00c0c80515557..bbc2abea51df7 100644 --- a/src/test/ui/range/range-1.stderr +++ b/src/test/ui/range/range-1.stderr @@ -24,5 +24,5 @@ LL | let range = *arr..; error: aborting due to 3 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/range/range_traits-2.rs b/src/test/ui/range/range_traits-2.rs index c34ef781d8c78..234d7a64dc8b0 100644 --- a/src/test/ui/range/range_traits-2.rs +++ b/src/test/ui/range/range_traits-2.rs @@ -4,4 +4,3 @@ use std::ops::*; struct R(Range); fn main() {} - diff --git a/src/test/ui/range/range_traits-2.stderr b/src/test/ui/range/range_traits-2.stderr index f7f887006ed5f..598a0b3ed0374 100644 --- a/src/test/ui/range/range_traits-2.stderr +++ b/src/test/ui/range/range_traits-2.stderr @@ -1,7 +1,7 @@ error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/range_traits-2.rs:3:10 | -LL | #[derive(Copy, Clone)] //~ ERROR Copy +LL | #[derive(Copy, Clone)] | ^^^^ LL | struct R(Range); | ------------ this field does not implement `Copy` diff --git a/src/test/ui/range/range_traits-3.rs b/src/test/ui/range/range_traits-3.rs index b0448afce04ea..2d597cce5ad56 100644 --- a/src/test/ui/range/range_traits-3.rs +++ b/src/test/ui/range/range_traits-3.rs @@ -4,4 +4,3 @@ use std::ops::*; struct R(RangeFrom); fn main() {} - diff --git a/src/test/ui/range/range_traits-3.stderr b/src/test/ui/range/range_traits-3.stderr index 910ba51727675..e2713a2bd5ed8 100644 --- a/src/test/ui/range/range_traits-3.stderr +++ b/src/test/ui/range/range_traits-3.stderr @@ -1,7 +1,7 @@ error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/range_traits-3.rs:3:10 | -LL | #[derive(Copy, Clone)] //~ ERROR Copy +LL | #[derive(Copy, Clone)] | ^^^^ LL | struct R(RangeFrom); | ---------------- this field does not implement `Copy` diff --git a/src/test/ui/range/range_traits-4.rs b/src/test/ui/range/range_traits-4.rs index ff84577048379..52c706080f3c2 100644 --- a/src/test/ui/range/range_traits-4.rs +++ b/src/test/ui/range/range_traits-4.rs @@ -7,4 +7,3 @@ struct R(RangeTo); fn main() {} - diff --git a/src/test/ui/range/range_traits-5.rs b/src/test/ui/range/range_traits-5.rs index 95505c94d1fb7..a8c3e9b0d62c0 100644 --- a/src/test/ui/range/range_traits-5.rs +++ b/src/test/ui/range/range_traits-5.rs @@ -7,4 +7,3 @@ struct R(RangeFull); fn main() {} - diff --git a/src/test/ui/range/range_traits-6.rs b/src/test/ui/range/range_traits-6.rs index 041f04a349876..bce106bbfe79b 100644 --- a/src/test/ui/range/range_traits-6.rs +++ b/src/test/ui/range/range_traits-6.rs @@ -4,4 +4,3 @@ use std::ops::*; struct R(RangeInclusive); fn main() {} - diff --git a/src/test/ui/range/range_traits-6.stderr b/src/test/ui/range/range_traits-6.stderr index c1916e24bfeef..226d72ce0262e 100644 --- a/src/test/ui/range/range_traits-6.stderr +++ b/src/test/ui/range/range_traits-6.stderr @@ -1,7 +1,7 @@ error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/range_traits-6.rs:3:10 | -LL | #[derive(Copy, Clone)] //~ ERROR Copy +LL | #[derive(Copy, Clone)] | ^^^^ LL | struct R(RangeInclusive); | --------------------- this field does not implement `Copy` diff --git a/src/test/ui/range/range_traits-7.rs b/src/test/ui/range/range_traits-7.rs index c328ecb223a28..548676063caf7 100644 --- a/src/test/ui/range/range_traits-7.rs +++ b/src/test/ui/range/range_traits-7.rs @@ -7,4 +7,3 @@ struct R(RangeToInclusive); fn main() {} - diff --git a/src/test/ui/reachable/expr_add.stderr b/src/test/ui/reachable/expr_add.stderr index 548600f26ec8f..02b29021cb61a 100644 --- a/src/test/ui/reachable/expr_add.stderr +++ b/src/test/ui/reachable/expr_add.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/expr_add.rs:17:13 | -LL | let x = Foo + return; //~ ERROR unreachable +LL | let x = Foo + return; | ^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/reachable/expr_array.stderr b/src/test/ui/reachable/expr_array.stderr index b6e79e551cd8e..18d7ffe74bd18 100644 --- a/src/test/ui/reachable/expr_array.stderr +++ b/src/test/ui/reachable/expr_array.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/expr_array.rs:9:34 | -LL | let x: [usize; 2] = [return, 22]; //~ ERROR unreachable +LL | let x: [usize; 2] = [return, 22]; | ^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unreachable_code)] error: unreachable expression --> $DIR/expr_array.rs:14:25 | -LL | let x: [usize; 2] = [22, return]; //~ ERROR unreachable +LL | let x: [usize; 2] = [22, return]; | ^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/reachable/expr_assign.stderr b/src/test/ui/reachable/expr_assign.stderr index 949009b729969..def16d90a7490 100644 --- a/src/test/ui/reachable/expr_assign.stderr +++ b/src/test/ui/reachable/expr_assign.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/expr_assign.rs:10:5 | -LL | x = return; //~ ERROR unreachable +LL | x = return; | ^^^^^^^^^^ | note: lint level defined here @@ -13,13 +13,13 @@ LL | #![deny(unreachable_code)] error: unreachable expression --> $DIR/expr_assign.rs:20:14 | -LL | *p = return; //~ ERROR unreachable +LL | *p = return; | ^^^^^^ error: unreachable expression --> $DIR/expr_assign.rs:26:15 | -LL | *{return; &mut i} = 22; //~ ERROR unreachable +LL | *{return; &mut i} = 22; | ^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/reachable/expr_block.stderr b/src/test/ui/reachable/expr_block.stderr index d71d12b744a64..a498502e6cb1a 100644 --- a/src/test/ui/reachable/expr_block.stderr +++ b/src/test/ui/reachable/expr_block.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/expr_block.rs:10:9 | -LL | 22 //~ ERROR unreachable +LL | 22 | ^^ | note: lint level defined here diff --git a/src/test/ui/reachable/expr_box.stderr b/src/test/ui/reachable/expr_box.stderr index 289cef24bcecb..63137ce3da180 100644 --- a/src/test/ui/reachable/expr_box.stderr +++ b/src/test/ui/reachable/expr_box.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/expr_box.rs:6:13 | -LL | let x = box return; //~ ERROR unreachable +LL | let x = box return; | ^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/reachable/expr_call.stderr b/src/test/ui/reachable/expr_call.stderr index aecaf24adc44b..df5cff16f9a46 100644 --- a/src/test/ui/reachable/expr_call.stderr +++ b/src/test/ui/reachable/expr_call.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/expr_call.rs:13:17 | -LL | foo(return, 22); //~ ERROR unreachable +LL | foo(return, 22); | ^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unreachable_code)] error: unreachable expression --> $DIR/expr_call.rs:18:5 | -LL | bar(return); //~ ERROR unreachable +LL | bar(return); | ^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/reachable/expr_cast.stderr b/src/test/ui/reachable/expr_cast.stderr index 21f8a0f418e5e..3086745d28ed4 100644 --- a/src/test/ui/reachable/expr_cast.stderr +++ b/src/test/ui/reachable/expr_cast.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/expr_cast.rs:9:13 | -LL | let x = {return} as !; //~ ERROR unreachable +LL | let x = {return} as !; | ^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/reachable/expr_if.rs b/src/test/ui/reachable/expr_if.rs index ed43bd8c6895e..a3d54892de5bb 100644 --- a/src/test/ui/reachable/expr_if.rs +++ b/src/test/ui/reachable/expr_if.rs @@ -4,7 +4,7 @@ #![deny(unreachable_code)] fn foo() { - if {return} { + if {return} { //~ ERROR unreachable block in `if` expression println!("Hello, world!"); } } diff --git a/src/test/ui/reachable/expr_if.stderr b/src/test/ui/reachable/expr_if.stderr index d11471da1a6a3..f1690e595e5d1 100644 --- a/src/test/ui/reachable/expr_if.stderr +++ b/src/test/ui/reachable/expr_if.stderr @@ -1,15 +1,25 @@ -error: unreachable statement - --> $DIR/expr_if.rs:27:5 +error: unreachable block in `if` expression + --> $DIR/expr_if.rs:7:17 | -LL | println!("But I am."); - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | if {return} { + | _________________^ +LL | | println!("Hello, world!"); +LL | | } + | |_____^ | note: lint level defined here --> $DIR/expr_if.rs:4:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ + +error: unreachable statement + --> $DIR/expr_if.rs:27:5 + | +LL | println!("But I am."); + | ^^^^^^^^^^^^^^^^^^^^^^ + | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/reachable/expr_method.stderr b/src/test/ui/reachable/expr_method.stderr index f1770df2f9ea8..bbfa2ef529add 100644 --- a/src/test/ui/reachable/expr_method.stderr +++ b/src/test/ui/reachable/expr_method.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/expr_method.rs:16:21 | -LL | Foo.foo(return, 22); //~ ERROR unreachable +LL | Foo.foo(return, 22); | ^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unreachable_code)] error: unreachable expression --> $DIR/expr_method.rs:21:5 | -LL | Foo.bar(return); //~ ERROR unreachable +LL | Foo.bar(return); | ^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/reachable/expr_repeat.stderr b/src/test/ui/reachable/expr_repeat.stderr index 288c18d5d6593..0536cdef72128 100644 --- a/src/test/ui/reachable/expr_repeat.stderr +++ b/src/test/ui/reachable/expr_repeat.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/expr_repeat.rs:9:25 | -LL | let x: [usize; 2] = [return; 2]; //~ ERROR unreachable +LL | let x: [usize; 2] = [return; 2]; | ^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/reachable/expr_return.stderr b/src/test/ui/reachable/expr_return.stderr index e5ce660d69596..3317da58aba1c 100644 --- a/src/test/ui/reachable/expr_return.stderr +++ b/src/test/ui/reachable/expr_return.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/expr_return.rs:10:22 | -LL | let x = {return {return {return;}}}; //~ ERROR unreachable +LL | let x = {return {return {return;}}}; | ^^^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/reachable/expr_struct.stderr b/src/test/ui/reachable/expr_struct.stderr index 5fbf603602baa..dcccb7a4db307 100644 --- a/src/test/ui/reachable/expr_struct.stderr +++ b/src/test/ui/reachable/expr_struct.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/expr_struct.rs:14:13 | -LL | let x = Foo { a: 22, b: 33, ..return }; //~ ERROR unreachable +LL | let x = Foo { a: 22, b: 33, ..return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -13,19 +13,19 @@ LL | #![deny(unreachable_code)] error: unreachable expression --> $DIR/expr_struct.rs:19:33 | -LL | let x = Foo { a: return, b: 33, ..return }; //~ ERROR unreachable +LL | let x = Foo { a: return, b: 33, ..return }; | ^^ error: unreachable expression --> $DIR/expr_struct.rs:24:39 | -LL | let x = Foo { a: 22, b: return, ..return }; //~ ERROR unreachable +LL | let x = Foo { a: 22, b: return, ..return }; | ^^^^^^ error: unreachable expression --> $DIR/expr_struct.rs:29:13 | -LL | let x = Foo { a: 22, b: return }; //~ ERROR unreachable +LL | let x = Foo { a: 22, b: return }; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/reachable/expr_tup.stderr b/src/test/ui/reachable/expr_tup.stderr index def678ec93ea2..1837031107d59 100644 --- a/src/test/ui/reachable/expr_tup.stderr +++ b/src/test/ui/reachable/expr_tup.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/expr_tup.rs:9:38 | -LL | let x: (usize, usize) = (return, 2); //~ ERROR unreachable +LL | let x: (usize, usize) = (return, 2); | ^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unreachable_code)] error: unreachable expression --> $DIR/expr_tup.rs:14:29 | -LL | let x: (usize, usize) = (2, return); //~ ERROR unreachable +LL | let x: (usize, usize) = (2, return); | ^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/reachable/expr_type.stderr b/src/test/ui/reachable/expr_type.stderr index b90cd79034172..f867c89163415 100644 --- a/src/test/ui/reachable/expr_type.stderr +++ b/src/test/ui/reachable/expr_type.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/expr_type.rs:9:13 | -LL | let x = {return}: !; //~ ERROR unreachable +LL | let x = {return}: !; | ^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr index 44887f0ee523b..61982289cdc6e 100644 --- a/src/test/ui/reachable/expr_unary.stderr +++ b/src/test/ui/reachable/expr_unary.stderr @@ -1,13 +1,13 @@ error[E0600]: cannot apply unary operator `!` to type `!` --> $DIR/expr_unary.rs:8:16 | -LL | let x: ! = ! { return; }; //~ ERROR unreachable +LL | let x: ! = ! { return; }; | ^^^^^^^^^^^^^ cannot apply unary operator `!` error: unreachable expression --> $DIR/expr_unary.rs:8:16 | -LL | let x: ! = ! { return; }; //~ ERROR unreachable +LL | let x: ! = ! { return; }; | ^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/recursion/recursion.stderr b/src/test/ui/recursion/recursion.stderr index 1bef37ad58883..751d56b70f18c 100644 --- a/src/test/ui/recursion/recursion.stderr +++ b/src/test/ui/recursion/recursion.stderr @@ -1,7 +1,7 @@ -error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/recursion.rs:12:1 | -LL | / fn test (n:isize, i:isize, first:T, second:T) ->isize { //~ ERROR recursion limit +LL | / fn test (n:isize, i:isize, first:T, second:T) ->isize { LL | | match n { 0 => {first.dot(second)} LL | | // FIXME(#4287) Error message should be here. It should be LL | | // a type error to instantiate `test` at a type other than T. diff --git a/src/test/ui/recursion/recursive-reexports.stderr b/src/test/ui/recursion/recursive-reexports.stderr index 681931ef830f6..01afc1458afb9 100644 --- a/src/test/ui/recursion/recursive-reexports.stderr +++ b/src/test/ui/recursion/recursive-reexports.stderr @@ -1,7 +1,7 @@ error[E0412]: cannot find type `S` in module `recursive_reexports` --> $DIR/recursive-reexports.rs:5:32 | -LL | fn f() -> recursive_reexports::S {} //~ ERROR cannot find type `S` in module `recursive_reexports` +LL | fn f() -> recursive_reexports::S {} | ^ not found in `recursive_reexports` error: aborting due to previous error diff --git a/src/test/ui/recursion/recursive-types-are-not-uninhabited.nll.stderr b/src/test/ui/recursion/recursive-types-are-not-uninhabited.nll.stderr new file mode 100644 index 0000000000000..eee331d95b9bc --- /dev/null +++ b/src/test/ui/recursion/recursive-types-are-not-uninhabited.nll.stderr @@ -0,0 +1,16 @@ +error[E0005]: refutable pattern in local binding: `Err(_)` not covered + --> $DIR/recursive-types-are-not-uninhabited.rs:6:9 + | +LL | let Ok(x) = res; + | ^^^^^ pattern `Err(_)` not covered + +error[E0381]: use of possibly uninitialized variable: `x` + --> $DIR/recursive-types-are-not-uninhabited.rs:8:5 + | +LL | x + | ^ use of possibly uninitialized `x` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0005, E0381. +For more information about an error, try `rustc --explain E0005`. diff --git a/src/test/ui/recursion/recursive-types-are-not-uninhabited.rs b/src/test/ui/recursion/recursive-types-are-not-uninhabited.rs index b3e4efb99401f..a618aba9413f0 100644 --- a/src/test/ui/recursion/recursive-types-are-not-uninhabited.rs +++ b/src/test/ui/recursion/recursive-types-are-not-uninhabited.rs @@ -6,9 +6,11 @@ fn foo(res: Result) -> u32 { let Ok(x) = res; //~^ ERROR refutable pattern x + //~^ WARN use of possibly uninitialized variable: `x` + //~| WARN this error has been downgraded to a warning for backwards compatibility + //~| WARN this represents potential undefined behavior in your code and this warning will } fn main() { foo(Ok(23)); } - diff --git a/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr b/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr index dad98cff452ce..9203f893fdbf7 100644 --- a/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr +++ b/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr @@ -4,6 +4,17 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered LL | let Ok(x) = res; | ^^^^^ pattern `Err(_)` not covered +warning[E0381]: use of possibly uninitialized variable: `x` + --> $DIR/recursive-types-are-not-uninhabited.rs:8:5 + | +LL | x + | ^ use of possibly uninitialized `x` + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + error: aborting due to previous error -For more information about this error, try `rustc --explain E0005`. +Some errors have detailed explanations: E0005, E0381. +For more information about an error, try `rustc --explain E0005`. diff --git a/src/test/ui/ref-suggestion.nll.stderr b/src/test/ui/ref-suggestion.nll.stderr deleted file mode 100644 index 402f3c77cdb7b..0000000000000 --- a/src/test/ui/ref-suggestion.nll.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0382]: use of moved value: `x` - --> $DIR/ref-suggestion.rs:4:5 - | -LL | let x = vec![1]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait -LL | let y = x; - | - value moved here -LL | x; //~ ERROR use of moved value - | ^ value used here after move - -error[E0382]: use of moved value: `x` - --> $DIR/ref-suggestion.rs:8:5 - | -LL | let x = vec![1]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait -LL | let mut y = x; - | - value moved here -LL | x; //~ ERROR use of moved value - | ^ value used here after move - -error[E0382]: use of moved value: `x` - --> $DIR/ref-suggestion.rs:16:5 - | -LL | (Some(y), ()) => {}, - | - value moved here -... -LL | x; //~ ERROR use of partially moved value - | ^ value used here after partial move - | - = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/ref-suggestion.rs b/src/test/ui/ref-suggestion.rs index 346d118f0f9a9..49d199cd9e754 100644 --- a/src/test/ui/ref-suggestion.rs +++ b/src/test/ui/ref-suggestion.rs @@ -13,5 +13,5 @@ fn main() { (Some(y), ()) => {}, _ => {}, } - x; //~ ERROR use of partially moved value + x; //~ ERROR use of moved value } diff --git a/src/test/ui/ref-suggestion.stderr b/src/test/ui/ref-suggestion.stderr index 1f871bafeec99..9ff8e21bb58bd 100644 --- a/src/test/ui/ref-suggestion.stderr +++ b/src/test/ui/ref-suggestion.stderr @@ -1,33 +1,33 @@ error[E0382]: use of moved value: `x` --> $DIR/ref-suggestion.rs:4:5 | +LL | let x = vec![1]; + | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait LL | let y = x; - | - value moved here -LL | x; //~ ERROR use of moved value + | - value moved here +LL | x; | ^ value used here after move - | - = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x` --> $DIR/ref-suggestion.rs:8:5 | +LL | let x = vec![1]; + | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait LL | let mut y = x; - | ----- value moved here -LL | x; //~ ERROR use of moved value + | - value moved here +LL | x; | ^ value used here after move - | - = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait -error[E0382]: use of partially moved value: `x` +error[E0382]: use of moved value: `x` --> $DIR/ref-suggestion.rs:16:5 | LL | (Some(y), ()) => {}, | - value moved here ... -LL | x; //~ ERROR use of partially moved value - | ^ value used here after move +LL | x; + | ^ value used here after partial move | - = note: move occurs because the value has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait error: aborting due to 3 previous errors diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr index 66e6a615b33bc..35478a7db860a 100644 --- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/regions-fn-subtyping-return-static-fail.rs:40:12 | -LL | want_F(bar); //~ ERROR mismatched types +LL | want_F(bar); | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | = note: expected type `for<'cx> fn(&'cx S) -> &'cx S` @@ -10,7 +10,7 @@ LL | want_F(bar); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12 | -LL | want_G(baz); //~ ERROR mismatched types +LL | want_G(baz); | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | = note: expected type `for<'cx> fn(&'cx S) -> &'static S` diff --git a/src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs b/src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs index 24676fe5e5bd9..5cbfe6ebebb7e 100644 --- a/src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs +++ b/src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs @@ -9,13 +9,6 @@ // rust-lang/rust#56537 // compile-pass -// We are already testing NLL explicitly via the revision system below. -// ignore-compare-mode-nll - -// revisions: ll nll migrate -//[ll] compile-flags:-Zborrowck=ast -//[nll] compile-flags:-Zborrowck=mir -Z two-phase-borrows -//[migrate] compile-flags:-Zborrowck=migrate -Z two-phase-borrows fn willy_no_annot<'w>(p: &'w str, q: &str) -> &'w str { let free_dumb = |_x| { p }; // no type annotation at all diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-big.ast.nll.stderr b/src/test/ui/regions/region-borrow-params-issue-29793-big.ast.nll.stderr deleted file mode 100644 index 8fb1ebbf7d0d0..0000000000000 --- a/src/test/ui/regions/region-borrow-params-issue-29793-big.ast.nll.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-big.rs:71:26 - | -LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-big.rs:71:9 - | -LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | WrapB::new().set(move |t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-big.rs:71:26 - | -LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `y` is borrowed here - | | - | may outlive borrowed value `y` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-big.rs:71:9 - | -LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword - | -LL | WrapB::new().set(move |t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-big.ast.stderr b/src/test/ui/regions/region-borrow-params-issue-29793-big.ast.stderr deleted file mode 100644 index 27d8ce4ab5092..0000000000000 --- a/src/test/ui/regions/region-borrow-params-issue-29793-big.ast.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0597]: `x` does not live long enough - --> $DIR/region-borrow-params-issue-29793-big.rs:71:43 - | -LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | --------- ^ borrowed value does not live long enough - | | - | capture occurs here -... -LL | }); - | - borrowed value dropped before borrower - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `y` does not live long enough - --> $DIR/region-borrow-params-issue-29793-big.rs:71:54 - | -LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | --------- ^ borrowed value does not live long enough - | | - | capture occurs here -... -LL | }); - | - borrowed value dropped before borrower - | - = note: values in a scope are dropped in the opposite order they are created - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-big.mir.stderr b/src/test/ui/regions/region-borrow-params-issue-29793-big.mir.stderr deleted file mode 100644 index 8fb1ebbf7d0d0..0000000000000 --- a/src/test/ui/regions/region-borrow-params-issue-29793-big.mir.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-big.rs:71:26 - | -LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-big.rs:71:9 - | -LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | WrapB::new().set(move |t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-big.rs:71:26 - | -LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `y` is borrowed here - | | - | may outlive borrowed value `y` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-big.rs:71:9 - | -LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword - | -LL | WrapB::new().set(move |t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-big.rs b/src/test/ui/regions/region-borrow-params-issue-29793-big.rs index f21140b43de92..83b1a6eab57b4 100644 --- a/src/test/ui/regions/region-borrow-params-issue-29793-big.rs +++ b/src/test/ui/regions/region-borrow-params-issue-29793-big.rs @@ -6,10 +6,6 @@ // behavior (because the improperly accepted closure was actually // able to be invoked). -// ignore-tidy-linelength -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - struct WrapA(Option); impl WrapA { @@ -69,10 +65,8 @@ impl WrapA fn main() { let mut w = WrapA::new().set(|x: usize, y: usize| { WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) - //[ast]~^ ERROR `x` does not live long enough - //[ast]~| ERROR `y` does not live long enough - //[mir]~^^^ ERROR closure may outlive the current function - //[mir]~| ERROR closure may outlive the current function + //~^ ERROR closure may outlive the current function + //~| ERROR closure may outlive the current function }); w.handle(); // This works diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-big.stderr b/src/test/ui/regions/region-borrow-params-issue-29793-big.stderr new file mode 100644 index 0000000000000..328e602ca765c --- /dev/null +++ b/src/test/ui/regions/region-borrow-params-issue-29793-big.stderr @@ -0,0 +1,39 @@ +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-big.rs:67:26 + | +LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-big.rs:67:9 + | +LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | WrapB::new().set(move |t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^ + +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-big.rs:67:26 + | +LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) + | ^^^^^^^^^ - `y` is borrowed here + | | + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-big.rs:67:9 + | +LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | WrapB::new().set(move |t: bool| if t { x } else { y }) // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-small.nll.stderr b/src/test/ui/regions/region-borrow-params-issue-29793-small.nll.stderr deleted file mode 100644 index 18610b7cffb02..0000000000000 --- a/src/test/ui/regions/region-borrow-params-issue-29793-small.nll.stderr +++ /dev/null @@ -1,363 +0,0 @@ -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:9:17 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:12:16 - | -LL | return f; - | ^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:9:17 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `y` is borrowed here - | | - | may outlive borrowed value `y` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:12:16 - | -LL | return f; - | ^ -help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:24:17 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:27:9 - | -LL | f - | ^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:24:17 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `y` is borrowed here - | | - | may outlive borrowed value `y` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:27:9 - | -LL | f - | ^ -help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:55:17 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:58:16 - | -LL | return Box::new(f); - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:55:17 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `y` is borrowed here - | | - | may outlive borrowed value `y` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:58:16 - | -LL | return Box::new(f); - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:66:17 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:69:9 - | -LL | Box::new(f) - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:66:17 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `y` is borrowed here - | | - | may outlive borrowed value `y` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:69:9 - | -LL | Box::new(f) - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:90:21 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:93:20 - | -LL | return Box::new(f); - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:90:21 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `y` is borrowed here - | | - | may outlive borrowed value `y` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:93:20 - | -LL | return Box::new(f); - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:104:21 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:107:13 - | -LL | Box::new(f) - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:104:21 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `y` is borrowed here - | | - | may outlive borrowed value `y` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:107:13 - | -LL | Box::new(f) - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:132:21 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:135:20 - | -LL | return Box::new(f); - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:132:21 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `y` is borrowed here - | | - | may outlive borrowed value `y` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:135:20 - | -LL | return Box::new(f); - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:147:21 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:150:13 - | -LL | Box::new(f) - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:147:21 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `y` is borrowed here - | | - | may outlive borrowed value `y` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:150:13 - | -LL | Box::new(f) - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:175:21 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:178:20 - | -LL | return Box::new(f); - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:175:21 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `y` is borrowed here - | | - | may outlive borrowed value `y` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:178:20 - | -LL | return Box::new(f); - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:189:21 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:192:13 - | -LL | Box::new(f) - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function - --> $DIR/region-borrow-params-issue-29793-small.rs:189:21 - | -LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^ - `y` is borrowed here - | | - | may outlive borrowed value `y` - | -note: closure is returned here - --> $DIR/region-borrow-params-issue-29793-small.rs:192:13 - | -LL | Box::new(f) - | ^^^^^^^^^^^ -help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword - | -LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | ^^^^^^^^^^^^^^ - -error: aborting due to 20 previous errors - -For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-small.rs b/src/test/ui/regions/region-borrow-params-issue-29793-small.rs index 08ed79cbdbf3c..5f1c2ed08f6b7 100644 --- a/src/test/ui/regions/region-borrow-params-issue-29793-small.rs +++ b/src/test/ui/regions/region-borrow-params-issue-29793-small.rs @@ -7,8 +7,8 @@ fn escaping_borrow_of_closure_params_1() { let g = |x: usize, y:usize| { let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - //~^ ERROR `x` does not live long enough - //~| ERROR `y` does not live long enough + //~^ ERROR E0373 + //~| ERROR E0373 return f; }; @@ -22,8 +22,8 @@ fn escaping_borrow_of_closure_params_1() { fn escaping_borrow_of_closure_params_2() { let g = |x: usize, y:usize| { let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - //~^ ERROR `x` does not live long enough - //~| ERROR `y` does not live long enough + //~^ ERROR E0373 + //~| ERROR E0373 f }; @@ -51,7 +51,7 @@ fn ok_borrow_of_fn_params(a: usize, b:usize) { // TOP-LEVEL FN'S fn escaping_borrow_of_fn_params_1() { - fn g<'a>(x: usize, y:usize) -> Box usize + 'a> { + fn g<'a>(x: usize, y:usize) -> Box usize + 'a> { let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) //~^ ERROR E0373 //~| ERROR E0373 @@ -62,7 +62,7 @@ fn escaping_borrow_of_fn_params_1() { } fn escaping_borrow_of_fn_params_2() { - fn g<'a>(x: usize, y:usize) -> Box usize + 'a> { + fn g<'a>(x: usize, y:usize) -> Box usize + 'a> { let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) //~^ ERROR E0373 //~| ERROR E0373 @@ -73,7 +73,7 @@ fn escaping_borrow_of_fn_params_2() { } fn move_of_fn_params() { - fn g<'a>(x: usize, y:usize) -> Box usize + 'a> { + fn g<'a>(x: usize, y:usize) -> Box usize + 'a> { let f = move |t: bool| if t { x } else { y }; return Box::new(f); }; @@ -86,7 +86,7 @@ fn move_of_fn_params() { fn escaping_borrow_of_method_params_1() { struct S; impl S { - fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { + fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) //~^ ERROR E0373 //~| ERROR E0373 @@ -100,7 +100,7 @@ fn escaping_borrow_of_method_params_1() { fn escaping_borrow_of_method_params_2() { struct S; impl S { - fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { + fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) //~^ ERROR E0373 //~| ERROR E0373 @@ -113,7 +113,7 @@ fn escaping_borrow_of_method_params_2() { fn move_of_method_params() { struct S; impl S { - fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { + fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { let f = move |t: bool| if t { x } else { y }; return Box::new(f); } @@ -125,10 +125,10 @@ fn move_of_method_params() { // TRAIT IMPL METHODS fn escaping_borrow_of_trait_impl_params_1() { - trait T { fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a>; } + trait T { fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a>; } struct S; impl T for S { - fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { + fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) //~^ ERROR E0373 //~| ERROR E0373 @@ -140,10 +140,10 @@ fn escaping_borrow_of_trait_impl_params_1() { } fn escaping_borrow_of_trait_impl_params_2() { - trait T { fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a>; } + trait T { fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a>; } struct S; impl T for S { - fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { + fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) //~^ ERROR E0373 //~| ERROR E0373 @@ -154,10 +154,10 @@ fn escaping_borrow_of_trait_impl_params_2() { } fn move_of_trait_impl_params() { - trait T { fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a>; } + trait T { fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a>; } struct S; impl T for S { - fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { + fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { let f = move |t: bool| if t { x } else { y }; return Box::new(f); } @@ -171,7 +171,7 @@ fn move_of_trait_impl_params() { fn escaping_borrow_of_trait_default_params_1() { struct S; trait T { - fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { + fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) //~^ ERROR E0373 //~| ERROR E0373 @@ -185,7 +185,7 @@ fn escaping_borrow_of_trait_default_params_1() { fn escaping_borrow_of_trait_default_params_2() { struct S; trait T { - fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { + fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) //~^ ERROR E0373 //~| ERROR E0373 @@ -199,7 +199,7 @@ fn escaping_borrow_of_trait_default_params_2() { fn move_of_trait_default_params() { struct S; trait T { - fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { + fn g<'a>(&self, x: usize, y:usize) -> Box usize + 'a> { let f = move |t: bool| if t { x } else { y }; return Box::new(f); } @@ -210,4 +210,3 @@ fn move_of_trait_default_params() { } fn main() { } - diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-small.stderr b/src/test/ui/regions/region-borrow-params-issue-29793-small.stderr index d6ad68fe94e1e..18610b7cffb02 100644 --- a/src/test/ui/regions/region-borrow-params-issue-29793-small.stderr +++ b/src/test/ui/regions/region-borrow-params-issue-29793-small.stderr @@ -1,54 +1,74 @@ -error[E0597]: `x` does not live long enough - --> $DIR/region-borrow-params-issue-29793-small.rs:9:34 +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:9:17 | LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | --------- ^ borrowed value does not live long enough + | ^^^^^^^^^ - `x` is borrowed here | | - | capture occurs here -... -LL | }; - | - borrowed value dropped before borrower + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:12:16 | - = note: values in a scope are dropped in the opposite order they are created +LL | return f; + | ^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^ -error[E0597]: `y` does not live long enough - --> $DIR/region-borrow-params-issue-29793-small.rs:9:45 +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:9:17 | LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | --------- ^ borrowed value does not live long enough + | ^^^^^^^^^ - `y` is borrowed here | | - | capture occurs here -... -LL | }; - | - borrowed value dropped before borrower + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:12:16 | - = note: values in a scope are dropped in the opposite order they are created +LL | return f; + | ^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^ -error[E0597]: `x` does not live long enough - --> $DIR/region-borrow-params-issue-29793-small.rs:24:34 +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:24:17 | LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | --------- ^ borrowed value does not live long enough + | ^^^^^^^^^ - `x` is borrowed here | | - | capture occurs here -... -LL | }; - | - borrowed value dropped before borrower + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:27:9 | - = note: values in a scope are dropped in the opposite order they are created +LL | f + | ^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^ -error[E0597]: `y` does not live long enough - --> $DIR/region-borrow-params-issue-29793-small.rs:24:45 +error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function + --> $DIR/region-borrow-params-issue-29793-small.rs:24:17 | LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) - | --------- ^ borrowed value does not live long enough + | ^^^^^^^^^ - `y` is borrowed here | | - | capture occurs here -... -LL | }; - | - borrowed value dropped before borrower + | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:27:9 | - = note: values in a scope are dropped in the opposite order they are created +LL | f + | ^ +help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword + | +LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^ error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function --> $DIR/region-borrow-params-issue-29793-small.rs:55:17 @@ -57,6 +77,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x | ^^^^^^^^^ - `x` is borrowed here | | | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:58:16 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -69,6 +95,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x | ^^^^^^^^^ - `y` is borrowed here | | | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:58:16 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -81,6 +113,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x | ^^^^^^^^^ - `x` is borrowed here | | | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:69:9 + | +LL | Box::new(f) + | ^^^^^^^^^^^ help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -93,6 +131,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x | ^^^^^^^^^ - `y` is borrowed here | | | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:69:9 + | +LL | Box::new(f) + | ^^^^^^^^^^^ help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -105,6 +149,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors fo | ^^^^^^^^^ - `x` is borrowed here | | | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:93:20 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -117,6 +167,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors fo | ^^^^^^^^^ - `y` is borrowed here | | | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:93:20 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -129,6 +185,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors fo | ^^^^^^^^^ - `x` is borrowed here | | | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:107:13 + | +LL | Box::new(f) + | ^^^^^^^^^^^ help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -141,6 +203,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors fo | ^^^^^^^^^ - `y` is borrowed here | | | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:107:13 + | +LL | Box::new(f) + | ^^^^^^^^^^^ help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -153,6 +221,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors fo | ^^^^^^^^^ - `x` is borrowed here | | | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:135:20 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -165,6 +239,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors fo | ^^^^^^^^^ - `y` is borrowed here | | | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:135:20 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -177,6 +257,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors fo | ^^^^^^^^^ - `x` is borrowed here | | | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:150:13 + | +LL | Box::new(f) + | ^^^^^^^^^^^ help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -189,6 +275,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors fo | ^^^^^^^^^ - `y` is borrowed here | | | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:150:13 + | +LL | Box::new(f) + | ^^^^^^^^^^^ help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -201,6 +293,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors fo | ^^^^^^^^^ - `x` is borrowed here | | | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:178:20 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -213,6 +311,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors fo | ^^^^^^^^^ - `y` is borrowed here | | | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:178:20 + | +LL | return Box::new(f); + | ^^^^^^^^^^^ help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -225,6 +329,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors fo | ^^^^^^^^^ - `x` is borrowed here | | | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:192:13 + | +LL | Box::new(f) + | ^^^^^^^^^^^ help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -237,6 +347,12 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors fo | ^^^^^^^^^ - `y` is borrowed here | | | may outlive borrowed value `y` + | +note: closure is returned here + --> $DIR/region-borrow-params-issue-29793-small.rs:192:13 + | +LL | Box::new(f) + | ^^^^^^^^^^^ help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword | LL | let f = move |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) @@ -244,5 +360,4 @@ LL | let f = move |t: bool| if t { x } else { y }; // (separate erro error: aborting due to 20 previous errors -Some errors occurred: E0373, E0597. -For more information about an error, try `rustc --explain E0373`. +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/regions/region-bound-on-closure-outlives-call.nll.stderr b/src/test/ui/regions/region-bound-on-closure-outlives-call.nll.stderr deleted file mode 100644 index fa4c8a9dc6d8d..0000000000000 --- a/src/test/ui/regions/region-bound-on-closure-outlives-call.nll.stderr +++ /dev/null @@ -1,25 +0,0 @@ -warning: function cannot return without recursing - --> $DIR/region-bound-on-closure-outlives-call.rs:1:1 - | -LL | fn call_rec(mut f: F) -> usize where F: FnMut(usize) -> usize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing -LL | //~^ WARN function cannot return without recursing -LL | (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f` - | ----------- recursive call site - | - = note: #[warn(unconditional_recursion)] on by default - = help: a `loop` may express intention better if this is on purpose - -error[E0505]: cannot move out of `f` because it is borrowed - --> $DIR/region-bound-on-closure-outlives-call.rs:3:25 - | -LL | (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f` - | ---------- ^ move out of `f` occurs here - | || | - | || borrow occurs due to use in closure - | |borrow of `f` occurs here - | borrow later used by call - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/regions/region-bound-on-closure-outlives-call.stderr b/src/test/ui/regions/region-bound-on-closure-outlives-call.stderr index 3e60efd14720e..d455902ee8c07 100644 --- a/src/test/ui/regions/region-bound-on-closure-outlives-call.stderr +++ b/src/test/ui/regions/region-bound-on-closure-outlives-call.stderr @@ -3,8 +3,8 @@ warning: function cannot return without recursing | LL | fn call_rec(mut f: F) -> usize where F: FnMut(usize) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing -LL | //~^ WARN function cannot return without recursing -LL | (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f` +LL | +LL | (|x| f(x))(call_rec(f)) | ----------- recursive call site | = note: #[warn(unconditional_recursion)] on by default @@ -13,9 +13,10 @@ LL | (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f` error[E0505]: cannot move out of `f` because it is borrowed --> $DIR/region-bound-on-closure-outlives-call.rs:3:25 | -LL | (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f` - | --- ^ move out of `f` occurs here - | | +LL | (|x| f(x))(call_rec(f)) + | --- - ^ move out of `f` occurs here + | | | + | | borrow occurs due to use in closure | borrow of `f` occurs here error: aborting due to previous error diff --git a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.rs b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.rs index 3a211b0463605..40d2b740b4303 100644 --- a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.rs +++ b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.rs @@ -10,15 +10,15 @@ trait SomeTrait { } struct Foo<'a,'b,'c> { //~ ERROR parameter `'c` is never used // All of these are ok, because we can derive exactly one bound: - a: Box, - b: Box>, - c: Box>, - d: Box, - e: Box+Send>, // we can derive two bounds, but one is 'static, so ok - f: Box, // OK, defaults to 'static due to RFC 599. - g: Box, + a: Box, + b: Box>, + c: Box>, + d: Box, + e: Box+Send>, // we can derive two bounds, but one is 'static, so ok + f: Box, // OK, defaults to 'static due to RFC 599. + g: Box, - z: Box+'b+'c>, + z: Box+'b+'c>, //~^ ERROR only a single explicit lifetime bound is permitted //~| ERROR lifetime bound not satisfied } diff --git a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr index 16c31fbcac0ff..003dd0699d381 100644 --- a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr +++ b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr @@ -1,35 +1,35 @@ error[E0226]: only a single explicit lifetime bound is permitted - --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:22 + --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:26 | -LL | z: Box+'b+'c>, - | ^^ +LL | z: Box+'b+'c>, + | ^^ error[E0478]: lifetime bound not satisfied --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:5 | -LL | z: Box+'b+'c>, - | ^^^^^^^^^^^^^^^^^^^^ +LL | z: Box+'b+'c>, + | ^^^^^^^^^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime 'b as defined on the struct at 11:15 --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:15 | -LL | struct Foo<'a,'b,'c> { //~ ERROR parameter `'c` is never used +LL | struct Foo<'a,'b,'c> { | ^^ note: but lifetime parameter must outlive the lifetime 'a as defined on the struct at 11:12 --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:12 | -LL | struct Foo<'a,'b,'c> { //~ ERROR parameter `'c` is never used +LL | struct Foo<'a,'b,'c> { | ^^ error[E0392]: parameter `'c` is never used --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:18 | -LL | struct Foo<'a,'b,'c> { //~ ERROR parameter `'c` is never used - | ^^ unused type parameter +LL | struct Foo<'a,'b,'c> { + | ^^ unused parameter | = help: consider removing `'c` or using a marker such as `std::marker::PhantomData` error: aborting due to 3 previous errors -Some errors occurred: E0226, E0392, E0478. -For more information about an error, try `rustc --explain E0226`. +Some errors have detailed explanations: E0392, E0478. +For more information about an error, try `rustc --explain E0392`. diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr new file mode 100644 index 0000000000000..76129b4d188d3 --- /dev/null +++ b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr @@ -0,0 +1,11 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/region-invariant-static-error-reporting.rs:15:9 + | +LL | fn unify<'a>(x: Option>, f: fn(Invariant<'a>)) { + | - `x` is a reference that is only valid in the function body +LL | let bad = if x.is_some() { +LL | x.unwrap() + | ^^^^^^^^^^ `x` escapes the function body here + +error: aborting due to previous error + diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr new file mode 100644 index 0000000000000..24c9a315badf6 --- /dev/null +++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43 + | +LL | let _: fn(&mut &isize, &mut &isize) = a; + | ^ expected concrete lifetime, found bound lifetime parameter + | + = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` + found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr index 5c8b3d3ba6922..fd78f82d0f321 100644 --- a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr +++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr @@ -4,7 +4,7 @@ error[E0623]: lifetime mismatch LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) { | --------- --------- these two types are declared with different lifetimes... LL | // Illegal now because there is no `'b:'a` declaration. -LL | *x = *y; //~ ERROR E0623 +LL | *x = *y; | ^^ ...but data from `y` flows into `x` here error[E0623]: lifetime mismatch @@ -13,13 +13,13 @@ error[E0623]: lifetime mismatch LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { | --------- --------- these two types are declared with different lifetimes... ... -LL | a(x, y); //~ ERROR lifetime mismatch [E0623] +LL | a(x, y); | ^ ...but data from `y` flows into `x` here error[E0308]: mismatched types --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43 | -LL | let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR mismatched types +LL | let _: fn(&mut &isize, &mut &isize) = a; | ^ expected concrete lifetime, found bound lifetime parameter | = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` @@ -27,5 +27,4 @@ LL | let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR mismatched types error: aborting due to 3 previous errors -Some errors occurred: E0308, E0623. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr new file mode 100644 index 0000000000000..6d031e9ac3b98 --- /dev/null +++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56 + | +LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; + | ^ expected concrete lifetime, found bound lifetime parameter + | + = note: expected type `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)` + found type `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr index f36885f7aeb99..220c5493d19b1 100644 --- a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr +++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr @@ -4,7 +4,7 @@ error[E0623]: lifetime mismatch LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) { | --------- --------- these two types are declared with different lifetimes... LL | // Illegal now because there is no `'b:'a` declaration. -LL | *x = *y; //~ ERROR E0623 +LL | *x = *y; | ^^ ...but data from `y` flows into `x` here error[E0623]: lifetime mismatch @@ -15,7 +15,7 @@ LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) { | | | these two types are declared with different lifetimes... ... -LL | *z = *y; //~ ERROR E0623 +LL | *z = *y; | ^^ ...but data from `y` flows into `z` here error[E0623]: lifetime mismatch @@ -24,13 +24,13 @@ error[E0623]: lifetime mismatch LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) { | --------- --------- these two types are declared with different lifetimes... ... -LL | a(x, y, z); //~ ERROR lifetime mismatch [E0623] +LL | a(x, y, z); | ^ ...but data from `y` flows into `x` here error[E0308]: mismatched types --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56 | -LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR E0308 +LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; | ^ expected concrete lifetime, found bound lifetime parameter | = note: expected type `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)` @@ -38,5 +38,4 @@ LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; //~ ERROR E0308 error: aborting due to 4 previous errors -Some errors occurred: E0308, E0623. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/region-object-lifetime-2.nll.stderr b/src/test/ui/regions/region-object-lifetime-2.nll.stderr new file mode 100644 index 0000000000000..60084773466a6 --- /dev/null +++ b/src/test/ui/regions/region-object-lifetime-2.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/region-object-lifetime-2.rs:10:5 + | +LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x.borrowed() + | ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/region-object-lifetime-2.rs b/src/test/ui/regions/region-object-lifetime-2.rs index 92c85020e9a85..4279848789338 100644 --- a/src/test/ui/regions/region-object-lifetime-2.rs +++ b/src/test/ui/regions/region-object-lifetime-2.rs @@ -6,7 +6,7 @@ trait Foo { } // Borrowed receiver but two distinct lifetimes, we get an error. -fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a Foo) -> &'b () { +fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () { x.borrowed() //~ ERROR cannot infer } diff --git a/src/test/ui/regions/region-object-lifetime-2.stderr b/src/test/ui/regions/region-object-lifetime-2.stderr index f1e87ebf4749c..0c5e22ebae283 100644 --- a/src/test/ui/regions/region-object-lifetime-2.stderr +++ b/src/test/ui/regions/region-object-lifetime-2.stderr @@ -1,30 +1,29 @@ error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements --> $DIR/region-object-lifetime-2.rs:10:7 | -LL | x.borrowed() //~ ERROR cannot infer +LL | x.borrowed() | ^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 9:42... --> $DIR/region-object-lifetime-2.rs:9:42 | -LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a Foo) -> &'b () { +LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () { | ^^ note: ...so that reference does not outlive borrowed content --> $DIR/region-object-lifetime-2.rs:10:5 | -LL | x.borrowed() //~ ERROR cannot infer +LL | x.borrowed() | ^ note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 9:45... --> $DIR/region-object-lifetime-2.rs:9:45 | -LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a Foo) -> &'b () { +LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () { | ^^ note: ...so that reference does not outlive borrowed content --> $DIR/region-object-lifetime-2.rs:10:5 | -LL | x.borrowed() //~ ERROR cannot infer +LL | x.borrowed() | ^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/region-object-lifetime-4.nll.stderr b/src/test/ui/regions/region-object-lifetime-4.nll.stderr new file mode 100644 index 0000000000000..75b049dae21f8 --- /dev/null +++ b/src/test/ui/regions/region-object-lifetime-4.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/region-object-lifetime-4.rs:12:5 + | +LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | x.borrowed() + | ^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/region-object-lifetime-4.rs b/src/test/ui/regions/region-object-lifetime-4.rs index d2ab617ebb764..4fe12b2acfc69 100644 --- a/src/test/ui/regions/region-object-lifetime-4.rs +++ b/src/test/ui/regions/region-object-lifetime-4.rs @@ -8,7 +8,7 @@ trait Foo { // Here we have two distinct lifetimes, but we try to return a pointer // with the longer lifetime when (from the signature) we only know // that it lives as long as the shorter lifetime. Therefore, error. -fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (Foo+'b)) -> &'b () { +fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () { x.borrowed() //~ ERROR cannot infer } diff --git a/src/test/ui/regions/region-object-lifetime-4.stderr b/src/test/ui/regions/region-object-lifetime-4.stderr index 862a469ddb98c..e737d27d5606f 100644 --- a/src/test/ui/regions/region-object-lifetime-4.stderr +++ b/src/test/ui/regions/region-object-lifetime-4.stderr @@ -1,30 +1,29 @@ error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements --> $DIR/region-object-lifetime-4.rs:12:7 | -LL | x.borrowed() //~ ERROR cannot infer +LL | x.borrowed() | ^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 11:41... --> $DIR/region-object-lifetime-4.rs:11:41 | -LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (Foo+'b)) -> &'b () { +LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () { | ^^ note: ...so that reference does not outlive borrowed content --> $DIR/region-object-lifetime-4.rs:12:5 | -LL | x.borrowed() //~ ERROR cannot infer +LL | x.borrowed() | ^ note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 11:44... --> $DIR/region-object-lifetime-4.rs:11:44 | -LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (Foo+'b)) -> &'b () { +LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () { | ^^ note: ...so that reference does not outlive borrowed content --> $DIR/region-object-lifetime-4.rs:12:5 | -LL | x.borrowed() //~ ERROR cannot infer +LL | x.borrowed() | ^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/region-object-lifetime-5.nll.stderr b/src/test/ui/regions/region-object-lifetime-5.nll.stderr deleted file mode 100644 index c6d7135a2dbca..0000000000000 --- a/src/test/ui/regions/region-object-lifetime-5.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0515]: cannot return value referencing local data `*x` - --> $DIR/region-object-lifetime-5.rs:11:5 - | -LL | x.borrowed() //~ ERROR `*x` does not live long enough - | -^^^^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `*x` is borrowed here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/region-object-lifetime-5.rs b/src/test/ui/regions/region-object-lifetime-5.rs index 5009b2bbf32f6..307bbcbd58d7a 100644 --- a/src/test/ui/regions/region-object-lifetime-5.rs +++ b/src/test/ui/regions/region-object-lifetime-5.rs @@ -7,8 +7,8 @@ trait Foo { // Here, the object is bounded by an anonymous lifetime and returned // as `&'static`, so you get an error. -fn owned_receiver(x: Box) -> &'static () { - x.borrowed() //~ ERROR `*x` does not live long enough +fn owned_receiver(x: Box) -> &'static () { + x.borrowed() //~ ERROR cannot return value referencing local data `*x` } fn main() {} diff --git a/src/test/ui/regions/region-object-lifetime-5.stderr b/src/test/ui/regions/region-object-lifetime-5.stderr index 002bae18b1c01..b86f6e3a2a122 100644 --- a/src/test/ui/regions/region-object-lifetime-5.stderr +++ b/src/test/ui/regions/region-object-lifetime-5.stderr @@ -1,13 +1,12 @@ -error[E0597]: `*x` does not live long enough +error[E0515]: cannot return value referencing local data `*x` --> $DIR/region-object-lifetime-5.rs:11:5 | -LL | x.borrowed() //~ ERROR `*x` does not live long enough - | ^ borrowed value does not live long enough -LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... +LL | x.borrowed() + | -^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `*x` is borrowed here error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr new file mode 100644 index 0000000000000..43acbfd412d91 --- /dev/null +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr @@ -0,0 +1,38 @@ +error[E0621]: explicit lifetime required in the type of `v` + --> $DIR/region-object-lifetime-in-coercion.rs:8:12 + | +LL | fn a(v: &[u8]) -> Box { + | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` +LL | let x: Box = Box::new(v); + | ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required + +error[E0621]: explicit lifetime required in the type of `v` + --> $DIR/region-object-lifetime-in-coercion.rs:14:5 + | +LL | fn b(v: &[u8]) -> Box { + | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` +LL | Box::new(v) + | ^^^^^^^^^^^ lifetime `'static` required + +error[E0621]: explicit lifetime required in the type of `v` + --> $DIR/region-object-lifetime-in-coercion.rs:21:5 + | +LL | fn c(v: &[u8]) -> Box { + | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` +... +LL | Box::new(v) + | ^^^^^^^^^^^ lifetime `'static` required + +error: lifetime may not live long enough + --> $DIR/region-object-lifetime-in-coercion.rs:26:5 + | +LL | fn d<'a,'b>(v: &'a [u8]) -> Box { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | Box::new(v) + | ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.rs b/src/test/ui/regions/region-object-lifetime-in-coercion.rs index dfba04b0d25fc..2dc67599913a6 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.rs +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.rs @@ -4,30 +4,30 @@ trait Foo {} impl<'a> Foo for &'a [u8] {} -fn a(v: &[u8]) -> Box { - let x: Box = Box::new(v); +fn a(v: &[u8]) -> Box { + let x: Box = Box::new(v); //~^ ERROR explicit lifetime required in the type of `v` [E0621] x } -fn b(v: &[u8]) -> Box { +fn b(v: &[u8]) -> Box { Box::new(v) //~^ ERROR explicit lifetime required in the type of `v` [E0621] } -fn c(v: &[u8]) -> Box { +fn c(v: &[u8]) -> Box { // same as previous case due to RFC 599 Box::new(v) //~^ ERROR explicit lifetime required in the type of `v` [E0621] } -fn d<'a,'b>(v: &'a [u8]) -> Box { +fn d<'a,'b>(v: &'a [u8]) -> Box { Box::new(v) //~^ ERROR cannot infer an appropriate lifetime due to conflicting } -fn e<'a:'b,'b>(v: &'a [u8]) -> Box { +fn e<'a:'b,'b>(v: &'a [u8]) -> Box { Box::new(v) // OK, thanks to 'a:'b } diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index b8ea6d3476b51..8209fa1840d05 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -1,15 +1,15 @@ error[E0621]: explicit lifetime required in the type of `v` - --> $DIR/region-object-lifetime-in-coercion.rs:8:33 + --> $DIR/region-object-lifetime-in-coercion.rs:8:37 | -LL | fn a(v: &[u8]) -> Box { +LL | fn a(v: &[u8]) -> Box { | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` -LL | let x: Box = Box::new(v); - | ^^^^^^^^^^^ lifetime `'static` required +LL | let x: Box = Box::new(v); + | ^^^^^^^^^^^ lifetime `'static` required error[E0621]: explicit lifetime required in the type of `v` --> $DIR/region-object-lifetime-in-coercion.rs:14:5 | -LL | fn b(v: &[u8]) -> Box { +LL | fn b(v: &[u8]) -> Box { | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` LL | Box::new(v) | ^^^^^^^^^^^ lifetime `'static` required @@ -17,7 +17,7 @@ LL | Box::new(v) error[E0621]: explicit lifetime required in the type of `v` --> $DIR/region-object-lifetime-in-coercion.rs:21:5 | -LL | fn c(v: &[u8]) -> Box { +LL | fn c(v: &[u8]) -> Box { | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` ... LL | Box::new(v) @@ -32,7 +32,7 @@ LL | Box::new(v) note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 25:6... --> $DIR/region-object-lifetime-in-coercion.rs:25:6 | -LL | fn d<'a,'b>(v: &'a [u8]) -> Box { +LL | fn d<'a,'b>(v: &'a [u8]) -> Box { | ^^ = note: ...so that the expression is assignable: expected &[u8] @@ -40,7 +40,7 @@ LL | fn d<'a,'b>(v: &'a [u8]) -> Box { note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 25:9... --> $DIR/region-object-lifetime-in-coercion.rs:25:9 | -LL | fn d<'a,'b>(v: &'a [u8]) -> Box { +LL | fn d<'a,'b>(v: &'a [u8]) -> Box { | ^^ = note: ...so that the expression is assignable: expected std::boxed::Box<(dyn Foo + 'b)> @@ -48,5 +48,4 @@ LL | fn d<'a,'b>(v: &'a [u8]) -> Box { error: aborting due to 4 previous errors -Some errors occurred: E0495, E0621. -For more information about an error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/regions/regions-addr-of-arg.nll.stderr b/src/test/ui/regions/regions-addr-of-arg.nll.stderr deleted file mode 100644 index 0f60bc669b2dc..0000000000000 --- a/src/test/ui/regions/regions-addr-of-arg.nll.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0597]: `a` does not live long enough - --> $DIR/regions-addr-of-arg.rs:5:30 - | -LL | let _p: &'static isize = &a; //~ ERROR `a` does not live long enough - | -------------- ^^ borrowed value does not live long enough - | | - | type annotation requires that `a` is borrowed for `'static` -LL | } - | - `a` dropped here while still borrowed - -error[E0515]: cannot return reference to function parameter `a` - --> $DIR/regions-addr-of-arg.rs:13:5 - | -LL | &a //~ ERROR `a` does not live long enough - | ^^ returns a reference to data owned by the current function - -error: aborting due to 2 previous errors - -Some errors occurred: E0515, E0597. -For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-addr-of-arg.rs b/src/test/ui/regions/regions-addr-of-arg.rs index 06f16be8217c0..1805141c4210e 100644 --- a/src/test/ui/regions/regions-addr-of-arg.rs +++ b/src/test/ui/regions/regions-addr-of-arg.rs @@ -10,7 +10,7 @@ fn bar(a: isize) { } fn zed<'a>(a: isize) -> &'a isize { - &a //~ ERROR `a` does not live long enough + &a //~ ERROR cannot return reference to function parameter `a` } fn main() { diff --git a/src/test/ui/regions/regions-addr-of-arg.stderr b/src/test/ui/regions/regions-addr-of-arg.stderr index 61e28b8bbeadf..e77289287e536 100644 --- a/src/test/ui/regions/regions-addr-of-arg.stderr +++ b/src/test/ui/regions/regions-addr-of-arg.stderr @@ -1,27 +1,20 @@ error[E0597]: `a` does not live long enough - --> $DIR/regions-addr-of-arg.rs:5:31 + --> $DIR/regions-addr-of-arg.rs:5:30 | -LL | let _p: &'static isize = &a; //~ ERROR `a` does not live long enough - | ^ borrowed value does not live long enough +LL | let _p: &'static isize = &a; + | -------------- ^^ borrowed value does not live long enough + | | + | type annotation requires that `a` is borrowed for `'static` LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - `a` dropped here while still borrowed -error[E0597]: `a` does not live long enough - --> $DIR/regions-addr-of-arg.rs:13:6 - | -LL | &a //~ ERROR `a` does not live long enough - | ^ borrowed value does not live long enough -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 12:8... - --> $DIR/regions-addr-of-arg.rs:12:8 +error[E0515]: cannot return reference to function parameter `a` + --> $DIR/regions-addr-of-arg.rs:13:5 | -LL | fn zed<'a>(a: isize) -> &'a isize { - | ^^ +LL | &a + | ^^ returns a reference to data owned by the current function error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors have detailed explanations: E0515, E0597. +For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-addr-of-self.nll.stderr b/src/test/ui/regions/regions-addr-of-self.nll.stderr new file mode 100644 index 0000000000000..3d7aac74bd4f7 --- /dev/null +++ b/src/test/ui/regions/regions-addr-of-self.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/regions-addr-of-self.rs:7:16 + | +LL | pub fn chase_cat(&mut self) { + | - let's call the lifetime of this reference `'1` +LL | let p: &'static mut usize = &mut self.cats_chased; + | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-addr-of-self.stderr b/src/test/ui/regions/regions-addr-of-self.stderr index 2ea8aecacdae7..2274e9341dbc9 100644 --- a/src/test/ui/regions/regions-addr-of-self.stderr +++ b/src/test/ui/regions/regions-addr-of-self.stderr @@ -1,29 +1,28 @@ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements --> $DIR/regions-addr-of-self.rs:7:37 | -LL | let p: &'static mut usize = &mut self.cats_chased; //~ ERROR cannot infer +LL | let p: &'static mut usize = &mut self.cats_chased; | ^^^^^^^^^^^^^^^^^^^^^ | note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:5... --> $DIR/regions-addr-of-self.rs:6:5 | LL | / pub fn chase_cat(&mut self) { -LL | | let p: &'static mut usize = &mut self.cats_chased; //~ ERROR cannot infer +LL | | let p: &'static mut usize = &mut self.cats_chased; LL | | *p += 1; LL | | } | |_____^ note: ...so that reference does not outlive borrowed content --> $DIR/regions-addr-of-self.rs:7:37 | -LL | let p: &'static mut usize = &mut self.cats_chased; //~ ERROR cannot infer +LL | let p: &'static mut usize = &mut self.cats_chased; | ^^^^^^^^^^^^^^^^^^^^^ = note: but, the lifetime must be valid for the static lifetime... note: ...so that reference does not outlive borrowed content --> $DIR/regions-addr-of-self.rs:7:37 | -LL | let p: &'static mut usize = &mut self.cats_chased; //~ ERROR cannot infer +LL | let p: &'static mut usize = &mut self.cats_chased; | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr b/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr new file mode 100644 index 0000000000000..345e617a7a380 --- /dev/null +++ b/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr @@ -0,0 +1,35 @@ +error: lifetime may not live long enough + --> $DIR/regions-addr-of-upvar-self.rs:10:20 + | +LL | let _f = || { + | -- lifetime `'1` represents this closure's body +LL | let p: &'static mut usize = &mut self.food; + | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` + | + = note: closure implements `FnMut`, so references to captured variables can't escape the closure + +error: lifetime may not live long enough + --> $DIR/regions-addr-of-upvar-self.rs:10:20 + | +LL | pub fn chase_cat(&mut self) { + | - let's call the lifetime of this reference `'1` +LL | let _f = || { +LL | let p: &'static mut usize = &mut self.food; + | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` + +error[E0597]: `self` does not live long enough + --> $DIR/regions-addr-of-upvar-self.rs:10:46 + | +LL | let _f = || { + | -- value captured here +LL | let p: &'static mut usize = &mut self.food; + | ------------------ ^^^^ borrowed value does not live long enough + | | + | type annotation requires that `self` is borrowed for `'static` +... +LL | } + | - `self` dropped here while still borrowed + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.stderr b/src/test/ui/regions/regions-addr-of-upvar-self.stderr index 97470aae54a0b..d02caeb44f1a8 100644 --- a/src/test/ui/regions/regions-addr-of-upvar-self.stderr +++ b/src/test/ui/regions/regions-addr-of-upvar-self.stderr @@ -1,10 +1,10 @@ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements --> $DIR/regions-addr-of-upvar-self.rs:10:41 | -LL | let p: &'static mut usize = &mut self.food; //~ ERROR cannot infer +LL | let p: &'static mut usize = &mut self.food; | ^^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime as defined on the body at 9:18... +note: first, the lifetime cannot outlive the lifetime '_ as defined on the body at 9:18... --> $DIR/regions-addr-of-upvar-self.rs:9:18 | LL | let _f = || { @@ -12,15 +12,14 @@ LL | let _f = || { note: ...so that reference does not outlive borrowed content --> $DIR/regions-addr-of-upvar-self.rs:10:41 | -LL | let p: &'static mut usize = &mut self.food; //~ ERROR cannot infer +LL | let p: &'static mut usize = &mut self.food; | ^^^^^^^^^^^^^^ = note: but, the lifetime must be valid for the static lifetime... note: ...so that reference does not outlive borrowed content --> $DIR/regions-addr-of-upvar-self.rs:10:41 | -LL | let p: &'static mut usize = &mut self.food; //~ ERROR cannot infer +LL | let p: &'static mut usize = &mut self.food; | ^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-adjusted-lvalue-op.nll.stderr b/src/test/ui/regions/regions-adjusted-lvalue-op.nll.stderr deleted file mode 100644 index f188da5038d8b..0000000000000 --- a/src/test/ui/regions/regions-adjusted-lvalue-op.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable - --> $DIR/regions-adjusted-lvalue-op.rs:14:16 - | -LL | v[0].oh_no(&v); //~ ERROR cannot borrow `v` as immutable because - | - ----- ^^ immutable borrow occurs here - | | | - | | mutable borrow later used by call - | mutable borrow occurs here - -error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable - --> $DIR/regions-adjusted-lvalue-op.rs:15:16 - | -LL | (*v).oh_no(&v); //~ ERROR cannot borrow `v` as immutable because - | - ----- ^^ immutable borrow occurs here - | | | - | | mutable borrow later used by call - | mutable borrow occurs here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/regions/regions-adjusted-lvalue-op.stderr b/src/test/ui/regions/regions-adjusted-lvalue-op.stderr index 9988289b91e6c..2c55634445d81 100644 --- a/src/test/ui/regions/regions-adjusted-lvalue-op.stderr +++ b/src/test/ui/regions/regions-adjusted-lvalue-op.stderr @@ -1,19 +1,19 @@ error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable - --> $DIR/regions-adjusted-lvalue-op.rs:14:17 + --> $DIR/regions-adjusted-lvalue-op.rs:14:16 | -LL | v[0].oh_no(&v); //~ ERROR cannot borrow `v` as immutable because - | - ^- mutable borrow ends here - | | | - | | immutable borrow occurs here +LL | v[0].oh_no(&v); + | - ----- ^^ immutable borrow occurs here + | | | + | | mutable borrow later used by call | mutable borrow occurs here error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable - --> $DIR/regions-adjusted-lvalue-op.rs:15:17 + --> $DIR/regions-adjusted-lvalue-op.rs:15:16 | -LL | (*v).oh_no(&v); //~ ERROR cannot borrow `v` as immutable because - | - ^- mutable borrow ends here - | | | - | | immutable borrow occurs here +LL | (*v).oh_no(&v); + | - ----- ^^ immutable borrow occurs here + | | | + | | mutable borrow later used by call | mutable borrow occurs here error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.ast.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.ast.stderr deleted file mode 100644 index 76ead4e94ef66..0000000000000 --- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.ast.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0491]: in type `&'a WithAssoc>`, reference has a longer lifetime than the data it references - --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:45:13 - | -LL | let _x: &'a WithAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the pointer is valid for the lifetime 'a as defined on the function body at 37:15 - --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:37:15 - | -LL | fn with_assoc<'a,'b>() { - | ^^ -note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 37:18 - --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:37:18 - | -LL | fn with_assoc<'a,'b>() { - | ^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0491`. diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr new file mode 100644 index 0000000000000..867eafe2529d8 --- /dev/null +++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:43:12 + | +LL | fn with_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _: &'a WithAssoc> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr new file mode 100644 index 0000000000000..f31f25bf00b60 --- /dev/null +++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr @@ -0,0 +1,20 @@ +error[E0491]: in type `&'a WithAssoc>`, reference has a longer lifetime than the data it references + --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:43:12 + | +LL | let _: &'a WithAssoc> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the pointer is valid for the lifetime 'a as defined on the function body at 37:15 + --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:37:15 + | +LL | fn with_assoc<'a,'b>() { + | ^^ +note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 37:18 + --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:37:18 + | +LL | fn with_assoc<'a,'b>() { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0491`. diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.mir.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.mir.stderr deleted file mode 100644 index ad94d375b5bb7..0000000000000 --- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.mir.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:45:13 - | -LL | fn with_assoc<'a,'b>() { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -... -LL | let _x: &'a WithAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` - -error: aborting due to previous error - diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr new file mode 100644 index 0000000000000..867eafe2529d8 --- /dev/null +++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:43:12 + | +LL | fn with_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _: &'a WithAssoc> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs index 1d53492199230..97c5559360077 100644 --- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs +++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs @@ -3,8 +3,8 @@ // outlive the location in which the type appears, even when the // associted type is in a supertype. Issue #22246. -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir +// revisions: migrate nll +//[nll]compile-flags: -Z borrowck=mir #![allow(dead_code)] @@ -40,11 +40,9 @@ fn with_assoc<'a,'b>() { // outlive 'a. In this case, that means TheType<'b>::TheAssocType, // which is &'b (), must outlive 'a. - // FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if - // `_x` is changed to `_` - let _x: &'a WithAssoc> = loop { }; - //[ast]~^ ERROR reference has a longer lifetime - //[mir]~^^ ERROR lifetime may not live long enough + let _: &'a WithAssoc> = loop { }; + //[migrate]~^ ERROR reference has a longer lifetime + //[nll]~^^ ERROR lifetime may not live long enough } fn main() { diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr deleted file mode 100644 index aa92c59cee076..0000000000000 --- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0491]: in type `&'a WithAssoc>`, reference has a longer lifetime than the data it references - --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:42:13 - | -LL | let _x: &'a WithAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the pointer is valid for the lifetime 'a as defined on the function body at 34:15 - --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:34:15 - | -LL | fn with_assoc<'a,'b>() { - | ^^ -note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 34:18 - --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:34:18 - | -LL | fn with_assoc<'a,'b>() { - | ^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0491`. diff --git a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr index d01e991103923..9732cd12ce15f 100644 --- a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr +++ b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr @@ -46,4 +46,3 @@ LL | impl<'a,'b> Foo<'b> for &'a i64 { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr index 33a4ea01ce2e5..2067bc3946c92 100644 --- a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr +++ b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr @@ -21,4 +21,3 @@ LL | impl<'a> Foo for &'a i32 { error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr new file mode 100644 index 0000000000000..86bd100538d70 --- /dev/null +++ b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr @@ -0,0 +1,50 @@ +error: lifetime may not live long enough + --> $DIR/regions-bounded-by-trait-requiring-static.rs:22:5 + | +LL | fn param_not_ok<'a>(x: &'a isize) { + | -- lifetime `'a` defined here +LL | assert_send::<&'a isize>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5 + | +LL | fn param_not_ok1<'a>(_: &'a isize) { + | -- lifetime `'a` defined here +LL | assert_send::<&'a str>(); + | ^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/regions-bounded-by-trait-requiring-static.rs:30:5 + | +LL | fn param_not_ok2<'a>(_: &'a isize) { + | -- lifetime `'a` defined here +LL | assert_send::<&'a [isize]>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/regions-bounded-by-trait-requiring-static.rs:44:5 + | +LL | fn box_with_region_not_ok<'a>() { + | -- lifetime `'a` defined here +LL | assert_send::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/regions-bounded-by-trait-requiring-static.rs:55:5 + | +LL | fn unsafe_ok2<'a>(_: &'a isize) { + | -- lifetime `'a` defined here +LL | assert_send::<*const &'a isize>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/regions-bounded-by-trait-requiring-static.rs:59:5 + | +LL | fn unsafe_ok3<'a>(_: &'a isize) { + | -- lifetime `'a` defined here +LL | assert_send::<*mut &'a isize>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr index dbda9f4067b03..fcd7332cf39f9 100644 --- a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr +++ b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr @@ -1,7 +1,7 @@ error[E0477]: the type `&'a isize` does not fulfill the required lifetime --> $DIR/regions-bounded-by-trait-requiring-static.rs:22:5 | -LL | assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lifetime +LL | assert_send::<&'a isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: type must satisfy the static lifetime @@ -9,7 +9,7 @@ LL | assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lif error[E0477]: the type `&'a str` does not fulfill the required lifetime --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5 | -LL | assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime +LL | assert_send::<&'a str>(); | ^^^^^^^^^^^^^^^^^^^^^^ | = note: type must satisfy the static lifetime @@ -17,7 +17,7 @@ LL | assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifet error[E0477]: the type `&'a [isize]` does not fulfill the required lifetime --> $DIR/regions-bounded-by-trait-requiring-static.rs:30:5 | -LL | assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required lifetime +LL | assert_send::<&'a [isize]>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: type must satisfy the static lifetime @@ -25,7 +25,7 @@ LL | assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required l error[E0477]: the type `std::boxed::Box<&'a isize>` does not fulfill the required lifetime --> $DIR/regions-bounded-by-trait-requiring-static.rs:44:5 | -LL | assert_send::>(); //~ ERROR does not fulfill the required lifetime +LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: type must satisfy the static lifetime @@ -33,7 +33,7 @@ LL | assert_send::>(); //~ ERROR does not fulfill the require error[E0477]: the type `*const &'a isize` does not fulfill the required lifetime --> $DIR/regions-bounded-by-trait-requiring-static.rs:55:5 | -LL | assert_send::<*const &'a isize>(); //~ ERROR does not fulfill the required lifetime +LL | assert_send::<*const &'a isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: type must satisfy the static lifetime @@ -41,11 +41,10 @@ LL | assert_send::<*const &'a isize>(); //~ ERROR does not fulfill the requi error[E0477]: the type `*mut &'a isize` does not fulfill the required lifetime --> $DIR/regions-bounded-by-trait-requiring-static.rs:59:5 | -LL | assert_send::<*mut &'a isize>(); //~ ERROR does not fulfill the required lifetime +LL | assert_send::<*mut &'a isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: type must satisfy the static lifetime error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0477`. diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr new file mode 100644 index 0000000000000..a8ab92d75c06d --- /dev/null +++ b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/regions-bounded-method-type-parameters-cross-crate.rs:20:5 + | +LL | fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) { + | -- -- lifetime `'y` defined here + | | + | lifetime `'x` defined here +LL | // Here the value provided for 'y is 'y, and hence 'y:'x does not hold. +LL | a.bigger_region(b) + | ^^^^^^^^^^^^^^^^^^ argument requires that `'y` must outlive `'x` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.stderr index 50339590ee541..4e88be1c1e8a8 100644 --- a/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.stderr +++ b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.stderr @@ -4,9 +4,8 @@ error[E0623]: lifetime mismatch LL | fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) { | ------- ------- these two types are declared with different lifetimes... LL | // Here the value provided for 'y is 'y, and hence 'y:'x does not hold. -LL | a.bigger_region(b) //~ ERROR lifetime mismatch [E0623] +LL | a.bigger_region(b) | ^^^^^^^^^^^^^ ...but data from `b` flows into `a` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr new file mode 100644 index 0000000000000..52ad2d9daeb1d --- /dev/null +++ b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr @@ -0,0 +1,13 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:5 + | +LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) { + | - - `b` is a reference that is only valid in the function body + | | + | `a` is declared here, outside of the function body +LL | // Here the value provided for 'y is 'b, and hence 'b:'a does not hold. +LL | f.method(b); + | ^^^^^^^^^^^ `b` escapes the function body here + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.stderr index c9cbacded907e..6b1302b539402 100644 --- a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.stderr +++ b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.stderr @@ -4,9 +4,8 @@ error[E0623]: lifetime mismatch LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) { | ------- ------- these two types are declared with different lifetimes... LL | // Here the value provided for 'y is 'b, and hence 'b:'a does not hold. -LL | f.method(b); //~ ERROR lifetime mismatch [E0623] +LL | f.method(b); | ^^^^^^ ...but data from `b` flows into `a` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr new file mode 100644 index 0000000000000..b6d7b8aac5f19 --- /dev/null +++ b/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/regions-bounded-method-type-parameters.rs:12:9 + | +LL | fn caller<'a>(x: &isize) { + | -- lifetime `'a` defined here +LL | Foo.some_method::<&'a isize>(); + | ^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters.stderr index 66b61b1349d2b..f77f97f44f2b7 100644 --- a/src/test/ui/regions/regions-bounded-method-type-parameters.stderr +++ b/src/test/ui/regions/regions-bounded-method-type-parameters.stderr @@ -8,4 +8,3 @@ LL | Foo.some_method::<&'a isize>(); error: aborting due to previous error -For more information about this error, try `rustc --explain E0477`. diff --git a/src/test/ui/regions/regions-bounds.nll.stderr b/src/test/ui/regions/regions-bounds.nll.stderr new file mode 100644 index 0000000000000..3345946bfddff --- /dev/null +++ b/src/test/ui/regions/regions-bounds.nll.stderr @@ -0,0 +1,22 @@ +error: lifetime may not live long enough + --> $DIR/regions-bounds.rs:9:12 + | +LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | return e; + | ^ returning this value requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/regions-bounds.rs:13:12 + | +LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | return e; + | ^ returning this value requires that `'a` must outlive `'b` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/regions/regions-bounds.stderr b/src/test/ui/regions/regions-bounds.stderr index 95857e987751b..27eb8891c6c06 100644 --- a/src/test/ui/regions/regions-bounds.stderr +++ b/src/test/ui/regions/regions-bounds.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/regions-bounds.rs:9:12 | -LL | return e; //~ ERROR mismatched types +LL | return e; | ^ lifetime mismatch | = note: expected type `TupleStruct<'b>` @@ -20,7 +20,7 @@ LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> { error[E0308]: mismatched types --> $DIR/regions-bounds.rs:13:12 | -LL | return e; //~ ERROR mismatched types +LL | return e; | ^ lifetime mismatch | = note: expected type `Struct<'b>` diff --git a/src/test/ui/regions/regions-close-associated-type-into-object.nll.stderr b/src/test/ui/regions/regions-close-associated-type-into-object.nll.stderr new file mode 100644 index 0000000000000..92c4956da02d2 --- /dev/null +++ b/src/test/ui/regions/regions-close-associated-type-into-object.nll.stderr @@ -0,0 +1,36 @@ +error[E0310]: the associated type `::Item` may not live long enough + --> $DIR/regions-close-associated-type-into-object.rs:15:5 + | +LL | Box::new(item) + | ^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `::Item: 'static`... + +error[E0310]: the associated type `::Item` may not live long enough + --> $DIR/regions-close-associated-type-into-object.rs:22:5 + | +LL | Box::new(item) + | ^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `::Item: 'static`... + +error[E0309]: the associated type `::Item` may not live long enough + --> $DIR/regions-close-associated-type-into-object.rs:28:5 + | +LL | Box::new(item) + | ^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `::Item: 'a`... + +error[E0309]: the associated type `::Item` may not live long enough + --> $DIR/regions-close-associated-type-into-object.rs:35:5 + | +LL | Box::new(item) + | ^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `::Item: 'a`... + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0309, E0310. +For more information about an error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-close-associated-type-into-object.rs b/src/test/ui/regions/regions-close-associated-type-into-object.rs index 853d961138718..0cbdc828c507f 100644 --- a/src/test/ui/regions/regions-close-associated-type-into-object.rs +++ b/src/test/ui/regions/regions-close-associated-type-into-object.rs @@ -9,54 +9,54 @@ trait Iter { fn as_item(&self) -> &Self::Item; } -fn bad1(v: T) -> Box +fn bad1(v: T) -> Box { let item = v.into_item(); Box::new(item) //~ ERROR associated type `::Item` may not live long enough } -fn bad2(v: T) -> Box +fn bad2(v: T) -> Box where Box : X { let item: Box<_> = box v.into_item(); Box::new(item) //~ ERROR associated type `::Item` may not live long enough } -fn bad3<'a, T: Iter>(v: T) -> Box +fn bad3<'a, T: Iter>(v: T) -> Box { let item = v.into_item(); Box::new(item) //~ ERROR associated type `::Item` may not live long enough } -fn bad4<'a, T: Iter>(v: T) -> Box +fn bad4<'a, T: Iter>(v: T) -> Box where Box : X { let item: Box<_> = box v.into_item(); Box::new(item) //~ ERROR associated type `::Item` may not live long enough } -fn ok1<'a, T: Iter>(v: T) -> Box +fn ok1<'a, T: Iter>(v: T) -> Box where T::Item : 'a { let item = v.into_item(); Box::new(item) // OK, T::Item : 'a is declared } -fn ok2<'a, T: Iter>(v: &T, w: &'a T::Item) -> Box +fn ok2<'a, T: Iter>(v: &T, w: &'a T::Item) -> Box where T::Item : Clone { let item = Clone::clone(w); Box::new(item) // OK, T::Item : 'a is implied } -fn ok3<'a, T: Iter>(v: &'a T) -> Box +fn ok3<'a, T: Iter>(v: &'a T) -> Box where T::Item : Clone + 'a { let item = Clone::clone(v.as_item()); Box::new(item) // OK, T::Item : 'a was declared } -fn meh1<'a, T: Iter>(v: &'a T) -> Box +fn meh1<'a, T: Iter>(v: &'a T) -> Box where T::Item : Clone { // This case is kind of interesting. It's the same as `ok3` but diff --git a/src/test/ui/regions/regions-close-associated-type-into-object.stderr b/src/test/ui/regions/regions-close-associated-type-into-object.stderr index 182081ede0c6f..2401f549a5604 100644 --- a/src/test/ui/regions/regions-close-associated-type-into-object.stderr +++ b/src/test/ui/regions/regions-close-associated-type-into-object.stderr @@ -1,56 +1,56 @@ error[E0310]: the associated type `::Item` may not live long enough --> $DIR/regions-close-associated-type-into-object.rs:15:5 | -LL | Box::new(item) //~ ERROR associated type `::Item` may not live long enough +LL | Box::new(item) | ^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `::Item: 'static`... note: ...so that the type `::Item` will meet its required lifetime bounds --> $DIR/regions-close-associated-type-into-object.rs:15:5 | -LL | Box::new(item) //~ ERROR associated type `::Item` may not live long enough +LL | Box::new(item) | ^^^^^^^^^^^^^^ error[E0310]: the associated type `::Item` may not live long enough --> $DIR/regions-close-associated-type-into-object.rs:22:5 | -LL | Box::new(item) //~ ERROR associated type `::Item` may not live long enough +LL | Box::new(item) | ^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `::Item: 'static`... note: ...so that the type `std::boxed::Box<::Item>` will meet its required lifetime bounds --> $DIR/regions-close-associated-type-into-object.rs:22:5 | -LL | Box::new(item) //~ ERROR associated type `::Item` may not live long enough +LL | Box::new(item) | ^^^^^^^^^^^^^^ error[E0309]: the associated type `::Item` may not live long enough --> $DIR/regions-close-associated-type-into-object.rs:28:5 | -LL | Box::new(item) //~ ERROR associated type `::Item` may not live long enough +LL | Box::new(item) | ^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `::Item: 'a`... note: ...so that the type `::Item` will meet its required lifetime bounds --> $DIR/regions-close-associated-type-into-object.rs:28:5 | -LL | Box::new(item) //~ ERROR associated type `::Item` may not live long enough +LL | Box::new(item) | ^^^^^^^^^^^^^^ error[E0309]: the associated type `::Item` may not live long enough --> $DIR/regions-close-associated-type-into-object.rs:35:5 | -LL | Box::new(item) //~ ERROR associated type `::Item` may not live long enough +LL | Box::new(item) | ^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `::Item: 'a`... note: ...so that the type `std::boxed::Box<::Item>` will meet its required lifetime bounds --> $DIR/regions-close-associated-type-into-object.rs:35:5 | -LL | Box::new(item) //~ ERROR associated type `::Item` may not live long enough +LL | Box::new(item) | ^^^^^^^^^^^^^^ error: aborting due to 4 previous errors -Some errors occurred: E0309, E0310. +Some errors have detailed explanations: E0309, E0310. For more information about an error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-close-object-into-object-1.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-1.nll.stderr deleted file mode 100644 index 0e68a0548e622..0000000000000 --- a/src/test/ui/regions/regions-close-object-into-object-1.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0515]: cannot return value referencing local data `*v` - --> $DIR/regions-close-object-into-object-1.rs:12:5 - | -LL | box B(&*v) as Box //~ ERROR `*v` does not live long enough - | ^^^^^^---^^^^^^^^^^^ - | | | - | | `*v` is borrowed here - | returns a value referencing data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-close-object-into-object-1.rs b/src/test/ui/regions/regions-close-object-into-object-1.rs index 7a862f97a99d2..5518c6a94b1d0 100644 --- a/src/test/ui/regions/regions-close-object-into-object-1.rs +++ b/src/test/ui/regions/regions-close-object-into-object-1.rs @@ -9,7 +9,7 @@ trait X { } impl<'a, T> X for B<'a, T> {} fn f<'a, T:'static, U>(v: Box+'static>) -> Box { - box B(&*v) as Box //~ ERROR `*v` does not live long enough + box B(&*v) as Box //~ ERROR cannot return value referencing local data `*v` } fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-1.stderr b/src/test/ui/regions/regions-close-object-into-object-1.stderr index 817f664db45d1..8e119c4f5355f 100644 --- a/src/test/ui/regions/regions-close-object-into-object-1.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-1.stderr @@ -1,13 +1,12 @@ -error[E0597]: `*v` does not live long enough - --> $DIR/regions-close-object-into-object-1.rs:12:12 +error[E0515]: cannot return value referencing local data `*v` + --> $DIR/regions-close-object-into-object-1.rs:12:5 | -LL | box B(&*v) as Box //~ ERROR `*v` does not live long enough - | ^^ borrowed value does not live long enough -LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... +LL | box B(&*v) as Box + | ^^^^^^---^^^^^^^^^^^ + | | | + | | `*v` is borrowed here + | returns a value referencing data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr new file mode 100644 index 0000000000000..806a3ca82425b --- /dev/null +++ b/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr @@ -0,0 +1,20 @@ +error: lifetime may not live long enough + --> $DIR/regions-close-object-into-object-2.rs:10:5 + | +LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { + | -- lifetime `'a` defined here +LL | box B(&*v) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error[E0515]: cannot return value referencing local data `*v` + --> $DIR/regions-close-object-into-object-2.rs:10:5 + | +LL | box B(&*v) as Box + | ^^^^^^---^^^^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here + | returns a value referencing data owned by the current function + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-close-object-into-object-2.rs b/src/test/ui/regions/regions-close-object-into-object-2.rs index cebb4ac68cbc6..2364ba2728600 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.rs +++ b/src/test/ui/regions/regions-close-object-into-object-2.rs @@ -1,13 +1,13 @@ #![feature(box_syntax)] trait A { } -struct B<'a, T:'a>(&'a (A+'a)); +struct B<'a, T:'a>(&'a (dyn A + 'a)); trait X { } impl<'a, T> X for B<'a, T> {} -fn g<'a, T: 'static>(v: Box+'a>) -> Box { - box B(&*v) as Box //~ ERROR cannot infer +fn g<'a, T: 'static>(v: Box + 'a>) -> Box { + box B(&*v) as Box //~ ERROR cannot infer } fn main() { } diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index de9a250ced660..fa203debb3a1b 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -1,18 +1,18 @@ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements --> $DIR/regions-close-object-into-object-2.rs:10:11 | -LL | box B(&*v) as Box //~ ERROR cannot infer +LL | box B(&*v) as Box | ^^^ | note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 9:6... --> $DIR/regions-close-object-into-object-2.rs:9:6 | -LL | fn g<'a, T: 'static>(v: Box+'a>) -> Box { +LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ^^ note: ...so that the type `(dyn A + 'a)` is not borrowed for too long --> $DIR/regions-close-object-into-object-2.rs:10:11 | -LL | box B(&*v) as Box //~ ERROR cannot infer +LL | box B(&*v) as Box | ^^^ = note: but, the lifetime must be valid for the static lifetime... = note: ...so that the expression is assignable: @@ -21,4 +21,3 @@ LL | box B(&*v) as Box //~ ERROR cannot infer error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-close-object-into-object-3.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-3.nll.stderr deleted file mode 100644 index 6225575ddf3a1..0000000000000 --- a/src/test/ui/regions/regions-close-object-into-object-3.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0515]: cannot return value referencing local data `*v` - --> $DIR/regions-close-object-into-object-3.rs:11:5 - | -LL | box B(&*v) as Box //~ ERROR `*v` does not live long enough - | ^^^^^^---^^^^^^^^^^^ - | | | - | | `*v` is borrowed here - | returns a value referencing data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-close-object-into-object-3.rs b/src/test/ui/regions/regions-close-object-into-object-3.rs index cafbf0932249d..6f6b3a170027d 100644 --- a/src/test/ui/regions/regions-close-object-into-object-3.rs +++ b/src/test/ui/regions/regions-close-object-into-object-3.rs @@ -8,7 +8,7 @@ trait X { } impl<'a, T> X for B<'a, T> {} fn h<'a, T, U:'static>(v: Box+'static>) -> Box { - box B(&*v) as Box //~ ERROR `*v` does not live long enough + box B(&*v) as Box //~ ERROR cannot return value referencing local data `*v` } fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-3.stderr b/src/test/ui/regions/regions-close-object-into-object-3.stderr index 1736a5f215cd7..9ea13638f5cad 100644 --- a/src/test/ui/regions/regions-close-object-into-object-3.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-3.stderr @@ -1,13 +1,12 @@ -error[E0597]: `*v` does not live long enough - --> $DIR/regions-close-object-into-object-3.rs:11:12 +error[E0515]: cannot return value referencing local data `*v` + --> $DIR/regions-close-object-into-object-3.rs:11:5 | -LL | box B(&*v) as Box //~ ERROR `*v` does not live long enough - | ^^ borrowed value does not live long enough -LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... +LL | box B(&*v) as Box + | ^^^^^^---^^^^^^^^^^^ + | | | + | | `*v` is borrowed here + | returns a value referencing data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr new file mode 100644 index 0000000000000..1e57023bc2320 --- /dev/null +++ b/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr @@ -0,0 +1,37 @@ +error[E0310]: the parameter type `U` may not live long enough + --> $DIR/regions-close-object-into-object-4.rs:10:5 + | +LL | box B(&*v) as Box + | ^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `U: 'static`... + +error: lifetime may not live long enough + --> $DIR/regions-close-object-into-object-4.rs:10:5 + | +LL | fn i<'a, T, U>(v: Box+'a>) -> Box { + | -- lifetime `'a` defined here +LL | box B(&*v) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error[E0515]: cannot return value referencing local data `*v` + --> $DIR/regions-close-object-into-object-4.rs:10:5 + | +LL | box B(&*v) as Box + | ^^^^^^---^^^^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here + | returns a value referencing data owned by the current function + +error[E0310]: the parameter type `U` may not live long enough + --> $DIR/regions-close-object-into-object-4.rs:10:9 + | +LL | box B(&*v) as Box + | ^^^^^^ + | + = help: consider adding an explicit lifetime bound `U: 'static`... + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0310, E0515. +For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/regions/regions-close-object-into-object-4.rs b/src/test/ui/regions/regions-close-object-into-object-4.rs index 91aab057bb9a2..d531077043686 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.rs +++ b/src/test/ui/regions/regions-close-object-into-object-4.rs @@ -1,13 +1,13 @@ #![feature(box_syntax)] trait A { } -struct B<'a, T:'a>(&'a (A+'a)); +struct B<'a, T:'a>(&'a (dyn A + 'a)); trait X { } impl<'a, T> X for B<'a, T> {} -fn i<'a, T, U>(v: Box+'a>) -> Box { - box B(&*v) as Box //~ ERROR cannot infer +fn i<'a, T, U>(v: Box+'a>) -> Box { + box B(&*v) as Box //~ ERROR cannot infer } fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 87bf28d74d4d5..f5e66f84a9ee7 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -1,18 +1,18 @@ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements --> $DIR/regions-close-object-into-object-4.rs:10:11 | -LL | box B(&*v) as Box //~ ERROR cannot infer +LL | box B(&*v) as Box | ^^^ | note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 9:6... --> $DIR/regions-close-object-into-object-4.rs:9:6 | -LL | fn i<'a, T, U>(v: Box+'a>) -> Box { +LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ^^ note: ...so that the type `(dyn A + 'a)` is not borrowed for too long --> $DIR/regions-close-object-into-object-4.rs:10:11 | -LL | box B(&*v) as Box //~ ERROR cannot infer +LL | box B(&*v) as Box | ^^^ = note: but, the lifetime must be valid for the static lifetime... = note: ...so that the expression is assignable: @@ -21,4 +21,3 @@ LL | box B(&*v) as Box //~ ERROR cannot infer error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr new file mode 100644 index 0000000000000..08ba1b17b5663 --- /dev/null +++ b/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr @@ -0,0 +1,29 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-object-into-object-5.rs:17:5 + | +LL | box B(&*v) as Box + | ^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'static`... + +error[E0515]: cannot return value referencing local data `*v` + --> $DIR/regions-close-object-into-object-5.rs:17:5 + | +LL | box B(&*v) as Box + | ^^^^^^---^^^^^^^^^^^ + | | | + | | `*v` is borrowed here + | returns a value referencing data owned by the current function + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-object-into-object-5.rs:17:9 + | +LL | box B(&*v) as Box + | ^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'static`... + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0310, E0515. +For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr new file mode 100644 index 0000000000000..7d3d51bdb437e --- /dev/null +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr @@ -0,0 +1,20 @@ +error[E0310]: the parameter type `A` may not live long enough + --> $DIR/regions-close-over-type-parameter-1.rs:10:5 + | +LL | box v as Box + | ^^^^^ + | + = help: consider adding an explicit lifetime bound `A: 'static`... + +error[E0309]: the parameter type `A` may not live long enough + --> $DIR/regions-close-over-type-parameter-1.rs:20:5 + | +LL | box v as Box + | ^^^^^ + | + = help: consider adding an explicit lifetime bound `A: 'b`... + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0309, E0310. +For more information about an error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.rs b/src/test/ui/regions/regions-close-over-type-parameter-1.rs index 9aee9663e8f46..6a9aa66a446c3 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-1.rs +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.rs @@ -6,18 +6,18 @@ trait SomeTrait { fn get(&self) -> isize; } -fn make_object1(v: A) -> Box { - box v as Box +fn make_object1(v: A) -> Box { + box v as Box //~^ ERROR the parameter type `A` may not live long enough //~| ERROR the parameter type `A` may not live long enough } -fn make_object2<'a,A:SomeTrait+'a>(v: A) -> Box { - box v as Box +fn make_object2<'a,A:SomeTrait+'a>(v: A) -> Box { + box v as Box } -fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { - box v as Box +fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { + box v as Box //~^ ERROR the parameter type `A` may not live long enough //~| ERROR the parameter type `A` may not live long enough } diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr index 6d33f147308c5..81534b7b770d0 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr @@ -1,60 +1,60 @@ error[E0310]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:10:5 | -LL | fn make_object1(v: A) -> Box { +LL | fn make_object1(v: A) -> Box { | -- help: consider adding an explicit lifetime bound `A: 'static`... -LL | box v as Box +LL | box v as Box | ^^^^^ | note: ...so that the type `A` will meet its required lifetime bounds --> $DIR/regions-close-over-type-parameter-1.rs:10:5 | -LL | box v as Box +LL | box v as Box | ^^^^^ error[E0310]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:10:5 | -LL | fn make_object1(v: A) -> Box { +LL | fn make_object1(v: A) -> Box { | -- help: consider adding an explicit lifetime bound `A: 'static`... -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | box v as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...so that it can be closed over into an object --> $DIR/regions-close-over-type-parameter-1.rs:10:5 | -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | box v as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:20:5 | -LL | fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { +LL | fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { | -- help: consider adding an explicit lifetime bound `A: 'b`... -LL | box v as Box +LL | box v as Box | ^^^^^ | note: ...so that the type `A` will meet its required lifetime bounds --> $DIR/regions-close-over-type-parameter-1.rs:20:5 | -LL | box v as Box +LL | box v as Box | ^^^^^ error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:20:5 | -LL | fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { +LL | fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { | -- help: consider adding an explicit lifetime bound `A: 'b`... -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | box v as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...so that it can be closed over into an object --> $DIR/regions-close-over-type-parameter-1.rs:20:5 | -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | box v as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors -Some errors occurred: E0309, E0310. +Some errors have detailed explanations: E0309, E0310. For more information about an error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr new file mode 100644 index 0000000000000..88d6abd1428aa --- /dev/null +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5 + | +LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { + | -- -- lifetime `'c` defined here + | | + | lifetime `'a` defined here +LL | // A outlives 'a AND 'b...but not 'c. +LL | box v as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'c` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs b/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs index defbc5d9f2395..26643e08985be 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs @@ -5,19 +5,19 @@ trait SomeTrait { fn get(&self) -> isize; } -fn make_object_good1<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { +fn make_object_good1<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b... - box v as Box // ...hence this type is safe. + box v as Box // ...hence this type is safe. } -fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { +fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b... - box v as Box // ...hence this type is safe. + box v as Box // ...hence this type is safe. } -fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { +fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b...but not 'c. - box v as Box //~ ERROR cannot infer an appropriate lifetime + box v as Box //~ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr index 4803ae8441518..8b3dbc8b64902 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr @@ -1,23 +1,23 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5 | -LL | box v as Box //~ ERROR cannot infer an appropriate lifetime - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | box v as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 18:20... --> $DIR/regions-close-over-type-parameter-multiple.rs:18:20 | -LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { +LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { | ^^ note: ...so that the declared lifetime parameter bounds are satisfied --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5 | -LL | box v as Box //~ ERROR cannot infer an appropriate lifetime - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | box v as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: but, the lifetime must be valid for the lifetime 'c as defined on the function body at 18:26... --> $DIR/regions-close-over-type-parameter-multiple.rs:18:26 | -LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { +LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { | ^^ = note: ...so that the expression is assignable: expected std::boxed::Box<(dyn SomeTrait + 'c)> @@ -25,4 +25,3 @@ LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-close-param-into-object.nll.stderr b/src/test/ui/regions/regions-close-param-into-object.nll.stderr new file mode 100644 index 0000000000000..7bd7824f00a46 --- /dev/null +++ b/src/test/ui/regions/regions-close-param-into-object.nll.stderr @@ -0,0 +1,36 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-param-into-object.rs:6:5 + | +LL | Box::new(v) + | ^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'static`... + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-param-into-object.rs:12:5 + | +LL | Box::new(v) + | ^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'static`... + +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-close-param-into-object.rs:18:5 + | +LL | Box::new(v) + | ^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'a`... + +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-close-param-into-object.rs:24:5 + | +LL | Box::new(v) + | ^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'a`... + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0309, E0310. +For more information about an error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-close-param-into-object.rs b/src/test/ui/regions/regions-close-param-into-object.rs index 86590748cb2d4..2760e5eed9595 100644 --- a/src/test/ui/regions/regions-close-param-into-object.rs +++ b/src/test/ui/regions/regions-close-param-into-object.rs @@ -1,24 +1,24 @@ trait X { fn foo(&self) {} } -fn p1(v: T) -> Box +fn p1(v: T) -> Box where T : X { Box::new(v) //~ ERROR parameter type `T` may not live long enough } -fn p2(v: Box) -> Box +fn p2(v: Box) -> Box where Box : X { Box::new(v) //~ ERROR parameter type `T` may not live long enough } -fn p3<'a,T>(v: T) -> Box +fn p3<'a,T>(v: T) -> Box where T : X { Box::new(v) //~ ERROR parameter type `T` may not live long enough } -fn p4<'a,T>(v: Box) -> Box +fn p4<'a,T>(v: Box) -> Box where Box : X { Box::new(v) //~ ERROR parameter type `T` may not live long enough diff --git a/src/test/ui/regions/regions-close-param-into-object.stderr b/src/test/ui/regions/regions-close-param-into-object.stderr index 58028fc7bd8cc..7f2c646c12196 100644 --- a/src/test/ui/regions/regions-close-param-into-object.stderr +++ b/src/test/ui/regions/regions-close-param-into-object.stderr @@ -1,64 +1,64 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:6:5 | -LL | fn p1(v: T) -> Box +LL | fn p1(v: T) -> Box | - help: consider adding an explicit lifetime bound `T: 'static`... ... -LL | Box::new(v) //~ ERROR parameter type `T` may not live long enough +LL | Box::new(v) | ^^^^^^^^^^^ | note: ...so that the type `T` will meet its required lifetime bounds --> $DIR/regions-close-param-into-object.rs:6:5 | -LL | Box::new(v) //~ ERROR parameter type `T` may not live long enough +LL | Box::new(v) | ^^^^^^^^^^^ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:12:5 | -LL | fn p2(v: Box) -> Box +LL | fn p2(v: Box) -> Box | - help: consider adding an explicit lifetime bound `T: 'static`... ... -LL | Box::new(v) //~ ERROR parameter type `T` may not live long enough +LL | Box::new(v) | ^^^^^^^^^^^ | note: ...so that the type `std::boxed::Box` will meet its required lifetime bounds --> $DIR/regions-close-param-into-object.rs:12:5 | -LL | Box::new(v) //~ ERROR parameter type `T` may not live long enough +LL | Box::new(v) | ^^^^^^^^^^^ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:18:5 | -LL | fn p3<'a,T>(v: T) -> Box +LL | fn p3<'a,T>(v: T) -> Box | - help: consider adding an explicit lifetime bound `T: 'a`... ... -LL | Box::new(v) //~ ERROR parameter type `T` may not live long enough +LL | Box::new(v) | ^^^^^^^^^^^ | note: ...so that the type `T` will meet its required lifetime bounds --> $DIR/regions-close-param-into-object.rs:18:5 | -LL | Box::new(v) //~ ERROR parameter type `T` may not live long enough +LL | Box::new(v) | ^^^^^^^^^^^ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:24:5 | -LL | fn p4<'a,T>(v: Box) -> Box +LL | fn p4<'a,T>(v: Box) -> Box | - help: consider adding an explicit lifetime bound `T: 'a`... ... -LL | Box::new(v) //~ ERROR parameter type `T` may not live long enough +LL | Box::new(v) | ^^^^^^^^^^^ | note: ...so that the type `std::boxed::Box` will meet its required lifetime bounds --> $DIR/regions-close-param-into-object.rs:24:5 | -LL | Box::new(v) //~ ERROR parameter type `T` may not live long enough +LL | Box::new(v) | ^^^^^^^^^^^ error: aborting due to 4 previous errors -Some errors occurred: E0309, E0310. +Some errors have detailed explanations: E0309, E0310. For more information about an error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-creating-enums.nll.stderr b/src/test/ui/regions/regions-creating-enums.nll.stderr deleted file mode 100644 index fe4b97a33b5cf..0000000000000 --- a/src/test/ui/regions/regions-creating-enums.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0515]: cannot return reference to temporary value - --> $DIR/regions-creating-enums.rs:23:16 - | -LL | return &Ast::Num((*f)(x)); //~ ERROR borrowed value does not live long enough - | ^----------------- - | || - | |temporary value created here - | returns a reference to data owned by the current function - -error[E0515]: cannot return reference to temporary value - --> $DIR/regions-creating-enums.rs:28:16 - | -LL | return &Ast::Add(m_x, m_y); //~ ERROR borrowed value does not live long enough - | ^------------------ - | || - | |temporary value created here - | returns a reference to data owned by the current function - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-creating-enums.rs b/src/test/ui/regions/regions-creating-enums.rs index ea8d4373e0931..6ed68f8033ccd 100644 --- a/src/test/ui/regions/regions-creating-enums.rs +++ b/src/test/ui/regions/regions-creating-enums.rs @@ -20,12 +20,12 @@ fn compute(x: &Ast) -> usize { fn map_nums<'a,'b, F>(x: &Ast, f: &mut F) -> &'a Ast<'b> where F: FnMut(usize) -> usize { match *x { Ast::Num(x) => { - return &Ast::Num((*f)(x)); //~ ERROR borrowed value does not live long enough + return &Ast::Num((*f)(x)); //~ ERROR cannot return reference to temporary value } Ast::Add(x, y) => { let m_x = map_nums(x, f); let m_y = map_nums(y, f); - return &Ast::Add(m_x, m_y); //~ ERROR borrowed value does not live long enough + return &Ast::Add(m_x, m_y); //~ ERROR cannot return reference to temporary value } } } diff --git a/src/test/ui/regions/regions-creating-enums.stderr b/src/test/ui/regions/regions-creating-enums.stderr index 36cd6d0c22e5b..a95d84629013e 100644 --- a/src/test/ui/regions/regions-creating-enums.stderr +++ b/src/test/ui/regions/regions-creating-enums.stderr @@ -1,33 +1,21 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/regions-creating-enums.rs:23:17 +error[E0515]: cannot return reference to temporary value + --> $DIR/regions-creating-enums.rs:23:16 | -LL | return &Ast::Num((*f)(x)); //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^^^^^^^^^- temporary value only lives until here - | | - | temporary value does not live long enough - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 20:13... - --> $DIR/regions-creating-enums.rs:20:13 - | -LL | fn map_nums<'a,'b, F>(x: &Ast, f: &mut F) -> &'a Ast<'b> where F: FnMut(usize) -> usize { - | ^^ - = note: consider using a `let` binding to increase its lifetime +LL | return &Ast::Num((*f)(x)); + | ^----------------- + | || + | |temporary value created here + | returns a reference to data owned by the current function -error[E0597]: borrowed value does not live long enough - --> $DIR/regions-creating-enums.rs:28:17 - | -LL | return &Ast::Add(m_x, m_y); //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^^^^^^^^^^- temporary value only lives until here - | | - | temporary value does not live long enough - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 20:13... - --> $DIR/regions-creating-enums.rs:20:13 +error[E0515]: cannot return reference to temporary value + --> $DIR/regions-creating-enums.rs:28:16 | -LL | fn map_nums<'a,'b, F>(x: &Ast, f: &mut F) -> &'a Ast<'b> where F: FnMut(usize) -> usize { - | ^^ - = note: consider using a `let` binding to increase its lifetime +LL | return &Ast::Add(m_x, m_y); + | ^------------------ + | || + | |temporary value created here + | returns a reference to data owned by the current function error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-creating-enums3.nll.stderr b/src/test/ui/regions/regions-creating-enums3.nll.stderr new file mode 100644 index 0000000000000..e35a878fce177 --- /dev/null +++ b/src/test/ui/regions/regions-creating-enums3.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/regions-creating-enums3.rs:7:5 + | +LL | fn mk_add_bad1<'a,'b>(x: &'a Ast<'a>, y: &'b Ast<'b>) -> Ast<'a> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | Ast::Add(x, y) + | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-creating-enums3.stderr b/src/test/ui/regions/regions-creating-enums3.stderr index 2a0efaa598c7c..763b62d945df8 100644 --- a/src/test/ui/regions/regions-creating-enums3.stderr +++ b/src/test/ui/regions/regions-creating-enums3.stderr @@ -5,9 +5,8 @@ LL | fn mk_add_bad1<'a,'b>(x: &'a Ast<'a>, y: &'b Ast<'b>) -> Ast<'a> { | ----------- ------- | | | this parameter and the return type are declared with different lifetimes... -LL | Ast::Add(x, y) //~ ERROR lifetime mismatch [E0623] +LL | Ast::Add(x, y) | ^^^^^^^^^^^^^^ ...but data from `y` is returned here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-creating-enums4.nll.stderr b/src/test/ui/regions/regions-creating-enums4.nll.stderr new file mode 100644 index 0000000000000..4eac457feda2c --- /dev/null +++ b/src/test/ui/regions/regions-creating-enums4.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/regions-creating-enums4.rs:7:5 + | +LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | Ast::Add(x, y) + | ^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-creating-enums4.stderr b/src/test/ui/regions/regions-creating-enums4.stderr index 569530768b837..e13cbe9960ab8 100644 --- a/src/test/ui/regions/regions-creating-enums4.stderr +++ b/src/test/ui/regions/regions-creating-enums4.stderr @@ -1,7 +1,7 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/regions-creating-enums4.rs:7:5 | -LL | Ast::Add(x, y) //~ ERROR cannot infer +LL | Ast::Add(x, y) | ^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 6:16... @@ -23,4 +23,3 @@ LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> { error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-early-bound-error-method.nll.stderr b/src/test/ui/regions/regions-early-bound-error-method.nll.stderr new file mode 100644 index 0000000000000..1540a7bacd7b2 --- /dev/null +++ b/src/test/ui/regions/regions-early-bound-error-method.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/regions-early-bound-error-method.rs:20:9 + | +LL | impl<'a> Box<'a> { + | -- lifetime `'a` defined here +LL | fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize { + | -- lifetime `'b` defined here +LL | g2.get() + | ^^^^^^^^ returning this value requires that `'b` must outlive `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-early-bound-error-method.stderr b/src/test/ui/regions/regions-early-bound-error-method.stderr index 7b9f2c9503b2f..2e5f55f8742cc 100644 --- a/src/test/ui/regions/regions-early-bound-error-method.stderr +++ b/src/test/ui/regions/regions-early-bound-error-method.stderr @@ -17,4 +17,3 @@ LL | fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize { error: aborting due to previous error -For more information about this error, try `rustc --explain E0312`. diff --git a/src/test/ui/regions/regions-early-bound-error.nll.stderr b/src/test/ui/regions/regions-early-bound-error.nll.stderr new file mode 100644 index 0000000000000..7836291a7caab --- /dev/null +++ b/src/test/ui/regions/regions-early-bound-error.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/regions-early-bound-error.rs:19:5 + | +LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | g1.get() + | ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-early-bound-error.stderr b/src/test/ui/regions/regions-early-bound-error.stderr index a68355b78f54c..bc52f4bef7eaa 100644 --- a/src/test/ui/regions/regions-early-bound-error.stderr +++ b/src/test/ui/regions/regions-early-bound-error.stderr @@ -17,4 +17,3 @@ LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize { error: aborting due to previous error -For more information about this error, try `rustc --explain E0312`. diff --git a/src/test/ui/regions/regions-enum-not-wf.stderr b/src/test/ui/regions/regions-enum-not-wf.stderr index d10f7ed28fc2d..8701408566759 100644 --- a/src/test/ui/regions/regions-enum-not-wf.stderr +++ b/src/test/ui/regions/regions-enum-not-wf.stderr @@ -3,13 +3,13 @@ error[E0309]: the parameter type `T` may not live long enough | LL | enum Ref1<'a, T> { | - help: consider adding an explicit lifetime bound `T: 'a`... -LL | Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough +LL | Ref1Variant1(RequireOutlives<'a, T>) | ^^^^^^^^^^^^^^^^^^^^^^ | note: ...so that the type `T` will meet its required lifetime bounds --> $DIR/regions-enum-not-wf.rs:18:18 | -LL | Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough +LL | Ref1Variant1(RequireOutlives<'a, T>) | ^^^^^^^^^^^^^^^^^^^^^^ error[E0309]: the parameter type `T` may not live long enough @@ -18,40 +18,40 @@ error[E0309]: the parameter type `T` may not live long enough LL | enum Ref2<'a, T> { | - help: consider adding an explicit lifetime bound `T: 'a`... LL | Ref2Variant1, -LL | Ref2Variant2(isize, RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough +LL | Ref2Variant2(isize, RequireOutlives<'a, T>), | ^^^^^^^^^^^^^^^^^^^^^^ | note: ...so that the type `T` will meet its required lifetime bounds --> $DIR/regions-enum-not-wf.rs:23:25 | -LL | Ref2Variant2(isize, RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough +LL | Ref2Variant2(isize, RequireOutlives<'a, T>), | ^^^^^^^^^^^^^^^^^^^^^^ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:35:1 | -LL | enum RefDouble<'a, 'b, T> { //~ ERROR the parameter type `T` may not live long enough [E0309] +LL | enum RefDouble<'a, 'b, T> { | ^ - help: consider adding an explicit lifetime bound `T: 'b`... | _| | | LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>) -LL | | //~^ the parameter type `T` may not live long enough [E0309] +LL | | LL | | } | |_^ | note: ...so that the type `T` will meet its required lifetime bounds --> $DIR/regions-enum-not-wf.rs:35:1 | -LL | / enum RefDouble<'a, 'b, T> { //~ ERROR the parameter type `T` may not live long enough [E0309] +LL | / enum RefDouble<'a, 'b, T> { LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>) -LL | | //~^ the parameter type `T` may not live long enough [E0309] +LL | | LL | | } | |_^ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:36:23 | -LL | enum RefDouble<'a, 'b, T> { //~ ERROR the parameter type `T` may not live long enough [E0309] +LL | enum RefDouble<'a, 'b, T> { | - help: consider adding an explicit lifetime bound `T: 'b`... LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/regions/regions-escape-method.nll.stderr b/src/test/ui/regions/regions-escape-method.nll.stderr new file mode 100644 index 0000000000000..9f425125b9896 --- /dev/null +++ b/src/test/ui/regions/regions-escape-method.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/regions-escape-method.rs:15:13 + | +LL | s.f(|p| p) + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 i32 + | has type `&'1 i32` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-escape-method.stderr b/src/test/ui/regions/regions-escape-method.stderr index 8575a24281d05..d867448e1372a 100644 --- a/src/test/ui/regions/regions-escape-method.stderr +++ b/src/test/ui/regions/regions-escape-method.stderr @@ -1,13 +1,13 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/regions-escape-method.rs:15:13 | -LL | s.f(|p| p) //~ ERROR cannot infer +LL | s.f(|p| p) | ^ | note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 15:9... --> $DIR/regions-escape-method.rs:15:9 | -LL | s.f(|p| p) //~ ERROR cannot infer +LL | s.f(|p| p) | ^^^^^ = note: ...so that the expression is assignable: expected &i32 @@ -15,14 +15,13 @@ LL | s.f(|p| p) //~ ERROR cannot infer note: but, the lifetime must be valid for the method call at 15:5... --> $DIR/regions-escape-method.rs:15:5 | -LL | s.f(|p| p) //~ ERROR cannot infer +LL | s.f(|p| p) | ^^^^^^^^^^ note: ...so that a type/lifetime parameter is in scope here --> $DIR/regions-escape-method.rs:15:5 | -LL | s.f(|p| p) //~ ERROR cannot infer +LL | s.f(|p| p) | ^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr b/src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr new file mode 100644 index 0000000000000..cae6c33ac6e17 --- /dev/null +++ b/src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/regions-escape-via-trait-or-not.rs:18:14 + | +LL | with(|o| o) + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 isize + | has type `&'1 isize` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.stderr b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr index 8f4bfd889a836..c8a02683d1000 100644 --- a/src/test/ui/regions/regions-escape-via-trait-or-not.stderr +++ b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr @@ -1,13 +1,13 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/regions-escape-via-trait-or-not.rs:18:14 | -LL | with(|o| o) //~ ERROR cannot infer +LL | with(|o| o) | ^ | note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 18:10... --> $DIR/regions-escape-via-trait-or-not.rs:18:10 | -LL | with(|o| o) //~ ERROR cannot infer +LL | with(|o| o) | ^^^^^ = note: ...so that the expression is assignable: expected &isize @@ -15,14 +15,13 @@ LL | with(|o| o) //~ ERROR cannot infer note: but, the lifetime must be valid for the expression at 18:5... --> $DIR/regions-escape-via-trait-or-not.rs:18:5 | -LL | with(|o| o) //~ ERROR cannot infer +LL | with(|o| o) | ^^^^ note: ...so type `fn([closure@$DIR/regions-escape-via-trait-or-not.rs:18:10: 18:15]) -> isize {with::<&isize, [closure@$DIR/regions-escape-via-trait-or-not.rs:18:10: 18:15]>}` of expression is valid during the expression --> $DIR/regions-escape-via-trait-or-not.rs:18:5 | -LL | with(|o| o) //~ ERROR cannot infer +LL | with(|o| o) | ^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr index 42a5a7c806e08..cda5ce273bd99 100644 --- a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr +++ b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/regions-fn-subtyping-return-static.rs:41:12 | -LL | want_F(bar); //~ ERROR mismatched types +LL | want_F(bar); | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | = note: expected type `for<'cx> fn(&'cx S) -> &'cx S` diff --git a/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr b/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr index e3f42d592283a..3b8f09f1ad80a 100644 --- a/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr @@ -2,7 +2,7 @@ error[E0491]: in type `&'a &'b usize`, reference has a longer lifetime than the --> $DIR/regions-free-region-ordering-callee-4.rs:5:1 | LL | / fn ordering4<'a, 'b, F>(a: &'a usize, b: &'b usize, x: F) where F: FnOnce(&'a &'b usize) { -LL | | //~^ ERROR reference has a longer lifetime than the data it references +LL | | LL | | // Do not infer ordering from closure argument types. LL | | let z: Option<&'a &'b usize> = None; LL | | } diff --git a/src/test/ui/regions/regions-free-region-ordering-callee.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-callee.nll.stderr new file mode 100644 index 0000000000000..9ae484eaf4558 --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-callee.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-callee.rs:13:5 + | +LL | fn ordering2<'a, 'b>(x: &'a &'b usize, y: &'a usize) -> &'b usize { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // However, it is not safe to assume that 'b <= 'a +LL | &*y + | ^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-callee.rs:18:12 + | +LL | fn ordering3<'a, 'b>(x: &'a usize, y: &'b usize) -> &'a &'b usize { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // Do not infer an ordering from the return value. +LL | let z: &'b usize = &*x; + | ^^^^^^^^^ type annotation requires that `'a` must outlive `'b` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/regions/regions-free-region-ordering-callee.stderr b/src/test/ui/regions/regions-free-region-ordering-callee.stderr index b5c66386341a8..49cf1dfc642da 100644 --- a/src/test/ui/regions/regions-free-region-ordering-callee.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-callee.stderr @@ -6,7 +6,7 @@ LL | fn ordering2<'a, 'b>(x: &'a &'b usize, y: &'a usize) -> &'b usize { | | | this parameter and the return type are declared with different lifetimes... LL | // However, it is not safe to assume that 'b <= 'a -LL | &*y //~ ERROR lifetime mismatch [E0623] +LL | &*y | ^^^ ...but data from `x` is returned here error[E0623]: lifetime mismatch @@ -22,4 +22,3 @@ LL | let z: &'b usize = &*x; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.ast.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.ast.stderr deleted file mode 100644 index 73266ab50fad0..0000000000000 --- a/src/test/ui/regions/regions-free-region-ordering-caller.ast.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error[E0623]: lifetime mismatch - --> $DIR/regions-free-region-ordering-caller.rs:11:12 - | -LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { - | --------- --------- - | | - | these two types are declared with different lifetimes... -LL | let z: Option<&'b &'a usize> = None;//[ast]~ ERROR E0623 - | ^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here - -error[E0623]: lifetime mismatch - --> $DIR/regions-free-region-ordering-caller.rs:17:12 - | -LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { - | --------- --------- - | | - | these two types are declared with different lifetimes... -LL | let y: Paramd<'a> = Paramd { x: a }; -LL | let z: Option<&'b Paramd<'a>> = None;//[ast]~ ERROR E0623 - | ^^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here - -error[E0623]: lifetime mismatch - --> $DIR/regions-free-region-ordering-caller.rs:22:12 - | -LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { - | --------- --------- these two types are declared with different lifetimes... -LL | let z: Option<&'a &'b usize> = None;//[ast]~ ERROR E0623 - | ^^^^^^^^^^^^^^^^^^^^^ ...but data from `b` flows into `a` here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr new file mode 100644 index 0000000000000..16eda2844c64c --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr @@ -0,0 +1,33 @@ +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-caller.rs:11:12 + | +LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let z: Option<&'b &'a usize> = None; + | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-caller.rs:17:12 + | +LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let y: Paramd<'a> = Paramd { x: a }; +LL | let z: Option<&'b Paramd<'a>> = None; + | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-caller.rs:22:12 + | +LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let z: Option<&'a &'b usize> = None; + | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr new file mode 100644 index 0000000000000..9d6bae79ce5d8 --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr @@ -0,0 +1,31 @@ +error[E0623]: lifetime mismatch + --> $DIR/regions-free-region-ordering-caller.rs:11:12 + | +LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { + | --------- --------- + | | + | these two types are declared with different lifetimes... +LL | let z: Option<&'b &'a usize> = None; + | ^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here + +error[E0623]: lifetime mismatch + --> $DIR/regions-free-region-ordering-caller.rs:17:12 + | +LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { + | --------- --------- + | | + | these two types are declared with different lifetimes... +LL | let y: Paramd<'a> = Paramd { x: a }; +LL | let z: Option<&'b Paramd<'a>> = None; + | ^^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here + +error[E0623]: lifetime mismatch + --> $DIR/regions-free-region-ordering-caller.rs:22:12 + | +LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { + | --------- --------- these two types are declared with different lifetimes... +LL | let z: Option<&'a &'b usize> = None; + | ^^^^^^^^^^^^^^^^^^^^^ ...but data from `b` flows into `a` here + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.mir.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.mir.stderr deleted file mode 100644 index abec468c9ea3e..0000000000000 --- a/src/test/ui/regions/regions-free-region-ordering-caller.mir.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/regions-free-region-ordering-caller.rs:11:12 - | -LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | let z: Option<&'b &'a usize> = None;//[ast]~ ERROR E0623 - | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` - -error: lifetime may not live long enough - --> $DIR/regions-free-region-ordering-caller.rs:17:12 - | -LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | let y: Paramd<'a> = Paramd { x: a }; -LL | let z: Option<&'b Paramd<'a>> = None;//[ast]~ ERROR E0623 - | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` - -error: lifetime may not live long enough - --> $DIR/regions-free-region-ordering-caller.rs:22:12 - | -LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | let z: Option<&'a &'b usize> = None;//[ast]~ ERROR E0623 - | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` - -error: aborting due to 3 previous errors - diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr new file mode 100644 index 0000000000000..16eda2844c64c --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr @@ -0,0 +1,33 @@ +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-caller.rs:11:12 + | +LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let z: Option<&'b &'a usize> = None; + | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-caller.rs:17:12 + | +LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let y: Paramd<'a> = Paramd { x: a }; +LL | let z: Option<&'b Paramd<'a>> = None; + | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-caller.rs:22:12 + | +LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let z: Option<&'a &'b usize> = None; + | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.rs b/src/test/ui/regions/regions-free-region-ordering-caller.rs index 621e6e78b4650..c0b12f23cdba7 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller.rs +++ b/src/test/ui/regions/regions-free-region-ordering-caller.rs @@ -2,25 +2,25 @@ // than the thing it points at and ensure that they result in // errors. See also regions-free-region-ordering-callee.rs -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir +// revisions: migrate nll +//[nll]compile-flags: -Z borrowck=mir struct Paramd<'a> { x: &'a usize } fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { - let z: Option<&'b &'a usize> = None;//[ast]~ ERROR E0623 - //[mir]~^ ERROR lifetime may not live long enough + let z: Option<&'b &'a usize> = None;//[migrate]~ ERROR E0623 + //[nll]~^ ERROR lifetime may not live long enough } fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { let y: Paramd<'a> = Paramd { x: a }; - let z: Option<&'b Paramd<'a>> = None;//[ast]~ ERROR E0623 - //[mir]~^ ERROR lifetime may not live long enough + let z: Option<&'b Paramd<'a>> = None;//[migrate]~ ERROR E0623 + //[nll]~^ ERROR lifetime may not live long enough } fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { - let z: Option<&'a &'b usize> = None;//[ast]~ ERROR E0623 - //[mir]~^ ERROR lifetime may not live long enough + let z: Option<&'a &'b usize> = None;//[migrate]~ ERROR E0623 + //[nll]~^ ERROR lifetime may not live long enough } fn main() {} diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.stderr deleted file mode 100644 index 67ee950ae8f5a..0000000000000 --- a/src/test/ui/regions/regions-free-region-ordering-caller.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error[E0623]: lifetime mismatch - --> $DIR/regions-free-region-ordering-caller.rs:8:12 - | -LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { - | --------- --------- - | | - | these two types are declared with different lifetimes... -LL | let z: Option<&'b &'a usize> = None;//~ ERROR E0623 - | ^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here - -error[E0623]: lifetime mismatch - --> $DIR/regions-free-region-ordering-caller.rs:13:12 - | -LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { - | --------- --------- - | | - | these two types are declared with different lifetimes... -LL | let y: Paramd<'a> = Paramd { x: a }; -LL | let z: Option<&'b Paramd<'a>> = None;//~ ERROR E0623 - | ^^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here - -error[E0623]: lifetime mismatch - --> $DIR/regions-free-region-ordering-caller.rs:17:12 - | -LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { - | --------- --------- these two types are declared with different lifetimes... -LL | let z: Option<&'a &'b usize> = None;//~ ERROR E0623 - | ^^^^^^^^^^^^^^^^^^^^^ ...but data from `b` flows into `a` here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr deleted file mode 100644 index 539343a68294f..0000000000000 --- a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/regions-free-region-ordering-caller1.rs:9:27 - | -LL | fn call1<'a>(x: &'a usize) { - | -- lifetime `'a` defined here -... -LL | let z: &'a & usize = &(&y); - | ----------- ^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'a` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0597]: `y` does not live long enough - --> $DIR/regions-free-region-ordering-caller1.rs:9:27 - | -LL | fn call1<'a>(x: &'a usize) { - | -- lifetime `'a` defined here -... -LL | let z: &'a & usize = &(&y); - | ----------- ^^^^ borrowed value does not live long enough - | | - | type annotation requires that `y` is borrowed for `'a` -... -LL | } - | - `y` dropped here while still borrowed - -error: aborting due to 2 previous errors - -Some errors occurred: E0597, E0716. -For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.rs b/src/test/ui/regions/regions-free-region-ordering-caller1.rs index d9251c085e1d2..f32455616699f 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller1.rs +++ b/src/test/ui/regions/regions-free-region-ordering-caller1.rs @@ -7,7 +7,7 @@ fn call1<'a>(x: &'a usize) { // &'a &'z usize requires that 'a <= 'z: let y: usize = 3; let z: &'a & usize = &(&y); - //~^ ERROR borrowed value does not live long enough + //~^ ERROR temporary value dropped while borrowed //~^^ ERROR `y` does not live long enough } diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.stderr index 08aaa35e08c48..8042b1740b141 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller1.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-caller1.stderr @@ -1,33 +1,32 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/regions-free-region-ordering-caller1.rs:9:27 | +LL | fn call1<'a>(x: &'a usize) { + | -- lifetime `'a` defined here +... LL | let z: &'a & usize = &(&y); - | ^^^^ temporary value does not live long enough + | ----------- ^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'a` ... LL | } - | - temporary value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 5:10... - --> $DIR/regions-free-region-ordering-caller1.rs:5:10 - | -LL | fn call1<'a>(x: &'a usize) { - | ^^ + | - temporary value is freed at the end of this statement error[E0597]: `y` does not live long enough - --> $DIR/regions-free-region-ordering-caller1.rs:9:29 + --> $DIR/regions-free-region-ordering-caller1.rs:9:27 | +LL | fn call1<'a>(x: &'a usize) { + | -- lifetime `'a` defined here +... LL | let z: &'a & usize = &(&y); - | ^ borrowed value does not live long enough + | ----------- ^^^^ borrowed value does not live long enough + | | + | type annotation requires that `y` is borrowed for `'a` ... LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 5:10... - --> $DIR/regions-free-region-ordering-caller1.rs:5:10 - | -LL | fn call1<'a>(x: &'a usize) { - | ^^ + | - `y` dropped here while still borrowed error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors have detailed explanations: E0597, E0716. +For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr new file mode 100644 index 0000000000000..480a81d33f64c --- /dev/null +++ b/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/regions-free-region-ordering-incorrect.rs:15:9 + | +LL | impl<'b, T> Node<'b, T> { + | -- lifetime `'b` defined here +LL | fn get<'a>(&'a self) -> &'b T { + | -- lifetime `'a` defined here +LL | / match self.next { +LL | | Some(ref next) => next.get(), +LL | | None => &self.val +LL | | } + | |_________^ returning this value requires that `'a` must outlive `'b` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr b/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr index 12e080726763b..5fad6de2a62af 100644 --- a/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr @@ -1,7 +1,7 @@ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements --> $DIR/regions-free-region-ordering-incorrect.rs:17:21 | -LL | None => &self.val //~ ERROR cannot infer +LL | None => &self.val | ^^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime 'a as defined on the method body at 14:12... @@ -12,7 +12,7 @@ LL | fn get<'a>(&'a self) -> &'b T { note: ...so that reference does not outlive borrowed content --> $DIR/regions-free-region-ordering-incorrect.rs:17:21 | -LL | None => &self.val //~ ERROR cannot infer +LL | None => &self.val | ^^^^^^^^^ note: but, the lifetime must be valid for the lifetime 'b as defined on the impl at 13:6... --> $DIR/regions-free-region-ordering-incorrect.rs:13:6 @@ -24,10 +24,9 @@ note: ...so that reference does not outlive borrowed content | LL | / match self.next { LL | | Some(ref next) => next.get(), -LL | | None => &self.val //~ ERROR cannot infer +LL | | None => &self.val LL | | } | |_________^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-glb-free-free.stderr b/src/test/ui/regions/regions-glb-free-free.stderr index 23492b3c718eb..575037a0a4d63 100644 --- a/src/test/ui/regions/regions-glb-free-free.stderr +++ b/src/test/ui/regions/regions-glb-free-free.stderr @@ -3,7 +3,7 @@ error[E0621]: explicit lifetime required in the type of `s` | LL | pub fn set_desc(self, s: &str) -> Flag<'a> { | ---- help: add explicit lifetime `'a` to the type of `s`: `&'a str` -LL | / Flag { //~ ERROR explicit lifetime required in the type of `s` [E0621] +LL | / Flag { LL | | name: self.name, LL | | desc: s, LL | | max_count: self.max_count, diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr new file mode 100644 index 0000000000000..0f0f86dfcdd69 --- /dev/null +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr @@ -0,0 +1,11 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-implied-bounds-projection-gap-1.rs:16:5 + | +LL | wf::<&'x T>(); + | ^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'x`... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs b/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs index 7e04b6782eba1..a4272802af54d 100644 --- a/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs @@ -18,7 +18,7 @@ trait Trait2<'a, 'b> { // this argument `t` is not automatically considered well-formed, // since for it to be WF, we would need to know that `'y: 'x`, but we // do not infer that. -fn callee<'x, 'y, T>(t: &'x for<'z> Trait1< >::Foo >) +fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< >::Foo >) //~^ ERROR reference has a longer lifetime than the data it references { } diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr index e2a4a1eec4253..b3390bcc4d50b 100644 --- a/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr @@ -1,8 +1,8 @@ error[E0491]: in type `&'x (dyn for<'z> Trait1<>::Foo> + 'x)`, reference has a longer lifetime than the data it references --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:1 | -LL | / fn callee<'x, 'y, T>(t: &'x for<'z> Trait1< >::Foo >) -LL | | //~^ ERROR reference has a longer lifetime than the data it references +LL | / fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< >::Foo >) +LL | | LL | | { LL | | } | |_^ @@ -10,12 +10,12 @@ LL | | } note: the pointer is valid for the lifetime 'x as defined on the function body at 21:11 --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:11 | -LL | fn callee<'x, 'y, T>(t: &'x for<'z> Trait1< >::Foo >) +LL | fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< >::Foo >) | ^^ note: but the referenced data is only valid for the lifetime 'y as defined on the function body at 21:15 --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:15 | -LL | fn callee<'x, 'y, T>(t: &'x for<'z> Trait1< >::Foo >) +LL | fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< >::Foo >) | ^^ error: aborting due to previous error diff --git a/src/test/ui/regions/regions-in-enums-anon.stderr b/src/test/ui/regions/regions-in-enums-anon.stderr index 9cfdb67939f12..ae06e7653dbeb 100644 --- a/src/test/ui/regions/regions-in-enums-anon.stderr +++ b/src/test/ui/regions/regions-in-enums-anon.stderr @@ -1,7 +1,7 @@ error[E0106]: missing lifetime specifier --> $DIR/regions-in-enums-anon.rs:4:9 | -LL | Bar(&isize) //~ ERROR missing lifetime specifier +LL | Bar(&isize) | ^ expected lifetime parameter error: aborting due to previous error diff --git a/src/test/ui/regions/regions-in-enums.stderr b/src/test/ui/regions/regions-in-enums.stderr index d0137d1afefbe..cfed9feba4b82 100644 --- a/src/test/ui/regions/regions-in-enums.stderr +++ b/src/test/ui/regions/regions-in-enums.stderr @@ -1,13 +1,13 @@ error[E0261]: use of undeclared lifetime name `'foo` --> $DIR/regions-in-enums.rs:13:9 | -LL | X5(&'foo usize) //~ ERROR use of undeclared lifetime name `'foo` +LL | X5(&'foo usize) | ^^^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-in-enums.rs:17:9 | -LL | X6(&'a usize) //~ ERROR use of undeclared lifetime name `'a` +LL | X6(&'a usize) | ^^ undeclared lifetime error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-in-structs-anon.stderr b/src/test/ui/regions/regions-in-structs-anon.stderr index 9defd82aed596..a1d4ebb597b4c 100644 --- a/src/test/ui/regions/regions-in-structs-anon.stderr +++ b/src/test/ui/regions/regions-in-structs-anon.stderr @@ -1,7 +1,7 @@ error[E0106]: missing lifetime specifier --> $DIR/regions-in-structs-anon.rs:4:8 | -LL | x: &isize //~ ERROR missing lifetime specifier +LL | x: &isize | ^ expected lifetime parameter error: aborting due to previous error diff --git a/src/test/ui/regions/regions-in-structs.stderr b/src/test/ui/regions/regions-in-structs.stderr index dea7f1054183e..8314942759d1a 100644 --- a/src/test/ui/regions/regions-in-structs.stderr +++ b/src/test/ui/regions/regions-in-structs.stderr @@ -1,13 +1,13 @@ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-in-structs.rs:10:9 | -LL | a: &'a isize, //~ ERROR use of undeclared lifetime name `'a` +LL | a: &'a isize, | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-in-structs.rs:11:9 | -LL | b: &'a isize, //~ ERROR use of undeclared lifetime name `'a` +LL | b: &'a isize, | ^^ undeclared lifetime error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-infer-at-fn-not-param.rs b/src/test/ui/regions/regions-infer-at-fn-not-param.rs index 0fd734d57b5ce..fb9c5d5c210c9 100644 --- a/src/test/ui/regions/regions-infer-at-fn-not-param.rs +++ b/src/test/ui/regions/regions-infer-at-fn-not-param.rs @@ -1,13 +1,13 @@ struct Parameterized1<'a> { - g: Box + g: Box } struct NotParameterized1 { - g: Box + g: Box } struct NotParameterized2 { - g: Box + g: Box } fn take1<'a>(p: Parameterized1) -> Parameterized1<'a> { p } diff --git a/src/test/ui/regions/regions-infer-borrow-scope-too-big.nll.stderr b/src/test/ui/regions/regions-infer-borrow-scope-too-big.nll.stderr deleted file mode 100644 index 62f0ceba94f29..0000000000000 --- a/src/test/ui/regions/regions-infer-borrow-scope-too-big.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0515]: cannot return value referencing local data `*p` - --> $DIR/regions-infer-borrow-scope-too-big.rs:13:12 - | -LL | let xc = x_coord(&*p); //~ ERROR `*p` does not live long enough - | --- `*p` is borrowed here -LL | assert_eq!(*xc, 3); -LL | return xc; - | ^^ returns a value referencing data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-infer-borrow-scope-too-big.rs b/src/test/ui/regions/regions-infer-borrow-scope-too-big.rs index 3bf1c67da9971..250b41da5788a 100644 --- a/src/test/ui/regions/regions-infer-borrow-scope-too-big.rs +++ b/src/test/ui/regions/regions-infer-borrow-scope-too-big.rs @@ -8,9 +8,9 @@ fn x_coord<'r>(p: &'r Point) -> &'r isize { } fn foo<'a>(p: Box) -> &'a isize { - let xc = x_coord(&*p); //~ ERROR `*p` does not live long enough + let xc = x_coord(&*p); assert_eq!(*xc, 3); - return xc; + return xc; //~ ERROR cannot return value referencing local data `*p` } fn main() {} diff --git a/src/test/ui/regions/regions-infer-borrow-scope-too-big.stderr b/src/test/ui/regions/regions-infer-borrow-scope-too-big.stderr index 562ec649a48ec..2c7a6e8b5c0b9 100644 --- a/src/test/ui/regions/regions-infer-borrow-scope-too-big.stderr +++ b/src/test/ui/regions/regions-infer-borrow-scope-too-big.stderr @@ -1,18 +1,12 @@ -error[E0597]: `*p` does not live long enough - --> $DIR/regions-infer-borrow-scope-too-big.rs:11:23 +error[E0515]: cannot return value referencing local data `*p` + --> $DIR/regions-infer-borrow-scope-too-big.rs:13:12 | -LL | let xc = x_coord(&*p); //~ ERROR `*p` does not live long enough - | ^^ borrowed value does not live long enough -... -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 10:8... - --> $DIR/regions-infer-borrow-scope-too-big.rs:10:8 - | -LL | fn foo<'a>(p: Box) -> &'a isize { - | ^^ +LL | let xc = x_coord(&*p); + | --- `*p` is borrowed here +LL | assert_eq!(*xc, 3); +LL | return xc; + | ^^ returns a value referencing data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-infer-bound-from-trait-self.nll.stderr b/src/test/ui/regions/regions-infer-bound-from-trait-self.nll.stderr new file mode 100644 index 0000000000000..0651e305cde35 --- /dev/null +++ b/src/test/ui/regions/regions-infer-bound-from-trait-self.nll.stderr @@ -0,0 +1,11 @@ +error[E0309]: the parameter type `Self` may not live long enough + --> $DIR/regions-infer-bound-from-trait-self.rs:46:9 + | +LL | check_bound(x, self) + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `Self: 'a`... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr b/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr new file mode 100644 index 0000000000000..1f7b34fc69962 --- /dev/null +++ b/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr @@ -0,0 +1,19 @@ +error[E0309]: the parameter type `A` may not live long enough + --> $DIR/regions-infer-bound-from-trait.rs:33:5 + | +LL | check_bound(x, a) + | ^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `A: 'a`... + +error[E0309]: the parameter type `A` may not live long enough + --> $DIR/regions-infer-bound-from-trait.rs:37:5 + | +LL | check_bound(x, a) + | ^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `A: 'a`... + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-infer-bound-from-trait.stderr b/src/test/ui/regions/regions-infer-bound-from-trait.stderr index 100ac7633584e..382d932e81add 100644 --- a/src/test/ui/regions/regions-infer-bound-from-trait.stderr +++ b/src/test/ui/regions/regions-infer-bound-from-trait.stderr @@ -3,13 +3,13 @@ error[E0309]: the parameter type `A` may not live long enough | LL | fn bar1<'a,A>(x: Inv<'a>, a: A) { | - help: consider adding an explicit lifetime bound `A: 'a`... -LL | check_bound(x, a) //~ ERROR parameter type `A` may not live long enough +LL | check_bound(x, a) | ^^^^^^^^^^^ | note: ...so that the type `A` will meet its required lifetime bounds --> $DIR/regions-infer-bound-from-trait.rs:33:5 | -LL | check_bound(x, a) //~ ERROR parameter type `A` may not live long enough +LL | check_bound(x, a) | ^^^^^^^^^^^ error[E0309]: the parameter type `A` may not live long enough @@ -17,13 +17,13 @@ error[E0309]: the parameter type `A` may not live long enough | LL | fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) { | -- help: consider adding an explicit lifetime bound `A: 'a`... -LL | check_bound(x, a) //~ ERROR parameter type `A` may not live long enough +LL | check_bound(x, a) | ^^^^^^^^^^^ | note: ...so that the type `A` will meet its required lifetime bounds --> $DIR/regions-infer-bound-from-trait.rs:37:5 | -LL | check_bound(x, a) //~ ERROR parameter type `A` may not live long enough +LL | check_bound(x, a) | ^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-infer-call-3.nll.stderr b/src/test/ui/regions/regions-infer-call-3.nll.stderr new file mode 100644 index 0000000000000..ca51555a07749 --- /dev/null +++ b/src/test/ui/regions/regions-infer-call-3.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-call-3.rs:8:24 + | +LL | let z = with(|y| { select(x, y) }); + | -- ^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 isize + | has type `&'1 isize` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-call-3.stderr b/src/test/ui/regions/regions-infer-call-3.stderr index 1d6dbdb2c7b57..151c8307a14f6 100644 --- a/src/test/ui/regions/regions-infer-call-3.stderr +++ b/src/test/ui/regions/regions-infer-call-3.stderr @@ -27,4 +27,3 @@ LL | let z = with(|y| { select(x, y) }); error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-infer-contravariance-due-to-decl.nll.stderr b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.nll.stderr new file mode 100644 index 0000000000000..cefeecf16e2d4 --- /dev/null +++ b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-contravariance-due-to-decl.rs:25:12 + | +LL | fn use_<'short,'long>(c: Contravariant<'short>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: Contravariant<'long> = c; + | ^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-contravariance-due-to-decl.stderr b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.stderr index 9dafc16808664..9374818960d36 100644 --- a/src/test/ui/regions/regions-infer-contravariance-due-to-decl.stderr +++ b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.stderr @@ -7,9 +7,8 @@ LL | s: &'short isize, LL | l: &'long isize, | ------------ ... -LL | let _: Contravariant<'long> = c; //~ ERROR E0623 +LL | let _: Contravariant<'long> = c; | ^ ...but data from `c` flows into `l` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-infer-covariance-due-to-decl.nll.stderr b/src/test/ui/regions/regions-infer-covariance-due-to-decl.nll.stderr new file mode 100644 index 0000000000000..1bddecba50a72 --- /dev/null +++ b/src/test/ui/regions/regions-infer-covariance-due-to-decl.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-covariance-due-to-decl.rs:22:12 + | +LL | fn use_<'short,'long>(c: Covariant<'long>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: Covariant<'short> = c; + | ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-covariance-due-to-decl.stderr b/src/test/ui/regions/regions-infer-covariance-due-to-decl.stderr index a474270366611..cd0a18a892f20 100644 --- a/src/test/ui/regions/regions-infer-covariance-due-to-decl.stderr +++ b/src/test/ui/regions/regions-infer-covariance-due-to-decl.stderr @@ -6,9 +6,8 @@ LL | fn use_<'short,'long>(c: Covariant<'long>, LL | s: &'short isize, | ------------- these two types are declared with different lifetimes... ... -LL | let _: Covariant<'short> = c; //~ ERROR E0623 +LL | let _: Covariant<'short> = c; | ^ ...but data from `s` flows into `c` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr new file mode 100644 index 0000000000000..0c1e3989b234a --- /dev/null +++ b/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-invariance-due-to-decl.rs:12:5 + | +LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { + | -- lifetime `'r` defined here +LL | b_isize + | ^^^^^^^ returning this value requires that `'r` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr index 8d8c218958a27..d31ed3ede36fa 100644 --- a/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr +++ b/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/regions-infer-invariance-due-to-decl.rs:12:5 | -LL | b_isize //~ ERROR mismatched types +LL | b_isize | ^^^^^^^ lifetime mismatch | = note: expected type `Invariant<'static>` diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr new file mode 100644 index 0000000000000..0edeb2723998f --- /dev/null +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:10:5 + | +LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { + | -- lifetime `'r` defined here +LL | b_isize + | ^^^^^^^ returning this value requires that `'r` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.rs b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.rs index 168bf0284a18e..5843598ab48e4 100644 --- a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.rs +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.rs @@ -1,5 +1,5 @@ struct Invariant<'a> { - f: Box, + f: Box, } fn to_same_lifetime<'r>(b_isize: Invariant<'r>) { diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr index 7058757f908ed..f8bdd014db7c6 100644 --- a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:10:5 | -LL | b_isize //~ ERROR mismatched types +LL | b_isize | ^^^^^^^ lifetime mismatch | = note: expected type `Invariant<'static>` diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr new file mode 100644 index 0000000000000..724dd7e3f6d3f --- /dev/null +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:10:5 + | +LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { + | -- lifetime `'r` defined here +LL | b_isize + | ^^^^^^^ returning this value requires that `'r` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.rs b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.rs index 90c86cebce38f..f0af18cf61804 100644 --- a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.rs +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.rs @@ -1,5 +1,5 @@ struct Invariant<'a> { - f: Box *mut &'a isize + 'static>, + f: Box *mut &'a isize + 'static>, } fn to_same_lifetime<'r>(b_isize: Invariant<'r>) { diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr index 51b2330b658f4..1de6f22f08e50 100644 --- a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:10:5 | -LL | b_isize //~ ERROR mismatched types +LL | b_isize | ^^^^^^^ lifetime mismatch | = note: expected type `Invariant<'static>` diff --git a/src/test/ui/regions/regions-infer-not-param.nll.stderr b/src/test/ui/regions/regions-infer-not-param.nll.stderr new file mode 100644 index 0000000000000..2064b060ec419 --- /dev/null +++ b/src/test/ui/regions/regions-infer-not-param.nll.stderr @@ -0,0 +1,26 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-not-param.rs:15:54 + | +LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } + | -- -- lifetime `'b` defined here ^ returning this value requires that `'a` must outlive `'b` + | | + | lifetime `'a` defined here + +error: lifetime may not live long enough + --> $DIR/regions-infer-not-param.rs:19:63 + | +LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } + | -- -- lifetime `'b` defined here ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | | + | lifetime `'a` defined here + +error: lifetime may not live long enough + --> $DIR/regions-infer-not-param.rs:19:63 + | +LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } + | -- -- lifetime `'b` defined here ^ returning this value requires that `'a` must outlive `'b` + | | + | lifetime `'a` defined here + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/regions/regions-infer-not-param.rs b/src/test/ui/regions/regions-infer-not-param.rs index 214402952a3db..d1744f8a51eee 100644 --- a/src/test/ui/regions/regions-infer-not-param.rs +++ b/src/test/ui/regions/regions-infer-not-param.rs @@ -4,12 +4,12 @@ struct Direct<'a> { struct Indirect1 { // Here the lifetime parameter of direct is bound by the fn() - g: Box + g: Box } struct Indirect2<'a> { // But here it is set to 'a - g: Box) + 'static> + g: Box) + 'static> } fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } //~ ERROR mismatched types diff --git a/src/test/ui/regions/regions-infer-not-param.stderr b/src/test/ui/regions/regions-infer-not-param.stderr index d0d41c271c6bd..f43ab82912187 100644 --- a/src/test/ui/regions/regions-infer-not-param.stderr +++ b/src/test/ui/regions/regions-infer-not-param.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/regions-infer-not-param.rs:15:54 | -LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } //~ ERROR mismatched types +LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } | ^ lifetime mismatch | = note: expected type `Direct<'b>` @@ -9,18 +9,18 @@ LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } //~ ERROR mismatch note: the lifetime 'a as defined on the function body at 15:16... --> $DIR/regions-infer-not-param.rs:15:16 | -LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } //~ ERROR mismatched types +LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } | ^^ note: ...does not necessarily outlive the lifetime 'b as defined on the function body at 15:19 --> $DIR/regions-infer-not-param.rs:15:19 | -LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } //~ ERROR mismatched types +LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } | ^^ error[E0308]: mismatched types --> $DIR/regions-infer-not-param.rs:19:63 | -LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } //~ ERROR mismatched types +LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } | ^ lifetime mismatch | = note: expected type `Indirect2<'b>` @@ -28,18 +28,18 @@ LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } //~ ERROR note: the lifetime 'a as defined on the function body at 19:19... --> $DIR/regions-infer-not-param.rs:19:19 | -LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } //~ ERROR mismatched types +LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } | ^^ note: ...does not necessarily outlive the lifetime 'b as defined on the function body at 19:22 --> $DIR/regions-infer-not-param.rs:19:22 | -LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } //~ ERROR mismatched types +LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } | ^^ error[E0308]: mismatched types --> $DIR/regions-infer-not-param.rs:19:63 | -LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } //~ ERROR mismatched types +LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } | ^ lifetime mismatch | = note: expected type `Indirect2<'b>` @@ -47,12 +47,12 @@ LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } //~ ERROR note: the lifetime 'b as defined on the function body at 19:22... --> $DIR/regions-infer-not-param.rs:19:22 | -LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } //~ ERROR mismatched types +LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } | ^^ note: ...does not necessarily outlive the lifetime 'a as defined on the function body at 19:19 --> $DIR/regions-infer-not-param.rs:19:19 | -LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } //~ ERROR mismatched types +LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } | ^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr b/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr new file mode 100644 index 0000000000000..a86e6ccdc5edf --- /dev/null +++ b/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/regions-infer-paramd-indirect.rs:22:9 + | +LL | impl<'a> SetF<'a> for C<'a> { + | -- lifetime `'a` defined here +... +LL | fn set_f_bad(&mut self, b: Box) { + | - has type `std::boxed::Box>` +LL | self.f = b; + | ^^^^^^ assignment requires that `'1` must outlive `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.stderr b/src/test/ui/regions/regions-infer-paramd-indirect.stderr index 47de228e31d24..1b999ed059c40 100644 --- a/src/test/ui/regions/regions-infer-paramd-indirect.stderr +++ b/src/test/ui/regions/regions-infer-paramd-indirect.stderr @@ -11,10 +11,10 @@ note: the anonymous lifetime #2 defined on the method body at 21:5... | LL | / fn set_f_bad(&mut self, b: Box) { LL | | self.f = b; -LL | | //~^ ERROR mismatched types -LL | | //~| expected type `std::boxed::Box>` -LL | | //~| found type `std::boxed::Box>` -LL | | //~| lifetime mismatch +LL | | +LL | | +LL | | +LL | | LL | | } | |_____^ note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 16:6 diff --git a/src/test/ui/regions/regions-infer-proc-static-upvar.nll.stderr b/src/test/ui/regions/regions-infer-proc-static-upvar.nll.stderr deleted file mode 100644 index b44f8c1e7a8dd..0000000000000 --- a/src/test/ui/regions/regions-infer-proc-static-upvar.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0597]: `x` does not live long enough - --> $DIR/regions-infer-proc-static-upvar.rs:10:13 - | -LL | let y = &x; //~ ERROR `x` does not live long enough - | ^^ borrowed value does not live long enough -LL | / foo(move|| { -LL | | let _a = *y; -LL | | }); - | |______- argument requires that `x` is borrowed for `'static` -LL | } - | - `x` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-infer-proc-static-upvar.stderr b/src/test/ui/regions/regions-infer-proc-static-upvar.stderr index f929a06bad75d..803d0d7449108 100644 --- a/src/test/ui/regions/regions-infer-proc-static-upvar.stderr +++ b/src/test/ui/regions/regions-infer-proc-static-upvar.stderr @@ -1,13 +1,14 @@ error[E0597]: `x` does not live long enough - --> $DIR/regions-infer-proc-static-upvar.rs:10:14 + --> $DIR/regions-infer-proc-static-upvar.rs:10:13 | -LL | let y = &x; //~ ERROR `x` does not live long enough - | ^ borrowed value does not live long enough -... -LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... +LL | let y = &x; + | ^^ borrowed value does not live long enough +LL | / foo(move|| { +LL | | let _a = *y; +LL | | }); + | |______- argument requires that `x` is borrowed for `'static` +LL | } + | - `x` dropped here while still borrowed error: aborting due to previous error diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr new file mode 100644 index 0000000000000..e1f14fc0cd919 --- /dev/null +++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43 + | +LL | let _: fn(&mut &isize, &mut &isize) = a; + | ^ expected concrete lifetime, found bound lifetime parameter + | + = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` + found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr index 99d85e9e4b5a6..0c3c342728c01 100644 --- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr +++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr @@ -4,7 +4,7 @@ error[E0623]: lifetime mismatch LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) { | --------- --------- these two types are declared with different lifetimes... LL | // Illegal now because there is no `'b:'a` declaration. -LL | *x = *y; //~ ERROR E0623 +LL | *x = *y; | ^^ ...but data from `y` flows into `x` here error[E0623]: lifetime mismatch @@ -13,13 +13,13 @@ error[E0623]: lifetime mismatch LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { | --------- --------- these two types are declared with different lifetimes... ... -LL | a(x, y); //~ ERROR lifetime mismatch [E0623] +LL | a(x, y); | ^ ...but data from `y` flows into `x` here error[E0308]: mismatched types --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43 | -LL | let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0308 +LL | let _: fn(&mut &isize, &mut &isize) = a; | ^ expected concrete lifetime, found bound lifetime parameter | = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` @@ -27,5 +27,4 @@ LL | let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0308 error: aborting due to 3 previous errors -Some errors occurred: E0308, E0623. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.nll.stderr b/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.nll.stderr deleted file mode 100644 index 48daff1dbd872..0000000000000 --- a/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0515]: cannot return value referencing temporary value - --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:16:3 - | -LL | let testValue = &id(Test); - | -------- temporary value created here -LL | //~^ ERROR borrowed value does not live long enough -LL | testValue - | ^^^^^^^^^ returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing temporary value - --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:22:3 - | -LL | let testValue = &id(MyEnum::Variant1); - | -------------------- temporary value created here -LL | //~^ ERROR borrowed value does not live long enough -LL | testValue - | ^^^^^^^^^ returns a value referencing data owned by the current function - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.rs b/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.rs index 2d21a51108381..1b25294c7e161 100644 --- a/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.rs +++ b/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.rs @@ -12,14 +12,14 @@ enum MyEnum { fn structLifetime<'a>() -> &'a Test { let testValue = &id(Test); - //~^ ERROR borrowed value does not live long enough testValue + //~^ ERROR cannot return value referencing temporary value } fn variantLifetime<'a>() -> &'a MyEnum { let testValue = &id(MyEnum::Variant1); - //~^ ERROR borrowed value does not live long enough testValue + //~^ ERROR cannot return value referencing temporary value } diff --git a/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.stderr b/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.stderr index c0bfc475f1960..b4bf2ab312d30 100644 --- a/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.stderr +++ b/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.stderr @@ -1,33 +1,19 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:14:20 +error[E0515]: cannot return value referencing temporary value + --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:15:3 | LL | let testValue = &id(Test); - | ^^^^^^^^ temporary value does not live long enough -... -LL | } - | - temporary value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:19... - --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:13:19 - | -LL | fn structLifetime<'a>() -> &'a Test { - | ^^ + | -------- temporary value created here +LL | testValue + | ^^^^^^^^^ returns a value referencing data owned by the current function -error[E0597]: borrowed value does not live long enough - --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:20:20 +error[E0515]: cannot return value referencing temporary value + --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:21:3 | LL | let testValue = &id(MyEnum::Variant1); - | ^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -... -LL | } - | - temporary value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 19:20... - --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:19:20 - | -LL | fn variantLifetime<'a>() -> &'a MyEnum { - | ^^ + | -------------------- temporary value created here +LL | testValue + | ^^^^^^^^^ returns a value referencing data owned by the current function error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-name-duplicated.stderr b/src/test/ui/regions/regions-name-duplicated.stderr index 1b552006a934d..a7e03a61adcf5 100644 --- a/src/test/ui/regions/regions-name-duplicated.stderr +++ b/src/test/ui/regions/regions-name-duplicated.stderr @@ -1,7 +1,7 @@ error[E0263]: lifetime name `'a` declared twice in the same scope --> $DIR/regions-name-duplicated.rs:1:16 | -LL | struct Foo<'a, 'a> { //~ ERROR lifetime name `'a` declared twice +LL | struct Foo<'a, 'a> { | -- ^^ declared twice | | | previous declaration here diff --git a/src/test/ui/regions/regions-name-static.stderr b/src/test/ui/regions/regions-name-static.stderr index bf7b021f9fe58..4b7026e65eacc 100644 --- a/src/test/ui/regions/regions-name-static.stderr +++ b/src/test/ui/regions/regions-name-static.stderr @@ -1,7 +1,7 @@ error[E0262]: invalid lifetime parameter name: `'static` --> $DIR/regions-name-static.rs:1:12 | -LL | struct Foo<'static> { //~ ERROR invalid lifetime parameter name: `'static` +LL | struct Foo<'static> { | ^^^^^^^ 'static is a reserved lifetime name error: aborting due to previous error diff --git a/src/test/ui/regions/regions-name-undeclared.rs b/src/test/ui/regions/regions-name-undeclared.rs index 230a97a04b625..044c688977262 100644 --- a/src/test/ui/regions/regions-name-undeclared.rs +++ b/src/test/ui/regions/regions-name-undeclared.rs @@ -33,14 +33,14 @@ fn bar<'a>(x: &'a isize) { // &'a CAN be declared on functions and used then: fn g<'a>(a: &'a isize) { } // OK - fn h(a: Box FnOnce(&'a isize)>) { } // OK + fn h(a: Box FnOnce(&'a isize)>) { } // OK } // Test nesting of lifetimes in fn type declarations fn fn_types(a: &'a isize, //~ ERROR undeclared lifetime - b: Box FnOnce(&'a isize, + b: Box FnOnce(&'a isize, &'b isize, //~ ERROR undeclared lifetime - Box FnOnce(&'a isize, + Box FnOnce(&'a isize, &'b isize)>, &'b isize)>, //~ ERROR undeclared lifetime c: &'a isize) //~ ERROR undeclared lifetime diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index 7b041d5dad5eb..4840d751f7f57 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -1,67 +1,67 @@ error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:15:24 | -LL | fn m4(&self, arg: &'b isize) { } //~ ERROR undeclared lifetime +LL | fn m4(&self, arg: &'b isize) { } | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:16:12 | -LL | fn m5(&'b self) { } //~ ERROR undeclared lifetime +LL | fn m5(&'b self) { } | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:17:27 | -LL | fn m6(&self, arg: Foo<'b>) { } //~ ERROR undeclared lifetime +LL | fn m6(&self, arg: Foo<'b>) { } | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:25:22 | -LL | type X = Option<&'a isize>; //~ ERROR undeclared lifetime +LL | type X = Option<&'a isize>; | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:27:13 | -LL | E1(&'a isize) //~ ERROR undeclared lifetime +LL | E1(&'a isize) | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:30:13 | -LL | f: &'a isize //~ ERROR undeclared lifetime +LL | f: &'a isize | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:32:14 | -LL | fn f(a: &'a isize) { } //~ ERROR undeclared lifetime +LL | fn f(a: &'a isize) { } | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:40:17 | -LL | fn fn_types(a: &'a isize, //~ ERROR undeclared lifetime +LL | fn fn_types(a: &'a isize, | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:42:36 | -LL | &'b isize, //~ ERROR undeclared lifetime +LL | &'b isize, | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:45:36 | -LL | &'b isize)>, //~ ERROR undeclared lifetime +LL | &'b isize)>, | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:46:17 | -LL | c: &'a isize) //~ ERROR undeclared lifetime +LL | c: &'a isize) | ^^ undeclared lifetime error: aborting due to 11 previous errors diff --git a/src/test/ui/regions/regions-nested-fns-2.nll.stderr b/src/test/ui/regions/regions-nested-fns-2.nll.stderr deleted file mode 100644 index ebcc31d3a20e9..0000000000000 --- a/src/test/ui/regions/regions-nested-fns-2.nll.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0597]: `y` does not live long enough - --> $DIR/regions-nested-fns-2.rs:8:25 - | -LL | |z| { - | --- value captured here -LL | //~^ ERROR E0373 -LL | if false { &y } else { z } - | -^ - | || - | |borrowed value does not live long enough - | returning this value requires that `y` is borrowed for `'static` -LL | }); -LL | } - | - `y` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-nested-fns-2.rs b/src/test/ui/regions/regions-nested-fns-2.rs index 1b51880f4159b..3b3e26c4503d4 100644 --- a/src/test/ui/regions/regions-nested-fns-2.rs +++ b/src/test/ui/regions/regions-nested-fns-2.rs @@ -4,8 +4,8 @@ fn nested() { let y = 3; ignore( |z| { - //~^ ERROR E0373 if false { &y } else { z } + //~^ ERROR `y` does not live long enough }); } diff --git a/src/test/ui/regions/regions-nested-fns-2.stderr b/src/test/ui/regions/regions-nested-fns-2.stderr index 924eac6fdd41e..43c8d1272c744 100644 --- a/src/test/ui/regions/regions-nested-fns-2.stderr +++ b/src/test/ui/regions/regions-nested-fns-2.stderr @@ -1,16 +1,17 @@ -error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function - --> $DIR/regions-nested-fns-2.rs:6:9 +error[E0597]: `y` does not live long enough + --> $DIR/regions-nested-fns-2.rs:7:25 | LL | |z| { - | ^^^ may outlive borrowed value `y` -LL | //~^ ERROR E0373 + | --- value captured here LL | if false { &y } else { z } - | - `y` is borrowed here -help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword - | -LL | move |z| { - | ^^^^^^^^ + | -^ + | || + | |borrowed value does not live long enough + | returning this value requires that `y` is borrowed for `'static` +... +LL | } + | - `y` dropped here while still borrowed error: aborting due to previous error -For more information about this error, try `rustc --explain E0373`. +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-nested-fns.nll.stderr b/src/test/ui/regions/regions-nested-fns.nll.stderr new file mode 100644 index 0000000000000..97650636cb67f --- /dev/null +++ b/src/test/ui/regions/regions-nested-fns.nll.stderr @@ -0,0 +1,51 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/regions-nested-fns.rs:10:9 + | +LL | let mut ay = &y; + | ------ `ay` is declared here, outside of the closure body +LL | +LL | ignore:: FnMut(&'z isize)>>(Box::new(|z| { + | - `z` is a reference that is only valid in the closure body +... +LL | ay = z; + | ^^^^^^ `z` escapes the closure body here + +error[E0597]: `y` does not live long enough + --> $DIR/regions-nested-fns.rs:5:18 + | +LL | let mut ay = &y; + | ^^ borrowed value does not live long enough +... +LL | if false { return ay; } + | -- returning this value requires that `y` is borrowed for `'static` +... +LL | } + | - `y` dropped here while still borrowed + +error[E0597]: `y` does not live long enough + --> $DIR/regions-nested-fns.rs:9:15 + | +LL | ignore:: FnMut(&'z isize)>>(Box::new(|z| { + | --- value captured here +LL | ay = x; +LL | ay = &y; + | ^ borrowed value does not live long enough +... +LL | if false { return ay; } + | -- returning this value requires that `y` is borrowed for `'static` +... +LL | } + | - `y` dropped here while still borrowed + +error: lifetime may not live long enough + --> $DIR/regions-nested-fns.rs:14:27 + | +LL | fn nested<'x>(x: &'x isize) { + | -- lifetime `'x` defined here +... +LL | if false { return x; } + | ^ returning this value requires that `'x` must outlive `'static` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-nested-fns.rs b/src/test/ui/regions/regions-nested-fns.rs index 161d812f016a6..c02d4e0ce453b 100644 --- a/src/test/ui/regions/regions-nested-fns.rs +++ b/src/test/ui/regions/regions-nested-fns.rs @@ -4,13 +4,13 @@ fn nested<'x>(x: &'x isize) { let y = 3; let mut ay = &y; //~ ERROR E0495 - ignore:: FnMut(&'z isize)>>(Box::new(|z| { + ignore:: FnMut(&'z isize)>>(Box::new(|z| { ay = x; ay = &y; ay = z; })); - ignore::< Box FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { + ignore::< Box FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { if false { return x; } //~ ERROR E0312 if false { return ay; } return z; diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr index d6d4c44de61dd..15c9c9ca4ddbb 100644 --- a/src/test/ui/regions/regions-nested-fns.stderr +++ b/src/test/ui/regions/regions-nested-fns.stderr @@ -1,14 +1,14 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/regions-nested-fns.rs:5:18 | -LL | let mut ay = &y; //~ ERROR E0495 +LL | let mut ay = &y; | ^^ | -note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 7:54... - --> $DIR/regions-nested-fns.rs:7:54 +note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 7:58... + --> $DIR/regions-nested-fns.rs:7:58 | -LL | ignore:: FnMut(&'z isize)>>(Box::new(|z| { - | ______________________________________________________^ +LL | ignore:: FnMut(&'z isize)>>(Box::new(|z| { + | __________________________________________________________^ LL | | ay = x; LL | | ay = &y; LL | | ay = z; @@ -19,12 +19,12 @@ note: ...so that reference does not outlive borrowed content | LL | ay = z; | ^ -note: but, the lifetime must be valid for the anonymous lifetime #2 defined on the body at 13:68... - --> $DIR/regions-nested-fns.rs:13:68 +note: but, the lifetime must be valid for the anonymous lifetime #2 defined on the body at 13:72... + --> $DIR/regions-nested-fns.rs:13:72 | -LL | ignore::< Box FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { - | ____________________________________________________________________^ -LL | | if false { return x; } //~ ERROR E0312 +LL | ignore::< Box FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { + | ________________________________________________________________________^ +LL | | if false { return x; } LL | | if false { return ay; } LL | | return z; LL | | })); @@ -36,15 +36,15 @@ LL | | })); error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/regions-nested-fns.rs:14:27 | -LL | if false { return x; } //~ ERROR E0312 +LL | if false { return x; } | ^ | -note: ...the reference is valid for the anonymous lifetime #2 defined on the body at 13:68... - --> $DIR/regions-nested-fns.rs:13:68 +note: ...the reference is valid for the anonymous lifetime #2 defined on the body at 13:72... + --> $DIR/regions-nested-fns.rs:13:72 | -LL | ignore::< Box FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { - | ____________________________________________________________________^ -LL | | if false { return x; } //~ ERROR E0312 +LL | ignore::< Box FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { + | ________________________________________________________________________^ +LL | | if false { return x; } LL | | if false { return ay; } LL | | return z; LL | | })); @@ -57,5 +57,3 @@ LL | fn nested<'x>(x: &'x isize) { error: aborting due to 2 previous errors -Some errors occurred: E0312, E0495. -For more information about an error, try `rustc --explain E0312`. diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr index a4197eed22524..912e118316271 100644 --- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -1,7 +1,7 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/regions-normalize-in-where-clause-list.rs:22:1 | -LL | / fn bar<'a, 'b>() //~ ERROR cannot infer +LL | / fn bar<'a, 'b>() LL | | where <() as Project<'a, 'b>>::Item : Eq LL | | { LL | | } @@ -10,12 +10,12 @@ LL | | } note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 22:8... --> $DIR/regions-normalize-in-where-clause-list.rs:22:8 | -LL | fn bar<'a, 'b>() //~ ERROR cannot infer +LL | fn bar<'a, 'b>() | ^^ note: ...but the lifetime must also be valid for the lifetime 'b as defined on the function body at 22:12... --> $DIR/regions-normalize-in-where-clause-list.rs:22:12 | -LL | fn bar<'a, 'b>() //~ ERROR cannot infer +LL | fn bar<'a, 'b>() | ^^ = note: ...so that the types are compatible: expected Project<'a, 'b> @@ -23,4 +23,3 @@ LL | fn bar<'a, 'b>() //~ ERROR cannot infer error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.mir.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr similarity index 100% rename from src/test/ui/regions/regions-outlives-projection-container-hrtb.mir.stderr rename to src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.ast.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr similarity index 100% rename from src/test/ui/regions/regions-outlives-projection-container-hrtb.ast.stderr rename to src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr new file mode 100644 index 0000000000000..5028663ba6d04 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container-hrtb.rs:35:12 + | +LL | fn with_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _: &'a WithHrAssoc> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container-hrtb.rs:57:12 + | +LL | fn with_assoc_sub<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _: &'a WithHrAssocSub> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs b/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs index 2871d962c42c9..407a4fdf59bb7 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs +++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs @@ -1,8 +1,8 @@ // Test that structs with higher-ranked where clauses don't generate // "outlives" requirements. Issue #22246. -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir +// revisions: migrate nll +//[nll]compile-flags: -Z borrowck=mir #![allow(dead_code)] @@ -33,8 +33,8 @@ fn with_assoc<'a,'b>() { // We get an error because 'b:'a does not hold: let _: &'a WithHrAssoc> = loop { }; - //[ast]~^ ERROR reference has a longer lifetime - //[mir]~^^ ERROR lifetime may not live long enough + //[migrate]~^ ERROR reference has a longer lifetime + //[nll]~^^ ERROR lifetime may not live long enough } /////////////////////////////////////////////////////////////////////////// @@ -55,8 +55,8 @@ fn with_assoc_sub<'a,'b>() { // below to be well-formed, it is not related to the HR relation. let _: &'a WithHrAssocSub> = loop { }; - //[ast]~^ ERROR reference has a longer lifetime - //[mir]~^^ ERROR lifetime may not live long enough + //[migrate]~^ ERROR reference has a longer lifetime + //[nll]~^^ ERROR lifetime may not live long enough } diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.stderr deleted file mode 100644 index 856e28f141f10..0000000000000 --- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error[E0491]: in type `&'a WithHrAssoc>`, reference has a longer lifetime than the data it references - --> $DIR/regions-outlives-projection-container-hrtb.rs:32:12 - | -LL | let _: &'a WithHrAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the pointer is valid for the lifetime 'a as defined on the function body at 29:15 - --> $DIR/regions-outlives-projection-container-hrtb.rs:29:15 - | -LL | fn with_assoc<'a,'b>() { - | ^^ -note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 29:18 - --> $DIR/regions-outlives-projection-container-hrtb.rs:29:18 - | -LL | fn with_assoc<'a,'b>() { - | ^^ - -error[E0491]: in type `&'a WithHrAssocSub>`, reference has a longer lifetime than the data it references - --> $DIR/regions-outlives-projection-container-hrtb.rs:53:12 - | -LL | let _: &'a WithHrAssocSub> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the pointer is valid for the lifetime 'a as defined on the function body at 49:19 - --> $DIR/regions-outlives-projection-container-hrtb.rs:49:19 - | -LL | fn with_assoc_sub<'a,'b>() { - | ^^ -note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 49:22 - --> $DIR/regions-outlives-projection-container-hrtb.rs:49:22 - | -LL | fn with_assoc_sub<'a,'b>() { - | ^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0491`. diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.mir.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr similarity index 100% rename from src/test/ui/regions/regions-outlives-projection-container-wc.mir.stderr rename to src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.ast.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr similarity index 100% rename from src/test/ui/regions/regions-outlives-projection-container-wc.ast.stderr rename to src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr new file mode 100644 index 0000000000000..880fe17b740e4 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container-wc.rs:37:12 + | +LL | fn with_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _: &'a WithAssoc> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.rs b/src/test/ui/regions/regions-outlives-projection-container-wc.rs index 37622211327c0..5037ea536dae9 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-wc.rs +++ b/src/test/ui/regions/regions-outlives-projection-container-wc.rs @@ -3,8 +3,8 @@ // outlive the location in which the type appears, even when the // constraint is in a where clause not a bound. Issue #22246. -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir +// revisions: migrate nll +//[nll]compile-flags: -Z borrowck=mir #![allow(dead_code)] @@ -35,8 +35,8 @@ fn with_assoc<'a,'b>() { // which is &'b (), must outlive 'a. let _: &'a WithAssoc> = loop { }; - //[ast]~^ ERROR reference has a longer lifetime - //[mir]~^^ ERROR lifetime may not live long enough + //[migrate]~^ ERROR reference has a longer lifetime + //[nll]~^^ ERROR lifetime may not live long enough } fn main() { diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.stderr deleted file mode 100644 index 0d73d3d64322e..0000000000000 --- a/src/test/ui/regions/regions-outlives-projection-container-wc.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0491]: in type `&'a WithAssoc>`, reference has a longer lifetime than the data it references - --> $DIR/regions-outlives-projection-container-wc.rs:34:12 - | -LL | let _: &'a WithAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the pointer is valid for the lifetime 'a as defined on the function body at 28:15 - --> $DIR/regions-outlives-projection-container-wc.rs:28:15 - | -LL | fn with_assoc<'a,'b>() { - | ^^ -note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 28:18 - --> $DIR/regions-outlives-projection-container-wc.rs:28:18 - | -LL | fn with_assoc<'a,'b>() { - | ^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0491`. diff --git a/src/test/ui/regions/regions-outlives-projection-container.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container.nll.stderr new file mode 100644 index 0000000000000..ef87d02ec0812 --- /dev/null +++ b/src/test/ui/regions/regions-outlives-projection-container.nll.stderr @@ -0,0 +1,46 @@ +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container.rs:40:13 + | +LL | fn with_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _x: &'a WithAssoc> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container.rs:58:13 + | +LL | fn without_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _x: &'a WithoutAssoc> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container.rs:67:5 + | +LL | fn call_with_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | call::<&'a WithAssoc>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` + +error: lifetime may not live long enough + --> $DIR/regions-outlives-projection-container.rs:74:5 + | +LL | fn call_without_assoc<'a,'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | call::<&'a WithoutAssoc>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/regions/regions-outlives-projection-container.stderr b/src/test/ui/regions/regions-outlives-projection-container.stderr index 884314f421a1a..b50347ac96427 100644 --- a/src/test/ui/regions/regions-outlives-projection-container.stderr +++ b/src/test/ui/regions/regions-outlives-projection-container.stderr @@ -52,7 +52,7 @@ LL | fn call_with_assoc<'a,'b>() { error[E0491]: in type `&'a WithoutAssoc>`, reference has a longer lifetime than the data it references --> $DIR/regions-outlives-projection-container.rs:74:12 | -LL | call::<&'a WithoutAssoc>>(); //~ ERROR reference has a longer lifetime +LL | call::<&'a WithoutAssoc>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime 'a as defined on the function body at 71:23 diff --git a/src/test/ui/regions/regions-pattern-typing-issue-19552.nll.stderr b/src/test/ui/regions/regions-pattern-typing-issue-19552.nll.stderr deleted file mode 100644 index 8809cf4b09e52..0000000000000 --- a/src/test/ui/regions/regions-pattern-typing-issue-19552.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0597]: `line` does not live long enough - --> $DIR/regions-pattern-typing-issue-19552.rs:5:14 - | -LL | match [&*line] { //~ ERROR `line` does not live long enough - | ^^^^ borrowed value does not live long enough -LL | [ word ] => { assert_static(word); } - | ------------------- argument requires that `line` is borrowed for `'static` -LL | } -LL | } - | - `line` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-pattern-typing-issue-19552.stderr b/src/test/ui/regions/regions-pattern-typing-issue-19552.stderr index ad80925cad7d2..f77d94a24b88f 100644 --- a/src/test/ui/regions/regions-pattern-typing-issue-19552.stderr +++ b/src/test/ui/regions/regions-pattern-typing-issue-19552.stderr @@ -1,13 +1,13 @@ error[E0597]: `line` does not live long enough --> $DIR/regions-pattern-typing-issue-19552.rs:5:14 | -LL | match [&*line] { //~ ERROR `line` does not live long enough +LL | match [&*line] { | ^^^^ borrowed value does not live long enough -... +LL | [ word ] => { assert_static(word); } + | ------------------- argument requires that `line` is borrowed for `'static` +LL | } LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - `line` dropped here while still borrowed error: aborting due to previous error diff --git a/src/test/ui/regions/regions-pattern-typing-issue-19997.ast.nll.stderr b/src/test/ui/regions/regions-pattern-typing-issue-19997.ast.nll.stderr deleted file mode 100644 index 935620075f7c6..0000000000000 --- a/src/test/ui/regions/regions-pattern-typing-issue-19997.ast.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0506]: cannot assign to `a1` because it is borrowed - --> $DIR/regions-pattern-typing-issue-19997.rs:10:13 - | -LL | match (&a1,) { - | --- borrow of `a1` occurs here -LL | (&ref b0,) => { -LL | a1 = &f; //[ast]~ ERROR cannot assign - | ^^^^^^^ assignment to borrowed `a1` occurs here -LL | //[mir]~^ ERROR cannot assign to `a1` because it is borrowed -LL | drop(b0); - | -- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/regions/regions-pattern-typing-issue-19997.ast.stderr b/src/test/ui/regions/regions-pattern-typing-issue-19997.ast.stderr deleted file mode 100644 index e23c6ada2b565..0000000000000 --- a/src/test/ui/regions/regions-pattern-typing-issue-19997.ast.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0506]: cannot assign to `a1` because it is borrowed - --> $DIR/regions-pattern-typing-issue-19997.rs:10:13 - | -LL | match (&a1,) { - | -- borrow of `a1` occurs here -LL | (&ref b0,) => { -LL | a1 = &f; //[ast]~ ERROR cannot assign - | ^^^^^^^ assignment to borrowed `a1` occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/regions/regions-pattern-typing-issue-19997.mir.stderr b/src/test/ui/regions/regions-pattern-typing-issue-19997.mir.stderr deleted file mode 100644 index 935620075f7c6..0000000000000 --- a/src/test/ui/regions/regions-pattern-typing-issue-19997.mir.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0506]: cannot assign to `a1` because it is borrowed - --> $DIR/regions-pattern-typing-issue-19997.rs:10:13 - | -LL | match (&a1,) { - | --- borrow of `a1` occurs here -LL | (&ref b0,) => { -LL | a1 = &f; //[ast]~ ERROR cannot assign - | ^^^^^^^ assignment to borrowed `a1` occurs here -LL | //[mir]~^ ERROR cannot assign to `a1` because it is borrowed -LL | drop(b0); - | -- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/regions/regions-pattern-typing-issue-19997.rs b/src/test/ui/regions/regions-pattern-typing-issue-19997.rs index 35f38af0cfef1..39190697fe70e 100644 --- a/src/test/ui/regions/regions-pattern-typing-issue-19997.rs +++ b/src/test/ui/regions/regions-pattern-typing-issue-19997.rs @@ -1,14 +1,10 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - fn main() { let a0 = 0; let f = 1; let mut a1 = &a0; match (&a1,) { (&ref b0,) => { - a1 = &f; //[ast]~ ERROR cannot assign - //[mir]~^ ERROR cannot assign to `a1` because it is borrowed + a1 = &f; //~ ERROR cannot assign to `a1` because it is borrowed drop(b0); } } diff --git a/src/test/ui/regions/regions-pattern-typing-issue-19997.stderr b/src/test/ui/regions/regions-pattern-typing-issue-19997.stderr new file mode 100644 index 0000000000000..ae60e3c0d5d67 --- /dev/null +++ b/src/test/ui/regions/regions-pattern-typing-issue-19997.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `a1` because it is borrowed + --> $DIR/regions-pattern-typing-issue-19997.rs:7:13 + | +LL | match (&a1,) { + | --- borrow of `a1` occurs here +LL | (&ref b0,) => { +LL | a1 = &f; + | ^^^^^^^ assignment to borrowed `a1` occurs here +LL | drop(b0); + | -- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/regions/regions-proc-bound-capture.rs b/src/test/ui/regions/regions-proc-bound-capture.rs index f2010dbe62d8d..0c903b7384992 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.rs +++ b/src/test/ui/regions/regions-proc-bound-capture.rs @@ -1,10 +1,10 @@ -fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> { +fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> { // This is legal, because the region bound on `proc` // states that it captures `x`. Box::new(move|| { *x }) } -fn static_proc(x: &isize) -> Box(isize) + 'static> { +fn static_proc(x: &isize) -> Box(isize) + 'static> { // This is illegal, because the region bound on `proc` is 'static. Box::new(move|| { *x }) //~ ERROR explicit lifetime required in the type of `x` [E0621] } diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index 31be3ab4d3d5b..c53af34456ef3 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -1,10 +1,10 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/regions-proc-bound-capture.rs:9:5 | -LL | fn static_proc(x: &isize) -> Box(isize) + 'static> { +LL | fn static_proc(x: &isize) -> Box(isize) + 'static> { | ------ help: add explicit lifetime `'static` to the type of `x`: `&'static isize` LL | // This is illegal, because the region bound on `proc` is 'static. -LL | Box::new(move|| { *x }) //~ ERROR explicit lifetime required in the type of `x` [E0621] +LL | Box::new(move|| { *x }) | ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required error: aborting due to previous error diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.nll.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.nll.stderr new file mode 100644 index 0000000000000..c8582f8bfe7f0 --- /dev/null +++ b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:4:5 + | +LL | fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | &mut ***p + | ^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.stderr index 5670e5305ebbe..ead448df930fe 100644 --- a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.stderr +++ b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.stderr @@ -5,9 +5,8 @@ LL | fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b m | ----------------------------- ------------- | | | this parameter and the return type are declared with different lifetimes... -LL | &mut ***p //~ ERROR lifetime mismatch [E0623] +LL | &mut ***p | ^^^^^^^^^ ...but data from `p` is returned here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.nll.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.nll.stderr new file mode 100644 index 0000000000000..5946e7bf84950 --- /dev/null +++ b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:6:5 + | +LL | fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | &mut **p + | ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.stderr index 90004e27d95c7..064e89ee001c1 100644 --- a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.stderr +++ b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.stderr @@ -5,9 +5,8 @@ LL | fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize { | --------------------- ------------- | | | this parameter and the return type are declared with different lifetimes... -LL | &mut **p //~ ERROR lifetime mismatch [E0623] +LL | &mut **p | ^^^^^^^^ ...but data from `p` is returned here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-ref-in-fn-arg.nll.stderr b/src/test/ui/regions/regions-ref-in-fn-arg.nll.stderr deleted file mode 100644 index bead12356f1f2..0000000000000 --- a/src/test/ui/regions/regions-ref-in-fn-arg.nll.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0515]: cannot return value referencing function parameter - --> $DIR/regions-ref-in-fn-arg.rs:5:5 - | -LL | fn arg_item(box ref x: Box) -> &'static isize { - | --------- function parameter borrowed here -LL | x //~^ ERROR borrowed value does not live long enough - | ^ returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing function parameter - --> $DIR/regions-ref-in-fn-arg.rs:11:22 - | -LL | with(|box ref x| x) //~ ERROR borrowed value does not live long enough - | --------- ^ returns a value referencing data owned by the current function - | | - | function parameter borrowed here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-ref-in-fn-arg.rs b/src/test/ui/regions/regions-ref-in-fn-arg.rs index cf9e7b27ed0af..d1cbd279b65a5 100644 --- a/src/test/ui/regions/regions-ref-in-fn-arg.rs +++ b/src/test/ui/regions/regions-ref-in-fn-arg.rs @@ -2,13 +2,13 @@ #![feature(box_syntax)] fn arg_item(box ref x: Box) -> &'static isize { - x //~^ ERROR borrowed value does not live long enough + x //~ ERROR cannot return value referencing function parameter } fn with(f: F) -> R where F: FnOnce(Box) -> R { f(box 3) } fn arg_closure() -> &'static isize { - with(|box ref x| x) //~ ERROR borrowed value does not live long enough + with(|box ref x| x) //~ ERROR cannot return value referencing function parameter } fn main() {} diff --git a/src/test/ui/regions/regions-ref-in-fn-arg.stderr b/src/test/ui/regions/regions-ref-in-fn-arg.stderr index 748508ecbcd39..ccba6c59b616e 100644 --- a/src/test/ui/regions/regions-ref-in-fn-arg.stderr +++ b/src/test/ui/regions/regions-ref-in-fn-arg.stderr @@ -1,24 +1,19 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/regions-ref-in-fn-arg.rs:4:17 +error[E0515]: cannot return value referencing function parameter + --> $DIR/regions-ref-in-fn-arg.rs:5:5 | LL | fn arg_item(box ref x: Box) -> &'static isize { - | ^^^^^ borrowed value does not live long enough -LL | x //~^ ERROR borrowed value does not live long enough -LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | --------- function parameter borrowed here +LL | x + | ^ returns a value referencing data owned by the current function -error[E0597]: borrowed value does not live long enough - --> $DIR/regions-ref-in-fn-arg.rs:11:15 - | -LL | with(|box ref x| x) //~ ERROR borrowed value does not live long enough - | ^^^^^ - borrowed value only lives until here - | | - | borrowed value does not live long enough +error[E0515]: cannot return value referencing function parameter + --> $DIR/regions-ref-in-fn-arg.rs:11:22 | - = note: borrowed value must be valid for the static lifetime... +LL | with(|box ref x| x) + | --------- ^ returns a value referencing data owned by the current function + | | + | function parameter borrowed here error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-ret-borrowed-1.nll.stderr b/src/test/ui/regions/regions-ret-borrowed-1.nll.stderr new file mode 100644 index 0000000000000..0784e894ea920 --- /dev/null +++ b/src/test/ui/regions/regions-ret-borrowed-1.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/regions-ret-borrowed-1.rs:10:14 + | +LL | with(|o| o) + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 isize + | has type `&'1 isize` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr index 72e47cea094c5..403af2a9e6a44 100644 --- a/src/test/ui/regions/regions-ret-borrowed-1.stderr +++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr @@ -25,4 +25,3 @@ LL | with(|o| o) error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-ret-borrowed.nll.stderr b/src/test/ui/regions/regions-ret-borrowed.nll.stderr new file mode 100644 index 0000000000000..d9be5ef89cceb --- /dev/null +++ b/src/test/ui/regions/regions-ret-borrowed.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/regions-ret-borrowed.rs:13:14 + | +LL | with(|o| o) + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 isize + | has type `&'1 isize` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr index ce0c429ccb247..5d1f26da6c783 100644 --- a/src/test/ui/regions/regions-ret-borrowed.stderr +++ b/src/test/ui/regions/regions-ret-borrowed.stderr @@ -25,4 +25,3 @@ LL | with(|o| o) error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-ret.nll.stderr b/src/test/ui/regions/regions-ret.nll.stderr deleted file mode 100644 index b8b4ce56bb249..0000000000000 --- a/src/test/ui/regions/regions-ret.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0515]: cannot return reference to temporary value - --> $DIR/regions-ret.rs:4:12 - | -LL | return &id(3); //~ ERROR borrowed value does not live long enough - | ^----- - | || - | |temporary value created here - | returns a reference to data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-ret.rs b/src/test/ui/regions/regions-ret.rs index a094d1af5b709..580545ef8566c 100644 --- a/src/test/ui/regions/regions-ret.rs +++ b/src/test/ui/regions/regions-ret.rs @@ -1,7 +1,7 @@ fn id(x: T) -> T { x } fn f(_x: &isize) -> &isize { - return &id(3); //~ ERROR borrowed value does not live long enough + return &id(3); //~ ERROR cannot return reference to temporary value } fn main() { diff --git a/src/test/ui/regions/regions-ret.stderr b/src/test/ui/regions/regions-ret.stderr index 001f62ab60cde..0e4875ac9855b 100644 --- a/src/test/ui/regions/regions-ret.stderr +++ b/src/test/ui/regions/regions-ret.stderr @@ -1,20 +1,12 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/regions-ret.rs:4:13 +error[E0515]: cannot return reference to temporary value + --> $DIR/regions-ret.rs:4:12 | -LL | return &id(3); //~ ERROR borrowed value does not live long enough - | ^^^^^- temporary value only lives until here - | | - | temporary value does not live long enough - | -note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 3:1... - --> $DIR/regions-ret.rs:3:1 - | -LL | / fn f(_x: &isize) -> &isize { -LL | | return &id(3); //~ ERROR borrowed value does not live long enough -LL | | } - | |_^ - = note: consider using a `let` binding to increase its lifetime +LL | return &id(3); + | ^----- + | || + | |temporary value created here + | returns a reference to data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr new file mode 100644 index 0000000000000..4c275b19492c6 --- /dev/null +++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr @@ -0,0 +1,13 @@ +error: captured variable cannot escape `FnMut` closure body + --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24 + | +LL | let mut f = || &mut x; + | - ^^^^^^ returns a reference to a captured variable which escapes the closure body + | | + | inferred to be a `FnMut` closure + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr index e4b14811d9075..291b8367f7b75 100644 --- a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr +++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr @@ -1,18 +1,18 @@ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24 | -LL | let mut f = || &mut x; //~ ERROR cannot infer +LL | let mut f = || &mut x; | ^^^^^^ | -note: first, the lifetime cannot outlive the lifetime as defined on the body at 7:21... +note: first, the lifetime cannot outlive the lifetime '_ as defined on the body at 7:21... --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:21 | -LL | let mut f = || &mut x; //~ ERROR cannot infer +LL | let mut f = || &mut x; | ^^^^^^^^^ note: ...so that closure can access `x` --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24 | -LL | let mut f = || &mut x; //~ ERROR cannot infer +LL | let mut f = || &mut x; | ^^^^^^ note: but, the lifetime must be valid for the call at 9:17... --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:9:17 @@ -27,4 +27,3 @@ LL | let y = f(); error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-return-stack-allocated-vec.nll.stderr b/src/test/ui/regions/regions-return-stack-allocated-vec.nll.stderr deleted file mode 100644 index 1bdcf83521d0a..0000000000000 --- a/src/test/ui/regions/regions-return-stack-allocated-vec.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0515]: cannot return reference to temporary value - --> $DIR/regions-return-stack-allocated-vec.rs:4:5 - | -LL | &[x] //~ ERROR borrowed value does not live long enough - | ^--- - | || - | |temporary value created here - | returns a reference to data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-return-stack-allocated-vec.rs b/src/test/ui/regions/regions-return-stack-allocated-vec.rs index 8d071dbc60695..97fbdbf46851e 100644 --- a/src/test/ui/regions/regions-return-stack-allocated-vec.rs +++ b/src/test/ui/regions/regions-return-stack-allocated-vec.rs @@ -1,7 +1,7 @@ // Test that we cannot return a stack allocated slice fn function(x: isize) -> &'static [isize] { - &[x] //~ ERROR borrowed value does not live long enough + &[x] //~ ERROR cannot return reference to temporary value } fn main() { diff --git a/src/test/ui/regions/regions-return-stack-allocated-vec.stderr b/src/test/ui/regions/regions-return-stack-allocated-vec.stderr index 78eec7cc456e8..9d87fe266b158 100644 --- a/src/test/ui/regions/regions-return-stack-allocated-vec.stderr +++ b/src/test/ui/regions/regions-return-stack-allocated-vec.stderr @@ -1,13 +1,12 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/regions-return-stack-allocated-vec.rs:4:6 +error[E0515]: cannot return reference to temporary value + --> $DIR/regions-return-stack-allocated-vec.rs:4:5 | -LL | &[x] //~ ERROR borrowed value does not live long enough - | ^^^ temporary value does not live long enough -LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... +LL | &[x] + | ^--- + | || + | |temporary value created here + | returns a reference to data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-static-bound.ll.nll.stderr b/src/test/ui/regions/regions-static-bound.ll.nll.stderr new file mode 100644 index 0000000000000..d6cec03e0ff2e --- /dev/null +++ b/src/test/ui/regions/regions-static-bound.ll.nll.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/regions-static-bound.rs:9:5 + | +LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { + | -- lifetime `'a` defined here +LL | t //[ll]~ ERROR E0312 + | ^ returning this value requires that `'a` must outlive `'static` + +error[E0621]: explicit lifetime required in the type of `u` + --> $DIR/regions-static-bound.rs:14:5 + | +LL | fn error(u: &(), v: &()) { + | --- help: add explicit lifetime `'static` to the type of `u`: `&'static ()` +LL | static_id(&u); //[ll]~ ERROR explicit lifetime required in the type of `u` [E0621] + | ^^^^^^^^^^^^^ lifetime `'static` required + +error[E0621]: explicit lifetime required in the type of `v` + --> $DIR/regions-static-bound.rs:16:5 + | +LL | fn error(u: &(), v: &()) { + | --- help: add explicit lifetime `'static` to the type of `v`: `&'static ()` +... +LL | static_id_indirect(&v); //[ll]~ ERROR explicit lifetime required in the type of `v` [E0621] + | ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/regions/regions-static-bound.ll.stderr b/src/test/ui/regions/regions-static-bound.ll.stderr deleted file mode 100644 index 4695a82ebb4cd..0000000000000 --- a/src/test/ui/regions/regions-static-bound.ll.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0312]: lifetime of reference outlives lifetime of borrowed content... - --> $DIR/regions-static-bound.rs:9:5 - | -LL | t //[ll]~ ERROR E0312 - | ^ - | - = note: ...the reference is valid for the static lifetime... -note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 8:24 - --> $DIR/regions-static-bound.rs:8:24 - | -LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { - | ^^ - -error[E0621]: explicit lifetime required in the type of `u` - --> $DIR/regions-static-bound.rs:14:5 - | -LL | fn error(u: &(), v: &()) { - | --- help: add explicit lifetime `'static` to the type of `u`: `&'static ()` -LL | static_id(&u); //[ll]~ ERROR explicit lifetime required in the type of `u` [E0621] - | ^^^^^^^^^ lifetime `'static` required - -error[E0621]: explicit lifetime required in the type of `v` - --> $DIR/regions-static-bound.rs:16:5 - | -LL | fn error(u: &(), v: &()) { - | --- help: add explicit lifetime `'static` to the type of `v`: `&'static ()` -... -LL | static_id_indirect(&v); //[ll]~ ERROR explicit lifetime required in the type of `v` [E0621] - | ^^^^^^^^^^^^^^^^^^ lifetime `'static` required - -error: aborting due to 3 previous errors - -Some errors occurred: E0312, E0621. -For more information about an error, try `rustc --explain E0312`. diff --git a/src/test/ui/regions/regions-static-bound.migrate.nll.stderr b/src/test/ui/regions/regions-static-bound.migrate.nll.stderr new file mode 100644 index 0000000000000..b5f3e6cfaba09 --- /dev/null +++ b/src/test/ui/regions/regions-static-bound.migrate.nll.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/regions-static-bound.rs:9:5 + | +LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { + | -- lifetime `'a` defined here +LL | t + | ^ returning this value requires that `'a` must outlive `'static` + +error[E0621]: explicit lifetime required in the type of `u` + --> $DIR/regions-static-bound.rs:14:5 + | +LL | fn error(u: &(), v: &()) { + | --- help: add explicit lifetime `'static` to the type of `u`: `&'static ()` +LL | static_id(&u); + | ^^^^^^^^^^^^^ lifetime `'static` required + +error[E0621]: explicit lifetime required in the type of `v` + --> $DIR/regions-static-bound.rs:16:5 + | +LL | fn error(u: &(), v: &()) { + | --- help: add explicit lifetime `'static` to the type of `v`: `&'static ()` +... +LL | static_id_indirect(&v); + | ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/regions/regions-static-bound.migrate.stderr b/src/test/ui/regions/regions-static-bound.migrate.stderr new file mode 100644 index 0000000000000..fc8cca929d389 --- /dev/null +++ b/src/test/ui/regions/regions-static-bound.migrate.stderr @@ -0,0 +1,33 @@ +error[E0312]: lifetime of reference outlives lifetime of borrowed content... + --> $DIR/regions-static-bound.rs:9:5 + | +LL | t + | ^ + | + = note: ...the reference is valid for the static lifetime... +note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 8:24 + --> $DIR/regions-static-bound.rs:8:24 + | +LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { + | ^^ + +error[E0621]: explicit lifetime required in the type of `u` + --> $DIR/regions-static-bound.rs:14:5 + | +LL | fn error(u: &(), v: &()) { + | --- help: add explicit lifetime `'static` to the type of `u`: `&'static ()` +LL | static_id(&u); + | ^^^^^^^^^ lifetime `'static` required + +error[E0621]: explicit lifetime required in the type of `v` + --> $DIR/regions-static-bound.rs:16:5 + | +LL | fn error(u: &(), v: &()) { + | --- help: add explicit lifetime `'static` to the type of `v`: `&'static ()` +... +LL | static_id_indirect(&v); + | ^^^^^^^^^^^^^^^^^^ lifetime `'static` required + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/regions/regions-static-bound.nll.stderr b/src/test/ui/regions/regions-static-bound.nll.stderr index d6cec03e0ff2e..b5f3e6cfaba09 100644 --- a/src/test/ui/regions/regions-static-bound.nll.stderr +++ b/src/test/ui/regions/regions-static-bound.nll.stderr @@ -3,7 +3,7 @@ error: lifetime may not live long enough | LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { | -- lifetime `'a` defined here -LL | t //[ll]~ ERROR E0312 +LL | t | ^ returning this value requires that `'a` must outlive `'static` error[E0621]: explicit lifetime required in the type of `u` @@ -11,7 +11,7 @@ error[E0621]: explicit lifetime required in the type of `u` | LL | fn error(u: &(), v: &()) { | --- help: add explicit lifetime `'static` to the type of `u`: `&'static ()` -LL | static_id(&u); //[ll]~ ERROR explicit lifetime required in the type of `u` [E0621] +LL | static_id(&u); | ^^^^^^^^^^^^^ lifetime `'static` required error[E0621]: explicit lifetime required in the type of `v` @@ -20,7 +20,7 @@ error[E0621]: explicit lifetime required in the type of `v` LL | fn error(u: &(), v: &()) { | --- help: add explicit lifetime `'static` to the type of `v`: `&'static ()` ... -LL | static_id_indirect(&v); //[ll]~ ERROR explicit lifetime required in the type of `v` [E0621] +LL | static_id_indirect(&v); | ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required error: aborting due to 3 previous errors diff --git a/src/test/ui/regions/regions-static-bound.rs b/src/test/ui/regions/regions-static-bound.rs index c1a15e50a4d06..1db54881d3e03 100644 --- a/src/test/ui/regions/regions-static-bound.rs +++ b/src/test/ui/regions/regions-static-bound.rs @@ -1,4 +1,4 @@ -// revisions: ll nll +// revisions: migrate nll //[nll] compile-flags:-Zborrowck=mir fn static_id<'a,'b>(t: &'a ()) -> &'static () @@ -6,14 +6,14 @@ fn static_id<'a,'b>(t: &'a ()) -> &'static () fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () where 'a: 'b, 'b: 'static { t } fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { - t //[ll]~ ERROR E0312 + t //[migrate]~ ERROR E0312 //[nll]~^ ERROR lifetime may not live long enough } fn error(u: &(), v: &()) { - static_id(&u); //[ll]~ ERROR explicit lifetime required in the type of `u` [E0621] + static_id(&u); //[migrate]~ ERROR explicit lifetime required in the type of `u` [E0621] //[nll]~^ ERROR explicit lifetime required in the type of `u` [E0621] - static_id_indirect(&v); //[ll]~ ERROR explicit lifetime required in the type of `v` [E0621] + static_id_indirect(&v); //[migrate]~ ERROR explicit lifetime required in the type of `v` [E0621] //[nll]~^ ERROR explicit lifetime required in the type of `v` [E0621] } diff --git a/src/test/ui/regions/regions-steal-closure.nll.stderr b/src/test/ui/regions/regions-steal-closure.nll.stderr deleted file mode 100644 index c30f9c52363a6..0000000000000 --- a/src/test/ui/regions/regions-steal-closure.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0597]: `i` does not live long enough - --> $DIR/regions-steal-closure.rs:14:28 - | -LL | let mut cl_box = { - | ---------- borrow later stored here -LL | let mut i = 3; -LL | box_it(Box::new(|| i += 1)) //~ ERROR `i` does not live long enough - | -- ^ borrowed value does not live long enough - | | - | value captured here -LL | }; - | - `i` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-steal-closure.rs b/src/test/ui/regions/regions-steal-closure.rs index e6b34510bb567..83e93522c9483 100644 --- a/src/test/ui/regions/regions-steal-closure.rs +++ b/src/test/ui/regions/regions-steal-closure.rs @@ -1,10 +1,10 @@ #![feature(fn_traits)] struct ClosureBox<'a> { - cl: Box, + cl: Box, } -fn box_it<'r>(x: Box) -> ClosureBox<'r> { +fn box_it<'r>(x: Box) -> ClosureBox<'r> { ClosureBox {cl: x} } diff --git a/src/test/ui/regions/regions-steal-closure.stderr b/src/test/ui/regions/regions-steal-closure.stderr index dc5c167153525..5b0efaf95597d 100644 --- a/src/test/ui/regions/regions-steal-closure.stderr +++ b/src/test/ui/regions/regions-steal-closure.stderr @@ -1,15 +1,15 @@ error[E0597]: `i` does not live long enough --> $DIR/regions-steal-closure.rs:14:28 | -LL | box_it(Box::new(|| i += 1)) //~ ERROR `i` does not live long enough +LL | let mut cl_box = { + | ---------- borrow later stored here +LL | let mut i = 3; +LL | box_it(Box::new(|| i += 1)) | -- ^ borrowed value does not live long enough | | - | capture occurs here + | value captured here LL | }; - | - borrowed value only lives until here -LL | cl_box.cl.call_mut(()); -LL | } - | - borrowed value needs to live until here + | - `i` dropped here while still borrowed error: aborting due to previous error diff --git a/src/test/ui/regions/regions-trait-1.rs b/src/test/ui/regions/regions-trait-1.rs index 7273887193620..0da8ac53695e9 100644 --- a/src/test/ui/regions/regions-trait-1.rs +++ b/src/test/ui/regions/regions-trait-1.rs @@ -19,12 +19,12 @@ impl<'a> GetCtxt for HasCtxt<'a> { } -fn get_v(gc: Box) -> usize { +fn get_v(gc: Box) -> usize { gc.get_ctxt().v } fn main() { let ctxt = Ctxt { v: 22 }; let hc = HasCtxt { c: &ctxt }; - assert_eq!(get_v(box hc as Box), 22); + assert_eq!(get_v(box hc as Box), 22); } diff --git a/src/test/ui/regions/regions-trait-1.stderr b/src/test/ui/regions/regions-trait-1.stderr index e1aa2a2c29931..421f826ccc54e 100644 --- a/src/test/ui/regions/regions-trait-1.stderr +++ b/src/test/ui/regions/regions-trait-1.stderr @@ -1,7 +1,7 @@ error[E0308]: method not compatible with trait --> $DIR/regions-trait-1.rs:16:5 | -LL | fn get_ctxt(&self) -> &'a Ctxt { //~ ERROR method not compatible with trait +LL | fn get_ctxt(&self) -> &'a Ctxt { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `fn(&HasCtxt<'a>) -> &Ctxt` @@ -14,7 +14,7 @@ LL | impl<'a> GetCtxt for HasCtxt<'a> { note: ...does not necessarily outlive the anonymous lifetime #1 defined on the method body at 16:5 --> $DIR/regions-trait-1.rs:16:5 | -LL | / fn get_ctxt(&self) -> &'a Ctxt { //~ ERROR method not compatible with trait +LL | / fn get_ctxt(&self) -> &'a Ctxt { LL | | self.c LL | | } | |_____^ diff --git a/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr b/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr new file mode 100644 index 0000000000000..f4b1a89db9a73 --- /dev/null +++ b/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/regions-trait-object-subtyping.rs:15:5 + | +LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // Without knowing 'a:'b, we can't coerce +LL | x + | ^ returning this value requires that `'a` must outlive `'b` + +error: lifetime may not live long enough + --> $DIR/regions-trait-object-subtyping.rs:22:5 + | +LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // We can't coerce because it is packed in `Wrapper` +LL | x + | ^ returning this value requires that `'b` must outlive `'a` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/regions/regions-trait-object-subtyping.rs b/src/test/ui/regions/regions-trait-object-subtyping.rs index eb2623544563f..5b36194870ef6 100644 --- a/src/test/ui/regions/regions-trait-object-subtyping.rs +++ b/src/test/ui/regions/regions-trait-object-subtyping.rs @@ -1,23 +1,23 @@ trait Dummy { fn dummy(&self); } -fn foo1<'a:'b,'b>(x: &'a mut (Dummy+'a)) -> &'b mut (Dummy+'b) { +fn foo1<'a:'b,'b>(x: &'a mut (dyn Dummy+'a)) -> &'b mut (dyn Dummy+'b) { // Here, we are able to coerce x } -fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) { +fn foo2<'a:'b,'b>(x: &'b mut (dyn Dummy+'a)) -> &'b mut (dyn Dummy+'b) { // Here, we are able to coerce x } -fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { +fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy { // Without knowing 'a:'b, we can't coerce x //~ ERROR lifetime bound not satisfied //~^ ERROR cannot infer an appropriate lifetime } struct Wrapper(T); -fn foo4<'a:'b,'b>(x: Wrapper<&'a mut Dummy>) -> Wrapper<&'b mut Dummy> { +fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> { // We can't coerce because it is packed in `Wrapper` x //~ ERROR mismatched types } diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr index dc5ce34d7d89a..6de92f13840b3 100644 --- a/src/test/ui/regions/regions-trait-object-subtyping.stderr +++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr @@ -1,40 +1,40 @@ error[E0478]: lifetime bound not satisfied --> $DIR/regions-trait-object-subtyping.rs:15:5 | -LL | x //~ ERROR lifetime bound not satisfied +LL | x | ^ | note: lifetime parameter instantiated with the lifetime 'a as defined on the function body at 13:9 --> $DIR/regions-trait-object-subtyping.rs:13:9 | -LL | fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { +LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy { | ^^ note: but lifetime parameter must outlive the lifetime 'b as defined on the function body at 13:12 --> $DIR/regions-trait-object-subtyping.rs:13:12 | -LL | fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { +LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy { | ^^ error[E0495]: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements --> $DIR/regions-trait-object-subtyping.rs:15:5 | -LL | x //~ ERROR lifetime bound not satisfied +LL | x | ^ | note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 13:9... --> $DIR/regions-trait-object-subtyping.rs:13:9 | -LL | fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { +LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy { | ^^ note: ...so that reference does not outlive borrowed content --> $DIR/regions-trait-object-subtyping.rs:15:5 | -LL | x //~ ERROR lifetime bound not satisfied +LL | x | ^ note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 13:12... --> $DIR/regions-trait-object-subtyping.rs:13:12 | -LL | fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { +LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy { | ^^ = note: ...so that the expression is assignable: expected &'b mut (dyn Dummy + 'b) @@ -43,7 +43,7 @@ LL | fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { error[E0308]: mismatched types --> $DIR/regions-trait-object-subtyping.rs:22:5 | -LL | x //~ ERROR mismatched types +LL | x | ^ lifetime mismatch | = note: expected type `Wrapper<&'b mut (dyn Dummy + 'b)>` @@ -51,15 +51,15 @@ LL | x //~ ERROR mismatched types note: the lifetime 'b as defined on the function body at 20:15... --> $DIR/regions-trait-object-subtyping.rs:20:15 | -LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut Dummy>) -> Wrapper<&'b mut Dummy> { +LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> { | ^^ note: ...does not necessarily outlive the lifetime 'a as defined on the function body at 20:9 --> $DIR/regions-trait-object-subtyping.rs:20:9 | -LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut Dummy>) -> Wrapper<&'b mut Dummy> { +LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> { | ^^ error: aborting due to 3 previous errors -Some errors occurred: E0308, E0478, E0495. +Some errors have detailed explanations: E0308, E0478. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/regions-trait-variance.nll.stderr b/src/test/ui/regions/regions-trait-variance.nll.stderr deleted file mode 100644 index ca05c93a7ecea..0000000000000 --- a/src/test/ui/regions/regions-trait-variance.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0515]: cannot return value referencing local data `*b` - --> $DIR/regions-trait-variance.rs:38:5 - | -LL | let bb: &B = &*b; //~ ERROR `*b` does not live long enough - | --- `*b` is borrowed here -LL | make_a(bb) - | ^^^^^^^^^^ returns a value referencing data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-trait-variance.rs b/src/test/ui/regions/regions-trait-variance.rs index d5462b21fa71c..9169d457d4051 100644 --- a/src/test/ui/regions/regions-trait-variance.rs +++ b/src/test/ui/regions/regions-trait-variance.rs @@ -23,10 +23,10 @@ impl Drop for B { } struct A<'r> { - p: &'r (X+'r) + p: &'r (dyn X + 'r) } -fn make_a(p:&X) -> A { +fn make_a(p: &dyn X) -> A { A{p:p} } @@ -34,8 +34,8 @@ fn make_make_a<'a>() -> A<'a> { let b: Box = box B { i: 1, }; - let bb: &B = &*b; //~ ERROR `*b` does not live long enough - make_a(bb) + let bb: &B = &*b; + make_a(bb) //~ ERROR cannot return value referencing local data `*b` } fn main() { diff --git a/src/test/ui/regions/regions-trait-variance.stderr b/src/test/ui/regions/regions-trait-variance.stderr index ddc8ce9796d60..56c9f89e1f597 100644 --- a/src/test/ui/regions/regions-trait-variance.stderr +++ b/src/test/ui/regions/regions-trait-variance.stderr @@ -1,18 +1,11 @@ -error[E0597]: `*b` does not live long enough - --> $DIR/regions-trait-variance.rs:37:19 +error[E0515]: cannot return value referencing local data `*b` + --> $DIR/regions-trait-variance.rs:38:5 | -LL | let bb: &B = &*b; //~ ERROR `*b` does not live long enough - | ^^ borrowed value does not live long enough +LL | let bb: &B = &*b; + | --- `*b` is borrowed here LL | make_a(bb) -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the lifetime 'a as defined on the function body at 33:16... - --> $DIR/regions-trait-variance.rs:33:16 - | -LL | fn make_make_a<'a>() -> A<'a> { - | ^^ + | ^^^^^^^^^^ returns a value referencing data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/regions/regions-undeclared.stderr b/src/test/ui/regions/regions-undeclared.stderr index 7e35dc1c4741a..495aec3fde5f1 100644 --- a/src/test/ui/regions/regions-undeclared.stderr +++ b/src/test/ui/regions/regions-undeclared.stderr @@ -1,31 +1,31 @@ error[E0261]: use of undeclared lifetime name `'blk` --> $DIR/regions-undeclared.rs:1:14 | -LL | static c_x: &'blk isize = &22; //~ ERROR use of undeclared lifetime name `'blk` +LL | static c_x: &'blk isize = &22; | ^^^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-undeclared.rs:4:10 | -LL | Foo(&'a isize), //~ ERROR use of undeclared lifetime name `'a` +LL | Foo(&'a isize), | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-undeclared.rs:5:10 | -LL | Bar(&'a isize), //~ ERROR use of undeclared lifetime name `'a` +LL | Bar(&'a isize), | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-undeclared.rs:8:15 | -LL | fn fnDecl(x: &'a isize, //~ ERROR use of undeclared lifetime name `'a` +LL | fn fnDecl(x: &'a isize, | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-undeclared.rs:9:15 | -LL | y: &'a isize) //~ ERROR use of undeclared lifetime name `'a` +LL | y: &'a isize) | ^^ undeclared lifetime error: aborting due to 5 previous errors diff --git a/src/test/ui/regions/regions-var-type-out-of-scope.nll.stderr b/src/test/ui/regions/regions-var-type-out-of-scope.nll.stderr deleted file mode 100644 index e38574e774d14..0000000000000 --- a/src/test/ui/regions/regions-var-type-out-of-scope.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/regions-var-type-out-of-scope.rs:9:14 - | -LL | x = &id(3); //~ ERROR borrowed value does not live long enough - | ^^^^^- temporary value is freed at the end of this statement - | | - | creates a temporary which is freed while still in use -LL | assert_eq!(*x, 3); - | ------------------ borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/regions/regions-var-type-out-of-scope.rs b/src/test/ui/regions/regions-var-type-out-of-scope.rs index e972163097490..aba55e9df6ac6 100644 --- a/src/test/ui/regions/regions-var-type-out-of-scope.rs +++ b/src/test/ui/regions/regions-var-type-out-of-scope.rs @@ -6,7 +6,7 @@ fn foo(cond: bool) { let mut x; if cond { - x = &id(3); //~ ERROR borrowed value does not live long enough + x = &id(3); //~ ERROR temporary value dropped while borrowed assert_eq!(*x, 3); } } diff --git a/src/test/ui/regions/regions-var-type-out-of-scope.stderr b/src/test/ui/regions/regions-var-type-out-of-scope.stderr index f474b9a2343cf..146fb8fd81fc6 100644 --- a/src/test/ui/regions/regions-var-type-out-of-scope.stderr +++ b/src/test/ui/regions/regions-var-type-out-of-scope.stderr @@ -1,16 +1,16 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/regions-var-type-out-of-scope.rs:9:14 | -LL | x = &id(3); //~ ERROR borrowed value does not live long enough - | ^^^^^- temporary value dropped here while still borrowed +LL | x = &id(3); + | ^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough -... -LL | } - | - temporary value needs to live until here + | creates a temporary which is freed while still in use +LL | assert_eq!(*x, 3); + | ------------------ borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.nll.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.nll.stderr new file mode 100644 index 0000000000000..f5b96f314c578 --- /dev/null +++ b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:25:12 + | +LL | fn use_<'short,'long>(c: S<'long, 'short>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: S<'long, 'long> = c; + | ^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.stderr index 20615e6a3d7b2..6b3a488805f97 100644 --- a/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.stderr +++ b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.stderr @@ -2,13 +2,10 @@ error[E0623]: lifetime mismatch --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:25:30 | LL | fn use_<'short,'long>(c: S<'long, 'short>, - | ---------------- - | | - | this type is declared with multiple lifetimes... + | ---------------- this type is declared with multiple lifetimes... ... -LL | let _: S<'long, 'long> = c; //~ ERROR E0623 +LL | let _: S<'long, 'long> = c; | ^ ...but data with one lifetime flows into the other here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant.nll.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant.nll.stderr new file mode 100644 index 0000000000000..372510a2f7e28 --- /dev/null +++ b/src/test/ui/regions/regions-variance-contravariant-use-covariant.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/regions-variance-contravariant-use-covariant.rs:23:12 + | +LL | fn use_<'short,'long>(c: Contravariant<'short>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: Contravariant<'long> = c; + | ^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant.stderr index da8d218819192..44199881444ad 100644 --- a/src/test/ui/regions/regions-variance-contravariant-use-covariant.stderr +++ b/src/test/ui/regions/regions-variance-contravariant-use-covariant.stderr @@ -7,9 +7,8 @@ LL | s: &'short isize, LL | l: &'long isize, | ------------ ... -LL | let _: Contravariant<'long> = c; //~ ERROR E0623 +LL | let _: Contravariant<'long> = c; | ^ ...but data from `c` flows into `l` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-variance-covariant-use-contravariant.nll.stderr b/src/test/ui/regions/regions-variance-covariant-use-contravariant.nll.stderr new file mode 100644 index 0000000000000..e87e914727c5f --- /dev/null +++ b/src/test/ui/regions/regions-variance-covariant-use-contravariant.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/regions-variance-covariant-use-contravariant.rs:23:12 + | +LL | fn use_<'short,'long>(c: Covariant<'long>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: Covariant<'short> = c; + | ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-variance-covariant-use-contravariant.stderr b/src/test/ui/regions/regions-variance-covariant-use-contravariant.stderr index 74a6aee262765..22ba8838893d6 100644 --- a/src/test/ui/regions/regions-variance-covariant-use-contravariant.stderr +++ b/src/test/ui/regions/regions-variance-covariant-use-contravariant.stderr @@ -6,9 +6,8 @@ LL | fn use_<'short,'long>(c: Covariant<'long>, LL | s: &'short isize, | ------------- these two types are declared with different lifetimes... ... -LL | let _: Covariant<'short> = c; //~ ERROR E0623 +LL | let _: Covariant<'short> = c; | ^ ...but data from `s` flows into `c` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr b/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr new file mode 100644 index 0000000000000..adee33bfc7e83 --- /dev/null +++ b/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/regions-variance-invariant-use-contravariant.rs:20:12 + | +LL | fn use_<'short,'long>(c: Invariant<'long>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: Invariant<'short> = c; + | ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-variance-invariant-use-contravariant.stderr b/src/test/ui/regions/regions-variance-invariant-use-contravariant.stderr index 2332acdf83215..a779b485ea701 100644 --- a/src/test/ui/regions/regions-variance-invariant-use-contravariant.stderr +++ b/src/test/ui/regions/regions-variance-invariant-use-contravariant.stderr @@ -6,9 +6,8 @@ LL | fn use_<'short,'long>(c: Invariant<'long>, LL | s: &'short isize, | ------------- these two types are declared with different lifetimes... ... -LL | let _: Invariant<'short> = c; //~ ERROR E0623 +LL | let _: Invariant<'short> = c; | ^ ...but data from `s` flows into `c` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr b/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr new file mode 100644 index 0000000000000..15853e6ca5d69 --- /dev/null +++ b/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/regions-variance-invariant-use-covariant.rs:17:12 + | +LL | fn use_<'b>(c: Invariant<'b>) { + | -- lifetime `'b` defined here +... +LL | let _: Invariant<'static> = c; + | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr b/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr index f1d1a14f52b8b..90b37ce935a6d 100644 --- a/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr +++ b/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/regions-variance-invariant-use-covariant.rs:17:33 | -LL | let _: Invariant<'static> = c; //~ ERROR mismatched types +LL | let _: Invariant<'static> = c; | ^ lifetime mismatch | = note: expected type `Invariant<'static>` diff --git a/src/test/ui/regions/regions-wf-trait-object.rs b/src/test/ui/regions/regions-wf-trait-object.rs index 61bab359f9a08..d0053b2023445 100644 --- a/src/test/ui/regions/regions-wf-trait-object.rs +++ b/src/test/ui/regions/regions-wf-trait-object.rs @@ -4,7 +4,7 @@ trait TheTrait<'t>: 't { } struct Foo<'a,'b> { - x: Box+'b> //~ ERROR E0478 + x: Box+'b> //~ ERROR E0478 } fn main() { } diff --git a/src/test/ui/regions/regions-wf-trait-object.stderr b/src/test/ui/regions/regions-wf-trait-object.stderr index c26895773761e..4e12478c36da3 100644 --- a/src/test/ui/regions/regions-wf-trait-object.stderr +++ b/src/test/ui/regions/regions-wf-trait-object.stderr @@ -1,8 +1,8 @@ error[E0478]: lifetime bound not satisfied --> $DIR/regions-wf-trait-object.rs:7:5 | -LL | x: Box+'b> //~ ERROR E0478 - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | x: Box+'b> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime 'b as defined on the struct at 6:15 --> $DIR/regions-wf-trait-object.rs:6:15 diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/reject-specialized-drops-8142.stderr index 1782d3b310582..08aca3bb14c26 100644 --- a/src/test/ui/reject-specialized-drops-8142.stderr +++ b/src/test/ui/reject-specialized-drops-8142.stderr @@ -2,7 +2,7 @@ error[E0367]: The requirement `'adds_bnd : 'al` is added only by the Drop impl. --> $DIR/reject-specialized-drops-8142.rs:19:1 | LL | / impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT -LL | | //~^ ERROR The requirement `'adds_bnd : 'al` is added only by the Drop impl. +LL | | LL | | fn drop(&mut self) { } } | |____________________________^ | @@ -16,7 +16,7 @@ error[E0367]: The requirement `'adds_bnd : 'al` is added only by the Drop impl. --> $DIR/reject-specialized-drops-8142.rs:23:1 | LL | / impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT -LL | | //~^ ERROR The requirement `'adds_bnd : 'al` is added only by the Drop impl. +LL | | LL | | fn drop(&mut self) { } } | |____________________________^ | @@ -111,5 +111,5 @@ LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 } error: aborting due to 8 previous errors -Some errors occurred: E0308, E0366, E0367, E0495. +Some errors have detailed explanations: E0308, E0366, E0367. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat_count.stderr index df3227bfcde13..df73ac0b182f0 100644 --- a/src/test/ui/repeat_count.stderr +++ b/src/test/ui/repeat_count.stderr @@ -42,12 +42,20 @@ error[E0308]: mismatched types | LL | let f = [0; -4_isize]; | ^^^^^^^^ expected usize, found isize +help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit + | +LL | let f = [0; (-4_isize).try_into().unwrap()]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/repeat_count.rs:28:23 | LL | let f = [0_usize; -1_isize]; | ^^^^^^^^ expected usize, found isize +help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit + | +LL | let f = [0_usize; (-1_isize).try_into().unwrap()]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/repeat_count.rs:34:17 @@ -60,5 +68,5 @@ LL | let g = [0; G { g: () }]; error: aborting due to 8 previous errors -Some errors occurred: E0308, E0435. +Some errors have detailed explanations: E0308, E0435. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/repr.rs b/src/test/ui/repr.rs index 9d844745f4299..564d673260102 100644 --- a/src/test/ui/repr.rs +++ b/src/test/ui/repr.rs @@ -1,13 +1,10 @@ -#[repr] -//~^ ERROR attribute must be of the form +#[repr] //~ ERROR malformed `repr` attribute struct _A {} -#[repr = "B"] -//~^ ERROR attribute must be of the form +#[repr = "B"] //~ ERROR malformed `repr` attribute struct _B {} -#[repr = "C"] -//~^ ERROR attribute must be of the form +#[repr = "C"] //~ ERROR malformed `repr` attribute struct _C {} #[repr(C)] diff --git a/src/test/ui/repr.stderr b/src/test/ui/repr.stderr index 7ebfe083ddd01..e756510a437c8 100644 --- a/src/test/ui/repr.stderr +++ b/src/test/ui/repr.stderr @@ -1,20 +1,20 @@ -error: attribute must be of the form `#[repr(C, packed, ...)]` +error: malformed `repr` attribute input --> $DIR/repr.rs:1:1 | LL | #[repr] - | ^^^^^^^ + | ^^^^^^^ help: must be of the form: `#[repr(C, packed, ...)]` -error: attribute must be of the form `#[repr(C, packed, ...)]` - --> $DIR/repr.rs:5:1 +error: malformed `repr` attribute input + --> $DIR/repr.rs:4:1 | LL | #[repr = "B"] - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ help: must be of the form: `#[repr(C, packed, ...)]` -error: attribute must be of the form `#[repr(C, packed, ...)]` - --> $DIR/repr.rs:9:1 +error: malformed `repr` attribute input + --> $DIR/repr.rs:7:1 | LL | #[repr = "C"] - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ help: must be of the form: `#[repr(C, packed, ...)]` error: aborting due to 3 previous errors diff --git a/src/test/ui/repr/repr-align-assign.stderr b/src/test/ui/repr/repr-align-assign.stderr index 884a99357cdbe..177bd81e8f265 100644 --- a/src/test/ui/repr/repr-align-assign.stderr +++ b/src/test/ui/repr/repr-align-assign.stderr @@ -1,15 +1,14 @@ error[E0693]: incorrect `repr(align)` attribute format --> $DIR/repr-align-assign.rs:5:8 | -LL | #[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format +LL | #[repr(align=8)] | ^^^^^^^ help: use parentheses instead: `align(8)` error[E0693]: incorrect `repr(align)` attribute format --> $DIR/repr-align-assign.rs:8:8 | -LL | #[repr(align="8")] //~ ERROR incorrect `repr(align)` attribute format +LL | #[repr(align="8")] | ^^^^^^^^^ help: use parentheses instead: `align(8)` error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0693`. diff --git a/src/test/ui/repr/repr-align.rs b/src/test/ui/repr/repr-align.rs index 9ce89e82ca225..bc6a9fe562a67 100644 --- a/src/test/ui/repr/repr-align.rs +++ b/src/test/ui/repr/repr-align.rs @@ -1,19 +1,27 @@ -#![feature(repr_align_enum)] #![allow(dead_code)] #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer -struct A(i32); +struct S0(i32); #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two -struct B(i32); +struct S1(i32); #[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29 -struct C(i32); +struct S2(i32); #[repr(align(536870912))] // ok: this is the largest accepted alignment -struct D(i32); +struct S3(i32); + +#[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer +enum E0 { A, B } #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two -enum E { Left, Right } +enum E1 { A, B } + +#[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29 +enum E2 { A, B } + +#[repr(align(536870912))] // ok: this is the largest accepted alignment +enum E3 { A, B } fn main() {} diff --git a/src/test/ui/repr/repr-align.stderr b/src/test/ui/repr/repr-align.stderr index f1a5d88ace1fd..280cab2b4a144 100644 --- a/src/test/ui/repr/repr-align.stderr +++ b/src/test/ui/repr/repr-align.stderr @@ -1,27 +1,39 @@ error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer - --> $DIR/repr-align.rs:4:8 + --> $DIR/repr-align.rs:3:8 | -LL | #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer +LL | #[repr(align(16.0))] | ^^^^^^^^^^^ error[E0589]: invalid `repr(align)` attribute: not a power of two - --> $DIR/repr-align.rs:7:8 + --> $DIR/repr-align.rs:6:8 | -LL | #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two +LL | #[repr(align(15))] | ^^^^^^^^^ error[E0589]: invalid `repr(align)` attribute: larger than 2^29 - --> $DIR/repr-align.rs:10:8 + --> $DIR/repr-align.rs:9:8 | -LL | #[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29 +LL | #[repr(align(4294967296))] | ^^^^^^^^^^^^^^^^^ +error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer + --> $DIR/repr-align.rs:15:8 + | +LL | #[repr(align(16.0))] + | ^^^^^^^^^^^ + error[E0589]: invalid `repr(align)` attribute: not a power of two - --> $DIR/repr-align.rs:16:8 + --> $DIR/repr-align.rs:18:8 | -LL | #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two +LL | #[repr(align(15))] | ^^^^^^^^^ -error: aborting due to 4 previous errors +error[E0589]: invalid `repr(align)` attribute: larger than 2^29 + --> $DIR/repr-align.rs:21:8 + | +LL | #[repr(align(4294967296))] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0589`. diff --git a/src/test/ui/repr/repr-packed-contains-align.stderr b/src/test/ui/repr/repr-packed-contains-align.stderr index 59f8b359d1f56..219516d8abc48 100644 --- a/src/test/ui/repr/repr-packed-contains-align.stderr +++ b/src/test/ui/repr/repr-packed-contains-align.stderr @@ -1,31 +1,31 @@ error[E0588]: packed type cannot transitively contain a `[repr(align)]` type --> $DIR/repr-packed-contains-align.rs:19:1 | -LL | struct SC(SA); //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type +LL | struct SC(SA); | ^^^^^^^^^^^^^^ error[E0588]: packed type cannot transitively contain a `[repr(align)]` type --> $DIR/repr-packed-contains-align.rs:22:1 | -LL | struct SD(SB); //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type +LL | struct SD(SB); | ^^^^^^^^^^^^^^ error[E0588]: packed type cannot transitively contain a `[repr(align)]` type --> $DIR/repr-packed-contains-align.rs:25:1 | -LL | struct SE(UA); //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type +LL | struct SE(UA); | ^^^^^^^^^^^^^^ error[E0588]: packed type cannot transitively contain a `[repr(align)]` type --> $DIR/repr-packed-contains-align.rs:28:1 | -LL | struct SF(UB); //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type +LL | struct SF(UB); | ^^^^^^^^^^^^^^ error[E0588]: packed type cannot transitively contain a `[repr(align)]` type --> $DIR/repr-packed-contains-align.rs:31:1 | -LL | / union UC { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type +LL | / union UC { LL | | a: UA LL | | } | |_^ @@ -33,7 +33,7 @@ LL | | } error[E0588]: packed type cannot transitively contain a `[repr(align)]` type --> $DIR/repr-packed-contains-align.rs:36:1 | -LL | / union UD { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type +LL | / union UD { LL | | n: UB LL | | } | |_^ @@ -41,7 +41,7 @@ LL | | } error[E0588]: packed type cannot transitively contain a `[repr(align)]` type --> $DIR/repr-packed-contains-align.rs:41:1 | -LL | / union UE { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type +LL | / union UE { LL | | a: SA LL | | } | |_^ @@ -49,11 +49,10 @@ LL | | } error[E0588]: packed type cannot transitively contain a `[repr(align)]` type --> $DIR/repr-packed-contains-align.rs:46:1 | -LL | / union UF { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type +LL | / union UF { LL | | n: SB LL | | } | |_^ error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0588`. diff --git a/src/test/ui/repr/repr-transparent-other-items.rs b/src/test/ui/repr/repr-transparent-other-items.rs index 392e7c9de4d09..c3d772f6266c0 100644 --- a/src/test/ui/repr/repr-transparent-other-items.rs +++ b/src/test/ui/repr/repr-transparent-other-items.rs @@ -1,26 +1,5 @@ // See also repr-transparent.rs -#[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum -enum Void {} //~| ERROR should be applied to struct - -#[repr(transparent)] //~ ERROR should be applied to struct -enum FieldlessEnum { - Foo, - Bar, -} - -#[repr(transparent)] //~ ERROR should be applied to struct -enum Enum { - Foo(String), - Bar(u32), -} - -#[repr(transparent)] //~ ERROR should be applied to struct -union Foo { - u: u32, - s: i32 -} - #[repr(transparent)] //~ ERROR should be applied to struct fn cant_repr_this() {} diff --git a/src/test/ui/repr/repr-transparent-other-items.stderr b/src/test/ui/repr/repr-transparent-other-items.stderr index 5b7f9650d0c0a..03df3569b42bc 100644 --- a/src/test/ui/repr/repr-transparent-other-items.stderr +++ b/src/test/ui/repr/repr-transparent-other-items.stderr @@ -1,69 +1,19 @@ -error[E0517]: attribute should be applied to struct +error[E0517]: attribute should be applied to struct, enum, or union --> $DIR/repr-transparent-other-items.rs:3:8 | -LL | #[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum - | ^^^^^^^^^^^ -LL | enum Void {} //~| ERROR should be applied to struct - | ------------ not a struct - -error[E0517]: attribute should be applied to struct - --> $DIR/repr-transparent-other-items.rs:6:8 - | -LL | #[repr(transparent)] //~ ERROR should be applied to struct - | ^^^^^^^^^^^ -LL | / enum FieldlessEnum { -LL | | Foo, -LL | | Bar, -LL | | } - | |_- not a struct - -error[E0517]: attribute should be applied to struct - --> $DIR/repr-transparent-other-items.rs:12:8 - | -LL | #[repr(transparent)] //~ ERROR should be applied to struct - | ^^^^^^^^^^^ -LL | / enum Enum { -LL | | Foo(String), -LL | | Bar(u32), -LL | | } - | |_- not a struct - -error[E0517]: attribute should be applied to struct - --> $DIR/repr-transparent-other-items.rs:18:8 - | -LL | #[repr(transparent)] //~ ERROR should be applied to struct - | ^^^^^^^^^^^ -LL | / union Foo { -LL | | u: u32, -LL | | s: i32 -LL | | } - | |_- not a struct - -error[E0517]: attribute should be applied to struct - --> $DIR/repr-transparent-other-items.rs:24:8 - | -LL | #[repr(transparent)] //~ ERROR should be applied to struct +LL | #[repr(transparent)] | ^^^^^^^^^^^ LL | fn cant_repr_this() {} - | ---------------------- not a struct + | ---------------------- not a struct, enum, or union -error[E0517]: attribute should be applied to struct - --> $DIR/repr-transparent-other-items.rs:27:8 +error[E0517]: attribute should be applied to struct, enum, or union + --> $DIR/repr-transparent-other-items.rs:6:8 | -LL | #[repr(transparent)] //~ ERROR should be applied to struct +LL | #[repr(transparent)] | ^^^^^^^^^^^ LL | static CANT_REPR_THIS: u32 = 0; - | ------------------------------- not a struct - -error[E0084]: unsupported representation for zero-variant enum - --> $DIR/repr-transparent-other-items.rs:3:1 - | -LL | #[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum - | ^^^^^^^^^^^^^^^^^^^^ -LL | enum Void {} //~| ERROR should be applied to struct - | ------------ zero-variant enum + | ------------------------------- not a struct, enum, or union -error: aborting due to 7 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0084, E0517. -For more information about an error, try `rustc --explain E0084`. +For more information about this error, try `rustc --explain E0517`. diff --git a/src/test/ui/repr/repr-transparent-other-reprs.stderr b/src/test/ui/repr/repr-transparent-other-reprs.stderr index 1aafa43624926..9b48bb3a43d2a 100644 --- a/src/test/ui/repr/repr-transparent-other-reprs.stderr +++ b/src/test/ui/repr/repr-transparent-other-reprs.stderr @@ -1,25 +1,25 @@ error[E0692]: transparent struct cannot have other repr hints --> $DIR/repr-transparent-other-reprs.rs:5:8 | -LL | #[repr(transparent, C)] //~ ERROR cannot have other repr +LL | #[repr(transparent, C)] | ^^^^^^^^^^^ ^ error[E0692]: transparent struct cannot have other repr hints --> $DIR/repr-transparent-other-reprs.rs:10:8 | -LL | #[repr(transparent, packed)] //~ ERROR cannot have other repr +LL | #[repr(transparent, packed)] | ^^^^^^^^^^^ ^^^^^^ error[E0692]: transparent struct cannot have other repr hints --> $DIR/repr-transparent-other-reprs.rs:13:8 | -LL | #[repr(transparent, align(2))] //~ ERROR cannot have other repr +LL | #[repr(transparent, align(2))] | ^^^^^^^^^^^ ^^^^^^^^ error[E0692]: transparent struct cannot have other repr hints --> $DIR/repr-transparent-other-reprs.rs:16:8 | -LL | #[repr(transparent)] //~ ERROR cannot have other repr +LL | #[repr(transparent)] | ^^^^^^^^^^^ LL | #[repr(C)] | ^ diff --git a/src/test/ui/repr/repr-transparent.rs b/src/test/ui/repr/repr-transparent.rs index 66d39ff9bb593..730d428ff500b 100644 --- a/src/test/ui/repr/repr-transparent.rs +++ b/src/test/ui/repr/repr-transparent.rs @@ -3,7 +3,7 @@ // - repr-transparent-other-reprs.rs // - repr-transparent-other-items.rs -#![feature(repr_align)] +#![feature(repr_align, transparent_enums, transparent_unions)] use std::marker::PhantomData; @@ -39,4 +39,36 @@ struct ZstAlign32(PhantomData); #[repr(transparent)] struct GenericAlign(ZstAlign32, u32); //~ ERROR alignment larger than 1 +#[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum +enum Void {} +//~^ ERROR transparent enum needs exactly one variant, but has 0 + +#[repr(transparent)] +enum FieldlessEnum { //~ ERROR transparent enum needs exactly one non-zero-sized field, but has 0 + Foo, +} + +#[repr(transparent)] +enum TooManyFieldsEnum { + Foo(u32, String), +} +//~^^^ ERROR transparent enum needs exactly one non-zero-sized field, but has 2 + +#[repr(transparent)] +enum TooManyVariants { //~ ERROR transparent enum needs exactly one variant, but has 2 + Foo(String), + Bar, +} + +#[repr(transparent)] +union UnitUnion { //~ ERROR transparent union needs exactly one non-zero-sized field, but has 0 + u: (), +} + +#[repr(transparent)] +union TooManyFields { //~ ERROR transparent union needs exactly one non-zero-sized field, but has 2 + u: u32, + s: i32 +} + fn main() {} diff --git a/src/test/ui/repr/repr-transparent.stderr b/src/test/ui/repr/repr-transparent.stderr index 02bf2154fe593..f0c1fbe8ac9e1 100644 --- a/src/test/ui/repr/repr-transparent.stderr +++ b/src/test/ui/repr/repr-transparent.stderr @@ -1,72 +1,116 @@ error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0 --> $DIR/repr-transparent.rs:11:1 | -LL | struct NoFields; //~ ERROR needs exactly one non-zero-sized field - | ^^^^^^^^^^^^^^^^ - | - = note: non-zero-sized field +LL | struct NoFields; + | ^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0 --> $DIR/repr-transparent.rs:14:1 | -LL | struct ContainsOnlyZst(()); //~ ERROR needs exactly one non-zero-sized field - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: non-zero-sized field +LL | struct ContainsOnlyZst(()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0 --> $DIR/repr-transparent.rs:17:1 | -LL | struct ContainsOnlyZstArray([bool; 0]); //~ ERROR needs exactly one non-zero-sized field - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: non-zero-sized field +LL | struct ContainsOnlyZstArray([bool; 0]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0 --> $DIR/repr-transparent.rs:20:1 | LL | struct ContainsMultipleZst(PhantomData<*const i32>, NoFields); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: non-zero-sized field + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 2 --> $DIR/repr-transparent.rs:24:1 | -LL | struct MultipleNonZst(u8, u8); //~ ERROR needs exactly one non-zero-sized field - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: non-zero-sized field - --> $DIR/repr-transparent.rs:24:23 - | -LL | struct MultipleNonZst(u8, u8); //~ ERROR needs exactly one non-zero-sized field - | ^^ ^^ +LL | struct MultipleNonZst(u8, u8); + | ^^^^^^^^^^^^^^^^^^^^^^--^^--^^ + | | | | + | | | this field is non-zero-sized + | | this field is non-zero-sized + | needs exactly one non-zero-sized field, but has 2 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 2 --> $DIR/repr-transparent.rs:30:1 | LL | pub struct StructWithProjection(f32, ::It); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: non-zero-sized field - --> $DIR/repr-transparent.rs:30:33 - | -LL | pub struct StructWithProjection(f32, ::It); - | ^^^ ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^-------------------^^ + | | | | + | | | this field is non-zero-sized + | | this field is non-zero-sized + | needs exactly one non-zero-sized field, but has 2 error[E0691]: zero-sized field in transparent struct has alignment larger than 1 --> $DIR/repr-transparent.rs:34:32 | -LL | struct NontrivialAlignZst(u32, [u16; 0]); //~ ERROR alignment larger than 1 - | ^^^^^^^^ +LL | struct NontrivialAlignZst(u32, [u16; 0]); + | ^^^^^^^^ has alignment larger than 1 error[E0691]: zero-sized field in transparent struct has alignment larger than 1 --> $DIR/repr-transparent.rs:40:24 | -LL | struct GenericAlign(ZstAlign32, u32); //~ ERROR alignment larger than 1 - | ^^^^^^^^^^^^^ +LL | struct GenericAlign(ZstAlign32, u32); + | ^^^^^^^^^^^^^ has alignment larger than 1 + +error[E0084]: unsupported representation for zero-variant enum + --> $DIR/repr-transparent.rs:42:1 + | +LL | #[repr(transparent)] + | ^^^^^^^^^^^^^^^^^^^^ +LL | enum Void {} + | ------------ zero-variant enum + +error[E0731]: transparent enum needs exactly one variant, but has 0 + --> $DIR/repr-transparent.rs:43:1 + | +LL | enum Void {} + | ^^^^^^^^^ needs exactly one variant, but has 0 + +error[E0690]: the variant of a transparent enum needs exactly one non-zero-sized field, but has 0 + --> $DIR/repr-transparent.rs:47:1 + | +LL | enum FieldlessEnum { + | ^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0 + +error[E0690]: the variant of a transparent enum needs exactly one non-zero-sized field, but has 2 + --> $DIR/repr-transparent.rs:52:1 + | +LL | enum TooManyFieldsEnum { + | ^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 2 +LL | Foo(u32, String), + | --- ------ this field is non-zero-sized + | | + | this field is non-zero-sized + +error[E0731]: transparent enum needs exactly one variant, but has 2 + --> $DIR/repr-transparent.rs:58:1 + | +LL | enum TooManyVariants { + | ^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2 +LL | Foo(String), + | ----------- +LL | Bar, + | --- too many variants in `TooManyVariants` + +error[E0690]: transparent union needs exactly one non-zero-sized field, but has 0 + --> $DIR/repr-transparent.rs:64:1 + | +LL | union UnitUnion { + | ^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0 + +error[E0690]: transparent union needs exactly one non-zero-sized field, but has 2 + --> $DIR/repr-transparent.rs:69:1 + | +LL | union TooManyFields { + | ^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 2 +LL | u: u32, + | ------ this field is non-zero-sized +LL | s: i32 + | ------ this field is non-zero-sized -error: aborting due to 8 previous errors +error: aborting due to 15 previous errors -Some errors occurred: E0690, E0691. -For more information about an error, try `rustc --explain E0690`. +Some errors have detailed explanations: E0084, E0690, E0691, E0731. +For more information about an error, try `rustc --explain E0084`. diff --git a/src/test/ui/reserved/reserved-attr-on-macro.stderr b/src/test/ui/reserved/reserved-attr-on-macro.stderr index 46d3478b62841..c8738d1ed3429 100644 --- a/src/test/ui/reserved/reserved-attr-on-macro.stderr +++ b/src/test/ui/reserved/reserved-attr-on-macro.stderr @@ -1,15 +1,16 @@ -error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics (see issue #29642) +error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics --> $DIR/reserved-attr-on-macro.rs:1:3 | LL | #[rustc_attribute_should_be_reserved] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(rustc_attrs)] to the crate attributes to enable error: cannot determine resolution for the macro `foo` --> $DIR/reserved-attr-on-macro.rs:8:5 | -LL | foo!(); //~ ERROR cannot determine resolution for the macro `foo` +LL | foo!(); | ^^^ | = note: import resolution is stuck, try simplifying macro imports diff --git a/src/test/ui/resolve/auxiliary/issue_19452_aux.rs b/src/test/ui/resolve/auxiliary/issue-19452-aux.rs similarity index 100% rename from src/test/ui/resolve/auxiliary/issue_19452_aux.rs rename to src/test/ui/resolve/auxiliary/issue-19452-aux.rs diff --git a/src/test/ui/resolve/auxiliary/issue_3907.rs b/src/test/ui/resolve/auxiliary/issue-3907.rs similarity index 100% rename from src/test/ui/resolve/auxiliary/issue_3907.rs rename to src/test/ui/resolve/auxiliary/issue-3907.rs diff --git a/src/test/ui/resolve/enums-are-namespaced-xc.stderr b/src/test/ui/resolve/enums-are-namespaced-xc.stderr index a0771ed9dcad9..3e812c2694d03 100644 --- a/src/test/ui/resolve/enums-are-namespaced-xc.stderr +++ b/src/test/ui/resolve/enums-are-namespaced-xc.stderr @@ -30,5 +30,5 @@ LL | use namespaced_enums::Foo::C; error: aborting due to 3 previous errors -Some errors occurred: E0422, E0425. +Some errors have detailed explanations: E0422, E0425. For more information about an error, try `rustc --explain E0422`. diff --git a/src/test/ui/resolve/issue-14254.stderr b/src/test/ui/resolve/issue-14254.stderr index 783b3addfc2ec..97d42aa8ef4a5 100644 --- a/src/test/ui/resolve/issue-14254.stderr +++ b/src/test/ui/resolve/issue-14254.stderr @@ -20,13 +20,13 @@ error[E0425]: cannot find value `x` in this scope --> $DIR/issue-14254.rs:30:9 | LL | x; - | ^ help: try: `self.x` + | ^ help: you might have meant to use the available field: `self.x` error[E0425]: cannot find value `y` in this scope --> $DIR/issue-14254.rs:32:9 | LL | y; - | ^ help: try: `self.y` + | ^ help: you might have meant to use the available field: `self.y` error[E0425]: cannot find value `a` in this scope --> $DIR/issue-14254.rs:34:9 @@ -56,13 +56,13 @@ error[E0425]: cannot find value `x` in this scope --> $DIR/issue-14254.rs:47:9 | LL | x; - | ^ help: try: `self.x` + | ^ help: you might have meant to use the available field: `self.x` error[E0425]: cannot find value `y` in this scope --> $DIR/issue-14254.rs:49:9 | LL | y; - | ^ help: try: `self.y` + | ^ help: you might have meant to use the available field: `self.y` error[E0425]: cannot find value `a` in this scope --> $DIR/issue-14254.rs:51:9 diff --git a/src/test/ui/resolve/issue-16058.stderr b/src/test/ui/resolve/issue-16058.stderr index 9766f8f1412b6..64177ac2a8310 100644 --- a/src/test/ui/resolve/issue-16058.stderr +++ b/src/test/ui/resolve/issue-16058.stderr @@ -14,4 +14,3 @@ LL | use std::thread::Result; error: aborting due to previous error -For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/resolve/issue-17518.stderr b/src/test/ui/resolve/issue-17518.stderr index 5d080d989446f..057aac25234d2 100644 --- a/src/test/ui/resolve/issue-17518.stderr +++ b/src/test/ui/resolve/issue-17518.stderr @@ -1,7 +1,7 @@ error[E0422]: cannot find struct, variant or union type `E` in this scope --> $DIR/issue-17518.rs:6:5 | -LL | E { name: "foobar" }; //~ ERROR cannot find struct, variant or union type `E` +LL | E { name: "foobar" }; | ^ not found in this scope help: possible candidate is found in another module, you can import it into scope | diff --git a/src/test/ui/resolve/issue-19452.rs b/src/test/ui/resolve/issue-19452.rs index 5c58cabb3cdd8..1d3aa49eac67f 100644 --- a/src/test/ui/resolve/issue-19452.rs +++ b/src/test/ui/resolve/issue-19452.rs @@ -1,4 +1,5 @@ -// aux-build:issue_19452_aux.rs +// aux-build:issue-19452-aux.rs + extern crate issue_19452_aux; enum Homura { diff --git a/src/test/ui/resolve/issue-19452.stderr b/src/test/ui/resolve/issue-19452.stderr index ef96fffee926b..56a0e397b854c 100644 --- a/src/test/ui/resolve/issue-19452.stderr +++ b/src/test/ui/resolve/issue-19452.stderr @@ -1,11 +1,11 @@ error[E0423]: expected value, found struct variant `Homura::Madoka` - --> $DIR/issue-19452.rs:9:18 + --> $DIR/issue-19452.rs:10:18 | LL | let homura = Homura::Madoka; | ^^^^^^^^^^^^^^ did you mean `Homura::Madoka { /* fields */ }`? error[E0423]: expected value, found struct variant `issue_19452_aux::Homura::Madoka` - --> $DIR/issue-19452.rs:12:18 + --> $DIR/issue-19452.rs:13:18 | LL | let homura = issue_19452_aux::Homura::Madoka; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ did you mean `issue_19452_aux::Homura::Madoka { /* fields */ }`? diff --git a/src/test/ui/resolve/issue-21221-1.stderr b/src/test/ui/resolve/issue-21221-1.stderr index 925923f92be4e..d00d87393aab6 100644 --- a/src/test/ui/resolve/issue-21221-1.stderr +++ b/src/test/ui/resolve/issue-21221-1.stderr @@ -47,5 +47,5 @@ LL | use std::ops::Div; error: aborting due to 4 previous errors -Some errors occurred: E0405, E0412. +Some errors have detailed explanations: E0405, E0412. For more information about an error, try `rustc --explain E0405`. diff --git a/src/test/ui/resolve/issue-22692.stderr b/src/test/ui/resolve/issue-22692.stderr index 1c8d959d60d68..e076419f68d47 100644 --- a/src/test/ui/resolve/issue-22692.stderr +++ b/src/test/ui/resolve/issue-22692.stderr @@ -1,10 +1,10 @@ error[E0423]: expected value, found struct `String` --> $DIR/issue-22692.rs:2:13 | -LL | let _ = String.new(); //~ ERROR expected value, found struct `String` +LL | let _ = String.new(); | ^^^^^^---- | | - | help: use `::` to access an associated function: `String::new` + | help: use the path separator to refer to an item: `String::new` error: aborting due to previous error diff --git a/src/test/ui/resolve/issue-23305.rs b/src/test/ui/resolve/issue-23305.rs index af335acd41bc3..95635e12a63b1 100644 --- a/src/test/ui/resolve/issue-23305.rs +++ b/src/test/ui/resolve/issue-23305.rs @@ -2,7 +2,7 @@ pub trait ToNbt { fn new(val: T) -> Self; } -impl ToNbt {} +impl dyn ToNbt {} //~^ ERROR cycle detected fn main() {} diff --git a/src/test/ui/resolve/issue-23305.stderr b/src/test/ui/resolve/issue-23305.stderr index 1da56ad05d28c..0ed3af81d5668 100644 --- a/src/test/ui/resolve/issue-23305.stderr +++ b/src/test/ui/resolve/issue-23305.stderr @@ -1,10 +1,10 @@ -error[E0391]: cycle detected when processing `` - --> $DIR/issue-23305.rs:5:12 +error[E0391]: cycle detected when processing `` + --> $DIR/issue-23305.rs:5:16 | -LL | impl ToNbt {} - | ^^^^ +LL | impl dyn ToNbt {} + | ^^^^ | - = note: ...which again requires processing ``, completing the cycle + = note: ...which again requires processing ``, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-23305.rs:1:1 | diff --git a/src/test/ui/resolve/issue-2356.stderr b/src/test/ui/resolve/issue-2356.stderr index fb4acaa141e35..7790383843e17 100644 --- a/src/test/ui/resolve/issue-2356.stderr +++ b/src/test/ui/resolve/issue-2356.stderr @@ -20,10 +20,7 @@ error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:39:5 | LL | whiskers -= other; - | ^^^^^^^^ - | | - | `self` value is a keyword only available in methods with `self` parameter - | help: try: `self.whiskers` + | ^^^^^^^^ a field by this name exists in `Self` error[E0425]: cannot find function `shave` in this scope --> $DIR/issue-2356.rs:41:5 @@ -83,16 +80,13 @@ error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:79:5 | LL | whiskers = 0; - | ^^^^^^^^ help: try: `self.whiskers` + | ^^^^^^^^ help: you might have meant to use the available field: `self.whiskers` error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:84:5 | LL | whiskers = 4; - | ^^^^^^^^ - | | - | `self` value is a keyword only available in methods with `self` parameter - | help: try: `self.whiskers` + | ^^^^^^^^ a field by this name exists in `Self` error[E0425]: cannot find function `purr_louder` in this scope --> $DIR/issue-2356.rs:86:5 @@ -108,5 +102,5 @@ LL | self += 1; error: aborting due to 17 previous errors -Some errors occurred: E0424, E0425. +Some errors have detailed explanations: E0424, E0425. For more information about an error, try `rustc --explain E0424`. diff --git a/src/test/ui/resolve/issue-33876.rs b/src/test/ui/resolve/issue-33876.rs index dd31fc231cfb5..e233ec631cc13 100644 --- a/src/test/ui/resolve/issue-33876.rs +++ b/src/test/ui/resolve/issue-33876.rs @@ -7,6 +7,6 @@ trait Bar {} impl Bar for Foo {} fn main() { - let any: &Any = &Bar; //~ ERROR expected value, found trait `Bar` + let any: &dyn Any = &Bar; //~ ERROR expected value, found trait `Bar` if any.is::() { println!("u32"); } } diff --git a/src/test/ui/resolve/issue-33876.stderr b/src/test/ui/resolve/issue-33876.stderr index fb61abc950546..52308f2a7f028 100644 --- a/src/test/ui/resolve/issue-33876.stderr +++ b/src/test/ui/resolve/issue-33876.stderr @@ -1,8 +1,8 @@ error[E0423]: expected value, found trait `Bar` - --> $DIR/issue-33876.rs:10:22 + --> $DIR/issue-33876.rs:10:26 | -LL | let any: &Any = &Bar; //~ ERROR expected value, found trait `Bar` - | ^^^ not a value +LL | let any: &dyn Any = &Bar; + | ^^^ not a value error: aborting due to previous error diff --git a/src/test/ui/resolve/issue-3907-2.rs b/src/test/ui/resolve/issue-3907-2.rs index 89e10ca4f2c91..46f145e63e157 100644 --- a/src/test/ui/resolve/issue-3907-2.rs +++ b/src/test/ui/resolve/issue-3907-2.rs @@ -1,7 +1,8 @@ -// aux-build:issue_3907.rs +// aux-build:issue-3907.rs + extern crate issue_3907; -type Foo = issue_3907::Foo+'static; +type Foo = dyn issue_3907::Foo + 'static; struct S { name: isize diff --git a/src/test/ui/resolve/issue-3907-2.stderr b/src/test/ui/resolve/issue-3907-2.stderr index 4fce898dfa96c..968c1f3e463d0 100644 --- a/src/test/ui/resolve/issue-3907-2.stderr +++ b/src/test/ui/resolve/issue-3907-2.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `issue_3907::Foo` cannot be made into an object - --> $DIR/issue-3907-2.rs:10:1 + --> $DIR/issue-3907-2.rs:11:1 | LL | fn bar(_x: Foo) {} | ^^^^^^^^^^^^^^^ the trait `issue_3907::Foo` cannot be made into an object diff --git a/src/test/ui/resolve/issue-3907.rs b/src/test/ui/resolve/issue-3907.rs index a76c3134c0ca3..6211de4271782 100644 --- a/src/test/ui/resolve/issue-3907.rs +++ b/src/test/ui/resolve/issue-3907.rs @@ -1,7 +1,8 @@ -// aux-build:issue_3907.rs +// aux-build:issue-3907.rs + extern crate issue_3907; -type Foo = issue_3907::Foo; +type Foo = dyn issue_3907::Foo; struct S { name: isize diff --git a/src/test/ui/resolve/issue-3907.stderr b/src/test/ui/resolve/issue-3907.stderr index 55bd555676ab2..384df571e2a80 100644 --- a/src/test/ui/resolve/issue-3907.stderr +++ b/src/test/ui/resolve/issue-3907.stderr @@ -1,7 +1,7 @@ error[E0404]: expected trait, found type alias `Foo` - --> $DIR/issue-3907.rs:10:6 + --> $DIR/issue-3907.rs:11:6 | -LL | impl Foo for S { //~ ERROR expected trait, found type alias `Foo` +LL | impl Foo for S { | ^^^ type aliases cannot be used as traits | = note: did you mean to use a trait alias? diff --git a/src/test/ui/resolve/issue-5035-2.rs b/src/test/ui/resolve/issue-5035-2.rs index f88a2375a4315..b831bb4be3487 100644 --- a/src/test/ui/resolve/issue-5035-2.rs +++ b/src/test/ui/resolve/issue-5035-2.rs @@ -1,5 +1,5 @@ trait I {} -type K = I+'static; +type K = dyn I + 'static; fn foo(_x: K) {} //~^ ERROR the size for values of type diff --git a/src/test/ui/resolve/issue-5035.rs b/src/test/ui/resolve/issue-5035.rs index c00567a75b7a3..49fa312f9d257 100644 --- a/src/test/ui/resolve/issue-5035.rs +++ b/src/test/ui/resolve/issue-5035.rs @@ -1,5 +1,5 @@ trait I {} -type K = I; +type K = dyn I; impl K for isize {} //~ ERROR expected trait, found type alias `K` use ImportError; //~ ERROR unresolved import `ImportError` [E0432] diff --git a/src/test/ui/resolve/issue-5035.stderr b/src/test/ui/resolve/issue-5035.stderr index 57ad5f22f4c24..96befdbe07339 100644 --- a/src/test/ui/resolve/issue-5035.stderr +++ b/src/test/ui/resolve/issue-5035.stderr @@ -1,13 +1,13 @@ error[E0432]: unresolved import `ImportError` --> $DIR/issue-5035.rs:5:5 | -LL | use ImportError; //~ ERROR unresolved import `ImportError` [E0432] +LL | use ImportError; | ^^^^^^^^^^^ no `ImportError` in the root error[E0404]: expected trait, found type alias `K` --> $DIR/issue-5035.rs:3:6 | -LL | impl K for isize {} //~ ERROR expected trait, found type alias `K` +LL | impl K for isize {} | ^ | | | type aliases cannot be used as traits @@ -17,5 +17,5 @@ LL | impl K for isize {} //~ ERROR expected trait, found type alias `K` error: aborting due to 2 previous errors -Some errors occurred: E0404, E0432. +Some errors have detailed explanations: E0404, E0432. For more information about an error, try `rustc --explain E0404`. diff --git a/src/test/ui/resolve/issue-54379.rs b/src/test/ui/resolve/issue-54379.rs index a48f66bf0fda0..807c54393f29b 100644 --- a/src/test/ui/resolve/issue-54379.rs +++ b/src/test/ui/resolve/issue-54379.rs @@ -6,7 +6,7 @@ fn main() { let thing = MyStruct { s1: None }; match thing { - MyStruct { .., Some(_) } => {}, //~ ERROR pattern does not mention field `s1` + MyStruct { .., Some(_) } => {}, //~^ ERROR expected `,` //~| ERROR expected `}`, found `,` _ => {} diff --git a/src/test/ui/resolve/issue-54379.stderr b/src/test/ui/resolve/issue-54379.stderr index 9dbab6917c7e8..2a6b54572de03 100644 --- a/src/test/ui/resolve/issue-54379.stderr +++ b/src/test/ui/resolve/issue-54379.stderr @@ -1,7 +1,7 @@ error: expected `}`, found `,` --> $DIR/issue-54379.rs:9:22 | -LL | MyStruct { .., Some(_) } => {}, //~ ERROR pattern does not mention field `s1` +LL | MyStruct { .., Some(_) } => {}, | --^ | | | | | expected `}` @@ -10,15 +10,8 @@ LL | MyStruct { .., Some(_) } => {}, //~ ERROR pattern does not mention error: expected `,` --> $DIR/issue-54379.rs:9:24 | -LL | MyStruct { .., Some(_) } => {}, //~ ERROR pattern does not mention field `s1` +LL | MyStruct { .., Some(_) } => {}, | ^^^^ -error[E0027]: pattern does not mention field `s1` - --> $DIR/issue-54379.rs:9:9 - | -LL | MyStruct { .., Some(_) } => {}, //~ ERROR pattern does not mention field `s1` - | ^^^^^^^^^^^^^^^^^^^^^^^^ missing field `s1` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/resolve/issue-6702.stderr b/src/test/ui/resolve/issue-6702.stderr index 906ac2808aa90..9a46f0d774262 100644 --- a/src/test/ui/resolve/issue-6702.stderr +++ b/src/test/ui/resolve/issue-6702.stderr @@ -1,7 +1,7 @@ error[E0423]: expected function, found struct `Monster` --> $DIR/issue-6702.rs:7:14 | -LL | let _m = Monster(); //~ ERROR expected function, found struct `Monster` +LL | let _m = Monster(); | ^^^^^^^ did you mean `Monster { /* fields */ }`? error: aborting due to previous error diff --git a/src/test/ui/resolve/levenshtein.stderr b/src/test/ui/resolve/levenshtein.stderr index cddfe4e7ff55a..7af2cdf7b5736 100644 --- a/src/test/ui/resolve/levenshtein.stderr +++ b/src/test/ui/resolve/levenshtein.stderr @@ -48,5 +48,5 @@ LL | let b: m::first = m::second; // Misspelled item in module. error: aborting due to 8 previous errors -Some errors occurred: E0412, E0425. +Some errors have detailed explanations: E0412, E0425. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/resolve/name-clash-nullary.stderr b/src/test/ui/resolve/name-clash-nullary.stderr index 5bb9371da6d2e..51793f426d6d4 100644 --- a/src/test/ui/resolve/name-clash-nullary.stderr +++ b/src/test/ui/resolve/name-clash-nullary.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/name-clash-nullary.rs:2:7 | -LL | let None: isize = 42; //~ ERROR mismatched types +LL | let None: isize = 42; | ^^^^ expected isize, found enum `std::option::Option` | = note: expected type `isize` diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index 01f0941282e35..a1a8714ab3f38 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -3,22 +3,32 @@ error[E0423]: expected value, found enum `n::Z` | LL | n::Z; | ^^^^ - | - = note: did you mean to use one of the following variants? - - `m::Z::Fn` - - `m::Z::Struct` - - `m::Z::Unit` +help: try using one of the enum's variants + | +LL | m::Z::Fn; + | ^^^^^^^^ +LL | m::Z::Struct; + | ^^^^^^^^^^^^ +LL | m::Z::Unit; + | ^^^^^^^^^^ error[E0423]: expected value, found enum `Z` --> $DIR/privacy-enum-ctor.rs:25:9 | LL | Z; - | ^ help: a function with a similar name exists: `f` + | ^ +help: a function with a similar name exists | - = note: did you mean to use one of the following variants? - - `m::Z::Fn` - - `m::Z::Struct` - - `m::Z::Unit` +LL | f; + | ^ +help: try using one of the enum's variants + | +LL | m::Z::Fn; + | ^^^^^^^^ +LL | m::Z::Struct; + | ^^^^^^^^^^^^ +LL | m::Z::Unit; + | ^^^^^^^^^^ error[E0423]: expected value, found struct variant `Z::Struct` --> $DIR/privacy-enum-ctor.rs:29:20 @@ -31,15 +41,18 @@ error[E0423]: expected value, found enum `m::E` | LL | let _: E = m::E; | ^^^^ - | - = note: did you mean to use one of the following variants? - - `E::Fn` - - `E::Struct` - - `E::Unit` help: a function with a similar name exists | LL | let _: E = m::f; | ^ +help: try using one of the enum's variants + | +LL | let _: E = E::Fn; + | ^^^^^ +LL | let _: E = E::Struct; + | ^^^^^^^^^ +LL | let _: E = E::Unit; + | ^^^^^^^ help: possible better candidates are found in other modules, you can import them into scope | LL | use std::f32::consts::E; @@ -58,11 +71,14 @@ error[E0423]: expected value, found enum `E` | LL | let _: E = E; | ^ +help: try using one of the enum's variants | - = note: did you mean to use one of the following variants? - - `E::Fn` - - `E::Struct` - - `E::Unit` +LL | let _: E = E::Fn; + | ^^^^^ +LL | let _: E = E::Struct; + | ^^^^^^^^^ +LL | let _: E = E::Unit; + | ^^^^^^^ help: possible better candidates are found in other modules, you can import them into scope | LL | use std::f32::consts::E; @@ -95,11 +111,14 @@ error[E0423]: expected value, found enum `m::n::Z` | LL | let _: Z = m::n::Z; | ^^^^^^^ +help: try using one of the enum's variants | - = note: did you mean to use one of the following variants? - - `m::Z::Fn` - - `m::Z::Struct` - - `m::Z::Unit` +LL | let _: Z = m::Z::Fn; + | ^^^^^^^^ +LL | let _: Z = m::Z::Struct; + | ^^^^^^^^^^^^ +LL | let _: Z = m::Z::Unit; + | ^^^^^^^^^^ error[E0412]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:61:12 @@ -247,5 +266,5 @@ LL | let _: E = E::Unit; error: aborting due to 23 previous errors -Some errors occurred: E0308, E0412, E0423, E0603, E0618. +Some errors have detailed explanations: E0308, E0412, E0423, E0603, E0618. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/resolve/privacy-struct-ctor.stderr b/src/test/ui/resolve/privacy-struct-ctor.stderr index 519e74d9f6315..9bf7d19117448 100644 --- a/src/test/ui/resolve/privacy-struct-ctor.stderr +++ b/src/test/ui/resolve/privacy-struct-ctor.stderr @@ -67,5 +67,5 @@ LL | xcrate::m::n::Z; error: aborting due to 10 previous errors -Some errors occurred: E0423, E0603. +Some errors have detailed explanations: E0423, E0603. For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/resolve/resolve-assoc-suggestions.stderr b/src/test/ui/resolve/resolve-assoc-suggestions.stderr index f2e1d72e7a351..87040015b8d80 100644 --- a/src/test/ui/resolve/resolve-assoc-suggestions.stderr +++ b/src/test/ui/resolve/resolve-assoc-suggestions.stderr @@ -14,7 +14,7 @@ error[E0425]: cannot find value `field` in this scope --> $DIR/resolve-assoc-suggestions.rs:20:9 | LL | field; - | ^^^^^ help: try: `self.field` + | ^^^^^ help: you might have meant to use the available field: `self.field` error[E0412]: cannot find type `Type` in this scope --> $DIR/resolve-assoc-suggestions.rs:23:16 @@ -54,5 +54,5 @@ LL | method; error: aborting due to 9 previous errors -Some errors occurred: E0412, E0425, E0531. +Some errors have detailed explanations: E0412, E0425. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/resolve/resolve-bad-import-prefix.stderr b/src/test/ui/resolve/resolve-bad-import-prefix.stderr index f39e1edb61347..852b9c6afff3e 100644 --- a/src/test/ui/resolve/resolve-bad-import-prefix.stderr +++ b/src/test/ui/resolve/resolve-bad-import-prefix.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `Nonexistent` --> $DIR/resolve-bad-import-prefix.rs:12:5 | -LL | use Nonexistent::{}; //~ ERROR unresolved import `Nonexistent` +LL | use Nonexistent::{}; | ^^^^^^^^^^^^^^^ no `Nonexistent` in the root error: aborting due to previous error diff --git a/src/test/ui/resolve/resolve-bad-visibility.stderr b/src/test/ui/resolve/resolve-bad-visibility.stderr index 519e7a946e14c..b8004a48a6777 100644 --- a/src/test/ui/resolve/resolve-bad-visibility.stderr +++ b/src/test/ui/resolve/resolve-bad-visibility.stderr @@ -1,34 +1,32 @@ error: visibilities can only be restricted to ancestor modules --> $DIR/resolve-bad-visibility.rs:6:8 | -LL | pub(in std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules +LL | pub(in std::vec) struct F; | ^^^^^^^^ error[E0577]: expected module, found enum `E` --> $DIR/resolve-bad-visibility.rs:4:8 | -LL | pub(in E) struct S; //~ ERROR expected module, found enum `E` +LL | pub(in E) struct S; | ^ not a module error[E0577]: expected module, found trait `Tr` --> $DIR/resolve-bad-visibility.rs:5:8 | -LL | pub(in Tr) struct Z; //~ ERROR expected module, found trait `Tr` +LL | pub(in Tr) struct Z; | ^^ not a module error[E0578]: cannot find module `nonexistent` in the crate root --> $DIR/resolve-bad-visibility.rs:7:8 | -LL | pub(in nonexistent) struct G; //~ ERROR cannot find module `nonexistent` in the crate root +LL | pub(in nonexistent) struct G; | ^^^^^^^^^^^ not found in the crate root error[E0578]: cannot find module `too_soon` in the crate root --> $DIR/resolve-bad-visibility.rs:8:8 | -LL | pub(in too_soon) struct H; //~ ERROR cannot find module `too_soon` in the crate root +LL | pub(in too_soon) struct H; | ^^^^^^^^ not found in the crate root error: aborting due to 5 previous errors -Some errors occurred: E0577, E0578. -For more information about an error, try `rustc --explain E0577`. diff --git a/src/test/ui/resolve/resolve-conflict-import-vs-extern-crate.stderr b/src/test/ui/resolve/resolve-conflict-import-vs-extern-crate.stderr index 24889a0a820ea..a0a858209019d 100644 --- a/src/test/ui/resolve/resolve-conflict-import-vs-extern-crate.stderr +++ b/src/test/ui/resolve/resolve-conflict-import-vs-extern-crate.stderr @@ -1,13 +1,13 @@ error[E0254]: the name `std` is defined multiple times --> $DIR/resolve-conflict-import-vs-extern-crate.rs:1:5 | -LL | use std::slice as std; //~ ERROR the name `std` is defined multiple times +LL | use std::slice as std; | ^^^^^^^^^^^^^^^^^ `std` reimported here | = note: `std` must be defined only once in the type namespace of this module help: you can use `as` to change the binding name of the import | -LL | use std::slice as other_std; //~ ERROR the name `std` is defined multiple times +LL | use std::slice as other_std; | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/resolve/resolve-conflict-import-vs-import.stderr b/src/test/ui/resolve/resolve-conflict-import-vs-import.stderr index 1b4b058b783ad..8df68ad3229ed 100644 --- a/src/test/ui/resolve/resolve-conflict-import-vs-import.stderr +++ b/src/test/ui/resolve/resolve-conflict-import-vs-import.stderr @@ -4,10 +4,7 @@ error[E0252]: the name `transmute` is defined multiple times LL | use std::mem::transmute; | ------------------- previous import of the value `transmute` here LL | use std::mem::transmute; - | ----^^^^^^^^^^^^^^^^^^^- - | | | - | | `transmute` reimported here - | help: remove unnecessary import + | ^^^^^^^^^^^^^^^^^^^ `transmute` reimported here | = note: `transmute` must be defined only once in the value namespace of this module diff --git a/src/test/ui/resolve/resolve-conflict-item-vs-extern-crate.stderr b/src/test/ui/resolve/resolve-conflict-item-vs-extern-crate.stderr index 5e190bf318530..7b9fb6c63f677 100644 --- a/src/test/ui/resolve/resolve-conflict-item-vs-extern-crate.stderr +++ b/src/test/ui/resolve/resolve-conflict-item-vs-extern-crate.stderr @@ -1,7 +1,7 @@ error[E0260]: the name `std` is defined multiple times --> $DIR/resolve-conflict-item-vs-extern-crate.rs:2:1 | -LL | mod std {} //~ ERROR the name `std` is defined multiple times +LL | mod std {} | ^^^^^^^ `std` redefined here | = note: `std` must be defined only once in the type namespace of this module diff --git a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr index a14d3d67b10a3..6f660872f5e58 100644 --- a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr +++ b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr @@ -49,5 +49,5 @@ LL | Opts::A(ref mut i) | Opts::B(ref i) => {} error: aborting due to 6 previous errors -Some errors occurred: E0308, E0409. +Some errors have detailed explanations: E0308, E0409. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/resolve/resolve-inconsistent-names.stderr b/src/test/ui/resolve/resolve-inconsistent-names.stderr index 20346d5aefe78..c75718149fa4e 100644 --- a/src/test/ui/resolve/resolve-inconsistent-names.stderr +++ b/src/test/ui/resolve/resolve-inconsistent-names.stderr @@ -1,7 +1,7 @@ error[E0408]: variable `a` is not bound in all patterns --> $DIR/resolve-inconsistent-names.rs:4:12 | -LL | a | b => {} //~ ERROR variable `a` is not bound in all patterns +LL | a | b => {} | - ^ pattern doesn't bind `a` | | | variable not in all patterns @@ -9,7 +9,7 @@ LL | a | b => {} //~ ERROR variable `a` is not bound in all patterns error[E0408]: variable `b` is not bound in all patterns --> $DIR/resolve-inconsistent-names.rs:4:8 | -LL | a | b => {} //~ ERROR variable `a` is not bound in all patterns +LL | a | b => {} | ^ - variable not in all patterns | | | pattern doesn't bind `b` diff --git a/src/test/ui/resolve/resolve-label.stderr b/src/test/ui/resolve/resolve-label.stderr index fecfd922347b3..72a8e443bac9f 100644 --- a/src/test/ui/resolve/resolve-label.stderr +++ b/src/test/ui/resolve/resolve-label.stderr @@ -1,7 +1,7 @@ error[E0426]: use of undeclared label `'l` --> $DIR/resolve-label.rs:5:23 | -LL | break 'l; //~ ERROR use of undeclared label +LL | break 'l; | ^^ undeclared label `'l` error: aborting due to previous error diff --git a/src/test/ui/resolve/resolve-primitive-fallback.stderr b/src/test/ui/resolve/resolve-primitive-fallback.stderr index 963bab43551c4..92c2a03298381 100644 --- a/src/test/ui/resolve/resolve-primitive-fallback.stderr +++ b/src/test/ui/resolve/resolve-primitive-fallback.stderr @@ -18,5 +18,5 @@ LL | std::mem::size_of(u16); error: aborting due to 3 previous errors -Some errors occurred: E0061, E0412, E0423. +Some errors have detailed explanations: E0061, E0412, E0423. For more information about an error, try `rustc --explain E0061`. diff --git a/src/test/ui/resolve/resolve-self-in-impl-2.stderr b/src/test/ui/resolve/resolve-self-in-impl-2.stderr index 1f5887e1352e7..3791fe90a6bae 100644 --- a/src/test/ui/resolve/resolve-self-in-impl-2.stderr +++ b/src/test/ui/resolve/resolve-self-in-impl-2.stderr @@ -1,16 +1,16 @@ error[E0411]: expected trait, found self type `Self` --> $DIR/resolve-self-in-impl-2.rs:4:6 | -LL | impl Self for S {} //~ ERROR expected trait, found self type `Self` +LL | impl Self for S {} | ^^^^ `Self` is only available in impls, traits, and type definitions error[E0405]: cannot find trait `N` in `Self` --> $DIR/resolve-self-in-impl-2.rs:5:12 | -LL | impl Self::N for S {} //~ ERROR cannot find trait `N` in `Self` +LL | impl Self::N for S {} | ^ not found in `Self` error: aborting due to 2 previous errors -Some errors occurred: E0405, E0411. +Some errors have detailed explanations: E0405, E0411. For more information about an error, try `rustc --explain E0405`. diff --git a/src/test/ui/resolve/resolve-self-in-impl.stderr b/src/test/ui/resolve/resolve-self-in-impl.stderr index 1940c0cd2a4b7..58e851e5c12ca 100644 --- a/src/test/ui/resolve/resolve-self-in-impl.stderr +++ b/src/test/ui/resolve/resolve-self-in-impl.stderr @@ -1,7 +1,7 @@ error[E0391]: cycle detected when processing `` --> $DIR/resolve-self-in-impl.rs:14:13 | -LL | impl Tr for Self {} //~ ERROR cycle detected +LL | impl Tr for Self {} | ^^^^ | = note: ...which again requires processing ``, completing the cycle @@ -20,7 +20,7 @@ LL | | fn main() {} error[E0391]: cycle detected when processing `` --> $DIR/resolve-self-in-impl.rs:15:15 | -LL | impl Tr for S {} //~ ERROR cycle detected +LL | impl Tr for S {} | ^^^^ | = note: ...which again requires processing ``, completing the cycle @@ -39,7 +39,7 @@ LL | | fn main() {} error[E0391]: cycle detected when processing `` --> $DIR/resolve-self-in-impl.rs:16:6 | -LL | impl Self {} //~ ERROR cycle detected +LL | impl Self {} | ^^^^ | = note: ...which again requires processing ``, completing the cycle @@ -58,7 +58,7 @@ LL | | fn main() {} error[E0391]: cycle detected when processing `` --> $DIR/resolve-self-in-impl.rs:17:8 | -LL | impl S {} //~ ERROR cycle detected +LL | impl S {} | ^^^^ | = note: ...which again requires processing ``, completing the cycle @@ -77,7 +77,7 @@ LL | | fn main() {} error[E0391]: cycle detected when processing `` --> $DIR/resolve-self-in-impl.rs:18:1 | -LL | impl Tr for S {} //~ ERROR cycle detected +LL | impl Tr for S {} | ^^^^^^^^^^^^^^^^^^^^^^ | = note: ...which again requires processing ``, completing the cycle diff --git a/src/test/ui/resolve/resolve-speculative-adjustment.stderr b/src/test/ui/resolve/resolve-speculative-adjustment.stderr index c4a6ced1ca4c0..892b50309a905 100644 --- a/src/test/ui/resolve/resolve-speculative-adjustment.stderr +++ b/src/test/ui/resolve/resolve-speculative-adjustment.stderr @@ -14,7 +14,7 @@ error[E0425]: cannot find value `field` in this scope --> $DIR/resolve-speculative-adjustment.rs:23:9 | LL | field; - | ^^^^^ help: try: `self.field` + | ^^^^^ help: you might have meant to use the available field: `self.field` error[E0425]: cannot find function `method` in this scope --> $DIR/resolve-speculative-adjustment.rs:25:9 diff --git a/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr b/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr index f6b8abf4057e5..10a703ee09351 100644 --- a/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr +++ b/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr @@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/resolve-type-param-in-item-in-trait.rs:8:22 | LL | trait TraitA { - | - type variable from outer function + | - type parameter from outer function LL | fn outer(&self) { | ----- try adding a local generic parameter in this method instead LL | enum Foo { @@ -13,7 +13,7 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/resolve-type-param-in-item-in-trait.rs:16:23 | LL | trait TraitB { - | - type variable from outer function + | - type parameter from outer function LL | fn outer(&self) { | ----- try adding a local generic parameter in this method instead LL | struct Foo(A); @@ -23,7 +23,7 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/resolve-type-param-in-item-in-trait.rs:23:28 | LL | trait TraitC { - | - type variable from outer function + | - type parameter from outer function LL | fn outer(&self) { | ----- try adding a local generic parameter in this method instead LL | struct Foo { a: A } @@ -33,7 +33,7 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/resolve-type-param-in-item-in-trait.rs:30:22 | LL | trait TraitD { - | - type variable from outer function + | - type parameter from outer function LL | fn outer(&self) { LL | fn foo(a: A) { } | ------ ^ use of generic parameter from outer function diff --git a/src/test/ui/resolve/resolve-variant-assoc-item.rs b/src/test/ui/resolve/resolve-variant-assoc-item.rs index f0f55c0c66718..db4fedfb0bdf8 100644 --- a/src/test/ui/resolve/resolve-variant-assoc-item.rs +++ b/src/test/ui/resolve/resolve-variant-assoc-item.rs @@ -2,6 +2,6 @@ enum E { V } use E::V; fn main() { - E::V::associated_item; //~ ERROR failed to resolve: not a module `V` - V::associated_item; //~ ERROR failed to resolve: not a module `V` + E::V::associated_item; //~ ERROR failed to resolve: `V` is a variant, not a module + V::associated_item; //~ ERROR failed to resolve: `V` is a variant, not a module } diff --git a/src/test/ui/resolve/resolve-variant-assoc-item.stderr b/src/test/ui/resolve/resolve-variant-assoc-item.stderr index b93005849f430..4be1019968bcc 100644 --- a/src/test/ui/resolve/resolve-variant-assoc-item.stderr +++ b/src/test/ui/resolve/resolve-variant-assoc-item.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: not a module `V` +error[E0433]: failed to resolve: `V` is a variant, not a module --> $DIR/resolve-variant-assoc-item.rs:5:8 | -LL | E::V::associated_item; //~ ERROR failed to resolve: not a module `V` - | ^ not a module `V` +LL | E::V::associated_item; + | ^ `V` is a variant, not a module -error[E0433]: failed to resolve: not a module `V` +error[E0433]: failed to resolve: `V` is a variant, not a module --> $DIR/resolve-variant-assoc-item.rs:6:5 | -LL | V::associated_item; //~ ERROR failed to resolve: not a module `V` - | ^ not a module `V` +LL | V::associated_item; + | ^ `V` is a variant, not a module error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/token-error-correct-2.stderr b/src/test/ui/resolve/token-error-correct-2.stderr index 481ed88288971..d568117d67626 100644 --- a/src/test/ui/resolve/token-error-correct-2.stderr +++ b/src/test/ui/resolve/token-error-correct-2.stderr @@ -3,8 +3,8 @@ error: incorrect close delimiter: `)` | LL | if foo { | - un-closed delimiter -LL | //~^ ERROR: cannot find value `foo` -LL | ) //~ ERROR: incorrect close delimiter: `)` +LL | +LL | ) | ^ incorrect close delimiter error[E0425]: cannot find value `foo` in this scope diff --git a/src/test/ui/resolve/token-error-correct-3.rs b/src/test/ui/resolve/token-error-correct-3.rs index b1ca0bbfc57c1..212b88ac8b05f 100644 --- a/src/test/ui/resolve/token-error-correct-3.rs +++ b/src/test/ui/resolve/token-error-correct-3.rs @@ -10,16 +10,14 @@ pub mod raw { pub fn ensure_dir_exists, F: FnOnce(&Path)>(path: P, callback: F) -> io::Result { - if !is_directory(path.as_ref()) { //~ ERROR: cannot find function `is_directory` - callback(path.as_ref(); //~ ERROR expected one of - fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types - //~^ expected (), found enum `std::result::Result` - //~| expected type `()` - //~| found type `std::result::Result` - //~| expected one of + if !is_directory(path.as_ref()) { + //~^ ERROR cannot find function `is_directory` + callback(path.as_ref(); + //~^ ERROR expected one of + fs::create_dir_all(path.as_ref()).map(|()| true) + //~^ ERROR mismatched types } else { - //~^ ERROR: expected one of - //~| unexpected token + //~^ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `)` Ok(false); } diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index a6bb83c71f313..607573f27698b 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -1,31 +1,30 @@ error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;` - --> $DIR/token-error-correct-3.rs:14:35 + --> $DIR/token-error-correct-3.rs:15:35 | -LL | callback(path.as_ref(); //~ ERROR expected one of - | - ^ - | | | - | | help: `)` may belong here +LL | callback(path.as_ref(); + | - ^ help: `)` may belong here + | | | unclosed delimiter error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` - --> $DIR/token-error-correct-3.rs:20:9 + --> $DIR/token-error-correct-3.rs:19:9 | -LL | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types +LL | fs::create_dir_all(path.as_ref()).map(|()| true) | - expected one of `.`, `;`, `?`, `}`, or an operator here -... +LL | LL | } else { | ^ unexpected token error[E0425]: cannot find function `is_directory` in this scope --> $DIR/token-error-correct-3.rs:13:13 | -LL | if !is_directory(path.as_ref()) { //~ ERROR: cannot find function `is_directory` +LL | if !is_directory(path.as_ref()) { | ^^^^^^^^^^^^ not found in this scope error[E0308]: mismatched types - --> $DIR/token-error-correct-3.rs:15:13 + --> $DIR/token-error-correct-3.rs:17:13 | -LL | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types +LL | fs::create_dir_all(path.as_ref()).map(|()| true) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;` | | | expected (), found enum `std::result::Result` @@ -35,5 +34,5 @@ LL | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mis error: aborting due to 4 previous errors -Some errors occurred: E0308, E0425. +Some errors have detailed explanations: E0308, E0425. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index b0827ea7367c2..9452e2d68deca 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -5,7 +5,7 @@ LL | fn main() { | - close delimiter possibly meant for this LL | foo(bar(; | - un-closed delimiter -LL | //~^ ERROR cannot find function `bar` in this scope +LL | LL | } | ^ incorrect close delimiter diff --git a/src/test/ui/resolve/tuple-struct-alias.stderr b/src/test/ui/resolve/tuple-struct-alias.stderr index f299aa40a31ef..02af357a2c32c 100644 --- a/src/test/ui/resolve/tuple-struct-alias.stderr +++ b/src/test/ui/resolve/tuple-struct-alias.stderr @@ -1,7 +1,7 @@ error[E0423]: expected function, found type alias `A` --> $DIR/tuple-struct-alias.rs:5:13 | -LL | let s = A(0, 1); //~ ERROR expected function +LL | let s = A(0, 1); | ^ help: a tuple struct with a similar name exists: `S` | = note: can't use a type alias as a constructor @@ -9,12 +9,12 @@ LL | let s = A(0, 1); //~ ERROR expected function error[E0532]: expected tuple struct/variant, found type alias `A` --> $DIR/tuple-struct-alias.rs:7:9 | -LL | A(..) => {} //~ ERROR expected tuple struct/variant +LL | A(..) => {} | ^ help: a tuple struct with a similar name exists: `S` | = note: can't use a type alias as a constructor error: aborting due to 2 previous errors -Some errors occurred: E0423, E0532. +Some errors have detailed explanations: E0423, E0532. For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr index 70cabcbeb60b8..c86a6d70344cc 100644 --- a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr +++ b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr @@ -14,5 +14,5 @@ LL | fn g isize>(x: F) {} error: aborting due to 2 previous errors -Some errors occurred: E0404, E0405. +Some errors have detailed explanations: E0404, E0405. For more information about an error, try `rustc --explain E0404`. diff --git a/src/test/ui/resolve/unresolved_static_type_field.stderr b/src/test/ui/resolve/unresolved_static_type_field.stderr index a517324378772..06926b53ddd35 100644 --- a/src/test/ui/resolve/unresolved_static_type_field.stderr +++ b/src/test/ui/resolve/unresolved_static_type_field.stderr @@ -2,10 +2,7 @@ error[E0425]: cannot find value `cx` in this scope --> $DIR/unresolved_static_type_field.rs:9:11 | LL | f(cx); - | ^^ - | | - | `self` value is a keyword only available in methods with `self` parameter - | help: try: `self.cx` + | ^^ a field by this name exists in `Self` error: aborting due to previous error diff --git a/src/test/ui/resolve/use_suggestion_placement.stderr b/src/test/ui/resolve/use_suggestion_placement.stderr index dcbb8dfe665ce..258b989387c50 100644 --- a/src/test/ui/resolve/use_suggestion_placement.stderr +++ b/src/test/ui/resolve/use_suggestion_placement.stderr @@ -1,7 +1,7 @@ error[E0412]: cannot find type `Path` in this scope --> $DIR/use_suggestion_placement.rs:17:16 | -LL | type Bar = Path; //~ ERROR cannot find +LL | type Bar = Path; | ^^^^ not found in this scope help: possible candidate is found in another module, you can import it into scope | @@ -11,7 +11,7 @@ LL | use std::path::Path; error[E0425]: cannot find value `A` in this scope --> $DIR/use_suggestion_placement.rs:22:13 | -LL | let _ = A; //~ ERROR cannot find +LL | let _ = A; | ^ not found in this scope help: possible candidate is found in another module, you can import it into scope | @@ -21,7 +21,7 @@ LL | use m::A; error[E0412]: cannot find type `HashMap` in this scope --> $DIR/use_suggestion_placement.rs:27:23 | -LL | type Dict = HashMap; //~ ERROR cannot find +LL | type Dict = HashMap; | ^^^^^^^ not found in this scope help: possible candidates are found in other modules, you can import them into scope | @@ -32,5 +32,5 @@ LL | use std::collections::hash_map::HashMap; error: aborting due to 3 previous errors -Some errors occurred: E0412, E0425. +Some errors have detailed explanations: E0412, E0425. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/resolve_self_super_hint.rs b/src/test/ui/resolve_self_super_hint.rs index 193a6ecf9d570..a9423830d9040 100644 --- a/src/test/ui/resolve_self_super_hint.rs +++ b/src/test/ui/resolve_self_super_hint.rs @@ -1,23 +1,26 @@ -#![feature(alloc)] #![allow(unused_extern_crates)] mod a { extern crate alloc; use alloc::HashMap; //~^ ERROR unresolved import `alloc` [E0432] - //~| did you mean `self::alloc`? + //~| HELP a similar path exists + //~| SUGGESTION self::alloc mod b { use alloc::HashMap; //~^ ERROR unresolved import `alloc` [E0432] - //~| did you mean `super::alloc`? + //~| HELP a similar path exists + //~| SUGGESTION super::alloc mod c { use alloc::HashMap; //~^ ERROR unresolved import `alloc` [E0432] - //~| did you mean `a::alloc`? + //~| HELP a similar path exists + //~| SUGGESTION a::alloc mod d { use alloc::HashMap; //~^ ERROR unresolved import `alloc` [E0432] - //~| did you mean `a::alloc`? + //~| HELP a similar path exists + //~| SUGGESTION a::alloc } } } diff --git a/src/test/ui/resolve_self_super_hint.stderr b/src/test/ui/resolve_self_super_hint.stderr index ddae0e5f6aaba..14cdae97d14f3 100644 --- a/src/test/ui/resolve_self_super_hint.stderr +++ b/src/test/ui/resolve_self_super_hint.stderr @@ -1,26 +1,32 @@ error[E0432]: unresolved import `alloc` - --> $DIR/resolve_self_super_hint.rs:6:9 + --> $DIR/resolve_self_super_hint.rs:5:9 | LL | use alloc::HashMap; - | ^^^^^ did you mean `self::alloc`? + | ^^^^^ help: a similar path exists: `self::alloc` error[E0432]: unresolved import `alloc` --> $DIR/resolve_self_super_hint.rs:10:13 | LL | use alloc::HashMap; - | ^^^^^ did you mean `super::alloc`? + | ^^^^^ help: a similar path exists: `super::alloc` error[E0432]: unresolved import `alloc` - --> $DIR/resolve_self_super_hint.rs:14:17 + --> $DIR/resolve_self_super_hint.rs:15:17 | LL | use alloc::HashMap; - | ^^^^^ did you mean `a::alloc`? + | ^^^^^ + | | + | unresolved import + | help: a similar path exists: `a::alloc` error[E0432]: unresolved import `alloc` - --> $DIR/resolve_self_super_hint.rs:18:21 + --> $DIR/resolve_self_super_hint.rs:20:21 | LL | use alloc::HashMap; - | ^^^^^ did you mean `a::alloc`? + | ^^^^^ + | | + | unresolved import + | help: a similar path exists: `a::alloc` error: aborting due to 4 previous errors diff --git a/src/test/ui/retslot-cast.stderr b/src/test/ui/retslot-cast.stderr index 855aa501082b1..a1169910ae7e2 100644 --- a/src/test/ui/retslot-cast.stderr +++ b/src/test/ui/retslot-cast.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types --> $DIR/retslot-cast.rs:13:5 | -LL | inner(x) //~ ERROR mismatched types - | ^^^^^^^^ expected trait `std::iter::Iterator`, found trait `std::iter::Iterator + std::marker::Send` +LL | inner(x) + | ^^^^^^^^ expected trait `std::iter::Iterator`, found trait `std::iter::Iterator + std::marker::Send` | - = note: expected type `std::option::Option<&dyn std::iter::Iterator>` - found type `std::option::Option<&dyn std::iter::Iterator + std::marker::Send>` + = note: expected type `std::option::Option<&dyn std::iter::Iterator>` + found type `std::option::Option<&dyn std::iter::Iterator + std::marker::Send>` error: aborting due to previous error diff --git a/src/test/ui/return/return-from-diverging.rs b/src/test/ui/return/return-from-diverging.rs index faeccaace6987..2ee48e7bc4762 100644 --- a/src/test/ui/return/return-from-diverging.rs +++ b/src/test/ui/return/return-from-diverging.rs @@ -6,4 +6,3 @@ fn fail() -> ! { fn main() { } - diff --git a/src/test/ui/return/return-from-diverging.stderr b/src/test/ui/return/return-from-diverging.stderr index 2862ae641df15..3dd029c14c0fd 100644 --- a/src/test/ui/return/return-from-diverging.stderr +++ b/src/test/ui/return/return-from-diverging.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | fn fail() -> ! { | - expected `!` because of return type -LL | return "wow"; //~ ERROR mismatched types +LL | return "wow"; | ^^^^^ expected !, found reference | = note: expected type `!` diff --git a/src/test/ui/return/return-match-array-const.stderr b/src/test/ui/return/return-match-array-const.stderr index 763b3d987d7cf..6e8c9ed40bbee 100644 --- a/src/test/ui/return/return-match-array-const.stderr +++ b/src/test/ui/return/return-match-array-const.stderr @@ -1,19 +1,19 @@ error[E0572]: return statement outside of function body --> $DIR/return-match-array-const.rs:2:10 | -LL | [(); return match 0 { n => n }]; //~ ERROR: return statement outside of function body +LL | [(); return match 0 { n => n }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0572]: return statement outside of function body --> $DIR/return-match-array-const.rs:4:10 | -LL | [(); return match 0 { 0 => 0 }]; //~ ERROR: return statement outside of function body +LL | [(); return match 0 { 0 => 0 }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0572]: return statement outside of function body --> $DIR/return-match-array-const.rs:6:10 | -LL | [(); return match () { 'a' => 0, _ => 0 }]; //~ ERROR: return statement outside of function body +LL | [(); return match () { 'a' => 0, _ => 0 }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/return/return-unit-from-diverging.rs b/src/test/ui/return/return-unit-from-diverging.rs index 31a13784b478d..48417599b1d87 100644 --- a/src/test/ui/return/return-unit-from-diverging.rs +++ b/src/test/ui/return/return-unit-from-diverging.rs @@ -7,4 +7,3 @@ fn fail() -> ! { fn main() { } - diff --git a/src/test/ui/return/return-unit-from-diverging.stderr b/src/test/ui/return/return-unit-from-diverging.stderr index 19eccac343380..befc57563a9c5 100644 --- a/src/test/ui/return/return-unit-from-diverging.stderr +++ b/src/test/ui/return/return-unit-from-diverging.stderr @@ -3,7 +3,7 @@ error[E0069]: `return;` in a function whose return type is not `()` | LL | fn fail() -> ! { | - expected `!` because of this return type -LL | return; //~ ERROR in a function whose return type is not +LL | return; | ^^^^^^ return type is not `()` error: aborting due to previous error diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs index 2f3c094ff3954..7b499af632ece 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs @@ -4,7 +4,6 @@ // compile-pass -#![feature(nll)] #![feature(bind_by_move_pattern_guards)] use std::sync::mpsc::channel; diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2015.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2015.stderr index 4c17ce23b3768..34e8b0e14399e 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2015.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2015.stderr @@ -1,9 +1,10 @@ -error[E0008]: cannot bind by-move into a pattern guard - --> $DIR/feature-gate.rs:33:16 +error: compilation successful + --> $DIR/feature-gate.rs:41:1 | -LL | A { a: v } if *v == 42 => v, - | ^ moves value into pattern guard +LL | / fn main() { +LL | | foo(107) +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0008`. diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2018.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2018.stderr index 4bde9b0c8d910..34e8b0e14399e 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2018.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2018.stderr @@ -1,5 +1,5 @@ error: compilation successful - --> $DIR/feature-gate.rs:42:1 + --> $DIR/feature-gate.rs:41:1 | LL | / fn main() { LL | | foo(107) diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_feature_nll.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_feature_nll.stderr index 4bde9b0c8d910..34e8b0e14399e 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_feature_nll.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_feature_nll.stderr @@ -1,5 +1,5 @@ error: compilation successful - --> $DIR/feature-gate.rs:42:1 + --> $DIR/feature-gate.rs:41:1 | LL | / fn main() { LL | | foo(107) diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_znll.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_znll.stderr index 4bde9b0c8d910..34e8b0e14399e 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_znll.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_znll.stderr @@ -1,5 +1,5 @@ error: compilation successful - --> $DIR/feature-gate.rs:42:1 + --> $DIR/feature-gate.rs:41:1 | LL | / fn main() { LL | | foo(107) diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.no_gate.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.no_gate.stderr index 4c17ce23b3768..2a1a04b3f494c 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.no_gate.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.no_gate.stderr @@ -3,6 +3,8 @@ error[E0008]: cannot bind by-move into a pattern guard | LL | A { a: v } if *v == 42 => v, | ^ moves value into pattern guard + | + = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.rs index f6df4d07baad0..97f90f7762a41 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.rs +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.rs @@ -32,7 +32,6 @@ fn foo(n: i32) { A { a: v } if *v == 42 => v, //[no_gate]~^ ERROR cannot bind by-move into a pattern guard - //[gate_and_2015]~^^ ERROR cannot bind by-move into a pattern guard _ => Box::new(0) }; @@ -42,6 +41,7 @@ fn foo(n: i32) { fn main() { foo(107) } -//[gate_and_2018]~^^^ ERROR compilation successful -//[gate_and_znll]~^^^^ ERROR compilation successful -//[gate_and_feature_nll]~^^^^^ ERROR compilation successful +//[gate_and_2015]~^^^ ERROR compilation successful +//[gate_and_2018]~^^^^ ERROR compilation successful +//[gate_and_znll]~^^^^^ ERROR compilation successful +//[gate_and_feature_nll]~^^^^^^ ERROR compilation successful diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs index 9a9d11ce1b13e..aca6aa5f0f867 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs @@ -1,4 +1,3 @@ -#![feature(nll)] #![feature(bind_by_move_pattern_guards)] // compile-pass diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs index 0fec6b273d3bc..bf387d01b6b2e 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs @@ -6,7 +6,7 @@ enum VecWrapper { A(Vec) } fn foo(x: VecWrapper) -> usize { match x { VecWrapper::A(v) if { drop(v); false } => 1, - //~^ ERROR cannot move out of borrowed content + //~^ ERROR cannot move out of `v` in pattern guard VecWrapper::A(v) => v.len() } } diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr index 502006e1b3f90..f6e4e5bd49bf8 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr @@ -1,8 +1,10 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `v` in pattern guard --> $DIR/rfc-reject-double-move-across-arms.rs:8:36 | LL | VecWrapper::A(v) if { drop(v); false } => 1, - | ^ cannot move out of borrowed content + | ^ move occurs because `v` has type `std::vec::Vec`, which does not implement the `Copy` trait + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error: aborting due to previous error diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs index 396bfc1c93199..ba999e9b3a4a3 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs @@ -7,7 +7,7 @@ fn foo(n: i32) { let x = A { a: Box::new(n) }; let _y = match x { A { a: v } if { drop(v); true } => v, - //~^ ERROR cannot move out of borrowed content + //~^ ERROR cannot move out of `v` in pattern guard _ => Box::new(0), }; } diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr index dd8f42f749709..ec133b028e8f8 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr @@ -1,8 +1,10 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `v` in pattern guard --> $DIR/rfc-reject-double-move-in-first-arm.rs:9:30 | LL | A { a: v } if { drop(v); true } => v, - | ^ cannot move out of borrowed content + | ^ move occurs because `v` has type `std::boxed::Box`, which does not implement the `Copy` trait + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error: aborting due to previous error diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr index 23a56bf8fec11..7f6749fc9ccb5 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr @@ -2,7 +2,7 @@ error: functions using `#[should_panic]` must return `()` --> $DIR/termination-trait-in-test-should-panic.rs:11:1 | LL | / fn not_a_num() -> Result<(), ParseIntError> { -LL | | //~^ ERROR functions using `#[should_panic]` must return `()` +LL | | LL | | let _: u32 = "abc".parse()?; LL | | Ok(()) LL | | } diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr index c1be04ca881e8..31b90340d79f7 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr @@ -1,7 +1,7 @@ error[E0277]: `main` has invalid return type `char` --> $DIR/termination-trait-main-wrong-type.rs:1:14 | -LL | fn main() -> char { //~ ERROR +LL | fn main() -> char { | ^^^^ `main` can only return types that implement `std::process::Termination` | = help: consider using `()`, or a `Result` diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr index 2f05f9b0f7a18..72a58a04170fc 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr @@ -1,7 +1,7 @@ error[E0277]: `main` has invalid return type `ReturnType` --> $DIR/termination-trait-not-satisfied.rs:3:14 | -LL | fn main() -> ReturnType { //~ ERROR `main` has invalid return type `ReturnType` +LL | fn main() -> ReturnType { | ^^^^^^^^^^ `main` can only return types that implement `std::process::Termination` | = help: consider using `()`, or a `Result` diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs index c648f5428571c..193a523aed24b 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs @@ -1,8 +1,8 @@ // compile-flags: --test -use std::num::ParseIntError; +use std::num::ParseFloatError; #[test] -fn can_parse_zero_as_f32() -> Result { //~ ERROR +fn can_parse_zero_as_f32() -> Result { //~ ERROR "0".parse() } diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr index a99f852d99bca..f253b67a01914 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr @@ -1,12 +1,12 @@ -error[E0277]: `main` has invalid return type `std::result::Result` +error[E0277]: `main` has invalid return type `std::result::Result` --> $DIR/termination-trait-test-wrong-type.rs:6:1 | -LL | / fn can_parse_zero_as_f32() -> Result { //~ ERROR +LL | / fn can_parse_zero_as_f32() -> Result { LL | | "0".parse() LL | | } | |_^ `main` can only return types that implement `std::process::Termination` | - = help: the trait `std::process::Termination` is not implemented for `std::result::Result` + = help: the trait `std::process::Termination` is not implemented for `std::result::Result` = note: required by `test::assert_test_result` error: aborting due to previous error diff --git a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr index 3a6f66ca4dac5..c74b82dbbd828 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr @@ -4,8 +4,8 @@ error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immu LL | while let Some(Ok(string)) = foo.get() { | --- immutable borrow occurs here LL | foo.mutate(); - | ^^^^^^^^^^^^ mutable borrow occurs here -LL | //~^ ERROR cannot borrow `foo` as mutable + | ^^^ mutable borrow occurs here +LL | LL | println!("foo={:?}", *string); | ------- immutable borrow later used here diff --git a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr index e946d41e23489..04572920ee414 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr @@ -2,11 +2,12 @@ error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immu --> $DIR/borrowck-issue-49631.rs:20:9 | LL | while let Some(Ok(string)) = foo.get() { - | --- - immutable borrow ends here - | | - | immutable borrow occurs here + | --- immutable borrow occurs here LL | foo.mutate(); - | ^^^ mutable borrow occurs here + | ^^^^^^^^^^^^ mutable borrow occurs here +LL | +LL | println!("foo={:?}", *string); + | ------- immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/rfc-2005-default-binding-mode/const.stderr b/src/test/ui/rfc-2005-default-binding-mode/const.stderr index 7ce8a3256327e..210b4f6be63d0 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/const.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/const.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/const.rs:14:9 | -LL | FOO => {}, //~ ERROR mismatched types +LL | FOO => {}, | ^^^ expected &Foo, found struct `Foo` | = note: expected type `&Foo` diff --git a/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr deleted file mode 100644 index 5920be4132a96..0000000000000 --- a/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0594]: cannot assign to `*x` which is behind a `&` reference - --> $DIR/enum.rs:9:5 - | -LL | *x += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written - -error[E0594]: cannot assign to `*x` which is behind a `&` reference - --> $DIR/enum.rs:13:9 - | -LL | *x += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written - -error[E0594]: cannot assign to `*x` which is behind a `&` reference - --> $DIR/enum.rs:19:9 - | -LL | *x += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/enum.rs b/src/test/ui/rfc-2005-default-binding-mode/enum.rs index 7609345404feb..af82d36f87eb0 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/enum.rs +++ b/src/test/ui/rfc-2005-default-binding-mode/enum.rs @@ -6,17 +6,17 @@ use Wrapper::Wrap; pub fn main() { let Wrap(x) = &Wrap(3); - *x += 1; //~ ERROR cannot assign to immutable + *x += 1; //~ ERROR cannot assign to `*x` which is behind a `&` reference if let Some(x) = &Some(3) { - *x += 1; //~ ERROR cannot assign to immutable + *x += 1; //~ ERROR cannot assign to `*x` which is behind a `&` reference } else { panic!(); } while let Some(x) = &Some(3) { - *x += 1; //~ ERROR cannot assign to immutable + *x += 1; //~ ERROR cannot assign to `*x` which is behind a `&` reference break; } } diff --git a/src/test/ui/rfc-2005-default-binding-mode/enum.stderr b/src/test/ui/rfc-2005-default-binding-mode/enum.stderr index d29b0111d8bb2..9d53e6d7887df 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/enum.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/enum.stderr @@ -1,21 +1,20 @@ -error[E0594]: cannot assign to immutable borrowed content `*x` +error[E0594]: cannot assign to `*x` which is behind a `&` reference --> $DIR/enum.rs:9:5 | -LL | *x += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot borrow as mutable +LL | *x += 1; + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written -error[E0594]: cannot assign to immutable borrowed content `*x` +error[E0594]: cannot assign to `*x` which is behind a `&` reference --> $DIR/enum.rs:13:9 | -LL | *x += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot borrow as mutable +LL | *x += 1; + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written -error[E0594]: cannot assign to immutable borrowed content `*x` +error[E0594]: cannot assign to `*x` which is behind a `&` reference --> $DIR/enum.rs:19:9 | -LL | *x += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot borrow as mutable +LL | *x += 1; + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr deleted file mode 100644 index 2206c2f340e14..0000000000000 --- a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0594]: cannot assign to `*n` which is behind a `&` reference - --> $DIR/explicit-mut.rs:7:13 - | -LL | *n += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written - -error[E0594]: cannot assign to `*n` which is behind a `&` reference - --> $DIR/explicit-mut.rs:15:13 - | -LL | *n += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written - -error[E0594]: cannot assign to `*n` which is behind a `&` reference - --> $DIR/explicit-mut.rs:23:13 - | -LL | *n += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.rs b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.rs index 73efddef6cd10..212fd94ded3e7 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.rs +++ b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.rs @@ -4,7 +4,7 @@ fn main() { match &&Some(5i32) { Some(n) => { - *n += 1; //~ ERROR cannot assign to immutable + *n += 1; //~ ERROR cannot assign to `*n` which is behind a `&` reference let _ = n; } None => {}, @@ -12,7 +12,7 @@ fn main() { match &mut &Some(5i32) { Some(n) => { - *n += 1; //~ ERROR cannot assign to immutable + *n += 1; //~ ERROR cannot assign to `*n` which is behind a `&` reference let _ = n; } None => {}, @@ -20,7 +20,7 @@ fn main() { match &&mut Some(5i32) { Some(n) => { - *n += 1; //~ ERROR cannot assign to immutable + *n += 1; //~ ERROR cannot assign to `*n` which is behind a `&` reference let _ = n; } None => {}, diff --git a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr index e03f67760d7e7..5eace3d263d46 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr @@ -1,21 +1,20 @@ -error[E0594]: cannot assign to immutable borrowed content `*n` +error[E0594]: cannot assign to `*n` which is behind a `&` reference --> $DIR/explicit-mut.rs:7:13 | -LL | *n += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot borrow as mutable +LL | *n += 1; + | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written -error[E0594]: cannot assign to immutable borrowed content `*n` +error[E0594]: cannot assign to `*n` which is behind a `&` reference --> $DIR/explicit-mut.rs:15:13 | -LL | *n += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot borrow as mutable +LL | *n += 1; + | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written -error[E0594]: cannot assign to immutable borrowed content `*n` +error[E0594]: cannot assign to `*n` which is behind a `&` reference --> $DIR/explicit-mut.rs:23:13 | -LL | *n += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot borrow as mutable +LL | *n += 1; + | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.rs b/src/test/ui/rfc-2005-default-binding-mode/for.rs index 2fa7852635c30..3bf053eb874ce 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/for.rs +++ b/src/test/ui/rfc-2005-default-binding-mode/for.rs @@ -5,5 +5,6 @@ pub fn main() { // The below desugars to &(ref n, mut m). for (n, mut m) in &tups { //~^ ERROR cannot bind by-move and by-ref in the same pattern + //~| ERROR cannot move out of a shared reference } } diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.stderr b/src/test/ui/rfc-2005-default-binding-mode/for.stderr index 37aaa9cfd70a0..8a1ded1d5b94a 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/for.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/for.stderr @@ -6,6 +6,16 @@ LL | for (n, mut m) in &tups { | | | both by-ref and by-move used -error: aborting due to previous error +error[E0507]: cannot move out of a shared reference + --> $DIR/for.rs:6:23 + | +LL | for (n, mut m) in &tups { + | ----- ^^^^^ + | | + | data moved here + | move occurs because `m` has type `Foo`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0009`. +Some errors have detailed explanations: E0009, E0507. +For more information about an error, try `rustc --explain E0009`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/lit.stderr b/src/test/ui/rfc-2005-default-binding-mode/lit.stderr index b78b4432bbe31..9be1876b7145b 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/lit.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/lit.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/lit.rs:7:13 | -LL | "abc" => true, //~ ERROR mismatched types +LL | "abc" => true, | ^^^^^ expected &str, found str | = note: expected type `&&str` @@ -10,7 +10,7 @@ LL | "abc" => true, //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/lit.rs:16:9 | -LL | b"abc" => true, //~ ERROR mismatched types +LL | b"abc" => true, | ^^^^^^ expected &[u8], found array of 3 elements | = note: expected type `&&[u8]` diff --git a/src/test/ui/rfc-2005-default-binding-mode/no-double-error.stderr b/src/test/ui/rfc-2005-default-binding-mode/no-double-error.stderr index 9d35e167075ae..c672acee040b6 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/no-double-error.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/no-double-error.stderr @@ -1,10 +1,8 @@ error[E0599]: no associated item named `XXX` found for type `u32` in the current scope --> $DIR/no-double-error.rs:8:14 | -LL | u32::XXX => { } //~ ERROR no associated item named - | -----^^^ - | | - | associated item not found in `u32` +LL | u32::XXX => { } + | ^^^ associated item not found in `u32` error: aborting due to previous error diff --git a/src/test/ui/rfc-2005-default-binding-mode/slice.stderr b/src/test/ui/rfc-2005-default-binding-mode/slice.stderr index 1dfad0d31896c..f1e91a05f082f 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/slice.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/slice.stderr @@ -1,8 +1,10 @@ error[E0004]: non-exhaustive patterns: `&[]` not covered --> $DIR/slice.rs:6:11 | -LL | match sl { //~ ERROR non-exhaustive patterns +LL | match sl { | ^^ pattern `&[]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.rs b/src/test/ui/rfc-2008-non-exhaustive/enum.rs index d9b1a9895104c..7423a970e2e3b 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/enum.rs @@ -12,4 +12,48 @@ fn main() { NonExhaustiveEnum::Tuple(_) => "second", NonExhaustiveEnum::Struct { .. } => "third" }; + + // Everything below this is expected to compile successfully. + + let enum_unit = NonExhaustiveEnum::Unit; + + match enum_unit { + NonExhaustiveEnum::Unit => 1, + NonExhaustiveEnum::Tuple(_) => 2, + // This particular arm tests that a enum marked as non-exhaustive + // will not error if its variants are matched exhaustively. + NonExhaustiveEnum::Struct { field } => field, + _ => 0 // no error with wildcard + }; + + match enum_unit { + _ => "no error with only wildcard" + }; + + // #53549: Check that variant constructors can still be called normally. + match NonExhaustiveEnum::Unit { + NonExhaustiveEnum::Unit => {}, + _ => {} + }; + + match NonExhaustiveEnum::Tuple(2) { + NonExhaustiveEnum::Tuple(2) => {}, + _ => {} + }; + + match (NonExhaustiveEnum::Unit {}) { + NonExhaustiveEnum::Unit {} => {}, + _ => {} + }; + + match (NonExhaustiveEnum::Tuple { 0: 2 }) { + NonExhaustiveEnum::Tuple { 0: 2 } => {}, + _ => {} + }; + + match (NonExhaustiveEnum::Struct { field: 2 }) { + NonExhaustiveEnum::Struct { field: 2 } => {}, + _ => {} + }; + } diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr index acce9779067a6..b5c1a4ebba4ac 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr @@ -3,6 +3,8 @@ error[E0004]: non-exhaustive patterns: `_` not covered | LL | match enum_unit { | ^^^^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs new file mode 100644 index 0000000000000..a3626bf60b260 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs @@ -0,0 +1,20 @@ +// run-pass + +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum NonExhaustiveEnum { + Unit, + Tuple(u32), + Struct { field: u32 } +} + +fn main() { + let enum_unit = NonExhaustiveEnum::Unit; + + match enum_unit { + NonExhaustiveEnum::Unit => "first", + NonExhaustiveEnum::Tuple(_) => "second", + NonExhaustiveEnum::Struct { .. } => "third", + }; +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.rs b/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.rs index 3375210fc59eb..b7938e1afa3bc 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.rs @@ -1,7 +1,7 @@ #![feature(non_exhaustive)] #[non_exhaustive(anything)] -//~^ ERROR attribute must be of the form +//~^ ERROR malformed `non_exhaustive` attribute struct Foo; #[non_exhaustive] diff --git a/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.stderr b/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.stderr index 1d055fe8d4cb8..21dc340d21204 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.stderr @@ -1,15 +1,15 @@ -error: attribute must be of the form `#[non_exhaustive]` +error: malformed `non_exhaustive` attribute input --> $DIR/invalid-attribute.rs:3:1 | LL | #[non_exhaustive(anything)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[non_exhaustive]` error[E0701]: attribute can only be applied to a struct or enum --> $DIR/invalid-attribute.rs:7:1 | LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ -LL | //~^ ERROR attribute can only be applied to a struct or enum [E0701] +LL | LL | trait Bar { } | ------------- not a struct or enum @@ -18,7 +18,7 @@ error[E0701]: attribute can only be applied to a struct or enum | LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ -LL | //~^ ERROR attribute can only be applied to a struct or enum [E0701] +LL | LL | / union Baz { LL | | f1: u16, LL | | f2: u16 diff --git a/src/test/ui/rfc-2008-non-exhaustive/struct.rs b/src/test/ui/rfc-2008-non-exhaustive/struct.rs new file mode 100644 index 0000000000000..94ac588d24083 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/struct.rs @@ -0,0 +1,49 @@ +// aux-build:structs.rs +extern crate structs; + +use structs::{NormalStruct, UnitStruct, TupleStruct, FunctionalRecord}; + +fn main() { + let fr = FunctionalRecord { + //~^ ERROR cannot create non-exhaustive struct + first_field: 1920, + second_field: 1080, + ..FunctionalRecord::default() + }; + + let ns = NormalStruct { first_field: 640, second_field: 480 }; + //~^ ERROR cannot create non-exhaustive struct + + let NormalStruct { first_field, second_field } = ns; + //~^ ERROR `..` required with struct marked as non-exhaustive + + let ts = TupleStruct(640, 480); + //~^ ERROR expected function, found struct `TupleStruct` [E0423] + + let ts_explicit = structs::TupleStruct(640, 480); + //~^ ERROR tuple struct `TupleStruct` is private [E0603] + + let TupleStruct { 0: first_field, 1: second_field } = ts; + //~^ ERROR `..` required with struct marked as non-exhaustive + + let us = UnitStruct; + //~^ ERROR expected value, found struct `UnitStruct` [E0423] + + let us_explicit = structs::UnitStruct; + //~^ ERROR unit struct `UnitStruct` is private [E0603] + + let UnitStruct { } = us; + //~^ ERROR `..` required with struct marked as non-exhaustive +} + +// Everything below this is expected to compile successfully. + +// We only test matching here as we cannot create non-exhaustive +// structs from another crate. ie. they'll never pass in run-pass tests. +fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) { + let NormalStruct { first_field, second_field, .. } = ns; + + let TupleStruct { 0: first, 1: second, .. } = ts; + + let UnitStruct { .. } = us; +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/struct.stderr b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr new file mode 100644 index 0000000000000..96040f11b525f --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr @@ -0,0 +1,64 @@ +error[E0423]: expected function, found struct `TupleStruct` + --> $DIR/struct.rs:20:14 + | +LL | let ts = TupleStruct(640, 480); + | ^^^^^^^^^^^ constructor is not visible here due to private fields + +error[E0423]: expected value, found struct `UnitStruct` + --> $DIR/struct.rs:29:14 + | +LL | let us = UnitStruct; + | ^^^^^^^^^^ constructor is not visible here due to private fields + +error[E0603]: tuple struct `TupleStruct` is private + --> $DIR/struct.rs:23:32 + | +LL | let ts_explicit = structs::TupleStruct(640, 480); + | ^^^^^^^^^^^ + +error[E0603]: unit struct `UnitStruct` is private + --> $DIR/struct.rs:32:32 + | +LL | let us_explicit = structs::UnitStruct; + | ^^^^^^^^^^ + +error[E0639]: cannot create non-exhaustive struct using struct expression + --> $DIR/struct.rs:7:14 + | +LL | let fr = FunctionalRecord { + | ______________^ +LL | | +LL | | first_field: 1920, +LL | | second_field: 1080, +LL | | ..FunctionalRecord::default() +LL | | }; + | |_____^ + +error[E0639]: cannot create non-exhaustive struct using struct expression + --> $DIR/struct.rs:14:14 + | +LL | let ns = NormalStruct { first_field: 640, second_field: 480 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0638]: `..` required with struct marked as non-exhaustive + --> $DIR/struct.rs:17:9 + | +LL | let NormalStruct { first_field, second_field } = ns; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0638]: `..` required with struct marked as non-exhaustive + --> $DIR/struct.rs:26:9 + | +LL | let TupleStruct { 0: first_field, 1: second_field } = ts; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0638]: `..` required with struct marked as non-exhaustive + --> $DIR/struct.rs:35:9 + | +LL | let UnitStruct { } = us; + | ^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0423, E0603, E0638, E0639. +For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/structs.rs b/src/test/ui/rfc-2008-non-exhaustive/structs.rs deleted file mode 100644 index 303d71d12df33..0000000000000 --- a/src/test/ui/rfc-2008-non-exhaustive/structs.rs +++ /dev/null @@ -1,37 +0,0 @@ -// aux-build:structs.rs -extern crate structs; - -use structs::{NormalStruct, UnitStruct, TupleStruct, FunctionalRecord}; - -fn main() { - let fr = FunctionalRecord { - //~^ ERROR cannot create non-exhaustive struct - first_field: 1920, - second_field: 1080, - ..FunctionalRecord::default() - }; - - let ns = NormalStruct { first_field: 640, second_field: 480 }; - //~^ ERROR cannot create non-exhaustive struct - - let NormalStruct { first_field, second_field } = ns; - //~^ ERROR `..` required with struct marked as non-exhaustive - - let ts = TupleStruct(640, 480); - //~^ ERROR expected function, found struct `TupleStruct` [E0423] - - let ts_explicit = structs::TupleStruct(640, 480); - //~^ ERROR tuple struct `TupleStruct` is private [E0603] - - let TupleStruct { 0: first_field, 1: second_field } = ts; - //~^ ERROR `..` required with struct marked as non-exhaustive - - let us = UnitStruct; - //~^ ERROR expected value, found struct `UnitStruct` [E0423] - - let us_explicit = structs::UnitStruct; - //~^ ERROR unit struct `UnitStruct` is private [E0603] - - let UnitStruct { } = us; - //~^ ERROR `..` required with struct marked as non-exhaustive -} diff --git a/src/test/ui/rfc-2008-non-exhaustive/structs.stderr b/src/test/ui/rfc-2008-non-exhaustive/structs.stderr deleted file mode 100644 index 4532b5c34cc0f..0000000000000 --- a/src/test/ui/rfc-2008-non-exhaustive/structs.stderr +++ /dev/null @@ -1,64 +0,0 @@ -error[E0423]: expected function, found struct `TupleStruct` - --> $DIR/structs.rs:20:14 - | -LL | let ts = TupleStruct(640, 480); - | ^^^^^^^^^^^ constructor is not visible here due to private fields - -error[E0423]: expected value, found struct `UnitStruct` - --> $DIR/structs.rs:29:14 - | -LL | let us = UnitStruct; - | ^^^^^^^^^^ constructor is not visible here due to private fields - -error[E0603]: tuple struct `TupleStruct` is private - --> $DIR/structs.rs:23:32 - | -LL | let ts_explicit = structs::TupleStruct(640, 480); - | ^^^^^^^^^^^ - -error[E0603]: unit struct `UnitStruct` is private - --> $DIR/structs.rs:32:32 - | -LL | let us_explicit = structs::UnitStruct; - | ^^^^^^^^^^ - -error[E0639]: cannot create non-exhaustive struct using struct expression - --> $DIR/structs.rs:7:14 - | -LL | let fr = FunctionalRecord { - | ______________^ -LL | | //~^ ERROR cannot create non-exhaustive struct -LL | | first_field: 1920, -LL | | second_field: 1080, -LL | | ..FunctionalRecord::default() -LL | | }; - | |_____^ - -error[E0639]: cannot create non-exhaustive struct using struct expression - --> $DIR/structs.rs:14:14 - | -LL | let ns = NormalStruct { first_field: 640, second_field: 480 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0638]: `..` required with struct marked as non-exhaustive - --> $DIR/structs.rs:17:9 - | -LL | let NormalStruct { first_field, second_field } = ns; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0638]: `..` required with struct marked as non-exhaustive - --> $DIR/structs.rs:26:9 - | -LL | let TupleStruct { 0: first_field, 1: second_field } = ts; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0638]: `..` required with struct marked as non-exhaustive - --> $DIR/structs.rs:35:9 - | -LL | let UnitStruct { } = us; - | ^^^^^^^^^^^^^^ - -error: aborting due to 9 previous errors - -Some errors occurred: E0423, E0603, E0638, E0639. -For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs similarity index 99% rename from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs rename to src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs index 5e71cce1297cb..2b1d7d9ac5030 100644 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs @@ -1,4 +1,5 @@ // run-pass + #![allow(unused_variables)] #![feature(non_exhaustive)] diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs new file mode 100644 index 0000000000000..8cb9a8cf1f613 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs @@ -0,0 +1,33 @@ +#![crate_type = "rlib"] +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub enum PartiallyInhabitedVariants { + Tuple(u8), + #[non_exhaustive] Struct { x: ! } +} + +pub struct IndirectUninhabitedEnum(UninhabitedEnum); + +pub struct IndirectUninhabitedStruct(UninhabitedStruct); + +pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + +pub struct IndirectUninhabitedVariants(UninhabitedVariants); diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs new file mode 100644 index 0000000000000..80b9dc4c1c338 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs @@ -0,0 +1,38 @@ +// aux-build:uninhabited.rs +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +// This test checks that uninhabited non-exhaustive types cannot coerce to any type, as the never +// type can. + +struct A; + +fn can_coerce_never_type_to_anything(x: !) -> A { + x +} + +fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr new file mode 100644 index 0000000000000..d05ee1d39ec35 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr @@ -0,0 +1,47 @@ +error[E0308]: mismatched types + --> $DIR/coercions.rs:23:5 + | +LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found enum `uninhabited::UninhabitedEnum` + | + = note: expected type `A` + found type `uninhabited::UninhabitedEnum` + +error[E0308]: mismatched types + --> $DIR/coercions.rs:27:5 + | +LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found struct `uninhabited::UninhabitedTupleStruct` + | + = note: expected type `A` + found type `uninhabited::UninhabitedTupleStruct` + +error[E0308]: mismatched types + --> $DIR/coercions.rs:31:5 + | +LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found struct `uninhabited::UninhabitedStruct` + | + = note: expected type `A` + found type `uninhabited::UninhabitedStruct` + +error[E0308]: mismatched types + --> $DIR/coercions.rs:35:5 + | +LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found enum `uninhabited::UninhabitedVariants` + | + = note: expected type `A` + found type `uninhabited::UninhabitedVariants` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs new file mode 100644 index 0000000000000..803a542f8aa4b --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs @@ -0,0 +1,46 @@ +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +struct A; + +// This test checks that uninhabited non-exhaustive types defined in the same crate cannot coerce +// to any type, as the never type can. + +fn can_coerce_never_type_to_anything(x: !) -> A { + x +} + +fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr new file mode 100644 index 0000000000000..8f6b709bb1f34 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr @@ -0,0 +1,47 @@ +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:31:5 + | +LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found enum `UninhabitedEnum` + | + = note: expected type `A` + found type `UninhabitedEnum` + +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:35:5 + | +LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found struct `UninhabitedTupleStruct` + | + = note: expected type `A` + found type `UninhabitedTupleStruct` + +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:39:5 + | +LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found struct `UninhabitedStruct` + | + = note: expected type `A` + found type `UninhabitedStruct` + +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:43:5 + | +LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found enum `UninhabitedVariants` + | + = note: expected type `A` + found type `UninhabitedVariants` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs new file mode 100644 index 0000000000000..98a7fdbc5049a --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs @@ -0,0 +1,36 @@ +// aux-build:uninhabited.rs +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + IndirectUninhabitedEnum, + IndirectUninhabitedStruct, + IndirectUninhabitedTupleStruct, + IndirectUninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type through a level of +// indirection from an extern crate will not compile. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr new file mode 100644 index 0000000000000..af82022e1da99 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr @@ -0,0 +1,35 @@ +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `uninhabited::IndirectUninhabitedEnum` is not handled + --> $DIR/indirect_match.rs:19:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `uninhabited::IndirectUninhabitedStruct` is not handled + --> $DIR/indirect_match.rs:23:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `uninhabited::IndirectUninhabitedTupleStruct` is not handled + --> $DIR/indirect_match.rs:27:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `uninhabited::IndirectUninhabitedVariants` is not handled + --> $DIR/indirect_match.rs:33:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs new file mode 100644 index 0000000000000..3c8d495e12cb6 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs @@ -0,0 +1,52 @@ +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub struct IndirectUninhabitedEnum(UninhabitedEnum); + +pub struct IndirectUninhabitedStruct(UninhabitedStruct); + +pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + +pub struct IndirectUninhabitedVariants(UninhabitedVariants); + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type through a level of +// indirection from the defining crate will not compile without `#![feature(exhaustive_patterns)]`. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr new file mode 100644 index 0000000000000..27b120792d6d1 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr @@ -0,0 +1,59 @@ +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `IndirectUninhabitedEnum` is not handled + --> $DIR/indirect_match_same_crate.rs:35:11 + | +LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum); + | ---------------------------------------------------- + | | | + | | variant not covered + | `IndirectUninhabitedEnum` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `IndirectUninhabitedStruct` is not handled + --> $DIR/indirect_match_same_crate.rs:39:11 + | +LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct); + | -------------------------------------------------------- + | | | + | | variant not covered + | `IndirectUninhabitedStruct` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `IndirectUninhabitedTupleStruct` is not handled + --> $DIR/indirect_match_same_crate.rs:43:11 + | +LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + | ------------------------------------------------------------------ + | | | + | | variant not covered + | `IndirectUninhabitedTupleStruct` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `IndirectUninhabitedVariants` is not handled + --> $DIR/indirect_match_same_crate.rs:49:11 + | +LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants); + | ------------------------------------------------------------ + | | | + | | variant not covered + | `IndirectUninhabitedVariants` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs new file mode 100644 index 0000000000000..be86519ecb159 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs @@ -0,0 +1,40 @@ +// aux-build:uninhabited.rs +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + IndirectUninhabitedEnum, + IndirectUninhabitedStruct, + IndirectUninhabitedTupleStruct, + IndirectUninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type through a level of +// indirection from an extern crate will not compile. In particular, this enables the +// `exhaustive_patterns` feature as this can change the branch used in the compiler to determine +// this. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr new file mode 100644 index 0000000000000..17a8d01007205 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr @@ -0,0 +1,35 @@ +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:23:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedStruct` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedVariants` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs new file mode 100644 index 0000000000000..d1e7c3b4d518a --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs @@ -0,0 +1,58 @@ +// check-pass + +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub struct IndirectUninhabitedEnum(UninhabitedEnum); + +pub struct IndirectUninhabitedStruct(UninhabitedStruct); + +pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + +pub struct IndirectUninhabitedVariants(UninhabitedVariants); + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate +// will compile. In particular, this enables the `exhaustive_patterns` feature as this can +// change the branch used in the compiler to determine this. +// Codegen is skipped because tests with long names can cause issues on Windows CI, see #60648. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs new file mode 100644 index 0000000000000..e54098d4d48b9 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs @@ -0,0 +1,34 @@ +// aux-build:uninhabited.rs +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate +// will not compile. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr new file mode 100644 index 0000000000000..de39688f45a4d --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr @@ -0,0 +1,35 @@ +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty + --> $DIR/match.rs:19:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `uninhabited::UninhabitedStruct` is not handled + --> $DIR/match.rs:23:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `uninhabited::UninhabitedTupleStruct` is not handled + --> $DIR/match.rs:27:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: multiple patterns of type `uninhabited::UninhabitedVariants` are not handled + --> $DIR/match.rs:31:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs new file mode 100644 index 0000000000000..6405dd3bd65b7 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs @@ -0,0 +1,42 @@ +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate +// will compile. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr new file mode 100644 index 0000000000000..410285a39a945 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr @@ -0,0 +1,49 @@ +error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `UninhabitedStruct` is not handled + --> $DIR/match_same_crate.rs:31:11 + | +LL | pub struct UninhabitedStruct { + | - ----------------- variant not covered + | _| + | | +LL | | _priv: !, +LL | | } + | |_- `UninhabitedStruct` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `UninhabitedTupleStruct` is not handled + --> $DIR/match_same_crate.rs:35:11 + | +LL | pub struct UninhabitedTupleStruct(!); + | ------------------------------------- + | | | + | | variant not covered + | `UninhabitedTupleStruct` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: multiple patterns of type `UninhabitedVariants` are not handled + --> $DIR/match_same_crate.rs:39:11 + | +LL | / pub enum UninhabitedVariants { +LL | | #[non_exhaustive] Tuple(!), + | | ----- variant not covered +LL | | #[non_exhaustive] Struct { x: ! } + | | ------ variant not covered +LL | | } + | |_- `UninhabitedVariants` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs new file mode 100644 index 0000000000000..900dfff652ea6 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs @@ -0,0 +1,37 @@ +// aux-build:uninhabited.rs +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate +// will not compile. In particular, this enables the `exhaustive_patterns` feature as this can +// change the branch used in the compiler to determine this. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr new file mode 100644 index 0000000000000..48a888bc50be0 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr @@ -0,0 +1,35 @@ +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:22:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedStruct` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:26:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedTupleStruct` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:30:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedVariants` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:34:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs new file mode 100644 index 0000000000000..8973d21bff6fa --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs @@ -0,0 +1,48 @@ +// check-pass + +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate +// will compile. In particular, this enables the `exhaustive_patterns` feature as this can +// change the branch used in the compiler to determine this. +// Codegen is skipped because tests with long names can cause issues on Windows CI, see #60648. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs new file mode 100644 index 0000000000000..97061310d19e2 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs @@ -0,0 +1,59 @@ +// aux-build:uninhabited.rs +// compile-pass +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] + +extern crate uninhabited; + +use uninhabited::{ + PartiallyInhabitedVariants, + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +fn uninhabited_enum() -> Option { + None +} + +fn uninhabited_variant() -> Option { + None +} + +fn partially_inhabited_variant() -> PartiallyInhabitedVariants { + PartiallyInhabitedVariants::Tuple(3) +} + +fn uninhabited_struct() -> Option { + None +} + +fn uninhabited_tuple_struct() -> Option { + None +} + +// This test checks that non-exhaustive types that would normally be considered uninhabited within +// the defining crate are not considered uninhabited from extern crates. + +fn main() { + match uninhabited_enum() { + Some(_x) => (), // This line would normally error. + None => (), + } + + match uninhabited_variant() { + Some(_x) => (), // This line would normally error. + None => (), + } + + // This line would normally error. + while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() { + } + + while let Some(_x) = uninhabited_struct() { // This line would normally error. + } + + while let Some(_x) = uninhabited_tuple_struct() { // This line would normally error. + } +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs new file mode 100644 index 0000000000000..302a35cab5f90 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs @@ -0,0 +1,71 @@ +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub enum PartiallyInhabitedVariants { + Tuple(u8), + #[non_exhaustive] Struct { x: ! } +} + +fn uninhabited_enum() -> Option { + None +} + +fn uninhabited_variant() -> Option { + None +} + +fn partially_inhabited_variant() -> PartiallyInhabitedVariants { + PartiallyInhabitedVariants::Tuple(3) +} + +fn uninhabited_struct() -> Option { + None +} + +fn uninhabited_tuple_struct() -> Option { + None +} + +// This test checks that non-exhaustive types that would normally be considered uninhabited within +// the defining crate are still considered uninhabited. + +fn main() { + match uninhabited_enum() { + Some(_x) => (), //~ ERROR unreachable pattern + None => (), + } + + match uninhabited_variant() { + Some(_x) => (), //~ ERROR unreachable pattern + None => (), + } + + while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() { + //~^ ERROR unreachable pattern + } + + while let Some(_x) = uninhabited_struct() { //~ ERROR unreachable pattern + } + + while let Some(_x) = uninhabited_tuple_struct() { //~ ERROR unreachable pattern + } +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr new file mode 100644 index 0000000000000..72f37d9a60ba8 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr @@ -0,0 +1,38 @@ +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:53:9 + | +LL | Some(_x) => (), + | ^^^^^^^^ + | +note: lint level defined here + --> $DIR/patterns_same_crate.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:58:9 + | +LL | Some(_x) => (), + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:62:15 + | +LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:66:15 + | +LL | while let Some(_x) = uninhabited_struct() { + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:69:15 + | +LL | while let Some(_x) = uninhabited_tuple_struct() { + | ^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/rfc-2008-non-exhaustive/variant.rs b/src/test/ui/rfc-2008-non-exhaustive/variant.rs new file mode 100644 index 0000000000000..bc346aea51cfc --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/variant.rs @@ -0,0 +1,33 @@ +// aux-build:variants.rs + +extern crate variants; + +use variants::NonExhaustiveVariants; + +fn main() { + let variant_struct = NonExhaustiveVariants::Struct { field: 640 }; + //~^ ERROR cannot create non-exhaustive variant + + let variant_tuple = NonExhaustiveVariants::Tuple(640); + //~^ ERROR tuple variant `Tuple` is private [E0603] + + let variant_unit = NonExhaustiveVariants::Unit; + //~^ ERROR unit variant `Unit` is private [E0603] + + match variant_struct { + NonExhaustiveVariants::Unit => "", + //~^ ERROR unit variant `Unit` is private [E0603] + NonExhaustiveVariants::Tuple(fe_tpl) => "", + //~^ ERROR tuple variant `Tuple` is private [E0603] + NonExhaustiveVariants::Struct { field } => "" + //~^ ERROR `..` required with variant marked as non-exhaustive + }; + + if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct { + //~^ ERROR tuple variant `Tuple` is private [E0603] + } + + if let NonExhaustiveVariants::Struct { field } = variant_struct { + //~^ ERROR `..` required with variant marked as non-exhaustive + } +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/variant.stderr b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr new file mode 100644 index 0000000000000..d9d6ea21b8bd4 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr @@ -0,0 +1,52 @@ +error[E0603]: tuple variant `Tuple` is private + --> $DIR/variant.rs:11:48 + | +LL | let variant_tuple = NonExhaustiveVariants::Tuple(640); + | ^^^^^ + +error[E0603]: unit variant `Unit` is private + --> $DIR/variant.rs:14:47 + | +LL | let variant_unit = NonExhaustiveVariants::Unit; + | ^^^^ + +error[E0603]: unit variant `Unit` is private + --> $DIR/variant.rs:18:32 + | +LL | NonExhaustiveVariants::Unit => "", + | ^^^^ + +error[E0603]: tuple variant `Tuple` is private + --> $DIR/variant.rs:20:32 + | +LL | NonExhaustiveVariants::Tuple(fe_tpl) => "", + | ^^^^^ + +error[E0603]: tuple variant `Tuple` is private + --> $DIR/variant.rs:26:35 + | +LL | if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct { + | ^^^^^ + +error[E0639]: cannot create non-exhaustive variant using struct expression + --> $DIR/variant.rs:8:26 + | +LL | let variant_struct = NonExhaustiveVariants::Struct { field: 640 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0638]: `..` required with variant marked as non-exhaustive + --> $DIR/variant.rs:22:9 + | +LL | NonExhaustiveVariants::Struct { field } => "" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0638]: `..` required with variant marked as non-exhaustive + --> $DIR/variant.rs:30:12 + | +LL | if let NonExhaustiveVariants::Struct { field } = variant_struct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0603, E0638, E0639. +For more information about an error, try `rustc --explain E0603`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants.rs b/src/test/ui/rfc-2008-non-exhaustive/variants.rs deleted file mode 100644 index 373bbc3547f38..0000000000000 --- a/src/test/ui/rfc-2008-non-exhaustive/variants.rs +++ /dev/null @@ -1,26 +0,0 @@ -// aux-build:variants.rs -extern crate variants; - -use variants::NonExhaustiveVariants; - -/* - * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for - * variants. See issue #44109 and PR 45394. - */ -// ignore-test - -fn main() { - let variant_struct = NonExhaustiveVariants::Struct { field: 640 }; - //~^ ERROR cannot create non-exhaustive variant - - let variant_tuple = NonExhaustiveVariants::Tuple { 0: 640 }; - //~^ ERROR cannot create non-exhaustive variant - - match variant_struct { - NonExhaustiveVariants::Unit => "", - NonExhaustiveVariants::Tuple(fe_tpl) => "", - //~^ ERROR `..` required with variant marked as non-exhaustive - NonExhaustiveVariants::Struct { field } => "" - //~^ ERROR `..` required with variant marked as non-exhaustive - }; -} diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants_create.rs b/src/test/ui/rfc-2008-non-exhaustive/variants_create.rs deleted file mode 100644 index 9ed244144dff9..0000000000000 --- a/src/test/ui/rfc-2008-non-exhaustive/variants_create.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![feature(non_exhaustive)] - -/* - * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for - * variants. See issue #44109 and PR 45394. - */ - -pub enum NonExhaustiveVariants { - #[non_exhaustive] Unit, - //~^ ERROR #[non_exhaustive] is not yet supported on variants - #[non_exhaustive] Tuple(u32), - //~^ ERROR #[non_exhaustive] is not yet supported on variants - #[non_exhaustive] Struct { field: u32 } - //~^ ERROR #[non_exhaustive] is not yet supported on variants -} - -fn main() { } diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr b/src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr deleted file mode 100644 index 5b099d58ec467..0000000000000 --- a/src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: #[non_exhaustive] is not yet supported on variants - --> $DIR/variants_create.rs:9:23 - | -LL | #[non_exhaustive] Unit, - | ^^^^ - -error: #[non_exhaustive] is not yet supported on variants - --> $DIR/variants_create.rs:11:23 - | -LL | #[non_exhaustive] Tuple(u32), - | ^^^^^^^^^^ - -error: #[non_exhaustive] is not yet supported on variants - --> $DIR/variants_create.rs:13:23 - | -LL | #[non_exhaustive] Struct { field: u32 } - | ^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants_fictive_visibility.rs b/src/test/ui/rfc-2008-non-exhaustive/variants_fictive_visibility.rs new file mode 100644 index 0000000000000..62f6e4463f936 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/variants_fictive_visibility.rs @@ -0,0 +1,12 @@ +// compile-pass +// aux-build:variants.rs + +extern crate variants; + +const S: u8 = 0; + +// OK, `Struct` in value namespace is crate-private, so it's filtered away +// and there's no conflict with the previously defined `const S`. +use variants::NonExhaustiveVariants::Struct as S; + +fn main() {} diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs similarity index 76% rename from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs rename to src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs index 603e69b9ff9b0..470a5ea9833ad 100644 --- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs @@ -1,11 +1,6 @@ // run-pass -#![feature(non_exhaustive)] -/* - * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for - * variants. See issue #44109 and PR 45394. - */ -// ignore-test +#![feature(non_exhaustive)] pub enum NonExhaustiveVariants { #[non_exhaustive] Unit, diff --git a/src/test/ui/rfc-2093-infer-outlives/cross-crate.rs b/src/test/ui/rfc-2093-infer-outlives/cross-crate.rs index ce50452dd523f..a9bfeabf16e5e 100644 --- a/src/test/ui/rfc-2093-infer-outlives/cross-crate.rs +++ b/src/test/ui/rfc-2093-infer-outlives/cross-crate.rs @@ -6,4 +6,3 @@ struct Foo<'a, T> { //~ ERROR rustc_outlives } fn main() {} - diff --git a/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr b/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr index 850e7caec5483..3368e35d304f0 100644 --- a/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/cross-crate.rs:4:1 | -LL | / struct Foo<'a, T> { //~ ERROR rustc_outlives +LL | / struct Foo<'a, T> { LL | | bar: std::slice::IterMut<'a, T> LL | | } | |_^ diff --git a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.rs b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.rs index 812e8c8bb3e89..5297d0d9842e2 100644 --- a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.rs +++ b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - /* * We don't infer `T: 'static` outlives relationships by default. * Instead an additional feature gate `infer_static_outlives_requirements` @@ -14,4 +12,3 @@ struct Bar { } fn main() {} - diff --git a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr index e4f4b58fb33ae..b049d8a4ab3c3 100644 --- a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr @@ -1,15 +1,15 @@ error[E0310]: the parameter type `U` may not live long enough - --> $DIR/dont-infer-static.rs:10:5 + --> $DIR/dont-infer-static.rs:8:5 | LL | struct Foo { | - help: consider adding an explicit lifetime bound `U: 'static`... -LL | bar: Bar //~ ERROR the parameter type `U` may not live long enough [E0310] +LL | bar: Bar | ^^^^^^^^^^^ | note: ...so that the type `U` will meet its required lifetime bounds - --> $DIR/dont-infer-static.rs:10:5 + --> $DIR/dont-infer-static.rs:8:5 | -LL | bar: Bar //~ ERROR the parameter type `U` may not live long enough [E0310] +LL | bar: Bar | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/rfc-2093-infer-outlives/enum.rs b/src/test/ui/rfc-2093-infer-outlives/enum.rs index 622794ea9ac3b..71d2d32226556 100644 --- a/src/test/ui/rfc-2093-infer-outlives/enum.rs +++ b/src/test/ui/rfc-2093-infer-outlives/enum.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - #![feature(rustc_attrs)] // Needs an explicit where clause stating outlives condition. (RFC 2093) diff --git a/src/test/ui/rfc-2093-infer-outlives/enum.stderr b/src/test/ui/rfc-2093-infer-outlives/enum.stderr index c8e730090fc31..dd56c1f79c712 100644 --- a/src/test/ui/rfc-2093-infer-outlives/enum.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/enum.stderr @@ -1,7 +1,7 @@ error: rustc_outlives - --> $DIR/enum.rs:9:1 + --> $DIR/enum.rs:7:1 | -LL | / enum Foo<'a, T> { //~ ERROR rustc_outlives +LL | / enum Foo<'a, T> { LL | | One(Bar<'a, T>) LL | | } | |_^ @@ -9,9 +9,9 @@ LL | | } = note: T : 'a error: rustc_outlives - --> $DIR/enum.rs:15:1 + --> $DIR/enum.rs:13:1 | -LL | / struct Bar<'b, U> { //~ ERROR rustc_outlives +LL | / struct Bar<'b, U> { LL | | field2: &'b U LL | | } | |_^ @@ -19,9 +19,9 @@ LL | | } = note: U : 'b error: rustc_outlives - --> $DIR/enum.rs:21:1 + --> $DIR/enum.rs:19:1 | -LL | / enum Ying<'c, K> { //~ ERROR rustc_outlives +LL | / enum Ying<'c, K> { LL | | One(&'c Yang) LL | | } | |_^ diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr index a5bee93a1509d..c87ef6c391b11 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/explicit-dyn.rs:8:1 | -LL | / struct Foo<'a, A> //~ ERROR rustc_outlives +LL | / struct Foo<'a, A> LL | | { LL | | foo: Box> LL | | } diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-enum.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.rs index b7a66a326b84e..c330c27fea0a9 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-enum.rs +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.rs @@ -11,4 +11,3 @@ struct Bar<'x, T> where T: 'x { } fn main() {} - diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr index 2149e0533c616..611df047cffc3 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/explicit-enum.rs:4:1 | -LL | / enum Foo<'a, U> { //~ ERROR rustc_outlives +LL | / enum Foo<'a, U> { LL | | One(Bar<'a, U>) LL | | } | |_^ diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr index 46793b1690a87..8e9b158ab7c9d 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/explicit-projection.rs:8:1 | -LL | / struct Foo<'a, A, B> where A: Trait<'a, B> //~ ERROR rustc_outlives +LL | / struct Foo<'a, A, B> where A: Trait<'a, B> LL | | { LL | | foo: >::Type LL | | } diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-struct.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.rs index 3c69f9f612eaa..3d5e610b934b3 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-struct.rs +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.rs @@ -11,4 +11,3 @@ struct Bar<'a, T> where T: 'a { } fn main() {} - diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr index b694b7a95436e..cbff2b777fe71 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/explicit-struct.rs:4:1 | -LL | / struct Foo<'b, U> { //~ ERROR rustc_outlives +LL | / struct Foo<'b, U> { LL | | bar: Bar<'b, U> LL | | } | |_^ diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs index 87a789b06a0ad..a16fb7670a603 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs @@ -13,4 +13,3 @@ union Bar<'a, T> where T: 'a { } fn main() {} - diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr index d70fad9d83047..adf62651cacb1 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/explicit-union.rs:6:1 | -LL | / union Foo<'b, U> { //~ ERROR rustc_outlives +LL | / union Foo<'b, U> { LL | | bar: Bar<'b, U> LL | | } | |_^ diff --git a/src/test/ui/rfc-2093-infer-outlives/infer-static.rs b/src/test/ui/rfc-2093-infer-outlives/infer-static.rs index 916d4849edbba..bd778e3b13623 100644 --- a/src/test/ui/rfc-2093-infer-outlives/infer-static.rs +++ b/src/test/ui/rfc-2093-infer-outlives/infer-static.rs @@ -10,4 +10,3 @@ struct Bar { } fn main() {} - diff --git a/src/test/ui/rfc-2093-infer-outlives/infer-static.stderr b/src/test/ui/rfc-2093-infer-outlives/infer-static.stderr index b3a827f38c557..106db765f7ead 100644 --- a/src/test/ui/rfc-2093-infer-outlives/infer-static.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/infer-static.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/infer-static.rs:5:1 | -LL | / struct Foo { //~ ERROR rustc_outlives +LL | / struct Foo { LL | | bar: Bar LL | | } | |_^ diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr index 76d18bbee9d6b..6b143ba7eb963 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/nested-enum.rs:4:1 | -LL | / enum Foo<'a, T> { //~ ERROR rustc_outlives +LL | / enum Foo<'a, T> { LL | | LL | | One(Bar<'a, T>) LL | | } diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr index 2900a29ed7c07..4d8f7b7c8c465 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/nested-regions.rs:4:1 | -LL | / struct Foo<'a, 'b, T> { //~ ERROR rustc_outlives +LL | / struct Foo<'a, 'b, T> { LL | | x: &'a &'b T LL | | } | |_^ diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr index e8b822df95032..17d7c014e1029 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/nested-structs.rs:4:1 | -LL | / struct Foo<'a, T> { //~ ERROR rustc_outlives +LL | / struct Foo<'a, T> { LL | | field1: Bar<'a, T> LL | | } | |_^ diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr index 56a2f873c768b..fc4b1a223294d 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/nested-union.rs:6:1 | -LL | / union Foo<'a, T> { //~ ERROR rustc_outlives +LL | / union Foo<'a, T> { LL | | field1: Bar<'a, T> LL | | } | |_^ diff --git a/src/test/ui/rfc-2093-infer-outlives/projection.rs b/src/test/ui/rfc-2093-infer-outlives/projection.rs index 0b9637e9528ed..411c86da1dec5 100644 --- a/src/test/ui/rfc-2093-infer-outlives/projection.rs +++ b/src/test/ui/rfc-2093-infer-outlives/projection.rs @@ -6,4 +6,3 @@ struct Foo<'a, T: Iterator> { //~ ERROR rustc_outlives } fn main() {} - diff --git a/src/test/ui/rfc-2093-infer-outlives/projection.stderr b/src/test/ui/rfc-2093-infer-outlives/projection.stderr index 73d2420af00dd..8a91c44c5806e 100644 --- a/src/test/ui/rfc-2093-infer-outlives/projection.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/projection.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/projection.rs:4:1 | -LL | / struct Foo<'a, T: Iterator> { //~ ERROR rustc_outlives +LL | / struct Foo<'a, T: Iterator> { LL | | bar: &'a T::Item LL | | } | |_^ diff --git a/src/test/ui/rfc-2093-infer-outlives/reference.stderr b/src/test/ui/rfc-2093-infer-outlives/reference.stderr index 41a8de2d84bcf..adb1c4a629042 100644 --- a/src/test/ui/rfc-2093-infer-outlives/reference.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/reference.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/reference.rs:4:1 | -LL | / struct Foo<'a, T> { //~ ERROR rustc_outlives +LL | / struct Foo<'a, T> { LL | | bar: &'a T, LL | | } | |_^ diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr index d10f7ed28fc2d..8701408566759 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr @@ -3,13 +3,13 @@ error[E0309]: the parameter type `T` may not live long enough | LL | enum Ref1<'a, T> { | - help: consider adding an explicit lifetime bound `T: 'a`... -LL | Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough +LL | Ref1Variant1(RequireOutlives<'a, T>) | ^^^^^^^^^^^^^^^^^^^^^^ | note: ...so that the type `T` will meet its required lifetime bounds --> $DIR/regions-enum-not-wf.rs:18:18 | -LL | Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough +LL | Ref1Variant1(RequireOutlives<'a, T>) | ^^^^^^^^^^^^^^^^^^^^^^ error[E0309]: the parameter type `T` may not live long enough @@ -18,40 +18,40 @@ error[E0309]: the parameter type `T` may not live long enough LL | enum Ref2<'a, T> { | - help: consider adding an explicit lifetime bound `T: 'a`... LL | Ref2Variant1, -LL | Ref2Variant2(isize, RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough +LL | Ref2Variant2(isize, RequireOutlives<'a, T>), | ^^^^^^^^^^^^^^^^^^^^^^ | note: ...so that the type `T` will meet its required lifetime bounds --> $DIR/regions-enum-not-wf.rs:23:25 | -LL | Ref2Variant2(isize, RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough +LL | Ref2Variant2(isize, RequireOutlives<'a, T>), | ^^^^^^^^^^^^^^^^^^^^^^ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:35:1 | -LL | enum RefDouble<'a, 'b, T> { //~ ERROR the parameter type `T` may not live long enough [E0309] +LL | enum RefDouble<'a, 'b, T> { | ^ - help: consider adding an explicit lifetime bound `T: 'b`... | _| | | LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>) -LL | | //~^ the parameter type `T` may not live long enough [E0309] +LL | | LL | | } | |_^ | note: ...so that the type `T` will meet its required lifetime bounds --> $DIR/regions-enum-not-wf.rs:35:1 | -LL | / enum RefDouble<'a, 'b, T> { //~ ERROR the parameter type `T` may not live long enough [E0309] +LL | / enum RefDouble<'a, 'b, T> { LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>) -LL | | //~^ the parameter type `T` may not live long enough [E0309] +LL | | LL | | } | |_^ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:36:23 | -LL | enum RefDouble<'a, 'b, T> { //~ ERROR the parameter type `T` may not live long enough [E0309] +LL | enum RefDouble<'a, 'b, T> { | - help: consider adding an explicit lifetime bound `T: 'b`... LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr index 4b7732251b0d0..be8b5c6446cad 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr @@ -1,7 +1,7 @@ error[E0491]: in type `&'a rev_variant_struct_region::Foo<'b>`, reference has a longer lifetime than the data it references --> $DIR/regions-outlives-nominal-type-region-rev.rs:17:9 | -LL | type Out = &'a Foo<'b>; //~ ERROR reference has a longer lifetime +LL | type Out = &'a Foo<'b>; | ^^^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime 'a as defined on the impl at 16:10 diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr index 9cabc973d1a96..9a3ba2d65cad7 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr @@ -1,7 +1,7 @@ error[E0491]: in type `&'a variant_struct_region::Foo<'b>`, reference has a longer lifetime than the data it references --> $DIR/regions-outlives-nominal-type-region.rs:17:9 | -LL | type Out = &'a Foo<'b>; //~ ERROR reference has a longer lifetime +LL | type Out = &'a Foo<'b>; | ^^^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime 'a as defined on the impl at 16:10 diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr index 6142228664a4f..5389beea3a70c 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr @@ -1,7 +1,7 @@ error[E0491]: in type `&'a variant_struct_type::Foo<&'b i32>`, reference has a longer lifetime than the data it references --> $DIR/regions-outlives-nominal-type-type-rev.rs:17:9 | -LL | type Out = &'a Foo<&'b i32>; //~ ERROR reference has a longer lifetime +LL | type Out = &'a Foo<&'b i32>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime 'a as defined on the impl at 16:10 diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr index 0831f3acef283..2f3ef48a05441 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr @@ -1,7 +1,7 @@ error[E0491]: in type `&'a variant_struct_type::Foo<&'b i32>`, reference has a longer lifetime than the data it references --> $DIR/regions-outlives-nominal-type-type.rs:17:9 | -LL | type Out = &'a Foo<&'b i32>; //~ ERROR reference has a longer lifetime +LL | type Out = &'a Foo<&'b i32>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime 'a as defined on the impl at 16:10 diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr index 2485c7c3659a0..5a11c5fb95fef 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr @@ -3,13 +3,13 @@ error[E0309]: the parameter type `T` may not live long enough | LL | impl<'a, T> Trait<'a, T> for usize { | - help: consider adding an explicit lifetime bound `T: 'a`... -LL | type Out = &'a T; //~ ERROR `T` may not live long enough +LL | type Out = &'a T; | ^^^^^^^^^^^^^^^^^ | note: ...so that the reference type `&'a T` does not outlive the data it points at --> $DIR/regions-struct-not-wf.rs:13:5 | -LL | type Out = &'a T; //~ ERROR `T` may not live long enough +LL | type Out = &'a T; | ^^^^^^^^^^^^^^^^^ error[E0309]: the parameter type `T` may not live long enough @@ -17,19 +17,19 @@ error[E0309]: the parameter type `T` may not live long enough | LL | impl<'a, T> Trait<'a, T> for u32 { | - help: consider adding an explicit lifetime bound `T: 'a`... -LL | type Out = RefOk<'a, T>; //~ ERROR `T` may not live long enough +LL | type Out = RefOk<'a, T>; | ^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...so that the type `T` will meet its required lifetime bounds --> $DIR/regions-struct-not-wf.rs:21:5 | -LL | type Out = RefOk<'a, T>; //~ ERROR `T` may not live long enough +LL | type Out = RefOk<'a, T>; | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0491]: in type `&'a &'b T`, reference has a longer lifetime than the data it references --> $DIR/regions-struct-not-wf.rs:25:5 | -LL | type Out = &'a &'b T; //~ ERROR reference has a longer lifetime than the data +LL | type Out = &'a &'b T; | ^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime 'a as defined on the impl at 24:6 @@ -45,5 +45,5 @@ LL | impl<'a, 'b, T> Trait1<'a, 'b, T> for u32 { error: aborting due to 3 previous errors -Some errors occurred: E0309, E0491. +Some errors have detailed explanations: E0309, E0491. For more information about an error, try `rustc --explain E0309`. diff --git a/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr b/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr index 62b546adfc145..0be14a6956f45 100644 --- a/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr @@ -1,7 +1,7 @@ error: rustc_outlives --> $DIR/self-dyn.rs:9:1 | -LL | / struct Foo<'a, 'b, A> //~ ERROR rustc_outlives +LL | / struct Foo<'a, 'b, A> LL | | { LL | | foo: Box> LL | | } diff --git a/src/test/ui/rfc-2093-infer-outlives/self-structs.rs b/src/test/ui/rfc-2093-infer-outlives/self-structs.rs index d2550a99e814c..8f2d29d6f17c2 100644 --- a/src/test/ui/rfc-2093-infer-outlives/self-structs.rs +++ b/src/test/ui/rfc-2093-infer-outlives/self-structs.rs @@ -2,7 +2,7 @@ #[rustc_outlives] struct Foo<'a, 'b, T> { //~ ERROR rustc_outlives - field1: Bar<'a, 'b, T> + field1: dyn Bar<'a, 'b, T> } trait Bar<'x, 's, U> diff --git a/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr b/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr index 15ff6009e5c60..b32c9743e9edb 100644 --- a/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr @@ -1,8 +1,8 @@ error: rustc_outlives --> $DIR/self-structs.rs:4:1 | -LL | / struct Foo<'a, 'b, T> { //~ ERROR rustc_outlives -LL | | field1: Bar<'a, 'b, T> +LL | / struct Foo<'a, 'b, T> { +LL | | field1: dyn Bar<'a, 'b, T> LL | | } | |_^ | diff --git a/src/test/ui/rfc-2126-crate-paths/crate-path-non-absolute.stderr b/src/test/ui/rfc-2126-crate-paths/crate-path-non-absolute.stderr index 23485f7a55990..e4c47901455c9 100644 --- a/src/test/ui/rfc-2126-crate-paths/crate-path-non-absolute.stderr +++ b/src/test/ui/rfc-2126-crate-paths/crate-path-non-absolute.stderr @@ -1,13 +1,13 @@ error[E0433]: failed to resolve: `crate` in paths can only be used in start position --> $DIR/crate-path-non-absolute.rs:7:22 | -LL | let s = ::m::crate::S; //~ ERROR failed to resolve +LL | let s = ::m::crate::S; | ^^^^^ `crate` in paths can only be used in start position error[E0433]: failed to resolve: global paths cannot start with `crate` --> $DIR/crate-path-non-absolute.rs:8:20 | -LL | let s1 = ::crate::S; //~ ERROR failed to resolve +LL | let s1 = ::crate::S; | ^^^^^ global paths cannot start with `crate` error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/meta.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/meta.stderr index e9de20edb5051..eb4b9dea41bdd 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/meta.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/meta.stderr @@ -1,7 +1,7 @@ error[E0463]: can't find crate for `meta` --> $DIR/meta.rs:5:5 | -LL | use meta; //~ ERROR can't find crate for `meta` +LL | use meta; | ^^^^ can't find crate error: aborting due to previous error diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr index 23aeb92f4871d..64b920e9aa7e6 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `xcrate` --> $DIR/non-existent-1.rs:3:5 | -LL | use xcrate::S; //~ ERROR unresolved import `xcrate` +LL | use xcrate::S; | ^^^^^^ use of undeclared type or module `xcrate` error: aborting due to previous error diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr index b4982d5083c64..bfce180789cb1 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `ycrate` --> $DIR/non-existent-3.rs:3:5 | -LL | use ycrate; //~ ERROR unresolved import `ycrate` +LL | use ycrate; | ^^^^^^ no `ycrate` external crate error: aborting due to previous error diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/not-whitelisted.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/not-whitelisted.stderr index 3bea7816b3061..4e3fff98e6f4b 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/not-whitelisted.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/not-whitelisted.stderr @@ -1,13 +1,13 @@ error: cannot import a built-in macro --> $DIR/not-whitelisted.rs:6:5 | -LL | use test; //~ ERROR cannot import a built-in macro +LL | use test; | ^^^^ error[E0432]: unresolved import `alloc` --> $DIR/not-whitelisted.rs:5:5 | -LL | use alloc; //~ ERROR unresolved import `alloc` +LL | use alloc; | ^^^^^ no `alloc` external crate error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/single-segment.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/single-segment.stderr index d32835a49f88d..396a798c8204f 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/single-segment.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/single-segment.stderr @@ -1,19 +1,19 @@ error: crate root imports need to be explicitly named: `use crate as name;` --> $DIR/single-segment.rs:5:5 | -LL | use crate; //~ ERROR crate root imports need to be explicitly named: `use crate as name;` +LL | use crate; | ^^^^^ error: cannot glob-import all possible crates --> $DIR/single-segment.rs:6:5 | -LL | use *; //~ ERROR cannot glob-import all possible crates +LL | use *; | ^ error[E0423]: expected value, found module `xcrate` --> $DIR/single-segment.rs:9:13 | -LL | let s = ::xcrate; //~ ERROR expected value, found module `xcrate` +LL | let s = ::xcrate; | ^^^^^^^^ not a value error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2166-underscore-imports/basic.stderr b/src/test/ui/rfc-2166-underscore-imports/basic.stderr index 3080359192603..9ca60e8e0a955 100644 --- a/src/test/ui/rfc-2166-underscore-imports/basic.stderr +++ b/src/test/ui/rfc-2166-underscore-imports/basic.stderr @@ -1,7 +1,7 @@ warning: unused import: `m::Tr1 as _` --> $DIR/basic.rs:26:9 | -LL | use m::Tr1 as _; //~ WARN unused import +LL | use m::Tr1 as _; | ^^^^^^^^^^^ | note: lint level defined here @@ -13,6 +13,6 @@ LL | #![warn(unused_imports, unused_extern_crates)] warning: unused import: `S as _` --> $DIR/basic.rs:27:9 | -LL | use S as _; //~ WARN unused import +LL | use S as _; | ^^^^^^ diff --git a/src/test/ui/rfc-2166-underscore-imports/unused-2018.stderr b/src/test/ui/rfc-2166-underscore-imports/unused-2018.stderr index 4163c2876074b..861b3f1d4fd1e 100644 --- a/src/test/ui/rfc-2166-underscore-imports/unused-2018.stderr +++ b/src/test/ui/rfc-2166-underscore-imports/unused-2018.stderr @@ -1,7 +1,7 @@ error: unused import: `core::any` --> $DIR/unused-2018.rs:6:9 | -LL | use core::any; //~ ERROR unused import: `core::any` +LL | use core::any; | ^^^^^^^^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unused_imports)] error: unused import: `core` --> $DIR/unused-2018.rs:10:9 | -LL | use core; //~ ERROR unused import: `core` +LL | use core; | ^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs index 3d24f49ad7509..e885263aa8084 100644 --- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs +++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs @@ -1,6 +1,7 @@ // run-pass // ignore-cloudabi no processes // ignore-emscripten no processes +// ignore-sgx no processes // Tests ensuring that `dbg!(expr)` has the expected run-time behavior. // as well as some compile time properties we expect. @@ -33,6 +34,9 @@ fn test() { // We can move `b` because it's Copy. drop(b); + // Without parameters works as expected. + let _: () = dbg!(); + // Test that we can borrow and that successive applications is still identity. let a = NoCopy(1337); let b: &NoCopy = dbg!(dbg!(&a)); @@ -51,35 +55,59 @@ fn test() { 7331 })); assert_eq!(foo, 42); + + // Test trailing comma: + assert_eq!(("Yeah",), dbg!(("Yeah",))); + + // Test multiple arguments: + assert_eq!((1u8, 2u32), dbg!(1, + 2)); + + // Test multiple arguments + trailing comma: + assert_eq!((1u8, 2u32, "Yeah"), dbg!(1u8, 2u32, + "Yeah",)); } fn validate_stderr(stderr: Vec) { assert_eq!(stderr, &[ - ":21] Unit = Unit", + ":22] Unit = Unit", - ":22] a = Unit", + ":23] a = Unit", - ":28] Point{x: 42, y: 24,} = Point {", + ":29] Point{x: 42, y: 24,} = Point {", " x: 42,", - " y: 24", + " y: 24,", "}", - ":29] b = Point {", + ":30] b = Point {", " x: 42,", - " y: 24", + " y: 24,", "}", - ":38] &a = NoCopy(", - " 1337", + ":38]", + + ":42] &a = NoCopy(", + " 1337,", ")", - ":38] dbg!(& a) = NoCopy(", - " 1337", + ":42] dbg!(& a) = NoCopy(", + " 1337,", ")", - ":43] f(&42) = 42", + ":47] f(&42) = 42", "before", - ":48] { foo += 1; eprintln!(\"before\"); 7331 } = 7331", + ":52] { foo += 1; eprintln!(\"before\"); 7331 } = 7331", + + ":60] (\"Yeah\",) = (", + " \"Yeah\",", + ")", + + ":63] 1 = 1", + ":63] 2 = 2", + + ":67] 1u8 = 1", + ":67] 2u32 = 2", + ":67] \"Yeah\" = \"Yeah\"", ]); } diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.nll.stderr b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.nll.stderr deleted file mode 100644 index 5a730ad2be42c..0000000000000 --- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0382]: use of moved value: `a` - --> $DIR/dbg-macro-move-semantics.rs:9:18 - | -LL | let a = NoCopy(0); - | - move occurs because `a` has type `NoCopy`, which does not implement the `Copy` trait -LL | let _ = dbg!(a); - | ------- value moved here -LL | let _ = dbg!(a); //~ ERROR use of moved value - | ^ value used here after move - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.rs b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.rs index e6ddb3d91bfef..9f3c567b641b5 100644 --- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.rs +++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.rs @@ -7,5 +7,4 @@ fn main() { let a = NoCopy(0); let _ = dbg!(a); let _ = dbg!(a); //~ ERROR use of moved value - //~^ ERROR use of moved value } diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr index 5f3a6b414e048..5f0b3a1d40b7e 100644 --- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr +++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr @@ -1,25 +1,15 @@ error[E0382]: use of moved value: `a` --> $DIR/dbg-macro-move-semantics.rs:9:18 | +LL | let a = NoCopy(0); + | - move occurs because `a` has type `NoCopy`, which does not implement the `Copy` trait LL | let _ = dbg!(a); | ------- value moved here -LL | let _ = dbg!(a); //~ ERROR use of moved value - | ^ value used here after move - | - = note: move occurs because `a` has type `NoCopy`, which does not implement the `Copy` trait - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) - -error[E0382]: use of moved value: `a` - --> $DIR/dbg-macro-move-semantics.rs:9:13 - | LL | let _ = dbg!(a); - | ------- value moved here -LL | let _ = dbg!(a); //~ ERROR use of moved value - | ^^^^^^^ value used here after move + | ^ value used here after move | - = note: move occurs because `a` has type `NoCopy`, which does not implement the `Copy` trait = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index bd41f7b340530..ecab673953d6d 100644 --- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -1,7 +1,7 @@ error[E0277]: `NotDebug` doesn't implement `std::fmt::Debug` --> $DIR/dbg-macro-requires-debug.rs:6:23 | -LL | let _: NotDebug = dbg!(NotDebug); //~ ERROR `NotDebug` doesn't implement `std::fmt::Debug` +LL | let _: NotDebug = dbg!(NotDebug); | ^^^^^^^^^^^^^^ `NotDebug` cannot be formatted using `{:?}` | = help: the trait `std::fmt::Debug` is not implemented for `NotDebug` diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs new file mode 100644 index 0000000000000..e66d46575664f --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs @@ -0,0 +1,6 @@ +// compile-pass +// compile-flags: -Z unpretty=expanded + +fn main() { + if let 0 = 1 {} +} diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout new file mode 100644 index 0000000000000..a6b15f9bbf65d --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout @@ -0,0 +1,10 @@ +#![feature(prelude_import)] +#![no_std] +#[prelude_import] +use ::std::prelude::v1::*; +#[macro_use] +extern crate std; +// compile-pass +// compile-flags: -Z unpretty=expanded + +fn main() { if let 0 = 1 { } } diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs new file mode 100644 index 0000000000000..7d1e5c3d64df3 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs @@ -0,0 +1,244 @@ +// Here we test that `lowering` behaves correctly wrt. `let $pats = $expr` expressions. +// +// We want to make sure that `let` is banned in situations other than: +// +// expr = +// | ... +// | "if" expr_with_let block {"else" block}? +// | {label ":"}? while" expr_with_let block +// ; +// +// expr_with_let = +// | "let" top_pats "=" expr +// | expr_with_let "&&" expr_with_let +// | "(" expr_with_let ")" +// | expr +// ; +// +// To that end, we check some positions which is not part of the language above. + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete +#![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test. +//~^ WARN the feature `let_chains` is incomplete + +#![allow(irrefutable_let_patterns)] + +use std::ops::Range; + +fn main() {} + +fn nested_within_if_expr() { + if &let 0 = 0 {} //~ ERROR `let` expressions are not supported here + //~^ ERROR mismatched types + + if !let 0 = 0 {} //~ ERROR `let` expressions are not supported here + if *let 0 = 0 {} //~ ERROR `let` expressions are not supported here + //~^ ERROR type `bool` cannot be dereferenced + if -let 0 = 0 {} //~ ERROR `let` expressions are not supported here + //~^ ERROR cannot apply unary operator `-` to type `bool` + + fn _check_try_binds_tighter() -> Result<(), ()> { + if let 0 = 0? {} + //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + Ok(()) + } + if (let 0 = 0)? {} //~ ERROR `let` expressions are not supported here + //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~| ERROR the `?` operator can only be used in a function that returns `Result` + + if true || let 0 = 0 {} //~ ERROR `let` expressions are not supported here + if (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here + if true && (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here + if true || (true && let 0 = 0) {} //~ ERROR `let` expressions are not supported here + + let mut x = true; + if x = let 0 = 0 {} //~ ERROR `let` expressions are not supported here + //~^ ERROR mismatched types + + if true..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here + //~^ ERROR mismatched types + if ..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here + //~^ ERROR mismatched types + if (let 0 = 0).. {} //~ ERROR `let` expressions are not supported here + //~^ ERROR mismatched types + + // Binds as `(let ... = true)..true &&/|| false`. + if let Range { start: _, end: _ } = true..true && false {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + if let Range { start: _, end: _ } = true..true || false {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + + // Binds as `(let Range { start: F, end } = F)..(|| true)`. + const F: fn() -> bool = || true; + if let Range { start: F, end } = F..|| true {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + + // Binds as `(let Range { start: true, end } = t)..(&&false)`. + let t = &&true; + if let Range { start: true, end } = t..&&false {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + + if let true = let true = true {} //~ ERROR `let` expressions are not supported here +} + +fn nested_within_while_expr() { + while &let 0 = 0 {} //~ ERROR `let` expressions are not supported here + //~^ ERROR mismatched types + + while !let 0 = 0 {} //~ ERROR `let` expressions are not supported here + while *let 0 = 0 {} //~ ERROR `let` expressions are not supported here + //~^ ERROR type `bool` cannot be dereferenced + while -let 0 = 0 {} //~ ERROR `let` expressions are not supported here + //~^ ERROR cannot apply unary operator `-` to type `bool` + + fn _check_try_binds_tighter() -> Result<(), ()> { + while let 0 = 0? {} + //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + Ok(()) + } + while (let 0 = 0)? {} //~ ERROR `let` expressions are not supported here + //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~| ERROR the `?` operator can only be used in a function that returns `Result` + + while true || let 0 = 0 {} //~ ERROR `let` expressions are not supported here + while (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here + while true && (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here + while true || (true && let 0 = 0) {} //~ ERROR `let` expressions are not supported here + + let mut x = true; + while x = let 0 = 0 {} //~ ERROR `let` expressions are not supported here + //~^ ERROR mismatched types + + while true..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here + //~^ ERROR mismatched types + while ..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here + //~^ ERROR mismatched types + while (let 0 = 0).. {} //~ ERROR `let` expressions are not supported here + //~^ ERROR mismatched types + + // Binds as `(let ... = true)..true &&/|| false`. + while let Range { start: _, end: _ } = true..true && false {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + while let Range { start: _, end: _ } = true..true || false {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + + // Binds as `(let Range { start: F, end } = F)..(|| true)`. + const F: fn() -> bool = || true; + while let Range { start: F, end } = F..|| true {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + + // Binds as `(let Range { start: true, end } = t)..(&&false)`. + let t = &&true; + while let Range { start: true, end } = t..&&false {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + + while let true = let true = true {} //~ ERROR `let` expressions are not supported here +} + +fn not_error_because_clarified_intent() { + if let Range { start: _, end: _ } = (true..true || false) { } + + if let Range { start: _, end: _ } = (true..true && false) { } + + while let Range { start: _, end: _ } = (true..true || false) { } + + while let Range { start: _, end: _ } = (true..true && false) { } +} + +fn outside_if_and_while_expr() { + &let 0 = 0; //~ ERROR `let` expressions are not supported here + + !let 0 = 0; //~ ERROR `let` expressions are not supported here + *let 0 = 0; //~ ERROR `let` expressions are not supported here + //~^ ERROR type `bool` cannot be dereferenced + -let 0 = 0; //~ ERROR `let` expressions are not supported here + //~^ ERROR cannot apply unary operator `-` to type `bool` + + fn _check_try_binds_tighter() -> Result<(), ()> { + let 0 = 0?; + //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + Ok(()) + } + (let 0 = 0)?; //~ ERROR `let` expressions are not supported here + //~^ ERROR the `?` operator can only be used in a function that returns `Result` + //~| ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + + true || let 0 = 0; //~ ERROR `let` expressions are not supported here + (true || let 0 = 0); //~ ERROR `let` expressions are not supported here + true && (true || let 0 = 0); //~ ERROR `let` expressions are not supported here + + let mut x = true; + x = let 0 = 0; //~ ERROR `let` expressions are not supported here + + true..(let 0 = 0); //~ ERROR `let` expressions are not supported here + ..(let 0 = 0); //~ ERROR `let` expressions are not supported here + (let 0 = 0)..; //~ ERROR `let` expressions are not supported here + + (let Range { start: _, end: _ } = true..true || false); + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + + (let true = let true = true); + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + + // Check function tail position. + &let 0 = 0 + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types +} + +// Let's make sure that `let` inside const generic arguments are considered. +fn inside_const_generic_arguments() { + struct A; + impl A<{B}> { const O: u32 = 5; } + + if let A::<{ + true && let 1 = 1 //~ ERROR `let` expressions are not supported here + //~^ ERROR constant contains unimplemented expression type + //~| ERROR constant contains unimplemented expression type + }>::O = 5 {} + + while let A::<{ + true && let 1 = 1 //~ ERROR `let` expressions are not supported here + //~^ ERROR constant contains unimplemented expression type + //~| ERROR constant contains unimplemented expression type + }>::O = 5 {} + + if A::<{ + true && let 1 = 1 //~ ERROR `let` expressions are not supported here + //~^ ERROR constant contains unimplemented expression type + //~| ERROR constant contains unimplemented expression type + }>::O == 5 {} + + // In the cases above we have `ExprKind::Block` to help us out. + // Below however, we would not have a block and so an implementation might go + // from visiting expressions to types without banning `let` expressions down the tree. + // This tests ensures that we are not caught by surprise should the parser + // admit non-IDENT expressions in const generic arguments. + + if A::< + true && let 1 = 1 //~ ERROR expected one of `,` or `>`, found `&&` + >::O == 5 {} +} diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr new file mode 100644 index 0000000000000..207d0d6d6b84a --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -0,0 +1,987 @@ +error: expected one of `,` or `>`, found `&&` + --> $DIR/disallowed-positions.rs:242:14 + | +LL | true && let 1 = 1 + | ^^ expected one of `,` or `>` here + +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/disallowed-positions.rs:20:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +warning: the feature `let_chains` is incomplete and may cause the compiler to crash + --> $DIR/disallowed-positions.rs:22:12 + | +LL | #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test. + | ^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:32:9 + | +LL | if &let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:35:9 + | +LL | if !let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:36:9 + | +LL | if *let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:38:9 + | +LL | if -let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:46:9 + | +LL | if (let 0 = 0)? {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:50:16 + | +LL | if true || let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:51:17 + | +LL | if (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:52:25 + | +LL | if true && (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:53:25 + | +LL | if true || (true && let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:56:12 + | +LL | if x = let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:59:15 + | +LL | if true..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:61:11 + | +LL | if ..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:63:9 + | +LL | if (let 0 = 0).. {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:67:8 + | +LL | if let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:71:8 + | +LL | if let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:78:8 + | +LL | if let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:86:8 + | +LL | if let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:92:19 + | +LL | if let true = let true = true {} + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:96:12 + | +LL | while &let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:99:12 + | +LL | while !let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:100:12 + | +LL | while *let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:102:12 + | +LL | while -let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:110:12 + | +LL | while (let 0 = 0)? {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:114:19 + | +LL | while true || let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:115:20 + | +LL | while (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:116:28 + | +LL | while true && (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:117:28 + | +LL | while true || (true && let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:120:15 + | +LL | while x = let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:123:18 + | +LL | while true..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:125:14 + | +LL | while ..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:127:12 + | +LL | while (let 0 = 0).. {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:131:11 + | +LL | while let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:135:11 + | +LL | while let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:142:11 + | +LL | while let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:150:11 + | +LL | while let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:156:22 + | +LL | while let true = let true = true {} + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:170:6 + | +LL | &let 0 = 0; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:172:6 + | +LL | !let 0 = 0; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:173:6 + | +LL | *let 0 = 0; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:175:6 + | +LL | -let 0 = 0; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:183:6 + | +LL | (let 0 = 0)?; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:187:13 + | +LL | true || let 0 = 0; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:188:14 + | +LL | (true || let 0 = 0); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:189:22 + | +LL | true && (true || let 0 = 0); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:192:9 + | +LL | x = let 0 = 0; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:194:12 + | +LL | true..(let 0 = 0); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:195:8 + | +LL | ..(let 0 = 0); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:196:6 + | +LL | (let 0 = 0)..; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:198:6 + | +LL | (let Range { start: _, end: _ } = true..true || false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:202:6 + | +LL | (let true = let true = true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:202:17 + | +LL | (let true = let true = true); + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:207:6 + | +LL | &let 0 = 0 + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:218:17 + | +LL | true && let 1 = 1 + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:224:17 + | +LL | true && let 1 = 1 + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:230:17 + | +LL | true && let 1 = 1 + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:32:8 + | +LL | if &let 0 = 0 {} + | ^^^^^^^^^^ expected bool, found &bool + | + = note: expected type `bool` + found type `&bool` + +error[E0614]: type `bool` cannot be dereferenced + --> $DIR/disallowed-positions.rs:36:8 + | +LL | if *let 0 = 0 {} + | ^^^^^^^^^^ + +error[E0600]: cannot apply unary operator `-` to type `bool` + --> $DIR/disallowed-positions.rs:38:8 + | +LL | if -let 0 = 0 {} + | ^^^^^^^^^^ cannot apply unary operator `-` + | + = note: an implementation of `std::ops::Neg` might be missing for `bool` + +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/disallowed-positions.rs:46:8 + | +LL | if (let 0 = 0)? {} + | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` + | + = help: the trait `std::ops::Try` is not implemented for `bool` + = note: required by `std::ops::Try::into_result` + +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) + --> $DIR/disallowed-positions.rs:46:8 + | +LL | if (let 0 = 0)? {} + | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` + | + = help: the trait `std::ops::Try` is not implemented for `()` + = note: required by `std::ops::Try::from_error` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:56:8 + | +LL | if x = let 0 = 0 {} + | ^^^^^^^^^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `x == let 0 = 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:59:8 + | +LL | if true..(let 0 = 0) {} + | ^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:61:8 + | +LL | if ..(let 0 = 0) {} + | ^^^^^^^^^^^^^ expected bool, found struct `std::ops::RangeTo` + | + = note: expected type `bool` + found type `std::ops::RangeTo` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:63:8 + | +LL | if (let 0 = 0).. {} + | ^^^^^^^^^^^^^ expected bool, found struct `std::ops::RangeFrom` + | + = note: expected type `bool` + found type `std::ops::RangeFrom` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:67:12 + | +LL | if let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` + | | + | expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:67:8 + | +LL | if let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:71:12 + | +LL | if let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` + | | + | expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:71:8 + | +LL | if let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:78:12 + | +LL | if let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found struct `std::ops::Range` + | + = note: expected type `fn() -> bool` + found type `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:78:41 + | +LL | if let Range { start: F, end } = F..|| true {} + | ^^^^^^^ expected bool, found closure + | + = note: expected type `bool` + found type `[closure@$DIR/disallowed-positions.rs:78:41: 78:48]` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:78:8 + | +LL | if let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:86:12 + | +LL | if let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this match expression has type `bool` + | | + | expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:86:44 + | +LL | if let Range { start: true, end } = t..&&false {} + | ^^^^^^^ expected bool, found &&bool + | + = note: expected type `bool` + found type `&&bool` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:86:8 + | +LL | if let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range` + +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/disallowed-positions.rs:42:20 + | +LL | if let 0 = 0? {} + | ^^ the `?` operator cannot be applied to type `{integer}` + | + = help: the trait `std::ops::Try` is not implemented for `{integer}` + = note: required by `std::ops::Try::into_result` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:96:11 + | +LL | while &let 0 = 0 {} + | ^^^^^^^^^^ expected bool, found &bool + | + = note: expected type `bool` + found type `&bool` + +error[E0614]: type `bool` cannot be dereferenced + --> $DIR/disallowed-positions.rs:100:11 + | +LL | while *let 0 = 0 {} + | ^^^^^^^^^^ + +error[E0600]: cannot apply unary operator `-` to type `bool` + --> $DIR/disallowed-positions.rs:102:11 + | +LL | while -let 0 = 0 {} + | ^^^^^^^^^^ cannot apply unary operator `-` + | + = note: an implementation of `std::ops::Neg` might be missing for `bool` + +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/disallowed-positions.rs:110:11 + | +LL | while (let 0 = 0)? {} + | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` + | + = help: the trait `std::ops::Try` is not implemented for `bool` + = note: required by `std::ops::Try::into_result` + +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) + --> $DIR/disallowed-positions.rs:110:11 + | +LL | while (let 0 = 0)? {} + | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` + | + = help: the trait `std::ops::Try` is not implemented for `()` + = note: required by `std::ops::Try::from_error` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:120:11 + | +LL | while x = let 0 = 0 {} + | ^^^^^^^^^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `x == let 0 = 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:123:11 + | +LL | while true..(let 0 = 0) {} + | ^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:125:11 + | +LL | while ..(let 0 = 0) {} + | ^^^^^^^^^^^^^ expected bool, found struct `std::ops::RangeTo` + | + = note: expected type `bool` + found type `std::ops::RangeTo` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:127:11 + | +LL | while (let 0 = 0).. {} + | ^^^^^^^^^^^^^ expected bool, found struct `std::ops::RangeFrom` + | + = note: expected type `bool` + found type `std::ops::RangeFrom` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:131:15 + | +LL | while let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` + | | + | expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:131:11 + | +LL | while let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:135:15 + | +LL | while let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` + | | + | expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:135:11 + | +LL | while let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:142:15 + | +LL | while let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found struct `std::ops::Range` + | + = note: expected type `fn() -> bool` + found type `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:142:44 + | +LL | while let Range { start: F, end } = F..|| true {} + | ^^^^^^^ expected bool, found closure + | + = note: expected type `bool` + found type `[closure@$DIR/disallowed-positions.rs:142:44: 142:51]` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:142:11 + | +LL | while let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:150:15 + | +LL | while let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this match expression has type `bool` + | | + | expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:150:47 + | +LL | while let Range { start: true, end } = t..&&false {} + | ^^^^^^^ expected bool, found &&bool + | + = note: expected type `bool` + found type `&&bool` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:150:11 + | +LL | while let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range` + +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/disallowed-positions.rs:106:23 + | +LL | while let 0 = 0? {} + | ^^ the `?` operator cannot be applied to type `{integer}` + | + = help: the trait `std::ops::Try` is not implemented for `{integer}` + = note: required by `std::ops::Try::into_result` + +error[E0614]: type `bool` cannot be dereferenced + --> $DIR/disallowed-positions.rs:173:5 + | +LL | *let 0 = 0; + | ^^^^^^^^^^ + +error[E0600]: cannot apply unary operator `-` to type `bool` + --> $DIR/disallowed-positions.rs:175:5 + | +LL | -let 0 = 0; + | ^^^^^^^^^^ cannot apply unary operator `-` + | + = note: an implementation of `std::ops::Neg` might be missing for `bool` + +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/disallowed-positions.rs:183:5 + | +LL | (let 0 = 0)?; + | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` + | + = help: the trait `std::ops::Try` is not implemented for `bool` + = note: required by `std::ops::Try::into_result` + +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) + --> $DIR/disallowed-positions.rs:183:5 + | +LL | (let 0 = 0)?; + | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` + | + = help: the trait `std::ops::Try` is not implemented for `()` + = note: required by `std::ops::Try::from_error` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:198:10 + | +LL | (let Range { start: _, end: _ } = true..true || false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` + | | + | expected bool, found struct `std::ops::Range` + | + = note: expected type `bool` + found type `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:207:5 + | +LL | fn outside_if_and_while_expr() { + | - help: try adding a return type: `-> &bool` +... +LL | &let 0 = 0 + | ^^^^^^^^^^ expected (), found &bool + | + = note: expected type `()` + found type `&bool` + +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/disallowed-positions.rs:179:17 + | +LL | let 0 = 0?; + | ^^ the `?` operator cannot be applied to type `{integer}` + | + = help: the trait `std::ops::Try` is not implemented for `{integer}` + = note: required by `std::ops::Try::into_result` + +error[E0019]: constant contains unimplemented expression type + --> $DIR/disallowed-positions.rs:218:25 + | +LL | true && let 1 = 1 + | ^ + +error[E0019]: constant contains unimplemented expression type + --> $DIR/disallowed-positions.rs:218:21 + | +LL | true && let 1 = 1 + | ^ + +error[E0019]: constant contains unimplemented expression type + --> $DIR/disallowed-positions.rs:224:25 + | +LL | true && let 1 = 1 + | ^ + +error[E0019]: constant contains unimplemented expression type + --> $DIR/disallowed-positions.rs:224:21 + | +LL | true && let 1 = 1 + | ^ + +error[E0019]: constant contains unimplemented expression type + --> $DIR/disallowed-positions.rs:230:25 + | +LL | true && let 1 = 1 + | ^ + +error[E0019]: constant contains unimplemented expression type + --> $DIR/disallowed-positions.rs:230:21 + | +LL | true && let 1 = 1 + | ^ + +error: aborting due to 109 previous errors + +Some errors have detailed explanations: E0019, E0277, E0308, E0600, E0614. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs new file mode 100644 index 0000000000000..64987663adb90 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs @@ -0,0 +1,136 @@ +// gate-test-let_chains + +// Here we test feature gating for ´let_chains`. +// See `disallowed-positions.rs` for the grammar +// defining the language for gated allowed positions. + +#![allow(irrefutable_let_patterns)] + +use std::ops::Range; + +fn _if() { + if let 0 = 1 {} // Stable! + + if (let 0 = 1) {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + + if (((let 0 = 1))) {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + + if true && let 0 = 1 {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + + if let 0 = 1 && true {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + + if (let 0 = 1) && true {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + + if true && (let 0 = 1) {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + + if (let 0 = 1) && (let 0 = 1) {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + + if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + + if let Range { start: _, end: _ } = (true..true) && false {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here +} + +fn _while() { + while let 0 = 1 {} // Stable! + + while (let 0 = 1) {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + + while (((let 0 = 1))) {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + + while true && let 0 = 1 {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + + while let 0 = 1 && true {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + + while (let 0 = 1) && true {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + + while true && (let 0 = 1) {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + + while (let 0 = 1) && (let 0 = 1) {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + + while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + + while let Range { start: _, end: _ } = (true..true) && false {} + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here +} + +fn _macros() { + macro_rules! noop_expr { ($e:expr) => {}; } + + noop_expr!((let 0 = 1)); + //~^ ERROR `let` expressions in this position are experimental [E0658] + + macro_rules! use_expr { + ($e:expr) => { + if $e {} + while $e {} + } + } + use_expr!((let 0 = 1 && 0 == 0)); + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + use_expr!((let 0 = 1)); + //~^ ERROR `let` expressions in this position are experimental [E0658] + //~| ERROR `let` expressions are not supported here + #[cfg(FALSE)] (let 0 = 1); + //~^ ERROR `let` expressions in this position are experimental [E0658] + use_expr!(let 0 = 1); + //~^ ERROR no rules expected the token `let` + // ^--- FIXME(53667): Consider whether `Let` can be added to `ident_can_begin_expr`. +} + +fn main() {} diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr new file mode 100644 index 0000000000000..6167427fa9fdc --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr @@ -0,0 +1,570 @@ +error: no rules expected the token `let` + --> $DIR/feature-gate.rs:131:15 + | +LL | macro_rules! use_expr { + | --------------------- when calling this macro +... +LL | use_expr!(let 0 = 1); + | ^^^ no rules expected this token in macro call + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:14:9 + | +LL | if (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:18:11 + | +LL | if (((let 0 = 1))) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:22:16 + | +LL | if true && let 0 = 1 {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:26:8 + | +LL | if let 0 = 1 && true {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:30:9 + | +LL | if (let 0 = 1) && true {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:34:17 + | +LL | if true && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:38:9 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:38:24 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:44:8 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:44:21 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:44:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:44:48 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:44:61 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:56:8 + | +LL | if let Range { start: _, end: _ } = (true..true) && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:64:12 + | +LL | while (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:68:14 + | +LL | while (((let 0 = 1))) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:72:19 + | +LL | while true && let 0 = 1 {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:76:11 + | +LL | while let 0 = 1 && true {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:80:12 + | +LL | while (let 0 = 1) && true {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:84:20 + | +LL | while true && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:88:12 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:88:27 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:94:11 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:94:24 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:94:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:94:51 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:94:64 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:106:11 + | +LL | while let Range { start: _, end: _ } = (true..true) && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:129:20 + | +LL | #[cfg(FALSE)] (let 0 = 1); + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:114:17 + | +LL | noop_expr!((let 0 = 1)); + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:123:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error[E0658]: `let` expressions in this position are experimental + --> $DIR/feature-gate.rs:126:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53667 + = help: add #![feature(let_chains)] to the crate attributes to enable + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:14:9 + | +LL | if (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:18:11 + | +LL | if (((let 0 = 1))) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:22:16 + | +LL | if true && let 0 = 1 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:26:8 + | +LL | if let 0 = 1 && true {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:30:9 + | +LL | if (let 0 = 1) && true {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:34:17 + | +LL | if true && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:38:9 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:38:24 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:44:8 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:44:21 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:44:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:44:48 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:44:61 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:56:8 + | +LL | if let Range { start: _, end: _ } = (true..true) && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:64:12 + | +LL | while (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:68:14 + | +LL | while (((let 0 = 1))) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:72:19 + | +LL | while true && let 0 = 1 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:76:11 + | +LL | while let 0 = 1 && true {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:80:12 + | +LL | while (let 0 = 1) && true {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:84:20 + | +LL | while true && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:88:12 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:88:27 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:94:11 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:94:24 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:94:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:94:51 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:94:64 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:106:11 + | +LL | while let Range { start: _, end: _ } = (true..true) && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:123:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:126:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + +error: aborting due to 63 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs b/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs new file mode 100644 index 0000000000000..1de4e5bcebee9 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs @@ -0,0 +1,18 @@ +// run-pass + +#![allow(irrefutable_let_patterns)] + +use std::ops::Range; + +fn main() { + let x: bool; + // This should associate as: `(x = (true && false));`. + x = true && false; + assert!(!x); + + fn _f1() -> bool { + // Should associate as `(let _ = (return (true && false)))`. + if let _ = return true && false {}; + } + assert!(!_f1()); +} diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs deleted file mode 100644 index d79798d57e820..0000000000000 --- a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs +++ /dev/null @@ -1,38 +0,0 @@ -// edition:2015 - -// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up -// with examples easier. - -#[allow(irrefutable_let_patterns)] -fn main() { - use std::ops::Range; - - if let Range { start: _, end: _ } = true..true && false { } - //~^ ERROR ambiguous use of `&&` - - if let Range { start: _, end: _ } = true..true || false { } - //~^ ERROR ambiguous use of `||` - - while let Range { start: _, end: _ } = true..true && false { } - //~^ ERROR ambiguous use of `&&` - - while let Range { start: _, end: _ } = true..true || false { } - //~^ ERROR ambiguous use of `||` - - if let true = false && false { } - //~^ ERROR ambiguous use of `&&` - - while let true = (1 == 2) && false { } - //~^ ERROR ambiguous use of `&&` - - // The following cases are not an error as parenthesis are used to - // clarify intent: - - if let Range { start: _, end: _ } = true..(true || false) { } - - if let Range { start: _, end: _ } = true..(true && false) { } - - while let Range { start: _, end: _ } = true..(true || false) { } - - while let Range { start: _, end: _ } = true..(true && false) { } -} diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr deleted file mode 100644 index 2cd59fe56cf2d..0000000000000 --- a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr +++ /dev/null @@ -1,56 +0,0 @@ -error: ambiguous use of `&&` - --> $DIR/syntax-ambiguity-2015.rs:10:47 - | -LL | if let Range { start: _, end: _ } = true..true && false { } - | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` - | - = note: this will be a error until the `let_chains` feature is stabilized - = note: see rust-lang/rust#53668 for more information - -error: ambiguous use of `||` - --> $DIR/syntax-ambiguity-2015.rs:13:47 - | -LL | if let Range { start: _, end: _ } = true..true || false { } - | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` - | - = note: this will be a error until the `let_chains` feature is stabilized - = note: see rust-lang/rust#53668 for more information - -error: ambiguous use of `&&` - --> $DIR/syntax-ambiguity-2015.rs:16:50 - | -LL | while let Range { start: _, end: _ } = true..true && false { } - | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` - | - = note: this will be a error until the `let_chains` feature is stabilized - = note: see rust-lang/rust#53668 for more information - -error: ambiguous use of `||` - --> $DIR/syntax-ambiguity-2015.rs:19:50 - | -LL | while let Range { start: _, end: _ } = true..true || false { } - | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` - | - = note: this will be a error until the `let_chains` feature is stabilized - = note: see rust-lang/rust#53668 for more information - -error: ambiguous use of `&&` - --> $DIR/syntax-ambiguity-2015.rs:22:19 - | -LL | if let true = false && false { } - | ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)` - | - = note: this will be a error until the `let_chains` feature is stabilized - = note: see rust-lang/rust#53668 for more information - -error: ambiguous use of `&&` - --> $DIR/syntax-ambiguity-2015.rs:25:22 - | -LL | while let true = (1 == 2) && false { } - | ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)` - | - = note: this will be a error until the `let_chains` feature is stabilized - = note: see rust-lang/rust#53668 for more information - -error: aborting due to 6 previous errors - diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs deleted file mode 100644 index 687bf659416ab..0000000000000 --- a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs +++ /dev/null @@ -1,38 +0,0 @@ -// edition:2018 - -// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up -// with examples easier. - -#[allow(irrefutable_let_patterns)] -fn main() { - use std::ops::Range; - - if let Range { start: _, end: _ } = true..true && false { } - //~^ ERROR ambiguous use of `&&` - - if let Range { start: _, end: _ } = true..true || false { } - //~^ ERROR ambiguous use of `||` - - while let Range { start: _, end: _ } = true..true && false { } - //~^ ERROR ambiguous use of `&&` - - while let Range { start: _, end: _ } = true..true || false { } - //~^ ERROR ambiguous use of `||` - - if let true = false && false { } - //~^ ERROR ambiguous use of `&&` - - while let true = (1 == 2) && false { } - //~^ ERROR ambiguous use of `&&` - - // The following cases are not an error as parenthesis are used to - // clarify intent: - - if let Range { start: _, end: _ } = true..(true || false) { } - - if let Range { start: _, end: _ } = true..(true && false) { } - - while let Range { start: _, end: _ } = true..(true || false) { } - - while let Range { start: _, end: _ } = true..(true && false) { } -} diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr deleted file mode 100644 index cbba2d7473334..0000000000000 --- a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr +++ /dev/null @@ -1,56 +0,0 @@ -error: ambiguous use of `&&` - --> $DIR/syntax-ambiguity-2018.rs:10:47 - | -LL | if let Range { start: _, end: _ } = true..true && false { } - | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` - | - = note: this will be a error until the `let_chains` feature is stabilized - = note: see rust-lang/rust#53668 for more information - -error: ambiguous use of `||` - --> $DIR/syntax-ambiguity-2018.rs:13:47 - | -LL | if let Range { start: _, end: _ } = true..true || false { } - | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` - | - = note: this will be a error until the `let_chains` feature is stabilized - = note: see rust-lang/rust#53668 for more information - -error: ambiguous use of `&&` - --> $DIR/syntax-ambiguity-2018.rs:16:50 - | -LL | while let Range { start: _, end: _ } = true..true && false { } - | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` - | - = note: this will be a error until the `let_chains` feature is stabilized - = note: see rust-lang/rust#53668 for more information - -error: ambiguous use of `||` - --> $DIR/syntax-ambiguity-2018.rs:19:50 - | -LL | while let Range { start: _, end: _ } = true..true || false { } - | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` - | - = note: this will be a error until the `let_chains` feature is stabilized - = note: see rust-lang/rust#53668 for more information - -error: ambiguous use of `&&` - --> $DIR/syntax-ambiguity-2018.rs:22:19 - | -LL | if let true = false && false { } - | ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)` - | - = note: this will be a error until the `let_chains` feature is stabilized - = note: see rust-lang/rust#53668 for more information - -error: ambiguous use of `&&` - --> $DIR/syntax-ambiguity-2018.rs:25:22 - | -LL | while let true = (1 == 2) && false { } - | ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)` - | - = note: this will be a error until the `let_chains` feature is stabilized - = note: see rust-lang/rust#53668 for more information - -error: aborting due to 6 previous errors - diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs new file mode 100644 index 0000000000000..e900ccab4fd83 --- /dev/null +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs @@ -0,0 +1,8 @@ +// edition:2018 + +#![feature(param_attrs)] + +trait Trait2015 { fn foo(#[allow(C)] i32); } +//~^ ERROR expected one of `:` or `@`, found `)` + +fn main() {} diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr new file mode 100644 index 0000000000000..d0ed65f288011 --- /dev/null +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr @@ -0,0 +1,18 @@ +error: expected one of `:` or `@`, found `)` + --> $DIR/param-attrs-2018.rs:5:41 + | +LL | trait Trait2015 { fn foo(#[allow(C)] i32); } + | ^ expected one of `:` or `@` here + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this was a parameter name, give it a type + | +LL | trait Trait2015 { fn foo(#[allow(C)] i32: TypeName); } + | ^^^^^^^^^^^^^ +help: if this is a type, explicitly ignore the parameter name + | +LL | trait Trait2015 { fn foo(#[allow(C)] _: i32); } + | ^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs new file mode 100644 index 0000000000000..c521d04fda562 --- /dev/null +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs @@ -0,0 +1,225 @@ +// compile-flags: --cfg something +// compile-pass + +#![feature(param_attrs)] + +extern "C" { + fn ffi( + #[allow(C)] a: i32, + #[cfg(something)] b: i32, + #[cfg_attr(something, cfg(nothing))] c: i32, + #[deny(C)] d: i32, + #[forbid(C)] #[warn(C)] ... + ); +} + +type FnType = fn( + #[allow(C)] a: i32, + #[cfg(something)] b: i32, + #[cfg_attr(something, cfg(nothing))] c: i32, + #[deny(C)] d: i32, + #[forbid(C)] #[warn(C)] e: i32 +); + +pub fn foo( + #[allow(C)] a: i32, + #[cfg(something)] b: i32, + #[cfg_attr(something, cfg(nothing))] c: i32, + #[deny(C)] d: i32, + #[forbid(C)] #[warn(C)] e: i32 +) {} + +// self, &self and &mut self + +struct SelfStruct {} +impl SelfStruct { + fn foo( + #[allow(C)] self, + #[cfg(something)] a: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(C)] b: i32, + ) {} +} + +struct RefStruct {} +impl RefStruct { + fn foo( + #[allow(C)] &self, + #[cfg(something)] a: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(C)] b: i32, + ) {} +} +trait RefTrait { + fn foo( + #[forbid(C)] &self, + #[warn(C)] a: i32 + ) {} +} +impl RefTrait for RefStruct { + fn foo( + #[forbid(C)] &self, + #[warn(C)] a: i32 + ) {} +} + +struct MutStruct {} +impl MutStruct { + fn foo( + #[allow(C)] &mut self, + #[cfg(something)] a: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(C)] b: i32, + ) {} +} +trait MutTrait { + fn foo( + #[forbid(C)] &mut self, + #[warn(C)] a: i32 + ) {} +} +impl MutTrait for MutStruct { + fn foo( + #[forbid(C)] &mut self, + #[warn(C)] a: i32 + ) {} +} + +// self: Self, self: &Self and self: &mut Self + +struct NamedSelfSelfStruct {} +impl NamedSelfSelfStruct { + fn foo( + #[allow(C)] self: Self, + #[cfg(something)] a: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(C)] b: i32, + ) {} +} + +struct NamedSelfRefStruct {} +impl NamedSelfRefStruct { + fn foo( + #[allow(C)] self: &Self, + #[cfg(something)] a: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(C)] b: i32, + ) {} +} +trait NamedSelfRefTrait { + fn foo( + #[forbid(C)] self: &Self, + #[warn(C)] a: i32 + ) {} +} +impl NamedSelfRefTrait for NamedSelfRefStruct { + fn foo( + #[forbid(C)] self: &Self, + #[warn(C)] a: i32 + ) {} +} + +struct NamedSelfMutStruct {} +impl NamedSelfMutStruct { + fn foo( + #[allow(C)] self: &mut Self, + #[cfg(something)] a: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(C)] b: i32, + ) {} +} +trait NamedSelfMutTrait { + fn foo( + #[forbid(C)] self: &mut Self, + #[warn(C)] a: i32 + ) {} +} +impl NamedSelfMutTrait for NamedSelfMutStruct { + fn foo( + #[forbid(C)] self: &mut Self, + #[warn(C)] a: i32 + ) {} +} + +// &'a self and &'a mut self + +struct NamedLifetimeRefStruct {} +impl NamedLifetimeRefStruct { + fn foo<'a>( + #[allow(C)] self: &'a Self, + #[cfg(something)] a: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(C)] b: i32, + ) {} +} +trait NamedLifetimeRefTrait { + fn foo<'a>( + #[forbid(C)] &'a self, + #[warn(C)] a: i32 + ) {} +} +impl NamedLifetimeRefTrait for NamedLifetimeRefStruct { + fn foo<'a>( + #[forbid(C)] &'a self, + #[warn(C)] a: i32 + ) {} +} + +struct NamedLifetimeMutStruct {} +impl NamedLifetimeMutStruct { + fn foo<'a>( + #[allow(C)] self: &'a mut Self, + #[cfg(something)] a: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(C)] b: i32, + ) {} +} +trait NamedLifetimeMutTrait { + fn foo<'a>( + #[forbid(C)] &'a mut self, + #[warn(C)] a: i32 + ) {} +} +impl NamedLifetimeMutTrait for NamedLifetimeMutStruct { + fn foo<'a>( + #[forbid(C)] &'a mut self, + #[warn(C)] a: i32 + ) {} +} + +// Box + +struct BoxSelfStruct {} +impl BoxSelfStruct { + fn foo( + #[allow(C)] self: Box, + #[cfg(something)] a: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(C)] b: i32, + ) {} +} +trait BoxSelfTrait { + fn foo( + #[forbid(C)] self: Box, + #[warn(C)] a: i32 + ) {} +} +impl BoxSelfTrait for BoxSelfStruct { + fn foo( + #[forbid(C)] self: Box, + #[warn(C)] a: i32 + ) {} +} + +fn main() { + let _: unsafe extern "C" fn(_, _, _, ...) = ffi; + let _: fn(_, _, _, _) = foo; + let _: FnType = |_, _, _, _| {}; + let c = | + #[allow(C)] a: u32, + #[cfg(something)] b: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(C)] c: i32, + | {}; + let _ = c(1, 2); +} diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs new file mode 100644 index 0000000000000..352375729bd45 --- /dev/null +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs @@ -0,0 +1,145 @@ +#![feature(param_attrs)] + +extern "C" { + fn ffi( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + #[test] a: i32, + //~^ ERROR The attribute `test` is currently unknown to the compiler and may have + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + ); +} + +type FnType = fn( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + #[test] a: u32, + //~^ ERROR The attribute `test` is currently unknown to the compiler and may have + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in +); + +pub fn foo( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + #[test] a: u32, + //~^ ERROR The attribute `test` is currently unknown to the compiler and may have + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in +) {} + +struct SelfStruct {} +impl SelfStruct { + fn foo( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + self, + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[test] a: i32, + //~^ ERROR The attribute `test` is currently unknown to the compiler and may have + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + /// Qux + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + ) {} +} + +struct RefStruct {} +impl RefStruct { + fn foo( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + &self, + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[test] a: i32, + //~^ ERROR The attribute `test` is currently unknown to the compiler and may have + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + /// Qux + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + ) {} +} +trait RefTrait { + fn foo( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + &self, + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[test] a: i32, + //~^ ERROR The attribute `test` is currently unknown to the compiler and may have + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + /// Qux + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + ) {} +} +impl RefTrait for RefStruct { + fn foo( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + &self, + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[test] a: i32, + //~^ ERROR The attribute `test` is currently unknown to the compiler and may have + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + /// Qux + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + ) {} +} + +fn main() { + let _ = | + /// Foo + //~^ ERROR documentation comments cannot be applied to function + #[test] a: u32, + //~^ ERROR The attribute `test` is currently unknown to the compiler and may have + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32 + //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in + | {}; +} diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr new file mode 100644 index 0000000000000..e6f3efc04ce27 --- /dev/null +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr @@ -0,0 +1,339 @@ +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:5:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:9:9 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:11:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:13:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:15:9 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:21:5 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:25:5 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:27:5 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:29:5 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:31:5 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:36:5 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:40:5 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:42:5 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:44:5 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:46:5 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:53:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:56:9 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:60:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:62:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:64:9 + | +LL | /// Qux + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:66:9 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:74:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:77:9 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:81:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:83:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:85:9 + | +LL | /// Qux + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:87:9 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:93:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:96:9 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:100:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:102:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:104:9 + | +LL | /// Qux + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:106:9 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:112:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:115:9 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:119:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:121:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:123:9 + | +LL | /// Qux + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:125:9 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:132:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:136:9 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:138:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:140:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:142:9 + | +LL | #[no_mangle] b: i32 + | ^^^^^^^^^^^^ + +error[E0658]: The attribute `test` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/param-attrs-builtin-attrs.rs:7:9 + | +LL | #[test] a: i32, + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `test` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/param-attrs-builtin-attrs.rs:23:5 + | +LL | #[test] a: u32, + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `test` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/param-attrs-builtin-attrs.rs:38:5 + | +LL | #[test] a: u32, + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `test` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/param-attrs-builtin-attrs.rs:58:9 + | +LL | #[test] a: i32, + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `test` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/param-attrs-builtin-attrs.rs:79:9 + | +LL | #[test] a: i32, + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `test` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/param-attrs-builtin-attrs.rs:98:9 + | +LL | #[test] a: i32, + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `test` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/param-attrs-builtin-attrs.rs:117:9 + | +LL | #[test] a: i32, + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `test` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/param-attrs-builtin-attrs.rs:134:9 + | +LL | #[test] a: u32, + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error: aborting due to 52 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.rs new file mode 100644 index 0000000000000..977b5d9ce3495 --- /dev/null +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.rs @@ -0,0 +1,79 @@ +// compile-flags: --cfg something + +#![feature(param_attrs)] +#![deny(unused_variables)] + +extern "C" { + fn ffi( + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + #[cfg_attr(something, cfg(nothing))] c: i32, + #[cfg_attr(nothing, cfg(nothing))] ... + ); +} + +type FnType = fn( + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + #[cfg_attr(nothing, cfg(nothing))] c: i32, + #[cfg_attr(something, cfg(nothing))] d: i32, +); + +fn foo( + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + //~^ ERROR unused variable: `b` [unused_variables] + #[cfg_attr(nothing, cfg(nothing))] c: i32, + //~^ ERROR unused variable: `c` [unused_variables] + #[cfg_attr(something, cfg(nothing))] d: i32, +) {} + +struct RefStruct {} +impl RefStruct { + fn bar( + &self, + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + //~^ ERROR unused variable: `b` [unused_variables] + #[cfg_attr(nothing, cfg(nothing))] c: i32, + //~^ ERROR unused variable: `c` [unused_variables] + #[cfg_attr(something, cfg(nothing))] d: i32, + ) {} +} +trait RefTrait { + fn bar( + &self, + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + //~^ ERROR unused variable: `b` [unused_variables] + #[cfg_attr(nothing, cfg(nothing))] c: i32, + //~^ ERROR unused variable: `c` [unused_variables] + #[cfg_attr(something, cfg(nothing))] d: i32, + ) {} +} +impl RefTrait for RefStruct { + fn bar( + &self, + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + //~^ ERROR unused variable: `b` [unused_variables] + #[cfg_attr(nothing, cfg(nothing))] c: i32, + //~^ ERROR unused variable: `c` [unused_variables] + #[cfg_attr(something, cfg(nothing))] d: i32, + ) {} +} + +fn main() { + let _: unsafe extern "C" fn(_, ...) = ffi; + let _: fn(_, _) = foo; + let _: FnType = |_, _| {}; + let c = | + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + //~^ ERROR unused variable: `b` [unused_variables] + #[cfg_attr(nothing, cfg(nothing))] c: i32, + //~^ ERROR unused variable: `c` [unused_variables] + #[cfg_attr(something, cfg(nothing))] d: i32, + | {}; + let _ = c(1, 2); +} diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.stderr new file mode 100644 index 0000000000000..c97190324e5a2 --- /dev/null +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.stderr @@ -0,0 +1,68 @@ +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:24:23 + | +LL | #[cfg(something)] b: i32, + | ^ help: consider prefixing with an underscore: `_b` + | +note: lint level defined here + --> $DIR/param-attrs-cfg.rs:4:9 + | +LL | #![deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: unused variable: `c` + --> $DIR/param-attrs-cfg.rs:26:40 + | +LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, + | ^ help: consider prefixing with an underscore: `_c` + +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:72:27 + | +LL | #[cfg(something)] b: i32, + | ^ help: consider prefixing with an underscore: `_b` + +error: unused variable: `c` + --> $DIR/param-attrs-cfg.rs:74:44 + | +LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, + | ^ help: consider prefixing with an underscore: `_c` + +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:47:27 + | +LL | #[cfg(something)] b: i32, + | ^ help: consider prefixing with an underscore: `_b` + +error: unused variable: `c` + --> $DIR/param-attrs-cfg.rs:49:44 + | +LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, + | ^ help: consider prefixing with an underscore: `_c` + +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:36:27 + | +LL | #[cfg(something)] b: i32, + | ^ help: consider prefixing with an underscore: `_b` + +error: unused variable: `c` + --> $DIR/param-attrs-cfg.rs:38:44 + | +LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, + | ^ help: consider prefixing with an underscore: `_c` + +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:58:27 + | +LL | #[cfg(something)] b: i32, + | ^ help: consider prefixing with an underscore: `_b` + +error: unused variable: `c` + --> $DIR/param-attrs-cfg.rs:60:44 + | +LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, + | ^ help: consider prefixing with an underscore: `_c` + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.rs new file mode 100644 index 0000000000000..c5a6514efb0f0 --- /dev/null +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.rs @@ -0,0 +1,14 @@ +// gate-test-param_attrs + +fn foo( + /// Foo + //~^ ERROR documentation comments cannot be applied to function parameters + //~| NOTE doc comments are not allowed here + //~| ERROR attributes on function parameters are unstable + //~| NOTE https://github.com/rust-lang/rust/issues/60406 + #[allow(C)] a: u8 + //~^ ERROR attributes on function parameters are unstable + //~| NOTE https://github.com/rust-lang/rust/issues/60406 +) {} + +fn main() {} diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.stderr new file mode 100644 index 0000000000000..82f21e7fdbcb4 --- /dev/null +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-feature-gate.stderr @@ -0,0 +1,27 @@ +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-feature-gate.rs:4:5 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error[E0658]: attributes on function parameters are unstable + --> $DIR/param-attrs-feature-gate.rs:4:5 + | +LL | /// Foo + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/60406 + = help: add #![feature(param_attrs)] to the crate attributes to enable + +error[E0658]: attributes on function parameters are unstable + --> $DIR/param-attrs-feature-gate.rs:9:5 + | +LL | #[allow(C)] a: u8 + | ^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/60406 + = help: add #![feature(param_attrs)] to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc1445/feature-gate.no_gate.stderr b/src/test/ui/rfc1445/feature-gate.no_gate.stderr index 8c6a08d84a493..3a2014fab090b 100644 --- a/src/test/ui/rfc1445/feature-gate.no_gate.stderr +++ b/src/test/ui/rfc1445/feature-gate.no_gate.stderr @@ -1,9 +1,10 @@ -error[E0658]: the semantics of constant patterns is not yet settled (see issue #31434) +error[E0658]: the semantics of constant patterns is not yet settled --> $DIR/feature-gate.rs:13:1 | -LL | #[structural_match] //[no_gate]~ ERROR semantics of constant patterns is not yet settled +LL | #[structural_match] | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/31434 = help: add #![feature(structural_match)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/rfc1445/feature-gate.with_gate.stderr b/src/test/ui/rfc1445/feature-gate.with_gate.stderr index da681662c2fa8..ca8dc75c5335f 100644 --- a/src/test/ui/rfc1445/feature-gate.with_gate.stderr +++ b/src/test/ui/rfc1445/feature-gate.with_gate.stderr @@ -1,7 +1,7 @@ error: compilation successful --> $DIR/feature-gate.rs:21:1 | -LL | / fn main() { //[with_gate]~ ERROR compilation successful +LL | / fn main() { LL | | let y = Foo { x: 1 }; LL | | match y { LL | | FOO => { } diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.rs b/src/test/ui/rfc1445/match-forbidden-without-eq.rs index 78d799e2b01db..1cca27520618d 100644 --- a/src/test/ui/rfc1445/match-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/match-forbidden-without-eq.rs @@ -20,6 +20,8 @@ fn main() { f32::INFINITY => { } //~^ WARNING floating-point types cannot be used in patterns //~| WARNING will become a hard error in a future release + //~| WARNING floating-point types cannot be used in patterns + //~| WARNING this was previously accepted by the compiler but is being phased out _ => { } } } diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.stderr b/src/test/ui/rfc1445/match-forbidden-without-eq.stderr index ebea2f364ec88..4ec1e8ddb9533 100644 --- a/src/test/ui/rfc1445/match-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/match-forbidden-without-eq.stderr @@ -14,5 +14,14 @@ LL | f32::INFINITY => { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 +warning: floating-point types cannot be used in patterns + --> $DIR/match-forbidden-without-eq.rs:20:9 + | +LL | f32::INFINITY => { } + | ^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + error: aborting due to previous error diff --git a/src/test/ui/rfc1598-generic-associated-types/collections.rs b/src/test/ui/rfc1598-generic-associated-types/collections.rs index 5414bb4a6d20e..ede6a3b2b3938 100644 --- a/src/test/ui/rfc1598-generic-associated-types/collections.rs +++ b/src/test/ui/rfc1598-generic-associated-types/collections.rs @@ -2,7 +2,7 @@ //~^ WARNING the feature `generic_associated_types` is incomplete #![feature(associated_type_defaults)] -// FIXME(#44265): "lifetime arguments are not allowed on this entity" errors will be addressed in a +// FIXME(#44265): "lifetime arguments are not allowed for this type" errors will be addressed in a // follow-up PR. // A Collection trait and collection families. Based on @@ -15,14 +15,14 @@ trait Collection { // Test associated type defaults with parameters type Sibling: Collection = <>::Family as CollectionFamily>::Member; - //~^ ERROR type arguments are not allowed on this entity [E0109] + //~^ ERROR type arguments are not allowed for this type [E0109] fn empty() -> Self; fn add(&mut self, value: T); fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>; - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] } trait CollectionFamily { @@ -48,13 +48,13 @@ impl Collection for Vec { } fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> { - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] self.iter() } } fn floatify(ints: &C) -> <>::Family as CollectionFamily>::Member -//~^ ERROR type arguments are not allowed on this entity [E0109] +//~^ ERROR type arguments are not allowed for this type [E0109] where C: Collection, { @@ -66,7 +66,7 @@ where } fn floatify_sibling(ints: &C) -> >::Sibling -//~^ ERROR type arguments are not allowed on this entity [E0109] +//~^ ERROR type arguments are not allowed for this type [E0109] where C: Collection, { diff --git a/src/test/ui/rfc1598-generic-associated-types/collections.stderr b/src/test/ui/rfc1598-generic-associated-types/collections.stderr index eeed04bd89213..d0fe5035bca46 100644 --- a/src/test/ui/rfc1598-generic-associated-types/collections.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/collections.stderr @@ -4,31 +4,31 @@ warning: the feature `generic_associated_types` is incomplete and may cause the LL | #![feature(generic_associated_types)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/collections.rs:56:90 | LL | fn floatify(ints: &C) -> <>::Family as CollectionFamily>::Member | ^^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/collections.rs:68:69 | LL | fn floatify_sibling(ints: &C) -> >::Sibling | ^^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/collections.rs:17:71 | LL | <>::Family as CollectionFamily>::Member; | ^ type argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/collections.rs:24:50 | LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>; | ^^^^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/collections.rs:50:50 | LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> { @@ -36,5 +36,4 @@ LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> { error: aborting due to 5 previous errors -Some errors occurred: E0109, E0110. -For more information about an error, try `rustc --explain E0109`. +For more information about this error, try `rustc --explain E0109`. diff --git a/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.rs b/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.rs index d9c482e23e47c..3a459a4551c8d 100644 --- a/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.rs +++ b/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.rs @@ -3,7 +3,7 @@ use std::ops::Deref; -// FIXME(#44265): "lifetime arguments are not allowed on this entity" errors will be addressed in a +// FIXME(#44265): "lifetime arguments are not allowed for this type" errors will be addressed in a // follow-up PR. trait Foo { @@ -15,15 +15,15 @@ trait Baz { // This weird type tests that we can use universal function call syntax to access the Item on type Baa<'a>: Deref as Foo>::Bar<'a, 'static>>; - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] - //~| ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] + //~| ERROR lifetime arguments are not allowed for this type [E0109] } impl Baz for T where T: Foo { type Quux<'a> = T; type Baa<'a> = &'a ::Bar<'a, 'static>; - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] } fn main() {} diff --git a/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr b/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr index fd6116d2da23a..b2dd523c8f597 100644 --- a/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr @@ -4,19 +4,19 @@ warning: the feature `generic_associated_types` is incomplete and may cause the LL | #![feature(generic_associated_types)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/construct_with_other_type.rs:17:46 | LL | type Baa<'a>: Deref as Foo>::Bar<'a, 'static>>; | ^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/construct_with_other_type.rs:17:63 | LL | type Baa<'a>: Deref as Foo>::Bar<'a, 'static>>; | ^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/construct_with_other_type.rs:25:40 | LL | type Baa<'a> = &'a ::Bar<'a, 'static>; @@ -24,4 +24,4 @@ LL | type Baa<'a> = &'a ::Bar<'a, 'static>; error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0110`. +For more information about this error, try `rustc --explain E0109`. diff --git a/src/test/ui/rfc1598-generic-associated-types/gat-dont-ice-on-absent-feature.rs b/src/test/ui/rfc1598-generic-associated-types/gat-dont-ice-on-absent-feature.rs new file mode 100644 index 0000000000000..84fbb47301f04 --- /dev/null +++ b/src/test/ui/rfc1598-generic-associated-types/gat-dont-ice-on-absent-feature.rs @@ -0,0 +1,14 @@ +// rust-lang/rust#60654: Do not ICE on an attempt to use GATs that is +// missing the feature gate. + +struct Foo; + +impl Iterator for Foo { + type Item<'b> = &'b Foo; //~ ERROR generic associated types are unstable [E0658] + + fn next(&mut self) -> Option { + None + } +} + +fn main() { } diff --git a/src/test/ui/rfc1598-generic-associated-types/gat-dont-ice-on-absent-feature.stderr b/src/test/ui/rfc1598-generic-associated-types/gat-dont-ice-on-absent-feature.stderr new file mode 100644 index 0000000000000..27b1d73d0434a --- /dev/null +++ b/src/test/ui/rfc1598-generic-associated-types/gat-dont-ice-on-absent-feature.stderr @@ -0,0 +1,12 @@ +error[E0658]: generic associated types are unstable + --> $DIR/gat-dont-ice-on-absent-feature.rs:7:5 + | +LL | type Item<'b> = &'b Foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 + = help: add #![feature(generic_associated_types)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc1598-generic-associated-types/generic-associated-types-where.rs b/src/test/ui/rfc1598-generic-associated-types/generic-associated-types-where.rs index b0d1fa1a74fb5..01daf307c0068 100644 --- a/src/test/ui/rfc1598-generic-associated-types/generic-associated-types-where.rs +++ b/src/test/ui/rfc1598-generic-associated-types/generic-associated-types-where.rs @@ -9,7 +9,7 @@ trait Foo { type Assoc where Self: Sized; type Assoc2 where T: Display; type Assoc3; - type WithDefault where T: Debug = Iterator; + type WithDefault where T: Debug = dyn Iterator; type NoGenerics; } @@ -19,7 +19,7 @@ impl Foo for Bar { type Assoc = usize; type Assoc2 = Vec; type Assoc3 where T: Iterator = Vec; - type WithDefault<'a, T> = &'a Iterator; + type WithDefault<'a, T> = &'a dyn Iterator; type NoGenerics = ::std::cell::Cell; } diff --git a/src/test/ui/rfc1598-generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/rfc1598-generic-associated-types/generic-associated-types-where.stderr index 5aa34bca13011..b323104048f66 100644 --- a/src/test/ui/rfc1598-generic-associated-types/generic-associated-types-where.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/generic-associated-types-where.stderr @@ -1,6 +1,6 @@ warning: the feature `generic_associated_types` is incomplete and may cause the compiler to crash --> $DIR/generic-associated-types-where.rs:1:12 | -LL | #![feature(generic_associated_types)] //~ WARN `generic_associated_types` is incomplete +LL | #![feature(generic_associated_types)] | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc1598-generic-associated-types/generic_associated_type_undeclared_lifetimes.rs b/src/test/ui/rfc1598-generic-associated-types/generic_associated_type_undeclared_lifetimes.rs index 2e6d7470b49a2..150899a034b86 100644 --- a/src/test/ui/rfc1598-generic-associated-types/generic_associated_type_undeclared_lifetimes.rs +++ b/src/test/ui/rfc1598-generic-associated-types/generic_associated_type_undeclared_lifetimes.rs @@ -3,20 +3,20 @@ use std::ops::Deref; -// FIXME(#44265): "lifetime arguments are not allowed on this entity" errors will be addressed in a +// FIXME(#44265): "lifetime arguments are not allowed for this type" errors will be addressed in a // follow-up PR. trait Iterable { type Item<'a>; type Iter<'a>: Iterator> - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] + Deref>; //~^ ERROR undeclared lifetime - //~| ERROR lifetime arguments are not allowed on this entity [E0110] + //~| ERROR lifetime arguments are not allowed for this type [E0109] fn iter<'a>(&'a self) -> Self::Iter<'undeclared>; //~^ ERROR undeclared lifetime - //~| ERROR lifetime arguments are not allowed on this entity [E0110] + //~| ERROR lifetime arguments are not allowed for this type [E0109] } fn main() {} diff --git a/src/test/ui/rfc1598-generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr b/src/test/ui/rfc1598-generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr index 3cebab6389557..f8c0a1f3bff34 100644 --- a/src/test/ui/rfc1598-generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr @@ -16,19 +16,19 @@ error[E0261]: use of undeclared lifetime name `'undeclared` LL | fn iter<'a>(&'a self) -> Self::Iter<'undeclared>; | ^^^^^^^^^^^ undeclared lifetime -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/generic_associated_type_undeclared_lifetimes.rs:11:47 | LL | type Iter<'a>: Iterator> | ^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/generic_associated_type_undeclared_lifetimes.rs:13:37 | LL | + Deref>; | ^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/generic_associated_type_undeclared_lifetimes.rs:17:41 | LL | fn iter<'a>(&'a self) -> Self::Iter<'undeclared>; @@ -36,5 +36,5 @@ LL | fn iter<'a>(&'a self) -> Self::Iter<'undeclared>; error: aborting due to 5 previous errors -Some errors occurred: E0110, E0261. -For more information about an error, try `rustc --explain E0110`. +Some errors have detailed explanations: E0109, E0261. +For more information about an error, try `rustc --explain E0109`. diff --git a/src/test/ui/rfc1598-generic-associated-types/iterable.rs b/src/test/ui/rfc1598-generic-associated-types/iterable.rs index 69258506651c4..29953b9db1a31 100644 --- a/src/test/ui/rfc1598-generic-associated-types/iterable.rs +++ b/src/test/ui/rfc1598-generic-associated-types/iterable.rs @@ -3,16 +3,16 @@ use std::ops::Deref; -// FIXME(#44265): "lifetime arguments are not allowed on this entity" errors will be addressed in a +// FIXME(#44265): "lifetime arguments are not allowed for this type" errors will be addressed in a // follow-up PR. trait Iterable { type Item<'a>; type Iter<'a>: Iterator>; - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] fn iter<'a>(&'a self) -> Self::Iter<'a>; - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] } // Impl for struct type @@ -21,7 +21,7 @@ impl Iterable for Vec { type Iter<'a> = std::slice::Iter<'a, T>; fn iter<'a>(&'a self) -> Self::Iter<'a> { - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] self.iter() } } @@ -32,18 +32,18 @@ impl Iterable for [T] { type Iter<'a> = std::slice::Iter<'a, T>; fn iter<'a>(&'a self) -> Self::Iter<'a> { - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] self.iter() } } fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> { - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] it.iter() } fn get_first<'a, I: Iterable>(it: &'a I) -> Option> { - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] it.iter().next() } diff --git a/src/test/ui/rfc1598-generic-associated-types/iterable.stderr b/src/test/ui/rfc1598-generic-associated-types/iterable.stderr index cc3ade6f39d90..6d5d0cc382840 100644 --- a/src/test/ui/rfc1598-generic-associated-types/iterable.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/iterable.stderr @@ -4,37 +4,37 @@ warning: the feature `generic_associated_types` is incomplete and may cause the LL | #![feature(generic_associated_types)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/iterable.rs:11:47 | LL | type Iter<'a>: Iterator>; | ^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/iterable.rs:40:53 | LL | fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> { | ^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/iterable.rs:45:60 | LL | fn get_first<'a, I: Iterable>(it: &'a I) -> Option> { | ^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/iterable.rs:14:41 | LL | fn iter<'a>(&'a self) -> Self::Iter<'a>; | ^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/iterable.rs:23:41 | LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { | ^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/iterable.rs:34:41 | LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { @@ -42,4 +42,4 @@ LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0110`. +For more information about this error, try `rustc --explain E0109`. diff --git a/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.rs b/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.rs index 851e331a0e965..aa3f4b186da83 100644 --- a/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.rs +++ b/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.rs @@ -2,7 +2,7 @@ //~^ WARNING the feature `generic_associated_types` is incomplete #![feature(associated_type_defaults)] -// FIXME(#44265): "lifetime arguments are not allowed on this entity" errors will be addressed in a +// FIXME(#44265): "lifetime arguments are not allowed for this type" errors will be addressed in a // follow-up PR. // FIXME(#44265): Update expected errors once E110 is resolved, now does not get past `trait Foo`. @@ -15,13 +15,13 @@ trait Foo { type E<'a, T>; // Test parameters in default values type FOk = Self::E<'static, T>; - //~^ ERROR type arguments are not allowed on this entity [E0109] - //~| ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR type arguments are not allowed for this type [E0109] + //~| ERROR lifetime arguments are not allowed for this type [E0109] type FErr1 = Self::E<'static, 'static>; // Error - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] type FErr2 = Self::E<'static, T, u32>; // Error - //~^ ERROR type arguments are not allowed on this entity [E0109] - //~| ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR type arguments are not allowed for this type [E0109] + //~| ERROR lifetime arguments are not allowed for this type [E0109] } struct Fooy; diff --git a/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr b/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr index 265b0fab77061..817d911184d0a 100644 --- a/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr @@ -4,31 +4,31 @@ warning: the feature `generic_associated_types` is incomplete and may cause the LL | #![feature(generic_associated_types)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/parameter_number_and_kind.rs:17:27 | LL | type FOk = Self::E<'static, T>; | ^^^^^^^ lifetime argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/parameter_number_and_kind.rs:17:36 | LL | type FOk = Self::E<'static, T>; | ^ type argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/parameter_number_and_kind.rs:20:26 | LL | type FErr1 = Self::E<'static, 'static>; // Error | ^^^^^^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/parameter_number_and_kind.rs:22:29 | LL | type FErr2 = Self::E<'static, T, u32>; // Error | ^^^^^^^ lifetime argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/parameter_number_and_kind.rs:22:38 | LL | type FErr2 = Self::E<'static, T, u32>; // Error @@ -36,5 +36,4 @@ LL | type FErr2 = Self::E<'static, T, u32>; // Error error: aborting due to 5 previous errors -Some errors occurred: E0109, E0110. -For more information about an error, try `rustc --explain E0109`. +For more information about this error, try `rustc --explain E0109`. diff --git a/src/test/ui/rfc1598-generic-associated-types/pointer_family.rs b/src/test/ui/rfc1598-generic-associated-types/pointer_family.rs index 2d188aed42778..edeeaba756549 100644 --- a/src/test/ui/rfc1598-generic-associated-types/pointer_family.rs +++ b/src/test/ui/rfc1598-generic-associated-types/pointer_family.rs @@ -10,7 +10,7 @@ use std::ops::Deref; trait PointerFamily { type Pointer: Deref; fn new(value: T) -> Self::Pointer; - //~^ ERROR type arguments are not allowed on this entity [E0109] + //~^ ERROR type arguments are not allowed for this type [E0109] } struct ArcFamily; @@ -18,7 +18,7 @@ struct ArcFamily; impl PointerFamily for ArcFamily { type Pointer = Arc; fn new(value: T) -> Self::Pointer { - //~^ ERROR type arguments are not allowed on this entity [E0109] + //~^ ERROR type arguments are not allowed for this type [E0109] Arc::new(value) } } @@ -28,14 +28,14 @@ struct RcFamily; impl PointerFamily for RcFamily { type Pointer = Rc; fn new(value: T) -> Self::Pointer { - //~^ ERROR type arguments are not allowed on this entity [E0109] + //~^ ERROR type arguments are not allowed for this type [E0109] Rc::new(value) } } struct Foo { bar: P::Pointer, - //~^ ERROR type arguments are not allowed on this entity [E0109] + //~^ ERROR type arguments are not allowed for this type [E0109] } fn main() {} diff --git a/src/test/ui/rfc1598-generic-associated-types/pointer_family.stderr b/src/test/ui/rfc1598-generic-associated-types/pointer_family.stderr index 2b9eed2a688a2..0966f8f9422aa 100644 --- a/src/test/ui/rfc1598-generic-associated-types/pointer_family.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/pointer_family.stderr @@ -4,25 +4,25 @@ warning: the feature `generic_associated_types` is incomplete and may cause the LL | #![feature(generic_associated_types)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/pointer_family.rs:37:21 | LL | bar: P::Pointer, | ^^^^^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/pointer_family.rs:12:42 | LL | fn new(value: T) -> Self::Pointer; | ^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/pointer_family.rs:20:42 | LL | fn new(value: T) -> Self::Pointer { | ^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/pointer_family.rs:30:42 | LL | fn new(value: T) -> Self::Pointer { diff --git a/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.rs b/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.rs index e0184164b3ac2..4e177fb41d732 100644 --- a/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.rs +++ b/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.rs @@ -10,13 +10,13 @@ trait StreamingIterator { type Item<'a>; // Applying the lifetime parameter `'a` to `Self::Item` inside the trait. fn next<'a>(&'a self) -> Option>; - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] } struct Foo { // Applying a concrete lifetime to the constructor outside the trait. bar: ::Item<'static>, - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] } // Users can bound parameters by the type constructed by that trait's associated type constructor @@ -24,7 +24,7 @@ struct Foo { //FIXME(sunjay): This next line should parse and be valid //fn foo StreamingIterator=&'a [i32]>>(iter: T) { /* ... */ } fn foo(iter: T) where T: StreamingIterator, for<'a> T::Item<'a>: Display { /* ... */ } -//~^ ERROR lifetime arguments are not allowed on this entity [E0110] +//~^ ERROR lifetime arguments are not allowed for this type [E0109] // Full example of enumerate iterator @@ -36,9 +36,9 @@ struct StreamEnumerate { impl StreamingIterator for StreamEnumerate { type Item<'a> = (usize, I::Item<'a>); - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] fn next<'a>(&'a self) -> Option> { - //~^ ERROR lifetime arguments are not allowed on this entity [E0110] + //~^ ERROR lifetime arguments are not allowed for this type [E0109] match self.iter.next() { None => None, Some(val) => { diff --git a/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr b/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr index 5afbba5d2d744..5fc1e3dddbe74 100644 --- a/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr @@ -4,31 +4,31 @@ warning: the feature `generic_associated_types` is incomplete and may cause the LL | #![feature(generic_associated_types)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/streaming_iterator.rs:18:41 | LL | bar: ::Item<'static>, | ^^^^^^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/streaming_iterator.rs:26:64 | LL | fn foo(iter: T) where T: StreamingIterator, for<'a> T::Item<'a>: Display { /* ... */ } | ^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/streaming_iterator.rs:12:48 | LL | fn next<'a>(&'a self) -> Option>; | ^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/streaming_iterator.rs:38:37 | LL | type Item<'a> = (usize, I::Item<'a>); | ^^ lifetime argument not allowed -error[E0110]: lifetime arguments are not allowed on this entity +error[E0109]: lifetime arguments are not allowed for this type --> $DIR/streaming_iterator.rs:40:48 | LL | fn next<'a>(&'a self) -> Option> { @@ -36,4 +36,4 @@ LL | fn next<'a>(&'a self) -> Option> { error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0110`. +For more information about this error, try `rustc --explain E0109`. diff --git a/src/test/ui/rfc1623.rs b/src/test/ui/rfc1623.rs index 5920446dbc2e2..ebb4d56af9eec 100644 --- a/src/test/ui/rfc1623.rs +++ b/src/test/ui/rfc1623.rs @@ -13,7 +13,7 @@ static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = struct SomeStruct<'x, 'y, 'z: 'x> { foo: &'x Foo<'z>, bar: &'x Bar<'z>, - f: &'y for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Bar<'b>, + f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Bar<'b>, } fn id(t: T) -> T { diff --git a/src/test/ui/rmeta-lib-pass.rs b/src/test/ui/rmeta-lib-pass.rs index 6149b1685f5c7..4ab4117dd6ccd 100644 --- a/src/test/ui/rmeta-lib-pass.rs +++ b/src/test/ui/rmeta-lib-pass.rs @@ -1,5 +1,5 @@ // compile-flags: --emit=metadata -// aux-build:rmeta_rlib.rs +// aux-build:rmeta-rlib.rs // no-prefer-dynamic // compile-pass diff --git a/src/test/ui/rmeta-pass.rs b/src/test/ui/rmeta-pass.rs index bcd40144f7216..9c88de7a0330b 100644 --- a/src/test/ui/rmeta-pass.rs +++ b/src/test/ui/rmeta-pass.rs @@ -1,5 +1,5 @@ // compile-flags: --emit=metadata -// aux-build:rmeta_meta.rs +// aux-build:rmeta-meta.rs // no-prefer-dynamic // compile-pass diff --git a/src/test/ui/rmeta.stderr b/src/test/ui/rmeta.stderr index d36b3a746e6a7..d15caeb669811 100644 --- a/src/test/ui/rmeta.stderr +++ b/src/test/ui/rmeta.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `Foo` in this scope --> $DIR/rmeta.rs:7:13 | -LL | let _ = Foo; //~ ERROR cannot find value `Foo` in this scope +LL | let _ = Foo; | ^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/rmeta_lib.rs b/src/test/ui/rmeta_lib.rs index 345b712e37e47..6c74aec32e30b 100644 --- a/src/test/ui/rmeta_lib.rs +++ b/src/test/ui/rmeta_lib.rs @@ -1,4 +1,4 @@ -// aux-build:rmeta_meta.rs +// aux-build:rmeta-meta.rs // no-prefer-dynamic // error-pattern: crate `rmeta_meta` required to be available in rlib format, but was not found diff --git a/src/test/ui/rmeta_meta_main.rs b/src/test/ui/rmeta_meta_main.rs index df550775ee465..52cd0c2f53fad 100644 --- a/src/test/ui/rmeta_meta_main.rs +++ b/src/test/ui/rmeta_meta_main.rs @@ -1,5 +1,5 @@ // compile-flags: --emit=metadata -// aux-build:rmeta_meta.rs +// aux-build:rmeta-meta.rs // no-prefer-dynamic // Check that building a metadata crate finds an error with a dependent, diff --git a/src/test/ui/rmeta_meta_main.stderr b/src/test/ui/rmeta_meta_main.stderr index bed9076d84cbe..347e5e97d7a06 100644 --- a/src/test/ui/rmeta_meta_main.stderr +++ b/src/test/ui/rmeta_meta_main.stderr @@ -1,7 +1,7 @@ error[E0560]: struct `rmeta_meta::Foo` has no field named `field2` --> $DIR/rmeta_meta_main.rs:13:19 | -LL | let _ = Foo { field2: 42 }; //~ ERROR struct `rmeta_meta::Foo` has no field named `field2` +LL | let _ = Foo { field2: 42 }; | ^^^^^^ help: a field with a similar name exists: `field` error: aborting due to previous error diff --git a/src/test/ui/rust-2018/async-ident-allowed.stderr b/src/test/ui/rust-2018/async-ident-allowed.stderr index 61e1facd30e5d..d3e450e9be0b5 100644 --- a/src/test/ui/rust-2018/async-ident-allowed.stderr +++ b/src/test/ui/rust-2018/async-ident-allowed.stderr @@ -1,7 +1,7 @@ error: `async` is a keyword in the 2018 edition --> $DIR/async-ident-allowed.rs:9:9 | -LL | let async = 3; //~ ERROR: is a keyword +LL | let async = 3; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | note: lint level defined here diff --git a/src/test/ui/rust-2018/async-ident.stderr b/src/test/ui/rust-2018/async-ident.stderr index b33c043c9ea25..b149533775633 100644 --- a/src/test/ui/rust-2018/async-ident.stderr +++ b/src/test/ui/rust-2018/async-ident.stderr @@ -1,7 +1,7 @@ error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:7:4 | -LL | fn async() {} //~ ERROR async +LL | fn async() {} | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` | note: lint level defined here diff --git a/src/test/ui/rust-2018/dyn-keyword.stderr b/src/test/ui/rust-2018/dyn-keyword.stderr index 5a3e00ab1d96a..fa79df49fb665 100644 --- a/src/test/ui/rust-2018/dyn-keyword.stderr +++ b/src/test/ui/rust-2018/dyn-keyword.stderr @@ -1,7 +1,7 @@ error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-keyword.rs:8:9 | -LL | let dyn = (); //~ ERROR dyn +LL | let dyn = (); | ^^^ help: you can use a raw identifier to stay compatible: `r#dyn` | note: lint level defined here diff --git a/src/test/ui/rust-2018/dyn-trait-compatibility.stderr b/src/test/ui/rust-2018/dyn-trait-compatibility.stderr index 6be0052046583..e1f099e91907b 100644 --- a/src/test/ui/rust-2018/dyn-trait-compatibility.stderr +++ b/src/test/ui/rust-2018/dyn-trait-compatibility.stderr @@ -1,17 +1,17 @@ error: expected identifier, found keyword `dyn` --> $DIR/dyn-trait-compatibility.rs:4:16 | -LL | type A1 = dyn::dyn; //~ERROR expected identifier, found keyword `dyn` +LL | type A1 = dyn::dyn; | ^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | -LL | type A1 = dyn::r#dyn; //~ERROR expected identifier, found keyword `dyn` +LL | type A1 = dyn::r#dyn; | ^^^^^ error: expected identifier, found `<` --> $DIR/dyn-trait-compatibility.rs:5:14 | -LL | type A2 = dyn; //~ERROR expected identifier, found `<` +LL | type A2 = dyn; | ^ expected identifier error: aborting due to 2 previous errors diff --git a/src/test/ui/rust-2018/edition-lint-infer-outlives-multispan.rs b/src/test/ui/rust-2018/edition-lint-infer-outlives-multispan.rs index ca6abdf5e700a..0b3de0df2b884 100644 --- a/src/test/ui/rust-2018/edition-lint-infer-outlives-multispan.rs +++ b/src/test/ui/rust-2018/edition-lint-infer-outlives-multispan.rs @@ -1,75 +1,368 @@ #![allow(unused)] #![deny(explicit_outlives_requirements)] -use std::fmt::{Debug, Display}; // These examples should live in edition-lint-infer-outlives.rs, but are split // into this separate file because they can't be `rustfix`'d (and thus, can't // be part of a `run-rustfix` test file) until rust-lang-nursery/rustfix#141 // is solved -struct TeeOutlivesAyIsDebugBee<'a, 'b, T: 'a + Debug + 'b> { - //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T +mod structs { + use std::fmt::Debug; + + struct TeeOutlivesAyIsDebugBee<'a, 'b, T: 'a + Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: 'a + Debug + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: 'a + Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeOutlivesAyYooBeeIsDebug<'a, 'b, T: 'a, U: 'b + Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + struct TeeOutlivesAyYooIsDebugBee<'a, 'b, T: 'a, U: Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + struct TeeOutlivesAyYooWhereBee<'a, 'b, T: 'a, U> where U: 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + struct TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: 'a + Debug + 'b { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T: 'a, U> where U: 'b + Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + struct TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T: 'a, U> where U: Debug + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + struct TeeWhereOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where T: 'a, U: 'b + Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + struct TeeWhereOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where T: 'a, U: Debug + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + struct BeeOutlivesAyTeeBee<'a, 'b: 'a, T: 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + struct BeeOutlivesAyTeeAyBee<'a, 'b: 'a, T: 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + struct BeeOutlivesAyTeeOutlivesAyIsDebugBee<'a, 'b: 'a, T: 'a + Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct BeeWhereAyTeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where 'b: 'a, T: 'a + Debug + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct BeeOutlivesAyTeeYooOutlivesAyIsDebugBee<'a, 'b: 'a, T, U: 'a + Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct BeeWhereAyTeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> + where U: 'a + Debug + 'b, 'b: 'a + //~^ ERROR outlives requirements can be inferred + { + tee: T, + yoo: &'a &'b U + } } -struct TeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: 'a + Debug + 'b { +mod tuple_structs { + use std::fmt::Debug; + + struct TeeOutlivesAyIsDebugBee<'a, 'b, T: 'a + Debug + 'b>(&'a &'b T); //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T -} -struct TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: 'a + Debug + 'b> { + struct TeeWhereOutlivesAyIsDebugBee<'a, 'b, T>(&'a &'b T) where T: 'a + Debug + 'b; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeOutlivesAyYooBeeIsDebug<'a, 'b, T: 'a, U: 'b + Debug> { + struct TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: 'a + Debug + 'b>(T, &'a &'b U); //~^ ERROR outlives requirements can be inferred - tee: &'a T, - yoo: &'b U -} -struct TeeOutlivesAyYooIsDebugBee<'a, 'b, T: 'a, U: Debug + 'b> { + struct TeeOutlivesAyYooBeeIsDebug<'a, 'b, T: 'a, U: 'b + Debug>(&'a T, &'b U); //~^ ERROR outlives requirements can be inferred - tee: &'a T, - yoo: &'b U -} -struct TeeOutlivesAyYooWhereBee<'a, 'b, T: 'a, U> where U: 'b { + struct TeeOutlivesAyYooIsDebugBee<'a, 'b, T: 'a, U: Debug + 'b>(&'a T, &'b U); //~^ ERROR outlives requirements can be inferred - tee: &'a T, - yoo: &'b U -} -struct TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: 'a + Debug + 'b { + struct TeeOutlivesAyYooWhereBee<'a, 'b, T: 'a, U>(&'a T, &'b U) where U: 'b; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T: 'a, U> where U: 'b + Debug { + struct TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U>(T, &'a &'b U) where U: 'a + Debug + 'b; //~^ ERROR outlives requirements can be inferred - tee: &'a T, - yoo: &'b U -} -struct TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T: 'a, U> where U: Debug + 'b { + struct TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T: 'a, U>(&'a T, &'b U) where U: 'b + Debug; //~^ ERROR outlives requirements can be inferred - tee: &'a T, - yoo: &'b U -} -struct TeeWhereOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where T: 'a, U: 'b + Debug { + struct TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T: 'a, U>(&'a T, &'b U) where U: Debug + 'b; + //~^ ERROR outlives requirements can be inferred + + struct TeeWhereAyYooWhereBeeIsDebug<'a, 'b, T, U>(&'a T, &'b U) where T: 'a, U: 'b + Debug; + //~^ ERROR outlives requirements can be inferred + + struct TeeWhereAyYooWhereIsDebugBee<'a, 'b, T, U>(&'a T, &'b U) where T: 'a, U: Debug + 'b; + //~^ ERROR outlives requirements can be inferred + + struct BeeOutlivesAyTeeBee<'a, 'b: 'a, T: 'b>(&'a &'b T); + //~^ ERROR outlives requirements can be inferred + + struct BeeOutlivesAyTeeAyBee<'a, 'b: 'a, T: 'a + 'b>(&'a &'b T); + //~^ ERROR outlives requirements can be inferred + + struct BeeOutlivesAyTeeOutlivesAyIsDebugBee<'a, 'b: 'a, T: 'a + Debug + 'b>(&'a &'b T); + //~^ ERROR outlives requirements can be inferred + + struct BeeWhereAyTeeWhereAyIsDebugBee<'a, 'b, T>(&'a &'b T) where 'b: 'a, T: 'a + Debug + 'b; //~^ ERROR outlives requirements can be inferred - tee: &'a T, - yoo: &'b U -} -struct TeeWhereOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where T: 'a, U: Debug + 'b { + struct BeeOutlivesAyTeeYooOutlivesAyIsDebugBee<'a, 'b: 'a, T, U: 'a + Debug + 'b>(T, &'a &'b U); //~^ ERROR outlives requirements can be inferred - tee: &'a T, - yoo: &'b U + + struct BeeWhereAyTeeYooWhereAyIsDebugBee<'a, 'b, T, U>(T, &'a &'b U) + where U: 'a + Debug + 'b, 'b: 'a; + //~^ ERROR outlives requirements can be inferred +} + +mod enums { + use std::fmt::Debug; + + enum TeeOutlivesAyIsDebugBee<'a, 'b, T: 'a + Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + } + + enum TeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: 'a + Debug + 'b { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + } + + enum TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: 'a + Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + V { tee: T, }, + W(&'a &'b U), + } + + enum TeeOutlivesAyYooBeeIsDebug<'a, 'b, T: 'a, U: 'b + Debug> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T, yoo: &'b U }, + W, + } + + enum TeeOutlivesAyYooIsDebugBee<'a, 'b, T: 'a, U: Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + V(&'a T, &'b U), + W, + } + + enum TeeOutlivesAyYooWhereBee<'a, 'b, T: 'a, U> where U: 'b { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + W(&'b U), + } + + enum TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: 'a + Debug + 'b { + //~^ ERROR outlives requirements can be inferred + V { tee: T, yoo: &'a &'b U }, + W, + } + + enum TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T: 'a, U> where U: 'b + Debug { + //~^ ERROR outlives requirements can be inferred + V(&'a T, &'b U), + W, + } + + enum TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T: 'a, U> where U: Debug + 'b { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + W(&'b U) + } + + enum TeeWhereOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where T: 'a, U: 'b + Debug { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T, yoo: &'b U }, + W, + } + + enum TeeWhereOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where T: 'a, U: Debug + 'b { + //~^ ERROR outlives requirements can be inferred + V(&'a T, &'b U), + W, + } + + enum BeeOutlivesAyTeeBee<'a, 'b: 'a, T: 'b> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + } + + enum BeeOutlivesAyTeeAyBee<'a, 'b: 'a, T: 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + W, + } + + enum BeeOutlivesAyTeeOutlivesAyIsDebugBee<'a, 'b: 'a, T: 'a + Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + } + + enum BeeWhereAyTeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where 'b: 'a, T: 'a + Debug + 'b { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + } + + enum BeeOutlivesAyTeeYooOutlivesAyIsDebugBee<'a, 'b: 'a, T, U: 'a + Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + V { tee: T }, + W(&'a &'b U), + } + + enum BeeWhereAyTeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: 'a + Debug + 'b, 'b: 'a { + //~^ ERROR outlives requirements can be inferred + V { tee: T, yoo: &'a &'b U }, + } +} + +mod unions { + use std::fmt::Debug; + + union TeeOutlivesAyIsDebugBee<'a, 'b, T: 'a + Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: 'a + Debug + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: 'a + Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeOutlivesAyYooBeeIsDebug<'a, 'b, T: 'a, U: 'b + Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + union TeeOutlivesAyYooIsDebugBee<'a, 'b, T: 'a, U: Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + union TeeOutlivesAyYooWhereBee<'a, 'b, T: 'a, U> where U: 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + union TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: 'a + Debug + 'b { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T: 'a, U> where U: 'b + Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + union TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T: 'a, U> where U: Debug + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + union TeeWhereOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where T: 'a, U: 'b + Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + union TeeWhereOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where T: 'a, U: Debug + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: &'b U + } + + union BeeOutlivesAyTeeBee<'a, 'b: 'a, T: 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + union BeeOutlivesAyTeeAyBee<'a, 'b: 'a, T: 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + union BeeOutlivesAyTeeOutlivesAyIsDebugBee<'a, 'b: 'a, T: 'a + Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union BeeWhereAyTeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where 'b: 'a, T: 'a + Debug + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union BeeOutlivesAyTeeYooOutlivesAyIsDebugBee<'a, 'b: 'a, T, U: 'a + Debug + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union BeeWhereAyTeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: 'a + Debug + 'b, 'b: 'a { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } } fn main() {} diff --git a/src/test/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr b/src/test/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr index 3c65dde01624e..e0e846422d3ce 100644 --- a/src/test/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr +++ b/src/test/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr @@ -1,8 +1,8 @@ error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives-multispan.rs:11:43 + --> $DIR/edition-lint-infer-outlives-multispan.rs:13:47 | -LL | struct TeeOutlivesAyIsDebugBee<'a, 'b, T: 'a + Debug + 'b> { - | ^^^^^ ^^^^^ +LL | struct TeeOutlivesAyIsDebugBee<'a, 'b, T: 'a + Debug + 'b> { + | ^^^^^ ^^^^^ | note: lint level defined here --> $DIR/edition-lint-infer-outlives-multispan.rs:2:9 @@ -11,108 +11,678 @@ LL | #![deny(explicit_outlives_requirements)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these bounds | -LL | struct TeeOutlivesAyIsDebugBee<'a, 'b, T: Debug> { - | -- -- +LL | struct TeeOutlivesAyIsDebugBee<'a, 'b, T: Debug> { + | -- -- error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives-multispan.rs:16:57 + --> $DIR/edition-lint-infer-outlives-multispan.rs:18:61 | -LL | struct TeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: 'a + Debug + 'b { - | ^^^^^ ^^^^^ +LL | struct TeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: 'a + Debug + 'b { + | ^^^^^ ^^^^^ help: remove these bounds | -LL | struct TeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: Debug { - | -- -- +LL | struct TeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: Debug { + | -- -- error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives-multispan.rs:21:49 + --> $DIR/edition-lint-infer-outlives-multispan.rs:23:53 | -LL | struct TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: 'a + Debug + 'b> { - | ^^^^^ ^^^^^ +LL | struct TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: 'a + Debug + 'b> { + | ^^^^^ ^^^^^ help: remove these bounds | -LL | struct TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: Debug> { - | -- -- +LL | struct TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: Debug> { + | -- -- error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives-multispan.rs:27:44 + --> $DIR/edition-lint-infer-outlives-multispan.rs:29:48 | -LL | struct TeeOutlivesAyYooBeeIsDebug<'a, 'b, T: 'a, U: 'b + Debug> { - | ^^^^ ^^^^^ +LL | struct TeeOutlivesAyYooBeeIsDebug<'a, 'b, T: 'a, U: 'b + Debug> { + | ^^^^ ^^^^^ help: remove these bounds | -LL | struct TeeOutlivesAyYooBeeIsDebug<'a, 'b, T, U: Debug> { - | -- -- +LL | struct TeeOutlivesAyYooBeeIsDebug<'a, 'b, T, U: Debug> { + | -- -- error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives-multispan.rs:33:44 + --> $DIR/edition-lint-infer-outlives-multispan.rs:35:48 | -LL | struct TeeOutlivesAyYooIsDebugBee<'a, 'b, T: 'a, U: Debug + 'b> { - | ^^^^ ^^^^^ +LL | struct TeeOutlivesAyYooIsDebugBee<'a, 'b, T: 'a, U: Debug + 'b> { + | ^^^^ ^^^^^ help: remove these bounds | -LL | struct TeeOutlivesAyYooIsDebugBee<'a, 'b, T, U: Debug> { - | -- -- +LL | struct TeeOutlivesAyYooIsDebugBee<'a, 'b, T, U: Debug> { + | -- -- error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives-multispan.rs:39:42 + --> $DIR/edition-lint-infer-outlives-multispan.rs:41:46 | -LL | struct TeeOutlivesAyYooWhereBee<'a, 'b, T: 'a, U> where U: 'b { - | ^^^^ ^^^^^^^^^^^^ +LL | struct TeeOutlivesAyYooWhereBee<'a, 'b, T: 'a, U> where U: 'b { + | ^^^^ ^^^^^^^^^^^^ help: remove these bounds | -LL | struct TeeOutlivesAyYooWhereBee<'a, 'b, T, U> { - | -- -- +LL | struct TeeOutlivesAyYooWhereBee<'a, 'b, T, U> { + | -- -- error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives-multispan.rs:45:63 + --> $DIR/edition-lint-infer-outlives-multispan.rs:47:67 | -LL | struct TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: 'a + Debug + 'b { - | ^^^^^ ^^^^^ +LL | struct TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: 'a + Debug + 'b { + | ^^^^^ ^^^^^ help: remove these bounds | -LL | struct TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: Debug { - | -- -- +LL | struct TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: Debug { + | -- -- error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives-multispan.rs:51:49 + --> $DIR/edition-lint-infer-outlives-multispan.rs:53:53 | -LL | struct TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T: 'a, U> where U: 'b + Debug { - | ^^^^ ^^^^^ +LL | struct TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T: 'a, U> where U: 'b + Debug { + | ^^^^ ^^^^^ help: remove these bounds | -LL | struct TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where U: Debug { - | -- -- +LL | struct TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where U: Debug { + | -- -- error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives-multispan.rs:57:49 + --> $DIR/edition-lint-infer-outlives-multispan.rs:59:53 | -LL | struct TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T: 'a, U> where U: Debug + 'b { - | ^^^^ ^^^^^ +LL | struct TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T: 'a, U> where U: Debug + 'b { + | ^^^^ ^^^^^ help: remove these bounds | -LL | struct TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where U: Debug { - | -- -- +LL | struct TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where U: Debug { + | -- -- error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives-multispan.rs:63:65 + --> $DIR/edition-lint-infer-outlives-multispan.rs:65:69 | -LL | struct TeeWhereOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where T: 'a, U: 'b + Debug { - | ^^^^^^^ ^^^^^ +LL | struct TeeWhereOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where T: 'a, U: 'b + Debug { + | ^^^^^^^ ^^^^^ help: remove these bounds | -LL | struct TeeWhereOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where U: Debug { - | -- -- +LL | struct TeeWhereOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where U: Debug { + | -- -- error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives-multispan.rs:69:65 + --> $DIR/edition-lint-infer-outlives-multispan.rs:71:69 | -LL | struct TeeWhereOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where T: 'a, U: Debug + 'b { - | ^^^^^^^ ^^^^^ +LL | struct TeeWhereOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where T: 'a, U: Debug + 'b { + | ^^^^^^^ ^^^^^ help: remove these bounds | -LL | struct TeeWhereOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where U: Debug { - | -- -- +LL | struct TeeWhereOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where U: Debug { + | -- -- -error: aborting due to 11 previous errors +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:77:38 + | +LL | struct BeeOutlivesAyTeeBee<'a, 'b: 'a, T: 'b> { + | ^^^^ ^^^^ +help: remove these bounds + | +LL | struct BeeOutlivesAyTeeBee<'a, 'b, T> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:82:40 + | +LL | struct BeeOutlivesAyTeeAyBee<'a, 'b: 'a, T: 'a + 'b> { + | ^^^^ ^^^^^^^^^ +help: remove these bounds + | +LL | struct BeeOutlivesAyTeeAyBee<'a, 'b, T> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:87:55 + | +LL | struct BeeOutlivesAyTeeOutlivesAyIsDebugBee<'a, 'b: 'a, T: 'a + Debug + 'b> { + | ^^^^ ^^^^^ ^^^^^ +help: remove these bounds + | +LL | struct BeeOutlivesAyTeeOutlivesAyIsDebugBee<'a, 'b, T: Debug> { + | -- -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:92:68 + | +LL | struct BeeWhereAyTeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where 'b: 'a, T: 'a + Debug + 'b { + | ^^^^^^^^ ^^^^^ ^^^^^ +help: remove these bounds + | +LL | struct BeeWhereAyTeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: Debug { + | -- -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:97:58 + | +LL | struct BeeOutlivesAyTeeYooOutlivesAyIsDebugBee<'a, 'b: 'a, T, U: 'a + Debug + 'b> { + | ^^^^ ^^^^^ ^^^^^ +help: remove these bounds + | +LL | struct BeeOutlivesAyTeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: Debug> { + | -- -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:104:18 + | +LL | where U: 'a + Debug + 'b, 'b: 'a + | ^^^^^ ^^^^^ ^^^^^^ +help: remove these bounds + | +LL | where U: Debug, + | -- ---- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:115:47 + | +LL | struct TeeOutlivesAyIsDebugBee<'a, 'b, T: 'a + Debug + 'b>(&'a &'b T); + | ^^^^^ ^^^^^ +help: remove these bounds + | +LL | struct TeeOutlivesAyIsDebugBee<'a, 'b, T: Debug>(&'a &'b T); + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:118:72 + | +LL | struct TeeWhereOutlivesAyIsDebugBee<'a, 'b, T>(&'a &'b T) where T: 'a + Debug + 'b; + | ^^^^^ ^^^^^ +help: remove these bounds + | +LL | struct TeeWhereOutlivesAyIsDebugBee<'a, 'b, T>(&'a &'b T) where T: Debug; + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:121:53 + | +LL | struct TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: 'a + Debug + 'b>(T, &'a &'b U); + | ^^^^^ ^^^^^ +help: remove these bounds + | +LL | struct TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: Debug>(T, &'a &'b U); + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:124:48 + | +LL | struct TeeOutlivesAyYooBeeIsDebug<'a, 'b, T: 'a, U: 'b + Debug>(&'a T, &'b U); + | ^^^^ ^^^^^ +help: remove these bounds + | +LL | struct TeeOutlivesAyYooBeeIsDebug<'a, 'b, T, U: Debug>(&'a T, &'b U); + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:127:48 + | +LL | struct TeeOutlivesAyYooIsDebugBee<'a, 'b, T: 'a, U: Debug + 'b>(&'a T, &'b U); + | ^^^^ ^^^^^ +help: remove these bounds + | +LL | struct TeeOutlivesAyYooIsDebugBee<'a, 'b, T, U: Debug>(&'a T, &'b U); + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:130:46 + | +LL | struct TeeOutlivesAyYooWhereBee<'a, 'b, T: 'a, U>(&'a T, &'b U) where U: 'b; + | ^^^^ ^^^^^^^^^^^ +help: remove these bounds + | +LL | struct TeeOutlivesAyYooWhereBee<'a, 'b, T, U>(&'a T, &'b U) ; + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:133:81 + | +LL | struct TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U>(T, &'a &'b U) where U: 'a + Debug + 'b; + | ^^^^^ ^^^^^ +help: remove these bounds + | +LL | struct TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U>(T, &'a &'b U) where U: Debug; + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:136:53 + | +LL | struct TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T: 'a, U>(&'a T, &'b U) where U: 'b + Debug; + | ^^^^ ^^^^^ +help: remove these bounds + | +LL | struct TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U>(&'a T, &'b U) where U: Debug; + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:139:53 + | +LL | struct TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T: 'a, U>(&'a T, &'b U) where U: Debug + 'b; + | ^^^^ ^^^^^ +help: remove these bounds + | +LL | struct TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U>(&'a T, &'b U) where U: Debug; + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:142:75 + | +LL | struct TeeWhereAyYooWhereBeeIsDebug<'a, 'b, T, U>(&'a T, &'b U) where T: 'a, U: 'b + Debug; + | ^^^^^^^ ^^^^^ +help: remove these bounds + | +LL | struct TeeWhereAyYooWhereBeeIsDebug<'a, 'b, T, U>(&'a T, &'b U) where U: Debug; + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:145:75 + | +LL | struct TeeWhereAyYooWhereIsDebugBee<'a, 'b, T, U>(&'a T, &'b U) where T: 'a, U: Debug + 'b; + | ^^^^^^^ ^^^^^ +help: remove these bounds + | +LL | struct TeeWhereAyYooWhereIsDebugBee<'a, 'b, T, U>(&'a T, &'b U) where U: Debug; + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:148:38 + | +LL | struct BeeOutlivesAyTeeBee<'a, 'b: 'a, T: 'b>(&'a &'b T); + | ^^^^ ^^^^ +help: remove these bounds + | +LL | struct BeeOutlivesAyTeeBee<'a, 'b, T>(&'a &'b T); + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:151:40 + | +LL | struct BeeOutlivesAyTeeAyBee<'a, 'b: 'a, T: 'a + 'b>(&'a &'b T); + | ^^^^ ^^^^^^^^^ +help: remove these bounds + | +LL | struct BeeOutlivesAyTeeAyBee<'a, 'b, T>(&'a &'b T); + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:154:55 + | +LL | struct BeeOutlivesAyTeeOutlivesAyIsDebugBee<'a, 'b: 'a, T: 'a + Debug + 'b>(&'a &'b T); + | ^^^^ ^^^^^ ^^^^^ +help: remove these bounds + | +LL | struct BeeOutlivesAyTeeOutlivesAyIsDebugBee<'a, 'b, T: Debug>(&'a &'b T); + | -- -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:157:71 + | +LL | struct BeeWhereAyTeeWhereAyIsDebugBee<'a, 'b, T>(&'a &'b T) where 'b: 'a, T: 'a + Debug + 'b; + | ^^^^^^^^ ^^^^^ ^^^^^ +help: remove these bounds + | +LL | struct BeeWhereAyTeeWhereAyIsDebugBee<'a, 'b, T>(&'a &'b T) where T: Debug; + | -- -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:160:58 + | +LL | struct BeeOutlivesAyTeeYooOutlivesAyIsDebugBee<'a, 'b: 'a, T, U: 'a + Debug + 'b>(T, &'a &'b U); + | ^^^^ ^^^^^ ^^^^^ +help: remove these bounds + | +LL | struct BeeOutlivesAyTeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: Debug>(T, &'a &'b U); + | -- -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:164:18 + | +LL | where U: 'a + Debug + 'b, 'b: 'a; + | ^^^^^ ^^^^^ ^^^^^^ +help: remove these bounds + | +LL | where U: Debug, ; + | -- ---- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:171:45 + | +LL | enum TeeOutlivesAyIsDebugBee<'a, 'b, T: 'a + Debug + 'b> { + | ^^^^^ ^^^^^ +help: remove these bounds + | +LL | enum TeeOutlivesAyIsDebugBee<'a, 'b, T: Debug> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:176:59 + | +LL | enum TeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: 'a + Debug + 'b { + | ^^^^^ ^^^^^ +help: remove these bounds + | +LL | enum TeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: Debug { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:181:51 + | +LL | enum TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: 'a + Debug + 'b> { + | ^^^^^ ^^^^^ +help: remove these bounds + | +LL | enum TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: Debug> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:187:46 + | +LL | enum TeeOutlivesAyYooBeeIsDebug<'a, 'b, T: 'a, U: 'b + Debug> { + | ^^^^ ^^^^^ +help: remove these bounds + | +LL | enum TeeOutlivesAyYooBeeIsDebug<'a, 'b, T, U: Debug> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:193:46 + | +LL | enum TeeOutlivesAyYooIsDebugBee<'a, 'b, T: 'a, U: Debug + 'b> { + | ^^^^ ^^^^^ +help: remove these bounds + | +LL | enum TeeOutlivesAyYooIsDebugBee<'a, 'b, T, U: Debug> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:199:44 + | +LL | enum TeeOutlivesAyYooWhereBee<'a, 'b, T: 'a, U> where U: 'b { + | ^^^^ ^^^^^^^^^^^^ +help: remove these bounds + | +LL | enum TeeOutlivesAyYooWhereBee<'a, 'b, T, U> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:205:65 + | +LL | enum TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: 'a + Debug + 'b { + | ^^^^^ ^^^^^ +help: remove these bounds + | +LL | enum TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: Debug { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:211:51 + | +LL | enum TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T: 'a, U> where U: 'b + Debug { + | ^^^^ ^^^^^ +help: remove these bounds + | +LL | enum TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where U: Debug { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:217:51 + | +LL | enum TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T: 'a, U> where U: Debug + 'b { + | ^^^^ ^^^^^ +help: remove these bounds + | +LL | enum TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where U: Debug { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:223:67 + | +LL | enum TeeWhereOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where T: 'a, U: 'b + Debug { + | ^^^^^^^ ^^^^^ +help: remove these bounds + | +LL | enum TeeWhereOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where U: Debug { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:229:67 + | +LL | enum TeeWhereOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where T: 'a, U: Debug + 'b { + | ^^^^^^^ ^^^^^ +help: remove these bounds + | +LL | enum TeeWhereOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where U: Debug { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:235:36 + | +LL | enum BeeOutlivesAyTeeBee<'a, 'b: 'a, T: 'b> { + | ^^^^ ^^^^ +help: remove these bounds + | +LL | enum BeeOutlivesAyTeeBee<'a, 'b, T> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:240:38 + | +LL | enum BeeOutlivesAyTeeAyBee<'a, 'b: 'a, T: 'a + 'b> { + | ^^^^ ^^^^^^^^^ +help: remove these bounds + | +LL | enum BeeOutlivesAyTeeAyBee<'a, 'b, T> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:246:53 + | +LL | enum BeeOutlivesAyTeeOutlivesAyIsDebugBee<'a, 'b: 'a, T: 'a + Debug + 'b> { + | ^^^^ ^^^^^ ^^^^^ +help: remove these bounds + | +LL | enum BeeOutlivesAyTeeOutlivesAyIsDebugBee<'a, 'b, T: Debug> { + | -- -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:251:66 + | +LL | enum BeeWhereAyTeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where 'b: 'a, T: 'a + Debug + 'b { + | ^^^^^^^^ ^^^^^ ^^^^^ +help: remove these bounds + | +LL | enum BeeWhereAyTeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: Debug { + | -- -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:256:56 + | +LL | enum BeeOutlivesAyTeeYooOutlivesAyIsDebugBee<'a, 'b: 'a, T, U: 'a + Debug + 'b> { + | ^^^^ ^^^^^ ^^^^^ +help: remove these bounds + | +LL | enum BeeOutlivesAyTeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: Debug> { + | -- -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:262:75 + | +LL | enum BeeWhereAyTeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: 'a + Debug + 'b, 'b: 'a { + | ^^^^^ ^^^^^ ^^^^^^ +help: remove these bounds + | +LL | enum BeeWhereAyTeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: Debug, { + | -- ---- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:271:46 + | +LL | union TeeOutlivesAyIsDebugBee<'a, 'b, T: 'a + Debug + 'b> { + | ^^^^^ ^^^^^ +help: remove these bounds + | +LL | union TeeOutlivesAyIsDebugBee<'a, 'b, T: Debug> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:276:60 + | +LL | union TeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: 'a + Debug + 'b { + | ^^^^^ ^^^^^ +help: remove these bounds + | +LL | union TeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: Debug { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:281:52 + | +LL | union TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: 'a + Debug + 'b> { + | ^^^^^ ^^^^^ +help: remove these bounds + | +LL | union TeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: Debug> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:287:47 + | +LL | union TeeOutlivesAyYooBeeIsDebug<'a, 'b, T: 'a, U: 'b + Debug> { + | ^^^^ ^^^^^ +help: remove these bounds + | +LL | union TeeOutlivesAyYooBeeIsDebug<'a, 'b, T, U: Debug> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:293:47 + | +LL | union TeeOutlivesAyYooIsDebugBee<'a, 'b, T: 'a, U: Debug + 'b> { + | ^^^^ ^^^^^ +help: remove these bounds + | +LL | union TeeOutlivesAyYooIsDebugBee<'a, 'b, T, U: Debug> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:299:45 + | +LL | union TeeOutlivesAyYooWhereBee<'a, 'b, T: 'a, U> where U: 'b { + | ^^^^ ^^^^^^^^^^^^ +help: remove these bounds + | +LL | union TeeOutlivesAyYooWhereBee<'a, 'b, T, U> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:305:66 + | +LL | union TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: 'a + Debug + 'b { + | ^^^^^ ^^^^^ +help: remove these bounds + | +LL | union TeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: Debug { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:311:52 + | +LL | union TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T: 'a, U> where U: 'b + Debug { + | ^^^^ ^^^^^ +help: remove these bounds + | +LL | union TeeOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where U: Debug { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:317:52 + | +LL | union TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T: 'a, U> where U: Debug + 'b { + | ^^^^ ^^^^^ +help: remove these bounds + | +LL | union TeeOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where U: Debug { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:323:68 + | +LL | union TeeWhereOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where T: 'a, U: 'b + Debug { + | ^^^^^^^ ^^^^^ +help: remove these bounds + | +LL | union TeeWhereOutlivesAyYooWhereBeeIsDebug<'a, 'b, T, U> where U: Debug { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:329:68 + | +LL | union TeeWhereOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where T: 'a, U: Debug + 'b { + | ^^^^^^^ ^^^^^ +help: remove these bounds + | +LL | union TeeWhereOutlivesAyYooWhereIsDebugBee<'a, 'b, T, U> where U: Debug { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:335:37 + | +LL | union BeeOutlivesAyTeeBee<'a, 'b: 'a, T: 'b> { + | ^^^^ ^^^^ +help: remove these bounds + | +LL | union BeeOutlivesAyTeeBee<'a, 'b, T> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:340:39 + | +LL | union BeeOutlivesAyTeeAyBee<'a, 'b: 'a, T: 'a + 'b> { + | ^^^^ ^^^^^^^^^ +help: remove these bounds + | +LL | union BeeOutlivesAyTeeAyBee<'a, 'b, T> { + | -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:345:54 + | +LL | union BeeOutlivesAyTeeOutlivesAyIsDebugBee<'a, 'b: 'a, T: 'a + Debug + 'b> { + | ^^^^ ^^^^^ ^^^^^ +help: remove these bounds + | +LL | union BeeOutlivesAyTeeOutlivesAyIsDebugBee<'a, 'b, T: Debug> { + | -- -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:350:67 + | +LL | union BeeWhereAyTeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where 'b: 'a, T: 'a + Debug + 'b { + | ^^^^^^^^ ^^^^^ ^^^^^ +help: remove these bounds + | +LL | union BeeWhereAyTeeWhereOutlivesAyIsDebugBee<'a, 'b, T> where T: Debug { + | -- -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:355:57 + | +LL | union BeeOutlivesAyTeeYooOutlivesAyIsDebugBee<'a, 'b: 'a, T, U: 'a + Debug + 'b> { + | ^^^^ ^^^^^ ^^^^^ +help: remove these bounds + | +LL | union BeeOutlivesAyTeeYooOutlivesAyIsDebugBee<'a, 'b, T, U: Debug> { + | -- -- -- + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:361:76 + | +LL | union BeeWhereAyTeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: 'a + Debug + 'b, 'b: 'a { + | ^^^^^ ^^^^^ ^^^^^^ +help: remove these bounds + | +LL | union BeeWhereAyTeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: Debug, { + | -- ---- + +error: aborting due to 68 previous errors diff --git a/src/test/ui/rust-2018/edition-lint-infer-outlives.fixed b/src/test/ui/rust-2018/edition-lint-infer-outlives.fixed index eb48933dca537..13645244da069 100644 --- a/src/test/ui/rust-2018/edition-lint-infer-outlives.fixed +++ b/src/test/ui/rust-2018/edition-lint-infer-outlives.fixed @@ -3,9 +3,6 @@ #![allow(unused)] #![deny(explicit_outlives_requirements)] -use std::fmt::{Debug, Display}; - - // Programmatically generated examples! // // Exercise outlives bounds for each of the following parameter/position @@ -17,177 +14,773 @@ use std::fmt::{Debug, Display}; // • two parameters (T and U), one bound inline, one with a where clause // • two parameters (T and U), both with where clauses // -// —and for every permutation of 0, 1, or 2 lifetimes to outlive and 0 or 1 -// trait bounds distributed among said parameters (subject to no where clause -// being empty and the struct having at least one lifetime). +// —and for every permutation of 1 or 2 lifetimes to outlive and 0 or 1 trait +// bounds distributed among said parameters (subject to no where clause being +// empty and the struct having at least one lifetime). +// +// —and for each of tuple structs, enums and unions. + +mod structs { + use std::fmt::Debug; + + struct TeeOutlivesAy<'a, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + struct TeeOutlivesAyIsDebug<'a, T: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + struct TeeIsDebugOutlivesAy<'a, T: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + struct TeeOutlivesAyBee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeOutlivesAyBeeIsDebug<'a, 'b, T: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeWhereOutlivesAy<'a, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + struct TeeWhereOutlivesAyIsDebug<'a, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + struct TeeWhereIsDebugOutlivesAy<'a, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + struct TeeWhereOutlivesAyBee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeWhereIsDebugOutlivesAyBee<'a, 'b, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeYooOutlivesAy<'a, T, U> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a U + } + + struct TeeYooOutlivesAyIsDebug<'a, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a U + } + + struct TeeYooIsDebugOutlivesAy<'a, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a U + } + + struct TeeOutlivesAyYooIsDebug<'a, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: U + } + + struct TeeYooOutlivesAyBee<'a, 'b, T, U> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeOutlivesAyBeeYooIsDebug<'a, 'b, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + yoo: U + } + + struct TeeYooWhereOutlivesAy<'a, T, U> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a U + } + + struct TeeYooWhereOutlivesAyIsDebug<'a, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a U + } + + struct TeeYooWhereIsDebugOutlivesAy<'a, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a U + } + + struct TeeOutlivesAyYooWhereIsDebug<'a, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: U + } + + struct TeeYooWhereOutlivesAyBee<'a, 'b, T, U> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + yoo: U + } + + struct TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: U + } + + struct TeeWhereOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + yoo: U + } + + struct BeeOutlivesAy<'a, 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b (), + } + + struct BeeWhereOutlivesAy<'a, 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b (), + } + + struct BeeOutlivesAyTee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + struct BeeWhereOutlivesAyTee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + struct BeeWhereOutlivesAyTeeWhereBee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + struct BeeWhereOutlivesAyTeeWhereAyBee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + struct BeeOutlivesAyTeeDebug<'a, 'b, T: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + struct BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } +} +mod tuple_structs { + use std::fmt::Debug; -struct TeeOutlivesAy<'a, T> { + struct TeeOutlivesAy<'a, T>(&'a T); //~^ ERROR outlives requirements can be inferred - tee: &'a T -} -struct TeeOutlivesAyIsDebug<'a, T: Debug> { + struct TeeOutlivesAyIsDebug<'a, T: Debug>(&'a T); //~^ ERROR outlives requirements can be inferred - tee: &'a T -} -struct TeeIsDebugOutlivesAy<'a, T: Debug> { + struct TeeIsDebugOutlivesAy<'a, T: Debug>(&'a T); //~^ ERROR outlives requirements can be inferred - tee: &'a T -} -struct TeeOutlivesAyBee<'a, 'b, T> { + struct TeeOutlivesAyBee<'a, 'b, T>(&'a &'b T); //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T -} -struct TeeOutlivesAyBeeIsDebug<'a, 'b, T: Debug> { + struct TeeOutlivesAyBeeIsDebug<'a, 'b, T: Debug>(&'a &'b T); //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T -} -struct TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug> { + struct TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug>(&'a &'b T); //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T -} -struct TeeWhereOutlivesAy<'a, T> { + struct TeeWhereOutlivesAy<'a, T>(&'a T) ; //~^ ERROR outlives requirements can be inferred - tee: &'a T -} -struct TeeWhereOutlivesAyIsDebug<'a, T> where T: Debug { + struct TeeWhereOutlivesAyIsDebug<'a, T>(&'a T) where T: Debug; //~^ ERROR outlives requirements can be inferred - tee: &'a T -} -struct TeeWhereIsDebugOutlivesAy<'a, T> where T: Debug { + struct TeeWhereIsDebugOutlivesAy<'a, T>(&'a T) where T: Debug; //~^ ERROR outlives requirements can be inferred - tee: &'a T -} -struct TeeWhereOutlivesAyBee<'a, 'b, T> { + struct TeeWhereOutlivesAyBee<'a, 'b, T>(&'a &'b T) ; //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T -} -struct TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T> where T: Debug { + struct TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T>(&'a &'b T) where T: Debug; //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T -} -struct TeeWhereIsDebugOutlivesAyBee<'a, 'b, T> where T: Debug { + struct TeeWhereIsDebugOutlivesAyBee<'a, 'b, T>(&'a &'b T) where T: Debug; //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T -} -struct TeeYooOutlivesAy<'a, T, U> { + struct TeeYooOutlivesAy<'a, T, U>(T, &'a U); //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a U -} -struct TeeYooOutlivesAyIsDebug<'a, T, U: Debug> { + struct TeeYooOutlivesAyIsDebug<'a, T, U: Debug>(T, &'a U); //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a U -} -struct TeeYooIsDebugOutlivesAy<'a, T, U: Debug> { + struct TeeYooIsDebugOutlivesAy<'a, T, U: Debug>(T, &'a U); //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a U -} -struct TeeOutlivesAyYooIsDebug<'a, T, U: Debug> { + struct TeeOutlivesAyYooIsDebug<'a, T, U: Debug>(&'a T, U); //~^ ERROR outlives requirements can be inferred - tee: &'a T, - yoo: U -} -struct TeeYooOutlivesAyBee<'a, 'b, T, U> { + struct TeeYooOutlivesAyBee<'a, 'b, T, U>(T, &'a &'b U); //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: Debug> { + struct TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: Debug>(T, &'a &'b U); //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug> { + struct TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug>(T, &'a &'b U); //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeOutlivesAyBeeYooIsDebug<'a, 'b, T, U: Debug> { + struct TeeOutlivesAyBeeYooIsDebug<'a, 'b, T, U: Debug>(&'a &'b T, U); //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T, - yoo: U -} -struct TeeYooWhereOutlivesAy<'a, T, U> { + struct TeeYooWhereOutlivesAy<'a, T, U>(T, &'a U) ; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a U -} -struct TeeYooWhereOutlivesAyIsDebug<'a, T, U> where U: Debug { + struct TeeYooWhereOutlivesAyIsDebug<'a, T, U>(T, &'a U) where U: Debug; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a U -} -struct TeeYooWhereIsDebugOutlivesAy<'a, T, U> where U: Debug { + struct TeeYooWhereIsDebugOutlivesAy<'a, T, U>(T, &'a U) where U: Debug; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a U -} -struct TeeOutlivesAyYooWhereIsDebug<'a, T, U> where U: Debug { + struct TeeOutlivesAyYooWhereIsDebug<'a, T, U>(&'a T, U) where U: Debug; //~^ ERROR outlives requirements can be inferred - tee: &'a T, - yoo: U -} -struct TeeYooWhereOutlivesAyBee<'a, 'b, T, U> { + struct TeeYooWhereOutlivesAyBee<'a, 'b, T, U>(T, &'a &'b U) ; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U> where U: Debug { + struct TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U>(T, &'a &'b U) where U: Debug; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U> where U: Debug { + struct TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U>(T, &'a &'b U) where U: Debug; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where U: Debug { + struct TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U>(&'a &'b T, U) where U: Debug; //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T, - yoo: U -} -struct TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U> where U: Debug { + struct TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U>(&'a T, U) where U: Debug; + //~^ ERROR outlives requirements can be inferred + + struct TeeWhereAyBeeYooWhereIsDebug<'a, 'b, T, U>(&'a &'b T, U) where U: Debug; + //~^ ERROR outlives requirements can be inferred + + struct BeeOutlivesAy<'a, 'b>(&'a &'b ()); + //~^ ERROR outlives requirements can be inferred + + struct BeeWhereOutlivesAy<'a, 'b>(&'a &'b ()) ; + //~^ ERROR outlives requirements can be inferred + + struct BeeOutlivesAyTee<'a, 'b, T>(&'a &'b T); + //~^ ERROR outlives requirements can be inferred + + struct BeeWhereOutlivesAyTee<'a, 'b, T>(&'a &'b T) ; + //~^ ERROR outlives requirements can be inferred + + struct BeeWhereOutlivesAyTeeWhereBee<'a, 'b, T>(&'a &'b T) ; + //~^ ERROR outlives requirements can be inferred + + struct BeeWhereOutlivesAyTeeWhereAyBee<'a, 'b, T>(&'a &'b T) ; //~^ ERROR outlives requirements can be inferred - tee: &'a T, - yoo: U -} -struct TeeWhereOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where U: Debug { + struct BeeOutlivesAyTeeDebug<'a, 'b, T: Debug>(&'a &'b T); //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T, - yoo: U + + struct BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T>(&'a &'b T) where T: Debug; + //~^ ERROR outlives requirements can be inferred +} + +mod enums { + use std::fmt::Debug; + + enum TeeOutlivesAy<'a, T> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + } + + enum TeeOutlivesAyIsDebug<'a, T: Debug> { + //~^ ERROR outlives requirements can be inferred + V(&'a T), + } + + enum TeeIsDebugOutlivesAy<'a, T: Debug> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + W, + } + + enum TeeOutlivesAyBee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + W, + } + + enum TeeOutlivesAyBeeIsDebug<'a, 'b, T: Debug> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + } + + enum TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug> { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + } + + enum TeeWhereOutlivesAy<'a, T> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + W, + } + + enum TeeWhereOutlivesAyIsDebug<'a, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + V(&'a T), + W, + } + + enum TeeWhereIsDebugOutlivesAy<'a, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + } + + enum TeeWhereOutlivesAyBee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + } + + enum TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + W, + } + + enum TeeWhereIsDebugOutlivesAyBee<'a, 'b, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + W, + } + + enum TeeYooOutlivesAy<'a, T, U> { + //~^ ERROR outlives requirements can be inferred + V { tee: T }, + W(&'a U), + } + + enum TeeYooOutlivesAyIsDebug<'a, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + V { tee: T, yoo: &'a U }, + W, + } + + enum TeeYooIsDebugOutlivesAy<'a, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + V(T, &'a U), + W, + } + + enum TeeOutlivesAyYooIsDebug<'a, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + W(U), + } + + enum TeeYooOutlivesAyBee<'a, 'b, T, U> { + //~^ ERROR outlives requirements can be inferred + V { tee: T, yoo: &'a &'b U }, + W, + } + + enum TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + V(T, &'a &'b U), + W, + } + + enum TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + V { tee: T, yoo: &'a &'b U }, + W, + } + + enum TeeOutlivesAyBeeYooIsDebug<'a, 'b, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T, U), + W, + } + + enum TeeYooWhereOutlivesAy<'a, T, U> { + //~^ ERROR outlives requirements can be inferred + V { tee: T }, + W(&'a U), + } + + enum TeeYooWhereOutlivesAyIsDebug<'a, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + V { tee: T, yoo: &'a U }, + W, + } + + enum TeeYooWhereIsDebugOutlivesAy<'a, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + V(T, &'a U), + W, + } + + enum TeeOutlivesAyYooWhereIsDebug<'a, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + W(U), + } + + enum TeeYooWhereOutlivesAyBee<'a, 'b, T, U> { + //~^ ERROR outlives requirements can be inferred + V { tee: T, yoo: &'a &'b U }, + W, + } + + enum TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + V(T, &'a &'b U), + W, + } + + enum TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + V { tee: T }, + W(&'a &'b U), + } + + enum TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T, yoo: U }, + W, + } + + enum TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + V(&'a T, U), + W, + } + + enum TeeWhereOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + W(U), + } + + enum BeeOutlivesAy<'a, 'b> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b () }, + } + + enum BeeWhereOutlivesAy<'a, 'b> { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b ()), + } + + enum BeeOutlivesAyTee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + W, + } + + enum BeeWhereOutlivesAyTee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + W, + } + + enum BeeWhereOutlivesAyTeeWhereBee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + } + + enum BeeWhereOutlivesAyTeeWhereAyBee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + W, + } + + enum BeeOutlivesAyTeeDebug<'a, 'b, T: Debug> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + } + + enum BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + } +} + +mod unions { + use std::fmt::Debug; + + union TeeOutlivesAy<'a, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + union TeeOutlivesAyIsDebug<'a, T: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + union TeeIsDebugOutlivesAy<'a, T: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + union TeeOutlivesAyBee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeOutlivesAyBeeIsDebug<'a, 'b, T: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeWhereOutlivesAy<'a, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + union TeeWhereOutlivesAyIsDebug<'a, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + union TeeWhereIsDebugOutlivesAy<'a, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + union TeeWhereOutlivesAyBee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeWhereIsDebugOutlivesAyBee<'a, 'b, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeYooOutlivesAy<'a, T, U> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a U + } + + union TeeYooOutlivesAyIsDebug<'a, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a U + } + + union TeeYooIsDebugOutlivesAy<'a, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a U + } + + union TeeOutlivesAyYooIsDebug<'a, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: *const U + } + + union TeeYooOutlivesAyBee<'a, 'b, T, U> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeOutlivesAyBeeYooIsDebug<'a, 'b, T, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + yoo: *const U + } + + union TeeYooWhereOutlivesAy<'a, T, U> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a U + } + + union TeeYooWhereOutlivesAyIsDebug<'a, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a U + } + + union TeeYooWhereIsDebugOutlivesAy<'a, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a U + } + + union TeeOutlivesAyYooWhereIsDebug<'a, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: *const U + } + + union TeeYooWhereOutlivesAyBee<'a, 'b, T, U> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + yoo: *const U + } + + union TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: *const U + } + + union TeeWhereOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + yoo: *const U + } + + union BeeOutlivesAy<'a, 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b (), + } + + union BeeWhereOutlivesAy<'a, 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b (), + } + + union BeeOutlivesAyTee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + union BeeWhereOutlivesAyTee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + union BeeWhereOutlivesAyTeeWhereBee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + union BeeWhereOutlivesAyTeeWhereAyBee<'a, 'b, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + union BeeOutlivesAyTeeDebug<'a, 'b, T: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + union BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where T: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } } diff --git a/src/test/ui/rust-2018/edition-lint-infer-outlives.rs b/src/test/ui/rust-2018/edition-lint-infer-outlives.rs index fd31341365c65..d9486ba66f8aa 100644 --- a/src/test/ui/rust-2018/edition-lint-infer-outlives.rs +++ b/src/test/ui/rust-2018/edition-lint-infer-outlives.rs @@ -3,9 +3,6 @@ #![allow(unused)] #![deny(explicit_outlives_requirements)] -use std::fmt::{Debug, Display}; - - // Programmatically generated examples! // // Exercise outlives bounds for each of the following parameter/position @@ -17,177 +14,773 @@ use std::fmt::{Debug, Display}; // • two parameters (T and U), one bound inline, one with a where clause // • two parameters (T and U), both with where clauses // -// —and for every permutation of 0, 1, or 2 lifetimes to outlive and 0 or 1 -// trait bounds distributed among said parameters (subject to no where clause -// being empty and the struct having at least one lifetime). +// —and for every permutation of 1 or 2 lifetimes to outlive and 0 or 1 trait +// bounds distributed among said parameters (subject to no where clause being +// empty and the struct having at least one lifetime). +// +// —and for each of tuple structs, enums and unions. + +mod structs { + use std::fmt::Debug; + + struct TeeOutlivesAy<'a, T: 'a> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + struct TeeOutlivesAyIsDebug<'a, T: 'a + Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + struct TeeIsDebugOutlivesAy<'a, T: Debug + 'a> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + struct TeeOutlivesAyBee<'a, 'b, T: 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeOutlivesAyBeeIsDebug<'a, 'b, T: 'a + 'b + Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug + 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeWhereOutlivesAy<'a, T> where T: 'a { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + struct TeeWhereOutlivesAyIsDebug<'a, T> where T: 'a + Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + struct TeeWhereIsDebugOutlivesAy<'a, T> where T: Debug + 'a { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + struct TeeWhereOutlivesAyBee<'a, 'b, T> where T: 'a + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T> where T: 'a + 'b + Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeWhereIsDebugOutlivesAyBee<'a, 'b, T> where T: Debug + 'a + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + struct TeeYooOutlivesAy<'a, T, U: 'a> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a U + } + + struct TeeYooOutlivesAyIsDebug<'a, T, U: 'a + Debug> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a U + } + + struct TeeYooIsDebugOutlivesAy<'a, T, U: Debug + 'a> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a U + } + + struct TeeOutlivesAyYooIsDebug<'a, T: 'a, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: U + } + + struct TeeYooOutlivesAyBee<'a, 'b, T, U: 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: 'a + 'b + Debug> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug + 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeOutlivesAyBeeYooIsDebug<'a, 'b, T: 'a + 'b, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + yoo: U + } + + struct TeeYooWhereOutlivesAy<'a, T, U> where U: 'a { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a U + } + + struct TeeYooWhereOutlivesAyIsDebug<'a, T, U> where U: 'a + Debug { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a U + } + + struct TeeYooWhereIsDebugOutlivesAy<'a, T, U> where U: Debug + 'a { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a U + } + + struct TeeOutlivesAyYooWhereIsDebug<'a, T: 'a, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: U + } + + struct TeeYooWhereOutlivesAyBee<'a, 'b, T, U> where U: 'a + 'b { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U> where U: 'a + 'b + Debug { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U> where U: Debug + 'a + 'b { + //~^ ERROR outlives requirements can be inferred + tee: T, + yoo: &'a &'b U + } + + struct TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T: 'a + 'b, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + yoo: U + } + + struct TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U> where T: 'a, U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: U + } + + struct TeeWhereOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where T: 'a + 'b, U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + yoo: U + } + + struct BeeOutlivesAy<'a, 'b: 'a> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b (), + } + + struct BeeWhereOutlivesAy<'a, 'b> where 'b: 'a { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b (), + } + + struct BeeOutlivesAyTee<'a, 'b: 'a, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + struct BeeWhereOutlivesAyTee<'a, 'b, T> where 'b: 'a { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + struct BeeWhereOutlivesAyTeeWhereBee<'a, 'b, T> where 'b: 'a, T: 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + struct BeeWhereOutlivesAyTeeWhereAyBee<'a, 'b, T> where 'b: 'a, T: 'a + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + struct BeeOutlivesAyTeeDebug<'a, 'b: 'a, T: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + struct BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where 'b: 'a, T: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } +} +mod tuple_structs { + use std::fmt::Debug; -struct TeeOutlivesAy<'a, T: 'a> { + struct TeeOutlivesAy<'a, T: 'a>(&'a T); //~^ ERROR outlives requirements can be inferred - tee: &'a T -} -struct TeeOutlivesAyIsDebug<'a, T: 'a + Debug> { + struct TeeOutlivesAyIsDebug<'a, T: 'a + Debug>(&'a T); //~^ ERROR outlives requirements can be inferred - tee: &'a T -} -struct TeeIsDebugOutlivesAy<'a, T: Debug + 'a> { + struct TeeIsDebugOutlivesAy<'a, T: Debug + 'a>(&'a T); //~^ ERROR outlives requirements can be inferred - tee: &'a T -} -struct TeeOutlivesAyBee<'a, 'b, T: 'a + 'b> { + struct TeeOutlivesAyBee<'a, 'b, T: 'a + 'b>(&'a &'b T); //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T -} -struct TeeOutlivesAyBeeIsDebug<'a, 'b, T: 'a + 'b + Debug> { + struct TeeOutlivesAyBeeIsDebug<'a, 'b, T: 'a + 'b + Debug>(&'a &'b T); //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T -} -struct TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug + 'a + 'b> { + struct TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug + 'a + 'b>(&'a &'b T); //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T -} -struct TeeWhereOutlivesAy<'a, T> where T: 'a { + struct TeeWhereOutlivesAy<'a, T>(&'a T) where T: 'a; //~^ ERROR outlives requirements can be inferred - tee: &'a T -} -struct TeeWhereOutlivesAyIsDebug<'a, T> where T: 'a + Debug { + struct TeeWhereOutlivesAyIsDebug<'a, T>(&'a T) where T: 'a + Debug; //~^ ERROR outlives requirements can be inferred - tee: &'a T -} -struct TeeWhereIsDebugOutlivesAy<'a, T> where T: Debug + 'a { + struct TeeWhereIsDebugOutlivesAy<'a, T>(&'a T) where T: Debug + 'a; //~^ ERROR outlives requirements can be inferred - tee: &'a T -} -struct TeeWhereOutlivesAyBee<'a, 'b, T> where T: 'a + 'b { + struct TeeWhereOutlivesAyBee<'a, 'b, T>(&'a &'b T) where T: 'a + 'b; //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T -} -struct TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T> where T: 'a + 'b + Debug { + struct TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T>(&'a &'b T) where T: 'a + 'b + Debug; //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T -} -struct TeeWhereIsDebugOutlivesAyBee<'a, 'b, T> where T: Debug + 'a + 'b { + struct TeeWhereIsDebugOutlivesAyBee<'a, 'b, T>(&'a &'b T) where T: Debug + 'a + 'b; //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T -} -struct TeeYooOutlivesAy<'a, T, U: 'a> { + struct TeeYooOutlivesAy<'a, T, U: 'a>(T, &'a U); //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a U -} -struct TeeYooOutlivesAyIsDebug<'a, T, U: 'a + Debug> { + struct TeeYooOutlivesAyIsDebug<'a, T, U: 'a + Debug>(T, &'a U); //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a U -} -struct TeeYooIsDebugOutlivesAy<'a, T, U: Debug + 'a> { + struct TeeYooIsDebugOutlivesAy<'a, T, U: Debug + 'a>(T, &'a U); //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a U -} -struct TeeOutlivesAyYooIsDebug<'a, T: 'a, U: Debug> { + struct TeeOutlivesAyYooIsDebug<'a, T: 'a, U: Debug>(&'a T, U); //~^ ERROR outlives requirements can be inferred - tee: &'a T, - yoo: U -} -struct TeeYooOutlivesAyBee<'a, 'b, T, U: 'a + 'b> { + struct TeeYooOutlivesAyBee<'a, 'b, T, U: 'a + 'b>(T, &'a &'b U); //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: 'a + 'b + Debug> { + struct TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: 'a + 'b + Debug>(T, &'a &'b U); //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug + 'a + 'b> { + struct TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug + 'a + 'b>(T, &'a &'b U); //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeOutlivesAyBeeYooIsDebug<'a, 'b, T: 'a + 'b, U: Debug> { + struct TeeOutlivesAyBeeYooIsDebug<'a, 'b, T: 'a + 'b, U: Debug>(&'a &'b T, U); //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T, - yoo: U -} -struct TeeYooWhereOutlivesAy<'a, T, U> where U: 'a { + struct TeeYooWhereOutlivesAy<'a, T, U>(T, &'a U) where U: 'a; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a U -} -struct TeeYooWhereOutlivesAyIsDebug<'a, T, U> where U: 'a + Debug { + struct TeeYooWhereOutlivesAyIsDebug<'a, T, U>(T, &'a U) where U: 'a + Debug; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a U -} -struct TeeYooWhereIsDebugOutlivesAy<'a, T, U> where U: Debug + 'a { + struct TeeYooWhereIsDebugOutlivesAy<'a, T, U>(T, &'a U) where U: Debug + 'a; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a U -} -struct TeeOutlivesAyYooWhereIsDebug<'a, T: 'a, U> where U: Debug { + struct TeeOutlivesAyYooWhereIsDebug<'a, T: 'a, U>(&'a T, U) where U: Debug; //~^ ERROR outlives requirements can be inferred - tee: &'a T, - yoo: U -} -struct TeeYooWhereOutlivesAyBee<'a, 'b, T, U> where U: 'a + 'b { + struct TeeYooWhereOutlivesAyBee<'a, 'b, T, U>(T, &'a &'b U) where U: 'a + 'b; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U> where U: 'a + 'b + Debug { + struct TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U>(T, &'a &'b U) where U: 'a + 'b + Debug; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U> where U: Debug + 'a + 'b { + struct TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U>(T, &'a &'b U) where U: Debug + 'a + 'b; //~^ ERROR outlives requirements can be inferred - tee: T, - yoo: &'a &'b U -} -struct TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T: 'a + 'b, U> where U: Debug { + struct TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T: 'a + 'b, U>(&'a &'b T, U) where U: Debug; //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T, - yoo: U -} -struct TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U> where T: 'a, U: Debug { + struct TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U>(&'a T, U) where T: 'a, U: Debug; + //~^ ERROR outlives requirements can be inferred + + struct TeeWhereAyBeeYooWhereIsDebug<'a, 'b, T, U>(&'a &'b T, U) where T: 'a + 'b, U: Debug; + //~^ ERROR outlives requirements can be inferred + + struct BeeOutlivesAy<'a, 'b: 'a>(&'a &'b ()); + //~^ ERROR outlives requirements can be inferred + + struct BeeWhereOutlivesAy<'a, 'b>(&'a &'b ()) where 'b: 'a; + //~^ ERROR outlives requirements can be inferred + + struct BeeOutlivesAyTee<'a, 'b: 'a, T>(&'a &'b T); + //~^ ERROR outlives requirements can be inferred + + struct BeeWhereOutlivesAyTee<'a, 'b, T>(&'a &'b T) where 'b: 'a; + //~^ ERROR outlives requirements can be inferred + + struct BeeWhereOutlivesAyTeeWhereBee<'a, 'b, T>(&'a &'b T) where 'b: 'a, T: 'b; + //~^ ERROR outlives requirements can be inferred + + struct BeeWhereOutlivesAyTeeWhereAyBee<'a, 'b, T>(&'a &'b T) where 'b: 'a, T: 'a + 'b; //~^ ERROR outlives requirements can be inferred - tee: &'a T, - yoo: U -} -struct TeeWhereOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where T: 'a + 'b, U: Debug { + struct BeeOutlivesAyTeeDebug<'a, 'b: 'a, T: Debug>(&'a &'b T); //~^ ERROR outlives requirements can be inferred - tee: &'a &'b T, - yoo: U + + struct BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T>(&'a &'b T) where 'b: 'a, T: Debug; + //~^ ERROR outlives requirements can be inferred +} + +mod enums { + use std::fmt::Debug; + + enum TeeOutlivesAy<'a, T: 'a> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + } + + enum TeeOutlivesAyIsDebug<'a, T: 'a + Debug> { + //~^ ERROR outlives requirements can be inferred + V(&'a T), + } + + enum TeeIsDebugOutlivesAy<'a, T: Debug + 'a> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + W, + } + + enum TeeOutlivesAyBee<'a, 'b, T: 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + W, + } + + enum TeeOutlivesAyBeeIsDebug<'a, 'b, T: 'a + 'b + Debug> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + } + + enum TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug + 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + } + + enum TeeWhereOutlivesAy<'a, T> where T: 'a { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + W, + } + + enum TeeWhereOutlivesAyIsDebug<'a, T> where T: 'a + Debug { + //~^ ERROR outlives requirements can be inferred + V(&'a T), + W, + } + + enum TeeWhereIsDebugOutlivesAy<'a, T> where T: Debug + 'a { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + } + + enum TeeWhereOutlivesAyBee<'a, 'b, T> where T: 'a + 'b { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + } + + enum TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T> where T: 'a + 'b + Debug { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + W, + } + + enum TeeWhereIsDebugOutlivesAyBee<'a, 'b, T> where T: Debug + 'a + 'b { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + W, + } + + enum TeeYooOutlivesAy<'a, T, U: 'a> { + //~^ ERROR outlives requirements can be inferred + V { tee: T }, + W(&'a U), + } + + enum TeeYooOutlivesAyIsDebug<'a, T, U: 'a + Debug> { + //~^ ERROR outlives requirements can be inferred + V { tee: T, yoo: &'a U }, + W, + } + + enum TeeYooIsDebugOutlivesAy<'a, T, U: Debug + 'a> { + //~^ ERROR outlives requirements can be inferred + V(T, &'a U), + W, + } + + enum TeeOutlivesAyYooIsDebug<'a, T: 'a, U: Debug> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + W(U), + } + + enum TeeYooOutlivesAyBee<'a, 'b, T, U: 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + V { tee: T, yoo: &'a &'b U }, + W, + } + + enum TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: 'a + 'b + Debug> { + //~^ ERROR outlives requirements can be inferred + V(T, &'a &'b U), + W, + } + + enum TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug + 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + V { tee: T, yoo: &'a &'b U }, + W, + } + + enum TeeOutlivesAyBeeYooIsDebug<'a, 'b, T: 'a + 'b, U: Debug> { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T, U), + W, + } + + enum TeeYooWhereOutlivesAy<'a, T, U> where U: 'a { + //~^ ERROR outlives requirements can be inferred + V { tee: T }, + W(&'a U), + } + + enum TeeYooWhereOutlivesAyIsDebug<'a, T, U> where U: 'a + Debug { + //~^ ERROR outlives requirements can be inferred + V { tee: T, yoo: &'a U }, + W, + } + + enum TeeYooWhereIsDebugOutlivesAy<'a, T, U> where U: Debug + 'a { + //~^ ERROR outlives requirements can be inferred + V(T, &'a U), + W, + } + + enum TeeOutlivesAyYooWhereIsDebug<'a, T: 'a, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a T }, + W(U), + } + + enum TeeYooWhereOutlivesAyBee<'a, 'b, T, U> where U: 'a + 'b { + //~^ ERROR outlives requirements can be inferred + V { tee: T, yoo: &'a &'b U }, + W, + } + + enum TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U> where U: 'a + 'b + Debug { + //~^ ERROR outlives requirements can be inferred + V(T, &'a &'b U), + W, + } + + enum TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U> where U: Debug + 'a + 'b { + //~^ ERROR outlives requirements can be inferred + V { tee: T }, + W(&'a &'b U), + } + + enum TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T: 'a + 'b, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T, yoo: U }, + W, + } + + enum TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U> where T: 'a, U: Debug { + //~^ ERROR outlives requirements can be inferred + V(&'a T, U), + W, + } + + enum TeeWhereOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where T: 'a + 'b, U: Debug { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + W(U), + } + + enum BeeOutlivesAy<'a, 'b: 'a> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b () }, + } + + enum BeeWhereOutlivesAy<'a, 'b> where 'b: 'a { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b ()), + } + + enum BeeOutlivesAyTee<'a, 'b: 'a, T> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + W, + } + + enum BeeWhereOutlivesAyTee<'a, 'b, T> where 'b: 'a { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + W, + } + + enum BeeWhereOutlivesAyTeeWhereBee<'a, 'b, T> where 'b: 'a, T: 'b { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + } + + enum BeeWhereOutlivesAyTeeWhereAyBee<'a, 'b, T> where 'b: 'a, T: 'a + 'b { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + W, + } + + enum BeeOutlivesAyTeeDebug<'a, 'b: 'a, T: Debug> { + //~^ ERROR outlives requirements can be inferred + V { tee: &'a &'b T }, + } + + enum BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where 'b: 'a, T: Debug { + //~^ ERROR outlives requirements can be inferred + V(&'a &'b T), + } +} + +mod unions { + use std::fmt::Debug; + + union TeeOutlivesAy<'a, T: 'a> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + union TeeOutlivesAyIsDebug<'a, T: 'a + Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + union TeeIsDebugOutlivesAy<'a, T: Debug + 'a> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + union TeeOutlivesAyBee<'a, 'b, T: 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeOutlivesAyBeeIsDebug<'a, 'b, T: 'a + 'b + Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug + 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeWhereOutlivesAy<'a, T> where T: 'a { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + union TeeWhereOutlivesAyIsDebug<'a, T> where T: 'a + Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + union TeeWhereIsDebugOutlivesAy<'a, T> where T: Debug + 'a { + //~^ ERROR outlives requirements can be inferred + tee: &'a T + } + + union TeeWhereOutlivesAyBee<'a, 'b, T> where T: 'a + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T> where T: 'a + 'b + Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeWhereIsDebugOutlivesAyBee<'a, 'b, T> where T: Debug + 'a + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T + } + + union TeeYooOutlivesAy<'a, T, U: 'a> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a U + } + + union TeeYooOutlivesAyIsDebug<'a, T, U: 'a + Debug> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a U + } + + union TeeYooIsDebugOutlivesAy<'a, T, U: Debug + 'a> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a U + } + + union TeeOutlivesAyYooIsDebug<'a, T: 'a, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: *const U + } + + union TeeYooOutlivesAyBee<'a, 'b, T, U: 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: 'a + 'b + Debug> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug + 'a + 'b> { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeOutlivesAyBeeYooIsDebug<'a, 'b, T: 'a + 'b, U: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + yoo: *const U + } + + union TeeYooWhereOutlivesAy<'a, T, U> where U: 'a { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a U + } + + union TeeYooWhereOutlivesAyIsDebug<'a, T, U> where U: 'a + Debug { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a U + } + + union TeeYooWhereIsDebugOutlivesAy<'a, T, U> where U: Debug + 'a { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a U + } + + union TeeOutlivesAyYooWhereIsDebug<'a, T: 'a, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: *const U + } + + union TeeYooWhereOutlivesAyBee<'a, 'b, T, U> where U: 'a + 'b { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U> where U: 'a + 'b + Debug { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U> where U: Debug + 'a + 'b { + //~^ ERROR outlives requirements can be inferred + tee: *const T, + yoo: &'a &'b U + } + + union TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T: 'a + 'b, U> where U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + yoo: *const U + } + + union TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U> where T: 'a, U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a T, + yoo: *const U + } + + union TeeWhereOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where T: 'a + 'b, U: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + yoo: *const U + } + + union BeeOutlivesAy<'a, 'b: 'a> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b (), + } + + union BeeWhereOutlivesAy<'a, 'b> where 'b: 'a { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b (), + } + + union BeeOutlivesAyTee<'a, 'b: 'a, T> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + union BeeWhereOutlivesAyTee<'a, 'b, T> where 'b: 'a { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + union BeeWhereOutlivesAyTeeWhereBee<'a, 'b, T> where 'b: 'a, T: 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + union BeeWhereOutlivesAyTeeWhereAyBee<'a, 'b, T> where 'b: 'a, T: 'a + 'b { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + union BeeOutlivesAyTeeDebug<'a, 'b: 'a, T: Debug> { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } + + union BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where 'b: 'a, T: Debug { + //~^ ERROR outlives requirements can be inferred + tee: &'a &'b T, + } } diff --git a/src/test/ui/rust-2018/edition-lint-infer-outlives.stderr b/src/test/ui/rust-2018/edition-lint-infer-outlives.stderr index 8b957984af58c..cddce94254b40 100644 --- a/src/test/ui/rust-2018/edition-lint-infer-outlives.stderr +++ b/src/test/ui/rust-2018/edition-lint-infer-outlives.stderr @@ -1,8 +1,8 @@ error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:25:27 + --> $DIR/edition-lint-infer-outlives.rs:26:31 | -LL | struct TeeOutlivesAy<'a, T: 'a> { - | ^^^^ help: remove this bound +LL | struct TeeOutlivesAy<'a, T: 'a> { + | ^^^^ help: remove this bound | note: lint level defined here --> $DIR/edition-lint-infer-outlives.rs:4:9 @@ -11,178 +11,910 @@ LL | #![deny(explicit_outlives_requirements)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:30:36 + --> $DIR/edition-lint-infer-outlives.rs:31:40 | -LL | struct TeeOutlivesAyIsDebug<'a, T: 'a + Debug> { - | ^^^^^ help: remove this bound +LL | struct TeeOutlivesAyIsDebug<'a, T: 'a + Debug> { + | ^^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:35:41 + --> $DIR/edition-lint-infer-outlives.rs:36:45 | -LL | struct TeeIsDebugOutlivesAy<'a, T: Debug + 'a> { - | ^^^^^ help: remove this bound +LL | struct TeeIsDebugOutlivesAy<'a, T: Debug + 'a> { + | ^^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:40:34 + --> $DIR/edition-lint-infer-outlives.rs:41:38 | -LL | struct TeeOutlivesAyBee<'a, 'b, T: 'a + 'b> { - | ^^^^^^^^^ help: remove these bounds +LL | struct TeeOutlivesAyBee<'a, 'b, T: 'a + 'b> { + | ^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:45:43 + --> $DIR/edition-lint-infer-outlives.rs:46:47 | -LL | struct TeeOutlivesAyBeeIsDebug<'a, 'b, T: 'a + 'b + Debug> { - | ^^^^^^^^^^ help: remove these bounds +LL | struct TeeOutlivesAyBeeIsDebug<'a, 'b, T: 'a + 'b + Debug> { + | ^^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:50:48 + --> $DIR/edition-lint-infer-outlives.rs:51:52 | -LL | struct TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug + 'a + 'b> { - | ^^^^^^^^^^ help: remove these bounds +LL | struct TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug + 'a + 'b> { + | ^^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:55:33 + --> $DIR/edition-lint-infer-outlives.rs:56:37 | -LL | struct TeeWhereOutlivesAy<'a, T> where T: 'a { - | ^^^^^^^^^^^^ help: remove this bound +LL | struct TeeWhereOutlivesAy<'a, T> where T: 'a { + | ^^^^^^^^^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:60:50 + --> $DIR/edition-lint-infer-outlives.rs:61:54 | -LL | struct TeeWhereOutlivesAyIsDebug<'a, T> where T: 'a + Debug { - | ^^^^^ help: remove this bound +LL | struct TeeWhereOutlivesAyIsDebug<'a, T> where T: 'a + Debug { + | ^^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:65:55 + --> $DIR/edition-lint-infer-outlives.rs:66:59 | -LL | struct TeeWhereIsDebugOutlivesAy<'a, T> where T: Debug + 'a { - | ^^^^^ help: remove this bound +LL | struct TeeWhereIsDebugOutlivesAy<'a, T> where T: Debug + 'a { + | ^^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:70:40 + --> $DIR/edition-lint-infer-outlives.rs:71:44 | -LL | struct TeeWhereOutlivesAyBee<'a, 'b, T> where T: 'a + 'b { - | ^^^^^^^^^^^^^^^^^ help: remove these bounds +LL | struct TeeWhereOutlivesAyBee<'a, 'b, T> where T: 'a + 'b { + | ^^^^^^^^^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:75:57 + --> $DIR/edition-lint-infer-outlives.rs:76:61 | -LL | struct TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T> where T: 'a + 'b + Debug { - | ^^^^^^^^^^ help: remove these bounds +LL | struct TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T> where T: 'a + 'b + Debug { + | ^^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:80:62 + --> $DIR/edition-lint-infer-outlives.rs:81:66 | -LL | struct TeeWhereIsDebugOutlivesAyBee<'a, 'b, T> where T: Debug + 'a + 'b { - | ^^^^^^^^^^ help: remove these bounds +LL | struct TeeWhereIsDebugOutlivesAyBee<'a, 'b, T> where T: Debug + 'a + 'b { + | ^^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:85:33 + --> $DIR/edition-lint-infer-outlives.rs:86:37 | -LL | struct TeeYooOutlivesAy<'a, T, U: 'a> { - | ^^^^ help: remove this bound +LL | struct TeeYooOutlivesAy<'a, T, U: 'a> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:92:46 + | +LL | struct TeeYooOutlivesAyIsDebug<'a, T, U: 'a + Debug> { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:98:51 + | +LL | struct TeeYooIsDebugOutlivesAy<'a, T, U: Debug + 'a> { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:104:41 + | +LL | struct TeeOutlivesAyYooIsDebug<'a, T: 'a, U: Debug> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:110:44 + | +LL | struct TeeYooOutlivesAyBee<'a, 'b, T, U: 'a + 'b> { + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:116:53 + | +LL | struct TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: 'a + 'b + Debug> { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:122:58 + | +LL | struct TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug + 'a + 'b> { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:128:48 + | +LL | struct TeeOutlivesAyBeeYooIsDebug<'a, 'b, T: 'a + 'b, U: Debug> { + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:134:43 + | +LL | struct TeeYooWhereOutlivesAy<'a, T, U> where U: 'a { + | ^^^^^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:140:60 + | +LL | struct TeeYooWhereOutlivesAyIsDebug<'a, T, U> where U: 'a + Debug { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:146:65 + | +LL | struct TeeYooWhereIsDebugOutlivesAy<'a, T, U> where U: Debug + 'a { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:152:46 + | +LL | struct TeeOutlivesAyYooWhereIsDebug<'a, T: 'a, U> where U: Debug { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:158:50 + | +LL | struct TeeYooWhereOutlivesAyBee<'a, 'b, T, U> where U: 'a + 'b { + | ^^^^^^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:164:67 + | +LL | struct TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U> where U: 'a + 'b + Debug { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:170:72 + | +LL | struct TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U> where U: Debug + 'a + 'b { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:176:53 + | +LL | struct TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T: 'a + 'b, U> where U: Debug { + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:182:62 + | +LL | struct TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U> where T: 'a, U: Debug { + | ^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:188:69 + | +LL | struct TeeWhereOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where T: 'a + 'b, U: Debug { + | ^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:194:32 + | +LL | struct BeeOutlivesAy<'a, 'b: 'a> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:199:38 + | +LL | struct BeeWhereOutlivesAy<'a, 'b> where 'b: 'a { + | ^^^^^^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:204:35 + | +LL | struct BeeOutlivesAyTee<'a, 'b: 'a, T> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:209:44 + | +LL | struct BeeWhereOutlivesAyTee<'a, 'b, T> where 'b: 'a { + | ^^^^^^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:214:52 + | +LL | struct BeeWhereOutlivesAyTeeWhereBee<'a, 'b, T> where 'b: 'a, T: 'b { + | ^^^^^^^^^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:219:54 + | +LL | struct BeeWhereOutlivesAyTeeWhereAyBee<'a, 'b, T> where 'b: 'a, T: 'a + 'b { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:224:40 + | +LL | struct BeeOutlivesAyTeeDebug<'a, 'b: 'a, T: Debug> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:229:61 + | +LL | struct BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where 'b: 'a, T: Debug { + | ^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:238:31 + | +LL | struct TeeOutlivesAy<'a, T: 'a>(&'a T); + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:241:40 + | +LL | struct TeeOutlivesAyIsDebug<'a, T: 'a + Debug>(&'a T); + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:244:45 + | +LL | struct TeeIsDebugOutlivesAy<'a, T: Debug + 'a>(&'a T); + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:247:38 + | +LL | struct TeeOutlivesAyBee<'a, 'b, T: 'a + 'b>(&'a &'b T); + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:250:47 + | +LL | struct TeeOutlivesAyBeeIsDebug<'a, 'b, T: 'a + 'b + Debug>(&'a &'b T); + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:253:52 + | +LL | struct TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug + 'a + 'b>(&'a &'b T); + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:256:45 + | +LL | struct TeeWhereOutlivesAy<'a, T>(&'a T) where T: 'a; + | ^^^^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:259:61 + | +LL | struct TeeWhereOutlivesAyIsDebug<'a, T>(&'a T) where T: 'a + Debug; + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:262:66 + | +LL | struct TeeWhereIsDebugOutlivesAy<'a, T>(&'a T) where T: Debug + 'a; + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:265:56 + | +LL | struct TeeWhereOutlivesAyBee<'a, 'b, T>(&'a &'b T) where T: 'a + 'b; + | ^^^^^^^^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:91:42 + --> $DIR/edition-lint-infer-outlives.rs:268:72 | -LL | struct TeeYooOutlivesAyIsDebug<'a, T, U: 'a + Debug> { - | ^^^^^ help: remove this bound +LL | struct TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T>(&'a &'b T) where T: 'a + 'b + Debug; + | ^^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:97:47 + --> $DIR/edition-lint-infer-outlives.rs:271:77 | -LL | struct TeeYooIsDebugOutlivesAy<'a, T, U: Debug + 'a> { - | ^^^^^ help: remove this bound +LL | struct TeeWhereIsDebugOutlivesAyBee<'a, 'b, T>(&'a &'b T) where T: Debug + 'a + 'b; + | ^^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:103:37 + --> $DIR/edition-lint-infer-outlives.rs:274:37 | -LL | struct TeeOutlivesAyYooIsDebug<'a, T: 'a, U: Debug> { +LL | struct TeeYooOutlivesAy<'a, T, U: 'a>(T, &'a U); | ^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:109:40 + --> $DIR/edition-lint-infer-outlives.rs:277:46 | -LL | struct TeeYooOutlivesAyBee<'a, 'b, T, U: 'a + 'b> { - | ^^^^^^^^^ help: remove these bounds +LL | struct TeeYooOutlivesAyIsDebug<'a, T, U: 'a + Debug>(T, &'a U); + | ^^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:115:49 + --> $DIR/edition-lint-infer-outlives.rs:280:51 | -LL | struct TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: 'a + 'b + Debug> { - | ^^^^^^^^^^ help: remove these bounds +LL | struct TeeYooIsDebugOutlivesAy<'a, T, U: Debug + 'a>(T, &'a U); + | ^^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:121:54 + --> $DIR/edition-lint-infer-outlives.rs:283:41 | -LL | struct TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug + 'a + 'b> { - | ^^^^^^^^^^ help: remove these bounds +LL | struct TeeOutlivesAyYooIsDebug<'a, T: 'a, U: Debug>(&'a T, U); + | ^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:127:44 + --> $DIR/edition-lint-infer-outlives.rs:286:44 | -LL | struct TeeOutlivesAyBeeYooIsDebug<'a, 'b, T: 'a + 'b, U: Debug> { +LL | struct TeeYooOutlivesAyBee<'a, 'b, T, U: 'a + 'b>(T, &'a &'b U); | ^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:133:39 + --> $DIR/edition-lint-infer-outlives.rs:289:53 | -LL | struct TeeYooWhereOutlivesAy<'a, T, U> where U: 'a { - | ^^^^^^^^^^^^ help: remove this bound +LL | struct TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: 'a + 'b + Debug>(T, &'a &'b U); + | ^^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:139:56 + --> $DIR/edition-lint-infer-outlives.rs:292:58 | -LL | struct TeeYooWhereOutlivesAyIsDebug<'a, T, U> where U: 'a + Debug { - | ^^^^^ help: remove this bound +LL | struct TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug + 'a + 'b>(T, &'a &'b U); + | ^^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:145:61 + --> $DIR/edition-lint-infer-outlives.rs:295:48 | -LL | struct TeeYooWhereIsDebugOutlivesAy<'a, T, U> where U: Debug + 'a { - | ^^^^^ help: remove this bound +LL | struct TeeOutlivesAyBeeYooIsDebug<'a, 'b, T: 'a + 'b, U: Debug>(&'a &'b T, U); + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:298:54 + | +LL | struct TeeYooWhereOutlivesAy<'a, T, U>(T, &'a U) where U: 'a; + | ^^^^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:301:70 + | +LL | struct TeeYooWhereOutlivesAyIsDebug<'a, T, U>(T, &'a U) where U: 'a + Debug; + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:304:75 + | +LL | struct TeeYooWhereIsDebugOutlivesAy<'a, T, U>(T, &'a U) where U: Debug + 'a; + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:307:46 + | +LL | struct TeeOutlivesAyYooWhereIsDebug<'a, T: 'a, U>(&'a T, U) where U: Debug; + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:310:65 + | +LL | struct TeeYooWhereOutlivesAyBee<'a, 'b, T, U>(T, &'a &'b U) where U: 'a + 'b; + | ^^^^^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:313:81 + | +LL | struct TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U>(T, &'a &'b U) where U: 'a + 'b + Debug; + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:316:86 + | +LL | struct TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U>(T, &'a &'b U) where U: Debug + 'a + 'b; + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:319:53 + | +LL | struct TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T: 'a + 'b, U>(&'a &'b T, U) where U: Debug; + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:322:72 + | +LL | struct TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U>(&'a T, U) where T: 'a, U: Debug; + | ^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:325:75 + | +LL | struct TeeWhereAyBeeYooWhereIsDebug<'a, 'b, T, U>(&'a &'b T, U) where T: 'a + 'b, U: Debug; + | ^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:328:32 + | +LL | struct BeeOutlivesAy<'a, 'b: 'a>(&'a &'b ()); + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:331:51 + | +LL | struct BeeWhereOutlivesAy<'a, 'b>(&'a &'b ()) where 'b: 'a; + | ^^^^^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:334:35 + | +LL | struct BeeOutlivesAyTee<'a, 'b: 'a, T>(&'a &'b T); + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:337:56 + | +LL | struct BeeWhereOutlivesAyTee<'a, 'b, T>(&'a &'b T) where 'b: 'a; + | ^^^^^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:340:64 + | +LL | struct BeeWhereOutlivesAyTeeWhereBee<'a, 'b, T>(&'a &'b T) where 'b: 'a, T: 'b; + | ^^^^^^^^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:343:66 + | +LL | struct BeeWhereOutlivesAyTeeWhereAyBee<'a, 'b, T>(&'a &'b T) where 'b: 'a, T: 'a + 'b; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:346:40 + | +LL | struct BeeOutlivesAyTeeDebug<'a, 'b: 'a, T: Debug>(&'a &'b T); + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:349:72 + | +LL | struct BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T>(&'a &'b T) where 'b: 'a, T: Debug; + | ^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:356:29 + | +LL | enum TeeOutlivesAy<'a, T: 'a> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:361:38 + | +LL | enum TeeOutlivesAyIsDebug<'a, T: 'a + Debug> { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:366:43 + | +LL | enum TeeIsDebugOutlivesAy<'a, T: Debug + 'a> { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:372:36 + | +LL | enum TeeOutlivesAyBee<'a, 'b, T: 'a + 'b> { + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:378:45 + | +LL | enum TeeOutlivesAyBeeIsDebug<'a, 'b, T: 'a + 'b + Debug> { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:383:50 + | +LL | enum TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug + 'a + 'b> { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:388:35 + | +LL | enum TeeWhereOutlivesAy<'a, T> where T: 'a { + | ^^^^^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:394:52 + | +LL | enum TeeWhereOutlivesAyIsDebug<'a, T> where T: 'a + Debug { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:400:57 + | +LL | enum TeeWhereIsDebugOutlivesAy<'a, T> where T: Debug + 'a { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:405:42 + | +LL | enum TeeWhereOutlivesAyBee<'a, 'b, T> where T: 'a + 'b { + | ^^^^^^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:410:59 + | +LL | enum TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T> where T: 'a + 'b + Debug { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:416:64 + | +LL | enum TeeWhereIsDebugOutlivesAyBee<'a, 'b, T> where T: Debug + 'a + 'b { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:422:35 + | +LL | enum TeeYooOutlivesAy<'a, T, U: 'a> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:428:44 + | +LL | enum TeeYooOutlivesAyIsDebug<'a, T, U: 'a + Debug> { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:434:49 + | +LL | enum TeeYooIsDebugOutlivesAy<'a, T, U: Debug + 'a> { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:440:39 + | +LL | enum TeeOutlivesAyYooIsDebug<'a, T: 'a, U: Debug> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:446:42 + | +LL | enum TeeYooOutlivesAyBee<'a, 'b, T, U: 'a + 'b> { + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:452:51 + | +LL | enum TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: 'a + 'b + Debug> { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:458:56 + | +LL | enum TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug + 'a + 'b> { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:464:46 + | +LL | enum TeeOutlivesAyBeeYooIsDebug<'a, 'b, T: 'a + 'b, U: Debug> { + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:470:41 + | +LL | enum TeeYooWhereOutlivesAy<'a, T, U> where U: 'a { + | ^^^^^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:476:58 + | +LL | enum TeeYooWhereOutlivesAyIsDebug<'a, T, U> where U: 'a + Debug { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:482:63 + | +LL | enum TeeYooWhereIsDebugOutlivesAy<'a, T, U> where U: Debug + 'a { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:488:44 + | +LL | enum TeeOutlivesAyYooWhereIsDebug<'a, T: 'a, U> where U: Debug { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:494:48 + | +LL | enum TeeYooWhereOutlivesAyBee<'a, 'b, T, U> where U: 'a + 'b { + | ^^^^^^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:500:65 + | +LL | enum TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U> where U: 'a + 'b + Debug { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:506:70 + | +LL | enum TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U> where U: Debug + 'a + 'b { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:512:51 + | +LL | enum TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T: 'a + 'b, U> where U: Debug { + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:518:60 + | +LL | enum TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U> where T: 'a, U: Debug { + | ^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:524:67 + | +LL | enum TeeWhereOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where T: 'a + 'b, U: Debug { + | ^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:530:30 + | +LL | enum BeeOutlivesAy<'a, 'b: 'a> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:535:36 + | +LL | enum BeeWhereOutlivesAy<'a, 'b> where 'b: 'a { + | ^^^^^^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:540:33 + | +LL | enum BeeOutlivesAyTee<'a, 'b: 'a, T> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:546:42 + | +LL | enum BeeWhereOutlivesAyTee<'a, 'b, T> where 'b: 'a { + | ^^^^^^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:552:50 + | +LL | enum BeeWhereOutlivesAyTeeWhereBee<'a, 'b, T> where 'b: 'a, T: 'b { + | ^^^^^^^^^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:557:52 + | +LL | enum BeeWhereOutlivesAyTeeWhereAyBee<'a, 'b, T> where 'b: 'a, T: 'a + 'b { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:563:38 + | +LL | enum BeeOutlivesAyTeeDebug<'a, 'b: 'a, T: Debug> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:568:59 + | +LL | enum BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where 'b: 'a, T: Debug { + | ^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:577:30 + | +LL | union TeeOutlivesAy<'a, T: 'a> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:582:39 + | +LL | union TeeOutlivesAyIsDebug<'a, T: 'a + Debug> { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:587:44 + | +LL | union TeeIsDebugOutlivesAy<'a, T: Debug + 'a> { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:592:37 + | +LL | union TeeOutlivesAyBee<'a, 'b, T: 'a + 'b> { + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:597:46 + | +LL | union TeeOutlivesAyBeeIsDebug<'a, 'b, T: 'a + 'b + Debug> { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:602:51 + | +LL | union TeeIsDebugOutlivesAyBee<'a, 'b, T: Debug + 'a + 'b> { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:607:36 + | +LL | union TeeWhereOutlivesAy<'a, T> where T: 'a { + | ^^^^^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:612:53 + | +LL | union TeeWhereOutlivesAyIsDebug<'a, T> where T: 'a + Debug { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:617:58 + | +LL | union TeeWhereIsDebugOutlivesAy<'a, T> where T: Debug + 'a { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:622:43 + | +LL | union TeeWhereOutlivesAyBee<'a, 'b, T> where T: 'a + 'b { + | ^^^^^^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:627:60 + | +LL | union TeeWhereOutlivesAyBeeIsDebug<'a, 'b, T> where T: 'a + 'b + Debug { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:632:65 + | +LL | union TeeWhereIsDebugOutlivesAyBee<'a, 'b, T> where T: Debug + 'a + 'b { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:637:36 + | +LL | union TeeYooOutlivesAy<'a, T, U: 'a> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:643:45 + | +LL | union TeeYooOutlivesAyIsDebug<'a, T, U: 'a + Debug> { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:649:50 + | +LL | union TeeYooIsDebugOutlivesAy<'a, T, U: Debug + 'a> { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:655:40 + | +LL | union TeeOutlivesAyYooIsDebug<'a, T: 'a, U: Debug> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:661:43 + | +LL | union TeeYooOutlivesAyBee<'a, 'b, T, U: 'a + 'b> { + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:667:52 + | +LL | union TeeYooOutlivesAyBeeIsDebug<'a, 'b, T, U: 'a + 'b + Debug> { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:673:57 + | +LL | union TeeYooIsDebugOutlivesAyBee<'a, 'b, T, U: Debug + 'a + 'b> { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:679:47 + | +LL | union TeeOutlivesAyBeeYooIsDebug<'a, 'b, T: 'a + 'b, U: Debug> { + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:685:42 + | +LL | union TeeYooWhereOutlivesAy<'a, T, U> where U: 'a { + | ^^^^^^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:691:59 + | +LL | union TeeYooWhereOutlivesAyIsDebug<'a, T, U> where U: 'a + Debug { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:697:64 + | +LL | union TeeYooWhereIsDebugOutlivesAy<'a, T, U> where U: Debug + 'a { + | ^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:703:45 + | +LL | union TeeOutlivesAyYooWhereIsDebug<'a, T: 'a, U> where U: Debug { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:709:49 + | +LL | union TeeYooWhereOutlivesAyBee<'a, 'b, T, U> where U: 'a + 'b { + | ^^^^^^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:715:66 + | +LL | union TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U> where U: 'a + 'b + Debug { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:721:71 + | +LL | union TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U> where U: Debug + 'a + 'b { + | ^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:727:52 + | +LL | union TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T: 'a + 'b, U> where U: Debug { + | ^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:733:61 + | +LL | union TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U> where T: 'a, U: Debug { + | ^^^^^^^ help: remove this bound + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:739:68 + | +LL | union TeeWhereOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where T: 'a + 'b, U: Debug { + | ^^^^^^^^^^^^ help: remove these bounds + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:745:31 + | +LL | union BeeOutlivesAy<'a, 'b: 'a> { + | ^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:151:42 + --> $DIR/edition-lint-infer-outlives.rs:750:37 | -LL | struct TeeOutlivesAyYooWhereIsDebug<'a, T: 'a, U> where U: Debug { - | ^^^^ help: remove this bound +LL | union BeeWhereOutlivesAy<'a, 'b> where 'b: 'a { + | ^^^^^^^^^^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:157:46 + --> $DIR/edition-lint-infer-outlives.rs:755:34 | -LL | struct TeeYooWhereOutlivesAyBee<'a, 'b, T, U> where U: 'a + 'b { - | ^^^^^^^^^^^^^^^^^ help: remove these bounds +LL | union BeeOutlivesAyTee<'a, 'b: 'a, T> { + | ^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:163:63 + --> $DIR/edition-lint-infer-outlives.rs:760:43 | -LL | struct TeeYooWhereOutlivesAyBeeIsDebug<'a, 'b, T, U> where U: 'a + 'b + Debug { - | ^^^^^^^^^^ help: remove these bounds +LL | union BeeWhereOutlivesAyTee<'a, 'b, T> where 'b: 'a { + | ^^^^^^^^^^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:169:68 + --> $DIR/edition-lint-infer-outlives.rs:765:51 | -LL | struct TeeYooWhereIsDebugOutlivesAyBee<'a, 'b, T, U> where U: Debug + 'a + 'b { - | ^^^^^^^^^^ help: remove these bounds +LL | union BeeWhereOutlivesAyTeeWhereBee<'a, 'b, T> where 'b: 'a, T: 'b { + | ^^^^^^^^^^^^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:175:49 + --> $DIR/edition-lint-infer-outlives.rs:770:53 | -LL | struct TeeOutlivesAyBeeYooWhereIsDebug<'a, 'b, T: 'a + 'b, U> where U: Debug { - | ^^^^^^^^^ help: remove these bounds +LL | union BeeWhereOutlivesAyTeeWhereAyBee<'a, 'b, T> where 'b: 'a, T: 'a + 'b { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these bounds error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:181:58 + --> $DIR/edition-lint-infer-outlives.rs:775:39 | -LL | struct TeeWhereOutlivesAyYooWhereIsDebug<'a, T, U> where T: 'a, U: Debug { - | ^^^^^^^ help: remove this bound +LL | union BeeOutlivesAyTeeDebug<'a, 'b: 'a, T: Debug> { + | ^^^^ help: remove this bound error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:187:65 + --> $DIR/edition-lint-infer-outlives.rs:780:60 | -LL | struct TeeWhereOutlivesAyBeeYooWhereIsDebug<'a, 'b, T, U> where T: 'a + 'b, U: Debug { - | ^^^^^^^^^^^^ help: remove these bounds +LL | union BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where 'b: 'a, T: Debug { + | ^^^^^^^^ help: remove this bound -error: aborting due to 30 previous errors +error: aborting due to 152 previous errors diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed index a9f4a1edbb68d..e51ce5d1d5b83 100644 --- a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed +++ b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed @@ -12,8 +12,11 @@ //~^ ERROR unused extern crate -use edition_lint_paths as bar; -//~^ ERROR `extern crate` is not idiomatic in the new edition +// Shouldn't suggest changing to `use`, as `bar` +// would no longer be added to the prelude which could cause +// compilation errors for imports that use `bar` in other +// modules. See #57672. +extern crate edition_lint_paths as bar; fn main() { // This is not considered to *use* the `extern crate` in Rust 2018: @@ -23,4 +26,3 @@ fn main() { // But this should be a use of the (renamed) crate: crate::bar::foo(); } - diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs index 02e3e83df128c..debbf085d6182 100644 --- a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs +++ b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs @@ -12,8 +12,11 @@ extern crate edition_lint_paths; //~^ ERROR unused extern crate +// Shouldn't suggest changing to `use`, as `bar` +// would no longer be added to the prelude which could cause +// compilation errors for imports that use `bar` in other +// modules. See #57672. extern crate edition_lint_paths as bar; -//~^ ERROR `extern crate` is not idiomatic in the new edition fn main() { // This is not considered to *use* the `extern crate` in Rust 2018: @@ -23,4 +26,3 @@ fn main() { // But this should be a use of the (renamed) crate: crate::bar::foo(); } - diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr index f3f9193948667..13980c70a82aa 100644 --- a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr +++ b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr @@ -11,11 +11,5 @@ LL | #![deny(rust_2018_idioms)] | ^^^^^^^^^^^^^^^^ = note: #[deny(unused_extern_crates)] implied by #[deny(rust_2018_idioms)] -error: `extern crate` is not idiomatic in the new edition - --> $DIR/extern-crate-idiomatic-in-2018.rs:15:1 - | -LL | extern crate edition_lint_paths as bar; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use` - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic.fixed b/src/test/ui/rust-2018/extern-crate-idiomatic.fixed index 38dddf38d30eb..3111b1dabcbfd 100644 --- a/src/test/ui/rust-2018/extern-crate-idiomatic.fixed +++ b/src/test/ui/rust-2018/extern-crate-idiomatic.fixed @@ -16,4 +16,3 @@ use edition_lint_paths::foo; fn main() { foo(); } - diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic.rs b/src/test/ui/rust-2018/extern-crate-idiomatic.rs index 38dddf38d30eb..3111b1dabcbfd 100644 --- a/src/test/ui/rust-2018/extern-crate-idiomatic.rs +++ b/src/test/ui/rust-2018/extern-crate-idiomatic.rs @@ -16,4 +16,3 @@ use edition_lint_paths::foo; fn main() { foo(); } - diff --git a/src/test/ui/rust-2018/extern-crate-referenced-by-self-path.fixed b/src/test/ui/rust-2018/extern-crate-referenced-by-self-path.fixed index e249c8a026d96..11b9a67ed7030 100644 --- a/src/test/ui/rust-2018/extern-crate-referenced-by-self-path.fixed +++ b/src/test/ui/rust-2018/extern-crate-referenced-by-self-path.fixed @@ -15,4 +15,3 @@ use self::edition_lint_paths::foo; fn main() { foo(); } - diff --git a/src/test/ui/rust-2018/extern-crate-referenced-by-self-path.rs b/src/test/ui/rust-2018/extern-crate-referenced-by-self-path.rs index e249c8a026d96..11b9a67ed7030 100644 --- a/src/test/ui/rust-2018/extern-crate-referenced-by-self-path.rs +++ b/src/test/ui/rust-2018/extern-crate-referenced-by-self-path.rs @@ -15,4 +15,3 @@ use self::edition_lint_paths::foo; fn main() { foo(); } - diff --git a/src/test/ui/rust-2018/extern-crate-rename.fixed b/src/test/ui/rust-2018/extern-crate-rename.fixed index aa8b935289e44..c4c9bdf58c3d8 100644 --- a/src/test/ui/rust-2018/extern-crate-rename.fixed +++ b/src/test/ui/rust-2018/extern-crate-rename.fixed @@ -16,4 +16,3 @@ use crate::my_crate::foo; fn main() { foo(); } - diff --git a/src/test/ui/rust-2018/extern-crate-rename.rs b/src/test/ui/rust-2018/extern-crate-rename.rs index 98c7d341bff22..8f14f2f1fec87 100644 --- a/src/test/ui/rust-2018/extern-crate-rename.rs +++ b/src/test/ui/rust-2018/extern-crate-rename.rs @@ -16,4 +16,3 @@ use my_crate::foo; fn main() { foo(); } - diff --git a/src/test/ui/rust-2018/extern-crate-submod.fixed b/src/test/ui/rust-2018/extern-crate-submod.fixed index 0564e58f3c7dd..2a8e24db0bdc5 100644 --- a/src/test/ui/rust-2018/extern-crate-submod.fixed +++ b/src/test/ui/rust-2018/extern-crate-submod.fixed @@ -23,4 +23,3 @@ use crate::m::edition_lint_paths::foo; fn main() { foo(); } - diff --git a/src/test/ui/rust-2018/extern-crate-submod.rs b/src/test/ui/rust-2018/extern-crate-submod.rs index 206f3903b4716..f3a357917cc7f 100644 --- a/src/test/ui/rust-2018/extern-crate-submod.rs +++ b/src/test/ui/rust-2018/extern-crate-submod.rs @@ -23,4 +23,3 @@ use m::edition_lint_paths::foo; fn main() { foo(); } - diff --git a/src/test/ui/rust-2018/future-proofing-locals.rs b/src/test/ui/rust-2018/future-proofing-locals.rs index 1e53c2d1daca4..2c388cf3713b0 100644 --- a/src/test/ui/rust-2018/future-proofing-locals.rs +++ b/src/test/ui/rust-2018/future-proofing-locals.rs @@ -1,6 +1,7 @@ // edition:2018 #![allow(non_camel_case_types)] +#![allow(unused_imports)] mod T { pub struct U; diff --git a/src/test/ui/rust-2018/future-proofing-locals.stderr b/src/test/ui/rust-2018/future-proofing-locals.stderr index 413e199cd646c..7021489a6ddcf 100644 --- a/src/test/ui/rust-2018/future-proofing-locals.stderr +++ b/src/test/ui/rust-2018/future-proofing-locals.stderr @@ -1,55 +1,55 @@ error: imports cannot refer to type parameters - --> $DIR/future-proofing-locals.rs:13:9 + --> $DIR/future-proofing-locals.rs:14:9 | -LL | use T as _; //~ ERROR imports cannot refer to type parameters +LL | use T as _; | ^ error: imports cannot refer to type parameters - --> $DIR/future-proofing-locals.rs:14:9 + --> $DIR/future-proofing-locals.rs:15:9 | -LL | use T::U; //~ ERROR imports cannot refer to type parameters +LL | use T::U; | ^ error: imports cannot refer to type parameters - --> $DIR/future-proofing-locals.rs:15:9 + --> $DIR/future-proofing-locals.rs:16:9 | -LL | use T::*; //~ ERROR imports cannot refer to type parameters +LL | use T::*; | ^ error: imports cannot refer to type parameters - --> $DIR/future-proofing-locals.rs:19:9 + --> $DIR/future-proofing-locals.rs:20:9 | -LL | use T; //~ ERROR imports cannot refer to type parameters +LL | use T; | ^ error: imports cannot refer to local variables - --> $DIR/future-proofing-locals.rs:25:9 + --> $DIR/future-proofing-locals.rs:26:9 | -LL | use x as _; //~ ERROR imports cannot refer to local variables +LL | use x as _; | ^ error: imports cannot refer to local variables - --> $DIR/future-proofing-locals.rs:31:9 + --> $DIR/future-proofing-locals.rs:32:9 | -LL | use x; //~ ERROR imports cannot refer to local variables +LL | use x; | ^ error: imports cannot refer to local variables - --> $DIR/future-proofing-locals.rs:37:17 + --> $DIR/future-proofing-locals.rs:38:17 | -LL | use x; //~ ERROR imports cannot refer to local variables +LL | use x; | ^ error: imports cannot refer to type parameters - --> $DIR/future-proofing-locals.rs:45:10 + --> $DIR/future-proofing-locals.rs:46:10 | -LL | use {T as _, x}; //~ ERROR imports cannot refer to type parameters +LL | use {T as _, x}; | ^ error: imports cannot refer to local variables - --> $DIR/future-proofing-locals.rs:45:18 + --> $DIR/future-proofing-locals.rs:46:18 | -LL | use {T as _, x}; //~ ERROR imports cannot refer to type parameters +LL | use {T as _, x}; | ^ error: aborting due to 9 previous errors diff --git a/src/test/ui/rust-2018/issue-54006.stderr b/src/test/ui/rust-2018/issue-54006.stderr index 6c6d7720be2c2..1978138a68878 100644 --- a/src/test/ui/rust-2018/issue-54006.stderr +++ b/src/test/ui/rust-2018/issue-54006.stderr @@ -2,7 +2,7 @@ error[E0432]: unresolved import `alloc` --> $DIR/issue-54006.rs:6:5 | LL | use alloc::vec; - | ^^^^^ did you mean `core::alloc`? + | ^^^^^ help: a similar path exists: `core::alloc` error: cannot determine resolution for the macro `vec` --> $DIR/issue-54006.rs:10:18 diff --git a/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr b/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr index 7f3f6ccf39e07..49aaff620d66f 100644 --- a/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr +++ b/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr @@ -1,7 +1,7 @@ error: unused extern crate --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:12:1 | -LL | / #[cfg(blandiloquence)] //~ HELP remove it +LL | / #[cfg(blandiloquence)] LL | | extern crate edition_lint_paths; | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | |________________________________| diff --git a/src/test/ui/rust-2018/local-path-suggestions-2015.stderr b/src/test/ui/rust-2018/local-path-suggestions-2015.stderr index be642c3bcdcbb..666864a18af88 100644 --- a/src/test/ui/rust-2018/local-path-suggestions-2015.stderr +++ b/src/test/ui/rust-2018/local-path-suggestions-2015.stderr @@ -1,8 +1,11 @@ error[E0432]: unresolved import `foobar` --> $DIR/local-path-suggestions-2015.rs:24:5 | -LL | use foobar::Baz; //~ ERROR unresolved import `foobar` - | ^^^^^^ did you mean `aux_baz::foobar`? +LL | use foobar::Baz; + | ^^^^^^ + | | + | unresolved import + | help: a similar path exists: `aux_baz::foobar` error: aborting due to previous error diff --git a/src/test/ui/rust-2018/local-path-suggestions-2018.stderr b/src/test/ui/rust-2018/local-path-suggestions-2018.stderr index 71c8289264ffe..40f3d6bf1cf1e 100644 --- a/src/test/ui/rust-2018/local-path-suggestions-2018.stderr +++ b/src/test/ui/rust-2018/local-path-suggestions-2018.stderr @@ -1,16 +1,16 @@ error[E0432]: unresolved import `foo` --> $DIR/local-path-suggestions-2018.rs:10:9 | -LL | use foo::Bar; //~ ERROR unresolved import `foo` - | ^^^ did you mean `crate::foo`? +LL | use foo::Bar; + | ^^^ help: a similar path exists: `crate::foo` | = note: `use` statements changed in Rust 2018; read more at error[E0432]: unresolved import `foobar` --> $DIR/local-path-suggestions-2018.rs:19:5 | -LL | use foobar::Baz; //~ ERROR unresolved import `foobar` - | ^^^^^^ did you mean `baz::foobar`? +LL | use foobar::Baz; + | ^^^^^^ help: a similar path exists: `baz::foobar` error: aborting due to 2 previous errors diff --git a/src/test/ui/rust-2018/macro-use-warned-against.stderr b/src/test/ui/rust-2018/macro-use-warned-against.stderr index 55213a77a2c0e..c3e459606e107 100644 --- a/src/test/ui/rust-2018/macro-use-warned-against.stderr +++ b/src/test/ui/rust-2018/macro-use-warned-against.stderr @@ -1,7 +1,7 @@ warning: deprecated `#[macro_use]` directive used to import macros should be replaced at use sites with a `use` statement to import the macro instead --> $DIR/macro-use-warned-against.rs:7:1 | -LL | #[macro_use] //~ WARN should be replaced at use sites with a `use` statement +LL | #[macro_use] | ^^^^^^^^^^^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![warn(macro_use_extern_crate, unused)] warning: unused `#[macro_use]` import --> $DIR/macro-use-warned-against.rs:9:1 | -LL | #[macro_use] //~ WARN unused `#[macro_use]` +LL | #[macro_use] | ^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/rust-2018/remove-extern-crate.fixed b/src/test/ui/rust-2018/remove-extern-crate.fixed index a977e00c0131b..14575d18c236a 100644 --- a/src/test/ui/rust-2018/remove-extern-crate.fixed +++ b/src/test/ui/rust-2018/remove-extern-crate.fixed @@ -4,11 +4,14 @@ // aux-build:remove-extern-crate.rs // compile-flags:--extern remove_extern_crate -#![feature(alloc)] #![warn(rust_2018_idioms)] -use core as another_name; +// Shouldn't suggest changing to `use`, as `another_name` +// would no longer be added to the prelude which could cause +// compilation errors for imports that use `another_name` in other +// modules. See #57672. +extern crate core as another_name; use remove_extern_crate; #[macro_use] extern crate remove_extern_crate as something_else; diff --git a/src/test/ui/rust-2018/remove-extern-crate.rs b/src/test/ui/rust-2018/remove-extern-crate.rs index cafe82d846ed8..0ee85f34e40d9 100644 --- a/src/test/ui/rust-2018/remove-extern-crate.rs +++ b/src/test/ui/rust-2018/remove-extern-crate.rs @@ -4,10 +4,13 @@ // aux-build:remove-extern-crate.rs // compile-flags:--extern remove_extern_crate -#![feature(alloc)] #![warn(rust_2018_idioms)] extern crate core; +// Shouldn't suggest changing to `use`, as `another_name` +// would no longer be added to the prelude which could cause +// compilation errors for imports that use `another_name` in other +// modules. See #57672. extern crate core as another_name; use remove_extern_crate; #[macro_use] diff --git a/src/test/ui/rust-2018/remove-extern-crate.stderr b/src/test/ui/rust-2018/remove-extern-crate.stderr index 4e08b7aa6a03d..5de0dfe961338 100644 --- a/src/test/ui/rust-2018/remove-extern-crate.stderr +++ b/src/test/ui/rust-2018/remove-extern-crate.stderr @@ -1,24 +1,18 @@ warning: unused extern crate - --> $DIR/remove-extern-crate.rs:10:1 + --> $DIR/remove-extern-crate.rs:9:1 | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ help: remove it | note: lint level defined here - --> $DIR/remove-extern-crate.rs:8:9 + --> $DIR/remove-extern-crate.rs:7:9 | LL | #![warn(rust_2018_idioms)] | ^^^^^^^^^^^^^^^^ = note: #[warn(unused_extern_crates)] implied by #[warn(rust_2018_idioms)] warning: `extern crate` is not idiomatic in the new edition - --> $DIR/remove-extern-crate.rs:11:1 - | -LL | extern crate core as another_name; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use` - -warning: `extern crate` is not idiomatic in the new edition - --> $DIR/remove-extern-crate.rs:29:5 + --> $DIR/remove-extern-crate.rs:32:5 | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ help: convert it to a `use` diff --git a/src/test/ui/rust-2018/suggestions-not-always-applicable.stderr b/src/test/ui/rust-2018/suggestions-not-always-applicable.stderr index 53ea9e6457268..19e87b664cc9e 100644 --- a/src/test/ui/rust-2018/suggestions-not-always-applicable.stderr +++ b/src/test/ui/rust-2018/suggestions-not-always-applicable.stderr @@ -1,7 +1,7 @@ warning: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition --> $DIR/suggestions-not-always-applicable.rs:17:5 | -LL | #[foo] //~ WARN: absolute paths must start with +LL | #[foo] | ^^^^^^ | note: lint level defined here @@ -16,7 +16,7 @@ LL | #![warn(rust_2018_compatibility)] warning: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition --> $DIR/suggestions-not-always-applicable.rs:17:5 | -LL | #[foo] //~ WARN: absolute paths must start with +LL | #[foo] | ^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! diff --git a/src/test/ui/rust-2018/trait-import-suggestions.stderr b/src/test/ui/rust-2018/trait-import-suggestions.stderr index e4c17680c90a5..a81181228dfda 100644 --- a/src/test/ui/rust-2018/trait-import-suggestions.stderr +++ b/src/test/ui/rust-2018/trait-import-suggestions.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `foobar` found for type `u32` in the current scope --> $DIR/trait-import-suggestions.rs:22:11 | -LL | x.foobar(); //~ ERROR no method named `foobar` +LL | x.foobar(); | ^^^^^^ | = help: items from traits can only be used if the trait is in scope @@ -11,7 +11,7 @@ LL | x.foobar(); //~ ERROR no method named `foobar` error[E0599]: no method named `bar` found for type `u32` in the current scope --> $DIR/trait-import-suggestions.rs:28:7 | -LL | x.bar(); //~ ERROR no method named `bar` +LL | x.bar(); | ^^^ | = help: items from traits can only be used if the trait is in scope @@ -23,16 +23,14 @@ LL | use crate::foo::Bar; error[E0599]: no method named `baz` found for type `u32` in the current scope --> $DIR/trait-import-suggestions.rs:29:7 | -LL | x.baz(); //~ ERROR no method named `baz` +LL | x.baz(); | ^^^ error[E0599]: no function or associated item named `from_str` found for type `u32` in the current scope --> $DIR/trait-import-suggestions.rs:30:18 | -LL | let y = u32::from_str("33"); //~ ERROR no function or associated item named `from_str` - | -----^^^^^^^^ - | | - | function or associated item not found in `u32` +LL | let y = u32::from_str("33"); + | ^^^^^^^^ function or associated item not found in `u32` | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope, perhaps add a `use` for it: diff --git a/src/test/ui/rust-2018/uniform-paths/auxiliary/cross-crate.rs b/src/test/ui/rust-2018/uniform-paths/auxiliary/cross-crate.rs new file mode 100644 index 0000000000000..4aa5d1870000d --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths/auxiliary/cross-crate.rs @@ -0,0 +1,5 @@ +// edition:2018 + +pub use ignore as built_in_attr; +pub use u8 as built_in_type; +pub use rustfmt as tool_mod; diff --git a/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.stderr b/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.stderr index 4a01ba5088f62..db176876382d6 100644 --- a/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.stderr +++ b/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.stderr @@ -1,7 +1,7 @@ error[E0659]: `sub` is ambiguous (name vs any other name during import resolution) --> $DIR/block-scoped-shadow-nested.rs:16:13 | -LL | use sub::bar; //~ ERROR `sub` is ambiguous +LL | use sub::bar; | ^^^ ambiguous name | note: `sub` could refer to the module imported here diff --git a/src/test/ui/rust-2018/uniform-paths/cross-crate.rs b/src/test/ui/rust-2018/uniform-paths/cross-crate.rs new file mode 100644 index 0000000000000..27d6dbf4683e3 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths/cross-crate.rs @@ -0,0 +1,11 @@ +// edition:2018 +// aux-build:cross-crate.rs + +extern crate cross_crate; +use cross_crate::*; + +#[built_in_attr] //~ ERROR cannot use a built-in attribute through an import +#[tool_mod::skip] //~ ERROR cannot use a tool module through an import +fn main() { + let _: built_in_type; // OK +} diff --git a/src/test/ui/rust-2018/uniform-paths/cross-crate.stderr b/src/test/ui/rust-2018/uniform-paths/cross-crate.stderr new file mode 100644 index 0000000000000..fdde75faf5f04 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths/cross-crate.stderr @@ -0,0 +1,26 @@ +error: cannot use a built-in attribute through an import + --> $DIR/cross-crate.rs:7:3 + | +LL | #[built_in_attr] + | ^^^^^^^^^^^^^ + | +note: the built-in attribute imported here + --> $DIR/cross-crate.rs:5:5 + | +LL | use cross_crate::*; + | ^^^^^^^^^^^^^^ + +error: cannot use a tool module through an import + --> $DIR/cross-crate.rs:8:3 + | +LL | #[tool_mod::skip] + | ^^^^^^^^ + | +note: the tool module imported here + --> $DIR/cross-crate.rs:5:5 + | +LL | use cross_crate::*; + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/rust-2018/uniform-paths/deadlock.stderr b/src/test/ui/rust-2018/uniform-paths/deadlock.stderr index 8bbc8f33039b9..b4ac15c588ebd 100644 --- a/src/test/ui/rust-2018/uniform-paths/deadlock.stderr +++ b/src/test/ui/rust-2018/uniform-paths/deadlock.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import --> $DIR/deadlock.rs:4:5 | -LL | use foo::bar; //~ ERROR unresolved import +LL | use foo::bar; | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/rust-2018/uniform-paths/issue-54253.stderr b/src/test/ui/rust-2018/uniform-paths/issue-54253.stderr index 3d7176265a27e..adde635903515 100644 --- a/src/test/ui/rust-2018/uniform-paths/issue-54253.stderr +++ b/src/test/ui/rust-2018/uniform-paths/issue-54253.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `crate::version` --> $DIR/issue-54253.rs:10:9 | -LL | use crate::version; //~ ERROR unresolved import `crate::version` +LL | use crate::version; | ^^^^^^^^^^^^^^ no `version` in the root error: aborting due to previous error diff --git a/src/test/ui/rust-2018/uniform-paths/issue-56596.stderr b/src/test/ui/rust-2018/uniform-paths/issue-56596.stderr index 293d0ec6a7208..b1c0b461db4ad 100644 --- a/src/test/ui/rust-2018/uniform-paths/issue-56596.stderr +++ b/src/test/ui/rust-2018/uniform-paths/issue-56596.stderr @@ -1,7 +1,7 @@ error[E0659]: `issue_56596` is ambiguous (name vs any other name during import resolution) --> $DIR/issue-56596.rs:12:5 | -LL | use issue_56596; //~ ERROR `issue_56596` is ambiguous +LL | use issue_56596; | ^^^^^^^^^^^ ambiguous name | = note: `issue_56596` could refer to an extern crate passed with `--extern` diff --git a/src/test/ui/rust-2018/uniform-paths/macro-rules.stderr b/src/test/ui/rust-2018/uniform-paths/macro-rules.stderr index 684f5fceac15f..f1b5e0c5efaac 100644 --- a/src/test/ui/rust-2018/uniform-paths/macro-rules.stderr +++ b/src/test/ui/rust-2018/uniform-paths/macro-rules.stderr @@ -1,19 +1,19 @@ error[E0364]: `legacy_macro` is private, and cannot be re-exported --> $DIR/macro-rules.rs:11:13 | -LL | pub use legacy_macro as _; //~ ERROR `legacy_macro` is private, and cannot be re-exported +LL | pub use legacy_macro as _; | ^^^^^^^^^^^^^^^^^ | note: consider marking `legacy_macro` as `pub` in the imported module --> $DIR/macro-rules.rs:11:13 | -LL | pub use legacy_macro as _; //~ ERROR `legacy_macro` is private, and cannot be re-exported +LL | pub use legacy_macro as _; | ^^^^^^^^^^^^^^^^^ error[E0659]: `legacy_macro` is ambiguous (name vs any other name during import resolution) --> $DIR/macro-rules.rs:31:13 | -LL | use legacy_macro as _; //~ ERROR `legacy_macro` is ambiguous +LL | use legacy_macro as _; | ^^^^^^^^^^^^ ambiguous name | note: `legacy_macro` could refer to the macro defined here @@ -30,5 +30,5 @@ LL | macro legacy_macro() {} error: aborting due to 2 previous errors -Some errors occurred: E0364, E0659. +Some errors have detailed explanations: E0364, E0659. For more information about an error, try `rustc --explain E0364`. diff --git a/src/test/ui/rust-2018/uniform-paths/prelude-fail-2.stderr b/src/test/ui/rust-2018/uniform-paths/prelude-fail-2.stderr index 40b8fcf7158eb..fc6453193bc98 100644 --- a/src/test/ui/rust-2018/uniform-paths/prelude-fail-2.stderr +++ b/src/test/ui/rust-2018/uniform-paths/prelude-fail-2.stderr @@ -1,7 +1,7 @@ error: cannot use a built-in attribute through an import --> $DIR/prelude-fail-2.rs:15:3 | -LL | #[imported_inline] //~ ERROR cannot use a built-in attribute through an import +LL | #[imported_inline] | ^^^^^^^^^^^^^^^ | note: the built-in attribute imported here @@ -13,13 +13,13 @@ LL | use inline as imported_inline; error: cannot use a built-in attribute through an import --> $DIR/prelude-fail-2.rs:16:3 | -LL | #[builtin::imported_inline] //~ ERROR cannot use a built-in attribute through an import +LL | #[builtin::imported_inline] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot use a tool module through an import --> $DIR/prelude-fail-2.rs:17:3 | -LL | #[imported_rustfmt::skip] //~ ERROR cannot use a tool module through an import +LL | #[imported_rustfmt::skip] | ^^^^^^^^^^^^^^^^ | note: the tool module imported here @@ -31,7 +31,7 @@ LL | use rustfmt as imported_rustfmt; error: cannot use a tool module through an import --> $DIR/prelude-fail-2.rs:18:13 | -LL | #[tool_mod::imported_rustfmt::skip] //~ ERROR cannot use a tool module through an import +LL | #[tool_mod::imported_rustfmt::skip] | ^^^^^^^^^^^^^^^^ | note: the tool module imported here diff --git a/src/test/ui/rust-2018/uniform-paths/prelude-fail.stderr b/src/test/ui/rust-2018/uniform-paths/prelude-fail.stderr index fdfea416b12f1..42daf7c6fb12f 100644 --- a/src/test/ui/rust-2018/uniform-paths/prelude-fail.stderr +++ b/src/test/ui/rust-2018/uniform-paths/prelude-fail.stderr @@ -1,14 +1,14 @@ error: cannot import a built-in macro --> $DIR/prelude-fail.rs:4:5 | -LL | use env as env_imported; //~ ERROR cannot import a built-in macro +LL | use env as env_imported; | ^^^^^^^^^^^^^^^^^^^ error[E0432]: unresolved import `rustfmt` --> $DIR/prelude-fail.rs:7:5 | -LL | use rustfmt::skip as imported_rustfmt_skip; //~ ERROR unresolved import `rustfmt` - | ^^^^^^^ not a module `rustfmt` +LL | use rustfmt::skip as imported_rustfmt_skip; + | ^^^^^^^ `rustfmt` is a tool module, not a module error: aborting due to 2 previous errors diff --git a/src/test/ui/rustc-args-required-const.stderr b/src/test/ui/rustc-args-required-const.stderr index 7a1caf3c40fe7..8b302692053a2 100644 --- a/src/test/ui/rustc-args-required-const.stderr +++ b/src/test/ui/rustc-args-required-const.stderr @@ -1,13 +1,13 @@ error: argument 1 is required to be a constant --> $DIR/rustc-args-required-const.rs:24:5 | -LL | foo(a); //~ ERROR: argument 1 is required to be a constant +LL | foo(a); | ^^^^^^ error: argument 2 is required to be a constant --> $DIR/rustc-args-required-const.rs:26:5 | -LL | bar(a, a); //~ ERROR: argument 2 is required to be a constant +LL | bar(a, a); | ^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/rustc-args-required-const2.stderr b/src/test/ui/rustc-args-required-const2.stderr index 005f68fa2e64d..a8906ad3bc551 100644 --- a/src/test/ui/rustc-args-required-const2.stderr +++ b/src/test/ui/rustc-args-required-const2.stderr @@ -1,7 +1,7 @@ error: this function can only be invoked directly, not through a function pointer --> $DIR/rustc-args-required-const2.rs:8:13 | -LL | let a = foo; //~ ERROR: this function can only be invoked directly +LL | let a = foo; | ^^^ error: aborting due to previous error diff --git a/src/test/ui/rustc-error.stderr b/src/test/ui/rustc-error.stderr index c6b9cf77e5887..dcbc0e1feb213 100644 --- a/src/test/ui/rustc-error.stderr +++ b/src/test/ui/rustc-error.stderr @@ -2,7 +2,7 @@ error: compilation successful --> $DIR/rustc-error.rs:4:1 | LL | / fn main() { -LL | | //~^ ERROR compilation successful +LL | | LL | | } | |_^ diff --git a/src/test/ui/safe-extern-statics-mut.stderr b/src/test/ui/safe-extern-statics-mut.stderr index 4eecce6d3d31c..3880388341445 100644 --- a/src/test/ui/safe-extern-statics-mut.stderr +++ b/src/test/ui/safe-extern-statics-mut.stderr @@ -1,7 +1,7 @@ error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/safe-extern-statics-mut.rs:11:13 | -LL | let b = B; //~ ERROR use of mutable static is unsafe +LL | let b = B; | ^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior @@ -9,7 +9,7 @@ LL | let b = B; //~ ERROR use of mutable static is unsafe error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/safe-extern-statics-mut.rs:12:14 | -LL | let rb = &B; //~ ERROR use of mutable static is unsafe +LL | let rb = &B; | ^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior @@ -17,7 +17,7 @@ LL | let rb = &B; //~ ERROR use of mutable static is unsafe error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/safe-extern-statics-mut.rs:13:14 | -LL | let xb = XB; //~ ERROR use of mutable static is unsafe +LL | let xb = XB; | ^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior @@ -25,7 +25,7 @@ LL | let xb = XB; //~ ERROR use of mutable static is unsafe error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/safe-extern-statics-mut.rs:14:15 | -LL | let xrb = &XB; //~ ERROR use of mutable static is unsafe +LL | let xrb = &XB; | ^^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior diff --git a/src/test/ui/safe-extern-statics.stderr b/src/test/ui/safe-extern-statics.stderr index 11ade798ba478..86976a2c932d1 100644 --- a/src/test/ui/safe-extern-statics.stderr +++ b/src/test/ui/safe-extern-statics.stderr @@ -1,7 +1,7 @@ error: use of extern static is unsafe and requires unsafe function or block (error E0133) --> $DIR/safe-extern-statics.rs:13:13 | -LL | let a = A; //~ ERROR use of extern static is unsafe +LL | let a = A; | ^ | = note: #[deny(safe_extern_statics)] on by default @@ -12,7 +12,7 @@ LL | let a = A; //~ ERROR use of extern static is unsafe error: use of extern static is unsafe and requires unsafe function or block (error E0133) --> $DIR/safe-extern-statics.rs:15:14 | -LL | let ra = &A; //~ ERROR use of extern static is unsafe +LL | let ra = &A; | ^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -22,7 +22,7 @@ LL | let ra = &A; //~ ERROR use of extern static is unsafe error: use of extern static is unsafe and requires unsafe function or block (error E0133) --> $DIR/safe-extern-statics.rs:17:14 | -LL | let xa = XA; //~ ERROR use of extern static is unsafe +LL | let xa = XA; | ^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -32,7 +32,7 @@ LL | let xa = XA; //~ ERROR use of extern static is unsafe error: use of extern static is unsafe and requires unsafe function or block (error E0133) --> $DIR/safe-extern-statics.rs:19:15 | -LL | let xra = &XA; //~ ERROR use of extern static is unsafe +LL | let xra = &XA; | ^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/src/test/ui/save-analysis/emit-notifications.nll.stderr b/src/test/ui/save-analysis/emit-notifications.nll.stderr new file mode 100644 index 0000000000000..60734cedb50e3 --- /dev/null +++ b/src/test/ui/save-analysis/emit-notifications.nll.stderr @@ -0,0 +1,2 @@ +{"artifact":"$TEST_BUILD_DIR/save-analysis/emit-notifications.nll/save-analysis/libemit_notifications.json","emit":"save-analysis"} +{"artifact":"$TEST_BUILD_DIR/save-analysis/emit-notifications.nll/libemit_notifications.rlib","emit":"link"} diff --git a/src/test/ui/save-analysis/emit-notifications.rs b/src/test/ui/save-analysis/emit-notifications.rs new file mode 100644 index 0000000000000..ebc2717499843 --- /dev/null +++ b/src/test/ui/save-analysis/emit-notifications.rs @@ -0,0 +1,7 @@ +// compile-pass +// compile-flags: -Zsave-analysis -Zemit-artifact-notifications +// compile-flags: --crate-type rlib --error-format=json +// ignore-pass +// ^-- needed because otherwise, the .stderr file changes with --pass check + +pub fn foo() {} diff --git a/src/test/ui/save-analysis/emit-notifications.stderr b/src/test/ui/save-analysis/emit-notifications.stderr new file mode 100644 index 0000000000000..e16f60f8b5faf --- /dev/null +++ b/src/test/ui/save-analysis/emit-notifications.stderr @@ -0,0 +1,2 @@ +{"artifact":"$TEST_BUILD_DIR/save-analysis/emit-notifications/save-analysis/libemit_notifications.json","emit":"save-analysis"} +{"artifact":"$TEST_BUILD_DIR/save-analysis/emit-notifications/libemit_notifications.rlib","emit":"link"} diff --git a/src/test/ui/save-analysis/issue-59134-0.rs b/src/test/ui/save-analysis/issue-59134-0.rs new file mode 100644 index 0000000000000..a0871ca18094e --- /dev/null +++ b/src/test/ui/save-analysis/issue-59134-0.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zsave-analysis + +// Check that this doesn't ICE when processing associated const (field expr). + +pub fn f() { + trait Trait {} + impl dyn Trait { + const FLAG: u32 = bogus.field; //~ ERROR cannot find value `bogus` + } +} + +fn main() {} diff --git a/src/test/ui/save-analysis/issue-59134-0.stderr b/src/test/ui/save-analysis/issue-59134-0.stderr new file mode 100644 index 0000000000000..4e9b2e6fdeb4d --- /dev/null +++ b/src/test/ui/save-analysis/issue-59134-0.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `bogus` in this scope + --> $DIR/issue-59134-0.rs:8:27 + | +LL | const FLAG: u32 = bogus.field; + | ^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/save-analysis/issue-59134-1.rs b/src/test/ui/save-analysis/issue-59134-1.rs new file mode 100644 index 0000000000000..3cb629777a497 --- /dev/null +++ b/src/test/ui/save-analysis/issue-59134-1.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zsave-analysis + +// Check that this doesn't ICE when processing associated const (type). + +fn func() { + trait Trait { + type MyType; + const CONST: Self::MyType = bogus.field; //~ ERROR cannot find value `bogus` + } +} + +fn main() {} diff --git a/src/test/ui/save-analysis/issue-59134-1.stderr b/src/test/ui/save-analysis/issue-59134-1.stderr new file mode 100644 index 0000000000000..bdc335eaac041 --- /dev/null +++ b/src/test/ui/save-analysis/issue-59134-1.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `bogus` in this scope + --> $DIR/issue-59134-1.rs:8:37 + | +LL | const CONST: Self::MyType = bogus.field; + | ^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/arbitrary-self-types-not-object-safe.rs b/src/test/ui/self/arbitrary-self-types-not-object-safe.rs similarity index 86% rename from src/test/ui/arbitrary-self-types-not-object-safe.rs rename to src/test/ui/self/arbitrary-self-types-not-object-safe.rs index 2c1fd937a65ad..7443d888c9ec8 100644 --- a/src/test/ui/arbitrary-self-types-not-object-safe.rs +++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.rs @@ -28,13 +28,13 @@ impl Bar for usize { } fn make_foo() { - let x = Rc::new(5usize) as Rc; + let x = Rc::new(5usize) as Rc; //~^ ERROR E0038 //~| ERROR E0038 } fn make_bar() { - let x = Rc::new(5usize) as Rc; + let x = Rc::new(5usize) as Rc; x.bar(); } diff --git a/src/test/ui/arbitrary-self-types-not-object-safe.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.stderr similarity index 78% rename from src/test/ui/arbitrary-self-types-not-object-safe.stderr rename to src/test/ui/self/arbitrary-self-types-not-object-safe.stderr index dacab1222aba3..e45bc2657f1ea 100644 --- a/src/test/ui/arbitrary-self-types-not-object-safe.stderr +++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.stderr @@ -1,15 +1,15 @@ error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/arbitrary-self-types-not-object-safe.rs:31:32 | -LL | let x = Rc::new(5usize) as Rc; - | ^^^^^^^ the trait `Foo` cannot be made into an object +LL | let x = Rc::new(5usize) as Rc; + | ^^^^^^^^^^^ the trait `Foo` cannot be made into an object | = note: method `foo`'s receiver cannot be dispatched on error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/arbitrary-self-types-not-object-safe.rs:31:13 | -LL | let x = Rc::new(5usize) as Rc; +LL | let x = Rc::new(5usize) as Rc; | ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | = note: method `foo`'s receiver cannot be dispatched on diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime.rs b/src/test/ui/self/arbitrary_self_types_pin_lifetime.rs new file mode 100644 index 0000000000000..3002013881249 --- /dev/null +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime.rs @@ -0,0 +1,60 @@ +// check-pass + +use std::pin::Pin; +use std::task::{Context, Poll}; + +struct Foo; + +impl Foo { + fn pin_ref(self: Pin<&Self>) -> Pin<&Self> { self } + + fn pin_mut(self: Pin<&mut Self>) -> Pin<&mut Self> { self } + + fn pin_pin_pin_ref(self: Pin>>) -> Pin>> { self } + + fn pin_ref_impl_trait(self: Pin<&Self>) -> impl Clone + '_ { self } + + fn b(self: Pin<&Foo>, f: &Foo) -> Pin<&Foo> { self } +} + +type Alias = Pin; +impl Foo { + fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> Alias<&Self> { self } +} + +struct Bar { + field1: T, + field2: U, +} + +impl Bar { + fn fields(self: Pin<&mut Self>) -> (Pin<&mut T>, Pin<&mut U>) { + let this = self.get_mut(); + (Pin::new(&mut this.field1), Pin::new(&mut this.field2)) + } +} + +trait AsyncBufRead { + fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) + -> Poll>; +} + +struct Baz(Vec); + +impl AsyncBufRead for Baz { + fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) + -> Poll> + { + Poll::Ready(Ok(&self.get_mut().0)) + } +} + +fn main() { + let mut foo = Foo; + { Pin::new(&foo).pin_ref() }; + { Pin::new(&mut foo).pin_mut() }; + { Pin::new(Pin::new(Pin::new(&foo))).pin_pin_pin_ref() }; + { Pin::new(&foo).pin_ref_impl_trait() }; + let mut bar = Bar { field1: 0u8, field2: 1u8 }; + { Pin::new(&mut bar).fields() }; +} diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr new file mode 100644 index 0000000000000..dcfc9ba511d74 --- /dev/null +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:8:31 + | +LL | fn f(self: Pin<&Self>) -> impl Clone { self } + | - ^^^^^^^^^^ opaque type requires that `'1` must outlive `'static` + | | + | let's call the lifetime of this reference `'1` +help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a constraint + | +LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs new file mode 100644 index 0000000000000..ad8959727cbee --- /dev/null +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs @@ -0,0 +1,13 @@ +// compile-fail + +use std::pin::Pin; + +struct Foo; + +impl Foo { + fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR cannot infer an appropriate lifetime +} + +fn main() { + { Pin::new(&Foo).f() }; +} diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr new file mode 100644 index 0000000000000..5118280e7ec0c --- /dev/null +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -0,0 +1,20 @@ +error: cannot infer an appropriate lifetime + --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:8:44 + | +LL | fn f(self: Pin<&Self>) -> impl Clone { self } + | ---------- ^^^^ ...but this borrow... + | | + | this return type evaluates to the `'static` lifetime... + | +note: ...can't outlive the anonymous lifetime #1 defined on the method body at 8:5 + --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:8:5 + | +LL | fn f(self: Pin<&Self>) -> impl Clone { self } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 8:5 + | +LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr new file mode 100644 index 0000000000000..8a0f1a804ad82 --- /dev/null +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:46 + | +LL | fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } + | - - ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | | | + | | let's call the lifetime of this reference `'1` + | let's call the lifetime of this reference `'2` + +error: lifetime may not live long enough + --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:10:69 + | +LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } + | - - ^^^^^^^^^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | | | + | | let's call the lifetime of this reference `'1` + | let's call the lifetime of this reference `'2` + +error: lifetime may not live long enough + --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:15:58 + | +LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } + | -- ---- has type `std::pin::Pin<&'1 Foo>` ^^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` + | | + | lifetime `'a` defined here + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs new file mode 100644 index 0000000000000..fc5f94201b81a --- /dev/null +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs @@ -0,0 +1,18 @@ +// compile-fail + +use std::pin::Pin; + +struct Foo; + +impl Foo { + fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } //~ ERROR E0623 + + fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } //~ ERROR E0623 +} + +type Alias = Pin; +impl Foo { + fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } //~ ERROR E0623 +} + +fn main() {} diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr new file mode 100644 index 0000000000000..3296e14f806e1 --- /dev/null +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr @@ -0,0 +1,26 @@ +error[E0623]: lifetime mismatch + --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:46 + | +LL | fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } + | ---- ---- ^ ...but data from `f` is returned here + | | + | this parameter and the return type are declared with different lifetimes... + +error[E0623]: lifetime mismatch + --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:10:76 + | +LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } + | ---- ----------------- ^ ...but data from `f` is returned here + | | + | this parameter and the return type are declared with different lifetimes... + +error[E0623]: lifetime mismatch + --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:15:58 + | +LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } + | ------ --- ^^^ ...but data from `arg` is returned here + | | + | this parameter and the return type are declared with different lifetimes... + +error: aborting due to 3 previous errors + diff --git a/src/test/run-pass/arbitrary_self_types_pointers_and_wrappers.rs b/src/test/ui/self/arbitrary_self_types_pointers_and_wrappers.rs similarity index 99% rename from src/test/run-pass/arbitrary_self_types_pointers_and_wrappers.rs rename to src/test/ui/self/arbitrary_self_types_pointers_and_wrappers.rs index 6904c29111ee3..65fec3becacee 100644 --- a/src/test/run-pass/arbitrary_self_types_pointers_and_wrappers.rs +++ b/src/test/ui/self/arbitrary_self_types_pointers_and_wrappers.rs @@ -1,3 +1,4 @@ +// run-pass #![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)] #![feature(rustc_attrs)] diff --git a/src/test/run-pass/self/arbitrary_self_types_raw_pointer_struct.rs b/src/test/ui/self/arbitrary_self_types_raw_pointer_struct.rs similarity index 100% rename from src/test/run-pass/self/arbitrary_self_types_raw_pointer_struct.rs rename to src/test/ui/self/arbitrary_self_types_raw_pointer_struct.rs diff --git a/src/test/run-pass/self/arbitrary_self_types_raw_pointer_trait.rs b/src/test/ui/self/arbitrary_self_types_raw_pointer_trait.rs similarity index 86% rename from src/test/run-pass/self/arbitrary_self_types_raw_pointer_trait.rs rename to src/test/ui/self/arbitrary_self_types_raw_pointer_trait.rs index acbe896eebe77..0a9370e6f5ac7 100644 --- a/src/test/run-pass/self/arbitrary_self_types_raw_pointer_trait.rs +++ b/src/test/ui/self/arbitrary_self_types_raw_pointer_trait.rs @@ -34,8 +34,8 @@ impl Foo for u32 { } fn main() { - let null_i32 = ptr::null::() as *const Foo; - let null_u32 = ptr::null::() as *const Foo; + let null_i32 = ptr::null::() as *const dyn Foo; + let null_u32 = ptr::null::() as *const dyn Foo; assert_eq!("I'm an i32!", null_i32.foo()); assert_eq!("I'm a u32!", null_u32.foo()); @@ -45,7 +45,7 @@ fn main() { assert_eq!("I'm an i32!", valid_i32_thin.foo()); assert_eq!(5, unsafe { valid_i32_thin.bar() }); assert_eq!(5, unsafe { (&valid_i32_thin as *const *const i32).complicated() }); - let valid_i32_fat = valid_i32_thin as *const Foo; + let valid_i32_fat = valid_i32_thin as *const dyn Foo; assert_eq!("I'm an i32!", valid_i32_fat.foo()); assert_eq!(5, unsafe { valid_i32_fat.bar() }); @@ -54,7 +54,7 @@ fn main() { assert_eq!("I'm a u32!", valid_u32_thin.foo()); assert_eq!(18, unsafe { valid_u32_thin.bar() }); assert_eq!(18, unsafe { (&valid_u32_thin as *const *const u32).complicated() }); - let valid_u32_fat = valid_u32_thin as *const Foo; + let valid_u32_fat = valid_u32_thin as *const dyn Foo; assert_eq!("I'm a u32!", valid_u32_fat.foo()); assert_eq!(18, unsafe { valid_u32_fat.bar() }); diff --git a/src/test/run-pass/self/arbitrary_self_types_silly.rs b/src/test/ui/self/arbitrary_self_types_silly.rs similarity index 100% rename from src/test/run-pass/self/arbitrary_self_types_silly.rs rename to src/test/ui/self/arbitrary_self_types_silly.rs diff --git a/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs b/src/test/ui/self/arbitrary_self_types_stdlib_pointers.rs similarity index 99% rename from src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs rename to src/test/ui/self/arbitrary_self_types_stdlib_pointers.rs index 9f6a647a07b31..29563fbbd8676 100644 --- a/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs +++ b/src/test/ui/self/arbitrary_self_types_stdlib_pointers.rs @@ -1,3 +1,4 @@ +// run-pass #![feature(arbitrary_self_types)] #![feature(rustc_attrs)] diff --git a/src/test/run-pass/self/arbitrary_self_types_struct.rs b/src/test/ui/self/arbitrary_self_types_struct.rs similarity index 100% rename from src/test/run-pass/self/arbitrary_self_types_struct.rs rename to src/test/ui/self/arbitrary_self_types_struct.rs diff --git a/src/test/run-pass/self/arbitrary_self_types_trait.rs b/src/test/ui/self/arbitrary_self_types_trait.rs similarity index 100% rename from src/test/run-pass/self/arbitrary_self_types_trait.rs rename to src/test/ui/self/arbitrary_self_types_trait.rs diff --git a/src/test/run-pass/self/arbitrary_self_types_unsized_struct.rs b/src/test/ui/self/arbitrary_self_types_unsized_struct.rs similarity index 100% rename from src/test/run-pass/self/arbitrary_self_types_unsized_struct.rs rename to src/test/ui/self/arbitrary_self_types_unsized_struct.rs diff --git a/src/test/run-pass/self/auxiliary/explicit_self_xcrate.rs b/src/test/ui/self/auxiliary/explicit_self_xcrate.rs similarity index 100% rename from src/test/run-pass/self/auxiliary/explicit_self_xcrate.rs rename to src/test/ui/self/auxiliary/explicit_self_xcrate.rs diff --git a/src/test/run-pass/self/builtin-superkinds-self-type.rs b/src/test/ui/self/builtin-superkinds-self-type.rs similarity index 100% rename from src/test/run-pass/self/builtin-superkinds-self-type.rs rename to src/test/ui/self/builtin-superkinds-self-type.rs diff --git a/src/test/run-pass/self/by-value-self-in-mut-slot.rs b/src/test/ui/self/by-value-self-in-mut-slot.rs similarity index 100% rename from src/test/run-pass/self/by-value-self-in-mut-slot.rs rename to src/test/ui/self/by-value-self-in-mut-slot.rs diff --git a/src/test/ui/self/elision/README.md b/src/test/ui/self/elision/README.md new file mode 100644 index 0000000000000..7ace2e0c89039 --- /dev/null +++ b/src/test/ui/self/elision/README.md @@ -0,0 +1,44 @@ +Test cases intended to document behavior and try to exhaustively +explore the combinations. + +## Confidence + +These tests are not yet considered 100% normative, in that some +aspects of the current behavior are not desirable. This is expressed +in the "confidence" field in the following table. Values: + +| Confidence | Interpretation | +| --- | --- | +| 100% | this will remain recommended behavior | +| 75% | unclear whether we will continue to accept this | +| 50% | this will likely be deprecated but remain valid | +| 25% | this could change in the future | +| 0% | this is definitely bogus and will likely change in the future in *some* way | + +## Tests + +| Test file | `Self` type | Pattern | Current elision behavior | Confidence | +| --- | --- | --- | --- | --- | +| `self.rs` | `Struct` | `Self` | ignore `self` parameter | 100% | +| `struct.rs` | `Struct` | `Struct` | ignore `self` parameter | 100% | +| `alias.rs` | `Struct` | `Alias` | ignore `self` parameter | 100% | +| `ref-self.rs` | `Struct` | `&Self` | take lifetime from `&Self` | 100% | +| `ref-mut-self.rs` | `Struct` | `&mut Self` | take lifetime from `&mut Self` | 100% | +| `ref-struct.rs` | `Struct` | `&Struct` | take lifetime from `&Self` | 50% | +| `ref-mut-struct.rs` | `Struct` | `&mut Struct` | take lifetime from `&mut Self` | 50% | +| `ref-alias.rs` | `Struct` | `&Alias` | ignore `Alias` | 0% | +| `ref-mut-alias.rs` | `Struct` | `&mut Alias` | ignore `Alias` | 0% | +| `lt-self.rs` | `Struct<'a>` | `Self` | ignore `Self` (and hence `'a`) | 25% | +| `lt-struct.rs` | `Struct<'a>` | `Self` | ignore `Self` (and hence `'a`) | 0% | +| `lt-alias.rs` | `Alias<'a>` | `Self` | ignore `Self` (and hence `'a`) | 0% | +| `lt-ref-self.rs` | `Struct<'a>` | `&Self` | take lifetime from `&Self` | 75% | + +In each case, we test the following patterns: + +- `self: XXX` +- `self: Box` +- `self: Pin` +- `self: Box>` +- `self: Box>` + +In the non-reference cases, `Pin` causes errors so we substitute `Rc`. diff --git a/src/test/ui/self/elision/alias.rs b/src/test/ui/self/elision/alias.rs new file mode 100644 index 0000000000000..b5aacfaeec427 --- /dev/null +++ b/src/test/ui/self/elision/alias.rs @@ -0,0 +1,36 @@ +// check-pass + +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::rc::Rc; + +struct Struct { } + +type Alias = Struct; + +impl Struct { + // Test using an alias for `Struct`: + + fn alias(self: Alias, f: &u32) -> &u32 { + f + } + + fn box_Alias(self: Box, f: &u32) -> &u32 { + f + } + + fn rc_Alias(self: Rc, f: &u32) -> &u32 { + f + } + + fn box_box_Alias(self: Box>, f: &u32) -> &u32 { + f + } + + fn box_rc_Alias(self: Box>, f: &u32) -> &u32 { + f + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/assoc.rs b/src/test/ui/self/elision/assoc.rs new file mode 100644 index 0000000000000..163eb49383a87 --- /dev/null +++ b/src/test/ui/self/elision/assoc.rs @@ -0,0 +1,40 @@ +// check-pass + +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::rc::Rc; + +trait Trait { + type AssocType; +} + +struct Struct { } + +impl Trait for Struct { + type AssocType = Self; +} + +impl Struct { + fn assoc(self: ::AssocType, f: &u32) -> &u32 { + f + } + + fn box_AssocType(self: Box<::AssocType>, f: &u32) -> &u32 { + f + } + + fn rc_AssocType(self: Rc<::AssocType>, f: &u32) -> &u32 { + f + } + + fn box_box_AssocType(self: Box::AssocType>>, f: &u32) -> &u32 { + f + } + + fn box_rc_AssocType(self: Box::AssocType>>, f: &u32) -> &u32 { + f + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/lt-alias.rs b/src/test/ui/self/elision/lt-alias.rs new file mode 100644 index 0000000000000..df2300deda25f --- /dev/null +++ b/src/test/ui/self/elision/lt-alias.rs @@ -0,0 +1,38 @@ +// check-pass + +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::rc::Rc; + +struct Struct<'a> { x: &'a u32 } + +type Alias<'a> = Struct<'a>; + +impl<'a> Alias<'a> { + fn take_self(self, f: &u32) -> &u32 { + f + } + + fn take_Alias(self: Alias<'a>, f: &u32) -> &u32 { + f + } + + fn take_Box_Alias(self: Box>, f: &u32) -> &u32 { + f + } + + fn take_Box_Box_Alias(self: Box>>, f: &u32) -> &u32 { + f + } + + fn take_Rc_Alias(self: Rc>, f: &u32) -> &u32 { + f + } + + fn take_Box_Rc_Alias(self: Box>>, f: &u32) -> &u32 { + f + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/lt-assoc.rs b/src/test/ui/self/elision/lt-assoc.rs new file mode 100644 index 0000000000000..70573598fcb16 --- /dev/null +++ b/src/test/ui/self/elision/lt-assoc.rs @@ -0,0 +1,44 @@ +// check-pass + +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::rc::Rc; + +trait Trait { + type AssocType; +} + +struct Struct<'a> { x: &'a u32 } + +impl<'a> Trait for Struct<'a> { + type AssocType = Self; +} + +impl<'a> Struct<'a> { + fn take_self(self, f: &u32) -> &u32 { + f + } + + fn take_AssocType(self: as Trait>::AssocType, f: &u32) -> &u32 { + f + } + + fn take_Box_AssocType(self: Box< as Trait>::AssocType>, f: &u32) -> &u32 { + f + } + + fn take_Box_Box_AssocType(self: Box as Trait>::AssocType>>, f: &u32) -> &u32 { + f + } + + fn take_Rc_AssocType(self: Rc< as Trait>::AssocType>, f: &u32) -> &u32 { + f + } + + fn take_Box_Rc_AssocType(self: Box as Trait>::AssocType>>, f: &u32) -> &u32 { + f + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/lt-ref-self.nll.stderr b/src/test/ui/self/elision/lt-ref-self.nll.stderr new file mode 100644 index 0000000000000..e97a01e746d4b --- /dev/null +++ b/src/test/ui/self/elision/lt-ref-self.nll.stderr @@ -0,0 +1,62 @@ +error: lifetime may not live long enough + --> $DIR/lt-ref-self.rs:12:9 + | +LL | fn ref_self(&self, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/lt-ref-self.rs:18:9 + | +LL | fn ref_Self(self: &Self, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/lt-ref-self.rs:22:9 + | +LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/lt-ref-self.rs:26:9 + | +LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/lt-ref-self.rs:30:9 + | +LL | fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/lt-ref-self.rs:34:9 + | +LL | fn box_pin_Self(self: Box>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/self/elision/lt-ref-self.rs b/src/test/ui/self/elision/lt-ref-self.rs new file mode 100644 index 0000000000000..8abf2876a5c1b --- /dev/null +++ b/src/test/ui/self/elision/lt-ref-self.rs @@ -0,0 +1,38 @@ +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::pin::Pin; + +struct Struct<'a> { data: &'a u32 } + +impl<'a> Struct<'a> { + // Test using `&self` sugar: + + fn ref_self(&self, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + // Test using `&Self` explicitly: + + fn ref_Self(self: &Self, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_pin_Self(self: Box>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/lt-ref-self.stderr b/src/test/ui/self/elision/lt-ref-self.stderr new file mode 100644 index 0000000000000..f73b3eddd3821 --- /dev/null +++ b/src/test/ui/self/elision/lt-ref-self.stderr @@ -0,0 +1,62 @@ +error[E0623]: lifetime mismatch + --> $DIR/lt-ref-self.rs:12:9 + | +LL | fn ref_self(&self, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/lt-ref-self.rs:18:9 + | +LL | fn ref_Self(self: &Self, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/lt-ref-self.rs:22:9 + | +LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/lt-ref-self.rs:26:9 + | +LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/lt-ref-self.rs:30:9 + | +LL | fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/lt-ref-self.rs:34:9 + | +LL | fn box_pin_Self(self: Box>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/self/elision/lt-self.rs b/src/test/ui/self/elision/lt-self.rs new file mode 100644 index 0000000000000..9b0ee5e42a51a --- /dev/null +++ b/src/test/ui/self/elision/lt-self.rs @@ -0,0 +1,49 @@ +// check-pass + +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::pin::Pin; +use std::rc::Rc; + +struct Struct<'a> { + x: &'a u32 +} + +impl<'a> Struct<'a> { + fn take_self(self, f: &u32) -> &u32 { + f + } + + fn take_Self(self: Self, f: &u32) -> &u32 { + f + } + + fn take_Box_Self(self: Box, f: &u32) -> &u32 { + f + } + + fn take_Box_Box_Self(self: Box>, f: &u32) -> &u32 { + f + } + + fn take_Rc_Self(self: Rc, f: &u32) -> &u32 { + f + } + + fn take_Box_Rc_Self(self: Box>, f: &u32) -> &u32 { + f + } + + // N/A + //fn take_Pin_Self(self: Pin, f: &u32) -> &u32 { + // f + //} + + // N/A + //fn take_Box_Pin_Self(self: Box>, f: &u32) -> &u32 { + // f + //} +} + +fn main() { } diff --git a/src/test/ui/self/elision/lt-struct.rs b/src/test/ui/self/elision/lt-struct.rs new file mode 100644 index 0000000000000..e41dfbbe0bf0d --- /dev/null +++ b/src/test/ui/self/elision/lt-struct.rs @@ -0,0 +1,36 @@ +// check-pass + +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::rc::Rc; + +struct Struct<'a> { x: &'a u32 } + +impl<'a> Struct<'a> { + fn take_self(self, f: &u32) -> &u32 { + f + } + + fn take_Struct(self: Struct<'a>, f: &u32) -> &u32 { + f + } + + fn take_Box_Struct(self: Box>, f: &u32) -> &u32 { + f + } + + fn take_Box_Box_Struct(self: Box>>, f: &u32) -> &u32 { + f + } + + fn take_Rc_Struct(self: Rc>, f: &u32) -> &u32 { + f + } + + fn take_Box_Rc_Struct(self: Box>>, f: &u32) -> &u32 { + f + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/multiple-ref-self.rs b/src/test/ui/self/elision/multiple-ref-self.rs new file mode 100644 index 0000000000000..f39613d0c9007 --- /dev/null +++ b/src/test/ui/self/elision/multiple-ref-self.rs @@ -0,0 +1,43 @@ +// check-pass + +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::marker::PhantomData; +use std::ops::Deref; +use std::pin::Pin; + +struct Struct { } + +struct Wrap(T, PhantomData

    ); + +impl Deref for Wrap { + type Target = T; + fn deref(&self) -> &T { &self.0 } +} + +impl Struct { + // Test using multiple `&Self`: + + fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 { + f + } + + fn box_wrap_ref_Self_ref_Self(self: Box>, f: &u32) -> &u32 { + f + } + + fn pin_wrap_ref_Self_ref_Self(self: Pin>, f: &u32) -> &u32 { + f + } + + fn box_box_wrap_ref_Self_ref_Self(self: Box>>, f: &u32) -> &u32 { + f + } + + fn box_pin_wrap_ref_Self_ref_Self(self: Box>>, f: &u32) -> &u32 { + f + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/ref-alias.rs b/src/test/ui/self/elision/ref-alias.rs new file mode 100644 index 0000000000000..d83ac612235e3 --- /dev/null +++ b/src/test/ui/self/elision/ref-alias.rs @@ -0,0 +1,39 @@ +// check-pass + +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::pin::Pin; + +struct Struct { } + +type Alias = Struct; + +impl Struct { + // Test using an alias for `Struct`: + // + // FIXME. We currently fail to recognize this as the self type, which + // feels like a bug. + + fn ref_Alias(self: &Alias, f: &u32) -> &u32 { + f + } + + fn box_ref_Alias(self: Box<&Alias>, f: &u32) -> &u32 { + f + } + + fn pin_ref_Alias(self: Pin<&Alias>, f: &u32) -> &u32 { + f + } + + fn box_box_ref_Alias(self: Box>, f: &u32) -> &u32 { + f + } + + fn box_pin_ref_Alias(self: Box>, f: &u32) -> &u32 { + f + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/ref-assoc.rs b/src/test/ui/self/elision/ref-assoc.rs new file mode 100644 index 0000000000000..f9354bc884710 --- /dev/null +++ b/src/test/ui/self/elision/ref-assoc.rs @@ -0,0 +1,40 @@ +// check-pass + +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::pin::Pin; + +trait Trait { + type AssocType; +} + +struct Struct { } + +impl Trait for Struct { + type AssocType = Self; +} + +impl Struct { + fn ref_AssocType(self: &::AssocType, f: &u32) -> &u32 { + f + } + + fn box_ref_AssocType(self: Box<&::AssocType>, f: &u32) -> &u32 { + f + } + + fn pin_ref_AssocType(self: Pin<&::AssocType>, f: &u32) -> &u32 { + f + } + + fn box_box_ref_AssocType(self: Box::AssocType>>, f: &u32) -> &u32 { + f + } + + fn box_pin_ref_AssocType(self: Box::AssocType>>, f: &u32) -> &u32 { + f + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/ref-mut-alias.rs b/src/test/ui/self/elision/ref-mut-alias.rs new file mode 100644 index 0000000000000..395816f8f5d80 --- /dev/null +++ b/src/test/ui/self/elision/ref-mut-alias.rs @@ -0,0 +1,36 @@ +// check-pass + +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::pin::Pin; + +struct Struct { } + +type Alias = Struct; + +impl Struct { + // Test using an alias for `Struct`: + + fn ref_Alias(self: &mut Alias, f: &u32) -> &u32 { + f + } + + fn box_ref_Alias(self: Box<&mut Alias>, f: &u32) -> &u32 { + f + } + + fn pin_ref_Alias(self: Pin<&mut Alias>, f: &u32) -> &u32 { + f + } + + fn box_box_ref_Alias(self: Box>, f: &u32) -> &u32 { + f + } + + fn box_pin_ref_Alias(self: Box>, f: &u32) -> &u32 { + f + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/ref-mut-self.nll.stderr b/src/test/ui/self/elision/ref-mut-self.nll.stderr new file mode 100644 index 0000000000000..3a8ae3fdcba8c --- /dev/null +++ b/src/test/ui/self/elision/ref-mut-self.nll.stderr @@ -0,0 +1,62 @@ +error: lifetime may not live long enough + --> $DIR/ref-mut-self.rs:12:9 + | +LL | fn ref_self(&mut self, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-mut-self.rs:18:9 + | +LL | fn ref_Self(self: &mut Self, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-mut-self.rs:22:9 + | +LL | fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-mut-self.rs:26:9 + | +LL | fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-mut-self.rs:30:9 + | +LL | fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-mut-self.rs:34:9 + | +LL | fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/self/elision/ref-mut-self.rs b/src/test/ui/self/elision/ref-mut-self.rs new file mode 100644 index 0000000000000..a7ea47bb7f6de --- /dev/null +++ b/src/test/ui/self/elision/ref-mut-self.rs @@ -0,0 +1,38 @@ +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::pin::Pin; + +struct Struct { } + +impl Struct { + // Test using `&mut self` sugar: + + fn ref_self(&mut self, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + // Test using `&mut Self` explicitly: + + fn ref_Self(self: &mut Self, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/ref-mut-self.stderr b/src/test/ui/self/elision/ref-mut-self.stderr new file mode 100644 index 0000000000000..37984cd72fbac --- /dev/null +++ b/src/test/ui/self/elision/ref-mut-self.stderr @@ -0,0 +1,62 @@ +error[E0623]: lifetime mismatch + --> $DIR/ref-mut-self.rs:12:9 + | +LL | fn ref_self(&mut self, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-mut-self.rs:18:9 + | +LL | fn ref_Self(self: &mut Self, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-mut-self.rs:22:9 + | +LL | fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-mut-self.rs:26:9 + | +LL | fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-mut-self.rs:30:9 + | +LL | fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-mut-self.rs:34:9 + | +LL | fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/self/elision/ref-mut-struct.nll.stderr b/src/test/ui/self/elision/ref-mut-struct.nll.stderr new file mode 100644 index 0000000000000..66152ba40a5f5 --- /dev/null +++ b/src/test/ui/self/elision/ref-mut-struct.nll.stderr @@ -0,0 +1,52 @@ +error: lifetime may not live long enough + --> $DIR/ref-mut-struct.rs:12:9 + | +LL | fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-mut-struct.rs:16:9 + | +LL | fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-mut-struct.rs:20:9 + | +LL | fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-mut-struct.rs:24:9 + | +LL | fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-mut-struct.rs:28:9 + | +LL | fn box_pin_ref_Struct(self: Box>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/self/elision/ref-mut-struct.rs b/src/test/ui/self/elision/ref-mut-struct.rs new file mode 100644 index 0000000000000..795ddf8ac1354 --- /dev/null +++ b/src/test/ui/self/elision/ref-mut-struct.rs @@ -0,0 +1,32 @@ +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::pin::Pin; + +struct Struct { } + +impl Struct { + // Test using `&mut Struct` explicitly: + + fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_pin_ref_Struct(self: Box>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/ref-mut-struct.stderr b/src/test/ui/self/elision/ref-mut-struct.stderr new file mode 100644 index 0000000000000..2a4826905b94a --- /dev/null +++ b/src/test/ui/self/elision/ref-mut-struct.stderr @@ -0,0 +1,52 @@ +error[E0623]: lifetime mismatch + --> $DIR/ref-mut-struct.rs:12:9 + | +LL | fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-mut-struct.rs:16:9 + | +LL | fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-mut-struct.rs:20:9 + | +LL | fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-mut-struct.rs:24:9 + | +LL | fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-mut-struct.rs:28:9 + | +LL | fn box_pin_ref_Struct(self: Box>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/self/elision/ref-self.nll.stderr b/src/test/ui/self/elision/ref-self.nll.stderr new file mode 100644 index 0000000000000..20045be0527a4 --- /dev/null +++ b/src/test/ui/self/elision/ref-self.nll.stderr @@ -0,0 +1,72 @@ +error: lifetime may not live long enough + --> $DIR/ref-self.rs:21:9 + | +LL | fn ref_self(&self, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-self.rs:27:9 + | +LL | fn ref_Self(self: &Self, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-self.rs:31:9 + | +LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-self.rs:35:9 + | +LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-self.rs:39:9 + | +LL | fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-self.rs:43:9 + | +LL | fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-self.rs:47:9 + | +LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/self/elision/ref-self.rs b/src/test/ui/self/elision/ref-self.rs new file mode 100644 index 0000000000000..e389d8518ada4 --- /dev/null +++ b/src/test/ui/self/elision/ref-self.rs @@ -0,0 +1,51 @@ +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::marker::PhantomData; +use std::ops::Deref; +use std::pin::Pin; + +struct Struct { } + +struct Wrap(T, PhantomData

    ); + +impl Deref for Wrap { + type Target = T; + fn deref(&self) -> &T { &self.0 } +} + +impl Struct { + // Test using `&self` sugar: + + fn ref_self(&self, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + // Test using `&Self` explicitly: + + fn ref_Self(self: &Self, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 { + f //~ ERROR lifetime mismatch + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/ref-self.stderr b/src/test/ui/self/elision/ref-self.stderr new file mode 100644 index 0000000000000..611498f18da42 --- /dev/null +++ b/src/test/ui/self/elision/ref-self.stderr @@ -0,0 +1,72 @@ +error[E0623]: lifetime mismatch + --> $DIR/ref-self.rs:21:9 + | +LL | fn ref_self(&self, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-self.rs:27:9 + | +LL | fn ref_Self(self: &Self, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-self.rs:31:9 + | +LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-self.rs:35:9 + | +LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-self.rs:39:9 + | +LL | fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-self.rs:43:9 + | +LL | fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-self.rs:47:9 + | +LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 { + | --- --- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/self/elision/ref-struct.nll.stderr b/src/test/ui/self/elision/ref-struct.nll.stderr new file mode 100644 index 0000000000000..a258bc9f74390 --- /dev/null +++ b/src/test/ui/self/elision/ref-struct.nll.stderr @@ -0,0 +1,52 @@ +error: lifetime may not live long enough + --> $DIR/ref-struct.rs:12:9 + | +LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-struct.rs:16:9 + | +LL | fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-struct.rs:20:9 + | +LL | fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-struct.rs:24:9 + | +LL | fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/ref-struct.rs:28:9 + | +LL | fn box_pin_Struct(self: Box>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/self/elision/ref-struct.rs b/src/test/ui/self/elision/ref-struct.rs new file mode 100644 index 0000000000000..342d6d2b36357 --- /dev/null +++ b/src/test/ui/self/elision/ref-struct.rs @@ -0,0 +1,32 @@ +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::pin::Pin; + +struct Struct { } + +impl Struct { + // Test using `&Struct` explicitly: + + fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } + + fn box_pin_Struct(self: Box>, f: &u32) -> &u32 { + f //~ ERROR lifetime mismatch + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/ref-struct.stderr b/src/test/ui/self/elision/ref-struct.stderr new file mode 100644 index 0000000000000..186e651c143bf --- /dev/null +++ b/src/test/ui/self/elision/ref-struct.stderr @@ -0,0 +1,52 @@ +error[E0623]: lifetime mismatch + --> $DIR/ref-struct.rs:12:9 + | +LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-struct.rs:16:9 + | +LL | fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-struct.rs:20:9 + | +LL | fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-struct.rs:24:9 + | +LL | fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error[E0623]: lifetime mismatch + --> $DIR/ref-struct.rs:28:9 + | +LL | fn box_pin_Struct(self: Box>, f: &u32) -> &u32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | f + | ^ ...but data from `f` is returned here + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/self/elision/self.rs b/src/test/ui/self/elision/self.rs new file mode 100644 index 0000000000000..dbcef71ba14fc --- /dev/null +++ b/src/test/ui/self/elision/self.rs @@ -0,0 +1,36 @@ +// check-pass + +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::rc::Rc; + +struct Struct { } + +impl Struct { + fn take_self(self, f: &u32) -> &u32 { + f + } + + fn take_Self(self: Self, f: &u32) -> &u32 { + f + } + + fn take_Box_Self(self: Box, f: &u32) -> &u32 { + f + } + + fn take_Box_Box_Self(self: Box>, f: &u32) -> &u32 { + f + } + + fn take_Rc_Self(self: Rc, f: &u32) -> &u32 { + f + } + + fn take_Box_Rc_Self(self: Box>, f: &u32) -> &u32 { + f + } +} + +fn main() { } diff --git a/src/test/ui/self/elision/struct.rs b/src/test/ui/self/elision/struct.rs new file mode 100644 index 0000000000000..227e993bd3c61 --- /dev/null +++ b/src/test/ui/self/elision/struct.rs @@ -0,0 +1,32 @@ +// check-pass + +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] + +use std::rc::Rc; + +struct Struct { } + +impl Struct { + fn ref_Struct(self: Struct, f: &u32) -> &u32 { + f + } + + fn box_Struct(self: Box, f: &u32) -> &u32 { + f + } + + fn rc_Struct(self: Rc, f: &u32) -> &u32 { + f + } + + fn box_box_Struct(self: Box>, f: &u32) -> &u32 { + f + } + + fn box_rc_Struct(self: Box>, f: &u32) -> &u32 { + f + } +} + +fn main() { } diff --git a/src/test/run-pass/self/explicit-self-closures.rs b/src/test/ui/self/explicit-self-closures.rs similarity index 94% rename from src/test/run-pass/self/explicit-self-closures.rs rename to src/test/ui/self/explicit-self-closures.rs index 61be98fe3d3cd..1217823da116e 100644 --- a/src/test/run-pass/self/explicit-self-closures.rs +++ b/src/test/ui/self/explicit-self-closures.rs @@ -1,4 +1,4 @@ -// run-pass +// compile-pass #![allow(dead_code)] // Test to make sure that explicit self params work inside closures diff --git a/src/test/run-pass/self/explicit-self-generic.rs b/src/test/ui/self/explicit-self-generic.rs similarity index 100% rename from src/test/run-pass/self/explicit-self-generic.rs rename to src/test/ui/self/explicit-self-generic.rs diff --git a/src/test/run-pass/self/explicit-self-objects-uniq.rs b/src/test/ui/self/explicit-self-objects-uniq.rs similarity index 88% rename from src/test/run-pass/self/explicit-self-objects-uniq.rs rename to src/test/ui/self/explicit-self-objects-uniq.rs index f95686cf11234..0050bc7124d71 100644 --- a/src/test/run-pass/self/explicit-self-objects-uniq.rs +++ b/src/test/ui/self/explicit-self-objects-uniq.rs @@ -17,6 +17,6 @@ impl Foo for S { pub fn main() { let x = box S { x: 3 }; - let y = x as Box; + let y = x as Box; y.f(); } diff --git a/src/test/run-pass/self/explicit-self.rs b/src/test/ui/self/explicit-self.rs similarity index 100% rename from src/test/run-pass/self/explicit-self.rs rename to src/test/ui/self/explicit-self.rs diff --git a/src/test/run-pass/self/explicit_self_xcrate_exe.rs b/src/test/ui/self/explicit_self_xcrate_exe.rs similarity index 100% rename from src/test/run-pass/self/explicit_self_xcrate_exe.rs rename to src/test/ui/self/explicit_self_xcrate_exe.rs diff --git a/src/test/run-pass/self/move-self.rs b/src/test/ui/self/move-self.rs similarity index 100% rename from src/test/run-pass/self/move-self.rs rename to src/test/ui/self/move-self.rs diff --git a/src/test/run-pass/self/object-safety-sized-self-by-value-self.rs b/src/test/ui/self/object-safety-sized-self-by-value-self.rs similarity index 95% rename from src/test/run-pass/self/object-safety-sized-self-by-value-self.rs rename to src/test/ui/self/object-safety-sized-self-by-value-self.rs index ae0512666ce0b..43b1d8b9149a1 100644 --- a/src/test/run-pass/self/object-safety-sized-self-by-value-self.rs +++ b/src/test/ui/self/object-safety-sized-self-by-value-self.rs @@ -23,7 +23,7 @@ fn tick1(mut c: C) -> u32 { c.get() } -fn tick2(c: &mut Counter) { +fn tick2(c: &mut dyn Counter) { tick3(c); } diff --git a/src/test/run-pass/self/object-safety-sized-self-generic-method.rs b/src/test/ui/self/object-safety-sized-self-generic-method.rs similarity index 95% rename from src/test/run-pass/self/object-safety-sized-self-generic-method.rs rename to src/test/ui/self/object-safety-sized-self-generic-method.rs index 0b3f663373785..e0b0526a3338a 100644 --- a/src/test/run-pass/self/object-safety-sized-self-generic-method.rs +++ b/src/test/ui/self/object-safety-sized-self-generic-method.rs @@ -23,7 +23,7 @@ fn tick1(c: &mut C) { c.with(|i| ()); } -fn tick2(c: &mut Counter) { +fn tick2(c: &mut dyn Counter) { tick3(c); } diff --git a/src/test/run-pass/self/object-safety-sized-self-return-Self.rs b/src/test/ui/self/object-safety-sized-self-return-Self.rs similarity index 95% rename from src/test/run-pass/self/object-safety-sized-self-return-Self.rs rename to src/test/ui/self/object-safety-sized-self-return-Self.rs index e88dba0a4e8a3..222c754394569 100644 --- a/src/test/run-pass/self/object-safety-sized-self-return-Self.rs +++ b/src/test/ui/self/object-safety-sized-self-return-Self.rs @@ -23,7 +23,7 @@ fn preticked() -> C { c } -fn tick(c: &mut Counter) { +fn tick(c: &mut dyn Counter) { tick_generic(c); } diff --git a/src/test/run-pass/self/self-impl.rs b/src/test/ui/self/self-impl-2.rs similarity index 100% rename from src/test/run-pass/self/self-impl.rs rename to src/test/ui/self/self-impl-2.rs diff --git a/src/test/run-pass/self/self-in-mut-slot-default-method.rs b/src/test/ui/self/self-in-mut-slot-default-method.rs similarity index 100% rename from src/test/run-pass/self/self-in-mut-slot-default-method.rs rename to src/test/ui/self/self-in-mut-slot-default-method.rs diff --git a/src/test/run-pass/self/self-in-mut-slot-immediate-value.rs b/src/test/ui/self/self-in-mut-slot-immediate-value.rs similarity index 100% rename from src/test/run-pass/self/self-in-mut-slot-immediate-value.rs rename to src/test/ui/self/self-in-mut-slot-immediate-value.rs diff --git a/src/test/run-pass/self/self-in-typedefs.rs b/src/test/ui/self/self-in-typedefs.rs similarity index 96% rename from src/test/run-pass/self/self-in-typedefs.rs rename to src/test/ui/self/self-in-typedefs.rs index 9c0906013fafc..e4fe7324ef3a6 100644 --- a/src/test/run-pass/self/self-in-typedefs.rs +++ b/src/test/ui/self/self-in-typedefs.rs @@ -1,4 +1,4 @@ -// run-pass +// compile-pass #![feature(untagged_unions)] diff --git a/src/test/ui/self/self-infer.stderr b/src/test/ui/self/self-infer.stderr index 4b8fd7037795a..f91cfe5eb621b 100644 --- a/src/test/ui/self/self-infer.stderr +++ b/src/test/ui/self/self-infer.stderr @@ -1,13 +1,13 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/self-infer.rs:4:16 | -LL | fn f(self: _) {} //~ERROR the type placeholder `_` is not allowed within types on item sig +LL | fn f(self: _) {} | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/self-infer.rs:5:17 | -LL | fn g(self: &_) {} //~ERROR the type placeholder `_` is not allowed within types on item sig +LL | fn g(self: &_) {} | ^ not allowed in type signatures error: aborting due to 2 previous errors diff --git a/src/test/run-pass/self/self-re-assign.rs b/src/test/ui/self/self-re-assign.rs similarity index 100% rename from src/test/run-pass/self/self-re-assign.rs rename to src/test/ui/self/self-re-assign.rs diff --git a/src/test/run-pass/self/self-shadowing-import.rs b/src/test/ui/self/self-shadowing-import.rs similarity index 100% rename from src/test/run-pass/self/self-shadowing-import.rs rename to src/test/ui/self/self-shadowing-import.rs diff --git a/src/test/run-pass/self/self-type-param.rs b/src/test/ui/self/self-type-param.rs similarity index 93% rename from src/test/run-pass/self/self-type-param.rs rename to src/test/ui/self/self-type-param.rs index 6deae5f2d12f4..57e01caa692de 100644 --- a/src/test/run-pass/self/self-type-param.rs +++ b/src/test/ui/self/self-type-param.rs @@ -1,4 +1,4 @@ -// run-pass +// compile-pass #![allow(dead_code)] // pretty-expanded FIXME #23616 diff --git a/src/test/ui/self/self-vs-path-ambiguity.stderr b/src/test/ui/self/self-vs-path-ambiguity.stderr index 954d240e71b63..5ce6a81bfcfd7 100644 --- a/src/test/ui/self/self-vs-path-ambiguity.stderr +++ b/src/test/ui/self/self-vs-path-ambiguity.stderr @@ -1,7 +1,7 @@ error: unexpected lifetime `'a` in pattern --> $DIR/self-vs-path-ambiguity.rs:9:11 | -LL | fn i(&'a self::S: &S) {} //~ ERROR unexpected lifetime `'a` in pattern +LL | fn i(&'a self::S: &S) {} | ^^ unexpected lifetime error: aborting due to previous error diff --git a/src/test/ui/self/self_lifetime.rs b/src/test/ui/self/self_lifetime.rs new file mode 100644 index 0000000000000..f04bd83ab6e4c --- /dev/null +++ b/src/test/ui/self/self_lifetime.rs @@ -0,0 +1,15 @@ +// check-pass + +// https://github.com/rust-lang/rust/pull/60944#issuecomment-495346120 + +struct Foo<'a>(&'a ()); +impl<'a> Foo<'a> { + fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } +} + +type Alias = Foo<'static>; +impl Alias { + fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } +} + +fn main() {} diff --git a/src/test/ui/self/self_type_keyword-2.stderr b/src/test/ui/self/self_type_keyword-2.stderr index 55c8796e158f0..359410bc1cd6a 100644 --- a/src/test/ui/self/self_type_keyword-2.stderr +++ b/src/test/ui/self/self_type_keyword-2.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `self::Self` --> $DIR/self_type_keyword-2.rs:1:5 | -LL | use self::Self as Foo; //~ ERROR unresolved import `self::Self` +LL | use self::Self as Foo; | ^^^^^^^^^^^^^^^^^ no `Self` in the root error[E0531]: cannot find unit struct/variant or constant `Self` in this scope @@ -24,5 +24,4 @@ LL | Foo { x: Self } => (), error: aborting due to 4 previous errors -Some errors occurred: E0432, E0531. -For more information about an error, try `rustc --explain E0432`. +For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/self/self_type_keyword.rs b/src/test/ui/self/self_type_keyword.rs index 4a1681e4e2b8a..01b3309fcacb1 100644 --- a/src/test/ui/self/self_type_keyword.rs +++ b/src/test/ui/self/self_type_keyword.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z continue-parse-after-error - mod foo { struct Self; //~^ ERROR expected identifier, found keyword `Self` diff --git a/src/test/ui/self/self_type_keyword.stderr b/src/test/ui/self/self_type_keyword.stderr index f75377a220b49..b63de98b8e702 100644 --- a/src/test/ui/self/self_type_keyword.stderr +++ b/src/test/ui/self/self_type_keyword.stderr @@ -1,68 +1,68 @@ error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:4:10 + --> $DIR/self_type_keyword.rs:2:10 | LL | struct Self; | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:16:13 + --> $DIR/self_type_keyword.rs:14:13 | LL | ref Self => (), | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:18:13 + --> $DIR/self_type_keyword.rs:16:13 | LL | mut Self => (), | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:20:17 + --> $DIR/self_type_keyword.rs:18:17 | LL | ref mut Self => (), | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:24:15 + --> $DIR/self_type_keyword.rs:22:15 | LL | Foo { Self } => (), | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:30:26 + --> $DIR/self_type_keyword.rs:28:26 | LL | extern crate core as Self; | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:35:32 + --> $DIR/self_type_keyword.rs:33:32 | LL | use std::option::Option as Self; | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:40:11 + --> $DIR/self_type_keyword.rs:38:11 | LL | trait Self {} | ^^^^ expected identifier, found keyword error: lifetimes cannot use keyword names - --> $DIR/self_type_keyword.rs:8:12 + --> $DIR/self_type_keyword.rs:6:12 | LL | struct Bar<'Self>; | ^^^^^ error: cannot find macro `Self!` in this scope - --> $DIR/self_type_keyword.rs:22:9 + --> $DIR/self_type_keyword.rs:20:9 | LL | Self!() => (), | ^^^^ error[E0392]: parameter `'Self` is never used - --> $DIR/self_type_keyword.rs:8:12 + --> $DIR/self_type_keyword.rs:6:12 | LL | struct Bar<'Self>; - | ^^^^^ unused type parameter + | ^^^^^ unused parameter | = help: consider removing `'Self` or using a marker such as `std::marker::PhantomData` diff --git a/src/test/run-pass/self/string-self-append.rs b/src/test/ui/self/string-self-append.rs similarity index 100% rename from src/test/run-pass/self/string-self-append.rs rename to src/test/ui/self/string-self-append.rs diff --git a/src/test/ui/self/suggest-self.rs b/src/test/ui/self/suggest-self.rs index 9d81b6fd7ca4d..1cc17116ea7f7 100644 --- a/src/test/ui/self/suggest-self.rs +++ b/src/test/ui/self/suggest-self.rs @@ -39,4 +39,3 @@ fn main() { let len = this.len(); let len = my.len(); } - diff --git a/src/test/run-pass/self/ufcs-explicit-self.rs b/src/test/ui/self/ufcs-explicit-self.rs similarity index 100% rename from src/test/run-pass/self/ufcs-explicit-self.rs rename to src/test/ui/self/ufcs-explicit-self.rs diff --git a/src/test/run-pass/self/uniq-self-in-mut-slot.rs b/src/test/ui/self/uniq-self-in-mut-slot.rs similarity index 100% rename from src/test/run-pass/self/uniq-self-in-mut-slot.rs rename to src/test/ui/self/uniq-self-in-mut-slot.rs diff --git a/src/test/run-pass/self/where-for-self.rs b/src/test/ui/self/where-for-self.rs similarity index 100% rename from src/test/run-pass/self/where-for-self.rs rename to src/test/ui/self/where-for-self.rs diff --git a/src/test/ui/seq-args.stderr b/src/test/ui/seq-args.stderr index 81ba1abcd6dcb..2e7d901640e84 100644 --- a/src/test/ui/seq-args.stderr +++ b/src/test/ui/seq-args.stderr @@ -1,13 +1,13 @@ error[E0107]: wrong number of type arguments: expected 0, found 1 --> $DIR/seq-args.rs:4:13 | -LL | impl Seq for Vec { //~ ERROR wrong number of type arguments +LL | impl Seq for Vec { | ^ unexpected type argument error[E0107]: wrong number of type arguments: expected 0, found 1 --> $DIR/seq-args.rs:7:10 | -LL | impl Seq for u32 { //~ ERROR wrong number of type arguments +LL | impl Seq for u32 { | ^^^^ unexpected type argument error: aborting due to 2 previous errors diff --git a/src/test/ui/shadowed/shadowed-trait-methods.stderr b/src/test/ui/shadowed/shadowed-trait-methods.stderr index 38b604af29000..e05da17983f83 100644 --- a/src/test/ui/shadowed/shadowed-trait-methods.stderr +++ b/src/test/ui/shadowed/shadowed-trait-methods.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `f` found for type `()` in the current scope --> $DIR/shadowed-trait-methods.rs:13:8 | -LL | ().f() //~ ERROR no method +LL | ().f() | ^ | = help: items from traits can only be used if the trait is in scope diff --git a/src/test/ui/shadowed/shadowed-use-visibility.stderr b/src/test/ui/shadowed/shadowed-use-visibility.stderr index 60e474a845fe0..7c66fdf60b1d4 100644 --- a/src/test/ui/shadowed/shadowed-use-visibility.stderr +++ b/src/test/ui/shadowed/shadowed-use-visibility.stderr @@ -1,13 +1,13 @@ error[E0603]: module `bar` is private --> $DIR/shadowed-use-visibility.rs:9:14 | -LL | use foo::bar::f as g; //~ ERROR module `bar` is private +LL | use foo::bar::f as g; | ^^^ error[E0603]: module `f` is private --> $DIR/shadowed-use-visibility.rs:15:10 | -LL | use bar::f::f; //~ ERROR module `f` is private +LL | use bar::f::f; | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/shadowed/shadowing-in-the-same-pattern.stderr b/src/test/ui/shadowed/shadowing-in-the-same-pattern.stderr index 5d0fc912d95c3..71197efcaba54 100644 --- a/src/test/ui/shadowed/shadowing-in-the-same-pattern.stderr +++ b/src/test/ui/shadowed/shadowing-in-the-same-pattern.stderr @@ -1,13 +1,13 @@ error[E0416]: identifier `a` is bound more than once in the same pattern --> $DIR/shadowing-in-the-same-pattern.rs:3:10 | -LL | fn f((a, a): (isize, isize)) {} //~ ERROR identifier `a` is bound more than once +LL | fn f((a, a): (isize, isize)) {} | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern --> $DIR/shadowing-in-the-same-pattern.rs:6:13 | -LL | let (a, a) = (1, 1); //~ ERROR identifier `a` is bound more than once +LL | let (a, a) = (1, 1); | ^ used in a pattern more than once error: aborting due to 2 previous errors diff --git a/src/test/ui/shift-various-bad-types.stderr b/src/test/ui/shift-various-bad-types.stderr index 1bcff65ad754f..409fabb951adc 100644 --- a/src/test/ui/shift-various-bad-types.stderr +++ b/src/test/ui/shift-various-bad-types.stderr @@ -27,8 +27,12 @@ error[E0308]: mismatched types | LL | let _: i32 = 22_i64 >> 1_i32; | ^^^^^^^^^^^^^^^ expected i32, found i64 +help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit + | +LL | let _: i32 = (22_i64 >> 1_i32).try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.stderr index 0e88540bcc8e5..e10ac2e1192c1 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.stderr +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.stderr @@ -12,4 +12,3 @@ LL | simd_saturating_sub(z, z); error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic.stderr index 27493950af0c6..014db52504fc8 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic.stderr +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic.stderr @@ -84,4 +84,3 @@ LL | simd_xor(z, z); error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-bitmask.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-bitmask.stderr index d016838d098d4..f9135d1cbfeb5 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-bitmask.stderr +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-bitmask.stderr @@ -30,4 +30,3 @@ LL | let _: u128 = simd_bitmask(m64); error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-cast.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-cast.stderr index 6e33e3b30f505..333f92a40a871 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-cast.stderr +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-cast.stderr @@ -24,4 +24,3 @@ LL | simd_cast::<_, i32x8>(x); error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-comparison.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-comparison.stderr index d8da2e5ee5788..cea319f1bc86b 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-comparison.stderr +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-comparison.stderr @@ -108,4 +108,3 @@ LL | simd_ge::<_, i16x8>(x, x); error: aborting due to 18 previous errors -For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-elements.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-elements.stderr index 2f8ffb6035e53..3a84567b53a40 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-elements.stderr +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-elements.stderr @@ -90,4 +90,3 @@ LL | simd_shuffle8::<_, i32x2>(x, x, [0; 8]); error: aborting due to 15 previous errors -For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-reduction.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-reduction.stderr index b56de9613ddb4..144571cb26353 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-reduction.stderr +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-reduction.stderr @@ -72,4 +72,3 @@ LL | simd_reduce_mul_ordered(z, x); error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr index a46352c730802..e03e396fdf40d 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr @@ -48,4 +48,3 @@ LL | simd_select_bitmask("x", x, x); error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd-type.rs b/src/test/ui/simd-type.rs index d1e2efa6a3331..9e4b7e7656055 100644 --- a/src/test/ui/simd-type.rs +++ b/src/test/ui/simd-type.rs @@ -7,7 +7,4 @@ struct empty; //~ ERROR SIMD vector cannot be empty #[repr(simd)] struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous -#[repr(simd)] -struct int4(isize, isize, isize, isize); //~ ERROR SIMD vector element type should be machine type - fn main() {} diff --git a/src/test/ui/simd-type.stderr b/src/test/ui/simd-type.stderr index 5e309cea6ef16..0c4242f46b786 100644 --- a/src/test/ui/simd-type.stderr +++ b/src/test/ui/simd-type.stderr @@ -1,22 +1,16 @@ error[E0075]: SIMD vector cannot be empty --> $DIR/simd-type.rs:5:1 | -LL | struct empty; //~ ERROR SIMD vector cannot be empty +LL | struct empty; | ^^^^^^^^^^^^^ error[E0076]: SIMD vector should be homogeneous --> $DIR/simd-type.rs:8:1 | -LL | struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous +LL | struct i64f64(i64, f64); | ^^^^^^^^^^^^^^^^^^^^^^^^ SIMD elements must have the same type -error[E0077]: SIMD vector element type should be machine type - --> $DIR/simd-type.rs:11:1 - | -LL | struct int4(isize, isize, isize, isize); //~ ERROR SIMD vector element type should be machine type - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0075, E0076, E0077. +Some errors have detailed explanations: E0075, E0076. For more information about an error, try `rustc --explain E0075`. diff --git a/src/test/ui/similar-tokens.stderr b/src/test/ui/similar-tokens.stderr index 898c3a0aa95c8..3113d4a872d8f 100644 --- a/src/test/ui/similar-tokens.stderr +++ b/src/test/ui/similar-tokens.stderr @@ -1,7 +1,7 @@ error: expected one of `,`, `::`, `as`, or `}`, found `.` --> $DIR/similar-tokens.rs:7:10 | -LL | use x::{A. B}; //~ ERROR expected one of `,`, `::`, `as`, or `}`, found `.` +LL | use x::{A. B}; | ^ expected one of `,`, `::`, `as`, or `}` here error: aborting due to previous error diff --git a/src/test/ui/single-primitive-inherent-impl.stderr b/src/test/ui/single-primitive-inherent-impl.stderr index 21bbbe693466d..d357afa3b3841 100644 --- a/src/test/ui/single-primitive-inherent-impl.stderr +++ b/src/test/ui/single-primitive-inherent-impl.stderr @@ -2,7 +2,7 @@ error[E0390]: only a single inherent implementation marked with `#[lang = "str"] --> $DIR/single-primitive-inherent-impl.rs:11:1 | LL | / impl str { -LL | | //~^ error: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive +LL | | LL | | } | |_^ | @@ -10,7 +10,7 @@ help: consider using a trait to implement these methods --> $DIR/single-primitive-inherent-impl.rs:11:1 | LL | / impl str { -LL | | //~^ error: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive +LL | | LL | | } | |_^ diff --git a/src/test/ui/single-use-lifetime/fn-types.stderr b/src/test/ui/single-use-lifetime/fn-types.stderr index 7e23d75c4e589..bec24be07af63 100644 --- a/src/test/ui/single-use-lifetime/fn-types.stderr +++ b/src/test/ui/single-use-lifetime/fn-types.stderr @@ -1,7 +1,7 @@ error: lifetime parameter `'a` only used once --> $DIR/fn-types.rs:9:10 | -LL | a: for<'a> fn(&'a u32), //~ ERROR `'a` only used once +LL | a: for<'a> fn(&'a u32), | ^^ -- ...is used only here | | | this lifetime... diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr index 0199074ad64d2..4bf08534b8c48 100644 --- a/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr +++ b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr @@ -1,7 +1,7 @@ error: lifetime parameter `'a` only used once --> $DIR/one-use-in-fn-argument.rs:8:6 | -LL | fn a<'a>(x: &'a u32) { //~ ERROR `'a` only used once +LL | fn a<'a>(x: &'a u32) { | ^^ -- ...is used only here | | | this lifetime... @@ -13,7 +13,7 @@ LL | #![deny(single_use_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^ help: elide the single-use lifetime | -LL | fn a(x: &u32) { //~ ERROR `'a` only used once +LL | fn a(x: &u32) { | -- -- error: aborting due to previous error diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs b/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs index 876a0a564daf5..92b25cbf58410 100644 --- a/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs +++ b/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs @@ -1,20 +1,16 @@ -// compile-pass - -#![deny(single_use_lifetimes)] -#![allow(dead_code)] -#![allow(unused_variables)] - // Test that we DO NOT warn when lifetime name is used only // once in a fn return type -- using `'_` is not legal there, // as it must refer back to an argument. // // (Normally, using `'static` would be preferred, but there are // times when that is not what you want.) -// -// run-pass + +// compile-pass + +#![deny(single_use_lifetimes)] fn b<'a>() -> &'a u32 { // OK: used only in return type &22 } -fn main() { } +fn main() {} diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr b/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr index 094894bf2d1ec..8115a1e64011f 100644 --- a/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr +++ b/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr @@ -1,7 +1,7 @@ error: lifetime parameter `'f` only used once --> $DIR/one-use-in-inherent-impl-header.rs:12:6 | -LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once +LL | impl<'f> Foo<'f> { | ^^ -- ...is used only here | | | this lifetime... diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr index 5bd4efb6bb1e1..48bd9f19126b2 100644 --- a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr +++ b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr @@ -1,7 +1,7 @@ error: lifetime parameter `'a` only used once --> $DIR/one-use-in-inherent-method-argument.rs:12:19 | -LL | fn inherent_a<'a>(&self, data: &'a u32) { //~ ERROR `'a` only used once +LL | fn inherent_a<'a>(&self, data: &'a u32) { | ^^ -- ...is used only here | | | this lifetime... @@ -13,13 +13,13 @@ LL | #![deny(single_use_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^ help: elide the single-use lifetime | -LL | fn inherent_a(&self, data: &u32) { //~ ERROR `'a` only used once +LL | fn inherent_a(&self, data: &u32) { | -- -- error: lifetime parameter `'f` only used once --> $DIR/one-use-in-inherent-method-argument.rs:11:6 | -LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once +LL | impl<'f> Foo<'f> { | ^^ -- ...is used only here | | | this lifetime... diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr index f0e4ac411c2ba..9c93da4627156 100644 --- a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr +++ b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr @@ -1,7 +1,7 @@ error: lifetime parameter `'f` only used once --> $DIR/one-use-in-inherent-method-return.rs:12:6 | -LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once +LL | impl<'f> Foo<'f> { | ^^ -- ...is used only here | | | this lifetime... diff --git a/src/test/ui/single-use-lifetime/one-use-in-struct.rs b/src/test/ui/single-use-lifetime/one-use-in-struct.rs index e0328c9d94a14..6c4d2a4a7ad41 100644 --- a/src/test/ui/single-use-lifetime/one-use-in-struct.rs +++ b/src/test/ui/single-use-lifetime/one-use-in-struct.rs @@ -18,4 +18,11 @@ enum Bar<'f> { trait Baz<'f> { } +// `Derive`d impls shouldn't trigger a warning, either (Issue #53738). + +#[derive(Debug)] +struct Quux<'a> { + priors: &'a u32, +} + fn main() { } diff --git a/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr b/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr index 7d3fc82abf40b..047e0591e4b9a 100644 --- a/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr +++ b/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr @@ -1,7 +1,7 @@ error: lifetime parameter `'g` only used once --> $DIR/one-use-in-trait-method-argument.rs:15:13 | -LL | fn next<'g>(&'g mut self) -> Option { //~ ERROR `'g` only used once +LL | fn next<'g>(&'g mut self) -> Option { | ^^ -- ...is used only here | | | this lifetime... @@ -13,7 +13,7 @@ LL | #![deny(single_use_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^ help: elide the single-use lifetime | -LL | fn next(&mut self) -> Option { //~ ERROR `'g` only used once +LL | fn next(&mut self) -> Option { | ---- error: aborting due to previous error diff --git a/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr b/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr index 7a1af1323d8dd..6f0ba02b5067b 100644 --- a/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr +++ b/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr @@ -1,7 +1,7 @@ error: lifetime parameter `'f` only used once --> $DIR/two-uses-in-inherent-method-argument-and-return.rs:12:6 | -LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once +LL | impl<'f> Foo<'f> { | ^^ -- ...is used only here | | | this lifetime... diff --git a/src/test/ui/single-use-lifetime/zero-uses-in-impl.stderr b/src/test/ui/single-use-lifetime/zero-uses-in-impl.stderr index 3f9d907ade679..650a9b4600ea2 100644 --- a/src/test/ui/single-use-lifetime/zero-uses-in-impl.stderr +++ b/src/test/ui/single-use-lifetime/zero-uses-in-impl.stderr @@ -1,7 +1,7 @@ error: lifetime parameter `'a` never used --> $DIR/zero-uses-in-impl.rs:8:6 | -LL | impl<'a> Foo {} //~ ERROR `'a` never used +LL | impl<'a> Foo {} | -^^- help: elide the unused lifetime | note: lint level defined here diff --git a/src/test/ui/slice-2.stderr b/src/test/ui/slice-2.stderr index ef0eeb7a8da3f..561feb90f0a54 100644 --- a/src/test/ui/slice-2.stderr +++ b/src/test/ui/slice-2.stderr @@ -1,25 +1,25 @@ error[E0608]: cannot index into a value of type `Foo` --> $DIR/slice-2.rs:7:6 | -LL | &x[..]; //~ ERROR cannot index into a value of type `Foo` +LL | &x[..]; | ^^^^^ error[E0608]: cannot index into a value of type `Foo` --> $DIR/slice-2.rs:8:6 | -LL | &x[Foo..]; //~ ERROR cannot index into a value of type `Foo` +LL | &x[Foo..]; | ^^^^^^^^ error[E0608]: cannot index into a value of type `Foo` --> $DIR/slice-2.rs:9:6 | -LL | &x[..Foo]; //~ ERROR cannot index into a value of type `Foo` +LL | &x[..Foo]; | ^^^^^^^^ error[E0608]: cannot index into a value of type `Foo` --> $DIR/slice-2.rs:10:6 | -LL | &x[Foo..Foo]; //~ ERROR cannot index into a value of type `Foo` +LL | &x[Foo..Foo]; | ^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/slice-mut-2.nll.stderr b/src/test/ui/slice-mut-2.nll.stderr deleted file mode 100644 index eeef23e694b7a..0000000000000 --- a/src/test/ui/slice-mut-2.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/slice-mut-2.rs:7:18 - | -LL | let x: &[isize] = &[1, 2, 3, 4, 5]; - | ---------------- help: consider changing this to be a mutable reference: `&mut [1, 2, 3, 4, 5]` -... -LL | let _ = &mut x[2..4]; //~ERROR cannot borrow immutable borrowed content `*x` as mutable - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/slice-mut-2.rs b/src/test/ui/slice-mut-2.rs index 9586103f5f18c..216edbb780886 100644 --- a/src/test/ui/slice-mut-2.rs +++ b/src/test/ui/slice-mut-2.rs @@ -4,5 +4,5 @@ fn main() { let x: &[isize] = &[1, 2, 3, 4, 5]; // Can't mutably slice an immutable slice let slice: &mut [isize] = &mut [0, 1]; - let _ = &mut x[2..4]; //~ERROR cannot borrow immutable borrowed content `*x` as mutable + let _ = &mut x[2..4]; //~ERROR cannot borrow `*x` as mutable, as it is behind a `&` reference } diff --git a/src/test/ui/slice-mut-2.stderr b/src/test/ui/slice-mut-2.stderr index 07a8bd7699ec2..bad0268772b79 100644 --- a/src/test/ui/slice-mut-2.stderr +++ b/src/test/ui/slice-mut-2.stderr @@ -1,8 +1,11 @@ -error[E0596]: cannot borrow immutable borrowed content `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/slice-mut-2.rs:7:18 | -LL | let _ = &mut x[2..4]; //~ERROR cannot borrow immutable borrowed content `*x` as mutable - | ^ cannot borrow as mutable +LL | let x: &[isize] = &[1, 2, 3, 4, 5]; + | ---------------- help: consider changing this to be a mutable reference: `&mut [1, 2, 3, 4, 5]` +... +LL | let _ = &mut x[2..4]; + | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff --git a/src/test/ui/span/E0057.stderr b/src/test/ui/span/E0057.stderr index 5906a05c32c97..6b5890cac36c5 100644 --- a/src/test/ui/span/E0057.stderr +++ b/src/test/ui/span/E0057.stderr @@ -1,13 +1,13 @@ error[E0057]: this function takes 1 parameter but 0 parameters were supplied --> $DIR/E0057.rs:3:13 | -LL | let a = f(); //~ ERROR E0057 +LL | let a = f(); | ^^^ expected 1 parameter error[E0057]: this function takes 1 parameter but 2 parameters were supplied --> $DIR/E0057.rs:5:13 | -LL | let c = f(2, 3); //~ ERROR E0057 +LL | let c = f(2, 3); | ^^^^^^^ expected 1 parameter error: aborting due to 2 previous errors diff --git a/src/test/ui/span/E0072.stderr b/src/test/ui/span/E0072.stderr index 4cb9eb308022e..d4a5e7400d2a4 100644 --- a/src/test/ui/span/E0072.stderr +++ b/src/test/ui/span/E0072.stderr @@ -1,7 +1,7 @@ error[E0072]: recursive type `ListNode` has infinite size --> $DIR/E0072.rs:1:1 | -LL | struct ListNode { //~ ERROR has infinite size +LL | struct ListNode { | ^^^^^^^^^^^^^^^ recursive type has infinite size LL | head: u8, LL | tail: Option, diff --git a/src/test/ui/span/E0204.stderr b/src/test/ui/span/E0204.stderr index acb7cd2a557dc..5a981a4a6e48f 100644 --- a/src/test/ui/span/E0204.stderr +++ b/src/test/ui/span/E0204.stderr @@ -4,13 +4,13 @@ error[E0204]: the trait `Copy` may not be implemented for this type LL | foo: Vec, | ------------- this field does not implement `Copy` ... -LL | impl Copy for Foo { } //~ ERROR may not be implemented for this type +LL | impl Copy for Foo { } | ^^^^ error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/E0204.rs:7:10 | -LL | #[derive(Copy)] //~ ERROR may not be implemented for this type +LL | #[derive(Copy)] | ^^^^ LL | struct Foo2<'a> { LL | ty: &'a mut bool, @@ -22,13 +22,13 @@ error[E0204]: the trait `Copy` may not be implemented for this type LL | Bar { x: Vec }, | ----------- this field does not implement `Copy` ... -LL | impl Copy for EFoo { } //~ ERROR may not be implemented for this type +LL | impl Copy for EFoo { } | ^^^^ error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/E0204.rs:19:10 | -LL | #[derive(Copy)] //~ ERROR may not be implemented for this type +LL | #[derive(Copy)] | ^^^^ LL | enum EFoo2<'a> { LL | Bar(&'a mut bool), diff --git a/src/test/ui/span/E0493.stderr b/src/test/ui/span/E0493.stderr index d05e89e257f45..7e164ba9681c6 100644 --- a/src/test/ui/span/E0493.stderr +++ b/src/test/ui/span/E0493.stderr @@ -6,4 +6,3 @@ LL | const F : Foo = (Foo { a : 0 }, Foo { a : 1 }).1; error: aborting due to previous error -For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/span/E0535.stderr b/src/test/ui/span/E0535.stderr index 8502776eb1687..f52c3f9f2c043 100644 --- a/src/test/ui/span/E0535.stderr +++ b/src/test/ui/span/E0535.stderr @@ -1,7 +1,7 @@ error[E0535]: invalid argument --> $DIR/E0535.rs:1:10 | -LL | #[inline(unknown)] //~ ERROR E0535 +LL | #[inline(unknown)] | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/span/E0536.stderr b/src/test/ui/span/E0536.stderr index 18e2104f7ad85..820b0d7441b4a 100644 --- a/src/test/ui/span/E0536.stderr +++ b/src/test/ui/span/E0536.stderr @@ -1,7 +1,7 @@ error[E0536]: expected 1 cfg-pattern --> $DIR/E0536.rs:1:7 | -LL | #[cfg(not())] //~ ERROR E0536 +LL | #[cfg(not())] | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/span/E0537.stderr b/src/test/ui/span/E0537.stderr index 53e8637ea3025..5478c3fbcdda3 100644 --- a/src/test/ui/span/E0537.stderr +++ b/src/test/ui/span/E0537.stderr @@ -1,7 +1,7 @@ error[E0537]: invalid predicate `unknown` --> $DIR/E0537.rs:1:7 | -LL | #[cfg(unknown())] //~ ERROR E0537 +LL | #[cfg(unknown())] | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr deleted file mode 100644 index 0aa44fa3a3ae0..0000000000000 --- a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr +++ /dev/null @@ -1,88 +0,0 @@ -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:53:24 - | -LL | fn deref_mut_field1(x: Own) { - | - help: consider changing this to be mutable: `mut x` -LL | let __isize = &mut x.y; //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:65:10 - | -LL | fn deref_extend_mut_field1(x: &Own) -> &mut isize { - | ----------- help: consider changing this to be a mutable reference: `&mut Own` -LL | &mut x.y //~ ERROR cannot borrow - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:78:19 - | -LL | let _x = &mut x.x; - | - first mutable borrow occurs here -LL | let _y = &mut x.y; //~ ERROR cannot borrow - | ^ second mutable borrow occurs here -LL | use_mut(_x); - | -- first borrow later used here - -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:88:5 - | -LL | fn assign_field1<'a>(x: Own) { - | - help: consider changing this to be mutable: `mut x` -LL | x.y = 3; //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:92:5 - | -LL | fn assign_field2<'a>(x: &'a Own) { - | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` -LL | x.y = 3; //~ ERROR cannot borrow - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:101:5 - | -LL | let _p: &mut Point = &mut **x; - | -- first mutable borrow occurs here -LL | x.y = 3; //~ ERROR cannot borrow - | ^ second mutable borrow occurs here -LL | use_mut(_p); - | -- first borrow later used here - -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:109:5 - | -LL | fn deref_mut_method1(x: Own) { - | - help: consider changing this to be mutable: `mut x` -LL | x.set(0, 0); //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:121:5 - | -LL | fn deref_extend_mut_method1(x: &Own) -> &mut isize { - | ----------- help: consider changing this to be a mutable reference: `&mut Own` -LL | x.y_mut() //~ ERROR cannot borrow - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:129:6 - | -LL | fn assign_method1<'a>(x: Own) { - | - help: consider changing this to be mutable: `mut x` -LL | *x.y_mut() = 3; //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:133:6 - | -LL | fn assign_method2<'a>(x: &'a Own) { - | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` -LL | *x.y_mut() = 3; //~ ERROR cannot borrow - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to 10 previous errors - -Some errors occurred: E0499, E0596. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr index e0524be6b0c46..8fceef64c8cf2 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr @@ -1,90 +1,88 @@ -error[E0596]: cannot borrow immutable argument `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:53:24 | LL | fn deref_mut_field1(x: Own) { - | - help: make this binding mutable: `mut x` -LL | let __isize = &mut x.y; //~ ERROR cannot borrow - | ^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut x` +LL | let __isize = &mut x.y; + | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:65:10 | LL | fn deref_extend_mut_field1(x: &Own) -> &mut isize { - | ----------- use `&mut Own` here to make mutable -LL | &mut x.y //~ ERROR cannot borrow - | ^ cannot borrow as mutable + | ----------- help: consider changing this to be a mutable reference: `&mut Own` +LL | &mut x.y + | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0499]: cannot borrow `*x` as mutable more than once at a time --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:78:19 | LL | let _x = &mut x.x; | - first mutable borrow occurs here -LL | let _y = &mut x.y; //~ ERROR cannot borrow +LL | let _y = &mut x.y; | ^ second mutable borrow occurs here LL | use_mut(_x); -LL | } - | - first borrow ends here + | -- first borrow later used here -error[E0596]: cannot borrow immutable argument `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:88:5 | LL | fn assign_field1<'a>(x: Own) { - | - help: make this binding mutable: `mut x` -LL | x.y = 3; //~ ERROR cannot borrow - | ^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut x` +LL | x.y = 3; + | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:92:5 | LL | fn assign_field2<'a>(x: &'a Own) { - | -------------- use `&'a mut Own` here to make mutable -LL | x.y = 3; //~ ERROR cannot borrow - | ^ cannot borrow as mutable + | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` +LL | x.y = 3; + | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0499]: cannot borrow `*x` as mutable more than once at a time --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:101:5 | LL | let _p: &mut Point = &mut **x; | -- first mutable borrow occurs here -LL | x.y = 3; //~ ERROR cannot borrow +LL | x.y = 3; | ^ second mutable borrow occurs here LL | use_mut(_p); -LL | } - | - first borrow ends here + | -- first borrow later used here -error[E0596]: cannot borrow immutable argument `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:109:5 | LL | fn deref_mut_method1(x: Own) { - | - help: make this binding mutable: `mut x` -LL | x.set(0, 0); //~ ERROR cannot borrow - | ^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut x` +LL | x.set(0, 0); + | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:121:5 | LL | fn deref_extend_mut_method1(x: &Own) -> &mut isize { - | ----------- use `&mut Own` here to make mutable -LL | x.y_mut() //~ ERROR cannot borrow - | ^ cannot borrow as mutable + | ----------- help: consider changing this to be a mutable reference: `&mut Own` +LL | x.y_mut() + | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable argument `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:129:6 | LL | fn assign_method1<'a>(x: Own) { - | - help: make this binding mutable: `mut x` -LL | *x.y_mut() = 3; //~ ERROR cannot borrow - | ^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut x` +LL | *x.y_mut() = 3; + | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:133:6 | LL | fn assign_method2<'a>(x: &'a Own) { - | -------------- use `&'a mut Own` here to make mutable -LL | *x.y_mut() = 3; //~ ERROR cannot borrow - | ^ cannot borrow as mutable + | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` +LL | *x.y_mut() = 3; + | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to 10 previous errors -Some errors occurred: E0499, E0596. +Some errors have detailed explanations: E0499, E0596. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr deleted file mode 100644 index ef80e4bc3d645..0000000000000 --- a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:29:25 - | -LL | fn deref_mut1(x: Own) { - | - help: consider changing this to be mutable: `mut x` -LL | let __isize = &mut *x; //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:41:11 - | -LL | fn deref_extend_mut1<'a>(x: &'a Own) -> &'a mut isize { - | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` -LL | &mut **x //~ ERROR cannot borrow - | ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:49:6 - | -LL | fn assign1<'a>(x: Own) { - | - help: consider changing this to be mutable: `mut x` -LL | *x = 3; //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:53:6 - | -LL | fn assign2<'a>(x: &'a Own) { - | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` -LL | **x = 3; //~ ERROR cannot borrow - | ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr index 46d11065a86e5..3ebfba7e4debe 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr @@ -1,34 +1,34 @@ -error[E0596]: cannot borrow immutable argument `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:29:25 | LL | fn deref_mut1(x: Own) { - | - help: make this binding mutable: `mut x` -LL | let __isize = &mut *x; //~ ERROR cannot borrow - | ^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut x` +LL | let __isize = &mut *x; + | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:41:11 | LL | fn deref_extend_mut1<'a>(x: &'a Own) -> &'a mut isize { - | -------------- use `&'a mut Own` here to make mutable -LL | &mut **x //~ ERROR cannot borrow - | ^^ cannot borrow as mutable + | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` +LL | &mut **x + | ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable argument `x` as mutable +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:49:6 | LL | fn assign1<'a>(x: Own) { - | - help: make this binding mutable: `mut x` -LL | *x = 3; //~ ERROR cannot borrow - | ^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut x` +LL | *x = 3; + | ^ cannot borrow as mutable -error[E0596]: cannot borrow immutable borrowed content `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:53:6 | LL | fn assign2<'a>(x: &'a Own) { - | -------------- use `&'a mut Own` here to make mutable -LL | **x = 3; //~ ERROR cannot borrow - | ^^ cannot borrow as mutable + | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` +LL | **x = 3; + | ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to 4 previous errors diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr deleted file mode 100644 index e752a467edcf3..0000000000000 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr +++ /dev/null @@ -1,52 +0,0 @@ -error[E0499]: cannot borrow `f` as mutable more than once at a time - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:12:16 - | -LL | f(Box::new(|| { - | - ^^ second mutable borrow occurs here - | | - | first mutable borrow occurs here - | first borrow later used by call -LL | //~^ ERROR: cannot borrow `f` as mutable more than once -LL | f((Box::new(|| {}))) - | - second borrow occurs due to use of `f` in closure - -error[E0596]: cannot borrow `*f` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:25:5 - | -LL | fn test2(f: &F) where F: FnMut() { - | -- help: consider changing this to be a mutable reference: `&mut F` -LL | (*f)(); - | ^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `*f.f` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:34:5 - | -LL | fn test4(f: &Test) { - | ----- help: consider changing this to be a mutable reference: `&mut Test<'_>` -LL | f.f.call_mut(()) - | ^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:56:13 - | -LL | let mut f = move |g: Box, b: isize| { - | ----- captured outer variable -... -LL | foo(f); - | ^ cannot move out of captured variable in an `FnMut` closure - -error[E0505]: cannot move out of `f` because it is borrowed - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16 - | -LL | f(Box::new(|a| { - | - ^^^ move out of `f` occurs here - | | - | borrow of `f` occurs here - | borrow later used by call -LL | foo(f); - | - move occurs due to use in closure - -error: aborting due to 5 previous errors - -Some errors occurred: E0499, E0505, E0507, E0596. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs index cfebd6f700359..938fdaf11f09b 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs @@ -2,10 +2,10 @@ // Ensure that invoking a closure counts as a unique immutable borrow -type Fn<'a> = Box; +type Fn<'a> = Box; struct Test<'a> { - f: Box + f: Box } fn call(mut f: F) where F: FnMut(Fn) { @@ -23,7 +23,7 @@ fn test1() { fn test2(f: &F) where F: FnMut() { (*f)(); - //~^ ERROR cannot borrow immutable borrowed content `*f` as mutable + //~^ ERROR cannot borrow `*f` as mutable, as it is behind a `&` reference } fn test3(f: &mut F) where F: FnMut() { @@ -32,7 +32,7 @@ fn test3(f: &mut F) where F: FnMut() { fn test4(f: &Test) { f.f.call_mut(()) - //~^ ERROR: cannot borrow `Box` content `*f.f` of immutable binding as mutable + //~^ ERROR: cannot borrow `f.f` as mutable, as it is behind a `&` reference } fn test5(f: &mut Test) { @@ -47,15 +47,15 @@ fn test6() { } fn test7() { - fn foo(_: F) where F: FnMut(Box, isize) {} + fn foo(_: F) where F: FnMut(Box, isize) {} let s = String::new(); // Capture to make f !Copy - let mut f = move |g: Box, b: isize| { + let mut f = move |g: Box, b: isize| { let _ = s.len(); }; f(Box::new(|a| { + //~^ ERROR cannot move out of `f` because it is borrowed foo(f); - //~^ ERROR cannot move `f` into closure because it is borrowed - //~| ERROR cannot move out of captured outer variable in an `FnMut` closure + //~^ ERROR cannot move out of `f`, a captured variable in an `FnMut` closure }), 3); } diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr index d81d402fce733..72f875bbd14a4 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -5,46 +5,48 @@ LL | f(Box::new(|| { | - ^^ second mutable borrow occurs here | | | first mutable borrow occurs here -LL | //~^ ERROR: cannot borrow `f` as mutable more than once + | first borrow later used by call +LL | LL | f((Box::new(|| {}))) - | - borrow occurs due to use of `f` in closure -LL | })); - | - first borrow ends here + | - second borrow occurs due to use of `f` in closure -error[E0596]: cannot borrow immutable borrowed content `*f` as mutable +error[E0596]: cannot borrow `*f` as mutable, as it is behind a `&` reference --> $DIR/borrowck-call-is-borrow-issue-12224.rs:25:5 | LL | fn test2(f: &F) where F: FnMut() { - | -- use `&mut F` here to make mutable + | -- help: consider changing this to be a mutable reference: `&mut F` LL | (*f)(); - | ^^^^ cannot borrow as mutable + | ^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow `Box` content `*f.f` of immutable binding as mutable +error[E0596]: cannot borrow `f.f` as mutable, as it is behind a `&` reference --> $DIR/borrowck-call-is-borrow-issue-12224.rs:34:5 | LL | fn test4(f: &Test) { - | ----- use `&mut Test` here to make mutable + | ----- help: consider changing this to be a mutable reference: `&mut Test<'_>` LL | f.f.call_mut(()) - | ^^^ cannot borrow as mutable + | ^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0504]: cannot move `f` into closure because it is borrowed - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:56:13 +error[E0507]: cannot move out of `f`, a captured variable in an `FnMut` closure + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:57:13 | -LL | f(Box::new(|a| { - | - borrow of `f` occurs here +LL | let mut f = move |g: Box, b: isize| { + | ----- captured outer variable +... LL | foo(f); - | ^ move into closure occurs here + | ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 54:6 s:std::string::String]`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured outer variable in an `FnMut` closure - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:56:13 +error[E0505]: cannot move out of `f` because it is borrowed + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16 | -LL | let mut f = move |g: Box, b: isize| { - | ----- captured outer variable -... +LL | f(Box::new(|a| { + | - ^^^ move out of `f` occurs here + | | + | borrow of `f` occurs here +LL | LL | foo(f); - | ^ cannot move out of captured outer variable in an `FnMut` closure + | - move occurs due to use in closure error: aborting due to 5 previous errors -Some errors occurred: E0499, E0504, E0507, E0596. +Some errors have detailed explanations: E0499, E0505, E0507, E0596. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.nll.stderr b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.nll.stderr deleted file mode 100644 index 16c482b575aae..0000000000000 --- a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-call-method-from-mut-aliasable.rs:17:5 - | -LL | fn b(x: &Foo) { - | ---- help: consider changing this to be a mutable reference: `&mut Foo` -LL | x.f(); -LL | x.h(); //~ ERROR cannot borrow - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr index 4875e27ef4552..6b5e0779e5fa5 100644 --- a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr +++ b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr @@ -1,11 +1,11 @@ -error[E0596]: cannot borrow immutable borrowed content `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-call-method-from-mut-aliasable.rs:17:5 | LL | fn b(x: &Foo) { - | ---- use `&mut Foo` here to make mutable + | ---- help: consider changing this to be a mutable reference: `&mut Foo` LL | x.f(); -LL | x.h(); //~ ERROR cannot borrow - | ^ cannot borrow as mutable +LL | x.h(); + | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff --git a/src/test/ui/span/borrowck-fn-in-const-b.nll.stderr b/src/test/ui/span/borrowck-fn-in-const-b.nll.stderr deleted file mode 100644 index 9133d482c29c6..0000000000000 --- a/src/test/ui/span/borrowck-fn-in-const-b.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-fn-in-const-b.rs:7:9 - | -LL | fn broken(x: &Vec) { - | ------------ help: consider changing this to be a mutable reference: `&mut std::vec::Vec` -LL | x.push(format!("this is broken")); - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/span/borrowck-fn-in-const-b.stderr b/src/test/ui/span/borrowck-fn-in-const-b.stderr index 4a30bdf3b08cb..9133d482c29c6 100644 --- a/src/test/ui/span/borrowck-fn-in-const-b.stderr +++ b/src/test/ui/span/borrowck-fn-in-const-b.stderr @@ -1,10 +1,10 @@ -error[E0596]: cannot borrow immutable borrowed content `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-fn-in-const-b.rs:7:9 | LL | fn broken(x: &Vec) { - | ------------ use `&mut Vec` here to make mutable + | ------------ help: consider changing this to be a mutable reference: `&mut std::vec::Vec` LL | x.push(format!("this is broken")); - | ^ cannot borrow as mutable + | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr b/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr deleted file mode 100644 index f5f1193264822..0000000000000 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr +++ /dev/null @@ -1,42 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-let-suggestion-suffixes.rs:19:14 - | -LL | v3.push(&id('x')); // statement 6 - | ^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary which is freed while still in use -... -LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); - | -- borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - -error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-let-suggestion-suffixes.rs:29:18 - | -LL | v4.push(&id('y')); - | ^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary which is freed while still in use -... -LL | v4.use_ref(); - | -- borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - -error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-let-suggestion-suffixes.rs:40:14 - | -LL | v5.push(&id('z')); - | ^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary which is freed while still in use -... -LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); - | -- borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.rs b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs index 4b14907cec04f..4744f3710ce53 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.rs +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs @@ -1,4 +1,3 @@ -#![feature(rustc_attrs)] fn id(x: T) -> T { x } fn f() { @@ -7,51 +6,52 @@ fn f() { let mut v2 = Vec::new(); // statement 2 - let young = ['y']; // statement 3 + { + let young = ['y']; // statement 3 - v2.push(&young[0]); // statement 4 - //~^ ERROR `young[..]` does not live long enough - //~| NOTE borrowed value does not live long enough - //~| NOTE values in a scope are dropped in the opposite order they are created + v2.push(&young[0]); // statement 4 + //~^ ERROR `young[_]` does not live long enough + //~| NOTE borrowed value does not live long enough + } //~ NOTE `young[_]` dropped here while still borrowed let mut v3 = Vec::new(); // statement 5 v3.push(&id('x')); // statement 6 - //~^ ERROR borrowed value does not live long enough - //~| NOTE temporary value does not live long enough - //~| NOTE temporary value dropped here while still borrowed - //~| NOTE consider using a `let` binding to increase its lifetime + //~^ ERROR temporary value dropped while borrowed + //~| NOTE creates a temporary which is freed while still in use + //~| NOTE temporary value is freed at the end of this statement + //~| NOTE consider using a `let` binding to create a longer lived value { let mut v4 = Vec::new(); // (sub) statement 0 v4.push(&id('y')); - //~^ ERROR borrowed value does not live long enough - //~| NOTE temporary value does not live long enough - //~| NOTE temporary value dropped here while still borrowed - //~| NOTE consider using a `let` binding to increase its lifetime + //~^ ERROR temporary value dropped while borrowed + //~| NOTE creates a temporary which is freed while still in use + //~| NOTE temporary value is freed at the end of this statement + //~| NOTE consider using a `let` binding to create a longer lived value v4.use_ref(); + //~^ NOTE borrow later used here } // (statement 7) - //~^ NOTE temporary value needs to live until here let mut v5 = Vec::new(); // statement 8 v5.push(&id('z')); - //~^ ERROR borrowed value does not live long enough - //~| NOTE temporary value does not live long enough - //~| NOTE temporary value dropped here while still borrowed - //~| NOTE consider using a `let` binding to increase its lifetime + //~^ ERROR temporary value dropped while borrowed + //~| NOTE creates a temporary which is freed while still in use + //~| NOTE temporary value is freed at the end of this statement + //~| NOTE consider using a `let` binding to create a longer lived value v1.push(&old[0]); (v1, v2, v3, /* v4 is above. */ v5).use_ref(); + //~^ NOTE borrow later used here + //~| NOTE borrow later used here + //~| NOTE borrow later used here } -//~^ NOTE `young[..]` dropped here while still borrowed -//~| NOTE temporary value needs to live until here -//~| NOTE temporary value needs to live until here -fn main() { #![rustc_error] // rust-lang/rust#49855 +fn main() { f(); } diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr index 8bf542e37ff19..7ba909d208aff 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr @@ -1,53 +1,55 @@ -error[E0597]: `young[..]` does not live long enough - --> $DIR/borrowck-let-suggestion-suffixes.rs:12:14 +error[E0597]: `young[_]` does not live long enough + --> $DIR/borrowck-let-suggestion-suffixes.rs:12:17 | -LL | v2.push(&young[0]); // statement 4 - | ^^^^^^^^ borrowed value does not live long enough +LL | v2.push(&young[0]); // statement 4 + | ^^^^^^^^^ borrowed value does not live long enough ... -LL | } - | - `young[..]` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created +LL | } + | - `young[_]` dropped here while still borrowed +... +LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); + | -- borrow later used here -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion-suffixes.rs:19:14 | LL | v3.push(&id('x')); // statement 6 - | ^^^^^^^ - temporary value dropped here while still borrowed + | ^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... -LL | } - | - temporary value needs to live until here +LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); + | -- borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion-suffixes.rs:29:18 | LL | v4.push(&id('y')); - | ^^^^^^^ - temporary value dropped here while still borrowed + | ^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... -LL | } // (statement 7) - | - temporary value needs to live until here +LL | v4.use_ref(); + | -- borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion-suffixes.rs:40:14 | LL | v5.push(&id('z')); - | ^^^^^^^ - temporary value dropped here while still borrowed + | ^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... -LL | } - | - temporary value needs to live until here +LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); + | -- borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors have detailed explanations: E0597, E0716. +For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/borrowck-object-mutability.nll.stderr b/src/test/ui/span/borrowck-object-mutability.nll.stderr deleted file mode 100644 index 1a5802e98114d..0000000000000 --- a/src/test/ui/span/borrowck-object-mutability.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-object-mutability.rs:8:5 - | -LL | fn borrowed_receiver(x: &Foo) { - | ---- help: consider changing this to be a mutable reference: `&mut dyn Foo` -LL | x.borrowed(); -LL | x.borrowed_mut(); //~ ERROR cannot borrow - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable - --> $DIR/borrowck-object-mutability.rs:18:5 - | -LL | fn owned_receiver(x: Box) { - | - help: consider changing this to be mutable: `mut x` -LL | x.borrowed(); -LL | x.borrowed_mut(); //~ ERROR cannot borrow - | ^ cannot borrow as mutable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/span/borrowck-object-mutability.rs b/src/test/ui/span/borrowck-object-mutability.rs index e672c46453582..f5adc2cc1413e 100644 --- a/src/test/ui/span/borrowck-object-mutability.rs +++ b/src/test/ui/span/borrowck-object-mutability.rs @@ -3,22 +3,22 @@ trait Foo { fn borrowed_mut(&mut self); } -fn borrowed_receiver(x: &Foo) { +fn borrowed_receiver(x: &dyn Foo) { x.borrowed(); x.borrowed_mut(); //~ ERROR cannot borrow } -fn borrowed_mut_receiver(x: &mut Foo) { +fn borrowed_mut_receiver(x: &mut dyn Foo) { x.borrowed(); x.borrowed_mut(); } -fn owned_receiver(x: Box) { +fn owned_receiver(x: Box) { x.borrowed(); x.borrowed_mut(); //~ ERROR cannot borrow } -fn mut_owned_receiver(mut x: Box) { +fn mut_owned_receiver(mut x: Box) { x.borrowed(); x.borrowed_mut(); } diff --git a/src/test/ui/span/borrowck-object-mutability.stderr b/src/test/ui/span/borrowck-object-mutability.stderr index e846331dc0b86..fe6d05c588f7f 100644 --- a/src/test/ui/span/borrowck-object-mutability.stderr +++ b/src/test/ui/span/borrowck-object-mutability.stderr @@ -1,19 +1,19 @@ -error[E0596]: cannot borrow immutable borrowed content `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-object-mutability.rs:8:5 | -LL | fn borrowed_receiver(x: &Foo) { - | ---- use `&mut Foo` here to make mutable +LL | fn borrowed_receiver(x: &dyn Foo) { + | -------- help: consider changing this to be a mutable reference: `&mut dyn Foo` LL | x.borrowed(); -LL | x.borrowed_mut(); //~ ERROR cannot borrow - | ^ cannot borrow as mutable +LL | x.borrowed_mut(); + | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable `Box` content `*x` as mutable +error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable --> $DIR/borrowck-object-mutability.rs:18:5 | -LL | fn owned_receiver(x: Box) { - | - help: make this binding mutable: `mut x` +LL | fn owned_receiver(x: Box) { + | - help: consider changing this to be mutable: `mut x` LL | x.borrowed(); -LL | x.borrowed_mut(); //~ ERROR cannot borrow +LL | x.borrowed_mut(); | ^ cannot borrow as mutable error: aborting due to 2 previous errors diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr b/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr deleted file mode 100644 index 4f529ce9511db..0000000000000 --- a/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-ref-into-rvalue.rs:3:11 - | -LL | match Some("Hello".to_string()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use -... -LL | } - | - temporary value is freed at the end of this statement -LL | println!("{}", *msg); - | ---- borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.rs b/src/test/ui/span/borrowck-ref-into-rvalue.rs index aeaebf073a708..c11aa1af54095 100644 --- a/src/test/ui/span/borrowck-ref-into-rvalue.rs +++ b/src/test/ui/span/borrowck-ref-into-rvalue.rs @@ -1,8 +1,8 @@ fn main() { let msg; match Some("Hello".to_string()) { + //~^ ERROR temporary value dropped while borrowed Some(ref m) => { - //~^ ERROR borrowed value does not live long enough msg = m; }, None => { panic!() } diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.stderr b/src/test/ui/span/borrowck-ref-into-rvalue.stderr index b8e79be8b61b8..4f529ce9511db 100644 --- a/src/test/ui/span/borrowck-ref-into-rvalue.stderr +++ b/src/test/ui/span/borrowck-ref-into-rvalue.stderr @@ -1,17 +1,16 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/borrowck-ref-into-rvalue.rs:4:14 +error[E0716]: temporary value dropped while borrowed + --> $DIR/borrowck-ref-into-rvalue.rs:3:11 | -LL | Some(ref m) => { - | ^^^^^ borrowed value does not live long enough +LL | match Some("Hello".to_string()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use ... LL | } - | - borrowed value dropped here while still borrowed + | - temporary value is freed at the end of this statement LL | println!("{}", *msg); -LL | } - | - borrowed value needs to live until here + | ---- borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index cda500c3f5dbe..996d80a07e058 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -50,10 +50,7 @@ error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:21:9 | LL | s = format!("foo"); - | ^^^^^^^^^^^^^^ - | | - | expected mutable reference, found struct `std::string::String` - | help: consider mutably borrowing here: `&mut format!("foo")` + | ^^^^^^^^^^^^^^ expected mutable reference, found struct `std::string::String` | = note: expected type `&mut std::string::String` found type `std::string::String` diff --git a/src/test/ui/span/destructor-restrictions.nll.stderr b/src/test/ui/span/destructor-restrictions.nll.stderr deleted file mode 100644 index 981c5a23816fa..0000000000000 --- a/src/test/ui/span/destructor-restrictions.nll.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0597]: `*a` does not live long enough - --> $DIR/destructor-restrictions.rs:8:10 - | -LL | *a.borrow() + 1 - | ^--------- - | | - | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... -LL | }; //~^ ERROR `*a` does not live long enough - | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, i32>` - | | - | `*a` dropped here while still borrowed - | - = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/destructor-restrictions.stderr b/src/test/ui/span/destructor-restrictions.stderr index 8fec877467813..a3c6cfb6ae447 100644 --- a/src/test/ui/span/destructor-restrictions.stderr +++ b/src/test/ui/span/destructor-restrictions.stderr @@ -2,11 +2,16 @@ error[E0597]: `*a` does not live long enough --> $DIR/destructor-restrictions.rs:8:10 | LL | *a.borrow() + 1 - | ^ borrowed value does not live long enough -LL | }; //~^ ERROR `*a` does not live long enough - | -- borrowed value needs to live until here + | ^--------- + | | + | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... +LL | }; + | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, i32>` | | | `*a` dropped here while still borrowed + | + = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. error: aborting due to previous error diff --git a/src/test/ui/span/dropck-object-cycle.nll.stderr b/src/test/ui/span/dropck-object-cycle.nll.stderr deleted file mode 100644 index cfaf470212fdd..0000000000000 --- a/src/test/ui/span/dropck-object-cycle.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0597]: `*m` does not live long enough - --> $DIR/dropck-object-cycle.rs:27:31 - | -LL | assert_eq!(object_invoke1(&*m), (4,5)); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `*m` dropped here while still borrowed - | borrow might be used here, when `m` is dropped and runs the destructor for type `std::boxed::Box>` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/dropck-object-cycle.rs b/src/test/ui/span/dropck-object-cycle.rs index 7b7f37d53f110..a26123d5246f6 100644 --- a/src/test/ui/span/dropck-object-cycle.rs +++ b/src/test/ui/span/dropck-object-cycle.rs @@ -8,7 +8,7 @@ trait Trait<'a> { fn short<'b>(&'b self) -> isize; } -fn object_invoke1<'d>(x: &'d Trait<'d>) -> (isize, isize) { loop { } } +fn object_invoke1<'d>(x: &'d dyn Trait<'d>) -> (isize, isize) { loop { } } trait MakerTrait { fn mk() -> Self; @@ -18,12 +18,12 @@ fn make_val() -> T { MakerTrait::mk() } -impl<'t> MakerTrait for Box+'static> { - fn mk() -> Box+'static> { loop { } } +impl<'t> MakerTrait for Box+'static> { + fn mk() -> Box+'static> { loop { } } } pub fn main() { - let m : Box = make_val(); + let m : Box = make_val(); assert_eq!(object_invoke1(&*m), (4,5)); //~^ ERROR `*m` does not live long enough @@ -45,4 +45,3 @@ pub fn main() { // the type of `m` *strictly outlives* `'m`. Hence we get an // error. } - diff --git a/src/test/ui/span/dropck-object-cycle.stderr b/src/test/ui/span/dropck-object-cycle.stderr index 3fc52853d0220..cfaf470212fdd 100644 --- a/src/test/ui/span/dropck-object-cycle.stderr +++ b/src/test/ui/span/dropck-object-cycle.stderr @@ -1,13 +1,14 @@ error[E0597]: `*m` does not live long enough - --> $DIR/dropck-object-cycle.rs:27:32 + --> $DIR/dropck-object-cycle.rs:27:31 | LL | assert_eq!(object_invoke1(&*m), (4,5)); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough ... LL | } - | - `*m` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created + | - + | | + | `*m` dropped here while still borrowed + | borrow might be used here, when `m` is dropped and runs the destructor for type `std::boxed::Box>` error: aborting due to previous error diff --git a/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr b/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr deleted file mode 100644 index e9caae64beb82..0000000000000 --- a/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0597]: `b2` does not live long enough - --> $DIR/dropck_arr_cycle_checked.rs:93:24 - | -LL | b1.a[0].v.set(Some(&b2)); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `b2` dropped here while still borrowed - | borrow might be used here, when `b1` is dropped and runs the destructor for type `B<'_>` - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `b3` does not live long enough - --> $DIR/dropck_arr_cycle_checked.rs:95:24 - | -LL | b1.a[1].v.set(Some(&b3)); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `b3` dropped here while still borrowed - | borrow might be used here, when `b1` is dropped and runs the destructor for type `B<'_>` - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `b1` does not live long enough - --> $DIR/dropck_arr_cycle_checked.rs:101:24 - | -LL | b3.a[0].v.set(Some(&b1)); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `b1` dropped here while still borrowed - | borrow might be used here, when `b1` is dropped and runs the destructor for type `B<'_>` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/dropck_arr_cycle_checked.rs b/src/test/ui/span/dropck_arr_cycle_checked.rs index 35145014a5a40..ac31e4910d5a6 100644 --- a/src/test/ui/span/dropck_arr_cycle_checked.rs +++ b/src/test/ui/span/dropck_arr_cycle_checked.rs @@ -95,13 +95,10 @@ fn f() { b1.a[1].v.set(Some(&b3)); //~^ ERROR `b3` does not live long enough b2.a[0].v.set(Some(&b2)); - //~^ ERROR `b2` does not live long enough b2.a[1].v.set(Some(&b3)); - //~^ ERROR `b3` does not live long enough b3.a[0].v.set(Some(&b1)); //~^ ERROR `b1` does not live long enough b3.a[1].v.set(Some(&b2)); - //~^ ERROR `b2` does not live long enough } fn main() { diff --git a/src/test/ui/span/dropck_arr_cycle_checked.stderr b/src/test/ui/span/dropck_arr_cycle_checked.stderr index aae71799e30f2..068c779ae5267 100644 --- a/src/test/ui/span/dropck_arr_cycle_checked.stderr +++ b/src/test/ui/span/dropck_arr_cycle_checked.stderr @@ -1,69 +1,43 @@ error[E0597]: `b2` does not live long enough - --> $DIR/dropck_arr_cycle_checked.rs:93:25 + --> $DIR/dropck_arr_cycle_checked.rs:93:24 | LL | b1.a[0].v.set(Some(&b2)); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough ... LL | } - | - `b2` dropped here while still borrowed + | - + | | + | `b2` dropped here while still borrowed + | borrow might be used here, when `b1` is dropped and runs the destructor for type `B<'_>` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `b3` does not live long enough - --> $DIR/dropck_arr_cycle_checked.rs:95:25 + --> $DIR/dropck_arr_cycle_checked.rs:95:24 | LL | b1.a[1].v.set(Some(&b3)); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough ... LL | } - | - `b3` dropped here while still borrowed + | - + | | + | `b3` dropped here while still borrowed + | borrow might be used here, when `b1` is dropped and runs the destructor for type `B<'_>` | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `b2` does not live long enough - --> $DIR/dropck_arr_cycle_checked.rs:97:25 - | -LL | b2.a[0].v.set(Some(&b2)); - | ^^ borrowed value does not live long enough -... -LL | } - | - `b2` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `b3` does not live long enough - --> $DIR/dropck_arr_cycle_checked.rs:99:25 - | -LL | b2.a[1].v.set(Some(&b3)); - | ^^ borrowed value does not live long enough -... -LL | } - | - `b3` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `b1` does not live long enough - --> $DIR/dropck_arr_cycle_checked.rs:101:25 + --> $DIR/dropck_arr_cycle_checked.rs:99:24 | LL | b3.a[0].v.set(Some(&b1)); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough ... LL | } - | - `b1` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `b2` does not live long enough - --> $DIR/dropck_arr_cycle_checked.rs:103:25 - | -LL | b3.a[1].v.set(Some(&b2)); - | ^^ borrowed value does not live long enough -LL | //~^ ERROR `b2` does not live long enough -LL | } - | - `b2` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created + | - + | | + | `b1` dropped here while still borrowed + | borrow might be used here, when `b1` is dropped and runs the destructor for type `B<'_>` -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr b/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr deleted file mode 100644 index 5774ac13cb7e5..0000000000000 --- a/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0597]: `d2` does not live long enough - --> $DIR/dropck_direct_cycle_with_drop.rs:36:19 - | -LL | d1.p.set(Some(&d2)); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `d2` dropped here while still borrowed - | borrow might be used here, when `d1` is dropped and runs the `Drop` code for type `D` - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `d1` does not live long enough - --> $DIR/dropck_direct_cycle_with_drop.rs:38:19 - | -LL | d2.p.set(Some(&d1)); - | ^^^ borrowed value does not live long enough -LL | //~^ ERROR `d1` does not live long enough -LL | } - | - - | | - | `d1` dropped here while still borrowed - | borrow might be used here, when `d1` is dropped and runs the `Drop` code for type `D` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/dropck_direct_cycle_with_drop.stderr b/src/test/ui/span/dropck_direct_cycle_with_drop.stderr index bc4b517c51d6e..07ae138ac71ea 100644 --- a/src/test/ui/span/dropck_direct_cycle_with_drop.stderr +++ b/src/test/ui/span/dropck_direct_cycle_with_drop.stderr @@ -1,24 +1,28 @@ error[E0597]: `d2` does not live long enough - --> $DIR/dropck_direct_cycle_with_drop.rs:36:20 + --> $DIR/dropck_direct_cycle_with_drop.rs:36:19 | LL | d1.p.set(Some(&d2)); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough ... LL | } - | - `d2` dropped here while still borrowed + | - + | | + | `d2` dropped here while still borrowed + | borrow might be used here, when `d1` is dropped and runs the `Drop` code for type `D` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `d1` does not live long enough - --> $DIR/dropck_direct_cycle_with_drop.rs:38:20 + --> $DIR/dropck_direct_cycle_with_drop.rs:38:19 | LL | d2.p.set(Some(&d1)); - | ^^ borrowed value does not live long enough -LL | //~^ ERROR `d1` does not live long enough + | ^^^ borrowed value does not live long enough +LL | LL | } - | - `d1` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created + | - + | | + | `d1` dropped here while still borrowed + | borrow might be used here, when `d1` is dropped and runs the `Drop` code for type `D` error: aborting due to 2 previous errors diff --git a/src/test/ui/span/dropck_misc_variants.nll.stderr b/src/test/ui/span/dropck_misc_variants.nll.stderr deleted file mode 100644 index 76e90574cef44..0000000000000 --- a/src/test/ui/span/dropck_misc_variants.nll.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0597]: `bomb` does not live long enough - --> $DIR/dropck_misc_variants.rs:23:36 - | -LL | _w = Wrap::<&[&str]>(NoisyDrop(&bomb)); - | ^^^^^ borrowed value does not live long enough -LL | } - | - - | | - | `bomb` dropped here while still borrowed - | borrow might be used here, when `_w` is dropped and runs the destructor for type `Wrap<&[&str]>` - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `v` does not live long enough - --> $DIR/dropck_misc_variants.rs:31:27 - | -LL | let u = NoisyDrop(&v); - | ^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `v` dropped here while still borrowed - | borrow might be used here, when `_w` is dropped and runs the destructor for closure - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/dropck_misc_variants.stderr b/src/test/ui/span/dropck_misc_variants.stderr index b2de455cdc819..76e90574cef44 100644 --- a/src/test/ui/span/dropck_misc_variants.stderr +++ b/src/test/ui/span/dropck_misc_variants.stderr @@ -1,23 +1,29 @@ error[E0597]: `bomb` does not live long enough - --> $DIR/dropck_misc_variants.rs:23:37 + --> $DIR/dropck_misc_variants.rs:23:36 | LL | _w = Wrap::<&[&str]>(NoisyDrop(&bomb)); - | ^^^^ borrowed value does not live long enough + | ^^^^^ borrowed value does not live long enough LL | } - | - `bomb` dropped here while still borrowed + | - + | | + | `bomb` dropped here while still borrowed + | borrow might be used here, when `_w` is dropped and runs the destructor for type `Wrap<&[&str]>` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `v` does not live long enough - --> $DIR/dropck_misc_variants.rs:31:28 + --> $DIR/dropck_misc_variants.rs:31:27 | LL | let u = NoisyDrop(&v); - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough ... LL | } - | - `v` dropped here while still borrowed + | - + | | + | `v` dropped here while still borrowed + | borrow might be used here, when `_w` is dropped and runs the destructor for closure | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error: aborting due to 2 previous errors diff --git a/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr b/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr deleted file mode 100644 index 05692515af846..0000000000000 --- a/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0597]: `c2` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:98:24 - | -LL | c1.v[0].v.set(Some(&c2)); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `c2` dropped here while still borrowed - | borrow might be used here, when `c1` is dropped and runs the destructor for type `C<'_>` - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `c3` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:100:24 - | -LL | c1.v[1].v.set(Some(&c3)); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `c3` dropped here while still borrowed - | borrow might be used here, when `c1` is dropped and runs the destructor for type `C<'_>` - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `c1` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:106:24 - | -LL | c3.v[0].v.set(Some(&c1)); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `c1` dropped here while still borrowed - | borrow might be used here, when `c1` is dropped and runs the destructor for type `C<'_>` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/dropck_vec_cycle_checked.rs b/src/test/ui/span/dropck_vec_cycle_checked.rs index c80e0386e6a15..bacd99c68254f 100644 --- a/src/test/ui/span/dropck_vec_cycle_checked.rs +++ b/src/test/ui/span/dropck_vec_cycle_checked.rs @@ -100,13 +100,10 @@ fn f() { c1.v[1].v.set(Some(&c3)); //~^ ERROR `c3` does not live long enough c2.v[0].v.set(Some(&c2)); - //~^ ERROR `c2` does not live long enough c2.v[1].v.set(Some(&c3)); - //~^ ERROR `c3` does not live long enough c3.v[0].v.set(Some(&c1)); //~^ ERROR `c1` does not live long enough c3.v[1].v.set(Some(&c2)); - //~^ ERROR `c2` does not live long enough } fn main() { diff --git a/src/test/ui/span/dropck_vec_cycle_checked.stderr b/src/test/ui/span/dropck_vec_cycle_checked.stderr index 35e4314d0c66f..7ff991c0c3737 100644 --- a/src/test/ui/span/dropck_vec_cycle_checked.stderr +++ b/src/test/ui/span/dropck_vec_cycle_checked.stderr @@ -1,69 +1,43 @@ error[E0597]: `c2` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:98:25 + --> $DIR/dropck_vec_cycle_checked.rs:98:24 | LL | c1.v[0].v.set(Some(&c2)); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough ... LL | } - | - `c2` dropped here while still borrowed + | - + | | + | `c2` dropped here while still borrowed + | borrow might be used here, when `c1` is dropped and runs the destructor for type `C<'_>` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `c3` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:100:25 + --> $DIR/dropck_vec_cycle_checked.rs:100:24 | LL | c1.v[1].v.set(Some(&c3)); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough ... LL | } - | - `c3` dropped here while still borrowed + | - + | | + | `c3` dropped here while still borrowed + | borrow might be used here, when `c1` is dropped and runs the destructor for type `C<'_>` | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c2` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:102:25 - | -LL | c2.v[0].v.set(Some(&c2)); - | ^^ borrowed value does not live long enough -... -LL | } - | - `c2` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c3` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:104:25 - | -LL | c2.v[1].v.set(Some(&c3)); - | ^^ borrowed value does not live long enough -... -LL | } - | - `c3` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `c1` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:106:25 + --> $DIR/dropck_vec_cycle_checked.rs:104:24 | LL | c3.v[0].v.set(Some(&c1)); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough ... LL | } - | - `c1` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `c2` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:108:25 - | -LL | c3.v[1].v.set(Some(&c2)); - | ^^ borrowed value does not live long enough -LL | //~^ ERROR `c2` does not live long enough -LL | } - | - `c2` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created + | - + | | + | `c1` dropped here while still borrowed + | borrow might be used here, when `c1` is dropped and runs the destructor for type `C<'_>` -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/gated-features-attr-spans.stderr b/src/test/ui/span/gated-features-attr-spans.stderr index 9c4c12ba07687..938edbe463fc6 100644 --- a/src/test/ui/span/gated-features-attr-spans.stderr +++ b/src/test/ui/span/gated-features-attr-spans.stderr @@ -1,9 +1,10 @@ -error[E0658]: SIMD types are experimental and possibly buggy (see issue #27731) +error[E0658]: SIMD types are experimental and possibly buggy --> $DIR/gated-features-attr-spans.rs:1:1 | -LL | #[repr(simd)] //~ ERROR are experimental +LL | #[repr(simd)] | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(repr_simd)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr index 8e08d3690e660..81409aac2897d 100644 --- a/src/test/ui/span/impl-wrong-item-for-trait.stderr +++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr @@ -68,5 +68,5 @@ LL | impl Debug for FooTypeForMethod { error: aborting due to 8 previous errors -Some errors occurred: E0046, E0323, E0324, E0325, E0437. +Some errors have detailed explanations: E0046, E0323, E0324, E0325, E0437. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/span/import-ty-params.stderr b/src/test/ui/span/import-ty-params.stderr index cff71bf2e62de..a02a1edc13499 100644 --- a/src/test/ui/span/import-ty-params.stderr +++ b/src/test/ui/span/import-ty-params.stderr @@ -1,13 +1,13 @@ error: unexpected generic arguments in path --> $DIR/import-ty-params.rs:14:15 | -LL | import! { a::b::c::S } //~ ERROR unexpected generic arguments in path +LL | import! { a::b::c::S } | ^^^^^^^^^^^^^^ error: unexpected generic arguments in path --> $DIR/import-ty-params.rs:17:15 | -LL | import! { a::b::c::S<> } //~ ERROR unexpected generic arguments in path +LL | import! { a::b::c::S<> } | ^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/span/issue-11925.nll.stderr b/src/test/ui/span/issue-11925.nll.stderr deleted file mode 100644 index f5e329f6c397e..0000000000000 --- a/src/test/ui/span/issue-11925.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0515]: cannot return reference to local data `x` - --> $DIR/issue-11925.rs:8:35 - | -LL | let f = to_fn_once(move|| &x); //~ ERROR does not live long enough - | ^^ returns a reference to data owned by the current function - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/span/issue-11925.rs b/src/test/ui/span/issue-11925.rs index 276aaa1c2931d..0f6472b05f7aa 100644 --- a/src/test/ui/span/issue-11925.rs +++ b/src/test/ui/span/issue-11925.rs @@ -5,7 +5,7 @@ fn to_fn_once>(f: F) -> F { f } fn main() { let r = { let x: Box<_> = box 42; - let f = to_fn_once(move|| &x); //~ ERROR does not live long enough + let f = to_fn_once(move|| &x); //~ ERROR cannot return reference to local data `x` f() }; diff --git a/src/test/ui/span/issue-11925.stderr b/src/test/ui/span/issue-11925.stderr index 46e2a41b3c34d..1d317fc331f73 100644 --- a/src/test/ui/span/issue-11925.stderr +++ b/src/test/ui/span/issue-11925.stderr @@ -1,15 +1,9 @@ -error[E0597]: `x` does not live long enough - --> $DIR/issue-11925.rs:8:36 +error[E0515]: cannot return reference to local data `x` + --> $DIR/issue-11925.rs:8:35 | -LL | let f = to_fn_once(move|| &x); //~ ERROR does not live long enough - | ^ - | | - | borrowed value does not live long enough - | `x` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here +LL | let f = to_fn_once(move|| &x); + | ^^ returns a reference to data owned by the current function error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/span/issue-15480.nll.stderr b/src/test/ui/span/issue-15480.nll.stderr deleted file mode 100644 index 23ee2256dd85b..0000000000000 --- a/src/test/ui/span/issue-15480.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-15480.rs:5:10 - | -LL | &id(3) - | ^^^^^ creates a temporary which is freed while still in use -LL | ]; - | - temporary value is freed at the end of this statement -... -LL | for &&x in &v { - | -- borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/span/issue-15480.rs b/src/test/ui/span/issue-15480.rs index c1024234094b6..b286d94178a1e 100644 --- a/src/test/ui/span/issue-15480.rs +++ b/src/test/ui/span/issue-15480.rs @@ -4,7 +4,7 @@ fn main() { let v = vec![ &id(3) ]; - //~^^ ERROR borrowed value does not live long enough + //~^^ ERROR temporary value dropped while borrowed for &&x in &v { println!("{}", x + 3); diff --git a/src/test/ui/span/issue-15480.stderr b/src/test/ui/span/issue-15480.stderr index c5e3899faca49..23ee2256dd85b 100644 --- a/src/test/ui/span/issue-15480.stderr +++ b/src/test/ui/span/issue-15480.stderr @@ -1,16 +1,16 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/issue-15480.rs:5:10 | LL | &id(3) - | ^^^^^ temporary value does not live long enough + | ^^^^^ creates a temporary which is freed while still in use LL | ]; - | - temporary value dropped here while still borrowed + | - temporary value is freed at the end of this statement ... -LL | } - | - temporary value needs to live until here +LL | for &&x in &v { + | -- borrow later used here | - = note: consider using a `let` binding to increase its lifetime + = note: consider using a `let` binding to create a longer lived value error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.nll.stderr b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.nll.stderr deleted file mode 100644 index 4696945814586..0000000000000 --- a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.nll.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0597]: `y` does not live long enough - --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:10:5 - | -LL | y.borrow().clone() - | ^--------- - | | - | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... -LL | } - | - - | | - | `y` dropped here while still borrowed - | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, std::string::String>` - | - = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. - -error[E0597]: `y` does not live long enough - --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:17:9 - | -LL | y.borrow().clone() - | ^--------- - | | - | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... -LL | }; - | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, std::string::String>` - | | - | `y` dropped here while still borrowed - | - = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr index f18f0da3199f0..4696945814586 100644 --- a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr +++ b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr @@ -2,21 +2,32 @@ error[E0597]: `y` does not live long enough --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:10:5 | LL | y.borrow().clone() - | ^ borrowed value does not live long enough + | ^--------- + | | + | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... LL | } - | - `y` dropped here while still borrowed + | - + | | + | `y` dropped here while still borrowed + | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, std::string::String>` | - = note: values in a scope are dropped in the opposite order they are created + = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. error[E0597]: `y` does not live long enough --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:17:9 | LL | y.borrow().clone() - | ^ borrowed value does not live long enough + | ^--------- + | | + | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... LL | }; - | -- borrowed value needs to live until here + | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, std::string::String>` | | | `y` dropped here while still borrowed + | + = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. error: aborting due to 2 previous errors diff --git a/src/test/ui/span/issue-24356.rs b/src/test/ui/span/issue-24356.rs index 7696bd54226da..7ec05aab29a71 100644 --- a/src/test/ui/span/issue-24356.rs +++ b/src/test/ui/span/issue-24356.rs @@ -1,7 +1,5 @@ // Regression test for #24356 -// ignore-tidy-linelength - fn main() { { use std::ops::Deref; diff --git a/src/test/ui/span/issue-24356.stderr b/src/test/ui/span/issue-24356.stderr index 102cc4201e2ec..4827e9ddd50fd 100644 --- a/src/test/ui/span/issue-24356.stderr +++ b/src/test/ui/span/issue-24356.stderr @@ -1,5 +1,5 @@ error[E0046]: not all trait items implemented, missing: `Target` - --> $DIR/issue-24356.rs:20:9 + --> $DIR/issue-24356.rs:18:9 | LL | impl Deref for Thing { | ^^^^^^^^^^^^^^^^^^^^ missing `Target` in implementation diff --git a/src/test/ui/span/issue-24690.stderr b/src/test/ui/span/issue-24690.stderr index 964e323b83ed4..0864497911d30 100644 --- a/src/test/ui/span/issue-24690.stderr +++ b/src/test/ui/span/issue-24690.stderr @@ -1,7 +1,7 @@ warning: unused variable: `theOtherTwo` --> $DIR/issue-24690.rs:13:9 | -LL | let theOtherTwo = 2; //~ WARN should have a snake case name +LL | let theOtherTwo = 2; | ^^^^^^^^^^^ help: consider prefixing with an underscore: `_theOtherTwo` | note: lint level defined here @@ -14,7 +14,7 @@ LL | #![warn(unused)] warning: variable `theTwo` should have a snake case name --> $DIR/issue-24690.rs:12:9 | -LL | let theTwo = 2; //~ WARN should have a snake case name +LL | let theTwo = 2; | ^^^^^^ help: convert the identifier to snake case: `the_two` | = note: #[warn(non_snake_case)] on by default @@ -22,6 +22,6 @@ LL | let theTwo = 2; //~ WARN should have a snake case name warning: variable `theOtherTwo` should have a snake case name --> $DIR/issue-24690.rs:13:9 | -LL | let theOtherTwo = 2; //~ WARN should have a snake case name +LL | let theOtherTwo = 2; | ^^^^^^^^^^^ help: convert the identifier to snake case: `the_other_two` diff --git a/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.nll.stderr b/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.nll.stderr deleted file mode 100644 index 809e60a8c8aac..0000000000000 --- a/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0597]: `d1` does not live long enough - --> $DIR/issue-24805-dropck-child-has-items-via-parent.rs:28:18 - | -LL | _d = D_Child(&d1); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `d1` dropped here while still borrowed - | borrow might be used here, when `_d` is dropped and runs the `Drop` code for type `D_Child` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.stderr b/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.stderr index ad90fcd54d44b..809e60a8c8aac 100644 --- a/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.stderr +++ b/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.stderr @@ -1,13 +1,16 @@ error[E0597]: `d1` does not live long enough - --> $DIR/issue-24805-dropck-child-has-items-via-parent.rs:28:19 + --> $DIR/issue-24805-dropck-child-has-items-via-parent.rs:28:18 | LL | _d = D_Child(&d1); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough ... LL | } - | - `d1` dropped here while still borrowed + | - + | | + | `d1` dropped here while still borrowed + | borrow might be used here, when `_d` is dropped and runs the `Drop` code for type `D_Child` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error: aborting due to previous error diff --git a/src/test/ui/span/issue-24805-dropck-trait-has-items.nll.stderr b/src/test/ui/span/issue-24805-dropck-trait-has-items.nll.stderr deleted file mode 100644 index 2e217066915d3..0000000000000 --- a/src/test/ui/span/issue-24805-dropck-trait-has-items.nll.stderr +++ /dev/null @@ -1,42 +0,0 @@ -error[E0597]: `d1` does not live long enough - --> $DIR/issue-24805-dropck-trait-has-items.rs:37:26 - | -LL | _d = D_HasSelfMethod(&d1); - | ^^^ borrowed value does not live long enough -LL | } - | - - | | - | `d1` dropped here while still borrowed - | borrow might be used here, when `_d` is dropped and runs the `Drop` code for type `D_HasSelfMethod` - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `d1` does not live long enough - --> $DIR/issue-24805-dropck-trait-has-items.rs:43:33 - | -LL | _d = D_HasMethodWithSelfArg(&d1); - | ^^^ borrowed value does not live long enough -LL | } - | - - | | - | `d1` dropped here while still borrowed - | borrow might be used here, when `_d` is dropped and runs the `Drop` code for type `D_HasMethodWithSelfArg` - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `d1` does not live long enough - --> $DIR/issue-24805-dropck-trait-has-items.rs:49:20 - | -LL | _d = D_HasType(&d1); - | ^^^ borrowed value does not live long enough -LL | } - | - - | | - | `d1` dropped here while still borrowed - | borrow might be used here, when `_d` is dropped and runs the `Drop` code for type `D_HasType` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-24805-dropck-trait-has-items.stderr b/src/test/ui/span/issue-24805-dropck-trait-has-items.stderr index 3de40149287e0..2e217066915d3 100644 --- a/src/test/ui/span/issue-24805-dropck-trait-has-items.stderr +++ b/src/test/ui/span/issue-24805-dropck-trait-has-items.stderr @@ -1,32 +1,41 @@ error[E0597]: `d1` does not live long enough - --> $DIR/issue-24805-dropck-trait-has-items.rs:37:27 + --> $DIR/issue-24805-dropck-trait-has-items.rs:37:26 | LL | _d = D_HasSelfMethod(&d1); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough LL | } - | - `d1` dropped here while still borrowed + | - + | | + | `d1` dropped here while still borrowed + | borrow might be used here, when `_d` is dropped and runs the `Drop` code for type `D_HasSelfMethod` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `d1` does not live long enough - --> $DIR/issue-24805-dropck-trait-has-items.rs:43:34 + --> $DIR/issue-24805-dropck-trait-has-items.rs:43:33 | LL | _d = D_HasMethodWithSelfArg(&d1); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough LL | } - | - `d1` dropped here while still borrowed + | - + | | + | `d1` dropped here while still borrowed + | borrow might be used here, when `_d` is dropped and runs the `Drop` code for type `D_HasMethodWithSelfArg` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `d1` does not live long enough - --> $DIR/issue-24805-dropck-trait-has-items.rs:49:21 + --> $DIR/issue-24805-dropck-trait-has-items.rs:49:20 | LL | _d = D_HasType(&d1); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough LL | } - | - `d1` dropped here while still borrowed + | - + | | + | `d1` dropped here while still borrowed + | borrow might be used here, when `_d` is dropped and runs the `Drop` code for type `D_HasType` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error: aborting due to 3 previous errors diff --git a/src/test/ui/span/issue-24895-copy-clone-dropck.nll.stderr b/src/test/ui/span/issue-24895-copy-clone-dropck.nll.stderr deleted file mode 100644 index 18a3dc9e6defa..0000000000000 --- a/src/test/ui/span/issue-24895-copy-clone-dropck.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0597]: `d1` does not live long enough - --> $DIR/issue-24895-copy-clone-dropck.rs:27:14 - | -LL | d2 = D(S(&d1, "inner"), "d2"); - | ^^^ borrowed value does not live long enough -LL | } - | - - | | - | `d1` dropped here while still borrowed - | borrow might be used here, when `d2` is dropped and runs the `Drop` code for type `D` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-24895-copy-clone-dropck.stderr b/src/test/ui/span/issue-24895-copy-clone-dropck.stderr index 91859194318bd..18a3dc9e6defa 100644 --- a/src/test/ui/span/issue-24895-copy-clone-dropck.stderr +++ b/src/test/ui/span/issue-24895-copy-clone-dropck.stderr @@ -1,12 +1,15 @@ error[E0597]: `d1` does not live long enough - --> $DIR/issue-24895-copy-clone-dropck.rs:27:15 + --> $DIR/issue-24895-copy-clone-dropck.rs:27:14 | LL | d2 = D(S(&d1, "inner"), "d2"); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough LL | } - | - `d1` dropped here while still borrowed + | - + | | + | `d1` dropped here while still borrowed + | borrow might be used here, when `d2` is dropped and runs the `Drop` code for type `D` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error: aborting due to previous error diff --git a/src/test/ui/span/issue-25199.nll.stderr b/src/test/ui/span/issue-25199.nll.stderr deleted file mode 100644 index d70a4afc1bf34..0000000000000 --- a/src/test/ui/span/issue-25199.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0597]: `container` does not live long enough - --> $DIR/issue-25199.rs:70:27 - | -LL | let test = Test{test: &container}; - | ^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `container` dropped here while still borrowed - | borrow might be used here, when `container` is dropped and runs the destructor for type `Container<'_>` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-25199.rs b/src/test/ui/span/issue-25199.rs index 4ef57457ca340..dbc3b190068ec 100644 --- a/src/test/ui/span/issue-25199.rs +++ b/src/test/ui/span/issue-25199.rs @@ -34,7 +34,7 @@ impl Drop for VecHolder { struct Container<'a> { v: VecHolder, - d: RefCell>>, + d: RefCell>>, } impl<'a> Container<'a> { @@ -71,5 +71,4 @@ fn main() { //~^ ERROR `container` does not live long enough println!("container.v[30]: {:?}", container.v.v[30]); container.store(test); - //~^ ERROR `container` does not live long enough } diff --git a/src/test/ui/span/issue-25199.stderr b/src/test/ui/span/issue-25199.stderr index 135d8150c34ed..d70a4afc1bf34 100644 --- a/src/test/ui/span/issue-25199.stderr +++ b/src/test/ui/span/issue-25199.stderr @@ -1,25 +1,15 @@ error[E0597]: `container` does not live long enough - --> $DIR/issue-25199.rs:70:28 + --> $DIR/issue-25199.rs:70:27 | LL | let test = Test{test: &container}; - | ^^^^^^^^^ borrowed value does not live long enough + | ^^^^^^^^^^ borrowed value does not live long enough ... LL | } - | - `container` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error[E0597]: `container` does not live long enough - --> $DIR/issue-25199.rs:73:5 - | -LL | container.store(test); - | ^^^^^^^^^ borrowed value does not live long enough -LL | //~^ ERROR `container` does not live long enough -LL | } - | - `container` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created + | - + | | + | `container` dropped here while still borrowed + | borrow might be used here, when `container` is dropped and runs the destructor for type `Container<'_>` -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-26656.nll.stderr b/src/test/ui/span/issue-26656.nll.stderr deleted file mode 100644 index 1e939c484fb7b..0000000000000 --- a/src/test/ui/span/issue-26656.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0597]: `ticking` does not live long enough - --> $DIR/issue-26656.rs:40:35 - | -LL | zook.button = B::BigRedButton(&ticking); - | ^^^^^^^^ borrowed value does not live long enough -LL | } - | - - | | - | `ticking` dropped here while still borrowed - | borrow might be used here, when `zook` is dropped and runs the `Drop` code for type `Zook` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-26656.rs b/src/test/ui/span/issue-26656.rs index c5a70c87ed873..cde68da189736 100644 --- a/src/test/ui/span/issue-26656.rs +++ b/src/test/ui/span/issue-26656.rs @@ -10,7 +10,7 @@ impl Trigger for () { // Still unsound Zook trait Button { fn push(&self); } -struct Zook { button: B, trigger: Box+'static> } +struct Zook { button: B, trigger: Box+'static> } impl Drop for Zook { fn drop(&mut self) { diff --git a/src/test/ui/span/issue-26656.stderr b/src/test/ui/span/issue-26656.stderr index ba2befb90a9c1..1e939c484fb7b 100644 --- a/src/test/ui/span/issue-26656.stderr +++ b/src/test/ui/span/issue-26656.stderr @@ -1,12 +1,15 @@ error[E0597]: `ticking` does not live long enough - --> $DIR/issue-26656.rs:40:36 + --> $DIR/issue-26656.rs:40:35 | LL | zook.button = B::BigRedButton(&ticking); - | ^^^^^^^ borrowed value does not live long enough + | ^^^^^^^^ borrowed value does not live long enough LL | } - | - `ticking` dropped here while still borrowed + | - + | | + | `ticking` dropped here while still borrowed + | borrow might be used here, when `zook` is dropped and runs the `Drop` code for type `Zook` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error: aborting due to previous error diff --git a/src/test/ui/span/issue-27522.stderr b/src/test/ui/span/issue-27522.stderr index 1fcb839d17059..46f424b1927b1 100644 --- a/src/test/ui/span/issue-27522.stderr +++ b/src/test/ui/span/issue-27522.stderr @@ -1,7 +1,7 @@ error[E0307]: invalid method receiver type: &SomeType --> $DIR/issue-27522.rs:6:22 | -LL | fn handler(self: &SomeType); //~ ERROR invalid method receiver type +LL | fn handler(self: &SomeType); | ^^^^^^^^^ | = note: type must be `Self` or a type that dereferences to it @@ -9,4 +9,3 @@ LL | fn handler(self: &SomeType); //~ ERROR invalid method receiver type error: aborting due to previous error -For more information about this error, try `rustc --explain E0307`. diff --git a/src/test/ui/span/issue-29106.nll.stderr b/src/test/ui/span/issue-29106.nll.stderr deleted file mode 100644 index 3b403de12d536..0000000000000 --- a/src/test/ui/span/issue-29106.nll.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0597]: `x` does not live long enough - --> $DIR/issue-29106.rs:16:26 - | -LL | y = Arc::new(Foo(&x)); - | ^^ borrowed value does not live long enough -LL | } - | - - | | - | `x` dropped here while still borrowed - | borrow might be used here, when `y` is dropped and runs the `Drop` code for type `std::sync::Arc` - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `x` does not live long enough - --> $DIR/issue-29106.rs:23:25 - | -LL | y = Rc::new(Foo(&x)); - | ^^ borrowed value does not live long enough -LL | } - | - - | | - | `x` dropped here while still borrowed - | borrow might be used here, when `y` is dropped and runs the `Drop` code for type `std::rc::Rc` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-29106.stderr b/src/test/ui/span/issue-29106.stderr index bb2f8462246b1..3b403de12d536 100644 --- a/src/test/ui/span/issue-29106.stderr +++ b/src/test/ui/span/issue-29106.stderr @@ -1,22 +1,28 @@ error[E0597]: `x` does not live long enough - --> $DIR/issue-29106.rs:16:27 + --> $DIR/issue-29106.rs:16:26 | LL | y = Arc::new(Foo(&x)); - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough LL | } - | - `x` dropped here while still borrowed + | - + | | + | `x` dropped here while still borrowed + | borrow might be used here, when `y` is dropped and runs the `Drop` code for type `std::sync::Arc` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `x` does not live long enough - --> $DIR/issue-29106.rs:23:26 + --> $DIR/issue-29106.rs:23:25 | LL | y = Rc::new(Foo(&x)); - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough LL | } - | - `x` dropped here while still borrowed + | - + | | + | `x` dropped here while still borrowed + | borrow might be used here, when `y` is dropped and runs the `Drop` code for type `std::rc::Rc` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error: aborting due to 2 previous errors diff --git a/src/test/ui/span/issue-29595.stderr b/src/test/ui/span/issue-29595.stderr index dbb1743ec0ef8..24dfdf8ebc299 100644 --- a/src/test/ui/span/issue-29595.stderr +++ b/src/test/ui/span/issue-29595.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `u8: Tr` is not satisfied --> $DIR/issue-29595.rs:6:17 | -LL | let a: u8 = Tr::C; //~ ERROR the trait bound `u8: Tr` is not satisfied +LL | let a: u8 = Tr::C; | ^^^^^ the trait `Tr` is not implemented for `u8` | note: required by `Tr::C` diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 9b3b68f6ff46a..5dd9895c6e4f4 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -1,34 +1,54 @@ error: expected one of `:` or `@`, found `<` --> $DIR/issue-34264.rs:1:14 | -LL | fn foo(Option, String) {} //~ ERROR expected one of +LL | fn foo(Option, String) {} | ^ expected one of `:` or `@` here error: expected one of `:` or `@`, found `)` --> $DIR/issue-34264.rs:1:27 | -LL | fn foo(Option, String) {} //~ ERROR expected one of +LL | fn foo(Option, String) {} | ^ expected one of `:` or `@` here + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this was a parameter name, give it a type + | +LL | fn foo(Option, String: TypeName) {} + | ^^^^^^^^^^^^^^^^ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn foo(Option, _: String) {} + | ^^^^^^^^^ error: expected one of `:` or `@`, found `,` --> $DIR/issue-34264.rs:3:9 | -LL | fn bar(x, y: usize) {} //~ ERROR expected one of +LL | fn bar(x, y: usize) {} | ^ expected one of `:` or `@` here + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this was a parameter name, give it a type + | +LL | fn bar(x: TypeName, y: usize) {} + | ^^^^^^^^^^^ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn bar(_: x, y: usize) {} + | ^^^^ error[E0061]: this function takes 2 parameters but 3 parameters were supplied --> $DIR/issue-34264.rs:7:5 | -LL | fn foo(Option, String) {} //~ ERROR expected one of +LL | fn foo(Option, String) {} | --------------------------- defined here ... -LL | foo(Some(42), 2, ""); //~ ERROR this function takes +LL | foo(Some(42), 2, ""); | ^^^^^^^^^^^^^^^^^^^^ expected 2 parameters error[E0308]: mismatched types --> $DIR/issue-34264.rs:8:13 | -LL | bar("", ""); //~ ERROR mismatched types +LL | bar("", ""); | ^^ expected usize, found reference | = note: expected type `usize` @@ -37,13 +57,13 @@ LL | bar("", ""); //~ ERROR mismatched types error[E0061]: this function takes 2 parameters but 3 parameters were supplied --> $DIR/issue-34264.rs:10:5 | -LL | fn bar(x, y: usize) {} //~ ERROR expected one of +LL | fn bar(x, y: usize) {} | ------------------- defined here ... -LL | bar(1, 2, 3); //~ ERROR this function takes +LL | bar(1, 2, 3); | ^^^^^^^^^^^^ expected 2 parameters error: aborting due to 6 previous errors -Some errors occurred: E0061, E0308. +Some errors have detailed explanations: E0061, E0308. For more information about an error, try `rustc --explain E0061`. diff --git a/src/test/ui/span/issue-36530.stderr b/src/test/ui/span/issue-36530.stderr index b2b494a2c9c34..ee479d6c79185 100644 --- a/src/test/ui/span/issue-36530.stderr +++ b/src/test/ui/span/issue-36530.stderr @@ -1,25 +1,28 @@ -error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/issue-36530.rs:3:3 | -LL | #[foo] //~ ERROR is currently unknown to the compiler +LL | #[foo] | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: non-builtin inner attributes are unstable (see issue #54726) +error[E0658]: non-builtin inner attributes are unstable --> $DIR/issue-36530.rs:5:5 | -LL | #![foo] //~ ERROR is currently unknown to the compiler +LL | #![foo] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54726 = help: add #![feature(custom_inner_attributes)] to the crate attributes to enable -error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/issue-36530.rs:5:8 | -LL | #![foo] //~ ERROR is currently unknown to the compiler +LL | #![foo] | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/span/issue-36537.nll.stderr b/src/test/ui/span/issue-36537.nll.stderr deleted file mode 100644 index edb804e850e2c..0000000000000 --- a/src/test/ui/span/issue-36537.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0597]: `a` does not live long enough - --> $DIR/issue-36537.rs:5:9 - | -LL | p = &a; - | ^^^^^^ borrowed value does not live long enough -... -LL | } - | - `a` dropped here while still borrowed -LL | p.use_ref(); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-36537.stderr b/src/test/ui/span/issue-36537.stderr index d3bcbb25add3c..edb804e850e2c 100644 --- a/src/test/ui/span/issue-36537.stderr +++ b/src/test/ui/span/issue-36537.stderr @@ -1,14 +1,13 @@ error[E0597]: `a` does not live long enough - --> $DIR/issue-36537.rs:5:14 + --> $DIR/issue-36537.rs:5:9 | LL | p = &a; - | ^ borrowed value does not live long enough + | ^^^^^^ borrowed value does not live long enough ... LL | } | - `a` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here +LL | p.use_ref(); + | - borrow later used here error: aborting due to previous error diff --git a/src/test/ui/span/issue-37767.stderr b/src/test/ui/span/issue-37767.stderr index f91f2a50e8595..0bbff45436c23 100644 --- a/src/test/ui/span/issue-37767.stderr +++ b/src/test/ui/span/issue-37767.stderr @@ -1,7 +1,7 @@ error[E0034]: multiple applicable items in scope --> $DIR/issue-37767.rs:10:7 | -LL | a.foo() //~ ERROR multiple applicable items +LL | a.foo() | ^^^ multiple `foo` found | note: candidate #1 is defined in the trait `A` @@ -20,7 +20,7 @@ LL | fn foo(&mut self) {} error[E0034]: multiple applicable items in scope --> $DIR/issue-37767.rs:22:7 | -LL | a.foo() //~ ERROR multiple applicable items +LL | a.foo() | ^^^ multiple `foo` found | note: candidate #1 is defined in the trait `C` @@ -39,7 +39,7 @@ LL | fn foo(&self) {} error[E0034]: multiple applicable items in scope --> $DIR/issue-37767.rs:34:7 | -LL | a.foo() //~ ERROR multiple applicable items +LL | a.foo() | ^^^ multiple `foo` found | note: candidate #1 is defined in the trait `E` diff --git a/src/test/ui/span/issue-39018.rs b/src/test/ui/span/issue-39018.rs index 6dbc8d39976ad..a3b1d1d81799f 100644 --- a/src/test/ui/span/issue-39018.rs +++ b/src/test/ui/span/issue-39018.rs @@ -16,3 +16,23 @@ enum World { Hello, Goodbye, } + +fn foo() { + let a = String::new(); + let b = String::new(); + let c = ""; + let d = ""; + let e = &a; + let _ = &a + &b; //~ ERROR binary operation + let _ = &a + b; //~ ERROR binary operation + let _ = a + &b; // ok + let _ = a + b; //~ ERROR mismatched types + let _ = e + b; //~ ERROR binary operation + let _ = e + &b; //~ ERROR binary operation + let _ = e + d; //~ ERROR binary operation + let _ = e + &d; //~ ERROR binary operation + let _ = &c + &d; //~ ERROR binary operation + let _ = &c + d; //~ ERROR binary operation + let _ = c + &d; //~ ERROR binary operation + let _ = c + d; //~ ERROR binary operation +} diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index 00f1b11df19e2..d8fbf841b6157 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -1,31 +1,176 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` - --> $DIR/issue-39018.rs:2:13 + --> $DIR/issue-39018.rs:2:22 | LL | let x = "Hello " + "World!"; - | ^^^^^^^^^^^^^^^^^^^ `+` can't be used to concatenate two `&str` strings + | -------- ^ -------- &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let x = "Hello ".to_owned() + "World!"; | ^^^^^^^^^^^^^^^^^^^ error[E0369]: binary operation `+` cannot be applied to type `World` - --> $DIR/issue-39018.rs:8:13 + --> $DIR/issue-39018.rs:8:26 | LL | let y = World::Hello + World::Goodbye; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------ ^ -------------- World + | | + | World | = note: an implementation of `std::ops::Add` might be missing for `World` error[E0369]: binary operation `+` cannot be applied to type `&str` - --> $DIR/issue-39018.rs:11:13 + --> $DIR/issue-39018.rs:11:22 | LL | let x = "Hello " + "World!".to_owned(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `+` can't be used to concatenate a `&str` with a `String` + | -------- ^ ------------------- std::string::String + | | | + | | `+` cannot be used to concatenate a `&str` with a `String` + | &str help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let x = "Hello ".to_owned() + &"World!".to_owned(); | ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:26:16 + | +LL | let _ = &a + &b; + | -- ^ -- &std::string::String + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &std::string::String +help: String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = a + &b; + | ^ + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:27:16 + | +LL | let _ = &a + b; + | -- ^ - std::string::String + | | | + | | `+` cannot be used to concatenate a `&str` with a `String` + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = a + &b; + | ^ ^^ + +error[E0308]: mismatched types + --> $DIR/issue-39018.rs:29:17 + | +LL | let _ = a + b; + | ^ + | | + | expected &str, found struct `std::string::String` + | help: consider borrowing here: `&b` + | + = note: expected type `&str` + found type `std::string::String` + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:30:15 + | +LL | let _ = e + b; + | - ^ - std::string::String + | | | + | | `+` cannot be used to concatenate a `&str` with a `String` + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = e.to_owned() + &b; + | ^^^^^^^^^^^^ ^^ + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:31:15 + | +LL | let _ = e + &b; + | - ^ -- &std::string::String + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = e.to_owned() + &b; + | ^^^^^^^^^^^^ + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:32:15 + | +LL | let _ = e + d; + | - ^ - &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = e.to_owned() + d; + | ^^^^^^^^^^^^ + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:33:15 + | +LL | let _ = e + &d; + | - ^ -- &&str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = e.to_owned() + &d; + | ^^^^^^^^^^^^ + +error[E0369]: binary operation `+` cannot be applied to type `&&str` + --> $DIR/issue-39018.rs:34:16 + | +LL | let _ = &c + &d; + | -- ^ -- &&str + | | + | &&str + | + = note: an implementation of `std::ops::Add` might be missing for `&&str` + +error[E0369]: binary operation `+` cannot be applied to type `&&str` + --> $DIR/issue-39018.rs:35:16 + | +LL | let _ = &c + d; + | -- ^ - &str + | | + | &&str + | + = note: an implementation of `std::ops::Add` might be missing for `&&str` + +error[E0369]: binary operation `+` cannot be applied to type `&str` + --> $DIR/issue-39018.rs:36:15 + | +LL | let _ = c + &d; + | - ^ -- &&str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = c.to_owned() + &d; + | ^^^^^^^^^^^^ + +error[E0369]: binary operation `+` cannot be applied to type `&str` + --> $DIR/issue-39018.rs:37:15 + | +LL | let _ = c + d; + | - ^ - &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = c.to_owned() + d; + | ^^^^^^^^^^^^ + +error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0369`. +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/span/issue-40157.nll.stderr b/src/test/ui/span/issue-40157.nll.stderr deleted file mode 100644 index 0b365c3f7b6b3..0000000000000 --- a/src/test/ui/span/issue-40157.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0597]: `foo` does not live long enough - --> $DIR/issue-40157.rs:2:53 - | -LL | {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });} - | ------------------------^^^--------- - | | | | - | | | `foo` dropped here while still borrowed - | | borrowed value does not live long enough - | borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-40157.stderr b/src/test/ui/span/issue-40157.stderr index 55fc8d8ee5f56..0b365c3f7b6b3 100644 --- a/src/test/ui/span/issue-40157.stderr +++ b/src/test/ui/span/issue-40157.stderr @@ -2,13 +2,11 @@ error[E0597]: `foo` does not live long enough --> $DIR/issue-40157.rs:2:53 | LL | {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });} - | -----------------------------------------------^^^---------------------- - | | | | - | | | `foo` dropped here while still borrowed - | | borrowed value does not live long enough - | borrowed value needs to live until here - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ------------------------^^^--------- + | | | | + | | | `foo` dropped here while still borrowed + | | borrowed value does not live long enough + | borrow later used here error: aborting due to previous error diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr index 1899a4e55d5ab..04c2870d83297 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `std::option::Option<_>` --> $DIR/issue-42234-unknown-receiver-type.rs:7:5 | LL | let x: Option<_> = None; - | - consider giving `x` a type + | - consider giving `x` the explicit type `std::option::Option<_>`, where the type parameter `T` is specified LL | x.unwrap().method_that_could_exist_on_some_type(); | ^^^^^^^^^^ cannot infer type for `T` | @@ -11,7 +11,7 @@ LL | x.unwrap().method_that_could_exist_on_some_type(); error[E0282]: type annotations needed --> $DIR/issue-42234-unknown-receiver-type.rs:12:5 | -LL | / data.iter() //~ ERROR type annotations needed +LL | / data.iter() LL | | .sum::<_>() | |___________________^ cannot infer type | diff --git a/src/test/ui/span/issue-7575.rs b/src/test/ui/span/issue-7575.rs index c33398cd39cab..ea0a66540b931 100644 --- a/src/test/ui/span/issue-7575.rs +++ b/src/test/ui/span/issue-7575.rs @@ -1,6 +1,4 @@ // Test the mechanism for warning about possible missing `self` declarations. -// ignore-tidy-linelength - trait CtxtFn { fn f8(self, _: usize) -> usize; fn f9(_: usize) -> usize; diff --git a/src/test/ui/span/issue-7575.stderr b/src/test/ui/span/issue-7575.stderr index b2c9e505f07b6..614638752f166 100644 --- a/src/test/ui/span/issue-7575.stderr +++ b/src/test/ui/span/issue-7575.stderr @@ -1,24 +1,24 @@ error[E0599]: no method named `f9` found for type `usize` in the current scope - --> $DIR/issue-7575.rs:64:18 + --> $DIR/issue-7575.rs:62:18 | LL | u.f8(42) + u.f9(342) + m.fff(42) | ^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: candidate #1 is defined in the trait `CtxtFn` - --> $DIR/issue-7575.rs:6:5 + --> $DIR/issue-7575.rs:4:5 | LL | fn f9(_: usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^ = help: to disambiguate the method call, write `CtxtFn::f9(u, 342)` instead note: candidate #2 is defined in the trait `OtherTrait` - --> $DIR/issue-7575.rs:10:5 + --> $DIR/issue-7575.rs:8:5 | LL | fn f9(_: usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^ = help: to disambiguate the method call, write `OtherTrait::f9(u, 342)` instead note: candidate #3 is defined in the trait `UnusedTrait` - --> $DIR/issue-7575.rs:19:5 + --> $DIR/issue-7575.rs:17:5 | LL | fn f9(_: usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | fn f9(_: usize) -> usize; candidate #3: `UnusedTrait` error[E0599]: no method named `fff` found for type `Myisize` in the current scope - --> $DIR/issue-7575.rs:64:30 + --> $DIR/issue-7575.rs:62:30 | LL | struct Myisize(isize); | ---------------------- method `fff` not found for this @@ -43,20 +43,20 @@ LL | u.f8(42) + u.f9(342) + m.fff(42) | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `Myisize` - --> $DIR/issue-7575.rs:41:5 + --> $DIR/issue-7575.rs:39:5 | LL | fn fff(i: isize) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0599]: no method named `is_str` found for type `T` in the current scope - --> $DIR/issue-7575.rs:72:7 + --> $DIR/issue-7575.rs:70:7 | LL | t.is_str() | ^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `ManyImplTrait` - --> $DIR/issue-7575.rs:47:5 + --> $DIR/issue-7575.rs:45:5 | LL | fn is_str() -> bool { | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/span/issue28498-reject-ex1.nll.stderr b/src/test/ui/span/issue28498-reject-ex1.nll.stderr deleted file mode 100644 index 86e2d8c56b08f..0000000000000 --- a/src/test/ui/span/issue28498-reject-ex1.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0713]: borrow may still be in use when destructor runs - --> $DIR/issue28498-reject-ex1.rs:34:29 - | -LL | foo.data[0].1.set(Some(&foo.data[1])); - | ^^^^^^^^ -... -LL | } - | - - | | - | here, drop of `foo` needs exclusive access to `foo.data`, because the type `Foo>` implements the `Drop` trait - | borrow might be used here, when `foo` is dropped and runs the `Drop` code for type `Foo` - | - = note: consider using a `let` binding to create a longer lived value - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0713`. diff --git a/src/test/ui/span/issue28498-reject-ex1.rs b/src/test/ui/span/issue28498-reject-ex1.rs index 05104d1cdc020..4d1b4125503b6 100644 --- a/src/test/ui/span/issue28498-reject-ex1.rs +++ b/src/test/ui/span/issue28498-reject-ex1.rs @@ -32,7 +32,6 @@ fn main() { foo.data.push(Concrete(0, Cell::new(None))); foo.data[0].1.set(Some(&foo.data[1])); - //~^ ERROR `foo.data` does not live long enough + //~^ ERROR borrow may still be in use when destructor runs foo.data[1].1.set(Some(&foo.data[0])); - //~^ ERROR `foo.data` does not live long enough } diff --git a/src/test/ui/span/issue28498-reject-ex1.stderr b/src/test/ui/span/issue28498-reject-ex1.stderr index 8daef82f8bbd8..86e2d8c56b08f 100644 --- a/src/test/ui/span/issue28498-reject-ex1.stderr +++ b/src/test/ui/span/issue28498-reject-ex1.stderr @@ -1,25 +1,17 @@ -error[E0597]: `foo.data` does not live long enough +error[E0713]: borrow may still be in use when destructor runs --> $DIR/issue28498-reject-ex1.rs:34:29 | LL | foo.data[0].1.set(Some(&foo.data[1])); - | ^^^^^^^^ borrowed value does not live long enough + | ^^^^^^^^ ... LL | } - | - `foo.data` dropped here while still borrowed + | - + | | + | here, drop of `foo` needs exclusive access to `foo.data`, because the type `Foo>` implements the `Drop` trait + | borrow might be used here, when `foo` is dropped and runs the `Drop` code for type `Foo` | - = note: values in a scope are dropped in the opposite order they are created + = note: consider using a `let` binding to create a longer lived value -error[E0597]: `foo.data` does not live long enough - --> $DIR/issue28498-reject-ex1.rs:36:29 - | -LL | foo.data[1].1.set(Some(&foo.data[0])); - | ^^^^^^^^ borrowed value does not live long enough -LL | //~^ ERROR `foo.data` does not live long enough -LL | } - | - `foo.data` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0713`. diff --git a/src/test/ui/span/issue28498-reject-lifetime-param.nll.stderr b/src/test/ui/span/issue28498-reject-lifetime-param.nll.stderr deleted file mode 100644 index 3273b51ba0f04..0000000000000 --- a/src/test/ui/span/issue28498-reject-lifetime-param.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0597]: `first_dropped` does not live long enough - --> $DIR/issue28498-reject-lifetime-param.rs:34:19 - | -LL | foo1 = Foo(1, &first_dropped); - | ^^^^^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `first_dropped` dropped here while still borrowed - | borrow might be used here, when `foo1` is dropped and runs the `Drop` code for type `Foo` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue28498-reject-lifetime-param.rs b/src/test/ui/span/issue28498-reject-lifetime-param.rs index 062636af3f1e3..9bc01766be564 100644 --- a/src/test/ui/span/issue28498-reject-lifetime-param.rs +++ b/src/test/ui/span/issue28498-reject-lifetime-param.rs @@ -29,8 +29,7 @@ fn main() { last_dropped = ScribbleOnDrop(format!("last")); first_dropped = ScribbleOnDrop(format!("first")); - foo0 = Foo(0, &last_dropped); - //~^ ERROR `last_dropped` does not live long enough + foo0 = Foo(0, &last_dropped); // OK foo1 = Foo(1, &first_dropped); //~^ ERROR `first_dropped` does not live long enough diff --git a/src/test/ui/span/issue28498-reject-lifetime-param.stderr b/src/test/ui/span/issue28498-reject-lifetime-param.stderr index 0e51729f8d6ba..1dcb40e5d9cb7 100644 --- a/src/test/ui/span/issue28498-reject-lifetime-param.stderr +++ b/src/test/ui/span/issue28498-reject-lifetime-param.stderr @@ -1,25 +1,17 @@ -error[E0597]: `last_dropped` does not live long enough - --> $DIR/issue28498-reject-lifetime-param.rs:32:20 - | -LL | foo0 = Foo(0, &last_dropped); - | ^^^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `last_dropped` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - error[E0597]: `first_dropped` does not live long enough - --> $DIR/issue28498-reject-lifetime-param.rs:34:20 + --> $DIR/issue28498-reject-lifetime-param.rs:33:19 | LL | foo1 = Foo(1, &first_dropped); - | ^^^^^^^^^^^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^^^ borrowed value does not live long enough ... LL | } - | - `first_dropped` dropped here while still borrowed + | - + | | + | `first_dropped` dropped here while still borrowed + | borrow might be used here, when `foo1` is dropped and runs the `Drop` code for type `Foo` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue28498-reject-passed-to-fn.nll.stderr b/src/test/ui/span/issue28498-reject-passed-to-fn.nll.stderr deleted file mode 100644 index ae08e3e5e6c5c..0000000000000 --- a/src/test/ui/span/issue28498-reject-passed-to-fn.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0597]: `first_dropped` does not live long enough - --> $DIR/issue28498-reject-passed-to-fn.rs:36:19 - | -LL | foo1 = Foo(1, &first_dropped, Box::new(callback)); - | ^^^^^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `first_dropped` dropped here while still borrowed - | borrow might be used here, when `foo1` is dropped and runs the `Drop` code for type `Foo` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue28498-reject-passed-to-fn.rs b/src/test/ui/span/issue28498-reject-passed-to-fn.rs index 27a757e850bdc..c59de5df41170 100644 --- a/src/test/ui/span/issue28498-reject-passed-to-fn.rs +++ b/src/test/ui/span/issue28498-reject-passed-to-fn.rs @@ -31,8 +31,7 @@ fn main() { last_dropped = ScribbleOnDrop(format!("last")); first_dropped = ScribbleOnDrop(format!("first")); - foo0 = Foo(0, &last_dropped, Box::new(callback)); - //~^ ERROR `last_dropped` does not live long enough + foo0 = Foo(0, &last_dropped, Box::new(callback)); // OK foo1 = Foo(1, &first_dropped, Box::new(callback)); //~^ ERROR `first_dropped` does not live long enough diff --git a/src/test/ui/span/issue28498-reject-passed-to-fn.stderr b/src/test/ui/span/issue28498-reject-passed-to-fn.stderr index 80533c79f10fd..214a6f6d65ca5 100644 --- a/src/test/ui/span/issue28498-reject-passed-to-fn.stderr +++ b/src/test/ui/span/issue28498-reject-passed-to-fn.stderr @@ -1,25 +1,17 @@ -error[E0597]: `last_dropped` does not live long enough - --> $DIR/issue28498-reject-passed-to-fn.rs:34:20 - | -LL | foo0 = Foo(0, &last_dropped, Box::new(callback)); - | ^^^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `last_dropped` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - error[E0597]: `first_dropped` does not live long enough - --> $DIR/issue28498-reject-passed-to-fn.rs:36:20 + --> $DIR/issue28498-reject-passed-to-fn.rs:35:19 | LL | foo1 = Foo(1, &first_dropped, Box::new(callback)); - | ^^^^^^^^^^^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^^^ borrowed value does not live long enough ... LL | } - | - `first_dropped` dropped here while still borrowed + | - + | | + | `first_dropped` dropped here while still borrowed + | borrow might be used here, when `foo1` is dropped and runs the `Drop` code for type `Foo` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue28498-reject-trait-bound.nll.stderr b/src/test/ui/span/issue28498-reject-trait-bound.nll.stderr deleted file mode 100644 index 600fd539fe4d0..0000000000000 --- a/src/test/ui/span/issue28498-reject-trait-bound.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0597]: `first_dropped` does not live long enough - --> $DIR/issue28498-reject-trait-bound.rs:36:19 - | -LL | foo1 = Foo(1, &first_dropped); - | ^^^^^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `first_dropped` dropped here while still borrowed - | borrow might be used here, when `foo1` is dropped and runs the `Drop` code for type `Foo` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue28498-reject-trait-bound.rs b/src/test/ui/span/issue28498-reject-trait-bound.rs index 3ea67d1662d56..8813180c8919f 100644 --- a/src/test/ui/span/issue28498-reject-trait-bound.rs +++ b/src/test/ui/span/issue28498-reject-trait-bound.rs @@ -31,8 +31,7 @@ fn main() { last_dropped = ScribbleOnDrop(format!("last")); first_dropped = ScribbleOnDrop(format!("first")); - foo0 = Foo(0, &last_dropped); - //~^ ERROR `last_dropped` does not live long enough + foo0 = Foo(0, &last_dropped); // OK foo1 = Foo(1, &first_dropped); //~^ ERROR `first_dropped` does not live long enough diff --git a/src/test/ui/span/issue28498-reject-trait-bound.stderr b/src/test/ui/span/issue28498-reject-trait-bound.stderr index 3ce4dd9fdd684..d4fe291bef398 100644 --- a/src/test/ui/span/issue28498-reject-trait-bound.stderr +++ b/src/test/ui/span/issue28498-reject-trait-bound.stderr @@ -1,25 +1,17 @@ -error[E0597]: `last_dropped` does not live long enough - --> $DIR/issue28498-reject-trait-bound.rs:34:20 - | -LL | foo0 = Foo(0, &last_dropped); - | ^^^^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `last_dropped` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created - error[E0597]: `first_dropped` does not live long enough - --> $DIR/issue28498-reject-trait-bound.rs:36:20 + --> $DIR/issue28498-reject-trait-bound.rs:35:19 | LL | foo1 = Foo(1, &first_dropped); - | ^^^^^^^^^^^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^^^ borrowed value does not live long enough ... LL | } - | - `first_dropped` dropped here while still borrowed + | - + | | + | `first_dropped` dropped here while still borrowed + | borrow might be used here, when `foo1` is dropped and runs the `Drop` code for type `Foo` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/lint-unused-unsafe.stderr b/src/test/ui/span/lint-unused-unsafe.stderr index 7f16cfae859ed..ac8107990c2bd 100644 --- a/src/test/ui/span/lint-unused-unsafe.stderr +++ b/src/test/ui/span/lint-unused-unsafe.stderr @@ -1,7 +1,7 @@ error: unnecessary `unsafe` block --> $DIR/lint-unused-unsafe.rs:16:13 | -LL | fn bad1() { unsafe {} } //~ ERROR: unnecessary `unsafe` block +LL | fn bad1() { unsafe {} } | ^^^^^^ unnecessary `unsafe` block | note: lint level defined here @@ -13,13 +13,13 @@ LL | #![deny(unused_unsafe)] error: unnecessary `unsafe` block --> $DIR/lint-unused-unsafe.rs:17:13 | -LL | fn bad2() { unsafe { bad1() } } //~ ERROR: unnecessary `unsafe` block +LL | fn bad2() { unsafe { bad1() } } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block --> $DIR/lint-unused-unsafe.rs:18:20 | -LL | unsafe fn bad3() { unsafe {} } //~ ERROR: unnecessary `unsafe` block +LL | unsafe fn bad3() { unsafe {} } | ---------------- ^^^^^^ unnecessary `unsafe` block | | | because it's nested under this `unsafe` fn @@ -27,13 +27,13 @@ LL | unsafe fn bad3() { unsafe {} } //~ ERROR: unnecessary `unsafe` bl error: unnecessary `unsafe` block --> $DIR/lint-unused-unsafe.rs:19:13 | -LL | fn bad4() { unsafe { callback(||{}) } } //~ ERROR: unnecessary `unsafe` block +LL | fn bad4() { unsafe { callback(||{}) } } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block --> $DIR/lint-unused-unsafe.rs:20:20 | -LL | unsafe fn bad5() { unsafe { unsf() } } //~ ERROR: unnecessary `unsafe` block +LL | unsafe fn bad5() { unsafe { unsf() } } | ---------------- ^^^^^^ unnecessary `unsafe` block | | | because it's nested under this `unsafe` fn @@ -43,7 +43,7 @@ error: unnecessary `unsafe` block | LL | unsafe { // don't put the warning here | ------ because it's nested under this `unsafe` block -LL | unsafe { //~ ERROR: unnecessary `unsafe` block +LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block @@ -51,7 +51,7 @@ error: unnecessary `unsafe` block | LL | unsafe fn bad7() { | ---------------- because it's nested under this `unsafe` fn -LL | unsafe { //~ ERROR: unnecessary `unsafe` block +LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block @@ -59,8 +59,8 @@ error: unnecessary `unsafe` block | LL | unsafe fn bad7() { | ---------------- because it's nested under this `unsafe` fn -LL | unsafe { //~ ERROR: unnecessary `unsafe` block -LL | unsafe { //~ ERROR: unnecessary `unsafe` block +LL | unsafe { +LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: aborting due to 8 previous errors diff --git a/src/test/ui/span/macro-span-replacement.stderr b/src/test/ui/span/macro-span-replacement.stderr index f6c303164bfd1..128e4ec1212ca 100644 --- a/src/test/ui/span/macro-span-replacement.stderr +++ b/src/test/ui/span/macro-span-replacement.stderr @@ -1,7 +1,7 @@ warning: struct is never constructed: `S` --> $DIR/macro-span-replacement.rs:7:14 | -LL | $b $a; //~ WARN struct is never constructed +LL | $b $a; | ^ ... LL | m!(S struct); diff --git a/src/test/ui/span/macro-ty-params.stderr b/src/test/ui/span/macro-ty-params.stderr index 965ca7000be80..39b3edc67033d 100644 --- a/src/test/ui/span/macro-ty-params.stderr +++ b/src/test/ui/span/macro-ty-params.stderr @@ -1,25 +1,25 @@ error: generic arguments in macro path --> $DIR/macro-ty-params.rs:10:10 | -LL | foo::!(); //~ ERROR generic arguments in macro path +LL | foo::!(); | ^^^ error: generic arguments in macro path --> $DIR/macro-ty-params.rs:11:10 | -LL | foo::<>!(); //~ ERROR generic arguments in macro path +LL | foo::<>!(); | ^^ error: unexpected generic arguments in path --> $DIR/macro-ty-params.rs:12:8 | -LL | m!(Default<>); //~ ERROR generic arguments in macro path +LL | m!(Default<>); | ^^^^^^^^^ error: generic arguments in macro path --> $DIR/macro-ty-params.rs:12:15 | -LL | m!(Default<>); //~ ERROR generic arguments in macro path +LL | m!(Default<>); | ^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/span/missing-unit-argument.stderr b/src/test/ui/span/missing-unit-argument.stderr index bf19eb6946189..f1a29bed32b1c 100644 --- a/src/test/ui/span/missing-unit-argument.stderr +++ b/src/test/ui/span/missing-unit-argument.stderr @@ -1,11 +1,11 @@ error[E0061]: this function takes 1 parameter but 0 parameters were supplied --> $DIR/missing-unit-argument.rs:11:33 | -LL | let _: Result<(), String> = Ok(); //~ ERROR this function takes +LL | let _: Result<(), String> = Ok(); | ^^^^ help: expected the unit value `()`; create it with empty parentheses | -LL | let _: Result<(), String> = Ok(()); //~ ERROR this function takes +LL | let _: Result<(), String> = Ok(()); | ^^ error[E0061]: this function takes 2 parameters but 0 parameters were supplied @@ -14,7 +14,7 @@ error[E0061]: this function takes 2 parameters but 0 parameters were supplied LL | fn foo(():(), ():()) {} | -------------------- defined here ... -LL | foo(); //~ ERROR this function takes +LL | foo(); | ^^^^^ expected 2 parameters error[E0061]: this function takes 2 parameters but 1 parameter was supplied @@ -23,7 +23,7 @@ error[E0061]: this function takes 2 parameters but 1 parameter was supplied LL | fn foo(():(), ():()) {} | -------------------- defined here ... -LL | foo(()); //~ ERROR this function takes +LL | foo(()); | ^^^^^^^ expected 2 parameters error[E0061]: this function takes 1 parameter but 0 parameters were supplied @@ -32,11 +32,11 @@ error[E0061]: this function takes 1 parameter but 0 parameters were supplied LL | fn bar(():()) {} | ------------- defined here ... -LL | bar(); //~ ERROR this function takes +LL | bar(); | ^^^^^ help: expected the unit value `()`; create it with empty parentheses | -LL | bar(()); //~ ERROR this function takes +LL | bar(()); | ^^ error[E0061]: this function takes 1 parameter but 0 parameters were supplied @@ -45,11 +45,11 @@ error[E0061]: this function takes 1 parameter but 0 parameters were supplied LL | fn baz(self, (): ()) { } | -------------------- defined here ... -LL | S.baz(); //~ ERROR this function takes +LL | S.baz(); | ^^^ help: expected the unit value `()`; create it with empty parentheses | -LL | S.baz(()); //~ ERROR this function takes +LL | S.baz(()); | ^^ error[E0061]: this function takes 1 parameter but 0 parameters were supplied @@ -58,11 +58,11 @@ error[E0061]: this function takes 1 parameter but 0 parameters were supplied LL | fn generic(self, _: T) { } | ------------------------- defined here ... -LL | S.generic::<()>(); //~ ERROR this function takes +LL | S.generic::<()>(); | ^^^^^^^ help: expected the unit value `()`; create it with empty parentheses | -LL | S.generic::<()>(()); //~ ERROR this function takes +LL | S.generic::<()>(()); | ^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/span/move-closure.stderr b/src/test/ui/span/move-closure.stderr index f09e052f6530f..e2226b197aeb8 100644 --- a/src/test/ui/span/move-closure.stderr +++ b/src/test/ui/span/move-closure.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/move-closure.rs:5:17 | -LL | let x: () = move || (); //~ ERROR mismatched types +LL | let x: () = move || (); | ^^^^^^^^^^ expected (), found closure | = note: expected type `()` diff --git a/src/test/ui/span/multiline-span-E0072.stderr b/src/test/ui/span/multiline-span-E0072.stderr index ee392f5994c84..dd322fe833b49 100644 --- a/src/test/ui/span/multiline-span-E0072.stderr +++ b/src/test/ui/span/multiline-span-E0072.stderr @@ -1,7 +1,7 @@ error[E0072]: recursive type `ListNode` has infinite size --> $DIR/multiline-span-E0072.rs:2:1 | -LL | / struct //~ ERROR has infinite size +LL | / struct LL | | ListNode LL | | { LL | | head: u8, diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index 18b6cd06afbbb..6495d9bc73977 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -1,7 +1,7 @@ error[E0277]: cannot add `()` to `u32` --> $DIR/multiline-span-simple.rs:13:18 | -LL | foo(1 as u32 + //~ ERROR cannot add `()` to `u32` +LL | foo(1 as u32 + | ^ no implementation for `u32 + ()` | = help: the trait `std::ops::Add<()>` is not implemented for `u32` diff --git a/src/test/ui/span/mut-arg-hint.nll.stderr b/src/test/ui/span/mut-arg-hint.nll.stderr deleted file mode 100644 index e0fa3c3a1e6f5..0000000000000 --- a/src/test/ui/span/mut-arg-hint.nll.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference - --> $DIR/mut-arg-hint.rs:3:9 - | -LL | fn foo(mut a: &String) { - | ------- help: consider changing this to be a mutable reference: `&mut std::string::String` -LL | a.push_str("bar"); //~ ERROR cannot borrow immutable borrowed content - | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference - --> $DIR/mut-arg-hint.rs:8:5 - | -LL | pub fn foo<'a>(mut a: &'a String) { - | ---------- help: consider changing this to be a mutable reference: `&'a mut String` -LL | a.push_str("foo"); //~ ERROR cannot borrow immutable borrowed content - | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference - --> $DIR/mut-arg-hint.rs:15:9 - | -LL | pub fn foo(mut a: &String) { - | ------- help: consider changing this to be a mutable reference: `&mut std::string::String` -LL | a.push_str("foo"); //~ ERROR cannot borrow immutable borrowed content - | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/span/mut-arg-hint.rs b/src/test/ui/span/mut-arg-hint.rs index 3d46613aa7ac9..d7ff1f0de4180 100644 --- a/src/test/ui/span/mut-arg-hint.rs +++ b/src/test/ui/span/mut-arg-hint.rs @@ -1,18 +1,18 @@ trait B { fn foo(mut a: &String) { - a.push_str("bar"); //~ ERROR cannot borrow immutable borrowed content + a.push_str("bar"); //~ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference } } pub fn foo<'a>(mut a: &'a String) { - a.push_str("foo"); //~ ERROR cannot borrow immutable borrowed content + a.push_str("foo"); //~ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference } struct A {} impl A { pub fn foo(mut a: &String) { - a.push_str("foo"); //~ ERROR cannot borrow immutable borrowed content + a.push_str("foo"); //~ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference } } diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr index ea6fc8bee637b..8027cf69cf4bc 100644 --- a/src/test/ui/span/mut-arg-hint.stderr +++ b/src/test/ui/span/mut-arg-hint.stderr @@ -1,26 +1,26 @@ -error[E0596]: cannot borrow immutable borrowed content `*a` as mutable +error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:3:9 | LL | fn foo(mut a: &String) { - | ------- use `&mut String` here to make mutable -LL | a.push_str("bar"); //~ ERROR cannot borrow immutable borrowed content - | ^ cannot borrow as mutable + | ------- help: consider changing this to be a mutable reference: `&mut std::string::String` +LL | a.push_str("bar"); + | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable borrowed content `*a` as mutable +error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:8:5 | LL | pub fn foo<'a>(mut a: &'a String) { - | ---------- use `&'a mut String` here to make mutable -LL | a.push_str("foo"); //~ ERROR cannot borrow immutable borrowed content - | ^ cannot borrow as mutable + | ---------- help: consider changing this to be a mutable reference: `&'a mut String` +LL | a.push_str("foo"); + | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow immutable borrowed content `*a` as mutable +error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:15:9 | LL | pub fn foo(mut a: &String) { - | ------- use `&mut String` here to make mutable -LL | a.push_str("foo"); //~ ERROR cannot borrow immutable borrowed content - | ^ cannot borrow as mutable + | ------- help: consider changing this to be a mutable reference: `&mut std::string::String` +LL | a.push_str("foo"); + | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to 3 previous errors diff --git a/src/test/ui/span/mut-ptr-cant-outlive-ref.nll.stderr b/src/test/ui/span/mut-ptr-cant-outlive-ref.nll.stderr deleted file mode 100644 index d3ba848fe6bb7..0000000000000 --- a/src/test/ui/span/mut-ptr-cant-outlive-ref.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0597]: `b` does not live long enough - --> $DIR/mut-ptr-cant-outlive-ref.rs:8:15 - | -LL | p = &*b; - | ^ borrowed value does not live long enough -LL | } - | - `b` dropped here while still borrowed -LL | //~^^ ERROR `b` does not live long enough -LL | p.use_ref(); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr b/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr index f6cf568a8d2bf..21b29464df502 100644 --- a/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr +++ b/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr @@ -5,9 +5,9 @@ LL | p = &*b; | ^ borrowed value does not live long enough LL | } | - `b` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here +LL | +LL | p.use_ref(); + | - borrow later used here error: aborting due to previous error diff --git a/src/test/ui/span/non-existing-module-import.stderr b/src/test/ui/span/non-existing-module-import.stderr index 5ac5df1b4c738..25c09959047a1 100644 --- a/src/test/ui/span/non-existing-module-import.stderr +++ b/src/test/ui/span/non-existing-module-import.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `std::bar` --> $DIR/non-existing-module-import.rs:1:10 | -LL | use std::bar::{foo1, foo2}; //~ ERROR unresolved import +LL | use std::bar::{foo1, foo2}; | ^^^ could not find `bar` in `std` error: aborting due to previous error diff --git a/src/test/ui/span/pub-struct-field.stderr b/src/test/ui/span/pub-struct-field.stderr index 66afbf253c9b9..065340f446a79 100644 --- a/src/test/ui/span/pub-struct-field.stderr +++ b/src/test/ui/span/pub-struct-field.stderr @@ -3,7 +3,7 @@ error[E0124]: field `bar` is already declared | LL | bar: u8, | ------- `bar` first declared here -LL | pub bar: u8, //~ ERROR is already declared +LL | pub bar: u8, | ^^^^^^^^^^^ field already declared error[E0124]: field `bar` is already declared @@ -11,8 +11,8 @@ error[E0124]: field `bar` is already declared | LL | bar: u8, | ------- `bar` first declared here -LL | pub bar: u8, //~ ERROR is already declared -LL | pub(crate) bar: u8, //~ ERROR is already declared +LL | pub bar: u8, +LL | pub(crate) bar: u8, | ^^^^^^^^^^^^^^^^^^ field already declared error: aborting due to 2 previous errors diff --git a/src/test/ui/span/range-2.nll.stderr b/src/test/ui/span/range-2.nll.stderr deleted file mode 100644 index 8ca8156b0830c..0000000000000 --- a/src/test/ui/span/range-2.nll.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0597]: `a` does not live long enough - --> $DIR/range-2.rs:7:9 - | -LL | let r = { - | - borrow later stored here -... -LL | &a..&b - | ^^ borrowed value does not live long enough -LL | }; - | - `a` dropped here while still borrowed - -error[E0597]: `b` does not live long enough - --> $DIR/range-2.rs:7:13 - | -LL | let r = { - | - borrow later stored here -... -LL | &a..&b - | ^^ borrowed value does not live long enough -LL | }; - | - `b` dropped here while still borrowed - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/range-2.stderr b/src/test/ui/span/range-2.stderr index 7d0edd6971ceb..8ca8156b0830c 100644 --- a/src/test/ui/span/range-2.stderr +++ b/src/test/ui/span/range-2.stderr @@ -1,24 +1,24 @@ error[E0597]: `a` does not live long enough - --> $DIR/range-2.rs:7:10 + --> $DIR/range-2.rs:7:9 | +LL | let r = { + | - borrow later stored here +... LL | &a..&b - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough LL | }; | - `a` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here error[E0597]: `b` does not live long enough - --> $DIR/range-2.rs:7:14 + --> $DIR/range-2.rs:7:13 | +LL | let r = { + | - borrow later stored here +... LL | &a..&b - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough LL | }; | - `b` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here error: aborting due to 2 previous errors diff --git a/src/test/ui/span/recursive-type-field.stderr b/src/test/ui/span/recursive-type-field.stderr index 3a8f0e60038e5..d240872647e50 100644 --- a/src/test/ui/span/recursive-type-field.stderr +++ b/src/test/ui/span/recursive-type-field.stderr @@ -1,7 +1,7 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/recursive-type-field.rs:3:1 | -LL | struct Foo<'a> { //~ ERROR recursive type +LL | struct Foo<'a> { | ^^^^^^^^^^^^^^ recursive type has infinite size LL | bar: Bar<'a>, | ------------ recursive without indirection @@ -11,7 +11,7 @@ LL | bar: Bar<'a>, error[E0072]: recursive type `Bar` has infinite size --> $DIR/recursive-type-field.rs:8:1 | -LL | struct Bar<'a> { //~ ERROR recursive type +LL | struct Bar<'a> { | ^^^^^^^^^^^^^^ recursive type has infinite size LL | y: (Foo<'a>, Foo<'a>), | --------------------- recursive without indirection diff --git a/src/test/ui/span/regionck-unboxed-closure-lifetimes.nll.stderr b/src/test/ui/span/regionck-unboxed-closure-lifetimes.nll.stderr deleted file mode 100644 index 8e9cd59515443..0000000000000 --- a/src/test/ui/span/regionck-unboxed-closure-lifetimes.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0597]: `c` does not live long enough - --> $DIR/regionck-unboxed-closure-lifetimes.rs:8:21 - | -LL | let c_ref = &c; - | ^^ borrowed value does not live long enough -... -LL | } - | - `c` dropped here while still borrowed -LL | f.use_mut(); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr b/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr index b3f09669f5fc7..8e9cd59515443 100644 --- a/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr +++ b/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr @@ -1,14 +1,13 @@ error[E0597]: `c` does not live long enough - --> $DIR/regionck-unboxed-closure-lifetimes.rs:8:22 + --> $DIR/regionck-unboxed-closure-lifetimes.rs:8:21 | LL | let c_ref = &c; - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough ... LL | } | - `c` dropped here while still borrowed LL | f.use_mut(); -LL | } - | - borrowed value needs to live until here + | - borrow later used here error: aborting due to previous error diff --git a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr deleted file mode 100644 index 2be2d0ff7b5ad..0000000000000 --- a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/regions-close-over-borrowed-ref-in-obj.rs:12:27 - | -LL | let ss: &isize = &id(1); - | ^^^^^ creates a temporary which is freed while still in use -... -LL | } - | - temporary value is freed at the end of this statement -LL | } - | - borrow might be used here, when `blah` is dropped and runs the destructor for type `std::boxed::Box` - | - = note: consider using a `let` binding to create a longer lived value - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs index 9ca352a07fcec..e34f84683bbc7 100644 --- a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs +++ b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs @@ -10,7 +10,7 @@ fn main() { let blah; { let ss: &isize = &id(1); - //~^ ERROR borrowed value does not live long enough - blah = box ss as Box; + //~^ ERROR temporary value dropped while borrowed + blah = box ss as Box; } } diff --git a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr index 8a853e7ce59de..2be2d0ff7b5ad 100644 --- a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr +++ b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr @@ -1,14 +1,16 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/regions-close-over-borrowed-ref-in-obj.rs:12:27 | LL | let ss: &isize = &id(1); - | ^^^^^ temporary value does not live long enough + | ^^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value dropped here while still borrowed + | - temporary value is freed at the end of this statement LL | } - | - temporary value needs to live until here + | - borrow might be used here, when `blah` is dropped and runs the destructor for type `std::boxed::Box` + | + = note: consider using a `let` binding to create a longer lived value error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr b/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr deleted file mode 100644 index 2e584d9a884f1..0000000000000 --- a/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0597]: `tmp0` does not live long enough - --> $DIR/regions-close-over-type-parameter-2.rs:23:20 - | -LL | let tmp1 = &tmp0; - | ^^^^^ borrowed value does not live long enough -LL | repeater3(tmp1) - | --------------- borrow later captured here by trait object -LL | }; - | - `tmp0` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/regions-close-over-type-parameter-2.rs b/src/test/ui/span/regions-close-over-type-parameter-2.rs index 11187b74c4299..29083154b8991 100644 --- a/src/test/ui/span/regions-close-over-type-parameter-2.rs +++ b/src/test/ui/span/regions-close-over-type-parameter-2.rs @@ -10,8 +10,8 @@ impl Foo for A { fn get(&self) { } } -fn repeater3<'a,A:'a>(v: A) -> Box { - box v as Box +fn repeater3<'a,A:'a>(v: A) -> Box { + box v as Box } fn main() { diff --git a/src/test/ui/span/regions-close-over-type-parameter-2.stderr b/src/test/ui/span/regions-close-over-type-parameter-2.stderr index 5ee155c1d1818..2e584d9a884f1 100644 --- a/src/test/ui/span/regions-close-over-type-parameter-2.stderr +++ b/src/test/ui/span/regions-close-over-type-parameter-2.stderr @@ -1,13 +1,12 @@ error[E0597]: `tmp0` does not live long enough - --> $DIR/regions-close-over-type-parameter-2.rs:23:21 + --> $DIR/regions-close-over-type-parameter-2.rs:23:20 | LL | let tmp1 = &tmp0; - | ^^^^ borrowed value does not live long enough + | ^^^^^ borrowed value does not live long enough LL | repeater3(tmp1) + | --------------- borrow later captured here by trait object LL | }; - | -- borrowed value needs to live until here - | | - | `tmp0` dropped here while still borrowed + | - `tmp0` dropped here while still borrowed error: aborting due to previous error diff --git a/src/test/ui/span/regions-escape-loop-via-variable.nll.stderr b/src/test/ui/span/regions-escape-loop-via-variable.nll.stderr deleted file mode 100644 index 42df668529749..0000000000000 --- a/src/test/ui/span/regions-escape-loop-via-variable.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0597]: `x` does not live long enough - --> $DIR/regions-escape-loop-via-variable.rs:11:13 - | -LL | let x = 1 + *p; - | -- borrow later used here -LL | p = &x; - | ^^ borrowed value does not live long enough -LL | } - | - `x` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/regions-escape-loop-via-variable.stderr b/src/test/ui/span/regions-escape-loop-via-variable.stderr index e3870db0c668e..42df668529749 100644 --- a/src/test/ui/span/regions-escape-loop-via-variable.stderr +++ b/src/test/ui/span/regions-escape-loop-via-variable.stderr @@ -1,13 +1,12 @@ error[E0597]: `x` does not live long enough - --> $DIR/regions-escape-loop-via-variable.rs:11:14 + --> $DIR/regions-escape-loop-via-variable.rs:11:13 | +LL | let x = 1 + *p; + | -- borrow later used here LL | p = &x; - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough LL | } | - `x` dropped here while still borrowed -LL | //~^^ ERROR `x` does not live long enough -LL | } - | - borrowed value needs to live until here error: aborting due to previous error diff --git a/src/test/ui/span/regions-escape-loop-via-vec.nll.stderr b/src/test/ui/span/regions-escape-loop-via-vec.nll.stderr deleted file mode 100644 index e07fb72778210..0000000000000 --- a/src/test/ui/span/regions-escape-loop-via-vec.nll.stderr +++ /dev/null @@ -1,49 +0,0 @@ -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/regions-escape-loop-via-vec.rs:5:11 - | -LL | let mut _y = vec![&mut x]; - | ------ borrow of `x` occurs here -LL | while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed - | ^ use of borrowed `x` -LL | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed -LL | _y.push(&mut z); - | -- borrow later used here - -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/regions-escape-loop-via-vec.rs:6:21 - | -LL | let mut _y = vec![&mut x]; - | ------ borrow of `x` occurs here -LL | while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed -LL | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed - | ^ use of borrowed `x` -LL | _y.push(&mut z); - | -- borrow later used here - -error[E0597]: `z` does not live long enough - --> $DIR/regions-escape-loop-via-vec.rs:7:17 - | -LL | _y.push(&mut z); - | -- ^^^^^^ borrowed value does not live long enough - | | - | borrow later used here -... -LL | } - | - `z` dropped here while still borrowed - -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/regions-escape-loop-via-vec.rs:9:9 - | -LL | let mut _y = vec![&mut x]; - | ------ borrow of `x` occurs here -... -LL | _y.push(&mut z); - | -- borrow later used here -LL | //~^ ERROR `z` does not live long enough -LL | x += 1; //~ ERROR cannot assign - | ^^^^^^ use of borrowed `x` - -error: aborting due to 4 previous errors - -Some errors occurred: E0503, E0597. -For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/span/regions-escape-loop-via-vec.rs b/src/test/ui/span/regions-escape-loop-via-vec.rs index 52f3dc37c9019..1fceb09696770 100644 --- a/src/test/ui/span/regions-escape-loop-via-vec.rs +++ b/src/test/ui/span/regions-escape-loop-via-vec.rs @@ -6,7 +6,7 @@ fn broken() { let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed _y.push(&mut z); //~^ ERROR `z` does not live long enough - x += 1; //~ ERROR cannot assign + x += 1; //~ ERROR cannot use `x` because it was mutably borrowed } } diff --git a/src/test/ui/span/regions-escape-loop-via-vec.stderr b/src/test/ui/span/regions-escape-loop-via-vec.stderr index 09a7123d8f04e..b47250db723fe 100644 --- a/src/test/ui/span/regions-escape-loop-via-vec.stderr +++ b/src/test/ui/span/regions-escape-loop-via-vec.stderr @@ -1,41 +1,49 @@ -error[E0597]: `z` does not live long enough - --> $DIR/regions-escape-loop-via-vec.rs:7:22 - | -LL | _y.push(&mut z); - | ^ borrowed value does not live long enough -... -LL | } - | - `z` dropped here while still borrowed -LL | } - | - borrowed value needs to live until here - error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/regions-escape-loop-via-vec.rs:5:11 | LL | let mut _y = vec![&mut x]; - | - borrow of `x` occurs here -LL | while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed + | ------ borrow of `x` occurs here +LL | while x < 10 { | ^ use of borrowed `x` +LL | let mut z = x; +LL | _y.push(&mut z); + | -- borrow later used here error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/regions-escape-loop-via-vec.rs:6:13 + --> $DIR/regions-escape-loop-via-vec.rs:6:21 | LL | let mut _y = vec![&mut x]; - | - borrow of `x` occurs here -LL | while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed -LL | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed - | ^^^^^ use of borrowed `x` + | ------ borrow of `x` occurs here +LL | while x < 10 { +LL | let mut z = x; + | ^ use of borrowed `x` +LL | _y.push(&mut z); + | -- borrow later used here -error[E0506]: cannot assign to `x` because it is borrowed +error[E0597]: `z` does not live long enough + --> $DIR/regions-escape-loop-via-vec.rs:7:17 + | +LL | _y.push(&mut z); + | -- ^^^^^^ borrowed value does not live long enough + | | + | borrow later used here +... +LL | } + | - `z` dropped here while still borrowed + +error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/regions-escape-loop-via-vec.rs:9:9 | LL | let mut _y = vec![&mut x]; - | - borrow of `x` occurs here + | ------ borrow of `x` occurs here ... -LL | x += 1; //~ ERROR cannot assign - | ^^^^^^ assignment to borrowed `x` occurs here +LL | _y.push(&mut z); + | -- borrow later used here +LL | +LL | x += 1; + | ^^^^^^ use of borrowed `x` error: aborting due to 4 previous errors -Some errors occurred: E0503, E0506, E0597. +Some errors have detailed explanations: E0503, E0597. For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/span/regions-infer-borrow-scope-within-loop.nll.stderr b/src/test/ui/span/regions-infer-borrow-scope-within-loop.nll.stderr deleted file mode 100644 index fd67c65c4e917..0000000000000 --- a/src/test/ui/span/regions-infer-borrow-scope-within-loop.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0597]: `*x` does not live long enough - --> $DIR/regions-infer-borrow-scope-within-loop.rs:13:20 - | -LL | y = borrow(&*x); - | ^^^ borrowed value does not live long enough -... -LL | } - | - `*x` dropped here while still borrowed -LL | assert!(*y != 0); - | -- borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/regions-infer-borrow-scope-within-loop.stderr b/src/test/ui/span/regions-infer-borrow-scope-within-loop.stderr index 94abbcef035a5..fd67c65c4e917 100644 --- a/src/test/ui/span/regions-infer-borrow-scope-within-loop.stderr +++ b/src/test/ui/span/regions-infer-borrow-scope-within-loop.stderr @@ -1,14 +1,13 @@ error[E0597]: `*x` does not live long enough - --> $DIR/regions-infer-borrow-scope-within-loop.rs:13:21 + --> $DIR/regions-infer-borrow-scope-within-loop.rs:13:20 | LL | y = borrow(&*x); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough ... LL | } | - `*x` dropped here while still borrowed LL | assert!(*y != 0); -LL | } - | - borrowed value needs to live until here + | -- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/span/send-is-not-static-ensures-scoping.nll.stderr b/src/test/ui/span/send-is-not-static-ensures-scoping.nll.stderr deleted file mode 100644 index 65d10c1305b8c..0000000000000 --- a/src/test/ui/span/send-is-not-static-ensures-scoping.nll.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0597]: `x` does not live long enough - --> $DIR/send-is-not-static-ensures-scoping.rs:16:17 - | -LL | let bad = { - | --- borrow later stored here -LL | let x = 1; -LL | let y = &x; - | ^^ borrowed value does not live long enough -... -LL | }; - | - `x` dropped here while still borrowed - -error[E0597]: `y` does not live long enough - --> $DIR/send-is-not-static-ensures-scoping.rs:20:22 - | -LL | let bad = { - | --- borrow later stored here -... -LL | scoped(|| { - | -- value captured here -LL | let _z = y; - | ^ borrowed value does not live long enough -... -LL | }; - | - `y` dropped here while still borrowed - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/send-is-not-static-ensures-scoping.rs b/src/test/ui/span/send-is-not-static-ensures-scoping.rs index ac07420ee362d..2aecc2a7e0d96 100644 --- a/src/test/ui/span/send-is-not-static-ensures-scoping.rs +++ b/src/test/ui/span/send-is-not-static-ensures-scoping.rs @@ -1,5 +1,5 @@ struct Guard<'a> { - f: Box, + f: Box, } fn scoped<'a, F: Fn() + Send + 'a>(f: F) -> Guard<'a> { diff --git a/src/test/ui/span/send-is-not-static-ensures-scoping.stderr b/src/test/ui/span/send-is-not-static-ensures-scoping.stderr index 47026284fb150..65d10c1305b8c 100644 --- a/src/test/ui/span/send-is-not-static-ensures-scoping.stderr +++ b/src/test/ui/span/send-is-not-static-ensures-scoping.stderr @@ -1,28 +1,28 @@ error[E0597]: `x` does not live long enough - --> $DIR/send-is-not-static-ensures-scoping.rs:16:18 + --> $DIR/send-is-not-static-ensures-scoping.rs:16:17 | +LL | let bad = { + | --- borrow later stored here +LL | let x = 1; LL | let y = &x; - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough ... LL | }; | - `x` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here error[E0597]: `y` does not live long enough --> $DIR/send-is-not-static-ensures-scoping.rs:20:22 | +LL | let bad = { + | --- borrow later stored here +... LL | scoped(|| { - | -- capture occurs here + | -- value captured here LL | let _z = y; | ^ borrowed value does not live long enough ... LL | }; - | - borrowed value only lives until here -... -LL | } - | - borrowed value needs to live until here + | - `y` dropped here while still borrowed error: aborting due to 2 previous errors diff --git a/src/test/ui/span/send-is-not-static-std-sync-2.nll.stderr b/src/test/ui/span/send-is-not-static-std-sync-2.nll.stderr deleted file mode 100644 index bcd07e1164777..0000000000000 --- a/src/test/ui/span/send-is-not-static-std-sync-2.nll.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error[E0597]: `x` does not live long enough - --> $DIR/send-is-not-static-std-sync-2.rs:11:20 - | -LL | let lock = { - | ---- borrow later stored here -LL | let x = 1; -LL | Mutex::new(&x) - | ^^ borrowed value does not live long enough -LL | }; - | - `x` dropped here while still borrowed - -error[E0597]: `x` does not live long enough - --> $DIR/send-is-not-static-std-sync-2.rs:21:21 - | -LL | let lock = { - | ---- borrow later stored here -LL | let x = 1; -LL | RwLock::new(&x) - | ^^ borrowed value does not live long enough -LL | }; - | - `x` dropped here while still borrowed - -error[E0597]: `x` does not live long enough - --> $DIR/send-is-not-static-std-sync-2.rs:31:25 - | -LL | let (_tx, rx) = { - | --- borrow later used here -... -LL | let _ = tx.send(&x); - | ^^ borrowed value does not live long enough -LL | (tx, rx) -LL | }; - | - `x` dropped here while still borrowed - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/send-is-not-static-std-sync-2.stderr b/src/test/ui/span/send-is-not-static-std-sync-2.stderr index 4172731745ec3..bcd07e1164777 100644 --- a/src/test/ui/span/send-is-not-static-std-sync-2.stderr +++ b/src/test/ui/span/send-is-not-static-std-sync-2.stderr @@ -1,36 +1,36 @@ error[E0597]: `x` does not live long enough - --> $DIR/send-is-not-static-std-sync-2.rs:11:21 + --> $DIR/send-is-not-static-std-sync-2.rs:11:20 | +LL | let lock = { + | ---- borrow later stored here +LL | let x = 1; LL | Mutex::new(&x) - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough LL | }; | - `x` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here error[E0597]: `x` does not live long enough - --> $DIR/send-is-not-static-std-sync-2.rs:21:22 + --> $DIR/send-is-not-static-std-sync-2.rs:21:21 | +LL | let lock = { + | ---- borrow later stored here +LL | let x = 1; LL | RwLock::new(&x) - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough LL | }; | - `x` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here error[E0597]: `x` does not live long enough - --> $DIR/send-is-not-static-std-sync-2.rs:31:26 + --> $DIR/send-is-not-static-std-sync-2.rs:31:25 | +LL | let (_tx, rx) = { + | --- borrow later used here +... LL | let _ = tx.send(&x); - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough LL | (tx, rx) LL | }; | - `x` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here error: aborting due to 3 previous errors diff --git a/src/test/ui/span/send-is-not-static-std-sync.nll.stderr b/src/test/ui/span/send-is-not-static-std-sync.nll.stderr deleted file mode 100644 index 54960c16405d5..0000000000000 --- a/src/test/ui/span/send-is-not-static-std-sync.nll.stderr +++ /dev/null @@ -1,72 +0,0 @@ -error[E0505]: cannot move out of `y` because it is borrowed - --> $DIR/send-is-not-static-std-sync.rs:13:10 - | -LL | *lock.lock().unwrap() = &*y; - | --- borrow of `*y` occurs here -LL | drop(y); //~ ERROR cannot move out - | ^ move out of `y` occurs here -... -LL | *lock.lock().unwrap() = &z; - | ---- borrow later used here - -error[E0597]: `z` does not live long enough - --> $DIR/send-is-not-static-std-sync.rs:16:33 - | -LL | *lock.lock().unwrap() = &z; - | ^^ borrowed value does not live long enough -LL | } - | - `z` dropped here while still borrowed -LL | //~^^ ERROR `z` does not live long enough -LL | lock.use_ref(); // (Mutex is #[may_dangle] so its dtor does not use `z` => needs explicit use) - | ---- borrow later used here - -error[E0505]: cannot move out of `y` because it is borrowed - --> $DIR/send-is-not-static-std-sync.rs:27:10 - | -LL | *lock.write().unwrap() = &*y; - | --- borrow of `*y` occurs here -LL | drop(y); //~ ERROR cannot move out - | ^ move out of `y` occurs here -... -LL | *lock.write().unwrap() = &z; - | ---- borrow later used here - -error[E0597]: `z` does not live long enough - --> $DIR/send-is-not-static-std-sync.rs:30:34 - | -LL | *lock.write().unwrap() = &z; - | ^^ borrowed value does not live long enough -LL | } - | - `z` dropped here while still borrowed -LL | //~^^ ERROR `z` does not live long enough -LL | lock.use_ref(); // (RwLock is #[may_dangle] so its dtor does not use `z` => needs explicit use) - | ---- borrow later used here - -error[E0505]: cannot move out of `y` because it is borrowed - --> $DIR/send-is-not-static-std-sync.rs:43:10 - | -LL | tx.send(&*y); - | --- borrow of `*y` occurs here -LL | drop(y); //~ ERROR cannot move out - | ^ move out of `y` occurs here -... -LL | tx.send(&z).unwrap(); - | -- borrow later used here - -error[E0597]: `z` does not live long enough - --> $DIR/send-is-not-static-std-sync.rs:46:17 - | -LL | tx.send(&z).unwrap(); - | ^^ borrowed value does not live long enough -LL | } - | - `z` dropped here while still borrowed -... -LL | } - | - borrow might be used here, when `tx` is dropped and runs the `Drop` code for type `std::sync::mpsc::Sender` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to 6 previous errors - -Some errors occurred: E0505, E0597. -For more information about an error, try `rustc --explain E0505`. diff --git a/src/test/ui/span/send-is-not-static-std-sync.stderr b/src/test/ui/span/send-is-not-static-std-sync.stderr index 74c2bad24dea2..d00b157d389ef 100644 --- a/src/test/ui/span/send-is-not-static-std-sync.stderr +++ b/src/test/ui/span/send-is-not-static-std-sync.stderr @@ -1,61 +1,72 @@ +error[E0505]: cannot move out of `y` because it is borrowed + --> $DIR/send-is-not-static-std-sync.rs:13:10 + | +LL | *lock.lock().unwrap() = &*y; + | --- borrow of `*y` occurs here +LL | drop(y); + | ^ move out of `y` occurs here +... +LL | *lock.lock().unwrap() = &z; + | ---- borrow later used here + error[E0597]: `z` does not live long enough - --> $DIR/send-is-not-static-std-sync.rs:16:34 + --> $DIR/send-is-not-static-std-sync.rs:16:33 | LL | *lock.lock().unwrap() = &z; - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough LL | } | - `z` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here +LL | +LL | lock.use_ref(); // (Mutex is #[may_dangle] so its dtor does not use `z` => needs explicit use) + | ---- borrow later used here error[E0505]: cannot move out of `y` because it is borrowed - --> $DIR/send-is-not-static-std-sync.rs:13:10 + --> $DIR/send-is-not-static-std-sync.rs:27:10 | -LL | *lock.lock().unwrap() = &*y; - | -- borrow of `*y` occurs here -LL | drop(y); //~ ERROR cannot move out +LL | *lock.write().unwrap() = &*y; + | --- borrow of `*y` occurs here +LL | drop(y); | ^ move out of `y` occurs here +... +LL | *lock.write().unwrap() = &z; + | ---- borrow later used here error[E0597]: `z` does not live long enough - --> $DIR/send-is-not-static-std-sync.rs:30:35 + --> $DIR/send-is-not-static-std-sync.rs:30:34 | LL | *lock.write().unwrap() = &z; - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough LL | } | - `z` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here +LL | +LL | lock.use_ref(); // (RwLock is #[may_dangle] so its dtor does not use `z` => needs explicit use) + | ---- borrow later used here error[E0505]: cannot move out of `y` because it is borrowed - --> $DIR/send-is-not-static-std-sync.rs:27:10 + --> $DIR/send-is-not-static-std-sync.rs:43:10 | -LL | *lock.write().unwrap() = &*y; - | -- borrow of `*y` occurs here -LL | drop(y); //~ ERROR cannot move out +LL | tx.send(&*y); + | --- borrow of `*y` occurs here +LL | drop(y); | ^ move out of `y` occurs here +... +LL | tx.send(&z).unwrap(); + | -- borrow later used here error[E0597]: `z` does not live long enough - --> $DIR/send-is-not-static-std-sync.rs:46:18 + --> $DIR/send-is-not-static-std-sync.rs:46:17 | LL | tx.send(&z).unwrap(); - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough LL | } | - `z` dropped here while still borrowed ... LL | } - | - borrowed value needs to live until here - -error[E0505]: cannot move out of `y` because it is borrowed - --> $DIR/send-is-not-static-std-sync.rs:43:10 + | - borrow might be used here, when `tx` is dropped and runs the `Drop` code for type `std::sync::mpsc::Sender` | -LL | tx.send(&*y); - | -- borrow of `*y` occurs here -LL | drop(y); //~ ERROR cannot move out - | ^ move out of `y` occurs here + = note: values in a scope are dropped in the opposite order they are defined error: aborting due to 6 previous errors -Some errors occurred: E0505, E0597. +Some errors have detailed explanations: E0505, E0597. For more information about an error, try `rustc --explain E0505`. diff --git a/src/test/ui/span/slice-borrow.nll.stderr b/src/test/ui/span/slice-borrow.nll.stderr deleted file mode 100644 index 84d0c847b7bdc..0000000000000 --- a/src/test/ui/span/slice-borrow.nll.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/slice-borrow.rs:6:28 - | -LL | let x: &[isize] = &vec![1, 2, 3, 4, 5]; - | ^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use -... -LL | } - | - temporary value is freed at the end of this statement -LL | y.use_ref(); - | - borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/span/slice-borrow.rs b/src/test/ui/span/slice-borrow.rs index 23e53039e9453..38cd7acbdfa13 100644 --- a/src/test/ui/span/slice-borrow.rs +++ b/src/test/ui/span/slice-borrow.rs @@ -4,7 +4,7 @@ fn main() { let y; { let x: &[isize] = &vec![1, 2, 3, 4, 5]; - //~^ ERROR borrowed value does not live long enough + //~^ ERROR temporary value dropped while borrowed y = &x[1..]; } y.use_ref(); diff --git a/src/test/ui/span/slice-borrow.stderr b/src/test/ui/span/slice-borrow.stderr index a03cac58e2ea8..84d0c847b7bdc 100644 --- a/src/test/ui/span/slice-borrow.stderr +++ b/src/test/ui/span/slice-borrow.stderr @@ -1,17 +1,17 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/slice-borrow.rs:6:28 | LL | let x: &[isize] = &vec![1, 2, 3, 4, 5]; - | ^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value dropped here while still borrowed + | - temporary value is freed at the end of this statement LL | y.use_ref(); -LL | } - | - temporary value needs to live until here + | - borrow later used here | + = note: consider using a `let` binding to create a longer lived value = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/span/suggestion-non-ascii.rs b/src/test/ui/span/suggestion-non-ascii.rs index 74032cf0266f8..914efd85a0ce7 100644 --- a/src/test/ui/span/suggestion-non-ascii.rs +++ b/src/test/ui/span/suggestion-non-ascii.rs @@ -2,4 +2,3 @@ fn main() { let tup = (1,); println!("☃{}", tup[0]); //~ ERROR cannot index into a value of type } - diff --git a/src/test/ui/span/suggestion-non-ascii.stderr b/src/test/ui/span/suggestion-non-ascii.stderr index 40b11695d7528..b14632d4e1bd1 100644 --- a/src/test/ui/span/suggestion-non-ascii.stderr +++ b/src/test/ui/span/suggestion-non-ascii.stderr @@ -1,7 +1,7 @@ error[E0608]: cannot index into a value of type `({integer},)` --> $DIR/suggestion-non-ascii.rs:3:21 | -LL | println!("☃{}", tup[0]); //~ ERROR cannot index into a value of type +LL | println!("☃{}", tup[0]); | ^^^^^^ help: to access tuple elements, use: `tup.0` error: aborting due to previous error diff --git a/src/test/ui/span/typo-suggestion.stderr b/src/test/ui/span/typo-suggestion.stderr index 7b12c4430ed4a..61d4e06119c4f 100644 --- a/src/test/ui/span/typo-suggestion.stderr +++ b/src/test/ui/span/typo-suggestion.stderr @@ -1,13 +1,13 @@ error[E0425]: cannot find value `bar` in this scope --> $DIR/typo-suggestion.rs:5:26 | -LL | println!("Hello {}", bar); //~ ERROR cannot find value +LL | println!("Hello {}", bar); | ^^^ not found in this scope error[E0425]: cannot find value `fob` in this scope --> $DIR/typo-suggestion.rs:8:26 | -LL | println!("Hello {}", fob); //~ ERROR cannot find value +LL | println!("Hello {}", fob); | ^^^ help: a local variable with a similar name exists: `foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/span/unused-warning-point-at-signature.stderr b/src/test/ui/span/unused-warning-point-at-signature.stderr index e07548121b52b..3007d90c99006 100644 --- a/src/test/ui/span/unused-warning-point-at-signature.stderr +++ b/src/test/ui/span/unused-warning-point-at-signature.stderr @@ -1,7 +1,7 @@ warning: enum is never used: `Enum` --> $DIR/unused-warning-point-at-signature.rs:5:1 | -LL | enum Enum { //~ WARN enum is never used +LL | enum Enum { | ^^^^^^^^^ | note: lint level defined here @@ -14,19 +14,19 @@ LL | #![warn(unused)] warning: struct is never constructed: `Struct` --> $DIR/unused-warning-point-at-signature.rs:12:1 | -LL | struct Struct { //~ WARN struct is never constructed +LL | struct Struct { | ^^^^^^^^^^^^^ warning: function is never used: `func` --> $DIR/unused-warning-point-at-signature.rs:19:1 | -LL | fn func() -> usize { //~ WARN function is never used +LL | fn func() -> usize { | ^^^^^^^^^^^^^^^^^^ warning: function is never used: `func_complete_span` --> $DIR/unused-warning-point-at-signature.rs:23:1 | -LL | / fn //~ WARN function is never used +LL | / fn LL | | func_complete_span() LL | | -> usize LL | | { diff --git a/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr b/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr deleted file mode 100644 index c5e2ca2e28f39..0000000000000 --- a/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0597]: `c2` does not live long enough - --> $DIR/vec-must-not-hide-type-from-dropck.rs:117:24 - | -LL | c1.v[0].v.set(Some(&c2)); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `c2` dropped here while still borrowed - | borrow might be used here, when `c1` is dropped and runs the destructor for type `C<'_>` - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `c1` does not live long enough - --> $DIR/vec-must-not-hide-type-from-dropck.rs:119:24 - | -LL | c2.v[0].v.set(Some(&c1)); - | ^^^ borrowed value does not live long enough -LL | //~^ ERROR `c1` does not live long enough -LL | } - | - - | | - | `c1` dropped here while still borrowed - | borrow might be used here, when `c1` is dropped and runs the destructor for type `C<'_>` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/vec-must-not-hide-type-from-dropck.stderr b/src/test/ui/span/vec-must-not-hide-type-from-dropck.stderr index 1eee88ad21af5..f87c32d1ad0c6 100644 --- a/src/test/ui/span/vec-must-not-hide-type-from-dropck.stderr +++ b/src/test/ui/span/vec-must-not-hide-type-from-dropck.stderr @@ -1,24 +1,28 @@ error[E0597]: `c2` does not live long enough - --> $DIR/vec-must-not-hide-type-from-dropck.rs:117:25 + --> $DIR/vec-must-not-hide-type-from-dropck.rs:117:24 | LL | c1.v[0].v.set(Some(&c2)); - | ^^ borrowed value does not live long enough + | ^^^ borrowed value does not live long enough ... LL | } - | - `c2` dropped here while still borrowed + | - + | | + | `c2` dropped here while still borrowed + | borrow might be used here, when `c1` is dropped and runs the destructor for type `C<'_>` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `c1` does not live long enough - --> $DIR/vec-must-not-hide-type-from-dropck.rs:119:25 + --> $DIR/vec-must-not-hide-type-from-dropck.rs:119:24 | LL | c2.v[0].v.set(Some(&c1)); - | ^^ borrowed value does not live long enough -LL | //~^ ERROR `c1` does not live long enough + | ^^^ borrowed value does not live long enough +LL | LL | } - | - `c1` dropped here while still borrowed - | - = note: values in a scope are dropped in the opposite order they are created + | - + | | + | `c1` dropped here while still borrowed + | borrow might be used here, when `c1` is dropped and runs the destructor for type `C<'_>` error: aborting due to 2 previous errors diff --git a/src/test/ui/span/vec_refs_data_with_early_death.nll.stderr b/src/test/ui/span/vec_refs_data_with_early_death.nll.stderr deleted file mode 100644 index 684e784531325..0000000000000 --- a/src/test/ui/span/vec_refs_data_with_early_death.nll.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0597]: `x` does not live long enough - --> $DIR/vec_refs_data_with_early_death.rs:17:12 - | -LL | v.push(&x); - | ^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `x` dropped here while still borrowed - | borrow might be used here, when `v` is dropped and runs the `Drop` code for type `Bag` - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `y` does not live long enough - --> $DIR/vec_refs_data_with_early_death.rs:19:12 - | -LL | v.push(&y); - | ^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `y` dropped here while still borrowed - | borrow might be used here, when `v` is dropped and runs the `Drop` code for type `Bag` - | - = note: values in a scope are dropped in the opposite order they are defined - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/vec_refs_data_with_early_death.stderr b/src/test/ui/span/vec_refs_data_with_early_death.stderr index 65fd6b50643ad..684e784531325 100644 --- a/src/test/ui/span/vec_refs_data_with_early_death.stderr +++ b/src/test/ui/span/vec_refs_data_with_early_death.stderr @@ -1,24 +1,30 @@ error[E0597]: `x` does not live long enough - --> $DIR/vec_refs_data_with_early_death.rs:17:13 + --> $DIR/vec_refs_data_with_early_death.rs:17:12 | LL | v.push(&x); - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough ... LL | } - | - `x` dropped here while still borrowed + | - + | | + | `x` dropped here while still borrowed + | borrow might be used here, when `v` is dropped and runs the `Drop` code for type `Bag` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `y` does not live long enough - --> $DIR/vec_refs_data_with_early_death.rs:19:13 + --> $DIR/vec_refs_data_with_early_death.rs:19:12 | LL | v.push(&y); - | ^ borrowed value does not live long enough + | ^^ borrowed value does not live long enough ... LL | } - | - `y` dropped here while still borrowed + | - + | | + | `y` dropped here while still borrowed + | borrow might be used here, when `v` is dropped and runs the `Drop` code for type `Bag` | - = note: values in a scope are dropped in the opposite order they are created + = note: values in a scope are dropped in the opposite order they are defined error: aborting due to 2 previous errors diff --git a/src/test/ui/span/visibility-ty-params.stderr b/src/test/ui/span/visibility-ty-params.stderr index d7914528f4686..cdbede3c197e3 100644 --- a/src/test/ui/span/visibility-ty-params.stderr +++ b/src/test/ui/span/visibility-ty-params.stderr @@ -1,23 +1,22 @@ error: unexpected generic arguments in path --> $DIR/visibility-ty-params.rs:6:5 | -LL | m!{ S } //~ ERROR unexpected generic arguments in path +LL | m!{ S } | ^^^^^ error: unexpected generic arguments in path --> $DIR/visibility-ty-params.rs:10:9 | -LL | m!{ m<> } //~ ERROR unexpected generic arguments in path +LL | m!{ m<> } | ^^^ error[E0577]: expected module, found struct `S` --> $DIR/visibility-ty-params.rs:6:5 | -LL | m!{ S } //~ ERROR unexpected generic arguments in path +LL | m!{ S } | -^^^^ | | | help: a module with a similar name exists: `m` error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0577`. diff --git a/src/test/ui/span/wf-method-late-bound-regions.nll.stderr b/src/test/ui/span/wf-method-late-bound-regions.nll.stderr deleted file mode 100644 index 6b0b008208f17..0000000000000 --- a/src/test/ui/span/wf-method-late-bound-regions.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0597]: `pointer` does not live long enough - --> $DIR/wf-method-late-bound-regions.rs:20:18 - | -LL | let dangling = { - | -------- borrow later stored here -LL | let pointer = Box::new(42); -LL | f2.xmute(&pointer) - | ^^^^^^^^ borrowed value does not live long enough -LL | }; - | - `pointer` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/wf-method-late-bound-regions.stderr b/src/test/ui/span/wf-method-late-bound-regions.stderr index a30e0f4d7e0ed..6b0b008208f17 100644 --- a/src/test/ui/span/wf-method-late-bound-regions.stderr +++ b/src/test/ui/span/wf-method-late-bound-regions.stderr @@ -1,13 +1,13 @@ error[E0597]: `pointer` does not live long enough - --> $DIR/wf-method-late-bound-regions.rs:20:19 + --> $DIR/wf-method-late-bound-regions.rs:20:18 | +LL | let dangling = { + | -------- borrow later stored here +LL | let pointer = Box::new(42); LL | f2.xmute(&pointer) - | ^^^^^^^ borrowed value does not live long enough + | ^^^^^^^^ borrowed value does not live long enough LL | }; | - `pointer` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here error: aborting due to previous error diff --git a/src/test/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr b/src/test/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr index 3b3076cc67230..b95e62edaaa76 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr @@ -1,11 +1,12 @@ -error[E0658]: specialization is unstable (see issue #31844) +error[E0658]: specialization is unstable --> $DIR/specialization-feature-gate-default.rs:7:1 | -LL | / default impl Foo for T { //~ ERROR specialization is unstable +LL | / default impl Foo for T { LL | | fn foo(&self) {} LL | | } | |_^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/31844 = help: add #![feature(specialization)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr b/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr index 7ca9df9f5d93f..91690f64d948c 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr @@ -7,7 +7,7 @@ LL | | fn bar(&self) {} LL | | } | |_- parent `impl` is here ... -LL | fn foo(&self) {} //~ ERROR E0520 +LL | fn foo(&self) {} | ^^^^^^^^^^^^^^^^ cannot specialize default item `foo` | = note: to specialize, `foo` in the parent `impl` must be marked `default` @@ -21,7 +21,7 @@ LL | | fn bar(&self) {} LL | | } | |_- parent `impl` is here ... -LL | fn bar(&self) {} //~ ERROR E0520 +LL | fn bar(&self) {} | ^^^^^^^^^^^^^^^^ cannot specialize default item `bar` | = note: to specialize, `bar` in the parent `impl` must be marked `default` @@ -34,7 +34,7 @@ LL | | type T = u8; LL | | } | |_- parent `impl` is here ... -LL | type T = (); //~ ERROR E0520 +LL | type T = (); | ^^^^^^^^^^^^ cannot specialize default item `T` | = note: to specialize, `T` in the parent `impl` must be marked `default` @@ -47,7 +47,7 @@ LL | | fn baz(&self) {} LL | | } | |_- parent `impl` is here ... -LL | fn baz(&self) {} //~ ERROR E0520 +LL | fn baz(&self) {} | ^^^^^^^^^^^^^^^^ cannot specialize default item `baz` | = note: to specialize, `baz` in the parent `impl` must be marked `default` @@ -60,7 +60,7 @@ LL | | fn redundant(&self) {} LL | | } | |_- parent `impl` is here ... -LL | fn redundant(&self) {} //~ ERROR E0520 +LL | fn redundant(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `redundant` | = note: to specialize, `redundant` in the parent `impl` must be marked `default` diff --git a/src/test/ui/specialization/defaultimpl/validation.stderr b/src/test/ui/specialization/defaultimpl/validation.stderr index 2778cac7ae571..14a06c39088d4 100644 --- a/src/test/ui/specialization/defaultimpl/validation.stderr +++ b/src/test/ui/specialization/defaultimpl/validation.stderr @@ -1,7 +1,7 @@ error: inherent impls cannot be default --> $DIR/validation.rs:7:1 | -LL | default impl S {} //~ ERROR inherent impls cannot be default +LL | default impl S {} | ^^^^^^^^^^^^^^^^^ | = note: only trait implementations may be annotated with default @@ -9,19 +9,19 @@ LL | default impl S {} //~ ERROR inherent impls cannot be default error: impls of auto traits cannot be default --> $DIR/validation.rs:9:1 | -LL | default unsafe impl Send for S {} //~ ERROR impls of auto traits cannot be default +LL | default unsafe impl Send for S {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impls of auto traits cannot be default --> $DIR/validation.rs:10:1 | -LL | default impl !Send for Z {} //~ ERROR impls of auto traits cannot be default +LL | default impl !Send for Z {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0192]: negative impls are only allowed for auto traits (e.g., `Send` and `Sync`) --> $DIR/validation.rs:13:1 | -LL | default impl !Tr for S {} //~ ERROR negative impls are only allowed for auto traits +LL | default impl !Tr for S {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/specialization/issue-39448.stderr b/src/test/ui/specialization/issue-39448.stderr index 0b0fd2c4af591..861a1d9e8fc66 100644 --- a/src/test/ui/specialization/issue-39448.stderr +++ b/src/test/ui/specialization/issue-39448.stderr @@ -1,7 +1,7 @@ error[E0275]: overflow evaluating the requirement `T: FromA` --> $DIR/issue-39448.rs:45:13 | -LL | x.foo(y.to()).to() //~ ERROR overflow evaluating the requirement +LL | x.foo(y.to()).to() | ^^ | = note: required because of the requirements on the impl of `FromA` for `T` diff --git a/src/test/ui/specialization/issue-52050.stderr b/src/test/ui/specialization/issue-52050.stderr index 9187d04cfce6a..dcb34f3ad4836 100644 --- a/src/test/ui/specialization/issue-52050.stderr +++ b/src/test/ui/specialization/issue-52050.stderr @@ -8,7 +8,7 @@ LL | | { LL | | } | |_- first implementation here LL | -LL | impl IntoPyDictPointer for () //~ ERROR conflicting implementations +LL | impl IntoPyDictPointer for () | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` | = note: upstream crates may add new impl of trait `std::iter::Iterator` for type `()` in future versions diff --git a/src/test/ui/specialization/specialization-default-projection.stderr b/src/test/ui/specialization/specialization-default-projection.stderr index b781c35ea391a..ab0bdc44cff1a 100644 --- a/src/test/ui/specialization/specialization-default-projection.stderr +++ b/src/test/ui/specialization/specialization-default-projection.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn generic() -> ::Assoc { | ----------------- expected `::Assoc` because of return type ... -LL | () //~ ERROR mismatched types +LL | () | ^^ expected associated type, found () | = note: expected type `::Assoc` @@ -16,7 +16,7 @@ error[E0308]: mismatched types LL | fn monomorphic() -> () { | -- expected `()` because of return type ... -LL | generic::<()>() //~ ERROR mismatched types +LL | generic::<()>() | ^^^^^^^^^^^^^^^- help: try adding a semicolon: `;` | | | expected (), found associated type diff --git a/src/test/ui/specialization/specialization-default-types.stderr b/src/test/ui/specialization/specialization-default-types.stderr index 3b4ae2d821775..1192b0e5cfa53 100644 --- a/src/test/ui/specialization/specialization-default-types.stderr +++ b/src/test/ui/specialization/specialization-default-types.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | default fn generate(self) -> Self::Output { | ------------ expected `::Output` because of return type -LL | Box::new(self) //~ ERROR mismatched types +LL | Box::new(self) | ^^^^^^^^^^^^^^ expected associated type, found struct `std::boxed::Box` | = note: expected type `::Output` @@ -14,7 +14,7 @@ error[E0308]: mismatched types | LL | fn trouble(t: T) -> Box { | ------ expected `std::boxed::Box` because of return type -LL | Example::generate(t) //~ ERROR mismatched types +LL | Example::generate(t) | ^^^^^^^^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found associated type | = note: expected type `std::boxed::Box` diff --git a/src/test/ui/specialization/specialization-feature-gate-default.stderr b/src/test/ui/specialization/specialization-feature-gate-default.stderr index 13d656bd060e5..e649f2aa47a6c 100644 --- a/src/test/ui/specialization/specialization-feature-gate-default.stderr +++ b/src/test/ui/specialization/specialization-feature-gate-default.stderr @@ -1,9 +1,10 @@ -error[E0658]: specialization is unstable (see issue #31844) +error[E0658]: specialization is unstable --> $DIR/specialization-feature-gate-default.rs:10:5 | -LL | default fn foo(&self) {} //~ ERROR specialization is unstable +LL | default fn foo(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/31844 = help: add #![feature(specialization)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/specialization/specialization-feature-gate-overlap.stderr b/src/test/ui/specialization/specialization-feature-gate-overlap.stderr index d6714375d16e6..baaf7aa43321a 100644 --- a/src/test/ui/specialization/specialization-feature-gate-overlap.stderr +++ b/src/test/ui/specialization/specialization-feature-gate-overlap.stderr @@ -4,7 +4,7 @@ error[E0119]: conflicting implementations of trait `Foo` for type `u8`: LL | impl Foo for T { | ----------------- first implementation here ... -LL | impl Foo for u8 { //~ ERROR E0119 +LL | impl Foo for u8 { | ^^^^^^^^^^^^^^^ conflicting implementation for `u8` error: aborting due to previous error diff --git a/src/test/ui/specialization/specialization-no-default.stderr b/src/test/ui/specialization/specialization-no-default.stderr index c57f98ac74de2..c39986de38dc2 100644 --- a/src/test/ui/specialization/specialization-no-default.stderr +++ b/src/test/ui/specialization/specialization-no-default.stderr @@ -7,7 +7,7 @@ LL | | fn bar(&self) {} LL | | } | |_- parent `impl` is here ... -LL | fn foo(&self) {} //~ ERROR E0520 +LL | fn foo(&self) {} | ^^^^^^^^^^^^^^^^ cannot specialize default item `foo` | = note: to specialize, `foo` in the parent `impl` must be marked `default` @@ -21,7 +21,7 @@ LL | | fn bar(&self) {} LL | | } | |_- parent `impl` is here ... -LL | fn bar(&self) {} //~ ERROR E0520 +LL | fn bar(&self) {} | ^^^^^^^^^^^^^^^^ cannot specialize default item `bar` | = note: to specialize, `bar` in the parent `impl` must be marked `default` @@ -34,7 +34,7 @@ LL | | type T = u8; LL | | } | |_- parent `impl` is here ... -LL | type T = (); //~ ERROR E0520 +LL | type T = (); | ^^^^^^^^^^^^ cannot specialize default item `T` | = note: to specialize, `T` in the parent `impl` must be marked `default` @@ -47,7 +47,7 @@ LL | | fn baz(&self) {} LL | | } | |_- parent `impl` is here ... -LL | fn baz(&self) {} //~ ERROR E0520 +LL | fn baz(&self) {} | ^^^^^^^^^^^^^^^^ cannot specialize default item `baz` | = note: to specialize, `baz` in the parent `impl` must be marked `default` @@ -60,7 +60,7 @@ LL | | fn redundant(&self) {} LL | | } | |_- parent `impl` is here ... -LL | default fn redundant(&self) {} //~ ERROR E0520 +LL | default fn redundant(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `redundant` | = note: to specialize, `redundant` in the parent `impl` must be marked `default` diff --git a/src/test/ui/specialization/specialization-overlap-hygiene.rs b/src/test/ui/specialization/specialization-overlap-hygiene.rs new file mode 100644 index 0000000000000..93e7c83253e40 --- /dev/null +++ b/src/test/ui/specialization/specialization-overlap-hygiene.rs @@ -0,0 +1,23 @@ +#![feature(decl_macro)] + +struct X; + +macro_rules! define_f_legacy { () => { + fn f() {} +}} +macro define_g_modern() { + fn g() {} +} + +impl X { + fn f() {} //~ ERROR duplicate definitions with name `f` + fn g() {} // OK +} +impl X { + define_f_legacy!(); +} +impl X { + define_g_modern!(); +} + +fn main() {} diff --git a/src/test/ui/specialization/specialization-overlap-hygiene.stderr b/src/test/ui/specialization/specialization-overlap-hygiene.stderr new file mode 100644 index 0000000000000..6adf16de4621a --- /dev/null +++ b/src/test/ui/specialization/specialization-overlap-hygiene.stderr @@ -0,0 +1,12 @@ +error[E0592]: duplicate definitions with name `f` + --> $DIR/specialization-overlap-hygiene.rs:13:4 + | +LL | fn f() {} + | --------- other definition for `f` +... +LL | fn f() {} + | ^^^^^^^^^ duplicate definitions for `f` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0592`. diff --git a/src/test/ui/specialization/specialization-overlap-negative.stderr b/src/test/ui/specialization/specialization-overlap-negative.stderr index b9ab1bd637cc5..947aad824ea88 100644 --- a/src/test/ui/specialization/specialization-overlap-negative.stderr +++ b/src/test/ui/specialization/specialization-overlap-negative.stderr @@ -3,7 +3,7 @@ error[E0119]: conflicting implementations of trait `std::marker::Send` for type | LL | unsafe impl Send for TestType {} | ------------------------------------------ first implementation here -LL | impl !Send for TestType {} //~ ERROR E0119 +LL | impl !Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>` error: aborting due to previous error diff --git a/src/test/ui/specialization/specialization-overlap.stderr b/src/test/ui/specialization/specialization-overlap.stderr index eef8cb44b8882..4275e7bdd85e2 100644 --- a/src/test/ui/specialization/specialization-overlap.stderr +++ b/src/test/ui/specialization/specialization-overlap.stderr @@ -3,7 +3,7 @@ error[E0119]: conflicting implementations of trait `Foo` for type `std::vec::Vec | LL | impl Foo for T {} | ------------------------ first implementation here -LL | impl Foo for Vec {} //~ ERROR E0119 +LL | impl Foo for Vec {} | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `std::vec::Vec<_>` error[E0119]: conflicting implementations of trait `Bar` for type `(u8, u8)`: @@ -11,7 +11,7 @@ error[E0119]: conflicting implementations of trait `Bar` for type `(u8, u8)`: | LL | impl Bar for (T, u8) {} | ----------------------- first implementation here -LL | impl Bar for (u8, T) {} //~ ERROR E0119 +LL | impl Bar for (u8, T) {} | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(u8, u8)` error[E0119]: conflicting implementations of trait `Baz` for type `u8`: @@ -19,7 +19,7 @@ error[E0119]: conflicting implementations of trait `Baz` for type `u8`: | LL | impl Baz for u8 {} | --------------------- first implementation here -LL | impl Baz for T {} //~ ERROR E0119 +LL | impl Baz for T {} | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u8` error[E0119]: conflicting implementations of trait `Qux`: @@ -27,7 +27,7 @@ error[E0119]: conflicting implementations of trait `Qux`: | LL | impl Qux for T {} | ------------------------ first implementation here -LL | impl Qux for T {} //~ ERROR E0119 +LL | impl Qux for T {} | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation error: aborting due to 4 previous errors diff --git a/src/test/ui/specialization/specialization-polarity.stderr b/src/test/ui/specialization/specialization-polarity.stderr index d1f48b78864cb..bc1b2aeb70fc7 100644 --- a/src/test/ui/specialization/specialization-polarity.stderr +++ b/src/test/ui/specialization/specialization-polarity.stderr @@ -3,7 +3,7 @@ error[E0119]: conflicting implementations of trait `Foo` for type `u8`: | LL | impl Foo for T {} | ----------------- first implementation here -LL | impl !Foo for u8 {} //~ ERROR E0119 +LL | impl !Foo for u8 {} | ^^^^^^^^^^^^^^^^ conflicting implementation for `u8` error[E0119]: conflicting implementations of trait `Bar` for type `u8`: @@ -11,7 +11,7 @@ error[E0119]: conflicting implementations of trait `Bar` for type `u8`: | LL | impl !Bar for T {} | ------------------ first implementation here -LL | impl Bar for u8 {} //~ ERROR E0119 +LL | impl Bar for u8 {} | ^^^^^^^^^^^^^^^ conflicting implementation for `u8` error: aborting due to 2 previous errors diff --git a/src/test/ui/stability-attribute/missing-stability-attr-at-top-level.stderr b/src/test/ui/stability-attribute/missing-stability-attr-at-top-level.stderr index f674797694557..b6c9564e904c4 100644 --- a/src/test/ui/stability-attribute/missing-stability-attr-at-top-level.stderr +++ b/src/test/ui/stability-attribute/missing-stability-attr-at-top-level.stderr @@ -2,7 +2,7 @@ error: crate has missing stability attribute --> $DIR/missing-stability-attr-at-top-level.rs:1:1 | LL | / #![feature(staged_api)] -LL | | //~^ ERROR crate has missing stability attribute +LL | | LL | | LL | | fn main() {} | |____________^ diff --git a/src/test/ui/stability-attribute/stability-attribute-issue-43027.stderr b/src/test/ui/stability-attribute/stability-attribute-issue-43027.stderr index 7ffb4bb487a7b..280c72acccb18 100644 --- a/src/test/ui/stability-attribute/stability-attribute-issue-43027.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-issue-43027.stderr @@ -1,7 +1,7 @@ error: field has missing stability attribute --> $DIR/stability-attribute-issue-43027.rs:5:23 | -LL | pub struct Reverse(pub T); //~ ERROR field has missing stability attribute +LL | pub struct Reverse(pub T); | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/stability-attribute/stability-attribute-issue.rs b/src/test/ui/stability-attribute/stability-attribute-issue.rs index fc4a7dab1af0a..cda1aff133f94 100644 --- a/src/test/ui/stability-attribute/stability-attribute-issue.rs +++ b/src/test/ui/stability-attribute/stability-attribute-issue.rs @@ -1,6 +1,4 @@ // aux-build:stability_attribute_issue.rs -// ignore-tidy-linelength - #![deny(deprecated)] extern crate stability_attribute_issue; @@ -8,7 +6,7 @@ use stability_attribute_issue::*; fn main() { unstable(); - //~^ ERROR use of unstable library feature 'unstable_test_feature' (see issue #1) + //~^ ERROR use of unstable library feature 'unstable_test_feature' unstable_msg(); - //~^ ERROR use of unstable library feature 'unstable_test_feature': message (see issue #2) + //~^ ERROR use of unstable library feature 'unstable_test_feature': message } diff --git a/src/test/ui/stability-attribute/stability-attribute-issue.stderr b/src/test/ui/stability-attribute/stability-attribute-issue.stderr index 94fdc0db3d9b6..7e6fbe1600d1e 100644 --- a/src/test/ui/stability-attribute/stability-attribute-issue.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-issue.stderr @@ -1,17 +1,19 @@ -error[E0658]: use of unstable library feature 'unstable_test_feature' (see issue #1) - --> $DIR/stability-attribute-issue.rs:10:5 +error[E0658]: use of unstable library feature 'unstable_test_feature' + --> $DIR/stability-attribute-issue.rs:8:5 | LL | unstable(); | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/1 = help: add #![feature(unstable_test_feature)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'unstable_test_feature': message (see issue #2) - --> $DIR/stability-attribute-issue.rs:12:5 +error[E0658]: use of unstable library feature 'unstable_test_feature': message + --> $DIR/stability-attribute-issue.rs:10:5 | LL | unstable_msg(); | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/2 = help: add #![feature(unstable_test_feature)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.stderr b/src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.stderr index cd8ea921d3036..77f896a86d58a 100644 --- a/src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.stderr @@ -1,19 +1,19 @@ error: stability attributes may not be used outside of the standard library --> $DIR/stability-attribute-non-staged-force-unstable.rs:3:1 | -LL | #[unstable()] //~ ERROR: stability attributes may not be used +LL | #[unstable()] | ^^^^^^^^^^^^^ error: stability attributes may not be used outside of the standard library --> $DIR/stability-attribute-non-staged-force-unstable.rs:4:1 | -LL | #[stable()] //~ ERROR: stability attributes may not be used +LL | #[stable()] | ^^^^^^^^^^^ error: stability attributes may not be used outside of the standard library --> $DIR/stability-attribute-non-staged-force-unstable.rs:5:1 | -LL | #[rustc_deprecated()] //~ ERROR: stability attributes may not be used +LL | #[rustc_deprecated()] | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/stability-attribute/stability-attribute-non-staged.stderr b/src/test/ui/stability-attribute/stability-attribute-non-staged.stderr index 67f6ef857f179..e98f789f54c7d 100644 --- a/src/test/ui/stability-attribute/stability-attribute-non-staged.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-non-staged.stderr @@ -1,19 +1,19 @@ error: stability attributes may not be used outside of the standard library --> $DIR/stability-attribute-non-staged.rs:1:1 | -LL | #[unstable()] //~ ERROR: stability attributes may not be used +LL | #[unstable()] | ^^^^^^^^^^^^^ error: stability attributes may not be used outside of the standard library --> $DIR/stability-attribute-non-staged.rs:2:1 | -LL | #[stable()] //~ ERROR: stability attributes may not be used +LL | #[stable()] | ^^^^^^^^^^^ error: stability attributes may not be used outside of the standard library --> $DIR/stability-attribute-non-staged.rs:3:1 | -LL | #[rustc_deprecated()] //~ ERROR: stability attributes may not be used +LL | #[rustc_deprecated()] | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr index 6f5c844a65713..d683d0895301f 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr @@ -1,22 +1,22 @@ error[E0538]: multiple 'feature' items --> $DIR/stability-attribute-sanity-2.rs:7:25 | -LL | #[stable(feature = "a", feature = "b", since = "1.0.0")] //~ ERROR multiple 'feature' items +LL | #[stable(feature = "a", feature = "b", since = "1.0.0")] | ^^^^^^^^^^^^^ error[E0541]: unknown meta item 'sinse' --> $DIR/stability-attribute-sanity-2.rs:10:25 | -LL | #[stable(feature = "a", sinse = "1.0.0")] //~ ERROR unknown meta item 'sinse' +LL | #[stable(feature = "a", sinse = "1.0.0")] | ^^^^^^^^^^^^^^^ expected one of `since`, `note` error[E0545]: incorrect 'issue' --> $DIR/stability-attribute-sanity-2.rs:13:1 | -LL | #[unstable(feature = "a", issue = "no")] //~ ERROR incorrect 'issue' +LL | #[unstable(feature = "a", issue = "no")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors -Some errors occurred: E0538, E0541, E0545. +Some errors have detailed explanations: E0538, E0541. For more information about an error, try `rustc --explain E0538`. diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-3.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity-3.stderr index 1c759d49b9947..b1c56ef224ae7 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity-3.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity-3.stderr @@ -1,7 +1,7 @@ error: macro has missing stability attribute --> $DIR/stability-attribute-sanity-3.rs:8:1 | -LL | / macro_rules! mac { //~ ERROR macro has missing stability attribute +LL | / macro_rules! mac { LL | | () => () LL | | } | |_^ diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-4.rs b/src/test/ui/stability-attribute/stability-attribute-sanity-4.rs index 3fd54bc02e417..c64899c1e9240 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity-4.rs +++ b/src/test/ui/stability-attribute/stability-attribute-sanity-4.rs @@ -5,24 +5,24 @@ #![stable(feature = "rust1", since = "1.0.0")] mod bogus_attribute_types_2 { - #[unstable] //~ ERROR attribute must be of the form + #[unstable] //~ ERROR malformed `unstable` attribute fn f1() { } - #[unstable = "b"] //~ ERROR attribute must be of the form + #[unstable = "b"] //~ ERROR malformed `unstable` attribute fn f2() { } - #[stable] //~ ERROR attribute must be of the form + #[stable] //~ ERROR malformed `stable` attribute fn f3() { } - #[stable = "a"] //~ ERROR attribute must be of the form + #[stable = "a"] //~ ERROR malformed `stable` attribute fn f4() { } #[stable(feature = "a", since = "b")] - #[rustc_deprecated] //~ ERROR attribute must be of the form + #[rustc_deprecated] //~ ERROR malformed `rustc_deprecated` attribute fn f5() { } #[stable(feature = "a", since = "b")] - #[rustc_deprecated = "a"] //~ ERROR attribute must be of the form + #[rustc_deprecated = "a"] //~ ERROR malformed `rustc_deprecated` attribute fn f6() { } } diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-4.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity-4.stderr index 4b4efe9d8cadd..9d23b344ed15e 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity-4.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity-4.stderr @@ -1,38 +1,38 @@ -error: attribute must be of the form `#[unstable(feature = "name", reason = "...", issue = "N")]` +error: malformed `unstable` attribute input --> $DIR/stability-attribute-sanity-4.rs:8:5 | -LL | #[unstable] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^ +LL | #[unstable] + | ^^^^^^^^^^^ help: must be of the form: `#[unstable(feature = "name", reason = "...", issue = "N")]` -error: attribute must be of the form `#[unstable(feature = "name", reason = "...", issue = "N")]` +error: malformed `unstable` attribute input --> $DIR/stability-attribute-sanity-4.rs:11:5 | -LL | #[unstable = "b"] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^^^^ +LL | #[unstable = "b"] + | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[unstable(feature = "name", reason = "...", issue = "N")]` -error: attribute must be of the form `#[stable(feature = "name", since = "version")]` +error: malformed `stable` attribute input --> $DIR/stability-attribute-sanity-4.rs:14:5 | -LL | #[stable] //~ ERROR attribute must be of the form - | ^^^^^^^^^ +LL | #[stable] + | ^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` -error: attribute must be of the form `#[stable(feature = "name", since = "version")]` +error: malformed `stable` attribute input --> $DIR/stability-attribute-sanity-4.rs:17:5 | -LL | #[stable = "a"] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^^ +LL | #[stable = "a"] + | ^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` -error: attribute must be of the form `#[rustc_deprecated(since = "version", reason = "...")]` +error: malformed `rustc_deprecated` attribute input --> $DIR/stability-attribute-sanity-4.rs:21:5 | -LL | #[rustc_deprecated] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_deprecated] + | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_deprecated(since = "version", reason = "...")]` -error: attribute must be of the form `#[rustc_deprecated(since = "version", reason = "...")]` +error: malformed `rustc_deprecated` attribute input --> $DIR/stability-attribute-sanity-4.rs:25:5 | -LL | #[rustc_deprecated = "a"] //~ ERROR attribute must be of the form - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_deprecated = "a"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_deprecated(since = "version", reason = "...")]` error: aborting due to 6 previous errors diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr index 74c1bbfed6f70..d9a5448bdd8af 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr @@ -1,97 +1,97 @@ error[E0541]: unknown meta item 'reason' --> $DIR/stability-attribute-sanity.rs:8:42 | -LL | #[stable(feature = "a", since = "b", reason)] //~ ERROR unknown meta item 'reason' [E0541] +LL | #[stable(feature = "a", since = "b", reason)] | ^^^^^^ expected one of `since`, `note` error[E0539]: incorrect meta item --> $DIR/stability-attribute-sanity.rs:11:29 | -LL | #[stable(feature = "a", since)] //~ ERROR incorrect meta item [E0539] +LL | #[stable(feature = "a", since)] | ^^^^^ error[E0539]: incorrect meta item --> $DIR/stability-attribute-sanity.rs:14:14 | -LL | #[stable(feature, since = "a")] //~ ERROR incorrect meta item [E0539] +LL | #[stable(feature, since = "a")] | ^^^^^^^ error[E0539]: incorrect meta item --> $DIR/stability-attribute-sanity.rs:17:29 | -LL | #[stable(feature = "a", since(b))] //~ ERROR incorrect meta item [E0539] +LL | #[stable(feature = "a", since(b))] | ^^^^^^^^ error[E0539]: incorrect meta item --> $DIR/stability-attribute-sanity.rs:20:14 | -LL | #[stable(feature(b), since = "a")] //~ ERROR incorrect meta item [E0539] +LL | #[stable(feature(b), since = "a")] | ^^^^^^^^^^ error[E0546]: missing 'feature' --> $DIR/stability-attribute-sanity.rs:25:5 | -LL | #[unstable(issue = "0")] //~ ERROR missing 'feature' [E0546] +LL | #[unstable(issue = "0")] | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0547]: missing 'issue' --> $DIR/stability-attribute-sanity.rs:28:5 | -LL | #[unstable(feature = "b")] //~ ERROR missing 'issue' [E0547] +LL | #[unstable(feature = "b")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0546]: missing 'feature' --> $DIR/stability-attribute-sanity.rs:31:5 | -LL | #[stable(since = "a")] //~ ERROR missing 'feature' [E0546] +LL | #[stable(since = "a")] | ^^^^^^^^^^^^^^^^^^^^^^ error[E0542]: missing 'since' --> $DIR/stability-attribute-sanity.rs:36:5 | -LL | #[stable(feature = "a")] //~ ERROR missing 'since' [E0542] +LL | #[stable(feature = "a")] | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0542]: missing 'since' --> $DIR/stability-attribute-sanity.rs:40:5 | -LL | #[rustc_deprecated(reason = "a")] //~ ERROR missing 'since' [E0542] +LL | #[rustc_deprecated(reason = "a")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0544]: multiple stability levels --> $DIR/stability-attribute-sanity.rs:45:1 | -LL | #[stable(feature = "a", since = "b")] //~ ERROR multiple stability levels [E0544] +LL | #[stable(feature = "a", since = "b")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0544]: multiple stability levels --> $DIR/stability-attribute-sanity.rs:49:1 | -LL | #[unstable(feature = "b", issue = "0")] //~ ERROR multiple stability levels [E0544] +LL | #[unstable(feature = "b", issue = "0")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0544]: multiple stability levels --> $DIR/stability-attribute-sanity.rs:53:1 | -LL | #[stable(feature = "a", since = "b")] //~ ERROR multiple stability levels [E0544] +LL | #[stable(feature = "a", since = "b")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0540]: multiple rustc_deprecated attributes --> $DIR/stability-attribute-sanity.rs:61:1 | -LL | pub const fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540] +LL | pub const fn multiple4() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0553]: multiple rustc_const_unstable attributes --> $DIR/stability-attribute-sanity.rs:61:1 | -LL | pub const fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540] +LL | pub const fn multiple4() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Invalid stability or deprecation version found --> $DIR/stability-attribute-sanity.rs:61:1 | -LL | pub const fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540] +LL | pub const fn multiple4() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0549]: rustc_deprecated attribute must be paired with either stable or unstable attribute @@ -102,5 +102,4 @@ LL | fn deprecated_without_unstable_or_stable() { } error: aborting due to 17 previous errors -Some errors occurred: E0539, E0540, E0541, E0542, E0544, E0546, E0547, E0549, E0553. -For more information about an error, try `rustc --explain E0539`. +For more information about this error, try `rustc --explain E0541`. diff --git a/src/test/ui/static/static-closures.stderr b/src/test/ui/static/static-closures.stderr index 99235e26e15e7..ced78c03e09d6 100644 --- a/src/test/ui/static/static-closures.stderr +++ b/src/test/ui/static/static-closures.stderr @@ -6,4 +6,3 @@ LL | static || {}; error: aborting due to previous error -For more information about this error, try `rustc --explain E0697`. diff --git a/src/test/ui/static/static-drop-scope.nll.stderr b/src/test/ui/static/static-drop-scope.nll.stderr deleted file mode 100644 index df6383b4fc222..0000000000000 --- a/src/test/ui/static/static-drop-scope.nll.stderr +++ /dev/null @@ -1,72 +0,0 @@ -error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:9:60 - | -LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor); - | ^^^^^^^^ statics cannot evaluate destructors - -error[E0716]: temporary value dropped while borrowed - --> $DIR/static-drop-scope.rs:9:60 - | -LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor); - | ------^^^^^^^^- - | | | | - | | | temporary value is freed at the end of this statement - | | creates a temporary which is freed while still in use - | using this value as a static requires that borrow lasts for `'static` - -error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:13:59 - | -LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor); - | ^^^^^^^^ constants cannot evaluate destructors - -error[E0716]: temporary value dropped while borrowed - --> $DIR/static-drop-scope.rs:13:59 - | -LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor); - | ------^^^^^^^^- - | | | | - | | | temporary value is freed at the end of this statement - | | creates a temporary which is freed while still in use - | using this value as a constant requires that borrow lasts for `'static` - -error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:17:28 - | -LL | static EARLY_DROP_S: i32 = (WithDtor, 0).1; - | ^^^^^^^^^^^^^ statics cannot evaluate destructors - -error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:20:27 - | -LL | const EARLY_DROP_C: i32 = (WithDtor, 0).1; - | ^^^^^^^^^^^^^ constants cannot evaluate destructors - -error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:23:24 - | -LL | const fn const_drop(_: T) {} - | ^ constant functions cannot evaluate destructors - -error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:27:5 - | -LL | (x, ()).1 - | ^^^^^^^ constant functions cannot evaluate destructors - -error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:31:34 - | -LL | const EARLY_DROP_C_OPTION: i32 = (Some(WithDtor), 0).1; - | ^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors - -error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:36:43 - | -LL | const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1; - | ^^^^^^^^^^^ constants cannot evaluate destructors - -error: aborting due to 10 previous errors - -Some errors occurred: E0493, E0716. -For more information about an error, try `rustc --explain E0493`. diff --git a/src/test/ui/static/static-drop-scope.rs b/src/test/ui/static/static-drop-scope.rs index e5a9f2a405644..0de28d5469b38 100644 --- a/src/test/ui/static/static-drop-scope.rs +++ b/src/test/ui/static/static-drop-scope.rs @@ -8,11 +8,11 @@ impl Drop for WithDtor { static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor); //~^ ERROR destructors cannot be evaluated at compile-time -//~| ERROR borrowed value does not live long enoug +//~| ERROR temporary value dropped while borrowed const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor); //~^ ERROR destructors cannot be evaluated at compile-time -//~| ERROR borrowed value does not live long enoug +//~| ERROR temporary value dropped while borrowed static EARLY_DROP_S: i32 = (WithDtor, 0).1; //~^ ERROR destructors cannot be evaluated at compile-time diff --git a/src/test/ui/static/static-drop-scope.stderr b/src/test/ui/static/static-drop-scope.stderr index 3e3032eb4fb60..8a23dad1ba3ea 100644 --- a/src/test/ui/static/static-drop-scope.stderr +++ b/src/test/ui/static/static-drop-scope.stderr @@ -4,15 +4,15 @@ error[E0493]: destructors cannot be evaluated at compile-time LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor); | ^^^^^^^^ statics cannot evaluate destructors -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/static-drop-scope.rs:9:60 | LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor); - | ^^^^^^^^- temporary value only lives until here - | | - | temporary value does not live long enough - | - = note: borrowed value must be valid for the static lifetime... + | ------^^^^^^^^- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary which is freed while still in use + | using this value as a static requires that borrow lasts for `'static` error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/static-drop-scope.rs:13:59 @@ -20,15 +20,15 @@ error[E0493]: destructors cannot be evaluated at compile-time LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor); | ^^^^^^^^ constants cannot evaluate destructors -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/static-drop-scope.rs:13:59 | LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor); - | ^^^^^^^^- temporary value only lives until here - | | - | temporary value does not live long enough - | - = note: borrowed value must be valid for the static lifetime... + | ------^^^^^^^^- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary which is freed while still in use + | using this value as a constant requires that borrow lasts for `'static` error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/static-drop-scope.rs:17:28 @@ -68,5 +68,4 @@ LL | const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1; error: aborting due to 10 previous errors -Some errors occurred: E0493, E0597. -For more information about an error, try `rustc --explain E0493`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/static/static-items-cant-move.stderr b/src/test/ui/static/static-items-cant-move.stderr index 1ac772a460189..235e9ee9b919d 100644 --- a/src/test/ui/static/static-items-cant-move.stderr +++ b/src/test/ui/static/static-items-cant-move.stderr @@ -1,8 +1,8 @@ -error[E0507]: cannot move out of static item +error[E0507]: cannot move out of static item `BAR` --> $DIR/static-items-cant-move.rs:18:10 | -LL | test(BAR); //~ ERROR cannot move out of static item - | ^^^ cannot move out of static item +LL | test(BAR); + | ^^^ move occurs because `BAR` has type `Foo`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/static/static-lifetime-bound.nll.stderr b/src/test/ui/static/static-lifetime-bound.nll.stderr deleted file mode 100644 index 9a8a344cbd87e..0000000000000 --- a/src/test/ui/static/static-lifetime-bound.nll.stderr +++ /dev/null @@ -1,22 +0,0 @@ -warning: unnecessary lifetime parameter `'a` - --> $DIR/static-lifetime-bound.rs:1:6 - | -LL | fn f<'a: 'static>(_: &'a i32) {} //~WARN unnecessary lifetime parameter `'a` - | ^^^^^^^^^^^ - | - = help: you can use the `'static` lifetime directly, in place of `'a` - -error[E0597]: `x` does not live long enough - --> $DIR/static-lifetime-bound.rs:5:7 - | -LL | f(&x); //~ERROR does not live long enough - | --^^- - | | | - | | borrowed value does not live long enough - | argument requires that `x` is borrowed for `'static` -LL | } - | - `x` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/static/static-lifetime-bound.stderr b/src/test/ui/static/static-lifetime-bound.stderr index dc8e83610d4b6..90d728204e70b 100644 --- a/src/test/ui/static/static-lifetime-bound.stderr +++ b/src/test/ui/static/static-lifetime-bound.stderr @@ -1,20 +1,21 @@ warning: unnecessary lifetime parameter `'a` --> $DIR/static-lifetime-bound.rs:1:6 | -LL | fn f<'a: 'static>(_: &'a i32) {} //~WARN unnecessary lifetime parameter `'a` +LL | fn f<'a: 'static>(_: &'a i32) {} | ^^^^^^^^^^^ | = help: you can use the `'static` lifetime directly, in place of `'a` error[E0597]: `x` does not live long enough - --> $DIR/static-lifetime-bound.rs:5:8 + --> $DIR/static-lifetime-bound.rs:5:7 | -LL | f(&x); //~ERROR does not live long enough - | ^ borrowed value does not live long enough +LL | f(&x); + | --^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'static` LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - `x` dropped here while still borrowed error: aborting due to previous error diff --git a/src/test/ui/static/static-lifetime.stderr b/src/test/ui/static/static-lifetime.stderr index 65c60ceb2e374..8516ac07b6cf3 100644 --- a/src/test/ui/static/static-lifetime.stderr +++ b/src/test/ui/static/static-lifetime.stderr @@ -1,13 +1,13 @@ error[E0478]: lifetime bound not satisfied --> $DIR/static-lifetime.rs:3:20 | -LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} //~ ERROR lifetime bound +LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} | ^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime 'a as defined on the impl at 3:6 --> $DIR/static-lifetime.rs:3:6 | -LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} //~ ERROR lifetime bound +LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} | ^^ = note: but lifetime parameter must outlive the static lifetime diff --git a/src/test/ui/static/static-method-privacy.stderr b/src/test/ui/static/static-method-privacy.stderr index c72295f97ca1c..14ca9f58301e2 100644 --- a/src/test/ui/static/static-method-privacy.stderr +++ b/src/test/ui/static/static-method-privacy.stderr @@ -1,7 +1,7 @@ error[E0624]: method `new` is private --> $DIR/static-method-privacy.rs:9:13 | -LL | let _ = a::S::new(); //~ ERROR method `new` is private +LL | let _ = a::S::new(); | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/static/static-mut-bad-types.stderr b/src/test/ui/static/static-mut-bad-types.stderr index e97165705ca70..88d62011fc4e8 100644 --- a/src/test/ui/static/static-mut-bad-types.stderr +++ b/src/test/ui/static/static-mut-bad-types.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/static-mut-bad-types.rs:5:13 | -LL | a = true; //~ ERROR: mismatched types +LL | a = true; | ^^^^ expected isize, found bool error: aborting due to previous error diff --git a/src/test/ui/static/static-mut-foreign-requires-unsafe.stderr b/src/test/ui/static/static-mut-foreign-requires-unsafe.stderr index 9964e1d98b11f..e7ed0b710b2f3 100644 --- a/src/test/ui/static/static-mut-foreign-requires-unsafe.stderr +++ b/src/test/ui/static/static-mut-foreign-requires-unsafe.stderr @@ -1,7 +1,7 @@ error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/static-mut-foreign-requires-unsafe.rs:6:5 | -LL | a += 3; //~ ERROR: requires unsafe +LL | a += 3; | ^^^^^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior @@ -9,7 +9,7 @@ LL | a += 3; //~ ERROR: requires unsafe error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/static-mut-foreign-requires-unsafe.rs:7:5 | -LL | a = 4; //~ ERROR: requires unsafe +LL | a = 4; | ^^^^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior @@ -17,7 +17,7 @@ LL | a = 4; //~ ERROR: requires unsafe error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/static-mut-foreign-requires-unsafe.rs:8:14 | -LL | let _b = a; //~ ERROR: requires unsafe +LL | let _b = a; | ^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior diff --git a/src/test/ui/static/static-mut-not-constant.stderr b/src/test/ui/static/static-mut-not-constant.stderr index d2c6ba6a2f85a..3560be0e29e43 100644 --- a/src/test/ui/static/static-mut-not-constant.stderr +++ b/src/test/ui/static/static-mut-not-constant.stderr @@ -12,5 +12,5 @@ LL | static mut a: Box = box 3; error: aborting due to 2 previous errors -Some errors occurred: E0010, E0019. +Some errors have detailed explanations: E0010, E0019. For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/static/static-mut-not-pat.stderr b/src/test/ui/static/static-mut-not-pat.stderr index 0714df0d11dca..33c1cd6a59506 100644 --- a/src/test/ui/static/static-mut-not-pat.stderr +++ b/src/test/ui/static/static-mut-not-pat.stderr @@ -4,7 +4,7 @@ error[E0530]: match bindings cannot shadow statics LL | static mut a: isize = 3; | ------------------------ the static `a` is defined here ... -LL | a => {} //~ ERROR match bindings cannot shadow statics +LL | a => {} | ^ cannot be named the same as a static error[E0530]: match bindings cannot shadow statics diff --git a/src/test/ui/static/static-mut-requires-unsafe.stderr b/src/test/ui/static/static-mut-requires-unsafe.stderr index 66ee6989b01ef..85e468b333c28 100644 --- a/src/test/ui/static/static-mut-requires-unsafe.stderr +++ b/src/test/ui/static/static-mut-requires-unsafe.stderr @@ -1,7 +1,7 @@ error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/static-mut-requires-unsafe.rs:4:5 | -LL | a += 3; //~ ERROR: requires unsafe +LL | a += 3; | ^^^^^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior @@ -9,7 +9,7 @@ LL | a += 3; //~ ERROR: requires unsafe error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/static-mut-requires-unsafe.rs:5:5 | -LL | a = 4; //~ ERROR: requires unsafe +LL | a = 4; | ^^^^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior @@ -17,7 +17,7 @@ LL | a = 4; //~ ERROR: requires unsafe error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/static-mut-requires-unsafe.rs:6:14 | -LL | let _b = a; //~ ERROR: requires unsafe +LL | let _b = a; | ^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior diff --git a/src/test/ui/static/static-reference-to-fn-1.stderr b/src/test/ui/static/static-reference-to-fn-1.stderr index 84cd6db4c4a94..f6d2385ac69af 100644 --- a/src/test/ui/static/static-reference-to-fn-1.stderr +++ b/src/test/ui/static/static-reference-to-fn-1.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/static-reference-to-fn-1.rs:17:15 | -LL | func: &foo, //~ ERROR mismatched types +LL | func: &foo, | ^^^^ expected fn pointer, found fn item | = note: expected type `&fn() -> std::option::Option` diff --git a/src/test/ui/static/static-reference-to-fn-2.nll.stderr b/src/test/ui/static/static-reference-to-fn-2.nll.stderr deleted file mode 100644 index 2e00c9491d7ca..0000000000000 --- a/src/test/ui/static/static-reference-to-fn-2.nll.stderr +++ /dev/null @@ -1,47 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/static-reference-to-fn-2.rs:18:22 - | -LL | fn state1(self_: &mut StateMachineIter) -> Option<&'static str> { - | ----- has type `&mut StateMachineIter<'1>` -LL | self_.statefn = &id(state2 as StateMachineFunc); - | -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement - | | | - | | creates a temporary which is freed while still in use - | assignment requires that borrow lasts for `'1` - -error[E0716]: temporary value dropped while borrowed - --> $DIR/static-reference-to-fn-2.rs:24:22 - | -LL | fn state2(self_: &mut StateMachineIter) -> Option<(&'static str)> { - | ----- has type `&mut StateMachineIter<'1>` -LL | self_.statefn = &id(state3 as StateMachineFunc); - | -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement - | | | - | | creates a temporary which is freed while still in use - | assignment requires that borrow lasts for `'1` - -error[E0716]: temporary value dropped while borrowed - --> $DIR/static-reference-to-fn-2.rs:30:22 - | -LL | fn state3(self_: &mut StateMachineIter) -> Option<(&'static str)> { - | ----- has type `&mut StateMachineIter<'1>` -LL | self_.statefn = &id(finished as StateMachineFunc); - | -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement - | | | - | | creates a temporary which is freed while still in use - | assignment requires that borrow lasts for `'1` - -error[E0515]: cannot return value referencing temporary value - --> $DIR/static-reference-to-fn-2.rs:40:5 - | -LL | / StateMachineIter { -LL | | statefn: &id(state1 as StateMachineFunc) - | | ------------------------------ temporary value created here -LL | | //~^ ERROR borrowed value does not live long enough -LL | | } - | |_____^ returns a value referencing data owned by the current function - -error: aborting due to 4 previous errors - -Some errors occurred: E0515, E0716. -For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/static/static-reference-to-fn-2.rs b/src/test/ui/static/static-reference-to-fn-2.rs index 8e66532cad917..6693667c091b3 100644 --- a/src/test/ui/static/static-reference-to-fn-2.rs +++ b/src/test/ui/static/static-reference-to-fn-2.rs @@ -16,19 +16,19 @@ impl<'a> Iterator for StateMachineIter<'a> { fn state1(self_: &mut StateMachineIter) -> Option<&'static str> { self_.statefn = &id(state2 as StateMachineFunc); - //~^ ERROR borrowed value does not live long enough + //~^ ERROR temporary value dropped while borrowed return Some("state1"); } fn state2(self_: &mut StateMachineIter) -> Option<(&'static str)> { self_.statefn = &id(state3 as StateMachineFunc); - //~^ ERROR borrowed value does not live long enough + //~^ ERROR temporary value dropped while borrowed return Some("state2"); } fn state3(self_: &mut StateMachineIter) -> Option<(&'static str)> { self_.statefn = &id(finished as StateMachineFunc); - //~^ ERROR borrowed value does not live long enough + //~^ ERROR temporary value dropped while borrowed return Some("state3"); } @@ -38,8 +38,8 @@ fn finished(_: &mut StateMachineIter) -> Option<(&'static str)> { fn state_iter() -> StateMachineIter<'static> { StateMachineIter { + //~^ ERROR cannot return value referencing temporary value statefn: &id(state1 as StateMachineFunc) - //~^ ERROR borrowed value does not live long enough } } diff --git a/src/test/ui/static/static-reference-to-fn-2.stderr b/src/test/ui/static/static-reference-to-fn-2.stderr index d94913c7e2224..028e11a60cef4 100644 --- a/src/test/ui/static/static-reference-to-fn-2.stderr +++ b/src/test/ui/static/static-reference-to-fn-2.stderr @@ -1,71 +1,47 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:18:22 | +LL | fn state1(self_: &mut StateMachineIter) -> Option<&'static str> { + | ----- has type `&mut StateMachineIter<'1>` LL | self_.statefn = &id(state2 as StateMachineFunc); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value only lives until here - | | - | temporary value does not live long enough - | -note: borrowed value must be valid for the anonymous lifetime #2 defined on the function body at 17:1... - --> $DIR/static-reference-to-fn-2.rs:17:1 - | -LL | / fn state1(self_: &mut StateMachineIter) -> Option<&'static str> { -LL | | self_.statefn = &id(state2 as StateMachineFunc); -LL | | //~^ ERROR borrowed value does not live long enough -LL | | return Some("state1"); -LL | | } - | |_^ - = note: consider using a `let` binding to increase its lifetime + | -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement + | | | + | | creates a temporary which is freed while still in use + | assignment requires that borrow lasts for `'1` -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:24:22 | +LL | fn state2(self_: &mut StateMachineIter) -> Option<(&'static str)> { + | ----- has type `&mut StateMachineIter<'1>` LL | self_.statefn = &id(state3 as StateMachineFunc); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value only lives until here - | | - | temporary value does not live long enough - | -note: borrowed value must be valid for the anonymous lifetime #2 defined on the function body at 23:1... - --> $DIR/static-reference-to-fn-2.rs:23:1 - | -LL | / fn state2(self_: &mut StateMachineIter) -> Option<(&'static str)> { -LL | | self_.statefn = &id(state3 as StateMachineFunc); -LL | | //~^ ERROR borrowed value does not live long enough -LL | | return Some("state2"); -LL | | } - | |_^ - = note: consider using a `let` binding to increase its lifetime + | -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement + | | | + | | creates a temporary which is freed while still in use + | assignment requires that borrow lasts for `'1` -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:30:22 | +LL | fn state3(self_: &mut StateMachineIter) -> Option<(&'static str)> { + | ----- has type `&mut StateMachineIter<'1>` LL | self_.statefn = &id(finished as StateMachineFunc); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value only lives until here - | | - | temporary value does not live long enough - | -note: borrowed value must be valid for the anonymous lifetime #2 defined on the function body at 29:1... - --> $DIR/static-reference-to-fn-2.rs:29:1 - | -LL | / fn state3(self_: &mut StateMachineIter) -> Option<(&'static str)> { -LL | | self_.statefn = &id(finished as StateMachineFunc); -LL | | //~^ ERROR borrowed value does not live long enough -LL | | return Some("state3"); -LL | | } - | |_^ - = note: consider using a `let` binding to increase its lifetime + | -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement + | | | + | | creates a temporary which is freed while still in use + | assignment requires that borrow lasts for `'1` -error[E0597]: borrowed value does not live long enough - --> $DIR/static-reference-to-fn-2.rs:41:19 - | -LL | statefn: &id(state1 as StateMachineFunc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -... -LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... +error[E0515]: cannot return value referencing temporary value + --> $DIR/static-reference-to-fn-2.rs:40:5 + | +LL | / StateMachineIter { +LL | | +LL | | statefn: &id(state1 as StateMachineFunc) + | | ------------------------------ temporary value created here +LL | | } + | |_____^ returns a value referencing data owned by the current function error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors have detailed explanations: E0515, E0716. +For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/static/static-region-bound.nll.stderr b/src/test/ui/static/static-region-bound.nll.stderr deleted file mode 100644 index 0a5686051cda4..0000000000000 --- a/src/test/ui/static/static-region-bound.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/static-region-bound.rs:10:14 - | -LL | let x = &id(3); //~ ERROR borrowed value does not live long enough - | ^^^^^ creates a temporary which is freed while still in use -LL | f(x); - | ---- argument requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/static/static-region-bound.rs b/src/test/ui/static/static-region-bound.rs index ee411370d15fa..f133133b33650 100644 --- a/src/test/ui/static/static-region-bound.rs +++ b/src/test/ui/static/static-region-bound.rs @@ -7,6 +7,6 @@ fn f(_: T) {} fn main() { let x: Box<_> = box 3; f(x); - let x = &id(3); //~ ERROR borrowed value does not live long enough + let x = &id(3); //~ ERROR temporary value dropped while borrowed f(x); } diff --git a/src/test/ui/static/static-region-bound.stderr b/src/test/ui/static/static-region-bound.stderr index 611f47ddfde75..15261259ed412 100644 --- a/src/test/ui/static/static-region-bound.stderr +++ b/src/test/ui/static/static-region-bound.stderr @@ -1,14 +1,13 @@ -error[E0597]: borrowed value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/static-region-bound.rs:10:14 | -LL | let x = &id(3); //~ ERROR borrowed value does not live long enough - | ^^^^^ temporary value does not live long enough +LL | let x = &id(3); + | ^^^^^ creates a temporary which is freed while still in use LL | f(x); + | ---- argument requires that borrow lasts for `'static` LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - temporary value is freed at the end of this statement error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/std-uncopyable-atomics.nll.stderr b/src/test/ui/std-uncopyable-atomics.nll.stderr deleted file mode 100644 index 0a5e7c64b1a83..0000000000000 --- a/src/test/ui/std-uncopyable-atomics.nll.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/std-uncopyable-atomics.rs:9:13 - | -LL | let x = *&x; //~ ERROR: cannot move out of borrowed content - | ^^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `&x` - -error[E0507]: cannot move out of borrowed content - --> $DIR/std-uncopyable-atomics.rs:11:13 - | -LL | let x = *&x; //~ ERROR: cannot move out of borrowed content - | ^^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `&x` - -error[E0507]: cannot move out of borrowed content - --> $DIR/std-uncopyable-atomics.rs:13:13 - | -LL | let x = *&x; //~ ERROR: cannot move out of borrowed content - | ^^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `&x` - -error[E0507]: cannot move out of borrowed content - --> $DIR/std-uncopyable-atomics.rs:15:13 - | -LL | let x = *&x; //~ ERROR: cannot move out of borrowed content - | ^^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `&x` - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/std-uncopyable-atomics.rs b/src/test/ui/std-uncopyable-atomics.rs index 2c79a9c440e65..d85864ecac285 100644 --- a/src/test/ui/std-uncopyable-atomics.rs +++ b/src/test/ui/std-uncopyable-atomics.rs @@ -6,11 +6,11 @@ use std::ptr; fn main() { let x = AtomicBool::new(false); - let x = *&x; //~ ERROR: cannot move out of borrowed content + let x = *&x; //~ ERROR: cannot move out of a shared reference let x = AtomicIsize::new(0); - let x = *&x; //~ ERROR: cannot move out of borrowed content + let x = *&x; //~ ERROR: cannot move out of a shared reference let x = AtomicUsize::new(0); - let x = *&x; //~ ERROR: cannot move out of borrowed content + let x = *&x; //~ ERROR: cannot move out of a shared reference let x: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - let x = *&x; //~ ERROR: cannot move out of borrowed content + let x = *&x; //~ ERROR: cannot move out of a shared reference } diff --git a/src/test/ui/std-uncopyable-atomics.stderr b/src/test/ui/std-uncopyable-atomics.stderr index ecf9963c145f2..9db9fcf40f82c 100644 --- a/src/test/ui/std-uncopyable-atomics.stderr +++ b/src/test/ui/std-uncopyable-atomics.stderr @@ -1,38 +1,38 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of a shared reference --> $DIR/std-uncopyable-atomics.rs:9:13 | -LL | let x = *&x; //~ ERROR: cannot move out of borrowed content +LL | let x = *&x; | ^^^ | | - | cannot move out of borrowed content - | help: consider using a reference instead: `&*&x` + | move occurs because value has type `std::sync::atomic::AtomicBool`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*&x` -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of a shared reference --> $DIR/std-uncopyable-atomics.rs:11:13 | -LL | let x = *&x; //~ ERROR: cannot move out of borrowed content +LL | let x = *&x; | ^^^ | | - | cannot move out of borrowed content - | help: consider using a reference instead: `&*&x` + | move occurs because value has type `std::sync::atomic::AtomicIsize`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*&x` -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of a shared reference --> $DIR/std-uncopyable-atomics.rs:13:13 | -LL | let x = *&x; //~ ERROR: cannot move out of borrowed content +LL | let x = *&x; | ^^^ | | - | cannot move out of borrowed content - | help: consider using a reference instead: `&*&x` + | move occurs because value has type `std::sync::atomic::AtomicUsize`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*&x` -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of a shared reference --> $DIR/std-uncopyable-atomics.rs:15:13 | -LL | let x = *&x; //~ ERROR: cannot move out of borrowed content +LL | let x = *&x; | ^^^ | | - | cannot move out of borrowed content - | help: consider using a reference instead: `&*&x` + | move occurs because value has type `std::sync::atomic::AtomicPtr`, which does not implement the `Copy` trait + | help: consider borrowing here: `&*&x` error: aborting due to 4 previous errors diff --git a/src/test/ui/stmt_expr_attrs_no_feature.rs b/src/test/ui/stmt_expr_attrs_no_feature.rs index 0a71d8d133374..674a5ed18cee3 100644 --- a/src/test/ui/stmt_expr_attrs_no_feature.rs +++ b/src/test/ui/stmt_expr_attrs_no_feature.rs @@ -1,4 +1,4 @@ -#![feature(custom_attribute)] +#![feature(rustc_attrs)] macro_rules! stmt_mac { () => { @@ -7,18 +7,19 @@ macro_rules! stmt_mac { } fn main() { - #[attr] + #[rustc_dummy] fn a() {} - #[attr] //~ ERROR attributes on expressions are experimental + // Bug: built-in attrs like `rustc_dummy` are not gated on blocks, but other attrs are. + #[rustfmt::skip] //~ ERROR attributes on expressions are experimental { } - #[attr] + #[rustc_dummy] 5; - #[attr] + #[rustc_dummy] stmt_mac!(); } @@ -26,25 +27,25 @@ fn main() { #[cfg(unset)] fn c() { - #[attr] + #[rustc_dummy] 5; } #[cfg(not(unset))] fn j() { - #[attr] + #[rustc_dummy] 5; } #[cfg_attr(not(unset), cfg(unset))] fn d() { - #[attr] + #[rustc_dummy] 8; } #[cfg_attr(not(unset), cfg(not(unset)))] fn i() { - #[attr] + #[rustc_dummy] 8; } @@ -53,30 +54,30 @@ fn i() { macro_rules! item_mac { ($e:ident) => { fn $e() { - #[attr] + #[rustc_dummy] 42; #[cfg(unset)] fn f() { - #[attr] + #[rustc_dummy] 5; } #[cfg(not(unset))] fn k() { - #[attr] + #[rustc_dummy] 5; } #[cfg_attr(not(unset), cfg(unset))] fn g() { - #[attr] + #[rustc_dummy] 8; } #[cfg_attr(not(unset), cfg(not(unset)))] fn h() { - #[attr] + #[rustc_dummy] 8; } @@ -90,51 +91,51 @@ item_mac!(e); extern { #[cfg(unset)] - fn x(a: [u8; #[attr] 5]); - fn y(a: [u8; #[attr] 5]); //~ ERROR 15701 + fn x(a: [u8; #[rustc_dummy] 5]); + fn y(a: [u8; #[rustc_dummy] 5]); //~ ERROR attributes on expressions are experimental } struct Foo; impl Foo { #[cfg(unset)] - const X: u8 = #[attr] 5; - const Y: u8 = #[attr] 5; //~ ERROR 15701 + const X: u8 = #[rustc_dummy] 5; + const Y: u8 = #[rustc_dummy] 5; //~ ERROR attributes on expressions are experimental } trait Bar { #[cfg(unset)] - const X: [u8; #[attr] 5]; - const Y: [u8; #[attr] 5]; //~ ERROR 15701 + const X: [u8; #[rustc_dummy] 5]; + const Y: [u8; #[rustc_dummy] 5]; //~ ERROR attributes on expressions are experimental } struct Joyce { #[cfg(unset)] - field: [u8; #[attr] 5], - field2: [u8; #[attr] 5] //~ ERROR 15701 + field: [u8; #[rustc_dummy] 5], + field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental } struct Walky( - #[cfg(unset)] [u8; #[attr] 5], - [u8; #[attr] 5] //~ ERROR 15701 + #[cfg(unset)] [u8; #[rustc_dummy] 5], + [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental ); enum Mike { Happy( - #[cfg(unset)] [u8; #[attr] 5], - [u8; #[attr] 5] //~ ERROR 15701 + #[cfg(unset)] [u8; #[rustc_dummy] 5], + [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental ), Angry { #[cfg(unset)] - field: [u8; #[attr] 5], - field2: [u8; #[attr] 5] //~ ERROR 15701 + field: [u8; #[rustc_dummy] 5], + field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental } } fn pat() { match 5 { #[cfg(unset)] - 5 => #[attr] (), - 6 => #[attr] (), //~ ERROR 15701 + 5 => #[rustc_dummy] (), + 6 => #[rustc_dummy] (), //~ ERROR attributes on expressions are experimental _ => (), } } diff --git a/src/test/ui/stmt_expr_attrs_no_feature.stderr b/src/test/ui/stmt_expr_attrs_no_feature.stderr index c4d735915a16c..01372cc164b62 100644 --- a/src/test/ui/stmt_expr_attrs_no_feature.stderr +++ b/src/test/ui/stmt_expr_attrs_no_feature.stderr @@ -1,73 +1,82 @@ -error[E0658]: attributes on expressions are experimental. (see issue #15701) - --> $DIR/stmt_expr_attrs_no_feature.rs:13:5 +error[E0658]: attributes on expressions are experimental + --> $DIR/stmt_expr_attrs_no_feature.rs:14:5 | -LL | #[attr] //~ ERROR attributes on expressions are experimental - | ^^^^^^^ +LL | #[rustfmt::skip] + | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) - --> $DIR/stmt_expr_attrs_no_feature.rs:94:18 +error[E0658]: attributes on expressions are experimental + --> $DIR/stmt_expr_attrs_no_feature.rs:95:18 | -LL | fn y(a: [u8; #[attr] 5]); //~ ERROR 15701 - | ^^^^^^^ +LL | fn y(a: [u8; #[rustc_dummy] 5]); + | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) - --> $DIR/stmt_expr_attrs_no_feature.rs:101:19 +error[E0658]: attributes on expressions are experimental + --> $DIR/stmt_expr_attrs_no_feature.rs:102:19 | -LL | const Y: u8 = #[attr] 5; //~ ERROR 15701 - | ^^^^^^^ +LL | const Y: u8 = #[rustc_dummy] 5; + | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) - --> $DIR/stmt_expr_attrs_no_feature.rs:107:19 +error[E0658]: attributes on expressions are experimental + --> $DIR/stmt_expr_attrs_no_feature.rs:108:19 | -LL | const Y: [u8; #[attr] 5]; //~ ERROR 15701 - | ^^^^^^^ +LL | const Y: [u8; #[rustc_dummy] 5]; + | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) - --> $DIR/stmt_expr_attrs_no_feature.rs:113:18 +error[E0658]: attributes on expressions are experimental + --> $DIR/stmt_expr_attrs_no_feature.rs:114:18 | -LL | field2: [u8; #[attr] 5] //~ ERROR 15701 - | ^^^^^^^ +LL | field2: [u8; #[rustc_dummy] 5] + | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) - --> $DIR/stmt_expr_attrs_no_feature.rs:118:10 +error[E0658]: attributes on expressions are experimental + --> $DIR/stmt_expr_attrs_no_feature.rs:119:10 | -LL | [u8; #[attr] 5] //~ ERROR 15701 - | ^^^^^^^ +LL | [u8; #[rustc_dummy] 5] + | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) - --> $DIR/stmt_expr_attrs_no_feature.rs:124:14 +error[E0658]: attributes on expressions are experimental + --> $DIR/stmt_expr_attrs_no_feature.rs:125:14 | -LL | [u8; #[attr] 5] //~ ERROR 15701 - | ^^^^^^^ +LL | [u8; #[rustc_dummy] 5] + | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) - --> $DIR/stmt_expr_attrs_no_feature.rs:129:22 +error[E0658]: attributes on expressions are experimental + --> $DIR/stmt_expr_attrs_no_feature.rs:130:22 | -LL | field2: [u8; #[attr] 5] //~ ERROR 15701 - | ^^^^^^^ +LL | field2: [u8; #[rustc_dummy] 5] + | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) - --> $DIR/stmt_expr_attrs_no_feature.rs:137:14 +error[E0658]: attributes on expressions are experimental + --> $DIR/stmt_expr_attrs_no_feature.rs:138:14 | -LL | 6 => #[attr] (), //~ ERROR 15701 - | ^^^^^^^ +LL | 6 => #[rustc_dummy] (), + | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable error: aborting due to 9 previous errors diff --git a/src/test/ui/str/str-array-assignment.stderr b/src/test/ui/str/str-array-assignment.stderr index 87809d212d79d..ecd5fb4412967 100644 --- a/src/test/ui/str/str-array-assignment.stderr +++ b/src/test/ui/str/str-array-assignment.stderr @@ -48,5 +48,5 @@ LL | let w: &str = s[..2]; error: aborting due to 4 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/str/str-as-char.fixed b/src/test/ui/str/str-as-char.fixed index accead5c850cc..42bbef8391785 100644 --- a/src/test/ui/str/str-as-char.fixed +++ b/src/test/ui/str/str-as-char.fixed @@ -1,6 +1,5 @@ // run-rustfix fn main() { - println!("{}", "●●"); //~ ERROR character literal may only contain one codepoint - //~^ ERROR format argument must be a string literal + println!("●●"); //~ ERROR character literal may only contain one codepoint } diff --git a/src/test/ui/str/str-as-char.rs b/src/test/ui/str/str-as-char.rs index fb179ec7245d2..09b9dfc590db3 100644 --- a/src/test/ui/str/str-as-char.rs +++ b/src/test/ui/str/str-as-char.rs @@ -2,5 +2,4 @@ fn main() { println!('●●'); //~ ERROR character literal may only contain one codepoint - //~^ ERROR format argument must be a string literal } diff --git a/src/test/ui/str/str-as-char.stderr b/src/test/ui/str/str-as-char.stderr index 4ca430a4cde9b..540a1b55376ff 100644 --- a/src/test/ui/str/str-as-char.stderr +++ b/src/test/ui/str/str-as-char.stderr @@ -1,22 +1,12 @@ error: character literal may only contain one codepoint --> $DIR/str-as-char.rs:4:14 | -LL | println!('●●'); //~ ERROR character literal may only contain one codepoint +LL | println!('●●'); | ^^^^ help: if you meant to write a `str` literal, use double quotes | -LL | println!("●●"); //~ ERROR character literal may only contain one codepoint +LL | println!("●●"); | ^^^^ -error: format argument must be a string literal - --> $DIR/str-as-char.rs:4:14 - | -LL | println!('●●'); //~ ERROR character literal may only contain one codepoint - | ^^^^ -help: you might be missing a string literal to format with - | -LL | println!("{}", '●●'); //~ ERROR character literal may only contain one codepoint - | ^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/str/str-concat-on-double-ref.stderr b/src/test/ui/str/str-concat-on-double-ref.stderr index a67db1936f07e..3e53cdc4d98ca 100644 --- a/src/test/ui/str/str-concat-on-double-ref.stderr +++ b/src/test/ui/str/str-concat-on-double-ref.stderr @@ -1,10 +1,15 @@ error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` - --> $DIR/str-concat-on-double-ref.rs:4:13 + --> $DIR/str-concat-on-double-ref.rs:4:15 | LL | let c = a + b; - | ^^^^^ + | - ^ - &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | - = note: an implementation of `std::ops::Add` might be missing for `&std::string::String` +LL | let c = a.to_owned() + b; + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/str/str-idx.stderr b/src/test/ui/str/str-idx.stderr index 99df85d92fd96..e388534f132d2 100644 --- a/src/test/ui/str/str-idx.stderr +++ b/src/test/ui/str/str-idx.stderr @@ -1,7 +1,7 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-idx.rs:3:17 | -LL | let _: u8 = s[4]; //~ ERROR the type `str` cannot be indexed by `{integer}` +LL | let _: u8 = s[4]; | ^^^^ string indices are ranges of `usize` | = help: the trait `std::slice::SliceIndex` is not implemented for `{integer}` @@ -12,7 +12,7 @@ LL | let _: u8 = s[4]; //~ ERROR the type `str` cannot be indexed by `{integ error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-idx.rs:4:15 | -LL | let _ = s.get(4); //~ ERROR the type `str` cannot be indexed by `{integer}` +LL | let _ = s.get(4); | ^^^ string indices are ranges of `usize` | = help: the trait `std::slice::SliceIndex` is not implemented for `{integer}` @@ -22,7 +22,7 @@ LL | let _ = s.get(4); //~ ERROR the type `str` cannot be indexed by `{integ error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-idx.rs:5:15 | -LL | let _ = s.get_unchecked(4); //~ ERROR the type `str` cannot be indexed by `{integer}` +LL | let _ = s.get_unchecked(4); | ^^^^^^^^^^^^^ string indices are ranges of `usize` | = help: the trait `std::slice::SliceIndex` is not implemented for `{integer}` @@ -32,7 +32,7 @@ LL | let _ = s.get_unchecked(4); //~ ERROR the type `str` cannot be indexed error[E0277]: the type `str` cannot be indexed by `char` --> $DIR/str-idx.rs:6:17 | -LL | let _: u8 = s['c']; //~ ERROR the type `str` cannot be indexed by `char` +LL | let _: u8 = s['c']; | ^^^^^^ string indices are ranges of `usize` | = help: the trait `std::slice::SliceIndex` is not implemented for `char` diff --git a/src/test/ui/str/str-lit-type-mismatch.stderr b/src/test/ui/str/str-lit-type-mismatch.stderr index c14e9090fef98..ef40faa8e26eb 100644 --- a/src/test/ui/str/str-lit-type-mismatch.stderr +++ b/src/test/ui/str/str-lit-type-mismatch.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/str-lit-type-mismatch.rs:2:20 | -LL | let x: &[u8] = "foo"; //~ ERROR mismatched types +LL | let x: &[u8] = "foo"; | ^^^^^ | | | expected slice, found str @@ -13,7 +13,7 @@ LL | let x: &[u8] = "foo"; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/str-lit-type-mismatch.rs:3:23 | -LL | let y: &[u8; 4] = "baaa"; //~ ERROR mismatched types +LL | let y: &[u8; 4] = "baaa"; | ^^^^^^ | | | expected array of 4 elements, found str @@ -25,7 +25,7 @@ LL | let y: &[u8; 4] = "baaa"; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/str-lit-type-mismatch.rs:4:19 | -LL | let z: &str = b"foo"; //~ ERROR mismatched types +LL | let z: &str = b"foo"; | ^^^^^^ | | | expected str, found array of 3 elements diff --git a/src/test/ui/struct-literal-variant-in-if.rs b/src/test/ui/struct-literal-variant-in-if.rs new file mode 100644 index 0000000000000..4ef8effaf1f5f --- /dev/null +++ b/src/test/ui/struct-literal-variant-in-if.rs @@ -0,0 +1,25 @@ +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +enum E { + V { field: bool }, + I { field1: bool, field2: usize }, + J { field: isize }, + K { field: &'static str}, +} +fn test_E(x: E) { + let field = true; + if x == E::V { field } {} + //~^ ERROR expected value, found struct variant `E::V` + //~| ERROR mismatched types + if x == E::I { field1: true, field2: 42 } {} + //~^ ERROR struct literals are not allowed here + if x == E::V { field: false } {} + //~^ ERROR struct literals are not allowed here + if x == E::J { field: -42 } {} + //~^ ERROR struct literals are not allowed here + if x == E::K { field: "" } {} + //~^ ERROR struct literals are not allowed here + let y: usize = (); + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/struct-literal-variant-in-if.stderr b/src/test/ui/struct-literal-variant-in-if.stderr new file mode 100644 index 0000000000000..f91b9d7dce60f --- /dev/null +++ b/src/test/ui/struct-literal-variant-in-if.stderr @@ -0,0 +1,73 @@ +error: struct literals are not allowed here + --> $DIR/struct-literal-variant-in-if.rs:13:13 + | +LL | if x == E::I { field1: true, field2: 42 } {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: surround the struct literal with parentheses + | +LL | if x == (E::I { field1: true, field2: 42 }) {} + | ^ ^ + +error: struct literals are not allowed here + --> $DIR/struct-literal-variant-in-if.rs:15:13 + | +LL | if x == E::V { field: false } {} + | ^^^^^^^^^^^^^^^^^^^^^ +help: surround the struct literal with parentheses + | +LL | if x == (E::V { field: false }) {} + | ^ ^ + +error: struct literals are not allowed here + --> $DIR/struct-literal-variant-in-if.rs:17:13 + | +LL | if x == E::J { field: -42 } {} + | ^^^^^^^^^^^^^^^^^^^ +help: surround the struct literal with parentheses + | +LL | if x == (E::J { field: -42 }) {} + | ^ ^ + +error: struct literals are not allowed here + --> $DIR/struct-literal-variant-in-if.rs:19:13 + | +LL | if x == E::K { field: "" } {} + | ^^^^^^^^^^^^^^^^^^ +help: surround the struct literal with parentheses + | +LL | if x == (E::K { field: "" }) {} + | ^ ^ + +error[E0423]: expected value, found struct variant `E::V` + --> $DIR/struct-literal-variant-in-if.rs:10:13 + | +LL | if x == E::V { field } {} + | ^^^^---------- + | | + | help: surround the struct literal with parenthesis: `(E::V { field })` + +error[E0308]: mismatched types + --> $DIR/struct-literal-variant-in-if.rs:10:20 + | +LL | fn test_E(x: E) { + | - help: try adding a return type: `-> bool` +LL | let field = true; +LL | if x == E::V { field } {} + | ^^^^^ expected (), found bool + | + = note: expected type `()` + found type `bool` + +error[E0308]: mismatched types + --> $DIR/struct-literal-variant-in-if.rs:21:20 + | +LL | let y: usize = (); + | ^^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0308, E0423. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/structs/struct-base-wrong-type-2.rs b/src/test/ui/structs/struct-base-wrong-type-2.rs deleted file mode 100644 index 562f75b8e85bd..0000000000000 --- a/src/test/ui/structs/struct-base-wrong-type-2.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Check that `base` in `Fru { field: expr, ..base }` must have right type. -// -// See also struct-base-wrong-type.rs, which tests same condition -// within a const expression. - -struct Foo { a: isize, b: isize } -struct Bar { x: isize } - -fn main() { - let b = Bar { x: 5 }; - let f = Foo { a: 2, ..b }; //~ ERROR mismatched types - //~| expected type `Foo` - //~| found type `Bar` - //~| expected struct `Foo`, found struct `Bar` - let f__isize = Foo { a: 2, ..4 }; //~ ERROR mismatched types - //~| expected type `Foo` - //~| found type `{integer}` - //~| expected struct `Foo`, found integer -} diff --git a/src/test/ui/structs/struct-base-wrong-type-2.stderr b/src/test/ui/structs/struct-base-wrong-type-2.stderr deleted file mode 100644 index b15ea51bb2d4c..0000000000000 --- a/src/test/ui/structs/struct-base-wrong-type-2.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/struct-base-wrong-type-2.rs:11:27 - | -LL | let f = Foo { a: 2, ..b }; //~ ERROR mismatched types - | ^ expected struct `Foo`, found struct `Bar` - | - = note: expected type `Foo` - found type `Bar` - -error[E0308]: mismatched types - --> $DIR/struct-base-wrong-type-2.rs:15:34 - | -LL | let f__isize = Foo { a: 2, ..4 }; //~ ERROR mismatched types - | ^ expected struct `Foo`, found integer - | - = note: expected type `Foo` - found type `{integer}` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/structs/struct-base-wrong-type.rs b/src/test/ui/structs/struct-base-wrong-type.rs index 6252673c296fb..b64c6b499369f 100644 --- a/src/test/ui/structs/struct-base-wrong-type.rs +++ b/src/test/ui/structs/struct-base-wrong-type.rs @@ -1,27 +1,14 @@ // Check that `base` in `Fru { field: expr, ..base }` must have right type. -// -// See also struct-base-wrong-type-2.rs, which tests same condition -// within a function body. struct Foo { a: isize, b: isize } struct Bar { x: isize } static bar: Bar = Bar { x: 5 }; static foo: Foo = Foo { a: 2, ..bar }; //~ ERROR mismatched types - //~| expected type `Foo` - //~| found type `Bar` - //~| expected struct `Foo`, found struct `Bar` static foo_i: Foo = Foo { a: 2, ..4 }; //~ ERROR mismatched types - //~| expected type `Foo` - //~| found type `{integer}` - //~| expected struct `Foo`, found integer fn main() { let b = Bar { x: 5 }; - // errors below are no longer caught since error above causes - // compilation to abort before we bother checking function bodies. - // See also struct-base-wrong-type-2.rs, which checks that we - // would catch these errors eventually. - let f = Foo { a: 2, ..b }; - let f__isize = Foo { a: 2, ..4 }; + let f = Foo { a: 2, ..b }; //~ ERROR mismatched types + let f__isize = Foo { a: 2, ..4 }; //~ ERROR mismatched types } diff --git a/src/test/ui/structs/struct-base-wrong-type.stderr b/src/test/ui/structs/struct-base-wrong-type.stderr index 045eb610f7d1f..a0216305f3115 100644 --- a/src/test/ui/structs/struct-base-wrong-type.stderr +++ b/src/test/ui/structs/struct-base-wrong-type.stderr @@ -1,21 +1,39 @@ error[E0308]: mismatched types - --> $DIR/struct-base-wrong-type.rs:10:33 + --> $DIR/struct-base-wrong-type.rs:7:33 | -LL | static foo: Foo = Foo { a: 2, ..bar }; //~ ERROR mismatched types +LL | static foo: Foo = Foo { a: 2, ..bar }; | ^^^ expected struct `Foo`, found struct `Bar` | = note: expected type `Foo` found type `Bar` error[E0308]: mismatched types - --> $DIR/struct-base-wrong-type.rs:14:35 + --> $DIR/struct-base-wrong-type.rs:8:35 | -LL | static foo_i: Foo = Foo { a: 2, ..4 }; //~ ERROR mismatched types +LL | static foo_i: Foo = Foo { a: 2, ..4 }; | ^ expected struct `Foo`, found integer | = note: expected type `Foo` found type `{integer}` -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/struct-base-wrong-type.rs:12:27 + | +LL | let f = Foo { a: 2, ..b }; + | ^ expected struct `Foo`, found struct `Bar` + | + = note: expected type `Foo` + found type `Bar` + +error[E0308]: mismatched types + --> $DIR/struct-base-wrong-type.rs:13:34 + | +LL | let f__isize = Foo { a: 2, ..4 }; + | ^ expected struct `Foo`, found integer + | + = note: expected type `Foo` + found type `{integer}` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/structs/struct-field-cfg.stderr b/src/test/ui/structs/struct-field-cfg.stderr index c8c624d548b67..29bad31ef969f 100644 --- a/src/test/ui/structs/struct-field-cfg.stderr +++ b/src/test/ui/structs/struct-field-cfg.stderr @@ -22,9 +22,9 @@ error[E0026]: struct `Foo` does not have a field named `absent` --> $DIR/struct-field-cfg.rs:16:42 | LL | let Foo { present: (), #[cfg(all())] absent: () } = foo; - | ^^^^^^^^^^ struct `Foo` does not have this field + | ^^^^^^ struct `Foo` does not have this field error: aborting due to 4 previous errors -Some errors occurred: E0026, E0027, E0063, E0560. +Some errors have detailed explanations: E0026, E0027, E0063, E0560. For more information about an error, try `rustc --explain E0026`. diff --git a/src/test/ui/structs/struct-field-privacy.stderr b/src/test/ui/structs/struct-field-privacy.stderr index 5e30a4e403de1..91d000b8672e0 100644 --- a/src/test/ui/structs/struct-field-privacy.stderr +++ b/src/test/ui/structs/struct-field-privacy.stderr @@ -1,31 +1,31 @@ error[E0616]: field `a` of struct `inner::A` is private --> $DIR/struct-field-privacy.rs:23:5 | -LL | b.a; //~ ERROR: field `a` of struct `inner::A` is private +LL | b.a; | ^^^ error[E0616]: field `b` of struct `inner::B` is private --> $DIR/struct-field-privacy.rs:26:5 | -LL | c.b; //~ ERROR: field `b` of struct `inner::B` is private +LL | c.b; | ^^^ error[E0616]: field `a` of struct `xc::A` is private --> $DIR/struct-field-privacy.rs:28:5 | -LL | d.a; //~ ERROR: field `a` of struct `xc::A` is private +LL | d.a; | ^^^ error[E0616]: field `b` of struct `xc::B` is private --> $DIR/struct-field-privacy.rs:32:5 | -LL | e.b; //~ ERROR: field `b` of struct `xc::B` is private +LL | e.b; | ^^^ error[E0616]: field `1` of struct `inner::Z` is private --> $DIR/struct-field-privacy.rs:35:5 | -LL | z.1; //~ ERROR: field `1` of struct `inner::Z` is private +LL | z.1; | ^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/structs/struct-fields-dupe.stderr b/src/test/ui/structs/struct-fields-dupe.stderr index 7739ef80fc873..aaf2533dc011a 100644 --- a/src/test/ui/structs/struct-fields-dupe.stderr +++ b/src/test/ui/structs/struct-fields-dupe.stderr @@ -3,7 +3,7 @@ error[E0062]: field `foo` specified more than once | LL | foo: 0, | ------ first use of `foo` -LL | foo: 0 //~ ERROR field `foo` specified more than once +LL | foo: 0 | ^^^ used more than once error: aborting due to previous error diff --git a/src/test/ui/structs/struct-fields-missing.stderr b/src/test/ui/structs/struct-fields-missing.stderr index edbac000dea01..b3e42a94809d7 100644 --- a/src/test/ui/structs/struct-fields-missing.stderr +++ b/src/test/ui/structs/struct-fields-missing.stderr @@ -1,7 +1,7 @@ error[E0063]: missing field `bar` in initializer of `BuildData` --> $DIR/struct-fields-missing.rs:7:15 | -LL | let foo = BuildData { //~ ERROR missing field `bar` in initializer of `BuildData` +LL | let foo = BuildData { | ^^^^^^^^^ missing `bar` error: aborting due to previous error diff --git a/src/test/ui/structs/struct-fields-shorthand-unresolved.stderr b/src/test/ui/structs/struct-fields-shorthand-unresolved.stderr index 37ec6c0f015ff..09fc4f7ee586a 100644 --- a/src/test/ui/structs/struct-fields-shorthand-unresolved.stderr +++ b/src/test/ui/structs/struct-fields-shorthand-unresolved.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `y` in this scope --> $DIR/struct-fields-shorthand-unresolved.rs:10:9 | -LL | y //~ ERROR cannot find value `y` in this scope +LL | y | ^ help: a local variable with a similar name exists: `x` error: aborting due to previous error diff --git a/src/test/ui/structs/struct-fields-shorthand.rs b/src/test/ui/structs/struct-fields-shorthand.rs index 45e3014f22e20..1bdcc8315c154 100644 --- a/src/test/ui/structs/struct-fields-shorthand.rs +++ b/src/test/ui/structs/struct-fields-shorthand.rs @@ -9,4 +9,3 @@ fn main() { x, y, z //~ ERROR struct `Foo` has no field named `z` }; } - diff --git a/src/test/ui/structs/struct-fields-shorthand.stderr b/src/test/ui/structs/struct-fields-shorthand.stderr index 0d3d633f61cf3..a285a392168c7 100644 --- a/src/test/ui/structs/struct-fields-shorthand.stderr +++ b/src/test/ui/structs/struct-fields-shorthand.stderr @@ -1,7 +1,7 @@ error[E0560]: struct `Foo` has no field named `z` --> $DIR/struct-fields-shorthand.rs:9:15 | -LL | x, y, z //~ ERROR struct `Foo` has no field named `z` +LL | x, y, z | ^ `Foo` does not have this field | = note: available fields are: `x`, `y` diff --git a/src/test/ui/structs/struct-fields-typo.stderr b/src/test/ui/structs/struct-fields-typo.stderr index c2fab714f7c15..6949a0a4a6828 100644 --- a/src/test/ui/structs/struct-fields-typo.stderr +++ b/src/test/ui/structs/struct-fields-typo.stderr @@ -1,7 +1,7 @@ error[E0609]: no field `baa` on type `BuildData` --> $DIR/struct-fields-typo.rs:11:17 | -LL | let x = foo.baa; //~ ERROR no field `baa` on type `BuildData` +LL | let x = foo.baa; | ^^^ help: a field with a similar name exists: `bar` error: aborting due to previous error diff --git a/src/test/ui/structs/struct-like-enum-nonexhaustive.stderr b/src/test/ui/structs/struct-like-enum-nonexhaustive.stderr index d651ea0b4e2d7..d6b5af1796403 100644 --- a/src/test/ui/structs/struct-like-enum-nonexhaustive.stderr +++ b/src/test/ui/structs/struct-like-enum-nonexhaustive.stderr @@ -1,8 +1,17 @@ error[E0004]: non-exhaustive patterns: `B { x: Some(_) }` not covered --> $DIR/struct-like-enum-nonexhaustive.rs:8:11 | -LL | match x { //~ ERROR non-exhaustive patterns - | ^ pattern `B { x: Some(_) }` not covered +LL | / enum A { +LL | | B { x: Option }, + | | - not covered +LL | | C +LL | | } + | |_- `A` defined here +... +LL | match x { + | ^ pattern `B { x: Some(_) }` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/structs/struct-missing-comma.stderr b/src/test/ui/structs/struct-missing-comma.stderr index 00ef1a7ff9269..f5b79f54001e7 100644 --- a/src/test/ui/structs/struct-missing-comma.stderr +++ b/src/test/ui/structs/struct-missing-comma.stderr @@ -1,7 +1,7 @@ error: expected `,`, or `}`, found `bar` --> $DIR/struct-missing-comma.rs:4:13 | -LL | foo: u32 //~ expected `,`, or `}`, found `bar` +LL | foo: u32 | ^ help: try adding a comma: `,` error: aborting due to previous error diff --git a/src/test/ui/structs/struct-pat-derived-error.stderr b/src/test/ui/structs/struct-pat-derived-error.stderr index dd1dc71f7fd8b..673715cd3ef6b 100644 --- a/src/test/ui/structs/struct-pat-derived-error.stderr +++ b/src/test/ui/structs/struct-pat-derived-error.stderr @@ -1,22 +1,22 @@ error[E0609]: no field `d` on type `&A` --> $DIR/struct-pat-derived-error.rs:8:31 | -LL | let A { x, y } = self.d; //~ ERROR no field `d` on type `&A` +LL | let A { x, y } = self.d; | ^ error[E0026]: struct `A` does not have fields named `x`, `y` --> $DIR/struct-pat-derived-error.rs:8:17 | -LL | let A { x, y } = self.d; //~ ERROR no field `d` on type `&A` +LL | let A { x, y } = self.d; | ^ ^ struct `A` does not have these fields error[E0027]: pattern does not mention fields `b`, `c` --> $DIR/struct-pat-derived-error.rs:8:13 | -LL | let A { x, y } = self.d; //~ ERROR no field `d` on type `&A` +LL | let A { x, y } = self.d; | ^^^^^^^^^^ missing fields `b`, `c` error: aborting due to 3 previous errors -Some errors occurred: E0026, E0027, E0609. +Some errors have detailed explanations: E0026, E0027, E0609. For more information about an error, try `rustc --explain E0026`. diff --git a/src/test/ui/structs/struct-path-associated-type.rs b/src/test/ui/structs/struct-path-associated-type.rs index 7c770852d22d2..15b37facc502d 100644 --- a/src/test/ui/structs/struct-path-associated-type.rs +++ b/src/test/ui/structs/struct-path-associated-type.rs @@ -13,7 +13,7 @@ fn f() { //~^ ERROR expected struct, variant or union type, found associated type let z = T::A:: {}; //~^ ERROR expected struct, variant or union type, found associated type - //~| ERROR type arguments are not allowed on this entity + //~| ERROR type arguments are not allowed for this type match S { T::A {} => {} //~^ ERROR expected struct, variant or union type, found associated type @@ -22,7 +22,7 @@ fn f() { fn g>() { let s = T::A {}; // OK - let z = T::A:: {}; //~ ERROR type arguments are not allowed on this entity + let z = T::A:: {}; //~ ERROR type arguments are not allowed for this type match S { T::A {} => {} // OK } @@ -31,7 +31,7 @@ fn g>() { fn main() { let s = S::A {}; //~ ERROR ambiguous associated type let z = S::A:: {}; //~ ERROR ambiguous associated type - //~^ ERROR type arguments are not allowed on this entity + //~^ ERROR type arguments are not allowed for this type match S { S::A {} => {} //~ ERROR ambiguous associated type } diff --git a/src/test/ui/structs/struct-path-associated-type.stderr b/src/test/ui/structs/struct-path-associated-type.stderr index 80824d9847838..7cfbd7b720b34 100644 --- a/src/test/ui/structs/struct-path-associated-type.stderr +++ b/src/test/ui/structs/struct-path-associated-type.stderr @@ -4,7 +4,7 @@ error[E0071]: expected struct, variant or union type, found associated type LL | let s = T::A {}; | ^^^^ not a struct -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/struct-path-associated-type.rs:14:20 | LL | let z = T::A:: {}; @@ -22,37 +22,37 @@ error[E0071]: expected struct, variant or union type, found associated type LL | T::A {} => {} | ^^^^ not a struct -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/struct-path-associated-type.rs:25:20 | -LL | let z = T::A:: {}; //~ ERROR type arguments are not allowed on this entity +LL | let z = T::A:: {}; | ^^ type argument not allowed error[E0223]: ambiguous associated type --> $DIR/struct-path-associated-type.rs:32:13 | -LL | let s = S::A {}; //~ ERROR ambiguous associated type +LL | let s = S::A {}; | ^^^^ help: use fully-qualified syntax: `::A` -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/struct-path-associated-type.rs:33:20 | -LL | let z = S::A:: {}; //~ ERROR ambiguous associated type +LL | let z = S::A:: {}; | ^^ type argument not allowed error[E0223]: ambiguous associated type --> $DIR/struct-path-associated-type.rs:33:13 | -LL | let z = S::A:: {}; //~ ERROR ambiguous associated type +LL | let z = S::A:: {}; | ^^^^^^^^^^ help: use fully-qualified syntax: `::A` error[E0223]: ambiguous associated type --> $DIR/struct-path-associated-type.rs:36:9 | -LL | S::A {} => {} //~ ERROR ambiguous associated type +LL | S::A {} => {} | ^^^^ help: use fully-qualified syntax: `::A` error: aborting due to 9 previous errors -Some errors occurred: E0071, E0109, E0223. +Some errors have detailed explanations: E0071, E0109, E0223. For more information about an error, try `rustc --explain E0071`. diff --git a/src/test/ui/structs/struct-path-self-type-mismatch.stderr b/src/test/ui/structs/struct-path-self-type-mismatch.stderr index 0b1b1e83400a5..72c6d7ae22b4b 100644 --- a/src/test/ui/structs/struct-path-self-type-mismatch.stderr +++ b/src/test/ui/structs/struct-path-self-type-mismatch.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/struct-path-self-type-mismatch.rs:7:23 | -LL | Self { inner: 1.5f32 }; //~ ERROR mismatched types +LL | Self { inner: 1.5f32 }; | ^^^^^^ expected i32, found f32 error[E0308]: mismatched types @@ -19,9 +19,9 @@ error[E0308]: mismatched types LL | fn new(u: U) -> Foo { | ------ expected `Foo` because of return type LL | / Self { -LL | | //~^ ERROR mismatched types +LL | | LL | | inner: u -LL | | //~^ ERROR mismatched types +LL | | LL | | } | |_________^ expected type parameter, found a different type parameter | diff --git a/src/test/ui/structs/struct-path-self.rs b/src/test/ui/structs/struct-path-self.rs index 51ed9e5457eb7..77880bfca4074 100644 --- a/src/test/ui/structs/struct-path-self.rs +++ b/src/test/ui/structs/struct-path-self.rs @@ -6,7 +6,7 @@ trait Tr { //~^ ERROR expected struct, variant or union type, found Self let z = Self:: {}; //~^ ERROR expected struct, variant or union type, found Self - //~| ERROR type arguments are not allowed on this entity + //~| ERROR type arguments are not allowed for this type match s { Self { .. } => {} //~^ ERROR expected struct, variant or union type, found Self @@ -17,7 +17,7 @@ trait Tr { impl Tr for S { fn f() { let s = Self {}; // OK - let z = Self:: {}; //~ ERROR type arguments are not allowed on this entity + let z = Self:: {}; //~ ERROR type arguments are not allowed for this type match s { Self { .. } => {} // OK } @@ -27,7 +27,7 @@ impl Tr for S { impl S { fn g() { let s = Self {}; // OK - let z = Self:: {}; //~ ERROR type arguments are not allowed on this entity + let z = Self:: {}; //~ ERROR type arguments are not allowed for this type match s { Self { .. } => {} // OK } diff --git a/src/test/ui/structs/struct-path-self.stderr b/src/test/ui/structs/struct-path-self.stderr index cda6b7a533f65..9eaa1f95bd0c1 100644 --- a/src/test/ui/structs/struct-path-self.stderr +++ b/src/test/ui/structs/struct-path-self.stderr @@ -4,7 +4,7 @@ error[E0071]: expected struct, variant or union type, found Self LL | let s = Self {}; | ^^^^ not a struct -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/struct-path-self.rs:7:24 | LL | let z = Self:: {}; @@ -22,19 +22,19 @@ error[E0071]: expected struct, variant or union type, found Self LL | Self { .. } => {} | ^^^^ not a struct -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/struct-path-self.rs:20:24 | -LL | let z = Self:: {}; //~ ERROR type arguments are not allowed on this entity +LL | let z = Self:: {}; | ^^ type argument not allowed -error[E0109]: type arguments are not allowed on this entity +error[E0109]: type arguments are not allowed for this type --> $DIR/struct-path-self.rs:30:24 | -LL | let z = Self:: {}; //~ ERROR type arguments are not allowed on this entity +LL | let z = Self:: {}; | ^^ type argument not allowed error: aborting due to 6 previous errors -Some errors occurred: E0071, E0109. +Some errors have detailed explanations: E0071, E0109. For more information about an error, try `rustc --explain E0071`. diff --git a/src/test/ui/structs/struct-pattern-match-useless.stderr b/src/test/ui/structs/struct-pattern-match-useless.stderr index 561964bcb24b6..5b0c9305448a7 100644 --- a/src/test/ui/structs/struct-pattern-match-useless.stderr +++ b/src/test/ui/structs/struct-pattern-match-useless.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/struct-pattern-match-useless.rs:12:9 | -LL | Foo { .. } => () //~ ERROR unreachable pattern +LL | Foo { .. } => () | ^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/structs/struct-variant-privacy-xc.stderr b/src/test/ui/structs/struct-variant-privacy-xc.stderr index da61fc83c2622..39241b6b3fc1d 100644 --- a/src/test/ui/structs/struct-variant-privacy-xc.stderr +++ b/src/test/ui/structs/struct-variant-privacy-xc.stderr @@ -1,13 +1,13 @@ error[E0603]: enum `Bar` is private --> $DIR/struct-variant-privacy-xc.rs:4:33 | -LL | fn f(b: struct_variant_privacy::Bar) { //~ ERROR enum `Bar` is private +LL | fn f(b: struct_variant_privacy::Bar) { | ^^^ error[E0603]: enum `Bar` is private --> $DIR/struct-variant-privacy-xc.rs:6:33 | -LL | struct_variant_privacy::Bar::Baz { a: _a } => {} //~ ERROR enum `Bar` is private +LL | struct_variant_privacy::Bar::Baz { a: _a } => {} | ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/structs/struct-variant-privacy.stderr b/src/test/ui/structs/struct-variant-privacy.stderr index 0895b52998c45..127a650104485 100644 --- a/src/test/ui/structs/struct-variant-privacy.stderr +++ b/src/test/ui/structs/struct-variant-privacy.stderr @@ -1,13 +1,13 @@ error[E0603]: enum `Bar` is private --> $DIR/struct-variant-privacy.rs:7:14 | -LL | fn f(b: foo::Bar) { //~ ERROR enum `Bar` is private +LL | fn f(b: foo::Bar) { | ^^^ error[E0603]: enum `Bar` is private --> $DIR/struct-variant-privacy.rs:9:14 | -LL | foo::Bar::Baz { a: _a } => {} //~ ERROR enum `Bar` is private +LL | foo::Bar::Baz { a: _a } => {} | ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/structs/structure-constructor-type-mismatch.stderr b/src/test/ui/structs/structure-constructor-type-mismatch.stderr index cc62316bec185..62d872bb3e4d6 100644 --- a/src/test/ui/structs/structure-constructor-type-mismatch.stderr +++ b/src/test/ui/structs/structure-constructor-type-mismatch.stderr @@ -73,13 +73,13 @@ LL | x: 7, error[E0107]: wrong number of type arguments: expected 0, found 1 --> $DIR/structure-constructor-type-mismatch.rs:48:24 | -LL | let pt3 = PointF:: { //~ ERROR wrong number of type arguments +LL | let pt3 = PointF:: { | ^^^ unexpected type argument error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:49:12 | -LL | x: 9, //~ ERROR mismatched types +LL | x: 9, | ^ | | | expected f32, found integer @@ -91,7 +91,7 @@ LL | x: 9, //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:50:12 | -LL | y: 10, //~ ERROR mismatched types +LL | y: 10, | ^^ | | | expected f32, found integer @@ -103,7 +103,7 @@ LL | y: 10, //~ ERROR mismatched types error[E0107]: wrong number of type arguments: expected 0, found 1 --> $DIR/structure-constructor-type-mismatch.rs:54:18 | -LL | PointF:: { .. } => {} //~ ERROR wrong number of type arguments +LL | PointF:: { .. } => {} | ^^^ unexpected type argument error[E0308]: mismatched types @@ -111,7 +111,7 @@ error[E0308]: mismatched types | LL | match (Point { x: 1, y: 2 }) { | ---------------------- this match expression has type `Point<{integer}>` -LL | PointF:: { .. } => {} //~ ERROR wrong number of type arguments +LL | PointF:: { .. } => {} | ^^^^^^^^^^^^^^^^^^^^ expected integer, found f32 | = note: expected type `Point<{integer}>` @@ -122,7 +122,7 @@ error[E0308]: mismatched types | LL | match (Point { x: 1, y: 2 }) { | ---------------------- this match expression has type `Point<{integer}>` -LL | PointF { .. } => {} //~ ERROR mismatched types +LL | PointF { .. } => {} | ^^^^^^^^^^^^^ expected integer, found f32 | = note: expected type `Point<{integer}>` @@ -133,7 +133,7 @@ error[E0308]: mismatched types | LL | match (Pair { x: 1, y: 2 }) { | --------------------- this match expression has type `Pair<{integer}, {integer}>` -LL | PairF:: { .. } => {} //~ ERROR mismatched types +LL | PairF:: { .. } => {} | ^^^^^^^^^^^^^^^^^^^ expected integer, found f32 | = note: expected type `Pair<{integer}, {integer}>` @@ -141,5 +141,5 @@ LL | PairF:: { .. } => {} //~ ERROR mismatched types error: aborting due to 13 previous errors -Some errors occurred: E0107, E0308. +Some errors have detailed explanations: E0107, E0308. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/substs-ppaux.normal.stderr b/src/test/ui/substs-ppaux.normal.stderr index 567b4d9f4403e..123dd86b90549 100644 --- a/src/test/ui/substs-ppaux.normal.stderr +++ b/src/test/ui/substs-ppaux.normal.stderr @@ -51,5 +51,5 @@ LL | fn bar<'a, T>() where T: 'a {} error: aborting due to 5 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/substs-ppaux.rs b/src/test/ui/substs-ppaux.rs index 7ad7ccb54448f..129ebd43594ce 100644 --- a/src/test/ui/substs-ppaux.rs +++ b/src/test/ui/substs-ppaux.rs @@ -25,7 +25,7 @@ fn foo<'z>() where &'z (): Sized { let x: () = >::bar::<'static, char>; //[verbose]~^ ERROR mismatched types //[verbose]~| expected type `()` - //[verbose]~| found type `fn() {>::bar::}` + //[verbose]~| found type `fn() {>::bar::}` //[normal]~^^^^ ERROR mismatched types //[normal]~| expected type `()` //[normal]~| found type `fn() {>::bar::<'static, char>}` diff --git a/src/test/ui/substs-ppaux.verbose.stderr b/src/test/ui/substs-ppaux.verbose.stderr index 9d8a555dffe16..9167346282bab 100644 --- a/src/test/ui/substs-ppaux.verbose.stderr +++ b/src/test/ui/substs-ppaux.verbose.stderr @@ -14,7 +14,7 @@ LL | let x: () = >::bar::<'static, char>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found fn item | = note: expected type `()` - found type `fn() {>::bar::}` + found type `fn() {>::bar::}` error[E0308]: mismatched types --> $DIR/substs-ppaux.rs:33:17 @@ -51,5 +51,5 @@ LL | fn bar<'a, T>() where T: 'a {} error: aborting due to 5 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/suffixed-literal-meta.rs b/src/test/ui/suffixed-literal-meta.rs index bd2d6623d9104..a6531490c0159 100644 --- a/src/test/ui/suffixed-literal-meta.rs +++ b/src/test/ui/suffixed-literal-meta.rs @@ -1,15 +1,15 @@ -#![feature(custom_attribute)] +#![feature(rustc_attrs)] -#[my_attr = 1usize] //~ ERROR: suffixed literals are not allowed in attributes -#[my_attr = 1u8] //~ ERROR: suffixed literals are not allowed in attributes -#[my_attr = 1u16] //~ ERROR: suffixed literals are not allowed in attributes -#[my_attr = 1u32] //~ ERROR: suffixed literals are not allowed in attributes -#[my_attr = 1u64] //~ ERROR: suffixed literals are not allowed in attributes -#[my_attr = 1isize] //~ ERROR: suffixed literals are not allowed in attributes -#[my_attr = 1i8] //~ ERROR: suffixed literals are not allowed in attributes -#[my_attr = 1i16] //~ ERROR: suffixed literals are not allowed in attributes -#[my_attr = 1i32] //~ ERROR: suffixed literals are not allowed in attributes -#[my_attr = 1i64] //~ ERROR: suffixed literals are not allowed in attributes -#[my_attr = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes -#[my_attr = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes -fn main() { } +#[rustc_dummy = 1usize] //~ ERROR: suffixed literals are not allowed in attributes +#[rustc_dummy = 1u8] //~ ERROR: suffixed literals are not allowed in attributes +#[rustc_dummy = 1u16] //~ ERROR: suffixed literals are not allowed in attributes +#[rustc_dummy = 1u32] //~ ERROR: suffixed literals are not allowed in attributes +#[rustc_dummy = 1u64] //~ ERROR: suffixed literals are not allowed in attributes +#[rustc_dummy = 1isize] //~ ERROR: suffixed literals are not allowed in attributes +#[rustc_dummy = 1i8] //~ ERROR: suffixed literals are not allowed in attributes +#[rustc_dummy = 1i16] //~ ERROR: suffixed literals are not allowed in attributes +#[rustc_dummy = 1i32] //~ ERROR: suffixed literals are not allowed in attributes +#[rustc_dummy = 1i64] //~ ERROR: suffixed literals are not allowed in attributes +#[rustc_dummy = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes +#[rustc_dummy = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes +fn main() {} diff --git a/src/test/ui/suffixed-literal-meta.stderr b/src/test/ui/suffixed-literal-meta.stderr index 265aa78d53f12..83de173b1a703 100644 --- a/src/test/ui/suffixed-literal-meta.stderr +++ b/src/test/ui/suffixed-literal-meta.stderr @@ -1,96 +1,96 @@ error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:3:13 + --> $DIR/suffixed-literal-meta.rs:3:17 | -LL | #[my_attr = 1usize] //~ ERROR: suffixed literals are not allowed in attributes - | ^^^^^^ +LL | #[rustc_dummy = 1usize] + | ^^^^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:4:13 + --> $DIR/suffixed-literal-meta.rs:4:17 | -LL | #[my_attr = 1u8] //~ ERROR: suffixed literals are not allowed in attributes - | ^^^ +LL | #[rustc_dummy = 1u8] + | ^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:5:13 + --> $DIR/suffixed-literal-meta.rs:5:17 | -LL | #[my_attr = 1u16] //~ ERROR: suffixed literals are not allowed in attributes - | ^^^^ +LL | #[rustc_dummy = 1u16] + | ^^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:6:13 + --> $DIR/suffixed-literal-meta.rs:6:17 | -LL | #[my_attr = 1u32] //~ ERROR: suffixed literals are not allowed in attributes - | ^^^^ +LL | #[rustc_dummy = 1u32] + | ^^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:7:13 + --> $DIR/suffixed-literal-meta.rs:7:17 | -LL | #[my_attr = 1u64] //~ ERROR: suffixed literals are not allowed in attributes - | ^^^^ +LL | #[rustc_dummy = 1u64] + | ^^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:8:13 + --> $DIR/suffixed-literal-meta.rs:8:17 | -LL | #[my_attr = 1isize] //~ ERROR: suffixed literals are not allowed in attributes - | ^^^^^^ +LL | #[rustc_dummy = 1isize] + | ^^^^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:9:13 + --> $DIR/suffixed-literal-meta.rs:9:17 | -LL | #[my_attr = 1i8] //~ ERROR: suffixed literals are not allowed in attributes - | ^^^ +LL | #[rustc_dummy = 1i8] + | ^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:10:13 + --> $DIR/suffixed-literal-meta.rs:10:17 | -LL | #[my_attr = 1i16] //~ ERROR: suffixed literals are not allowed in attributes - | ^^^^ +LL | #[rustc_dummy = 1i16] + | ^^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:11:13 + --> $DIR/suffixed-literal-meta.rs:11:17 | -LL | #[my_attr = 1i32] //~ ERROR: suffixed literals are not allowed in attributes - | ^^^^ +LL | #[rustc_dummy = 1i32] + | ^^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:12:13 + --> $DIR/suffixed-literal-meta.rs:12:17 | -LL | #[my_attr = 1i64] //~ ERROR: suffixed literals are not allowed in attributes - | ^^^^ +LL | #[rustc_dummy = 1i64] + | ^^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:13:13 + --> $DIR/suffixed-literal-meta.rs:13:17 | -LL | #[my_attr = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes - | ^^^^^^ +LL | #[rustc_dummy = 1.0f32] + | ^^^^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:14:13 + --> $DIR/suffixed-literal-meta.rs:14:17 | -LL | #[my_attr = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes - | ^^^^^^ +LL | #[rustc_dummy = 1.0f64] + | ^^^^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). diff --git a/src/test/ui/suggestions/assoc-const-as-field.rs b/src/test/ui/suggestions/assoc-const-as-field.rs new file mode 100644 index 0000000000000..678b58936a8d6 --- /dev/null +++ b/src/test/ui/suggestions/assoc-const-as-field.rs @@ -0,0 +1,13 @@ +pub mod Mod { + pub struct Foo {} + impl Foo { + pub const BAR: usize = 42; + } +} + +fn foo(_: usize) {} + +fn main() { + foo(Mod::Foo.Bar); + //~^ ERROR expected value, found +} diff --git a/src/test/ui/suggestions/assoc-const-as-field.stderr b/src/test/ui/suggestions/assoc-const-as-field.stderr new file mode 100644 index 0000000000000..5e746ecb2f28f --- /dev/null +++ b/src/test/ui/suggestions/assoc-const-as-field.stderr @@ -0,0 +1,11 @@ +error[E0423]: expected value, found struct `Mod::Foo` + --> $DIR/assoc-const-as-field.rs:11:9 + | +LL | foo(Mod::Foo.Bar); + | ^^^^^^^^---- + | | + | help: use the path separator to refer to an item: `Mod::Foo::Bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/src/test/ui/suggestions/attribute-typos.stderr b/src/test/ui/suggestions/attribute-typos.stderr index e40da787e96ca..8367ff20aa408 100644 --- a/src/test/ui/suggestions/attribute-typos.stderr +++ b/src/test/ui/suggestions/attribute-typos.stderr @@ -1,25 +1,28 @@ -error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics (see issue #29642) +error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics --> $DIR/attribute-typos.rs:11:3 | -LL | #[rustc_err] //~ ERROR E0658 +LL | #[rustc_err] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(rustc_attrs)] to the crate attributes to enable -error[E0658]: The attribute `tests` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `tests` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/attribute-typos.rs:6:3 | -LL | #[tests] //~ ERROR E0658 +LL | #[tests] | ^^^^^ help: a built-in attribute with a similar name exists: `test` | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `deprcated` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `deprcated` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/attribute-typos.rs:1:3 | -LL | #[deprcated] //~ ERROR E0658 +LL | #[deprcated] | ^^^^^^^^^ help: a built-in attribute with a similar name exists: `deprecated` | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/suggestions/auxiliary/foo.rs b/src/test/ui/suggestions/auxiliary/foo.rs new file mode 100644 index 0000000000000..e90bbef6d5c5f --- /dev/null +++ b/src/test/ui/suggestions/auxiliary/foo.rs @@ -0,0 +1,3 @@ +//! Contains a struct with almost the same name as itself, to trigger Levenshtein suggestions. + +pub struct Foo; diff --git a/src/test/ui/suggestions/borrow-for-loop-head.rs b/src/test/ui/suggestions/borrow-for-loop-head.rs new file mode 100644 index 0000000000000..c2bda55e58903 --- /dev/null +++ b/src/test/ui/suggestions/borrow-for-loop-head.rs @@ -0,0 +1,10 @@ +fn main() { + let a = vec![1, 2, 3]; + for i in &a { + for j in a { + //~^ ERROR cannot move out of `a` because it is borrowed + //~| ERROR use of moved value: `a` + println!("{} * {} = {}", i, j, i * j); + } + } +} diff --git a/src/test/ui/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr new file mode 100644 index 0000000000000..36bced9e4332b --- /dev/null +++ b/src/test/ui/suggestions/borrow-for-loop-head.stderr @@ -0,0 +1,24 @@ +error[E0505]: cannot move out of `a` because it is borrowed + --> $DIR/borrow-for-loop-head.rs:4:18 + | +LL | for i in &a { + | -- borrow of `a` occurs here +LL | for j in a { + | ^ move out of `a` occurs here + +error[E0382]: use of moved value: `a` + --> $DIR/borrow-for-loop-head.rs:4:18 + | +LL | let a = vec![1, 2, 3]; + | - move occurs because `a` has type `std::vec::Vec`, which does not implement the `Copy` trait +LL | for i in &a { +LL | for j in a { + | ^ + | | + | value moved here, in previous iteration of loop + | help: consider borrowing to avoid moving into the for loop: `&a` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0382, E0505. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.rs b/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.rs new file mode 100644 index 0000000000000..ef1c09d218058 --- /dev/null +++ b/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.rs @@ -0,0 +1,14 @@ +fn warn(_: &str) {} + +macro_rules! intrinsic_match { + ($intrinsic:expr) => { + warn(format!("unsupported intrinsic {}", $intrinsic)); + //~^ ERROR mismatched types + }; +} + +fn main() { + intrinsic_match! { + "abc" + }; +} diff --git a/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr b/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr new file mode 100644 index 0000000000000..bc7a7247a1283 --- /dev/null +++ b/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/dont-suggest-deref-inside-macro-issue-58298.rs:11:5 + | +LL | / intrinsic_match! { +LL | | "abc" +LL | | }; + | | ^ + | | | + | |______expected &str, found struct `std::string::String` + | in this macro invocation + | + = note: expected type `&str` + found type `std::string::String` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.rs b/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.rs index 4faede353059a..1c1230346a56c 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.rs +++ b/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - #[derive(Clone)] enum Either { One(X), diff --git a/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr b/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr index 4b51294f86a0f..c0b7a5a5b6250 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr +++ b/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr @@ -1,57 +1,57 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:41:27 +error[E0507]: cannot move out of a shared reference + --> $DIR/duplicate-suggestions.rs:39:27 | LL | let &(X(_t), X(_u)) = &(x.clone(), x.clone()); - | --------------- ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | --------------- ^^^^^^^^^^^^^^^^^^^^^^^ | | | | | | | ...and here | | data moved here | help: consider removing the `&`: `(X(_t), X(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:41:13 + --> $DIR/duplicate-suggestions.rs:39:13 | LL | let &(X(_t), X(_u)) = &(x.clone(), x.clone()); | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:45:50 +error[E0507]: cannot move out of a shared reference + --> $DIR/duplicate-suggestions.rs:43:50 | LL | if let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { } - | ----------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | ----------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^ | | | | | | | ...and here | | data moved here | help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:45:26 + --> $DIR/duplicate-suggestions.rs:43:26 | LL | if let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { } | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:49:53 +error[E0507]: cannot move out of a shared reference + --> $DIR/duplicate-suggestions.rs:47:53 | LL | while let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { } - | ----------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | ----------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^ | | | | | | | ...and here | | data moved here | help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:49:29 + --> $DIR/duplicate-suggestions.rs:47:29 | LL | while let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { } | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:53:11 +error[E0507]: cannot move out of a shared reference + --> $DIR/duplicate-suggestions.rs:51:11 | LL | match &(e.clone(), e.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | &(Either::One(_t), Either::Two(_u)) => (), | -- -- ...and here | | @@ -61,7 +61,7 @@ LL | &(Either::Two(_t), Either::One(_u)) => (), | -- ...and here -- ...and here | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:55:23 + --> $DIR/duplicate-suggestions.rs:53:23 | LL | &(Either::One(_t), Either::Two(_u)) => (), | ^^ ^^ @@ -77,12 +77,12 @@ help: consider removing the `&` LL | (Either::Two(_t), Either::One(_u)) => (), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:63:11 +error[E0507]: cannot move out of a shared reference + --> $DIR/duplicate-suggestions.rs:61:11 | LL | match &(e.clone(), e.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | &(Either::One(_t), Either::Two(_u)) | ----------------------------------- | | | | @@ -91,17 +91,17 @@ LL | &(Either::One(_t), Either::Two(_u)) | help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:65:23 + --> $DIR/duplicate-suggestions.rs:63:23 | LL | &(Either::One(_t), Either::Two(_u)) | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:72:11 +error[E0507]: cannot move out of a shared reference + --> $DIR/duplicate-suggestions.rs:70:11 | LL | match &(e.clone(), e.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | &(Either::One(_t), Either::Two(_u)) => (), | ----------------------------------- | | | | @@ -110,17 +110,17 @@ LL | &(Either::One(_t), Either::Two(_u)) => (), | help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:74:23 + --> $DIR/duplicate-suggestions.rs:72:23 | LL | &(Either::One(_t), Either::Two(_u)) => (), | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:80:11 +error[E0507]: cannot move out of a shared reference + --> $DIR/duplicate-suggestions.rs:78:11 | LL | match &(e.clone(), e.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | &(Either::One(_t), Either::Two(_u)) => (), | ----------------------------------- | | | | @@ -129,65 +129,65 @@ LL | &(Either::One(_t), Either::Two(_u)) => (), | help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:82:23 + --> $DIR/duplicate-suggestions.rs:80:23 | LL | &(Either::One(_t), Either::Two(_u)) => (), | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:93:31 +error[E0507]: cannot move out of a mutable reference + --> $DIR/duplicate-suggestions.rs:91:31 | LL | let &mut (X(_t), X(_u)) = &mut (xm.clone(), xm.clone()); - | ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | | | | | ...and here | | data moved here | help: consider removing the `&mut`: `(X(_t), X(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:93:17 + --> $DIR/duplicate-suggestions.rs:91:17 | LL | let &mut (X(_t), X(_u)) = &mut (xm.clone(), xm.clone()); | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:97:54 +error[E0507]: cannot move out of a mutable reference + --> $DIR/duplicate-suggestions.rs:95:54 | LL | if let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { } - | --------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | --------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | | | | | ...and here | | data moved here | help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:97:30 + --> $DIR/duplicate-suggestions.rs:95:30 | LL | if let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { } | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:101:57 +error[E0507]: cannot move out of a mutable reference + --> $DIR/duplicate-suggestions.rs:99:57 | LL | while let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { } - | --------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | --------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | | | | | ...and here | | data moved here | help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:101:33 + --> $DIR/duplicate-suggestions.rs:99:33 | LL | while let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { } | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:105:11 +error[E0507]: cannot move out of a mutable reference + --> $DIR/duplicate-suggestions.rs:103:11 | LL | match &mut (em.clone(), em.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | &mut (Either::One(_t), Either::Two(_u)) => (), | -- -- ...and here | | @@ -197,7 +197,7 @@ LL | &mut (Either::Two(_t), Either::One(_u)) => (), | -- ...and here -- ...and here | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:107:27 + --> $DIR/duplicate-suggestions.rs:105:27 | LL | &mut (Either::One(_t), Either::Two(_u)) => (), | ^^ ^^ @@ -213,12 +213,12 @@ help: consider removing the `&mut` LL | (Either::Two(_t), Either::One(_u)) => (), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:115:11 +error[E0507]: cannot move out of a mutable reference + --> $DIR/duplicate-suggestions.rs:113:11 | LL | match &mut (em.clone(), em.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | &mut (Either::One(_t), Either::Two(_u)) | --------------------------------------- | | | | @@ -227,17 +227,17 @@ LL | &mut (Either::One(_t), Either::Two(_u)) | help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:117:27 + --> $DIR/duplicate-suggestions.rs:115:27 | LL | &mut (Either::One(_t), Either::Two(_u)) | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:124:11 +error[E0507]: cannot move out of a mutable reference + --> $DIR/duplicate-suggestions.rs:122:11 | LL | match &mut (em.clone(), em.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | &mut (Either::One(_t), Either::Two(_u)) => (), | --------------------------------------- | | | | @@ -246,17 +246,17 @@ LL | &mut (Either::One(_t), Either::Two(_u)) => (), | help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:126:27 + --> $DIR/duplicate-suggestions.rs:124:27 | LL | &mut (Either::One(_t), Either::Two(_u)) => (), | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:132:11 +error[E0507]: cannot move out of a mutable reference + --> $DIR/duplicate-suggestions.rs:130:11 | LL | match &mut (em.clone(), em.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | &mut (Either::One(_t), Either::Two(_u)) => (), | --------------------------------------- | | | | @@ -265,17 +265,17 @@ LL | &mut (Either::One(_t), Either::Two(_u)) => (), | help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:134:27 + --> $DIR/duplicate-suggestions.rs:132:27 | LL | &mut (Either::One(_t), Either::Two(_u)) => (), | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:140:11 +error[E0507]: cannot move out of a mutable reference + --> $DIR/duplicate-suggestions.rs:138:11 | LL | match &mut (em.clone(), em.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | &mut (Either::One(_t), Either::Two(_u)) => (), | --------------------------------------- | | | | @@ -284,41 +284,39 @@ LL | &mut (Either::One(_t), Either::Two(_u)) => (), | help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:142:27 + --> $DIR/duplicate-suggestions.rs:140:27 | LL | &mut (Either::One(_t), Either::Two(_u)) => (), | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:88:11 +error[E0507]: cannot move out of a shared reference + --> $DIR/duplicate-suggestions.rs:86:11 | LL | fn f5(&(X(_t), X(_u)): &(X, X)) { } | ^^^^--^^^^^--^^ | | | | | | | ...and here | | data moved here - | cannot move out of borrowed content | help: consider removing the `&`: `(X(_t), X(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:88:15 + --> $DIR/duplicate-suggestions.rs:86:15 | LL | fn f5(&(X(_t), X(_u)): &(X, X)) { } | ^^ ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/duplicate-suggestions.rs:148:11 +error[E0507]: cannot move out of a mutable reference + --> $DIR/duplicate-suggestions.rs:146:11 | LL | fn f6(&mut (X(_t), X(_u)): &mut (X, X)) { } | ^^^^^^^^--^^^^^--^^ | | | | | | | ...and here | | data moved here - | cannot move out of borrowed content | help: consider removing the `&mut`: `(X(_t), X(_u))` | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/duplicate-suggestions.rs:148:19 + --> $DIR/duplicate-suggestions.rs:146:19 | LL | fn f6(&mut (X(_t), X(_u)): &mut (X, X)) { } | ^^ ^^ diff --git a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.rs b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.rs index 90a9fe4e7d06c..6e3879a4155b9 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.rs +++ b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - #[derive(Clone)] enum Either { One(X), diff --git a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr index f1d515e932c60..c50cbcde85553 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr +++ b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr @@ -1,419 +1,281 @@ -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/move-into-closure.rs:30:21 +error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure + --> $DIR/move-into-closure.rs:28:21 | LL | let x = X(Y); | - captured outer variable ... LL | let X(_t) = x; - | -- ^ - | | | - | | cannot move out of captured variable in an `Fn` closure - | | help: consider borrowing here: `&x` + | -- ^ help: consider borrowing here: `&x` + | | | data moved here - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:30:15 - | -LL | let X(_t) = x; - | ^^ + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/move-into-closure.rs:34:34 +error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure + --> $DIR/move-into-closure.rs:32:34 | LL | let e = Either::One(X(Y)); | - captured outer variable ... LL | if let Either::One(_t) = e { } - | -- ^ - | | | - | | cannot move out of captured variable in an `Fn` closure - | | help: consider borrowing here: `&e` + | -- ^ help: consider borrowing here: `&e` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:34:28 - | -LL | if let Either::One(_t) = e { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/move-into-closure.rs:38:37 +error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure + --> $DIR/move-into-closure.rs:36:37 | LL | let e = Either::One(X(Y)); | - captured outer variable ... LL | while let Either::One(_t) = e { } - | -- ^ - | | | - | | cannot move out of captured variable in an `Fn` closure - | | help: consider borrowing here: `&e` + | -- ^ help: consider borrowing here: `&e` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:38:31 - | -LL | while let Either::One(_t) = e { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/move-into-closure.rs:42:15 +error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure + --> $DIR/move-into-closure.rs:40:15 | LL | let e = Either::One(X(Y)); | - captured outer variable ... LL | match e { - | ^ - | | - | cannot move out of captured variable in an `Fn` closure - | help: consider borrowing here: `&e` + | ^ help: consider borrowing here: `&e` ... LL | Either::One(_t) - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:46:25 - | -LL | Either::One(_t) - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/move-into-closure.rs:49:15 +error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure + --> $DIR/move-into-closure.rs:47:15 | LL | let e = Either::One(X(Y)); | - captured outer variable ... LL | match e { - | ^ - | | - | cannot move out of captured variable in an `Fn` closure - | help: consider borrowing here: `&e` + | ^ help: consider borrowing here: `&e` ... LL | Either::One(_t) => (), - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:53:25 - | -LL | Either::One(_t) => (), - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/move-into-closure.rs:58:25 +error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure + --> $DIR/move-into-closure.rs:56:25 | LL | let x = X(Y); | - captured outer variable ... LL | let X(mut _t) = x; - | ------ ^ - | | | - | | cannot move out of captured variable in an `Fn` closure - | | help: consider borrowing here: `&x` + | ------ ^ help: consider borrowing here: `&x` + | | | data moved here - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:58:15 - | -LL | let X(mut _t) = x; - | ^^^^^^ + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/move-into-closure.rs:62:38 +error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure + --> $DIR/move-into-closure.rs:60:38 | LL | let mut em = Either::One(X(Y)); | ------ captured outer variable ... LL | if let Either::One(mut _t) = em { } - | ------ ^^ - | | | - | | cannot move out of captured variable in an `Fn` closure - | | help: consider borrowing here: `&em` + | ------ ^^ help: consider borrowing here: `&em` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:62:28 - | -LL | if let Either::One(mut _t) = em { } - | ^^^^^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/move-into-closure.rs:66:41 +error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure + --> $DIR/move-into-closure.rs:64:41 | LL | let mut em = Either::One(X(Y)); | ------ captured outer variable ... LL | while let Either::One(mut _t) = em { } - | ------ ^^ - | | | - | | cannot move out of captured variable in an `Fn` closure - | | help: consider borrowing here: `&em` + | ------ ^^ help: consider borrowing here: `&em` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:66:31 - | -LL | while let Either::One(mut _t) = em { } - | ^^^^^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/move-into-closure.rs:70:15 +error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure + --> $DIR/move-into-closure.rs:68:15 | LL | let mut em = Either::One(X(Y)); | ------ captured outer variable ... LL | match em { - | ^^ - | | - | cannot move out of captured variable in an `Fn` closure - | help: consider borrowing here: `&em` + | ^^ help: consider borrowing here: `&em` ... LL | Either::One(mut _t) - | ------ data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:74:25 - | -LL | Either::One(mut _t) - | ^^^^^^ + | ------ + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/move-into-closure.rs:77:15 +error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure + --> $DIR/move-into-closure.rs:75:15 | LL | let mut em = Either::One(X(Y)); | ------ captured outer variable ... LL | match em { - | ^^ - | | - | cannot move out of captured variable in an `Fn` closure - | help: consider borrowing here: `&em` + | ^^ help: consider borrowing here: `&em` ... LL | Either::One(mut _t) => (), - | ------ data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:81:25 - | -LL | Either::One(mut _t) => (), - | ^^^^^^ + | ------ + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/move-into-closure.rs:97:21 +error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure + --> $DIR/move-into-closure.rs:95:21 | LL | let x = X(Y); | - captured outer variable ... LL | let X(_t) = x; - | -- ^ - | | | - | | cannot move out of captured variable in an `FnMut` closure - | | help: consider borrowing here: `&x` + | -- ^ help: consider borrowing here: `&x` + | | | data moved here - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:97:15 - | -LL | let X(_t) = x; - | ^^ + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/move-into-closure.rs:101:34 +error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure + --> $DIR/move-into-closure.rs:99:34 | LL | let e = Either::One(X(Y)); | - captured outer variable ... LL | if let Either::One(_t) = e { } - | -- ^ - | | | - | | cannot move out of captured variable in an `FnMut` closure - | | help: consider borrowing here: `&e` + | -- ^ help: consider borrowing here: `&e` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:101:28 - | -LL | if let Either::One(_t) = e { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/move-into-closure.rs:105:37 +error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure + --> $DIR/move-into-closure.rs:103:37 | LL | let e = Either::One(X(Y)); | - captured outer variable ... LL | while let Either::One(_t) = e { } - | -- ^ - | | | - | | cannot move out of captured variable in an `FnMut` closure - | | help: consider borrowing here: `&e` + | -- ^ help: consider borrowing here: `&e` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:105:31 - | -LL | while let Either::One(_t) = e { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/move-into-closure.rs:109:15 +error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure + --> $DIR/move-into-closure.rs:107:15 | LL | let e = Either::One(X(Y)); | - captured outer variable ... LL | match e { - | ^ - | | - | cannot move out of captured variable in an `FnMut` closure - | help: consider borrowing here: `&e` + | ^ help: consider borrowing here: `&e` ... LL | Either::One(_t) - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:113:25 - | -LL | Either::One(_t) - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/move-into-closure.rs:116:15 +error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure + --> $DIR/move-into-closure.rs:114:15 | LL | let e = Either::One(X(Y)); | - captured outer variable ... LL | match e { - | ^ - | | - | cannot move out of captured variable in an `FnMut` closure - | help: consider borrowing here: `&e` + | ^ help: consider borrowing here: `&e` ... LL | Either::One(_t) => (), - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:120:25 - | -LL | Either::One(_t) => (), - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/move-into-closure.rs:125:25 +error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure + --> $DIR/move-into-closure.rs:123:25 | LL | let x = X(Y); | - captured outer variable ... LL | let X(mut _t) = x; - | ------ ^ - | | | - | | cannot move out of captured variable in an `FnMut` closure - | | help: consider borrowing here: `&x` + | ------ ^ help: consider borrowing here: `&x` + | | | data moved here - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:125:15 - | -LL | let X(mut _t) = x; - | ^^^^^^ + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/move-into-closure.rs:129:38 +error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure + --> $DIR/move-into-closure.rs:127:38 | LL | let mut em = Either::One(X(Y)); | ------ captured outer variable ... LL | if let Either::One(mut _t) = em { } - | ------ ^^ - | | | - | | cannot move out of captured variable in an `FnMut` closure - | | help: consider borrowing here: `&em` + | ------ ^^ help: consider borrowing here: `&em` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:129:28 - | -LL | if let Either::One(mut _t) = em { } - | ^^^^^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/move-into-closure.rs:133:41 +error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure + --> $DIR/move-into-closure.rs:131:41 | LL | let mut em = Either::One(X(Y)); | ------ captured outer variable ... LL | while let Either::One(mut _t) = em { } - | ------ ^^ - | | | - | | cannot move out of captured variable in an `FnMut` closure - | | help: consider borrowing here: `&em` + | ------ ^^ help: consider borrowing here: `&em` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:133:31 - | -LL | while let Either::One(mut _t) = em { } - | ^^^^^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/move-into-closure.rs:137:15 +error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure + --> $DIR/move-into-closure.rs:135:15 | LL | let mut em = Either::One(X(Y)); | ------ captured outer variable ... LL | match em { - | ^^ - | | - | cannot move out of captured variable in an `FnMut` closure - | help: consider borrowing here: `&em` + | ^^ help: consider borrowing here: `&em` ... LL | Either::One(mut _t) - | ------ data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:141:25 - | -LL | Either::One(mut _t) - | ^^^^^^ + | ------ + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/move-into-closure.rs:144:15 +error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure + --> $DIR/move-into-closure.rs:142:15 | LL | let mut em = Either::One(X(Y)); | ------ captured outer variable ... LL | match em { - | ^^ - | | - | cannot move out of captured variable in an `FnMut` closure - | help: consider borrowing here: `&em` + | ^^ help: consider borrowing here: `&em` ... LL | Either::One(mut _t) => (), - | ------ data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:148:25 - | -LL | Either::One(mut _t) => (), - | ^^^^^^ + | ------ + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/move-into-closure.rs:152:15 +error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure + --> $DIR/move-into-closure.rs:150:15 | LL | let mut em = Either::One(X(Y)); | ------ captured outer variable ... LL | match em { - | ^^ - | | - | cannot move out of captured variable in an `FnMut` closure - | help: consider borrowing here: `&em` + | ^^ help: consider borrowing here: `&em` ... LL | Either::One(mut _t) => (), - | ------ data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/move-into-closure.rs:156:25 - | -LL | Either::One(mut _t) => (), - | ^^^^^^ + | ------ + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error: aborting due to 21 previous errors diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.rs b/src/test/ui/suggestions/dont-suggest-ref/simple.rs index 58aab85ac2673..69b303a66237e 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/simple.rs +++ b/src/test/ui/suggestions/dont-suggest-ref/simple.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - #[derive(Clone)] enum Either { One(X), @@ -39,26 +37,26 @@ pub fn main() { let X(_t) = *s; //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION s if let Either::One(_t) = *r { } //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION r while let Either::One(_t) = *r { } //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION r match *r { //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION r Either::One(_t) | Either::Two(_t) => (), } match *r { //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION r Either::One(_t) => (), Either::Two(ref _t) => (), @@ -67,26 +65,26 @@ pub fn main() { let X(_t) = *sm; //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION sm if let Either::One(_t) = *rm { } //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION rm while let Either::One(_t) = *rm { } //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION rm match *rm { //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION rm Either::One(_t) | Either::Two(_t) => (), } match *rm { //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION rm Either::One(_t) => (), Either::Two(ref _t) => (), @@ -94,7 +92,7 @@ pub fn main() { } match *rm { //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION rm Either::One(_t) => (), Either::Two(ref mut _t) => (), diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr index 296fcef0c4a30..cb3ce5991aeee 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr +++ b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr @@ -1,525 +1,336 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:40:17 +error[E0507]: cannot move out of `s.0` which is behind a shared reference + --> $DIR/simple.rs:38:17 | LL | let X(_t) = *s; - | -- ^^ - | | | - | | cannot move out of borrowed content - | | help: consider removing the `*`: `s` + | -- ^^ help: consider borrowing here: `&*s` + | | | data moved here - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:40:11 - | -LL | let X(_t) = *s; - | ^^ + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:44:30 +error[E0507]: cannot move out of `r.0` which is behind a shared reference + --> $DIR/simple.rs:42:30 | LL | if let Either::One(_t) = *r { } - | -- ^^ - | | | - | | cannot move out of borrowed content - | | help: consider removing the `*`: `r` + | -- ^^ help: consider borrowing here: `&*r` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:44:24 - | -LL | if let Either::One(_t) = *r { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:48:33 +error[E0507]: cannot move out of `r.0` which is behind a shared reference + --> $DIR/simple.rs:46:33 | LL | while let Either::One(_t) = *r { } - | -- ^^ - | | | - | | cannot move out of borrowed content - | | help: consider removing the `*`: `r` + | -- ^^ help: consider borrowing here: `&*r` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:48:27 - | -LL | while let Either::One(_t) = *r { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:52:11 +error[E0507]: cannot move out of `r.0` which is behind a shared reference + --> $DIR/simple.rs:50:11 | LL | match *r { - | ^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `r` + | ^^ help: consider borrowing here: `&*r` ... LL | Either::One(_t) - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:56:21 - | -LL | Either::One(_t) - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:59:11 +error[E0507]: cannot move out of `r.0` which is behind a shared reference + --> $DIR/simple.rs:57:11 | LL | match *r { - | ^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `r` + | ^^ help: consider borrowing here: `&*r` ... LL | Either::One(_t) => (), - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:63:21 - | -LL | Either::One(_t) => (), - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:68:17 +error[E0507]: cannot move out of `sm.0` which is behind a mutable reference + --> $DIR/simple.rs:66:17 | LL | let X(_t) = *sm; - | -- ^^^ - | | | - | | cannot move out of borrowed content - | | help: consider removing the `*`: `sm` + | -- ^^^ help: consider borrowing here: `&*sm` + | | | data moved here - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:68:11 - | -LL | let X(_t) = *sm; - | ^^ + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:72:30 +error[E0507]: cannot move out of `rm.0` which is behind a mutable reference + --> $DIR/simple.rs:70:30 | LL | if let Either::One(_t) = *rm { } - | -- ^^^ - | | | - | | cannot move out of borrowed content - | | help: consider removing the `*`: `rm` + | -- ^^^ help: consider borrowing here: `&*rm` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:72:24 - | -LL | if let Either::One(_t) = *rm { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:76:33 +error[E0507]: cannot move out of `rm.0` which is behind a mutable reference + --> $DIR/simple.rs:74:33 | LL | while let Either::One(_t) = *rm { } - | -- ^^^ - | | | - | | cannot move out of borrowed content - | | help: consider removing the `*`: `rm` + | -- ^^^ help: consider borrowing here: `&*rm` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:76:27 - | -LL | while let Either::One(_t) = *rm { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:80:11 +error[E0507]: cannot move out of `rm.0` which is behind a mutable reference + --> $DIR/simple.rs:78:11 | LL | match *rm { - | ^^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `rm` + | ^^^ help: consider borrowing here: `&*rm` ... LL | Either::One(_t) - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:84:21 - | -LL | Either::One(_t) - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:87:11 +error[E0507]: cannot move out of `rm.0` which is behind a mutable reference + --> $DIR/simple.rs:85:11 | LL | match *rm { - | ^^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `rm` + | ^^^ help: consider borrowing here: `&*rm` ... LL | Either::One(_t) => (), - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:91:21 - | -LL | Either::One(_t) => (), - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:95:11 +error[E0507]: cannot move out of `rm.0` which is behind a mutable reference + --> $DIR/simple.rs:93:11 | LL | match *rm { - | ^^^ - | | - | cannot move out of borrowed content - | help: consider removing the `*`: `rm` + | ^^^ help: consider borrowing here: `&*rm` ... LL | Either::One(_t) => (), - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:99:21 - | -LL | Either::One(_t) => (), - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:104:17 +error[E0507]: cannot move out of index of `std::vec::Vec` + --> $DIR/simple.rs:102:17 | LL | let X(_t) = vs[0]; - | -- ^^^^^ - | | | - | | cannot move out of borrowed content - | | help: consider borrowing here: `&vs[0]` + | -- ^^^^^ help: consider borrowing here: `&vs[0]` + | | | data moved here - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:104:11 - | -LL | let X(_t) = vs[0]; - | ^^ + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:108:30 +error[E0507]: cannot move out of index of `std::vec::Vec` + --> $DIR/simple.rs:106:30 | LL | if let Either::One(_t) = vr[0] { } - | -- ^^^^^ - | | | - | | cannot move out of borrowed content - | | help: consider borrowing here: `&vr[0]` + | -- ^^^^^ help: consider borrowing here: `&vr[0]` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:108:24 - | -LL | if let Either::One(_t) = vr[0] { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:112:33 +error[E0507]: cannot move out of index of `std::vec::Vec` + --> $DIR/simple.rs:110:33 | LL | while let Either::One(_t) = vr[0] { } - | -- ^^^^^ - | | | - | | cannot move out of borrowed content - | | help: consider borrowing here: `&vr[0]` + | -- ^^^^^ help: consider borrowing here: `&vr[0]` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:112:27 - | -LL | while let Either::One(_t) = vr[0] { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:116:11 +error[E0507]: cannot move out of index of `std::vec::Vec` + --> $DIR/simple.rs:114:11 | LL | match vr[0] { - | ^^^^^ - | | - | cannot move out of borrowed content - | help: consider borrowing here: `&vr[0]` + | ^^^^^ help: consider borrowing here: `&vr[0]` ... LL | Either::One(_t) - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:120:21 - | -LL | Either::One(_t) - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:123:11 +error[E0507]: cannot move out of index of `std::vec::Vec` + --> $DIR/simple.rs:121:11 | LL | match vr[0] { - | ^^^^^ - | | - | cannot move out of borrowed content - | help: consider borrowing here: `&vr[0]` + | ^^^^^ help: consider borrowing here: `&vr[0]` ... LL | Either::One(_t) => (), - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:127:21 - | -LL | Either::One(_t) => (), - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:132:17 +error[E0507]: cannot move out of index of `std::vec::Vec` + --> $DIR/simple.rs:130:17 | LL | let X(_t) = vsm[0]; - | -- ^^^^^^ - | | | - | | cannot move out of borrowed content - | | help: consider borrowing here: `&vsm[0]` + | -- ^^^^^^ help: consider borrowing here: `&vsm[0]` + | | | data moved here - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:132:11 - | -LL | let X(_t) = vsm[0]; - | ^^ + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:136:30 +error[E0507]: cannot move out of index of `std::vec::Vec` + --> $DIR/simple.rs:134:30 | LL | if let Either::One(_t) = vrm[0] { } - | -- ^^^^^^ - | | | - | | cannot move out of borrowed content - | | help: consider borrowing here: `&vrm[0]` + | -- ^^^^^^ help: consider borrowing here: `&vrm[0]` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:136:24 - | -LL | if let Either::One(_t) = vrm[0] { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:140:33 +error[E0507]: cannot move out of index of `std::vec::Vec` + --> $DIR/simple.rs:138:33 | LL | while let Either::One(_t) = vrm[0] { } - | -- ^^^^^^ - | | | - | | cannot move out of borrowed content - | | help: consider borrowing here: `&vrm[0]` + | -- ^^^^^^ help: consider borrowing here: `&vrm[0]` + | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:140:27 - | -LL | while let Either::One(_t) = vrm[0] { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:144:11 +error[E0507]: cannot move out of index of `std::vec::Vec` + --> $DIR/simple.rs:142:11 | LL | match vrm[0] { - | ^^^^^^ - | | - | cannot move out of borrowed content - | help: consider borrowing here: `&vrm[0]` + | ^^^^^^ help: consider borrowing here: `&vrm[0]` ... LL | Either::One(_t) - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:148:21 - | -LL | Either::One(_t) - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:151:11 +error[E0507]: cannot move out of index of `std::vec::Vec` + --> $DIR/simple.rs:149:11 | LL | match vrm[0] { - | ^^^^^^ - | | - | cannot move out of borrowed content - | help: consider borrowing here: `&vrm[0]` + | ^^^^^^ help: consider borrowing here: `&vrm[0]` ... LL | Either::One(_t) => (), - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:155:21 - | -LL | Either::One(_t) => (), - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:159:11 +error[E0507]: cannot move out of index of `std::vec::Vec` + --> $DIR/simple.rs:157:11 | LL | match vrm[0] { - | ^^^^^^ - | | - | cannot move out of borrowed content - | help: consider borrowing here: `&vrm[0]` + | ^^^^^^ help: consider borrowing here: `&vrm[0]` ... LL | Either::One(_t) => (), - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:163:21 - | -LL | Either::One(_t) => (), - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:170:18 +error[E0507]: cannot move out of `s.0` which is behind a shared reference + --> $DIR/simple.rs:168:18 | LL | let &X(_t) = s; - | ------ ^ cannot move out of borrowed content + | ------ ^ | | | | | data moved here + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the `&`: `X(_t)` - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:170:12 - | -LL | let &X(_t) = s; - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:174:31 +error[E0507]: cannot move out of `r.0` which is behind a shared reference + --> $DIR/simple.rs:172:31 | LL | if let &Either::One(_t) = r { } - | ---------------- ^ cannot move out of borrowed content + | ---------------- ^ | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:174:25 - | -LL | if let &Either::One(_t) = r { } - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:178:34 +error[E0507]: cannot move out of `r.0` which is behind a shared reference + --> $DIR/simple.rs:176:34 | LL | while let &Either::One(_t) = r { } - | ---------------- ^ cannot move out of borrowed content + | ---------------- ^ | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:178:28 - | -LL | while let &Either::One(_t) = r { } - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:182:11 +error[E0507]: cannot move out of `r.0` which is behind a shared reference + --> $DIR/simple.rs:180:11 | LL | match r { - | ^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^ +LL | LL | &Either::One(_t) | ---------------- | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:184:22 - | -LL | &Either::One(_t) - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:190:11 +error[E0507]: cannot move out of `r.0` which is behind a shared reference + --> $DIR/simple.rs:188:11 | LL | match r { - | ^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^ +LL | LL | &Either::One(_t) => (), | ---------------- | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:192:22 - | -LL | &Either::One(_t) => (), - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:197:11 +error[E0507]: cannot move out of `r.0` which is behind a shared reference + --> $DIR/simple.rs:195:11 | LL | match r { - | ^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^ +LL | LL | &Either::One(_t) => (), | ---------------- | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:199:22 - | -LL | &Either::One(_t) => (), - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:209:22 +error[E0507]: cannot move out of `sm.0` which is behind a mutable reference + --> $DIR/simple.rs:207:22 | LL | let &mut X(_t) = sm; - | ---------- ^^ cannot move out of borrowed content + | ---------- ^^ | | | | | data moved here + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `X(_t)` - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:209:16 - | -LL | let &mut X(_t) = sm; - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:213:35 +error[E0507]: cannot move out of `rm.0` which is behind a mutable reference + --> $DIR/simple.rs:211:35 | LL | if let &mut Either::One(_t) = rm { } - | -------------------- ^^ cannot move out of borrowed content + | -------------------- ^^ | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:213:29 - | -LL | if let &mut Either::One(_t) = rm { } - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:217:38 +error[E0507]: cannot move out of `rm.0` which is behind a mutable reference + --> $DIR/simple.rs:215:38 | LL | while let &mut Either::One(_t) = rm { } - | -------------------- ^^ cannot move out of borrowed content + | -------------------- ^^ | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:217:32 - | -LL | while let &mut Either::One(_t) = rm { } - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:221:11 +error[E0507]: cannot move out of `rm.0` which is behind a mutable reference + --> $DIR/simple.rs:219:11 | LL | match rm { - | ^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^ +LL | LL | &mut Either::One(_t) => (), | -- data moved here ... @@ -527,7 +338,7 @@ LL | &mut Either::Two(_t) => (), | -- ...and here | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/simple.rs:223:26 + --> $DIR/simple.rs:221:26 | LL | &mut Either::One(_t) => (), | ^^ @@ -543,455 +354,318 @@ help: consider removing the `&mut` LL | Either::Two(_t) => (), | ^^^^^^^^^^^^^^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:230:11 +error[E0507]: cannot move out of `rm.0` which is behind a mutable reference + --> $DIR/simple.rs:228:11 | LL | match rm { - | ^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^ +LL | LL | &mut Either::One(_t) => (), | -------------------- | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:232:26 - | -LL | &mut Either::One(_t) => (), - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:237:11 +error[E0507]: cannot move out of `rm.0` which is behind a mutable reference + --> $DIR/simple.rs:235:11 | LL | match rm { - | ^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^ +LL | LL | &mut Either::One(_t) => (), | -------------------- | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:239:26 - | -LL | &mut Either::One(_t) => (), - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:244:11 +error[E0507]: cannot move out of `rm.0` which is behind a mutable reference + --> $DIR/simple.rs:242:11 | LL | match rm { - | ^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^ +LL | LL | &mut Either::One(_t) => (), | -------------------- | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:246:26 - | -LL | &mut Either::One(_t) => (), - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:260:21 +error[E0507]: cannot move out of a shared reference + --> $DIR/simple.rs:258:21 | LL | let (&X(_t),) = (&x.clone(),); - | -- ^^^^^^^^^^^^^ cannot move out of borrowed content + | -- ^^^^^^^^^^^^^ | | | data moved here - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:260:13 - | -LL | let (&X(_t),) = (&x.clone(),); - | ^^ + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:262:34 +error[E0507]: cannot move out of a shared reference + --> $DIR/simple.rs:260:34 | LL | if let (&Either::One(_t),) = (&e.clone(),) { } - | -- ^^^^^^^^^^^^^ cannot move out of borrowed content + | -- ^^^^^^^^^^^^^ | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:262:26 - | -LL | if let (&Either::One(_t),) = (&e.clone(),) { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:264:37 +error[E0507]: cannot move out of a shared reference + --> $DIR/simple.rs:262:37 | LL | while let (&Either::One(_t),) = (&e.clone(),) { } - | -- ^^^^^^^^^^^^^ cannot move out of borrowed content + | -- ^^^^^^^^^^^^^ | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:264:29 - | -LL | while let (&Either::One(_t),) = (&e.clone(),) { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:266:11 +error[E0507]: cannot move out of a shared reference + --> $DIR/simple.rs:264:11 | LL | match (&e.clone(),) { - | ^^^^^^^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move -LL | (&Either::One(_t),) - | -- data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:268:23 - | + | ^^^^^^^^^^^^^ +LL | LL | (&Either::One(_t),) - | ^^ + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:274:25 +error[E0507]: cannot move out of a mutable reference + --> $DIR/simple.rs:272:25 | LL | let (&mut X(_t),) = (&mut xm.clone(),); - | -- ^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | -- ^^^^^^^^^^^^^^^^^^ | | | data moved here - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:274:17 - | -LL | let (&mut X(_t),) = (&mut xm.clone(),); - | ^^ + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:276:38 +error[E0507]: cannot move out of a mutable reference + --> $DIR/simple.rs:274:38 | LL | if let (&mut Either::One(_t),) = (&mut em.clone(),) { } - | -- ^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | -- ^^^^^^^^^^^^^^^^^^ | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:276:30 - | -LL | if let (&mut Either::One(_t),) = (&mut em.clone(),) { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:278:41 +error[E0507]: cannot move out of a mutable reference + --> $DIR/simple.rs:276:41 | LL | while let (&mut Either::One(_t),) = (&mut em.clone(),) { } - | -- ^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content + | -- ^^^^^^^^^^^^^^^^^^ | | | data moved here - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:278:33 - | -LL | while let (&mut Either::One(_t),) = (&mut em.clone(),) { } - | ^^ + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:280:11 +error[E0507]: cannot move out of a mutable reference + --> $DIR/simple.rs:278:11 | LL | match (&mut em.clone(),) { - | ^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^^^^^^^^^^^^ +LL | LL | (&mut Either::One(_t),) => (), | -- data moved here LL | (&mut Either::Two(_t),) => (), | -- ...and here | note: move occurs because these variables have types that don't implement the `Copy` trait - --> $DIR/simple.rs:282:27 + --> $DIR/simple.rs:280:27 | LL | (&mut Either::One(_t),) => (), | ^^ LL | (&mut Either::Two(_t),) => (), | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:290:18 +error[E0507]: cannot move out of a shared reference + --> $DIR/simple.rs:288:18 | LL | let &X(_t) = &x; - | ------ ^^ cannot move out of borrowed content + | ------ ^^ | | | | | data moved here + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the `&`: `X(_t)` - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:290:12 - | -LL | let &X(_t) = &x; - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:294:31 +error[E0507]: cannot move out of a shared reference + --> $DIR/simple.rs:292:31 | LL | if let &Either::One(_t) = &e { } - | ---------------- ^^ cannot move out of borrowed content + | ---------------- ^^ | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:294:25 - | -LL | if let &Either::One(_t) = &e { } - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:298:34 +error[E0507]: cannot move out of a shared reference + --> $DIR/simple.rs:296:34 | LL | while let &Either::One(_t) = &e { } - | ---------------- ^^ cannot move out of borrowed content + | ---------------- ^^ | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:298:28 - | -LL | while let &Either::One(_t) = &e { } - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:302:11 +error[E0507]: cannot move out of a shared reference + --> $DIR/simple.rs:300:11 | LL | match &e { - | ^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^ +LL | LL | &Either::One(_t) | ---------------- | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:304:22 - | -LL | &Either::One(_t) - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:310:11 +error[E0507]: cannot move out of a shared reference + --> $DIR/simple.rs:308:11 | LL | match &e { - | ^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^ +LL | LL | &Either::One(_t) => (), | ---------------- | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:312:22 - | -LL | &Either::One(_t) => (), - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:317:11 +error[E0507]: cannot move out of a shared reference + --> $DIR/simple.rs:315:11 | LL | match &e { - | ^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^ +LL | LL | &Either::One(_t) => (), | ---------------- | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:319:22 - | -LL | &Either::One(_t) => (), - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:325:22 +error[E0507]: cannot move out of a mutable reference + --> $DIR/simple.rs:323:22 | LL | let &mut X(_t) = &mut xm; - | ---------- ^^^^^^^ cannot move out of borrowed content + | ---------- ^^^^^^^ | | | | | data moved here + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `X(_t)` - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:325:16 - | -LL | let &mut X(_t) = &mut xm; - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:329:35 +error[E0507]: cannot move out of a mutable reference + --> $DIR/simple.rs:327:35 | LL | if let &mut Either::One(_t) = &mut em { } - | -------------------- ^^^^^^^ cannot move out of borrowed content + | -------------------- ^^^^^^^ | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:329:29 - | -LL | if let &mut Either::One(_t) = &mut em { } - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:333:38 +error[E0507]: cannot move out of a mutable reference + --> $DIR/simple.rs:331:38 | LL | while let &mut Either::One(_t) = &mut em { } - | -------------------- ^^^^^^^ cannot move out of borrowed content + | -------------------- ^^^^^^^ | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:333:32 - | -LL | while let &mut Either::One(_t) = &mut em { } - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:337:11 +error[E0507]: cannot move out of a mutable reference + --> $DIR/simple.rs:335:11 | LL | match &mut em { - | ^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^ +LL | LL | &mut Either::One(_t) | -------------------- | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:339:26 - | -LL | &mut Either::One(_t) - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:345:11 +error[E0507]: cannot move out of a mutable reference + --> $DIR/simple.rs:343:11 | LL | match &mut em { - | ^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^ +LL | LL | &mut Either::One(_t) => (), | -------------------- | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:347:26 - | -LL | &mut Either::One(_t) => (), - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:352:11 +error[E0507]: cannot move out of a mutable reference + --> $DIR/simple.rs:350:11 | LL | match &mut em { - | ^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^ +LL | LL | &mut Either::One(_t) => (), | -------------------- | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:354:26 - | -LL | &mut Either::One(_t) => (), - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:359:11 +error[E0507]: cannot move out of a mutable reference + --> $DIR/simple.rs:357:11 | LL | match &mut em { - | ^^^^^^^ cannot move out of borrowed content -LL | //~^ ERROR cannot move + | ^^^^^^^ +LL | LL | &mut Either::One(_t) => (), | -------------------- | | | | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `Either::One(_t)` - | -note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait - --> $DIR/simple.rs:361:26 - | -LL | &mut Either::One(_t) => (), - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:204:11 +error[E0507]: cannot move out of a shared reference + --> $DIR/simple.rs:202:11 | LL | fn f1(&X(_t): &X) { } | ^^^--^ | | | | | data moved here - | cannot move out of borrowed content + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the `&`: `X(_t)` - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:204:14 - | -LL | fn f1(&X(_t): &X) { } - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:251:11 +error[E0507]: cannot move out of a mutable reference + --> $DIR/simple.rs:249:11 | LL | fn f2(&mut X(_t): &mut X) { } | ^^^^^^^--^ | | | | | data moved here - | cannot move out of borrowed content + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | help: consider removing the `&mut`: `X(_t)` - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:251:18 - | -LL | fn f2(&mut X(_t): &mut X) { } - | ^^ -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:271:11 +error[E0507]: cannot move out of a shared reference + --> $DIR/simple.rs:269:11 | LL | fn f3((&X(_t),): (&X,)) { } | ^^^^--^^^ - | | | - | | data moved here - | cannot move out of borrowed content - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:271:15 - | -LL | fn f3((&X(_t),): (&X,)) { } - | ^^ + | | + | data moved here + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content - --> $DIR/simple.rs:285:11 +error[E0507]: cannot move out of a mutable reference + --> $DIR/simple.rs:283:11 | LL | fn f4((&mut X(_t),): (&mut X,)) { } | ^^^^^^^^--^^^ - | | | - | | data moved here - | cannot move out of borrowed content - | -note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait - --> $DIR/simple.rs:285:19 - | -LL | fn f4((&mut X(_t),): (&mut X,)) { } - | ^^ + | | + | data moved here + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait error: aborting due to 60 previous errors diff --git a/src/test/ui/suggestions/format-borrow.rs b/src/test/ui/suggestions/format-borrow.rs new file mode 100644 index 0000000000000..63930e7f787fd --- /dev/null +++ b/src/test/ui/suggestions/format-borrow.rs @@ -0,0 +1,6 @@ +fn main() { + let a: String = &String::from("a"); + //~^ ERROR mismatched types + let b: String = &format!("b"); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/suggestions/format-borrow.stderr b/src/test/ui/suggestions/format-borrow.stderr new file mode 100644 index 0000000000000..44bb11faa7f38 --- /dev/null +++ b/src/test/ui/suggestions/format-borrow.stderr @@ -0,0 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/format-borrow.rs:2:21 + | +LL | let a: String = &String::from("a"); + | ^^^^^^^^^^^^^^^^^^ + | | + | expected struct `std::string::String`, found reference + | help: consider removing the borrow: `String::from("a")` + | + = note: expected type `std::string::String` + found type `&std::string::String` + +error[E0308]: mismatched types + --> $DIR/format-borrow.rs:4:21 + | +LL | let b: String = &format!("b"); + | ^^^^^^^^^^^^^ + | | + | expected struct `std::string::String`, found reference + | help: consider removing the borrow: `format!("b")` + | + = note: expected type `std::string::String` + found type `&std::string::String` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs new file mode 100644 index 0000000000000..e72a2d8ccc629 --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs @@ -0,0 +1,7 @@ +trait Bar {} +impl Bar for u8 {} +fn foo() -> impl Bar { + 5; //~^ ERROR the trait bound `(): Bar` is not satisfied +} + +fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr new file mode 100644 index 0000000000000..cc3a2b9419caf --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr @@ -0,0 +1,13 @@ +error[E0277]: the trait bound `(): Bar` is not satisfied + --> $DIR/impl-trait-return-trailing-semicolon.rs:3:13 + | +LL | fn foo() -> impl Bar { + | ^^^^^^^^ the trait `Bar` is not implemented for `()` +LL | 5; + | - consider removing this semicolon + | + = note: the return type of a function must have a statically known size + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/into-str.rs b/src/test/ui/suggestions/into-str.rs new file mode 100644 index 0000000000000..9793ee801d185 --- /dev/null +++ b/src/test/ui/suggestions/into-str.rs @@ -0,0 +1,6 @@ +fn foo<'a, T>(_t: T) where T: Into<&'a str> {} + +fn main() { + foo(String::new()); + //~^ ERROR the trait bound `&str: std::convert::From` is not satisfied +} diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr new file mode 100644 index 0000000000000..3e28700ce9552 --- /dev/null +++ b/src/test/ui/suggestions/into-str.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `&str: std::convert::From` is not satisfied + --> $DIR/into-str.rs:4:5 + | +LL | foo(String::new()); + | ^^^ the trait `std::convert::From` is not implemented for `&str` + | + = note: to coerce a `std::string::String` into a `&str`, use `&*` as a prefix + = note: required because of the requirements on the impl of `std::convert::Into<&str>` for `std::string::String` +note: required by `foo` + --> $DIR/into-str.rs:1:1 + | +LL | fn foo<'a, T>(_t: T) where T: Into<&'a str> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr index 40ddb5ec53c29..f81c45e2f8da0 100644 --- a/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr +++ b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr @@ -4,7 +4,7 @@ error[E0618]: expected function, found `bool` LL | fn vindictive() -> bool { true } | -------------------------------- `vindictive` defined here returns `bool` ... -LL | vindictive() //~ ERROR expected function, found `bool` +LL | vindictive() | -^^^^^^^^^^^- help: try adding a semicolon: `;` | _____| | | diff --git a/src/test/ui/suggestions/issue-52820.rs b/src/test/ui/suggestions/issue-52820.rs new file mode 100644 index 0000000000000..075b07f565203 --- /dev/null +++ b/src/test/ui/suggestions/issue-52820.rs @@ -0,0 +1,12 @@ +struct Bravery { + guts: String, + brains: String, +} + +fn main() { + let guts = "mettle"; + let _ = Bravery { + guts, //~ ERROR mismatched types + brains: guts.clone(), //~ ERROR mismatched types + }; +} diff --git a/src/test/ui/suggestions/issue-52820.stderr b/src/test/ui/suggestions/issue-52820.stderr new file mode 100644 index 0000000000000..fb568aca250e7 --- /dev/null +++ b/src/test/ui/suggestions/issue-52820.stderr @@ -0,0 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/issue-52820.rs:9:9 + | +LL | guts, + | ^^^^ + | | + | expected struct `std::string::String`, found &str + | help: try using a conversion method: `guts: guts.to_string()` + | + = note: expected type `std::string::String` + found type `&str` + +error[E0308]: mismatched types + --> $DIR/issue-52820.rs:10:17 + | +LL | brains: guts.clone(), + | ^^^^^^^^^^^^ + | | + | expected struct `std::string::String`, found &str + | help: try using a conversion method: `guts.to_string()` + | + = note: expected type `std::string::String` + found type `&str` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/issue-57672.rs b/src/test/ui/suggestions/issue-57672.rs new file mode 100644 index 0000000000000..1773f72fc741c --- /dev/null +++ b/src/test/ui/suggestions/issue-57672.rs @@ -0,0 +1,14 @@ +// aux-build:foo.rs +// compile-flags:--extern foo +// compile-pass +// edition:2018 + +#![deny(unused_extern_crates)] + +extern crate foo as foo_renamed; + +pub mod m { + pub use foo_renamed::Foo; +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-59819.fixed b/src/test/ui/suggestions/issue-59819.fixed new file mode 100644 index 0000000000000..644d2a4e41baf --- /dev/null +++ b/src/test/ui/suggestions/issue-59819.fixed @@ -0,0 +1,35 @@ +// run-rustfix + +#![allow(warnings)] + +// Test that suggestion to add `*` characters applies to implementations of `Deref` as well as +// references. + +struct Foo(i32); + +struct Bar(String); + +impl std::ops::Deref for Foo { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::ops::Deref for Bar { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn main() { + let x = Foo(42); + let y: i32 = *x; //~ ERROR mismatched types + let a = &42; + let b: i32 = *a; //~ ERROR mismatched types + + // Do not make a suggestion when adding a `*` wouldn't actually fix the issue: + let f = Bar("bar".to_string()); + let g: String = f.to_string(); //~ ERROR mismatched types +} diff --git a/src/test/ui/suggestions/issue-59819.rs b/src/test/ui/suggestions/issue-59819.rs new file mode 100644 index 0000000000000..8e8ff8372e808 --- /dev/null +++ b/src/test/ui/suggestions/issue-59819.rs @@ -0,0 +1,35 @@ +// run-rustfix + +#![allow(warnings)] + +// Test that suggestion to add `*` characters applies to implementations of `Deref` as well as +// references. + +struct Foo(i32); + +struct Bar(String); + +impl std::ops::Deref for Foo { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::ops::Deref for Bar { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn main() { + let x = Foo(42); + let y: i32 = x; //~ ERROR mismatched types + let a = &42; + let b: i32 = a; //~ ERROR mismatched types + + // Do not make a suggestion when adding a `*` wouldn't actually fix the issue: + let f = Bar("bar".to_string()); + let g: String = f; //~ ERROR mismatched types +} diff --git a/src/test/ui/suggestions/issue-59819.stderr b/src/test/ui/suggestions/issue-59819.stderr new file mode 100644 index 0000000000000..66898115cbd6d --- /dev/null +++ b/src/test/ui/suggestions/issue-59819.stderr @@ -0,0 +1,39 @@ +error[E0308]: mismatched types + --> $DIR/issue-59819.rs:28:18 + | +LL | let y: i32 = x; + | ^ + | | + | expected i32, found struct `Foo` + | help: consider dereferencing the type: `*x` + | + = note: expected type `i32` + found type `Foo` + +error[E0308]: mismatched types + --> $DIR/issue-59819.rs:30:18 + | +LL | let b: i32 = a; + | ^ + | | + | expected i32, found &{integer} + | help: consider dereferencing the borrow: `*a` + | + = note: expected type `i32` + found type `&{integer}` + +error[E0308]: mismatched types + --> $DIR/issue-59819.rs:34:21 + | +LL | let g: String = f; + | ^ + | | + | expected struct `std::string::String`, found struct `Bar` + | help: try using a conversion method: `f.to_string()` + | + = note: expected type `std::string::String` + found type `Bar` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/match-ergonomics.rs b/src/test/ui/suggestions/match-ergonomics.rs new file mode 100644 index 0000000000000..c4fc01469bf65 --- /dev/null +++ b/src/test/ui/suggestions/match-ergonomics.rs @@ -0,0 +1,41 @@ +fn main() { + let x = vec![1i32]; + match &x[..] { + [&v] => {}, //~ ERROR mismatched types + _ => {}, + } + match x { + [&v] => {}, //~ ERROR expected an array or slice + _ => {}, + } + match &x[..] { + [v] => {}, + _ => {}, + } + match &x[..] { + &[v] => {}, + _ => {}, + } + match x { + [v] => {}, //~ ERROR expected an array or slice + _ => {}, + } + let y = 1i32; + match &y { + &v => {}, + _ => {}, + } + match y { + &v => {}, //~ ERROR mismatched types + _ => {}, + } + match &y { + v => {}, + _ => {}, + } + match y { + v => {}, + _ => {}, + } + if let [&v] = &x[..] {} //~ ERROR mismatched types +} diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr new file mode 100644 index 0000000000000..b7497be6ceb36 --- /dev/null +++ b/src/test/ui/suggestions/match-ergonomics.stderr @@ -0,0 +1,52 @@ +error[E0308]: mismatched types + --> $DIR/match-ergonomics.rs:4:10 + | +LL | [&v] => {}, + | ^^ + | | + | expected i32, found reference + | help: you can probably remove the explicit borrow: `v` + | + = note: expected type `i32` + found type `&_` + +error[E0529]: expected an array or slice, found `std::vec::Vec` + --> $DIR/match-ergonomics.rs:8:9 + | +LL | [&v] => {}, + | ^^^^ pattern cannot match with input type `std::vec::Vec` + +error[E0529]: expected an array or slice, found `std::vec::Vec` + --> $DIR/match-ergonomics.rs:20:9 + | +LL | [v] => {}, + | ^^^ pattern cannot match with input type `std::vec::Vec` + +error[E0308]: mismatched types + --> $DIR/match-ergonomics.rs:29:9 + | +LL | &v => {}, + | ^^ + | | + | expected i32, found reference + | help: you can probably remove the explicit borrow: `v` + | + = note: expected type `i32` + found type `&_` + +error[E0308]: mismatched types + --> $DIR/match-ergonomics.rs:40:13 + | +LL | if let [&v] = &x[..] {} + | ^^ + | | + | expected i32, found reference + | help: you can probably remove the explicit borrow: `v` + | + = note: expected type `i32` + found type `&_` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0308, E0529. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/mut-ref-reassignment.rs b/src/test/ui/suggestions/mut-ref-reassignment.rs new file mode 100644 index 0000000000000..1428324934de2 --- /dev/null +++ b/src/test/ui/suggestions/mut-ref-reassignment.rs @@ -0,0 +1,17 @@ +fn suggestion(opt: &mut Option) { + opt = None; //~ ERROR mismatched types +} + +fn no_suggestion(opt: &mut Result) { + opt = None //~ ERROR mismatched types +} + +fn suggestion2(opt: &mut Option) { + opt = Some(String::new())//~ ERROR mismatched types +} + +fn no_suggestion2(opt: &mut Option) { + opt = Some(42)//~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/suggestions/mut-ref-reassignment.stderr b/src/test/ui/suggestions/mut-ref-reassignment.stderr new file mode 100644 index 0000000000000..66b78a1b14015 --- /dev/null +++ b/src/test/ui/suggestions/mut-ref-reassignment.stderr @@ -0,0 +1,47 @@ +error[E0308]: mismatched types + --> $DIR/mut-ref-reassignment.rs:2:11 + | +LL | opt = None; + | ^^^^ expected mutable reference, found enum `std::option::Option` + | + = note: expected type `&mut std::option::Option` + found type `std::option::Option<_>` +help: consider dereferencing here to assign to the mutable borrowed piece of memory + | +LL | *opt = None; + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/mut-ref-reassignment.rs:6:11 + | +LL | opt = None + | ^^^^ expected mutable reference, found enum `std::option::Option` + | + = note: expected type `&mut std::result::Result` + found type `std::option::Option<_>` + +error[E0308]: mismatched types + --> $DIR/mut-ref-reassignment.rs:10:11 + | +LL | opt = Some(String::new()) + | ^^^^^^^^^^^^^^^^^^^ expected mutable reference, found enum `std::option::Option` + | + = note: expected type `&mut std::option::Option` + found type `std::option::Option` +help: consider dereferencing here to assign to the mutable borrowed piece of memory + | +LL | *opt = Some(String::new()) + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/mut-ref-reassignment.rs:14:11 + | +LL | opt = Some(42) + | ^^^^^^^^ expected mutable reference, found enum `std::option::Option` + | + = note: expected type `&mut std::option::Option` + found type `std::option::Option<{integer}>` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/no-extern-crate-in-type.rs b/src/test/ui/suggestions/no-extern-crate-in-type.rs new file mode 100644 index 0000000000000..bb93ef4549dc2 --- /dev/null +++ b/src/test/ui/suggestions/no-extern-crate-in-type.rs @@ -0,0 +1,7 @@ +// aux-build:foo.rs + +extern crate foo; + +type Output = Option; //~ ERROR cannot find type `Foo` + +fn main() {} diff --git a/src/test/ui/suggestions/no-extern-crate-in-type.stderr b/src/test/ui/suggestions/no-extern-crate-in-type.stderr new file mode 100644 index 0000000000000..d4a5a956714c9 --- /dev/null +++ b/src/test/ui/suggestions/no-extern-crate-in-type.stderr @@ -0,0 +1,13 @@ +error[E0412]: cannot find type `Foo` in this scope + --> $DIR/no-extern-crate-in-type.rs:5:22 + | +LL | type Output = Option; + | ^^^ not found in this scope +help: possible candidate is found in another module, you can import it into scope + | +LL | use foo::Foo; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/suggestions/option-content-move.fixed b/src/test/ui/suggestions/option-content-move.fixed new file mode 100644 index 0000000000000..ba16bcc8a336d --- /dev/null +++ b/src/test/ui/suggestions/option-content-move.fixed @@ -0,0 +1,39 @@ +//run-rustfix + +pub struct LipogramCorpora { + selections: Vec<(char, Option)>, +} + +impl LipogramCorpora { + pub fn validate_all(&mut self) -> Result<(), char> { + for selection in &self.selections { + if selection.1.is_some() { + if selection.1.as_ref().unwrap().contains(selection.0) { + //~^ ERROR cannot move out of `selection.1` + return Err(selection.0); + } + } + } + Ok(()) + } +} + +pub struct LipogramCorpora2 { + selections: Vec<(char, Result)>, +} + +impl LipogramCorpora2 { + pub fn validate_all(&mut self) -> Result<(), char> { + for selection in &self.selections { + if selection.1.is_ok() { + if selection.1.as_ref().unwrap().contains(selection.0) { + //~^ ERROR cannot move out of `selection.1` + return Err(selection.0); + } + } + } + Ok(()) + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/option-content-move.rs b/src/test/ui/suggestions/option-content-move.rs new file mode 100644 index 0000000000000..ef38f114eca55 --- /dev/null +++ b/src/test/ui/suggestions/option-content-move.rs @@ -0,0 +1,39 @@ +//run-rustfix + +pub struct LipogramCorpora { + selections: Vec<(char, Option)>, +} + +impl LipogramCorpora { + pub fn validate_all(&mut self) -> Result<(), char> { + for selection in &self.selections { + if selection.1.is_some() { + if selection.1.unwrap().contains(selection.0) { + //~^ ERROR cannot move out of `selection.1` + return Err(selection.0); + } + } + } + Ok(()) + } +} + +pub struct LipogramCorpora2 { + selections: Vec<(char, Result)>, +} + +impl LipogramCorpora2 { + pub fn validate_all(&mut self) -> Result<(), char> { + for selection in &self.selections { + if selection.1.is_ok() { + if selection.1.unwrap().contains(selection.0) { + //~^ ERROR cannot move out of `selection.1` + return Err(selection.0); + } + } + } + Ok(()) + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/option-content-move.stderr b/src/test/ui/suggestions/option-content-move.stderr new file mode 100644 index 0000000000000..c842e7b2930bd --- /dev/null +++ b/src/test/ui/suggestions/option-content-move.stderr @@ -0,0 +1,21 @@ +error[E0507]: cannot move out of `selection.1` which is behind a shared reference + --> $DIR/option-content-move.rs:11:20 + | +LL | if selection.1.unwrap().contains(selection.0) { + | ^^^^^^^^^^^ + | | + | move occurs because `selection.1` has type `std::option::Option`, which does not implement the `Copy` trait + | help: consider borrowing the `Option`'s content: `selection.1.as_ref()` + +error[E0507]: cannot move out of `selection.1` which is behind a shared reference + --> $DIR/option-content-move.rs:29:20 + | +LL | if selection.1.unwrap().contains(selection.0) { + | ^^^^^^^^^^^ + | | + | move occurs because `selection.1` has type `std::result::Result`, which does not implement the `Copy` trait + | help: consider borrowing the `Result`'s content: `selection.1.as_ref()` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/suggestions/recover-invalid-float.fixed b/src/test/ui/suggestions/recover-invalid-float.fixed new file mode 100644 index 0000000000000..62389ba612083 --- /dev/null +++ b/src/test/ui/suggestions/recover-invalid-float.fixed @@ -0,0 +1,10 @@ +// run-rustfix + +fn main() { + let _: f32 = 0.3; + //~^ ERROR float literals must have an integer part + let _: f32 = 0.42f32; + //~^ ERROR float literals must have an integer part + let _: f64 = 0.5f64; + //~^ ERROR float literals must have an integer part +} diff --git a/src/test/ui/suggestions/recover-invalid-float.rs b/src/test/ui/suggestions/recover-invalid-float.rs index 506ef8900b881..a5a7efe5e76e8 100644 --- a/src/test/ui/suggestions/recover-invalid-float.rs +++ b/src/test/ui/suggestions/recover-invalid-float.rs @@ -1,11 +1,10 @@ +// run-rustfix + fn main() { - let _: usize = .3; + let _: f32 = .3; //~^ ERROR float literals must have an integer part - //~| ERROR mismatched types - let _: usize = .42f32; + let _: f32 = .42f32; //~^ ERROR float literals must have an integer part - //~| ERROR mismatched types - let _: usize = .5f64; + let _: f64 = .5f64; //~^ ERROR float literals must have an integer part - //~| ERROR mismatched types } diff --git a/src/test/ui/suggestions/recover-invalid-float.stderr b/src/test/ui/suggestions/recover-invalid-float.stderr index c464676b444cc..dd24746eab80f 100644 --- a/src/test/ui/suggestions/recover-invalid-float.stderr +++ b/src/test/ui/suggestions/recover-invalid-float.stderr @@ -1,42 +1,20 @@ error: float literals must have an integer part - --> $DIR/recover-invalid-float.rs:2:20 + --> $DIR/recover-invalid-float.rs:4:18 | -LL | let _: usize = .3; - | ^^ help: must have an integer part: `0.3` +LL | let _: f32 = .3; + | ^^ help: must have an integer part: `0.3` error: float literals must have an integer part - --> $DIR/recover-invalid-float.rs:5:20 + --> $DIR/recover-invalid-float.rs:6:18 | -LL | let _: usize = .42f32; - | ^^^^^^ help: must have an integer part: `0.42f32` +LL | let _: f32 = .42f32; + | ^^^^^^ help: must have an integer part: `0.42f32` error: float literals must have an integer part - --> $DIR/recover-invalid-float.rs:8:20 + --> $DIR/recover-invalid-float.rs:8:18 | -LL | let _: usize = .5f64; - | ^^^^^ help: must have an integer part: `0.5f64` +LL | let _: f64 = .5f64; + | ^^^^^ help: must have an integer part: `0.5f64` -error[E0308]: mismatched types - --> $DIR/recover-invalid-float.rs:2:20 - | -LL | let _: usize = .3; - | ^^ expected usize, found floating-point number - | - = note: expected type `usize` - found type `{float}` - -error[E0308]: mismatched types - --> $DIR/recover-invalid-float.rs:5:20 - | -LL | let _: usize = .42f32; - | ^^^^^^ expected usize, found f32 - -error[E0308]: mismatched types - --> $DIR/recover-invalid-float.rs:8:20 - | -LL | let _: usize = .5f64; - | ^^^^^ expected usize, found f64 - -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/return-without-lifetime.rs b/src/test/ui/suggestions/return-without-lifetime.rs new file mode 100644 index 0000000000000..9bfce11be9ea3 --- /dev/null +++ b/src/test/ui/suggestions/return-without-lifetime.rs @@ -0,0 +1,10 @@ +struct Thing<'a>(&'a ()); +struct Foo<'a>(&usize); +//~^ ERROR missing lifetime specifier + +fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } +//~^ ERROR missing lifetime specifier +fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } +//~^ ERROR missing lifetime specifier + +fn main() {} diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr new file mode 100644 index 0000000000000..7f5ff95938e30 --- /dev/null +++ b/src/test/ui/suggestions/return-without-lifetime.stderr @@ -0,0 +1,25 @@ +error[E0106]: missing lifetime specifier + --> $DIR/return-without-lifetime.rs:2:16 + | +LL | struct Foo<'a>(&usize); + | ^ help: consider using the named lifetime: `&'a` + +error[E0106]: missing lifetime specifier + --> $DIR/return-without-lifetime.rs:5:34 + | +LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } + | ^ help: consider using the named lifetime: `&'a` + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from + +error[E0106]: missing lifetime specifier + --> $DIR/return-without-lifetime.rs:7:35 + | +LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } + | ^ help: consider using the named lifetime: `&'a` + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr b/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr new file mode 100644 index 0000000000000..f4eb9813c1ac7 --- /dev/null +++ b/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr @@ -0,0 +1,11 @@ +error[E0310]: the parameter type `impl Debug` may not live long enough + --> $DIR/suggest-impl-trait-lifetime.rs:7:5 + | +LL | bar(d); + | ^^^^^^ + | + = help: consider adding an explicit lifetime bound `impl Debug: 'static`... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/suggestions/suggest-labels.stderr b/src/test/ui/suggestions/suggest-labels.stderr index 88a0f9698877f..02d46a3f59607 100644 --- a/src/test/ui/suggestions/suggest-labels.stderr +++ b/src/test/ui/suggestions/suggest-labels.stderr @@ -1,20 +1,32 @@ error[E0426]: use of undeclared label `'fo` --> $DIR/suggest-labels.rs:4:15 | -LL | break 'fo; //~ ERROR use of undeclared label - | ^^^ did you mean `'foo`? +LL | break 'fo; + | ^^^ +help: a label with a similar name exists in this scope + | +LL | break 'foo; + | ^^^^ error[E0426]: use of undeclared label `'bor` --> $DIR/suggest-labels.rs:8:18 | -LL | continue 'bor; //~ ERROR use of undeclared label - | ^^^^ did you mean `'bar`? +LL | continue 'bor; + | ^^^^ +help: a label with a similar name exists in this scope + | +LL | continue 'bar; + | ^^^^ error[E0426]: use of undeclared label `'longlable` --> $DIR/suggest-labels.rs:13:19 | -LL | break 'longlable; //~ ERROR use of undeclared label - | ^^^^^^^^^^ did you mean `'longlabel1`? +LL | break 'longlable; + | ^^^^^^^^^^ +help: a label with a similar name exists in this scope + | +LL | break 'longlabel1; + | ^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/suggestions/suggest-methods.stderr b/src/test/ui/suggestions/suggest-methods.stderr index b7727cf03a4e7..ad4a4deb5a886 100644 --- a/src/test/ui/suggestions/suggest-methods.stderr +++ b/src/test/ui/suggestions/suggest-methods.stderr @@ -4,25 +4,25 @@ error[E0599]: no method named `bat` found for type `Foo` in the current scope LL | struct Foo; | ----------- method `bat` not found for this ... -LL | f.bat(1.0); //~ ERROR no method named - | ^^^ help: did you mean: `bar` +LL | f.bat(1.0); + | ^^^ help: there is a method with a similar name: `bar` error[E0599]: no method named `is_emtpy` found for type `std::string::String` in the current scope --> $DIR/suggest-methods.rs:21:15 | -LL | let _ = s.is_emtpy(); //~ ERROR no method named - | ^^^^^^^^ help: did you mean: `is_empty` +LL | let _ = s.is_emtpy(); + | ^^^^^^^^ help: there is a method with a similar name: `is_empty` error[E0599]: no method named `count_eos` found for type `u32` in the current scope --> $DIR/suggest-methods.rs:25:19 | -LL | let _ = 63u32.count_eos(); //~ ERROR no method named - | ^^^^^^^^^ help: did you mean: `count_zeros` +LL | let _ = 63u32.count_eos(); + | ^^^^^^^^^ help: there is a method with a similar name: `count_zeros` error[E0599]: no method named `count_o` found for type `u32` in the current scope --> $DIR/suggest-methods.rs:28:19 | -LL | let _ = 63u32.count_o(); //~ ERROR no method named +LL | let _ = 63u32.count_o(); | ^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/suggest-move-lifetimes.stderr b/src/test/ui/suggestions/suggest-move-lifetimes.stderr index 2d6dee0621662..1851c8deaa8b4 100644 --- a/src/test/ui/suggestions/suggest-move-lifetimes.stderr +++ b/src/test/ui/suggestions/suggest-move-lifetimes.stderr @@ -1,26 +1,26 @@ error: lifetime parameters must be declared prior to type parameters --> $DIR/suggest-move-lifetimes.rs:1:13 | -LL | struct A { //~ ERROR lifetime parameters must be declared - | ----^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T>` +LL | struct A { + | ----^^- help: reorder the parameters: lifetimes, then types: `<'a, T>` error: lifetime parameters must be declared prior to type parameters --> $DIR/suggest-move-lifetimes.rs:5:13 | -LL | struct B { //~ ERROR lifetime parameters must be declared - | ----^^---- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, U>` +LL | struct B { + | ----^^---- help: reorder the parameters: lifetimes, then types: `<'a, T, U>` error: lifetime parameters must be declared prior to type parameters --> $DIR/suggest-move-lifetimes.rs:10:16 | -LL | struct C { //~ ERROR lifetime parameters must be declared - | -------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, U>` +LL | struct C { + | -------^^- help: reorder the parameters: lifetimes, then types: `<'a, T, U>` error: lifetime parameters must be declared prior to type parameters --> $DIR/suggest-move-lifetimes.rs:15:16 | -LL | struct D { //~ ERROR lifetime parameters must be declared - | -------^^--^^-----^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, 'c, T, U, V>` +LL | struct D { + | -------^^--^^-----^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, 'c, T, U, V>` error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr index 0901b71911d43..552fb78cd3fdd 100644 --- a/src/test/ui/suggestions/suggest-move-types.stderr +++ b/src/test/ui/suggestions/suggest-move-types.stderr @@ -1,7 +1,7 @@ error: associated type bindings must be declared after generic parameters --> $DIR/suggest-move-types.rs:28:20 | -LL | struct A> { //~ ERROR associated type bindings must be declared after generic parameters +LL | struct A> { | ----^^^ | | | this associated type binding should be moved after the generic parameters @@ -17,7 +17,7 @@ LL | struct Al<'a, T, M: OneWithLifetime> { error: associated type bindings must be declared after generic parameters --> $DIR/suggest-move-types.rs:41:28 | -LL | struct B> { //~ ERROR associated type bindings must be declared after generic parameters +LL | struct B> { | ----^^----^^----^^^^^^^^^ | | | | | | | this associated type binding should be moved after the generic parameters @@ -37,7 +37,7 @@ LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime $DIR/suggest-move-types.rs:57:28 | -LL | struct C> { //~ ERROR associated type bindings must be declared after generic parameters +LL | struct C> { | ^^^----^^----^^----^^^^^^ | | | | | | | this associated type binding should be moved after the generic parameters @@ -57,7 +57,7 @@ LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime $DIR/suggest-move-types.rs:73:28 | -LL | struct D> { //~ ERROR associated type bindings must be declared after generic parameters +LL | struct D> { | ^^^----^^----^^^^^----^^^ | | | | | | | this associated type binding should be moved after the generic parameters diff --git a/src/test/ui/suggestions/suggest-on-bare-closure-call.rs b/src/test/ui/suggestions/suggest-on-bare-closure-call.rs new file mode 100644 index 0000000000000..355708c08ec2f --- /dev/null +++ b/src/test/ui/suggestions/suggest-on-bare-closure-call.rs @@ -0,0 +1,4 @@ +fn main() { + let _ = ||{}(); + //~^ ERROR expected function, found `()` +} diff --git a/src/test/ui/suggestions/suggest-on-bare-closure-call.stderr b/src/test/ui/suggestions/suggest-on-bare-closure-call.stderr new file mode 100644 index 0000000000000..17001e3974c6d --- /dev/null +++ b/src/test/ui/suggestions/suggest-on-bare-closure-call.stderr @@ -0,0 +1,15 @@ +error[E0618]: expected function, found `()` + --> $DIR/suggest-on-bare-closure-call.rs:2:15 + | +LL | let _ = ||{}(); + | ^^-- + | | + | call expression requires function +help: if you meant to create this closure and immediately call it, surround the closure with parenthesis + | +LL | let _ = (||{})(); + | ^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0618`. diff --git a/src/test/ui/suggestions/suggest-ref-mut.rs b/src/test/ui/suggestions/suggest-ref-mut.rs index b4a6fa39f9052..d04113ffccc3a 100644 --- a/src/test/ui/suggestions/suggest-ref-mut.rs +++ b/src/test/ui/suggestions/suggest-ref-mut.rs @@ -1,5 +1,3 @@ -#![feature(nll)] - struct X(usize); impl X { diff --git a/src/test/ui/suggestions/suggest-ref-mut.stderr b/src/test/ui/suggestions/suggest-ref-mut.stderr index 9f00967d84089..2414367875718 100644 --- a/src/test/ui/suggestions/suggest-ref-mut.stderr +++ b/src/test/ui/suggestions/suggest-ref-mut.stderr @@ -1,5 +1,5 @@ error[E0594]: cannot assign to `self.0` which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:9:9 + --> $DIR/suggest-ref-mut.rs:7:9 | LL | fn zap(&self) { | ----- help: consider changing this to be a mutable reference: `&mut self` @@ -8,7 +8,7 @@ LL | self.0 = 32; | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*foo` which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:18:5 + --> $DIR/suggest-ref-mut.rs:16:5 | LL | let ref foo = 16; | ------- help: consider changing this to be a mutable reference: `ref mut foo` @@ -17,7 +17,7 @@ LL | *foo = 32; | ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*bar` which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:23:9 + --> $DIR/suggest-ref-mut.rs:21:9 | LL | if let Some(ref bar) = Some(16) { | ------- help: consider changing this to be a mutable reference: `ref mut bar` @@ -26,7 +26,7 @@ LL | *bar = 32; | ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*quo` which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:27:22 + --> $DIR/suggest-ref-mut.rs:25:22 | LL | ref quo => { *quo = 32; }, | ------- ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written @@ -35,4 +35,3 @@ LL | ref quo => { *quo = 32; }, error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/suggestions/suggest-std-when-using-type.rs b/src/test/ui/suggestions/suggest-std-when-using-type.rs new file mode 100644 index 0000000000000..9ca68a635da96 --- /dev/null +++ b/src/test/ui/suggestions/suggest-std-when-using-type.rs @@ -0,0 +1,7 @@ +fn main() { + let pi = f32::consts::PI; //~ ERROR ambiguous associated type + let bytes = "hello world".as_bytes(); + let string = unsafe { + str::from_utf8(bytes) //~ ERROR no function or associated item named `from_utf8` found + }; +} diff --git a/src/test/ui/suggestions/suggest-std-when-using-type.stderr b/src/test/ui/suggestions/suggest-std-when-using-type.stderr new file mode 100644 index 0000000000000..eecb4e60f9d59 --- /dev/null +++ b/src/test/ui/suggestions/suggest-std-when-using-type.stderr @@ -0,0 +1,24 @@ +error[E0223]: ambiguous associated type + --> $DIR/suggest-std-when-using-type.rs:2:14 + | +LL | let pi = f32::consts::PI; + | ^^^^^^^^^^^^^^^ +help: you are looking for the module in `std`, not the primitive type + | +LL | let pi = std::f32::consts::PI; + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0599]: no function or associated item named `from_utf8` found for type `str` in the current scope + --> $DIR/suggest-std-when-using-type.rs:5:14 + | +LL | str::from_utf8(bytes) + | ^^^^^^^^^ function or associated item not found in `str` +help: you are looking for the module in `std`, not the primitive type + | +LL | std::str::from_utf8(bytes) + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0223, E0599. +For more information about an error, try `rustc --explain E0223`. diff --git a/src/test/ui/suggestions/suggest-variants.rs b/src/test/ui/suggestions/suggest-variants.rs index 6d6e280d9652f..d418834432e08 100644 --- a/src/test/ui/suggestions/suggest-variants.rs +++ b/src/test/ui/suggestions/suggest-variants.rs @@ -12,4 +12,7 @@ fn main() { println!("My shape is {:?}", Shape::Squareee { size: 5}); //~ ERROR no variant `Squareee` println!("My shape is {:?}", Shape::Circl { size: 5}); //~ ERROR no variant `Circl` println!("My shape is {:?}", Shape::Rombus{ size: 5}); //~ ERROR no variant `Rombus` + Shape::Squareee; //~ ERROR no variant + Shape::Circl; //~ ERROR no variant + Shape::Rombus; //~ ERROR no variant } diff --git a/src/test/ui/suggestions/suggest-variants.stderr b/src/test/ui/suggestions/suggest-variants.stderr index 36abda2a89bb8..ef0ba70c34066 100644 --- a/src/test/ui/suggestions/suggest-variants.stderr +++ b/src/test/ui/suggestions/suggest-variants.stderr @@ -1,20 +1,65 @@ -error: no variant `Squareee` on enum `Shape` - --> $DIR/suggest-variants.rs:12:34 +error: no variant `Squareee` in enum `Shape` + --> $DIR/suggest-variants.rs:12:41 | -LL | println!("My shape is {:?}", Shape::Squareee { size: 5}); //~ ERROR no variant `Squareee` - | ^^^^^^^^^^^^^^^ help: did you mean: `Shape::Square` +LL | enum Shape { + | ---------- variant `Squareee` not found here +... +LL | println!("My shape is {:?}", Shape::Squareee { size: 5}); + | ^^^^^^^^ help: there is a variant with a similar name: `Square` -error: no variant `Circl` on enum `Shape` - --> $DIR/suggest-variants.rs:13:34 +error: no variant `Circl` in enum `Shape` + --> $DIR/suggest-variants.rs:13:41 | -LL | println!("My shape is {:?}", Shape::Circl { size: 5}); //~ ERROR no variant `Circl` - | ^^^^^^^^^^^^ help: did you mean: `Shape::Circle` +LL | enum Shape { + | ---------- variant `Circl` not found here +... +LL | println!("My shape is {:?}", Shape::Circl { size: 5}); + | ^^^^^ help: there is a variant with a similar name: `Circle` -error: no variant `Rombus` on enum `Shape` - --> $DIR/suggest-variants.rs:14:34 +error: no variant `Rombus` in enum `Shape` + --> $DIR/suggest-variants.rs:14:41 | -LL | println!("My shape is {:?}", Shape::Rombus{ size: 5}); //~ ERROR no variant `Rombus` - | ^^^^^^^^^^^^^ unknown variant +LL | enum Shape { + | ---------- variant `Rombus` not found here +... +LL | println!("My shape is {:?}", Shape::Rombus{ size: 5}); + | -------^^^^^^ + | | + | variant not found in `Shape` -error: aborting due to 3 previous errors +error[E0599]: no variant or associated item named `Squareee` found for type `Shape` in the current scope + --> $DIR/suggest-variants.rs:15:12 + | +LL | enum Shape { + | ---------- variant or associated item `Squareee` not found here +... +LL | Shape::Squareee; + | ^^^^^^^^ + | | + | variant or associated item not found in `Shape` + | help: there is a variant with a similar name: `Square` + +error[E0599]: no variant or associated item named `Circl` found for type `Shape` in the current scope + --> $DIR/suggest-variants.rs:16:12 + | +LL | enum Shape { + | ---------- variant or associated item `Circl` not found here +... +LL | Shape::Circl; + | ^^^^^ + | | + | variant or associated item not found in `Shape` + | help: there is a variant with a similar name: `Circle` + +error[E0599]: no variant or associated item named `Rombus` found for type `Shape` in the current scope + --> $DIR/suggest-variants.rs:17:12 + | +LL | enum Shape { + | ---------- variant or associated item `Rombus` not found here +... +LL | Shape::Rombus; + | ^^^^^^ variant or associated item not found in `Shape` + +error: aborting due to 6 previous errors +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/suggestions/type-ascription-instead-of-let.rs b/src/test/ui/suggestions/type-ascription-instead-of-let.rs new file mode 100644 index 0000000000000..0e1c307502728 --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-let.rs @@ -0,0 +1,10 @@ +fn fun(x: i32) -> i32 { x } + +fn main() { + let closure_annotated = |value: i32| -> i32 { + temp: i32 = fun(5i32); + //~^ ERROR cannot find value `temp` in this scope + temp + value + 1 + //~^ ERROR cannot find value `temp` in this scope + }; +} diff --git a/src/test/ui/suggestions/type-ascription-instead-of-let.stderr b/src/test/ui/suggestions/type-ascription-instead-of-let.stderr new file mode 100644 index 0000000000000..92e4b5798c889 --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-let.stderr @@ -0,0 +1,18 @@ +error[E0425]: cannot find value `temp` in this scope + --> $DIR/type-ascription-instead-of-let.rs:5:9 + | +LL | temp: i32 = fun(5i32); + | ^^^^ + | | + | not found in this scope + | help: maybe you meant to write an assignment here: `let temp` + +error[E0425]: cannot find value `temp` in this scope + --> $DIR/type-ascription-instead-of-let.rs:7:9 + | +LL | temp + value + 1 + | ^^^^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/suggestions/type-ascription-instead-of-method.rs b/src/test/ui/suggestions/type-ascription-instead-of-method.rs new file mode 100644 index 0000000000000..361729d50c2f3 --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-method.rs @@ -0,0 +1,4 @@ +fn main() { + Box:new("foo".to_string()) + //~^ ERROR expected type, found +} diff --git a/src/test/ui/suggestions/type-ascription-instead-of-method.stderr b/src/test/ui/suggestions/type-ascription-instead-of-method.stderr new file mode 100644 index 0000000000000..15ec087b1cc01 --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-method.stderr @@ -0,0 +1,10 @@ +error: expected type, found `"foo"` + --> $DIR/type-ascription-instead-of-method.rs:2:13 + | +LL | Box:new("foo".to_string()) + | - ^^^^^ expecting a type here because of type ascription + | | + | help: maybe you meant to write a path separator here: `::` + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path.rs b/src/test/ui/suggestions/type-ascription-instead-of-path.rs new file mode 100644 index 0000000000000..4c0fe6d8b5b4e --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-path.rs @@ -0,0 +1,5 @@ +fn main() { + std:io::stdin(); + //~^ ERROR failed to resolve: use of undeclared type or module `io` + //~| ERROR expected value, found module +} diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path.stderr b/src/test/ui/suggestions/type-ascription-instead-of-path.stderr new file mode 100644 index 0000000000000..0f9b31fb52b4f --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-path.stderr @@ -0,0 +1,18 @@ +error[E0433]: failed to resolve: use of undeclared type or module `io` + --> $DIR/type-ascription-instead-of-path.rs:2:9 + | +LL | std:io::stdin(); + | ^^ use of undeclared type or module `io` + +error[E0423]: expected value, found module `std` + --> $DIR/type-ascription-instead-of-path.rs:2:5 + | +LL | std:io::stdin(); + | ^^^- help: maybe you meant to write a path separator here: `::` + | | + | not a value + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0423, E0433. +For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/suggestions/type-ascription-instead-of-variant.rs b/src/test/ui/suggestions/type-ascription-instead-of-variant.rs new file mode 100644 index 0000000000000..b90867fef6b51 --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-variant.rs @@ -0,0 +1,4 @@ +fn main() { + let _ = Option:Some(""); + //~^ ERROR expected type, found +} diff --git a/src/test/ui/suggestions/type-ascription-instead-of-variant.stderr b/src/test/ui/suggestions/type-ascription-instead-of-variant.stderr new file mode 100644 index 0000000000000..5719a667a8415 --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-variant.stderr @@ -0,0 +1,10 @@ +error: expected type, found `""` + --> $DIR/type-ascription-instead-of-variant.rs:2:25 + | +LL | let _ = Option:Some(""); + | - ^^ expecting a type here because of type ascription + | | + | help: maybe you meant to write a path separator here: `::` + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr index d0f9e1f7f7c8e..a25c644680ee0 100644 --- a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr +++ b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr @@ -2,21 +2,19 @@ error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:19 | LL | let _ = RGB { r, g, c }; - | ^ expected f64, found f32 -help: you can cast an `f32` to `f64` in a lossless way - | -LL | let _ = RGB { r: r.into(), g, c }; - | ^^^^^^^^^^^ + | ^ + | | + | expected f64, found f32 + | help: you can convert an `f32` to `f64`: `r: r.into()` error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:22 | LL | let _ = RGB { r, g, c }; - | ^ expected f64, found f32 -help: you can cast an `f32` to `f64` in a lossless way - | -LL | let _ = RGB { r, g: g.into(), c }; - | ^^^^^^^^^^^ + | ^ + | | + | expected f64, found f32 + | help: you can convert an `f32` to `f64`: `g: g.into()` error[E0560]: struct `RGB` has no field named `c` --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:25 @@ -26,5 +24,5 @@ LL | let _ = RGB { r, g, c }; error: aborting due to 3 previous errors -Some errors occurred: E0308, E0560. +Some errors have detailed explanations: E0308, E0560. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr index 6bc16ba8b70fa..ed8013d5997e4 100644 --- a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr +++ b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr @@ -2,31 +2,28 @@ error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand.rs:8:19 | LL | let _ = RGB { r, g, b }; - | ^ expected f64, found f32 -help: you can cast an `f32` to `f64` in a lossless way - | -LL | let _ = RGB { r: r.into(), g, b }; - | ^^^^^^^^^^^ + | ^ + | | + | expected f64, found f32 + | help: you can convert an `f32` to `f64`: `r: r.into()` error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand.rs:8:22 | LL | let _ = RGB { r, g, b }; - | ^ expected f64, found f32 -help: you can cast an `f32` to `f64` in a lossless way - | -LL | let _ = RGB { r, g: g.into(), b }; - | ^^^^^^^^^^^ + | ^ + | | + | expected f64, found f32 + | help: you can convert an `f32` to `f64`: `g: g.into()` error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand.rs:8:25 | LL | let _ = RGB { r, g, b }; - | ^ expected f64, found f32 -help: you can cast an `f32` to `f64` in a lossless way - | -LL | let _ = RGB { r, g, b: b.into() }; - | ^^^^^^^^^^^ + | ^ + | | + | expected f64, found f32 + | help: you can convert an `f32` to `f64`: `b: b.into()` error: aborting due to 3 previous errors diff --git a/src/test/ui/suggestions/unused-closure-argument.rs b/src/test/ui/suggestions/unused-closure-argument.rs new file mode 100644 index 0000000000000..677003ebf225c --- /dev/null +++ b/src/test/ui/suggestions/unused-closure-argument.rs @@ -0,0 +1,20 @@ +#![deny(unused_variables)] + +struct Point { + x: i32, + y: i32, +} + +fn main() { + let points = vec!(Point { x: 1, y: 2 }, Point { x: 3, y: 4 }); + + let _: i32 = points.iter() + .map(|Point { x, y }| y) + //~^ ERROR unused variable + .sum(); + + let _: i32 = points.iter() + .map(|x| 4) + //~^ ERROR unused variable + .sum(); +} diff --git a/src/test/ui/suggestions/unused-closure-argument.stderr b/src/test/ui/suggestions/unused-closure-argument.stderr new file mode 100644 index 0000000000000..5cfdd79659b27 --- /dev/null +++ b/src/test/ui/suggestions/unused-closure-argument.stderr @@ -0,0 +1,20 @@ +error: unused variable: `x` + --> $DIR/unused-closure-argument.rs:12:23 + | +LL | .map(|Point { x, y }| y) + | ^ help: try ignoring the field: `x: _` + | +note: lint level defined here + --> $DIR/unused-closure-argument.rs:1:9 + | +LL | #![deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: unused variable: `x` + --> $DIR/unused-closure-argument.rs:17:15 + | +LL | .map(|x| 4) + | ^ help: consider prefixing with an underscore: `_x` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.rs b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.rs index a3cc53e69e20e..78487bd7bb58c 100644 --- a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.rs +++ b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.rs @@ -4,7 +4,7 @@ pub trait T { type C; } pub struct Foo { - i: Box>, + i: Box>, //~^ ERROR must be specified //~| ERROR wrong number of type arguments } diff --git a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr index 16e9fa90aa1a6..d273ec3fca59b 100644 --- a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr +++ b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr @@ -1,10 +1,10 @@ error[E0107]: wrong number of type arguments: expected 2, found 4 - --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:28 + --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:32 | -LL | i: Box>, - | ^^^^^ ^^^^^ unexpected type argument - | | - | unexpected type argument +LL | i: Box>, + | ^^^^^ ^^^^^ unexpected type argument + | | + | unexpected type argument error[E0191]: the value of the associated types `A` (from the trait `T`), `C` (from the trait `T`) must be specified --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:12 @@ -15,17 +15,17 @@ LL | type B; LL | type C; | ------- `C` defined here ... -LL | i: Box>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | i: Box>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | associated type `A` must be specified | associated type `C` must be specified help: if you meant to specify the associated types, write | -LL | i: Box>, - | ^^^^^^^^^ ^^^^^^^^^ +LL | i: Box>, + | ^^^^^^^^^ ^^^^^^^^^ error: aborting due to 2 previous errors -Some errors occurred: E0107, E0191. +Some errors have detailed explanations: E0107, E0191. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/super-at-top-level.stderr b/src/test/ui/super-at-top-level.stderr index ce7a39339767c..d04ce384fe886 100644 --- a/src/test/ui/super-at-top-level.stderr +++ b/src/test/ui/super-at-top-level.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: there are too many initial `super`s. --> $DIR/super-at-top-level.rs:1:5 | -LL | use super::f; //~ ERROR there are too many initial `super`s +LL | use super::f; | ^^^^^ there are too many initial `super`s. error: aborting due to previous error diff --git a/src/test/ui/svh/svh-change-lit.stderr b/src/test/ui/svh/svh-change-lit.stderr index ebb39224caa58..bf51e31bfd668 100644 --- a/src/test/ui/svh/svh-change-lit.stderr +++ b/src/test/ui/svh/svh-change-lit.stderr @@ -1,7 +1,7 @@ error[E0460]: found possibly newer version of crate `a` which `b` depends on --> $DIR/svh-change-lit.rs:10:1 | -LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on +LL | extern crate b; | ^^^^^^^^^^^^^^^ | = note: perhaps that crate needs to be recompiled? @@ -11,4 +11,3 @@ LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which error: aborting due to previous error -For more information about this error, try `rustc --explain E0460`. diff --git a/src/test/ui/svh/svh-change-significant-cfg.stderr b/src/test/ui/svh/svh-change-significant-cfg.stderr index d7196fc21f84e..c747464db753c 100644 --- a/src/test/ui/svh/svh-change-significant-cfg.stderr +++ b/src/test/ui/svh/svh-change-significant-cfg.stderr @@ -1,7 +1,7 @@ error[E0460]: found possibly newer version of crate `a` which `b` depends on --> $DIR/svh-change-significant-cfg.rs:10:1 | -LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on +LL | extern crate b; | ^^^^^^^^^^^^^^^ | = note: perhaps that crate needs to be recompiled? @@ -11,4 +11,3 @@ LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which error: aborting due to previous error -For more information about this error, try `rustc --explain E0460`. diff --git a/src/test/ui/svh/svh-change-trait-bound.stderr b/src/test/ui/svh/svh-change-trait-bound.stderr index 38678d7ec2ce4..b144b3b70da03 100644 --- a/src/test/ui/svh/svh-change-trait-bound.stderr +++ b/src/test/ui/svh/svh-change-trait-bound.stderr @@ -1,7 +1,7 @@ error[E0460]: found possibly newer version of crate `a` which `b` depends on --> $DIR/svh-change-trait-bound.rs:10:1 | -LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on +LL | extern crate b; | ^^^^^^^^^^^^^^^ | = note: perhaps that crate needs to be recompiled? @@ -11,4 +11,3 @@ LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which error: aborting due to previous error -For more information about this error, try `rustc --explain E0460`. diff --git a/src/test/ui/svh/svh-change-type-arg.stderr b/src/test/ui/svh/svh-change-type-arg.stderr index 037d7867b0dca..473e4000d2d9c 100644 --- a/src/test/ui/svh/svh-change-type-arg.stderr +++ b/src/test/ui/svh/svh-change-type-arg.stderr @@ -1,7 +1,7 @@ error[E0460]: found possibly newer version of crate `a` which `b` depends on --> $DIR/svh-change-type-arg.rs:10:1 | -LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on +LL | extern crate b; | ^^^^^^^^^^^^^^^ | = note: perhaps that crate needs to be recompiled? @@ -11,4 +11,3 @@ LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which error: aborting due to previous error -For more information about this error, try `rustc --explain E0460`. diff --git a/src/test/ui/svh/svh-change-type-ret.stderr b/src/test/ui/svh/svh-change-type-ret.stderr index 184ac9e0e7c78..ecb332fc5b5e9 100644 --- a/src/test/ui/svh/svh-change-type-ret.stderr +++ b/src/test/ui/svh/svh-change-type-ret.stderr @@ -1,7 +1,7 @@ error[E0460]: found possibly newer version of crate `a` which `b` depends on --> $DIR/svh-change-type-ret.rs:10:1 | -LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on +LL | extern crate b; | ^^^^^^^^^^^^^^^ | = note: perhaps that crate needs to be recompiled? @@ -11,4 +11,3 @@ LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which error: aborting due to previous error -For more information about this error, try `rustc --explain E0460`. diff --git a/src/test/ui/svh/svh-change-type-static.stderr b/src/test/ui/svh/svh-change-type-static.stderr index d3aeb073cd7a1..33f7e3c485acd 100644 --- a/src/test/ui/svh/svh-change-type-static.stderr +++ b/src/test/ui/svh/svh-change-type-static.stderr @@ -1,7 +1,7 @@ error[E0460]: found possibly newer version of crate `a` which `b` depends on --> $DIR/svh-change-type-static.rs:10:1 | -LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on +LL | extern crate b; | ^^^^^^^^^^^^^^^ | = note: perhaps that crate needs to be recompiled? @@ -11,4 +11,3 @@ LL | extern crate b; //~ ERROR: found possibly newer version of crate `a` which error: aborting due to previous error -For more information about this error, try `rustc --explain E0460`. diff --git a/src/test/ui/svh/svh-use-trait.stderr b/src/test/ui/svh/svh-use-trait.stderr index 0af44502375f2..3230bb5c38457 100644 --- a/src/test/ui/svh/svh-use-trait.stderr +++ b/src/test/ui/svh/svh-use-trait.stderr @@ -1,7 +1,7 @@ error[E0460]: found possibly newer version of crate `uta` which `utb` depends on --> $DIR/svh-use-trait.rs:15:1 | -LL | extern crate utb; //~ ERROR: found possibly newer version of crate `uta` which `utb` depends +LL | extern crate utb; | ^^^^^^^^^^^^^^^^^ | = note: perhaps that crate needs to be recompiled? @@ -11,4 +11,3 @@ LL | extern crate utb; //~ ERROR: found possibly newer version of crate `uta` wh error: aborting due to previous error -For more information about this error, try `rustc --explain E0460`. diff --git a/src/test/ui/switched-expectations.stderr b/src/test/ui/switched-expectations.stderr index bbb9b51650e02..043d130051d77 100644 --- a/src/test/ui/switched-expectations.stderr +++ b/src/test/ui/switched-expectations.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/switched-expectations.rs:3:30 | -LL | let ref string: String = var; //~ ERROR mismatched types [E0308] +LL | let ref string: String = var; | ^^^ expected struct `std::string::String`, found i32 | = note: expected type `std::string::String` diff --git a/src/test/ui/symbol-names/basic.legacy.stderr b/src/test/ui/symbol-names/basic.legacy.stderr new file mode 100644 index 0000000000000..e26168dcfc488 --- /dev/null +++ b/src/test/ui/symbol-names/basic.legacy.stderr @@ -0,0 +1,26 @@ +error: symbol-name(_ZN5basic4main17hd72940ef9669d526E) + --> $DIR/basic.rs:7:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(basic::main::hd72940ef9669d526) + --> $DIR/basic.rs:7:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(basic::main) + --> $DIR/basic.rs:7:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: def-path(main) + --> $DIR/basic.rs:14:1 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/symbol-names/basic.rs b/src/test/ui/symbol-names/basic.rs index 2a051a5e144da..aa88184eddfd4 100644 --- a/src/test/ui/symbol-names/basic.rs +++ b/src/test/ui/symbol-names/basic.rs @@ -1,6 +1,18 @@ +// revisions: legacy v0 +//[legacy]compile-flags: -Z symbol-mangling-version=legacy + //[v0]compile-flags: -Z symbol-mangling-version=v0 + #![feature(rustc_attrs)] -#[rustc_symbol_name] //~ ERROR _ZN5basic4main -#[rustc_item_path] //~ ERROR item-path(main) +#[rustc_symbol_name] +//[legacy]~^ ERROR symbol-name(_ZN5basic4main +//[legacy]~| ERROR demangling(basic::main +//[legacy]~| ERROR demangling-alt(basic::main) + //[v0]~^^^^ ERROR symbol-name(_RNvCs4fqI2P2rA04_5basic4main) + //[v0]~| ERROR demangling(basic[317d481089b8c8fe]::main) + //[v0]~| ERROR demangling-alt(basic::main) +#[rustc_def_path] +//[legacy]~^ ERROR def-path(main) + //[v0]~^^ ERROR def-path(main) fn main() { } diff --git a/src/test/ui/symbol-names/basic.stderr b/src/test/ui/symbol-names/basic.stderr index ca789df9bd187..7539cbada8b7b 100644 --- a/src/test/ui/symbol-names/basic.stderr +++ b/src/test/ui/symbol-names/basic.stderr @@ -1,14 +1,14 @@ -error: symbol-name(_ZN5basic4main17h08bcaf310214ed52E) +error: symbol-name(_ZN5basic4main17hd72940ef9669d526E) --> $DIR/basic.rs:3:1 | -LL | #[rustc_symbol_name] //~ ERROR _ZN5basic4main +LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: item-path(main) +error: def-path(main) --> $DIR/basic.rs:4:1 | -LL | #[rustc_item_path] //~ ERROR item-path(main) - | ^^^^^^^^^^^^^^^^^^ +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/symbol-names/basic.v0.stderr b/src/test/ui/symbol-names/basic.v0.stderr new file mode 100644 index 0000000000000..40a39daaedce1 --- /dev/null +++ b/src/test/ui/symbol-names/basic.v0.stderr @@ -0,0 +1,26 @@ +error: symbol-name(_RNvCs4fqI2P2rA04_5basic4main) + --> $DIR/basic.rs:7:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(basic[317d481089b8c8fe]::main) + --> $DIR/basic.rs:7:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(basic::main) + --> $DIR/basic.rs:7:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: def-path(main) + --> $DIR/basic.rs:14:1 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr new file mode 100644 index 0000000000000..c1d22a919d900 --- /dev/null +++ b/src/test/ui/symbol-names/impl1.legacy.stderr @@ -0,0 +1,74 @@ +error: symbol-name(_ZN5impl13foo3Foo3bar17he53b9bee7600ed8dE) + --> $DIR/impl1.rs:13:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(impl1::foo::Foo::bar::he53b9bee7600ed8d) + --> $DIR/impl1.rs:13:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(impl1::foo::Foo::bar) + --> $DIR/impl1.rs:13:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: def-path(foo::Foo::bar) + --> $DIR/impl1.rs:20:9 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h86c41f0462d901d4E) + --> $DIR/impl1.rs:31:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(impl1::bar::::baz::h86c41f0462d901d4) + --> $DIR/impl1.rs:31:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(impl1::bar::::baz) + --> $DIR/impl1.rs:31:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: def-path(bar::::baz) + --> $DIR/impl1.rs:38:9 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: symbol-name(_ZN198_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h6f205aef6a8ccc7bE) + --> $DIR/impl1.rs:63:13 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h6f205aef6a8ccc7b) + --> $DIR/impl1.rs:63:13 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method) + --> $DIR/impl1.rs:63:13 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: def-path(<[&dyn Foo extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method) + --> $DIR/impl1.rs:70:13 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index 97169c33b8cbf..52bb118fa23a0 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -1,12 +1,25 @@ -#![feature(rustc_attrs)] +// ignore-tidy-linelength +// revisions: legacy v0 +//[legacy]compile-flags: -Z symbol-mangling-version=legacy + //[v0]compile-flags: -Z symbol-mangling-version=v0 + +#![feature(optin_builtin_traits, rustc_attrs)] #![allow(dead_code)] mod foo { pub struct Foo { x: u32 } impl Foo { - #[rustc_symbol_name] //~ ERROR _ZN5impl13foo3Foo3bar - #[rustc_item_path] //~ ERROR item-path(foo::Foo::bar) + #[rustc_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar + //[legacy]~| ERROR demangling(impl1::foo::Foo::bar + //[legacy]~| ERROR demangling-alt(impl1::foo::Foo::bar) + //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13fooNtB2_3Foo3bar) + //[v0]~| ERROR demangling(::bar) + //[v0]~| ERROR demangling-alt(::bar) + #[rustc_def_path] + //[legacy]~^ ERROR def-path(foo::Foo::bar) + //[v0]~^^ ERROR def-path(foo::Foo::bar) fn bar() { } } } @@ -15,11 +28,49 @@ mod bar { use foo::Foo; impl Foo { - #[rustc_symbol_name] //~ ERROR _ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz - #[rustc_item_path] //~ ERROR item-path(bar::::baz) + #[rustc_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz + //[legacy]~| ERROR demangling(impl1::bar::::baz + //[legacy]~| ERROR demangling-alt(impl1::bar::::baz) + //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13barNtNtB4_3foo3Foo3baz) + //[v0]~| ERROR demangling(::baz) + //[v0]~| ERROR demangling-alt(::baz) + #[rustc_def_path] + //[legacy]~^ ERROR def-path(bar::::baz) + //[v0]~^^ ERROR def-path(bar::::baz) fn baz() { } } } +trait Foo { + type Assoc; +} + +auto trait AutoTrait {} + fn main() { + // Test closure mangling, and disambiguators. + || {}; + || { + trait Bar { + fn method(&self) {} + } + + // Test type mangling, by putting them in an `impl` header. + // FIXME(eddyb) test C varargs when `core::ffi::VaListImpl` stops leaking into the signature + // (which is a problem because `core` has an unpredictable hash) - see also #44930. + impl Bar for [&'_ (dyn Foo + AutoTrait); 3] { + #[rustc_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN198_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method + //[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method + //[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method) + //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs4fqI2P2rA04_5impl14mains_0ARDNtB6_3Foop5AssocFG0_KCRL0_hEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method) + //[v0]~| ERROR demangling(<[&dyn impl1[317d481089b8c8fe]::Foo extern "C" fn(&'b u8)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method) + //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo extern "C" fn(&'b u8)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method) + #[rustc_def_path] + //[legacy]~^ ERROR def-path(<[&dyn Foo extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method) + //[v0]~^^ ERROR def-path(<[&dyn Foo extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method) + fn method(&self) {} + } + }; } diff --git a/src/test/ui/symbol-names/impl1.stderr b/src/test/ui/symbol-names/impl1.stderr index 75d3e40e1b2fc..20e48782a3a9e 100644 --- a/src/test/ui/symbol-names/impl1.stderr +++ b/src/test/ui/symbol-names/impl1.stderr @@ -1,26 +1,26 @@ -error: symbol-name(_ZN5impl13foo3Foo3bar17hc487d6ec13fe9124E) +error: symbol-name(_ZN5impl13foo3Foo3bar17he53b9bee7600ed8dE) --> $DIR/impl1.rs:8:9 | -LL | #[rustc_symbol_name] //~ ERROR _ZN5impl13foo3Foo3bar +LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: item-path(foo::Foo::bar) +error: def-path(foo::Foo::bar) --> $DIR/impl1.rs:9:9 | -LL | #[rustc_item_path] //~ ERROR item-path(foo::Foo::bar) - | ^^^^^^^^^^^^^^^^^^ +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ -error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h38577281258e1527E) +error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h86c41f0462d901d4E) --> $DIR/impl1.rs:18:9 | -LL | #[rustc_symbol_name] //~ ERROR _ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz +LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: item-path(bar::::baz) +error: def-path(bar::::baz) --> $DIR/impl1.rs:19:9 | -LL | #[rustc_item_path] //~ ERROR item-path(bar::::baz) - | ^^^^^^^^^^^^^^^^^^ +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/symbol-names/impl1.v0.stderr b/src/test/ui/symbol-names/impl1.v0.stderr new file mode 100644 index 0000000000000..1c4b256c9e933 --- /dev/null +++ b/src/test/ui/symbol-names/impl1.v0.stderr @@ -0,0 +1,74 @@ +error: symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13fooNtB2_3Foo3bar) + --> $DIR/impl1.rs:13:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(::bar) + --> $DIR/impl1.rs:13:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(::bar) + --> $DIR/impl1.rs:13:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: def-path(foo::Foo::bar) + --> $DIR/impl1.rs:20:9 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13barNtNtB4_3foo3Foo3baz) + --> $DIR/impl1.rs:31:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(::baz) + --> $DIR/impl1.rs:31:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(::baz) + --> $DIR/impl1.rs:31:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: def-path(bar::::baz) + --> $DIR/impl1.rs:38:9 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RNvXNCNvCs4fqI2P2rA04_5impl14mains_0ARDNtB6_3Foop5AssocFG0_KCRL0_hEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method) + --> $DIR/impl1.rs:63:13 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(<[&dyn impl1[317d481089b8c8fe]::Foo extern "C" fn(&'b u8)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method) + --> $DIR/impl1.rs:63:13 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(<[&dyn impl1::Foo extern "C" fn(&'b u8)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method) + --> $DIR/impl1.rs:63:13 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: def-path(<[&dyn Foo extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method) + --> $DIR/impl1.rs:70:13 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + diff --git a/src/test/ui/symbol-names/impl2.rs b/src/test/ui/symbol-names/impl2.rs new file mode 100644 index 0000000000000..d48b182f2a200 --- /dev/null +++ b/src/test/ui/symbol-names/impl2.rs @@ -0,0 +1,14 @@ +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait Foo { + fn baz(); +} + +impl Foo for [u8; 1 + 2] { + #[rustc_def_path] //~ ERROR def-path(<[u8; _] as Foo>::baz) + fn baz() { } +} + +fn main() { +} diff --git a/src/test/ui/symbol-names/impl2.stderr b/src/test/ui/symbol-names/impl2.stderr new file mode 100644 index 0000000000000..de26fed44139e --- /dev/null +++ b/src/test/ui/symbol-names/impl2.stderr @@ -0,0 +1,8 @@ +error: def-path(<[u8; _] as Foo>::baz) + --> $DIR/impl2.rs:9:5 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/symbol-names/issue-60925.legacy.stderr b/src/test/ui/symbol-names/issue-60925.legacy.stderr new file mode 100644 index 0000000000000..7fcd2ede31b69 --- /dev/null +++ b/src/test/ui/symbol-names/issue-60925.legacy.stderr @@ -0,0 +1,20 @@ +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h059a991a004536adE) + --> $DIR/issue-60925.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(issue_60925::foo::Foo $DIR/issue-60925.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(issue_60925::foo::Foo $DIR/issue-60925.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/symbol-names/issue-60925.rs b/src/test/ui/symbol-names/issue-60925.rs new file mode 100644 index 0000000000000..89de15cc0f3e4 --- /dev/null +++ b/src/test/ui/symbol-names/issue-60925.rs @@ -0,0 +1,49 @@ +// ignore-tidy-linelength +// revisions: legacy v0 +//[legacy]compile-flags: -Z symbol-mangling-version=legacy + //[v0]compile-flags: -Z symbol-mangling-version=v0 + +#![feature(rustc_attrs)] + +// This test is the same code as in ui/issue-53912.rs but this test checks that the symbol mangling +// fix produces the correct result, whereas that test just checks that the reproduction compiles +// successfully and doesn't crash LLVM + +fn dummy() {} + +mod llvm { + pub(crate) struct Foo; +} +mod foo { + pub(crate) struct Foo(T); + + impl Foo<::llvm::Foo> { + #[rustc_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo + //[legacy]~| ERROR demangling(issue_60925::foo::Foo>::foo) + //[v0]~| ERROR demangling-alt(>::foo) + pub(crate) fn foo() { + for _ in 0..0 { + for _ in &[::dummy()] { + ::dummy(); + ::dummy(); + ::dummy(); + } + } + } + } + + pub(crate) fn foo() { + Foo::foo(); + Foo::foo(); + } +} + +pub fn foo() { + foo::foo(); +} + +fn main() {} diff --git a/src/test/ui/symbol-names/issue-60925.stderr b/src/test/ui/symbol-names/issue-60925.stderr new file mode 100644 index 0000000000000..ae753f0cebbcd --- /dev/null +++ b/src/test/ui/symbol-names/issue-60925.stderr @@ -0,0 +1,20 @@ +error: symbol-name(_ZN11issue_609253foo36Foo$LT$issue_60925..llv$6d$..Foo$GT$3foo17h059a991a004536adE) + --> $DIR/issue-60925.rs:16:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(issue_60925::foo::Foo $DIR/issue-60925.rs:16:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(issue_60925::foo::Foo $DIR/issue-60925.rs:16:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/symbol-names/issue-60925.v0.stderr b/src/test/ui/symbol-names/issue-60925.v0.stderr new file mode 100644 index 0000000000000..5ead40211d20d --- /dev/null +++ b/src/test/ui/symbol-names/issue-60925.v0.stderr @@ -0,0 +1,20 @@ +error: symbol-name(_RNvMNtCs4fqI2P2rA04_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo) + --> $DIR/issue-60925.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>::foo) + --> $DIR/issue-60925.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>::foo) + --> $DIR/issue-60925.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/syntax-trait-polarity-feature-gate.stderr b/src/test/ui/syntax-trait-polarity-feature-gate.stderr index 7b9c3da3712f9..86b4bc1157b72 100644 --- a/src/test/ui/syntax-trait-polarity-feature-gate.stderr +++ b/src/test/ui/syntax-trait-polarity-feature-gate.stderr @@ -1,9 +1,10 @@ -error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now (see issue #13231) +error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now --> $DIR/syntax-trait-polarity-feature-gate.rs:7:1 | LL | impl !Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/13231 = help: add #![feature(optin_builtin_traits)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/syntax-trait-polarity.stderr b/src/test/ui/syntax-trait-polarity.stderr index 689e24bb8346e..b66db9feedbdc 100644 --- a/src/test/ui/syntax-trait-polarity.stderr +++ b/src/test/ui/syntax-trait-polarity.stderr @@ -36,5 +36,5 @@ LL | impl !TestTrait for TestType2 {} error: aborting due to 6 previous errors -Some errors occurred: E0192, E0198. +Some errors have detailed explanations: E0192, E0198. For more information about an error, try `rustc --explain E0192`. diff --git a/src/test/ui/synthetic-param.stderr b/src/test/ui/synthetic-param.stderr index 7bdab439572b5..bfafd8cbd72ec 100644 --- a/src/test/ui/synthetic-param.stderr +++ b/src/test/ui/synthetic-param.stderr @@ -1,21 +1,20 @@ error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position. --> $DIR/synthetic-param.rs:20:5 | -LL | func::(42); //~ ERROR cannot provide explicit type parameters +LL | func::(42); | ^^^^^^^^^^ error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position. --> $DIR/synthetic-param.rs:23:5 | -LL | Foo::func::(42); //~ ERROR cannot provide explicit type parameters +LL | Foo::func::(42); | ^^^^^^^^^^^^^^^ error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position. --> $DIR/synthetic-param.rs:26:5 | -LL | Bar::::func::(42); //~ ERROR cannot provide explicit type parameters +LL | Bar::::func::(42); | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0632`. diff --git a/src/test/ui/tag-type-args.stderr b/src/test/ui/tag-type-args.stderr index 40523ee907b88..ac44dad4a888b 100644 --- a/src/test/ui/tag-type-args.stderr +++ b/src/test/ui/tag-type-args.stderr @@ -1,7 +1,7 @@ error[E0107]: wrong number of type arguments: expected 1, found 0 --> $DIR/tag-type-args.rs:3:11 | -LL | fn foo(c: Quux) { assert!((false)); } //~ ERROR wrong number of type arguments +LL | fn foo(c: Quux) { assert!((false)); } | ^^^^ expected 1 type argument error: aborting due to previous error diff --git a/src/test/ui/tag-variant-cast-non-nullary.stderr b/src/test/ui/tag-variant-cast-non-nullary.stderr index 797a55f65fe18..87ec20f20d789 100644 --- a/src/test/ui/tag-variant-cast-non-nullary.stderr +++ b/src/test/ui/tag-variant-cast-non-nullary.stderr @@ -1,7 +1,7 @@ error[E0605]: non-primitive cast: `NonNullary` as `isize` --> $DIR/tag-variant-cast-non-nullary.rs:8:15 | -LL | let val = v as isize; //~ ERROR non-primitive cast: `NonNullary` as `isize` [E0605] +LL | let val = v as isize; | ^^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait diff --git a/src/test/ui/tag-variant-disr-dup.stderr b/src/test/ui/tag-variant-disr-dup.stderr index b3de25e87b353..ca12894c04292 100644 --- a/src/test/ui/tag-variant-disr-dup.stderr +++ b/src/test/ui/tag-variant-disr-dup.stderr @@ -3,7 +3,7 @@ error[E0081]: discriminant value `0` already exists | LL | Black = 0x000000, | -------- first use of `0` -LL | White = 0x000000, //~ ERROR discriminant value `0` already exists +LL | White = 0x000000, | ^^^^^^^^ enum already has `0` error: aborting due to previous error diff --git a/src/test/ui/target-feature-gate.rs b/src/test/ui/target-feature-gate.rs index 84300301b7629..bc7f7caa10766 100644 --- a/src/test/ui/target-feature-gate.rs +++ b/src/test/ui/target-feature-gate.rs @@ -23,6 +23,8 @@ // gate-test-adx_target_feature // gate-test-cmpxchg16b_target_feature // gate-test-movbe_target_feature +// gate-test-rtm_target_feature +// gate-test-f16c_target_feature // min-llvm-version 6.0 #[target_feature(enable = "avx512bw")] diff --git a/src/test/ui/target-feature-gate.stderr b/src/test/ui/target-feature-gate.stderr index 24141d0064fb0..c7adba868eaf8 100644 --- a/src/test/ui/target-feature-gate.stderr +++ b/src/test/ui/target-feature-gate.stderr @@ -1,9 +1,10 @@ -error[E0658]: the target feature `avx512bw` is currently unstable (see issue #44839) - --> $DIR/target-feature-gate.rs:28:18 +error[E0658]: the target feature `avx512bw` is currently unstable + --> $DIR/target-feature-gate.rs:30:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44839 = help: add #![feature(avx512_target_feature)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/target-feature-wrong.rs b/src/test/ui/target-feature-wrong.rs index ddae8870905ad..ac02c9cc648c2 100644 --- a/src/test/ui/target-feature-wrong.rs +++ b/src/test/ui/target-feature-wrong.rs @@ -14,22 +14,26 @@ #![feature(target_feature)] #[target_feature = "+sse2"] -//~^ ERROR: must be of the form +//~^ ERROR malformed `target_feature` attribute #[target_feature(enable = "foo")] -//~^ ERROR: not valid for this target +//~^ ERROR not valid for this target +//~| NOTE `foo` is not valid for this target #[target_feature(bar)] -//~^ ERROR: only accepts sub-keys +//~^ ERROR malformed `target_feature` attribute #[target_feature(disable = "baz")] -//~^ ERROR: only accepts sub-keys +//~^ ERROR malformed `target_feature` attribute unsafe fn foo() {} #[target_feature(enable = "sse2")] -//~^ ERROR: can only be applied to `unsafe` function +//~^ ERROR #[target_feature(..)] can only be applied to `unsafe` functions +//~| NOTE can only be applied to `unsafe` functions fn bar() {} +//~^ NOTE not an `unsafe` function #[target_feature(enable = "sse2")] -//~^ ERROR: should be applied to a function +//~^ ERROR attribute should be applied to a function mod another {} +//~^ NOTE not a function #[inline(always)] //~^ ERROR: cannot use #[inline(always)] diff --git a/src/test/ui/target-feature-wrong.stderr b/src/test/ui/target-feature-wrong.stderr index 236f5c4afec39..ff9678efdddc2 100644 --- a/src/test/ui/target-feature-wrong.stderr +++ b/src/test/ui/target-feature-wrong.stderr @@ -1,44 +1,47 @@ -error: attribute must be of the form `#[target_feature(enable = "name")]` +error: malformed `target_feature` attribute input --> $DIR/target-feature-wrong.rs:16:1 | LL | #[target_feature = "+sse2"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]` error: the feature named `foo` is not valid for this target --> $DIR/target-feature-wrong.rs:18:18 | LL | #[target_feature(enable = "foo")] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ `foo` is not valid for this target -error: #[target_feature(..)] only accepts sub-keys of `enable` currently - --> $DIR/target-feature-wrong.rs:20:18 +error: malformed `target_feature` attribute input + --> $DIR/target-feature-wrong.rs:21:18 | LL | #[target_feature(bar)] - | ^^^ + | ^^^ help: must be of the form: `enable = ".."` -error: #[target_feature(..)] only accepts sub-keys of `enable` currently - --> $DIR/target-feature-wrong.rs:22:18 +error: malformed `target_feature` attribute input + --> $DIR/target-feature-wrong.rs:23:18 | LL | #[target_feature(disable = "baz")] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."` -error: #[target_feature(..)] can only be applied to `unsafe` function - --> $DIR/target-feature-wrong.rs:26:1 +error: #[target_feature(..)] can only be applied to `unsafe` functions + --> $DIR/target-feature-wrong.rs:27:1 | LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only be applied to `unsafe` functions +... +LL | fn bar() {} + | ----------- not an `unsafe` function error: attribute should be applied to a function - --> $DIR/target-feature-wrong.rs:30:1 + --> $DIR/target-feature-wrong.rs:33:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | //~^ ERROR: should be applied to a function +LL | LL | mod another {} | -------------- not a function error: cannot use #[inline(always)] with #[target_feature] - --> $DIR/target-feature-wrong.rs:34:1 + --> $DIR/target-feature-wrong.rs:38:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/terr-in-field.stderr b/src/test/ui/terr-in-field.stderr index 5a9c0898aad18..91c3b3014a200 100644 --- a/src/test/ui/terr-in-field.stderr +++ b/src/test/ui/terr-in-field.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/terr-in-field.rs:13:14 | -LL | want_foo(b); //~ ERROR mismatched types +LL | want_foo(b); | ^ expected struct `Foo`, found struct `Bar` | = note: expected type `Foo` diff --git a/src/test/ui/terr-sorts.stderr b/src/test/ui/terr-sorts.stderr index dfaf8186fc38b..05b9fb43fe1bc 100644 --- a/src/test/ui/terr-sorts.stderr +++ b/src/test/ui/terr-sorts.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/terr-sorts.rs:10:14 | -LL | want_foo(b); //~ ERROR mismatched types +LL | want_foo(b); | ^ expected struct `Foo`, found struct `std::boxed::Box` | = note: expected type `Foo` diff --git a/src/test/ui/test-attr-non-associated-functions.stderr b/src/test/ui/test-attr-non-associated-functions.stderr index 8a1cc6fa367f5..6176aa03d84da 100644 --- a/src/test/ui/test-attr-non-associated-functions.stderr +++ b/src/test/ui/test-attr-non-associated-functions.stderr @@ -1,7 +1,7 @@ error: #[test] attribute is only allowed on non associated functions --> $DIR/test-attr-non-associated-functions.rs:9:5 | -LL | / fn new() -> A { //~ ERROR #[test] attribute is only allowed on non associated functions +LL | / fn new() -> A { LL | | A {} LL | | } | |_____^ diff --git a/src/test/ui/test-cfg.stderr b/src/test/ui/test-cfg.stderr index 93ca9a27de23b..c35fe2f9458d4 100644 --- a/src/test/ui/test-cfg.stderr +++ b/src/test/ui/test-cfg.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find function `foo` in this scope --> $DIR/test-cfg.rs:7:5 | -LL | foo(); //~ ERROR cannot find function `foo` in this scope +LL | foo(); | ^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/test-warns-dead-code.stderr b/src/test/ui/test-warns-dead-code.stderr index fe74ad133405a..62e99225dd902 100644 --- a/src/test/ui/test-warns-dead-code.stderr +++ b/src/test/ui/test-warns-dead-code.stderr @@ -1,7 +1,7 @@ error: function is never used: `dead` --> $DIR/test-warns-dead-code.rs:5:1 | -LL | fn dead() {} //~ error: function is never used: `dead` +LL | fn dead() {} | ^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/thread-local-in-ctfe.nll.stderr b/src/test/ui/thread-local-in-ctfe.nll.stderr index c5cca9d25c19b..18d01b1879018 100644 --- a/src/test/ui/thread-local-in-ctfe.nll.stderr +++ b/src/test/ui/thread-local-in-ctfe.nll.stderr @@ -10,47 +10,40 @@ error[E0625]: thread-local statics cannot be accessed at compile-time LL | static C: &u32 = &A; | ^^ -warning[E0712]: thread-local variable borrowed past end of function +error[E0712]: thread-local variable borrowed past end of function --> $DIR/thread-local-in-ctfe.rs:9:18 | LL | static C: &u32 = &A; | ^^- end of enclosing function is here | | | thread-local variables cannot be borrowed beyond the end of the function - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future error[E0625]: thread-local statics cannot be accessed at compile-time - --> $DIR/thread-local-in-ctfe.rs:12:16 + --> $DIR/thread-local-in-ctfe.rs:15:16 | LL | const D: u32 = A; | ^ error[E0625]: thread-local statics cannot be accessed at compile-time - --> $DIR/thread-local-in-ctfe.rs:15:17 + --> $DIR/thread-local-in-ctfe.rs:18:17 | LL | const E: &u32 = &A; | ^^ -warning[E0712]: thread-local variable borrowed past end of function - --> $DIR/thread-local-in-ctfe.rs:15:17 +error[E0712]: thread-local variable borrowed past end of function + --> $DIR/thread-local-in-ctfe.rs:18:17 | LL | const E: &u32 = &A; | ^^- end of enclosing function is here | | | thread-local variables cannot be borrowed beyond the end of the function - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future error[E0625]: thread-local statics cannot be accessed at compile-time - --> $DIR/thread-local-in-ctfe.rs:19:5 + --> $DIR/thread-local-in-ctfe.rs:25:5 | LL | A | ^ -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors -Some errors occurred: E0625, E0712. -For more information about an error, try `rustc --explain E0625`. +For more information about this error, try `rustc --explain E0712`. diff --git a/src/test/ui/thread-local-in-ctfe.rs b/src/test/ui/thread-local-in-ctfe.rs index 313d39de36b6a..7ca1a2e7e90c2 100644 --- a/src/test/ui/thread-local-in-ctfe.rs +++ b/src/test/ui/thread-local-in-ctfe.rs @@ -8,12 +8,18 @@ static B: u32 = A; static C: &u32 = &A; //~^ ERROR thread-local statics cannot be accessed at compile-time +//~| WARNING thread-local variable borrowed past end of function +//~| WARNING this error has been downgraded to a warning +//~| WARNING this warning will become a hard error in the future const D: u32 = A; //~^ ERROR thread-local statics cannot be accessed at compile-time const E: &u32 = &A; //~^ ERROR thread-local statics cannot be accessed at compile-time +//~| WARNING thread-local variable borrowed past end of function +//~| WARNING this error has been downgraded to a warning +//~| WARNING this warning will become a hard error in the future const fn f() -> u32 { A diff --git a/src/test/ui/thread-local-in-ctfe.stderr b/src/test/ui/thread-local-in-ctfe.stderr index abeb2a3e0dee5..6869109e67fc0 100644 --- a/src/test/ui/thread-local-in-ctfe.stderr +++ b/src/test/ui/thread-local-in-ctfe.stderr @@ -10,24 +10,48 @@ error[E0625]: thread-local statics cannot be accessed at compile-time LL | static C: &u32 = &A; | ^^ +warning[E0712]: thread-local variable borrowed past end of function + --> $DIR/thread-local-in-ctfe.rs:9:18 + | +LL | static C: &u32 = &A; + | ^^- end of enclosing function is here + | | + | thread-local variables cannot be borrowed beyond the end of the function + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + error[E0625]: thread-local statics cannot be accessed at compile-time - --> $DIR/thread-local-in-ctfe.rs:12:16 + --> $DIR/thread-local-in-ctfe.rs:15:16 | LL | const D: u32 = A; | ^ error[E0625]: thread-local statics cannot be accessed at compile-time - --> $DIR/thread-local-in-ctfe.rs:15:17 + --> $DIR/thread-local-in-ctfe.rs:18:17 | LL | const E: &u32 = &A; | ^^ +warning[E0712]: thread-local variable borrowed past end of function + --> $DIR/thread-local-in-ctfe.rs:18:17 + | +LL | const E: &u32 = &A; + | ^^- end of enclosing function is here + | | + | thread-local variables cannot be borrowed beyond the end of the function + | + = warning: this error has been downgraded to a warning for backwards compatibility with previous releases + = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future + = note: for more information, try `rustc --explain E0729` + error[E0625]: thread-local statics cannot be accessed at compile-time - --> $DIR/thread-local-in-ctfe.rs:19:5 + --> $DIR/thread-local-in-ctfe.rs:25:5 | LL | A | ^ error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0625`. +For more information about this error, try `rustc --explain E0712`. diff --git a/src/test/ui/thread-local-mutation.nll.stderr b/src/test/ui/thread-local-mutation.nll.stderr deleted file mode 100644 index 0a3664b0d9d40..0000000000000 --- a/src/test/ui/thread-local-mutation.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0594]: cannot assign to immutable static item `S` - --> $DIR/thread-local-mutation.rs:11:5 - | -LL | S = "after"; //~ ERROR cannot assign to immutable - | ^^^^^^^^^^^ cannot assign - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/thread-local-mutation.stderr b/src/test/ui/thread-local-mutation.stderr index bf298523e1b73..7f7738b5d6509 100644 --- a/src/test/ui/thread-local-mutation.stderr +++ b/src/test/ui/thread-local-mutation.stderr @@ -1,9 +1,8 @@ -error[E0594]: cannot assign to immutable thread-local static item +error[E0594]: cannot assign to immutable static item `S` --> $DIR/thread-local-mutation.rs:11:5 | -LL | S = "after"; //~ ERROR cannot assign to immutable - | ^^^^^^^^^^^ +LL | S = "after"; + | ^^^^^^^^^^^ cannot assign error: aborting due to previous error -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs index 33cffcefd898a..ce902b7e7d28a 100644 --- a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs +++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs @@ -1,12 +1,11 @@ -#![feature(custom_attribute)] - type A = rustfmt; //~ ERROR expected type, found tool module `rustfmt` type B = rustfmt::skip; //~ ERROR expected type, found tool attribute `rustfmt::skip` #[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope struct S; -#[rustfmt] // OK, interpreted as a custom attribute +// Interpreted as a feature gated custom attribute +#[rustfmt] //~ ERROR attribute `rustfmt` is currently unknown fn check() {} #[rustfmt::skip] // OK diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr index dd1de22f3da00..1df9821f24440 100644 --- a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr +++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr @@ -1,40 +1,49 @@ +error[E0658]: The attribute `rustfmt` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/tool-attributes-misplaced-1.rs:8:3 + | +LL | #[rustfmt] + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + error: cannot find derive macro `rustfmt` in this scope - --> $DIR/tool-attributes-misplaced-1.rs:6:10 + --> $DIR/tool-attributes-misplaced-1.rs:4:10 | -LL | #[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope +LL | #[derive(rustfmt)] | ^^^^^^^ error: cannot find macro `rustfmt!` in this scope - --> $DIR/tool-attributes-misplaced-1.rs:15:5 + --> $DIR/tool-attributes-misplaced-1.rs:14:5 | -LL | rustfmt!(); //~ ERROR cannot find macro `rustfmt!` in this scope +LL | rustfmt!(); | ^^^^^^^ error[E0573]: expected type, found tool module `rustfmt` - --> $DIR/tool-attributes-misplaced-1.rs:3:10 + --> $DIR/tool-attributes-misplaced-1.rs:1:10 | -LL | type A = rustfmt; //~ ERROR expected type, found tool module `rustfmt` +LL | type A = rustfmt; | ^^^^^^^ not a type error[E0573]: expected type, found tool attribute `rustfmt::skip` - --> $DIR/tool-attributes-misplaced-1.rs:4:10 + --> $DIR/tool-attributes-misplaced-1.rs:2:10 | -LL | type B = rustfmt::skip; //~ ERROR expected type, found tool attribute `rustfmt::skip` +LL | type B = rustfmt::skip; | ^^^^^^^^^^^^^ not a type error[E0423]: expected value, found tool module `rustfmt` - --> $DIR/tool-attributes-misplaced-1.rs:14:5 + --> $DIR/tool-attributes-misplaced-1.rs:13:5 | -LL | rustfmt; //~ ERROR expected value, found tool module `rustfmt` +LL | rustfmt; | ^^^^^^^ not a value error[E0423]: expected value, found tool attribute `rustfmt::skip` - --> $DIR/tool-attributes-misplaced-1.rs:17:5 + --> $DIR/tool-attributes-misplaced-1.rs:16:5 | -LL | rustfmt::skip; //~ ERROR expected value, found tool attribute `rustfmt::skip` +LL | rustfmt::skip; | ^^^^^^^^^^^^^ not a value -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors -Some errors occurred: E0423, E0573. +Some errors have detailed explanations: E0423, E0658. For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-2.stderr b/src/test/ui/tool-attributes/tool-attributes-misplaced-2.stderr index 50a7b5973283c..c5f5f59c32c30 100644 --- a/src/test/ui/tool-attributes/tool-attributes-misplaced-2.stderr +++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-2.stderr @@ -1,13 +1,13 @@ error: expected a macro, found tool attribute --> $DIR/tool-attributes-misplaced-2.rs:1:10 | -LL | #[derive(rustfmt::skip)] //~ ERROR expected a macro, found tool attribute +LL | #[derive(rustfmt::skip)] | ^^^^^^^^^^^^^ error: expected a macro, found tool attribute --> $DIR/tool-attributes-misplaced-2.rs:5:5 | -LL | rustfmt::skip!(); //~ ERROR expected a macro, found tool attribute +LL | rustfmt::skip!(); | ^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/tool-attributes/tool-attributes-shadowing.stderr b/src/test/ui/tool-attributes/tool-attributes-shadowing.stderr index 62b5b8e2ac239..98ad109a07e8a 100644 --- a/src/test/ui/tool-attributes/tool-attributes-shadowing.stderr +++ b/src/test/ui/tool-attributes/tool-attributes-shadowing.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: could not find `skip` in `rustfmt` --> $DIR/tool-attributes-shadowing.rs:3:12 | -LL | #[rustfmt::skip] //~ ERROR failed to resolve: could not find `skip` in `rustfmt` +LL | #[rustfmt::skip] | ^^^^ could not find `skip` in `rustfmt` error: aborting due to previous error diff --git a/src/test/ui/tool_lints-fail.stderr b/src/test/ui/tool_lints-fail.stderr index 6b027eecf2682..a61157f21b8e5 100644 --- a/src/test/ui/tool_lints-fail.stderr +++ b/src/test/ui/tool_lints-fail.stderr @@ -1,7 +1,7 @@ error: unknown lint: `clippy` --> $DIR/tool_lints-fail.rs:6:9 | -LL | #![deny(clippy)] //~ ERROR: unknown lint: `clippy` +LL | #![deny(clippy)] | ^^^^^^ | note: lint level defined here diff --git a/src/test/ui/tool_lints.stderr b/src/test/ui/tool_lints.stderr index 2484b10116f0e..de941604a9491 100644 --- a/src/test/ui/tool_lints.stderr +++ b/src/test/ui/tool_lints.stderr @@ -6,4 +6,3 @@ LL | #[warn(foo::bar)] error: aborting due to previous error -For more information about this error, try `rustc --explain E0710`. diff --git a/src/test/ui/trace_macros-format.stderr b/src/test/ui/trace_macros-format.stderr index a180c360b4a74..650b87076981f 100644 --- a/src/test/ui/trace_macros-format.stderr +++ b/src/test/ui/trace_macros-format.stderr @@ -1,37 +1,37 @@ error: trace_macros! accepts only `true` or `false` --> $DIR/trace_macros-format.rs:4:5 | -LL | trace_macros!(); //~ ERROR trace_macros! accepts only `true` or `false` +LL | trace_macros!(); | ^^^^^^^^^^^^^^^^ error: trace_macros! accepts only `true` or `false` --> $DIR/trace_macros-format.rs:5:5 | -LL | trace_macros!(1); //~ ERROR trace_macros! accepts only `true` or `false` +LL | trace_macros!(1); | ^^^^^^^^^^^^^^^^^ error: trace_macros! accepts only `true` or `false` --> $DIR/trace_macros-format.rs:6:5 | -LL | trace_macros!(ident); //~ ERROR trace_macros! accepts only `true` or `false` +LL | trace_macros!(ident); | ^^^^^^^^^^^^^^^^^^^^^ error: trace_macros! accepts only `true` or `false` --> $DIR/trace_macros-format.rs:7:5 | -LL | trace_macros!(for); //~ ERROR trace_macros! accepts only `true` or `false` +LL | trace_macros!(for); | ^^^^^^^^^^^^^^^^^^^ error: trace_macros! accepts only `true` or `false` --> $DIR/trace_macros-format.rs:8:5 | -LL | trace_macros!(true,); //~ ERROR trace_macros! accepts only `true` or `false` +LL | trace_macros!(true,); | ^^^^^^^^^^^^^^^^^^^^^ error: trace_macros! accepts only `true` or `false` --> $DIR/trace_macros-format.rs:9:5 | -LL | trace_macros!(false 1); //~ ERROR trace_macros! accepts only `true` or `false` +LL | trace_macros!(false 1); | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/trace_macros-gate.stderr b/src/test/ui/trace_macros-gate.stderr index 4831aa158dbc8..e0ffcfe295fdf 100644 --- a/src/test/ui/trace_macros-gate.stderr +++ b/src/test/ui/trace_macros-gate.stderr @@ -1,42 +1,46 @@ -error[E0658]: `trace_macros` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `trace_macros` is not stable enough for use and is subject to change --> $DIR/trace_macros-gate.rs:4:5 | -LL | trace_macros!(); //~ ERROR `trace_macros` is not stable +LL | trace_macros!(); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(trace_macros)] to the crate attributes to enable error: trace_macros! accepts only `true` or `false` --> $DIR/trace_macros-gate.rs:4:5 | -LL | trace_macros!(); //~ ERROR `trace_macros` is not stable +LL | trace_macros!(); | ^^^^^^^^^^^^^^^^ -error[E0658]: `trace_macros` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `trace_macros` is not stable enough for use and is subject to change --> $DIR/trace_macros-gate.rs:6:5 | -LL | trace_macros!(true); //~ ERROR `trace_macros` is not stable +LL | trace_macros!(true); | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(trace_macros)] to the crate attributes to enable -error[E0658]: `trace_macros` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `trace_macros` is not stable enough for use and is subject to change --> $DIR/trace_macros-gate.rs:7:5 | -LL | trace_macros!(false); //~ ERROR `trace_macros` is not stable +LL | trace_macros!(false); | ^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(trace_macros)] to the crate attributes to enable -error[E0658]: `trace_macros` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `trace_macros` is not stable enough for use and is subject to change --> $DIR/trace_macros-gate.rs:10:26 | -LL | ($x: ident) => { trace_macros!($x) } //~ ERROR `trace_macros` is not stable +LL | ($x: ident) => { trace_macros!($x) } | ^^^^^^^^^^^^^^^^^ ... LL | expando!(true); | --------------- in this macro invocation | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(trace_macros)] to the crate attributes to enable error: aborting due to 5 previous errors diff --git a/src/test/ui/trait-method-number-parameters.stderr b/src/test/ui/trait-method-number-parameters.stderr index 32101239e66c9..e47fe1a8026d5 100644 --- a/src/test/ui/trait-method-number-parameters.stderr +++ b/src/test/ui/trait-method-number-parameters.stderr @@ -4,7 +4,7 @@ error[E0050]: method `foo` has 2 parameters but the declaration in trait `Foo::f LL | fn foo(&mut self, x: i32, y: i32) -> i32; | ------------------------- trait requires 3 parameters ... -LL | / &mut self, //~ ERROR +LL | / &mut self, LL | | x: i32, | |______________^ expected 3 parameters, found 2 diff --git a/src/test/ui/traits/cycle-cache-err-60010.rs b/src/test/ui/traits/cycle-cache-err-60010.rs new file mode 100644 index 0000000000000..45aa1b3c52239 --- /dev/null +++ b/src/test/ui/traits/cycle-cache-err-60010.rs @@ -0,0 +1,71 @@ +// Test that we properly detect the cycle amongst the traits +// here and report an error. + +use std::panic::RefUnwindSafe; + +trait Database { + type Storage; +} +trait HasQueryGroup {} +trait Query { + type Data; +} +trait SourceDatabase { + fn parse(&self) { + loop {} + } +} + +struct ParseQuery; +struct RootDatabase { + _runtime: Runtime, +} +struct Runtime { + _storage: Box, +} +struct SalsaStorage { + _parse: >::Data, //~ ERROR overflow +} + +impl Database for RootDatabase { //~ ERROR overflow + type Storage = SalsaStorage; +} +impl HasQueryGroup for RootDatabase {} +impl Query for ParseQuery +where + DB: SourceDatabase, + DB: Database, +{ + type Data = RootDatabase; +} +impl SourceDatabase for T +where + T: RefUnwindSafe, + T: HasQueryGroup, +{ +} + +pub(crate) fn goto_implementation(db: &RootDatabase) -> u32 { + // This is not satisfied: + // + // - `RootDatabase: SourceDatabase` + // - requires `RootDatabase: RefUnwindSafe` + `RootDatabase: HasQueryGroup` + // - `RootDatabase: RefUnwindSafe` + // - requires `Runtime: RefUnwindSafe` + // - `Runtime: RefUnwindSafe` + // - requires `DB::Storage: RefUnwindSafe` (`SalsaStorage: RefUnwindSafe`) + // - `SalsaStorage: RefUnwindSafe` + // - requires `>::Data: RefUnwindSafe`, + // which means `ParseQuery: Query` + // - `ParseQuery: Query` + // - requires `RootDatabase: SourceDatabase`, + // - `RootDatabase: SourceDatabase` is already on the stack, so we have a + // cycle with non-coinductive participants + // + // we used to fail to report an error here because we got the + // caching wrong. + SourceDatabase::parse(db); + 22 +} + +fn main() {} diff --git a/src/test/ui/traits/cycle-cache-err-60010.stderr b/src/test/ui/traits/cycle-cache-err-60010.stderr new file mode 100644 index 0000000000000..9192f7ba2e3b0 --- /dev/null +++ b/src/test/ui/traits/cycle-cache-err-60010.stderr @@ -0,0 +1,20 @@ +error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase` + --> $DIR/cycle-cache-err-60010.rs:27:5 + | +LL | _parse: >::Data, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: required because of the requirements on the impl of `Query` for `ParseQuery` + +error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase` + --> $DIR/cycle-cache-err-60010.rs:30:6 + | +LL | impl Database for RootDatabase { + | ^^^^^^^^ + | + = note: required because of the requirements on the impl of `Query` for `ParseQuery` + = note: required because it appears within the type `SalsaStorage` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/traits/trait-alias-ambiguous.rs b/src/test/ui/traits/trait-alias-ambiguous.rs new file mode 100644 index 0000000000000..28409e0c66277 --- /dev/null +++ b/src/test/ui/traits/trait-alias-ambiguous.rs @@ -0,0 +1,24 @@ +#![feature(trait_alias)] + +mod inner { + pub trait A { fn foo(&self); } + pub trait B { fn foo(&self); } + + impl A for u8 { + fn foo(&self) {} + } + impl B for u8 { + fn foo(&self) {} + } + + pub trait C = A + B; +} + +use inner::C; + +fn main() { + let t = 1u8; + t.foo(); //~ ERROR E0034 + + inner::A::foo(&t); // ok +} diff --git a/src/test/ui/traits/trait-alias-ambiguous.stderr b/src/test/ui/traits/trait-alias-ambiguous.stderr new file mode 100644 index 0000000000000..b7443269b882d --- /dev/null +++ b/src/test/ui/traits/trait-alias-ambiguous.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/trait-alias-ambiguous.rs:21:7 + | +LL | t.foo(); + | ^^^ multiple `foo` found + | +note: candidate #1 is defined in an impl of the trait `inner::A` for the type `u8` + --> $DIR/trait-alias-ambiguous.rs:8:9 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `inner::B` for the type `u8` + --> $DIR/trait-alias-ambiguous.rs:11:9 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/src/test/ui/traits/trait-alias-object.rs b/src/test/ui/traits/trait-alias-object.rs deleted file mode 100644 index 379637401179b..0000000000000 --- a/src/test/ui/traits/trait-alias-object.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(trait_alias)] - -trait EqAlias = Eq; -trait IteratorAlias = Iterator; - -fn main() { - let _: &dyn EqAlias = &123; //~ ERROR `EqAlias` cannot be made into an object - let _: &dyn IteratorAlias = &vec![123].into_iter(); //~ ERROR must be specified -} diff --git a/src/test/ui/traits/trait-alias-object.stderr b/src/test/ui/traits/trait-alias-object.stderr deleted file mode 100644 index 604db6f7e1899..0000000000000 --- a/src/test/ui/traits/trait-alias-object.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0038]: the trait `EqAlias` cannot be made into an object - --> $DIR/trait-alias-object.rs:7:13 - | -LL | let _: &dyn EqAlias = &123; //~ ERROR `EqAlias` cannot be made into an object - | ^^^^^^^^^^^ the trait `EqAlias` cannot be made into an object - | - = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses - -error[E0191]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified - --> $DIR/trait-alias-object.rs:8:13 - | -LL | let _: &dyn IteratorAlias = &vec![123].into_iter(); //~ ERROR must be specified - | ^^^^^^^^^^^^^^^^^ associated type `Item` must be specified - -error: aborting due to 2 previous errors - -Some errors occurred: E0038, E0191. -For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/traits/trait-alias-syntax.stderr b/src/test/ui/traits/trait-alias-syntax.stderr deleted file mode 100644 index fc96f6274393d..0000000000000 --- a/src/test/ui/traits/trait-alias-syntax.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: trait aliases cannot be `auto` - --> $DIR/trait-alias-syntax.rs:4:19 - | -LL | auto trait A = Foo; //~ ERROR trait aliases cannot be `auto` - | ^ trait aliases cannot be `auto` - -error: trait aliases cannot be `unsafe` - --> $DIR/trait-alias-syntax.rs:5:21 - | -LL | unsafe trait B = Foo; //~ ERROR trait aliases cannot be `unsafe` - | ^ trait aliases cannot be `unsafe` - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/traits/auxiliary/trait_alias.rs b/src/test/ui/traits/trait-alias/auxiliary/trait_alias.rs similarity index 100% rename from src/test/ui/traits/auxiliary/trait_alias.rs rename to src/test/ui/traits/trait-alias/auxiliary/trait_alias.rs diff --git a/src/test/run-pass/traits/trait-alias-bounds.rs b/src/test/ui/traits/trait-alias/trait-alias-bounds.rs similarity index 96% rename from src/test/run-pass/traits/trait-alias-bounds.rs rename to src/test/ui/traits/trait-alias/trait-alias-bounds.rs index d3dd5cee0c33b..b97eb38c5af8d 100644 --- a/src/test/run-pass/traits/trait-alias-bounds.rs +++ b/src/test/ui/traits/trait-alias/trait-alias-bounds.rs @@ -1,3 +1,5 @@ +// run-pass + #![feature(trait_alias)] use std::marker::PhantomData; @@ -15,7 +17,7 @@ struct Foo(PhantomData); #[allow(dead_code)] struct Bar(PhantomData) where T: SendSyncAlias; -impl EmptyAlias {} +impl dyn EmptyAlias {} impl Empty for T {} diff --git a/src/test/ui/traits/trait-alias-cross-crate.rs b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.rs similarity index 100% rename from src/test/ui/traits/trait-alias-cross-crate.rs rename to src/test/ui/traits/trait-alias/trait-alias-cross-crate.rs diff --git a/src/test/ui/traits/trait-alias-cross-crate.stderr b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr similarity index 100% rename from src/test/ui/traits/trait-alias-cross-crate.stderr rename to src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr diff --git a/src/test/ui/traits/trait-alias-impl.rs b/src/test/ui/traits/trait-alias/trait-alias-impl.rs similarity index 100% rename from src/test/ui/traits/trait-alias-impl.rs rename to src/test/ui/traits/trait-alias/trait-alias-impl.rs diff --git a/src/test/ui/traits/trait-alias-impl.stderr b/src/test/ui/traits/trait-alias/trait-alias-impl.stderr similarity index 76% rename from src/test/ui/traits/trait-alias-impl.stderr rename to src/test/ui/traits/trait-alias/trait-alias-impl.stderr index 6a6cedb014a7e..301db4fb71c65 100644 --- a/src/test/ui/traits/trait-alias-impl.stderr +++ b/src/test/ui/traits/trait-alias/trait-alias-impl.stderr @@ -1,7 +1,7 @@ error[E0404]: expected trait, found trait alias `DefaultAlias` --> $DIR/trait-alias-impl.rs:5:6 | -LL | impl DefaultAlias for () {} //~ ERROR expected trait, found trait alias +LL | impl DefaultAlias for () {} | ^^^^^^^^^^^^ not a trait error: aborting due to previous error diff --git a/src/test/ui/traits/trait-alias/trait-alias-maybe-bound.rs b/src/test/ui/traits/trait-alias/trait-alias-maybe-bound.rs new file mode 100644 index 0000000000000..3dfcf03ce79da --- /dev/null +++ b/src/test/ui/traits/trait-alias/trait-alias-maybe-bound.rs @@ -0,0 +1,29 @@ +// compile-pass + +// Test that `dyn ... + ?Sized + ...` resulting from the expansion of trait aliases is okay. + +#![feature(trait_alias)] + +trait Foo {} + +trait S = ?Sized; + +// Nest a couple of levels deep: +trait _0 = S; +trait _1 = _0; + +// Straight list expansion: +type _T0 = dyn _1 + Foo; + +// In second position: +type _T1 = dyn Foo + _1; + +// ... and with an auto trait: +type _T2 = dyn Foo + Send + _1; + +// Twice: +trait _2 = _1 + _1; + +type _T3 = dyn _2 + Foo; + +fn main() {} diff --git a/src/test/ui/traits/trait-alias/trait-alias-no-duplicates.rs b/src/test/ui/traits/trait-alias/trait-alias-no-duplicates.rs new file mode 100644 index 0000000000000..88feb89170dd3 --- /dev/null +++ b/src/test/ui/traits/trait-alias/trait-alias-no-duplicates.rs @@ -0,0 +1,126 @@ +// The purpose of this test is to demonstrate that duplicating object safe traits +// that are not auto traits is rejected with trait aliases even though one could +// reasonably accept this. + +#![feature(trait_alias)] + +use std::marker::Unpin; + +// Some arbitrary object-safe trait: +trait Obj {} + +// Nest a few levels deep: +trait _0 = Obj; +trait _1 = _0; + +type _T00 = dyn _0 + _0; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T01 = dyn _1 + _0; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T02 = dyn _1 + _1; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T03 = dyn Obj + _1; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T04 = dyn _1 + Obj; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +// Nest some more and in weird ways: + +trait _2 = _0 + _1; +trait _3 = Obj; +trait _4 = _3; + +type _T10 = dyn _2 + _3; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T11 = dyn _3 + _2; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T12 = dyn Obj + _2; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T13 = dyn _2 + Obj; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T14 = dyn _1 + _3; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T15 = dyn _3 + _1; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T16 = dyn _1 + _4; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T17 = dyn _4 + _1; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +// Include auto traits: + +trait _5 = Obj + Send; + +type _T20 = dyn _5 + _5; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T21 = dyn Obj + _5; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T22 = dyn _5 + Obj; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T23 = dyn _5 + Send + Sync + Obj; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +// Also nest: + +trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send + +type _T30 = dyn _6; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T31 = dyn _6 + Send; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T32 = dyn Send + _6; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +// Nest some more: + +trait _7 = _5 + Sync; +trait _8 = Unpin + _7; + +type _T40 = dyn _8 + Obj; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T41 = dyn Obj + _8; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T42 = dyn _8 + _4; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T43 = dyn _4 + _8; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T44 = dyn _4 + Send + Sync + _8; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +// Take higher ranked types into account. + +// Note that `'a` and `'b` are intentionally different to make sure we consider +// them semantically the same. +trait ObjL<'l> {} +trait _9 = for<'a> ObjL<'a>; +trait _10 = for<'b> ObjL<'b>; +type _T50 = dyn _9 + _10; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +trait ObjT {} +trait _11 = ObjT fn(&'a u8)>; +trait _12 = ObjT fn(&'b u8)>; +type _T60 = dyn _11 + _12; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +fn main() {} diff --git a/src/test/ui/traits/trait-alias/trait-alias-no-duplicates.stderr b/src/test/ui/traits/trait-alias/trait-alias-no-duplicates.stderr new file mode 100644 index 0000000000000..6df1df86508ee --- /dev/null +++ b/src/test/ui/traits/trait-alias/trait-alias-no-duplicates.stderr @@ -0,0 +1,458 @@ +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:16:22 + | +LL | trait _0 = Obj; + | --- + | | + | additional non-auto trait + | first non-auto trait +... +LL | type _T00 = dyn _0 + _0; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:19:22 + | +LL | trait _0 = Obj; + | --- + | | + | additional non-auto trait + | first non-auto trait +LL | trait _1 = _0; + | -- referenced here (first use) +... +LL | type _T01 = dyn _1 + _0; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:22:22 + | +LL | trait _0 = Obj; + | --- + | | + | additional non-auto trait + | first non-auto trait +LL | trait _1 = _0; + | -- + | | + | referenced here (additional use) + | referenced here (first use) +... +LL | type _T02 = dyn _1 + _1; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:25:23 + | +LL | trait _0 = Obj; + | --- additional non-auto trait +LL | trait _1 = _0; + | -- referenced here (additional use) +... +LL | type _T03 = dyn Obj + _1; + | --- ^^ trait alias used in trait object type (additional use) + | | + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:28:22 + | +LL | trait _0 = Obj; + | --- first non-auto trait +LL | trait _1 = _0; + | -- referenced here (first use) +... +LL | type _T04 = dyn _1 + Obj; + | -- ^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:37:17 + | +LL | trait _0 = Obj; + | --- + | | + | additional non-auto trait + | first non-auto trait +LL | trait _1 = _0; + | -- referenced here (additional use) +... +LL | trait _2 = _0 + _1; + | -- -- referenced here (additional use) + | | + | referenced here (first use) +... +LL | type _T10 = dyn _2 + _3; + | ^^ + | | + | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:40:22 + | +LL | trait _0 = Obj; + | --- additional non-auto trait +... +LL | trait _2 = _0 + _1; + | -- referenced here (additional use) +LL | trait _3 = Obj; + | --- first non-auto trait +... +LL | type _T11 = dyn _3 + _2; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:43:23 + | +LL | trait _0 = Obj; + | --- additional non-auto trait +... +LL | trait _2 = _0 + _1; + | -- referenced here (additional use) +... +LL | type _T12 = dyn Obj + _2; + | --- ^^ trait alias used in trait object type (additional use) + | | + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:46:17 + | +LL | trait _0 = Obj; + | --- + | | + | additional non-auto trait + | first non-auto trait +LL | trait _1 = _0; + | -- referenced here (additional use) +... +LL | trait _2 = _0 + _1; + | -- -- referenced here (additional use) + | | + | referenced here (first use) +... +LL | type _T13 = dyn _2 + Obj; + | ^^ + | | + | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:49:22 + | +LL | trait _0 = Obj; + | --- first non-auto trait +LL | trait _1 = _0; + | -- referenced here (first use) +... +LL | trait _3 = Obj; + | --- additional non-auto trait +... +LL | type _T14 = dyn _1 + _3; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:52:22 + | +LL | trait _0 = Obj; + | --- additional non-auto trait +LL | trait _1 = _0; + | -- referenced here (additional use) +... +LL | trait _3 = Obj; + | --- first non-auto trait +... +LL | type _T15 = dyn _3 + _1; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:55:22 + | +LL | trait _0 = Obj; + | --- first non-auto trait +LL | trait _1 = _0; + | -- referenced here (first use) +... +LL | trait _3 = Obj; + | --- additional non-auto trait +LL | trait _4 = _3; + | -- referenced here (additional use) +... +LL | type _T16 = dyn _1 + _4; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:58:22 + | +LL | trait _0 = Obj; + | --- additional non-auto trait +LL | trait _1 = _0; + | -- referenced here (additional use) +... +LL | trait _3 = Obj; + | --- first non-auto trait +LL | trait _4 = _3; + | -- referenced here (first use) +... +LL | type _T17 = dyn _4 + _1; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:65:22 + | +LL | trait _5 = Obj + Send; + | --- + | | + | additional non-auto trait + | first non-auto trait +LL | +LL | type _T20 = dyn _5 + _5; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:68:23 + | +LL | trait _5 = Obj + Send; + | --- additional non-auto trait +... +LL | type _T21 = dyn Obj + _5; + | --- ^^ trait alias used in trait object type (additional use) + | | + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:71:22 + | +LL | trait _5 = Obj + Send; + | --- first non-auto trait +... +LL | type _T22 = dyn _5 + Obj; + | -- ^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:74:36 + | +LL | trait _5 = Obj + Send; + | --- first non-auto trait +... +LL | type _T23 = dyn _5 + Send + Sync + Obj; + | -- ^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:81:17 + | +LL | trait _5 = Obj + Send; + | --- + | | + | additional non-auto trait + | first non-auto trait +... +LL | trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send + | -- -- referenced here (additional use) + | | + | referenced here (first use) +LL | +LL | type _T30 = dyn _6; + | ^^ + | | + | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:84:17 + | +LL | trait _5 = Obj + Send; + | --- + | | + | additional non-auto trait + | first non-auto trait +... +LL | trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send + | -- -- referenced here (additional use) + | | + | referenced here (first use) +... +LL | type _T31 = dyn _6 + Send; + | ^^ + | | + | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:87:24 + | +LL | trait _5 = Obj + Send; + | --- + | | + | additional non-auto trait + | first non-auto trait +... +LL | trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send + | -- -- referenced here (additional use) + | | + | referenced here (first use) +... +LL | type _T32 = dyn Send + _6; + | ^^ + | | + | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:95:22 + | +LL | trait _5 = Obj + Send; + | --- first non-auto trait +... +LL | trait _7 = _5 + Sync; + | -- referenced here (first use) +LL | trait _8 = Unpin + _7; + | -- referenced here (first use) +LL | +LL | type _T40 = dyn _8 + Obj; + | -- ^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:98:23 + | +LL | trait _5 = Obj + Send; + | --- additional non-auto trait +... +LL | trait _7 = _5 + Sync; + | -- referenced here (additional use) +LL | trait _8 = Unpin + _7; + | -- referenced here (additional use) +... +LL | type _T41 = dyn Obj + _8; + | --- ^^ trait alias used in trait object type (additional use) + | | + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:101:22 + | +LL | trait _3 = Obj; + | --- additional non-auto trait +LL | trait _4 = _3; + | -- referenced here (additional use) +... +LL | trait _5 = Obj + Send; + | --- first non-auto trait +... +LL | trait _7 = _5 + Sync; + | -- referenced here (first use) +LL | trait _8 = Unpin + _7; + | -- referenced here (first use) +... +LL | type _T42 = dyn _8 + _4; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:104:22 + | +LL | trait _3 = Obj; + | --- first non-auto trait +LL | trait _4 = _3; + | -- referenced here (first use) +... +LL | trait _5 = Obj + Send; + | --- additional non-auto trait +... +LL | trait _7 = _5 + Sync; + | -- referenced here (additional use) +LL | trait _8 = Unpin + _7; + | -- referenced here (additional use) +... +LL | type _T43 = dyn _4 + _8; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:107:36 + | +LL | trait _3 = Obj; + | --- first non-auto trait +LL | trait _4 = _3; + | -- referenced here (first use) +... +LL | trait _5 = Obj + Send; + | --- additional non-auto trait +... +LL | trait _7 = _5 + Sync; + | -- referenced here (additional use) +LL | trait _8 = Unpin + _7; + | -- referenced here (additional use) +... +LL | type _T44 = dyn _4 + Send + Sync + _8; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:117:22 + | +LL | trait _9 = for<'a> ObjL<'a>; + | ---------------- first non-auto trait +LL | trait _10 = for<'b> ObjL<'b>; + | ---------------- additional non-auto trait +LL | type _T50 = dyn _9 + _10; + | -- ^^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-duplicates.rs:123:23 + | +LL | trait _11 = ObjT fn(&'a u8)>; + | ------------------------ first non-auto trait +LL | trait _12 = ObjT fn(&'b u8)>; + | ------------------------ additional non-auto trait +LL | type _T60 = dyn _11 + _12; + | --- ^^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error: aborting due to 27 previous errors + +For more information about this error, try `rustc --explain E0225`. diff --git a/src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.rs b/src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.rs new file mode 100644 index 0000000000000..4dad8c0f87349 --- /dev/null +++ b/src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.rs @@ -0,0 +1,121 @@ +// The purpose of this test is to demonstrate that trait alias expansion +// preserves the rule that `dyn Trait` may only reference one non-auto trait. + +#![feature(trait_alias)] + +use std::marker::Unpin; + +// Some arbitrary object-safe traits: +trait ObjA {} +trait ObjB {} + +// Nest a few levels deep: +trait _0 = ObjA; +trait _1 = _0; + +type _T00 = dyn _0 + ObjB; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T01 = dyn ObjB + _0; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T02 = dyn ObjB + _1; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T03 = dyn _1 + ObjB; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +// Nest some more and in weird ways: + +trait _2 = ObjB; +trait _3 = _2; +trait _4 = _3; + +type _T10 = dyn _2 + _3; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T11 = dyn _3 + _2; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T12 = dyn _2 + _4; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T13 = dyn _4 + _2; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +// Include auto traits: + +trait _5 = Sync + ObjB + Send; + +type _T20 = dyn _5 + _1; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T21 = dyn _1 + _5; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T22 = dyn _5 + ObjA; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T23 = dyn ObjA + _5; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T24 = dyn Send + _5 + _1 + Sync; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T25 = dyn _1 + Sync + _5 + Send; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T26 = dyn Sync + Send + _5 + ObjA; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T27 = dyn Send + Sync + ObjA + _5; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +// Also nest: + +trait _6 = _1 + _5; +trait _7 = _6; +trait _8 = _7; + +type _T30 = dyn _6; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T31 = dyn _6 + Send; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T32 = dyn Send + _6; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T33 = dyn _8; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T34 = dyn _8 + Send; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T35 = dyn Send + _8; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +// Nest some more: + +trait _9 = _5 + Sync; +trait _10 = Unpin + _9; + +type _T40 = dyn _10 + ObjA; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T41 = dyn ObjA + _10; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T42 = dyn _10 + _1; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T43 = dyn Send + _10 + Sync + ObjA; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T44 = dyn ObjA + _10 + Send + Sync; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _T45 = dyn Sync + Send + _10 + _1; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +fn main() {} diff --git a/src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.stderr b/src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.stderr new file mode 100644 index 0000000000000..15685a228833d --- /dev/null +++ b/src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.stderr @@ -0,0 +1,513 @@ +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:16:22 + | +LL | trait _0 = ObjA; + | ---- first non-auto trait +... +LL | type _T00 = dyn _0 + ObjB; + | -- ^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:19:24 + | +LL | trait _0 = ObjA; + | ---- additional non-auto trait +... +LL | type _T01 = dyn ObjB + _0; + | ---- ^^ trait alias used in trait object type (additional use) + | | + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:22:24 + | +LL | trait _0 = ObjA; + | ---- additional non-auto trait +LL | trait _1 = _0; + | -- referenced here (additional use) +... +LL | type _T02 = dyn ObjB + _1; + | ---- ^^ trait alias used in trait object type (additional use) + | | + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:25:22 + | +LL | trait _0 = ObjA; + | ---- first non-auto trait +LL | trait _1 = _0; + | -- referenced here (first use) +... +LL | type _T03 = dyn _1 + ObjB; + | -- ^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:34:22 + | +LL | trait _2 = ObjB; + | ---- + | | + | additional non-auto trait + | first non-auto trait +LL | trait _3 = _2; + | -- referenced here (additional use) +... +LL | type _T10 = dyn _2 + _3; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:37:22 + | +LL | trait _2 = ObjB; + | ---- + | | + | additional non-auto trait + | first non-auto trait +LL | trait _3 = _2; + | -- referenced here (first use) +... +LL | type _T11 = dyn _3 + _2; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:40:22 + | +LL | trait _2 = ObjB; + | ---- + | | + | additional non-auto trait + | first non-auto trait +LL | trait _3 = _2; + | -- referenced here (additional use) +LL | trait _4 = _3; + | -- referenced here (additional use) +... +LL | type _T12 = dyn _2 + _4; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:43:22 + | +LL | trait _2 = ObjB; + | ---- + | | + | additional non-auto trait + | first non-auto trait +LL | trait _3 = _2; + | -- referenced here (first use) +LL | trait _4 = _3; + | -- referenced here (first use) +... +LL | type _T13 = dyn _4 + _2; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:50:22 + | +LL | trait _0 = ObjA; + | ---- additional non-auto trait +LL | trait _1 = _0; + | -- referenced here (additional use) +... +LL | trait _5 = Sync + ObjB + Send; + | ---- first non-auto trait +LL | +LL | type _T20 = dyn _5 + _1; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:53:22 + | +LL | trait _0 = ObjA; + | ---- first non-auto trait +LL | trait _1 = _0; + | -- referenced here (first use) +... +LL | trait _5 = Sync + ObjB + Send; + | ---- additional non-auto trait +... +LL | type _T21 = dyn _1 + _5; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:56:22 + | +LL | trait _5 = Sync + ObjB + Send; + | ---- first non-auto trait +... +LL | type _T22 = dyn _5 + ObjA; + | -- ^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:59:24 + | +LL | trait _5 = Sync + ObjB + Send; + | ---- additional non-auto trait +... +LL | type _T23 = dyn ObjA + _5; + | ---- ^^ trait alias used in trait object type (additional use) + | | + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:62:29 + | +LL | trait _0 = ObjA; + | ---- additional non-auto trait +LL | trait _1 = _0; + | -- referenced here (additional use) +... +LL | trait _5 = Sync + ObjB + Send; + | ---- first non-auto trait +... +LL | type _T24 = dyn Send + _5 + _1 + Sync; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:65:29 + | +LL | trait _0 = ObjA; + | ---- first non-auto trait +LL | trait _1 = _0; + | -- referenced here (first use) +... +LL | trait _5 = Sync + ObjB + Send; + | ---- additional non-auto trait +... +LL | type _T25 = dyn _1 + Sync + _5 + Send; + | -- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:68:36 + | +LL | trait _5 = Sync + ObjB + Send; + | ---- first non-auto trait +... +LL | type _T26 = dyn Sync + Send + _5 + ObjA; + | -- ^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:71:38 + | +LL | trait _5 = Sync + ObjB + Send; + | ---- additional non-auto trait +... +LL | type _T27 = dyn Send + Sync + ObjA + _5; + | ---- ^^ trait alias used in trait object type (additional use) + | | + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:80:17 + | +LL | trait _0 = ObjA; + | ---- first non-auto trait +LL | trait _1 = _0; + | -- referenced here (first use) +... +LL | trait _5 = Sync + ObjB + Send; + | ---- additional non-auto trait +... +LL | trait _6 = _1 + _5; + | -- -- referenced here (additional use) + | | + | referenced here (first use) +... +LL | type _T30 = dyn _6; + | ^^ + | | + | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:83:17 + | +LL | trait _0 = ObjA; + | ---- first non-auto trait +LL | trait _1 = _0; + | -- referenced here (first use) +... +LL | trait _5 = Sync + ObjB + Send; + | ---- additional non-auto trait +... +LL | trait _6 = _1 + _5; + | -- -- referenced here (additional use) + | | + | referenced here (first use) +... +LL | type _T31 = dyn _6 + Send; + | ^^ + | | + | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:86:24 + | +LL | trait _0 = ObjA; + | ---- first non-auto trait +LL | trait _1 = _0; + | -- referenced here (first use) +... +LL | trait _5 = Sync + ObjB + Send; + | ---- additional non-auto trait +... +LL | trait _6 = _1 + _5; + | -- -- referenced here (additional use) + | | + | referenced here (first use) +... +LL | type _T32 = dyn Send + _6; + | ^^ + | | + | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:89:17 + | +LL | trait _0 = ObjA; + | ---- first non-auto trait +LL | trait _1 = _0; + | -- referenced here (first use) +... +LL | trait _5 = Sync + ObjB + Send; + | ---- additional non-auto trait +... +LL | trait _6 = _1 + _5; + | -- -- referenced here (additional use) + | | + | referenced here (first use) +LL | trait _7 = _6; + | -- + | | + | referenced here (additional use) + | referenced here (first use) +LL | trait _8 = _7; + | -- + | | + | referenced here (additional use) + | referenced here (first use) +... +LL | type _T33 = dyn _8; + | ^^ + | | + | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:92:17 + | +LL | trait _0 = ObjA; + | ---- first non-auto trait +LL | trait _1 = _0; + | -- referenced here (first use) +... +LL | trait _5 = Sync + ObjB + Send; + | ---- additional non-auto trait +... +LL | trait _6 = _1 + _5; + | -- -- referenced here (additional use) + | | + | referenced here (first use) +LL | trait _7 = _6; + | -- + | | + | referenced here (additional use) + | referenced here (first use) +LL | trait _8 = _7; + | -- + | | + | referenced here (additional use) + | referenced here (first use) +... +LL | type _T34 = dyn _8 + Send; + | ^^ + | | + | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:95:24 + | +LL | trait _0 = ObjA; + | ---- first non-auto trait +LL | trait _1 = _0; + | -- referenced here (first use) +... +LL | trait _5 = Sync + ObjB + Send; + | ---- additional non-auto trait +... +LL | trait _6 = _1 + _5; + | -- -- referenced here (additional use) + | | + | referenced here (first use) +LL | trait _7 = _6; + | -- + | | + | referenced here (additional use) + | referenced here (first use) +LL | trait _8 = _7; + | -- + | | + | referenced here (additional use) + | referenced here (first use) +... +LL | type _T35 = dyn Send + _8; + | ^^ + | | + | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:103:23 + | +LL | trait _5 = Sync + ObjB + Send; + | ---- first non-auto trait +... +LL | trait _9 = _5 + Sync; + | -- referenced here (first use) +LL | trait _10 = Unpin + _9; + | -- referenced here (first use) +LL | +LL | type _T40 = dyn _10 + ObjA; + | --- ^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:106:24 + | +LL | trait _5 = Sync + ObjB + Send; + | ---- additional non-auto trait +... +LL | trait _9 = _5 + Sync; + | -- referenced here (additional use) +LL | trait _10 = Unpin + _9; + | -- referenced here (additional use) +... +LL | type _T41 = dyn ObjA + _10; + | ---- ^^^ trait alias used in trait object type (additional use) + | | + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:109:23 + | +LL | trait _0 = ObjA; + | ---- additional non-auto trait +LL | trait _1 = _0; + | -- referenced here (additional use) +... +LL | trait _5 = Sync + ObjB + Send; + | ---- first non-auto trait +... +LL | trait _9 = _5 + Sync; + | -- referenced here (first use) +LL | trait _10 = Unpin + _9; + | -- referenced here (first use) +... +LL | type _T42 = dyn _10 + _1; + | --- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:112:37 + | +LL | trait _5 = Sync + ObjB + Send; + | ---- first non-auto trait +... +LL | trait _9 = _5 + Sync; + | -- referenced here (first use) +LL | trait _10 = Unpin + _9; + | -- referenced here (first use) +... +LL | type _T43 = dyn Send + _10 + Sync + ObjA; + | --- ^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:115:24 + | +LL | trait _5 = Sync + ObjB + Send; + | ---- additional non-auto trait +... +LL | trait _9 = _5 + Sync; + | -- referenced here (additional use) +LL | trait _10 = Unpin + _9; + | -- referenced here (additional use) +... +LL | type _T44 = dyn ObjA + _10 + Send + Sync; + | ---- ^^^ trait alias used in trait object type (additional use) + | | + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-no-extra-traits.rs:118:37 + | +LL | trait _0 = ObjA; + | ---- additional non-auto trait +LL | trait _1 = _0; + | -- referenced here (additional use) +... +LL | trait _5 = Sync + ObjB + Send; + | ---- first non-auto trait +... +LL | trait _9 = _5 + Sync; + | -- referenced here (first use) +LL | trait _10 = Unpin + _9; + | -- referenced here (first use) +... +LL | type _T45 = dyn Sync + Send + _10 + _1; + | --- ^^ trait alias used in trait object type (additional use) + | | + | trait alias used in trait object type (first use) + +error: aborting due to 28 previous errors + +For more information about this error, try `rustc --explain E0225`. diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs b/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs new file mode 100644 index 0000000000000..d62fd7e59c920 --- /dev/null +++ b/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs @@ -0,0 +1,11 @@ +#![feature(trait_alias)] + +trait EqAlias = Eq; +trait IteratorAlias = Iterator; + +fn main() { + let _: &dyn EqAlias = &123; + //~^ ERROR the trait `std::cmp::Eq` cannot be made into an object [E0038] + let _: &dyn IteratorAlias = &vec![123].into_iter(); + //~^ ERROR must be specified +} diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr new file mode 100644 index 0000000000000..9a9b917703085 --- /dev/null +++ b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr @@ -0,0 +1,18 @@ +error[E0038]: the trait `std::cmp::Eq` cannot be made into an object + --> $DIR/trait-alias-object-fail.rs:7:13 + | +LL | let _: &dyn EqAlias = &123; + | ^^^^^^^^^^^ the trait `std::cmp::Eq` cannot be made into an object + | + = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses + +error[E0191]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified + --> $DIR/trait-alias-object-fail.rs:9:13 + | +LL | let _: &dyn IteratorAlias = &vec![123].into_iter(); + | ^^^^^^^^^^^^^^^^^ associated type `Item` must be specified + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0038, E0191. +For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-wf.rs b/src/test/ui/traits/trait-alias/trait-alias-object-wf.rs new file mode 100644 index 0000000000000..fb26b7e2df7cb --- /dev/null +++ b/src/test/ui/traits/trait-alias/trait-alias-object-wf.rs @@ -0,0 +1,85 @@ +// run-pass + +// This test checks that trait objects involving trait aliases are well-formed. + +#![feature(trait_alias)] + +trait Obj {} + +trait _0 = Send + Sync; + +// Just auto traits: + +trait _1 = _0 + Send + Sync; + +use std::marker::Unpin; + +fn _f0() { + let _: Box; + let _: Box; + let _: Box; +} + +// Include object safe traits: + +fn _f1() { + let _: Box; + let _: Box; + let _: Box; +} + +// And when the object safe trait is in a trait alias: + +trait _2 = Obj; + +fn _f2() { + let _: Box; + let _: Box; + let _: Box; +} + +// And it should also work when that trait is has auto traits to the right of it. + +trait _3 = Obj + Unpin; + +fn _f3() { + let _: Box; + let _: Box; + let _: Box; +} + +// Nest the trait deeply: + +trait _4 = _3; +trait _5 = _4 + Sync + _0 + Send; +trait _6 = _5 + Send + _1 + Sync; + +fn _f4() { + let _: Box; + let _: Box; + let _: Box; +} + +// Just nest the trait alone: + +trait _7 = _2; +trait _8 = _7; +trait _9 = _8; + +fn _f5() { + let _: Box; +} + +// First bound is auto trait: + +trait _10 = Send + Obj; +trait _11 = Obj + Send; +trait _12 = Sync + _11; +trait _13 = Send + _12; + +fn f6() { + let _: Box; + let _: Box; +} + +fn main() {} diff --git a/src/test/ui/traits/trait-alias/trait-alias-object.rs b/src/test/ui/traits/trait-alias/trait-alias-object.rs new file mode 100644 index 0000000000000..12177cd827fdf --- /dev/null +++ b/src/test/ui/traits/trait-alias/trait-alias-object.rs @@ -0,0 +1,18 @@ +// run-pass + +#![feature(trait_alias)] + +trait Foo = PartialEq + Send; +trait Bar = Foo + Sync; + +trait I32Iterator = Iterator; + +pub fn main() { + let a: &dyn Bar = &123; + assert!(*a == 123); + let b = Box::new(456) as Box; + assert!(*b == 456); + + let c: &mut dyn I32Iterator = &mut vec![123].into_iter(); + assert_eq!(c.next(), Some(123)); +} diff --git a/src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.rs b/src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.rs new file mode 100644 index 0000000000000..e4abf314e0a96 --- /dev/null +++ b/src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.rs @@ -0,0 +1,22 @@ +// Test that `dyn ?Sized` (i.e., a trait object with only a maybe buond) is not allowed, when just +// `?Sized` results from trait alias expansion. + +#![feature(trait_alias)] + +trait S = ?Sized; + +// Nest a couple of levels deep: +trait _0 = S; +trait _1 = _0; + +// Straight list expansion: +type _T0 = dyn _1; +//~^ ERROR at least one trait is required for an object type [E0224] + +// Twice: +trait _2 = _1 + _1; + +type _T1 = dyn _2; +//~^ ERROR at least one trait is required for an object type [E0224] + +fn main() {} diff --git a/src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.stderr b/src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.stderr new file mode 100644 index 0000000000000..6de79fa917b16 --- /dev/null +++ b/src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.stderr @@ -0,0 +1,14 @@ +error[E0224]: at least one trait is required for an object type + --> $DIR/trait-alias-only-maybe-bound.rs:13:12 + | +LL | type _T0 = dyn _1; + | ^^^^^^ + +error[E0224]: at least one trait is required for an object type + --> $DIR/trait-alias-only-maybe-bound.rs:19:12 + | +LL | type _T1 = dyn _2; + | ^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/traits/trait-alias-syntax.rs b/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.rs similarity index 100% rename from src/test/ui/traits/trait-alias-syntax.rs rename to src/test/ui/traits/trait-alias/trait-alias-syntax-fail.rs diff --git a/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.stderr b/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.stderr new file mode 100644 index 0000000000000..f456a2d778c25 --- /dev/null +++ b/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.stderr @@ -0,0 +1,14 @@ +error: trait aliases cannot be `auto` + --> $DIR/trait-alias-syntax-fail.rs:4:19 + | +LL | auto trait A = Foo; + | ^ trait aliases cannot be `auto` + +error: trait aliases cannot be `unsafe` + --> $DIR/trait-alias-syntax-fail.rs:5:21 + | +LL | unsafe trait B = Foo; + | ^ trait aliases cannot be `unsafe` + +error: aborting due to 2 previous errors + diff --git a/src/test/run-pass/traits/trait-alias-syntax.rs b/src/test/ui/traits/trait-alias/trait-alias-syntax.rs similarity index 97% rename from src/test/run-pass/traits/trait-alias-syntax.rs rename to src/test/ui/traits/trait-alias/trait-alias-syntax.rs index 7cdd9184d3f5c..17557a51aa723 100644 --- a/src/test/run-pass/traits/trait-alias-syntax.rs +++ b/src/test/ui/traits/trait-alias/trait-alias-syntax.rs @@ -1,3 +1,5 @@ +// run-pass + #![feature(trait_alias)] trait SimpleAlias = Default; diff --git a/src/test/ui/traits/trait-alias-wf.rs b/src/test/ui/traits/trait-alias/trait-alias-wf.rs similarity index 100% rename from src/test/ui/traits/trait-alias-wf.rs rename to src/test/ui/traits/trait-alias/trait-alias-wf.rs diff --git a/src/test/ui/traits/trait-alias-wf.stderr b/src/test/ui/traits/trait-alias/trait-alias-wf.stderr similarity index 87% rename from src/test/ui/traits/trait-alias-wf.stderr rename to src/test/ui/traits/trait-alias/trait-alias-wf.stderr index 1f64ce76dc6b7..ee2dd5b24afed 100644 --- a/src/test/ui/traits/trait-alias-wf.stderr +++ b/src/test/ui/traits/trait-alias/trait-alias-wf.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `T: Foo` is not satisfied --> $DIR/trait-alias-wf.rs:5:1 | -LL | trait B = A; //~ ERROR `T: Foo` is not satisfied +LL | trait B = A; | ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `T` | = help: consider adding a `where T: Foo` bound diff --git a/src/test/ui/run-pass/traits/trait-alias.rs b/src/test/ui/traits/trait-alias/trait-alias.rs similarity index 98% rename from src/test/ui/run-pass/traits/trait-alias.rs rename to src/test/ui/traits/trait-alias/trait-alias.rs index 9be5664869e05..d8168f2990c46 100644 --- a/src/test/ui/run-pass/traits/trait-alias.rs +++ b/src/test/ui/traits/trait-alias/trait-alias.rs @@ -1,4 +1,5 @@ // run-pass + #![feature(trait_alias)] pub trait Foo {} diff --git a/src/test/ui/traits/trait-as-struct-constructor.stderr b/src/test/ui/traits/trait-as-struct-constructor.stderr index e1d54fbf8aa7b..434dcbc8736aa 100644 --- a/src/test/ui/traits/trait-as-struct-constructor.stderr +++ b/src/test/ui/traits/trait-as-struct-constructor.stderr @@ -6,4 +6,3 @@ LL | TraitNotAStruct{ value: 0 }; error: aborting due to previous error -For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/traits/trait-bounds-not-on-bare-trait.rs b/src/test/ui/traits/trait-bounds-not-on-bare-trait.rs index fd3af6f3a9aaa..33c9f2f00cfee 100644 --- a/src/test/ui/traits/trait-bounds-not-on-bare-trait.rs +++ b/src/test/ui/traits/trait-bounds-not-on-bare-trait.rs @@ -6,6 +6,7 @@ trait Foo { fn foo(_x: Foo + Send) { //~^ ERROR the size for values of type + //~| WARN trait objects without an explicit `dyn` are deprecated } fn main() { } diff --git a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr index 5aee1e7e982a8..250ea4b1c3201 100644 --- a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr +++ b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr @@ -1,3 +1,11 @@ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/trait-bounds-not-on-bare-trait.rs:7:12 + | +LL | fn foo(_x: Foo + Send) { + | ^^^^^^^^^^ help: use `dyn`: `dyn Foo + Send` + | + = note: #[warn(bare_trait_objects)] on by default + error[E0277]: the size for values of type `(dyn Foo + std::marker::Send + 'static)` cannot be known at compilation time --> $DIR/trait-bounds-not-on-bare-trait.rs:7:8 | diff --git a/src/test/ui/traits/trait-bounds-not-on-struct.stderr b/src/test/ui/traits/trait-bounds-not-on-struct.stderr index 1595fff618f05..a649a4eee5570 100644 --- a/src/test/ui/traits/trait-bounds-not-on-struct.stderr +++ b/src/test/ui/traits/trait-bounds-not-on-struct.stderr @@ -1,13 +1,13 @@ error[E0404]: expected trait, found struct `Foo` --> $DIR/trait-bounds-not-on-struct.rs:5:16 | -LL | fn foo(_x: Box) { } //~ ERROR expected trait, found struct `Foo` +LL | fn foo(_x: Box) { } | ^^^ not a trait error[E0404]: expected trait, found struct `Vec` --> $DIR/trait-bounds-not-on-struct.rs:7:21 | -LL | type A = Box>; //~ ERROR expected trait, found struct `Vec` +LL | type A = Box>; | ^^^^^^ not a trait error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr index 5429029c1ec91..9a4cc90f3a5e0 100644 --- a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr +++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr @@ -14,7 +14,7 @@ LL | struct Foo { error[E0277]: the trait bound `isize: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:19:5 | -LL | a: Foo, //~ ERROR E0277 +LL | a: Foo, | ^^^^^^^^^^^^^ the trait `Trait` is not implemented for `isize` | note: required by `Foo` @@ -26,7 +26,7 @@ LL | struct Foo { error[E0277]: the trait bound `usize: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:23:10 | -LL | Quux(Bar), //~ ERROR E0277 +LL | Quux(Bar), | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize` | note: required by `Bar` @@ -38,7 +38,7 @@ LL | enum Bar { error[E0277]: the trait bound `U: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:27:5 | -LL | b: Foo, //~ ERROR E0277 +LL | b: Foo, | ^^^^^^^^^ the trait `Trait` is not implemented for `U` | = help: consider adding a `where U: Trait` bound @@ -51,7 +51,7 @@ LL | struct Foo { error[E0277]: the trait bound `V: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:31:21 | -LL | EvenMoreBadness(Bar), //~ ERROR E0277 +LL | EvenMoreBadness(Bar), | ^^^^^^ the trait `Trait` is not implemented for `V` | = help: consider adding a `where V: Trait` bound @@ -64,7 +64,7 @@ LL | enum Bar { error[E0277]: the trait bound `i32: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:35:5 | -LL | Foo, //~ ERROR E0277 +LL | Foo, | ^^^^^^^^ the trait `Trait` is not implemented for `i32` | note: required by `Foo` @@ -76,7 +76,7 @@ LL | struct Foo { error[E0277]: the trait bound `u8: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:39:22 | -LL | DictionaryLike { field: Bar }, //~ ERROR E0277 +LL | DictionaryLike { field: Bar }, | ^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u8` | note: required by `Bar` diff --git a/src/test/ui/traits/trait-bounds-sugar.rs b/src/test/ui/traits/trait-bounds-sugar.rs index 0892153c0cf86..65b6f6faa4250 100644 --- a/src/test/ui/traits/trait-bounds-sugar.rs +++ b/src/test/ui/traits/trait-bounds-sugar.rs @@ -2,17 +2,17 @@ trait Foo {} -fn a(_x: Box) { +fn a(_x: Box) { } -fn b(_x: &'static (Foo+'static)) { +fn b(_x: &'static (dyn Foo + 'static)) { } -fn c(x: Box) { +fn c(x: Box) { a(x); //~ ERROR mismatched types } -fn d(x: &'static (Foo+Sync)) { +fn d(x: &'static (dyn Foo + Sync)) { b(x); } diff --git a/src/test/ui/traits/trait-bounds-sugar.stderr b/src/test/ui/traits/trait-bounds-sugar.stderr index eb45a16afb1c8..2aa025cb7a682 100644 --- a/src/test/ui/traits/trait-bounds-sugar.stderr +++ b/src/test/ui/traits/trait-bounds-sugar.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/trait-bounds-sugar.rs:12:7 | -LL | a(x); //~ ERROR mismatched types +LL | a(x); | ^ expected trait `Foo + std::marker::Send`, found trait `Foo + std::marker::Sync` | = note: expected type `std::boxed::Box<(dyn Foo + std::marker::Send + 'static)>` diff --git a/src/test/ui/traits/trait-coercion-generic-bad.rs b/src/test/ui/traits/trait-coercion-generic-bad.rs index 5aa2183414820..2e115c732b9d7 100644 --- a/src/test/ui/traits/trait-coercion-generic-bad.rs +++ b/src/test/ui/traits/trait-coercion-generic-bad.rs @@ -13,7 +13,7 @@ impl Trait<&'static str> for Struct { } fn main() { - let s: Box> = Box::new(Struct { person: "Fred" }); + let s: Box> = Box::new(Struct { person: "Fred" }); //~^ ERROR `Struct: Trait` is not satisfied s.f(1); } diff --git a/src/test/ui/traits/trait-coercion-generic-bad.stderr b/src/test/ui/traits/trait-coercion-generic-bad.stderr index 7f3b46b8ae52d..f2710dea0952f 100644 --- a/src/test/ui/traits/trait-coercion-generic-bad.stderr +++ b/src/test/ui/traits/trait-coercion-generic-bad.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `Struct: Trait` is not satisfied - --> $DIR/trait-coercion-generic-bad.rs:16:32 + --> $DIR/trait-coercion-generic-bad.rs:16:36 | -LL | let s: Box> = Box::new(Struct { person: "Fred" }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `Struct` +LL | let s: Box> = Box::new(Struct { person: "Fred" }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `Struct` | = help: the following implementations were found: > diff --git a/src/test/ui/traits/trait-coercion-generic-regions.nll.stderr b/src/test/ui/traits/trait-coercion-generic-regions.nll.stderr deleted file mode 100644 index 6092a9dc10d3c..0000000000000 --- a/src/test/ui/traits/trait-coercion-generic-regions.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0597]: `person` does not live long enough - --> $DIR/trait-coercion-generic-regions.rs:17:24 - | -LL | let person: &str = &person; //~ ERROR `person` does not live long enough - | ^^^^^^^ - | | - | borrowed value does not live long enough - | assignment requires that `person` is borrowed for `'static` -LL | let s: Box> = Box::new(Struct { person: person }); -LL | } - | - `person` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/traits/trait-coercion-generic-regions.rs b/src/test/ui/traits/trait-coercion-generic-regions.rs index 148b7dd5c43da..af478df6dfa99 100644 --- a/src/test/ui/traits/trait-coercion-generic-regions.rs +++ b/src/test/ui/traits/trait-coercion-generic-regions.rs @@ -15,5 +15,5 @@ impl Trait<&'static str> for Struct { fn main() { let person = "Fred".to_string(); let person: &str = &person; //~ ERROR `person` does not live long enough - let s: Box> = Box::new(Struct { person: person }); + let s: Box> = Box::new(Struct { person: person }); } diff --git a/src/test/ui/traits/trait-coercion-generic-regions.stderr b/src/test/ui/traits/trait-coercion-generic-regions.stderr index 23c2a72743eea..d21b48e571df9 100644 --- a/src/test/ui/traits/trait-coercion-generic-regions.stderr +++ b/src/test/ui/traits/trait-coercion-generic-regions.stderr @@ -1,13 +1,14 @@ error[E0597]: `person` does not live long enough - --> $DIR/trait-coercion-generic-regions.rs:17:25 + --> $DIR/trait-coercion-generic-regions.rs:17:24 | -LL | let person: &str = &person; //~ ERROR `person` does not live long enough - | ^^^^^^ borrowed value does not live long enough -LL | let s: Box> = Box::new(Struct { person: person }); +LL | let person: &str = &person; + | ^^^^^^^ + | | + | borrowed value does not live long enough + | assignment requires that `person` is borrowed for `'static` +LL | let s: Box> = Box::new(Struct { person: person }); LL | } - | - borrowed value only lives until here - | - = note: borrowed value must be valid for the static lifetime... + | - `person` dropped here while still borrowed error: aborting due to previous error diff --git a/src/test/ui/traits/trait-duplicate-methods.stderr b/src/test/ui/traits/trait-duplicate-methods.stderr index bb6d0b6d7f148..7cba4cb63e6b0 100644 --- a/src/test/ui/traits/trait-duplicate-methods.stderr +++ b/src/test/ui/traits/trait-duplicate-methods.stderr @@ -3,7 +3,7 @@ error[E0428]: the name `orange` is defined multiple times | LL | fn orange(&self); | ----------------- previous definition of the value `orange` here -LL | fn orange(&self); //~ ERROR the name `orange` is defined multiple times +LL | fn orange(&self); | ^^^^^^^^^^^^^^^^^ `orange` redefined here | = note: `orange` must be defined only once in the value namespace of this trait diff --git a/src/test/ui/traits/trait-impl-1.rs b/src/test/ui/traits/trait-impl-1.rs index 29f58a6a9cbc1..43b822218354f 100644 --- a/src/test/ui/traits/trait-impl-1.rs +++ b/src/test/ui/traits/trait-impl-1.rs @@ -4,7 +4,7 @@ trait T {} -impl<'a> T+'a { +impl<'a> dyn T + 'a { fn foo(&self) {} } diff --git a/src/test/ui/traits/trait-impl-1.stderr b/src/test/ui/traits/trait-impl-1.stderr index 8ee642974b724..71d5cc26bf141 100644 --- a/src/test/ui/traits/trait-impl-1.stderr +++ b/src/test/ui/traits/trait-impl-1.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `foo` found for type `&i32` in the current scope --> $DIR/trait-impl-1.rs:15:7 | -LL | x.foo(); //~ERROR: no method named `foo` found for type `&i32` in the current scope +LL | x.foo(); | ^^^ error: aborting due to previous error diff --git a/src/test/ui/traits/trait-impl-can-not-have-untraitful-items.stderr b/src/test/ui/traits/trait-impl-can-not-have-untraitful-items.stderr index 5a50a11086326..0abed79d38470 100644 --- a/src/test/ui/traits/trait-impl-can-not-have-untraitful-items.stderr +++ b/src/test/ui/traits/trait-impl-can-not-have-untraitful-items.stderr @@ -1,22 +1,22 @@ error[E0438]: const `BAR` is not a member of trait `A` --> $DIR/trait-impl-can-not-have-untraitful-items.rs:4:5 | -LL | const BAR: () = (); //~ ERROR const `BAR` is not a member of trait `A` +LL | const BAR: () = (); | ^^^^^^^^^^^^^^^^^^^ not a member of trait `A` error[E0437]: type `Baz` is not a member of trait `A` --> $DIR/trait-impl-can-not-have-untraitful-items.rs:5:5 | -LL | type Baz = (); //~ ERROR type `Baz` is not a member of trait `A` +LL | type Baz = (); | ^^^^^^^^^^^^^^ not a member of trait `A` error[E0407]: method `foo` is not a member of trait `A` --> $DIR/trait-impl-can-not-have-untraitful-items.rs:6:5 | -LL | fn foo(&self) { } //~ ERROR method `foo` is not a member of trait `A` +LL | fn foo(&self) { } | ^^^^^^^^^^^^^^^^^ not a member of trait `A` error: aborting due to 3 previous errors -Some errors occurred: E0407, E0437, E0438. +Some errors have detailed explanations: E0407, E0437, E0438. For more information about an error, try `rustc --explain E0407`. diff --git a/src/test/ui/traits/trait-impl-for-module.stderr b/src/test/ui/traits/trait-impl-for-module.stderr index 99da4b7c87af0..4a06cd777d49e 100644 --- a/src/test/ui/traits/trait-impl-for-module.stderr +++ b/src/test/ui/traits/trait-impl-for-module.stderr @@ -1,9 +1,8 @@ error[E0573]: expected type, found module `a` --> $DIR/trait-impl-for-module.rs:7:12 | -LL | impl A for a { //~ ERROR expected type, found module +LL | impl A for a { | ^ help: a trait with a similar name exists: `A` error: aborting due to previous error -For more information about this error, try `rustc --explain E0573`. diff --git a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr index 95dc6364e13c5..fb417b82d15ce 100644 --- a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr +++ b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr @@ -1,18 +1,18 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements --> $DIR/trait-impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:13 | -LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { //~ ERROR cannot infer an appropriate lifetime +LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { | ^^^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 24:6... --> $DIR/trait-impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:6 | -LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { //~ ERROR cannot infer an appropriate lifetime +LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { | ^^ note: ...but the lifetime must also be valid for the lifetime 'b as defined on the impl at 24:9... --> $DIR/trait-impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:9 | -LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { //~ ERROR cannot infer an appropriate lifetime +LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { | ^^ = note: ...so that the types are compatible: expected T1<'a> @@ -20,4 +20,3 @@ LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { //~ ERROR cannot infer an appropriat error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/traits/trait-item-privacy.rs b/src/test/ui/traits/trait-item-privacy.rs index dfc8c8f4f6cc1..d58bbef38c492 100644 --- a/src/test/ui/traits/trait-item-privacy.rs +++ b/src/test/ui/traits/trait-item-privacy.rs @@ -68,7 +68,7 @@ fn check_method() { S.b(); //~ ERROR no method named `b` found for type `S` in the current scope S.c(); // OK // a, b, c are resolved as inherent items, their traits don't need to be in scope - let c = &S as &C; + let c = &S as &dyn C; c.a(); //~ ERROR method `a` is private c.b(); // OK c.c(); // OK @@ -121,10 +121,10 @@ fn check_assoc_ty() { let _: T::C; // OK // Associated types, bindings - let _: assoc_ty::B< + let _: dyn assoc_ty::B< B = u8, // OK >; - let _: C< + let _: dyn C< A = u8, //~ ERROR associated type `A` is private B = u8, // OK C = u8, // OK diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr index c65a9a3ed945c..de699a69fa8bc 100644 --- a/src/test/ui/traits/trait-item-privacy.stderr +++ b/src/test/ui/traits/trait-item-privacy.stderr @@ -4,7 +4,7 @@ error[E0599]: no method named `a` found for type `S` in the current scope LL | struct S; | --------- method `a` not found for this ... -LL | S.a(); //~ ERROR no method named `a` found for type `S` in the current scope +LL | S.a(); | ^ | = help: items from traits can only be used if the trait is implemented and in scope @@ -17,7 +17,7 @@ error[E0599]: no method named `b` found for type `S` in the current scope LL | struct S; | --------- method `b` not found for this ... -LL | S.b(); //~ ERROR no method named `b` found for type `S` in the current scope +LL | S.b(); | ^ | = help: items from traits can only be used if the trait is in scope @@ -29,7 +29,7 @@ LL | use method::B; error[E0624]: method `a` is private --> $DIR/trait-item-privacy.rs:72:7 | -LL | c.a(); //~ ERROR method `a` is private +LL | c.a(); | ^ error[E0599]: no function or associated item named `a` found for type `S` in the current scope @@ -39,9 +39,7 @@ LL | struct S; | --------- function or associated item `a` not found for this ... LL | S::a(&S); - | ---^ - | | - | function or associated item not found in `S` + | ^ function or associated item not found in `S` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `a`, perhaps you need to implement it: @@ -54,9 +52,7 @@ LL | struct S; | --------- function or associated item `b` not found for this ... LL | S::b(&S); - | ---^ - | | - | function or associated item not found in `S` + | ^ function or associated item not found in `S` | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope, perhaps add a `use` for it: @@ -67,7 +63,7 @@ LL | use method::B; error[E0624]: method `a` is private --> $DIR/trait-item-privacy.rs:84:5 | -LL | C::a(&S); //~ ERROR method `a` is private +LL | C::a(&S); | ^^^^ error[E0599]: no associated item named `A` found for type `S` in the current scope @@ -76,10 +72,8 @@ error[E0599]: no associated item named `A` found for type `S` in the current sco LL | struct S; | --------- associated item `A` not found for this ... -LL | S::A; //~ ERROR no associated item named `A` found for type `S` in the current scope - | ---^ - | | - | associated item not found in `S` +LL | S::A; + | ^ associated item not found in `S` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `A`, perhaps you need to implement it: @@ -91,10 +85,8 @@ error[E0599]: no associated item named `B` found for type `S` in the current sco LL | struct S; | --------- associated item `B` not found for this ... -LL | S::B; //~ ERROR no associated item named `B` found for type `S` in the current scope - | ---^ - | | - | associated item not found in `S` +LL | S::B; + | ^ associated item not found in `S` | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope, perhaps add a `use` for it: @@ -105,13 +97,13 @@ LL | use assoc_const::B; error[E0624]: associated constant `A` is private --> $DIR/trait-item-privacy.rs:101:5 | -LL | C::A; //~ ERROR associated constant `A` is private +LL | C::A; | ^^^^ error[E0038]: the trait `assoc_const::C` cannot be made into an object --> $DIR/trait-item-privacy.rs:101:5 | -LL | C::A; //~ ERROR associated constant `A` is private +LL | C::A; | ^^^^ the trait `assoc_const::C` cannot be made into an object | = note: the trait cannot contain associated consts like `C` @@ -121,34 +113,34 @@ LL | C::A; //~ ERROR associated constant `A` is private error[E0223]: ambiguous associated type --> $DIR/trait-item-privacy.rs:115:12 | -LL | let _: S::A; //~ ERROR ambiguous associated type +LL | let _: S::A; | ^^^^ help: use fully-qualified syntax: `::A` error[E0223]: ambiguous associated type --> $DIR/trait-item-privacy.rs:116:12 | -LL | let _: S::B; //~ ERROR ambiguous associated type +LL | let _: S::B; | ^^^^ help: use fully-qualified syntax: `::B` error[E0223]: ambiguous associated type --> $DIR/trait-item-privacy.rs:117:12 | -LL | let _: S::C; //~ ERROR ambiguous associated type +LL | let _: S::C; | ^^^^ help: use fully-qualified syntax: `::C` error: associated type `A` is private --> $DIR/trait-item-privacy.rs:119:12 | -LL | let _: T::A; //~ ERROR associated type `A` is private +LL | let _: T::A; | ^^^^ error: associated type `A` is private --> $DIR/trait-item-privacy.rs:128:9 | -LL | A = u8, //~ ERROR associated type `A` is private +LL | A = u8, | ^^^^^^ error: aborting due to 15 previous errors -Some errors occurred: E0038, E0223, E0599, E0624. +Some errors have detailed explanations: E0038, E0223, E0599, E0624. For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/traits/trait-method-private.stderr b/src/test/ui/traits/trait-method-private.stderr index ed6aeeb9c898e..c1dd9387ebc48 100644 --- a/src/test/ui/traits/trait-method-private.stderr +++ b/src/test/ui/traits/trait-method-private.stderr @@ -1,7 +1,7 @@ error[E0624]: method `method` is private --> $DIR/trait-method-private.rs:19:9 | -LL | foo.method(); //~ ERROR is private +LL | foo.method(); | ^^^^^^ | = help: items from traits can only be used if the trait is in scope diff --git a/src/test/ui/traits/trait-object-auto-dedup-in-impl.rs b/src/test/ui/traits/trait-object-auto-dedup-in-impl.rs index 6ba5d28a6c4c2..85698f1948904 100644 --- a/src/test/ui/traits/trait-object-auto-dedup-in-impl.rs +++ b/src/test/ui/traits/trait-object-auto-dedup-in-impl.rs @@ -5,15 +5,15 @@ struct Struct; impl Trait for Struct {} trait Trait {} -type Send1 = Trait + Send; -type Send2 = Trait + Send + Send; +type Send1 = dyn Trait + Send; +type Send2 = dyn Trait + Send + Send; fn main () {} -impl Trait + Send { +impl dyn Trait + Send { fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test` } -impl Trait + Send + Send { +impl dyn Trait + Send + Send { fn test(&self) { println!("two"); } } diff --git a/src/test/ui/traits/trait-object-auto-dedup-in-impl.stderr b/src/test/ui/traits/trait-object-auto-dedup-in-impl.stderr index 2d2c3843548e9..2570db0212aa1 100644 --- a/src/test/ui/traits/trait-object-auto-dedup-in-impl.stderr +++ b/src/test/ui/traits/trait-object-auto-dedup-in-impl.stderr @@ -1,7 +1,7 @@ error[E0592]: duplicate definitions with name `test` --> $DIR/trait-object-auto-dedup-in-impl.rs:14:5 | -LL | fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test` +LL | fn test(&self) { println!("one"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `test` ... LL | fn test(&self) { println!("two"); } diff --git a/src/test/ui/traits/trait-object-macro-matcher.rs b/src/test/ui/traits/trait-object-macro-matcher.rs index 0f55e2dc4f21e..a6852569f3a12 100644 --- a/src/test/ui/traits/trait-object-macro-matcher.rs +++ b/src/test/ui/traits/trait-object-macro-matcher.rs @@ -5,7 +5,8 @@ macro_rules! m { } fn main() { - m!(Copy + Send + 'static); //~ ERROR the trait `std::marker::Copy` cannot be made into an object - m!('static + Send); - m!('static +); //~ ERROR at least one non-builtin trait is required for an object type + m!(dyn Copy + Send + 'static); + //~^ ERROR the trait `std::marker::Copy` cannot be made into an object + m!(dyn 'static + Send); + m!(dyn 'static +); //~ ERROR at least one trait is required for an object type } diff --git a/src/test/ui/traits/trait-object-macro-matcher.stderr b/src/test/ui/traits/trait-object-macro-matcher.stderr index 678f4fb595573..6b5effaad9bc4 100644 --- a/src/test/ui/traits/trait-object-macro-matcher.stderr +++ b/src/test/ui/traits/trait-object-macro-matcher.stderr @@ -1,18 +1,17 @@ -error[E0224]: at least one non-builtin trait is required for an object type - --> $DIR/trait-object-macro-matcher.rs:10:8 +error[E0224]: at least one trait is required for an object type + --> $DIR/trait-object-macro-matcher.rs:11:8 | -LL | m!('static +); //~ ERROR at least one non-builtin trait is required for an object type - | ^^^^^^^^^ +LL | m!(dyn 'static +); + | ^^^^^^^^^^^^^ error[E0038]: the trait `std::marker::Copy` cannot be made into an object --> $DIR/trait-object-macro-matcher.rs:8:8 | -LL | m!(Copy + Send + 'static); //~ ERROR the trait `std::marker::Copy` cannot be made into an object - | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` cannot be made into an object +LL | m!(dyn Copy + Send + 'static); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` cannot be made into an object | = note: the trait cannot require that `Self : Sized` error: aborting due to 2 previous errors -Some errors occurred: E0038, E0224. -For more information about an error, try `rustc --explain E0038`. +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/traits/trait-object-safety.rs b/src/test/ui/traits/trait-object-safety.rs index e333bf6bfe53b..f43d332d69637 100644 --- a/src/test/ui/traits/trait-object-safety.rs +++ b/src/test/ui/traits/trait-object-safety.rs @@ -12,6 +12,6 @@ impl Tr for St { } fn main() { - let _: &Tr = &St; //~ ERROR E0038 + let _: &dyn Tr = &St; //~ ERROR E0038 //~^ ERROR E0038 } diff --git a/src/test/ui/traits/trait-object-safety.stderr b/src/test/ui/traits/trait-object-safety.stderr index 0a0c5ff086b56..68edc17870534 100644 --- a/src/test/ui/traits/trait-object-safety.stderr +++ b/src/test/ui/traits/trait-object-safety.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Tr` cannot be made into an object - --> $DIR/trait-object-safety.rs:15:18 + --> $DIR/trait-object-safety.rs:15:22 | -LL | let _: &Tr = &St; //~ ERROR E0038 - | ^^^ the trait `Tr` cannot be made into an object +LL | let _: &dyn Tr = &St; + | ^^^ the trait `Tr` cannot be made into an object | = note: method `foo` has no receiver = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Tr>` for `&St` @@ -10,8 +10,8 @@ LL | let _: &Tr = &St; //~ ERROR E0038 error[E0038]: the trait `Tr` cannot be made into an object --> $DIR/trait-object-safety.rs:15:12 | -LL | let _: &Tr = &St; //~ ERROR E0038 - | ^^^ the trait `Tr` cannot be made into an object +LL | let _: &dyn Tr = &St; + | ^^^^^^^ the trait `Tr` cannot be made into an object | = note: method `foo` has no receiver diff --git a/src/test/ui/traits/trait-object-vs-lifetime-2.rs b/src/test/ui/traits/trait-object-vs-lifetime-2.rs index 2579a0056f142..0b33dc7f69a3a 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime-2.rs +++ b/src/test/ui/traits/trait-object-vs-lifetime-2.rs @@ -1,13 +1,11 @@ // A few contrived examples where lifetime should (or should not) be parsed as an object type. // Lifetimes parsed as types are still rejected later by semantic checks. -// compile-flags: -Z continue-parse-after-error - // `'static` is a lifetime, `'static +` is a type, `'a` is a type fn g() where 'static: 'static, - 'static +: 'static + Copy, - //~^ ERROR at least one non-builtin trait is required for an object type + dyn 'static +: 'static + Copy, + //~^ ERROR at least one trait is required for an object type {} fn main() {} diff --git a/src/test/ui/traits/trait-object-vs-lifetime-2.stderr b/src/test/ui/traits/trait-object-vs-lifetime-2.stderr index 70ad839b9af6c..014d380b63ca5 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime-2.stderr +++ b/src/test/ui/traits/trait-object-vs-lifetime-2.stderr @@ -1,9 +1,8 @@ -error[E0224]: at least one non-builtin trait is required for an object type - --> $DIR/trait-object-vs-lifetime-2.rs:9:5 +error[E0224]: at least one trait is required for an object type + --> $DIR/trait-object-vs-lifetime-2.rs:7:5 | -LL | 'static +: 'static + Copy, - | ^^^^^^^^^ +LL | dyn 'static +: 'static + Copy, + | ^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0224`. diff --git a/src/test/ui/traits/trait-object-vs-lifetime.rs b/src/test/ui/traits/trait-object-vs-lifetime.rs index 36dec21be0520..e0ff734948376 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime.rs +++ b/src/test/ui/traits/trait-object-vs-lifetime.rs @@ -6,12 +6,12 @@ struct S<'a, T>(&'a u8, T); fn main() { // `'static` is a lifetime argument, `'static +` is a type argument let _: S<'static, u8>; - let _: S<'static, 'static +>; - //~^ at least one non-builtin trait is required for an object type + let _: S<'static, dyn 'static +>; + //~^ at least one trait is required for an object type let _: S<'static, 'static>; //~^ ERROR wrong number of lifetime arguments: expected 1, found 2 //~| ERROR wrong number of type arguments: expected 1, found 0 - let _: S<'static +, 'static>; + let _: S; //~^ ERROR lifetime arguments must be declared prior to type arguments - //~| ERROR at least one non-builtin trait is required for an object type + //~| ERROR at least one trait is required for an object type } diff --git a/src/test/ui/traits/trait-object-vs-lifetime.stderr b/src/test/ui/traits/trait-object-vs-lifetime.stderr index e0c52a72a0931..be1958770a426 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime.stderr +++ b/src/test/ui/traits/trait-object-vs-lifetime.stderr @@ -1,14 +1,14 @@ error: lifetime arguments must be declared prior to type arguments - --> $DIR/trait-object-vs-lifetime.rs:14:25 + --> $DIR/trait-object-vs-lifetime.rs:14:29 | -LL | let _: S<'static +, 'static>; - | ^^^^^^^ +LL | let _: S; + | ^^^^^^^ -error[E0224]: at least one non-builtin trait is required for an object type +error[E0224]: at least one trait is required for an object type --> $DIR/trait-object-vs-lifetime.rs:9:23 | -LL | let _: S<'static, 'static +>; - | ^^^^^^^^^ +LL | let _: S<'static, dyn 'static +>; + | ^^^^^^^^^^^^^ error[E0107]: wrong number of lifetime arguments: expected 1, found 2 --> $DIR/trait-object-vs-lifetime.rs:11:23 @@ -22,13 +22,12 @@ error[E0107]: wrong number of type arguments: expected 1, found 0 LL | let _: S<'static, 'static>; | ^^^^^^^^^^^^^^^^^^^ expected 1 type argument -error[E0224]: at least one non-builtin trait is required for an object type +error[E0224]: at least one trait is required for an object type --> $DIR/trait-object-vs-lifetime.rs:14:14 | -LL | let _: S<'static +, 'static>; - | ^^^^^^^^^ +LL | let _: S; + | ^^^^^^^^^^^^^ error: aborting due to 5 previous errors -Some errors occurred: E0107, E0224. -For more information about an error, try `rustc --explain E0107`. +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/traits/trait-object-with-self-in-projection-output-repeated-supertrait.rs b/src/test/ui/traits/trait-object-with-self-in-projection-output-repeated-supertrait.rs index 46c083f930591..3e9f612a2afee 100644 --- a/src/test/ui/traits/trait-object-with-self-in-projection-output-repeated-supertrait.rs +++ b/src/test/ui/traits/trait-object-with-self-in-projection-output-repeated-supertrait.rs @@ -1,5 +1,8 @@ // compile-pass +// FIXME(eddyb) shorten the name so windows doesn't choke on it. +#![crate_name = "trait_test"] + // Regression test related to #56288. Check that a supertrait projection (of // `Output`) that references `Self` is ok if there is another occurence of // the same supertrait that specifies the projection explicitly, even if diff --git a/src/test/ui/traits/trait-or-new-type-instead.stderr b/src/test/ui/traits/trait-or-new-type-instead.stderr index e8bd20019a890..4726b0668e516 100644 --- a/src/test/ui/traits/trait-or-new-type-instead.stderr +++ b/src/test/ui/traits/trait-or-new-type-instead.stderr @@ -2,7 +2,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher --> $DIR/trait-or-new-type-instead.rs:1:1 | LL | / impl Option { -LL | | //~^ ERROR cannot define inherent `impl` for a type outside of the crate where the type is defined +LL | | LL | | pub fn foo(&self) { } LL | | } | |_^ impl for type defined outside of crate. diff --git a/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr b/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr index 2c644480f0a54..d11562e2a001b 100644 --- a/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr +++ b/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr @@ -1,8 +1,10 @@ error[E0369]: binary operation `*` cannot be applied to type `&T` - --> $DIR/trait-resolution-in-overloaded-op.rs:8:5 + --> $DIR/trait-resolution-in-overloaded-op.rs:8:7 | -LL | a * b //~ ERROR binary operation `*` cannot be applied to type `&T` - | ^^^^^ +LL | a * b + | - ^ - f64 + | | + | &T | = note: an implementation of `std::ops::Mul` might be missing for `&T` diff --git a/src/test/ui/traits/trait-safety-inherent-impl.stderr b/src/test/ui/traits/trait-safety-inherent-impl.stderr index 969b16633ce34..3911261083ecc 100644 --- a/src/test/ui/traits/trait-safety-inherent-impl.stderr +++ b/src/test/ui/traits/trait-safety-inherent-impl.stderr @@ -1,7 +1,7 @@ error[E0197]: inherent impls cannot be unsafe --> $DIR/trait-safety-inherent-impl.rs:5:1 | -LL | / unsafe impl SomeStruct { //~ ERROR inherent impls cannot be unsafe +LL | / unsafe impl SomeStruct { LL | | fn foo(self) { } LL | | } | |_^ diff --git a/src/test/ui/traits/trait-safety-trait-impl-cc.stderr b/src/test/ui/traits/trait-safety-trait-impl-cc.stderr index 3be72fbfdd722..5234e205a84b5 100644 --- a/src/test/ui/traits/trait-safety-trait-impl-cc.stderr +++ b/src/test/ui/traits/trait-safety-trait-impl-cc.stderr @@ -1,7 +1,7 @@ error[E0200]: the trait `lib::Foo` requires an `unsafe impl` declaration --> $DIR/trait-safety-trait-impl-cc.rs:9:1 | -LL | / impl lib::Foo for Bar { //~ ERROR requires an `unsafe impl` declaration +LL | / impl lib::Foo for Bar { LL | | fn foo(&self) -> isize { LL | | panic!(); LL | | } diff --git a/src/test/ui/traits/trait-safety-trait-impl.stderr b/src/test/ui/traits/trait-safety-trait-impl.stderr index 22e9b4d4035ee..5b29fd12ab5fd 100644 --- a/src/test/ui/traits/trait-safety-trait-impl.stderr +++ b/src/test/ui/traits/trait-safety-trait-impl.stderr @@ -1,16 +1,16 @@ error[E0200]: the trait `UnsafeTrait` requires an `unsafe impl` declaration --> $DIR/trait-safety-trait-impl.rs:14:1 | -LL | impl UnsafeTrait for u16 { } //~ ERROR requires an `unsafe impl` declaration +LL | impl UnsafeTrait for u16 { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0199]: implementing the trait `SafeTrait` is not unsafe --> $DIR/trait-safety-trait-impl.rs:16:1 | -LL | unsafe impl SafeTrait for u32 { } //~ ERROR the trait `SafeTrait` is not unsafe +LL | unsafe impl SafeTrait for u32 { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors -Some errors occurred: E0199, E0200. +Some errors have detailed explanations: E0199, E0200. For more information about an error, try `rustc --explain E0199`. diff --git a/src/test/ui/traits/trait-test-2.rs b/src/test/ui/traits/trait-test-2.rs index 20d979df4bf43..86570f1152e1e 100644 --- a/src/test/ui/traits/trait-test-2.rs +++ b/src/test/ui/traits/trait-test-2.rs @@ -8,7 +8,7 @@ impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } fn main() { 10.dup::(); //~ ERROR wrong number of type arguments: expected 0, found 1 10.blah::(); //~ ERROR wrong number of type arguments: expected 1, found 2 - (box 10 as Box).dup(); + (box 10 as Box).dup(); //~^ ERROR E0038 //~| ERROR E0038 } diff --git a/src/test/ui/traits/trait-test-2.stderr b/src/test/ui/traits/trait-test-2.stderr index c01317f3d5b99..5d5251925a1ae 100644 --- a/src/test/ui/traits/trait-test-2.stderr +++ b/src/test/ui/traits/trait-test-2.stderr @@ -1,20 +1,20 @@ error[E0107]: wrong number of type arguments: expected 0, found 1 --> $DIR/trait-test-2.rs:9:14 | -LL | 10.dup::(); //~ ERROR wrong number of type arguments: expected 0, found 1 +LL | 10.dup::(); | ^^^ unexpected type argument error[E0107]: wrong number of type arguments: expected 1, found 2 --> $DIR/trait-test-2.rs:10:20 | -LL | 10.blah::(); //~ ERROR wrong number of type arguments: expected 1, found 2 +LL | 10.blah::(); | ^^^ unexpected type argument error[E0038]: the trait `bar` cannot be made into an object --> $DIR/trait-test-2.rs:11:16 | -LL | (box 10 as Box).dup(); - | ^^^^^^^^ the trait `bar` cannot be made into an object +LL | (box 10 as Box).dup(); + | ^^^^^^^^^^^^ the trait `bar` cannot be made into an object | = note: method `dup` references the `Self` type in its arguments or return type = note: method `blah` has generic type parameters @@ -22,7 +22,7 @@ LL | (box 10 as Box).dup(); error[E0038]: the trait `bar` cannot be made into an object --> $DIR/trait-test-2.rs:11:6 | -LL | (box 10 as Box).dup(); +LL | (box 10 as Box).dup(); | ^^^^^^ the trait `bar` cannot be made into an object | = note: method `dup` references the `Self` type in its arguments or return type @@ -31,5 +31,5 @@ LL | (box 10 as Box).dup(); error: aborting due to 4 previous errors -Some errors occurred: E0038, E0107. +Some errors have detailed explanations: E0038, E0107. For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/traits/trait-test.stderr b/src/test/ui/traits/trait-test.stderr index 2383175d513bc..f5e47e51526c6 100644 --- a/src/test/ui/traits/trait-test.stderr +++ b/src/test/ui/traits/trait-test.stderr @@ -1,7 +1,7 @@ error[E0404]: expected trait, found builtin type `isize` --> $DIR/trait-test.rs:4:6 | -LL | impl isize for usize { fn foo(&self) {} } //~ ERROR trait +LL | impl isize for usize { fn foo(&self) {} } | ^^^^^ not a trait error: aborting due to previous error diff --git a/src/test/ui/traits/trait-with-dst.rs b/src/test/ui/traits/trait-with-dst.rs new file mode 100644 index 0000000000000..86d6585bc6143 --- /dev/null +++ b/src/test/ui/traits/trait-with-dst.rs @@ -0,0 +1,22 @@ +// compile-pass +// #55266 + +struct VTable { + _to_dst_ptr: fn(*mut ()) -> *mut DST, +} + +trait HasVTableFor { + const VTABLE: &'static VTable; +} + +impl HasVTableFor for T { + const VTABLE: &'static VTable = &VTable { + _to_dst_ptr: |_: *mut ()| unsafe { std::mem::zeroed() }, + }; +} + +pub fn push() { + >::VTABLE; +} + +fn main() {} diff --git a/src/test/ui/traits/traits-assoc-type-in-supertrait-bad.stderr b/src/test/ui/traits/traits-assoc-type-in-supertrait-bad.stderr index ce1aadca597c5..44643e8c8de43 100644 --- a/src/test/ui/traits/traits-assoc-type-in-supertrait-bad.stderr +++ b/src/test/ui/traits/traits-assoc-type-in-supertrait-bad.stderr @@ -1,7 +1,7 @@ error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == u32` --> $DIR/traits-assoc-type-in-supertrait-bad.rs:11:6 | -LL | impl Foo for IntoIter { //~ ERROR type mismatch +LL | impl Foo for IntoIter { | ^^^ expected i32, found u32 | = note: expected type `i32` diff --git a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr b/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr index 7aa9809c07455..87e7ba3e7efcf 100644 --- a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr @@ -1,13 +1,13 @@ error[E0568]: auto traits cannot have super traits --> $DIR/traits-inductive-overflow-supertrait-oibit.rs:7:1 | -LL | auto trait Magic: Copy {} //~ ERROR E0568 +LL | auto trait Magic: Copy {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `NoClone: std::marker::Copy` is not satisfied --> $DIR/traits-inductive-overflow-supertrait-oibit.rs:15:18 | -LL | let (a, b) = copy(NoClone); //~ ERROR +LL | let (a, b) = copy(NoClone); | ^^^^ the trait `std::marker::Copy` is not implemented for `NoClone` | = note: required because of the requirements on the impl of `Magic` for `NoClone` @@ -19,5 +19,4 @@ LL | fn copy(x: T) -> (T, T) { (x, x) } error: aborting due to 2 previous errors -Some errors occurred: E0277, E0568. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/traits-inductive-overflow-supertrait.stderr b/src/test/ui/traits/traits-inductive-overflow-supertrait.stderr index d4b3b6b7d716a..769582a778bcf 100644 --- a/src/test/ui/traits/traits-inductive-overflow-supertrait.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-supertrait.stderr @@ -1,7 +1,7 @@ error[E0275]: overflow evaluating the requirement `NoClone: Magic` --> $DIR/traits-inductive-overflow-supertrait.rs:13:18 | -LL | let (a, b) = copy(NoClone); //~ ERROR E0275 +LL | let (a, b) = copy(NoClone); | ^^^^ | = note: required because of the requirements on the impl of `Magic` for `NoClone` diff --git a/src/test/ui/traits/traits-inductive-overflow-two-traits.stderr b/src/test/ui/traits/traits-inductive-overflow-two-traits.stderr index cee9aa348c38e..61adbf00f7188 100644 --- a/src/test/ui/traits/traits-inductive-overflow-two-traits.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-two-traits.stderr @@ -1,7 +1,7 @@ error[E0275]: overflow evaluating the requirement `*mut (): Magic` --> $DIR/traits-inductive-overflow-two-traits.rs:19:5 | -LL | wizard::<*mut ()>(); //~ ERROR E0275 +LL | wizard::<*mut ()>(); | ^^^^^^^^^^^^^^^^^ | note: required by `wizard` diff --git a/src/test/ui/traits/traits-multidispatch-bad.stderr b/src/test/ui/traits/traits-multidispatch-bad.stderr index d6c6697c3c0e5..9e6c38ced0d26 100644 --- a/src/test/ui/traits/traits-multidispatch-bad.stderr +++ b/src/test/ui/traits/traits-multidispatch-bad.stderr @@ -1,8 +1,12 @@ error[E0308]: mismatched types --> $DIR/traits-multidispatch-bad.rs:19:17 | -LL | test(22i32, 44i32); //~ ERROR mismatched types +LL | test(22i32, 44i32); | ^^^^^ expected u32, found i32 +help: change the type of the numeric literal from `i32` to `u32` + | +LL | test(22i32, 44u32); + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/traits/traits-repeated-supertrait-ambig.rs b/src/test/ui/traits/traits-repeated-supertrait-ambig.rs index 5fa7e87aa4b97..6aaef8a305bce 100644 --- a/src/test/ui/traits/traits-repeated-supertrait-ambig.rs +++ b/src/test/ui/traits/traits-repeated-supertrait-ambig.rs @@ -22,7 +22,7 @@ impl CompareTo for i64 { impl CompareToInts for i64 { } -fn with_obj(c: &CompareToInts) -> bool { +fn with_obj(c: &dyn CompareToInts) -> bool { c.same_as(22) //~ ERROR `dyn CompareToInts: CompareTo` is not satisfied } diff --git a/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr b/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr index f906378eb3cbd..5d1c91376868f 100644 --- a/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr +++ b/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr @@ -1,13 +1,13 @@ error[E0277]: the trait bound `dyn CompareToInts: CompareTo` is not satisfied --> $DIR/traits-repeated-supertrait-ambig.rs:26:7 | -LL | c.same_as(22) //~ ERROR `dyn CompareToInts: CompareTo` is not satisfied +LL | c.same_as(22) | ^^^^^^^ the trait `CompareTo` is not implemented for `dyn CompareToInts` error[E0277]: the trait bound `C: CompareTo` is not satisfied --> $DIR/traits-repeated-supertrait-ambig.rs:30:7 | -LL | c.same_as(22) //~ ERROR `C: CompareTo` is not satisfied +LL | c.same_as(22) | ^^^^^^^ the trait `CompareTo` is not implemented for `C` | = help: consider adding a `where C: CompareTo` bound @@ -15,7 +15,7 @@ LL | c.same_as(22) //~ ERROR `C: CompareTo` is not satisfied error[E0277]: the trait bound `dyn CompareToInts: CompareTo` is not satisfied --> $DIR/traits-repeated-supertrait-ambig.rs:34:5 | -LL | CompareToInts::same_as(c, 22) //~ ERROR `dyn CompareToInts: CompareTo` is not satisfied +LL | CompareToInts::same_as(c, 22) | ^^^^^^^^^^^^^^^^^^^^^^ the trait `CompareTo` is not implemented for `dyn CompareToInts` | note: required by `CompareTo::same_as` @@ -27,7 +27,7 @@ LL | fn same_as(&self, t: T) -> bool; error[E0277]: the trait bound `C: CompareTo` is not satisfied --> $DIR/traits-repeated-supertrait-ambig.rs:38:5 | -LL | CompareTo::same_as(c, 22) //~ ERROR `C: CompareTo` is not satisfied +LL | CompareTo::same_as(c, 22) | ^^^^^^^^^^^^^^^^^^ the trait `CompareTo` is not implemented for `C` | = help: consider adding a `where C: CompareTo` bound @@ -40,7 +40,7 @@ LL | fn same_as(&self, t: T) -> bool; error[E0277]: the trait bound `i64: CompareTo` is not satisfied --> $DIR/traits-repeated-supertrait-ambig.rs:42:23 | -LL | assert_eq!(22_i64.same_as(22), true); //~ ERROR `i64: CompareTo` is not satisfied +LL | assert_eq!(22_i64.same_as(22), true); | ^^^^^^^ the trait `CompareTo` is not implemented for `i64` | = help: the following implementations were found: diff --git a/src/test/ui/run-pass/traits/traits-static-outlives-a-where-clause.rs b/src/test/ui/traits/traits-static-outlives-a-where-clause.rs similarity index 100% rename from src/test/ui/run-pass/traits/traits-static-outlives-a-where-clause.rs rename to src/test/ui/traits/traits-static-outlives-a-where-clause.rs diff --git a/src/test/ui/traits/wf-trait-object-maybe-bound.rs b/src/test/ui/traits/wf-trait-object-maybe-bound.rs new file mode 100644 index 0000000000000..f24c1301c53ab --- /dev/null +++ b/src/test/ui/traits/wf-trait-object-maybe-bound.rs @@ -0,0 +1,20 @@ +// compile-fail + +// Test that `dyn ... + ?Sized + ...` is okay (though `?Sized` has no effect in trait objects). + +trait Foo {} + +type _0 = dyn ?Sized + Foo; +//~^ ERROR `?Trait` is not permitted in trait object types + +type _1 = dyn Foo + ?Sized; +//~^ ERROR `?Trait` is not permitted in trait object types + +type _2 = dyn Foo + ?Sized + ?Sized; +//~^ ERROR `?Trait` is not permitted in trait object types +//~| ERROR `?Trait` is not permitted in trait object types + +type _3 = dyn ?Sized + Foo; +//~^ ERROR `?Trait` is not permitted in trait object types + +fn main() {} diff --git a/src/test/ui/traits/wf-trait-object-maybe-bound.stderr b/src/test/ui/traits/wf-trait-object-maybe-bound.stderr new file mode 100644 index 0000000000000..11187342d59f2 --- /dev/null +++ b/src/test/ui/traits/wf-trait-object-maybe-bound.stderr @@ -0,0 +1,32 @@ +error: `?Trait` is not permitted in trait object types + --> $DIR/wf-trait-object-maybe-bound.rs:7:15 + | +LL | type _0 = dyn ?Sized + Foo; + | ^^^^^^ + +error: `?Trait` is not permitted in trait object types + --> $DIR/wf-trait-object-maybe-bound.rs:10:21 + | +LL | type _1 = dyn Foo + ?Sized; + | ^^^^^^ + +error: `?Trait` is not permitted in trait object types + --> $DIR/wf-trait-object-maybe-bound.rs:13:21 + | +LL | type _2 = dyn Foo + ?Sized + ?Sized; + | ^^^^^^ + +error: `?Trait` is not permitted in trait object types + --> $DIR/wf-trait-object-maybe-bound.rs:13:30 + | +LL | type _2 = dyn Foo + ?Sized + ?Sized; + | ^^^^^^ + +error: `?Trait` is not permitted in trait object types + --> $DIR/wf-trait-object-maybe-bound.rs:17:15 + | +LL | type _3 = dyn ?Sized + Foo; + | ^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/traits/wf-trait-object-no-duplicates.rs b/src/test/ui/traits/wf-trait-object-no-duplicates.rs new file mode 100644 index 0000000000000..678ede58296a4 --- /dev/null +++ b/src/test/ui/traits/wf-trait-object-no-duplicates.rs @@ -0,0 +1,33 @@ +// The purpose of this test is to demonstrate that duplicating object safe traits +// that are not auto-traits is rejected even though one could reasonably accept this. + +// Some arbitrary object-safe trait: +trait Obj {} + +// Demonstrate that recursive expansion of trait aliases doesn't affect stable behavior: +type _0 = dyn Obj + Obj; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +// Some variations: + +type _1 = dyn Send + Obj + Obj; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _2 = dyn Obj + Send + Obj; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +type _3 = dyn Obj + Send + Send; // But it is OK to duplicate auto traits. + +// Take higher ranked types into account. + +// Note that `'a` and `'b` are intentionally different to make sure we consider +// them semantically the same. +trait ObjL<'l> {} +type _4 = dyn for<'a> ObjL<'a> + for<'b> ObjL<'b>; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +trait ObjT {} +type _5 = dyn ObjT fn(&'a u8)> + ObjT fn(&'b u8)>; +//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225] + +fn main() {} diff --git a/src/test/ui/traits/wf-trait-object-no-duplicates.stderr b/src/test/ui/traits/wf-trait-object-no-duplicates.stderr new file mode 100644 index 0000000000000..269d92fe43db8 --- /dev/null +++ b/src/test/ui/traits/wf-trait-object-no-duplicates.stderr @@ -0,0 +1,58 @@ +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/wf-trait-object-no-duplicates.rs:8:21 + | +LL | type _0 = dyn Obj + Obj; + | --- ^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/wf-trait-object-no-duplicates.rs:13:28 + | +LL | type _1 = dyn Send + Obj + Obj; + | --- ^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/wf-trait-object-no-duplicates.rs:16:28 + | +LL | type _2 = dyn Obj + Send + Obj; + | --- ^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/wf-trait-object-no-duplicates.rs:26:34 + | +LL | type _4 = dyn for<'a> ObjL<'a> + for<'b> ObjL<'b>; + | ---------------- ^^^^^^^^^^^^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/wf-trait-object-no-duplicates.rs:30:42 + | +LL | type _5 = dyn ObjT fn(&'a u8)> + ObjT fn(&'b u8)>; + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0225`. diff --git a/src/test/ui/traits/wf-trait-object-only-maybe-bound.rs b/src/test/ui/traits/wf-trait-object-only-maybe-bound.rs new file mode 100644 index 0000000000000..3e6db3e997c9b --- /dev/null +++ b/src/test/ui/traits/wf-trait-object-only-maybe-bound.rs @@ -0,0 +1,7 @@ +// Test that `dyn ?Sized` (i.e., a trait object with only a maybe buond) is not allowed. + +type _0 = dyn ?Sized; +//~^ ERROR at least one trait is required for an object type [E0224] +//~| ERROR ?Trait` is not permitted in trait object types + +fn main() {} diff --git a/src/test/ui/traits/wf-trait-object-only-maybe-bound.stderr b/src/test/ui/traits/wf-trait-object-only-maybe-bound.stderr new file mode 100644 index 0000000000000..8cc97addc7dd4 --- /dev/null +++ b/src/test/ui/traits/wf-trait-object-only-maybe-bound.stderr @@ -0,0 +1,14 @@ +error: `?Trait` is not permitted in trait object types + --> $DIR/wf-trait-object-only-maybe-bound.rs:3:15 + | +LL | type _0 = dyn ?Sized; + | ^^^^^^ + +error[E0224]: at least one trait is required for an object type + --> $DIR/wf-trait-object-only-maybe-bound.rs:3:11 + | +LL | type _0 = dyn ?Sized; + | ^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/traits/wf-trait-object-reverse-order.rs b/src/test/ui/traits/wf-trait-object-reverse-order.rs new file mode 100644 index 0000000000000..4f676cbe33846 --- /dev/null +++ b/src/test/ui/traits/wf-trait-object-reverse-order.rs @@ -0,0 +1,15 @@ +// run-pass + +// Ensure that `dyn $($AutoTrait)+ ObjSafe` is well-formed. + +use std::marker::Unpin; + +// Some arbitrary object-safe trait: +trait Obj {} + +type _0 = dyn Unpin; +type _1 = dyn Send + Obj; +type _2 = dyn Send + Unpin + Obj; +type _3 = dyn Send + Unpin + Sync + Obj; + +fn main() {} diff --git a/src/test/ui/transmute-equal-assoc-types.stderr b/src/test/ui/transmute-equal-assoc-types.stderr index 46bbf1c185889..ce7657f9640b4 100644 --- a/src/test/ui/transmute-equal-assoc-types.stderr +++ b/src/test/ui/transmute-equal-assoc-types.stderr @@ -1,7 +1,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-equal-assoc-types.rs:6:5 | -LL | ::std::mem::transmute(foo) //~ ERROR cannot transmute between types of different sizes +LL | ::std::mem::transmute(foo) | ^^^^^^^^^^^^^^^^^^^^^ | = note: `::Bar` does not have a fixed size diff --git a/src/test/ui/transmute/main.stderr b/src/test/ui/transmute/main.stderr index f4e88fc860acd..c72876e050f05 100644 --- a/src/test/ui/transmute/main.stderr +++ b/src/test/ui/transmute/main.stderr @@ -1,7 +1,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/main.rs:16:5 | -LL | transmute(x) //~ ERROR cannot transmute between types of different sizes +LL | transmute(x) | ^^^^^^^^^ | = note: source type: `>::T` (size can vary because of ::T) @@ -10,7 +10,7 @@ LL | transmute(x) //~ ERROR cannot transmute between types of different size error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/main.rs:20:17 | -LL | let x: u8 = transmute(10u16); //~ ERROR cannot transmute between types of different sizes +LL | let x: u8 = transmute(10u16); | ^^^^^^^^^ | = note: source type: `u16` (16 bits) @@ -19,7 +19,7 @@ LL | let x: u8 = transmute(10u16); //~ ERROR cannot transmute between types error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/main.rs:24:17 | -LL | let x: u8 = transmute("test"); //~ ERROR cannot transmute between types of different sizes +LL | let x: u8 = transmute("test"); | ^^^^^^^^^ | = note: source type: `&str` ($STR bits) @@ -28,7 +28,7 @@ LL | let x: u8 = transmute("test"); //~ ERROR cannot transmute between types error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/main.rs:29:18 | -LL | let x: Foo = transmute(10); //~ ERROR cannot transmute between types of different sizes +LL | let x: Foo = transmute(10); | ^^^^^^^^^ | = note: source type: `i32` (32 bits) diff --git a/src/test/ui/transmute/transmute-fat-pointers.stderr b/src/test/ui/transmute/transmute-fat-pointers.stderr index 4b34950881a48..e8335fcbed9d0 100644 --- a/src/test/ui/transmute/transmute-fat-pointers.stderr +++ b/src/test/ui/transmute/transmute-fat-pointers.stderr @@ -1,7 +1,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-fat-pointers.rs:10:14 | -LL | unsafe { transmute(x) } //~ ERROR cannot transmute between types of different sizes +LL | unsafe { transmute(x) } | ^^^^^^^^^ | = note: source type: `&[T]` (N bits) @@ -10,7 +10,7 @@ LL | unsafe { transmute(x) } //~ ERROR cannot transmute between types of dif error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-fat-pointers.rs:14:14 | -LL | unsafe { transmute(x) } //~ ERROR cannot transmute between types of different sizes +LL | unsafe { transmute(x) } | ^^^^^^^^^ | = note: source type: `&T` (pointer to `T`) @@ -19,7 +19,7 @@ LL | unsafe { transmute(x) } //~ ERROR cannot transmute between types of dif error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-fat-pointers.rs:26:14 | -LL | unsafe { transmute(x) } //~ ERROR cannot transmute between types of different sizes +LL | unsafe { transmute(x) } | ^^^^^^^^^ | = note: source type: `&T` (pointer to `T`) @@ -28,7 +28,7 @@ LL | unsafe { transmute(x) } //~ ERROR cannot transmute between types of dif error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-fat-pointers.rs:30:14 | -LL | unsafe { transmute(x) } //~ ERROR cannot transmute between types of different sizes +LL | unsafe { transmute(x) } | ^^^^^^^^^ | = note: source type: `&T` (N bits) diff --git a/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr b/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr index d08078bcfbaea..1a6093343ab84 100644 --- a/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr +++ b/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr @@ -88,5 +88,5 @@ LL | mem::transmute::<_, Option>(Some(baz)); error: aborting due to 9 previous errors -Some errors occurred: E0512, E0591. +Some errors have detailed explanations: E0512, E0591. For more information about an error, try `rustc --explain E0512`. diff --git a/src/test/ui/transmute/transmute-impl.stderr b/src/test/ui/transmute/transmute-impl.stderr index 8acc0aaf3ab52..dd19bcd54e328 100644 --- a/src/test/ui/transmute/transmute-impl.stderr +++ b/src/test/ui/transmute/transmute-impl.stderr @@ -1,7 +1,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-impl.rs:21:18 | -LL | unsafe { transmute(x) } //~ ERROR cannot transmute between types of different sizes +LL | unsafe { transmute(x) } | ^^^^^^^^^ | = note: source type: `&T` (pointer to `T`) diff --git a/src/test/ui/transmute/transmute-imut-to-mut.rs b/src/test/ui/transmute/transmute-imut-to-mut.rs index 94361a29087ea..8e34e0ae8c74d 100644 --- a/src/test/ui/transmute/transmute-imut-to-mut.rs +++ b/src/test/ui/transmute/transmute-imut-to-mut.rs @@ -6,4 +6,3 @@ fn main() { let _a: &mut u8 = unsafe { transmute(&1u8) }; //~^ ERROR mutating transmuted &mut T from &T may cause undefined behavior } - diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy-reborrow.nll.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy-reborrow.nll.stderr deleted file mode 100644 index 8b86dd9a4c92a..0000000000000 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy-reborrow.nll.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0596]: cannot borrow `**t` as mutable, as it is behind a `&` reference - --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:6:5 - | -LL | fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy { - | --------------- help: consider changing this to be a mutable reference: `&'a mut &'a mut i32` -LL | *t //~ ERROR - | ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error[E0596]: cannot borrow `**t` as mutable, as it is behind a `&` reference - --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:10:6 - | -LL | fn copy_reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy { - | --------------- help: consider changing this to be a mutable reference: `&'a mut &'a mut i32` -LL | {*t} //~ ERROR - | ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy-reborrow.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy-reborrow.stderr index a3995b7edefae..aac119afda544 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy-reborrow.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy-reborrow.stderr @@ -1,19 +1,19 @@ -error[E0389]: cannot borrow data mutably in a `&` reference +error[E0596]: cannot borrow `**t` as mutable, as it is behind a `&` reference --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:6:5 | LL | fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy { - | --------------- use `&'a mut &'a mut i32` here to make mutable -LL | *t //~ ERROR - | ^^ assignment into an immutable reference + | --------------- help: consider changing this to be a mutable reference: `&'a mut &'a mut i32` +LL | *t + | ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0389]: cannot borrow data mutably in a `&` reference +error[E0596]: cannot borrow `**t` as mutable, as it is behind a `&` reference --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:10:6 | LL | fn copy_reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy { - | --------------- use `&'a mut &'a mut i32` here to make mutable -LL | {*t} //~ ERROR - | ^^ assignment into an immutable reference + | --------------- help: consider changing this to be a mutable reference: `&'a mut &'a mut i32` +LL | {*t} + | ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0389`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr index f769f23f115fd..e9c28248044f9 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr @@ -4,8 +4,12 @@ error[E0308]: mismatched types LL | fn global_bound_is_hidden() -> u8 | -- expected `u8` because of return type ... -LL | B::get_x() //~ ERROR +LL | B::get_x() | ^^^^^^^^^^ expected u8, found i32 +help: you can convert an `i32` to `u8` and panic if the converted value wouldn't fit + | +LL | B::get_x().try_into().unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.rs b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.rs index a5d5b93772651..d411807673c66 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.rs +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.rs @@ -13,8 +13,8 @@ struct T { struct S(str, str) where str: Sized; -fn unsized_local() where for<'a> T: Sized { - let x: T = *(Box::new(T { x: 1 }) as Box>); +fn unsized_local() where for<'a> T: Sized { + let x: T = *(Box::new(T { x: 1 }) as Box>); } fn return_str() -> str where str: Sized { diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr index a9d2634c1ad71..fda1d6d70ac58 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr @@ -7,10 +7,10 @@ LL | struct S(str, str) where str: Sized; = note: #[warn(trivial_bounds)] on by default warning: Trait bound for<'a> T<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters - --> $DIR/trivial-bounds-inconsistent-sized.rs:16:45 + --> $DIR/trivial-bounds-inconsistent-sized.rs:16:49 | -LL | fn unsized_local() where for<'a> T: Sized { - | ^^^^^ +LL | fn unsized_local() where for<'a> T: Sized { + | ^^^^^ warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-sized.rs:20:35 diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.rs b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.rs index fdbaec9a5c7ff..f6538b14d1711 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.rs +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.rs @@ -52,8 +52,8 @@ struct Dst { struct TwoStrs(str, str) where str: Sized; -fn unsized_local() where for<'a> Dst: Sized { - let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); +fn unsized_local() where for<'a> Dst: Sized { + let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); } fn return_str() -> str where str: Sized { diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr index 744e146f83003..a0d638f17147e 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr @@ -64,10 +64,10 @@ LL | struct TwoStrs(str, str) where str: Sized; | ^^^^^ warning: Trait bound for<'a> Dst<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters - --> $DIR/trivial-bounds-inconsistent.rs:55:47 + --> $DIR/trivial-bounds-inconsistent.rs:55:51 | -LL | fn unsized_local() where for<'a> Dst: Sized { - | ^^^^^ +LL | fn unsized_local() where for<'a> Dst: Sized { + | ^^^^^ warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:59:35 diff --git a/src/test/ui/trivial-bounds/trivial-bounds-leak-copy.stderr b/src/test/ui/trivial-bounds/trivial-bounds-leak-copy.stderr index b8e669d4a7c34..e96a24196863c 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-leak-copy.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-leak-copy.stderr @@ -1,8 +1,8 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `*t` which is behind a shared reference --> $DIR/trivial-bounds-leak-copy.rs:9:5 | -LL | *t //~ ERROR - | ^^ cannot move out of borrowed content +LL | *t + | ^^ move occurs because `*t` has type `std::string::String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/trivial-bounds/trivial-bounds-leak.rs b/src/test/ui/trivial-bounds/trivial-bounds-leak.rs index dc4f1c7f9fc16..249051d806701 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-leak.rs +++ b/src/test/ui/trivial-bounds/trivial-bounds-leak.rs @@ -29,4 +29,3 @@ fn foo() { fn generic_function(t: T) {} fn main() {} - diff --git a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr index aa055d3dc03f5..46b4b2a878492 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr @@ -1,7 +1,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/trivial-bounds-leak.rs:12:25 | -LL | fn cant_return_str() -> str { //~ ERROR +LL | fn cant_return_str() -> str { | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` @@ -11,7 +11,7 @@ LL | fn cant_return_str() -> str { //~ ERROR error[E0599]: no method named `test` found for type `i32` in the current scope --> $DIR/trivial-bounds-leak.rs:24:10 | -LL | 3i32.test(); //~ ERROR +LL | 3i32.test(); | ^^^^ | = help: items from traits can only be used if the trait is implemented and in scope @@ -21,7 +21,7 @@ LL | 3i32.test(); //~ ERROR error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/trivial-bounds-leak.rs:25:5 | -LL | Foo::test(&4i32); //~ ERROR +LL | Foo::test(&4i32); | ^^^^^^^^^ the trait `Foo` is not implemented for `i32` | note: required by `Foo::test` @@ -33,7 +33,7 @@ LL | fn test(&self); error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/trivial-bounds-leak.rs:26:5 | -LL | generic_function(5i32); //~ ERROR +LL | generic_function(5i32); | ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32` | note: required by `generic_function` @@ -44,5 +44,5 @@ LL | fn generic_function(t: T) {} error: aborting due to 4 previous errors -Some errors occurred: E0277, E0599. +Some errors have detailed explanations: E0277, E0599. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr b/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr index 6518e90287881..2f4b2df24cd54 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr @@ -1,7 +1,7 @@ error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:5:21 | -LL | struct A where i32: Copy; //~ ERROR +LL | struct A where i32: Copy; | ^^^^ | note: lint level defined here @@ -13,13 +13,13 @@ LL | #![deny(trivial_bounds)] error: Trait bound i32: X<()> does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:18:30 | -LL | fn global_param() where i32: X<()> {} //~ ERROR +LL | fn global_param() where i32: X<()> {} | ^^^^^ error: Trait bound i32: Z does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:22:35 | -LL | fn global_projection() where i32: Z {} //~ ERROR +LL | fn global_projection() where i32: Z {} | ^^^^^^^^^^ error: Lifetime bound i32 : 'static does not depend on any type or lifetime parameters @@ -37,13 +37,13 @@ LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {} error: Lifetime bound 'static : 'static does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:35:37 | -LL | fn global_outlives() where 'static: 'static {} //~ ERROR +LL | fn global_outlives() where 'static: 'static {} | ^^^^^^^ error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:38:46 | -LL | fn mixed_bounds() where i32: X + Copy {} //~ ERROR +LL | fn mixed_bounds() where i32: X + Copy {} | ^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/trivial_casts.rs b/src/test/ui/trivial_casts.rs index c1f5441a36b08..dd578e074fdac 100644 --- a/src/test/ui/trivial_casts.rs +++ b/src/test/ui/trivial_casts.rs @@ -49,29 +49,29 @@ pub fn main() { // unsize trait let x: &Bar = &Bar; - let _ = x as &Foo; //~ERROR trivial cast: `&Bar` as `&dyn Foo` - let _ = x as *const Foo; //~ERROR trivial cast: `&Bar` as `*const dyn Foo` - let _: &Foo = x; - let _: *const Foo = x; + let _ = x as &dyn Foo; //~ERROR trivial cast: `&Bar` as `&dyn Foo` + let _ = x as *const dyn Foo; //~ERROR trivial cast: `&Bar` as `*const dyn Foo` + let _: &dyn Foo = x; + let _: *const dyn Foo = x; let x: &mut Bar = &mut Bar; - let _ = x as &mut Foo; //~ERROR trivial cast: `&mut Bar` as `&mut dyn Foo` - let _ = x as *mut Foo; //~ERROR trivial cast: `&mut Bar` as `*mut dyn Foo` - let _: &mut Foo = x; - let _: *mut Foo = x; + let _ = x as &mut dyn Foo; //~ERROR trivial cast: `&mut Bar` as `&mut dyn Foo` + let _ = x as *mut dyn Foo; //~ERROR trivial cast: `&mut Bar` as `*mut dyn Foo` + let _: &mut dyn Foo = x; + let _: *mut dyn Foo = x; let x: Box = Box::new(Bar); - let _ = x as Box; //~ERROR `std::boxed::Box` as `std::boxed::Box` + let _ = x as Box; //~ERROR `std::boxed::Box` as `std::boxed::Box` let x: Box = Box::new(Bar); - let _: Box = x; + let _: Box = x; // functions fn baz(_x: i32) {} - let _ = &baz as &Fn(i32); //~ERROR `&fn(i32) {main::baz}` as `&dyn std::ops::Fn(i32)` - let _: &Fn(i32) = &baz; + let _ = &baz as &dyn Fn(i32); //~ERROR `&fn(i32) {main::baz}` as `&dyn std::ops::Fn(i32)` + let _: &dyn Fn(i32) = &baz; let x = |_x: i32| {}; - let _ = &x as &Fn(i32); //~ERROR trivial cast - let _: &Fn(i32) = &x; + let _ = &x as &dyn Fn(i32); //~ERROR trivial cast + let _: &dyn Fn(i32) = &x; } // subtyping diff --git a/src/test/ui/trivial_casts.stderr b/src/test/ui/trivial_casts.stderr index fb1db76b13890..8fa44372f0b4f 100644 --- a/src/test/ui/trivial_casts.stderr +++ b/src/test/ui/trivial_casts.stderr @@ -1,7 +1,7 @@ error: trivial numeric cast: `i32` as `i32` --> $DIR/trivial_casts.rs:16:13 | -LL | let _ = 42_i32 as i32; //~ ERROR trivial numeric cast: `i32` as `i32` +LL | let _ = 42_i32 as i32; | ^^^^^^^^^^^^^ | note: lint level defined here @@ -14,7 +14,7 @@ LL | #![deny(trivial_casts, trivial_numeric_casts)] error: trivial numeric cast: `u8` as `u8` --> $DIR/trivial_casts.rs:19:13 | -LL | let _ = 42_u8 as u8; //~ ERROR trivial numeric cast: `u8` as `u8` +LL | let _ = 42_u8 as u8; | ^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable @@ -22,7 +22,7 @@ LL | let _ = 42_u8 as u8; //~ ERROR trivial numeric cast: `u8` as `u8` error: trivial cast: `&u32` as `*const u32` --> $DIR/trivial_casts.rs:24:13 | -LL | let _ = x as *const u32; //~ERROR trivial cast: `&u32` as `*const u32` +LL | let _ = x as *const u32; | ^^^^^^^^^^^^^^^ | note: lint level defined here @@ -35,7 +35,7 @@ LL | #![deny(trivial_casts, trivial_numeric_casts)] error: trivial cast: `&mut u32` as `*mut u32` --> $DIR/trivial_casts.rs:28:13 | -LL | let _ = x as *mut u32; //~ERROR trivial cast: `&mut u32` as `*mut u32` +LL | let _ = x as *mut u32; | ^^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable @@ -43,7 +43,7 @@ LL | let _ = x as *mut u32; //~ERROR trivial cast: `&mut u32` as `*mut u32` error: trivial cast: `&[u32; 3]` as `&[u32]` --> $DIR/trivial_casts.rs:33:13 | -LL | let _ = x as &[u32]; //~ERROR trivial cast: `&[u32; 3]` as `&[u32]` +LL | let _ = x as &[u32]; | ^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable @@ -51,7 +51,7 @@ LL | let _ = x as &[u32]; //~ERROR trivial cast: `&[u32; 3]` as `&[u32]` error: trivial cast: `&[u32; 3]` as `*const [u32]` --> $DIR/trivial_casts.rs:34:13 | -LL | let _ = x as *const [u32]; //~ERROR trivial cast: `&[u32; 3]` as `*const [u32]` +LL | let _ = x as *const [u32]; | ^^^^^^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable @@ -59,7 +59,7 @@ LL | let _ = x as *const [u32]; //~ERROR trivial cast: `&[u32; 3]` as `*cons error: trivial cast: `&mut [u32; 3]` as `&mut [u32]` --> $DIR/trivial_casts.rs:39:13 | -LL | let _ = x as &mut [u32]; //~ERROR trivial cast: `&mut [u32; 3]` as `&mut [u32]` +LL | let _ = x as &mut [u32]; | ^^^^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable @@ -67,7 +67,7 @@ LL | let _ = x as &mut [u32]; //~ERROR trivial cast: `&mut [u32; 3]` as `&mu error: trivial cast: `&mut [u32; 3]` as `*mut [u32]` --> $DIR/trivial_casts.rs:40:13 | -LL | let _ = x as *mut [u32]; //~ERROR trivial cast: `&mut [u32; 3]` as `*mut [u32]` +LL | let _ = x as *mut [u32]; | ^^^^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable @@ -83,63 +83,63 @@ LL | let _ = x as Box<[u32]>; error: trivial cast: `&Bar` as `&dyn Foo` --> $DIR/trivial_casts.rs:52:13 | -LL | let _ = x as &Foo; //~ERROR trivial cast: `&Bar` as `&dyn Foo` - | ^^^^^^^^^ +LL | let _ = x as &dyn Foo; + | ^^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable error: trivial cast: `&Bar` as `*const dyn Foo` --> $DIR/trivial_casts.rs:53:13 | -LL | let _ = x as *const Foo; //~ERROR trivial cast: `&Bar` as `*const dyn Foo` - | ^^^^^^^^^^^^^^^ +LL | let _ = x as *const dyn Foo; + | ^^^^^^^^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable error: trivial cast: `&mut Bar` as `&mut dyn Foo` --> $DIR/trivial_casts.rs:58:13 | -LL | let _ = x as &mut Foo; //~ERROR trivial cast: `&mut Bar` as `&mut dyn Foo` - | ^^^^^^^^^^^^^ +LL | let _ = x as &mut dyn Foo; + | ^^^^^^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable error: trivial cast: `&mut Bar` as `*mut dyn Foo` --> $DIR/trivial_casts.rs:59:13 | -LL | let _ = x as *mut Foo; //~ERROR trivial cast: `&mut Bar` as `*mut dyn Foo` - | ^^^^^^^^^^^^^ +LL | let _ = x as *mut dyn Foo; + | ^^^^^^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable error: trivial cast: `std::boxed::Box` as `std::boxed::Box` --> $DIR/trivial_casts.rs:64:13 | -LL | let _ = x as Box; //~ERROR `std::boxed::Box` as `std::boxed::Box` - | ^^^^^^^^^^^^^ +LL | let _ = x as Box; + | ^^^^^^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable error: trivial cast: `&fn(i32) {main::baz}` as `&dyn std::ops::Fn(i32)` --> $DIR/trivial_casts.rs:70:13 | -LL | let _ = &baz as &Fn(i32); //~ERROR `&fn(i32) {main::baz}` as `&dyn std::ops::Fn(i32)` - | ^^^^^^^^^^^^^^^^ +LL | let _ = &baz as &dyn Fn(i32); + | ^^^^^^^^^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable error: trivial cast: `&[closure@$DIR/trivial_casts.rs:72:13: 72:25]` as `&dyn std::ops::Fn(i32)` --> $DIR/trivial_casts.rs:73:13 | -LL | let _ = &x as &Fn(i32); //~ERROR trivial cast - | ^^^^^^^^^^^^^^ +LL | let _ = &x as &dyn Fn(i32); + | ^^^^^^^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable error: trivial cast: `&'a Bar` as `&'a Bar` --> $DIR/trivial_casts.rs:79:13 | -LL | let _ = a as &'a Bar; //~ERROR trivial cast +LL | let _ = a as &'a Bar; | ^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable @@ -147,7 +147,7 @@ LL | let _ = a as &'a Bar; //~ERROR trivial cast error: trivial cast: `&'b Bar` as `&'a Bar` --> $DIR/trivial_casts.rs:81:13 | -LL | let _ = b as &'a Bar; //~ERROR trivial cast +LL | let _ = b as &'a Bar; | ^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable @@ -155,7 +155,7 @@ LL | let _ = b as &'a Bar; //~ERROR trivial cast error: trivial cast: `&'b Bar` as `&'b Bar` --> $DIR/trivial_casts.rs:83:13 | -LL | let _ = b as &'b Bar; //~ERROR trivial cast +LL | let _ = b as &'b Bar; | ^^^^^^^^^^^^ | = help: cast can be replaced by coercion; this might require a temporary variable diff --git a/src/test/ui/try-block/try-block-bad-lifetime.rs b/src/test/ui/try-block/try-block-bad-lifetime.rs index 872604f4eee84..6063e2e463e2e 100644 --- a/src/test/ui/try-block/try-block-bad-lifetime.rs +++ b/src/test/ui/try-block/try-block-bad-lifetime.rs @@ -35,4 +35,3 @@ pub fn main() { *i_ptr = 50; } } - diff --git a/src/test/ui/try-block/try-block-bad-lifetime.stderr b/src/test/ui/try-block/try-block-bad-lifetime.stderr index b1b925d694ff9..de1667d8832b7 100644 --- a/src/test/ui/try-block/try-block-bad-lifetime.stderr +++ b/src/test/ui/try-block/try-block-bad-lifetime.stderr @@ -16,10 +16,10 @@ error[E0506]: cannot assign to `i` because it is borrowed LL | let k = &mut i; | ------ borrow of `i` occurs here ... -LL | i = 10; //~ ERROR cannot assign to `i` because it is borrowed +LL | i = 10; | ^^^^^^ assignment to borrowed `i` occurs here LL | }; -LL | ::std::mem::drop(k); //~ ERROR use of moved value: `k` +LL | ::std::mem::drop(k); | - borrow later used here error[E0382]: use of moved value: `k` @@ -31,7 +31,7 @@ LL | let mut j: Result<(), &mut i32> = try { LL | Err(k) ?; | - value moved here ... -LL | ::std::mem::drop(k); //~ ERROR use of moved value: `k` +LL | ::std::mem::drop(k); | ^ value used here after move error[E0506]: cannot assign to `i` because it is borrowed @@ -40,7 +40,7 @@ error[E0506]: cannot assign to `i` because it is borrowed LL | let k = &mut i; | ------ borrow of `i` occurs here ... -LL | i = 40; //~ ERROR cannot assign to `i` because it is borrowed +LL | i = 40; | ^^^^^^ assignment to borrowed `i` occurs here LL | LL | let i_ptr = if let Err(i_ptr) = j { i_ptr } else { panic ! ("") }; @@ -48,5 +48,5 @@ LL | let i_ptr = if let Err(i_ptr) = j { i_ptr } else { panic ! ("") }; error: aborting due to 4 previous errors -Some errors occurred: E0382, E0506, E0597. +Some errors have detailed explanations: E0382, E0506, E0597. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/try-block/try-block-bad-type.rs b/src/test/ui/try-block/try-block-bad-type.rs index 0e297dd8ff16b..4dfc8e6a2fca4 100644 --- a/src/test/ui/try-block/try-block-bad-type.rs +++ b/src/test/ui/try-block/try-block-bad-type.rs @@ -4,7 +4,7 @@ pub fn main() { let res: Result = try { - Err("")?; //~ ERROR the trait bound `i32: std::convert::From<&str>` is not satisfied + Err("")?; //~ ERROR `?` couldn't convert the error 5 }; diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr index df8e646280c9a..e1c2c6b675e9b 100644 --- a/src/test/ui/try-block/try-block-bad-type.stderr +++ b/src/test/ui/try-block/try-block-bad-type.stderr @@ -1,21 +1,22 @@ -error[E0277]: the trait bound `i32: std::convert::From<&str>` is not satisfied - --> $DIR/try-block-bad-type.rs:7:9 +error[E0277]: `?` couldn't convert the error to `i32` + --> $DIR/try-block-bad-type.rs:7:16 | -LL | Err("")?; //~ ERROR the trait bound `i32: std::convert::From<&str>` is not satisfied - | ^^^^^^^^ the trait `std::convert::From<&str>` is not implemented for `i32` +LL | Err("")?; + | ^ the trait `std::convert::From<&str>` is not implemented for `i32` | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following implementations were found: > - > > > + > and 2 others = note: required by `std::convert::From::from` error[E0271]: type mismatch resolving ` as std::ops::Try>::Ok == &str` --> $DIR/try-block-bad-type.rs:12:9 | -LL | "" //~ ERROR type mismatch +LL | "" | ^^ expected i32, found &str | = note: expected type `i32` @@ -24,7 +25,7 @@ LL | "" //~ ERROR type mismatch error[E0271]: type mismatch resolving ` as std::ops::Try>::Ok == ()` --> $DIR/try-block-bad-type.rs:15:39 | -LL | let res: Result = try { }; //~ ERROR type mismatch +LL | let res: Result = try { }; | ^ expected i32, found () | = note: expected type `i32` @@ -33,7 +34,7 @@ LL | let res: Result = try { }; //~ ERROR type mismatch error[E0277]: the trait bound `(): std::ops::Try` is not satisfied --> $DIR/try-block-bad-type.rs:17:23 | -LL | let res: () = try { }; //~ the trait bound `(): std::ops::Try` is not satisfied +LL | let res: () = try { }; | ^^^ the trait `std::ops::Try` is not implemented for `()` | = note: required by `std::ops::Try::from_ok` @@ -41,12 +42,12 @@ LL | let res: () = try { }; //~ the trait bound `(): std::ops::Try` is not s error[E0277]: the trait bound `i32: std::ops::Try` is not satisfied --> $DIR/try-block-bad-type.rs:19:24 | -LL | let res: i32 = try { 5 }; //~ ERROR the trait bound `i32: std::ops::Try` is not satisfied +LL | let res: i32 = try { 5 }; | ^^^^^ the trait `std::ops::Try` is not implemented for `i32` | = note: required by `std::ops::Try::from_ok` error: aborting due to 5 previous errors -Some errors occurred: E0271, E0277. +Some errors have detailed explanations: E0271, E0277. For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/try-block/try-block-catch.rs b/src/test/ui/try-block/try-block-catch.rs new file mode 100644 index 0000000000000..d165015611d04 --- /dev/null +++ b/src/test/ui/try-block/try-block-catch.rs @@ -0,0 +1,10 @@ +// compile-flags: --edition 2018 + +#![feature(try_blocks)] + +fn main() { + let res: Option = try { + true + } catch { }; + //~^ ERROR keyword `catch` cannot follow a `try` block +} diff --git a/src/test/ui/try-block/try-block-catch.stderr b/src/test/ui/try-block/try-block-catch.stderr new file mode 100644 index 0000000000000..39cf943f4d8ab --- /dev/null +++ b/src/test/ui/try-block/try-block-catch.stderr @@ -0,0 +1,10 @@ +error: keyword `catch` cannot follow a `try` block + --> $DIR/try-block-catch.rs:8:7 + | +LL | } catch { }; + | ^^^^^ + | + = help: try using `match` on the result of the `try` block instead + +error: aborting due to previous error + diff --git a/src/test/ui/try-block/try-block-in-edition2015.stderr b/src/test/ui/try-block/try-block-in-edition2015.stderr index 7394fec6f3660..7034cdce7553d 100644 --- a/src/test/ui/try-block/try-block-in-edition2015.stderr +++ b/src/test/ui/try-block/try-block-in-edition2015.stderr @@ -3,12 +3,12 @@ error: expected identifier, found keyword `let` | LL | let try_result: Option<_> = try { | --- while parsing this struct -LL | //~^ ERROR expected struct, variant or union type, found macro `try` -LL | let x = 5; //~ ERROR expected identifier, found keyword +LL | +LL | let x = 5; | ^^^ expected identifier, found keyword help: you can escape reserved keywords to use them as identifiers | -LL | r#let x = 5; //~ ERROR expected identifier, found keyword +LL | r#let x = 5; | ^^^^^ error[E0574]: expected struct, variant or union type, found macro `try` @@ -21,4 +21,3 @@ LL | let try_result: Option<_> = try { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0574`. diff --git a/src/test/ui/try-block/try-block-in-match.stderr b/src/test/ui/try-block/try-block-in-match.stderr index 089347073b5c6..936e0fe19bafe 100644 --- a/src/test/ui/try-block/try-block-in-match.stderr +++ b/src/test/ui/try-block/try-block-in-match.stderr @@ -1,7 +1,7 @@ error: expected expression, found reserved keyword `try` --> $DIR/try-block-in-match.rs:6:11 | -LL | match try { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `try` +LL | match try { false } { _ => {} } | ----- ^^^ expected expression | | | while parsing this match expression diff --git a/src/test/ui/try-block/try-block-in-while.stderr b/src/test/ui/try-block/try-block-in-while.stderr index b4f17778b2983..026df15eb877a 100644 --- a/src/test/ui/try-block/try-block-in-while.stderr +++ b/src/test/ui/try-block/try-block-in-while.stderr @@ -1,7 +1,7 @@ error: expected expression, found reserved keyword `try` --> $DIR/try-block-in-while.rs:6:11 | -LL | while try { false } {} //~ ERROR expected expression, found reserved keyword `try` +LL | while try { false } {} | ^^^ expected expression error: aborting due to previous error diff --git a/src/test/ui/try-block/try-block-maybe-bad-lifetime.rs b/src/test/ui/try-block/try-block-maybe-bad-lifetime.rs index 113d089c757c0..1d1c3d980e230 100644 --- a/src/test/ui/try-block/try-block-maybe-bad-lifetime.rs +++ b/src/test/ui/try-block/try-block-maybe-bad-lifetime.rs @@ -42,4 +42,3 @@ pub fn main() { do_something_with(j); } } - diff --git a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr index dafbde6a5150b..1f0e09277ba97 100644 --- a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr +++ b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr @@ -4,7 +4,7 @@ error[E0506]: cannot assign to `i` because it is borrowed LL | &i | -- borrow of `i` occurs here LL | }; -LL | i = 0; //~ ERROR cannot assign to `i` because it is borrowed +LL | i = 0; | ^^^^^ assignment to borrowed `i` occurs here LL | let _ = i; LL | do_something_with(x); @@ -19,7 +19,7 @@ LL | let x = String::new(); LL | ::std::mem::drop(x); | - value moved here LL | }; -LL | println!("{}", x); //~ ERROR borrow of moved value: `x` +LL | println!("{}", x); | ^ value borrowed here after move error[E0506]: cannot assign to `i` because it is borrowed @@ -28,7 +28,7 @@ error[E0506]: cannot assign to `i` because it is borrowed LL | j = &i; | -- borrow of `i` occurs here LL | }; -LL | i = 0; //~ ERROR cannot assign to `i` because it is borrowed +LL | i = 0; | ^^^^^ assignment to borrowed `i` occurs here LL | let _ = i; LL | do_something_with(j); @@ -36,5 +36,5 @@ LL | do_something_with(j); error: aborting due to 3 previous errors -Some errors occurred: E0382, E0506. +Some errors have detailed explanations: E0382, E0506. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/try-block/try-block-opt-init.rs b/src/test/ui/try-block/try-block-opt-init.rs index ef559226e67df..2387db8de4d6a 100644 --- a/src/test/ui/try-block/try-block-opt-init.rs +++ b/src/test/ui/try-block/try-block-opt-init.rs @@ -14,4 +14,3 @@ pub fn main() { }; assert_eq!(cfg_res, 5); //~ ERROR borrow of possibly uninitialized variable: `cfg_res` } - diff --git a/src/test/ui/try-block/try-block-opt-init.stderr b/src/test/ui/try-block/try-block-opt-init.stderr index a0bc45d4fcd5c..ec0128dbdf0fc 100644 --- a/src/test/ui/try-block/try-block-opt-init.stderr +++ b/src/test/ui/try-block/try-block-opt-init.stderr @@ -1,7 +1,7 @@ error[E0381]: borrow of possibly uninitialized variable: `cfg_res` --> $DIR/try-block-opt-init.rs:15:5 | -LL | assert_eq!(cfg_res, 5); //~ ERROR borrow of possibly uninitialized variable: `cfg_res` +LL | assert_eq!(cfg_res, 5); | ^^^^^^^^^^^^^^^^^^^^^^^ use of possibly uninitialized `cfg_res` | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/try-on-option.rs b/src/test/ui/try-on-option.rs index 9c8e8b33ad68a..5d94cee8e3721 100644 --- a/src/test/ui/try-on-option.rs +++ b/src/test/ui/try-on-option.rs @@ -4,12 +4,12 @@ fn main() {} fn foo() -> Result { let x: Option = None; - x?; //~ the trait bound + x?; //~ ERROR `?` couldn't convert the error Ok(22) } fn bar() -> u32 { let x: Option = None; - x?; //~ the `?` operator + x?; //~ ERROR the `?` operator 22 } diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr index 438b3c2e343ff..db5046f8c151a 100644 --- a/src/test/ui/try-on-option.stderr +++ b/src/test/ui/try-on-option.stderr @@ -1,15 +1,16 @@ -error[E0277]: the trait bound `(): std::convert::From` is not satisfied - --> $DIR/try-on-option.rs:7:5 +error[E0277]: `?` couldn't convert the error to `()` + --> $DIR/try-on-option.rs:7:6 | -LL | x?; //~ the trait bound - | ^^ the trait `std::convert::From` is not implemented for `()` +LL | x?; + | ^ the trait `std::convert::From` is not implemented for `()` | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = note: required by `std::convert::From::from` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/try-on-option.rs:13:5 | -LL | x?; //~ the `?` operator +LL | x?; | ^^ cannot use the `?` operator in a function that returns `u32` | = help: the trait `std::ops::Try` is not implemented for `u32` diff --git a/src/test/ui/try-operator-on-main.stderr b/src/test/ui/try-operator-on-main.stderr index 9a2052f72835d..9f120e009485e 100644 --- a/src/test/ui/try-operator-on-main.stderr +++ b/src/test/ui/try-operator-on-main.stderr @@ -1,7 +1,7 @@ error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/try-operator-on-main.rs:9:5 | -LL | std::fs::File::open("foo")?; //~ ERROR the `?` operator can only +LL | std::fs::File::open("foo")?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` | = help: the trait `std::ops::Try` is not implemented for `()` @@ -10,7 +10,7 @@ LL | std::fs::File::open("foo")?; //~ ERROR the `?` operator can only error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` --> $DIR/try-operator-on-main.rs:12:5 | -LL | ()?; //~ ERROR the `?` operator can only +LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | = help: the trait `std::ops::Try` is not implemented for `()` @@ -19,7 +19,7 @@ LL | ()?; //~ ERROR the `?` operator can only error[E0277]: the trait bound `(): std::ops::Try` is not satisfied --> $DIR/try-operator-on-main.rs:15:5 | -LL | try_trait_generic::<()>(); //~ ERROR the trait bound +LL | try_trait_generic::<()>(); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Try` is not implemented for `()` | note: required by `try_trait_generic` @@ -31,7 +31,7 @@ LL | fn try_trait_generic() -> T { error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` --> $DIR/try-operator-on-main.rs:22:5 | -LL | ()?; //~ ERROR the `?` operator can only +LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | = help: the trait `std::ops::Try` is not implemented for `()` diff --git a/src/test/ui/try-poll.rs b/src/test/ui/try-poll.rs index 3d7115c522346..f63950ad5e905 100644 --- a/src/test/ui/try-poll.rs +++ b/src/test/ui/try-poll.rs @@ -1,7 +1,6 @@ // compile-pass #![allow(dead_code, unused)] -#![feature(futures_api)] use std::task::Poll; diff --git a/src/test/ui/tuple/tuple-arity-mismatch.rs b/src/test/ui/tuple/tuple-arity-mismatch.rs index 1c8b881d2469e..4f505c05a6a2c 100644 --- a/src/test/ui/tuple/tuple-arity-mismatch.rs +++ b/src/test/ui/tuple/tuple-arity-mismatch.rs @@ -13,5 +13,5 @@ fn main() { //~^ ERROR mismatched types //~| expected type `(isize, f64)` //~| found type `(isize,)` - //~| expected a tuple with 2 elements, found one with 1 elements + //~| expected a tuple with 2 elements, found one with 1 element } diff --git a/src/test/ui/tuple/tuple-arity-mismatch.stderr b/src/test/ui/tuple/tuple-arity-mismatch.stderr index 650f4c58c776c..6946a60c59af9 100644 --- a/src/test/ui/tuple/tuple-arity-mismatch.stderr +++ b/src/test/ui/tuple/tuple-arity-mismatch.stderr @@ -11,7 +11,7 @@ error[E0308]: mismatched types --> $DIR/tuple-arity-mismatch.rs:12:20 | LL | let y = first ((1,)); - | ^^^^ expected a tuple with 2 elements, found one with 1 elements + | ^^^^ expected a tuple with 2 elements, found one with 1 element | = note: expected type `(isize, f64)` found type `(isize,)` diff --git a/src/test/ui/tuple/tuple-float-index.stderr b/src/test/ui/tuple/tuple-float-index.stderr index 9a3e384b9d1c9..a0ea0e0a30a72 100644 --- a/src/test/ui/tuple/tuple-float-index.stderr +++ b/src/test/ui/tuple/tuple-float-index.stderr @@ -1,7 +1,7 @@ error: unexpected token: `1.1` --> $DIR/tuple-float-index.rs:4:17 | -LL | (1, (2, 3)).1.1; //~ ERROR unexpected token: `1.1` +LL | (1, (2, 3)).1.1; | ------------^^^ | | | | | unexpected token diff --git a/src/test/ui/tuple/tuple-struct-fields/test2.stderr b/src/test/ui/tuple/tuple-struct-fields/test2.stderr index 80f0ddc0e4fcd..78176c67ed201 100644 --- a/src/test/ui/tuple/tuple-struct-fields/test2.stderr +++ b/src/test/ui/tuple/tuple-struct-fields/test2.stderr @@ -4,13 +4,13 @@ error: expected one of `)` or `,`, found `(` LL | struct S3(pub $t ()); | ^ expected one of `)` or `,` here ... -LL | define_struct! { (foo) } //~ ERROR cannot find type `foo` in this scope +LL | define_struct! { (foo) } | ------------------------ in this macro invocation error[E0412]: cannot find type `foo` in this scope --> $DIR/test2.rs:11:23 | -LL | define_struct! { (foo) } //~ ERROR cannot find type `foo` in this scope +LL | define_struct! { (foo) } | ^^^ not found in this scope error: aborting due to 2 previous errors diff --git a/src/test/ui/tuple/tuple-struct-fields/test3.stderr b/src/test/ui/tuple/tuple-struct-fields/test3.stderr index fbc01744fe445..e105aad09e6b5 100644 --- a/src/test/ui/tuple/tuple-struct-fields/test3.stderr +++ b/src/test/ui/tuple/tuple-struct-fields/test3.stderr @@ -4,13 +4,13 @@ error: expected one of `)` or `,`, found `(` LL | struct S3(pub($t) ()); | ^ expected one of `)` or `,` here ... -LL | define_struct! { foo } //~ ERROR cannot find type `foo` in this scope +LL | define_struct! { foo } | ---------------------- in this macro invocation error[E0412]: cannot find type `foo` in this scope --> $DIR/test3.rs:11:22 | -LL | define_struct! { foo } //~ ERROR cannot find type `foo` in this scope +LL | define_struct! { foo } | ^^^ not found in this scope error: aborting due to 2 previous errors diff --git a/src/test/ui/tuple/tuple-struct-nonexhaustive.stderr b/src/test/ui/tuple/tuple-struct-nonexhaustive.stderr index 8d627fc2a8d72..bbdf9ceed23a2 100644 --- a/src/test/ui/tuple/tuple-struct-nonexhaustive.stderr +++ b/src/test/ui/tuple/tuple-struct-nonexhaustive.stderr @@ -1,8 +1,13 @@ error[E0004]: non-exhaustive patterns: `Foo(_, _)` not covered --> $DIR/tuple-struct-nonexhaustive.rs:5:11 | -LL | match x { //~ ERROR non-exhaustive +LL | struct Foo(isize, isize); + | ------------------------- `Foo` defined here +... +LL | match x { | ^ pattern `Foo(_, _)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error: aborting due to previous error diff --git a/src/test/ui/tutorial-suffix-inference-test.stderr b/src/test/ui/tutorial-suffix-inference-test.stderr index 6ba1b098d19b7..f3e1cc41cada2 100644 --- a/src/test/ui/tutorial-suffix-inference-test.stderr +++ b/src/test/ui/tutorial-suffix-inference-test.stderr @@ -2,23 +2,30 @@ error[E0308]: mismatched types --> $DIR/tutorial-suffix-inference-test.rs:9:18 | LL | identity_u16(x); - | ^ expected u16, found u8 -help: you can cast an `u8` to `u16`, which will zero-extend the source value - | -LL | identity_u16(x.into()); - | ^^^^^^^^ + | ^ + | | + | expected u16, found u8 + | help: you can convert an `u8` to `u16`: `x.into()` error[E0308]: mismatched types --> $DIR/tutorial-suffix-inference-test.rs:12:18 | LL | identity_u16(y); | ^ expected u16, found i32 +help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit + | +LL | identity_u16(y.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/tutorial-suffix-inference-test.rs:21:18 | LL | identity_u16(a); | ^ expected u16, found isize +help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit + | +LL | identity_u16(a.try_into().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/type-alias-enum-variants-panic.rs b/src/test/ui/type-alias-enum-variants-panic.rs deleted file mode 100644 index f97592f5d3b15..0000000000000 --- a/src/test/ui/type-alias-enum-variants-panic.rs +++ /dev/null @@ -1,17 +0,0 @@ -// ignore-tidy-linelength - -#![feature(type_alias_enum_variants)] - -#![allow(unreachable_code)] - -enum Enum { Variant {} } -type Alias = Enum; - -fn main() { - Alias::Variant; - //~^ ERROR expected unit struct/variant or constant, found struct variant `::Variant` [E0533] - let Alias::Variant = panic!(); - //~^ ERROR expected unit struct/variant or constant, found struct variant `::Variant` [E0533] - let Alias::Variant(..) = panic!(); - //~^ ERROR expected tuple struct/variant, found struct variant `::Variant` [E0164] -} diff --git a/src/test/ui/type-alias-enum-variants-panic.stderr b/src/test/ui/type-alias-enum-variants-panic.stderr deleted file mode 100644 index 3480d116383ee..0000000000000 --- a/src/test/ui/type-alias-enum-variants-panic.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0533]: expected unit struct/variant or constant, found struct variant `::Variant` - --> $DIR/type-alias-enum-variants-panic.rs:11:5 - | -LL | Alias::Variant; - | ^^^^^^^^^^^^^^ - -error[E0533]: expected unit struct/variant or constant, found struct variant `::Variant` - --> $DIR/type-alias-enum-variants-panic.rs:13:9 - | -LL | let Alias::Variant = panic!(); - | ^^^^^^^^^^^^^^ - -error[E0164]: expected tuple struct/variant, found struct variant `::Variant` - --> $DIR/type-alias-enum-variants-panic.rs:15:9 - | -LL | let Alias::Variant(..) = panic!(); - | ^^^^^^^^^^^^^^^^^^ not a tuple variant or struct - -error: aborting due to 3 previous errors - -Some errors occurred: E0164, E0533. -For more information about an error, try `rustc --explain E0164`. diff --git a/src/test/ui/type-alias-enum-variants-priority-2.rs b/src/test/ui/type-alias-enum-variants-priority-2.rs deleted file mode 100644 index 295f8acf62f85..0000000000000 --- a/src/test/ui/type-alias-enum-variants-priority-2.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![feature(type_alias_enum_variants)] - -enum E { - V(u8) -} - -impl E { - fn V() {} -} - -fn main() { - ::V(); //~ ERROR this function takes 1 parameter but 0 parameters were supplied -} diff --git a/src/test/ui/type-alias-enum-variants-priority-2.stderr b/src/test/ui/type-alias-enum-variants-priority-2.stderr deleted file mode 100644 index c6ec96ebb7d3b..0000000000000 --- a/src/test/ui/type-alias-enum-variants-priority-2.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0061]: this function takes 1 parameter but 0 parameters were supplied - --> $DIR/type-alias-enum-variants-priority-2.rs:12:5 - | -LL | V(u8) - | ----- defined here -... -LL | ::V(); //~ ERROR this function takes 1 parameter but 0 parameters were supplied - | ^^^^^^^^ expected 1 parameter - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0061`. diff --git a/src/test/ui/type-alias-enum-variants-priority-3.rs b/src/test/ui/type-alias-enum-variants-priority-3.rs deleted file mode 100644 index 33f96553b57f0..0000000000000 --- a/src/test/ui/type-alias-enum-variants-priority-3.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(type_alias_enum_variants)] - -enum E { - V -} - -fn check() -> ::V {} -//~^ ERROR expected type, found variant `V` - -fn main() {} diff --git a/src/test/ui/type-alias-enum-variants-priority-3.stderr b/src/test/ui/type-alias-enum-variants-priority-3.stderr deleted file mode 100644 index b3451542a2570..0000000000000 --- a/src/test/ui/type-alias-enum-variants-priority-3.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: expected type, found variant `V` - --> $DIR/type-alias-enum-variants-priority-3.rs:7:15 - | -LL | fn check() -> ::V {} - | ^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/type-alias-enum-variants-priority.rs b/src/test/ui/type-alias-enum-variants-priority.rs deleted file mode 100644 index db1da2b12e256..0000000000000 --- a/src/test/ui/type-alias-enum-variants-priority.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![feature(type_alias_enum_variants)] -#![deny(ambiguous_associated_items)] - -enum E { - V -} - -trait Tr { - type V; - fn f() -> Self::V; -} - -impl Tr for E { - type V = u8; - fn f() -> Self::V { 0 } - //~^ ERROR ambiguous associated item - //~| WARN this was previously accepted -} - -fn main() {} diff --git a/src/test/ui/type-alias-enum-variants-priority.stderr b/src/test/ui/type-alias-enum-variants-priority.stderr deleted file mode 100644 index dcf7dc77ed5ea..0000000000000 --- a/src/test/ui/type-alias-enum-variants-priority.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: ambiguous associated item - --> $DIR/type-alias-enum-variants-priority.rs:15:15 - | -LL | fn f() -> Self::V { 0 } - | ^^^^^^^ help: use fully-qualified syntax: `::V` - | -note: lint level defined here - --> $DIR/type-alias-enum-variants-priority.rs:2:9 - | -LL | #![deny(ambiguous_associated_items)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57644 -note: `V` could refer to variant defined here - --> $DIR/type-alias-enum-variants-priority.rs:5:5 - | -LL | V - | ^ -note: `V` could also refer to associated type defined here - --> $DIR/type-alias-enum-variants-priority.rs:9:5 - | -LL | type V; - | ^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/type-alias-enum-variants.rs b/src/test/ui/type-alias-enum-variants.rs deleted file mode 100644 index 3ec200d57c55d..0000000000000 --- a/src/test/ui/type-alias-enum-variants.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(type_alias_enum_variants)] - -type Alias = Option; - -fn main() { - let _ = Option::::None; // OK - let _ = Option::None::; // OK (Lint in future!) - let _ = Alias::::None; // OK - let _ = Alias::None::; // Error - //~^ type arguments are not allowed on this entity -} diff --git a/src/test/ui/type-alias-enum-variants.stderr b/src/test/ui/type-alias-enum-variants.stderr deleted file mode 100644 index cf81f5b27ac6b..0000000000000 --- a/src/test/ui/type-alias-enum-variants.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0109]: type arguments are not allowed on this entity - --> $DIR/type-alias-enum-variants.rs:9:27 - | -LL | let _ = Alias::None::; // Error - | ^^ type argument not allowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0109`. diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args-pass.rs b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args-pass.rs new file mode 100644 index 0000000000000..0c212096f9234 --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args-pass.rs @@ -0,0 +1,59 @@ +// run-pass + +// Check that resolving, in the value namespace, to an `enum` variant +// through a type alias is well behaved in the presence of generics. +// We check for situations with: +// 1. a generic type `Alias`, we can type-apply `Alias` when referring to a variant. +// 2. a monotype `AliasFixed` of generic `Enum`, we can refer to variants +// and the type-application of `T` in `AliasFixed` is kept. + +#![allow(irrefutable_let_patterns)] + +enum Enum { TSVariant(T), SVariant { v: T }, UVariant } +type Alias = Enum; +type AliasFixed = Enum<()>; + +macro_rules! is_variant { + (TSVariant, $expr:expr) => (is_variant!(@check TSVariant, (_), $expr)); + (SVariant, $expr:expr) => (is_variant!(@check SVariant, { v: _ }, $expr)); + (UVariant, $expr:expr) => (is_variant!(@check UVariant, {}, $expr)); + (@check $variant:ident, $matcher:tt, $expr:expr) => ( + assert!(if let Enum::$variant::<()> $matcher = $expr { true } else { false }, + "expr does not have correct type"); + ); +} + +fn main() { + // Tuple struct variant + + is_variant!(TSVariant, Enum::TSVariant(())); + is_variant!(TSVariant, Enum::TSVariant::<()>(())); + is_variant!(TSVariant, Enum::<()>::TSVariant(())); + + is_variant!(TSVariant, Alias::TSVariant(())); + is_variant!(TSVariant, Alias::<()>::TSVariant(())); + + is_variant!(TSVariant, AliasFixed::TSVariant(())); + + // Struct variant + + is_variant!(SVariant, Enum::SVariant { v: () }); + is_variant!(SVariant, Enum::SVariant::<()> { v: () }); + is_variant!(SVariant, Enum::<()>::SVariant { v: () }); + + is_variant!(SVariant, Alias::SVariant { v: () }); + is_variant!(SVariant, Alias::<()>::SVariant { v: () }); + + is_variant!(SVariant, AliasFixed::SVariant { v: () }); + + // Unit variant + + is_variant!(UVariant, Enum::UVariant); + is_variant!(UVariant, Enum::UVariant::<()>); + is_variant!(UVariant, Enum::<()>::UVariant); + + is_variant!(UVariant, Alias::UVariant); + is_variant!(UVariant, Alias::<()>::UVariant); + + is_variant!(UVariant, AliasFixed::UVariant); +} diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.rs b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.rs new file mode 100644 index 0000000000000..f182c3ba8c798 --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.rs @@ -0,0 +1,105 @@ +// Checks that applied type arguments of enums, and aliases to them, are respected. +// For example, `Self` is never a type constructor. Therefore, no types can be applied to it. +// +// We also check that the variant to an type-aliased enum cannot be type applied whether +// that alias is generic or monomorphic. + +enum Enum { TSVariant(T), SVariant { v: T }, UVariant } +type Alias = Enum; +type AliasFixed = Enum<()>; + +impl Enum { + fn ts_variant() { + Self::TSVariant(()); + //~^ ERROR mismatched types [E0308] + Self::TSVariant::<()>(()); + //~^ ERROR type arguments are not allowed for this type [E0109] + Self::<()>::TSVariant(()); + //~^ ERROR type arguments are not allowed for this type [E0109] + //~^^ ERROR mismatched types [E0308] + Self::<()>::TSVariant::<()>(()); + //~^ ERROR type arguments are not allowed for this type [E0109] + //~^^ ERROR type arguments are not allowed for this type [E0109] + } + + fn s_variant() { + Self::SVariant { v: () }; + //~^ ERROR mismatched types [E0308] + Self::SVariant::<()> { v: () }; + //~^ ERROR type arguments are not allowed for this type [E0109] + //~^^ ERROR mismatched types [E0308] + Self::<()>::SVariant { v: () }; + //~^ ERROR type arguments are not allowed for this type [E0109] + //~^^ ERROR mismatched types [E0308] + Self::<()>::SVariant::<()> { v: () }; + //~^ ERROR type arguments are not allowed for this type [E0109] + //~^^ ERROR type arguments are not allowed for this type [E0109] + //~^^^ ERROR mismatched types [E0308] + } + + fn u_variant() { + Self::UVariant::<()>; + //~^ ERROR type arguments are not allowed for this type [E0109] + Self::<()>::UVariant; + //~^ ERROR type arguments are not allowed for this type [E0109] + Self::<()>::UVariant::<()>; + //~^ ERROR type arguments are not allowed for this type [E0109] + //~^^ ERROR type arguments are not allowed for this type [E0109] + } +} + +fn main() { + // Tuple struct variant + + Enum::<()>::TSVariant::<()>(()); + //~^ ERROR type arguments are not allowed for this type [E0109] + + Alias::TSVariant::<()>(()); + //~^ ERROR type arguments are not allowed for this type [E0109] + Alias::<()>::TSVariant::<()>(()); + //~^ ERROR type arguments are not allowed for this type [E0109] + + AliasFixed::TSVariant::<()>(()); + //~^ ERROR type arguments are not allowed for this type [E0109] + AliasFixed::<()>::TSVariant(()); + //~^ ERROR wrong number of type arguments: expected 0, found 1 [E0107] + AliasFixed::<()>::TSVariant::<()>(()); + //~^ ERROR type arguments are not allowed for this type [E0109] + //~^^ ERROR wrong number of type arguments: expected 0, found 1 [E0107] + + // Struct variant + + Enum::<()>::SVariant::<()> { v: () }; + //~^ ERROR type arguments are not allowed for this type [E0109] + + Alias::SVariant::<()> { v: () }; + //~^ ERROR type arguments are not allowed for this type [E0109] + Alias::<()>::SVariant::<()> { v: () }; + //~^ ERROR type arguments are not allowed for this type [E0109] + + AliasFixed::SVariant::<()> { v: () }; + //~^ ERROR type arguments are not allowed for this type [E0109] + AliasFixed::<()>::SVariant { v: () }; + //~^ ERROR wrong number of type arguments: expected 0, found 1 [E0107] + AliasFixed::<()>::SVariant::<()> { v: () }; + //~^ ERROR type arguments are not allowed for this type [E0109] + //~^^ ERROR wrong number of type arguments: expected 0, found 1 [E0107] + + // Unit variant + + Enum::<()>::UVariant::<()>; + //~^ ERROR type arguments are not allowed for this type [E0109] + + Alias::UVariant::<()>; + //~^ ERROR type arguments are not allowed for this type [E0109] + Alias::<()>::UVariant::<()>; + //~^ ERROR type arguments are not allowed for this type [E0109] + + AliasFixed::UVariant::<()>; + //~^ ERROR type arguments are not allowed for this type [E0109] + AliasFixed::<()>::UVariant; + //~^ ERROR wrong number of type arguments: expected 0, found 1 [E0107] + AliasFixed::<()>::UVariant::<()>; + //~^ ERROR type arguments are not allowed for this type [E0109] + //~^^ ERROR wrong number of type arguments: expected 0, found 1 [E0107] +} diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr new file mode 100644 index 0000000000000..ee73622cb7bd1 --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr @@ -0,0 +1,256 @@ +error[E0308]: mismatched types + --> $DIR/enum-variant-generic-args.rs:13:25 + | +LL | Self::TSVariant(()); + | ^^ expected type parameter, found () + | + = note: expected type `T` + found type `()` + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:15:27 + | +LL | Self::TSVariant::<()>(()); + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:17:16 + | +LL | Self::<()>::TSVariant(()); + | ^^ type argument not allowed + +error[E0308]: mismatched types + --> $DIR/enum-variant-generic-args.rs:17:31 + | +LL | Self::<()>::TSVariant(()); + | ^^ expected type parameter, found () + | + = note: expected type `T` + found type `()` + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:20:16 + | +LL | Self::<()>::TSVariant::<()>(()); + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:20:33 + | +LL | Self::<()>::TSVariant::<()>(()); + | ^^ type argument not allowed + +error[E0308]: mismatched types + --> $DIR/enum-variant-generic-args.rs:26:29 + | +LL | Self::SVariant { v: () }; + | ^^ expected type parameter, found () + | + = note: expected type `T` + found type `()` + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:28:26 + | +LL | Self::SVariant::<()> { v: () }; + | ^^ type argument not allowed + +error[E0308]: mismatched types + --> $DIR/enum-variant-generic-args.rs:28:35 + | +LL | Self::SVariant::<()> { v: () }; + | ^^ expected type parameter, found () + | + = note: expected type `T` + found type `()` + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:31:16 + | +LL | Self::<()>::SVariant { v: () }; + | ^^ type argument not allowed + +error[E0308]: mismatched types + --> $DIR/enum-variant-generic-args.rs:31:35 + | +LL | Self::<()>::SVariant { v: () }; + | ^^ expected type parameter, found () + | + = note: expected type `T` + found type `()` + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:34:16 + | +LL | Self::<()>::SVariant::<()> { v: () }; + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:34:32 + | +LL | Self::<()>::SVariant::<()> { v: () }; + | ^^ type argument not allowed + +error[E0308]: mismatched types + --> $DIR/enum-variant-generic-args.rs:34:41 + | +LL | Self::<()>::SVariant::<()> { v: () }; + | ^^ expected type parameter, found () + | + = note: expected type `T` + found type `()` + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:41:26 + | +LL | Self::UVariant::<()>; + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:43:16 + | +LL | Self::<()>::UVariant; + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:45:16 + | +LL | Self::<()>::UVariant::<()>; + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:45:32 + | +LL | Self::<()>::UVariant::<()>; + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:54:29 + | +LL | Enum::<()>::TSVariant::<()>(()); + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:57:24 + | +LL | Alias::TSVariant::<()>(()); + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:59:30 + | +LL | Alias::<()>::TSVariant::<()>(()); + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:62:29 + | +LL | AliasFixed::TSVariant::<()>(()); + | ^^ type argument not allowed + +error[E0107]: wrong number of type arguments: expected 0, found 1 + --> $DIR/enum-variant-generic-args.rs:64:18 + | +LL | AliasFixed::<()>::TSVariant(()); + | ^^ unexpected type argument + +error[E0107]: wrong number of type arguments: expected 0, found 1 + --> $DIR/enum-variant-generic-args.rs:66:18 + | +LL | AliasFixed::<()>::TSVariant::<()>(()); + | ^^ unexpected type argument + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:66:35 + | +LL | AliasFixed::<()>::TSVariant::<()>(()); + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:72:28 + | +LL | Enum::<()>::SVariant::<()> { v: () }; + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:75:23 + | +LL | Alias::SVariant::<()> { v: () }; + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:77:29 + | +LL | Alias::<()>::SVariant::<()> { v: () }; + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:80:28 + | +LL | AliasFixed::SVariant::<()> { v: () }; + | ^^ type argument not allowed + +error[E0107]: wrong number of type arguments: expected 0, found 1 + --> $DIR/enum-variant-generic-args.rs:82:18 + | +LL | AliasFixed::<()>::SVariant { v: () }; + | ^^ unexpected type argument + +error[E0107]: wrong number of type arguments: expected 0, found 1 + --> $DIR/enum-variant-generic-args.rs:84:18 + | +LL | AliasFixed::<()>::SVariant::<()> { v: () }; + | ^^ unexpected type argument + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:84:34 + | +LL | AliasFixed::<()>::SVariant::<()> { v: () }; + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:90:28 + | +LL | Enum::<()>::UVariant::<()>; + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:93:23 + | +LL | Alias::UVariant::<()>; + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:95:29 + | +LL | Alias::<()>::UVariant::<()>; + | ^^ type argument not allowed + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:98:28 + | +LL | AliasFixed::UVariant::<()>; + | ^^ type argument not allowed + +error[E0107]: wrong number of type arguments: expected 0, found 1 + --> $DIR/enum-variant-generic-args.rs:100:18 + | +LL | AliasFixed::<()>::UVariant; + | ^^ unexpected type argument + +error[E0107]: wrong number of type arguments: expected 0, found 1 + --> $DIR/enum-variant-generic-args.rs:102:18 + | +LL | AliasFixed::<()>::UVariant::<()>; + | ^^ unexpected type argument + +error[E0109]: type arguments are not allowed for this type + --> $DIR/enum-variant-generic-args.rs:102:34 + | +LL | AliasFixed::<()>::UVariant::<()>; + | ^^ type argument not allowed + +error: aborting due to 39 previous errors + +Some errors have detailed explanations: E0107, E0109, E0308. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.rs b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.rs new file mode 100644 index 0000000000000..fa3e1a35fc27a --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.rs @@ -0,0 +1,23 @@ +// Check that an `enum` variant is resolved, in the value namespace, +// with higher priority than other inherent items when there is a conflict. + +enum E { + V(u8) +} + +impl E { + fn V() {} +} + +enum E2 { + V, +} + +impl E2 { + const V: u8 = 0; +} + +fn main() { + ::V(); //~ ERROR this function takes 1 parameter but 0 parameters were supplied + let _: u8 = ::V; //~ ERROR mismatched types +} diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr new file mode 100644 index 0000000000000..0394ddab46cda --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr @@ -0,0 +1,22 @@ +error[E0061]: this function takes 1 parameter but 0 parameters were supplied + --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:21:5 + | +LL | V(u8) + | ----- defined here +... +LL | ::V(); + | ^^^^^^^^ expected 1 parameter + +error[E0308]: mismatched types + --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:22:17 + | +LL | let _: u8 = ::V; + | ^^^^^^^ expected u8, found enum `E2` + | + = note: expected type `u8` + found type `E2` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0061, E0308. +For more information about an error, try `rustc --explain E0061`. diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.rs b/src/test/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.rs new file mode 100644 index 0000000000000..7f69590400b3c --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.rs @@ -0,0 +1,37 @@ +// Check that a projection `Self::V` in a trait implementation, +// with an associated type named `V`, for an `enum` with a variant named `V`, +// results in triggering the deny-by-default lint `ambiguous_associated_items`. +// The lint suggests that qualified syntax should be used instead. +// That is, the user would write `::V`. +// +// The rationale for this is that while `enum` variants do currently +// not exist in the type namespace but solely in the value namespace, +// RFC #2593 "Enum variant types", would add enum variants to the type namespace. +// However, currently `enum` variants are resolved with high priority as +// they are resolved as inherent associated items. +// Should #2953 therefore be implemented, `Self::V` would suddenly switch +// from referring to the associated type `V` instead of the variant `V`. +// The lint exists to keep us forward compatible with #2593. +// +// As a closing note, provided that #2933 was implemented and +// if `enum` variants were given lower priority than associated types, +// it would be impossible to refer to the `enum` variant `V` whereas +// the associated type could be referred to with qualified syntax as seen above. + +enum E { + V +} + +trait Tr { + type V; + fn f() -> Self::V; +} + +impl Tr for E { + type V = u8; + fn f() -> Self::V { 0 } + //~^ ERROR ambiguous associated item + //~| WARN this was previously accepted +} + +fn main() {} diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr new file mode 100644 index 0000000000000..f0dd689934f83 --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr @@ -0,0 +1,22 @@ +error: ambiguous associated item + --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:32:15 + | +LL | fn f() -> Self::V { 0 } + | ^^^^^^^ help: use fully-qualified syntax: `::V` + | + = note: #[deny(ambiguous_associated_items)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57644 +note: `V` could refer to variant defined here + --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:22:5 + | +LL | V + | ^ +note: `V` could also refer to associated type defined here + --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:26:5 + | +LL | type V; + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-Self-issue-58006.rs b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-Self-issue-58006.rs new file mode 100644 index 0000000000000..c1e56fc4caa9f --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-Self-issue-58006.rs @@ -0,0 +1,14 @@ +pub enum Enum { + A(usize), +} + +impl Enum { + fn foo(&self) -> () { + match self { + Self::A => (), + //~^ ERROR expected unit struct/variant or constant, found tuple variant + } + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-Self-issue-58006.stderr b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-Self-issue-58006.stderr new file mode 100644 index 0000000000000..128a85e15634c --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-Self-issue-58006.stderr @@ -0,0 +1,8 @@ +error[E0533]: expected unit struct/variant or constant, found tuple variant `::A` + --> $DIR/incorrect-variant-form-through-Self-issue-58006.rs:8:13 + | +LL | Self::A => (), + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.rs b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.rs new file mode 100644 index 0000000000000..ce45d59198af8 --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.rs @@ -0,0 +1,21 @@ +// ignore-tidy-linelength + +// Check that creating/matching on an enum variant through an alias with +// the wrong braced/unit form is caught as an error. + +enum Enum { Braced {}, Unit, Tuple() } +type Alias = Enum; + +fn main() { + Alias::Braced; + //~^ ERROR expected unit struct/variant or constant, found struct variant `::Braced` [E0533] + let Alias::Braced = panic!(); + //~^ ERROR expected unit struct/variant or constant, found struct variant `::Braced` [E0533] + let Alias::Braced(..) = panic!(); + //~^ ERROR expected tuple struct/variant, found struct variant `::Braced` [E0164] + + Alias::Unit(); + //~^ ERROR expected function, found enum variant `::Unit` + let Alias::Unit() = panic!(); + //~^ ERROR expected tuple struct/variant, found unit variant `::Unit` [E0164] +} diff --git a/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr new file mode 100644 index 0000000000000..c1ea816b7facf --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr @@ -0,0 +1,43 @@ +error[E0533]: expected unit struct/variant or constant, found struct variant `::Braced` + --> $DIR/incorrect-variant-form-through-alias-caught.rs:10:5 + | +LL | Alias::Braced; + | ^^^^^^^^^^^^^ + +error[E0533]: expected unit struct/variant or constant, found struct variant `::Braced` + --> $DIR/incorrect-variant-form-through-alias-caught.rs:12:9 + | +LL | let Alias::Braced = panic!(); + | ^^^^^^^^^^^^^ + +error[E0164]: expected tuple struct/variant, found struct variant `::Braced` + --> $DIR/incorrect-variant-form-through-alias-caught.rs:14:9 + | +LL | let Alias::Braced(..) = panic!(); + | ^^^^^^^^^^^^^^^^^ not a tuple variant or struct + +error[E0618]: expected function, found enum variant `::Unit` + --> $DIR/incorrect-variant-form-through-alias-caught.rs:17:5 + | +LL | enum Enum { Braced {}, Unit, Tuple() } + | ---- `::Unit` defined here +... +LL | Alias::Unit(); + | ^^^^^^^^^^^-- + | | + | call expression requires function +help: `::Unit` is a unit variant, you need to write it without the parenthesis + | +LL | ::Unit; + | ^^^^^^^^^^^^^ + +error[E0164]: expected tuple struct/variant, found unit variant `::Unit` + --> $DIR/incorrect-variant-form-through-alias-caught.rs:19:9 + | +LL | let Alias::Unit() = panic!(); + | ^^^^^^^^^^^^^ not a tuple variant or struct + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0164, E0618. +For more information about an error, try `rustc --explain E0164`. diff --git a/src/test/ui/issues/issue-57866.rs b/src/test/ui/type-alias-enum-variants/issue-57866.rs similarity index 88% rename from src/test/ui/issues/issue-57866.rs rename to src/test/ui/type-alias-enum-variants/issue-57866.rs index 77c50e53868e1..fa351ed51dd46 100644 --- a/src/test/ui/issues/issue-57866.rs +++ b/src/test/ui/type-alias-enum-variants/issue-57866.rs @@ -1,7 +1,5 @@ // compile-pass -#![feature(type_alias_enum_variants)] - enum Outer { A(T) } diff --git a/src/test/ui/type-alias-enum-variants/issue-61801-path-pattern-can-infer.rs b/src/test/ui/type-alias-enum-variants/issue-61801-path-pattern-can-infer.rs new file mode 100644 index 0000000000000..dfc618b164902 --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/issue-61801-path-pattern-can-infer.rs @@ -0,0 +1,28 @@ +// In this regression test we check that a path pattern referring to a unit variant +// through a type alias is successful in inferring the generic argument. + +// compile-pass + +enum Opt { + N, + S(T), +} + +type OptAlias = Opt; + +fn f1(x: OptAlias) { + match x { + OptAlias::N // We previously failed to infer `T` to `u8`. + => (), + _ => (), + } + + match x { + < + OptAlias<_> // And we failed to infer this type also. + >::N => (), + _ => (), + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-enum-variants/no-type-application-on-aliased-enum-variant.rs b/src/test/ui/type-alias-enum-variants/no-type-application-on-aliased-enum-variant.rs new file mode 100644 index 0000000000000..c1153fa4dc7b4 --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/no-type-application-on-aliased-enum-variant.rs @@ -0,0 +1,14 @@ +// Check that a generic type for an `enum` admits type application +// on both the type constructor and the generic type's variant. +// +// Also check that a type alias to said generic type admits type application +// on the type constructor but *NOT* the variant. + +type Alias = Option; + +fn main() { + let _ = Option::::None; // OK + let _ = Option::None::; // OK (Lint in future!) + let _ = Alias::::None; // OK + let _ = Alias::None::; //~ ERROR type arguments are not allowed for this type +} diff --git a/src/test/ui/type-alias-enum-variants/no-type-application-on-aliased-enum-variant.stderr b/src/test/ui/type-alias-enum-variants/no-type-application-on-aliased-enum-variant.stderr new file mode 100644 index 0000000000000..a1064d6925111 --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/no-type-application-on-aliased-enum-variant.stderr @@ -0,0 +1,9 @@ +error[E0109]: type arguments are not allowed for this type + --> $DIR/no-type-application-on-aliased-enum-variant.rs:13:27 + | +LL | let _ = Alias::None::; + | ^^ type argument not allowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0109`. diff --git a/src/test/ui/type-alias-enum-variants/resolve-to-enum-variant-in-type-namespace-and-error.rs b/src/test/ui/type-alias-enum-variants/resolve-to-enum-variant-in-type-namespace-and-error.rs new file mode 100644 index 0000000000000..11f4b05d0bf5d --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/resolve-to-enum-variant-in-type-namespace-and-error.rs @@ -0,0 +1,11 @@ +// Check that the compiler will resolve `::V` to the variant `V` in the type namespace +// but will reject this because `enum` variants do not exist in the type namespace. + +enum E { + V +} + +fn check() -> ::V {} +//~^ ERROR expected type, found variant `V` + +fn main() {} diff --git a/src/test/ui/type-alias-enum-variants/resolve-to-enum-variant-in-type-namespace-and-error.stderr b/src/test/ui/type-alias-enum-variants/resolve-to-enum-variant-in-type-namespace-and-error.stderr new file mode 100644 index 0000000000000..f190bfb69839e --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/resolve-to-enum-variant-in-type-namespace-and-error.stderr @@ -0,0 +1,8 @@ +error: expected type, found variant `V` + --> $DIR/resolve-to-enum-variant-in-type-namespace-and-error.rs:8:15 + | +LL | fn check() -> ::V {} + | ^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/type-alias-enum-variants/type-alias-enum-variants-pass.rs b/src/test/ui/type-alias-enum-variants/type-alias-enum-variants-pass.rs new file mode 100644 index 0000000000000..39677733d524d --- /dev/null +++ b/src/test/ui/type-alias-enum-variants/type-alias-enum-variants-pass.rs @@ -0,0 +1,69 @@ +// run-pass + +// Check that it is possible to resolve, in the value namespace, +// to an `enum` variant through a type alias. This includes `Self`. +// Type qualified syntax `::Variant` also works when syntactically valid. + +#[derive(Debug, PartialEq, Eq)] +enum Foo { + Bar(i32), + Baz { i: i32 }, + Qux, +} + +type FooAlias = Foo; +type OptionAlias = Option; + +macro_rules! check_pat { + ($x:expr, $p:pat) => { + assert!(if let $p = $x { true } else { false }); + }; +} + +impl Foo { + fn bar() -> Self { + let x = Self::Bar(3); + assert_eq!(x, ::Bar(3)); + check_pat!(x, Self::Bar(3)); + x + } + + fn baz() -> Self { + let x = Self::Baz { i: 42 }; + check_pat!(x, Self::Baz { i: 42 }); + x + } + + fn qux() -> Self { + let x = Self::Qux; + assert_eq!(x, ::Qux); + check_pat!(x, Self::Qux); + check_pat!(x, ::Qux); + x + } +} + +fn main() { + let bar = Foo::Bar(1); + assert_eq!(bar, FooAlias::Bar(1)); + assert_eq!(bar, ::Bar(1)); + check_pat!(bar, FooAlias::Bar(1)); + + let baz = FooAlias::Baz { i: 2 }; + assert_eq!(baz, Foo::Baz { i: 2 }); + check_pat!(baz, FooAlias::Baz { i: 2 }); + + let qux = Foo::Qux; + assert_eq!(qux, FooAlias::Qux); + assert_eq!(qux, ::Qux); + check_pat!(qux, FooAlias::Qux); + check_pat!(qux, ::Qux); + + assert_eq!(Foo::bar(), Foo::Bar(3)); + assert_eq!(Foo::baz(), Foo::Baz { i: 42 }); + assert_eq!(Foo::qux(), Foo::Qux); + + let some = Option::Some(4); + assert_eq!(some, OptionAlias::Some(4)); + check_pat!(some, OptionAlias::Some(4)); +} diff --git a/src/test/ui/type-alias/issue-62263-self-in-atb.rs b/src/test/ui/type-alias/issue-62263-self-in-atb.rs new file mode 100644 index 0000000000000..5e812db4d2362 --- /dev/null +++ b/src/test/ui/type-alias/issue-62263-self-in-atb.rs @@ -0,0 +1,8 @@ +pub trait Trait { + type A; +} + +pub type Alias = dyn Trait; +//~^ ERROR failed to resolve: use of undeclared type or module `Self` [E0433] + +fn main() {} diff --git a/src/test/ui/type-alias/issue-62263-self-in-atb.stderr b/src/test/ui/type-alias/issue-62263-self-in-atb.stderr new file mode 100644 index 0000000000000..a642d029f93b5 --- /dev/null +++ b/src/test/ui/type-alias/issue-62263-self-in-atb.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: use of undeclared type or module `Self` + --> $DIR/issue-62263-self-in-atb.rs:5:32 + | +LL | pub type Alias = dyn Trait; + | ^^^^ use of undeclared type or module `Self` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs b/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs new file mode 100644 index 0000000000000..0b95ddeb19e78 --- /dev/null +++ b/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs @@ -0,0 +1,4 @@ +type Alias = Self::Target; +//~^ ERROR failed to resolve: use of undeclared type or module `Self` [E0433] + +fn main() {} diff --git a/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr b/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr new file mode 100644 index 0000000000000..6eb445e9dbcfe --- /dev/null +++ b/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: use of undeclared type or module `Self` + --> $DIR/issue-62305-self-assoc-ty.rs:1:14 + | +LL | type Alias = Self::Target; + | ^^^^ use of undeclared type or module `Self` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/type-alias/issue-62364-self-ty-arg.rs b/src/test/ui/type-alias/issue-62364-self-ty-arg.rs new file mode 100644 index 0000000000000..bebb4a9021aab --- /dev/null +++ b/src/test/ui/type-alias/issue-62364-self-ty-arg.rs @@ -0,0 +1,8 @@ +struct Struct { + field: P1, +} + +type Alias<'a> = Struct<&'a Self>; +//~^ ERROR cannot find type `Self` in this scope [E0411] + +fn main() {} diff --git a/src/test/ui/type-alias/issue-62364-self-ty-arg.stderr b/src/test/ui/type-alias/issue-62364-self-ty-arg.stderr new file mode 100644 index 0000000000000..5ed27760a82dd --- /dev/null +++ b/src/test/ui/type-alias/issue-62364-self-ty-arg.stderr @@ -0,0 +1,9 @@ +error[E0411]: cannot find type `Self` in this scope + --> $DIR/issue-62364-self-ty-arg.rs:5:29 + | +LL | type Alias<'a> = Struct<&'a Self>; + | ^^^^ `Self` is only available in impls, traits, and type definitions + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0411`. diff --git a/src/test/ui/type/type-alias-bounds.rs b/src/test/ui/type/type-alias-bounds.rs index e2be2b9890251..f3cc5becc6f74 100644 --- a/src/test/ui/type/type-alias-bounds.rs +++ b/src/test/ui/type/type-alias-bounds.rs @@ -1,44 +1,44 @@ -// Test ignored_generic_bounds lint warning about bounds in type aliases +// Test `ignored_generic_bounds` lint warning about bounds in type aliases. // compile-pass #![allow(dead_code)] use std::rc::Rc; -type SVec = Vec; +type SVec = Vec; //~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds] type S2Vec where T: Send = Vec; //~^ WARN where clauses are not enforced in type aliases [type_alias_bounds] -type VVec<'b, 'a: 'b+'b> = (&'b u32, Vec<&'a i32>); +type VVec<'b, 'a: 'b + 'b> = (&'b u32, Vec<&'a i32>); //~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds] -type WVec<'b, T: 'b+'b> = (&'b u32, Vec); +type WVec<'b, T: 'b + 'b> = (&'b u32, Vec); //~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds] type W2Vec<'b, T> where T: 'b, T: 'b = (&'b u32, Vec); //~^ WARN where clauses are not enforced in type aliases [type_alias_bounds] -static STATIC : u32 = 0; +static STATIC: u32 = 0; fn foo<'a>(y: &'a i32) { // If any of the bounds above would matter, the code below would be rejected. // This can be seen when replacing the type aliases above by newtype structs. // (The type aliases have no unused parameters to make that a valid transformation.) - let mut x : SVec<_> = Vec::new(); + let mut x: SVec<_> = Vec::new(); x.push(Rc::new(42)); // is not send - let mut x : S2Vec<_> = Vec::new(); - x.push(Rc::new(42)); // is not send + let mut x: S2Vec<_> = Vec::new(); + x.push(Rc::new(42)); // is not `Send` - let mut x : VVec<'static, 'a> = (&STATIC, Vec::new()); - x.1.push(y); // 'a: 'static does not hold + let mut x: VVec<'static, 'a> = (&STATIC, Vec::new()); + x.1.push(y); // `'a: 'static` does not hold - let mut x : WVec<'static, &'a i32> = (&STATIC, Vec::new()); - x.1.push(y); // &'a i32: 'static does not hold + let mut x: WVec<'static, &'a i32> = (&STATIC, Vec::new()); + x.1.push(y); // `&'a i32: 'static` does not hold - let mut x : W2Vec<'static, &'a i32> = (&STATIC, Vec::new()); - x.1.push(y); // &'a i32: 'static does not hold + let mut x: W2Vec<'static, &'a i32> = (&STATIC, Vec::new()); + x.1.push(y); // `&'a i32: 'static` does not hold } -// Bounds are not checked either, i.e., the definition is not necessarily well-formed +// Bounds are not checked either; i.e., the definition is not necessarily well-formed. struct Sendable(T); type MySendable = Sendable; // no error here! @@ -47,9 +47,9 @@ trait Bound { type Assoc; } type T1 = U::Assoc; //~ WARN not enforced in type aliases type T2 where U: Bound = U::Assoc; //~ WARN not enforced in type aliases -// This errors -// type T3 = U::Assoc; -// Do this instead +// This errors: +// `type T3 = U::Assoc;` +// Do this instead: type T4 = ::Assoc; // Make sure the help about associatd types is not shown incorrectly diff --git a/src/test/ui/type/type-alias-bounds.stderr b/src/test/ui/type/type-alias-bounds.stderr index b13e400105210..177e5f893ed66 100644 --- a/src/test/ui/type/type-alias-bounds.stderr +++ b/src/test/ui/type/type-alias-bounds.stderr @@ -1,8 +1,8 @@ warning: bounds on generic parameters are not enforced in type aliases --> $DIR/type-alias-bounds.rs:8:14 | -LL | type SVec = Vec; - | ^^^^ ^^^^ +LL | type SVec = Vec; + | ^^^^ ^^^^ | = note: #[warn(type_alias_bounds)] on by default = help: the bound will not be checked when the type alias is used, and should be removed @@ -18,16 +18,16 @@ LL | type S2Vec where T: Send = Vec; warning: bounds on generic parameters are not enforced in type aliases --> $DIR/type-alias-bounds.rs:12:19 | -LL | type VVec<'b, 'a: 'b+'b> = (&'b u32, Vec<&'a i32>); - | ^^ ^^ +LL | type VVec<'b, 'a: 'b + 'b> = (&'b u32, Vec<&'a i32>); + | ^^ ^^ | = help: the bound will not be checked when the type alias is used, and should be removed warning: bounds on generic parameters are not enforced in type aliases --> $DIR/type-alias-bounds.rs:14:18 | -LL | type WVec<'b, T: 'b+'b> = (&'b u32, Vec); - | ^^ ^^ +LL | type WVec<'b, T: 'b + 'b> = (&'b u32, Vec); + | ^^ ^^ | = help: the bound will not be checked when the type alias is used, and should be removed @@ -42,33 +42,33 @@ LL | type W2Vec<'b, T> where T: 'b, T: 'b = (&'b u32, Vec); warning: bounds on generic parameters are not enforced in type aliases --> $DIR/type-alias-bounds.rs:47:12 | -LL | type T1 = U::Assoc; //~ WARN not enforced in type aliases +LL | type T1 = U::Assoc; | ^^^^^ | = help: the bound will not be checked when the type alias is used, and should be removed help: use fully disambiguated paths (i.e., `::Assoc`) to refer to associated types in type aliases --> $DIR/type-alias-bounds.rs:47:21 | -LL | type T1 = U::Assoc; //~ WARN not enforced in type aliases +LL | type T1 = U::Assoc; | ^^^^^^^^ warning: where clauses are not enforced in type aliases --> $DIR/type-alias-bounds.rs:48:18 | -LL | type T2 where U: Bound = U::Assoc; //~ WARN not enforced in type aliases +LL | type T2 where U: Bound = U::Assoc; | ^^^^^^^^ | = help: the clause will not be checked when the type alias is used, and should be removed help: use fully disambiguated paths (i.e., `::Assoc`) to refer to associated types in type aliases --> $DIR/type-alias-bounds.rs:48:29 | -LL | type T2 where U: Bound = U::Assoc; //~ WARN not enforced in type aliases +LL | type T2 where U: Bound = U::Assoc; | ^^^^^^^^ warning: bounds on generic parameters are not enforced in type aliases --> $DIR/type-alias-bounds.rs:56:12 | -LL | type T5 = ::Assoc; //~ WARN not enforced in type aliases +LL | type T5 = ::Assoc; | ^^^^^ | = help: the bound will not be checked when the type alias is used, and should be removed @@ -76,7 +76,7 @@ LL | type T5 = ::Assoc; //~ WARN not enforced in type ali warning: bounds on generic parameters are not enforced in type aliases --> $DIR/type-alias-bounds.rs:57:12 | -LL | type T6 = ::std::vec::Vec; //~ WARN not enforced in type aliases +LL | type T6 = ::std::vec::Vec; | ^^^^^ | = help: the bound will not be checked when the type alias is used, and should be removed diff --git a/src/test/ui/type/type-arg-out-of-scope.rs b/src/test/ui/type/type-arg-out-of-scope.rs index d5b815f6a95e9..02aad00770793 100644 --- a/src/test/ui/type/type-arg-out-of-scope.rs +++ b/src/test/ui/type/type-arg-out-of-scope.rs @@ -1,5 +1,5 @@ // error-pattern:can't use generic parameters from outer function fn foo(x: T) { - fn bar(f: Box T>) { } + fn bar(f: Box T>) { } } fn main() { foo(1); } diff --git a/src/test/ui/type/type-arg-out-of-scope.stderr b/src/test/ui/type/type-arg-out-of-scope.stderr index 645cbb33abec1..0b6283fbc51e9 100644 --- a/src/test/ui/type/type-arg-out-of-scope.stderr +++ b/src/test/ui/type/type-arg-out-of-scope.stderr @@ -1,20 +1,20 @@ error[E0401]: can't use generic parameters from outer function - --> $DIR/type-arg-out-of-scope.rs:3:25 + --> $DIR/type-arg-out-of-scope.rs:3:29 | LL | fn foo(x: T) { - | - type variable from outer function -LL | fn bar(f: Box T>) { } - | --- ^ use of generic parameter from outer function + | - type parameter from outer function +LL | fn bar(f: Box T>) { } + | --- ^ use of generic parameter from outer function | | | help: try using a local generic parameter instead: `bar` error[E0401]: can't use generic parameters from outer function - --> $DIR/type-arg-out-of-scope.rs:3:31 + --> $DIR/type-arg-out-of-scope.rs:3:35 | LL | fn foo(x: T) { - | - type variable from outer function -LL | fn bar(f: Box T>) { } - | --- ^ use of generic parameter from outer function + | - type parameter from outer function +LL | fn bar(f: Box T>) { } + | --- ^ use of generic parameter from outer function | | | help: try using a local generic parameter instead: `bar` diff --git a/src/test/ui/type/type-ascription-instead-of-initializer.stderr b/src/test/ui/type/type-ascription-instead-of-initializer.stderr index 8ce367d70f014..a22d25697d8bd 100644 --- a/src/test/ui/type/type-ascription-instead-of-initializer.stderr +++ b/src/test/ui/type/type-ascription-instead-of-initializer.stderr @@ -1,7 +1,7 @@ error: expected type, found `10` --> $DIR/type-ascription-instead-of-initializer.rs:2:31 | -LL | let x: Vec::with_capacity(10, 20); //~ ERROR expected type, found `10` +LL | let x: Vec::with_capacity(10, 20); | -- ^^ | || | |help: use `=` if you meant to assign @@ -10,7 +10,7 @@ LL | let x: Vec::with_capacity(10, 20); //~ ERROR expected type, found `10` error[E0061]: this function takes 1 parameter but 2 parameters were supplied --> $DIR/type-ascription-instead-of-initializer.rs:2:12 | -LL | let x: Vec::with_capacity(10, 20); //~ ERROR expected type, found `10` +LL | let x: Vec::with_capacity(10, 20); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 parameter error: aborting due to 2 previous errors diff --git a/src/test/ui/type/type-ascription-instead-of-statement-end.stderr b/src/test/ui/type/type-ascription-instead-of-statement-end.stderr index db99d1ec07be3..4929922c83fe6 100644 --- a/src/test/ui/type/type-ascription-instead-of-statement-end.stderr +++ b/src/test/ui/type/type-ascription-instead-of-statement-end.stderr @@ -3,14 +3,22 @@ error: expected type, found `0` | LL | println!("test"): | - help: try using a semicolon: `;` -LL | 0; //~ ERROR expected type, found `0` +LL | 0; | ^ expecting a type here because of type ascription error: expected type, found `0` --> $DIR/type-ascription-instead-of-statement-end.rs:9:23 | -LL | println!("test"): 0; //~ ERROR expected type, found `0` +LL | println!("test"): 0; | ^ expecting a type here because of type ascription + | + = note: #![feature(type_ascription)] lets you annotate an expression with a type: `: ` +note: this expression expects an ascribed type after the colon + --> $DIR/type-ascription-instead-of-statement-end.rs:9:5 + | +LL | println!("test"): 0; + | ^^^^^^^^^^^^^^^^ + = help: this might be indicative of a syntax error elsewhere error: aborting due to 2 previous errors diff --git a/src/test/ui/type/type-ascription-precedence.stderr b/src/test/ui/type/type-ascription-precedence.stderr index e52e2bc5e9a78..aecb0f8738785 100644 --- a/src/test/ui/type/type-ascription-precedence.stderr +++ b/src/test/ui/type/type-ascription-precedence.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/type-ascription-precedence.rs:31:7 | -LL | &(S: &S); //~ ERROR mismatched types +LL | &(S: &S); | ^ expected &S, found struct `S` | = note: expected type `&S` @@ -10,7 +10,7 @@ LL | &(S: &S); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-ascription-precedence.rs:35:7 | -LL | *(S: Z); //~ ERROR mismatched types +LL | *(S: Z); | ^ expected struct `Z`, found struct `S` | = note: expected type `Z` @@ -19,13 +19,13 @@ LL | *(S: Z); //~ ERROR mismatched types error[E0614]: type `Z` cannot be dereferenced --> $DIR/type-ascription-precedence.rs:35:5 | -LL | *(S: Z); //~ ERROR mismatched types +LL | *(S: Z); | ^^^^^^^ error[E0308]: mismatched types --> $DIR/type-ascription-precedence.rs:40:7 | -LL | -(S: Z); //~ ERROR mismatched types +LL | -(S: Z); | ^ expected struct `Z`, found struct `S` | = note: expected type `Z` @@ -34,7 +34,7 @@ LL | -(S: Z); //~ ERROR mismatched types error[E0600]: cannot apply unary operator `-` to type `Z` --> $DIR/type-ascription-precedence.rs:40:5 | -LL | -(S: Z); //~ ERROR mismatched types +LL | -(S: Z); | ^^^^^^^ cannot apply unary operator `-` | = note: an implementation of `std::ops::Neg` might be missing for `Z` @@ -42,7 +42,7 @@ LL | -(S: Z); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-ascription-precedence.rs:45:5 | -LL | (S + Z): Z; //~ ERROR mismatched types +LL | (S + Z): Z; | ^^^^^^^ expected struct `Z`, found struct `S` | = note: expected type `Z` @@ -51,7 +51,7 @@ LL | (S + Z): Z; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-ascription-precedence.rs:49:5 | -LL | (S * Z): Z; //~ ERROR mismatched types +LL | (S * Z): Z; | ^^^^^^^ expected struct `Z`, found struct `S` | = note: expected type `Z` @@ -60,7 +60,7 @@ LL | (S * Z): Z; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-ascription-precedence.rs:53:5 | -LL | (S .. S): S; //~ ERROR mismatched types +LL | (S .. S): S; | ^^^^^^^^ expected struct `S`, found struct `std::ops::Range` | = note: expected type `S` @@ -68,5 +68,5 @@ LL | (S .. S): S; //~ ERROR mismatched types error: aborting due to 8 previous errors -Some errors occurred: E0308, E0600, E0614. +Some errors have detailed explanations: E0308, E0600, E0614. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/type/type-ascription-soundness.stderr b/src/test/ui/type/type-ascription-soundness.stderr index f681a0423024d..150e19020fea4 100644 --- a/src/test/ui/type/type-ascription-soundness.stderr +++ b/src/test/ui/type/type-ascription-soundness.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/type-ascription-soundness.rs:7:17 | -LL | let ref x = arr: &[u8]; //~ ERROR mismatched types +LL | let ref x = arr: &[u8]; | ^^^ expected slice, found array of 3 elements | = note: expected type `&[u8]` @@ -10,7 +10,7 @@ LL | let ref x = arr: &[u8]; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-ascription-soundness.rs:8:21 | -LL | let ref mut x = arr: &[u8]; //~ ERROR mismatched types +LL | let ref mut x = arr: &[u8]; | ^^^ expected slice, found array of 3 elements | = note: expected type `&[u8]` @@ -19,7 +19,7 @@ LL | let ref mut x = arr: &[u8]; //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-ascription-soundness.rs:9:11 | -LL | match arr: &[u8] { //~ ERROR mismatched types +LL | match arr: &[u8] { | ^^^ expected slice, found array of 3 elements | = note: expected type `&[u8]` @@ -28,7 +28,7 @@ LL | match arr: &[u8] { //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-ascription-soundness.rs:12:17 | -LL | let _len = (arr: &[u8]).len(); //~ ERROR mismatched types +LL | let _len = (arr: &[u8]).len(); | ^^^ expected slice, found array of 3 elements | = note: expected type `&[u8]` diff --git a/src/test/ui/type/type-ascription-with-fn-call.stderr b/src/test/ui/type/type-ascription-with-fn-call.stderr index a290e69e0cb6f..624c817e33e32 100644 --- a/src/test/ui/type/type-ascription-with-fn-call.stderr +++ b/src/test/ui/type/type-ascription-with-fn-call.stderr @@ -3,7 +3,7 @@ error[E0573]: expected type, found function `f` | LL | f() : | - help: did you mean to use `;` here instead? -LL | f(); //~ ERROR expected type, found function +LL | f(); | ^^^ | | | not a type @@ -11,4 +11,3 @@ LL | f(); //~ ERROR expected type, found function error: aborting due to previous error -For more information about this error, try `rustc --explain E0573`. diff --git a/src/test/ui/type/type-check/assignment-expected-bool.rs b/src/test/ui/type/type-check/assignment-expected-bool.rs new file mode 100644 index 0000000000000..03830fea062cf --- /dev/null +++ b/src/test/ui/type/type-check/assignment-expected-bool.rs @@ -0,0 +1,34 @@ +// The purpose of this text is to ensure that we get good +// diagnostics when a `bool` is expected but that due to +// an assignment expression `x = y` the type is `()`. + +fn main() { + let _: bool = 0 = 0; //~ ERROR mismatched types [E0308] + + let _: bool = match 0 { + 0 => 0 = 0, //~ ERROR mismatched types [E0308] + _ => 0 = 0, //~ ERROR mismatched types [E0308] + }; + + let _: bool = match true { + true => 0 = 0, //~ ERROR mismatched types [E0308] + _ => (), + }; + + if 0 = 0 {} //~ ERROR mismatched types [E0308] + + let _: bool = if { 0 = 0 } { //~ ERROR mismatched types [E0308] + 0 = 0 //~ ERROR mismatched types [E0308] + } else { + 0 = 0 //~ ERROR mismatched types [E0308] + }; + + let _ = (0 = 0) //~ ERROR mismatched types [E0308] + && { 0 = 0 } //~ ERROR mismatched types [E0308] + || (0 = 0); //~ ERROR mismatched types [E0308] + + // A test to check that not expecting `bool` behaves well: + let _: usize = 0 = 0; + //~^ ERROR mismatched types [E0308] + //~| ERROR invalid left-hand side expression [E0070] +} diff --git a/src/test/ui/type/type-check/assignment-expected-bool.stderr b/src/test/ui/type/type-check/assignment-expected-bool.stderr new file mode 100644 index 0000000000000..b636a71f3afe2 --- /dev/null +++ b/src/test/ui/type/type-check/assignment-expected-bool.stderr @@ -0,0 +1,151 @@ +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:6:19 + | +LL | let _: bool = 0 = 0; + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:9:14 + | +LL | 0 => 0 = 0, + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:10:14 + | +LL | _ => 0 = 0, + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:14:17 + | +LL | true => 0 = 0, + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:18:8 + | +LL | if 0 = 0 {} + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:20:24 + | +LL | let _: bool = if { 0 = 0 } { + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:21:9 + | +LL | 0 = 0 + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:23:9 + | +LL | 0 = 0 + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:26:13 + | +LL | let _ = (0 = 0) + | ^^^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:27:14 + | +LL | && { 0 = 0 } + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:28:12 + | +LL | || (0 = 0); + | ^^^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `0 == 0` + | + = note: expected type `bool` + found type `()` + +error[E0070]: invalid left-hand side expression + --> $DIR/assignment-expected-bool.rs:31:20 + | +LL | let _: usize = 0 = 0; + | ^^^^^ left-hand of expression not valid + +error[E0308]: mismatched types + --> $DIR/assignment-expected-bool.rs:31:20 + | +LL | let _: usize = 0 = 0; + | ^^^^^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error: aborting due to 13 previous errors + +Some errors have detailed explanations: E0070, E0308. +For more information about an error, try `rustc --explain E0070`. diff --git a/src/test/ui/type/type-check/assignment-in-if.rs b/src/test/ui/type/type-check/assignment-in-if.rs index 232b0a00b307d..77b122b0a794a 100644 --- a/src/test/ui/type/type-check/assignment-in-if.rs +++ b/src/test/ui/type/type-check/assignment-in-if.rs @@ -31,8 +31,13 @@ fn main() { //~^ ERROR mismatched types println!("{}", x); } - if (if true { x = 4 } else { x = 5 }) { - //~^ ERROR mismatched types + if ( + if true { + x = 4 //~ ERROR mismatched types + } else { + x = 5 //~ ERROR mismatched types + } + ) { println!("{}", x); } } diff --git a/src/test/ui/type/type-check/assignment-in-if.stderr b/src/test/ui/type/type-check/assignment-in-if.stderr index 403f7b4f7ae89..87b8d17c21bcc 100644 --- a/src/test/ui/type/type-check/assignment-in-if.stderr +++ b/src/test/ui/type/type-check/assignment-in-if.stderr @@ -47,14 +47,29 @@ LL | if 3 = x { found type `()` error[E0308]: mismatched types - --> $DIR/assignment-in-if.rs:34:8 + --> $DIR/assignment-in-if.rs:36:13 | -LL | if (if true { x = 4 } else { x = 5 }) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found () +LL | x = 4 + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `x == 4` | = note: expected type `bool` found type `()` -error: aborting due to 5 previous errors +error[E0308]: mismatched types + --> $DIR/assignment-in-if.rs:38:13 + | +LL | x = 5 + | ^^^^^ + | | + | expected bool, found () + | help: try comparing for equality: `x == 5` + | + = note: expected type `bool` + found type `()` + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr index a2df3dcd8e708..8edec6e0ea3fd 100644 --- a/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr +++ b/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `[_; 0]` --> $DIR/cannot_infer_local_or_array.rs:2:13 | -LL | let x = []; //~ ERROR type annotations needed +LL | let x = []; | - ^^ cannot infer type | | - | consider giving `x` a type + | consider giving `x` the explicit type `[_; 0]`, with the type parameters specified error: aborting due to previous error diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr index 8215947d49cdd..6524bf5dd2bc5 100644 --- a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr +++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `std::vec::Vec` --> $DIR/cannot_infer_local_or_vec.rs:2:13 | LL | let x = vec![]; | - ^^^^^^ cannot infer type for `T` | | - | consider giving `x` a type + | consider giving `x` the explicit type `std::vec::Vec`, where the type parameter `T` is specified | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr index 1065d49c26b2d..6d1ef240da60c 100644 --- a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr +++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `(std::vec::Vec,)` --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18 | LL | let (x, ) = (vec![], ); | ----- ^^^^^^ cannot infer type for `T` | | - | consider giving the pattern a type + | consider giving this pattern the explicit type `(std::vec::Vec,)`, where the type parameter `T` is specified | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/type/type-check/issue-22897.stderr b/src/test/ui/type/type-check/issue-22897.stderr index a4f1c4d5d4df2..2b3f0696f3c22 100644 --- a/src/test/ui/type/type-check/issue-22897.stderr +++ b/src/test/ui/type/type-check/issue-22897.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed --> $DIR/issue-22897.rs:4:5 | -LL | []; //~ ERROR type annotations needed +LL | []; | ^^ cannot infer type for `[_; 0]` error: aborting due to previous error diff --git a/src/test/ui/type/type-check/issue-40294.stderr b/src/test/ui/type/type-check/issue-40294.stderr index d63abdbeb5d4c..254875fcaab3a 100644 --- a/src/test/ui/type/type-check/issue-40294.stderr +++ b/src/test/ui/type/type-check/issue-40294.stderr @@ -1,7 +1,7 @@ error[E0283]: type annotations required: cannot resolve `&'a T: Foo` --> $DIR/issue-40294.rs:5:1 | -LL | / fn foo<'a,'b,T>(x: &'a T, y: &'b T) //~ ERROR type annotations required +LL | / fn foo<'a,'b,T>(x: &'a T, y: &'b T) LL | | where &'a T : Foo, LL | | &'b T : Foo LL | | { diff --git a/src/test/ui/type/type-check/issue-41314.stderr b/src/test/ui/type/type-check/issue-41314.stderr index a4ae2a97134e7..c2bba98d10a83 100644 --- a/src/test/ui/type/type-check/issue-41314.stderr +++ b/src/test/ui/type/type-check/issue-41314.stderr @@ -1,18 +1,18 @@ error[E0026]: variant `X::Y` does not have a field named `number` --> $DIR/issue-41314.rs:7:16 | -LL | X::Y { number } => {} //~ ERROR does not have a field named `number` +LL | X::Y { number } => {} | ^^^^^^ variant `X::Y` does not have this field error[E0027]: pattern does not mention field `0` --> $DIR/issue-41314.rs:7:9 | -LL | X::Y { number } => {} //~ ERROR does not have a field named `number` +LL | X::Y { number } => {} | ^^^^^^^^^^^^^^^ missing field `0` | = note: trying to match a tuple variant with a struct variant pattern error: aborting due to 2 previous errors -Some errors occurred: E0026, E0027. +Some errors have detailed explanations: E0026, E0027. For more information about an error, try `rustc --explain E0026`. diff --git a/src/test/ui/type/type-check/missing_trait_impl.stderr b/src/test/ui/type/type-check/missing_trait_impl.stderr index 9f59e7162e072..2a158ab8564f3 100644 --- a/src/test/ui/type/type-check/missing_trait_impl.stderr +++ b/src/test/ui/type/type-check/missing_trait_impl.stderr @@ -1,15 +1,17 @@ error[E0369]: binary operation `+` cannot be applied to type `T` - --> $DIR/missing_trait_impl.rs:5:13 + --> $DIR/missing_trait_impl.rs:5:15 | -LL | let z = x + y; //~ ERROR binary operation `+` cannot be applied to type `T` - | ^^^^^ +LL | let z = x + y; + | - ^ - T + | | + | T | = note: `T` might need a bound for `std::ops::Add` error[E0368]: binary assignment operation `+=` cannot be applied to type `T` --> $DIR/missing_trait_impl.rs:9:5 | -LL | x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T` +LL | x += x; | -^^^^^ | | | cannot use `+=` on type `T` @@ -18,5 +20,5 @@ LL | x += x; //~ ERROR binary assignment operation `+=` cannot be applied to error: aborting due to 2 previous errors -Some errors occurred: E0368, E0369. +Some errors have detailed explanations: E0368, E0369. For more information about an error, try `rustc --explain E0368`. diff --git a/src/test/ui/type/type-check/unknown_type_for_closure.stderr b/src/test/ui/type/type-check/unknown_type_for_closure.stderr index 45142b556ecd9..5971f56c97f7d 100644 --- a/src/test/ui/type/type-check/unknown_type_for_closure.stderr +++ b/src/test/ui/type/type-check/unknown_type_for_closure.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed --> $DIR/unknown_type_for_closure.rs:2:14 | -LL | let x = |_| { }; //~ ERROR type annotations needed +LL | let x = |_| { }; | ^ consider giving this closure parameter a type error: aborting due to previous error diff --git a/src/test/ui/type/type-dependent-def-issue-49241.rs b/src/test/ui/type/type-dependent-def-issue-49241.rs index 51bd116fbd61c..5ad50ffcbc389 100644 --- a/src/test/ui/type/type-dependent-def-issue-49241.rs +++ b/src/test/ui/type/type-dependent-def-issue-49241.rs @@ -3,4 +3,5 @@ fn main() { const l: usize = v.count(); //~ ERROR attempt to use a non-constant value in a constant let s: [u32; l] = v.into_iter().collect(); //~^ ERROR evaluation of constant value failed + //~^^ ERROR a collection of type } diff --git a/src/test/ui/type/type-dependent-def-issue-49241.stderr b/src/test/ui/type/type-dependent-def-issue-49241.stderr index 0af777fdcf907..851004d105897 100644 --- a/src/test/ui/type/type-dependent-def-issue-49241.stderr +++ b/src/test/ui/type/type-dependent-def-issue-49241.stderr @@ -1,7 +1,7 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-dependent-def-issue-49241.rs:3:22 | -LL | const l: usize = v.count(); //~ ERROR attempt to use a non-constant value in a constant +LL | const l: usize = v.count(); | ^ non-constant value error[E0080]: evaluation of constant value failed @@ -10,7 +10,15 @@ error[E0080]: evaluation of constant value failed LL | let s: [u32; l] = v.into_iter().collect(); | ^ referenced constant has errors -error: aborting due to 2 previous errors +error[E0277]: a collection of type `[u32; _]` cannot be built from an iterator over elements of type `{integer}` + --> $DIR/type-dependent-def-issue-49241.rs:4:37 + | +LL | let s: [u32; l] = v.into_iter().collect(); + | ^^^^^^^ a collection of type `[u32; _]` cannot be built from `std::iter::Iterator` + | + = help: the trait `std::iter::FromIterator<{integer}>` is not implemented for `[u32; _]` + +error: aborting due to 3 previous errors -Some errors occurred: E0080, E0435. +Some errors have detailed explanations: E0080, E0277, E0435. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/type/type-mismatch-multiple.rs b/src/test/ui/type/type-mismatch-multiple.rs index 1904ccf5d5945..b8f04ca8d4a33 100644 --- a/src/test/ui/type/type-mismatch-multiple.rs +++ b/src/test/ui/type/type-mismatch-multiple.rs @@ -7,4 +7,3 @@ fn main() { let a: bool = 1; let b: i32 = true; } //~| expected bool, found integer //~| ERROR mismatched types //~| expected i32, found bool - diff --git a/src/test/ui/type/type-mismatch.stderr b/src/test/ui/type/type-mismatch.stderr index 0b239e91eb804..7aea9db6167a3 100644 --- a/src/test/ui/type/type-mismatch.stderr +++ b/src/test/ui/type/type-mismatch.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/type-mismatch.rs:17:17 | -LL | want::(f); //~ ERROR mismatched types +LL | want::(f); | ^ expected struct `foo`, found usize | = note: expected type `foo` @@ -10,7 +10,7 @@ LL | want::(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:18:17 | -LL | want::(f); //~ ERROR mismatched types +LL | want::(f); | ^ expected struct `bar`, found usize | = note: expected type `bar` @@ -19,7 +19,7 @@ LL | want::(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:19:24 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `Foo`, found usize | = note: expected type `Foo` @@ -28,7 +28,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:20:27 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `Foo`, found usize | = note: expected type `Foo` @@ -37,7 +37,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:21:22 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `Foo`, found usize | = note: expected type `Foo` @@ -46,7 +46,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:22:25 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `Foo`, found usize | = note: expected type `Foo` @@ -55,7 +55,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:23:22 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `Foo`, found usize | = note: expected type `Foo` @@ -64,7 +64,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:24:25 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `Foo`, found usize | = note: expected type `Foo` @@ -73,7 +73,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:28:19 | -LL | want::(f); //~ ERROR mismatched types +LL | want::(f); | ^ expected usize, found struct `foo` | = note: expected type `usize` @@ -82,7 +82,7 @@ LL | want::(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:29:17 | -LL | want::(f); //~ ERROR mismatched types +LL | want::(f); | ^ expected struct `bar`, found struct `foo` | = note: expected type `bar` @@ -91,7 +91,7 @@ LL | want::(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:30:24 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `Foo`, found struct `foo` | = note: expected type `Foo` @@ -100,7 +100,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:31:27 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `Foo`, found struct `foo` | = note: expected type `Foo` @@ -109,7 +109,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:32:22 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `Foo`, found struct `foo` | = note: expected type `Foo` @@ -118,7 +118,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:33:25 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `Foo`, found struct `foo` | = note: expected type `Foo` @@ -127,7 +127,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:34:22 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `Foo`, found struct `foo` | = note: expected type `Foo` @@ -136,7 +136,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:35:25 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `Foo`, found struct `foo` | = note: expected type `Foo` @@ -145,7 +145,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:39:19 | -LL | want::(f); //~ ERROR mismatched types +LL | want::(f); | ^ expected usize, found struct `Foo` | = note: expected type `usize` @@ -154,7 +154,7 @@ LL | want::(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:40:17 | -LL | want::(f); //~ ERROR mismatched types +LL | want::(f); | ^ expected struct `foo`, found struct `Foo` | = note: expected type `foo` @@ -163,7 +163,7 @@ LL | want::(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:41:17 | -LL | want::(f); //~ ERROR mismatched types +LL | want::(f); | ^ expected struct `bar`, found struct `Foo` | = note: expected type `bar` @@ -172,7 +172,7 @@ LL | want::(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:42:24 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected usize, found struct `foo` | = note: expected type `Foo` @@ -181,7 +181,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:43:27 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected usize, found struct `foo` | = note: expected type `Foo` @@ -190,7 +190,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:44:25 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `B`, found struct `A` | = note: expected type `Foo<_, B>` @@ -199,7 +199,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:45:22 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `bar`, found struct `foo` | = note: expected type `Foo` @@ -208,7 +208,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:46:25 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `bar`, found struct `foo` | = note: expected type `Foo` @@ -217,7 +217,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:47:23 | -LL | want::<&Foo>(f); //~ ERROR mismatched types +LL | want::<&Foo>(f); | ^ | | | expected &Foo, found struct `Foo` @@ -229,7 +229,7 @@ LL | want::<&Foo>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:48:26 | -LL | want::<&Foo>(f); //~ ERROR mismatched types +LL | want::<&Foo>(f); | ^ expected reference, found struct `Foo` | = note: expected type `&Foo` @@ -238,7 +238,7 @@ LL | want::<&Foo>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:52:19 | -LL | want::(f); //~ ERROR mismatched types +LL | want::(f); | ^ expected usize, found struct `Foo` | = note: expected type `usize` @@ -247,7 +247,7 @@ LL | want::(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:53:17 | -LL | want::(f); //~ ERROR mismatched types +LL | want::(f); | ^ expected struct `foo`, found struct `Foo` | = note: expected type `foo` @@ -256,7 +256,7 @@ LL | want::(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:54:17 | -LL | want::(f); //~ ERROR mismatched types +LL | want::(f); | ^ expected struct `bar`, found struct `Foo` | = note: expected type `bar` @@ -265,7 +265,7 @@ LL | want::(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:55:24 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected usize, found struct `foo` | = note: expected type `Foo` @@ -274,7 +274,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:56:27 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected usize, found struct `foo` | = note: expected type `Foo` @@ -283,7 +283,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:57:22 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `A`, found struct `B` | = note: expected type `Foo<_, A>` @@ -292,7 +292,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:58:22 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `bar`, found struct `foo` | = note: expected type `Foo` @@ -301,7 +301,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:59:25 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `bar`, found struct `foo` | = note: expected type `Foo` @@ -310,7 +310,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:60:23 | -LL | want::<&Foo>(f); //~ ERROR mismatched types +LL | want::<&Foo>(f); | ^ expected &Foo, found struct `Foo` | = note: expected type `&Foo` @@ -319,7 +319,7 @@ LL | want::<&Foo>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:61:26 | -LL | want::<&Foo>(f); //~ ERROR mismatched types +LL | want::<&Foo>(f); | ^ | | | expected reference, found struct `Foo` @@ -331,7 +331,7 @@ LL | want::<&Foo>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:65:19 | -LL | want::(f); //~ ERROR mismatched types +LL | want::(f); | ^ expected usize, found struct `Foo` | = note: expected type `usize` @@ -340,7 +340,7 @@ LL | want::(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:66:17 | -LL | want::(f); //~ ERROR mismatched types +LL | want::(f); | ^ expected struct `foo`, found struct `Foo` | = note: expected type `foo` @@ -349,7 +349,7 @@ LL | want::(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:67:17 | -LL | want::(f); //~ ERROR mismatched types +LL | want::(f); | ^ expected struct `bar`, found struct `Foo` | = note: expected type `bar` @@ -358,7 +358,7 @@ LL | want::(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:68:24 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected usize, found struct `foo` | = note: expected type `Foo` @@ -367,7 +367,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:69:27 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected usize, found struct `foo` | = note: expected type `Foo` @@ -376,7 +376,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:70:22 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `A`, found struct `B` | = note: expected type `Foo<_, A, B>` @@ -385,7 +385,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:71:25 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `B`, found struct `A` | = note: expected type `Foo<_, _, B>` @@ -394,7 +394,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:72:22 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `bar`, found struct `foo` | = note: expected type `Foo` @@ -403,7 +403,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:73:25 | -LL | want::>(f); //~ ERROR mismatched types +LL | want::>(f); | ^ expected struct `bar`, found struct `foo` | = note: expected type `Foo` @@ -412,7 +412,7 @@ LL | want::>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:74:23 | -LL | want::<&Foo>(f); //~ ERROR mismatched types +LL | want::<&Foo>(f); | ^ expected &Foo, found struct `Foo` | = note: expected type `&Foo` @@ -421,7 +421,7 @@ LL | want::<&Foo>(f); //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/type-mismatch.rs:75:26 | -LL | want::<&Foo>(f); //~ ERROR mismatched types +LL | want::<&Foo>(f); | ^ expected reference, found struct `Foo` | = note: expected type `&Foo` diff --git a/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.rs b/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.rs index 3e1c876c76ba8..444453dc69437 100644 --- a/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.rs +++ b/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.rs @@ -11,7 +11,7 @@ impl MyAdd for i32 { fn main() { let x: i32 = 5; - let y = x as MyAdd; + let y = x as dyn MyAdd; //~^ ERROR E0038 //~| ERROR cast to unsized type: `i32` as `dyn MyAdd` } diff --git a/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr b/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr index 7306929d712ab..58727ea0fef99 100644 --- a/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr +++ b/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr @@ -1,24 +1,24 @@ error[E0620]: cast to unsized type: `i32` as `dyn MyAdd` --> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:14:13 | -LL | let y = x as MyAdd; - | ^^^^^^^^^^^^^^^ +LL | let y = x as dyn MyAdd; + | ^^^^^^^^^^^^^^^^^^^ | help: consider using a box or reference as appropriate --> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:14:13 | -LL | let y = x as MyAdd; +LL | let y = x as dyn MyAdd; | ^ error[E0038]: the trait `MyAdd` cannot be made into an object --> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:14:18 | -LL | let y = x as MyAdd; - | ^^^^^^^^^^ the trait `MyAdd` cannot be made into an object +LL | let y = x as dyn MyAdd; + | ^^^^^^^^^^^^^^ the trait `MyAdd` cannot be made into an object | = note: method `add` references the `Self` type in its arguments or return type error: aborting due to 2 previous errors -Some errors occurred: E0038, E0620. +Some errors have detailed explanations: E0038, E0620. For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/type/type-parameter-defaults-referencing-Self.rs b/src/test/ui/type/type-parameter-defaults-referencing-Self.rs index 721bf960a55c2..a4c59dced029a 100644 --- a/src/test/ui/type/type-parameter-defaults-referencing-Self.rs +++ b/src/test/ui/type/type-parameter-defaults-referencing-Self.rs @@ -7,7 +7,7 @@ trait Foo { fn method(&self); } -fn foo(x: &Foo) { } +fn foo(x: &dyn Foo) { } //~^ ERROR the type parameter `T` must be explicitly specified fn main() { } diff --git a/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr b/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr index 70093b61f251b..0d6ca9d9dcd9f 100644 --- a/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr +++ b/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr @@ -1,8 +1,8 @@ error[E0393]: the type parameter `T` must be explicitly specified - --> $DIR/type-parameter-defaults-referencing-Self.rs:10:12 + --> $DIR/type-parameter-defaults-referencing-Self.rs:10:16 | -LL | fn foo(x: &Foo) { } - | ^^^ missing reference to `T` +LL | fn foo(x: &dyn Foo) { } + | ^^^ missing reference to `T` | = note: because of the default `Self` reference, type parameters must be specified on object types diff --git a/src/test/ui/type/type-params-in-different-spaces-1.stderr b/src/test/ui/type/type-params-in-different-spaces-1.stderr index e1b8ff70a6315..b3b78424fd904 100644 --- a/src/test/ui/type/type-params-in-different-spaces-1.stderr +++ b/src/test/ui/type/type-params-in-different-spaces-1.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/type-params-in-different-spaces-1.rs:5:17 | -LL | *self + rhs //~ ERROR mismatched types +LL | *self + rhs | ^^^ expected Self, found type parameter | = note: expected type `Self` diff --git a/src/test/ui/type/type-params-in-different-spaces-2.stderr b/src/test/ui/type/type-params-in-different-spaces-2.stderr index 3d50c2c8baf8d..15db94ef1e3c3 100644 --- a/src/test/ui/type/type-params-in-different-spaces-2.stderr +++ b/src/test/ui/type/type-params-in-different-spaces-2.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `Self: Tr` is not satisfied --> $DIR/type-params-in-different-spaces-2.rs:10:9 | -LL | Tr::op(u) //~ ERROR E0277 +LL | Tr::op(u) | ^^^^^^ the trait `Tr` is not implemented for `Self` | = help: consider adding a `where Self: Tr` bound @@ -14,7 +14,7 @@ LL | fn op(_: T) -> Self; error[E0277]: the trait bound `Self: Tr` is not satisfied --> $DIR/type-params-in-different-spaces-2.rs:16:9 | -LL | Tr::op(u) //~ ERROR E0277 +LL | Tr::op(u) | ^^^^^^ the trait `Tr` is not implemented for `Self` | = help: consider adding a `where Self: Tr` bound diff --git a/src/test/ui/type/type-params-in-different-spaces-3.stderr b/src/test/ui/type/type-params-in-different-spaces-3.stderr index 69288ea491da1..4e8134da2ddf4 100644 --- a/src/test/ui/type/type-params-in-different-spaces-3.stderr +++ b/src/test/ui/type/type-params-in-different-spaces-3.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | fn test(u: X) -> Self { | ---- expected `Self` because of return type -LL | u //~ ERROR mismatched types +LL | u | ^ expected Self, found type parameter | = note: expected type `Self` diff --git a/src/test/ui/type/type-path-err-node-types.stderr b/src/test/ui/type/type-path-err-node-types.stderr index e73b1fb029ce8..ed744478f26f8 100644 --- a/src/test/ui/type/type-path-err-node-types.stderr +++ b/src/test/ui/type/type-path-err-node-types.stderr @@ -1,28 +1,28 @@ error[E0433]: failed to resolve: use of undeclared type or module `NonExistent` --> $DIR/type-path-err-node-types.rs:15:5 | -LL | NonExistent::Assoc::; //~ ERROR undeclared type or module `NonExistent` +LL | NonExistent::Assoc::; | ^^^^^^^^^^^ use of undeclared type or module `NonExistent` error[E0412]: cannot find type `Nonexistent` in this scope --> $DIR/type-path-err-node-types.rs:7:12 | -LL | let _: Nonexistent; //~ ERROR cannot find type `Nonexistent` in this scope +LL | let _: Nonexistent; | ^^^^^^^^^^^ not found in this scope error[E0576]: cannot find method or associated constant `nonexistent` in trait `Tr` --> $DIR/type-path-err-node-types.rs:11:21 | -LL | >::nonexistent(); //~ ERROR cannot find method or associated constant `nonexistent` +LL | >::nonexistent(); | ^^^^^^^^^^^ not found in `Tr` error[E0425]: cannot find value `nonexistent` in this scope --> $DIR/type-path-err-node-types.rs:19:5 | -LL | nonexistent.nonexistent::(); //~ ERROR cannot find value `nonexistent` +LL | nonexistent.nonexistent::(); | ^^^^^^^^^^^ not found in this scope error: aborting due to 4 previous errors -Some errors occurred: E0412, E0425, E0433, E0576. +Some errors have detailed explanations: E0412, E0425, E0433. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/type/type-recursive.stderr b/src/test/ui/type/type-recursive.stderr index b1ecc1f91cbcf..72bf372e561d6 100644 --- a/src/test/ui/type/type-recursive.stderr +++ b/src/test/ui/type/type-recursive.stderr @@ -1,7 +1,7 @@ error[E0072]: recursive type `T1` has infinite size --> $DIR/type-recursive.rs:1:1 | -LL | struct T1 { //~ ERROR E0072 +LL | struct T1 { | ^^^^^^^^^ recursive type has infinite size LL | foo: isize, LL | foolish: T1 diff --git a/src/test/ui/type/type-shadow.stderr b/src/test/ui/type/type-shadow.stderr index 4c7aa00565adf..f15bdc16d5144 100644 --- a/src/test/ui/type/type-shadow.stderr +++ b/src/test/ui/type/type-shadow.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/type-shadow.rs:6:20 | -LL | let y: Y = "hello"; //~ ERROR mismatched types +LL | let y: Y = "hello"; | ^^^^^^^ expected isize, found reference | = note: expected type `isize` diff --git a/src/test/ui/type_length_limit.rs b/src/test/ui/type_length_limit.rs index bb54669d37df2..cd15f81a61535 100644 --- a/src/test/ui/type_length_limit.rs +++ b/src/test/ui/type_length_limit.rs @@ -1,3 +1,5 @@ +// ignore-musl +// ignore-x86 // error-pattern: reached the type-length limit while instantiating // Test that the type length limit can be changed. diff --git a/src/test/ui/type_length_limit.stderr b/src/test/ui/type_length_limit.stderr index 910eca075948a..7e308f107ba00 100644 --- a/src/test/ui/type_length_limit.stderr +++ b/src/test/ui/type_length_limit.stderr @@ -1,6 +1,10 @@ -error: reached the type-length limit while instantiating `std::mem::drop::>` + --> $SRC_DIR/libcore/mem/mod.rs:LL:COL | - = note: consider adding a `#![type_length_limit="512"]` attribute to your crate +LL | pub fn drop(_x: T) { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: consider adding a `#![type_length_limit="1094"]` attribute to your crate error: aborting due to previous error diff --git a/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr index bb63917fc0860..d41086186f8d7 100644 --- a/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr +++ b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr @@ -3,11 +3,11 @@ error[E0308]: mismatched types | LL | fn ice(x: Box>) { | - possibly return type missing here? -LL | *x //~ ERROR mismatched types [E0308] +LL | *x | ^^ expected (), found trait std::iter::Iterator | = note: expected type `()` - found type `(dyn std::iter::Iterator + 'static)` + found type `(dyn std::iter::Iterator + 'static)` error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr b/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr index 41bf3fd1c4460..1184e30749fe0 100644 --- a/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr +++ b/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr @@ -1,9 +1,8 @@ error[E0568]: auto traits cannot have super traits --> $DIR/typeck-auto-trait-no-supertraits-2.rs:3:1 | -LL | auto trait Magic : Sized where Option : Magic {} //~ ERROR E0568 +LL | auto trait Magic : Sized where Option : Magic {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0568`. diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr b/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr index bf40eaad65390..7b45ca07b35c7 100644 --- a/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr +++ b/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr @@ -1,9 +1,8 @@ error[E0568]: auto traits cannot have super traits --> $DIR/typeck-auto-trait-no-supertraits.rs:27:1 | -LL | auto trait Magic: Copy {} //~ ERROR E0568 +LL | auto trait Magic: Copy {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0568`. diff --git a/src/test/ui/typeck/typeck-builtin-bound-type-parameters.rs b/src/test/ui/typeck/typeck-builtin-bound-type-parameters.rs index 7760866436210..f466c19e051ed 100644 --- a/src/test/ui/typeck/typeck-builtin-bound-type-parameters.rs +++ b/src/test/ui/typeck/typeck-builtin-bound-type-parameters.rs @@ -1,7 +1,7 @@ fn foo1, U>(x: T) {} //~^ ERROR wrong number of type arguments: expected 0, found 1 [E0107] -trait Trait: Copy {} +trait Trait: Copy {} //~^ ERROR wrong number of type arguments: expected 0, found 1 [E0107] struct MyStruct1>; diff --git a/src/test/ui/typeck/typeck-builtin-bound-type-parameters.stderr b/src/test/ui/typeck/typeck-builtin-bound-type-parameters.stderr index 0242287a3e5ef..0be1c8ef3bc16 100644 --- a/src/test/ui/typeck/typeck-builtin-bound-type-parameters.stderr +++ b/src/test/ui/typeck/typeck-builtin-bound-type-parameters.stderr @@ -7,8 +7,8 @@ LL | fn foo1, U>(x: T) {} error[E0107]: wrong number of type arguments: expected 0, found 1 --> $DIR/typeck-builtin-bound-type-parameters.rs:4:19 | -LL | trait Trait: Copy {} - | ^^^^ unexpected type argument +LL | trait Trait: Copy {} + | ^^^^^^^^ unexpected type argument error[E0107]: wrong number of type arguments: expected 0, found 1 --> $DIR/typeck-builtin-bound-type-parameters.rs:7:26 diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr index 3f7e4a674e65a..a31ee83ae1ccc 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr @@ -1,7 +1,7 @@ error[E0277]: `::AssocType` cannot be sent between threads safely --> $DIR/typeck-default-trait-impl-assoc-type.rs:9:5 | -LL | is_send::(); //~ ERROR E0277 +LL | is_send::(); | ^^^^^^^^^^^^^^^^^^^^^^^ `::AssocType` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `::AssocType` diff --git a/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr b/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr index 2bfb4110603f5..6518684496559 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr @@ -1,7 +1,7 @@ error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:13:1 | -LL | impl DefaultedTrait for (A,) { } //~ ERROR E0117 +LL | impl DefaultedTrait for (A,) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate | = note: the impl does not reference only types defined in this crate @@ -10,7 +10,7 @@ LL | impl DefaultedTrait for (A,) { } //~ ERROR E0117 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:16:1 | -LL | impl !DefaultedTrait for (B,) { } //~ ERROR E0117 +LL | impl !DefaultedTrait for (B,) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate | = note: the impl does not reference only types defined in this crate @@ -19,13 +19,13 @@ LL | impl !DefaultedTrait for (B,) { } //~ ERROR E0117 error[E0321]: cross-crate traits with a default impl, like `lib::DefaultedTrait`, can only be implemented for a struct/enum type defined in the current crate --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:20:1 | -LL | impl DefaultedTrait for Box { } //~ ERROR E0321 +LL | impl DefaultedTrait for Box { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait for type in another crate error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:21:1 | -LL | impl DefaultedTrait for lib::Something { } //~ ERROR E0117 +LL | impl DefaultedTrait for lib::Something { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate | = note: the impl does not reference only types defined in this crate @@ -33,5 +33,5 @@ LL | impl DefaultedTrait for lib::Something { } //~ ERROR E0117 error: aborting due to 4 previous errors -Some errors occurred: E0117, E0321. +Some errors have detailed explanations: E0117, E0321. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.rs b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.rs index f31dac27caec4..e4487fb110cf1 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.rs +++ b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - #![feature(optin_builtin_traits)] struct Managed; diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr index 5330c04074b2f..4d435bf4e8b24 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr @@ -1,18 +1,18 @@ error[E0277]: `MyNotSync` cannot be shared between threads safely - --> $DIR/typeck-default-trait-impl-negation-sync.rs:35:5 + --> $DIR/typeck-default-trait-impl-negation-sync.rs:33:5 | LL | is_sync::(); | ^^^^^^^^^^^^^^^^^^^^ `MyNotSync` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `MyNotSync` note: required by `is_sync` - --> $DIR/typeck-default-trait-impl-negation-sync.rs:31:1 + --> $DIR/typeck-default-trait-impl-negation-sync.rs:29:1 | LL | fn is_sync() {} | ^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `std::cell::UnsafeCell` cannot be shared between threads safely - --> $DIR/typeck-default-trait-impl-negation-sync.rs:38:5 + --> $DIR/typeck-default-trait-impl-negation-sync.rs:36:5 | LL | is_sync::(); | ^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` cannot be shared between threads safely @@ -20,13 +20,13 @@ LL | is_sync::(); = help: within `MyTypeWUnsafe`, the trait `std::marker::Sync` is not implemented for `std::cell::UnsafeCell` = note: required because it appears within the type `MyTypeWUnsafe` note: required by `is_sync` - --> $DIR/typeck-default-trait-impl-negation-sync.rs:31:1 + --> $DIR/typeck-default-trait-impl-negation-sync.rs:29:1 | LL | fn is_sync() {} | ^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `Managed` cannot be shared between threads safely - --> $DIR/typeck-default-trait-impl-negation-sync.rs:41:5 + --> $DIR/typeck-default-trait-impl-negation-sync.rs:39:5 | LL | is_sync::(); | ^^^^^^^^^^^^^^^^^^^^^^^^ `Managed` cannot be shared between threads safely @@ -34,7 +34,7 @@ LL | is_sync::(); = help: within `MyTypeManaged`, the trait `std::marker::Sync` is not implemented for `Managed` = note: required because it appears within the type `MyTypeManaged` note: required by `is_sync` - --> $DIR/typeck-default-trait-impl-negation-sync.rs:31:1 + --> $DIR/typeck-default-trait-impl-negation-sync.rs:29:1 | LL | fn is_sync() {} | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr index 736e1b8da7f3c..a850cc7b377d0 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr @@ -1,7 +1,7 @@ error[E0277]: `T` cannot be sent between threads safely --> $DIR/typeck-default-trait-impl-send-param.rs:5:5 | -LL | is_send::() //~ ERROR E0277 +LL | is_send::() | ^^^^^^^^^^^^ `T` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `T` diff --git a/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr b/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr index 759a16cdafde9..1251d6eee80f0 100644 --- a/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr +++ b/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr @@ -28,7 +28,7 @@ LL | fn bar(self: &Bar, x: isize) -> isize { error[E0308]: mismatched method receiver --> $DIR/ufcs-explicit-self-bad.rs:37:21 | -LL | fn dummy2(self: &Bar) {} //~ ERROR mismatched method receiver +LL | fn dummy2(self: &Bar) {} | ^^^^^^^ lifetime mismatch | = note: expected type `&'a Bar` @@ -36,7 +36,7 @@ LL | fn dummy2(self: &Bar) {} //~ ERROR mismatched method receiver note: the anonymous lifetime #1 defined on the method body at 37:5... --> $DIR/ufcs-explicit-self-bad.rs:37:5 | -LL | fn dummy2(self: &Bar) {} //~ ERROR mismatched method receiver +LL | fn dummy2(self: &Bar) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 35:6 --> $DIR/ufcs-explicit-self-bad.rs:35:6 @@ -47,7 +47,7 @@ LL | impl<'a, T> SomeTrait for &'a Bar { error[E0308]: mismatched method receiver --> $DIR/ufcs-explicit-self-bad.rs:37:21 | -LL | fn dummy2(self: &Bar) {} //~ ERROR mismatched method receiver +LL | fn dummy2(self: &Bar) {} | ^^^^^^^ lifetime mismatch | = note: expected type `&'a Bar` @@ -60,7 +60,7 @@ LL | impl<'a, T> SomeTrait for &'a Bar { note: ...does not necessarily outlive the anonymous lifetime #1 defined on the method body at 37:5 --> $DIR/ufcs-explicit-self-bad.rs:37:5 | -LL | fn dummy2(self: &Bar) {} //~ ERROR mismatched method receiver +LL | fn dummy2(self: &Bar) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched method receiver @@ -103,5 +103,4 @@ LL | fn dummy3(self: &&Bar) {} error: aborting due to 7 previous errors -Some errors occurred: E0307, E0308. -For more information about an error, try `rustc --explain E0307`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/ufcs/ufcs-partially-resolved.rs b/src/test/ui/ufcs/ufcs-partially-resolved.rs index 4efded8b37661..82a593ff16cfa 100644 --- a/src/test/ui/ufcs/ufcs-partially-resolved.rs +++ b/src/test/ui/ufcs/ufcs-partially-resolved.rs @@ -45,9 +45,9 @@ fn main() { ::NN; //~ ERROR cannot find method or associated constant `NN` in `E::N` ::NN; //~ ERROR cannot find method or associated constant `NN` in `A::N` let _: ::NN; //~ ERROR cannot find associated type `NN` in `Tr::Y` - let _: ::NN; //~ ERROR failed to resolve: not a module `Y` + let _: ::NN; //~ ERROR failed to resolve: `Y` is a variant, not a module ::NN; //~ ERROR cannot find method or associated constant `NN` in `Tr::Y` - ::NN; //~ ERROR failed to resolve: not a module `Y` + ::NN; //~ ERROR failed to resolve: `Y` is a variant, not a module let _: ::Z; //~ ERROR expected associated type, found method `Dr::Z` ::X; //~ ERROR expected method or associated constant, found associated type `Dr::X` diff --git a/src/test/ui/ufcs/ufcs-partially-resolved.stderr b/src/test/ui/ufcs/ufcs-partially-resolved.stderr index 3cd1cac71fa76..5ee8adaaf270f 100644 --- a/src/test/ui/ufcs/ufcs-partially-resolved.stderr +++ b/src/test/ui/ufcs/ufcs-partially-resolved.stderr @@ -1,163 +1,163 @@ -error[E0433]: failed to resolve: not a module `Y` +error[E0433]: failed to resolve: `Y` is a variant, not a module --> $DIR/ufcs-partially-resolved.rs:48:22 | -LL | let _: ::NN; //~ ERROR failed to resolve: not a module `Y` - | ^ not a module `Y` +LL | let _: ::NN; + | ^ `Y` is a variant, not a module -error[E0433]: failed to resolve: not a module `Y` +error[E0433]: failed to resolve: `Y` is a variant, not a module --> $DIR/ufcs-partially-resolved.rs:50:15 | -LL | ::NN; //~ ERROR failed to resolve: not a module `Y` - | ^ not a module `Y` +LL | ::NN; + | ^ `Y` is a variant, not a module error[E0576]: cannot find associated type `N` in trait `Tr` --> $DIR/ufcs-partially-resolved.rs:19:24 | -LL | let _: ::N; //~ ERROR cannot find associated type `N` in trait `Tr` +LL | let _: ::N; | ^ help: an associated type with a similar name exists: `Y` error[E0576]: cannot find associated type `N` in enum `E` --> $DIR/ufcs-partially-resolved.rs:20:23 | -LL | let _: ::N; //~ ERROR cannot find associated type `N` in enum `E` +LL | let _: ::N; | ^ not found in `E` error[E0576]: cannot find associated type `N` in `A` --> $DIR/ufcs-partially-resolved.rs:21:23 | -LL | let _: ::N; //~ ERROR cannot find associated type `N` in `A` +LL | let _: ::N; | ^ not found in `A` error[E0576]: cannot find method or associated constant `N` in trait `Tr` --> $DIR/ufcs-partially-resolved.rs:22:17 | -LL | ::N; //~ ERROR cannot find method or associated constant `N` in trait `Tr` +LL | ::N; | ^ help: a method with a similar name exists: `Y` error[E0576]: cannot find method or associated constant `N` in enum `E` --> $DIR/ufcs-partially-resolved.rs:23:16 | -LL | ::N; //~ ERROR cannot find method or associated constant `N` in enum `E` +LL | ::N; | ^ not found in `E` error[E0576]: cannot find method or associated constant `N` in `A` --> $DIR/ufcs-partially-resolved.rs:24:16 | -LL | ::N; //~ ERROR cannot find method or associated constant `N` in `A` +LL | ::N; | ^ not found in `A` error[E0575]: expected associated type, found variant `E::Y` --> $DIR/ufcs-partially-resolved.rs:26:12 | -LL | let _: ::Y; //~ ERROR expected associated type, found variant `E::Y` +LL | let _: ::Y; | ^^^^^^^^^^^^ not a associated type error[E0575]: expected method or associated constant, found unit variant `E::Y` --> $DIR/ufcs-partially-resolved.rs:28:5 | -LL | ::Y; //~ ERROR expected method or associated constant, found unit variant `E::Y` +LL | ::Y; | ^^^^^^^^^^^^ not a method or associated constant error[E0576]: cannot find associated type `N` in trait `Tr` --> $DIR/ufcs-partially-resolved.rs:30:24 | -LL | let _: ::N::NN; //~ ERROR cannot find associated type `N` in trait `Tr` +LL | let _: ::N::NN; | ^ help: an associated type with a similar name exists: `Y` error[E0576]: cannot find associated type `N` in enum `E` --> $DIR/ufcs-partially-resolved.rs:31:23 | -LL | let _: ::N::NN; //~ ERROR cannot find associated type `N` in enum `E` +LL | let _: ::N::NN; | ^ not found in `E` error[E0576]: cannot find associated type `N` in `A` --> $DIR/ufcs-partially-resolved.rs:32:23 | -LL | let _: ::N::NN; //~ ERROR cannot find associated type `N` in `A` +LL | let _: ::N::NN; | ^ not found in `A` error[E0576]: cannot find associated type `N` in trait `Tr` --> $DIR/ufcs-partially-resolved.rs:33:17 | -LL | ::N::NN; //~ ERROR cannot find associated type `N` in trait `Tr` +LL | ::N::NN; | ^ help: an associated type with a similar name exists: `Y` error[E0576]: cannot find associated type `N` in enum `E` --> $DIR/ufcs-partially-resolved.rs:34:16 | -LL | ::N::NN; //~ ERROR cannot find associated type `N` in enum `E` +LL | ::N::NN; | ^ not found in `E` error[E0576]: cannot find associated type `N` in `A` --> $DIR/ufcs-partially-resolved.rs:35:16 | -LL | ::N::NN; //~ ERROR cannot find associated type `N` in `A` +LL | ::N::NN; | ^ not found in `A` error[E0575]: expected associated type, found variant `E::Y` --> $DIR/ufcs-partially-resolved.rs:37:12 | -LL | let _: ::Y::NN; //~ ERROR expected associated type, found variant `E::Y` +LL | let _: ::Y::NN; | ^^^^^^^^^^^^^^^^ not a associated type error[E0575]: expected associated type, found variant `E::Y` --> $DIR/ufcs-partially-resolved.rs:39:5 | -LL | ::Y::NN; //~ ERROR expected associated type, found variant `E::Y` +LL | ::Y::NN; | ^^^^^^^^^^^^^^^^ not a associated type error[E0576]: cannot find associated type `NN` in `Tr::N` --> $DIR/ufcs-partially-resolved.rs:41:27 | -LL | let _: ::NN; //~ ERROR cannot find associated type `NN` in `Tr::N` +LL | let _: ::NN; | ^^ not found in `Tr::N` error[E0576]: cannot find associated type `NN` in `E::N` --> $DIR/ufcs-partially-resolved.rs:42:26 | -LL | let _: ::NN; //~ ERROR cannot find associated type `NN` in `E::N` +LL | let _: ::NN; | ^^ not found in `E::N` error[E0576]: cannot find associated type `NN` in `A::N` --> $DIR/ufcs-partially-resolved.rs:43:26 | -LL | let _: ::NN; //~ ERROR cannot find associated type `NN` in `A::N` +LL | let _: ::NN; | ^^ not found in `A::N` error[E0576]: cannot find method or associated constant `NN` in `Tr::N` --> $DIR/ufcs-partially-resolved.rs:44:20 | -LL | ::NN; //~ ERROR cannot find method or associated constant `NN` in `Tr::N` +LL | ::NN; | ^^ not found in `Tr::N` error[E0576]: cannot find method or associated constant `NN` in `E::N` --> $DIR/ufcs-partially-resolved.rs:45:19 | -LL | ::NN; //~ ERROR cannot find method or associated constant `NN` in `E::N` +LL | ::NN; | ^^ not found in `E::N` error[E0576]: cannot find method or associated constant `NN` in `A::N` --> $DIR/ufcs-partially-resolved.rs:46:19 | -LL | ::NN; //~ ERROR cannot find method or associated constant `NN` in `A::N` +LL | ::NN; | ^^ not found in `A::N` error[E0576]: cannot find associated type `NN` in `Tr::Y` --> $DIR/ufcs-partially-resolved.rs:47:27 | -LL | let _: ::NN; //~ ERROR cannot find associated type `NN` in `Tr::Y` +LL | let _: ::NN; | ^^ not found in `Tr::Y` error[E0576]: cannot find method or associated constant `NN` in `Tr::Y` --> $DIR/ufcs-partially-resolved.rs:49:20 | -LL | ::NN; //~ ERROR cannot find method or associated constant `NN` in `Tr::Y` +LL | ::NN; | ^^ not found in `Tr::Y` error[E0575]: expected associated type, found method `Dr::Z` --> $DIR/ufcs-partially-resolved.rs:52:12 | -LL | let _: ::Z; //~ ERROR expected associated type, found method `Dr::Z` +LL | let _: ::Z; | ^^^^^^^^^^^^- | | | help: an associated type with a similar name exists: `X` @@ -165,7 +165,7 @@ LL | let _: ::Z; //~ ERROR expected associated type, found method error[E0575]: expected method or associated constant, found associated type `Dr::X` --> $DIR/ufcs-partially-resolved.rs:53:5 | -LL | ::X; //~ ERROR expected method or associated constant, found associated type `Dr::X` +LL | ::X; | ^^^^^^^^^^^^- | | | help: a method with a similar name exists: `Z` @@ -175,7 +175,7 @@ LL | ::X; //~ ERROR expected method or associated constant, found error[E0575]: expected associated type, found method `Dr::Z` --> $DIR/ufcs-partially-resolved.rs:54:12 | -LL | let _: ::Z::N; //~ ERROR expected associated type, found method `Dr::Z` +LL | let _: ::Z::N; | ^^^^^^^^^^^^-^^^ | | | help: an associated type with a similar name exists: `X` @@ -183,26 +183,22 @@ LL | let _: ::Z::N; //~ ERROR expected associated type, found meth error[E0223]: ambiguous associated type --> $DIR/ufcs-partially-resolved.rs:36:12 | -LL | let _: ::Y::NN; //~ ERROR ambiguous associated type +LL | let _: ::Y::NN; | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<::Y as Trait>::NN` error[E0599]: no associated item named `NN` found for type `::Y` in the current scope --> $DIR/ufcs-partially-resolved.rs:38:20 | -LL | ::Y::NN; //~ ERROR no associated item named `NN` found for type `::Y` - | ---------------^^ - | | - | associated item not found in `::Y` +LL | ::Y::NN; + | ^^ associated item not found in `::Y` error[E0599]: no associated item named `N` found for type `::X` in the current scope --> $DIR/ufcs-partially-resolved.rs:55:20 | -LL | ::X::N; //~ ERROR no associated item named `N` found for type `::X` - | ---------------^ - | | - | associated item not found in `::X` +LL | ::X::N; + | ^ associated item not found in `::X` error: aborting due to 32 previous errors -Some errors occurred: E0223, E0433, E0575, E0576, E0599. +Some errors have detailed explanations: E0223, E0433, E0599. For more information about an error, try `rustc --explain E0223`. diff --git a/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr index e3027eedbf909..f749ed3f9d865 100644 --- a/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -11,14 +11,22 @@ error[E0308]: mismatched types | LL | >::add(1u32, 2); | ^^^^ expected i32, found u32 +help: change the type of the numeric literal from `u32` to `i32` + | +LL | >::add(1i32, 2); + | ^^^^ error[E0308]: mismatched types --> $DIR/ufcs-qpath-self-mismatch.rs:8:31 | LL | >::add(1, 2u32); | ^^^^ expected i32, found u32 +help: change the type of the numeric literal from `u32` to `i32` + | +LL | >::add(1, 2i32); + | ^^^^ error: aborting due to 3 previous errors -Some errors occurred: E0277, E0308. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/ui-testing-optout.stderr b/src/test/ui/ui-testing-optout.stderr index 5a662e0ea89c2..313e198e39e36 100644 --- a/src/test/ui/ui-testing-optout.stderr +++ b/src/test/ui/ui-testing-optout.stderr @@ -1,19 +1,19 @@ error[E0412]: cannot find type `B` in this scope --> $DIR/ui-testing-optout.rs:4:10 | -4 | type A = B; //~ ERROR +4 | type A = B; | ^ help: a type alias with a similar name exists: `A` error[E0412]: cannot find type `D` in this scope --> $DIR/ui-testing-optout.rs:10:10 | -10 | type C = D; //~ ERROR +10 | type C = D; | ^ help: a type alias with a similar name exists: `A` error[E0412]: cannot find type `F` in this scope --> $DIR/ui-testing-optout.rs:95:10 | -95 | type E = F; //~ ERROR +95 | type E = F; | ^ help: a type alias with a similar name exists: `A` error: aborting due to 3 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.rs b/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.rs index 1eb9de778e82d..d8b201bf82d3b 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.rs +++ b/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.rs @@ -10,11 +10,11 @@ trait Foo { } fn main() { - let x: Box; + let x: Box; //~^ ERROR parenthetical notation is only stable when used with `Fn`-family // No errors with these: - let x: Box; - let x: Box; - let x: Box; + let x: Box; + let x: Box; + let x: Box; } diff --git a/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr b/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr index 038167ae9d733..c23acbcb311d6 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr @@ -1,9 +1,10 @@ -error[E0658]: parenthetical notation is only stable when used with `Fn`-family traits (see issue #29625) - --> $DIR/unboxed-closure-feature-gate.rs:13:16 +error[E0658]: parenthetical notation is only stable when used with `Fn`-family traits + --> $DIR/unboxed-closure-feature-gate.rs:13:20 | -LL | let x: Box; - | ^^^^^^^^^^ +LL | let x: Box; + | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.nll.stderr deleted file mode 100644 index 0e996902d621d..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.nll.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/unboxed-closure-illegal-move.rs:15:31 - | -LL | let x = Box::new(0); - | - captured outer variable -LL | let f = to_fn(|| drop(x)); //~ ERROR cannot move - | ^ cannot move out of captured variable in an `Fn` closure - -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/unboxed-closure-illegal-move.rs:19:35 - | -LL | let x = Box::new(0); - | - captured outer variable -LL | let f = to_fn_mut(|| drop(x)); //~ ERROR cannot move - | ^ cannot move out of captured variable in an `FnMut` closure - -error[E0507]: cannot move out of captured variable in an `Fn` closure - --> $DIR/unboxed-closure-illegal-move.rs:28:36 - | -LL | let x = Box::new(0); - | - captured outer variable -LL | let f = to_fn(move || drop(x)); //~ ERROR cannot move - | ^ cannot move out of captured variable in an `Fn` closure - -error[E0507]: cannot move out of captured variable in an `FnMut` closure - --> $DIR/unboxed-closure-illegal-move.rs:32:40 - | -LL | let x = Box::new(0); - | - captured outer variable -LL | let f = to_fn_mut(move || drop(x)); //~ ERROR cannot move - | ^ cannot move out of captured variable in an `FnMut` closure - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr index ae83242d5349a..58062872aa3c3 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr @@ -1,34 +1,34 @@ -error[E0507]: cannot move out of captured outer variable in an `Fn` closure +error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure --> $DIR/unboxed-closure-illegal-move.rs:15:31 | LL | let x = Box::new(0); | - captured outer variable -LL | let f = to_fn(|| drop(x)); //~ ERROR cannot move - | ^ cannot move out of captured outer variable in an `Fn` closure +LL | let f = to_fn(|| drop(x)); + | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured outer variable in an `FnMut` closure +error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure --> $DIR/unboxed-closure-illegal-move.rs:19:35 | LL | let x = Box::new(0); | - captured outer variable -LL | let f = to_fn_mut(|| drop(x)); //~ ERROR cannot move - | ^ cannot move out of captured outer variable in an `FnMut` closure +LL | let f = to_fn_mut(|| drop(x)); + | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured outer variable in an `Fn` closure +error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure --> $DIR/unboxed-closure-illegal-move.rs:28:36 | LL | let x = Box::new(0); | - captured outer variable -LL | let f = to_fn(move || drop(x)); //~ ERROR cannot move - | ^ cannot move out of captured outer variable in an `Fn` closure +LL | let f = to_fn(move || drop(x)); + | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait -error[E0507]: cannot move out of captured outer variable in an `FnMut` closure +error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure --> $DIR/unboxed-closure-illegal-move.rs:32:40 | LL | let x = Box::new(0); | - captured outer variable -LL | let f = to_fn_mut(move || drop(x)); //~ ERROR cannot move - | ^ cannot move out of captured outer variable in an `FnMut` closure +LL | let f = to_fn_mut(move || drop(x)); + | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait error: aborting due to 4 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.nll.stderr deleted file mode 100644 index 51a0a6e575646..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.nll.stderr +++ /dev/null @@ -1,75 +0,0 @@ -error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/unboxed-closure-immutable-capture.rs:9:13 - | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -LL | move || x = 1; //~ ERROR cannot assign - | ^^^^^ cannot assign - -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/unboxed-closure-immutable-capture.rs:10:17 - | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -LL | move || x = 1; //~ ERROR cannot assign -LL | move || set(&mut x); //~ ERROR cannot borrow - | ^^^^^^ cannot borrow as mutable - -error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/unboxed-closure-immutable-capture.rs:11:13 - | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... -LL | move || x = 1; //~ ERROR cannot assign - | ^^^^^ cannot assign - -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/unboxed-closure-immutable-capture.rs:12:17 - | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... -LL | move || set(&mut x); //~ ERROR cannot borrow - | ^^^^^^ cannot borrow as mutable - -error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/unboxed-closure-immutable-capture.rs:13:8 - | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... -LL | || x = 1; //~ ERROR cannot assign - | ^^^^^ cannot assign - -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/unboxed-closure-immutable-capture.rs:15:12 - | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... -LL | || set(&mut x); //~ ERROR cannot assign - | ^^^^^^ cannot borrow as mutable - -error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/unboxed-closure-immutable-capture.rs:16:8 - | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... -LL | || x = 1; //~ ERROR cannot assign - | ^^^^^ cannot assign - -error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/unboxed-closure-immutable-capture.rs:18:12 - | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... -LL | || set(&mut x); //~ ERROR cannot assign - | ^^^^^^ cannot borrow as mutable - -error: aborting due to 8 previous errors - -Some errors occurred: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.rs b/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.rs index 5d59cecf99ae6..3eba9c4d431a2 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.rs +++ b/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.rs @@ -11,9 +11,7 @@ fn main() { move || x = 1; //~ ERROR cannot assign move || set(&mut x); //~ ERROR cannot borrow || x = 1; //~ ERROR cannot assign - // FIXME: this should be `cannot borrow` (issue #18330) - || set(&mut x); //~ ERROR cannot assign + || set(&mut x); //~ ERROR cannot borrow || x = 1; //~ ERROR cannot assign - // FIXME: this should be `cannot borrow` (issue #18330) - || set(&mut x); //~ ERROR cannot assign + || set(&mut x); //~ ERROR cannot borrow } diff --git a/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr b/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr index 1865e2486f14e..9fd8aa562f4e4 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr @@ -1,69 +1,74 @@ -error[E0595]: closure cannot assign to immutable local variable `x` - --> $DIR/unboxed-closure-immutable-capture.rs:13:5 +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:9:13 | LL | let x = 0; - | - help: make this binding mutable: `mut x` -... -LL | || x = 1; //~ ERROR cannot assign - | ^^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut x` +LL | move || x = 1; + | ^^^^^ cannot assign -error[E0595]: closure cannot assign to immutable local variable `x` - --> $DIR/unboxed-closure-immutable-capture.rs:15:5 +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:10:17 | LL | let x = 0; - | - help: make this binding mutable: `mut x` -... -LL | || set(&mut x); //~ ERROR cannot assign - | ^^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut x` +LL | move || x = 1; +LL | move || set(&mut x); + | ^^^^^^ cannot borrow as mutable -error[E0595]: closure cannot assign to immutable local variable `x` - --> $DIR/unboxed-closure-immutable-capture.rs:16:5 +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:11:13 | LL | let x = 0; - | - help: make this binding mutable: `mut x` + | - help: consider changing this to be mutable: `mut x` ... -LL | || x = 1; //~ ERROR cannot assign - | ^^ cannot borrow mutably +LL | move || x = 1; + | ^^^^^ cannot assign -error[E0595]: closure cannot assign to immutable local variable `x` - --> $DIR/unboxed-closure-immutable-capture.rs:18:5 +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:12:17 | LL | let x = 0; - | - help: make this binding mutable: `mut x` + | - help: consider changing this to be mutable: `mut x` ... -LL | || set(&mut x); //~ ERROR cannot assign - | ^^ cannot borrow mutably +LL | move || set(&mut x); + | ^^^^^^ cannot borrow as mutable -error[E0594]: cannot assign to captured outer variable in an `FnMut` closure - --> $DIR/unboxed-closure-immutable-capture.rs:9:13 +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:13:8 | LL | let x = 0; - | - help: consider making `x` mutable: `mut x` -LL | move || x = 1; //~ ERROR cannot assign - | ^^^^^ + | - help: consider changing this to be mutable: `mut x` +... +LL | || x = 1; + | ^^^^^ cannot assign -error[E0596]: cannot borrow captured outer variable in an `FnMut` closure as mutable - --> $DIR/unboxed-closure-immutable-capture.rs:10:22 +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:14:12 | -LL | move || set(&mut x); //~ ERROR cannot borrow - | ^ +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +... +LL | || set(&mut x); + | ^^^^^^ cannot borrow as mutable -error[E0594]: cannot assign to captured outer variable in an `FnMut` closure - --> $DIR/unboxed-closure-immutable-capture.rs:11:13 +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:15:8 | LL | let x = 0; - | - help: consider making `x` mutable: `mut x` + | - help: consider changing this to be mutable: `mut x` ... -LL | move || x = 1; //~ ERROR cannot assign - | ^^^^^ +LL | || x = 1; + | ^^^^^ cannot assign -error[E0596]: cannot borrow captured outer variable in an `FnMut` closure as mutable - --> $DIR/unboxed-closure-immutable-capture.rs:12:22 +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closure-immutable-capture.rs:16:12 | -LL | move || set(&mut x); //~ ERROR cannot borrow - | ^ +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +... +LL | || set(&mut x); + | ^^^^^^ cannot borrow as mutable error: aborting due to 8 previous errors -Some errors occurred: E0594, E0595, E0596. -For more information about an error, try `rustc --explain E0594`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/unboxed-closures/unboxed-closure-no-cyclic-sig.stderr b/src/test/ui/unboxed-closures/unboxed-closure-no-cyclic-sig.stderr index fc45520851889..0d3766426bd2f 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-no-cyclic-sig.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-no-cyclic-sig.stderr @@ -1,7 +1,7 @@ error[E0644]: closure/generator type that references itself --> $DIR/unboxed-closure-no-cyclic-sig.rs:8:7 | -LL | g(|_| { }); //~ ERROR closure/generator type that references itself +LL | g(|_| { }); | ^^^^^^^^ cyclic type of infinite size | = note: closures cannot capture themselves or take themselves as argument; diff --git a/src/test/ui/unboxed-closures/unboxed-closure-region.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closure-region.nll.stderr deleted file mode 100644 index 1c55a6bb08eb5..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closure-region.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0597]: `x` does not live long enough - --> $DIR/unboxed-closure-region.rs:8:12 - | -LL | let _f = { - | -- borrow later stored here -LL | let x = 0; -LL | || x //~ ERROR `x` does not live long enough - | -- ^ borrowed value does not live long enough - | | - | value captured here -LL | }; - | - `x` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/unboxed-closures/unboxed-closure-region.stderr b/src/test/ui/unboxed-closures/unboxed-closure-region.stderr index a0f009c0689c9..b40b2f67d9bad 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-region.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-region.stderr @@ -1,15 +1,15 @@ error[E0597]: `x` does not live long enough --> $DIR/unboxed-closure-region.rs:8:12 | -LL | || x //~ ERROR `x` does not live long enough +LL | let _f = { + | -- borrow later stored here +LL | let x = 0; +LL | || x | -- ^ borrowed value does not live long enough | | - | capture occurs here + | value captured here LL | }; - | - borrowed value only lives until here -LL | _f; -LL | } - | - borrowed value needs to live until here + | - `x` dropped here while still borrowed error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.rs b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.rs index 044859de6a4a5..f1c83f0606fad 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.rs +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.rs @@ -15,14 +15,14 @@ fn eq() where A : Eq { } fn test<'a,'b>() { // Parens are equivalent to omitting default in angle. - eq::< Foo<(isize,),Output=()>, Foo(isize) >(); + eq::, dyn Foo(isize)>(); // In angle version, we supply something other than the default - eq::< Foo<(isize,),isize,Output=()>, Foo(isize) >(); + eq::, dyn Foo(isize)>(); //~^ ERROR E0277 // Supply default explicitly. - eq::< Foo<(isize,),(isize,),Output=()>, Foo(isize) >(); + eq::, dyn Foo(isize)>(); } fn main() { } diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr index 508c2f780b9fb..fd5ef4b9df15a 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `dyn Foo<(isize,), isize, Output=()>: Eq>` is not satisfied +error[E0277]: the trait bound `dyn Foo<(isize,), isize, Output = ()>: Eq>` is not satisfied --> $DIR/unboxed-closure-sugar-default.rs:21:5 | -LL | eq::< Foo<(isize,),isize,Output=()>, Foo(isize) >(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq>` is not implemented for `dyn Foo<(isize,), isize, Output=()>` +LL | eq::, dyn Foo(isize)>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq>` is not implemented for `dyn Foo<(isize,), isize, Output = ()>` | note: required by `eq` --> $DIR/unboxed-closure-sugar-default.rs:14:1 diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs index 95bd391f251b8..0fc3e23ec73ef 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs @@ -17,31 +17,31 @@ fn eq>() { } fn test<'a,'b>() { // No errors expected: - eq::< Foo<(),Output=()>, Foo() >(); - eq::< Foo<(isize,),Output=()>, Foo(isize) >(); - eq::< Foo<(isize,usize),Output=()>, Foo(isize,usize) >(); - eq::< Foo<(isize,usize),Output=usize>, Foo(isize,usize) -> usize >(); - eq::< Foo<(&'a isize,&'b usize),Output=usize>, Foo(&'a isize,&'b usize) -> usize >(); + eq::< dyn Foo<(),Output=()>, dyn Foo() >(); + eq::< dyn Foo<(isize,),Output=()>, dyn Foo(isize) >(); + eq::< dyn Foo<(isize,usize),Output=()>, dyn Foo(isize,usize) >(); + eq::< dyn Foo<(isize,usize),Output=usize>, dyn Foo(isize,usize) -> usize >(); + eq::< dyn Foo<(&'a isize,&'b usize),Output=usize>, dyn Foo(&'a isize,&'b usize) -> usize >(); // Test that anonymous regions in `()` form are equivalent // to fresh bound regions, and that we can intermingle // named and anonymous as we choose: - eq::< for<'x,'y> Foo<(&'x isize,&'y usize),Output=usize>, - for<'x,'y> Foo(&'x isize,&'y usize) -> usize >(); - eq::< for<'x,'y> Foo<(&'x isize,&'y usize),Output=usize>, - for<'x> Foo(&'x isize,&usize) -> usize >(); - eq::< for<'x,'y> Foo<(&'x isize,&'y usize),Output=usize>, - for<'y> Foo(&isize,&'y usize) -> usize >(); - eq::< for<'x,'y> Foo<(&'x isize,&'y usize),Output=usize>, - Foo(&isize,&usize) -> usize >(); + eq::< dyn for<'x,'y> Foo<(&'x isize,&'y usize),Output=usize>, + dyn for<'x,'y> Foo(&'x isize,&'y usize) -> usize >(); + eq::< dyn for<'x,'y> Foo<(&'x isize,&'y usize),Output=usize>, + dyn for<'x> Foo(&'x isize,&usize) -> usize >(); + eq::< dyn for<'x,'y> Foo<(&'x isize,&'y usize),Output=usize>, + dyn for<'y> Foo(&isize,&'y usize) -> usize >(); + eq::< dyn for<'x,'y> Foo<(&'x isize,&'y usize),Output=usize>, + dyn Foo(&isize,&usize) -> usize >(); // lifetime elision - eq::< for<'x> Foo<(&'x isize,), Output=&'x isize>, - Foo(&isize) -> &isize >(); + eq::< dyn for<'x> Foo<(&'x isize,), Output=&'x isize>, + dyn Foo(&isize) -> &isize >(); // Errors expected: - eq::< Foo<(),Output=()>, - Foo(char) >(); + eq::< dyn Foo<(),Output=()>, + dyn Foo(char) >(); //~^^ ERROR E0277 } diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr index 071ba2792b0ac..005a86bc2178b 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr @@ -1,9 +1,9 @@ -error[E0277]: the trait bound `dyn Foo<(char,), Output=()>: Eq>` is not satisfied +error[E0277]: the trait bound `dyn Foo<(char,), Output = ()>: Eq>` is not satisfied --> $DIR/unboxed-closure-sugar-equiv.rs:43:5 | -LL | / eq::< Foo<(),Output=()>, -LL | | Foo(char) >(); - | |___________________________________________________________________^ the trait `Eq>` is not implemented for `dyn Foo<(char,), Output=()>` +LL | / eq::< dyn Foo<(),Output=()>, +LL | | dyn Foo(char) >(); + | |_______________________________________________________________________^ the trait `Eq>` is not implemented for `dyn Foo<(char,), Output = ()>` | note: required by `eq` --> $DIR/unboxed-closure-sugar-equiv.rs:16:1 diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.rs b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.rs index b61d8b8c8c790..d11d663f17261 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.rs +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.rs @@ -18,10 +18,10 @@ impl Eq for X { } fn eq>() { } fn main() { - eq::< for<'a> Foo<(&'a isize,), Output=&'a isize>, - Foo(&isize) -> &isize >(); - eq::< for<'a> Foo<(&'a isize,), Output=(&'a isize, &'a isize)>, - Foo(&isize) -> (&isize, &isize) >(); + eq::< dyn for<'a> Foo<(&'a isize,), Output=&'a isize>, + dyn Foo(&isize) -> &isize >(); + eq::< dyn for<'a> Foo<(&'a isize,), Output=(&'a isize, &'a isize)>, + dyn Foo(&isize) -> (&isize, &isize) >(); - let _: Foo(&isize, &usize) -> &usize; //~ ERROR missing lifetime specifier + let _: dyn Foo(&isize, &usize) -> &usize; //~ ERROR missing lifetime specifier } diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr index e631c33678863..9fb9a07166f84 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr @@ -1,8 +1,8 @@ error[E0106]: missing lifetime specifier - --> $DIR/unboxed-closure-sugar-lifetime-elision.rs:26:35 + --> $DIR/unboxed-closure-sugar-lifetime-elision.rs:26:39 | -LL | let _: Foo(&isize, &usize) -> &usize; //~ ERROR missing lifetime specifier - | ^ expected lifetime parameter +LL | let _: dyn Foo(&isize, &usize) -> &usize; + | ^ expected lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.rs b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.rs index 09927a940192a..6d6ed4b568f0b 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.rs +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.rs @@ -1,6 +1,6 @@ // Test that the `Fn` traits require `()` form without a feature gate. -fn bar1(x: &Fn<(), Output=()>) { +fn bar1(x: &dyn Fn<(), Output=()>) { //~^ ERROR of `Fn`-family traits' type parameters is subject to change } diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr index 90f04a52d370a..e1ed85d4f4672 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr @@ -1,17 +1,19 @@ -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) - --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:3:13 +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead + --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:3:17 | -LL | fn bar1(x: &Fn<(), Output=()>) { - | ^^^^^^^^^^^^^^^^^ +LL | fn bar1(x: &dyn Fn<(), Output=()>) { + | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:7:28 | LL | fn bar2(x: &T) where T: Fn<()> { | ^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.rs b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.rs index 799d9f33e2e9d..76c928d7b6ab5 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.rs +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.rs @@ -20,14 +20,14 @@ fn same_type>(a: A, b: B) { } fn test<'a,'b>() { // Parens are equivalent to omitting default in angle. - eq::< Foo<(isize,),Output=()>, Foo(isize) >(); + eq::< dyn Foo<(isize,),Output=()>, dyn Foo(isize) >(); // Here we specify 'static explicitly in angle-bracket version. // Parenthesized winds up getting inferred. - eq::< Foo<'static, (isize,),Output=()>, Foo(isize) >(); + eq::< dyn Foo<'static, (isize,),Output=()>, dyn Foo(isize) >(); } -fn test2(x: &Foo<(isize,),Output=()>, y: &Foo(isize)) { +fn test2(x: &dyn Foo<(isize,),Output=()>, y: &dyn Foo(isize)) { //~^ ERROR wrong number of lifetime arguments: expected 1, found 0 // Here, the omitted lifetimes are expanded to distinct things. same_type(x, y) diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr index 8eed7d58c4666..e9d51983a7a48 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr @@ -1,8 +1,8 @@ error[E0107]: wrong number of lifetime arguments: expected 1, found 0 - --> $DIR/unboxed-closure-sugar-region.rs:30:43 + --> $DIR/unboxed-closure-sugar-region.rs:30:51 | -LL | fn test2(x: &Foo<(isize,),Output=()>, y: &Foo(isize)) { - | ^^^^^^^^^^ expected 1 lifetime argument +LL | fn test2(x: &dyn Foo<(isize,),Output=()>, y: &dyn Foo(isize)) { + | ^^^^^^^^^^ expected 1 lifetime argument error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.stderr index fa52e66fb0349..81095826f38ae 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.stderr @@ -12,5 +12,5 @@ LL | let x: Box = panic!(); error: aborting due to 2 previous errors -Some errors occurred: E0107, E0214. +Some errors have detailed explanations: E0107, E0214. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.stderr index b34237937ee1c..3c78d9f9135cf 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.stderr @@ -12,5 +12,5 @@ LL | fn foo(b: Box) { error: aborting due to 2 previous errors -Some errors occurred: E0107, E0214. +Some errors have detailed explanations: E0107, E0214. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs index df0c495a11cc6..a6c86311b3772 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs @@ -2,7 +2,7 @@ trait One { fn foo(&self) -> A; } -fn foo(_: &One()) //~ ERROR associated type `Output` not found for `One<()>` +fn foo(_: &dyn One()) //~ ERROR associated type `Output` not found for `One<()>` {} fn main() { } diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr index 84ed797450c24..c59082932ddfe 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr @@ -1,8 +1,8 @@ error[E0220]: associated type `Output` not found for `One<()>` - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs:5:15 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs:5:19 | -LL | fn foo(_: &One()) //~ ERROR associated type `Output` not found for `One<()>` - | ^^ associated type `Output` not found +LL | fn foo(_: &dyn One()) + | ^^ associated type `Output` not found error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs index 5f5ad7902aa3e..01c76d64c6ba0 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs @@ -2,7 +2,7 @@ trait Three { fn dummy(&self) -> (A,B,C); } -fn foo(_: &Three()) +fn foo(_: &dyn Three()) //~^ ERROR wrong number of type arguments //~| ERROR associated type `Output` not found {} diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr index 3a9fff3831c61..6c61e74584a50 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr @@ -1,16 +1,16 @@ error[E0107]: wrong number of type arguments: expected 3, found 1 - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:12 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:16 | -LL | fn foo(_: &Three()) - | ^^^^^^^ expected 3 type arguments +LL | fn foo(_: &dyn Three()) + | ^^^^^^^ expected 3 type arguments error[E0220]: associated type `Output` not found for `Three<(), [type error], [type error]>` - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:17 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:21 | -LL | fn foo(_: &Three()) - | ^^ associated type `Output` not found +LL | fn foo(_: &dyn Three()) + | ^^ associated type `Output` not found error: aborting due to 2 previous errors -Some errors occurred: E0107, E0220. +Some errors have detailed explanations: E0107, E0220. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs index 2e87d91f8bdc0..bc9901c795b3a 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs @@ -2,7 +2,7 @@ trait Zero { fn dummy(&self); } -fn foo(_: Zero()) +fn foo(_: dyn Zero()) //~^ ERROR wrong number of type arguments //~| ERROR associated type `Output` not found for `Zero` {} diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr index 3f80197897c2a..b96e2cbc36bb4 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr @@ -1,16 +1,16 @@ error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:5:15 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:5:19 | -LL | fn foo(_: Zero()) - | ^^ unexpected type argument +LL | fn foo(_: dyn Zero()) + | ^^ unexpected type argument error[E0220]: associated type `Output` not found for `Zero` - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:5:15 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:5:19 | -LL | fn foo(_: Zero()) - | ^^ associated type `Output` not found +LL | fn foo(_: dyn Zero()) + | ^^ associated type `Output` not found error: aborting due to 2 previous errors -Some errors occurred: E0107, E0220. +Some errors have detailed explanations: E0107, E0220. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr index a04062e7b9d3a..bd707a8508a7d 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr @@ -12,5 +12,5 @@ LL | fn f isize>(x: F) {} error: aborting due to 2 previous errors -Some errors occurred: E0107, E0220. +Some errors have detailed explanations: E0107, E0220. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-borrow-conflict.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-borrow-conflict.nll.stderr deleted file mode 100644 index a47d33d29e158..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closures-borrow-conflict.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/unboxed-closures-borrow-conflict.rs:9:14 - | -LL | let f = || x += 1; - | -- - borrow occurs due to use of `x` in closure - | | - | borrow of `x` occurs here -LL | let _y = x; //~ ERROR cannot use `x` because it was mutably borrowed - | ^ use of borrowed `x` -LL | f; - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-borrow-conflict.stderr b/src/test/ui/unboxed-closures/unboxed-closures-borrow-conflict.stderr index 461eebc59c029..21d6b4fde7e90 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-borrow-conflict.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-borrow-conflict.stderr @@ -1,10 +1,14 @@ error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/unboxed-closures-borrow-conflict.rs:9:9 + --> $DIR/unboxed-closures-borrow-conflict.rs:9:14 | LL | let f = || x += 1; - | -- borrow of `x` occurs here -LL | let _y = x; //~ ERROR cannot use `x` because it was mutably borrowed - | ^^ use of borrowed `x` + | -- - borrow occurs due to use of `x` in closure + | | + | borrow of `x` occurs here +LL | let _y = x; + | ^ use of borrowed `x` +LL | f; + | - borrow later used here error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.nll.stderr deleted file mode 100644 index 1749c20b582b0..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.nll.stderr +++ /dev/null @@ -1,62 +0,0 @@ -error[E0597]: `factorial` does not live long enough - --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:15:17 - | -LL | let f = |x: u32| -> u32 { - | --------------- value captured here -LL | let g = factorial.as_ref().unwrap(); - | ^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `factorial` dropped here while still borrowed - | borrow might be used here, when `factorial` is dropped and runs the destructor for type `std::option::Option u32>>` - -error[E0506]: cannot assign to `factorial` because it is borrowed - --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:20:5 - | -LL | let f = |x: u32| -> u32 { - | --------------- borrow of `factorial` occurs here -LL | let g = factorial.as_ref().unwrap(); - | --------- borrow occurs due to use in closure -... -LL | factorial = Some(Box::new(f)); - | ^^^^^^^^^ - | | - | assignment to borrowed `factorial` occurs here - | borrow later used here - -error[E0597]: `factorial` does not live long enough - --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:28:17 - | -LL | let mut factorial: Option u32 + 'static>> = None; - | ------------------------------------- type annotation requires that `factorial` is borrowed for `'static` -LL | -LL | let f = |x: u32| -> u32 { - | --------------- value captured here -LL | //~^ ERROR closure may outlive the current function, but it borrows `factorial` -LL | let g = factorial.as_ref().unwrap(); - | ^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - `factorial` dropped here while still borrowed - -error[E0506]: cannot assign to `factorial` because it is borrowed - --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:32:5 - | -LL | let mut factorial: Option u32 + 'static>> = None; - | ------------------------------------- type annotation requires that `factorial` is borrowed for `'static` -LL | -LL | let f = |x: u32| -> u32 { - | --------------- borrow of `factorial` occurs here -LL | //~^ ERROR closure may outlive the current function, but it borrows `factorial` -LL | let g = factorial.as_ref().unwrap(); - | --------- borrow occurs due to use in closure -... -LL | factorial = Some(Box::new(f)); - | ^^^^^^^^^ assignment to borrowed `factorial` occurs here - -error: aborting due to 4 previous errors - -Some errors occurred: E0506, E0597. -For more information about an error, try `rustc --explain E0506`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.rs b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.rs index b72482a712118..1358ba0f953e8 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.rs @@ -9,7 +9,7 @@ fn a() { // iteration, but it still doesn't work. The weird structure with // the `Option` is to avoid giving any useful hints about the `Fn` // kind via the expected type. - let mut factorial: Option u32>> = None; + let mut factorial: Option u32>> = None; let f = |x: u32| -> u32 { let g = factorial.as_ref().unwrap(); @@ -18,18 +18,20 @@ fn a() { }; factorial = Some(Box::new(f)); + //~^ ERROR cannot assign to `factorial` because it is borrowed } fn b() { - let mut factorial: Option u32 + 'static>> = None; + let mut factorial: Option u32 + 'static>> = None; let f = |x: u32| -> u32 { - //~^ ERROR closure may outlive the current function, but it borrows `factorial` let g = factorial.as_ref().unwrap(); + //~^ ERROR `factorial` does not live long enough if x == 0 {1} else {x * g(x-1)} }; factorial = Some(Box::new(f)); + //~^ ERROR cannot assign to `factorial` because it is borrowed } fn main() { } diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr index 85d98c18d7ffd..0466887e371e9 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr @@ -2,29 +2,59 @@ error[E0597]: `factorial` does not live long enough --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:15:17 | LL | let f = |x: u32| -> u32 { - | --------------- capture occurs here + | --------------- value captured here LL | let g = factorial.as_ref().unwrap(); | ^^^^^^^^^ borrowed value does not live long enough ... LL | } - | - borrowed value dropped before borrower + | - + | | + | `factorial` dropped here while still borrowed + | borrow might be used here, when `factorial` is dropped and runs the destructor for type `std::option::Option u32>>` + +error[E0506]: cannot assign to `factorial` because it is borrowed + --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:20:5 | - = note: values in a scope are dropped in the opposite order they are created +LL | let f = |x: u32| -> u32 { + | --------------- borrow of `factorial` occurs here +LL | let g = factorial.as_ref().unwrap(); + | --------- borrow occurs due to use in closure +... +LL | factorial = Some(Box::new(f)); + | ^^^^^^^^^ + | | + | assignment to borrowed `factorial` occurs here + | borrow later used here -error[E0373]: closure may outlive the current function, but it borrows `factorial`, which is owned by the current function - --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:26:13 +error[E0597]: `factorial` does not live long enough + --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:28:17 | +LL | let mut factorial: Option u32 + 'static>> = None; + | ----------------------------------------- type annotation requires that `factorial` is borrowed for `'static` +LL | LL | let f = |x: u32| -> u32 { - | ^^^^^^^^^^^^^^^ may outlive borrowed value `factorial` -LL | //~^ ERROR closure may outlive the current function, but it borrows `factorial` + | --------------- value captured here LL | let g = factorial.as_ref().unwrap(); - | --------- `factorial` is borrowed here -help: to force the closure to take ownership of `factorial` (and any other referenced variables), use the `move` keyword + | ^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `factorial` dropped here while still borrowed + +error[E0506]: cannot assign to `factorial` because it is borrowed + --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:33:5 | -LL | let f = move |x: u32| -> u32 { - | ^^^^^^^^^^^^^^^^^^^^ +LL | let mut factorial: Option u32 + 'static>> = None; + | ----------------------------------------- type annotation requires that `factorial` is borrowed for `'static` +LL | +LL | let f = |x: u32| -> u32 { + | --------------- borrow of `factorial` occurs here +LL | let g = factorial.as_ref().unwrap(); + | --------- borrow occurs due to use in closure +... +LL | factorial = Some(Box::new(f)); + | ^^^^^^^^^ assignment to borrowed `factorial` occurs here -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors -Some errors occurred: E0373, E0597. -For more information about an error, try `rustc --explain E0373`. +Some errors have detailed explanations: E0506, E0597. +For more information about an error, try `rustc --explain E0506`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr index bd58e241f0cb0..18af3dc640d1c 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `std::option::Option` --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:16:32 | LL | let mut closure0 = None; - | ------------ consider giving `closure0` a type + | ------------ consider giving `closure0` the explicit type `std::option::Option`, with the type parameters specified ... LL | return c(); | ^^^ cannot infer type diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr new file mode 100644 index 0000000000000..ead42c1488966 --- /dev/null +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/unboxed-closures-infer-argument-types-two-region-pointers.rs:17:9 + | +LL | doit(0, &|x, y| { + | - - has type `&'1 i32` + | | + | has type `&std::cell::Cell<&'2 i32>` +LL | x.set(y); + | ^^^^^^^^ argument requires that `'1` must outlive `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr index bf43dc62744f3..728efadf4196e 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr @@ -1,7 +1,7 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/unboxed-closures-infer-argument-types-two-region-pointers.rs:17:15 | -LL | x.set(y); //~ ERROR E0312 +LL | x.set(y); | ^ | note: ...the reference is valid for the anonymous lifetime #3 defined on the body at 16:14... @@ -9,7 +9,7 @@ note: ...the reference is valid for the anonymous lifetime #3 defined on the bod | LL | doit(0, &|x, y| { | ______________^ -LL | | x.set(y); //~ ERROR E0312 +LL | | x.set(y); LL | | }); | |_____^ note: ...but the borrowed content is only valid for the anonymous lifetime #4 defined on the body at 16:14 @@ -17,10 +17,9 @@ note: ...but the borrowed content is only valid for the anonymous lifetime #4 de | LL | doit(0, &|x, y| { | ______________^ -LL | | x.set(y); //~ ERROR E0312 +LL | | x.set(y); LL | | }); | |_____^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0312`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr index 384cd090cb3c7..9287353245e98 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr @@ -1,7 +1,7 @@ error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` --> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13 | -LL | let c = || drop(y.0); //~ ERROR expected a closure that implements the `Fn` trait +LL | let c = || drop(y.0); | ^^^^^^^^-^^^ | | | | | closure is `FnOnce` because it moves the variable `y` out of its environment diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.nll.stderr deleted file mode 100644 index 89ac402b5e02b..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0596]: cannot borrow `tick1` as mutable, as it is not declared as mutable - --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:17:9 - | -LL | let tick1 = || { - | ----- help: consider changing this to be mutable: `mut tick1` -... -LL | tick1(); - | ^^^^^ cannot borrow as mutable - -error[E0596]: cannot borrow `tick2` as mutable, as it is not declared as mutable - --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:20:5 - | -LL | let tick2 = || { //~ ERROR closure cannot assign to immutable local variable `tick1` - | ----- help: consider changing this to be mutable: `mut tick2` -... -LL | tick2(); //~ ERROR cannot borrow - | ^^^^^ cannot borrow as mutable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs index aaa692c109f69..6401b5e01fcd9 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs @@ -11,10 +11,9 @@ fn main() { }; // In turn, tick2 must be inferred to FnMut so that it can call - // tick1, but we forgot the mut. The error message we currently - // get seems... suboptimal. - let tick2 = || { //~ ERROR closure cannot assign to immutable local variable `tick1` - tick1(); + // tick1, but we forgot the mut. + let tick2 = || { + tick1(); //~ ERROR cannot borrow `tick1` as mutable }; tick2(); //~ ERROR cannot borrow diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr index bc839d7b53622..5dea424596e9c 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr @@ -1,22 +1,21 @@ -error[E0595]: closure cannot assign to immutable local variable `tick1` - --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:16:17 +error[E0596]: cannot borrow `tick1` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:16:9 | LL | let tick1 = || { - | ----- help: make this binding mutable: `mut tick1` + | ----- help: consider changing this to be mutable: `mut tick1` ... -LL | let tick2 = || { //~ ERROR closure cannot assign to immutable local variable `tick1` - | ^^ cannot borrow mutably +LL | tick1(); + | ^^^^^ cannot borrow as mutable -error[E0596]: cannot borrow immutable local variable `tick2` as mutable - --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:20:5 +error[E0596]: cannot borrow `tick2` as mutable, as it is not declared as mutable + --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:19:5 | -LL | let tick2 = || { //~ ERROR closure cannot assign to immutable local variable `tick1` - | ----- help: make this binding mutable: `mut tick2` +LL | let tick2 = || { + | ----- help: consider changing this to be mutable: `mut tick2` ... -LL | tick2(); //~ ERROR cannot borrow - | ^^^^^ cannot borrow mutably +LL | tick2(); + | ^^^^^ cannot borrow as mutable error: aborting due to 2 previous errors -Some errors occurred: E0595, E0596. -For more information about an error, try `rustc --explain E0595`. +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.nll.stderr deleted file mode 100644 index 9c0a71e73f522..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable - --> $DIR/unboxed-closures-infer-fnmut-missing-mut.rs:7:5 - | -LL | let tick = || counter += 1; - | ---- help: consider changing this to be mutable: `mut tick` -LL | tick(); //~ ERROR cannot borrow immutable local variable `tick` as mutable - | ^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.rs b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.rs index de3f9839d2664..5c0ceb23d614c 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.rs @@ -4,5 +4,5 @@ fn main() { let mut counter = 0; let tick = || counter += 1; - tick(); //~ ERROR cannot borrow immutable local variable `tick` as mutable + tick(); //~ ERROR cannot borrow `tick` as mutable, as it is not declared as mutable } diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr index d4d285275e9e2..eb398628846dd 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr @@ -1,10 +1,10 @@ -error[E0596]: cannot borrow immutable local variable `tick` as mutable +error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable --> $DIR/unboxed-closures-infer-fnmut-missing-mut.rs:7:5 | LL | let tick = || counter += 1; - | ---- help: make this binding mutable: `mut tick` -LL | tick(); //~ ERROR cannot borrow immutable local variable `tick` as mutable - | ^^^^ cannot borrow mutably + | ---- help: consider changing this to be mutable: `mut tick` +LL | tick(); + | ^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.nll.stderr deleted file mode 100644 index fa3426a1f7096..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable - --> $DIR/unboxed-closures-infer-fnmut-move-missing-mut.rs:7:5 - | -LL | let tick = move || counter += 1; - | ---- help: consider changing this to be mutable: `mut tick` -LL | tick(); //~ ERROR cannot borrow immutable local variable `tick` as mutable - | ^^^^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.rs b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.rs index b011c5a58bc3e..144a674ac589e 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.rs @@ -4,5 +4,5 @@ fn main() { let mut counter = 0; let tick = move || counter += 1; - tick(); //~ ERROR cannot borrow immutable local variable `tick` as mutable + tick(); //~ ERROR cannot borrow `tick` as mutable, as it is not declared as mutable } diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr index 2137f9904ce16..b9d76d9a752ce 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr @@ -1,10 +1,10 @@ -error[E0596]: cannot borrow immutable local variable `tick` as mutable +error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable --> $DIR/unboxed-closures-infer-fnmut-move-missing-mut.rs:7:5 | LL | let tick = move || counter += 1; - | ---- help: make this binding mutable: `mut tick` -LL | tick(); //~ ERROR cannot borrow immutable local variable `tick` as mutable - | ^^^^ cannot borrow mutably + | ---- help: consider changing this to be mutable: `mut tick` +LL | tick(); + | ^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr index 52650903ba3f2..0b9aa61a765fa 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr @@ -3,7 +3,7 @@ error[E0382]: use of moved value: `tick` | LL | tick(); | ---- value moved here -LL | tick(); //~ ERROR use of moved value: `tick` +LL | tick(); | ^^^^ value used here after move | note: closure cannot be invoked more than once because it moves the variable `counter` out of its environment diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr index 23d61c33ffe06..20773d561f9f2 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr @@ -3,7 +3,7 @@ error[E0382]: use of moved value: `tick` | LL | tick(); | ---- value moved here -LL | tick(); //~ ERROR use of moved value: `tick` +LL | tick(); | ^^^^ value used here after move | note: closure cannot be invoked more than once because it moves the variable `counter` out of its environment diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.nll.stderr deleted file mode 100644 index 9b2f1cd4ae339..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.nll.stderr +++ /dev/null @@ -1,45 +0,0 @@ -error[E0594]: cannot assign to `n`, as it is not declared as mutable - --> $DIR/unboxed-closures-mutate-upvar.rs:15:9 - | -LL | let n = 0; - | - help: consider changing this to be mutable: `mut n` -LL | let mut f = to_fn_mut(|| { //~ ERROR closure cannot assign -LL | n += 1; - | ^^^^^^ cannot assign - -error[E0594]: cannot assign to `n`, as it is not declared as mutable - --> $DIR/unboxed-closures-mutate-upvar.rs:32:9 - | -LL | let n = 0; - | - help: consider changing this to be mutable: `mut n` -... -LL | n += 1; //~ ERROR cannot assign - | ^^^^^^ cannot assign - -error[E0594]: cannot assign to `n`, as it is not declared as mutable - --> $DIR/unboxed-closures-mutate-upvar.rs:46:9 - | -LL | let n = 0; - | - help: consider changing this to be mutable: `mut n` -LL | let mut f = to_fn(move || { -LL | n += 1; //~ ERROR cannot assign - | ^^^^^^ cannot assign - -error[E0594]: cannot assign to `n`, as it is a captured variable in a `Fn` closure - --> $DIR/unboxed-closures-mutate-upvar.rs:53:9 - | -LL | n += 1; //~ ERROR cannot assign - | ^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/unboxed-closures-mutate-upvar.rs:52:23 - | -LL | let mut f = to_fn(move || { - | _______________________^ -LL | | n += 1; //~ ERROR cannot assign -LL | | }); - | |_____^ - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.rs b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.rs index 3bea9226f2115..57e6d30658ce5 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.rs @@ -11,8 +11,8 @@ fn to_fn_mut>(f: F) -> F { f } fn a() { let n = 0; - let mut f = to_fn_mut(|| { //~ ERROR closure cannot assign - n += 1; + let mut f = to_fn_mut(|| { + n += 1; //~ ERROR cannot assign to `n`, as it is not declared as mutable }); } diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr index 99fc287b1eefa..fef6c23a50130 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr @@ -1,53 +1,44 @@ -error[E0595]: closure cannot assign to immutable local variable `n` - --> $DIR/unboxed-closures-mutate-upvar.rs:14:27 +error[E0594]: cannot assign to `n`, as it is not declared as mutable + --> $DIR/unboxed-closures-mutate-upvar.rs:15:9 | LL | let n = 0; - | - help: make this binding mutable: `mut n` -LL | let mut f = to_fn_mut(|| { //~ ERROR closure cannot assign - | ^^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut n` +LL | let mut f = to_fn_mut(|| { +LL | n += 1; + | ^^^^^^ cannot assign -error[E0594]: cannot assign to captured outer variable in an `FnMut` closure +error[E0594]: cannot assign to `n`, as it is not declared as mutable --> $DIR/unboxed-closures-mutate-upvar.rs:32:9 | LL | let n = 0; - | - help: consider making `n` mutable: `mut n` + | - help: consider changing this to be mutable: `mut n` ... -LL | n += 1; //~ ERROR cannot assign - | ^^^^^^ +LL | n += 1; + | ^^^^^^ cannot assign -error[E0594]: cannot assign to captured outer variable in an `Fn` closure +error[E0594]: cannot assign to `n`, as it is not declared as mutable --> $DIR/unboxed-closures-mutate-upvar.rs:46:9 | -LL | n += 1; //~ ERROR cannot assign - | ^^^^^^ - | - = note: `Fn` closures cannot capture their enclosing environment for modifications -help: consider changing this closure to take self by mutable reference - --> $DIR/unboxed-closures-mutate-upvar.rs:45:23 - | -LL | let mut f = to_fn(move || { - | _______________________^ -LL | | n += 1; //~ ERROR cannot assign -LL | | }); - | |_____^ +LL | let n = 0; + | - help: consider changing this to be mutable: `mut n` +LL | let mut f = to_fn(move || { +LL | n += 1; + | ^^^^^^ cannot assign -error[E0594]: cannot assign to captured outer variable in an `Fn` closure +error[E0594]: cannot assign to `n`, as it is a captured variable in a `Fn` closure --> $DIR/unboxed-closures-mutate-upvar.rs:53:9 | -LL | n += 1; //~ ERROR cannot assign - | ^^^^^^ +LL | n += 1; + | ^^^^^^ cannot assign | - = note: `Fn` closures cannot capture their enclosing environment for modifications -help: consider changing this closure to take self by mutable reference +help: consider changing this to accept closures that implement `FnMut` --> $DIR/unboxed-closures-mutate-upvar.rs:52:23 | LL | let mut f = to_fn(move || { | _______________________^ -LL | | n += 1; //~ ERROR cannot assign +LL | | n += 1; LL | | }); | |_____^ error: aborting due to 4 previous errors -Some errors occurred: E0594, E0595. -For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.ast.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.ast.nll.stderr deleted file mode 100644 index 2f83a6485cdd7..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.ast.nll.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0594]: cannot assign to `counter`, as it is a captured variable in a `Fn` closure - --> $DIR/unboxed-closures-mutated-upvar-from-fn-closure.rs:14:9 - | -LL | counter += 1; - | ^^^^^^^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/unboxed-closures-mutated-upvar-from-fn-closure.rs:13:10 - | -LL | call(|| { - | __________^ -LL | | counter += 1; -LL | | //[ast]~^ ERROR cannot assign to data in a captured outer variable in an `Fn` closure -LL | | //[mir]~^^ ERROR cannot assign to `counter` -LL | | }); - | |_____^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.ast.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.ast.stderr deleted file mode 100644 index 293f59ff4b27a..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.ast.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0387]: cannot assign to data in a captured outer variable in an `Fn` closure - --> $DIR/unboxed-closures-mutated-upvar-from-fn-closure.rs:14:9 - | -LL | counter += 1; - | ^^^^^^^^^^^^ - | -help: consider changing this closure to take self by mutable reference - --> $DIR/unboxed-closures-mutated-upvar-from-fn-closure.rs:13:10 - | -LL | call(|| { - | __________^ -LL | | counter += 1; -LL | | //[ast]~^ ERROR cannot assign to data in a captured outer variable in an `Fn` closure -LL | | //[mir]~^^ ERROR cannot assign to `counter` -LL | | }); - | |_____^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0387`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.mir.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.mir.stderr deleted file mode 100644 index 2f83a6485cdd7..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.mir.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0594]: cannot assign to `counter`, as it is a captured variable in a `Fn` closure - --> $DIR/unboxed-closures-mutated-upvar-from-fn-closure.rs:14:9 - | -LL | counter += 1; - | ^^^^^^^^^^^^ cannot assign - | -help: consider changing this to accept closures that implement `FnMut` - --> $DIR/unboxed-closures-mutated-upvar-from-fn-closure.rs:13:10 - | -LL | call(|| { - | __________^ -LL | | counter += 1; -LL | | //[ast]~^ ERROR cannot assign to data in a captured outer variable in an `Fn` closure -LL | | //[mir]~^^ ERROR cannot assign to `counter` -LL | | }); - | |_____^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.rs b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.rs index a5dcb57d33a61..174ad245d59fe 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.rs @@ -1,6 +1,3 @@ -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - // Test that a by-ref `FnMut` closure gets an error when it tries to // mutate a value. @@ -12,7 +9,6 @@ fn main() { let mut counter = 0; call(|| { counter += 1; - //[ast]~^ ERROR cannot assign to data in a captured outer variable in an `Fn` closure - //[mir]~^^ ERROR cannot assign to `counter` + //~^ ERROR cannot assign to `counter` }); } diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr new file mode 100644 index 0000000000000..2bc1f01af9815 --- /dev/null +++ b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr @@ -0,0 +1,18 @@ +error[E0594]: cannot assign to `counter`, as it is a captured variable in a `Fn` closure + --> $DIR/unboxed-closures-mutated-upvar-from-fn-closure.rs:11:9 + | +LL | counter += 1; + | ^^^^^^^^^^^^ cannot assign + | +help: consider changing this to accept closures that implement `FnMut` + --> $DIR/unboxed-closures-mutated-upvar-from-fn-closure.rs:10:10 + | +LL | call(|| { + | __________^ +LL | | counter += 1; +LL | | +LL | | }); + | |_____^ + +error: aborting due to previous error + diff --git a/src/test/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.nll.stderr deleted file mode 100644 index 830f6bc993dfe..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0499]: cannot borrow `*self` as mutable more than once at a time - --> $DIR/unboxed-closures-recursive-fn-using-fn-mut.rs:22:21 - | -LL | (self.func)(self, arg) - | ----------- ^^^^ second mutable borrow occurs here - | | - | first mutable borrow occurs here - | first borrow later used by call - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.rs b/src/test/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.rs index 0beead1ad92c3..6a707b2096d44 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.rs @@ -17,14 +17,14 @@ impl YCombinator { } } -impl R, A) -> R> FnMut<(A,)> for YCombinator { +impl R, A) -> R> FnMut<(A,)> for YCombinator { extern "rust-call" fn call_mut(&mut self, (arg,): (A,)) -> R { (self.func)(self, arg) //~^ ERROR cannot borrow `*self` as mutable more than once at a time } } -impl R, A) -> R> FnOnce<(A,)> for YCombinator { +impl R, A) -> R> FnOnce<(A,)> for YCombinator { type Output = R; extern "rust-call" fn call_once(mut self, args: (A,)) -> R { self.call_mut(args) @@ -33,7 +33,7 @@ impl R, A) -> R> FnOnce<(A,)> for YCombinator u32, arg: u32| -> u32 { + let factorial = |recur: &mut dyn FnMut(u32) -> u32, arg: u32| -> u32 { counter += 1; if arg == 0 {1} else {arg * recur(arg-1)} }; diff --git a/src/test/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.stderr b/src/test/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.stderr index f881d1982a5f5..830f6bc993dfe 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-recursive-fn-using-fn-mut.stderr @@ -2,10 +2,10 @@ error[E0499]: cannot borrow `*self` as mutable more than once at a time --> $DIR/unboxed-closures-recursive-fn-using-fn-mut.rs:22:21 | LL | (self.func)(self, arg) - | ----------- ^^^^ - first borrow ends here - | | | - | | second mutable borrow occurs here + | ----------- ^^^^ second mutable borrow occurs here + | | | first mutable borrow occurs here + | first borrow later used by call error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr b/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr index 1fccbb9c85727..2e1845888a2f7 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `call` found for type `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]` in the current scope --> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10 | -LL | mut_.call((0, )); //~ ERROR no method named `call` found +LL | mut_.call((0, )); | ^^^^ | = note: mut_ is a function, perhaps you wish to call it diff --git a/src/test/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr b/src/test/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr index 82e8c63ce27e4..758762fd5fde3 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr @@ -1,8 +1,12 @@ error[E0308]: mismatched types --> $DIR/unboxed-closures-type-mismatch.rs:5:15 | -LL | let z = f(1_usize, 2); //~ ERROR mismatched types +LL | let z = f(1_usize, 2); | ^^^^^^^ expected isize, found usize +help: change the type of the numeric literal from `usize` to `isize` + | +LL | let z = f(1_isize, 2); + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/unconstrained-none.stderr b/src/test/ui/unconstrained-none.stderr index e0ddae4cc8994..eb918b25d2bef 100644 --- a/src/test/ui/unconstrained-none.stderr +++ b/src/test/ui/unconstrained-none.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed --> $DIR/unconstrained-none.rs:4:5 | -LL | None; //~ ERROR type annotations needed [E0282] +LL | None; | ^^^^ cannot infer type for `T` error: aborting due to previous error diff --git a/src/test/ui/unconstrained-ref.stderr b/src/test/ui/unconstrained-ref.stderr index 7722963293f30..d9a129a2d7b22 100644 --- a/src/test/ui/unconstrained-ref.stderr +++ b/src/test/ui/unconstrained-ref.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed --> $DIR/unconstrained-ref.rs:6:5 | -LL | S { o: &None }; //~ ERROR type annotations needed [E0282] +LL | S { o: &None }; | ^ cannot infer type for `T` error: aborting due to previous error diff --git a/src/test/ui/underscore-ident-matcher.stderr b/src/test/ui/underscore-ident-matcher.stderr index 29fb9157b681e..241c3d3d8ce61 100644 --- a/src/test/ui/underscore-ident-matcher.stderr +++ b/src/test/ui/underscore-ident-matcher.stderr @@ -4,7 +4,7 @@ error: no rules expected the token `_` LL | macro_rules! identity { | --------------------- when calling this macro ... -LL | let identity!(_) = 10; //~ ERROR no rules expected the token `_` +LL | let identity!(_) = 10; | ^ no rules expected this token in macro call error: aborting due to previous error diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr index 904c6c23def16..b20c23ade2b78 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr @@ -1,16 +1,15 @@ error[E0106]: missing lifetime specifier --> $DIR/dyn-trait-underscore-in-struct.rs:9:24 | -LL | x: Box, //~ ERROR missing lifetime specifier +LL | x: Box, | ^^ expected lifetime parameter error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound --> $DIR/dyn-trait-underscore-in-struct.rs:9:12 | -LL | x: Box, //~ ERROR missing lifetime specifier +LL | x: Box, | ^^^^^^^^^^^^^^ error: aborting due to 2 previous errors -Some errors occurred: E0106, E0228. -For more information about an error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr new file mode 100644 index 0000000000000..8ed48bda26e85 --- /dev/null +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/dyn-trait-underscore.rs:8:5 + | +LL | fn a(items: &[T]) -> Box> { + | - let's call the lifetime of this reference `'1` +LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` +LL | Box::new(items.iter()) + | ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index 4eb959311ca48..92e5ac282e4d6 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -1,7 +1,7 @@ error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements --> $DIR/dyn-trait-underscore.rs:8:20 | -LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime +LL | Box::new(items.iter()) | ^^^^ | note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 6:1... @@ -9,19 +9,18 @@ note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on th | LL | / fn a(items: &[T]) -> Box> { LL | | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` -LL | | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime +LL | | Box::new(items.iter()) LL | | } | |_^ note: ...so that reference does not outlive borrowed content --> $DIR/dyn-trait-underscore.rs:8:14 | -LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime +LL | Box::new(items.iter()) | ^^^^^ = note: but, the lifetime must be valid for the static lifetime... = note: ...so that the expression is assignable: - expected std::boxed::Box<(dyn std::iter::Iterator + 'static)> - found std::boxed::Box> + expected std::boxed::Box<(dyn std::iter::Iterator + 'static)> + found std::boxed::Box> error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/underscore-lifetime/in-binder.stderr b/src/test/ui/underscore-lifetime/in-binder.stderr index fcd7eddb57605..1b936dd9aec2f 100644 --- a/src/test/ui/underscore-lifetime/in-binder.stderr +++ b/src/test/ui/underscore-lifetime/in-binder.stderr @@ -36,4 +36,3 @@ LL | fn foo<'_>() { error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr index ec9fe6ad9ae1b..ed61bdfdddab3 100644 --- a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr @@ -1,7 +1,7 @@ error[E0106]: missing lifetime specifier --> $DIR/in-fn-return-illegal.rs:5:30 | -LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } //~ ERROR missing lifetime specifier +LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } | ^^ expected lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` diff --git a/src/test/ui/underscore-lifetime/in-struct.stderr b/src/test/ui/underscore-lifetime/in-struct.stderr index 2b19c6865dc0f..6bbdc71195a50 100644 --- a/src/test/ui/underscore-lifetime/in-struct.stderr +++ b/src/test/ui/underscore-lifetime/in-struct.stderr @@ -1,13 +1,13 @@ error[E0106]: missing lifetime specifier --> $DIR/in-struct.rs:6:9 | -LL | x: &'_ u32, //~ ERROR missing lifetime specifier +LL | x: &'_ u32, | ^^ expected lifetime parameter error[E0106]: missing lifetime specifier --> $DIR/in-struct.rs:10:14 | -LL | Variant(&'_ u32), //~ ERROR missing lifetime specifier +LL | Variant(&'_ u32), | ^^ expected lifetime parameter error: aborting due to 2 previous errors diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.rs b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.rs index 614f7e49f8757..3d049cc5639c0 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.rs +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.rs @@ -7,7 +7,7 @@ fn foo<'_> //~ ERROR cannot be used here trait Meh<'a> {} impl<'a> Meh<'a> for u8 {} -fn meh() -> Box Meh<'_>> //~ ERROR cannot be used here +fn meh() -> Box Meh<'_>> //~ ERROR cannot be used here //~^ ERROR missing lifetime specifier { Box::new(5u8) diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index e0c2c89c08c3d..ef9e7e39df0bc 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -1,38 +1,37 @@ error[E0637]: `'_` cannot be used here --> $DIR/underscore-lifetime-binders.rs:4:8 | -LL | fn foo<'_> //~ ERROR cannot be used here +LL | fn foo<'_> | ^^ `'_` is a reserved lifetime name error[E0637]: `'_` cannot be used here - --> $DIR/underscore-lifetime-binders.rs:10:21 + --> $DIR/underscore-lifetime-binders.rs:10:25 | -LL | fn meh() -> Box Meh<'_>> //~ ERROR cannot be used here - | ^^ `'_` is a reserved lifetime name +LL | fn meh() -> Box Meh<'_>> + | ^^ `'_` is a reserved lifetime name error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:2:17 | -LL | struct Baz<'a>(&'_ &'a u8); //~ ERROR missing lifetime specifier +LL | struct Baz<'a>(&'_ &'a u8); | ^^ expected lifetime parameter error[E0106]: missing lifetime specifier - --> $DIR/underscore-lifetime-binders.rs:10:29 + --> $DIR/underscore-lifetime-binders.rs:10:33 | -LL | fn meh() -> Box Meh<'_>> //~ ERROR cannot be used here - | ^^ help: consider giving it a 'static lifetime: `'static` +LL | fn meh() -> Box Meh<'_>> + | ^^ help: consider giving it a 'static lifetime: `'static` | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:16:35 | -LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } //~ ERROR missing lifetime specifier +LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } | ^^ expected lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_` or `y` + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or `y` error: aborting due to 5 previous errors -Some errors occurred: E0106, E0637. -For more information about an error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.nll.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.nll.stderr new file mode 100644 index 0000000000000..e1d57b8ba1eda --- /dev/null +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/underscore-lifetime-elison-mismatch.rs:1:42 + | +LL | fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); } + | - - ^^^^^^^^^ argument requires that `'1` must outlive `'2` + | | | + | | let's call the lifetime of this reference `'1` + | let's call the lifetime of this reference `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr index b653b30bf6b76..21fdfcaef862e 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr @@ -1,11 +1,10 @@ error[E0623]: lifetime mismatch --> $DIR/underscore-lifetime-elison-mismatch.rs:1:49 | -LL | fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); } //~ ERROR lifetime mismatch +LL | fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); } | ------ ------ ^ ...but data from `y` flows into `x` here | | | these two types are declared with different lifetimes... error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/underscore-lifetime/underscore-outlives-bounds.stderr b/src/test/ui/underscore-lifetime/underscore-outlives-bounds.stderr index e4ff653f3ad42..6fa74d4e31034 100644 --- a/src/test/ui/underscore-lifetime/underscore-outlives-bounds.stderr +++ b/src/test/ui/underscore-lifetime/underscore-outlives-bounds.stderr @@ -1,9 +1,8 @@ error[E0637]: `'_` cannot be used here --> $DIR/underscore-outlives-bounds.rs:7:10 | -LL | impl<'b: '_> Foo<'b> for i32 {} //~ ERROR `'_` cannot be used here +LL | impl<'b: '_> Foo<'b> for i32 {} | ^^ `'_` is a reserved lifetime name error: aborting due to previous error -For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2015.stderr b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2015.stderr index fe726cb49c737..eec8e4b846886 100644 --- a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2015.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2015.stderr @@ -6,4 +6,3 @@ LL | T: WithType<&u32> error: aborting due to previous error -For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2018.stderr b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2018.stderr index fe726cb49c737..eec8e4b846886 100644 --- a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2018.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2018.stderr @@ -6,4 +6,3 @@ LL | T: WithType<&u32> error: aborting due to previous error -For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2015.stderr b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2015.stderr index 95939fd6b7e03..d2c3e352045b6 100644 --- a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2015.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2015.stderr @@ -6,4 +6,3 @@ LL | T: WithRegion<'_> error: aborting due to previous error -For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2018.stderr b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2018.stderr index 95939fd6b7e03..d2c3e352045b6 100644 --- a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2018.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2018.stderr @@ -6,4 +6,3 @@ LL | T: WithRegion<'_> error: aborting due to previous error -For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2015.stderr b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2015.stderr index fbd14de21078b..586b2b6aeaf28 100644 --- a/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2015.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2015.stderr @@ -6,4 +6,3 @@ LL | T: WithType<&u32> error: aborting due to previous error -For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2018.stderr b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2018.stderr index fbd14de21078b..586b2b6aeaf28 100644 --- a/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2018.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2018.stderr @@ -6,4 +6,3 @@ LL | T: WithType<&u32> error: aborting due to previous error -For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2015.stderr b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2015.stderr index 92caff0dcde99..faabf57a7df40 100644 --- a/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2015.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2015.stderr @@ -6,4 +6,3 @@ LL | T: WithRegion<'_> error: aborting due to previous error -For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2018.stderr b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2018.stderr index 92caff0dcde99..faabf57a7df40 100644 --- a/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2018.stderr +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2018.stderr @@ -6,4 +6,3 @@ LL | T: WithRegion<'_> error: aborting due to previous error -For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clauses.stderr b/src/test/ui/underscore-lifetime/where-clauses.stderr index 57fe2456f4cc5..8674a925c110d 100644 --- a/src/test/ui/underscore-lifetime/where-clauses.stderr +++ b/src/test/ui/underscore-lifetime/where-clauses.stderr @@ -1,15 +1,14 @@ error[E0637]: `'_` cannot be used here --> $DIR/where-clauses.rs:3:10 | -LL | impl<'b: '_> Foo<'b> for i32 {} //~ ERROR `'_` cannot be used here +LL | impl<'b: '_> Foo<'b> for i32 {} | ^^ `'_` is a reserved lifetime name error[E0637]: `'_` cannot be used here --> $DIR/where-clauses.rs:5:9 | -LL | impl Foo<'static> for Vec {} //~ ERROR `'_` cannot be used here +LL | impl Foo<'static> for Vec {} | ^^ `'_` is a reserved lifetime name error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/unevaluated_fixed_size_array_len.stderr b/src/test/ui/unevaluated_fixed_size_array_len.stderr index 200cf2a994d82..be6ed8d56232e 100644 --- a/src/test/ui/unevaluated_fixed_size_array_len.stderr +++ b/src/test/ui/unevaluated_fixed_size_array_len.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `[(); 0]: Foo` is not satisfied --> $DIR/unevaluated_fixed_size_array_len.rs:12:5 | -LL | <[(); 0] as Foo>::foo() //~ ERROR E0277 +LL | <[(); 0] as Foo>::foo() | ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `[(); 0]` | = help: the following implementations were found: diff --git a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr b/src/test/ui/uninhabited/uninhabited-enum-cast.stderr index 36dab0c43eb76..a39af7832f8c9 100644 --- a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr +++ b/src/test/ui/uninhabited/uninhabited-enum-cast.stderr @@ -1,7 +1,7 @@ error[E0605]: non-primitive cast: `E` as `isize` --> $DIR/uninhabited-enum-cast.rs:4:20 | -LL | println!("{}", (e as isize).to_string()); //~ ERROR non-primitive cast +LL | println!("{}", (e as isize).to_string()); | ^^^^^^^^^^^^ | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.rs b/src/test/ui/uninhabited/uninhabited-irrefutable.rs index c32d3a4a0a291..48cd92719b49a 100644 --- a/src/test/ui/uninhabited/uninhabited-irrefutable.rs +++ b/src/test/ui/uninhabited/uninhabited-irrefutable.rs @@ -26,4 +26,3 @@ fn main() { let x: Foo = Foo::D(123); let Foo::D(_y) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered } - diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr index 63819bf949bd3..45976f8ac56ad 100644 --- a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr +++ b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr @@ -1,8 +1,16 @@ error[E0005]: refutable pattern in local binding: `A(_)` not covered --> $DIR/uninhabited-irrefutable.rs:27:9 | -LL | let Foo::D(_y) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered - | ^^^^^^^^^^ pattern `A(_)` not covered +LL | / enum Foo { +LL | | A(foo::SecretlyEmpty), +LL | | B(foo::NotSoSecretlyEmpty), +LL | | C(NotSoSecretlyEmpty), +LL | | D(u32), +LL | | } + | |_- `Foo` defined here +... +LL | let Foo::D(_y) = x; + | ^^^^^^^^^^ pattern `A(_)` not covered error: aborting due to previous error diff --git a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr index b88dcc9aea435..de7a963577085 100644 --- a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr +++ b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr @@ -1,56 +1,50 @@ error[E0004]: non-exhaustive patterns: `Err(_)` not covered --> $DIR/uninhabited-matches-feature-gated.rs:5:19 | -LL | let _ = match x { //~ ERROR non-exhaustive +LL | let _ = match x { | ^ pattern `Err(_)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: type `&Void` is non-empty --> $DIR/uninhabited-matches-feature-gated.rs:10:19 | -LL | let _ = match x {}; //~ ERROR non-exhaustive +LL | let _ = match x {}; | ^ | -help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - --> $DIR/uninhabited-matches-feature-gated.rs:10:19 - | -LL | let _ = match x {}; //~ ERROR non-exhaustive - | ^ + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty --> $DIR/uninhabited-matches-feature-gated.rs:13:19 | -LL | let _ = match x {}; //~ ERROR non-exhaustive +LL | let _ = match x {}; | ^ | -help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - --> $DIR/uninhabited-matches-feature-gated.rs:13:19 - | -LL | let _ = match x {}; //~ ERROR non-exhaustive - | ^ + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty --> $DIR/uninhabited-matches-feature-gated.rs:16:19 | -LL | let _ = match x {}; //~ ERROR non-exhaustive +LL | let _ = match x {}; | ^ | -help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - --> $DIR/uninhabited-matches-feature-gated.rs:16:19 - | -LL | let _ = match x {}; //~ ERROR non-exhaustive - | ^ + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `&[_]` not covered --> $DIR/uninhabited-matches-feature-gated.rs:19:19 | -LL | let _ = match x { //~ ERROR non-exhaustive +LL | let _ = match x { | ^ pattern `&[_]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `Err(_)` not covered --> $DIR/uninhabited-matches-feature-gated.rs:27:19 | -LL | let _ = match x { //~ ERROR non-exhaustive +LL | let _ = match x { | ^ pattern `Err(_)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0005]: refutable pattern in local binding: `Err(_)` not covered --> $DIR/uninhabited-matches-feature-gated.rs:32:9 @@ -60,5 +54,5 @@ LL | let Ok(x) = x; error: aborting due to 7 previous errors -Some errors occurred: E0004, E0005. +Some errors have detailed explanations: E0004, E0005. For more information about an error, try `rustc --explain E0004`. diff --git a/src/test/ui/uninhabited/uninhabited-patterns.rs b/src/test/ui/uninhabited/uninhabited-patterns.rs index 609ed3d75bafa..1bf01184a08e7 100644 --- a/src/test/ui/uninhabited/uninhabited-patterns.rs +++ b/src/test/ui/uninhabited/uninhabited-patterns.rs @@ -45,4 +45,3 @@ fn main() { //~^ ERROR unreachable pattern } } - diff --git a/src/test/ui/uninhabited/uninhabited-patterns.stderr b/src/test/ui/uninhabited/uninhabited-patterns.stderr index eaae024cbf915..3e5329cfb3011 100644 --- a/src/test/ui/uninhabited/uninhabited-patterns.stderr +++ b/src/test/ui/uninhabited/uninhabited-patterns.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/uninhabited-patterns.rs:27:9 | -LL | &[..] => (), //~ ERROR unreachable pattern +LL | &[..] => (), | ^^^^^ | note: lint level defined here @@ -13,19 +13,19 @@ LL | #![deny(unreachable_patterns)] error: unreachable pattern --> $DIR/uninhabited-patterns.rs:32:9 | -LL | Ok(box _) => (), //~ ERROR unreachable pattern +LL | Ok(box _) => (), | ^^^^^^^^^ error: unreachable pattern --> $DIR/uninhabited-patterns.rs:34:9 | -LL | Err(&[..]) => (), //~ ERROR unreachable pattern +LL | Err(&[..]) => (), | ^^^^^^^^^^ error: unreachable pattern --> $DIR/uninhabited-patterns.rs:41:9 | -LL | Err(Ok(_y)) => (), //~ ERROR unreachable pattern +LL | Err(Ok(_y)) => (), | ^^^^^^^^^^^ error: unreachable pattern diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.nll.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.nll.stderr deleted file mode 100644 index 29d161fe150e7..0000000000000 --- a/src/test/ui/union/union-borrow-move-parent-sibling.nll.stderr +++ /dev/null @@ -1,70 +0,0 @@ -error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`) - --> $DIR/union-borrow-move-parent-sibling.rs:15:13 - | -LL | let a = &mut u.x.0; - | ---------- mutable borrow occurs here (via `u.x.0`) -LL | let b = &u.y; //~ ERROR cannot borrow `u.y` - | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0` -- occurs here -LL | use_borrow(a); - | - mutable borrow later used here - | - = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0` - -error[E0382]: use of moved value: `u` - --> $DIR/union-borrow-move-parent-sibling.rs:22:13 - | -LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; - | - move occurs because `u` has type `U`, which does not implement the `Copy` trait -LL | let a = u.x.0; - | ----- value moved here -LL | let b = u.y; //~ ERROR use of moved value: `u.y` - | ^^^ value used here after move - -error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`) - --> $DIR/union-borrow-move-parent-sibling.rs:28:13 - | -LL | let a = &mut (u.x.0).0; - | -------------- mutable borrow occurs here (via `u.x.0.0`) -LL | let b = &u.y; //~ ERROR cannot borrow `u.y` - | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0.0` -- occurs here -LL | use_borrow(a); - | - mutable borrow later used here - | - = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0` - -error[E0382]: use of moved value: `u` - --> $DIR/union-borrow-move-parent-sibling.rs:35:13 - | -LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; - | - move occurs because `u` has type `U`, which does not implement the `Copy` trait -LL | let a = (u.x.0).0; - | --------- value moved here -LL | let b = u.y; //~ ERROR use of moved value: `u.y` - | ^^^ value used here after move - -error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `*u.y`) - --> $DIR/union-borrow-move-parent-sibling.rs:41:13 - | -LL | let a = &mut *u.y; - | --------- mutable borrow occurs here (via `*u.y`) -LL | let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`) - | ^^^^ immutable borrow of `u.x` -- which overlaps with `*u.y` -- occurs here -LL | use_borrow(a); - | - mutable borrow later used here - | - = note: `u.x` is a field of the union `U`, so it overlaps the field `*u.y` - -error[E0382]: use of moved value: `u` - --> $DIR/union-borrow-move-parent-sibling.rs:48:13 - | -LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; - | - move occurs because `u` has type `U`, which does not implement the `Copy` trait -LL | let a = *u.y; - | ---- value moved here -LL | let b = u.x; //~ ERROR use of moved value: `u.x` - | ^^^ value used here after move - -error: aborting due to 6 previous errors - -Some errors occurred: E0382, E0502. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.rs b/src/test/ui/union/union-borrow-move-parent-sibling.rs index 43abbd374fcf1..1b6052f10ba4a 100644 --- a/src/test/ui/union/union-borrow-move-parent-sibling.rs +++ b/src/test/ui/union/union-borrow-move-parent-sibling.rs @@ -12,27 +12,27 @@ fn use_borrow(_: &T) {} unsafe fn parent_sibling_borrow() { let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; let a = &mut u.x.0; - let b = &u.y; //~ ERROR cannot borrow `u.y` + let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`) use_borrow(a); } unsafe fn parent_sibling_move() { let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; let a = u.x.0; - let b = u.y; //~ ERROR use of moved value: `u.y` + let b = u.y; //~ ERROR use of moved value: `u` } unsafe fn grandparent_sibling_borrow() { let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; let a = &mut (u.x.0).0; - let b = &u.y; //~ ERROR cannot borrow `u.y` + let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`) use_borrow(a); } unsafe fn grandparent_sibling_move() { let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; let a = (u.x.0).0; - let b = u.y; //~ ERROR use of moved value: `u.y` + let b = u.y; //~ ERROR use of moved value: `u` } unsafe fn deref_sibling_borrow() { @@ -45,7 +45,7 @@ unsafe fn deref_sibling_borrow() { unsafe fn deref_sibling_move() { let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; let a = *u.y; - let b = u.x; //~ ERROR use of moved value: `u.x` + let b = u.x; //~ ERROR use of moved value: `u` } diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.stderr index 9058707e50516..2f4c921ea08f9 100644 --- a/src/test/ui/union/union-borrow-move-parent-sibling.stderr +++ b/src/test/ui/union/union-borrow-move-parent-sibling.stderr @@ -1,67 +1,70 @@ -error[E0502]: cannot borrow `u.y` as immutable because `u.x.0` is also borrowed as mutable - --> $DIR/union-borrow-move-parent-sibling.rs:15:14 +error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`) + --> $DIR/union-borrow-move-parent-sibling.rs:15:13 | LL | let a = &mut u.x.0; - | ----- mutable borrow occurs here -LL | let b = &u.y; //~ ERROR cannot borrow `u.y` - | ^^^ immutable borrow occurs here + | ---------- mutable borrow occurs here (via `u.x.0`) +LL | let b = &u.y; + | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0` -- occurs here LL | use_borrow(a); -LL | } - | - mutable borrow ends here + | - mutable borrow later used here + | + = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0` -error[E0382]: use of moved value: `u.y` - --> $DIR/union-borrow-move-parent-sibling.rs:22:9 +error[E0382]: use of moved value: `u` + --> $DIR/union-borrow-move-parent-sibling.rs:22:13 | +LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; + | - move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = u.x.0; - | - value moved here -LL | let b = u.y; //~ ERROR use of moved value: `u.y` - | ^ value used here after move - | - = note: move occurs because `u.y` has type `[type error]`, which does not implement the `Copy` trait + | ----- value moved here +LL | let b = u.y; + | ^^^ value used here after move -error[E0502]: cannot borrow `u.y` as immutable because `u.x.0.0` is also borrowed as mutable - --> $DIR/union-borrow-move-parent-sibling.rs:28:14 +error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`) + --> $DIR/union-borrow-move-parent-sibling.rs:28:13 | LL | let a = &mut (u.x.0).0; - | --------- mutable borrow occurs here -LL | let b = &u.y; //~ ERROR cannot borrow `u.y` - | ^^^ immutable borrow occurs here + | -------------- mutable borrow occurs here (via `u.x.0.0`) +LL | let b = &u.y; + | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0.0` -- occurs here LL | use_borrow(a); -LL | } - | - mutable borrow ends here + | - mutable borrow later used here + | + = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0` -error[E0382]: use of moved value: `u.y` - --> $DIR/union-borrow-move-parent-sibling.rs:35:9 +error[E0382]: use of moved value: `u` + --> $DIR/union-borrow-move-parent-sibling.rs:35:13 | +LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; + | - move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = (u.x.0).0; - | - value moved here -LL | let b = u.y; //~ ERROR use of moved value: `u.y` - | ^ value used here after move - | - = note: move occurs because `u.y` has type `[type error]`, which does not implement the `Copy` trait + | --------- value moved here +LL | let b = u.y; + | ^^^ value used here after move -error[E0502]: cannot borrow `u` (via `u.x`) as immutable because `u` is also borrowed as mutable (via `*u.y`) - --> $DIR/union-borrow-move-parent-sibling.rs:41:14 +error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `*u.y`) + --> $DIR/union-borrow-move-parent-sibling.rs:41:13 | LL | let a = &mut *u.y; - | ---- mutable borrow occurs here (via `*u.y`) -LL | let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`) - | ^^^ immutable borrow of `u.x` -- which overlaps with `*u.y` -- occurs here + | --------- mutable borrow occurs here (via `*u.y`) +LL | let b = &u.x; + | ^^^^ immutable borrow of `u.x` -- which overlaps with `*u.y` -- occurs here LL | use_borrow(a); -LL | } - | - mutable borrow ends here + | - mutable borrow later used here + | + = note: `u.x` is a field of the union `U`, so it overlaps the field `*u.y` -error[E0382]: use of moved value: `u.x` - --> $DIR/union-borrow-move-parent-sibling.rs:48:9 +error[E0382]: use of moved value: `u` + --> $DIR/union-borrow-move-parent-sibling.rs:48:13 | +LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; + | - move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = *u.y; - | - value moved here -LL | let b = u.x; //~ ERROR use of moved value: `u.x` - | ^ value used here after move - | - = note: move occurs because `u.x` has type `[type error]`, which does not implement the `Copy` trait + | ---- value moved here +LL | let b = u.x; + | ^^^ value used here after move error: aborting due to 6 previous errors -Some errors occurred: E0382, E0502. +Some errors have detailed explanations: E0382, E0502. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/union/union-const-pat.stderr b/src/test/ui/union/union-const-pat.stderr index 5106721f310ec..dc87f4de5219f 100644 --- a/src/test/ui/union/union-const-pat.stderr +++ b/src/test/ui/union/union-const-pat.stderr @@ -1,7 +1,7 @@ error: cannot use unions in constant patterns --> $DIR/union-const-pat.rs:10:9 | -LL | C => {} //~ ERROR cannot use unions in constant patterns +LL | C => {} | ^ error: aborting due to previous error diff --git a/src/test/ui/union/union-copy.stderr b/src/test/ui/union/union-copy.stderr index b3991b5ba6a59..a875ff660f979 100644 --- a/src/test/ui/union/union-copy.stderr +++ b/src/test/ui/union/union-copy.stderr @@ -4,7 +4,7 @@ error[E0204]: the trait `Copy` may not be implemented for this type LL | a: String | --------- this field does not implement `Copy` ... -LL | impl Copy for W {} //~ ERROR the trait `Copy` may not be implemented for this type +LL | impl Copy for W {} | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr index 9580a9710e1f9..37a0093784048 100644 --- a/src/test/ui/union/union-derive-clone.stderr +++ b/src/test/ui/union/union-derive-clone.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `U1: std::marker::Copy` is not satisfied --> $DIR/union-derive-clone.rs:3:10 | -LL | #[derive(Clone)] //~ ERROR the trait bound `U1: std::marker::Copy` is not satisfied +LL | #[derive(Clone)] | ^^^^^ the trait `std::marker::Copy` is not implemented for `U1` | = note: required by `std::clone::AssertParamIsCopy` @@ -12,7 +12,7 @@ error[E0599]: no method named `clone` found for type `U4` in the cu LL | union U4 { | ----------- method `clone` not found for this ... -LL | let w = u.clone(); //~ ERROR no method named `clone` found for type `U4` +LL | let w = u.clone(); | ^^^^^ | = note: the method `clone` exists but the following trait bounds were not satisfied: @@ -23,5 +23,5 @@ LL | let w = u.clone(); //~ ERROR no method named `clone` found for type `U4 error: aborting due to 2 previous errors -Some errors occurred: E0277, E0599. +Some errors have detailed explanations: E0277, E0599. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/union/union-derive-eq.stderr b/src/test/ui/union/union-derive-eq.stderr index d93dcd64efc02..f63ab1704c497 100644 --- a/src/test/ui/union/union-derive-eq.stderr +++ b/src/test/ui/union/union-derive-eq.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `PartialEqNotEq: std::cmp::Eq` is not satisfied --> $DIR/union-derive-eq.rs:15:5 | -LL | a: PartialEqNotEq, //~ ERROR the trait bound `PartialEqNotEq: std::cmp::Eq` is not satisfied +LL | a: PartialEqNotEq, | ^^^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `PartialEqNotEq` | = note: required by `std::cmp::AssertParamIsEq` diff --git a/src/test/ui/union/union-derive.stderr b/src/test/ui/union/union-derive.stderr index 0ec873553f307..919c6d5ceda65 100644 --- a/src/test/ui/union/union-derive.stderr +++ b/src/test/ui/union/union-derive.stderr @@ -1,37 +1,37 @@ error: this trait cannot be derived for unions --> $DIR/union-derive.rs:9:5 | -LL | Debug, //~ ERROR this trait cannot be derived for unions +LL | Debug, | ^^^^^ error: this trait cannot be derived for unions --> $DIR/union-derive.rs:8:5 | -LL | Default, //~ ERROR this trait cannot be derived for unions +LL | Default, | ^^^^^^^ error: this trait cannot be derived for unions --> $DIR/union-derive.rs:7:5 | -LL | Hash, //~ ERROR this trait cannot be derived for unions +LL | Hash, | ^^^^ error: this trait cannot be derived for unions --> $DIR/union-derive.rs:6:5 | -LL | Ord, //~ ERROR this trait cannot be derived for unions +LL | Ord, | ^^^ error: this trait cannot be derived for unions --> $DIR/union-derive.rs:5:5 | -LL | PartialOrd, //~ ERROR this trait cannot be derived for unions +LL | PartialOrd, | ^^^^^^^^^^ error: this trait cannot be derived for unions --> $DIR/union-derive.rs:4:5 | -LL | PartialEq, //~ ERROR this trait cannot be derived for unions +LL | PartialEq, | ^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/union/union-empty.stderr b/src/test/ui/union/union-empty.stderr index 71bba8fda2eb1..a80b27e6eb563 100644 --- a/src/test/ui/union/union-empty.stderr +++ b/src/test/ui/union/union-empty.stderr @@ -1,7 +1,7 @@ error: unions cannot have zero fields --> $DIR/union-empty.rs:1:1 | -LL | union U {} //~ ERROR unions cannot have zero fields +LL | union U {} | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/union/union-fields-1.stderr b/src/test/ui/union/union-fields-1.stderr index 3f165db4763e6..f848db726f9ef 100644 --- a/src/test/ui/union/union-fields-1.stderr +++ b/src/test/ui/union/union-fields-1.stderr @@ -1,7 +1,7 @@ error: field is never used: `c` --> $DIR/union-fields-1.rs:6:5 | -LL | c: u8, //~ ERROR field is never used +LL | c: u8, | ^^^^^ | note: lint level defined here @@ -13,19 +13,19 @@ LL | #![deny(dead_code)] error: field is never used: `a` --> $DIR/union-fields-1.rs:9:5 | -LL | a: u8, //~ ERROR field is never used +LL | a: u8, | ^^^^^ error: field is never used: `a` --> $DIR/union-fields-1.rs:13:20 | -LL | union NoDropLike { a: u8 } //~ ERROR field is never used +LL | union NoDropLike { a: u8 } | ^^^^^ error: field is never used: `c` --> $DIR/union-fields-1.rs:18:5 | -LL | c: u8, //~ ERROR field is never used +LL | c: u8, | ^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/union/union-fields-2.stderr b/src/test/ui/union/union-fields-2.stderr index 959554f6d220c..68cb66d89d218 100644 --- a/src/test/ui/union/union-fields-2.stderr +++ b/src/test/ui/union/union-fields-2.stderr @@ -1,19 +1,19 @@ error: union expressions should have exactly one field --> $DIR/union-fields-2.rs:7:13 | -LL | let u = U {}; //~ ERROR union expressions should have exactly one field +LL | let u = U {}; | ^ error: union expressions should have exactly one field --> $DIR/union-fields-2.rs:9:13 | -LL | let u = U { a: 0, b: 1 }; //~ ERROR union expressions should have exactly one field +LL | let u = U { a: 0, b: 1 }; | ^ error[E0560]: union `U` has no field named `c` --> $DIR/union-fields-2.rs:10:29 | -LL | let u = U { a: 0, b: 1, c: 2 }; //~ ERROR union expressions should have exactly one field +LL | let u = U { a: 0, b: 1, c: 2 }; | ^ `U` does not have this field | = note: available fields are: `a`, `b` @@ -21,64 +21,64 @@ LL | let u = U { a: 0, b: 1, c: 2 }; //~ ERROR union expressions should have error: union expressions should have exactly one field --> $DIR/union-fields-2.rs:10:13 | -LL | let u = U { a: 0, b: 1, c: 2 }; //~ ERROR union expressions should have exactly one field +LL | let u = U { a: 0, b: 1, c: 2 }; | ^ error: union expressions should have exactly one field --> $DIR/union-fields-2.rs:12:13 | -LL | let u = U { ..u }; //~ ERROR union expressions should have exactly one field +LL | let u = U { ..u }; | ^ error[E0436]: functional record update syntax requires a struct --> $DIR/union-fields-2.rs:12:19 | -LL | let u = U { ..u }; //~ ERROR union expressions should have exactly one field +LL | let u = U { ..u }; | ^ error: union patterns should have exactly one field --> $DIR/union-fields-2.rs:15:9 | -LL | let U {} = u; //~ ERROR union patterns should have exactly one field +LL | let U {} = u; | ^^^^ error: union patterns should have exactly one field --> $DIR/union-fields-2.rs:17:9 | -LL | let U { a, b } = u; //~ ERROR union patterns should have exactly one field +LL | let U { a, b } = u; | ^^^^^^^^^^ error[E0026]: union `U` does not have a field named `c` --> $DIR/union-fields-2.rs:18:19 | -LL | let U { a, b, c } = u; //~ ERROR union patterns should have exactly one field +LL | let U { a, b, c } = u; | ^ union `U` does not have this field error: union patterns should have exactly one field --> $DIR/union-fields-2.rs:18:9 | -LL | let U { a, b, c } = u; //~ ERROR union patterns should have exactly one field +LL | let U { a, b, c } = u; | ^^^^^^^^^^^^^ error: union patterns should have exactly one field --> $DIR/union-fields-2.rs:20:9 | -LL | let U { .. } = u; //~ ERROR union patterns should have exactly one field +LL | let U { .. } = u; | ^^^^^^^^ error: `..` cannot be used in union patterns --> $DIR/union-fields-2.rs:20:9 | -LL | let U { .. } = u; //~ ERROR union patterns should have exactly one field +LL | let U { .. } = u; | ^^^^^^^^ error: `..` cannot be used in union patterns --> $DIR/union-fields-2.rs:22:9 | -LL | let U { a, .. } = u; //~ ERROR `..` cannot be used in union patterns +LL | let U { a, .. } = u; | ^^^^^^^^^^^ error: aborting due to 13 previous errors -Some errors occurred: E0026, E0436, E0560. +Some errors have detailed explanations: E0026, E0436, E0560. For more information about an error, try `rustc --explain E0026`. diff --git a/src/test/ui/union/union-lint-dead-code.stderr b/src/test/ui/union/union-lint-dead-code.stderr index 6551523c54df5..79c38a4681445 100644 --- a/src/test/ui/union/union-lint-dead-code.stderr +++ b/src/test/ui/union/union-lint-dead-code.stderr @@ -1,7 +1,7 @@ error: field is never used: `b` --> $DIR/union-lint-dead-code.rs:5:5 | -LL | b: bool, //~ ERROR: field is never used +LL | b: bool, | ^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/union/union-nonrepresentable.stderr b/src/test/ui/union/union-nonrepresentable.stderr index 1a7603a46374b..746c1033ea348 100644 --- a/src/test/ui/union/union-nonrepresentable.stderr +++ b/src/test/ui/union/union-nonrepresentable.stderr @@ -1,7 +1,7 @@ error[E0072]: recursive type `U` has infinite size --> $DIR/union-nonrepresentable.rs:3:1 | -LL | union U { //~ ERROR recursive type `U` has infinite size +LL | union U { | ^^^^^^^ recursive type has infinite size LL | a: u8, LL | b: U, diff --git a/src/test/ui/union/union-repr-c.stderr b/src/test/ui/union/union-repr-c.stderr index bac09c34b8b13..c60817a849a3b 100644 --- a/src/test/ui/union/union-repr-c.stderr +++ b/src/test/ui/union/union-repr-c.stderr @@ -1,7 +1,7 @@ error: `extern` block uses type `W` which is not FFI-safe: this union has unspecified layout --> $DIR/union-repr-c.rs:15:22 | -LL | static FOREIGN2: W; //~ ERROR union has unspecified layout +LL | static FOREIGN2: W; | ^ | note: lint level defined here @@ -9,7 +9,7 @@ note: lint level defined here | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ - = help: consider adding a #[repr(C)] attribute to this union + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union note: type defined here --> $DIR/union-repr-c.rs:9:1 | diff --git a/src/test/ui/union/union-suggest-field.stderr b/src/test/ui/union/union-suggest-field.stderr index 8ea07360d0f22..5050e4a986499 100644 --- a/src/test/ui/union/union-suggest-field.stderr +++ b/src/test/ui/union/union-suggest-field.stderr @@ -7,16 +7,16 @@ LL | let u = U { principle: 0 }; error[E0609]: no field `principial` on type `U` --> $DIR/union-suggest-field.rs:14:15 | -LL | let w = u.principial; //~ ERROR no field `principial` on type `U` +LL | let w = u.principial; | ^^^^^^^^^^ help: a field with a similar name exists: `principal` error[E0615]: attempted to take value of method `calculate` on type `U` --> $DIR/union-suggest-field.rs:18:15 | -LL | let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U` +LL | let y = u.calculate; | ^^^^^^^^^ help: use parentheses to call the method: `calculate()` error: aborting due to 3 previous errors -Some errors occurred: E0560, E0609, E0615. +Some errors have detailed explanations: E0560, E0609, E0615. For more information about an error, try `rustc --explain E0560`. diff --git a/src/test/ui/union/union-unsafe.stderr b/src/test/ui/union/union-unsafe.stderr index 35051485f6ad0..ab62508fcf666 100644 --- a/src/test/ui/union/union-unsafe.stderr +++ b/src/test/ui/union/union-unsafe.stderr @@ -1,7 +1,7 @@ error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:21:5 | -LL | u3.a = T::default(); //~ ERROR assignment to non-`Copy` union field is unsafe +LL | u3.a = T::default(); | ^^^^ assignment to non-`Copy` union field | = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized @@ -9,7 +9,7 @@ LL | u3.a = T::default(); //~ ERROR assignment to non-`Copy` union field is error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:33:13 | -LL | let a = u1.a; //~ ERROR access to union field is unsafe +LL | let a = u1.a; | ^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior @@ -17,7 +17,7 @@ LL | let a = u1.a; //~ ERROR access to union field is unsafe error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:35:14 | -LL | let U1 { a } = u1; //~ ERROR access to union field is unsafe +LL | let U1 { a } = u1; | ^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior @@ -25,7 +25,7 @@ LL | let U1 { a } = u1; //~ ERROR access to union field is unsafe error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:36:20 | -LL | if let U1 { a: 12 } = u1 {} //~ ERROR access to union field is unsafe +LL | if let U1 { a: 12 } = u1 {} | ^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior @@ -33,7 +33,7 @@ LL | if let U1 { a: 12 } = u1 {} //~ ERROR access to union field is unsafe error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:40:5 | -LL | u2.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field is unsafe +LL | u2.a = String::from("new"); | ^^^^ assignment to non-`Copy` union field | = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized @@ -41,7 +41,7 @@ LL | u2.a = String::from("new"); //~ ERROR assignment to non-`Copy` union fi error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:44:5 | -LL | u3.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field is unsafe +LL | u3.a = String::from("new"); | ^^^^ assignment to non-`Copy` union field | = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized diff --git a/src/test/ui/union/union-with-drop-fields-lint.stderr b/src/test/ui/union/union-with-drop-fields-lint.stderr index d8f456f2aefbc..2f90f240d2e19 100644 --- a/src/test/ui/union/union-with-drop-fields-lint.stderr +++ b/src/test/ui/union/union-with-drop-fields-lint.stderr @@ -1,7 +1,7 @@ error: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union --> $DIR/union-with-drop-fields-lint.rs:10:5 | -LL | a: String, //~ ERROR union contains a field with possibly non-trivial drop code +LL | a: String, | ^^^^^^^^^ | note: lint level defined here @@ -13,13 +13,13 @@ LL | #![deny(unions_with_drop_fields)] error: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union --> $DIR/union-with-drop-fields-lint.rs:18:5 | -LL | a: S, //~ ERROR union contains a field with possibly non-trivial drop code +LL | a: S, | ^^^^ error: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union --> $DIR/union-with-drop-fields-lint.rs:23:5 | -LL | a: T, //~ ERROR union contains a field with possibly non-trivial drop code +LL | a: T, | ^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/unique-object-noncopyable.rs b/src/test/ui/unique-object-noncopyable.rs index 1c467a2421a2a..dd38a7190aa0e 100644 --- a/src/test/ui/unique-object-noncopyable.rs +++ b/src/test/ui/unique-object-noncopyable.rs @@ -20,6 +20,6 @@ impl Foo for Bar { fn main() { let x = box Bar { x: 10 }; - let y: Box = x as Box; + let y: Box = x as Box; let _z = y.clone(); //~ ERROR no method named `clone` found } diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr index 78b46027c95ee..407905f52e750 100644 --- a/src/test/ui/unique-object-noncopyable.stderr +++ b/src/test/ui/unique-object-noncopyable.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `clone` found for type `std::boxed::Box` in the current scope --> $DIR/unique-object-noncopyable.rs:24:16 | -LL | let _z = y.clone(); //~ ERROR no method named `clone` found +LL | let _z = y.clone(); | ^^^^^ | = note: the method `clone` exists but the following trait bounds were not satisfied: diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr index c7cabd172eb39..0f6ba90afacf4 100644 --- a/src/test/ui/unique-pinned-nocopy.stderr +++ b/src/test/ui/unique-pinned-nocopy.stderr @@ -1,7 +1,7 @@ error[E0599]: no method named `clone` found for type `std::boxed::Box` in the current scope --> $DIR/unique-pinned-nocopy.rs:12:16 | -LL | let _j = i.clone(); //~ ERROR no method named `clone` found +LL | let _j = i.clone(); | ^^^^^ | = note: the method `clone` exists but the following trait bounds were not satisfied: diff --git a/src/test/ui/unknown-lint-tool-name.stderr b/src/test/ui/unknown-lint-tool-name.stderr index e9d44e2e3bced..dd3070bbcb3d2 100644 --- a/src/test/ui/unknown-lint-tool-name.stderr +++ b/src/test/ui/unknown-lint-tool-name.stderr @@ -1,15 +1,14 @@ error[E0710]: an unknown tool name found in scoped lint: `foo::bar` --> $DIR/unknown-lint-tool-name.rs:1:9 | -LL | #![deny(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar` +LL | #![deny(foo::bar)] | ^^^ error[E0710]: an unknown tool name found in scoped lint: `foo::bar` --> $DIR/unknown-lint-tool-name.rs:3:9 | -LL | #[allow(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar` +LL | #[allow(foo::bar)] | ^^^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0710`. diff --git a/src/test/ui/unknown-tool-name.stderr b/src/test/ui/unknown-tool-name.stderr index 7bd2da285980c..7a6ed57bda6f3 100644 --- a/src/test/ui/unknown-tool-name.stderr +++ b/src/test/ui/unknown-tool-name.stderr @@ -1,7 +1,7 @@ error[E0433]: failed to resolve: use of undeclared type or module `foo` --> $DIR/unknown-tool-name.rs:1:3 | -LL | #[foo::bar] //~ ERROR failed to resolve: use of undeclared type or module `foo` +LL | #[foo::bar] | ^^^ use of undeclared type or module `foo` error: aborting due to previous error diff --git a/src/test/ui/unnecessary-extern-crate.rs b/src/test/ui/unnecessary-extern-crate.rs index e25b99bcb61dd..67eaaf4b6c21b 100644 --- a/src/test/ui/unnecessary-extern-crate.rs +++ b/src/test/ui/unnecessary-extern-crate.rs @@ -1,7 +1,7 @@ // edition:2018 #![deny(unused_extern_crates)] -#![feature(alloc, test, rustc_private, crate_visibility_modifier)] +#![feature(test, rustc_private, crate_visibility_modifier)] extern crate libc; //~^ ERROR unused extern crate diff --git a/src/test/ui/unop-move-semantics.nll.stderr b/src/test/ui/unop-move-semantics.nll.stderr deleted file mode 100644 index 58953d55b1fba..0000000000000 --- a/src/test/ui/unop-move-semantics.nll.stderr +++ /dev/null @@ -1,52 +0,0 @@ -error[E0382]: borrow of moved value: `x` - --> $DIR/unop-move-semantics.rs:8:5 - | -LL | fn move_then_borrow + Clone>(x: T) { - | - - move occurs because `x` has type `T`, which does not implement the `Copy` trait - | | - | consider adding a `Copy` constraint to this type argument -LL | !x; - | - value moved here -LL | -LL | x.clone(); //~ ERROR: use of moved value - | ^ value borrowed here after move - -error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/unop-move-semantics.rs:15:6 - | -LL | let m = &x; - | -- borrow of `x` occurs here -... -LL | !x; //~ ERROR: cannot move out of `x` because it is borrowed - | ^ move out of `x` occurs here -... -LL | use_mut(n); use_imm(m); - | - borrow later used here - -error[E0505]: cannot move out of `y` because it is borrowed - --> $DIR/unop-move-semantics.rs:17:6 - | -LL | let n = &mut y; - | ------ borrow of `y` occurs here -... -LL | !y; //~ ERROR: cannot move out of `y` because it is borrowed - | ^ move out of `y` occurs here -LL | use_mut(n); use_imm(m); - | - borrow later used here - -error[E0507]: cannot move out of borrowed content - --> $DIR/unop-move-semantics.rs:24:6 - | -LL | !*m; //~ ERROR: cannot move out of borrowed content - | ^^ cannot move out of borrowed content - -error[E0507]: cannot move out of borrowed content - --> $DIR/unop-move-semantics.rs:26:6 - | -LL | !*n; //~ ERROR: cannot move out of borrowed content - | ^^ cannot move out of borrowed content - -error: aborting due to 5 previous errors - -Some errors occurred: E0382, E0505, E0507. -For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/unop-move-semantics.rs b/src/test/ui/unop-move-semantics.rs index 24bd89d4c39ce..8168da8242fd4 100644 --- a/src/test/ui/unop-move-semantics.rs +++ b/src/test/ui/unop-move-semantics.rs @@ -5,7 +5,7 @@ use std::ops::Not; fn move_then_borrow + Clone>(x: T) { !x; - x.clone(); //~ ERROR: use of moved value + x.clone(); //~ ERROR: borrow of moved value } fn move_borrowed>(x: T, mut y: T) { @@ -21,9 +21,9 @@ fn illegal_dereference>(mut x: T, y: T) { let m = &mut x; let n = &y; - !*m; //~ ERROR: cannot move out of borrowed content + !*m; //~ ERROR: cannot move out of `*m` - !*n; //~ ERROR: cannot move out of borrowed content + !*n; //~ ERROR: cannot move out of `*n` use_imm(n); use_mut(m); } fn main() {} diff --git a/src/test/ui/unop-move-semantics.stderr b/src/test/ui/unop-move-semantics.stderr index 65d2967c61ee8..6aa3d0b09896b 100644 --- a/src/test/ui/unop-move-semantics.stderr +++ b/src/test/ui/unop-move-semantics.stderr @@ -1,45 +1,52 @@ -error[E0382]: use of moved value: `x` +error[E0382]: borrow of moved value: `x` --> $DIR/unop-move-semantics.rs:8:5 | +LL | fn move_then_borrow + Clone>(x: T) { + | - - move occurs because `x` has type `T`, which does not implement the `Copy` trait + | | + | consider adding a `Copy` constraint to this type argument LL | !x; | - value moved here LL | -LL | x.clone(); //~ ERROR: use of moved value - | ^ value used here after move - | - = note: move occurs because `x` has type `T`, which does not implement the `Copy` trait +LL | x.clone(); + | ^ value borrowed here after move error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/unop-move-semantics.rs:15:6 | LL | let m = &x; - | - borrow of `x` occurs here + | -- borrow of `x` occurs here ... -LL | !x; //~ ERROR: cannot move out of `x` because it is borrowed +LL | !x; | ^ move out of `x` occurs here +... +LL | use_mut(n); use_imm(m); + | - borrow later used here error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/unop-move-semantics.rs:17:6 | LL | let n = &mut y; - | - borrow of `y` occurs here + | ------ borrow of `y` occurs here ... -LL | !y; //~ ERROR: cannot move out of `y` because it is borrowed +LL | !y; | ^ move out of `y` occurs here +LL | use_mut(n); use_imm(m); + | - borrow later used here -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `*m` which is behind a mutable reference --> $DIR/unop-move-semantics.rs:24:6 | -LL | !*m; //~ ERROR: cannot move out of borrowed content - | ^^ cannot move out of borrowed content +LL | !*m; + | ^^ move occurs because `*m` has type `T`, which does not implement the `Copy` trait -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of `*n` which is behind a shared reference --> $DIR/unop-move-semantics.rs:26:6 | -LL | !*n; //~ ERROR: cannot move out of borrowed content - | ^^ cannot move out of borrowed content +LL | !*n; + | ^^ move occurs because `*n` has type `T`, which does not implement the `Copy` trait error: aborting due to 5 previous errors -Some errors occurred: E0382, E0505, E0507. +Some errors have detailed explanations: E0382, E0505, E0507. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/unop-neg-bool.stderr b/src/test/ui/unop-neg-bool.stderr index c13c1a15a7cde..182730137492b 100644 --- a/src/test/ui/unop-neg-bool.stderr +++ b/src/test/ui/unop-neg-bool.stderr @@ -1,7 +1,7 @@ error[E0600]: cannot apply unary operator `-` to type `bool` --> $DIR/unop-neg-bool.rs:2:5 | -LL | -true; //~ ERROR cannot apply unary operator `-` to type `bool` +LL | -true; | ^^^^^ cannot apply unary operator `-` | = note: an implementation of `std::ops::Neg` might be missing for `bool` diff --git a/src/test/ui/unreachable/unreachable-arm.rs b/src/test/ui/unreachable/unreachable-arm.rs index 9f1a5a39587b3..64c3896851669 100644 --- a/src/test/ui/unreachable/unreachable-arm.rs +++ b/src/test/ui/unreachable/unreachable-arm.rs @@ -12,4 +12,3 @@ fn main() { _ => { } } } - diff --git a/src/test/ui/unreachable/unreachable-arm.stderr b/src/test/ui/unreachable/unreachable-arm.stderr index 5b34482b59bb0..8e65745c7b099 100644 --- a/src/test/ui/unreachable/unreachable-arm.stderr +++ b/src/test/ui/unreachable/unreachable-arm.stderr @@ -1,7 +1,7 @@ error: unreachable pattern --> $DIR/unreachable-arm.rs:11:9 | -LL | Foo::A(_, 1) => { } //~ ERROR unreachable pattern +LL | Foo::A(_, 1) => { } | ^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/unreachable/unreachable-code.stderr b/src/test/ui/unreachable/unreachable-code.stderr index afb3629d5fda1..803bb966be8fc 100644 --- a/src/test/ui/unreachable/unreachable-code.stderr +++ b/src/test/ui/unreachable/unreachable-code.stderr @@ -1,7 +1,7 @@ error: unreachable statement --> $DIR/unreachable-code.rs:7:3 | -LL | let a = 3; //~ ERROR: unreachable statement +LL | let a = 3; | ^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/unreachable/unreachable-in-call.stderr b/src/test/ui/unreachable/unreachable-in-call.stderr index b78070d3fb129..f8dd54590f6ae 100644 --- a/src/test/ui/unreachable/unreachable-in-call.stderr +++ b/src/test/ui/unreachable/unreachable-in-call.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/unreachable-in-call.rs:14:10 | -LL | get_u8()); //~ ERROR unreachable expression +LL | get_u8()); | ^^^^^^^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unreachable_code)] error: unreachable expression --> $DIR/unreachable-in-call.rs:17:5 | -LL | / call( //~ ERROR unreachable expression +LL | / call( LL | | get_u8(), LL | | diverge()); | |__________________^ diff --git a/src/test/ui/unreachable/unreachable-loop-patterns.rs b/src/test/ui/unreachable/unreachable-loop-patterns.rs index 9794806375324..56ab1a270a75d 100644 --- a/src/test/ui/unreachable/unreachable-loop-patterns.rs +++ b/src/test/ui/unreachable/unreachable-loop-patterns.rs @@ -19,5 +19,5 @@ impl Iterator for Void { fn main() { for _ in unimplemented!() as Void {} //~^ ERROR unreachable pattern + //~^^ ERROR unreachable pattern } - diff --git a/src/test/ui/unreachable/unreachable-loop-patterns.stderr b/src/test/ui/unreachable/unreachable-loop-patterns.stderr index d2f255c3e104d..254d1178d142e 100644 --- a/src/test/ui/unreachable/unreachable-loop-patterns.stderr +++ b/src/test/ui/unreachable/unreachable-loop-patterns.stderr @@ -10,5 +10,11 @@ note: lint level defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: unreachable pattern + --> $DIR/unreachable-loop-patterns.rs:20:14 + | +LL | for _ in unimplemented!() as Void {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/unreachable/unreachable-try-pattern.rs b/src/test/ui/unreachable/unreachable-try-pattern.rs index 1c1e01ff0e916..6665c58e457f1 100644 --- a/src/test/ui/unreachable/unreachable-try-pattern.rs +++ b/src/test/ui/unreachable/unreachable-try-pattern.rs @@ -39,4 +39,3 @@ fn main() { let _ = qux(Ok(123)); let _ = vom(Ok(123)); } - diff --git a/src/test/ui/unreachable/unreachable-variant.stderr b/src/test/ui/unreachable/unreachable-variant.stderr index 60fdae5cbcee8..276c77f9b4249 100644 --- a/src/test/ui/unreachable/unreachable-variant.stderr +++ b/src/test/ui/unreachable/unreachable-variant.stderr @@ -1,7 +1,7 @@ error[E0603]: module `super_sekrit` is private --> $DIR/unreachable-variant.rs:6:21 | -LL | let _x = other::super_sekrit::sooper_sekrit::baz; //~ ERROR is private +LL | let _x = other::super_sekrit::sooper_sekrit::baz; | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/unreachable/unwarned-match-on-never.stderr b/src/test/ui/unreachable/unwarned-match-on-never.stderr index 8807e5f04e585..ccb70d7431145 100644 --- a/src/test/ui/unreachable/unwarned-match-on-never.stderr +++ b/src/test/ui/unreachable/unwarned-match-on-never.stderr @@ -1,7 +1,7 @@ error: unreachable expression --> $DIR/unwarned-match-on-never.rs:10:5 | -LL | match x {} //~ ERROR unreachable expression +LL | match x {} | ^^^^^^^^^^ | note: lint level defined here @@ -13,13 +13,13 @@ LL | #![deny(unreachable_code)] error: unreachable arm --> $DIR/unwarned-match-on-never.rs:15:15 | -LL | () => () //~ ERROR unreachable arm +LL | () => () | ^^ error: unreachable expression --> $DIR/unwarned-match-on-never.rs:21:5 | -LL | / match () { //~ ERROR unreachable expression +LL | / match () { LL | | () => (), LL | | } | |_____^ diff --git a/src/test/ui/unresolved/unresolved-extern-mod-suggestion.stderr b/src/test/ui/unresolved/unresolved-extern-mod-suggestion.stderr index e8679a3726d30..28333228a29ba 100644 --- a/src/test/ui/unresolved/unresolved-extern-mod-suggestion.stderr +++ b/src/test/ui/unresolved/unresolved-extern-mod-suggestion.stderr @@ -4,10 +4,7 @@ error[E0254]: the name `core` is defined multiple times LL | extern crate core; | ------------------ previous import of the extern crate `core` here LL | use core; - | ----^^^^- - | | | - | | `core` reimported here - | help: remove unnecessary import + | ^^^^ `core` reimported here | = note: `core` must be defined only once in the type namespace of this module diff --git a/src/test/ui/unresolved/unresolved-import-recovery.stderr b/src/test/ui/unresolved/unresolved-import-recovery.stderr index 0154d002efeec..5e371b70bfa50 100644 --- a/src/test/ui/unresolved/unresolved-import-recovery.stderr +++ b/src/test/ui/unresolved/unresolved-import-recovery.stderr @@ -1,7 +1,7 @@ error[E0432]: unresolved import `unresolved` --> $DIR/unresolved-import-recovery.rs:4:13 | -LL | pub use unresolved; //~ ERROR unresolved import `unresolved` +LL | pub use unresolved; | ^^^^^^^^^^ no `unresolved` in the root error: aborting due to previous error diff --git a/src/test/ui/unresolved/unresolved-import.rs b/src/test/ui/unresolved/unresolved-import.rs index be2a2c75485f6..4c7d4bb935331 100644 --- a/src/test/ui/unresolved/unresolved-import.rs +++ b/src/test/ui/unresolved/unresolved-import.rs @@ -1,16 +1,20 @@ -// ignore-tidy-linelength - use foo::bar; //~ ERROR unresolved import `foo` [E0432] //~^ maybe a missing `extern crate foo;`? use bar::Baz as x; //~ ERROR unresolved import `bar::Baz` [E0432] - //~^ no `Baz` in `bar`. Did you mean to use `Bar`? + //~| no `Baz` in `bar` + //~| HELP a similar name exists in the module + //~| SUGGESTION Bar use food::baz; //~ ERROR unresolved import `food::baz` - //~^ no `baz` in `food`. Did you mean to use `bag`? + //~| no `baz` in `food` + //~| HELP a similar name exists in the module + //~| SUGGESTION bag use food::{beens as Foo}; //~ ERROR unresolved import `food::beens` [E0432] - //~^ no `beens` in `food`. Did you mean to use `beans`? + //~| no `beens` in `food` + //~| HELP a similar name exists in the module + //~| SUGGESTION beans mod bar { pub struct Bar; @@ -32,7 +36,8 @@ mod m { } use MyEnum::*; //~ ERROR unresolved import `MyEnum` [E0432] - //~^ did you mean `self::MyEnum`? + //~| HELP a similar path exists + //~| SUGGESTION self::MyEnum } mod items { @@ -41,7 +46,8 @@ mod items { } use Enum::*; //~ ERROR unresolved import `Enum` [E0432] - //~^ did you mean `self::Enum`? + //~| HELP a similar path exists + //~| SUGGESTION self::Enum fn item() {} } diff --git a/src/test/ui/unresolved/unresolved-import.stderr b/src/test/ui/unresolved/unresolved-import.stderr index 0dc4b72208ac1..fb5c0760d1582 100644 --- a/src/test/ui/unresolved/unresolved-import.stderr +++ b/src/test/ui/unresolved/unresolved-import.stderr @@ -1,38 +1,47 @@ error[E0432]: unresolved import `foo` - --> $DIR/unresolved-import.rs:3:5 + --> $DIR/unresolved-import.rs:1:5 | -LL | use foo::bar; //~ ERROR unresolved import `foo` [E0432] +LL | use foo::bar; | ^^^ maybe a missing `extern crate foo;`? error[E0432]: unresolved import `bar::Baz` - --> $DIR/unresolved-import.rs:6:5 + --> $DIR/unresolved-import.rs:4:5 | -LL | use bar::Baz as x; //~ ERROR unresolved import `bar::Baz` [E0432] - | ^^^^^^^^^^^^^ no `Baz` in `bar`. Did you mean to use `Bar`? +LL | use bar::Baz as x; + | ^^^^^---^^^^^ + | | | + | | help: a similar name exists in the module: `Bar` + | no `Baz` in `bar` error[E0432]: unresolved import `food::baz` --> $DIR/unresolved-import.rs:9:5 | -LL | use food::baz; //~ ERROR unresolved import `food::baz` - | ^^^^^^^^^ no `baz` in `food`. Did you mean to use `bag`? +LL | use food::baz; + | ^^^^^^--- + | | | + | | help: a similar name exists in the module: `bag` + | no `baz` in `food` error[E0432]: unresolved import `food::beens` - --> $DIR/unresolved-import.rs:12:12 + --> $DIR/unresolved-import.rs:14:12 | -LL | use food::{beens as Foo}; //~ ERROR unresolved import `food::beens` [E0432] - | ^^^^^^^^^^^^ no `beens` in `food`. Did you mean to use `beans`? +LL | use food::{beens as Foo}; + | -----^^^^^^^ + | | + | no `beens` in `food` + | help: a similar name exists in the module: `beans` error[E0432]: unresolved import `MyEnum` - --> $DIR/unresolved-import.rs:34:9 + --> $DIR/unresolved-import.rs:38:9 | -LL | use MyEnum::*; //~ ERROR unresolved import `MyEnum` [E0432] - | ^^^^^^ did you mean `self::MyEnum`? +LL | use MyEnum::*; + | ^^^^^^ help: a similar path exists: `self::MyEnum` error[E0432]: unresolved import `Enum` - --> $DIR/unresolved-import.rs:43:9 + --> $DIR/unresolved-import.rs:48:9 | -LL | use Enum::*; //~ ERROR unresolved import `Enum` [E0432] - | ^^^^ did you mean `self::Enum`? +LL | use Enum::*; + | ^^^^ help: a similar path exists: `self::Enum` error: aborting due to 6 previous errors diff --git a/src/test/ui/unrestricted-attribute-tokens.rs b/src/test/ui/unrestricted-attribute-tokens.rs index 4798f7b396cd6..b07ab96bce13f 100644 --- a/src/test/ui/unrestricted-attribute-tokens.rs +++ b/src/test/ui/unrestricted-attribute-tokens.rs @@ -1,8 +1,8 @@ // compile-pass -#![feature(custom_attribute)] +#![feature(rustc_attrs)] -#[my_attr(a b c d)] -#[my_attr[a b c d]] -#[my_attr{a b c d}] +#[rustc_dummy(a b c d)] +#[rustc_dummy[a b c d]] +#[rustc_dummy{a b c d}] fn main() {} diff --git a/src/test/ui/unsafe/ranged_ints.stderr b/src/test/ui/unsafe/ranged_ints.stderr index f59a930b5a901..4e43df495c0d0 100644 --- a/src/test/ui/unsafe/ranged_ints.stderr +++ b/src/test/ui/unsafe/ranged_ints.stderr @@ -1,7 +1,7 @@ error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block --> $DIR/ranged_ints.rs:7:14 | -LL | let _x = NonZero(0); //~ ERROR initializing type with `rustc_layout_scalar_valid_range` attr +LL | let _x = NonZero(0); | ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr | = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior diff --git a/src/test/ui/unsafe/ranged_ints2.stderr b/src/test/ui/unsafe/ranged_ints2.stderr index ae63f47ed74a7..ee1d1f10e71b2 100644 --- a/src/test/ui/unsafe/ranged_ints2.stderr +++ b/src/test/ui/unsafe/ranged_ints2.stderr @@ -1,7 +1,7 @@ error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block --> $DIR/ranged_ints2.rs:8:13 | -LL | let y = &mut x.0; //~ ERROR mutation of layout constrained field is unsafe +LL | let y = &mut x.0; | ^^^^^^^^ mutation of layout constrained field | = note: mutating layout constrained fields cannot statically be checked for valid values diff --git a/src/test/ui/unsafe/ranged_ints2_const.stderr b/src/test/ui/unsafe/ranged_ints2_const.stderr index fb3841948f11f..6a47c5b14146b 100644 --- a/src/test/ui/unsafe/ranged_ints2_const.stderr +++ b/src/test/ui/unsafe/ranged_ints2_const.stderr @@ -1,28 +1,30 @@ -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/ranged_ints2_const.rs:11:9 | -LL | let y = &mut x.0; //~ ERROR references in const fn are unstable +LL | let y = &mut x.0; | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable (see issue #57563) +error[E0723]: mutable references in const fn are unstable --> $DIR/ranged_ints2_const.rs:18:9 | -LL | let y = unsafe { &mut x.0 }; //~ ERROR mutable references in const fn are unstable +LL | let y = unsafe { &mut x.0 }; | ^ | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block --> $DIR/ranged_ints2_const.rs:11:13 | -LL | let y = &mut x.0; //~ ERROR references in const fn are unstable +LL | let y = &mut x.0; | ^^^^^^^^ mutation of layout constrained field | = note: mutating layout constrained fields cannot statically be checked for valid values error: aborting due to 3 previous errors -Some errors occurred: E0133, E0723. +Some errors have detailed explanations: E0133, E0723. For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/ranged_ints3.stderr b/src/test/ui/unsafe/ranged_ints3.stderr index 311a058fdb07f..4d4c9167150ed 100644 --- a/src/test/ui/unsafe/ranged_ints3.stderr +++ b/src/test/ui/unsafe/ranged_ints3.stderr @@ -1,7 +1,7 @@ error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block --> $DIR/ranged_ints3.rs:10:13 | -LL | let y = &x.0; //~ ERROR borrow of layout constrained field with interior mutability +LL | let y = &x.0; | ^^^^ borrow of layout constrained field with interior mutability | = note: references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values diff --git a/src/test/ui/unsafe/ranged_ints3_const.stderr b/src/test/ui/unsafe/ranged_ints3_const.stderr index d83d75787d948..d2eb3bc536008 100644 --- a/src/test/ui/unsafe/ranged_ints3_const.stderr +++ b/src/test/ui/unsafe/ranged_ints3_const.stderr @@ -1,24 +1,24 @@ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead --> $DIR/ranged_ints3_const.rs:12:13 | -LL | let y = &x.0; //~ ERROR cannot borrow a constant which may contain interior mutability +LL | let y = &x.0; | ^^^^ error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead --> $DIR/ranged_ints3_const.rs:19:22 | -LL | let y = unsafe { &x.0 }; //~ ERROR cannot borrow a constant which may contain interior mut +LL | let y = unsafe { &x.0 }; | ^^^^ error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block --> $DIR/ranged_ints3_const.rs:12:13 | -LL | let y = &x.0; //~ ERROR cannot borrow a constant which may contain interior mutability +LL | let y = &x.0; | ^^^^ borrow of layout constrained field with interior mutability | = note: references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values error: aborting due to 3 previous errors -Some errors occurred: E0133, E0492. +Some errors have detailed explanations: E0133, E0492. For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/ranged_ints4.stderr b/src/test/ui/unsafe/ranged_ints4.stderr index c6468b643b41a..68c22589d3ff5 100644 --- a/src/test/ui/unsafe/ranged_ints4.stderr +++ b/src/test/ui/unsafe/ranged_ints4.stderr @@ -1,7 +1,7 @@ error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block --> $DIR/ranged_ints4.rs:8:5 | -LL | x.0 = 0; //~ ERROR mutation of layout constrained field is unsafe +LL | x.0 = 0; | ^^^^^^^ mutation of layout constrained field | = note: mutating layout constrained fields cannot statically be checked for valid values diff --git a/src/test/ui/unsafe/unsafe-around-compiler-generated-unsafe.stderr b/src/test/ui/unsafe/unsafe-around-compiler-generated-unsafe.stderr index 7751fe017b8e2..28b18d50fff19 100644 --- a/src/test/ui/unsafe/unsafe-around-compiler-generated-unsafe.stderr +++ b/src/test/ui/unsafe/unsafe-around-compiler-generated-unsafe.stderr @@ -1,7 +1,7 @@ error: unnecessary `unsafe` block --> $DIR/unsafe-around-compiler-generated-unsafe.rs:6:5 | -LL | unsafe { println!("foo"); } //~ ERROR unnecessary `unsafe` +LL | unsafe { println!("foo"); } | ^^^^^^ unnecessary `unsafe` block | note: lint level defined here diff --git a/src/test/ui/unsafe/unsafe-const-fn.rs b/src/test/ui/unsafe/unsafe-const-fn.rs index cadfdd064e39d..3b4becf17a76c 100644 --- a/src/test/ui/unsafe/unsafe-const-fn.rs +++ b/src/test/ui/unsafe/unsafe-const-fn.rs @@ -10,4 +10,3 @@ const VAL: u32 = dummy(0xFFFF); fn main() { assert_eq!(VAL, 0xFFFF0000); } - diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr index 1e000062cc3e8..8f621d6ed11ca 100644 --- a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr +++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr @@ -1,7 +1,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block --> $DIR/unsafe-fn-assign-deref-ptr.rs:6:5 | -LL | *p = 0; //~ ERROR dereference of raw pointer is unsafe +LL | *p = 0; | ^^^^^^ dereference of raw pointer | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior diff --git a/src/test/ui/unsafe/unsafe-fn-autoderef.stderr b/src/test/ui/unsafe/unsafe-fn-autoderef.stderr index ded64ba69e891..20a88c356108d 100644 --- a/src/test/ui/unsafe/unsafe-fn-autoderef.stderr +++ b/src/test/ui/unsafe/unsafe-fn-autoderef.stderr @@ -1,7 +1,7 @@ error[E0609]: no field `f` on type `*const Rec` --> $DIR/unsafe-fn-autoderef.rs:19:14 | -LL | return p.f; //~ ERROR no field `f` on type `*const Rec` +LL | return p.f; | --^ | | | help: `p` is a raw pointer; try dereferencing it: `(*p).f` diff --git a/src/test/ui/unsafe/unsafe-fn-called-from-safe.stderr b/src/test/ui/unsafe/unsafe-fn-called-from-safe.stderr index 4ad7c6e5c75d1..80d2c6ced24c8 100644 --- a/src/test/ui/unsafe/unsafe-fn-called-from-safe.stderr +++ b/src/test/ui/unsafe/unsafe-fn-called-from-safe.stderr @@ -1,7 +1,7 @@ error[E0133]: call to unsafe function is unsafe and requires unsafe function or block --> $DIR/unsafe-fn-called-from-safe.rs:4:5 | -LL | f(); //~ ERROR call to unsafe function is unsafe +LL | f(); | ^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr b/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr index d48a7681cadc5..e8e82dec0b0bb 100644 --- a/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr +++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr @@ -1,7 +1,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block --> $DIR/unsafe-fn-deref-ptr.rs:2:12 | -LL | return *p; //~ ERROR dereference of raw pointer is unsafe +LL | return *p; | ^^ dereference of raw pointer | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior diff --git a/src/test/ui/unsafe/unsafe-fn-used-as-value.stderr b/src/test/ui/unsafe/unsafe-fn-used-as-value.stderr index f68e849341b9b..a7b73ec53429b 100644 --- a/src/test/ui/unsafe/unsafe-fn-used-as-value.stderr +++ b/src/test/ui/unsafe/unsafe-fn-used-as-value.stderr @@ -1,7 +1,7 @@ error[E0133]: call to unsafe function is unsafe and requires unsafe function or block --> $DIR/unsafe-fn-used-as-value.rs:5:5 | -LL | x(); //~ ERROR call to unsafe function is unsafe +LL | x(); | ^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior diff --git a/src/test/ui/unsafe/unsafe-subtyping.stderr b/src/test/ui/unsafe/unsafe-subtyping.stderr index 3db0bcba81bf3..cac5ee07089e8 100644 --- a/src/test/ui/unsafe/unsafe-subtyping.stderr +++ b/src/test/ui/unsafe/unsafe-subtyping.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | fn foo(x: Option) -> Option { | ---------------------- expected `std::option::Option` because of return type -LL | x //~ ERROR mismatched types +LL | x | ^ expected unsafe fn, found normal fn | = note: expected type `std::option::Option` diff --git a/src/test/ui/unsized-locals/borrow-after-move.nll.stderr b/src/test/ui/unsized-locals/borrow-after-move.nll.stderr deleted file mode 100644 index 010e182674b75..0000000000000 --- a/src/test/ui/unsized-locals/borrow-after-move.nll.stderr +++ /dev/null @@ -1,57 +0,0 @@ -error[E0382]: borrow of moved value: `x` - --> $DIR/borrow-after-move.rs:20:24 - | -LL | let y = *x; - | -- value moved here -LL | drop_unsized(y); -LL | println!("{}", &x); - | ^^ value borrowed here after partial move - | - = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait - -error[E0382]: borrow of moved value: `y` - --> $DIR/borrow-after-move.rs:22:24 - | -LL | let y = *x; - | - move occurs because `y` has type `str`, which does not implement the `Copy` trait -LL | drop_unsized(y); - | - value moved here -... -LL | println!("{}", &y); - | ^^ value borrowed here after move - -error[E0382]: borrow of moved value: `x` - --> $DIR/borrow-after-move.rs:30:24 - | -LL | let y = *x; - | -- value moved here -LL | y.foo(); -LL | println!("{}", &x); - | ^^ value borrowed here after partial move - | - = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait - -error[E0382]: borrow of moved value: `y` - --> $DIR/borrow-after-move.rs:32:24 - | -LL | let y = *x; - | - move occurs because `y` has type `str`, which does not implement the `Copy` trait -LL | y.foo(); - | - value moved here -... -LL | println!("{}", &y); - | ^^ value borrowed here after move - -error[E0382]: borrow of moved value: `x` - --> $DIR/borrow-after-move.rs:39:24 - | -LL | x.foo(); - | - value moved here -LL | println!("{}", &x); - | ^^ value borrowed here after partial move - | - = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/unsized-locals/borrow-after-move.rs b/src/test/ui/unsized-locals/borrow-after-move.rs index 587a2180c1558..3299fdf3a9ce8 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.rs +++ b/src/test/ui/unsized-locals/borrow-after-move.rs @@ -18,9 +18,9 @@ fn main() { let y = *x; drop_unsized(y); println!("{}", &x); - //~^ERROR use of moved value + //~^ERROR borrow of moved value println!("{}", &y); - //~^ERROR use of moved value + //~^ERROR borrow of moved value } { @@ -28,15 +28,15 @@ fn main() { let y = *x; y.foo(); println!("{}", &x); - //~^ERROR use of moved value + //~^ERROR borrow of moved value println!("{}", &y); - //~^ERROR use of moved value + //~^ERROR borrow of moved value } { let x = "hello".to_owned().into_boxed_str(); x.foo(); println!("{}", &x); - //~^ERROR use of moved value + //~^ERROR borrow of moved value } } diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr index 8eea01f25c865..010e182674b75 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.stderr +++ b/src/test/ui/unsized-locals/borrow-after-move.stderr @@ -1,54 +1,54 @@ -error[E0382]: use of moved value: `x` - --> $DIR/borrow-after-move.rs:20:25 +error[E0382]: borrow of moved value: `x` + --> $DIR/borrow-after-move.rs:20:24 | LL | let y = *x; - | - value moved here + | -- value moved here LL | drop_unsized(y); LL | println!("{}", &x); - | ^ value used here after move + | ^^ value borrowed here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `y` - --> $DIR/borrow-after-move.rs:22:25 +error[E0382]: borrow of moved value: `y` + --> $DIR/borrow-after-move.rs:22:24 | +LL | let y = *x; + | - move occurs because `y` has type `str`, which does not implement the `Copy` trait LL | drop_unsized(y); | - value moved here ... LL | println!("{}", &y); - | ^ value used here after move - | - = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait + | ^^ value borrowed here after move -error[E0382]: use of moved value: `x` - --> $DIR/borrow-after-move.rs:30:25 +error[E0382]: borrow of moved value: `x` + --> $DIR/borrow-after-move.rs:30:24 | LL | let y = *x; - | - value moved here + | -- value moved here LL | y.foo(); LL | println!("{}", &x); - | ^ value used here after move + | ^^ value borrowed here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `y` - --> $DIR/borrow-after-move.rs:32:25 +error[E0382]: borrow of moved value: `y` + --> $DIR/borrow-after-move.rs:32:24 | +LL | let y = *x; + | - move occurs because `y` has type `str`, which does not implement the `Copy` trait LL | y.foo(); | - value moved here ... LL | println!("{}", &y); - | ^ value used here after move - | - = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait + | ^^ value borrowed here after move -error[E0382]: use of moved value: `x` - --> $DIR/borrow-after-move.rs:39:25 +error[E0382]: borrow of moved value: `x` + --> $DIR/borrow-after-move.rs:39:24 | LL | x.foo(); | - value moved here LL | println!("{}", &x); - | ^ value used here after move + | ^^ value borrowed here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait diff --git a/src/test/ui/unsized-locals/double-move.nll.stderr b/src/test/ui/unsized-locals/double-move.nll.stderr deleted file mode 100644 index c0c3e436f535b..0000000000000 --- a/src/test/ui/unsized-locals/double-move.nll.stderr +++ /dev/null @@ -1,63 +0,0 @@ -error[E0382]: use of moved value: `y` - --> $DIR/double-move.rs:20:22 - | -LL | let y = *x; - | - move occurs because `y` has type `str`, which does not implement the `Copy` trait -LL | drop_unsized(y); - | - value moved here -LL | drop_unsized(y); //~ERROR use of moved value - | ^ value used here after move - -error[E0382]: use of moved value: `x` - --> $DIR/double-move.rs:26:22 - | -LL | let _y = *x; - | -- value moved here -LL | drop_unsized(x); //~ERROR use of moved value - | ^ value used here after partial move - | - = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `*x` - --> $DIR/double-move.rs:32:18 - | -LL | let x = "hello".to_owned().into_boxed_str(); - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait -LL | drop_unsized(x); - | - value moved here -LL | let _y = *x; //~ERROR use of moved value - | ^^ value used here after move - -error[E0382]: use of moved value: `y` - --> $DIR/double-move.rs:39:9 - | -LL | let y = *x; - | - move occurs because `y` has type `str`, which does not implement the `Copy` trait -LL | y.foo(); - | - value moved here -LL | y.foo(); //~ERROR use of moved value - | ^ value used here after move - -error[E0382]: use of moved value: `*x` - --> $DIR/double-move.rs:45:9 - | -LL | let _y = *x; - | -- value moved here -LL | x.foo(); //~ERROR use of moved value - | ^ value used here after move - | - = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `*x` - --> $DIR/double-move.rs:51:18 - | -LL | x.foo(); - | - value moved here -LL | let _y = *x; //~ERROR use of moved value - | ^^ value used here after move - | - = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr index 1009e913b7b67..47fa0d4a437ba 100644 --- a/src/test/ui/unsized-locals/double-move.stderr +++ b/src/test/ui/unsized-locals/double-move.stderr @@ -1,60 +1,60 @@ error[E0382]: use of moved value: `y` --> $DIR/double-move.rs:20:22 | +LL | let y = *x; + | - move occurs because `y` has type `str`, which does not implement the `Copy` trait LL | drop_unsized(y); | - value moved here -LL | drop_unsized(y); //~ERROR use of moved value +LL | drop_unsized(y); | ^ value used here after move - | - = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x` --> $DIR/double-move.rs:26:22 | LL | let _y = *x; - | -- value moved here -LL | drop_unsized(x); //~ERROR use of moved value - | ^ value used here after move + | -- value moved here +LL | drop_unsized(x); + | ^ value used here after partial move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` - --> $DIR/double-move.rs:32:13 + --> $DIR/double-move.rs:32:18 | +LL | let x = "hello".to_owned().into_boxed_str(); + | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait LL | drop_unsized(x); | - value moved here -LL | let _y = *x; //~ERROR use of moved value - | ^^ value used here after move - | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait +LL | let _y = *x; + | ^^ value used here after move error[E0382]: use of moved value: `y` --> $DIR/double-move.rs:39:9 | +LL | let y = *x; + | - move occurs because `y` has type `str`, which does not implement the `Copy` trait LL | y.foo(); | - value moved here -LL | y.foo(); //~ERROR use of moved value +LL | y.foo(); | ^ value used here after move - | - = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:45:9 | LL | let _y = *x; - | -- value moved here -LL | x.foo(); //~ERROR use of moved value + | -- value moved here +LL | x.foo(); | ^ value used here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` - --> $DIR/double-move.rs:51:13 + --> $DIR/double-move.rs:51:18 | LL | x.foo(); | - value moved here -LL | let _y = *x; //~ERROR use of moved value - | ^^ value used here after move +LL | let _y = *x; + | ^^ value used here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait diff --git a/src/test/ui/unsized-locals/unsized-exprs2.nll.stderr b/src/test/ui/unsized-locals/unsized-exprs2.nll.stderr deleted file mode 100644 index a94414ef5603b..0000000000000 --- a/src/test/ui/unsized-locals/unsized-exprs2.nll.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0508]: cannot move out of type `[u8]`, a non-copy slice - --> $DIR/unsized-exprs2.rs:22:19 - | -LL | udrop::<[u8]>(foo()[..]); - | ^^^^^^^^^ cannot move out of here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/unsized-locals/unsized-exprs2.rs b/src/test/ui/unsized-locals/unsized-exprs2.rs index 3fb5a002e0e3c..534439aa6c41c 100644 --- a/src/test/ui/unsized-locals/unsized-exprs2.rs +++ b/src/test/ui/unsized-locals/unsized-exprs2.rs @@ -20,5 +20,5 @@ impl std::ops::Add for A<[u8]> { fn main() { udrop::<[u8]>(foo()[..]); - //~^ERROR cannot move out of indexed content + //~^ERROR cannot move out of type `[u8]`, a non-copy slice } diff --git a/src/test/ui/unsized-locals/unsized-exprs2.stderr b/src/test/ui/unsized-locals/unsized-exprs2.stderr index d7cb4bffb483d..650285cb6740a 100644 --- a/src/test/ui/unsized-locals/unsized-exprs2.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs2.stderr @@ -1,9 +1,12 @@ -error[E0507]: cannot move out of indexed content +error[E0508]: cannot move out of type `[u8]`, a non-copy slice --> $DIR/unsized-exprs2.rs:22:19 | LL | udrop::<[u8]>(foo()[..]); - | ^^^^^^^^^ cannot move out of indexed content + | ^^^^^^^^^ + | | + | cannot move out of here + | move occurs because value has type `[u8]`, which does not implement the `Copy` trait error: aborting due to previous error -For more information about this error, try `rustc --explain E0507`. +For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/unsized-locals/unsized-index.rs b/src/test/ui/unsized-locals/unsized-index.rs new file mode 100644 index 0000000000000..2e6bd82bda302 --- /dev/null +++ b/src/test/ui/unsized-locals/unsized-index.rs @@ -0,0 +1,23 @@ +// compile-pass + +// `std::ops::Index` has an `: ?Sized` bound on the `Idx` type param. This is +// an accidental left-over from the times when it `Index` was by-reference. +// Tightening the bound now could be a breaking change. Although no crater +// regression were observed (https://github.com/rust-lang/rust/pull/59527), +// let's be conservative and just add a test for this. +#![feature(unsized_locals)] + +use std::ops; + +pub struct A; + +impl ops::Index for A { + type Output = (); + fn index(&self, _: str) -> &Self::Output { panic!() } +} + +impl ops::IndexMut for A { + fn index_mut(&mut self, _: str) -> &mut Self::Output { panic!() } +} + +fn main() {} diff --git a/src/test/ui/unsized/unsized-enum2.rs b/src/test/ui/unsized/unsized-enum2.rs index 0fe4a3acfbe20..d589f5ae582c6 100644 --- a/src/test/ui/unsized/unsized-enum2.rs +++ b/src/test/ui/unsized/unsized-enum2.rs @@ -13,10 +13,10 @@ trait PathHelper2 {} trait PathHelper3 {} trait PathHelper4 {} -struct Path1(PathHelper1); -struct Path2(PathHelper2); -struct Path3(PathHelper3); -struct Path4(PathHelper4); +struct Path1(dyn PathHelper1); +struct Path2(dyn PathHelper2); +struct Path3(dyn PathHelper3); +struct Path4(dyn PathHelper4); enum E { // parameter @@ -50,13 +50,13 @@ enum E { //~^ ERROR the size for values of type // plain trait - VM(Foo), + VM(dyn Foo), //~^ ERROR the size for values of type - VN{x: Bar}, + VN{x: dyn Bar}, //~^ ERROR the size for values of type - VO(isize, FooBar), + VO(isize, dyn FooBar), //~^ ERROR the size for values of type - VP{u: isize, x: BarFoo}, + VP{u: isize, x: dyn BarFoo}, //~^ ERROR the size for values of type // projected @@ -72,4 +72,3 @@ enum E { fn main() { } - diff --git a/src/test/ui/unsized/unsized-enum2.stderr b/src/test/ui/unsized/unsized-enum2.stderr index 9109366e4fcfd..cdd5747d86b0f 100644 --- a/src/test/ui/unsized/unsized-enum2.stderr +++ b/src/test/ui/unsized/unsized-enum2.stderr @@ -85,8 +85,8 @@ LL | VH{u: isize, x: [u32]}, error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:53:8 | -LL | VM(Foo), - | ^^^ doesn't have a size known at compile-time +LL | VM(dyn Foo), + | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + 'static)` = note: to learn more, visit @@ -95,8 +95,8 @@ LL | VM(Foo), error[E0277]: the size for values of type `(dyn Bar + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:55:8 | -LL | VN{x: Bar}, - | ^^^^^^ doesn't have a size known at compile-time +LL | VN{x: dyn Bar}, + | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn Bar + 'static)` = note: to learn more, visit @@ -105,8 +105,8 @@ LL | VN{x: Bar}, error[E0277]: the size for values of type `(dyn FooBar + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:57:15 | -LL | VO(isize, FooBar), - | ^^^^^^ doesn't have a size known at compile-time +LL | VO(isize, dyn FooBar), + | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn FooBar + 'static)` = note: to learn more, visit @@ -115,8 +115,8 @@ LL | VO(isize, FooBar), error[E0277]: the size for values of type `(dyn BarFoo + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:59:18 | -LL | VP{u: isize, x: BarFoo}, - | ^^^^^^^^^ doesn't have a size known at compile-time +LL | VP{u: isize, x: dyn BarFoo}, + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn BarFoo + 'static)` = note: to learn more, visit diff --git a/src/test/ui/unspecified-self-in-trait-ref.stderr b/src/test/ui/unspecified-self-in-trait-ref.stderr index b295b39d33c1d..06370cec90e2d 100644 --- a/src/test/ui/unspecified-self-in-trait-ref.stderr +++ b/src/test/ui/unspecified-self-in-trait-ref.stderr @@ -2,33 +2,25 @@ error[E0599]: no function or associated item named `lol` found for type `dyn Foo --> $DIR/unspecified-self-in-trait-ref.rs:10:18 | LL | let a = Foo::lol(); - | -----^^^ - | | - | function or associated item not found in `dyn Foo<_>` + | ^^^ function or associated item not found in `dyn Foo<_>` error[E0599]: no function or associated item named `lol` found for type `dyn Foo<_>` in the current scope --> $DIR/unspecified-self-in-trait-ref.rs:12:23 | LL | let b = Foo::<_>::lol(); - | ----------^^^ - | | - | function or associated item not found in `dyn Foo<_>` + | ^^^ function or associated item not found in `dyn Foo<_>` error[E0599]: no function or associated item named `lol` found for type `dyn Bar<_, _>` in the current scope --> $DIR/unspecified-self-in-trait-ref.rs:14:18 | LL | let c = Bar::lol(); - | -----^^^ - | | - | function or associated item not found in `dyn Bar<_, _>` + | ^^^ function or associated item not found in `dyn Bar<_, _>` error[E0599]: no function or associated item named `lol` found for type `dyn Bar` in the current scope --> $DIR/unspecified-self-in-trait-ref.rs:16:30 | LL | let d = Bar::::lol(); - | -----------------^^^ - | | - | function or associated item not found in `dyn Bar` + | ^^^ function or associated item not found in `dyn Bar` error[E0393]: the type parameter `A` must be explicitly specified --> $DIR/unspecified-self-in-trait-ref.rs:18:13 @@ -40,5 +32,5 @@ LL | let e = Bar::::lol(); error: aborting due to 5 previous errors -Some errors occurred: E0393, E0599. +Some errors have detailed explanations: E0393, E0599. For more information about an error, try `rustc --explain E0393`. diff --git a/src/test/ui/unused/unused-attr.rs b/src/test/ui/unused/unused-attr.rs index 810732a977578..cb8ac0e6a05c0 100644 --- a/src/test/ui/unused/unused-attr.rs +++ b/src/test/ui/unused/unused-attr.rs @@ -1,49 +1,48 @@ #![deny(unused_attributes)] -#![allow(dead_code, unused_imports, unused_extern_crates)] -#![feature(custom_attribute)] +#![feature(rustc_attrs)] -#![foo] //~ ERROR unused attribute +#![rustc_dummy] //~ ERROR unused attribute -#[foo] //~ ERROR unused attribute +#[rustc_dummy] //~ ERROR unused attribute extern crate core; -#[foo] //~ ERROR unused attribute +#[rustc_dummy] //~ ERROR unused attribute use std::collections; -#[foo] //~ ERROR unused attribute +#[rustc_dummy] //~ ERROR unused attribute extern "C" { - #[foo] //~ ERROR unused attribute + #[rustc_dummy] //~ ERROR unused attribute fn foo(); } -#[foo] //~ ERROR unused attribute +#[rustc_dummy] //~ ERROR unused attribute mod foo { - #[foo] //~ ERROR unused attribute + #[rustc_dummy] //~ ERROR unused attribute pub enum Foo { - #[foo] //~ ERROR unused attribute + #[rustc_dummy] //~ ERROR unused attribute Bar, } } -#[foo] //~ ERROR unused attribute +#[rustc_dummy] //~ ERROR unused attribute fn bar(f: foo::Foo) { match f { - #[foo] //~ ERROR unused attribute + #[rustc_dummy] //~ ERROR unused attribute foo::Foo::Bar => {} } } -#[foo] //~ ERROR unused attribute +#[rustc_dummy] //~ ERROR unused attribute struct Foo { - #[foo] //~ ERROR unused attribute + #[rustc_dummy] //~ ERROR unused attribute a: isize } -#[foo] //~ ERROR unused attribute +#[rustc_dummy] //~ ERROR unused attribute trait Baz { - #[foo] //~ ERROR unused attribute + #[rustc_dummy] //~ ERROR unused attribute fn blah(&self); - #[foo] //~ ERROR unused attribute + #[rustc_dummy] //~ ERROR unused attribute fn blah2(&self) {} } diff --git a/src/test/ui/unused/unused-attr.stderr b/src/test/ui/unused/unused-attr.stderr index 6d8a4dd84e65b..956b870715eb2 100644 --- a/src/test/ui/unused/unused-attr.stderr +++ b/src/test/ui/unused/unused-attr.stderr @@ -1,8 +1,8 @@ error: unused attribute - --> $DIR/unused-attr.rs:7:1 + --> $DIR/unused-attr.rs:6:1 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ | note: lint level defined here --> $DIR/unused-attr.rs:1:9 @@ -11,88 +11,88 @@ LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:10:1 + --> $DIR/unused-attr.rs:9:1 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:15:5 + --> $DIR/unused-attr.rs:14:5 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:13:1 + --> $DIR/unused-attr.rs:12:1 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:23:9 + --> $DIR/unused-attr.rs:22:9 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:21:5 + --> $DIR/unused-attr.rs:20:5 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:19:1 + --> $DIR/unused-attr.rs:18:1 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:31:9 + --> $DIR/unused-attr.rs:30:9 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:28:1 + --> $DIR/unused-attr.rs:27:1 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:38:5 + --> $DIR/unused-attr.rs:37:5 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:36:1 + --> $DIR/unused-attr.rs:35:1 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:44:5 + --> $DIR/unused-attr.rs:43:5 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:46:5 + --> $DIR/unused-attr.rs:45:5 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:42:1 + --> $DIR/unused-attr.rs:41:1 | -LL | #[foo] //~ ERROR unused attribute - | ^^^^^^ +LL | #[rustc_dummy] + | ^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr.rs:5:1 + --> $DIR/unused-attr.rs:4:1 | -LL | #![foo] //~ ERROR unused attribute - | ^^^^^^^ +LL | #![rustc_dummy] + | ^^^^^^^^^^^^^^^ error: aborting due to 15 previous errors diff --git a/src/test/ui/unused/unused-macro-rules.stderr b/src/test/ui/unused/unused-macro-rules.stderr index c6ec064096b15..5c0b9f262b8c7 100644 --- a/src/test/ui/unused/unused-macro-rules.stderr +++ b/src/test/ui/unused/unused-macro-rules.stderr @@ -1,7 +1,7 @@ error: unused macro definition --> $DIR/unused-macro-rules.rs:4:1 | -LL | / macro_rules! unused { //~ ERROR: unused macro definition +LL | / macro_rules! unused { LL | | () => {}; LL | | } | |_^ @@ -15,7 +15,7 @@ LL | #![deny(unused_macros)] error: unused macro definition --> $DIR/unused-macro-rules.rs:11:9 | -LL | / macro_rules! m { //~ ERROR: unused macro definition +LL | / macro_rules! m { LL | | () => {}; LL | | } | |_________^ @@ -26,7 +26,7 @@ LL | create_macro!(); error: unused macro definition --> $DIR/unused-macro-rules.rs:24:5 | -LL | / macro_rules! unused { //~ ERROR: unused macro definition +LL | / macro_rules! unused { LL | | () => {}; LL | | } | |_____^ diff --git a/src/test/ui/unused/unused-macro-with-bad-frag-spec.stderr b/src/test/ui/unused/unused-macro-with-bad-frag-spec.stderr index e4624a5fe058b..6edf0a2cf8d52 100644 --- a/src/test/ui/unused/unused-macro-with-bad-frag-spec.stderr +++ b/src/test/ui/unused/unused-macro-with-bad-frag-spec.stderr @@ -1,7 +1,7 @@ error: invalid fragment specifier `t_ty` --> $DIR/unused-macro-with-bad-frag-spec.rs:6:6 | -LL | ($wrong:t_ty) => () //~ ERROR invalid fragment specifier `t_ty` +LL | ($wrong:t_ty) => () | ^^^^^^^^^^^ | = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis` diff --git a/src/test/ui/unused/unused-macro-with-follow-violation.stderr b/src/test/ui/unused/unused-macro-with-follow-violation.stderr index dfeb3a407e583..5eced4f06c0cd 100644 --- a/src/test/ui/unused/unused-macro-with-follow-violation.stderr +++ b/src/test/ui/unused/unused-macro-with-follow-violation.stderr @@ -1,7 +1,7 @@ error: `$e:expr` is followed by `+`, which is not allowed for `expr` fragments --> $DIR/unused-macro-with-follow-violation.rs:4:14 | -LL | ($e:expr +) => () //~ ERROR not allowed for `expr` fragments +LL | ($e:expr +) => () | ^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` diff --git a/src/test/ui/unused/unused-macro.stderr b/src/test/ui/unused/unused-macro.stderr index a83b5be5fbf73..d18fe82564e03 100644 --- a/src/test/ui/unused/unused-macro.stderr +++ b/src/test/ui/unused/unused-macro.stderr @@ -1,7 +1,7 @@ error: unused macro definition --> $DIR/unused-macro.rs:5:1 | -LL | / macro unused { //~ ERROR: unused macro definition +LL | / macro unused { LL | | () => {} LL | | } | |_^ @@ -15,7 +15,7 @@ LL | #![deny(unused_macros)] error: unused macro definition --> $DIR/unused-macro.rs:15:5 | -LL | / macro unused { //~ ERROR: unused macro definition +LL | / macro unused { LL | | () => {} LL | | } | |_____^ @@ -29,7 +29,7 @@ LL | #[deny(unused_macros)] error: unused macro definition --> $DIR/unused-macro.rs:21:5 | -LL | / pub(crate) macro unused { //~ ERROR: unused macro definition +LL | / pub(crate) macro unused { LL | | () => {} LL | | } | |_____^ diff --git a/src/test/ui/unused/unused-result.stderr b/src/test/ui/unused/unused-result.stderr index 2eb53eac40643..e2aee75f3ed31 100644 --- a/src/test/ui/unused/unused-result.stderr +++ b/src/test/ui/unused/unused-result.stderr @@ -1,7 +1,7 @@ error: unused `MustUse` that must be used --> $DIR/unused-result.rs:21:5 | -LL | foo::(); //~ ERROR: unused `MustUse` that must be used +LL | foo::(); | ^^^^^^^^^^^^^^^^^ | note: lint level defined here @@ -13,7 +13,7 @@ LL | #![deny(unused_results, unused_must_use)] error: unused `MustUseMsg` that must be used --> $DIR/unused-result.rs:22:5 | -LL | foo::(); //~ ERROR: unused `MustUseMsg` that must be used +LL | foo::(); | ^^^^^^^^^^^^^^^^^^^^ | = note: some message @@ -21,7 +21,7 @@ LL | foo::(); //~ ERROR: unused `MustUseMsg` that must be used error: unused result --> $DIR/unused-result.rs:34:5 | -LL | foo::(); //~ ERROR: unused result +LL | foo::(); | ^^^^^^^^^^^^^^^ | note: lint level defined here @@ -33,13 +33,13 @@ LL | #![deny(unused_results, unused_must_use)] error: unused `MustUse` that must be used --> $DIR/unused-result.rs:35:5 | -LL | foo::(); //~ ERROR: unused `MustUse` that must be used +LL | foo::(); | ^^^^^^^^^^^^^^^^^ error: unused `MustUseMsg` that must be used --> $DIR/unused-result.rs:36:5 | -LL | foo::(); //~ ERROR: unused `MustUseMsg` that must be used +LL | foo::(); | ^^^^^^^^^^^^^^^^^^^^ | = note: some message diff --git a/src/test/ui/auxiliary/use_from_trait_xc.rs b/src/test/ui/use/auxiliary/use-from-trait-xc.rs similarity index 100% rename from src/test/ui/auxiliary/use_from_trait_xc.rs rename to src/test/ui/use/auxiliary/use-from-trait-xc.rs diff --git a/src/test/ui/use/auxiliary/use_from_trait_xc.rs b/src/test/ui/use/auxiliary/use_from_trait_xc.rs deleted file mode 100644 index 4abe11941b11f..0000000000000 --- a/src/test/ui/use/auxiliary/use_from_trait_xc.rs +++ /dev/null @@ -1,29 +0,0 @@ -pub use self::sub::{Bar, Baz}; - -pub trait Trait { - fn foo(&self); - type Assoc; - const CONST: u32; -} - -struct Foo; - -impl Foo { - pub fn new() {} - - pub const C: u32 = 0; -} - -mod sub { - pub struct Bar; - - impl Bar { - pub fn new() {} - } - - pub enum Baz {} - - impl Baz { - pub fn new() {} - } -} diff --git a/src/test/ui/issue-18986.rs b/src/test/ui/use/issue-18986.rs similarity index 85% rename from src/test/ui/issue-18986.rs rename to src/test/ui/use/issue-18986.rs index 1c431a45ab23e..f0b292f2911c0 100644 --- a/src/test/ui/issue-18986.rs +++ b/src/test/ui/use/issue-18986.rs @@ -1,4 +1,4 @@ -// aux-build:use_from_trait_xc.rs +// aux-build:use-from-trait-xc.rs extern crate use_from_trait_xc; pub use use_from_trait_xc::Trait; diff --git a/src/test/ui/use/issue-18986.stderr b/src/test/ui/use/issue-18986.stderr new file mode 100644 index 0000000000000..14e1bb624033b --- /dev/null +++ b/src/test/ui/use/issue-18986.stderr @@ -0,0 +1,8 @@ +error[E0574]: expected struct, variant or union type, found trait `Trait` + --> $DIR/issue-18986.rs:8:9 + | +LL | Trait { x: 42 } => () + | ^^^^^ not a struct, variant or union type + +error: aborting due to previous error + diff --git a/src/test/ui/use/use-after-move-based-on-type.nll.stderr b/src/test/ui/use/use-after-move-based-on-type.nll.stderr deleted file mode 100644 index 8160ada9d62ea..0000000000000 --- a/src/test/ui/use/use-after-move-based-on-type.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: borrow of moved value: `x` - --> $DIR/use-after-move-based-on-type.rs:4:20 - | -LL | let x = "Hello!".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait -LL | let _y = x; - | - value moved here -LL | println!("{}", x); //~ ERROR use of moved value - | ^ value borrowed here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/use/use-after-move-based-on-type.rs b/src/test/ui/use/use-after-move-based-on-type.rs index fc8ea6f79eb87..ba7aa0345e19c 100644 --- a/src/test/ui/use/use-after-move-based-on-type.rs +++ b/src/test/ui/use/use-after-move-based-on-type.rs @@ -1,5 +1,5 @@ fn main() { let x = "Hello!".to_string(); let _y = x; - println!("{}", x); //~ ERROR use of moved value + println!("{}", x); //~ ERROR borrow of moved value } diff --git a/src/test/ui/use/use-after-move-based-on-type.stderr b/src/test/ui/use/use-after-move-based-on-type.stderr index 2282cdfad14dd..520f88f55dc1a 100644 --- a/src/test/ui/use/use-after-move-based-on-type.stderr +++ b/src/test/ui/use/use-after-move-based-on-type.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `x` +error[E0382]: borrow of moved value: `x` --> $DIR/use-after-move-based-on-type.rs:4:20 | +LL | let x = "Hello!".to_string(); + | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait LL | let _y = x; - | -- value moved here -LL | println!("{}", x); //~ ERROR use of moved value - | ^ value used here after move - | - = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - value moved here +LL | println!("{}", x); + | ^ value borrowed here after move error: aborting due to previous error diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.nll.stderr b/src/test/ui/use/use-after-move-implicity-coerced-object.nll.stderr deleted file mode 100644 index e16bca380679f..0000000000000 --- a/src/test/ui/use/use-after-move-implicity-coerced-object.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0382]: borrow of moved value: `n` - --> $DIR/use-after-move-implicity-coerced-object.rs:28:13 - | -LL | let n: Box<_> = box Number { n: 42 }; - | - move occurs because `n` has type `std::boxed::Box`, which does not implement the `Copy` trait -LL | let mut l: Box<_> = box List { list: Vec::new() }; -LL | l.push(n); - | - value moved here -LL | let x = n.to_string(); - | ^ value borrowed here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.rs b/src/test/ui/use/use-after-move-implicity-coerced-object.rs index e43506916644a..76487ef1c1409 100644 --- a/src/test/ui/use/use-after-move-implicity-coerced-object.rs +++ b/src/test/ui/use/use-after-move-implicity-coerced-object.rs @@ -13,10 +13,10 @@ impl fmt::Display for Number { } struct List { - list: Vec> } + list: Vec> } impl List { - fn push(&mut self, n: Box) { + fn push(&mut self, n: Box) { self.list.push(n); } } @@ -26,5 +26,5 @@ fn main() { let mut l: Box<_> = box List { list: Vec::new() }; l.push(n); let x = n.to_string(); - //~^ ERROR: use of moved value: `n` + //~^ ERROR: borrow of moved value: `n` } diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr index babff9be25241..e16bca380679f 100644 --- a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr +++ b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr @@ -1,12 +1,13 @@ -error[E0382]: use of moved value: `n` +error[E0382]: borrow of moved value: `n` --> $DIR/use-after-move-implicity-coerced-object.rs:28:13 | +LL | let n: Box<_> = box Number { n: 42 }; + | - move occurs because `n` has type `std::boxed::Box`, which does not implement the `Copy` trait +LL | let mut l: Box<_> = box List { list: Vec::new() }; LL | l.push(n); | - value moved here LL | let x = n.to_string(); - | ^ value used here after move - | - = note: move occurs because `n` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ value borrowed here after move error: aborting due to previous error diff --git a/src/test/ui/use/use-after-move-self-based-on-type.nll.stderr b/src/test/ui/use/use-after-move-self-based-on-type.nll.stderr deleted file mode 100644 index 4119741d805cd..0000000000000 --- a/src/test/ui/use/use-after-move-self-based-on-type.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: use of moved value: `self` - --> $DIR/use-after-move-self-based-on-type.rs:12:16 - | -LL | pub fn foo(self) -> isize { - | ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait -LL | self.bar(); - | ---- value moved here -LL | return self.x; //~ ERROR use of moved value: `self.x` - | ^^^^^^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/use/use-after-move-self-based-on-type.rs b/src/test/ui/use/use-after-move-self-based-on-type.rs index 4d84ae9b27173..9325834954f52 100644 --- a/src/test/ui/use/use-after-move-self-based-on-type.rs +++ b/src/test/ui/use/use-after-move-self-based-on-type.rs @@ -9,7 +9,7 @@ impl Drop for S { impl S { pub fn foo(self) -> isize { self.bar(); - return self.x; //~ ERROR use of moved value: `self.x` + return self.x; //~ ERROR use of moved value: `self` } pub fn bar(self) {} diff --git a/src/test/ui/use/use-after-move-self-based-on-type.stderr b/src/test/ui/use/use-after-move-self-based-on-type.stderr index a3acc1aad0f00..9bf1175430c84 100644 --- a/src/test/ui/use/use-after-move-self-based-on-type.stderr +++ b/src/test/ui/use/use-after-move-self-based-on-type.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `self.x` +error[E0382]: use of moved value: `self` --> $DIR/use-after-move-self-based-on-type.rs:12:16 | +LL | pub fn foo(self) -> isize { + | ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait LL | self.bar(); | ---- value moved here -LL | return self.x; //~ ERROR use of moved value: `self.x` +LL | return self.x; | ^^^^^^ value used here after move - | - = note: move occurs because `self` has type `S`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/use/use-after-move-self.nll.stderr b/src/test/ui/use/use-after-move-self.nll.stderr deleted file mode 100644 index e2ce3690cb904..0000000000000 --- a/src/test/ui/use/use-after-move-self.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: use of moved value: `self` - --> $DIR/use-after-move-self.rs:10:16 - | -LL | pub fn foo(self) -> isize { - | ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait -LL | self.bar(); - | ---- value moved here -LL | return *self.x; //~ ERROR use of moved value: `*self.x` - | ^^^^^^^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/use/use-after-move-self.rs b/src/test/ui/use/use-after-move-self.rs index 1337d61a6d8e8..a6f6c45573d0a 100644 --- a/src/test/ui/use/use-after-move-self.rs +++ b/src/test/ui/use/use-after-move-self.rs @@ -7,7 +7,7 @@ struct S { impl S { pub fn foo(self) -> isize { self.bar(); - return *self.x; //~ ERROR use of moved value: `*self.x` + return *self.x; //~ ERROR use of moved value: `self` } pub fn bar(self) {} diff --git a/src/test/ui/use/use-after-move-self.stderr b/src/test/ui/use/use-after-move-self.stderr index 3cb77acaf3dd4..3be0a65550b7f 100644 --- a/src/test/ui/use/use-after-move-self.stderr +++ b/src/test/ui/use/use-after-move-self.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `*self.x` +error[E0382]: use of moved value: `self` --> $DIR/use-after-move-self.rs:10:16 | +LL | pub fn foo(self) -> isize { + | ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait LL | self.bar(); | ---- value moved here -LL | return *self.x; //~ ERROR use of moved value: `*self.x` +LL | return *self.x; | ^^^^^^^ value used here after move - | - = note: move occurs because `self` has type `S`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/use/use-associated-const.rs b/src/test/ui/use/use-associated-const.rs new file mode 100644 index 0000000000000..714fbdabb81ce --- /dev/null +++ b/src/test/ui/use/use-associated-const.rs @@ -0,0 +1,13 @@ +#![allow(unused_imports)] + +pub mod foo { + pub struct Foo; + + impl Foo { + pub const BAR: i32 = 0; + } +} + +use foo::Foo::BAR; //~ ERROR unresolved import `foo::Foo` + +fn main() {} diff --git a/src/test/ui/use/use-associated-const.stderr b/src/test/ui/use/use-associated-const.stderr new file mode 100644 index 0000000000000..4bc0d7e61cb2c --- /dev/null +++ b/src/test/ui/use/use-associated-const.stderr @@ -0,0 +1,9 @@ +error[E0432]: unresolved import `foo::Foo` + --> $DIR/use-associated-const.rs:11:10 + | +LL | use foo::Foo::BAR; + | ^^^ `Foo` is a struct, not a module + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/use/use-from-trait-xc.rs b/src/test/ui/use/use-from-trait-xc.rs index e6f102f6269a7..695ed66a1c183 100644 --- a/src/test/ui/use/use-from-trait-xc.rs +++ b/src/test/ui/use/use-from-trait-xc.rs @@ -1,4 +1,4 @@ -// aux-build:use_from_trait_xc.rs +// aux-build:use-from-trait-xc.rs extern crate use_from_trait_xc; diff --git a/src/test/ui/use/use-from-trait-xc.stderr b/src/test/ui/use/use-from-trait-xc.stderr index 8ff75b503d5ae..f7438cce22967 100644 --- a/src/test/ui/use/use-from-trait-xc.stderr +++ b/src/test/ui/use/use-from-trait-xc.stderr @@ -19,20 +19,20 @@ LL | use use_from_trait_xc::Trait::CONST; error[E0432]: unresolved import `use_from_trait_xc::Foo` --> $DIR/use-from-trait-xc.rs:14:24 | -LL | use use_from_trait_xc::Foo::new; //~ ERROR struct `Foo` is private - | ^^^ not a module `Foo` +LL | use use_from_trait_xc::Foo::new; + | ^^^ `Foo` is a struct, not a module error[E0432]: unresolved import `use_from_trait_xc::Foo` --> $DIR/use-from-trait-xc.rs:17:24 | -LL | use use_from_trait_xc::Foo::C; //~ ERROR struct `Foo` is private - | ^^^ not a module `Foo` +LL | use use_from_trait_xc::Foo::C; + | ^^^ `Foo` is a struct, not a module error[E0432]: unresolved import `use_from_trait_xc::Bar` --> $DIR/use-from-trait-xc.rs:20:24 | LL | use use_from_trait_xc::Bar::new as bnew; - | ^^^ not a module `Bar` + | ^^^ `Bar` is a struct, not a module error[E0432]: unresolved import `use_from_trait_xc::Baz::new` --> $DIR/use-from-trait-xc.rs:23:5 @@ -43,16 +43,16 @@ LL | use use_from_trait_xc::Baz::new as baznew; error[E0603]: struct `Foo` is private --> $DIR/use-from-trait-xc.rs:14:24 | -LL | use use_from_trait_xc::Foo::new; //~ ERROR struct `Foo` is private +LL | use use_from_trait_xc::Foo::new; | ^^^ error[E0603]: struct `Foo` is private --> $DIR/use-from-trait-xc.rs:17:24 | -LL | use use_from_trait_xc::Foo::C; //~ ERROR struct `Foo` is private +LL | use use_from_trait_xc::Foo::C; | ^^^ error: aborting due to 9 previous errors -Some errors occurred: E0253, E0432, E0603. +Some errors have detailed explanations: E0253, E0432, E0603. For more information about an error, try `rustc --explain E0253`. diff --git a/src/test/ui/use/use-from-trait.rs b/src/test/ui/use/use-from-trait.rs index fe578723bd3fc..eab4bb6e3b5be 100644 --- a/src/test/ui/use/use-from-trait.rs +++ b/src/test/ui/use/use-from-trait.rs @@ -1,17 +1,10 @@ -use Trait::foo; -//~^ ERROR `foo` is not directly importable -use Trait::Assoc; -//~^ ERROR `Assoc` is not directly importable -use Trait::C; -//~^ ERROR `C` is not directly importable +use Trait::foo; //~ ERROR `foo` is not directly importable +use Trait::Assoc; //~ ERROR `Assoc` is not directly importable +use Trait::C; //~ ERROR `C` is not directly importable -use Foo::new; -//~^ ERROR unresolved import `Foo` [E0432] -//~| not a module `Foo` +use Foo::new; //~ ERROR unresolved import `Foo` [E0432] -use Foo::C2; -//~^ ERROR unresolved import `Foo` [E0432] -//~| not a module `Foo` +use Foo::C2; //~ ERROR unresolved import `Foo` [E0432] pub trait Trait { fn foo(); diff --git a/src/test/ui/use/use-from-trait.stderr b/src/test/ui/use/use-from-trait.stderr index 9e138422a2fb0..a5b0e356b34c5 100644 --- a/src/test/ui/use/use-from-trait.stderr +++ b/src/test/ui/use/use-from-trait.stderr @@ -5,30 +5,30 @@ LL | use Trait::foo; | ^^^^^^^^^^ cannot be imported directly error[E0253]: `Assoc` is not directly importable - --> $DIR/use-from-trait.rs:3:5 + --> $DIR/use-from-trait.rs:2:5 | LL | use Trait::Assoc; | ^^^^^^^^^^^^ cannot be imported directly error[E0253]: `C` is not directly importable - --> $DIR/use-from-trait.rs:5:5 + --> $DIR/use-from-trait.rs:3:5 | LL | use Trait::C; | ^^^^^^^^ cannot be imported directly error[E0432]: unresolved import `Foo` - --> $DIR/use-from-trait.rs:8:5 + --> $DIR/use-from-trait.rs:5:5 | LL | use Foo::new; - | ^^^ not a module `Foo` + | ^^^ `Foo` is a struct, not a module error[E0432]: unresolved import `Foo` - --> $DIR/use-from-trait.rs:12:5 + --> $DIR/use-from-trait.rs:7:5 | LL | use Foo::C2; - | ^^^ not a module `Foo` + | ^^^ `Foo` is a struct, not a module error: aborting due to 5 previous errors -Some errors occurred: E0253, E0432. +Some errors have detailed explanations: E0253, E0432. For more information about an error, try `rustc --explain E0253`. diff --git a/src/test/ui/use/use-keyword.stderr b/src/test/ui/use/use-keyword.stderr index 1cb30fa487e09..62b6a77fbfb98 100644 --- a/src/test/ui/use/use-keyword.stderr +++ b/src/test/ui/use/use-keyword.stderr @@ -18,5 +18,5 @@ LL | use super::{self as C}; error: aborting due to 3 previous errors -Some errors occurred: E0429, E0432. +Some errors have detailed explanations: E0429, E0432. For more information about an error, try `rustc --explain E0429`. diff --git a/src/test/ui/use/use-mod.stderr b/src/test/ui/use/use-mod.stderr index c23ab34eae678..0cae5eb14aeeb 100644 --- a/src/test/ui/use/use-mod.stderr +++ b/src/test/ui/use/use-mod.stderr @@ -29,5 +29,5 @@ LL | self error: aborting due to 3 previous errors -Some errors occurred: E0252, E0430, E0431. +Some errors have detailed explanations: E0252, E0430, E0431. For more information about an error, try `rustc --explain E0252`. diff --git a/src/test/ui/use/use-mod/use-mod-3.stderr b/src/test/ui/use/use-mod/use-mod-3.stderr index c644ec752f90d..0c800ec35e409 100644 --- a/src/test/ui/use/use-mod/use-mod-3.stderr +++ b/src/test/ui/use/use-mod/use-mod-3.stderr @@ -1,13 +1,13 @@ error[E0603]: module `bar` is private --> $DIR/use-mod-3.rs:1:10 | -LL | use foo::bar::{ //~ ERROR module `bar` is private +LL | use foo::bar::{ | ^^^ error[E0603]: module `bar` is private --> $DIR/use-mod-3.rs:4:10 | -LL | use foo::bar::{ //~ ERROR module `bar` is private +LL | use foo::bar::{ | ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/use/use-mod/use-mod-4.stderr b/src/test/ui/use/use-mod/use-mod-4.stderr index fc0f8952c4794..df9898844d34d 100644 --- a/src/test/ui/use/use-mod/use-mod-4.stderr +++ b/src/test/ui/use/use-mod/use-mod-4.stderr @@ -1,7 +1,7 @@ error[E0429]: `self` imports are only allowed within a { } list --> $DIR/use-mod-4.rs:1:5 | -LL | use foo::self; //~ ERROR unresolved import `foo` +LL | use foo::self; | ^^^^^^^^^ error[E0429]: `self` imports are only allowed within a { } list @@ -13,10 +13,10 @@ LL | use std::mem::self; error[E0432]: unresolved import `foo` --> $DIR/use-mod-4.rs:1:5 | -LL | use foo::self; //~ ERROR unresolved import `foo` +LL | use foo::self; | ^^^ maybe a missing `extern crate foo;`? error: aborting due to 3 previous errors -Some errors occurred: E0429, E0432. +Some errors have detailed explanations: E0429, E0432. For more information about an error, try `rustc --explain E0429`. diff --git a/src/test/ui/use/use-nested-groups-error.stderr b/src/test/ui/use/use-nested-groups-error.stderr index 9d6fd9df6cbe6..7234c8ec621cd 100644 --- a/src/test/ui/use/use-nested-groups-error.stderr +++ b/src/test/ui/use/use-nested-groups-error.stderr @@ -2,7 +2,10 @@ error[E0432]: unresolved import `a::b1::C1` --> $DIR/use-nested-groups-error.rs:9:14 | LL | use a::{b1::{C1, C2}, B2}; - | ^^ no `C1` in `a::b1`. Did you mean to use `C2`? + | ^^ + | | + | no `C1` in `a::b1` + | help: a similar name exists in the module: `C2` error: aborting due to previous error diff --git a/src/test/ui/use/use-paths-as-items.stderr b/src/test/ui/use/use-paths-as-items.stderr index 00f468cdf316b..b09001a9bcd45 100644 --- a/src/test/ui/use/use-paths-as-items.stderr +++ b/src/test/ui/use/use-paths-as-items.stderr @@ -3,11 +3,8 @@ error[E0252]: the name `mem` is defined multiple times | LL | use std::{mem, ptr}; | --- previous import of the module `mem` here -LL | use std::mem; //~ ERROR the name `mem` is defined multiple times - | ----^^^^^^^^- - | | | - | | `mem` reimported here - | help: remove unnecessary import +LL | use std::mem; + | ^^^^^^^^ `mem` reimported here | = note: `mem` must be defined only once in the type namespace of this module diff --git a/src/test/ui/use/use-self-type.stderr b/src/test/ui/use/use-self-type.stderr index 50b4cdf357d89..0dd0e04267c33 100644 --- a/src/test/ui/use/use-self-type.stderr +++ b/src/test/ui/use/use-self-type.stderr @@ -1,16 +1,16 @@ error[E0433]: failed to resolve: use of undeclared type or module `Self` --> $DIR/use-self-type.rs:7:16 | -LL | pub(in Self::f) struct Z; //~ ERROR use of undeclared type or module `Self` +LL | pub(in Self::f) struct Z; | ^^^^ use of undeclared type or module `Self` error[E0432]: unresolved import `Self` --> $DIR/use-self-type.rs:6:13 | -LL | use Self::f; //~ ERROR unresolved import +LL | use Self::f; | ^^^^ use of undeclared type or module `Self` error: aborting due to 2 previous errors -Some errors occurred: E0432, E0433. +Some errors have detailed explanations: E0432, E0433. For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/use/use-super-global-path.stderr b/src/test/ui/use/use-super-global-path.stderr index ee7deb264df54..72b3deaaecea5 100644 --- a/src/test/ui/use/use-super-global-path.stderr +++ b/src/test/ui/use/use-super-global-path.stderr @@ -1,19 +1,19 @@ error[E0433]: failed to resolve: global paths cannot start with `super` --> $DIR/use-super-global-path.rs:7:11 | -LL | use ::super::{S, Z}; //~ ERROR global paths cannot start with `super` +LL | use ::super::{S, Z}; | ^^^^^ global paths cannot start with `super` error[E0433]: failed to resolve: global paths cannot start with `super` --> $DIR/use-super-global-path.rs:10:15 | -LL | use ::super::main; //~ ERROR global paths cannot start with `super` +LL | use ::super::main; | ^^^^^ global paths cannot start with `super` error[E0425]: cannot find function `main` in this scope --> $DIR/use-super-global-path.rs:11:9 | -LL | main(); //~ ERROR cannot find function `main` in this scope +LL | main(); | ^^^^ not found in this scope help: possible candidate is found in another module, you can import it into scope | @@ -22,5 +22,5 @@ LL | use main; error: aborting due to 3 previous errors -Some errors occurred: E0425, E0433. +Some errors have detailed explanations: E0425, E0433. For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/used.stderr b/src/test/ui/used.stderr index c998e27c531e9..ea77f129d8ef0 100644 --- a/src/test/ui/used.stderr +++ b/src/test/ui/used.stderr @@ -1,25 +1,25 @@ error: attribute must be applied to a `static` variable --> $DIR/used.rs:4:1 | -LL | #[used] //~ ERROR attribute must be applied to a `static` variable +LL | #[used] | ^^^^^^^ error: attribute must be applied to a `static` variable --> $DIR/used.rs:7:1 | -LL | #[used] //~ ERROR attribute must be applied to a `static` variable +LL | #[used] | ^^^^^^^ error: attribute must be applied to a `static` variable --> $DIR/used.rs:10:1 | -LL | #[used] //~ ERROR attribute must be applied to a `static` variable +LL | #[used] | ^^^^^^^ error: attribute must be applied to a `static` variable --> $DIR/used.rs:13:1 | -LL | #[used] //~ ERROR attribute must be applied to a `static` variable +LL | #[used] | ^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/useless-comment.rs b/src/test/ui/useless-comment.rs new file mode 100644 index 0000000000000..7d2e5ab6f2b7f --- /dev/null +++ b/src/test/ui/useless-comment.rs @@ -0,0 +1,45 @@ +#![feature(stmt_expr_attributes)] + +#![deny(unused_doc_comments)] + +macro_rules! mac { + () => {} +} + +/// foo //~ ERROR unused doc comment +mac!(); + +fn foo() { + /// a //~ ERROR unused doc comment + let x = 12; + + /// multi-line //~ unused doc comment + /// doc comment + /// that is unused + match x { + /// c //~ ERROR unused doc comment + 1 => {}, + _ => {} + } + + /// foo //~ ERROR unused doc comment + unsafe {} + + #[doc = "foo"] //~ ERROR unused doc comment + #[doc = "bar"] //~ ERROR unused doc comment + 3; + + /// bar //~ ERROR unused doc comment + mac!(); + + let x = /** comment */ 47; //~ ERROR unused doc comment + + /// dox //~ ERROR unused doc comment + { + + } +} + +fn main() { + foo(); +} diff --git a/src/test/ui/useless-comment.stderr b/src/test/ui/useless-comment.stderr new file mode 100644 index 0000000000000..925e307963692 --- /dev/null +++ b/src/test/ui/useless-comment.stderr @@ -0,0 +1,98 @@ +error: unused doc comment + --> $DIR/useless-comment.rs:9:1 + | +LL | /// foo + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | mac!(); + | ------- rustdoc does not generate documentation for macro expansions + | +note: lint level defined here + --> $DIR/useless-comment.rs:3:9 + | +LL | #![deny(unused_doc_comments)] + | ^^^^^^^^^^^^^^^^^^^ + = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion + +error: unused doc comment + --> $DIR/useless-comment.rs:13:5 + | +LL | /// a + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = 12; + | ----------- rustdoc does not generate documentation for statements + +error: unused doc comment + --> $DIR/useless-comment.rs:16:5 + | +LL | / /// multi-line +LL | | /// doc comment +LL | | /// that is unused + | |______________________^ +LL | / match x { +LL | | /// c +LL | | 1 => {}, +LL | | _ => {} +LL | | } + | |_____- rustdoc does not generate documentation for expressions + +error: unused doc comment + --> $DIR/useless-comment.rs:20:9 + | +LL | /// c + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | 1 => {}, + | ------- rustdoc does not generate documentation for match arms + +error: unused doc comment + --> $DIR/useless-comment.rs:25:5 + | +LL | /// foo + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe {} + | --------- rustdoc does not generate documentation for expressions + +error: unused doc comment + --> $DIR/useless-comment.rs:28:5 + | +LL | #[doc = "foo"] + | ^^^^^^^^^^^^^^ +LL | #[doc = "bar"] +LL | 3; + | - rustdoc does not generate documentation for expressions + +error: unused doc comment + --> $DIR/useless-comment.rs:29:5 + | +LL | #[doc = "bar"] + | ^^^^^^^^^^^^^^ +LL | 3; + | - rustdoc does not generate documentation for expressions + +error: unused doc comment + --> $DIR/useless-comment.rs:32:5 + | +LL | /// bar + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | mac!(); + | ------- rustdoc does not generate documentation for macro expansions + | + = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion + +error: unused doc comment + --> $DIR/useless-comment.rs:35:13 + | +LL | let x = /** comment */ 47; + | ^^^^^^^^^^^^^^ -- rustdoc does not generate documentation for expressions + +error: unused doc comment + --> $DIR/useless-comment.rs:37:5 + | +LL | /// dox + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / { +LL | | +LL | | } + | |_____- rustdoc does not generate documentation for expressions + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/useless-pub.stderr b/src/test/ui/useless-pub.stderr index 5bca980f21e15..14c4983ae29b9 100644 --- a/src/test/ui/useless-pub.stderr +++ b/src/test/ui/useless-pub.stderr @@ -1,19 +1,19 @@ error[E0449]: unnecessary visibility qualifier --> $DIR/useless-pub.rs:8:5 | -LL | pub fn foo(&self) {} //~ ERROR: unnecessary visibility qualifier +LL | pub fn foo(&self) {} | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/useless-pub.rs:12:10 | -LL | V1 { pub f: i32 }, //~ ERROR unnecessary visibility qualifier +LL | V1 { pub f: i32 }, | ^^^ `pub` not permitted here because it's implied error[E0449]: unnecessary visibility qualifier --> $DIR/useless-pub.rs:13:8 | -LL | V2(pub i32), //~ ERROR unnecessary visibility qualifier +LL | V2(pub i32), | ^^^ `pub` not permitted here because it's implied error: aborting due to 3 previous errors diff --git a/src/test/ui/useless_comment.rs b/src/test/ui/useless_comment.rs deleted file mode 100644 index 531eec007fc48..0000000000000 --- a/src/test/ui/useless_comment.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![deny(unused_doc_comments)] - -fn foo() { - /// a //~ ERROR doc comment not used by rustdoc - let x = 12; - - /// b //~ doc comment not used by rustdoc - match x { - /// c //~ ERROR doc comment not used by rustdoc - 1 => {}, - _ => {} - } - - /// foo //~ ERROR doc comment not used by rustdoc - unsafe {} -} - -fn main() { - foo(); -} diff --git a/src/test/ui/useless_comment.stderr b/src/test/ui/useless_comment.stderr deleted file mode 100644 index cc818f6ce7c39..0000000000000 --- a/src/test/ui/useless_comment.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error: doc comment not used by rustdoc - --> $DIR/useless_comment.rs:4:5 - | -LL | /// a //~ ERROR doc comment not used by rustdoc - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: lint level defined here - --> $DIR/useless_comment.rs:1:9 - | -LL | #![deny(unused_doc_comments)] - | ^^^^^^^^^^^^^^^^^^^ - -error: doc comment not used by rustdoc - --> $DIR/useless_comment.rs:7:5 - | -LL | /// b //~ doc comment not used by rustdoc - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: doc comment not used by rustdoc - --> $DIR/useless_comment.rs:9:9 - | -LL | /// c //~ ERROR doc comment not used by rustdoc - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: doc comment not used by rustdoc - --> $DIR/useless_comment.rs:14:5 - | -LL | /// foo //~ ERROR doc comment not used by rustdoc - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors - diff --git a/src/test/ui/user-defined-macro-rules.stderr b/src/test/ui/user-defined-macro-rules.stderr index a2d7b171a73ab..057515228e0d1 100644 --- a/src/test/ui/user-defined-macro-rules.stderr +++ b/src/test/ui/user-defined-macro-rules.stderr @@ -1,7 +1,7 @@ error: user-defined macros may not be named `macro_rules` --> $DIR/user-defined-macro-rules.rs:3:1 | -LL | macro_rules! macro_rules { () => {} } //~ ERROR user-defined macros may not be named `macro_rules` +LL | macro_rules! macro_rules { () => {} } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/utf8_idents.stderr b/src/test/ui/utf8_idents.stderr index 52fb607af5b25..b65848cc58f6e 100644 --- a/src/test/ui/utf8_idents.stderr +++ b/src/test/ui/utf8_idents.stderr @@ -1,39 +1,43 @@ -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/utf8_idents.rs:2:5 | -LL | 'β, //~ ERROR non-ascii idents are not fully supported +LL | 'β, | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/utf8_idents.rs:3:5 | -LL | γ //~ ERROR non-ascii idents are not fully supported +LL | γ | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/utf8_idents.rs:8:5 | -LL | δ: usize //~ ERROR non-ascii idents are not fully supported +LL | δ: usize | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/utf8_idents.rs:12:9 | -LL | let α = 0.00001f64; //~ ERROR non-ascii idents are not fully supported +LL | let α = 0.00001f64; | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable warning: type parameter `γ` should have an upper camel case name --> $DIR/utf8_idents.rs:3:5 | -LL | γ //~ ERROR non-ascii idents are not fully supported +LL | γ | ^ help: convert the identifier to upper camel case: `Γ` | = note: #[warn(non_camel_case_types)] on by default diff --git a/src/test/ui/variance/variance-associated-types.stderr b/src/test/ui/variance/variance-associated-types.stderr index 75ebc86689819..b9aa9695f6224 100644 --- a/src/test/ui/variance/variance-associated-types.stderr +++ b/src/test/ui/variance/variance-associated-types.stderr @@ -1,7 +1,7 @@ error[E0208]: [-, +] --> $DIR/variance-associated-types.rs:13:1 | -LL | / struct Foo<'a, T : Trait<'a>> { //~ ERROR [-, +] +LL | / struct Foo<'a, T : Trait<'a>> { LL | | field: (T, &'a ()) LL | | } | |_^ @@ -9,11 +9,10 @@ LL | | } error[E0208]: [o, o] --> $DIR/variance-associated-types.rs:18:1 | -LL | / struct Bar<'a, T : Trait<'a>> { //~ ERROR [o, o] +LL | / struct Bar<'a, T : Trait<'a>> { LL | | field: >::Type LL | | } | |_^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0208`. diff --git a/src/test/ui/variance/variance-btree-invariant-types.nll.stderr b/src/test/ui/variance/variance-btree-invariant-types.nll.stderr new file mode 100644 index 0000000000000..344437f74e495 --- /dev/null +++ b/src/test/ui/variance/variance-btree-invariant-types.nll.stderr @@ -0,0 +1,106 @@ +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:4:5 + | +LL | fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, &'new (), ()> { + | ---- lifetime `'new` defined here +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:7:5 + | +LL | fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, (), &'new ()> { + | ---- lifetime `'new` defined here +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:10:5 + | +LL | fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, &'static (), ()> { + | ---- lifetime `'new` defined here +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:13:5 + | +LL | fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, (), &'static ()> { + | ---- lifetime `'new` defined here +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:18:5 + | +LL | fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>) + | ---- lifetime `'new` defined here +LL | -> OccupiedEntry<'a, &'new (), ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:22:5 + | +LL | fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>) + | ---- lifetime `'new` defined here +LL | -> OccupiedEntry<'a, (), &'new ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:26:5 + | +LL | fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>) + | ---- lifetime `'new` defined here +LL | -> OccupiedEntry<'a, &'static (), ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:30:5 + | +LL | fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>) + | ---- lifetime `'new` defined here +LL | -> OccupiedEntry<'a, (), &'static ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:35:5 + | +LL | fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>) + | ---- lifetime `'new` defined here +LL | -> VacantEntry<'a, &'new (), ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:39:5 + | +LL | fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>) + | ---- lifetime `'new` defined here +LL | -> VacantEntry<'a, (), &'new ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:43:5 + | +LL | fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>) + | ---- lifetime `'new` defined here +LL | -> VacantEntry<'a, &'static (), ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:47:5 + | +LL | fn vac_contra_val<'a, 'new>(v: VacantEntry<'a, (), &'new ()>) + | ---- lifetime `'new` defined here +LL | -> VacantEntry<'a, (), &'static ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + +error: aborting due to 12 previous errors + diff --git a/src/test/ui/variance/variance-btree-invariant-types.stderr b/src/test/ui/variance/variance-btree-invariant-types.stderr index 0d8b4dddc68c1..49222fc7fa627 100644 --- a/src/test/ui/variance/variance-btree-invariant-types.stderr +++ b/src/test/ui/variance/variance-btree-invariant-types.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/variance-btree-invariant-types.rs:4:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `std::collections::btree_map::IterMut<'_, &'new (), _>` @@ -16,7 +16,7 @@ LL | fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, & error[E0308]: mismatched types --> $DIR/variance-btree-invariant-types.rs:7:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `std::collections::btree_map::IterMut<'_, _, &'new ()>` @@ -31,7 +31,7 @@ LL | fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, ( error[E0308]: mismatched types --> $DIR/variance-btree-invariant-types.rs:10:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `std::collections::btree_map::IterMut<'_, &'static (), _>` @@ -46,7 +46,7 @@ LL | fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, & error[E0308]: mismatched types --> $DIR/variance-btree-invariant-types.rs:13:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `std::collections::btree_map::IterMut<'_, _, &'static ()>` @@ -61,7 +61,7 @@ LL | fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, ( error[E0308]: mismatched types --> $DIR/variance-btree-invariant-types.rs:18:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `std::collections::btree_map::OccupiedEntry<'_, &'new (), _>` @@ -76,7 +76,7 @@ LL | fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>) error[E0308]: mismatched types --> $DIR/variance-btree-invariant-types.rs:22:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `std::collections::btree_map::OccupiedEntry<'_, _, &'new ()>` @@ -91,7 +91,7 @@ LL | fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>) error[E0308]: mismatched types --> $DIR/variance-btree-invariant-types.rs:26:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `std::collections::btree_map::OccupiedEntry<'_, &'static (), _>` @@ -106,7 +106,7 @@ LL | fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>) error[E0308]: mismatched types --> $DIR/variance-btree-invariant-types.rs:30:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `std::collections::btree_map::OccupiedEntry<'_, _, &'static ()>` @@ -121,7 +121,7 @@ LL | fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>) error[E0308]: mismatched types --> $DIR/variance-btree-invariant-types.rs:35:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `std::collections::btree_map::VacantEntry<'_, &'new (), _>` @@ -136,7 +136,7 @@ LL | fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>) error[E0308]: mismatched types --> $DIR/variance-btree-invariant-types.rs:39:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `std::collections::btree_map::VacantEntry<'_, _, &'new ()>` @@ -151,7 +151,7 @@ LL | fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>) error[E0308]: mismatched types --> $DIR/variance-btree-invariant-types.rs:43:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `std::collections::btree_map::VacantEntry<'_, &'static (), _>` @@ -166,7 +166,7 @@ LL | fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>) error[E0308]: mismatched types --> $DIR/variance-btree-invariant-types.rs:47:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `std::collections::btree_map::VacantEntry<'_, _, &'static ()>` diff --git a/src/test/ui/variance/variance-cell-is-invariant.nll.stderr b/src/test/ui/variance/variance-cell-is-invariant.nll.stderr new file mode 100644 index 0000000000000..a3ae5320c90d4 --- /dev/null +++ b/src/test/ui/variance/variance-cell-is-invariant.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/variance-cell-is-invariant.rs:14:12 + | +LL | fn use_<'short,'long>(c: Foo<'short>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: Foo<'long> = c; + | ^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + +error: aborting due to previous error + diff --git a/src/test/ui/variance/variance-cell-is-invariant.stderr b/src/test/ui/variance/variance-cell-is-invariant.stderr index ba76c2efec485..91f6d7659ed4e 100644 --- a/src/test/ui/variance/variance-cell-is-invariant.stderr +++ b/src/test/ui/variance/variance-cell-is-invariant.stderr @@ -7,9 +7,8 @@ LL | s: &'short isize, LL | l: &'long isize, | ------------ LL | _where:Option<&'short &'long ()>) { -LL | let _: Foo<'long> = c; //~ ERROR E0623 +LL | let _: Foo<'long> = c; | ^ ...but data from `c` flows into `l` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr b/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr new file mode 100644 index 0000000000000..69818aedd154c --- /dev/null +++ b/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/variance-contravariant-arg-object.rs:14:5 + | +LL | fn get_min_from_max<'min, 'max>(v: Box>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ returning this value requires that `'min` must outlive `'max` + +error: lifetime may not live long enough + --> $DIR/variance-contravariant-arg-object.rs:22:5 + | +LL | fn get_max_from_min<'min, 'max, G>(v: Box>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ returning this value requires that `'min` must outlive `'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-contravariant-arg-object.rs b/src/test/ui/variance/variance-contravariant-arg-object.rs index 27e5675dcde87..947f4cd8b8f4d 100644 --- a/src/test/ui/variance/variance-contravariant-arg-object.rs +++ b/src/test/ui/variance/variance-contravariant-arg-object.rs @@ -7,15 +7,15 @@ trait Get : 'static { fn get(&self, t: T); } -fn get_min_from_max<'min, 'max>(v: Box>) - -> Box> +fn get_min_from_max<'min, 'max>(v: Box>) + -> Box> where 'max : 'min { v //~ ERROR mismatched types } -fn get_max_from_min<'min, 'max, G>(v: Box>) - -> Box> +fn get_max_from_min<'min, 'max, G>(v: Box>) + -> Box> where 'max : 'min { // Previously OK: diff --git a/src/test/ui/variance/variance-contravariant-arg-object.stderr b/src/test/ui/variance/variance-contravariant-arg-object.stderr index 79681c776736d..263c849e19981 100644 --- a/src/test/ui/variance/variance-contravariant-arg-object.stderr +++ b/src/test/ui/variance/variance-contravariant-arg-object.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/variance-contravariant-arg-object.rs:14:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `dyn Get<&'min i32>` @@ -9,18 +9,18 @@ LL | v //~ ERROR mismatched types note: the lifetime 'min as defined on the function body at 10:21... --> $DIR/variance-contravariant-arg-object.rs:10:21 | -LL | fn get_min_from_max<'min, 'max>(v: Box>) +LL | fn get_min_from_max<'min, 'max>(v: Box>) | ^^^^ note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 10:27 --> $DIR/variance-contravariant-arg-object.rs:10:27 | -LL | fn get_min_from_max<'min, 'max>(v: Box>) +LL | fn get_min_from_max<'min, 'max>(v: Box>) | ^^^^ error[E0308]: mismatched types --> $DIR/variance-contravariant-arg-object.rs:22:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `dyn Get<&'max i32>` @@ -28,12 +28,12 @@ LL | v //~ ERROR mismatched types note: the lifetime 'min as defined on the function body at 17:21... --> $DIR/variance-contravariant-arg-object.rs:17:21 | -LL | fn get_max_from_min<'min, 'max, G>(v: Box>) +LL | fn get_max_from_min<'min, 'max, G>(v: Box>) | ^^^^ note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 17:27 --> $DIR/variance-contravariant-arg-object.rs:17:27 | -LL | fn get_max_from_min<'min, 'max, G>(v: Box>) +LL | fn get_max_from_min<'min, 'max, G>(v: Box>) | ^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/variance/variance-contravariant-arg-trait-match.nll.stderr b/src/test/ui/variance/variance-contravariant-arg-trait-match.nll.stderr new file mode 100644 index 0000000000000..dbd75cb52fa83 --- /dev/null +++ b/src/test/ui/variance/variance-contravariant-arg-trait-match.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/variance-contravariant-arg-trait-match.rs:13:5 + | +LL | fn get_min_from_max<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::() + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + +error: lifetime may not live long enough + --> $DIR/variance-contravariant-arg-trait-match.rs:21:5 + | +LL | fn get_max_from_min<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::() + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr b/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr index 4c97a5892f149..ffe690dd22073 100644 --- a/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr +++ b/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/variance-contravariant-arg-trait-match.rs:13:5 | -LL | impls_get::() //~ ERROR mismatched types +LL | impls_get::() | ^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `Get<&'min i32>` @@ -20,7 +20,7 @@ LL | fn get_min_from_max<'min, 'max, G>() error[E0308]: mismatched types --> $DIR/variance-contravariant-arg-trait-match.rs:21:5 | -LL | impls_get::() //~ ERROR mismatched types +LL | impls_get::() | ^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `Get<&'max i32>` diff --git a/src/test/ui/variance/variance-contravariant-self-trait-match.nll.stderr b/src/test/ui/variance/variance-contravariant-self-trait-match.nll.stderr new file mode 100644 index 0000000000000..9212cf24be3bf --- /dev/null +++ b/src/test/ui/variance/variance-contravariant-self-trait-match.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/variance-contravariant-self-trait-match.rs:13:5 + | +LL | fn get_min_from_max<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<&'min G>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + +error: lifetime may not live long enough + --> $DIR/variance-contravariant-self-trait-match.rs:22:5 + | +LL | fn get_max_from_min<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<&'max G>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-contravariant-self-trait-match.stderr b/src/test/ui/variance/variance-contravariant-self-trait-match.stderr index 30a7b02de76f9..6f445d79bf5d2 100644 --- a/src/test/ui/variance/variance-contravariant-self-trait-match.stderr +++ b/src/test/ui/variance/variance-contravariant-self-trait-match.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/variance-contravariant-self-trait-match.rs:13:5 | -LL | impls_get::<&'min G>(); //~ ERROR mismatched types +LL | impls_get::<&'min G>(); | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `Get` @@ -20,7 +20,7 @@ LL | fn get_min_from_max<'min, 'max, G>() error[E0308]: mismatched types --> $DIR/variance-contravariant-self-trait-match.rs:22:5 | -LL | impls_get::<&'max G>(); //~ ERROR mismatched types +LL | impls_get::<&'max G>(); | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `Get` diff --git a/src/test/ui/variance/variance-covariant-arg-object.nll.stderr b/src/test/ui/variance/variance-covariant-arg-object.nll.stderr new file mode 100644 index 0000000000000..63ab7fe96512d --- /dev/null +++ b/src/test/ui/variance/variance-covariant-arg-object.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/variance-covariant-arg-object.rs:15:5 + | +LL | fn get_min_from_max<'min, 'max>(v: Box>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ returning this value requires that `'min` must outlive `'max` + +error: lifetime may not live long enough + --> $DIR/variance-covariant-arg-object.rs:22:5 + | +LL | fn get_max_from_min<'min, 'max, G>(v: Box>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ returning this value requires that `'min` must outlive `'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-covariant-arg-object.rs b/src/test/ui/variance/variance-covariant-arg-object.rs index 4b371841654f2..7cbf65ae3d924 100644 --- a/src/test/ui/variance/variance-covariant-arg-object.rs +++ b/src/test/ui/variance/variance-covariant-arg-object.rs @@ -7,16 +7,16 @@ trait Get : 'static { fn get(&self) -> T; } -fn get_min_from_max<'min, 'max>(v: Box>) - -> Box> +fn get_min_from_max<'min, 'max>(v: Box>) + -> Box> where 'max : 'min { // Previously OK, now an error as traits are invariant. v //~ ERROR mismatched types } -fn get_max_from_min<'min, 'max, G>(v: Box>) - -> Box> +fn get_max_from_min<'min, 'max, G>(v: Box>) + -> Box> where 'max : 'min { v //~ ERROR mismatched types diff --git a/src/test/ui/variance/variance-covariant-arg-object.stderr b/src/test/ui/variance/variance-covariant-arg-object.stderr index afdcccd21192c..94f80c2b657f5 100644 --- a/src/test/ui/variance/variance-covariant-arg-object.stderr +++ b/src/test/ui/variance/variance-covariant-arg-object.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/variance-covariant-arg-object.rs:15:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `dyn Get<&'min i32>` @@ -9,18 +9,18 @@ LL | v //~ ERROR mismatched types note: the lifetime 'min as defined on the function body at 10:21... --> $DIR/variance-covariant-arg-object.rs:10:21 | -LL | fn get_min_from_max<'min, 'max>(v: Box>) +LL | fn get_min_from_max<'min, 'max>(v: Box>) | ^^^^ note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 10:27 --> $DIR/variance-covariant-arg-object.rs:10:27 | -LL | fn get_min_from_max<'min, 'max>(v: Box>) +LL | fn get_min_from_max<'min, 'max>(v: Box>) | ^^^^ error[E0308]: mismatched types --> $DIR/variance-covariant-arg-object.rs:22:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `dyn Get<&'max i32>` @@ -28,12 +28,12 @@ LL | v //~ ERROR mismatched types note: the lifetime 'min as defined on the function body at 18:21... --> $DIR/variance-covariant-arg-object.rs:18:21 | -LL | fn get_max_from_min<'min, 'max, G>(v: Box>) +LL | fn get_max_from_min<'min, 'max, G>(v: Box>) | ^^^^ note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 18:27 --> $DIR/variance-covariant-arg-object.rs:18:27 | -LL | fn get_max_from_min<'min, 'max, G>(v: Box>) +LL | fn get_max_from_min<'min, 'max, G>(v: Box>) | ^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/variance/variance-covariant-arg-trait-match.nll.stderr b/src/test/ui/variance/variance-covariant-arg-trait-match.nll.stderr new file mode 100644 index 0000000000000..33589121c4b83 --- /dev/null +++ b/src/test/ui/variance/variance-covariant-arg-trait-match.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/variance-covariant-arg-trait-match.rs:14:5 + | +LL | fn get_min_from_max<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::() + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + +error: lifetime may not live long enough + --> $DIR/variance-covariant-arg-trait-match.rs:20:5 + | +LL | fn get_max_from_min<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::() + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-covariant-arg-trait-match.stderr b/src/test/ui/variance/variance-covariant-arg-trait-match.stderr index 3c1f43943a004..c0209edc91553 100644 --- a/src/test/ui/variance/variance-covariant-arg-trait-match.stderr +++ b/src/test/ui/variance/variance-covariant-arg-trait-match.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/variance-covariant-arg-trait-match.rs:14:5 | -LL | impls_get::() //~ ERROR mismatched types +LL | impls_get::() | ^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `Get<&'min i32>` @@ -20,7 +20,7 @@ LL | fn get_min_from_max<'min, 'max, G>() error[E0308]: mismatched types --> $DIR/variance-covariant-arg-trait-match.rs:20:5 | -LL | impls_get::() //~ ERROR mismatched types +LL | impls_get::() | ^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `Get<&'max i32>` diff --git a/src/test/ui/variance/variance-covariant-self-trait-match.nll.stderr b/src/test/ui/variance/variance-covariant-self-trait-match.nll.stderr new file mode 100644 index 0000000000000..6b2413d68be29 --- /dev/null +++ b/src/test/ui/variance/variance-covariant-self-trait-match.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/variance-covariant-self-trait-match.rs:14:5 + | +LL | fn get_min_from_max<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<&'min G>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + +error: lifetime may not live long enough + --> $DIR/variance-covariant-self-trait-match.rs:20:5 + | +LL | fn get_max_from_min<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<&'max G>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-covariant-self-trait-match.stderr b/src/test/ui/variance/variance-covariant-self-trait-match.stderr index c3a15662f7297..fe5fe105c6b3c 100644 --- a/src/test/ui/variance/variance-covariant-self-trait-match.stderr +++ b/src/test/ui/variance/variance-covariant-self-trait-match.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/variance-covariant-self-trait-match.rs:14:5 | -LL | impls_get::<&'min G>(); //~ ERROR mismatched types +LL | impls_get::<&'min G>(); | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `Get` @@ -20,7 +20,7 @@ LL | fn get_min_from_max<'min, 'max, G>() error[E0308]: mismatched types --> $DIR/variance-covariant-self-trait-match.rs:20:5 | -LL | impls_get::<&'max G>(); //~ ERROR mismatched types +LL | impls_get::<&'max G>(); | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `Get` diff --git a/src/test/ui/variance/variance-invariant-arg-object.nll.stderr b/src/test/ui/variance/variance-invariant-arg-object.nll.stderr new file mode 100644 index 0000000000000..fe2f35b63b57d --- /dev/null +++ b/src/test/ui/variance/variance-invariant-arg-object.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/variance-invariant-arg-object.rs:11:5 + | +LL | fn get_min_from_max<'min, 'max>(v: Box>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ returning this value requires that `'min` must outlive `'max` + +error: lifetime may not live long enough + --> $DIR/variance-invariant-arg-object.rs:18:5 + | +LL | fn get_max_from_min<'min, 'max, G>(v: Box>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ returning this value requires that `'min` must outlive `'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-invariant-arg-object.rs b/src/test/ui/variance/variance-invariant-arg-object.rs index 91f5982e5339f..886d263c45768 100644 --- a/src/test/ui/variance/variance-invariant-arg-object.rs +++ b/src/test/ui/variance/variance-invariant-arg-object.rs @@ -4,15 +4,15 @@ trait Get : 'static { fn get(&self, t: T) -> T; } -fn get_min_from_max<'min, 'max>(v: Box>) - -> Box> +fn get_min_from_max<'min, 'max>(v: Box>) + -> Box> where 'max : 'min { v //~ ERROR mismatched types } -fn get_max_from_min<'min, 'max, G>(v: Box>) - -> Box> +fn get_max_from_min<'min, 'max, G>(v: Box>) + -> Box> where 'max : 'min { v //~ ERROR mismatched types diff --git a/src/test/ui/variance/variance-invariant-arg-object.stderr b/src/test/ui/variance/variance-invariant-arg-object.stderr index b0dddd6ed4978..50a8697d4392f 100644 --- a/src/test/ui/variance/variance-invariant-arg-object.stderr +++ b/src/test/ui/variance/variance-invariant-arg-object.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/variance-invariant-arg-object.rs:11:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `dyn Get<&'min i32>` @@ -9,18 +9,18 @@ LL | v //~ ERROR mismatched types note: the lifetime 'min as defined on the function body at 7:21... --> $DIR/variance-invariant-arg-object.rs:7:21 | -LL | fn get_min_from_max<'min, 'max>(v: Box>) +LL | fn get_min_from_max<'min, 'max>(v: Box>) | ^^^^ note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 7:27 --> $DIR/variance-invariant-arg-object.rs:7:27 | -LL | fn get_min_from_max<'min, 'max>(v: Box>) +LL | fn get_min_from_max<'min, 'max>(v: Box>) | ^^^^ error[E0308]: mismatched types --> $DIR/variance-invariant-arg-object.rs:18:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `dyn Get<&'max i32>` @@ -28,12 +28,12 @@ LL | v //~ ERROR mismatched types note: the lifetime 'min as defined on the function body at 14:21... --> $DIR/variance-invariant-arg-object.rs:14:21 | -LL | fn get_max_from_min<'min, 'max, G>(v: Box>) +LL | fn get_max_from_min<'min, 'max, G>(v: Box>) | ^^^^ note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 14:27 --> $DIR/variance-invariant-arg-object.rs:14:27 | -LL | fn get_max_from_min<'min, 'max, G>(v: Box>) +LL | fn get_max_from_min<'min, 'max, G>(v: Box>) | ^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/variance/variance-invariant-arg-trait-match.nll.stderr b/src/test/ui/variance/variance-invariant-arg-trait-match.nll.stderr new file mode 100644 index 0000000000000..2ab44c54c7216 --- /dev/null +++ b/src/test/ui/variance/variance-invariant-arg-trait-match.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/variance-invariant-arg-trait-match.rs:10:5 + | +LL | fn get_min_from_max<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::() + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + +error: lifetime may not live long enough + --> $DIR/variance-invariant-arg-trait-match.rs:16:5 + | +LL | fn get_max_from_min<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::() + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-invariant-arg-trait-match.stderr b/src/test/ui/variance/variance-invariant-arg-trait-match.stderr index 32aac2e3a2b89..c8a1111e6237d 100644 --- a/src/test/ui/variance/variance-invariant-arg-trait-match.stderr +++ b/src/test/ui/variance/variance-invariant-arg-trait-match.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/variance-invariant-arg-trait-match.rs:10:5 | -LL | impls_get::() //~ ERROR mismatched types +LL | impls_get::() | ^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `Get<&'min i32>` @@ -20,7 +20,7 @@ LL | fn get_min_from_max<'min, 'max, G>() error[E0308]: mismatched types --> $DIR/variance-invariant-arg-trait-match.rs:16:5 | -LL | impls_get::() //~ ERROR mismatched types +LL | impls_get::() | ^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `Get<&'max i32>` diff --git a/src/test/ui/variance/variance-invariant-self-trait-match.nll.stderr b/src/test/ui/variance/variance-invariant-self-trait-match.nll.stderr new file mode 100644 index 0000000000000..7b7c42fea8da8 --- /dev/null +++ b/src/test/ui/variance/variance-invariant-self-trait-match.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/variance-invariant-self-trait-match.rs:10:5 + | +LL | fn get_min_from_max<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<&'min G>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + +error: lifetime may not live long enough + --> $DIR/variance-invariant-self-trait-match.rs:16:5 + | +LL | fn get_max_from_min<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<&'max G>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-invariant-self-trait-match.stderr b/src/test/ui/variance/variance-invariant-self-trait-match.stderr index ba96fbdaa14dd..cb03d95f77104 100644 --- a/src/test/ui/variance/variance-invariant-self-trait-match.stderr +++ b/src/test/ui/variance/variance-invariant-self-trait-match.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/variance-invariant-self-trait-match.rs:10:5 | -LL | impls_get::<&'min G>(); //~ ERROR mismatched types +LL | impls_get::<&'min G>(); | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `Get` @@ -20,7 +20,7 @@ LL | fn get_min_from_max<'min, 'max, G>() error[E0308]: mismatched types --> $DIR/variance-invariant-self-trait-match.rs:16:5 | -LL | impls_get::<&'max G>(); //~ ERROR mismatched types +LL | impls_get::<&'max G>(); | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `Get` diff --git a/src/test/ui/variance/variance-issue-20533.nll.stderr b/src/test/ui/variance/variance-issue-20533.nll.stderr deleted file mode 100644 index 469adaf6f0eed..0000000000000 --- a/src/test/ui/variance/variance-issue-20533.nll.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0505]: cannot move out of `a` because it is borrowed - --> $DIR/variance-issue-20533.rs:28:14 - | -LL | let x = foo(&a); - | -- borrow of `a` occurs here -LL | drop(a); //~ ERROR cannot move out of `a` - | ^ move out of `a` occurs here -LL | drop(x); - | - borrow later used here - -error[E0505]: cannot move out of `a` because it is borrowed - --> $DIR/variance-issue-20533.rs:34:14 - | -LL | let x = bar(&a); - | -- borrow of `a` occurs here -LL | drop(a); //~ ERROR cannot move out of `a` - | ^ move out of `a` occurs here -LL | drop(x); - | - borrow later used here - -error[E0505]: cannot move out of `a` because it is borrowed - --> $DIR/variance-issue-20533.rs:40:14 - | -LL | let x = baz(&a); - | -- borrow of `a` occurs here -LL | drop(a); //~ ERROR cannot move out of `a` - | ^ move out of `a` occurs here -LL | drop(x); - | - borrow later used here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/variance/variance-issue-20533.stderr b/src/test/ui/variance/variance-issue-20533.stderr index 27aca3401f92e..008e2a002bbb0 100644 --- a/src/test/ui/variance/variance-issue-20533.stderr +++ b/src/test/ui/variance/variance-issue-20533.stderr @@ -2,25 +2,31 @@ error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:28:14 | LL | let x = foo(&a); - | - borrow of `a` occurs here -LL | drop(a); //~ ERROR cannot move out of `a` + | -- borrow of `a` occurs here +LL | drop(a); | ^ move out of `a` occurs here +LL | drop(x); + | - borrow later used here error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:34:14 | LL | let x = bar(&a); - | - borrow of `a` occurs here -LL | drop(a); //~ ERROR cannot move out of `a` + | -- borrow of `a` occurs here +LL | drop(a); | ^ move out of `a` occurs here +LL | drop(x); + | - borrow later used here error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:40:14 | LL | let x = baz(&a); - | - borrow of `a` occurs here -LL | drop(a); //~ ERROR cannot move out of `a` + | -- borrow of `a` occurs here +LL | drop(a); | ^ move out of `a` occurs here +LL | drop(x); + | - borrow later used here error: aborting due to 3 previous errors diff --git a/src/test/ui/variance/variance-object-types.rs b/src/test/ui/variance/variance-object-types.rs index 12af7ae8c5b8a..14e11f681b100 100644 --- a/src/test/ui/variance/variance-object-types.rs +++ b/src/test/ui/variance/variance-object-types.rs @@ -9,7 +9,7 @@ use std::cell::Cell; // get an invariant result for `'a`. #[rustc_variance] struct Foo<'a> { //~ ERROR [o] - x: Box &'a i32 + 'static> + x: Box &'a i32 + 'static> } fn main() { diff --git a/src/test/ui/variance/variance-object-types.stderr b/src/test/ui/variance/variance-object-types.stderr index 3ba86c2620e02..d97d222e711ad 100644 --- a/src/test/ui/variance/variance-object-types.stderr +++ b/src/test/ui/variance/variance-object-types.stderr @@ -1,11 +1,10 @@ error[E0208]: [o] --> $DIR/variance-object-types.rs:11:1 | -LL | / struct Foo<'a> { //~ ERROR [o] -LL | | x: Box &'a i32 + 'static> +LL | / struct Foo<'a> { +LL | | x: Box &'a i32 + 'static> LL | | } | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0208`. diff --git a/src/test/ui/variance/variance-regions-direct.stderr b/src/test/ui/variance/variance-regions-direct.stderr index 82dc8df372689..8c9c89955bd34 100644 --- a/src/test/ui/variance/variance-regions-direct.stderr +++ b/src/test/ui/variance/variance-regions-direct.stderr @@ -1,7 +1,7 @@ error[E0208]: [-, -, -] --> $DIR/variance-regions-direct.rs:9:1 | -LL | / struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -] +LL | / struct Test2<'a, 'b, 'c> { LL | | x: &'a isize, LL | | y: &'b [isize], LL | | c: &'c str @@ -11,7 +11,7 @@ LL | | } error[E0208]: [+, +, +] --> $DIR/variance-regions-direct.rs:18:1 | -LL | / struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +] +LL | / struct Test3<'a, 'b, 'c> { LL | | x: extern "Rust" fn(&'a isize), LL | | y: extern "Rust" fn(&'b [isize]), LL | | c: extern "Rust" fn(&'c str), @@ -21,7 +21,7 @@ LL | | } error[E0208]: [-, o] --> $DIR/variance-regions-direct.rs:27:1 | -LL | / struct Test4<'a, 'b:'a> { //~ ERROR [-, o] +LL | / struct Test4<'a, 'b:'a> { LL | | x: &'a mut &'b isize, LL | | } | |_^ @@ -29,7 +29,7 @@ LL | | } error[E0208]: [+, o] --> $DIR/variance-regions-direct.rs:35:1 | -LL | / struct Test5<'a, 'b:'a> { //~ ERROR [+, o] +LL | / struct Test5<'a, 'b:'a> { LL | | x: extern "Rust" fn(&'a mut &'b isize), LL | | } | |_^ @@ -37,7 +37,7 @@ LL | | } error[E0208]: [-, o] --> $DIR/variance-regions-direct.rs:45:1 | -LL | / struct Test6<'a, 'b:'a> { //~ ERROR [-, o] +LL | / struct Test6<'a, 'b:'a> { LL | | x: &'a mut extern "Rust" fn(&'b isize), LL | | } | |_^ @@ -45,7 +45,7 @@ LL | | } error[E0208]: [*] --> $DIR/variance-regions-direct.rs:52:1 | -LL | / struct Test7<'a> { //~ ERROR [*] +LL | / struct Test7<'a> { LL | | x: isize LL | | } | |_^ @@ -53,7 +53,7 @@ LL | | } error[E0208]: [+, -, o] --> $DIR/variance-regions-direct.rs:59:1 | -LL | / enum Test8<'a, 'b, 'c:'b> { //~ ERROR [+, -, o] +LL | / enum Test8<'a, 'b, 'c:'b> { LL | | Test8A(extern "Rust" fn(&'a isize)), LL | | Test8B(&'b [isize]), LL | | Test8C(&'b mut &'c str), @@ -62,4 +62,3 @@ LL | | } error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0208`. diff --git a/src/test/ui/variance/variance-regions-indirect.stderr b/src/test/ui/variance/variance-regions-indirect.stderr index 401fa2f3baa3a..17efc6231d5e7 100644 --- a/src/test/ui/variance/variance-regions-indirect.stderr +++ b/src/test/ui/variance/variance-regions-indirect.stderr @@ -1,7 +1,7 @@ error[E0208]: [+, -, o, *] --> $DIR/variance-regions-indirect.rs:8:1 | -LL | / enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *] +LL | / enum Base<'a, 'b, 'c:'b, 'd> { LL | | Test8A(extern "Rust" fn(&'a isize)), LL | | Test8B(&'b [isize]), LL | | Test8C(&'b mut &'c str), @@ -11,7 +11,7 @@ LL | | } error[E0208]: [*, o, -, +] --> $DIR/variance-regions-indirect.rs:15:1 | -LL | / struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, -, +] +LL | / struct Derived1<'w, 'x:'y, 'y, 'z> { LL | | f: Base<'z, 'y, 'x, 'w> LL | | } | |_^ @@ -19,7 +19,7 @@ LL | | } error[E0208]: [o, o, *] --> $DIR/variance-regions-indirect.rs:20:1 | -LL | / struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *] +LL | / struct Derived2<'a, 'b:'a, 'c> { LL | | f: Base<'a, 'a, 'b, 'c> LL | | } | |_^ @@ -27,7 +27,7 @@ LL | | } error[E0208]: [o, -, *] --> $DIR/variance-regions-indirect.rs:25:1 | -LL | / struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, -, *] +LL | / struct Derived3<'a:'b, 'b, 'c> { LL | | f: Base<'a, 'b, 'a, 'c> LL | | } | |_^ @@ -35,11 +35,10 @@ LL | | } error[E0208]: [+, -, o] --> $DIR/variance-regions-indirect.rs:30:1 | -LL | / struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [+, -, o] +LL | / struct Derived4<'a, 'b, 'c:'b> { LL | | f: Base<'a, 'b, 'c, 'a> LL | | } | |_^ error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0208`. diff --git a/src/test/ui/variance/variance-regions-unused-direct.stderr b/src/test/ui/variance/variance-regions-unused-direct.stderr index 207cc9147f1c3..21ff475663c6c 100644 --- a/src/test/ui/variance/variance-regions-unused-direct.stderr +++ b/src/test/ui/variance/variance-regions-unused-direct.stderr @@ -1,16 +1,16 @@ error[E0392]: parameter `'a` is never used --> $DIR/variance-regions-unused-direct.rs:5:18 | -LL | struct Bivariant<'a>; //~ ERROR parameter `'a` is never used - | ^^ unused type parameter +LL | struct Bivariant<'a>; + | ^^ unused parameter | = help: consider removing `'a` or using a marker such as `std::marker::PhantomData` error[E0392]: parameter `'d` is never used --> $DIR/variance-regions-unused-direct.rs:7:19 | -LL | struct Struct<'a, 'd> { //~ ERROR parameter `'d` is never used - | ^^ unused type parameter +LL | struct Struct<'a, 'd> { + | ^^ unused parameter | = help: consider removing `'d` or using a marker such as `std::marker::PhantomData` diff --git a/src/test/ui/variance/variance-regions-unused-indirect.stderr b/src/test/ui/variance/variance-regions-unused-indirect.stderr index 08d1189ea2c9d..fd66217f692f1 100644 --- a/src/test/ui/variance/variance-regions-unused-indirect.stderr +++ b/src/test/ui/variance/variance-regions-unused-indirect.stderr @@ -1,16 +1,16 @@ error[E0392]: parameter `'a` is never used --> $DIR/variance-regions-unused-indirect.rs:3:10 | -LL | enum Foo<'a> { //~ ERROR parameter `'a` is never used - | ^^ unused type parameter +LL | enum Foo<'a> { + | ^^ unused parameter | = help: consider removing `'a` or using a marker such as `std::marker::PhantomData` error[E0392]: parameter `'a` is never used --> $DIR/variance-regions-unused-indirect.rs:7:10 | -LL | enum Bar<'a> { //~ ERROR parameter `'a` is never used - | ^^ unused type parameter +LL | enum Bar<'a> { + | ^^ unused parameter | = help: consider removing `'a` or using a marker such as `std::marker::PhantomData` diff --git a/src/test/ui/variance/variance-trait-bounds.stderr b/src/test/ui/variance/variance-trait-bounds.stderr index 1fabadabbcbbf..98bc1b003c39d 100644 --- a/src/test/ui/variance/variance-trait-bounds.stderr +++ b/src/test/ui/variance/variance-trait-bounds.stderr @@ -1,7 +1,7 @@ error[E0208]: [+, +] --> $DIR/variance-trait-bounds.rs:16:1 | -LL | / struct TestStruct> { //~ ERROR [+, +] +LL | / struct TestStruct> { LL | | t: T, u: U LL | | } | |_^ @@ -9,7 +9,7 @@ LL | | } error[E0208]: [*, +] --> $DIR/variance-trait-bounds.rs:21:1 | -LL | / enum TestEnum> { //~ ERROR [*, +] +LL | / enum TestEnum> { LL | | Foo(T) LL | | } | |_^ @@ -17,7 +17,7 @@ LL | | } error[E0208]: [*, +] --> $DIR/variance-trait-bounds.rs:26:1 | -LL | / struct TestContraStruct> { //~ ERROR [*, +] +LL | / struct TestContraStruct> { LL | | t: T LL | | } | |_^ @@ -25,11 +25,10 @@ LL | | } error[E0208]: [*, +] --> $DIR/variance-trait-bounds.rs:31:1 | -LL | / struct TestBox+Setter> { //~ ERROR [*, +] +LL | / struct TestBox+Setter> { LL | | t: T LL | | } | |_^ error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0208`. diff --git a/src/test/ui/variance/variance-trait-matching.nll.stderr b/src/test/ui/variance/variance-trait-matching.nll.stderr new file mode 100644 index 0000000000000..3308cc6d25016 --- /dev/null +++ b/src/test/ui/variance/variance-trait-matching.nll.stderr @@ -0,0 +1,12 @@ +error[E0621]: explicit lifetime required in the type of `get` + --> $DIR/variance-trait-matching.rs:24:5 + | +LL | fn get<'a, G>(get: &G) -> i32 + | -- help: add explicit lifetime `'a` to the type of `get`: `&'a G` +... +LL | pick(get, &22) + | ^^^^^^^^^^^^^^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/variance/variance-trait-matching.stderr b/src/test/ui/variance/variance-trait-matching.stderr index 2d11515a19c0e..514153103bea3 100644 --- a/src/test/ui/variance/variance-trait-matching.stderr +++ b/src/test/ui/variance/variance-trait-matching.stderr @@ -4,7 +4,7 @@ error[E0621]: explicit lifetime required in the type of `get` LL | fn get<'a, G>(get: &G) -> i32 | -- help: add explicit lifetime `'a` to the type of `get`: `&'a G` ... -LL | pick(get, &22) //~ ERROR explicit lifetime required in the type of `get` [E0621] +LL | pick(get, &22) | ^^^^ lifetime `'a` required error: aborting due to previous error diff --git a/src/test/ui/variance/variance-trait-object-bound.rs b/src/test/ui/variance/variance-trait-object-bound.rs index ada93b7f6efc7..ec3c973bc7639 100644 --- a/src/test/ui/variance/variance-trait-object-bound.rs +++ b/src/test/ui/variance/variance-trait-object-bound.rs @@ -12,7 +12,7 @@ trait T { fn foo(&self); } #[rustc_variance] struct TOption<'a> { //~ ERROR [-] - v: Option>, + v: Option>, } fn main() { } diff --git a/src/test/ui/variance/variance-trait-object-bound.stderr b/src/test/ui/variance/variance-trait-object-bound.stderr index c824f5a6db731..fb0fab1950cef 100644 --- a/src/test/ui/variance/variance-trait-object-bound.stderr +++ b/src/test/ui/variance/variance-trait-object-bound.stderr @@ -1,11 +1,10 @@ error[E0208]: [-] --> $DIR/variance-trait-object-bound.rs:14:1 | -LL | / struct TOption<'a> { //~ ERROR [-] -LL | | v: Option>, +LL | / struct TOption<'a> { +LL | | v: Option>, LL | | } | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0208`. diff --git a/src/test/ui/variance/variance-types-bounds.rs b/src/test/ui/variance/variance-types-bounds.rs index 5cbda10fbdeda..d1814dd97a0ad 100644 --- a/src/test/ui/variance/variance-types-bounds.rs +++ b/src/test/ui/variance/variance-types-bounds.rs @@ -36,8 +36,8 @@ trait Setter { #[rustc_variance] struct TestObject { //~ ERROR [o, o] - n: Box+Send>, - m: Box+Send>, + n: Box+Send>, + m: Box+Send>, } fn main() {} diff --git a/src/test/ui/variance/variance-types-bounds.stderr b/src/test/ui/variance/variance-types-bounds.stderr index 31271952f776f..5cffdffc7f2d4 100644 --- a/src/test/ui/variance/variance-types-bounds.stderr +++ b/src/test/ui/variance/variance-types-bounds.stderr @@ -1,7 +1,7 @@ error[E0208]: [+, +] --> $DIR/variance-types-bounds.rs:7:1 | -LL | / struct TestImm { //~ ERROR [+, +] +LL | / struct TestImm { LL | | x: A, LL | | y: B, LL | | } @@ -10,7 +10,7 @@ LL | | } error[E0208]: [+, o] --> $DIR/variance-types-bounds.rs:13:1 | -LL | / struct TestMut { //~ ERROR [+, o] +LL | / struct TestMut { LL | | x: A, LL | | y: &'static mut B, LL | | } @@ -19,7 +19,7 @@ LL | | } error[E0208]: [+, o] --> $DIR/variance-types-bounds.rs:19:1 | -LL | / struct TestIndirect { //~ ERROR [+, o] +LL | / struct TestIndirect { LL | | m: TestMut LL | | } | |_^ @@ -27,7 +27,7 @@ LL | | } error[E0208]: [o, o] --> $DIR/variance-types-bounds.rs:24:1 | -LL | / struct TestIndirect2 { //~ ERROR [o, o] +LL | / struct TestIndirect2 { LL | | n: TestMut, LL | | m: TestMut LL | | } @@ -36,12 +36,11 @@ LL | | } error[E0208]: [o, o] --> $DIR/variance-types-bounds.rs:38:1 | -LL | / struct TestObject { //~ ERROR [o, o] -LL | | n: Box+Send>, -LL | | m: Box+Send>, +LL | / struct TestObject { +LL | | n: Box+Send>, +LL | | m: Box+Send>, LL | | } | |_^ error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0208`. diff --git a/src/test/ui/variance/variance-types.stderr b/src/test/ui/variance/variance-types.stderr index 4362f69420261..05bd4747cf168 100644 --- a/src/test/ui/variance/variance-types.stderr +++ b/src/test/ui/variance/variance-types.stderr @@ -1,7 +1,7 @@ error[E0208]: [-, o, o] --> $DIR/variance-types.rs:10:1 | -LL | / struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [-, o, o] +LL | / struct InvariantMut<'a,A:'a,B:'a> { LL | | t: &'a mut (A,B) LL | | } | |_^ @@ -9,7 +9,7 @@ LL | | } error[E0208]: [o] --> $DIR/variance-types.rs:15:1 | -LL | / struct InvariantCell { //~ ERROR [o] +LL | / struct InvariantCell { LL | | t: Cell LL | | } | |_^ @@ -17,7 +17,7 @@ LL | | } error[E0208]: [o] --> $DIR/variance-types.rs:20:1 | -LL | / struct InvariantIndirect { //~ ERROR [o] +LL | / struct InvariantIndirect { LL | | t: InvariantCell LL | | } | |_^ @@ -25,7 +25,7 @@ LL | | } error[E0208]: [+] --> $DIR/variance-types.rs:25:1 | -LL | / struct Covariant { //~ ERROR [+] +LL | / struct Covariant { LL | | t: A, u: fn() -> A LL | | } | |_^ @@ -33,7 +33,7 @@ LL | | } error[E0208]: [-] --> $DIR/variance-types.rs:30:1 | -LL | / struct Contravariant { //~ ERROR [-] +LL | / struct Contravariant { LL | | t: fn(A) LL | | } | |_^ @@ -41,7 +41,7 @@ LL | | } error[E0208]: [+, -, o] --> $DIR/variance-types.rs:35:1 | -LL | / enum Enum { //~ ERROR [+, -, o] +LL | / enum Enum { LL | | Foo(Covariant), LL | | Bar(Contravariant), LL | | Zed(Covariant,Contravariant) @@ -50,4 +50,3 @@ LL | | } error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0208`. diff --git a/src/test/ui/variance/variance-unused-region-param.stderr b/src/test/ui/variance/variance-unused-region-param.stderr index 9cd133bbc937b..a96b2338bf428 100644 --- a/src/test/ui/variance/variance-unused-region-param.stderr +++ b/src/test/ui/variance/variance-unused-region-param.stderr @@ -1,16 +1,16 @@ error[E0392]: parameter `'a` is never used --> $DIR/variance-unused-region-param.rs:3:19 | -LL | struct SomeStruct<'a> { x: u32 } //~ ERROR parameter `'a` is never used - | ^^ unused type parameter +LL | struct SomeStruct<'a> { x: u32 } + | ^^ unused parameter | = help: consider removing `'a` or using a marker such as `std::marker::PhantomData` error[E0392]: parameter `'a` is never used --> $DIR/variance-unused-region-param.rs:4:15 | -LL | enum SomeEnum<'a> { Nothing } //~ ERROR parameter `'a` is never used - | ^^ unused type parameter +LL | enum SomeEnum<'a> { Nothing } + | ^^ unused parameter | = help: consider removing `'a` or using a marker such as `std::marker::PhantomData` diff --git a/src/test/ui/variance/variance-unused-type-param.stderr b/src/test/ui/variance/variance-unused-type-param.stderr index 34c430f5498da..883db46298624 100644 --- a/src/test/ui/variance/variance-unused-type-param.stderr +++ b/src/test/ui/variance/variance-unused-type-param.stderr @@ -2,7 +2,7 @@ error[E0392]: parameter `A` is never used --> $DIR/variance-unused-type-param.rs:6:19 | LL | struct SomeStruct { x: u32 } - | ^ unused type parameter + | ^ unused parameter | = help: consider removing `A` or using a marker such as `std::marker::PhantomData` @@ -10,7 +10,7 @@ error[E0392]: parameter `A` is never used --> $DIR/variance-unused-type-param.rs:9:15 | LL | enum SomeEnum { Nothing } - | ^ unused type parameter + | ^ unused parameter | = help: consider removing `A` or using a marker such as `std::marker::PhantomData` @@ -18,7 +18,7 @@ error[E0392]: parameter `T` is never used --> $DIR/variance-unused-type-param.rs:13:15 | LL | enum ListCell { - | ^ unused type parameter + | ^ unused parameter | = help: consider removing `T` or using a marker such as `std::marker::PhantomData` diff --git a/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr new file mode 100644 index 0000000000000..8468448b27bd2 --- /dev/null +++ b/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/variance-use-contravariant-struct-1.rs:12:5 + | +LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ returning this value requires that `'min` must outlive `'max` + +error: aborting due to previous error + diff --git a/src/test/ui/variance/variance-use-contravariant-struct-1.stderr b/src/test/ui/variance/variance-use-contravariant-struct-1.stderr index 89a49a00b34e6..7c433378df5c3 100644 --- a/src/test/ui/variance/variance-use-contravariant-struct-1.stderr +++ b/src/test/ui/variance/variance-use-contravariant-struct-1.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/variance-use-contravariant-struct-1.rs:12:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `SomeStruct<&'min ()>` diff --git a/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr new file mode 100644 index 0000000000000..19a22f064beb0 --- /dev/null +++ b/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr @@ -0,0 +1,13 @@ +error: lifetime may not live long enough + --> $DIR/variance-use-covariant-struct-1.rs:10:5 + | +LL | fn foo<'min,'max>(v: SomeStruct<&'min ()>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ returning this value requires that `'min` must outlive `'max` + +error: aborting due to previous error + diff --git a/src/test/ui/variance/variance-use-covariant-struct-1.stderr b/src/test/ui/variance/variance-use-covariant-struct-1.stderr index a6f298c9bfbe0..6ae7d12c4633f 100644 --- a/src/test/ui/variance/variance-use-covariant-struct-1.stderr +++ b/src/test/ui/variance/variance-use-covariant-struct-1.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/variance-use-covariant-struct-1.rs:10:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `SomeStruct<&'max ()>` diff --git a/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr new file mode 100644 index 0000000000000..61f80fe77e63d --- /dev/null +++ b/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/variance-use-invariant-struct-1.rs:12:5 + | +LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ returning this value requires that `'min` must outlive `'max` + +error: lifetime may not live long enough + --> $DIR/variance-use-invariant-struct-1.rs:19:5 + | +LL | fn bar<'min,'max>(v: SomeStruct<&'min ()>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ returning this value requires that `'min` must outlive `'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-use-invariant-struct-1.stderr b/src/test/ui/variance/variance-use-invariant-struct-1.stderr index 2bd39d5a831f2..793954e3a1f04 100644 --- a/src/test/ui/variance/variance-use-invariant-struct-1.stderr +++ b/src/test/ui/variance/variance-use-invariant-struct-1.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/variance-use-invariant-struct-1.rs:12:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `SomeStruct<&'min ()>` @@ -20,7 +20,7 @@ LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>) error[E0308]: mismatched types --> $DIR/variance-use-invariant-struct-1.rs:19:5 | -LL | v //~ ERROR mismatched types +LL | v | ^ lifetime mismatch | = note: expected type `SomeStruct<&'max ()>` diff --git a/src/test/ui/variants/variant-size-differences.stderr b/src/test/ui/variants/variant-size-differences.stderr index 5cd168df53824..c82c253f610d0 100644 --- a/src/test/ui/variants/variant-size-differences.stderr +++ b/src/test/ui/variants/variant-size-differences.stderr @@ -1,7 +1,7 @@ error: enum variant is more than three times larger (1024 bytes) than the next largest --> $DIR/variant-size-differences.rs:5:5 | -LL | VBig([u8; 1024]), //~ ERROR variant is more than three times larger +LL | VBig([u8; 1024]), | ^^^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/variants/variant-used-as-type.stderr b/src/test/ui/variants/variant-used-as-type.stderr index fdfc044d81f6c..1138b69ae3bc3 100644 --- a/src/test/ui/variants/variant-used-as-type.stderr +++ b/src/test/ui/variants/variant-used-as-type.stderr @@ -24,4 +24,3 @@ LL | impl Ty {} error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0573`. diff --git a/src/test/ui/vec/vec-macro-with-comma-only.stderr b/src/test/ui/vec/vec-macro-with-comma-only.stderr index 92e704c3fb4b3..abbee347c00bc 100644 --- a/src/test/ui/vec/vec-macro-with-comma-only.stderr +++ b/src/test/ui/vec/vec-macro-with-comma-only.stderr @@ -1,7 +1,7 @@ error: no rules expected the token `,` --> $DIR/vec-macro-with-comma-only.rs:2:10 | -LL | vec![,]; //~ ERROR no rules expected the token `,` +LL | vec![,]; | ^ no rules expected this token in macro call error: aborting due to previous error diff --git a/src/test/ui/vec/vec-mut-iter-borrow.nll.stderr b/src/test/ui/vec/vec-mut-iter-borrow.nll.stderr deleted file mode 100644 index c77be26f01938..0000000000000 --- a/src/test/ui/vec/vec-mut-iter-borrow.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0499]: cannot borrow `xs` as mutable more than once at a time - --> $DIR/vec-mut-iter-borrow.rs:5:9 - | -LL | for x in &mut xs { - | ------- - | | - | first mutable borrow occurs here - | first borrow later used here -LL | xs.push(1) //~ ERROR cannot borrow `xs` - | ^^ second mutable borrow occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/vec/vec-mut-iter-borrow.stderr b/src/test/ui/vec/vec-mut-iter-borrow.stderr index 9b4b56737915a..679fd8997733b 100644 --- a/src/test/ui/vec/vec-mut-iter-borrow.stderr +++ b/src/test/ui/vec/vec-mut-iter-borrow.stderr @@ -2,11 +2,11 @@ error[E0499]: cannot borrow `xs` as mutable more than once at a time --> $DIR/vec-mut-iter-borrow.rs:5:9 | LL | for x in &mut xs { - | -- - | || - | |first borrow ends here - | first mutable borrow occurs here -LL | xs.push(1) //~ ERROR cannot borrow `xs` + | ------- + | | + | first mutable borrow occurs here + | first borrow later used here +LL | xs.push(1) | ^^ second mutable borrow occurs here error: aborting due to previous error diff --git a/src/test/ui/vec/vec-res-add.stderr b/src/test/ui/vec/vec-res-add.stderr index 39552697631db..78b70f09e9005 100644 --- a/src/test/ui/vec/vec-res-add.stderr +++ b/src/test/ui/vec/vec-res-add.stderr @@ -1,8 +1,10 @@ error[E0369]: binary operation `+` cannot be applied to type `std::vec::Vec` - --> $DIR/vec-res-add.rs:16:13 + --> $DIR/vec-res-add.rs:16:15 | LL | let k = i + j; - | ^^^^^ + | - ^ - std::vec::Vec + | | + | std::vec::Vec | = note: an implementation of `std::ops::Add` might be missing for `std::vec::Vec` diff --git a/src/test/ui/vector-cast-weirdness.stderr b/src/test/ui/vector-cast-weirdness.stderr index 330b87801ebb0..37055bb75f559 100644 --- a/src/test/ui/vector-cast-weirdness.stderr +++ b/src/test/ui/vector-cast-weirdness.stderr @@ -1,7 +1,7 @@ error[E0606]: casting `&mut [u8; 2]` as `*mut u8` is invalid --> $DIR/vector-cast-weirdness.rs:21:23 | -LL | let p1: *mut u8 = &mut x1.y as *mut _; //~ ERROR casting +LL | let p1: *mut u8 = &mut x1.y as *mut _; | ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/vector-no-ann.rs b/src/test/ui/vector-no-ann.rs index 200364a5d937e..1f11d9c8dffc7 100644 --- a/src/test/ui/vector-no-ann.rs +++ b/src/test/ui/vector-no-ann.rs @@ -1,4 +1,4 @@ fn main() { let _foo = Vec::new(); - //~^ ERROR type annotations needed [E0282] + //~^ ERROR type annotations needed } diff --git a/src/test/ui/vector-no-ann.stderr b/src/test/ui/vector-no-ann.stderr index 01b569f97f910..28100d7c89e71 100644 --- a/src/test/ui/vector-no-ann.stderr +++ b/src/test/ui/vector-no-ann.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `std::vec::Vec` --> $DIR/vector-no-ann.rs:2:16 | LL | let _foo = Vec::new(); | ---- ^^^^^^^^ cannot infer type for `T` | | - | consider giving `_foo` a type + | consider giving `_foo` the explicit type `std::vec::Vec`, where the type parameter `T` is specified error: aborting due to previous error diff --git a/src/test/ui/vtable-res-trait-param.stderr b/src/test/ui/vtable-res-trait-param.stderr index 6dac9fe335f69..58a88979b2faf 100644 --- a/src/test/ui/vtable-res-trait-param.stderr +++ b/src/test/ui/vtable-res-trait-param.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `{integer}: TraitA` is not satisfied --> $DIR/vtable-res-trait-param.rs:17:7 | -LL | b.gimme_an_a(y) //~ ERROR `{integer}: TraitA` is not satisfied +LL | b.gimme_an_a(y) | ^^^^^^^^^^ the trait `TraitA` is not implemented for `{integer}` error: aborting due to previous error diff --git a/src/test/ui/walk-struct-literal-with.nll.stderr b/src/test/ui/walk-struct-literal-with.nll.stderr deleted file mode 100644 index 2263747607b9c..0000000000000 --- a/src/test/ui/walk-struct-literal-with.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: borrow of moved value: `start` - --> $DIR/walk-struct-literal-with.rs:16:20 - | -LL | let start = Mine{test:"Foo".to_string(), other_val:0}; - | ----- move occurs because `start` has type `Mine`, which does not implement the `Copy` trait -LL | let end = Mine{other_val:1, ..start.make_string_bar()}; - | ----- value moved here -LL | println!("{}", start.test); //~ ERROR use of moved value: `start.test` - | ^^^^^^^^^^ value borrowed here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/walk-struct-literal-with.rs b/src/test/ui/walk-struct-literal-with.rs index 31dfd58fa98d2..ee1a77eb9a48a 100644 --- a/src/test/ui/walk-struct-literal-with.rs +++ b/src/test/ui/walk-struct-literal-with.rs @@ -13,5 +13,5 @@ impl Mine{ fn main(){ let start = Mine{test:"Foo".to_string(), other_val:0}; let end = Mine{other_val:1, ..start.make_string_bar()}; - println!("{}", start.test); //~ ERROR use of moved value: `start.test` + println!("{}", start.test); //~ ERROR borrow of moved value: `start` } diff --git a/src/test/ui/walk-struct-literal-with.stderr b/src/test/ui/walk-struct-literal-with.stderr index 9362301b4081d..eeb594a21f38c 100644 --- a/src/test/ui/walk-struct-literal-with.stderr +++ b/src/test/ui/walk-struct-literal-with.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `start.test` +error[E0382]: borrow of moved value: `start` --> $DIR/walk-struct-literal-with.rs:16:20 | +LL | let start = Mine{test:"Foo".to_string(), other_val:0}; + | ----- move occurs because `start` has type `Mine`, which does not implement the `Copy` trait LL | let end = Mine{other_val:1, ..start.make_string_bar()}; | ----- value moved here -LL | println!("{}", start.test); //~ ERROR use of moved value: `start.test` - | ^^^^^^^^^^ value used here after move - | - = note: move occurs because `start` has type `Mine`, which does not implement the `Copy` trait +LL | println!("{}", start.test); + | ^^^^^^^^^^ value borrowed here after move error: aborting due to previous error diff --git a/src/test/ui/warn-path-statement.stderr b/src/test/ui/warn-path-statement.stderr index 55d33058c17fa..30afb99e5f02c 100644 --- a/src/test/ui/warn-path-statement.stderr +++ b/src/test/ui/warn-path-statement.stderr @@ -1,7 +1,7 @@ error: path statement with no effect --> $DIR/warn-path-statement.rs:5:5 | -LL | x; //~ ERROR path statement with no effect +LL | x; | ^^ | = note: requested on the command line with `-D path-statements` diff --git a/src/test/ui/wasm-custom-section-relocations.stderr b/src/test/ui/wasm-custom-section-relocations.stderr index 272dd8d524d68..eb8ab2644a330 100644 --- a/src/test/ui/wasm-custom-section-relocations.stderr +++ b/src/test/ui/wasm-custom-section-relocations.stderr @@ -1,13 +1,13 @@ error: statics with a custom `#[link_section]` must be a simple list of bytes on the wasm target with no extra levels of indirection such as references --> $DIR/wasm-custom-section-relocations.rs:4:1 | -LL | pub static A: &[u8] = &[1]; //~ ERROR: no extra levels of indirection +LL | pub static A: &[u8] = &[1]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: statics with a custom `#[link_section]` must be a simple list of bytes on the wasm target with no extra levels of indirection such as references --> $DIR/wasm-custom-section-relocations.rs:13:1 | -LL | pub static D: &usize = &C; //~ ERROR: no extra levels of indirection +LL | pub static D: &usize = &C; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/wasm-import-module.rs b/src/test/ui/wasm-import-module.rs index 618bf1952aa5d..16d628a618744 100644 --- a/src/test/ui/wasm-import-module.rs +++ b/src/test/ui/wasm-import-module.rs @@ -8,4 +8,3 @@ extern {} extern {} fn main() {} - diff --git a/src/test/ui/wasm-import-module.stderr b/src/test/ui/wasm-import-module.stderr index a3955bb676e93..20eec4c9f59bf 100644 --- a/src/test/ui/wasm-import-module.stderr +++ b/src/test/ui/wasm-import-module.stderr @@ -1,19 +1,19 @@ error: must be of the form #[link(wasm_import_module = "...")] --> $DIR/wasm-import-module.rs:1:22 | -LL | #[link(name = "...", wasm_import_module)] //~ ERROR: must be of the form +LL | #[link(name = "...", wasm_import_module)] | ^^^^^^^^^^^^^^^^^^ error: must be of the form #[link(wasm_import_module = "...")] --> $DIR/wasm-import-module.rs:4:22 | -LL | #[link(name = "...", wasm_import_module(x))] //~ ERROR: must be of the form +LL | #[link(name = "...", wasm_import_module(x))] | ^^^^^^^^^^^^^^^^^^^^^ error: must be of the form #[link(wasm_import_module = "...")] --> $DIR/wasm-import-module.rs:7:22 | -LL | #[link(name = "...", wasm_import_module())] //~ ERROR: must be of the form +LL | #[link(name = "...", wasm_import_module())] | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/wf/wf-array-elem-sized.stderr b/src/test/ui/wf/wf-array-elem-sized.stderr index 69df9ea7857d5..b222d07580eaf 100644 --- a/src/test/ui/wf/wf-array-elem-sized.stderr +++ b/src/test/ui/wf/wf-array-elem-sized.stderr @@ -1,7 +1,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/wf-array-elem-sized.rs:7:5 | -LL | foo: [[u8]], //~ ERROR E0277 +LL | foo: [[u8]], | ^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` diff --git a/src/test/ui/wf/wf-enum-bound.stderr b/src/test/ui/wf/wf-enum-bound.stderr index 487592dcaca62..de28a882f13c3 100644 --- a/src/test/ui/wf/wf-enum-bound.stderr +++ b/src/test/ui/wf/wf-enum-bound.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-enum-bound.rs:9:1 | -LL | / enum SomeEnum //~ ERROR E0277 +LL | / enum SomeEnum LL | | where T: ExtraCopy LL | | { LL | | SomeVariant(T,U) diff --git a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr index f4b8ec0c66874..6c1267cf7e1b4 100644 --- a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr +++ b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied --> $DIR/wf-enum-fields-struct-variant.rs:13:9 | -LL | f: IsCopy //~ ERROR E0277 +LL | f: IsCopy | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` | = help: consider adding a `where A: std::marker::Copy` bound diff --git a/src/test/ui/wf/wf-enum-fields.stderr b/src/test/ui/wf/wf-enum-fields.stderr index 600dd3dc03def..9c4eec6c5fbf0 100644 --- a/src/test/ui/wf/wf-enum-fields.stderr +++ b/src/test/ui/wf/wf-enum-fields.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied --> $DIR/wf-enum-fields.rs:12:17 | -LL | SomeVariant(IsCopy) //~ ERROR E0277 +LL | SomeVariant(IsCopy) | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` | = help: consider adding a `where A: std::marker::Copy` bound diff --git a/src/test/ui/wf/wf-fn-where-clause.stderr b/src/test/ui/wf/wf-fn-where-clause.stderr index 594ce7d2f49ca..b50e895d8655c 100644 --- a/src/test/ui/wf/wf-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-fn-where-clause.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-fn-where-clause.rs:8:1 | -LL | / fn foo() where T: ExtraCopy //~ ERROR E0277 +LL | / fn foo() where T: ExtraCopy LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` @@ -33,5 +33,5 @@ LL | fn bar() where Vec:, {} error: aborting due to 3 previous errors -Some errors occurred: E0038, E0277. +Some errors have detailed explanations: E0038, E0277. For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/wf/wf-impl-associated-type-region.stderr b/src/test/ui/wf/wf-impl-associated-type-region.stderr index de7e8fa9a28af..9cc36025305f6 100644 --- a/src/test/ui/wf/wf-impl-associated-type-region.stderr +++ b/src/test/ui/wf/wf-impl-associated-type-region.stderr @@ -3,13 +3,13 @@ error[E0309]: the parameter type `T` may not live long enough | LL | impl<'a, T> Foo<'a> for T { | - help: consider adding an explicit lifetime bound `T: 'a`... -LL | type Bar = &'a T; //~ ERROR E0309 +LL | type Bar = &'a T; | ^^^^^^^^^^^^^^^^^ | note: ...so that the reference type `&'a T` does not outlive the data it points at --> $DIR/wf-impl-associated-type-region.rs:10:5 | -LL | type Bar = &'a T; //~ ERROR E0309 +LL | type Bar = &'a T; | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-arg.stderr b/src/test/ui/wf/wf-in-fn-arg.stderr index 987984060e698..8635dad851667 100644 --- a/src/test/ui/wf/wf-in-fn-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-arg.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-in-fn-arg.rs:10:1 | -LL | / fn bar(_: &MustBeCopy) //~ ERROR E0277 +LL | / fn bar(_: &MustBeCopy) LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `T` diff --git a/src/test/ui/wf/wf-in-fn-ret.stderr b/src/test/ui/wf/wf-in-fn-ret.stderr index 81aae855b8439..3879f7b0a4bf0 100644 --- a/src/test/ui/wf/wf-in-fn-ret.stderr +++ b/src/test/ui/wf/wf-in-fn-ret.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-in-fn-ret.rs:10:1 | -LL | / fn bar() -> MustBeCopy //~ ERROR E0277 +LL | / fn bar() -> MustBeCopy LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `T` diff --git a/src/test/ui/wf/wf-in-fn-type-arg.stderr b/src/test/ui/wf/wf-in-fn-type-arg.stderr index e60529dba1ed2..40cb4a7050cca 100644 --- a/src/test/ui/wf/wf-in-fn-type-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-type-arg.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-in-fn-type-arg.rs:9:5 | -LL | x: fn(MustBeCopy) //~ ERROR E0277 +LL | x: fn(MustBeCopy) | ^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound diff --git a/src/test/ui/wf/wf-in-fn-type-ret.stderr b/src/test/ui/wf/wf-in-fn-type-ret.stderr index 9f18a00926d7b..059f164e25c28 100644 --- a/src/test/ui/wf/wf-in-fn-type-ret.stderr +++ b/src/test/ui/wf/wf-in-fn-type-ret.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-in-fn-type-ret.rs:9:5 | -LL | x: fn() -> MustBeCopy //~ ERROR E0277 +LL | x: fn() -> MustBeCopy | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound diff --git a/src/test/ui/wf/wf-in-fn-type-static.stderr b/src/test/ui/wf/wf-in-fn-type-static.stderr index 1fabfb04adde3..8952c78aacd71 100644 --- a/src/test/ui/wf/wf-in-fn-type-static.stderr +++ b/src/test/ui/wf/wf-in-fn-type-static.stderr @@ -4,13 +4,13 @@ error[E0310]: the parameter type `T` may not live long enough LL | struct Foo { | - help: consider adding an explicit lifetime bound `T: 'static`... LL | // needs T: 'static -LL | x: fn() -> &'static T //~ ERROR E0310 +LL | x: fn() -> &'static T | ^^^^^^^^^^^^^^^^^^^^^ | note: ...so that the reference type `&'static T` does not outlive the data it points at --> $DIR/wf-in-fn-type-static.rs:13:5 | -LL | x: fn() -> &'static T //~ ERROR E0310 +LL | x: fn() -> &'static T | ^^^^^^^^^^^^^^^^^^^^^ error[E0310]: the parameter type `T` may not live long enough @@ -19,13 +19,13 @@ error[E0310]: the parameter type `T` may not live long enough LL | struct Bar { | - help: consider adding an explicit lifetime bound `T: 'static`... LL | // needs T: Copy -LL | x: fn(&'static T) //~ ERROR E0310 +LL | x: fn(&'static T) | ^^^^^^^^^^^^^^^^^ | note: ...so that the reference type `&'static T` does not outlive the data it points at --> $DIR/wf-in-fn-type-static.rs:18:5 | -LL | x: fn(&'static T) //~ ERROR E0310 +LL | x: fn(&'static T) | ^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/wf/wf-in-fn-where-clause.stderr b/src/test/ui/wf/wf-in-fn-where-clause.stderr index 8d6700e357145..1e732a3341c0b 100644 --- a/src/test/ui/wf/wf-in-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-in-fn-where-clause.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-in-fn-where-clause.rs:9:1 | -LL | / fn bar() //~ ERROR E0277 +LL | / fn bar() LL | | where T: MustBeCopy LL | | { LL | | } diff --git a/src/test/ui/wf/wf-in-obj-type-static.rs b/src/test/ui/wf/wf-in-obj-type-static.rs index 858a75ab1ab5a..1ad2fd1edb3b8 100644 --- a/src/test/ui/wf/wf-in-obj-type-static.rs +++ b/src/test/ui/wf/wf-in-obj-type-static.rs @@ -11,7 +11,7 @@ struct MustBeCopy { struct Foo { // needs T: 'static - x: Object<&'static T> //~ ERROR E0310 + x: dyn Object<&'static T> //~ ERROR E0310 } diff --git a/src/test/ui/wf/wf-in-obj-type-static.stderr b/src/test/ui/wf/wf-in-obj-type-static.stderr index 9e0628e3ec610..c461da76a2576 100644 --- a/src/test/ui/wf/wf-in-obj-type-static.stderr +++ b/src/test/ui/wf/wf-in-obj-type-static.stderr @@ -4,14 +4,14 @@ error[E0310]: the parameter type `T` may not live long enough LL | struct Foo { | - help: consider adding an explicit lifetime bound `T: 'static`... LL | // needs T: 'static -LL | x: Object<&'static T> //~ ERROR E0310 - | ^^^^^^^^^^^^^^^^^^^^^ +LL | x: dyn Object<&'static T> + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...so that the reference type `&'static T` does not outlive the data it points at --> $DIR/wf-in-obj-type-static.rs:14:5 | -LL | x: Object<&'static T> //~ ERROR E0310 - | ^^^^^^^^^^^^^^^^^^^^^ +LL | x: dyn Object<&'static T> + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-obj-type-trait.rs b/src/test/ui/wf/wf-in-obj-type-trait.rs index fad1da199ea91..170fad55f8f65 100644 --- a/src/test/ui/wf/wf-in-obj-type-trait.rs +++ b/src/test/ui/wf/wf-in-obj-type-trait.rs @@ -8,7 +8,7 @@ struct MustBeCopy { struct Bar { // needs T: Copy - x: Object> //~ ERROR E0277 + x: dyn Object> //~ ERROR E0277 } fn main() { } diff --git a/src/test/ui/wf/wf-in-obj-type-trait.stderr b/src/test/ui/wf/wf-in-obj-type-trait.stderr index a4a14817d3f76..2c85dd042e7ba 100644 --- a/src/test/ui/wf/wf-in-obj-type-trait.stderr +++ b/src/test/ui/wf/wf-in-obj-type-trait.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-in-obj-type-trait.rs:11:5 | -LL | x: Object> //~ ERROR E0277 - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` +LL | x: dyn Object> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound note: required by `MustBeCopy` diff --git a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr index ba9d3d7877dda..b79093f7d0235 100644 --- a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr +++ b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-inherent-impl-method-where-clause.rs:12:5 | -LL | / fn foo(self) where T: ExtraCopy //~ ERROR E0277 +LL | / fn foo(self) where T: ExtraCopy LL | | {} | |______^ the trait `std::marker::Copy` is not implemented for `U` | diff --git a/src/test/ui/wf/wf-inherent-impl-where-clause.stderr b/src/test/ui/wf/wf-inherent-impl-where-clause.stderr index 2ed9cc56f94ab..f10ff841acbf6 100644 --- a/src/test/ui/wf/wf-inherent-impl-where-clause.stderr +++ b/src/test/ui/wf/wf-inherent-impl-where-clause.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-inherent-impl-where-clause.rs:11:1 | -LL | / impl Foo where T: ExtraCopy //~ ERROR E0277 +LL | / impl Foo where T: ExtraCopy LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` diff --git a/src/test/ui/wf/wf-misc-methods-issue-28609.nll.stderr b/src/test/ui/wf/wf-misc-methods-issue-28609.nll.stderr deleted file mode 100644 index 21ac2031d0408..0000000000000 --- a/src/test/ui/wf/wf-misc-methods-issue-28609.nll.stderr +++ /dev/null @@ -1,55 +0,0 @@ -error[E0515]: cannot return value referencing temporary value - --> $DIR/wf-misc-methods-issue-28609.rs:22:5 - | -LL | s.transmute_inherent(&mut 42) //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^^^^^--^ - | | | - | | temporary value created here - | returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing local variable `four` - --> $DIR/wf-misc-methods-issue-28609.rs:36:5 - | -LL | s.bomb = Some(&four); //~ ERROR does not live long enough - | ----- `four` is borrowed here -LL | &s - | ^^ returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing local variable `four` - --> $DIR/wf-misc-methods-issue-28609.rs:43:5 - | -LL | s.bomb = Some(&four); //~ ERROR does not live long enough - | ----- `four` is borrowed here -LL | &*s - | ^^^ returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing temporary value - --> $DIR/wf-misc-methods-issue-28609.rs:53:5 - | -LL | s << &mut 3 //~ ERROR does not live long enough - | ^^^^^^^^^^- - | | | - | | temporary value created here - | returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing temporary value - --> $DIR/wf-misc-methods-issue-28609.rs:58:5 - | -LL | s.shl(&mut 3) //~ ERROR does not live long enough - | ^^^^^^^^^^^-^ - | | | - | | temporary value created here - | returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing temporary value - --> $DIR/wf-misc-methods-issue-28609.rs:63:5 - | -LL | S2::shl(s, &mut 3) //~ ERROR does not live long enough - | ^^^^^^^^^^^^^^^^-^ - | | | - | | temporary value created here - | returns a value referencing data owned by the current function - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/wf/wf-misc-methods-issue-28609.rs b/src/test/ui/wf/wf-misc-methods-issue-28609.rs index 505d7d75d5398..050f866e1c813 100644 --- a/src/test/ui/wf/wf-misc-methods-issue-28609.rs +++ b/src/test/ui/wf/wf-misc-methods-issue-28609.rs @@ -19,7 +19,7 @@ impl<'a, 'b> S<'a, 'b> { fn return_dangling_pointer_inherent(s: S2) -> &u32 { let s = s; - s.transmute_inherent(&mut 42) //~ ERROR does not live long enough + s.transmute_inherent(&mut 42) //~ ERROR cannot return value referencing temporary value } impl<'a, 'b> Deref for S<'a, 'b> { @@ -32,15 +32,15 @@ impl<'a, 'b> Deref for S<'a, 'b> { fn return_dangling_pointer_coerce(s: S2) -> &u32 { let four = 4; let mut s = s; - s.bomb = Some(&four); //~ ERROR does not live long enough - &s + s.bomb = Some(&four); + &s //~ ERROR cannot return value referencing local variable `four` } fn return_dangling_pointer_unary_op(s: S2) -> &u32 { let four = 4; let mut s = s; - s.bomb = Some(&four); //~ ERROR does not live long enough - &*s + s.bomb = Some(&four); + &*s //~ ERROR cannot return value referencing local variable `four` } impl<'a, 'b> Shl<&'b u32> for S<'a, 'b> { @@ -50,17 +50,17 @@ impl<'a, 'b> Shl<&'b u32> for S<'a, 'b> { fn return_dangling_pointer_binary_op(s: S2) -> &u32 { let s = s; - s << &mut 3 //~ ERROR does not live long enough + s << &mut 3 //~ ERROR cannot return value referencing temporary value } fn return_dangling_pointer_method(s: S2) -> &u32 { let s = s; - s.shl(&mut 3) //~ ERROR does not live long enough + s.shl(&mut 3) //~ ERROR cannot return value referencing temporary value } fn return_dangling_pointer_ufcs(s: S2) -> &u32 { let s = s; - S2::shl(s, &mut 3) //~ ERROR does not live long enough + S2::shl(s, &mut 3) //~ ERROR cannot return value referencing temporary value } fn main() { diff --git a/src/test/ui/wf/wf-misc-methods-issue-28609.stderr b/src/test/ui/wf/wf-misc-methods-issue-28609.stderr index 46dc4dc8870da..fc58984345a91 100644 --- a/src/test/ui/wf/wf-misc-methods-issue-28609.stderr +++ b/src/test/ui/wf/wf-misc-methods-issue-28609.stderr @@ -1,111 +1,55 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/wf-misc-methods-issue-28609.rs:22:31 - | -LL | s.transmute_inherent(&mut 42) //~ ERROR does not live long enough - | ^^ temporary value does not live long enough -LL | } - | - temporary value only lives until here - | -note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 20:1... - --> $DIR/wf-misc-methods-issue-28609.rs:20:1 - | -LL | / fn return_dangling_pointer_inherent(s: S2) -> &u32 { -LL | | let s = s; -LL | | s.transmute_inherent(&mut 42) //~ ERROR does not live long enough -LL | | } - | |_^ +error[E0515]: cannot return value referencing temporary value + --> $DIR/wf-misc-methods-issue-28609.rs:22:5 + | +LL | s.transmute_inherent(&mut 42) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^--^ + | | | + | | temporary value created here + | returns a value referencing data owned by the current function -error[E0597]: `four` does not live long enough - --> $DIR/wf-misc-methods-issue-28609.rs:35:20 +error[E0515]: cannot return value referencing local variable `four` + --> $DIR/wf-misc-methods-issue-28609.rs:36:5 | -LL | s.bomb = Some(&four); //~ ERROR does not live long enough - | ^^^^ borrowed value does not live long enough +LL | s.bomb = Some(&four); + | ----- `four` is borrowed here LL | &s -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 32:1... - --> $DIR/wf-misc-methods-issue-28609.rs:32:1 - | -LL | / fn return_dangling_pointer_coerce(s: S2) -> &u32 { -LL | | let four = 4; -LL | | let mut s = s; -LL | | s.bomb = Some(&four); //~ ERROR does not live long enough -LL | | &s -LL | | } - | |_^ + | ^^ returns a value referencing data owned by the current function -error[E0597]: `four` does not live long enough - --> $DIR/wf-misc-methods-issue-28609.rs:42:20 +error[E0515]: cannot return value referencing local variable `four` + --> $DIR/wf-misc-methods-issue-28609.rs:43:5 | -LL | s.bomb = Some(&four); //~ ERROR does not live long enough - | ^^^^ borrowed value does not live long enough +LL | s.bomb = Some(&four); + | ----- `four` is borrowed here LL | &*s -LL | } - | - borrowed value only lives until here - | -note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 39:1... - --> $DIR/wf-misc-methods-issue-28609.rs:39:1 - | -LL | / fn return_dangling_pointer_unary_op(s: S2) -> &u32 { -LL | | let four = 4; -LL | | let mut s = s; -LL | | s.bomb = Some(&four); //~ ERROR does not live long enough -LL | | &*s -LL | | } - | |_^ + | ^^^ returns a value referencing data owned by the current function -error[E0597]: borrowed value does not live long enough - --> $DIR/wf-misc-methods-issue-28609.rs:53:15 - | -LL | s << &mut 3 //~ ERROR does not live long enough - | ^ temporary value does not live long enough -LL | } - | - temporary value only lives until here - | -note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 51:1... - --> $DIR/wf-misc-methods-issue-28609.rs:51:1 - | -LL | / fn return_dangling_pointer_binary_op(s: S2) -> &u32 { -LL | | let s = s; -LL | | s << &mut 3 //~ ERROR does not live long enough -LL | | } - | |_^ +error[E0515]: cannot return value referencing temporary value + --> $DIR/wf-misc-methods-issue-28609.rs:53:5 + | +LL | s << &mut 3 + | ^^^^^^^^^^- + | | | + | | temporary value created here + | returns a value referencing data owned by the current function -error[E0597]: borrowed value does not live long enough - --> $DIR/wf-misc-methods-issue-28609.rs:58:16 - | -LL | s.shl(&mut 3) //~ ERROR does not live long enough - | ^ temporary value does not live long enough -LL | } - | - temporary value only lives until here - | -note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 56:1... - --> $DIR/wf-misc-methods-issue-28609.rs:56:1 - | -LL | / fn return_dangling_pointer_method(s: S2) -> &u32 { -LL | | let s = s; -LL | | s.shl(&mut 3) //~ ERROR does not live long enough -LL | | } - | |_^ +error[E0515]: cannot return value referencing temporary value + --> $DIR/wf-misc-methods-issue-28609.rs:58:5 + | +LL | s.shl(&mut 3) + | ^^^^^^^^^^^-^ + | | | + | | temporary value created here + | returns a value referencing data owned by the current function -error[E0597]: borrowed value does not live long enough - --> $DIR/wf-misc-methods-issue-28609.rs:63:21 - | -LL | S2::shl(s, &mut 3) //~ ERROR does not live long enough - | ^ temporary value does not live long enough -LL | } - | - temporary value only lives until here - | -note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 61:1... - --> $DIR/wf-misc-methods-issue-28609.rs:61:1 - | -LL | / fn return_dangling_pointer_ufcs(s: S2) -> &u32 { -LL | | let s = s; -LL | | S2::shl(s, &mut 3) //~ ERROR does not live long enough -LL | | } - | |_^ +error[E0515]: cannot return value referencing temporary value + --> $DIR/wf-misc-methods-issue-28609.rs:63:5 + | +LL | S2::shl(s, &mut 3) + | ^^^^^^^^^^^^^^^^-^ + | | | + | | temporary value created here + | returns a value referencing data owned by the current function error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/wf/wf-object-safe.rs b/src/test/ui/wf/wf-object-safe.rs index 08f68f6c004fa..42e6917551fd9 100644 --- a/src/test/ui/wf/wf-object-safe.rs +++ b/src/test/ui/wf/wf-object-safe.rs @@ -6,5 +6,5 @@ trait A { } fn main() { - let _x: &A; //~ ERROR E0038 + let _x: &dyn A; //~ ERROR E0038 } diff --git a/src/test/ui/wf/wf-object-safe.stderr b/src/test/ui/wf/wf-object-safe.stderr index 2a514d9d2c2b9..3b264ecd580ec 100644 --- a/src/test/ui/wf/wf-object-safe.stderr +++ b/src/test/ui/wf/wf-object-safe.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `A` cannot be made into an object --> $DIR/wf-object-safe.rs:9:13 | -LL | let _x: &A; //~ ERROR E0038 - | ^^ the trait `A` cannot be made into an object +LL | let _x: &dyn A; + | ^^^^^^ the trait `A` cannot be made into an object | = note: method `foo` references the `Self` type in its arguments or return type diff --git a/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.rs b/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.rs index 1c4cda261d1c9..85a332e244ff0 100644 --- a/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.rs +++ b/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.rs @@ -16,8 +16,7 @@ struct Foo<'a,T> { trait Baz { } impl<'a, T> Trait<'a, T> for u32 { - type Out = &'a Baz; //~ ERROR `T` may not live long enough + type Out = &'a dyn Baz; //~ ERROR `T` may not live long enough } fn main() { } - diff --git a/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr b/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr index 04f8c70bbf420..f1cf514e6b298 100644 --- a/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr +++ b/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr @@ -3,13 +3,13 @@ error[E0309]: the parameter type `T` may not live long enough | LL | impl<'a, T> Trait<'a, T> for usize { | - help: consider adding an explicit lifetime bound `T: 'a`... -LL | type Out = &'a fn(T); //~ ERROR `T` may not live long enough +LL | type Out = &'a fn(T); | ^^^^^^^^^^^^^^^^^^^^^ | note: ...so that the reference type `&'a fn(T)` does not outlive the data it points at --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:9:5 | -LL | type Out = &'a fn(T); //~ ERROR `T` may not live long enough +LL | type Out = &'a fn(T); | ^^^^^^^^^^^^^^^^^^^^^ error[E0309]: the parameter type `T` may not live long enough @@ -17,14 +17,14 @@ error[E0309]: the parameter type `T` may not live long enough | LL | impl<'a, T> Trait<'a, T> for u32 { | - help: consider adding an explicit lifetime bound `T: 'a`... -LL | type Out = &'a Baz; //~ ERROR `T` may not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | type Out = &'a dyn Baz; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...so that the reference type `&'a (dyn Baz + 'a)` does not outlive the data it points at --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:19:5 | -LL | type Out = &'a Baz; //~ ERROR `T` may not live long enough - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | type Out = &'a dyn Baz; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.rs b/src/test/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.rs new file mode 100644 index 0000000000000..d0167c8c268cf --- /dev/null +++ b/src/test/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.rs @@ -0,0 +1,31 @@ +// rust-lang/rust#58158: We have special-case code to deal with case +// when a type is both packed and needs drop glue, (we move the fields +// out of their potentially unaligned locations before dropping them, +// which requires they be Sized; see PR #44884). +// +// So, we need to check if a given type needs drop-glue. That requires +// that we actually know that the concrete type, and we guard against +// the type having unknown parts (i.e. type variables) by ICE'ing in +// that scenario. +// +// But in a case where we have a projection (`Type as Trait::Assoc`) +// where `Type` does not actually implement `Trait`, we of course +// cannot have a concrete type, because there is no impl to look up +// the concrete type for the associated type `Assoc`. +// +// So, this test is just making sure that in such a case that we do +// not immediately ICE, and instead allow the underlying type error to +// surface. + +pub struct Matrix(S); +pub struct DefaultAllocator; + +pub trait Allocator { type Buffer; } + +// impl Allocator for DefaultAllocator { type Buffer = (); } + +#[repr(packed)] +struct Foo(Matrix<::Buffer>); +//~^ ERROR the trait bound `DefaultAllocator: Allocator` is not satisfied + +fn main() { } diff --git a/src/test/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr b/src/test/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr new file mode 100644 index 0000000000000..e460cdcd3f3e5 --- /dev/null +++ b/src/test/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `DefaultAllocator: Allocator` is not satisfied + --> $DIR/wf-packed-on-proj-of-type-as-unimpl-trait.rs:28:12 + | +LL | struct Foo(Matrix<::Buffer>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Allocator` is not implemented for `DefaultAllocator` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/wf/wf-static-method.nll.stderr b/src/test/ui/wf/wf-static-method.nll.stderr new file mode 100644 index 0000000000000..338de6db18006 --- /dev/null +++ b/src/test/ui/wf/wf-static-method.nll.stderr @@ -0,0 +1,65 @@ +error: lifetime may not live long enough + --> $DIR/wf-static-method.rs:17:9 + | +LL | impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | u + | ^ returning this value requires that `'b` must outlive `'a` + +error: lifetime may not live long enough + --> $DIR/wf-static-method.rs:26:18 + | +LL | impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let me = Self::make_me(); + | ^^^^^^^^^^^^^ requires that `'b` must outlive `'a` + +error: lifetime may not live long enough + --> $DIR/wf-static-method.rs:33:9 + | +LL | impl<'a, 'b> Evil<'a, 'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | fn inherent_evil(u: &'b u32) -> &'a u32 { +LL | u + | ^ returning this value requires that `'b` must outlive `'a` + +error: lifetime may not live long enough + --> $DIR/wf-static-method.rs:41:5 + | +LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | <()>::static_evil(b) + | ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a` + +error: lifetime may not live long enough + --> $DIR/wf-static-method.rs:45:5 + | +LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | ::static_evil(b) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a` + +error: lifetime may not live long enough + --> $DIR/wf-static-method.rs:50:5 + | +LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | ::inherent_evil(b) // bug? shouldn't this be an error + | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a` + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/wf/wf-static-method.stderr b/src/test/ui/wf/wf-static-method.stderr index 78ea903e699c3..f82526aa88ebf 100644 --- a/src/test/ui/wf/wf-static-method.stderr +++ b/src/test/ui/wf/wf-static-method.stderr @@ -1,7 +1,7 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/wf-static-method.rs:17:9 | -LL | u //~ ERROR E0312 +LL | u | ^ | note: ...the reference is valid for the lifetime 'a as defined on the impl at 14:6... @@ -18,7 +18,7 @@ LL | impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () { error[E0478]: lifetime bound not satisfied --> $DIR/wf-static-method.rs:26:18 | -LL | let me = Self::make_me(); //~ ERROR lifetime bound not satisfied +LL | let me = Self::make_me(); | ^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime 'b as defined on the impl at 23:10 @@ -35,7 +35,7 @@ LL | impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> { error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/wf-static-method.rs:33:9 | -LL | u //~ ERROR E0312 +LL | u | ^ | note: ...the reference is valid for the lifetime 'a as defined on the impl at 31:6... @@ -52,7 +52,7 @@ LL | impl<'a, 'b> Evil<'a, 'b> { error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements --> $DIR/wf-static-method.rs:41:5 | -LL | <()>::static_evil(b) //~ ERROR cannot infer an appropriate lifetime +LL | <()>::static_evil(b) | ^^^^^^^^^^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime 'b as defined on the function body at 40:13... @@ -63,7 +63,7 @@ LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 { note: ...so that reference does not outlive borrowed content --> $DIR/wf-static-method.rs:41:23 | -LL | <()>::static_evil(b) //~ ERROR cannot infer an appropriate lifetime +LL | <()>::static_evil(b) | ^ note: but, the lifetime must be valid for the lifetime 'a as defined on the function body at 40:9... --> $DIR/wf-static-method.rs:40:9 @@ -73,7 +73,7 @@ LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 { note: ...so that reference does not outlive borrowed content --> $DIR/wf-static-method.rs:41:5 | -LL | <()>::static_evil(b) //~ ERROR cannot infer an appropriate lifetime +LL | <()>::static_evil(b) | ^^^^^^^^^^^^^^^^^^^^ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements @@ -105,5 +105,4 @@ LL | ::static_evil(b) error: aborting due to 5 previous errors -Some errors occurred: E0312, E0478, E0495. -For more information about an error, try `rustc --explain E0312`. +For more information about this error, try `rustc --explain E0478`. diff --git a/src/test/ui/wf/wf-struct-bound.stderr b/src/test/ui/wf/wf-struct-bound.stderr index 37defb87ee524..1fdcced90cc56 100644 --- a/src/test/ui/wf/wf-struct-bound.stderr +++ b/src/test/ui/wf/wf-struct-bound.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-struct-bound.rs:9:1 | -LL | / struct SomeStruct //~ ERROR E0277 +LL | / struct SomeStruct LL | | where T: ExtraCopy LL | | { LL | | data: (T,U) diff --git a/src/test/ui/wf/wf-struct-field.stderr b/src/test/ui/wf/wf-struct-field.stderr index e31552b408954..e609f93ff700b 100644 --- a/src/test/ui/wf/wf-struct-field.stderr +++ b/src/test/ui/wf/wf-struct-field.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied --> $DIR/wf-struct-field.rs:12:5 | -LL | data: IsCopy //~ ERROR E0277 +LL | data: IsCopy | ^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` | = help: consider adding a `where A: std::marker::Copy` bound diff --git a/src/test/ui/wf/wf-trait-associated-type-bound.stderr b/src/test/ui/wf/wf-trait-associated-type-bound.stderr index f8ba74a2fdc3e..658d41218e483 100644 --- a/src/test/ui/wf/wf-trait-associated-type-bound.stderr +++ b/src/test/ui/wf/wf-trait-associated-type-bound.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-trait-associated-type-bound.rs:9:1 | -LL | / trait SomeTrait { //~ ERROR E0277 +LL | / trait SomeTrait { LL | | type Type1: ExtraCopy; LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `T` diff --git a/src/test/ui/wf/wf-trait-bound.stderr b/src/test/ui/wf/wf-trait-bound.stderr index 585571a6a3cb2..5cc9451bf5cac 100644 --- a/src/test/ui/wf/wf-trait-bound.stderr +++ b/src/test/ui/wf/wf-trait-bound.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-trait-bound.rs:9:1 | -LL | / trait SomeTrait //~ ERROR E0277 +LL | / trait SomeTrait LL | | where T: ExtraCopy LL | | { LL | | } diff --git a/src/test/ui/wf/wf-trait-default-fn-arg.stderr b/src/test/ui/wf/wf-trait-default-fn-arg.stderr index eeafc06db3472..e713389223654 100644 --- a/src/test/ui/wf/wf-trait-default-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-arg.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied --> $DIR/wf-trait-default-fn-arg.rs:11:5 | LL | / fn bar(&self, x: &Bar) { -LL | | //~^ ERROR E0277 +LL | | LL | | // LL | | // Here, Eq ought to be implemented. LL | | } diff --git a/src/test/ui/wf/wf-trait-default-fn-ret.stderr b/src/test/ui/wf/wf-trait-default-fn-ret.stderr index 7fabd6b471364..5a310a826dd90 100644 --- a/src/test/ui/wf/wf-trait-default-fn-ret.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-ret.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied --> $DIR/wf-trait-default-fn-ret.rs:11:5 | LL | / fn bar(&self) -> Bar { -LL | | //~^ ERROR E0277 +LL | | LL | | // LL | | // Here, Eq ought to be implemented. LL | | loop { } diff --git a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr index 669dd08b21f98..d5a00be6d3464 100644 --- a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied --> $DIR/wf-trait-default-fn-where-clause.rs:11:5 | LL | / fn bar(&self) where A: Bar { -LL | | //~^ ERROR E0277 +LL | | LL | | // LL | | // Here, Eq ought to be implemented. LL | | } diff --git a/src/test/ui/wf/wf-trait-superbound.stderr b/src/test/ui/wf/wf-trait-superbound.stderr index 0bcda407d9cd0..a3c4ab58f65f7 100644 --- a/src/test/ui/wf/wf-trait-superbound.stderr +++ b/src/test/ui/wf/wf-trait-superbound.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-trait-superbound.rs:9:1 | -LL | / trait SomeTrait: ExtraCopy { //~ ERROR E0277 +LL | / trait SomeTrait: ExtraCopy { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `T` | diff --git a/src/test/ui/where-clauses/where-for-self-2.stderr b/src/test/ui/where-clauses/where-for-self-2.stderr index bbcb61a856d8d..dbe68b82c24cb 100644 --- a/src/test/ui/where-clauses/where-for-self-2.stderr +++ b/src/test/ui/where-clauses/where-for-self-2.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `for<'a> &'a _: Bar` is not satisfied --> $DIR/where-for-self-2.rs:21:5 | -LL | foo(&X); //~ ERROR trait bound +LL | foo(&X); | ^^^ the trait `for<'a> Bar` is not implemented for `&'a _` | = help: the following implementations were found: diff --git a/src/test/ui/where-clauses/where-for-self.stderr b/src/test/ui/where-clauses/where-for-self.stderr index d06afc1e42376..84430ffcf887f 100644 --- a/src/test/ui/where-clauses/where-for-self.stderr +++ b/src/test/ui/where-clauses/where-for-self.stderr @@ -6,4 +6,3 @@ LL | where for<'a> &'a T: for<'b> Bar<'b> error: aborting due to previous error -For more information about this error, try `rustc --explain E0316`. diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.rs b/src/test/ui/where-clauses/where-lifetime-resolution.rs index 4c46a77ae2916..0d426386768c8 100644 --- a/src/test/ui/where-clauses/where-lifetime-resolution.rs +++ b/src/test/ui/where-clauses/where-lifetime-resolution.rs @@ -2,10 +2,10 @@ trait Trait1<'a> {} trait Trait2<'a, 'b> {} fn f() where - for<'a> Trait1<'a>: Trait1<'a>, // OK - (for<'a> Trait1<'a>): Trait1<'a>, + for<'a> dyn Trait1<'a>: Trait1<'a>, // OK + (dyn for<'a> Trait1<'a>): Trait1<'a>, //~^ ERROR use of undeclared lifetime name `'a` - for<'a> for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, + for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, //~^ ERROR use of undeclared lifetime name `'b` //~| ERROR nested quantification of lifetimes {} diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.stderr b/src/test/ui/where-clauses/where-lifetime-resolution.stderr index ce6354b0ae72f..0081ae07163b3 100644 --- a/src/test/ui/where-clauses/where-lifetime-resolution.stderr +++ b/src/test/ui/where-clauses/where-lifetime-resolution.stderr @@ -1,22 +1,21 @@ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/where-lifetime-resolution.rs:6:34 + --> $DIR/where-lifetime-resolution.rs:6:38 | -LL | (for<'a> Trait1<'a>): Trait1<'a>, - | ^^ undeclared lifetime +LL | (dyn for<'a> Trait1<'a>): Trait1<'a>, + | ^^ undeclared lifetime error[E0316]: nested quantification of lifetimes - --> $DIR/where-lifetime-resolution.rs:8:13 + --> $DIR/where-lifetime-resolution.rs:8:17 | -LL | for<'a> for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/where-lifetime-resolution.rs:8:48 + --> $DIR/where-lifetime-resolution.rs:8:52 | -LL | for<'a> for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, - | ^^ undeclared lifetime +LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, + | ^^ undeclared lifetime error: aborting due to 3 previous errors -Some errors occurred: E0261, E0316. -For more information about an error, try `rustc --explain E0261`. +For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/while-let.stderr b/src/test/ui/while-let.stderr index 6d61143d33c84..156d0e6c33d83 100644 --- a/src/test/ui/while-let.stderr +++ b/src/test/ui/while-let.stderr @@ -4,7 +4,7 @@ warning: irrefutable while-let pattern LL | while let $p = $e $b | ^^^^^ ... -LL | / foo!(a, 1, { //~ WARN irrefutable while-let +LL | / foo!(a, 1, { LL | | println!("irrefutable pattern"); LL | | }); | |_______- in this macro invocation @@ -17,7 +17,7 @@ warning: irrefutable while-let pattern LL | while let $p = $e $b | ^^^^^ ... -LL | / bar!(a, 1, { //~ WARN irrefutable while-let +LL | / bar!(a, 1, { LL | | println!("irrefutable pattern"); LL | | }); | |_______- in this macro invocation @@ -25,7 +25,7 @@ LL | | }); warning: irrefutable while-let pattern --> $DIR/while-let.rs:24:5 | -LL | / while let a = 1 { //~ WARN irrefutable while-let +LL | / while let a = 1 { LL | | println!("irrefutable pattern"); LL | | break; LL | | } diff --git a/src/test/ui/write-to-static-mut-in-static.stderr b/src/test/ui/write-to-static-mut-in-static.stderr index eba1c609d2f83..4349f6e89c119 100644 --- a/src/test/ui/write-to-static-mut-in-static.stderr +++ b/src/test/ui/write-to-static-mut-in-static.stderr @@ -24,5 +24,5 @@ LL | pub static mut C: u32 = unsafe { C = 1; 0 }; error: aborting due to 2 previous errors -Some errors occurred: E0080, E0391. +Some errors have detailed explanations: E0080, E0391. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/writing-to-immutable-vec.nll.stderr b/src/test/ui/writing-to-immutable-vec.nll.stderr deleted file mode 100644 index 6ec56f90ca47a..0000000000000 --- a/src/test/ui/writing-to-immutable-vec.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable - --> $DIR/writing-to-immutable-vec.rs:3:5 - | -LL | let v: Vec = vec![1, 2, 3]; - | - help: consider changing this to be mutable: `mut v` -LL | v[1] = 4; //~ ERROR cannot borrow immutable local variable `v` as mutable - | ^ cannot borrow as mutable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/writing-to-immutable-vec.rs b/src/test/ui/writing-to-immutable-vec.rs index ad2bf33fc20ba..dbcc3f0bbe98c 100644 --- a/src/test/ui/writing-to-immutable-vec.rs +++ b/src/test/ui/writing-to-immutable-vec.rs @@ -1,4 +1,4 @@ fn main() { let v: Vec = vec![1, 2, 3]; - v[1] = 4; //~ ERROR cannot borrow immutable local variable `v` as mutable + v[1] = 4; //~ ERROR cannot borrow `v` as mutable, as it is not declared as mutable } diff --git a/src/test/ui/writing-to-immutable-vec.stderr b/src/test/ui/writing-to-immutable-vec.stderr index 3a99186b46f6a..a65765c86c8b7 100644 --- a/src/test/ui/writing-to-immutable-vec.stderr +++ b/src/test/ui/writing-to-immutable-vec.stderr @@ -1,10 +1,10 @@ -error[E0596]: cannot borrow immutable local variable `v` as mutable +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable --> $DIR/writing-to-immutable-vec.rs:3:5 | LL | let v: Vec = vec![1, 2, 3]; - | - help: make this binding mutable: `mut v` -LL | v[1] = 4; //~ ERROR cannot borrow immutable local variable `v` as mutable - | ^ cannot borrow mutably + | - help: consider changing this to be mutable: `mut v` +LL | v[1] = 4; + | ^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/wrong-mul-method-signature.rs b/src/test/ui/wrong-mul-method-signature.rs index 54e2af5525920..1c2f865599e8b 100644 --- a/src/test/ui/wrong-mul-method-signature.rs +++ b/src/test/ui/wrong-mul-method-signature.rs @@ -61,9 +61,8 @@ pub fn main() { let x: Vec1 = Vec1 { x: 1.0 } * 2.0; // this is OK let x: Vec2 = Vec2 { x: 1.0, y: 2.0 } * 2.0; // trait had reversed order - // (we no longer signal a compile error here, since the - // error in the trait signature will cause compilation to - // abort before we bother looking at function bodies.) + //~^ ERROR mismatched types + //~| ERROR mismatched types let x: i32 = Vec3 { x: 1.0, y: 2.0, z: 3.0 } * 2.0; } diff --git a/src/test/ui/wrong-mul-method-signature.stderr b/src/test/ui/wrong-mul-method-signature.stderr index 8630ebcb58042..2317bf8e8293c 100644 --- a/src/test/ui/wrong-mul-method-signature.stderr +++ b/src/test/ui/wrong-mul-method-signature.stderr @@ -25,6 +25,25 @@ LL | fn mul(self, s: f64) -> f64 { = note: expected type `fn(Vec3, f64) -> i32` found type `fn(Vec3, f64) -> f64` -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/wrong-mul-method-signature.rs:63:45 + | +LL | let x: Vec2 = Vec2 { x: 1.0, y: 2.0 } * 2.0; // trait had reversed order + | ^^^ expected struct `Vec2`, found floating-point number + | + = note: expected type `Vec2` + found type `{float}` + +error[E0308]: mismatched types + --> $DIR/wrong-mul-method-signature.rs:63:19 + | +LL | let x: Vec2 = Vec2 { x: 1.0, y: 2.0 } * 2.0; // trait had reversed order + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Vec2`, found f64 + | + = note: expected type `Vec2` + found type `f64` + +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0053`. +Some errors have detailed explanations: E0053, E0308. +For more information about an error, try `rustc --explain E0053`. diff --git a/src/test/ui/xc-private-method.rs b/src/test/ui/xc-private-method.rs index 157249194a345..e95cab93d750e 100644 --- a/src/test/ui/xc-private-method.rs +++ b/src/test/ui/xc-private-method.rs @@ -1,4 +1,4 @@ -// aux-build:xc_private_method_lib.rs +// aux-build:xc-private-method-lib.rs extern crate xc_private_method_lib; diff --git a/src/test/ui/xc-private-method2.rs b/src/test/ui/xc-private-method2.rs index 6d73570318ae8..f11b251082bf2 100644 --- a/src/test/ui/xc-private-method2.rs +++ b/src/test/ui/xc-private-method2.rs @@ -1,4 +1,4 @@ -// aux-build:xc_private_method_lib.rs +// aux-build:xc-private-method-lib.rs extern crate xc_private_method_lib; diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index 93d0f61e1d9f0..63b6399bb9034 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -7,4 +7,3 @@ edition = "2018" [dependencies] toml = "0.4" serde = { version = "1.0", features = ["derive"] } -serde_derive = "1.0" diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 8d87c404d0b28..b6e087c3844fa 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -10,7 +10,7 @@ use std::io::{self, Read, Write}; use std::path::{PathBuf, Path}; use std::process::{Command, Stdio}; -static HOSTS: &'static [&'static str] = &[ +static HOSTS: &[&str] = &[ "aarch64-unknown-linux-gnu", "arm-unknown-linux-gnueabi", "arm-unknown-linux-gnueabihf", @@ -23,6 +23,10 @@ static HOSTS: &'static [&'static str] = &[ "mips64-unknown-linux-gnuabi64", "mips64el-unknown-linux-gnuabi64", "mipsel-unknown-linux-gnu", + "mipsisa32r6-unknown-linux-gnu", + "mipsisa32r6el-unknown-linux-gnu", + "mipsisa64r6-unknown-linux-gnuabi64", + "mipsisa64r6el-unknown-linux-gnuabi64", "powerpc-unknown-linux-gnu", "powerpc64-unknown-linux-gnu", "powerpc64le-unknown-linux-gnu", @@ -32,10 +36,11 @@ static HOSTS: &'static [&'static str] = &[ "x86_64-pc-windows-msvc", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl", "x86_64-unknown-netbsd", ]; -static TARGETS: &'static [&'static str] = &[ +static TARGETS: &[&str] = &[ "aarch64-apple-ios", "aarch64-fuchsia", "aarch64-linux-android", @@ -77,6 +82,10 @@ static TARGETS: &'static [&'static str] = &[ "mips-unknown-linux-musl", "mips64-unknown-linux-gnuabi64", "mips64el-unknown-linux-gnuabi64", + "mipsisa32r6-unknown-linux-gnu", + "mipsisa32r6el-unknown-linux-gnu", + "mipsisa64r6-unknown-linux-gnuabi64", + "mipsisa64r6el-unknown-linux-gnuabi64", "mipsel-unknown-linux-gnu", "mipsel-unknown-linux-musl", "nvptx64-nvidia-cuda", @@ -94,9 +103,12 @@ static TARGETS: &'static [&'static str] = &[ "thumbv7em-none-eabi", "thumbv7em-none-eabihf", "thumbv7m-none-eabi", + "thumbv8m.base-none-eabi", "thumbv8m.main-none-eabi", + "thumbv8m.main-none-eabihf", "wasm32-unknown-emscripten", "wasm32-unknown-unknown", + "wasm32-wasi", "x86_64-apple-darwin", "x86_64-apple-ios", "x86_64-fortanix-unknown-sgx", @@ -106,6 +118,7 @@ static TARGETS: &'static [&'static str] = &[ "x86_64-pc-windows-msvc", "x86_64-rumprun-netbsd", "x86_64-sun-solaris", + "x86_64-pc-solaris", "x86_64-unknown-cloudabi", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu", @@ -115,7 +128,7 @@ static TARGETS: &'static [&'static str] = &[ "x86_64-unknown-redox", ]; -static DOCS_TARGETS: &'static [&'static str] = &[ +static DOCS_TARGETS: &[&str] = &[ "i686-apple-darwin", "i686-pc-windows-gnu", "i686-pc-windows-msvc", @@ -126,7 +139,7 @@ static DOCS_TARGETS: &'static [&'static str] = &[ "x86_64-unknown-linux-gnu", ]; -static MINGW: &'static [&'static str] = &[ +static MINGW: &[&str] = &[ "i686-pc-windows-gnu", "x86_64-pc-windows-gnu", ]; @@ -153,7 +166,7 @@ struct Rename { to: String, } -#[derive(Serialize)] +#[derive(Serialize, Default)] struct Target { available: bool, url: Option, @@ -165,17 +178,7 @@ struct Target { } impl Target { - fn unavailable() -> Target { - Target { - available: false, - url: None, - hash: None, - xz_url: None, - xz_hash: None, - components: None, - extensions: None, - } - } + fn unavailable() -> Self { Self::default() } } #[derive(Serialize)] @@ -184,6 +187,12 @@ struct Component { target: String, } +impl Component { + fn from_str(pkg: &str, target: &str) -> Self { + Self { pkg: pkg.to_string(), target: target.to_string() } + } +} + macro_rules! t { ($e:expr) => (match $e { Ok(e) => e, @@ -301,6 +310,25 @@ fn main() { }.build(); } +enum PkgType { RustSrc, Cargo, Rls, Clippy, Rustfmt, LlvmTools, Lldb, Miri, Other } + +impl PkgType { + fn from_component(component: &str) -> Self { + use PkgType::*; + match component { + "rust-src" => RustSrc, + "cargo" => Cargo, + "rls" | "rls-preview" => Rls, + "clippy" | "clippy-preview" => Clippy, + "rustfmt" | "rustfmt-preview" => Rustfmt, + "llvm-tools" | "llvm-tools-preview" => LlvmTools, + "lldb" | "lldb-preview" => Lldb, + "miri" | "miri-preview" => Miri, + _ => Other, + } + } +} + impl Builder { fn build(&mut self) { self.rust_version = self.version("rust", "x86_64-unknown-linux-gnu"); @@ -349,38 +377,57 @@ impl Builder { renames: BTreeMap::new(), profiles: BTreeMap::new(), }; + self.add_packages_to(&mut manifest); + self.add_profiles_to(&mut manifest); + self.add_renames_to(&mut manifest); + manifest.pkg.insert("rust".to_string(), self.rust_package(&manifest)); + manifest + } - self.package("rustc", &mut manifest.pkg, HOSTS); - self.package("cargo", &mut manifest.pkg, HOSTS); - self.package("rust-mingw", &mut manifest.pkg, MINGW); - self.package("rust-std", &mut manifest.pkg, TARGETS); - self.package("rust-docs", &mut manifest.pkg, DOCS_TARGETS); - self.package("rust-src", &mut manifest.pkg, &["*"]); - self.package("rls-preview", &mut manifest.pkg, HOSTS); - self.package("clippy-preview", &mut manifest.pkg, HOSTS); - self.package("rustfmt-preview", &mut manifest.pkg, HOSTS); - self.package("rust-analysis", &mut manifest.pkg, TARGETS); - self.package("llvm-tools-preview", &mut manifest.pkg, TARGETS); - self.package("lldb-preview", &mut manifest.pkg, TARGETS); - - self.profile("minimal", - &mut manifest.profiles, - &["rustc", "cargo", "rust-std", "rust-mingw"]); - self.profile("default", - &mut manifest.profiles, - &["rustc", "cargo", "rust-std", "rust-mingw", - "rust-docs", "rustfmt-preview", "clippy-preview"]); - self.profile("complete", - &mut manifest.profiles, - &["rustc", "cargo", "rust-std", "rust-mingw", - "rust-docs", "rustfmt-preview", "clippy-preview", - "rls-preview", "rust-src", "llvm-tools-preview", - "lldb-preview", "rust-analysis"]); - - manifest.renames.insert("rls".to_owned(), Rename { to: "rls-preview".to_owned() }); - manifest.renames.insert("rustfmt".to_owned(), Rename { to: "rustfmt-preview".to_owned() }); - manifest.renames.insert("clippy".to_owned(), Rename { to: "clippy-preview".to_owned() }); + fn add_packages_to(&mut self, manifest: &mut Manifest) { + let mut package = |name, targets| self.package(name, &mut manifest.pkg, targets); + package("rustc", HOSTS); + package("cargo", HOSTS); + package("rust-mingw", MINGW); + package("rust-std", TARGETS); + package("rust-docs", DOCS_TARGETS); + package("rust-src", &["*"]); + package("rls-preview", HOSTS); + package("clippy-preview", HOSTS); + package("miri-preview", HOSTS); + package("rustfmt-preview", HOSTS); + package("rust-analysis", TARGETS); + package("llvm-tools-preview", TARGETS); + package("lldb-preview", TARGETS); + } + + fn add_profiles_to(&mut self, manifest: &mut Manifest) { + let mut profile = |name, pkgs| self.profile(name, &mut manifest.profiles, pkgs); + profile("minimal", &["rustc", "cargo", "rust-std", "rust-mingw"]); + profile("default", &[ + "rustc", "cargo", "rust-std", "rust-mingw", + "rust-docs", "rustfmt-preview", "clippy-preview" + ]); + profile("complete", &[ + "rustc", "cargo", "rust-std", "rust-mingw", + "rust-docs", "rustfmt-preview", "clippy-preview", + "rls-preview", "rust-src", "llvm-tools-preview", + "lldb-preview", "rust-analysis", "miri-preview" + ]); + } + fn add_renames_to(&self, manifest: &mut Manifest) { + let mut rename = |from: &str, to: &str| manifest.renames.insert( + from.to_owned(), + Rename { to: to.to_owned() } + ); + rename("rls", "rls-preview"); + rename("rustfmt", "rustfmt-preview"); + rename("clippy", "clippy-preview"); + rename("miri", "miri-preview"); + } + + fn rust_package(&mut self, manifest: &Manifest) -> Package { let mut pkg = Package { version: self.cached_version("rust") .as_ref() @@ -390,89 +437,82 @@ impl Builder { target: BTreeMap::new(), }; for host in HOSTS { - let filename = self.filename("rust", host); - let digest = match self.digests.remove(&filename) { - Some(digest) => digest, - None => { - pkg.target.insert(host.to_string(), Target::unavailable()); - continue - } - }; - let xz_filename = filename.replace(".tar.gz", ".tar.xz"); - let xz_digest = self.digests.remove(&xz_filename); - let mut components = Vec::new(); - let mut extensions = Vec::new(); - - // rustc/rust-std/cargo/docs are all required, and so is rust-mingw - // if it's available for the target. - components.extend(vec![ - Component { pkg: "rustc".to_string(), target: host.to_string() }, - Component { pkg: "rust-std".to_string(), target: host.to_string() }, - Component { pkg: "cargo".to_string(), target: host.to_string() }, - Component { pkg: "rust-docs".to_string(), target: host.to_string() }, - ]); - if host.contains("pc-windows-gnu") { - components.push(Component { - pkg: "rust-mingw".to_string(), - target: host.to_string(), - }); - } - - // Tools are always present in the manifest, but might be marked as unavailable if they - // weren't built - extensions.extend(vec![ - Component { pkg: "clippy-preview".to_string(), target: host.to_string() }, - Component { pkg: "rls-preview".to_string(), target: host.to_string() }, - Component { pkg: "rustfmt-preview".to_string(), target: host.to_string() }, - Component { pkg: "llvm-tools-preview".to_string(), target: host.to_string() }, - Component { pkg: "lldb-preview".to_string(), target: host.to_string() }, - Component { pkg: "rust-analysis".to_string(), target: host.to_string() }, - ]); - - for target in TARGETS { - if target != host { - extensions.push(Component { - pkg: "rust-std".to_string(), - target: target.to_string(), - }); - } - } - extensions.push(Component { - pkg: "rust-src".to_string(), - target: "*".to_string(), - }); - - // If the components/extensions don't actually exist for this - // particular host/target combination then nix it entirely from our - // lists. - { - let has_component = |c: &Component| { - if c.target == "*" { - return true - } - let pkg = match manifest.pkg.get(&c.pkg) { - Some(p) => p, - None => return false, - }; - pkg.target.get(&c.target).is_some() - }; - extensions.retain(&has_component); - components.retain(&has_component); + if let Some(target) = self.target_host_combination(host, &manifest) { + pkg.target.insert(host.to_string(), target); + } else { + pkg.target.insert(host.to_string(), Target::unavailable()); + continue } + } + pkg + } - pkg.target.insert(host.to_string(), Target { - available: true, - url: Some(self.url(&filename)), - hash: Some(digest), - xz_url: xz_digest.as_ref().map(|_| self.url(&xz_filename)), - xz_hash: xz_digest, - components: Some(components), - extensions: Some(extensions), - }); + fn target_host_combination(&mut self, host: &str, manifest: &Manifest) -> Option { + let filename = self.filename("rust", host); + let digest = self.digests.remove(&filename)?; + let xz_filename = filename.replace(".tar.gz", ".tar.xz"); + let xz_digest = self.digests.remove(&xz_filename); + let mut components = Vec::new(); + let mut extensions = Vec::new(); + + let host_component = |pkg| Component::from_str(pkg, host); + + // rustc/rust-std/cargo/docs are all required, + // and so is rust-mingw if it's available for the target. + components.extend(vec![ + host_component("rustc"), + host_component("rust-std"), + host_component("cargo"), + host_component("rust-docs"), + ]); + if host.contains("pc-windows-gnu") { + components.push(host_component("rust-mingw")); } - manifest.pkg.insert("rust".to_string(), pkg); - manifest + // Tools are always present in the manifest, + // but might be marked as unavailable if they weren't built. + extensions.extend(vec![ + host_component("clippy-preview"), + host_component("miri-preview"), + host_component("rls-preview"), + host_component("rustfmt-preview"), + host_component("llvm-tools-preview"), + host_component("lldb-preview"), + host_component("rust-analysis"), + ]); + + extensions.extend( + TARGETS.iter() + .filter(|&&target| target != host) + .map(|target| Component::from_str("rust-std", target)) + ); + extensions.push(Component::from_str("rust-src", "*")); + + // If the components/extensions don't actually exist for this + // particular host/target combination then nix it entirely from our + // lists. + let has_component = |c: &Component| { + if c.target == "*" { + return true + } + let pkg = match manifest.pkg.get(&c.pkg) { + Some(p) => p, + None => return false, + }; + pkg.target.get(&c.target).is_some() + }; + extensions.retain(&has_component); + components.retain(&has_component); + + Some(Target { + available: true, + url: Some(self.url(&filename)), + hash: Some(digest), + xz_url: xz_digest.as_ref().map(|_| self.url(&xz_filename)), + xz_hash: xz_digest, + components: Some(components), + extensions: Some(extensions), + }) } fn profile(&mut self, @@ -486,10 +526,17 @@ impl Builder { pkgname: &str, dst: &mut BTreeMap, targets: &[&str]) { - let (version, is_present) = match *self.cached_version(pkgname) { - Some(ref version) => (version.clone(), true), - None => (String::new(), false), - }; + let (version, mut is_present) = self.cached_version(pkgname) + .as_ref() + .cloned() + .map(|version| (version, true)) + .unwrap_or_default(); + + // miri needs to build std with xargo, which doesn't allow stable/beta: + // + if pkgname == "miri-preview" && self.rust_release != "nightly" { + is_present = false; // ignore it + } let targets = targets.iter().map(|name| { if is_present { @@ -513,15 +560,7 @@ impl Builder { } else { // If the component is not present for this build add it anyway but mark it as // unavailable -- this way rustup won't allow upgrades without --force - (name.to_string(), Target { - available: false, - url: None, - hash: None, - xz_url: None, - xz_hash: None, - components: None, - extensions: None, - }) + (name.to_string(), Target::unavailable()) } }).collect(); @@ -540,89 +579,65 @@ impl Builder { } fn filename(&self, component: &str, target: &str) -> String { - if component == "rust-src" { - format!("rust-src-{}.tar.gz", self.rust_release) - } else if component == "cargo" { - format!("cargo-{}-{}.tar.gz", self.cargo_release, target) - } else if component == "rls" || component == "rls-preview" { - format!("rls-{}-{}.tar.gz", self.rls_release, target) - } else if component == "clippy" || component == "clippy-preview" { - format!("clippy-{}-{}.tar.gz", self.clippy_release, target) - } else if component == "rustfmt" || component == "rustfmt-preview" { - format!("rustfmt-{}-{}.tar.gz", self.rustfmt_release, target) - } else if component == "llvm-tools" || component == "llvm-tools-preview" { - format!("llvm-tools-{}-{}.tar.gz", self.llvm_tools_release, target) - } else if component == "lldb" || component == "lldb-preview" { - format!("lldb-{}-{}.tar.gz", self.lldb_release, target) - } else if component == "miri" || component == "miri-preview" { - format!("miri-{}-{}.tar.gz", self.miri_release, target) - } else { - format!("{}-{}-{}.tar.gz", component, self.rust_release, target) + use PkgType::*; + match PkgType::from_component(component) { + RustSrc => format!("rust-src-{}.tar.gz", self.rust_release), + Cargo => format!("cargo-{}-{}.tar.gz", self.cargo_release, target), + Rls => format!("rls-{}-{}.tar.gz", self.rls_release, target), + Clippy => format!("clippy-{}-{}.tar.gz", self.clippy_release, target), + Rustfmt => format!("rustfmt-{}-{}.tar.gz", self.rustfmt_release, target), + LlvmTools => format!("llvm-tools-{}-{}.tar.gz", self.llvm_tools_release, target), + Lldb => format!("lldb-{}-{}.tar.gz", self.lldb_release, target), + Miri => format!("miri-{}-{}.tar.gz", self.miri_release, target), + Other => format!("{}-{}-{}.tar.gz", component, self.rust_release, target), } } fn cached_version(&self, component: &str) -> &Option { - if component == "cargo" { - &self.cargo_version - } else if component == "rls" || component == "rls-preview" { - &self.rls_version - } else if component == "clippy" || component == "clippy-preview" { - &self.clippy_version - } else if component == "rustfmt" || component == "rustfmt-preview" { - &self.rustfmt_version - } else if component == "llvm-tools" || component == "llvm-tools-preview" { - &self.llvm_tools_version - } else if component == "lldb" || component == "lldb-preview" { - &self.lldb_version - } else if component == "miri" || component == "miri-preview" { - &self.miri_version - } else { - &self.rust_version + use PkgType::*; + match PkgType::from_component(component) { + Cargo => &self.cargo_version, + Rls => &self.rls_version, + Clippy => &self.clippy_version, + Rustfmt => &self.rustfmt_version, + LlvmTools => &self.llvm_tools_version, + Lldb => &self.lldb_version, + Miri => &self.miri_version, + _ => &self.rust_version, } } fn cached_git_commit_hash(&self, component: &str) -> &Option { - if component == "cargo" { - &self.cargo_git_commit_hash - } else if component == "rls" || component == "rls-preview" { - &self.rls_git_commit_hash - } else if component == "clippy" || component == "clippy-preview" { - &self.clippy_git_commit_hash - } else if component == "rustfmt" || component == "rustfmt-preview" { - &self.rustfmt_git_commit_hash - } else if component == "llvm-tools" || component == "llvm-tools-preview" { - &self.llvm_tools_git_commit_hash - } else if component == "lldb" || component == "lldb-preview" { - &self.lldb_git_commit_hash - } else if component == "miri" || component == "miri-preview" { - &self.miri_git_commit_hash - } else { - &self.rust_git_commit_hash + use PkgType::*; + match PkgType::from_component(component) { + Cargo => &self.cargo_git_commit_hash, + Rls => &self.rls_git_commit_hash, + Clippy => &self.clippy_git_commit_hash, + Rustfmt => &self.rustfmt_git_commit_hash, + LlvmTools => &self.llvm_tools_git_commit_hash, + Lldb => &self.lldb_git_commit_hash, + Miri => &self.miri_git_commit_hash, + _ => &self.rust_git_commit_hash, } } fn version(&self, component: &str, target: &str) -> Option { - let mut cmd = Command::new("tar"); - let filename = self.filename(component, target); - cmd.arg("xf") - .arg(self.input.join(&filename)) - .arg(format!("{}/version", filename.replace(".tar.gz", ""))) - .arg("-O"); - let output = t!(cmd.output()); - if output.status.success() { - Some(String::from_utf8_lossy(&output.stdout).trim().to_string()) - } else { - // Perhaps we didn't build this package. - None - } + self.untar(component, target, |filename| format!("{}/version", filename)) } fn git_commit_hash(&self, component: &str, target: &str) -> Option { + self.untar(component, target, |filename| format!("{}/git-commit-hash", filename)) + } + + fn untar(&self, component: &str, target: &str, dir: F) -> Option + where + F: FnOnce(String) -> String + { let mut cmd = Command::new("tar"); let filename = self.filename(component, target); cmd.arg("xf") .arg(self.input.join(&filename)) - .arg(format!("{}/git-commit-hash", filename.replace(".tar.gz", ""))) + .arg(dir(filename.replace(".tar.gz", ""))) .arg("-O"); let output = t!(cmd.output()); if output.status.success() { diff --git a/src/tools/cargo b/src/tools/cargo index 5c6aa46e6f286..9edd089168f87 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 5c6aa46e6f28661270979696e7b4c2f0dff8628f +Subproject commit 9edd089168f8795b3890bc3daf5b99f03e9f8765 diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 7f3c159075b97..14035eedbb44b 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -30,7 +30,7 @@ const TEST_REPOS: &'static [Test] = &[ }, Test { name: "tokei", - repo: "https://github.com/Aaronepower/tokei", + repo: "https://github.com/XAMPPRocky/tokei", sha: "5e11c4852fe4aa086b0e4fe5885822fbe57ba928", lock: None, packages: &[], @@ -61,7 +61,7 @@ const TEST_REPOS: &'static [Test] = &[ Test { name: "webrender", repo: "https://github.com/servo/webrender", - sha: "57250b2b8fa63934f80e5376a29f7dcb3f759ad6", + sha: "cdadd068f4c7218bd983d856981d561e605270ab", lock: None, packages: &[], }, diff --git a/src/tools/clippy b/src/tools/clippy index 7bc2e1d60d23a..e3cb40e4f7e56 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit 7bc2e1d60d23a2f6a31d7a04d40171372d80b5b3 +Subproject commit e3cb40e4f7e566ffe260b2b9d606485c7c22d642 diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 00e1a53473cda..e759ad1f35dde 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -7,13 +7,11 @@ edition = "2018" [dependencies] diff = "0.1.10" env_logger = { version = "0.5", default-features = false } -filetime = "0.2" getopts = "0.2" log = "0.4" regex = "1.0" -serde = "1.0" +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -serde_derive = "1.0" rustfix = "0.4.1" lazy_static = "1.0" walkdir = "2" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 6b3117a1f74f4..a75d9f0b0bb9b 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -1,5 +1,6 @@ pub use self::Mode::*; +use std::ffi::OsString; use std::fmt; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -15,7 +16,8 @@ pub enum Mode { RunPass, RunPassValgrind, Pretty, - DebugInfoBoth, + DebugInfoCdb, + DebugInfoGdbLldb, DebugInfoGdb, DebugInfoLldb, Codegen, @@ -24,16 +26,19 @@ pub enum Mode { Incremental, RunMake, Ui, + JsDocTest, MirOpt, + Assembly, } impl Mode { pub fn disambiguator(self) -> &'static str { // Run-pass and pretty run-pass tests could run concurrently, and if they do, // they need to keep their output segregated. Same is true for debuginfo tests that - // can be run both on gdb and lldb. + // can be run on cdb, gdb, and lldb. match self { Pretty => ".pretty", + DebugInfoCdb => ".cdb", DebugInfoGdb => ".gdb", DebugInfoLldb => ".lldb", _ => "", @@ -50,7 +55,8 @@ impl FromStr for Mode { "run-pass" => Ok(RunPass), "run-pass-valgrind" => Ok(RunPassValgrind), "pretty" => Ok(Pretty), - "debuginfo-both" => Ok(DebugInfoBoth), + "debuginfo-cdb" => Ok(DebugInfoCdb), + "debuginfo-gdb+lldb" => Ok(DebugInfoGdbLldb), "debuginfo-lldb" => Ok(DebugInfoLldb), "debuginfo-gdb" => Ok(DebugInfoGdb), "codegen" => Ok(Codegen), @@ -59,7 +65,9 @@ impl FromStr for Mode { "incremental" => Ok(Incremental), "run-make" => Ok(RunMake), "ui" => Ok(Ui), + "js-doc-test" => Ok(JsDocTest), "mir-opt" => Ok(MirOpt), + "assembly" => Ok(Assembly), _ => Err(()), } } @@ -73,7 +81,8 @@ impl fmt::Display for Mode { RunPass => "run-pass", RunPassValgrind => "run-pass-valgrind", Pretty => "pretty", - DebugInfoBoth => "debuginfo-both", + DebugInfoCdb => "debuginfo-cdb", + DebugInfoGdbLldb => "debuginfo-gdb+lldb", DebugInfoGdb => "debuginfo-gdb", DebugInfoLldb => "debuginfo-lldb", Codegen => "codegen", @@ -82,7 +91,39 @@ impl fmt::Display for Mode { Incremental => "incremental", RunMake => "run-make", Ui => "ui", + JsDocTest => "js-doc-test", MirOpt => "mir-opt", + Assembly => "assembly", + }; + fmt::Display::fmt(s, f) + } +} + +#[derive(Clone, Copy, PartialEq, Debug, Hash)] +pub enum PassMode { + Check, + Build, + Run, +} + +impl FromStr for PassMode { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "check" => Ok(PassMode::Check), + "build" => Ok(PassMode::Build), + "run" => Ok(PassMode::Run), + _ => Err(()), + } + } +} + +impl fmt::Display for PassMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match *self { + PassMode::Check => "check", + PassMode::Build => "build", + PassMode::Run => "run", }; fmt::Display::fmt(s, f) } @@ -111,6 +152,7 @@ impl CompareMode { } } +/// Configuration for compiletest #[derive(Clone)] pub struct Config { /// `true` to to overwrite stderr/stdout files instead of complaining about changes in output. @@ -137,6 +179,9 @@ pub struct Config { /// The LLVM `FileCheck` binary path. pub llvm_filecheck: Option, + /// Path to LLVM's bin directory. + pub llvm_bin_dir: Option, + /// The valgrind path. pub valgrind_path: Option, @@ -169,6 +214,9 @@ pub struct Config { /// Exactly match the filter, rather than a substring pub filter_exact: bool, + /// Force the pass mode of a check/build/run-pass test to this mode. + pub force_pass_mode: Option, + /// Write out a parseable log of tests that were run pub logfile: Option, @@ -188,6 +236,9 @@ pub struct Config { /// Host triple for the compiler being invoked pub host: String, + /// Path to / name of the Microsoft Console Debugger (CDB) executable + pub cdb: Option, + /// Path to / name of the GDB executable pub gdb: Option, @@ -239,6 +290,11 @@ pub struct Config { /// mode describing what file the actual ui output will be compared to pub compare_mode: Option, + /// If true, this will generate a coverage file with UI test files that run `MachineApplicable` + /// diagnostics but are missing `run-rustfix` annotations. The generated coverage file is + /// created in `//rustfix_missing_coverage.txt` + pub rustfix_coverage: bool, + // Configuration for various run-make tests frobbing things like C compilers // or querying about various LLVM component information. pub cc: String, @@ -248,6 +304,8 @@ pub struct Config { pub linker: Option, pub llvm_components: String, pub llvm_cxxflags: String, + + /// Path to a NodeJS executable. Used for JS doctests, emscripten and WASM tests pub nodejs: Option, } diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index 0329fb0db1422..5b3936ffc1e3b 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -7,6 +7,8 @@ use std::io::BufReader; use std::path::Path; use std::str::FromStr; +use log::*; + #[derive(Clone, Debug, PartialEq)] pub enum ErrorKind { Help, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index c2c4a6b69cca5..52f777db2daa6 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -4,7 +4,9 @@ use std::io::prelude::*; use std::io::BufReader; use std::path::{Path, PathBuf}; -use crate::common::{self, CompareMode, Config, Mode}; +use log::*; + +use crate::common::{self, CompareMode, Config, Mode, PassMode}; use crate::util; use crate::extract_gdb_version; @@ -55,9 +57,9 @@ enum ParsedNameDirective { NoMatch, /// Match. Match, - /// Mode was DebugInfoBoth and this matched gdb. + /// Mode was DebugInfoGdbLldb and this matched gdb. MatchGdb, - /// Mode was DebugInfoBoth and this matched lldb. + /// Mode was DebugInfoGdbLldb and this matched lldb. MatchLldb, } @@ -79,15 +81,22 @@ impl EarlyProps { revisions: vec![], }; - if config.mode == common::DebugInfoBoth { + if config.mode == common::DebugInfoGdbLldb { if config.lldb_python_dir.is_none() { props.ignore = props.ignore.no_lldb(); } if config.gdb_version.is_none() { props.ignore = props.ignore.no_gdb(); } + } else if config.mode == common::DebugInfoCdb { + if config.cdb.is_none() { + props.ignore = Ignore::Ignore; + } } + let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some(); + let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(); + iter_header(testfile, None, &mut |ln| { // we should check if any only- exists and if it exists // and does not matches the current platform, skip the test @@ -116,14 +125,24 @@ impl EarlyProps { config.parse_needs_matching_clang(ln) { props.ignore = Ignore::Ignore; } + + if !rustc_has_profiler_support && + config.parse_needs_profiler_support(ln) { + props.ignore = Ignore::Ignore; + } + + if !rustc_has_sanitizer_support && + config.parse_needs_sanitizer_support(ln) { + props.ignore = Ignore::Ignore; + } } - if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoBoth) && + if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoGdbLldb) && props.ignore.can_run_gdb() && ignore_gdb(config, ln) { props.ignore = props.ignore.no_gdb(); } - if (config.mode == common::DebugInfoLldb || config.mode == common::DebugInfoBoth) && + if (config.mode == common::DebugInfoLldb || config.mode == common::DebugInfoGdbLldb) && props.ignore.can_run_lldb() && ignore_lldb(config, ln) { props.ignore = props.ignore.no_lldb(); } @@ -286,8 +305,15 @@ pub struct TestProps { // directory as the test, but for backwards compatibility reasons // we also check the auxiliary directory) pub aux_builds: Vec, + // A list of crates to pass '--extern-private name:PATH' flags for + // This should be a subset of 'aux_build' + // FIXME: Replace this with a better solution: https://github.com/rust-lang/rust/pull/54020 + pub extern_private: Vec, // Environment settings to use for compiling pub rustc_env: Vec<(String, String)>, + // Environment variables to unset prior to compiling. + // Variables are unset before applying 'rustc_env'. + pub unset_rustc_env: Vec, // Environment settings to use during execution pub exec_env: Vec<(String, String)>, // Lines to check if they appear in the expected debugger output @@ -303,6 +329,10 @@ pub struct TestProps { // For UI tests, allows compiler to generate arbitrary output to stderr pub dont_check_compiler_stderr: bool, // Don't force a --crate-type=dylib flag on the command line + // + // Set this for example if you have an auxiliary test file that contains + // a proc-macro and needs `#![crate_type = "proc-macro"]`. This ensures + // that the aux file is compiled as a `proc-macro` and not as a `dylib`. pub no_prefer_dynamic: bool, // Run --pretty expanded when running pretty printing tests pub pretty_expanded: bool, @@ -319,22 +349,24 @@ pub struct TestProps { // testing harness and used when generating compilation // arguments. (In particular, it propagates to the aux-builds.) pub incremental_dir: Option, - // Specifies that a test must actually compile without errors. - pub compile_pass: bool, + // How far should the test proceed while still passing. + pass_mode: Option, + // Ignore `--pass` overrides from the command line for this test. + ignore_pass: bool, // rustdoc will test the output of the `--test` option pub check_test_line_numbers_match: bool, - // The test must be compiled and run successfully. Only used in UI tests for now. - pub run_pass: bool, - // Skip any codegen step and running the executable. Only for run-pass. - pub skip_codegen: bool, // Do not pass `-Z ui-testing` to UI tests pub disable_ui_testing_normalization: bool, // customized normalization rules pub normalize_stdout: Vec<(String, String)>, pub normalize_stderr: Vec<(String, String)>, pub failure_status: i32, + // Whether or not `rustfix` should apply the `CodeSuggestion`s of this test and compile the + // resulting Rust code. pub run_rustfix: bool, + // If true, `rustfix` will only apply `MachineApplicable` suggestions. pub rustfix_only_machine_applicable: bool, + pub assembly_output: Option, } impl TestProps { @@ -345,8 +377,10 @@ impl TestProps { run_flags: None, pp_exact: None, aux_builds: vec![], + extern_private: vec![], revisions: vec![], rustc_env: vec![], + unset_rustc_env: vec![], exec_env: vec![], check_lines: vec![], build_aux_docs: false, @@ -360,16 +394,16 @@ impl TestProps { pretty_compare_only: false, forbid_output: vec![], incremental_dir: None, - compile_pass: false, + pass_mode: None, + ignore_pass: false, check_test_line_numbers_match: false, - run_pass: false, - skip_codegen: false, disable_ui_testing_normalization: false, normalize_stdout: vec![], normalize_stderr: vec![], failure_status: -1, run_rustfix: false, rustfix_only_machine_applicable: false, + assembly_output: None, } } @@ -460,6 +494,10 @@ impl TestProps { self.aux_builds.push(ab); } + if let Some(ep) = config.parse_extern_private(ln) { + self.extern_private.push(ep); + } + if let Some(ee) = config.parse_env(ln, "exec-env") { self.exec_env.push(ee); } @@ -468,6 +506,10 @@ impl TestProps { self.rustc_env.push(ee); } + if let Some(ev) = config.parse_name_value_directive(ln, "unset-rustc-env") { + self.unset_rustc_env.push(ev); + } + if let Some(cl) = config.parse_check_line(ln) { self.check_lines.push(cl); } @@ -480,17 +522,10 @@ impl TestProps { self.check_test_line_numbers_match = config.parse_check_test_line_numbers_match(ln); } - if !self.run_pass { - self.run_pass = config.parse_run_pass(ln); - } - - if !self.compile_pass { - // run-pass implies must_compile_successfully - self.compile_pass = config.parse_compile_pass(ln) || self.run_pass; - } + self.update_pass_mode(ln, cfg, config); - if !self.skip_codegen { - self.skip_codegen = config.parse_skip_codegen(ln); + if !self.ignore_pass { + self.ignore_pass = config.parse_ignore_pass(ln); } if !self.disable_ui_testing_normalization { @@ -517,6 +552,10 @@ impl TestProps { self.rustfix_only_machine_applicable = config.parse_rustfix_only_machine_applicable(ln); } + + if self.assembly_output.is_none() { + self.assembly_output = config.parse_assembly_output(ln); + } }); if self.failure_status == -1 { @@ -534,6 +573,50 @@ impl TestProps { } } } + + fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config) { + let check_no_run = |s| { + if config.mode != Mode::Ui && config.mode != Mode::Incremental { + panic!("`{}` header is only supported in UI and incremental tests", s); + } + if config.mode == Mode::Incremental && + !revision.map_or(false, |r| r.starts_with("cfail")) && + !self.revisions.iter().all(|r| r.starts_with("cfail")) { + panic!("`{}` header is only supported in `cfail` incremental tests", s); + } + }; + let pass_mode = if config.parse_name_directive(ln, "check-pass") { + check_no_run("check-pass"); + Some(PassMode::Check) + } else if config.parse_name_directive(ln, "build-pass") { + check_no_run("build-pass"); + Some(PassMode::Build) + } else if config.parse_name_directive(ln, "compile-pass") /* compatibility */ { + check_no_run("compile-pass"); + Some(PassMode::Build) + } else if config.parse_name_directive(ln, "run-pass") { + if config.mode != Mode::Ui && config.mode != Mode::RunPass /* compatibility */ { + panic!("`run-pass` header is only supported in UI tests") + } + Some(PassMode::Run) + } else { + None + }; + match (self.pass_mode, pass_mode) { + (None, Some(_)) => self.pass_mode = pass_mode, + (Some(_), Some(_)) => panic!("multiple `*-pass` headers in a single test"), + (_, None) => {} + } + } + + pub fn pass_mode(&self, config: &Config) -> Option { + if !self.ignore_pass { + if let (mode @ Some(_), Some(_)) = (config.force_pass_mode, self.pass_mode) { + return mode; + } + } + self.pass_mode + } } fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut dyn FnMut(&str)) { @@ -594,6 +677,11 @@ impl Config { fn parse_aux_build(&self, line: &str) -> Option { self.parse_name_value_directive(line, "aux-build") + .map(|r| r.trim().to_string()) + } + + fn parse_extern_private(&self, line: &str) -> Option { + self.parse_name_value_directive(line, "extern-private") } fn parse_compile_flags(&self, line: &str) -> Option { @@ -656,10 +744,6 @@ impl Config { } } - fn parse_compile_pass(&self, line: &str) -> bool { - self.parse_name_directive(line, "compile-pass") - } - fn parse_disable_ui_testing_normalization(&self, line: &str) -> bool { self.parse_name_directive(line, "disable-ui-testing-normalization") } @@ -668,12 +752,13 @@ impl Config { self.parse_name_directive(line, "check-test-line-numbers-match") } - fn parse_run_pass(&self, line: &str) -> bool { - self.parse_name_directive(line, "run-pass") + fn parse_ignore_pass(&self, line: &str) -> bool { + self.parse_name_directive(line, "ignore-pass") } - fn parse_skip_codegen(&self, line: &str) -> bool { - self.parse_name_directive(line, "skip-codegen") + fn parse_assembly_output(&self, line: &str) -> Option { + self.parse_name_value_directive(line, "assembly-output") + .map(|r| r.trim().to_string()) } fn parse_env(&self, line: &str, name: &str) -> Option<(String, String)> { @@ -716,6 +801,14 @@ impl Config { self.parse_name_directive(line, "needs-matching-clang") } + fn parse_needs_profiler_support(&self, line: &str) -> bool { + self.parse_name_directive(line, "needs-profiler-support") + } + + fn parse_needs_sanitizer_support(&self, line: &str) -> bool { + self.parse_name_directive(line, "needs-sanitizer-support") + } + /// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86` /// or `normalize-stderr-32bit`. fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirective { @@ -741,7 +834,7 @@ impl Config { ParsedNameDirective::Match } else { match self.mode { - common::DebugInfoBoth => { + common::DebugInfoGdbLldb => { if name == "gdb" { ParsedNameDirective::MatchGdb } else if name == "lldb" { @@ -750,6 +843,11 @@ impl Config { ParsedNameDirective::NoMatch } }, + common::DebugInfoCdb => if name == "cdb" { + ParsedNameDirective::Match + } else { + ParsedNameDirective::NoMatch + }, common::DebugInfoGdb => if name == "gdb" { ParsedNameDirective::Match } else { diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 12aae303f29aa..02b09e21ff022 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -1,12 +1,13 @@ +//! These structs are a subset of the ones found in `syntax::json`. +//! They are only used for deserialization of JSON output provided by libtest. + use crate::errors::{Error, ErrorKind}; use crate::runtest::ProcRes; +use serde::Deserialize; use serde_json; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::str::FromStr; -// These structs are a subset of the ones found in -// `syntax::json`. - #[derive(Deserialize)] struct Diagnostic { message: String, @@ -17,6 +18,12 @@ struct Diagnostic { rendered: Option, } +#[derive(Deserialize)] +struct ArtifactNotification { + #[allow(dead_code)] + artifact: PathBuf, +} + #[derive(Deserialize, Clone)] struct DiagnosticSpan { file_name: String, @@ -62,23 +69,26 @@ struct DiagnosticCode { explanation: Option, } -pub fn extract_rendered(output: &str, proc_res: &ProcRes) -> String { +pub fn extract_rendered(output: &str) -> String { output .lines() .filter_map(|line| { if line.starts_with('{') { - match serde_json::from_str::(line) { - Ok(diagnostic) => diagnostic.rendered, - Err(error) => { - proc_res.fatal(Some(&format!( - "failed to decode compiler output as json: \ - `{}`\nline: {}\noutput: {}", - error, line, output - ))); - } + if let Ok(diagnostic) = serde_json::from_str::(line) { + diagnostic.rendered + } else if let Ok(_) = serde_json::from_str::(line) { + // Ignore the notification. + None + } else { + print!( + "failed to decode compiler output as json: line: {}\noutput: {}", + line, output + ); + panic!() } } else { - None + // preserve non-JSON lines, such as ICEs + Some(format!("{}\n", line)) } }) .collect() diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 86cdadade108f..597fdf2d95e30 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -1,22 +1,14 @@ #![crate_name = "compiletest"] #![feature(test)] +#![feature(vec_remove_item)] #![deny(warnings, rust_2018_idioms)] -#[cfg(unix)] -extern crate libc; -#[macro_use] -extern crate log; -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate serde_derive; extern crate test; -use crate::common::CompareMode; +use crate::common::{CompareMode, PassMode}; use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS}; use crate::common::{Config, TestPaths}; -use crate::common::{DebugInfoBoth, DebugInfoGdb, DebugInfoLldb, Mode, Pretty}; -use filetime::FileTime; +use crate::common::{DebugInfoCdb, DebugInfoGdbLldb, DebugInfoGdb, DebugInfoLldb, Mode, Pretty}; use getopts::Options; use std::env; use std::ffi::OsString; @@ -24,11 +16,13 @@ use std::fs; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; use std::process::Command; +use std::time::SystemTime; use test::ColorConfig; use crate::util::logv; use walkdir::WalkDir; use env_logger; use getopts; +use log::*; use self::header::{EarlyProps, Ignore}; @@ -134,6 +128,12 @@ pub fn parse_config(args: Vec) -> Config { "(compile-fail|run-fail|run-pass|\ run-pass-valgrind|pretty|debug-info|incremental|mir-opt)", ) + .optopt( + "", + "pass", + "force {check,build,run}-pass tests to this mode.", + "check | build | run" + ) .optflag("", "ignored", "run tests marked as ignored") .optflag("", "exact", "filters match exactly") .optopt( @@ -170,6 +170,12 @@ pub fn parse_config(args: Vec) -> Config { .optopt("", "logfile", "file to log test execution to", "FILE") .optopt("", "target", "the target to build for", "TARGET") .optopt("", "host", "the host to build for", "HOST") + .optopt( + "", + "cdb", + "path to CDB to use for CDB debuginfo tests", + "PATH", + ) .optopt( "", "gdb", @@ -220,6 +226,7 @@ pub fn parse_config(args: Vec) -> Config { "LIST", ) .reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS") + .optopt("", "llvm-bin-dir", "Path to LLVM's `bin` directory", "PATH") .optopt("", "nodejs", "the name of nodejs", "PATH") .optopt( "", @@ -233,6 +240,12 @@ pub fn parse_config(args: Vec) -> Config { "mode describing what file the actual ui output will be compared to", "COMPARE MODE", ) + .optflag( + "", + "rustfix-coverage", + "enable this to generate a Rustfix coverage file, which is saved in \ + `.//rustfix_missing_coverage.txt`", + ) .optflag("h", "help", "show this message"); let (argv0, args_) = args.split_first().unwrap(); @@ -272,6 +285,7 @@ pub fn parse_config(args: Vec) -> Config { let target = opt_str2(matches.opt_str("target")); let android_cross_path = opt_path(matches, "android-cross-path"); + let cdb = analyze_cdb(matches.opt_str("cdb"), &target); let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); let (lldb_version, lldb_native_rust) = extract_lldb_version(matches.opt_str("lldb-version")); @@ -299,7 +313,8 @@ pub fn parse_config(args: Vec) -> Config { valgrind_path: matches.opt_str("valgrind-path"), force_valgrind: matches.opt_present("force-valgrind"), run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), - llvm_filecheck: matches.opt_str("llvm-filecheck").map(|s| PathBuf::from(&s)), + llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from), + llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from), src_base, build_base: opt_path(matches, "build-base"), stage_id: matches.opt_str("stage-id").unwrap(), @@ -311,12 +326,17 @@ pub fn parse_config(args: Vec) -> Config { run_ignored, filter: matches.free.first().cloned(), filter_exact: matches.opt_present("exact"), + force_pass_mode: matches.opt_str("pass").map(|mode| + mode.parse::() + .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode)) + ), logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)), runtool: matches.opt_str("runtool"), host_rustcflags: matches.opt_str("host-rustcflags"), target_rustcflags: matches.opt_str("target-rustcflags"), target: target, host: opt_str2(matches.opt_str("host")), + cdb, gdb, gdb_version, gdb_native_rust, @@ -336,6 +356,7 @@ pub fn parse_config(args: Vec) -> Config { color, remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), compare_mode: matches.opt_str("compare-mode").map(CompareMode::parse), + rustfix_coverage: matches.opt_present("rustfix-coverage"), cc: matches.opt_str("cc").unwrap(), cxx: matches.opt_str("cxx").unwrap(), @@ -371,6 +392,10 @@ pub fn log_config(config: &Config) { ), ); logv(c, format!("filter_exact: {}", config.filter_exact)); + logv(c, format!( + "force_pass_mode: {}", + opt_str(&config.force_pass_mode.map(|m| format!("{}", m))), + )); logv(c, format!("runtool: {}", opt_str(&config.runtool))); logv( c, @@ -418,7 +443,7 @@ pub fn opt_str2(maybestr: Option) -> String { pub fn run_tests(config: &Config) { if config.target.contains("android") { - if config.mode == DebugInfoGdb || config.mode == DebugInfoBoth { + if config.mode == DebugInfoGdb || config.mode == DebugInfoGdbLldb { println!( "{} debug-info test uses tcp 5039 port.\ please reserve it", @@ -437,8 +462,8 @@ pub fn run_tests(config: &Config) { match config.mode { // Note that we don't need to emit the gdb warning when - // DebugInfoBoth, so it is ok to list that here. - DebugInfoBoth | DebugInfoLldb => { + // DebugInfoGdbLldb, so it is ok to list that here. + DebugInfoGdbLldb | DebugInfoLldb => { if let Some(lldb_version) = config.lldb_version.as_ref() { if is_blacklisted_lldb_version(&lldb_version[..]) { println!( @@ -467,7 +492,8 @@ pub fn run_tests(config: &Config) { return; } } - _ => { /* proceed */ } + + DebugInfoCdb | _ => { /* proceed */ } } // FIXME(#33435) Avoid spurious failures in codegen-units/partitioning tests. @@ -475,6 +501,19 @@ pub fn run_tests(config: &Config) { let _ = fs::remove_dir_all("tmp/partitioning-tests"); } + // If we want to collect rustfix coverage information, + // we first make sure that the coverage file does not exist. + // It will be created later on. + if config.rustfix_coverage { + let mut coverage_file_path = config.build_base.clone(); + coverage_file_path.push("rustfix_missing_coverage.txt"); + if coverage_file_path.exists() { + if let Err(e) = fs::remove_file(&coverage_file_path) { + panic!("Could not delete {} due to {}", coverage_file_path.display(), e) + } + } + } + let opts = test_opts(config); let tests = make_tests(config); // sadly osx needs some file descriptor limits raised for running tests in @@ -502,6 +541,7 @@ pub fn run_tests(config: &Config) { pub fn test_opts(config: &Config) -> test::TestOpts { test::TestOpts { + exclude_should_panic: false, filter: config.filter.clone(), filter_exact: config.filter_exact, run_ignored: if config.run_ignored { @@ -598,6 +638,8 @@ fn collect_tests_from_dir( Ok(()) } + +/// Returns true if `file_name` looks like a proper test file name. pub fn is_test(file_name: &OsString) -> bool { let file_name = file_name.to_str().unwrap(); @@ -648,7 +690,7 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> Vec Self { + let time = fs::metadata(p) + .and_then(|metadata| metadata.modified()) + .unwrap_or(SystemTime::UNIX_EPOCH); + Stamp { - time: mtime(&p), + time, file: p.into(), } } - fn from_dir(path: &Path) -> impl Iterator { + fn from_dir(path: &Path) -> impl Iterator { WalkDir::new(path) .into_iter() .map(|entry| entry.unwrap()) .filter(|entry| entry.file_type().is_file()) - .map(|entry| Stamp::from_path(entry.path())) - } -} + .map(|entry| { + let time = (|| -> io::Result<_> { entry.metadata()?.modified() })(); -fn mtime(path: &Path) -> FileTime { - fs::metadata(path) - .map(|f| FileTime::from_last_modification_time(&f)) - .unwrap_or_else(|_| FileTime::zero()) + Stamp { + time: time.unwrap_or(SystemTime::UNIX_EPOCH), + file: entry.path().into(), + } + }) + } } fn make_test_name( @@ -791,7 +838,7 @@ fn make_test_closure( revision: Option<&String>, ) -> test::TestFn { let mut config = config.clone(); - if config.mode == DebugInfoBoth { + if config.mode == DebugInfoGdbLldb { // If both gdb and lldb were ignored, then the test as a whole // would be ignored. if !ignore.can_run_gdb() { @@ -817,6 +864,47 @@ fn is_android_gdb_target(target: &String) -> bool { } } +/// Returns `true` if the given target is a MSVC target for the purpouses of CDB testing. +fn is_pc_windows_msvc_target(target: &String) -> bool { + target.ends_with("-pc-windows-msvc") +} + +fn find_cdb(target: &String) -> Option { + if !(cfg!(windows) && is_pc_windows_msvc_target(target)) { + return None; + } + + let pf86 = env::var_os("ProgramFiles(x86)").or(env::var_os("ProgramFiles"))?; + let cdb_arch = if cfg!(target_arch="x86") { + "x86" + } else if cfg!(target_arch="x86_64") { + "x64" + } else if cfg!(target_arch="aarch64") { + "arm64" + } else if cfg!(target_arch="arm") { + "arm" + } else { + return None; // No compatible CDB.exe in the Windows 10 SDK + }; + + let mut path = PathBuf::new(); + path.push(pf86); + path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too? + path.push(cdb_arch); + path.push(r"cdb.exe"); + + if !path.exists() { + return None; + } + + Some(path.into_os_string()) +} + +/// Returns Path to CDB +fn analyze_cdb(cdb: Option, target: &String) -> Option { + cdb.map(|s| OsString::from(s)).or(find_cdb(target)) +} + /// Returns (Path to GDB, GDB Version, GDB has Rust Support) fn analyze_gdb(gdb: Option, target: &String, android_cross_path: &PathBuf) -> (Option, Option, bool) { @@ -1048,3 +1136,12 @@ fn test_extract_gdb_version() { 7012050: "GNU gdb (GDB) 7.12.50.20161027-git", } } + +#[test] +fn is_test_test() { + assert_eq!(true, is_test(&OsString::from("a_test.rs"))); + assert_eq!(false, is_test(&OsString::from(".a_test.rs"))); + assert_eq!(false, is_test(&OsString::from("a_cat.gif"))); + assert_eq!(false, is_test(&OsString::from("#a_dog_gif"))); + assert_eq!(false, is_test(&OsString::from("~a_temp_file"))); +} diff --git a/src/tools/compiletest/src/raise_fd_limit.rs b/src/tools/compiletest/src/raise_fd_limit.rs index 7f1d7e0d3cdd4..e9c91094104e9 100644 --- a/src/tools/compiletest/src/raise_fd_limit.rs +++ b/src/tools/compiletest/src/raise_fd_limit.rs @@ -7,7 +7,6 @@ #[cfg(any(target_os = "macos", target_os = "ios"))] #[allow(non_camel_case_types)] pub unsafe fn raise_fd_limit() { - use libc; use std::cmp; use std::io; use std::mem::size_of_val; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index bac41a7c57904..35caf82dd7128 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1,16 +1,18 @@ -use crate::common::CompareMode; +// ignore-tidy-filelength + +use crate::common::{CompareMode, PassMode}; use crate::common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT}; use crate::common::{output_base_dir, output_base_name, output_testname_unique}; -use crate::common::{Codegen, CodegenUnits, DebugInfoBoth, DebugInfoGdb, DebugInfoLldb, Rustdoc}; +use crate::common::{Codegen, CodegenUnits, Rustdoc}; +use crate::common::{DebugInfoCdb, DebugInfoGdbLldb, DebugInfoGdb, DebugInfoLldb}; use crate::common::{CompileFail, Pretty, RunFail, RunPass, RunPassValgrind}; use crate::common::{Config, TestPaths}; -use crate::common::{Incremental, MirOpt, RunMake, Ui}; +use crate::common::{Incremental, MirOpt, RunMake, Ui, JsDocTest, Assembly}; use diff; use crate::errors::{self, Error, ErrorKind}; -use filetime::FileTime; use crate::header::TestProps; use crate::json; -use regex::Regex; +use regex::{Captures, Regex}; use rustfix::{apply_suggestions, get_suggestions_from_json, Filter}; use crate::util::{logv, PathBufExt}; @@ -19,7 +21,7 @@ use std::collections::{HashMap, HashSet, VecDeque}; use std::env; use std::ffi::{OsStr, OsString}; use std::fmt; -use std::fs::{self, create_dir_all, File}; +use std::fs::{self, create_dir_all, File, OpenOptions}; use std::hash::{Hash, Hasher}; use std::io::prelude::*; use std::io::{self, BufReader}; @@ -27,6 +29,9 @@ use std::path::{Path, PathBuf}; use std::process::{Child, Command, ExitStatus, Output, Stdio}; use std::str; +use lazy_static::lazy_static; +use log::*; + use crate::extract_gdb_version; use crate::is_android_gdb_target; @@ -74,6 +79,25 @@ pub fn dylib_env_var() -> &'static str { } } +/// The platform-specific library name +pub fn get_lib_name(lib: &str, dylib: bool) -> String { + // In some casess (e.g. MUSL), we build a static + // library, rather than a dynamic library. + // In this case, the only path we can pass + // with '--extern-meta' is the '.lib' file + if !dylib { + return format!("lib{}.rlib", lib); + } + + if cfg!(windows) { + format!("{}.dll", lib) + } else if cfg!(target_os = "macos") { + format!("lib{}.dylib", lib) + } else { + format!("lib{}.so", lib) + } +} + #[derive(Debug, PartialEq)] pub enum DiffLine { Context(String), @@ -219,7 +243,11 @@ pub fn compute_stamp_hash(config: &Config) -> String { let mut hash = DefaultHasher::new(); config.stage_id.hash(&mut hash); - if config.mode == DebugInfoGdb || config.mode == DebugInfoBoth { + if config.mode == DebugInfoCdb { + config.cdb.hash(&mut hash); + } + + if config.mode == DebugInfoGdb || config.mode == DebugInfoGdbLldb { match config.gdb { None => env::var_os("PATH").hash(&mut hash), Some(ref s) if s.is_empty() => env::var_os("PATH").hash(&mut hash), @@ -227,11 +255,15 @@ pub fn compute_stamp_hash(config: &Config) -> String { }; } - if config.mode == DebugInfoLldb || config.mode == DebugInfoBoth { + if config.mode == DebugInfoLldb || config.mode == DebugInfoGdbLldb { env::var_os("PATH").hash(&mut hash); env::var_os("PYTHONPATH").hash(&mut hash); } + if let Ui | RunPass | Incremental | Pretty = config.mode { + config.force_pass_mode.hash(&mut hash); + } + format!("{:x}", hash.finish()) } @@ -262,10 +294,11 @@ impl<'test> TestCx<'test> { RunFail => self.run_rfail_test(), RunPassValgrind => self.run_valgrind_test(), Pretty => self.run_pretty_test(), - DebugInfoBoth => { + DebugInfoGdbLldb => { self.run_debuginfo_gdb_test(); self.run_debuginfo_lldb_test(); }, + DebugInfoCdb => self.run_debuginfo_cdb_test(), DebugInfoGdb => self.run_debuginfo_gdb_test(), DebugInfoLldb => self.run_debuginfo_lldb_test(), Codegen => self.run_codegen_test(), @@ -275,23 +308,28 @@ impl<'test> TestCx<'test> { RunMake => self.run_rmake_test(), RunPass | Ui => self.run_ui_test(), MirOpt => self.run_mir_opt_test(), + Assembly => self.run_assembly_test(), + JsDocTest => self.run_js_doc_test(), } } + fn pass_mode(&self) -> Option { + self.props.pass_mode(self.config) + } + fn should_run_successfully(&self) -> bool { - let run_pass = match self.config.mode { - RunPass => true, - Ui => self.props.run_pass, - _ => unimplemented!(), - }; - return run_pass && !self.props.skip_codegen; + match self.config.mode { + RunPass | Ui => self.pass_mode() == Some(PassMode::Run), + mode => panic!("unimplemented for mode {:?}", mode), + } } fn should_compile_successfully(&self) -> bool { match self.config.mode { - CompileFail => self.props.compile_pass, + CompileFail => false, RunPass => true, - Ui => self.props.compile_pass, + JsDocTest => true, + Ui => self.pass_mode().is_some(), Incremental => { let revision = self.revision .expect("incremental tests require a list of revisions"); @@ -299,7 +337,7 @@ impl<'test> TestCx<'test> { true } else if revision.starts_with("cfail") { // FIXME: would be nice if incremental revs could start with "cpass" - self.props.compile_pass + self.pass_mode().is_some() } else { panic!("revision name must begin with rpass, rfail, or cfail"); } @@ -401,11 +439,9 @@ impl<'test> TestCx<'test> { "run-pass tests with expected warnings should be moved to ui/" ); - if !self.props.skip_codegen { - let proc_res = self.exec_compiled_test(); - if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); - } + let proc_res = self.exec_compiled_test(); + if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); } } @@ -630,6 +666,95 @@ impl<'test> TestCx<'test> { self.compose_and_run_compiler(rustc, Some(src)) } + fn run_debuginfo_cdb_test(&self) { + assert!(self.revision.is_none(), "revisions not relevant here"); + + let config = Config { + target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), + host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), + mode: DebugInfoCdb, + ..self.config.clone() + }; + + let test_cx = TestCx { + config: &config, + ..*self + }; + + test_cx.run_debuginfo_cdb_test_no_opt(); + } + + fn run_debuginfo_cdb_test_no_opt(&self) { + // compile test file (it should have 'compile-flags:-g' in the header) + let compile_result = self.compile_test(); + if !compile_result.status.success() { + self.fatal_proc_rec("compilation failed!", &compile_result); + } + + let exe_file = self.make_exe_name(); + + let prefixes = { + static PREFIXES: &'static [&'static str] = &["cdb", "cdbg"]; + // No "native rust support" variation for CDB yet. + PREFIXES + }; + + // Parse debugger commands etc from test files + let DebuggerCommands { + commands, + check_lines, + breakpoint_lines, + .. + } = self.parse_debugger_commands(prefixes); + + // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands + let mut script_str = String::with_capacity(2048); + script_str.push_str("version\n"); // List CDB (and more) version info in test output + script_str.push_str(".nvlist\n"); // List loaded `*.natvis` files, bulk of custom MSVC debug + + // Set breakpoints on every line that contains the string "#break" + let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy(); + for line in &breakpoint_lines { + script_str.push_str(&format!( + "bp `{}:{}`\n", + source_file_name, line + )); + } + + // Append the other `cdb-command:`s + for line in &commands { + script_str.push_str(line); + script_str.push_str("\n"); + } + + script_str.push_str("\nqq\n"); // Quit the debugger (including remote debugger, if any) + + // Write the script into a file + debug!("script_str = {}", script_str); + self.dump_output_file(&script_str, "debugger.script"); + let debugger_script = self.make_out_name("debugger.script"); + + let cdb_path = &self.config.cdb.as_ref().unwrap(); + let mut cdb = Command::new(cdb_path); + cdb + .arg("-lines") // Enable source line debugging. + .arg("-cf").arg(&debugger_script) + .arg(&exe_file); + + let debugger_run_result = self.compose_and_run( + cdb, + self.config.run_lib_path.to_str().unwrap(), + None, // aux_path + None // input + ); + + if !debugger_run_result.status.success() { + self.fatal_proc_rec("Error while running CDB", &debugger_run_result); + } + + self.check_debugger_output(&debugger_run_result, &check_lines); + } + fn run_debuginfo_gdb_test(&self) { assert!(self.revision.is_none(), "revisions not relevant here"); @@ -1223,7 +1348,7 @@ impl<'test> TestCx<'test> { fn check_error_patterns(&self, output_to_check: &str, proc_res: &ProcRes) { debug!("check_error_patterns"); if self.props.error_patterns.is_empty() { - if self.props.compile_pass { + if self.pass_mode().is_some() { return; } else { self.fatal(&format!( @@ -1398,10 +1523,21 @@ impl<'test> TestCx<'test> { } fn compile_test(&self) -> ProcRes { - let mut rustc = self.make_compile_args( - &self.testpaths.file, - TargetLocation::ThisFile(self.make_exe_name()), - ); + // Only use `make_exe_name` when the test ends up being executed. + let will_execute = match self.config.mode { + RunPass | Ui => self.should_run_successfully(), + Incremental => self.revision.unwrap().starts_with("r"), + RunFail | RunPassValgrind | MirOpt | + DebugInfoCdb | DebugInfoGdbLldb | DebugInfoGdb | DebugInfoLldb => true, + _ => false, + }; + let output_file = if will_execute { + TargetLocation::ThisFile(self.make_exe_name()) + } else { + TargetLocation::ThisDirectory(self.output_base_dir()) + }; + + let mut rustc = self.make_compile_args(&self.testpaths.file, output_file); rustc.arg("-L").arg(&self.aux_output_dir_name()); @@ -1582,6 +1718,16 @@ impl<'test> TestCx<'test> { create_dir_all(&aux_dir).unwrap(); } + // Use a Vec instead of a HashMap to preserve original order + let mut extern_priv = self.props.extern_private.clone(); + + let mut add_extern_priv = |priv_dep: &str, dylib: bool| { + let lib_name = get_lib_name(priv_dep, dylib); + rustc + .arg("--extern-private") + .arg(format!("{}={}", priv_dep, aux_dir.join(lib_name).to_str().unwrap())); + }; + for rel_ab in &self.props.aux_builds { let aux_testpaths = self.compute_aux_test_paths(rel_ab); let aux_props = @@ -1598,12 +1744,15 @@ impl<'test> TestCx<'test> { create_dir_all(aux_cx.output_base_dir()).unwrap(); let mut aux_rustc = aux_cx.make_compile_args(&aux_testpaths.file, aux_output); - let crate_type = if aux_props.no_prefer_dynamic { - None + let (dylib, crate_type) = if aux_props.no_prefer_dynamic { + (true, None) } else if self.config.target.contains("cloudabi") || self.config.target.contains("emscripten") - || (self.config.target.contains("musl") && !aux_props.force_host) + || (self.config.target.contains("musl") + && !aux_props.force_host + && !self.config.host.contains("musl")) || self.config.target.contains("wasm32") + || self.config.target.contains("nvptx") { // We primarily compile all auxiliary libraries as dynamic libraries // to avoid code size bloat and large binaries as much as possible @@ -1614,11 +1763,20 @@ impl<'test> TestCx<'test> { // dynamic libraries so we just go back to building a normal library. Note, // however, that for MUSL if the library is built with `force_host` then // it's ok to be a dylib as the host should always support dylibs. - Some("lib") + (false, Some("lib")) } else { - Some("dylib") + (true, Some("dylib")) }; + let trimmed = rel_ab.trim_end_matches(".rs").to_string(); + + // Normally, every 'extern-private' has a correspodning 'aux-build' + // entry. If so, we remove it from our list of private crates, + // and add an '--extern-private' flag to rustc + if extern_priv.remove_item(&trimmed).is_some() { + add_extern_priv(&trimmed, dylib); + } + if let Some(crate_type) = crate_type { aux_rustc.args(&["--crate-type", crate_type]); } @@ -1642,6 +1800,15 @@ impl<'test> TestCx<'test> { } } + // Add any '--extern-private' entries without a matching + // 'aux-build' + for private_lib in extern_priv { + add_extern_priv(&private_lib, true); + } + + self.props.unset_rustc_env.clone() + .iter() + .fold(&mut rustc, |rustc, v| rustc.env_remove(v)); rustc.envs(self.props.rustc_env.clone()); self.compose_and_run( rustc, @@ -1711,8 +1878,13 @@ impl<'test> TestCx<'test> { result } - fn make_compile_args(&self, input_file: &Path, output_file: TargetLocation) -> Command { - let is_rustdoc = self.config.src_base.ends_with("rustdoc-ui"); + fn make_compile_args( + &self, + input_file: &Path, + output_file: TargetLocation, + ) -> Command { + let is_rustdoc = self.config.src_base.ends_with("rustdoc-ui") || + self.config.src_base.ends_with("rustdoc-js"); let mut rustc = if !is_rustdoc { Command::new(&self.config.rustc_path) } else { @@ -1801,20 +1973,13 @@ impl<'test> TestCx<'test> { rustc.arg(dir_opt); } - RunFail | RunPassValgrind | Pretty | DebugInfoBoth | DebugInfoGdb | DebugInfoLldb - | Codegen | Rustdoc | RunMake | CodegenUnits => { + RunFail | RunPassValgrind | Pretty | DebugInfoCdb | DebugInfoGdbLldb | DebugInfoGdb + | DebugInfoLldb | Codegen | Rustdoc | RunMake | CodegenUnits | JsDocTest | Assembly => { // do not use JSON output } } - if self.props.skip_codegen { - assert!( - !self - .props - .compile_flags - .iter() - .any(|s| s.starts_with("--emit")) - ); + if let Some(PassMode::Check) = self.pass_mode() { rustc.args(&["--emit", "metadata"]); } @@ -1831,16 +1996,21 @@ impl<'test> TestCx<'test> { rustc.arg("-o").arg(path); } TargetLocation::ThisDirectory(path) => { - rustc.arg("--out-dir").arg(path); + if is_rustdoc { + // `rustdoc` uses `-o` for the output directory. + rustc.arg("-o").arg(path); + } else { + rustc.arg("--out-dir").arg(path); + } } } match self.config.compare_mode { Some(CompareMode::Nll) => { - rustc.args(&["-Zborrowck=migrate", "-Ztwo-phase-borrows"]); + rustc.args(&["-Zborrowck=mir"]); } Some(CompareMode::Polonius) => { - rustc.args(&["-Zpolonius", "-Zborrowck=mir", "-Ztwo-phase-borrows"]); + rustc.args(&["-Zpolonius", "-Zborrowck=mir"]); } None => {} } @@ -1858,6 +2028,11 @@ impl<'test> TestCx<'test> { } } + // Use dynamic musl for tests because static doesn't allow creating dylibs + if self.config.host.contains("musl") { + rustc.arg("-Ctarget-feature=-crt-static"); + } + rustc.args(&self.props.compile_flags); rustc @@ -2041,50 +2216,10 @@ impl<'test> TestCx<'test> { } fn fatal_proc_rec(&self, err: &str, proc_res: &ProcRes) -> ! { - self.try_print_open_handles(); self.error(err); proc_res.fatal(None); } - // This function is a poor man's attempt to debug rust-lang/rust#38620, if - // that's closed then this should be deleted - // - // This is a very "opportunistic" debugging attempt, so we ignore all - // errors here. - fn try_print_open_handles(&self) { - if !cfg!(windows) { - return; - } - if self.config.mode != Incremental { - return; - } - - let filename = match self.testpaths.file.file_stem() { - Some(path) => path, - None => return, - }; - - let mut cmd = Command::new("handle.exe"); - cmd.arg("-a").arg("-u"); - cmd.arg(filename); - cmd.arg("-nobanner"); - cmd.stdout(Stdio::piped()); - cmd.stderr(Stdio::piped()); - let output = match cmd.spawn().and_then(read2_abbreviated) { - Ok(output) => output, - Err(_) => return, - }; - println!("---------------------------------------------------"); - println!("ran extra command to debug rust-lang/rust#38620: "); - println!("{:?}", cmd); - println!("result: {}", output.status); - println!("--- stdout ----------------------------------------"); - println!("{}", String::from_utf8_lossy(&output.stdout)); - println!("--- stderr ----------------------------------------"); - println!("{}", String::from_utf8_lossy(&output.stderr)); - println!("---------------------------------------------------"); - } - // codegen tests (using FileCheck) fn compile_test_and_save_ir(&self) -> ProcRes { @@ -2097,12 +2232,37 @@ impl<'test> TestCx<'test> { self.compose_and_run_compiler(rustc, None) } - fn check_ir_with_filecheck(&self) -> ProcRes { - let irfile = self.output_base_name().with_extension("ll"); + fn compile_test_and_save_assembly(&self) -> (ProcRes, PathBuf) { + // This works with both `--emit asm` (as default output name for the assembly) + // and `ptx-linker` because the latter can write output at requested location. + let output_path = self.output_base_name().with_extension("s"); + + let output_file = TargetLocation::ThisFile(output_path.clone()); + let mut rustc = self.make_compile_args(&self.testpaths.file, output_file); + + rustc.arg("-L").arg(self.aux_output_dir_name()); + + match self.props.assembly_output.as_ref().map(AsRef::as_ref) { + Some("emit-asm") => { + rustc.arg("--emit=asm"); + } + + Some("ptx-linker") => { + // No extra flags needed. + } + + Some(_) => self.fatal("unknown 'assembly-output' header"), + None => self.fatal("missing 'assembly-output' header"), + } + + (self.compose_and_run_compiler(rustc, None), output_path) + } + + fn verify_with_filecheck(&self, output: &Path) -> ProcRes { let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap()); filecheck .arg("--input-file") - .arg(irfile) + .arg(output) .arg(&self.testpaths.file); // It would be more appropriate to make most of the arguments configurable through // a comment-attribute similar to `compile-flags`. For example, --check-prefixes is a very @@ -2121,12 +2281,29 @@ impl<'test> TestCx<'test> { self.fatal("missing --llvm-filecheck"); } - let mut proc_res = self.compile_test_and_save_ir(); + let proc_res = self.compile_test_and_save_ir(); + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + let output_path = self.output_base_name().with_extension("ll"); + let proc_res = self.verify_with_filecheck(&output_path); + if !proc_res.status.success() { + self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res); + } + } + + fn run_assembly_test(&self) { + if self.config.llvm_filecheck.is_none() { + self.fatal("missing --llvm-filecheck"); + } + + let (proc_res, output_path) = self.compile_test_and_save_assembly(); if !proc_res.status.success() { self.fatal_proc_rec("compilation failed!", &proc_res); } - proc_res = self.check_ir_with_filecheck(); + let proc_res = self.verify_with_filecheck(&output_path); if !proc_res.status.success() { self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res); } @@ -2134,9 +2311,7 @@ impl<'test> TestCx<'test> { fn charset() -> &'static str { // FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset - if cfg!(target_os = "bitrig") { - "auto" - } else if cfg!(target_os = "freebsd") { + if cfg!(target_os = "freebsd") { "ISO-8859-1" } else { "UTF-8" @@ -2587,8 +2762,7 @@ impl<'test> TestCx<'test> { create_dir_all(&tmpdir).unwrap(); let host = &self.config.host; - let make = if host.contains("bitrig") - || host.contains("dragonfly") + let make = if host.contains("dragonfly") || host.contains("freebsd") || host.contains("netbsd") || host.contains("openbsd") @@ -2637,10 +2811,24 @@ impl<'test> TestCx<'test> { cmd.env("CLANG", clang); } + if let Some(ref filecheck) = self.config.llvm_filecheck { + cmd.env("LLVM_FILECHECK", filecheck); + } + + if let Some(ref llvm_bin_dir) = self.config.llvm_bin_dir { + cmd.env("LLVM_BIN_DIR", llvm_bin_dir); + } + // We don't want RUSTFLAGS set from the outside to interfere with // compiler flags set in the test cases: cmd.env_remove("RUSTFLAGS"); + // Use dynamic musl for tests because static doesn't allow creating dylibs + if self.config.host.contains("musl") { + cmd.env("RUSTFLAGS", "-Ctarget-feature=-crt-static") + .env("IS_MUSL_HOST", "1"); + } + if self.config.target.contains("msvc") && self.config.cc != "" { // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` // and that `lib.exe` lives next to it. @@ -2710,6 +2898,27 @@ impl<'test> TestCx<'test> { fs::remove_dir(path) } + fn run_js_doc_test(&self) { + if let Some(nodejs) = &self.config.nodejs { + let out_dir = self.output_base_dir(); + + self.document(&out_dir); + + let root = self.config.find_rust_src_root().unwrap(); + let res = self.cmd2procres( + Command::new(&nodejs) + .arg(root.join("src/tools/rustdoc-js/tester.js")) + .arg(out_dir.parent().expect("no parent")) + .arg(&self.testpaths.file.file_stem().expect("couldn't get file stem")), + ); + if !res.status.success() { + self.fatal_proc_rec("rustdoc-js test failed!", &res); + } + } else { + self.fatal("no nodeJS"); + } + } + fn run_ui_test(&self) { // if the user specified a format in the ui test // print the output to the stderr file, otherwise extract @@ -2732,7 +2941,7 @@ impl<'test> TestCx<'test> { let stderr = if explicit { proc_res.stderr.clone() } else { - json::extract_rendered(&proc_res.stderr, &proc_res) + json::extract_rendered(&proc_res.stderr) }; let normalized_stderr = self.normalize_output(&stderr, &self.props.normalize_stderr); @@ -2750,6 +2959,34 @@ impl<'test> TestCx<'test> { if self.config.compare_mode.is_some() { // don't test rustfix with nll right now + } else if self.config.rustfix_coverage { + // Find out which tests have `MachineApplicable` suggestions but are missing + // `run-rustfix` or `run-rustfix-only-machine-applicable` headers. + // + // This will return an empty `Vec` in case the executed test file has a + // `compile-flags: --error-format=xxxx` header with a value other than `json`. + let suggestions = get_suggestions_from_json( + &proc_res.stderr, + &HashSet::new(), + Filter::MachineApplicableOnly + ).unwrap_or_default(); + if suggestions.len() > 0 + && !self.props.run_rustfix + && !self.props.rustfix_only_machine_applicable { + let mut coverage_file_path = self.config.build_base.clone(); + coverage_file_path.push("rustfix_missing_coverage.txt"); + debug!("coverage_file_path: {}", coverage_file_path.display()); + + let mut file = OpenOptions::new() + .create(true) + .append(true) + .open(coverage_file_path.as_path()) + .expect("could not create or open file"); + + if let Err(_) = writeln!(file, "{}", self.testpaths.file.display()) { + panic!("couldn't write to {}", coverage_file_path.display()); + } + } } else if self.props.run_rustfix { // Apply suggestions from rustc to the code itself let unfixed_code = self @@ -2886,7 +3123,7 @@ impl<'test> TestCx<'test> { } fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) { - let t = |file| FileTime::from_last_modification_time(&fs::metadata(file).unwrap()); + let t = |file| fs::metadata(file).unwrap().modified().unwrap(); let source_file = &self.testpaths.file; let output_time = t(output_file); let source_time = t(source_file); @@ -3027,42 +3264,40 @@ impl<'test> TestCx<'test> { } fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String { - let parent_dir = self.testpaths.file.parent().unwrap(); let cflags = self.props.compile_flags.join(" "); let json = cflags.contains("--error-format json") || cflags.contains("--error-format pretty-json") || cflags.contains("--error-format=json") || cflags.contains("--error-format=pretty-json"); - let parent_dir_str = if json { - parent_dir.display().to_string().replace("\\", "\\\\") - } else { - parent_dir.display().to_string() + + let mut normalized = output.to_string(); + + let mut normalize_path = |from: &Path, to: &str| { + let mut from = from.display().to_string(); + if json { + from = from.replace("\\", "\\\\"); + } + normalized = normalized.replace(&from, to); }; - let mut normalized = output.replace(&parent_dir_str, "$DIR"); + let parent_dir = self.testpaths.file.parent().unwrap(); + normalize_path(parent_dir, "$DIR"); // Paths into the libstd/libcore let src_dir = self.config.src_base.parent().unwrap().parent().unwrap(); - let src_dir_str = if json { - src_dir.display().to_string().replace("\\", "\\\\") - } else { - src_dir.display().to_string() - }; - normalized = normalized.replace(&src_dir_str, "$SRC_DIR"); + normalize_path(src_dir, "$SRC_DIR"); // Paths into the build directory let test_build_dir = &self.config.build_base; let parent_build_dir = test_build_dir.parent().unwrap().parent().unwrap().parent().unwrap(); // eg. /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui - normalized = normalized.replace(test_build_dir.to_str().unwrap(), "$TEST_BUILD_DIR"); + normalize_path(test_build_dir, "$TEST_BUILD_DIR"); // eg. /home/user/rust/build - normalized = normalized.replace(&parent_build_dir.to_str().unwrap(), "$BUILD_DIR"); + normalize_path(parent_build_dir, "$BUILD_DIR"); // Paths into lib directory. - let mut lib_dir = parent_build_dir.parent().unwrap().to_path_buf(); - lib_dir.push("lib"); - normalized = normalized.replace(&lib_dir.to_str().unwrap(), "$LIB_DIR"); + normalize_path(&parent_build_dir.parent().unwrap().join("lib"), "$LIB_DIR"); if json { // escaped newlines in json strings should be readable @@ -3079,10 +3314,14 @@ impl<'test> TestCx<'test> { normalized = Regex::new("SRC_DIR(.+):\\d+:\\d+").unwrap() .replace_all(&normalized, "SRC_DIR$1:LL:COL").into_owned(); - normalized = normalized.replace("\\\\", "\\") // denormalize for paths on windows - .replace("\\", "/") // normalize for paths on windows - .replace("\r\n", "\n") // normalize for linebreaks on windows - .replace("\t", "\\t"); // makes tabs visible + normalized = Self::normalize_platform_differences(&normalized); + normalized = normalized.replace("\t", "\\t"); // makes tabs visible + + // Remove test annotations like `//~ ERROR text` from the output, + // since they duplicate actual errors and make the output hard to read. + normalized = Regex::new("\\s*//(\\[.*\\])?~.*").unwrap() + .replace_all(&normalized, "").into_owned(); + for rule in custom_rules { let re = Regex::new(&rule.0).expect("bad regex in custom normalization rule"); normalized = re.replace_all(&normalized, &rule.1[..]).into_owned(); @@ -3090,6 +3329,36 @@ impl<'test> TestCx<'test> { normalized } + /// Normalize output differences across platforms. Generally changes Windows output to be more + /// Unix-like. + /// + /// Replaces backslashes in paths with forward slashes, and replaces CRLF line endings + /// with LF. + fn normalize_platform_differences(output: &str) -> String { + lazy_static! { + /// Used to find Windows paths. + /// + /// It's not possible to detect paths in the error messages generally, but this is a + /// decent enough heuristic. + static ref PATH_BACKSLASH_RE: Regex = Regex::new(r#"(?x) + (?: + # Match paths that don't include spaces. + (?:\\[\pL\pN\.\-_']+)+\.\pL+ + | + # If the path starts with a well-known root, then allow spaces. + \$(?:DIR|SRC_DIR|TEST_BUILD_DIR|BUILD_DIR|LIB_DIR)(?:\\[\pL\pN\.\-_' ]+)+ + )"# + ).unwrap(); + } + + let output = output.replace(r"\\", r"\"); + + PATH_BACKSLASH_RE.replace_all(&output, |caps: &Captures<'_>| { + println!("{}", &caps[0]); + caps[0].replace(r"\", "/") + }).replace("\r\n", "\n") + } + fn expected_output_path(&self, kind: &str) -> PathBuf { let mut path = expected_output_path( &self.testpaths, @@ -3290,9 +3559,13 @@ impl ProcRes { {}\n\ ------------------------------------------\n\ \n", - self.status, self.cmdline, self.stdout, self.stderr + self.status, self.cmdline, + json::extract_rendered(&self.stdout), + json::extract_rendered(&self.stderr), ); - panic!(); + // Use resume_unwind instead of panic!() to prevent a panic message + backtrace from + // compiletest, which is unnecessary noise. + std::panic::resume_unwind(Box::new(())); } } @@ -3421,3 +3694,68 @@ fn read2_abbreviated(mut child: Child) -> io::Result { stderr: stderr.into_bytes(), }) } + +#[cfg(test)] +mod tests { + use super::TestCx; + + #[test] + fn normalize_platform_differences() { + assert_eq!( + TestCx::normalize_platform_differences(r"$DIR\foo.rs"), + "$DIR/foo.rs" + ); + assert_eq!( + TestCx::normalize_platform_differences(r"$BUILD_DIR\..\parser.rs"), + "$BUILD_DIR/../parser.rs" + ); + assert_eq!( + TestCx::normalize_platform_differences(r"$DIR\bar.rs hello\nworld"), + r"$DIR/bar.rs hello\nworld" + ); + assert_eq!( + TestCx::normalize_platform_differences(r"either bar\baz.rs or bar\baz\mod.rs"), + r"either bar/baz.rs or bar/baz/mod.rs", + ); + assert_eq!( + TestCx::normalize_platform_differences(r"`.\some\path.rs`"), + r"`./some/path.rs`", + ); + assert_eq!( + TestCx::normalize_platform_differences(r"`some\path.rs`"), + r"`some/path.rs`", + ); + assert_eq!( + TestCx::normalize_platform_differences(r"$DIR\path-with-dashes.rs"), + r"$DIR/path-with-dashes.rs" + ); + assert_eq!( + TestCx::normalize_platform_differences(r"$DIR\path_with_underscores.rs"), + r"$DIR/path_with_underscores.rs", + ); + assert_eq!( + TestCx::normalize_platform_differences(r"$DIR\foo.rs:12:11"), "$DIR/foo.rs:12:11", + ); + assert_eq!( + TestCx::normalize_platform_differences(r"$DIR\path with spaces 'n' quotes"), + "$DIR/path with spaces 'n' quotes", + ); + assert_eq!( + TestCx::normalize_platform_differences(r"$DIR\file_with\no_extension"), + "$DIR/file_with/no_extension", + ); + + assert_eq!(TestCx::normalize_platform_differences(r"\n"), r"\n"); + assert_eq!(TestCx::normalize_platform_differences(r"{ \n"), r"{ \n"); + assert_eq!(TestCx::normalize_platform_differences(r"`\]`"), r"`\]`"); + assert_eq!(TestCx::normalize_platform_differences(r#""\{""#), r#""\{""#); + assert_eq!( + TestCx::normalize_platform_differences(r#"write!(&mut v, "Hello\n")"#), + r#"write!(&mut v, "Hello\n")"# + ); + assert_eq!( + TestCx::normalize_platform_differences(r#"println!("test\ntest")"#), + r#"println!("test\ntest")"#, + ); + } +} diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 240287fa248bd..8caf5ca00f505 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -3,11 +3,12 @@ use std::env; use std::path::PathBuf; use crate::common::Config; +use log::*; + /// Conversion table from triple OS name to Rust SYSNAME const OS_TABLE: &'static [(&'static str, &'static str)] = &[ ("android", "android"), ("androideabi", "android"), - ("bitrig", "bitrig"), ("cloudabi", "cloudabi"), ("cuda", "cuda"), ("darwin", "macos"), @@ -41,7 +42,6 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[ ("armv7", "arm"), ("armv7s", "arm"), ("asmjs", "asmjs"), - ("cuda", "cuda"), ("hexagon", "hexagon"), ("i386", "x86"), ("i586", "x86"), @@ -49,8 +49,17 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[ ("mips", "mips"), ("mips64", "mips64"), ("mips64el", "mips64"), + ("mipsisa32r6", "mips"), + ("mipsisa32r6el", "mips"), + ("mipsisa64r6", "mips64"), + ("mipsisa64r6el", "mips64"), ("mipsel", "mips"), + ("mipsisa32r6", "mips"), + ("mipsisa32r6el", "mips"), + ("mipsisa64r6", "mips64"), + ("mipsisa64r6el", "mips64"), ("msp430", "msp430"), + ("nvptx64", "nvptx64"), ("powerpc", "powerpc"), ("powerpc64", "powerpc64"), ("powerpc64le", "powerpc64"), @@ -158,7 +167,7 @@ fn test_get_arch_failure() { fn test_get_arch() { assert_eq!("x86_64", get_arch("x86_64-unknown-linux-gnu")); assert_eq!("x86_64", get_arch("amd64")); - assert_eq!("cuda", get_arch("nvptx64-nvidia-cuda")); + assert_eq!("nvptx64", get_arch("nvptx64-nvidia-cuda")); } #[test] diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index faeeea605a2b4..3e7c7ab6379d8 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -15,6 +15,7 @@ use std::path::Path; use std::path::PathBuf; use std::cell::RefCell; +use syntax::edition::DEFAULT_EDITION; use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; use rustdoc::html::markdown::{Markdown, IdMap, ErrorCodes, PLAYGROUND}; @@ -27,9 +28,10 @@ enum OutputFormat { } impl OutputFormat { - fn from(format: &str) -> OutputFormat { + fn from(format: &str, resource_suffix: &str) -> OutputFormat { match &*format.to_lowercase() { - "html" => OutputFormat::HTML(HTMLFormatter(RefCell::new(IdMap::new()))), + "html" => OutputFormat::HTML(HTMLFormatter(RefCell::new(IdMap::new()), + resource_suffix.to_owned())), "markdown" => OutputFormat::Markdown(MarkdownFormatter), s => OutputFormat::Unknown(s.to_owned()), } @@ -44,7 +46,7 @@ trait Formatter { fn footer(&self, output: &mut dyn Write) -> Result<(), Box>; } -struct HTMLFormatter(RefCell); +struct HTMLFormatter(RefCell, String); struct MarkdownFormatter; impl Formatter for HTMLFormatter { @@ -55,7 +57,7 @@ impl Formatter for HTMLFormatter { Rust Compiler Error Index - + -"##)?; +"##, suffix=self.1)?; Ok(()) } @@ -96,7 +98,8 @@ impl Formatter for HTMLFormatter { Some(ref desc) => { let mut id_map = self.0.borrow_mut(); write!(output, "{}", - Markdown(desc, &[], RefCell::new(&mut id_map), ErrorCodes::Yes))? + Markdown(desc, &[], RefCell::new(&mut id_map), + ErrorCodes::Yes, DEFAULT_EDITION))? }, None => write!(output, "

    No description.

    \n")?, } @@ -242,9 +245,12 @@ fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box (OutputFormat, PathBuf) { let mut args = env::args().skip(1); - let format = args.next().map(|a| OutputFormat::from(&a)) - .unwrap_or(OutputFormat::from("html")); - let dst = args.next().map(PathBuf::from).unwrap_or_else(|| { + let format = args.next(); + let dst = args.next(); + let resource_suffix = args.next().unwrap_or_else(String::new); + let format = format.map(|a| OutputFormat::from(&a, &resource_suffix)) + .unwrap_or(OutputFormat::from("html", &resource_suffix)); + let dst = dst.map(PathBuf::from).unwrap_or_else(|| { match format { OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"), OutputFormat::Markdown(..) => PathBuf::from("doc/error-index.md"), @@ -260,7 +266,7 @@ fn main() { *slot.borrow_mut() = Some((None, String::from("https://play.rust-lang.org/"))); }); let (format, dst) = parse_args(); - let result = syntax::with_globals(move || { + let result = syntax::with_default_globals(move || { main_with_result(format, &dst) }); if let Err(e) = result { diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 9a6c97dbca015..e2bcd4d40af7f 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -135,8 +135,8 @@ fn check(cache: &mut Cache, file.ends_with("ty/struct.Slice.html") || file.ends_with("ty/enum.Attributes.html") || file.ends_with("ty/struct.SymbolName.html") || - file.ends_with("io/struct.IoVec.html") || - file.ends_with("io/struct.IoVecMut.html") { + file.ends_with("io/struct.IoSlice.html") || + file.ends_with("io/struct.IoSliceMut.html") { return None; } // FIXME(#32553) diff --git a/src/tools/miri b/src/tools/miri index 724be298a1e12..d2df509867fbb 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 724be298a1e12593dbc3786cafc307627e46e802 +Subproject commit d2df509867fbbbd35730c90aef54a8e73b046cd6 diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index fb6132a5358ef..d5dff1dcae0d5 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -3,6 +3,7 @@ import sys import re +import os import json import datetime import collections @@ -12,16 +13,21 @@ except ImportError: import urllib.request as urllib2 -# List of people to ping when the status of a tool changed. +# List of people to ping when the status of a tool or a book changed. MAINTAINERS = { 'miri': '@oli-obk @RalfJung @eddyb', 'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk @phansch', - 'rls': '@nrc @Xanewok', - 'rustfmt': '@nrc @topecongiro', + 'rls': '@Xanewok', + 'rustfmt': '@topecongiro', 'book': '@carols10cents @steveklabnik', 'nomicon': '@frewsxcv @Gankro', - 'reference': '@steveklabnik @Havvy @matthewjasper @alercah', + 'reference': '@steveklabnik @Havvy @matthewjasper @ehuss', 'rust-by-example': '@steveklabnik @marioidival @projektir', + 'embedded-book': ( + '@adamgreig @andre-richter @jamesmunns @korken89 ' + '@ryankurte @thejpster @therealprof' + ), + 'edition-guide': '@ehuss @Centril @steveklabnik', } REPOS = { @@ -33,6 +39,8 @@ 'nomicon': 'https://github.com/rust-lang-nursery/nomicon', 'reference': 'https://github.com/rust-lang-nursery/reference', 'rust-by-example': 'https://github.com/rust-lang/rust-by-example', + 'embedded-book': 'https://github.com/rust-embedded/book', + 'edition-guide': 'https://github.com/rust-lang-nursery/edition-guide', } @@ -46,35 +54,51 @@ def read_current_status(current_commit, path): return json.loads(status) return {} +def gh_url(): + return os.environ['TOOLSTATE_ISSUES_API_URL'] + +def maybe_delink(message): + if os.environ.get('TOOLSTATE_SKIP_MENTIONS') is not None: + return message.replace("@", "") + return message + def issue( tool, + status, maintainers, relevant_pr_number, relevant_pr_user, pr_reviewer, ): # Open an issue about the toolstate failure. - gh_url = 'https://api.github.com/repos/rust-lang/rust/issues' assignees = [x.strip() for x in maintainers.split('@') if x != ''] - assignees.append(relevant_pr_user) + if status == 'test-fail': + status_description = 'has failing tests' + else: + status_description = 'no longer builds' + request = json.dumps({ + 'body': maybe_delink(textwrap.dedent('''\ + Hello, this is your friendly neighborhood mergebot. + After merging PR {}, I observed that the tool {} {}. + A follow-up PR to the repository {} is needed to fix the fallout. + + cc @{}, do you think you would have time to do the follow-up work? + If so, that would be great! + + cc @{}, the PR reviewer, and @rust-lang/compiler -- nominating for prioritization. + + ''').format( + relevant_pr_number, tool, status_description, + REPOS.get(tool), relevant_pr_user, pr_reviewer + )), + 'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number), + 'assignees': assignees, + 'labels': ['T-compiler', 'I-nominated'], + }) + print("Creating issue:\n{}".format(request)) response = urllib2.urlopen(urllib2.Request( - gh_url, - json.dumps({ - 'body': textwrap.dedent('''\ - Hello, this is your friendly neighborhood mergebot. - After merging PR {}, I observed that the tool {} no longer builds. - A follow-up PR to the repository {} is needed to fix the fallout. - - cc @{}, do you think you would have time to do the follow-up work? - If so, that would be great! - - cc @{}, the PR reviewer, and @rust-lang/compiler -- nominating for prioritization. - - ''').format(relevant_pr_number, tool, REPOS[tool], relevant_pr_user, pr_reviewer), - 'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number), - 'assignees': assignees, - 'labels': ['T-compiler', 'I-nominated'], - }), + gh_url(), + request, { 'Authorization': 'token ' + github_token, 'Content-Type': 'application/json', @@ -112,13 +136,13 @@ def update_latest( for status in latest: tool = status['tool'] changed = False - build_failed = False + create_issue_for_status = None # set to the status that caused the issue for os, s in current_status.items(): old = status[os] new = s.get(tool, old) status[os] = new - if new > old: + if new > old: # comparing the strings, but they are ordered appropriately! # things got fixed or at least the status quo improved changed = True message += '🎉 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \ @@ -130,22 +154,27 @@ def update_latest( .format(tool, os, old, new) message += '{} (cc {}, @rust-lang/infra).\n' \ .format(title, MAINTAINERS.get(tool)) - # only create issues for build failures. Other failures can be spurious - if new == 'build-fail': - build_failed = True + # Most tools only create issues for build failures. + # Other failures can be spurious. + if new == 'build-fail' or (tool == 'miri' and new == 'test-fail'): + create_issue_for_status = new - if build_failed: + if create_issue_for_status is not None: try: issue( - tool, MAINTAINERS.get(tool), + tool, create_issue_for_status, MAINTAINERS.get(tool, ''), relevant_pr_number, relevant_pr_user, pr_reviewer, ) - except IOError as e: + except urllib2.HTTPError as e: # network errors will simply end up not creating an issue, but that's better # than failing the entire build job - print("I/O error: {0}".format(e)) + print("HTTPError when creating issue for status regression: {0}\n{1}" + .format(e, e.read())) + except IOError as e: + print("I/O error when creating issue for status regression: {0}".format(e)) except: - print("Unexpected error: {0}".format(sys.exc_info()[0])) + print("Unexpected error when creating issue for status regression: {0}" + .format(sys.exc_info()[0])) raise if changed: @@ -209,11 +238,10 @@ def update_latest( f.write(message) # Write the toolstate comment on the PR as well. - gh_url = 'https://api.github.com/repos/rust-lang/rust/issues/{}/comments' \ - .format(number) + issue_url = gh_url() + '/{}/comments'.format(number) response = urllib2.urlopen(urllib2.Request( - gh_url, - json.dumps({'body': message}), + issue_url, + json.dumps({'body': maybe_delink(message)}), { 'Authorization': 'token ' + github_token, 'Content-Type': 'application/json', diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index cb9dac27ce491..f42de44176787 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -1,3 +1,5 @@ +#![deny(rust_2018_idioms)] + /// This is a small client program intended to pair with `remote-test-server` in /// this repository. This client connects to the server over TCP and is used to /// push artifacts and run tests on the server instead of locally. @@ -15,7 +17,7 @@ use std::process::{Command, Stdio}; use std::thread; use std::time::Duration; -const REMOTE_ADDR_ENV: &'static str = "TEST_DEVICE_ADDR"; +const REMOTE_ADDR_ENV: &str = "TEST_DEVICE_ADDR"; macro_rules! t { ($e:expr) => (match $e { diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index 750eea3a28aef..e1270489d315f 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -1,3 +1,5 @@ +#![deny(rust_2018_idioms)] + /// This is a small server which is intended to run inside of an emulator or /// on a remote test device. This server pairs with the `remote-test-client` /// program in this repository. The `remote-test-client` connects to this @@ -120,7 +122,7 @@ struct RemoveOnDrop<'a> { inner: &'a Path, } -impl<'a> Drop for RemoveOnDrop<'a> { +impl Drop for RemoveOnDrop<'_> { fn drop(&mut self) { t!(fs::remove_dir_all(self.inner)); } diff --git a/src/tools/rls b/src/tools/rls index 0d6f53e1a4adb..124483dd2f10f 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit 0d6f53e1a4adbaf7d83cdc0cb54720203fcb522e +Subproject commit 124483dd2f10fe3ba32f7f5b75f32224c77f9010 diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 5bf1553b22711..54549e4c7e98f 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -2,15 +2,14 @@ authors = ["The Rust Project Developers"] name = "rustbook" version = "0.1.0" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" edition = "2018" [dependencies] clap = "2.25.0" -[dependencies.mdbook_2] -package = "mdbook" -version = "0.2.3" +[dependencies.mdbook] +version = "0.3.0" default-features = false features = ["search"] diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index 5a6246347cc03..04e48dde86b21 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -1,4 +1,5 @@ -// +#![deny(rust_2018_idioms)] + use clap::{crate_version}; use std::env; @@ -9,8 +10,8 @@ use clap::{App, ArgMatches, SubCommand, AppSettings}; use mdbook_1::{MDBook as MDBook1}; use mdbook_1::errors::{Result as Result1}; -use mdbook_2::{MDBook as MDBook2}; -use mdbook_2::errors::{Result as Result2}; +use mdbook::MDBook; +use mdbook::errors::Result; fn main() { let d_message = "-d, --dest-dir=[dest-dir] @@ -47,8 +48,8 @@ fn main() { ::std::process::exit(101); } } - Some("2") => { - if let Err(e) = build_2(sub_matches) { + Some("2") | Some("3") => { + if let Err(e) = build(sub_matches) { eprintln!("Error: {}", e); for cause in e.iter().skip(1) { @@ -59,7 +60,7 @@ fn main() { } } _ => { - panic!("Invalid mdBook version! Select '1' or '2'"); + panic!("Invalid mdBook version! Select '1' or '2' or '3'"); } }; }, @@ -68,7 +69,7 @@ fn main() { } // Build command implementation -pub fn build_1(args: &ArgMatches) -> Result1<()> { +pub fn build_1(args: &ArgMatches<'_>) -> Result1<()> { let book_dir = get_book_dir(args); let mut book = MDBook1::load(&book_dir)?; @@ -85,9 +86,9 @@ pub fn build_1(args: &ArgMatches) -> Result1<()> { } // Build command implementation -pub fn build_2(args: &ArgMatches) -> Result2<()> { +pub fn build(args: &ArgMatches<'_>) -> Result<()> { let book_dir = get_book_dir(args); - let mut book = MDBook2::load(&book_dir)?; + let mut book = MDBook::load(&book_dir)?; // Set this to allow us to catch bugs in advance. book.config.build.create_missing = false; @@ -101,7 +102,7 @@ pub fn build_2(args: &ArgMatches) -> Result2<()> { Ok(()) } -fn get_book_dir(args: &ArgMatches) -> PathBuf { +fn get_book_dir(args: &ArgMatches<'_>) -> PathBuf { if let Some(dir) = args.value_of("dir") { // Check if path is relative from current dir, or absolute... let p = Path::new(dir); diff --git a/src/tools/rustc-std-workspace-alloc/Cargo.toml b/src/tools/rustc-std-workspace-alloc/Cargo.toml new file mode 100644 index 0000000000000..05df1fddc7f1c --- /dev/null +++ b/src/tools/rustc-std-workspace-alloc/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rustc-std-workspace-alloc" +version = "1.0.0" +authors = ["Alex Crichton "] +license = 'MIT OR Apache-2.0' +description = """ +Hack for the compiler's own build system +""" + +[lib] +path = "lib.rs" + +[dependencies] +alloc = { path = "../../liballoc" } diff --git a/src/tools/rustc-std-workspace-alloc/lib.rs b/src/tools/rustc-std-workspace-alloc/lib.rs new file mode 100644 index 0000000000000..c38a8d2f204e4 --- /dev/null +++ b/src/tools/rustc-std-workspace-alloc/lib.rs @@ -0,0 +1,9 @@ +#![feature(no_core)] +#![no_core] + +// See rustc-std-workspace-core for why this crate is needed. + +// Rename the crate to avoid conflicting with the alloc module in liballoc. +extern crate alloc as foo; + +pub use foo::*; diff --git a/src/tools/rustc-std-workspace-core/Cargo.toml b/src/tools/rustc-std-workspace-core/Cargo.toml index d527ce12bc3a1..38ca56a557be6 100644 --- a/src/tools/rustc-std-workspace-core/Cargo.toml +++ b/src/tools/rustc-std-workspace-core/Cargo.toml @@ -2,7 +2,7 @@ name = "rustc-std-workspace-core" version = "1.0.0" authors = ["Alex Crichton "] -license = 'MIT/Apache-2.0' +license = 'MIT OR Apache-2.0' description = """ Hack for the compiler's own build system """ diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 1aba52bafbbc7..26b447d2efe7f 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -2,7 +2,7 @@ name = "rustc-workspace-hack" version = "1.0.0" authors = ["Alex Crichton "] -license = 'MIT/Apache-2.0' +license = 'MIT OR Apache-2.0' description = """ Hack for the compiler's own build system """ @@ -26,6 +26,7 @@ features = [ "basetsd", "consoleapi", "errhandlingapi", + "ioapiset", "jobapi", "jobapi2", "knownfolders", @@ -33,11 +34,14 @@ features = [ "memoryapi", "minschannel", "minwinbase", + "namedpipeapi", + "ntdef", "ntsecapi", "ntstatus", "objbase", - "profileapi", "processenv", + "processthreadsapi", + "profileapi", "psapi", "schannel", "securitybaseapi", @@ -52,17 +56,22 @@ features = [ "winbase", "wincon", "wincrypt", + "winsock2", + "ws2def", + "ws2ipdef", + "ws2tcpip", ] [dependencies] curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true } parking_lot = { version = "0.7", features = ['nightly'] } -rand = { version = "0.5.5", features = ["i128_support"] } +rand = { version = "0.6.1", features = ["i128_support"] } serde = { version = "1.0.82", features = ['derive'] } serde_json = { version = "1.0.31", features = ["raw_value"] } smallvec = { version = "0.6", features = ['union', 'may_dangle'] } -scopeguard = { version = "0.3.3", features = ["use_std", "default"]} -byteorder = { version = "1.2.7", features = ["i128"]} +scopeguard = { version = "0.3.3", features = ["use_std", "default"] } +byteorder = { version = "1.2.7", features = ["i128"] } +syn = { version = "0.15.35", features = ["extra-traits", "full"] } [target.'cfg(not(windows))'.dependencies] diff --git a/src/tools/rustdoc-js-std/tester.js b/src/tools/rustdoc-js-std/tester.js new file mode 100644 index 0000000000000..d5f0ab9f4292d --- /dev/null +++ b/src/tools/rustdoc-js-std/tester.js @@ -0,0 +1,344 @@ +const fs = require('fs'); + +const TEST_FOLDER = 'src/test/rustdoc-js-std/'; + +function getNextStep(content, pos, stop) { + while (pos < content.length && content[pos] !== stop && + (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) { + pos += 1; + } + if (pos >= content.length) { + return null; + } + if (content[pos] !== stop) { + return pos * -1; + } + return pos; +} + +// Stupid function extractor based on indent. Doesn't support block +// comments. If someone puts a ' or an " in a block comment this +// will blow up. Template strings are not tested and might also be +// broken. +function extractFunction(content, functionName) { + var indent = 0; + var splitter = "function " + functionName + "("; + + while (true) { + var start = content.indexOf(splitter); + if (start === -1) { + break; + } + var pos = start; + while (pos < content.length && content[pos] !== ')') { + pos += 1; + } + if (pos >= content.length) { + break; + } + pos = getNextStep(content, pos + 1, '{'); + if (pos === null) { + break; + } else if (pos < 0) { + content = content.slice(-pos); + continue; + } + while (pos < content.length) { + // Eat single-line comments + if (content[pos] === '/' && pos > 0 && content[pos-1] === '/') { + do { + pos += 1; + } while (pos < content.length && content[pos] !== '\n'); + + // Eat quoted strings + } else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") { + var stop = content[pos]; + var is_escaped = false; + do { + if (content[pos] === '\\') { + pos += 2; + } else { + pos += 1; + } + } while (pos < content.length && + (content[pos] !== stop || content[pos - 1] === '\\')); + + // Otherwise, check for indent + } else if (content[pos] === '{') { + indent += 1; + } else if (content[pos] === '}') { + indent -= 1; + if (indent === 0) { + return content.slice(start, pos + 1); + } + } + pos += 1; + } + content = content.slice(start + 1); + } + return null; +} + +// Stupid function extractor for array. +function extractArrayVariable(content, arrayName) { + var splitter = "var " + arrayName; + while (true) { + var start = content.indexOf(splitter); + if (start === -1) { + break; + } + var pos = getNextStep(content, start, '='); + if (pos === null) { + break; + } else if (pos < 0) { + content = content.slice(-pos); + continue; + } + pos = getNextStep(content, pos, '['); + if (pos === null) { + break; + } else if (pos < 0) { + content = content.slice(-pos); + continue; + } + while (pos < content.length) { + if (content[pos] === '"' || content[pos] === "'") { + var stop = content[pos]; + do { + if (content[pos] === '\\') { + pos += 2; + } else { + pos += 1; + } + } while (pos < content.length && + (content[pos] !== stop || content[pos - 1] === '\\')); + } else if (content[pos] === ']' && + pos + 1 < content.length && + content[pos + 1] === ';') { + return content.slice(start, pos + 2); + } + pos += 1; + } + content = content.slice(start + 1); + } + return null; +} + +// Stupid function extractor for variable. +function extractVariable(content, varName) { + var splitter = "var " + varName; + while (true) { + var start = content.indexOf(splitter); + if (start === -1) { + break; + } + var pos = getNextStep(content, start, '='); + if (pos === null) { + break; + } else if (pos < 0) { + content = content.slice(-pos); + continue; + } + while (pos < content.length) { + if (content[pos] === '"' || content[pos] === "'") { + var stop = content[pos]; + do { + if (content[pos] === '\\') { + pos += 2; + } else { + pos += 1; + } + } while (pos < content.length && + (content[pos] !== stop || content[pos - 1] === '\\')); + } else if (content[pos] === ';') { + return content.slice(start, pos + 1); + } + pos += 1; + } + content = content.slice(start + 1); + } + return null; +} + +function loadContent(content) { + var Module = module.constructor; + var m = new Module(); + m._compile(content, "tmp.js"); + m.exports.ignore_order = content.indexOf("\n// ignore-order\n") !== -1 || + content.startsWith("// ignore-order\n"); + m.exports.exact_check = content.indexOf("\n// exact-check\n") !== -1 || + content.startsWith("// exact-check\n"); + m.exports.should_fail = content.indexOf("\n// should-fail\n") !== -1 || + content.startsWith("// should-fail\n"); + return m.exports; +} + +function readFile(filePath) { + return fs.readFileSync(filePath, 'utf8'); +} + +function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) { + var content = ''; + for (var i = 0; i < thingsToLoad.length; ++i) { + var tmp = funcToCall(fileContent, thingsToLoad[i]); + if (tmp === null) { + console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"'); + process.exit(1); + } + content += tmp; + content += 'exports.' + thingsToLoad[i] + ' = ' + thingsToLoad[i] + ';'; + } + return content; +} + +function lookForEntry(entry, data) { + for (var i = 0; i < data.length; ++i) { + var allGood = true; + for (var key in entry) { + if (!entry.hasOwnProperty(key)) { + continue; + } + var value = data[i][key]; + // To make our life easier, if there is a "parent" type, we add it to the path. + if (key === 'path' && data[i]['parent'] !== undefined) { + if (value.length > 0) { + value += '::' + data[i]['parent']['name']; + } else { + value = data[i]['parent']['name']; + } + } + if (value !== entry[key]) { + allGood = false; + break; + } + } + if (allGood === true) { + return i; + } + } + return null; +} + +function findFile(dir, name, extension) { + var entries = fs.readdirSync(dir); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + var file_type = fs.statSync(dir + entry); + if (file_type.isDirectory()) { + continue; + } + if (entry.startsWith(name) && entry.endsWith(extension)) { + return entry; + } + } + return null; +} + +function readFileMatching(dir, name, extension) { + if (dir.endsWith("/") === false) { + dir += "/"; + } + var f = findFile(dir, name, extension); + if (f === null) { + return ""; + } + return readFile(dir + f); +} + +function main(argv) { + if (argv.length !== 3) { + console.error("Expected toolchain to check as argument (for example \ + 'x86_64-apple-darwin')"); + return 1; + } + var toolchain = argv[2]; + + var mainJs = readFileMatching("build/" + toolchain + "/doc/", "main", ".js"); + var ALIASES = readFileMatching("build/" + toolchain + "/doc/", "aliases", ".js"); + var searchIndex = readFileMatching("build/" + toolchain + "/doc/", + "search-index", ".js").split("\n"); + if (searchIndex[searchIndex.length - 1].length === 0) { + searchIndex.pop(); + } + searchIndex.pop(); + searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;'); + finalJS = ""; + + var arraysToLoad = ["itemTypes"]; + var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", + "GENERICS_DATA", "NAME", "INPUTS_DATA", "OUTPUT_DATA", + "TY_PRIMITIVE", "TY_KEYWORD", + "levenshtein_row2"]; + // execQuery first parameter is built in getQuery (which takes in the search input). + // execQuery last parameter is built in buildIndex. + // buildIndex requires the hashmap from search-index. + var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult", + "getQuery", "buildIndex", "execQuery", "execSearch"]; + + finalJS += 'window = { "currentCrate": "std" };\n'; + finalJS += 'var rootPath = "../";\n'; + finalJS += ALIASES; + finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs); + finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs); + finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs); + + var loaded = loadContent(finalJS); + var index = loaded.buildIndex(searchIndex.searchIndex); + + var errors = 0; + + fs.readdirSync(TEST_FOLDER).forEach(function(file) { + var loadedFile = loadContent(readFile(TEST_FOLDER + file) + + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;'); + const expected = loadedFile.EXPECTED; + const query = loadedFile.QUERY; + const filter_crate = loadedFile.FILTER_CRATE; + const ignore_order = loadedFile.ignore_order; + const exact_check = loadedFile.exact_check; + const should_fail = loadedFile.should_fail; + var results = loaded.execSearch(loaded.getQuery(query), index); + process.stdout.write('Checking "' + file + '" ... '); + var error_text = []; + for (var key in expected) { + if (!expected.hasOwnProperty(key)) { + continue; + } + if (!results.hasOwnProperty(key)) { + error_text.push('==> Unknown key "' + key + '"'); + break; + } + var entry = expected[key]; + var prev_pos = -1; + for (var i = 0; i < entry.length; ++i) { + var entry_pos = lookForEntry(entry[i], results[key]); + if (entry_pos === null) { + error_text.push("==> Result not found in '" + key + "': '" + + JSON.stringify(entry[i]) + "'"); + } else if (exact_check === true && prev_pos + 1 !== entry_pos) { + error_text.push("==> Exact check failed at position " + (prev_pos + 1) + ": " + + "expected '" + JSON.stringify(entry[i]) + "' but found '" + + JSON.stringify(results[key][i]) + "'"); + } else if (ignore_order === false && entry_pos < prev_pos) { + error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " + + " before '" + JSON.stringify(results[key][entry_pos]) + "'"); + } else { + prev_pos = entry_pos; + } + } + } + if (error_text.length === 0 && should_fail === true) { + errors += 1; + console.error("FAILED"); + console.error("==> Test was supposed to fail but all items were found..."); + } else if (error_text.length !== 0 && should_fail === false) { + errors += 1; + console.error("FAILED"); + console.error(error_text.join("\n")); + } else { + console.log("OK"); + } + }); + return errors; +} + +process.exit(main(process.argv)); diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index c41da93a98310..833ce5d137047 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -1,4 +1,5 @@ const fs = require('fs'); +const { spawnSync } = require('child_process'); const TEST_FOLDER = 'src/test/rustdoc-js/'; @@ -219,16 +220,10 @@ function lookForEntry(entry, data) { return null; } -function main(argv) { - if (argv.length !== 3) { - console.error("Expected toolchain to check as argument (for example 'x86_64-apple-darwin'"); - return 1; - } - var toolchain = argv[2]; - - var mainJs = readFile("build/" + toolchain + "/doc/main.js"); - var ALIASES = readFile("build/" + toolchain + "/doc/aliases.js"); - var searchIndex = readFile("build/" + toolchain + "/doc/search-index.js").split("\n"); +function load_files(out_folder, crate) { + var mainJs = readFile(out_folder + "/main.js"); + var ALIASES = readFile(out_folder + "/aliases.js"); + var searchIndex = readFile(out_folder + "/search-index.js").split("\n"); if (searchIndex[searchIndex.length - 1].length === 0) { searchIndex.pop(); } @@ -247,7 +242,7 @@ function main(argv) { var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult", "getQuery", "buildIndex", "execQuery", "execSearch"]; - finalJS += 'window = { "currentCrate": "std" };\n'; + finalJS += 'window = { "currentCrate": "' + crate + '" };\n'; finalJS += 'var rootPath = "../";\n'; finalJS += ALIASES; finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs); @@ -255,12 +250,36 @@ function main(argv) { finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs); var loaded = loadContent(finalJS); - var index = loaded.buildIndex(searchIndex.searchIndex); + return [loaded, loaded.buildIndex(searchIndex.searchIndex)]; +} + +function main(argv) { + if (argv.length < 4) { + console.error("USAGE: node tester.js OUT_FOLDER [TESTS]"); + return 1; + } + if (argv[2].substr(-1) !== "/") { + argv[2] += "/"; + } + const out_folder = argv[2]; var errors = 0; - fs.readdirSync(TEST_FOLDER).forEach(function(file) { - var loadedFile = loadContent(readFile(TEST_FOLDER + file) + + for (var j = 3; j < argv.length; ++j) { + const test_name = argv[j]; + + process.stdout.write('Checking "' + test_name + '" ... '); + if (!fs.existsSync(TEST_FOLDER + test_name + ".js")) { + errors += 1; + console.error("FAILED"); + console.error("==> Missing '" + test_name + ".js' file..."); + continue; + } + + const test_out_folder = out_folder + test_name; + + var [loaded, index] = load_files(test_out_folder, test_name); + var loadedFile = loadContent(readFile(TEST_FOLDER + test_name + ".js") + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;'); const expected = loadedFile.EXPECTED; const query = loadedFile.QUERY; @@ -269,7 +288,6 @@ function main(argv) { const exact_check = loadedFile.exact_check; const should_fail = loadedFile.should_fail; var results = loaded.execSearch(loaded.getQuery(query), index); - process.stdout.write('Checking "' + file + '" ... '); var error_text = []; for (var key in expected) { if (!expected.hasOwnProperty(key)) { @@ -309,7 +327,7 @@ function main(argv) { } else { console.log("OK"); } - }); + } return errors; } diff --git a/src/tools/rustdoc/main.rs b/src/tools/rustdoc/main.rs index 8bdc365c4ca68..8171708e99d00 100644 --- a/src/tools/rustdoc/main.rs +++ b/src/tools/rustdoc/main.rs @@ -1,15 +1,3 @@ #![deny(rust_2018_idioms)] -#![feature(link_args)] - -#[allow(unused_attributes)] -// Set the stack size at link time on Windows. See rustc_driver::in_rustc_thread -// for the rationale. -#[cfg_attr(all(windows, target_env = "msvc"), link_args = "/STACK:16777216")] -// We only build for msvc and gnu now, but we use a exhaustive condition here -// so we can expect either the stack size to be set or the build fails. -#[cfg_attr(all(windows, not(target_env = "msvc")), link_args = "-Wl,--stack,16777216")] -// See src/rustc/rustc.rs for the corresponding rustc settings. -extern {} - fn main() { rustdoc::main() } diff --git a/src/tools/rustfmt b/src/tools/rustfmt index d6829d62dca64..d33450247b17d 160000 --- a/src/tools/rustfmt +++ b/src/tools/rustfmt @@ -1 +1 @@ -Subproject commit d6829d62dca64dfe7ceaa96d1a9c1cd36428221d +Subproject commit d33450247b17d92a951d9663822c5a3635a37dde diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index f7b491823f838..43cae31f33f1f 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -2,8 +2,11 @@ name = "tidy" version = "0.1.0" authors = ["Alex Crichton "] +edition = "2018" [dependencies] -serde = "1.0.8" -serde_derive = "1.0.8" +regex = "1" +serde = { version = "1.0.8", features = ["derive"] } serde_json = "1.0.2" +lazy_static = "1" +walkdir = "2" diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 610d1d8af3b5e..680585a6e04a7 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -25,16 +25,17 @@ pub fn check(path: &Path, bad: &mut bool) { } } - super::walk(path, + super::walk_no_read(path, &mut |path| super::filter_dirs(path) || path.ends_with("src/etc"), - &mut |file| { + &mut |entry| { + let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); let extensions = [".py", ".sh"]; if extensions.iter().any(|e| filename.ends_with(e)) { return; } - let metadata = t!(fs::symlink_metadata(&file), &file); + let metadata = t!(entry.metadata(), file); if metadata.mode() & 0o111 != 0 { let rel_path = file.strip_prefix(path).unwrap(); let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/"); diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 94dd5478e5297..6169ffc429797 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -5,6 +5,7 @@ use std::fs; use std::path::Path; use std::process::Command; +use serde::Deserialize; use serde_json; const LICENSES: &[&str] = &[ @@ -32,6 +33,8 @@ const EXCEPTIONS: &[&str] = &[ "is-match", // MPL-2.0, mdbook "cssparser", // MPL-2.0, rustdoc "smallvec", // MPL-2.0, rustdoc + "rdrand", // ISC, mdbook, rustfmt + "fuchsia-cprng", // BSD-3-Clause, mdbook, rustfmt "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo "fuchsia-zircon", // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir) "cssparser-macros", // MPL-2.0, rustdoc @@ -46,20 +49,26 @@ const EXCEPTIONS: &[&str] = &[ "adler32", // BSD-3-Clause AND Zlib, cargo dep that isn't used "fortanix-sgx-abi", // MPL-2.0+, libstd but only for `sgx` target "constant_time_eq", // CC0-1.0, rustfmt + "utf8parse", // Apache-2.0 OR MIT, cargo via strip-ansi-escapes + "vte", // Apache-2.0 OR MIT, cargo via strip-ansi-escapes + "sized-chunks", // MPL-2.0+, cargo via im-rc ]; /// Which crates to check against the whitelist? -const WHITELIST_CRATES: &[CrateVersion] = &[ +const WHITELIST_CRATES: &[CrateVersion<'_>] = &[ CrateVersion("rustc", "0.0.0"), CrateVersion("rustc_codegen_llvm", "0.0.0"), ]; /// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible. -const WHITELIST: &[Crate] = &[ +const WHITELIST: &[Crate<'_>] = &[ Crate("adler32"), Crate("aho-corasick"), + Crate("annotate-snippets"), + Crate("ansi_term"), Crate("arrayvec"), Crate("atty"), + Crate("autocfg"), Crate("backtrace"), Crate("backtrace-sys"), Crate("bitflags"), @@ -87,6 +96,8 @@ const WHITELIST: &[Crate] = &[ Crate("fuchsia-zircon-sys"), Crate("getopts"), Crate("humantime"), + Crate("indexmap"), + Crate("itertools"), Crate("jobserver"), Crate("kernel32-sys"), Crate("lazy_static"), @@ -95,6 +106,7 @@ const WHITELIST: &[Crate] = &[ Crate("lock_api"), Crate("log"), Crate("log_settings"), + Crate("measureme"), Crate("memchr"), Crate("memmap"), Crate("memoffset"), @@ -137,6 +149,7 @@ const WHITELIST: &[Crate] = &[ Crate("smallvec"), Crate("stable_deref_trait"), Crate("syn"), + Crate("synstructure"), Crate("tempfile"), Crate("termcolor"), Crate("terminon"), @@ -183,7 +196,7 @@ struct Crate<'a>(&'a str); // (name) #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)] struct CrateVersion<'a>(&'a str, &'a str); // (name, version) -impl<'a> Crate<'a> { +impl Crate<'_> { pub fn id_str(&self) -> String { format!("{} ", self.0) } @@ -237,7 +250,7 @@ pub fn check(path: &Path, bad: &mut bool) { } let toml = dir.path().join("Cargo.toml"); - *bad = *bad || !check_license(&toml); + *bad = !check_license(&toml) || *bad; } assert!(saw_dir, "no vendored source"); } @@ -330,10 +343,10 @@ fn get_deps(path: &Path, cargo: &Path) -> Resolve { /// Checks the dependencies of the given crate from the given cargo metadata to see if they are on /// the whitelist. Returns a list of illegal dependencies. -fn check_crate_whitelist<'a, 'b>( - whitelist: &'a HashSet, +fn check_crate_whitelist<'a>( + whitelist: &'a HashSet>, resolve: &'a Resolve, - visited: &'b mut BTreeSet>, + visited: &mut BTreeSet>, krate: CrateVersion<'a>, must_be_on_whitelist: bool, ) -> BTreeSet> { @@ -378,7 +391,7 @@ fn check_crate_duplicate(resolve: &Resolve, bad: &mut bool) { // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times // under control. - // "cargo", // FIXME(#53005) + "cargo", "rustc-ap-syntax", ]; let mut name_to_id: HashMap<_, Vec<_>> = HashMap::new(); diff --git a/src/tools/tidy/src/errors.rs b/src/tools/tidy/src/errors.rs index 76ebc9b601099..1bc27745376cc 100644 --- a/src/tools/tidy/src/errors.rs +++ b/src/tools/tidy/src/errors.rs @@ -4,24 +4,19 @@ //! statistics about the error codes. use std::collections::HashMap; -use std::fs::File; -use std::io::prelude::*; use std::path::Path; pub fn check(path: &Path, bad: &mut bool) { - let mut contents = String::new(); let mut map: HashMap<_, Vec<_>> = HashMap::new(); super::walk(path, &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), - &mut |file| { + &mut |entry, contents| { + let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); - if filename != "diagnostics.rs" && filename != "diagnostic_list.rs" { + if filename != "error_codes.rs" { return } - contents.truncate(0); - t!(t!(File::open(file)).read_to_string(&mut contents)); - // In the `register_long_diagnostics!` macro, entries look like this: // // ``` diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 7126c0c2f6ecf..1841beb1fd116 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -7,13 +7,21 @@ //! * Library features have at most one stability level. //! * Library features have at most one `since` value. //! * All unstable lang features have tests to ensure they are actually unstable. +//! * Language features in a group are sorted by `since` value. use std::collections::HashMap; use std::fmt; -use std::fs::{self, File}; -use std::io::prelude::*; +use std::fs; use std::path::Path; +use regex::Regex; + +mod version; +use version::Version; + +const FEATURE_GROUP_START_PREFIX: &str = "// feature-group-start"; +const FEATURE_GROUP_END_PREFIX: &str = "// feature-group-end"; + #[derive(Debug, PartialEq, Clone)] pub enum Status { Stable, @@ -22,7 +30,7 @@ pub enum Status { } impl fmt::Display for Status { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let as_str = match *self { Status::Stable => "stable", Status::Unstable => "unstable", @@ -35,27 +43,55 @@ impl fmt::Display for Status { #[derive(Debug, Clone)] pub struct Feature { pub level: Status, - pub since: String, + pub since: Option, pub has_gate_test: bool, pub tracking_issue: Option, } pub type Features = HashMap; -pub fn check(path: &Path, bad: &mut bool, quiet: bool) { +pub struct CollectedFeatures { + pub lib: Features, + pub lang: Features, +} + +// Currently only used for unstable book generation +pub fn collect_lib_features(base_src_path: &Path) -> Features { + let mut lib_features = Features::new(); + + // This library feature is defined in the `compiler_builtins` crate, which + // has been moved out-of-tree. Now it can no longer be auto-discovered by + // `tidy`, because we need to filter out its (submodule) directory. Manually + // add it to the set of known library features so we can still generate docs. + lib_features.insert("compiler_builtins_lib".to_owned(), Feature { + level: Status::Unstable, + since: None, + has_gate_test: false, + tracking_issue: None, + }); + + map_lib_features(base_src_path, + &mut |res, _, _| { + if let Ok((name, feature)) = res { + lib_features.insert(name.to_owned(), feature); + } + }); + lib_features +} + +pub fn check(path: &Path, bad: &mut bool, verbose: bool) -> CollectedFeatures { let mut features = collect_lang_features(path, bad); assert!(!features.is_empty()); let lib_features = get_and_check_lib_features(path, bad, &features); assert!(!lib_features.is_empty()); - let mut contents = String::new(); - super::walk_many(&[&path.join("test/ui"), &path.join("test/ui-fulldeps"), &path.join("test/compile-fail")], &mut |path| super::filter_dirs(path), - &mut |file| { + &mut |entry, contents| { + let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); if !filename.ends_with(".rs") || filename == "features.rs" || filename == "diagnostic_list.rs" { @@ -65,9 +101,6 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) { let filen_underscore = filename.replace('-',"_").replace(".rs",""); let filename_is_gate_test = test_filen_gate(&filen_underscore, &mut features); - contents.truncate(0); - t!(t!(File::open(&file), &file).read_to_string(&mut contents)); - for (i, line) in contents.lines().enumerate() { let mut err = |msg: &str| { tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg); @@ -121,46 +154,69 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) { } if *bad { - return; + return CollectedFeatures { lib: lib_features, lang: features }; } - if quiet { + + if verbose { + let mut lines = Vec::new(); + lines.extend(format_features(&features, "lang")); + lines.extend(format_features(&lib_features, "lib")); + + lines.sort(); + for line in lines { + println!("* {}", line); + } + } else { println!("* {} features", features.len()); - return; } - let mut lines = Vec::new(); - for (name, feature) in features.iter() { - lines.push(format!("{:<32} {:<8} {:<12} {:<8}", - name, - "lang", - feature.level, - feature.since)); - } - for (name, feature) in lib_features { - lines.push(format!("{:<32} {:<8} {:<12} {:<8}", - name, - "lib", - feature.level, - feature.since)); - } + CollectedFeatures { lib: lib_features, lang: features } +} - lines.sort(); - for line in lines { - println!("* {}", line); - } +fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator + 'a { + features.iter().map(move |(name, feature)| { + format!("{:<32} {:<8} {:<12} {:<8}", + name, + family, + feature.level, + feature.since.map_or("None".to_owned(), + |since| since.to_string())) + }) } fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> { - line.find(attr) - .and_then(|i| line[i..].find('"').map(|j| i + j + 1)) - .and_then(|i| line[i..].find('"').map(|j| (i, i + j))) - .map(|(i, j)| &line[i..j]) + lazy_static::lazy_static! { + static ref ISSUE: Regex = Regex::new(r#"issue\s*=\s*"([^"]*)""#).unwrap(); + static ref FEATURE: Regex = Regex::new(r#"feature\s*=\s*"([^"]*)""#).unwrap(); + static ref SINCE: Regex = Regex::new(r#"since\s*=\s*"([^"]*)""#).unwrap(); + } + + let r = match attr { + "issue" => &*ISSUE, + "feature" => &*FEATURE, + "since" => &*SINCE, + _ => unimplemented!("{} not handled", attr), + }; + + r.captures(line) + .and_then(|c| c.get(1)) + .map(|m| m.as_str()) +} + +#[test] +fn test_find_attr_val() { + let s = r#"#[unstable(feature = "checked_duration_since", issue = "58402")]"#; + assert_eq!(find_attr_val(s, "feature"), Some("checked_duration_since")); + assert_eq!(find_attr_val(s, "issue"), Some("58402")); + assert_eq!(find_attr_val(s, "since"), None); } fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool { - if filen_underscore.starts_with("feature_gate") { + let prefix = "feature_gate_"; + if filen_underscore.starts_with(prefix) { for (n, f) in features.iter_mut() { - if filen_underscore == format!("feature_gate_{}", n) { + // Equivalent to filen_underscore == format!("feature_gate_{}", n) + if &filen_underscore[prefix.len()..] == n { f.has_gate_test = true; return true; } @@ -173,17 +229,46 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { let contents = t!(fs::read_to_string(base_src_path.join("libsyntax/feature_gate.rs"))); // We allow rustc-internal features to omit a tracking issue. - // These features must be marked with a `// rustc internal` in its own group. - let mut next_feature_is_rustc_internal = false; + // To make tidy accept omitting a tracking issue, group the list of features + // without one inside `// no-tracking-issue` and `// no-tracking-issue-end`. + let mut next_feature_omits_tracking_issue = false; + + let mut in_feature_group = false; + let mut prev_since = None; contents.lines().zip(1..) .filter_map(|(line, line_number)| { let line = line.trim(); - if line.starts_with("// rustc internal") { - next_feature_is_rustc_internal = true; + + // Within -start and -end, the tracking issue can be omitted. + match line { + "// no-tracking-issue-start" => { + next_feature_omits_tracking_issue = true; + return None; + } + "// no-tracking-issue-end" => { + next_feature_omits_tracking_issue = false; + return None; + } + _ => {} + } + + if line.starts_with(FEATURE_GROUP_START_PREFIX) { + if in_feature_group { + tidy_error!( + bad, + // ignore-tidy-linelength + "libsyntax/feature_gate.rs:{}: new feature group is started without ending the previous one", + line_number, + ); + } + + in_feature_group = true; + prev_since = None; return None; - } else if line.is_empty() { - next_feature_is_rustc_internal = false; + } else if line.starts_with(FEATURE_GROUP_END_PREFIX) { + in_feature_group = false; + prev_since = None; return None; } @@ -195,10 +280,36 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { _ => return None, }; let name = parts.next().unwrap().trim(); - let since = parts.next().unwrap().trim().trim_matches('"'); + + let since_str = parts.next().unwrap().trim().trim_matches('"'); + let since = match since_str.parse() { + Ok(since) => Some(since), + Err(err) => { + tidy_error!( + bad, + "libsyntax/feature_gate.rs:{}: failed to parse since: {} ({:?})", + line_number, + since_str, + err, + ); + None + } + }; + if in_feature_group { + if prev_since > since { + tidy_error!( + bad, + "libsyntax/feature_gate.rs:{}: feature {} is not sorted by since", + line_number, + name, + ); + } + prev_since = since; + } + let issue_str = parts.next().unwrap().trim(); let tracking_issue = if issue_str.starts_with("None") { - if level == Status::Unstable && !next_feature_is_rustc_internal { + if level == Status::Unstable && !next_feature_omits_tracking_issue { *bad = true; tidy_error!( bad, @@ -209,14 +320,13 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { } None } else { - next_feature_is_rustc_internal = false; let s = issue_str.split('(').nth(1).unwrap().split(')').nth(0).unwrap(); Some(s.parse().unwrap()) }; Some((name.to_owned(), Feature { level, - since: since.to_owned(), + since, has_gate_test: false, tracking_issue, })) @@ -224,32 +334,6 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { .collect() } -pub fn collect_lib_features(base_src_path: &Path) -> Features { - let mut lib_features = Features::new(); - - // This library feature is defined in the `compiler_builtins` crate, which - // has been moved out-of-tree. Now it can no longer be auto-discovered by - // `tidy`, because we need to filter out its (submodule) directory. Manually - // add it to the set of known library features so we can still generate docs. - lib_features.insert("compiler_builtins_lib".to_owned(), Feature { - level: Status::Unstable, - since: String::new(), - has_gate_test: false, - tracking_issue: None, - }); - - map_lib_features(base_src_path, - &mut |res, _, _| { - if let Ok((name, feature)) = res { - if lib_features.contains_key(name) { - return; - } - lib_features.insert(name.to_owned(), feature); - } - }); - lib_features -} - fn get_and_check_lib_features(base_src_path: &Path, bad: &mut bool, lang_features: &Features) -> Features { @@ -284,20 +368,25 @@ fn get_and_check_lib_features(base_src_path: &Path, fn map_lib_features(base_src_path: &Path, mf: &mut dyn FnMut(Result<(&str, Feature), &str>, &Path, usize)) { - let mut contents = String::new(); super::walk(base_src_path, &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), - &mut |file| { + &mut |entry, contents| { + let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); if !filename.ends_with(".rs") || filename == "features.rs" || filename == "diagnostic_list.rs" { return; } - contents.truncate(0); - t!(t!(File::open(&file), &file).read_to_string(&mut contents)); + // This is an early exit -- all the attributes we're concerned with must contain this: + // * rustc_const_unstable( + // * unstable( + // * stable( + if !contents.contains("stable(") { + return; + } - let mut becoming_feature: Option<(String, Feature)> = None; + let mut becoming_feature: Option<(&str, Feature)> = None; for (i, line) in contents.lines().enumerate() { macro_rules! err { ($msg:expr) => {{ @@ -330,11 +419,11 @@ fn map_lib_features(base_src_path: &Path, // `const fn` features are handled specially. let feature_name = match find_attr_val(line, "feature") { Some(name) => name, - None => err!("malformed stability attribute"), + None => err!("malformed stability attribute: missing `feature` key"), }; let feature = Feature { level: Status::Unstable, - since: "None".to_owned(), + since: None, has_gate_test: false, // FIXME(#57563): #57563 is now used as a common tracking issue, // although we would like to have specific tracking issues for each @@ -353,27 +442,30 @@ fn map_lib_features(base_src_path: &Path, }; let feature_name = match find_attr_val(line, "feature") { Some(name) => name, - None => err!("malformed stability attribute"), + None => err!("malformed stability attribute: missing `feature` key"), }; - let since = match find_attr_val(line, "since") { - Some(name) => name, + let since = match find_attr_val(line, "since").map(|x| x.parse()) { + Some(Ok(since)) => Some(since), + Some(Err(_err)) => { + err!("malformed stability attribute: can't parse `since` key"); + }, None if level == Status::Stable => { - err!("malformed stability attribute"); + err!("malformed stability attribute: missing the `since` key"); } - None => "None", + None => None, }; let tracking_issue = find_attr_val(line, "issue").map(|s| s.parse().unwrap()); let feature = Feature { level, - since: since.to_owned(), + since, has_gate_test: false, tracking_issue, }; if line.contains(']') { mf(Ok((feature_name, feature)), file, i + 1); } else { - becoming_feature = Some((feature_name.to_owned(), feature)); + becoming_feature = Some((feature_name, feature)); } } }); diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs new file mode 100644 index 0000000000000..1ce9fe127dd93 --- /dev/null +++ b/src/tools/tidy/src/features/version.rs @@ -0,0 +1,90 @@ +use std::str::FromStr; +use std::num::ParseIntError; +use std::fmt; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Version { + parts: [u32; 3], +} + +impl fmt::Display for Version { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad(&format!("{}.{}.{}", self.parts[0], self.parts[1], self.parts[2])) + } +} + +#[derive(Debug, PartialEq, Eq)] +pub enum ParseVersionError { + ParseIntError(ParseIntError), + WrongNumberOfParts, +} + +impl From for ParseVersionError { + fn from(err: ParseIntError) -> Self { + ParseVersionError::ParseIntError(err) + } +} + +impl FromStr for Version { + type Err = ParseVersionError; + + fn from_str(s: &str) -> Result { + let mut iter = s.split('.').map(|part| Ok(part.parse()?)); + + let mut part = || { + iter.next() + .unwrap_or(Err(ParseVersionError::WrongNumberOfParts)) + }; + + let parts = [part()?, part()?, part()?]; + + if let Some(_) = iter.next() { + // Ensure we don't have more than 3 parts. + return Err(ParseVersionError::WrongNumberOfParts); + } + + Ok(Self { parts }) + } +} + +#[cfg(test)] +mod test { + use super::Version; + + #[test] + fn test_try_from_invalid_version() { + assert!("".parse::().is_err()); + assert!("hello".parse::().is_err()); + assert!("1.32.hi".parse::().is_err()); + assert!("1.32..1".parse::().is_err()); + assert!("1.32".parse::().is_err()); + assert!("1.32.0.1".parse::().is_err()); + } + + #[test] + fn test_try_from_single() { + assert_eq!("1.32.0".parse(), Ok(Version { parts: [1, 32, 0] })); + assert_eq!("1.0.0".parse(), Ok(Version { parts: [1, 0, 0] })); + } + + #[test] + fn test_compare() { + let v_1_0_0 = "1.0.0".parse::().unwrap(); + let v_1_32_0 = "1.32.0".parse::().unwrap(); + let v_1_32_1 = "1.32.1".parse::().unwrap(); + assert!(v_1_0_0 < v_1_32_1); + assert!(v_1_0_0 < v_1_32_0); + assert!(v_1_32_0 < v_1_32_1); + } + + #[test] + fn test_to_string() { + let v_1_0_0 = "1.0.0".parse::().unwrap(); + let v_1_32_1 = "1.32.1".parse::().unwrap(); + + assert_eq!(v_1_0_0.to_string(), "1.0.0"); + assert_eq!(v_1_32_1.to_string(), "1.32.1"); + assert_eq!(format!("{:<8}", v_1_32_1), "1.32.1 "); + assert_eq!(format!("{:>8}", v_1_32_1), " 1.32.1"); + } +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 022c53f909c75..a0bf0b0735418 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -3,12 +3,9 @@ //! This library contains the tidy lints and exposes it //! to be used by tools. -extern crate serde; -extern crate serde_json; -#[macro_use] -extern crate serde_derive; - -use std::fs; +use walkdir::{DirEntry, WalkDir}; +use std::fs::File; +use std::io::Read; use std::path::Path; @@ -70,25 +67,35 @@ fn filter_dirs(path: &Path) -> bool { skip.iter().any(|p| path.ends_with(p)) } -fn walk_many(paths: &[&Path], skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&Path)) { + +fn walk_many( + paths: &[&Path], skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str) +) { for path in paths { walk(path, skip, f); } } -fn walk(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&Path)) { - if let Ok(dir) = fs::read_dir(path) { - for entry in dir { - let entry = t!(entry); - let kind = t!(entry.file_type()); - let path = entry.path(); - if kind.is_dir() { - if !skip(&path) { - walk(&path, skip, f); - } - } else { - f(&path); +fn walk(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str)) { + let mut contents = String::new(); + walk_no_read(path, skip, &mut |entry| { + contents.clear(); + if t!(File::open(entry.path()), entry.path()).read_to_string(&mut contents).is_err() { + contents.clear(); + } + f(&entry, &contents); + }); +} + +fn walk_no_read(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry)) { + let walker = WalkDir::new(path).into_iter() + .filter_entry(|e| !skip(e.path())); + for entry in walker { + if let Ok(entry) = entry { + if entry.file_type().is_dir() { + continue; } + f(&entry); } } } diff --git a/src/tools/tidy/src/libcoretest.rs b/src/tools/tidy/src/libcoretest.rs index b15b9c3462f79..ea92f989ada7d 100644 --- a/src/tools/tidy/src/libcoretest.rs +++ b/src/tools/tidy/src/libcoretest.rs @@ -4,29 +4,22 @@ //! item. All tests must be written externally in `libcore/tests`. use std::path::Path; -use std::fs::read_to_string; pub fn check(path: &Path, bad: &mut bool) { let libcore_path = path.join("libcore"); super::walk( &libcore_path, &mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"), - &mut |subpath| { + &mut |entry, contents| { + let subpath = entry.path(); if let Some("rs") = subpath.extension().and_then(|e| e.to_str()) { - match read_to_string(subpath) { - Ok(contents) => { - if contents.contains("#[test]") { - tidy_error!( - bad, - "{} contains #[test]; libcore tests must be placed inside \ - `src/libcore/tests/`", - subpath.display() - ); - } - } - Err(err) => { - panic!("failed to read file {:?}: {}", subpath, err); - } + if contents.contains("#[test]") { + tidy_error!( + bad, + "{} contains #[test]; libcore tests must be placed inside \ + `src/libcore/tests/`", + subpath.display() + ); } } }, diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 6622403826665..918762ed6e69a 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -4,10 +4,8 @@ //! etc. This is run by default on `make check` and as part of the auto //! builders. -#![deny(rust_2018_idioms)] #![deny(warnings)] -extern crate tidy; use tidy::*; use std::process; @@ -21,14 +19,14 @@ fn main() { let args: Vec = env::args().skip(1).collect(); let mut bad = false; - let quiet = args.iter().any(|s| *s == "--quiet"); + let verbose = args.iter().any(|s| *s == "--verbose"); bins::check(&path, &mut bad); style::check(&path, &mut bad); errors::check(&path, &mut bad); cargo::check(&path, &mut bad); - features::check(&path, &mut bad, quiet); + let collected = features::check(&path, &mut bad, verbose); pal::check(&path, &mut bad); - unstable_book::check(&path, &mut bad); + unstable_book::check(&path, collected, &mut bad); libcoretest::check(&path, &mut bad); if !args.iter().any(|s| *s == "--no-vendor") { deps::check(&path, &mut bad); diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index ed2218f09d26b..c6bb16318b6ee 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -31,8 +31,6 @@ //! platform-specific cfgs are allowed. Not sure yet how to deal with //! this in the long term. -use std::fs::File; -use std::io::Read; use std::path::Path; use std::iter::Iterator; @@ -42,6 +40,10 @@ const EXCEPTION_PATHS: &[&str] = &[ "src/libpanic_abort", "src/libpanic_unwind", "src/libunwind", + // black_box implementation is LLVM-version specific and it uses + // target_os to tell targets with different LLVM-versions appart + // (e.g. `wasm32-unknown-emscripten` vs `wasm32-unknown-unknown`): + "src/libcore/hint.rs", "src/libstd/sys/", // Platform-specific code for std lives here. // This has the trailing slash so that sys_common is not excepted. "src/libstd/os", // Platform-specific public interfaces @@ -54,8 +56,10 @@ const EXCEPTION_PATHS: &[&str] = &[ "src/libstd/f64.rs", // Integration test for platform-specific run-time feature detection: "src/libstd/tests/run-time-detect.rs" , + "src/libstd/net/test.rs", "src/libstd/sys_common/mod.rs", "src/libstd/sys_common/net.rs", + "src/libstd/sys_common/backtrace.rs", "src/libterm", // Not sure how to make this crate portable, but test crate needs it. "src/libtest", // Probably should defer to unstable `std::sys` APIs. "src/libstd/sync/mpsc", // some tests are only run on non-emscripten @@ -81,29 +85,26 @@ const EXCEPTION_PATHS: &[&str] = &[ ]; pub fn check(path: &Path, bad: &mut bool) { - let mut contents = String::new(); // Sanity check that the complex parsing here works. let mut saw_target_arch = false; let mut saw_cfg_bang = false; - super::walk(path, &mut super::filter_dirs, &mut |file| { + super::walk(path, &mut super::filter_dirs, &mut |entry, contents| { + let file = entry.path(); let filestr = file.to_string_lossy().replace("\\", "/"); if !filestr.ends_with(".rs") { return } let is_exception_path = EXCEPTION_PATHS.iter().any(|s| filestr.contains(&**s)); if is_exception_path { return } - check_cfgs(&mut contents, &file, bad, &mut saw_target_arch, &mut saw_cfg_bang); + check_cfgs(contents, &file, bad, &mut saw_target_arch, &mut saw_cfg_bang); }); assert!(saw_target_arch); assert!(saw_cfg_bang); } -fn check_cfgs(contents: &mut String, file: &Path, +fn check_cfgs(contents: &str, file: &Path, bad: &mut bool, saw_target_arch: &mut bool, saw_cfg_bang: &mut bool) { - contents.truncate(0); - t!(t!(File::open(file), file).read_to_string(contents)); - // For now it's ok to have platform-specific code after 'mod tests'. let mod_tests_idx = find_test_mod(contents); let contents = &contents[..mod_tests_idx]; @@ -198,7 +199,7 @@ fn parse_cfgs<'a>(contents: &'a str) -> Vec<(usize, &'a str)> { succeeds_non_ident && preceeds_whitespace_and_paren }); - cfgs.map(|i| { + cfgs.flat_map(|i| { let mut depth = 0; let contents_from = &contents[i..]; for (j, byte) in contents_from.bytes().enumerate() { @@ -209,13 +210,15 @@ fn parse_cfgs<'a>(contents: &'a str) -> Vec<(usize, &'a str)> { b')' => { depth -= 1; if depth == 0 { - return (i, &contents_from[..=j]); + return Some((i, &contents_from[..=j])); } } _ => { } } } - unreachable!() + // if the parentheses are unbalanced just ignore this cfg -- it'll be caught when attempting + // to run the compiler, and there's no real reason to lint it separately here + None }).collect() } diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index a4321cd757129..4a159d926b7cc 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -3,21 +3,22 @@ //! Example checks are: //! //! * No lines over 100 characters. +//! * No files with over 3000 lines. //! * No tabs. //! * No trailing whitespace. //! * No CR characters. //! * No `TODO` or `XXX` directives. //! * No unexplained ` ```ignore ` or ` ```rust,ignore ` doc tests. //! -//! A number of these checks can be opted-out of with various directives like -//! `// ignore-tidy-linelength`. +//! A number of these checks can be opted-out of with various directives of the form: +//! `// ignore-tidy-CHECK-NAME`. -use std::fs::File; -use std::io::prelude::*; use std::path::Path; const COLS: usize = 100; +const LINES: usize = 3000; + const UNEXPLAINED_IGNORE_DOCTEST_INFO: &str = r#"unexplained "```ignore" doctest; try one: * make the test actually pass, by adding necessary imports and declarations, or @@ -35,7 +36,7 @@ when executed when assertions are disabled. Use llvm::report_fatal_error for increased robustness."; /// Parser states for `line_is_url`. -#[derive(PartialEq)] +#[derive(Clone, Copy, PartialEq)] #[allow(non_camel_case_types)] enum LIUState { EXP_COMMENT_START, @@ -53,11 +54,12 @@ enum LIUState { fn line_is_url(line: &str) -> bool { use self::LIUState::*; let mut state: LIUState = EXP_COMMENT_START; + let is_url = |w: &str| w.starts_with("http://") || w.starts_with("https://"); for tok in line.split_whitespace() { match (state, tok) { - (EXP_COMMENT_START, "//") => state = EXP_LINK_LABEL_OR_URL, - (EXP_COMMENT_START, "///") => state = EXP_LINK_LABEL_OR_URL, + (EXP_COMMENT_START, "//") | + (EXP_COMMENT_START, "///") | (EXP_COMMENT_START, "//!") => state = EXP_LINK_LABEL_OR_URL, (EXP_LINK_LABEL_OR_URL, w) @@ -65,14 +67,18 @@ fn line_is_url(line: &str) -> bool { => state = EXP_URL, (EXP_LINK_LABEL_OR_URL, w) - if w.starts_with("http://") || w.starts_with("https://") + if is_url(w) => state = EXP_END, (EXP_URL, w) - if w.starts_with("http://") || w.starts_with("https://") || w.starts_with("../") + if is_url(w) || w.starts_with("../") + => state = EXP_END, + + (_, w) + if w.len() > COLS && is_url(w) => state = EXP_END, - (_, _) => return false, + (_, _) => {} } } @@ -90,9 +96,43 @@ fn long_line_is_ok(line: &str) -> bool { false } +enum Directive { + /// By default, tidy always warns against style issues. + Deny, + + /// `Ignore(false)` means that an `ignore-tidy-*` directive + /// has been provided, but is unnecessary. `Ignore(true)` + /// means that it is necessary (i.e. a warning would be + /// produced if `ignore-tidy-*` was not present). + Ignore(bool), +} + +fn contains_ignore_directive(can_contain: bool, contents: &str, check: &str) -> Directive { + if !can_contain { + return Directive::Deny; + } + // Update `can_contain` when changing this + if contents.contains(&format!("// ignore-tidy-{}", check)) || + contents.contains(&format!("# ignore-tidy-{}", check)) { + Directive::Ignore(false) + } else { + Directive::Deny + } +} + +macro_rules! suppressible_tidy_err { + ($err:ident, $skip:ident, $msg:expr) => { + if let Directive::Deny = $skip { + $err($msg); + } else { + $skip = Directive::Ignore(true); + } + }; +} + pub fn check(path: &Path, bad: &mut bool) { - let mut contents = String::new(); - super::walk(path, &mut super::filter_dirs, &mut |file| { + super::walk(path, &mut super::filter_dirs, &mut |entry, contents| { + let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h"]; if extensions.iter().all(|e| !filename.ends_with(e)) || @@ -100,35 +140,41 @@ pub fn check(path: &Path, bad: &mut bool) { return } - contents.truncate(0); - t!(t!(File::open(file), file).read_to_string(&mut contents)); - if contents.is_empty() { tidy_error!(bad, "{}: empty file", file.display()); } - let skip_cr = contents.contains("ignore-tidy-cr"); - let skip_tab = contents.contains("ignore-tidy-tab"); - let skip_length = contents.contains("ignore-tidy-linelength"); - let skip_end_whitespace = contents.contains("ignore-tidy-end-whitespace"); - let skip_copyright = contents.contains("ignore-tidy-copyright"); + let can_contain = contents.contains("// ignore-tidy-") || + contents.contains("# ignore-tidy-"); + let mut skip_cr = contains_ignore_directive(can_contain, &contents, "cr"); + let mut skip_tab = contains_ignore_directive(can_contain, &contents, "tab"); + let mut skip_line_length = contains_ignore_directive(can_contain, &contents, "linelength"); + let mut skip_file_length = contains_ignore_directive(can_contain, &contents, "filelength"); + let mut skip_end_whitespace = + contains_ignore_directive(can_contain, &contents, "end-whitespace"); + let mut skip_copyright = contains_ignore_directive(can_contain, &contents, "copyright"); + let mut leading_new_lines = false; let mut trailing_new_lines = 0; + let mut lines = 0; for (i, line) in contents.split('\n').enumerate() { let mut err = |msg: &str| { tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg); }; - if !skip_length && line.chars().count() > COLS - && !long_line_is_ok(line) { - err(&format!("line longer than {} chars", COLS)); + if line.chars().count() > COLS && !long_line_is_ok(line) { + suppressible_tidy_err!( + err, + skip_line_length, + &format!("line longer than {} chars", COLS) + ); } - if !skip_tab && line.contains('\t') { - err("tab character"); + if line.contains('\t') { + suppressible_tidy_err!(err, skip_tab, "tab character"); } - if !skip_end_whitespace && (line.ends_with(' ') || line.ends_with('\t')) { - err("trailing whitespace"); + if line.ends_with(' ') || line.ends_with('\t') { + suppressible_tidy_err!(err, skip_end_whitespace, "trailing whitespace"); } - if !skip_cr && line.contains('\r') { - err("CR character"); + if line.contains('\r') { + suppressible_tidy_err!(err, skip_cr, "CR character"); } if filename != "style.rs" { if line.contains("TODO") { @@ -138,12 +184,16 @@ pub fn check(path: &Path, bad: &mut bool) { err("XXX is deprecated; use FIXME") } } - if !skip_copyright && (line.starts_with("// Copyright") || - line.starts_with("# Copyright") || - line.starts_with("Copyright")) - && (line.contains("Rust Developers") || - line.contains("Rust Project Developers")) { - err("copyright notices attributed to the Rust Project Developers are deprecated"); + if (line.starts_with("// Copyright") || + line.starts_with("# Copyright") || + line.starts_with("Copyright")) + && (line.contains("Rust Developers") || + line.contains("Rust Project Developers")) { + suppressible_tidy_err!( + err, + skip_copyright, + "copyright notices attributed to the Rust Project Developers are deprecated" + ); } if line.ends_with("```ignore") || line.ends_with("```rust,ignore") { err(UNEXPLAINED_IGNORE_DOCTEST_INFO); @@ -152,15 +202,53 @@ pub fn check(path: &Path, bad: &mut bool) { err(LLVM_UNREACHABLE_INFO); } if line.is_empty() { + if i == 0 { + leading_new_lines = true; + } trailing_new_lines += 1; } else { trailing_new_lines = 0; } + lines = i; + } + if leading_new_lines { + tidy_error!(bad, "{}: leading newline", file.display()); } match trailing_new_lines { 0 => tidy_error!(bad, "{}: missing trailing newline", file.display()), - 1 | 2 => {} + 1 => {} n => tidy_error!(bad, "{}: too many trailing newlines ({})", file.display(), n), }; + if lines > LINES { + let mut err = |_| { + tidy_error!( + bad, + "{}: too many lines ({}) (add `// \ + ignore-tidy-filelength` to the file to suppress this error)", + file.display(), + lines + ); + }; + suppressible_tidy_err!(err, skip_file_length, ""); + } + + if let Directive::Ignore(false) = skip_cr { + tidy_error!(bad, "{}: ignoring CR characters unnecessarily", file.display()); + } + if let Directive::Ignore(false) = skip_tab { + tidy_error!(bad, "{}: ignoring tab characters unnecessarily", file.display()); + } + if let Directive::Ignore(false) = skip_line_length { + tidy_error!(bad, "{}: ignoring line length unnecessarily", file.display()); + } + if let Directive::Ignore(false) = skip_file_length { + tidy_error!(bad, "{}: ignoring file length unnecessarily", file.display()); + } + if let Directive::Ignore(false) = skip_end_whitespace { + tidy_error!(bad, "{}: ignoring trailing whitespace unnecessarily", file.display()); + } + if let Directive::Ignore(false) = skip_copyright { + tidy_error!(bad, "{}: ignoring copyright unnecessarily", file.display()); + } }) } diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index b572b52ea8f35..2c52cecccb5df 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -4,10 +4,9 @@ use std::fs; use std::path::Path; pub fn check(path: &Path, bad: &mut bool) { - super::walk_many( - &[&path.join("test/ui"), &path.join("test/ui-fulldeps")], - &mut |_| false, - &mut |file_path| { + for path in &[&path.join("test/ui"), &path.join("test/ui-fulldeps")] { + super::walk_no_read(path, &mut |_| false, &mut |entry| { + let file_path = entry.path(); if let Some(ext) = file_path.extension() { if ext == "stderr" || ext == "stdout" { // Test output filenames have one of the formats: @@ -45,6 +44,6 @@ pub fn check(path: &Path, bad: &mut bool) { } } } - }, - ); + }); + } } diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs index cd60f36b1d273..fb63520f0684a 100644 --- a/src/tools/tidy/src/unstable_book.rs +++ b/src/tools/tidy/src/unstable_book.rs @@ -1,30 +1,30 @@ use std::collections::BTreeSet; use std::fs; -use std::path; -use crate::features::{collect_lang_features, collect_lib_features, Features, Status}; +use std::path::{PathBuf, Path}; +use crate::features::{CollectedFeatures, Features, Feature, Status}; -pub const PATH_STR: &str = "doc/unstable-book/src"; +pub const PATH_STR: &str = "doc/unstable-book"; -pub const COMPILER_FLAGS_DIR: &str = "compiler-flags"; +pub const COMPILER_FLAGS_DIR: &str = "src/compiler-flags"; -pub const LANG_FEATURES_DIR: &str = "language-features"; +pub const LANG_FEATURES_DIR: &str = "src/language-features"; -pub const LIB_FEATURES_DIR: &str = "library-features"; +pub const LIB_FEATURES_DIR: &str = "src/library-features"; /// Builds the path to the Unstable Book source directory from the Rust 'src' directory. -pub fn unstable_book_path(base_src_path: &path::Path) -> path::PathBuf { +pub fn unstable_book_path(base_src_path: &Path) -> PathBuf { base_src_path.join(PATH_STR) } /// Builds the path to the directory where the features are documented within the Unstable Book /// source directory. -pub fn unstable_book_lang_features_path(base_src_path: &path::Path) -> path::PathBuf { +pub fn unstable_book_lang_features_path(base_src_path: &Path) -> PathBuf { unstable_book_path(base_src_path).join(LANG_FEATURES_DIR) } /// Builds the path to the directory where the features are documented within the Unstable Book /// source directory. -pub fn unstable_book_lib_features_path(base_src_path: &path::Path) -> path::PathBuf { +pub fn unstable_book_lib_features_path(base_src_path: &Path) -> PathBuf { unstable_book_path(base_src_path).join(LIB_FEATURES_DIR) } @@ -45,7 +45,7 @@ pub fn collect_unstable_feature_names(features: &Features) -> BTreeSet { .collect() } -pub fn collect_unstable_book_section_file_names(dir: &path::Path) -> BTreeSet { +pub fn collect_unstable_book_section_file_names(dir: &Path) -> BTreeSet { fs::read_dir(dir) .expect("could not read directory") .map(|entry| entry.expect("could not read directory entry")) @@ -60,7 +60,7 @@ pub fn collect_unstable_book_section_file_names(dir: &path::Path) -> BTreeSet BTreeSet { collect_unstable_book_section_file_names(&unstable_book_lang_features_path(base_src_path)) } @@ -69,18 +69,26 @@ fn collect_unstable_book_lang_features_section_file_names(base_src_path: &path:: /// /// * hyphens replaced by underscores, /// * the markdown suffix ('.md') removed. -fn collect_unstable_book_lib_features_section_file_names(base_src_path: &path::Path) - -> BTreeSet { +fn collect_unstable_book_lib_features_section_file_names(base_src_path: &Path) -> BTreeSet { collect_unstable_book_section_file_names(&unstable_book_lib_features_path(base_src_path)) } -pub fn check(path: &path::Path, bad: &mut bool) { - // Library features - - let lang_features = collect_lang_features(path, bad); - let lib_features = collect_lib_features(path).into_iter().filter(|&(ref name, _)| { +pub fn check(path: &Path, features: CollectedFeatures, bad: &mut bool) { + let lang_features = features.lang; + let mut lib_features = features.lib.into_iter().filter(|&(ref name, _)| { !lang_features.contains_key(name) - }).collect(); + }).collect::(); + + // This library feature is defined in the `compiler_builtins` crate, which + // has been moved out-of-tree. Now it can no longer be auto-discovered by + // `tidy`, because we need to filter out its (submodule) directory. Manually + // add it to the set of known library features so we can still generate docs. + lib_features.insert("compiler_builtins_lib".to_owned(), Feature { + level: Status::Unstable, + since: None, + has_gate_test: false, + tracking_issue: None, + }); // Library features let unstable_lib_feature_names = collect_unstable_feature_names(&lib_features); diff --git a/src/tools/unstable-book-gen/Cargo.toml b/src/tools/unstable-book-gen/Cargo.toml index 3209de09aeb68..e43e4e6c7cb5a 100644 --- a/src/tools/unstable-book-gen/Cargo.toml +++ b/src/tools/unstable-book-gen/Cargo.toml @@ -3,7 +3,7 @@ authors = ["est31 ", "The Rust Project Developers"] name = "unstable-book-gen" version = "0.1.0" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" edition = "2018" [dependencies] diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs index 427014ce7fe55..e92d174a4e1d4 100644 --- a/src/tools/unstable-book-gen/src/main.rs +++ b/src/tools/unstable-book-gen/src/main.rs @@ -52,7 +52,7 @@ fn set_to_summary_str(set: &BTreeSet, dir: &str fn generate_summary(path: &Path, lang_features: &Features, lib_features: &Features) { let compiler_flags = collect_unstable_book_section_file_names( - &path.join("compiler-flags")); + &path.join("src/compiler-flags")); let compiler_flags_str = set_to_summary_str(&compiler_flags, "compiler-flags"); @@ -61,11 +61,11 @@ fn generate_summary(path: &Path, lang_features: &Features, lib_features: &Featur let unstable_lib_features = collect_unstable_feature_names(&lib_features); let lang_features_str = set_to_summary_str(&unstable_lang_features, - LANG_FEATURES_DIR); + "language-features"); let lib_features_str = set_to_summary_str(&unstable_lib_features, - LIB_FEATURES_DIR); + "library-features"); - let mut file = t!(File::create(&path.join("SUMMARY.md"))); + let mut file = t!(File::create(&path.join("src/SUMMARY.md"))); t!(file.write_fmt(format_args!(include_str!("SUMMARY.md"), compiler_flags = compiler_flags_str, language_features = lang_features_str, @@ -102,8 +102,8 @@ fn generate_unstable_book_files(src :&Path, out: &Path, features :&Features) { } } -fn copy_recursive(path: &Path, to: &Path) { - for entry in t!(fs::read_dir(path)) { +fn copy_recursive(from: &Path, to: &Path) { + for entry in t!(fs::read_dir(from)) { let e = t!(entry); let t = t!(e.metadata()); let dest = &to.join(e.file_name()); @@ -120,7 +120,7 @@ fn main() { let src_path_str = env::args_os().skip(1).next().expect("source path required"); let dest_path_str = env::args_os().skip(2).next().expect("destination path required"); let src_path = Path::new(&src_path_str); - let dest_path = Path::new(&dest_path_str).join("src"); + let dest_path = Path::new(&dest_path_str); let lang_features = collect_lang_features(src_path, &mut false); let lib_features = collect_lib_features(src_path).into_iter().filter(|&(ref name, _)| { diff --git a/triagebot.toml b/triagebot.toml new file mode 100644 index 0000000000000..0e703a3ab349d --- /dev/null +++ b/triagebot.toml @@ -0,0 +1,8 @@ +[relabel] +allow-unauthenticated = [ + "C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", + # I-* without I-nominated + "I-compilemem", "I-compiletime", "I-crash", "I-hang", "I-ICE", "I-slow", +] + +[assign]

    ::Target as Future>::Output; - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll { - Pin::get_mut(self).as_mut().poll(waker) + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + Pin::get_mut(self).as_mut().poll(cx) } } diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs index 6693ecbac41fa..89ea4713cfdaa 100644 --- a/src/libcore/future/mod.rs +++ b/src/libcore/future/mod.rs @@ -1,8 +1,7 @@ -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#![stable(feature = "futures_api", since = "1.36.0")] //! Asynchronous values. mod future; +#[stable(feature = "futures_api", since = "1.36.0")] pub use self::future::Future; diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index d5d29c91e0346..38e3864284240 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -81,9 +81,8 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fmt; -use marker; -use mem; +use crate::fmt; +use crate::marker; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] @@ -282,34 +281,31 @@ pub trait Hasher { #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u16(&mut self, i: u16) { - self.write(&unsafe { mem::transmute::<_, [u8; 2]>(i) }) + self.write(&i.to_ne_bytes()) } /// Writes a single `u32` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u32(&mut self, i: u32) { - self.write(&unsafe { mem::transmute::<_, [u8; 4]>(i) }) + self.write(&i.to_ne_bytes()) } /// Writes a single `u64` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u64(&mut self, i: u64) { - self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) }) + self.write(&i.to_ne_bytes()) } /// Writes a single `u128` into this hasher. #[inline] #[stable(feature = "i128", since = "1.26.0")] fn write_u128(&mut self, i: u128) { - self.write(&unsafe { mem::transmute::<_, [u8; 16]>(i) }) + self.write(&i.to_ne_bytes()) } /// Writes a single `usize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_usize(&mut self, i: usize) { - let bytes = unsafe { - ::slice::from_raw_parts(&i as *const usize as *const u8, mem::size_of::()) - }; - self.write(bytes); + self.write(&i.to_ne_bytes()) } /// Writes a single `i8` into this hasher. @@ -322,31 +318,31 @@ pub trait Hasher { #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i16(&mut self, i: i16) { - self.write_u16(i as u16) + self.write(&i.to_ne_bytes()) } /// Writes a single `i32` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i32(&mut self, i: i32) { - self.write_u32(i as u32) + self.write(&i.to_ne_bytes()) } /// Writes a single `i64` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i64(&mut self, i: i64) { - self.write_u64(i as u64) + self.write(&i.to_ne_bytes()) } /// Writes a single `i128` into this hasher. #[inline] #[stable(feature = "i128", since = "1.26.0")] fn write_i128(&mut self, i: i128) { - self.write_u128(i as u128) + self.write(&i.to_ne_bytes()) } /// Writes a single `isize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_isize(&mut self, i: isize) { - self.write_usize(i as usize) + self.write(&i.to_ne_bytes()) } } @@ -504,7 +500,7 @@ pub struct BuildHasherDefault(marker::PhantomData); #[stable(since = "1.9.0", feature = "core_impl_debug")] impl fmt::Debug for BuildHasherDefault { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("BuildHasherDefault") } } @@ -545,8 +541,9 @@ impl Eq for BuildHasherDefault {} ////////////////////////////////////////////////////////////////////////////// mod impls { - use mem; - use slice; + use crate::mem; + use crate::slice; + use super::*; macro_rules! impl_write { @@ -620,11 +617,11 @@ mod impls { ( $($name:ident)+) => ( #[stable(feature = "rust1", since = "1.0.0")] - impl<$($name: Hash),*> Hash for ($($name,)*) where last_type!($($name,)+): ?Sized { + impl<$($name: Hash),+> Hash for ($($name,)+) where last_type!($($name,)+): ?Sized { #[allow(non_snake_case)] fn hash(&self, state: &mut S) { - let ($(ref $name,)*) = *self; - $($name.hash(state);)* + let ($(ref $name,)+) = *self; + $($name.hash(state);)+ } } ); diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 235c79307ab8d..19aeafd882ef1 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -2,10 +2,10 @@ #![allow(deprecated)] // the types in this module are deprecated -use marker::PhantomData; -use ptr; -use cmp; -use mem; +use crate::marker::PhantomData; +use crate::ptr; +use crate::cmp; +use crate::mem; /// An implementation of SipHash 1-3. /// @@ -269,7 +269,7 @@ impl super::Hasher for Hasher { #[inline] fn write_usize(&mut self, i: usize) { let bytes = unsafe { - ::slice::from_raw_parts(&i as *const usize as *const u8, mem::size_of::()) + crate::slice::from_raw_parts(&i as *const usize as *const u8, mem::size_of::()) }; self.short_write(bytes); } diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs index 89de5c1bc8af8..519212bb6cb4e 100644 --- a/src/libcore/hint.rs +++ b/src/libcore/hint.rs @@ -2,7 +2,7 @@ //! Hints to compiler that affects how code should be emitted or optimized. -use intrinsics; +use crate::intrinsics; /// Informs the compiler that this point in the code is not reachable, enabling /// further optimizations. @@ -21,11 +21,10 @@ use intrinsics; /// difficult-to-debug problems. /// /// Use this function only when you can prove that the code will never call it. +/// Otherwise, consider using the [`unreachable!`] macro, which does not allow +/// optimizations but will panic when executed. /// -/// The [`unreachable!()`] macro is the safe counterpart of this function, which -/// will panic instead when executed. -/// -/// [`unreachable!()`]: ../macro.unreachable.html +/// [`unreachable!`]: ../macro.unreachable.html /// /// # Example /// @@ -50,25 +49,93 @@ pub unsafe fn unreachable_unchecked() -> ! { intrinsics::unreachable() } -/// Save power or switch hyperthreads in a busy-wait spin-loop. +/// Signals the processor that it is entering a busy-wait spin-loop. +/// +/// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving +/// power or switching hyper-threads. +/// +/// This function is different than [`std::thread::yield_now`] which directly yields to the +/// system's scheduler, whereas `spin_loop` only signals the processor that it is entering a +/// busy-wait spin-loop without yielding control to the system's scheduler. /// -/// This function is deliberately more primitive than -/// [`std::thread::yield_now`](../../std/thread/fn.yield_now.html) and -/// does not directly yield to the system's scheduler. -/// In some cases it might be useful to use a combination of both functions. -/// Careful benchmarking is advised. +/// Using a busy-wait spin-loop with `spin_loop` is ideally used in situations where a +/// contended lock is held by another thread executed on a different CPU and where the waiting +/// times are relatively small. Because entering busy-wait spin-loop does not trigger the system's +/// scheduler, no overhead for switching threads occurs. However, if the thread holding the +/// contended lock is running on the same CPU, the spin-loop is likely to occupy an entire CPU slice +/// before switching to the thread that holds the lock. If the contending lock is held by a thread +/// on the same CPU or if the waiting times for acquiring the lock are longer, it is often better to +/// use [`std::thread::yield_now`]. /// -/// On some platforms this function may not do anything at all. +/// **Note**: On platforms that do not support receiving spin-loop hints this function does not +/// do anything at all. +/// +/// [`std::thread::yield_now`]: ../../std/thread/fn.yield_now.html #[inline] #[unstable(feature = "renamed_spin_loop", issue = "55002")] pub fn spin_loop() { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + #[cfg( + all( + any(target_arch = "x86", target_arch = "x86_64"), + target_feature = "sse2" + ) + )] { + #[cfg(target_arch = "x86")] { + unsafe { crate::arch::x86::_mm_pause() }; + } + + #[cfg(target_arch = "x86_64")] { + unsafe { crate::arch::x86_64::_mm_pause() }; + } + } + + #[cfg( + any( + target_arch = "aarch64", + all(target_arch = "arm", target_feature = "v6") + ) + )] { + #[cfg(target_arch = "aarch64")] { + unsafe { crate::arch::aarch64::__yield() }; + } + #[cfg(target_arch = "arm")] { + unsafe { crate::arch::arm::__yield() }; + } + } +} + +/// A function that is opaque to the optimizer, to allow benchmarks to +/// pretend to use outputs to assist in avoiding dead-code +/// elimination. +/// +/// This function is a no-op, and does not even read from `dummy`. +#[inline] +#[unstable(feature = "test", issue = "27812")] +#[allow(unreachable_code)] // this makes #[cfg] a bit easier below. +pub fn black_box(dummy: T) -> T { + // We need to "use" the argument in some way LLVM can't introspect, and on + // targets that support it we can typically leverage inline assembly to do + // this. LLVM's intepretation of inline assembly is that it's, well, a black + // box. This isn't the greatest implementation since it probably deoptimizes + // more than we want, but it's so far good enough. + #[cfg(not(any( + target_arch = "asmjs", + all( + target_arch = "wasm32", + target_os = "emscripten" + ) + )))] unsafe { - asm!("pause" ::: "memory" : "volatile"); + asm!("" : : "r"(&dummy)); + return dummy; } - #[cfg(target_arch = "aarch64")] + // Not all platforms support inline assembly so try to do something without + // inline assembly which in theory still hinders at least some optimizations + // on those targets. This is the "best effort" scenario. unsafe { - asm!("yield" ::: "memory" : "volatile"); + let ret = crate::ptr::read_volatile(&dummy); + crate::mem::forget(dummy); + ret } } diff --git a/src/libcore/internal_macros.rs b/src/libcore/internal_macros.rs index faca785e488c3..3acf2ec837d88 100644 --- a/src/libcore/internal_macros.rs +++ b/src/libcore/internal_macros.rs @@ -37,21 +37,21 @@ macro_rules! forward_ref_binop { } #[$attr] - impl<'a> $imp<&'a $u> for $t { + impl $imp<&$u> for $t { type Output = <$t as $imp<$u>>::Output; #[inline] - fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { + fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output { $imp::$method(self, *other) } } #[$attr] - impl<'a, 'b> $imp<&'a $u> for &'b $t { + impl $imp<&$u> for &$t { type Output = <$t as $imp<$u>>::Output; #[inline] - fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { + fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output { $imp::$method(*self, *other) } } @@ -67,9 +67,9 @@ macro_rules! forward_ref_op_assign { }; (impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => { #[$attr] - impl<'a> $imp<&'a $u> for $t { + impl $imp<&$u> for $t { #[inline] - fn $method(&mut self, other: &'a $u) { + fn $method(&mut self, other: &$u) { $imp::$method(self, *other); } } @@ -81,9 +81,7 @@ macro_rules! forward_ref_op_assign { macro_rules! impl_fn_for_zst { ($( $( #[$attr: meta] )* - // FIXME: when libcore is in the 2018 edition, use `?` repetition in - // $( <$( $li : lifetime ),+> )? - struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )* Fn = + struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn = |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty $body: block; )+) => { @@ -91,14 +89,14 @@ macro_rules! impl_fn_for_zst { $( #[$attr] )* struct $Name; - impl $( <$( $lifetime ),+> )* Fn<($( $ArgTy, )*)> for $Name { + impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name { #[inline] extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy { $body } } - impl $( <$( $lifetime ),+> )* FnMut<($( $ArgTy, )*)> for $Name { + impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name { #[inline] extern "rust-call" fn call_mut( &mut self, @@ -108,7 +106,7 @@ macro_rules! impl_fn_for_zst { } } - impl $( <$( $lifetime ),+> )* FnOnce<($( $ArgTy, )*)> for $Name { + impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name { type Output = $ReturnTy; #[inline] diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index e6098b1b24cc0..b30eff8baa9c8 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -39,7 +39,7 @@ #[stable(feature = "drop_in_place", since = "1.8.0")] #[rustc_deprecated(reason = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.18.0")] -pub use ptr::drop_in_place; +pub use crate::ptr::drop_in_place; extern "rust-intrinsic" { // N.B., these intrinsics take raw pointers because they mutate aliased @@ -737,16 +737,6 @@ extern "rust-intrinsic" { /// /// There are a few things that `transmute` is really useful for. /// - /// Getting the bitpattern of a floating point type (or, more generally, - /// type punning, when `T` and `U` aren't pointers): - /// - /// ``` - /// let bitpattern = unsafe { - /// std::mem::transmute::(1.0) - /// }; - /// assert_eq!(bitpattern, 0x3F800000); - /// ``` - /// /// Turning a pointer into a function pointer. This is *not* portable to /// machines where function pointers and data pointers have different sizes. /// @@ -1061,6 +1051,19 @@ extern "rust-intrinsic" { /// Returns the absolute value of an `f64`. pub fn fabsf64(x: f64) -> f64; + /// Returns the minimum of two `f32` values. + #[cfg(not(bootstrap))] + pub fn minnumf32(x: f32, y: f32) -> f32; + /// Returns the minimum of two `f64` values. + #[cfg(not(bootstrap))] + pub fn minnumf64(x: f64, y: f64) -> f64; + /// Returns the maximum of two `f32` values. + #[cfg(not(bootstrap))] + pub fn maxnumf32(x: f32, y: f32) -> f32; + /// Returns the maximum of two `f64` values. + #[cfg(not(bootstrap))] + pub fn maxnumf64(x: f64, y: f64) -> f64; + /// Copies the sign from `y` to `x` for `f32` values. pub fn copysignf32(x: f32, y: f32) -> f32; /// Copies the sign from `y` to `x` for `f64` values. @@ -1250,6 +1253,21 @@ extern "rust-intrinsic" { /// y < 0 or y >= N, where N is the width of T in bits. pub fn unchecked_shr(x: T, y: T) -> T; + /// Returns the result of an unchecked addition, resulting in + /// undefined behavior when `x + y > T::max_value()` or `x + y < T::min_value()`. + #[cfg(not(bootstrap))] + pub fn unchecked_add(x: T, y: T) -> T; + + /// Returns the result of an unchecked substraction, resulting in + /// undefined behavior when `x - y > T::max_value()` or `x - y < T::min_value()`. + #[cfg(not(bootstrap))] + pub fn unchecked_sub(x: T, y: T) -> T; + + /// Returns the result of an unchecked multiplication, resulting in + /// undefined behavior when `x * y > T::max_value()` or `x * y < T::min_value()`. + #[cfg(not(bootstrap))] + pub fn unchecked_mul(x: T, y: T) -> T; + /// Performs rotate left. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_left` method. For example, @@ -1282,13 +1300,11 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_add` method. For example, /// [`std::u32::saturating_add`](../../std/primitive.u32.html#method.saturating_add) - #[cfg(not(stage0))] pub fn saturating_add(a: T, b: T) -> T; /// Computes `a - b`, while saturating at numeric bounds. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_sub` method. For example, /// [`std::u32::saturating_sub`](../../std/primitive.u32.html#method.saturating_sub) - #[cfg(not(stage0))] pub fn saturating_sub(a: T, b: T) -> T; /// Returns the value of the discriminant for the variant in 'v', @@ -1303,37 +1319,17 @@ extern "rust-intrinsic" { /// platforms this is a `*mut *mut T` which is filled in by the compiler and /// on MSVC it's `*mut [usize; 2]`. For more information see the compiler's /// source as well as std's catch implementation. - pub fn try(f: fn(*mut u8), data: *mut u8, local_ptr: *mut u8) -> i32; + pub fn r#try(f: fn(*mut u8), data: *mut u8, local_ptr: *mut u8) -> i32; /// Emits a `!nontemporal` store according to LLVM (see their docs). /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); } -mod real_intrinsics { - extern "rust-intrinsic" { - /// Copies `count * size_of::()` bytes from `src` to `dst`. The source - /// and destination must *not* overlap. - /// For the full docs, see the stabilized wrapper [`copy_nonoverlapping`]. - /// - /// [`copy_nonoverlapping`]: ../../std/ptr/fn.copy_nonoverlapping.html - pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); - - /// Copies `count * size_of::()` bytes from `src` to `dst`. The source - /// and destination may overlap. - /// For the full docs, see the stabilized wrapper [`copy`]. - /// - /// [`copy`]: ../../std/ptr/fn.copy.html - pub fn copy(src: *const T, dst: *mut T, count: usize); - - /// Sets `count * size_of::()` bytes of memory starting at `dst` to - /// `val`. - /// For the full docs, see the stabilized wrapper [`write_bytes`]. - /// - /// [`write_bytes`]: ../../std/ptr/fn.write_bytes.html - pub fn write_bytes(dst: *mut T, val: u8, count: usize); - } -} +// Some functions are defined here because they accidentally got made +// available in this module on stable. See . +// (`transmute` also falls into this category, but it cannot be wrapped due to the +// check that `T` and `U` have the same size.) /// Copies `count * size_of::()` bytes from `src` to `dst`. The source /// and destination must *not* overlap. @@ -1421,7 +1417,10 @@ mod real_intrinsics { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { - real_intrinsics::copy_nonoverlapping(src, dst, count); + extern "rust-intrinsic" { + fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); + } + copy_nonoverlapping(src, dst, count); } /// Copies `count * size_of::()` bytes from `src` to `dst`. The source @@ -1478,7 +1477,10 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub unsafe fn copy(src: *const T, dst: *mut T, count: usize) { - real_intrinsics::copy(src, dst, count) + extern "rust-intrinsic" { + fn copy(src: *const T, dst: *mut T, count: usize); + } + copy(src, dst, count) } /// Sets `count * size_of::()` bytes of memory starting at `dst` to @@ -1556,5 +1558,58 @@ pub unsafe fn copy(src: *const T, dst: *mut T, count: usize) { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { - real_intrinsics::write_bytes(dst, val, count) + extern "rust-intrinsic" { + fn write_bytes(dst: *mut T, val: u8, count: usize); + } + write_bytes(dst, val, count) +} + +// Simple bootstrap implementations of minnum/maxnum for stage0 compilation. + +/// Returns the minimum of two `f32` values. +#[cfg(bootstrap)] +pub fn minnumf32(x: f32, y: f32) -> f32 { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signaling NaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x < y || y != y { x } else { y }) * 1.0 +} + +/// Returns the minimum of two `f64` values. +#[cfg(bootstrap)] +pub fn minnumf64(x: f64, y: f64) -> f64 { + // Identical to the `f32` case. + (if x < y || y != y { x } else { y }) * 1.0 +} + +/// Returns the maximum of two `f32` values. +#[cfg(bootstrap)] +pub fn maxnumf32(x: f32, y: f32) -> f32 { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signaling NaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x < y || x != x { y } else { x }) * 1.0 +} + +/// Returns the maximum of two `f64` values. +#[cfg(bootstrap)] +pub fn maxnumf64(x: f64, y: f64) -> f64 { + // Identical to the `f32` case. + (if x < y || x != x { y } else { x }) * 1.0 +} + +/// For bootstrapping, implement unchecked_sub as just wrapping_sub. +#[cfg(bootstrap)] +pub unsafe fn unchecked_sub(x: T, y: T) -> T { + sub_with_overflow(x, y).0 } diff --git a/src/libcore/iter/adapters/chain.rs b/src/libcore/iter/adapters/chain.rs index 573b096fb463e..76239ebc0abaf 100644 --- a/src/libcore/iter/adapters/chain.rs +++ b/src/libcore/iter/adapters/chain.rs @@ -1,5 +1,6 @@ -use ops::Try; -use usize; +use crate::ops::Try; +use crate::usize; + use super::super::{Iterator, DoubleEndedIterator, FusedIterator, TrustedLen}; /// An iterator that strings two iterators together. @@ -257,4 +258,3 @@ impl FusedIterator for Chain unsafe impl TrustedLen for Chain where A: TrustedLen, B: TrustedLen, {} - diff --git a/src/libcore/iter/adapters/flatten.rs b/src/libcore/iter/adapters/flatten.rs index 40f6865d38bcf..8c2aae477bf2a 100644 --- a/src/libcore/iter/adapters/flatten.rs +++ b/src/libcore/iter/adapters/flatten.rs @@ -1,5 +1,6 @@ -use fmt; -use ops::Try; +use crate::fmt; +use crate::ops::Try; + use super::super::{Iterator, DoubleEndedIterator, FusedIterator}; use super::Map; @@ -33,7 +34,7 @@ impl Clone for FlatMap impl fmt::Debug for FlatMap where U::IntoIter: fmt::Debug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FlatMap").field("inner", &self.inner).finish() } } @@ -119,7 +120,7 @@ impl fmt::Debug for Flatten where I: Iterator + fmt::Debug, U: Iterator + fmt::Debug, I::Item: IntoIterator, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Flatten").field("inner", &self.inner).finish() } } @@ -327,4 +328,3 @@ impl DoubleEndedIterator for FlattenCompat .rfold(init, |acc, iter| iter.rfold(acc, &mut fold)) } } - diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs index bca1b76dbb975..c2edcd22f953b 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -1,8 +1,9 @@ -use cmp; -use fmt; -use ops::Try; -use usize; -use intrinsics; +use crate::cmp; +use crate::fmt; +use crate::ops::Try; +use crate::usize; +use crate::intrinsics; + use super::{Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen}; use super::LoopState; @@ -129,19 +130,20 @@ unsafe impl TrustedLen for Rev /// /// [`copied`]: trait.Iterator.html#method.copied /// [`Iterator`]: trait.Iterator.html -#[unstable(feature = "iter_copied", issue = "57127")] +#[stable(feature = "iter_copied", since = "1.36.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] #[derive(Clone, Debug)] pub struct Copied { it: I, } + impl Copied { pub(super) fn new(it: I) -> Copied { Copied { it } } } -#[unstable(feature = "iter_copied", issue = "57127")] +#[stable(feature = "iter_copied", since = "1.36.0")] impl<'a, I, T: 'a> Iterator for Copied where I: Iterator, T: Copy { @@ -168,7 +170,7 @@ impl<'a, I, T: 'a> Iterator for Copied } } -#[unstable(feature = "iter_copied", issue = "57127")] +#[stable(feature = "iter_copied", since = "1.36.0")] impl<'a, I, T: 'a> DoubleEndedIterator for Copied where I: DoubleEndedIterator, T: Copy { @@ -189,7 +191,7 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Copied } } -#[unstable(feature = "iter_copied", issue = "57127")] +#[stable(feature = "iter_copied", since = "1.36.0")] impl<'a, I, T: 'a> ExactSizeIterator for Copied where I: ExactSizeIterator, T: Copy { @@ -202,7 +204,7 @@ impl<'a, I, T: 'a> ExactSizeIterator for Copied } } -#[unstable(feature = "iter_copied", issue = "57127")] +#[stable(feature = "iter_copied", since = "1.36.0")] impl<'a, I, T: 'a> FusedIterator for Copied where I: FusedIterator, T: Copy {} @@ -221,7 +223,7 @@ unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Copied } } -#[unstable(feature = "iter_copied", issue = "57127")] +#[stable(feature = "iter_copied", since = "1.36.0")] unsafe impl<'a, I, T: 'a> TrustedLen for Copied where I: TrustedLen, T: Copy @@ -552,7 +554,7 @@ impl Map { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for Map { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Map") .field("iter", &self.iter) .finish() @@ -668,7 +670,7 @@ impl Filter { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for Filter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Filter") .field("iter", &self.iter) .finish() @@ -681,12 +683,7 @@ impl Iterator for Filter where P: FnMut(&I::Item) -> bool #[inline] fn next(&mut self) -> Option { - for x in &mut self.iter { - if (self.predicate)(&x) { - return Some(x); - } - } - None + self.try_for_each(Err).err() } #[inline] @@ -707,12 +704,9 @@ impl Iterator for Filter where P: FnMut(&I::Item) -> bool // Using the branchless version will also simplify the LLVM byte code, thus // leaving more budget for LLVM optimizations. #[inline] - fn count(mut self) -> usize { - let mut count = 0; - for x in &mut self.iter { - count += (self.predicate)(&x) as usize; - } - count + fn count(self) -> usize { + let mut predicate = self.predicate; + self.iter.map(|x| predicate(&x) as usize).sum() } #[inline] @@ -746,12 +740,7 @@ impl DoubleEndedIterator for Filter { #[inline] fn next_back(&mut self) -> Option { - for x in self.iter.by_ref().rev() { - if (self.predicate)(&x) { - return Some(x); - } - } - None + self.try_rfold((), |_, x| Err(x)).err() } #[inline] @@ -805,7 +794,7 @@ impl FilterMap { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for FilterMap { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FilterMap") .field("iter", &self.iter) .finish() @@ -820,12 +809,7 @@ impl Iterator for FilterMap #[inline] fn next(&mut self) -> Option { - for x in self.iter.by_ref() { - if let Some(y) = (self.f)(x) { - return Some(y); - } - } - None + self.try_for_each(Err).err() } #[inline] @@ -863,12 +847,7 @@ impl DoubleEndedIterator for FilterMap { #[inline] fn next_back(&mut self) -> Option { - for x in self.iter.by_ref().rev() { - if let Some(y) = (self.f)(x) { - return Some(y); - } - } - None + self.try_rfold((), |_, x| Err(x)).err() } #[inline] @@ -1003,6 +982,16 @@ impl DoubleEndedIterator for Enumerate where }) } + #[inline] + fn nth_back(&mut self, n: usize) -> Option<(usize, ::Item)> { + self.iter.nth_back(n).map(|a| { + let len = self.iter.len(); + // Can safely add, `ExactSizeIterator` promises that the number of + // elements fits into a `usize`. + (self.count + len, a) + }) + } + #[inline] fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try @@ -1221,7 +1210,7 @@ impl Peekable { } } -/// An iterator that rejects elements while `predicate` is true. +/// An iterator that rejects elements while `predicate` returns `true`. /// /// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its /// documentation for more. @@ -1244,7 +1233,7 @@ impl SkipWhile { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for SkipWhile { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SkipWhile") .field("iter", &self.iter) .field("flag", &self.flag) @@ -1309,7 +1298,7 @@ impl Iterator for SkipWhile impl FusedIterator for SkipWhile where I: FusedIterator, P: FnMut(&I::Item) -> bool {} -/// An iterator that only accepts elements while `predicate` is true. +/// An iterator that only accepts elements while `predicate` returns `true`. /// /// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its /// documentation for more. @@ -1332,7 +1321,7 @@ impl TakeWhile { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for TakeWhile { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TakeWhile") .field("iter", &self.iter) .field("flag", &self.flag) @@ -1520,6 +1509,20 @@ impl DoubleEndedIterator for Skip where I: DoubleEndedIterator + ExactSize } } + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n < len { + self.iter.nth_back(n) + } else { + if len > 0 { + // consume the original iterator + self.iter.nth_back(len-1); + } + None + } + } + fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try { @@ -1656,7 +1659,7 @@ impl Scan { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for Scan { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Scan") .field("iter", &self.iter) .field("state", &self.state) @@ -1812,6 +1815,17 @@ impl DoubleEndedIterator for Fuse where I: DoubleEndedIterator { } } + #[inline] + default fn nth_back(&mut self, n: usize) -> Option<::Item> { + if self.done { + None + } else { + let nth = self.iter.nth_back(n); + self.done = nth.is_none(); + nth + } + } + #[inline] default fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try @@ -1900,6 +1914,11 @@ impl DoubleEndedIterator for Fuse self.iter.next_back() } + #[inline] + fn nth_back(&mut self, n: usize) -> Option<::Item> { + self.iter.nth_back(n) + } + #[inline] fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try @@ -1950,7 +1969,7 @@ impl Inspect { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for Inspect { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Inspect") .field("iter", &self.iter) .finish() diff --git a/src/libcore/iter/adapters/zip.rs b/src/libcore/iter/adapters/zip.rs index 3548d0e282602..06f047d92872e 100644 --- a/src/libcore/iter/adapters/zip.rs +++ b/src/libcore/iter/adapters/zip.rs @@ -1,4 +1,5 @@ -use cmp; +use crate::cmp; + use super::super::{Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen}; /// An iterator that iterates two other iterators simultaneously. diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 5dcca7ee0ca01..6eccb9d1ea86d 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -101,7 +101,7 @@ //! type Item = usize; //! //! // next() is the only required method -//! fn next(&mut self) -> Option { +//! fn next(&mut self) -> Option { //! // Increment our count. This is why we started at zero. //! self.count += 1; //! @@ -140,6 +140,11 @@ //! call `next()` on your iterator, until it reaches `None`. Let's go over that //! next. //! +//! Also note that `Iterator` provides a default implementation of methods such as `nth` and `fold` +//! which call `next` internally. However, it is also possible to write a custom implementation of +//! methods like `nth` and `fold` if an iterator can compute them more efficiently without calling +//! `next`. +//! //! # for Loops and IntoIterator //! //! Rust's `for` loop syntax is actually sugar for iterators. Here's a basic @@ -306,7 +311,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use ops::Try; +use crate::ops::Try; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::Iterator; @@ -352,7 +357,7 @@ pub use self::adapters::Cloned; pub use self::adapters::StepBy; #[stable(feature = "iterator_flatten", since = "1.29.0")] pub use self::adapters::Flatten; -#[unstable(feature = "iter_copied", issue = "57127")] +#[stable(feature = "iter_copied", since = "1.36.0")] pub use self::adapters::Copied; pub(crate) use self::adapters::TrustedRandomAccess; diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index e7efd9728b94a..efda3b263cc97 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -1,7 +1,7 @@ -use convert::TryFrom; -use mem; -use ops::{self, Add, Sub, Try}; -use usize; +use crate::convert::TryFrom; +use crate::mem; +use crate::ops::{self, Add, Sub, Try}; +use crate::usize; use super::{FusedIterator, TrustedLen}; @@ -34,6 +34,13 @@ pub trait Step: Clone + PartialOrd + Sized { /// Adds a `usize`, returning `None` on overflow. fn add_usize(&self, n: usize) -> Option; + + /// Subtracts a `usize`, returning `None` on underflow. + fn sub_usize(&self, n: usize) -> Option { + // this default implementation makes the addition of `sub_usize` a non-breaking change + let _ = n; + unimplemented!() + } } // These are still macro-generated because the integer literals resolve to different types. @@ -68,11 +75,9 @@ macro_rules! step_impl_unsigned { issue = "42168")] impl Step for $t { #[inline] - #[allow(trivial_numeric_casts)] fn steps_between(start: &$t, end: &$t) -> Option { if *start < *end { - // Note: We assume $t <= usize here - Some((*end - *start) as usize) + usize::try_from(*end - *start).ok() } else { Some(0) } @@ -87,6 +92,15 @@ macro_rules! step_impl_unsigned { } } + #[inline] + #[allow(unreachable_patterns)] + fn sub_usize(&self, n: usize) -> Option { + match <$t>::try_from(n) { + Ok(n_as_t) => self.checked_sub(n_as_t), + Err(_) => None, + } + } + step_identical_methods!(); } )*) @@ -98,13 +112,11 @@ macro_rules! step_impl_signed { issue = "42168")] impl Step for $t { #[inline] - #[allow(trivial_numeric_casts)] fn steps_between(start: &$t, end: &$t) -> Option { if *start < *end { - // Note: We assume $t <= isize here - // Use .wrapping_sub and cast to usize to compute the - // difference that may not fit inside the range of isize. - Some((*end as isize).wrapping_sub(*start as isize) as usize) + // Use .wrapping_sub and cast to unsigned to compute the + // difference that may not fit inside the range of $t. + usize::try_from(end.wrapping_sub(*start) as $unsigned).ok() } else { Some(0) } @@ -129,25 +141,23 @@ macro_rules! step_impl_signed { } } - step_identical_methods!(); - } - )*) -} - -macro_rules! step_impl_no_between { - ($($t:ty)*) => ($( - #[unstable(feature = "step_trait", - reason = "likely to be replaced by finer-grained traits", - issue = "42168")] - impl Step for $t { - #[inline] - fn steps_between(_start: &Self, _end: &Self) -> Option { - None - } - #[inline] - fn add_usize(&self, n: usize) -> Option { - self.checked_add(n as $t) + #[allow(unreachable_patterns)] + fn sub_usize(&self, n: usize) -> Option { + match <$unsigned>::try_from(n) { + Ok(n_as_unsigned) => { + // Wrapping in unsigned space handles cases like + // `80_i8.sub_usize(200) == Some(-120_i8)`, + // even though 200_usize is out of range for i8. + let wrapped = (*self as $unsigned).wrapping_sub(n_as_unsigned) as $t; + if wrapped <= *self { + Some(wrapped) + } else { + None // Subtraction underflowed + } + } + Err(_) => None, + } } step_identical_methods!(); @@ -155,25 +165,9 @@ macro_rules! step_impl_no_between { )*) } -step_impl_unsigned!(usize u8 u16); -#[cfg(not(target_pointer_width = "16"))] -step_impl_unsigned!(u32); -#[cfg(target_pointer_width = "16")] -step_impl_no_between!(u32); +step_impl_unsigned!(usize u8 u16 u32 u64 u128); step_impl_signed!([isize: usize] [i8: u8] [i16: u16]); -#[cfg(not(target_pointer_width = "16"))] -step_impl_signed!([i32: u32]); -#[cfg(target_pointer_width = "16")] -step_impl_no_between!(i32); -#[cfg(target_pointer_width = "64")] -step_impl_unsigned!(u64); -#[cfg(target_pointer_width = "64")] -step_impl_signed!([i64: u64]); -// If the target pointer width is not 64-bits, we -// assume here that it is less than 64-bits. -#[cfg(not(target_pointer_width = "64"))] -step_impl_no_between!(u64 i64); -step_impl_no_between!(u128 i128); +step_impl_signed!([i32: u32] [i64: u64] [i128: u128]); macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( @@ -229,7 +223,7 @@ impl Iterator for ops::Range { fn size_hint(&self) -> (usize, Option) { match Step::steps_between(&self.start, &self.end) { Some(hint) => (hint, Some(hint)), - None => (0, None) + None => (usize::MAX, None) } } @@ -273,8 +267,8 @@ range_incl_exact_iter_impl!(u8 u16 i8 i16); // // They need to guarantee that .size_hint() is either exact, or that // the upper bound is None when it does not fit the type limits. -range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64); -range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64); +range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128); +range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128); #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for ops::Range { @@ -287,6 +281,19 @@ impl DoubleEndedIterator for ops::Range { None } } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + if let Some(minus_n) = self.end.sub_usize(n) { + if minus_n > self.start { + self.end = minus_n.sub_one(); + return Some(self.end.clone()) + } + } + + self.end = self.start.clone(); + None + } } #[stable(feature = "fused", since = "1.26.0")] @@ -350,7 +357,7 @@ impl Iterator for ops::RangeInclusive { match Step::steps_between(&self.start, &self.end) { Some(hint) => (hint.saturating_add(1), hint.checked_add(1)), - None => (0, None), + None => (usize::MAX, None), } } @@ -362,7 +369,7 @@ impl Iterator for ops::RangeInclusive { } if let Some(plus_n) = self.start.add_usize(n) { - use cmp::Ordering::*; + use crate::cmp::Ordering::*; match plus_n.partial_cmp(&self.end) { Some(Less) => { @@ -444,6 +451,34 @@ impl DoubleEndedIterator for ops::RangeInclusive { }) } + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.compute_is_empty(); + if self.is_empty.unwrap_or_default() { + return None; + } + + if let Some(minus_n) = self.end.sub_usize(n) { + use crate::cmp::Ordering::*; + + match minus_n.partial_cmp(&self.start) { + Some(Greater) => { + self.is_empty = Some(false); + self.end = minus_n.sub_one(); + return Some(minus_n); + } + Some(Equal) => { + self.is_empty = Some(true); + return Some(minus_n); + } + _ => {} + } + } + + self.is_empty = Some(true); + None + } + #[inline] fn try_rfold(&mut self, init: B, mut f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 74ff7f41d76fa..70a3b70c180dc 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -1,6 +1,6 @@ -use fmt; -use marker; -use usize; +use crate::fmt; +use crate::marker; +use crate::usize; use super::{FusedIterator, TrustedLen}; @@ -39,8 +39,7 @@ unsafe impl TrustedLen for Repeat {} /// Creates a new iterator that endlessly repeats a single element. /// -/// The `repeat()` function repeats a single value over and over and over and -/// over and over and 🔁. +/// The `repeat()` function repeats a single value over and over again. /// /// Infinite iterators like `repeat()` are often used with adapters like /// [`take`], in order to make them finite. @@ -128,8 +127,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Creates a new iterator that repeats elements of type `A` endlessly by /// applying the provided closure, the repeater, `F: FnMut() -> A`. /// -/// The `repeat_with()` function calls the repeater over and over and over and -/// over and over and 🔁. +/// The `repeat_with()` function calls the repeater over and over again. /// /// Infinite iterators like `repeat_with()` are often used with adapters like /// [`take`], in order to make them finite. @@ -202,7 +200,7 @@ pub struct Empty(marker::PhantomData); #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for Empty { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Empty") } } @@ -285,7 +283,7 @@ pub const fn empty() -> Empty { #[derive(Clone, Debug)] #[stable(feature = "iter_once", since = "1.2.0")] pub struct Once { - inner: ::option::IntoIter + inner: crate::option::IntoIter } #[stable(feature = "iter_once", since = "1.2.0")] @@ -377,8 +375,8 @@ pub fn once(value: T) -> Once { Once { inner: Some(value).into_iter() } } -/// An iterator that repeats elements of type `A` endlessly by -/// applying the provided closure `F: FnMut() -> A`. +/// An iterator that yields a single element of type `A` by +/// applying the provided closure `F: FnOnce() -> A`. /// /// This `struct` is created by the [`once_with`] function. /// See its documentation for more. @@ -560,7 +558,7 @@ impl Iterator for FromFn #[stable(feature = "iter_from_fn", since = "1.34.0")] impl fmt::Debug for FromFn { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FromFn").finish() } } @@ -633,7 +631,7 @@ impl FusedIterator for Successors #[stable(feature = "iter_successors", since = "1.34.0")] impl fmt::Debug for Successors { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Successors") .field("next", &self.next) .finish() diff --git a/src/libcore/iter/traits/accum.rs b/src/libcore/iter/traits/accum.rs index dfe1d2a1006d7..adfb639bae341 100644 --- a/src/libcore/iter/traits/accum.rs +++ b/src/libcore/iter/traits/accum.rs @@ -1,5 +1,5 @@ -use ops::{Mul, Add}; -use num::Wrapping; +use crate::ops::{Mul, Add}; +use crate::num::Wrapping; /// Trait to represent types that can be created by summing up an iterator. /// @@ -72,10 +72,10 @@ macro_rules! integer_sum_product { ($($a:ty)*) => ( integer_sum_product!(@impls 0, 1, #[stable(feature = "iter_arith_traits", since = "1.12.0")], - $($a)+); + $($a)*); integer_sum_product!(@impls Wrapping(0), Wrapping(1), #[stable(feature = "wrapping_iter_arith", since = "1.14.0")], - $(Wrapping<$a>)+); + $(Wrapping<$a>)*); ); } @@ -223,3 +223,113 @@ impl Product> for Result ResultShunt::process(iter, |i| i.product()) } } + +/// An iterator adapter that produces output as long as the underlying +/// iterator produces `Option::Some` values. +struct OptionShunt { + iter: I, + exited_early: bool, +} + +impl OptionShunt +where + I: Iterator>, +{ + /// Process the given iterator as if it yielded a `T` instead of a + /// `Option`. Any `None` value will stop the inner iterator and + /// the overall result will be a `None`. + pub fn process(iter: I, mut f: F) -> Option + where + F: FnMut(&mut Self) -> U, + { + let mut shunt = OptionShunt::new(iter); + let value = f(shunt.by_ref()); + shunt.reconstruct(value) + } + + fn new(iter: I) -> Self { + OptionShunt { + iter, + exited_early: false, + } + } + + /// Consume the adapter and rebuild a `Option` value. + fn reconstruct(self, val: U) -> Option { + if self.exited_early { + None + } else { + Some(val) + } + } +} + +impl Iterator for OptionShunt +where + I: Iterator>, +{ + type Item = T; + + fn next(&mut self) -> Option { + match self.iter.next() { + Some(Some(v)) => Some(v), + Some(None) => { + self.exited_early = true; + None + } + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + if self.exited_early { + (0, Some(0)) + } else { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + } +} + +#[stable(feature = "iter_arith_traits_option", since = "1.37.0")] +impl Sum> for Option +where + T: Sum, +{ + /// Takes each element in the `Iterator`: if it is a `None`, no further + /// elements are taken, and the `None` is returned. Should no `None` occur, + /// the sum of all elements is returned. + /// + /// # Examples + /// + /// This sums up the position of the character 'a' in a vector of strings, + /// if a word did not have the character 'a' the operation returns `None`: + /// + /// ``` + /// let words = vec!["have", "a", "great", "day"]; + /// let total: Option = words.iter().map(|w| w.find('a')).sum(); + /// assert_eq!(total, Some(5)); + /// ``` + fn sum(iter: I) -> Option + where + I: Iterator>, + { + OptionShunt::process(iter, |i| i.sum()) + } +} + +#[stable(feature = "iter_arith_traits_option", since = "1.37.0")] +impl Product> for Option +where + T: Product, +{ + /// Takes each element in the `Iterator`: if it is a `None`, no further + /// elements are taken, and the `None` is returned. Should no `None` occur, + /// the product of all elements is returned. + fn product(iter: I) -> Option + where + I: Iterator>, + { + OptionShunt::process(iter, |i| i.product()) + } +} diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs index 5204f6a642509..1865160bc3cf4 100644 --- a/src/libcore/iter/traits/collect.rs +++ b/src/libcore/iter/traits/collect.rs @@ -167,7 +167,7 @@ pub trait FromIterator: Sized { /// // and we'll implement IntoIterator /// impl IntoIterator for MyCollection { /// type Item = i32; -/// type IntoIter = ::std::vec::IntoIter; +/// type IntoIter = ::std::vec::IntoIter; /// /// fn into_iter(self) -> Self::IntoIter { /// self.0.into_iter() @@ -196,7 +196,7 @@ pub trait FromIterator: Sized { /// ```rust /// fn collect_as_strings(collection: T) -> Vec /// where T: IntoIterator, -/// T::Item : std::fmt::Debug, +/// T::Item: std::fmt::Debug, /// { /// collection /// .into_iter() diff --git a/src/libcore/iter/traits/double_ended.rs b/src/libcore/iter/traits/double_ended.rs index 2976afc0b4f81..2c1aeb5690a58 100644 --- a/src/libcore/iter/traits/double_ended.rs +++ b/src/libcore/iter/traits/double_ended.rs @@ -1,5 +1,5 @@ -use ops::Try; -use iter::LoopState; +use crate::ops::Try; +use crate::iter::LoopState; /// An iterator able to yield elements from both ends. /// @@ -88,7 +88,6 @@ pub trait DoubleEndedIterator: Iterator { /// Basic usage: /// /// ``` - /// #![feature(iter_nth_back)] /// let a = [1, 2, 3]; /// assert_eq!(a.iter().nth_back(2), Some(&1)); /// ``` @@ -96,7 +95,6 @@ pub trait DoubleEndedIterator: Iterator { /// Calling `nth_back()` multiple times doesn't rewind the iterator: /// /// ``` - /// #![feature(iter_nth_back)] /// let a = [1, 2, 3]; /// /// let mut iter = a.iter(); @@ -108,12 +106,11 @@ pub trait DoubleEndedIterator: Iterator { /// Returning `None` if there are less than `n + 1` elements: /// /// ``` - /// #![feature(iter_nth_back)] /// let a = [1, 2, 3]; /// assert_eq!(a.iter().nth_back(10), None); /// ``` #[inline] - #[unstable(feature = "iter_nth_back", issue = "56995")] + #[stable(feature = "iter_nth_back", since = "1.37.0")] fn nth_back(&mut self, mut n: usize) -> Option { for x in self.rev() { if n == 0 { return Some(x) } diff --git a/src/libcore/iter/traits/exact_size.rs b/src/libcore/iter/traits/exact_size.rs index d6eab40213edb..4a7db348b1851 100644 --- a/src/libcore/iter/traits/exact_size.rs +++ b/src/libcore/iter/traits/exact_size.rs @@ -45,7 +45,7 @@ /// # } /// # impl Iterator for Counter { /// # type Item = usize; -/// # fn next(&mut self) -> Option { +/// # fn next(&mut self) -> Option { /// # self.count += 1; /// # if self.count < 6 { /// # Some(self.count) @@ -140,4 +140,3 @@ impl ExactSizeIterator for &mut I { (**self).is_empty() } } - diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index 861e9c3157a79..30923c7414504 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -1,5 +1,5 @@ -use cmp::Ordering; -use ops::Try; +use crate::cmp::Ordering; +use crate::ops::Try; use super::super::LoopState; use super::super::{Chain, Cycle, Copied, Cloned, Enumerate, Filter, FilterMap, Fuse}; @@ -356,7 +356,7 @@ pub trait Iterator { /// /// ``` /// let a = [0, 1, 2, 3, 4, 5]; - /// let mut iter = a.into_iter().step_by(2); + /// let mut iter = a.iter().step_by(2); /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&2)); @@ -531,7 +531,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.into_iter().map(|x| 2 * x); + /// let mut iter = a.iter().map(|x| 2 * x); /// /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), Some(4)); @@ -620,7 +620,7 @@ pub trait Iterator { /// ``` /// let a = [0i32, 1, 2]; /// - /// let mut iter = a.into_iter().filter(|x| x.is_positive()); + /// let mut iter = a.iter().filter(|x| x.is_positive()); /// /// assert_eq!(iter.next(), Some(&1)); /// assert_eq!(iter.next(), Some(&2)); @@ -634,7 +634,7 @@ pub trait Iterator { /// ``` /// let a = [0, 1, 2]; /// - /// let mut iter = a.into_iter().filter(|x| **x > 1); // need two *s! + /// let mut iter = a.iter().filter(|x| **x > 1); // need two *s! /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); @@ -646,7 +646,7 @@ pub trait Iterator { /// ``` /// let a = [0, 1, 2]; /// - /// let mut iter = a.into_iter().filter(|&x| *x > 1); // both & and * + /// let mut iter = a.iter().filter(|&x| *x > 1); // both & and * /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); @@ -657,7 +657,7 @@ pub trait Iterator { /// ``` /// let a = [0, 1, 2]; /// - /// let mut iter = a.into_iter().filter(|&&x| x > 1); // two &s + /// let mut iter = a.iter().filter(|&&x| x > 1); // two &s /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); @@ -837,7 +837,7 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 0, 1]; /// - /// let mut iter = a.into_iter().skip_while(|x| x.is_negative()); + /// let mut iter = a.iter().skip_while(|x| x.is_negative()); /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&1)); @@ -851,7 +851,7 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1]; /// - /// let mut iter = a.into_iter().skip_while(|x| **x < 0); // need two *s! + /// let mut iter = a.iter().skip_while(|x| **x < 0); // need two *s! /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&1)); @@ -863,7 +863,7 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1, -2]; /// - /// let mut iter = a.into_iter().skip_while(|x| **x < 0); + /// let mut iter = a.iter().skip_while(|x| **x < 0); /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&1)); @@ -898,7 +898,7 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 0, 1]; /// - /// let mut iter = a.into_iter().take_while(|x| x.is_negative()); + /// let mut iter = a.iter().take_while(|x| x.is_negative()); /// /// assert_eq!(iter.next(), Some(&-1)); /// assert_eq!(iter.next(), None); @@ -911,7 +911,7 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1]; /// - /// let mut iter = a.into_iter().take_while(|x| **x < 0); // need two *s! + /// let mut iter = a.iter().take_while(|x| **x < 0); // need two *s! /// /// assert_eq!(iter.next(), Some(&-1)); /// assert_eq!(iter.next(), None); @@ -922,7 +922,7 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1, -2]; /// - /// let mut iter = a.into_iter().take_while(|x| **x < 0); + /// let mut iter = a.iter().take_while(|x| **x < 0); /// /// assert_eq!(iter.next(), Some(&-1)); /// @@ -937,7 +937,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3, 4]; - /// let mut iter = a.into_iter(); + /// let mut iter = a.iter(); /// /// let result: Vec = iter.by_ref() /// .take_while(|n| **n != 3) @@ -964,6 +964,7 @@ pub trait Iterator { /// Creates an iterator that skips the first `n` elements. /// /// After they have been consumed, the rest of the elements are yielded. + /// Rather than overriding this method directly, instead override the `nth` method. /// /// # Examples /// @@ -1321,7 +1322,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let iter = a.into_iter(); + /// let iter = a.iter(); /// /// let sum: i32 = iter.take(5).fold(0, |acc, i| acc + i ); /// @@ -1334,7 +1335,7 @@ pub trait Iterator { /// // let's try that again /// let a = [1, 2, 3]; /// - /// let mut iter = a.into_iter(); + /// let mut iter = a.iter(); /// /// // instead, we add in a .by_ref() /// let sum: i32 = iter.by_ref().take(2).fold(0, |acc, i| acc + i ); @@ -1479,7 +1480,7 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// /// let (even, odd): (Vec, Vec) = a - /// .into_iter() + /// .iter() /// .partition(|&n| n % 2 == 0); /// /// assert_eq!(even, vec![2]); @@ -1494,13 +1495,13 @@ pub trait Iterator { let mut left: B = Default::default(); let mut right: B = Default::default(); - for x in self { + self.for_each(|x| { if f(&x) { left.extend(Some(x)) } else { right.extend(Some(x)) } - } + }); (left, right) } @@ -2008,12 +2009,7 @@ pub trait Iterator { #[stable(feature = "rust1", since = "1.0.0")] fn max(self) -> Option where Self: Sized, Self::Item: Ord { - select_fold1(self, - |_| (), - // switch to y even if it is only equal, to preserve - // stability. - |_, x, _, y| *x <= *y) - .map(|(_, x)| x) + self.max_by(Ord::cmp) } /// Returns the minimum element of an iterator. @@ -2038,12 +2034,7 @@ pub trait Iterator { #[stable(feature = "rust1", since = "1.0.0")] fn min(self) -> Option where Self: Sized, Self::Item: Ord { - select_fold1(self, - |_| (), - // only switch to y if it is strictly smaller, to - // preserve stability. - |_, x, _, y| *x > *y) - .map(|(_, x)| x) + self.min_by(Ord::cmp) } /// Returns the element that gives the maximum value from the @@ -2062,15 +2053,11 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] - fn max_by_key(self, f: F) -> Option + fn max_by_key(self, mut f: F) -> Option where Self: Sized, F: FnMut(&Self::Item) -> B, { - select_fold1(self, - f, - // switch to y even if it is only equal, to preserve - // stability. - |x_p, _, y_p, _| x_p <= y_p) - .map(|(_, x)| x) + // switch to y even if it is only equal, to preserve stability. + select_fold1(self.map(|x| (f(&x), x)), |(x_p, _), (y_p, _)| x_p <= y_p).map(|(_, x)| x) } /// Returns the element that gives the maximum value with respect to the @@ -2092,12 +2079,8 @@ pub trait Iterator { fn max_by(self, mut compare: F) -> Option where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, { - select_fold1(self, - |_| (), - // switch to y even if it is only equal, to preserve - // stability. - |_, x, _, y| Ordering::Greater != compare(x, y)) - .map(|(_, x)| x) + // switch to y even if it is only equal, to preserve stability. + select_fold1(self, |x, y| compare(x, y) != Ordering::Greater) } /// Returns the element that gives the minimum value from the @@ -2115,15 +2098,11 @@ pub trait Iterator { /// assert_eq!(*a.iter().min_by_key(|x| x.abs()).unwrap(), 0); /// ``` #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] - fn min_by_key(self, f: F) -> Option + fn min_by_key(self, mut f: F) -> Option where Self: Sized, F: FnMut(&Self::Item) -> B, { - select_fold1(self, - f, - // only switch to y if it is strictly smaller, to - // preserve stability. - |x_p, _, y_p, _| x_p > y_p) - .map(|(_, x)| x) + // only switch to y if it is strictly smaller, to preserve stability. + select_fold1(self.map(|x| (f(&x), x)), |(x_p, _), (y_p, _)| x_p > y_p).map(|(_, x)| x) } /// Returns the element that gives the minimum value with respect to the @@ -2145,12 +2124,8 @@ pub trait Iterator { fn min_by(self, mut compare: F) -> Option where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, { - select_fold1(self, - |_| (), - // switch to y even if it is strictly smaller, to - // preserve stability. - |_, x, _, y| Ordering::Greater == compare(x, y)) - .map(|(_, x)| x) + // only switch to y if it is strictly smaller, to preserve stability. + select_fold1(self, |x, y| compare(x, y) == Ordering::Greater) } @@ -2232,8 +2207,6 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// #![feature(iter_copied)] - /// /// let a = [1, 2, 3]; /// /// let v_cloned: Vec<_> = a.iter().copied().collect(); @@ -2244,7 +2217,7 @@ pub trait Iterator { /// assert_eq!(v_cloned, vec![1, 2, 3]); /// assert_eq!(v_map, vec![1, 2, 3]); /// ``` - #[unstable(feature = "iter_copied", issue = "57127")] + #[stable(feature = "iter_copied", since = "1.36.0")] fn copied<'a, T: 'a>(self) -> Copied where Self: Sized + Iterator, T: Copy { @@ -2461,145 +2434,61 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are unequal to those of /// another. #[stable(feature = "iter_order", since = "1.5.0")] - fn ne(mut self, other: I) -> bool where + fn ne(self, other: I) -> bool where I: IntoIterator, Self::Item: PartialEq, Self: Sized, { - let mut other = other.into_iter(); - - loop { - let x = match self.next() { - None => return other.next().is_some(), - Some(val) => val, - }; - - let y = match other.next() { - None => return true, - Some(val) => val, - }; - - if x != y { return true } - } + !self.eq(other) } /// Determines if the elements of this `Iterator` are lexicographically /// less than those of another. #[stable(feature = "iter_order", since = "1.5.0")] - fn lt(mut self, other: I) -> bool where + fn lt(self, other: I) -> bool where I: IntoIterator, Self::Item: PartialOrd, Self: Sized, { - let mut other = other.into_iter(); - - loop { - let x = match self.next() { - None => return other.next().is_some(), - Some(val) => val, - }; - - let y = match other.next() { - None => return false, - Some(val) => val, - }; - - match x.partial_cmp(&y) { - Some(Ordering::Less) => return true, - Some(Ordering::Equal) => (), - Some(Ordering::Greater) => return false, - None => return false, - } - } + self.partial_cmp(other) == Some(Ordering::Less) } /// Determines if the elements of this `Iterator` are lexicographically /// less or equal to those of another. #[stable(feature = "iter_order", since = "1.5.0")] - fn le(mut self, other: I) -> bool where + fn le(self, other: I) -> bool where I: IntoIterator, Self::Item: PartialOrd, Self: Sized, { - let mut other = other.into_iter(); - - loop { - let x = match self.next() { - None => { other.next(); return true; }, - Some(val) => val, - }; - - let y = match other.next() { - None => return false, - Some(val) => val, - }; - - match x.partial_cmp(&y) { - Some(Ordering::Less) => return true, - Some(Ordering::Equal) => (), - Some(Ordering::Greater) => return false, - None => return false, - } + match self.partial_cmp(other) { + Some(Ordering::Less) | Some(Ordering::Equal) => true, + _ => false, } } /// Determines if the elements of this `Iterator` are lexicographically /// greater than those of another. #[stable(feature = "iter_order", since = "1.5.0")] - fn gt(mut self, other: I) -> bool where + fn gt(self, other: I) -> bool where I: IntoIterator, Self::Item: PartialOrd, Self: Sized, { - let mut other = other.into_iter(); - - loop { - let x = match self.next() { - None => { other.next(); return false; }, - Some(val) => val, - }; - - let y = match other.next() { - None => return true, - Some(val) => val, - }; - - match x.partial_cmp(&y) { - Some(Ordering::Less) => return false, - Some(Ordering::Equal) => (), - Some(Ordering::Greater) => return true, - None => return false, - } - } + self.partial_cmp(other) == Some(Ordering::Greater) } /// Determines if the elements of this `Iterator` are lexicographically /// greater than or equal to those of another. #[stable(feature = "iter_order", since = "1.5.0")] - fn ge(mut self, other: I) -> bool where + fn ge(self, other: I) -> bool where I: IntoIterator, Self::Item: PartialOrd, Self: Sized, { - let mut other = other.into_iter(); - - loop { - let x = match self.next() { - None => return other.next().is_none(), - Some(val) => val, - }; - - let y = match other.next() { - None => return true, - Some(val) => val, - }; - - match x.partial_cmp(&y) { - Some(Ordering::Less) => return false, - Some(Ordering::Equal) => (), - Some(Ordering::Greater) => return true, - None => return false, - } + match self.partial_cmp(other) { + Some(Ordering::Greater) | Some(Ordering::Equal) => true, + _ => false, } } @@ -2693,34 +2582,23 @@ pub trait Iterator { } } -/// Select an element from an iterator based on the given "projection" -/// and "comparison" function. +/// Select an element from an iterator based on the given "comparison" +/// function. /// /// This is an idiosyncratic helper to try to factor out the /// commonalities of {max,min}{,_by}. In particular, this avoids /// having to implement optimizations several times. #[inline] -fn select_fold1(mut it: I, - mut f_proj: FProj, - mut f_cmp: FCmp) -> Option<(B, I::Item)> - where I: Iterator, - FProj: FnMut(&I::Item) -> B, - FCmp: FnMut(&B, &I::Item, &B, &I::Item) -> bool +fn select_fold1(mut it: I, mut f: F) -> Option + where + I: Iterator, + F: FnMut(&I::Item, &I::Item) -> bool, { // start with the first element as our selection. This avoids // having to use `Option`s inside the loop, translating to a // sizeable performance gain (6x in one case). it.next().map(|first| { - let first_p = f_proj(&first); - - it.fold((first_p, first), |(sel_p, sel), x| { - let x_p = f_proj(&x); - if f_cmp(&sel_p, &sel, &x_p, &x) { - (x_p, x) - } else { - (sel_p, sel) - } - }) + it.fold(first, |sel, x| if f(&sel, &x) { x } else { sel }) }) } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 63688e70c45cb..04c50329de3d0 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -60,18 +60,20 @@ #![warn(deprecated_in_future)] #![warn(missing_docs)] -#![warn(intra_doc_link_resolution_failure)] #![warn(missing_debug_implementations)] +#![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings + +#![deny(rust_2018_idioms)] +#![allow(explicit_outlives_requirements)] #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] #![feature(asm)] -#![feature(associated_type_defaults)] +#![feature(bound_cloned)] #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] #![feature(const_fn_union)] -#![feature(custom_attribute)] #![feature(doc_cfg)] #![feature(doc_spotlight)] #![feature(extern_types)] @@ -97,6 +99,7 @@ #![feature(staged_api)] #![feature(std_internals)] #![feature(stmt_expr_attributes)] +#![cfg_attr(not(bootstrap), feature(transparent_unions))] #![feature(unboxed_closures)] #![feature(unsized_locals)] #![feature(untagged_unions)] @@ -117,12 +120,11 @@ #![feature(const_str_len)] #![feature(const_int_conversion)] #![feature(const_transmute)] -#![feature(reverse_bits)] #![feature(non_exhaustive)] #![feature(structural_match)] #![feature(abi_unadjusted)] #![feature(adx_target_feature)] -#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)] +#![feature(maybe_uninit_slice, maybe_uninit_array)] #![feature(external_doc)] #[prelude_import] diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index fdbfa56000b8e..589061b282681 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -1,20 +1,21 @@ -/// Entry point of thread panic. For details, see `std::macros`. +/// Panics the current thread. +/// +/// For details, see `std::macros`. #[macro_export] -#[cfg_attr(not(stage0), allow_internal_unstable(core_panic, __rust_unstable_column))] -#[cfg_attr(stage0, allow_internal_unstable)] +#[allow_internal_unstable(core_panic, __rust_unstable_column)] #[stable(feature = "core", since = "1.6.0")] macro_rules! panic { () => ( - panic!("explicit panic") + $crate::panic!("explicit panic") ); ($msg:expr) => ({ $crate::panicking::panic(&($msg, file!(), line!(), __rust_unstable_column!())) }); ($msg:expr,) => ( - panic!($msg) + $crate::panic!($msg) ); ($fmt:expr, $($arg:tt)+) => ({ - $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), + $crate::panicking::panic_fmt(format_args!($fmt, $($arg)+), &(file!(), line!(), __rust_unstable_column!())) }); } @@ -57,7 +58,7 @@ macro_rules! assert_eq { } }); ($left:expr, $right:expr,) => ({ - assert_eq!($left, $right) + $crate::assert_eq!($left, $right) }); ($left:expr, $right:expr, $($arg:tt)+) => ({ match (&($left), &($right)) { @@ -114,7 +115,7 @@ macro_rules! assert_ne { } }); ($left:expr, $right:expr,) => { - assert_ne!($left, $right) + $crate::assert_ne!($left, $right) }; ($left:expr, $right:expr, $($arg:tt)+) => ({ match (&($left), &($right)) { @@ -133,7 +134,7 @@ macro_rules! assert_ne { }); } -/// Ensure that a boolean expression is `true` at runtime. +/// Asserts that a boolean expression is `true` at runtime. /// /// This will invoke the [`panic!`] macro if the provided expression cannot be /// evaluated to `true` at runtime. @@ -207,7 +208,7 @@ macro_rules! debug_assert { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! debug_assert_eq { - ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_eq!($($arg)*); }) + ($($arg:tt)*) => (if cfg!(debug_assertions) { $crate::assert_eq!($($arg)*); }) } /// Asserts that two expressions are not equal to each other. @@ -234,11 +235,10 @@ macro_rules! debug_assert_eq { #[macro_export] #[stable(feature = "assert_ne", since = "1.13.0")] macro_rules! debug_assert_ne { - ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_ne!($($arg)*); }) + ($($arg:tt)*) => (if cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); }) } -/// Helper macro for reducing boilerplate code for matching `Result` together -/// with converting downstream errors. +/// Unwraps a result or propagates its error. /// /// The `?` operator was added to replace `try!` and should be used instead. /// Furthermore, `try` is a reserved word in Rust 2018, so if you must use @@ -310,10 +310,10 @@ macro_rules! r#try { return $crate::result::Result::Err($crate::convert::From::from(err)) } }); - ($expr:expr,) => (r#try!($expr)); + ($expr:expr,) => ($crate::r#try!($expr)); } -/// Write formatted data into a buffer. +/// Writes formatted data into a buffer. /// /// This macro accepts a format string, a list of arguments, and a 'writer'. Arguments will be /// formatted according to the specified format string and the result will be passed to the writer. @@ -422,21 +422,20 @@ macro_rules! write { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(stage0, allow_internal_unstable)] -#[cfg_attr(not(stage0), allow_internal_unstable(format_args_nl))] +#[allow_internal_unstable(format_args_nl)] macro_rules! writeln { ($dst:expr) => ( - write!($dst, "\n") + $crate::write!($dst, "\n") ); ($dst:expr,) => ( - writeln!($dst) + $crate::writeln!($dst) ); ($dst:expr, $($arg:tt)*) => ( $dst.write_fmt(format_args_nl!($($arg)*)) ); } -/// A utility macro for indicating unreachable code. +/// Indicates unreachable code. /// /// This is useful any time that the compiler can't determine that some code is unreachable. For /// example: @@ -446,9 +445,10 @@ macro_rules! writeln { /// * Iterators that dynamically terminate. /// /// If the determination that the code is unreachable proves incorrect, the -/// program immediately terminates with a [`panic!`]. The function [`unreachable_unchecked`], -/// which belongs to the [`std::hint`] module, informs the compiler to -/// optimize the code out of the release version entirely. +/// program immediately terminates with a [`panic!`]. +/// +/// The unsafe counterpart of this macro is the [`unreachable_unchecked`] function, which +/// will cause undefined behavior if the code is reached. /// /// [`panic!`]: ../std/macro.panic.html /// [`unreachable_unchecked`]: ../std/hint/fn.unreachable_unchecked.html @@ -494,17 +494,17 @@ macro_rules! unreachable { panic!("internal error: entered unreachable code") }); ($msg:expr) => ({ - unreachable!("{}", $msg) + $crate::unreachable!("{}", $msg) }); ($msg:expr,) => ({ - unreachable!($msg) + $crate::unreachable!($msg) }); ($fmt:expr, $($arg:tt)*) => ({ panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) }); } -/// A standardized placeholder for marking unfinished code. +/// Indicates unfinished code. /// /// This can be useful if you are prototyping and are just looking to have your /// code type-check, or if you're implementing a trait that requires multiple @@ -558,10 +558,69 @@ macro_rules! unreachable { #[stable(feature = "rust1", since = "1.0.0")] macro_rules! unimplemented { () => (panic!("not yet implemented")); - ($($arg:tt)+) => (panic!("not yet implemented: {}", format_args!($($arg)*))); + ($($arg:tt)+) => (panic!("not yet implemented: {}", format_args!($($arg)+))); +} + +/// Indicates unfinished code. +/// +/// This can be useful if you are prototyping and are just looking to have your +/// code typecheck. `todo!` works exactly like `unimplemented!`. The only +/// difference between the two macros is the name. +/// +/// # Panics +/// +/// This will always [panic!](macro.panic.html) +/// +/// # Examples +/// +/// Here's an example of some in-progress code. We have a trait `Foo`: +/// +/// ``` +/// trait Foo { +/// fn bar(&self); +/// fn baz(&self); +/// } +/// ``` +/// +/// We want to implement `Foo` on one of our types, but we also want to work on +/// just `bar()` first. In order for our code to compile, we need to implement +/// `baz()`, so we can use `todo!`: +/// +/// ``` +/// #![feature(todo_macro)] +/// +/// # trait Foo { +/// # fn bar(&self); +/// # fn baz(&self); +/// # } +/// struct MyStruct; +/// +/// impl Foo for MyStruct { +/// fn bar(&self) { +/// // implementation goes here +/// } +/// +/// fn baz(&self) { +/// // let's not worry about implementing baz() for now +/// todo!(); +/// } +/// } +/// +/// fn main() { +/// let s = MyStruct; +/// s.bar(); +/// +/// // we aren't even using baz() yet, so this is fine. +/// } +/// ``` +#[macro_export] +#[unstable(feature = "todo_macro", issue = "59277")] +macro_rules! todo { + () => (panic!("not yet implemented")); + ($($arg:tt)+) => (panic!("not yet implemented: {}", format_args!($($arg)+))); } -/// A macro to create an array of [`MaybeUninit`] +/// Creates an array of [`MaybeUninit`]. /// /// This macro constructs an uninitialized array of the type `[MaybeUninit; N]`. /// @@ -569,12 +628,12 @@ macro_rules! unimplemented { #[macro_export] #[unstable(feature = "maybe_uninit_array", issue = "53491")] macro_rules! uninitialized_array { - // This `into_initialized` is safe because an array of `MaybeUninit` does not + // This `assume_init` is safe because an array of `MaybeUninit` does not // require initialization. // FIXME(#49147): Could be replaced by an array initializer, once those can // be any const expression. ($t:ty; $size:expr) => (unsafe { - MaybeUninit::<[MaybeUninit<$t>; $size]>::uninitialized().into_initialized() + MaybeUninit::<[MaybeUninit<$t>; $size]>::uninit().assume_init() }); } @@ -588,7 +647,7 @@ macro_rules! uninitialized_array { #[cfg(rustdoc)] mod builtin { - /// Unconditionally causes compilation to fail with the given error message when encountered. + /// Causes compilation to fail with the given error message when encountered. /// /// For more information, see the documentation for [`std::compile_error!`]. /// @@ -600,7 +659,7 @@ mod builtin { ($msg:expr,) => ({ /* compiler built-in */ }); } - /// The core macro for formatted string creation & output. + /// Constructs parameters for the other string-formatting macros. /// /// For more information, see the documentation for [`std::format_args!`]. /// @@ -612,7 +671,7 @@ mod builtin { ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); } - /// Inspect an environment variable at compile time. + /// Inspects an environment variable at compile time. /// /// For more information, see the documentation for [`std::env!`]. /// @@ -624,7 +683,7 @@ mod builtin { ($name:expr,) => ({ /* compiler built-in */ }); } - /// Optionally inspect an environment variable at compile time. + /// Optionally inspects an environment variable at compile time. /// /// For more information, see the documentation for [`std::option_env!`]. /// @@ -636,7 +695,7 @@ mod builtin { ($name:expr,) => ({ /* compiler built-in */ }); } - /// Concatenate identifiers into one identifier. + /// Concatenates identifiers into one identifier. /// /// For more information, see the documentation for [`std::concat_idents!`]. /// @@ -660,7 +719,7 @@ mod builtin { ($($e:expr,)*) => ({ /* compiler built-in */ }); } - /// A macro which expands to the line number on which it was invoked. + /// Expands to the line number on which it was invoked. /// /// For more information, see the documentation for [`std::line!`]. /// @@ -669,7 +728,7 @@ mod builtin { #[rustc_doc_only_macro] macro_rules! line { () => ({ /* compiler built-in */ }) } - /// A macro which expands to the column number on which it was invoked. + /// Expands to the column number on which it was invoked. /// /// For more information, see the documentation for [`std::column!`]. /// @@ -678,7 +737,7 @@ mod builtin { #[rustc_doc_only_macro] macro_rules! column { () => ({ /* compiler built-in */ }) } - /// A macro which expands to the file name from which it was invoked. + /// Expands to the file name from which it was invoked. /// /// For more information, see the documentation for [`std::file!`]. /// @@ -687,7 +746,7 @@ mod builtin { #[rustc_doc_only_macro] macro_rules! file { () => ({ /* compiler built-in */ }) } - /// A macro which stringifies its arguments. + /// Stringifies its arguments. /// /// For more information, see the documentation for [`std::stringify!`]. /// @@ -729,7 +788,7 @@ mod builtin { #[rustc_doc_only_macro] macro_rules! module_path { () => ({ /* compiler built-in */ }) } - /// Boolean evaluation of configuration flags, at compile-time. + /// Evaluates boolean combinations of configuration flags, at compile-time. /// /// For more information, see the documentation for [`std::cfg!`]. /// @@ -738,7 +797,7 @@ mod builtin { #[rustc_doc_only_macro] macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } - /// Parse a file as an expression or an item according to the context. + /// Parses a file as an expression or an item according to the context. /// /// For more information, see the documentation for [`std::include!`]. /// @@ -750,7 +809,7 @@ mod builtin { ($file:expr,) => ({ /* compiler built-in */ }); } - /// Ensure that a boolean expression is `true` at runtime. + /// Asserts that a boolean expression is `true` at runtime. /// /// For more information, see the documentation for [`std::assert!`]. /// diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 29606cb19038f..d9757d78dcebb 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -6,10 +6,10 @@ #![stable(feature = "rust1", since = "1.0.0")] -use cell::UnsafeCell; -use cmp; -use hash::Hash; -use hash::Hasher; +use crate::cell::UnsafeCell; +use crate::cmp; +use crate::hash::Hash; +use crate::hash::Hasher; /// Types that can be transferred across thread boundaries. /// @@ -73,9 +73,9 @@ impl !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 @@ -103,7 +103,7 @@ pub trait Sized { /// `Unsize` is implemented for: /// /// - `[T; N]` is `Unsize<[T]>` -/// - `T` is `Unsize` when `T: Trait` +/// - `T` is `Unsize` when `T: Trait` /// - `Foo<..., T, ...>` is `Unsize>` if: /// - `T: Unsize` /// - Foo is a struct @@ -636,7 +636,7 @@ unsafe impl Freeze for &mut T {} /// [`Pin